aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorDenis Joseph Barrow <D.Barow@option.com>2009-01-02 08:47:52 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2009-01-02 13:19:41 -0500
commit542f54823614915780c3459b0e6062f06c0c0f99 (patch)
tree5f2238ef62b1d6e39b8e428b2b7aa36f4ac714aa /drivers/net
parentac9720c37e8795317e8be3adad63cb0d5522a640 (diff)
tty: Modem functions for the HSO driver
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: Alan Cox <alan@redhat.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/usb/hso.c331
1 files changed, 318 insertions, 13 deletions
diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c
index 7373fb6b3f88..d974d970e5fd 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.
@@ -305,7 +346,7 @@ static void async_get_intf(struct work_struct *data);
305static void async_put_intf(struct work_struct *data); 346static void async_put_intf(struct work_struct *data);
306static int hso_put_activity(struct hso_device *hso_dev); 347static int hso_put_activity(struct hso_device *hso_dev);
307static int hso_get_activity(struct hso_device *hso_dev); 348static int hso_get_activity(struct hso_device *hso_dev);
308 349static void tiocmget_intr_callback(struct urb *urb);
309/*****************************************************************************/ 350/*****************************************************************************/
310/* Helping functions */ 351/* Helping functions */
311/*****************************************************************************/ 352/*****************************************************************************/
@@ -1419,25 +1460,217 @@ static int hso_serial_chars_in_buffer(struct tty_struct *tty)
1419 1460
1420 return chars; 1461 return chars;
1421} 1462}
1463int tiocmget_submit_urb(struct hso_serial *serial,
1464 struct hso_tiocmget *tiocmget,
1465 struct usb_device *usb)
1466{
1467 int result;
1468
1469 if (serial->parent->usb_gone)
1470 return -ENODEV;
1471 usb_fill_int_urb(tiocmget->urb, usb,
1472 usb_rcvintpipe(usb,
1473 tiocmget->endp->
1474 bEndpointAddress & 0x7F),
1475 &tiocmget->serial_state_notification,
1476 sizeof(struct hso_serial_state_notification),
1477 tiocmget_intr_callback, serial,
1478 tiocmget->endp->bInterval);
1479 result = usb_submit_urb(tiocmget->urb, GFP_ATOMIC);
1480 if (result) {
1481 dev_warn(&usb->dev, "%s usb_submit_urb failed %d\n", __func__,
1482 result);
1483 }
1484 return result;
1485
1486}
1487
1488static void tiocmget_intr_callback(struct urb *urb)
1489{
1490 struct hso_serial *serial = urb->context;
1491 struct hso_tiocmget *tiocmget;
1492 int status = urb->status;
1493 u16 UART_state_bitmap, prev_UART_state_bitmap;
1494 struct uart_icount *icount;
1495 struct hso_serial_state_notification *serial_state_notification;
1496 struct usb_device *usb;
1497
1498 /* Sanity checks */
1499 if (!serial)
1500 return;
1501 if (status) {
1502 log_usb_status(status, __func__);
1503 return;
1504 }
1505 tiocmget = serial->tiocmget;
1506 if (!tiocmget)
1507 return;
1508 usb = serial->parent->usb;
1509 serial_state_notification = &tiocmget->serial_state_notification;
1510 if (serial_state_notification->bmRequestType != BM_REQUEST_TYPE ||
1511 serial_state_notification->bNotification != B_NOTIFICATION ||
1512 le16_to_cpu(serial_state_notification->wValue) != W_VALUE ||
1513 le16_to_cpu(serial_state_notification->wIndex) != W_INDEX ||
1514 le16_to_cpu(serial_state_notification->wLength) != W_LENGTH) {
1515 dev_warn(&usb->dev,
1516 "hso received invalid serial state notification\n");
1517 DUMP(serial_state_notification,
1518 sizeof(hso_serial_state_notifation))
1519 } else {
1520
1521 UART_state_bitmap = le16_to_cpu(serial_state_notification->
1522 UART_state_bitmap);
1523 prev_UART_state_bitmap = tiocmget->prev_UART_state_bitmap;
1524 icount = &tiocmget->icount;
1525 spin_lock(&serial->serial_lock);
1526 if ((UART_state_bitmap & B_OVERRUN) !=
1527 (prev_UART_state_bitmap & B_OVERRUN))
1528 icount->parity++;
1529 if ((UART_state_bitmap & B_PARITY) !=
1530 (prev_UART_state_bitmap & B_PARITY))
1531 icount->parity++;
1532 if ((UART_state_bitmap & B_FRAMING) !=
1533 (prev_UART_state_bitmap & B_FRAMING))
1534 icount->frame++;
1535 if ((UART_state_bitmap & B_RING_SIGNAL) &&
1536 !(prev_UART_state_bitmap & B_RING_SIGNAL))
1537 icount->rng++;
1538 if ((UART_state_bitmap & B_BREAK) !=
1539 (prev_UART_state_bitmap & B_BREAK))
1540 icount->brk++;
1541 if ((UART_state_bitmap & B_TX_CARRIER) !=
1542 (prev_UART_state_bitmap & B_TX_CARRIER))
1543 icount->dsr++;
1544 if ((UART_state_bitmap & B_RX_CARRIER) !=
1545 (prev_UART_state_bitmap & B_RX_CARRIER))
1546 icount->dcd++;
1547 tiocmget->prev_UART_state_bitmap = UART_state_bitmap;
1548 spin_unlock(&serial->serial_lock);
1549 tiocmget->intr_completed = 1;
1550 wake_up_interruptible(&tiocmget->waitq);
1551 }
1552 memset(serial_state_notification, 0,
1553 sizeof(struct hso_serial_state_notification));
1554 tiocmget_submit_urb(serial,
1555 tiocmget,
1556 serial->parent->usb);
1557}
1558
1559/*
1560 * next few functions largely stolen from drivers/serial/serial_core.c
1561 */
1562/* Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
1563 * - mask passed in arg for lines of interest
1564 * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
1565 * Caller should use TIOCGICOUNT to see which one it was
1566 */
1567static int
1568hso_wait_modem_status(struct hso_serial *serial, unsigned long arg)
1569{
1570 DECLARE_WAITQUEUE(wait, current);
1571 struct uart_icount cprev, cnow;
1572 struct hso_tiocmget *tiocmget;
1573 int ret;
1574
1575 tiocmget = serial->tiocmget;
1576 if (!tiocmget)
1577 return -ENOENT;
1578 /*
1579 * note the counters on entry
1580 */
1581 spin_lock_irq(&serial->serial_lock);
1582 memcpy(&cprev, &tiocmget->icount, sizeof(struct uart_icount));
1583 spin_unlock_irq(&serial->serial_lock);
1584 add_wait_queue(&tiocmget->waitq, &wait);
1585 for (;;) {
1586 spin_lock_irq(&serial->serial_lock);
1587 memcpy(&cnow, &tiocmget->icount, sizeof(struct uart_icount));
1588 spin_unlock_irq(&serial->serial_lock);
1589 set_current_state(TASK_INTERRUPTIBLE);
1590 if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
1591 ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
1592 ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd))) {
1593 ret = 0;
1594 break;
1595 }
1596 schedule();
1597 /* see if a signal did it */
1598 if (signal_pending(current)) {
1599 ret = -ERESTARTSYS;
1600 break;
1601 }
1602 cprev = cnow;
1603 }
1604 current->state = TASK_RUNNING;
1605 remove_wait_queue(&tiocmget->waitq, &wait);
1606
1607 return ret;
1608}
1609
1610/*
1611 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
1612 * Return: write counters to the user passed counter struct
1613 * NB: both 1->0 and 0->1 transitions are counted except for
1614 * RI where only 0->1 is counted.
1615 */
1616static int hso_get_count(struct hso_serial *serial,
1617 struct serial_icounter_struct __user *icnt)
1618{
1619 struct serial_icounter_struct icount;
1620 struct uart_icount cnow;
1621 struct hso_tiocmget *tiocmget = serial->tiocmget;
1622
1623 if (!tiocmget)
1624 return -ENOENT;
1625 spin_lock_irq(&serial->serial_lock);
1626 memcpy(&cnow, &tiocmget->icount, sizeof(struct uart_icount));
1627 spin_unlock_irq(&serial->serial_lock);
1628
1629 icount.cts = cnow.cts;
1630 icount.dsr = cnow.dsr;
1631 icount.rng = cnow.rng;
1632 icount.dcd = cnow.dcd;
1633 icount.rx = cnow.rx;
1634 icount.tx = cnow.tx;
1635 icount.frame = cnow.frame;
1636 icount.overrun = cnow.overrun;
1637 icount.parity = cnow.parity;
1638 icount.brk = cnow.brk;
1639 icount.buf_overrun = cnow.buf_overrun;
1640
1641 return copy_to_user(icnt, &icount, sizeof(icount)) ? -EFAULT : 0;
1642}
1643
1422 1644
1423static int hso_serial_tiocmget(struct tty_struct *tty, struct file *file) 1645static int hso_serial_tiocmget(struct tty_struct *tty, struct file *file)
1424{ 1646{
1425 unsigned int value; 1647 int retval;
1426 struct hso_serial *serial = get_serial_by_tty(tty); 1648 struct hso_serial *serial = get_serial_by_tty(tty);
1427 unsigned long flags; 1649 struct hso_tiocmget *tiocmget;
1650 u16 UART_state_bitmap;
1428 1651
1429 /* sanity check */ 1652 /* sanity check */
1430 if (!serial) { 1653 if (!serial) {
1431 D1("no tty structures"); 1654 D1("no tty structures");
1432 return -EINVAL; 1655 return -EINVAL;
1433 } 1656 }
1434 1657 spin_lock_irq(&serial->serial_lock);
1435 spin_lock_irqsave(&serial->serial_lock, flags); 1658 retval = ((serial->rts_state) ? TIOCM_RTS : 0) |
1436 value = ((serial->rts_state) ? TIOCM_RTS : 0) |
1437 ((serial->dtr_state) ? TIOCM_DTR : 0); 1659 ((serial->dtr_state) ? TIOCM_DTR : 0);
1438 spin_unlock_irqrestore(&serial->serial_lock, flags); 1660 tiocmget = serial->tiocmget;
1439 1661 if (tiocmget) {
1440 return value; 1662
1663 UART_state_bitmap = le16_to_cpu(
1664 tiocmget->prev_UART_state_bitmap);
1665 if (UART_state_bitmap & B_RING_SIGNAL)
1666 retval |= TIOCM_RNG;
1667 if (UART_state_bitmap & B_RX_CARRIER)
1668 retval |= TIOCM_CD;
1669 if (UART_state_bitmap & B_TX_CARRIER)
1670 retval |= TIOCM_DSR;
1671 }
1672 spin_unlock_irq(&serial->serial_lock);
1673 return retval;
1441} 1674}
1442 1675
1443static int hso_serial_tiocmset(struct tty_struct *tty, struct file *file, 1676static int hso_serial_tiocmset(struct tty_struct *tty, struct file *file,
@@ -1479,6 +1712,32 @@ static int hso_serial_tiocmset(struct tty_struct *tty, struct file *file,
1479 USB_CTRL_SET_TIMEOUT); 1712 USB_CTRL_SET_TIMEOUT);
1480} 1713}
1481 1714
1715static int hso_serial_ioctl(struct tty_struct *tty, struct file *file,
1716 unsigned int cmd, unsigned long arg)
1717{
1718 struct hso_serial *serial = get_serial_by_tty(tty);
1719 void __user *uarg = (void __user *)arg;
1720 int ret = 0;
1721 D4("IOCTL cmd: %d, arg: %ld", cmd, arg);
1722
1723 if (!serial)
1724 return -ENODEV;
1725 switch (cmd) {
1726 case TIOCMIWAIT:
1727 ret = hso_wait_modem_status(serial, arg);
1728 break;
1729
1730 case TIOCGICOUNT:
1731 ret = hso_get_count(serial, uarg);
1732 break;
1733 default:
1734 ret = -ENOIOCTLCMD;
1735 break;
1736 }
1737 return ret;
1738}
1739
1740
1482/* starts a transmit */ 1741/* starts a transmit */
1483static void hso_kick_transmit(struct hso_serial *serial) 1742static void hso_kick_transmit(struct hso_serial *serial)
1484{ 1743{
@@ -1956,7 +2215,10 @@ static int hso_start_serial_device(struct hso_device *hso_dev, gfp_t flags)
1956 serial->shared_int->use_count++; 2215 serial->shared_int->use_count++;
1957 mutex_unlock(&serial->shared_int->shared_int_lock); 2216 mutex_unlock(&serial->shared_int->shared_int_lock);
1958 } 2217 }
1959 2218 if (serial->tiocmget)
2219 tiocmget_submit_urb(serial,
2220 serial->tiocmget,
2221 serial->parent->usb);
1960 return result; 2222 return result;
1961} 2223}
1962 2224
@@ -1964,6 +2226,7 @@ static int hso_stop_serial_device(struct hso_device *hso_dev)
1964{ 2226{
1965 int i; 2227 int i;
1966 struct hso_serial *serial = dev2ser(hso_dev); 2228 struct hso_serial *serial = dev2ser(hso_dev);
2229 struct hso_tiocmget *tiocmget;
1967 2230
1968 if (!serial) 2231 if (!serial)
1969 return -ENODEV; 2232 return -ENODEV;
@@ -1992,6 +2255,11 @@ static int hso_stop_serial_device(struct hso_device *hso_dev)
1992 } 2255 }
1993 mutex_unlock(&serial->shared_int->shared_int_lock); 2256 mutex_unlock(&serial->shared_int->shared_int_lock);
1994 } 2257 }
2258 tiocmget = serial->tiocmget;
2259 if (tiocmget) {
2260 wake_up_interruptible(&tiocmget->waitq);
2261 usb_kill_urb(tiocmget->urb);
2262 }
1995 2263
1996 return 0; 2264 return 0;
1997} 2265}
@@ -2338,6 +2606,20 @@ exit:
2338 return NULL; 2606 return NULL;
2339} 2607}
2340 2608
2609static void hso_free_tiomget(struct hso_serial *serial)
2610{
2611 struct hso_tiocmget *tiocmget = serial->tiocmget;
2612 if (tiocmget) {
2613 kfree(tiocmget);
2614 if (tiocmget->urb) {
2615 usb_free_urb(tiocmget->urb);
2616 tiocmget->urb = NULL;
2617 }
2618 serial->tiocmget = NULL;
2619
2620 }
2621}
2622
2341/* Frees an AT channel ( goes for both mux and non-mux ) */ 2623/* Frees an AT channel ( goes for both mux and non-mux ) */
2342static void hso_free_serial_device(struct hso_device *hso_dev) 2624static void hso_free_serial_device(struct hso_device *hso_dev)
2343{ 2625{
@@ -2356,6 +2638,7 @@ static void hso_free_serial_device(struct hso_device *hso_dev)
2356 else 2638 else
2357 mutex_unlock(&serial->shared_int->shared_int_lock); 2639 mutex_unlock(&serial->shared_int->shared_int_lock);
2358 } 2640 }
2641 hso_free_tiomget(serial);
2359 kfree(serial); 2642 kfree(serial);
2360 hso_free_device(hso_dev); 2643 hso_free_device(hso_dev);
2361} 2644}
@@ -2367,6 +2650,7 @@ static struct hso_device *hso_create_bulk_serial_device(
2367 struct hso_device *hso_dev; 2650 struct hso_device *hso_dev;
2368 struct hso_serial *serial; 2651 struct hso_serial *serial;
2369 int num_urbs; 2652 int num_urbs;
2653 struct hso_tiocmget *tiocmget;
2370 2654
2371 hso_dev = hso_create_device(interface, port); 2655 hso_dev = hso_create_device(interface, port);
2372 if (!hso_dev) 2656 if (!hso_dev)
@@ -2379,8 +2663,27 @@ static struct hso_device *hso_create_bulk_serial_device(
2379 serial->parent = hso_dev; 2663 serial->parent = hso_dev;
2380 hso_dev->port_data.dev_serial = serial; 2664 hso_dev->port_data.dev_serial = serial;
2381 2665
2382 if (port & HSO_PORT_MODEM) 2666 if (port & HSO_PORT_MODEM) {
2383 num_urbs = 2; 2667 num_urbs = 2;
2668 serial->tiocmget = kzalloc(sizeof(struct hso_tiocmget),
2669 GFP_KERNEL);
2670 /* it isn't going to break our heart if serial->tiocmget
2671 * allocation fails don't bother checking this.
2672 */
2673 if (serial->tiocmget) {
2674 tiocmget = serial->tiocmget;
2675 tiocmget->urb = usb_alloc_urb(0, GFP_KERNEL);
2676 if (tiocmget->urb) {
2677 mutex_init(&tiocmget->mutex);
2678 init_waitqueue_head(&tiocmget->waitq);
2679 tiocmget->endp = hso_get_ep(
2680 interface,
2681 USB_ENDPOINT_XFER_INT,
2682 USB_DIR_IN);
2683 } else
2684 hso_free_tiomget(serial);
2685 }
2686 }
2384 else 2687 else
2385 num_urbs = 1; 2688 num_urbs = 1;
2386 2689
@@ -2416,6 +2719,7 @@ static struct hso_device *hso_create_bulk_serial_device(
2416exit2: 2719exit2:
2417 hso_serial_common_free(serial); 2720 hso_serial_common_free(serial);
2418exit: 2721exit:
2722 hso_free_tiomget(serial);
2419 kfree(serial); 2723 kfree(serial);
2420 hso_free_device(hso_dev); 2724 hso_free_device(hso_dev);
2421 return NULL; 2725 return NULL;
@@ -2926,6 +3230,7 @@ static const struct tty_operations hso_serial_ops = {
2926 .close = hso_serial_close, 3230 .close = hso_serial_close,
2927 .write = hso_serial_write, 3231 .write = hso_serial_write,
2928 .write_room = hso_serial_write_room, 3232 .write_room = hso_serial_write_room,
3233 .ioctl = hso_serial_ioctl,
2929 .set_termios = hso_serial_set_termios, 3234 .set_termios = hso_serial_set_termios,
2930 .chars_in_buffer = hso_serial_chars_in_buffer, 3235 .chars_in_buffer = hso_serial_chars_in_buffer,
2931 .tiocmget = hso_serial_tiocmget, 3236 .tiocmget = hso_serial_tiocmget,