ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/BeOS/serial_beos.cpp
Revision: 1.4
Committed: 2000-04-10T18:52:53Z (24 years, 7 months ago) by cebix
Branch: MAIN
CVS Tags: snapshot-13072000
Changes since 1.3: +1 -1 lines
Log Message:
- updated copyright info: 1999->2000

File Contents

# User Rev Content
1 cebix 1.1 /*
2     * serial_beos.cpp - Serial device driver, BeOS specific stuff
3     *
4 cebix 1.4 * Basilisk II (C) 1997-2000 Christian Bauer
5 cebix 1.1 *
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     wait_for_thread(input_thread, &l);
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     wait_for_thread(output_thread, &l);
87     }
88     acquire_sem(device_sem);
89     delete_sem(device_sem);
90     delete device;
91     }
92    
93 cebix 1.2 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 cebix 1.1
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 cebix 1.2 int16 BeSERDPort::open(uint16 config)
158 cebix 1.1 {
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 cebix 1.3 fd = ::open(name, O_WRONLY);
173 cebix 1.1 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 cebix 1.2 int16 BeSERDPort::prime_in(uint32 pb, uint32 dce)
208 cebix 1.1 {
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 cebix 1.2 int16 BeSERDPort::prime_out(uint32 pb, uint32 dce)
225 cebix 1.1 {
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 cebix 1.2 int16 BeSERDPort::control(uint32 pb, uint32 dce, uint16 code)
242 cebix 1.1 {
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 cebix 1.2 int16 BeSERDPort::status(uint32 pb, uint32 dce, uint16 code)
437 cebix 1.1 {
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 cebix 1.2 int16 BeSERDPort::close()
489 cebix 1.1 {
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 cebix 1.3 ::close(fd);
517 cebix 1.1 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     }