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

📄 ds.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	 * pseudo multi-function card, we need to unbind	 * all devices	 */	did = p_dev->dev.driver_data;	if (did && (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) &&	    (p_dev->socket->device_count != 0) &&	    (p_dev->device_no == 0))		pcmcia_card_remove(p_dev->socket, p_dev);	/* detach the "instance" */	if (!p_drv)		return 0;	if (p_drv->remove)	       	p_drv->remove(p_dev);	p_dev->dev_node = NULL;	/* check for proper unloading */	if (p_dev->_irq || p_dev->_io || p_dev->_locked)		printk(KERN_INFO "pcmcia: driver %s did not release config properly\n",		       p_drv->drv.name);	for (i = 0; i < MAX_WIN; i++)		if (p_dev->_win & CLIENT_WIN_REQ(i))			printk(KERN_INFO "pcmcia: driver %s did not release windows properly\n",			       p_drv->drv.name);	/* references from pcmcia_probe_device */	pcmcia_put_dev(p_dev);	module_put(p_drv->owner);	return 0;}/* * pcmcia_device_query -- determine information about a pcmcia device */static int pcmcia_device_query(struct pcmcia_device *p_dev){	cistpl_manfid_t manf_id;	cistpl_funcid_t func_id;	cistpl_vers_1_t	*vers1;	unsigned int i;	vers1 = kmalloc(sizeof(*vers1), GFP_KERNEL);	if (!vers1)		return -ENOMEM;	if (!pccard_read_tuple(p_dev->socket, p_dev->func,			       CISTPL_MANFID, &manf_id)) {		p_dev->manf_id = manf_id.manf;		p_dev->card_id = manf_id.card;		p_dev->has_manf_id = 1;		p_dev->has_card_id = 1;	}	if (!pccard_read_tuple(p_dev->socket, p_dev->func,			       CISTPL_FUNCID, &func_id)) {		p_dev->func_id = func_id.func;		p_dev->has_func_id = 1;	} else {		/* rule of thumb: cards with no FUNCID, but with		 * common memory device geometry information, are		 * probably memory cards (from pcmcia-cs) */		cistpl_device_geo_t *devgeo;		devgeo = kmalloc(sizeof(*devgeo), GFP_KERNEL);		if (!devgeo) {			kfree(vers1);			return -ENOMEM;		}		if (!pccard_read_tuple(p_dev->socket, p_dev->func,				      CISTPL_DEVICE_GEO, devgeo)) {			ds_dbg(0, "mem device geometry probably means "			       "FUNCID_MEMORY\n");			p_dev->func_id = CISTPL_FUNCID_MEMORY;			p_dev->has_func_id = 1;		}		kfree(devgeo);	}	if (!pccard_read_tuple(p_dev->socket, p_dev->func, CISTPL_VERS_1,			       vers1)) {		for (i=0; i < vers1->ns; i++) {			char *tmp;			unsigned int length;			tmp = vers1->str + vers1->ofs[i];			length = strlen(tmp) + 1;			if ((length < 2) || (length > 255))				continue;			p_dev->prod_id[i] = kmalloc(sizeof(char) * length,						    GFP_KERNEL);			if (!p_dev->prod_id[i])				continue;			p_dev->prod_id[i] = strncpy(p_dev->prod_id[i],						    tmp, length);		}	}	kfree(vers1);	return 0;}/* device_add_lock is needed to avoid double registration by cardmgr and kernel. * Serializes pcmcia_device_add; will most likely be removed in future. * * While it has the caveat that adding new PCMCIA devices inside(!) device_register() * won't work, this doesn't matter much at the moment: the driver core doesn't * support it either. */static DEFINE_MUTEX(device_add_lock);struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int function){	struct pcmcia_device *p_dev, *tmp_dev;	unsigned long flags;	int bus_id_len;	s = pcmcia_get_socket(s);	if (!s)		return NULL;	mutex_lock(&device_add_lock);	ds_dbg(3, "adding device to %d, function %d\n", s->sock, function);	/* max of 4 devices per card */	if (s->device_count == 4)		goto err_put;	p_dev = kzalloc(sizeof(struct pcmcia_device), GFP_KERNEL);	if (!p_dev)		goto err_put;	p_dev->socket = s;	p_dev->device_no = (s->device_count++);	p_dev->func   = function;	p_dev->dev.bus = &pcmcia_bus_type;	p_dev->dev.parent = s->dev.parent;	p_dev->dev.release = pcmcia_release_dev;	/* by default don't allow DMA */	p_dev->dma_mask = DMA_MASK_NONE;	p_dev->dev.dma_mask = &p_dev->dma_mask;	bus_id_len = sprintf (p_dev->dev.bus_id, "%d.%d", p_dev->socket->sock, p_dev->device_no);	p_dev->devname = kmalloc(6 + bus_id_len + 1, GFP_KERNEL);	if (!p_dev->devname)		goto err_free;	sprintf (p_dev->devname, "pcmcia%s", p_dev->dev.bus_id);	ds_dbg(3, "devname is %s\n", p_dev->devname);	spin_lock_irqsave(&pcmcia_dev_list_lock, flags);	/*	 * p_dev->function_config must be the same for all card functions.	 * Note that this is serialized by the device_add_lock, so that	 * only one such struct will be created.	 */        list_for_each_entry(tmp_dev, &s->devices_list, socket_device_list)                if (p_dev->func == tmp_dev->func) {			p_dev->function_config = tmp_dev->function_config;			kref_get(&p_dev->function_config->ref);		}	/* Add to the list in pcmcia_bus_socket */	list_add(&p_dev->socket_device_list, &s->devices_list);	spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);	if (!p_dev->function_config) {		ds_dbg(3, "creating config_t for %s\n", p_dev->dev.bus_id);		p_dev->function_config = kzalloc(sizeof(struct config_t),						 GFP_KERNEL);		if (!p_dev->function_config)			goto err_unreg;		kref_init(&p_dev->function_config->ref);	}	printk(KERN_NOTICE "pcmcia: registering new device %s\n",	       p_dev->devname);	pcmcia_device_query(p_dev);	if (device_register(&p_dev->dev))		goto err_unreg;	mutex_unlock(&device_add_lock);	return p_dev; err_unreg:	spin_lock_irqsave(&pcmcia_dev_list_lock, flags);	list_del(&p_dev->socket_device_list);	spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); err_free:	kfree(p_dev->devname);	kfree(p_dev);	s->device_count--; err_put:	mutex_unlock(&device_add_lock);	pcmcia_put_socket(s);	return NULL;}static int pcmcia_card_add(struct pcmcia_socket *s){	cisinfo_t cisinfo;	cistpl_longlink_mfc_t mfc;	unsigned int no_funcs, i;	int ret = 0;	if (!(s->resource_setup_done)) {		ds_dbg(3, "no resources available, delaying card_add\n");		return -EAGAIN; /* try again, but later... */	}	if (pcmcia_validate_mem(s)) {		ds_dbg(3, "validating mem resources failed, "		       "delaying card_add\n");		return -EAGAIN; /* try again, but later... */	}	ret = pccard_validate_cis(s, BIND_FN_ALL, &cisinfo);	if (ret || !cisinfo.Chains) {		ds_dbg(0, "invalid CIS or invalid resources\n");		return -ENODEV;	}	if (!pccard_read_tuple(s, BIND_FN_ALL, CISTPL_LONGLINK_MFC, &mfc))		no_funcs = mfc.nfn;	else		no_funcs = 1;	s->functions = no_funcs;	for (i=0; i < no_funcs; i++)		pcmcia_device_add(s, i);	return (ret);}static void pcmcia_delayed_add_device(struct work_struct *work){	struct pcmcia_socket *s =		container_of(work, struct pcmcia_socket, device_add);	ds_dbg(1, "adding additional device to %d\n", s->sock);	pcmcia_device_add(s, s->pcmcia_state.mfc_pfc);	s->pcmcia_state.device_add_pending = 0;	s->pcmcia_state.mfc_pfc = 0;}static int pcmcia_requery(struct device *dev, void * _data){	struct pcmcia_device *p_dev = to_pcmcia_dev(dev);	if (!p_dev->dev.driver) {		ds_dbg(1, "update device information for %s\n",		       p_dev->dev.bus_id);		pcmcia_device_query(p_dev);	}	return 0;}static void pcmcia_bus_rescan(struct pcmcia_socket *skt, int new_cis){	int no_devices = 0;	int ret = 0;	unsigned long flags;	/* must be called with skt_mutex held */	ds_dbg(0, "re-scanning socket %d\n", skt->sock);	spin_lock_irqsave(&pcmcia_dev_list_lock, flags);	if (list_empty(&skt->devices_list))		no_devices = 1;	spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);	/* If this is because of a CIS override, start over */	if (new_cis && !no_devices)		pcmcia_card_remove(skt, NULL);	/* if no devices were added for this socket yet because of	 * missing resource information or other trouble, we need to	 * do this now. */	if (no_devices || new_cis) {		ret = pcmcia_card_add(skt);		if (ret)			return;	}	/* some device information might have changed because of a CIS	 * update or because we can finally read it correctly... so	 * determine it again, overwriting old values if necessary. */	bus_for_each_dev(&pcmcia_bus_type, NULL, NULL, pcmcia_requery);	/* we re-scan all devices, not just the ones connected to this	 * socket. This does not matter, though. */	ret = bus_rescan_devices(&pcmcia_bus_type);	if (ret)		printk(KERN_INFO "pcmcia: bus_rescan_devices failed\n");}#ifdef CONFIG_PCMCIA_LOAD_CIS/** * pcmcia_load_firmware - load CIS from userspace if device-provided is broken * @dev: the pcmcia device which needs a CIS override * @filename: requested filename in /lib/firmware/ * * This uses the in-kernel firmware loading mechanism to use a "fake CIS" if * the one provided by the card is broken. The firmware files reside in * /lib/firmware/ in userspace. */static int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename){	struct pcmcia_socket *s = dev->socket;	const struct firmware *fw;	char path[20];	int ret = -ENOMEM;	int no_funcs;	int old_funcs;	cisdump_t *cis;	cistpl_longlink_mfc_t mfc;	if (!filename)		return -EINVAL;	ds_dbg(1, "trying to load CIS file %s\n", filename);	if (strlen(filename) > 14) {		printk(KERN_WARNING "pcmcia: CIS filename is too long\n");		return -EINVAL;	}	snprintf(path, 20, "%s", filename);	if (request_firmware(&fw, path, &dev->dev) == 0) {		if (fw->size >= CISTPL_MAX_CIS_SIZE) {			ret = -EINVAL;			printk(KERN_ERR "pcmcia: CIS override is too big\n");			goto release;		}		cis = kzalloc(sizeof(cisdump_t), GFP_KERNEL);		if (!cis) {			ret = -ENOMEM;			goto release;		}		cis->Length = fw->size + 1;		memcpy(cis->Data, fw->data, fw->size);		if (!pcmcia_replace_cis(s, cis))			ret = 0;		else {			printk(KERN_ERR "pcmcia: CIS override failed\n");			goto release;		}		/* update information */		pcmcia_device_query(dev);		/* does this cis override add or remove functions? */		old_funcs = s->functions;		if (!pccard_read_tuple(s, BIND_FN_ALL, CISTPL_LONGLINK_MFC, &mfc))			no_funcs = mfc.nfn;		else			no_funcs = 1;		s->functions = no_funcs;		if (old_funcs > no_funcs)			pcmcia_card_remove(s, dev);		else if (no_funcs > old_funcs)			pcmcia_add_device_later(s, 1);	} release:	release_firmware(fw);	return (ret);}#else /* !CONFIG_PCMCIA_LOAD_CIS */static inline int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename){	return -ENODEV;}#endifstatic inline int pcmcia_devmatch(struct pcmcia_device *dev,				  struct pcmcia_device_id *did){	if (did->match_flags & PCMCIA_DEV_ID_MATCH_MANF_ID) {		if ((!dev->has_manf_id) || (dev->manf_id != did->manf_id))			return 0;	}	if (did->match_flags & PCMCIA_DEV_ID_MATCH_CARD_ID) {		if ((!dev->has_card_id) || (dev->card_id != did->card_id))			return 0;	}	if (did->match_flags & PCMCIA_DEV_ID_MATCH_FUNCTION) {		if (dev->func != did->function)			return 0;	}	if (did->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID1) {		if (!dev->prod_id[0])			return 0;		if (strcmp(did->prod_id[0], dev->prod_id[0]))			return 0;	}	if (did->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID2) {		if (!dev->prod_id[1])			return 0;		if (strcmp(did->prod_id[1], dev->prod_id[1]))			return 0;	}	if (did->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID3) {		if (!dev->prod_id[2])			return 0;		if (strcmp(did->prod_id[2], dev->prod_id[2]))			return 0;	}	if (did->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID4) {		if (!dev->prod_id[3])			return 0;		if (strcmp(did->prod_id[3], dev->prod_id[3]))			return 0;	}	if (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) {		if (dev->device_no != did->device_no)			return 0;	}	if (did->match_flags & PCMCIA_DEV_ID_MATCH_FUNC_ID) {		if ((!dev->has_func_id) || (dev->func_id != did->func_id))			return 0;		/* if this is a pseudo-multi-function device,		 * we need explicit matches */		if (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO)			return 0;		if (dev->device_no)			return 0;		/* also, FUNC_ID matching needs to be activated by userspace		 * after it has re-checked that there is no possible module		 * with a prod_id/manf_id/card_id match.		 */		ds_dbg(0, "skipping FUNC_ID match for %s until userspace "		       "interaction\n", dev->dev.bus_id);		if (!dev->allow_func_id_match)			return 0;	}	if (did->match_flags & PCMCIA_DEV_ID_MATCH_FAKE_CIS) {		ds_dbg(0, "device %s needs a fake CIS\n", dev->dev.bus_id);		if (!dev->socket->fake_cis)			pcmcia_load_firmware(dev, did->cisfile);		if (!dev->socket->fake_cis)			return 0;	}	if (did->match_flags & PCMCIA_DEV_ID_MATCH_ANONYMOUS) {		int i;		for (i=0; i<4; i++)			if (dev->prod_id[i])				return 0;		if (dev->has_manf_id || dev->has_card_id || dev->has_func_id)			return 0;	}	dev->dev.driver_data = (void *) did;	return 1;}static int pcmcia_bus_match(struct device * dev, struct device_driver * drv) {	struct pcmcia_device * p_dev = to_pcmcia_dev(dev);	struct pcmcia_driver * p_drv = to_pcmcia_drv(drv);	struct pcmcia_device_id *did = p_drv->id_table;	struct pcmcia_dynid *dynid;	/* match dynamic devices first */	spin_lock(&p_drv->dynids.lock);	list_for_each_entry(dynid, &p_drv->dynids.list, node) {		ds_dbg(3, "trying to match %s to %s\n", dev->bus_id,		       drv->name);		if (pcmcia_devmatch(p_dev, &dynid->id)) {			ds_dbg(0, "matched %s to %s\n", dev->bus_id,			       drv->name);			spin_unlock(&p_drv->dynids.lock);			return 1;		}	}	spin_unlock(&p_drv->dynids.lock);#ifdef CONFIG_PCMCIA_IOCTL	/* matching by cardmgr */	if (p_dev->cardmgr == p_drv) {		ds_dbg(0, "cardmgr matched %s to %s\n", dev->bus_id,		       drv->name);		return 1;	}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -