diff options
Diffstat (limited to 'drivers/char/nozomi.c')
-rw-r--r-- | drivers/char/nozomi.c | 157 |
1 files changed, 81 insertions, 76 deletions
diff --git a/drivers/char/nozomi.c b/drivers/char/nozomi.c index 2ad7d37afbd0..a3f32a15fde4 100644 --- a/drivers/char/nozomi.c +++ b/drivers/char/nozomi.c | |||
@@ -136,10 +136,6 @@ static int debug; | |||
136 | #define RECEIVE_BUF_MAX 4 | 136 | #define RECEIVE_BUF_MAX 4 |
137 | 137 | ||
138 | 138 | ||
139 | /* Define all types of vendors and devices to support */ | ||
140 | #define VENDOR1 0x1931 /* Vendor Option */ | ||
141 | #define DEVICE1 0x000c /* HSDPA card */ | ||
142 | |||
143 | #define R_IIR 0x0000 /* Interrupt Identity Register */ | 139 | #define R_IIR 0x0000 /* Interrupt Identity Register */ |
144 | #define R_FCR 0x0000 /* Flow Control Register */ | 140 | #define R_FCR 0x0000 /* Flow Control Register */ |
145 | #define R_IER 0x0004 /* Interrupt Enable Register */ | 141 | #define R_IER 0x0004 /* Interrupt Enable Register */ |
@@ -371,6 +367,8 @@ struct port { | |||
371 | struct mutex tty_sem; | 367 | struct mutex tty_sem; |
372 | wait_queue_head_t tty_wait; | 368 | wait_queue_head_t tty_wait; |
373 | struct async_icount tty_icount; | 369 | struct async_icount tty_icount; |
370 | |||
371 | struct nozomi *dc; | ||
374 | }; | 372 | }; |
375 | 373 | ||
376 | /* Private data one for each card in the system */ | 374 | /* Private data one for each card in the system */ |
@@ -405,7 +403,7 @@ struct buffer { | |||
405 | 403 | ||
406 | /* Global variables */ | 404 | /* Global variables */ |
407 | static const struct pci_device_id nozomi_pci_tbl[] __devinitconst = { | 405 | static const struct pci_device_id nozomi_pci_tbl[] __devinitconst = { |
408 | {PCI_DEVICE(VENDOR1, DEVICE1)}, | 406 | {PCI_DEVICE(0x1931, 0x000c)}, /* Nozomi HSDPA */ |
409 | {}, | 407 | {}, |
410 | }; | 408 | }; |
411 | 409 | ||
@@ -414,6 +412,8 @@ MODULE_DEVICE_TABLE(pci, nozomi_pci_tbl); | |||
414 | static struct nozomi *ndevs[NOZOMI_MAX_CARDS]; | 412 | static struct nozomi *ndevs[NOZOMI_MAX_CARDS]; |
415 | static struct tty_driver *ntty_driver; | 413 | static struct tty_driver *ntty_driver; |
416 | 414 | ||
415 | static const struct tty_port_operations noz_tty_port_ops; | ||
416 | |||
417 | /* | 417 | /* |
418 | * find card by tty_index | 418 | * find card by tty_index |
419 | */ | 419 | */ |
@@ -853,8 +853,6 @@ static int receive_data(enum port_type index, struct nozomi *dc) | |||
853 | goto put; | 853 | goto put; |
854 | } | 854 | } |
855 | 855 | ||
856 | tty_buffer_request_room(tty, size); | ||
857 | |||
858 | while (size > 0) { | 856 | while (size > 0) { |
859 | read_mem32((u32 *) buf, addr + offset, RECEIVE_BUF_MAX); | 857 | read_mem32((u32 *) buf, addr + offset, RECEIVE_BUF_MAX); |
860 | 858 | ||
@@ -1473,9 +1471,11 @@ static int __devinit nozomi_card_init(struct pci_dev *pdev, | |||
1473 | 1471 | ||
1474 | for (i = 0; i < MAX_PORT; i++) { | 1472 | for (i = 0; i < MAX_PORT; i++) { |
1475 | struct device *tty_dev; | 1473 | struct device *tty_dev; |
1476 | 1474 | struct port *port = &dc->port[i]; | |
1477 | mutex_init(&dc->port[i].tty_sem); | 1475 | port->dc = dc; |
1478 | tty_port_init(&dc->port[i].port); | 1476 | mutex_init(&port->tty_sem); |
1477 | tty_port_init(&port->port); | ||
1478 | port->port.ops = &noz_tty_port_ops; | ||
1479 | tty_dev = tty_register_device(ntty_driver, dc->index_start + i, | 1479 | tty_dev = tty_register_device(ntty_driver, dc->index_start + i, |
1480 | &pdev->dev); | 1480 | &pdev->dev); |
1481 | 1481 | ||
@@ -1600,67 +1600,74 @@ static void set_dtr(const struct tty_struct *tty, int dtr) | |||
1600 | * ---------------------------------------------------------------------------- | 1600 | * ---------------------------------------------------------------------------- |
1601 | */ | 1601 | */ |
1602 | 1602 | ||
1603 | /* Called when the userspace process opens the tty, /dev/noz*. */ | 1603 | static int ntty_install(struct tty_driver *driver, struct tty_struct *tty) |
1604 | static int ntty_open(struct tty_struct *tty, struct file *file) | ||
1605 | { | 1604 | { |
1606 | struct port *port = get_port_by_tty(tty); | 1605 | struct port *port = get_port_by_tty(tty); |
1607 | struct nozomi *dc = get_dc_by_tty(tty); | 1606 | struct nozomi *dc = get_dc_by_tty(tty); |
1608 | unsigned long flags; | 1607 | int ret; |
1609 | |||
1610 | if (!port || !dc || dc->state != NOZOMI_STATE_READY) | 1608 | if (!port || !dc || dc->state != NOZOMI_STATE_READY) |
1611 | return -ENODEV; | 1609 | return -ENODEV; |
1612 | 1610 | ret = tty_init_termios(tty); | |
1613 | if (mutex_lock_interruptible(&port->tty_sem)) | 1611 | if (ret == 0) { |
1614 | return -ERESTARTSYS; | 1612 | tty_driver_kref_get(driver); |
1615 | 1613 | driver->ttys[tty->index] = tty; | |
1616 | port->port.count++; | ||
1617 | dc->open_ttys++; | ||
1618 | |||
1619 | /* Enable interrupt downlink for channel */ | ||
1620 | if (port->port.count == 1) { | ||
1621 | tty->driver_data = port; | ||
1622 | tty_port_tty_set(&port->port, tty); | ||
1623 | DBG1("open: %d", port->token_dl); | ||
1624 | spin_lock_irqsave(&dc->spin_mutex, flags); | ||
1625 | dc->last_ier = dc->last_ier | port->token_dl; | ||
1626 | writew(dc->last_ier, dc->reg_ier); | ||
1627 | spin_unlock_irqrestore(&dc->spin_mutex, flags); | ||
1628 | } | 1614 | } |
1629 | mutex_unlock(&port->tty_sem); | 1615 | return ret; |
1630 | return 0; | ||
1631 | } | 1616 | } |
1632 | 1617 | ||
1633 | /* Called when the userspace process close the tty, /dev/noz*. Also | 1618 | static void ntty_cleanup(struct tty_struct *tty) |
1634 | called immediately if ntty_open fails in which case tty->driver_data | 1619 | { |
1635 | will be NULL an we exit by the first return */ | 1620 | tty->driver_data = NULL; |
1621 | } | ||
1636 | 1622 | ||
1637 | static void ntty_close(struct tty_struct *tty, struct file *file) | 1623 | static int ntty_activate(struct tty_port *tport, struct tty_struct *tty) |
1638 | { | 1624 | { |
1639 | struct nozomi *dc = get_dc_by_tty(tty); | 1625 | struct port *port = container_of(tport, struct port, port); |
1640 | struct port *nport = tty->driver_data; | 1626 | struct nozomi *dc = port->dc; |
1641 | struct tty_port *port = &nport->port; | ||
1642 | unsigned long flags; | 1627 | unsigned long flags; |
1643 | 1628 | ||
1644 | if (!dc || !nport) | 1629 | DBG1("open: %d", port->token_dl); |
1645 | return; | 1630 | spin_lock_irqsave(&dc->spin_mutex, flags); |
1631 | dc->last_ier = dc->last_ier | port->token_dl; | ||
1632 | writew(dc->last_ier, dc->reg_ier); | ||
1633 | dc->open_ttys++; | ||
1634 | spin_unlock_irqrestore(&dc->spin_mutex, flags); | ||
1635 | printk("noz: activated %d: %p\n", tty->index, tport); | ||
1636 | return 0; | ||
1637 | } | ||
1646 | 1638 | ||
1647 | /* Users cannot interrupt a close */ | 1639 | static int ntty_open(struct tty_struct *tty, struct file *filp) |
1648 | mutex_lock(&nport->tty_sem); | 1640 | { |
1641 | struct port *port = get_port_by_tty(tty); | ||
1642 | return tty_port_open(&port->port, tty, filp); | ||
1643 | } | ||
1649 | 1644 | ||
1650 | WARN_ON(!port->count); | 1645 | static void ntty_shutdown(struct tty_port *tport) |
1646 | { | ||
1647 | struct port *port = container_of(tport, struct port, port); | ||
1648 | struct nozomi *dc = port->dc; | ||
1649 | unsigned long flags; | ||
1651 | 1650 | ||
1651 | DBG1("close: %d", port->token_dl); | ||
1652 | spin_lock_irqsave(&dc->spin_mutex, flags); | ||
1653 | dc->last_ier &= ~(port->token_dl); | ||
1654 | writew(dc->last_ier, dc->reg_ier); | ||
1652 | dc->open_ttys--; | 1655 | dc->open_ttys--; |
1653 | port->count--; | 1656 | spin_unlock_irqrestore(&dc->spin_mutex, flags); |
1657 | printk("noz: shutdown %p\n", tport); | ||
1658 | } | ||
1654 | 1659 | ||
1655 | if (port->count == 0) { | 1660 | static void ntty_close(struct tty_struct *tty, struct file *filp) |
1656 | DBG1("close: %d", nport->token_dl); | 1661 | { |
1657 | tty_port_tty_set(port, NULL); | 1662 | struct port *port = tty->driver_data; |
1658 | spin_lock_irqsave(&dc->spin_mutex, flags); | 1663 | if (port) |
1659 | dc->last_ier &= ~(nport->token_dl); | 1664 | tty_port_close(&port->port, tty, filp); |
1660 | writew(dc->last_ier, dc->reg_ier); | 1665 | } |
1661 | spin_unlock_irqrestore(&dc->spin_mutex, flags); | 1666 | |
1662 | } | 1667 | static void ntty_hangup(struct tty_struct *tty) |
1663 | mutex_unlock(&nport->tty_sem); | 1668 | { |
1669 | struct port *port = tty->driver_data; | ||
1670 | tty_port_hangup(&port->port); | ||
1664 | } | 1671 | } |
1665 | 1672 | ||
1666 | /* | 1673 | /* |
@@ -1680,15 +1687,7 @@ static int ntty_write(struct tty_struct *tty, const unsigned char *buffer, | |||
1680 | if (!dc || !port) | 1687 | if (!dc || !port) |
1681 | return -ENODEV; | 1688 | return -ENODEV; |
1682 | 1689 | ||
1683 | if (unlikely(!mutex_trylock(&port->tty_sem))) { | 1690 | mutex_lock(&port->tty_sem); |
1684 | /* | ||
1685 | * must test lock as tty layer wraps calls | ||
1686 | * to this function with BKL | ||
1687 | */ | ||
1688 | dev_err(&dc->pdev->dev, "Would have deadlocked - " | ||
1689 | "return EAGAIN\n"); | ||
1690 | return -EAGAIN; | ||
1691 | } | ||
1692 | 1691 | ||
1693 | if (unlikely(!port->port.count)) { | 1692 | if (unlikely(!port->port.count)) { |
1694 | DBG1(" "); | 1693 | DBG1(" "); |
@@ -1728,25 +1727,23 @@ exit: | |||
1728 | * This method is called by the upper tty layer. | 1727 | * This method is called by the upper tty layer. |
1729 | * #according to sources N_TTY.c it expects a value >= 0 and | 1728 | * #according to sources N_TTY.c it expects a value >= 0 and |
1730 | * does not check for negative values. | 1729 | * does not check for negative values. |
1730 | * | ||
1731 | * If the port is unplugged report lots of room and let the bits | ||
1732 | * dribble away so we don't block anything. | ||
1731 | */ | 1733 | */ |
1732 | static int ntty_write_room(struct tty_struct *tty) | 1734 | static int ntty_write_room(struct tty_struct *tty) |
1733 | { | 1735 | { |
1734 | struct port *port = tty->driver_data; | 1736 | struct port *port = tty->driver_data; |
1735 | int room = 0; | 1737 | int room = 4096; |
1736 | const struct nozomi *dc = get_dc_by_tty(tty); | 1738 | const struct nozomi *dc = get_dc_by_tty(tty); |
1737 | 1739 | ||
1738 | if (!dc || !port) | 1740 | if (dc) { |
1739 | return 0; | 1741 | mutex_lock(&port->tty_sem); |
1740 | if (!mutex_trylock(&port->tty_sem)) | 1742 | if (port->port.count) |
1741 | return 0; | 1743 | room = port->fifo_ul.size - |
1742 | 1744 | kfifo_len(&port->fifo_ul); | |
1743 | if (!port->port.count) | 1745 | mutex_unlock(&port->tty_sem); |
1744 | goto exit; | 1746 | } |
1745 | |||
1746 | room = port->fifo_ul.size - kfifo_len(&port->fifo_ul); | ||
1747 | |||
1748 | exit: | ||
1749 | mutex_unlock(&port->tty_sem); | ||
1750 | return room; | 1747 | return room; |
1751 | } | 1748 | } |
1752 | 1749 | ||
@@ -1906,10 +1903,16 @@ exit_in_buffer: | |||
1906 | return rval; | 1903 | return rval; |
1907 | } | 1904 | } |
1908 | 1905 | ||
1906 | static const struct tty_port_operations noz_tty_port_ops = { | ||
1907 | .activate = ntty_activate, | ||
1908 | .shutdown = ntty_shutdown, | ||
1909 | }; | ||
1910 | |||
1909 | static const struct tty_operations tty_ops = { | 1911 | static const struct tty_operations tty_ops = { |
1910 | .ioctl = ntty_ioctl, | 1912 | .ioctl = ntty_ioctl, |
1911 | .open = ntty_open, | 1913 | .open = ntty_open, |
1912 | .close = ntty_close, | 1914 | .close = ntty_close, |
1915 | .hangup = ntty_hangup, | ||
1913 | .write = ntty_write, | 1916 | .write = ntty_write, |
1914 | .write_room = ntty_write_room, | 1917 | .write_room = ntty_write_room, |
1915 | .unthrottle = ntty_unthrottle, | 1918 | .unthrottle = ntty_unthrottle, |
@@ -1917,6 +1920,8 @@ static const struct tty_operations tty_ops = { | |||
1917 | .chars_in_buffer = ntty_chars_in_buffer, | 1920 | .chars_in_buffer = ntty_chars_in_buffer, |
1918 | .tiocmget = ntty_tiocmget, | 1921 | .tiocmget = ntty_tiocmget, |
1919 | .tiocmset = ntty_tiocmset, | 1922 | .tiocmset = ntty_tiocmset, |
1923 | .install = ntty_install, | ||
1924 | .cleanup = ntty_cleanup, | ||
1920 | }; | 1925 | }; |
1921 | 1926 | ||
1922 | /* Module initialization */ | 1927 | /* Module initialization */ |