1aaf4989bSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
25b2fc499SJeff Garzik /****************************************************************
35b2fc499SJeff Garzik *
45b2fc499SJeff Garzik * kaweth.c - driver for KL5KUSB101 based USB->Ethernet
55b2fc499SJeff Garzik *
65b2fc499SJeff Garzik * (c) 2000 Interlan Communications
75b2fc499SJeff Garzik * (c) 2000 Stephane Alnet
85b2fc499SJeff Garzik * (C) 2001 Brad Hards
95b2fc499SJeff Garzik * (C) 2002 Oliver Neukum
105b2fc499SJeff Garzik *
115b2fc499SJeff Garzik * Original author: The Zapman <zapman@interlan.net>
125b2fc499SJeff Garzik * Inspired by, and much credit goes to Michael Rothwell
135b2fc499SJeff Garzik * <rothwell@interlan.net> for the test equipment, help, and patience
145b2fc499SJeff Garzik * Based off of (and with thanks to) Petko Manolov's pegaus.c driver.
155b2fc499SJeff Garzik * Also many thanks to Joel Silverman and Ed Surprenant at Kawasaki
165b2fc499SJeff Garzik * for providing the firmware and driver resources.
175b2fc499SJeff Garzik *
185b2fc499SJeff Garzik ****************************************************************/
195b2fc499SJeff Garzik
205b2fc499SJeff Garzik /* TODO:
215b2fc499SJeff Garzik * Develop test procedures for USB net interfaces
225b2fc499SJeff Garzik * Run test procedures
235b2fc499SJeff Garzik * Fix bugs from previous two steps
245b2fc499SJeff Garzik * Snoop other OSs for any tricks we're not doing
255b2fc499SJeff Garzik * Reduce arbitrary timeouts
265b2fc499SJeff Garzik * Smart multicast support
275b2fc499SJeff Garzik * Temporary MAC change support
285b2fc499SJeff Garzik * Tunable SOFs parameter - ioctl()?
295b2fc499SJeff Garzik * Ethernet stats collection
305b2fc499SJeff Garzik * Code formatting improvements
315b2fc499SJeff Garzik */
325b2fc499SJeff Garzik
335b2fc499SJeff Garzik #include <linux/module.h>
345b2fc499SJeff Garzik #include <linux/slab.h>
355b2fc499SJeff Garzik #include <linux/string.h>
365b2fc499SJeff Garzik #include <linux/delay.h>
375b2fc499SJeff Garzik #include <linux/netdevice.h>
385b2fc499SJeff Garzik #include <linux/etherdevice.h>
395b2fc499SJeff Garzik #include <linux/usb.h>
405b2fc499SJeff Garzik #include <linux/types.h>
415b2fc499SJeff Garzik #include <linux/ethtool.h>
425b2fc499SJeff Garzik #include <linux/dma-mapping.h>
435b2fc499SJeff Garzik #include <linux/wait.h>
4479682499SDavid Woodhouse #include <linux/firmware.h>
457c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
465b2fc499SJeff Garzik #include <asm/byteorder.h>
475b2fc499SJeff Garzik
485b2fc499SJeff Garzik #undef DEBUG
495b2fc499SJeff Garzik
505b2fc499SJeff Garzik #define KAWETH_MTU 1514
515b2fc499SJeff Garzik #define KAWETH_BUF_SIZE 1664
525b2fc499SJeff Garzik #define KAWETH_TX_TIMEOUT (5 * HZ)
535b2fc499SJeff Garzik #define KAWETH_SCRATCH_SIZE 32
545b2fc499SJeff Garzik #define KAWETH_FIRMWARE_BUF_SIZE 4096
552b2b2e35SRuss Dill #define KAWETH_CONTROL_TIMEOUT (30000)
565b2fc499SJeff Garzik
575b2fc499SJeff Garzik #define KAWETH_STATUS_BROKEN 0x0000001
585b2fc499SJeff Garzik #define KAWETH_STATUS_CLOSING 0x0000002
595b2fc499SJeff Garzik #define KAWETH_STATUS_SUSPENDING 0x0000004
605b2fc499SJeff Garzik
615b2fc499SJeff Garzik #define KAWETH_STATUS_BLOCKED (KAWETH_STATUS_CLOSING | KAWETH_STATUS_SUSPENDING)
625b2fc499SJeff Garzik
635b2fc499SJeff Garzik #define KAWETH_PACKET_FILTER_PROMISCUOUS 0x01
645b2fc499SJeff Garzik #define KAWETH_PACKET_FILTER_ALL_MULTICAST 0x02
655b2fc499SJeff Garzik #define KAWETH_PACKET_FILTER_DIRECTED 0x04
665b2fc499SJeff Garzik #define KAWETH_PACKET_FILTER_BROADCAST 0x08
675b2fc499SJeff Garzik #define KAWETH_PACKET_FILTER_MULTICAST 0x10
685b2fc499SJeff Garzik
695b2fc499SJeff Garzik /* Table 7 */
705b2fc499SJeff Garzik #define KAWETH_COMMAND_GET_ETHERNET_DESC 0x00
715b2fc499SJeff Garzik #define KAWETH_COMMAND_MULTICAST_FILTERS 0x01
725b2fc499SJeff Garzik #define KAWETH_COMMAND_SET_PACKET_FILTER 0x02
735b2fc499SJeff Garzik #define KAWETH_COMMAND_STATISTICS 0x03
745b2fc499SJeff Garzik #define KAWETH_COMMAND_SET_TEMP_MAC 0x06
755b2fc499SJeff Garzik #define KAWETH_COMMAND_GET_TEMP_MAC 0x07
765b2fc499SJeff Garzik #define KAWETH_COMMAND_SET_URB_SIZE 0x08
775b2fc499SJeff Garzik #define KAWETH_COMMAND_SET_SOFS_WAIT 0x09
785b2fc499SJeff Garzik #define KAWETH_COMMAND_SCAN 0xFF
795b2fc499SJeff Garzik
805b2fc499SJeff Garzik #define KAWETH_SOFS_TO_WAIT 0x05
815b2fc499SJeff Garzik
825b2fc499SJeff Garzik #define INTBUFFERSIZE 4
835b2fc499SJeff Garzik
845b2fc499SJeff Garzik #define STATE_OFFSET 0
855b2fc499SJeff Garzik #define STATE_MASK 0x40
865b2fc499SJeff Garzik #define STATE_SHIFT 5
875b2fc499SJeff Garzik
885b2fc499SJeff Garzik #define IS_BLOCKED(s) (s & KAWETH_STATUS_BLOCKED)
895b2fc499SJeff Garzik
905b2fc499SJeff Garzik
915b2fc499SJeff Garzik MODULE_AUTHOR("Michael Zappe <zapman@interlan.net>, Stephane Alnet <stephane@u-picardie.fr>, Brad Hards <bhards@bigpond.net.au> and Oliver Neukum <oliver@neukum.org>");
925b2fc499SJeff Garzik MODULE_DESCRIPTION("KL5USB101 USB Ethernet driver");
935b2fc499SJeff Garzik MODULE_LICENSE("GPL");
9479682499SDavid Woodhouse MODULE_FIRMWARE("kaweth/new_code.bin");
9579682499SDavid Woodhouse MODULE_FIRMWARE("kaweth/new_code_fix.bin");
9679682499SDavid Woodhouse MODULE_FIRMWARE("kaweth/trigger_code.bin");
9779682499SDavid Woodhouse MODULE_FIRMWARE("kaweth/trigger_code_fix.bin");
985b2fc499SJeff Garzik
995b2fc499SJeff Garzik static const char driver_name[] = "kaweth";
1005b2fc499SJeff Garzik
1015b2fc499SJeff Garzik static int kaweth_probe(
1025b2fc499SJeff Garzik struct usb_interface *intf,
1035b2fc499SJeff Garzik const struct usb_device_id *id /* from id_table */
1045b2fc499SJeff Garzik );
1055b2fc499SJeff Garzik static void kaweth_disconnect(struct usb_interface *intf);
1065b2fc499SJeff Garzik static int kaweth_suspend(struct usb_interface *intf, pm_message_t message);
1075b2fc499SJeff Garzik static int kaweth_resume(struct usb_interface *intf);
1085b2fc499SJeff Garzik
1095b2fc499SJeff Garzik /****************************************************************
1105b2fc499SJeff Garzik * usb_device_id
1115b2fc499SJeff Garzik ****************************************************************/
11206fa59a0SArvind Yadav static const struct usb_device_id usb_klsi_table[] = {
1135b2fc499SJeff Garzik { USB_DEVICE(0x03e8, 0x0008) }, /* AOX Endpoints USB Ethernet */
1145b2fc499SJeff Garzik { USB_DEVICE(0x04bb, 0x0901) }, /* I-O DATA USB-ET/T */
1155b2fc499SJeff Garzik { USB_DEVICE(0x0506, 0x03e8) }, /* 3Com 3C19250 */
1165b2fc499SJeff Garzik { USB_DEVICE(0x0506, 0x11f8) }, /* 3Com 3C460 */
1175b2fc499SJeff Garzik { USB_DEVICE(0x0557, 0x2002) }, /* ATEN USB Ethernet */
1185b2fc499SJeff Garzik { USB_DEVICE(0x0557, 0x4000) }, /* D-Link DSB-650C */
1195b2fc499SJeff Garzik { USB_DEVICE(0x0565, 0x0002) }, /* Peracom Enet */
1205b2fc499SJeff Garzik { USB_DEVICE(0x0565, 0x0003) }, /* Optus@Home UEP1045A */
1215b2fc499SJeff Garzik { USB_DEVICE(0x0565, 0x0005) }, /* Peracom Enet2 */
1225b2fc499SJeff Garzik { USB_DEVICE(0x05e9, 0x0008) }, /* KLSI KL5KUSB101B */
1235b2fc499SJeff Garzik { USB_DEVICE(0x05e9, 0x0009) }, /* KLSI KL5KUSB101B (Board change) */
1245b2fc499SJeff Garzik { USB_DEVICE(0x066b, 0x2202) }, /* Linksys USB10T */
1255b2fc499SJeff Garzik { USB_DEVICE(0x06e1, 0x0008) }, /* ADS USB-10BT */
1265b2fc499SJeff Garzik { USB_DEVICE(0x06e1, 0x0009) }, /* ADS USB-10BT */
1275b2fc499SJeff Garzik { USB_DEVICE(0x0707, 0x0100) }, /* SMC 2202USB */
1285b2fc499SJeff Garzik { USB_DEVICE(0x07aa, 0x0001) }, /* Correga K.K. */
1295b2fc499SJeff Garzik { USB_DEVICE(0x07b8, 0x4000) }, /* D-Link DU-E10 */
130dacf4fc8SAndreas Hartmann { USB_DEVICE(0x07c9, 0xb010) }, /* Allied Telesyn AT-USB10 USB Ethernet Adapter */
1315b2fc499SJeff Garzik { USB_DEVICE(0x0846, 0x1001) }, /* NetGear EA-101 */
1325b2fc499SJeff Garzik { USB_DEVICE(0x0846, 0x1002) }, /* NetGear EA-101 */
1335b2fc499SJeff Garzik { USB_DEVICE(0x085a, 0x0008) }, /* PortGear Ethernet Adapter */
1345b2fc499SJeff Garzik { USB_DEVICE(0x085a, 0x0009) }, /* PortGear Ethernet Adapter */
1355b2fc499SJeff Garzik { USB_DEVICE(0x087d, 0x5704) }, /* Jaton USB Ethernet Device Adapter */
1365b2fc499SJeff Garzik { USB_DEVICE(0x0951, 0x0008) }, /* Kingston Technology USB Ethernet Adapter */
1375b2fc499SJeff Garzik { USB_DEVICE(0x095a, 0x3003) }, /* Portsmith Express Ethernet Adapter */
1385b2fc499SJeff Garzik { USB_DEVICE(0x10bd, 0x1427) }, /* ASANTE USB To Ethernet Adapter */
1395b2fc499SJeff Garzik { USB_DEVICE(0x1342, 0x0204) }, /* Mobility USB-Ethernet Adapter */
1405b2fc499SJeff Garzik { USB_DEVICE(0x13d2, 0x0400) }, /* Shark Pocket Adapter */
1415b2fc499SJeff Garzik { USB_DEVICE(0x1485, 0x0001) }, /* Silicom U2E */
1425b2fc499SJeff Garzik { USB_DEVICE(0x1485, 0x0002) }, /* Psion Dacom Gold Port Ethernet */
1435b2fc499SJeff Garzik { USB_DEVICE(0x1645, 0x0005) }, /* Entrega E45 */
1445b2fc499SJeff Garzik { USB_DEVICE(0x1645, 0x0008) }, /* Entrega USB Ethernet Adapter */
1455b2fc499SJeff Garzik { USB_DEVICE(0x1645, 0x8005) }, /* PortGear Ethernet Adapter */
1465b2fc499SJeff Garzik { USB_DEVICE(0x1668, 0x0323) }, /* Actiontec USB Ethernet */
1475b2fc499SJeff Garzik { USB_DEVICE(0x2001, 0x4000) }, /* D-link DSB-650C */
1485b2fc499SJeff Garzik {} /* Null terminator */
1495b2fc499SJeff Garzik };
1505b2fc499SJeff Garzik
1515b2fc499SJeff Garzik MODULE_DEVICE_TABLE (usb, usb_klsi_table);
1525b2fc499SJeff Garzik
1535b2fc499SJeff Garzik /****************************************************************
1545b2fc499SJeff Garzik * kaweth_driver
1555b2fc499SJeff Garzik ****************************************************************/
1565b2fc499SJeff Garzik static struct usb_driver kaweth_driver = {
1575b2fc499SJeff Garzik .name = driver_name,
1585b2fc499SJeff Garzik .probe = kaweth_probe,
1595b2fc499SJeff Garzik .disconnect = kaweth_disconnect,
1605b2fc499SJeff Garzik .suspend = kaweth_suspend,
1615b2fc499SJeff Garzik .resume = kaweth_resume,
1625b2fc499SJeff Garzik .id_table = usb_klsi_table,
1635b2fc499SJeff Garzik .supports_autosuspend = 1,
164e1f12eb6SSarah Sharp .disable_hub_initiated_lpm = 1,
1655b2fc499SJeff Garzik };
1665b2fc499SJeff Garzik
1675b2fc499SJeff Garzik typedef __u8 eth_addr_t[6];
1685b2fc499SJeff Garzik
1695b2fc499SJeff Garzik /****************************************************************
1705b2fc499SJeff Garzik * usb_eth_dev
1715b2fc499SJeff Garzik ****************************************************************/
1725b2fc499SJeff Garzik struct usb_eth_dev {
1735b2fc499SJeff Garzik char *name;
1745b2fc499SJeff Garzik __u16 vendor;
1755b2fc499SJeff Garzik __u16 device;
1765b2fc499SJeff Garzik void *pdata;
1775b2fc499SJeff Garzik };
1785b2fc499SJeff Garzik
1795b2fc499SJeff Garzik /****************************************************************
1805b2fc499SJeff Garzik * kaweth_ethernet_configuration
1815b2fc499SJeff Garzik * Refer Table 8
1825b2fc499SJeff Garzik ****************************************************************/
1835b2fc499SJeff Garzik struct kaweth_ethernet_configuration
1845b2fc499SJeff Garzik {
1855b2fc499SJeff Garzik __u8 size;
1865b2fc499SJeff Garzik __u8 reserved1;
1875b2fc499SJeff Garzik __u8 reserved2;
1885b2fc499SJeff Garzik eth_addr_t hw_addr;
1895b2fc499SJeff Garzik __u32 statistics_mask;
1905b2fc499SJeff Garzik __le16 segment_size;
1915b2fc499SJeff Garzik __u16 max_multicast_filters;
1925b2fc499SJeff Garzik __u8 reserved3;
193ba2d3587SEric Dumazet } __packed;
1945b2fc499SJeff Garzik
1955b2fc499SJeff Garzik /****************************************************************
1965b2fc499SJeff Garzik * kaweth_device
1975b2fc499SJeff Garzik ****************************************************************/
1985b2fc499SJeff Garzik struct kaweth_device
1995b2fc499SJeff Garzik {
2005b2fc499SJeff Garzik spinlock_t device_lock;
2015b2fc499SJeff Garzik
2025b2fc499SJeff Garzik __u32 status;
2035b2fc499SJeff Garzik int end;
2045b2fc499SJeff Garzik int suspend_lowmem_rx;
2055b2fc499SJeff Garzik int suspend_lowmem_ctrl;
2065b2fc499SJeff Garzik int linkstate;
2075b2fc499SJeff Garzik int opened;
2085b2fc499SJeff Garzik struct delayed_work lowmem_work;
2095b2fc499SJeff Garzik
2105b2fc499SJeff Garzik struct usb_device *dev;
2115b2fc499SJeff Garzik struct usb_interface *intf;
2125b2fc499SJeff Garzik struct net_device *net;
2135b2fc499SJeff Garzik wait_queue_head_t term_wait;
2145b2fc499SJeff Garzik
2155b2fc499SJeff Garzik struct urb *rx_urb;
2165b2fc499SJeff Garzik struct urb *tx_urb;
2175b2fc499SJeff Garzik struct urb *irq_urb;
2185b2fc499SJeff Garzik
2195b2fc499SJeff Garzik dma_addr_t intbufferhandle;
2205b2fc499SJeff Garzik __u8 *intbuffer;
2215b2fc499SJeff Garzik dma_addr_t rxbufferhandle;
2225b2fc499SJeff Garzik __u8 *rx_buf;
2235b2fc499SJeff Garzik
2245b2fc499SJeff Garzik
2255b2fc499SJeff Garzik struct sk_buff *tx_skb;
2265b2fc499SJeff Garzik
2275b2fc499SJeff Garzik __u8 *firmware_buf;
2285b2fc499SJeff Garzik __u8 scratch[KAWETH_SCRATCH_SIZE];
2295b2fc499SJeff Garzik __u16 packet_filter_bitmap;
2305b2fc499SJeff Garzik
2315b2fc499SJeff Garzik struct kaweth_ethernet_configuration configuration;
2325b2fc499SJeff Garzik };
2335b2fc499SJeff Garzik
2345b2fc499SJeff Garzik /****************************************************************
2355b2fc499SJeff Garzik * kaweth_read_configuration
2365b2fc499SJeff Garzik ****************************************************************/
kaweth_read_configuration(struct kaweth_device * kaweth)2375b2fc499SJeff Garzik static int kaweth_read_configuration(struct kaweth_device *kaweth)
2385b2fc499SJeff Garzik {
239af3563beSSebastian Andrzej Siewior return usb_control_msg(kaweth->dev, usb_rcvctrlpipe(kaweth->dev, 0),
2405b2fc499SJeff Garzik KAWETH_COMMAND_GET_ETHERNET_DESC,
2415b2fc499SJeff Garzik USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE,
242af3563beSSebastian Andrzej Siewior 0, 0,
243af3563beSSebastian Andrzej Siewior &kaweth->configuration,
2445b2fc499SJeff Garzik sizeof(kaweth->configuration),
2455b2fc499SJeff Garzik KAWETH_CONTROL_TIMEOUT);
2465b2fc499SJeff Garzik }
2475b2fc499SJeff Garzik
2485b2fc499SJeff Garzik /****************************************************************
2495b2fc499SJeff Garzik * kaweth_set_urb_size
2505b2fc499SJeff Garzik ****************************************************************/
kaweth_set_urb_size(struct kaweth_device * kaweth,__u16 urb_size)2515b2fc499SJeff Garzik static int kaweth_set_urb_size(struct kaweth_device *kaweth, __u16 urb_size)
2525b2fc499SJeff Garzik {
25349ae25b0SGreg Kroah-Hartman netdev_dbg(kaweth->net, "Setting URB size to %d\n", (unsigned)urb_size);
2545b2fc499SJeff Garzik
255af3563beSSebastian Andrzej Siewior return usb_control_msg(kaweth->dev, usb_sndctrlpipe(kaweth->dev, 0),
2565b2fc499SJeff Garzik KAWETH_COMMAND_SET_URB_SIZE,
2575b2fc499SJeff Garzik USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
258af3563beSSebastian Andrzej Siewior urb_size, 0,
259af3563beSSebastian Andrzej Siewior &kaweth->scratch, 0,
2605b2fc499SJeff Garzik KAWETH_CONTROL_TIMEOUT);
2615b2fc499SJeff Garzik }
2625b2fc499SJeff Garzik
2635b2fc499SJeff Garzik /****************************************************************
2645b2fc499SJeff Garzik * kaweth_set_sofs_wait
2655b2fc499SJeff Garzik ****************************************************************/
kaweth_set_sofs_wait(struct kaweth_device * kaweth,__u16 sofs_wait)2665b2fc499SJeff Garzik static int kaweth_set_sofs_wait(struct kaweth_device *kaweth, __u16 sofs_wait)
2675b2fc499SJeff Garzik {
26849ae25b0SGreg Kroah-Hartman netdev_dbg(kaweth->net, "Set SOFS wait to %d\n", (unsigned)sofs_wait);
2695b2fc499SJeff Garzik
270af3563beSSebastian Andrzej Siewior return usb_control_msg(kaweth->dev, usb_sndctrlpipe(kaweth->dev, 0),
2715b2fc499SJeff Garzik KAWETH_COMMAND_SET_SOFS_WAIT,
2725b2fc499SJeff Garzik USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
273af3563beSSebastian Andrzej Siewior sofs_wait, 0,
274af3563beSSebastian Andrzej Siewior &kaweth->scratch, 0,
2755b2fc499SJeff Garzik KAWETH_CONTROL_TIMEOUT);
2765b2fc499SJeff Garzik }
2775b2fc499SJeff Garzik
2785b2fc499SJeff Garzik /****************************************************************
2795b2fc499SJeff Garzik * kaweth_set_receive_filter
2805b2fc499SJeff Garzik ****************************************************************/
kaweth_set_receive_filter(struct kaweth_device * kaweth,__u16 receive_filter)2815b2fc499SJeff Garzik static int kaweth_set_receive_filter(struct kaweth_device *kaweth,
2825b2fc499SJeff Garzik __u16 receive_filter)
2835b2fc499SJeff Garzik {
28449ae25b0SGreg Kroah-Hartman netdev_dbg(kaweth->net, "Set receive filter to %d\n",
28549ae25b0SGreg Kroah-Hartman (unsigned)receive_filter);
2865b2fc499SJeff Garzik
287af3563beSSebastian Andrzej Siewior return usb_control_msg(kaweth->dev, usb_sndctrlpipe(kaweth->dev, 0),
2885b2fc499SJeff Garzik KAWETH_COMMAND_SET_PACKET_FILTER,
2895b2fc499SJeff Garzik USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
290af3563beSSebastian Andrzej Siewior receive_filter, 0,
291af3563beSSebastian Andrzej Siewior &kaweth->scratch, 0,
2925b2fc499SJeff Garzik KAWETH_CONTROL_TIMEOUT);
2935b2fc499SJeff Garzik }
2945b2fc499SJeff Garzik
2955b2fc499SJeff Garzik /****************************************************************
2965b2fc499SJeff Garzik * kaweth_download_firmware
2975b2fc499SJeff Garzik ****************************************************************/
kaweth_download_firmware(struct kaweth_device * kaweth,const char * fwname,__u8 interrupt,__u8 type)2985b2fc499SJeff Garzik static int kaweth_download_firmware(struct kaweth_device *kaweth,
29979682499SDavid Woodhouse const char *fwname,
3005b2fc499SJeff Garzik __u8 interrupt,
3015b2fc499SJeff Garzik __u8 type)
3025b2fc499SJeff Garzik {
30379682499SDavid Woodhouse const struct firmware *fw;
30479682499SDavid Woodhouse int data_len;
30579682499SDavid Woodhouse int ret;
30679682499SDavid Woodhouse
30779682499SDavid Woodhouse ret = request_firmware(&fw, fwname, &kaweth->dev->dev);
30879682499SDavid Woodhouse if (ret) {
309db6b2219SGreg Kroah-Hartman dev_err(&kaweth->intf->dev, "Firmware request failed\n");
31079682499SDavid Woodhouse return ret;
3115b2fc499SJeff Garzik }
3125b2fc499SJeff Garzik
31379682499SDavid Woodhouse if (fw->size > KAWETH_FIRMWARE_BUF_SIZE) {
314db6b2219SGreg Kroah-Hartman dev_err(&kaweth->intf->dev, "Firmware too big: %zu\n",
315db6b2219SGreg Kroah-Hartman fw->size);
316986e3f6eSJesper Juhl release_firmware(fw);
31779682499SDavid Woodhouse return -ENOSPC;
31879682499SDavid Woodhouse }
31979682499SDavid Woodhouse data_len = fw->size;
32079682499SDavid Woodhouse memcpy(kaweth->firmware_buf, fw->data, fw->size);
32179682499SDavid Woodhouse
32279682499SDavid Woodhouse release_firmware(fw);
3235b2fc499SJeff Garzik
3245b2fc499SJeff Garzik kaweth->firmware_buf[2] = (data_len & 0xFF) - 7;
3255b2fc499SJeff Garzik kaweth->firmware_buf[3] = data_len >> 8;
3265b2fc499SJeff Garzik kaweth->firmware_buf[4] = type;
3275b2fc499SJeff Garzik kaweth->firmware_buf[5] = interrupt;
3285b2fc499SJeff Garzik
32949ae25b0SGreg Kroah-Hartman netdev_dbg(kaweth->net, "High: %i, Low:%i\n", kaweth->firmware_buf[3],
3305b2fc499SJeff Garzik kaweth->firmware_buf[2]);
3315b2fc499SJeff Garzik
33249ae25b0SGreg Kroah-Hartman netdev_dbg(kaweth->net,
33349ae25b0SGreg Kroah-Hartman "Downloading firmware at %p to kaweth device at %p\n",
3340abc1ceeSAlan Cox kaweth->firmware_buf, kaweth);
33549ae25b0SGreg Kroah-Hartman netdev_dbg(kaweth->net, "Firmware length: %d\n", data_len);
3365b2fc499SJeff Garzik
337af3563beSSebastian Andrzej Siewior return usb_control_msg(kaweth->dev, usb_sndctrlpipe(kaweth->dev, 0),
3385b2fc499SJeff Garzik KAWETH_COMMAND_SCAN,
3395b2fc499SJeff Garzik USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
340af3563beSSebastian Andrzej Siewior 0, 0,
341af3563beSSebastian Andrzej Siewior kaweth->firmware_buf, data_len,
3425b2fc499SJeff Garzik KAWETH_CONTROL_TIMEOUT);
3435b2fc499SJeff Garzik }
3445b2fc499SJeff Garzik
3455b2fc499SJeff Garzik /****************************************************************
3465b2fc499SJeff Garzik * kaweth_trigger_firmware
3475b2fc499SJeff Garzik ****************************************************************/
kaweth_trigger_firmware(struct kaweth_device * kaweth,__u8 interrupt)3485b2fc499SJeff Garzik static int kaweth_trigger_firmware(struct kaweth_device *kaweth,
3495b2fc499SJeff Garzik __u8 interrupt)
3505b2fc499SJeff Garzik {
3515b2fc499SJeff Garzik kaweth->firmware_buf[0] = 0xB6;
3525b2fc499SJeff Garzik kaweth->firmware_buf[1] = 0xC3;
3535b2fc499SJeff Garzik kaweth->firmware_buf[2] = 0x01;
3545b2fc499SJeff Garzik kaweth->firmware_buf[3] = 0x00;
3555b2fc499SJeff Garzik kaweth->firmware_buf[4] = 0x06;
3565b2fc499SJeff Garzik kaweth->firmware_buf[5] = interrupt;
3575b2fc499SJeff Garzik kaweth->firmware_buf[6] = 0x00;
3585b2fc499SJeff Garzik kaweth->firmware_buf[7] = 0x00;
3595b2fc499SJeff Garzik
360af3563beSSebastian Andrzej Siewior return usb_control_msg(kaweth->dev, usb_sndctrlpipe(kaweth->dev, 0),
3615b2fc499SJeff Garzik KAWETH_COMMAND_SCAN,
3625b2fc499SJeff Garzik USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
363af3563beSSebastian Andrzej Siewior 0, 0,
364af3563beSSebastian Andrzej Siewior (void *)kaweth->firmware_buf, 8,
3655b2fc499SJeff Garzik KAWETH_CONTROL_TIMEOUT);
3665b2fc499SJeff Garzik }
3675b2fc499SJeff Garzik
3685b2fc499SJeff Garzik /****************************************************************
3695b2fc499SJeff Garzik * kaweth_reset
3705b2fc499SJeff Garzik ****************************************************************/
kaweth_reset(struct kaweth_device * kaweth)3715b2fc499SJeff Garzik static int kaweth_reset(struct kaweth_device *kaweth)
3725b2fc499SJeff Garzik {
3735b2fc499SJeff Garzik int result;
3745b2fc499SJeff Garzik
375f0816ce3SOliver Neukum result = usb_reset_configuration(kaweth->dev);
3765b2fc499SJeff Garzik mdelay(10);
3775b2fc499SJeff Garzik
37849ae25b0SGreg Kroah-Hartman netdev_dbg(kaweth->net, "kaweth_reset() returns %d.\n", result);
3795b2fc499SJeff Garzik
3805b2fc499SJeff Garzik return result;
3815b2fc499SJeff Garzik }
3825b2fc499SJeff Garzik
3835b2fc499SJeff Garzik static void kaweth_usb_receive(struct urb *);
3845b2fc499SJeff Garzik static int kaweth_resubmit_rx_urb(struct kaweth_device *, gfp_t);
3855b2fc499SJeff Garzik
3865b2fc499SJeff Garzik /****************************************************************
3875b2fc499SJeff Garzik int_callback
3885b2fc499SJeff Garzik *****************************************************************/
3895b2fc499SJeff Garzik
kaweth_resubmit_int_urb(struct kaweth_device * kaweth,gfp_t mf)3905b2fc499SJeff Garzik static void kaweth_resubmit_int_urb(struct kaweth_device *kaweth, gfp_t mf)
3915b2fc499SJeff Garzik {
3925b2fc499SJeff Garzik int status;
3935b2fc499SJeff Garzik
3945b2fc499SJeff Garzik status = usb_submit_urb (kaweth->irq_urb, mf);
3955b2fc499SJeff Garzik if (unlikely(status == -ENOMEM)) {
3965b2fc499SJeff Garzik kaweth->suspend_lowmem_ctrl = 1;
3975b2fc499SJeff Garzik schedule_delayed_work(&kaweth->lowmem_work, HZ/4);
3985b2fc499SJeff Garzik } else {
3995b2fc499SJeff Garzik kaweth->suspend_lowmem_ctrl = 0;
4005b2fc499SJeff Garzik }
4015b2fc499SJeff Garzik
4025b2fc499SJeff Garzik if (status)
403db6b2219SGreg Kroah-Hartman dev_err(&kaweth->intf->dev,
404db6b2219SGreg Kroah-Hartman "can't resubmit intr, %s-%s, status %d\n",
4055b2fc499SJeff Garzik kaweth->dev->bus->bus_name,
4065b2fc499SJeff Garzik kaweth->dev->devpath, status);
4075b2fc499SJeff Garzik }
4085b2fc499SJeff Garzik
int_callback(struct urb * u)4095b2fc499SJeff Garzik static void int_callback(struct urb *u)
4105b2fc499SJeff Garzik {
4115b2fc499SJeff Garzik struct kaweth_device *kaweth = u->context;
4125b2fc499SJeff Garzik int act_state;
413c94cb314SOliver Neukum int status = u->status;
4145b2fc499SJeff Garzik
415c94cb314SOliver Neukum switch (status) {
4165b2fc499SJeff Garzik case 0: /* success */
4175b2fc499SJeff Garzik break;
4185b2fc499SJeff Garzik case -ECONNRESET: /* unlink */
4195b2fc499SJeff Garzik case -ENOENT:
4205b2fc499SJeff Garzik case -ESHUTDOWN:
4215b2fc499SJeff Garzik return;
4225b2fc499SJeff Garzik /* -EPIPE: should clear the halt */
4235b2fc499SJeff Garzik default: /* error */
4245b2fc499SJeff Garzik goto resubmit;
4255b2fc499SJeff Garzik }
4265b2fc499SJeff Garzik
4275b2fc499SJeff Garzik /* we check the link state to report changes */
4285b2fc499SJeff Garzik if (kaweth->linkstate != (act_state = ( kaweth->intbuffer[STATE_OFFSET] | STATE_MASK) >> STATE_SHIFT)) {
4295b2fc499SJeff Garzik if (act_state)
4305b2fc499SJeff Garzik netif_carrier_on(kaweth->net);
4315b2fc499SJeff Garzik else
4325b2fc499SJeff Garzik netif_carrier_off(kaweth->net);
4335b2fc499SJeff Garzik
4345b2fc499SJeff Garzik kaweth->linkstate = act_state;
4355b2fc499SJeff Garzik }
4365b2fc499SJeff Garzik resubmit:
4375b2fc499SJeff Garzik kaweth_resubmit_int_urb(kaweth, GFP_ATOMIC);
4385b2fc499SJeff Garzik }
4395b2fc499SJeff Garzik
kaweth_resubmit_tl(struct work_struct * work)4405b2fc499SJeff Garzik static void kaweth_resubmit_tl(struct work_struct *work)
4415b2fc499SJeff Garzik {
4425b2fc499SJeff Garzik struct kaweth_device *kaweth =
4435b2fc499SJeff Garzik container_of(work, struct kaweth_device, lowmem_work.work);
4445b2fc499SJeff Garzik
4455b2fc499SJeff Garzik if (IS_BLOCKED(kaweth->status))
4465b2fc499SJeff Garzik return;
4475b2fc499SJeff Garzik
4485b2fc499SJeff Garzik if (kaweth->suspend_lowmem_rx)
4495b2fc499SJeff Garzik kaweth_resubmit_rx_urb(kaweth, GFP_NOIO);
4505b2fc499SJeff Garzik
4515b2fc499SJeff Garzik if (kaweth->suspend_lowmem_ctrl)
4525b2fc499SJeff Garzik kaweth_resubmit_int_urb(kaweth, GFP_NOIO);
4535b2fc499SJeff Garzik }
4545b2fc499SJeff Garzik
4555b2fc499SJeff Garzik
4565b2fc499SJeff Garzik /****************************************************************
4575b2fc499SJeff Garzik * kaweth_resubmit_rx_urb
4585b2fc499SJeff Garzik ****************************************************************/
kaweth_resubmit_rx_urb(struct kaweth_device * kaweth,gfp_t mem_flags)4595b2fc499SJeff Garzik static int kaweth_resubmit_rx_urb(struct kaweth_device *kaweth,
4605b2fc499SJeff Garzik gfp_t mem_flags)
4615b2fc499SJeff Garzik {
4625b2fc499SJeff Garzik int result;
4635b2fc499SJeff Garzik
4645b2fc499SJeff Garzik usb_fill_bulk_urb(kaweth->rx_urb,
4655b2fc499SJeff Garzik kaweth->dev,
4665b2fc499SJeff Garzik usb_rcvbulkpipe(kaweth->dev, 1),
4675b2fc499SJeff Garzik kaweth->rx_buf,
4685b2fc499SJeff Garzik KAWETH_BUF_SIZE,
4695b2fc499SJeff Garzik kaweth_usb_receive,
4705b2fc499SJeff Garzik kaweth);
4715b2fc499SJeff Garzik kaweth->rx_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
4725b2fc499SJeff Garzik kaweth->rx_urb->transfer_dma = kaweth->rxbufferhandle;
4735b2fc499SJeff Garzik
4745b2fc499SJeff Garzik if((result = usb_submit_urb(kaweth->rx_urb, mem_flags))) {
4755b2fc499SJeff Garzik if (result == -ENOMEM) {
4765b2fc499SJeff Garzik kaweth->suspend_lowmem_rx = 1;
4775b2fc499SJeff Garzik schedule_delayed_work(&kaweth->lowmem_work, HZ/4);
4785b2fc499SJeff Garzik }
479db6b2219SGreg Kroah-Hartman dev_err(&kaweth->intf->dev, "resubmitting rx_urb %d failed\n",
480db6b2219SGreg Kroah-Hartman result);
4815b2fc499SJeff Garzik } else {
4825b2fc499SJeff Garzik kaweth->suspend_lowmem_rx = 0;
4835b2fc499SJeff Garzik }
4845b2fc499SJeff Garzik
4855b2fc499SJeff Garzik return result;
4865b2fc499SJeff Garzik }
4875b2fc499SJeff Garzik
488a19c2619SSebastian Andrzej Siewior static void kaweth_async_set_rx_mode(struct kaweth_device *kaweth,
489a19c2619SSebastian Andrzej Siewior bool may_sleep);
4905b2fc499SJeff Garzik
4915b2fc499SJeff Garzik /****************************************************************
4925b2fc499SJeff Garzik * kaweth_usb_receive
4935b2fc499SJeff Garzik ****************************************************************/
kaweth_usb_receive(struct urb * urb)4945b2fc499SJeff Garzik static void kaweth_usb_receive(struct urb *urb)
4955b2fc499SJeff Garzik {
49649ae25b0SGreg Kroah-Hartman struct device *dev = &urb->dev->dev;
4975b2fc499SJeff Garzik struct kaweth_device *kaweth = urb->context;
4985b2fc499SJeff Garzik struct net_device *net = kaweth->net;
499c94cb314SOliver Neukum int status = urb->status;
500ba49fed8SSebastian Andrzej Siewior unsigned long flags;
5015b2fc499SJeff Garzik int count = urb->actual_length;
5025b2fc499SJeff Garzik int count2 = urb->transfer_buffer_length;
5035b2fc499SJeff Garzik
5045b2fc499SJeff Garzik __u16 pkt_len = le16_to_cpup((__le16 *)kaweth->rx_buf);
5055b2fc499SJeff Garzik
5065b2fc499SJeff Garzik struct sk_buff *skb;
5075b2fc499SJeff Garzik
508710b523aSLarry Finger if (unlikely(status == -EPIPE)) {
5096ffa770eSTobias Klauser net->stats.rx_errors++;
5105b2fc499SJeff Garzik kaweth->end = 1;
5115b2fc499SJeff Garzik wake_up(&kaweth->term_wait);
51249ae25b0SGreg Kroah-Hartman dev_dbg(dev, "Status was -EPIPE.\n");
5135b2fc499SJeff Garzik return;
5145b2fc499SJeff Garzik }
515710b523aSLarry Finger if (unlikely(status == -ECONNRESET || status == -ESHUTDOWN)) {
516710b523aSLarry Finger /* we are killed - set a flag and wake the disconnect handler */
517710b523aSLarry Finger kaweth->end = 1;
518710b523aSLarry Finger wake_up(&kaweth->term_wait);
51949ae25b0SGreg Kroah-Hartman dev_dbg(dev, "Status was -ECONNRESET or -ESHUTDOWN.\n");
520710b523aSLarry Finger return;
521710b523aSLarry Finger }
522710b523aSLarry Finger if (unlikely(status == -EPROTO || status == -ETIME ||
523710b523aSLarry Finger status == -EILSEQ)) {
5246ffa770eSTobias Klauser net->stats.rx_errors++;
52549ae25b0SGreg Kroah-Hartman dev_dbg(dev, "Status was -EPROTO, -ETIME, or -EILSEQ.\n");
526710b523aSLarry Finger return;
527710b523aSLarry Finger }
528710b523aSLarry Finger if (unlikely(status == -EOVERFLOW)) {
5296ffa770eSTobias Klauser net->stats.rx_errors++;
53049ae25b0SGreg Kroah-Hartman dev_dbg(dev, "Status was -EOVERFLOW.\n");
531710b523aSLarry Finger }
532ba49fed8SSebastian Andrzej Siewior spin_lock_irqsave(&kaweth->device_lock, flags);
5335b2fc499SJeff Garzik if (IS_BLOCKED(kaweth->status)) {
534ba49fed8SSebastian Andrzej Siewior spin_unlock_irqrestore(&kaweth->device_lock, flags);
5355b2fc499SJeff Garzik return;
5365b2fc499SJeff Garzik }
537ba49fed8SSebastian Andrzej Siewior spin_unlock_irqrestore(&kaweth->device_lock, flags);
5385b2fc499SJeff Garzik
539c94cb314SOliver Neukum if(status && status != -EREMOTEIO && count != 1) {
540db6b2219SGreg Kroah-Hartman dev_err(&kaweth->intf->dev,
541db6b2219SGreg Kroah-Hartman "%s RX status: %d count: %d packet_len: %d\n",
542db6b2219SGreg Kroah-Hartman net->name, status, count, (int)pkt_len);
5435b2fc499SJeff Garzik kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC);
5445b2fc499SJeff Garzik return;
5455b2fc499SJeff Garzik }
5465b2fc499SJeff Garzik
5475b2fc499SJeff Garzik if(kaweth->net && (count > 2)) {
5485b2fc499SJeff Garzik if(pkt_len > (count - 2)) {
549db6b2219SGreg Kroah-Hartman dev_err(&kaweth->intf->dev,
550db6b2219SGreg Kroah-Hartman "Packet length too long for USB frame (pkt_len: %x, count: %x)\n",
551db6b2219SGreg Kroah-Hartman pkt_len, count);
552db6b2219SGreg Kroah-Hartman dev_err(&kaweth->intf->dev, "Packet len & 2047: %x\n",
553db6b2219SGreg Kroah-Hartman pkt_len & 2047);
554db6b2219SGreg Kroah-Hartman dev_err(&kaweth->intf->dev, "Count 2: %x\n", count2);
5555b2fc499SJeff Garzik kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC);
5565b2fc499SJeff Garzik return;
5575b2fc499SJeff Garzik }
5585b2fc499SJeff Garzik
5595b2fc499SJeff Garzik if(!(skb = dev_alloc_skb(pkt_len+2))) {
5605b2fc499SJeff Garzik kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC);
5615b2fc499SJeff Garzik return;
5625b2fc499SJeff Garzik }
5635b2fc499SJeff Garzik
5645b2fc499SJeff Garzik skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
5655b2fc499SJeff Garzik
5668c7b7faaSDavid S. Miller skb_copy_to_linear_data(skb, kaweth->rx_buf + 2, pkt_len);
5675b2fc499SJeff Garzik
5685b2fc499SJeff Garzik skb_put(skb, pkt_len);
5695b2fc499SJeff Garzik
5705b2fc499SJeff Garzik skb->protocol = eth_type_trans(skb, net);
5715b2fc499SJeff Garzik
5725b2fc499SJeff Garzik netif_rx(skb);
5735b2fc499SJeff Garzik
5746ffa770eSTobias Klauser net->stats.rx_packets++;
5756ffa770eSTobias Klauser net->stats.rx_bytes += pkt_len;
5765b2fc499SJeff Garzik }
5775b2fc499SJeff Garzik
5785b2fc499SJeff Garzik kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC);
5795b2fc499SJeff Garzik }
5805b2fc499SJeff Garzik
5815b2fc499SJeff Garzik /****************************************************************
5825b2fc499SJeff Garzik * kaweth_open
5835b2fc499SJeff Garzik ****************************************************************/
kaweth_open(struct net_device * net)5845b2fc499SJeff Garzik static int kaweth_open(struct net_device *net)
5855b2fc499SJeff Garzik {
5865b2fc499SJeff Garzik struct kaweth_device *kaweth = netdev_priv(net);
5875b2fc499SJeff Garzik int res;
5885b2fc499SJeff Garzik
5895b2fc499SJeff Garzik res = usb_autopm_get_interface(kaweth->intf);
5905b2fc499SJeff Garzik if (res) {
591db6b2219SGreg Kroah-Hartman dev_err(&kaweth->intf->dev, "Interface cannot be resumed.\n");
5925b2fc499SJeff Garzik return -EIO;
5935b2fc499SJeff Garzik }
5945b2fc499SJeff Garzik res = kaweth_resubmit_rx_urb(kaweth, GFP_KERNEL);
5955b2fc499SJeff Garzik if (res)
5965b2fc499SJeff Garzik goto err_out;
5975b2fc499SJeff Garzik
5985b2fc499SJeff Garzik usb_fill_int_urb(
5995b2fc499SJeff Garzik kaweth->irq_urb,
6005b2fc499SJeff Garzik kaweth->dev,
6015b2fc499SJeff Garzik usb_rcvintpipe(kaweth->dev, 3),
6025b2fc499SJeff Garzik kaweth->intbuffer,
6035b2fc499SJeff Garzik INTBUFFERSIZE,
6045b2fc499SJeff Garzik int_callback,
6055b2fc499SJeff Garzik kaweth,
6065b2fc499SJeff Garzik 250); /* overriding the descriptor */
6075b2fc499SJeff Garzik kaweth->irq_urb->transfer_dma = kaweth->intbufferhandle;
6085b2fc499SJeff Garzik kaweth->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
6095b2fc499SJeff Garzik
6105b2fc499SJeff Garzik res = usb_submit_urb(kaweth->irq_urb, GFP_KERNEL);
6115b2fc499SJeff Garzik if (res) {
6125b2fc499SJeff Garzik usb_kill_urb(kaweth->rx_urb);
6135b2fc499SJeff Garzik goto err_out;
6145b2fc499SJeff Garzik }
6155b2fc499SJeff Garzik kaweth->opened = 1;
6165b2fc499SJeff Garzik
6175b2fc499SJeff Garzik netif_start_queue(net);
6185b2fc499SJeff Garzik
619a19c2619SSebastian Andrzej Siewior kaweth_async_set_rx_mode(kaweth, true);
6205b2fc499SJeff Garzik return 0;
6215b2fc499SJeff Garzik
6225b2fc499SJeff Garzik err_out:
623ceb0c77eSOliver Neukum usb_autopm_put_interface(kaweth->intf);
6245b2fc499SJeff Garzik return -EIO;
6255b2fc499SJeff Garzik }
6265b2fc499SJeff Garzik
6275b2fc499SJeff Garzik /****************************************************************
6285b2fc499SJeff Garzik * kaweth_kill_urbs
6295b2fc499SJeff Garzik ****************************************************************/
kaweth_kill_urbs(struct kaweth_device * kaweth)6305b2fc499SJeff Garzik static void kaweth_kill_urbs(struct kaweth_device *kaweth)
6315b2fc499SJeff Garzik {
6325b2fc499SJeff Garzik usb_kill_urb(kaweth->irq_urb);
6335b2fc499SJeff Garzik usb_kill_urb(kaweth->rx_urb);
6345b2fc499SJeff Garzik usb_kill_urb(kaweth->tx_urb);
6355b2fc499SJeff Garzik
6364bb073c0SDavid S. Miller cancel_delayed_work_sync(&kaweth->lowmem_work);
6375b2fc499SJeff Garzik
6385b2fc499SJeff Garzik /* a scheduled work may have resubmitted,
6395b2fc499SJeff Garzik we hit them again */
6405b2fc499SJeff Garzik usb_kill_urb(kaweth->irq_urb);
6415b2fc499SJeff Garzik usb_kill_urb(kaweth->rx_urb);
6425b2fc499SJeff Garzik }
6435b2fc499SJeff Garzik
6445b2fc499SJeff Garzik /****************************************************************
6455b2fc499SJeff Garzik * kaweth_close
6465b2fc499SJeff Garzik ****************************************************************/
kaweth_close(struct net_device * net)6475b2fc499SJeff Garzik static int kaweth_close(struct net_device *net)
6485b2fc499SJeff Garzik {
6495b2fc499SJeff Garzik struct kaweth_device *kaweth = netdev_priv(net);
6505b2fc499SJeff Garzik
6515b2fc499SJeff Garzik netif_stop_queue(net);
6525b2fc499SJeff Garzik kaweth->opened = 0;
6535b2fc499SJeff Garzik
6545b2fc499SJeff Garzik kaweth->status |= KAWETH_STATUS_CLOSING;
6555b2fc499SJeff Garzik
6565b2fc499SJeff Garzik kaweth_kill_urbs(kaweth);
6575b2fc499SJeff Garzik
6585b2fc499SJeff Garzik kaweth->status &= ~KAWETH_STATUS_CLOSING;
6595b2fc499SJeff Garzik
660ceb0c77eSOliver Neukum usb_autopm_put_interface(kaweth->intf);
6615b2fc499SJeff Garzik
6625b2fc499SJeff Garzik return 0;
6635b2fc499SJeff Garzik }
6645b2fc499SJeff Garzik
kaweth_get_link(struct net_device * dev)6655b2fc499SJeff Garzik static u32 kaweth_get_link(struct net_device *dev)
6665b2fc499SJeff Garzik {
6675b2fc499SJeff Garzik struct kaweth_device *kaweth = netdev_priv(dev);
6685b2fc499SJeff Garzik
6695b2fc499SJeff Garzik return kaweth->linkstate;
6705b2fc499SJeff Garzik }
6715b2fc499SJeff Garzik
6720fc0b732SStephen Hemminger static const struct ethtool_ops ops = {
6735b2fc499SJeff Garzik .get_link = kaweth_get_link
6745b2fc499SJeff Garzik };
6755b2fc499SJeff Garzik
6765b2fc499SJeff Garzik /****************************************************************
6775b2fc499SJeff Garzik * kaweth_usb_transmit_complete
6785b2fc499SJeff Garzik ****************************************************************/
kaweth_usb_transmit_complete(struct urb * urb)6795b2fc499SJeff Garzik static void kaweth_usb_transmit_complete(struct urb *urb)
6805b2fc499SJeff Garzik {
6815b2fc499SJeff Garzik struct kaweth_device *kaweth = urb->context;
6825b2fc499SJeff Garzik struct sk_buff *skb = kaweth->tx_skb;
683c94cb314SOliver Neukum int status = urb->status;
6845b2fc499SJeff Garzik
685c94cb314SOliver Neukum if (unlikely(status != 0))
686c94cb314SOliver Neukum if (status != -ENOENT)
68749ae25b0SGreg Kroah-Hartman dev_dbg(&urb->dev->dev, "%s: TX status %d.\n",
68849ae25b0SGreg Kroah-Hartman kaweth->net->name, status);
6895b2fc499SJeff Garzik
6905b2fc499SJeff Garzik netif_wake_queue(kaweth->net);
6915b2fc499SJeff Garzik dev_kfree_skb_irq(skb);
6925b2fc499SJeff Garzik }
6935b2fc499SJeff Garzik
6945b2fc499SJeff Garzik /****************************************************************
6955b2fc499SJeff Garzik * kaweth_start_xmit
6965b2fc499SJeff Garzik ****************************************************************/
kaweth_start_xmit(struct sk_buff * skb,struct net_device * net)69725a79c41SStephen Hemminger static netdev_tx_t kaweth_start_xmit(struct sk_buff *skb,
69825a79c41SStephen Hemminger struct net_device *net)
6995b2fc499SJeff Garzik {
7005b2fc499SJeff Garzik struct kaweth_device *kaweth = netdev_priv(net);
7015b2fc499SJeff Garzik __le16 *private_header;
7025b2fc499SJeff Garzik
7035b2fc499SJeff Garzik int res;
7045b2fc499SJeff Garzik
7054ff61c8fSLarry Finger spin_lock_irq(&kaweth->device_lock);
7065b2fc499SJeff Garzik
707a19c2619SSebastian Andrzej Siewior kaweth_async_set_rx_mode(kaweth, false);
7085b2fc499SJeff Garzik netif_stop_queue(net);
7095b2fc499SJeff Garzik if (IS_BLOCKED(kaweth->status)) {
7105b2fc499SJeff Garzik goto skip;
7115b2fc499SJeff Garzik }
7125b2fc499SJeff Garzik
7135b2fc499SJeff Garzik /* We now decide whether we can put our special header into the sk_buff */
71439fba783SEric Dumazet if (skb_cow_head(skb, 2)) {
7156ffa770eSTobias Klauser net->stats.tx_errors++;
7165b2fc499SJeff Garzik netif_start_queue(net);
7174ff61c8fSLarry Finger spin_unlock_irq(&kaweth->device_lock);
71839fba783SEric Dumazet dev_kfree_skb_any(skb);
7196ed10654SPatrick McHardy return NETDEV_TX_OK;
7205b2fc499SJeff Garzik }
7215b2fc499SJeff Garzik
722d58ff351SJohannes Berg private_header = __skb_push(skb, 2);
7235b2fc499SJeff Garzik *private_header = cpu_to_le16(skb->len-2);
7245b2fc499SJeff Garzik kaweth->tx_skb = skb;
7255b2fc499SJeff Garzik
7265b2fc499SJeff Garzik usb_fill_bulk_urb(kaweth->tx_urb,
7275b2fc499SJeff Garzik kaweth->dev,
7285b2fc499SJeff Garzik usb_sndbulkpipe(kaweth->dev, 2),
7295b2fc499SJeff Garzik private_header,
7305b2fc499SJeff Garzik skb->len,
7315b2fc499SJeff Garzik kaweth_usb_transmit_complete,
7325b2fc499SJeff Garzik kaweth);
7335b2fc499SJeff Garzik kaweth->end = 0;
7345b2fc499SJeff Garzik
7355b2fc499SJeff Garzik if((res = usb_submit_urb(kaweth->tx_urb, GFP_ATOMIC)))
7365b2fc499SJeff Garzik {
7374dc89948SGreg Kroah-Hartman dev_warn(&net->dev, "kaweth failed tx_urb %d\n", res);
7385b2fc499SJeff Garzik skip:
7396ffa770eSTobias Klauser net->stats.tx_errors++;
7405b2fc499SJeff Garzik
7415b2fc499SJeff Garzik netif_start_queue(net);
7425b2fc499SJeff Garzik dev_kfree_skb_irq(skb);
7435b2fc499SJeff Garzik }
7445b2fc499SJeff Garzik else
7455b2fc499SJeff Garzik {
7466ffa770eSTobias Klauser net->stats.tx_packets++;
7476ffa770eSTobias Klauser net->stats.tx_bytes += skb->len;
7485b2fc499SJeff Garzik }
7495b2fc499SJeff Garzik
7504ff61c8fSLarry Finger spin_unlock_irq(&kaweth->device_lock);
7515b2fc499SJeff Garzik
7526ed10654SPatrick McHardy return NETDEV_TX_OK;
7535b2fc499SJeff Garzik }
7545b2fc499SJeff Garzik
7555b2fc499SJeff Garzik /****************************************************************
7565b2fc499SJeff Garzik * kaweth_set_rx_mode
7575b2fc499SJeff Garzik ****************************************************************/
kaweth_set_rx_mode(struct net_device * net)7585b2fc499SJeff Garzik static void kaweth_set_rx_mode(struct net_device *net)
7595b2fc499SJeff Garzik {
7605b2fc499SJeff Garzik struct kaweth_device *kaweth = netdev_priv(net);
7615b2fc499SJeff Garzik
7625b2fc499SJeff Garzik __u16 packet_filter_bitmap = KAWETH_PACKET_FILTER_DIRECTED |
7635b2fc499SJeff Garzik KAWETH_PACKET_FILTER_BROADCAST |
7645b2fc499SJeff Garzik KAWETH_PACKET_FILTER_MULTICAST;
7655b2fc499SJeff Garzik
76649ae25b0SGreg Kroah-Hartman netdev_dbg(net, "Setting Rx mode to %d\n", packet_filter_bitmap);
7675b2fc499SJeff Garzik
7685b2fc499SJeff Garzik netif_stop_queue(net);
7695b2fc499SJeff Garzik
7705b2fc499SJeff Garzik if (net->flags & IFF_PROMISC) {
7715b2fc499SJeff Garzik packet_filter_bitmap |= KAWETH_PACKET_FILTER_PROMISCUOUS;
7725b2fc499SJeff Garzik }
7734cd24eafSJiri Pirko else if (!netdev_mc_empty(net) || (net->flags & IFF_ALLMULTI)) {
7745b2fc499SJeff Garzik packet_filter_bitmap |= KAWETH_PACKET_FILTER_ALL_MULTICAST;
7755b2fc499SJeff Garzik }
7765b2fc499SJeff Garzik
7775b2fc499SJeff Garzik kaweth->packet_filter_bitmap = packet_filter_bitmap;
7785b2fc499SJeff Garzik netif_wake_queue(net);
7795b2fc499SJeff Garzik }
7805b2fc499SJeff Garzik
7815b2fc499SJeff Garzik /****************************************************************
7825b2fc499SJeff Garzik * kaweth_async_set_rx_mode
7835b2fc499SJeff Garzik ****************************************************************/
kaweth_async_set_rx_mode(struct kaweth_device * kaweth,bool may_sleep)784a19c2619SSebastian Andrzej Siewior static void kaweth_async_set_rx_mode(struct kaweth_device *kaweth,
785a19c2619SSebastian Andrzej Siewior bool may_sleep)
7865b2fc499SJeff Garzik {
787a19c2619SSebastian Andrzej Siewior int ret;
7885b2fc499SJeff Garzik __u16 packet_filter_bitmap = kaweth->packet_filter_bitmap;
789710b523aSLarry Finger
7905b2fc499SJeff Garzik kaweth->packet_filter_bitmap = 0;
7915b2fc499SJeff Garzik if (packet_filter_bitmap == 0)
7925b2fc499SJeff Garzik return;
7935b2fc499SJeff Garzik
794a19c2619SSebastian Andrzej Siewior if (!may_sleep)
795710b523aSLarry Finger return;
796710b523aSLarry Finger
797a19c2619SSebastian Andrzej Siewior ret = usb_control_msg(kaweth->dev, usb_sndctrlpipe(kaweth->dev, 0),
7985b2fc499SJeff Garzik KAWETH_COMMAND_SET_PACKET_FILTER,
7995b2fc499SJeff Garzik USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
800a19c2619SSebastian Andrzej Siewior packet_filter_bitmap, 0,
801a19c2619SSebastian Andrzej Siewior &kaweth->scratch, 0,
8025b2fc499SJeff Garzik KAWETH_CONTROL_TIMEOUT);
803a19c2619SSebastian Andrzej Siewior if (ret < 0)
804db6b2219SGreg Kroah-Hartman dev_err(&kaweth->intf->dev, "Failed to set Rx mode: %d\n",
805a19c2619SSebastian Andrzej Siewior ret);
806a19c2619SSebastian Andrzej Siewior else
80749ae25b0SGreg Kroah-Hartman netdev_dbg(kaweth->net, "Set Rx mode to %d\n",
80849ae25b0SGreg Kroah-Hartman packet_filter_bitmap);
8095b2fc499SJeff Garzik }
8105b2fc499SJeff Garzik
8115b2fc499SJeff Garzik /****************************************************************
8125b2fc499SJeff Garzik * kaweth_tx_timeout
8135b2fc499SJeff Garzik ****************************************************************/
kaweth_tx_timeout(struct net_device * net,unsigned int txqueue)8140290bd29SMichael S. Tsirkin static void kaweth_tx_timeout(struct net_device *net, unsigned int txqueue)
8155b2fc499SJeff Garzik {
8165b2fc499SJeff Garzik struct kaweth_device *kaweth = netdev_priv(net);
8175b2fc499SJeff Garzik
8184dc89948SGreg Kroah-Hartman dev_warn(&net->dev, "%s: Tx timed out. Resetting.\n", net->name);
8196ffa770eSTobias Klauser net->stats.tx_errors++;
820860e9538SFlorian Westphal netif_trans_update(net);
8215b2fc499SJeff Garzik
8225b2fc499SJeff Garzik usb_unlink_urb(kaweth->tx_urb);
8235b2fc499SJeff Garzik }
8245b2fc499SJeff Garzik
8255b2fc499SJeff Garzik /****************************************************************
8265b2fc499SJeff Garzik * kaweth_suspend
8275b2fc499SJeff Garzik ****************************************************************/
kaweth_suspend(struct usb_interface * intf,pm_message_t message)8285b2fc499SJeff Garzik static int kaweth_suspend(struct usb_interface *intf, pm_message_t message)
8295b2fc499SJeff Garzik {
8305b2fc499SJeff Garzik struct kaweth_device *kaweth = usb_get_intfdata(intf);
8315b2fc499SJeff Garzik unsigned long flags;
8325b2fc499SJeff Garzik
8335b2fc499SJeff Garzik spin_lock_irqsave(&kaweth->device_lock, flags);
8345b2fc499SJeff Garzik kaweth->status |= KAWETH_STATUS_SUSPENDING;
8355b2fc499SJeff Garzik spin_unlock_irqrestore(&kaweth->device_lock, flags);
8365b2fc499SJeff Garzik
8375b2fc499SJeff Garzik kaweth_kill_urbs(kaweth);
8385b2fc499SJeff Garzik return 0;
8395b2fc499SJeff Garzik }
8405b2fc499SJeff Garzik
8415b2fc499SJeff Garzik /****************************************************************
8425b2fc499SJeff Garzik * kaweth_resume
8435b2fc499SJeff Garzik ****************************************************************/
kaweth_resume(struct usb_interface * intf)8445b2fc499SJeff Garzik static int kaweth_resume(struct usb_interface *intf)
8455b2fc499SJeff Garzik {
8465b2fc499SJeff Garzik struct kaweth_device *kaweth = usb_get_intfdata(intf);
8475b2fc499SJeff Garzik unsigned long flags;
8485b2fc499SJeff Garzik
8495b2fc499SJeff Garzik spin_lock_irqsave(&kaweth->device_lock, flags);
8505b2fc499SJeff Garzik kaweth->status &= ~KAWETH_STATUS_SUSPENDING;
8515b2fc499SJeff Garzik spin_unlock_irqrestore(&kaweth->device_lock, flags);
8525b2fc499SJeff Garzik
8535b2fc499SJeff Garzik if (!kaweth->opened)
8545b2fc499SJeff Garzik return 0;
8555b2fc499SJeff Garzik kaweth_resubmit_rx_urb(kaweth, GFP_NOIO);
8565b2fc499SJeff Garzik kaweth_resubmit_int_urb(kaweth, GFP_NOIO);
8575b2fc499SJeff Garzik
8585b2fc499SJeff Garzik return 0;
8595b2fc499SJeff Garzik }
8605b2fc499SJeff Garzik
8615b2fc499SJeff Garzik /****************************************************************
8625b2fc499SJeff Garzik * kaweth_probe
8635b2fc499SJeff Garzik ****************************************************************/
864321ea8b2SOliver Neukum
865321ea8b2SOliver Neukum
866321ea8b2SOliver Neukum static const struct net_device_ops kaweth_netdev_ops = {
867321ea8b2SOliver Neukum .ndo_open = kaweth_open,
868321ea8b2SOliver Neukum .ndo_stop = kaweth_close,
869321ea8b2SOliver Neukum .ndo_start_xmit = kaweth_start_xmit,
870321ea8b2SOliver Neukum .ndo_tx_timeout = kaweth_tx_timeout,
871afc4b13dSJiri Pirko .ndo_set_rx_mode = kaweth_set_rx_mode,
872240c102dSBen Hutchings .ndo_set_mac_address = eth_mac_addr,
873240c102dSBen Hutchings .ndo_validate_addr = eth_validate_addr,
874321ea8b2SOliver Neukum };
875321ea8b2SOliver Neukum
kaweth_probe(struct usb_interface * intf,const struct usb_device_id * id)8765b2fc499SJeff Garzik static int kaweth_probe(
8775b2fc499SJeff Garzik struct usb_interface *intf,
8785b2fc499SJeff Garzik const struct usb_device_id *id /* from id_table */
8795b2fc499SJeff Garzik )
8805b2fc499SJeff Garzik {
88149ae25b0SGreg Kroah-Hartman struct device *dev = &intf->dev;
88249ae25b0SGreg Kroah-Hartman struct usb_device *udev = interface_to_usbdev(intf);
8835b2fc499SJeff Garzik struct kaweth_device *kaweth;
8845b2fc499SJeff Garzik struct net_device *netdev;
8855b2fc499SJeff Garzik const eth_addr_t bcast_addr = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
8865b2fc499SJeff Garzik int result = 0;
887575ced7fSOliver Neukum int rv = -EIO;
8885b2fc499SJeff Garzik
88949ae25b0SGreg Kroah-Hartman dev_dbg(dev,
89049ae25b0SGreg Kroah-Hartman "Kawasaki Device Probe (Device number:%d): 0x%4.4x:0x%4.4x:0x%4.4x\n",
89149ae25b0SGreg Kroah-Hartman udev->devnum, le16_to_cpu(udev->descriptor.idVendor),
89249ae25b0SGreg Kroah-Hartman le16_to_cpu(udev->descriptor.idProduct),
89349ae25b0SGreg Kroah-Hartman le16_to_cpu(udev->descriptor.bcdDevice));
8945b2fc499SJeff Garzik
89549ae25b0SGreg Kroah-Hartman dev_dbg(dev, "Device at %p\n", udev);
8965b2fc499SJeff Garzik
89749ae25b0SGreg Kroah-Hartman dev_dbg(dev, "Descriptor length: %x type: %x\n",
89849ae25b0SGreg Kroah-Hartman (int)udev->descriptor.bLength,
89949ae25b0SGreg Kroah-Hartman (int)udev->descriptor.bDescriptorType);
9005b2fc499SJeff Garzik
9015b2fc499SJeff Garzik netdev = alloc_etherdev(sizeof(*kaweth));
9025b2fc499SJeff Garzik if (!netdev)
9035b2fc499SJeff Garzik return -ENOMEM;
9045b2fc499SJeff Garzik
9055b2fc499SJeff Garzik kaweth = netdev_priv(netdev);
90649ae25b0SGreg Kroah-Hartman kaweth->dev = udev;
9075b2fc499SJeff Garzik kaweth->net = netdev;
90860bcabd0SOliver Neukum kaweth->intf = intf;
9095b2fc499SJeff Garzik
9105b2fc499SJeff Garzik spin_lock_init(&kaweth->device_lock);
9115b2fc499SJeff Garzik init_waitqueue_head(&kaweth->term_wait);
9125b2fc499SJeff Garzik
91349ae25b0SGreg Kroah-Hartman dev_dbg(dev, "Resetting.\n");
9145b2fc499SJeff Garzik
9155b2fc499SJeff Garzik kaweth_reset(kaweth);
9165b2fc499SJeff Garzik
9175b2fc499SJeff Garzik /*
9185b2fc499SJeff Garzik * If high byte of bcdDevice is nonzero, firmware is already
9195b2fc499SJeff Garzik * downloaded. Don't try to do it again, or we'll hang the device.
9205b2fc499SJeff Garzik */
9215b2fc499SJeff Garzik
92249ae25b0SGreg Kroah-Hartman if (le16_to_cpu(udev->descriptor.bcdDevice) >> 8) {
92349ae25b0SGreg Kroah-Hartman dev_info(dev, "Firmware present in device.\n");
9245b2fc499SJeff Garzik } else {
9255b2fc499SJeff Garzik /* Download the firmware */
92649ae25b0SGreg Kroah-Hartman dev_info(dev, "Downloading firmware...\n");
9275b2fc499SJeff Garzik kaweth->firmware_buf = (__u8 *)__get_free_page(GFP_KERNEL);
928575ced7fSOliver Neukum if (!kaweth->firmware_buf) {
929575ced7fSOliver Neukum rv = -ENOMEM;
930575ced7fSOliver Neukum goto err_free_netdev;
931575ced7fSOliver Neukum }
9325b2fc499SJeff Garzik if ((result = kaweth_download_firmware(kaweth,
93379682499SDavid Woodhouse "kaweth/new_code.bin",
9345b2fc499SJeff Garzik 100,
9355b2fc499SJeff Garzik 2)) < 0) {
93649ae25b0SGreg Kroah-Hartman dev_err(dev, "Error downloading firmware (%d)\n",
937db6b2219SGreg Kroah-Hartman result);
9385b2fc499SJeff Garzik goto err_fw;
9395b2fc499SJeff Garzik }
9405b2fc499SJeff Garzik
9415b2fc499SJeff Garzik if ((result = kaweth_download_firmware(kaweth,
94279682499SDavid Woodhouse "kaweth/new_code_fix.bin",
9435b2fc499SJeff Garzik 100,
9445b2fc499SJeff Garzik 3)) < 0) {
94549ae25b0SGreg Kroah-Hartman dev_err(dev, "Error downloading firmware fix (%d)\n",
946db6b2219SGreg Kroah-Hartman result);
9475b2fc499SJeff Garzik goto err_fw;
9485b2fc499SJeff Garzik }
9495b2fc499SJeff Garzik
9505b2fc499SJeff Garzik if ((result = kaweth_download_firmware(kaweth,
95179682499SDavid Woodhouse "kaweth/trigger_code.bin",
9525b2fc499SJeff Garzik 126,
9535b2fc499SJeff Garzik 2)) < 0) {
95449ae25b0SGreg Kroah-Hartman dev_err(dev, "Error downloading trigger code (%d)\n",
955db6b2219SGreg Kroah-Hartman result);
9565b2fc499SJeff Garzik goto err_fw;
9575b2fc499SJeff Garzik
9585b2fc499SJeff Garzik }
9595b2fc499SJeff Garzik
9605b2fc499SJeff Garzik if ((result = kaweth_download_firmware(kaweth,
96179682499SDavid Woodhouse "kaweth/trigger_code_fix.bin",
9625b2fc499SJeff Garzik 126,
9635b2fc499SJeff Garzik 3)) < 0) {
96449ae25b0SGreg Kroah-Hartman dev_err(dev, "Error downloading trigger code fix (%d)\n", result);
9655b2fc499SJeff Garzik goto err_fw;
9665b2fc499SJeff Garzik }
9675b2fc499SJeff Garzik
9685b2fc499SJeff Garzik
9695b2fc499SJeff Garzik if ((result = kaweth_trigger_firmware(kaweth, 126)) < 0) {
97049ae25b0SGreg Kroah-Hartman dev_err(dev, "Error triggering firmware (%d)\n", result);
9715b2fc499SJeff Garzik goto err_fw;
9725b2fc499SJeff Garzik }
9735b2fc499SJeff Garzik
9745b2fc499SJeff Garzik /* Device will now disappear for a moment... */
97549ae25b0SGreg Kroah-Hartman dev_info(dev, "Firmware loaded. I'll be back...\n");
9765b2fc499SJeff Garzik err_fw:
9775b2fc499SJeff Garzik free_page((unsigned long)kaweth->firmware_buf);
9785b2fc499SJeff Garzik free_netdev(netdev);
9795b2fc499SJeff Garzik return -EIO;
9805b2fc499SJeff Garzik }
9815b2fc499SJeff Garzik
9825b2fc499SJeff Garzik result = kaweth_read_configuration(kaweth);
9835b2fc499SJeff Garzik
9845b2fc499SJeff Garzik if(result < 0) {
98549ae25b0SGreg Kroah-Hartman dev_err(dev, "Error reading configuration (%d), no net device created\n", result);
9865b2fc499SJeff Garzik goto err_free_netdev;
9875b2fc499SJeff Garzik }
9885b2fc499SJeff Garzik
98949ae25b0SGreg Kroah-Hartman dev_info(dev, "Statistics collection: %x\n", kaweth->configuration.statistics_mask);
99049ae25b0SGreg Kroah-Hartman dev_info(dev, "Multicast filter limit: %x\n", kaweth->configuration.max_multicast_filters & ((1 << 15) - 1));
99149ae25b0SGreg Kroah-Hartman dev_info(dev, "MTU: %d\n", le16_to_cpu(kaweth->configuration.segment_size));
99249ae25b0SGreg Kroah-Hartman dev_info(dev, "Read MAC address %pM\n", kaweth->configuration.hw_addr);
9935b2fc499SJeff Garzik
9945b2fc499SJeff Garzik if(!memcmp(&kaweth->configuration.hw_addr,
9955b2fc499SJeff Garzik &bcast_addr,
9965b2fc499SJeff Garzik sizeof(bcast_addr))) {
99749ae25b0SGreg Kroah-Hartman dev_err(dev, "Firmware not functioning properly, no net device created\n");
9985b2fc499SJeff Garzik goto err_free_netdev;
9995b2fc499SJeff Garzik }
10005b2fc499SJeff Garzik
10015b2fc499SJeff Garzik if(kaweth_set_urb_size(kaweth, KAWETH_BUF_SIZE) < 0) {
100249ae25b0SGreg Kroah-Hartman dev_dbg(dev, "Error setting URB size\n");
10035b2fc499SJeff Garzik goto err_free_netdev;
10045b2fc499SJeff Garzik }
10055b2fc499SJeff Garzik
10065b2fc499SJeff Garzik if(kaweth_set_sofs_wait(kaweth, KAWETH_SOFS_TO_WAIT) < 0) {
100749ae25b0SGreg Kroah-Hartman dev_err(dev, "Error setting SOFS wait\n");
10085b2fc499SJeff Garzik goto err_free_netdev;
10095b2fc499SJeff Garzik }
10105b2fc499SJeff Garzik
10115b2fc499SJeff Garzik result = kaweth_set_receive_filter(kaweth,
10125b2fc499SJeff Garzik KAWETH_PACKET_FILTER_DIRECTED |
10135b2fc499SJeff Garzik KAWETH_PACKET_FILTER_BROADCAST |
10145b2fc499SJeff Garzik KAWETH_PACKET_FILTER_MULTICAST);
10155b2fc499SJeff Garzik
10165b2fc499SJeff Garzik if(result < 0) {
101749ae25b0SGreg Kroah-Hartman dev_err(dev, "Error setting receive filter\n");
10185b2fc499SJeff Garzik goto err_free_netdev;
10195b2fc499SJeff Garzik }
10205b2fc499SJeff Garzik
102149ae25b0SGreg Kroah-Hartman dev_dbg(dev, "Initializing net device.\n");
10225b2fc499SJeff Garzik
10235b2fc499SJeff Garzik kaweth->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
10245b2fc499SJeff Garzik if (!kaweth->tx_urb)
10255b2fc499SJeff Garzik goto err_free_netdev;
10265b2fc499SJeff Garzik kaweth->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
10275b2fc499SJeff Garzik if (!kaweth->rx_urb)
10285b2fc499SJeff Garzik goto err_only_tx;
10295b2fc499SJeff Garzik kaweth->irq_urb = usb_alloc_urb(0, GFP_KERNEL);
10305b2fc499SJeff Garzik if (!kaweth->irq_urb)
10315b2fc499SJeff Garzik goto err_tx_and_rx;
10325b2fc499SJeff Garzik
1033997ea58eSDaniel Mack kaweth->intbuffer = usb_alloc_coherent( kaweth->dev,
10345b2fc499SJeff Garzik INTBUFFERSIZE,
10355b2fc499SJeff Garzik GFP_KERNEL,
10365b2fc499SJeff Garzik &kaweth->intbufferhandle);
10375b2fc499SJeff Garzik if (!kaweth->intbuffer)
10385b2fc499SJeff Garzik goto err_tx_and_rx_and_irq;
1039997ea58eSDaniel Mack kaweth->rx_buf = usb_alloc_coherent( kaweth->dev,
10405b2fc499SJeff Garzik KAWETH_BUF_SIZE,
10415b2fc499SJeff Garzik GFP_KERNEL,
10425b2fc499SJeff Garzik &kaweth->rxbufferhandle);
10435b2fc499SJeff Garzik if (!kaweth->rx_buf)
10445b2fc499SJeff Garzik goto err_all_but_rxbuf;
10455b2fc499SJeff Garzik
10465b2fc499SJeff Garzik memcpy(netdev->broadcast, &bcast_addr, sizeof(bcast_addr));
1047*2674e7eaSJakub Kicinski eth_hw_addr_set(netdev, (u8 *)&kaweth->configuration.hw_addr);
10485b2fc499SJeff Garzik
1049321ea8b2SOliver Neukum netdev->netdev_ops = &kaweth_netdev_ops;
10505b2fc499SJeff Garzik netdev->watchdog_timeo = KAWETH_TX_TIMEOUT;
10515b2fc499SJeff Garzik netdev->mtu = le16_to_cpu(kaweth->configuration.segment_size);
10527ad24ea4SWilfried Klaebe netdev->ethtool_ops = &ops;
10535b2fc499SJeff Garzik
10545b2fc499SJeff Garzik /* kaweth is zeroed as part of alloc_netdev */
10555b2fc499SJeff Garzik INIT_DELAYED_WORK(&kaweth->lowmem_work, kaweth_resubmit_tl);
10565b2fc499SJeff Garzik usb_set_intfdata(intf, kaweth);
10575b2fc499SJeff Garzik
105849ae25b0SGreg Kroah-Hartman SET_NETDEV_DEV(netdev, dev);
10595b2fc499SJeff Garzik if (register_netdev(netdev) != 0) {
106049ae25b0SGreg Kroah-Hartman dev_err(dev, "Error registering netdev.\n");
10615b2fc499SJeff Garzik goto err_intfdata;
10625b2fc499SJeff Garzik }
10635b2fc499SJeff Garzik
106449ae25b0SGreg Kroah-Hartman dev_info(dev, "kaweth interface created at %s\n",
1065880c9c66SGreg Kroah-Hartman kaweth->net->name);
10665b2fc499SJeff Garzik
10675b2fc499SJeff Garzik return 0;
10685b2fc499SJeff Garzik
10695b2fc499SJeff Garzik err_intfdata:
10705b2fc499SJeff Garzik usb_set_intfdata(intf, NULL);
1071997ea58eSDaniel Mack usb_free_coherent(kaweth->dev, KAWETH_BUF_SIZE, (void *)kaweth->rx_buf, kaweth->rxbufferhandle);
10725b2fc499SJeff Garzik err_all_but_rxbuf:
1073997ea58eSDaniel Mack usb_free_coherent(kaweth->dev, INTBUFFERSIZE, (void *)kaweth->intbuffer, kaweth->intbufferhandle);
10745b2fc499SJeff Garzik err_tx_and_rx_and_irq:
10755b2fc499SJeff Garzik usb_free_urb(kaweth->irq_urb);
10765b2fc499SJeff Garzik err_tx_and_rx:
10775b2fc499SJeff Garzik usb_free_urb(kaweth->rx_urb);
10785b2fc499SJeff Garzik err_only_tx:
10795b2fc499SJeff Garzik usb_free_urb(kaweth->tx_urb);
10805b2fc499SJeff Garzik err_free_netdev:
10815b2fc499SJeff Garzik free_netdev(netdev);
10825b2fc499SJeff Garzik
1083575ced7fSOliver Neukum return rv;
10845b2fc499SJeff Garzik }
10855b2fc499SJeff Garzik
10865b2fc499SJeff Garzik /****************************************************************
10875b2fc499SJeff Garzik * kaweth_disconnect
10885b2fc499SJeff Garzik ****************************************************************/
kaweth_disconnect(struct usb_interface * intf)10895b2fc499SJeff Garzik static void kaweth_disconnect(struct usb_interface *intf)
10905b2fc499SJeff Garzik {
10915b2fc499SJeff Garzik struct kaweth_device *kaweth = usb_get_intfdata(intf);
10925b2fc499SJeff Garzik struct net_device *netdev;
10935b2fc499SJeff Garzik
10945b2fc499SJeff Garzik usb_set_intfdata(intf, NULL);
10955b2fc499SJeff Garzik if (!kaweth) {
109625985edcSLucas De Marchi dev_warn(&intf->dev, "unregistering non-existent device\n");
10975b2fc499SJeff Garzik return;
10985b2fc499SJeff Garzik }
10995b2fc499SJeff Garzik netdev = kaweth->net;
11005b2fc499SJeff Garzik
110149ae25b0SGreg Kroah-Hartman netdev_dbg(kaweth->net, "Unregistering net device\n");
11025b2fc499SJeff Garzik unregister_netdev(netdev);
11035b2fc499SJeff Garzik
11045b2fc499SJeff Garzik usb_free_urb(kaweth->rx_urb);
11055b2fc499SJeff Garzik usb_free_urb(kaweth->tx_urb);
11065b2fc499SJeff Garzik usb_free_urb(kaweth->irq_urb);
11075b2fc499SJeff Garzik
1108997ea58eSDaniel Mack usb_free_coherent(kaweth->dev, KAWETH_BUF_SIZE, (void *)kaweth->rx_buf, kaweth->rxbufferhandle);
1109997ea58eSDaniel Mack usb_free_coherent(kaweth->dev, INTBUFFERSIZE, (void *)kaweth->intbuffer, kaweth->intbufferhandle);
11105b2fc499SJeff Garzik
11115b2fc499SJeff Garzik free_netdev(netdev);
11125b2fc499SJeff Garzik }
11135b2fc499SJeff Garzik
11145b2fc499SJeff Garzik
1115d632eb1bSGreg Kroah-Hartman module_usb_driver(kaweth_driver);
1116