X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fnet%2Fwireless%2Fwavelan_cs.c;fp=drivers%2Fnet%2Fwireless%2Fwavelan_cs.c;h=98122f3a4bc272bce7df9228dd5e4adf1f50dfd4;hb=64ba3f394c830ec48a1c31b53dcae312c56f1604;hp=561250f73fd38e6d0acbcb92d27184838305b30f;hpb=be1e6109ac94a859551f8e1774eb9a8469fe055c;p=linux-2.6.git diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c index 561250f73..98122f3a4 100644 --- a/drivers/net/wireless/wavelan_cs.c +++ b/drivers/net/wireless/wavelan_cs.c @@ -1005,7 +1005,7 @@ static inline void wv_82593_reconfig(struct net_device * dev) { net_local * lp = netdev_priv(dev); - struct pcmcia_device * link = lp->link; + dev_link_t * link = lp->link; unsigned long flags; /* Arm the flag, will be cleard in wv_82593_config() */ @@ -3194,8 +3194,11 @@ wavelan_packet_xmit(struct sk_buff * skb, * and we don't have the Ethernet specific requirement of beeing * able to detect collisions, therefore in theory we don't really * need to pad. Jean II */ - if (skb_padto(skb, ETH_ZLEN)) - return 0; + if (skb->len < ETH_ZLEN) { + skb = skb_padto(skb, ETH_ZLEN); + if (skb == NULL) + return 0; + } wv_packet_write(dev, skb->data, skb->len); @@ -3741,16 +3744,16 @@ wv_pcmcia_reset(struct net_device * dev) { int i; conf_reg_t reg = { 0, CS_READ, CISREG_COR, 0 }; - struct pcmcia_device * link = ((net_local *)netdev_priv(dev))->link; + dev_link_t * link = ((net_local *)netdev_priv(dev))->link; #ifdef DEBUG_CONFIG_TRACE printk(KERN_DEBUG "%s: ->wv_pcmcia_reset()\n", dev->name); #endif - i = pcmcia_access_configuration_register(link, ®); + i = pcmcia_access_configuration_register(link->handle, ®); if(i != CS_SUCCESS) { - cs_error(link, AccessConfigurationRegister, i); + cs_error(link->handle, AccessConfigurationRegister, i); return FALSE; } @@ -3761,19 +3764,19 @@ wv_pcmcia_reset(struct net_device * dev) reg.Action = CS_WRITE; reg.Value = reg.Value | COR_SW_RESET; - i = pcmcia_access_configuration_register(link, ®); + i = pcmcia_access_configuration_register(link->handle, ®); if(i != CS_SUCCESS) { - cs_error(link, AccessConfigurationRegister, i); + cs_error(link->handle, AccessConfigurationRegister, i); return FALSE; } reg.Action = CS_WRITE; reg.Value = COR_LEVEL_IRQ | COR_CONFIG; - i = pcmcia_access_configuration_register(link, ®); + i = pcmcia_access_configuration_register(link->handle, ®); if(i != CS_SUCCESS) { - cs_error(link, AccessConfigurationRegister, i); + cs_error(link->handle, AccessConfigurationRegister, i); return FALSE; } @@ -3937,8 +3940,9 @@ wv_hw_reset(struct net_device * dev) * (called by wavelan_event()) */ static inline int -wv_pcmcia_config(struct pcmcia_device * link) +wv_pcmcia_config(dev_link_t * link) { + client_handle_t handle = link->handle; tuple_t tuple; cisparse_t parse; struct net_device * dev = (struct net_device *) link->priv; @@ -3961,16 +3965,16 @@ wv_pcmcia_config(struct pcmcia_device * link) { tuple.Attributes = 0; tuple.DesiredTuple = CISTPL_CONFIG; - i = pcmcia_get_first_tuple(link, &tuple); + i = pcmcia_get_first_tuple(handle, &tuple); if(i != CS_SUCCESS) break; tuple.TupleData = (cisdata_t *)buf; tuple.TupleDataMax = 64; tuple.TupleOffset = 0; - i = pcmcia_get_tuple_data(link, &tuple); + i = pcmcia_get_tuple_data(handle, &tuple); if(i != CS_SUCCESS) break; - i = pcmcia_parse_tuple(link, &tuple, &parse); + i = pcmcia_parse_tuple(handle, &tuple, &parse); if(i != CS_SUCCESS) break; link->conf.ConfigBase = parse.config.base; @@ -3979,16 +3983,19 @@ wv_pcmcia_config(struct pcmcia_device * link) while(0); if(i != CS_SUCCESS) { - cs_error(link, ParseTuple, i); + cs_error(link->handle, ParseTuple, i); + link->state &= ~DEV_CONFIG_PENDING; return FALSE; } - + + /* Configure card */ + link->state |= DEV_CONFIG; do { - i = pcmcia_request_io(link, &link->io); + i = pcmcia_request_io(link->handle, &link->io); if(i != CS_SUCCESS) { - cs_error(link, RequestIO, i); + cs_error(link->handle, RequestIO, i); break; } @@ -3996,10 +4003,10 @@ wv_pcmcia_config(struct pcmcia_device * link) * Now allocate an interrupt line. Note that this does not * actually assign a handler to the interrupt. */ - i = pcmcia_request_irq(link, &link->irq); + i = pcmcia_request_irq(link->handle, &link->irq); if(i != CS_SUCCESS) { - cs_error(link, RequestIRQ, i); + cs_error(link->handle, RequestIRQ, i); break; } @@ -4008,15 +4015,15 @@ wv_pcmcia_config(struct pcmcia_device * link) * the I/O windows and the interrupt mapping. */ link->conf.ConfigIndex = 1; - i = pcmcia_request_configuration(link, &link->conf); + i = pcmcia_request_configuration(link->handle, &link->conf); if(i != CS_SUCCESS) { - cs_error(link, RequestConfiguration, i); + cs_error(link->handle, RequestConfiguration, i); break; } /* - * Allocate a small memory window. Note that the struct pcmcia_device + * Allocate a small memory window. Note that the dev_link_t * structure provides space for one window handle -- if your * device needs several windows, you'll need to keep track of * the handles in your private data structure, link->priv. @@ -4024,10 +4031,10 @@ wv_pcmcia_config(struct pcmcia_device * link) req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE; req.Base = req.Size = 0; req.AccessSpeed = mem_speed; - i = pcmcia_request_window(&link, &req, &link->win); + i = pcmcia_request_window(&link->handle, &req, &link->win); if(i != CS_SUCCESS) { - cs_error(link, RequestWindow, i); + cs_error(link->handle, RequestWindow, i); break; } @@ -4039,7 +4046,7 @@ wv_pcmcia_config(struct pcmcia_device * link) i = pcmcia_map_mem_page(link->win, &mem); if(i != CS_SUCCESS) { - cs_error(link, MapMemPage, i); + cs_error(link->handle, MapMemPage, i); break; } @@ -4053,7 +4060,7 @@ wv_pcmcia_config(struct pcmcia_device * link) lp->mem, dev->irq, (u_int) dev->base_addr); #endif - SET_NETDEV_DEV(dev, &handle_to_dev(link)); + SET_NETDEV_DEV(dev, &handle_to_dev(handle)); i = register_netdev(dev); if(i != 0) { @@ -4065,6 +4072,7 @@ wv_pcmcia_config(struct pcmcia_device * link) } while(0); /* Humm... Disguised goto !!! */ + link->state &= ~DEV_CONFIG_PENDING; /* If any step failed, release any partially configured state */ if(i != 0) { @@ -4073,7 +4081,7 @@ wv_pcmcia_config(struct pcmcia_device * link) } strcpy(((net_local *) netdev_priv(dev))->node.dev_name, dev->name); - link->dev_node = &((net_local *) netdev_priv(dev))->node; + link->dev = &((net_local *) netdev_priv(dev))->node; #ifdef DEBUG_CONFIG_TRACE printk(KERN_DEBUG "<-wv_pcmcia_config()\n"); @@ -4088,20 +4096,26 @@ wv_pcmcia_config(struct pcmcia_device * link) * still open, this will be postponed until it is closed. */ static void -wv_pcmcia_release(struct pcmcia_device *link) +wv_pcmcia_release(dev_link_t *link) { - struct net_device * dev = (struct net_device *) link->priv; - net_local * lp = netdev_priv(dev); + struct net_device * dev = (struct net_device *) link->priv; + net_local * lp = netdev_priv(dev); #ifdef DEBUG_CONFIG_TRACE - printk(KERN_DEBUG "%s: -> wv_pcmcia_release(0x%p)\n", dev->name, link); + printk(KERN_DEBUG "%s: -> wv_pcmcia_release(0x%p)\n", dev->name, link); #endif - iounmap(lp->mem); - pcmcia_disable_device(link); + /* Don't bother checking to see if these succeed or not */ + iounmap(lp->mem); + pcmcia_release_window(link->win); + pcmcia_release_configuration(link->handle); + pcmcia_release_io(link->handle, &link->io); + pcmcia_release_irq(link->handle, &link->irq); + + link->state &= ~DEV_CONFIG; #ifdef DEBUG_CONFIG_TRACE - printk(KERN_DEBUG "%s: <- wv_pcmcia_release()\n", dev->name); + printk(KERN_DEBUG "%s: <- wv_pcmcia_release()\n", dev->name); #endif } @@ -4465,7 +4479,7 @@ static int wavelan_open(struct net_device * dev) { net_local * lp = netdev_priv(dev); - struct pcmcia_device * link = lp->link; + dev_link_t * link = lp->link; kio_addr_t base = dev->base_addr; #ifdef DEBUG_CALLBACK_TRACE @@ -4519,7 +4533,7 @@ wavelan_open(struct net_device * dev) static int wavelan_close(struct net_device * dev) { - struct pcmcia_device * link = ((net_local *)netdev_priv(dev))->link; + dev_link_t * link = ((net_local *)netdev_priv(dev))->link; kio_addr_t base = dev->base_addr; #ifdef DEBUG_CALLBACK_TRACE @@ -4573,36 +4587,45 @@ wavelan_close(struct net_device * dev) * card insertion event. */ static int -wavelan_probe(struct pcmcia_device *p_dev) +wavelan_attach(struct pcmcia_device *p_dev) { + dev_link_t * link; /* Info for cardmgr */ struct net_device * dev; /* Interface generic data */ net_local * lp; /* Interface specific data */ - int ret; #ifdef DEBUG_CALLBACK_TRACE printk(KERN_DEBUG "-> wavelan_attach()\n"); #endif + /* Initialize the dev_link_t structure */ + link = kzalloc(sizeof(struct dev_link_t), GFP_KERNEL); + if (!link) return -ENOMEM; + /* The io structure describes IO port mapping */ - p_dev->io.NumPorts1 = 8; - p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8; - p_dev->io.IOAddrLines = 3; + link->io.NumPorts1 = 8; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + link->io.IOAddrLines = 3; /* Interrupt setup */ - p_dev->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; - p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID; - p_dev->irq.Handler = wavelan_interrupt; + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; + link->irq.IRQInfo1 = IRQ_LEVEL_ID; + link->irq.Handler = wavelan_interrupt; /* General socket configuration */ - p_dev->conf.Attributes = CONF_ENABLE_IRQ; - p_dev->conf.IntType = INT_MEMORY_AND_IO; + link->conf.Attributes = CONF_ENABLE_IRQ; + link->conf.Vcc = 50; + link->conf.IntType = INT_MEMORY_AND_IO; + + /* Chain drivers */ + link->next = NULL; /* Allocate the generic data structure */ dev = alloc_etherdev(sizeof(net_local)); - if (!dev) + if (!dev) { + kfree(link); return -ENOMEM; - - p_dev->priv = p_dev->irq.Instance = dev; + } + link->priv = link->irq.Instance = dev; lp = netdev_priv(dev); @@ -4619,6 +4642,7 @@ wavelan_probe(struct pcmcia_device *p_dev) spin_lock_init(&lp->spinlock); /* back links */ + lp->link = link; lp->dev = dev; /* wavelan NET3 callbacks */ @@ -4644,18 +4668,15 @@ wavelan_probe(struct pcmcia_device *p_dev) /* Other specific data */ dev->mtu = WAVELAN_MTU; - ret = wv_pcmcia_config(p_dev); - if (ret) - return ret; + link->handle = p_dev; + p_dev->instance = link; - ret = wv_hw_config(dev); - if (ret) { + link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; + if(wv_pcmcia_config(link) && + wv_hw_config(dev)) + wv_init_info(dev); + else dev->irq = 0; - pcmcia_disable_device(p_dev); - return ret; - } - - wv_init_info(dev); #ifdef DEBUG_CALLBACK_TRACE printk(KERN_DEBUG "<- wavelan_attach()\n"); @@ -4672,14 +4693,25 @@ wavelan_probe(struct pcmcia_device *p_dev) * is released. */ static void -wavelan_detach(struct pcmcia_device *link) +wavelan_detach(struct pcmcia_device *p_dev) { + dev_link_t *link = dev_to_instance(p_dev); + #ifdef DEBUG_CALLBACK_TRACE printk(KERN_DEBUG "-> wavelan_detach(0x%p)\n", link); #endif - /* Some others haven't done their job : give them another chance */ - wv_pcmcia_release(link); + /* + * 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(). + */ + if(link->state & DEV_CONFIG) + { + /* Some others haven't done their job : give them another chance */ + wv_pcmcia_release(link); + } /* Free pieces */ if(link->priv) @@ -4688,21 +4720,23 @@ wavelan_detach(struct pcmcia_device *link) /* Remove ourselves from the kernel list of ethernet devices */ /* Warning : can't be called from interrupt, timer or wavelan_close() */ - if (link->dev_node) + if (link->dev) unregister_netdev(dev); - link->dev_node = NULL; + link->dev = NULL; ((net_local *)netdev_priv(dev))->link = NULL; ((net_local *)netdev_priv(dev))->dev = NULL; free_netdev(dev); } + kfree(link); #ifdef DEBUG_CALLBACK_TRACE printk(KERN_DEBUG "<- wavelan_detach()\n"); #endif } -static int wavelan_suspend(struct pcmcia_device *link) +static int wavelan_suspend(struct pcmcia_device *p_dev) { + dev_link_t *link = dev_to_instance(p_dev); struct net_device * dev = (struct net_device *) link->priv; /* NB: wavelan_close will be called, but too late, so we are @@ -4714,22 +4748,36 @@ static int wavelan_suspend(struct pcmcia_device *link) /* Stop receiving new messages and wait end of transmission */ wv_ru_stop(dev); - if (link->open) - netif_device_detach(dev); - /* Power down the module */ hacr_write(dev->base_addr, HACR_DEFAULT & (~HACR_PWR_STAT)); + /* The card is now suspended */ + link->state |= DEV_SUSPEND; + + if(link->state & DEV_CONFIG) + { + if(link->open) + netif_device_detach(dev); + pcmcia_release_configuration(link->handle); + } + return 0; } -static int wavelan_resume(struct pcmcia_device *link) +static int wavelan_resume(struct pcmcia_device *p_dev) { + dev_link_t *link = dev_to_instance(p_dev); struct net_device * dev = (struct net_device *) link->priv; - if (link->open) { - wv_hw_reset(dev); - netif_device_attach(dev); + link->state &= ~DEV_SUSPEND; + if(link->state & DEV_CONFIG) + { + pcmcia_request_configuration(link->handle, &link->conf); + if(link->open) /* If RESET -> True, If RESUME -> False ? */ + { + wv_hw_reset(dev); + netif_device_attach(dev); + } } return 0; @@ -4750,7 +4798,7 @@ static struct pcmcia_driver wavelan_driver = { .drv = { .name = "wavelan_cs", }, - .probe = wavelan_probe, + .probe = wavelan_attach, .remove = wavelan_detach, .id_table = wavelan_ids, .suspend = wavelan_suspend,