1*5b2fc499SJeff Garzik /* 2*5b2fc499SJeff Garzik * Copyright (c) 1999-2005 Petko Manolov (petkan@users.sourceforge.net) 3*5b2fc499SJeff Garzik * 4*5b2fc499SJeff Garzik * This program is free software; you can redistribute it and/or modify 5*5b2fc499SJeff Garzik * it under the terms of the GNU General Public License version 2 as 6*5b2fc499SJeff Garzik * published by the Free Software Foundation. 7*5b2fc499SJeff Garzik * 8*5b2fc499SJeff Garzik * ChangeLog: 9*5b2fc499SJeff Garzik * .... Most of the time spent on reading sources & docs. 10*5b2fc499SJeff Garzik * v0.2.x First official release for the Linux kernel. 11*5b2fc499SJeff Garzik * v0.3.0 Beutified and structured, some bugs fixed. 12*5b2fc499SJeff Garzik * v0.3.x URBifying bulk requests and bugfixing. First relatively 13*5b2fc499SJeff Garzik * stable release. Still can touch device's registers only 14*5b2fc499SJeff Garzik * from top-halves. 15*5b2fc499SJeff Garzik * v0.4.0 Control messages remained unurbified are now URBs. 16*5b2fc499SJeff Garzik * Now we can touch the HW at any time. 17*5b2fc499SJeff Garzik * v0.4.9 Control urbs again use process context to wait. Argh... 18*5b2fc499SJeff Garzik * Some long standing bugs (enable_net_traffic) fixed. 19*5b2fc499SJeff Garzik * Also nasty trick about resubmiting control urb from 20*5b2fc499SJeff Garzik * interrupt context used. Please let me know how it 21*5b2fc499SJeff Garzik * behaves. Pegasus II support added since this version. 22*5b2fc499SJeff Garzik * TODO: suppressing HCD warnings spewage on disconnect. 23*5b2fc499SJeff Garzik * v0.4.13 Ethernet address is now set at probe(), not at open() 24*5b2fc499SJeff Garzik * time as this seems to break dhcpd. 25*5b2fc499SJeff Garzik * v0.5.0 branch to 2.5.x kernels 26*5b2fc499SJeff Garzik * v0.5.1 ethtool support added 27*5b2fc499SJeff Garzik * v0.5.5 rx socket buffers are in a pool and the their allocation 28*5b2fc499SJeff Garzik * is out of the interrupt routine. 29*5b2fc499SJeff Garzik */ 30*5b2fc499SJeff Garzik 31*5b2fc499SJeff Garzik #include <linux/sched.h> 32*5b2fc499SJeff Garzik #include <linux/slab.h> 33*5b2fc499SJeff Garzik #include <linux/init.h> 34*5b2fc499SJeff Garzik #include <linux/delay.h> 35*5b2fc499SJeff Garzik #include <linux/netdevice.h> 36*5b2fc499SJeff Garzik #include <linux/etherdevice.h> 37*5b2fc499SJeff Garzik #include <linux/ethtool.h> 38*5b2fc499SJeff Garzik #include <linux/mii.h> 39*5b2fc499SJeff Garzik #include <linux/usb.h> 40*5b2fc499SJeff Garzik #include <linux/module.h> 41*5b2fc499SJeff Garzik #include <asm/byteorder.h> 42*5b2fc499SJeff Garzik #include <asm/uaccess.h> 43*5b2fc499SJeff Garzik #include "pegasus.h" 44*5b2fc499SJeff Garzik 45*5b2fc499SJeff Garzik /* 46*5b2fc499SJeff Garzik * Version Information 47*5b2fc499SJeff Garzik */ 48*5b2fc499SJeff Garzik #define DRIVER_VERSION "v0.6.14 (2006/09/27)" 49*5b2fc499SJeff Garzik #define DRIVER_AUTHOR "Petko Manolov <petkan@users.sourceforge.net>" 50*5b2fc499SJeff Garzik #define DRIVER_DESC "Pegasus/Pegasus II USB Ethernet driver" 51*5b2fc499SJeff Garzik 52*5b2fc499SJeff Garzik static const char driver_name[] = "pegasus"; 53*5b2fc499SJeff Garzik 54*5b2fc499SJeff Garzik #undef PEGASUS_WRITE_EEPROM 55*5b2fc499SJeff Garzik #define BMSR_MEDIA (BMSR_10HALF | BMSR_10FULL | BMSR_100HALF | \ 56*5b2fc499SJeff Garzik BMSR_100FULL | BMSR_ANEGCAPABLE) 57*5b2fc499SJeff Garzik 58*5b2fc499SJeff Garzik static int loopback = 0; 59*5b2fc499SJeff Garzik static int mii_mode = 0; 60*5b2fc499SJeff Garzik static char *devid=NULL; 61*5b2fc499SJeff Garzik 62*5b2fc499SJeff Garzik static struct usb_eth_dev usb_dev_id[] = { 63*5b2fc499SJeff Garzik #define PEGASUS_DEV(pn, vid, pid, flags) \ 64*5b2fc499SJeff Garzik {.name = pn, .vendor = vid, .device = pid, .private = flags}, 65*5b2fc499SJeff Garzik #include "pegasus.h" 66*5b2fc499SJeff Garzik #undef PEGASUS_DEV 67*5b2fc499SJeff Garzik {NULL, 0, 0, 0}, 68*5b2fc499SJeff Garzik {NULL, 0, 0, 0} 69*5b2fc499SJeff Garzik }; 70*5b2fc499SJeff Garzik 71*5b2fc499SJeff Garzik static struct usb_device_id pegasus_ids[] = { 72*5b2fc499SJeff Garzik #define PEGASUS_DEV(pn, vid, pid, flags) \ 73*5b2fc499SJeff Garzik {.match_flags = USB_DEVICE_ID_MATCH_DEVICE, .idVendor = vid, .idProduct = pid}, 74*5b2fc499SJeff Garzik #include "pegasus.h" 75*5b2fc499SJeff Garzik #undef PEGASUS_DEV 76*5b2fc499SJeff Garzik {}, 77*5b2fc499SJeff Garzik {} 78*5b2fc499SJeff Garzik }; 79*5b2fc499SJeff Garzik 80*5b2fc499SJeff Garzik MODULE_AUTHOR(DRIVER_AUTHOR); 81*5b2fc499SJeff Garzik MODULE_DESCRIPTION(DRIVER_DESC); 82*5b2fc499SJeff Garzik MODULE_LICENSE("GPL"); 83*5b2fc499SJeff Garzik module_param(loopback, bool, 0); 84*5b2fc499SJeff Garzik module_param(mii_mode, bool, 0); 85*5b2fc499SJeff Garzik module_param(devid, charp, 0); 86*5b2fc499SJeff Garzik MODULE_PARM_DESC(loopback, "Enable MAC loopback mode (bit 0)"); 87*5b2fc499SJeff Garzik MODULE_PARM_DESC(mii_mode, "Enable HomePNA mode (bit 0),default=MII mode = 0"); 88*5b2fc499SJeff Garzik MODULE_PARM_DESC(devid, "The format is: 'DEV_name:VendorID:DeviceID:Flags'"); 89*5b2fc499SJeff Garzik 90*5b2fc499SJeff Garzik /* use ethtool to change the level for any given device */ 91*5b2fc499SJeff Garzik static int msg_level = -1; 92*5b2fc499SJeff Garzik module_param (msg_level, int, 0); 93*5b2fc499SJeff Garzik MODULE_PARM_DESC (msg_level, "Override default message level"); 94*5b2fc499SJeff Garzik 95*5b2fc499SJeff Garzik MODULE_DEVICE_TABLE(usb, pegasus_ids); 96*5b2fc499SJeff Garzik 97*5b2fc499SJeff Garzik static int update_eth_regs_async(pegasus_t *); 98*5b2fc499SJeff Garzik /* Aargh!!! I _really_ hate such tweaks */ 99*5b2fc499SJeff Garzik static void ctrl_callback(struct urb *urb) 100*5b2fc499SJeff Garzik { 101*5b2fc499SJeff Garzik pegasus_t *pegasus = urb->context; 102*5b2fc499SJeff Garzik 103*5b2fc499SJeff Garzik if (!pegasus) 104*5b2fc499SJeff Garzik return; 105*5b2fc499SJeff Garzik 106*5b2fc499SJeff Garzik switch (urb->status) { 107*5b2fc499SJeff Garzik case 0: 108*5b2fc499SJeff Garzik if (pegasus->flags & ETH_REGS_CHANGE) { 109*5b2fc499SJeff Garzik pegasus->flags &= ~ETH_REGS_CHANGE; 110*5b2fc499SJeff Garzik pegasus->flags |= ETH_REGS_CHANGED; 111*5b2fc499SJeff Garzik update_eth_regs_async(pegasus); 112*5b2fc499SJeff Garzik return; 113*5b2fc499SJeff Garzik } 114*5b2fc499SJeff Garzik break; 115*5b2fc499SJeff Garzik case -EINPROGRESS: 116*5b2fc499SJeff Garzik return; 117*5b2fc499SJeff Garzik case -ENOENT: 118*5b2fc499SJeff Garzik break; 119*5b2fc499SJeff Garzik default: 120*5b2fc499SJeff Garzik if (netif_msg_drv(pegasus)) 121*5b2fc499SJeff Garzik dev_dbg(&pegasus->intf->dev, "%s, status %d\n", 122*5b2fc499SJeff Garzik __FUNCTION__, urb->status); 123*5b2fc499SJeff Garzik } 124*5b2fc499SJeff Garzik pegasus->flags &= ~ETH_REGS_CHANGED; 125*5b2fc499SJeff Garzik wake_up(&pegasus->ctrl_wait); 126*5b2fc499SJeff Garzik } 127*5b2fc499SJeff Garzik 128*5b2fc499SJeff Garzik static int get_registers(pegasus_t * pegasus, __u16 indx, __u16 size, 129*5b2fc499SJeff Garzik void *data) 130*5b2fc499SJeff Garzik { 131*5b2fc499SJeff Garzik int ret; 132*5b2fc499SJeff Garzik char *buffer; 133*5b2fc499SJeff Garzik DECLARE_WAITQUEUE(wait, current); 134*5b2fc499SJeff Garzik 135*5b2fc499SJeff Garzik buffer = kmalloc(size, GFP_KERNEL); 136*5b2fc499SJeff Garzik if (!buffer) { 137*5b2fc499SJeff Garzik if (netif_msg_drv(pegasus)) 138*5b2fc499SJeff Garzik dev_warn(&pegasus->intf->dev, "out of memory in %s\n", 139*5b2fc499SJeff Garzik __FUNCTION__); 140*5b2fc499SJeff Garzik return -ENOMEM; 141*5b2fc499SJeff Garzik } 142*5b2fc499SJeff Garzik add_wait_queue(&pegasus->ctrl_wait, &wait); 143*5b2fc499SJeff Garzik set_current_state(TASK_UNINTERRUPTIBLE); 144*5b2fc499SJeff Garzik while (pegasus->flags & ETH_REGS_CHANGED) 145*5b2fc499SJeff Garzik schedule(); 146*5b2fc499SJeff Garzik remove_wait_queue(&pegasus->ctrl_wait, &wait); 147*5b2fc499SJeff Garzik set_current_state(TASK_RUNNING); 148*5b2fc499SJeff Garzik 149*5b2fc499SJeff Garzik pegasus->dr.bRequestType = PEGASUS_REQT_READ; 150*5b2fc499SJeff Garzik pegasus->dr.bRequest = PEGASUS_REQ_GET_REGS; 151*5b2fc499SJeff Garzik pegasus->dr.wValue = cpu_to_le16(0); 152*5b2fc499SJeff Garzik pegasus->dr.wIndex = cpu_to_le16p(&indx); 153*5b2fc499SJeff Garzik pegasus->dr.wLength = cpu_to_le16p(&size); 154*5b2fc499SJeff Garzik pegasus->ctrl_urb->transfer_buffer_length = size; 155*5b2fc499SJeff Garzik 156*5b2fc499SJeff Garzik usb_fill_control_urb(pegasus->ctrl_urb, pegasus->usb, 157*5b2fc499SJeff Garzik usb_rcvctrlpipe(pegasus->usb, 0), 158*5b2fc499SJeff Garzik (char *) &pegasus->dr, 159*5b2fc499SJeff Garzik buffer, size, ctrl_callback, pegasus); 160*5b2fc499SJeff Garzik 161*5b2fc499SJeff Garzik add_wait_queue(&pegasus->ctrl_wait, &wait); 162*5b2fc499SJeff Garzik set_current_state(TASK_UNINTERRUPTIBLE); 163*5b2fc499SJeff Garzik 164*5b2fc499SJeff Garzik /* using ATOMIC, we'd never wake up if we slept */ 165*5b2fc499SJeff Garzik if ((ret = usb_submit_urb(pegasus->ctrl_urb, GFP_ATOMIC))) { 166*5b2fc499SJeff Garzik set_current_state(TASK_RUNNING); 167*5b2fc499SJeff Garzik if (ret == -ENODEV) 168*5b2fc499SJeff Garzik netif_device_detach(pegasus->net); 169*5b2fc499SJeff Garzik if (netif_msg_drv(pegasus)) 170*5b2fc499SJeff Garzik dev_err(&pegasus->intf->dev, "%s, status %d\n", 171*5b2fc499SJeff Garzik __FUNCTION__, ret); 172*5b2fc499SJeff Garzik goto out; 173*5b2fc499SJeff Garzik } 174*5b2fc499SJeff Garzik 175*5b2fc499SJeff Garzik schedule(); 176*5b2fc499SJeff Garzik out: 177*5b2fc499SJeff Garzik remove_wait_queue(&pegasus->ctrl_wait, &wait); 178*5b2fc499SJeff Garzik memcpy(data, buffer, size); 179*5b2fc499SJeff Garzik kfree(buffer); 180*5b2fc499SJeff Garzik 181*5b2fc499SJeff Garzik return ret; 182*5b2fc499SJeff Garzik } 183*5b2fc499SJeff Garzik 184*5b2fc499SJeff Garzik static int set_registers(pegasus_t * pegasus, __u16 indx, __u16 size, 185*5b2fc499SJeff Garzik void *data) 186*5b2fc499SJeff Garzik { 187*5b2fc499SJeff Garzik int ret; 188*5b2fc499SJeff Garzik char *buffer; 189*5b2fc499SJeff Garzik DECLARE_WAITQUEUE(wait, current); 190*5b2fc499SJeff Garzik 191*5b2fc499SJeff Garzik buffer = kmalloc(size, GFP_KERNEL); 192*5b2fc499SJeff Garzik if (!buffer) { 193*5b2fc499SJeff Garzik if (netif_msg_drv(pegasus)) 194*5b2fc499SJeff Garzik dev_warn(&pegasus->intf->dev, "out of memory in %s\n", 195*5b2fc499SJeff Garzik __FUNCTION__); 196*5b2fc499SJeff Garzik return -ENOMEM; 197*5b2fc499SJeff Garzik } 198*5b2fc499SJeff Garzik memcpy(buffer, data, size); 199*5b2fc499SJeff Garzik 200*5b2fc499SJeff Garzik add_wait_queue(&pegasus->ctrl_wait, &wait); 201*5b2fc499SJeff Garzik set_current_state(TASK_UNINTERRUPTIBLE); 202*5b2fc499SJeff Garzik while (pegasus->flags & ETH_REGS_CHANGED) 203*5b2fc499SJeff Garzik schedule(); 204*5b2fc499SJeff Garzik remove_wait_queue(&pegasus->ctrl_wait, &wait); 205*5b2fc499SJeff Garzik set_current_state(TASK_RUNNING); 206*5b2fc499SJeff Garzik 207*5b2fc499SJeff Garzik pegasus->dr.bRequestType = PEGASUS_REQT_WRITE; 208*5b2fc499SJeff Garzik pegasus->dr.bRequest = PEGASUS_REQ_SET_REGS; 209*5b2fc499SJeff Garzik pegasus->dr.wValue = cpu_to_le16(0); 210*5b2fc499SJeff Garzik pegasus->dr.wIndex = cpu_to_le16p(&indx); 211*5b2fc499SJeff Garzik pegasus->dr.wLength = cpu_to_le16p(&size); 212*5b2fc499SJeff Garzik pegasus->ctrl_urb->transfer_buffer_length = size; 213*5b2fc499SJeff Garzik 214*5b2fc499SJeff Garzik usb_fill_control_urb(pegasus->ctrl_urb, pegasus->usb, 215*5b2fc499SJeff Garzik usb_sndctrlpipe(pegasus->usb, 0), 216*5b2fc499SJeff Garzik (char *) &pegasus->dr, 217*5b2fc499SJeff Garzik buffer, size, ctrl_callback, pegasus); 218*5b2fc499SJeff Garzik 219*5b2fc499SJeff Garzik add_wait_queue(&pegasus->ctrl_wait, &wait); 220*5b2fc499SJeff Garzik set_current_state(TASK_UNINTERRUPTIBLE); 221*5b2fc499SJeff Garzik 222*5b2fc499SJeff Garzik if ((ret = usb_submit_urb(pegasus->ctrl_urb, GFP_ATOMIC))) { 223*5b2fc499SJeff Garzik if (ret == -ENODEV) 224*5b2fc499SJeff Garzik netif_device_detach(pegasus->net); 225*5b2fc499SJeff Garzik if (netif_msg_drv(pegasus)) 226*5b2fc499SJeff Garzik dev_err(&pegasus->intf->dev, "%s, status %d\n", 227*5b2fc499SJeff Garzik __FUNCTION__, ret); 228*5b2fc499SJeff Garzik goto out; 229*5b2fc499SJeff Garzik } 230*5b2fc499SJeff Garzik 231*5b2fc499SJeff Garzik schedule(); 232*5b2fc499SJeff Garzik out: 233*5b2fc499SJeff Garzik remove_wait_queue(&pegasus->ctrl_wait, &wait); 234*5b2fc499SJeff Garzik kfree(buffer); 235*5b2fc499SJeff Garzik 236*5b2fc499SJeff Garzik return ret; 237*5b2fc499SJeff Garzik } 238*5b2fc499SJeff Garzik 239*5b2fc499SJeff Garzik static int set_register(pegasus_t * pegasus, __u16 indx, __u8 data) 240*5b2fc499SJeff Garzik { 241*5b2fc499SJeff Garzik int ret; 242*5b2fc499SJeff Garzik char *tmp; 243*5b2fc499SJeff Garzik DECLARE_WAITQUEUE(wait, current); 244*5b2fc499SJeff Garzik 245*5b2fc499SJeff Garzik tmp = kmalloc(1, GFP_KERNEL); 246*5b2fc499SJeff Garzik if (!tmp) { 247*5b2fc499SJeff Garzik if (netif_msg_drv(pegasus)) 248*5b2fc499SJeff Garzik dev_warn(&pegasus->intf->dev, "out of memory in %s\n", 249*5b2fc499SJeff Garzik __FUNCTION__); 250*5b2fc499SJeff Garzik return -ENOMEM; 251*5b2fc499SJeff Garzik } 252*5b2fc499SJeff Garzik memcpy(tmp, &data, 1); 253*5b2fc499SJeff Garzik add_wait_queue(&pegasus->ctrl_wait, &wait); 254*5b2fc499SJeff Garzik set_current_state(TASK_UNINTERRUPTIBLE); 255*5b2fc499SJeff Garzik while (pegasus->flags & ETH_REGS_CHANGED) 256*5b2fc499SJeff Garzik schedule(); 257*5b2fc499SJeff Garzik remove_wait_queue(&pegasus->ctrl_wait, &wait); 258*5b2fc499SJeff Garzik set_current_state(TASK_RUNNING); 259*5b2fc499SJeff Garzik 260*5b2fc499SJeff Garzik pegasus->dr.bRequestType = PEGASUS_REQT_WRITE; 261*5b2fc499SJeff Garzik pegasus->dr.bRequest = PEGASUS_REQ_SET_REG; 262*5b2fc499SJeff Garzik pegasus->dr.wValue = cpu_to_le16(data); 263*5b2fc499SJeff Garzik pegasus->dr.wIndex = cpu_to_le16p(&indx); 264*5b2fc499SJeff Garzik pegasus->dr.wLength = cpu_to_le16(1); 265*5b2fc499SJeff Garzik pegasus->ctrl_urb->transfer_buffer_length = 1; 266*5b2fc499SJeff Garzik 267*5b2fc499SJeff Garzik usb_fill_control_urb(pegasus->ctrl_urb, pegasus->usb, 268*5b2fc499SJeff Garzik usb_sndctrlpipe(pegasus->usb, 0), 269*5b2fc499SJeff Garzik (char *) &pegasus->dr, 270*5b2fc499SJeff Garzik tmp, 1, ctrl_callback, pegasus); 271*5b2fc499SJeff Garzik 272*5b2fc499SJeff Garzik add_wait_queue(&pegasus->ctrl_wait, &wait); 273*5b2fc499SJeff Garzik set_current_state(TASK_UNINTERRUPTIBLE); 274*5b2fc499SJeff Garzik 275*5b2fc499SJeff Garzik if ((ret = usb_submit_urb(pegasus->ctrl_urb, GFP_ATOMIC))) { 276*5b2fc499SJeff Garzik if (ret == -ENODEV) 277*5b2fc499SJeff Garzik netif_device_detach(pegasus->net); 278*5b2fc499SJeff Garzik if (netif_msg_drv(pegasus)) 279*5b2fc499SJeff Garzik dev_err(&pegasus->intf->dev, "%s, status %d\n", 280*5b2fc499SJeff Garzik __FUNCTION__, ret); 281*5b2fc499SJeff Garzik goto out; 282*5b2fc499SJeff Garzik } 283*5b2fc499SJeff Garzik 284*5b2fc499SJeff Garzik schedule(); 285*5b2fc499SJeff Garzik out: 286*5b2fc499SJeff Garzik remove_wait_queue(&pegasus->ctrl_wait, &wait); 287*5b2fc499SJeff Garzik kfree(tmp); 288*5b2fc499SJeff Garzik 289*5b2fc499SJeff Garzik return ret; 290*5b2fc499SJeff Garzik } 291*5b2fc499SJeff Garzik 292*5b2fc499SJeff Garzik static int update_eth_regs_async(pegasus_t * pegasus) 293*5b2fc499SJeff Garzik { 294*5b2fc499SJeff Garzik int ret; 295*5b2fc499SJeff Garzik 296*5b2fc499SJeff Garzik pegasus->dr.bRequestType = PEGASUS_REQT_WRITE; 297*5b2fc499SJeff Garzik pegasus->dr.bRequest = PEGASUS_REQ_SET_REGS; 298*5b2fc499SJeff Garzik pegasus->dr.wValue = 0; 299*5b2fc499SJeff Garzik pegasus->dr.wIndex = cpu_to_le16(EthCtrl0); 300*5b2fc499SJeff Garzik pegasus->dr.wLength = cpu_to_le16(3); 301*5b2fc499SJeff Garzik pegasus->ctrl_urb->transfer_buffer_length = 3; 302*5b2fc499SJeff Garzik 303*5b2fc499SJeff Garzik usb_fill_control_urb(pegasus->ctrl_urb, pegasus->usb, 304*5b2fc499SJeff Garzik usb_sndctrlpipe(pegasus->usb, 0), 305*5b2fc499SJeff Garzik (char *) &pegasus->dr, 306*5b2fc499SJeff Garzik pegasus->eth_regs, 3, ctrl_callback, pegasus); 307*5b2fc499SJeff Garzik 308*5b2fc499SJeff Garzik if ((ret = usb_submit_urb(pegasus->ctrl_urb, GFP_ATOMIC))) { 309*5b2fc499SJeff Garzik if (ret == -ENODEV) 310*5b2fc499SJeff Garzik netif_device_detach(pegasus->net); 311*5b2fc499SJeff Garzik if (netif_msg_drv(pegasus)) 312*5b2fc499SJeff Garzik dev_err(&pegasus->intf->dev, "%s, status %d\n", 313*5b2fc499SJeff Garzik __FUNCTION__, ret); 314*5b2fc499SJeff Garzik } 315*5b2fc499SJeff Garzik 316*5b2fc499SJeff Garzik return ret; 317*5b2fc499SJeff Garzik } 318*5b2fc499SJeff Garzik 319*5b2fc499SJeff Garzik /* Returns 0 on success, error on failure */ 320*5b2fc499SJeff Garzik static int read_mii_word(pegasus_t * pegasus, __u8 phy, __u8 indx, __u16 * regd) 321*5b2fc499SJeff Garzik { 322*5b2fc499SJeff Garzik int i; 323*5b2fc499SJeff Garzik __u8 data[4] = { phy, 0, 0, indx }; 324*5b2fc499SJeff Garzik __le16 regdi; 325*5b2fc499SJeff Garzik int ret; 326*5b2fc499SJeff Garzik 327*5b2fc499SJeff Garzik set_register(pegasus, PhyCtrl, 0); 328*5b2fc499SJeff Garzik set_registers(pegasus, PhyAddr, sizeof (data), data); 329*5b2fc499SJeff Garzik set_register(pegasus, PhyCtrl, (indx | PHY_READ)); 330*5b2fc499SJeff Garzik for (i = 0; i < REG_TIMEOUT; i++) { 331*5b2fc499SJeff Garzik ret = get_registers(pegasus, PhyCtrl, 1, data); 332*5b2fc499SJeff Garzik if (ret == -ESHUTDOWN) 333*5b2fc499SJeff Garzik goto fail; 334*5b2fc499SJeff Garzik if (data[0] & PHY_DONE) 335*5b2fc499SJeff Garzik break; 336*5b2fc499SJeff Garzik } 337*5b2fc499SJeff Garzik if (i < REG_TIMEOUT) { 338*5b2fc499SJeff Garzik ret = get_registers(pegasus, PhyData, 2, ®di); 339*5b2fc499SJeff Garzik *regd = le16_to_cpu(regdi); 340*5b2fc499SJeff Garzik return ret; 341*5b2fc499SJeff Garzik } 342*5b2fc499SJeff Garzik fail: 343*5b2fc499SJeff Garzik if (netif_msg_drv(pegasus)) 344*5b2fc499SJeff Garzik dev_warn(&pegasus->intf->dev, "%s failed\n", __FUNCTION__); 345*5b2fc499SJeff Garzik 346*5b2fc499SJeff Garzik return ret; 347*5b2fc499SJeff Garzik } 348*5b2fc499SJeff Garzik 349*5b2fc499SJeff Garzik static int mdio_read(struct net_device *dev, int phy_id, int loc) 350*5b2fc499SJeff Garzik { 351*5b2fc499SJeff Garzik pegasus_t *pegasus = (pegasus_t *) netdev_priv(dev); 352*5b2fc499SJeff Garzik u16 res; 353*5b2fc499SJeff Garzik 354*5b2fc499SJeff Garzik read_mii_word(pegasus, phy_id, loc, &res); 355*5b2fc499SJeff Garzik return (int)res; 356*5b2fc499SJeff Garzik } 357*5b2fc499SJeff Garzik 358*5b2fc499SJeff Garzik static int write_mii_word(pegasus_t * pegasus, __u8 phy, __u8 indx, __u16 regd) 359*5b2fc499SJeff Garzik { 360*5b2fc499SJeff Garzik int i; 361*5b2fc499SJeff Garzik __u8 data[4] = { phy, 0, 0, indx }; 362*5b2fc499SJeff Garzik int ret; 363*5b2fc499SJeff Garzik 364*5b2fc499SJeff Garzik data[1] = (u8) regd; 365*5b2fc499SJeff Garzik data[2] = (u8) (regd >> 8); 366*5b2fc499SJeff Garzik set_register(pegasus, PhyCtrl, 0); 367*5b2fc499SJeff Garzik set_registers(pegasus, PhyAddr, sizeof(data), data); 368*5b2fc499SJeff Garzik set_register(pegasus, PhyCtrl, (indx | PHY_WRITE)); 369*5b2fc499SJeff Garzik for (i = 0; i < REG_TIMEOUT; i++) { 370*5b2fc499SJeff Garzik ret = get_registers(pegasus, PhyCtrl, 1, data); 371*5b2fc499SJeff Garzik if (ret == -ESHUTDOWN) 372*5b2fc499SJeff Garzik goto fail; 373*5b2fc499SJeff Garzik if (data[0] & PHY_DONE) 374*5b2fc499SJeff Garzik break; 375*5b2fc499SJeff Garzik } 376*5b2fc499SJeff Garzik if (i < REG_TIMEOUT) 377*5b2fc499SJeff Garzik return ret; 378*5b2fc499SJeff Garzik 379*5b2fc499SJeff Garzik fail: 380*5b2fc499SJeff Garzik if (netif_msg_drv(pegasus)) 381*5b2fc499SJeff Garzik dev_warn(&pegasus->intf->dev, "%s failed\n", __FUNCTION__); 382*5b2fc499SJeff Garzik return -ETIMEDOUT; 383*5b2fc499SJeff Garzik } 384*5b2fc499SJeff Garzik 385*5b2fc499SJeff Garzik static void mdio_write(struct net_device *dev, int phy_id, int loc, int val) 386*5b2fc499SJeff Garzik { 387*5b2fc499SJeff Garzik pegasus_t *pegasus = (pegasus_t *) netdev_priv(dev); 388*5b2fc499SJeff Garzik 389*5b2fc499SJeff Garzik write_mii_word(pegasus, phy_id, loc, val); 390*5b2fc499SJeff Garzik } 391*5b2fc499SJeff Garzik 392*5b2fc499SJeff Garzik static int read_eprom_word(pegasus_t * pegasus, __u8 index, __u16 * retdata) 393*5b2fc499SJeff Garzik { 394*5b2fc499SJeff Garzik int i; 395*5b2fc499SJeff Garzik __u8 tmp; 396*5b2fc499SJeff Garzik __le16 retdatai; 397*5b2fc499SJeff Garzik int ret; 398*5b2fc499SJeff Garzik 399*5b2fc499SJeff Garzik set_register(pegasus, EpromCtrl, 0); 400*5b2fc499SJeff Garzik set_register(pegasus, EpromOffset, index); 401*5b2fc499SJeff Garzik set_register(pegasus, EpromCtrl, EPROM_READ); 402*5b2fc499SJeff Garzik 403*5b2fc499SJeff Garzik for (i = 0; i < REG_TIMEOUT; i++) { 404*5b2fc499SJeff Garzik ret = get_registers(pegasus, EpromCtrl, 1, &tmp); 405*5b2fc499SJeff Garzik if (tmp & EPROM_DONE) 406*5b2fc499SJeff Garzik break; 407*5b2fc499SJeff Garzik if (ret == -ESHUTDOWN) 408*5b2fc499SJeff Garzik goto fail; 409*5b2fc499SJeff Garzik } 410*5b2fc499SJeff Garzik if (i < REG_TIMEOUT) { 411*5b2fc499SJeff Garzik ret = get_registers(pegasus, EpromData, 2, &retdatai); 412*5b2fc499SJeff Garzik *retdata = le16_to_cpu(retdatai); 413*5b2fc499SJeff Garzik return ret; 414*5b2fc499SJeff Garzik } 415*5b2fc499SJeff Garzik 416*5b2fc499SJeff Garzik fail: 417*5b2fc499SJeff Garzik if (netif_msg_drv(pegasus)) 418*5b2fc499SJeff Garzik dev_warn(&pegasus->intf->dev, "%s failed\n", __FUNCTION__); 419*5b2fc499SJeff Garzik return -ETIMEDOUT; 420*5b2fc499SJeff Garzik } 421*5b2fc499SJeff Garzik 422*5b2fc499SJeff Garzik #ifdef PEGASUS_WRITE_EEPROM 423*5b2fc499SJeff Garzik static inline void enable_eprom_write(pegasus_t * pegasus) 424*5b2fc499SJeff Garzik { 425*5b2fc499SJeff Garzik __u8 tmp; 426*5b2fc499SJeff Garzik int ret; 427*5b2fc499SJeff Garzik 428*5b2fc499SJeff Garzik get_registers(pegasus, EthCtrl2, 1, &tmp); 429*5b2fc499SJeff Garzik set_register(pegasus, EthCtrl2, tmp | EPROM_WR_ENABLE); 430*5b2fc499SJeff Garzik } 431*5b2fc499SJeff Garzik 432*5b2fc499SJeff Garzik static inline void disable_eprom_write(pegasus_t * pegasus) 433*5b2fc499SJeff Garzik { 434*5b2fc499SJeff Garzik __u8 tmp; 435*5b2fc499SJeff Garzik int ret; 436*5b2fc499SJeff Garzik 437*5b2fc499SJeff Garzik get_registers(pegasus, EthCtrl2, 1, &tmp); 438*5b2fc499SJeff Garzik set_register(pegasus, EpromCtrl, 0); 439*5b2fc499SJeff Garzik set_register(pegasus, EthCtrl2, tmp & ~EPROM_WR_ENABLE); 440*5b2fc499SJeff Garzik } 441*5b2fc499SJeff Garzik 442*5b2fc499SJeff Garzik static int write_eprom_word(pegasus_t * pegasus, __u8 index, __u16 data) 443*5b2fc499SJeff Garzik { 444*5b2fc499SJeff Garzik int i; 445*5b2fc499SJeff Garzik __u8 tmp, d[4] = { 0x3f, 0, 0, EPROM_WRITE }; 446*5b2fc499SJeff Garzik int ret; 447*5b2fc499SJeff Garzik 448*5b2fc499SJeff Garzik set_registers(pegasus, EpromOffset, 4, d); 449*5b2fc499SJeff Garzik enable_eprom_write(pegasus); 450*5b2fc499SJeff Garzik set_register(pegasus, EpromOffset, index); 451*5b2fc499SJeff Garzik set_registers(pegasus, EpromData, 2, &data); 452*5b2fc499SJeff Garzik set_register(pegasus, EpromCtrl, EPROM_WRITE); 453*5b2fc499SJeff Garzik 454*5b2fc499SJeff Garzik for (i = 0; i < REG_TIMEOUT; i++) { 455*5b2fc499SJeff Garzik ret = get_registers(pegasus, EpromCtrl, 1, &tmp); 456*5b2fc499SJeff Garzik if (ret == -ESHUTDOWN) 457*5b2fc499SJeff Garzik goto fail; 458*5b2fc499SJeff Garzik if (tmp & EPROM_DONE) 459*5b2fc499SJeff Garzik break; 460*5b2fc499SJeff Garzik } 461*5b2fc499SJeff Garzik disable_eprom_write(pegasus); 462*5b2fc499SJeff Garzik if (i < REG_TIMEOUT) 463*5b2fc499SJeff Garzik return ret; 464*5b2fc499SJeff Garzik fail: 465*5b2fc499SJeff Garzik if (netif_msg_drv(pegasus)) 466*5b2fc499SJeff Garzik dev_warn(&pegasus->intf->dev, "%s failed\n", __FUNCTION__); 467*5b2fc499SJeff Garzik return -ETIMEDOUT; 468*5b2fc499SJeff Garzik } 469*5b2fc499SJeff Garzik #endif /* PEGASUS_WRITE_EEPROM */ 470*5b2fc499SJeff Garzik 471*5b2fc499SJeff Garzik static inline void get_node_id(pegasus_t * pegasus, __u8 * id) 472*5b2fc499SJeff Garzik { 473*5b2fc499SJeff Garzik int i; 474*5b2fc499SJeff Garzik __u16 w16; 475*5b2fc499SJeff Garzik 476*5b2fc499SJeff Garzik for (i = 0; i < 3; i++) { 477*5b2fc499SJeff Garzik read_eprom_word(pegasus, i, &w16); 478*5b2fc499SJeff Garzik ((__le16 *) id)[i] = cpu_to_le16p(&w16); 479*5b2fc499SJeff Garzik } 480*5b2fc499SJeff Garzik } 481*5b2fc499SJeff Garzik 482*5b2fc499SJeff Garzik static void set_ethernet_addr(pegasus_t * pegasus) 483*5b2fc499SJeff Garzik { 484*5b2fc499SJeff Garzik __u8 node_id[6]; 485*5b2fc499SJeff Garzik 486*5b2fc499SJeff Garzik if (pegasus->features & PEGASUS_II) { 487*5b2fc499SJeff Garzik get_registers(pegasus, 0x10, sizeof(node_id), node_id); 488*5b2fc499SJeff Garzik } else { 489*5b2fc499SJeff Garzik get_node_id(pegasus, node_id); 490*5b2fc499SJeff Garzik set_registers(pegasus, EthID, sizeof (node_id), node_id); 491*5b2fc499SJeff Garzik } 492*5b2fc499SJeff Garzik memcpy(pegasus->net->dev_addr, node_id, sizeof (node_id)); 493*5b2fc499SJeff Garzik } 494*5b2fc499SJeff Garzik 495*5b2fc499SJeff Garzik static inline int reset_mac(pegasus_t * pegasus) 496*5b2fc499SJeff Garzik { 497*5b2fc499SJeff Garzik __u8 data = 0x8; 498*5b2fc499SJeff Garzik int i; 499*5b2fc499SJeff Garzik 500*5b2fc499SJeff Garzik set_register(pegasus, EthCtrl1, data); 501*5b2fc499SJeff Garzik for (i = 0; i < REG_TIMEOUT; i++) { 502*5b2fc499SJeff Garzik get_registers(pegasus, EthCtrl1, 1, &data); 503*5b2fc499SJeff Garzik if (~data & 0x08) { 504*5b2fc499SJeff Garzik if (loopback & 1) 505*5b2fc499SJeff Garzik break; 506*5b2fc499SJeff Garzik if (mii_mode && (pegasus->features & HAS_HOME_PNA)) 507*5b2fc499SJeff Garzik set_register(pegasus, Gpio1, 0x34); 508*5b2fc499SJeff Garzik else 509*5b2fc499SJeff Garzik set_register(pegasus, Gpio1, 0x26); 510*5b2fc499SJeff Garzik set_register(pegasus, Gpio0, pegasus->features); 511*5b2fc499SJeff Garzik set_register(pegasus, Gpio0, DEFAULT_GPIO_SET); 512*5b2fc499SJeff Garzik break; 513*5b2fc499SJeff Garzik } 514*5b2fc499SJeff Garzik } 515*5b2fc499SJeff Garzik if (i == REG_TIMEOUT) 516*5b2fc499SJeff Garzik return -ETIMEDOUT; 517*5b2fc499SJeff Garzik 518*5b2fc499SJeff Garzik if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_LINKSYS || 519*5b2fc499SJeff Garzik usb_dev_id[pegasus->dev_index].vendor == VENDOR_DLINK) { 520*5b2fc499SJeff Garzik set_register(pegasus, Gpio0, 0x24); 521*5b2fc499SJeff Garzik set_register(pegasus, Gpio0, 0x26); 522*5b2fc499SJeff Garzik } 523*5b2fc499SJeff Garzik if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_ELCON) { 524*5b2fc499SJeff Garzik __u16 auxmode; 525*5b2fc499SJeff Garzik read_mii_word(pegasus, 3, 0x1b, &auxmode); 526*5b2fc499SJeff Garzik write_mii_word(pegasus, 3, 0x1b, auxmode | 4); 527*5b2fc499SJeff Garzik } 528*5b2fc499SJeff Garzik 529*5b2fc499SJeff Garzik return 0; 530*5b2fc499SJeff Garzik } 531*5b2fc499SJeff Garzik 532*5b2fc499SJeff Garzik static int enable_net_traffic(struct net_device *dev, struct usb_device *usb) 533*5b2fc499SJeff Garzik { 534*5b2fc499SJeff Garzik __u16 linkpart; 535*5b2fc499SJeff Garzik __u8 data[4]; 536*5b2fc499SJeff Garzik pegasus_t *pegasus = netdev_priv(dev); 537*5b2fc499SJeff Garzik int ret; 538*5b2fc499SJeff Garzik 539*5b2fc499SJeff Garzik read_mii_word(pegasus, pegasus->phy, MII_LPA, &linkpart); 540*5b2fc499SJeff Garzik data[0] = 0xc9; 541*5b2fc499SJeff Garzik data[1] = 0; 542*5b2fc499SJeff Garzik if (linkpart & (ADVERTISE_100FULL | ADVERTISE_10FULL)) 543*5b2fc499SJeff Garzik data[1] |= 0x20; /* set full duplex */ 544*5b2fc499SJeff Garzik if (linkpart & (ADVERTISE_100FULL | ADVERTISE_100HALF)) 545*5b2fc499SJeff Garzik data[1] |= 0x10; /* set 100 Mbps */ 546*5b2fc499SJeff Garzik if (mii_mode) 547*5b2fc499SJeff Garzik data[1] = 0; 548*5b2fc499SJeff Garzik data[2] = (loopback & 1) ? 0x09 : 0x01; 549*5b2fc499SJeff Garzik 550*5b2fc499SJeff Garzik memcpy(pegasus->eth_regs, data, sizeof (data)); 551*5b2fc499SJeff Garzik ret = set_registers(pegasus, EthCtrl0, 3, data); 552*5b2fc499SJeff Garzik 553*5b2fc499SJeff Garzik if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_LINKSYS || 554*5b2fc499SJeff Garzik usb_dev_id[pegasus->dev_index].vendor == VENDOR_LINKSYS2 || 555*5b2fc499SJeff Garzik usb_dev_id[pegasus->dev_index].vendor == VENDOR_DLINK) { 556*5b2fc499SJeff Garzik u16 auxmode; 557*5b2fc499SJeff Garzik read_mii_word(pegasus, 0, 0x1b, &auxmode); 558*5b2fc499SJeff Garzik write_mii_word(pegasus, 0, 0x1b, auxmode | 4); 559*5b2fc499SJeff Garzik } 560*5b2fc499SJeff Garzik 561*5b2fc499SJeff Garzik return ret; 562*5b2fc499SJeff Garzik } 563*5b2fc499SJeff Garzik 564*5b2fc499SJeff Garzik static void fill_skb_pool(pegasus_t * pegasus) 565*5b2fc499SJeff Garzik { 566*5b2fc499SJeff Garzik int i; 567*5b2fc499SJeff Garzik 568*5b2fc499SJeff Garzik for (i = 0; i < RX_SKBS; i++) { 569*5b2fc499SJeff Garzik if (pegasus->rx_pool[i]) 570*5b2fc499SJeff Garzik continue; 571*5b2fc499SJeff Garzik pegasus->rx_pool[i] = dev_alloc_skb(PEGASUS_MTU + 2); 572*5b2fc499SJeff Garzik /* 573*5b2fc499SJeff Garzik ** we give up if the allocation fail. the tasklet will be 574*5b2fc499SJeff Garzik ** rescheduled again anyway... 575*5b2fc499SJeff Garzik */ 576*5b2fc499SJeff Garzik if (pegasus->rx_pool[i] == NULL) 577*5b2fc499SJeff Garzik return; 578*5b2fc499SJeff Garzik skb_reserve(pegasus->rx_pool[i], 2); 579*5b2fc499SJeff Garzik } 580*5b2fc499SJeff Garzik } 581*5b2fc499SJeff Garzik 582*5b2fc499SJeff Garzik static void free_skb_pool(pegasus_t * pegasus) 583*5b2fc499SJeff Garzik { 584*5b2fc499SJeff Garzik int i; 585*5b2fc499SJeff Garzik 586*5b2fc499SJeff Garzik for (i = 0; i < RX_SKBS; i++) { 587*5b2fc499SJeff Garzik if (pegasus->rx_pool[i]) { 588*5b2fc499SJeff Garzik dev_kfree_skb(pegasus->rx_pool[i]); 589*5b2fc499SJeff Garzik pegasus->rx_pool[i] = NULL; 590*5b2fc499SJeff Garzik } 591*5b2fc499SJeff Garzik } 592*5b2fc499SJeff Garzik } 593*5b2fc499SJeff Garzik 594*5b2fc499SJeff Garzik static inline struct sk_buff *pull_skb(pegasus_t * pegasus) 595*5b2fc499SJeff Garzik { 596*5b2fc499SJeff Garzik int i; 597*5b2fc499SJeff Garzik struct sk_buff *skb; 598*5b2fc499SJeff Garzik 599*5b2fc499SJeff Garzik for (i = 0; i < RX_SKBS; i++) { 600*5b2fc499SJeff Garzik if (likely(pegasus->rx_pool[i] != NULL)) { 601*5b2fc499SJeff Garzik skb = pegasus->rx_pool[i]; 602*5b2fc499SJeff Garzik pegasus->rx_pool[i] = NULL; 603*5b2fc499SJeff Garzik return skb; 604*5b2fc499SJeff Garzik } 605*5b2fc499SJeff Garzik } 606*5b2fc499SJeff Garzik return NULL; 607*5b2fc499SJeff Garzik } 608*5b2fc499SJeff Garzik 609*5b2fc499SJeff Garzik static void read_bulk_callback(struct urb *urb) 610*5b2fc499SJeff Garzik { 611*5b2fc499SJeff Garzik pegasus_t *pegasus = urb->context; 612*5b2fc499SJeff Garzik struct net_device *net; 613*5b2fc499SJeff Garzik int rx_status, count = urb->actual_length; 614*5b2fc499SJeff Garzik u8 *buf = urb->transfer_buffer; 615*5b2fc499SJeff Garzik __u16 pkt_len; 616*5b2fc499SJeff Garzik 617*5b2fc499SJeff Garzik if (!pegasus) 618*5b2fc499SJeff Garzik return; 619*5b2fc499SJeff Garzik 620*5b2fc499SJeff Garzik net = pegasus->net; 621*5b2fc499SJeff Garzik if (!netif_device_present(net) || !netif_running(net)) 622*5b2fc499SJeff Garzik return; 623*5b2fc499SJeff Garzik 624*5b2fc499SJeff Garzik switch (urb->status) { 625*5b2fc499SJeff Garzik case 0: 626*5b2fc499SJeff Garzik break; 627*5b2fc499SJeff Garzik case -ETIME: 628*5b2fc499SJeff Garzik if (netif_msg_rx_err(pegasus)) 629*5b2fc499SJeff Garzik pr_debug("%s: reset MAC\n", net->name); 630*5b2fc499SJeff Garzik pegasus->flags &= ~PEGASUS_RX_BUSY; 631*5b2fc499SJeff Garzik break; 632*5b2fc499SJeff Garzik case -EPIPE: /* stall, or disconnect from TT */ 633*5b2fc499SJeff Garzik /* FIXME schedule work to clear the halt */ 634*5b2fc499SJeff Garzik if (netif_msg_rx_err(pegasus)) 635*5b2fc499SJeff Garzik printk(KERN_WARNING "%s: no rx stall recovery\n", 636*5b2fc499SJeff Garzik net->name); 637*5b2fc499SJeff Garzik return; 638*5b2fc499SJeff Garzik case -ENOENT: 639*5b2fc499SJeff Garzik case -ECONNRESET: 640*5b2fc499SJeff Garzik case -ESHUTDOWN: 641*5b2fc499SJeff Garzik if (netif_msg_ifdown(pegasus)) 642*5b2fc499SJeff Garzik pr_debug("%s: rx unlink, %d\n", net->name, urb->status); 643*5b2fc499SJeff Garzik return; 644*5b2fc499SJeff Garzik default: 645*5b2fc499SJeff Garzik if (netif_msg_rx_err(pegasus)) 646*5b2fc499SJeff Garzik pr_debug("%s: RX status %d\n", net->name, urb->status); 647*5b2fc499SJeff Garzik goto goon; 648*5b2fc499SJeff Garzik } 649*5b2fc499SJeff Garzik 650*5b2fc499SJeff Garzik if (!count || count < 4) 651*5b2fc499SJeff Garzik goto goon; 652*5b2fc499SJeff Garzik 653*5b2fc499SJeff Garzik rx_status = buf[count - 2]; 654*5b2fc499SJeff Garzik if (rx_status & 0x1e) { 655*5b2fc499SJeff Garzik if (netif_msg_rx_err(pegasus)) 656*5b2fc499SJeff Garzik pr_debug("%s: RX packet error %x\n", 657*5b2fc499SJeff Garzik net->name, rx_status); 658*5b2fc499SJeff Garzik pegasus->stats.rx_errors++; 659*5b2fc499SJeff Garzik if (rx_status & 0x06) // long or runt 660*5b2fc499SJeff Garzik pegasus->stats.rx_length_errors++; 661*5b2fc499SJeff Garzik if (rx_status & 0x08) 662*5b2fc499SJeff Garzik pegasus->stats.rx_crc_errors++; 663*5b2fc499SJeff Garzik if (rx_status & 0x10) // extra bits 664*5b2fc499SJeff Garzik pegasus->stats.rx_frame_errors++; 665*5b2fc499SJeff Garzik goto goon; 666*5b2fc499SJeff Garzik } 667*5b2fc499SJeff Garzik if (pegasus->chip == 0x8513) { 668*5b2fc499SJeff Garzik pkt_len = le32_to_cpu(*(__le32 *)urb->transfer_buffer); 669*5b2fc499SJeff Garzik pkt_len &= 0x0fff; 670*5b2fc499SJeff Garzik pegasus->rx_skb->data += 2; 671*5b2fc499SJeff Garzik } else { 672*5b2fc499SJeff Garzik pkt_len = buf[count - 3] << 8; 673*5b2fc499SJeff Garzik pkt_len += buf[count - 4]; 674*5b2fc499SJeff Garzik pkt_len &= 0xfff; 675*5b2fc499SJeff Garzik pkt_len -= 8; 676*5b2fc499SJeff Garzik } 677*5b2fc499SJeff Garzik 678*5b2fc499SJeff Garzik /* 679*5b2fc499SJeff Garzik * If the packet is unreasonably long, quietly drop it rather than 680*5b2fc499SJeff Garzik * kernel panicing by calling skb_put. 681*5b2fc499SJeff Garzik */ 682*5b2fc499SJeff Garzik if (pkt_len > PEGASUS_MTU) 683*5b2fc499SJeff Garzik goto goon; 684*5b2fc499SJeff Garzik 685*5b2fc499SJeff Garzik /* 686*5b2fc499SJeff Garzik * at this point we are sure pegasus->rx_skb != NULL 687*5b2fc499SJeff Garzik * so we go ahead and pass up the packet. 688*5b2fc499SJeff Garzik */ 689*5b2fc499SJeff Garzik skb_put(pegasus->rx_skb, pkt_len); 690*5b2fc499SJeff Garzik pegasus->rx_skb->protocol = eth_type_trans(pegasus->rx_skb, net); 691*5b2fc499SJeff Garzik netif_rx(pegasus->rx_skb); 692*5b2fc499SJeff Garzik pegasus->stats.rx_packets++; 693*5b2fc499SJeff Garzik pegasus->stats.rx_bytes += pkt_len; 694*5b2fc499SJeff Garzik 695*5b2fc499SJeff Garzik if (pegasus->flags & PEGASUS_UNPLUG) 696*5b2fc499SJeff Garzik return; 697*5b2fc499SJeff Garzik 698*5b2fc499SJeff Garzik spin_lock(&pegasus->rx_pool_lock); 699*5b2fc499SJeff Garzik pegasus->rx_skb = pull_skb(pegasus); 700*5b2fc499SJeff Garzik spin_unlock(&pegasus->rx_pool_lock); 701*5b2fc499SJeff Garzik 702*5b2fc499SJeff Garzik if (pegasus->rx_skb == NULL) 703*5b2fc499SJeff Garzik goto tl_sched; 704*5b2fc499SJeff Garzik goon: 705*5b2fc499SJeff Garzik usb_fill_bulk_urb(pegasus->rx_urb, pegasus->usb, 706*5b2fc499SJeff Garzik usb_rcvbulkpipe(pegasus->usb, 1), 707*5b2fc499SJeff Garzik pegasus->rx_skb->data, PEGASUS_MTU + 8, 708*5b2fc499SJeff Garzik read_bulk_callback, pegasus); 709*5b2fc499SJeff Garzik rx_status = usb_submit_urb(pegasus->rx_urb, GFP_ATOMIC); 710*5b2fc499SJeff Garzik if (rx_status == -ENODEV) 711*5b2fc499SJeff Garzik netif_device_detach(pegasus->net); 712*5b2fc499SJeff Garzik else if (rx_status) { 713*5b2fc499SJeff Garzik pegasus->flags |= PEGASUS_RX_URB_FAIL; 714*5b2fc499SJeff Garzik goto tl_sched; 715*5b2fc499SJeff Garzik } else { 716*5b2fc499SJeff Garzik pegasus->flags &= ~PEGASUS_RX_URB_FAIL; 717*5b2fc499SJeff Garzik } 718*5b2fc499SJeff Garzik 719*5b2fc499SJeff Garzik return; 720*5b2fc499SJeff Garzik 721*5b2fc499SJeff Garzik tl_sched: 722*5b2fc499SJeff Garzik tasklet_schedule(&pegasus->rx_tl); 723*5b2fc499SJeff Garzik } 724*5b2fc499SJeff Garzik 725*5b2fc499SJeff Garzik static void rx_fixup(unsigned long data) 726*5b2fc499SJeff Garzik { 727*5b2fc499SJeff Garzik pegasus_t *pegasus; 728*5b2fc499SJeff Garzik unsigned long flags; 729*5b2fc499SJeff Garzik int status; 730*5b2fc499SJeff Garzik 731*5b2fc499SJeff Garzik pegasus = (pegasus_t *) data; 732*5b2fc499SJeff Garzik if (pegasus->flags & PEGASUS_UNPLUG) 733*5b2fc499SJeff Garzik return; 734*5b2fc499SJeff Garzik 735*5b2fc499SJeff Garzik spin_lock_irqsave(&pegasus->rx_pool_lock, flags); 736*5b2fc499SJeff Garzik fill_skb_pool(pegasus); 737*5b2fc499SJeff Garzik if (pegasus->flags & PEGASUS_RX_URB_FAIL) 738*5b2fc499SJeff Garzik if (pegasus->rx_skb) 739*5b2fc499SJeff Garzik goto try_again; 740*5b2fc499SJeff Garzik if (pegasus->rx_skb == NULL) { 741*5b2fc499SJeff Garzik pegasus->rx_skb = pull_skb(pegasus); 742*5b2fc499SJeff Garzik } 743*5b2fc499SJeff Garzik if (pegasus->rx_skb == NULL) { 744*5b2fc499SJeff Garzik if (netif_msg_rx_err(pegasus)) 745*5b2fc499SJeff Garzik printk(KERN_WARNING "%s: low on memory\n", 746*5b2fc499SJeff Garzik pegasus->net->name); 747*5b2fc499SJeff Garzik tasklet_schedule(&pegasus->rx_tl); 748*5b2fc499SJeff Garzik goto done; 749*5b2fc499SJeff Garzik } 750*5b2fc499SJeff Garzik usb_fill_bulk_urb(pegasus->rx_urb, pegasus->usb, 751*5b2fc499SJeff Garzik usb_rcvbulkpipe(pegasus->usb, 1), 752*5b2fc499SJeff Garzik pegasus->rx_skb->data, PEGASUS_MTU + 8, 753*5b2fc499SJeff Garzik read_bulk_callback, pegasus); 754*5b2fc499SJeff Garzik try_again: 755*5b2fc499SJeff Garzik status = usb_submit_urb(pegasus->rx_urb, GFP_ATOMIC); 756*5b2fc499SJeff Garzik if (status == -ENODEV) 757*5b2fc499SJeff Garzik netif_device_detach(pegasus->net); 758*5b2fc499SJeff Garzik else if (status) { 759*5b2fc499SJeff Garzik pegasus->flags |= PEGASUS_RX_URB_FAIL; 760*5b2fc499SJeff Garzik tasklet_schedule(&pegasus->rx_tl); 761*5b2fc499SJeff Garzik } else { 762*5b2fc499SJeff Garzik pegasus->flags &= ~PEGASUS_RX_URB_FAIL; 763*5b2fc499SJeff Garzik } 764*5b2fc499SJeff Garzik done: 765*5b2fc499SJeff Garzik spin_unlock_irqrestore(&pegasus->rx_pool_lock, flags); 766*5b2fc499SJeff Garzik } 767*5b2fc499SJeff Garzik 768*5b2fc499SJeff Garzik static void write_bulk_callback(struct urb *urb) 769*5b2fc499SJeff Garzik { 770*5b2fc499SJeff Garzik pegasus_t *pegasus = urb->context; 771*5b2fc499SJeff Garzik struct net_device *net = pegasus->net; 772*5b2fc499SJeff Garzik 773*5b2fc499SJeff Garzik if (!pegasus) 774*5b2fc499SJeff Garzik return; 775*5b2fc499SJeff Garzik 776*5b2fc499SJeff Garzik if (!netif_device_present(net) || !netif_running(net)) 777*5b2fc499SJeff Garzik return; 778*5b2fc499SJeff Garzik 779*5b2fc499SJeff Garzik switch (urb->status) { 780*5b2fc499SJeff Garzik case -EPIPE: 781*5b2fc499SJeff Garzik /* FIXME schedule_work() to clear the tx halt */ 782*5b2fc499SJeff Garzik netif_stop_queue(net); 783*5b2fc499SJeff Garzik if (netif_msg_tx_err(pegasus)) 784*5b2fc499SJeff Garzik printk(KERN_WARNING "%s: no tx stall recovery\n", 785*5b2fc499SJeff Garzik net->name); 786*5b2fc499SJeff Garzik return; 787*5b2fc499SJeff Garzik case -ENOENT: 788*5b2fc499SJeff Garzik case -ECONNRESET: 789*5b2fc499SJeff Garzik case -ESHUTDOWN: 790*5b2fc499SJeff Garzik if (netif_msg_ifdown(pegasus)) 791*5b2fc499SJeff Garzik pr_debug("%s: tx unlink, %d\n", net->name, urb->status); 792*5b2fc499SJeff Garzik return; 793*5b2fc499SJeff Garzik default: 794*5b2fc499SJeff Garzik if (netif_msg_tx_err(pegasus)) 795*5b2fc499SJeff Garzik pr_info("%s: TX status %d\n", net->name, urb->status); 796*5b2fc499SJeff Garzik /* FALL THROUGH */ 797*5b2fc499SJeff Garzik case 0: 798*5b2fc499SJeff Garzik break; 799*5b2fc499SJeff Garzik } 800*5b2fc499SJeff Garzik 801*5b2fc499SJeff Garzik net->trans_start = jiffies; 802*5b2fc499SJeff Garzik netif_wake_queue(net); 803*5b2fc499SJeff Garzik } 804*5b2fc499SJeff Garzik 805*5b2fc499SJeff Garzik static void intr_callback(struct urb *urb) 806*5b2fc499SJeff Garzik { 807*5b2fc499SJeff Garzik pegasus_t *pegasus = urb->context; 808*5b2fc499SJeff Garzik struct net_device *net; 809*5b2fc499SJeff Garzik int status; 810*5b2fc499SJeff Garzik 811*5b2fc499SJeff Garzik if (!pegasus) 812*5b2fc499SJeff Garzik return; 813*5b2fc499SJeff Garzik net = pegasus->net; 814*5b2fc499SJeff Garzik 815*5b2fc499SJeff Garzik switch (urb->status) { 816*5b2fc499SJeff Garzik case 0: 817*5b2fc499SJeff Garzik break; 818*5b2fc499SJeff Garzik case -ECONNRESET: /* unlink */ 819*5b2fc499SJeff Garzik case -ENOENT: 820*5b2fc499SJeff Garzik case -ESHUTDOWN: 821*5b2fc499SJeff Garzik return; 822*5b2fc499SJeff Garzik default: 823*5b2fc499SJeff Garzik /* some Pegasus-I products report LOTS of data 824*5b2fc499SJeff Garzik * toggle errors... avoid log spamming 825*5b2fc499SJeff Garzik */ 826*5b2fc499SJeff Garzik if (netif_msg_timer(pegasus)) 827*5b2fc499SJeff Garzik pr_debug("%s: intr status %d\n", net->name, 828*5b2fc499SJeff Garzik urb->status); 829*5b2fc499SJeff Garzik } 830*5b2fc499SJeff Garzik 831*5b2fc499SJeff Garzik if (urb->actual_length >= 6) { 832*5b2fc499SJeff Garzik u8 * d = urb->transfer_buffer; 833*5b2fc499SJeff Garzik 834*5b2fc499SJeff Garzik /* byte 0 == tx_status1, reg 2B */ 835*5b2fc499SJeff Garzik if (d[0] & (TX_UNDERRUN|EXCESSIVE_COL 836*5b2fc499SJeff Garzik |LATE_COL|JABBER_TIMEOUT)) { 837*5b2fc499SJeff Garzik pegasus->stats.tx_errors++; 838*5b2fc499SJeff Garzik if (d[0] & TX_UNDERRUN) 839*5b2fc499SJeff Garzik pegasus->stats.tx_fifo_errors++; 840*5b2fc499SJeff Garzik if (d[0] & (EXCESSIVE_COL | JABBER_TIMEOUT)) 841*5b2fc499SJeff Garzik pegasus->stats.tx_aborted_errors++; 842*5b2fc499SJeff Garzik if (d[0] & LATE_COL) 843*5b2fc499SJeff Garzik pegasus->stats.tx_window_errors++; 844*5b2fc499SJeff Garzik } 845*5b2fc499SJeff Garzik 846*5b2fc499SJeff Garzik /* d[5].LINK_STATUS lies on some adapters. 847*5b2fc499SJeff Garzik * d[0].NO_CARRIER kicks in only with failed TX. 848*5b2fc499SJeff Garzik * ... so monitoring with MII may be safest. 849*5b2fc499SJeff Garzik */ 850*5b2fc499SJeff Garzik 851*5b2fc499SJeff Garzik /* bytes 3-4 == rx_lostpkt, reg 2E/2F */ 852*5b2fc499SJeff Garzik pegasus->stats.rx_missed_errors += ((d[3] & 0x7f) << 8) | d[4]; 853*5b2fc499SJeff Garzik } 854*5b2fc499SJeff Garzik 855*5b2fc499SJeff Garzik status = usb_submit_urb(urb, GFP_ATOMIC); 856*5b2fc499SJeff Garzik if (status == -ENODEV) 857*5b2fc499SJeff Garzik netif_device_detach(pegasus->net); 858*5b2fc499SJeff Garzik if (status && netif_msg_timer(pegasus)) 859*5b2fc499SJeff Garzik printk(KERN_ERR "%s: can't resubmit interrupt urb, %d\n", 860*5b2fc499SJeff Garzik net->name, status); 861*5b2fc499SJeff Garzik } 862*5b2fc499SJeff Garzik 863*5b2fc499SJeff Garzik static void pegasus_tx_timeout(struct net_device *net) 864*5b2fc499SJeff Garzik { 865*5b2fc499SJeff Garzik pegasus_t *pegasus = netdev_priv(net); 866*5b2fc499SJeff Garzik if (netif_msg_timer(pegasus)) 867*5b2fc499SJeff Garzik printk(KERN_WARNING "%s: tx timeout\n", net->name); 868*5b2fc499SJeff Garzik usb_unlink_urb(pegasus->tx_urb); 869*5b2fc499SJeff Garzik pegasus->stats.tx_errors++; 870*5b2fc499SJeff Garzik } 871*5b2fc499SJeff Garzik 872*5b2fc499SJeff Garzik static int pegasus_start_xmit(struct sk_buff *skb, struct net_device *net) 873*5b2fc499SJeff Garzik { 874*5b2fc499SJeff Garzik pegasus_t *pegasus = netdev_priv(net); 875*5b2fc499SJeff Garzik int count = ((skb->len + 2) & 0x3f) ? skb->len + 2 : skb->len + 3; 876*5b2fc499SJeff Garzik int res; 877*5b2fc499SJeff Garzik __u16 l16 = skb->len; 878*5b2fc499SJeff Garzik 879*5b2fc499SJeff Garzik netif_stop_queue(net); 880*5b2fc499SJeff Garzik 881*5b2fc499SJeff Garzik ((__le16 *) pegasus->tx_buff)[0] = cpu_to_le16(l16); 882*5b2fc499SJeff Garzik skb_copy_from_linear_data(skb, pegasus->tx_buff + 2, skb->len); 883*5b2fc499SJeff Garzik usb_fill_bulk_urb(pegasus->tx_urb, pegasus->usb, 884*5b2fc499SJeff Garzik usb_sndbulkpipe(pegasus->usb, 2), 885*5b2fc499SJeff Garzik pegasus->tx_buff, count, 886*5b2fc499SJeff Garzik write_bulk_callback, pegasus); 887*5b2fc499SJeff Garzik if ((res = usb_submit_urb(pegasus->tx_urb, GFP_ATOMIC))) { 888*5b2fc499SJeff Garzik if (netif_msg_tx_err(pegasus)) 889*5b2fc499SJeff Garzik printk(KERN_WARNING "%s: fail tx, %d\n", 890*5b2fc499SJeff Garzik net->name, res); 891*5b2fc499SJeff Garzik switch (res) { 892*5b2fc499SJeff Garzik case -EPIPE: /* stall, or disconnect from TT */ 893*5b2fc499SJeff Garzik /* cleanup should already have been scheduled */ 894*5b2fc499SJeff Garzik break; 895*5b2fc499SJeff Garzik case -ENODEV: /* disconnect() upcoming */ 896*5b2fc499SJeff Garzik netif_device_detach(pegasus->net); 897*5b2fc499SJeff Garzik break; 898*5b2fc499SJeff Garzik default: 899*5b2fc499SJeff Garzik pegasus->stats.tx_errors++; 900*5b2fc499SJeff Garzik netif_start_queue(net); 901*5b2fc499SJeff Garzik } 902*5b2fc499SJeff Garzik } else { 903*5b2fc499SJeff Garzik pegasus->stats.tx_packets++; 904*5b2fc499SJeff Garzik pegasus->stats.tx_bytes += skb->len; 905*5b2fc499SJeff Garzik net->trans_start = jiffies; 906*5b2fc499SJeff Garzik } 907*5b2fc499SJeff Garzik dev_kfree_skb(skb); 908*5b2fc499SJeff Garzik 909*5b2fc499SJeff Garzik return 0; 910*5b2fc499SJeff Garzik } 911*5b2fc499SJeff Garzik 912*5b2fc499SJeff Garzik static struct net_device_stats *pegasus_netdev_stats(struct net_device *dev) 913*5b2fc499SJeff Garzik { 914*5b2fc499SJeff Garzik return &((pegasus_t *) netdev_priv(dev))->stats; 915*5b2fc499SJeff Garzik } 916*5b2fc499SJeff Garzik 917*5b2fc499SJeff Garzik static inline void disable_net_traffic(pegasus_t * pegasus) 918*5b2fc499SJeff Garzik { 919*5b2fc499SJeff Garzik int tmp = 0; 920*5b2fc499SJeff Garzik 921*5b2fc499SJeff Garzik set_registers(pegasus, EthCtrl0, 2, &tmp); 922*5b2fc499SJeff Garzik } 923*5b2fc499SJeff Garzik 924*5b2fc499SJeff Garzik static inline void get_interrupt_interval(pegasus_t * pegasus) 925*5b2fc499SJeff Garzik { 926*5b2fc499SJeff Garzik __u8 data[2]; 927*5b2fc499SJeff Garzik 928*5b2fc499SJeff Garzik read_eprom_word(pegasus, 4, (__u16 *) data); 929*5b2fc499SJeff Garzik if (pegasus->usb->speed != USB_SPEED_HIGH) { 930*5b2fc499SJeff Garzik if (data[1] < 0x80) { 931*5b2fc499SJeff Garzik if (netif_msg_timer(pegasus)) 932*5b2fc499SJeff Garzik dev_info(&pegasus->intf->dev, "intr interval " 933*5b2fc499SJeff Garzik "changed from %ums to %ums\n", 934*5b2fc499SJeff Garzik data[1], 0x80); 935*5b2fc499SJeff Garzik data[1] = 0x80; 936*5b2fc499SJeff Garzik #ifdef PEGASUS_WRITE_EEPROM 937*5b2fc499SJeff Garzik write_eprom_word(pegasus, 4, *(__u16 *) data); 938*5b2fc499SJeff Garzik #endif 939*5b2fc499SJeff Garzik } 940*5b2fc499SJeff Garzik } 941*5b2fc499SJeff Garzik pegasus->intr_interval = data[1]; 942*5b2fc499SJeff Garzik } 943*5b2fc499SJeff Garzik 944*5b2fc499SJeff Garzik static void set_carrier(struct net_device *net) 945*5b2fc499SJeff Garzik { 946*5b2fc499SJeff Garzik pegasus_t *pegasus = netdev_priv(net); 947*5b2fc499SJeff Garzik u16 tmp; 948*5b2fc499SJeff Garzik 949*5b2fc499SJeff Garzik if (read_mii_word(pegasus, pegasus->phy, MII_BMSR, &tmp)) 950*5b2fc499SJeff Garzik return; 951*5b2fc499SJeff Garzik 952*5b2fc499SJeff Garzik if (tmp & BMSR_LSTATUS) 953*5b2fc499SJeff Garzik netif_carrier_on(net); 954*5b2fc499SJeff Garzik else 955*5b2fc499SJeff Garzik netif_carrier_off(net); 956*5b2fc499SJeff Garzik } 957*5b2fc499SJeff Garzik 958*5b2fc499SJeff Garzik static void free_all_urbs(pegasus_t * pegasus) 959*5b2fc499SJeff Garzik { 960*5b2fc499SJeff Garzik usb_free_urb(pegasus->intr_urb); 961*5b2fc499SJeff Garzik usb_free_urb(pegasus->tx_urb); 962*5b2fc499SJeff Garzik usb_free_urb(pegasus->rx_urb); 963*5b2fc499SJeff Garzik usb_free_urb(pegasus->ctrl_urb); 964*5b2fc499SJeff Garzik } 965*5b2fc499SJeff Garzik 966*5b2fc499SJeff Garzik static void unlink_all_urbs(pegasus_t * pegasus) 967*5b2fc499SJeff Garzik { 968*5b2fc499SJeff Garzik usb_kill_urb(pegasus->intr_urb); 969*5b2fc499SJeff Garzik usb_kill_urb(pegasus->tx_urb); 970*5b2fc499SJeff Garzik usb_kill_urb(pegasus->rx_urb); 971*5b2fc499SJeff Garzik usb_kill_urb(pegasus->ctrl_urb); 972*5b2fc499SJeff Garzik } 973*5b2fc499SJeff Garzik 974*5b2fc499SJeff Garzik static int alloc_urbs(pegasus_t * pegasus) 975*5b2fc499SJeff Garzik { 976*5b2fc499SJeff Garzik pegasus->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL); 977*5b2fc499SJeff Garzik if (!pegasus->ctrl_urb) { 978*5b2fc499SJeff Garzik return 0; 979*5b2fc499SJeff Garzik } 980*5b2fc499SJeff Garzik pegasus->rx_urb = usb_alloc_urb(0, GFP_KERNEL); 981*5b2fc499SJeff Garzik if (!pegasus->rx_urb) { 982*5b2fc499SJeff Garzik usb_free_urb(pegasus->ctrl_urb); 983*5b2fc499SJeff Garzik return 0; 984*5b2fc499SJeff Garzik } 985*5b2fc499SJeff Garzik pegasus->tx_urb = usb_alloc_urb(0, GFP_KERNEL); 986*5b2fc499SJeff Garzik if (!pegasus->tx_urb) { 987*5b2fc499SJeff Garzik usb_free_urb(pegasus->rx_urb); 988*5b2fc499SJeff Garzik usb_free_urb(pegasus->ctrl_urb); 989*5b2fc499SJeff Garzik return 0; 990*5b2fc499SJeff Garzik } 991*5b2fc499SJeff Garzik pegasus->intr_urb = usb_alloc_urb(0, GFP_KERNEL); 992*5b2fc499SJeff Garzik if (!pegasus->intr_urb) { 993*5b2fc499SJeff Garzik usb_free_urb(pegasus->tx_urb); 994*5b2fc499SJeff Garzik usb_free_urb(pegasus->rx_urb); 995*5b2fc499SJeff Garzik usb_free_urb(pegasus->ctrl_urb); 996*5b2fc499SJeff Garzik return 0; 997*5b2fc499SJeff Garzik } 998*5b2fc499SJeff Garzik 999*5b2fc499SJeff Garzik return 1; 1000*5b2fc499SJeff Garzik } 1001*5b2fc499SJeff Garzik 1002*5b2fc499SJeff Garzik static int pegasus_open(struct net_device *net) 1003*5b2fc499SJeff Garzik { 1004*5b2fc499SJeff Garzik pegasus_t *pegasus = netdev_priv(net); 1005*5b2fc499SJeff Garzik int res; 1006*5b2fc499SJeff Garzik 1007*5b2fc499SJeff Garzik if (pegasus->rx_skb == NULL) 1008*5b2fc499SJeff Garzik pegasus->rx_skb = pull_skb(pegasus); 1009*5b2fc499SJeff Garzik /* 1010*5b2fc499SJeff Garzik ** Note: no point to free the pool. it is empty :-) 1011*5b2fc499SJeff Garzik */ 1012*5b2fc499SJeff Garzik if (!pegasus->rx_skb) 1013*5b2fc499SJeff Garzik return -ENOMEM; 1014*5b2fc499SJeff Garzik 1015*5b2fc499SJeff Garzik res = set_registers(pegasus, EthID, 6, net->dev_addr); 1016*5b2fc499SJeff Garzik 1017*5b2fc499SJeff Garzik usb_fill_bulk_urb(pegasus->rx_urb, pegasus->usb, 1018*5b2fc499SJeff Garzik usb_rcvbulkpipe(pegasus->usb, 1), 1019*5b2fc499SJeff Garzik pegasus->rx_skb->data, PEGASUS_MTU + 8, 1020*5b2fc499SJeff Garzik read_bulk_callback, pegasus); 1021*5b2fc499SJeff Garzik if ((res = usb_submit_urb(pegasus->rx_urb, GFP_KERNEL))) { 1022*5b2fc499SJeff Garzik if (res == -ENODEV) 1023*5b2fc499SJeff Garzik netif_device_detach(pegasus->net); 1024*5b2fc499SJeff Garzik if (netif_msg_ifup(pegasus)) 1025*5b2fc499SJeff Garzik pr_debug("%s: failed rx_urb, %d", net->name, res); 1026*5b2fc499SJeff Garzik goto exit; 1027*5b2fc499SJeff Garzik } 1028*5b2fc499SJeff Garzik 1029*5b2fc499SJeff Garzik usb_fill_int_urb(pegasus->intr_urb, pegasus->usb, 1030*5b2fc499SJeff Garzik usb_rcvintpipe(pegasus->usb, 3), 1031*5b2fc499SJeff Garzik pegasus->intr_buff, sizeof (pegasus->intr_buff), 1032*5b2fc499SJeff Garzik intr_callback, pegasus, pegasus->intr_interval); 1033*5b2fc499SJeff Garzik if ((res = usb_submit_urb(pegasus->intr_urb, GFP_KERNEL))) { 1034*5b2fc499SJeff Garzik if (res == -ENODEV) 1035*5b2fc499SJeff Garzik netif_device_detach(pegasus->net); 1036*5b2fc499SJeff Garzik if (netif_msg_ifup(pegasus)) 1037*5b2fc499SJeff Garzik pr_debug("%s: failed intr_urb, %d\n", net->name, res); 1038*5b2fc499SJeff Garzik usb_kill_urb(pegasus->rx_urb); 1039*5b2fc499SJeff Garzik goto exit; 1040*5b2fc499SJeff Garzik } 1041*5b2fc499SJeff Garzik if ((res = enable_net_traffic(net, pegasus->usb))) { 1042*5b2fc499SJeff Garzik if (netif_msg_ifup(pegasus)) 1043*5b2fc499SJeff Garzik pr_debug("%s: can't enable_net_traffic() - %d\n", 1044*5b2fc499SJeff Garzik net->name, res); 1045*5b2fc499SJeff Garzik res = -EIO; 1046*5b2fc499SJeff Garzik usb_kill_urb(pegasus->rx_urb); 1047*5b2fc499SJeff Garzik usb_kill_urb(pegasus->intr_urb); 1048*5b2fc499SJeff Garzik free_skb_pool(pegasus); 1049*5b2fc499SJeff Garzik goto exit; 1050*5b2fc499SJeff Garzik } 1051*5b2fc499SJeff Garzik set_carrier(net); 1052*5b2fc499SJeff Garzik netif_start_queue(net); 1053*5b2fc499SJeff Garzik if (netif_msg_ifup(pegasus)) 1054*5b2fc499SJeff Garzik pr_debug("%s: open\n", net->name); 1055*5b2fc499SJeff Garzik res = 0; 1056*5b2fc499SJeff Garzik exit: 1057*5b2fc499SJeff Garzik return res; 1058*5b2fc499SJeff Garzik } 1059*5b2fc499SJeff Garzik 1060*5b2fc499SJeff Garzik static int pegasus_close(struct net_device *net) 1061*5b2fc499SJeff Garzik { 1062*5b2fc499SJeff Garzik pegasus_t *pegasus = netdev_priv(net); 1063*5b2fc499SJeff Garzik 1064*5b2fc499SJeff Garzik netif_stop_queue(net); 1065*5b2fc499SJeff Garzik if (!(pegasus->flags & PEGASUS_UNPLUG)) 1066*5b2fc499SJeff Garzik disable_net_traffic(pegasus); 1067*5b2fc499SJeff Garzik tasklet_kill(&pegasus->rx_tl); 1068*5b2fc499SJeff Garzik unlink_all_urbs(pegasus); 1069*5b2fc499SJeff Garzik 1070*5b2fc499SJeff Garzik return 0; 1071*5b2fc499SJeff Garzik } 1072*5b2fc499SJeff Garzik 1073*5b2fc499SJeff Garzik static void pegasus_get_drvinfo(struct net_device *dev, 1074*5b2fc499SJeff Garzik struct ethtool_drvinfo *info) 1075*5b2fc499SJeff Garzik { 1076*5b2fc499SJeff Garzik pegasus_t *pegasus = netdev_priv(dev); 1077*5b2fc499SJeff Garzik strncpy(info->driver, driver_name, sizeof (info->driver) - 1); 1078*5b2fc499SJeff Garzik strncpy(info->version, DRIVER_VERSION, sizeof (info->version) - 1); 1079*5b2fc499SJeff Garzik usb_make_path(pegasus->usb, info->bus_info, sizeof (info->bus_info)); 1080*5b2fc499SJeff Garzik } 1081*5b2fc499SJeff Garzik 1082*5b2fc499SJeff Garzik /* also handles three patterns of some kind in hardware */ 1083*5b2fc499SJeff Garzik #define WOL_SUPPORTED (WAKE_MAGIC|WAKE_PHY) 1084*5b2fc499SJeff Garzik 1085*5b2fc499SJeff Garzik static void 1086*5b2fc499SJeff Garzik pegasus_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) 1087*5b2fc499SJeff Garzik { 1088*5b2fc499SJeff Garzik pegasus_t *pegasus = netdev_priv(dev); 1089*5b2fc499SJeff Garzik 1090*5b2fc499SJeff Garzik wol->supported = WAKE_MAGIC | WAKE_PHY; 1091*5b2fc499SJeff Garzik wol->wolopts = pegasus->wolopts; 1092*5b2fc499SJeff Garzik } 1093*5b2fc499SJeff Garzik 1094*5b2fc499SJeff Garzik static int 1095*5b2fc499SJeff Garzik pegasus_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) 1096*5b2fc499SJeff Garzik { 1097*5b2fc499SJeff Garzik pegasus_t *pegasus = netdev_priv(dev); 1098*5b2fc499SJeff Garzik u8 reg78 = 0x04; 1099*5b2fc499SJeff Garzik 1100*5b2fc499SJeff Garzik if (wol->wolopts & ~WOL_SUPPORTED) 1101*5b2fc499SJeff Garzik return -EINVAL; 1102*5b2fc499SJeff Garzik 1103*5b2fc499SJeff Garzik if (wol->wolopts & WAKE_MAGIC) 1104*5b2fc499SJeff Garzik reg78 |= 0x80; 1105*5b2fc499SJeff Garzik if (wol->wolopts & WAKE_PHY) 1106*5b2fc499SJeff Garzik reg78 |= 0x40; 1107*5b2fc499SJeff Garzik /* FIXME this 0x10 bit still needs to get set in the chip... */ 1108*5b2fc499SJeff Garzik if (wol->wolopts) 1109*5b2fc499SJeff Garzik pegasus->eth_regs[0] |= 0x10; 1110*5b2fc499SJeff Garzik else 1111*5b2fc499SJeff Garzik pegasus->eth_regs[0] &= ~0x10; 1112*5b2fc499SJeff Garzik pegasus->wolopts = wol->wolopts; 1113*5b2fc499SJeff Garzik return set_register(pegasus, WakeupControl, reg78); 1114*5b2fc499SJeff Garzik } 1115*5b2fc499SJeff Garzik 1116*5b2fc499SJeff Garzik static inline void pegasus_reset_wol(struct net_device *dev) 1117*5b2fc499SJeff Garzik { 1118*5b2fc499SJeff Garzik struct ethtool_wolinfo wol; 1119*5b2fc499SJeff Garzik 1120*5b2fc499SJeff Garzik memset(&wol, 0, sizeof wol); 1121*5b2fc499SJeff Garzik (void) pegasus_set_wol(dev, &wol); 1122*5b2fc499SJeff Garzik } 1123*5b2fc499SJeff Garzik 1124*5b2fc499SJeff Garzik static int 1125*5b2fc499SJeff Garzik pegasus_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) 1126*5b2fc499SJeff Garzik { 1127*5b2fc499SJeff Garzik pegasus_t *pegasus; 1128*5b2fc499SJeff Garzik 1129*5b2fc499SJeff Garzik if (in_atomic()) 1130*5b2fc499SJeff Garzik return 0; 1131*5b2fc499SJeff Garzik 1132*5b2fc499SJeff Garzik pegasus = netdev_priv(dev); 1133*5b2fc499SJeff Garzik mii_ethtool_gset(&pegasus->mii, ecmd); 1134*5b2fc499SJeff Garzik 1135*5b2fc499SJeff Garzik return 0; 1136*5b2fc499SJeff Garzik } 1137*5b2fc499SJeff Garzik 1138*5b2fc499SJeff Garzik static int 1139*5b2fc499SJeff Garzik pegasus_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) 1140*5b2fc499SJeff Garzik { 1141*5b2fc499SJeff Garzik pegasus_t *pegasus = netdev_priv(dev); 1142*5b2fc499SJeff Garzik return mii_ethtool_sset(&pegasus->mii, ecmd); 1143*5b2fc499SJeff Garzik } 1144*5b2fc499SJeff Garzik 1145*5b2fc499SJeff Garzik static int pegasus_nway_reset(struct net_device *dev) 1146*5b2fc499SJeff Garzik { 1147*5b2fc499SJeff Garzik pegasus_t *pegasus = netdev_priv(dev); 1148*5b2fc499SJeff Garzik return mii_nway_restart(&pegasus->mii); 1149*5b2fc499SJeff Garzik } 1150*5b2fc499SJeff Garzik 1151*5b2fc499SJeff Garzik static u32 pegasus_get_link(struct net_device *dev) 1152*5b2fc499SJeff Garzik { 1153*5b2fc499SJeff Garzik pegasus_t *pegasus = netdev_priv(dev); 1154*5b2fc499SJeff Garzik return mii_link_ok(&pegasus->mii); 1155*5b2fc499SJeff Garzik } 1156*5b2fc499SJeff Garzik 1157*5b2fc499SJeff Garzik static u32 pegasus_get_msglevel(struct net_device *dev) 1158*5b2fc499SJeff Garzik { 1159*5b2fc499SJeff Garzik pegasus_t *pegasus = netdev_priv(dev); 1160*5b2fc499SJeff Garzik return pegasus->msg_enable; 1161*5b2fc499SJeff Garzik } 1162*5b2fc499SJeff Garzik 1163*5b2fc499SJeff Garzik static void pegasus_set_msglevel(struct net_device *dev, u32 v) 1164*5b2fc499SJeff Garzik { 1165*5b2fc499SJeff Garzik pegasus_t *pegasus = netdev_priv(dev); 1166*5b2fc499SJeff Garzik pegasus->msg_enable = v; 1167*5b2fc499SJeff Garzik } 1168*5b2fc499SJeff Garzik 1169*5b2fc499SJeff Garzik static struct ethtool_ops ops = { 1170*5b2fc499SJeff Garzik .get_drvinfo = pegasus_get_drvinfo, 1171*5b2fc499SJeff Garzik .get_settings = pegasus_get_settings, 1172*5b2fc499SJeff Garzik .set_settings = pegasus_set_settings, 1173*5b2fc499SJeff Garzik .nway_reset = pegasus_nway_reset, 1174*5b2fc499SJeff Garzik .get_link = pegasus_get_link, 1175*5b2fc499SJeff Garzik .get_msglevel = pegasus_get_msglevel, 1176*5b2fc499SJeff Garzik .set_msglevel = pegasus_set_msglevel, 1177*5b2fc499SJeff Garzik .get_wol = pegasus_get_wol, 1178*5b2fc499SJeff Garzik .set_wol = pegasus_set_wol, 1179*5b2fc499SJeff Garzik }; 1180*5b2fc499SJeff Garzik 1181*5b2fc499SJeff Garzik static int pegasus_ioctl(struct net_device *net, struct ifreq *rq, int cmd) 1182*5b2fc499SJeff Garzik { 1183*5b2fc499SJeff Garzik __u16 *data = (__u16 *) & rq->ifr_ifru; 1184*5b2fc499SJeff Garzik pegasus_t *pegasus = netdev_priv(net); 1185*5b2fc499SJeff Garzik int res; 1186*5b2fc499SJeff Garzik 1187*5b2fc499SJeff Garzik switch (cmd) { 1188*5b2fc499SJeff Garzik case SIOCDEVPRIVATE: 1189*5b2fc499SJeff Garzik data[0] = pegasus->phy; 1190*5b2fc499SJeff Garzik case SIOCDEVPRIVATE + 1: 1191*5b2fc499SJeff Garzik read_mii_word(pegasus, data[0], data[1] & 0x1f, &data[3]); 1192*5b2fc499SJeff Garzik res = 0; 1193*5b2fc499SJeff Garzik break; 1194*5b2fc499SJeff Garzik case SIOCDEVPRIVATE + 2: 1195*5b2fc499SJeff Garzik if (!capable(CAP_NET_ADMIN)) 1196*5b2fc499SJeff Garzik return -EPERM; 1197*5b2fc499SJeff Garzik write_mii_word(pegasus, pegasus->phy, data[1] & 0x1f, data[2]); 1198*5b2fc499SJeff Garzik res = 0; 1199*5b2fc499SJeff Garzik break; 1200*5b2fc499SJeff Garzik default: 1201*5b2fc499SJeff Garzik res = -EOPNOTSUPP; 1202*5b2fc499SJeff Garzik } 1203*5b2fc499SJeff Garzik return res; 1204*5b2fc499SJeff Garzik } 1205*5b2fc499SJeff Garzik 1206*5b2fc499SJeff Garzik static void pegasus_set_multicast(struct net_device *net) 1207*5b2fc499SJeff Garzik { 1208*5b2fc499SJeff Garzik pegasus_t *pegasus = netdev_priv(net); 1209*5b2fc499SJeff Garzik 1210*5b2fc499SJeff Garzik if (net->flags & IFF_PROMISC) { 1211*5b2fc499SJeff Garzik pegasus->eth_regs[EthCtrl2] |= RX_PROMISCUOUS; 1212*5b2fc499SJeff Garzik if (netif_msg_link(pegasus)) 1213*5b2fc499SJeff Garzik pr_info("%s: Promiscuous mode enabled.\n", net->name); 1214*5b2fc499SJeff Garzik } else if (net->mc_count || 1215*5b2fc499SJeff Garzik (net->flags & IFF_ALLMULTI)) { 1216*5b2fc499SJeff Garzik pegasus->eth_regs[EthCtrl0] |= RX_MULTICAST; 1217*5b2fc499SJeff Garzik pegasus->eth_regs[EthCtrl2] &= ~RX_PROMISCUOUS; 1218*5b2fc499SJeff Garzik if (netif_msg_link(pegasus)) 1219*5b2fc499SJeff Garzik pr_info("%s: set allmulti\n", net->name); 1220*5b2fc499SJeff Garzik } else { 1221*5b2fc499SJeff Garzik pegasus->eth_regs[EthCtrl0] &= ~RX_MULTICAST; 1222*5b2fc499SJeff Garzik pegasus->eth_regs[EthCtrl2] &= ~RX_PROMISCUOUS; 1223*5b2fc499SJeff Garzik } 1224*5b2fc499SJeff Garzik 1225*5b2fc499SJeff Garzik pegasus->flags |= ETH_REGS_CHANGE; 1226*5b2fc499SJeff Garzik ctrl_callback(pegasus->ctrl_urb); 1227*5b2fc499SJeff Garzik } 1228*5b2fc499SJeff Garzik 1229*5b2fc499SJeff Garzik static __u8 mii_phy_probe(pegasus_t * pegasus) 1230*5b2fc499SJeff Garzik { 1231*5b2fc499SJeff Garzik int i; 1232*5b2fc499SJeff Garzik __u16 tmp; 1233*5b2fc499SJeff Garzik 1234*5b2fc499SJeff Garzik for (i = 0; i < 32; i++) { 1235*5b2fc499SJeff Garzik read_mii_word(pegasus, i, MII_BMSR, &tmp); 1236*5b2fc499SJeff Garzik if (tmp == 0 || tmp == 0xffff || (tmp & BMSR_MEDIA) == 0) 1237*5b2fc499SJeff Garzik continue; 1238*5b2fc499SJeff Garzik else 1239*5b2fc499SJeff Garzik return i; 1240*5b2fc499SJeff Garzik } 1241*5b2fc499SJeff Garzik 1242*5b2fc499SJeff Garzik return 0xff; 1243*5b2fc499SJeff Garzik } 1244*5b2fc499SJeff Garzik 1245*5b2fc499SJeff Garzik static inline void setup_pegasus_II(pegasus_t * pegasus) 1246*5b2fc499SJeff Garzik { 1247*5b2fc499SJeff Garzik __u8 data = 0xa5; 1248*5b2fc499SJeff Garzik 1249*5b2fc499SJeff Garzik set_register(pegasus, Reg1d, 0); 1250*5b2fc499SJeff Garzik set_register(pegasus, Reg7b, 1); 1251*5b2fc499SJeff Garzik mdelay(100); 1252*5b2fc499SJeff Garzik if ((pegasus->features & HAS_HOME_PNA) && mii_mode) 1253*5b2fc499SJeff Garzik set_register(pegasus, Reg7b, 0); 1254*5b2fc499SJeff Garzik else 1255*5b2fc499SJeff Garzik set_register(pegasus, Reg7b, 2); 1256*5b2fc499SJeff Garzik 1257*5b2fc499SJeff Garzik set_register(pegasus, 0x83, data); 1258*5b2fc499SJeff Garzik get_registers(pegasus, 0x83, 1, &data); 1259*5b2fc499SJeff Garzik 1260*5b2fc499SJeff Garzik if (data == 0xa5) { 1261*5b2fc499SJeff Garzik pegasus->chip = 0x8513; 1262*5b2fc499SJeff Garzik } else { 1263*5b2fc499SJeff Garzik pegasus->chip = 0; 1264*5b2fc499SJeff Garzik } 1265*5b2fc499SJeff Garzik 1266*5b2fc499SJeff Garzik set_register(pegasus, 0x80, 0xc0); 1267*5b2fc499SJeff Garzik set_register(pegasus, 0x83, 0xff); 1268*5b2fc499SJeff Garzik set_register(pegasus, 0x84, 0x01); 1269*5b2fc499SJeff Garzik 1270*5b2fc499SJeff Garzik if (pegasus->features & HAS_HOME_PNA && mii_mode) 1271*5b2fc499SJeff Garzik set_register(pegasus, Reg81, 6); 1272*5b2fc499SJeff Garzik else 1273*5b2fc499SJeff Garzik set_register(pegasus, Reg81, 2); 1274*5b2fc499SJeff Garzik } 1275*5b2fc499SJeff Garzik 1276*5b2fc499SJeff Garzik 1277*5b2fc499SJeff Garzik static struct workqueue_struct *pegasus_workqueue = NULL; 1278*5b2fc499SJeff Garzik #define CARRIER_CHECK_DELAY (2 * HZ) 1279*5b2fc499SJeff Garzik 1280*5b2fc499SJeff Garzik static void check_carrier(struct work_struct *work) 1281*5b2fc499SJeff Garzik { 1282*5b2fc499SJeff Garzik pegasus_t *pegasus = container_of(work, pegasus_t, carrier_check.work); 1283*5b2fc499SJeff Garzik set_carrier(pegasus->net); 1284*5b2fc499SJeff Garzik if (!(pegasus->flags & PEGASUS_UNPLUG)) { 1285*5b2fc499SJeff Garzik queue_delayed_work(pegasus_workqueue, &pegasus->carrier_check, 1286*5b2fc499SJeff Garzik CARRIER_CHECK_DELAY); 1287*5b2fc499SJeff Garzik } 1288*5b2fc499SJeff Garzik } 1289*5b2fc499SJeff Garzik 1290*5b2fc499SJeff Garzik static int pegasus_probe(struct usb_interface *intf, 1291*5b2fc499SJeff Garzik const struct usb_device_id *id) 1292*5b2fc499SJeff Garzik { 1293*5b2fc499SJeff Garzik struct usb_device *dev = interface_to_usbdev(intf); 1294*5b2fc499SJeff Garzik struct net_device *net; 1295*5b2fc499SJeff Garzik pegasus_t *pegasus; 1296*5b2fc499SJeff Garzik int dev_index = id - pegasus_ids; 1297*5b2fc499SJeff Garzik int res = -ENOMEM; 1298*5b2fc499SJeff Garzik 1299*5b2fc499SJeff Garzik usb_get_dev(dev); 1300*5b2fc499SJeff Garzik net = alloc_etherdev(sizeof(struct pegasus)); 1301*5b2fc499SJeff Garzik if (!net) { 1302*5b2fc499SJeff Garzik dev_err(&intf->dev, "can't allocate %s\n", "device"); 1303*5b2fc499SJeff Garzik goto out; 1304*5b2fc499SJeff Garzik } 1305*5b2fc499SJeff Garzik 1306*5b2fc499SJeff Garzik pegasus = netdev_priv(net); 1307*5b2fc499SJeff Garzik memset(pegasus, 0, sizeof (struct pegasus)); 1308*5b2fc499SJeff Garzik pegasus->dev_index = dev_index; 1309*5b2fc499SJeff Garzik init_waitqueue_head(&pegasus->ctrl_wait); 1310*5b2fc499SJeff Garzik 1311*5b2fc499SJeff Garzik if (!alloc_urbs(pegasus)) { 1312*5b2fc499SJeff Garzik dev_err(&intf->dev, "can't allocate %s\n", "urbs"); 1313*5b2fc499SJeff Garzik goto out1; 1314*5b2fc499SJeff Garzik } 1315*5b2fc499SJeff Garzik 1316*5b2fc499SJeff Garzik tasklet_init(&pegasus->rx_tl, rx_fixup, (unsigned long) pegasus); 1317*5b2fc499SJeff Garzik 1318*5b2fc499SJeff Garzik INIT_DELAYED_WORK(&pegasus->carrier_check, check_carrier); 1319*5b2fc499SJeff Garzik 1320*5b2fc499SJeff Garzik pegasus->intf = intf; 1321*5b2fc499SJeff Garzik pegasus->usb = dev; 1322*5b2fc499SJeff Garzik pegasus->net = net; 1323*5b2fc499SJeff Garzik SET_MODULE_OWNER(net); 1324*5b2fc499SJeff Garzik net->open = pegasus_open; 1325*5b2fc499SJeff Garzik net->stop = pegasus_close; 1326*5b2fc499SJeff Garzik net->watchdog_timeo = PEGASUS_TX_TIMEOUT; 1327*5b2fc499SJeff Garzik net->tx_timeout = pegasus_tx_timeout; 1328*5b2fc499SJeff Garzik net->do_ioctl = pegasus_ioctl; 1329*5b2fc499SJeff Garzik net->hard_start_xmit = pegasus_start_xmit; 1330*5b2fc499SJeff Garzik net->set_multicast_list = pegasus_set_multicast; 1331*5b2fc499SJeff Garzik net->get_stats = pegasus_netdev_stats; 1332*5b2fc499SJeff Garzik SET_ETHTOOL_OPS(net, &ops); 1333*5b2fc499SJeff Garzik pegasus->mii.dev = net; 1334*5b2fc499SJeff Garzik pegasus->mii.mdio_read = mdio_read; 1335*5b2fc499SJeff Garzik pegasus->mii.mdio_write = mdio_write; 1336*5b2fc499SJeff Garzik pegasus->mii.phy_id_mask = 0x1f; 1337*5b2fc499SJeff Garzik pegasus->mii.reg_num_mask = 0x1f; 1338*5b2fc499SJeff Garzik spin_lock_init(&pegasus->rx_pool_lock); 1339*5b2fc499SJeff Garzik pegasus->msg_enable = netif_msg_init (msg_level, NETIF_MSG_DRV 1340*5b2fc499SJeff Garzik | NETIF_MSG_PROBE | NETIF_MSG_LINK); 1341*5b2fc499SJeff Garzik 1342*5b2fc499SJeff Garzik pegasus->features = usb_dev_id[dev_index].private; 1343*5b2fc499SJeff Garzik get_interrupt_interval(pegasus); 1344*5b2fc499SJeff Garzik if (reset_mac(pegasus)) { 1345*5b2fc499SJeff Garzik dev_err(&intf->dev, "can't reset MAC\n"); 1346*5b2fc499SJeff Garzik res = -EIO; 1347*5b2fc499SJeff Garzik goto out2; 1348*5b2fc499SJeff Garzik } 1349*5b2fc499SJeff Garzik set_ethernet_addr(pegasus); 1350*5b2fc499SJeff Garzik fill_skb_pool(pegasus); 1351*5b2fc499SJeff Garzik if (pegasus->features & PEGASUS_II) { 1352*5b2fc499SJeff Garzik dev_info(&intf->dev, "setup Pegasus II specific registers\n"); 1353*5b2fc499SJeff Garzik setup_pegasus_II(pegasus); 1354*5b2fc499SJeff Garzik } 1355*5b2fc499SJeff Garzik pegasus->phy = mii_phy_probe(pegasus); 1356*5b2fc499SJeff Garzik if (pegasus->phy == 0xff) { 1357*5b2fc499SJeff Garzik dev_warn(&intf->dev, "can't locate MII phy, using default\n"); 1358*5b2fc499SJeff Garzik pegasus->phy = 1; 1359*5b2fc499SJeff Garzik } 1360*5b2fc499SJeff Garzik pegasus->mii.phy_id = pegasus->phy; 1361*5b2fc499SJeff Garzik usb_set_intfdata(intf, pegasus); 1362*5b2fc499SJeff Garzik SET_NETDEV_DEV(net, &intf->dev); 1363*5b2fc499SJeff Garzik pegasus_reset_wol(net); 1364*5b2fc499SJeff Garzik res = register_netdev(net); 1365*5b2fc499SJeff Garzik if (res) 1366*5b2fc499SJeff Garzik goto out3; 1367*5b2fc499SJeff Garzik queue_delayed_work(pegasus_workqueue, &pegasus->carrier_check, 1368*5b2fc499SJeff Garzik CARRIER_CHECK_DELAY); 1369*5b2fc499SJeff Garzik 1370*5b2fc499SJeff Garzik dev_info(&intf->dev, "%s, %s, %02x:%02x:%02x:%02x:%02x:%02x\n", 1371*5b2fc499SJeff Garzik net->name, 1372*5b2fc499SJeff Garzik usb_dev_id[dev_index].name, 1373*5b2fc499SJeff Garzik net->dev_addr [0], net->dev_addr [1], 1374*5b2fc499SJeff Garzik net->dev_addr [2], net->dev_addr [3], 1375*5b2fc499SJeff Garzik net->dev_addr [4], net->dev_addr [5]); 1376*5b2fc499SJeff Garzik return 0; 1377*5b2fc499SJeff Garzik 1378*5b2fc499SJeff Garzik out3: 1379*5b2fc499SJeff Garzik usb_set_intfdata(intf, NULL); 1380*5b2fc499SJeff Garzik free_skb_pool(pegasus); 1381*5b2fc499SJeff Garzik out2: 1382*5b2fc499SJeff Garzik free_all_urbs(pegasus); 1383*5b2fc499SJeff Garzik out1: 1384*5b2fc499SJeff Garzik free_netdev(net); 1385*5b2fc499SJeff Garzik out: 1386*5b2fc499SJeff Garzik usb_put_dev(dev); 1387*5b2fc499SJeff Garzik return res; 1388*5b2fc499SJeff Garzik } 1389*5b2fc499SJeff Garzik 1390*5b2fc499SJeff Garzik static void pegasus_disconnect(struct usb_interface *intf) 1391*5b2fc499SJeff Garzik { 1392*5b2fc499SJeff Garzik struct pegasus *pegasus = usb_get_intfdata(intf); 1393*5b2fc499SJeff Garzik 1394*5b2fc499SJeff Garzik usb_set_intfdata(intf, NULL); 1395*5b2fc499SJeff Garzik if (!pegasus) { 1396*5b2fc499SJeff Garzik dev_dbg(&intf->dev, "unregistering non-bound device?\n"); 1397*5b2fc499SJeff Garzik return; 1398*5b2fc499SJeff Garzik } 1399*5b2fc499SJeff Garzik 1400*5b2fc499SJeff Garzik pegasus->flags |= PEGASUS_UNPLUG; 1401*5b2fc499SJeff Garzik cancel_delayed_work(&pegasus->carrier_check); 1402*5b2fc499SJeff Garzik unregister_netdev(pegasus->net); 1403*5b2fc499SJeff Garzik usb_put_dev(interface_to_usbdev(intf)); 1404*5b2fc499SJeff Garzik unlink_all_urbs(pegasus); 1405*5b2fc499SJeff Garzik free_all_urbs(pegasus); 1406*5b2fc499SJeff Garzik free_skb_pool(pegasus); 1407*5b2fc499SJeff Garzik if (pegasus->rx_skb != NULL) { 1408*5b2fc499SJeff Garzik dev_kfree_skb(pegasus->rx_skb); 1409*5b2fc499SJeff Garzik pegasus->rx_skb = NULL; 1410*5b2fc499SJeff Garzik } 1411*5b2fc499SJeff Garzik free_netdev(pegasus->net); 1412*5b2fc499SJeff Garzik } 1413*5b2fc499SJeff Garzik 1414*5b2fc499SJeff Garzik static int pegasus_suspend (struct usb_interface *intf, pm_message_t message) 1415*5b2fc499SJeff Garzik { 1416*5b2fc499SJeff Garzik struct pegasus *pegasus = usb_get_intfdata(intf); 1417*5b2fc499SJeff Garzik 1418*5b2fc499SJeff Garzik netif_device_detach (pegasus->net); 1419*5b2fc499SJeff Garzik cancel_delayed_work(&pegasus->carrier_check); 1420*5b2fc499SJeff Garzik if (netif_running(pegasus->net)) { 1421*5b2fc499SJeff Garzik usb_kill_urb(pegasus->rx_urb); 1422*5b2fc499SJeff Garzik usb_kill_urb(pegasus->intr_urb); 1423*5b2fc499SJeff Garzik } 1424*5b2fc499SJeff Garzik return 0; 1425*5b2fc499SJeff Garzik } 1426*5b2fc499SJeff Garzik 1427*5b2fc499SJeff Garzik static int pegasus_resume (struct usb_interface *intf) 1428*5b2fc499SJeff Garzik { 1429*5b2fc499SJeff Garzik struct pegasus *pegasus = usb_get_intfdata(intf); 1430*5b2fc499SJeff Garzik 1431*5b2fc499SJeff Garzik netif_device_attach (pegasus->net); 1432*5b2fc499SJeff Garzik if (netif_running(pegasus->net)) { 1433*5b2fc499SJeff Garzik pegasus->rx_urb->status = 0; 1434*5b2fc499SJeff Garzik pegasus->rx_urb->actual_length = 0; 1435*5b2fc499SJeff Garzik read_bulk_callback(pegasus->rx_urb); 1436*5b2fc499SJeff Garzik 1437*5b2fc499SJeff Garzik pegasus->intr_urb->status = 0; 1438*5b2fc499SJeff Garzik pegasus->intr_urb->actual_length = 0; 1439*5b2fc499SJeff Garzik intr_callback(pegasus->intr_urb); 1440*5b2fc499SJeff Garzik } 1441*5b2fc499SJeff Garzik queue_delayed_work(pegasus_workqueue, &pegasus->carrier_check, 1442*5b2fc499SJeff Garzik CARRIER_CHECK_DELAY); 1443*5b2fc499SJeff Garzik return 0; 1444*5b2fc499SJeff Garzik } 1445*5b2fc499SJeff Garzik 1446*5b2fc499SJeff Garzik static struct usb_driver pegasus_driver = { 1447*5b2fc499SJeff Garzik .name = driver_name, 1448*5b2fc499SJeff Garzik .probe = pegasus_probe, 1449*5b2fc499SJeff Garzik .disconnect = pegasus_disconnect, 1450*5b2fc499SJeff Garzik .id_table = pegasus_ids, 1451*5b2fc499SJeff Garzik .suspend = pegasus_suspend, 1452*5b2fc499SJeff Garzik .resume = pegasus_resume, 1453*5b2fc499SJeff Garzik }; 1454*5b2fc499SJeff Garzik 1455*5b2fc499SJeff Garzik static void parse_id(char *id) 1456*5b2fc499SJeff Garzik { 1457*5b2fc499SJeff Garzik unsigned int vendor_id=0, device_id=0, flags=0, i=0; 1458*5b2fc499SJeff Garzik char *token, *name=NULL; 1459*5b2fc499SJeff Garzik 1460*5b2fc499SJeff Garzik if ((token = strsep(&id, ":")) != NULL) 1461*5b2fc499SJeff Garzik name = token; 1462*5b2fc499SJeff Garzik /* name now points to a null terminated string*/ 1463*5b2fc499SJeff Garzik if ((token = strsep(&id, ":")) != NULL) 1464*5b2fc499SJeff Garzik vendor_id = simple_strtoul(token, NULL, 16); 1465*5b2fc499SJeff Garzik if ((token = strsep(&id, ":")) != NULL) 1466*5b2fc499SJeff Garzik device_id = simple_strtoul(token, NULL, 16); 1467*5b2fc499SJeff Garzik flags = simple_strtoul(id, NULL, 16); 1468*5b2fc499SJeff Garzik pr_info("%s: new device %s, vendor ID 0x%04x, device ID 0x%04x, flags: 0x%x\n", 1469*5b2fc499SJeff Garzik driver_name, name, vendor_id, device_id, flags); 1470*5b2fc499SJeff Garzik 1471*5b2fc499SJeff Garzik if (vendor_id > 0x10000 || vendor_id == 0) 1472*5b2fc499SJeff Garzik return; 1473*5b2fc499SJeff Garzik if (device_id > 0x10000 || device_id == 0) 1474*5b2fc499SJeff Garzik return; 1475*5b2fc499SJeff Garzik 1476*5b2fc499SJeff Garzik for (i=0; usb_dev_id[i].name; i++); 1477*5b2fc499SJeff Garzik usb_dev_id[i].name = name; 1478*5b2fc499SJeff Garzik usb_dev_id[i].vendor = vendor_id; 1479*5b2fc499SJeff Garzik usb_dev_id[i].device = device_id; 1480*5b2fc499SJeff Garzik usb_dev_id[i].private = flags; 1481*5b2fc499SJeff Garzik pegasus_ids[i].match_flags = USB_DEVICE_ID_MATCH_DEVICE; 1482*5b2fc499SJeff Garzik pegasus_ids[i].idVendor = vendor_id; 1483*5b2fc499SJeff Garzik pegasus_ids[i].idProduct = device_id; 1484*5b2fc499SJeff Garzik } 1485*5b2fc499SJeff Garzik 1486*5b2fc499SJeff Garzik static int __init pegasus_init(void) 1487*5b2fc499SJeff Garzik { 1488*5b2fc499SJeff Garzik pr_info("%s: %s, " DRIVER_DESC "\n", driver_name, DRIVER_VERSION); 1489*5b2fc499SJeff Garzik if (devid) 1490*5b2fc499SJeff Garzik parse_id(devid); 1491*5b2fc499SJeff Garzik pegasus_workqueue = create_singlethread_workqueue("pegasus"); 1492*5b2fc499SJeff Garzik if (!pegasus_workqueue) 1493*5b2fc499SJeff Garzik return -ENOMEM; 1494*5b2fc499SJeff Garzik return usb_register(&pegasus_driver); 1495*5b2fc499SJeff Garzik } 1496*5b2fc499SJeff Garzik 1497*5b2fc499SJeff Garzik static void __exit pegasus_exit(void) 1498*5b2fc499SJeff Garzik { 1499*5b2fc499SJeff Garzik destroy_workqueue(pegasus_workqueue); 1500*5b2fc499SJeff Garzik usb_deregister(&pegasus_driver); 1501*5b2fc499SJeff Garzik } 1502*5b2fc499SJeff Garzik 1503*5b2fc499SJeff Garzik module_init(pegasus_init); 1504*5b2fc499SJeff Garzik module_exit(pegasus_exit); 1505