📄 dv1394.c
字号:
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 (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); mutex_unlock(&video->mtx); return ret;}static ssize_t dv1394_read(struct file *file, char __user *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 (!mutex_trylock(&video->mtx)) return -EAGAIN; } else { if (mutex_lock_interruptible(&video->mtx)) return -ERESTARTSYS; } if ( !video_card_initialized(video) ) { ret = do_dv1394_init_default(video); if (ret) { mutex_unlock(&video->mtx); 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); mutex_unlock(&video->mtx); return ret;}/*** DEVICE IOCTL INTERFACE ************************************************/static long dv1394_ioctl(struct file *file, unsigned int cmd, unsigned long arg){ struct video_card *video = file_to_video_card(file); unsigned long flags; int ret = -EINVAL; void __user *argp = (void __user *)arg; DECLARE_WAITQUEUE(wait, current); /* serialize this to prevent multi-threaded mayhem */ if (file->f_flags & O_NONBLOCK) { if (!mutex_trylock(&video->mtx)) return -EAGAIN; } else { if (mutex_lock_interruptible(&video->mtx)) return -ERESTARTSYS; } switch(cmd) { 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_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_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_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_IOC_INIT: { struct dv1394_init init; if (!argp) { ret = do_dv1394_init_default(video); } else { if (copy_from_user(&init, argp, sizeof(init))) { ret = -EFAULT; goto out; } ret = do_dv1394_init(video, &init); } break; } case DV1394_IOC_SHUTDOWN: do_dv1394_shutdown(video, 0); ret = 0; break; 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(argp, &status, sizeof(status))) { ret = -EFAULT; goto out; } ret = 0; break; } default: break; } out: mutex_unlock(&video->mtx); return ret;}/*** DEVICE FILE INTERFACE CONTINUED ***************************************/static int dv1394_open(struct inode *inode, struct file *file){ struct video_card *video = NULL; if (file->private_data) { video = (struct video_card*) file->private_data; } else { /* look up the card by ID */ unsigned long flags; spin_lock_irqsave(&dv1394_cards_lock, flags); if (!list_empty(&dv1394_cards)) { struct video_card *p; list_for_each_entry(p, &dv1394_cards, 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 + -