📄 nsp_cs.c
字号:
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, handle, &tuple); CS_CHECK(GetTupleData, handle, &tuple); CS_CHECK(ParseTuple, 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, handle, &conf); link->conf.Vcc = conf.Vcc; tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; CS_CHECK(GetFirstTuple, handle, &tuple); while (1) { cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); CFG_CHECK(GetTupleData, handle, &tuple); CFG_CHECK(ParseTuple, handle, &tuple, &parse); 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 */ CFG_CHECK(RequestIO, link->handle, &link->io); } 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; link->win = (window_handle_t)link->handle; CFG_CHECK(RequestWindow, &link->win, &req); map.Page = 0; map.CardOffset = mem->win[0].card_addr; CFG_CHECK(MapMemPage, link->win, &map); 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) { CardServices(ReleaseIO, link->handle, &link->io); } CS_CHECK(GetNextTuple, handle, &tuple); } if (link->conf.Attributes & CONF_ENABLE_IRQ) { CS_CHECK(RequestIRQ, link->handle, &link->irq); } CS_CHECK(RequestConfiguration, 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 arg[2], id; kernel_scsi_ioctl(dev, SCSI_IOCTL_GET_IDLUN, arg); id = (arg[0] & 0x0f) + ((arg[0] >> 4) & 0xf0) + ((arg[0] >> 8) & 0xf00) + ((arg[0] >> 12) & 0xf000); 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#undef CFG_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)); } CardServices(ReleaseWindow, link->win); } CardServices(ReleaseConfiguration, link->handle); if (link->io.NumPorts1) { CardServices(ReleaseIO, link->handle, &link->io); } if (link->irq.AssignedIRQ) { CardServices(ReleaseIRQ, 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) { CardServices(ReleaseConfiguration, 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) { CardServices(RequestConfiguration, 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_driver nsp_driver = { .owner = THIS_MODULE, .drv = { .name = "nsp_cs", }, .attach = nsp_cs_attach, .detach = nsp_cs_detach,};#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..."); CardServices(GetCardServicesInfo, &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);#else unregister_pcmcia_driver(&dev_info);#endif /* 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); }}module_init(nsp_cs_init)module_exit(nsp_cs_exit)/* end */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -