一个LED驱动的编写

来源:互联网 发布:java项目开发难点 编辑:程序博客网 时间:2024/04/28 01:11
#include <linux/kernel.h>#include <linux/module.h>#include <linux/cdev.h>#include <linux/fs.h>#include <linux/miscdevice.h>#include <linux/kdev_t.h>#include <linux/device.h>#include<linux/io.h>#include<linux/uaccess.h>#include<linux/export.h>#include<linux/types.h>#define GPM4CON 0x110002E0volatile unsigned long *baseaddr = 0;       //地址必须要 volatile 修饰,volatile 是防止优化,就是避免某次计算中间值存放在寄存器中没有存入flash,这会导致以后读取的值不是想要的#define rGPM4CON (*((volatile unsigned long *)(baseaddr + 0)))#define rGPM4DAT (*((volatile unsigned long *)(baseaddr + 1)))#define MYLED_MAJOR 0#define MYLED_NAME "led"#define MYLED_DRVNUM 1#define MYLED_NUM 4dev_t myled_devt;       //设备号int myled_major;struct class *myled_class;      //设备结构体struct cdev *myled;             //设备驱动核心结构char led_status[MYLED_NUM]={-1,-1,-1,-1};loff_t led_lseek (struct file *fp, loff_t off, int whence){    loff_t newoff=0;    switch(whence)    {        case SEEK_SET:            newoff=off;            break;        case SEEK_CUR:            newoff = fp->f_pos+off;            break;        case SEEK_END:            newoff = 4 + off;        default:            return -EINVAL;    }    if(newoff<0)        newoff = 0;    else if(newoff>4)        newoff = 4;    fp->f_pos=newoff;    return newoff;}ssize_t led_read (struct file *fp, char __user *buf, size_t size, loff_t *off){    int i=0;    unsigned long ret;    if(*off>4)        return -EINVAL;    if(*off+size>4)        size = 4-*off;    for(i=0;i<MYLED_NUM;i++)        led_status[i]= !(rGPM4DAT&(0x1<<i));    ret = copy_to_user(buf,&led_status[*off],size);    //copy_to_user 还是 copy_from_user 都是到前一个参数,且使用的都是地址    *off = *off+size;    printk("led_read is called\n");    return 0;}ssize_t led_write (struct file *fp, const char __user *buf, size_t size, loff_t *off){    int i;    unsigned long temp;    if(*off>4)        return -EINVAL;    if(*off + size >4)        size = 4 - *off;    temp = copy_from_user(&led_status[*off],buf,size);    for(i=0;i<MYLED_NUM;i++)    {        if(led_status[i] == 0)            rGPM4DAT |= (0x1<<i);        else if(led_status[i] == 1)            rGPM4DAT &= ~(0x1<<i);        else            return -EINVAL;    }    *off = *off + size;    printk("led_write is called \n");    return 0;}int led_open (struct inode *node, struct file *fp){    int i=0;    fp->private_data =(void *) MINOR(node->i_rdev);    rGPM4CON &= ~(0xffff);    rGPM4CON |= (0x1111);    for(i=0;i<MYLED_NUM;i++)    {        led_status[i] = !(rGPM4DAT&(0x1<<i));    }    printk("led_open is called \n");    return 0;}int led_close (struct inode *node, struct file *fp){    printk("led_close is called \n");    return 0;}struct file_operations led_fops={    .owner=THIS_MODULE,    .open =led_open,    .release = led_close,    .read=led_read,    .write = led_write,    .llseek = led_lseek,};static int __init myled_init(void)      //形参不能为空{    int i=0;#if MYLED_MAJOR                         //如果不为 0,则设备号就是自主分配    myled_major = MYLED_MAJOR;    myled_devt = MKDEV(myled_major,0);    if(register_chrdev_region(myled_devt,MYLED_DRVNUM,MYLED_NAME))      //静态注册设备号#else    if(alloc_chrdev_region(&myled_devt,0,MYLED_DRVNUM,MYLED_NAME))      //主设备号为 0 ,动态注册设备号#endif    {        printk("注册失败\n");        return -EBUSY;    }    myled = cdev_alloc();               //分配设备空间    /*    这里多说两句,每一个设备都是一个结构体,这个结构体包括    struct kobject kobj;                    の,忘了干嘛的    struct module *owner;                   所属的模块    const struct file_operations *ops;      所使用的文件操作函数    struct list_head list;                  链表,向内和联表添加    dev_t dev;                              设备号    unsigned int count;                     设备数目    */    cdev_init(myled,&led_fops);         //初始化设备        /*        这个初始化这是把文件函数结构体添加到设备结构体    */    if(cdev_add(myled,myled_devt,MYLED_DRVNUM))     //添加设备空间        {        printk("注册成功\n");        return -EBUSY;    }    printk("注册成功\n");    myled_class = class_create(THIS_MODULE,MYLED_NAME);     //产生一个设备类    for(i=0;i<MYLED_DRVNUM;i++)             //添加设备类进内核        device_create(myled_class,NULL,myled_devt+i,NULL,"myled%d",i);    baseaddr = ioremap(GPM4CON, 8);         //硬件地址映射到虚拟地址    return 0;}static void __exit myled_exit(void)     //形参不能为空,必须有个void{    iounmap(baseaddr);      //取消地址映射    device_destroy(myled_class, myled_devt);        //销毁在内核的设备    class_destroy(myled_class);                     //销毁设备类    cdev_del(myled);                                //删除设备    unregister_chrdev_region(myled_devt,MYLED_DRVNUM);  //注销设备    printk("注销成功\n");}module_init(myled_init);module_exit(myled_exit);MODULE_LICENSE("GPL");
原创粉丝点击