Thread: [Linux1394-cvslog] rev 740 - branches/linux-2.4
Brought to you by:
aeb,
bencollins
From: SVN U. <dde...@li...> - 2003-02-01 13:59:49
|
Author: ddennedy Date: 2003-01-07 22:31:25 -0500 (Tue, 07 Jan 2003) New Revision: 740 Added: branches/linux-2.4/dma.c branches/linux-2.4/dma.h Modified: branches/linux-2.4/Makefile branches/linux-2.4/dv1394-private.h branches/linux-2.4/dv1394.c Log: fix broken dv1394 receive mode and oops on module reload Modified: branches/linux-2.4/dv1394-private.h ============================================================================== --- branches/linux-2.4/dv1394-private.h (original) +++ branches/linux-2.4/dv1394-private.h 2003-02-01 08:59:16.000000000 -0500 @@ -28,8 +28,7 @@ #include "ieee1394.h" #include "ohci1394.h" -#include <linux/pci.h> -#include <asm/scatterlist.h> +#include "dma.h" /* data structures private to the dv1394 driver */ /* none of this is exposed to user-space */ @@ -167,12 +166,14 @@ } static inline void fill_input_last(struct input_last *il, + int want_interrupt, unsigned int data_size, unsigned long data_phys_addr) { u32 temp = 3 << 28; /* INPUT_LAST */ temp |= 8 << 24; /* s = 1, update xferStatus and resCount */ - temp |= 3 << 20; /* enable interrupts */ + if (want_interrupt) + temp |= 3 << 20; /* enable interrupts */ temp |= 0xC << 16; /* enable branch to address */ /* disable wait on sync field, not used in DV :-( */ temp |= data_size; @@ -301,8 +302,7 @@ unsigned long data; /* Max # of packets per frame */ - /* 320 is enough for NTSC, need to check what PAL is */ - #define MAX_PACKETS 500 +#define MAX_PACKETS 500 /* a PAGE_SIZE memory pool for allocating CIP headers @@ -383,35 +383,6 @@ /* reset f so that it can be used again */ static void frame_reset(struct frame *f); - -/* structure for bookkeeping of a large non-physically-contiguous DMA buffer */ - -struct dma_region { - unsigned int n_pages; - unsigned int n_dma_pages; - struct scatterlist *sglist; -}; - -/* return the DMA bus address of the byte with the given offset - relative to the beginning of the dma_region */ - -static inline dma_addr_t dma_offset_to_bus(struct dma_region *dma, unsigned long offset) -{ - int i; - struct scatterlist *sg; - - for(i = 0, sg = &dma->sglist[0]; i < dma->n_dma_pages; i++, sg++) { - if(offset < sg_dma_len(sg)) { - return sg_dma_address(sg) + offset; - } - offset -= sg_dma_len(sg); - } - - printk(KERN_ERR "dv1394: dma_offset_to_bus failed for offset %lu!\n", offset); - return 0; -} - - /* struct video_card contains all data associated with one instance of the dv1394 driver */ @@ -508,9 +479,8 @@ /* the large, non-contiguous (rvmalloc()) ringbuffer for DV data, exposed to user-space via mmap() */ - unsigned char *user_buf; - unsigned long user_buf_size; - struct dma_region user_dma; + unsigned long dv_buf_size; + struct dma_region dv_buf; /* next byte in the ringbuffer that a write() call will fill */ size_t write_off; @@ -579,10 +549,8 @@ /* physically contiguous packet ringbuffer for receive */ -#define MAX_PACKET_BUFFER 30 - struct packet *packet_buffer; - dma_addr_t packet_buffer_dma; - unsigned long packet_buffer_size; + struct dma_region packet_buf; + unsigned long packet_buf_size; unsigned int current_packet; int first_frame; /* received first start frame marker? */ Modified: branches/linux-2.4/Makefile ============================================================================== --- branches/linux-2.4/Makefile (original) +++ branches/linux-2.4/Makefile 2003-02-01 08:59:16.000000000 -0500 @@ -5,7 +5,7 @@ export-objs := ieee1394_core.o ohci1394.o cmp.o ieee1394-objs := ieee1394_core.o ieee1394_transactions.o hosts.o \ - highlevel.o csr.o nodemgr.o + highlevel.o csr.o nodemgr.o dma.o obj-$(CONFIG_IEEE1394) += ieee1394.o obj-$(CONFIG_IEEE1394_PCILYNX) += pcilynx.o Added: branches/linux-2.4/dma.c ============================================================================== --- branches/linux-2.4/dma.c (original) +++ branches/linux-2.4/dma.c 2003-02-01 08:59:16.000000000 -0500 @@ -0,0 +1,236 @@ +/* + * DMA region bookkeeping routines + * + * Copyright (C) 2002 Maas Digital LLC + * + * This code is licensed under the GPL. See the file COPYING in the root + * directory of the kernel sources for details. + */ + +#include <linux/module.h> +#include <linux/vmalloc.h> +#include <linux/slab.h> +#include "dma.h" + +/* dma_prog_region */ + +void dma_prog_region_init(struct dma_prog_region *prog) +{ + prog->kvirt = NULL; + prog->dev = NULL; + prog->n_pages = 0; + prog->bus_addr = 0; +} + +int dma_prog_region_alloc(struct dma_prog_region *prog, unsigned long n_bytes, struct pci_dev *dev) +{ + /* round up to page size */ + n_bytes = round_up_to_page(n_bytes); + + prog->n_pages = n_bytes / PAGE_SIZE; + + prog->kvirt = pci_alloc_consistent(dev, prog->n_pages * PAGE_SIZE, &prog->bus_addr); + if(!prog->kvirt) { + printk(KERN_ERR "dma_prog_region_alloc: pci_alloc_consistent() failed\n"); + dma_prog_region_free(prog); + return -ENOMEM; + } + + prog->dev = dev; + + return 0; +} + +void dma_prog_region_free(struct dma_prog_region *prog) +{ + if(prog->kvirt) { + pci_free_consistent(prog->dev, prog->n_pages * PAGE_SIZE, prog->kvirt, prog->bus_addr); + } + + prog->kvirt = NULL; + prog->dev = NULL; + prog->n_pages = 0; + prog->bus_addr = 0; +} + +/* dma_region */ + +void dma_region_init(struct dma_region *dma) +{ + dma->kvirt = NULL; + dma->dev = NULL; + dma->n_pages = 0; + dma->n_dma_pages = 0; + dma->sglist = NULL; +} + +int dma_region_alloc(struct dma_region *dma, unsigned long n_bytes, struct pci_dev *dev, int direction) +{ + unsigned int i, n_pages; + + /* round up to page size */ + n_bytes = round_up_to_page(n_bytes); + + n_pages = n_bytes / PAGE_SIZE; + + dma->kvirt = vmalloc_32(n_pages * PAGE_SIZE); + if(!dma->kvirt) { + printk(KERN_ERR "dma_region_alloc: vmalloc_32() failed\n"); + goto err; + } + + dma->n_pages = n_pages; + + /* Clear the ram out, no junk to the user */ + memset(dma->kvirt, 0, n_pages * PAGE_SIZE); + + /* allocate scatter/gather list */ + dma->sglist = kmalloc(dma->n_pages * sizeof(struct scatterlist), GFP_KERNEL); + if(!dma->sglist) { + printk(KERN_ERR "dma_region_alloc: kmalloc(sglist) failed\n"); + goto err; + } + + /* just to be safe - this will become unnecessary once sglist->address goes away */ + memset(dma->sglist, 0, dma->n_pages * sizeof(struct scatterlist)); + + /* fill scatter/gather list with pages */ + for(i = 0; i < dma->n_pages; i++) { + unsigned long va = (unsigned long) dma->kvirt + i * PAGE_SIZE; + + dma->sglist[i].page = vmalloc_to_page((void *)va); + dma->sglist[i].length = PAGE_SIZE; + } + + /* map sglist to the IOMMU */ + dma->n_dma_pages = pci_map_sg(dev, &dma->sglist[0], dma->n_pages, direction); + + if(dma->n_dma_pages == 0) { + printk(KERN_ERR "dma_region_alloc: pci_map_sg() failed\n"); + goto err; + } + + dma->dev = dev; + dma->direction = direction; + + return 0; + +err: + dma_region_free(dma); + return -ENOMEM; +} + +void dma_region_free(struct dma_region *dma) +{ + if(dma->n_dma_pages) { + pci_unmap_sg(dma->dev, dma->sglist, dma->n_pages, dma->direction); + dma->n_dma_pages = 0; + dma->dev = NULL; + } + + if(dma->sglist) { + kfree(dma->sglist); + dma->sglist = NULL; + } + + if(dma->kvirt) { + vfree(dma->kvirt); + dma->kvirt = NULL; + dma->n_pages = 0; + } +} + +/* find the scatterlist index and remaining offset corresponding to a + given offset from the beginning of the buffer */ +static inline int dma_region_find(struct dma_region *dma, unsigned long offset, unsigned long *rem) +{ + int i; + unsigned long off = offset; + + for(i = 0; i < dma->n_dma_pages; i++) { + if(off < sg_dma_len(&dma->sglist[i])) { + *rem = off; + return i; + } + + off -= sg_dma_len(&dma->sglist[i]); + } + + panic("dma_region_find: offset %lu beyond end of DMA mapping\n", offset); +} + +dma_addr_t dma_region_offset_to_bus(struct dma_region *dma, unsigned long offset) +{ + unsigned long rem; + + struct scatterlist *sg = &dma->sglist[dma_region_find(dma, offset, &rem)]; + return sg_dma_address(sg) + rem; +} + +void dma_region_sync(struct dma_region *dma, unsigned long offset, unsigned long len) +{ + int first, last; + unsigned long rem; + + if(!len) + len = 1; + + first = dma_region_find(dma, offset, &rem); + last = dma_region_find(dma, offset + len - 1, &rem); + + pci_dma_sync_sg(dma->dev, &dma->sglist[first], last - first + 1, dma->direction); +} + +/* nopage() handler for mmap access */ + +static struct page* +dma_region_pagefault(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 dma_region *dma = (struct dma_region*) area->vm_private_data; + + if(!dma->kvirt) + goto out; + + if( (address < (unsigned long) area->vm_start) || + (address > (unsigned long) area->vm_start + (PAGE_SIZE * dma->n_pages)) ) + goto out; + + offset = address - area->vm_start; + kernel_virt_addr = (unsigned long) dma->kvirt + offset; + ret = vmalloc_to_page((void*) kernel_virt_addr); + get_page(ret); +out: + return ret; +} + +static struct vm_operations_struct dma_region_vm_ops = { + .nopage = dma_region_pagefault, +}; + +int dma_region_mmap(struct dma_region *dma, struct file *file, struct vm_area_struct *vma) +{ + unsigned long size; + + if(!dma->kvirt) + return -EINVAL; + + /* must be page-aligned */ + if(vma->vm_pgoff != 0) + return -EINVAL; + + /* check the length */ + size = vma->vm_end - vma->vm_start; + if(size > (PAGE_SIZE * dma->n_pages)) + return -EINVAL; + + vma->vm_ops = &dma_region_vm_ops; + vma->vm_private_data = dma; + vma->vm_file = file; + vma->vm_flags |= VM_RESERVED; + + return 0; +} Added: branches/linux-2.4/dma.h ============================================================================== --- branches/linux-2.4/dma.h (original) +++ branches/linux-2.4/dma.h 2003-02-01 08:59:16.000000000 -0500 @@ -0,0 +1,84 @@ +/* + * DMA region bookkeeping routines + * + * Copyright (C) 2002 Maas Digital LLC + * + * This code is licensed under the GPL. See the file COPYING in the root + * directory of the kernel sources for details. + */ + +#ifndef IEEE1394_DMA_H +#define IEEE1394_DMA_H + +#include <linux/pci.h> +#include <asm/scatterlist.h> + +/* struct dma_prog_region + + a small, physically-contiguous DMA buffer with random-access, + synchronous usage characteristics +*/ + +struct dma_prog_region { + unsigned char *kvirt; /* kernel virtual address */ + struct pci_dev *dev; /* PCI device */ + unsigned int n_pages; /* # of kernel pages */ + dma_addr_t bus_addr; /* base bus address */ +}; + +/* clear out all fields but do not allocate any memory */ +void dma_prog_region_init(struct dma_prog_region *prog); +int dma_prog_region_alloc(struct dma_prog_region *prog, unsigned long n_bytes, struct pci_dev *dev); +void dma_prog_region_free(struct dma_prog_region *prog); + +static inline dma_addr_t dma_prog_region_offset_to_bus(struct dma_prog_region *prog, unsigned long offset) +{ + return prog->bus_addr + offset; +} + +/* struct dma_region + + a large, non-physically-contiguous DMA buffer with streaming, + asynchronous usage characteristics +*/ + +struct dma_region { + unsigned char *kvirt; /* kernel virtual address */ + struct pci_dev *dev; /* PCI device */ + unsigned int n_pages; /* # of kernel pages */ + unsigned int n_dma_pages; /* # of IOMMU pages */ + struct scatterlist *sglist; /* IOMMU mapping */ + int direction; /* PCI_DMA_TODEVICE, etc */ +}; + +/* clear out all fields but do not allocate anything */ +void dma_region_init(struct dma_region *dma); + +/* allocate the buffer and map it to the IOMMU */ +int dma_region_alloc(struct dma_region *dma, unsigned long n_bytes, struct pci_dev *dev, int direction); + +/* unmap and free the buffer */ +void dma_region_free(struct dma_region *dma); + +/* sync the IO bus' view of the buffer with the CPU's view */ +void dma_region_sync(struct dma_region *dma, unsigned long offset, unsigned long len); + +/* map the buffer into a user space process */ +int dma_region_mmap(struct dma_region *dma, struct file *file, struct vm_area_struct *vma); + +/* macro to index into a DMA region (or dma_prog_region) */ +#define dma_region_i(_dma, _type, _index) ( ((_type*) ((_dma)->kvirt)) + (_index) ) + +/* return the DMA bus address of the byte with the given offset + relative to the beginning of the dma_region */ +dma_addr_t dma_region_offset_to_bus(struct dma_region *dma, unsigned long offset); + +/* round up a number of bytes to be a multiple of the PAGE_SIZE */ +static inline unsigned long round_up_to_page(unsigned long len) +{ + if(len % PAGE_SIZE) + len += PAGE_SIZE - (len % PAGE_SIZE); + return len; +} + +#endif /* IEEE1394_DMA_H */ Modified: branches/linux-2.4/dv1394.c ============================================================================== --- branches/linux-2.4/dv1394.c (original) +++ branches/linux-2.4/dv1394.c 2003-02-01 08:59:16.000000000 -0500 @@ -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,9 +97,9 @@ #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> @@ -132,7 +138,7 @@ (will cause undeflows if your machine is too slow!) */ -#define DV1394_DEBUG_LEVEL 0 +#define DV1394_DEBUG_LEVEL 1 /* for debugging use ONLY: allow more than one open() of the device */ /* #define DV1394_ALLOW_MORE_THAN_ONE_OPEN 1 */ @@ -185,39 +191,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) @@ -446,11 +419,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 */ @@ -501,8 +470,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), @@ -516,8 +485,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]); @@ -551,8 +520,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]); @@ -593,13 +562,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); @@ -798,6 +762,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); @@ -825,47 +792,64 @@ } -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(); - - /* 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, - frame->descriptor_pool_dma | 1); /* Z=1 */ - 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); - /* run */ - reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, 0x8000); - flush_pci_write(video->ohci); + /* 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(); + + /* run */ + reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, 0x8000); + flush_pci_write(video->ohci); + + debug_printk("dv1394: DMA started\n"); - debug_printk("dv1394: DMA started\n"); - #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; + { + 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)); + } } @@ -873,7 +857,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; @@ -881,52 +865,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); - - /* link descriptors */ - last_branch_address = f->frame_end_branch; + /* 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 */ - if (last_branch_address) - *(last_branch_address) = cpu_to_le32(block_dma | 1); /* set Z=1 */ + f = video->frames[j]; - 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; + + 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]); + } - /* loop tail to head */ - if (f->frame_end_branch) - *(f->frame_end_branch) = cpu_to_le32(f->descriptor_pool_dma | 1); /* set Z=1 */ + } /* 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)); - } } @@ -940,6 +918,7 @@ u64 chan_mask; int retval = -EINVAL; + debug_printk( "dv1394: initialising %d\n", video->id ); if(init->api_version != DV1394_API_VERSION) goto err; @@ -969,15 +948,13 @@ 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) ) { + if(video->dv_buf.kvirt && video->dv_buf_size != new_buf_size) goto err; - } /* 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); +// if( video_card_initialized(video) ) +// do_dv1394_shutdown(video, 0); @@ -1076,93 +1053,39 @@ } } - - - 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"); + retval = dma_region_alloc(&video->dv_buf, new_buf_size, video->ohci->dev, PCI_DMA_TODEVICE); + if(retval) 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)); + + 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; - - /* 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; - } + video->frames[i]->data = (unsigned long) video->dv_buf.kvirt + i * video->frame_size; - /* 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_dv_buf; + + 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; @@ -1186,26 +1109,9 @@ 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_dv_buf: + dma_region_free(&video->dv_buf); + err_frames: for(i = 0; i < DV1394_MAX_FRAMES; i++) { if(video->frames[i]) @@ -1238,7 +1144,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; @@ -1270,7 +1176,6 @@ video->active_frame = -1; video->first_run = 1; - /* wait until DMA really stops */ i = 0; @@ -1282,6 +1187,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); @@ -1295,13 +1201,15 @@ printk(KERN_ERR "dv1394: stop_dma: DMA still going after %d ms!\n", i/10); } } - + else + debug_printk("dv1394: stop_dma: already stopped.\n"); + spin_unlock_irqrestore(&video->spinlock, flags); } -static int do_dv1394_shutdown(struct video_card *video, int free_user_buf) +static int do_dv1394_shutdown(struct video_card *video, int free_dv_buf) { int i; unsigned long flags; @@ -1322,7 +1230,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; } @@ -1336,13 +1245,14 @@ /* 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; @@ -1369,42 +1279,20 @@ /* 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; } + /* free packet buffer */ + dma_region_free(&video->packet_buf); + video->packet_buf_size = 0; + debug_printk("dv1394: shutdown complete\n"); return 0; } - - /* ********************************** *** MMAP() THEORY OF OPERATION *** @@ -1427,96 +1315,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 */ @@ -1632,7 +1452,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; @@ -1679,7 +1499,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; @@ -1732,7 +1556,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; @@ -1921,14 +1745,17 @@ } case DV1394_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; @@ -2026,7 +1853,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; } @@ -2318,9 +2145,7 @@ 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); + irq_printk("ContextControl = %08x, CommandPtr = %08x\n", reg_read(video->ohci, video->ohci_IsoXmitContextControlSet), reg_read(video->ohci, video->ohci_IsoXmitCommandPtr) @@ -2462,82 +2287,149 @@ int wake = 0; struct video_card *video = (struct video_card*) data; - if( (video->ohci_ir_ctx != -1) && - (reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 10)) ) { + spin_lock(&video->spinlock); + + 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; - - 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) { @@ -2716,6 +2608,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; @@ -2748,8 +2644,10 @@ 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); @@ -2762,10 +2660,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; |