📄 hpi_driver.c
字号:
/********************************************************************* * * * Filename: HPI_Driver.c * Version: 0.0.1 * Description: Implementation for the kernel module debug * Status: Experimental. * Author: snowerlist (snowerlist@163.com) * Created at: WuHan * Based on code by: snower * * Copyright (c) 2008.12 WH, All Rights Reserved. * This file is for ARM chip of DSP project xxx * 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. * ********************************************************************/#include <linux/module.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/interrupt.h>#include <linux/time.h>#include <linux/timer.h>#include <linux/fs.h>#include <linux/miscdevice.h>#include <linux/string.h>#include <linux/errno.h>#include <linux/init.h>#include <asm/uaccess.h>#include <asm/irq.h>#include <asm/mach-types.h>#include "HPI_Driver.h"static stDSPHPIInfo DSPHPIInfo;/* * Send singal to application who set his pid through ioctl, then the applicatioon will wakeup for this singal. * This is always used in interrupt! */ static void DSP_HPI_Signal_Send(void){ DSPHPIInfo.m_InterfaceSingal.si_signo = SIGRTMIN; DSPHPIInfo.m_InterfaceSingal.si_code = SI_KERNEL; DSPHPIInfo.m_InterfaceSingal.si_value.sival_int = DSP_HPI_ALARM; send_sig_info(SIGRTMIN, &DSPHPIInfo.m_InterfaceSingal, DSPHPIInfo.m_pstInterfaceTask); #ifdef debug printk("\nopsm irq detected!\n");#endif return;}/* * If interrupt function is used in this module, please implement this! */ static irqreturn_t DSP_HPI_Interrupt_Handler (int irq, void *dev_id, struct pt_regs *regs){ /*Add your interrupt handle code here!*/ DSP_HPI_Signal_Send(); /*Inform apps something happened!*/ return IRQ_HANDLED;}/* * This function is called when a user space program attempts to read * /dev/DSP_HPI. It puts the device to sleep on the wait queue until * button_sequence_finished writes some data to the buffer and flushes * the queue, at which point it writes the data out to the device and * returns the number of characters it has written. This function is * reentrant, so that many processes can be attempting to read from the * device at any one time. */static int DSP_HPI_Open(struct inode *inode, struct file *file){ int retval=0; MOD_INC_USE_COUNT; return retval;}static int DSP_HPI_Release (struct inode *inode, struct file *filp){ int retval=0; MOD_DEC_USE_COUNT; return retval;}static int DSP_HPI_Ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ int err = 0,ret_value=0; switch(cmd) { case INTERFACE_SET_CUR_PID: DSPHPIInfo.m_tInterfaceProcessID = arg; DSPHPIInfo.m_pstInterfaceTask = find_task_by_pid(DSPHPIInfo.m_tInterfaceProcessID);#ifdef debug printk("set current process pid %d\n", interface_process_id);#endif break; break; case READ_HPI_REG1: ret_value = (*(volatile u32 *)(DSPHPIInfo.m_stVirtualAddrSpace.m_pViturAddrReg1)); return ret_value; break; case READ_HPI_REG2: break; case READ_HPI_REG3: break; case READ_HPI_REG4: break; case WRITE_HPI_REG1: break; case WRITE_HPI_REG2: break; case WRITE_HPI_REG3: break; case WRITE_HPI_REG4: break; default: return -ENOTTY; break; } return 0;}static ssize_t DSP_HPI_Read (struct file *filp, char __user *buffer, size_t count, loff_t *ppos){ u32 u32ReadLength; ssize_t retval = 0; if(down_interruptible(&DSPHPIInfo.m_stProctoolSem)) return -ERESTARTSYS; if(count > (MAX_BUFFER_LEN)) { u32ReadLength = MAX_BUFFER_LEN; } /*Copy you data to m_pacBuffer*/ if (copy_to_user(buffer, DSPHPIInfo.m_stBufInfo.m_pacBuffer, u32ReadLength)) { retval = -EFAULT;#ifdef debug printk(KERN_INFO "DSP_HPI_Read: No enough buffer!\n");#endif goto out; } retval = u32ReadLength; out: up(&DSPHPIInfo.m_stProctoolSem); return retval;/* Return the number of bytes "read" */}static ssize_t DSP_HPI_Write (struct file *filp, char __user *buffer, size_t count, loff_t *ppos){ u32 u32WriteLength; ssize_t retval = -ENOMEM; /* value used in "goto out" statements */ if(down_interruptible(&DSPHPIInfo.m_stProctoolSem)) return -ERESTARTSYS; if(MAX_BUFFER_LEN <= count) {#ifdef debug printk(KERN_INFO "DSP_HPI_Write: No enough buffer!\n"); #endif goto out; } u32WriteLength = count; if(copy_from_user(DSPHPIInfo.m_stBufInfo.m_pacBuffer, buffer, u32WriteLength)) { retval = -EFAULT;#ifdef debug printk(KERN_INFO "DSP_HPI_Write: Get from Userspace fault!\n");#endif goto out; } DSPHPIInfo.m_stBufInfo.m_NewDataCount = u32WriteLength; retval = u32WriteLength; out: up(&DSPHPIInfo.m_stProctoolSem); return retval;}/* * This structure is the file operations structure, which specifies what * callbacks functions the kernel should call when a user mode process * attempts to perform these operations on the device. */static const struct file_operations DSP_HPI_fops = { .owner = THIS_MODULE, .open = DSP_HPI_Open, .release = DSP_HPI_Release, .ioctl = DSP_HPI_Ioctl, .read = DSP_HPI_Read, .write = DSP_HPI_Write,};/* * This structure is the misc device structure, which specifies the minor * device number (158 in this case), the name of the device (for /proc/misc), * and the address of the above file operations structure. */static struct miscdevice DSP_HPI_misc_device = { DSP_HPI_MINOR, DSP_HPI_DEV, &DSP_HPI_fops,};/*For this function you should check whether ioremap is successed by */static void Set_Vitual_Address(void){ DSPHPIInfo.m_stVirtualAddrSpace.m_pViturAddrReg1 = (u32 *)ioremap(PHY_ADDR_REG1, REGISTER_LENGTH); DSPHPIInfo.m_stVirtualAddrSpace.m_pViturAddrReg2 = (u32 *)ioremap(PHY_ADDR_REG2, REGISTER_LENGTH); DSPHPIInfo.m_stVirtualAddrSpace.m_pViturAddrReg3 = (u32 *)ioremap(PHY_ADDR_REG3, REGISTER_LENGTH); DSPHPIInfo.m_stVirtualAddrSpace.m_pViturAddrReg4 = (u32 *)ioremap(PHY_ADDR_REG4, REGISTER_LENGTH); return;}static int __init DSP_HPI_Init(void){ printk (KERN_INFO "DSP_HPI Driver Version %s (C) snowerlist " "<snowerlist@163.com> 2008.12.\n", DRIVER_VERSION); Set_Vitual_Address(); if (misc_register (&DSP_HPI_misc_device)) { printk (KERN_WARNING "DSP_HPI: Couldn't register device, " "%d.\n", DSP_HPI_MINOR); return -EBUSY; } if (request_irq (DSP_HPI_IRQ_NUM, DSP_HPI_Interrupt_Handler, DSP_HPI_IRQ_FLAG, DSP_HPI_DEV, NULL)) { printk (KERN_WARNING "DSP_HPI: IRQ %d is not free.\n", DSP_HPI_IRQ_NUM); misc_deregister (&DSP_HPI_misc_device); return -EIO; } return 0;}static void __exit DSP_HPI_Exit (void) { free_irq (DSP_HPI_IRQ_NUM, NULL); misc_deregister (&DSP_HPI_misc_device);}module_init(DSP_HPI_Init);module_exit(DSP_HPI_Exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("snowerlist <snower@163.com>");MODULE_DESCRIPTION("Kernel Driver for DSP HPI Interface");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -