Linux 字符设备驱动

来源:互联网 发布:通往天堂的钥匙淘宝网 编辑:程序博客网 时间:2024/06/01 20:48
字符设备驱动
主设备号和次设备号的获取
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");



原创粉丝点击