15b2fc499SJeff Garzik /**************************************************************** 25b2fc499SJeff Garzik * 35b2fc499SJeff Garzik * kaweth.c - driver for KL5KUSB101 based USB->Ethernet 45b2fc499SJeff Garzik * 55b2fc499SJeff Garzik * (c) 2000 Interlan Communications 65b2fc499SJeff Garzik * (c) 2000 Stephane Alnet 75b2fc499SJeff Garzik * (C) 2001 Brad Hards 85b2fc499SJeff Garzik * (C) 2002 Oliver Neukum 95b2fc499SJeff Garzik * 105b2fc499SJeff Garzik * Original author: The Zapman <zapman@interlan.net> 115b2fc499SJeff Garzik * Inspired by, and much credit goes to Michael Rothwell 125b2fc499SJeff Garzik * <rothwell@interlan.net> for the test equipment, help, and patience 135b2fc499SJeff Garzik * Based off of (and with thanks to) Petko Manolov's pegaus.c driver. 145b2fc499SJeff Garzik * Also many thanks to Joel Silverman and Ed Surprenant at Kawasaki 155b2fc499SJeff Garzik * for providing the firmware and driver resources. 165b2fc499SJeff Garzik * 175b2fc499SJeff Garzik * This program is free software; you can redistribute it and/or 185b2fc499SJeff Garzik * modify it under the terms of the GNU General Public License as 195b2fc499SJeff Garzik * published by the Free Software Foundation; either version 2, or 205b2fc499SJeff Garzik * (at your option) any later version. 215b2fc499SJeff Garzik * 225b2fc499SJeff Garzik * This program is distributed in the hope that it will be useful, 235b2fc499SJeff Garzik * but WITHOUT ANY WARRANTY; without even the implied warranty of 245b2fc499SJeff Garzik * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 255b2fc499SJeff Garzik * GNU General Public License for more details. 265b2fc499SJeff Garzik * 275b2fc499SJeff Garzik * You should have received a copy of the GNU General Public License 285b2fc499SJeff Garzik * along with this program; if not, write to the Free Software Foundation, 295b2fc499SJeff Garzik * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 305b2fc499SJeff Garzik * 315b2fc499SJeff Garzik ****************************************************************/ 325b2fc499SJeff Garzik 335b2fc499SJeff Garzik /* TODO: 345b2fc499SJeff Garzik * Develop test procedures for USB net interfaces 355b2fc499SJeff Garzik * Run test procedures 365b2fc499SJeff Garzik * Fix bugs from previous two steps 375b2fc499SJeff Garzik * Snoop other OSs for any tricks we're not doing 385b2fc499SJeff Garzik * Reduce arbitrary timeouts 395b2fc499SJeff Garzik * Smart multicast support 405b2fc499SJeff Garzik * Temporary MAC change support 415b2fc499SJeff Garzik * Tunable SOFs parameter - ioctl()? 425b2fc499SJeff Garzik * Ethernet stats collection 435b2fc499SJeff Garzik * Code formatting improvements 445b2fc499SJeff Garzik */ 455b2fc499SJeff Garzik 465b2fc499SJeff Garzik #include <linux/module.h> 475b2fc499SJeff Garzik #include <linux/slab.h> 485b2fc499SJeff Garzik #include <linux/string.h> 495b2fc499SJeff Garzik #include <linux/init.h> 505b2fc499SJeff Garzik #include <linux/delay.h> 515b2fc499SJeff Garzik #include <linux/netdevice.h> 525b2fc499SJeff Garzik #include <linux/etherdevice.h> 535b2fc499SJeff Garzik #include <linux/usb.h> 545b2fc499SJeff Garzik #include <linux/types.h> 555b2fc499SJeff Garzik #include <linux/ethtool.h> 565b2fc499SJeff Garzik #include <linux/dma-mapping.h> 575b2fc499SJeff Garzik #include <linux/wait.h> 5879682499SDavid Woodhouse #include <linux/firmware.h> 595b2fc499SJeff Garzik #include <asm/uaccess.h> 605b2fc499SJeff Garzik #include <asm/byteorder.h> 615b2fc499SJeff Garzik 625b2fc499SJeff Garzik #undef DEBUG 635b2fc499SJeff Garzik 645b2fc499SJeff Garzik #define KAWETH_MTU 1514 655b2fc499SJeff Garzik #define KAWETH_BUF_SIZE 1664 665b2fc499SJeff Garzik #define KAWETH_TX_TIMEOUT (5 * HZ) 675b2fc499SJeff Garzik #define KAWETH_SCRATCH_SIZE 32 685b2fc499SJeff Garzik #define KAWETH_FIRMWARE_BUF_SIZE 4096 692b2b2e35SRuss Dill #define KAWETH_CONTROL_TIMEOUT (30000) 705b2fc499SJeff Garzik 715b2fc499SJeff Garzik #define KAWETH_STATUS_BROKEN 0x0000001 725b2fc499SJeff Garzik #define KAWETH_STATUS_CLOSING 0x0000002 735b2fc499SJeff Garzik #define KAWETH_STATUS_SUSPENDING 0x0000004 745b2fc499SJeff Garzik 755b2fc499SJeff Garzik #define KAWETH_STATUS_BLOCKED (KAWETH_STATUS_CLOSING | KAWETH_STATUS_SUSPENDING) 765b2fc499SJeff Garzik 775b2fc499SJeff Garzik #define KAWETH_PACKET_FILTER_PROMISCUOUS 0x01 785b2fc499SJeff Garzik #define KAWETH_PACKET_FILTER_ALL_MULTICAST 0x02 795b2fc499SJeff Garzik #define KAWETH_PACKET_FILTER_DIRECTED 0x04 805b2fc499SJeff Garzik #define KAWETH_PACKET_FILTER_BROADCAST 0x08 815b2fc499SJeff Garzik #define KAWETH_PACKET_FILTER_MULTICAST 0x10 825b2fc499SJeff Garzik 835b2fc499SJeff Garzik /* Table 7 */ 845b2fc499SJeff Garzik #define KAWETH_COMMAND_GET_ETHERNET_DESC 0x00 855b2fc499SJeff Garzik #define KAWETH_COMMAND_MULTICAST_FILTERS 0x01 865b2fc499SJeff Garzik #define KAWETH_COMMAND_SET_PACKET_FILTER 0x02 875b2fc499SJeff Garzik #define KAWETH_COMMAND_STATISTICS 0x03 885b2fc499SJeff Garzik #define KAWETH_COMMAND_SET_TEMP_MAC 0x06 895b2fc499SJeff Garzik #define KAWETH_COMMAND_GET_TEMP_MAC 0x07 905b2fc499SJeff Garzik #define KAWETH_COMMAND_SET_URB_SIZE 0x08 915b2fc499SJeff Garzik #define KAWETH_COMMAND_SET_SOFS_WAIT 0x09 925b2fc499SJeff Garzik #define KAWETH_COMMAND_SCAN 0xFF 935b2fc499SJeff Garzik 945b2fc499SJeff Garzik #define KAWETH_SOFS_TO_WAIT 0x05 955b2fc499SJeff Garzik 965b2fc499SJeff Garzik #define INTBUFFERSIZE 4 975b2fc499SJeff Garzik 985b2fc499SJeff Garzik #define STATE_OFFSET 0 995b2fc499SJeff Garzik #define STATE_MASK 0x40 1005b2fc499SJeff Garzik #define STATE_SHIFT 5 1015b2fc499SJeff Garzik 1025b2fc499SJeff Garzik #define IS_BLOCKED(s) (s & KAWETH_STATUS_BLOCKED) 1035b2fc499SJeff Garzik 1045b2fc499SJeff Garzik 1055b2fc499SJeff 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>"); 1065b2fc499SJeff Garzik MODULE_DESCRIPTION("KL5USB101 USB Ethernet driver"); 1075b2fc499SJeff Garzik MODULE_LICENSE("GPL"); 10879682499SDavid Woodhouse MODULE_FIRMWARE("kaweth/new_code.bin"); 10979682499SDavid Woodhouse MODULE_FIRMWARE("kaweth/new_code_fix.bin"); 11079682499SDavid Woodhouse MODULE_FIRMWARE("kaweth/trigger_code.bin"); 11179682499SDavid Woodhouse MODULE_FIRMWARE("kaweth/trigger_code_fix.bin"); 1125b2fc499SJeff Garzik 1135b2fc499SJeff Garzik static const char driver_name[] = "kaweth"; 1145b2fc499SJeff Garzik 1155b2fc499SJeff Garzik static int kaweth_probe( 1165b2fc499SJeff Garzik struct usb_interface *intf, 1175b2fc499SJeff Garzik const struct usb_device_id *id /* from id_table */ 1185b2fc499SJeff Garzik ); 1195b2fc499SJeff Garzik static void kaweth_disconnect(struct usb_interface *intf); 1205b2fc499SJeff Garzik static int kaweth_internal_control_msg(struct usb_device *usb_dev, 1215b2fc499SJeff Garzik unsigned int pipe, 1225b2fc499SJeff Garzik struct usb_ctrlrequest *cmd, void *data, 1235b2fc499SJeff Garzik int len, int timeout); 1245b2fc499SJeff Garzik static int kaweth_suspend(struct usb_interface *intf, pm_message_t message); 1255b2fc499SJeff Garzik static int kaweth_resume(struct usb_interface *intf); 1265b2fc499SJeff Garzik 1275b2fc499SJeff Garzik /**************************************************************** 1285b2fc499SJeff Garzik * usb_device_id 1295b2fc499SJeff Garzik ****************************************************************/ 1305b2fc499SJeff Garzik static struct usb_device_id usb_klsi_table[] = { 1315b2fc499SJeff Garzik { USB_DEVICE(0x03e8, 0x0008) }, /* AOX Endpoints USB Ethernet */ 1325b2fc499SJeff Garzik { USB_DEVICE(0x04bb, 0x0901) }, /* I-O DATA USB-ET/T */ 1335b2fc499SJeff Garzik { USB_DEVICE(0x0506, 0x03e8) }, /* 3Com 3C19250 */ 1345b2fc499SJeff Garzik { USB_DEVICE(0x0506, 0x11f8) }, /* 3Com 3C460 */ 1355b2fc499SJeff Garzik { USB_DEVICE(0x0557, 0x2002) }, /* ATEN USB Ethernet */ 1365b2fc499SJeff Garzik { USB_DEVICE(0x0557, 0x4000) }, /* D-Link DSB-650C */ 1375b2fc499SJeff Garzik { USB_DEVICE(0x0565, 0x0002) }, /* Peracom Enet */ 1385b2fc499SJeff Garzik { USB_DEVICE(0x0565, 0x0003) }, /* Optus@Home UEP1045A */ 1395b2fc499SJeff Garzik { USB_DEVICE(0x0565, 0x0005) }, /* Peracom Enet2 */ 1405b2fc499SJeff Garzik { USB_DEVICE(0x05e9, 0x0008) }, /* KLSI KL5KUSB101B */ 1415b2fc499SJeff Garzik { USB_DEVICE(0x05e9, 0x0009) }, /* KLSI KL5KUSB101B (Board change) */ 1425b2fc499SJeff Garzik { USB_DEVICE(0x066b, 0x2202) }, /* Linksys USB10T */ 1435b2fc499SJeff Garzik { USB_DEVICE(0x06e1, 0x0008) }, /* ADS USB-10BT */ 1445b2fc499SJeff Garzik { USB_DEVICE(0x06e1, 0x0009) }, /* ADS USB-10BT */ 1455b2fc499SJeff Garzik { USB_DEVICE(0x0707, 0x0100) }, /* SMC 2202USB */ 1465b2fc499SJeff Garzik { USB_DEVICE(0x07aa, 0x0001) }, /* Correga K.K. */ 1475b2fc499SJeff Garzik { USB_DEVICE(0x07b8, 0x4000) }, /* D-Link DU-E10 */ 1485b2fc499SJeff Garzik { USB_DEVICE(0x0846, 0x1001) }, /* NetGear EA-101 */ 1495b2fc499SJeff Garzik { USB_DEVICE(0x0846, 0x1002) }, /* NetGear EA-101 */ 1505b2fc499SJeff Garzik { USB_DEVICE(0x085a, 0x0008) }, /* PortGear Ethernet Adapter */ 1515b2fc499SJeff Garzik { USB_DEVICE(0x085a, 0x0009) }, /* PortGear Ethernet Adapter */ 1525b2fc499SJeff Garzik { USB_DEVICE(0x087d, 0x5704) }, /* Jaton USB Ethernet Device Adapter */ 1535b2fc499SJeff Garzik { USB_DEVICE(0x0951, 0x0008) }, /* Kingston Technology USB Ethernet Adapter */ 1545b2fc499SJeff Garzik { USB_DEVICE(0x095a, 0x3003) }, /* Portsmith Express Ethernet Adapter */ 1555b2fc499SJeff Garzik { USB_DEVICE(0x10bd, 0x1427) }, /* ASANTE USB To Ethernet Adapter */ 1565b2fc499SJeff Garzik { USB_DEVICE(0x1342, 0x0204) }, /* Mobility USB-Ethernet Adapter */ 1575b2fc499SJeff Garzik { USB_DEVICE(0x13d2, 0x0400) }, /* Shark Pocket Adapter */ 1585b2fc499SJeff Garzik { USB_DEVICE(0x1485, 0x0001) }, /* Silicom U2E */ 1595b2fc499SJeff Garzik { USB_DEVICE(0x1485, 0x0002) }, /* Psion Dacom Gold Port Ethernet */ 1605b2fc499SJeff Garzik { USB_DEVICE(0x1645, 0x0005) }, /* Entrega E45 */ 1615b2fc499SJeff Garzik { USB_DEVICE(0x1645, 0x0008) }, /* Entrega USB Ethernet Adapter */ 1625b2fc499SJeff Garzik { USB_DEVICE(0x1645, 0x8005) }, /* PortGear Ethernet Adapter */ 1635b2fc499SJeff Garzik { USB_DEVICE(0x1668, 0x0323) }, /* Actiontec USB Ethernet */ 1645b2fc499SJeff Garzik { USB_DEVICE(0x2001, 0x4000) }, /* D-link DSB-650C */ 1655b2fc499SJeff Garzik {} /* Null terminator */ 1665b2fc499SJeff Garzik }; 1675b2fc499SJeff Garzik 1685b2fc499SJeff Garzik MODULE_DEVICE_TABLE (usb, usb_klsi_table); 1695b2fc499SJeff Garzik 1705b2fc499SJeff Garzik /**************************************************************** 1715b2fc499SJeff Garzik * kaweth_driver 1725b2fc499SJeff Garzik ****************************************************************/ 1735b2fc499SJeff Garzik static struct usb_driver kaweth_driver = { 1745b2fc499SJeff Garzik .name = driver_name, 1755b2fc499SJeff Garzik .probe = kaweth_probe, 1765b2fc499SJeff Garzik .disconnect = kaweth_disconnect, 1775b2fc499SJeff Garzik .suspend = kaweth_suspend, 1785b2fc499SJeff Garzik .resume = kaweth_resume, 1795b2fc499SJeff Garzik .id_table = usb_klsi_table, 1805b2fc499SJeff Garzik .supports_autosuspend = 1, 1815b2fc499SJeff Garzik }; 1825b2fc499SJeff Garzik 1835b2fc499SJeff Garzik typedef __u8 eth_addr_t[6]; 1845b2fc499SJeff Garzik 1855b2fc499SJeff Garzik /**************************************************************** 1865b2fc499SJeff Garzik * usb_eth_dev 1875b2fc499SJeff Garzik ****************************************************************/ 1885b2fc499SJeff Garzik struct usb_eth_dev { 1895b2fc499SJeff Garzik char *name; 1905b2fc499SJeff Garzik __u16 vendor; 1915b2fc499SJeff Garzik __u16 device; 1925b2fc499SJeff Garzik void *pdata; 1935b2fc499SJeff Garzik }; 1945b2fc499SJeff Garzik 1955b2fc499SJeff Garzik /**************************************************************** 1965b2fc499SJeff Garzik * kaweth_ethernet_configuration 1975b2fc499SJeff Garzik * Refer Table 8 1985b2fc499SJeff Garzik ****************************************************************/ 1995b2fc499SJeff Garzik struct kaweth_ethernet_configuration 2005b2fc499SJeff Garzik { 2015b2fc499SJeff Garzik __u8 size; 2025b2fc499SJeff Garzik __u8 reserved1; 2035b2fc499SJeff Garzik __u8 reserved2; 2045b2fc499SJeff Garzik eth_addr_t hw_addr; 2055b2fc499SJeff Garzik __u32 statistics_mask; 2065b2fc499SJeff Garzik __le16 segment_size; 2075b2fc499SJeff Garzik __u16 max_multicast_filters; 2085b2fc499SJeff Garzik __u8 reserved3; 2095b2fc499SJeff Garzik } __attribute__ ((packed)); 2105b2fc499SJeff Garzik 2115b2fc499SJeff Garzik /**************************************************************** 2125b2fc499SJeff Garzik * kaweth_device 2135b2fc499SJeff Garzik ****************************************************************/ 2145b2fc499SJeff Garzik struct kaweth_device 2155b2fc499SJeff Garzik { 2165b2fc499SJeff Garzik spinlock_t device_lock; 2175b2fc499SJeff Garzik 2185b2fc499SJeff Garzik __u32 status; 2195b2fc499SJeff Garzik int end; 2205b2fc499SJeff Garzik int suspend_lowmem_rx; 2215b2fc499SJeff Garzik int suspend_lowmem_ctrl; 2225b2fc499SJeff Garzik int linkstate; 2235b2fc499SJeff Garzik int opened; 2245b2fc499SJeff Garzik struct delayed_work lowmem_work; 2255b2fc499SJeff Garzik 2265b2fc499SJeff Garzik struct usb_device *dev; 2275b2fc499SJeff Garzik struct usb_interface *intf; 2285b2fc499SJeff Garzik struct net_device *net; 2295b2fc499SJeff Garzik wait_queue_head_t term_wait; 2305b2fc499SJeff Garzik 2315b2fc499SJeff Garzik struct urb *rx_urb; 2325b2fc499SJeff Garzik struct urb *tx_urb; 2335b2fc499SJeff Garzik struct urb *irq_urb; 2345b2fc499SJeff Garzik 2355b2fc499SJeff Garzik dma_addr_t intbufferhandle; 2365b2fc499SJeff Garzik __u8 *intbuffer; 2375b2fc499SJeff Garzik dma_addr_t rxbufferhandle; 2385b2fc499SJeff Garzik __u8 *rx_buf; 2395b2fc499SJeff Garzik 2405b2fc499SJeff Garzik 2415b2fc499SJeff Garzik struct sk_buff *tx_skb; 2425b2fc499SJeff Garzik 2435b2fc499SJeff Garzik __u8 *firmware_buf; 2445b2fc499SJeff Garzik __u8 scratch[KAWETH_SCRATCH_SIZE]; 2455b2fc499SJeff Garzik __u16 packet_filter_bitmap; 2465b2fc499SJeff Garzik 2475b2fc499SJeff Garzik struct kaweth_ethernet_configuration configuration; 2485b2fc499SJeff Garzik 2495b2fc499SJeff Garzik struct net_device_stats stats; 2505b2fc499SJeff Garzik }; 2515b2fc499SJeff Garzik 2525b2fc499SJeff Garzik /**************************************************************** 2535b2fc499SJeff Garzik * kaweth_control 2545b2fc499SJeff Garzik ****************************************************************/ 2555b2fc499SJeff Garzik static int kaweth_control(struct kaweth_device *kaweth, 2565b2fc499SJeff Garzik unsigned int pipe, 2575b2fc499SJeff Garzik __u8 request, 2585b2fc499SJeff Garzik __u8 requesttype, 2595b2fc499SJeff Garzik __u16 value, 2605b2fc499SJeff Garzik __u16 index, 2615b2fc499SJeff Garzik void *data, 2625b2fc499SJeff Garzik __u16 size, 2635b2fc499SJeff Garzik int timeout) 2645b2fc499SJeff Garzik { 2655b2fc499SJeff Garzik struct usb_ctrlrequest *dr; 266*051b982bSKevin Cernekee int retval; 2675b2fc499SJeff Garzik 2685b2fc499SJeff Garzik dbg("kaweth_control()"); 2695b2fc499SJeff Garzik 2705b2fc499SJeff Garzik if(in_interrupt()) { 2715b2fc499SJeff Garzik dbg("in_interrupt()"); 2725b2fc499SJeff Garzik return -EBUSY; 2735b2fc499SJeff Garzik } 2745b2fc499SJeff Garzik 2755b2fc499SJeff Garzik dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC); 2765b2fc499SJeff Garzik 2775b2fc499SJeff Garzik if (!dr) { 2785b2fc499SJeff Garzik dbg("kmalloc() failed"); 2795b2fc499SJeff Garzik return -ENOMEM; 2805b2fc499SJeff Garzik } 2815b2fc499SJeff Garzik 2825b2fc499SJeff Garzik dr->bRequestType = requesttype; 2835b2fc499SJeff Garzik dr->bRequest = request; 284da2bbdccSHarvey Harrison dr->wValue = cpu_to_le16(value); 285da2bbdccSHarvey Harrison dr->wIndex = cpu_to_le16(index); 286da2bbdccSHarvey Harrison dr->wLength = cpu_to_le16(size); 2875b2fc499SJeff Garzik 288*051b982bSKevin Cernekee retval = kaweth_internal_control_msg(kaweth->dev, 2895b2fc499SJeff Garzik pipe, 2905b2fc499SJeff Garzik dr, 2915b2fc499SJeff Garzik data, 2925b2fc499SJeff Garzik size, 2935b2fc499SJeff Garzik timeout); 294*051b982bSKevin Cernekee 295*051b982bSKevin Cernekee kfree(dr); 296*051b982bSKevin Cernekee return retval; 2975b2fc499SJeff Garzik } 2985b2fc499SJeff Garzik 2995b2fc499SJeff Garzik /**************************************************************** 3005b2fc499SJeff Garzik * kaweth_read_configuration 3015b2fc499SJeff Garzik ****************************************************************/ 3025b2fc499SJeff Garzik static int kaweth_read_configuration(struct kaweth_device *kaweth) 3035b2fc499SJeff Garzik { 3045b2fc499SJeff Garzik int retval; 3055b2fc499SJeff Garzik 3065b2fc499SJeff Garzik dbg("Reading kaweth configuration"); 3075b2fc499SJeff Garzik 3085b2fc499SJeff Garzik retval = kaweth_control(kaweth, 3095b2fc499SJeff Garzik usb_rcvctrlpipe(kaweth->dev, 0), 3105b2fc499SJeff Garzik KAWETH_COMMAND_GET_ETHERNET_DESC, 3115b2fc499SJeff Garzik USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE, 3125b2fc499SJeff Garzik 0, 3135b2fc499SJeff Garzik 0, 3145b2fc499SJeff Garzik (void *)&kaweth->configuration, 3155b2fc499SJeff Garzik sizeof(kaweth->configuration), 3165b2fc499SJeff Garzik KAWETH_CONTROL_TIMEOUT); 3175b2fc499SJeff Garzik 3185b2fc499SJeff Garzik return retval; 3195b2fc499SJeff Garzik } 3205b2fc499SJeff Garzik 3215b2fc499SJeff Garzik /**************************************************************** 3225b2fc499SJeff Garzik * kaweth_set_urb_size 3235b2fc499SJeff Garzik ****************************************************************/ 3245b2fc499SJeff Garzik static int kaweth_set_urb_size(struct kaweth_device *kaweth, __u16 urb_size) 3255b2fc499SJeff Garzik { 3265b2fc499SJeff Garzik int retval; 3275b2fc499SJeff Garzik 3285b2fc499SJeff Garzik dbg("Setting URB size to %d", (unsigned)urb_size); 3295b2fc499SJeff Garzik 3305b2fc499SJeff Garzik retval = kaweth_control(kaweth, 3315b2fc499SJeff Garzik usb_sndctrlpipe(kaweth->dev, 0), 3325b2fc499SJeff Garzik KAWETH_COMMAND_SET_URB_SIZE, 3335b2fc499SJeff Garzik USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, 3345b2fc499SJeff Garzik urb_size, 3355b2fc499SJeff Garzik 0, 3365b2fc499SJeff Garzik (void *)&kaweth->scratch, 3375b2fc499SJeff Garzik 0, 3385b2fc499SJeff Garzik KAWETH_CONTROL_TIMEOUT); 3395b2fc499SJeff Garzik 3405b2fc499SJeff Garzik return retval; 3415b2fc499SJeff Garzik } 3425b2fc499SJeff Garzik 3435b2fc499SJeff Garzik /**************************************************************** 3445b2fc499SJeff Garzik * kaweth_set_sofs_wait 3455b2fc499SJeff Garzik ****************************************************************/ 3465b2fc499SJeff Garzik static int kaweth_set_sofs_wait(struct kaweth_device *kaweth, __u16 sofs_wait) 3475b2fc499SJeff Garzik { 3485b2fc499SJeff Garzik int retval; 3495b2fc499SJeff Garzik 3505b2fc499SJeff Garzik dbg("Set SOFS wait to %d", (unsigned)sofs_wait); 3515b2fc499SJeff Garzik 3525b2fc499SJeff Garzik retval = kaweth_control(kaweth, 3535b2fc499SJeff Garzik usb_sndctrlpipe(kaweth->dev, 0), 3545b2fc499SJeff Garzik KAWETH_COMMAND_SET_SOFS_WAIT, 3555b2fc499SJeff Garzik USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, 3565b2fc499SJeff Garzik sofs_wait, 3575b2fc499SJeff Garzik 0, 3585b2fc499SJeff Garzik (void *)&kaweth->scratch, 3595b2fc499SJeff Garzik 0, 3605b2fc499SJeff Garzik KAWETH_CONTROL_TIMEOUT); 3615b2fc499SJeff Garzik 3625b2fc499SJeff Garzik return retval; 3635b2fc499SJeff Garzik } 3645b2fc499SJeff Garzik 3655b2fc499SJeff Garzik /**************************************************************** 3665b2fc499SJeff Garzik * kaweth_set_receive_filter 3675b2fc499SJeff Garzik ****************************************************************/ 3685b2fc499SJeff Garzik static int kaweth_set_receive_filter(struct kaweth_device *kaweth, 3695b2fc499SJeff Garzik __u16 receive_filter) 3705b2fc499SJeff Garzik { 3715b2fc499SJeff Garzik int retval; 3725b2fc499SJeff Garzik 3735b2fc499SJeff Garzik dbg("Set receive filter to %d", (unsigned)receive_filter); 3745b2fc499SJeff Garzik 3755b2fc499SJeff Garzik retval = kaweth_control(kaweth, 3765b2fc499SJeff Garzik usb_sndctrlpipe(kaweth->dev, 0), 3775b2fc499SJeff Garzik KAWETH_COMMAND_SET_PACKET_FILTER, 3785b2fc499SJeff Garzik USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, 3795b2fc499SJeff Garzik receive_filter, 3805b2fc499SJeff Garzik 0, 3815b2fc499SJeff Garzik (void *)&kaweth->scratch, 3825b2fc499SJeff Garzik 0, 3835b2fc499SJeff Garzik KAWETH_CONTROL_TIMEOUT); 3845b2fc499SJeff Garzik 3855b2fc499SJeff Garzik return retval; 3865b2fc499SJeff Garzik } 3875b2fc499SJeff Garzik 3885b2fc499SJeff Garzik /**************************************************************** 3895b2fc499SJeff Garzik * kaweth_download_firmware 3905b2fc499SJeff Garzik ****************************************************************/ 3915b2fc499SJeff Garzik static int kaweth_download_firmware(struct kaweth_device *kaweth, 39279682499SDavid Woodhouse const char *fwname, 3935b2fc499SJeff Garzik __u8 interrupt, 3945b2fc499SJeff Garzik __u8 type) 3955b2fc499SJeff Garzik { 39679682499SDavid Woodhouse const struct firmware *fw; 39779682499SDavid Woodhouse int data_len; 39879682499SDavid Woodhouse int ret; 39979682499SDavid Woodhouse 40079682499SDavid Woodhouse ret = request_firmware(&fw, fwname, &kaweth->dev->dev); 40179682499SDavid Woodhouse if (ret) { 40279682499SDavid Woodhouse err("Firmware request failed\n"); 40379682499SDavid Woodhouse return ret; 4045b2fc499SJeff Garzik } 4055b2fc499SJeff Garzik 40679682499SDavid Woodhouse if (fw->size > KAWETH_FIRMWARE_BUF_SIZE) { 40779682499SDavid Woodhouse err("Firmware too big: %zu", fw->size); 40879682499SDavid Woodhouse return -ENOSPC; 40979682499SDavid Woodhouse } 41079682499SDavid Woodhouse data_len = fw->size; 41179682499SDavid Woodhouse memcpy(kaweth->firmware_buf, fw->data, fw->size); 41279682499SDavid Woodhouse 41379682499SDavid Woodhouse release_firmware(fw); 4145b2fc499SJeff Garzik 4155b2fc499SJeff Garzik kaweth->firmware_buf[2] = (data_len & 0xFF) - 7; 4165b2fc499SJeff Garzik kaweth->firmware_buf[3] = data_len >> 8; 4175b2fc499SJeff Garzik kaweth->firmware_buf[4] = type; 4185b2fc499SJeff Garzik kaweth->firmware_buf[5] = interrupt; 4195b2fc499SJeff Garzik 4205b2fc499SJeff Garzik dbg("High: %i, Low:%i", kaweth->firmware_buf[3], 4215b2fc499SJeff Garzik kaweth->firmware_buf[2]); 4225b2fc499SJeff Garzik 4235b2fc499SJeff Garzik dbg("Downloading firmware at %p to kaweth device at %p", 42479682499SDavid Woodhouse fw->data, kaweth); 4255b2fc499SJeff Garzik dbg("Firmware length: %d", data_len); 4265b2fc499SJeff Garzik 4275b2fc499SJeff Garzik return kaweth_control(kaweth, 4285b2fc499SJeff Garzik usb_sndctrlpipe(kaweth->dev, 0), 4295b2fc499SJeff Garzik KAWETH_COMMAND_SCAN, 4305b2fc499SJeff Garzik USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, 4315b2fc499SJeff Garzik 0, 4325b2fc499SJeff Garzik 0, 4335b2fc499SJeff Garzik (void *)kaweth->firmware_buf, 4345b2fc499SJeff Garzik data_len, 4355b2fc499SJeff Garzik KAWETH_CONTROL_TIMEOUT); 4365b2fc499SJeff Garzik } 4375b2fc499SJeff Garzik 4385b2fc499SJeff Garzik /**************************************************************** 4395b2fc499SJeff Garzik * kaweth_trigger_firmware 4405b2fc499SJeff Garzik ****************************************************************/ 4415b2fc499SJeff Garzik static int kaweth_trigger_firmware(struct kaweth_device *kaweth, 4425b2fc499SJeff Garzik __u8 interrupt) 4435b2fc499SJeff Garzik { 4445b2fc499SJeff Garzik kaweth->firmware_buf[0] = 0xB6; 4455b2fc499SJeff Garzik kaweth->firmware_buf[1] = 0xC3; 4465b2fc499SJeff Garzik kaweth->firmware_buf[2] = 0x01; 4475b2fc499SJeff Garzik kaweth->firmware_buf[3] = 0x00; 4485b2fc499SJeff Garzik kaweth->firmware_buf[4] = 0x06; 4495b2fc499SJeff Garzik kaweth->firmware_buf[5] = interrupt; 4505b2fc499SJeff Garzik kaweth->firmware_buf[6] = 0x00; 4515b2fc499SJeff Garzik kaweth->firmware_buf[7] = 0x00; 4525b2fc499SJeff Garzik 4535b2fc499SJeff Garzik dbg("Triggering firmware"); 4545b2fc499SJeff Garzik 4555b2fc499SJeff Garzik return kaweth_control(kaweth, 4565b2fc499SJeff Garzik usb_sndctrlpipe(kaweth->dev, 0), 4575b2fc499SJeff Garzik KAWETH_COMMAND_SCAN, 4585b2fc499SJeff Garzik USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, 4595b2fc499SJeff Garzik 0, 4605b2fc499SJeff Garzik 0, 4615b2fc499SJeff Garzik (void *)kaweth->firmware_buf, 4625b2fc499SJeff Garzik 8, 4635b2fc499SJeff Garzik KAWETH_CONTROL_TIMEOUT); 4645b2fc499SJeff Garzik } 4655b2fc499SJeff Garzik 4665b2fc499SJeff Garzik /**************************************************************** 4675b2fc499SJeff Garzik * kaweth_reset 4685b2fc499SJeff Garzik ****************************************************************/ 4695b2fc499SJeff Garzik static int kaweth_reset(struct kaweth_device *kaweth) 4705b2fc499SJeff Garzik { 4715b2fc499SJeff Garzik int result; 4725b2fc499SJeff Garzik 4735b2fc499SJeff Garzik dbg("kaweth_reset(%p)", kaweth); 4745b2fc499SJeff Garzik result = kaweth_control(kaweth, 4755b2fc499SJeff Garzik usb_sndctrlpipe(kaweth->dev, 0), 4765b2fc499SJeff Garzik USB_REQ_SET_CONFIGURATION, 4775b2fc499SJeff Garzik 0, 4785b2fc499SJeff Garzik kaweth->dev->config[0].desc.bConfigurationValue, 4795b2fc499SJeff Garzik 0, 4805b2fc499SJeff Garzik NULL, 4815b2fc499SJeff Garzik 0, 4825b2fc499SJeff Garzik KAWETH_CONTROL_TIMEOUT); 4835b2fc499SJeff Garzik 4845b2fc499SJeff Garzik mdelay(10); 4855b2fc499SJeff Garzik 4865b2fc499SJeff Garzik dbg("kaweth_reset() returns %d.",result); 4875b2fc499SJeff Garzik 4885b2fc499SJeff Garzik return result; 4895b2fc499SJeff Garzik } 4905b2fc499SJeff Garzik 4915b2fc499SJeff Garzik static void kaweth_usb_receive(struct urb *); 4925b2fc499SJeff Garzik static int kaweth_resubmit_rx_urb(struct kaweth_device *, gfp_t); 4935b2fc499SJeff Garzik 4945b2fc499SJeff Garzik /**************************************************************** 4955b2fc499SJeff Garzik int_callback 4965b2fc499SJeff Garzik *****************************************************************/ 4975b2fc499SJeff Garzik 4985b2fc499SJeff Garzik static void kaweth_resubmit_int_urb(struct kaweth_device *kaweth, gfp_t mf) 4995b2fc499SJeff Garzik { 5005b2fc499SJeff Garzik int status; 5015b2fc499SJeff Garzik 5025b2fc499SJeff Garzik status = usb_submit_urb (kaweth->irq_urb, mf); 5035b2fc499SJeff Garzik if (unlikely(status == -ENOMEM)) { 5045b2fc499SJeff Garzik kaweth->suspend_lowmem_ctrl = 1; 5055b2fc499SJeff Garzik schedule_delayed_work(&kaweth->lowmem_work, HZ/4); 5065b2fc499SJeff Garzik } else { 5075b2fc499SJeff Garzik kaweth->suspend_lowmem_ctrl = 0; 5085b2fc499SJeff Garzik } 5095b2fc499SJeff Garzik 5105b2fc499SJeff Garzik if (status) 5115b2fc499SJeff Garzik err ("can't resubmit intr, %s-%s, status %d", 5125b2fc499SJeff Garzik kaweth->dev->bus->bus_name, 5135b2fc499SJeff Garzik kaweth->dev->devpath, status); 5145b2fc499SJeff Garzik } 5155b2fc499SJeff Garzik 5165b2fc499SJeff Garzik static void int_callback(struct urb *u) 5175b2fc499SJeff Garzik { 5185b2fc499SJeff Garzik struct kaweth_device *kaweth = u->context; 5195b2fc499SJeff Garzik int act_state; 520c94cb314SOliver Neukum int status = u->status; 5215b2fc499SJeff Garzik 522c94cb314SOliver Neukum switch (status) { 5235b2fc499SJeff Garzik case 0: /* success */ 5245b2fc499SJeff Garzik break; 5255b2fc499SJeff Garzik case -ECONNRESET: /* unlink */ 5265b2fc499SJeff Garzik case -ENOENT: 5275b2fc499SJeff Garzik case -ESHUTDOWN: 5285b2fc499SJeff Garzik return; 5295b2fc499SJeff Garzik /* -EPIPE: should clear the halt */ 5305b2fc499SJeff Garzik default: /* error */ 5315b2fc499SJeff Garzik goto resubmit; 5325b2fc499SJeff Garzik } 5335b2fc499SJeff Garzik 5345b2fc499SJeff Garzik /* we check the link state to report changes */ 5355b2fc499SJeff Garzik if (kaweth->linkstate != (act_state = ( kaweth->intbuffer[STATE_OFFSET] | STATE_MASK) >> STATE_SHIFT)) { 5365b2fc499SJeff Garzik if (act_state) 5375b2fc499SJeff Garzik netif_carrier_on(kaweth->net); 5385b2fc499SJeff Garzik else 5395b2fc499SJeff Garzik netif_carrier_off(kaweth->net); 5405b2fc499SJeff Garzik 5415b2fc499SJeff Garzik kaweth->linkstate = act_state; 5425b2fc499SJeff Garzik } 5435b2fc499SJeff Garzik resubmit: 5445b2fc499SJeff Garzik kaweth_resubmit_int_urb(kaweth, GFP_ATOMIC); 5455b2fc499SJeff Garzik } 5465b2fc499SJeff Garzik 5475b2fc499SJeff Garzik static void kaweth_resubmit_tl(struct work_struct *work) 5485b2fc499SJeff Garzik { 5495b2fc499SJeff Garzik struct kaweth_device *kaweth = 5505b2fc499SJeff Garzik container_of(work, struct kaweth_device, lowmem_work.work); 5515b2fc499SJeff Garzik 5525b2fc499SJeff Garzik if (IS_BLOCKED(kaweth->status)) 5535b2fc499SJeff Garzik return; 5545b2fc499SJeff Garzik 5555b2fc499SJeff Garzik if (kaweth->suspend_lowmem_rx) 5565b2fc499SJeff Garzik kaweth_resubmit_rx_urb(kaweth, GFP_NOIO); 5575b2fc499SJeff Garzik 5585b2fc499SJeff Garzik if (kaweth->suspend_lowmem_ctrl) 5595b2fc499SJeff Garzik kaweth_resubmit_int_urb(kaweth, GFP_NOIO); 5605b2fc499SJeff Garzik } 5615b2fc499SJeff Garzik 5625b2fc499SJeff Garzik 5635b2fc499SJeff Garzik /**************************************************************** 5645b2fc499SJeff Garzik * kaweth_resubmit_rx_urb 5655b2fc499SJeff Garzik ****************************************************************/ 5665b2fc499SJeff Garzik static int kaweth_resubmit_rx_urb(struct kaweth_device *kaweth, 5675b2fc499SJeff Garzik gfp_t mem_flags) 5685b2fc499SJeff Garzik { 5695b2fc499SJeff Garzik int result; 5705b2fc499SJeff Garzik 5715b2fc499SJeff Garzik usb_fill_bulk_urb(kaweth->rx_urb, 5725b2fc499SJeff Garzik kaweth->dev, 5735b2fc499SJeff Garzik usb_rcvbulkpipe(kaweth->dev, 1), 5745b2fc499SJeff Garzik kaweth->rx_buf, 5755b2fc499SJeff Garzik KAWETH_BUF_SIZE, 5765b2fc499SJeff Garzik kaweth_usb_receive, 5775b2fc499SJeff Garzik kaweth); 5785b2fc499SJeff Garzik kaweth->rx_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 5795b2fc499SJeff Garzik kaweth->rx_urb->transfer_dma = kaweth->rxbufferhandle; 5805b2fc499SJeff Garzik 5815b2fc499SJeff Garzik if((result = usb_submit_urb(kaweth->rx_urb, mem_flags))) { 5825b2fc499SJeff Garzik if (result == -ENOMEM) { 5835b2fc499SJeff Garzik kaweth->suspend_lowmem_rx = 1; 5845b2fc499SJeff Garzik schedule_delayed_work(&kaweth->lowmem_work, HZ/4); 5855b2fc499SJeff Garzik } 5865b2fc499SJeff Garzik err("resubmitting rx_urb %d failed", result); 5875b2fc499SJeff Garzik } else { 5885b2fc499SJeff Garzik kaweth->suspend_lowmem_rx = 0; 5895b2fc499SJeff Garzik } 5905b2fc499SJeff Garzik 5915b2fc499SJeff Garzik return result; 5925b2fc499SJeff Garzik } 5935b2fc499SJeff Garzik 5945b2fc499SJeff Garzik static void kaweth_async_set_rx_mode(struct kaweth_device *kaweth); 5955b2fc499SJeff Garzik 5965b2fc499SJeff Garzik /**************************************************************** 5975b2fc499SJeff Garzik * kaweth_usb_receive 5985b2fc499SJeff Garzik ****************************************************************/ 5995b2fc499SJeff Garzik static void kaweth_usb_receive(struct urb *urb) 6005b2fc499SJeff Garzik { 6015b2fc499SJeff Garzik struct kaweth_device *kaweth = urb->context; 6025b2fc499SJeff Garzik struct net_device *net = kaweth->net; 603c94cb314SOliver Neukum int status = urb->status; 6045b2fc499SJeff Garzik 6055b2fc499SJeff Garzik int count = urb->actual_length; 6065b2fc499SJeff Garzik int count2 = urb->transfer_buffer_length; 6075b2fc499SJeff Garzik 6085b2fc499SJeff Garzik __u16 pkt_len = le16_to_cpup((__le16 *)kaweth->rx_buf); 6095b2fc499SJeff Garzik 6105b2fc499SJeff Garzik struct sk_buff *skb; 6115b2fc499SJeff Garzik 612710b523aSLarry Finger if (unlikely(status == -EPIPE)) { 613710b523aSLarry Finger kaweth->stats.rx_errors++; 6145b2fc499SJeff Garzik kaweth->end = 1; 6155b2fc499SJeff Garzik wake_up(&kaweth->term_wait); 616710b523aSLarry Finger dbg("Status was -EPIPE."); 6175b2fc499SJeff Garzik return; 6185b2fc499SJeff Garzik } 619710b523aSLarry Finger if (unlikely(status == -ECONNRESET || status == -ESHUTDOWN)) { 620710b523aSLarry Finger /* we are killed - set a flag and wake the disconnect handler */ 621710b523aSLarry Finger kaweth->end = 1; 622710b523aSLarry Finger wake_up(&kaweth->term_wait); 623710b523aSLarry Finger dbg("Status was -ECONNRESET or -ESHUTDOWN."); 624710b523aSLarry Finger return; 625710b523aSLarry Finger } 626710b523aSLarry Finger if (unlikely(status == -EPROTO || status == -ETIME || 627710b523aSLarry Finger status == -EILSEQ)) { 628710b523aSLarry Finger kaweth->stats.rx_errors++; 629710b523aSLarry Finger dbg("Status was -EPROTO, -ETIME, or -EILSEQ."); 630710b523aSLarry Finger return; 631710b523aSLarry Finger } 632710b523aSLarry Finger if (unlikely(status == -EOVERFLOW)) { 633710b523aSLarry Finger kaweth->stats.rx_errors++; 634710b523aSLarry Finger dbg("Status was -EOVERFLOW."); 635710b523aSLarry Finger } 6365b2fc499SJeff Garzik spin_lock(&kaweth->device_lock); 6375b2fc499SJeff Garzik if (IS_BLOCKED(kaweth->status)) { 6385b2fc499SJeff Garzik spin_unlock(&kaweth->device_lock); 6395b2fc499SJeff Garzik return; 6405b2fc499SJeff Garzik } 6415b2fc499SJeff Garzik spin_unlock(&kaweth->device_lock); 6425b2fc499SJeff Garzik 643c94cb314SOliver Neukum if(status && status != -EREMOTEIO && count != 1) { 6445b2fc499SJeff Garzik err("%s RX status: %d count: %d packet_len: %d", 6455b2fc499SJeff Garzik net->name, 646c94cb314SOliver Neukum status, 6475b2fc499SJeff Garzik count, 6485b2fc499SJeff Garzik (int)pkt_len); 6495b2fc499SJeff Garzik kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC); 6505b2fc499SJeff Garzik return; 6515b2fc499SJeff Garzik } 6525b2fc499SJeff Garzik 6535b2fc499SJeff Garzik if(kaweth->net && (count > 2)) { 6545b2fc499SJeff Garzik if(pkt_len > (count - 2)) { 6555b2fc499SJeff Garzik err("Packet length too long for USB frame (pkt_len: %x, count: %x)",pkt_len, count); 6565b2fc499SJeff Garzik err("Packet len & 2047: %x", pkt_len & 2047); 6575b2fc499SJeff Garzik err("Count 2: %x", count2); 6585b2fc499SJeff Garzik kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC); 6595b2fc499SJeff Garzik return; 6605b2fc499SJeff Garzik } 6615b2fc499SJeff Garzik 6625b2fc499SJeff Garzik if(!(skb = dev_alloc_skb(pkt_len+2))) { 6635b2fc499SJeff Garzik kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC); 6645b2fc499SJeff Garzik return; 6655b2fc499SJeff Garzik } 6665b2fc499SJeff Garzik 6675b2fc499SJeff Garzik skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ 6685b2fc499SJeff Garzik 6698c7b7faaSDavid S. Miller skb_copy_to_linear_data(skb, kaweth->rx_buf + 2, pkt_len); 6705b2fc499SJeff Garzik 6715b2fc499SJeff Garzik skb_put(skb, pkt_len); 6725b2fc499SJeff Garzik 6735b2fc499SJeff Garzik skb->protocol = eth_type_trans(skb, net); 6745b2fc499SJeff Garzik 6755b2fc499SJeff Garzik netif_rx(skb); 6765b2fc499SJeff Garzik 6775b2fc499SJeff Garzik kaweth->stats.rx_packets++; 6785b2fc499SJeff Garzik kaweth->stats.rx_bytes += pkt_len; 6795b2fc499SJeff Garzik } 6805b2fc499SJeff Garzik 6815b2fc499SJeff Garzik kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC); 6825b2fc499SJeff Garzik } 6835b2fc499SJeff Garzik 6845b2fc499SJeff Garzik /**************************************************************** 6855b2fc499SJeff Garzik * kaweth_open 6865b2fc499SJeff Garzik ****************************************************************/ 6875b2fc499SJeff Garzik static int kaweth_open(struct net_device *net) 6885b2fc499SJeff Garzik { 6895b2fc499SJeff Garzik struct kaweth_device *kaweth = netdev_priv(net); 6905b2fc499SJeff Garzik int res; 6915b2fc499SJeff Garzik 6925b2fc499SJeff Garzik dbg("Opening network device."); 6935b2fc499SJeff Garzik 6945b2fc499SJeff Garzik res = usb_autopm_get_interface(kaweth->intf); 6955b2fc499SJeff Garzik if (res) { 6965b2fc499SJeff Garzik err("Interface cannot be resumed."); 6975b2fc499SJeff Garzik return -EIO; 6985b2fc499SJeff Garzik } 6995b2fc499SJeff Garzik res = kaweth_resubmit_rx_urb(kaweth, GFP_KERNEL); 7005b2fc499SJeff Garzik if (res) 7015b2fc499SJeff Garzik goto err_out; 7025b2fc499SJeff Garzik 7035b2fc499SJeff Garzik usb_fill_int_urb( 7045b2fc499SJeff Garzik kaweth->irq_urb, 7055b2fc499SJeff Garzik kaweth->dev, 7065b2fc499SJeff Garzik usb_rcvintpipe(kaweth->dev, 3), 7075b2fc499SJeff Garzik kaweth->intbuffer, 7085b2fc499SJeff Garzik INTBUFFERSIZE, 7095b2fc499SJeff Garzik int_callback, 7105b2fc499SJeff Garzik kaweth, 7115b2fc499SJeff Garzik 250); /* overriding the descriptor */ 7125b2fc499SJeff Garzik kaweth->irq_urb->transfer_dma = kaweth->intbufferhandle; 7135b2fc499SJeff Garzik kaweth->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 7145b2fc499SJeff Garzik 7155b2fc499SJeff Garzik res = usb_submit_urb(kaweth->irq_urb, GFP_KERNEL); 7165b2fc499SJeff Garzik if (res) { 7175b2fc499SJeff Garzik usb_kill_urb(kaweth->rx_urb); 7185b2fc499SJeff Garzik goto err_out; 7195b2fc499SJeff Garzik } 7205b2fc499SJeff Garzik kaweth->opened = 1; 7215b2fc499SJeff Garzik 7225b2fc499SJeff Garzik netif_start_queue(net); 7235b2fc499SJeff Garzik 7245b2fc499SJeff Garzik kaweth_async_set_rx_mode(kaweth); 7255b2fc499SJeff Garzik return 0; 7265b2fc499SJeff Garzik 7275b2fc499SJeff Garzik err_out: 7285b2fc499SJeff Garzik usb_autopm_enable(kaweth->intf); 7295b2fc499SJeff Garzik return -EIO; 7305b2fc499SJeff Garzik } 7315b2fc499SJeff Garzik 7325b2fc499SJeff Garzik /**************************************************************** 7335b2fc499SJeff Garzik * kaweth_kill_urbs 7345b2fc499SJeff Garzik ****************************************************************/ 7355b2fc499SJeff Garzik static void kaweth_kill_urbs(struct kaweth_device *kaweth) 7365b2fc499SJeff Garzik { 7375b2fc499SJeff Garzik usb_kill_urb(kaweth->irq_urb); 7385b2fc499SJeff Garzik usb_kill_urb(kaweth->rx_urb); 7395b2fc499SJeff Garzik usb_kill_urb(kaweth->tx_urb); 7405b2fc499SJeff Garzik 7414bb073c0SDavid S. Miller cancel_delayed_work_sync(&kaweth->lowmem_work); 7425b2fc499SJeff Garzik 7435b2fc499SJeff Garzik /* a scheduled work may have resubmitted, 7445b2fc499SJeff Garzik we hit them again */ 7455b2fc499SJeff Garzik usb_kill_urb(kaweth->irq_urb); 7465b2fc499SJeff Garzik usb_kill_urb(kaweth->rx_urb); 7475b2fc499SJeff Garzik } 7485b2fc499SJeff Garzik 7495b2fc499SJeff Garzik /**************************************************************** 7505b2fc499SJeff Garzik * kaweth_close 7515b2fc499SJeff Garzik ****************************************************************/ 7525b2fc499SJeff Garzik static int kaweth_close(struct net_device *net) 7535b2fc499SJeff Garzik { 7545b2fc499SJeff Garzik struct kaweth_device *kaweth = netdev_priv(net); 7555b2fc499SJeff Garzik 7565b2fc499SJeff Garzik netif_stop_queue(net); 7575b2fc499SJeff Garzik kaweth->opened = 0; 7585b2fc499SJeff Garzik 7595b2fc499SJeff Garzik kaweth->status |= KAWETH_STATUS_CLOSING; 7605b2fc499SJeff Garzik 7615b2fc499SJeff Garzik kaweth_kill_urbs(kaweth); 7625b2fc499SJeff Garzik 7635b2fc499SJeff Garzik kaweth->status &= ~KAWETH_STATUS_CLOSING; 7645b2fc499SJeff Garzik 7655b2fc499SJeff Garzik usb_autopm_enable(kaweth->intf); 7665b2fc499SJeff Garzik 7675b2fc499SJeff Garzik return 0; 7685b2fc499SJeff Garzik } 7695b2fc499SJeff Garzik 7705b2fc499SJeff Garzik static void kaweth_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) 7715b2fc499SJeff Garzik { 7725b2fc499SJeff Garzik struct kaweth_device *kaweth = netdev_priv(dev); 7735b2fc499SJeff Garzik 7745b2fc499SJeff Garzik strlcpy(info->driver, driver_name, sizeof(info->driver)); 7755b2fc499SJeff Garzik usb_make_path(kaweth->dev, info->bus_info, sizeof (info->bus_info)); 7765b2fc499SJeff Garzik } 7775b2fc499SJeff Garzik 7785b2fc499SJeff Garzik static u32 kaweth_get_link(struct net_device *dev) 7795b2fc499SJeff Garzik { 7805b2fc499SJeff Garzik struct kaweth_device *kaweth = netdev_priv(dev); 7815b2fc499SJeff Garzik 7825b2fc499SJeff Garzik return kaweth->linkstate; 7835b2fc499SJeff Garzik } 7845b2fc499SJeff Garzik 7850fc0b732SStephen Hemminger static const struct ethtool_ops ops = { 7865b2fc499SJeff Garzik .get_drvinfo = kaweth_get_drvinfo, 7875b2fc499SJeff Garzik .get_link = kaweth_get_link 7885b2fc499SJeff Garzik }; 7895b2fc499SJeff Garzik 7905b2fc499SJeff Garzik /**************************************************************** 7915b2fc499SJeff Garzik * kaweth_usb_transmit_complete 7925b2fc499SJeff Garzik ****************************************************************/ 7935b2fc499SJeff Garzik static void kaweth_usb_transmit_complete(struct urb *urb) 7945b2fc499SJeff Garzik { 7955b2fc499SJeff Garzik struct kaweth_device *kaweth = urb->context; 7965b2fc499SJeff Garzik struct sk_buff *skb = kaweth->tx_skb; 797c94cb314SOliver Neukum int status = urb->status; 7985b2fc499SJeff Garzik 799c94cb314SOliver Neukum if (unlikely(status != 0)) 800c94cb314SOliver Neukum if (status != -ENOENT) 801c94cb314SOliver Neukum dbg("%s: TX status %d.", kaweth->net->name, status); 8025b2fc499SJeff Garzik 8035b2fc499SJeff Garzik netif_wake_queue(kaweth->net); 8045b2fc499SJeff Garzik dev_kfree_skb_irq(skb); 8055b2fc499SJeff Garzik } 8065b2fc499SJeff Garzik 8075b2fc499SJeff Garzik /**************************************************************** 8085b2fc499SJeff Garzik * kaweth_start_xmit 8095b2fc499SJeff Garzik ****************************************************************/ 81025a79c41SStephen Hemminger static netdev_tx_t kaweth_start_xmit(struct sk_buff *skb, 81125a79c41SStephen Hemminger struct net_device *net) 8125b2fc499SJeff Garzik { 8135b2fc499SJeff Garzik struct kaweth_device *kaweth = netdev_priv(net); 8145b2fc499SJeff Garzik __le16 *private_header; 8155b2fc499SJeff Garzik 8165b2fc499SJeff Garzik int res; 8175b2fc499SJeff Garzik 8184ff61c8fSLarry Finger spin_lock_irq(&kaweth->device_lock); 8195b2fc499SJeff Garzik 8205b2fc499SJeff Garzik kaweth_async_set_rx_mode(kaweth); 8215b2fc499SJeff Garzik netif_stop_queue(net); 8225b2fc499SJeff Garzik if (IS_BLOCKED(kaweth->status)) { 8235b2fc499SJeff Garzik goto skip; 8245b2fc499SJeff Garzik } 8255b2fc499SJeff Garzik 8265b2fc499SJeff Garzik /* We now decide whether we can put our special header into the sk_buff */ 8275b2fc499SJeff Garzik if (skb_cloned(skb) || skb_headroom(skb) < 2) { 8285b2fc499SJeff Garzik /* no such luck - we make our own */ 8295b2fc499SJeff Garzik struct sk_buff *copied_skb; 8305b2fc499SJeff Garzik copied_skb = skb_copy_expand(skb, 2, 0, GFP_ATOMIC); 8315b2fc499SJeff Garzik dev_kfree_skb_irq(skb); 8325b2fc499SJeff Garzik skb = copied_skb; 8335b2fc499SJeff Garzik if (!copied_skb) { 8345b2fc499SJeff Garzik kaweth->stats.tx_errors++; 8355b2fc499SJeff Garzik netif_start_queue(net); 8364ff61c8fSLarry Finger spin_unlock_irq(&kaweth->device_lock); 8376ed10654SPatrick McHardy return NETDEV_TX_OK; 8385b2fc499SJeff Garzik } 8395b2fc499SJeff Garzik } 8405b2fc499SJeff Garzik 8415b2fc499SJeff Garzik private_header = (__le16 *)__skb_push(skb, 2); 8425b2fc499SJeff Garzik *private_header = cpu_to_le16(skb->len-2); 8435b2fc499SJeff Garzik kaweth->tx_skb = skb; 8445b2fc499SJeff Garzik 8455b2fc499SJeff Garzik usb_fill_bulk_urb(kaweth->tx_urb, 8465b2fc499SJeff Garzik kaweth->dev, 8475b2fc499SJeff Garzik usb_sndbulkpipe(kaweth->dev, 2), 8485b2fc499SJeff Garzik private_header, 8495b2fc499SJeff Garzik skb->len, 8505b2fc499SJeff Garzik kaweth_usb_transmit_complete, 8515b2fc499SJeff Garzik kaweth); 8525b2fc499SJeff Garzik kaweth->end = 0; 8535b2fc499SJeff Garzik 8545b2fc499SJeff Garzik if((res = usb_submit_urb(kaweth->tx_urb, GFP_ATOMIC))) 8555b2fc499SJeff Garzik { 8564dc89948SGreg Kroah-Hartman dev_warn(&net->dev, "kaweth failed tx_urb %d\n", res); 8575b2fc499SJeff Garzik skip: 8585b2fc499SJeff Garzik kaweth->stats.tx_errors++; 8595b2fc499SJeff Garzik 8605b2fc499SJeff Garzik netif_start_queue(net); 8615b2fc499SJeff Garzik dev_kfree_skb_irq(skb); 8625b2fc499SJeff Garzik } 8635b2fc499SJeff Garzik else 8645b2fc499SJeff Garzik { 8655b2fc499SJeff Garzik kaweth->stats.tx_packets++; 8665b2fc499SJeff Garzik kaweth->stats.tx_bytes += skb->len; 8675b2fc499SJeff Garzik net->trans_start = jiffies; 8685b2fc499SJeff Garzik } 8695b2fc499SJeff Garzik 8704ff61c8fSLarry Finger spin_unlock_irq(&kaweth->device_lock); 8715b2fc499SJeff Garzik 8726ed10654SPatrick McHardy return NETDEV_TX_OK; 8735b2fc499SJeff Garzik } 8745b2fc499SJeff Garzik 8755b2fc499SJeff Garzik /**************************************************************** 8765b2fc499SJeff Garzik * kaweth_set_rx_mode 8775b2fc499SJeff Garzik ****************************************************************/ 8785b2fc499SJeff Garzik static void kaweth_set_rx_mode(struct net_device *net) 8795b2fc499SJeff Garzik { 8805b2fc499SJeff Garzik struct kaweth_device *kaweth = netdev_priv(net); 8815b2fc499SJeff Garzik 8825b2fc499SJeff Garzik __u16 packet_filter_bitmap = KAWETH_PACKET_FILTER_DIRECTED | 8835b2fc499SJeff Garzik KAWETH_PACKET_FILTER_BROADCAST | 8845b2fc499SJeff Garzik KAWETH_PACKET_FILTER_MULTICAST; 8855b2fc499SJeff Garzik 8865b2fc499SJeff Garzik dbg("Setting Rx mode to %d", packet_filter_bitmap); 8875b2fc499SJeff Garzik 8885b2fc499SJeff Garzik netif_stop_queue(net); 8895b2fc499SJeff Garzik 8905b2fc499SJeff Garzik if (net->flags & IFF_PROMISC) { 8915b2fc499SJeff Garzik packet_filter_bitmap |= KAWETH_PACKET_FILTER_PROMISCUOUS; 8925b2fc499SJeff Garzik } 8935b2fc499SJeff Garzik else if ((net->mc_count) || (net->flags & IFF_ALLMULTI)) { 8945b2fc499SJeff Garzik packet_filter_bitmap |= KAWETH_PACKET_FILTER_ALL_MULTICAST; 8955b2fc499SJeff Garzik } 8965b2fc499SJeff Garzik 8975b2fc499SJeff Garzik kaweth->packet_filter_bitmap = packet_filter_bitmap; 8985b2fc499SJeff Garzik netif_wake_queue(net); 8995b2fc499SJeff Garzik } 9005b2fc499SJeff Garzik 9015b2fc499SJeff Garzik /**************************************************************** 9025b2fc499SJeff Garzik * kaweth_async_set_rx_mode 9035b2fc499SJeff Garzik ****************************************************************/ 9045b2fc499SJeff Garzik static void kaweth_async_set_rx_mode(struct kaweth_device *kaweth) 9055b2fc499SJeff Garzik { 906710b523aSLarry Finger int result; 9075b2fc499SJeff Garzik __u16 packet_filter_bitmap = kaweth->packet_filter_bitmap; 908710b523aSLarry Finger 9095b2fc499SJeff Garzik kaweth->packet_filter_bitmap = 0; 9105b2fc499SJeff Garzik if (packet_filter_bitmap == 0) 9115b2fc499SJeff Garzik return; 9125b2fc499SJeff Garzik 913710b523aSLarry Finger if (in_interrupt()) 914710b523aSLarry Finger return; 915710b523aSLarry Finger 9165b2fc499SJeff Garzik result = kaweth_control(kaweth, 9175b2fc499SJeff Garzik usb_sndctrlpipe(kaweth->dev, 0), 9185b2fc499SJeff Garzik KAWETH_COMMAND_SET_PACKET_FILTER, 9195b2fc499SJeff Garzik USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, 9205b2fc499SJeff Garzik packet_filter_bitmap, 9215b2fc499SJeff Garzik 0, 9225b2fc499SJeff Garzik (void *)&kaweth->scratch, 9235b2fc499SJeff Garzik 0, 9245b2fc499SJeff Garzik KAWETH_CONTROL_TIMEOUT); 9255b2fc499SJeff Garzik 9265b2fc499SJeff Garzik if(result < 0) { 9275b2fc499SJeff Garzik err("Failed to set Rx mode: %d", result); 9285b2fc499SJeff Garzik } 9295b2fc499SJeff Garzik else { 9305b2fc499SJeff Garzik dbg("Set Rx mode to %d", packet_filter_bitmap); 9315b2fc499SJeff Garzik } 9325b2fc499SJeff Garzik } 9335b2fc499SJeff Garzik 9345b2fc499SJeff Garzik /**************************************************************** 9355b2fc499SJeff Garzik * kaweth_netdev_stats 9365b2fc499SJeff Garzik ****************************************************************/ 9375b2fc499SJeff Garzik static struct net_device_stats *kaweth_netdev_stats(struct net_device *dev) 9385b2fc499SJeff Garzik { 9395b2fc499SJeff Garzik struct kaweth_device *kaweth = netdev_priv(dev); 9405b2fc499SJeff Garzik return &kaweth->stats; 9415b2fc499SJeff Garzik } 9425b2fc499SJeff Garzik 9435b2fc499SJeff Garzik /**************************************************************** 9445b2fc499SJeff Garzik * kaweth_tx_timeout 9455b2fc499SJeff Garzik ****************************************************************/ 9465b2fc499SJeff Garzik static void kaweth_tx_timeout(struct net_device *net) 9475b2fc499SJeff Garzik { 9485b2fc499SJeff Garzik struct kaweth_device *kaweth = netdev_priv(net); 9495b2fc499SJeff Garzik 9504dc89948SGreg Kroah-Hartman dev_warn(&net->dev, "%s: Tx timed out. Resetting.\n", net->name); 9515b2fc499SJeff Garzik kaweth->stats.tx_errors++; 9525b2fc499SJeff Garzik net->trans_start = jiffies; 9535b2fc499SJeff Garzik 9545b2fc499SJeff Garzik usb_unlink_urb(kaweth->tx_urb); 9555b2fc499SJeff Garzik } 9565b2fc499SJeff Garzik 9575b2fc499SJeff Garzik /**************************************************************** 9585b2fc499SJeff Garzik * kaweth_suspend 9595b2fc499SJeff Garzik ****************************************************************/ 9605b2fc499SJeff Garzik static int kaweth_suspend(struct usb_interface *intf, pm_message_t message) 9615b2fc499SJeff Garzik { 9625b2fc499SJeff Garzik struct kaweth_device *kaweth = usb_get_intfdata(intf); 9635b2fc499SJeff Garzik unsigned long flags; 9645b2fc499SJeff Garzik 9655b2fc499SJeff Garzik dbg("Suspending device"); 9665b2fc499SJeff Garzik spin_lock_irqsave(&kaweth->device_lock, flags); 9675b2fc499SJeff Garzik kaweth->status |= KAWETH_STATUS_SUSPENDING; 9685b2fc499SJeff Garzik spin_unlock_irqrestore(&kaweth->device_lock, flags); 9695b2fc499SJeff Garzik 9705b2fc499SJeff Garzik kaweth_kill_urbs(kaweth); 9715b2fc499SJeff Garzik return 0; 9725b2fc499SJeff Garzik } 9735b2fc499SJeff Garzik 9745b2fc499SJeff Garzik /**************************************************************** 9755b2fc499SJeff Garzik * kaweth_resume 9765b2fc499SJeff Garzik ****************************************************************/ 9775b2fc499SJeff Garzik static int kaweth_resume(struct usb_interface *intf) 9785b2fc499SJeff Garzik { 9795b2fc499SJeff Garzik struct kaweth_device *kaweth = usb_get_intfdata(intf); 9805b2fc499SJeff Garzik unsigned long flags; 9815b2fc499SJeff Garzik 9825b2fc499SJeff Garzik dbg("Resuming device"); 9835b2fc499SJeff Garzik spin_lock_irqsave(&kaweth->device_lock, flags); 9845b2fc499SJeff Garzik kaweth->status &= ~KAWETH_STATUS_SUSPENDING; 9855b2fc499SJeff Garzik spin_unlock_irqrestore(&kaweth->device_lock, flags); 9865b2fc499SJeff Garzik 9875b2fc499SJeff Garzik if (!kaweth->opened) 9885b2fc499SJeff Garzik return 0; 9895b2fc499SJeff Garzik kaweth_resubmit_rx_urb(kaweth, GFP_NOIO); 9905b2fc499SJeff Garzik kaweth_resubmit_int_urb(kaweth, GFP_NOIO); 9915b2fc499SJeff Garzik 9925b2fc499SJeff Garzik return 0; 9935b2fc499SJeff Garzik } 9945b2fc499SJeff Garzik 9955b2fc499SJeff Garzik /**************************************************************** 9965b2fc499SJeff Garzik * kaweth_probe 9975b2fc499SJeff Garzik ****************************************************************/ 998321ea8b2SOliver Neukum 999321ea8b2SOliver Neukum 1000321ea8b2SOliver Neukum static const struct net_device_ops kaweth_netdev_ops = { 1001321ea8b2SOliver Neukum .ndo_open = kaweth_open, 1002321ea8b2SOliver Neukum .ndo_stop = kaweth_close, 1003321ea8b2SOliver Neukum .ndo_start_xmit = kaweth_start_xmit, 1004321ea8b2SOliver Neukum .ndo_tx_timeout = kaweth_tx_timeout, 1005321ea8b2SOliver Neukum .ndo_set_multicast_list = kaweth_set_rx_mode, 1006321ea8b2SOliver Neukum .ndo_get_stats = kaweth_netdev_stats, 1007635ecaa7SBen Hutchings .ndo_change_mtu = eth_change_mtu, 1008240c102dSBen Hutchings .ndo_set_mac_address = eth_mac_addr, 1009240c102dSBen Hutchings .ndo_validate_addr = eth_validate_addr, 1010321ea8b2SOliver Neukum }; 1011321ea8b2SOliver Neukum 10125b2fc499SJeff Garzik static int kaweth_probe( 10135b2fc499SJeff Garzik struct usb_interface *intf, 10145b2fc499SJeff Garzik const struct usb_device_id *id /* from id_table */ 10155b2fc499SJeff Garzik ) 10165b2fc499SJeff Garzik { 10175b2fc499SJeff Garzik struct usb_device *dev = interface_to_usbdev(intf); 10185b2fc499SJeff Garzik struct kaweth_device *kaweth; 10195b2fc499SJeff Garzik struct net_device *netdev; 10205b2fc499SJeff Garzik const eth_addr_t bcast_addr = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; 10215b2fc499SJeff Garzik int result = 0; 10225b2fc499SJeff Garzik 10235b2fc499SJeff Garzik dbg("Kawasaki Device Probe (Device number:%d): 0x%4.4x:0x%4.4x:0x%4.4x", 10245b2fc499SJeff Garzik dev->devnum, 10255b2fc499SJeff Garzik le16_to_cpu(dev->descriptor.idVendor), 10265b2fc499SJeff Garzik le16_to_cpu(dev->descriptor.idProduct), 10275b2fc499SJeff Garzik le16_to_cpu(dev->descriptor.bcdDevice)); 10285b2fc499SJeff Garzik 10295b2fc499SJeff Garzik dbg("Device at %p", dev); 10305b2fc499SJeff Garzik 10315b2fc499SJeff Garzik dbg("Descriptor length: %x type: %x", 10325b2fc499SJeff Garzik (int)dev->descriptor.bLength, 10335b2fc499SJeff Garzik (int)dev->descriptor.bDescriptorType); 10345b2fc499SJeff Garzik 10355b2fc499SJeff Garzik netdev = alloc_etherdev(sizeof(*kaweth)); 10365b2fc499SJeff Garzik if (!netdev) 10375b2fc499SJeff Garzik return -ENOMEM; 10385b2fc499SJeff Garzik 10395b2fc499SJeff Garzik kaweth = netdev_priv(netdev); 10405b2fc499SJeff Garzik kaweth->dev = dev; 10415b2fc499SJeff Garzik kaweth->net = netdev; 10425b2fc499SJeff Garzik 10435b2fc499SJeff Garzik spin_lock_init(&kaweth->device_lock); 10445b2fc499SJeff Garzik init_waitqueue_head(&kaweth->term_wait); 10455b2fc499SJeff Garzik 10465b2fc499SJeff Garzik dbg("Resetting."); 10475b2fc499SJeff Garzik 10485b2fc499SJeff Garzik kaweth_reset(kaweth); 10495b2fc499SJeff Garzik 10505b2fc499SJeff Garzik /* 10515b2fc499SJeff Garzik * If high byte of bcdDevice is nonzero, firmware is already 10525b2fc499SJeff Garzik * downloaded. Don't try to do it again, or we'll hang the device. 10535b2fc499SJeff Garzik */ 10545b2fc499SJeff Garzik 10555b2fc499SJeff Garzik if (le16_to_cpu(dev->descriptor.bcdDevice) >> 8) { 1056880c9c66SGreg Kroah-Hartman dev_info(&intf->dev, "Firmware present in device.\n"); 10575b2fc499SJeff Garzik } else { 10585b2fc499SJeff Garzik /* Download the firmware */ 1059880c9c66SGreg Kroah-Hartman dev_info(&intf->dev, "Downloading firmware...\n"); 10605b2fc499SJeff Garzik kaweth->firmware_buf = (__u8 *)__get_free_page(GFP_KERNEL); 10615b2fc499SJeff Garzik if ((result = kaweth_download_firmware(kaweth, 106279682499SDavid Woodhouse "kaweth/new_code.bin", 10635b2fc499SJeff Garzik 100, 10645b2fc499SJeff Garzik 2)) < 0) { 10655b2fc499SJeff Garzik err("Error downloading firmware (%d)", result); 10665b2fc499SJeff Garzik goto err_fw; 10675b2fc499SJeff Garzik } 10685b2fc499SJeff Garzik 10695b2fc499SJeff Garzik if ((result = kaweth_download_firmware(kaweth, 107079682499SDavid Woodhouse "kaweth/new_code_fix.bin", 10715b2fc499SJeff Garzik 100, 10725b2fc499SJeff Garzik 3)) < 0) { 10735b2fc499SJeff Garzik err("Error downloading firmware fix (%d)", result); 10745b2fc499SJeff Garzik goto err_fw; 10755b2fc499SJeff Garzik } 10765b2fc499SJeff Garzik 10775b2fc499SJeff Garzik if ((result = kaweth_download_firmware(kaweth, 107879682499SDavid Woodhouse "kaweth/trigger_code.bin", 10795b2fc499SJeff Garzik 126, 10805b2fc499SJeff Garzik 2)) < 0) { 10815b2fc499SJeff Garzik err("Error downloading trigger code (%d)", result); 10825b2fc499SJeff Garzik goto err_fw; 10835b2fc499SJeff Garzik 10845b2fc499SJeff Garzik } 10855b2fc499SJeff Garzik 10865b2fc499SJeff Garzik if ((result = kaweth_download_firmware(kaweth, 108779682499SDavid Woodhouse "kaweth/trigger_code_fix.bin", 10885b2fc499SJeff Garzik 126, 10895b2fc499SJeff Garzik 3)) < 0) { 10905b2fc499SJeff Garzik err("Error downloading trigger code fix (%d)", result); 10915b2fc499SJeff Garzik goto err_fw; 10925b2fc499SJeff Garzik } 10935b2fc499SJeff Garzik 10945b2fc499SJeff Garzik 10955b2fc499SJeff Garzik if ((result = kaweth_trigger_firmware(kaweth, 126)) < 0) { 10965b2fc499SJeff Garzik err("Error triggering firmware (%d)", result); 10975b2fc499SJeff Garzik goto err_fw; 10985b2fc499SJeff Garzik } 10995b2fc499SJeff Garzik 11005b2fc499SJeff Garzik /* Device will now disappear for a moment... */ 1101880c9c66SGreg Kroah-Hartman dev_info(&intf->dev, "Firmware loaded. I'll be back...\n"); 11025b2fc499SJeff Garzik err_fw: 11035b2fc499SJeff Garzik free_page((unsigned long)kaweth->firmware_buf); 11045b2fc499SJeff Garzik free_netdev(netdev); 11055b2fc499SJeff Garzik return -EIO; 11065b2fc499SJeff Garzik } 11075b2fc499SJeff Garzik 11085b2fc499SJeff Garzik result = kaweth_read_configuration(kaweth); 11095b2fc499SJeff Garzik 11105b2fc499SJeff Garzik if(result < 0) { 11115b2fc499SJeff Garzik err("Error reading configuration (%d), no net device created", result); 11125b2fc499SJeff Garzik goto err_free_netdev; 11135b2fc499SJeff Garzik } 11145b2fc499SJeff Garzik 1115880c9c66SGreg Kroah-Hartman dev_info(&intf->dev, "Statistics collection: %x\n", kaweth->configuration.statistics_mask); 1116880c9c66SGreg Kroah-Hartman dev_info(&intf->dev, "Multicast filter limit: %x\n", kaweth->configuration.max_multicast_filters & ((1 << 15) - 1)); 1117880c9c66SGreg Kroah-Hartman dev_info(&intf->dev, "MTU: %d\n", le16_to_cpu(kaweth->configuration.segment_size)); 1118880c9c66SGreg Kroah-Hartman dev_info(&intf->dev, "Read MAC address %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n", 11195b2fc499SJeff Garzik (int)kaweth->configuration.hw_addr[0], 11205b2fc499SJeff Garzik (int)kaweth->configuration.hw_addr[1], 11215b2fc499SJeff Garzik (int)kaweth->configuration.hw_addr[2], 11225b2fc499SJeff Garzik (int)kaweth->configuration.hw_addr[3], 11235b2fc499SJeff Garzik (int)kaweth->configuration.hw_addr[4], 11245b2fc499SJeff Garzik (int)kaweth->configuration.hw_addr[5]); 11255b2fc499SJeff Garzik 11265b2fc499SJeff Garzik if(!memcmp(&kaweth->configuration.hw_addr, 11275b2fc499SJeff Garzik &bcast_addr, 11285b2fc499SJeff Garzik sizeof(bcast_addr))) { 11295b2fc499SJeff Garzik err("Firmware not functioning properly, no net device created"); 11305b2fc499SJeff Garzik goto err_free_netdev; 11315b2fc499SJeff Garzik } 11325b2fc499SJeff Garzik 11335b2fc499SJeff Garzik if(kaweth_set_urb_size(kaweth, KAWETH_BUF_SIZE) < 0) { 11345b2fc499SJeff Garzik dbg("Error setting URB size"); 11355b2fc499SJeff Garzik goto err_free_netdev; 11365b2fc499SJeff Garzik } 11375b2fc499SJeff Garzik 11385b2fc499SJeff Garzik if(kaweth_set_sofs_wait(kaweth, KAWETH_SOFS_TO_WAIT) < 0) { 11395b2fc499SJeff Garzik err("Error setting SOFS wait"); 11405b2fc499SJeff Garzik goto err_free_netdev; 11415b2fc499SJeff Garzik } 11425b2fc499SJeff Garzik 11435b2fc499SJeff Garzik result = kaweth_set_receive_filter(kaweth, 11445b2fc499SJeff Garzik KAWETH_PACKET_FILTER_DIRECTED | 11455b2fc499SJeff Garzik KAWETH_PACKET_FILTER_BROADCAST | 11465b2fc499SJeff Garzik KAWETH_PACKET_FILTER_MULTICAST); 11475b2fc499SJeff Garzik 11485b2fc499SJeff Garzik if(result < 0) { 11495b2fc499SJeff Garzik err("Error setting receive filter"); 11505b2fc499SJeff Garzik goto err_free_netdev; 11515b2fc499SJeff Garzik } 11525b2fc499SJeff Garzik 11535b2fc499SJeff Garzik dbg("Initializing net device."); 11545b2fc499SJeff Garzik 11555b2fc499SJeff Garzik kaweth->intf = intf; 11565b2fc499SJeff Garzik 11575b2fc499SJeff Garzik kaweth->tx_urb = usb_alloc_urb(0, GFP_KERNEL); 11585b2fc499SJeff Garzik if (!kaweth->tx_urb) 11595b2fc499SJeff Garzik goto err_free_netdev; 11605b2fc499SJeff Garzik kaweth->rx_urb = usb_alloc_urb(0, GFP_KERNEL); 11615b2fc499SJeff Garzik if (!kaweth->rx_urb) 11625b2fc499SJeff Garzik goto err_only_tx; 11635b2fc499SJeff Garzik kaweth->irq_urb = usb_alloc_urb(0, GFP_KERNEL); 11645b2fc499SJeff Garzik if (!kaweth->irq_urb) 11655b2fc499SJeff Garzik goto err_tx_and_rx; 11665b2fc499SJeff Garzik 11675b2fc499SJeff Garzik kaweth->intbuffer = usb_buffer_alloc( kaweth->dev, 11685b2fc499SJeff Garzik INTBUFFERSIZE, 11695b2fc499SJeff Garzik GFP_KERNEL, 11705b2fc499SJeff Garzik &kaweth->intbufferhandle); 11715b2fc499SJeff Garzik if (!kaweth->intbuffer) 11725b2fc499SJeff Garzik goto err_tx_and_rx_and_irq; 11735b2fc499SJeff Garzik kaweth->rx_buf = usb_buffer_alloc( kaweth->dev, 11745b2fc499SJeff Garzik KAWETH_BUF_SIZE, 11755b2fc499SJeff Garzik GFP_KERNEL, 11765b2fc499SJeff Garzik &kaweth->rxbufferhandle); 11775b2fc499SJeff Garzik if (!kaweth->rx_buf) 11785b2fc499SJeff Garzik goto err_all_but_rxbuf; 11795b2fc499SJeff Garzik 11805b2fc499SJeff Garzik memcpy(netdev->broadcast, &bcast_addr, sizeof(bcast_addr)); 11815b2fc499SJeff Garzik memcpy(netdev->dev_addr, &kaweth->configuration.hw_addr, 11825b2fc499SJeff Garzik sizeof(kaweth->configuration.hw_addr)); 11835b2fc499SJeff Garzik 1184321ea8b2SOliver Neukum netdev->netdev_ops = &kaweth_netdev_ops; 11855b2fc499SJeff Garzik netdev->watchdog_timeo = KAWETH_TX_TIMEOUT; 11865b2fc499SJeff Garzik netdev->mtu = le16_to_cpu(kaweth->configuration.segment_size); 11875b2fc499SJeff Garzik SET_ETHTOOL_OPS(netdev, &ops); 11885b2fc499SJeff Garzik 11895b2fc499SJeff Garzik /* kaweth is zeroed as part of alloc_netdev */ 11905b2fc499SJeff Garzik INIT_DELAYED_WORK(&kaweth->lowmem_work, kaweth_resubmit_tl); 11915b2fc499SJeff Garzik usb_set_intfdata(intf, kaweth); 11925b2fc499SJeff Garzik 11935b2fc499SJeff Garzik #if 0 11945b2fc499SJeff Garzik // dma_supported() is deeply broken on almost all architectures 11955b2fc499SJeff Garzik if (dma_supported (&intf->dev, 0xffffffffffffffffULL)) 11965b2fc499SJeff Garzik kaweth->net->features |= NETIF_F_HIGHDMA; 11975b2fc499SJeff Garzik #endif 11985b2fc499SJeff Garzik 11995b2fc499SJeff Garzik SET_NETDEV_DEV(netdev, &intf->dev); 12005b2fc499SJeff Garzik if (register_netdev(netdev) != 0) { 12015b2fc499SJeff Garzik err("Error registering netdev."); 12025b2fc499SJeff Garzik goto err_intfdata; 12035b2fc499SJeff Garzik } 12045b2fc499SJeff Garzik 1205880c9c66SGreg Kroah-Hartman dev_info(&intf->dev, "kaweth interface created at %s\n", 1206880c9c66SGreg Kroah-Hartman kaweth->net->name); 12075b2fc499SJeff Garzik 12085b2fc499SJeff Garzik dbg("Kaweth probe returning."); 12095b2fc499SJeff Garzik 12105b2fc499SJeff Garzik return 0; 12115b2fc499SJeff Garzik 12125b2fc499SJeff Garzik err_intfdata: 12135b2fc499SJeff Garzik usb_set_intfdata(intf, NULL); 12145b2fc499SJeff Garzik usb_buffer_free(kaweth->dev, KAWETH_BUF_SIZE, (void *)kaweth->rx_buf, kaweth->rxbufferhandle); 12155b2fc499SJeff Garzik err_all_but_rxbuf: 12165b2fc499SJeff Garzik usb_buffer_free(kaweth->dev, INTBUFFERSIZE, (void *)kaweth->intbuffer, kaweth->intbufferhandle); 12175b2fc499SJeff Garzik err_tx_and_rx_and_irq: 12185b2fc499SJeff Garzik usb_free_urb(kaweth->irq_urb); 12195b2fc499SJeff Garzik err_tx_and_rx: 12205b2fc499SJeff Garzik usb_free_urb(kaweth->rx_urb); 12215b2fc499SJeff Garzik err_only_tx: 12225b2fc499SJeff Garzik usb_free_urb(kaweth->tx_urb); 12235b2fc499SJeff Garzik err_free_netdev: 12245b2fc499SJeff Garzik free_netdev(netdev); 12255b2fc499SJeff Garzik 12265b2fc499SJeff Garzik return -EIO; 12275b2fc499SJeff Garzik } 12285b2fc499SJeff Garzik 12295b2fc499SJeff Garzik /**************************************************************** 12305b2fc499SJeff Garzik * kaweth_disconnect 12315b2fc499SJeff Garzik ****************************************************************/ 12325b2fc499SJeff Garzik static void kaweth_disconnect(struct usb_interface *intf) 12335b2fc499SJeff Garzik { 12345b2fc499SJeff Garzik struct kaweth_device *kaweth = usb_get_intfdata(intf); 12355b2fc499SJeff Garzik struct net_device *netdev; 12365b2fc499SJeff Garzik 1237880c9c66SGreg Kroah-Hartman dev_info(&intf->dev, "Unregistering\n"); 12385b2fc499SJeff Garzik 12395b2fc499SJeff Garzik usb_set_intfdata(intf, NULL); 12405b2fc499SJeff Garzik if (!kaweth) { 12414dc89948SGreg Kroah-Hartman dev_warn(&intf->dev, "unregistering non-existant device\n"); 12425b2fc499SJeff Garzik return; 12435b2fc499SJeff Garzik } 12445b2fc499SJeff Garzik netdev = kaweth->net; 12455b2fc499SJeff Garzik 12465b2fc499SJeff Garzik dbg("Unregistering net device"); 12475b2fc499SJeff Garzik unregister_netdev(netdev); 12485b2fc499SJeff Garzik 12495b2fc499SJeff Garzik usb_free_urb(kaweth->rx_urb); 12505b2fc499SJeff Garzik usb_free_urb(kaweth->tx_urb); 12515b2fc499SJeff Garzik usb_free_urb(kaweth->irq_urb); 12525b2fc499SJeff Garzik 12535b2fc499SJeff Garzik usb_buffer_free(kaweth->dev, KAWETH_BUF_SIZE, (void *)kaweth->rx_buf, kaweth->rxbufferhandle); 12545b2fc499SJeff Garzik usb_buffer_free(kaweth->dev, INTBUFFERSIZE, (void *)kaweth->intbuffer, kaweth->intbufferhandle); 12555b2fc499SJeff Garzik 12565b2fc499SJeff Garzik free_netdev(netdev); 12575b2fc499SJeff Garzik } 12585b2fc499SJeff Garzik 12595b2fc499SJeff Garzik 12605b2fc499SJeff Garzik // FIXME this completion stuff is a modified clone of 12615b2fc499SJeff Garzik // an OLD version of some stuff in usb.c ... 12625b2fc499SJeff Garzik struct usb_api_data { 12635b2fc499SJeff Garzik wait_queue_head_t wqh; 12645b2fc499SJeff Garzik int done; 12655b2fc499SJeff Garzik }; 12665b2fc499SJeff Garzik 12675b2fc499SJeff Garzik /*-------------------------------------------------------------------* 12685b2fc499SJeff Garzik * completion handler for compatibility wrappers (sync control/bulk) * 12695b2fc499SJeff Garzik *-------------------------------------------------------------------*/ 12705b2fc499SJeff Garzik static void usb_api_blocking_completion(struct urb *urb) 12715b2fc499SJeff Garzik { 12725b2fc499SJeff Garzik struct usb_api_data *awd = (struct usb_api_data *)urb->context; 12735b2fc499SJeff Garzik 12745b2fc499SJeff Garzik awd->done=1; 12755b2fc499SJeff Garzik wake_up(&awd->wqh); 12765b2fc499SJeff Garzik } 12775b2fc499SJeff Garzik 12785b2fc499SJeff Garzik /*-------------------------------------------------------------------* 12795b2fc499SJeff Garzik * COMPATIBILITY STUFF * 12805b2fc499SJeff Garzik *-------------------------------------------------------------------*/ 12815b2fc499SJeff Garzik 12825b2fc499SJeff Garzik // Starts urb and waits for completion or timeout 12835b2fc499SJeff Garzik static int usb_start_wait_urb(struct urb *urb, int timeout, int* actual_length) 12845b2fc499SJeff Garzik { 12855b2fc499SJeff Garzik struct usb_api_data awd; 12865b2fc499SJeff Garzik int status; 12875b2fc499SJeff Garzik 12885b2fc499SJeff Garzik init_waitqueue_head(&awd.wqh); 12895b2fc499SJeff Garzik awd.done = 0; 12905b2fc499SJeff Garzik 12915b2fc499SJeff Garzik urb->context = &awd; 12925b2fc499SJeff Garzik status = usb_submit_urb(urb, GFP_NOIO); 12935b2fc499SJeff Garzik if (status) { 12945b2fc499SJeff Garzik // something went wrong 12955b2fc499SJeff Garzik usb_free_urb(urb); 12965b2fc499SJeff Garzik return status; 12975b2fc499SJeff Garzik } 12985b2fc499SJeff Garzik 12995b2fc499SJeff Garzik if (!wait_event_timeout(awd.wqh, awd.done, timeout)) { 13005b2fc499SJeff Garzik // timeout 13014dc89948SGreg Kroah-Hartman dev_warn(&urb->dev->dev, "usb_control/bulk_msg: timeout\n"); 13025b2fc499SJeff Garzik usb_kill_urb(urb); // remove urb safely 13035b2fc499SJeff Garzik status = -ETIMEDOUT; 13045b2fc499SJeff Garzik } 13055b2fc499SJeff Garzik else { 13065b2fc499SJeff Garzik status = urb->status; 13075b2fc499SJeff Garzik } 13085b2fc499SJeff Garzik 13095b2fc499SJeff Garzik if (actual_length) { 13105b2fc499SJeff Garzik *actual_length = urb->actual_length; 13115b2fc499SJeff Garzik } 13125b2fc499SJeff Garzik 13135b2fc499SJeff Garzik usb_free_urb(urb); 13145b2fc499SJeff Garzik return status; 13155b2fc499SJeff Garzik } 13165b2fc499SJeff Garzik 13175b2fc499SJeff Garzik /*-------------------------------------------------------------------*/ 13185b2fc499SJeff Garzik // returns status (negative) or length (positive) 13195b2fc499SJeff Garzik static int kaweth_internal_control_msg(struct usb_device *usb_dev, 13205b2fc499SJeff Garzik unsigned int pipe, 13215b2fc499SJeff Garzik struct usb_ctrlrequest *cmd, void *data, 13225b2fc499SJeff Garzik int len, int timeout) 13235b2fc499SJeff Garzik { 13245b2fc499SJeff Garzik struct urb *urb; 13255b2fc499SJeff Garzik int retv; 13265b2fc499SJeff Garzik int length = 0; /* shut up GCC */ 13275b2fc499SJeff Garzik 13285b2fc499SJeff Garzik urb = usb_alloc_urb(0, GFP_NOIO); 13295b2fc499SJeff Garzik if (!urb) 13305b2fc499SJeff Garzik return -ENOMEM; 13315b2fc499SJeff Garzik 13325b2fc499SJeff Garzik usb_fill_control_urb(urb, usb_dev, pipe, (unsigned char*)cmd, data, 13335b2fc499SJeff Garzik len, usb_api_blocking_completion, NULL); 13345b2fc499SJeff Garzik 13355b2fc499SJeff Garzik retv = usb_start_wait_urb(urb, timeout, &length); 13365b2fc499SJeff Garzik if (retv < 0) { 13375b2fc499SJeff Garzik return retv; 13385b2fc499SJeff Garzik } 13395b2fc499SJeff Garzik else { 13405b2fc499SJeff Garzik return length; 13415b2fc499SJeff Garzik } 13425b2fc499SJeff Garzik } 13435b2fc499SJeff Garzik 13445b2fc499SJeff Garzik 13455b2fc499SJeff Garzik /**************************************************************** 13465b2fc499SJeff Garzik * kaweth_init 13475b2fc499SJeff Garzik ****************************************************************/ 13485b2fc499SJeff Garzik static int __init kaweth_init(void) 13495b2fc499SJeff Garzik { 13505b2fc499SJeff Garzik dbg("Driver loading"); 13515b2fc499SJeff Garzik return usb_register(&kaweth_driver); 13525b2fc499SJeff Garzik } 13535b2fc499SJeff Garzik 13545b2fc499SJeff Garzik /**************************************************************** 13555b2fc499SJeff Garzik * kaweth_exit 13565b2fc499SJeff Garzik ****************************************************************/ 13575b2fc499SJeff Garzik static void __exit kaweth_exit(void) 13585b2fc499SJeff Garzik { 13595b2fc499SJeff Garzik usb_deregister(&kaweth_driver); 13605b2fc499SJeff Garzik } 13615b2fc499SJeff Garzik 13625b2fc499SJeff Garzik module_init(kaweth_init); 13635b2fc499SJeff Garzik module_exit(kaweth_exit); 13645b2fc499SJeff Garzik 13655b2fc499SJeff Garzik 13665b2fc499SJeff Garzik 13675b2fc499SJeff Garzik 13685b2fc499SJeff Garzik 13695b2fc499SJeff Garzik 13705b2fc499SJeff Garzik 13715b2fc499SJeff Garzik 13725b2fc499SJeff Garzik 1373