Chinaunix首页 | 论坛 | 博客
  • 博客访问: 251459
  • 博文数量: 81
  • 博客积分: 325
  • 博客等级: 一等列兵
  • 技术积分: 595
  • 用 户 组: 普通用户
  • 注册时间: 2012-03-17 21:00
文章分类
文章存档

2016年(2)

2013年(33)

2012年(47)

我的朋友

分类:

2012-11-28 22:06:58

原文地址:s3c6410_leds.c驱动分析 作者:zhongli_i

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驱动,自己写应用程序玩了。


阅读(890) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~