source: xtideuniversalbios/trunk/Serial_Server/library/Process.cpp @ 209

Last change on this file since 209 was 209, checked in by gregli@…, 12 years ago

Initial checkin for the Serial Server code, to be run on a host computer with a hard disk image file. Connected via a serial line, this provides the I/O for the serial port support in the XTIDE bios. At present, this is a Win32 command line program, run without parameters for usage information.

File size: 7.3 KB
Line 
1//======================================================================
2//
3// Project:     XTIDE Universal BIOS, Serial Port Server
4//
5// File:        process.cpp - Processes commands received over the serial port
6//
7
8#include "library.h"
9#include <memory.h>
10#include <string.h>
11
12union _buff {
13    struct {
14        unsigned char command;
15        unsigned char driveAndHead;
16        unsigned char count;
17        unsigned char sector;
18        unsigned short cylinder;
19    } chs;
20    struct {
21        unsigned char command;
22        unsigned char bits24;
23        unsigned char count;
24        unsigned char bits00;
25        unsigned char bits08;
26        unsigned char bits16;
27    } lba;
28    struct {
29        unsigned char command;
30        unsigned char driveAndHead;
31        unsigned char count;
32        unsigned char undefined1;
33        unsigned char portAndBaud;
34        unsigned char undefined2;
35    } inquire;
36    unsigned char b[514];
37    unsigned short w[257];
38} buff;
39
40#define SERIAL_COMMAND_HEADER 0xa0
41
42#define SERIAL_COMMAND_WRITE 1
43#define SERIAL_COMMAND_READWRITE 2
44#define SERIAL_COMMAND_RWMASK 3
45#define SERIAL_COMMAND_INQUIRE 0
46
47#define SERIAL_COMMAND_MASK 0xe3
48#define SERIAL_COMMAND_HEADERMASK 0xe0
49
50#define SERIAL_INQUIRE_PORTANDBAUD_BAUD 3
51#define SERIAL_INQUIRE_PORTANDBAUD_PORT 0xfc
52
53void processRequests( Serial *serial, Image *image0, Image *image1, int timeoutEnabled, int verboseLevel )
54{
55    unsigned char workCommand;
56    int workOffset, workCount;
57
58    int vtype;
59
60    unsigned long mylba;
61    unsigned long readto;
62    unsigned long buffoffset;
63    int timeout;
64    unsigned long lasttick;
65    unsigned short crc;
66    unsigned long GetTime_Timeout_Local;
67    unsigned long len;
68    Image *img;
69    unsigned long cyl, sect, head;
70
71    GetTime_Timeout_Local = GetTime_Timeout();
72
73    buffoffset = 0;
74    readto = 0;
75    timeout = 0;
76    workCount = workOffset = workCommand = 0;
77    lasttick = GetTime();
78
79    while( timeout || (len = serial->readCharacters( &buff.b[buffoffset], (readto ? readto-buffoffset : 1) )) )
80    {
81        buffoffset += len;
82
83        if( verboseLevel >= 4 )
84        {
85            char logBuff[ 514*9 + 10 ];
86            int logCount;
87
88            if( verboseLevel == 6 || buffoffset == readto )
89            {
90                if( verboseLevel == 4 && buffoffset > 11 )
91                    logCount = 11;
92                else
93                    logCount = buffoffset;
94
95                for( int t = 0; t < logCount; t++ )
96                    sprintf( &logBuff[t*9], "[%3d:%02x] ", t, buff.b[t] );
97                if( logCount != buffoffset )
98                    sprintf( &logBuff[logCount*9], "... " );
99
100                log( 4, logBuff );
101            }
102        }
103
104        timeout = 0;
105
106        if( buffoffset != 1 && (timeoutEnabled && GetTime() > lasttick + GetTime_Timeout_Local) )
107        {
108            timeout = 1;
109            buff.b[0] = buff.b[buffoffset];
110            buffoffset = 0;
111            len = 1;
112            workCount = 0;
113            log( 2, "Timeout waiting on command" );
114            continue;
115        }
116
117        lasttick = GetTime();
118
119        if( buffoffset == 1 && !readto )
120        {
121            if( workCount )
122            {
123                readto = 1;
124            }
125            else if( (buff.b[0] & SERIAL_COMMAND_HEADERMASK) == SERIAL_COMMAND_HEADER )
126            {
127                readto = 8;
128            }
129            else
130            {
131                if( verboseLevel >= 2 )
132                {
133                    if( buff.b[0] >= 0x20 && buff.b[0] <= 0x7e )
134                        log( 3, "[%d:%c]", buff.b[0], buff.b[0] );
135                    else
136                        log( 3, "[%d]", buff.b[0] );
137                }
138                buffoffset = 0;
139                continue;
140            }
141        }
142
143        // read 512 bytes from serial port - only one reason for that size: Write Sector
144        //
145        if( buffoffset == readto && readto == 514 )
146        {
147            buffoffset = readto = 0;
148            if( (crc = checksum( &buff.w[0], 256 )) != buff.w[256] )
149            {
150                log( 1, "Bad Write Sector Checksum" );
151                continue;
152            }
153
154            if( img->readOnly )
155            {
156                log( 2, "Attempt to write to read-only image" );
157                continue;
158            }
159
160            img->seekSector( mylba + workOffset );
161            img->writeSector( &buff.w[0] );
162
163            if( serial->writeCharacters( &buff.w[256], 2 ) != 2 )
164                log( 1, "Serial Port Write Error" );
165
166            workOffset++;
167            workCount--;
168        }
169
170        // 8 byte command received, or a continuation of the previous command
171        //
172        else if( (buffoffset == readto && readto == 8) ||
173                 (buffoffset == readto && readto == 1 && workCount) )
174        {
175            buffoffset = readto = 0;
176            if( workCount )
177            {
178                if( buff.b[0] != (workCount-0) )
179                {
180                    log( 1, "Continue Fault: Received=%d, Expected=%d", buff.b[0], workCount );
181                    workCount = 0;
182                    continue;
183                }
184            }
185            else
186            {
187                if( (crc = checksum( &buff.w[0], 3 )) != buff.w[3] )
188                {
189                    log( 1, "Bad Command Checksum: %02x %02x %02x %02x %02x %02x %02x %02x, Checksum=%02x",
190                         buff.b[0], buff.b[1], buff.b[2], buff.b[3], buff.b[4], buff.b[5], buff.b[6], buff.b[7], crc);
191                    continue;
192                }
193
194                if( (buff.inquire.driveAndHead & ATA_DriveAndHead_Drive) )
195                {
196                    if( !image1 )
197                    {
198                        log( 2, "slave drive selected when not supplied" );
199                        continue;
200                    }
201                    img = NULL;
202                }
203                else
204                    img = image0;
205
206                workCommand = buff.chs.command & SERIAL_COMMAND_RWMASK;
207
208                if( (workCommand != SERIAL_COMMAND_INQUIRE) && (buff.chs.command & ATA_COMMAND_LBA) )
209                {
210                    mylba = ((((unsigned long) buff.lba.bits24) & ATA_COMMAND_HEADMASK) << 24) 
211                        | (((unsigned long) buff.lba.bits16) << 16) 
212                        | (((unsigned long) buff.lba.bits08) << 8) 
213                        | ((unsigned long) buff.lba.bits00);
214                    vtype = 1;
215                }
216                else
217                {
218                    cyl = buff.chs.cylinder;
219                    sect = buff.chs.sector;
220                    head = (buff.chs.driveAndHead & ATA_COMMAND_HEADMASK);
221                    mylba = (((cyl*img->head + head)*img->sect) + sect-1);
222                    vtype = 2;
223                }
224
225                if( (workCommand & SERIAL_COMMAND_WRITE) && img->readOnly )
226                {
227                    log( 2, "Write attempt to Read Only disk" );
228                    continue;
229                }
230
231                workOffset = 0;
232                workCount = buff.chs.count;
233            }
234
235            if( workCount && (workCommand == (SERIAL_COMMAND_WRITE | SERIAL_COMMAND_READWRITE)) )
236            {
237                readto = 514;
238            }
239            else 
240            {
241                if( workCommand == SERIAL_COMMAND_INQUIRE )
242                {
243                    log( 2, "Inquire Disk Information, Drive=%d", 
244                         (buff.inquire.driveAndHead & ATA_DriveAndHead_Drive) >> 4 );
245
246                    if( serial->speedEmulation && 
247                        (buff.inquire.portAndBaud & SERIAL_INQUIRE_PORTANDBAUD_BAUD) != serial->baudRate->divisor )
248                    {
249                        struct baudRate *br;
250
251                        br = baudRateMatchDivisor( buff.inquire.portAndBaud & SERIAL_INQUIRE_PORTANDBAUD_BAUD );
252
253                        if( br )
254                            log( 2, "    Ignoring Inquire with Baud Rate=%d", br->rate );
255                        else
256                            log( 2, "    Ignoring Inquire with Unknown Baud Rate (portAndBaud=%d)", buff.inquire.portAndBaud );
257                        workCount = 0;
258                        continue;
259                    }
260
261                    img->respondInquire( &buff.w[0], serial->baudRate, buff.inquire.portAndBaud );
262                }
263                else
264                {
265                    img->seekSector( mylba + workOffset );
266                    img->readSector( &buff.w[0] );
267                }
268
269                buff.w[256] = checksum( &buff.w[0], 256 );
270
271                if( serial->writeCharacters( &buff.w[0], 514 ) != 514 )
272                {
273                    log( 1, "Serial Port Write Error" );
274                }
275
276                workCount--;
277                workOffset++;
278            }
279
280            if( verboseLevel > 1 )
281            {
282                if( vtype == 1 )
283                    log( 2, "%s: LBA=%u, Count=%u", 
284                         (workCommand & SERIAL_COMMAND_WRITE ? "Write" : "Read"),
285                         mylba, workCount );
286                else if( vtype == 2 )
287                    log( 2, "%s: Cylinder=%u, Sector=%u, Head=%u, Count=%u, LBA=%u", 
288                         (workCommand & SERIAL_COMMAND_WRITE ? "Write" : (workCommand & SERIAL_COMMAND_READWRITE ? "Read" : "Inquire")),
289                         cyl, sect, head, workCount, mylba );
290
291                vtype = 0;       
292
293                if( workOffset > 1 )
294                    log( 3, "       Offset=%u, Checksum=%04x", workOffset-1, buff.w[256] );               
295            }
296        }
297    }
298}
Note: See TracBrowser for help on using the repository browser.