📄 dv1394.c
字号:
target_frame = video->first_clear_frame; spin_unlock_irqrestore(&video->spinlock, flags); if (video->frames[target_frame]->state == FRAME_CLEAR) { /* how much room is left in the target frame buffer */ cnt = video->frame_size - (video->write_off - target_frame * video->frame_size); } else { /* buffer is already used */ cnt = 0; } if (cnt > count) cnt = count; if (cnt <= 0) { /* no room left, gotta wait */ if (file->f_flags & O_NONBLOCK) { if (!ret) ret = -EAGAIN; break; } if (signal_pending(current)) { if (!ret) ret = -ERESTARTSYS; break; } schedule(); continue; /* start over from 'while(count > 0)...' */ } if (copy_from_user(video->dv_buf.kvirt + video->write_off, buffer, cnt)) { if (!ret) ret = -EFAULT; break; } video->write_off = (video->write_off + cnt) % (video->n_frames * video->frame_size); count -= cnt; buffer += cnt; ret += cnt; if (video->write_off == video->frame_size * ((target_frame + 1) % video->n_frames)) frame_prepare(video, target_frame); } remove_wait_queue(&video->waitq, &wait); set_current_state(TASK_RUNNING); up(&video->sem); return ret;}static ssize_t dv1394_read(struct file *file, char *buffer, size_t count, loff_t *ppos){ struct video_card *video = file_to_video_card(file); DECLARE_WAITQUEUE(wait, current); ssize_t ret; size_t cnt; unsigned long flags; int target_frame; /* serialize this to prevent multi-threaded mayhem */ if (file->f_flags & O_NONBLOCK) { if (down_trylock(&video->sem)) return -EAGAIN; } else { if (down_interruptible(&video->sem)) return -ERESTARTSYS; } if ( !video_card_initialized(video) ) { ret = do_dv1394_init_default(video); if (ret) { up(&video->sem); return ret; } video->continuity_counter = -1; receive_packets(video); start_dma_receive(video); } ret = 0; add_wait_queue(&video->waitq, &wait); while (count > 0) { /* must set TASK_INTERRUPTIBLE *before* checking for free buffers; otherwise we could miss a wakeup if the interrupt fires between the check and the schedule() */ set_current_state(TASK_INTERRUPTIBLE); spin_lock_irqsave(&video->spinlock, flags); target_frame = video->first_clear_frame; spin_unlock_irqrestore(&video->spinlock, flags); if (target_frame >= 0 && video->n_clear_frames > 0 && video->frames[target_frame]->state == FRAME_CLEAR) { /* how much room is left in the target frame buffer */ cnt = video->frame_size - (video->write_off - target_frame * video->frame_size); } else { /* buffer is already used */ cnt = 0; } if (cnt > count) cnt = count; if (cnt <= 0) { /* no room left, gotta wait */ if (file->f_flags & O_NONBLOCK) { if (!ret) ret = -EAGAIN; break; } if (signal_pending(current)) { if (!ret) ret = -ERESTARTSYS; break; } schedule(); continue; /* start over from 'while(count > 0)...' */ } if (copy_to_user(buffer, video->dv_buf.kvirt + video->write_off, cnt)) { if (!ret) ret = -EFAULT; break; } video->write_off = (video->write_off + cnt) % (video->n_frames * video->frame_size); count -= cnt; buffer += cnt; ret += cnt; if (video->write_off == video->frame_size * ((target_frame + 1) % video->n_frames)) { spin_lock_irqsave(&video->spinlock, flags); video->n_clear_frames--; video->first_clear_frame = (video->first_clear_frame + 1) % video->n_frames; spin_unlock_irqrestore(&video->spinlock, flags); } } remove_wait_queue(&video->waitq, &wait); set_current_state(TASK_RUNNING); up(&video->sem); return ret;}/*** DEVICE IOCTL INTERFACE ************************************************//* I *think* the VFS serializes ioctl() for us, so we don't have to worry about situations like having two threads in here at once... */static int dv1394_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ struct video_card *video = file_to_video_card(file); unsigned long flags; int ret = -EINVAL; DECLARE_WAITQUEUE(wait, current); /* serialize this to prevent multi-threaded mayhem */ if (file->f_flags & O_NONBLOCK) { if (down_trylock(&video->sem)) return -EAGAIN; } else { if (down_interruptible(&video->sem)) return -ERESTARTSYS; } switch(cmd) { case DV1394_SUBMIT_FRAMES: case DV1394_IOC_SUBMIT_FRAMES: { unsigned int n_submit; if ( !video_card_initialized(video) ) { ret = do_dv1394_init_default(video); if (ret) goto out; } n_submit = (unsigned int) arg; if (n_submit > video->n_frames) { ret = -EINVAL; goto out; } while (n_submit > 0) { add_wait_queue(&video->waitq, &wait); set_current_state(TASK_INTERRUPTIBLE); spin_lock_irqsave(&video->spinlock, flags); /* wait until video->first_clear_frame is really CLEAR */ while (video->frames[video->first_clear_frame]->state != FRAME_CLEAR) { 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); frame_prepare(video, video->first_clear_frame); n_submit--; } ret = 0; break; } case DV1394_WAIT_FRAMES: case DV1394_IOC_WAIT_FRAMES: { unsigned int n_wait; if ( !video_card_initialized(video) ) { ret = -EINVAL; goto out; } n_wait = (unsigned int) arg; /* since we re-run the last frame on underflow, we will never actually have n_frames clear frames; at most only n_frames - 1 */ if (n_wait > (video->n_frames-1) ) { ret = -EINVAL; goto out; } 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: case DV1394_IOC_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: case DV1394_IOC_START_RECEIVE: { if ( !video_card_initialized(video) ) { ret = do_dv1394_init_default(video); if (ret) goto out; } video->continuity_counter = -1; receive_packets(video); start_dma_receive(video); ret = 0; break; } case DV1394_INIT: case DV1394_IOC_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: case DV1394_IOC_SHUTDOWN: do_dv1394_shutdown(video, 0); ret = 0; break; case DV1394_GET_STATUS: case DV1394_IOC_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) == 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; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -