📄 raw1394.c
字号:
req->req.error = RAW1394_ERROR_SEND_ERROR; req->req.length = 0; queue_complete_req(req); } return sizeof(struct raw1394_request);}static int get_config_rom(struct file_info *fi, struct pending_request *req){ size_t return_size; unsigned char rom_version; int ret=sizeof(struct raw1394_request); quadlet_t *data = kmalloc(req->req.length, SLAB_KERNEL); int status; if (!data) return -ENOMEM; status = hpsb_get_config_rom(fi->host, data, req->req.length, &return_size, &rom_version); if (copy_to_user(int2ptr(req->req.recvb), data, req->req.length)) ret = -EFAULT; if (copy_to_user(int2ptr(req->req.tag), &return_size, sizeof(return_size))) ret = -EFAULT; if (copy_to_user(int2ptr(req->req.address), &rom_version, sizeof(rom_version))) ret = -EFAULT; if (copy_to_user(int2ptr(req->req.sendb), &status, sizeof(status))) ret = -EFAULT; kfree(data); if (ret >= 0) { free_pending_request(req); /* we have to free the request, because we queue no response, and therefore nobody will free it */ } return ret;}static int update_config_rom(struct file_info *fi, struct pending_request *req){ int ret=sizeof(struct raw1394_request); quadlet_t *data = kmalloc(req->req.length, SLAB_KERNEL); if (!data) return -ENOMEM; if (copy_from_user(data,int2ptr(req->req.sendb), req->req.length)) { ret= -EFAULT; } else { int status = hpsb_update_config_rom(fi->host, data, req->req.length, (unsigned char) req->req.misc); if (copy_to_user(int2ptr(req->req.recvb), &status, sizeof(status))) ret = -ENOMEM; } kfree(data); if (ret >= 0) { free_pending_request(req); /* we have to free the request, because we queue no response, and therefore nobody will free it */ } return ret;}static int state_connected(struct file_info *fi, struct pending_request *req){ int node = req->req.address >> 48; req->req.error = RAW1394_ERROR_NONE; switch (req->req.type) { case RAW1394_REQ_ECHO: queue_complete_req(req); return sizeof(struct raw1394_request); case RAW1394_REQ_ISO_SEND: return handle_iso_send(fi, req, node); case RAW1394_REQ_ARM_REGISTER: return arm_register(fi, req); case RAW1394_REQ_ARM_UNREGISTER: return arm_unregister(fi, req); case RAW1394_REQ_RESET_NOTIFY: return reset_notification(fi, req); 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: if (req->req.misc == RAW1394_LONG_RESET) { DBGMSG("busreset called (type: LONG)"); hpsb_reset_bus(fi->host, LONG_RESET); free_pending_request(req); /* we have to free the request, because we queue no response, and therefore nobody will free it */ return sizeof(struct raw1394_request); } if (req->req.misc == RAW1394_SHORT_RESET) { DBGMSG("busreset called (type: SHORT)"); hpsb_reset_bus(fi->host, SHORT_RESET); free_pending_request(req); /* we have to free the request, because we queue no response, and therefore nobody will free it */ return sizeof(struct raw1394_request); } /* error EINVAL (22) invalid argument */ return (-EINVAL); case RAW1394_REQ_GET_ROM: return get_config_rom(fi, req); case RAW1394_REQ_UPDATE_ROM: return update_config_rom(fi, req); } 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_PHYPACKET: return write_phypacket(fi, req); case RAW1394_REQ_ASYNC_SEND: return handle_async_send(fi, req); } if (req->req.length == 0) { req->req.error = RAW1394_ERROR_INVALID_ARG; queue_complete_req(req); return sizeof(struct raw1394_request); } return handle_async_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;}/* rawiso operations *//* check if any RAW1394_REQ_RAWISO_ACTIVITY event is already in the* completion queue (reqlists_lock must be taken) */static inline int __rawiso_event_in_queue(struct file_info *fi){ struct list_head *lh; struct pending_request *req; list_for_each(lh, &fi->req_complete) { req = list_entry(lh, struct pending_request, list); if (req->req.type == RAW1394_REQ_RAWISO_ACTIVITY) { return 1; } } return 0;}/* put a RAWISO_ACTIVITY event in the queue, if one isn't there already */static void queue_rawiso_event(struct file_info *fi){ unsigned long flags; spin_lock_irqsave(&fi->reqlists_lock, flags); /* only one ISO activity event may be in the queue */ if (!__rawiso_event_in_queue(fi)) { struct pending_request *req = __alloc_pending_request(SLAB_ATOMIC); if (req) { req->file_info = fi; req->req.type = RAW1394_REQ_RAWISO_ACTIVITY; req->req.generation = get_hpsb_generation(fi->host); __queue_complete_req(req); } else { /* on allocation failure, signal an overflow */ if (fi->iso_handle) { atomic_inc(&fi->iso_handle->overflows); } } } spin_unlock_irqrestore(&fi->reqlists_lock, flags);}static void rawiso_activity_cb(struct hpsb_iso *iso){ unsigned long flags; struct list_head *lh; struct host_info *hi; spin_lock_irqsave(&host_info_lock, flags); hi = find_host_info(iso->host); if (hi != NULL) { list_for_each(lh, &hi->file_info_list) { struct file_info *fi = list_entry(lh, struct file_info, list); if (fi->iso_handle == iso) queue_rawiso_event(fi); } } spin_unlock_irqrestore(&host_info_lock, flags);}/* helper function - gather all the kernel iso status bits for returning to user-space */static void raw1394_iso_fill_status(struct hpsb_iso *iso, struct raw1394_iso_status *stat){ stat->config.data_buf_size = iso->buf_size; stat->config.buf_packets = iso->buf_packets; stat->config.channel = iso->channel; stat->config.speed = iso->speed; stat->config.irq_interval = iso->irq_interval; stat->n_packets = hpsb_iso_n_ready(iso); stat->overflows = atomic_read(&iso->overflows); stat->xmit_cycle = iso->xmit_cycle;}static int raw1394_iso_xmit_init(struct file_info *fi, void *uaddr){ struct raw1394_iso_status stat; if (!fi->host) return -EINVAL; if (copy_from_user(&stat, uaddr, sizeof(stat))) return -EFAULT; fi->iso_handle = hpsb_iso_xmit_init(fi->host, stat.config.data_buf_size, stat.config.buf_packets, stat.config.channel, stat.config.speed, stat.config.irq_interval, rawiso_activity_cb); if (!fi->iso_handle) return -ENOMEM; fi->iso_state = RAW1394_ISO_XMIT; raw1394_iso_fill_status(fi->iso_handle, &stat); if (copy_to_user(uaddr, &stat, sizeof(stat))) return -EFAULT; /* queue an event to get things started */ rawiso_activity_cb(fi->iso_handle); return 0;}static int raw1394_iso_recv_init(struct file_info *fi, void *uaddr){ struct raw1394_iso_status stat; if (!fi->host) return -EINVAL; if (copy_from_user(&stat, uaddr, sizeof(stat))) return -EFAULT; fi->iso_handle = hpsb_iso_recv_init(fi->host, stat.config.data_buf_size, stat.config.buf_packets, stat.config.channel, stat.config.irq_interval, rawiso_activity_cb); if (!fi->iso_handle) return -ENOMEM; fi->iso_state = RAW1394_ISO_RECV; raw1394_iso_fill_status(fi->iso_handle, &stat); if (copy_to_user(uaddr, &stat, sizeof(stat))) return -EFAULT; return 0;}static int raw1394_iso_get_status(struct file_info *fi, void *uaddr){ struct raw1394_iso_status stat; struct hpsb_iso *iso = fi->iso_handle; raw1394_iso_fill_status(fi->iso_handle, &stat); if (copy_to_user(uaddr, &stat, sizeof(stat))) return -EFAULT; /* reset overflow counter */ atomic_set(&iso->overflows, 0); return 0;}/* copy N packet_infos out of the ringbuffer into user-supplied array */static int raw1394_iso_recv_packets(struct file_info *fi, void *uaddr){ struct raw1394_iso_packets upackets; unsigned int packet = fi->iso_handle->first_packet; int i; if (copy_from_user(&upackets, uaddr, sizeof(upackets))) return -EFAULT; if (upackets.n_packets > hpsb_iso_n_ready(fi->iso_handle)) return -EINVAL; /* ensure user-supplied buffer is accessible and big enough */ if (verify_area(VERIFY_WRITE, upackets.infos, upackets.n_packets * sizeof(struct raw1394_iso_packet_info))) return -EFAULT; /* copy the packet_infos out */ for (i = 0; i < upackets.n_packets; i++) { if (__copy_to_user(&upackets.infos[i], &fi->iso_handle->infos[packet], sizeof(struct raw1394_iso_packet_info))) return -EFAULT; packet = (packet + 1) % fi->iso_handle->buf_packets; } return 0;}/* copy N packet_infos from user to ringbuffer, and queue them for transmission */static int raw1394_iso_send_packets(struct file_info *fi, void *uaddr){ struct raw1394_iso_packets upackets; int i, rv; if (copy_from_user(&upackets, uaddr, sizeof(upackets))) return -EFAULT; if (upackets.n_packets > hpsb_iso_n_ready(fi->iso_handle)) return -EINVAL; /* ensure user-supplied buffer is accessible and big enough */ if (verify_area(VERIFY_READ, upackets.infos, upackets.n_packets * sizeof(struct raw1394_iso_packet_info))) return -EFAULT; /* copy the infos structs in and queue the packets */ for (i = 0; i < upackets.n_packets; i++) { struct raw1394_iso_packet_info info; if (__copy_from_user(&info, &upackets.infos[i], sizeof(struct raw1394_iso_packet_info))) return -EFAULT; rv = hpsb_iso_xmit_queue_packet(fi->iso_handle, info.offset, info.len, info.tag, info.sy); if (rv) return rv; } return 0;}static void raw1394_iso_shutdown(struct file_info *fi){ if (fi->iso_handle) hpsb_iso_shutdown(fi->iso_handle); fi->iso_handle = NULL; fi->iso_state = RAW1394_ISO_INACTIVE;}/* mmap the rawiso xmit/recv buffer */static int raw1394_mmap(struct file *file, struct vm_area_struct *vma){ struct file_info *fi = file->private_data; if (fi->iso_state == RAW1394_ISO_INACTIVE) return -EINVAL; return dma_region_mmap(&fi->iso_handle->data_buf, file, vma);}/* ioctl is only used for rawiso operations */static int raw1394_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ struct file_info *fi = file->private_data; switch(fi->iso_state) { case RAW1394_ISO_INACTIVE: switch(cmd) { case RAW1394_IOC_ISO_XMIT_INIT: return raw1394_iso_xmit_init(fi, (void*) arg); case RAW1394_IOC_ISO_RECV_INIT: return raw1394_iso_recv_init(fi, (void*) arg); default: break; } break; case RAW1394_ISO_RECV: switch(cmd) { case RAW1394_IOC_ISO_RECV_START: { /* copy args from user-space */ int args[3]; if (copy_from_user(&args[0], (void*) arg, sizeof(args))) return -EFAULT; return hpsb_iso_recv_start(fi->iso_handle, args[0], args[1], args[2]); } case RAW1394_IOC_ISO_XMIT_RECV_STOP: hpsb_iso_stop(fi->iso_handle); return 0; case RAW1394_IOC_ISO_RECV_LISTEN_CHANNEL: return hpsb_iso_recv_listen_channel(fi->iso_handle, arg); case RAW1394_IOC_ISO_RECV_UNLISTEN_CHANNEL: return hpsb_iso_recv_unlisten_channel(fi->iso_handle, arg); case RAW1394_IOC_ISO_RECV_SET_CHANNEL_MASK: { /* copy the u64 from user-space */ u64 mask; if (copy_from_user(&mask, (void*) arg, sizeof(mask))) return -EFAULT; return hpsb_iso_recv_set_channel_mask(fi->iso_handle, mask); } case RAW1394_IOC_ISO_GET_STATUS: return raw1394_iso_get_st
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -