📄 adb.c
字号:
if (!ret) { devs = adb_scan_bus(); if (adb_controller->autopoll) adb_controller->autopoll(devs); } nret = notifier_call_chain(&adb_client_list, ADB_MSG_POST_RESET, NULL); if (nret & NOTIFY_STOP_MASK) return -EBUSY; return ret;}voidadb_poll(void){ if ((adb_controller == NULL)||(adb_controller->poll == NULL)) return; adb_controller->poll();}static voidadb_probe_wakeup(struct adb_request *req){ complete(&adb_probe_task_comp);}static struct adb_request adb_sreq;static int adb_sreq_lock; // Use semaphore ! */ intadb_request(struct adb_request *req, void (*done)(struct adb_request *), int flags, int nbytes, ...){ va_list list; int i, use_sreq; int rc; if ((adb_controller == NULL) || (adb_controller->send_request == NULL)) return -ENXIO; if (nbytes < 1) return -EINVAL; if (req == NULL && (flags & ADBREQ_NOSEND)) return -EINVAL; if (req == NULL) { if (test_and_set_bit(0,&adb_sreq_lock)) { printk("adb.c: Warning: contention on static request !\n"); return -EPERM; } req = &adb_sreq; flags |= ADBREQ_SYNC; use_sreq = 1; } else use_sreq = 0; req->nbytes = nbytes+1; req->done = done; req->reply_expected = flags & ADBREQ_REPLY; req->data[0] = ADB_PACKET; va_start(list, nbytes); for (i = 0; i < nbytes; ++i) req->data[i+1] = va_arg(list, int); va_end(list); if (flags & ADBREQ_NOSEND) return 0; /* Synchronous requests send from the probe thread cause it to * block. Beware that the "done" callback will be overriden ! */ if ((flags & ADBREQ_SYNC) && (current->pid && adb_probe_task_pid && adb_probe_task_pid == current->pid)) { req->done = adb_probe_wakeup; rc = adb_controller->send_request(req, 0); if (rc || req->complete) goto bail; wait_for_completion(&adb_probe_task_comp); rc = 0; goto bail; } rc = adb_controller->send_request(req, flags & ADBREQ_SYNC);bail: if (use_sreq) clear_bit(0, &adb_sreq_lock); return rc;} /* Ultimately this should return the number of devices with the given default id. And it does it now ! Note: changed behaviour: This function will now register if default_id _and_ handler_id both match but handler_id can be left to 0 to match with default_id only. When handler_id is set, this function will try to adjust the handler_id id it doesn't match. */intadb_register(int default_id, int handler_id, struct adb_ids *ids, void (*handler)(unsigned char *, int, struct pt_regs *, int)){ int i; ids->nids = 0; for (i = 1; i < 16; i++) { if ((adb_handler[i].original_address == default_id) && (!handler_id || (handler_id == adb_handler[i].handler_id) || adb_try_handler_change(i, handler_id))) { if (adb_handler[i].handler != 0) { printk(KERN_ERR "Two handlers for ADB device %d\n", default_id); continue; } adb_handler[i].handler = handler; ids->id[ids->nids++] = i; } } return ids->nids;}intadb_unregister(int index){ if (!adb_handler[index].handler) return -ENODEV; adb_handler[index].handler = 0; return 0;}voidadb_input(unsigned char *buf, int nb, struct pt_regs *regs, int autopoll){ int i, id; static int dump_adb_input = 0; /* We skip keystrokes and mouse moves when the sleep process * has been started. We stop autopoll, but this is another security */ if (adb_got_sleep) return; id = buf[0] >> 4; if (dump_adb_input) { printk(KERN_INFO "adb packet: "); for (i = 0; i < nb; ++i) printk(" %x", buf[i]); printk(", id = %d\n", id); } if (adb_handler[id].handler != 0) { (*adb_handler[id].handler)(buf, nb, regs, autopoll); }}/* Try to change handler to new_id. Will return 1 if successful */intadb_try_handler_change(int address, int new_id){ struct adb_request req; if (adb_handler[address].handler_id == new_id) return 1; adb_request(&req, NULL, ADBREQ_SYNC, 3, ADB_WRITEREG(address, 3), address | 0x20, new_id); adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1, ADB_READREG(address, 3)); if (req.reply_len < 2) return 0; if (req.reply[2] != new_id) return 0; adb_handler[address].handler_id = req.reply[2]; return 1;}intadb_get_infos(int address, int *original_address, int *handler_id){ *original_address = adb_handler[address].original_address; *handler_id = adb_handler[address].handler_id; return (*original_address != 0);}/* * /dev/adb device driver. */#define ADB_MAJOR 56 /* major number for /dev/adb */struct adbdev_state { spinlock_t lock; atomic_t n_pending; struct adb_request *completed; wait_queue_head_t wait_queue; int inuse;};static void adb_write_done(struct adb_request *req){ struct adbdev_state *state = (struct adbdev_state *) req->arg; unsigned long flags; if (!req->complete) { req->reply_len = 0; req->complete = 1; } spin_lock_irqsave(&state->lock, flags); atomic_dec(&state->n_pending); if (!state->inuse) { kfree(req); if (atomic_read(&state->n_pending) == 0) { spin_unlock_irqrestore(&state->lock, flags); kfree(state); return; } } else { struct adb_request **ap = &state->completed; while (*ap != NULL) ap = &(*ap)->next; req->next = NULL; *ap = req; wake_up_interruptible(&state->wait_queue); } spin_unlock_irqrestore(&state->lock, flags);}static int adb_open(struct inode *inode, struct file *file){ struct adbdev_state *state; if (MINOR(inode->i_rdev) > 0 || adb_controller == NULL) return -ENXIO; state = kmalloc(sizeof(struct adbdev_state), GFP_KERNEL); if (state == 0) return -ENOMEM; file->private_data = state; spin_lock_init(&state->lock); atomic_set(&state->n_pending, 0); state->completed = NULL; init_waitqueue_head(&state->wait_queue); state->inuse = 1; return 0;}static int adb_release(struct inode *inode, struct file *file){ struct adbdev_state *state = file->private_data; unsigned long flags; lock_kernel(); if (state) { file->private_data = NULL; spin_lock_irqsave(&state->lock, flags); if (atomic_read(&state->n_pending) == 0 && state->completed == NULL) { spin_unlock_irqrestore(&state->lock, flags); kfree(state); } else { state->inuse = 0; spin_unlock_irqrestore(&state->lock, flags); } } unlock_kernel(); return 0;}static ssize_t adb_read(struct file *file, char *buf, size_t count, loff_t *ppos){ int ret; struct adbdev_state *state = file->private_data; struct adb_request *req; wait_queue_t wait = __WAITQUEUE_INITIALIZER(wait,current); unsigned long flags; if (count < 2) return -EINVAL; if (count > sizeof(req->reply)) count = sizeof(req->reply); ret = verify_area(VERIFY_WRITE, buf, count); if (ret) return ret; req = NULL; spin_lock_irqsave(&state->lock, flags); add_wait_queue(&state->wait_queue, &wait); current->state = TASK_INTERRUPTIBLE; for (;;) { req = state->completed; if (req != NULL) state->completed = req->next; else if (atomic_read(&state->n_pending) == 0) ret = -EIO; if (req != NULL || ret != 0) break; if (file->f_flags & O_NONBLOCK) { ret = -EAGAIN; break; } if (signal_pending(current)) { ret = -ERESTARTSYS; break; } spin_unlock_irqrestore(&state->lock, flags); schedule(); spin_lock_irqsave(&state->lock, flags); } current->state = TASK_RUNNING; remove_wait_queue(&state->wait_queue, &wait); spin_unlock_irqrestore(&state->lock, flags); if (ret) return ret; ret = req->reply_len; if (ret > count) ret = count; if (ret > 0 && copy_to_user(buf, req->reply, ret)) ret = -EFAULT; kfree(req); return ret;}static ssize_t adb_write(struct file *file, const char *buf, size_t count, loff_t *ppos){ int ret/*, i*/; struct adbdev_state *state = file->private_data; struct adb_request *req; if (count < 2 || count > sizeof(req->data)) return -EINVAL; if (adb_controller == NULL) return -ENXIO; ret = verify_area(VERIFY_READ, buf, count); if (ret) return ret; req = (struct adb_request *) kmalloc(sizeof(struct adb_request), GFP_KERNEL); if (req == NULL) return -ENOMEM; req->nbytes = count; req->done = adb_write_done; req->arg = (void *) state; req->complete = 0; ret = -EFAULT; if (copy_from_user(req->data, buf, count)) goto out; atomic_inc(&state->n_pending); /* If a probe is in progress, wait for it to complete */ while (adb_probe_task_pid != 0 || test_bit(0, &adb_probe_task_flag)) schedule(); /* Special case for ADB_BUSRESET request, all others are sent to the controller */ if ((req->data[0] == ADB_PACKET)&&(count > 1) &&(req->data[1] == ADB_BUSRESET)) { ret = do_adb_reset_bus(); atomic_dec(&state->n_pending); if (ret == 0) ret = count; goto out; } else { req->reply_expected = ((req->data[1] & 0xc) == 0xc); if (adb_controller && adb_controller->send_request) ret = adb_controller->send_request(req, 0); else ret = -ENXIO; } if (ret != 0) { atomic_dec(&state->n_pending); goto out; } return count;out: kfree(req); return ret;}static struct file_operations adb_fops = { llseek: no_llseek, read: adb_read, write: adb_write, open: adb_open, release: adb_release,};static voidadbdev_init(void){ if (devfs_register_chrdev(ADB_MAJOR, "adb", &adb_fops)) printk(KERN_ERR "adb: unable to get major %d\n", ADB_MAJOR); else devfs_register (NULL, "adb", DEVFS_FL_DEFAULT, ADB_MAJOR, 0, S_IFCHR | S_IRUSR | S_IWUSR, &adb_fops, NULL);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -