📄 dv1394.c
字号:
add_wait_queue(&video->waitq, &wait); set_current_state(TASK_INTERRUPTIBLE); spin_lock_irqsave(&video->spinlock, flags); while(video->n_clear_frames < n_wait) { spin_unlock_irqrestore(&video->spinlock, flags); if(signal_pending(current)) { remove_wait_queue(&video->waitq, &wait); set_current_state(TASK_RUNNING); ret = -EINTR; goto out; } schedule(); set_current_state(TASK_INTERRUPTIBLE); spin_lock_irqsave(&video->spinlock, flags); } spin_unlock_irqrestore(&video->spinlock, flags); remove_wait_queue(&video->waitq, &wait); set_current_state(TASK_RUNNING); ret = 0; break; } case DV1394_RECEIVE_FRAMES: { unsigned int n_recv; if( !video_card_initialized(video) ) { ret = -EINVAL; goto out; } n_recv = (unsigned int) arg; /* at least one frame must be active */ if(n_recv > (video->n_frames-1) ) { ret = -EINVAL; goto out; } spin_lock_irqsave(&video->spinlock, flags); /* release the clear frames */ video->n_clear_frames -= n_recv; /* advance the clear frame cursor */ video->first_clear_frame = (video->first_clear_frame + n_recv) % video->n_frames; /* reset dropped_frames */ video->dropped_frames = 0; spin_unlock_irqrestore(&video->spinlock, flags); ret = 0; break; } case DV1394_START_RECEIVE: { if( !video_card_initialized(video) ) { ret = do_dv1394_init_default(video); if(ret) goto out; } receive_packets(video, video->frames[video->first_clear_frame]); ret = 0; break; } case DV1394_INIT: { struct dv1394_init init; if(arg == (unsigned long) NULL) { ret = do_dv1394_init_default(video); } else { if(copy_from_user(&init, (void*)arg, sizeof(init))) { ret = -EFAULT; goto out; } ret = do_dv1394_init(video, &init); } break; } case DV1394_SHUTDOWN: ret = do_dv1394_shutdown(video, 0); break; case DV1394_GET_STATUS: { struct dv1394_status status; if( !video_card_initialized(video) ) { ret = -EINVAL; goto out; } status.init.api_version = DV1394_API_VERSION; status.init.channel = video->channel; status.init.n_frames = video->n_frames; status.init.format = video->pal_or_ntsc; status.init.cip_n = video->cip_n; status.init.cip_d = video->cip_d; status.init.syt_offset = video->syt_offset; status.first_clear_frame = video->first_clear_frame; /* the rest of the fields need to be locked against the interrupt */ spin_lock_irqsave(&video->spinlock, flags); status.active_frame = video->active_frame; status.n_clear_frames = video->n_clear_frames; status.dropped_frames = video->dropped_frames; /* reset dropped_frames */ video->dropped_frames = 0; spin_unlock_irqrestore(&video->spinlock, flags); if(copy_to_user((void*)arg, &status, sizeof(status))) { ret = -EFAULT; goto out; } ret = 0; break; } default: break; } out: up(&video->sem); return ret;}/*** DEVICE FILE INTERFACE CONTINUED ***************************************/static int dv1394_open(struct inode *inode, struct file *file){ struct video_card *video = NULL; /* if the device was opened through devfs, then file->private_data has already been set to video by devfs */ if(file->private_data) { video = (struct video_card*) file->private_data; } else { /* look up the card by ID */ struct list_head *lh; unsigned long flags; spin_lock_irqsave(&dv1394_cards_lock, flags); if(!list_empty(&dv1394_cards)) { struct video_card *p; list_for_each(lh, &dv1394_cards) { p = list_entry(lh, struct video_card, list); if((p->id >> 2) == ieee1394_file_to_instance(file)) { video = p; break; } } } spin_unlock_irqrestore(&dv1394_cards_lock, flags); if(!video) { debug_printk("dv1394: OHCI card %d not found", ieee1394_file_to_instance(file)); return -ENODEV; } file->private_data = (void*) video; } #ifndef DV1394_ALLOW_MORE_THAN_ONE_OPEN if( test_and_set_bit(0, &video->open) ) { /* video is already open by someone else */ return -EBUSY; }#endif return 0;}static int dv1394_release(struct inode *inode, struct file *file){ struct video_card *video = file_to_video_card(file); /* OK to free the DMA buffer, no more mappings can exist */ do_dv1394_shutdown(video, 1); /* clean up async I/O users */ dv1394_fasync(-1, file, 0); /* give someone else a turn */ clear_bit(0, &video->open); return 0;}/*** PROC_FS INTERFACE ******************************************************/#ifdef CONFIG_PROC_FSstatic LIST_HEAD(dv1394_procfs);struct dv1394_procfs_entry { struct list_head list; struct proc_dir_entry *procfs; char name[32]; struct dv1394_procfs_entry *parent;};static spinlock_t dv1394_procfs_lock = SPIN_LOCK_UNLOCKED;static int dv1394_procfs_read( char *page, char **start, off_t off, int count, int *eof, void *data){ struct video_card *video = (struct video_card*) data; snprintf( page, count, "\format=%s\n\channel=%d\n\cip_n=%lu\n\cip_d=%lu\n\syt_offset=%u\n", (video->pal_or_ntsc == DV1394_NTSC ? "NTSC" : "PAL"), video->channel, video->cip_n, video->cip_d, video->syt_offset ); return strlen(page);}/* lifted from the stallion.c driver */#undef TOLOWER#define TOLOWER(x) ((((x) >= 'A') && ((x) <= 'Z')) ? ((x) + 0x20) : (x))static unsigned long atol(char *str){ unsigned long val; int base, c; char *sp; val = 0; sp = str; if ((*sp == '0') && (*(sp+1) == 'x')) { base = 16; sp += 2; } else if (*sp == '0') { base = 8; sp++; } else { base = 10; } for (; (*sp != 0); sp++) { c = (*sp > '9') ? (TOLOWER(*sp) - 'a' + 10) : (*sp - '0'); if ((c < 0) || (c >= base)) { printk(KERN_ERR "dv1394: atol() invalid argument %s\n", str); val = 0; break; } val = (val * base) + c; } return(val);}static int dv1394_procfs_write( struct file *file, const char *buffer, unsigned long count, void *data){ int len = 0; char new_value[65]; char *pos; struct video_card *video = (struct video_card*) data; if (count > 64) len = 64; else len = count; if (copy_from_user( new_value, buffer, len)) return -EFAULT; new_value[len] = 0; pos = strchr(new_value, '='); if (pos != NULL) { int val_len = len - (pos-new_value) - 1; char buf[65]; memset(buf, 0, 65); strncpy(buf, pos+1, val_len); if (buf[val_len-1] == '\n') buf[val_len-1] = 0; if (strnicmp( new_value, "format", (pos-new_value)) == 0) { if (strnicmp( buf, "NTSC", val_len) == 0) video->pal_or_ntsc = DV1394_NTSC; else if (strnicmp( buf, "PAL", val_len) == 0) video->pal_or_ntsc = DV1394_PAL; } else if (strnicmp( new_value, "cip_n", (pos-new_value)) == 0) { video->cip_n = atol(buf); } else if (strnicmp( new_value, "cip_d", (pos-new_value)) == 0) { video->cip_d = atol(buf); } else if (strnicmp( new_value, "syt_offset", (pos-new_value)) == 0) { video->syt_offset = atol(buf); } else if (strnicmp( new_value, "channel", (pos-new_value)) == 0) { video->channel = atol(buf); } } return len;}struct dv1394_procfs_entry *dv1394_procfs_find( char *name){ struct list_head *lh; struct dv1394_procfs_entry *p; spin_lock( &dv1394_procfs_lock); if(!list_empty(&dv1394_procfs)) { list_for_each(lh, &dv1394_procfs) { p = list_entry(lh, struct dv1394_procfs_entry, list); if(!strncmp(p->name, name, sizeof(p->name))) { spin_unlock( &dv1394_procfs_lock); return p; } } } spin_unlock( &dv1394_procfs_lock); return NULL;}static int dv1394_procfs_add_entry(struct video_card *video){ char buf[32]; struct dv1394_procfs_entry *p; struct dv1394_procfs_entry *parent; p = kmalloc(sizeof(struct dv1394_procfs_entry), GFP_KERNEL); if(!p) { printk(KERN_ERR "dv1394: cannot allocate dv1394_procfs_entry\n"); goto err; } memset(p, 0, sizeof(struct dv1394_procfs_entry)); snprintf(buf, sizeof(buf), "dv/host%d/%s", (video->id>>2), (video->pal_or_ntsc == DV1394_NTSC ? "NTSC" : "PAL")); parent = dv1394_procfs_find(buf); if (parent == NULL) { printk(KERN_ERR "dv1394: unable to locate parent procfs of %s\n", buf); goto err_free; } p->procfs = create_proc_entry( (video->mode == MODE_RECEIVE ? "in" : "out"), 0666, parent->procfs); if (p->procfs == NULL) { printk(KERN_ERR "dv1394: unable to create /proc/bus/ieee1394/%s/%s\n", parent->name, (video->mode == MODE_RECEIVE ? "in" : "out")); goto err_free; } p->procfs->owner = THIS_MODULE; p->procfs->data = video; p->procfs->read_proc = dv1394_procfs_read; p->procfs->write_proc = dv1394_procfs_write; spin_lock( &dv1394_procfs_lock); INIT_LIST_HEAD(&p->list); list_add_tail(&p->list, &dv1394_procfs); spin_unlock( &dv1394_procfs_lock); return 0; err_free: kfree(p); err: return -ENOMEM;}static intdv1394_procfs_add_dir( char *name, struct dv1394_procfs_entry *parent, struct dv1394_procfs_entry **out){ struct dv1394_procfs_entry *p; p = kmalloc(sizeof(struct dv1394_procfs_entry), GFP_KERNEL); if(!p) { printk(KERN_ERR "dv1394: cannot allocate dv1394_procfs_entry\n"); goto err; } memset(p, 0, sizeof(struct dv1394_procfs_entry)); if (parent == NULL) { snprintf(p->name, sizeof(p->name), "%s", name); p->procfs = proc_mkdir( name, ieee1394_procfs_entry); } else { snprintf(p->name, sizeof(p->name), "%s/%s", parent->name, name); p->procfs = proc_mkdir( name, parent->procfs); } if (p->procfs == NULL) { printk(KERN_ERR "dv1394: unable to create /proc/bus/ieee1394/%s\n", p->name); goto err_free; } p->procfs->owner = THIS_MODULE; p->parent = parent; if (out != NULL) *out = p; spin_lock( &dv1394_procfs_lock); INIT_LIST_HEAD(&p->list); list_add_tail(&p->list, &dv1394_procfs); spin_unlock( &dv1394_procfs_lock); return 0; err_free: kfree(p); err: return -ENOMEM;}void dv1394_procfs_del( char *name){ struct dv1394_procfs_entry *p = dv1394_procfs_find(name); if (p != NULL) { if (p->parent == NULL) remove_proc_entry(p->name, ieee1394_procfs_entry); else remove_proc_entry(p->name, p->parent->procfs); spin_lock( &dv1394_procfs_lock); list_del(&p->list); spin_unlock( &dv1394_procfs_lock); kfree(p); }}#endif /* CONFIG_PROC_FS *//*** DEVICE DRIVER HANDLERS ************************************************/static void it_tasklet_func(unsigned long data){ int wake = 0; struct video_card *video = (struct video_card*) data; spin_lock(&video->spinlock); irq_printk("INTERRUPT! Video = %08lx Iso event Recv: %08x Xmit: %08x\n", (unsigned long) video, isoRecvIntEvent, isoXmitIntEvent); irq_printk("ContextCont
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -