📄 kaweth.c
字号:
0, (void *)kaweth->firmware_buf, 8, KAWETH_CONTROL_TIMEOUT);}/**************************************************************** * kaweth_reset ****************************************************************/static int kaweth_reset(struct kaweth_device *kaweth){ int result; dbg("kaweth_reset(%p)", kaweth); result = kaweth_control(kaweth, usb_sndctrlpipe(kaweth->dev, 0), USB_REQ_SET_CONFIGURATION, 0, kaweth->dev->config[0].desc.bConfigurationValue, 0, NULL, 0, KAWETH_CONTROL_TIMEOUT); mdelay(10); dbg("kaweth_reset() returns %d.",result); return result;}static void kaweth_usb_receive(struct urb *);static int kaweth_resubmit_rx_urb(struct kaweth_device *, gfp_t);/**************************************************************** int_callback*****************************************************************/static void kaweth_resubmit_int_urb(struct kaweth_device *kaweth, gfp_t mf){ int status; status = usb_submit_urb (kaweth->irq_urb, mf); if (unlikely(status == -ENOMEM)) { kaweth->suspend_lowmem_ctrl = 1; schedule_delayed_work(&kaweth->lowmem_work, HZ/4); } else { kaweth->suspend_lowmem_ctrl = 0; } if (status) err ("can't resubmit intr, %s-%s, status %d", kaweth->dev->bus->bus_name, kaweth->dev->devpath, status);}static void int_callback(struct urb *u){ struct kaweth_device *kaweth = u->context; int act_state; switch (u->status) { case 0: /* success */ break; case -ECONNRESET: /* unlink */ case -ENOENT: case -ESHUTDOWN: return; /* -EPIPE: should clear the halt */ default: /* error */ goto resubmit; } /* we check the link state to report changes */ if (kaweth->linkstate != (act_state = ( kaweth->intbuffer[STATE_OFFSET] | STATE_MASK) >> STATE_SHIFT)) { if (act_state) netif_carrier_on(kaweth->net); else netif_carrier_off(kaweth->net); kaweth->linkstate = act_state; }resubmit: kaweth_resubmit_int_urb(kaweth, GFP_ATOMIC);}static void kaweth_resubmit_tl(struct work_struct *work){ struct kaweth_device *kaweth = container_of(work, struct kaweth_device, lowmem_work.work); if (IS_BLOCKED(kaweth->status)) return; if (kaweth->suspend_lowmem_rx) kaweth_resubmit_rx_urb(kaweth, GFP_NOIO); if (kaweth->suspend_lowmem_ctrl) kaweth_resubmit_int_urb(kaweth, GFP_NOIO);}/**************************************************************** * kaweth_resubmit_rx_urb ****************************************************************/static int kaweth_resubmit_rx_urb(struct kaweth_device *kaweth, gfp_t mem_flags){ int result; usb_fill_bulk_urb(kaweth->rx_urb, kaweth->dev, usb_rcvbulkpipe(kaweth->dev, 1), kaweth->rx_buf, KAWETH_BUF_SIZE, kaweth_usb_receive, kaweth); kaweth->rx_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; kaweth->rx_urb->transfer_dma = kaweth->rxbufferhandle; if((result = usb_submit_urb(kaweth->rx_urb, mem_flags))) { if (result == -ENOMEM) { kaweth->suspend_lowmem_rx = 1; schedule_delayed_work(&kaweth->lowmem_work, HZ/4); } err("resubmitting rx_urb %d failed", result); } else { kaweth->suspend_lowmem_rx = 0; } return result;}static void kaweth_async_set_rx_mode(struct kaweth_device *kaweth);/**************************************************************** * kaweth_usb_receive ****************************************************************/static void kaweth_usb_receive(struct urb *urb){ struct kaweth_device *kaweth = urb->context; struct net_device *net = kaweth->net; int count = urb->actual_length; int count2 = urb->transfer_buffer_length; __u16 pkt_len = le16_to_cpup((__le16 *)kaweth->rx_buf); struct sk_buff *skb; if(unlikely(urb->status == -ECONNRESET || urb->status == -ESHUTDOWN)) /* we are killed - set a flag and wake the disconnect handler */ { kaweth->end = 1; wake_up(&kaweth->term_wait); return; } spin_lock(&kaweth->device_lock); if (IS_BLOCKED(kaweth->status)) { spin_unlock(&kaweth->device_lock); return; } spin_unlock(&kaweth->device_lock); if(urb->status && urb->status != -EREMOTEIO && count != 1) { err("%s RX status: %d count: %d packet_len: %d", net->name, urb->status, count, (int)pkt_len); kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC); return; } if(kaweth->net && (count > 2)) { if(pkt_len > (count - 2)) { err("Packet length too long for USB frame (pkt_len: %x, count: %x)",pkt_len, count); err("Packet len & 2047: %x", pkt_len & 2047); err("Count 2: %x", count2); kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC); return; } if(!(skb = dev_alloc_skb(pkt_len+2))) { kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC); return; } skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ skb_copy_to_linear_data(skb, kaweth->rx_buf + 2, pkt_len); skb_put(skb, pkt_len); skb->protocol = eth_type_trans(skb, net); netif_rx(skb); kaweth->stats.rx_packets++; kaweth->stats.rx_bytes += pkt_len; } kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC);}/**************************************************************** * kaweth_open ****************************************************************/static int kaweth_open(struct net_device *net){ struct kaweth_device *kaweth = netdev_priv(net); int res; dbg("Opening network device."); res = usb_autopm_get_interface(kaweth->intf); if (res) { err("Interface cannot be resumed."); return -EIO; } res = kaweth_resubmit_rx_urb(kaweth, GFP_KERNEL); if (res) goto err_out; usb_fill_int_urb( kaweth->irq_urb, kaweth->dev, usb_rcvintpipe(kaweth->dev, 3), kaweth->intbuffer, INTBUFFERSIZE, int_callback, kaweth, 250); /* overriding the descriptor */ kaweth->irq_urb->transfer_dma = kaweth->intbufferhandle; kaweth->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; res = usb_submit_urb(kaweth->irq_urb, GFP_KERNEL); if (res) { usb_kill_urb(kaweth->rx_urb); goto err_out; } kaweth->opened = 1; netif_start_queue(net); kaweth_async_set_rx_mode(kaweth); return 0;err_out: usb_autopm_enable(kaweth->intf); return -EIO;}/**************************************************************** * kaweth_kill_urbs ****************************************************************/static void kaweth_kill_urbs(struct kaweth_device *kaweth){ usb_kill_urb(kaweth->irq_urb); usb_kill_urb(kaweth->rx_urb); usb_kill_urb(kaweth->tx_urb); flush_scheduled_work(); /* a scheduled work may have resubmitted, we hit them again */ usb_kill_urb(kaweth->irq_urb); usb_kill_urb(kaweth->rx_urb);}/**************************************************************** * kaweth_close ****************************************************************/static int kaweth_close(struct net_device *net){ struct kaweth_device *kaweth = netdev_priv(net); netif_stop_queue(net); kaweth->opened = 0; kaweth->status |= KAWETH_STATUS_CLOSING; kaweth_kill_urbs(kaweth); kaweth->status &= ~KAWETH_STATUS_CLOSING; usb_autopm_enable(kaweth->intf); return 0;}static void kaweth_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info){ struct kaweth_device *kaweth = netdev_priv(dev); strlcpy(info->driver, driver_name, sizeof(info->driver)); usb_make_path(kaweth->dev, info->bus_info, sizeof (info->bus_info));}static u32 kaweth_get_link(struct net_device *dev){ struct kaweth_device *kaweth = netdev_priv(dev); return kaweth->linkstate;}static struct ethtool_ops ops = { .get_drvinfo = kaweth_get_drvinfo, .get_link = kaweth_get_link};/**************************************************************** * kaweth_usb_transmit_complete ****************************************************************/static void kaweth_usb_transmit_complete(struct urb *urb){ struct kaweth_device *kaweth = urb->context; struct sk_buff *skb = kaweth->tx_skb; if (unlikely(urb->status != 0)) if (urb->status != -ENOENT) dbg("%s: TX status %d.", kaweth->net->name, urb->status); netif_wake_queue(kaweth->net); dev_kfree_skb_irq(skb);}/**************************************************************** * kaweth_start_xmit ****************************************************************/static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net){ struct kaweth_device *kaweth = netdev_priv(net); __le16 *private_header; int res; spin_lock(&kaweth->device_lock); kaweth_async_set_rx_mode(kaweth); netif_stop_queue(net); if (IS_BLOCKED(kaweth->status)) { goto skip; } /* We now decide whether we can put our special header into the sk_buff */ if (skb_cloned(skb) || skb_headroom(skb) < 2) { /* no such luck - we make our own */ struct sk_buff *copied_skb; copied_skb = skb_copy_expand(skb, 2, 0, GFP_ATOMIC); dev_kfree_skb_irq(skb); skb = copied_skb; if (!copied_skb) { kaweth->stats.tx_errors++; netif_start_queue(net); spin_unlock(&kaweth->device_lock); return 0; } } private_header = (__le16 *)__skb_push(skb, 2); *private_header = cpu_to_le16(skb->len-2); kaweth->tx_skb = skb; usb_fill_bulk_urb(kaweth->tx_urb, kaweth->dev, usb_sndbulkpipe(kaweth->dev, 2), private_header, skb->len, kaweth_usb_transmit_complete, kaweth); kaweth->end = 0; if((res = usb_submit_urb(kaweth->tx_urb, GFP_ATOMIC))) { warn("kaweth failed tx_urb %d", res);skip: kaweth->stats.tx_errors++; netif_start_queue(net); dev_kfree_skb_irq(skb); } else { kaweth->stats.tx_packets++; kaweth->stats.tx_bytes += skb->len; net->trans_start = jiffies; } 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 = netdev_priv(net); __u16 packet_filter_bitmap = KAWETH_PACKET_FILTER_DIRECTED | KAWETH_PACKET_FILTER_BROADCAST | KAWETH_PACKET_FILTER_MULTICAST; 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->scratch, 0, KAWETH_CONTROL_TIMEOUT); if(result < 0) { err("Failed to set Rx mode: %d", result); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -