JZ2440字符设备驱动

建议看看大神嵌入式linux系统的路径规划与经验分享(干货满满)_嵌入式推理能进行路径规划吗-优快云博客

先从框架入手学习。

1、模块加载卸载

static int __init led_init(void)
{

    return 0;
}

static void __exit led_exit(void)
{

    return 0;
}

module_init(led_init);
module_exit(led_exit);

MODULE_LICENSE("GPL");

2、注册注销字符设备

static struct file_operations leds_fops;

static int __init led_init(void)
{
    register_chrdev(250, "anyname", &leds_fops);
    return 0;
}

static void __exit led_exit(void)
{
    unregister_chrdev(250, "anyname");
    return 0;
}

module_init(led_init);
module_exit(led_exit);

MODULE_LICENSE("GPL");

insmod后(使用modprobe没成功,先不管能用就行),cat /proc/devices查看有anyname设备名字和设备号250。

3、丰富file_operations leds_fops的操作函数(基本功能:打开关闭读写)

static int leds_open(struct inode *inode, struct file *filp) 
{  
	return 0; 
} 

static ssize_t leds_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt) 
{ 
	return 0; 
} 

static ssize_t leds_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt) 
{ 
	return 0; 
}

static int leds_release(struct inode *inode, struct file *filp) 
{ 
	return 0; 
}

static struct file_operations leds_fops = {
    .owner = THIS_MODULE, 
    .open = leds_open, 
    .read = leds_read, 
    .write = leds_write, 
    .release = leds_release,
};

static int __init led_init(void)
{
    register_chrdev(250, "anyname", &leds_fops);
    return 0;
}

static void __exit led_exit(void)
{
    unregister_chrdev(250, "anyname");
    return 0;
}

module_init(led_init);
module_exit(led_exit);

MODULE_LICENSE("GPL");

4、更改驱动为动态分配设备号

static int leds_open(struct inode *inode, struct file *filp) 
{  
	return 0; 
} 

static ssize_t leds_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt) 
{ 
	return 0; 
} 

static ssize_t leds_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt) 
{ 
	return 0; 
}

static int leds_release(struct inode *inode, struct file *filp) 
{ 
	return 0; 
}

static struct file_operations leds_fops = {
    .owner = THIS_MODULE, 
    .open = leds_open, 
    .read = leds_read, 
    .write = leds_write, 
    .release = leds_release,
};



dev_t devid;
struct cdev cdev;

static int __init led_init(void)
{
    alloc_chrdev_region(&devid, 0, 1, "leds");
    cdev.owner = THIS_MODULE; 
    cdev_init(&cdev, &leds_fops);   
    cdev_add(&cdev, devid, 1);

    return 0;
}

static void __exit led_exit(void)
{
    cdev_del(&cdev);
    unregister_chrdev_region(devid, 1);
    return 0;
}

module_init(led_init);
module_exit(led_exit);

MODULE_LICENSE("GPL");

5、自动生成设备文件(等同于手动mknod)

static int leds_open(struct inode *inode, struct file *filp) 
{  
	return 0; 
} 

static ssize_t leds_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt) 
{ 
	return 0; 
} 

static ssize_t leds_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt) 
{ 
	return 0; 
}

static int leds_release(struct inode *inode, struct file *filp) 
{ 
	return 0; 
}

static struct file_operations leds_fops = {
    .owner = THIS_MODULE, 
    .open = leds_open, 
    .read = leds_read, 
    .write = leds_write, 
    .release = leds_release,
};



dev_t devid;
struct cdev cdev;

struct class *class;
struct device *device;

static int __init led_init(void)
{
    alloc_chrdev_region(&devid, 0, 1, "leds");
    cdev.owner = THIS_MODULE; 
    cdev_init(&cdev, &leds_fops);   
    cdev_add(&cdev, devid, 1);

    class = class_create(THIS_MODULE, "leds");
    device = device_create(class, NULL, devid, NULL, "leds");

    return 0;
}

static void __exit led_exit(void)
{
    cdev_del(&cdev);
    unregister_chrdev_region(devid, 1);

    device_destroy(class, devid); 
    class_destroy(class);

    return 0;
}

module_init(led_init);
module_exit(led_exit);

MODULE_LICENSE("GPL");

6、初始化设备

注意:(1)不能直接操作寄存器物理地址,要用ioremap虚拟化成虚拟地址;

           (2)不能直接操作虚拟地址,要使用内核函数readl、writel等;

           (3)对寄存器的操作遵循“读-改-写”。

#define GPF_CONTROL_ADDR  0x56000050
#define GPF_DATA_ADDR  0x56000050
static void __iomem *gpfcon;
static void __iomem *gpfdat;

static int leds_open(struct inode *inode, struct file *filp) 
{  
	return 0; 
} 

static ssize_t leds_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt) 
{ 
    unsigned char readbuf[100];
    copy_to_user(buf, readbuf, cnt);
	return 0; 
} 

static ssize_t leds_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt) 
{ 
    unsigned char writebuf[100];
    copy_from_user(writebuf, buf, cnt);
	return 0; 
}

static int leds_release(struct inode *inode, struct file *filp) 
{ 
	return 0; 
}

static struct file_operations leds_fops = {
    .owner = THIS_MODULE, 
    .open = leds_open, 
    .read = leds_read, 
    .write = leds_write, 
    .release = leds_release,
};



dev_t devid;
struct cdev cdev;

struct class *class;
struct device *device;

static int __init led_init(void)
{

    gpfcon = ioremap(GPF_CONTROL_ADDR, 4);
	gpfdat = ioremap(GPF_DATA_ADDR, 4);

    val = readl(gpfcon);
	val &= ~(3<<(4*2) | 3<<(5*2) | 3<<(6*2));
	val |= 1<<(4*2)| 1<<(5*2)| 1<<(6*2);
	writel(val, gpfcon);


    alloc_chrdev_region(&devid, 0, 1, "leds");
    cdev.owner = THIS_MODULE; 
    cdev_init(&cdev, &leds_fops);   
    cdev_add(&cdev, devid, 1);

    class = class_create(THIS_MODULE, "leds");
    device = device_create(class, NULL, devid, NULL, "leds");

    return 0;
}

static void __exit led_exit(void)
{
    iounmap(gpfcon);
    iounmap(gpfdat);

    cdev_del(&cdev);
    unregister_chrdev_region(devid, 1);

    device_destroy(class, devid); 
    class_destroy(class);

    return 0;
}

module_init(led_init);
module_exit(led_exit);

MODULE_LICENSE("GPL");

7、Makefile:

KERNELDIR := /home/embedfire/linux/afeng/linux-4.19-rc3

CURRENT_PATH :=$(shell pwd)

all:
        $(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules


clean:
        $(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules clean

obj-m += leds_drv.o

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值