花了半年时间在QNX系统上,这是一个RTOS,这个系统是高安全级别的系统,在核物理站/天文空间站/电站/地铁/交通运输(飞机/汽车/地铁)等工业系统领域占有70%以上的市场份额。
背景 :本文将我个人在QNX上移植内核和开发驱动以及应用程序的部分经验记录在此,因公司商业机密,部分源码不便公开。我会框架性的讲解开发思路。为了简化文章复杂性,我只讨论相同板子的平台驱动转移,我手中是at91sam9260-ek的板子。外部设备是公司硬件部单独添加的。
目的 :利用已有的Linux驱动,简化QNX的驱动编写。
大致思路 :Linux的驱动是基于模块的,每个驱动作为内核的扩展放进内存中,QNX的驱动就是一个进程,需要将模块改为一个应用程序。调整内核与驱动的通信机制。
以RTC驱动为例子:
Linux的驱动开发框架为 :
1.填充read/write/ioctl/probe等驱动回调函数,设置对应的接口。
2.编写每个部分的硬件相关代码。以write为例:
其他具体实现就不在这里描述了。
原文参考自web开发网:http://www.software8.co/wzjs/
为了将原有的Linux驱动移植到QNX上,需要改动read/write以及ioctl的函数接口参数。并将与Linux内核相关的函数去掉(通常不会在QNX里面用到)以read函数代码为例:
背景 :本文将我个人在QNX上移植内核和开发驱动以及应用程序的部分经验记录在此,因公司商业机密,部分源码不便公开。我会框架性的讲解开发思路。为了简化文章复杂性,我只讨论相同板子的平台驱动转移,我手中是at91sam9260-ek的板子。外部设备是公司硬件部单独添加的。
目的 :利用已有的Linux驱动,简化QNX的驱动编写。
大致思路 :Linux的驱动是基于模块的,每个驱动作为内核的扩展放进内存中,QNX的驱动就是一个进程,需要将模块改为一个应用程序。调整内核与驱动的通信机制。
以RTC驱动为例子:
Linux的驱动开发框架为 :
1.填充read/write/ioctl/probe等驱动回调函数,设置对应的接口。
static
struct file_operations rtc8025_fops = {
.owner = THIS_MODULE,
.open = rtc_open,
.release = rtc_release,
.read = rtc_read,
.write = rtc_write,
.ioctl = rtc_ioctl,
};
.owner = THIS_MODULE,
.open = rtc_open,
.release = rtc_release,
.read = rtc_read,
.write = rtc_write,
.ioctl = rtc_ioctl,
};
static ssize_t rtc_write(
struct file *filp, __user
const
char *buf,
size_t len,loff_t *ppos){
char buff[16];
VR_TIME *tm;
tm = kmalloc( sizeof(VR_TIME),GFP_KERNEL);
if ( NULL == tm ){
printk("Memory error!\n");
return -1;
}
if ( copy_from_user(buff, buf, len) )
return -EFAULT;
buff[len] = '\0';
set_time_value(tm, buff);
set_sys_time(tm);
kfree(tm);
return len;
}
3.注册设备的initial接口函数与exit接口函数。
size_t len,loff_t *ppos){
char buff[16];
VR_TIME *tm;
tm = kmalloc( sizeof(VR_TIME),GFP_KERNEL);
if ( NULL == tm ){
printk("Memory error!\n");
return -1;
}
if ( copy_from_user(buff, buf, len) )
return -EFAULT;
buff[len] = '\0';
set_time_value(tm, buff);
set_sys_time(tm);
kfree(tm);
return len;
}
static __init
int rtc8025_init(
void){
int ret;
printk("%s Driver Version: %s\n", DRIVER_NAME, VERSION);
ret = register_chrdev(major,DRIVER_NAME,&rtc8025_fops);
if ( ret < 0 ){
printk("unable to register %s\n",DRIVER_NAME);
return ret;
}
init_gpio();
msleep(10);
init_rtc();
return 0;
}
static __exit void rtc8025_exit( void){
i2c_stime(0xe0, 0x20);
i2c_stime(0xf0, 0);
i2c_stime(0x70, 0x00);
unregister_chrdev(major, DRIVER_NAME);
printk("%s unregister!\n", DRIVER_NAME);
}
module_init(rtc8025_init);
module_exit(rtc8025_exit);
int ret;
printk("%s Driver Version: %s\n", DRIVER_NAME, VERSION);
ret = register_chrdev(major,DRIVER_NAME,&rtc8025_fops);
if ( ret < 0 ){
printk("unable to register %s\n",DRIVER_NAME);
return ret;
}
init_gpio();
msleep(10);
init_rtc();
return 0;
}
static __exit void rtc8025_exit( void){
i2c_stime(0xe0, 0x20);
i2c_stime(0xf0, 0);
i2c_stime(0x70, 0x00);
unregister_chrdev(major, DRIVER_NAME);
printk("%s unregister!\n", DRIVER_NAME);
}
module_init(rtc8025_init);
module_exit(rtc8025_exit);
其他具体实现就不在这里描述了。
原文参考自web开发网:http://www.software8.co/wzjs/
为了将原有的Linux驱动移植到QNX上,需要改动read/write以及ioctl的函数接口参数。并将与Linux内核相关的函数去掉(通常不会在QNX里面用到)以read函数代码为例:
size_t rtc_read(
char *buf, size_t len,
int *ppos){
VR_TIME *tm = (VR_TIME *)buf;
static unsigned char tmp = 0;
tmp = i2c_rtime(0x00) & 0x7f; tm->second = BCD2DEC(tmp);
tmp = i2c_rtime(0x10) & 0x7f; tm->minute = BCD2DEC(tmp);
tmp = i2c_rtime(0x20) & 0x3f; tm->hour = BCD2DEC(tmp);
tmp = i2c_rtime(0x40) & 0x3f; tm->day = BCD2DEC(tmp);
tmp = i2c_rtime(0x50) & 0x1f; tm->month = BCD2DEC(tmp);
tmp = i2c_rtime(0x60); tm->year = BCD2DEC(tmp)+ 1920;
return 0;
}
VR_TIME *tm = (VR_TIME *)buf;
static unsigned char tmp = 0;
tmp = i2c_rtime(0x00) & 0x7f; tm->second = BCD2DEC(tmp);
tmp = i2c_rtime(0x10) & 0x7f; tm->minute = BCD2DEC(tmp);
tmp = i2c_rtime(0x20) & 0x3f; tm->hour = BCD2DEC(tmp);
tmp = i2c_rtime(0x40) & 0x3f; tm->day = BCD2DEC(tmp);
tmp = i2c_rtime(0x50) & 0x1f; tm->month = BCD2DEC(tmp);
tmp = i2c_rtime(0x60); tm->year = BCD2DEC(tmp)+ 1920;
return 0;
}