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