home *** CD-ROM | disk | FTP | other *** search
- /*
- * serial_beos.cpp - Serial device driver, BeOS specific stuff
- *
- * Basilisk II (C) 1997-2001 Christian Bauer
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
- #include <string.h>
- #include <stdio.h>
- #include <unistd.h>
- #include <DeviceKit.h>
-
- #include "sysdeps.h"
- #include "cpu_emulation.h"
- #include "main.h"
- #include "macos_util.h"
- #include "prefs.h"
- #include "serial.h"
- #include "serial_defs.h"
-
- #define DEBUG 0
- #include "debug.h"
-
- #define MONITOR 0
-
-
- // Buffer size for kernel-space transfers
- const int TMP_BUF_SIZE = 2048;
-
- // These packets are sent to the input/output threads
- const uint32 CMD_READ = 'read';
- const uint32 CMD_WRITE = 'writ';
- const uint32 CMD_QUIT = 'quit';
-
- struct ThreadPacket {
- uint32 pb;
- };
-
-
- // Driver private variables
- class BeSERDPort : public SERDPort {
- public:
- BeSERDPort(const char *dev)
- {
- device_name = dev;
- if (strstr(dev, "parallel")) {
- is_parallel = true;
- fd = -1;
- device = NULL;
- } else {
- is_parallel = false;
- device = new BSerialPort;
- }
- device_sem = create_sem(1, "serial port");
- input_thread = output_thread = 0;
- }
-
- virtual ~BeSERDPort()
- {
- status_t l;
- if (input_thread > 0) {
- send_data(input_thread, CMD_QUIT, NULL, 0);
- suspend_thread(input_thread); // Unblock thread
- snooze(1000);
- resume_thread(input_thread);
- while (wait_for_thread(input_thread, &l) == B_INTERRUPTED) ;
- }
- if (output_thread > 0) {
- send_data(output_thread, CMD_QUIT, NULL, 0);
- suspend_thread(output_thread); // Unblock thread
- snooze(1000);
- resume_thread(output_thread);
- while (wait_for_thread(output_thread, &l) == B_INTERRUPTED) ;
- }
- acquire_sem(device_sem);
- delete_sem(device_sem);
- delete device;
- }
-
- virtual int16 open(uint16 config);
- virtual int16 prime_in(uint32 pb, uint32 dce);
- virtual int16 prime_out(uint32 pb, uint32 dce);
- virtual int16 control(uint32 pb, uint32 dce, uint16 code);
- virtual int16 status(uint32 pb, uint32 dce, uint16 code);
- virtual int16 close(void);
-
- private:
- bool configure(uint16 config);
- void set_handshake(uint32 s, bool with_dtr);
- static status_t input_func(void *arg);
- static status_t output_func(void *arg);
-
- const char *device_name; // Name of BeOS port
- BSerialPort *device; // BeOS port object
- bool is_parallel; // Flag: Port is parallel, use fd
- int fd; // FD for parallel ports
- sem_id device_sem; // BSerialPort arbitration
-
- thread_id input_thread; // Data input thread
- thread_id output_thread; // Data output thread
-
- bool io_killed; // Flag: KillIO called, I/O threads must not call deferred tasks
- bool drop_dtr_on_close; // Flag: Negate DTR when driver is closed
-
- uint8 tmp_in_buf[TMP_BUF_SIZE]; // Buffers for copying from/to kernel space
- uint8 tmp_out_buf[TMP_BUF_SIZE];
- };
-
-
- #if DEBUG
- static const int baud_rates[] = {
- 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 230400, 31250
- };
- #endif
-
-
- /*
- * Initialization
- */
-
- void SerialInit(void)
- {
- // Read serial preferences and create structs for both ports
- the_serd_port[0] = new BeSERDPort(PrefsFindString("seriala"));
- the_serd_port[1] = new BeSERDPort(PrefsFindString("serialb"));
- }
-
-
- /*
- * Deinitialization
- */
-
- void SerialExit(void)
- {
- delete (BeSERDPort *)the_serd_port[0];
- delete (BeSERDPort *)the_serd_port[1];
- }
-
-
- /*
- * Open serial port
- */
-
- int16 BeSERDPort::open(uint16 config)
- {
- // Don't open NULL name devices
- if (device_name == NULL)
- return openErr;
-
- // Init variables
- io_killed = false;
- drop_dtr_on_close = true;
-
- // Open port
- while (acquire_sem(device_sem) == B_INTERRUPTED) ;
- if (is_parallel) {
- char name[256];
- sprintf(name, "/dev/parallel/%s", device_name);
- fd = ::open(name, O_WRONLY);
- if (fd < 0) {
- release_sem(device_sem);
- return openErr;
- }
- } else {
- device->SetFlowControl(B_HARDWARE_CONTROL); // Must be set before port is opened
- if (device->Open(device_name) > 0) {
- device->SetBlocking(true);
- device->SetTimeout(10000000);
- device->SetDTR(true);
- device->SetRTS(true);
- } else {
- release_sem(device_sem);
- return openErr;
- }
- }
-
- // Start input/output threads
- release_sem(device_sem);
- configure(config);
- while (acquire_sem(device_sem) == B_INTERRUPTED) ;
- while ((input_thread = spawn_thread(input_func, "Serial Input", B_NORMAL_PRIORITY, this)) == B_INTERRUPTED) ;
- resume_thread(input_thread);
- while ((output_thread = spawn_thread(output_func, "Serial Output", B_NORMAL_PRIORITY, this)) == B_INTERRUPTED) ;
- resume_thread(output_thread);
- release_sem(device_sem);
- return noErr;
- }
-
-
- /*
- * Read data from port
- */
-
- int16 BeSERDPort::prime_in(uint32 pb, uint32 dce)
- {
- // Send input command to input_thread
- read_done = false;
- read_pending = true;
- ThreadPacket p;
- p.pb = pb;
- WriteMacInt32(input_dt + serdtDCE, dce);
- while (send_data(input_thread, CMD_READ, &p, sizeof(ThreadPacket)) == B_INTERRUPTED) ;
- return 1; // Command in progress
- }
-
-
- /*
- * Write data to port
- */
-
- int16 BeSERDPort::prime_out(uint32 pb, uint32 dce)
- {
- // Send output command to output_thread
- write_done = false;
- write_pending = true;
- ThreadPacket p;
- p.pb = pb;
- WriteMacInt32(output_dt + serdtDCE, dce);
- while (send_data(output_thread, CMD_WRITE, &p, sizeof(ThreadPacket)) == B_INTERRUPTED) ;
- return 1; // Command in progress
- }
-
-
- /*
- * Control calls
- */
-
- int16 BeSERDPort::control(uint32 pb, uint32 dce, uint16 code)
- {
- switch (code) {
- case 1: // KillIO
- io_killed = true;
- suspend_thread(input_thread); // Unblock threads
- suspend_thread(output_thread);
- snooze(1000);
- resume_thread(input_thread);
- resume_thread(output_thread);
- while (read_pending || write_pending)
- snooze(10000);
- if (!is_parallel) {
- while (acquire_sem(device_sem) == B_INTERRUPTED) ;
- device->ClearInput();
- device->ClearOutput();
- release_sem(device_sem);
- }
- io_killed = false;
- return noErr;
-
- case kSERDConfiguration:
- if (configure(ReadMacInt16(pb + csParam)))
- return noErr;
- else
- return paramErr;
-
- case kSERDInputBuffer:
- return noErr; // Not supported under BeOS
-
- case kSERDSerHShake:
- set_handshake(pb + csParam, false);
- return noErr;
-
- case kSERDClearBreak:
- case kSERDSetBreak:
- return noErr; // Not supported under BeOS
-
- case kSERDBaudRate:
- if (!is_parallel) {
- uint16 rate = ReadMacInt16(pb + csParam);
- data_rate baud_rate;
- if (rate <= 50) {
- rate = 50; baud_rate = B_50_BPS;
- } else if (rate <= 75) {
- rate = 75; baud_rate = B_75_BPS;
- } else if (rate <= 110) {
- rate = 110; baud_rate = B_110_BPS;
- } else if (rate <= 134) {
- rate = 134; baud_rate = B_134_BPS;
- } else if (rate <= 150) {
- rate = 150; baud_rate = B_150_BPS;
- } else if (rate <= 200) {
- rate = 200; baud_rate = B_200_BPS;
- } else if (rate <= 300) {
- rate = 300; baud_rate = B_300_BPS;
- } else if (rate <= 600) {
- rate = 600; baud_rate = B_600_BPS;
- } else if (rate <= 1200) {
- rate = 1200; baud_rate = B_1200_BPS;
- } else if (rate <= 1800) {
- rate = 1800; baud_rate = B_1800_BPS;
- } else if (rate <= 2400) {
- rate = 2400; baud_rate = B_2400_BPS;
- } else if (rate <= 4800) {
- rate = 4800; baud_rate = B_4800_BPS;
- } else if (rate <= 9600) {
- rate = 9600; baud_rate = B_9600_BPS;
- } else if (rate <= 19200) {
- rate = 19200; baud_rate = B_19200_BPS;
- } else if (rate <= 31250) {
- rate = 31250; baud_rate = B_31250_BPS;
- } else if (rate <= 38400) {
- rate = 38400; baud_rate = B_38400_BPS;
- } else if (rate <= 57600) {
- rate = 57600; baud_rate = B_57600_BPS;
- }
- WriteMacInt16(pb + csParam, rate);
- acquire_sem(device_sem);
- if (device->SetDataRate(baud_rate) == B_OK) {
- release_sem(device_sem);
- return noErr;
- } else {
- release_sem(device_sem);
- return paramErr;
- }
- } else
- return noErr;
-
- case kSERDHandshake:
- case kSERDHandshakeRS232:
- set_handshake(pb + csParam, true);
- return noErr;
-
- case kSERDClockMIDI:
- if (!is_parallel) {
- while (acquire_sem(device_sem) == B_INTERRUPTED) ;
- device->SetParityMode(B_NO_PARITY);
- device->SetDataBits(B_DATA_BITS_8);
- device->SetStopBits(B_STOP_BITS_1);
- if (device->SetDataRate(B_31250_BPS) == B_OK) {
- release_sem(device_sem);
- return noErr;
- } else {
- release_sem(device_sem);
- return paramErr;
- }
- } else
- return noErr;
-
- case kSERDMiscOptions:
- drop_dtr_on_close = !(ReadMacInt8(pb + csParam) & kOptionPreserveDTR);
- return noErr;
-
- case kSERDAssertDTR:
- if (!is_parallel) {
- while (acquire_sem(device_sem) == B_INTERRUPTED) ;
- device->SetDTR(true);
- release_sem(device_sem);
- }
- return noErr;
-
- case kSERDNegateDTR:
- if (!is_parallel) {
- while (acquire_sem(device_sem) == B_INTERRUPTED) ;
- device->SetDTR(false);
- release_sem(device_sem);
- }
- return noErr;
-
- case kSERDSetPEChar:
- case kSERDSetPEAltChar:
- return noErr; // Not supported under BeOS
-
- case kSERDResetChannel:
- if (!is_parallel) {
- while (acquire_sem(device_sem) == B_INTERRUPTED) ;
- device->ClearInput();
- device->ClearOutput();
- release_sem(device_sem);
- }
- return noErr;
-
- case kSERDAssertRTS:
- if (!is_parallel) {
- while (acquire_sem(device_sem) == B_INTERRUPTED) ;
- device->SetRTS(true);
- release_sem(device_sem);
- }
- return noErr;
-
- case kSERDNegateRTS:
- if (!is_parallel) {
- while (acquire_sem(device_sem) == B_INTERRUPTED) ;
- device->SetRTS(false);
- release_sem(device_sem);
- }
- return noErr;
-
- case kSERD115KBaud:
- if (!is_parallel) {
- while (acquire_sem(device_sem) == B_INTERRUPTED) ;
- if (device->DataRate() != B_115200_BPS)
- if (device->SetDataRate(B_115200_BPS) != B_OK) {
- release_sem(device_sem);
- return paramErr;
- }
- release_sem(device_sem);
- }
- return noErr;
-
- case kSERD230KBaud:
- case kSERDSetHighSpeed:
- if (!is_parallel) {
- while (acquire_sem(device_sem) == B_INTERRUPTED) ;
- if (device->DataRate() != B_230400_BPS)
- if (device->SetDataRate(B_230400_BPS) != B_OK) {
- release_sem(device_sem);
- return paramErr;
- }
- release_sem(device_sem);
- }
- return noErr;
-
- default:
- printf("WARNING: SerialControl(): unimplemented control code %d\n", code);
- return controlErr;
- }
- }
-
-
- /*
- * Status calls
- */
-
- int16 BeSERDPort::status(uint32 pb, uint32 dce, uint16 code)
- {
- switch (code) {
- case kSERDInputCount:
- WriteMacInt32(pb + csParam, 0);
- if (!is_parallel) {
- int32 num = 0;
- while (acquire_sem(device_sem) == B_INTERRUPTED) ;
- device->NumCharsAvailable(&num);
- release_sem(device_sem);
- D(bug(" %d bytes in buffer\n", num));
- WriteMacInt32(pb + csParam, num);
- }
- return noErr;
-
- case kSERDStatus: {
- uint32 p = pb + csParam;
- WriteMacInt8(p + staCumErrs, cum_errors);
- cum_errors = 0;
- WriteMacInt8(p + staXOffSent, 0);
- WriteMacInt8(p + staXOffHold, 0);
- WriteMacInt8(p + staRdPend, read_pending);
- WriteMacInt8(p + staWrPend, write_pending);
- if (is_parallel) {
- WriteMacInt8(p + staCtsHold, 0);
- WriteMacInt8(p + staDsrHold, 0);
- WriteMacInt8(p + staModemStatus, dsrEvent | dcdEvent | ctsEvent);
- } else {
- while (acquire_sem(device_sem) == B_INTERRUPTED) ;
- WriteMacInt8(p + staCtsHold, !device->IsCTS());
- WriteMacInt8(p + staDsrHold, !device->IsDSR());
- WriteMacInt8(p + staModemStatus,
- (device->IsDSR() ? dsrEvent : 0)
- | (device->IsRI() ? riEvent : 0)
- | (device->IsDCD() ? dcdEvent : 0)
- | (device->IsCTS() ? ctsEvent : 0));
- release_sem(device_sem);
- }
- return noErr;
- }
-
- default:
- printf("WARNING: SerialStatus(): unimplemented status code %d\n", code);
- return statusErr;
- }
- }
-
-
- /*
- * Close serial port
- */
-
- int16 BeSERDPort::close()
- {
- // Kill threads
- status_t l;
- io_killed = true;
- if (input_thread > 0) {
- while (send_data(input_thread, CMD_QUIT, NULL, 0) == B_INTERRUPTED) ;
- if (read_pending) {
- suspend_thread(input_thread); // Unblock thread
- snooze(1000);
- resume_thread(input_thread);
- }
- while (wait_for_thread(input_thread, &l) == B_INTERRUPTED) ;
- }
- if (output_thread > 0) {
- while (send_data(output_thread, CMD_QUIT, NULL, 0) == B_INTERRUPTED) ;
- if (write_pending) {
- suspend_thread(output_thread); // Unblock thread
- snooze(1000);
- resume_thread(output_thread);
- }
- while (wait_for_thread(output_thread, &l) == B_INTERRUPTED) ;
- }
- input_thread = output_thread = 0;
-
- // Close port
- while (acquire_sem(device_sem) == B_INTERRUPTED) ;
- if (is_parallel) {
- ::close(fd);
- fd = -1;
- } else {
- if (drop_dtr_on_close)
- device->SetDTR(false);
- device->Close();
- }
- release_sem(device_sem);
- return noErr;
- }
-
-
- /*
- * Configure serial port with MacOS config word
- */
-
- bool BeSERDPort::configure(uint16 config)
- {
- D(bug(" configure %04x\n", config));
- if (is_parallel)
- return true;
-
- while (acquire_sem(device_sem) == B_INTERRUPTED) ;
-
- // Set number of stop bits
- switch (config & 0xc000) {
- case stop10:
- if (device->StopBits() != B_STOP_BITS_1)
- device->SetStopBits(B_STOP_BITS_1);
- break;
- case stop20:
- if (device->StopBits() != B_STOP_BITS_2)
- device->SetStopBits(B_STOP_BITS_2);
- break;
- default:
- release_sem(device_sem);
- return false;
- }
-
- // Set parity mode
- switch (config & 0x3000) {
- case noParity:
- if (device->ParityMode() != B_NO_PARITY)
- device->SetParityMode(B_NO_PARITY);
- break;
- case oddParity:
- if (device->ParityMode() != B_ODD_PARITY)
- device->SetParityMode(B_ODD_PARITY);
- break;
- case evenParity:
- if (device->ParityMode() != B_EVEN_PARITY)
- device->SetParityMode(B_EVEN_PARITY);
- break;
- default:
- release_sem(device_sem);
- return false;
- }
-
- // Set number of data bits
- switch (config & 0x0c00) {
- case data7:
- if (device->DataBits() != B_DATA_BITS_7)
- device->SetDataBits(B_DATA_BITS_7);
- break;
- case data8:
- if (device->DataBits() != B_DATA_BITS_8)
- device->SetDataBits(B_DATA_BITS_8);
- break;
- default:
- release_sem(device_sem);
- return false;
- }
-
- // Set baud rate
- data_rate baud_rate;
- switch (config & 0x03ff) {
- case baud150: baud_rate = B_150_BPS; break;
- case baud300: baud_rate = B_300_BPS; break;
- case baud600: baud_rate = B_600_BPS; break;
- case baud1200: baud_rate = B_1200_BPS; break;
- case baud1800: baud_rate = B_1800_BPS; break;
- case baud2400: baud_rate = B_2400_BPS; break;
- case baud4800: baud_rate = B_4800_BPS; break;
- case baud9600: baud_rate = B_9600_BPS; break;
- case baud19200: baud_rate = B_19200_BPS; break;
- case baud38400: baud_rate = B_38400_BPS; break;
- case baud57600: baud_rate = B_57600_BPS; break;
- default:
- release_sem(device_sem);
- return false;
- }
-
- 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));
- if (device->DataRate() != baud_rate) {
- bool res = device->SetDataRate(baud_rate) == B_OK;
- release_sem(device_sem);
- return res;
- } else {
- release_sem(device_sem);
- return true;
- }
- }
-
-
- /*
- * Set serial handshaking
- */
-
- void BeSERDPort::set_handshake(uint32 s, bool with_dtr)
- {
- D(bug(" set_handshake %02x %02x %02x %02x %02x %02x %02x %02x\n",
- ReadMacInt8(s + 0), ReadMacInt8(s + 1), ReadMacInt8(s + 2), ReadMacInt8(s + 3),
- ReadMacInt8(s + 4), ReadMacInt8(s + 5), ReadMacInt8(s + 6), ReadMacInt8(s + 7)));
- if (is_parallel)
- return;
-
- uint32 flow;
- if (with_dtr) {
- if (ReadMacInt8(s + shkFCTS) || ReadMacInt8(s + shkFDTR))
- flow = B_HARDWARE_CONTROL;
- else
- flow = B_SOFTWARE_CONTROL;
- } else {
- if (ReadMacInt8(s + shkFCTS))
- flow = B_HARDWARE_CONTROL;
- else
- flow = B_SOFTWARE_CONTROL;
- }
-
- D(bug(" %sware flow control\n", flow == B_HARDWARE_CONTROL ? "hard" : "soft"));
- while (acquire_sem(device_sem) == B_INTERRUPTED) ;
- if (device->FlowControl() != flow) {
- device->Close();
- device->SetFlowControl(flow);
- device->Open(device_name);
- }
- release_sem(device_sem);
- }
-
-
- /*
- * Data input thread
- */
-
- status_t BeSERDPort::input_func(void *arg)
- {
- BeSERDPort *s = (BeSERDPort *)arg;
- for (;;) {
-
- // Wait for commands
- thread_id sender;
- ThreadPacket p;
- uint32 code = receive_data(&sender, &p, sizeof(ThreadPacket));
- if (code == CMD_QUIT)
- break;
- if (code != CMD_READ)
- continue;
-
- // Execute command
- void *buf = Mac2HostAddr(ReadMacInt32(p.pb + ioBuffer));
- uint32 length = ReadMacInt32(p.pb + ioReqCount);
- D(bug("input_func waiting for %ld bytes of data...\n", length));
- int32 actual;
-
- // Buffer in kernel space?
- if ((uint32)buf < 0x80000000) {
-
- // Yes, transfer via buffer
- actual = 0;
- while (length) {
- uint32 transfer_size = (length > TMP_BUF_SIZE) ? TMP_BUF_SIZE : length;
- int32 transferred;
- acquire_sem(s->device_sem);
- if (s->is_parallel) {
- if ((transferred = read(s->fd, s->tmp_in_buf, transfer_size)) < 0 || s->io_killed) {
- // Error
- actual = transferred;
- release_sem(s->device_sem);
- break;
- }
- } else {
- if ((transferred = s->device->Read(s->tmp_in_buf, transfer_size)) < 0 || s->io_killed) {
- // Error
- actual = transferred;
- release_sem(s->device_sem);
- break;
- }
- }
- release_sem(s->device_sem);
- memcpy(buf, s->tmp_in_buf, transferred);
- buf = (void *)((uint8 *)buf + transferred);
- length -= transferred;
- actual += transferred;
- }
-
- } else {
-
- // No, transfer directly
- acquire_sem(s->device_sem);
- if (s->is_parallel)
- actual = read(s->fd, buf, length);
- else
- actual = s->device->Read(buf, length);
- release_sem(s->device_sem);
- }
-
- D(bug(" %ld bytes received\n", actual));
-
- #if MONITOR
- bug("Receiving serial data:\n");
- uint8 *adr = Mac2HostAddr(ReadMacInt32(p.pb + ioBuffer));
- for (int i=0; i<actual; i++) {
- bug("%02x ", adr[i]);
- }
- bug("\n");
- #endif
-
- // KillIO called? Then simply return
- if (s->io_killed) {
-
- WriteMacInt16(p.pb + ioResult, abortErr);
- WriteMacInt32(p.pb + ioActCount, 0);
- s->read_pending = s->read_done = false;
-
- } else {
-
- // Set error code
- if (actual >= 0) {
- WriteMacInt32(p.pb + ioActCount, actual);
- WriteMacInt32(s->input_dt + serdtResult, noErr);
- } else {
- WriteMacInt32(p.pb + ioActCount, 0);
- WriteMacInt32(s->input_dt + serdtResult, readErr);
- }
-
- // Trigger serial interrupt
- D(bug(" triggering serial interrupt\n"));
- s->read_done = true;
- SetInterruptFlag(INTFLAG_SERIAL);
- TriggerInterrupt();
- }
- }
- return 0;
- }
-
-
- /*
- * Data output thread
- */
-
- status_t BeSERDPort::output_func(void *arg)
- {
- BeSERDPort *s = (BeSERDPort *)arg;
- for (;;) {
-
- // Wait for commands
- thread_id sender;
- ThreadPacket p;
- uint32 code = receive_data(&sender, &p, sizeof(ThreadPacket));
- if (code == CMD_QUIT)
- break;
- if (code != CMD_WRITE)
- continue;
-
- // Execute command
- void *buf = Mac2HostAddr(ReadMacInt32(p.pb + ioBuffer));
- uint32 length = ReadMacInt32(p.pb + ioReqCount);
- D(bug("output_func transmitting %ld bytes of data...\n", length));
- int32 actual;
-
- #if MONITOR
- bug("Sending serial data:\n");
- uint8 *adr = (uint8 *)buf;
- for (int i=0; i<length; i++) {
- bug("%02x ", adr[i]);
- }
- bug("\n");
- #endif
-
- // Buffer in kernel space?
- if ((uint32)buf < 0x80000000) {
-
- // Yes, transfer via buffer
- actual = 0;
- while (length) {
- uint32 transfer_size = (length > TMP_BUF_SIZE) ? TMP_BUF_SIZE : length;
- memcpy(s->tmp_out_buf, buf, transfer_size);
- int32 transferred;
- acquire_sem(s->device_sem);
- if (s->is_parallel) {
- if ((transferred = write(s->fd, s->tmp_out_buf, transfer_size)) < transfer_size || s->io_killed) {
- if (transferred < 0) // Error
- actual = transferred;
- else
- actual += transferred;
- release_sem(s->device_sem);
- break;
- }
- } else {
- if ((transferred = s->device->Write(s->tmp_out_buf, transfer_size)) < transfer_size || s->io_killed) {
- if (transferred < 0) // Error
- actual = transferred;
- else
- actual += transferred;
- release_sem(s->device_sem);
- break;
- }
- }
- release_sem(s->device_sem);
- if (transferred > transfer_size) // R3 parallel port driver bug
- transferred = transfer_size;
- buf = (void *)((uint8 *)buf + transferred);
- length -= transferred;
- actual += transferred;
- }
-
- } else {
-
- // No, transfer directly
- acquire_sem(s->device_sem);
- if (s->is_parallel)
- actual = write(s->fd, buf, length);
- else
- actual = s->device->Write(buf, length);
- release_sem(s->device_sem);
- if (actual > length) // R3 parallel port driver bug
- actual = length;
- }
-
- D(bug(" %ld bytes transmitted\n", actual));
-
- // KillIO called? Then simply return
- if (s->io_killed) {
-
- WriteMacInt16(p.pb + ioResult, abortErr);
- WriteMacInt32(p.pb + ioActCount, 0);
- s->write_pending = s->write_done = false;
-
- } else {
-
- // Set error code
- if (actual >= 0) {
- WriteMacInt32(p.pb + ioActCount, actual);
- WriteMacInt32(s->output_dt + serdtResult, noErr);
- } else {
- WriteMacInt32(p.pb + ioActCount, 0);
- WriteMacInt32(s->output_dt + serdtResult, writErr);
- }
-
- // Trigger serial interrupt
- D(bug(" triggering serial interrupt\n"));
- s->write_done = true;
- SetInterruptFlag(INTFLAG_SERIAL);
- TriggerInterrupt();
- }
- }
- return 0;
- }
-