具体框图

应用层使用 open write 函数,驱动层提供自己的 open write 即可
- 便于管理,使用
file_operations来管理相关函数 - 通过
register_chrdev通知内核 - 入口
- 出口

具体代码如下
驱动代码(led_drv.c)
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/delay.h>
#include <linux/poll.h>
#include <linux/mutex.h>
#include <linux/wait.h>
#include <linux/uaccess.h>
#include <linux/device.h>
#include <asm/io.h>
static int major = 0;
static struct class *led_class;
// registers
// IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 地址:0x02290000 + 0x14
static volatile unsigned int *IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3;
// GPIO5_GDIR 地址:0x020AC004
static volatile unsigned int *GPIO5_GDIR;
//GPIO5_DR 地址:0x020AC000
static volatile unsigned int *GPIO5_DR;
static ssize_t led_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos)
{
char val;
int ret;
// copy_from_user : get data from app
ret = copy_from_user(&val, buf, 1);
// to set gpio register: out 1/0
if (val)
{
/* set gpio to let led on */
*GPIO5_DR &= ~(1<<3);
}
else
{
/* set gpio to let led off */
*GPIO5_DR |= (1<<3);
}
return 1;
}
static int led_open(struct inode *inode, struct file *filp)
{
/* enable gpio5
* configure gpio5_io3 as gpio
* configure gpio5_io3 as output
*/
*IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 &= ~0xf;
*IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 |= 0x5;
*GPIO5_GDIR |= (1<<3);
return 0;
}
static struct file_operations led_fops = {
.owner = THIS_MODULE,
.write = led_write,
.open = led_open,
};
// 入口函数
static int __init led_init(void)
{
printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
major = register_chrdev(0, "xiaodengled", &led_fops);
// ioremap 不能直接使用寄存器的物理地址,必须使用ioremap 映射得到一个虚拟地址
// registers
// IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 地址:0x02290000 + 0x14
IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 = ioremap(0x02290000 + 0x14, 4);
// GPIO5_GDIR 地址:0x020AC004
GPIO5_GDIR = ioremap(0x020AC004, 4);
//GPIO5_DR 地址:0x020AC000
GPIO5_DR = ioremap(0x020AC000, 4);
led_class = class_create(THIS_MODULE, "myled");
device_create(led_class, NULL, MKDEV(major, 0), NULL, "myled"); // /dev/myled
return 0;
}
// 出口函数
static void __exit led_exit(void)
{
iounmap(IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3);
iounmap(GPIO5_GDIR);
iounmap(GPIO5_DR);
device_destroy(led_class, MKDEV(major, 0));
class_destroy(led_class);
unregister_chrdev(major, "xiaodengled");
}
module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");
测试代码(ledtest.c)
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
// ledtest /dev/myled on
// ledtest /dev/myled off
int main(int argc, char **argv)
{
int fd;
char status = 0;
if(argc != 3)
{
printf("Usage: %s <dev> <on|off>\n", argv[0]);
printf(" eg: %s /dev/myled on\n", argv[0]);
printf(" eg: %s /dev/myled off\n", argv[0]);
return -1;
}
// open
fd = open(argv[1], O_RDWR);
if (fd < 0)
{
printf("can not open %s\n", argv[0]);
return -1;
}
// write
if(strcmp(argv[2], "on") == 0)
{
status = 1;
}
write(fd, &status, 1);
return 0;
}
编译后的具体操作
insmod led_drv.kocat /proc/deviceslsmodls /dev/myled -ldmesg | grep led_drv.c
应用程序的用法
板子没有操作 led 的效果图

点灯:./ledtest /dev/myled on

熄灯:./ledtest /dev/myled off


9044

被折叠的 条评论
为什么被折叠?



