📄 raw1394.c
字号:
P(error) || P(misc) || P(generation) || P(length) || P(address) || P(tag) || P(sendb) || P(recvb)) return -EFAULT; return sizeof(struct compat_raw1394_req);}#undef P#endif/* get next completed request (caller must hold fi->reqlists_lock) */static inline struct pending_request *__next_complete_req(struct file_info *fi){ struct list_head *lh; struct pending_request *req = NULL; if (!list_empty(&fi->req_complete)) { lh = fi->req_complete.next; list_del(lh); req = list_entry(lh, struct pending_request, list); } return req;}/* atomically get next completed request */static struct pending_request *next_complete_req(struct file_info *fi){ unsigned long flags; struct pending_request *req; spin_lock_irqsave(&fi->reqlists_lock, flags); req = __next_complete_req(fi); spin_unlock_irqrestore(&fi->reqlists_lock, flags); return req;}static ssize_t raw1394_read(struct file *file, char __user * 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 ret;#ifdef CONFIG_COMPAT if (count == sizeof(struct compat_raw1394_req)) { /* ok */ } else#endif if (count != sizeof(struct raw1394_request)) { return -EINVAL; } if (!access_ok(VERIFY_WRITE, buffer, count)) { return -EFAULT; } if (file->f_flags & O_NONBLOCK) { if (!(req = next_complete_req(fi))) return -EAGAIN; } else { /* * NB: We call the macro wait_event_interruptible() with a * condition argument with side effect. This is only possible * because the side effect does not occur until the condition * became true, and wait_event_interruptible() won't evaluate * the condition again after that. */ if (wait_event_interruptible(fi->wait_complete, (req = next_complete_req(fi)))) return -ERESTARTSYS; } if (req->req.length) { if (copy_to_user(int2ptr(req->req.recvb), req->data, req->req.length)) { req->req.error = RAW1394_ERROR_MEMFAULT; } }#ifdef CONFIG_COMPAT if (count == sizeof(struct compat_raw1394_req) && sizeof(struct compat_raw1394_req) != sizeof(struct raw1394_request)) { ret = raw1394_compat_read(buffer, &req->req); } else#endif { if (copy_to_user(buffer, &req->req, sizeof(req->req))) { ret = -EFAULT; goto out; } ret = (ssize_t) sizeof(struct raw1394_request); } out: free_pending_request(req); return ret;}static int state_opened(struct file_info *fi, struct pending_request *req){ if (req->req.type == RAW1394_REQ_INITIALIZE) { switch (req->req.misc) { case RAW1394_KERNELAPI_VERSION: case 3: fi->state = initialized; fi->protocol_version = req->req.misc; req->req.error = RAW1394_ERROR_NONE; req->req.generation = atomic_read(&internal_generation); break; default: req->req.error = RAW1394_ERROR_COMPAT; req->req.misc = RAW1394_KERNELAPI_VERSION; } } else { req->req.error = RAW1394_ERROR_STATE_ORDER; } req->req.length = 0; queue_complete_req(req); return sizeof(struct raw1394_request);}static int state_initialized(struct file_info *fi, struct pending_request *req){ unsigned long flags; struct host_info *hi; struct raw1394_khost_list *khl; if (req->req.generation != atomic_read(&internal_generation)) { req->req.error = RAW1394_ERROR_GENERATION; req->req.generation = atomic_read(&internal_generation); req->req.length = 0; queue_complete_req(req); return sizeof(struct raw1394_request); } switch (req->req.type) { case RAW1394_REQ_LIST_CARDS: spin_lock_irqsave(&host_info_lock, flags); khl = kmalloc(sizeof(*khl) * host_count, GFP_ATOMIC); if (khl) { req->req.misc = host_count; req->data = (quadlet_t *) khl; list_for_each_entry(hi, &host_info_list, list) { khl->nodes = hi->host->node_count; strcpy(khl->name, hi->host->driver->name); khl++; } } spin_unlock_irqrestore(&host_info_lock, flags); if (khl) { req->req.error = RAW1394_ERROR_NONE; req->req.length = min(req->req.length, (u32) (sizeof (struct raw1394_khost_list) * req->req.misc)); req->free_data = 1; } else { return -ENOMEM; } break; case RAW1394_REQ_SET_CARD: spin_lock_irqsave(&host_info_lock, flags); if (req->req.misc >= host_count) { req->req.error = RAW1394_ERROR_INVALID_ARG; goto out_set_card; } list_for_each_entry(hi, &host_info_list, list) if (!req->req.misc--) break; get_device(&hi->host->device); /* FIXME handle failure case */ list_add_tail(&fi->list, &hi->file_info_list); /* prevent unloading of the host's low-level driver */ if (!try_module_get(hi->host->driver->owner)) { req->req.error = RAW1394_ERROR_ABORTED; goto out_set_card; } WARN_ON(fi->host); fi->host = hi->host; fi->state = connected; req->req.error = RAW1394_ERROR_NONE; req->req.generation = get_hpsb_generation(fi->host); req->req.misc = (fi->host->node_id << 16) | fi->host->node_count; if (fi->protocol_version > 3) req->req.misc |= NODEID_TO_NODE(fi->host->irm_id) << 8;out_set_card: spin_unlock_irqrestore(&host_info_lock, flags); req->req.length = 0; break; default: req->req.error = RAW1394_ERROR_STATE_ORDER; req->req.length = 0; break; } queue_complete_req(req); return sizeof(struct raw1394_request);}static void handle_iso_listen(struct file_info *fi, struct pending_request *req){ int channel = req->req.misc; if ((channel > 63) || (channel < -64)) { req->req.error = RAW1394_ERROR_INVALID_ARG; } else if (channel >= 0) { /* allocate channel req.misc */ if (fi->listen_channels & (1ULL << channel)) { req->req.error = RAW1394_ERROR_ALREADY; } else { if (hpsb_listen_channel (&raw1394_highlevel, fi->host, channel)) { req->req.error = RAW1394_ERROR_ALREADY; } else { fi->listen_channels |= 1ULL << channel; fi->iso_buffer = int2ptr(req->req.recvb); fi->iso_buffer_length = req->req.length; } } } else { /* deallocate channel (one's complement neg) req.misc */ channel = ~channel; if (fi->listen_channels & (1ULL << channel)) { hpsb_unlisten_channel(&raw1394_highlevel, fi->host, channel); fi->listen_channels &= ~(1ULL << channel); } else { req->req.error = RAW1394_ERROR_INVALID_ARG; } } req->req.length = 0; queue_complete_req(req);}static void handle_fcp_listen(struct file_info *fi, struct pending_request *req){ if (req->req.misc) { if (fi->fcp_buffer) { req->req.error = RAW1394_ERROR_ALREADY; } else { fi->fcp_buffer = int2ptr(req->req.recvb); } } else { if (!fi->fcp_buffer) { req->req.error = RAW1394_ERROR_ALREADY; } else { fi->fcp_buffer = NULL; } } req->req.length = 0; queue_complete_req(req);}static int handle_async_request(struct file_info *fi, struct pending_request *req, int node){ unsigned long flags; struct hpsb_packet *packet = NULL; u64 addr = req->req.address & 0xffffffffffffULL; switch (req->req.type) { case RAW1394_REQ_ASYNC_READ: DBGMSG("read_request called"); packet = hpsb_make_readpacket(fi->host, node, addr, req->req.length); if (!packet) return -ENOMEM; if (req->req.length == 4) req->data = &packet->header[3]; else req->data = packet->data; break; case RAW1394_REQ_ASYNC_WRITE: DBGMSG("write_request called"); packet = hpsb_make_writepacket(fi->host, node, addr, NULL, req->req.length); if (!packet) return -ENOMEM; if (req->req.length == 4) { if (copy_from_user (&packet->header[3], int2ptr(req->req.sendb), req->req.length)) req->req.error = RAW1394_ERROR_MEMFAULT; } else { 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_ASYNC_STREAM: DBGMSG("stream_request called"); packet = hpsb_make_streampacket(fi->host, NULL, req->req.length, node & 0x3f /*channel */ , (req->req.misc >> 16) & 0x3, req->req.misc & 0xf); if (!packet) return -ENOMEM; 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: DBGMSG("lock_request called"); 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, NULL, 0); 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: DBGMSG("lock64_request called"); if ((req->req.misc == EXTCODE_FETCH_ADD) || (req->req.misc == EXTCODE_LITTLE_ADD)) { if (req->req.length != 8) { req->req.error = RAW1394_ERROR_INVALID_ARG; break; } } else { if (req->req.length != 16) { req->req.error = RAW1394_ERROR_INVALID_ARG; break; } } packet = hpsb_make_lock64packet(fi->host, node, addr, req->req.misc, NULL, 0); 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 = 8; break; 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); } hpsb_set_packet_complete_task(packet, (void (*)(void *))queue_complete_cb, req); spin_lock_irqsave(&fi->reqlists_lock, flags); list_add_tail(&req->list, &fi->req_pending); spin_unlock_irqrestore(&fi->reqlists_lock, flags); packet->generation = req->req.generation; if (hpsb_send_packet(packet) < 0) { req->req.error = RAW1394_ERROR_SEND_ERROR; req->req.length = 0; hpsb_free_tlabel(packet); queue_complete_req(req); } return sizeof(struct raw1394_request);}static int handle_iso_send(struct file_info *fi, struct pending_request *req, int channel){ unsigned long flags; struct hpsb_packet *packet; packet = hpsb_make_isopacket(fi->host, req->req.length, channel & 0x3f, (req->req.misc >> 16) & 0x3, req->req.misc & 0xf); if (!packet) return -ENOMEM; packet->speed_code = req->req.address & 0x3; req->packet = packet; 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->req.length = 0; hpsb_set_packet_complete_task(packet, (void (*)(void *))queue_complete_req, req); spin_lock_irqsave(&fi->reqlists_lock, flags); list_add_tail(&req->list, &fi->req_pending); spin_unlock_irqrestore(&fi->reqlists_lock, flags); /* Update the generation of the packet just before sending. */ packet->generation = req->req.generation; if (hpsb_send_packet(packet) < 0) { req->req.error = RAW1394_ERROR_SEND_ERROR; queue_complete_req(req); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -