第12课第2.3节 字符设备驱动程序之LED驱动程序_操作LED(四)
写一个点LED的驱动:
一、框架
二、完善、硬件的操作:
a.看原理图、确定引脚;
b.看2440手册;
c.写代码:
单片机:操作物理地址
驱动:用ioremap函数来映射虚拟地址
★★★
void *ioremap(unsigned long phys_addr, unsigned long size)
phys_addr:要映射的物理地址
size:要映射的长度,单位是字节
ioremap是以页为单位进行映射,你的长度写为4,16,32等等,都会映射到4096字节的空间。
★★★
下面的代码中:
gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16);
gpfdat = gpfcon + 1;
①先映射GPFCON为虚拟地址。F寄存器为GPFCON:0x56000050,GPFDAT:0x56000054,GPFUP:0x56000058,Reserved:0x5600005c共4个,2440为32位CPU,所以4个4字节为16字节,故这里映射16字节。
②gpfdat=gpfcon+1;这里指针加1是以上面"unsigned long "为单位的。unsigned long的字节数是4个字节。
驱动程序first_drv.c
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
static struct class *firstdrv_class; //一个类
static struct class_device *firstdrv_class_dev; //一个类里面再建立一个设备
volatile unsigned long *gpfcon = NULL;
volatile unsigned long *gpfdat = NULL;
static int first_drv_open(struct inode *inode, struct file *file)
{
//printk("first_drv_openn");
/* 配置GPF4,5,6为输出 */
*gpfcon &= ~((0x3<
*gpfcon |= ((0x1<
return 0;
}
static ssize_t first_drv_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
{
int val;
//printk("first_drv_writen");
//用户程序传进来的值,怎样才能取得到,用户空间-》内核空间
copy_from_user(&val, buf, count); // copy_to user()
if (val == 1)
{
//点灯
*gpfdat &= ~((1<<4) | (1<<5) | (1<<6));
}
else
{
//灭灯
*gpfdat |= (1<<4) | (1<<5) | (1<<6);
}
return 0;
}
static struct file_operations first_drv_fops = {
.owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
.open = first_drv_open,
.write = first_drv_write,
};
int major;
/*
在VFS(虚拟文件系统)中实际是用一个数组来管理文件,而这个数组就是以主设备号作为索引
在注册驱动的时候,register_chrdev函数会按照major作为索引在对应位置填入file_operation
*/
int first_drv_init(void)
{
//第一个参数写0:让系统给我们自动分配,在数组中找个空缺,返回主设备号
major = register_chrdev(0, "first_drv", &first_drv_fops); //注册驱动程序,告诉内核
/* 下面这两条信息就会在sys目录下,建立firstdrv这个类,再firstdrv这个类下,会创建xyz这个设备 */
/* 然后mdev就会创建/dev/xyz这个节点 */
//创建一个类
firstdrv_class = class_create(THIS_MODULE, "firstdrv");
//在这个类下面再创建一个设备
firstdrv_class_dev = class_device_create(firstdrv_class, NULL, MKDEV(major, 0), NULL, "xyz");
//映射:物理地址->虚拟地址
gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16); //指向的是虚拟地址,第一个参数是物理开始地址,第二个是长度(字节)
gpfdat = gpfcon + 1; //加1,实际加4个字节
return 0;
}
void first_drv_exit(void)
{
unregister_chrdev(major, "first_drv"); //卸载驱动
class_device_unregister(firstdrv_class_dev);
class_destroy(firstdrv_class);
iounmap(gpfcon);
}
module_init(first_drv_init);
module_exit(first_drv_exit);
MODULE_LICENSE("GPL");
用户程序firstdevtest.c
#include
#include
#include
#include
/* firstdrvtest on 打开
* firstdrvtest off 熄灯
*/
int main(int argc, char **argv)
{
int fd;
int val = 1;
fd = open("/dev/xyz", O_RDWR);
if (fd < 0)
{
printf("can't open!n");
}
//argc:传进来参数的个数
if (argc != 2)
{
printf("Usage :n"); //Usage用法不对
//在linux,<>尖括号表示参数不能省略,|或符号表示任选一个(on或者off)
printf("%s
return 0;
}
//第二个参数 等于 on
if (strcmp(argv[1], "on") == 0)
{
val = 1;
}
else
{
val = 0;
}
write(fd, &val, 4);
return 0;
}
『本文转载自网络,版权归原作者所有,如有侵权请联系删除』