📄 nsp_cs.c
字号:
timer_out: nsp_start_timer(tmpSC, data, 1000/102); return;}#ifdef PCMCIA_DEBUG#include "nsp_debug.c"#endif /* DBG_SHOWCOMMAND *//*----------------------------------------------------------------*//* look for ninja3 card and init if found *//*----------------------------------------------------------------*/static int nsp_detect(Scsi_Host_Template *sht){ struct Scsi_Host *host; /* registered host structure */ nsp_hw_data *data = &nsp_data; DEBUG(0, __FUNCTION__ " this_id=%d\n", sht->this_id); request_region(data->BaseAddress, data->NumAddress, "nsp_cs"); host = scsi_register(sht, 0); host->io_port = data->BaseAddress; host->unique_id = data->BaseAddress; host->n_io_port = data->NumAddress; host->irq = data->IrqNumber; host->dma_channel = 0xff; /* not use dms */ sprintf(nspinfo,/* Buffer size is 100 bytes *//* 0 1 2 3 4 5 6 7 8 9 0*//* 01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890*/ "NinjaSCSI-3/32Bi Driver $Revision: 1.42 $, I/O 0x%04lx-0x%04lx IRQ %2d", host->io_port, host->io_port + host->n_io_port, host->irq); sht->name = nspinfo; DEBUG(0, __FUNCTION__ " end\n"); return 1; /* detect done. */}/* nsp_cs requires own release handler because its uses dev_id (=data) */static int nsp_release(struct Scsi_Host *shpnt){ nsp_hw_data *data = &nsp_data; if (shpnt->irq) { free_irq(shpnt->irq, data); } if (shpnt->io_port && shpnt->n_io_port) { release_region(shpnt->io_port, shpnt->n_io_port); } return 0;}/*----------------------------------------------------------------*//* return info string *//*----------------------------------------------------------------*/static const char *nsp_info(struct Scsi_Host *shpnt){ return nspinfo;}/*---------------------------------------------------------------*//* error handler *//*---------------------------------------------------------------*/static int nsp_reset(Scsi_Cmnd *SCpnt, unsigned int why){ DEBUG(0, __FUNCTION__ " SCpnt=0x%p why=%d\n", SCpnt, why); nsp_eh_bus_reset(SCpnt); return SCSI_RESET_SUCCESS;}static int nsp_abort(Scsi_Cmnd *SCpnt){ DEBUG(0, __FUNCTION__ " SCpnt=0x%p\n", SCpnt); nsp_eh_bus_reset(SCpnt); return SCSI_ABORT_SUCCESS;}/*static int nsp_eh_strategy(struct Scsi_Host *Shost){ return FAILED;}*/static int nsp_eh_abort(Scsi_Cmnd *SCpnt){ DEBUG(0, __FUNCTION__ " SCpnt=0x%p\n", SCpnt); nsp_eh_bus_reset(SCpnt); return SUCCESS;}static int nsp_eh_device_reset(Scsi_Cmnd *SCpnt){ DEBUG(0, __FUNCTION__ " SCpnt=0x%p\n", SCpnt); return FAILED;}static int nsp_eh_bus_reset(Scsi_Cmnd *SCpnt){ unsigned int base = SCpnt->host->io_port; int i; DEBUG(0, __FUNCTION__ "() SCpnt=0x%p base=0x%x\n", SCpnt, base); nsp_write(base, IRQCONTROL, IRQCONTROL_ALLMASK); nsp_index_write(base, SCSIBUSCTRL, SCSI_RST); mdelay(100); /* 100ms */ nsp_index_write(base, SCSIBUSCTRL, 0); for(i = 0; i < 5; i++) { nsp_index_read(base, IRQPHASESENCE); /* dummy read */ } nsp_write(base, IRQCONTROL, IRQCONTROL_ALLCLEAR); return SUCCESS;}static int nsp_eh_host_reset(Scsi_Cmnd *SCpnt){ nsp_hw_data *data = &nsp_data; DEBUG(0, __FUNCTION__ "\n"); nsphw_init(data); return nsp_eh_bus_reset(SCpnt);}/********************************************************************** PCMCIA functions *********************************************************************//*====================================================================*/static void cs_error(client_handle_t handle, int func, int ret){ error_info_t err = { func, ret }; CardServices(ReportError, handle, &err);}/*====================================================================== nsp_cs_attach() creates an "instance" of the driver, allocating local data structures for one device. The device is registered with Card Services. The dev_link structure is initialized, but we don't actually configure the card at this point -- we wait until we receive a card insertion event.======================================================================*/static dev_link_t *nsp_cs_attach(void){ scsi_info_t *info; client_reg_t client_reg; dev_link_t *link; int ret, i; DEBUG(0, __FUNCTION__ "()\n"); /* Create new SCSI device */ info = kmalloc(sizeof(*info), GFP_KERNEL); if (!info) { return NULL; } memset(info, 0, sizeof(*info)); link = &info->link; link->priv = info; /* Initialize the dev_link_t structure */ link->release.function = &nsp_cs_release; link->release.data = (u_long)link; /* The io structure describes IO port mapping */ link->io.NumPorts1 = 0x10; link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; link->io.IOAddrLines = 10; /* not used */ /* Interrupt setup */ link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID; if (irq_list[0] == -1) { link->irq.IRQInfo2 = irq_mask; } else { for (i = 0; i < 4; i++) { link->irq.IRQInfo2 |= 1 << irq_list[i]; } } link->irq.Handler = &nspintr; link->irq.Instance = &nsp_data; /* General socket configuration */ link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.Vcc = 50; link->conf.IntType = INT_MEMORY_AND_IO; link->conf.Present = PRESENT_OPTION; /* 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 = &nsp_cs_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = CardServices(RegisterClient, &link->handle, &client_reg); if (ret != CS_SUCCESS) { cs_error(link->handle, RegisterClient, ret); nsp_cs_detach(link); return NULL; } 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; DEBUG(0, __FUNCTION__ "(0x%p)\n", link); /* Locate device structure */ for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) { if (*linkp == link) { break; } } if (*linkp == NULL) { return; } del_timer(&link->release); if (link->state & DEV_CONFIG) { nsp_cs_release((u_long)link); if (link->state & DEV_STALE_CONFIG) { link->state |= DEV_STALE_LINK; return; } } /* Break the link with Card Services */ if (link->handle) { CardServices(DeregisterClient, link->handle); } /* Unlink device structure, free bits */ *linkp = link->next; kfree(link->priv);} /* 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, args...) \while ((last_ret=CardServices(last_fn=(fn),args))!=0) goto cs_failed#define CFG_CHECK(fn, args...) \if (CardServices(fn, args) != 0) goto next_entry/*====================================================================*/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 i, last_ret, last_fn; u_char tuple_data[64]; config_info_t conf; Scsi_Device *dev; dev_node_t **tail, *node; struct Scsi_Host *host; nsp_hw_data *data = &nsp_data; DEBUG(0, __FUNCTION__ "() in\n"); 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 */ driver_template.module = &__this_module; 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) { CFG_CHECK(GetTupleData, handle, &tuple); CFG_CHECK(ParseTuple, handle, &tuple, &parse); link->conf.ConfigIndex = parse.cftable_entry.index; link->io.BasePort1 = parse.cftable_entry.io.win[0].base; i = CardServices(RequestIO, handle, &link->io); if (i == CS_SUCCESS) { break; } next_entry: DEBUG(0, __FUNCTION__ " next\n"); CS_CHECK(GetNextTuple, handle, &tuple); } CS_CHECK(RequestIRQ, handle, &link->irq); CS_CHECK(RequestConfiguration, handle, &link->conf); /* A bad hack... */ release_region(link->io.BasePort1, link->io.NumPorts1); /* Set port and IRQ */ data->BaseAddress = link->io.BasePort1; data->NumAddress = link->io.NumPorts1; data->IrqNumber = link->irq.AssignedIRQ; DEBUG(0, __FUNCTION__ " I/O[0x%x+0x%x] IRQ %d\n", data->BaseAddress, data->NumAddress, data->IrqNumber); if(nsphw_init(data) == FALSE) { goto cs_failed; } scsi_register_module(MODULE_SCSI_HA, &driver_template); DEBUG(0, "GET_SCSI_INFO\n"); tail = &link->dev; info->ndev = 0; for (host = scsi_hostlist; host != NULL; host = host->next) { if (host->hostt == &driver_template) { for (dev = host->host_queue; dev != NULL; dev = dev->next) { u_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; sprintf(node->dev_name, "st#%04lx", id); break; case TYPE_DISK: case TYPE_MOD: node->major = SCSI_DISK0_MAJOR; sprintf(node->dev_name, "sd#%04lx", id); break; case TYPE_ROM: case TYPE_WORM: node->major = SCSI_CDROM_MAJOR; sprintf(node->dev_name, "sr#%04lx", id); break; default: node->major = SCSI_GENERIC_MAJOR; sprintf(node->dev_name, "sg#%04lx", id); break; } *tail = node; tail = &node->next; info->ndev++; info->host = dev->host; } } } *tail = NULL; if (info->ndev == 0) { printk(KERN_INFO "nsp_cs: no SCSI devices found\n"); } /* 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); } printk("\n"); link->state &= ~DEV_CONFIG_PENDING; return;cs_failed: cs_error(link->handle, last_fn, last_ret); nsp_cs_release((u_long)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(u_long arg){ dev_link_t *link = (dev_link_t *)arg; DEBUG(0, __FUNCTION__ "(0x%p)\n", link); /* * If the device is currently in use, we won't release until it * is actually closed. */ if (link->open) { DEBUG(1, "nsp_cs: release postponed, '%s' still open\n", link->dev->dev_name); link->state |= DEV_STALE_CONFIG; return; } /* Unlink the device chain */ scsi_unregister_module(MODULE_SCSI_HA, &driver_template); link->dev = NULL; if (link->win) { 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 (link->state & DEV_STALE_LINK) { nsp_cs_detach(link); }} /* 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; DEBUG(1, __FUNCTION__ "(0x%06x)\n", event); switch (event) { case CS_EVENT_CARD_REMOVAL: DEBUG(0, " event: remove\n"); link->state &= ~DEV_PRESENT; if (link->state & DEV_CONFIG) { ((scsi_info_t *)link->priv)->stop = 1; mod_timer(&link->release, jiffies + HZ/20); } break; case CS_EVENT_CARD_INSERTION: DEBUG(0, " event: insert\n"); link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; info->bus = args->bus; nsp_cs_config(link); break; case CS_EVENT_PM_SUSPEND: link->state |= DEV_SUSPEND; /* Fall through... */ case CS_EVENT_RESET_PHYSICAL: /* Mark the device as stopped, to block IO until later */ info->stop = 1; if (link->state & DEV_CONFIG) { CardServices(ReleaseConfiguration, link->handle); } break; case CS_EVENT_PM_RESUME: link->state &= ~DEV_SUSPEND; /* Fall through... */ case CS_EVENT_CARD_RESET: DEBUG(0, " event: reset\n"); if (link->state & DEV_CONFIG) { Scsi_Cmnd tmp; CardServices(RequestConfiguration, link->handle, &link->conf); tmp.host = info->host; nsp_eh_host_reset(&tmp); } info->stop = 0; break; default: DEBUG(0, " event: unknown\n"); break; } DEBUG(0, __FUNCTION__ " end\n"); return 0;} /* nsp_cs_event *//*======================================================================* * module entry point *====================================================================*/static int __init nsp_cs_init(void){ servinfo_t serv; DEBUG(0, __FUNCTION__ "() in\n"); DEBUG(0, "%s\n", version); CardServices(GetCardServicesInfo, &serv); if (serv.Revision != CS_RELEASE_CODE) { printk(KERN_DEBUG "nsp_cs: Card Services release " "does not match!\n"); return -1; } register_pcmcia_driver(&dev_info, &nsp_cs_attach, &nsp_cs_detach); DEBUG(0, __FUNCTION__ "() out\n"); return 0;}static void __exit nsp_cs_cleanup(void){ DEBUG(0, __FUNCTION__ "() unloading\n"); unregister_pcmcia_driver(&dev_info); while (dev_list != NULL) { if (dev_list->state & DEV_CONFIG) { nsp_cs_release((u_long)dev_list); } nsp_cs_detach(dev_list); }}module_init(nsp_cs_init);module_exit(nsp_cs_cleanup);/* * * *//* end */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -