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

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

Changes:

  • Update of the copyright notices to include the year 2013.
File size: 10.4 KB
RevLine 
[209]1//======================================================================
2//
3// Project: XTIDE Universal BIOS, Serial Port Server
4//
5// File: process.cpp - Processes commands received over the serial port
6//
7
[376]8//
[526]9// XTIDE Universal BIOS and Associated Tools
10// Copyright (C) 2009-2010 by Tomi Tilli, 2011-2013 by XTIDE Universal BIOS Team.
[376]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.
[526]16//
[376]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
[526]20// GNU General Public License for more details.
[376]21// Visit http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
22//
23
[209]24#include "library.h"
25#include <memory.h>
26#include <string.h>
[219]27#include <stdio.h>
[209]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;
[233]49 unsigned char scan;
50 unsigned char port;
51 unsigned char baud;
[209]52 } inquire;
[277]53 struct {
54 unsigned char command;
55 unsigned char driveAndHead;
56 unsigned char count;
57 unsigned char scan;
58 unsigned short PackedPortAndBaud;
59 } inquirePacked;
[209]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
[219]74#define ATA_COMMAND_LBA 0x40
75#define ATA_COMMAND_HEADMASK 0xf
76
77#define ATA_DriveAndHead_Drive 0x10
78
[210]79void logBuff( char *message, unsigned long buffoffset, unsigned long readto, int verboseLevel )
80{
81 char logBuff[ 514*9 + 10 ];
82 int logCount;
83
[213]84 if( verboseLevel == 5 || (verboseLevel >= 3 && buffoffset == readto) )
[210]85 {
[213]86 if( verboseLevel == 3 && buffoffset > 11 )
[210]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
[211]96 log( 3, "%s%s", message, logBuff );
[210]97 }
98}
99
[219]100void processRequests( SerialAccess *serial, Image *image0, Image *image1, int timeoutEnabled, int verboseLevel )
[209]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;
[210]114 unsigned long perfTimer;
[233]115 unsigned char lastScan;
[209]116
117 GetTime_Timeout_Local = GetTime_Timeout();
118
119 buffoffset = 0;
120 readto = 0;
121 workCount = workOffset = workCommand = 0;
[233]122 lastScan = 0;
[215]123
[258]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
[209]134 lasttick = GetTime();
135
[215]136 while( (len = serial->readCharacters( &buff.b[buffoffset], (readto ? readto-buffoffset : 1) )) )
[209]137 {
138 buffoffset += len;
139
[210]140 //
141 // For debugging, look at the incoming packet
142 //
[213]143 if( verboseLevel >= 3 )
[210]144 logBuff( " Received: ", buffoffset, readto, verboseLevel );
[209]145
[215]146 if( timeoutEnabled && readto && GetTime() > lasttick + GetTime_Timeout_Local )
147 {
148 log( 1, "Timeout waiting on data from client, aborting previous command" );
[209]149
[215]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 }
[209]177 }
178
179 lasttick = GetTime();
180
[526]181 //
[210]182 // No work currently to do, look at each character as they come in...
183 //
[215]184 if( !readto )
[209]185 {
[215]186 if( (buff.b[0] & SERIAL_COMMAND_HEADERMASK) == SERIAL_COMMAND_HEADER )
[209]187 {
[210]188 //
189 // Found our command header byte to start a commnad sequence, read the next 7 and evaluate
190 //
[209]191 readto = 8;
[210]192 continue;
[209]193 }
194 else
195 {
[210]196 //
197 // Spurious characters, discard
198 //
[209]199 if( verboseLevel >= 2 )
200 {
201 if( buff.b[0] >= 0x20 && buff.b[0] <= 0x7e )
[211]202 log( 2, "Spurious: [%d:%c]", buff.b[0], buff.b[0] );
[209]203 else
[211]204 log( 2, "Spurious: [%d]", buff.b[0] );
[209]205 }
206 buffoffset = 0;
207 continue;
208 }
209 }
210
211 //
[210]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 //
[209]220 if( buffoffset == readto && readto == 514 )
221 {
222 buffoffset = readto = 0;
223 if( (crc = checksum( &buff.w[0], 256 )) != buff.w[256] )
224 {
[211]225 log( 0, "Bad Write Sector Checksum" );
[209]226 continue;
227 }
228
229 if( img->readOnly )
230 {
[211]231 log( 1, "Attempt to write to read-only image" );
[209]232 continue;
233 }
234
235 img->seekSector( mylba + workOffset );
236 img->writeSector( &buff.w[0] );
237
[210]238 //
239 // Echo back the CRC
240 //
[219]241 if( !serial->writeCharacters( &buff.w[256], 2 ) )
242 break;
[209]243
244 workOffset++;
245 workCount--;
[215]246
247 if( workCount )
248 readto = 1; // looking for continuation ACK
[209]249 }
250
[210]251 //
[209]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 {
[215]260 if( verboseLevel > 1 )
261 log( 2, " Continuation: Offset=%u, Checksum=%04x", workOffset-1, buff.w[256] );
262
[210]263 //
264 // Continuation...
265 //
[209]266 if( buff.b[0] != (workCount-0) )
267 {
[211]268 log( 0, "Continue Fault: Received=%d, Expected=%d", buff.b[0], workCount );
[209]269 workCount = 0;
270 continue;
271 }
272 }
273 else
274 {
[210]275 //
276 // New Command...
277 //
[209]278 if( (crc = checksum( &buff.w[0], 3 )) != buff.w[3] )
279 {
[215]280 log( 0, "Bad Command Checksum: %02x %02x %02x %02x %02x %02x %02x %02x, Checksum=%04x",
[209]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
[215]285 img = (buff.inquire.driveAndHead & ATA_DriveAndHead_Drive) ? image1 : image0;
[209]286
287 workCommand = buff.chs.command & SERIAL_COMMAND_RWMASK;
288
[217]289 if( (workCommand != SERIAL_COMMAND_INQUIRE) && (buff.chs.driveAndHead & ATA_COMMAND_LBA) )
[209]290 {
[526]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)
[209]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);
[215]301 mylba = img ? (((cyl*img->head + head)*img->sect) + sect-1) : 0;
[209]302 }
303
[215]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,
[233]313 ((unsigned short) buff.inquire.port) << 2,
314 baudRateMatchDivisor( buff.inquire.baud )->display );
[217]315 else if( buff.chs.driveAndHead & ATA_COMMAND_LBA )
[215]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
[209]330 if( (workCommand & SERIAL_COMMAND_WRITE) && img->readOnly )
331 {
[215]332 log( 1, " Write attempt to Read Only disk" );
333 workCount = 0;
[209]334 continue;
335 }
336
[213]337 if( verboseLevel > 0 && workCount > 100 )
[210]338 perfTimer = GetTime();
[209]339 }
340
341 if( workCount && (workCommand == (SERIAL_COMMAND_WRITE | SERIAL_COMMAND_READWRITE)) )
342 {
[210]343 //
344 // Write command... Setup to receive a sector
345 //
[209]346 readto = 514;
347 }
[526]348 else
[209]349 {
[210]350 //
351 // Inquire command...
352 //
[209]353 if( workCommand == SERIAL_COMMAND_INQUIRE )
354 {
[233]355 unsigned char localScan;
356
[526]357 if( serial->speedEmulation &&
[233]358 buff.inquire.baud != serial->baudRate->divisor )
[209]359 {
[215]360 log( 1, " Ignoring Inquire with wrong baud rate" );
[209]361 workCount = 0;
362 continue;
363 }
364
[526]365 localScan = buff.inquire.scan; // need to do this before the call to
[233]366 // img->respondInquire, as it will clear the buff
[526]367 img->respondInquire( &buff.w[0], buff.inquirePacked.PackedPortAndBaud,
368 serial->baudRate,
369 ((unsigned short) buff.inquire.port) << 2,
[233]370 (img == image1 && lastScan) || buff.inquire.scan );
371 lastScan = localScan;
[209]372 }
[210]373 //
374 // Read command...
375 //
[209]376 else
377 {
378 img->seekSector( mylba + workOffset );
379 img->readSector( &buff.w[0] );
[233]380 lastScan = 0;
[209]381 }
382
383 buff.w[256] = checksum( &buff.w[0], 256 );
384
[219]385 if( !serial->writeCharacters( &buff.w[0], 514 ) )
386 break;
[209]387
[215]388 if( verboseLevel >= 3 )
389 logBuff( " Sending: ", 514, 514, verboseLevel );
390
[209]391 workCount--;
392 workOffset++;
[215]393
394 if( workCount )
395 readto = 1; // looking for continuation ACK
[209]396 }
[210]397 }
[209]398
[215]399 if( workCount == 0 && workOffset > 100 )
400 log( 1, " Performance: %.2lf bytes per second", (512.0 * workOffset) / (GetTime() - perfTimer) * 1000.0 );
[209]401 }
402}
[210]403
404
Note: See TracBrowser for help on using the repository browser.