rtl8150.c
来自「是关于linux2.5.1的完全源码」· C语言 代码 · 共 835 行 · 第 1/2 页
C
835 行
/* * Copyright (c) 2002 Petko Manolov (petkan@users.sourceforge.net) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * */#include <linux/config.h>#include <linux/sched.h>#include <linux/signal.h>#include <linux/slab.h>#include <linux/module.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/mii.h>#include <linux/ethtool.h>#include <linux/devfs_fs_kernel.h>#include <linux/usb.h>#include <asm/uaccess.h>/* Version Information */#define DRIVER_VERSION "v0.5.4 (2002/04/11)"#define DRIVER_AUTHOR "Petko Manolov <petkan@users.sourceforge.net>"#define DRIVER_DESC "rtl8150 based usb-ethernet driver"#define IRD 0x0120#define MAR 0x0126#define CR 0x012e#define TCR 0x012f#define RCR 0x0130#define TSR 0x0132#define RSR 0x0133#define CON0 0x0135#define CON1 0x0136#define MSR 0x0137#define PHYADD 0x0138#define PHYDAT 0x0139#define PHYCNT 0x013b#define GPPC 0x013d#define BMCR 0x0140#define BMSR 0x0142#define ANAR 0x0144#define ANLP 0x0146#define AER 0x0148#define PHY_READ 0#define PHY_WRITE 0x20#define PHY_GO 0x40#define MII_TIMEOUT 10#define RTL8150_REQT_READ 0xc0#define RTL8150_REQT_WRITE 0x40#define RTL8150_REQ_GET_REGS 0x05#define RTL8150_REQ_SET_REGS 0x05#define RTL8150_MTU 1540#define RTL8150_TX_TIMEOUT (HZ)#define RX_SKB_POOL_SIZE 4/* rtl8150 flags */#define RTL8150_HW_CRC 0#define RX_REG_SET 1#define RTL8150_UNPLUG 2#define RX_URB_FAIL 3/* Define these values to match your device */#define VENDOR_ID_REALTEK 0x0bda#define PRODUCT_ID_RTL8150 0x8150/* table of devices that work with this driver */static struct usb_device_id rtl8150_table[] = { {USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8150)}, {}};MODULE_DEVICE_TABLE(usb, rtl8150_table);struct rtl8150 { unsigned long flags; struct usb_device *udev; struct semaphore sem; struct tasklet_struct tl; struct net_device_stats stats; struct net_device *netdev; struct urb *rx_urb, *tx_urb, *intr_urb, *ctrl_urb; struct sk_buff *tx_skb, *rx_skb; struct sk_buff *rx_skb_pool[RX_SKB_POOL_SIZE]; spinlock_t rx_pool_lock; struct usb_ctrlrequest dr; int intr_interval; u16 rx_creg; u8 intr_buff[8]; u8 phy;};typedef struct rtl8150 rtl8150_t;/* the global usb devfs handle */extern devfs_handle_t usb_devfs_handle;unsigned long multicast_filter_limit = 32;static void fill_skb_pool(rtl8150_t *);static void free_skb_pool(rtl8150_t *);static struct sk_buff *pull_skb(rtl8150_t *);static void rtl8150_disconnect(struct usb_device *dev, void *ptr);static void *rtl8150_probe(struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id);static struct usb_driver rtl8150_driver = { name: "rtl8150", probe: rtl8150_probe, disconnect: rtl8150_disconnect, id_table: rtl8150_table,};/***** device related part of the code***/static int get_registers(rtl8150_t * dev, u16 indx, u16 size, void *data){ return usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), RTL8150_REQ_GET_REGS, RTL8150_REQT_READ, indx, 0, data, size, HZ / 2);}static int set_registers(rtl8150_t * dev, u16 indx, u16 size, void *data){ return usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), RTL8150_REQ_SET_REGS, RTL8150_REQT_WRITE, indx, 0, data, size, HZ / 2);}static void ctrl_callback(struct urb *urb){ rtl8150_t *dev; switch (urb->status) { case 0: break; case -EINPROGRESS: break; case -ENOENT: break; default: warn("ctrl urb status %d", urb->status); } dev = urb->context; clear_bit(RX_REG_SET, &dev->flags);}static int async_set_registers(rtl8150_t * dev, u16 indx, u16 size, void *data){ int ret; if (test_bit(RX_REG_SET, &dev->flags)) return -EAGAIN; dev->dr.bRequestType = RTL8150_REQT_WRITE; dev->dr.bRequest = RTL8150_REQ_SET_REGS; dev->dr.wValue = cpu_to_le16(indx); dev->dr.wIndex = 0; dev->dr.wLength = cpu_to_le16(size); dev->ctrl_urb->transfer_buffer_length = size; FILL_CONTROL_URB(dev->ctrl_urb, dev->udev, usb_sndctrlpipe(dev->udev, 0), (char *) &dev->dr, &dev->rx_creg, size, ctrl_callback, dev); if ((ret = usb_submit_urb(dev->ctrl_urb, GFP_ATOMIC))) err("control request submission failed: %d", ret); else set_bit(RX_REG_SET, &dev->flags); return ret;}static int read_mii_word(rtl8150_t * dev, u8 phy, __u8 indx, u16 * reg){ int i; u8 data[3], tmp; data[0] = phy; data[1] = data[2] = 0; tmp = indx | PHY_READ | PHY_GO; i = 0; set_registers(dev, PHYADD, sizeof(data), data); set_registers(dev, PHYCNT, 1, &tmp); do { get_registers(dev, PHYCNT, 1, data); } while ((data[0] & PHY_GO) && (i++ < MII_TIMEOUT)); if (i < MII_TIMEOUT) { get_registers(dev, PHYDAT, 2, data); *reg = le16_to_cpup(data); return 0; } else return 1;}static int write_mii_word(rtl8150_t * dev, u8 phy, __u8 indx, u16 reg){ int i; u8 data[3], tmp; data[0] = phy; *(data + 1) = cpu_to_le16p(®); tmp = indx | PHY_WRITE | PHY_GO; i = 0; set_registers(dev, PHYADD, sizeof(data), data); set_registers(dev, PHYCNT, 1, &tmp); do { get_registers(dev, PHYCNT, 1, data); } while ((data[0] & PHY_GO) && (i++ < MII_TIMEOUT)); if (i < MII_TIMEOUT) return 0; else return 1;}static inline void set_ethernet_addr(rtl8150_t * dev){ u8 node_id[6]; get_registers(dev, IRD, sizeof(node_id), node_id); memcpy(dev->netdev->dev_addr, node_id, sizeof(node_id));}static int rtl8150_reset(rtl8150_t * dev){ u8 data = 0x10; int i = HZ; set_registers(dev, CR, 1, &data); do { get_registers(dev, CR, 1, &data); } while ((data & 0x10) && --i); return (i > 0) ? 1 : 0;}static int alloc_all_urbs(rtl8150_t * dev){ dev->rx_urb = usb_alloc_urb(0, GFP_KERNEL); if (!dev->rx_urb) return 0; dev->tx_urb = usb_alloc_urb(0, GFP_KERNEL); if (!dev->tx_urb) { usb_free_urb(dev->rx_urb); return 0; } dev->intr_urb = usb_alloc_urb(0, GFP_KERNEL); if (!dev->intr_urb) { usb_free_urb(dev->rx_urb); usb_free_urb(dev->tx_urb); return 0; } dev->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL); if (!dev->intr_urb) { usb_free_urb(dev->rx_urb); usb_free_urb(dev->tx_urb); usb_free_urb(dev->intr_urb); return 0; } return 1;}static void free_all_urbs(rtl8150_t * dev){ usb_free_urb(dev->rx_urb); usb_free_urb(dev->tx_urb); usb_free_urb(dev->intr_urb); usb_free_urb(dev->ctrl_urb);}static void unlink_all_urbs(rtl8150_t * dev){ usb_unlink_urb(dev->rx_urb); usb_unlink_urb(dev->tx_urb); usb_unlink_urb(dev->intr_urb); usb_unlink_urb(dev->ctrl_urb);}static void read_bulk_callback(struct urb *urb){ rtl8150_t *dev; unsigned pkt_len, res; struct sk_buff *skb; struct net_device *netdev; u16 rx_stat; dev = urb->context; if (!dev) return; if (test_bit(RTL8150_UNPLUG, &dev->flags)) return; netdev = dev->netdev; if (!netif_device_present(netdev)) return; switch (urb->status) { case 0: break; case -ENOENT: return; /* the urb is in unlink state */ case -ETIMEDOUT: warn("reset needed may be?.."); goto goon; default: warn("Rx status %d", urb->status); goto goon; } if (!dev->rx_skb) goto resched; res = urb->actual_length; rx_stat = le16_to_cpu(*(short *)(urb->transfer_buffer + res - 4)); pkt_len = res - 4; skb_put(dev->rx_skb, pkt_len); dev->rx_skb->protocol = eth_type_trans(dev->rx_skb, netdev); netif_rx(dev->rx_skb); dev->stats.rx_packets++; dev->stats.rx_bytes += pkt_len; skb = pull_skb(dev); if (!skb) goto resched; skb->dev = netdev; skb_reserve(skb, 2); dev->rx_skb = skb;goon: FILL_BULK_URB(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1), dev->rx_skb->data, RTL8150_MTU, read_bulk_callback, dev); if (usb_submit_urb(dev->rx_urb, GFP_ATOMIC)) { set_bit(RX_URB_FAIL, &dev->flags); goto resched; } else { clear_bit(RX_URB_FAIL, &dev->flags); } return;resched: tasklet_schedule(&dev->tl);}static void rx_fixup(unsigned long data){ rtl8150_t *dev; struct sk_buff *skb; dev = (rtl8150_t *)data; fill_skb_pool(dev); if (test_bit(RX_URB_FAIL, &dev->flags)) if (dev->rx_skb) goto try_again; if (!(skb = pull_skb(dev))) goto tlsched; dev->rx_skb = skb; FILL_BULK_URB(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1), dev->rx_skb->data, RTL8150_MTU, read_bulk_callback, dev);try_again: if (usb_submit_urb(dev->rx_urb, GFP_ATOMIC)) { set_bit(RX_URB_FAIL, &dev->flags); goto tlsched; } else { clear_bit(RX_URB_FAIL, &dev->flags); } return;tlsched: tasklet_schedule(&dev->tl);}static void write_bulk_callback(struct urb *urb){ rtl8150_t *dev; dev = urb->context; if (!dev) return; dev_kfree_skb_irq(dev->tx_skb); if (!netif_device_present(dev->netdev)) return; if (urb->status) info("%s: Tx status %d", dev->netdev->name, urb->status); dev->netdev->trans_start = jiffies; netif_wake_queue(dev->netdev);}void intr_callback(struct urb *urb){ rtl8150_t *dev; dev = urb->context; if (!dev) return; switch (urb->status) { case 0: break; case -ENOENT: return; default: info("%s: intr status %d", dev->netdev->name, urb->status); }}/*
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?