📄 catc.c
字号:
if (urb->status) dbg("ctrl_done, status %d, len %d.", urb->status, urb->actual_length); spin_lock_irqsave(&catc->ctrl_lock, flags); q = catc->ctrl_queue + catc->ctrl_tail; if (q->dir) { if (q->buf && q->len) memcpy(q->buf, catc->ctrl_buf, q->len); else q->buf = catc->ctrl_buf; } if (q->callback) q->callback(catc, q); catc->ctrl_tail = (catc->ctrl_tail + 1) & (CTRL_QUEUE - 1); if (catc->ctrl_head != catc->ctrl_tail) catc_ctrl_run(catc); else clear_bit(CTRL_RUNNING, &catc->flags); spin_unlock_irqrestore(&catc->ctrl_lock, flags);}static int catc_ctrl_async(struct catc *catc, u8 dir, u8 request, u16 value, u16 index, void *buf, int len, void (*callback)(struct catc *catc, struct ctrl_queue *q)){ struct ctrl_queue *q; int retval = 0; unsigned long flags; spin_lock_irqsave(&catc->ctrl_lock, flags); q = catc->ctrl_queue + catc->ctrl_head; q->dir = dir; q->request = request; q->value = value; q->index = index; q->buf = buf; q->len = len; q->callback = callback; catc->ctrl_head = (catc->ctrl_head + 1) & (CTRL_QUEUE - 1); if (catc->ctrl_head == catc->ctrl_tail) { err("ctrl queue full"); catc->ctrl_tail = (catc->ctrl_tail + 1) & (CTRL_QUEUE - 1); retval = -1; } if (!test_and_set_bit(CTRL_RUNNING, &catc->flags)) catc_ctrl_run(catc); spin_unlock_irqrestore(&catc->ctrl_lock, flags); return retval;}/* * Statistics. */static void catc_stats_done(struct catc *catc, struct ctrl_queue *q){ int index = q->index - EthStats; u16 data, last; catc->stats_buf[index] = *((char *)q->buf); if (index & 1) return; data = ((u16)catc->stats_buf[index] << 8) | catc->stats_buf[index + 1]; last = catc->stats_vals[index >> 1]; switch (index) { case TxSingleColl: case TxMultiColl: catc->stats.collisions += data - last; break; case TxExcessColl: catc->stats.tx_aborted_errors += data - last; catc->stats.tx_errors += data - last; break; case RxFramErr: catc->stats.rx_frame_errors += data - last; catc->stats.rx_errors += data - last; break; } catc->stats_vals[index >> 1] = data;}static void catc_stats_timer(unsigned long data){ struct catc *catc = (void *) data; int i; for (i = 0; i < 8; i++) catc_get_reg_async(catc, EthStats + 7 - i, catc_stats_done); mod_timer(&catc->timer, jiffies + STATS_UPDATE);}static struct net_device_stats *catc_get_stats(struct net_device *netdev){ struct catc *catc = netdev->priv; return &catc->stats;}/* * Receive modes. Broadcast, Multicast, Promisc. */static inline u32 ether_crc_le(int cnt, unsigned char *addr){ unsigned int crc = 0xffffffff; u8 byte, idx, bit; for (idx = 0; idx < cnt; idx++) for (byte = *addr++, bit = 0; bit < 8; bit++, byte >>= 1) crc = (crc >> 1) ^ (((crc ^ byte) & 1) ? 0xedb88320U : 0); return crc;}static void catc_multicast(unsigned char *addr, u8 *multicast){ unsigned int crc = ether_crc_le(6, addr); multicast[(crc >> 3) & 0x3f] |= 1 << (crc & 7);}static void catc_set_multicast_list(struct net_device *netdev){ struct catc *catc = netdev->priv; struct dev_mc_list *mc; u8 broadcast[6]; u8 rx = RxEnable | RxPolarity | RxMultiCast; int i; memset(broadcast, 0xff, 6); memset(catc->multicast, 0, 64); catc_multicast(broadcast, catc->multicast); catc_multicast(netdev->dev_addr, catc->multicast); if (netdev->flags & IFF_PROMISC) { memset(catc->multicast, 0xff, 64); rx |= (!catc->is_f5u011) ? RxPromisc : AltRxPromisc; } if (netdev->flags & IFF_ALLMULTI) { memset(catc->multicast, 0xff, 64); } else { for (i = 0, mc = netdev->mc_list; mc && i < netdev->mc_count; i++, mc = mc->next) { u32 crc = ether_crc_le(6, mc->dmi_addr); if (!catc->is_f5u011) { catc->multicast[(crc >> 3) & 0x3f] |= 1 << (crc & 7); } else { catc->multicast[7-(crc >> 29)] |= 1 << ((crc >> 26) & 7); } } } if (!catc->is_f5u011) { catc_set_reg_async(catc, RxUnit, rx); catc_write_mem_async(catc, 0xfa80, catc->multicast, 64); } else { f5u011_mchash_async(catc, catc->multicast); if (catc->rxmode[0] != rx) { catc->rxmode[0] = rx; dbg("Setting RX mode to %2.2X %2.2X", catc->rxmode[0], catc->rxmode[1]); f5u011_rxmode_async(catc, catc->rxmode); } }}/* * ioctl's */static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr){ struct catc *catc = dev->priv; u32 cmd; char tmp[40]; if (get_user(cmd, (u32 *)useraddr)) return -EFAULT; switch (cmd) { /* get driver info */ case ETHTOOL_GDRVINFO: { struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO}; strncpy(info.driver, SHORT_DRIVER_DESC, ETHTOOL_BUSINFO_LEN); strncpy(info.version, DRIVER_VERSION, ETHTOOL_BUSINFO_LEN); sprintf(tmp, "usb%d:%d", catc->usbdev->bus->busnum, catc->usbdev->devnum); strncpy(info.bus_info, tmp,ETHTOOL_BUSINFO_LEN); if (copy_to_user(useraddr, &info, sizeof(info))) return -EFAULT; return 0; } /* get settings */ case ETHTOOL_GSET: if (catc->is_f5u011) { struct ethtool_cmd ecmd = { ETHTOOL_GSET, SUPPORTED_10baseT_Half | SUPPORTED_TP, ADVERTISED_10baseT_Half | ADVERTISED_TP, SPEED_10, DUPLEX_HALF, PORT_TP, 0, XCVR_INTERNAL, AUTONEG_DISABLE, 1, 1 }; if (copy_to_user(useraddr, &ecmd, sizeof(ecmd))) return -EFAULT; return 0; } else { return -EOPNOTSUPP; } /* get link status */ case ETHTOOL_GLINK: { struct ethtool_value edata = {ETHTOOL_GLINK}; edata.data = netif_carrier_ok(dev); if (copy_to_user(useraddr, &edata, sizeof(edata))) return -EFAULT; return 0; } } /* Note that the ethtool user space code requires EOPNOTSUPP */ return -EOPNOTSUPP;}static int catc_ioctl(struct net_device *dev, struct ifreq *rq, int cmd){ switch(cmd) { case SIOCETHTOOL: return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); default: return -ENOTTY; /* Apparently this is the standard ioctl errno */ }}/* * Open, close. */static int catc_open(struct net_device *netdev){ struct catc *catc = netdev->priv; int status; catc->irq_urb.dev = catc->usbdev; if ((status = usb_submit_urb(&catc->irq_urb)) < 0) { err("submit(irq_urb) status %d", status); return -1; } netif_start_queue(netdev); if (!catc->is_f5u011) mod_timer(&catc->timer, jiffies + STATS_UPDATE); return 0;}static int catc_stop(struct net_device *netdev){ struct catc *catc = netdev->priv; netif_stop_queue(netdev); if (!catc->is_f5u011) del_timer_sync(&catc->timer); usb_unlink_urb(&catc->rx_urb); usb_unlink_urb(&catc->tx_urb); usb_unlink_urb(&catc->irq_urb); usb_unlink_urb(&catc->ctrl_urb); return 0;}/* * USB probe, disconnect. */static void *catc_probe(struct usb_device *usbdev, unsigned int ifnum, const struct usb_device_id *id){ struct net_device *netdev; struct catc *catc; u8 broadcast[6]; int i, pktsz; if (usb_set_interface(usbdev, ifnum, 1)) { err("Can't set altsetting 1."); return NULL; } catc = kmalloc(sizeof(struct catc), GFP_KERNEL); if (!catc) return NULL; memset(catc, 0, sizeof(struct catc)); netdev = init_etherdev(0, 0); if (!netdev) { kfree(catc); return NULL; } netdev->open = catc_open; netdev->hard_start_xmit = catc_hard_start_xmit; netdev->stop = catc_stop; netdev->get_stats = catc_get_stats; netdev->tx_timeout = catc_tx_timeout; netdev->watchdog_timeo = TX_TIMEOUT; netdev->set_multicast_list = catc_set_multicast_list; netdev->do_ioctl = catc_ioctl; netdev->priv = catc; catc->usbdev = usbdev; catc->netdev = netdev; catc->tx_lock = SPIN_LOCK_UNLOCKED; catc->ctrl_lock = SPIN_LOCK_UNLOCKED; init_timer(&catc->timer); catc->timer.data = (long) catc; catc->timer.function = catc_stats_timer; /* The F5U011 has the same vendor/product as the netmate * but a device version of 0x130 */ if (usbdev->descriptor.idVendor == 0x0423 && usbdev->descriptor.idProduct == 0xa && catc->usbdev->descriptor.bcdDevice == 0x0130) { dbg("Testing for f5u011"); catc->is_f5u011 = 1; atomic_set(&catc->recq_sz, 0); pktsz = RX_PKT_SZ; } else { pktsz = RX_MAX_BURST * (PKT_SZ + 2); } FILL_CONTROL_URB(&catc->ctrl_urb, usbdev, usb_sndctrlpipe(usbdev, 0), NULL, NULL, 0, catc_ctrl_done, catc); FILL_BULK_URB(&catc->tx_urb, usbdev, usb_sndbulkpipe(usbdev, 1), NULL, 0, catc_tx_done, catc); FILL_BULK_URB(&catc->rx_urb, usbdev, usb_rcvbulkpipe(usbdev, 1), catc->rx_buf, pktsz, catc_rx_done, catc); FILL_INT_URB(&catc->irq_urb, usbdev, usb_rcvintpipe(usbdev, 2), catc->irq_buf, 2, catc_irq_done, catc, 1); if (!catc->is_f5u011) { dbg("Checking memory size\n"); i = 0x12345678; catc_write_mem(catc, 0x7a80, &i, 4); i = 0x87654321; catc_write_mem(catc, 0xfa80, &i, 4); catc_read_mem(catc, 0x7a80, &i, 4); switch (i) { case 0x12345678: catc_set_reg(catc, TxBufCount, 8); catc_set_reg(catc, RxBufCount, 32); dbg("64k Memory\n"); break; default: warn("Couldn't detect memory size, assuming 32k"); case 0x87654321: catc_set_reg(catc, TxBufCount, 4); catc_set_reg(catc, RxBufCount, 16); dbg("32k Memory\n"); break; } dbg("Getting MAC from SEEROM."); catc_get_mac(catc, netdev->dev_addr); dbg("Setting MAC into registers."); for (i = 0; i < 6; i++) catc_set_reg(catc, StationAddr0 - i, netdev->dev_addr[i]); dbg("Filling the multicast list."); memset(broadcast, 0xff, 6); catc_multicast(broadcast, catc->multicast); catc_multicast(netdev->dev_addr, catc->multicast); catc_write_mem(catc, 0xfa80, catc->multicast, 64); dbg("Clearing error counters."); for (i = 0; i < 8; i++) catc_set_reg(catc, EthStats + i, 0); catc->last_stats = jiffies; dbg("Enabling."); catc_set_reg(catc, MaxBurst, RX_MAX_BURST); catc_set_reg(catc, OpModes, OpTxMerge | OpRxMerge | OpLenInclude | Op3MemWaits); catc_set_reg(catc, LEDCtrl, LEDLink); catc_set_reg(catc, RxUnit, RxEnable | RxPolarity | RxMultiCast); } else { dbg("Performing reset\n"); catc_reset(catc); catc_get_mac(catc, netdev->dev_addr); dbg("Setting RX Mode"); catc->rxmode[0] = RxEnable | RxPolarity | RxMultiCast; catc->rxmode[1] = 0; f5u011_rxmode(catc, catc->rxmode); } dbg("Init done."); printk(KERN_INFO "%s: %s USB Ethernet at usb%d:%d.%d, ", netdev->name, (catc->is_f5u011) ? "Belkin F5U011" : "CATC EL1210A NetMate", usbdev->bus->busnum, usbdev->devnum, ifnum); for (i = 0; i < 5; i++) printk("%2.2x:", netdev->dev_addr[i]); printk("%2.2x.\n", netdev->dev_addr[i]); return catc;}static void catc_disconnect(struct usb_device *usbdev, void *dev_ptr){ struct catc *catc = dev_ptr; unregister_netdev(catc->netdev); kfree(catc->netdev); kfree(catc);}/* * Module functions and tables. */static struct usb_device_id catc_id_table [] = { { USB_DEVICE(0x0423, 0xa) }, /* CATC Netmate, Belkin F5U011 */ { USB_DEVICE(0x0423, 0xc) }, /* CATC Netmate II, Belkin F5U111 */ { USB_DEVICE(0x08d1, 0x1) }, /* smartBridges smartNIC */ { }};MODULE_DEVICE_TABLE(usb, catc_id_table);static struct usb_driver catc_driver = { name: "catc", probe: catc_probe, disconnect: catc_disconnect, id_table: catc_id_table,};static int __init catc_init(void){ info(DRIVER_VERSION " " DRIVER_DESC); usb_register(&catc_driver); return 0;}static void __exit catc_exit(void){ usb_deregister(&catc_driver);}module_init(catc_init);module_exit(catc_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -