video1394.c
字号:
d = find_ctx(&ctx->context_list, OHCI_ISO_TRANSMIT, v.channel); if (d == NULL) return -EFAULT; if ((v.buffer<0) || (v.buffer>d->num_desc)) { PRINT(KERN_ERR, ohci->host->id, "Buffer %d out of range",v.buffer); return -EFAULT; } if (d->flags & VIDEO1394_VARIABLE_PACKET_SIZE) { int buf_size = d->nb_cmd * sizeof(unsigned int); struct video1394_queue_variable __user *p = argp; unsigned int __user *qv; if (get_user(qv, &p->packet_sizes)) return -EFAULT; psizes = kmalloc(buf_size, GFP_KERNEL); if (!psizes) return -ENOMEM; if (copy_from_user(psizes, qv, buf_size)) { kfree(psizes); return -EFAULT; } } spin_lock_irqsave(&d->lock,flags); if (d->buffer_status[v.buffer]!=VIDEO1394_BUFFER_FREE) { PRINT(KERN_ERR, ohci->host->id, "Buffer %d is already used",v.buffer); spin_unlock_irqrestore(&d->lock,flags); if (psizes) kfree(psizes); return -EFAULT; } if (d->flags & VIDEO1394_VARIABLE_PACKET_SIZE) { initialize_dma_it_prg_var_packet_queue( d, v.buffer, psizes, ohci); } d->buffer_status[v.buffer]=VIDEO1394_BUFFER_QUEUED; if (d->last_buffer >= 0) { d->it_prg[d->last_buffer] [ d->last_used_cmd[d->last_buffer] ].end.branchAddress = cpu_to_le32((dma_prog_region_offset_to_bus(&d->prg_reg[v.buffer], 0) & 0xfffffff0) | 0x3); d->it_prg[d->last_buffer] [ d->last_used_cmd[d->last_buffer] ].begin.branchAddress = cpu_to_le32((dma_prog_region_offset_to_bus(&d->prg_reg[v.buffer], 0) & 0xfffffff0) | 0x3); d->next_buffer[d->last_buffer] = v.buffer; } d->last_buffer = v.buffer; d->next_buffer[d->last_buffer] = -1; d->it_prg[d->last_buffer][d->last_used_cmd[d->last_buffer]].end.branchAddress = 0; spin_unlock_irqrestore(&d->lock,flags); if (!(reg_read(ohci, d->ctrlSet) & 0x8000)) { DBGMSG(ohci->host->id, "Starting iso transmit DMA ctx=%d", d->ctx); put_timestamp(ohci, d, d->last_buffer); /* Tell the controller where the first program is */ reg_write(ohci, d->cmdPtr, dma_prog_region_offset_to_bus(&d->prg_reg[v.buffer], 0) | 0x3); /* Run IT context */ reg_write(ohci, d->ctrlSet, 0x8000); } else { /* Wake up dma context if necessary */ if (!(reg_read(ohci, d->ctrlSet) & 0x400)) { PRINT(KERN_INFO, ohci->host->id, "Waking up iso transmit dma ctx=%d", d->ctx); put_timestamp(ohci, d, d->last_buffer); reg_write(ohci, d->ctrlSet, 0x1000); } } if (psizes) kfree(psizes); return 0; } case VIDEO1394_IOC_TALK_WAIT_BUFFER: { struct video1394_wait v; struct dma_iso_ctx *d; if (copy_from_user(&v, argp, sizeof(v))) return -EFAULT; d = find_ctx(&ctx->context_list, OHCI_ISO_TRANSMIT, v.channel); if (d == NULL) return -EFAULT; if ((v.buffer<0) || (v.buffer>d->num_desc)) { PRINT(KERN_ERR, ohci->host->id, "Buffer %d out of range",v.buffer); return -EFAULT; } switch(d->buffer_status[v.buffer]) { case VIDEO1394_BUFFER_READY: d->buffer_status[v.buffer]=VIDEO1394_BUFFER_FREE; return 0; case VIDEO1394_BUFFER_QUEUED:#if 1 while (d->buffer_status[v.buffer]!= VIDEO1394_BUFFER_READY) { interruptible_sleep_on(&d->waitq); if (signal_pending(current)) return -EINTR; }#else if (wait_event_interruptible(d->waitq, d->buffer_status[v.buffer] == VIDEO1394_BUFFER_READY) == -ERESTARTSYS) return -EINTR;#endif d->buffer_status[v.buffer]=VIDEO1394_BUFFER_FREE; return 0; default: PRINT(KERN_ERR, ohci->host->id, "Buffer %d is not queued",v.buffer); return -EFAULT; } } default: return -EINVAL; }}/* * This maps the vmalloced and reserved buffer to user space. * * FIXME: * - PAGE_READONLY should suffice!? * - remap_page_range is kind of inefficient for page by page remapping. * But e.g. pte_alloc() does not work in modules ... :-( */int video1394_mmap(struct file *file, struct vm_area_struct *vma){ struct file_ctx *ctx = (struct file_ctx *)file->private_data; int res = -EINVAL; lock_kernel(); if (ctx->current_ctx == NULL) { PRINT(KERN_ERR, ctx->ohci->host->id, "Current iso context not set"); } else res = dma_region_mmap(&ctx->current_ctx->dma, file, vma); unlock_kernel(); return res;}static int video1394_open(struct inode *inode, struct file *file){ int i = ieee1394_file_to_instance(file); struct ti_ohci *ohci; struct file_ctx *ctx; ohci = hpsb_get_hostinfo_bykey(&video1394_highlevel, i); if (ohci == NULL) return -EIO; ctx = kmalloc(sizeof(struct file_ctx), GFP_KERNEL); if (ctx == NULL) { PRINT(KERN_ERR, ohci->host->id, "Cannot malloc file_ctx"); return -ENOMEM; } memset(ctx, 0, sizeof(struct file_ctx)); ctx->ohci = ohci; INIT_LIST_HEAD(&ctx->context_list); ctx->current_ctx = NULL; file->private_data = ctx; return 0;}static int video1394_release(struct inode *inode, struct file *file){ struct file_ctx *ctx = (struct file_ctx *)file->private_data; struct ti_ohci *ohci = ctx->ohci; struct list_head *lh, *next; u64 mask; lock_kernel(); list_for_each_safe(lh, next, &ctx->context_list) { struct dma_iso_ctx *d; d = list_entry(lh, struct dma_iso_ctx, link); mask = (u64) 1 << d->channel; if (!(ohci->ISO_channel_usage & mask)) PRINT(KERN_ERR, ohci->host->id, "On release: Channel %d " "is not being used", d->channel); else ohci->ISO_channel_usage &= ~mask; PRINT(KERN_INFO, ohci->host->id, "On release: Iso %s context " "%d stop listening on channel %d", d->type == OHCI_ISO_RECEIVE ? "receive" : "transmit", d->ctx, d->channel); free_dma_iso_ctx(d); } kfree(ctx); file->private_data = NULL; unlock_kernel(); return 0;}static struct cdev video1394_cdev;static struct file_operations video1394_fops={ .owner = THIS_MODULE, .ioctl = video1394_ioctl, .mmap = video1394_mmap, .open = video1394_open, .release = video1394_release};/*** HOTPLUG STUFF **********************************************************//* * Export information about protocols/devices supported by this driver. */static struct ieee1394_device_id video1394_id_table[] = { { .match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION, .specifier_id = CAMERA_UNIT_SPEC_ID_ENTRY & 0xffffff, .version = CAMERA_SW_VERSION_ENTRY & 0xffffff }, { }};MODULE_DEVICE_TABLE(ieee1394, video1394_id_table);static struct hpsb_protocol_driver video1394_driver = { .name = "1394 Digital Camera Driver", .id_table = video1394_id_table, .driver = { .name = VIDEO1394_DRIVER_NAME, .bus = &ieee1394_bus_type, },};static void video1394_add_host (struct hpsb_host *host){ struct ti_ohci *ohci; int minor; /* We only work with the OHCI-1394 driver */ if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME)) return; ohci = (struct ti_ohci *)host->hostdata; if (!hpsb_create_hostinfo(&video1394_highlevel, host, 0)) { PRINT(KERN_ERR, ohci->host->id, "Cannot allocate hostinfo"); return; } hpsb_set_hostinfo(&video1394_highlevel, host, ohci); hpsb_set_hostinfo_key(&video1394_highlevel, host, ohci->host->id); minor = IEEE1394_MINOR_BLOCK_VIDEO1394 * 16 + ohci->host->id; devfs_mk_cdev(MKDEV(IEEE1394_MAJOR, minor), S_IFCHR | S_IRUSR | S_IWUSR, "%s/%d", VIDEO1394_DRIVER_NAME, ohci->host->id);}static void video1394_remove_host (struct hpsb_host *host){ struct ti_ohci *ohci = hpsb_get_hostinfo(&video1394_highlevel, host); if (ohci) devfs_remove("%s/%d", VIDEO1394_DRIVER_NAME, ohci->host->id); return;}static struct hpsb_highlevel video1394_highlevel = { .name = VIDEO1394_DRIVER_NAME, .add_host = video1394_add_host, .remove_host = video1394_remove_host,};MODULE_AUTHOR("Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>");MODULE_DESCRIPTION("driver for digital video on OHCI board");MODULE_SUPPORTED_DEVICE(VIDEO1394_DRIVER_NAME);MODULE_LICENSE("GPL");#ifdef CONFIG_COMPAT#define VIDEO1394_IOC32_LISTEN_QUEUE_BUFFER \ _IOW ('#', 0x12, struct video1394_wait32)#define VIDEO1394_IOC32_LISTEN_WAIT_BUFFER \ _IOWR('#', 0x13, struct video1394_wait32)#define VIDEO1394_IOC32_TALK_WAIT_BUFFER \ _IOW ('#', 0x17, struct video1394_wait32)#define VIDEO1394_IOC32_LISTEN_POLL_BUFFER \ _IOWR('#', 0x18, struct video1394_wait32)struct video1394_wait32 { u32 channel; u32 buffer; struct compat_timeval filltime;};static int video1394_wr_wait32(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file){ struct video1394_wait32 __user *argp = (void __user *)arg; struct video1394_wait32 wait32; struct video1394_wait wait; mm_segment_t old_fs; int ret; if (file->f_op->ioctl != video1394_ioctl) return -EFAULT; if (copy_from_user(&wait32, argp, sizeof(wait32))) return -EFAULT; wait.channel = wait32.channel; wait.buffer = wait32.buffer; wait.filltime.tv_sec = (time_t)wait32.filltime.tv_sec; wait.filltime.tv_usec = (suseconds_t)wait32.filltime.tv_usec; old_fs = get_fs(); set_fs(KERNEL_DS); if (cmd == VIDEO1394_IOC32_LISTEN_WAIT_BUFFER) ret = video1394_ioctl(file->f_dentry->d_inode, file, VIDEO1394_IOC_LISTEN_WAIT_BUFFER, (unsigned long) &wait); else ret = video1394_ioctl(file->f_dentry->d_inode, file, VIDEO1394_IOC_LISTEN_POLL_BUFFER, (unsigned long) &wait); set_fs(old_fs); if (!ret) { wait32.channel = wait.channel; wait32.buffer = wait.buffer; wait32.filltime.tv_sec = (int)wait.filltime.tv_sec; wait32.filltime.tv_usec = (int)wait.filltime.tv_usec; if (copy_to_user(argp, &wait32, sizeof(wait32))) ret = -EFAULT; } return ret;}static int video1394_w_wait32(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file){ struct video1394_wait32 wait32; struct video1394_wait wait; mm_segment_t old_fs; int ret; if (file->f_op->ioctl != video1394_ioctl) return -EFAULT; if (copy_from_user(&wait32, (void __user *)arg, sizeof(wait32))) return -EFAULT; wait.channel = wait32.channel; wait.buffer = wait32.buffer; wait.filltime.tv_sec = (time_t)wait32.filltime.tv_sec; wait.filltime.tv_usec = (suseconds_t)wait32.filltime.tv_usec; old_fs = get_fs(); set_fs(KERNEL_DS); if (cmd == VIDEO1394_IOC32_LISTEN_QUEUE_BUFFER) ret = video1394_ioctl(file->f_dentry->d_inode, file, VIDEO1394_IOC_LISTEN_QUEUE_BUFFER, (unsigned long) &wait); else ret = video1394_ioctl(file->f_dentry->d_inode, file, VIDEO1394_IOC_TALK_WAIT_BUFFER, (unsigned long) &wait); set_fs(old_fs); return ret;}static int video1394_queue_buf32(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file){ if (file->f_op->ioctl != video1394_ioctl) return -EFAULT; return -EFAULT; return video1394_ioctl(file->f_dentry->d_inode, file, VIDEO1394_IOC_TALK_QUEUE_BUFFER, arg);}#endif /* CONFIG_COMPAT */static void __exit video1394_exit_module (void){#ifdef CONFIG_COMPAT int ret; ret = unregister_ioctl32_conversion(VIDEO1394_IOC_LISTEN_CHANNEL); ret |= unregister_ioctl32_conversion(VIDEO1394_IOC_UNLISTEN_CHANNEL); ret |= unregister_ioctl32_conversion(VIDEO1394_IOC_TALK_CHANNEL); ret |= unregister_ioctl32_conversion(VIDEO1394_IOC_UNTALK_CHANNEL); ret |= unregister_ioctl32_conversion(VIDEO1394_IOC32_LISTEN_QUEUE_BUFFER); ret |= unregister_ioctl32_conversion(VIDEO1394_IOC32_LISTEN_WAIT_BUFFER); ret |= unregister_ioctl32_conversion(VIDEO1394_IOC_TALK_QUEUE_BUFFER); ret |= unregister_ioctl32_conversion(VIDEO1394_IOC32_TALK_WAIT_BUFFER); ret |= unregister_ioctl32_conversion(VIDEO1394_IOC32_LISTEN_POLL_BUFFER); if (ret) PRINT_G(KERN_CRIT, "Error unregistering ioctl32 translations");#endif hpsb_unregister_protocol(&video1394_driver); hpsb_unregister_highlevel(&video1394_highlevel); devfs_remove(VIDEO1394_DRIVER_NAME); cdev_del(&video1394_cdev); PRINT_G(KERN_INFO, "Removed " VIDEO1394_DRIVER_NAME " module");}static int __init video1394_init_module (void){ int ret; cdev_init(&video1394_cdev, &video1394_fops); video1394_cdev.owner = THIS_MODULE; kobject_set_name(&video1394_cdev.kobj, VIDEO1394_DRIVER_NAME); ret = cdev_add(&video1394_cdev, IEEE1394_VIDEO1394_DEV, 16); if (ret) { PRINT_G(KERN_ERR, "video1394: unable to get minor device block"); return ret; } devfs_mk_dir(VIDEO1394_DRIVER_NAME); hpsb_register_highlevel(&video1394_highlevel); ret = hpsb_register_protocol(&video1394_driver); if (ret) { PRINT_G(KERN_ERR, "video1394: failed to register protocol"); hpsb_unregister_highlevel(&video1394_highlevel); devfs_remove(VIDEO1394_DRIVER_NAME); cdev_del(&video1394_cdev); return ret; }#ifdef CONFIG_COMPAT { /* First the compatible ones */ ret = register_ioctl32_conversion(VIDEO1394_IOC_LISTEN_CHANNEL, NULL); ret |= register_ioctl32_conversion(VIDEO1394_IOC_UNLISTEN_CHANNEL, NULL); ret |= register_ioctl32_conversion(VIDEO1394_IOC_TALK_CHANNEL, NULL); ret |= register_ioctl32_conversion(VIDEO1394_IOC_UNTALK_CHANNEL, NULL); /* These need translation */ ret |= register_ioctl32_conversion(VIDEO1394_IOC32_LISTEN_QUEUE_BUFFER, video1394_w_wait32); ret |= register_ioctl32_conversion(VIDEO1394_IOC32_LISTEN_WAIT_BUFFER, video1394_wr_wait32); ret |= register_ioctl32_conversion(VIDEO1394_IOC_TALK_QUEUE_BUFFER, video1394_queue_buf32); ret |= register_ioctl32_conversion(VIDEO1394_IOC32_TALK_WAIT_BUFFER, video1394_w_wait32); ret |= register_ioctl32_conversion(VIDEO1394_IOC32_LISTEN_POLL_BUFFER, video1394_wr_wait32); if (ret) PRINT_G(KERN_INFO, "Error registering ioctl32 translations"); }#endif PRINT_G(KERN_INFO, "Installed " VIDEO1394_DRIVER_NAME " module"); return 0;}module_init(video1394_init_module);module_exit(video1394_exit_module);MODULE_ALIAS_CHARDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_VIDEO1394 * 16);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -