⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 nsp_cs.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 4 页
字号:
	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 + -