Linux驱动程序--虚拟平台总线


虚拟平台总线:
虚拟平台总线(platform bus)是总线模型的一种,由系统定义了总线类型platform_bus_type,并对驱动和设备进行了封装;

相关头文件:

#include <linux/platform_device.h>

设备资源: plat_device.c

1.定义用到的资源

/*************** 以下是平台设备(资源) ***************/
static struct resource device_resource[] = {
    [0]={
        .start = S3C24XX_PA_GPIO,    //MEM类表示的是起始物理地址
        .end   = S3C24XX_PA_GPIO + S3C24XX_SZ_GPIO - 1,
        .flags = IORESOURCE_MEM,     // 存储器(寄存器)资源
    },
    
    [1]={
        .start = IRQ_EINT8,
        .end   = IRQ_EINT8,
        .flags = IORESOURCE_IRQ,    // 中断资源
    },
 
    [2]={
        .start = 164,               // GPIO(164)~GPIO(167)
        .end   = 167,
        .flags = IORESOURCE_IO,     // IO资源
    },
};

2.注册虚拟平台设备

static struct platform_device *plat_device;
plat_device = platform_device_alloc("buttons",-1);    
platform_device_add_resources(plat_device ,&device_resource ,2);
platform_device_register(plat_device);

3.删除虚拟平台设备:

platform_device_unregister(plat_device);

注意事项:
1.platform_device_alloc动态分配的资源,删除时要释放(platform_device_unregister函数已做处理),也可以采用静态指定的方法实现;

2.platform_device_register/platform_device_add函数,
platform_device_register注册设备时,在函数的最后调用了platform_device_add;


驱动程序:plat_driver.c

/****************** 以下是平台驱动 ******************/
/*平台驱动定义*/
static struct platform_driver  plat_driver  = {
    .probe      = plat_probe,    //加载驱动时要执行的程序
    .remove     = plat_remove,   //删除驱动时要执行的程序
    .driver     = {              //struct device_driver
        .owner  = THIS_MODULE,
        .name   = "buttons",     //这里的名子要和平台的device的名子匹配
    },
};

注册驱动:

platform_driver_register(&plat_driver);

卸载驱动

platform_driver_unregister(&plat_driver);

实现probe函数:

static int plat_probe(struct platform_device *pdev)
{
    
}

实现remove函数:

static int plat_remove(struct platform_device *pdev)
{

}

获取资源(在probe函数中调用):

struct resource *res_irq;
res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);    
if (!res_irq) {
    printk("platform_get_resource fail\n");
    return -1;
}
    
struct resource *res_mem;
res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);    
if (!res_mem) {
    printk("platform_get_resource fail\n");
    return -1;
}

参数1: 匹配设备,由probe参数中传入;
参数2:设备类型,在device的资源flag中定义;
参数3:资源序号,用于区分多个类型相同的资源,下标从0开始;不同资源序号无关联,本例中IORESOURCE_IRQ只有一个,所以序号为0(多个连续的资源在一个结构中算1个资源);

返回值: 如果获取成功,则返回相关结构体,获取失败返回空指针;


工作机理:
当加载设备(驱动)时,内核自动遍历一遍该该总线驱动(设备);
如果匹配成功,内核就会调用driver中的probe函数;
设备和驱动的加载先后顺序无关;
当加载设备(驱动)时,内核就会调用driver中定义的remove函数;


注意事项:
1.模块必须声明为GPL,否则模块加载时内核会报怨找不到符号;
2.platform平台驱动本身不会产生设备文件,需要在probe函数中自行实现;
3.通过/sys/bus/platform/device中查看平台设备,名子与.name定义相同
4.通过/sys/bus/platform/driver中查看驱动程序,名子与.name定义相同
5.在3.0(或者更前一些,无须考证了)以后的版本中platform_device.h添加了宏定义module_platform_driver用于自动添加平台总线模块,以省去module_init/module_exit等繁杂操作;

module_platform_driver(&plat_driver);

在后续的内核版本中,platform总线已经用的淋(xiang)漓(dang)尽(fan)致(lan)了;

- 阅读全文 -

Linux驱动程序--GPIO配置及应用


文章摘要:
General Purpose Input Output(通用输入输出),Linux在新的内核中对GPIO接口进行了统一管理,对于不同平台的普通的IO操作,不需要单独的写驱动程序。
硬件平台: SMDK2410
内核版本: 2.6.38


内核配置选项:

Device Drivers --->
    GPIO Support --->
         [*] /sys/class/gpio/... (sysfs interface)  

配置后的内核,会产生/sys/class/gpio目录。


查看系统GPIO信息:

$ cd /sys/class/gpio
$ for i in gpiochip* ; do echo `cat $i/label`: `cat $i/base` ; done
GPIOA: 0
GPIOE: 128
GPIOF: 160
GPIOG: 192
GPIOH: 224
GPIOB: 32
GPIOC: 64
GPIOD: 96

计算引脚编号:
GPB0 = GPIOB + 0 = 32 + 0 = 32;
GPF4 = GPIOF + 4 = 160 + 4 = 164;

依次类推,实际上所有引脚是按顺序排列的。

导出引脚:

#echo 164 > /sys/class/gpio/export

操作说明:该操作在/sys/class/gpio目录下产生一个gpio164的链接;

移除引脚:

#echo 164 > /sys/class/gpio/unexport

配置引脚:

方向配置(输入/输出): 修改direction属性.

#echo "output" > /sys/class/gpio/gpio164/direction

input - 输入;
output - 输出。

中断配置:修改edge属性.

#echo "rising" > /sys/class/gpio/gpio164/edge

none - 表示引脚为普通输入,不是中断引脚;
rising - 表示引脚为中断输入,上升沿触发;
falling - 表示引脚为中断输入,下降沿触发;
both - 表示引脚为中断输入,双边沿触发。

读写操作:读取/修改value属性.

#echo -n 0 > /sys/class/gpio/gpio164/value
#echo -n 1 > /sys/class/gpio/gpio164/value
#cat /sys/class/gpio/gpio164/value

文件操作:
适用于应用程序访问:

fd = open("/sys/class/gpio/gpio164/value", O_RDWR);
write(fd,"0",1);
read(fd,buf,1);

GPIO驱动程序相关操作:

申请GPIO
gpio_request();
释放GPIO
gpio_free();

设置GPIO为输出
gpio_direction_output();
设置GPIO为输入
gpio_direction_input();

获取GPIO值
gpio_get_value();
设置GPIO值
gpio_set_value();

通过GPIO端口号查询中断号
gpio_to_irq();
成功返回对应中断号,失败(非中断引脚)返回NULL

通过中断号查询端口号
irq_to_gpio();

注意事项:
GPIO操作被声明为GPL导出,所以如果用到相关操作;
必须在模块中显示的声明为GPL模块,否则,编译器会报怨找不到相关符号;
一般模块都会声明为GPL,不过调试时往往会不记得加这些声明;
函数声明在linux/gpio.h
函数实现在driver/gpio/gpiolib.c

- 阅读全文 -

Linux驱动程序--AT24Cxx


文章摘要: 本文介绍了基于Linux的AT24C02驱动及应用程序。
内核版本: 2.6.38
硬件平台: SMDK2410


1.添加驱动程序
AT24Cxx驱动程序已经位于板级驱动中,只需要进行简单配置即可:

Misc devices  --->   
    EEPROM support  --->
        <*> I2C EEPROMs / RAMs / ROMs from most vendors 

当然前提是要添加I2C支持:

[*] I2C Support->

2.添加板级支持
在 arch/arm/mach-s3c24xx/mach-smdk2410.c 中添加代码:

#include <linux/i2c.h>
#include <linux/i2c/at24.h>
static struct at24_platform_data at24c02 = {  
    .byte_len   = SZ_2K / 8,  
    .page_size  = 8,  
    .flags      = 0,  
};  

static struct i2c_board_info __initdata smdk_i2c_devices[] = {  
    {  
        I2C_BOARD_INFO("24c02", 0x50),      // type, addr 1010 000
        .platform_data = &at24c02,  
    },  
};  

在smdk2410_init函数中增加如下:

i2c_register_board_info(0,smdk_i2c_devices,ARRAY_SIZE(smdk_i2c_devices)); 

注意事项:
1.AT24Cxx设备地址为(7位):1010 xxx,所以其地址为0x5X;
2.一定要添加板级支持信息(只有板级信息和驱动匹配时,才会正常加载);
3.I2C_BOARD_INFO中的24c02将显示为name名称(以及设备关联id_table);


查看设备:

#ls /sys/devices/platform/s3c2410-i2c.0/i2c-0/0-0050/
driver    eeprom    modalias    name    power    subsystem    uevent

#cat /sys/devices/platform/s3c2410-i2c.0/i2c-0/0-0050/name
24c02

打开设备文件:

fd = open("/sys/devices/platform/s3c2410-i2c.0/i2c-0/0-0050/eeprom", O_RDWR); 

写操作

lseek(fd, 0 , SEEK_SET);
ret = write(fd, write_data, 256); 

读操作

lseek(fd, 0 , SEEK_SET);
ret = read(fd, read_data, 256); 

关闭设备

close(fd);

注意事项:
每次读写操作前,一定要记住lseek数据地址;

- 阅读全文 -

数据库应用--触发器简介


文章描述:本文介绍了基于mysql数据库触发器的简单应用。
测试平台:mysql


触发器简介:
触发器是一种特殊类型的存储过程,它在指定的表中的数据发生变化时自动生效,唤醒调用触发器以响应 INSERT、UPDATE 或 DELETE 语句。


创建表tab1

CREATE TABLE tab1(
    id CHAR(16)
);

创建表tab2

CREATE TABLE tab2(
    id CHAR(16)
);

创建INSERT触发器

CREATE TRIGGER after_tab1_insert
AFTER INSERT ON tab1
FOR EACH ROW
BEGIN
    INSERT INTO tab2(id) VALUES(new.id);
END

INSERT测试: 查看tab2是否同步添加

INSERT INTO tab1 (id) VALUES('123456');

创建UPDATE触发器

CREATE TRIGGER after_tab1_update
AFTER UPDATE ON tab1
FOR EACH ROW
BEGIN
    UPDATE tab2 SET id = new.id where id = old.id;
END

UPDATE测试:查看tab2是否同步更新

UPDATE tab1 SET id='1234567890' WHERE id='123456';

创建DELETE触发器

CREATE TRIGGER after_tab1_delete
AFTER DELETE ON id1
FOR EACH ROW
BEGIN
    DELETE FROM tab2 WHERE id=old.id;
END

DELETE测试: 查看tab2是否同步删除

DELETE FROM tab1 WHERE id='1234567890';

删除触发器

DROP TRIGGER after_tab1_insert;
DROP TRIGGER after_tab1_update;
DROP TRIGGER after_tab1_delete;

查看触发器

SHOW TRIGGERS;

上述方法显示内容太多,不太容易查看,可以在数据库中查看:

SELECT 
TRIGGER_NAME,
EVENT_OBJECT_SCHEMA,
EVENT_OBJECT_TABLE
FROM 
information_schema.`TRIGGERS`;

注意事项:
1.old是指更新前的值,new是指更新后的值;
2.创建触发器前需要修改分割符: DELIMITER
3.并在创建完成后恢复默认: DELIMITER ;

- 阅读全文 -

mtd-utils制作


文章摘要: 本文主要描述了MTD(Memory Technology Device)工具的交叉编译制作。
开发环境: RHEL5
源码版本: mtd-utils-1.5.0 | zlib-1.2.6 | lzo-2.06 | e2fsprogs-1.42


1.交叉编译 zlib

$./configure --prefix=/home/user/mtd/install  

修改Makfile
由于zlib不支持指定--host选项,必须手工修改。

CC=arm-linux-gcc
LDSHARED=arm-linux-gcc -shared -Wl,-soname,libz.so.1,--version-script,zlib.map
CPP=arm-linux-g++

AR=arm-linux-ar
RANLIB=arm-linux-ranlib

编译安装

$make
$make install

2.交叉编译 LZO

$./configure --host=arm-linux --prefix=/home/user/mtd/install
$make
$make install

3.交叉编译 e2fsprogs

$./configure --host=arm-linux CC=arm-linux-gcc --prefix= /home/user/mtd/install  
$cd lib/uuid/
$make
$make install

注意事项:
我们需要的其实是uuid而不是整个e2fsprogs,整个还是蛮大的要编译蛮久,而且编译不一定能通过.


4.编译MTD
修改Makefile 添加以下代码:

CROSS=arm-linux-
PREFIX = /home/user/mtd/install
ZLIBCPPFLAGS = -I$(PREFIX)/include
LZOCPPFLAGS = -I$(PREFIX)/include
ZLIBLDFLAGS = -L$(PREFIX)/lib
LZOLDFLAGS = -L$(PREFIX)/lib

LDFLAGS += $(ZLIBLDFLAGS) $(LZOLDFLAGS)
CFLAGS ?= -O2 -g $(ZLIBCPPFLAGS) $(LZOCPPFLAGS)

编译安装

$make WITHOUT_XATTR=1
$make install

至此所需工具已经安装至/home/user/mtd/install/sbin目录下,可根据需要拷贝至开发板使用了。

- 阅读全文 -


Copyright©2025 春天花会开, All Rights Reserved. Email: webmaster@oroct.com