diff options
author | Denis Joseph Barrow <D.Barow@option.com> | 2009-01-02 08:47:52 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-01-02 13:19:41 -0500 |
commit | 542f54823614915780c3459b0e6062f06c0c0f99 (patch) | |
tree | 5f2238ef62b1d6e39b8e428b2b7aa36f4ac714aa /drivers/net/usb/hso.c | |
parent | ac9720c37e8795317e8be3adad63cb0d5522a640 (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/usb/hso.c')
-rw-r--r-- | drivers/net/usb/hso.c | 331 |
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 | |||
204 | struct 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 | |||
213 | struct 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 | |||
185 | struct hso_serial { | 225 | struct 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); | |||
305 | static void async_put_intf(struct work_struct *data); | 346 | static void async_put_intf(struct work_struct *data); |
306 | static int hso_put_activity(struct hso_device *hso_dev); | 347 | static int hso_put_activity(struct hso_device *hso_dev); |
307 | static int hso_get_activity(struct hso_device *hso_dev); | 348 | static int hso_get_activity(struct hso_device *hso_dev); |
308 | 349 | static 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 | } |
1463 | int 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 | |||
1488 | static 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 | */ | ||
1567 | static int | ||
1568 | hso_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 | */ | ||
1616 | static 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 | ||
1423 | static int hso_serial_tiocmget(struct tty_struct *tty, struct file *file) | 1645 | static 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 | ||
1443 | static int hso_serial_tiocmset(struct tty_struct *tty, struct file *file, | 1676 | static 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 | ||
1715 | static 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 */ |
1483 | static void hso_kick_transmit(struct hso_serial *serial) | 1742 | static 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 | ||
2609 | static 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 ) */ |
2342 | static void hso_free_serial_device(struct hso_device *hso_dev) | 2624 | static 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( | |||
2416 | exit2: | 2719 | exit2: |
2417 | hso_serial_common_free(serial); | 2720 | hso_serial_common_free(serial); |
2418 | exit: | 2721 | exit: |
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, |