📄 ds.c
字号:
if (node == bind_info->next) break; if (node == NULL) return -ENODEV; strncpy(bind_info->name, node->dev_name, DEV_NAME_LEN); bind_info->name[DEV_NAME_LEN-1] = '\0'; bind_info->major = node->major; bind_info->minor = node->minor; bind_info->next = node->next; return 0;} /* get_device_info *//*====================================================================*/static int unbind_request(int i, bind_info_t *bind_info){ socket_info_t *s = &socket_table[i]; socket_bind_t **b, *c; DEBUG(2, "unbind_request(%d, '%s')\n", i, (char *)bind_info->dev_info); for (b = &s->bind; *b; b = &(*b)->next) if ((strcmp((char *)(*b)->driver->dev_info, (char *)bind_info->dev_info) == 0) && ((*b)->function == bind_info->function)) break; if (*b == NULL) return -ENODEV; c = *b; c->driver->use_count--; if (c->driver->detach) { if (c->instance) c->driver->detach(c->instance); } else { if (c->driver->use_count == 0) { driver_info_t **d; for (d = &root_driver; *d; d = &((*d)->next)) if (c->driver == *d) break; *d = (*d)->next; kfree(c->driver); } } *b = c->next; kfree(c); return 0;} /* unbind_request *//*====================================================================== The user-mode PC Card device interface======================================================================*/static int ds_open(struct inode *inode, struct file *file){ socket_t i = MINOR(inode->i_rdev); socket_info_t *s; user_info_t *user; DEBUG(0, "ds_open(socket %d)\n", i); if ((i >= sockets) || (sockets == 0)) return -ENODEV; s = &socket_table[i]; if ((file->f_flags & O_ACCMODE) != O_RDONLY) { if (s->state & SOCKET_BUSY) return -EBUSY; else s->state |= SOCKET_BUSY; } user = kmalloc(sizeof(user_info_t), GFP_KERNEL); if (!user) return -ENOMEM; user->event_tail = user->event_head = 0; user->next = s->user; user->user_magic = USER_MAGIC; s->user = user; file->private_data = user; if (s->state & SOCKET_PRESENT) queue_event(user, CS_EVENT_CARD_INSERTION); return 0;} /* ds_open *//*====================================================================*/static int ds_release(struct inode *inode, struct file *file){ socket_t i = MINOR(inode->i_rdev); socket_info_t *s; user_info_t *user, **link; DEBUG(0, "ds_release(socket %d)\n", i); if ((i >= sockets) || (sockets == 0)) return 0; lock_kernel(); s = &socket_table[i]; user = file->private_data; if (CHECK_USER(user)) goto out; /* Unlink user data structure */ if ((file->f_flags & O_ACCMODE) != O_RDONLY) s->state &= ~SOCKET_BUSY; file->private_data = NULL; for (link = &s->user; *link; link = &(*link)->next) if (*link == user) break; if (link == NULL) goto out; *link = user->next; user->user_magic = 0; kfree(user);out: unlock_kernel(); return 0;} /* ds_release *//*====================================================================*/static ssize_t ds_read(struct file *file, char *buf, size_t count, loff_t *ppos){ socket_t i = MINOR(file->f_dentry->d_inode->i_rdev); socket_info_t *s; user_info_t *user; DEBUG(2, "ds_read(socket %d)\n", i); if ((i >= sockets) || (sockets == 0)) return -ENODEV; if (count < 4) return -EINVAL; s = &socket_table[i]; user = file->private_data; if (CHECK_USER(user)) return -EIO; if (queue_empty(user)) { interruptible_sleep_on(&s->queue); if (signal_pending(current)) return -EINTR; } put_user(get_queued_event(user), (int *)buf); return 4;} /* ds_read *//*====================================================================*/static ssize_t ds_write(struct file *file, const char *buf, size_t count, loff_t *ppos){ socket_t i = MINOR(file->f_dentry->d_inode->i_rdev); socket_info_t *s; user_info_t *user; DEBUG(2, "ds_write(socket %d)\n", i); if ((i >= sockets) || (sockets == 0)) return -ENODEV; if (count != 4) return -EINVAL; if ((file->f_flags & O_ACCMODE) == O_RDONLY) return -EBADF; s = &socket_table[i]; user = file->private_data; if (CHECK_USER(user)) return -EIO; if (s->req_pending) { s->req_pending--; get_user(s->req_result, (int *)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){ socket_t i = MINOR(file->f_dentry->d_inode->i_rdev); socket_info_t *s; user_info_t *user; DEBUG(2, "ds_poll(socket %d)\n", i); if ((i >= sockets) || (sockets == 0)) return POLLERR; s = &socket_table[i]; user = file->private_data; if (CHECK_USER(user)) return POLLERR; 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){ socket_t i = MINOR(inode->i_rdev); socket_info_t *s; u_int size; int ret, err; ds_ioctl_arg_t buf; DEBUG(2, "ds_ioctl(socket %d, %#x, %#lx)\n", i, cmd, arg); if ((i >= sockets) || (sockets == 0)) return -ENODEV; s = &socket_table[i]; 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, (char *)arg, size); if (err) { DEBUG(3, "ds_ioctl(): verify_read = %d\n", err); return err; } } if (cmd & IOC_OUT) { err = verify_area(VERIFY_WRITE, (char *)arg, size); if (err) { DEBUG(3, "ds_ioctl(): verify_write = %d\n", err); return err; } } err = ret = 0; if (cmd & IOC_IN) copy_from_user((char *)&buf, (char *)arg, 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: 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: ret = pcmcia_validate_cis(s->handle, &buf.cisinfo); break; case DS_SUSPEND_CARD: ret = pcmcia_suspend_card(s->handle, NULL); break; case DS_RESUME_CARD: ret = pcmcia_resume_card(s->handle, NULL); break; case DS_EJECT_CARD: ret = pcmcia_eject_card(s->handle, NULL); break; case DS_INSERT_CARD: ret = pcmcia_insert_card(s->handle, NULL); 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(i, &buf.bind_info); break; case DS_GET_DEVICE_INFO: err = get_device_info(i, &buf.bind_info, 1); break; case DS_GET_NEXT_DEVICE: err = get_device_info(i, &buf.bind_info, 0); break; case DS_UNBIND_REQUEST: err = unbind_request(i, &buf.bind_info); break; case DS_BIND_MTD: if (!suser()) return -EPERM; err = bind_mtd(i, &buf.mtd_info); break; default: err = -EINVAL; } if ((err == 0) && (ret != CS_SUCCESS)) { DEBUG(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((char *)arg, (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,};EXPORT_SYMBOL(register_pccard_driver);EXPORT_SYMBOL(unregister_pccard_driver);/*====================================================================*/int __init init_pcmcia_ds(void){ client_reg_t client_reg; servinfo_t serv; bind_req_t bind; socket_info_t *s; int i, ret; DEBUG(0, "%s\n", version); /* * 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.. */ current->state = TASK_INTERRUPTIBLE; schedule_timeout(HZ/10); pcmcia_get_card_services_info(&serv); if (serv.Revision != CS_RELEASE_CODE) { printk(KERN_NOTICE "ds: Card Services release does not match!\n"); return -1; } if (serv.Count == 0) { printk(KERN_NOTICE "ds: no socket drivers loaded!\n"); return -1; } sockets = serv.Count; socket_table = kmalloc(sockets*sizeof(socket_info_t), GFP_KERNEL); if (!socket_table) return -1; for (i = 0, s = socket_table; i < sockets; i++, s++) { s->state = 0; s->user = NULL; s->req_pending = 0; init_waitqueue_head(&s->queue); init_waitqueue_head(&s->request); s->handle = NULL; init_timer(&s->removal); s->removal.data = i; s->removal.function = &handle_removal; s->bind = NULL; } /* Set up hotline to Card Services */ client_reg.dev_info = bind.dev_info = &dev_info; 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; for (i = 0; i < sockets; i++) { bind.Socket = i; bind.Function = BIND_FN_ALL; ret = pcmcia_bind_device(&bind); if (ret != CS_SUCCESS) { cs_error(NULL, BindDevice, ret); break; } client_reg.event_callback_args.client_data = &socket_table[i]; ret = pcmcia_register_client(&socket_table[i].handle, &client_reg); if (ret != CS_SUCCESS) { cs_error(NULL, RegisterClient, ret); break; } } /* 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 if (proc_pccard) create_proc_read_entry("drivers",0,proc_pccard,proc_read_drivers,NULL); init_status = 0;#endif return 0;}#ifdef MODULEint __init init_module(void){ return init_pcmcia_ds();}void __exit cleanup_module(void){ int i;#ifdef CONFIG_PROC_FS if (proc_pccard) remove_proc_entry("drivers", proc_pccard);#endif if (major_dev != -1) unregister_chrdev(major_dev, "pcmcia"); for (i = 0; i < sockets; i++) pcmcia_deregister_client(socket_table[i].handle); sockets = 0; kfree(socket_table);}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -