实例中使用gpio0_12  可以将GPIO配置放到init中,只需要wirte、ioctl函数就可以了;

测试中碰到两个问题:

1、class节点在/sys/class/下找不到的问题,修改了fstab和rcS,增加mount sysfs。

 

2、printk打印信息的优先级问题。

#define KERN_EMERG "<0>" /* system is unusable */
#define KERN_ALERT "<1>" /* action must be taken immediately */
#define KERN_CRIT "<2>" /* critical conditions */
#define KERN_ERR "<3>" /* error conditions */
#define KERN_WARNING "<4>" /* warning conditions */
#define KERN_NOTICE "<5>" /* normal but significant condition */
#define KERN_INFO "<6>" /* informational */
#define KERN_DEBUG "<7>" /* debug-level messages */

 

源码如下:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/gpio.h>
#include <linux/moduleparam.h>
#include <linux/miscdevice.h>
#include <linux/device.h>
#include <asm/uaccess.h>

#define DEVICE_MEM_SIZE 2
#define AM335X_LEDS_GPIO 12

#define DEVICE_NAME "am335x_leds"//设备名称
#define DEVICE_COUNT 1//设备数量
static int am335x_leds_major = 0;//主设备号
static int am335x_leds_minor = 0;//次设备号

static dev_t dev_number;
static struct class *am335x_leds_class = NULL;
static unsigned char mem[DEVICE_MEM_SIZE];

struct cdev am335x_leds_cdev;


static long am335x_leds_ioctl(struct file *filp,unsigned int cmd,unsigned long arg)
{
switch(cmd)
{
case 0:
gpio_set_value(AM335X_LEDS_GPIO,0);
break;
case 1:
gpio_set_value(AM335X_LEDS_GPIO,1);
break;
default:
return -EINVAL;
}
return 0;
}

static int am335x_leds_open(struct inode *inodep, struct file * filep) // 打开设备
{
int ret = -1;

printk("%s,%d\n", __func__, __LINE__);

ret = gpio_request(AM335X_LEDS_GPIO,"GPIO0_12");

if(ret<0)
{
printk("gpio0_12 request failed\n");
}

ret = -1;
ret = gpio_direction_output(AM335X_LEDS_GPIO,1);

if(ret<0)
{
printk("gpio0_12 set output failed\n");
}

return ret;
}
static int am335x_leds_release(struct inode * inodep, struct file * filep) // 关闭设备
{
printk("%s,%d\n", __func__, __LINE__);

// gpio_free(AM335X_LEDS_GPIO);

return 1;
}
static ssize_t am335x_leds_read(struct file *filp,char __user *buf, size_t size, loff_t *ppos)
{
int ret = -1;
//读取数据到用户空间

if(copy_to_user(buf,mem,size))
{
ret= -EFAULT;
printk("copyfrom user failed\n");
}
else{
ret= size;
printk("read%d bytes from dev\n", size);
}
return ret;
}

static ssize_t am335x_leds_write(struct file *filp,const char __user *buf, size_t size, loff_t *ppos)//注意:第二个参数和read方法不同
{
int ret = -1;
unsigned tmp = size;
char mem[DEVICE_MEM_SIZE];


memset(mem,0,DEVICE_MEM_SIZE);

if(size > DEVICE_MEM_SIZE)
{
tmp = DEVICE_MEM_SIZE;
}
if(copy_from_user(mem,buf,size))
{
ret= -EFAULT;
printk("copyfrom user failed\n");

}
else{
ret= size;
if(mem[0] == '1')
{
gpio_set_value(AM335X_LEDS_GPIO,1);
}
else
{
gpio_set_value(AM335X_LEDS_GPIO,0);
}
printk("write%d bytes to dev\n", size);
}
return ret;
}

struct file_operations am335x_leds_fops =
{
.owner = THIS_MODULE,
.unlocked_ioctl = am335x_leds_ioctl,
.open = am335x_leds_open,
.release = am335x_leds_release,
.read = am335x_leds_read,
.write = am335x_leds_write,
};

static int __init am335x_leds_init(void)
{
int ret = 0;
struct device *am335x_leds_device = NULL;

printk(KERN_ALERT "%s,%d\n", __func__, __LINE__);

//cdev_init()函数用于初始化 cdev 的成员,并建立 cdev 和 file_operations 之间的连接
cdev_init(&am335x_leds_cdev, &am335x_leds_fops);
am335x_leds_cdev.owner = THIS_MODULE;

/**在调用 cdev_add()函数向系统注册字符设备之前,
*应首先调用 register_chrdev_region()或alloc_chrdev_region()函数向系统申请设备号
**/
if (am335x_leds_major)//静态申请
{
//使用下列宏则可以通过主设备号和次设备号生成 dev_t
dev_number = MKDEV(am335x_leds_major, am335x_leds_minor);
ret = register_chrdev_region(dev_number, DEVICE_COUNT, DEVICE_NAME);
printk(KERN_ALERT "Sucees register_chrdev_region.\n");
}
else //动态分配
{
ret = alloc_chrdev_region(&am335x_leds_cdev.dev, 0, DEVICE_COUNT, DEVICE_NAME);
am335x_leds_major = MAJOR(am335x_leds_cdev.dev);
am335x_leds_minor = MINOR(am335x_leds_cdev.dev);
// dev_number = MKDEV(am335x_leds_major, am335x_leds_minor);
dev_number = am335x_leds_cdev.dev;
printk(KERN_ALERT "Sucees alloc_chrdev_region. The Major is %d,The minor is %d\n",am335x_leds_major,am335x_leds_minor);
}
if(ret)
{
printk(KERN_ALERT "Failed to register_chrdev_region.\n");
return ret;
}

//系统添加一个 cdev,完成字符设备的注册。
ret = cdev_add(&am335x_leds_cdev, dev_number, DEVICE_COUNT);
if(ret)
{
printk(KERN_ALERT " Failed to cdev_add [Error] %d adding am335x_leds%d", ret, DEVICE_COUNT);
unregister_chrdev_region(dev_number, 1);
return ret;
}
//am335x_leds_class = class_create(THIS_MODULE,DEVICE_NAME);
am335x_leds_class = class_create(THIS_MODULE,"am335x_leds");

if(IS_ERR(am335x_leds_class))
{
printk(KERN_ALERT "failed in creating class.\n");
return -1;
}
else
{
printk(KERN_ALERT "Sucees in creating class.\n");
}
am335x_leds_device = device_create(am335x_leds_class,NULL,dev_number,NULL,"am335x_leds");

if(IS_ERR(am335x_leds_device))
{
device_destroy(am335x_leds_class,dev_number);
if(am335x_leds_class)
class_destroy(am335x_leds_class);
printk(KERN_ALERT "failed in creating device.\n");
return -1;
}
else
{
printk(KERN_ALERT "Sucees in creating device.\n");
}

return 0;
}

static void __exit am335x_leds_exit(void)
{
printk("%s,%d\n", __func__, __LINE__);

gpio_free(AM335X_LEDS_GPIO);
device_destroy(am335x_leds_class,dev_number);
if(am335x_leds_class)
class_destroy(am335x_leds_class);
//删除一个 cdev,完成字符设备的注销。
cdev_del(&am335x_leds_cdev);
//在调用cdev_del()函数从系统注销字符设备之后,unregister_chrdev_region()应该被调用以释放原先申请的设备号
unregister_chrdev_region(dev_number, DEVICE_COUNT);
}

module_init(am335x_leds_init);
module_exit(am335x_leds_exit);

MODULE_AUTHOR(" lazybeee");
MODULE_LICENSE("GPL");

 

Makefile:

# Kernel modules


obj-m += am335x_leds.o
KDIR := /mnt/wangyg/TI_Android_JB_4.2.2_DevKit_4.1.1/kernel

ARCH = arm
CROSS_COMPILE=arm-none-linux-gnueabi-
CC = $(CROSS_COMPILE)gcc

PWD = $(shell pwd)
all:
make -C $(KDIR) M=$(PWD) ARCH=arm CROSS_COMPILE=$(CROSS_COMPILE) modules
clean:
rm *.o *.ko *.mod.c .*.cmd *.order *.symvers

 

测试程序:

#include <stdio.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <linux/input.h>
#include <fcntl.h>

int main(int argc, char **argv)
{
int fd;
int cmd,arg;

if(argc<4)
{
printf("Usage ioctl <dev_file> <cmd> <arg>\n");
}
cmd = atoi(argv[2]);
arg = atoi(argv[3]);

printf("dev:%s\n",argv[1]);
printf("cmd:%d\n",cmd);
printf("arg:%d\n",arg);


fd = open(argv[1], O_RDWR);
if(fd < 0)
{
printf("***Can't open the am335x_leds!\r\n");
return -1;
}
ioctl(fd, cmd, arg);
close(fd);
printf("***App run over!\r\n");

return 1;
}

 

posted on 2019-02-21 15:19  懒床小蜜蜂  阅读(377)  评论(0编辑  收藏  举报