📄 dv1394.c
字号:
}#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 HPSB CALLBACKS ***********************************************/static int dv1394_init(struct ti_ohci *ohci, enum pal_or_ntsc format, enum modes mode){ struct video_card *video; unsigned long flags; int i; video = kzalloc(sizeof(*video), GFP_KERNEL); if (!video) { printk(KERN_ERR "dv1394: cannot allocate video_card\n"); return -1; } video->ohci = ohci; /* lower 2 bits of id indicate which of four "plugs" per host */ video->id = ohci->host->id << 2; if (format == DV1394_NTSC) video->id |= mode; else video->id |= 2 + mode; video->ohci_it_ctx = -1; video->ohci_ir_ctx = -1; video->ohci_IsoXmitContextControlSet = 0; video->ohci_IsoXmitContextControlClear = 0; video->ohci_IsoXmitCommandPtr = 0; video->ohci_IsoRcvContextControlSet = 0; video->ohci_IsoRcvContextControlClear = 0; video->ohci_IsoRcvCommandPtr = 0; video->ohci_IsoRcvContextMatch = 0; video->n_frames = 0; /* flag that video is not initialized */ video->channel = 63; /* default to broadcast channel */ video->active_frame = -1; /* initialize the following */ video->pal_or_ntsc = format; video->cip_n = 0; /* 0 = use builtin default */ video->cip_d = 0; video->syt_offset = 0; video->mode = mode; for (i = 0; i < DV1394_MAX_FRAMES; i++) video->frames[i] = NULL; dma_region_init(&video->dv_buf); video->dv_buf_size = 0; dma_region_init(&video->packet_buf); video->packet_buf_size = 0; clear_bit(0, &video->open); spin_lock_init(&video->spinlock); video->dma_running = 0; mutex_init(&video->mtx); init_waitqueue_head(&video->waitq); video->fasync = NULL; spin_lock_irqsave(&dv1394_cards_lock, flags); INIT_LIST_HEAD(&video->list); list_add_tail(&video->list, &dv1394_cards); spin_unlock_irqrestore(&dv1394_cards_lock, flags); debug_printk("dv1394: dv1394_init() OK on ID %d\n", video->id); return 0;}static void dv1394_remove_host(struct hpsb_host *host){ struct video_card *video, *tmp_video; unsigned long flags; int found_ohci_card = 0; do { video = NULL; spin_lock_irqsave(&dv1394_cards_lock, flags); list_for_each_entry(tmp_video, &dv1394_cards, list) { if ((tmp_video->id >> 2) == host->id) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -