📄 fastvnet_cs.c
字号:
}/********************************************************************* PCMCIA ATTACH / DETACH********************************************************************/static dev_link_t *vnet_attach (void){ dev_link_t *link; struct net_device *dev; struct net_local *local; int rc; client_reg_t client_reg; IF_VERY_LOUD(DbgPrint("-> vnet_attach()\n");) // Flush stale links for (link=dev_list; link; link=link->next) if (link->state & DEV_STALE_LINK) vnet_detach(link); // Initialize the dev_link_t structure link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); memset(link, 0, sizeof(struct dev_link_t)); link->release.function = &vnet_release; link->release.data = (u_long) link; link->conf.Vcc = 33; link->conf.IntType = INT_MEMORY_AND_IO; // Allocate space for netdevice (private data of link) dev = kmalloc(sizeof(struct net_device), GFP_KERNEL); memset(dev, 0, sizeof(struct net_device)); link->priv = dev; // Allocate space for netdevice priv (private data of netdevice) local = kmalloc(sizeof(struct net_local), GFP_KERNEL); memset(local, 0, sizeof(struct net_local)); dev->priv = local; // Initialize specific data local->link = link; local->dev = dev; spin_lock_init(&local->slock); /* Set the mgmt timer */ init_timer(&local->Adapter.MgmtTimer); local->Adapter.MgmtTimer.function = MgmtTimer; local->Adapter.MgmtTimer.data = (unsigned long) dev; // Standard setup for generic data ether_setup(dev); // kernel callbacks dev->open = vnet_open; dev->stop = vnet_close; dev->hard_start_xmit = vnet_tx; dev->get_stats = vnet_get_stats;#ifdef WIRELESS_EXT dev->do_ioctl = vnet_ioctl; dev->get_wireless_stats = vnet_get_wireless_stats;#endif // Other netdevice data init_dev_name(dev, local->node); dev->mtu = mtu; netif_stop_queue(dev); // Register with CardServices link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; client_reg.Attributes = INFO_IO_CLIENT; client_reg.EventMask = CS_EVENT_REGISTRATION_COMPLETE | CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; client_reg.event_handler = &vnet_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; rc = CardServices(RegisterClient, &link->handle, &client_reg); if (rc) { cs_error(link->handle, RegisterClient, rc); vnet_detach(link); return NULL; } IF_VERY_LOUD(DbgPrint("<- vnet_attach()\n");) return link;}static void vnet_detach (dev_link_t *link){ dev_link_t **linkp; IF_VERY_LOUD(DbgPrint("-> vnet_detach(0x%p)\n", link);) // Locate device structure for (linkp=&dev_list; *linkp; linkp=&(*linkp)->next) if (*linkp == link) break; if (!*linkp) { IF_DEBUG_ERRORS(DbgPrint("%s: Attempt to detach non-existing PCMCIA client!\n", dev_info);) return; } // If the device is currently configured and active, we won't // actually delete it yet. Instead, it is marked so that when the // release() function is called, that will trigger a proper // detach() del_timer(&link->release); if (link->state & DEV_CONFIG) { IF_LOUD(DbgPrint("%s: vnet_detach: detach postponed, %s still locked\n", dev_info, link->dev->dev_name);) vnet_release((u_long)link); if (link->state & DEV_STALE_CONFIG) { link->state |= DEV_STALE_LINK; return; } } // Break the line with CardServices if (link->handle) CardServices(DeregisterClient, link->handle); // Unlink device structure, free pieces *linkp = link->next; if (link->priv) { struct net_device *dev = (struct net_device *) link->priv; if (link->dev) { unregister_netdev(dev); IF_LOUD(DbgPrint("%s: Netdevice unregistered\n", dev_info);) } if (dev->priv) kfree(dev->priv); kfree(link->priv); } kfree(link); IF_VERY_LOUD(DbgPrint("<- vnet_detach()\n");)}/******************************************************************** * PCMCIA EVENT HANDLER********************************************************************/static int vnet_event (event_t event, int priority, event_callback_args_t *args){ dev_link_t *link = (dev_link_t *) args->client_data; struct net_device *dev = (struct net_device *) link->priv; struct net_local *local = (struct net_local *) dev->priv; PVNet_ADAPTER Adapter = &local->Adapter; IF_LOUD(DbgPrint("-> vnet_event(%s, %d, 0x%p)\n", ((event==CS_EVENT_REGISTRATION_COMPLETE) ? "registration complete" : ((event==CS_EVENT_CARD_INSERTION) ? "card insertion" : ((event==CS_EVENT_CARD_REMOVAL) ? "card removal" : ((event==CS_EVENT_RESET_PHYSICAL) ? "physical physical" : ((event==CS_EVENT_CARD_RESET) ? "card reset" : ((event==CS_EVENT_PM_SUSPEND) ? "pm suspend" : ((event==CS_EVENT_PM_RESUME) ? "pm resume" : "unknown"))))))), priority, args);) switch (event) { case CS_EVENT_CARD_INSERTION: link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; if (!vnet_config(link)) dev->irq = 0; Adapter->IsUp = TRUE; InitAdapter(&local->Adapter); SetParameters(&local->Adapter); if (!InitAndStartCard(&local->Adapter)) return -1; memcpy(dev->dev_addr, Adapter->StationAddress, 6); break; case CS_EVENT_CARD_REMOVAL: del_timer(&Adapter->MgmtTimer); link->state &= ~DEV_PRESENT; Adapter->IsUp = FALSE; if (link->state & DEV_CONFIG) { netif_stop_queue(dev); netif_device_detach(dev); mod_timer(&link->release, jiffies + HZ/20); } break; case CS_EVENT_PM_SUSPEND: link->state |= DEV_SUSPEND; case CS_EVENT_RESET_PHYSICAL: Adapter->IsUp = FALSE; if (link->state & DEV_CONFIG) { if (link->open) { netif_stop_queue(dev); netif_device_detach(dev); } CardServices(ReleaseConfiguration, link->handle); } break; case CS_EVENT_PM_RESUME: link->state &= ~DEV_SUSPEND; // Fall through case CS_EVENT_CARD_RESET: if (link->state & DEV_CONFIG) { CardServices(RequestConfiguration, link->handle, &link->conf); if (link->open) { netif_device_attach(dev); netif_start_queue(dev); } } break; } IF_VERY_LOUD(DbgPrint("<- vnet_event()\n");) return 0;}/******************************************************************** * MODULE INSERTION / REMOVAL********************************************************************/extern int init_module (void){ servinfo_t serv; IF_VERY_LOUD(DbgPrint("-> init_module()\n");) IF_LOUD(DbgPrint("%s: ATMEL 11Mbps Wireless PCMCIA LAN driver version %s\n", dev_info, version);) // Check CardServices release CardServices(GetCardServicesInfo, &serv); if (serv.Revision < CS_RELEASE_CODE) { printk("%s: CardServices release does not match!\n", dev_info); return -1; } // Register PCMCIA driver register_pcmcia_driver(&dev_info, &vnet_attach, &vnet_detach); IF_VERY_LOUD(DbgPrint("<- init_module()\n");) return 0;}extern void cleanup_module (void){ IF_VERY_LOUD(DbgPrint("-> cleanup_module()\n");) // Unregister PCMCIA driver unregister_pcmcia_driver(&dev_info); // Remove leftover devices if (dev_list) { IF_VERY_LOUD(DbgPrint("%s: Removing leftover devices!\n", dev_info);) } while (dev_list) { if (dev_list->state & DEV_CONFIG) vnet_release((u_long)dev_list); vnet_detach(dev_list); } IF_LOUD(DbgPrint("%s: Driver unloaded\n", dev_info);) IF_VERY_LOUD(DbgPrint("<- cleanup_module()\n");)}/******************************************************************** * NET OPEN / CLOSE********************************************************************/static int vnet_open (struct net_device *dev){ struct net_local *local = (struct net_local *) dev->priv; struct dev_link_t *link = local->link; IF_VERY_LOUD(DbgPrint("-> vnet_open(%s)\n", dev->name);) netif_device_attach(dev); netif_start_queue(dev); local->interrupt = 0; link->open++; MOD_INC_USE_COUNT; IF_VERY_LOUD(DbgPrint("<- vnet_open(%s)\n", dev->name);) return 0;}static int vnet_close (struct net_device *dev){ struct net_local *local = (struct net_local *) dev->priv; struct dev_link_t *link = local->link; // If the device isn't open, then nothing to do if (!link->open) { IF_VERY_LOUD(DbgPrint("<> vnet_close(%s)\n", dev->name);) return 0; } IF_VERY_LOUD(DbgPrint("-> vnet_close(%s)\n", dev->name);) // Close the device link->open--; MOD_DEC_USE_COUNT; // Check if card is still present if (netif_running(dev)) { netif_stop_queue(dev); netif_device_detach(dev); } else if (link->state & DEV_STALE_CONFIG) mod_timer(&link->release, jiffies + HZ/20); IF_VERY_LOUD(DbgPrint("<- vnet_close(%s)\n", dev->name);) return -EINVAL;}/******************************************************************** * NET Statistics ********************************************************************/struct net_device_stats *vnet_get_stats (struct net_device *dev){ struct net_local *local = (struct net_local *)dev->priv; PVNet_ADAPTER Adapter = &local->Adapter; IF_VERY_LOUD(DbgPrint("<> vnet_get_stats(%s)\n", dev->name);) local->stats.tx_packets=Adapter->Stats.TxDataPacketsOk; return(&((struct net_local *) dev->priv)->stats);}/*******************************************************************Management Timer*******************************************************************/VOIDMgmtTimer(u_long a){ struct net_device *dev ; struct net_local *local; PVNet_ADAPTER Adapter; dev = (struct net_device *) a; local = (struct net_local *)dev->priv; Adapter = &local->Adapter; if(!Adapter->IsUp || !(local->link->state & DEV_PRESENT)) { IF_LOUD(DbgPrint("** MgmtTimer reject ***\n");) return; } MgmtTimeOutCallBack(Adapter);}/******************************************************************** * NET TX / RX ********************************************************************/int vnet_tx (struct sk_buff *skb, struct net_device *dev){ struct net_local *local = (struct net_local *)dev->priv; ULONG TotalBytes=0; USHORT StartOfTxBuffer=0; unsigned long flags; ULONG Status; int len; UCHAR *p; PVNet_ADAPTER Adapter = &local->Adapter; IF_VERY_LOUD(DbgPrint("-> vnet_tx(%s)\n", dev->name);) if(Adapter->StationState != STATION_STATE_READY || !(local->link->state & DEV_PRESENT)) return 0; #if (KERNEL_VERSION_CODE < KERNEL_VERSION(2,3,42)) if (netif_queue_stopped(dev)) { IF_VERY_LOUD(DbgPrint("%s: vnet_tx(%s) called while busy!\n", dev_info, dev->name);) if ((jiffies - dev->trans_start) < TX_TIMEOUT) return 1; if (!netif_running(dev)) { IF_LOUD(DbgPrint("%s: %s Tx on stopped device!\n", dev_info, dev->name);) return 1; } }#endif skb_tx_check(dev, skb);#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,79)) skb->arp = 1;#endif // Disable interrupts spin_lock_irqsave(&local->slock, flags); // Prepare packet p = skb->data; len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN; TotalBytes = len; if ( TxResourcesAvailable(Adapter, TotalBytes+18, &StartOfTxBuffer) == FALSE) { Adapter->Stats.RxLost++; netif_stop_queue(dev); spin_unlock_irqrestore(&local->slock, flags); return 1; } TxEthernetPacket(Adapter,skb->data, len, &TotalBytes, StartOfTxBuffer, TRUE); TxUpdateDescriptor(Adapter, TotalBytes, StartOfTxBuffer, TRUE); // Send packet // Remember time transmission and count tx bytes dev->trans_start = jiffies; add_tx_bytes(&local->stats, len); // Re-enable interrupts spin_unlock_irqrestore(&local->slock, flags); DEV_KFREE_SKB(skb);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -