aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/usb/hso.c
diff options
context:
space:
mode:
authorDenis Joseph Barrow <D.Barow@option.com>2008-11-25 03:35:26 -0500
committerDavid S. Miller <davem@davemloft.net>2008-11-25 03:35:26 -0500
commit7ea3a9ad9bf360f746a7ad6fa72511a5c359490d (patch)
treeb0cc86b299173a11f88532449270f2bdf12204d0 /drivers/net/usb/hso.c
parent52429eb216385fdc6969c0112ba8b46cffefaaef (diff)
hso: Add TIOCM ioctl handling.
Makes TIOCM ioctls for Data Carrier Detect & related functions work like /drivers/serial/serial-core.c potentially needed for pppd & similar user programs. Signed-off-by: Denis Joseph Barrow <D.Barow@option.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/usb/hso.c')
-rw-r--r--drivers/net/usb/hso.c329
1 files changed, 317 insertions, 12 deletions
diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c
index cc37a2e67177..fd723dc79c50 100644
--- a/drivers/net/usb/hso.c
+++ b/drivers/net/usb/hso.c
@@ -39,8 +39,11 @@
39 * port is opened, as this have a huge impact on the network port 39 * port is opened, as this have a huge impact on the network port
40 * throughput. 40 * throughput.
41 * 41 *
42 * Interface 2: Standard modem interface - circuit switched interface, should 42 * Interface 2: Standard modem interface - circuit switched interface, this
43 * not be used. 43 * can be used to make a standard ppp connection however it
44 * should not be used in conjunction with the IP network interface
45 * enabled for USB performance reasons i.e. if using this set
46 * ideally disable_net=1.
44 * 47 *
45 *****************************************************************************/ 48 *****************************************************************************/
46 49
@@ -63,6 +66,8 @@
63#include <linux/usb/cdc.h> 66#include <linux/usb/cdc.h>
64#include <net/arp.h> 67#include <net/arp.h>
65#include <asm/byteorder.h> 68#include <asm/byteorder.h>
69#include <linux/serial_core.h>
70#include <linux/serial.h>
66 71
67 72
68#define DRIVER_VERSION "1.2" 73#define DRIVER_VERSION "1.2"
@@ -182,6 +187,41 @@ enum rx_ctrl_state{
182 RX_PENDING 187 RX_PENDING
183}; 188};
184 189
190#define BM_REQUEST_TYPE (0xa1)
191#define B_NOTIFICATION (0x20)
192#define W_VALUE (0x0)
193#define W_INDEX (0x2)
194#define W_LENGTH (0x2)
195
196#define B_OVERRUN (0x1<<6)
197#define B_PARITY (0x1<<5)
198#define B_FRAMING (0x1<<4)
199#define B_RING_SIGNAL (0x1<<3)
200#define B_BREAK (0x1<<2)
201#define B_TX_CARRIER (0x1<<1)
202#define B_RX_CARRIER (0x1<<0)
203
204struct hso_serial_state_notification {
205 u8 bmRequestType;
206 u8 bNotification;
207 u16 wValue;
208 u16 wIndex;
209 u16 wLength;
210 u16 UART_state_bitmap;
211} __attribute__((packed));
212
213struct hso_tiocmget {
214 struct mutex mutex;
215 wait_queue_head_t waitq;
216 int intr_completed;
217 struct usb_endpoint_descriptor *endp;
218 struct urb *urb;
219 struct hso_serial_state_notification serial_state_notification;
220 u16 prev_UART_state_bitmap;
221 struct uart_icount icount;
222};
223
224
185struct hso_serial { 225struct hso_serial {
186 struct hso_device *parent; 226 struct hso_device *parent;
187 int magic; 227 int magic;
@@ -219,6 +259,7 @@ struct hso_serial {
219 spinlock_t serial_lock; 259 spinlock_t serial_lock;
220 260
221 int (*write_data) (struct hso_serial *serial); 261 int (*write_data) (struct hso_serial *serial);
262 struct hso_tiocmget *tiocmget;
222 /* Hacks required to get flow control 263 /* Hacks required to get flow control
223 * working on the serial receive buffers 264 * working on the serial receive buffers
224 * so as not to drop characters on the floor. 265 * so as not to drop characters on the floor.
@@ -310,7 +351,7 @@ static void async_get_intf(struct work_struct *data);
310static void async_put_intf(struct work_struct *data); 351static void async_put_intf(struct work_struct *data);
311static int hso_put_activity(struct hso_device *hso_dev); 352static int hso_put_activity(struct hso_device *hso_dev);
312static int hso_get_activity(struct hso_device *hso_dev); 353static int hso_get_activity(struct hso_device *hso_dev);
313 354static void tiocmget_intr_callback(struct urb *urb);
314/*****************************************************************************/ 355/*****************************************************************************/
315/* Helping functions */ 356/* Helping functions */
316/*****************************************************************************/ 357/*****************************************************************************/
@@ -1460,25 +1501,217 @@ static int hso_serial_chars_in_buffer(struct tty_struct *tty)
1460 1501
1461 return chars; 1502 return chars;
1462} 1503}
1504int tiocmget_submit_urb(struct hso_serial *serial,
1505 struct hso_tiocmget *tiocmget,
1506 struct usb_device *usb)
1507{
1508 int result;
1509
1510 if (serial->parent->usb_gone)
1511 return -ENODEV;
1512 usb_fill_int_urb(tiocmget->urb, usb,
1513 usb_rcvintpipe(usb,
1514 tiocmget->endp->
1515 bEndpointAddress & 0x7F),
1516 &tiocmget->serial_state_notification,
1517 sizeof(struct hso_serial_state_notification),
1518 tiocmget_intr_callback, serial,
1519 tiocmget->endp->bInterval);
1520 result = usb_submit_urb(tiocmget->urb, GFP_ATOMIC);
1521 if (result) {
1522 dev_warn(&usb->dev, "%s usb_submit_urb failed %d\n", __func__,
1523 result);
1524 }
1525 return result;
1526
1527}
1528
1529static void tiocmget_intr_callback(struct urb *urb)
1530{
1531 struct hso_serial *serial = urb->context;
1532 struct hso_tiocmget *tiocmget;
1533 int status = urb->status;
1534 u16 UART_state_bitmap, prev_UART_state_bitmap;
1535 struct uart_icount *icount;
1536 struct hso_serial_state_notification *serial_state_notification;
1537 struct usb_device *usb;
1538
1539 /* Sanity checks */
1540 if (!serial)
1541 return;
1542 if (status) {
1543 log_usb_status(status, __func__);
1544 return;
1545 }
1546 tiocmget = serial->tiocmget;
1547 if (!tiocmget)
1548 return;
1549 usb = serial->parent->usb;
1550 serial_state_notification = &tiocmget->serial_state_notification;
1551 if (serial_state_notification->bmRequestType != BM_REQUEST_TYPE ||
1552 serial_state_notification->bNotification != B_NOTIFICATION ||
1553 le16_to_cpu(serial_state_notification->wValue) != W_VALUE ||
1554 le16_to_cpu(serial_state_notification->wIndex) != W_INDEX ||
1555 le16_to_cpu(serial_state_notification->wLength) != W_LENGTH) {
1556 dev_warn(&usb->dev,
1557 "hso received invalid serial state notification\n");
1558 DUMP(serial_state_notification,
1559 sizeof(hso_serial_state_notifation))
1560 } else {
1561
1562 UART_state_bitmap = le16_to_cpu(serial_state_notification->
1563 UART_state_bitmap);
1564 prev_UART_state_bitmap = tiocmget->prev_UART_state_bitmap;
1565 icount = &tiocmget->icount;
1566 spin_lock(&serial->serial_lock);
1567 if ((UART_state_bitmap & B_OVERRUN) !=
1568 (prev_UART_state_bitmap & B_OVERRUN))
1569 icount->parity++;
1570 if ((UART_state_bitmap & B_PARITY) !=
1571 (prev_UART_state_bitmap & B_PARITY))
1572 icount->parity++;
1573 if ((UART_state_bitmap & B_FRAMING) !=
1574 (prev_UART_state_bitmap & B_FRAMING))
1575 icount->frame++;
1576 if ((UART_state_bitmap & B_RING_SIGNAL) &&
1577 !(prev_UART_state_bitmap & B_RING_SIGNAL))
1578 icount->rng++;
1579 if ((UART_state_bitmap & B_BREAK) !=
1580 (prev_UART_state_bitmap & B_BREAK))
1581 icount->brk++;
1582 if ((UART_state_bitmap & B_TX_CARRIER) !=
1583 (prev_UART_state_bitmap & B_TX_CARRIER))
1584 icount->dsr++;
1585 if ((UART_state_bitmap & B_RX_CARRIER) !=
1586 (prev_UART_state_bitmap & B_RX_CARRIER))
1587 icount->dcd++;
1588 tiocmget->prev_UART_state_bitmap = UART_state_bitmap;
1589 spin_unlock(&serial->serial_lock);
1590 tiocmget->intr_completed = 1;
1591 wake_up_interruptible(&tiocmget->waitq);
1592 }
1593 memset(serial_state_notification, 0,
1594 sizeof(struct hso_serial_state_notification));
1595 tiocmget_submit_urb(serial,
1596 tiocmget,
1597 serial->parent->usb);
1598}
1599
1600/*
1601 * next few functions largely stolen from drivers/serial/serial_core.c
1602 */
1603/* Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
1604 * - mask passed in arg for lines of interest
1605 * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
1606 * Caller should use TIOCGICOUNT to see which one it was
1607 */
1608static int
1609hso_wait_modem_status(struct hso_serial *serial, unsigned long arg)
1610{
1611 DECLARE_WAITQUEUE(wait, current);
1612 struct uart_icount cprev, cnow;
1613 struct hso_tiocmget *tiocmget;
1614 int ret;
1615
1616 tiocmget = serial->tiocmget;
1617 if (!tiocmget)
1618 return -ENOENT;
1619 /*
1620 * note the counters on entry
1621 */
1622 spin_lock_irq(&serial->serial_lock);
1623 memcpy(&cprev, &tiocmget->icount, sizeof(struct uart_icount));
1624 spin_unlock_irq(&serial->serial_lock);
1625 add_wait_queue(&tiocmget->waitq, &wait);
1626 for (;;) {
1627 spin_lock_irq(&serial->serial_lock);
1628 memcpy(&cnow, &tiocmget->icount, sizeof(struct uart_icount));
1629 spin_unlock_irq(&serial->serial_lock);
1630 set_current_state(TASK_INTERRUPTIBLE);
1631 if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
1632 ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
1633 ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd))) {
1634 ret = 0;
1635 break;
1636 }
1637 schedule();
1638 /* see if a signal did it */
1639 if (signal_pending(current)) {
1640 ret = -ERESTARTSYS;
1641 break;
1642 }
1643 cprev = cnow;
1644 }
1645 current->state = TASK_RUNNING;
1646 remove_wait_queue(&tiocmget->waitq, &wait);
1647
1648 return ret;
1649}
1650
1651/*
1652 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
1653 * Return: write counters to the user passed counter struct
1654 * NB: both 1->0 and 0->1 transitions are counted except for
1655 * RI where only 0->1 is counted.
1656 */
1657static int hso_get_count(struct hso_serial *serial,
1658 struct serial_icounter_struct __user *icnt)
1659{
1660 struct serial_icounter_struct icount;
1661 struct uart_icount cnow;
1662 struct hso_tiocmget *tiocmget = serial->tiocmget;
1663
1664 if (!tiocmget)
1665 return -ENOENT;
1666 spin_lock_irq(&serial->serial_lock);
1667 memcpy(&cnow, &tiocmget->icount, sizeof(struct uart_icount));
1668 spin_unlock_irq(&serial->serial_lock);
1669
1670 icount.cts = cnow.cts;
1671 icount.dsr = cnow.dsr;
1672 icount.rng = cnow.rng;
1673 icount.dcd = cnow.dcd;
1674 icount.rx = cnow.rx;
1675 icount.tx = cnow.tx;
1676 icount.frame = cnow.frame;
1677 icount.overrun = cnow.overrun;
1678 icount.parity = cnow.parity;
1679 icount.brk = cnow.brk;
1680 icount.buf_overrun = cnow.buf_overrun;
1681
1682 return copy_to_user(icnt, &icount, sizeof(icount)) ? -EFAULT : 0;
1683}
1684
1463 1685
1464static int hso_serial_tiocmget(struct tty_struct *tty, struct file *file) 1686static int hso_serial_tiocmget(struct tty_struct *tty, struct file *file)
1465{ 1687{
1466 unsigned int value; 1688 int retval;
1467 struct hso_serial *serial = get_serial_by_tty(tty); 1689 struct hso_serial *serial = get_serial_by_tty(tty);
1468 unsigned long flags; 1690 struct hso_tiocmget *tiocmget;
1691 u16 UART_state_bitmap;
1469 1692
1470 /* sanity check */ 1693 /* sanity check */
1471 if (!serial) { 1694 if (!serial) {
1472 D1("no tty structures"); 1695 D1("no tty structures");
1473 return -EINVAL; 1696 return -EINVAL;
1474 } 1697 }
1475 1698 spin_lock_irq(&serial->serial_lock);
1476 spin_lock_irqsave(&serial->serial_lock, flags); 1699 retval = ((serial->rts_state) ? TIOCM_RTS : 0) |
1477 value = ((serial->rts_state) ? TIOCM_RTS : 0) |
1478 ((serial->dtr_state) ? TIOCM_DTR : 0); 1700 ((serial->dtr_state) ? TIOCM_DTR : 0);
1479 spin_unlock_irqrestore(&serial->serial_lock, flags); 1701 tiocmget = serial->tiocmget;
1702 if (tiocmget) {
1480 1703
1481 return value; 1704 UART_state_bitmap = le16_to_cpu(
1705 tiocmget->prev_UART_state_bitmap);
1706 if (UART_state_bitmap & B_RING_SIGNAL)
1707 retval |= TIOCM_RNG;
1708 if (UART_state_bitmap & B_RX_CARRIER)
1709 retval |= TIOCM_CD;
1710 if (UART_state_bitmap & B_TX_CARRIER)
1711 retval |= TIOCM_DSR;
1712 }
1713 spin_unlock_irq(&serial->serial_lock);
1714 return retval;
1482} 1715}
1483 1716
1484static int hso_serial_tiocmset(struct tty_struct *tty, struct file *file, 1717static int hso_serial_tiocmset(struct tty_struct *tty, struct file *file,
@@ -1520,6 +1753,32 @@ static int hso_serial_tiocmset(struct tty_struct *tty, struct file *file,
1520 USB_CTRL_SET_TIMEOUT); 1753 USB_CTRL_SET_TIMEOUT);
1521} 1754}
1522 1755
1756static int hso_serial_ioctl(struct tty_struct *tty, struct file *file,
1757 unsigned int cmd, unsigned long arg)
1758{
1759 struct hso_serial *serial = get_serial_by_tty(tty);
1760 void __user *uarg = (void __user *)arg;
1761 int ret = 0;
1762 D4("IOCTL cmd: %d, arg: %ld", cmd, arg);
1763
1764 if (!serial)
1765 return -ENODEV;
1766 switch (cmd) {
1767 case TIOCMIWAIT:
1768 ret = hso_wait_modem_status(serial, arg);
1769 break;
1770
1771 case TIOCGICOUNT:
1772 ret = hso_get_count(serial, uarg);
1773 break;
1774 default:
1775 ret = -ENOIOCTLCMD;
1776 break;
1777 }
1778 return ret;
1779}
1780
1781
1523/* starts a transmit */ 1782/* starts a transmit */
1524static void hso_kick_transmit(struct hso_serial *serial) 1783static void hso_kick_transmit(struct hso_serial *serial)
1525{ 1784{
@@ -1982,7 +2241,10 @@ static int hso_start_serial_device(struct hso_device *hso_dev, gfp_t flags)
1982 serial->shared_int->use_count++; 2241 serial->shared_int->use_count++;
1983 mutex_unlock(&serial->shared_int->shared_int_lock); 2242 mutex_unlock(&serial->shared_int->shared_int_lock);
1984 } 2243 }
1985 2244 if (serial->tiocmget)
2245 tiocmget_submit_urb(serial,
2246 serial->tiocmget,
2247 serial->parent->usb);
1986 return result; 2248 return result;
1987} 2249}
1988 2250
@@ -1990,6 +2252,7 @@ static int hso_stop_serial_device(struct hso_device *hso_dev)
1990{ 2252{
1991 int i; 2253 int i;
1992 struct hso_serial *serial = dev2ser(hso_dev); 2254 struct hso_serial *serial = dev2ser(hso_dev);
2255 struct hso_tiocmget *tiocmget;
1993 2256
1994 if (!serial) 2257 if (!serial)
1995 return -ENODEV; 2258 return -ENODEV;
@@ -2018,6 +2281,11 @@ static int hso_stop_serial_device(struct hso_device *hso_dev)
2018 } 2281 }
2019 mutex_unlock(&serial->shared_int->shared_int_lock); 2282 mutex_unlock(&serial->shared_int->shared_int_lock);
2020 } 2283 }
2284 tiocmget = serial->tiocmget;
2285 if (tiocmget) {
2286 wake_up_interruptible(&tiocmget->waitq);
2287 usb_kill_urb(tiocmget->urb);
2288 }
2021 2289
2022 return 0; 2290 return 0;
2023} 2291}
@@ -2368,6 +2636,20 @@ exit:
2368 return NULL; 2636 return NULL;
2369} 2637}
2370 2638
2639static void hso_free_tiomget(struct hso_serial *serial)
2640{
2641 struct hso_tiocmget *tiocmget = serial->tiocmget;
2642 if (tiocmget) {
2643 kfree(tiocmget);
2644 if (tiocmget->urb) {
2645 usb_free_urb(tiocmget->urb);
2646 tiocmget->urb = NULL;
2647 }
2648 serial->tiocmget = NULL;
2649
2650 }
2651}
2652
2371/* Frees an AT channel ( goes for both mux and non-mux ) */ 2653/* Frees an AT channel ( goes for both mux and non-mux ) */
2372static void hso_free_serial_device(struct hso_device *hso_dev) 2654static void hso_free_serial_device(struct hso_device *hso_dev)
2373{ 2655{
@@ -2386,6 +2668,7 @@ static void hso_free_serial_device(struct hso_device *hso_dev)
2386 else 2668 else
2387 mutex_unlock(&serial->shared_int->shared_int_lock); 2669 mutex_unlock(&serial->shared_int->shared_int_lock);
2388 } 2670 }
2671 hso_free_tiomget(serial);
2389 kfree(serial); 2672 kfree(serial);
2390 hso_free_device(hso_dev); 2673 hso_free_device(hso_dev);
2391} 2674}
@@ -2397,6 +2680,7 @@ static struct hso_device *hso_create_bulk_serial_device(
2397 struct hso_device *hso_dev; 2680 struct hso_device *hso_dev;
2398 struct hso_serial *serial; 2681 struct hso_serial *serial;
2399 int num_urbs; 2682 int num_urbs;
2683 struct hso_tiocmget *tiocmget;
2400 2684
2401 hso_dev = hso_create_device(interface, port); 2685 hso_dev = hso_create_device(interface, port);
2402 if (!hso_dev) 2686 if (!hso_dev)
@@ -2409,8 +2693,27 @@ static struct hso_device *hso_create_bulk_serial_device(
2409 serial->parent = hso_dev; 2693 serial->parent = hso_dev;
2410 hso_dev->port_data.dev_serial = serial; 2694 hso_dev->port_data.dev_serial = serial;
2411 2695
2412 if (port & HSO_PORT_MODEM) 2696 if (port & HSO_PORT_MODEM) {
2413 num_urbs = 2; 2697 num_urbs = 2;
2698 serial->tiocmget = kzalloc(sizeof(struct hso_tiocmget),
2699 GFP_KERNEL);
2700 /* it isn't going to break our heart if serial->tiocmget
2701 * allocation fails don't bother checking this.
2702 */
2703 if (serial->tiocmget) {
2704 tiocmget = serial->tiocmget;
2705 tiocmget->urb = usb_alloc_urb(0, GFP_KERNEL);
2706 if (tiocmget->urb) {
2707 mutex_init(&tiocmget->mutex);
2708 init_waitqueue_head(&tiocmget->waitq);
2709 tiocmget->endp = hso_get_ep(
2710 interface,
2711 USB_ENDPOINT_XFER_INT,
2712 USB_DIR_IN);
2713 } else
2714 hso_free_tiomget(serial);
2715 }
2716 }
2414 else 2717 else
2415 num_urbs = 1; 2718 num_urbs = 1;
2416 2719
@@ -2446,6 +2749,7 @@ static struct hso_device *hso_create_bulk_serial_device(
2446exit2: 2749exit2:
2447 hso_serial_common_free(serial); 2750 hso_serial_common_free(serial);
2448exit: 2751exit:
2752 hso_free_tiomget(serial);
2449 kfree(serial); 2753 kfree(serial);
2450 hso_free_device(hso_dev); 2754 hso_free_device(hso_dev);
2451 return NULL; 2755 return NULL;
@@ -2958,6 +3262,7 @@ static const struct tty_operations hso_serial_ops = {
2958 .close = hso_serial_close, 3262 .close = hso_serial_close,
2959 .write = hso_serial_write, 3263 .write = hso_serial_write,
2960 .write_room = hso_serial_write_room, 3264 .write_room = hso_serial_write_room,
3265 .ioctl = hso_serial_ioctl,
2961 .set_termios = hso_serial_set_termios, 3266 .set_termios = hso_serial_set_termios,
2962 .chars_in_buffer = hso_serial_chars_in_buffer, 3267 .chars_in_buffer = hso_serial_chars_in_buffer,
2963 .tiocmget = hso_serial_tiocmget, 3268 .tiocmget = hso_serial_tiocmget,