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
#define GPF3DAT 0x114001e4
#define ADCCFG 0x10010118
#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:
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);
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);
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 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);
unregister_chrdev_region(no,count);
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);
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);
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 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);
unregister_chrdev_region(no,count);
printk("exit.\n");
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id mydev_of_matches[] = {
{ .compatible = "fs4412,led", },
{ }
};
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);
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);
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 success.\n");
}
kbuf = (char*)kmalloc(PAGE_SIZE,GFP_KERNEL);
return 0;
}
static void myExit(void)
{
cdev_del(&mydev);
unregister_chrdev_region(no,count);
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);
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);
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 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);
unregister_chrdev_region(no,count);
printk("exit.\n");
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id mydev_of_matches[] = {
{ .compatible = "fs4412,key", },
{ }
};
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");