| Start/ | End/ | |||
| True | False | - | Line | Source |
| 1 | /**************************************************************** | |||
| 2 | * | |||
| 3 | * kaweth.c - driver for KL5KUSB101 based USB->Ethernet | |||
| 4 | * | |||
| 5 | * (c) 2000 Interlan Communications | |||
| 6 | * (c) 2000 Stephane Alnet | |||
| 7 | * (C) 2001 Brad Hards | |||
| 8 | * (C) 2002 Oliver Neukum | |||
| 9 | * | |||
| 10 | * Original author: The Zapman <zapman@interlan.net> | |||
| 11 | * Inspired by, and much credit goes to Michael Rothwell | |||
| 12 | * <rothwell@interlan.net> for the test equipment, help, and patience | |||
| 13 | * Based off of (and with thanks to) Petko Manolov's pegaus.c driver. | |||
| 14 | * Also many thanks to Joel Silverman and Ed Surprenant at Kawasaki | |||
| 15 | * for providing the firmware and driver resources. | |||
| 16 | * | |||
| 17 | * This program is free software; you can redistribute it and/or | |||
| 18 | * modify it under the terms of the GNU General Public License as | |||
| 19 | * published by the Free Software Foundation; either version 2, or | |||
| 20 | * (at your option) any later version. | |||
| 21 | * | |||
| 22 | * This program is distributed in the hope that it will be useful, | |||
| 23 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| 24 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| 25 | * GNU General Public License for more details. | |||
| 26 | * | |||
| 27 | * You should have received a copy of the GNU General Public License | |||
| 28 | * along with this program; if not, write to the Free Software Foundation, | |||
| 29 | * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| 30 | * | |||
| 31 | ****************************************************************/ | |||
| 32 | ||||
| 33 | /* TODO: | |||
| 34 | * Fix in_interrupt() problem | |||
| 35 | * Develop test procedures for USB net interfaces | |||
| 36 | * Run test procedures | |||
| 37 | * Fix bugs from previous two steps | |||
| 38 | * Snoop other OSs for any tricks we're not doing | |||
| 39 | * SMP locking | |||
| 40 | * Reduce arbitrary timeouts | |||
| 41 | * Smart multicast support | |||
| 42 | * Temporary MAC change support | |||
| 43 | * Tunable SOFs parameter - ioctl()? | |||
| 44 | * Ethernet stats collection | |||
| 45 | * Code formatting improvements | |||
| 46 | */ | |||
| 47 | ||||
| 48 | #include <linux/module.h> | |||
| 49 | #include <linux/sched.h> | |||
| 50 | #include <linux/slab.h> | |||
| 51 | #include <linux/string.h> | |||
| 52 | #include <linux/init.h> | |||
| 53 | #include <linux/delay.h> | |||
| 54 | #include <linux/netdevice.h> | |||
| 55 | #include <linux/etherdevice.h> | |||
| 56 | #include <linux/usb.h> | |||
| 57 | #include <linux/types.h> | |||
| 58 | #include <linux/ethtool.h> | |||
| 59 | #include <linux/pci.h> | |||
| 60 | #include <linux/dma-mapping.h> | |||
| 61 | #include <linux/wait.h> | |||
| 62 | #include <asm/uaccess.h> | |||
| 63 | #include <asm/semaphore.h> | |||
| 64 | #include <asm/byteorder.h> | |||
| 65 | ||||
| 66 | #undef DEBUG | |||
| 67 | ||||
| 68 | #ifdef DEBUG | |||
| 69 | #define kaweth_dbg(format, arg...) printk(KERN_DEBUG __FILE__ ": " format "\n" ,##arg) | |||
| 70 | #else | |||
| 71 | #define kaweth_dbg(format, arg...) do {} while (0) | |||
| 72 | #endif | |||
| 73 | #define kaweth_err(format, arg...) printk(KERN_ERR __FILE__ ": " format "\n" ,##arg) | |||
| 74 | #define kaweth_info(format, arg...) printk(KERN_INFO __FILE__ ": " format "\n" , ##arg) | |||
| 75 | #define kaweth_warn(format, arg...) printk(KERN_WARNING __FILE__ ": " format "\n" , ##arg) | |||
| 76 | ||||
| 77 | ||||
| 78 | #include "kawethfw.h" | |||
| 79 | ||||
| 80 | #define KAWETH_MTU 1514 | |||
| 81 | #define KAWETH_BUF_SIZE 1664 | |||
| 82 | #define KAWETH_TX_TIMEOUT (5 * HZ) | |||
| 83 | #define KAWETH_SCRATCH_SIZE 32 | |||
| 84 | #define KAWETH_FIRMWARE_BUF_SIZE 4096 | |||
| 85 | #define KAWETH_CONTROL_TIMEOUT (30 * HZ) | |||
| 86 | ||||
| 87 | #define KAWETH_STATUS_BROKEN 0x0000001 | |||
| 88 | #define KAWETH_STATUS_CLOSING 0x0000002 | |||
| 89 | ||||
| 90 | #define KAWETH_PACKET_FILTER_PROMISCUOUS 0x01 | |||
| 91 | #define KAWETH_PACKET_FILTER_ALL_MULTICAST 0x02 | |||
| 92 | #define KAWETH_PACKET_FILTER_DIRECTED 0x04 | |||
| 93 | #define KAWETH_PACKET_FILTER_BROADCAST 0x08 | |||
| 94 | #define KAWETH_PACKET_FILTER_MULTICAST 0x10 | |||
| 95 | ||||
| 96 | /* Table 7 */ | |||
| 97 | #define KAWETH_COMMAND_GET_ETHERNET_DESC 0x00 | |||
| 98 | #define KAWETH_COMMAND_MULTICAST_FILTERS 0x01 | |||
| 99 | #define KAWETH_COMMAND_SET_PACKET_FILTER 0x02 | |||
| 100 | #define KAWETH_COMMAND_STATISTICS 0x03 | |||
| 101 | #define KAWETH_COMMAND_SET_TEMP_MAC 0x06 | |||
| 102 | #define KAWETH_COMMAND_GET_TEMP_MAC 0x07 | |||
| 103 | #define KAWETH_COMMAND_SET_URB_SIZE 0x08 | |||
| 104 | #define KAWETH_COMMAND_SET_SOFS_WAIT 0x09 | |||
| 105 | #define KAWETH_COMMAND_SCAN 0xFF | |||
| 106 | ||||
| 107 | #define KAWETH_SOFS_TO_WAIT 0x05 | |||
| 108 | ||||
| 109 | #define INTBUFFERSIZE 4 | |||
| 110 | ||||
| 111 | #define STATE_OFFSET 0 | |||
| 112 | #define STATE_MASK 0x40 | |||
| 113 | #define STATE_SHIFT 5 | |||
| 114 | ||||
| 115 | ||||
| 116 | 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>"); | |||
| 117 | MODULE_DESCRIPTION("KL5USB101 USB Ethernet driver"); | |||
| 118 | MODULE_LICENSE("GPL"); | |||
| 119 | ||||
| 120 | static const char driver_name[] = "kaweth"; | |||
| 121 | ||||
| 122 | static int kaweth_probe( | |||
| 123 | struct usb_interface *intf, | |||
| 124 | const struct usb_device_id *id /* from id_table */ | |||
| 125 | ); | |||
| 126 | static void kaweth_disconnect(struct usb_interface *intf); | |||
| 127 | static int kaweth_internal_control_msg(struct usb_device *usb_dev, | |||
| 128 | unsigned int pipe, | |||
| 129 | struct usb_ctrlrequest *cmd, void *data, | |||
| 130 | int len, int timeout); | |||
| 131 | ||||
| 132 | /**************************************************************** | |||
| 133 | * usb_device_id | |||
| 134 | ****************************************************************/ | |||
| 135 | static struct usb_device_id usb_klsi_table[] = { | |||
| 136 | { USB_DEVICE(0x03e8, 0x0008) }, /* AOX Endpoints USB Ethernet */ | |||
| 137 | { USB_DEVICE(0x04bb, 0x0901) }, /* I-O DATA USB-ET/T */ | |||
| 138 | { USB_DEVICE(0x0506, 0x03e8) }, /* 3Com 3C19250 */ | |||
| 139 | { USB_DEVICE(0x0506, 0x11f8) }, /* 3Com 3C460 */ | |||
| 140 | { USB_DEVICE(0x0557, 0x2002) }, /* ATEN USB Ethernet */ | |||
| 141 | { USB_DEVICE(0x0557, 0x4000) }, /* D-Link DSB-650C */ | |||
| 142 | { USB_DEVICE(0x0565, 0x0002) }, /* Peracom Enet */ | |||
| 143 | { USB_DEVICE(0x0565, 0x0003) }, /* Optus@Home UEP1045A */ | |||
| 144 | { USB_DEVICE(0x0565, 0x0005) }, /* Peracom Enet2 */ | |||
| 145 | { USB_DEVICE(0x05e9, 0x0008) }, /* KLSI KL5KUSB101B */ | |||
| 146 | { USB_DEVICE(0x05e9, 0x0009) }, /* KLSI KL5KUSB101B (Board change) */ | |||
| 147 | { USB_DEVICE(0x066b, 0x2202) }, /* Linksys USB10T */ | |||
| 148 | { USB_DEVICE(0x06e1, 0x0008) }, /* ADS USB-10BT */ | |||
| 149 | { USB_DEVICE(0x06e1, 0x0009) }, /* ADS USB-10BT */ | |||
| 150 | { USB_DEVICE(0x0707, 0x0100) }, /* SMC 2202USB */ | |||
| 151 | { USB_DEVICE(0x07aa, 0x0001) }, /* Correga K.K. */ | |||
| 152 | { USB_DEVICE(0x07b8, 0x4000) }, /* D-Link DU-E10 */ | |||
| 153 | { USB_DEVICE(0x0846, 0x1001) }, /* NetGear EA-101 */ | |||
| 154 | { USB_DEVICE(0x0846, 0x1002) }, /* NetGear EA-101 */ | |||
| 155 | { USB_DEVICE(0x085a, 0x0008) }, /* PortGear Ethernet Adapter */ | |||
| 156 | { USB_DEVICE(0x085a, 0x0009) }, /* PortGear Ethernet Adapter */ | |||
| 157 | { USB_DEVICE(0x087d, 0x5704) }, /* Jaton USB Ethernet Device Adapter */ | |||
| 158 | { USB_DEVICE(0x0951, 0x0008) }, /* Kingston Technology USB Ethernet Adapter */ | |||
| 159 | { USB_DEVICE(0x095a, 0x3003) }, /* Portsmith Express Ethernet Adapter */ | |||
| 160 | { USB_DEVICE(0x10bd, 0x1427) }, /* ASANTE USB To Ethernet Adapter */ | |||
| 161 | { USB_DEVICE(0x1342, 0x0204) }, /* Mobility USB-Ethernet Adapter */ | |||
| 162 | { USB_DEVICE(0x13d2, 0x0400) }, /* Shark Pocket Adapter */ | |||
| 163 | { USB_DEVICE(0x1485, 0x0001) }, /* Silicom U2E */ | |||
| 164 | { USB_DEVICE(0x1485, 0x0002) }, /* Psion Dacom Gold Port Ethernet */ | |||
| 165 | { USB_DEVICE(0x1645, 0x0005) }, /* Entrega E45 */ | |||
| 166 | { USB_DEVICE(0x1645, 0x0008) }, /* Entrega USB Ethernet Adapter */ | |||
| 167 | { USB_DEVICE(0x1645, 0x8005) }, /* PortGear Ethernet Adapter */ | |||
| 168 | { USB_DEVICE(0x2001, 0x4000) }, /* D-link DSB-650C */ | |||
| 169 | {} /* Null terminator */ | |||
| 170 | }; | |||
| 171 | ||||
| 172 | MODULE_DEVICE_TABLE (usb, usb_klsi_table); | |||
| 173 | ||||
| 174 | /**************************************************************** | |||
| 175 | * kaweth_driver | |||
| 176 | ****************************************************************/ | |||
| 177 | static struct usb_driver kaweth_driver = { | |||
| 178 | .name = driver_name, | |||
| 179 | .probe = kaweth_probe, | |||
| 180 | .disconnect = kaweth_disconnect, | |||
| 181 | .id_table = usb_klsi_table, | |||
| 182 | }; | |||
| 183 | ||||
| 184 | typedef __u8 eth_addr_t[6]; | |||
| 185 | ||||
| 186 | /**************************************************************** | |||
| 187 | * usb_eth_dev | |||
| 188 | ****************************************************************/ | |||
| 189 | struct usb_eth_dev { | |||
| 190 | char *name; | |||
| 191 | __u16 vendor; | |||
| 192 | __u16 device; | |||
| 193 | void *pdata; | |||
| 194 | }; | |||
| 195 | ||||
| 196 | /**************************************************************** | |||
| 197 | * kaweth_ethernet_configuration | |||
| 198 | * Refer Table 8 | |||
| 199 | ****************************************************************/ | |||
| 200 | struct kaweth_ethernet_configuration | |||
| 201 | { | |||
| 202 | __u8 size; | |||
| 203 | __u8 reserved1; | |||
| 204 | __u8 reserved2; | |||
| 205 | eth_addr_t hw_addr; | |||
| 206 | __u32 statistics_mask; | |||
| 207 | __le16 segment_size; | |||
| 208 | __u16 max_multicast_filters; | |||
| 209 | __u8 reserved3; | |||
| 210 | } __attribute__ ((packed)); | |||
| 211 | ||||
| 212 | /**************************************************************** | |||
| 213 | * kaweth_device | |||
| 214 | ****************************************************************/ | |||
| 215 | struct kaweth_device | |||
| 216 | { | |||
| 217 | spinlock_t device_lock; | |||
| 218 | ||||
| 219 | __u32 status; | |||
| 220 | int end; | |||
| 221 | int suspend_lowmem_rx; | |||
| 222 | int suspend_lowmem_ctrl; | |||
| 223 | int linkstate; | |||
| 224 | struct work_struct lowmem_work; | |||
| 225 | ||||
| 226 | struct usb_device *dev; | |||
| 227 | struct net_device *net; | |||
| 228 | wait_queue_head_t term_wait; | |||
| 229 | ||||
| 230 | struct urb *rx_urb; | |||
| 231 | struct urb *tx_urb; | |||
| 232 | struct urb *irq_urb; | |||
| 233 | ||||
| 234 | dma_addr_t intbufferhandle; | |||
| 235 | __u8 *intbuffer; | |||
| 236 | dma_addr_t rxbufferhandle; | |||
| 237 | __u8 *rx_buf; | |||
| 238 | ||||
| 239 | ||||
| 240 | struct sk_buff *tx_skb; | |||
| 241 | ||||
| 242 | __u8 *firmware_buf; | |||
| 243 | __u8 scratch[KAWETH_SCRATCH_SIZE]; | |||
| 244 | __u16 packet_filter_bitmap; | |||
| 245 | ||||
| 246 | struct kaweth_ethernet_configuration configuration; | |||
| 247 | ||||
| 248 | struct net_device_stats stats; | |||
| 249 | }; | |||
| 250 | ||||
| 251 | ||||
| 252 | /**************************************************************** | |||
| 253 | * kaweth_control | |||
| 254 | ****************************************************************/ | |||
| 0 | 0 | - | 255 | static int kaweth_control(struct kaweth_device *kaweth, |
| 256 | unsigned int pipe, | |||
| 257 | __u8 request, | |||
| 258 | __u8 requesttype, | |||
| 259 | __u16 value, | |||
| 260 | __u16 index, | |||
| 261 | void *data, | |||
| 262 | __u16 size, | |||
| 263 | int timeout) | |||
| 264 | { | |||
| 265 | struct usb_ctrlrequest *dr; | |||
| 266 | ||||
| 267 | kaweth_dbg("kaweth_control()"); | |||
| 0 | 0 | - | 267 | do-while (0) |
| 268 | ||||
| 0 | 0 | - | 269 | if(in_interrupt()) { |
| 270 | kaweth_dbg("in_interrupt()"); | |||
| 0 | 0 | - | 270 | do-while (0) |
| 0 | - | 271 | return -EBUSY; | |
| 272 | } | |||
| 273 | ||||
| 274 | dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC); | |||
| 275 | ||||
| 0 | 0 | - | 276 | if (!dr) { |
| 277 | kaweth_dbg("kmalloc() failed"); | |||
| 0 | 0 | - | 277 | do-while (0) |
| 0 | - | 278 | return -ENOMEM; | |
| 279 | } | |||
| 280 | ||||
| 281 | dr->bRequestType= requesttype; | |||
| 282 | dr->bRequest = request; | |||
| 283 | dr->wValue = cpu_to_le16p(&value); | |||
| 284 | dr->wIndex = cpu_to_le16p(&index); | |||
| 285 | dr->wLength = cpu_to_le16p(&size); | |||
| 286 | ||||
| 287 | return kaweth_internal_control_msg(kaweth->dev, | |||
| 288 | pipe, | |||
| 289 | dr, | |||
| 290 | data, | |||
| 291 | size, | |||
| 0 | - | 292 | timeout); | |
| 293 | } | |||
| 294 | ||||
| 295 | /**************************************************************** | |||
| 296 | * kaweth_read_configuration | |||
| 297 | ****************************************************************/ | |||
| 0 | 0 | - | 298 | static int kaweth_read_configuration(struct kaweth_device *kaweth) |
| 299 | { | |||
| 300 | int retval; | |||
| 301 | ||||
| 302 | kaweth_dbg("Reading kaweth configuration"); | |||
| 0 | 0 | - | 302 | do-while (0) |
| 303 | ||||
| 304 | retval = kaweth_control(kaweth, | |||
| 305 | usb_rcvctrlpipe(kaweth->dev, 0), | |||
| 306 | KAWETH_COMMAND_GET_ETHERNET_DESC, | |||
| 307 | USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE, | |||
| 308 | 0, | |||
| 309 | 0, | |||
| 310 | (void *)&kaweth->configuration, | |||
| 311 | sizeof(kaweth->configuration), | |||
| 312 | KAWETH_CONTROL_TIMEOUT); | |||
| 313 | ||||
| 0 | - | 314 | return retval; | |
| 315 | } | |||
| 316 | ||||
| 317 | /**************************************************************** | |||
| 318 | * kaweth_set_urb_size | |||
| 319 | ****************************************************************/ | |||
| 0 | 0 | - | 320 | static int kaweth_set_urb_size(struct kaweth_device *kaweth, __u16 urb_size) |
| 321 | { | |||
| 322 | int retval; | |||
| 323 | ||||
| 324 | kaweth_dbg("Setting URB size to %d", (unsigned)urb_size); | |||
| 0 | 0 | - | 324 | do-while (0) |
| 325 | ||||
| 326 | retval = kaweth_control(kaweth, | |||
| 327 | usb_sndctrlpipe(kaweth->dev, 0), | |||
| 328 | KAWETH_COMMAND_SET_URB_SIZE, | |||
| 329 | USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, | |||
| 330 | urb_size, | |||
| 331 | 0, | |||
| 332 | (void *)&kaweth->scratch, | |||
| 333 | 0, | |||
| 334 | KAWETH_CONTROL_TIMEOUT); | |||
| 335 | ||||
| 0 | - | 336 | return retval; | |
| 337 | } | |||
| 338 | ||||
| 339 | /**************************************************************** | |||
| 340 | * kaweth_set_sofs_wait | |||
| 341 | ****************************************************************/ | |||
| 0 | 0 | - | 342 | static int kaweth_set_sofs_wait(struct kaweth_device *kaweth, __u16 sofs_wait) |
| 343 | { | |||
| 344 | int retval; | |||
| 345 | ||||
| 346 | kaweth_dbg("Set SOFS wait to %d", (unsigned)sofs_wait); | |||
| 0 | 0 | - | 346 | do-while (0) |
| 347 | ||||
| 348 | retval = kaweth_control(kaweth, | |||
| 349 | usb_sndctrlpipe(kaweth->dev, 0), | |||
| 350 | KAWETH_COMMAND_SET_SOFS_WAIT, | |||
| 351 | USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, | |||
| 352 | sofs_wait, | |||
| 353 | 0, | |||
| 354 | (void *)&kaweth->scratch, | |||
| 355 | 0, | |||
| 356 | KAWETH_CONTROL_TIMEOUT); | |||
| 357 | ||||
| 0 | - | 358 | return retval; | |
| 359 | } | |||
| 360 | ||||
| 361 | /**************************************************************** | |||
| 362 | * kaweth_set_receive_filter | |||
| 363 | ****************************************************************/ | |||
| 0 | 0 | - | 364 | static int kaweth_set_receive_filter(struct kaweth_device *kaweth, |
| 365 | __u16 receive_filter) | |||
| 366 | { | |||
| 367 | int retval; | |||
| 368 | ||||
| 369 | kaweth_dbg("Set receive filter to %d", (unsigned)receive_filter); | |||
| 0 | 0 | - | 369 | do-while (0) |
| 370 | ||||
| 371 | retval = kaweth_control(kaweth, | |||
| 372 | usb_sndctrlpipe(kaweth->dev, 0), | |||
| 373 | KAWETH_COMMAND_SET_PACKET_FILTER, | |||
| 374 | USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, | |||
| 375 | receive_filter, | |||
| 376 | 0, | |||
| 377 | (void *)&kaweth->scratch, | |||
| 378 | 0, | |||
| 379 | KAWETH_CONTROL_TIMEOUT); | |||
| 380 | ||||
| 0 | - | 381 | return retval; | |
| 382 | } | |||
| 383 | ||||
| 384 | /**************************************************************** | |||
| 385 | * kaweth_download_firmware | |||
| 386 | ****************************************************************/ | |||
| 0 | 0 | - | 387 | static int kaweth_download_firmware(struct kaweth_device *kaweth, |
| 388 | __u8 *data, | |||
| 389 | __u16 data_len, | |||
| 390 | __u8 interrupt, | |||
| 391 | __u8 type) | |||
| 392 | { | |||
| 0 | 0 | - | 393 | if(data_len > KAWETH_FIRMWARE_BUF_SIZE) { |
| 394 | kaweth_err("Firmware too big: %d", data_len); | |||
| 0 | - | 395 | return -ENOSPC; | |
| 396 | } | |||
| 397 | ||||
| 398 | memcpy(kaweth->firmware_buf, data, data_len); | |||
| 399 | ||||
| 400 | kaweth->firmware_buf[2] = (data_len & 0xFF) - 7; | |||
| 401 | kaweth->firmware_buf[3] = data_len >> 8; | |||
| 402 | kaweth->firmware_buf[4] = type; | |||
| 403 | kaweth->firmware_buf[5] = interrupt; | |||
| 404 | ||||
| 405 | kaweth_dbg("High: %i, Low:%i", kaweth->firmware_buf[3], | |||
| 0 | 0 | - | 405 | do-while (0) |
| 406 | kaweth->firmware_buf[2]); | |||
| 407 | ||||
| 408 | kaweth_dbg("Downloading firmware at %p to kaweth device at %p", | |||
| 0 | 0 | - | 408 | do-while (0) |
| 409 | data, | |||
| 410 | kaweth); | |||
| 411 | kaweth_dbg("Firmware length: %d", data_len); | |||
| 0 | 0 | - | 411 | do-while (0) |
| 412 | ||||
| 413 | return kaweth_control(kaweth, | |||
| 414 | usb_sndctrlpipe(kaweth->dev, 0), | |||
| 415 | KAWETH_COMMAND_SCAN, | |||
| 416 | USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, | |||
| 417 | 0, | |||
| 418 | 0, | |||
| 419 | (void *)kaweth->firmware_buf, | |||
| 420 | data_len, | |||
| 0 | - | 421 | KAWETH_CONTROL_TIMEOUT); | |
| 422 | } | |||
| 423 | ||||
| 424 | /**************************************************************** | |||
| 425 | * kaweth_trigger_firmware | |||
| 426 | ****************************************************************/ | |||
| 0 | 0 | - | 427 | static int kaweth_trigger_firmware(struct kaweth_device *kaweth, |
| 428 | __u8 interrupt) | |||
| 429 | { | |||
| 430 | kaweth->firmware_buf[0] = 0xB6; | |||
| 431 | kaweth->firmware_buf[1] = 0xC3; | |||
| 432 | kaweth->firmware_buf[2] = 0x01; | |||
| 433 | kaweth->firmware_buf[3] = 0x00; | |||
| 434 | kaweth->firmware_buf[4] = 0x06; | |||
| 435 | kaweth->firmware_buf[5] = interrupt; | |||
| 436 | kaweth->firmware_buf[6] = 0x00; | |||
| 437 | kaweth->firmware_buf[7] = 0x00; | |||
| 438 | ||||
| 439 | kaweth_dbg("Triggering firmware"); | |||
| 0 | 0 | - | 439 | do-while (0) |
| 440 | ||||
| 441 | return kaweth_control(kaweth, | |||
| 442 | usb_sndctrlpipe(kaweth->dev, 0), | |||
| 443 | KAWETH_COMMAND_SCAN, | |||
| 444 | USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, | |||
| 445 | 0, | |||
| 446 | 0, | |||
| 447 | (void *)kaweth->firmware_buf, | |||
| 448 | 8, | |||
| 0 | - | 449 | KAWETH_CONTROL_TIMEOUT); | |
| 450 | } | |||
| 451 | ||||
| 452 | /**************************************************************** | |||
| 453 | * kaweth_reset | |||
| 454 | ****************************************************************/ | |||
| 0 | 0 | - | 455 | static int kaweth_reset(struct kaweth_device *kaweth) |
| 456 | { | |||
| 457 | int result; | |||
| 458 | ||||
| 459 | kaweth_dbg("kaweth_reset(%p)", kaweth); | |||
| 0 | 0 | - | 459 | do-while (0) |
| 460 | result = kaweth_control(kaweth, | |||
| 461 | usb_sndctrlpipe(kaweth->dev, 0), | |||
| 462 | USB_REQ_SET_CONFIGURATION, | |||
| 463 | 0, | |||
| 464 | kaweth->dev->config[0].desc.bConfigurationValue, | |||
| 465 | 0, | |||
| 466 | NULL, | |||
| 467 | 0, | |||
| 468 | KAWETH_CONTROL_TIMEOUT); | |||
| 469 | ||||
| 470 | mdelay(10); | |||
| 0 | 0 | - | 470 | ternary-?: ( __builtin_constant_p ( 10 ) && ( .. |
| 0 | 0 | - | 470 | ternary-?: __builtin_constant_p ( ( 10 ) * 100.. |
| 0 | 0 | - | 470 | ternary-?: ( ( 10 ) * 1000 ) > 20000 |
| 471 | ||||
| 472 | kaweth_dbg("kaweth_reset() returns %d.",result); | |||
| 0 | 0 | - | 472 | do-while (0) |
| 473 | ||||
| 0 | - | 474 | return result; | |
| 475 | } | |||
| 476 | ||||
| 477 | static void kaweth_usb_receive(struct urb *, struct pt_regs *regs); | |||
| 478 | static int kaweth_resubmit_rx_urb(struct kaweth_device *, gfp_t); | |||
| 479 | ||||
| 480 | /**************************************************************** | |||
| 481 | int_callback | |||
| 482 | *****************************************************************/ | |||
| 483 | ||||
| 0 | 0 | - | 484 | static void kaweth_resubmit_int_urb(struct kaweth_device *kaweth, gfp_t mf) |
| 485 | { | |||
| 486 | int status; | |||
| 487 | ||||
| 488 | status = usb_submit_urb (kaweth->irq_urb, mf); | |||
| 0 | 0 | - | 489 | if (unlikely(status == -ENOMEM)) { |
| 490 | kaweth->suspend_lowmem_ctrl = 1; | |||
| 491 | schedule_delayed_work(&kaweth->lowmem_work, HZ/4); | |||
| 492 | } else { | |||
| 493 | kaweth->suspend_lowmem_ctrl = 0; | |||
| 494 | } | |||
| 495 | ||||
| 0 | 0 | - | 496 | if (status) |
| 497 | err ("can't resubmit intr, %s-%s, status %d", | |||
| 498 | kaweth->dev->bus->bus_name, | |||
| 499 | kaweth->dev->devpath, status); | |||
| 500 | } | |||
| 501 | ||||
| 0 | 0 | - | 502 | static void int_callback(struct urb *u, struct pt_regs *regs) |
| 503 | { | |||
| 504 | struct kaweth_device *kaweth = u->context; | |||
| 505 | int act_state; | |||
| 506 | ||||
| 507 | switch (u->status) { | |||
| 0 | - | 508 | case 0: /* success */ | |
| 0 | - | 509 | break; | |
| 0 | - | 510 | case -ECONNRESET: /* unlink */ | |
| 0 | - | 511 | case -ENOENT: | |
| 0 | - | 512 | case -ESHUTDOWN: | |
| 0 | - | 513 | return; | |
| 514 | /* -EPIPE: should clear the halt */ | |||
| 0 | - | 515 | default: /* error */ | |
| 0 | - | 516 | goto resubmit; | |
| 517 | } | |||
| 518 | ||||
| 519 | /* we check the link state to report changes */ | |||
| 0 | 0 | - | 520 | if (kaweth->linkstate != (act_state = ( kaweth->intbuffer[STATE_OFFSET] | STATE_MASK) >> STATE_SHIFT)) { |
| 0 | 0 | - | 521 | if (act_state) |
| 522 | netif_carrier_on(kaweth->net); | |||
| 523 | else | |||
| 524 | netif_carrier_off(kaweth->net); | |||
| 525 | ||||
| 526 | kaweth->linkstate = act_state; | |||
| 527 | } | |||
| 528 | resubmit: | |||
| 529 | kaweth_resubmit_int_urb(kaweth, GFP_ATOMIC); | |||
| 530 | } | |||
| 531 | ||||
| 0 | 0 | - | 532 | static void kaweth_resubmit_tl(void *d) |
| 533 | { | |||
| 534 | struct kaweth_device *kaweth = (struct kaweth_device *)d; | |||
| 535 | ||||
| 0 | 0 | - | 536 | if (kaweth->status | KAWETH_STATUS_CLOSING) |
| 0 | - | 537 | return; | |
| 538 | ||||
| 0 | 0 | - | 539 | if (kaweth->suspend_lowmem_rx) |
| 540 | kaweth_resubmit_rx_urb(kaweth, GFP_NOIO); | |||
| 541 | ||||
| 0 | 0 | - | 542 | if (kaweth->suspend_lowmem_ctrl) |
| 543 | kaweth_resubmit_int_urb(kaweth, GFP_NOIO); | |||
| 544 | } | |||
| 545 | ||||
| 546 | ||||
| 547 | /**************************************************************** | |||
| 548 | * kaweth_resubmit_rx_urb | |||
| 549 | ****************************************************************/ | |||
| 0 | 0 | - | 550 | static int kaweth_resubmit_rx_urb(struct kaweth_device *kaweth, |
| 551 | &nbs | |||