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

Last change on this file since 576 was 526, checked in by krille_n_@…, 12 years ago

Changes:

  • Update of the copyright notices to include the year 2013.
File size: 10.4 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//
9// XTIDE Universal BIOS and Associated Tools
10// Copyright (C) 2009-2010 by Tomi Tilli, 2011-2013 by XTIDE Universal BIOS Team.
11//
12// This program is free software; you can redistribute it and/or modify
13// it under the terms of the GNU General Public License as published by
14// the Free Software Foundation; either version 2 of the License, or
15// (at your option) any later version.
16//
17// This program is distributed in the hope that it will be useful,
18// but WITHOUT ANY WARRANTY; without even the implied warranty of
19// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20// GNU General Public License for more details.
21// Visit http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
22//
23
24#include "library.h"
25#include <memory.h>
26#include <string.h>
27#include <stdio.h>
28
29union _buff {
30 struct {
31 unsigned char command;
32 unsigned char driveAndHead;
33 unsigned char count;
34 unsigned char sector;
35 unsigned short cylinder;
36 } chs;
37 struct {
38 unsigned char command;
39 unsigned char bits24;
40 unsigned char count;
41 unsigned char bits00;
42 unsigned char bits08;
43 unsigned char bits16;
44 } lba;
45 struct {
46 unsigned char command;
47 unsigned char driveAndHead;
48 unsigned char count;
49 unsigned char scan;
50 unsigned char port;
51 unsigned char baud;
52 } inquire;
53 struct {
54 unsigned char command;
55 unsigned char driveAndHead;
56 unsigned char count;
57 unsigned char scan;
58 unsigned short PackedPortAndBaud;
59 } inquirePacked;
60 unsigned char b[514];
61 unsigned short w[257];
62} buff;
63
64#define SERIAL_COMMAND_HEADER 0xa0
65
66#define SERIAL_COMMAND_WRITE 1
67#define SERIAL_COMMAND_READWRITE 2
68#define SERIAL_COMMAND_RWMASK 3
69#define SERIAL_COMMAND_INQUIRE 0
70
71#define SERIAL_COMMAND_MASK 0xe3
72#define SERIAL_COMMAND_HEADERMASK 0xe0
73
74#define ATA_COMMAND_LBA 0x40
75#define ATA_COMMAND_HEADMASK 0xf
76
77#define ATA_DriveAndHead_Drive 0x10
78
79void logBuff( char *message, unsigned long buffoffset, unsigned long readto, int verboseLevel )
80{
81 char logBuff[ 514*9 + 10 ];
82 int logCount;
83
84 if( verboseLevel == 5 || (verboseLevel >= 3 && buffoffset == readto) )
85 {
86 if( verboseLevel == 3 && buffoffset > 11 )
87 logCount = 11;
88 else
89 logCount = buffoffset;
90
91 for( int t = 0; t < logCount; t++ )
92 sprintf( &logBuff[t*9], "[%3d:%02x] ", t, buff.b[t] );
93 if( logCount != buffoffset )
94 sprintf( &logBuff[logCount*9], "... " );
95
96 log( 3, "%s%s", message, logBuff );
97 }
98}
99
100void processRequests( SerialAccess *serial, Image *image0, Image *image1, int timeoutEnabled, int verboseLevel )
101{
102 unsigned char workCommand;
103 int workOffset, workCount;
104
105 unsigned long mylba;
106 unsigned long readto;
107 unsigned long buffoffset;
108 unsigned long lasttick;
109 unsigned short crc;
110 unsigned long GetTime_Timeout_Local;
111 unsigned long len;
112 Image *img;
113 unsigned long cyl, sect, head;
114 unsigned long perfTimer;
115 unsigned char lastScan;
116
117 GetTime_Timeout_Local = GetTime_Timeout();
118
119 buffoffset = 0;
120 readto = 0;
121 workCount = workOffset = workCommand = 0;
122 lastScan = 0;
123
124 //
125 // Floppy disks must come after any hard disks
126 //
127 if( (image0 && image0->floppy) && (image1 && !image1->floppy) )
128 {
129 img = image0;
130 image0 = image1;
131 image1 = img;
132 }
133
134 lasttick = GetTime();
135
136 while( (len = serial->readCharacters( &buff.b[buffoffset], (readto ? readto-buffoffset : 1) )) )
137 {
138 buffoffset += len;
139
140 //
141 // For debugging, look at the incoming packet
142 //
143 if( verboseLevel >= 3 )
144 logBuff( " Received: ", buffoffset, readto, verboseLevel );
145
146 if( timeoutEnabled && readto && GetTime() > lasttick + GetTime_Timeout_Local )
147 {
148 log( 1, "Timeout waiting on data from client, aborting previous command" );
149
150 workCount = workOffset = workCommand = 0;
151 readto = 0;
152
153 if( len <= 8 && (buff.b[buffoffset-len] & SERIAL_COMMAND_HEADERMASK) == SERIAL_COMMAND_HEADER )
154 {
155 // assume that we are at the front of a new command
156 //
157 memcpy( &buff.b[0], &buff.b[buffoffset-len], len );
158 buffoffset = len;
159 readto = 8;
160 // fall through to normal processing
161 }
162 else if( len == 1 )
163 {
164 // one new character, treat it like any other new character received, discarding the buffer
165 //
166 buff.b[0] = buff.b[buffoffset-1];
167 buffoffset = 1;
168 // fall through to normal processing
169 }
170 else
171 {
172 // discard even the newly received data and start listening anew
173 //
174 buffoffset = 0;
175 continue;
176 }
177 }
178
179 lasttick = GetTime();
180
181 //
182 // No work currently to do, look at each character as they come in...
183 //
184 if( !readto )
185 {
186 if( (buff.b[0] & SERIAL_COMMAND_HEADERMASK) == SERIAL_COMMAND_HEADER )
187 {
188 //
189 // Found our command header byte to start a commnad sequence, read the next 7 and evaluate
190 //
191 readto = 8;
192 continue;
193 }
194 else
195 {
196 //
197 // Spurious characters, discard
198 //
199 if( verboseLevel >= 2 )
200 {
201 if( buff.b[0] >= 0x20 && buff.b[0] <= 0x7e )
202 log( 2, "Spurious: [%d:%c]", buff.b[0], buff.b[0] );
203 else
204 log( 2, "Spurious: [%d]", buff.b[0] );
205 }
206 buffoffset = 0;
207 continue;
208 }
209 }
210
211 //
212 // Partial packet received, keep reading...
213 //
214 if( readto && buffoffset < readto )
215 continue;
216
217 //
218 // Read 512 bytes from serial port, only one command reads that many characters: Write Sector
219 //
220 if( buffoffset == readto && readto == 514 )
221 {
222 buffoffset = readto = 0;
223 if( (crc = checksum( &buff.w[0], 256 )) != buff.w[256] )
224 {
225 log( 0, "Bad Write Sector Checksum" );
226 continue;
227 }
228
229 if( img->readOnly )
230 {
231 log( 1, "Attempt to write to read-only image" );
232 continue;
233 }
234
235 img->seekSector( mylba + workOffset );
236 img->writeSector( &buff.w[0] );
237
238 //
239 // Echo back the CRC
240 //
241 if( !serial->writeCharacters( &buff.w[256], 2 ) )
242 break;
243
244 workOffset++;
245 workCount--;
246
247 if( workCount )
248 readto = 1; // looking for continuation ACK
249 }
250
251 //
252 // 8 byte command received, or a continuation of the previous command
253 //
254 else if( (buffoffset == readto && readto == 8) ||
255 (buffoffset == readto && readto == 1 && workCount) )
256 {
257 buffoffset = readto = 0;
258 if( workCount )
259 {
260 if( verboseLevel > 1 )
261 log( 2, " Continuation: Offset=%u, Checksum=%04x", workOffset-1, buff.w[256] );
262
263 //
264 // Continuation...
265 //
266 if( buff.b[0] != (workCount-0) )
267 {
268 log( 0, "Continue Fault: Received=%d, Expected=%d", buff.b[0], workCount );
269 workCount = 0;
270 continue;
271 }
272 }
273 else
274 {
275 //
276 // New Command...
277 //
278 if( (crc = checksum( &buff.w[0], 3 )) != buff.w[3] )
279 {
280 log( 0, "Bad Command Checksum: %02x %02x %02x %02x %02x %02x %02x %02x, Checksum=%04x",
281 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);
282 continue;
283 }
284
285 img = (buff.inquire.driveAndHead & ATA_DriveAndHead_Drive) ? image1 : image0;
286
287 workCommand = buff.chs.command & SERIAL_COMMAND_RWMASK;
288
289 if( (workCommand != SERIAL_COMMAND_INQUIRE) && (buff.chs.driveAndHead & ATA_COMMAND_LBA) )
290 {
291 mylba = ((((unsigned long) buff.lba.bits24) & ATA_COMMAND_HEADMASK) << 24)
292 | (((unsigned long) buff.lba.bits16) << 16)
293 | (((unsigned long) buff.lba.bits08) << 8)
294 | ((unsigned long) buff.lba.bits00);
295 }
296 else
297 {
298 cyl = buff.chs.cylinder;
299 sect = buff.chs.sector;
300 head = (buff.chs.driveAndHead & ATA_COMMAND_HEADMASK);
301 mylba = img ? (((cyl*img->head + head)*img->sect) + sect-1) : 0;
302 }
303
304 workOffset = 0;
305 workCount = buff.chs.count;
306
307 if( verboseLevel > 0 )
308 {
309 char *comStr = (workCommand & SERIAL_COMMAND_WRITE ? "Write" : "Read");
310
311 if( workCommand == SERIAL_COMMAND_INQUIRE )
312 log( 1, "Inquire %d: Client Port=0x%x, Client Baud=%s", img == image0 ? 0 : 1,
313 ((unsigned short) buff.inquire.port) << 2,
314 baudRateMatchDivisor( buff.inquire.baud )->display );
315 else if( buff.chs.driveAndHead & ATA_COMMAND_LBA )
316 log( 1, "%s %d: LBA=%u, Count=%u", comStr, img == image0 ? 0 : 1,
317 mylba, workCount );
318 else
319 log( 1, "%s %d: Cylinder=%u, Sector=%u, Head=%u, Count=%u, LBA=%u", comStr, img == image0 ? 0 : 1,
320 cyl, sect, head, workCount, mylba );
321 }
322
323 if( !img )
324 {
325 log( 1, " No slave drive provided" );
326 workCount = 0;
327 continue;
328 }
329
330 if( (workCommand & SERIAL_COMMAND_WRITE) && img->readOnly )
331 {
332 log( 1, " Write attempt to Read Only disk" );
333 workCount = 0;
334 continue;
335 }
336
337 if( verboseLevel > 0 && workCount > 100 )
338 perfTimer = GetTime();
339 }
340
341 if( workCount && (workCommand == (SERIAL_COMMAND_WRITE | SERIAL_COMMAND_READWRITE)) )
342 {
343 //
344 // Write command... Setup to receive a sector
345 //
346 readto = 514;
347 }
348 else
349 {
350 //
351 // Inquire command...
352 //
353 if( workCommand == SERIAL_COMMAND_INQUIRE )
354 {
355 unsigned char localScan;
356
357 if( serial->speedEmulation &&
358 buff.inquire.baud != serial->baudRate->divisor )
359 {
360 log( 1, " Ignoring Inquire with wrong baud rate" );
361 workCount = 0;
362 continue;
363 }
364
365 localScan = buff.inquire.scan; // need to do this before the call to
366 // img->respondInquire, as it will clear the buff
367 img->respondInquire( &buff.w[0], buff.inquirePacked.PackedPortAndBaud,
368 serial->baudRate,
369 ((unsigned short) buff.inquire.port) << 2,
370 (img == image1 && lastScan) || buff.inquire.scan );
371 lastScan = localScan;
372 }
373 //
374 // Read command...
375 //
376 else
377 {
378 img->seekSector( mylba + workOffset );
379 img->readSector( &buff.w[0] );
380 lastScan = 0;
381 }
382
383 buff.w[256] = checksum( &buff.w[0], 256 );
384
385 if( !serial->writeCharacters( &buff.w[0], 514 ) )
386 break;
387
388 if( verboseLevel >= 3 )
389 logBuff( " Sending: ", 514, 514, verboseLevel );
390
391 workCount--;
392 workOffset++;
393
394 if( workCount )
395 readto = 1; // looking for continuation ACK
396 }
397 }
398
399 if( workCount == 0 && workOffset > 100 )
400 log( 1, " Performance: %.2lf bytes per second", (512.0 * workOffset) / (GetTime() - perfTimer) * 1000.0 );
401 }
402}
403
404
Note: See TracBrowser for help on using the repository browser.