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() */
* 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);
{
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;
}
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;
}
* (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;
{
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;
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;
}
* 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;
}
* 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.
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;
}
i = pcmcia_map_mem_page(link->win, &mem);
if(i != CS_SUCCESS)
{
- cs_error(link, MapMemPage, i);
+ cs_error(link->handle, MapMemPage, i);
break;
}
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)
{
}
while(0); /* Humm... Disguised goto !!! */
+ link->state &= ~DEV_CONFIG_PENDING;
/* If any step failed, release any partially configured state */
if(i != 0)
{
}
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");
* 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
}
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
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
* 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);
spin_lock_init(&lp->spinlock);
/* back links */
+ lp->link = link;
lp->dev = dev;
/* wavelan NET3 callbacks */
/* 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");
* 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)
/* 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
/* 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;
.drv = {
.name = "wavelan_cs",
},
- .probe = wavelan_probe,
+ .probe = wavelan_attach,
.remove = wavelan_detach,
.id_table = wavelan_ids,
.suspend = wavelan_suspend,