📄 raw1394.c
字号:
if (copy_from_user(packet->data, int2ptr(req->req.sendb), req->req.length)) { req->req.error = RAW1394_ERROR_MEMFAULT; } } req->req.length = 0; break; case RAW1394_REQ_LOCK: if ((req->req.misc == EXTCODE_FETCH_ADD) || (req->req.misc == EXTCODE_LITTLE_ADD)) { if (req->req.length != 4) { req->req.error = RAW1394_ERROR_INVALID_ARG; break; } } else { if (req->req.length != 8) { req->req.error = RAW1394_ERROR_INVALID_ARG; break; } } packet = hpsb_make_lockpacket(fi->host, node, addr, req->req.misc); if (!packet) return -ENOMEM; if (copy_from_user(packet->data, int2ptr(req->req.sendb), req->req.length)) { req->req.error = RAW1394_ERROR_MEMFAULT; break; } req->data = packet->data; req->req.length = 4; break; case RAW1394_REQ_LOCK64: default: req->req.error = RAW1394_ERROR_STATE_ORDER; } req->packet = packet; if (req->req.error) { req->req.length = 0; queue_complete_req(req); return sizeof(struct raw1394_request); } req->tq.data = req; queue_task(&req->tq, &packet->complete_tq); spin_lock_irq(&fi->reqlists_lock); list_add_tail(&req->list, &fi->req_pending); spin_unlock_irq(&fi->reqlists_lock); packet->generation = req->req.generation; if (!hpsb_send_packet(packet)) { req->req.error = RAW1394_ERROR_SEND_ERROR; req->req.length = 0; free_tlabel(packet->host, packet->node_id, packet->tlabel); queue_complete_req(req); } return sizeof(struct raw1394_request);}static int handle_iso_send(struct file_info *fi, struct pending_request *req, int channel){ struct hpsb_packet *packet; packet = alloc_hpsb_packet(req->req.length); if (!packet) return -ENOMEM; req->packet = packet; fill_iso_packet(packet, req->req.length, channel & 0x3f, (req->req.misc >> 16) & 0x3, req->req.misc & 0xf); packet->type = hpsb_iso; packet->speed_code = req->req.address & 0x3; packet->host = fi->host; if (copy_from_user(packet->data, int2ptr(req->req.sendb), req->req.length)) { req->req.error = RAW1394_ERROR_MEMFAULT; req->req.length = 0; queue_complete_req(req); return sizeof(struct raw1394_request); } req->tq.data = req; req->tq.routine = (void (*)(void*))queue_complete_req; req->req.length = 0; queue_task(&req->tq, &packet->complete_tq); spin_lock_irq(&fi->reqlists_lock); list_add_tail(&req->list, &fi->req_pending); spin_unlock_irq(&fi->reqlists_lock); /* Update the generation of the packet just before sending. */ packet->generation = get_hpsb_generation(fi->host); if (!hpsb_send_packet(packet)) { req->req.error = RAW1394_ERROR_SEND_ERROR; queue_complete_req(req); } return sizeof(struct raw1394_request);}static int state_connected(struct file_info *fi, struct pending_request *req){ int node = req->req.address >> 48; req->req.error = RAW1394_ERROR_NONE; if (req->req.type == RAW1394_REQ_ISO_SEND) { return handle_iso_send(fi, req, node); } if (req->req.generation != get_hpsb_generation(fi->host)) { req->req.error = RAW1394_ERROR_GENERATION; req->req.generation = get_hpsb_generation(fi->host); req->req.length = 0; queue_complete_req(req); return sizeof(struct raw1394_request); } switch (req->req.type) { case RAW1394_REQ_ISO_LISTEN: handle_iso_listen(fi, req); return sizeof(struct raw1394_request); case RAW1394_REQ_FCP_LISTEN: handle_fcp_listen(fi, req); return sizeof(struct raw1394_request); case RAW1394_REQ_RESET_BUS: hpsb_reset_bus(fi->host, LONG_RESET); return sizeof(struct raw1394_request); } if (req->req.length == 0) { req->req.error = RAW1394_ERROR_INVALID_ARG; queue_complete_req(req); return sizeof(struct raw1394_request); } if (fi->host->node_id == node) { return handle_local_request(fi, req, node); } return handle_remote_request(fi, req, node);}static ssize_t raw1394_write(struct file *file, const char *buffer, size_t count, loff_t *offset_is_ignored){ struct file_info *fi = (struct file_info *)file->private_data; struct pending_request *req; ssize_t retval = 0; if (count != sizeof(struct raw1394_request)) { return -EINVAL; } req = alloc_pending_request(); if (req == NULL) { return -ENOMEM; } req->file_info = fi; if (copy_from_user(&req->req, buffer, sizeof(struct raw1394_request))) { free_pending_request(req); return -EFAULT; } switch (fi->state) { case opened: retval = state_opened(fi, req); break; case initialized: retval = state_initialized(fi, req); break; case connected: retval = state_connected(fi, req); break; } if (retval < 0) { free_pending_request(req); } return retval;}static unsigned int raw1394_poll(struct file *file, poll_table *pt){ struct file_info *fi = file->private_data; unsigned int mask = POLLOUT | POLLWRNORM; poll_wait(file, &fi->poll_wait_complete, pt); spin_lock_irq(&fi->reqlists_lock); if (!list_empty(&fi->req_complete)) { mask |= POLLIN | POLLRDNORM; } spin_unlock_irq(&fi->reqlists_lock); return mask;}static int raw1394_open(struct inode *inode, struct file *file){ struct file_info *fi; if (MINOR(inode->i_rdev)) { return -ENXIO; } V22_COMPAT_MOD_INC_USE_COUNT; fi = kmalloc(sizeof(struct file_info), SLAB_KERNEL); if (fi == NULL) { V22_COMPAT_MOD_DEC_USE_COUNT; return -ENOMEM; } memset(fi, 0, sizeof(struct file_info)); INIT_LIST_HEAD(&fi->list); fi->state = opened; INIT_LIST_HEAD(&fi->req_pending); INIT_LIST_HEAD(&fi->req_complete); sema_init(&fi->complete_sem, 0); spin_lock_init(&fi->reqlists_lock); init_waitqueue_head(&fi->poll_wait_complete); file->private_data = fi; return 0;}static int raw1394_release(struct inode *inode, struct file *file){ struct file_info *fi = file->private_data; struct list_head *lh; struct pending_request *req; int done = 0, i; lock_kernel(); for (i = 0; i < 64; i++) { if (fi->listen_channels & (1ULL << i)) { hpsb_unlisten_channel(hl_handle, fi->host, i); } } spin_lock(&host_info_lock); fi->listen_channels = 0; spin_unlock(&host_info_lock); while (!done) { spin_lock_irq(&fi->reqlists_lock); while (!list_empty(&fi->req_complete)) { lh = fi->req_complete.next; list_del(lh); req = list_entry(lh, struct pending_request, list); free_pending_request(req); } if (list_empty(&fi->req_pending)) done = 1; spin_unlock_irq(&fi->reqlists_lock); if (!done) down_interruptible(&fi->complete_sem); } if (fi->state == connected) { spin_lock_irq(&host_info_lock); list_del(&fi->list); spin_unlock_irq(&host_info_lock); hpsb_dec_host_usage(fi->host); } kfree(fi); V22_COMPAT_MOD_DEC_USE_COUNT; unlock_kernel(); return 0;}static struct hpsb_highlevel_ops hl_ops = { add_host: add_host, remove_host: remove_host, host_reset: host_reset, iso_receive: iso_receive, fcp_request: fcp_request,};static struct file_operations file_ops = { OWNER_THIS_MODULE read: raw1394_read, write: raw1394_write, poll: raw1394_poll, open: raw1394_open, release: raw1394_release, };static int __init init_raw1394(void){ hl_handle = hpsb_register_highlevel(RAW1394_DEVICE_NAME, &hl_ops); if (hl_handle == NULL) { HPSB_ERR("raw1394 failed to register with ieee1394 highlevel"); return -ENOMEM; } devfs_handle = devfs_register(NULL, RAW1394_DEVICE_NAME, DEVFS_FL_NONE, RAW1394_DEVICE_MAJOR, 0, S_IFCHR | S_IRUSR | S_IWUSR, &file_ops, NULL); if (devfs_register_chrdev(RAW1394_DEVICE_MAJOR, RAW1394_DEVICE_NAME, &file_ops)) { HPSB_ERR("raw1394 failed to register /dev/raw1394 device"); return -EBUSY; } printk(KERN_INFO "raw1394: /dev/%s device initialized\n", RAW1394_DEVICE_NAME); return 0;}static void __exit cleanup_raw1394(void){ devfs_unregister_chrdev(RAW1394_DEVICE_MAJOR, RAW1394_DEVICE_NAME); devfs_unregister(devfs_handle); hpsb_unregister_highlevel(hl_handle);}module_init(init_raw1394);module_exit(cleanup_raw1394);MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -