static void avmcs_release(u_long arg) { dev_link_t *link = (dev_link_t *)arg; /* If the device is currently in use, we won't release until it is actually closed. */ if (link->open) { link->state |= DEV_STALE_CONFIG; return; } b1pcmcia_delcard(link->io.BasePort1, link->irq.AssignedIRQ); /* Unlink the device chain */ link->dev = NULL; /* Don't bother checking to see if these succeed or not */ CardServices(ReleaseConfiguration, link->handle); CardServices(ReleaseIO, link->handle, &link->io); CardServices(ReleaseIRQ, link->handle, &link->irq); link->state &= ~DEV_CONFIG; if (link->state & DEV_STALE_LINK) avmcs_detach(link); } /* avmcs_release */
static void __exit avmcs_exit(void) { unregister_pccard_driver(&dev_info); while (dev_list != NULL) { if (dev_list->state & DEV_CONFIG) avmcs_release((u_long)dev_list); avmcs_detach(dev_list); } }
static void __exit avmcs_exit(void) { pcmcia_unregister_driver(&avmcs_driver); /* XXX: this really needs to move into generic code.. */ while (dev_list != NULL) { if (dev_list->state & DEV_CONFIG) avmcs_release(dev_list); avmcs_detach(dev_list); } }
static void avmcs_release(dev_link_t *link) { b1pcmcia_delcard(link->io.BasePort1, link->irq.AssignedIRQ); /* Unlink the device chain */ link->dev = NULL; /* Don't bother checking to see if these succeed or not */ pcmcia_release_configuration(link->handle); pcmcia_release_io(link->handle, &link->io); pcmcia_release_irq(link->handle, &link->irq); link->state &= ~DEV_CONFIG; if (link->state & DEV_STALE_LINK) avmcs_detach(link); } /* avmcs_release */
static dev_link_t *avmcs_attach(void) { client_reg_t client_reg; dev_link_t *link; local_info_t *local; int ret; /* Initialize the dev_link_t structure */ link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); if (!link) goto err; memset(link, 0, sizeof(struct dev_link_t)); /* The io structure describes IO port mapping */ link->io.NumPorts1 = 16; link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; link->io.NumPorts2 = 0; /* Interrupt setup */ link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED; link->irq.IRQInfo1 = IRQ_LEVEL_ID; /* General socket configuration */ link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.Vcc = 50; link->conf.IntType = INT_MEMORY_AND_IO; link->conf.ConfigIndex = 1; link->conf.Present = PRESENT_OPTION; /* Allocate space for private device-specific data */ local = kmalloc(sizeof(local_info_t), GFP_KERNEL); if (!local) goto err_kfree; memset(local, 0, sizeof(local_info_t)); link->priv = local; /* Register with Card Services */ link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; client_reg.EventMask = 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 = &avmcs_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); if (ret != 0) { cs_error(link->handle, RegisterClient, ret); avmcs_detach(link); goto err; } return link; err_kfree: kfree(link); err: return NULL; } /* avmcs_attach */
static dev_link_t *avmcs_attach(void) { client_reg_t client_reg; dev_link_t *link; local_info_t *local; int ret, i; /* Initialize the dev_link_t structure */ link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); if (!link) return NULL; memset(link, 0, sizeof(struct dev_link_t)); link->release.function = &avmcs_release; link->release.data = (u_long)link; /* The io structure describes IO port mapping */ link->io.NumPorts1 = 16; link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; link->io.NumPorts2 = 0; /* Interrupt setup */ link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED; link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID; if (irq_list[0] != -1) { for (i = 0; i < 10 && irq_list[i] > 0; i++) link->irq.IRQInfo2 |= 1 << irq_list[i]; } else { for (i = 0; i < 10 && default_irq_list[i] > 0; i++) link->irq.IRQInfo2 |= 1 << default_irq_list[i]; } /* General socket configuration */ link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.Vcc = 50; link->conf.IntType = INT_MEMORY_AND_IO; link->conf.ConfigIndex = 1; link->conf.Present = PRESENT_OPTION; /* Allocate space for private device-specific data */ local = kmalloc(sizeof(local_info_t), GFP_KERNEL); if (!local) return NULL; memset(local, 0, sizeof(local_info_t)); link->priv = local; /* Register with Card Services */ link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; client_reg.EventMask = 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 = &avmcs_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = CardServices(RegisterClient, &link->handle, &client_reg); if (ret != 0) { cs_error(link->handle, RegisterClient, ret); avmcs_detach(link); return NULL; } return link; } /* avmcs_attach */