驱动代码:
#include#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //-------------class_create,device_create------ #include /*用udev机制自动添加设备节点*/ struct class *led_class; static int led_major = 0; /* 主设备号 */ static struct cdev LedDevs; /* 应用程序执行ioctl(fd, cmd, arg)时的第2个参数 */ #define LED_MAGIC 'k' #define IOCTL_LED_ON _IOW (LED_MAGIC, 1, int) #define IOCTL_LED_OFF _IOW (LED_MAGIC, 2, int) #define IOCTL_LED_RUN _IOW (LED_MAGIC, 3, int) #define IOCTL_LED_SHINE _IOW (LED_MAGIC, 4, int) #define IOCTL_LED_ALLON _IOW (LED_MAGIC, 5, int) #define IOCTL_LED_ALLOFF _IOW (LED_MAGIC, 6, int) /* 用来指定LED所用的GPIO引脚 */ static unsigned long led_table [] = { S5PV210_MP04(4), S5PV210_MP04(5), S5PV210_MP04(6), S5PV210_MP04(7), }; #define LED_NUM ARRAY_SIZE(led_table) /* 应用程序对设备文件/dev/led执行open(...)时, * 就会调用leds_open函数 */ static int leds_open(struct inode *inode, struct file *file) { int i; for (i = 0; i < 4; i++) { // 设置GPIO引脚的功能:本驱动中LED所涉及的GPIO引脚设为输出功能 s3c_gpio_cfgpin(led_table[i], S3C_GPIO_OUTPUT); } return 0; } //LEDS all light on static void leds_all_on() { int i; for (i=0; i<4; i++) { gpio_set_value(led_table[i], 0); } } //LEDs all light off static void leds_all_off() { int i; for (i=0; i<4; i++) { gpio_set_value(led_table[i], 1); } } /* 应用程序对设备文件/dev/leds执行ioctl(...)时, * 就会调用leds_ioctl函数 */ static int leds_ioctl(struct file *file, unsigned int cmd, unsigned long arg)//没有inode,用邋unlocked_ioctl { printk("in the leds_ioctl!!\n"); // if (__get_user(data, (unsigned int __user *)arg)) //方法二:指针参数传递 // return -EFAULT; printk("arg is %d!!\n",arg); switch(cmd) { case IOCTL_LED_ON: printk("in the IOCTL_LED_ON!!\n"); // 设置指定引脚的输出电平为0 gpio_set_value(led_table[arg], 0); break; case IOCTL_LED_OFF: printk("in the IOCTL_LED_OFF!!\n"); // 设置指定引脚的输出电平为1 gpio_set_value(led_table[arg], 1); break; case IOCTL_LED_RUN: // 跑马灯 { printk("in the IOCTL_LED_RUN!!\n"); int i,j; leds_all_off(); //printk("IOCTL_LED_RUN"); for (i=0;i ) for (j=0;j<4;j++) { gpio_set_value(led_table[j], 0); mdelay(400); //delay 400ms gpio_set_value(led_table[j], 1); mdelay(400); //delay 400ms } break; } case IOCTL_LED_SHINE: // LED 闪烁 { printk("in the IOCTL_LED_SHINE!!\n"); int i,j; leds_all_off(); printk("IOCTL_LED_SHINE\n"); for (i=0;i ) { for (j=0;j<4;j++) gpio_set_value(led_table[j], 0); mdelay(400); //delay 400ms for (j=0;j<4;j++) gpio_set_value(led_table[j], 1); mdelay(400); } break ; } case IOCTL_LED_ALLON: printk("in the IOCTL_LED_ALLON!!\n"); // 设置指定引脚的输出电平为0 leds_all_on(); break; case IOCTL_LED_ALLOFF: printk("in the IOCTL_LED_ALLOFF!!\n"); // 设置指定引脚的输出电平为1 leds_all_off(); break; default: printk("in the default!!\n"); return -EINVAL; } return 0; } /* 这个结构是字符设备驱动程序的核心 * 当应用程序操作设备文件时所调用的open、read、write等函数, * 最终会调用这个结构中指定的对应函数 */ static struct file_operations leds_fops = { .owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */ .open = leds_open, .unlocked_ioctl = leds_ioctl, }; /* * Set up the cdev structure for a device. */ static void led_setup_cdev(struct cdev *dev, int minor, struct file_operations *fops) { int err, devno = MKDEV(led_major, minor); cdev_init(dev, fops); dev->owner = THIS_MODULE; dev->ops = fops; err = cdev_add (dev, devno, 1); /* Fail gracefully if need be */ if (err) printk (KERN_NOTICE "Error %d adding Led%d", err, minor); } /* * 执行“insmod leds.ko”命令时就会调用这个函数 */ static int __init leds_init(void) { int result; dev_t dev = MKDEV(led_major, 0); char dev_name[]="led"; /* 加载模式后,执行”cat /proc/devices”命令看到的设备名称 */ /*gpio_request*/ int i,ret; for (i = 0; i < LED_NUM; i++) { ret=gpio_request(led_table[i],"LED"); if(ret)//注意,是ret { printk("%s:request GPIO %d for LED failed,ret= %d\n",dev_name,led_table[i],ret); return ret; } s3c_gpio_cfgpin(led_table[i],S3C_GPIO_SFN(1));//output gpio_set_value(led_table[i],1); } /* Figure out our device number. */ if (led_major) result = register_chrdev_region(dev, 1, dev_name); else { result = alloc_chrdev_region(&dev, 0, 1, dev_name); led_major = MAJOR(dev); } if (result < 0) { printk(KERN_WARNING "leds: unable to get major %d\n", led_major); return result; } if (led_major == 0) led_major = result; /* Now set up cdev. */ led_setup_cdev(&LedDevs, 0, &leds_fops); /*udev机制可以自动添加设备节点,只需要添加xxx_class这个类,以及device_create()*/ led_class = class_create(THIS_MODULE, "led_class");/*在sys目录下创建xx_class这个类,/sys/class/~*/ device_create(led_class, NULL, LedDevs.dev, dev_name, dev_name);/*自动创建设备/dev/$DEVICE_NAME*/ printk("Led device installed, with major %d\n", led_major); printk("The device name is: %s\n", dev_name); return 0; } /* * 执行”rmmod leds”命令时就会调用这个函数 */ static void __exit leds_exit(void) { /*gpio_free*/ int i; for (i = 0; i < LED_NUM; i++) { gpio_free(led_table[i]); } /* 卸载驱动程序 */ cdev_del(&LedDevs); unregister_chrdev_region(MKDEV(led_major, 0), 1); printk("Led device uninstalled\n"); } /* 这两行指定驱动程序的初始化函数和卸载函数 */ module_init(leds_init); module_exit(leds_exit); /* 描述驱动程序的一些信息,不是必须的 */ MODULE_AUTHOR(""); // 驱动程序的作者 MODULE_DESCRIPTION("LED Driver"); // 一些描述信息 MODULE_LICENSE("Dual BSD/GPL"); // 遵循的协议
测试代码:
#include#include #include #include #define LED_MAGIC 'k' #define IOCTL_LED_ON _IOW (LED_MAGIC, 1, int) #define IOCTL_LED_OFF _IOW (LED_MAGIC, 2, int) #define IOCTL_LED_RUN _IOW (LED_MAGIC, 3, int) #define IOCTL_LED_SHINE _IOW (LED_MAGIC, 4, int) #define IOCTL_LED_ALLON _IOW (LED_MAGIC, 5, int) #define IOCTL_LED_ALLOFF _IOW (LED_MAGIC, 6, int) /* led_test on //对应四个LED全亮 led_test off // 对应四个LED全灭 led_test run // 运行跑马灯实验 led_test shine //4个LED灯全灭、全亮交替闪烁 led_test 1 on //对应LED1点亮 led_test 1 off // 对应LED1熄灭 ... led_test 4 on //对应LED4点亮 led_test 4 off // 对应LED4熄灭 */ void usage(char *exename) { printf("Usage:\n"); printf(" %s ", exename); printf(" led_no = 1, 2, 3 or 4\n"); } int main(int argc, char **argv) { unsigned int led_no; int fd = -1; unsigned int count=10; if (argc > 3 || argc == 1) goto err; fd = open("/dev/led", 0); // 打开设备 if (fd < 0) { printf("Can't open /dev/led\n"); return -1; } if (argc == 2) { if (!strcmp(argv[1], "on")) { ioctl(fd, IOCTL_LED_ALLON, count); // 点亮它 } else if (!strcmp(argv[1], "off")) { ioctl(fd, IOCTL_LED_ALLOFF, count); // 熄灭它 } else if (!strcmp(argv[1], "run")) { ioctl(fd, IOCTL_LED_RUN, count); //运行跑马灯 } else if (!strcmp(argv[1], "shine")) { ioctl(fd, IOCTL_LED_SHINE, count); //闪烁 } else { goto err; } } if (argc == 3) { led_no = atoi(argv[1]); // 操作哪个LED? if (led_no > 3) goto err; if (!strcmp(argv[2], "on")) { ioctl(fd, IOCTL_LED_ON, led_no); // 点亮 } else if (!strcmp(argv[2], "off")) { ioctl(fd, IOCTL_LED_OFF, led_no); // 熄灭 } else { goto err; } } close(fd); return 0; err: if (fd > 0) close(fd); usage(argv[0]); return -1; } \n