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

📄 hmp4d.c

📁 Hantro Driver MP4 Hardware Encoder/Decoder
💻 C
📖 第 1 页 / 共 2 页
字号:
/*  * Decoder device driver (kernel module) * * Copyright (C) 2005  Hantro Products Oy. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. * */#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 */#include <linux/wrapper.h>/* needed for virt_to_phys() */#include <asm/io.h>/* devfs */#include <linux/devfs_fs_kernel.h>#include <asm/uaccess.h>#include <linux/ioport.h>#define NON_PAGE_ALIGNED	1 	/* non page aligned */#define CONS_ALLOC		1	/* use consistent alloc */#if CONS_ALLOCu32	hmp4d_phys;#endif/* our own stuff */#include "hmp4d.h"#ifdef MV	#include "asm/arch/mx2-regs.h"#else/* motorola bsp */	#include "asm/arch/mx2.h"	#include <linux/pm.h>	#include <asm/arch/apmc.h>	#define APM_HMP4D 1	/* use apm for hmp4e driver */#endif//#define NODEVFS/* module description */MODULE_AUTHOR("Hantro Products Oy");MODULE_DESCRIPTION("Device driver for Hantro's MPEG4 decoder HW");MODULE_SUPPORTED_DEVICE("4400 MPEG4 Decoder");/* these could be module params in the future */#define DEC_IO_BASE                 0x10026800#define DEC_IO_SIZE                 (8*4)   /* bytes */#define DEC_IRQ                     50#define HMP4D_BUF_SIZE              700000 /* bytes */#define DEC_HW_ID                   0x00001842unsigned 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;    u32 *hwregs;    unsigned int irq;    struct fasync_struct *async_queue;}hmp4d_t;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);/* local */#ifdef APM_HMP4D	static int hmp4d_pm_handler(struct pm_dev *pmdev, pm_request_t rqst, void *data);#endif/* global static */static devfs_handle_t devfs_handle = NULL;#ifdef APM_HMP4D	static struct pm_dev *pmdev;	static struct apmc_user *g_hmp4d_apmc;#endifstatic int g_hmp4d_busy = 0;	/* readable by other modules through ipc */void 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 write_access){    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;	/* maintain HCLK = 88MHz at doze mode */#ifdef APM_HMP4D	apmc_set_level(g_hmp4d_apmc, APMC_LEVEL_LOW);#endif    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_bus(hmp4d_data.buffer), (unsigned long *) arg);#else        __put_user(hmp4d_phys, (unsigned long *) arg);#endif        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;}static int hmp4d_open(struct inode *inode, struct file *filp){    int result;    hmp4d_t *dev = &hmp4d_data;    filp->private_data = (void *) dev;#if 1    if(MOD_IN_USE)  /* just single access */        return -EBUSY;#endif    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++)	{		if(i == 2 || i == 6)		{			/*do not write			register 0x08 & 0x1C are read only */		}		else		{			writel(0, dev->hwregs + i);		}	}}#endif    result = request_irq(dev->irq, hmp4d_isr,                         SA_INTERRUPT, "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;    }    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;    /* free the encoder IRQ */{#include <asm/irq.h>/*	disable_irq(dev->irq); */}    free_irq(dev->irq, (void *) dev);    ResetAsic(dev);    /* remove this filp from the asynchronusly notified filp's */    hmp4d_fasync(-1, filp, 0);	g_hmp4d_busy = 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,};/* changed to devfs */int __init hmp4d_init(void){    int result;    /* if you want to test the module, you obviously need to "mknod". */    PDEBUG("module init\n");    printk(KERN_INFO "hmp4d: base_port=0x%08lx irq=%i\n", base_port, irq);#ifdef MV	MAX_MST_MGPCR(4) = 0x1; /* allow AHB burst to be breakable by other masters */	AIPI_PAR(2) &= ~(0x1 << 6);	/* Grant access to eMMa region on AIPI2 bus */	CRM_PCCR0 |= 0x08008000;#else	_reg_MAX_MST_MGPCR(4) = 0x1;

⌨️ 快捷键说明

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