#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h> //for MKDEV register_chrdev_region
#include <linux/cdev.h> //字符设备头文件
#include <asm/io.h>
#define LED_MA 500 //主设备号 用于区分不同种类的设备
//某些主设备号已经静态地分配给了大部分公用设备。见Documentation/devices.txt 。
#define LED_MI 0 //次设备号 用于区分同一类型的多个设备
#define LED_NUM 1 //设备个数
//注: 内核驱动里不能直接访问硬件地址,所以需要映射成内核虚地址,间接的访问
// *(unsigned int *)LED3_CON =0x01;
// *(unsigned int *)LED3_DAT =1;
struct cdev led; //定义字符设备
static struct mutex lock; //定义互斥体
/*LED实际的物理地址*/
#define LED2_CON 0x11000c40
#define LED2_DAT 0x11000c44
#define LED3_CON 0X11000C20
#define LED3_DAT 0X11000C24
#define LED4_CON 0x114001E0
#define LED4_DAT 0x114001E4
/*ioremap映射后的地址*/
unsigned int *led2con=NULL;
unsigned int *led2dat=NULL;
unsigned int *led3con=NULL;
unsigned int *led3dat=NULL;
unsigned int *led4con=NULL;
unsigned int *led4dat=NULL;
/*实现文件的open操作*/
int led_open(struct inode * inode, struct file *file)
{
mutex_lock(&lock); //加锁
printk("led_open ok\n");
return 0;
}
/*实现文件的release(close)操作*/
int led_release(struct inode * inode, struct file *file)
{
mutex_unlock(&lock); //解锁
printk(" led release ok\n");
return 0;
}
/*幻数*/
#define LED_MAGIC 'l'
#define LED2_ON _IOW(LED_MAGIC,0,int)
#define LED2_OFF _IOW(LED_MAGIC,1,int)
#define LED3_ON _IOW(LED_MAGIC,2,int)
#define LED3_OFF _IOW(LED_MAGIC,3,int)
#define LED4_ON _IOW(LED_MAGIC,4,int)
#define LED4_OFF _IOW(LED_MAGIC,5,int)
/*ioctl 实现定制个性化的命令*/
long led_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
// printk(" led_ioctl go\n");
switch(cmd)
{
case LED2_ON:
writel((readl(led2dat)& (~(0x1 << 7))) | (0x1<<7),led2dat);
break;
case LED2_OFF:
writel(readl(led2dat)&(~(0x1<<7)),led2dat);
break;
case LED3_ON:
writel((readl(led3dat)& (~(0x1 << 0))) | (0x1<<0),led3dat);
break;
case LED3_OFF:
writel(readl(led3dat) &(~(0x1<<0)),led3dat);
break;
case LED4_ON:
writel((readl(led4dat)& (~(0x1 << 4))) | (0x1<<4),led4dat);
break;
case LED4_OFF:
writel(readl(led4dat)&(~(0x1<<4)),led4dat);
break;
default:
printk(" no found cmd = %d\n",cmd);
break;
}
return 0;
}
/*设备的文件操作函数指针结构体*/
struct file_operations led_fps={
.open = led_open,
.release = led_release,
.unlocked_ioctl = led_ioctl,
};
int led_init(void)
{
//1.注册设备号
dev_t devno = MKDEV(LED_MA, LED_MI); //把主次设备号合并生成设备ID
int ret=0;
ret =register_chrdev_region(devno, LED_NUM, "newled"); //注册设备号
if(ret<0){
printk("register cdev error\n");
return -1;
}
//2.初始化字符设备
cdev_init(&led,&led_fps); //将设备和文件操作关联起来
ret = cdev_add(&led, devno, LED_NUM); //添加字符设备到系统中
if(ret<0){
printk("cdev_add error\n");
return -1;
}
/*把物理地址映射为内核虚地址*/
led2con =ioremap(LED2_CON,4);
if(led2con == NULL){
printk("ioremap led2con error\n");
return -1;
}
led2dat =ioremap(LED2_DAT,4);
if(led2dat == NULL){
printk("ioremap led2dat error\n");
return -1;
}
led3con =ioremap(LED3_CON,4);
if(led3con == NULL){
printk("ioremap led3con error\n");
return -1;
}
led3dat =ioremap(LED3_DAT,4);
if(led3dat == NULL){
printk("ioremap led3dat error\n");
return -1;
}
led4con =ioremap(LED4_CON,4);
if(led4con == NULL){
printk("ioremap led4con error\n");
return -1;
}
led4dat =ioremap(LED4_DAT,4);
if(led4dat == NULL){
printk("ioremap led4dat error\n");
return -1;
}
/*设置寄存器初值,初始化寄存器*/
writel((readl(led2con)& (~(0xf<<28))) | (0x1<<28),led2con);
writel((readl(led3con)& (~(0xf<<0))) | (0x1<<0),led3con);
writel((readl(led4con)& (~(0xf<<16))) | (0x1<<16),led4con);
mutex_init(&lock);//初始化互斥体
printk("led init go mutex\n");
return 0;
}
void led_exit(void)
{
//注意: 申请资源要与释放资源相配对
dev_t devno = MKDEV(LED_MA, LED_MI);
iounmap(led2con);
iounmap(led2dat);
iounmap(led3con);
iounmap(led3dat);
iounmap(led4con);
iounmap(led4dat); //取消映射
cdev_del(&led); //删除设备
unregister_chrdev_region(devno, LED_NUM); //取消注册
printk("led exit go\n");
}
module_init(led_init); //模块加载入口声明
module_exit(led_exit); //模块卸载入口声明
MODULE_LICENSE("Dual BSD/GPL"); //免费开源 许可声明
led字符设备驱动
最新推荐文章于 2022-12-01 10:56:19 发布