驱动代码:

#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/init.h>
#include <linux/serio.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/miscdevice.h>
#include <linux/gpio.h> #include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
#include <mach/regs-clock.h>
#include <plat/regs-timer.h> #include <mach/regs-gpio.h>
#include <linux/cdev.h>
//-------------class_create,device_create------
#include <linux/device.h> /*用udev机制自动添加设备节点*/
struct class *led_class; static int led_major = ; /* 主设备号 */
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(),
S5PV210_MP04(),
S5PV210_MP04(),
S5PV210_MP04(), };
#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 = ; i < ; i++) {
// 设置GPIO引脚的功能:本驱动中LED所涉及的GPIO引脚设为输出功能
s3c_gpio_cfgpin(led_table[i], S3C_GPIO_OUTPUT);
}
return ;
} //LEDS all light on
static void leds_all_on()
{
int i;
for (i=; i<; i++) {
gpio_set_value(led_table[i], );
}
} //LEDs all light off
static void leds_all_off()
{
int i;
for (i=; i<; i++) {
gpio_set_value(led_table[i], );
}
} /* 应用程序对设备文件/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], );
break; case IOCTL_LED_OFF:
printk("in the IOCTL_LED_OFF!!\n");
// 设置指定引脚的输出电平为1
gpio_set_value(led_table[arg], );
break; case IOCTL_LED_RUN:
// 跑马灯
{
printk("in the IOCTL_LED_RUN!!\n");
int i,j;
leds_all_off();
//printk("IOCTL_LED_RUN");
for (i=;i<arg;i++)
for (j=;j<;j++) {
gpio_set_value(led_table[j], );
mdelay(); //delay 400ms
gpio_set_value(led_table[j], );
mdelay(); //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=;i<arg;i++) {
for (j=;j<;j++)
gpio_set_value(led_table[j], );
mdelay(); //delay 400ms
for (j=;j<;j++)
gpio_set_value(led_table[j], );
mdelay();
}
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 ;
} /* 这个结构是字符设备驱动程序的核心
* 当应用程序操作设备文件时所调用的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, );
/* 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, );
char dev_name[]="led"; /* 加载模式后,执行”cat /proc/devices”命令看到的设备名称 */ /*gpio_request*/
int i,ret;
for (i = ; 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());//output
gpio_set_value(led_table[i],);
} /* Figure out our device number. */
if (led_major)
result = register_chrdev_region(dev, , dev_name);
else {
result = alloc_chrdev_region(&dev, , , dev_name);
led_major = MAJOR(dev);
}
if (result < ) {
printk(KERN_WARNING "leds: unable to get major %d\n", led_major);
return result;
}
if (led_major == )
led_major = result; /* Now set up cdev. */
led_setup_cdev(&LedDevs, , &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 ; } /*
* 执行”rmmod leds”命令时就会调用这个函数
*/
static void __exit leds_exit(void)
{
/*gpio_free*/
int i;
for (i = ; i < LED_NUM; i++)
{ gpio_free(led_table[i]);
} /* 卸载驱动程序 */
cdev_del(&LedDevs);
unregister_chrdev_region(MKDEV(led_major, ), );
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 <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h> #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 <led_no> <on/off>\n", exename);
printf(" led_no = 1, 2, 3 or 4\n");
} int main(int argc, char **argv)
{
unsigned int led_no;
int fd = -;
unsigned int count=; if (argc > || argc == )
goto err; fd = open("/dev/led", ); // 打开设备
if (fd < ) {
printf("Can't open /dev/led\n");
return -;
} if (argc == ) {
if (!strcmp(argv[], "on")) {
ioctl(fd, IOCTL_LED_ALLON, count); // 点亮它
} else if (!strcmp(argv[], "off")) {
ioctl(fd, IOCTL_LED_ALLOFF, count); // 熄灭它
} else if (!strcmp(argv[], "run")) {
ioctl(fd, IOCTL_LED_RUN, count); //运行跑马灯
} else if (!strcmp(argv[], "shine")) {
ioctl(fd, IOCTL_LED_SHINE, count); //闪烁
} else {
goto err;
}
} if (argc == ) {
led_no = atoi(argv[]); // 操作哪个LED?
if (led_no > )
goto err;
if (!strcmp(argv[], "on")) {
ioctl(fd, IOCTL_LED_ON, led_no); // 点亮
} else if (!strcmp(argv[], "off")) {
ioctl(fd, IOCTL_LED_OFF, led_no); // 熄灭
} else {
goto err;
}
} close(fd);
return ; err:
if (fd > )
close(fd);
usage(argv[]);
return -; }

Linux下实现流水灯等功能的LED驱动代码及测试实例的更多相关文章

  1. Linux下简易蜂鸣器驱动代码及测试实例

    驱动代码: #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> ...

  2. 《Linux下cp XXX1 XXX2的功能》的实现

    <Linux下cp XXX1 XXX2的功能>的实现 一.题目要求 编写MyCP.java 实现类似Linux下cp XXX1 XXX2的功能,要求MyCP支持两个参数: java MyC ...

  3. 编写MyCP.java 实现类似Linux下cp XXX1 XXX2的功能

    题目:编写MyCP.java 实现类似Linux下cp XXX1 XXX2的功能 要求:MyCP支持两个参数: java MyCP -tx XXX1.txt XXX2.bin 用来把文本文件(内容为十 ...

  4. 20175303 Mycp实现Linux下cp xxx1 xxx2的功能

    20175303 Mycp实现Linux下cp xxx1 xxx2的功能 一.题目要求 编写MyCP2.java 实现类似Linux下cp XXX1 XXX2的功能,要求MyCP2支持两个参数: ja ...

  5. 学号20175313 《实现Linux下cp XXX1 XXX2的功能(二)》第九周

    目录 MyCP2 一.题目要求 二.题目理解 三.需求分析 四.设计思路 五.伪代码分析 六.代码链接 七.代码实现过程中遇到的问题 八.运行结果截图 九.心得体会 十.参考资料 MyCP2 一.题目 ...

  6. 学号20175313 《实现Linux下cp XXX1 XXX2的功能(一)》第九周

    目录 MyCP 一.题目要求 二.题目理解 三.需求分析 四.设计思路 五.伪代码分析 六.代码链接 七.代码实现过程中遇到的问题 八.运行结果截图 九.参考资料 MyCP 一.题目要求 编写MyCP ...

  7. 补交 20155202 蓝墨云班课 编写MyCP.java 实现类似Linux下cp XXX1 XXX2的功能

    蓝墨云班课 编写MyCP.java 要求: 编写MyCP.java 实现类似Linux下cp XXX1 XXX2的功能,要求MyCP支持两个参数: java MyCP -tx XXX1.txt XXX ...

  8. linux下的CPU、内存、IO、网络的压力测试

    linux下的CPU.内存.IO.网络的压力测试  要远程测试其实很简单了,把结果放到一个微服务里直接在web里查看就可以了,或者同步到其他服务器上 一.对CPU进行简单测试: 1.通过bc命令计算特 ...

  9. [转帖]linux下的CPU、内存、IO、网络的压力测试

    linux下的CPU.内存.IO.网络的压力测试 https://www.cnblogs.com/zhuochong/p/10185881.html 一.对CPU进行简单测试: 1.通过bc命令计算特 ...

随机推荐

  1. Struts2中的类型转换

    1.     Struts2中的类型转换 我们知道通过HTTP提交到后台的数据,都是字符串的形式,而我们需要的数据类型当然不只字符串类型一种.所以,我们需要类型转换! 在Struts2中,类型转换的概 ...

  2. iOS 如何进行逆向工程

    原文:http://www.zhihu.com/question/20317296 季逸超,Peak-Labs创始人/CEO,猛犸浏览器.Rasgue- 有幸被邀请回答,不过不知道您要了解的'系统机制 ...

  3. Component migration documentation

    Component migration documentation The following is a list of migration documents for components we s ...

  4. h5拖放-基础知识

    <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...

  5. 设定范围和步长的递增数验证器Validator

    1.接口注释 @Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER}) @Retention(RUNTIME) @Docume ...

  6. famous javascript library.

    https://famo.us/ THE ULTIMATE WEB PLATFORM FOR DEVELOPERS AND DESIGNERS

  7. Linux上安装Squall

    Squall是Storm之上的类SQL查询工具,能够将类SQL语句转换成topology,然后提交给Storm运行. 安装Squall前要先安装Java和sbt(simple build tool), ...

  8. [ImportNew]Java中的并发处理

    本文来源:http://www.importnew.com/14506.html 这篇文章讨论了Java应用中并行处理的多种方法.从自己管理Java线程,到各种更好几的解决方法,Executor服务. ...

  9. MSP430矩阵及独立键盘

    在学习MSP430的时候,总是有很多东西记不住,同时又是英文的资料,好多东西也是没怎么看透,英文虽过六级但是看英文资料还是有一种想睡的冲动啊,在学习键盘的时候,我的这块板子有些不同,矩阵键盘和独立键盘 ...

  10. 【Android自动化打包】03. APK的数字签名

    1. 什么是数字签名?   数字签名就是为你的程序打上一种标记,来作为你自己的标识,当别人看到签名的时候会知道它是与你相关的   2. 为什么要数字签名?    最简单直接的回答: 系统要求的.   ...