驱动代码:

#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. 【Android动画】之Tween动画 (渐变、缩放、位移、旋转)

    Android 平台提供了两类动画. 一类是Tween动画,就是对场景里的对象不断的进行图像变化来产生动画效果(旋转.平移.放缩和渐变). 第二类就是 Frame动画,即顺序的播放事先做好的图像,与g ...

  2. careercup-C和C++ 13.5

    13.5 谈谈C语言关键字”volatile”的意义(或重要性)? 解答 关键字volatile的作用是指示编译器,即使代码不对变量做任何改动,该变量的值仍可能被外界修改.操作系统.硬件或其他线程都可 ...

  3. java_利用session校验图片认证码

    RegisterServlet:检验server,client验证码是否一致 ImageServlet: 产生验证码 <!DOCTYPE html> <html> <he ...

  4. C#_delegate - 调用列表 计算阶乘

    using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Dele ...

  5. (转载)c语言指针学习

    前言 近期俄罗斯的陨石.四月的血月.五月北京的飞雪以及天朝各种血腥和混乱,给人一种不详的预感.佛祖说的末法时期,五浊恶世 ,十恶之世,人再无心法约束,道德沦丧,和现在正好吻合.尤其是在天朝,空气,水, ...

  6. Android 断点续传

    断点续传指的是在下载或上传时,将下载或上传任务(一个文件或一个压缩包)人为的划分为几个部分,每一个部分采用一个线程进行上传或下载,如果碰到网络故障,可以从已经上传或下载的部分开始继续上传下载未完成的部 ...

  7. String 、InputStream、Reader 的转换

    1.String –> InputStream InputStrem is = new ByteArrayInputStream(str.getBytes());orByteArrayInput ...

  8. 关于国际化中的$NON-NLS-1$

    百度百科解释: 这实际与eclipse中支持i18n的一种方式,eclipse的标准结构,将所有string常量定义到·properties中,例如下面程序段中的TestRef.hello实际上是·p ...

  9. Servlet原理

    Servlet主要用来处理客户端请求并将其结果发送到客户端,下面我们来详细看一下Servlet. 一.Servlet的生命周期 Servlet的生命周期是由Servlet的容器来控制的(Tomcat ...

  10. selendroid项目实战3 selendroid driver初始化失败问题

    小米4/LG手机作为测试用机,随着测试时间变长,driver初始化失败率越来越高. 分析: 1.手机原因: 从小米换到LG,刚开始问题确实减少了,但是时间一长,又出现类似问题,提示Connect re ...