diff options
Diffstat (limited to 'drivers/net/usb/hso.c')
-rw-r--r-- | drivers/net/usb/hso.c | 434 |
1 files changed, 389 insertions, 45 deletions
diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index 9f7896a25f1b..c4918b86ed19 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c | |||
@@ -3,6 +3,8 @@ | |||
3 | * Driver for Option High Speed Mobile Devices. | 3 | * Driver for Option High Speed Mobile Devices. |
4 | * | 4 | * |
5 | * Copyright (C) 2008 Option International | 5 | * Copyright (C) 2008 Option International |
6 | * Filip Aben <f.aben@option.com> | ||
7 | * Denis Joseph Barrow <d.barow@option.com> | ||
6 | * Copyright (C) 2007 Andrew Bird (Sphere Systems Ltd) | 8 | * Copyright (C) 2007 Andrew Bird (Sphere Systems Ltd) |
7 | * <ajb@spheresystems.co.uk> | 9 | * <ajb@spheresystems.co.uk> |
8 | * Copyright (C) 2008 Greg Kroah-Hartman <gregkh@suse.de> | 10 | * Copyright (C) 2008 Greg Kroah-Hartman <gregkh@suse.de> |
@@ -39,8 +41,11 @@ | |||
39 | * port is opened, as this have a huge impact on the network port | 41 | * port is opened, as this have a huge impact on the network port |
40 | * throughput. | 42 | * throughput. |
41 | * | 43 | * |
42 | * Interface 2: Standard modem interface - circuit switched interface, should | 44 | * Interface 2: Standard modem interface - circuit switched interface, this |
43 | * not be used. | 45 | * can be used to make a standard ppp connection however it |
46 | * should not be used in conjunction with the IP network interface | ||
47 | * enabled for USB performance reasons i.e. if using this set | ||
48 | * ideally disable_net=1. | ||
44 | * | 49 | * |
45 | *****************************************************************************/ | 50 | *****************************************************************************/ |
46 | 51 | ||
@@ -63,6 +68,8 @@ | |||
63 | #include <linux/usb/cdc.h> | 68 | #include <linux/usb/cdc.h> |
64 | #include <net/arp.h> | 69 | #include <net/arp.h> |
65 | #include <asm/byteorder.h> | 70 | #include <asm/byteorder.h> |
71 | #include <linux/serial_core.h> | ||
72 | #include <linux/serial.h> | ||
66 | 73 | ||
67 | 74 | ||
68 | #define DRIVER_VERSION "1.2" | 75 | #define DRIVER_VERSION "1.2" |
@@ -182,6 +189,41 @@ enum rx_ctrl_state{ | |||
182 | RX_PENDING | 189 | RX_PENDING |
183 | }; | 190 | }; |
184 | 191 | ||
192 | #define BM_REQUEST_TYPE (0xa1) | ||
193 | #define B_NOTIFICATION (0x20) | ||
194 | #define W_VALUE (0x0) | ||
195 | #define W_INDEX (0x2) | ||
196 | #define W_LENGTH (0x2) | ||
197 | |||
198 | #define B_OVERRUN (0x1<<6) | ||
199 | #define B_PARITY (0x1<<5) | ||
200 | #define B_FRAMING (0x1<<4) | ||
201 | #define B_RING_SIGNAL (0x1<<3) | ||
202 | #define B_BREAK (0x1<<2) | ||
203 | #define B_TX_CARRIER (0x1<<1) | ||
204 | #define B_RX_CARRIER (0x1<<0) | ||
205 | |||
206 | struct hso_serial_state_notification { | ||
207 | u8 bmRequestType; | ||
208 | u8 bNotification; | ||
209 | u16 wValue; | ||
210 | u16 wIndex; | ||
211 | u16 wLength; | ||
212 | u16 UART_state_bitmap; | ||
213 | } __attribute__((packed)); | ||
214 | |||
215 | struct hso_tiocmget { | ||
216 | struct mutex mutex; | ||
217 | wait_queue_head_t waitq; | ||
218 | int intr_completed; | ||
219 | struct usb_endpoint_descriptor *endp; | ||
220 | struct urb *urb; | ||
221 | struct hso_serial_state_notification serial_state_notification; | ||
222 | u16 prev_UART_state_bitmap; | ||
223 | struct uart_icount icount; | ||
224 | }; | ||
225 | |||
226 | |||
185 | struct hso_serial { | 227 | struct hso_serial { |
186 | struct hso_device *parent; | 228 | struct hso_device *parent; |
187 | int magic; | 229 | int magic; |
@@ -219,6 +261,7 @@ struct hso_serial { | |||
219 | spinlock_t serial_lock; | 261 | spinlock_t serial_lock; |
220 | 262 | ||
221 | int (*write_data) (struct hso_serial *serial); | 263 | int (*write_data) (struct hso_serial *serial); |
264 | struct hso_tiocmget *tiocmget; | ||
222 | /* Hacks required to get flow control | 265 | /* Hacks required to get flow control |
223 | * working on the serial receive buffers | 266 | * working on the serial receive buffers |
224 | * so as not to drop characters on the floor. | 267 | * so as not to drop characters on the floor. |
@@ -305,7 +348,7 @@ static void async_get_intf(struct work_struct *data); | |||
305 | static void async_put_intf(struct work_struct *data); | 348 | static void async_put_intf(struct work_struct *data); |
306 | static int hso_put_activity(struct hso_device *hso_dev); | 349 | static int hso_put_activity(struct hso_device *hso_dev); |
307 | static int hso_get_activity(struct hso_device *hso_dev); | 350 | static int hso_get_activity(struct hso_device *hso_dev); |
308 | 351 | static void tiocmget_intr_callback(struct urb *urb); | |
309 | /*****************************************************************************/ | 352 | /*****************************************************************************/ |
310 | /* Helping functions */ | 353 | /* Helping functions */ |
311 | /*****************************************************************************/ | 354 | /*****************************************************************************/ |
@@ -362,8 +405,6 @@ static struct tty_driver *tty_drv; | |||
362 | static struct hso_device *serial_table[HSO_SERIAL_TTY_MINORS]; | 405 | static struct hso_device *serial_table[HSO_SERIAL_TTY_MINORS]; |
363 | static struct hso_device *network_table[HSO_MAX_NET_DEVICES]; | 406 | static struct hso_device *network_table[HSO_MAX_NET_DEVICES]; |
364 | static spinlock_t serial_table_lock; | 407 | static spinlock_t serial_table_lock; |
365 | static struct ktermios *hso_serial_termios[HSO_SERIAL_TTY_MINORS]; | ||
366 | static struct ktermios *hso_serial_termios_locked[HSO_SERIAL_TTY_MINORS]; | ||
367 | 408 | ||
368 | static const s32 default_port_spec[] = { | 409 | static const s32 default_port_spec[] = { |
369 | HSO_INTF_MUX | HSO_PORT_NETWORK, | 410 | HSO_INTF_MUX | HSO_PORT_NETWORK, |
@@ -1009,23 +1050,11 @@ static void read_bulk_callback(struct urb *urb) | |||
1009 | 1050 | ||
1010 | /* Serial driver functions */ | 1051 | /* Serial driver functions */ |
1011 | 1052 | ||
1012 | static void _hso_serial_set_termios(struct tty_struct *tty, | 1053 | static void hso_init_termios(struct ktermios *termios) |
1013 | struct ktermios *old) | ||
1014 | { | 1054 | { |
1015 | struct hso_serial *serial = get_serial_by_tty(tty); | ||
1016 | struct ktermios *termios; | ||
1017 | |||
1018 | if ((!tty) || (!tty->termios) || (!serial)) { | ||
1019 | printk(KERN_ERR "%s: no tty structures", __func__); | ||
1020 | return; | ||
1021 | } | ||
1022 | |||
1023 | D4("port %d", serial->minor); | ||
1024 | |||
1025 | /* | 1055 | /* |
1026 | * The default requirements for this device are: | 1056 | * The default requirements for this device are: |
1027 | */ | 1057 | */ |
1028 | termios = tty->termios; | ||
1029 | termios->c_iflag &= | 1058 | termios->c_iflag &= |
1030 | ~(IGNBRK /* disable ignore break */ | 1059 | ~(IGNBRK /* disable ignore break */ |
1031 | | BRKINT /* disable break causes interrupt */ | 1060 | | BRKINT /* disable break causes interrupt */ |
@@ -1057,15 +1086,38 @@ static void _hso_serial_set_termios(struct tty_struct *tty, | |||
1057 | termios->c_cflag |= CS8; /* character size 8 bits */ | 1086 | termios->c_cflag |= CS8; /* character size 8 bits */ |
1058 | 1087 | ||
1059 | /* baud rate 115200 */ | 1088 | /* baud rate 115200 */ |
1060 | tty_encode_baud_rate(serial->tty, 115200, 115200); | 1089 | tty_termios_encode_baud_rate(termios, 115200, 115200); |
1090 | } | ||
1091 | |||
1092 | static void _hso_serial_set_termios(struct tty_struct *tty, | ||
1093 | struct ktermios *old) | ||
1094 | { | ||
1095 | struct hso_serial *serial = get_serial_by_tty(tty); | ||
1096 | struct ktermios *termios; | ||
1097 | |||
1098 | if (!serial) { | ||
1099 | printk(KERN_ERR "%s: no tty structures", __func__); | ||
1100 | return; | ||
1101 | } | ||
1102 | |||
1103 | D4("port %d", serial->minor); | ||
1061 | 1104 | ||
1062 | /* | 1105 | /* |
1063 | * Force low_latency on; otherwise the pushes are scheduled; | 1106 | * Fix up unsupported bits |
1064 | * this is bad as it opens up the possibility of dropping bytes | ||
1065 | * on the floor. We don't want to drop bytes on the floor. :) | ||
1066 | */ | 1107 | */ |
1067 | serial->tty->low_latency = 1; | 1108 | termios = tty->termios; |
1068 | return; | 1109 | termios->c_iflag &= ~IXON; /* disable enable XON/XOFF flow control */ |
1110 | |||
1111 | termios->c_cflag &= | ||
1112 | ~(CSIZE /* no size */ | ||
1113 | | PARENB /* disable parity bit */ | ||
1114 | | CBAUD /* clear current baud rate */ | ||
1115 | | CBAUDEX); /* clear current buad rate */ | ||
1116 | |||
1117 | termios->c_cflag |= CS8; /* character size 8 bits */ | ||
1118 | |||
1119 | /* baud rate 115200 */ | ||
1120 | tty_encode_baud_rate(tty, 115200, 115200); | ||
1069 | } | 1121 | } |
1070 | 1122 | ||
1071 | static void hso_resubmit_rx_bulk_urb(struct hso_serial *serial, struct urb *urb) | 1123 | static void hso_resubmit_rx_bulk_urb(struct hso_serial *serial, struct urb *urb) |
@@ -1228,6 +1280,7 @@ static int hso_serial_open(struct tty_struct *tty, struct file *filp) | |||
1228 | 1280 | ||
1229 | /* sanity check */ | 1281 | /* sanity check */ |
1230 | if (serial == NULL || serial->magic != HSO_SERIAL_MAGIC) { | 1282 | if (serial == NULL || serial->magic != HSO_SERIAL_MAGIC) { |
1283 | WARN_ON(1); | ||
1231 | tty->driver_data = NULL; | 1284 | tty->driver_data = NULL; |
1232 | D1("Failed to open port"); | 1285 | D1("Failed to open port"); |
1233 | return -ENODEV; | 1286 | return -ENODEV; |
@@ -1242,8 +1295,10 @@ static int hso_serial_open(struct tty_struct *tty, struct file *filp) | |||
1242 | kref_get(&serial->parent->ref); | 1295 | kref_get(&serial->parent->ref); |
1243 | 1296 | ||
1244 | /* setup */ | 1297 | /* setup */ |
1298 | spin_lock_irq(&serial->serial_lock); | ||
1245 | tty->driver_data = serial; | 1299 | tty->driver_data = serial; |
1246 | serial->tty = tty; | 1300 | serial->tty = tty_kref_get(tty); |
1301 | spin_unlock_irq(&serial->serial_lock); | ||
1247 | 1302 | ||
1248 | /* check for port already opened, if not set the termios */ | 1303 | /* check for port already opened, if not set the termios */ |
1249 | serial->open_count++; | 1304 | serial->open_count++; |
@@ -1285,6 +1340,10 @@ static void hso_serial_close(struct tty_struct *tty, struct file *filp) | |||
1285 | 1340 | ||
1286 | D1("Closing serial port"); | 1341 | D1("Closing serial port"); |
1287 | 1342 | ||
1343 | /* Open failed, no close cleanup required */ | ||
1344 | if (serial == NULL) | ||
1345 | return; | ||
1346 | |||
1288 | mutex_lock(&serial->parent->mutex); | 1347 | mutex_lock(&serial->parent->mutex); |
1289 | usb_gone = serial->parent->usb_gone; | 1348 | usb_gone = serial->parent->usb_gone; |
1290 | 1349 | ||
@@ -1297,10 +1356,13 @@ static void hso_serial_close(struct tty_struct *tty, struct file *filp) | |||
1297 | kref_put(&serial->parent->ref, hso_serial_ref_free); | 1356 | kref_put(&serial->parent->ref, hso_serial_ref_free); |
1298 | if (serial->open_count <= 0) { | 1357 | if (serial->open_count <= 0) { |
1299 | serial->open_count = 0; | 1358 | serial->open_count = 0; |
1300 | if (serial->tty) { | 1359 | spin_lock_irq(&serial->serial_lock); |
1360 | if (serial->tty == tty) { | ||
1301 | serial->tty->driver_data = NULL; | 1361 | serial->tty->driver_data = NULL; |
1302 | serial->tty = NULL; | 1362 | serial->tty = NULL; |
1363 | tty_kref_put(tty); | ||
1303 | } | 1364 | } |
1365 | spin_unlock_irq(&serial->serial_lock); | ||
1304 | if (!usb_gone) | 1366 | if (!usb_gone) |
1305 | hso_stop_serial_device(serial->parent); | 1367 | hso_stop_serial_device(serial->parent); |
1306 | tasklet_kill(&serial->unthrottle_tasklet); | 1368 | tasklet_kill(&serial->unthrottle_tasklet); |
@@ -1400,25 +1462,217 @@ static int hso_serial_chars_in_buffer(struct tty_struct *tty) | |||
1400 | 1462 | ||
1401 | return chars; | 1463 | return chars; |
1402 | } | 1464 | } |
1465 | int tiocmget_submit_urb(struct hso_serial *serial, | ||
1466 | struct hso_tiocmget *tiocmget, | ||
1467 | struct usb_device *usb) | ||
1468 | { | ||
1469 | int result; | ||
1470 | |||
1471 | if (serial->parent->usb_gone) | ||
1472 | return -ENODEV; | ||
1473 | usb_fill_int_urb(tiocmget->urb, usb, | ||
1474 | usb_rcvintpipe(usb, | ||
1475 | tiocmget->endp-> | ||
1476 | bEndpointAddress & 0x7F), | ||
1477 | &tiocmget->serial_state_notification, | ||
1478 | sizeof(struct hso_serial_state_notification), | ||
1479 | tiocmget_intr_callback, serial, | ||
1480 | tiocmget->endp->bInterval); | ||
1481 | result = usb_submit_urb(tiocmget->urb, GFP_ATOMIC); | ||
1482 | if (result) { | ||
1483 | dev_warn(&usb->dev, "%s usb_submit_urb failed %d\n", __func__, | ||
1484 | result); | ||
1485 | } | ||
1486 | return result; | ||
1487 | |||
1488 | } | ||
1489 | |||
1490 | static void tiocmget_intr_callback(struct urb *urb) | ||
1491 | { | ||
1492 | struct hso_serial *serial = urb->context; | ||
1493 | struct hso_tiocmget *tiocmget; | ||
1494 | int status = urb->status; | ||
1495 | u16 UART_state_bitmap, prev_UART_state_bitmap; | ||
1496 | struct uart_icount *icount; | ||
1497 | struct hso_serial_state_notification *serial_state_notification; | ||
1498 | struct usb_device *usb; | ||
1499 | |||
1500 | /* Sanity checks */ | ||
1501 | if (!serial) | ||
1502 | return; | ||
1503 | if (status) { | ||
1504 | log_usb_status(status, __func__); | ||
1505 | return; | ||
1506 | } | ||
1507 | tiocmget = serial->tiocmget; | ||
1508 | if (!tiocmget) | ||
1509 | return; | ||
1510 | usb = serial->parent->usb; | ||
1511 | serial_state_notification = &tiocmget->serial_state_notification; | ||
1512 | if (serial_state_notification->bmRequestType != BM_REQUEST_TYPE || | ||
1513 | serial_state_notification->bNotification != B_NOTIFICATION || | ||
1514 | le16_to_cpu(serial_state_notification->wValue) != W_VALUE || | ||
1515 | le16_to_cpu(serial_state_notification->wIndex) != W_INDEX || | ||
1516 | le16_to_cpu(serial_state_notification->wLength) != W_LENGTH) { | ||
1517 | dev_warn(&usb->dev, | ||
1518 | "hso received invalid serial state notification\n"); | ||
1519 | DUMP(serial_state_notification, | ||
1520 | sizeof(hso_serial_state_notifation)) | ||
1521 | } else { | ||
1522 | |||
1523 | UART_state_bitmap = le16_to_cpu(serial_state_notification-> | ||
1524 | UART_state_bitmap); | ||
1525 | prev_UART_state_bitmap = tiocmget->prev_UART_state_bitmap; | ||
1526 | icount = &tiocmget->icount; | ||
1527 | spin_lock(&serial->serial_lock); | ||
1528 | if ((UART_state_bitmap & B_OVERRUN) != | ||
1529 | (prev_UART_state_bitmap & B_OVERRUN)) | ||
1530 | icount->parity++; | ||
1531 | if ((UART_state_bitmap & B_PARITY) != | ||
1532 | (prev_UART_state_bitmap & B_PARITY)) | ||
1533 | icount->parity++; | ||
1534 | if ((UART_state_bitmap & B_FRAMING) != | ||
1535 | (prev_UART_state_bitmap & B_FRAMING)) | ||
1536 | icount->frame++; | ||
1537 | if ((UART_state_bitmap & B_RING_SIGNAL) && | ||
1538 | !(prev_UART_state_bitmap & B_RING_SIGNAL)) | ||
1539 | icount->rng++; | ||
1540 | if ((UART_state_bitmap & B_BREAK) != | ||
1541 | (prev_UART_state_bitmap & B_BREAK)) | ||
1542 | icount->brk++; | ||
1543 | if ((UART_state_bitmap & B_TX_CARRIER) != | ||
1544 | (prev_UART_state_bitmap & B_TX_CARRIER)) | ||
1545 | icount->dsr++; | ||
1546 | if ((UART_state_bitmap & B_RX_CARRIER) != | ||
1547 | (prev_UART_state_bitmap & B_RX_CARRIER)) | ||
1548 | icount->dcd++; | ||
1549 | tiocmget->prev_UART_state_bitmap = UART_state_bitmap; | ||
1550 | spin_unlock(&serial->serial_lock); | ||
1551 | tiocmget->intr_completed = 1; | ||
1552 | wake_up_interruptible(&tiocmget->waitq); | ||
1553 | } | ||
1554 | memset(serial_state_notification, 0, | ||
1555 | sizeof(struct hso_serial_state_notification)); | ||
1556 | tiocmget_submit_urb(serial, | ||
1557 | tiocmget, | ||
1558 | serial->parent->usb); | ||
1559 | } | ||
1560 | |||
1561 | /* | ||
1562 | * next few functions largely stolen from drivers/serial/serial_core.c | ||
1563 | */ | ||
1564 | /* Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change | ||
1565 | * - mask passed in arg for lines of interest | ||
1566 | * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) | ||
1567 | * Caller should use TIOCGICOUNT to see which one it was | ||
1568 | */ | ||
1569 | static int | ||
1570 | hso_wait_modem_status(struct hso_serial *serial, unsigned long arg) | ||
1571 | { | ||
1572 | DECLARE_WAITQUEUE(wait, current); | ||
1573 | struct uart_icount cprev, cnow; | ||
1574 | struct hso_tiocmget *tiocmget; | ||
1575 | int ret; | ||
1576 | |||
1577 | tiocmget = serial->tiocmget; | ||
1578 | if (!tiocmget) | ||
1579 | return -ENOENT; | ||
1580 | /* | ||
1581 | * note the counters on entry | ||
1582 | */ | ||
1583 | spin_lock_irq(&serial->serial_lock); | ||
1584 | memcpy(&cprev, &tiocmget->icount, sizeof(struct uart_icount)); | ||
1585 | spin_unlock_irq(&serial->serial_lock); | ||
1586 | add_wait_queue(&tiocmget->waitq, &wait); | ||
1587 | for (;;) { | ||
1588 | spin_lock_irq(&serial->serial_lock); | ||
1589 | memcpy(&cnow, &tiocmget->icount, sizeof(struct uart_icount)); | ||
1590 | spin_unlock_irq(&serial->serial_lock); | ||
1591 | set_current_state(TASK_INTERRUPTIBLE); | ||
1592 | if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || | ||
1593 | ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || | ||
1594 | ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd))) { | ||
1595 | ret = 0; | ||
1596 | break; | ||
1597 | } | ||
1598 | schedule(); | ||
1599 | /* see if a signal did it */ | ||
1600 | if (signal_pending(current)) { | ||
1601 | ret = -ERESTARTSYS; | ||
1602 | break; | ||
1603 | } | ||
1604 | cprev = cnow; | ||
1605 | } | ||
1606 | current->state = TASK_RUNNING; | ||
1607 | remove_wait_queue(&tiocmget->waitq, &wait); | ||
1608 | |||
1609 | return ret; | ||
1610 | } | ||
1611 | |||
1612 | /* | ||
1613 | * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) | ||
1614 | * Return: write counters to the user passed counter struct | ||
1615 | * NB: both 1->0 and 0->1 transitions are counted except for | ||
1616 | * RI where only 0->1 is counted. | ||
1617 | */ | ||
1618 | static int hso_get_count(struct hso_serial *serial, | ||
1619 | struct serial_icounter_struct __user *icnt) | ||
1620 | { | ||
1621 | struct serial_icounter_struct icount; | ||
1622 | struct uart_icount cnow; | ||
1623 | struct hso_tiocmget *tiocmget = serial->tiocmget; | ||
1624 | |||
1625 | if (!tiocmget) | ||
1626 | return -ENOENT; | ||
1627 | spin_lock_irq(&serial->serial_lock); | ||
1628 | memcpy(&cnow, &tiocmget->icount, sizeof(struct uart_icount)); | ||
1629 | spin_unlock_irq(&serial->serial_lock); | ||
1630 | |||
1631 | icount.cts = cnow.cts; | ||
1632 | icount.dsr = cnow.dsr; | ||
1633 | icount.rng = cnow.rng; | ||
1634 | icount.dcd = cnow.dcd; | ||
1635 | icount.rx = cnow.rx; | ||
1636 | icount.tx = cnow.tx; | ||
1637 | icount.frame = cnow.frame; | ||
1638 | icount.overrun = cnow.overrun; | ||
1639 | icount.parity = cnow.parity; | ||
1640 | icount.brk = cnow.brk; | ||
1641 | icount.buf_overrun = cnow.buf_overrun; | ||
1642 | |||
1643 | return copy_to_user(icnt, &icount, sizeof(icount)) ? -EFAULT : 0; | ||
1644 | } | ||
1645 | |||
1403 | 1646 | ||
1404 | static int hso_serial_tiocmget(struct tty_struct *tty, struct file *file) | 1647 | static int hso_serial_tiocmget(struct tty_struct *tty, struct file *file) |
1405 | { | 1648 | { |
1406 | unsigned int value; | 1649 | int retval; |
1407 | struct hso_serial *serial = get_serial_by_tty(tty); | 1650 | struct hso_serial *serial = get_serial_by_tty(tty); |
1408 | unsigned long flags; | 1651 | struct hso_tiocmget *tiocmget; |
1652 | u16 UART_state_bitmap; | ||
1409 | 1653 | ||
1410 | /* sanity check */ | 1654 | /* sanity check */ |
1411 | if (!serial) { | 1655 | if (!serial) { |
1412 | D1("no tty structures"); | 1656 | D1("no tty structures"); |
1413 | return -EINVAL; | 1657 | return -EINVAL; |
1414 | } | 1658 | } |
1415 | 1659 | spin_lock_irq(&serial->serial_lock); | |
1416 | spin_lock_irqsave(&serial->serial_lock, flags); | 1660 | retval = ((serial->rts_state) ? TIOCM_RTS : 0) | |
1417 | value = ((serial->rts_state) ? TIOCM_RTS : 0) | | ||
1418 | ((serial->dtr_state) ? TIOCM_DTR : 0); | 1661 | ((serial->dtr_state) ? TIOCM_DTR : 0); |
1419 | spin_unlock_irqrestore(&serial->serial_lock, flags); | 1662 | tiocmget = serial->tiocmget; |
1663 | if (tiocmget) { | ||
1420 | 1664 | ||
1421 | return value; | 1665 | UART_state_bitmap = le16_to_cpu( |
1666 | tiocmget->prev_UART_state_bitmap); | ||
1667 | if (UART_state_bitmap & B_RING_SIGNAL) | ||
1668 | retval |= TIOCM_RNG; | ||
1669 | if (UART_state_bitmap & B_RX_CARRIER) | ||
1670 | retval |= TIOCM_CD; | ||
1671 | if (UART_state_bitmap & B_TX_CARRIER) | ||
1672 | retval |= TIOCM_DSR; | ||
1673 | } | ||
1674 | spin_unlock_irq(&serial->serial_lock); | ||
1675 | return retval; | ||
1422 | } | 1676 | } |
1423 | 1677 | ||
1424 | static int hso_serial_tiocmset(struct tty_struct *tty, struct file *file, | 1678 | static int hso_serial_tiocmset(struct tty_struct *tty, struct file *file, |
@@ -1460,6 +1714,32 @@ static int hso_serial_tiocmset(struct tty_struct *tty, struct file *file, | |||
1460 | USB_CTRL_SET_TIMEOUT); | 1714 | USB_CTRL_SET_TIMEOUT); |
1461 | } | 1715 | } |
1462 | 1716 | ||
1717 | static int hso_serial_ioctl(struct tty_struct *tty, struct file *file, | ||
1718 | unsigned int cmd, unsigned long arg) | ||
1719 | { | ||
1720 | struct hso_serial *serial = get_serial_by_tty(tty); | ||
1721 | void __user *uarg = (void __user *)arg; | ||
1722 | int ret = 0; | ||
1723 | D4("IOCTL cmd: %d, arg: %ld", cmd, arg); | ||
1724 | |||
1725 | if (!serial) | ||
1726 | return -ENODEV; | ||
1727 | switch (cmd) { | ||
1728 | case TIOCMIWAIT: | ||
1729 | ret = hso_wait_modem_status(serial, arg); | ||
1730 | break; | ||
1731 | |||
1732 | case TIOCGICOUNT: | ||
1733 | ret = hso_get_count(serial, uarg); | ||
1734 | break; | ||
1735 | default: | ||
1736 | ret = -ENOIOCTLCMD; | ||
1737 | break; | ||
1738 | } | ||
1739 | return ret; | ||
1740 | } | ||
1741 | |||
1742 | |||
1463 | /* starts a transmit */ | 1743 | /* starts a transmit */ |
1464 | static void hso_kick_transmit(struct hso_serial *serial) | 1744 | static void hso_kick_transmit(struct hso_serial *serial) |
1465 | { | 1745 | { |
@@ -1653,6 +1933,7 @@ static void hso_std_serial_write_bulk_callback(struct urb *urb) | |||
1653 | { | 1933 | { |
1654 | struct hso_serial *serial = urb->context; | 1934 | struct hso_serial *serial = urb->context; |
1655 | int status = urb->status; | 1935 | int status = urb->status; |
1936 | struct tty_struct *tty; | ||
1656 | 1937 | ||
1657 | /* sanity check */ | 1938 | /* sanity check */ |
1658 | if (!serial) { | 1939 | if (!serial) { |
@@ -1662,14 +1943,18 @@ static void hso_std_serial_write_bulk_callback(struct urb *urb) | |||
1662 | 1943 | ||
1663 | spin_lock(&serial->serial_lock); | 1944 | spin_lock(&serial->serial_lock); |
1664 | serial->tx_urb_used = 0; | 1945 | serial->tx_urb_used = 0; |
1946 | tty = tty_kref_get(serial->tty); | ||
1665 | spin_unlock(&serial->serial_lock); | 1947 | spin_unlock(&serial->serial_lock); |
1666 | if (status) { | 1948 | if (status) { |
1667 | log_usb_status(status, __func__); | 1949 | log_usb_status(status, __func__); |
1950 | tty_kref_put(tty); | ||
1668 | return; | 1951 | return; |
1669 | } | 1952 | } |
1670 | hso_put_activity(serial->parent); | 1953 | hso_put_activity(serial->parent); |
1671 | if (serial->tty) | 1954 | if (tty) { |
1672 | tty_wakeup(serial->tty); | 1955 | tty_wakeup(tty); |
1956 | tty_kref_put(tty); | ||
1957 | } | ||
1673 | hso_kick_transmit(serial); | 1958 | hso_kick_transmit(serial); |
1674 | 1959 | ||
1675 | D1(" "); | 1960 | D1(" "); |
@@ -1706,6 +1991,7 @@ static void ctrl_callback(struct urb *urb) | |||
1706 | struct hso_serial *serial = urb->context; | 1991 | struct hso_serial *serial = urb->context; |
1707 | struct usb_ctrlrequest *req; | 1992 | struct usb_ctrlrequest *req; |
1708 | int status = urb->status; | 1993 | int status = urb->status; |
1994 | struct tty_struct *tty; | ||
1709 | 1995 | ||
1710 | /* sanity check */ | 1996 | /* sanity check */ |
1711 | if (!serial) | 1997 | if (!serial) |
@@ -1713,9 +1999,11 @@ static void ctrl_callback(struct urb *urb) | |||
1713 | 1999 | ||
1714 | spin_lock(&serial->serial_lock); | 2000 | spin_lock(&serial->serial_lock); |
1715 | serial->tx_urb_used = 0; | 2001 | serial->tx_urb_used = 0; |
2002 | tty = tty_kref_get(serial->tty); | ||
1716 | spin_unlock(&serial->serial_lock); | 2003 | spin_unlock(&serial->serial_lock); |
1717 | if (status) { | 2004 | if (status) { |
1718 | log_usb_status(status, __func__); | 2005 | log_usb_status(status, __func__); |
2006 | tty_kref_put(tty); | ||
1719 | return; | 2007 | return; |
1720 | } | 2008 | } |
1721 | 2009 | ||
@@ -1734,25 +2022,31 @@ static void ctrl_callback(struct urb *urb) | |||
1734 | spin_unlock(&serial->serial_lock); | 2022 | spin_unlock(&serial->serial_lock); |
1735 | } else { | 2023 | } else { |
1736 | hso_put_activity(serial->parent); | 2024 | hso_put_activity(serial->parent); |
1737 | if (serial->tty) | 2025 | if (tty) |
1738 | tty_wakeup(serial->tty); | 2026 | tty_wakeup(tty); |
1739 | /* response to a write command */ | 2027 | /* response to a write command */ |
1740 | hso_kick_transmit(serial); | 2028 | hso_kick_transmit(serial); |
1741 | } | 2029 | } |
2030 | tty_kref_put(tty); | ||
1742 | } | 2031 | } |
1743 | 2032 | ||
1744 | /* handle RX data for serial port */ | 2033 | /* handle RX data for serial port */ |
1745 | static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial) | 2034 | static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial) |
1746 | { | 2035 | { |
1747 | struct tty_struct *tty = serial->tty; | 2036 | struct tty_struct *tty; |
1748 | int write_length_remaining = 0; | 2037 | int write_length_remaining = 0; |
1749 | int curr_write_len; | 2038 | int curr_write_len; |
2039 | |||
1750 | /* Sanity check */ | 2040 | /* Sanity check */ |
1751 | if (urb == NULL || serial == NULL) { | 2041 | if (urb == NULL || serial == NULL) { |
1752 | D1("serial = NULL"); | 2042 | D1("serial = NULL"); |
1753 | return -2; | 2043 | return -2; |
1754 | } | 2044 | } |
1755 | 2045 | ||
2046 | spin_lock(&serial->serial_lock); | ||
2047 | tty = tty_kref_get(serial->tty); | ||
2048 | spin_unlock(&serial->serial_lock); | ||
2049 | |||
1756 | /* Push data to tty */ | 2050 | /* Push data to tty */ |
1757 | if (tty) { | 2051 | if (tty) { |
1758 | write_length_remaining = urb->actual_length - | 2052 | write_length_remaining = urb->actual_length - |
@@ -1774,6 +2068,7 @@ static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial) | |||
1774 | serial->curr_rx_urb_offset = 0; | 2068 | serial->curr_rx_urb_offset = 0; |
1775 | serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 0; | 2069 | serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 0; |
1776 | } | 2070 | } |
2071 | tty_kref_put(tty); | ||
1777 | return write_length_remaining; | 2072 | return write_length_remaining; |
1778 | } | 2073 | } |
1779 | 2074 | ||
@@ -1922,7 +2217,10 @@ static int hso_start_serial_device(struct hso_device *hso_dev, gfp_t flags) | |||
1922 | serial->shared_int->use_count++; | 2217 | serial->shared_int->use_count++; |
1923 | mutex_unlock(&serial->shared_int->shared_int_lock); | 2218 | mutex_unlock(&serial->shared_int->shared_int_lock); |
1924 | } | 2219 | } |
1925 | 2220 | if (serial->tiocmget) | |
2221 | tiocmget_submit_urb(serial, | ||
2222 | serial->tiocmget, | ||
2223 | serial->parent->usb); | ||
1926 | return result; | 2224 | return result; |
1927 | } | 2225 | } |
1928 | 2226 | ||
@@ -1930,6 +2228,7 @@ static int hso_stop_serial_device(struct hso_device *hso_dev) | |||
1930 | { | 2228 | { |
1931 | int i; | 2229 | int i; |
1932 | struct hso_serial *serial = dev2ser(hso_dev); | 2230 | struct hso_serial *serial = dev2ser(hso_dev); |
2231 | struct hso_tiocmget *tiocmget; | ||
1933 | 2232 | ||
1934 | if (!serial) | 2233 | if (!serial) |
1935 | return -ENODEV; | 2234 | return -ENODEV; |
@@ -1958,6 +2257,11 @@ static int hso_stop_serial_device(struct hso_device *hso_dev) | |||
1958 | } | 2257 | } |
1959 | mutex_unlock(&serial->shared_int->shared_int_lock); | 2258 | mutex_unlock(&serial->shared_int->shared_int_lock); |
1960 | } | 2259 | } |
2260 | tiocmget = serial->tiocmget; | ||
2261 | if (tiocmget) { | ||
2262 | wake_up_interruptible(&tiocmget->waitq); | ||
2263 | usb_kill_urb(tiocmget->urb); | ||
2264 | } | ||
1961 | 2265 | ||
1962 | return 0; | 2266 | return 0; |
1963 | } | 2267 | } |
@@ -2304,6 +2608,20 @@ exit: | |||
2304 | return NULL; | 2608 | return NULL; |
2305 | } | 2609 | } |
2306 | 2610 | ||
2611 | static void hso_free_tiomget(struct hso_serial *serial) | ||
2612 | { | ||
2613 | struct hso_tiocmget *tiocmget = serial->tiocmget; | ||
2614 | if (tiocmget) { | ||
2615 | kfree(tiocmget); | ||
2616 | if (tiocmget->urb) { | ||
2617 | usb_free_urb(tiocmget->urb); | ||
2618 | tiocmget->urb = NULL; | ||
2619 | } | ||
2620 | serial->tiocmget = NULL; | ||
2621 | |||
2622 | } | ||
2623 | } | ||
2624 | |||
2307 | /* Frees an AT channel ( goes for both mux and non-mux ) */ | 2625 | /* Frees an AT channel ( goes for both mux and non-mux ) */ |
2308 | static void hso_free_serial_device(struct hso_device *hso_dev) | 2626 | static void hso_free_serial_device(struct hso_device *hso_dev) |
2309 | { | 2627 | { |
@@ -2322,6 +2640,7 @@ static void hso_free_serial_device(struct hso_device *hso_dev) | |||
2322 | else | 2640 | else |
2323 | mutex_unlock(&serial->shared_int->shared_int_lock); | 2641 | mutex_unlock(&serial->shared_int->shared_int_lock); |
2324 | } | 2642 | } |
2643 | hso_free_tiomget(serial); | ||
2325 | kfree(serial); | 2644 | kfree(serial); |
2326 | hso_free_device(hso_dev); | 2645 | hso_free_device(hso_dev); |
2327 | } | 2646 | } |
@@ -2333,6 +2652,7 @@ static struct hso_device *hso_create_bulk_serial_device( | |||
2333 | struct hso_device *hso_dev; | 2652 | struct hso_device *hso_dev; |
2334 | struct hso_serial *serial; | 2653 | struct hso_serial *serial; |
2335 | int num_urbs; | 2654 | int num_urbs; |
2655 | struct hso_tiocmget *tiocmget; | ||
2336 | 2656 | ||
2337 | hso_dev = hso_create_device(interface, port); | 2657 | hso_dev = hso_create_device(interface, port); |
2338 | if (!hso_dev) | 2658 | if (!hso_dev) |
@@ -2345,8 +2665,27 @@ static struct hso_device *hso_create_bulk_serial_device( | |||
2345 | serial->parent = hso_dev; | 2665 | serial->parent = hso_dev; |
2346 | hso_dev->port_data.dev_serial = serial; | 2666 | hso_dev->port_data.dev_serial = serial; |
2347 | 2667 | ||
2348 | if (port & HSO_PORT_MODEM) | 2668 | if ((port & HSO_PORT_MASK) == HSO_PORT_MODEM) { |
2349 | num_urbs = 2; | 2669 | num_urbs = 2; |
2670 | serial->tiocmget = kzalloc(sizeof(struct hso_tiocmget), | ||
2671 | GFP_KERNEL); | ||
2672 | /* it isn't going to break our heart if serial->tiocmget | ||
2673 | * allocation fails don't bother checking this. | ||
2674 | */ | ||
2675 | if (serial->tiocmget) { | ||
2676 | tiocmget = serial->tiocmget; | ||
2677 | tiocmget->urb = usb_alloc_urb(0, GFP_KERNEL); | ||
2678 | if (tiocmget->urb) { | ||
2679 | mutex_init(&tiocmget->mutex); | ||
2680 | init_waitqueue_head(&tiocmget->waitq); | ||
2681 | tiocmget->endp = hso_get_ep( | ||
2682 | interface, | ||
2683 | USB_ENDPOINT_XFER_INT, | ||
2684 | USB_DIR_IN); | ||
2685 | } else | ||
2686 | hso_free_tiomget(serial); | ||
2687 | } | ||
2688 | } | ||
2350 | else | 2689 | else |
2351 | num_urbs = 1; | 2690 | num_urbs = 1; |
2352 | 2691 | ||
@@ -2382,6 +2721,7 @@ static struct hso_device *hso_create_bulk_serial_device( | |||
2382 | exit2: | 2721 | exit2: |
2383 | hso_serial_common_free(serial); | 2722 | hso_serial_common_free(serial); |
2384 | exit: | 2723 | exit: |
2724 | hso_free_tiomget(serial); | ||
2385 | kfree(serial); | 2725 | kfree(serial); |
2386 | hso_free_device(hso_dev); | 2726 | hso_free_device(hso_dev); |
2387 | return NULL; | 2727 | return NULL; |
@@ -2786,15 +3126,20 @@ static void hso_serial_ref_free(struct kref *ref) | |||
2786 | static void hso_free_interface(struct usb_interface *interface) | 3126 | static void hso_free_interface(struct usb_interface *interface) |
2787 | { | 3127 | { |
2788 | struct hso_serial *hso_dev; | 3128 | struct hso_serial *hso_dev; |
3129 | struct tty_struct *tty; | ||
2789 | int i; | 3130 | int i; |
2790 | 3131 | ||
2791 | for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) { | 3132 | for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) { |
2792 | if (serial_table[i] | 3133 | if (serial_table[i] |
2793 | && (serial_table[i]->interface == interface)) { | 3134 | && (serial_table[i]->interface == interface)) { |
2794 | hso_dev = dev2ser(serial_table[i]); | 3135 | hso_dev = dev2ser(serial_table[i]); |
2795 | if (hso_dev->tty) | 3136 | spin_lock_irq(&hso_dev->serial_lock); |
2796 | tty_hangup(hso_dev->tty); | 3137 | tty = tty_kref_get(hso_dev->tty); |
3138 | spin_unlock_irq(&hso_dev->serial_lock); | ||
3139 | if (tty) | ||
3140 | tty_hangup(tty); | ||
2797 | mutex_lock(&hso_dev->parent->mutex); | 3141 | mutex_lock(&hso_dev->parent->mutex); |
3142 | tty_kref_put(tty); | ||
2798 | hso_dev->parent->usb_gone = 1; | 3143 | hso_dev->parent->usb_gone = 1; |
2799 | mutex_unlock(&hso_dev->parent->mutex); | 3144 | mutex_unlock(&hso_dev->parent->mutex); |
2800 | kref_put(&serial_table[i]->ref, hso_serial_ref_free); | 3145 | kref_put(&serial_table[i]->ref, hso_serial_ref_free); |
@@ -2887,6 +3232,7 @@ static const struct tty_operations hso_serial_ops = { | |||
2887 | .close = hso_serial_close, | 3232 | .close = hso_serial_close, |
2888 | .write = hso_serial_write, | 3233 | .write = hso_serial_write, |
2889 | .write_room = hso_serial_write_room, | 3234 | .write_room = hso_serial_write_room, |
3235 | .ioctl = hso_serial_ioctl, | ||
2890 | .set_termios = hso_serial_set_termios, | 3236 | .set_termios = hso_serial_set_termios, |
2891 | .chars_in_buffer = hso_serial_chars_in_buffer, | 3237 | .chars_in_buffer = hso_serial_chars_in_buffer, |
2892 | .tiocmget = hso_serial_tiocmget, | 3238 | .tiocmget = hso_serial_tiocmget, |
@@ -2939,9 +3285,7 @@ static int __init hso_init(void) | |||
2939 | tty_drv->subtype = SERIAL_TYPE_NORMAL; | 3285 | tty_drv->subtype = SERIAL_TYPE_NORMAL; |
2940 | tty_drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; | 3286 | tty_drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; |
2941 | tty_drv->init_termios = tty_std_termios; | 3287 | tty_drv->init_termios = tty_std_termios; |
2942 | tty_drv->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; | 3288 | hso_init_termios(&tty_drv->init_termios); |
2943 | tty_drv->termios = hso_serial_termios; | ||
2944 | tty_drv->termios_locked = hso_serial_termios_locked; | ||
2945 | tty_set_operations(tty_drv, &hso_serial_ops); | 3289 | tty_set_operations(tty_drv, &hso_serial_ops); |
2946 | 3290 | ||
2947 | /* register the tty driver */ | 3291 | /* register the tty driver */ |