Linux 字符设备驱动
2017-05-18 16:51
204 查看
字符设备驱动
主设备号和次设备号的获取
MAJOR(dev)
MINOR(dev)
MKDEV(ma,mi)
字符设备加载和卸载函数
struct xxx_dev
{
struct cdev cdev;
.....
};
static init __init xxx_init(void)
{
if(xxx_major)
result = register_chrdev_region(xxx_devno, 1,"DEV_NAME");
else
{
result = alloc_chrdev_region(&xxx_devno,0,1,"DEV_NAME");
XXX_MAJOR = MAJOR(xxx_devno);
}
cdev_init(&xxx_dev.cdev,&xxx_fops);
cdev-> cdev.owner = THIS_MODULE;
err = cdev_add(&xxx_dev.cdev,xxx_devno,1);
}
static void __exit xxx_exit(void)
{
cdev_del(&xxx_dev.cdev);
unregister_chrdev_region(xxx_devno,1);
}
static const struct file_operation xxx_fops =
{
.owner = THIS_MODULE,
.read = xxx_read,
.write = xxx_write,
.ioctl = xxx_ioctl,
};
字符设备驱动的file_operations结构体中成员函数
大多数字符设备驱动会实现read() write() ioctl()函数
ssize_t xxx_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
copy_to_user(buf,...,...);
}
ssize_t xxx_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
{
copy_from_user(..., buf, ...);
}
static long xxx_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
{
void __user *argp = (void __user *)arg;
int __user *p = argp;
int new_margin;
switch (cmd) {
case XA:
return copy_to_user(argp, &内核数据, 数据size);
case XB:
return put_user(0, p);
case XC:
if(get_user(new_margin, p))
return -EFAULT;
case XD:
return copy_form_user(argp, );
}
}
ioctl()命令
设备类型 序列号 方向 数据尺寸
8bit 8bit 2bit 13/14bit
命令码的设备类型字段为一个“幻数”,可以是0~0xff之间的值,
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36))
.unlocked_ioctl = fd650_ioctl,
#else
.ioctl = fd650_ioctl,
#endif
#if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,36))
static long stk_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
#else
static int stk_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
#endif
/* IOCTLs*/
#define STK_IOCTL_WRITE _IOW(STKDIR, 0x01, char[8])
#define STK_IOCTL_READ _IOWR(STKDIR, 0x02, char[8])
#define STK_IOCTL_SET_ENABLE _IOW(STKDIR, 0x03, char)
#define STK_IOCTL_GET_ENABLE _IOR(STKDIR, 0x04, char)
#define STK_IOCTL_SET_DELAY _IOW(STKDIR, 0x05, char)
#define STK_IOCTL_GET_DELAY _IOR(STKDIR, 0x06, char)
#define STK_IOCTL_SET_OFFSET _IOW(STKDIR, 0x07, char[3])
#define STK_IOCTL_GET_OFFSET _IOR(STKDIR, 0x08, char[3])
#define STK_IOCTL_GET_ACCELERATION _IOR(STKDIR, 0x09, int[3])
#define STK_IOCTL_SET_RANGE _IOW(STKDIR, 0x10, char)
#define STK_IOCTL_GET_RANGE _IOR(STKDIR, 0x11, char)
#define STK_IOCTL_SET_CALI _IOW(STKDIR, 0x12, char)
全专A20平台GPIO 控制LED灯的驱动实例:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/gpio.h>
#include <mach/sys_config.h>
#include <mach/hardware.h>
#include <mach/gpio.h>
#include <mach/platform.h>
#ifdef CONFIG_HAS_EARLYSUSPEND
#include <linux/earlysuspend.h>
#endif
#if defined(CONFIG_HAS_EARLYSUSPEND) || defined(CONFIG_PM)
#include <linux/pm.h>
#include <linux/earlysuspend.h>
#endif
static u32 debug_mask = 0;
#define dprintk(level_mask, fmt, arg...) if(unlikely(debug_mask & level_mask)) \
printk("[SUN7I-STANDBY-LED]:"fmt, ## arg)
#define LED_ON 1
#define LED_OFF 0
#define SUN7I_LED_NAME "sun7i-led"
static dev_t devid;
static struct sun7i_led {
struct cdev *cdev;
u32 standby_led;
u32 power_led;
#ifdef CONFIG_HAS_EARLYSUSPEND
struct early_suspend early_suspend;
#endif
};
u32 standby_led;
u32 power_led;
static struct sun7i_led *sun7i_devp;
#ifdef CONFIG_HAS_EARLYSUSPEND
static void sun7i_led_earlysuspend(struct early_suspend *h){
printk("=========sun7i_led_earlysuspend=======\n");
//__gpio_set_value(sun7i_devp->standby_led, LED_OFF);
//__gpio_set_value(sun7i_devp->power_led,LED_ON);
__gpio_set_value(standby_led,1);
__gpio_set_value(power_led,0);
printk("standby_led value:%d\n",__gpio_get_value(standby_led));
printk("power_led value:%d\n",__gpio_get_value(power_led));
}
static void sun7i_led_resume(struct early_suspend *h){
printk("===========sun7i_led_resume=========\n");
//__gpio_set_value(sun7i_devp->standby_led, LED_ON);
//__gpio_set_value(sun7i_devp->power_led,LED_OFF);
__gpio_set_value(standby_led,0);
__gpio_set_value(power_led,1);
printk("standby_led value:%d\n",__gpio_get_value(standby_led));
printk("power_led value:%d\n",__gpio_get_value(power_led));
}
/*
static struct early_suspend sun7i_led_earlysuspend_handle = {
.level = EARLY_SUSPEND_LEVEL_DISABLE_FB,
.suspend =sun7i_led_earlysuspend,
.resume =sun7i_led_resume,
};*/
#endif
static int sun7i_led_open(struct inode *inode, struct file *file){
printk("============%s===========\n",__func__);
return 0;
}
static int sun7i_led_release(struct inode *inode, struct file *file){
printk("============%s===========\n",__func__);
return 0;
}
long sun7i_led_ioctl(struct file *file, unsigned int cmd, unsigned long arg){
printk("===========sun7i_led_ioctl============\n");
return 0;
}
int sun7i_led_mmp(struct file *file, struct vm_area_struct *vma){
printk("========sun7i_led_mmp===========\n");
return 0;
}
static struct file_operations sun7i_fops = {
.owner = THIS_MODULE,
.open = sun7i_led_open,
.release = sun7i_led_release,
.unlocked_ioctl = sun7i_led_ioctl,
.mmap = sun7i_led_mmp,
};
static int sun7i_platform_frecth(void){
script_item_u val;
script_item_value_type_e type;
int state = -EINVAL;
type = script_get_item("card_boot", "power_led", &val);
if(SCIRPT_ITEM_VALUE_TYPE_PIO != type){
printk("error script_get_item \n");
return -1;
}
sun7i_devp->power_led=val.gpio.gpio;
type = script_get_item("card_boot","sleep_led",&val);
if(SCIRPT_ITEM_VALUE_TYPE_PIO != type){
printk("error ");
return -1;
}
sun7i_devp->standby_led = val.gpio.gpio;
state = gpio_request_one(sun7i_devp->standby_led, GPIOF_OUT_INIT_LOW,NULL);
if(0 != state){
printk("gpio_request_one standby_led failed!\n");
}
state = gpio_request_one(sun7i_devp->power_led,GPIOF_OUT_INIT_LOW,NULL);
if(0 != state){
printk("gpio_request_one power_led failed!\n");
}
return 0;
}
int __init sun7i_led_init(void)
{
int err,ret;
#if 1
standby_led = GPIOD(16);
power_led = GPIOD(17);
int state = -EINVAL;
state = gpio_request_one(standby_led,GPIOF_OUT_INIT_HIGH,NULL);
if(0 != state){
printk("gpio_request_one standby_led failed!\n");
}
state = gpio_request_one(power_led,GPIOF_OUT_INIT_LOW,NULL);
if(0 != state){
printk("gpio_request_one power_led failed!\n");
}
printk("===========%s===========\n",__func__);
sun7i_devp = kzalloc(sizeof(*sun7i_devp), GFP_KERNEL);
if(!sun7i_devp){
printk("alloc sun7i_devp failed!\n");
return -ENOMEM;
}
#endif
#if 0
if(!sun7i_platform_frecth()){
printk("sun7i_platform_frecth error\n");
}
#endif
//sun7i_cdev = sun7i_devp;
#ifdef CONFIG_HAS_EARLYSUSPEND
sun7i_devp->early_suspend.level=EARLY_SUSPEND_LEVEL_DISABLE_FB + 1;
sun7i_devp->early_suspend.suspend = sun7i_led_earlysuspend;
sun7i_devp->early_suspend.resume = sun7i_led_resume;
register_early_suspend(&sun7i_devp->early_suspend);
#endif
alloc_chrdev_region(&devid, 0, 1,SUN7I_LED_NAME);
sun7i_devp->cdev=cdev_alloc();
cdev_init(sun7i_devp->cdev,&sun7i_fops);
sun7i_devp->cdev->owner = THIS_MODULE;
err = cdev_add(sun7i_devp->cdev, devid, 1);
if(err){
printk("I was assigned major number:%d\n",MAJOR(devid));
return -1;
}
printk("===========sun7i_standby_led init ok==========\n");
return 0;
}
void __exit sun7i_led_exit(void){
gpio_free(sun7i_devp->power_led);
gpio_free(sun7i_devp->standby_led);
cdev_del(&sun7i_devp->cdev);
unregister_chrdev_region(devid, 1);
#ifdef CONFIG_HAS_EARLYSUSPEND
unregister_early_suspend(&sun7i_devp->early_suspend);
#endif
}
module_init(sun7i_led_init);
module_exit(sun7i_led_exit);
MODULE_ALIAS("SUN7I STANDBY LED");
MODULE_DESCRIPTION("8250 UART probe driver for SGI IP32 aka O2");
MODULE_LICENSE("GPL");
主设备号和次设备号的获取
MAJOR(dev)
MINOR(dev)
MKDEV(ma,mi)
字符设备加载和卸载函数
struct xxx_dev
{
struct cdev cdev;
.....
};
static init __init xxx_init(void)
{
if(xxx_major)
result = register_chrdev_region(xxx_devno, 1,"DEV_NAME");
else
{
result = alloc_chrdev_region(&xxx_devno,0,1,"DEV_NAME");
XXX_MAJOR = MAJOR(xxx_devno);
}
cdev_init(&xxx_dev.cdev,&xxx_fops);
cdev-> cdev.owner = THIS_MODULE;
err = cdev_add(&xxx_dev.cdev,xxx_devno,1);
}
static void __exit xxx_exit(void)
{
cdev_del(&xxx_dev.cdev);
unregister_chrdev_region(xxx_devno,1);
}
static const struct file_operation xxx_fops =
{
.owner = THIS_MODULE,
.read = xxx_read,
.write = xxx_write,
.ioctl = xxx_ioctl,
};
字符设备驱动的file_operations结构体中成员函数
大多数字符设备驱动会实现read() write() ioctl()函数
ssize_t xxx_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
copy_to_user(buf,...,...);
}
ssize_t xxx_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
{
copy_from_user(..., buf, ...);
}
static long xxx_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
{
void __user *argp = (void __user *)arg;
int __user *p = argp;
int new_margin;
switch (cmd) {
case XA:
return copy_to_user(argp, &内核数据, 数据size);
case XB:
return put_user(0, p);
case XC:
if(get_user(new_margin, p))
return -EFAULT;
case XD:
return copy_form_user(argp, );
}
}
ioctl()命令
设备类型 序列号 方向 数据尺寸
8bit 8bit 2bit 13/14bit
命令码的设备类型字段为一个“幻数”,可以是0~0xff之间的值,
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36))
.unlocked_ioctl = fd650_ioctl,
#else
.ioctl = fd650_ioctl,
#endif
#if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,36))
static long stk_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
#else
static int stk_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
#endif
/* IOCTLs*/
#define STK_IOCTL_WRITE _IOW(STKDIR, 0x01, char[8])
#define STK_IOCTL_READ _IOWR(STKDIR, 0x02, char[8])
#define STK_IOCTL_SET_ENABLE _IOW(STKDIR, 0x03, char)
#define STK_IOCTL_GET_ENABLE _IOR(STKDIR, 0x04, char)
#define STK_IOCTL_SET_DELAY _IOW(STKDIR, 0x05, char)
#define STK_IOCTL_GET_DELAY _IOR(STKDIR, 0x06, char)
#define STK_IOCTL_SET_OFFSET _IOW(STKDIR, 0x07, char[3])
#define STK_IOCTL_GET_OFFSET _IOR(STKDIR, 0x08, char[3])
#define STK_IOCTL_GET_ACCELERATION _IOR(STKDIR, 0x09, int[3])
#define STK_IOCTL_SET_RANGE _IOW(STKDIR, 0x10, char)
#define STK_IOCTL_GET_RANGE _IOR(STKDIR, 0x11, char)
#define STK_IOCTL_SET_CALI _IOW(STKDIR, 0x12, char)
全专A20平台GPIO 控制LED灯的驱动实例:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/gpio.h>
#include <mach/sys_config.h>
#include <mach/hardware.h>
#include <mach/gpio.h>
#include <mach/platform.h>
#ifdef CONFIG_HAS_EARLYSUSPEND
#include <linux/earlysuspend.h>
#endif
#if defined(CONFIG_HAS_EARLYSUSPEND) || defined(CONFIG_PM)
#include <linux/pm.h>
#include <linux/earlysuspend.h>
#endif
static u32 debug_mask = 0;
#define dprintk(level_mask, fmt, arg...) if(unlikely(debug_mask & level_mask)) \
printk("[SUN7I-STANDBY-LED]:"fmt, ## arg)
#define LED_ON 1
#define LED_OFF 0
#define SUN7I_LED_NAME "sun7i-led"
static dev_t devid;
static struct sun7i_led {
struct cdev *cdev;
u32 standby_led;
u32 power_led;
#ifdef CONFIG_HAS_EARLYSUSPEND
struct early_suspend early_suspend;
#endif
};
u32 standby_led;
u32 power_led;
static struct sun7i_led *sun7i_devp;
#ifdef CONFIG_HAS_EARLYSUSPEND
static void sun7i_led_earlysuspend(struct early_suspend *h){
printk("=========sun7i_led_earlysuspend=======\n");
//__gpio_set_value(sun7i_devp->standby_led, LED_OFF);
//__gpio_set_value(sun7i_devp->power_led,LED_ON);
__gpio_set_value(standby_led,1);
__gpio_set_value(power_led,0);
printk("standby_led value:%d\n",__gpio_get_value(standby_led));
printk("power_led value:%d\n",__gpio_get_value(power_led));
}
static void sun7i_led_resume(struct early_suspend *h){
printk("===========sun7i_led_resume=========\n");
//__gpio_set_value(sun7i_devp->standby_led, LED_ON);
//__gpio_set_value(sun7i_devp->power_led,LED_OFF);
__gpio_set_value(standby_led,0);
__gpio_set_value(power_led,1);
printk("standby_led value:%d\n",__gpio_get_value(standby_led));
printk("power_led value:%d\n",__gpio_get_value(power_led));
}
/*
static struct early_suspend sun7i_led_earlysuspend_handle = {
.level = EARLY_SUSPEND_LEVEL_DISABLE_FB,
.suspend =sun7i_led_earlysuspend,
.resume =sun7i_led_resume,
};*/
#endif
static int sun7i_led_open(struct inode *inode, struct file *file){
printk("============%s===========\n",__func__);
return 0;
}
static int sun7i_led_release(struct inode *inode, struct file *file){
printk("============%s===========\n",__func__);
return 0;
}
long sun7i_led_ioctl(struct file *file, unsigned int cmd, unsigned long arg){
printk("===========sun7i_led_ioctl============\n");
return 0;
}
int sun7i_led_mmp(struct file *file, struct vm_area_struct *vma){
printk("========sun7i_led_mmp===========\n");
return 0;
}
static struct file_operations sun7i_fops = {
.owner = THIS_MODULE,
.open = sun7i_led_open,
.release = sun7i_led_release,
.unlocked_ioctl = sun7i_led_ioctl,
.mmap = sun7i_led_mmp,
};
static int sun7i_platform_frecth(void){
script_item_u val;
script_item_value_type_e type;
int state = -EINVAL;
type = script_get_item("card_boot", "power_led", &val);
if(SCIRPT_ITEM_VALUE_TYPE_PIO != type){
printk("error script_get_item \n");
return -1;
}
sun7i_devp->power_led=val.gpio.gpio;
type = script_get_item("card_boot","sleep_led",&val);
if(SCIRPT_ITEM_VALUE_TYPE_PIO != type){
printk("error ");
return -1;
}
sun7i_devp->standby_led = val.gpio.gpio;
state = gpio_request_one(sun7i_devp->standby_led, GPIOF_OUT_INIT_LOW,NULL);
if(0 != state){
printk("gpio_request_one standby_led failed!\n");
}
state = gpio_request_one(sun7i_devp->power_led,GPIOF_OUT_INIT_LOW,NULL);
if(0 != state){
printk("gpio_request_one power_led failed!\n");
}
return 0;
}
int __init sun7i_led_init(void)
{
int err,ret;
#if 1
standby_led = GPIOD(16);
power_led = GPIOD(17);
int state = -EINVAL;
state = gpio_request_one(standby_led,GPIOF_OUT_INIT_HIGH,NULL);
if(0 != state){
printk("gpio_request_one standby_led failed!\n");
}
state = gpio_request_one(power_led,GPIOF_OUT_INIT_LOW,NULL);
if(0 != state){
printk("gpio_request_one power_led failed!\n");
}
printk("===========%s===========\n",__func__);
sun7i_devp = kzalloc(sizeof(*sun7i_devp), GFP_KERNEL);
if(!sun7i_devp){
printk("alloc sun7i_devp failed!\n");
return -ENOMEM;
}
#endif
#if 0
if(!sun7i_platform_frecth()){
printk("sun7i_platform_frecth error\n");
}
#endif
//sun7i_cdev = sun7i_devp;
#ifdef CONFIG_HAS_EARLYSUSPEND
sun7i_devp->early_suspend.level=EARLY_SUSPEND_LEVEL_DISABLE_FB + 1;
sun7i_devp->early_suspend.suspend = sun7i_led_earlysuspend;
sun7i_devp->early_suspend.resume = sun7i_led_resume;
register_early_suspend(&sun7i_devp->early_suspend);
#endif
alloc_chrdev_region(&devid, 0, 1,SUN7I_LED_NAME);
sun7i_devp->cdev=cdev_alloc();
cdev_init(sun7i_devp->cdev,&sun7i_fops);
sun7i_devp->cdev->owner = THIS_MODULE;
err = cdev_add(sun7i_devp->cdev, devid, 1);
if(err){
printk("I was assigned major number:%d\n",MAJOR(devid));
return -1;
}
printk("===========sun7i_standby_led init ok==========\n");
return 0;
}
void __exit sun7i_led_exit(void){
gpio_free(sun7i_devp->power_led);
gpio_free(sun7i_devp->standby_led);
cdev_del(&sun7i_devp->cdev);
unregister_chrdev_region(devid, 1);
#ifdef CONFIG_HAS_EARLYSUSPEND
unregister_early_suspend(&sun7i_devp->early_suspend);
#endif
}
module_init(sun7i_led_init);
module_exit(sun7i_led_exit);
MODULE_ALIAS("SUN7I STANDBY LED");
MODULE_DESCRIPTION("8250 UART probe driver for SGI IP32 aka O2");
MODULE_LICENSE("GPL");
相关文章推荐
- 编写Linux并行接口字符设备驱动
- Linux字符设备驱动学习
- Linux内核开发之简单字符设备驱动(下)
- Linux字符设备驱动(二)
- Linux字符设备驱动总结
- Linux字符设备驱动的register_chrdev()与unregister_chrdev()
- s3c2440基于linux的gpio led字符设备驱动实践 [转]
- LINUX—字符设备驱动之-globalmem
- Linux 字符设备驱动中的数据结构
- Linux字符设备驱动的register_chrdev()与unregister_chrdev()
- linux2.6字符设备驱动编程第一例:globalmem
- Linux嵌入式驱动初体验(七)--- LED驱动之字符设备篇
- linux分类驱动对字符设备框架压力的卸载
- 嵌入式Linux字符设备入门之--LED驱动详解
- 第12章 Linux字符设备驱动综合实例
- s3c2440基于linux的gpio led字符设备驱动实践
- Linux 驱动开发-字符设备驱动
- Linux 驱动开发-字符设备驱动一些函数用法
- Linux字符设备驱动的register_chrdev()与unregister_chrdev()
- LINUX—字符设备驱动之-globalmem