📄 cb20_cb.c
字号:
rsp->rsp1 = cb20in(cb_info, V_RESP1); rsp->rsp2 = cb20in(cb_info, V_RESP2); if (cb20in(cb_info, V_COMMAND) & COMMAND_BUSY) { cb20out(cb_info, V_EVACK, EV_CLEARCOMMANDBUSY); } /* acknowledge command */ cb20out(cb_info, V_EVACK, EV_CMD); cb_info->macstatus = 1; spin_unlock_irqrestore(&cb_info->cmd_lock, flags); return rc;}/* * Non busywait sleep */static void schednap(int jifs){ set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(jifs);} #if !defined(CONFIG_NET_PCMCIA)static void cb20_suspend(dev_node_t *dnp){ printk(KERN_ALERT "Suspend called! devnod=%p\n",dnp);}static void cb20_resume(dev_node_t *dnp){ printk(KERN_ALERT "Resume called! devnod=%p\n",dnp);}/* * ********* external pcmcia-cs attach/detach/probe functions. *********************** * @attach */static dev_node_t *cb20_attach(dev_locator_t *loc){ u_char bus, devfn; struct pci_dev *pdev=0; dev_node_t *node; struct cb20_info *v_info ; struct net_device *vdev; cb20_reap(); MOD_INC_USE_COUNT; node = kmalloc(sizeof(dev_node_t), GFP_KERNEL); if (!node){#ifdef DEBUG_CB printk(KERN_CRIT "Cannot allocate device node!\n");#endif MOD_DEC_USE_COUNT; return 0; } if (loc->bus != LOC_PCI){#ifdef DEBUG_CB printk(KERN_ERR "Dev locator is not PCI!\n");#endif MOD_DEC_USE_COUNT; kfree(node); return 0; } bus = loc->b.pci.bus; devfn = loc->b.pci.devfn; schednap(10); pdev = pci_find_slot(bus,devfn); if((vdev=cb20_probe(pdev))!=0){ add_cb20(vdev); v_info = vdev->priv; /* * Create top level /proc/cb20/devname device directory */#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,13)) v_info->device = create_proc_entry(vdev->name,S_IFDIR|0555,cb20_entry);#else memset(&v_info->proc_entry,0,sizeof(v_info->proc_entry)); v_info->proc_entry.namelen = strlen(vdev->name); v_info->proc_entry.name = vdev->name; v_info->proc_entry.mode = S_IFDIR|0555; v_info->proc_entry.nlink = 2; v_info->proc_entry.ops = cb20_entry.ops; proc_register( &cb20_entry,&v_info->proc_entry); #endif procsetup(vdev); sprintf(node->dev_name, vdev->name); node->major = node->minor = 0; node->next = NULL;#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,13)) netif_device_attach(vdev);#endif return node; } else printk(KERN_CRIT "Init cb20 failed\n"); kfree(node); MOD_DEC_USE_COUNT; return NULL;}static void cb20_detach(dev_node_t *node){ struct net_device *dev; struct cb20_info *v_info; if(!(dev=loc_cb20(node->dev_name))){ printk(KERN_ERR "Cant find device %s\n",node->dev_name); return; } v_info = (struct cb20_info *)dev->priv;#ifdef DEBUG_CB printk(KERN_DEBUG "cb20_detach: node=0x%p\n", node);#endif cb20out(v_info,CB_INTENABLE,0); /* no ints */ if(node ) { #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,13)) netif_device_detach(dev);#endif cb20_cleanup(dev); kfree(node); MOD_DEC_USE_COUNT; }}static void cb20_cleanup(struct net_device *dev){ struct cb20_info *v_info; printk(KERN_DEBUG "Cleanup call\n"); if(dev){ v_info = (struct cb20_info *)dev->priv; v_info->flags |= NOCARD; del_proc_entry(dev,dev->priv); stop_cb20_card(dev); del_cb20(dev); }}/* * @stop Stop CB20 device for external pcmcia-cs turn on REAP bit * for this device. Don't call unregister here as this is in * interupt context so we cannot call unregister_netdev as he * may sleep (BAD). Just mark it. */static int stop_cb20_card( struct net_device *vdev){ struct cb20_info *v_info = (struct cb20_info*)vdev->priv;#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,13)) struct sk_buff *skb=0;#endif int status; /* device has been freed * already bail */ if(vdev == 0) return -1;#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,13)) netif_device_detach(vdev);#endif cb20out(v_info,CB_INTENABLE,0); /* disable cardbus ints */ /* Turn off mac (disable card ) before freeing stuff or (boom) make sure card * is still there though */ if(cb20in(v_info,V_COMMAND)!=0xffff){ mac_disable(v_info); cb20out(v_info,V_EVINTEN,0); } #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,13)) /* Clean out tx queue */ if(skb_queue_len(&v_info->txq)> 0 ) for(;(skb = skb_dequeue(&v_info->txq));) dev_kfree_skb(skb);#endif pci_free_consistent(v_info->pcip,SHAREDMEMSIZE,v_info->SharedRegion,v_info->SharedBusaddr); if(cb20in(v_info,V_COMMAND)!=0xffff){ iounmap(v_info->auxregmembase); } if((status=pci_proc_detach_device(v_info->pcip))!=0){ printk(KERN_WARNING "Can't detach now err %d\n",status); return 1; } v_info->flags |= REAP ; return 0;}#endifstatic struct net_device *cb20_probe(struct pci_dev *pci){ int status; struct net_device *vdev; if((vdev = init_cb20_card(pci))==0){ printk(KERN_CRIT "K350: init_cb20! returns 0\n"); status = -1; } else status =0; if(vdev){ status = start_cb20(vdev); } else{ printk(KERN_CRIT "could not init CB20 null!\n"); return NULL; } if(status ){ printk(KERN_ERR "[ERROR] START STATUS = %x\n",status); unregister_netdev(vdev); kfree(vdev); return NULL; } return vdev;}/* * Proc setup for pcmcia or kernel pcmcia * Called after the device is initialized * and running. Contains proc nodes for dev * @procsetup */static void procsetup(struct net_device *targetdev){ struct cb20_info *v_info ;#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,13)) struct proc_dir_entry *entry;#endif v_info = targetdev->priv;#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,13)) entry = create_proc_entry("SSID",S_IFREG|S_IRUGO,v_info->device); entry->data = targetdev; entry->proc_fops = &proc_ssid_ops; entry = create_proc_entry("Status",S_IFREG|S_IRUGO,v_info->device); entry->data = targetdev; entry->proc_fops = &proc_status_ops;#else /* SSID */ memcpy( &v_info->proc_ssid_entry, &ssid_entry,sizeof( ssid_entry ) ); v_info->proc_ssid_entry.data = targetdev; proc_register(&v_info->proc_entry,&v_info->proc_ssid_entry); /* STATUS */ memcpy(&v_info->proc_status_entry,&status_entry,sizeof(status_entry)); v_info->proc_status_entry.data = targetdev; proc_register(&v_info->proc_entry,&v_info->proc_status_entry);#endif}#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,13))/* * Tickle TX ring if needed for unwedging tx */static void cb20txtmo(struct net_device *dev){ struct cb20_info *v_info ; int lasttx; lasttx = jiffies - dev->trans_start; v_info = (struct cb20_info *)dev->priv; v_info->stats.tx_errors++; /* RAW 8/13 for some reason the TXD's get lost and must be reclaimed. * When they vanish, tx timouts happen and txreclaim gets called * wich retries the transmit under 2.4. Under 2.2 the net_send_packet * routine will detect device busy ,reclaim the txd and retry the * transmission. */ txreclaim(dev); }#endif/* * Reclaim any outstanding TX descriptor(s) due to * a xmission error resulting in a tx timeout */static int txreclaim(struct net_device *dev){ struct cb20_info *v_info = (struct cb20_info*)dev->priv; CARD_TX_DESC txd; u16 irqstate; memset((char *)&txd,0,sizeof(txd)); memcpy((char *)&txd,(char *)v_info->txfids[0].CardRamOff,sizeof(txd)); irqstate = cb20in(v_info,V_EVSTAT); if(irqstate ){ printk(KERN_ERR "Missed irq %04x\n",irqstate); cb20out(v_info,V_EVACK,irqstate); } if(!txd.valid ){ txd.valid = 1; txd.eoc = 1; memcpy((char *)v_info->txfids[0].CardRamOff,(char *)&txd,sizeof(txd)); v_info->txdfc = 1; spin_unlock(&v_info->txd_lock); return 1; }#ifdef TX_DEBUG printk(KERN_ERR "TXV!!\n");#endif#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,55 )) send_packet(dev); /* Kick xmitter for 2.4 */#endif return 0;}#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,55 ))/* * @net_send_packet * * Attempt to transmit a packet. Adapted from skeleton.c for 2.2 * */static int net_send_packet(struct sk_buff *skb,struct net_device *dev){ int adhoc,i; unsigned char *buffer; s16 len,rlen,*payloadlen; struct cb20_info *v_info = (struct cb20_info*)dev->priv; u32 miclen; u8 *sendbuf; u32 dummy; adhoc = 0; if (dev->tbusy) { int tickssofar = jiffies - dev->trans_start; if (tickssofar < 5){ return 1; } printk(KERN_ERR "[TRANSMIT TIMEOUT], %s\n", dev->name); v_info->stats.tx_errors++; txreclaim(dev); dev->tbusy=0; dev->trans_start = jiffies; } /* * Block a timer-based transmit from overlapping. This could better be * done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name); else { /* send packet */ len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; buffer = skb->data; v_info->txfids[0].TxDesc.Offset= 0; v_info->txfids[0].TxDesc.valid = 1; v_info->txfids[0].TxDesc.eoc = 1; v_info->txfids[0].TxDesc.length= len + sizeof(HDR_802_11); /* * Magic, the cards firmware needs a length count (2 bytes) in the host buffer * right after TXFID_HDR. The TXFID_HDR contains the status short so payloadlen * is immediatly after it. ------------------------------------------------ * |TXFIDHDR+STATUS|PAYLOADLEN|802.3HDR|PACKETDATA| * ------------------------------------------------ */ payloadlen = (s16 *)(v_info->txfids[0].VirtualHostAddress + sizeof(TXFID_HDR)); sendbuf = v_info->txfids[0].VirtualHostAddress + sizeof(TXFID_HDR) + 2; /* * Firmware automaticly puts 802 header on so * we don't need to account for it in the length */ miclen = rlen = len; *payloadlen = len - sizeof(HDR_802_3); dev->trans_start = jiffies; /* copy data into cb20 dma buffer */ memcpy(sendbuf ,buffer,len ); /* * ReadCacheline hack */ for(i=0;i!=READLINE_DEL;i++) dummy = *(u32 *)sendbuf; /* Do the right thing (TM) for mic */ if(v_info->flags & MIC_CAPABLE){ adhoc = (v_info->flags & ADHOC) ? 1:0; if(Encapsulate(v_info,(ETH_HEADER_STRUC *)sendbuf,&miclen , adhoc)) { v_info->txfids[0].TxDesc.length= miclen + sizeof(HDR_802_11); *payloadlen = (s16 ) (miclen - sizeof(HDR_802_3)); } else {#ifdef DEBUG_MIC printk(KERN_DEBUG "Dumped tx packet\n");#endif goto dumptx; } } v_info->txdfc=0; memcpy((char *)v_info->txfids[0].CardRamOff, (char *)&v_info->txfids[0].TxDesc, sizeof(CARD_TX_DESC)); cb20out(v_info,V_EVACK,EV_XMIT); /* Send packet */ } dumptx: dev_kfree_skb(skb); return 0;}#else/* * @send_packet * * Attempt to transmit a packet. Can be called from interrupt * or transmit . return number of packets we tried to send */static int send_packet(struct net_device *dev){ struct sk_buff *skb; int npacks,adhoc,i; unsigned char *buffer; s16 len,rlen,*payloadlen; struct cb20_info *v_info = (struct cb20_info*)dev->priv; u32 miclen,dummy; u8 *sendbuf; CARD_TX_DESC txd; adhoc = 0; npacks = skb_queue_len(&v_info->txq); if(!npacks){ v_info->flags &= ~(TXBUSY); return 0; } /* check for txd available. TXCPY event * will free them. */ if(v_info->txdfc <= 0 ){#if TXD_DEBUG printk(KERN_WARNING "No TXD's in send_packet txdfx=%x\n",v_info->txdfc);#endif return 0; } /* get packet to send */ if((skb = skb_dequeue(&v_info->txq))==0){ printk(KERN_ERR "Dequeue'd zero in send_packet !!!!\n"); return 0; } len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; buffer = skb->data; memset((char *)&txd,0,sizeof(txd)); memcpy((char *)&txd,(char *)v_info->txfids[0].CardRamOff,sizeof(txd)); txd.Offset= 0; txd.valid = 1; txd.eoc=1 ; txd.length = len + sizeof(HDR_802_11); /* * Magic, the cards firmware needs a length count (2 bytes) in the host buffer * right after TXFID_HDR. The TXFID_HDR contains the status short so payloadlen * is immediatly after it. ------------------------------------------------ * |TXFIDHDR+STATUS|PAYLOADLEN|802.3HDR|PACKETDATA| * ------------------------------------------------ */ payloadlen = (s16 *)(v_info->txfids[0].VirtualHostAddress + sizeof(TXFID_HDR)); sendbuf = v_info->txfids[0].VirtualHostAddress + sizeof(TXFID_HDR) + 2; /* * Firmware automaticly puts 802 header on so * we don't need to account for it in the length */ miclen = rlen = len; *payloadlen = len - sizeof(HDR_802_3); dev->trans_start = jiffies; /* copy data into cb20 dma buffer */ memcpy(sendbuf ,buffer,len ); /* * ReadCacheline hack
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -