📄 keyspan_pda.c
字号:
case TIOCMBIS: /* set bits in bitmask <arg> */ case TIOCMBIC: /* clear bits from bitmask <arg> */ if (copy_from_user(&value, (unsigned int *)arg, sizeof(int))) return -EFAULT; rc = keyspan_pda_get_modem_info(serial, &status); if (rc < 0) return rc; mask = ((value & TIOCM_RTS) ? (1<<2) : 0) | ((value & TIOCM_DTR) ? (1<<7) : 0); if (cmd == TIOCMBIS) status |= mask; else status &= ~mask; rc = keyspan_pda_set_modem_info(serial, status); if (rc < 0) return rc; return 0; case TIOCMIWAIT: /* wait for any of the 4 modem inputs (DCD,RI,DSR,CTS)*/ /* TODO */ case TIOCGICOUNT: /* return count of modemline transitions */ return 0; /* TODO */ } return -ENOIOCTLCMD;}static int keyspan_pda_write(struct usb_serial_port *port, int from_user, const unsigned char *buf, int count){ struct usb_serial *serial = port->serial; int request_unthrottle = 0; int rc = 0; struct keyspan_pda_private *priv; priv = (struct keyspan_pda_private *)(port->private); /* guess how much room is left in the device's ring buffer, and if we want to send more than that, check first, updating our notion of what is left. If our write will result in no room left, ask the device to give us an interrupt when the room available rises above a threshold, and hold off all writers (eventually, those using select() or poll() too) until we receive that unthrottle interrupt. Block if we can't write anything at all, otherwise write as much as we can. */ dbg("keyspan_pda_write(%d)",count); if (count == 0) { dbg(" write request of 0 bytes"); return (0); } /* we might block because of: the TX urb is in-flight (wait until it completes) the device is full (wait until it says there is room) */ if (port->write_urb->status == -EINPROGRESS || priv->tx_throttled ) { return( 0 ); } /* At this point the URB is in our control, nobody else can submit it again (the only sudden transition was the one from EINPROGRESS to finished). Also, the tx process is not throttled. So we are ready to write. */ count = (count > port->bulk_out_size) ? port->bulk_out_size : count; /* Check if we might overrun the Tx buffer. If so, ask the device how much room it really has. This is done only on scheduler time, since usb_control_msg() sleeps. */ if (count > priv->tx_room && !in_interrupt()) { unsigned char room; rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), 6, /* write_room */ USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_IN, 0, /* value: 0 means "remaining room" */ 0, /* index */ &room, 1, 2*HZ); if (rc < 0) { dbg(" roomquery failed"); goto exit; } if (rc == 0) { dbg(" roomquery returned 0 bytes"); rc = -EIO; /* device didn't return any data */ goto exit; } dbg(" roomquery says %d", room); priv->tx_room = room; } if (count > priv->tx_room) { /* we're about to completely fill the Tx buffer, so we'll be throttled afterwards. */ count = priv->tx_room; request_unthrottle = 1; } if (count) { /* now transfer data */ if (from_user) { if( copy_from_user(port->write_urb->transfer_buffer, buf, count) ) { rc = -EFAULT; goto exit; } } else { memcpy (port->write_urb->transfer_buffer, buf, count); } /* send the data out the bulk port */ port->write_urb->transfer_buffer_length = count; priv->tx_room -= count; port->write_urb->dev = port->serial->dev; rc = usb_submit_urb(port->write_urb); if (rc) { dbg(" usb_submit_urb(write bulk) failed"); goto exit; } } else { /* There wasn't any room left, so we are throttled until the buffer empties a bit */ request_unthrottle = 1; } if (request_unthrottle) { priv->tx_throttled = 1; /* block writers */ MOD_INC_USE_COUNT; if (schedule_task(&priv->unthrottle_task) == 0) MOD_DEC_USE_COUNT; } rc = count;exit: return rc;}static void keyspan_pda_write_bulk_callback (struct urb *urb){ struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct usb_serial *serial; struct keyspan_pda_private *priv; priv = (struct keyspan_pda_private *)(port->private); if (port_paranoia_check (port, "keyspan_pda_rx_interrupt")) { return; } serial = port->serial; if (serial_paranoia_check (serial, "keyspan_pda_rx_interrupt")) { return; } /* queue up a wakeup at scheduler time */ MOD_INC_USE_COUNT; if (schedule_task(&priv->wakeup_task) == 0) MOD_DEC_USE_COUNT;}static int keyspan_pda_write_room (struct usb_serial_port *port){ struct keyspan_pda_private *priv; priv = (struct keyspan_pda_private *)(port->private); /* used by n_tty.c for processing of tabs and such. Giving it our conservative guess is probably good enough, but needs testing by running a console through the device. */ return (priv->tx_room);}static int keyspan_pda_chars_in_buffer (struct usb_serial_port *port){ struct keyspan_pda_private *priv; priv = (struct keyspan_pda_private *)(port->private); /* when throttled, return at least WAKEUP_CHARS to tell select() (via n_tty.c:normal_poll() ) that we're not writeable. */ if( port->write_urb->status == -EINPROGRESS || priv->tx_throttled ) return 256; return 0;}static int keyspan_pda_open (struct usb_serial_port *port, struct file *filp){ struct usb_serial *serial = port->serial; unsigned char room; int rc = 0; struct keyspan_pda_private *priv; down (&port->sem); MOD_INC_USE_COUNT; ++port->open_count; if (!port->active) { port->active = 1; /* find out how much room is in the Tx ring */ rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), 6, /* write_room */ USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_IN, 0, /* value */ 0, /* index */ &room, 1, 2*HZ); if (rc < 0) { dbg(__FUNCTION__" - roomquery failed"); goto error; } if (rc == 0) { dbg(__FUNCTION__" - roomquery returned 0 bytes"); rc = -EIO; goto error; } priv = (struct keyspan_pda_private *)(port->private); priv->tx_room = room; priv->tx_throttled = room ? 0 : 1; /* the normal serial device seems to always turn on DTR and RTS here, so do the same */ if (port->tty->termios->c_cflag & CBAUD) keyspan_pda_set_modem_info(serial, (1<<7) | (1<<2) ); else keyspan_pda_set_modem_info(serial, 0); /*Start reading from the device*/ port->interrupt_in_urb->dev = serial->dev; rc = usb_submit_urb(port->interrupt_in_urb); if (rc) { dbg(__FUNCTION__" - usb_submit_urb(read int) failed"); goto error; } } up (&port->sem); return rc;error: --port->open_count; port->active = 0; MOD_DEC_USE_COUNT; up (&port->sem); return rc;}static void keyspan_pda_close(struct usb_serial_port *port, struct file *filp){ struct usb_serial *serial = port->serial; down (&port->sem); --port->open_count; if (port->open_count <= 0) { if (serial->dev) { /* the normal serial device seems to always shut off DTR and RTS now */ if (port->tty->termios->c_cflag & HUPCL) keyspan_pda_set_modem_info(serial, 0); /* shutdown our bulk reads and writes */ usb_unlink_urb (port->write_urb); usb_unlink_urb (port->interrupt_in_urb); } port->active = 0; port->open_count = 0; } up (&port->sem); MOD_DEC_USE_COUNT;}/* download the firmware to a "fake" device (pre-renumeration) */static int keyspan_pda_fake_startup (struct usb_serial *serial){ int response; const struct ezusb_hex_record *record = NULL; /* download the firmware here ... */ response = ezusb_set_reset(serial, 1);#ifdef KEYSPAN if (serial->dev->descriptor.idVendor == KEYSPAN_VENDOR_ID) record = &keyspan_pda_firmware[0];#endif#ifdef XIRCOM if ((serial->dev->descriptor.idVendor == XIRCOM_VENDOR_ID) || (serial->dev->descriptor.idVendor == ENTREGRA_VENDOR_ID)) record = &xircom_pgs_firmware[0];#endif if (record == NULL) { err(__FUNCTION__": unknown vendor, aborting."); return -ENODEV; } while(record->address != 0xffff) { response = ezusb_writememory(serial, record->address, (unsigned char *)record->data, record->data_size, 0xa0); if (response < 0) { err("ezusb_writememory failed for Keyspan PDA " "firmware (%d %04X %p %d)", response, record->address, record->data, record->data_size); break; } record++; } /* bring device out of reset. Renumeration will occur in a moment and the new device will bind to the real driver */ response = ezusb_set_reset(serial, 0); /* we want this device to fail to have a driver assigned to it. */ return (1);}static int keyspan_pda_startup (struct usb_serial *serial){ struct keyspan_pda_private *priv; /* allocate the private data structures for all ports. Well, for all one ports. */ priv = serial->port[0].private = kmalloc(sizeof(struct keyspan_pda_private), GFP_KERNEL); if (!priv) return (1); /* error */ init_waitqueue_head(&serial->port[0].write_wait); INIT_LIST_HEAD(&priv->wakeup_task.list); priv->wakeup_task.sync = 0; priv->wakeup_task.routine = (void *)keyspan_pda_wakeup_write; priv->wakeup_task.data = (void *)(&serial->port[0]); INIT_LIST_HEAD(&priv->unthrottle_task.list); priv->unthrottle_task.sync = 0; priv->unthrottle_task.routine = (void *)keyspan_pda_request_unthrottle; priv->unthrottle_task.data = (void *)(serial); return (0);}static void keyspan_pda_shutdown (struct usb_serial *serial){ dbg (__FUNCTION__); while (serial->port[0].open_count > 0) { keyspan_pda_close (&serial->port[0], NULL); } kfree(serial->port[0].private);}#ifdef KEYSPANstatic struct usb_serial_device_type keyspan_pda_fake_device = { name: "Keyspan PDA - (prerenumeration)", id_table: id_table_fake, needs_interrupt_in: DONT_CARE, needs_bulk_in: DONT_CARE, needs_bulk_out: DONT_CARE, num_interrupt_in: NUM_DONT_CARE, num_bulk_in: NUM_DONT_CARE, num_bulk_out: NUM_DONT_CARE, num_ports: 1, startup: keyspan_pda_fake_startup,};#endif#ifdef XIRCOMstatic struct usb_serial_device_type xircom_pgs_fake_device = { name: "Xircom PGS - (prerenumeration)", id_table: id_table_fake_xircom, needs_interrupt_in: DONT_CARE, needs_bulk_in: DONT_CARE, needs_bulk_out: DONT_CARE, num_interrupt_in: NUM_DONT_CARE, num_bulk_in: NUM_DONT_CARE, num_bulk_out: NUM_DONT_CARE, num_ports: 1, startup: keyspan_pda_fake_startup,};static struct usb_serial_device_type entregra_pgs_fake_device = { name: "Entregra PGS - (prerenumeration)", id_table: id_table_fake_entregra, needs_interrupt_in: DONT_CARE, needs_bulk_in: DONT_CARE, needs_bulk_out: DONT_CARE, num_interrupt_in: NUM_DONT_CARE, num_bulk_in: NUM_DONT_CARE, num_bulk_out: NUM_DONT_CARE, num_ports: 1, startup: keyspan_pda_fake_startup,};#endifstatic struct usb_serial_device_type keyspan_pda_device = { name: "Keyspan PDA", id_table: id_table_std, needs_interrupt_in: MUST_HAVE, needs_bulk_in: DONT_CARE, needs_bulk_out: MUST_HAVE, num_interrupt_in: 1, num_bulk_in: 0, num_bulk_out: 1, num_ports: 1, open: keyspan_pda_open, close: keyspan_pda_close, write: keyspan_pda_write, write_room: keyspan_pda_write_room, write_bulk_callback: keyspan_pda_write_bulk_callback, read_int_callback: keyspan_pda_rx_interrupt, chars_in_buffer: keyspan_pda_chars_in_buffer, throttle: keyspan_pda_rx_throttle, unthrottle: keyspan_pda_rx_unthrottle, ioctl: keyspan_pda_ioctl, set_termios: keyspan_pda_set_termios, break_ctl: keyspan_pda_break_ctl, startup: keyspan_pda_startup, shutdown: keyspan_pda_shutdown,};static int __init keyspan_pda_init (void){ usb_serial_register (&keyspan_pda_device);#ifdef KEYSPAN usb_serial_register (&keyspan_pda_fake_device);#endif#ifdef XIRCOM usb_serial_register (&xircom_pgs_fake_device); usb_serial_register (&entregra_pgs_fake_device);#endif info(DRIVER_DESC " " DRIVER_VERSION); return 0;}static void __exit keyspan_pda_exit (void){ usb_serial_deregister (&keyspan_pda_device);#ifdef KEYSPAN usb_serial_deregister (&keyspan_pda_fake_device);#endif#ifdef XIRCOM usb_serial_deregister (&entregra_pgs_fake_device); usb_serial_deregister (&xircom_pgs_fake_device);#endif}module_init(keyspan_pda_init);module_exit(keyspan_pda_exit);MODULE_AUTHOR( DRIVER_AUTHOR );MODULE_DESCRIPTION( DRIVER_DESC );MODULE_LICENSE("GPL");MODULE_PARM(debug, "i");MODULE_PARM_DESC(debug, "Debug enabled or not");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -