diff options
author | Denis Joseph Barrow <D.Barow@option.com> | 2008-11-25 03:35:26 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-11-25 03:35:26 -0500 |
commit | 7ea3a9ad9bf360f746a7ad6fa72511a5c359490d (patch) | |
tree | b0cc86b299173a11f88532449270f2bdf12204d0 /drivers/net/usb | |
parent | 52429eb216385fdc6969c0112ba8b46cffefaaef (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')
-rw-r--r-- | drivers/net/usb/hso.c | 329 |
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 | |||
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. |
@@ -310,7 +351,7 @@ static void async_get_intf(struct work_struct *data); | |||
310 | static void async_put_intf(struct work_struct *data); | 351 | static void async_put_intf(struct work_struct *data); |
311 | static int hso_put_activity(struct hso_device *hso_dev); | 352 | static int hso_put_activity(struct hso_device *hso_dev); |
312 | static int hso_get_activity(struct hso_device *hso_dev); | 353 | static int hso_get_activity(struct hso_device *hso_dev); |
313 | 354 | static 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 | } |
1504 | int 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 | |||
1529 | static 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 | */ | ||
1608 | static int | ||
1609 | hso_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 | */ | ||
1657 | static 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 | ||
1464 | static int hso_serial_tiocmget(struct tty_struct *tty, struct file *file) | 1686 | static 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 | ||
1484 | static int hso_serial_tiocmset(struct tty_struct *tty, struct file *file, | 1717 | static 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 | ||
1756 | static 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 */ |
1524 | static void hso_kick_transmit(struct hso_serial *serial) | 1783 | static 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 | ||
2639 | static 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 ) */ |
2372 | static void hso_free_serial_device(struct hso_device *hso_dev) | 2654 | static 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( | |||
2446 | exit2: | 2749 | exit2: |
2447 | hso_serial_common_free(serial); | 2750 | hso_serial_common_free(serial); |
2448 | exit: | 2751 | exit: |
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, |