123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720 |
- // SPDX-License-Identifier: GPL-2.0+
- /*
- * USB Keyspan PDA / Xircom / Entrega Converter driver
- *
- * Copyright (C) 1999 - 2001 Greg Kroah-Hartman <[email protected]>
- * Copyright (C) 1999, 2000 Brian Warner <[email protected]>
- * Copyright (C) 2000 Al Borchers <[email protected]>
- * Copyright (C) 2020 Johan Hovold <[email protected]>
- *
- * See Documentation/usb/usb-serial.rst for more information on using this
- * driver
- */
- #include <linux/kernel.h>
- #include <linux/errno.h>
- #include <linux/slab.h>
- #include <linux/tty.h>
- #include <linux/tty_driver.h>
- #include <linux/tty_flip.h>
- #include <linux/module.h>
- #include <linux/spinlock.h>
- #include <linux/workqueue.h>
- #include <linux/uaccess.h>
- #include <linux/usb.h>
- #include <linux/usb/serial.h>
- #include <linux/usb/ezusb.h>
- #define DRIVER_AUTHOR "Brian Warner <[email protected]>, Johan Hovold <[email protected]>"
- #define DRIVER_DESC "USB Keyspan PDA Converter driver"
- #define KEYSPAN_TX_THRESHOLD 128
- struct keyspan_pda_private {
- int tx_room;
- struct work_struct unthrottle_work;
- struct usb_serial *serial;
- struct usb_serial_port *port;
- };
- static int keyspan_pda_write_start(struct usb_serial_port *port);
- #define KEYSPAN_VENDOR_ID 0x06cd
- #define KEYSPAN_PDA_FAKE_ID 0x0103
- #define KEYSPAN_PDA_ID 0x0104 /* no clue */
- /* For Xircom PGSDB9 and older Entrega version of the same device */
- #define XIRCOM_VENDOR_ID 0x085a
- #define XIRCOM_FAKE_ID 0x8027
- #define XIRCOM_FAKE_ID_2 0x8025 /* "PGMFHUB" serial */
- #define ENTREGA_VENDOR_ID 0x1645
- #define ENTREGA_FAKE_ID 0x8093
- static const struct usb_device_id id_table_combined[] = {
- { USB_DEVICE(KEYSPAN_VENDOR_ID, KEYSPAN_PDA_FAKE_ID) },
- { USB_DEVICE(XIRCOM_VENDOR_ID, XIRCOM_FAKE_ID) },
- { USB_DEVICE(XIRCOM_VENDOR_ID, XIRCOM_FAKE_ID_2) },
- { USB_DEVICE(ENTREGA_VENDOR_ID, ENTREGA_FAKE_ID) },
- { USB_DEVICE(KEYSPAN_VENDOR_ID, KEYSPAN_PDA_ID) },
- { } /* Terminating entry */
- };
- MODULE_DEVICE_TABLE(usb, id_table_combined);
- static const struct usb_device_id id_table_std[] = {
- { USB_DEVICE(KEYSPAN_VENDOR_ID, KEYSPAN_PDA_ID) },
- { } /* Terminating entry */
- };
- static const struct usb_device_id id_table_fake[] = {
- { USB_DEVICE(KEYSPAN_VENDOR_ID, KEYSPAN_PDA_FAKE_ID) },
- { USB_DEVICE(XIRCOM_VENDOR_ID, XIRCOM_FAKE_ID) },
- { USB_DEVICE(XIRCOM_VENDOR_ID, XIRCOM_FAKE_ID_2) },
- { USB_DEVICE(ENTREGA_VENDOR_ID, ENTREGA_FAKE_ID) },
- { } /* Terminating entry */
- };
- static int keyspan_pda_get_write_room(struct keyspan_pda_private *priv)
- {
- struct usb_serial_port *port = priv->port;
- struct usb_serial *serial = port->serial;
- u8 room;
- int rc;
- rc = usb_control_msg_recv(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,
- 2000,
- GFP_KERNEL);
- if (rc) {
- dev_dbg(&port->dev, "roomquery failed: %d\n", rc);
- return rc;
- }
- dev_dbg(&port->dev, "roomquery says %d\n", room);
- return room;
- }
- static void keyspan_pda_request_unthrottle(struct work_struct *work)
- {
- struct keyspan_pda_private *priv =
- container_of(work, struct keyspan_pda_private, unthrottle_work);
- struct usb_serial_port *port = priv->port;
- struct usb_serial *serial = port->serial;
- unsigned long flags;
- int result;
- dev_dbg(&port->dev, "%s\n", __func__);
- /*
- * Ask the device to tell us when the tx buffer becomes
- * sufficiently empty.
- */
- result = usb_control_msg(serial->dev,
- usb_sndctrlpipe(serial->dev, 0),
- 7, /* request_unthrottle */
- USB_TYPE_VENDOR | USB_RECIP_INTERFACE
- | USB_DIR_OUT,
- KEYSPAN_TX_THRESHOLD,
- 0, /* index */
- NULL,
- 0,
- 2000);
- if (result < 0)
- dev_dbg(&serial->dev->dev, "%s - error %d from usb_control_msg\n",
- __func__, result);
- /*
- * Need to check available space after requesting notification in case
- * buffer is already empty so that no notification is sent.
- */
- result = keyspan_pda_get_write_room(priv);
- if (result > KEYSPAN_TX_THRESHOLD) {
- spin_lock_irqsave(&port->lock, flags);
- priv->tx_room = max(priv->tx_room, result);
- spin_unlock_irqrestore(&port->lock, flags);
- usb_serial_port_softint(port);
- }
- }
- static void keyspan_pda_rx_interrupt(struct urb *urb)
- {
- struct usb_serial_port *port = urb->context;
- unsigned char *data = urb->transfer_buffer;
- unsigned int len = urb->actual_length;
- int retval;
- int status = urb->status;
- struct keyspan_pda_private *priv;
- unsigned long flags;
- priv = usb_get_serial_port_data(port);
- switch (status) {
- case 0:
- /* success */
- break;
- case -ECONNRESET:
- case -ENOENT:
- case -ESHUTDOWN:
- /* this urb is terminated, clean up */
- dev_dbg(&urb->dev->dev, "%s - urb shutting down with status: %d\n", __func__, status);
- return;
- default:
- dev_dbg(&urb->dev->dev, "%s - nonzero urb status received: %d\n", __func__, status);
- goto exit;
- }
- if (len < 1) {
- dev_warn(&port->dev, "short message received\n");
- goto exit;
- }
- /* see if the message is data or a status interrupt */
- switch (data[0]) {
- case 0:
- /* rest of message is rx data */
- if (len < 2)
- break;
- tty_insert_flip_string(&port->port, data + 1, len - 1);
- tty_flip_buffer_push(&port->port);
- break;
- case 1:
- /* status interrupt */
- if (len < 2) {
- dev_warn(&port->dev, "short interrupt message received\n");
- break;
- }
- dev_dbg(&port->dev, "rx int, d1=%d\n", data[1]);
- switch (data[1]) {
- case 1: /* modemline change */
- break;
- case 2: /* tx unthrottle interrupt */
- spin_lock_irqsave(&port->lock, flags);
- priv->tx_room = max(priv->tx_room, KEYSPAN_TX_THRESHOLD);
- spin_unlock_irqrestore(&port->lock, flags);
- keyspan_pda_write_start(port);
- usb_serial_port_softint(port);
- break;
- default:
- break;
- }
- break;
- default:
- break;
- }
- exit:
- retval = usb_submit_urb(urb, GFP_ATOMIC);
- if (retval)
- dev_err(&port->dev,
- "%s - usb_submit_urb failed with result %d\n",
- __func__, retval);
- }
- static void keyspan_pda_rx_throttle(struct tty_struct *tty)
- {
- struct usb_serial_port *port = tty->driver_data;
- /*
- * Stop receiving characters. We just turn off the URB request, and
- * let chars pile up in the device. If we're doing hardware
- * flowcontrol, the device will signal the other end when its buffer
- * fills up. If we're doing XON/XOFF, this would be a good time to
- * send an XOFF, although it might make sense to foist that off upon
- * the device too.
- */
- usb_kill_urb(port->interrupt_in_urb);
- }
- static void keyspan_pda_rx_unthrottle(struct tty_struct *tty)
- {
- struct usb_serial_port *port = tty->driver_data;
- /* just restart the receive interrupt URB */
- if (usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL))
- dev_dbg(&port->dev, "usb_submit_urb(read urb) failed\n");
- }
- static speed_t keyspan_pda_setbaud(struct usb_serial *serial, speed_t baud)
- {
- int rc;
- int bindex;
- switch (baud) {
- case 110:
- bindex = 0;
- break;
- case 300:
- bindex = 1;
- break;
- case 1200:
- bindex = 2;
- break;
- case 2400:
- bindex = 3;
- break;
- case 4800:
- bindex = 4;
- break;
- case 9600:
- bindex = 5;
- break;
- case 19200:
- bindex = 6;
- break;
- case 38400:
- bindex = 7;
- break;
- case 57600:
- bindex = 8;
- break;
- case 115200:
- bindex = 9;
- break;
- default:
- bindex = 5; /* Default to 9600 */
- baud = 9600;
- }
- rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
- 0, /* set baud */
- USB_TYPE_VENDOR
- | USB_RECIP_INTERFACE
- | USB_DIR_OUT, /* type */
- bindex, /* value */
- 0, /* index */
- NULL, /* &data */
- 0, /* size */
- 2000); /* timeout */
- if (rc < 0)
- return 0;
- return baud;
- }
- static void keyspan_pda_break_ctl(struct tty_struct *tty, int break_state)
- {
- struct usb_serial_port *port = tty->driver_data;
- struct usb_serial *serial = port->serial;
- int value;
- int result;
- if (break_state == -1)
- value = 1; /* start break */
- else
- value = 0; /* clear break */
- result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
- 4, /* set break */
- USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT,
- value, 0, NULL, 0, 2000);
- if (result < 0)
- dev_dbg(&port->dev, "%s - error %d from usb_control_msg\n",
- __func__, result);
- }
- static void keyspan_pda_set_termios(struct tty_struct *tty,
- struct usb_serial_port *port,
- const struct ktermios *old_termios)
- {
- struct usb_serial *serial = port->serial;
- speed_t speed;
- /*
- * cflag specifies lots of stuff: number of stop bits, parity, number
- * of data bits, baud. What can the device actually handle?:
- * CSTOPB (1 stop bit or 2)
- * PARENB (parity)
- * CSIZE (5bit .. 8bit)
- * There is minimal hw support for parity (a PSW bit seems to hold the
- * parity of whatever is in the accumulator). The UART either deals
- * with 10 bits (start, 8 data, stop) or 11 bits (start, 8 data,
- * 1 special, stop). So, with firmware changes, we could do:
- * 8N1: 10 bit
- * 8N2: 11 bit, extra bit always (mark?)
- * 8[EOMS]1: 11 bit, extra bit is parity
- * 7[EOMS]1: 10 bit, b0/b7 is parity
- * 7[EOMS]2: 11 bit, b0/b7 is parity, extra bit always (mark?)
- *
- * HW flow control is dictated by the tty->termios.c_cflags & CRTSCTS
- * bit.
- *
- * For now, just do baud.
- */
- speed = tty_get_baud_rate(tty);
- speed = keyspan_pda_setbaud(serial, speed);
- if (speed == 0) {
- dev_dbg(&port->dev, "can't handle requested baud rate\n");
- /* It hasn't changed so.. */
- speed = tty_termios_baud_rate(old_termios);
- }
- /*
- * Only speed can change so copy the old h/w parameters then encode
- * the new speed.
- */
- tty_termios_copy_hw(&tty->termios, old_termios);
- tty_encode_baud_rate(tty, speed, speed);
- }
- /*
- * Modem control pins: DTR and RTS are outputs and can be controlled.
- * DCD, RI, DSR, CTS are inputs and can be read. All outputs can also be
- * read. The byte passed is: DTR(b7) DCD RI DSR CTS RTS(b2) unused unused.
- */
- static int keyspan_pda_get_modem_info(struct usb_serial *serial,
- unsigned char *value)
- {
- int rc;
- u8 data;
- rc = usb_control_msg_recv(serial->dev, 0,
- 3, /* get pins */
- USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_IN,
- 0,
- 0,
- &data,
- 1,
- 2000,
- GFP_KERNEL);
- if (rc == 0)
- *value = data;
- return rc;
- }
- static int keyspan_pda_set_modem_info(struct usb_serial *serial,
- unsigned char value)
- {
- int rc;
- rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
- 3, /* set pins */
- USB_TYPE_VENDOR|USB_RECIP_INTERFACE|USB_DIR_OUT,
- value, 0, NULL, 0, 2000);
- return rc;
- }
- static int keyspan_pda_tiocmget(struct tty_struct *tty)
- {
- struct usb_serial_port *port = tty->driver_data;
- struct usb_serial *serial = port->serial;
- int rc;
- unsigned char status;
- int value;
- rc = keyspan_pda_get_modem_info(serial, &status);
- if (rc < 0)
- return rc;
- value = ((status & BIT(7)) ? TIOCM_DTR : 0) |
- ((status & BIT(6)) ? TIOCM_CAR : 0) |
- ((status & BIT(5)) ? TIOCM_RNG : 0) |
- ((status & BIT(4)) ? TIOCM_DSR : 0) |
- ((status & BIT(3)) ? TIOCM_CTS : 0) |
- ((status & BIT(2)) ? TIOCM_RTS : 0);
- return value;
- }
- static int keyspan_pda_tiocmset(struct tty_struct *tty,
- unsigned int set, unsigned int clear)
- {
- struct usb_serial_port *port = tty->driver_data;
- 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 |= BIT(2);
- if (set & TIOCM_DTR)
- status |= BIT(7);
- if (clear & TIOCM_RTS)
- status &= ~BIT(2);
- if (clear & TIOCM_DTR)
- status &= ~BIT(7);
- rc = keyspan_pda_set_modem_info(serial, status);
- return rc;
- }
- static int keyspan_pda_write_start(struct usb_serial_port *port)
- {
- struct keyspan_pda_private *priv = usb_get_serial_port_data(port);
- unsigned long flags;
- struct urb *urb;
- int count;
- int room;
- int rc;
- /*
- * Guess how much room is left in the device's ring buffer. 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 but also
- * query how much room is currently available (in case our guess was
- * too conservative and the buffer is already empty when the
- * unthrottle work is scheduled).
- */
- /*
- * 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)
- */
- spin_lock_irqsave(&port->lock, flags);
- room = priv->tx_room;
- count = kfifo_len(&port->write_fifo);
- if (!test_bit(0, &port->write_urbs_free) || count == 0 || room == 0) {
- spin_unlock_irqrestore(&port->lock, flags);
- return 0;
- }
- __clear_bit(0, &port->write_urbs_free);
- if (count > room)
- count = room;
- if (count > port->bulk_out_size)
- count = port->bulk_out_size;
- urb = port->write_urb;
- count = kfifo_out(&port->write_fifo, urb->transfer_buffer, count);
- urb->transfer_buffer_length = count;
- port->tx_bytes += count;
- priv->tx_room -= count;
- spin_unlock_irqrestore(&port->lock, flags);
- dev_dbg(&port->dev, "%s - count = %d, txroom = %d\n", __func__, count, room);
- rc = usb_submit_urb(urb, GFP_ATOMIC);
- if (rc) {
- dev_dbg(&port->dev, "usb_submit_urb(write bulk) failed\n");
- spin_lock_irqsave(&port->lock, flags);
- port->tx_bytes -= count;
- priv->tx_room = max(priv->tx_room, room + count);
- __set_bit(0, &port->write_urbs_free);
- spin_unlock_irqrestore(&port->lock, flags);
- return rc;
- }
- if (count == room)
- schedule_work(&priv->unthrottle_work);
- return count;
- }
- static void keyspan_pda_write_bulk_callback(struct urb *urb)
- {
- struct usb_serial_port *port = urb->context;
- unsigned long flags;
- spin_lock_irqsave(&port->lock, flags);
- port->tx_bytes -= urb->transfer_buffer_length;
- __set_bit(0, &port->write_urbs_free);
- spin_unlock_irqrestore(&port->lock, flags);
- keyspan_pda_write_start(port);
- usb_serial_port_softint(port);
- }
- static int keyspan_pda_write(struct tty_struct *tty, struct usb_serial_port *port,
- const unsigned char *buf, int count)
- {
- int rc;
- dev_dbg(&port->dev, "%s - count = %d\n", __func__, count);
- if (!count)
- return 0;
- count = kfifo_in_locked(&port->write_fifo, buf, count, &port->lock);
- rc = keyspan_pda_write_start(port);
- if (rc)
- return rc;
- return count;
- }
- static void keyspan_pda_dtr_rts(struct usb_serial_port *port, int on)
- {
- struct usb_serial *serial = port->serial;
- if (on)
- keyspan_pda_set_modem_info(serial, BIT(7) | BIT(2));
- else
- keyspan_pda_set_modem_info(serial, 0);
- }
- static int keyspan_pda_open(struct tty_struct *tty,
- struct usb_serial_port *port)
- {
- struct keyspan_pda_private *priv = usb_get_serial_port_data(port);
- int rc;
- /* find out how much room is in the Tx ring */
- rc = keyspan_pda_get_write_room(priv);
- if (rc < 0)
- return rc;
- spin_lock_irq(&port->lock);
- priv->tx_room = rc;
- spin_unlock_irq(&port->lock);
- rc = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
- if (rc) {
- dev_dbg(&port->dev, "%s - usb_submit_urb(read int) failed\n", __func__);
- return rc;
- }
- return 0;
- }
- static void keyspan_pda_close(struct usb_serial_port *port)
- {
- struct keyspan_pda_private *priv = usb_get_serial_port_data(port);
- /*
- * Stop the interrupt URB first as its completion handler may submit
- * the write URB.
- */
- usb_kill_urb(port->interrupt_in_urb);
- usb_kill_urb(port->write_urb);
- cancel_work_sync(&priv->unthrottle_work);
- spin_lock_irq(&port->lock);
- kfifo_reset(&port->write_fifo);
- spin_unlock_irq(&port->lock);
- }
- /* download the firmware to a "fake" device (pre-renumeration) */
- static int keyspan_pda_fake_startup(struct usb_serial *serial)
- {
- unsigned int vid = le16_to_cpu(serial->dev->descriptor.idVendor);
- const char *fw_name;
- /* download the firmware here ... */
- ezusb_fx1_set_reset(serial->dev, 1);
- switch (vid) {
- case KEYSPAN_VENDOR_ID:
- fw_name = "keyspan_pda/keyspan_pda.fw";
- break;
- case XIRCOM_VENDOR_ID:
- case ENTREGA_VENDOR_ID:
- fw_name = "keyspan_pda/xircom_pgs.fw";
- break;
- default:
- dev_err(&serial->dev->dev, "%s: unknown vendor, aborting.\n",
- __func__);
- return -ENODEV;
- }
- if (ezusb_fx1_ihex_firmware_download(serial->dev, fw_name) < 0) {
- dev_err(&serial->dev->dev, "failed to load firmware \"%s\"\n",
- fw_name);
- return -ENOENT;
- }
- /*
- * After downloading firmware renumeration will occur in a moment and
- * the new device will bind to the real driver.
- */
- /* We want this device to fail to have a driver assigned to it. */
- return 1;
- }
- MODULE_FIRMWARE("keyspan_pda/keyspan_pda.fw");
- MODULE_FIRMWARE("keyspan_pda/xircom_pgs.fw");
- static int keyspan_pda_port_probe(struct usb_serial_port *port)
- {
- struct keyspan_pda_private *priv;
- priv = kmalloc(sizeof(struct keyspan_pda_private), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
- INIT_WORK(&priv->unthrottle_work, keyspan_pda_request_unthrottle);
- priv->port = port;
- usb_set_serial_port_data(port, priv);
- return 0;
- }
- static void keyspan_pda_port_remove(struct usb_serial_port *port)
- {
- struct keyspan_pda_private *priv;
- priv = usb_get_serial_port_data(port);
- kfree(priv);
- }
- static struct usb_serial_driver keyspan_pda_fake_device = {
- .driver = {
- .owner = THIS_MODULE,
- .name = "keyspan_pda_pre",
- },
- .description = "Keyspan PDA - (prerenumeration)",
- .id_table = id_table_fake,
- .num_ports = 1,
- .attach = keyspan_pda_fake_startup,
- };
- static struct usb_serial_driver keyspan_pda_device = {
- .driver = {
- .owner = THIS_MODULE,
- .name = "keyspan_pda",
- },
- .description = "Keyspan PDA",
- .id_table = id_table_std,
- .num_ports = 1,
- .num_bulk_out = 1,
- .num_interrupt_in = 1,
- .dtr_rts = keyspan_pda_dtr_rts,
- .open = keyspan_pda_open,
- .close = keyspan_pda_close,
- .write = keyspan_pda_write,
- .write_bulk_callback = keyspan_pda_write_bulk_callback,
- .read_int_callback = keyspan_pda_rx_interrupt,
- .throttle = keyspan_pda_rx_throttle,
- .unthrottle = keyspan_pda_rx_unthrottle,
- .set_termios = keyspan_pda_set_termios,
- .break_ctl = keyspan_pda_break_ctl,
- .tiocmget = keyspan_pda_tiocmget,
- .tiocmset = keyspan_pda_tiocmset,
- .port_probe = keyspan_pda_port_probe,
- .port_remove = keyspan_pda_port_remove,
- };
- static struct usb_serial_driver * const serial_drivers[] = {
- &keyspan_pda_device,
- &keyspan_pda_fake_device,
- NULL
- };
- module_usb_serial_driver(serial_drivers, id_table_combined);
- MODULE_AUTHOR(DRIVER_AUTHOR);
- MODULE_DESCRIPTION(DRIVER_DESC);
- MODULE_LICENSE("GPL");
|