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

📄 ds.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
#endif	while (did && did->match_flags) {		ds_dbg(3, "trying to match %s to %s\n", dev->bus_id,		       drv->name);		if (pcmcia_devmatch(p_dev, did)) {			ds_dbg(0, "matched %s to %s\n", dev->bus_id,			       drv->name);			return 1;		}		did++;	}	return 0;}#ifdef CONFIG_HOTPLUGstatic int pcmcia_bus_uevent(struct device *dev, struct kobj_uevent_env *env){	struct pcmcia_device *p_dev;	int i;	u32 hash[4] = { 0, 0, 0, 0};	if (!dev)		return -ENODEV;	p_dev = to_pcmcia_dev(dev);	/* calculate hashes */	for (i=0; i<4; i++) {		if (!p_dev->prod_id[i])			continue;		hash[i] = crc32(0, p_dev->prod_id[i], strlen(p_dev->prod_id[i]));	}	if (add_uevent_var(env, "SOCKET_NO=%u", p_dev->socket->sock))		return -ENOMEM;	if (add_uevent_var(env, "DEVICE_NO=%02X", p_dev->device_no))		return -ENOMEM;	if (add_uevent_var(env, "MODALIAS=pcmcia:m%04Xc%04Xf%02Xfn%02Xpfn%02X"			   "pa%08Xpb%08Xpc%08Xpd%08X",			   p_dev->has_manf_id ? p_dev->manf_id : 0,			   p_dev->has_card_id ? p_dev->card_id : 0,			   p_dev->has_func_id ? p_dev->func_id : 0,			   p_dev->func,			   p_dev->device_no,			   hash[0],			   hash[1],			   hash[2],			   hash[3]))		return -ENOMEM;	return 0;}#elsestatic int pcmcia_bus_uevent(struct device *dev, struct kobj_uevent_env *env){	return -ENODEV;}#endif/************************ runtime PM support ***************************/static int pcmcia_dev_suspend(struct device *dev, pm_message_t state);static int pcmcia_dev_resume(struct device *dev);static int runtime_suspend(struct device *dev){	int rc;	down(&dev->sem);	rc = pcmcia_dev_suspend(dev, PMSG_SUSPEND);	up(&dev->sem);	if (!rc)		dev->power.power_state.event = PM_EVENT_SUSPEND;	return rc;}static void runtime_resume(struct device *dev){	int rc;	down(&dev->sem);	rc = pcmcia_dev_resume(dev);	up(&dev->sem);	if (!rc)		dev->power.power_state.event = PM_EVENT_ON;}/************************ per-device sysfs output ***************************/#define pcmcia_device_attr(field, test, format)				\static ssize_t field##_show (struct device *dev, struct device_attribute *attr, char *buf)		\{									\	struct pcmcia_device *p_dev = to_pcmcia_dev(dev);		\	return p_dev->test ? sprintf (buf, format, p_dev->field) : -ENODEV; \}#define pcmcia_device_stringattr(name, field)					\static ssize_t name##_show (struct device *dev, struct device_attribute *attr, char *buf)		\{									\	struct pcmcia_device *p_dev = to_pcmcia_dev(dev);		\	return p_dev->field ? sprintf (buf, "%s\n", p_dev->field) : -ENODEV; \}pcmcia_device_attr(func, socket, "0x%02x\n");pcmcia_device_attr(func_id, has_func_id, "0x%02x\n");pcmcia_device_attr(manf_id, has_manf_id, "0x%04x\n");pcmcia_device_attr(card_id, has_card_id, "0x%04x\n");pcmcia_device_stringattr(prod_id1, prod_id[0]);pcmcia_device_stringattr(prod_id2, prod_id[1]);pcmcia_device_stringattr(prod_id3, prod_id[2]);pcmcia_device_stringattr(prod_id4, prod_id[3]);static ssize_t pcmcia_show_pm_state(struct device *dev, struct device_attribute *attr, char *buf){	struct pcmcia_device *p_dev = to_pcmcia_dev(dev);	if (p_dev->suspended)		return sprintf(buf, "off\n");	else		return sprintf(buf, "on\n");}static ssize_t pcmcia_store_pm_state(struct device *dev, struct device_attribute *attr,				     const char *buf, size_t count){	struct pcmcia_device *p_dev = to_pcmcia_dev(dev);	int ret = 0;        if (!count)                return -EINVAL;	if ((!p_dev->suspended) && !strncmp(buf, "off", 3))		ret = runtime_suspend(dev);	else if (p_dev->suspended && !strncmp(buf, "on", 2))		runtime_resume(dev);	return ret ? ret : count;}static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf){	struct pcmcia_device *p_dev = to_pcmcia_dev(dev);	int i;	u32 hash[4] = { 0, 0, 0, 0};	/* calculate hashes */	for (i=0; i<4; i++) {		if (!p_dev->prod_id[i])			continue;		hash[i] = crc32(0,p_dev->prod_id[i],strlen(p_dev->prod_id[i]));	}	return sprintf(buf, "pcmcia:m%04Xc%04Xf%02Xfn%02Xpfn%02X"				"pa%08Xpb%08Xpc%08Xpd%08X\n",				p_dev->has_manf_id ? p_dev->manf_id : 0,				p_dev->has_card_id ? p_dev->card_id : 0,				p_dev->has_func_id ? p_dev->func_id : 0,				p_dev->func, p_dev->device_no,				hash[0], hash[1], hash[2], hash[3]);}static ssize_t pcmcia_store_allow_func_id_match(struct device *dev,		struct device_attribute *attr, const char *buf, size_t count){	struct pcmcia_device *p_dev = to_pcmcia_dev(dev);	int ret;	if (!count)		return -EINVAL;	mutex_lock(&p_dev->socket->skt_mutex);	p_dev->allow_func_id_match = 1;	mutex_unlock(&p_dev->socket->skt_mutex);	ret = bus_rescan_devices(&pcmcia_bus_type);	if (ret)		printk(KERN_INFO "pcmcia: bus_rescan_devices failed after "		       "allowing func_id matches\n");	return count;}static struct device_attribute pcmcia_dev_attrs[] = {	__ATTR(function, 0444, func_show, NULL),	__ATTR(pm_state, 0644, pcmcia_show_pm_state, pcmcia_store_pm_state),	__ATTR_RO(func_id),	__ATTR_RO(manf_id),	__ATTR_RO(card_id),	__ATTR_RO(prod_id1),	__ATTR_RO(prod_id2),	__ATTR_RO(prod_id3),	__ATTR_RO(prod_id4),	__ATTR_RO(modalias),	__ATTR(allow_func_id_match, 0200, NULL, pcmcia_store_allow_func_id_match),	__ATTR_NULL,};/* PM support, also needed for reset */static int pcmcia_dev_suspend(struct device * dev, pm_message_t state){	struct pcmcia_device *p_dev = to_pcmcia_dev(dev);	struct pcmcia_driver *p_drv = NULL;	int ret = 0;	ds_dbg(2, "suspending %s\n", dev->bus_id);	if (dev->driver)		p_drv = to_pcmcia_drv(dev->driver);	if (!p_drv)		goto out;	if (p_drv->suspend) {		ret = p_drv->suspend(p_dev);		if (ret) {			printk(KERN_ERR "pcmcia: device %s (driver %s) did "			       "not want to go to sleep (%d)\n",			       p_dev->devname, p_drv->drv.name, ret);			goto out;		}	}	if (p_dev->device_no == p_dev->func) {		ds_dbg(2, "releasing configuration for %s\n", dev->bus_id);		pcmcia_release_configuration(p_dev);	} out:	if (!ret)		p_dev->suspended = 1;	return ret;}static int pcmcia_dev_resume(struct device * dev){	struct pcmcia_device *p_dev = to_pcmcia_dev(dev);        struct pcmcia_driver *p_drv = NULL;	int ret = 0;	ds_dbg(2, "resuming %s\n", dev->bus_id);	if (dev->driver)		p_drv = to_pcmcia_drv(dev->driver);	if (!p_drv)		goto out;	if (p_dev->device_no == p_dev->func) {		ds_dbg(2, "requesting configuration for %s\n", dev->bus_id);		ret = pcmcia_request_configuration(p_dev, &p_dev->conf);		if (ret)			goto out;	}	if (p_drv->resume)		ret = p_drv->resume(p_dev); out:	if (!ret)		p_dev->suspended = 0;	return ret;}static int pcmcia_bus_suspend_callback(struct device *dev, void * _data){	struct pcmcia_socket *skt = _data;	struct pcmcia_device *p_dev = to_pcmcia_dev(dev);	if (p_dev->socket != skt || p_dev->suspended)		return 0;	return runtime_suspend(dev);}static int pcmcia_bus_resume_callback(struct device *dev, void * _data){	struct pcmcia_socket *skt = _data;	struct pcmcia_device *p_dev = to_pcmcia_dev(dev);	if (p_dev->socket != skt || !p_dev->suspended)		return 0;	runtime_resume(dev);	return 0;}static int pcmcia_bus_resume(struct pcmcia_socket *skt){	ds_dbg(2, "resuming socket %d\n", skt->sock);	bus_for_each_dev(&pcmcia_bus_type, NULL, skt, pcmcia_bus_resume_callback);	return 0;}static int pcmcia_bus_suspend(struct pcmcia_socket *skt){	ds_dbg(2, "suspending socket %d\n", skt->sock);	if (bus_for_each_dev(&pcmcia_bus_type, NULL, skt,			     pcmcia_bus_suspend_callback)) {		pcmcia_bus_resume(skt);		return -EIO;	}	return 0;}/*======================================================================    The card status event handler.    ======================================================================*//* Normally, the event is passed to individual drivers after * informing userspace. Only for CS_EVENT_CARD_REMOVAL this * is inversed to maintain historic compatibility. */static int ds_event(struct pcmcia_socket *skt, event_t event, int priority){	struct pcmcia_socket *s = pcmcia_get_socket(skt);	if (!s) {		printk(KERN_ERR "PCMCIA obtaining reference to socket %p " \			"failed, event 0x%x lost!\n", skt, event);		return -ENODEV;	}	ds_dbg(1, "ds_event(0x%06x, %d, 0x%p)\n",	       event, priority, skt);	switch (event) {	case CS_EVENT_CARD_REMOVAL:		s->pcmcia_state.present = 0;		pcmcia_card_remove(skt, NULL);		handle_event(skt, event);		break;	case CS_EVENT_CARD_INSERTION:		s->pcmcia_state.present = 1;		pcmcia_card_add(skt);		handle_event(skt, event);		break;	case CS_EVENT_EJECTION_REQUEST:		break;	case CS_EVENT_PM_SUSPEND:	case CS_EVENT_PM_RESUME:	case CS_EVENT_RESET_PHYSICAL:	case CS_EVENT_CARD_RESET:	default:		handle_event(skt, event);		break;    }    pcmcia_put_socket(s);    return 0;} /* ds_event */struct pcmcia_device * pcmcia_dev_present(struct pcmcia_device *_p_dev){	struct pcmcia_device *p_dev;	struct pcmcia_device *ret = NULL;	p_dev = pcmcia_get_dev(_p_dev);	if (!p_dev)		return NULL;	if (!p_dev->socket->pcmcia_state.present)		goto out;	if (p_dev->_removed)		goto out;	if (p_dev->suspended)		goto out;	ret = p_dev; out:	pcmcia_put_dev(p_dev);	return ret;}EXPORT_SYMBOL(pcmcia_dev_present);static struct pcmcia_callback pcmcia_bus_callback = {	.owner = THIS_MODULE,	.event = ds_event,	.requery = pcmcia_bus_rescan,	.suspend = pcmcia_bus_suspend,	.resume = pcmcia_bus_resume,};static int __devinit pcmcia_bus_add_socket(struct device *dev,					   struct class_interface *class_intf){	struct pcmcia_socket *socket = dev_get_drvdata(dev);	int ret;	socket = pcmcia_get_socket(socket);	if (!socket) {		printk(KERN_ERR "PCMCIA obtaining reference to socket %p failed\n", socket);		return -ENODEV;	}	/*	 * Ugly. But we want to wait for the socket threads to have started up.	 * We really should let the drivers themselves drive some of this..	 */	msleep(250);#ifdef CONFIG_PCMCIA_IOCTL	init_waitqueue_head(&socket->queue);#endif	INIT_LIST_HEAD(&socket->devices_list);	INIT_WORK(&socket->device_add, pcmcia_delayed_add_device);	memset(&socket->pcmcia_state, 0, sizeof(u8));	socket->device_count = 0;	ret = pccard_register_pcmcia(socket, &pcmcia_bus_callback);	if (ret) {		printk(KERN_ERR "PCMCIA registration PCCard core failed for socket %p\n", socket);		pcmcia_put_socket(socket);		return (ret);	}	return 0;}static void pcmcia_bus_remove_socket(struct device *dev,				     struct class_interface *class_intf){	struct pcmcia_socket *socket = dev_get_drvdata(dev);	if (!socket)		return;	socket->pcmcia_state.dead = 1;	pccard_register_pcmcia(socket, NULL);	/* unregister any unbound devices */	mutex_lock(&socket->skt_mutex);	pcmcia_card_remove(socket, NULL);	mutex_unlock(&socket->skt_mutex);	pcmcia_put_socket(socket);	return;}/* the pcmcia_bus_interface is used to handle pcmcia socket devices */static struct class_interface pcmcia_bus_interface = {	.class = &pcmcia_socket_class,	.add_dev = &pcmcia_bus_add_socket,	.remove_dev = &pcmcia_bus_remove_socket,};struct bus_type pcmcia_bus_type = {	.name = "pcmcia",	.uevent = pcmcia_bus_uevent,	.match = pcmcia_bus_match,	.dev_attrs = pcmcia_dev_attrs,	.probe = pcmcia_device_probe,	.remove = pcmcia_device_remove,	.suspend = pcmcia_dev_suspend,	.resume = pcmcia_dev_resume,};static int __init init_pcmcia_bus(void){	int ret;	spin_lock_init(&pcmcia_dev_list_lock);	ret = bus_register(&pcmcia_bus_type);	if (ret < 0) {		printk(KERN_WARNING "pcmcia: bus_register error: %d\n", ret);		return ret;	}	ret = class_interface_register(&pcmcia_bus_interface);	if (ret < 0) {		printk(KERN_WARNING			"pcmcia: class_interface_register error: %d\n", ret);		bus_unregister(&pcmcia_bus_type);		return ret;	}	pcmcia_setup_ioctl();	return 0;}fs_initcall(init_pcmcia_bus); /* one level after subsys_initcall so that 			       * pcmcia_socket_class is already registered */static void __exit exit_pcmcia_bus(void){	pcmcia_cleanup_ioctl();	class_interface_unregister(&pcmcia_bus_interface);	bus_unregister(&pcmcia_bus_type);}module_exit(exit_pcmcia_bus);MODULE_ALIAS("ds");

⌨️ 快捷键说明

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