📄 ds.c
字号:
struct pcmcia_bus_socket *s; user_info_t *user; ds_dbg(2, "ds_write(socket %d)\n", iminor(file->f_dentry->d_inode)); if (count != 4) return -EINVAL; if ((file->f_flags & O_ACCMODE) == O_RDONLY) return -EBADF; user = file->private_data; if (CHECK_USER(user)) return -EIO; s = user->socket; if (s->state & DS_SOCKET_DEAD) return -EIO; if (s->req_pending) { s->req_pending--; get_user(s->req_result, (int __user *)buf); if ((s->req_result != 0) || (s->req_pending == 0)) wake_up_interruptible(&s->request); } else return -EIO; return 4;} /* ds_write *//*====================================================================*//* No kernel lock - fine */static u_int ds_poll(struct file *file, poll_table *wait){ struct pcmcia_bus_socket *s; user_info_t *user; ds_dbg(2, "ds_poll(socket %d)\n", iminor(file->f_dentry->d_inode)); user = file->private_data; if (CHECK_USER(user)) return POLLERR; s = user->socket; /* * We don't check for a dead socket here since that * will send cardmgr into an endless spin. */ poll_wait(file, &s->queue, wait); if (!queue_empty(user)) return POLLIN | POLLRDNORM; return 0;} /* ds_poll *//*====================================================================*/static int ds_ioctl(struct inode * inode, struct file * file, u_int cmd, u_long arg){ struct pcmcia_bus_socket *s; void __user *uarg = (char __user *)arg; u_int size; int ret, err; ds_ioctl_arg_t buf; user_info_t *user; ds_dbg(2, "ds_ioctl(socket %d, %#x, %#lx)\n", iminor(inode), cmd, arg); user = file->private_data; if (CHECK_USER(user)) return -EIO; s = user->socket; if (s->state & DS_SOCKET_DEAD) return -EIO; size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT; if (size > sizeof(ds_ioctl_arg_t)) return -EINVAL; /* Permission check */ if (!(cmd & IOC_OUT) && !capable(CAP_SYS_ADMIN)) return -EPERM; if (cmd & IOC_IN) { err = verify_area(VERIFY_READ, uarg, size); if (err) { ds_dbg(3, "ds_ioctl(): verify_read = %d\n", err); return err; } } if (cmd & IOC_OUT) { err = verify_area(VERIFY_WRITE, uarg, size); if (err) { ds_dbg(3, "ds_ioctl(): verify_write = %d\n", err); return err; } } err = ret = 0; if (cmd & IOC_IN) __copy_from_user((char *)&buf, uarg, size); switch (cmd) { case DS_ADJUST_RESOURCE_INFO: ret = pcmcia_adjust_resource_info(s->handle, &buf.adjust); break; case DS_GET_CARD_SERVICES_INFO: ret = pcmcia_get_card_services_info(&buf.servinfo); break; case DS_GET_CONFIGURATION_INFO: ret = pcmcia_get_configuration_info(s->handle, &buf.config); break; case DS_GET_FIRST_TUPLE: pcmcia_validate_mem(s->parent); ret = pcmcia_get_first_tuple(s->handle, &buf.tuple); break; case DS_GET_NEXT_TUPLE: ret = pcmcia_get_next_tuple(s->handle, &buf.tuple); break; case DS_GET_TUPLE_DATA: buf.tuple.TupleData = buf.tuple_parse.data; buf.tuple.TupleDataMax = sizeof(buf.tuple_parse.data); ret = pcmcia_get_tuple_data(s->handle, &buf.tuple); break; case DS_PARSE_TUPLE: buf.tuple.TupleData = buf.tuple_parse.data; ret = pcmcia_parse_tuple(s->handle, &buf.tuple, &buf.tuple_parse.parse); break; case DS_RESET_CARD: ret = pcmcia_reset_card(s->handle, NULL); break; case DS_GET_STATUS: ret = pcmcia_get_status(s->handle, &buf.status); break; case DS_VALIDATE_CIS: pcmcia_validate_mem(s->parent); ret = pcmcia_validate_cis(s->handle, &buf.cisinfo); break; case DS_SUSPEND_CARD: ret = pcmcia_suspend_card(s->parent); break; case DS_RESUME_CARD: ret = pcmcia_resume_card(s->parent); break; case DS_EJECT_CARD: err = pcmcia_eject_card(s->parent); break; case DS_INSERT_CARD: err = pcmcia_insert_card(s->parent); break; case DS_ACCESS_CONFIGURATION_REGISTER: if ((buf.conf_reg.Action == CS_WRITE) && !capable(CAP_SYS_ADMIN)) return -EPERM; ret = pcmcia_access_configuration_register(s->handle, &buf.conf_reg); break; case DS_GET_FIRST_REGION: ret = pcmcia_get_first_region(s->handle, &buf.region); break; case DS_GET_NEXT_REGION: ret = pcmcia_get_next_region(s->handle, &buf.region); break; case DS_GET_FIRST_WINDOW: buf.win_info.handle = (window_handle_t)s->handle; ret = pcmcia_get_first_window(&buf.win_info.handle, &buf.win_info.window); break; case DS_GET_NEXT_WINDOW: ret = pcmcia_get_next_window(&buf.win_info.handle, &buf.win_info.window); break; case DS_GET_MEM_PAGE: ret = pcmcia_get_mem_page(buf.win_info.handle, &buf.win_info.map); break; case DS_REPLACE_CIS: ret = pcmcia_replace_cis(s->handle, &buf.cisdump); break; case DS_BIND_REQUEST: if (!capable(CAP_SYS_ADMIN)) return -EPERM; err = bind_request(s, &buf.bind_info); break; case DS_GET_DEVICE_INFO: err = get_device_info(s, &buf.bind_info, 1); break; case DS_GET_NEXT_DEVICE: err = get_device_info(s, &buf.bind_info, 0); break; case DS_UNBIND_REQUEST: err = unbind_request(s, &buf.bind_info); break; case DS_BIND_MTD: if (!capable(CAP_SYS_ADMIN)) return -EPERM; err = bind_mtd(s, &buf.mtd_info); break; default: err = -EINVAL; } if ((err == 0) && (ret != CS_SUCCESS)) { ds_dbg(2, "ds_ioctl: ret = %d\n", ret); switch (ret) { case CS_BAD_SOCKET: case CS_NO_CARD: err = -ENODEV; break; case CS_BAD_ARGS: case CS_BAD_ATTRIBUTE: case CS_BAD_IRQ: case CS_BAD_TUPLE: err = -EINVAL; break; case CS_IN_USE: err = -EBUSY; break; case CS_OUT_OF_RESOURCE: err = -ENOSPC; break; case CS_NO_MORE_ITEMS: err = -ENODATA; break; case CS_UNSUPPORTED_FUNCTION: err = -ENOSYS; break; default: err = -EIO; break; } } if (cmd & IOC_OUT) __copy_to_user(uarg, (char *)&buf, size); return err;} /* ds_ioctl *//*====================================================================*/static struct file_operations ds_fops = { .owner = THIS_MODULE, .open = ds_open, .release = ds_release, .ioctl = ds_ioctl, .read = ds_read, .write = ds_write, .poll = ds_poll,};static int __devinit pcmcia_bus_add_socket(struct class_device *class_dev){ struct pcmcia_socket *socket = class_dev->class_data; client_reg_t client_reg; bind_req_t bind; struct pcmcia_bus_socket *s; int ret; s = kmalloc(sizeof(struct pcmcia_bus_socket), GFP_KERNEL); if(!s) return -ENOMEM; memset(s, 0, sizeof(struct pcmcia_bus_socket)); atomic_set(&s->refcount, 1); /* * 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); init_waitqueue_head(&s->queue); init_waitqueue_head(&s->request); /* initialize data */ INIT_WORK(&s->removal, handle_removal, s); s->parent = socket; /* Set up hotline to Card Services */ client_reg.dev_info = bind.dev_info = &dev_info; bind.Socket = socket; bind.Function = BIND_FN_ALL; ret = pcmcia_bind_device(&bind); if (ret != CS_SUCCESS) { cs_error(NULL, BindDevice, ret); kfree(s); return -EINVAL; } client_reg.Attributes = INFO_MASTER_CLIENT; client_reg.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | CS_EVENT_EJECTION_REQUEST | CS_EVENT_INSERTION_REQUEST | CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; client_reg.event_handler = &ds_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = s; ret = pcmcia_register_client(&s->handle, &client_reg); if (ret != CS_SUCCESS) { cs_error(NULL, RegisterClient, ret); kfree(s); return -EINVAL; } socket->pcmcia = s; return 0;}static void pcmcia_bus_remove_socket(struct class_device *class_dev){ struct pcmcia_socket *socket = class_dev->class_data; if (!socket || !socket->pcmcia) return; flush_scheduled_work(); pcmcia_deregister_client(socket->pcmcia->handle); socket->pcmcia->state |= DS_SOCKET_DEAD; pcmcia_put_bus_socket(socket->pcmcia); socket->pcmcia = NULL; return;}/* the pcmcia_bus_interface is used to handle pcmcia socket devices */static struct class_interface pcmcia_bus_interface = { .class = &pcmcia_socket_class, .add = &pcmcia_bus_add_socket, .remove = &pcmcia_bus_remove_socket,};struct bus_type pcmcia_bus_type = { .name = "pcmcia",};EXPORT_SYMBOL(pcmcia_bus_type);static int __init init_pcmcia_bus(void){ int i; bus_register(&pcmcia_bus_type); class_interface_register(&pcmcia_bus_interface); /* Set up character device for user mode clients */ i = register_chrdev(0, "pcmcia", &ds_fops); if (i == -EBUSY) printk(KERN_NOTICE "unable to find a free device # for " "Driver Services\n"); else major_dev = i;#ifdef CONFIG_PROC_FS proc_pccard = proc_mkdir("pccard", proc_bus); if (proc_pccard) create_proc_read_entry("drivers",0,proc_pccard,proc_read_drivers,NULL);#endif 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){ class_interface_unregister(&pcmcia_bus_interface);#ifdef CONFIG_PROC_FS if (proc_pccard) { remove_proc_entry("drivers", proc_pccard); remove_proc_entry("pccard", proc_bus); }#endif if (major_dev != -1) unregister_chrdev(major_dev, "pcmcia"); bus_unregister(&pcmcia_bus_type);}module_exit(exit_pcmcia_bus);/* helpers for backwards-compatible functions */static struct pcmcia_bus_socket * get_socket_info_by_nr(unsigned int nr){ struct pcmcia_socket * s = pcmcia_get_socket_by_nr(nr); if (s && s->pcmcia) return s->pcmcia; else return NULL;}/* backwards-compatible accessing of driver --- by name! */struct cmp_data { void *dev_info; struct pcmcia_driver *drv;};static int cmp_drv_callback(struct device_driver *drv, void *data){ struct cmp_data *cmp = data; if (strncmp((char *)cmp->dev_info, (char *)drv->name, DEV_NAME_LEN) == 0) { cmp->drv = container_of(drv, struct pcmcia_driver, drv); return -EINVAL; } return 0;}static struct pcmcia_driver * get_pcmcia_driver (dev_info_t *dev_info){ int ret; struct cmp_data cmp = { .dev_info = dev_info, }; ret = bus_for_each_drv(&pcmcia_bus_type, NULL, &cmp, cmp_drv_callback); if (ret) return cmp.drv; return NULL;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -