是一个char字符类型的驱动
//配置模式为输出端口
static unsigned int led_cfg_table [] = {
S3C2410_GPB5_OUTP,
S3C2410_GPB6_OUTP,
S3C2410_GPB7_OUTP,
S3C2410_GPB8_OUTP,
};
s3c2410_gpio_cfgpin(S3C2410_GPB5, S3C2410_GPB5_OUTP);
s3c2410_gpio_cfgpin(37, 0x01 << 10);
这个在\arch\arm\mach-s3c2410\include\mach\regs-gpio.h中定义
#define S3C2410_GPB5 S3C2410_GPIONO(S3C2410_GPIO_BANKB, 5)
#define S3C2410_GPB5_INP (0x00 << 10)
#define S3C2410_GPB5_OUTP (0x01 << 10)
#define S3C2410_GPB5_nXBACK (0x02 << 10)
S3C2410_GPIONO(S3C2410_GPIO_BANKB, 5)
#define S3C2410_GPIONO(bank,offset) ((bank) + (offset))
#define S3C2410_GPIO_BANKA (32*0)
#define S3C2410_GPIO_BANKB (32*1)
static int __init dev_init(void)
{
int ret;
int i;
for (i = 0; i < 4; i++) {
s3c2410_gpio_cfgpin(led_table[i], led_cfg_table[i]);
s3c2410_gpio_setpin(led_table[i], 0);
}
在驱动的初始化函数中经常看到,__init 前缀, 这个在下面文件中定义
file:/include/linux/init.h
· /* These macros are used to mark some functions or
· * initialized data (doesn't apply to uninitialized data)
· * as `initialization' functions. The kernel can take this
· * as hint that the function is used only during the initialization
· * phase and free up used memory resources after
· *
· * Usage:
· * For functions:
· *
· * You should add __init immediately before the function name, like:
· *
· * static void __init initme(int x, int y)
· * {
· * extern int z; z = x * y;
· * }
主要是将这个函数放在init段section中,这样可以在执行完成后,释放内存。
void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int function)
{
void __iomem *base = S3C24XX_GPIO_BASE(pin);
unsigned long mask;
unsigned long con;
unsigned long flags;
if (pin < S3C2410_GPIO_BANKB) {
mask = 1 << S3C2410_GPIO_OFFSET(pin);
} else {
mask = 3 << S3C2410_GPIO_OFFSET(pin)*2; //3<<(37*2)
}
switch (function) {
case S3C2410_GPIO_LEAVE:
mask = 0;
function = 0;
break;
case S3C2410_GPIO_INPUT:
case S3C2410_GPIO_OUTPUT:
case S3C2410_GPIO_SFN2:
case S3C2410_GPIO_SFN3:
if (pin < S3C2410_GPIO_BANKB) {
function -= 1;
function &= 1;
function <<= S3C2410_GPIO_OFFSET(pin);
} else {
function &= 3;
function <<= S3C2410_GPIO_OFFSET(pin)*2;
}
}
/* modify the specified register wwith IRQs off */
local_irq_save(flags);
con = __raw_readl(base + 0x00);
con &= ~mask;
con |= function;
__raw_writel(con, base + 0x00);
local_irq_restore(flags);
}
#define S3C24XX_GPIO_BASE(x) S3C2410_GPIO_BASE(x)
#define S3C2410_GPIO_BASE(pin) ((((pin) & ~31) >> 1) + S3C24XX_VA_GPIO)
S3C24XX_VA_GPIO这个在\arch\arm\plat-s3c24xx\include\plat\map.h中定义,这个是Memory Map的定义:
#define S3C2410_PA_GPIO (0x56000000)
#define S3C24XX_VA_GPIO ((S3C24XX_PA_GPIO - S3C24XX_PA_UART) + S3C24XX_VA_UART)
#define S3C24XX_SZ_GPIO SZ_1M
其中PA表示Physical Address,VA表示Virtual Address
由pdf中的GPIO的定义可以看出是一致的。
/* UARTs */
#define S3C24XX_VA_UART S3C_VA_UART
#define S3C2410_PA_UART (0x50000000)
#define S3C_VA_UART S3C_ADDR(0x01000000) /* UART */
#define S3C_ADDR(x) (S3C_ADDR_BASE + (x))
#define S3C_ADDR_BASE (0xF4000000)
__iomem是2.6.9中加入的特性。是用来个表示指会指向一个I/O的内存空间。主要是为了driver的通用性考虑。由于不同的CPU体系结构对 I/O空间的表示可能不同。当使用__iomem时,compiler会忽略对变量的检查(因为用的是void __iomem)。但sparse会对它进行检查,当__iomem的指针和正常的指针混用时,就会发出一些warnings
有个地方讲不通:(这个地方应该是都不满足switch的条件,所以,function不改变)
#define S3C2410_GPIO_LEAVE (0xFFFFFFFF)
#define S3C2410_GPIO_INPUT (0xFFFFFFF0) /* not available on A */
#define S3C2410_GPIO_OUTPUT (0xFFFFFFF1)
#define S3C2410_GPIO_IRQ (0xFFFFFFF2) /* not available for all */
#define S3C2410_GPIO_SFN2 (0xFFFFFFF2) /* bank A => addr/cs/nand */
#define S3C2410_GPIO_SFN3 (0xFFFFFFF3) /* not available on A */
而
#define S3C2410_GPB5_OUTP (0x01 << 10)
所以,
s3c2410_gpio_cfgpin(S3C2410_GPB5, S3C2410_GPB5_OUTP);
switch (function)
根本对不上号?
#define __raw_readl(p) (*(unsigned long *)(p))
#define __raw_writel(v,p) (*(unsigned long *)(p) = (v))
*******************************
static struct miscdevice misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = DEVICE_NAME,
.fops = &dev_fops,
};
驱动注册时,如果次号指定MISC_DYNAMIC_MINOR,则进行动态分配。
#define DEVICE_NAME "leds"
include\linux
在这个头文件中主要是misc(混合)设备注册和注销:
其它类型---不能严格划分的设备类型,也叫混合类型
有:
1.
结构体:
struct miscdevice {
int minor;
const char *name;
const struct file_operations *fops;
struct list_head list;
struct device *parent;
struct device *this_device;
};
2.
misc设备注册:
extern int misc_register(struct miscdevice * misc);
misc设备注销:
extern int misc_deregister(struct miscdevice * misc);
说明:上面的结构体是注册混合设备所需要的参数。主要有:
minor:次设备号,所有的misc设备共用一个主设备号,所以注册misc设备时只要次设备号就可以了。利用次设备号来区分设备的。
name:misc设备名。
*fops:misc设备文件操作结构体。
其它三个参数很少用。
杂项设备(misc device)
杂项设备也是在嵌入式系统中用得比较多的一种设备驱动。在 Linux 内核的include\linux目录下有Miscdevice.h文件,要把自己定义的misc device从设备定义在这里。其实是因为这些字符设备不符合预先确定的字符设备范畴,所有这些设备采用主编号10 ,一起归于misc device,其实misc_register就是用主标号10调用register_chrdev()的。
也就是说,misc设备其实也就是特殊的字符设备,可自动生成设备节点。
module_init(dev_init);
module_exit(dev_exit);
参考:http://blog.csdn.net/zhandoushi1982/archive/2009/12/02/4927579.aspx