字符设备驱动
模板
#include<linux/kernel.h>
#include<linux/module.h>
#include <linux/delay.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/miscdevice.h>
#include <linux/platform_device.h>
#include <linux/cdev.h>
#define fly_pr_info(fmt, arg...) printk(KERN_WARNING fmt, ##arg)
#define FLYGPIO_DEBUG_ON 1
#define FLYGPIO_DEBUG(fmt, arg...) do {\
if (FLYGPIO_DEBUG_ON)\
fly_pr_info("<<-tlt->> [%d]"fmt"\n", __LINE__, ##arg);\
} while (0)
int mycdev_open(struct inode *inode, struct file *filp)
{
return 0;
}
int mycdev_release(struct inode *inode, struct file *filp)
{
return 0;
}
static ssize_t mycdev_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)
{
return 0;
}
static ssize_t mycdev_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos)
{
return 0;
}
static const struct file_operations mycdev_fops =
{
.read = mycdev_read,
.write = mycdev_write,
.open = mycdev_open,
.release = mycdev_release,
};
static struct miscdevice my_misc_device = {
.minor = MISC_DYNAMIC_MINOR,
.name = "my_miscdev",
.fops = &mycdev_fops,
};
static int mygpio_probe(struct platform_device *pdev)
{
int ret = 0;
FLYGPIO_DEBUG("@@flygpio Probe. \r\n");
ret = misc_register(&my_misc_device);
if (ret != 0 )
FLYGPIO_DEBUG("flygpio: flygpio_device register failed\n");
return ret;
}
static int mygpio_remove(struct platform_device *pdev)
{
FLYGPIO_DEBUG("flygpio remove. \r\n");
misc_deregister(&my_misc_device);
return 0;
}
static struct platform_driver mygpio_driver = {
.driver = {
.name = "mygpio-dev",
.owner = THIS_MODULE,
},
.remove = mygpio_remove,
.probe = mygpio_probe,
};
static struct platform_device mygpio_device = {
.name = "mygpio-dev",
.id = -1,
};
static int __init mycdev_init(void)
{
int ret = -1;
ret = platform_device_register(&mygpio_device);
if (ret)
{
FLYGPIO_DEBUG("platform_device_register_failed ");
goto platform_device_register_failed;
}
ret = platform_driver_register(&mygpio_driver);
if (ret)
{
FLYGPIO_DEBUG("platform_driver_register_failed ");
goto platform_driver_register_failed;
}
return 0;
platform_driver_register_failed:
platform_device_unregister(&flygpio_device);
platform_device_register_failed:
return ret;
}
static void __exit mycdev_exit(void)
{
FLYGPIO_DEBUG("mycdev exit\r\n");
platform_driver_unregister(&mygpio_driver);
platform_device_unregister(&mygpio_device);
}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");
添加设备树获取gpio可编译控灯
#include<linux/kernel.h>
#include<linux/module.h>
#include <linux/delay.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/miscdevice.h>
#include <linux/platform_device.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <generated/autoconf.h>
#include <linux/ioctl.h>
#include <linux/spinlock.h>
#include <asm/io.h>
#include <linux/irq.h>
#include <asm/atomic.h>
#include <linux/of_gpio.h>
#include <linux/time.h>
#include <linux/kthread.h>
#include <linux/types.h>
#include <linux/poll.h>
#include <linux/interrupt.h>
static struct device_node *flygpio_node = NULL;
// 设置gpio高低电平
static int apstate_led_pin = -1;
// #define LED_ON gpio_set_value(apstate_led_pin,0);
// #define LED_OFF gpio_set_value(apstate_led_pin,1);
#define LED_ON do{ gpio_set_value(apstate_led_pin,0); }while(0)
#define LED_OFF do{ gpio_set_value(apstate_led_pin,1); }while(0)
#define fly_pr_info(fmt, arg...) printk(KERN_WARNING fmt, ##arg)
#define FLYGPIO_DEBUG_ON 1
#define FLYGPIO_DEBUG(fmt, arg...) do {\
if (FLYGPIO_DEBUG_ON)\
fly_pr_info("<<-tlt->> [%d]"fmt"\n", __LINE__, ##arg);\
} while (0)
int mycdev_open(struct inode *inode, struct file *filp)
{
return 0;
}
int mycdev_release(struct inode *inode, struct file *filp)
{
return 0;
}
static ssize_t mycdev_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)
{
return (ssize_t)0;
}
static ssize_t mycdev_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos)
{
char readbuf[30];
int ret_cnt;
int CopyBufSize = (size < (sizeof(readbuf) - 1)) ? (size) : (sizeof(readbuf) - 1);
int pin,value;
// 将内核空间的数据拷贝到回调该函数的用户进程的用户进程空间
if (copy_from_user(readbuf, buf, CopyBufSize))
{
FLYGPIO_DEBUG("@@copy_from_user() fail.\r\n");
return -1;
}
FLYGPIO_DEBUG("@@hello write buffer :%s\n",readbuf);
//对写入的管脚和值使用空格分开,使用sscanf分别获取
ret_cnt = sscanf(readbuf, "%d %d",&pin, &value);
if(ret_cnt != 2)
{
FLYGPIO_DEBUG("@@ret_cnt != 2 fail.\r\n");
return -1;
}
// 判断设置的值是否合法 0 | 1
if(value == 0)
{
FLYGPIO_DEBUG("@@set LED OFF. \r\n");
LED_OFF;
}
else
{
FLYGPIO_DEBUG("@@set LED ON.\r\n");
LED_ON;
}
FLYGPIO_DEBUG("@@you write pin %d,value = %d \n",pin,value);
// 内核中返回值不可为0
return ((ssize_t)size);
}
static const struct file_operations mycdev_fops =
{
.read = mycdev_read,
.write = mycdev_write,
.open = mycdev_open,
.release = mycdev_release,
};
static struct miscdevice my_misc_device = {
.minor = MISC_DYNAMIC_MINOR,
.name = "my_miscdev",
.fops = &mycdev_fops,
};
static int mygpio_probe(struct platform_device *pdev)
{
int ret = 0;
FLYGPIO_DEBUG("@@flygpio Probe. \r\n");
ret = misc_register(&my_misc_device);
if (ret != 0 )
FLYGPIO_DEBUG("@@flygpio: flygpio_device register failed\n");
return ret;
}
static int mygpio_remove(struct platform_device *pdev)
{
FLYGPIO_DEBUG("@@flygpio remove. \r\n");
misc_deregister(&my_misc_device);
return 0;
}
static struct platform_driver mygpio_driver = {
.driver = {
.name = "mygpio-dev",
.owner = THIS_MODULE,
},
.remove = mygpio_remove,
.probe = mygpio_probe,
};
static struct platform_device mygpio_device = {
.name = "mygpio-dev",
.id = -1,
};
static int __init mycdev_init(void)
{
int ret = -1;
flygpio_node = of_find_compatible_node(NULL, NULL, "mediatek,flyrdgpio");
if(flygpio_node)
{
apstate_led_pin = of_get_named_gpio(flygpio_node,"apstate_led_gpio", 0);
FLYGPIO_DEBUG("@@my_gpio_get_name ---------apstate_led_pin------- oK\r\n");
if (!gpio_is_valid(apstate_led_pin))
{
FLYGPIO_DEBUG("apstate_led_pin bc_failed\n");
}
}
FLYGPIO_DEBUG("@@led 1 = %d \r\n",apstate_led_pin);
ret = gpio_request(apstate_led_pin, "apstate_led_pin");
if (ret < 0)
{
FLYGPIO_DEBUG("apstate_led_pin gpio bc_failed\n");
//return;
}
gpio_direction_output(apstate_led_pin, 0);
FLYGPIO_DEBUG("@@mycdev_init ");
ret = platform_device_register(&mygpio_device);
if (ret)
{
FLYGPIO_DEBUG("@@platform_device_register_failed ");
goto platform_device_register_failed;
}
ret = platform_driver_register(&mygpio_driver);
if (ret)
{
FLYGPIO_DEBUG("@@platform_driver_register_failed ");
goto platform_driver_register_failed;
}
return 0;
platform_driver_register_failed:
//platform_device_unregister(&flygpio_device);
platform_device_register_failed:
return ret;
}
static void __exit mycdev_exit(void)
{
FLYGPIO_DEBUG("@@mycdev exit\r\n");
platform_driver_unregister(&mygpio_driver);
platform_device_unregister(&mygpio_device);
}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");
Makefile
在驱动源码目录下的Makefile添加
obj-m +=testgpio.o
在驱动源码的上级目录下的Makefile添加
obj-m += test/
编译方法
在总项目路径如/ac8257目录下执行
source ./build/envsetup.sh
lunch 15
mmm kernel-4.9:kernel
make bootimage