nuc977 新字符驱动 led

本文详细介绍了Nuc977平台上的LED驱动模块实现,包括设备注册、GPIO控制、文件操作函数和模块加载卸载流程。通过具体代码示例,展示了如何使用字符设备驱动控制LED状态。

 drv_newcharled.c

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/io.h>
#include <linux/errno.h>
#include <linux/acpi.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/clk.h>
#include <linux/interrupt.h>
#include <linux/delay.h>

#include <mach/map.h>
#include <mach/regs-gpio.h>
#include <mach/regs-clock.h>
#include <mach/regs-gcr.h>

#include <mach/irqs.h>
#include <linux/fs.h>
#include <linux/cdev.h>

#include <linux/uaccess.h> // copy_from_user



#define NEWCHRLED_CNT 1 /* 设备号个数 */
#define NEWCHRLED_NAME "newchrled" /* 名字 */
#define LEDOFF 0 /* 关灯 */
#define LEDON 1 /* 开灯 */



/* newchrled 设备结构体 */
struct newchrled_dev{
	dev_t devid; /* 设备号 */
	struct cdev cdev; /* cdev */
	struct class *class; /* 类 */

	struct device *device; /* 设备 */
	int major; /* 主设备号 */
	int minor; /* 次设备号 */
};


struct newchrled_dev newchrled; /* led 设备 */



static int nuc977_led_open(struct inode *ino, struct file *file)
{
	file->private_data = &newchrled; /* 设置私有数据 */
	return 0;
}

static int nuc977_led_release(struct inode *ino, struct file *file)
{

	return 0;
}

 /*
static long nuc977_led_ioctl(struct file *file, unsigned int command , unsigned long arg)
{
	int val;

	unsigned int cmd=*((unsigned int *)command);
	if (cmd==0)
	{
		printk(KERN_INFO "nuc977_led_ioctl cmd=0\n");
		gpio_set_value(NUC970_PB0, 0);			
	}
	else
	{
		printk(KERN_INFO "nuc977_led_ioctl cmd=1\n");
		gpio_set_value(NUC970_PB0, 1);			
	}
	
		
	return 0;
	
}
*/


static long nuc977_led_ioctl( struct file *files, unsigned int cmd, unsigned long arg)
{
	printk("cmd is %d,arg is %d \n",cmd,(unsigned int)(arg));
	switch(cmd)
	{
		case LEDOFF:
			{
				printk(KERN_INFO "LEDOFF \n");
				gpio_set_value(NUC970_PB0, 0);	
				break;		
			}
			
		case LEDON:
			{
				printk(KERN_INFO "LEDON \n");	
				gpio_set_value(NUC970_PB0, 1);
				break;		
			}

	}
	return 0;
}




/*
102 * @description : 向设备写数据
103 * @param – filp : 设备文件,表示打开的文件描述符
104 * @param - buf : 要写给设备写入的数据
105 * @param - cnt : 要写入的数据长度
106 * @param – offt : 相对于文件首地址的偏移
107 * @return : 写入的字节数,如果为负值,表示写入失败
108 */

static ssize_t nuc977_led_write(struct file *filp, const char __user *buf,size_t cnt, loff_t *offt)
{
	int retvalue;
	unsigned char databuf[1];
	unsigned char ledstat;

	retvalue = copy_from_user(databuf, buf, cnt);
	if(retvalue < 0) {
		printk("kernel write failed!\r\n");
		return -EFAULT;
	}

	ledstat = databuf[0]; /* 获取状态值 */

	if(ledstat == LEDON) {
		 gpio_set_value(NUC970_PB0, 1);/* 打开 LED 灯 */
	} else if(ledstat == LEDOFF) {
		 gpio_set_value(NUC970_PB0, 0);	/* 关闭 LED 灯 */
	}
	return 0;
}




/* 设备操作函数 */
static struct file_operations newchrled_fops = {
	.owner = THIS_MODULE,
	.open = nuc977_led_open,
	.unlocked_ioctl = nuc977_led_ioctl,
	.write = nuc977_led_write,
	.release = nuc977_led_release,
};




static int __init nuc977_led_init(void)
{
	u32 val = 0;
	u32 ret;
	
	ret = gpio_request(NUC970_PB0,"NUC970_PB0");
	if(ret < 0){
		printk(KERN_EMERG "gpio_request NUC970_PB0 failed!\n");
		return ret; 
	}
	
	gpio_direction_output(NUC970_PB0,1);



	/* 注册字符设备驱动 */
	/* 1、创建设备号 */
	if (newchrled.major) { /* 定义了设备号 */
		newchrled.devid = MKDEV(newchrled.major, 0);
		register_chrdev_region(newchrled.devid, NEWCHRLED_CNT,NEWCHRLED_NAME);
	}
	else 
	{ /* 没有定义设备号 */
		alloc_chrdev_region(&newchrled.devid, 0, NEWCHRLED_CNT,	NEWCHRLED_NAME); /* 申请设备号 */
		newchrled.major = MAJOR(newchrled.devid); /* 获取主设备号 */
		newchrled.minor = MINOR(newchrled.devid); /* 获取次设备号 */
	}
	printk("newcheled major=%d,minor=%d\r\n",newchrled.major,newchrled.minor);


	/* 2、初始化 cdev */
	newchrled.cdev.owner = THIS_MODULE;
	cdev_init(&newchrled.cdev, &newchrled_fops);

	/* 3、添加一个 cdev */
	cdev_add(&newchrled.cdev, newchrled.devid, NEWCHRLED_CNT);

	/* 4、创建类 */
	newchrled.class = class_create(THIS_MODULE, NEWCHRLED_NAME);
	if (IS_ERR(newchrled.class)) {
		return PTR_ERR(newchrled.class);
	}

	/* 5、创建设备 */
	newchrled.device = device_create(newchrled.class, NULL,
	newchrled.devid, NULL, NEWCHRLED_NAME);
	if (IS_ERR(newchrled.device)) {
		return PTR_ERR(newchrled.device);
	}	
	
	printk(KERN_INFO "nuc977_led_init module initialized\n");

	return 0;
}

static void __exit nuc977_led_exit(void)
{

	/* 注销字符设备 */
	cdev_del(&newchrled.cdev);/* 删除 cdev */
	unregister_chrdev_region(newchrled.devid, NEWCHRLED_CNT);

	device_destroy(newchrled.class, newchrled.devid);
	class_destroy(newchrled.class);
	
	//gpio_free(NUC970_PB0);
	printk(KERN_INFO "nuc977_led_exit module exited\n");
	
}

module_init(nuc977_led_init);
module_exit(nuc977_led_exit);
MODULE_LICENSE("GPL");






Makefile

obj-m := drv_newcharled.o
PWD := $(shell pwd)
KDIR ?= /home/hbin/nuc977_bsp/nuc970bsp/linux-3.10.x
all:
	$(MAKE) -C $(KDIR) M=$(PWD)
clean:
	rm -rf .*.cmd *.o *.mod.c *.ko 

 

 

app_newcharled.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include "sys/types.h"
#include "sys/stat.h"
#include "fcntl.h"
#include "string.h"

#define LEDON    1
#define LEDOFF   0

int main(int argc, char *argv[])
{   
int fd ,retvalue;
char *filename;
unsigned char databuf[1];
if (argc != 3){
printf("Error Usage!");
return -1;
}
filename=argv[1];
fd = open(filename, O_RDWR);  // 打开设备
if (fd < 0) {
    printf("Can't open  %s \n",argv[1]);
    return -1;
}
databuf[0] = atoi(argv[2]); /* 要执行的操作:打开或关闭 */
/* 向/dev/led 文件写入数据 */
retvalue = write(fd, databuf, sizeof(databuf));
if(retvalue < 0){
printf("LED Control Failed!\r\n");
close(fd);
return -1;
}
retvalue = close(fd); /* 关闭文件 */
if(retvalue < 0){
printf("file %s close failed!\r\n", argv[1]);
return -1;
}
return 0;
}




arm-linux-gcc app_newcharled.c -o app_newcharled

 

secureCRT

~ # ifconfig eth0 192.168.0.4 up
nuc970-emac0 nuc970-emac0: eth0 is OPENED
~ # mount -t nfs -o nolock 192.168.0.199:/home/hbin/nfs /mnt

~ # cd /mnt
/mnt # ls
app        driver     rootfs_hb
/mnt # cd driver/
/mnt/driver # ls
drv_hello       drv_led         drv_led2        drv_newcharled
/mnt/driver # cd drv_newcharled/
/mnt/driver/drv_newcharled # ls
Makefile              drv_newcharled.c      drv_newcharled.mod.o
Module.symvers        drv_newcharled.ko     drv_newcharled.o
built-in.o            drv_newcharled.mod.c  modules.order
/mnt/driver/drv_newcharled # cp drv_newcharled.ko /lib/modules/
/mnt/driver/drv_newcharled # insmod /lib/modules/drv_newcharled.ko 
newcheled major=252,minor=0
nuc977_led_init module initialized

 

/mnt/app # ls
app_led           app_led2          app_newcharled    helloworld
app_led.c         app_led2.c        app_newcharled.c  helloworld.c
/mnt/app # ./app_newcharled /dev/newchrled 1
/mnt/app # ./app_newcharled /dev/newchrled 0
/mnt/app # ./app_newcharled /dev/newchrled 1
/mnt/app # ./app_newcharled /dev/newchrled 0
/mnt/app # rmmod /lib/modules/drv_newcharled.ko 

 

 

 

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

oshan2012

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值