📄 ds.c
字号:
return 0;}static int proc_read_drivers(char *buf, char **start, off_t pos, int count, int *eof, void *data){ char *p = buf; bus_for_each_drv(&pcmcia_bus_type, NULL, (void *) &p, proc_read_drivers_callback); return (p - buf);}#endif/*====================================================================== These manage a ring buffer of events pending for one user process ======================================================================*/static int queue_empty(user_info_t *user){ return (user->event_head == user->event_tail);}static event_t get_queued_event(user_info_t *user){ user->event_tail = (user->event_tail+1) % MAX_EVENTS; return user->event[user->event_tail];}static void queue_event(user_info_t *user, event_t event){ user->event_head = (user->event_head+1) % MAX_EVENTS; if (user->event_head == user->event_tail) user->event_tail = (user->event_tail+1) % MAX_EVENTS; user->event[user->event_head] = event;}static void handle_event(struct pcmcia_bus_socket *s, event_t event){ user_info_t *user; for (user = s->user; user; user = user->next) queue_event(user, event); wake_up_interruptible(&s->queue);}static int handle_request(struct pcmcia_bus_socket *s, event_t event){ if (s->req_pending != 0) return CS_IN_USE; if (s->state & DS_SOCKET_BUSY) s->req_pending = 1; handle_event(s, event); if (wait_event_interruptible(s->request, s->req_pending <= 0)) return CS_IN_USE; if (s->state & DS_SOCKET_BUSY) return s->req_result; return CS_SUCCESS;}static void handle_removal(void *data){ struct pcmcia_bus_socket *s = data; handle_event(s, CS_EVENT_CARD_REMOVAL); s->state &= ~DS_SOCKET_REMOVAL_PENDING;}/*====================================================================== The card status event handler. ======================================================================*/static int ds_event(event_t event, int priority, event_callback_args_t *args){ struct pcmcia_bus_socket *s; ds_dbg(1, "ds_event(0x%06x, %d, 0x%p)\n", event, priority, args->client_handle); s = args->client_data; switch (event) { case CS_EVENT_CARD_REMOVAL: s->state &= ~DS_SOCKET_PRESENT; if (!(s->state & DS_SOCKET_REMOVAL_PENDING)) { s->state |= DS_SOCKET_REMOVAL_PENDING; schedule_delayed_work(&s->removal, HZ/10); } break; case CS_EVENT_CARD_INSERTION: s->state |= DS_SOCKET_PRESENT; handle_event(s, event); break; case CS_EVENT_EJECTION_REQUEST: return handle_request(s, event); break; default: handle_event(s, event); break; } return 0;} /* ds_event *//*====================================================================== bind_mtd() connects a memory region with an MTD client. ======================================================================*/static int bind_mtd(struct pcmcia_bus_socket *bus_sock, mtd_info_t *mtd_info){ mtd_bind_t bind_req; int ret; bind_req.dev_info = &mtd_info->dev_info; bind_req.Attributes = mtd_info->Attributes; bind_req.Socket = bus_sock->parent; bind_req.CardOffset = mtd_info->CardOffset; ret = pcmcia_bind_mtd(&bind_req); if (ret != CS_SUCCESS) { cs_error(NULL, BindMTD, ret); printk(KERN_NOTICE "ds: unable to bind MTD '%s' to socket %d" " offset 0x%x\n", (char *)bind_req.dev_info, bus_sock->parent->sock, bind_req.CardOffset); return -ENODEV; } return 0;} /* bind_mtd *//*====================================================================== bind_request() connects a socket to a particular client driver. It looks up the specified device ID in the list of registered drivers, binds it to the socket, and tries to create an instance of the device. unbind_request() deletes a driver instance. ======================================================================*/static int bind_request(struct pcmcia_bus_socket *s, bind_info_t *bind_info){ struct pcmcia_driver *driver; socket_bind_t *b; bind_req_t bind_req; int ret; if (!s) return -EINVAL; ds_dbg(2, "bind_request(%d, '%s')\n", s->parent->sock, (char *)bind_info->dev_info); driver = get_pcmcia_driver(&bind_info->dev_info); if (!driver) return -EINVAL; for (b = s->bind; b; b = b->next) if ((driver == b->driver) && (bind_info->function == b->function)) break; if (b != NULL) { bind_info->instance = b->instance; return -EBUSY; } if (!try_module_get(driver->owner)) return -EINVAL; bind_req.Socket = s->parent; bind_req.Function = bind_info->function; bind_req.dev_info = (dev_info_t *) driver->drv.name; ret = pcmcia_bind_device(&bind_req); if (ret != CS_SUCCESS) { cs_error(NULL, BindDevice, ret); printk(KERN_NOTICE "ds: unable to bind '%s' to socket %d\n", (char *)dev_info, s->parent->sock); module_put(driver->owner); return -ENODEV; } /* Add binding to list for this socket */ driver->use_count++; b = kmalloc(sizeof(socket_bind_t), GFP_KERNEL); if (!b) { driver->use_count--; module_put(driver->owner); return -ENOMEM; } b->driver = driver; b->function = bind_info->function; b->instance = NULL; b->next = s->bind; s->bind = b; if (driver->attach) { b->instance = driver->attach(); if (b->instance == NULL) { printk(KERN_NOTICE "ds: unable to create instance " "of '%s'!\n", (char *)bind_info->dev_info); module_put(driver->owner); return -ENODEV; } } return 0;} /* bind_request *//*====================================================================*/static int get_device_info(struct pcmcia_bus_socket *s, bind_info_t *bind_info, int first){ socket_bind_t *b; dev_node_t *node;#ifdef CONFIG_CARDBUS /* * Some unbelievably ugly code to associate the PCI cardbus * device and its driver with the PCMCIA "bind" information. */ { struct pci_bus *bus; bus = pcmcia_lookup_bus(s->handle); if (bus) { struct list_head *list; struct pci_dev *dev = NULL; list = bus->devices.next; while (list != &bus->devices) { struct pci_dev *pdev = pci_dev_b(list); list = list->next; if (first) { dev = pdev; break; } /* Try to handle "next" here some way? */ } if (dev && dev->driver) { strlcpy(bind_info->name, dev->driver->name, DEV_NAME_LEN); bind_info->major = 0; bind_info->minor = 0; bind_info->next = NULL; return 0; } } }#endif for (b = s->bind; b; b = b->next) if ((strcmp((char *)b->driver->drv.name, (char *)bind_info->dev_info) == 0) && (b->function == bind_info->function)) break; if (b == NULL) return -ENODEV; if ((b->instance == NULL) || (b->instance->state & DEV_CONFIG_PENDING)) return -EAGAIN; if (first) node = b->instance->dev; else for (node = b->instance->dev; node; node = node->next) if (node == bind_info->next) break; if (node == NULL) return -ENODEV; strlcpy(bind_info->name, node->dev_name, DEV_NAME_LEN); bind_info->major = node->major; bind_info->minor = node->minor; bind_info->next = node->next; return 0;} /* get_device_info *//*====================================================================*/static int unbind_request(struct pcmcia_bus_socket *s, bind_info_t *bind_info){ socket_bind_t **b, *c; ds_dbg(2, "unbind_request(%d, '%s')\n", s->parent->sock, (char *)bind_info->dev_info); for (b = &s->bind; *b; b = &(*b)->next) if ((strcmp((char *)(*b)->driver->drv.name, (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); } module_put(c->driver->owner); *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 = iminor(inode); struct pcmcia_bus_socket *s; user_info_t *user; ds_dbg(0, "ds_open(socket %d)\n", i); s = pcmcia_get_bus_socket(i); if (!s) return -ENODEV; if ((file->f_flags & O_ACCMODE) != O_RDONLY) { if (s->state & DS_SOCKET_BUSY) return -EBUSY; else s->state |= DS_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; user->socket = s; s->user = user; file->private_data = user; if (s->state & DS_SOCKET_PRESENT) queue_event(user, CS_EVENT_CARD_INSERTION); return 0;} /* ds_open *//*====================================================================*/static int ds_release(struct inode *inode, struct file *file){ struct pcmcia_bus_socket *s; user_info_t *user, **link; ds_dbg(0, "ds_release(socket %d)\n", iminor(inode)); user = file->private_data; if (CHECK_USER(user)) goto out; s = user->socket; /* Unlink user data structure */ if ((file->f_flags & O_ACCMODE) != O_RDONLY) { s->state &= ~DS_SOCKET_BUSY; s->req_pending = 0; wake_up_interruptible(&s->request); } 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); pcmcia_put_bus_socket(s);out: return 0;} /* ds_release *//*====================================================================*/static ssize_t ds_read(struct file *file, char __user *buf, size_t count, loff_t *ppos){ struct pcmcia_bus_socket *s; user_info_t *user; int ret; ds_dbg(2, "ds_read(socket %d)\n", iminor(file->f_dentry->d_inode)); if (count < 4) return -EINVAL; user = file->private_data; if (CHECK_USER(user)) return -EIO; s = user->socket; if (s->state & DS_SOCKET_DEAD) return -EIO; ret = wait_event_interruptible(s->queue, !queue_empty(user)); if (ret == 0) ret = put_user(get_queued_event(user), (int __user *)buf) ? -EFAULT : 4; return ret;} /* ds_read *//*====================================================================*/static ssize_t ds_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -