patch-2.4.21 linux-2.4.21/drivers/ieee1394/dv1394.c
Next file: linux-2.4.21/drivers/ieee1394/dv1394.h
Previous file: linux-2.4.21/drivers/ieee1394/dv1394-private.h
Back to the patch index
Back to the overall index
- Lines: 1463
- Date:
2003-06-13 07:51:34.000000000 -0700
- Orig file:
linux-2.4.20/drivers/ieee1394/dv1394.c
- Orig date:
2002-11-28 15:53:13.000000000 -0800
diff -urN linux-2.4.20/drivers/ieee1394/dv1394.c linux-2.4.21/drivers/ieee1394/dv1394.c
@@ -53,6 +53,12 @@
via pci_alloc_consistent()
DONE:
+ - during reception, better handling of dropped frames and continuity errors
+ - during reception, prevent DMA from bypassing the irq tasklets
+ - reduce irq rate during reception (1/250 packets).
+ - add many more internal buffers during reception with scatter/gather dma.
+ - add dbc (continuity) checking on receive, increment status.dropped_frames
+ if not continuous.
- restart IT DMA after a bus reset
- safely obtain and release ISO Tx channels in cooperation with OHCI driver
- map received DIF blocks to their proper location in DV frame (ensure
@@ -91,13 +97,12 @@
#include <linux/fs.h>
#include <linux/poll.h>
#include <linux/smp_lock.h>
+#include <linux/bitops.h>
#include <asm/byteorder.h>
#include <asm/atomic.h>
-#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/proc_fs.h>
-#include <linux/tqueue.h>
#include <linux/delay.h>
#include <asm/pgtable.h>
#include <asm/page.h>
@@ -109,6 +114,7 @@
#include "ieee1394.h"
#include "ieee1394_types.h"
+#include "ieee1394_hotplug.h"
#include "hosts.h"
#include "ieee1394_core.h"
#include "highlevel.h"
@@ -168,8 +174,6 @@
static LIST_HEAD(dv1394_cards);
static spinlock_t dv1394_cards_lock = SPIN_LOCK_UNLOCKED;
-static struct hpsb_highlevel *hl_handle; /* = NULL; */
-
static LIST_HEAD(dv1394_devfs);
struct dv1394_devfs_entry {
struct list_head list;
@@ -186,39 +190,6 @@
return (struct video_card*) file->private_data;
}
-
-/*******************************/
-/* Memory management functions */
-/*******************************/
-
-/* note: we no longer use mem_map_reserve, because it causes a memory
- leak, and setting vma->vm_flags to VM_RESERVED should be sufficient
- to pin the pages in memory anyway. */
-
-static void * rvmalloc(unsigned long size)
-{
- void * mem;
-
- mem = vmalloc_32(size);
-
- if(mem)
- memset(mem, 0, size); /* Clear the ram out,
- no junk to the user */
- return mem;
-}
-
-static void rvfree(void * mem, unsigned long size)
-{
- if (mem) {
- vfree(mem);
- }
-}
-
-/***********************************/
-/* END Memory management functions */
-/***********************************/
-
-
/*** FRAME METHODS *********************************************************/
static void frame_reset(struct frame *f)
@@ -447,11 +418,7 @@
/******************************/
/* first descriptor - OUTPUT_MORE_IMMEDIATE, for the controller's IT header */
- fill_output_more_immediate( &(block->u.out.omi),
- /* tag - what is this??? */ 1,
- video->channel,
- /* sync tag - what is this??? */ 0,
- payload_size);
+ fill_output_more_immediate( &(block->u.out.omi), 1, video->channel, 0, payload_size);
if(empty_packet) {
/* second descriptor - OUTPUT_LAST for CIP header */
@@ -502,8 +469,8 @@
PAGE_SIZE - (data_p % PAGE_SIZE),
/* DMA address of data_p */
- dma_offset_to_bus(&f->video->user_dma,
- data_p - (unsigned long) f->video->user_buf));
+ dma_region_offset_to_bus(&video->dv_buf,
+ data_p - (unsigned long) video->dv_buf.kvirt));
fill_output_last( &(block->u.out.u.full.u.cross.ol),
@@ -517,8 +484,8 @@
480 - (PAGE_SIZE - (data_p % PAGE_SIZE)),
/* DMA address of data_p + PAGE_SIZE - (data_p % PAGE_SIZE) */
- dma_offset_to_bus(&f->video->user_dma,
- data_p + PAGE_SIZE - (data_p % PAGE_SIZE) - (unsigned long) f->video->user_buf));
+ dma_region_offset_to_bus(&video->dv_buf,
+ data_p + PAGE_SIZE - (data_p % PAGE_SIZE) - (unsigned long) video->dv_buf.kvirt));
if(first_packet)
f->frame_begin_timestamp = &(block->u.out.u.full.u.cross.ol.q[3]);
@@ -552,8 +519,8 @@
/* DMA address of data_p */
- dma_offset_to_bus(&f->video->user_dma,
- data_p - (unsigned long) f->video->user_buf));
+ dma_region_offset_to_bus(&video->dv_buf,
+ data_p - (unsigned long) video->dv_buf.kvirt));
if(first_packet)
f->frame_begin_timestamp = &(block->u.out.u.full.u.nocross.ol.q[3]);
@@ -594,13 +561,8 @@
to loop back up to the top */
*(f->frame_end_branch) = cpu_to_le32(f->descriptor_pool_dma | f->first_n_descriptors);
-
- /* make the latest version of the frame buffer visible to the PCI card */
- /* could optimize this by only syncing the pages associated with this frame */
- pci_dma_sync_sg(video->ohci->dev,
- &video->user_dma.sglist[0],
- video->user_dma.n_dma_pages,
- PCI_DMA_TODEVICE);
+ /* make the latest version of this frame visible to the PCI card */
+ dma_region_sync(&video->dv_buf, f->data - (unsigned long) video->dv_buf.kvirt, video->frame_size);
/* lock against DMA interrupt */
spin_lock_irqsave(&video->spinlock, irq_flags);
@@ -732,7 +694,7 @@
wmb();
#endif
-
+ video->dma_running = 1;
/* set the 'run' bit */
reg_write(video->ohci, video->ohci_IsoXmitContextControlSet, 0x8000);
@@ -799,6 +761,9 @@
int dif_sequence = p->data[1] >> 4; /* dif sequence number is in bits 4 - 7 */
int dif_block = p->data[2];
+ /* sanity check */
+ if (dif_sequence > 11 || dif_block > 149) return;
+
switch (section_type) {
case 0: /* 1 Header block */
memcpy( (void *) f->data + dif_sequence * 150 * 80, p->data, 480);
@@ -826,47 +791,66 @@
}
-static void start_dma_receive(struct video_card *video, struct frame *frame)
+static void start_dma_receive(struct video_card *video)
{
- /* reset iso recv control register */
- reg_write(video->ohci, video->ohci_IsoRcvContextControlClear, 0xFFFFFFFF);
- wmb();
+ if (video->first_run == 1) {
+ video->first_run = 0;
+
+ /* start DMA once all of the frames are READY */
+ video->n_clear_frames = 0;
+ video->first_clear_frame = -1;
+ video->current_packet = 0;
+ video->active_frame = 0;
+
+ /* reset iso recv control register */
+ reg_write(video->ohci, video->ohci_IsoRcvContextControlClear, 0xFFFFFFFF);
+ wmb();
+
+ /* clear bufferFill, set isochHeader and speed (0=100) */
+ reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, 0x40000000);
- /* clear bufferFill, set isochHeader and speed (0=100) */
- reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, 0x40000000);
+ /* match on all tags, listen on channel */
+ reg_write(video->ohci, video->ohci_IsoRcvContextMatch, 0xf0000000 | video->channel);
+
+ /* address and first descriptor block + Z=1 */
+ reg_write(video->ohci, video->ohci_IsoRcvCommandPtr,
+ video->frames[0]->descriptor_pool_dma | 1); /* Z=1 */
+ wmb();
- /* match on all tags, listen on channel */
- reg_write(video->ohci, video->ohci_IsoRcvContextMatch, 0xf0000000 | video->channel);
-
- /* address and first descriptor block + Z=1 */
- reg_write(video->ohci, video->ohci_IsoRcvCommandPtr,
- frame->descriptor_pool_dma | 1); /* Z=1 */
- wmb();
-
- /* run */
- reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, 0x8000);
- flush_pci_write(video->ohci);
-
- debug_printk("dv1394: DMA started\n");
+ video->dma_running = 1;
-#if DV1394_DEBUG_LEVEL >= 2
- {
- int i;
+ /* run */
+ reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, 0x8000);
+ flush_pci_write(video->ohci);
+
+ debug_printk("dv1394: DMA started\n");
- for(i = 0; i < 1000; ++i) {
- mdelay(1);
- if(reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 10)) {
- printk("DMA ACTIVE after %d msec\n", i);
- break;
+#if DV1394_DEBUG_LEVEL >= 2
+ {
+ int i;
+
+ for(i = 0; i < 1000; ++i) {
+ mdelay(1);
+ if(reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 10)) {
+ printk("DMA ACTIVE after %d msec\n", i);
+ break;
+ }
}
+ if( reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 11) ) {
+ printk("DEAD, event = %x\n",
+ reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & 0x1F);
+ } else
+ printk("RUNNING!\n");
}
- if( reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 11) ) {
- printk("DEAD, event = %x\n",
- reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & 0x1F);
- } else
- printk("RUNNING!\n");
- }
#endif
+ }
+ else if( reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 11) ) {
+ debug_printk("DEAD, event = %x\n",
+ reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & 0x1F);
+
+ /* wake */
+ reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, (1 << 12));
+ }
}
@@ -874,7 +858,7 @@
receive_packets() - build the DMA program for receiving
*/
-static void receive_packets(struct video_card *video, struct frame *f)
+static void receive_packets(struct video_card *video)
{
struct DMA_descriptor_block *block = NULL;
dma_addr_t block_dma = 0;
@@ -882,52 +866,46 @@
dma_addr_t data_dma = 0;
u32 *last_branch_address = NULL;
unsigned long irq_flags;
+ int want_interrupt = 0;
+ struct frame *f = NULL;
+ int i, j;
spin_lock_irqsave(&video->spinlock, irq_flags);
- video->n_clear_frames = 0;
- video->first_clear_frame = -1;
+ for (j = 0; j < video->n_frames; j++) {
- for (video->current_packet = 0; video->current_packet < MAX_PACKET_BUFFER; ++video->current_packet) {
- /* locate a descriptor block and packet from the buffer */
- block = &(f->descriptor_pool[video->current_packet]);
- block_dma = ((unsigned long) block - (unsigned long) f->descriptor_pool) + f->descriptor_pool_dma;
-
- data = &(video->packet_buffer[video->current_packet]);
- data_dma = ((unsigned long) data - (unsigned long) video->packet_buffer) + video->packet_buffer_dma;
-
- /* setup DMA descriptor block */
- fill_input_last( &(block->u.in.il), 512, data_dma);
+ /* connect frames */
+ if (j > 0 && f != NULL && f->frame_end_branch != NULL)
+ *(f->frame_end_branch) = cpu_to_le32(video->frames[j]->descriptor_pool_dma | 1); /* set Z=1 */
- /* link descriptors */
- last_branch_address = f->frame_end_branch;
+ f = video->frames[j];
- if (last_branch_address)
- *(last_branch_address) = cpu_to_le32(block_dma | 1); /* set Z=1 */
-
- f->frame_end_branch = &(block->u.in.il.q[2]);
- }
+ for (i = 0; i < MAX_PACKETS; i++) {
+ /* locate a descriptor block and packet from the buffer */
+ block = &(f->descriptor_pool[i]);
+ block_dma = ((unsigned long) block - (unsigned long) f->descriptor_pool) + f->descriptor_pool_dma;
+
+ data = ((struct packet*)video->packet_buf.kvirt) + f->frame_num * MAX_PACKETS + i;
+ data_dma = dma_region_offset_to_bus( &video->packet_buf,
+ ((unsigned long) data - (unsigned long) video->packet_buf.kvirt) );
+
+ /* setup DMA descriptor block */
+ want_interrupt = ((i % (MAX_PACKETS/2)) == 0 || i == (MAX_PACKETS-1));
+ fill_input_last( &(block->u.in.il), want_interrupt, 512, data_dma);
+
+ /* link descriptors */
+ last_branch_address = f->frame_end_branch;
- /* loop tail to head */
- if (f->frame_end_branch)
- *(f->frame_end_branch) = cpu_to_le32(f->descriptor_pool_dma | 1); /* set Z=1 */
+ if (last_branch_address != NULL)
+ *(last_branch_address) = cpu_to_le32(block_dma | 1); /* set Z=1 */
+
+ f->frame_end_branch = &(block->u.in.il.q[2]);
+ }
+
+ } /* next j */
spin_unlock_irqrestore(&video->spinlock, irq_flags);
- if (video->first_run) {
- /* start DMA once all of the frames are READY */
- video->first_run = 0;
- video->current_packet = 0;
- video->active_frame = f->frame_num;
- start_dma_receive(video, f);
- }
- else if( reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 11) ) {
- debug_printk("DEAD, event = %x\n",
- reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & 0x1F);
-
- /* wake */
- reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, (1 << 12));
- }
}
@@ -941,15 +919,16 @@
u64 chan_mask;
int retval = -EINVAL;
+ debug_printk("dv1394: initialising %d\n", video->id);
if(init->api_version != DV1394_API_VERSION)
- goto err;
+ return -EINVAL;
/* first sanitize all the parameters */
if( (init->n_frames < 2) || (init->n_frames > DV1394_MAX_FRAMES) )
- goto err;
+ return -EINVAL;
if( (init->format != DV1394_NTSC) && (init->format != DV1394_PAL) )
- goto err;
+ return -EINVAL;
if( (init->syt_offset == 0) || (init->syt_offset > 50) )
/* default SYT offset is 3 cycles */
@@ -970,17 +949,15 @@
if(new_buf_size % PAGE_SIZE) new_buf_size += PAGE_SIZE - (new_buf_size % PAGE_SIZE);
/* don't allow the user to allocate the DMA buffer more than once */
- if( (video->user_buf) &&
- (video->user_buf_size != new_buf_size) ) {
- goto err;
+ if(video->dv_buf.kvirt && video->dv_buf_size != new_buf_size) {
+ printk("dv1394: re-sizing the DMA buffer is not allowed\n");
+ return -EINVAL;
}
-
+
/* shutdown the card if it's currently active */
/* (the card should not be reset if the parameters are screwy) */
- if( video_card_initialized(video) )
- do_dv1394_shutdown(video, 0);
-
+ do_dv1394_shutdown(video, 0);
/* try to claim the ISO channel */
spin_lock_irqsave(&video->ohci->IR_channel_lock, flags);
@@ -997,7 +974,6 @@
/* initialize misc. fields of video */
video->n_frames = init->n_frames;
video->pal_or_ntsc = init->format;
-
video->cip_accum = 0;
video->continuity_counter = 0;
@@ -1013,7 +989,6 @@
video->current_packet = -1;
video->first_frame = 0;
-
if(video->pal_or_ntsc == DV1394_NTSC) {
video->cip_n = init->cip_n != 0 ? init->cip_n : CIP_N_NTSC;
video->cip_d = init->cip_d != 0 ? init->cip_d : CIP_D_NTSC;
@@ -1026,14 +1001,8 @@
video->syt_offset = init->syt_offset;
-
/* find and claim DMA contexts on the OHCI card */
- /* XXX this should be the last step of initialization, since the interrupt
- handler uses ohci_i*_ctx to indicate whether or not it is safe to touch
- frames. I'm not making this change quite yet, since it would be better
- to clean up the init/shutdown process first.*/
-
if(video->ohci_it_ctx == -1) {
ohci1394_init_iso_tasklet(&video->it_tasklet, OHCI_ISO_TRANSMIT,
it_tasklet_func, (unsigned long) video);
@@ -1041,14 +1010,12 @@
if (ohci1394_register_iso_tasklet(video->ohci, &video->it_tasklet) < 0) {
printk(KERN_ERR "dv1394: could not find an available IT DMA context\n");
retval = -EBUSY;
- goto err_ctx;
- }
- else {
- video->ohci_it_ctx = video->it_tasklet.context;
- debug_printk("dv1394: claimed IT DMA context %d\n", video->ohci_it_ctx);
+ goto err;
}
+
+ video->ohci_it_ctx = video->it_tasklet.context;
+ debug_printk("dv1394: claimed IT DMA context %d\n", video->ohci_it_ctx);
}
-
if(video->ohci_ir_ctx == -1) {
ohci1394_init_iso_tasklet(&video->ir_tasklet, OHCI_ISO_RECEIVE,
@@ -1057,14 +1024,11 @@
if (ohci1394_register_iso_tasklet(video->ohci, &video->ir_tasklet) < 0) {
printk(KERN_ERR "dv1394: could not find an available IR DMA context\n");
retval = -EBUSY;
- goto err_ctx;
- }
- else {
- video->ohci_ir_ctx = video->ir_tasklet.context;
- debug_printk("dv1394: claimed IR DMA context %d\n", video->ohci_ir_ctx);
+ goto err;
}
+ video->ohci_ir_ctx = video->ir_tasklet.context;
+ debug_printk("dv1394: claimed IR DMA context %d\n", video->ohci_ir_ctx);
}
-
/* allocate struct frames */
for(i = 0; i < init->n_frames; i++) {
@@ -1073,97 +1037,43 @@
if(!video->frames[i]) {
printk(KERN_ERR "dv1394: Cannot allocate frame structs\n");
retval = -ENOMEM;
- goto err_frames;
+ goto err;
}
}
-
-
- if(video->user_buf == NULL) {
- unsigned int i;
-
+ if(!video->dv_buf.kvirt) {
/* allocate the ringbuffer */
- video->user_buf = rvmalloc(new_buf_size);
- if(!video->user_buf) {
- printk(KERN_ERR "dv1394: Cannot allocate frame buffers\n");
- goto err_frames;
- }
- video->user_buf_size = new_buf_size;
-
- /* allocate the sglist to hold the DMA addresses */
- video->user_dma.n_pages = video->user_buf_size / PAGE_SIZE;
- video->user_dma.sglist = kmalloc(video->user_dma.n_pages * sizeof(struct scatterlist), GFP_KERNEL);
- if(!video->user_dma.sglist) {
- printk(KERN_ERR "dv1394: Cannot allocate sglist for user buffer\n");
- goto err_user_buf;
- }
-
- /* initialize all fields of all sglist entries to zero
- (new requirement due to PCI changes in 2.4.13) */
-
- memset(video->user_dma.sglist, 0, video->user_dma.n_pages * sizeof(struct scatterlist));
+ retval = dma_region_alloc(&video->dv_buf, new_buf_size, video->ohci->dev, PCI_DMA_TODEVICE);
+ if(retval)
+ goto err;
+
+ video->dv_buf_size = new_buf_size;
-
- /* fill the sglist with the kernel addresses of pages in the non-contiguous buffer */
- for(i = 0; i < video->user_dma.n_pages; i++) {
- unsigned long va = (unsigned long) video->user_buf + i * PAGE_SIZE;
-
- video->user_dma.sglist[i].page = vmalloc_to_page((void *)va);
- video->user_dma.sglist[i].length = PAGE_SIZE;
- }
-
- /* map the buffer in the IOMMU */
- /* the user_data buffer only allows DMA *to* the card for transmission;
- incoming DV data comes through the packet_buffer first, and then is copied to user_data */
- video->user_dma.n_dma_pages = pci_map_sg(video->ohci->dev,
- &video->user_dma.sglist[0],
- video->user_dma.n_pages,
- PCI_DMA_TODEVICE);
- if(video->user_dma.n_dma_pages == 0) {
- printk(KERN_ERR "dv1394: Error mapping user buffer to the IOMMU\n");
- goto err_user_buf;
- }
-
debug_printk("dv1394: Allocated %d frame buffers, total %u pages (%u DMA pages), %lu bytes\n",
- video->n_frames, video->user_dma.n_pages,
- video->user_dma.n_dma_pages, video->user_buf_size);
+ video->n_frames, video->dv_buf.n_pages,
+ video->dv_buf.n_dma_pages, video->dv_buf_size);
}
/* set up the frame->data pointers */
for(i = 0; i < video->n_frames; i++)
- video->frames[i]->data = (unsigned long) video->user_buf + i * video->frame_size;
+ video->frames[i]->data = (unsigned long) video->dv_buf.kvirt + i * video->frame_size;
- /* allocate packet buffers */
- video->packet_buffer_size = sizeof(struct packet) * MAX_PACKET_BUFFER;
- if (video->packet_buffer_size % PAGE_SIZE)
- video->packet_buffer_size += PAGE_SIZE - (video->packet_buffer_size % PAGE_SIZE);
-
-
- video->packet_buffer = kmalloc(video->packet_buffer_size, GFP_KERNEL);
-
- if(!video->packet_buffer) {
- printk(KERN_ERR "dv1394: Cannot allocate packet buffers");
- retval = -ENOMEM;
- goto err_user_buf;
- }
-
- /* map the packet buffer into the IOMMU */
- video->packet_buffer_dma = pci_map_single(video->ohci->dev,
- video->packet_buffer,
- video->packet_buffer_size,
- PCI_DMA_FROMDEVICE);
- if(!video->packet_buffer_dma) {
- printk(KERN_ERR "dv1394: Cannot map packet buffer to IOMMU");
- kfree(video->packet_buffer);
- video->packet_buffer = NULL;
- retval = -ENOMEM;
- goto err_user_buf;
+ if(!video->packet_buf.kvirt) {
+ /* allocate packet buffer */
+ video->packet_buf_size = sizeof(struct packet) * video->n_frames * MAX_PACKETS;
+ if (video->packet_buf_size % PAGE_SIZE)
+ video->packet_buf_size += PAGE_SIZE - (video->packet_buf_size % PAGE_SIZE);
+
+ retval = dma_region_alloc(&video->packet_buf, video->packet_buf_size,
+ video->ohci->dev, PCI_DMA_FROMDEVICE);
+ if(retval)
+ goto err;
+
+ debug_printk("dv1394: Allocated %d packets in buffer, total %u pages (%u DMA pages), %lu bytes\n",
+ video->n_frames*MAX_PACKETS, video->packet_buf.n_pages,
+ video->packet_buf.n_dma_pages, video->packet_buf_size);
}
-
- debug_printk("dv1394: Allocated %d packet buffers for receive, total %lu bytes\n",
- MAX_PACKET_BUFFER, video->packet_buffer_size);
-
-
+
/* set up register offsets for IT context */
/* IT DMA context registers are spaced 16 bytes apart */
video->ohci_IsoXmitContextControlSet = OHCI1394_IsoXmitContextControlSet+16*video->ohci_it_ctx;
@@ -1187,47 +1097,8 @@
return 0;
- err_user_buf:
- if(video->user_buf) {
- if(video->user_dma.sglist) {
- if(video->user_dma.n_dma_pages > 0) {
- /* unmap it from the IOMMU */
- pci_unmap_sg(video->ohci->dev,
- video->user_dma.sglist,
- video->user_dma.n_pages,
- PCI_DMA_TODEVICE);
- video->user_dma.n_dma_pages = 0;
- }
- kfree(video->user_dma.sglist);
- video->user_dma.sglist = NULL;
- video->user_dma.n_pages = 0;
- }
- rvfree(video->user_buf, video->user_buf_size);
- video->user_buf = NULL;
- video->user_buf_size = 0;
- }
-
- err_frames:
- for(i = 0; i < DV1394_MAX_FRAMES; i++) {
- if(video->frames[i])
- frame_delete(video->frames[i]);
- }
- video->n_frames = 0;
-
- err_ctx:
- if(video->ohci_it_ctx != -1) {
- ohci1394_unregister_iso_tasklet(video->ohci, &video->it_tasklet);
- video->ohci_it_ctx = -1;
- }
- if(video->ohci_ir_ctx != -1) {
- ohci1394_unregister_iso_tasklet(video->ohci, &video->ir_tasklet);
- video->ohci_ir_ctx = -1;
- }
-
- spin_lock_irqsave(&video->ohci->IR_channel_lock, flags);
- video->ohci->ISO_channel_usage &= ~chan_mask;
- spin_unlock_irqrestore(&video->ohci->IR_channel_lock, flags);
- err:
+err:
+ do_dv1394_shutdown(video, 1);
return retval;
}
@@ -1239,7 +1110,7 @@
struct dv1394_init init;
init.api_version = DV1394_API_VERSION;
- init.n_frames = 2;
+ init.n_frames = DV1394_MAX_FRAMES / 4;
/* the following are now set via proc_fs or devfs */
init.channel = video->channel;
init.format = video->pal_or_ntsc;
@@ -1255,10 +1126,15 @@
{
unsigned long flags;
int i;
-
+
/* no interrupts */
spin_lock_irqsave(&video->spinlock, flags);
+ video->dma_running = 0;
+
+ if( (video->ohci_it_ctx == -1) && (video->ohci_ir_ctx == -1) )
+ goto out;
+
/* stop DMA if in progress */
if( (video->active_frame != -1) ||
(reg_read(video->ohci, video->ohci_IsoXmitContextControlClear) & (1 << 10)) ||
@@ -1271,7 +1147,6 @@
video->active_frame = -1;
video->first_run = 1;
-
/* wait until DMA really stops */
i = 0;
@@ -1283,6 +1158,7 @@
if( (reg_read(video->ohci, video->ohci_IsoXmitContextControlClear) & (1 << 10)) ||
(reg_read(video->ohci, video->ohci_IsoRcvContextControlClear) & (1 << 10)) ) {
/* still active */
+ debug_printk("dv1394: stop_dma: DMA not stopped yet\n" );
mb();
} else {
debug_printk("dv1394: stop_dma: DMA stopped safely after %d ms\n", i/10);
@@ -1296,24 +1172,24 @@
printk(KERN_ERR "dv1394: stop_dma: DMA still going after %d ms!\n", i/10);
}
}
+ else
+ debug_printk("dv1394: stop_dma: already stopped.\n");
+out:
spin_unlock_irqrestore(&video->spinlock, flags);
}
-static int do_dv1394_shutdown(struct video_card *video, int free_user_buf)
+static void do_dv1394_shutdown(struct video_card *video, int free_dv_buf)
{
int i;
- unsigned long flags;
debug_printk("dv1394: shutdown...\n");
/* stop DMA if in progress */
stop_dma(video);
- spin_lock_irqsave(&video->spinlock, flags);
-
/* release the DMA contexts */
if(video->ohci_it_ctx != -1) {
video->ohci_IsoXmitContextControlSet = 0;
@@ -1323,7 +1199,8 @@
/* disable interrupts for IT context */
reg_write(video->ohci, OHCI1394_IsoXmitIntMaskClear, (1 << video->ohci_it_ctx));
- clear_bit(video->ohci_it_ctx, &video->ohci->it_ctx_usage);
+ /* remove tasklet */
+ ohci1394_unregister_iso_tasklet(video->ohci, &video->it_tasklet);
debug_printk("dv1394: IT context %d released\n", video->ohci_it_ctx);
video->ohci_it_ctx = -1;
}
@@ -1337,13 +1214,12 @@
/* disable interrupts for IR context */
reg_write(video->ohci, OHCI1394_IsoRecvIntMaskClear, (1 << video->ohci_ir_ctx));
- clear_bit(video->ohci_ir_ctx, &video->ohci->ir_ctx_usage);
+ /* remove tasklet */
+ ohci1394_unregister_iso_tasklet(video->ohci, &video->ir_tasklet);
debug_printk("dv1394: IR context %d released\n", video->ohci_ir_ctx);
video->ohci_ir_ctx = -1;
}
- spin_unlock_irqrestore(&video->spinlock, flags);
-
/* release the ISO channel */
if(video->channel != -1) {
u64 chan_mask;
@@ -1370,42 +1246,18 @@
/* we can't free the DMA buffer unless it is guaranteed that
no more user-space mappings exist */
- if(free_user_buf && video->user_buf) {
- if(video->user_dma.sglist) {
- if(video->user_dma.n_dma_pages > 0) {
- /* unmap it from the IOMMU */
- pci_unmap_sg(video->ohci->dev,
- video->user_dma.sglist,
- video->user_dma.n_pages,
- PCI_DMA_TODEVICE);
- video->user_dma.n_dma_pages = 0;
- }
- kfree(video->user_dma.sglist);
- video->user_dma.sglist = NULL;
- video->user_dma.n_pages = 0;
- }
- rvfree(video->user_buf, video->user_buf_size);
- video->user_buf = NULL;
- video->user_buf_size = 0;
- }
-
- if (video->packet_buffer) {
- pci_unmap_single(video->ohci->dev,
- video->packet_buffer_dma,
- video->packet_buffer_size,
- PCI_DMA_FROMDEVICE);
- kfree(video->packet_buffer);
- video->packet_buffer = NULL;
- video->packet_buffer_size = 0;
+ if(free_dv_buf) {
+ dma_region_free(&video->dv_buf);
+ video->dv_buf_size = 0;
}
- debug_printk("dv1394: shutdown complete\n");
+ /* free packet buffer */
+ dma_region_free(&video->packet_buf);
+ video->packet_buf_size = 0;
- return 0;
+ debug_printk("dv1394: shutdown OK\n");
}
-
-
/*
**********************************
*** MMAP() THEORY OF OPERATION ***
@@ -1428,96 +1280,28 @@
force the user to choose one buffer size and stick with
it. This small sacrifice is worth the huge reduction in
error-prone code in dv1394.
-
- Note: dv1394_mmap does no page table manipulation. The page
- table entries are created by the dv1394_nopage() handler as
- page faults are taken by the user.
-*/
-
-static struct page * dv1394_nopage(struct vm_area_struct * area, unsigned long address, int write_access)
-{
- unsigned long offset;
- unsigned long kernel_virt_addr;
- struct page *ret = NOPAGE_SIGBUS;
-
- struct video_card *video = (struct video_card*) area->vm_private_data;
-
- /* guard against process-context operations and the interrupt */
- /* (by definition page faults are taken in interrupt context) */
- spin_lock(&video->spinlock);
-
- if(!video->user_buf)
- goto out;
-
- if( (address < (unsigned long) area->vm_start) ||
- (address > (unsigned long) area->vm_start + video->user_buf_size) )
- goto out;
-
- offset = address - area->vm_start;
- kernel_virt_addr = (unsigned long) video->user_buf + offset;
- ret = vmalloc_to_page((void *)kernel_virt_addr);
- get_page(ret);
-
- out:
- spin_unlock(&video->spinlock);
- return ret;
-}
-
-static struct vm_operations_struct dv1394_vm_ops = {
- .nopage = dv1394_nopage
-};
-
-/*
- dv1394_mmap does no page table manipulation. The page table entries
- are created by the dv1394_nopage() handler as page faults are taken
- by the user.
*/
int dv1394_mmap(struct file *file, struct vm_area_struct *vma)
{
struct video_card *video = file_to_video_card(file);
- unsigned long size;
- int res = -EINVAL;
+ int retval = -EINVAL;
/* serialize mmap */
down(&video->sem);
if( ! video_card_initialized(video) ) {
- res = do_dv1394_init_default(video);
- if(res)
- goto err;
+ retval = do_dv1394_init_default(video);
+ if(retval)
+ goto out;
}
- /* region must be page-aligned */
- if(vma->vm_pgoff != 0)
- goto err;
-
- /* check the size the user is trying to map */
- size = vma->vm_end - vma->vm_start;
- if(size > video->user_buf_size)
- goto err;
-
- /*
- we don't actually mess with the page tables here.
- (nopage() takes care of that from the page fault handler)
- Just set up the vma->vm_ops.
- */
-
- vma->vm_ops = &dv1394_vm_ops;
- vma->vm_private_data = video;
- vma->vm_file = file;
-
- /* don't try to swap this out =) */
- vma->vm_flags |= VM_RESERVED;
-
- up(&video->sem);
- return 0;
- err:
+ retval = dma_region_mmap(&video->dv_buf, file, vma);
+out:
up(&video->sem);
- return res;
+ return retval;
}
-
/*** DEVICE FILE INTERFACE *************************************************/
/* no need to serialize, multiple threads OK */
@@ -1633,7 +1417,7 @@
continue; /* start over from 'while(count > 0)...' */
}
- if(copy_from_user(video->user_buf + video->write_off, buffer, cnt)) {
+ if(copy_from_user(video->dv_buf.kvirt + video->write_off, buffer, cnt)) {
if(!ret)
ret = -EFAULT;
break;
@@ -1680,7 +1464,11 @@
up(&video->sem);
return ret;
}
- receive_packets(video, video->frames[video->first_clear_frame]);
+ video->continuity_counter = -1;
+
+ receive_packets(video);
+
+ start_dma_receive(video);
}
ret = 0;
@@ -1733,7 +1521,7 @@
continue; /* start over from 'while(count > 0)...' */
}
- if(copy_to_user(buffer, video->user_buf + video->write_off, cnt)) {
+ if(copy_to_user(buffer, video->dv_buf.kvirt + video->write_off, cnt)) {
if(!ret)
ret = -EFAULT;
break;
@@ -1785,7 +1573,8 @@
switch(cmd)
{
- case DV1394_SUBMIT_FRAMES: {
+ case DV1394_SUBMIT_FRAMES:
+ case DV1394_IOC_SUBMIT_FRAMES: {
unsigned int n_submit;
if( !video_card_initialized(video) ) {
@@ -1838,8 +1627,8 @@
ret = 0;
break;
}
-
- case DV1394_WAIT_FRAMES: {
+ case DV1394_WAIT_FRAMES:
+ case DV1394_IOC_WAIT_FRAMES: {
unsigned int n_wait;
if( !video_card_initialized(video) ) {
@@ -1887,8 +1676,8 @@
ret = 0;
break;
}
-
- case DV1394_RECEIVE_FRAMES: {
+ case DV1394_RECEIVE_FRAMES:
+ case DV1394_IOC_RECEIVE_FRAMES: {
unsigned int n_recv;
if( !video_card_initialized(video) ) {
@@ -1920,22 +1709,25 @@
ret = 0;
break;
}
-
- case DV1394_START_RECEIVE: {
-
+ case DV1394_START_RECEIVE:
+ case DV1394_IOC_START_RECEIVE: {
if( !video_card_initialized(video) ) {
ret = do_dv1394_init_default(video);
if(ret)
goto out;
}
- receive_packets(video, video->frames[video->first_clear_frame]);
+ video->continuity_counter = -1;
+
+ receive_packets(video);
+
+ start_dma_receive(video);
ret = 0;
break;
}
-
- case DV1394_INIT: {
+ case DV1394_INIT:
+ case DV1394_IOC_INIT: {
struct dv1394_init init;
if(arg == (unsigned long) NULL) {
ret = do_dv1394_init_default(video);
@@ -1948,13 +1740,14 @@
}
break;
}
-
case DV1394_SHUTDOWN:
- ret = do_dv1394_shutdown(video, 0);
+ case DV1394_IOC_SHUTDOWN:
+ do_dv1394_shutdown(video, 0);
+ ret = 0;
break;
-
- case DV1394_GET_STATUS: {
+ case DV1394_GET_STATUS:
+ case DV1394_IOC_GET_STATUS: {
struct dv1394_status status;
if( !video_card_initialized(video) ) {
@@ -2027,7 +1820,7 @@
struct video_card *p;
list_for_each(lh, &dv1394_cards) {
p = list_entry(lh, struct video_card, list);
- if((p->id >> 2) == ieee1394_file_to_instance(file)) {
+ if((p->id) == ieee1394_file_to_instance(file)) {
video = p;
break;
}
@@ -2319,9 +2112,10 @@
struct video_card *video = (struct video_card*) data;
spin_lock(&video->spinlock);
-
- irq_printk("INTERRUPT! Video = %08lx Iso event Recv: %08x Xmit: %08x\n",
- (unsigned long) video, isoRecvIntEvent, isoXmitIntEvent);
+
+ 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)
@@ -2448,14 +2242,15 @@
} /* for(each frame) */
}
- spin_unlock(&video->spinlock);
-
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)
@@ -2463,83 +2258,151 @@
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)) ) {
+ (reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 10)) )
+ {
int sof=0; /* start-of-frame flag */
struct frame *f;
u16 packet_length, packet_time;
-
- packet_length = le16_to_cpu(video->packet_buffer[video->current_packet].data_length);
- packet_time = le16_to_cpu(video->packet_buffer[video->current_packet].timestamp);
-
- irq_printk("received packet %02d, timestamp=%04x, length=%04x, sof=%02x%02x\n", video->current_packet,
- packet_time, packet_length,
- video->packet_buffer[video->current_packet].data[0], video->packet_buffer[video->current_packet].data[1]);
-
- f = video->frames[video->active_frame];
-
- /* exclude empty packet */
- if (packet_length > 8) {
-
- /* check for start of frame */
- sof = (video->packet_buffer[video->current_packet].data[0] == 0x1f &&
- video->packet_buffer[video->current_packet].data[1] == 0x07);
-
- 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->n_clear_frames = video->n_frames;
- video->dropped_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;
+ 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(&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 = le16_to_cpu(block->u.in.il.q[3] >> 16);
+ xferstatus &= 0x1F;
+
+ /* get the current frame */
+ f = video->frames[video->active_frame];
+
+ /* exclude empty packet */
+ if (packet_length > 8 && xferstatus == 0x11) {
+ irq_printk("ir_tasklet_func: xferStatus/resCount [%d] = 0x%08x\n", i, le32_to_cpu(block->u.in.il.q[3]) );
+
+ /* 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;
- /* copy to buffer */
- if (f->n_packets > (video->frame_size / 480)) {
- printk(KERN_ERR "frame buffer overflow during receive\n");
+ 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);
- /* make sure we are seeing the latest changes to packet_buffer */
- pci_dma_sync_single(video->ohci->dev,
- video->packet_buffer_dma,
- video->packet_buffer_size,
- PCI_DMA_FROMDEVICE);
-
- frame_put_packet( f, &video->packet_buffer[video->current_packet]);
-
- } /* first_frame */
-
- } /* not empty packet */
-
- /* advance packet_buffer cursor */
- video->current_packet = (video->current_packet + 1) % MAX_PACKET_BUFFER;
+ /* 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 */
-
- spin_unlock(&video->spinlock);
if(wake) {
kill_fasync(&video->fasync, SIGIO, POLL_IN);
@@ -2547,6 +2410,9 @@
/* wake readers/writers/ioctl'ers */
wake_up_interruptible(&video->waitq);
}
+
+out:
+ spin_unlock(&video->spinlock);
}
static struct file_operations dv1394_fops=
@@ -2587,6 +2453,7 @@
return p;
}
+#ifdef CONFIG_DEVFS_FS
static int dv1394_devfs_add_entry(struct video_card *video)
{
char buf[32];
@@ -2694,6 +2561,29 @@
kfree(p);
}
}
+#endif /* CONFIG_DEVFS_FS */
+
+
+/*** 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
+ },
+ { }
+};
+
+static struct hpsb_protocol_driver dv1394_driver = {
+ .name = "DV/1394 Driver",
+ .id_table = dv1394_id_table,
+};
+
+MODULE_DEVICE_TABLE(ieee1394, dv1394_id_table);
+
/*** IEEE1394 HPSB CALLBACKS ***********************************************/
@@ -2715,6 +2605,10 @@
/* lower 2 bits of id indicate which of four "plugs"
per host */
video->id = ohci->id << 2;
+ if (format == DV1394_NTSC)
+ video->id |= mode;
+ else
+ video->id |= 2 + mode;
video->ohci_it_ctx = -1;
video->ohci_ir_ctx = -1;
@@ -2747,11 +2641,14 @@
for(i = 0; i < DV1394_MAX_FRAMES; i++)
video->frames[i] = NULL;
- video->user_buf = NULL;
- video->user_buf_size = 0;
+ 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;
init_MUTEX(&video->sem);
init_waitqueue_head(&video->waitq);
video->fasync = NULL;
@@ -2761,10 +2658,6 @@
list_add_tail(&video->list, &dv1394_cards);
spin_unlock_irqrestore(&dv1394_cards_lock, flags);
- if (format == DV1394_NTSC)
- video->id |= mode;
- else video->id |= 2 + mode;
-
#ifdef CONFIG_DEVFS_FS
if (dv1394_devfs_add_entry(video) < 0)
goto err_free;
@@ -2806,7 +2699,7 @@
struct ti_ohci *ohci;
struct video_card *video = NULL;
unsigned long flags;
- struct list_head *lh;
+ struct list_head *lh, *templh;
char buf[32];
int n;
@@ -2820,7 +2713,7 @@
/* find the corresponding video_cards */
spin_lock_irqsave(&dv1394_cards_lock, flags);
if(!list_empty(&dv1394_cards)) {
- list_for_each(lh, &dv1394_cards) {
+ list_for_each_safe(lh, templh, &dv1394_cards) {
video = list_entry(lh, struct video_card, list);
if((video->id >> 2) == ohci->id)
dv1394_un_init(video);
@@ -2852,7 +2745,6 @@
{
struct ti_ohci *ohci;
char buf[16];
- struct dv1394_devfs_entry *devfs_entry;
/* We only work with the OHCI-1394 driver */
if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME))
@@ -2874,13 +2766,15 @@
#endif
#ifdef CONFIG_DEVFS_FS
- devfs_entry = dv1394_devfs_find("dv");
+{
+ struct dv1394_devfs_entry *devfs_entry = dv1394_devfs_find("dv");
if (devfs_entry != NULL) {
snprintf(buf, sizeof(buf), "host%d", ohci->id);
dv1394_devfs_add_dir(buf, devfs_entry, &devfs_entry);
dv1394_devfs_add_dir("NTSC", devfs_entry, NULL);
dv1394_devfs_add_dir("PAL", devfs_entry, NULL);
}
+}
#endif
dv1394_init(ohci, DV1394_NTSC, MODE_RECEIVE);
@@ -2926,6 +2820,9 @@
spin_lock_irqsave(&video->spinlock, flags);
+ if(!video->dma_running)
+ goto out;
+
/* check IT context */
if(video->ohci_it_ctx != -1) {
u32 ctx;
@@ -2998,14 +2895,16 @@
reg_read(video->ohci, video->ohci_IsoRcvCommandPtr));
}
}
-
+
+out:
spin_unlock_irqrestore(&video->spinlock, flags);
/* wake readers/writers/ioctl'ers */
wake_up_interruptible(&video->waitq);
}
-static struct hpsb_highlevel_ops hl_ops = {
+static struct hpsb_highlevel dv1394_highlevel = {
+ .name = "dv1394",
.add_host = dv1394_add_host,
.remove_host = dv1394_remove_host,
.host_reset = dv1394_host_reset,
@@ -3021,8 +2920,11 @@
static void __exit dv1394_exit_module(void)
{
- hpsb_unregister_highlevel (hl_handle);
+ hpsb_unregister_protocol(&dv1394_driver);
+
+ hpsb_unregister_highlevel(&dv1394_highlevel);
ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_DV1394);
+
#ifdef CONFIG_DEVFS_FS
dv1394_devfs_del("dv");
#endif
@@ -3058,22 +2960,12 @@
}
#endif
- hl_handle = hpsb_register_highlevel ("dv1394", &hl_ops);
- if (hl_handle == NULL) {
- printk(KERN_ERR "dv1394: hpsb_register_highlevel failed\n");
- ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_DV1394);
-#ifdef CONFIG_DEVFS_FS
- dv1394_devfs_del("dv");
-#endif
-#ifdef CONFIG_PROC_FS
- dv1394_procfs_del("dv");
-#endif
- return -ENOMEM;
- }
+ hpsb_register_highlevel (&dv1394_highlevel);
+
+ hpsb_register_protocol(&dv1394_driver);
return 0;
}
module_init(dv1394_init_module);
module_exit(dv1394_exit_module);
-
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)