Implemented needed DMA functions (pool alloc/free, create/destroy, map/unmap single), manipulations with timers (schedule_timeout, schedule_wait). Modified: trunk/reactos/drivers/usb/cromwell/host/ohci_main.h Modified: trunk/reactos/drivers/usb/cromwell/linux/linux_wrapper.h Modified: trunk/reactos/drivers/usb/cromwell/linux/usb.h Modified: trunk/reactos/drivers/usb/cromwell/sys/linuxwrapper.c _____
Modified: trunk/reactos/drivers/usb/cromwell/host/ohci_main.h --- trunk/reactos/drivers/usb/cromwell/host/ohci_main.h 2005-07-19 11:18:40 UTC (rev 16641) +++ trunk/reactos/drivers/usb/cromwell/host/ohci_main.h 2005-07-19 13:19:04 UTC (rev 16642) @@ -38,6 +38,20 @@
ULONG SystemIoBusNumber; ULONG SystemIoSlotNumber; LIST_ENTRY AddressMappingListHead; + + // DMA stuff, and buffers + PDMA_ADAPTER pDmaAdapter; + PVOID MapRegisterBase; + ULONG mapRegisterCount; +#ifdef USB_DMA_SINGLE_SUPPORT + PHYSICAL_ADDRESS Buffer; + PVOID VirtualBuffer; + ULONG BufferSize; + + // Mdl used for single DMA transfers + PMDL Mdl; +#endif + //KDPC DpcObject; OHCI_DRIVER_EXTENSION *DriverExtension; ULONG DeviceOpened; _____
Modified: trunk/reactos/drivers/usb/cromwell/linux/linux_wrapper.h --- trunk/reactos/drivers/usb/cromwell/linux/linux_wrapper.h 2005-07-19 11:18:40 UTC (rev 16641) +++ trunk/reactos/drivers/usb/cromwell/linux/linux_wrapper.h 2005-07-19 13:19:04 UTC (rev 16642) @@ -34,7 +34,7 @@
typedef u32 dma_addr_t;
-typedef int spinlock_t; +typedef int spinlock_t; typedef int atomic_t; #ifndef STANDALONE #ifndef _MODE_T_ @@ -123,6 +123,8 @@ struct device *parent; struct list_head driver_list; void (*release)(struct device * dev); + + void *dev_ext; // ReactOS-specific: pointer to windows device extension }; struct class_device{int a;}; struct semaphore{int a;}; @@ -165,8 +167,20 @@ int dummy; };
+/* These definitions mirror those in pci.h, so they can be used + * interchangeably with their PCI_ counterparts */ +enum dma_data_direction { + DMA_BIDIRECTIONAL = 0, + DMA_TO_DEVICE = 1, + DMA_FROM_DEVICE = 2, + DMA_NONE = 3, +}; + +/* compatibility */ +#define PCI_DMA_TODEVICE DMA_TO_DEVICE +#define PCI_DMA_FROMDEVICE DMA_FROM_DEVICE + /* from mod_devicetable.h */ - struct usb_device_id { /* which fields to match against? */ __u16 match_flags; @@ -409,43 +423,49 @@
/* PCI */ -#define to_pci_dev(n) container_of(n, struct pci_dev, dev) +#define MAX_POOL_PAGES 2 +#define BITS_PER_LONG 32
-#define pci_pool_create(a,b,c,d,e) (void*)1 +struct pci_page +{ + PHYSICAL_ADDRESS dmaAddress; + PVOID virtualAddress;
-#define pci_pool_alloc(a,b,c) my_pci_pool_alloc(a,b,c) + unsigned long bitmap[128]; // 128 == 32bits*4096 blocks +};
-static void __inline__ *my_pci_pool_alloc(void* pool, size_t size, - dma_addr_t *dma_handle) +struct pci_pool { - void* a; - a=kmalloc(size,0); //FIXME -#ifdef MODULE - *dma_handle=((u32)a)&0xfffffff; -#else - *dma_handle=(u32)a; -#endif - return a; -} + char name[32]; + size_t size; + size_t allocation; + size_t blocks_per_page; + struct pci_dev *pdev;
+ // internal stuff + int pages_allocated; + int blocks_allocated;
-#define pci_pool_free(a,b,c) kfree(b) -#define pci_alloc_consistent(a,b,c) my_pci_alloc_consistent(a,b,c) + struct pci_page pages[MAX_POOL_PAGES]; +};
-static void __inline__ *my_pci_alloc_consistent(struct pci_dev *hwdev, size_t size, - dma_addr_t *dma_handle) -{ - void* a; +#define to_pci_dev(n) container_of(n, struct pci_dev, dev)
- a=kmalloc(size+256,0); //FIXME - a=(void*)(((int)a+255)&~255); // 256 alignment - *dma_handle=((u32)a)&0xfffffff; +#define pci_pool_create(a,b,c,d,e) my_pci_pool_create(a,b,c,d,e) +struct pci_pool *my_pci_pool_create(const char * name, struct pci_dev * pdev, size_t size, size_t align, size_t allocation);
- return a; -} +#define pci_pool_alloc(a,b,c) my_pci_pool_alloc(a,b,c) +void *my_pci_pool_alloc(struct pci_pool * pool, int mem_flags, dma_addr_t *dma_handle);
+#define pci_pool_free(a,b,c) my_pci_pool_free(a,b,c) +void my_pci_pool_free(struct pci_pool * pool, void * vaddr, dma_addr_t dma); + +#define pci_alloc_consistent(a,b,c) my_pci_alloc_consistent(a,b,c) +void *my_pci_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle); + #define pci_free_consistent(a,b,c,d) kfree(c) -#define pci_pool_destroy(a) do {} while(0) +#define pci_pool_destroy(a) my_pci_pool_destroy(a) +void my_pci_pool_destroy (struct pci_pool * pool);
#define pci_module_init(x) my_pci_module_init(x) int my_pci_module_init(struct pci_driver *x); @@ -464,17 +484,29 @@ #define dma_pool_free(a,b,c) pci_pool_free(a,b,c) #define dma_pool_destroy(a) pci_pool_destroy(a)
-#define dma_alloc_coherent(a,b,c,d) NULL -#define dma_free_coherent(a,b,c,d) do {} while(0) +//#define dma_alloc_coherent(a,b,c,d) NULL +//#define dma_free_coherent(a,b,c,d) do {} while(0) +#define dma_map_single(a,b,c,d) my_dma_map_single(a,b,c,d) +dma_addr_t my_dma_map_single(struct device *hwdev, void *ptr, size_t size, enum dma_data_direction direction);
-#define dma_map_single(a,b,c,d) ((u32)(b)&0xfffffff) -#define dma_unmap_single(a,b,c,d) do {} while(0) -#define pci_unmap_single(a,b,c,d) do {} while(0) -#define dma_sync_single(a,b,c,d) do {} while(0) -#define dma_sync_sg(a,b,c,d) do {} while(0) -#define dma_map_sg(a,b,c,d) 0 -#define dma_unmap_sg(a,b,c,d) do {} while(0) +#define dma_unmap_single(a,b,c,d) my_dma_unmap_single(a,b,c,d) +void my_dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, enum dma_data_direction direction);
+#define pci_unmap_single(a,b,c,d) my_pci_unmap_single(a,b,c,d) +void my_pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int direction); + +#define dma_sync_single(a,b,c,d) my_dma_sync_single(a,b,c,d) +void my_dma_sync_single(struct device *hwdev, dma_addr_t dma_handle, size_t size, int direction); + +#define dma_sync_sg(a,b,c,d) my_dma_sync_sg(a,b,c,d) +void my_dma_sync_sg(struct device *hwdev, struct scatterlist *sg, int nelems, int direction); + +#define dma_map_sg(a,b,c,d) my_dma_map_sg(a,b,c,d) +int my_dma_map_sg(struct device *hwdev, struct scatterlist *sg, int nents, enum dma_data_direction direction); + +#define dma_unmap_sg(a,b,c,d) my_dma_unmap_sg(a,b,c,d) +void my_dma_unmap_sg(struct device *hwdev, struct scatterlist *sg, int nents, enum dma_data_direction direction); + #define usb_create_driverfs_dev_files(a) do {} while(0) #define usb_create_driverfs_intf_files(a) do {} while(0) #define sg_dma_address(x) ((u32)((x)->page*4096 + (x)->offset)) @@ -482,12 +514,6 @@
#define page_address(x) ((void*)(x/4096))
-#define DMA_TO_DEVICE 0 -#define DMA_FROM_DEVICE 0 -#define PCI_DMA_TODEVICE -#define PCI_DMA_FROMDEVICE -#define PCI_DMA_TODEVICE - #define PCI_ROM_RESOURCE 1 #define IORESOURCE_IO CM_RESOURCE_PORT_IO
_____
Modified: trunk/reactos/drivers/usb/cromwell/linux/usb.h --- trunk/reactos/drivers/usb/cromwell/linux/usb.h 2005-07-19 11:18:40 UTC (rev 16641) +++ trunk/reactos/drivers/usb/cromwell/linux/usb.h 2005-07-19 13:19:04 UTC (rev 16642) @@ -327,7 +327,7 @@
{ int actual; actual = snprintf (buf, size, "usb-%s-%s", dev->bus->bus_name, dev->devpath); - return (actual >= (int)size) ? -1 : actual; + return (actual >= size) ? -1 : actual; }
/*---------------------------------------------------------------------- ---*/ _____
Modified: trunk/reactos/drivers/usb/cromwell/sys/linuxwrapper.c --- trunk/reactos/drivers/usb/cromwell/sys/linuxwrapper.c 2005-07-19 11:18:40 UTC (rev 16641) +++ trunk/reactos/drivers/usb/cromwell/sys/linuxwrapper.c 2005-07-19 13:19:04 UTC (rev 16642) @@ -40,8 +40,11 @@
#define MAX_DRVS 8 static struct device_driver *m_drivers[MAX_DRVS]; -static int drvs_num; +static int drvs_num=0; +unsigned int LAST_USB_EVENT_TICK;
+NTSTATUS init_dma(POHCI_DEVICE_EXTENSION pDevExt); +
/*---------------------------------------------------------------------- --*/ /* * Helper functions for top-level system @@ -69,6 +72,8 @@ need_wakeup=0; for(n=0;n<MAX_DRVS;n++) m_drivers[n]=NULL; + + init_dma(probe_dev->dev_ext); }
/*---------------------------------------------------------------------- --*/ void handle_irqs(int irq) @@ -92,17 +97,20 @@ int n; for(n=0;n<MAX_TIMERS;n++) { - if (main_timer_list[n] && - main_timer_list[n]->function && main_timer_list[n]->expires) + if (main_timer_list[n] && main_timer_list[n]->function) { void (*function)(unsigned long)=main_timer_list[n]->function; unsigned long data=main_timer_list[n]->data; - main_timer_list[n]->expires=0; - - main_timer_list[n]=NULL; // remove timer - //printk("do timer %i fn %p\n",n,function); - - function(data); + + if (main_timer_list[n]->expires>1) { + main_timer_list[n]->expires--; + } else { + + main_timer_list[n]->expires=0; + main_timer_list[n]=0; // remove timer + // Call Timer Function Data + function(data); + } } } } @@ -118,13 +126,13 @@ ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
- /*PsCreateSystemThread(&hThread, + PsCreateSystemThread(&hThread, THREAD_ALL_ACCESS, NULL, NULL, NULL, (PKSTART_ROUTINE)handler, - parm);*/ + parm);
DPRINT1("usbcore: Created system thread %d\n", (int)hThread);
@@ -229,24 +237,42 @@ }
/*---------------------------------------------------------------------- --*/ /* wait until woken up (only one wait allowed!) */ +extern unsigned int LAST_USB_IRQ; + int my_schedule_timeout(int x) { - int wait=1; - x+=10; // safety - printk("schedule_timeout %i\n",x); + LONGLONG HH; + LONGLONG temp; + LONGLONG delay; + extern unsigned int LAST_USB_EVENT_TICK;
+ printk("schedule_timeout: %d ms\n", x); + + x+=5; // safety + x = x*1000; // to us format + while(x>0) { - do_all_timers(); -#ifndef HAVE_IRQS - handle_irqs(-1); + KeQueryTickCount((LARGE_INTEGER *)&HH);//IoInputDword(0x8008); + temp = HH - LAST_USB_EVENT_TICK; + + //if (temp>(3579)) { //3579 = 1ms! + if (temp>1000) { + do_all_timers(); + LAST_USB_EVENT_TICK = HH; + }
-#endif + //if (LAST_USB_IRQ != OHCI_1_INTERRUPT ) { + // LAST_USB_IRQ = OHCI_1_INTERRUPT; + handle_irqs(-1); + //} + if (need_wakeup) break; - wait_ms(wait); - inc_jiffies(wait); - x-=wait; + + delay = 10; + KeDelayExecutionThread(KernelMode, FALSE, (LARGE_INTEGER *)&delay); //wait_us(1); + x-=1; } need_wakeup=0; printk("schedule DONE!!!!!!\n"); @@ -256,17 +282,34 @@
/*---------------------------------------------------------------------- --*/ void my_wait_for_completion(struct completion *x) { - int n=100; + LONGLONG HH; + LONGLONG temp; + LONGLONG delay; + extern unsigned int LAST_USB_EVENT_TICK; + printk("wait for completion\n");
+ int n=10; + n = n*1000; // to us format + while(!x->done && (n>0)) { - do_all_timers(); -#ifndef HAVE_IRQS - handle_irqs(-1); + KeQueryTickCount((LARGE_INTEGER *)&HH);//IoInputDword(0x8008); + temp = HH - LAST_USB_EVENT_TICK;
-#endif - wait_ms(10); + //if (temp>(3579)) { + if (temp>(1000)) { + do_all_timers(); + LAST_USB_EVENT_TICK = HH; + } + + //if (LAST_USB_IRQ != OHCI_1_INTERRUPT ) { + // LAST_USB_IRQ = OHCI_1_INTERRUPT; + handle_irqs(-1); + //} + + delay = 10; + KeDelayExecutionThread(KernelMode, FALSE, (LARGE_INTEGER *)&delay); //wait_us(1); n--; } printk("wait for completion done %i\n",x->done); @@ -374,11 +417,468 @@ ExFreeToNPagedLookasideList((PNPAGED_LOOKASIDE_LIST)co, ptr); }
/*---------------------------------------------------------------------- --*/ -// DMA, not used now +// DMA support routines
/*---------------------------------------------------------------------- --*/ +#ifdef USB_DMA_SINGLE_SUPPORT +static IO_ALLOCATION_ACTION NTAPI MapRegisterCallback(PDEVICE_OBJECT DeviceObject, + PIRP Irp, + PVOID MapRegisterBase, + PVOID Context); +#endif + +NTSTATUS +init_dma(POHCI_DEVICE_EXTENSION pDevExt) +{ + // Prepare device descriptor structure + DEVICE_DESCRIPTION dd; +#ifdef USB_DMA_SINGLE_SUPPORT + KEVENT DMAEvent; + KIRQL OldIrql; + NTSTATUS Status; +#endif + + RtlZeroMemory( &dd, sizeof(dd) ); + dd.Version = DEVICE_DESCRIPTION_VERSION; + dd.Master = TRUE; + dd.ScatterGather = TRUE; + dd.DemandMode = FALSE; + dd.AutoInitialize = FALSE; + dd.Dma32BitAddresses = TRUE; + dd.InterfaceType = PCIBus; + dd.DmaChannel = 0;//pDevExt->dmaChannel; + dd.MaximumLength = 128;//MAX_DMA_LENGTH; + dd.DmaWidth = Width32Bits; + dd.DmaSpeed = MaximumDmaSpeed; + + // The following taken from Win2k DDB: + // "Compute the maximum number of mapping regs + // this device could possibly need. Since the + // transfer may not be paged aligned, add one + // to allow the max xfer size to span a page." + //pDevExt->mapRegisterCount = (MAX_DMA_LENGTH / PAGE_SIZE) + 1; + + // TODO: Free it somewhere (PutDmaAdapter) + pDevExt->pDmaAdapter = + IoGetDmaAdapter( pDevExt->PhysicalDeviceObject, + &dd, + &pDevExt->mapRegisterCount); + + DPRINT1("IoGetDmaAdapter done 0x%X, mapRegisterCount=%d\n", pDevExt->pDmaAdapter, pDevExt->mapRegisterCount); + + // Fail if failed + if (pDevExt->pDmaAdapter == NULL) + return STATUS_INSUFFICIENT_RESOURCES; + +#ifdef USB_DMA_SINGLE_SUPPORT + /* Allocate buffer now */ + pDevExt->BufferSize = pDevExt->mapRegisterCount * PAGE_SIZE; + DPRINT1("Bufsize = %u\n", pDevExt->BufferSize); + pDevExt->VirtualBuffer = pDevExt->pDmaAdapter->DmaOperations->AllocateCommonBuffer( + pDevExt->pDmaAdapter, pDevExt->BufferSize, &pDevExt->Buffer, FALSE); + DPRINT1("Bufsize = %u, Buffer = 0x%x", pDevExt->BufferSize, pDevExt->Buffer.LowPart); + + if (!pDevExt->VirtualBuffer) + { + DPRINT1("Could not allocate buffer\n"); + // should try again with smaller buffer... + return STATUS_INSUFFICIENT_RESOURCES; + } + + DPRINT1("Calling IoAllocateMdl()\n"); + pDevExt->Mdl = IoAllocateMdl(pDevExt->VirtualBuffer, pDevExt->BufferSize, FALSE, FALSE, NULL); + DPRINT1("Bufsize == %u\n", pDevExt->BufferSize); + + if (!pDevExt->Mdl) + { + DPRINT1("IoAllocateMdl() FAILED\n"); + //TODO: Free the HAL buffer + return STATUS_INSUFFICIENT_RESOURCES; + } + + DPRINT1("VBuffer == 0x%x Mdl == %u Bufsize == %u\n", pDevExt->VirtualBuffer, pDevExt->Mdl, pDevExt->BufferSize); + + DPRINT1("Calling MmBuildMdlForNonPagedPool\n"); + MmBuildMdlForNonPagedPool(pDevExt->Mdl); + + + /* Get map registers for DMA */ + KeInitializeEvent(&DMAEvent, SynchronizationEvent, FALSE); + + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + // TODO: Free adapter channel somewhere + Status = pDevExt->pDmaAdapter->DmaOperations->AllocateAdapterChannel(pDevExt->pDm aAdapter, + pDevExt->PhysicalDeviceObject, pDevExt->mapRegisterCount, MapRegisterCallback, &DMAEvent); + KeLowerIrql(OldIrql); + + DPRINT1("VBuffer == 0x%x Bufsize == %u\n", pDevExt->VirtualBuffer, pDevExt->BufferSize); + KeWaitForSingleObject(&DMAEvent, Executive, KernelMode, FALSE, NULL); + + if(Status != STATUS_SUCCESS) + { + DPRINT("init_dma(): unable to allocate adapter channels\n"); + return STATUS_INSUFFICIENT_RESOURCES; + } +#endif + return STATUS_SUCCESS; +} + +/* + * FUNCTION: Acquire map registers in prep for DMA + * ARGUMENTS: + * DeviceObject: unused + * Irp: unused + * MapRegisterBase: returned to blocked thread via a member var + * Context: contains a pointer to the right ControllerInfo + * struct + * RETURNS: + * KeepObject, because that's what the DDK says to do + */ +#ifdef USB_DMA_SINGLE_SUPPORT +static IO_ALLOCATION_ACTION NTAPI MapRegisterCallback(PDEVICE_OBJECT DeviceObject, + PIRP Irp, + PVOID MapRegisterBase, + PVOID Context) +{ + POHCI_DEVICE_EXTENSION pDevExt = (POHCI_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + UNREFERENCED_PARAMETER(Irp); + + DPRINT("usb_linuxwrapper: MapRegisterCallback Called, base=0x%08x\n", MapRegisterBase); + + pDevExt->MapRegisterBase = MapRegisterBase; + + // signal that we are finished + KeSetEvent(Context, 0, FALSE); + + return KeepObject;//DeallocateObjectKeepRegisters; +} +#endif + void *my_dma_pool_alloc(struct dma_pool *pool, int gfp_flags, dma_addr_t *dma_handle) { // HalAllocCommonBuffer // But ideally IoGetDmaAdapter + + DPRINT1("dma_pool_alloc() called\n"); return NULL; } + +/* +pci_pool_create -- Creates a pool of pci consistent memory blocks, for dma. + +struct pci_pool * pci_pool_create (const char * name, struct pci_dev * pdev, size_t size, size_t align, size_t allocation, int flags); + +Arguments: +name - name of pool, for diagnostics +pdev - pci device that will be doing the DMA +size - size of the blocks in this pool. +align - alignment requirement for blocks; must be a power of two +allocation - returned blocks won't cross this boundary (or zero) +flags - SLAB_* flags (not all are supported). + +Description: +Returns a pci allocation pool with the requested characteristics, or null if one can't be created. +Given one of these pools, pci_pool_alloc may be used to allocate memory. Such memory will all have +"consistent" DMA mappings, accessible by the device and its driver without using cache flushing +primitives. The actual size of blocks allocated may be larger than requested because of alignment. +If allocation is nonzero, objects returned from pci_pool_alloc won't cross that size boundary. +This is useful for devices which have addressing restrictions on individual DMA transfers, such +as not crossing boundaries of 4KBytes. +*/ +struct pci_pool *my_pci_pool_create(const char * name, struct pci_dev * pdev, size_t size, size_t align, size_t allocation) +{ + struct pci_pool *retval; + + if (align == 0) + align = 1; + if (size == 0) + return 0; + else if (size < align) + size = align; + else if ((size % align) != 0) { + size += align + 1; + size &= ~(align - 1); + } + + if (allocation == 0) { + if (PAGE_SIZE < size) + allocation = size; + else + allocation = PAGE_SIZE; + // FIXME: round up for less fragmentation + } else if (allocation < size) + return 0; + + retval = ExAllocatePool(NonPagedPool, sizeof(retval)); //FIXME: Should it be non-paged? + // pci_pool is rather big struct + + // fill retval structure + strncpy (retval->name, name, sizeof retval->name); + retval->name[sizeof retval->name - 1] = 0; + + retval->allocation = allocation; + retval->size = size; + retval->blocks_per_page = allocation / size; + retval->pdev = pdev; + + retval->pages_allocated = 0; + retval->blocks_allocated = 0; + + DPRINT1("pci_pool_create(): %s/%s size %d, %d/page (%d alloc)\n", + pdev ? pdev->slot_name : NULL, retval->name, size, + retval->blocks_per_page, allocation); + + return retval; +} + +/* +Name: +pci_pool_alloc -- get a block of consistent memory + +Synopsis: +void * pci_pool_alloc (struct pci_pool * pool, int mem_flags, dma_addr_t * handle); + +Arguments: +pool - pci pool that will produce the block + +mem_flags - SLAB_KERNEL or SLAB_ATOMIC + +handle - pointer to dma address of block + +Description: +This returns the kernel virtual address of a currently unused block, and reports its dma +address through the handle. If such a memory block can't be allocated, null is returned. +*/ +void * my_pci_pool_alloc(struct pci_pool * pool, int mem_flags, dma_addr_t *dma_handle) +{ + PVOID result; + POHCI_DEVICE_EXTENSION devExt = (POHCI_DEVICE_EXTENSION)pool->pdev->dev_ext; + //PHYSICAL_ADDRESS logicalAddr; + DPRINT1("pci_pool_alloc() called, blocks already allocated=%d\n", pool->blocks_allocated); + //size_t current_block_in_page; + int page,map,i,block,offset; + + if (pool->pages_allocated == 0) + { + // we need to allocate at least one page + pool->pages[pool->pages_allocated].virtualAddress = + devExt->pDmaAdapter->DmaOperations->AllocateCommonBuffer(devExt->pDmaAda pter, + PAGE_SIZE, &pool->pages[pool->pages_allocated].dmaAddress, FALSE); //FIXME: Cache-enabled? + + // mark all blocks as free (bit=set) + memset(pool->pages[pool->pages_allocated].bitmap, 0xFF, 128*sizeof(long)); + + /* FIXME: the next line replaces physical address by virtual address: + * this change is needed to boot VMWare, but I'm really not sure this + * change is correct! + */ + //pool->pages[pool->pages_allocated].dmaAddress.QuadPart = (ULONG_PTR)pool->pages[pool->pages_allocated].virtualAddress; + pool->pages_allocated++; + } + + // search for a free block in all pages + for (page=0; page<pool->pages_allocated; page++) + { + for (map=0,i=0; i < pool->blocks_per_page; i+= BITS_PER_LONG, map++) + { + if (pool->pages[page].bitmap[map] == 0) + continue; + + block = ffz(~ pool->pages[page].bitmap[map]); + + if ((i + block) < pool->blocks_per_page) + { + clear_bit(block, &pool->pages[page].bitmap[map]); + offset = (BITS_PER_LONG * map) + block; + offset *= pool->size; + goto ready; + } + } + } + + //TODO: alloc page here then + DPRINT1("Panic!! We need one more page to be allocated, and Fireball doesn't want to alloc it!\n"); + offset = 0; + return 0; + +ready: + *dma_handle = pool->pages[page].dmaAddress.QuadPart + offset; + result = (char *)pool->pages[page].virtualAddress + offset; + pool->blocks_allocated++; + +#if 0 + // check do we have enough free blocks on the current page + if (pool->pages_allocated*pool->blocks_per_page < pool->blocks_allocated+1) + { + DPRINT1("Panic!! We need one more page to be allocated, and Fireball doesn't want to alloc it!\n"); + *dma_handle = 0; + return NULL; + } + + // Alloc one block now + pool->blocks_allocated++; + current_block_in_page = pool->blocks_allocated - (pool->blocks_allocated / pool->blocks_per_page) * pool->blocks_per_page; + *dma_handle = pool->pages[pool->pages_allocated-1].dmaAddress.QuadPart + pool->size*(current_block_in_page - 1); + result = pool->pages[pool->pages_allocated-1].virtualAddress + pool->size*(current_block_in_page - 1); +#endif + + return result; +} + +/* +Name +pci_pool_free -- put block back into pci pool +Synopsis + +void pci_pool_free (struct pci_pool * pool, void * vaddr, dma_addr_t dma); + +Arguments + +pool - the pci pool holding the block + +vaddr - virtual address of block + +dma - dma address of block + +Description: +Caller promises neither device nor driver will again touch this block unless it is first re-allocated. +*/ +void my_pci_pool_free (struct pci_pool * pool, void * vaddr, dma_addr_t dma) +{ + int page, block, map; + + // Find page + for (page=0; page<pool->pages_allocated; page++) + { + if (dma < pool->pages[page].dmaAddress.QuadPart) + continue; + if (dma < (pool->pages[page].dmaAddress.QuadPart + pool->allocation)) + break; + } + + block = dma - pool->pages[page].dmaAddress.QuadPart; + block /= pool->size; + map = block / BITS_PER_LONG; + block %= BITS_PER_LONG; + + // mark as free + set_bit (block, &pool->pages[page].bitmap[map]); + + pool->blocks_allocated--; + + DPRINT1("pci_pool_free(): alloc'd: %d\n", pool->blocks_allocated); +} + +/* +pci_pool_destroy -- destroys a pool of pci memory blocks. +Synopsis + +void pci_pool_destroy (struct pci_pool * pool); + + +Arguments: +pool - pci pool that will be destroyed + +Description +Caller guarantees that no more memory from the pool is in use, and that nothing will try to +use the pool after this call. +*/ +void __inline__ my_pci_pool_destroy (struct pci_pool * pool) +{ + DPRINT1("pci_pool_destroy(): alloc'd: %d, UNIMPLEMENTED\n", pool->blocks_allocated); + + ExFreePool(pool); +} + +void *my_pci_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle) +{ + POHCI_DEVICE_EXTENSION devExt = (POHCI_DEVICE_EXTENSION)hwdev->dev_ext; + DPRINT1("pci_alloc_consistent() size=%d\n", size); + + return devExt->pDmaAdapter->DmaOperations->AllocateCommonBuffer(devExt->pDmaAda pter, size, (PPHYSICAL_ADDRESS)dma_handle, FALSE); //FIXME: Cache-enabled? +} + +dma_addr_t my_dma_map_single(struct device *hwdev, void *ptr, size_t size, enum dma_data_direction direction) +{ + //PHYSICAL_ADDRESS BaseAddress; + //POHCI_DEVICE_EXTENSION pDevExt = (POHCI_DEVICE_EXTENSION)hwdev->dev_ext; + //PUCHAR VirtualAddress = (PUCHAR) MmGetMdlVirtualAddress(pDevExt->Mdl); + //ULONG transferSize = size; + //BOOLEAN WriteToDevice; + + //DPRINT1("dma_map_single() ptr=0x%lx, size=0x%x, dir=%d\n", ptr, size, direction); + /*ASSERT(pDevExt->BufferSize > size); + + // FIXME: It must be an error if DMA_BIDIRECTIONAL trasnfer happens, since MSDN says + // the buffer is locked + if (direction == DMA_BIDIRECTIONAL || direction == DMA_TO_DEVICE) + WriteToDevice = TRUE; + else + WriteToDevice = FALSE; + + DPRINT1("IoMapTransfer\n"); + BaseAddress = pDevExt->pDmaAdapter->DmaOperations->MapTransfer(pDevExt->pDmaAdapter, + pDevExt->Mdl, + pDevExt->MapRegisterBase, + (PUCHAR) MmGetMdlVirtualAddress(pDevExt->Mdl), + &transferSize, + WriteToDevice); + + if (WriteToDevice) + { + DPRINT1("Writing to the device...\n"); + memcpy(VirtualAddress, ptr, size); + } + else + { + DPRINT1("Reading from the device...\n"); + memcpy(ptr, VirtualAddress, size); + }*/ + + //DPRINT1("VBuffer == 0x%x (really 0x%x?) transf_size == %u\n", pDevExt->VirtualBuffer, MmGetPhysicalAddress(pDevExt->VirtualBuffer).LowPart, transferSize); + //DPRINT1("VBuffer == 0x%x (really 0x%x?) transf_size == %u\n", ptr, MmGetPhysicalAddress(ptr).LowPart, transferSize); + + return MmGetPhysicalAddress(ptr).QuadPart;//BaseAddress.QuadPart; /* BIG HACK */ +} + +// 2.6 version of pci_unmap_single +//void my_dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, enum dma_data_direction direction) +void my_dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, enum dma_data_direction direction) +{ + //DPRINT1("dma_unmap_single() called, nothing to do\n"); + /* nothing yet */ +} + +void my_dma_sync_single(struct device *hwdev, + dma_addr_t dma_handle, + size_t size, int direction) +{ + DPRINT1("dma_sync_single() called, UNIMPLEMENTED\n"); + /* nothing yet */ +} + +void my_dma_sync_sg(struct device *hwdev, + struct scatterlist *sg, + int nelems, int direction) +{ + DPRINT1("dma_sync_sg() called, UNIMPLEMENTED\n"); + /* nothing yet */ +} + + +int my_dma_map_sg(struct device *hwdev, struct scatterlist *sg, int nents, enum dma_data_direction direction) +{ + DPRINT1("dma_map_sg() called, UNIMPLEMENTED\n"); + return 0; +} + +void my_dma_unmap_sg(struct device *hwdev, struct scatterlist *sg, int nents, enum dma_data_direction direction) +{ + DPRINT1("dma_unmap_sg() called, UNIMPLEMENTED\n"); + /* nothing yet */ +} + +/* forwarder ro dma_ equivalent */ +void my_pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int direction) +{ + my_dma_unmap_single(&hwdev->dev, dma_addr, size, direction); +}