linux驱动开发扩展--自动创建设备文件并使用内核提供的寄存器读写接口例程

it2024-10-05  34

#include <linux/module.h> // module_init module_exit #include <linux/init.h> // __init __exit #include <linux/fs.h> #include <linux/string.h> #include <asm/uaccess.h> #include <mach/regs-gpio.h> #include <mach/gpio-bank.h> #include <linux/io.h> #include <linux/ioport.h> #include <mach/gpio-bank.h> #include <linux/cdev.h> #include <linux/types.h> #include <linux/device.h> //物理地址 #define GPJ0BASE 0xE0200240 #define GPJ0CON 0xE0200240 #define GPJ0DAT 0xE0200244 //虚拟地址 #define rGPJ0CON *((volatile unsigned int *)S5PV210_GPJ0CON) #define rGPJ0DAT *((volatile unsigned int *)S5PV210_GPJ0DAT) typedef struct GPJ0 { unsigned int CON; unsigned int DAT; }GPJ0_t; //GPJ0_t *pgpj0=NULL; static void __iomem *pgpj0; static dev_t devnb; char kbuf[10]="987654321"; static struct cdev mdev,*pdev; static struct class *test_class; volatile unsigned int *pGPJ0CON,*pGPJ0DAT; static int test_open(struct inode *inode, struct file *file) { printk(KERN_INFO "test_open\n"); //led on //rGPJ0CON = 0x11111111; //rGPJ0DAT = ((0<<3) | (0<<4) | (0<<5)); //*pGPJ0CON = 0x11111111; //*pGPJ0DAT = ((0<<3) | (0<<4) | (0<<5)); // 亮 //pgpj0->CON= 0x11111111; //pgpj0->DAT = ((0<<3) | (0<<4) | (0<<5)); // 亮 writel(0x11111111,pgpj0); writel(((0<<3) | (0<<4) | (0<<5)),pgpj0+4); return 0; } static int test_release(struct inode *inode, struct file *file) { printk(KERN_INFO "test_release\n"); //led off //rGPJ0CON = 0x11111111; //rGPJ0DAT = ((1<<3) | (1<<4) | (1<<5)); //*pGPJ0CON = 0x11111111; //*pGPJ0DAT = ((1<<3) | (1<<4) | (1<<5)); // 亮 //pgpj0->CON= 0x11111111; //pgpj0->DAT= ((1<<3) | (1<<4) | (1<<5)); // 亮 return 0; } static ssize_t test_read(struct file *file, char __user *buf, size_t size, loff_t *ppos) { int ret=-1; printk(KERN_INFO "test_chrdev_read\n"); ret=copy_to_user(buf,kbuf,10); if(ret) { printk(KERN_ERR "copy_to_user error, ret = %d.\n", ret); return ret; } printk(KERN_INFO "copy_to_user ok, ret = %d.\n", ret); return 0; } static ssize_t test_write(struct file *file, const char __user *buf,size_t siz, loff_t *ppos) { int ret=-1; printk(KERN_INFO "test_chrdev_write\n"); memset(kbuf, 0, 10); ret=copy_from_user(kbuf,buf,10); if(ret) { printk(KERN_ERR "copy_from_user error, ret = %d.\n", ret); return ret; } printk(KERN_INFO "copy_from_user ok, ret = %d.\n", ret); printk(KERN_INFO "buf = %s.\n", kbuf); return 0; } static const struct file_operations test_fops = { .owner = THIS_MODULE, .open = test_open, .release = test_release, .read = test_read, .write = test_write, }; // 模块安装函数 static int __init chrdev_init(void) { int ret=-1; printk(KERN_INFO "chrdev_init helloworld init\n"); //printk("<7>" "chrdev_init helloworld init\n"); //printk("<7> chrdev_init helloworld init\n"); //申请设备号 /*自己定义设备号*/ #if 0 devnb=MKDEV(250,12); ret=register_chrdev_region(devnb,1,"test-dev"); if (ret < 0) printk(KERN_WARNING "test: could not get major number\n"); #endif /*内核分配设备号*/ ret = alloc_chrdev_region(&devnb, 12, 1, "test-dev"); if (ret < 0) printk(KERN_ERR "%s: failed to allocate char dev region\n",__FILE__); printk(KERN_INFO "test: get major number done!\n"); printk(KERN_INFO "MA: %d MI: %d \n",MAJOR(devnb),MINOR(devnb)); //注册字符设备驱动 pdev = cdev_alloc(); //cdev_init(&mdev, &test_fops); cdev_init(pdev, &test_fops); //ret = cdev_add(&mdev, devnb, 1); ret = cdev_add(pdev, devnb, 1); if (ret) { printk(KERN_ERR "Unable to cdev_add\n"); return -EINVAL; } printk(KERN_INFO "cdev_add success\n"); //申请动态映射所需内存资源 //if (!request_mem_region(GPJ0CON, 4,"GPJ0CON,")) // return -EBUSY; //if (!request_mem_region(GPJ0DAT, 4, "GPJ0DAT")) // return -EINVAL; if (!request_mem_region(GPJ0BASE, sizeof(GPJ0_t), "GPJ0")) return -EINVAL; //建立动态映射 //pGPJ0CON = ioremap(GPJ0CON, 4); //pGPJ0DAT = ioremap(GPJ0DAT, 4); pgpj0 = ioremap(GPJ0BASE, sizeof(GPJ0_t)); //自动创建设备文件 test_class = class_create(THIS_MODULE, "test"); if (IS_ERR(test_class)) { printk(KERN_ERR "test: failed to create class"); return -EINVAL; } device_create(test_class, NULL, devnb, NULL, "test"); return 0; } // 模块下载函数 static void __exit chrdev_exit(void) { printk(KERN_INFO "chrdev_exit helloworld exit\n"); //销毁动态映射 //iounmap(pGPJ0CON); //iounmap(pGPJ0DAT); iounmap(pgpj0); //释放动态映射资源 //release_mem_region(GPJ0CON, 4); //release_mem_region(GPJ0DAT, 4); release_mem_region(GPJ0BASE, sizeof(GPJ0_t)); //注销字符设备驱动并释放设备号 //cdev_del(&mdev); cdev_del(pdev); unregister_chrdev_region(devnb, 1); //自动删除设备文件 device_destroy(test_class, devnb); class_destroy(test_class); } module_init(chrdev_init); module_exit(chrdev_exit); // MODULE_xxx这种宏作用是用来添加模块描述信息 MODULE_LICENSE("GPL"); // 描述模块的许可证 MODULE_AUTHOR("aston"); // 描述模块的作者 MODULE_DESCRIPTION("module test"); // 描述模块的介绍信息 MODULE_ALIAS("alias xxx"); // 描述模块的别名信息

 

最新回复(0)