📄 hmp4e.c
字号:
/*-------------------------------------------------------------------------------- ---- 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 2003 HANTRO PRODUCTS OY ---- ALL RIGHTS RESERVED ---- ---- The entire notice above must be reproduced on all copies. ---- -------------------------------------------------------------------------------------- Project : 1200s---- Abstract : Encoder device driver (kernel module)-------------------------------------------------------------------------------------- Version control information, please leave untouched.---- $RCSfile$-- $Author: root $-- $Date: 2006-03-15 11:58:36 +0800 (Wed, 15 Mar 2006) $-- $Revision: 2 $-- $Name$--------------------------------------------------------------------------------*/#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>/* standard error codes */#include <linux/errno.h>/* this header files wraps some common module-space operations ... here we use mem_map_reserve() macro */#define mem_map_reserve(p) set_bit(PG_reserved, &((p)->flags))#define mem_map_unreserve(p) clear_bit(PG_reserved, &((p)->flags))/* #include <linux/wrapper.h> *//* needed for virt_to_phys() */#include <asm/io.h>#include <linux/pci.h>#include <asm/uaccess.h>#include <linux/ioport.h>#include <linux/interrupt.h>/* our own stuff */#include "hmp4e.h"/* module description */MODULE_AUTHOR("Hantro Products Oy");MODULE_DESCRIPTION("Device driver for Hantro's hardware based MPEG4 encoder");MODULE_SUPPORTED_DEVICE("5250 MPEG4 Encoder");/* this is ARM Integrator specific stuff */#define INTEGRATOR_LOGIC_MODULE0_BASE 0x2000C000#define INT_EXPINT0 29/* these could be module params in the future */#define ENC_IO_BASE INTEGRATOR_LOGIC_MODULE0_BASE#define ENC_IO_SIZE (35*4) /* bytes */#define ENC_IRQ INT_EXPINT0#define HMP4E_BUF_SIZE (1048576) /* bytes */#define ENC_HW_ID 0x52500000unsigned long base_porte = INTEGRATOR_LOGIC_MODULE0_BASE;unsigned int irqe = ENC_IRQ;MODULE_PARM(base_porte, "l");MODULE_PARM_DESC(base_porte, "IO base address of the encoder hardware");MODULE_PARM(irqe, "i");MODULE_PARM_DESC(irqe, "interrupt number used by the encoder hardware");/* and this is our MAJOR; use 0 for dynamic allocation (recommended)*/static int hmp4e_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;}hmp4e_t;static hmp4e_t hmp4e_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(hmp4e_t * dev);int hmp4e_isr(int irq, void *dev_id, struct pt_regs *regs);#define pte_offset(dir, addr) ((pte_t *)pmd_page(*(dir)) + __pte_index(addr))/* Given PGD from the address space's page table, return the kernel * virtual mapping of the physical memory mapped at ADR. */static inline unsigned long uvirt_to_kva(pgd_t * pgd, unsigned long adr){ unsigned long ret = 0UL; pmd_t *pmd; pte_t *ptep, pte; if(!pgd_none(*pgd)) { pmd = pmd_offset(pgd, adr); if(!pmd_none(*pmd)) { ptep = pte_offset(pmd, adr); pte = *ptep; if(pte_present(pte)) { ret = (unsigned long) page_address(pte_page(pte)); ret |= (adr & (PAGE_SIZE - 1)); } } } PDEBUG("uv2kva(%lx-->%lx)", adr, ret); return ret;}static inline unsigned long uvirt_to_bus(unsigned long adr){ unsigned long kva, ret; pgd_t *pgd = pgd_offset(current->mm, adr); PDEBUG("uv2b got pgd"); kva = uvirt_to_kva(pgd, adr); ret = virt_to_phys((void *) kva); PDEBUG("uv2b(%lx-->%lx)", adr, ret); return ret;}/* VM operations */static struct page *hmp4e_vm_nopage(struct vm_area_struct *vma, unsigned long address, int write_access){ PDEBUG("hmp4e_vm_nopage: problem with mem access\n"); return NOPAGE_SIGBUS; /* send a SIGBUS */}static void hmp4e_vm_open(struct vm_area_struct *vma){ //MOD_INC_USE_COUNT; PDEBUG("hmp4e_vm_open:\n");}static void hmp4e_vm_close(struct vm_area_struct *vma){ //MOD_DEC_USE_COUNT; PDEBUG("hmp4e_vm_close:\n");}static struct vm_operations_struct hmp4e_vm_ops = { open:hmp4e_vm_open, close:hmp4e_vm_close, nopage:hmp4e_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 hmp4e_mmap(struct file *filp, struct vm_area_struct *vma){ int result; unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; PDEBUG("hmp4e_mmap: size = %lu off = 0x%08lx\n", (unsigned long) (vma->vm_end - vma->vm_start), offset); if(offset == 0) result = MapBuffers(filp, vma); else if(offset == hmp4e_data.iobaseaddr) result = MapHwRegs(filp, vma); else result = -EINVAL; if(result == 0) { vma->vm_ops = &hmp4e_vm_ops; /* open is not implicitly called when mmap is called */ hmp4e_vm_open(vma); } return result;}static int hmp4e_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) != HMP4E_IOC_MAGIC) return -ENOTTY; if(_IOC_NR(cmd) > HMP4E_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 HMP4E_IOCGBUFBUSADDRESS: __put_user(virt_to_phys(hmp4e_data.buffer), (unsigned long *) arg); break; case HMP4E_IOCGBUFSIZE: __put_user(hmp4e_data.buffsize, (unsigned int *) arg); break; case HMP4E_IOCGHWOFFSET: __put_user(hmp4e_data.iobaseaddr, (unsigned long *) arg); break; case HMP4E_IOCGHWIOSIZE: __put_user(hmp4e_data.iosize, (unsigned int *) arg); break; case HMP4E_IOC_CLI: disable_irq(hmp4e_data.irq); break; case HMP4E_IOC_STI: enable_irq(hmp4e_data.irq); break; case HMP4E_IOCXVIRT2BUS: { unsigned long base; __get_user(base, (unsigned int *) arg); base = uvirt_to_bus(base); __put_user(base, (unsigned int *) arg); } break; case HMP4E_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; } return 0;}static int hmp4e_open(struct inode *inode, struct file *filp){ int result; hmp4e_t *dev = &hmp4e_data; filp->private_data = (void *) dev;#if 0 if(MOD_IN_USE) /* just single access */ return -EBUSY;#endif result = request_irq(dev->irq, hmp4e_isr, SA_INTERRUPT, "hmp4e", (void *) dev); if(result == -EINVAL) { printk(KERN_ERR "hmp4e: Bad irq number or handler\n"); return result; } else if(result == -EBUSY) { printk(KERN_ERR "hmp4e: IRQ %d busy, change your config\n", dev->irq); return result; }/* enable_irq(dev->irq); */ //MOD_INC_USE_COUNT; PDEBUG("dev opened\n"); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -