📄 dv1394.c
字号:
static int dv1394_fasync(int fd, struct file *file, int on)
{
/* I just copied this code verbatim from Alan Cox's mouse driver example
(Documentation/DocBook/) */
struct video_card *video = file_to_video_card(file);
int retval = fasync_helper(fd, file, on, &video->fasync);
if (retval < 0)
return retval;
return 0;
}
static ssize_t dv1394_write(struct file *file, const 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;
}
}
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 (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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -