⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 usb-ohci-s3c2440.c

📁 linux2.4.20下的针对三星公司的s3c2410的usb模块驱动代码
💻 C
字号:
/* *  linux/drivers/usb/usb-ohci-s3c24a.c */#include <linux/module.h>#include <linux/init.h>#include <linux/sched.h>#include <linux/ioport.h>#include <linux/interrupt.h>#include <linux/slab.h>#include <linux/usb.h>#include <linux/pci.h>                    #include <asm/hardware.h>#include <asm/irq.h>#include <asm/io.h>                     #define OHCI_HW_DRIVER#include "usb-ohci.h"/**************** pcibuf.c *******************//* * simple buffer allocator for copying of unsafe to safe buffers * uses __alloc/__free for actual buffers * keeps track of safe buffers we've allocated so we can recover the * unsafe buffers. */                                            #define MAX_SAFE        32#define SIZE_SMALL      1024#define SIZE_LARGE      (16*1024)                                            static long mapped_alloc_size;static char *safe_buffers[MAX_SAFE][2];static struct pci_pool *small_buffer_cache,*large_buffer_cache;                                            static intinit_safe_buffers(struct pci_dev *dev){        small_buffer_cache = pci_pool_create("pci_small_buffer",                                            dev,                                            SIZE_SMALL,                                            0 /* byte alignment */,                                            0 /* no page-crossing issues */,GFP_KERNEL | GFP_DMA);                                                    if (small_buffer_cache == 0)                return -1;                                                    large_buffer_cache = pci_pool_create("pci_large_buffer",                                            dev,                                            SIZE_LARGE,                                            0 /* byte alignment */,                                            0 /* no page-crossing issues */,                                            GFP_KERNEL | GFP_DMA);        if (large_buffer_cache == 0)                return -1;                                                    return 0;}/* allocate a 'safe' buffer and keep track of it */static char *alloc_safe_buffer(char *unsafe, int size, dma_addr_t *pbus){        char *safe;        dma_addr_t busptr;        struct pci_pool *pool;        int i;                                                    if (0) printk("alloc_safe_buffer(size=%d)\n", size);                                                    if (size <= SIZE_SMALL)                pool = small_buffer_cache;        else                if (size < SIZE_LARGE)                        pool = large_buffer_cache;                                else                                        return 0;        safe = pci_pool_alloc(pool, SLAB_ATOMIC, &busptr);        if (safe == 0)                return 0;                                                    for (i = 0; i < MAX_SAFE; i++)                if (safe_buffers[i][0] == 0) {                        break;                }                                                    if (i == MAX_SAFE) {                panic(__FILE__ ": exceeded MAX_SAFE buffers");        }                                                    /* place the size index and the oldbuffer ptr in the first 8 bytes         * and return a ptr + 12 to caller         */        ((int *)safe)[0] = i;        ((char **)safe)[1] = (char *)pool;        ((char **)safe)[2] = unsafe;                                                    busptr += sizeof(int) + sizeof(char*) + sizeof(char *);                                                    safe_buffers[i][0] = (void *)busptr;        safe_buffers[i][1] = (void *)safe;                                                    safe += sizeof(int) + sizeof(char *) + sizeof(char *);                                                    *pbus = busptr;        return safe;}                                            /* determine if a buffer is from our "safe"pool */static char *find_safe_buffer(char *busptr, char **unsafe){        int i;        char *buf;                                                    for (i = 0; i < MAX_SAFE; i++) {                if (safe_buffers[i][0] == busptr) {                        if (0) printk("find_safe_buffer(%p) found @ %d\n", busptr, i);                        buf = safe_buffers[i][1];                        *unsafe = ((char **)buf)[2];                        return buf + sizeof(int) + sizeof(char *) + sizeof(char *);                }        }                                                    return (char *)0;}                                            static voidfree_safe_buffer(char *buf){        int index;        struct pci_pool *pool;        char *dma;                                                    if (0) printk("free_safe_buffer(buf=%p)\n", buf);                                                    /* retrieve the buffer size index */        buf -= sizeof(int) + sizeof(char*) + sizeof(char*);        index = ((int *)buf)[0];        pool = (struct pci_pool *)((char **)buf)[1];                                                    if (0) printk("free_safe_buffer(%p) index %d\n", buf, index);                                                    if (index < 0 || index >= MAX_SAFE){                printk(__FILE__ ": free_safe_buffer() corrupt buffer\n");                return;        }                                                    dma = safe_buffers[index][0];        safe_buffers[index][0] = 0;                                                    pci_pool_free(pool, buf, (u32)dma);}                                            /*  NOTE:  replace pci_map/unmap_single with local routines which will  do buffer copies if buffer is above 1mb...*/                                            /* * see if a buffer address is in an 'unsafe' range.  if it is * allocate a 'safe' buffer and copy the unsafe buffer into it. * substitute the safe buffer for the unsafe one. * (basically move the buffer from an unsafe area to a safe one) * * we assume calls to map_single are symmetric with calls to unmap_single... */dma_addr_telfin_map_single(struct pci_dev *hwdev, void *virtptr,               size_t size, int direction){        dma_addr_t busptr;                                                    mapped_alloc_size += size;                                                    if (0) printk("pci_map_single(hwdev=%p,ptr=%p,size=%d,dir=%x) "                      "alloced=%ld\n",                      hwdev, virtptr, size,direction, mapped_alloc_size);                                                    busptr = virt_to_bus(virtptr);                                                    /* we assume here that a buffer will never be >=64k */        if ( (((unsigned long)busptr) & 0x100000) ||             ((((unsigned long)busptr)+size) & 0x100000) )        {                char *safe;                                                            safe = alloc_safe_buffer(virtptr, size, &busptr);                if (safe == 0) {                        printk("unable to map unsafe buffer %p!\n", virtptr);                        return 0;                }                                                            if (0) printk("unsafe buffer %p (phy=%p) mapped to %p (phy=%p)\n",                              virtptr, (void *)virt_to_bus(virtptr),                              safe, (void *)busptr);                                                            memcpy(safe, virtptr, size);                consistent_sync(safe, size,direction);                                                            return busptr;        }                                                    consistent_sync(virtptr, size, direction);        return busptr;}                                            /* * see if a mapped address was really a "safe" buffer and if so, * copy the data from the safe buffer back to the unsafe buffer * and free up the safe buffer. * (basically return things back to the waythey should be) */voidelfin_unmap_single(struct pci_dev *hwdev,dma_addr_t dma_addr,                 size_t size, int direction){        char *safe, *unsafe;        void *buf;                                                    /* hack; usb-ohci.c never sends hwdev==NULL, all others do */        if (hwdev == NULL) {                return;        }                                                    mapped_alloc_size -= size;                                                    if (0) printk("pci_unmap_single(hwdev=%p,ptr=%p,size=%d,dir=%x) "                      "alloced=%ld\n",                      hwdev, (void *)dma_addr, size, direction,                      mapped_alloc_size);                                                    if ((safe = find_safe_buffer((void *)dma_addr, &unsafe))) {                if (0) printk("copyback unsafe %p, safe %p, size %d\n",                              unsafe, safe,size);                                                            consistent_sync(safe, size,PCI_DMA_FROMDEVICE);                memcpy(unsafe, safe, size);                free_safe_buffer(safe);        } else {                /* assume this is normal memory */                buf = bus_to_virt(dma_addr);                consistent_sync(buf, size, PCI_DMA_FROMDEVICE);        }}/**************** pcibuf.c *******************/int __devinithc_add_ohci(struct pci_dev *dev, int irq, void *membase, unsigned long flags,	    ohci_t **ohci, const char *name, const char *slot_name);extern void hc_remove_ohci(ohci_t *ohci);static ohci_t *s3c2440_ohci;static void __init elfin_ohci_configure(void){	CLKDIVN = 0x7;  //p.bhushan@samsung.com for 48MHz.	//clkdivn got by oring DIVN_UPLL as 0, HDIVN as 11 and PDIVN as 1.		UPLLCON = (60<<12)|(4<<4)|2; //KAILAS FOR 48Mhz	mdelay(1);	CLKCON |= CLKCON_USBH;}static int elfin_ohci_init(void){	int ret;	elfin_ohci_configure();	ret = hc_add_ohci((struct pci_dev *)1, IRQ_USBH,			  (void *)(io_p2v(0x49000000)), 0, &s3c2440_ohci,			  "usb-ohci", "s3c2440");	return ret;}static void elfin_ohci_exit(void){	hc_remove_ohci(s3c2440_ohci);}static int __init elfin_init_safe_buffers(void){        printk("Initializing S3C2440 buffer pool for DMA workaround\n");        init_safe_buffers(NULL);        elfin_ohci_init();        return 0;}                                                                                                 static void free_safe_buffers(void){        elfin_ohci_exit();         pci_pool_destroy(small_buffer_cache);        pci_pool_destroy(large_buffer_cache);}EXPORT_SYMBOL(elfin_map_single);EXPORT_SYMBOL(elfin_unmap_single);module_init(elfin_init_safe_buffers);module_exit(free_safe_buffers);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -