LED字符设备驱动实例及测试代码
驱动代码如下:
#include <linux/kernel.h>//内核头文件 #include <linux/init.h>//__init等 #include <linux/module.h>//模块加载的头文件 #include <linux/fs.h>//file_operations #include <linux/errno.h>//错误状态常数 #include <linux/types.h>//size_t,ssize_t等 //--------------cdev---------------- #include <linux/cdev.h> //-------------class_create,device_create------ #include <linux/device.h> //--------------GPIO----------------- #include <mach/gpio.h> #include <plat/gpio-cfg.h> #include <mach/regs-gpio.h> //-------CMD COMMAND---------------- #define LED1_ON 0x1 #define LED1_OFF 0x0 #define DEVICE_NAME "LED1" static int led1_gpios[]= { S5PV210_MP04(4), S5PV210_MP04(5), S5PV210_MP04(6), S5PV210_MP04(7) }; #define LED1_NUM ARRAY_SIZE(led1_gpios) /*用udev机制自动添加设备节点*/ struct class *led1_class; /*设备结构体*/ struct led1_dev_t { struct cdev cdev; }led1_dev; /* // ------------------- READ ------------------------ ssize_t led1_read (struct file * file ,char * buf, size_t count, loff_t * f_ops) { return count; } // ------------------- WRITE ----------------------- ssize_t led1_write (struct file * file ,const char * buf, size_t count, loff_t * f_ops) { return count; } // ------------------- OPEN ------------------------ ssize_t led1_open (struct inode * inode ,struct file * file) { return 0; } // ------------------- RELEASE/CLOSE --------------- ssize_t led1_release (struct inode * inode ,struct file * file) { return 0; } // ------------------------------------------------- */ // ------------------- IOCTL ----------------------- static int led1_ioctl (struct inode * inode ,struct file * file, unsigned int cmd, unsigned long arg) { if(arg > LED1_NUM) { printk("arg is %u ,led num is %d\n",arg,LED1_NUM); printk("num is err!!\n"); return - EINVAL; } switch (cmd) { case LED1_ON: { /*code*/ gpio_set_value(led1_gpios[arg],0); printk("led1 is on!!\n"); break; } case LED1_OFF: { /*code*/ gpio_set_value(led1_gpios[arg],1); printk("led1 is off!!\n"); break; } default : { printk ("CMD err!!\n"); return - EINVAL; } } return 0; } struct file_operations led1_fops ={ .owner = THIS_MODULE, // .open = led1_open, // .read = led1_read, // .write = led1_write, .ioctl = led1_ioctl, // .release = led1_release, }; // ------------------- INIT ------------------------ static int __init led1_init(void) { printk("led num is : %d\n",LED1_NUM); int i,ret; for (i = 0; i < LED1_NUM; i++) { /* ret=gpio_request(led1_gpios[i],"LED1"); if(ret)//注意,是ret { printk("%s:request GPIO %d for LED1 failed,ret= %d\n",DEVICE_NAME,led1_gpios[i],ret); return ret; } */ s3c_gpio_cfgpin(led1_gpios[i],S3C_GPIO_SFN(1)); gpio_set_value(led1_gpios[i],1); } /*init cdev*/ cdev_init(&led1_dev.cdev,&led1_fops); led1_dev.cdev.owner=THIS_MODULE; /*向系统动态申请未被占用的设备号*/ ret = alloc_chrdev_region(&led1_dev.cdev.dev,0,1,DEVICE_NAME);//int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,const char *name) if (ret) { printk("register failed\n"); return ret; } /*添加字符设备*/ ret = cdev_add(&led1_dev.cdev, led1_dev.cdev.dev, 1); if (ret) { printk("cdev add failed\n"); goto fail1; } /*udev机制可以自动添加设备节点,只需要添加xxx_class这个类,以及device_create()*/ led1_class = class_create(THIS_MODULE, "led1_class");/*在sys目录下创建xx_class这个类,/sys/class/~*/ if (IS_ERR(led1_class)) { printk("class create failed\n"); goto fail2; } device_create(led1_class, NULL, led1_dev.cdev.dev, DEVICE_NAME, DEVICE_NAME);/*自动创建设备/dev/$DEVICE_NAME*/ return ret; fail2: cdev_del(&led1_dev.cdev); fail1: unregister_chrdev_region(led1_dev.cdev.dev, 1); return ret; } static void __exit led1_exit(void) { int i; /* for (i = 0; i < LED1_NUM; i++) { gpio_free(led1_gpios[i]); } */ device_destroy(led1_class, led1_dev.cdev.dev); class_destroy(led1_class); cdev_del(&led1_dev.cdev); unregister_chrdev_region(led1_dev.cdev.dev, 1); } module_init(led1_init); module_exit(led1_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("mhb@seu");
测试代码如下:
#include <stdio.h> //#include "sys/types.h" #include <sys/ioctl.h> #include <stdlib.h> #include <unistd.h> //#include "termios.h" //#include "sys/stat.h" #include <fcntl.h> #define LED1_ON 0x1 #define LED1_OFF 0x0 main(int argc,char *argv[]) { int fd; if ((fd=open("/dev/LED1",O_RDWR /*| O_NDELAY | O_NOCTTY*/)) < 0) { printf("Open Device failed.\r\n"); exit(1); } else { printf("Open Device successed.\r\n"); } if (argc<3) { /* code */ printf("Usage: %s <on|off num>\n",argv[0]); exit(2); } if(!strcmp(argv[1],"on")) { printf("led1 will on!!\n"); printf("argv[2]=%d\n",atoi(argv[2])); if(ioctl(fd,LED1_ON,atoi(argv[2]))<0) { printf("ioctl err!!\n"); } } if(!strcmp(argv[1],"off")) { printf("led1 will off!!\n"); if(ioctl(fd,LED1_OFF,atoi(argv[2]))<0) { printf("ioctl err!!\n"); } } close(fd); }