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

Last change on this file since 209 was 209, checked in by gregli@…, 13 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.