📄 nsp_cs.c
字号:
client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); if (ret != CS_SUCCESS) { cs_error(link->handle, RegisterClient, ret); nsp_cs_detach(link); return NULL; } nsp_dbg(NSP_DEBUG_INIT, "link=0x%p", link); return link;} /* nsp_cs_attach *//*====================================================================== This deletes a driver "instance". The device is de-registered with Card Services. If it has been released, all local data structures are freed. Otherwise, the structures will be freed when the device is released.======================================================================*/static void nsp_cs_detach(dev_link_t *link){ dev_link_t **linkp; nsp_dbg(NSP_DEBUG_INIT, "in, link=0x%p", link); /* Locate device structure */ for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) { if (*linkp == link) { break; } } if (*linkp == NULL) { return; } if (link->state & DEV_CONFIG) nsp_cs_release(link); /* Break the link with Card Services */ if (link->handle) { pcmcia_deregister_client(link->handle); } /* Unlink device structure, free bits */ *linkp = link->next; kfree(link->priv); link->priv = NULL;} /* nsp_cs_detach *//*====================================================================== nsp_cs_config() is scheduled to run after a CARD_INSERTION event is received, to configure the PCMCIA socket, and to make the ethernet device available to the system.======================================================================*/#define CS_CHECK(fn, ret) \do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)/*====================================================================*/static void nsp_cs_config(dev_link_t *link){ client_handle_t handle = link->handle; scsi_info_t *info = link->priv; tuple_t tuple; cisparse_t parse; int last_ret, last_fn; unsigned char tuple_data[64]; config_info_t conf; win_req_t req; memreq_t map; cistpl_cftable_entry_t dflt = { 0 }; struct Scsi_Host *host; nsp_hw_data *data = &nsp_data_base;#if !(LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,74)) struct scsi_device *dev; dev_node_t **tail, *node;#endif nsp_dbg(NSP_DEBUG_INIT, "in"); tuple.DesiredTuple = CISTPL_CONFIG; tuple.Attributes = 0; tuple.TupleData = tuple_data; tuple.TupleDataMax = sizeof(tuple_data); tuple.TupleOffset = 0; CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; /* Configure card */ link->state |= DEV_CONFIG; /* Look up the current Vcc */ CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(handle, &conf)); link->conf.Vcc = conf.Vcc; tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); while (1) { cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); if (pcmcia_get_tuple_data(handle, &tuple) != 0 || pcmcia_parse_tuple(handle, &tuple, &parse) != 0) goto next_entry; if (cfg->flags & CISTPL_CFTABLE_DEFAULT) { dflt = *cfg; } if (cfg->index == 0) { goto next_entry; } link->conf.ConfigIndex = cfg->index; /* Does this card need audio output? */ if (cfg->flags & CISTPL_CFTABLE_AUDIO) { link->conf.Attributes |= CONF_ENABLE_SPKR; link->conf.Status = CCSR_AUDIO_ENA; } /* Use power settings for Vcc and Vpp if present */ /* Note that the CIS values need to be rescaled */ if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) { if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM]/10000) { goto next_entry; } } else if (dflt.vcc.present & (1<<CISTPL_POWER_VNOM)) { if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM]/10000) { goto next_entry; } } if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) { link->conf.Vpp1 = link->conf.Vpp2 = cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; } else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM)) { link->conf.Vpp1 = link->conf.Vpp2 = dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000; } /* Do we need to allocate an interrupt? */ if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) { link->conf.Attributes |= CONF_ENABLE_IRQ; } /* IO window settings */ link->io.NumPorts1 = link->io.NumPorts2 = 0; if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io; link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; if (!(io->flags & CISTPL_IO_8BIT)) link->io.Attributes1 = IO_DATA_PATH_WIDTH_16; if (!(io->flags & CISTPL_IO_16BIT)) link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK; link->io.BasePort1 = io->win[0].base; link->io.NumPorts1 = io->win[0].len; if (io->nwin > 1) { link->io.Attributes2 = link->io.Attributes1; link->io.BasePort2 = io->win[1].base; link->io.NumPorts2 = io->win[1].len; } /* This reserves IO space but doesn't actually enable it */ if (pcmcia_request_io(link->handle, &link->io) != 0) goto next_entry; } if ((cfg->mem.nwin > 0) || (dflt.mem.nwin > 0)) { cistpl_mem_t *mem = (cfg->mem.nwin) ? &cfg->mem : &dflt.mem; req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM; req.Attributes |= WIN_ENABLE; req.Base = mem->win[0].host_addr; req.Size = mem->win[0].len; if (req.Size < 0x1000) { req.Size = 0x1000; } req.AccessSpeed = 0; if (pcmcia_request_window(&link->handle, &req, &link->win) != 0) goto next_entry; map.Page = 0; map.CardOffset = mem->win[0].card_addr; if (pcmcia_map_mem_page(link->win, &map) != 0) goto next_entry; data->MmioAddress = (unsigned long)ioremap_nocache(req.Base, req.Size); data->MmioLength = req.Size; } /* If we got this far, we're cool! */ break; next_entry: nsp_dbg(NSP_DEBUG_INIT, "next"); if (link->io.NumPorts1) { pcmcia_release_io(link->handle, &link->io); } CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple)); } if (link->conf.Attributes & CONF_ENABLE_IRQ) { CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq)); } CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf)); if (free_ports) { if (link->io.BasePort1) { release_region(link->io.BasePort1, link->io.NumPorts1); } if (link->io.BasePort2) { release_region(link->io.BasePort2, link->io.NumPorts2); } } /* Set port and IRQ */ data->BaseAddress = link->io.BasePort1; data->NumAddress = link->io.NumPorts1; data->IrqNumber = link->irq.AssignedIRQ; nsp_dbg(NSP_DEBUG_INIT, "I/O[0x%x+0x%x] IRQ %d", data->BaseAddress, data->NumAddress, data->IrqNumber); if(nsphw_init(data) == FALSE) { goto cs_failed; }#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2)) host = nsp_detect(&nsp_driver_template);#else scsi_register_host(&nsp_driver_template); for (host = scsi_host_get_next(NULL); host != NULL; host = scsi_host_get_next(host)) { if (host->hostt == &nsp_driver_template) { break; } }#endif if (host == NULL) { nsp_dbg(NSP_DEBUG_INIT, "detect failed"); goto cs_failed; }#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,74)) scsi_add_host (host, NULL); scsi_scan_host(host); snprintf(info->node.dev_name, sizeof(info->node.dev_name), "scsi%d", host->host_no); link->dev = &info->node; info->host = host;#else nsp_dbg(NSP_DEBUG_INIT, "GET_SCSI_INFO"); tail = &link->dev; info->ndev = 0; nsp_dbg(NSP_DEBUG_INIT, "host=0x%p", host); for (dev = host->host_queue; dev != NULL; dev = dev->next) { unsigned long id; id = (dev->id & 0x0f) + ((dev->lun & 0x0f) << 4) + ((dev->channel & 0x0f) << 8) + ((dev->host->host_no & 0x0f) << 12); node = &info->node[info->ndev]; node->minor = 0; switch (dev->type) { case TYPE_TAPE: node->major = SCSI_TAPE_MAJOR; snprintf(node->dev_name, sizeof(node->dev_name), "st#%04lx", id); break; case TYPE_DISK: case TYPE_MOD: node->major = SCSI_DISK0_MAJOR; snprintf(node->dev_name, sizeof(node->dev_name), "sd#%04lx", id); break; case TYPE_ROM: case TYPE_WORM: node->major = SCSI_CDROM_MAJOR; snprintf(node->dev_name, sizeof(node->dev_name), "sr#%04lx", id); break; default: node->major = SCSI_GENERIC_MAJOR; snprintf(node->dev_name, sizeof(node->dev_name), "sg#%04lx", id); break; } *tail = node; tail = &node->next; info->ndev++; info->host = dev->host; } *tail = NULL; if (info->ndev == 0) { nsp_msg(KERN_INFO, "no SCSI devices found"); } nsp_dbg(NSP_DEBUG_INIT, "host=0x%p", host);#endif /* Finally, report what we've done */ printk(KERN_INFO "nsp_cs: index 0x%02x: Vcc %d.%d", link->conf.ConfigIndex, link->conf.Vcc/10, link->conf.Vcc%10); if (link->conf.Vpp1) { printk(", Vpp %d.%d", link->conf.Vpp1/10, link->conf.Vpp1%10); } if (link->conf.Attributes & CONF_ENABLE_IRQ) { printk(", irq %d", link->irq.AssignedIRQ); } if (link->io.NumPorts1) { printk(", io 0x%04x-0x%04x", link->io.BasePort1, link->io.BasePort1+link->io.NumPorts1-1); } if (link->io.NumPorts2) printk(" & 0x%04x-0x%04x", link->io.BasePort2, link->io.BasePort2+link->io.NumPorts2-1); if (link->win) printk(", mem 0x%06lx-0x%06lx", req.Base, req.Base+req.Size-1); printk("\n"); link->state &= ~DEV_CONFIG_PENDING; return; cs_failed: nsp_dbg(NSP_DEBUG_INIT, "config fail"); cs_error(link->handle, last_fn, last_ret); nsp_cs_release(link); return;} /* nsp_cs_config */#undef CS_CHECK/*====================================================================== After a card is removed, nsp_cs_release() will unregister the net device, and release the PCMCIA configuration. If the device is still open, this will be postponed until it is closed.======================================================================*/static void nsp_cs_release(dev_link_t *link){ scsi_info_t *info = link->priv; nsp_hw_data *data = NULL; if (info->host == NULL) { nsp_msg(KERN_DEBUG, "unexpected card release call."); } else { data = (nsp_hw_data *)info->host->hostdata; } nsp_dbg(NSP_DEBUG_INIT, "link=0x%p", link); /* Unlink the device chain */#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,2)) if (info->host != NULL) { scsi_remove_host(info->host); }#else scsi_unregister_host(&nsp_driver_template);#endif link->dev = NULL; if (link->win) { if (data != NULL) { iounmap((void *)(data->MmioAddress)); } pcmcia_release_window(link->win); } pcmcia_release_configuration(link->handle); if (link->io.NumPorts1) { pcmcia_release_io(link->handle, &link->io); } if (link->irq.AssignedIRQ) { pcmcia_release_irq(link->handle, &link->irq); } link->state &= ~DEV_CONFIG;#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,2)) if (info->host != NULL) { scsi_host_put(info->host); }#endif} /* nsp_cs_release *//*====================================================================== The card status event handler. Mostly, this schedules other stuff to run after an event is received. A CARD_REMOVAL event also sets some flags to discourage the net drivers from trying to talk to the card any more. When a CARD_REMOVAL event is received, we immediately set a flag to block future accesses to this device. All the functions that actually access the device should check this flag to make sure the card is still present.======================================================================*/static int nsp_cs_event(event_t event, int priority, event_callback_args_t *args){ dev_link_t *link = args->client_data; scsi_info_t *info = link->priv; nsp_hw_data *data; nsp_dbg(NSP_DEBUG_INIT, "in, event=0x%08x", event); switch (event) { case CS_EVENT_CARD_REMOVAL: nsp_dbg(NSP_DEBUG_INIT, "event: remove"); link->state &= ~DEV_PRESENT; if (link->state & DEV_CONFIG) { ((scsi_info_t *)link->priv)->stop = 1; nsp_cs_release(link); } break; case CS_EVENT_CARD_INSERTION: nsp_dbg(NSP_DEBUG_INIT, "event: insert"); link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,68)) info->bus = args->bus;#endif nsp_cs_config(link); break; case CS_EVENT_PM_SUSPEND: nsp_dbg(NSP_DEBUG_INIT, "event: suspend"); link->state |= DEV_SUSPEND; /* Fall through... */ case CS_EVENT_RESET_PHYSICAL: /* Mark the device as stopped, to block IO until later */ nsp_dbg(NSP_DEBUG_INIT, "event: reset physical"); if (info->host != NULL) { nsp_msg(KERN_INFO, "clear SDTR status"); data = (nsp_hw_data *)info->host->hostdata; nsphw_init_sync(data); } info->stop = 1; if (link->state & DEV_CONFIG) { pcmcia_release_configuration(link->handle); } break; case CS_EVENT_PM_RESUME: nsp_dbg(NSP_DEBUG_INIT, "event: resume"); link->state &= ~DEV_SUSPEND; /* Fall through... */ case CS_EVENT_CARD_RESET: nsp_dbg(NSP_DEBUG_INIT, "event: reset"); if (link->state & DEV_CONFIG) { pcmcia_request_configuration(link->handle, &link->conf); } info->stop = 0; if (info->host != NULL) { nsp_msg(KERN_INFO, "reset host and bus"); data = (nsp_hw_data *)info->host->hostdata; nsphw_init (data); nsp_bus_reset(data); } break; default: nsp_dbg(NSP_DEBUG_INIT, "event: unknown"); break; } nsp_dbg(NSP_DEBUG_INIT, "end"); return 0;} /* nsp_cs_event *//*======================================================================* * module entry point *====================================================================*/#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,68))static struct pcmcia_device_id nsp_cs_ids[] = { PCMCIA_DEVICE_PROD_ID123("IO DATA", "CBSC16 ", "1", 0x547e66dc, 0x0d63a3fd, 0x51de003a), PCMCIA_DEVICE_PROD_ID123("KME ", "SCSI-CARD-001", "1", 0x534c02bc, 0x52008408, 0x51de003a), PCMCIA_DEVICE_PROD_ID123("KME ", "SCSI-CARD-002", "1", 0x534c02bc, 0xcb09d5b2, 0x51de003a), PCMCIA_DEVICE_PROD_ID123("KME ", "SCSI-CARD-003", "1", 0x534c02bc, 0xbc0ee524, 0x51de003a), PCMCIA_DEVICE_PROD_ID123("KME ", "SCSI-CARD-004", "1", 0x534c02bc, 0x226a7087, 0x51de003a), PCMCIA_DEVICE_PROD_ID123("WBT", "NinjaSCSI-3", "R1.0", 0xc7ba805f, 0xfdc7c97d, 0x6973710e), PCMCIA_DEVICE_PROD_ID123("WORKBIT", "UltraNinja-16", "1", 0x28191418, 0xb70f4b09, 0x51de003a), PCMCIA_DEVICE_NULL};MODULE_DEVICE_TABLE(pcmcia, nsp_cs_ids);static struct pcmcia_driver nsp_driver = { .owner = THIS_MODULE, .drv = { .name = "nsp_cs", }, .attach = nsp_cs_attach, .event = nsp_cs_event, .detach = nsp_cs_detach, .id_table = nsp_cs_ids,};#endifstatic int __init nsp_cs_init(void){#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,68)) nsp_msg(KERN_INFO, "loading..."); return pcmcia_register_driver(&nsp_driver);#else servinfo_t serv; nsp_msg(KERN_INFO, "loading..."); pcmcia_get_card_services_info(&serv); if (serv.Revision != CS_RELEASE_CODE) { nsp_msg(KERN_DEBUG, "Card Services release does not match!"); return -EINVAL; } register_pcmcia_driver(&dev_info, &nsp_cs_attach, &nsp_cs_detach); nsp_dbg(NSP_DEBUG_INIT, "out"); return 0;#endif}static void __exit nsp_cs_exit(void){ nsp_msg(KERN_INFO, "unloading...");#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,68)) pcmcia_unregister_driver(&nsp_driver); BUG_ON(dev_list != NULL);#else unregister_pcmcia_driver(&dev_info); /* XXX: this really needs to move into generic code.. */ while (dev_list != NULL) { if (dev_list->state & DEV_CONFIG) { nsp_cs_release(dev_list); } nsp_cs_detach(dev_list); }#endif}module_init(nsp_cs_init)module_exit(nsp_cs_exit)/* end */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -