📄 video1394.c
字号:
reg_write(ohci, d->cmdPtr, virt_to_bus(&(d->ir_prg[v.buffer][0]))|0x1); /* Run IR 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->id, "Waking up iso dma ctx=%d", d->ctx); reg_write(ohci, d->ctrlSet, 0x1000); } } return 0; } case VIDEO1394_LISTEN_WAIT_BUFFER: { struct video1394_wait v; struct dma_iso_ctx *d; int i; if(copy_from_user(&v, (void *)arg, sizeof(v))) return -EFAULT; i = ir_ctx_listening(video, v.channel); if (i<0) return -EFAULT; d = video->ir_context[i]; if ((v.buffer<0) || (v.buffer>d->num_desc)) { PRINT(KERN_ERR, ohci->id, "buffer %d out of range",v.buffer); return -EFAULT; } /* * I change the way it works so that it returns * the last received frame. */ spin_lock_irqsave(&d->lock, flags); switch(d->buffer_status[v.buffer]) { case VIDEO1394_BUFFER_READY: d->buffer_status[v.buffer]=VIDEO1394_BUFFER_FREE; break; case VIDEO1394_BUFFER_QUEUED:#if 1 while(d->buffer_status[v.buffer]!= VIDEO1394_BUFFER_READY) { spin_unlock_irqrestore(&d->lock, flags); interruptible_sleep_on(&d->waitq); spin_lock_irqsave(&d->lock, flags); if(signal_pending(current)) { spin_unlock_irqrestore(&d->lock,flags); 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; break; default: PRINT(KERN_ERR, ohci->id, "buffer %d is not queued",v.buffer); spin_unlock_irqrestore(&d->lock, flags); return -EFAULT; } /* * Look ahead to see how many more buffers have been received */ i=0; while (d->buffer_status[(v.buffer+1)%d->num_desc]== VIDEO1394_BUFFER_READY) { v.buffer=(v.buffer+1)%d->num_desc; i++; } spin_unlock_irqrestore(&d->lock, flags); v.buffer=i; if(copy_to_user((void *)arg, &v, sizeof(v))) return -EFAULT; return 0; } case VIDEO1394_TALK_QUEUE_BUFFER: { struct video1394_wait v; struct dma_iso_ctx *d; int i; if(copy_from_user(&v, (void *)arg, sizeof(v))) return -EFAULT; i = it_ctx_talking(video, v.channel); if (i<0) return -EFAULT; d = video->it_context[i]; if ((v.buffer<0) || (v.buffer>d->num_desc)) { PRINT(KERN_ERR, ohci->id, "buffer %d out of range",v.buffer); return -EFAULT; } spin_lock_irqsave(&d->lock,flags); if (d->buffer_status[v.buffer]!=VIDEO1394_BUFFER_FREE) { PRINT(KERN_ERR, ohci->id, "buffer %d is already used",v.buffer); spin_unlock_irqrestore(&d->lock,flags); return -EFAULT; } d->buffer_status[v.buffer]=VIDEO1394_BUFFER_QUEUED; if (d->last_buffer>=0) { d->it_prg[d->last_buffer] [d->nb_cmd-1].end.branchAddress = (virt_to_bus(&(d->it_prg[v.buffer][0].begin.control)) & 0xfffffff0) | 0x3; d->it_prg[d->last_buffer] [d->nb_cmd-1].begin.branchAddress = (virt_to_bus(&(d->it_prg[v.buffer][0].begin.control)) & 0xfffffff0) | 0x3; } d->last_buffer = v.buffer; d->it_prg[d->last_buffer][d->nb_cmd-1].end.branchAddress = 0; spin_unlock_irqrestore(&d->lock,flags); if (!(reg_read(ohci, d->ctrlSet) & 0x8000)) { DBGMSG(ohci->id, "Starting iso transmit DMA ctx=%d", d->ctx); /* Tell the controller where the first program is */ reg_write(ohci, d->cmdPtr, virt_to_bus(&(d->it_prg[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->id, "Waking up iso transmit dma ctx=%d", d->ctx); reg_write(ohci, d->ctrlSet, 0x1000); } } return 0; } case VIDEO1394_TALK_WAIT_BUFFER: { struct video1394_wait v; struct dma_iso_ctx *d; int i; if(copy_from_user(&v, (void *)arg, sizeof(v))) return -EFAULT; i = it_ctx_talking(video, v.channel); if (i<0) return -EFAULT; d = video->it_context[i]; if ((v.buffer<0) || (v.buffer>d->num_desc)) { PRINT(KERN_ERR, ohci->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->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 video_card *video = &video_cards[MINOR(file->f_dentry->d_inode->i_rdev)]; struct ti_ohci *ohci; int res = -EINVAL; lock_kernel(); ohci = video->ohci; PRINT(KERN_INFO, ohci->id, "mmap"); if (video->current_ctx == NULL) { PRINT(KERN_ERR, ohci->id, "current iso context not set"); } else res = do_iso_mmap(ohci, video->current_ctx, (char *)vma->vm_start, (unsigned long)(vma->vm_end-vma->vm_start)); unlock_kernel(); return res;}static int video1394_open(struct inode *inode, struct file *file){ int i = MINOR(inode->i_rdev); if (i<0 || i>=num_of_video_cards) { PRINT(KERN_ERR, i, "ohci card %d not found", i); return -EIO; } V22_COMPAT_MOD_INC_USE_COUNT; PRINT(KERN_INFO, i, "open"); return 0;}static int video1394_release(struct inode *inode, struct file *file){ struct video_card *video = &video_cards[MINOR(inode->i_rdev)]; struct ti_ohci *ohci= video->ohci; u64 mask; int i; lock_kernel(); for (i=0;i<ohci->nb_iso_rcv_ctx-1;i++) if (video->ir_context[i]) { mask = (u64)0x1<<video->ir_context[i]->channel; if (!(ohci->ISO_channel_usage & mask)) PRINT(KERN_ERR, ohci->id, "channel %d is not being used", video->ir_context[i]->channel); else ohci->ISO_channel_usage &= ~mask; PRINT(KERN_INFO, ohci->id, "iso receive context %d stop listening " "on channel %d", i+1, video->ir_context[i]->channel); free_dma_iso_ctx(&video->ir_context[i]); } for (i=0;i<ohci->nb_iso_xmit_ctx;i++) if (video->it_context[i]) { mask = (u64)0x1<<video->it_context[i]->channel; if (!(ohci->ISO_channel_usage & mask)) PRINT(KERN_ERR, ohci->id, "channel %d is not being used", video->it_context[i]->channel); else ohci->ISO_channel_usage &= ~mask; PRINT(KERN_INFO, ohci->id, "iso transmit context %d stop talking " "on channel %d", i+1, video->it_context[i]->channel); free_dma_iso_ctx(&video->it_context[i]); } V22_COMPAT_MOD_DEC_USE_COUNT; PRINT(KERN_INFO, ohci->id, "release"); unlock_kernel(); return 0;}void irq_handler(int card, quadlet_t isoRecvIntEvent, quadlet_t isoXmitIntEvent){ int i; struct video_card *video = &video_cards[card]; DBGMSG(card, "Iso event Recv: %08x Xmit: %08x", isoRecvIntEvent, isoXmitIntEvent); for (i=0;i<video->ohci->nb_iso_rcv_ctx-1;i++) if (isoRecvIntEvent & (1<<(i+1))) wakeup_dma_ir_ctx(video->ohci, video->ir_context[i]); for (i=0;i<video->ohci->nb_iso_xmit_ctx;i++) if (isoXmitIntEvent & (1<<i)) wakeup_dma_it_ctx(video->ohci, video->it_context[i]);}static struct file_operations video1394_fops={ OWNER_THIS_MODULE ioctl: video1394_ioctl, mmap: video1394_mmap, open: video1394_open, release: video1394_release};static int video1394_init(int i, struct ti_ohci *ohci){ struct video_card *video = &video_cards[i]; if (ohci1394_register_video(ohci, &video_tmpl)<0) { PRINT(KERN_ERR, i, "register_video failed"); return -1; } video->ohci = ohci; /* Iso receive dma contexts */ video->ir_context = (struct dma_iso_ctx **) kmalloc((ohci->nb_iso_rcv_ctx-1)* sizeof(struct dma_iso_ctx *), GFP_KERNEL); if (video->ir_context) memset(video->ir_context, 0, (ohci->nb_iso_rcv_ctx-1)*sizeof(struct dma_iso_ctx *)); else { PRINT(KERN_ERR, ohci->id, "Cannot allocate ir_context"); return -1; } /* Iso transmit dma contexts */ video->it_context = (struct dma_iso_ctx **) kmalloc(ohci->nb_iso_xmit_ctx * sizeof(struct dma_iso_ctx *), GFP_KERNEL); if (video->it_context) memset(video->it_context, 0, ohci->nb_iso_xmit_ctx * sizeof(struct dma_iso_ctx *)); else { PRINT(KERN_ERR, ohci->id, "Cannot allocate it_context"); return -1; } return 0;}static void remove_card(struct video_card *video){ int i; ohci1394_unregister_video(video->ohci, &video_tmpl); /* Free the iso receive contexts */ if (video->ir_context) { for (i=0;i<video->ohci->nb_iso_rcv_ctx-1;i++) { free_dma_iso_ctx(&video->ir_context[i]); } kfree(video->ir_context); } /* Free the iso transmit contexts */ if (video->it_context) { for (i=0;i<video->ohci->nb_iso_xmit_ctx;i++) { free_dma_iso_ctx(&video->it_context[i]); } kfree(video->it_context); }}#ifdef MODULE/* EXPORT_NO_SYMBOLS; */MODULE_AUTHOR("Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>");MODULE_DESCRIPTION("driver for digital video on OHCI board");MODULE_SUPPORTED_DEVICE("video1394");void cleanup_module(void){ int i; unregister_chrdev(VIDEO1394_MAJOR, VIDEO1394_DRIVER_NAME); for (i=0; i<num_of_video_cards; i++) remove_card(&video_cards[i]); printk(KERN_INFO "removed " VIDEO1394_DRIVER_NAME " module\n");}int init_module(void){ struct ti_ohci *ohci; int i; memset(video_cards, 0, MAX_OHCI1394_CARDS * sizeof(struct video_card)); num_of_video_cards = 0; for (i=0; i<MAX_OHCI1394_CARDS; i++) { ohci=ohci1394_get_struct(i); if (ohci) { num_of_video_cards++; video1394_init(i, ohci); } } if (!num_of_video_cards) { PRINT_G(KERN_INFO, "no ohci card found... init failed"); return -EIO; } if (register_chrdev(VIDEO1394_MAJOR, VIDEO1394_DRIVER_NAME, &video1394_fops)) { printk("video1394: unable to get major %d\n", VIDEO1394_MAJOR); return -EIO; } PRINT_G(KERN_INFO, "initialized with %d ohci cards", num_of_video_cards); return 0;}#endif /* MODULE */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -