1.#include
miscdevice表示混杂设备。这里把LED定义为杂项设备的一个从设备,需要在这个头文件注册及注销,虽然也是字符设备,但不符合预先确定的字符设备范畴。misc device的主设备号均为10。
struct device;
struct miscdevice {
int minor; //次设备号
const char *name; //设备名称
const struct file_operations *fops; //设备的file_operations
struct list_head list; //链表
struct device *parent;
struct device *this_device;
const char *nodename;
mode_t mode;
};
extern int misc_register(struct miscdevice * misc); //注册杂项设备
extern int misc_deregister(struct miscdevice *misc);//注销杂项设备
在s3c6410_leds.c中
static struct miscdevice misc = {
.minor = MISC_DYNAMIC_MINOR, // =255
.name = DEVICE_NAME, // leds
.fops = &dev_fops,
};
在init函数中用ret = misc_register(&misc);注册设备。
2.#include
这个头文件起初没找到路径到底在哪里。
后面看到不是在include/mach/hardware.h中,而是/arch/arm/mach-s3c64xx/include/mach/目录下。
内核编译驱动时会在对应的体系结构下的include目录下寻找头文件。
只定义了一个头文件 #define __ASM_ARCH_HARDWARE_H __FILE__
3.ioctl函数
static long s3c6410_leds_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{ //cmd表示传送的命令 arg为第几个灯。
switch(cmd) {
unsigned tmp;
case 0:
case 1:
if (arg > 4)
{ //只有四盏灯 0、1、2、3
return -EINVAL;
}
//从IO读取32位数据到地址S3C64XX_GPMDAT
tmp = readl(S3C64XX_GPMDAT);
//这三个寄存器的地址定义为
//#define S3C64XX_GPMCON (S3C64XX_GPM_BASE + 0x00)
//#define S3C64XX_GPMDAT (S3C64XX_GPM_BASE + 0x04)
//#define S3C64XX_GPMPUD (S3C64XX_GPM_BASE + 0x08)
//#define S3C64XX_GPM_BASE S3C64XX_GPIOREG(0x0820)
//#define S3C64XX_VA_GPIO S3C_ADDR_CPU(0x00000000)
//可以算出要读取或者写入的地址就是寄存器的物理地址。S3C64XX_GPM_BASE为0x7F008820
if(cmd==0) //close light
{
tmp &= (~(1<
}
else //open light
{
tmp |= (1<
}
writel(tmp,S3C64XX_GPMDAT);
printk (DEVICE_NAME": %d %d\n", arg, cmd);
return 0;
default:
return -EINVAL;
}
}
还需要注意一点的是2.6内核的ioctl与2.4内核的ioctl不同,2.6内核中,ioctl的原型为
long (* unlocked_ioctl)(struct *file,unsigned int,unsigned long);
在file_operations中,需定义为.unlocked_ioctl= s3c6410_leds_ioctl。应用层中调用仍为ioctl()。
4.初始化函数
static int __init dev_init(void)
{
int ret;
unsigned tmp;
//gpm0-3 pull up
tmp = readl(S3C64XX_GPMPUD); //从IO口读32位数据到錿mp 参数为地址
tmp &= (~0xFF);//GPMPUD物理地址0x7F008828
tmp |= 0xaa;//使能上拉电阻
writel(tmp,S3C64XX_GPMPUD);
//gpm0-3 output mode GPM配置寄存器
tmp =readl(S3C64XX_GPMCON);
tmp &= (~0xFFFF);
tmp |= 0x1111; //设置为输出模式
writel(tmp,S3C64XX_GPMCON);
//gpm0-3 output 0
tmp = __raw_readl(S3C64XX_GPMDAT);
tmp |= 0x10;//输出数据00010000
writel(tmp,S3C64XX_GPMDAT);
//注册杂项字符设备
ret = misc_register(&misc);//不用手动创建节点
printk (DEVICE_NAME"\tinitialized\n");
return ret;
}
5.注销
static void __exit dev_exit(void)
{
misc_deregister(&misc);//注销杂项字符设备
}
我的这个驱动程序是直接被编译进内核,开发板启动以后不用创建设备节点,可以在应用程序中打开/dev/leds即可以访问驱动。
我的开发板目前还是不能加载我自己编译的驱动,虽然我已经重新编译内核,并且把LED GPIO support部分去掉,但还是不行,查看/dev目录下面也有leds设备节点。不明白怎么回事。
现在只能用自带的这个LED驱动,自己写应用程序玩了。
阅读(4684) | 评论(2) | 转发(1) |