1、混杂设备
什么是上拉电阻和下拉电阻?在GPIO端口中,一般一个芯片例如2440,会分为9组的GPIO端口。GPA GPB ...以GPA为例。GPACON用于设置端口的功能。GPADAT用于读写数据。GPAUP用于决定是否使用上拉电阻
主设备号为10的字符设备称为混杂设备。
为什么要引入混杂设备呢?为什么要把它从字符设备中独立出来。
字符驱动的使用方式有很多,①
我们先看一下通过字符设备来控制led的驱动程序:(1)初始化字符操作集,(2)分配devno设备号,(3)把dev添加到字符设备中;
#include <linux/module.h> #include <linux/init.h> #include <linux/cdev.h> #include <linux/fs.h> #include <linux/io.h>struct cdev cdev; dev_t devno; int led_open(struct inode *node, struct file *filp) {} long led_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) {} static struct file_operations led_fops = { .open = led_open, .unlocked_ioctl = led_ioctl, }; static int led_init() { cdev_init(&cdev,&led_fops); alloc_chrdev_region(&devno, 0 , 1 , "myled"); cdev_add(&cdev, devno, 1); return 0; } static void led_exit() { cdev_del(&cdev); unregister_chrdev_region(devno,1); } module_init(led_init); module_exit(led_exit);
MODULE_LICENSE("GPL");
我们发现每次这样使用字符设备时比较麻烦的,需要初始化、分配以及添加cdev devno;很多时候都是利用mknod命令手动创建设备节点。
实际上Linux内核为我们提供了一组函数,可以用来在模块加载的时候自动在/dev目录下创建相应设备节点,并在卸载模块时删除该节点
#include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/init.h> #include <linux/delay.h> #include <asm/uaccess.h> #include <asm/irq.h> #include <asm/io.h> #include <asm/arch/regs-gpio.h> #include <asm/hardware.h> static struct class *firstdrv_class; static struct class_device *firstdrv_class_dev; static int first_drv_open(struct inode *inode, struct file *file) {} static ssize_t first_drv_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos) {} static struct file_operations first_drv_fops = { .owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */ .open = first_drv_open, .write = first_drv_write, }; int major; static int first_drv_init(void) { major = register_chrdev(0, "first_drv", &first_drv_fops); // 注册, 告诉内核 firstdrv_class = class_create(THIS_MODULE, "firstdrv"); firstdrv_class_dev = class_device_create(firstdrv_class, NULL, MKDEV(major, 0), NULL, "xyz"); /* /dev/xyz */return 0; } static void first_drv_exit(void) { unregister_chrdev(major, "first_drv"); // 卸载 class_device_unregister(firstdrv_class_dev); class_destroy(firstdrv_class); iounmap(gpbcon); } module_init(first_drv_init); module_exit(first_drv_exit); MODULE_LICENSE("GPL");
2、回归正题--混杂设备驱动
(1)混杂设备结构体描述
(2)混杂设备注册
(3)代码案例
#include <linux/module.h> #include <linux/init.h> #include <linux/cdev.h> #include <linux/fs.h> #include <linux/io.h> #include <match/gpio-bank-k.h> #include "led.h" #define LEDCON 0x7f008800 #define LEDDAT 0x7f008808 unsigned int *led_config; unsigned int *led_data; #if 0 struct cdev cdev; dev_t devno; #endif int led_open(struct inode *node, struct file *filp) { led_config = ioremap(LEDCON,4); writel(0x11110000,led_config); led_data = ioremap(LEDDAT,4); return 0; } long led_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { switch (cmd) { case LED_ON: writel(0x00,led_data); return 0; case LED_OFF: writel(0xff,led_data); return 0; default: return -EINVAL; } } static struct file_operations led_fops = { .open = led_open, .unlocked_ioctl = led_ioctl, }; static struct miscdevice led_miscdev = { .minor =211, .name ="led", .fops =&led_fops, }; static int led_init() { misc_register(&led_miscdev); #if 0 cdev_init(&cdev,&led_fops); alloc_chrdev_region(&devno, 0 , 1 , "myled"); cdev_add(&cdev, devno, 1); #endif return 0; } static void led_exit() { misc_deregister(&led_miscdev); #if 0 cdev_del(&cdev); unregister_chrdev_region(devno,1); #endif } module_init(led_init); module_exit(led_exit);
MODULE_LICENSE("GPL");
(4)再来一个选择混杂设备驱动模型的按键驱动案例
#include <linux/module.h> #include <linux/init.h> #include <linux/cdev.h> #include <linux/fs.h> #include <linux/io.h> #if 0 struct miscdevice { int minor; const char *name; const struct file_operations *fops; struct list_head list; struct device *parent; struct device *this_device; const struct attribute_group **groups; const char *nodename; umode_t mode; }; #endif int key_open(struct inode *inode, struct file *filep) { return 0; } struct file_operations key_fops={ .open=key_fopen, }; struct miscdevice key_miscdev={ .minor = 200, .name = "key", .fops = &key_fops, }; static int key_init(void) { misc_register(&key_miscdev); } static void key_exit(void) { misc_deregister(&key_miscdev); } module_init(key_init); module_exit(key_exit);