📄 ds.c
字号:
#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 + -