一、设备驱动程序
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#define DeviceName "devicetree-timer-ioctl"
#define DeviceNodes 1
#define CLOSE_CMD _IO(0XEF, 1)
#define OPEN_CMD _IO(0XEF, 2)
#define SETPERIOD_CMD _IOW(0xEF, 3, int)
struct mod_struct {
dev_t devid;
struct cdev cdev;
struct class *class;
struct device *device;
int major;
int minor;
struct device_node *nd;
int gpio;
struct timer_list timer;
int timeperiod;
};
struct mod_struct mod_device;
static int kernel_timer_open(struct inode *inode, struct file *filp)
{
filp->private_data = &mod_device;
return 0;
}
static ssize_t kernel_timer_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{
return 0;
}
static ssize_t kernel_timer_write(struct file *filp, const char __user *buf,size_t cnt, loff_t *offt)
{
return 0;
}
static int kernel_timer_release(struct inode *inode, struct file *filp)
{
return 0;
}
static long kernel_timer_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
int ret = 0;
int value = 0;
struct mod_struct *dev = file->private_data;
switch (cmd) {
case CLOSE_CMD:
del_timer_sync(&dev->timer);
break;
case OPEN_CMD:
mod_timer(&dev->timer, jiffies + msecs_to_jiffies(dev->timeperiod));
break;
case SETPERIOD_CMD:
ret = copy_from_user(&value, (int *)arg, sizeof(int));
if(ret < 0) {
return -EFAULT;
}
dev->timeperiod = value;
mod_timer(&dev->timer, jiffies + msecs_to_jiffies(dev->timeperiod));
break;
}
return ret;
}
static struct file_operations beep_fops = {
.owner = THIS_MODULE,
.open = kernel_timer_open,
.read = kernel_timer_read,
.write = kernel_timer_write,
.release = kernel_timer_release,
.unlocked_ioctl = kernel_timer_ioctl,
};
static void timer_func(unsigned long arg)
{
struct mod_struct *dev = (struct mod_struct*)arg;
static int sta = 1;
sta = !sta;
gpio_set_value(dev->gpio, sta);
mod_timer(&dev->timer, jiffies + msecs_to_jiffies(dev->timeperiod));
}
int led_init(struct mod_struct *dev)
{
int ret = 0;
dev->nd = of_find_node_by_path("/devicetree-leds-pincrl");
if(dev->nd == NULL) {
printk("devicetree-leds-pincrl node not find!\r\n");
ret = -EINVAL;
goto fail_fd;
} else {
printk("devicetree-leds-pincrl node find!\r\n");
}
dev->gpio = of_get_named_gpio(dev->nd, "leds-gpio", 0);
if(dev->gpio < 0) {
printk("can't get leds-gpio\r\n");
ret = -EINVAL;
goto fail_gpio;
}
printk("led-gpio num = %d\r\n", dev->gpio);
ret = gpio_request(dev->gpio,"led2-gpio");
if(ret)
{
ret = -EBUSY;
printk("IO %d busy,can't request!\r\n",dev->gpio);
goto fail_ioreq;
}
ret = gpio_direction_output(dev->gpio,1);
if(ret < 0) {
printk("can't set gpio!\r\n");
goto fail_ioset;
}
return 0;
fail_ioset:
gpio_free(dev->gpio);
fail_ioreq:
fail_gpio:
fail_fd:
return ret;
}
static int __init kernel_timer_init(void)
{
int ret = 0;
if (mod_device.major)
{
mod_device.devid = MKDEV(mod_device.major,0);
ret = register_chrdev_region(mod_device.devid,DeviceNodes,DeviceName);
}
else {
ret = alloc_chrdev_region(&mod_device.devid,0,DeviceNodes,DeviceName);
mod_device.major = MAJOR(mod_device.devid);
mod_device.minor = MINOR(mod_device.devid);
}
if(ret < 0){ printk("设备号申请失败\r\n");goto fail_chrdev; }
printk("mod_device major=%d,minor=%d\r\n",mod_device.major,mod_device.minor);
mod_device.cdev.owner = THIS_MODULE;
cdev_init(&mod_device.cdev,&beep_fops);
ret = cdev_add(&mod_device.cdev,mod_device.devid,DeviceNodes);
if(ret < 0){ printk("添加cdev失败!\r\n");goto fail_cdev; }
mod_device.class = class_create(THIS_MODULE,DeviceName);
if (IS_ERR(mod_device.class)) { ret = PTR_ERR(mod_device.class);goto fail_class; }
mod_device.device = device_create(mod_device.class,NULL,mod_device.devid,NULL,"pinctrl-timer");
if (IS_ERR(mod_device.device)) { ret = PTR_ERR(mod_device.device);goto fail_device; }
ret = led_init(&mod_device);
if(ret < 0){ printk("led_init fail!\r\n");goto fail_ledinit; }
init_timer(&mod_device.timer);
mod_device.timer.function = timer_func;
mod_device.timer.expires = jiffies + msecs_to_jiffies(500);
mod_device.timer.data = (unsigned long)(&mod_device);
add_timer(&mod_device.timer);
return 0;
fail_ledinit:
device_destroy(mod_device.class,mod_device.devid);
fail_device:
class_destroy(mod_device.class);
fail_class:
cdev_del(&mod_device.cdev);
fail_cdev:
unregister_chrdev_region(mod_device.devid,DeviceNodes);
fail_chrdev:
return ret;
}
static void __exit kernel_timer_exit(void)
{
del_timer(&mod_device.timer);
gpio_set_value(mod_device.gpio,1);
gpio_free(mod_device.gpio);
device_destroy(mod_device.class,mod_device.devid);
class_destroy(mod_device.class);
cdev_del(&mod_device.cdev);
unregister_chrdev_region(mod_device.devid,DeviceNodes);
}
module_init(kernel_timer_init);
module_exit(kernel_timer_exit);
MODULE_LICENSE("GPL");
二、app测试程序
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#define CLOSE_CMD _IO(0XEF, 1)
#define OPEN_CMD _IO(0XEF, 2)
#define SETPERIOD_CMD _IOW(0xEF, 3, int)
int main(int argc, char *argv[])
{
int fd, ret;
char *filename;
unsigned char databuf[1];
unsigned int cmd;
unsigned int arg;
unsigned char str[100];
if(argc != 2) {
printf("Error Usage!\r\n");
return -1;
}
filename = argv[1];
fd = open(filename, O_RDWR);
if(fd < 0) {
printf("file %s open failed!\r\n", filename);
return -1;
}
while(1) {
printf("Input CMD:");
ret = scanf("%d", &cmd);
if(ret !=1 ) {
gets(str);
}
if(cmd == 1) {
ioctl(fd, CLOSE_CMD, &arg);
} else if(cmd == 2) {
ioctl(fd, OPEN_CMD, &arg);
} else if(cmd == 3) {
printf("Please input timer period->");
ret = scanf("%d", &arg);
printf("Your input message->%d\r\n",arg);
if(ret !=1 ) {
gets(str);
}
ioctl(fd, SETPERIOD_CMD, &arg);
}
}
close(fd);
return 0;
}