📄 hmp4d.c.svn-base
字号:
/******************************************************************************** ** This software is confidential and proprietary and may be used ** only as expressly authorized by a licensing agreement from ** ** Hantro Products Oy. ** ** In the event of publication, the following notice is applicable: ** ** (C) COPYRIGHT 2002 HANTRO PRODUCTS OY ** ALL RIGHTS RESERVED ** ** The entire notice above must be reproduced on all copies. ** *********************************************************************************** Project : 1200s** Abstract : Decoder Driver Module*********************************************************************************** Version control information, please leave untouched.** $RCSfile$* $Author$* $Date$* $Revision$********************************************************************************/#include <linux/kernel.h>#include <linux/module.h>/* needed for __init,__exit directives */#include <linux/init.h>/* needed for remap_page_range */#include <linux/mm.h>/* obviously, for kmalloc */#include <linux/slab.h>/* for struct file_operations, register_chrdev() */#include <linux/fs.h>#include <linux/interrupt.h>/* standard error codes */#include <linux/errno.h>/* this header files wraps some common module-space operations ... here we use mem_map_reserve() macro *///#include <linux/wrapper.h>#define mem_map_reserve(p) set_bit(PG_reserved, &((p)->flags))#define mem_map_unreserve(p) clear_bit(PG_reserved, &((p)->flags))/* needed for virt_to_phys() */#include <asm/io.h>#include <asm/uaccess.h>#include <linux/ioport.h>#define NON_PAGE_ALIGNED 1 /* non page aligned */#define CONS_ALLOC 0 /* use consistent alloc */#if CONS_ALLOCu32 hmp4d_phys;#endif/* our own includes */#include "hmp4d.h"/* module description */MODULE_AUTHOR("Hantro Products Oy");MODULE_LICENSE("GPL");MODULE_DESCRIPTION("Device driver for Hantro's MPEG4 decoder HW");MODULE_SUPPORTED_DEVICE("1200s MPEG4 Decoder");/* this is ARM Integrator specific */#define INTEGRATOR_LOGIC_MODULE0_BASE 0x20000000#define INT_EXPINT1 28 /* these could be module params in the future */#define DEC_IO_BASE INTEGRATOR_LOGIC_MODULE0_BASE#define DEC_IO_SIZE (22*4) /*(35*4)*/ #define DEC_IRQ INT_EXPINT1#define HMP4D_BUF_SIZE (1048576)/* bytes */#define DEC_HW_ID 0x5150unsigned long base_port = DEC_IO_BASE;unsigned int irq = DEC_IRQ;MODULE_PARM(base_port, "l");MODULE_PARM(irq, "i");/* and this is our MAJOR; use 0 for dynamic allocation (recommended)*/static int hmp4d_major = 0;/* here's all the must remember stuff */typedef struct{ char *buffer; unsigned int buffsize; unsigned long iobaseaddr; unsigned int iosize; volatile u8 *hwregs; unsigned int irq; struct fasync_struct *async_queue;}hmp4d_t;void dump_regs(unsigned long data);static hmp4d_t hmp4d_data; /* dynamic allocation? */static int AllocMemory(void);static void FreeMemory(void);static int ReserveIO(void);static void ReleaseIO(void);static int MapBuffers(struct file *filp, struct vm_area_struct *vma);static int MapHwRegs(struct file *filp, struct vm_area_struct *vma);static void ResetAsic(hmp4d_t * dev);int hmp4d_isr(int irq, void *dev_id, struct pt_regs *regs);/* VM operations */static struct page *hmp4d_vm_nopage(struct vm_area_struct *vma, unsigned long address, int *type){ PDEBUG("hmp4d_vm_nopage: problem with mem access\n"); return NOPAGE_SIGBUS; /* send a SIGBUS */}static void hmp4d_vm_open(struct vm_area_struct *vma){ //MOD_INC_USE_COUNT; PDEBUG("hmp4d_vm_open:\n");}static void hmp4d_vm_close(struct vm_area_struct *vma){ //MOD_DEC_USE_COUNT; PDEBUG("hmp4d_vm_close:\n");}static struct vm_operations_struct hmp4d_vm_ops = { open:hmp4d_vm_open, close:hmp4d_vm_close, nopage:hmp4d_vm_nopage,};/* the device's mmap method. The VFS has kindly prepared the process's * vm_area_struct for us, so we examine this to see what was requested. */static int hmp4d_mmap(struct file *filp, struct vm_area_struct *vma){ int result; unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;#if NON_PAGE_ALIGNED int ofs; ofs = hmp4d_data.iobaseaddr & (PAGE_SIZE - 1);#endif PDEBUG("hmp4d_mmap: size = %lu off = 0x%08lx\n", vma->vm_end - vma->vm_start, offset); if(offset == 0) result = MapBuffers(filp, vma);#if NON_PAGE_ALIGNED else if(offset == hmp4d_data.iobaseaddr - ofs)#else else if(offset == hmp4d_data.iobaseaddr)#endif result = MapHwRegs(filp, vma); else result = -EINVAL; if(result == 0) { vma->vm_ops = &hmp4d_vm_ops; /* open is not implicitly called when mmap is called */ hmp4d_vm_open(vma); } return result;}static int hmp4d_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg){ int err = 0; PDEBUG("ioctl cmd 0x%08ux\n", cmd); /* * extract the type and number bitfields, and don't decode * wrong cmds: return ENOTTY (inappropriate ioctl) before access_ok() */ if(_IOC_TYPE(cmd) != HMP4D_IOC_MAGIC) return -ENOTTY; if(_IOC_NR(cmd) > HMP4D_IOC_MAXNR) return -ENOTTY; /* * the direction is a bitmask, and VERIFY_WRITE catches R/W * transfers. `Type' is user-oriented, while * access_ok is kernel-oriented, so the concept of "read" and * "write" is reversed */ if(_IOC_DIR(cmd) & _IOC_READ) err = !access_ok(VERIFY_WRITE, (void *) arg, _IOC_SIZE(cmd)); else if(_IOC_DIR(cmd) & _IOC_WRITE) err = !access_ok(VERIFY_READ, (void *) arg, _IOC_SIZE(cmd)); if(err) return -EFAULT; switch (cmd) { case HMP4D_IOCHARDRESET: /* * reset the counter to 1, to allow unloading in case * of problems. Use 1, not 0, because the invoking * process has the device open. */ /* while(MOD_IN_USE) MOD_DEC_USE_COUNT; MOD_INC_USE_COUNT; */ break; case HMP4D_IOCGBUFBUSADDR:#if !CONS_ALLOC __put_user(virt_to_phys(hmp4d_data.buffer), (unsigned long *) arg);#else __put_user(hmp4d_phys, (unsigned long *) arg);#endif break; case HMP4D_IOCXVIRT2BUS: { unsigned long base; __get_user(base, (unsigned int *) arg); base = virt_to_phys((void *)base); __put_user(base, (unsigned int *) arg); } break; case HMP4D_IOCGBUFSIZE: __put_user(hmp4d_data.buffsize, (unsigned int *) arg); break; case HMP4D_IOCGHWOFFSET: __put_user(hmp4d_data.iobaseaddr, (unsigned long *) arg); break; case HMP4D_IOCGHWIOSIZE: __put_user(hmp4d_data.iosize, (unsigned int *) arg); break; } return 0;}#define IRQTEST1static int hmp4d_open(struct inode *inode, struct file *filp){ int result; hmp4d_t *dev = &hmp4d_data; printk("trying to open dev\n"); filp->private_data = (void *) dev;#if 0 if(MOD_IN_USE) /* just single access */ return -EBUSY;#endif#if 0 writel(0, dev->hwregs); /* disable first */#if 0 /*no-word write to any reg & write to reg7 causes AHB error*/ memset_io(dev->hwregs, 0, hmp4d_data.iosize); /* reset the HW interface */#else{ int i; for (i = 0; i < hmp4d_data.iosize / 4 - 1; i++) { writel(0, dev->hwregs + i); }}#endif#endif#ifndef IRQTEST1 result = request_irq(dev->irq, hmp4d_isr, SA_SHIRQ, "hmp4d", (void *) dev); if(result == -EINVAL) { printk(KERN_ERR "hmp4d: Bad irq number or handler\n"); return result; } else if(result == -EBUSY) { printk(KERN_ERR "hmp4d: IRQ %d busy, change your config\n", dev->irq); return result; }#endif// hantro_request_fb(); //MOD_INC_USE_COUNT; PDEBUG("dev opened\n"); return 0;}static int hmp4d_fasync(int fd, struct file *filp, int mode){ hmp4d_t *dev = (hmp4d_t *) filp->private_data; PDEBUG("fasync called\n"); return fasync_helper(fd, filp, mode, &dev->async_queue);}static int hmp4d_release(struct inode *inode, struct file *filp){ hmp4d_t *dev = (hmp4d_t *) filp->private_data; printk("trying to release dev\n");// hantro_free_fb(); /* free the encoder IRQ */// sasi{#include <asm/irq.h>// disable_irq(dev->irq);}#ifndef IRQTEST1 free_irq(dev->irq, (void *) dev);#endif ResetAsic(dev); /* remove this filp from the asynchronusly notified filp's */ hmp4d_fasync(-1, filp, 0); //MOD_DEC_USE_COUNT; PDEBUG("dev closed\n"); return 0;}/* VFS methods */static struct file_operations hmp4d_fops = { mmap:hmp4d_mmap, open:hmp4d_open, release:hmp4d_release, ioctl:hmp4d_ioctl, fasync:hmp4d_fasync,};static int use_hmp4d=1;static int __init setup_hmp4d(char *str){ if(str[0] == '0') use_hmp4d=0; return 1;}__setup("hmp4d=", setup_hmp4d);int __init hmp4d_init(void){ int result;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -