📄 kaweth.c
字号:
/**************************************************************** * kaweth_open ****************************************************************/static int kaweth_open(struct net_device *net){ struct kaweth_device *kaweth = (struct kaweth_device *)net->priv; kaweth_dbg("Dev usage: %d", kaweth->dev->refcnt.counter); kaweth_dbg("Opening network device."); kaweth_resubmit_rx_urb(kaweth); netif_start_queue(net); MOD_INC_USE_COUNT; kaweth_async_set_rx_mode(kaweth); return 0;}/**************************************************************** * kaweth_close ****************************************************************/static int kaweth_close(struct net_device *net){ struct kaweth_device *kaweth = net->priv; netif_stop_queue(net); kaweth->status |= KAWETH_STATUS_CLOSING; usb_unlink_urb(kaweth->rx_urb); kaweth->status &= ~KAWETH_STATUS_CLOSING; MOD_DEC_USE_COUNT; printk("Dev usage: %d", kaweth->dev->refcnt.counter); return 0;}/**************************************************************** * kaweth_ioctl ****************************************************************/static int kaweth_ioctl(struct net_device *net, struct ifreq *rq, int cmd){ return -EOPNOTSUPP;}/**************************************************************** * kaweth_usb_transmit_complete ****************************************************************/static void kaweth_usb_transmit_complete(struct urb *urb){ struct kaweth_device *kaweth = urb->context; spin_lock(&kaweth->device_lock); if (urb->status) kaweth_dbg("%s: TX status %d.", kaweth->net->name, urb->status); netif_wake_queue(kaweth->net); spin_unlock(&kaweth->device_lock);}/**************************************************************** * kaweth_start_xmit ****************************************************************/static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net){ struct kaweth_device *kaweth = net->priv; int count = skb->len; int res; spin_lock(&kaweth->device_lock); kaweth_async_set_rx_mode(kaweth); netif_stop_queue(net); *((__u16 *)kaweth->tx_buf) = cpu_to_le16(skb->len); memcpy(kaweth->tx_buf + 2, skb->data, skb->len); memset(kaweth->tx_urb, 0, sizeof(*kaweth->tx_urb)); FILL_BULK_URB(kaweth->tx_urb, kaweth->dev, usb_sndbulkpipe(kaweth->dev, 2), kaweth->tx_buf, count + 2, kaweth_usb_transmit_complete, kaweth); if((res = usb_submit_urb(kaweth->tx_urb))) { kaweth_warn("kaweth failed tx_urb %d", res); kaweth->stats.tx_errors++; netif_start_queue(net); } else { kaweth->stats.tx_packets++; kaweth->stats.tx_bytes += skb->len; net->trans_start = jiffies; } dev_kfree_skb(skb); spin_unlock(&kaweth->device_lock); return 0;}/**************************************************************** * kaweth_set_rx_mode ****************************************************************/static void kaweth_set_rx_mode(struct net_device *net){ struct kaweth_device *kaweth = net->priv; __u16 packet_filter_bitmap = KAWETH_PACKET_FILTER_DIRECTED | KAWETH_PACKET_FILTER_BROADCAST | KAWETH_PACKET_FILTER_MULTICAST; kaweth_dbg("Setting Rx mode to %d", packet_filter_bitmap); netif_stop_queue(net); if (net->flags & IFF_PROMISC) { packet_filter_bitmap |= KAWETH_PACKET_FILTER_PROMISCUOUS; } else if ((net->mc_count) || (net->flags & IFF_ALLMULTI)) { packet_filter_bitmap |= KAWETH_PACKET_FILTER_ALL_MULTICAST; } kaweth->packet_filter_bitmap = packet_filter_bitmap; netif_wake_queue(net);}/**************************************************************** * kaweth_async_set_rx_mode ****************************************************************/static void kaweth_async_set_rx_mode(struct kaweth_device *kaweth){ __u16 packet_filter_bitmap = kaweth->packet_filter_bitmap; kaweth->packet_filter_bitmap = 0; if(packet_filter_bitmap == 0) return; { int result; result = kaweth_control(kaweth, usb_sndctrlpipe(kaweth->dev, 0), KAWETH_COMMAND_SET_PACKET_FILTER, USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, packet_filter_bitmap, 0, (void *)&kaweth->firmware_buf, 0, KAWETH_CONTROL_TIMEOUT); if(result < 0) { kaweth_err("Failed to set Rx mode: %d", result); } else { kaweth_dbg("Set Rx mode to %d", packet_filter_bitmap); } }}/**************************************************************** * kaweth_netdev_stats ****************************************************************/static struct net_device_stats *kaweth_netdev_stats(struct net_device *dev){ return &((struct kaweth_device *)dev->priv)->stats;}/**************************************************************** * kaweth_tx_timeout ****************************************************************/static void kaweth_tx_timeout(struct net_device *net){ struct kaweth_device *kaweth = net->priv; kaweth_warn("%s: Tx timed out. Resetting.", net->name); kaweth->stats.tx_errors++; net->trans_start = jiffies; usb_unlink_urb(kaweth->tx_urb);}/**************************************************************** * kaweth_probe ****************************************************************/static void *kaweth_probe( struct usb_device *dev, /* the device */ unsigned ifnum, /* what interface */ const struct usb_device_id *id /* from id_table */ ){ struct kaweth_device *kaweth; const eth_addr_t bcast_addr = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; int result = 0; kaweth_dbg("Kawasaki Device Probe (Device number:%d): 0x%4.4x:0x%4.4x:0x%4.4x", dev->devnum, (int)dev->descriptor.idVendor, (int)dev->descriptor.idProduct, (int)dev->descriptor.bcdDevice); kaweth_dbg("Device at %p", dev); kaweth_dbg("Descriptor length: %x type: %x", (int)dev->descriptor.bLength, (int)dev->descriptor.bDescriptorType); if(!(kaweth = kmalloc(sizeof(struct kaweth_device), GFP_KERNEL))) { kaweth_dbg("out of memory allocating device structure\n"); return NULL; } memset(kaweth, 0, sizeof(struct kaweth_device)); kaweth->dev = dev; kaweth->status = 0; kaweth->net = NULL; kaweth->device_lock = SPIN_LOCK_UNLOCKED; kaweth_dbg("Resetting."); kaweth_reset(kaweth); /* * If high byte of bcdDevice is nonzero, firmware is already * downloaded. Don't try to do it again, or we'll hang the device. */ if (dev->descriptor.bcdDevice >> 8) { kaweth_info("Firmware present in device."); } else { /* Download the firmware */ kaweth_info("Downloading firmware..."); if ((result = kaweth_download_firmware(kaweth, kaweth_new_code, len_kaweth_new_code, 100, 2)) < 0) { kaweth_err("Error downloading firmware (%d)", result); kfree(kaweth); return NULL; } if ((result = kaweth_download_firmware(kaweth, kaweth_new_code_fix, len_kaweth_new_code_fix, 100, 3)) < 0) { kaweth_err("Error downloading firmware fix (%d)", result); kfree(kaweth); return NULL; } if ((result = kaweth_download_firmware(kaweth, kaweth_trigger_code, len_kaweth_trigger_code, 126, 2)) < 0) { kaweth_err("Error downloading trigger code (%d)", result); kfree(kaweth); return NULL; } if ((result = kaweth_download_firmware(kaweth, kaweth_trigger_code_fix, len_kaweth_trigger_code_fix, 126, 3)) < 0) { kaweth_err("Error downloading trigger code fix (%d)", result); kfree(kaweth); return NULL; } if ((result = kaweth_trigger_firmware(kaweth, 126)) < 0) { kaweth_err("Error triggering firmware (%d)", result); kfree(kaweth); return NULL; } /* Device will now disappear for a moment... */ kaweth_info("Firmware loaded. I'll be back..."); return NULL; } result = kaweth_read_configuration(kaweth); if(result < 0) { kaweth_err("Error reading configuration (%d), no net device created", result); kfree(kaweth); return NULL; } kaweth_info("Statistics collection: %x", kaweth->configuration.statistics_mask); kaweth_info("Multicast filter limit: %x", kaweth->configuration.max_multicast_filters & ((1 << 15) - 1)); kaweth_info("MTU: %d", le16_to_cpu(kaweth->configuration.segment_size)); kaweth_info("Read MAC address %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x", (int)kaweth->configuration.hw_addr[0], (int)kaweth->configuration.hw_addr[1], (int)kaweth->configuration.hw_addr[2], (int)kaweth->configuration.hw_addr[3], (int)kaweth->configuration.hw_addr[4], (int)kaweth->configuration.hw_addr[5]); if(!memcmp(&kaweth->configuration.hw_addr, &bcast_addr, sizeof(bcast_addr))) { kaweth_err("Firmware not functioning properly, no net device created"); kfree(kaweth); return NULL; } if(kaweth_set_urb_size(kaweth, KAWETH_BUF_SIZE) < 0) { kaweth_dbg("Error setting URB size"); return kaweth; } if(kaweth_set_sofs_wait(kaweth, KAWETH_SOFS_TO_WAIT) < 0) { kaweth_err("Error setting SOFS wait"); return kaweth; } result = kaweth_set_receive_filter(kaweth, KAWETH_PACKET_FILTER_DIRECTED | KAWETH_PACKET_FILTER_BROADCAST | KAWETH_PACKET_FILTER_MULTICAST); if(result < 0) { kaweth_err("Error setting receive filter"); return kaweth; } kaweth_dbg("Initializing net device."); kaweth->tx_urb = usb_alloc_urb(0); kaweth->rx_urb = usb_alloc_urb(0); kaweth->net = init_etherdev(0, 0); if (!kaweth->net) { kaweth_err("Error calling init_etherdev."); return kaweth; } memcpy(kaweth->net->broadcast, &bcast_addr, sizeof(bcast_addr)); memcpy(kaweth->net->dev_addr, &kaweth->configuration.hw_addr, sizeof(kaweth->configuration.hw_addr)); kaweth->net->priv = kaweth; kaweth->net->open = kaweth_open; kaweth->net->stop = kaweth_close; kaweth->net->watchdog_timeo = KAWETH_TX_TIMEOUT; kaweth->net->tx_timeout = kaweth_tx_timeout; kaweth->net->do_ioctl = kaweth_ioctl; kaweth->net->hard_start_xmit = kaweth_start_xmit; kaweth->net->set_multicast_list = kaweth_set_rx_mode; kaweth->net->get_stats = kaweth_netdev_stats; kaweth->net->mtu = le16_to_cpu(kaweth->configuration.segment_size); memset(&kaweth->stats, 0, sizeof(kaweth->stats)); kaweth_info("kaweth interface created at %s", kaweth->net->name); kaweth_dbg("Kaweth probe returning."); return kaweth;}/**************************************************************** * kaweth_disconnect ****************************************************************/static void kaweth_disconnect(struct usb_device *dev, void *ptr){ struct kaweth_device *kaweth = ptr; kaweth_info("Unregistering"); if (!kaweth) { kaweth_warn("unregistering non-existant device"); return; } if(kaweth->net) { if(kaweth->net->flags & IFF_UP) { kaweth_dbg("Closing net device"); dev_close(kaweth->net); } kaweth_dbg("Unregistering net device"); unregister_netdev(kaweth->net); } usb_free_urb(kaweth->rx_urb); usb_free_urb(kaweth->tx_urb); kfree(kaweth);}/*-------------------------------------------------------------------* * completion handler for compatibility wrappers (sync control/bulk) * *-------------------------------------------------------------------*/static void usb_api_blocking_completion(urb_t *urb){ struct usb_api_data *awd = (struct usb_api_data *)urb->context; awd->done=1; wake_up(&awd->wqh);}/*-------------------------------------------------------------------* * COMPATIBILITY STUFF * *-------------------------------------------------------------------*/// Starts urb and waits for completion or timeoutstatic int usb_start_wait_urb(urb_t *urb, int timeout, int* actual_length){ DECLARE_WAITQUEUE(wait, current); struct usb_api_data awd; int status; init_waitqueue_head(&awd.wqh); awd.done = 0; set_current_state(TASK_INTERRUPTIBLE); add_wait_queue(&awd.wqh, &wait); urb->context = &awd; status = usb_submit_urb(urb); if (status) { // something went wrong usb_free_urb(urb); set_current_state(TASK_RUNNING); remove_wait_queue(&awd.wqh, &wait); return status; } while (timeout && !awd.done) timeout = schedule_timeout(timeout); set_current_state(TASK_RUNNING); remove_wait_queue(&awd.wqh, &wait); if (!timeout) { // timeout kaweth_warn("usb_control/bulk_msg: timeout"); usb_unlink_urb(urb); // remove urb safely status = -ETIMEDOUT; } else { status = urb->status; } if (actual_length) { *actual_length = urb->actual_length; } usb_free_urb(urb); return status;}/*-------------------------------------------------------------------*/// returns status (negative) or length (positive)int kaweth_internal_control_msg(struct usb_device *usb_dev, unsigned int pipe, devrequest *cmd, void *data, int len, int timeout){ urb_t *urb; int retv; int length; urb = usb_alloc_urb(0); if (!urb) return -ENOMEM; FILL_CONTROL_URB(urb, usb_dev, pipe, (unsigned char*)cmd, data, len, (usb_complete_t)usb_api_blocking_completion,0); retv = usb_start_wait_urb(urb, timeout, &length); if (retv < 0) { return retv; } else { return length; }}/**************************************************************** * kaweth_init ****************************************************************/int __init kaweth_init(void){ kaweth_dbg("Driver loading"); return usb_register(&kaweth_driver);}/**************************************************************** * kaweth_exit ****************************************************************/void __exit kaweth_exit(void){ usb_deregister(&kaweth_driver);}module_init(kaweth_init);module_exit(kaweth_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -