驱动移植基础

13 篇文章 0 订阅
2 篇文章 0 订阅

linux模块框架

linux模块框架

/*头文件    头文件路径*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/kdev_t.h>
#include <linux/cdev.h>
#include <asm/io.h>

#include "mycmd.h"


#define MA 500
#define MI 0

#define GPF3CON 0x114001e0 /*led*/
#define GPF3DAT 0x114001e4

#define ADCCFG 0x10010118/*adc*/
#define ADCCON 0x126C0000
#define ADCDAT 0x126C000c
#define ADCMUX 0x126c001c

static dev_t no = 0;
static unsigned count = 1;
const char* name = "myDev02";
static struct cdev mydev;

static char buf[20]={0};

static unsigned int* gpf3con = NULL;
static unsigned int* gpf3dat = NULL;

static unsigned int* adccfg = NULL;
static unsigned int* adccon = NULL;
static unsigned int* adcdat = NULL;
static unsigned int* adcmux = NULL;






static void adc_init(void)
{
    adccfg = ioremap(ADCCFG,4);//物理地址映射到虚拟地址 
    adccon = ioremap(ADCCON,4);//物理地址映射到虚拟地址 
    adcmux = ioremap(ADCMUX,4);//物理地址映射到虚拟地址 
    adcdat = ioremap(ADCDAT,4);//物理地址映射到虚拟地址 

    writel(0x3,adcmux);
    writel(readl(adccfg)&~(0x1<<16),adccfg);
    writel((0x1<<16)|(0x1<<14)|(0xff<<6)|(0x1<<1),adccon);
}
static int adc_getData(void)
{
    return readl(adcdat)&0xfff;
}



static int myopen(struct inode* pi,struct file* pf)
{
    printk("myopen.\n");
    return 0;
}
static int myrelease(struct inode* pi,struct file* pf)
{
    printk("myrelease.\n");
    return 0;
}



static ssize_t myread(struct file* pf, char __user* rbuf, size_t len, loff_t* pl)
{
    int count = 0;

    printk("myread.\n");
    if(NULL==rbuf)
    {
        printk("wbuf is NULL");
        return -1;
    }
    while(buf[count])
    {
        rbuf[count] = buf[count];
        count++;
    }
    return count;

}
static ssize_t mywrite (struct file* pf, const char __user* wbuf, size_t len, loff_t* pl)
{
    int count = 0;

    printk("mywrite.\n");
    if(NULL==wbuf)
    {
        printk("wbuf is NULL");
        return -1;
    }
    while(wbuf[count])
    {
        buf[count] = wbuf[count];
        count++;
    }
    return count;
}



long myioctl (struct file* pf, unsigned int cmd, unsigned long arg)
{
    switch(cmd)
    {
        case LED_ON:
            printk("LED_ON.\n");
            writel(readl(gpf3dat)|(0x1<<4),gpf3dat);
            break;
        case LED_OFF:
            printk("LED_OFF.\n");
            writel(readl(gpf3dat)&~(0x1<<4),gpf3dat);
            break;
        case ADC_GET:
            //printk("ADC:%d.%dV.\n",adc_getData()*18/4095/10,adc_getData()*18/4095%10);
            return adc_getData();
            break;
        default:
            break;
    }
    return 0;
}

static struct file_operations myfops={
    .open = myopen,
    .release = myrelease,
    .read = myread,
    .write = mywrite,
    .unlocked_ioctl = myioctl,
};

static int myInit(void)
{
    int ret  = 0;
    int cret = 0;
    printk("mod02 init.\n");

    no = MKDEV(MA,MI);//生成唯一dev号
    ret = register_chrdev_region(no,count,name);//注册
    if(ret!=0)
    {
        printk("register failed.\n");
        return ret;
    }
    else
    {
        printk("register success.\n");
    }

    cdev_init(&mydev,&myfops);//cdev初始化

    cret = cdev_add(&mydev,no,count);//cdev添加
    if(cret!=0)
    {
        printk("cdev_add failed.\n");
        unregister_chrdev_region(no,count);//dev注销
        return -cret;
    }
    else
    {
        printk("cdev_add success.\n");
    }



    gpf3con = ioremap(GPF3CON,4);//物理地址映射到虚拟地址
    writel((readl(gpf3con)&~(0xf<<16))|(0x1<<16),gpf3con);//读修改写
    gpf3dat = ioremap(GPF3DAT,4);



    adc_init();
    return 0;
}
static void myExit(void)
{
    cdev_del(&mydev);//cdev删除
    unregister_chrdev_region(no,count);//dev注销
    printk("mod02 exit.\n");
}

module_init(myInit);
module_exit(myExit);

MODULE_LICENSE("GPL");


并发

init exit
file_operation    open,read ... ...
        |                    |        |
     user               open   read

互斥机制

中断屏蔽:只在单cpu下有效
原子操作:操作整型数据
自旋锁:不允许调度,“锁上就解”;解锁的时候,被锁住的任务获得执行效率高
信号量:在锁住的时候,cpu不会被占用,总体性能不会下降;解锁的时候,被锁住的时候不会马上执行,开销大
互斥锁:与信号量差不多

阻塞、非阻塞、异步

阻塞:获取资源,获取不到,一直等待
非阻塞:while(1){获取资源,获取不到,立马next} 轮询
异步通知
等待队列 阻塞

自旋锁

/*驱动*/
#include <linux/sys.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/kdev_t.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/spinlock.h>

#define MA 500
#define MI 0

#define LOCK 2
#define UNLOCK 3

static dev_t no = 0;
static struct cdev mydev;
const char* name = "myDev3";
static int count = 1;
static spinlock_t mylock; 
static char buf[50]={0};

static ssize_t myread(struct file* pf, char __user* rbuf, size_t len, loff_t* pl)
{
    int count = 0;
    if(NULL==rbuf)
    {
        printk("rbuf is NULL");
        return -1;
    }
    if(spin_is_locked(&mylock))
    {
        return LOCK; 
    }
    spin_lock(&mylock);
    count = copy_to_user(rbuf,buf,len);
    spin_unlock(&mylock);
    if(0!=count)
    {
        return -1;
    }
    return count;
}

static ssize_t mywrite (struct file* pf, const char __user* wbuf, size_t len, loff_t* pl)
{
    int count = 0;
    if(NULL==wbuf)
    {
        printk("wbuf is NULL");
        return -1;
    }
    if(spin_is_locked(&mylock))
    {
        return LOCK; 
    }
    spin_lock(&mylock);
    count = copy_from_user(buf,wbuf,len);
    spin_unlock(&mylock);
    if(0!=count)
    {
        return -1;
    }
    return count;
}

static struct file_operations myops={
    .read = myread,
    .write = mywrite,
}; 

static int myinit(void)
{
    int rret = 0;
    int cret = 0;
    printk("init\n");
    no = MKDEV(MA,MI);
    rret = register_chrdev_region(no,count,name);
    if(rret!=0)
    {
        printk("register failed\n");
        return rret;
    }
    else
    {
        printk("register successed\n");
    }
    cdev_init(&mydev,&myops);
    cret = cdev_add(&mydev,no,count);
    if(cret!=0)
    {
        printk("cdev_add failed\n");
        unregister_chrdev_region(no,count);
        return -cret;
    }
    else
    {
        printk("cdev_add successed\n");
    }
    spin_lock_init(&mylock);
    return 0;
}

static void myexit(void)
{
    cdev_del(&mydev);
    unregister_chrdev_region(no,count);
    printk("mod03 exit\n");
    return;
}

module_init(myinit);
module_exit(myexit);

MODULE_LICENSE("GPL");

异步信号

/*驱动*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/delay.h>
#include <linux/sched.h>
#include <linux/poll.h>
#include <asm/uaccess.h>

#define MA 500
#define MI 0
#define MAX_LEN 16

static dev_t no = 0;
static unsigned count = 1;
static const char *name = "mydev";
static struct cdev mydev;
static char kbuf[MAX_LEN] = {0};
static int w = 0;
struct fasync_struct *async_queue = NULL;

static int myopen(struct inode *pi, struct file *pf)
{
    return 0;
}

static int myrelease(struct inode *pi, struct file *pf)
{
    return 0;
}

ssize_t myread(struct file *pf, char __user *ubuf, size_t len, loff_t *poff)
{
    int ret = -1;
    if(len>MAX_LEN)
        return -EINVAL;
    ret = copy_to_user(ubuf,kbuf,len);
    if(0!=ret)
        return -1;
    w = 0;
    return len;
}

ssize_t mywrite(struct file *pf, const char __user *ubuf, size_t len, loff_t *poff)
{
    int ret = -1;
    if(len>MAX_LEN)
        return -EINVAL;
    ret = copy_from_user(kbuf,ubuf,len);
    if(0!=ret)
        return -1;
    w = 1;
    kill_fasync(&async_queue, SIGIO, POLL_IN);
    return len;
}

static int myfasync(int fd, struct file *filp, int mode)
{
	return fasync_helper(fd, filp, mode, &async_queue);
}

static const struct file_operations myops={
    .open = myopen,
    .release = myrelease,
    .read = myread,
    .write = mywrite,
    .fasync = myfasync,
};
    
static int myinit(void)
{
    int ret = -1;
    no = MKDEV(MA,MI);
    ret = register_chrdev_region(no, count, name);
    if(ret != 0)
    {
        printk("register failed.\n");
        return ret;
    }
    cdev_init(&mydev, &myops);
    ret = cdev_add(&mydev,no,count);
    if(ret != 0)
    {
        unregister_chrdev_region(no,count);
        return ret;
    }
    printk("init ok\n");
    return 0;
}

static void myexit(void)
{
    cdev_del(&mydev);
    unregister_chrdev_region(no,count);
    printk("exit ok.\n");
}

module_init(myinit);
module_exit(myexit);

MODULE_LICENSE("GPL");
/*应用*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>

int main(int argc, char *argv[])
{
    int fd = open("dev/mydev",O_RDWR);
    int oflags = 0;
    signal(SIGIO, sig_handler);
    fcntl(fd, F_SETOWN, getpid());//关联设备与进程
    oflags = fcntl(fd, F_GETFL); //获得文件状态标志
    fcntl(fd, F_SETFL, oflags | FASYNC);//设置文件状态标志
    sleep(2);
    write(fd, wbuf, sizeof(wbuf));
    while(1);
    return 0;
} 

平台设备

设备模型:分层分级
4个重要组成: dev drv bus class(设备 驱动 总线 设备类)
要在设备树文件中添加设备相关信息

平台驱动

/*驱动*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/kdev_t.h>
#include <linux/cdev.h>
#include <asm/io.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include "mycmd.h"

#define MA 400
#define MI 0

static dev_t no = 0;
static unsigned count = 1;
const char* name = "myDevLed";
static struct cdev mydev;
static unsigned int* gpf3con = NULL;
static unsigned int* gpf3dat = NULL;

static int myopen(struct inode* pi,struct file* pf)
{
    printk("myopen.\n");
    return 0;
}

static int myrelease(struct inode* pi,struct file* pf)
{
    printk("myrelease.\n");
    return 0;
}

long myioctl (struct file* pf, unsigned int cmd, unsigned long arg)
{
    switch(cmd)
    {
        case LED_ON:
            printk("LED_ON.\n");
            writel(readl(gpf3dat)|(0x1<<4),gpf3dat);
            break;
        case LED_OFF:
            printk("LED_OFF.\n");
            writel(readl(gpf3dat)&~(0x1<<4),gpf3dat);
            break;
        default:
            break;
    }
    return 0;
}

static struct file_operations myfops={
    .open = myopen,
    .release = myrelease,
    .unlocked_ioctl = myioctl,
};

static int myInit(struct platform_device* pdev)
{
    int ret  = 0;
    int cret = 0;
    struct resource* rescon = NULL;
    struct resource* resdat = NULL;
    printk("init.\n");
    no = MKDEV(MA,MI);//生成唯一dev号
    ret = register_chrdev_region(no,count,name);//注册
    if(ret!=0)
    {
        printk("register failed.\n");
        return ret;
    }
    else
    {
        printk("register success.\n");
    }
    cdev_init(&mydev,&myfops);//cdev初始化
    cret = cdev_add(&mydev,no,count);//cdev添加
    if(cret!=0)
    {
        printk("cdev_add failed.\n");
        unregister_chrdev_region(no,count);//dev注销
        return -cret;
    }
    else
    {
        printk("cdev_add success.\n");
    }
    
    rescon = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    resdat = platform_get_resource(pdev, IORESOURCE_MEM, 1);
    gpf3con = ioremap(rescon->start,4);
    gpf3dat = ioremap(resdat->start,4);
    writel((readl(gpf3con)&~(0xf<<16))|(0x1<<16),gpf3con);//读修改写
    return 0;
}

static int myExit(struct platform_device* pdev)
{
    cdev_del(&mydev);//cdev删除
    unregister_chrdev_region(no,count);//dev注销
    printk("exit.\n");
    return 0;
}

#ifdef CONFIG_OF
static const struct of_device_id mydev_of_matches[] = {
	{ .compatible = "fs4412,led", },
	{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, mydev_of_matches);
#endif

static struct platform_driver mydev_driver = {
	.driver	= {
		.name    = "mydevled",
		.owner	 = THIS_MODULE,
		.of_match_table = of_match_ptr(mydev_of_matches),
	},
	.probe   = myInit,
	.remove  = myExit,
};

module_platform_driver(mydev_driver);

MODULE_LICENSE("GPL");

共享内存

/*驱动*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/kdev_t.h>
#include <linux/cdev.h>
#include <asm/io.h>
#include <linux/gfp.h>
#include <linux/mm.h>
#include <linux/slab.h>

#define MA 500
#define MI 0

static dev_t no = 0;
static unsigned count = 1;
const char* name = "myDev02";
static struct cdev mydev;
char* kbuf = NULL;

static int myopen(struct inode* pi,struct file* pf)
{
    printk("myopen.\n");
    return 0;
}

static int myrelease(struct inode* pi,struct file* pf)
{
    printk("myrelease.\n");
    return 0;
}

int mymmap(struct file *pf, struct vm_area_struct *vma)
{
    vma->vm_flags |= VM_IO; 
    vma->vm_flags |= VM_DONTEXPAND |VM_DONTDUMP; 
    if(remap_pfn_range(vma,
                vma->vm_start,
                virt_to_phys(kbuf)>>PAGE_SHIFT,
                vma->vm_end - vma->vm_start,
                vma->vm_page_prot))
    {  
        return -EAGAIN;  
    }  
    return 0;  
}


static struct file_operations myfops={
    .open = myopen,
    .release = myrelease,
    .mmap = mymmap,
};

static int myInit(void)
{
    int ret  = 0;
    int cret = 0;
    printk("init.\n");
    no = MKDEV(MA,MI);//生成唯一dev号
    ret = register_chrdev_region(no,count,name);//注册
    if(ret!=0)
    {
        printk("register failed.\n");
        return ret;
    }
    else
    {
        printk("register success.\n");
    }
    cdev_init(&mydev,&myfops);//cdev初始化
    cret = cdev_add(&mydev,no,count);//cdev添加
    if(cret!=0)
    {
        printk("cdev_add failed.\n");
        unregister_chrdev_region(no,count);//dev注销
        return -cret;
    }
    else
    {
        printk("cdev_add success.\n");
    }
    kbuf = (char*)kmalloc(PAGE_SIZE,GFP_KERNEL);
    return 0;
}

static void myExit(void)
{
    cdev_del(&mydev);//cdev删除
    unregister_chrdev_region(no,count);//dev注销
    printk("exit.\n");
}

module_init(myInit);
module_exit(myExit);

MODULE_LICENSE("GPL");

中断

/*按键中断驱动*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/kdev_t.h>
#include <linux/cdev.h>
#include <asm/io.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/poll.h>
#include <asm/uaccess.h>

#define MA 500
#define MI 0

static dev_t no = 0;
static unsigned count = 1;
const char* name = "myDevKey";
static struct cdev mydev;
struct fasync_struct *async_queue = NULL;

static int myopen(struct inode* pi,struct file* pf)
{
    printk("myopen.\n");
    return 0;
}

static int myrelease(struct inode* pi,struct file* pf)
{
    printk("myrelease.\n");
    return 0;
}

static int myfasync(int fd, struct file *filp, int mode)
{
    return fasync_helper(fd, filp, mode, &async_queue);
}

static struct file_operations myfops={
    .open = myopen,
    .release = myrelease,
    .fasync = myfasync,
};

irqreturn_t handler(int no,void* arg)
{
    printk("key3\n");
    kill_fasync(&async_queue, SIGIO, POLL_IN);
    return IRQ_HANDLED;
}

static int myInit(struct platform_device* pdev)
{
    int ret  = 0;
    int cret = 0;
    int reqret = 0;
    struct resource* resirq = NULL;
    printk("init.\n");
    no = MKDEV(MA,MI);//生成唯一dev号
    ret = register_chrdev_region(no,count,name);//注册
    if(ret!=0)
    {
        printk("register failed.\n");
        return ret;
    }
    else
    {
        printk("register success.\n");
    }
    cdev_init(&mydev,&myfops);//cdev初始化
    cret = cdev_add(&mydev,no,count);//cdev添加
    if(cret!=0)
    {
        printk("cdev_add failed.\n");
        unregister_chrdev_region(no,count);//dev注销
        return -cret;
    }
    else
    {
        printk("cdev_add success.\n");
    }
    resirq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
    reqret = request_irq(resirq->start,handler,resirq->flags,"myirp",NULL);
    return 0;
}

static int myExit(struct platform_device* pdev)
{
    cdev_del(&mydev);//cdev删除
    unregister_chrdev_region(no,count);//dev注销
    printk("exit.\n");
    return 0;
}

#ifdef CONFIG_OF
static const struct of_device_id mydev_of_matches[] = {
	{ .compatible = "fs4412,key", },
	{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, mydev_of_matches);
#endif

static struct platform_driver mydev_driver = {
	.driver	= {
		.name    = "mydevkey",
		.owner	 = THIS_MODULE,
		.of_match_table = of_match_ptr(mydev_of_matches),
	},
	.probe   = myInit,
	.remove  = myExit,
};

module_platform_driver(mydev_driver);

MODULE_LICENSE("GPL");
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值