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

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

被折叠的 条评论
为什么被折叠?



