1 /*
2 * Copyright 2009-2010, François Revol, <revol@free.fr>.
3 * Sponsored by TuneTracker Systems.
4 * Based on the Haiku usb_serial driver which is:
5 *
6 * Copyright (c) 2007-2008 by Michael Lotz
7 * Heavily based on the original usb_serial driver which is:
8 *
9 * Copyright (c) 2003 by Siarzhuk Zharski <imker@gmx.li>
10 * Distributed under the terms of the MIT License.
11 */
12 #include "SerialDevice.h"
13 #include "UART.h"
14
15 #include <sys/ioctl.h>
16
SerialDevice(const struct serial_support_descriptor * device,uint32 ioBase,uint32 irq,const SerialDevice * master)17 SerialDevice::SerialDevice(const struct serial_support_descriptor *device,
18 uint32 ioBase, uint32 irq, const SerialDevice *master)
19 : /*fSupportDescriptor(device->descriptor),
20 fDevice(device),
21 fDescription(device->descriptor->name),*/
22 fSupportDescriptor(device),
23 fDevice(NULL),
24 fDescription(device->name),
25 //
26 fDeviceOpen(false),
27 fDeviceRemoved(false),
28 fBus(device->bus),
29 fIOBase(ioBase),
30 fIRQ(irq),
31 fMaster(master),
32 fCachedIER(0x0),
33 fCachedIIR(0x1),
34 fPendingDPC(0),
35 fReadBufferAvail(0),
36 fReadBufferIn(0),
37 fReadBufferOut(0),
38 fReadBufferSem(-1),
39 fWriteBufferAvail(0),
40 fWriteBufferIn(0),
41 fWriteBufferOut(0),
42 fWriteBufferSem(-1),
43 fDoneRead(-1),
44 fDoneWrite(-1),
45 fControlOut(0),
46 fInputStopped(false),
47 fMasterTTY(NULL),
48 fSlaveTTY(NULL),
49 fSystemTTYCookie(NULL),
50 fDeviceTTYCookie(NULL),
51 fDeviceThread(-1),
52 fStopDeviceThread(false)
53 {
54 memset(&fTTYConfig, 0, sizeof(termios));
55 fTTYConfig.c_cflag = B9600 | CS8 | CREAD;
56 memset(fReadBuffer, 'z', DEF_BUFFER_SIZE);
57 memset(fWriteBuffer, 'z', DEF_BUFFER_SIZE);
58 }
59
60
~SerialDevice()61 SerialDevice::~SerialDevice()
62 {
63 Removed();
64
65 if (fDoneWrite >= B_OK)
66 delete_sem(fDoneWrite);
67 if (fReadBufferSem >= B_OK)
68 delete_sem(fReadBufferSem);
69 if (fWriteBufferSem >= B_OK)
70 delete_sem(fWriteBufferSem);
71 }
72
73
74 bool
Probe()75 SerialDevice::Probe()
76 {
77 uint8 msr;
78 msr = ReadReg8(MSR);
79 // just in case read twice to make sure the "delta" bits are 0
80 msr = ReadReg8(MSR);
81 // this should be enough to probe for the device for now
82 // we might want to check the scratch reg, and try identifying
83 // the model as in:
84 // http://en.wikibooks.org/wiki/Serial_Programming/8250_UART_Programming#Software_Identification_of_the_UART
85 return (msr != 0xff);
86 }
87
88
89 status_t
Init()90 SerialDevice::Init()
91 {
92 fDoneWrite = create_sem(0, "pc_serial:done_write");
93 fReadBufferSem = create_sem(0, "pc_serial:done_read");
94 fWriteBufferSem = create_sem(0, "pc_serial:done_write");
95
96 // disable IRQ
97 fCachedIER = 0;
98 WriteReg8(IER, fCachedIER);
99
100 // disable DLAB
101 WriteReg8(LCR, 0);
102
103 return B_OK;
104 }
105
106
107 void
SetModes(struct termios * tios)108 SerialDevice::SetModes(struct termios *tios)
109 {
110 //TRACE_FUNCRES(trace_termios, tios);
111 spin(10000);
112 uint32 baudIndex = tios->c_cflag & CBAUD;
113 if (baudIndex > BLAST)
114 baudIndex = BLAST;
115
116 // update our master config in full
117 memcpy(&fTTYConfig, tios, sizeof(termios));
118 fTTYConfig.c_cflag &= ~CBAUD;
119 fTTYConfig.c_cflag |= baudIndex;
120
121 // only apply the relevant parts to the device side
122 termios config;
123 memset(&config, 0, sizeof(termios));
124 config.c_cflag = tios->c_cflag;
125 config.c_cflag &= ~CBAUD;
126 config.c_cflag |= baudIndex;
127
128 // update the termios of the device side
129 gTTYModule->tty_control(fDeviceTTYCookie, TCSETA, &config, sizeof(termios));
130
131 uint8 lcr = 0;
132 uint16 divisor = SupportDescriptor()->bauds[baudIndex];
133
134 switch (tios->c_cflag & CSIZE) {
135 #if CS5 != CS7
136 // in case someday...
137 case CS5:
138 lcr |= LCR_5BIT;
139 break;
140 case CS6:
141 lcr |= LCR_6BIT;
142 break;
143 #endif
144 case CS7:
145 lcr |= LCR_7BIT;
146 break;
147 case CS8:
148 default:
149 lcr |= LCR_8BIT;
150 break;
151 }
152
153 if (tios->c_cflag & CSTOPB)
154 lcr |= LCR_2STOP;
155 if (tios->c_cflag & PARENB)
156 lcr |= LCR_P_EN;
157 if ((tios->c_cflag & PARODD) == 0)
158 lcr |= LCR_P_EVEN;
159
160 if (baudIndex == B0) {
161 // disable
162 MaskReg8(MCR, MCR_DTR);
163 } else {
164 // set FCR now,
165 // 16650 and later chips have another reg at 2 when DLAB=1
166 uint8 fcr = FCR_ENABLE | FCR_RX_RST | FCR_TX_RST | FCR_F_8 | FCR_F64EN;
167 // enable fifo
168 //fcr = 0;
169 WriteReg8(FCR, fcr);
170
171 // unmask the divisor latch regs
172 WriteReg8(LCR, lcr | LCR_DLAB);
173 // set divisor
174 WriteReg8(DLLB, divisor & 0x00ff);
175 WriteReg8(DLHB, divisor >> 8);
176 //WriteReg8(2,0);
177
178 }
179 // set control lines, and disable divisor latch reg
180 WriteReg8(LCR, lcr);
181
182
183 #if 0
184 uint16 newControl = fControlOut;
185
186 static uint32 baudRates[] = {
187 0x00000000, //B0
188 0x00000032, //B50
189 0x0000004B, //B75
190 0x0000006E, //B110
191 0x00000086, //B134
192 0x00000096, //B150
193 0x000000C8, //B200
194 0x0000012C, //B300
195 0x00000258, //B600
196 0x000004B0, //B1200
197 0x00000708, //B1800
198 0x00000960, //B2400
199 0x000012C0, //B4800
200 0x00002580, //B9600
201 0x00004B00, //B19200
202 0x00009600, //B38400
203 0x0000E100, //B57600
204 0x0001C200, //B115200
205 0x00038400, //B230400
206 0x00070800, //460800
207 0x000E1000, //921600
208 };
209
210 usb_serial_line_coding lineCoding;
211 lineCoding.speed = baudRates[baudIndex];
212 lineCoding.stopbits = (tios->c_cflag & CSTOPB) ? LC_STOP_BIT_2 : LC_STOP_BIT_1;
213
214 if (tios->c_cflag & PARENB) {
215 lineCoding.parity = LC_PARITY_EVEN;
216 if (tios->c_cflag & PARODD)
217 lineCoding.parity = LC_PARITY_ODD;
218 } else
219 lineCoding.parity = LC_PARITY_NONE;
220
221 lineCoding.databits = (tios->c_cflag & CS8) ? 8 : 7;
222
223 if (lineCoding.speed == 0) {
224 newControl &= 0xfffffffe;
225 lineCoding.speed = fLineCoding.speed;
226 } else
227 newControl = CLS_LINE_DTR;
228
229 if (fControlOut != newControl) {
230 fControlOut = newControl;
231 TRACE("newctrl send to modem: 0x%08x\n", newControl);
232 SetControlLineState(newControl);
233 }
234
235 if (memcmp(&lineCoding, &fLineCoding, sizeof(usb_serial_line_coding)) != 0) {
236 fLineCoding.speed = lineCoding.speed;
237 fLineCoding.stopbits = lineCoding.stopbits;
238 fLineCoding.databits = lineCoding.databits;
239 fLineCoding.parity = lineCoding.parity;
240 TRACE("send to modem: speed %d sb: 0x%08x db: 0x%08x parity: 0x%08x\n",
241 fLineCoding.speed, fLineCoding.stopbits, fLineCoding.databits,
242 fLineCoding.parity);
243 SetLineCoding(&fLineCoding);
244 }
245 #endif
246 }
247
248
249 bool
Service(struct tty * tty,uint32 op,void * buffer,size_t length)250 SerialDevice::Service(struct tty *tty, uint32 op, void *buffer, size_t length)
251 {
252 uint8 msr;
253 status_t err;
254
255 TRACE("%s(,0x%08lx,,%d)\n", __FUNCTION__, op, length);
256 if (tty != fMasterTTY)
257 return false;
258
259 TRACE("%s(,0x%08lx,,%d)\n", __FUNCTION__, op, length);
260
261 switch (op) {
262 case TTYENABLE:
263 {
264 bool enable = *(bool *)buffer;
265 TRACE("TTYENABLE: %sable\n", enable ? "en" : "dis");
266
267 if (enable) {
268 //XXX:must call SetModes();
269 err = install_io_interrupt_handler(IRQ(), pc_serial_interrupt, this, 0);
270 TRACE("installing irq handler for %d: %s\n", IRQ(), strerror(err));
271 } else {
272 // remove the handler
273 remove_io_interrupt_handler(IRQ(), pc_serial_interrupt, this);
274 // disable IRQ
275 fCachedIER = 0;
276 WriteReg8(IER, fCachedIER);
277 WriteReg8(MCR, 0);
278 }
279
280 msr = ReadReg8(MSR);
281
282 SignalControlLineState(TTYHWDCD, msr & MSR_DCD);
283 SignalControlLineState(TTYHWCTS, msr & MSR_CTS);
284
285 if (enable) {
286 //
287 WriteReg8(MCR, MCR_DTR | MCR_RTS | MCR_IRQ_EN /*| MCR_LOOP*//*XXXXXXX*/);
288 // enable irqs
289 fCachedIER = IER_RLS | IER_MS | IER_RDA;
290 WriteReg8(IER, fCachedIER);
291 //WriteReg8(IER, IER_RDA);
292 }
293
294 return true;
295 }
296
297 case TTYISTOP:
298 fInputStopped = *(bool *)buffer;
299 TRACE("TTYISTOP: %sstopped\n", fInputStopped ? "" : "not ");
300
301 if (fInputStopped)
302 MaskReg8(MCR, MCR_RTS);
303 else
304 OrReg8(MCR, MCR_RTS);
305
306 //gTTYModule->ttyhwsignal(ptty, ddr, TTYHWCTS, false);
307 //SignalControlLineState(TTYHWCTS, !fInputStopped);
308 //msr = ReadReg8(MSR);
309 //SignalControlLineState(TTYHWCTS, msr & MSR_CTS);
310 return true;
311
312 case TTYGETSIGNALS:
313 TRACE("TTYGETSIGNALS\n");
314 msr = ReadReg8(MSR);
315 SignalControlLineState(TTYHWDCD, msr & MSR_DCD);
316 SignalControlLineState(TTYHWCTS, msr & MSR_CTS);
317 SignalControlLineState(TTYHWDSR, msr & MSR_DSR);
318 SignalControlLineState(TTYHWRI, msr & MSR_RI);
319 return true;
320
321 case TTYSETMODES:
322 TRACE("TTYSETMODES\n");
323 SetModes((struct termios *)buffer);
324 //WriteReg8(IER, IER_RLS | IER_MS | IER_RDA);
325 return true;
326
327 case TTYSETDTR:
328 case TTYSETRTS:
329 {
330 bool set = *(bool *)buffer;
331 uint8 bit = op == TTYSETDTR ? MCR_DTR : MCR_RTS;
332 if (set)
333 OrReg8(MCR, bit);
334 else
335 MaskReg8(MCR, bit);
336
337 return true;
338 }
339
340 case TTYOSTART:
341 TRACE("TTYOSTART\n");
342 // enable irqs
343 fCachedIER |= IER_THRE;
344 // XXX: toggle the bit to make VirtualBox happy !?
345 WriteReg8(IER, fCachedIER & ~IER_THRE);
346 WriteReg8(IER, fCachedIER);
347 return true;
348 case TTYOSYNC:
349 TRACE("TTYOSYNC\n");
350 return (ReadReg8(LSR) & (LSR_THRE | LSR_TSRE)) == (LSR_THRE | LSR_TSRE);
351 return true;
352 case TTYSETBREAK:
353 {
354 bool set = *(bool *)buffer;
355 if (set)
356 OrReg8(MCR, LCR_BREAK);
357 else
358 MaskReg8(MCR, LCR_BREAK);
359
360 return true;
361 }
362 case TTYFLUSH:
363 {
364 int directions = *(int*)buffer;
365 uint8 mask = 0;
366 if (directions & TCIFLUSH)
367 mask |= FCR_RX_RST;
368 if (directions & TCOFLUSH)
369 mask |= FCR_TX_RST;
370 // These bits clear themselves when flushing is complete
371 OrReg8(FCR, mask);
372
373 return true;
374 }
375 default:
376 return false;
377 }
378
379 return false;
380 }
381
382
383 bool
IsInterruptPending()384 SerialDevice::IsInterruptPending()
385 {
386 TRACE(("IsInterruptPending()\n"));
387
388 // because reading the IIR acknowledges some IRQ conditions,
389 // the next time we'll read we'll miss the IRQ condition
390 // so we just cache the value for the real handler
391 fCachedIIR = ReadReg8(IIR);
392
393 bool pending = (fCachedIIR & IIR_PENDING) == 0;
394
395 if (pending) {
396 // temporarily mask the IRQ
397 // else VirtualBox triggers one per every written byte it seems
398 // not sure it's required on real hardware
399 WriteReg8(IER, fCachedIER & ~(IER_RLS | IER_MS | IER_RDA | IER_THRE));
400
401 atomic_add(&fPendingDPC, 1);
402 }
403
404 return pending; // 0 means yes
405 }
406
407
408 int32
InterruptHandler()409 SerialDevice::InterruptHandler()
410 {
411 int32 ret = B_UNHANDLED_INTERRUPT;
412 //XXX: what should we do here ? (certainly not use a mutex !)
413
414 uint8 iir, lsr, msr;
415 uint8 buffer[64];
416 int tries = 8; // avoid busy looping
417 TRACE(("InterruptHandler()\n"));
418
419 // start with the first (cached) irq condition
420 iir = fCachedIIR;
421 while ((iir & IIR_PENDING) == 0) { // 0 means yes
422 status_t status;
423 size_t bytesLeft;
424 size_t readable = 0;
425 size_t fifoavail = 1;
426 size_t i;
427
428 //DEBUG
429 // for (int count = 0; ReadReg8(LSR) & LSR_DR; count++)
430 // gTTYModule->ttyin(&fTTY, &fRover, ReadReg8(RBR));
431
432 switch (iir & (IIR_IMASK | IIR_TO)) {
433 case IIR_THRE:
434 TRACE(("IIR_THRE\n"));
435 // check how much fifo we can use
436 //XXX: move to Init() ?
437 if ((iir & IIR_FMASK) == IIR_FMASK)
438 fifoavail = 16;
439 if (iir & IIR_F64EN)
440 fifoavail = 64;
441 // we're not open... just discard the data
442 if (!IsOpen())
443 break;
444 gTTYModule->tty_control(fDeviceTTYCookie, FIONREAD, &readable,
445 sizeof(readable));
446 TRACE("%s: FIONREAD: %d\n", __FUNCTION__, readable);
447
448 if (readable == 0) {
449 release_sem_etc(fDoneWrite, 1, B_DO_NOT_RESCHEDULE);
450 // mask it until there's data again
451 fCachedIER &= ~IER_THRE;
452 break;
453 }
454
455 bytesLeft = MIN(fifoavail, sizeof(buffer));
456 bytesLeft = MIN(bytesLeft, readable);
457 TRACE("%s: left %d\n", __FUNCTION__, bytesLeft);
458 status = gTTYModule->tty_read(fDeviceTTYCookie, buffer, &bytesLeft);
459 TRACE("%s: tty_read: %d\n", __FUNCTION__, bytesLeft);
460 if (status != B_OK) {
461 dprintf(DRIVER_NAME ": irq: tty_read: %s\n", strerror(status));
462 break;
463 }
464
465 for (i = 0; i < bytesLeft; i++) {
466 WriteReg8(THB, buffer[i]);
467 }
468
469 break;
470 case IIR_TO:
471 case IIR_TO | IIR_RDA:
472 // timeout: FALLTHROUGH
473 case IIR_RDA:
474 TRACE(("IIR_TO/RDA\n"));
475 // while data is ready... and we have room for it, get it
476 bytesLeft = sizeof(buffer);
477 for (i = 0; i < bytesLeft && (ReadReg8(LSR) & LSR_DR); i++) {
478 buffer[i] = ReadReg8(RBR);
479 }
480 // we're not open... just discard the data
481 if (!IsOpen())
482 break;
483 // we shouldn't block here but it's < 256 bytes anyway
484 status = gTTYModule->tty_write(fDeviceTTYCookie, buffer, &i);
485 if (status != B_OK) {
486 dprintf(DRIVER_NAME ": irq: tty_write: %s\n", strerror(status));
487 break;
488 }
489 break;
490 case IIR_RLS:
491 TRACE(("IIR_RLS\n"));
492 // ack
493 lsr = ReadReg8(LSR);
494 //XXX: handle this somehow
495 break;
496 case IIR_MS:
497 TRACE(("IIR_MS\n"));
498 // modem signals changed
499 msr = ReadReg8(MSR);
500 if (!IsOpen())
501 break;
502 if (msr & MSR_DDCD)
503 SignalControlLineState(TTYHWDCD, msr & MSR_DCD);
504 if (msr & MSR_DCTS)
505 SignalControlLineState(TTYHWCTS, msr & MSR_CTS);
506 if (msr & MSR_DDSR)
507 SignalControlLineState(TTYHWDSR, msr & MSR_DSR);
508 if (msr & MSR_TERI)
509 SignalControlLineState(TTYHWRI, msr & MSR_RI);
510 break;
511 default:
512 TRACE(("IIR_?\n"));
513 // something happened
514 break;
515 }
516 ret = B_HANDLED_INTERRUPT;
517 TRACE(("IRQ:h\n"));
518
519 // enough for now
520 if (tries-- == 0)
521 break;
522
523 // check the next IRQ condition
524 iir = ReadReg8(IIR);
525 }
526
527 atomic_add(&fPendingDPC, -1);
528
529 // unmask IRQ
530 WriteReg8(IER, fCachedIER);
531
532 TRACE_FUNCRET("< IRQ:%d\n", ret);
533 return ret;
534 }
535
536
537 status_t
Open(uint32 flags)538 SerialDevice::Open(uint32 flags)
539 {
540 status_t status = B_OK;
541
542 if (fDeviceOpen)
543 return B_BUSY;
544
545 if (fDeviceRemoved)
546 return B_DEV_NOT_READY;
547
548 status = gTTYModule->tty_create(pc_serial_service, NULL, &fMasterTTY);
549 if (status != B_OK) {
550 TRACE_ALWAYS("open: failed to init master tty\n");
551 return status;
552 }
553
554 status = gTTYModule->tty_create(pc_serial_service, fMasterTTY, &fSlaveTTY);
555 if (status != B_OK) {
556 TRACE_ALWAYS("open: failed to init slave tty\n");
557 gTTYModule->tty_destroy(fMasterTTY);
558 return status;
559 }
560
561 status = gTTYModule->tty_create_cookie(fMasterTTY, fSlaveTTY, O_RDWR, &fSystemTTYCookie);
562 if (status != B_OK) {
563 TRACE_ALWAYS("open: failed to init system tty cookie\n");
564 gTTYModule->tty_destroy(fMasterTTY);
565 gTTYModule->tty_destroy(fSlaveTTY);
566 return status;
567 }
568
569 status = gTTYModule->tty_create_cookie(fSlaveTTY, fMasterTTY, O_RDWR, &fDeviceTTYCookie);
570 if (status != B_OK) {
571 TRACE_ALWAYS("open: failed to init device tty cookie\n");
572 gTTYModule->tty_destroy_cookie(fSystemTTYCookie);
573 gTTYModule->tty_destroy(fMasterTTY);
574 gTTYModule->tty_destroy(fSlaveTTY);
575 return status;
576 }
577
578 ResetDevice();
579
580 //XXX: we shouldn't have to do this!
581 bool en = true;
582 Service(fMasterTTY, TTYENABLE, &en, sizeof(en));
583
584 if (status < B_OK) {
585 TRACE_ALWAYS("open: failed to open tty\n");
586 return status;
587 }
588
589 // set our config (will propagate to the slave config as well in SetModes()
590 gTTYModule->tty_control(fSystemTTYCookie, TCSETA, &fTTYConfig,
591 sizeof(termios));
592
593 #if 0
594 fDeviceThread = spawn_kernel_thread(_DeviceThread, "usb_serial device thread",
595 B_NORMAL_PRIORITY, this);
596
597 if (fDeviceThread < B_OK) {
598 TRACE_ALWAYS("open: failed to spawn kernel thread\n");
599 return fDeviceThread;
600 }
601
602 resume_thread(fDeviceThread);
603
604 fControlOut = CLS_LINE_DTR | CLS_LINE_RTS;
605 SetControlLineState(fControlOut);
606
607 status = gUSBModule->queue_interrupt(fControlPipe, fInterruptBuffer,
608 fInterruptBufferSize, InterruptCallbackFunction, this);
609 if (status < B_OK)
610 TRACE_ALWAYS("failed to queue initial interrupt\n");
611
612 #endif
613 fDeviceOpen = true;
614 return B_OK;
615 }
616
617
618 status_t
Read(char * buffer,size_t * numBytes)619 SerialDevice::Read(char *buffer, size_t *numBytes)
620 {
621 if (fDeviceRemoved) {
622 *numBytes = 0;
623 return B_DEV_NOT_READY;
624 }
625
626 status_t status;
627
628 status = gTTYModule->tty_read(fSystemTTYCookie, buffer, numBytes);
629
630 return status;
631 }
632
633
634 status_t
Write(const char * buffer,size_t * numBytes)635 SerialDevice::Write(const char *buffer, size_t *numBytes)
636 {
637 TRACE("%s(,&%d)\n", __FUNCTION__, *numBytes);
638 if (fDeviceRemoved) {
639 *numBytes = 0;
640 return B_DEV_NOT_READY;
641 }
642
643 status_t status;
644 size_t bytesLeft = *numBytes;
645 *numBytes = 0;
646
647 while (bytesLeft > 0) {
648 size_t length = MIN(bytesLeft, 256);
649 // TODO: This is an ugly hack; We use a small buffer size so that
650 // we don't overrun the tty line buffer and cause it to block. While
651 // that isn't a problem, we shouldn't just hardcode the value here.
652
653 TRACE("%s: tty_write(,&%d)\n", __FUNCTION__, length);
654 status = gTTYModule->tty_write(fSystemTTYCookie, buffer,
655 &length);
656 if (status != B_OK) {
657 TRACE_ALWAYS("failed to write to tty: %s\n", strerror(status));
658 return status;
659 }
660
661 buffer += length;
662 *numBytes += length;
663 bytesLeft -= length;
664
665 // XXX: WTF: this ought to be done by the tty module calling service_func!
666 // enable irqs
667 Service(fMasterTTY, TTYOSTART, NULL, 0);
668 }
669
670 status = acquire_sem_etc(fDoneWrite, 1, B_CAN_INTERRUPT, 0);
671 if (status != B_OK) {
672 TRACE_ALWAYS("write: failed to get write done sem "
673 "0x%08x\n", status);
674 return status;
675 }
676
677
678 if (*numBytes > 0)
679 return B_OK;
680
681 return B_ERROR;
682 }
683
684
685 status_t
Control(uint32 op,void * arg,size_t length)686 SerialDevice::Control(uint32 op, void *arg, size_t length)
687 {
688 status_t status = B_OK;
689
690 if (fDeviceRemoved)
691 return B_DEV_NOT_READY;
692
693 status = gTTYModule->tty_control(fSystemTTYCookie, op, arg, length);
694
695 return status;
696 }
697
698
699 status_t
Select(uint8 event,uint32 ref,selectsync * sync)700 SerialDevice::Select(uint8 event, uint32 ref, selectsync *sync)
701 {
702 if (fDeviceRemoved)
703 return B_DEV_NOT_READY;
704
705 return gTTYModule->tty_select(fSystemTTYCookie, event, ref, sync);
706 }
707
708
709 status_t
DeSelect(uint8 event,selectsync * sync)710 SerialDevice::DeSelect(uint8 event, selectsync *sync)
711 {
712 if (fDeviceRemoved)
713 return B_DEV_NOT_READY;
714
715 return gTTYModule->tty_deselect(fSystemTTYCookie, event, sync);
716 }
717
718
719 status_t
Close()720 SerialDevice::Close()
721 {
722 status_t status = B_OK;
723
724 OnClose();
725
726 if (!fDeviceRemoved) {
727 #if 0
728 gUSBModule->cancel_queued_transfers(fReadPipe);
729 gUSBModule->cancel_queued_transfers(fWritePipe);
730 gUSBModule->cancel_queued_transfers(fControlPipe);
731 #endif
732 }
733
734 fDeviceOpen = false;
735
736 gTTYModule->tty_close_cookie(fSystemTTYCookie);
737 gTTYModule->tty_close_cookie(fDeviceTTYCookie);
738
739 //XXX: we shouldn't have to do this!
740 bool en = false;
741 Service(fMasterTTY, TTYENABLE, &en, sizeof(en));
742
743 return status;
744 }
745
746
747 status_t
Free()748 SerialDevice::Free()
749 {
750 status_t status = B_OK;
751
752 // wait until currently executing DPC is done. In case another one
753 // is run beyond this point it will just bail out on !IsOpen().
754 //while (atomic_get(&fPendingDPC))
755 // snooze(1000);
756
757 gTTYModule->tty_destroy_cookie(fSystemTTYCookie);
758 gTTYModule->tty_destroy_cookie(fDeviceTTYCookie);
759 fSystemTTYCookie = fDeviceTTYCookie = NULL;
760
761 gTTYModule->tty_destroy(fMasterTTY);
762 gTTYModule->tty_destroy(fSlaveTTY);
763 fMasterTTY = fSlaveTTY = NULL;
764
765 return status;
766 }
767
768
769 void
Removed()770 SerialDevice::Removed()
771 {
772 if (fDeviceRemoved)
773 return;
774
775 // notifies us that the device was removed
776 fDeviceRemoved = true;
777
778 // we need to ensure that we do not use the device anymore
779 fStopDeviceThread = true;
780 fInputStopped = false;
781 #if 0
782 gUSBModule->cancel_queued_transfers(fReadPipe);
783 gUSBModule->cancel_queued_transfers(fWritePipe);
784 gUSBModule->cancel_queued_transfers(fControlPipe);
785 #endif
786
787 int32 result = B_OK;
788 wait_for_thread(fDeviceThread, &result);
789 fDeviceThread = -1;
790 }
791
792
793 status_t
AddDevice(const serial_config_descriptor * config)794 SerialDevice::AddDevice(const serial_config_descriptor *config)
795 {
796 // default implementation - does nothing
797 return B_ERROR;
798 }
799
800
801 status_t
ResetDevice()802 SerialDevice::ResetDevice()
803 {
804 // default implementation - does nothing
805 return B_OK;
806 }
807
808
809 #if 0
810 status_t
811 SerialDevice::SetLineCoding(usb_serial_line_coding *coding)
812 {
813 // default implementation - does nothing
814 return B_OK;
815 }
816 #endif
817
818 status_t
SignalControlLineState(int line,bool enable)819 SerialDevice::SignalControlLineState(int line, bool enable)
820 {
821 gTTYModule->tty_hardware_signal(fSystemTTYCookie, line, enable);
822
823 return B_OK;
824 }
825
826
827 void
OnRead(char ** buffer,size_t * numBytes)828 SerialDevice::OnRead(char **buffer, size_t *numBytes)
829 {
830 // default implementation - does nothing
831 }
832
833
834 void
OnWrite(const char * buffer,size_t * numBytes,size_t * packetBytes)835 SerialDevice::OnWrite(const char *buffer, size_t *numBytes, size_t *packetBytes)
836 {
837 // default implementation - does nothing
838 }
839
840
841 void
OnClose()842 SerialDevice::OnClose()
843 {
844 // default implementation - does nothing
845 }
846
847
848 int32
_DeviceThread(void * data)849 SerialDevice::_DeviceThread(void *data)
850 {
851 #if 0
852 SerialDevice *device = (SerialDevice *)data;
853
854 while (!device->fStopDeviceThread) {
855 status_t status = gUSBModule->queue_bulk(device->fReadPipe,
856 device->fReadBuffer, device->fReadBufferSize,
857 device->ReadCallbackFunction, data);
858 if (status < B_OK) {
859 TRACE_ALWAYS("device thread: queueing failed with error: 0x%08x\n", status);
860 break;
861 }
862
863 status = acquire_sem_etc(device->fDoneRead, 1, B_CAN_INTERRUPT, 0);
864 if (status < B_OK) {
865 TRACE_ALWAYS("device thread: failed to get read done sem 0x%08x\n", status);
866 break;
867 }
868
869 if (device->fStatusRead != B_OK) {
870 TRACE("device thread: device status error 0x%08x\n",
871 device->fStatusRead);
872 if (gUSBModule->clear_feature(device->fReadPipe,
873 USB_FEATURE_ENDPOINT_HALT) != B_OK) {
874 TRACE_ALWAYS("device thread: failed to clear halt feature\n");
875 break;
876 }
877 }
878
879 char *buffer = device->fReadBuffer;
880 size_t readLength = device->fActualLengthRead;
881 device->OnRead(&buffer, &readLength);
882 if (readLength == 0)
883 continue;
884
885 ddrover *ddr = gTTYModule->ddrstart(NULL);
886 if (!ddr) {
887 TRACE_ALWAYS("device thread: ddrstart problem\n");
888 return B_NO_MEMORY;
889 }
890
891 while (device->fInputStopped)
892 snooze(100);
893
894 gTTYModule->ttyilock(&device->fTTY, ddr, true);
895 for (size_t i = 0; i < readLength; i++)
896 gTTYModule->ttyin(&device->fTTY, ddr, buffer[i]);
897
898 gTTYModule->ttyilock(&device->fTTY, ddr, false);
899 gTTYModule->ddrdone(ddr);
900 }
901
902 #endif
903 return B_OK;
904 }
905
906
907 status_t
_WriteToDevice()908 SerialDevice::_WriteToDevice()
909 {
910 char *buffer = &fWriteBuffer[fWriteBufferIn];
911 size_t bytesLeft = DEF_BUFFER_SIZE - atomic_get(&fWriteBufferAvail);
912 bytesLeft = MIN(bytesLeft, DEF_BUFFER_SIZE - fWriteBufferIn);
913 TRACE("%s: in %d left %d\n", __FUNCTION__, fWriteBufferIn, bytesLeft);
914 status_t status = gTTYModule->tty_read(fDeviceTTYCookie, buffer,
915 &bytesLeft);
916 TRACE("%s: tty_read: %d\n", __FUNCTION__, bytesLeft);
917 if (status != B_OK) {
918 TRACE_ALWAYS("write to device: failed to read from TTY: %s\n",
919 strerror(status));
920 return status;
921 }
922 fWriteBufferIn += bytesLeft;
923 fWriteBufferIn %= DEF_BUFFER_SIZE;
924 atomic_add(&fWriteBufferAvail, bytesLeft);
925
926 // XXX: WTF: this ought to be done by the tty module calling service_func!
927 // enable irqs
928 Service(fMasterTTY, TTYOSTART, NULL, 0);
929
930 status = acquire_sem_etc(fWriteBufferSem, 1, B_CAN_INTERRUPT, 0);
931 if (status != B_OK) {
932 TRACE_ALWAYS("write to device: failed to acquire sem: %s\n",
933 strerror(status));
934 return status;
935 }
936 return B_OK;
937 }
938
939
940 void
ReadCallbackFunction(void * cookie,int32 status,void * data,uint32 actualLength)941 SerialDevice::ReadCallbackFunction(void *cookie, int32 status, void *data,
942 uint32 actualLength)
943 {
944 TRACE_FUNCALLS("read callback: cookie: 0x%08x status: 0x%08x data: 0x%08x len: %lu\n",
945 cookie, status, data, actualLength);
946
947 SerialDevice *device = (SerialDevice *)cookie;
948 device->fActualLengthRead = actualLength;
949 device->fStatusRead = status;
950 release_sem_etc(device->fDoneRead, 1, B_DO_NOT_RESCHEDULE);
951 }
952
953
954 void
WriteCallbackFunction(void * cookie,int32 status,void * data,uint32 actualLength)955 SerialDevice::WriteCallbackFunction(void *cookie, int32 status, void *data,
956 uint32 actualLength)
957 {
958 TRACE_FUNCALLS("write callback: cookie: 0x%08x status: 0x%08x data: 0x%08x len: %lu\n",
959 cookie, status, data, actualLength);
960
961 SerialDevice *device = (SerialDevice *)cookie;
962 device->fActualLengthWrite = actualLength;
963 device->fStatusWrite = status;
964 release_sem_etc(device->fDoneWrite, 1, B_DO_NOT_RESCHEDULE);
965 }
966
967
968 void
InterruptCallbackFunction(void * cookie,int32 status,void * data,uint32 actualLength)969 SerialDevice::InterruptCallbackFunction(void *cookie, int32 status,
970 void *data, uint32 actualLength)
971 {
972 TRACE_FUNCALLS("interrupt callback: cookie: 0x%08x status: 0x%08x data: 0x%08x len: %lu\n",
973 cookie, status, data, actualLength);
974
975 SerialDevice *device = (SerialDevice *)cookie;
976 device->fActualLengthInterrupt = actualLength;
977 device->fStatusInterrupt = status;
978
979 // ToDo: maybe handle those somehow?
980
981 if (status == B_OK && !device->fDeviceRemoved) {
982 #if 0
983 status = gUSBModule->queue_interrupt(device->fControlPipe,
984 device->fInterruptBuffer, device->fInterruptBufferSize,
985 device->InterruptCallbackFunction, device);
986 #endif
987 }
988 }
989
990
991
992 #if 0
993 SerialDevice *
994 SerialDevice::MakeDevice(usb_device device, uint16 vendorID,
995 uint16 productID)
996 {
997 const char *description = NULL;
998
999 switch (vendorID) {
1000 case VENDOR_IODATA:
1001 case VENDOR_ATEN:
1002 case VENDOR_TDK:
1003 case VENDOR_RATOC:
1004 case VENDOR_PROLIFIC:
1005 case VENDOR_ELECOM:
1006 case VENDOR_SOURCENEXT:
1007 case VENDOR_HAL:
1008 {
1009 switch (productID) {
1010 case PRODUCT_PROLIFIC_RSAQ2: description = "PL2303 Serial adapter (IODATA USB-RSAQ2)"; break;
1011 case PRODUCT_IODATA_USBRSAQ: description = "I/O Data USB serial adapter USB-RSAQ1"; break;
1012 case PRODUCT_ATEN_UC232A: description = "Aten Serial adapter"; break;
1013 case PRODUCT_TDK_UHA6400: description = "TDK USB-PHS Adapter UHA6400"; break;
1014 case PRODUCT_RATOC_REXUSB60: description = "Ratoc USB serial adapter REX-USB60"; break;
1015 case PRODUCT_PROLIFIC_PL2303: description = "PL2303 Serial adapter (ATEN/IOGEAR UC232A)"; break;
1016 case PRODUCT_ELECOM_UCSGT: description = "Elecom UC-SGT"; break;
1017 case PRODUCT_SOURCENEXT_KEIKAI8: description = "SOURCENEXT KeikaiDenwa 8"; break;
1018 case PRODUCT_SOURCENEXT_KEIKAI8_CHG: description = "SOURCENEXT KeikaiDenwa 8 with charger"; break;
1019 case PRODUCT_HAL_IMR001: description = "HAL Corporation Crossam2+USB"; break;
1020 }
1021
1022 if (!description)
1023 break;
1024
1025 return new(std::nothrow) ProlificDevice(device, vendorID, productID, description);
1026 }
1027
1028 case VENDOR_FTDI:
1029 {
1030 switch (productID) {
1031 case PRODUCT_FTDI_8U100AX: description = "FTDI 8U100AX serial converter"; break;
1032 case PRODUCT_FTDI_8U232AM: description = "FTDI 8U232AM serial converter"; break;
1033 }
1034
1035 if (!description)
1036 break;
1037
1038 return new(std::nothrow) FTDIDevice(device, vendorID, productID, description);
1039 }
1040
1041 case VENDOR_PALM:
1042 case VENDOR_KLSI:
1043 {
1044 switch (productID) {
1045 case PRODUCT_PALM_CONNECT: description = "PalmConnect RS232"; break;
1046 case PRODUCT_KLSI_KL5KUSB105D: description = "KLSI KL5KUSB105D"; break;
1047 }
1048
1049 if (!description)
1050 break;
1051
1052 return new(std::nothrow) KLSIDevice(device, vendorID, productID, description);
1053 }
1054 }
1055
1056 return new(std::nothrow) ACMDevice(device, vendorID, productID, "CDC ACM compatible device");
1057 }
1058 #endif
1059
1060
1061 uint8
ReadReg8(int reg)1062 SerialDevice::ReadReg8(int reg)
1063 {
1064 uint8 ret;
1065 switch (fBus) {
1066 case B_ISA_BUS:
1067 ret = gISAModule->read_io_8(IOBase() + reg);
1068 break;
1069 case B_PCI_BUS:
1070 ret = gPCIModule->read_io_8(IOBase() + reg);
1071 break;
1072 default:
1073 TRACE_ALWAYS("%s: unknown bus!\n", __FUNCTION__);
1074 ret = 0;
1075 //XXX:pcmcia ?
1076 }
1077 TRACE/*_ALWAYS*/("RR8(%d) = %d [%02x]\n", reg, ret, ret);
1078 //spin(1000);
1079 return ret;
1080 }
1081
1082 void
WriteReg8(int reg,uint8 value)1083 SerialDevice::WriteReg8(int reg, uint8 value)
1084 {
1085 // TRACE_ALWAYS("WR8(0x%04x+%d, %d [0x%x])\n", IOBase(), reg, value, value);
1086 TRACE/*_ALWAYS*/("WR8(%d, %d [0x%x])\n", reg, value, value);
1087 switch (fBus) {
1088 case B_ISA_BUS:
1089 gISAModule->write_io_8(IOBase() + reg, value);
1090 break;
1091 case B_PCI_BUS:
1092 gPCIModule->write_io_8(IOBase() + reg, value);
1093 break;
1094 default:
1095 TRACE_ALWAYS("%s: unknown bus!\n", __FUNCTION__);
1096 //XXX:pcmcia ?
1097 }
1098 //spin(10000);
1099 }
1100
1101
1102 void
OrReg8(int reg,uint8 value)1103 SerialDevice::OrReg8(int reg, uint8 value)
1104 {
1105 WriteReg8(reg, ReadReg8(reg) | value);
1106 }
1107
1108
1109 void
AndReg8(int reg,uint8 value)1110 SerialDevice::AndReg8(int reg, uint8 value)
1111 {
1112 WriteReg8(reg, ReadReg8(reg) & value);
1113 }
1114
1115
1116 void
MaskReg8(int reg,uint8 value)1117 SerialDevice::MaskReg8(int reg, uint8 value)
1118 {
1119 WriteReg8(reg, ReadReg8(reg) & ~value);
1120 }
1121