diff options
Diffstat (limited to 'drivers/net/usb/usbnet.c')
-rw-r--r-- | drivers/net/usb/usbnet.c | 196 |
1 files changed, 196 insertions, 0 deletions
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index edb81ed06950..c04110ba677f 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c | |||
@@ -1616,6 +1616,202 @@ void usbnet_device_suggests_idle(struct usbnet *dev) | |||
1616 | EXPORT_SYMBOL(usbnet_device_suggests_idle); | 1616 | EXPORT_SYMBOL(usbnet_device_suggests_idle); |
1617 | 1617 | ||
1618 | /*-------------------------------------------------------------------------*/ | 1618 | /*-------------------------------------------------------------------------*/ |
1619 | static int __usbnet_read_cmd(struct usbnet *dev, u8 cmd, u8 reqtype, | ||
1620 | u16 value, u16 index, void *data, u16 size) | ||
1621 | { | ||
1622 | void *buf = NULL; | ||
1623 | int err = -ENOMEM; | ||
1624 | |||
1625 | netdev_dbg(dev->net, "usbnet_read_cmd cmd=0x%02x reqtype=%02x" | ||
1626 | " value=0x%04x index=0x%04x size=%d\n", | ||
1627 | cmd, reqtype, value, index, size); | ||
1628 | |||
1629 | if (data) { | ||
1630 | buf = kmalloc(size, GFP_KERNEL); | ||
1631 | if (!buf) | ||
1632 | goto out; | ||
1633 | } | ||
1634 | |||
1635 | err = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), | ||
1636 | cmd, reqtype, value, index, buf, size, | ||
1637 | USB_CTRL_GET_TIMEOUT); | ||
1638 | if (err > 0 && err <= size) | ||
1639 | memcpy(data, buf, err); | ||
1640 | kfree(buf); | ||
1641 | out: | ||
1642 | return err; | ||
1643 | } | ||
1644 | |||
1645 | static int __usbnet_write_cmd(struct usbnet *dev, u8 cmd, u8 reqtype, | ||
1646 | u16 value, u16 index, const void *data, | ||
1647 | u16 size) | ||
1648 | { | ||
1649 | void *buf = NULL; | ||
1650 | int err = -ENOMEM; | ||
1651 | |||
1652 | netdev_dbg(dev->net, "usbnet_write_cmd cmd=0x%02x reqtype=%02x" | ||
1653 | " value=0x%04x index=0x%04x size=%d\n", | ||
1654 | cmd, reqtype, value, index, size); | ||
1655 | |||
1656 | if (data) { | ||
1657 | buf = kmemdup(data, size, GFP_KERNEL); | ||
1658 | if (!buf) | ||
1659 | goto out; | ||
1660 | } | ||
1661 | |||
1662 | err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), | ||
1663 | cmd, reqtype, value, index, buf, size, | ||
1664 | USB_CTRL_SET_TIMEOUT); | ||
1665 | kfree(buf); | ||
1666 | |||
1667 | out: | ||
1668 | return err; | ||
1669 | } | ||
1670 | |||
1671 | /* | ||
1672 | * The function can't be called inside suspend/resume callback, | ||
1673 | * otherwise deadlock will be caused. | ||
1674 | */ | ||
1675 | int usbnet_read_cmd(struct usbnet *dev, u8 cmd, u8 reqtype, | ||
1676 | u16 value, u16 index, void *data, u16 size) | ||
1677 | { | ||
1678 | int ret; | ||
1679 | |||
1680 | if (usb_autopm_get_interface(dev->intf) < 0) | ||
1681 | return -ENODEV; | ||
1682 | ret = __usbnet_read_cmd(dev, cmd, reqtype, value, index, | ||
1683 | data, size); | ||
1684 | usb_autopm_put_interface(dev->intf); | ||
1685 | return ret; | ||
1686 | } | ||
1687 | EXPORT_SYMBOL_GPL(usbnet_read_cmd); | ||
1688 | |||
1689 | /* | ||
1690 | * The function can't be called inside suspend/resume callback, | ||
1691 | * otherwise deadlock will be caused. | ||
1692 | */ | ||
1693 | int usbnet_write_cmd(struct usbnet *dev, u8 cmd, u8 reqtype, | ||
1694 | u16 value, u16 index, const void *data, u16 size) | ||
1695 | { | ||
1696 | int ret; | ||
1697 | |||
1698 | if (usb_autopm_get_interface(dev->intf) < 0) | ||
1699 | return -ENODEV; | ||
1700 | ret = __usbnet_write_cmd(dev, cmd, reqtype, value, index, | ||
1701 | data, size); | ||
1702 | usb_autopm_put_interface(dev->intf); | ||
1703 | return ret; | ||
1704 | } | ||
1705 | EXPORT_SYMBOL_GPL(usbnet_write_cmd); | ||
1706 | |||
1707 | /* | ||
1708 | * The function can be called inside suspend/resume callback safely | ||
1709 | * and should only be called by suspend/resume callback generally. | ||
1710 | */ | ||
1711 | int usbnet_read_cmd_nopm(struct usbnet *dev, u8 cmd, u8 reqtype, | ||
1712 | u16 value, u16 index, void *data, u16 size) | ||
1713 | { | ||
1714 | return __usbnet_read_cmd(dev, cmd, reqtype, value, index, | ||
1715 | data, size); | ||
1716 | } | ||
1717 | EXPORT_SYMBOL_GPL(usbnet_read_cmd_nopm); | ||
1718 | |||
1719 | /* | ||
1720 | * The function can be called inside suspend/resume callback safely | ||
1721 | * and should only be called by suspend/resume callback generally. | ||
1722 | */ | ||
1723 | int usbnet_write_cmd_nopm(struct usbnet *dev, u8 cmd, u8 reqtype, | ||
1724 | u16 value, u16 index, const void *data, | ||
1725 | u16 size) | ||
1726 | { | ||
1727 | return __usbnet_write_cmd(dev, cmd, reqtype, value, index, | ||
1728 | data, size); | ||
1729 | } | ||
1730 | EXPORT_SYMBOL_GPL(usbnet_write_cmd_nopm); | ||
1731 | |||
1732 | static void usbnet_async_cmd_cb(struct urb *urb) | ||
1733 | { | ||
1734 | struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context; | ||
1735 | int status = urb->status; | ||
1736 | |||
1737 | if (status < 0) | ||
1738 | dev_dbg(&urb->dev->dev, "%s failed with %d", | ||
1739 | __func__, status); | ||
1740 | |||
1741 | kfree(req); | ||
1742 | usb_free_urb(urb); | ||
1743 | } | ||
1744 | |||
1745 | /* | ||
1746 | * The caller must make sure that device can't be put into suspend | ||
1747 | * state until the control URB completes. | ||
1748 | */ | ||
1749 | int usbnet_write_cmd_async(struct usbnet *dev, u8 cmd, u8 reqtype, | ||
1750 | u16 value, u16 index, const void *data, u16 size) | ||
1751 | { | ||
1752 | struct usb_ctrlrequest *req = NULL; | ||
1753 | struct urb *urb; | ||
1754 | int err = -ENOMEM; | ||
1755 | void *buf = NULL; | ||
1756 | |||
1757 | netdev_dbg(dev->net, "usbnet_write_cmd cmd=0x%02x reqtype=%02x" | ||
1758 | " value=0x%04x index=0x%04x size=%d\n", | ||
1759 | cmd, reqtype, value, index, size); | ||
1760 | |||
1761 | urb = usb_alloc_urb(0, GFP_ATOMIC); | ||
1762 | if (!urb) { | ||
1763 | netdev_err(dev->net, "Error allocating URB in" | ||
1764 | " %s!\n", __func__); | ||
1765 | goto fail; | ||
1766 | } | ||
1767 | |||
1768 | if (data) { | ||
1769 | buf = kmemdup(data, size, GFP_ATOMIC); | ||
1770 | if (!buf) { | ||
1771 | netdev_err(dev->net, "Error allocating buffer" | ||
1772 | " in %s!\n", __func__); | ||
1773 | goto fail_free; | ||
1774 | } | ||
1775 | } | ||
1776 | |||
1777 | req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC); | ||
1778 | if (!req) { | ||
1779 | netdev_err(dev->net, "Failed to allocate memory for %s\n", | ||
1780 | __func__); | ||
1781 | goto fail_free_buf; | ||
1782 | } | ||
1783 | |||
1784 | req->bRequestType = reqtype; | ||
1785 | req->bRequest = cmd; | ||
1786 | req->wValue = cpu_to_le16(value); | ||
1787 | req->wIndex = cpu_to_le16(index); | ||
1788 | req->wLength = cpu_to_le16(size); | ||
1789 | |||
1790 | usb_fill_control_urb(urb, dev->udev, | ||
1791 | usb_sndctrlpipe(dev->udev, 0), | ||
1792 | (void *)req, buf, size, | ||
1793 | usbnet_async_cmd_cb, req); | ||
1794 | urb->transfer_flags |= URB_FREE_BUFFER; | ||
1795 | |||
1796 | err = usb_submit_urb(urb, GFP_ATOMIC); | ||
1797 | if (err < 0) { | ||
1798 | netdev_err(dev->net, "Error submitting the control" | ||
1799 | " message: status=%d\n", err); | ||
1800 | goto fail_free; | ||
1801 | } | ||
1802 | return 0; | ||
1803 | |||
1804 | fail_free_buf: | ||
1805 | kfree(buf); | ||
1806 | fail_free: | ||
1807 | kfree(req); | ||
1808 | usb_free_urb(urb); | ||
1809 | fail: | ||
1810 | return err; | ||
1811 | |||
1812 | } | ||
1813 | EXPORT_SYMBOL_GPL(usbnet_write_cmd_async); | ||
1814 | /*-------------------------------------------------------------------------*/ | ||
1619 | 1815 | ||
1620 | static int __init usbnet_init(void) | 1816 | static int __init usbnet_init(void) |
1621 | { | 1817 | { |