📄 dv1394.c
字号:
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;
}
#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;
}
/*** 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);
if (!video->dma_running)
goto out;
irq_printk("ContextControl = %08x, CommandPtr = %08x\n",
reg_read(video->ohci, video->ohci_IsoXmitContextControlSet),
reg_read(video->ohci, video->ohci_IsoXmitCommandPtr)
);
if ( (video->ohci_it_ctx != -1) &&
(reg_read(video->ohci, video->ohci_IsoXmitContextControlSet) & (1 << 10)) ) {
struct frame *f;
unsigned int frame, i;
if (video->active_frame == -1)
frame = 0;
else
frame = video->active_frame;
/* check all the DMA-able frames */
for (i = 0; i < video->n_frames; i++, frame = (frame+1) % video->n_frames) {
irq_printk("IRQ checking frame %d...", frame);
f = video->frames[frame];
if (f->state != FRAME_READY) {
irq_printk("clear, skipping\n");
/* we don't own this frame */
continue;
}
irq_printk("DMA\n");
/* check the frame begin semaphore to see if we can free the previous frame */
if ( *(f->frame_begin_timestamp) ) {
int prev_frame;
struct frame *prev_f;
/* don't reset, need this later *(f->frame_begin_timestamp) = 0; */
irq_printk(" BEGIN\n");
prev_frame = frame - 1;
if (prev_frame == -1)
prev_frame += video->n_frames;
prev_f = video->frames[prev_frame];
/* make sure we can actually garbage collect
this frame */
if ( (prev_f->state == FRAME_READY) &&
prev_f->done && (!f->done) )
{
frame_reset(prev_f);
video->n_clear_frames++;
wake = 1;
video->active_frame = frame;
irq_printk(" BEGIN - freeing previous frame %d, new active frame is %d\n", prev_frame, frame);
} else {
irq_printk(" BEGIN - can't free yet\n");
}
f->done = 1;
}
/* see if we need to set the timestamp for the next frame */
if ( *(f->mid_frame_timestamp) ) {
struct frame *next_frame;
u32 begin_ts, ts_cyc, ts_off;
*(f->mid_frame_timestamp) = 0;
begin_ts = le32_to_cpu(*(f->frame_begin_timestamp));
irq_printk(" MIDDLE - first packet was sent at cycle %4u (%2u), assigned timestamp was (%2u) %4u\n",
begin_ts & 0x1FFF, begin_ts & 0xF,
f->assigned_timestamp >> 12, f->assigned_timestamp & 0xFFF);
/* prepare next frame and assign timestamp */
next_frame = video->frames[ (frame+1) % video->n_frames ];
if (next_frame->state == FRAME_READY) {
irq_printk(" MIDDLE - next frame is ready, good\n");
} else {
debug_printk("dv1394: Underflow! At least one frame has been dropped.\n");
next_frame = f;
}
/* set the timestamp to the timestamp of the last frame sent,
plus the length of the last frame sent, plus the syt latency */
ts_cyc = begin_ts & 0xF;
/* advance one frame, plus syt latency (typically 2-3) */
ts_cyc += f->n_packets + video->syt_offset ;
ts_off = 0;
ts_cyc += ts_off/3072;
ts_off %= 3072;
next_frame->assigned_timestamp = ((ts_cyc&0xF) << 12) + ts_off;
if (next_frame->cip_syt1) {
next_frame->cip_syt1->b[6] = next_frame->assigned_timestamp >> 8;
next_frame->cip_syt1->b[7] = next_frame->assigned_timestamp & 0xFF;
}
if (next_frame->cip_syt2) {
next_frame->cip_syt2->b[6] = next_frame->assigned_timestamp >> 8;
next_frame->cip_syt2->b[7] = next_frame->assigned_timestamp & 0xFF;
}
}
/* see if the frame looped */
if ( *(f->frame_end_timestamp) ) {
*(f->frame_end_timestamp) = 0;
debug_printk(" END - the frame looped at least once\n");
video->dropped_frames++;
}
} /* for (each frame) */
}
if (wake) {
kill_fasync(&video->fasync, SIGIO, POLL_OUT);
/* wake readers/writers/ioctl'ers */
wake_up_interruptible(&video->waitq);
}
out:
spin_unlock(&video->spinlock);
}
static void ir_tasklet_func(unsigned long data)
{
int wake = 0;
struct video_card *video = (struct video_card*) data;
spin_lock(&video->spinlock);
if (!video->dma_running)
goto out;
if ( (video->ohci_ir_ctx != -1) &&
(reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 10)) ) {
int sof=0; /* start-of-frame flag */
struct frame *f;
u16 packet_length, packet_time;
int i, dbc=0;
struct DMA_descriptor_block *block = NULL;
u16 xferstatus;
int next_i, prev_i;
struct DMA_descriptor_block *next = NULL;
dma_addr_t next_dma = 0;
struct DMA_descriptor_block *prev = NULL;
/* loop over all descriptors in all frames */
for (i = 0; i < video->n_frames*MAX_PACKETS; i++) {
struct packet *p = dma_region_i(&video->packet_buf, struct packet, video->current_packet);
/* make sure we are seeing the latest changes to p */
dma_region_sync_for_cpu(&video->packet_buf,
(unsigned long) p - (unsigned long) video->packet_buf.kvirt,
sizeof(struct packet));
packet_length = le16_to_cpu(p->data_length);
packet_time = le16_to_cpu(p->timestamp);
irq_printk("received packet %02d, timestamp=%04x, length=%04x, sof=%02x%02x\n", video->current_packet,
packet_time, packet_length,
p->data[0], p->data[1]);
/* get the descriptor based on packet_buffer cursor */
f = video->frames[video->current_packet / MAX_PACKETS];
block = &(f->descriptor_pool[video->current_packet % MAX_PACKETS]);
xferstatus = le32_to_cpu(block->u.in.il.q[3]) >> 16;
xferstatus &= 0x1F;
irq_printk("ir_tasklet_func: xferStatus/resCount [%d] = 0x%08x\n", i, le32_to_cpu(block->u.in.il.q[3]) );
/* get the current frame */
f = video->frames[video->active_frame];
/* exclude empty packet */
if (packet_length > 8 && xferstatus == 0x11) {
/* check for start of frame */
/* DRD> Changed to check section type ([0]>>5==0)
and dif sequence ([1]>>4==0) */
sof = ( (p->data[0] >> 5) == 0 && (p->data[1] >> 4) == 0);
dbc = (int) (p->cip_h1 >> 24);
if ( video->continuity_counter != -1 && dbc > ((video->continuity_counter + 1) % 256) )
{
printk(KERN_WARNING "dv1394: discontinuity detected, dropping all frames\n" );
video->dropped_frames += video->n_clear_frames + 1;
video->first_frame = 0;
video->n_clear_frames = 0;
video->first_clear_frame = -1;
}
video->continuity_counter = dbc;
if (!video->first_frame) {
if (sof) {
video->first_frame = 1;
}
} else if (sof) {
/* close current frame */
frame_reset(f); /* f->state = STATE_CLEAR */
video->n_clear_frames++;
if (video->n_clear_frames > video->n_frames) {
video->dropped_frames++;
printk(KERN_WARNING "dv1394: dropped a frame during reception\n" );
video->n_clear_frames = video->n_frames-1;
video->first_clear_frame = (video->first_clear_frame + 1) % video->n_frames;
}
if (video->first_clear_frame == -1)
video->first_clear_frame = video->active_frame;
/* get the next frame */
video->active_frame = (video->active_frame + 1) % video->n_frames;
f = video->frames[video->active_frame];
irq_printk(" frame received, active_frame = %d, n_clear_frames = %d, first_clear_frame = %d\n",
video->active_frame, video->n_clear_frames, video->first_clear_frame);
}
if (video->first_frame) {
if (sof) {
/* open next frame */
f->state = FRAME_READY;
}
/* copy to buffer */
if (f->n_packets > (video->frame_size / 480)) {
printk(KERN_ERR "frame buffer overflow during receive\n");
}
frame_put_packet(f, p);
} /* first_frame */
}
/* stop, end of ready packets */
else if (xferstatus == 0) {
break;
}
/* reset xferStatus & resCount */
block->u.in.il.q[3] = cpu_to_le32(512);
/* terminate dma chain at this (next) packet */
next_i = video->current_packet;
f = video->frames[next_i / MAX_PACKETS];
next = &(f->descriptor_pool[next_i % MAX_PACKETS]);
next_dma = ((unsigned long) block - (unsigned long) f->descriptor_pool) + f->descriptor_pool_dma;
next->u.in.il.q[0] |= 3 << 20; /* enable interrupt */
next->u.in.il.q[2] = 0; /* disable branch */
/* link previous to next */
prev_i = (next_i == 0) ? (MAX_PACKETS * video->n_frames - 1) : (next_i - 1);
f = video->frames[prev_i / MAX_PACKETS];
prev = &(f->descriptor_pool[prev_i % MAX_PACKETS]);
if (prev_i % (MAX_PACKETS/2)) {
prev->u.in.il.q[0] &= ~(3 << 20); /* no interrupt */
} else {
prev->u.in.il.q[0] |= 3 << 20; /* enable interrupt */
}
prev->u.in.il.q[2] = cpu_to_le32(next_dma | 1); /* set Z=1 */
wmb();
/* wake up DMA in case it fell asleep */
reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, (1 << 12));
/* advance packet_buffer cursor */
video->current_packet = (video->current_packet + 1) % (MAX_PACKETS * video->n_frames);
} /* for all packets */
wake = 1; /* why the hell not? */
} /* receive interrupt */
if (wake) {
kill_fasync(&video->fasync, SIGIO, POLL_IN);
/* wake readers/writers/ioctl'ers */
wake_up_interruptible(&video->waitq);
}
out:
spin_unlock(&video->spinlock);
}
static struct cdev dv1394_cdev;
static const struct file_operations dv1394_fops=
{
.owner = THIS_MODULE,
.poll = dv1394_poll,
.unlocked_ioctl = dv1394_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = dv1394_compat_ioctl,
#endif
.mmap = dv1394_mmap,
.open = dv1394_open,
.write = dv1394_write,
.read = dv1394_read,
.release = dv1394_release,
.fasync = dv1394_fasync,
};
/*** HOTPLUG STUFF **********************************************************/
/*
* Export information about protocols/devices supported by this driver.
*/
static struct ieee1394_device_id dv1394_id_table[] = {
{
.match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
.specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff,
.version = AVC_SW_VERSION_ENTRY & 0xffffff
},
{ }
};
MODULE_DEVICE_TABLE(ieee1394, dv1394_id_table);
static struct hpsb_protocol_driver dv1394_driver = {
.name = "dv1394",
.id_table = dv1394_id_table,
};
/*** IEEE1394
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -