📄 rtd-dm6430.c
字号:
/* FILE NAME: rtd-dm64320.c FILE DESCRIPTION: Driver code for DM6430 PROJECT NAME: Linux DM6430 Driver, Library, and Example Programs PROJECT VERSION: (Defined in README.TXT) Copyright 2004 RTD Embedded Technologies, Inc. All Rights Reserved.*/#include <linux/spinlock.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/version.h>//#include <linux/config.h>#include <linux/init.h>#include <linux/stat.h>#include <linux/fs.h>#include <linux/errno.h>#include <linux/types.h>#include <linux/sched.h>#include <linux/ioport.h>#include <linux/time.h>#include <linux/mm.h>#include <linux/signal.h>#include <linux/slab.h>#include <asm/io.h>#include <asm/dma.h>#include <asm/uaccess.h>#include <dm6430ioctl.h>#include <dm6430driver.h>#define DRIVER_NAME "rtd-dm6430"#define PROJECT_RELEASE "2.0"#define DRIVER_DESCRIPTION "DM6430 device driver"#define DRIVER_COPYRIGHT \ "Copyright 2004 RTD Embedded Technologies, Inc. All Rights Reserved."static const char name[] = DRIVER_NAME;static const char description[] __initdata= DRIVER_DESCRIPTION;static const char version[] __initdata= PROJECT_RELEASE;static const char copyright[] __initdata= DRIVER_COPYRIGHT;static unsigned char major __initdata= 0;static int force __initdata= 0;static size_t buflength __initdata= 0x10000; /* default value 64K */#ifdef DEBUGstatic int debug __initdata= 0;#endifstatic struct Dm6430hrDevice devices[DM6430HR_MAX_DEVS];#ifndef DEBUG#define dm_outb_p(x, y) (outb_p(y, x))#define dm_inb_p(x) (inb_p(x))#define dm_outw_p(x, y) (outw_p(y, x))#define dm_inw_p(x) (inw_p(x))#elseunsigned chardm_inb_p(unsigned port) { unsigned char byte_read; byte_read = inb_p(port); printk(KERN_INFO "%X = inb_p(%X);\n", byte_read, port); return byte_read;}unsigned shortdm_inw_p(unsigned port) { unsigned short word_read; word_read = inw_p(port); printk(KERN_INFO "%X = inw_p(%X);\n", word_read, port); return word_read;}voiddm_outb_p(unsigned port, unsigned char byte_to_write) { printk(KERN_INFO "outb_p(%X,%X);\n", port, byte_to_write); outb_p(byte_to_write, port);}voiddm_outw_p(unsigned port, unsigned short word_to_write) { printk(KERN_INFO "outw_p(%X,%X);\n", port, word_to_write); outw_p(word_to_write, port);}#endif#define dm_insb(port, addr, count) (insb((port), (addr), (count)))#define dm_insw(port, addr, count) (insw((port), (addr), (count)))#define dm_dma_mem_alloc(size) __get_dma_pages(GFP_KERNEL, get_order(size))#define dm_dma_mem_free(addr, size) free_pages(addr, get_order(size))static int dm6430hr_register_device(struct Dm6430hrDevice * dev);static void dm6430hr_unregister_device(struct Dm6430hrDevice *dev);#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,0))/* Pure 2^n version of get_order */static inline intget_order(unsigned long size) { int order; size = (size - 1) >> (PAGE_SHIFT - 1); order = -1; do { size >>= 1; order++; } while(size); return order;}#endif /* LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,98) */static voiddm_stop_dma(struct Dm6430hrDevice *device_p, int dma) { unsigned long flags; flags = claim_dma_lock(); disable_dma(device_p->dma[dma]); clear_dma_ff(device_p->dma[dma]); release_dma_lock(flags);}static inline voidDM6430HRClear(struct Dm6430hrDevice *device_p, unsigned short Mask) {#ifdef DEBUG if (debug & DBG_DEV) printk(KERN_INFO "DM6430HRClear(0x%04x)\n", Mask);#endif /* setup the clear mask */ dm_outw_p(device_p->io + r_CLEAR_6430, Mask); /* clear */ dm_inw_p(device_p->io + r_CLEAR_6430);}static voidDM6430HR_Initdev(struct Dm6430hrDevice *device_p) { int i;#ifdef DEBUG if (debug & DBG_IOCTLS) printk(KERN_INFO "DM6430HR_Initdev()\n");#endif spin_lock(&device_p->lock); device_p->Control_Register = 0; for (i = 0; i < DM6430HR_IRQS ; i++) { device_p->irq_count[i] = 0; } for (i = 0; i < DM6430HR_DMAS; i++) { device_p->dmabuf[i].addr = 0; device_p->dmabuf[i].length = 0; device_p->Control_Register |= (device_p->dma[i] & 0x03) << (i ? 14 : 12); } /* Default board settings */ dm_outw_p(device_p->io + r_CONTROL_6430, device_p->Control_Register); dm_outw_p(device_p->io + r_TRIGGER_6430, device_p->Trigger_Register = 0); dm_outw_p(device_p->io + r_IRQ_6430, device_p->IRQ_Register = 0); dm_outw_p(device_p->io + r_DIN_CONFIG_6430, device_p->DIN_Register = 0); DM6430HRClear(device_p, 0x00FF); spin_unlock(&device_p->lock);}static voidDM6430HRIRQEnable(struct Dm6430hrDevice *device_p, int IRQChannel, int Enable) { static const unsigned short IRQs[16] = {0, 0, 0, 1, 0, 2, 0, 0, 0, 3, 4, 5, 6, 0, 0, 7};#ifdef DEBUG if (debug & DBG_DEV) printk(KERN_INFO "DM6430HRIRQEnable(%d, %d)\n", IRQChannel, Enable);#endif device_p->IRQ_Register &= (IRQChannel ? 0x1FFF : 0xFF1F); if (Enable) device_p->IRQ_Register |= ((IRQs[device_p->irq[IRQChannel]]) << (IRQChannel ? 13 : 5)); dm_outw_p(device_p->io + r_IRQ_6430, device_p->IRQ_Register); /* clear irq */ DM6430HRClear(device_p, IRQChannel ? DM6430_CL_IRQ2 : DM6430_CL_IRQ1);}static inline struct Dm6430hrDevice *lookup_dev(int minor) { if (minor >= DM6430HR_MAX_DEVS) return 0; return &devices[minor];}/******************************************************************************validate_dma_circuit() Purpose: Determine if a DMA circuit number given on certain ioctl() calls is valid. Parameters: dma_circuit => DMA circuit number to validate. Return Value: 0 dma_circuit is valid. EINVAL dma_circuit is not valid.*******************************************************************************/static intvalidate_dma_circuit(int dma_circuit) { switch (dma_circuit) { case DM6430HR_DMA1: case DM6430HR_DMA2: return 0; break; default: return -EINVAL; break; }}/******************************************************************************validate_interrupt_circuit() Purpose: Determine if an interrupt circuit number given on certain ioctl() calls is valid. Parameters: interrupt_circuit => Interrupt circuit number to validate. Return Value: 0 interrupt_circuit is valid. EINVAL interrupt_circuit is not valid.*******************************************************************************/static intvalidate_interrupt_circuit(int interrupt_circuit) { switch (interrupt_circuit) { case DM6430HR_INT1: case DM6430HR_INT2: return 0; break; default: return -EINVAL; break; }}static intdm6430hr_open(struct inode *inode_p, struct file *file_p) { int rc; struct Dm6430hrDevice *device_p;#ifdef DEBUG if (debug & DBG_FILEOPS) printk(KERN_INFO "dm6430hr_open()\n");#endif device_p = lookup_dev(MINOR((inode_p)->i_rdev)); if (!device_p) return -ENXIO; if (!device_p->io) return -ENXIO; if ( !(device_p->flags & INITIALIZED) && (rc = dm6430hr_register_device(device_p)) ) return rc; if (file_p->private_data) return -EBUSY; file_p->private_data = device_p; atomic_inc(&device_p->counter); return 0;}static intdm6430hr_release(struct inode *inode_p, struct file *file_p) { struct Dm6430hrDevice *device_p;#ifdef DEBUG if (debug & DBG_FILEOPS) printk(KERN_INFO "dm6430hr_release()\n");#endif device_p = (struct Dm6430hrDevice *) file_p->private_data; if (device_p) { int i; spin_lock(&device_p->lock); for (i = 0; i < DM6430HR_IRQS; i++) { if (device_p->callback[i].process == current) { device_p->callback[i].signo = 0; device_p->callback[i].process = 0; device_p->callback[i].context = 0; } } spin_unlock(&device_p->lock); if (atomic_dec_and_test(&device_p->counter) && !force) dm6430hr_unregister_device(device_p); } file_p->private_data = 0; return 0;}static intDM6430HR_IOCTL_INB_Handler(struct Dm6430hrDevice *device_p, ulong arg) { struct DM6430HR_IO8 io_rq; if (copy_from_user(&io_rq, (struct DM6430HR_IO8 *) arg, sizeof(io_rq))) return -EFAULT; if (io_rq.reg >= DM6430HR_IO_EXTENT) return -EINVAL; spin_lock(&device_p->lock); io_rq.value = dm_inb_p(device_p->io + io_rq.reg); spin_unlock(&device_p->lock);#ifdef DEBUG if (debug & DBG_DEV) printk( KERN_INFO "INB io + 0x%04x, value 0x%02x\n", io_rq.reg, io_rq.value );#endif if (copy_to_user((struct DM6430HR_IO8 *) arg, &io_rq, sizeof(io_rq))) return -EFAULT; return 0;}static intDM6430HR_IOCTL_OUTB_Handler(struct Dm6430hrDevice *device_p, ulong arg) { struct DM6430HR_IO8 io_rq; if (copy_from_user(&io_rq, (struct DM6430HR_IO8 *) arg, sizeof(io_rq))) return -EFAULT; if (io_rq.reg >= DM6430HR_IO_EXTENT) return -EINVAL; spin_lock(&device_p->lock); dm_outb_p(device_p->io + io_rq.reg, io_rq.value); spin_unlock(&device_p->lock);#ifdef DEBUG if (debug & DBG_DEV) printk( KERN_INFO "OUTB io + 0x%04x = 0x%02x\n", io_rq.reg, io_rq.value );#endif return 0;}static intDM6430HR_IOCTL_MOUTB_Handler(struct Dm6430hrDevice *device_p, ulong arg) { u_int8_t value; struct DM6430HR_MIO8 io_rq; if (copy_from_user(&io_rq, (struct DM6430HR_IO8 *) arg, sizeof(io_rq))) return -EFAULT; if (io_rq.reg >= DM6430HR_IO_EXTENT) return -EINVAL; spin_lock(&device_p->lock); value = dm_inb_p(device_p->io + io_rq.reg); value = (value & io_rq.mask) | (io_rq.value & ~io_rq.mask); dm_outb_p(device_p->io + io_rq.reg, value); spin_unlock(&device_p->lock);#ifdef DEBUG if (debug & DBG_DEV) printk( KERN_INFO "MOUTB io + 0x%04x = 0x%04x(0x%04x/0x%04x)\n", io_rq.reg, value, io_rq.value, io_rq.mask );#endif return 0;}static intDM6430HR_IOCTL_INW_Handler(struct Dm6430hrDevice *device_p, ulong arg) { struct DM6430HR_IO16 io_rq; if (copy_from_user(&io_rq, (struct DM6430HR_IO16 *) arg, sizeof(io_rq))) return -EFAULT; if ((io_rq.reg > (DM6430HR_IO_EXTENT - 2)) || (io_rq.reg & 1)) return -EINVAL; spin_lock(&device_p->lock); io_rq.value = dm_inw_p(device_p->io + io_rq.reg); spin_unlock(&device_p->lock);#ifdef DEBUG if (debug & DBG_DEV) printk( KERN_INFO "INW io + 0x%04x, value 0x%04x\n", io_rq.reg, io_rq.value );#endif if (copy_to_user((struct DM6430HR_IO16 *) arg, &io_rq, sizeof(io_rq))) return -EFAULT; return 0;}static intDM6430HR_IOCTL_OUTW_Handler(struct Dm6430hrDevice *device_p, ulong arg) { struct DM6430HR_IO16 io_rq; if (copy_from_user(&io_rq, (struct DM6430HR_IO16 *) arg, sizeof(io_rq))) return -EFAULT; if ((io_rq.reg > (DM6430HR_IO_EXTENT - 2)) || (io_rq.reg & 1)) return -EINVAL; spin_lock(&device_p->lock); switch (io_rq.reg) { case r_CONTROL_6430: device_p->Control_Register = io_rq.value; break; case r_DIN_CONFIG_6430: device_p->DIN_Register = io_rq.value; break; case r_IRQ_6430: device_p->IRQ_Register = io_rq.value; break; case r_TRIGGER_6430: device_p->Trigger_Register = io_rq.value; break; default: ; } dm_outw_p(device_p->io + io_rq.reg, io_rq.value); spin_unlock(&device_p->lock);#ifdef DEBUG if (debug & DBG_DEV) printk( KERN_INFO "OUTW io + 0x%04x = 0x%04x\n", io_rq.reg, io_rq.value );#endif return 0;}static intDM6430HR_IOCTL_MOUTW_Handler(struct Dm6430hrDevice *device_p, ulong arg) { u_int16_t value, *value_p; struct DM6430HR_MIO16 io_rq; if (copy_from_user(&io_rq, (struct DM6430HR_IO16 *) arg, sizeof(io_rq))) return -EFAULT; if ((io_rq.reg > (DM6430HR_IO_EXTENT - 2)) || (io_rq.reg & 1)) return -EINVAL; spin_lock(&device_p->lock); switch (io_rq.reg) { case r_CONTROL_6430: value_p = &device_p->Control_Register; break; case r_DIN_CONFIG_6430: value_p = &device_p->DIN_Register; break; case r_IRQ_6430: value_p = &device_p->IRQ_Register; break; case r_TRIGGER_6430: value_p = &device_p->Trigger_Register; break; default: value = dm_inw_p(device_p->io + io_rq.reg); value_p = &value; } *value_p = (*value_p & io_rq.mask) | (io_rq.value & (~io_rq.mask)); dm_outw_p(device_p->io + io_rq.reg, *value_p); spin_unlock(&device_p->lock);#ifdef DEBUG if (debug & DBG_DEV)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -