📄 adb.c
字号:
flags |= ADBREQ_SYNC; } 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; return adb_controller->send_request(req, flags & ADBREQ_SYNC);} /* 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 */extern void adbdev_init(void);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 long long adb_lseek(struct file *file, loff_t offset, int origin){ return -ESPIPE;}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; add_wait_queue(&state->wait_queue, &wait); current->state = TASK_INTERRUPTIBLE; for (;;) { spin_lock_irqsave(&state->lock, flags); req = state->completed; if (req != NULL) state->completed = req->next; else if (atomic_read(&state->n_pending) == 0) ret = -EIO; spin_unlock_irqrestore(&state->lock, flags); if (req != NULL || ret != 0) break; if (file->f_flags & O_NONBLOCK) { ret = -EAGAIN; break; } if (signal_pending(current)) { ret = -ERESTARTSYS; break; } schedule(); } current->state = TASK_RUNNING; remove_wait_queue(&state->wait_queue, &wait); 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; 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 (adb_controller == NULL) return -ENXIO; /* 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 = adb_reset_bus(); atomic_dec(&state->n_pending); 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: adb_lseek, read: adb_read, write: adb_write, open: adb_open, release: adb_release,};void adbdev_init(){#ifdef CONFIG_PPC if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) ) return;#endif#ifdef CONFIG_MAC if (!MACH_IS_MAC) return;#endif 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 + -