一.驱动框架
初始化:insmod 加载
1.确定主设备号:
分为静态和动态分配,其中LED_GPIO_SIZE 表示支持的次设备号数目,一般默认为1. 相关实现代码如下:
int result; dev_t dev; /*分配主设备号*/ if (scull_major) /*静态分配一个主设备号*/ { dev = MKDEV(scull_major,0); result = register_chrdev_region(dev,LED_GPIO_SIZE,DEVICE_NAME); } else /*动态分配一个主设备号*/ { result = alloc_chrdev_region(&dev,0,LED_GPIO_SIZE,DEVICE_NAME); scull_major = MAJOR(dev); } if(result <0) { printk("LED:can not get major:%d\n",scull_major); return result; }
static struct file_operations mini2440_leds_fops = { .owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */ .open = mini2440_leds_open, .write = mini2440_leds_write, };
内核用cdev结构来表示字符设备,cev_init()将文件操作和cdev关联。cdev_add()将之前生成的主次设备号和cdev连接在一起,
led_class = class_create(THIS_MODULE,DEVICE_NAME); cdev_init(&led_gpio_cdev, &mini2440_leds_fops); result = cdev_add(&led_gpio_cdev, dev, 1); if(result <0) { printk("LED:cdev_add error\n"); return result; } device_create(led_class, NULL, MKDEV(scull_major, 0), NULL, "led0");
dev_t dev_id = MKDEV(scull_major, 0); /*卸载主设备号*/ unregister_chrdev_region(dev_id, LED_GPIO_SIZE); device_destroy(led_class,MKDEV(scull_major, 0)); cdev_del(&led_gpio_cdev); class_destroy(led_class);
最后附上一个较为完整的驱动框架,其中创建了主设备号和次设备号,驱动代码如下:
#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 <mach/io.h> #include <mach/regs-gpio.h> #include <mach/hardware.h> #include <linux/device.h> #include <linux/cdev.h> #define DEVICE_NAME "led_1" #define LED_GPIO_SIZE 4 static int scull_major = 0; static struct class *led_class; static struct cdev led_gpio_cdev[LED_GPIO_SIZE]; static int mini2440_leds_open(struct inode *inode, struct file *file) { int minor = MINOR(inode->i_rdev); //MINOR(inode->i_cdev); printk("/dev/led%d has opened\n",minor); return 0; } static ssize_t mini2440_leds_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos) { char val; int minor = MINOR(filp->f_dentry->d_inode->i_rdev); copy_from_user(&val, buf, 1); printk("/dev/led%d write the val = %d\n",minor,val); return 0; } static struct file_operations mini2440_leds_fops = { .owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */ .open = mini2440_leds_open, .write = mini2440_leds_write, }; /* * 执行insmod命令时就会调用这个函数 */ static int mini2440_leds_init(void) { int result,i; dev_t dev; /*分配主设备号*/ if (scull_major) /*静态分配一个主设备号*/ { dev = MKDEV(scull_major,0); result = register_chrdev_region(dev,LED_GPIO_SIZE,DEVICE_NAME); } else /*动态分配一个主设备号*/ { result = alloc_chrdev_region(&dev,0,LED_GPIO_SIZE,DEVICE_NAME); scull_major = MAJOR(dev); } if(result <0) { printk("LED:can not get major:%d\n",scull_major); return result; } led_class = class_create(THIS_MODULE,DEVICE_NAME); if (IS_ERR(led_class)) { return PTR_ERR(led_class); } for (i=0; i<LED_GPIO_SIZE;i++) { cdev_init(&led_gpio_cdev[i], &mini2440_leds_fops); result = cdev_add(&led_gpio_cdev[i], (dev+i), 1); if(result <0) { printk("LED:cdev_add error\n"); return result; } device_create(led_class, NULL, MKDEV(scull_major, i), NULL, "led%d",i); } return 0; } /* * 执行rmmod命令时就会调用这个函数 */ static void mini2440_leds_exit(void) { int i; dev_t dev_id = MKDEV(scull_major, 0); /*卸载主设备号*/ unregister_chrdev_region(dev_id, LED_GPIO_SIZE); for(i=0;i<LED_GPIO_SIZE;i++) { device_destroy(led_class,MKDEV(scull_major, i)); cdev_del(&led_gpio_cdev[i]); } class_destroy(led_class); } /* 这两行指定驱动程序的初始化函数和卸载函数 */ module_init(mini2440_leds_init); module_exit(mini2440_leds_exit); /* 描述驱动程序的一些信息,不是必须的 */ MODULE_LICENSE("GPL");
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> /* * ledtest <dev> <on|off> */ void print_usage(char *file) { printf("Usage:\n"); printf("%s <dev> <on|off>\n",file); printf("eg. \n"); printf("%s /dev/led0 a\n", file); printf("%s /dev/led1 b\n", file); printf("%s /dev/led2 c\n", file); printf("%s /dev/led3 d\n", file); } int main(int argc, char **argv) { int fd; char* filename; char val; if (argc != 3) { print_usage(argv[0]); return 0; } filename = argv[1]; fd = open(filename, O_RDWR); if (fd < 0) { printf("error, can't open %s\n", filename); return 0; } if (!strcmp("a", argv[2])) { val = 10; write(fd, &val, 1); } else if (!strcmp("b", argv[2])) { val = 11; write(fd, &val, 1); } else if (!strcmp("c", argv[2])) { val = 12; write(fd, &val, 1); } else if (!strcmp("d", argv[2])) { val = 13; write(fd, &val, 1); } return 0; }