ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/BeOS/serial_beos.cpp
Revision: 1.10
Committed: 2008-01-01T09:40:32Z (16 years, 10 months ago) by gbeauche
Branch: MAIN
CVS Tags: HEAD
Changes since 1.9: +1 -1 lines
Log Message:
Happy New Year!

File Contents

# Content
1 /*
2 * serial_beos.cpp - Serial device driver, BeOS specific stuff
3 *
4 * Basilisk II (C) 1997-2008 Christian Bauer
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 #include <string.h>
22 #include <stdio.h>
23 #include <unistd.h>
24 #include <DeviceKit.h>
25
26 #include "sysdeps.h"
27 #include "cpu_emulation.h"
28 #include "main.h"
29 #include "macos_util.h"
30 #include "prefs.h"
31 #include "serial.h"
32 #include "serial_defs.h"
33
34 #define DEBUG 0
35 #include "debug.h"
36
37 #define MONITOR 0
38
39
40 // Buffer size for kernel-space transfers
41 const int TMP_BUF_SIZE = 2048;
42
43 // These packets are sent to the input/output threads
44 const uint32 CMD_READ = 'read';
45 const uint32 CMD_WRITE = 'writ';
46 const uint32 CMD_QUIT = 'quit';
47
48 struct ThreadPacket {
49 uint32 pb;
50 };
51
52
53 // Driver private variables
54 class BeSERDPort : public SERDPort {
55 public:
56 BeSERDPort(const char *dev)
57 {
58 device_name = dev;
59 if (strstr(dev, "parallel")) {
60 is_parallel = true;
61 fd = -1;
62 device = NULL;
63 } else {
64 is_parallel = false;
65 device = new BSerialPort;
66 }
67 device_sem = create_sem(1, "serial port");
68 input_thread = output_thread = 0;
69 }
70
71 virtual ~BeSERDPort()
72 {
73 status_t l;
74 if (input_thread > 0) {
75 send_data(input_thread, CMD_QUIT, NULL, 0);
76 suspend_thread(input_thread); // Unblock thread
77 snooze(1000);
78 resume_thread(input_thread);
79 while (wait_for_thread(input_thread, &l) == B_INTERRUPTED) ;
80 }
81 if (output_thread > 0) {
82 send_data(output_thread, CMD_QUIT, NULL, 0);
83 suspend_thread(output_thread); // Unblock thread
84 snooze(1000);
85 resume_thread(output_thread);
86 while (wait_for_thread(output_thread, &l) == B_INTERRUPTED) ;
87 }
88 acquire_sem(device_sem);
89 delete_sem(device_sem);
90 delete device;
91 }
92
93 virtual int16 open(uint16 config);
94 virtual int16 prime_in(uint32 pb, uint32 dce);
95 virtual int16 prime_out(uint32 pb, uint32 dce);
96 virtual int16 control(uint32 pb, uint32 dce, uint16 code);
97 virtual int16 status(uint32 pb, uint32 dce, uint16 code);
98 virtual int16 close(void);
99
100 private:
101 bool configure(uint16 config);
102 void set_handshake(uint32 s, bool with_dtr);
103 static status_t input_func(void *arg);
104 static status_t output_func(void *arg);
105
106 const char *device_name; // Name of BeOS port
107 BSerialPort *device; // BeOS port object
108 bool is_parallel; // Flag: Port is parallel, use fd
109 int fd; // FD for parallel ports
110 sem_id device_sem; // BSerialPort arbitration
111
112 thread_id input_thread; // Data input thread
113 thread_id output_thread; // Data output thread
114
115 bool io_killed; // Flag: KillIO called, I/O threads must not call deferred tasks
116 bool drop_dtr_on_close; // Flag: Negate DTR when driver is closed
117
118 uint8 tmp_in_buf[TMP_BUF_SIZE]; // Buffers for copying from/to kernel space
119 uint8 tmp_out_buf[TMP_BUF_SIZE];
120 };
121
122
123 #if DEBUG
124 static const int baud_rates[] = {
125 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 230400, 31250
126 };
127 #endif
128
129
130 /*
131 * Initialization
132 */
133
134 void SerialInit(void)
135 {
136 // Read serial preferences and create structs for both ports
137 the_serd_port[0] = new BeSERDPort(PrefsFindString("seriala"));
138 the_serd_port[1] = new BeSERDPort(PrefsFindString("serialb"));
139 }
140
141
142 /*
143 * Deinitialization
144 */
145
146 void SerialExit(void)
147 {
148 delete (BeSERDPort *)the_serd_port[0];
149 delete (BeSERDPort *)the_serd_port[1];
150 }
151
152
153 /*
154 * Open serial port
155 */
156
157 int16 BeSERDPort::open(uint16 config)
158 {
159 // Don't open NULL name devices
160 if (device_name == NULL)
161 return openErr;
162
163 // Init variables
164 io_killed = false;
165 drop_dtr_on_close = true;
166
167 // Open port
168 while (acquire_sem(device_sem) == B_INTERRUPTED) ;
169 if (is_parallel) {
170 char name[256];
171 sprintf(name, "/dev/parallel/%s", device_name);
172 fd = ::open(name, O_WRONLY);
173 if (fd < 0) {
174 release_sem(device_sem);
175 return openErr;
176 }
177 } else {
178 device->SetFlowControl(B_HARDWARE_CONTROL); // Must be set before port is opened
179 if (device->Open(device_name) > 0) {
180 device->SetBlocking(true);
181 device->SetTimeout(10000000);
182 device->SetDTR(true);
183 device->SetRTS(true);
184 } else {
185 release_sem(device_sem);
186 return openErr;
187 }
188 }
189
190 // Start input/output threads
191 release_sem(device_sem);
192 configure(config);
193 while (acquire_sem(device_sem) == B_INTERRUPTED) ;
194 while ((input_thread = spawn_thread(input_func, "Serial Input", B_NORMAL_PRIORITY, this)) == B_INTERRUPTED) ;
195 resume_thread(input_thread);
196 while ((output_thread = spawn_thread(output_func, "Serial Output", B_NORMAL_PRIORITY, this)) == B_INTERRUPTED) ;
197 resume_thread(output_thread);
198 release_sem(device_sem);
199 return noErr;
200 }
201
202
203 /*
204 * Read data from port
205 */
206
207 int16 BeSERDPort::prime_in(uint32 pb, uint32 dce)
208 {
209 // Send input command to input_thread
210 read_done = false;
211 read_pending = true;
212 ThreadPacket p;
213 p.pb = pb;
214 WriteMacInt32(input_dt + serdtDCE, dce);
215 while (send_data(input_thread, CMD_READ, &p, sizeof(ThreadPacket)) == B_INTERRUPTED) ;
216 return 1; // Command in progress
217 }
218
219
220 /*
221 * Write data to port
222 */
223
224 int16 BeSERDPort::prime_out(uint32 pb, uint32 dce)
225 {
226 // Send output command to output_thread
227 write_done = false;
228 write_pending = true;
229 ThreadPacket p;
230 p.pb = pb;
231 WriteMacInt32(output_dt + serdtDCE, dce);
232 while (send_data(output_thread, CMD_WRITE, &p, sizeof(ThreadPacket)) == B_INTERRUPTED) ;
233 return 1; // Command in progress
234 }
235
236
237 /*
238 * Control calls
239 */
240
241 int16 BeSERDPort::control(uint32 pb, uint32 dce, uint16 code)
242 {
243 switch (code) {
244 case 1: // KillIO
245 io_killed = true;
246 suspend_thread(input_thread); // Unblock threads
247 suspend_thread(output_thread);
248 snooze(1000);
249 resume_thread(input_thread);
250 resume_thread(output_thread);
251 while (read_pending || write_pending)
252 snooze(10000);
253 if (!is_parallel) {
254 while (acquire_sem(device_sem) == B_INTERRUPTED) ;
255 device->ClearInput();
256 device->ClearOutput();
257 release_sem(device_sem);
258 }
259 io_killed = false;
260 return noErr;
261
262 case kSERDConfiguration:
263 if (configure(ReadMacInt16(pb + csParam)))
264 return noErr;
265 else
266 return paramErr;
267
268 case kSERDInputBuffer:
269 return noErr; // Not supported under BeOS
270
271 case kSERDSerHShake:
272 set_handshake(pb + csParam, false);
273 return noErr;
274
275 case kSERDClearBreak:
276 case kSERDSetBreak:
277 return noErr; // Not supported under BeOS
278
279 case kSERDBaudRate:
280 if (!is_parallel) {
281 uint16 rate = ReadMacInt16(pb + csParam);
282 data_rate baud_rate;
283 if (rate <= 50) {
284 rate = 50; baud_rate = B_50_BPS;
285 } else if (rate <= 75) {
286 rate = 75; baud_rate = B_75_BPS;
287 } else if (rate <= 110) {
288 rate = 110; baud_rate = B_110_BPS;
289 } else if (rate <= 134) {
290 rate = 134; baud_rate = B_134_BPS;
291 } else if (rate <= 150) {
292 rate = 150; baud_rate = B_150_BPS;
293 } else if (rate <= 200) {
294 rate = 200; baud_rate = B_200_BPS;
295 } else if (rate <= 300) {
296 rate = 300; baud_rate = B_300_BPS;
297 } else if (rate <= 600) {
298 rate = 600; baud_rate = B_600_BPS;
299 } else if (rate <= 1200) {
300 rate = 1200; baud_rate = B_1200_BPS;
301 } else if (rate <= 1800) {
302 rate = 1800; baud_rate = B_1800_BPS;
303 } else if (rate <= 2400) {
304 rate = 2400; baud_rate = B_2400_BPS;
305 } else if (rate <= 4800) {
306 rate = 4800; baud_rate = B_4800_BPS;
307 } else if (rate <= 9600) {
308 rate = 9600; baud_rate = B_9600_BPS;
309 } else if (rate <= 19200) {
310 rate = 19200; baud_rate = B_19200_BPS;
311 } else if (rate <= 31250) {
312 rate = 31250; baud_rate = B_31250_BPS;
313 } else if (rate <= 38400) {
314 rate = 38400; baud_rate = B_38400_BPS;
315 } else if (rate <= 57600) {
316 rate = 57600; baud_rate = B_57600_BPS;
317 }
318 WriteMacInt16(pb + csParam, rate);
319 acquire_sem(device_sem);
320 if (device->SetDataRate(baud_rate) == B_OK) {
321 release_sem(device_sem);
322 return noErr;
323 } else {
324 release_sem(device_sem);
325 return paramErr;
326 }
327 } else
328 return noErr;
329
330 case kSERDHandshake:
331 case kSERDHandshakeRS232:
332 set_handshake(pb + csParam, true);
333 return noErr;
334
335 case kSERDClockMIDI:
336 if (!is_parallel) {
337 while (acquire_sem(device_sem) == B_INTERRUPTED) ;
338 device->SetParityMode(B_NO_PARITY);
339 device->SetDataBits(B_DATA_BITS_8);
340 device->SetStopBits(B_STOP_BITS_1);
341 if (device->SetDataRate(B_31250_BPS) == B_OK) {
342 release_sem(device_sem);
343 return noErr;
344 } else {
345 release_sem(device_sem);
346 return paramErr;
347 }
348 } else
349 return noErr;
350
351 case kSERDMiscOptions:
352 drop_dtr_on_close = !(ReadMacInt8(pb + csParam) & kOptionPreserveDTR);
353 return noErr;
354
355 case kSERDAssertDTR:
356 if (!is_parallel) {
357 while (acquire_sem(device_sem) == B_INTERRUPTED) ;
358 device->SetDTR(true);
359 release_sem(device_sem);
360 }
361 return noErr;
362
363 case kSERDNegateDTR:
364 if (!is_parallel) {
365 while (acquire_sem(device_sem) == B_INTERRUPTED) ;
366 device->SetDTR(false);
367 release_sem(device_sem);
368 }
369 return noErr;
370
371 case kSERDSetPEChar:
372 case kSERDSetPEAltChar:
373 return noErr; // Not supported under BeOS
374
375 case kSERDResetChannel:
376 if (!is_parallel) {
377 while (acquire_sem(device_sem) == B_INTERRUPTED) ;
378 device->ClearInput();
379 device->ClearOutput();
380 release_sem(device_sem);
381 }
382 return noErr;
383
384 case kSERDAssertRTS:
385 if (!is_parallel) {
386 while (acquire_sem(device_sem) == B_INTERRUPTED) ;
387 device->SetRTS(true);
388 release_sem(device_sem);
389 }
390 return noErr;
391
392 case kSERDNegateRTS:
393 if (!is_parallel) {
394 while (acquire_sem(device_sem) == B_INTERRUPTED) ;
395 device->SetRTS(false);
396 release_sem(device_sem);
397 }
398 return noErr;
399
400 case kSERD115KBaud:
401 if (!is_parallel) {
402 while (acquire_sem(device_sem) == B_INTERRUPTED) ;
403 if (device->DataRate() != B_115200_BPS)
404 if (device->SetDataRate(B_115200_BPS) != B_OK) {
405 release_sem(device_sem);
406 return paramErr;
407 }
408 release_sem(device_sem);
409 }
410 return noErr;
411
412 case kSERD230KBaud:
413 case kSERDSetHighSpeed:
414 if (!is_parallel) {
415 while (acquire_sem(device_sem) == B_INTERRUPTED) ;
416 if (device->DataRate() != B_230400_BPS)
417 if (device->SetDataRate(B_230400_BPS) != B_OK) {
418 release_sem(device_sem);
419 return paramErr;
420 }
421 release_sem(device_sem);
422 }
423 return noErr;
424
425 default:
426 printf("WARNING: SerialControl(): unimplemented control code %d\n", code);
427 return controlErr;
428 }
429 }
430
431
432 /*
433 * Status calls
434 */
435
436 int16 BeSERDPort::status(uint32 pb, uint32 dce, uint16 code)
437 {
438 switch (code) {
439 case kSERDInputCount:
440 WriteMacInt32(pb + csParam, 0);
441 if (!is_parallel) {
442 int32 num = 0;
443 while (acquire_sem(device_sem) == B_INTERRUPTED) ;
444 device->NumCharsAvailable(&num);
445 release_sem(device_sem);
446 D(bug(" %d bytes in buffer\n", num));
447 WriteMacInt32(pb + csParam, num);
448 }
449 return noErr;
450
451 case kSERDStatus: {
452 uint32 p = pb + csParam;
453 WriteMacInt8(p + staCumErrs, cum_errors);
454 cum_errors = 0;
455 WriteMacInt8(p + staXOffSent, 0);
456 WriteMacInt8(p + staXOffHold, 0);
457 WriteMacInt8(p + staRdPend, read_pending);
458 WriteMacInt8(p + staWrPend, write_pending);
459 if (is_parallel) {
460 WriteMacInt8(p + staCtsHold, 0);
461 WriteMacInt8(p + staDsrHold, 0);
462 WriteMacInt8(p + staModemStatus, dsrEvent | dcdEvent | ctsEvent);
463 } else {
464 while (acquire_sem(device_sem) == B_INTERRUPTED) ;
465 WriteMacInt8(p + staCtsHold, !device->IsCTS());
466 WriteMacInt8(p + staDsrHold, !device->IsDSR());
467 WriteMacInt8(p + staModemStatus,
468 (device->IsDSR() ? dsrEvent : 0)
469 | (device->IsRI() ? riEvent : 0)
470 | (device->IsDCD() ? dcdEvent : 0)
471 | (device->IsCTS() ? ctsEvent : 0));
472 release_sem(device_sem);
473 }
474 return noErr;
475 }
476
477 default:
478 printf("WARNING: SerialStatus(): unimplemented status code %d\n", code);
479 return statusErr;
480 }
481 }
482
483
484 /*
485 * Close serial port
486 */
487
488 int16 BeSERDPort::close()
489 {
490 // Kill threads
491 status_t l;
492 io_killed = true;
493 if (input_thread > 0) {
494 while (send_data(input_thread, CMD_QUIT, NULL, 0) == B_INTERRUPTED) ;
495 if (read_pending) {
496 suspend_thread(input_thread); // Unblock thread
497 snooze(1000);
498 resume_thread(input_thread);
499 }
500 while (wait_for_thread(input_thread, &l) == B_INTERRUPTED) ;
501 }
502 if (output_thread > 0) {
503 while (send_data(output_thread, CMD_QUIT, NULL, 0) == B_INTERRUPTED) ;
504 if (write_pending) {
505 suspend_thread(output_thread); // Unblock thread
506 snooze(1000);
507 resume_thread(output_thread);
508 }
509 while (wait_for_thread(output_thread, &l) == B_INTERRUPTED) ;
510 }
511 input_thread = output_thread = 0;
512
513 // Close port
514 while (acquire_sem(device_sem) == B_INTERRUPTED) ;
515 if (is_parallel) {
516 ::close(fd);
517 fd = -1;
518 } else {
519 if (drop_dtr_on_close)
520 device->SetDTR(false);
521 device->Close();
522 }
523 release_sem(device_sem);
524 return noErr;
525 }
526
527
528 /*
529 * Configure serial port with MacOS config word
530 */
531
532 bool BeSERDPort::configure(uint16 config)
533 {
534 D(bug(" configure %04x\n", config));
535 if (is_parallel)
536 return true;
537
538 while (acquire_sem(device_sem) == B_INTERRUPTED) ;
539
540 // Set number of stop bits
541 switch (config & 0xc000) {
542 case stop10:
543 if (device->StopBits() != B_STOP_BITS_1)
544 device->SetStopBits(B_STOP_BITS_1);
545 break;
546 case stop20:
547 if (device->StopBits() != B_STOP_BITS_2)
548 device->SetStopBits(B_STOP_BITS_2);
549 break;
550 default:
551 release_sem(device_sem);
552 return false;
553 }
554
555 // Set parity mode
556 switch (config & 0x3000) {
557 case noParity:
558 if (device->ParityMode() != B_NO_PARITY)
559 device->SetParityMode(B_NO_PARITY);
560 break;
561 case oddParity:
562 if (device->ParityMode() != B_ODD_PARITY)
563 device->SetParityMode(B_ODD_PARITY);
564 break;
565 case evenParity:
566 if (device->ParityMode() != B_EVEN_PARITY)
567 device->SetParityMode(B_EVEN_PARITY);
568 break;
569 default:
570 release_sem(device_sem);
571 return false;
572 }
573
574 // Set number of data bits
575 switch (config & 0x0c00) {
576 case data7:
577 if (device->DataBits() != B_DATA_BITS_7)
578 device->SetDataBits(B_DATA_BITS_7);
579 break;
580 case data8:
581 if (device->DataBits() != B_DATA_BITS_8)
582 device->SetDataBits(B_DATA_BITS_8);
583 break;
584 default:
585 release_sem(device_sem);
586 return false;
587 }
588
589 // Set baud rate
590 data_rate baud_rate;
591 switch (config & 0x03ff) {
592 case baud150: baud_rate = B_150_BPS; break;
593 case baud300: baud_rate = B_300_BPS; break;
594 case baud600: baud_rate = B_600_BPS; break;
595 case baud1200: baud_rate = B_1200_BPS; break;
596 case baud1800: baud_rate = B_1800_BPS; break;
597 case baud2400: baud_rate = B_2400_BPS; break;
598 case baud4800: baud_rate = B_4800_BPS; break;
599 case baud9600: baud_rate = B_9600_BPS; break;
600 case baud19200: baud_rate = B_19200_BPS; break;
601 case baud38400: baud_rate = B_38400_BPS; break;
602 case baud57600: baud_rate = B_57600_BPS; break;
603 default:
604 release_sem(device_sem);
605 return false;
606 }
607
608 D(bug(" baud rate %d, %d stop bits, %s parity, %d data bits\n", baud_rates[baud_rate], device->StopBits() == B_STOP_BITS_1 ? 1 : 2, device->ParityMode() == B_NO_PARITY ? "no" : device->ParityMode() == B_ODD_PARITY ? "odd" : "even", device->DataBits() == B_DATA_BITS_7 ? 7 : 8));
609 if (device->DataRate() != baud_rate) {
610 bool res = device->SetDataRate(baud_rate) == B_OK;
611 release_sem(device_sem);
612 return res;
613 } else {
614 release_sem(device_sem);
615 return true;
616 }
617 }
618
619
620 /*
621 * Set serial handshaking
622 */
623
624 void BeSERDPort::set_handshake(uint32 s, bool with_dtr)
625 {
626 D(bug(" set_handshake %02x %02x %02x %02x %02x %02x %02x %02x\n",
627 ReadMacInt8(s + 0), ReadMacInt8(s + 1), ReadMacInt8(s + 2), ReadMacInt8(s + 3),
628 ReadMacInt8(s + 4), ReadMacInt8(s + 5), ReadMacInt8(s + 6), ReadMacInt8(s + 7)));
629 if (is_parallel)
630 return;
631
632 uint32 flow;
633 if (with_dtr) {
634 if (ReadMacInt8(s + shkFCTS) || ReadMacInt8(s + shkFDTR))
635 flow = B_HARDWARE_CONTROL;
636 else
637 flow = B_SOFTWARE_CONTROL;
638 } else {
639 if (ReadMacInt8(s + shkFCTS))
640 flow = B_HARDWARE_CONTROL;
641 else
642 flow = B_SOFTWARE_CONTROL;
643 }
644
645 D(bug(" %sware flow control\n", flow == B_HARDWARE_CONTROL ? "hard" : "soft"));
646 while (acquire_sem(device_sem) == B_INTERRUPTED) ;
647 if (device->FlowControl() != flow) {
648 device->Close();
649 device->SetFlowControl(flow);
650 device->Open(device_name);
651 }
652 release_sem(device_sem);
653 }
654
655
656 /*
657 * Data input thread
658 */
659
660 status_t BeSERDPort::input_func(void *arg)
661 {
662 BeSERDPort *s = (BeSERDPort *)arg;
663 for (;;) {
664
665 // Wait for commands
666 thread_id sender;
667 ThreadPacket p;
668 uint32 code = receive_data(&sender, &p, sizeof(ThreadPacket));
669 if (code == CMD_QUIT)
670 break;
671 if (code != CMD_READ)
672 continue;
673
674 // Execute command
675 void *buf = Mac2HostAddr(ReadMacInt32(p.pb + ioBuffer));
676 uint32 length = ReadMacInt32(p.pb + ioReqCount);
677 D(bug("input_func waiting for %ld bytes of data...\n", length));
678 int32 actual;
679
680 // Buffer in kernel space?
681 if ((uint32)buf < 0x80000000) {
682
683 // Yes, transfer via buffer
684 actual = 0;
685 while (length) {
686 uint32 transfer_size = (length > TMP_BUF_SIZE) ? TMP_BUF_SIZE : length;
687 int32 transferred;
688 acquire_sem(s->device_sem);
689 if (s->is_parallel) {
690 if ((transferred = read(s->fd, s->tmp_in_buf, transfer_size)) < 0 || s->io_killed) {
691 // Error
692 actual = transferred;
693 release_sem(s->device_sem);
694 break;
695 }
696 } else {
697 if ((transferred = s->device->Read(s->tmp_in_buf, transfer_size)) < 0 || s->io_killed) {
698 // Error
699 actual = transferred;
700 release_sem(s->device_sem);
701 break;
702 }
703 }
704 release_sem(s->device_sem);
705 memcpy(buf, s->tmp_in_buf, transferred);
706 buf = (void *)((uint8 *)buf + transferred);
707 length -= transferred;
708 actual += transferred;
709 }
710
711 } else {
712
713 // No, transfer directly
714 acquire_sem(s->device_sem);
715 if (s->is_parallel)
716 actual = read(s->fd, buf, length);
717 else
718 actual = s->device->Read(buf, length);
719 release_sem(s->device_sem);
720 }
721
722 D(bug(" %ld bytes received\n", actual));
723
724 #if MONITOR
725 bug("Receiving serial data:\n");
726 uint8 *adr = Mac2HostAddr(ReadMacInt32(p.pb + ioBuffer));
727 for (int i=0; i<actual; i++) {
728 bug("%02x ", adr[i]);
729 }
730 bug("\n");
731 #endif
732
733 // KillIO called? Then simply return
734 if (s->io_killed) {
735
736 WriteMacInt16(p.pb + ioResult, abortErr);
737 WriteMacInt32(p.pb + ioActCount, 0);
738 s->read_pending = s->read_done = false;
739
740 } else {
741
742 // Set error code
743 if (actual >= 0) {
744 WriteMacInt32(p.pb + ioActCount, actual);
745 WriteMacInt32(s->input_dt + serdtResult, noErr);
746 } else {
747 WriteMacInt32(p.pb + ioActCount, 0);
748 WriteMacInt32(s->input_dt + serdtResult, readErr);
749 }
750
751 // Trigger serial interrupt
752 D(bug(" triggering serial interrupt\n"));
753 s->read_done = true;
754 SetInterruptFlag(INTFLAG_SERIAL);
755 TriggerInterrupt();
756 }
757 }
758 return 0;
759 }
760
761
762 /*
763 * Data output thread
764 */
765
766 status_t BeSERDPort::output_func(void *arg)
767 {
768 BeSERDPort *s = (BeSERDPort *)arg;
769 for (;;) {
770
771 // Wait for commands
772 thread_id sender;
773 ThreadPacket p;
774 uint32 code = receive_data(&sender, &p, sizeof(ThreadPacket));
775 if (code == CMD_QUIT)
776 break;
777 if (code != CMD_WRITE)
778 continue;
779
780 // Execute command
781 void *buf = Mac2HostAddr(ReadMacInt32(p.pb + ioBuffer));
782 uint32 length = ReadMacInt32(p.pb + ioReqCount);
783 D(bug("output_func transmitting %ld bytes of data...\n", length));
784 int32 actual;
785
786 #if MONITOR
787 bug("Sending serial data:\n");
788 uint8 *adr = (uint8 *)buf;
789 for (int i=0; i<length; i++) {
790 bug("%02x ", adr[i]);
791 }
792 bug("\n");
793 #endif
794
795 // Buffer in kernel space?
796 if ((uint32)buf < 0x80000000) {
797
798 // Yes, transfer via buffer
799 actual = 0;
800 while (length) {
801 uint32 transfer_size = (length > TMP_BUF_SIZE) ? TMP_BUF_SIZE : length;
802 memcpy(s->tmp_out_buf, buf, transfer_size);
803 int32 transferred;
804 acquire_sem(s->device_sem);
805 if (s->is_parallel) {
806 if ((transferred = write(s->fd, s->tmp_out_buf, transfer_size)) < transfer_size || s->io_killed) {
807 if (transferred < 0) // Error
808 actual = transferred;
809 else
810 actual += transferred;
811 release_sem(s->device_sem);
812 break;
813 }
814 } else {
815 if ((transferred = s->device->Write(s->tmp_out_buf, transfer_size)) < transfer_size || s->io_killed) {
816 if (transferred < 0) // Error
817 actual = transferred;
818 else
819 actual += transferred;
820 release_sem(s->device_sem);
821 break;
822 }
823 }
824 release_sem(s->device_sem);
825 if (transferred > transfer_size) // R3 parallel port driver bug
826 transferred = transfer_size;
827 buf = (void *)((uint8 *)buf + transferred);
828 length -= transferred;
829 actual += transferred;
830 }
831
832 } else {
833
834 // No, transfer directly
835 acquire_sem(s->device_sem);
836 if (s->is_parallel)
837 actual = write(s->fd, buf, length);
838 else
839 actual = s->device->Write(buf, length);
840 release_sem(s->device_sem);
841 if (actual > length) // R3 parallel port driver bug
842 actual = length;
843 }
844
845 D(bug(" %ld bytes transmitted\n", actual));
846
847 // KillIO called? Then simply return
848 if (s->io_killed) {
849
850 WriteMacInt16(p.pb + ioResult, abortErr);
851 WriteMacInt32(p.pb + ioActCount, 0);
852 s->write_pending = s->write_done = false;
853
854 } else {
855
856 // Set error code
857 if (actual >= 0) {
858 WriteMacInt32(p.pb + ioActCount, actual);
859 WriteMacInt32(s->output_dt + serdtResult, noErr);
860 } else {
861 WriteMacInt32(p.pb + ioActCount, 0);
862 WriteMacInt32(s->output_dt + serdtResult, writErr);
863 }
864
865 // Trigger serial interrupt
866 D(bug(" triggering serial interrupt\n"));
867 s->write_done = true;
868 SetInterruptFlag(INTFLAG_SERIAL);
869 TriggerInterrupt();
870 }
871 }
872 return 0;
873 }