📄 keyspan_pda.c
字号:
((status & (1<<5)) ? TIOCM_RNG : 0) | ((status & (1<<4)) ? TIOCM_DSR : 0) | ((status & (1<<3)) ? TIOCM_CTS : 0) | ((status & (1<<2)) ? TIOCM_RTS : 0); return value;}static int keyspan_pda_tiocmset(struct usb_serial_port *port, struct file *file, unsigned int set, unsigned int clear){ struct usb_serial *serial = port->serial; int rc; unsigned char status; rc = keyspan_pda_get_modem_info(serial, &status); if (rc < 0) return rc; if (set & TIOCM_RTS) status |= (1<<2); if (set & TIOCM_DTR) status |= (1<<7); if (clear & TIOCM_RTS) status &= ~(1<<2); if (clear & TIOCM_DTR) status &= ~(1<<7); rc = keyspan_pda_set_modem_info(serial, status); return rc;}static int keyspan_pda_ioctl(struct usb_serial_port *port, struct file *file, unsigned int cmd, unsigned long arg){ switch (cmd) { 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 = usb_get_serial_port_data(port); /* 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, GFP_ATOMIC); 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 */ schedule_work(&priv->unthrottle_work); } rc = count;exit: return rc;}static void keyspan_pda_write_bulk_callback (struct urb *urb, struct pt_regs *regs){ struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct keyspan_pda_private *priv; priv = usb_get_serial_port_data(port); /* queue up a wakeup at scheduler time */ schedule_work(&priv->wakeup_work);}static int keyspan_pda_write_room (struct usb_serial_port *port){ struct keyspan_pda_private *priv; priv = usb_get_serial_port_data(port); /* 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 = usb_get_serial_port_data(port); /* 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; /* 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("%s - roomquery failed", __FUNCTION__); goto error; } if (rc == 0) { dbg("%s - roomquery returned 0 bytes", __FUNCTION__); rc = -EIO; goto error; } priv = usb_get_serial_port_data(port); 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, GFP_KERNEL); if (rc) { dbg("%s - usb_submit_urb(read int) failed", __FUNCTION__); goto error; }error: return rc;}static void keyspan_pda_close(struct usb_serial_port *port, struct file *filp){ struct usb_serial *serial = port->serial; 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); }}/* 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("%s: unknown vendor, aborting.", __FUNCTION__); 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 = kmalloc(sizeof(struct keyspan_pda_private), GFP_KERNEL); if (!priv) return (1); /* error */ usb_set_serial_port_data(serial->port[0], priv); init_waitqueue_head(&serial->port[0]->write_wait); INIT_WORK(&priv->wakeup_work, (void *)keyspan_pda_wakeup_write, (void *)(serial->port[0])); INIT_WORK(&priv->unthrottle_work, (void *)keyspan_pda_request_unthrottle, (void *)(serial)); return (0);}static void keyspan_pda_shutdown (struct usb_serial *serial){ dbg("%s", __FUNCTION__); kfree(usb_get_serial_port_data(serial->port[0]));}#ifdef KEYSPANstatic struct usb_serial_device_type keyspan_pda_fake_device = { .owner = THIS_MODULE, .name = "Keyspan PDA - (prerenumeration)", .short_name = "keyspan_pda_pre", .id_table = id_table_fake, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, .num_bulk_out = NUM_DONT_CARE, .num_ports = 1, .attach = keyspan_pda_fake_startup,};#endif#ifdef XIRCOMstatic struct usb_serial_device_type xircom_pgs_fake_device = { .owner = THIS_MODULE, .name = "Xircom / Entregra PGS - (prerenumeration)", .short_name = "xircom_no_firm", .id_table = id_table_fake_xircom, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, .num_bulk_out = NUM_DONT_CARE, .num_ports = 1, .attach = keyspan_pda_fake_startup,};#endifstatic struct usb_serial_device_type keyspan_pda_device = { .owner = THIS_MODULE, .name = "Keyspan PDA", .short_name = "keyspan_pda", .id_table = id_table_std, .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, .tiocmget = keyspan_pda_tiocmget, .tiocmset = keyspan_pda_tiocmset, .attach = keyspan_pda_startup, .shutdown = keyspan_pda_shutdown,};static int __init keyspan_pda_init (void){ int retval; retval = usb_serial_register(&keyspan_pda_device); if (retval) goto failed_pda_register;#ifdef KEYSPAN retval = usb_serial_register(&keyspan_pda_fake_device); if (retval) goto failed_pda_fake_register;#endif#ifdef XIRCOM retval = usb_serial_register(&xircom_pgs_fake_device); if (retval) goto failed_xircom_register;#endif retval = usb_register(&keyspan_pda_driver); if (retval) goto failed_usb_register; info(DRIVER_DESC " " DRIVER_VERSION); return 0;failed_usb_register: #ifdef XIRCOM usb_serial_deregister(&xircom_pgs_fake_device);failed_xircom_register:#endif /* XIRCOM */#ifdef KEYSPAN usb_serial_deregister(&keyspan_pda_fake_device);#endif#ifdef KEYSPANfailed_pda_fake_register:#endif usb_serial_deregister(&keyspan_pda_device);failed_pda_register: return retval;}static void __exit keyspan_pda_exit (void){ usb_deregister (&keyspan_pda_driver); usb_serial_deregister (&keyspan_pda_device);#ifdef KEYSPAN usb_serial_deregister (&keyspan_pda_fake_device);#endif#ifdef XIRCOM 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_param(debug, bool, S_IRUGO | S_IWUSR);MODULE_PARM_DESC(debug, "Debug enabled or not");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -