linux2.6.14内核下移植16C554驱动

这几天移植在linux内核下调试16C554,扩展四串口驱动,用的是linux内核自带的8250.c驱动。
(1)8250.c内自带serial8250_init(),它在内核初始化时完成驱动的注册,所以我们需要添加的是设备资源。
(2)在arch/arm/mach-s3c2410/mach-smdk2410.c中添加四串口设备:
    staticstruct plat_serial8250_port my2410_st16c554_8250_data[] = {
     { //ARM体系结构中将IO和MEMORY统一编址,
    //因此这里使用的是Memory地址                   
       .mapbase = (unsigned long)S3C2410_CS1 +0x0FC0,   
       .irq               =IRQ_EINT2,                 
       .uartclk         =1843200,   
       .iotype          =UPIO_MEM32,        
       .flags            = (UPF_BOOT_AUTOCONF |UPF_IOREMAP),     
       .regshift        = 0,
       },
 //PORT(S3C2410_CS1 + 0x0, IRQ_EINT0),
      { //ARM体系结构中将IO和MEMORY统一编址,
    //因此这里使用的是Memory地址                   
       .mapbase = (unsigned long)S3C2410_CS1 +0x0FA0,   
       .irq               =IRQ_EINT8,                 
       .uartclk         =1843200,   
       .iotype          =UPIO_MEM32,        
       .flags            = (UPF_BOOT_AUTOCONF |UPF_IOREMAP),     
       .regshift        = 0,
        },
//PORT(S3C2410_CS2 + 0x0, IRQ_EINT1),
      { //ARM体系结构中将IO和MEMORY统一编址,
    //因此这里使用的是Memory地址                   
       .mapbase = (unsigned long)S3C2410_CS1 +0x0F60,   
       .irq               =IRQ_EINT11,                 
       .uartclk         =1843200,   
       .iotype          =UPIO_MEM32,        
       .flags            = (UPF_BOOT_AUTOCONF |UPF_IOREMAP),     
       .regshift        = 0,
        },
      //PORT(S3C2410_CS3 + 0x0, IRQ_EINT2),
        { //ARM体系结构中将IO和MEMORY统一编址,
    //因此这里使用的是Memory地址                   
       .mapbase = (unsigned long)S3C2410_CS1 +0x0EE0,   
       .irq               =IRQ_EINT19,                 
       .uartclk         =1843200,   
       .iotype          =UPIO_MEM32,        
       .flags            = (UPF_BOOT_AUTOCONF |UPF_IOREMAP),     
       .regshift        = 0,
        },
      //PORT(S3C2410_CS5 + 0x0, IRQ_EINT3),
      { },
};
 
static struct platform_device my2410_device_st16c554 = {
    .name            = "serial8250",
    .id                = PLAT8250_DEV_PLATFORM,
    .dev              = {
           .platform_data      = &my2410_st16c554_8250_data,
    },
};
然后在smdk2410_devices中添加上面定义的设备。
static struct platform_device *smdk2410_devices[] __initdata ={
 &s3c_device_usb,
 &s3c_device_lcd,
 &s3c_device_wdt,
 &s3c_device_i2c,
 &s3c_device_iis,
     &s3c_device_nand,
     &my2410_device_st16c554,
}; 
(3)下面就要修改8250.c
   首先在serial8250_init()中,serial8250_isa_devs =platform_device_register_simple("serial8250",PLAT8250_DEV_PLATFORM,NULL,0)这个函数有点诡异,我起先对它没有修改,但是内核启动之后设备总是注册不成功,找了找原因,实在不知道其中的PLAT8250_DEV_PLATFORM是什么意思,故把它改成-1,再次启动内核,貌似有了点进展。
   但是在内核启动的过程中,总是停止在serial8250_config_port()中autoconfig()中的serial_in()中,找到源代码查看,发现serial_in()中的readl()出了问题。readl()是访问内存空间虚拟地址的一个函数,在调用它之前必须将I/O空间映射到虚拟内存空间,所以估计是没有映射。
    找到:
static int serial8250_request_std_resource(struct uart_8250_port*up)
{
 unsigned int size = 8<<up->port.regshift;
 int ret = 0;
       printk("the port's size is %d",size);
 switch (up->port.iotype) {
 case UPIO_MEM:
  if(!up->port.mapbase)
   break;
  if(!request_mem_region(up->port.mapbase, size,"serial")) {
   ret =-EBUSY;
   break;
  }
  if(up->port.flags & UPF_IOREMAP){
   up->port.membase= ioremap(up->port.mapbase, size);
   if(!up->port.membase) {
    release_mem_region(up->port.mapbase,size);
    ret= -ENOMEM;
   }
  }
  break;
 case UPIO_HUB6:
 case UPIO_PORT:
  if(!request_region(up->port.iobase, size,"serial"))
   ret =-EBUSY;
  break;
 }
 return ret;
}
 
发现里面的iotype没有我们想要的UPIO_MEM32,所以没有进行request_mem_region和ioremap,故将UPIO_MEM改为UPIO_MEM32。
  再次编译,启动,可以注册了,下一步就要进行测试

 

 

-----------------------------------------------------------------------------------------------------

1、参照网页《我在Linux-2.6.32.2下为ST16C554移植驱动的经历》编写 

     sc16c554四串口驱动;

   原文:http://blog.chinaunix.net/u3/116495/showart.php?id=2272834

 

2、出现问题:

(1)首次没有移植成功;是因为sc16c554芯片硬件上复位信号电平给弄反了,以致于编译通过后,虽然用cat/proc/tty/driver/serial命令也出现了四个串口,但是串口信息不对,全为UNKOWN设备。后放弃。

(2)遂自己编写驱动查找原因,编写了字符型设备来驱动16c554,发现片选、数据、和地址信号都有,就是没有中断,就查硬件设备三要素(电源、时钟、复位),后来发现设备复位电平不对,把芯片管脚翘起,收发正常。

(3)芯片正常后,仿照8250.c编写tty驱动,编写成功,linux2.6.13linux2.6.32.2上使用supervivinorflash上引导正常,但是用友善之臂提供的vboot引导出现问题,不成功。老是报内核地址为NULL,非法引用,然后就是一片寄存器值。看vboot源码没有找到问题所在,然后按照(1)的方法又进行二次移植。

(4)二次移植时,居然正常了,欣喜中。但很快发现数据发送不对,每次只能发送16个字节。问题出在

#definePORT(_base,_irq)                   \

{

       .mapbase = (unsignedlong)_base,   \

       .irq               =_irq,        \

       .uartclk         =16000000,      \

       .iotype          =UPIO_MEM32,    \

       .flags            = (UPF_BOOT_AUTOCONF | UPF_IOREMAP), \

       .regshift        = 0, \

}

 

iotype应为UPIO_MEM,即8位读写。

 

更改后即可。

(3)ttS3收发不对,使用cat/proc/tty/driver/serial命令查看时总是被识别为XScale设备和UNKOWN设备。后来发现是

      *((volatile unsigned int *)S3C2410_BWSCON) =

((*((volatile unsigned int*)S3C2410_BWSCON)) &~(0x30333<<4))

                           | S3C2410_BWSCON_DW1_8

                           | S3C2410_BWSCON_DW2_8

                           | S3C2410_BWSCON_DW3_8

                           | S3C2410_BWSCON_DW4_8;

设置不对,应该为

      *((volatile unsigned int *)S3C2410_BWSCON) =

((*((volatile unsigned int*)S3C2410_BWSCON)) &~(0x03333<<4))

                           | S3C2410_BWSCON_DW1_8

                           | S3C2410_BWSCON_DW2_8

                           | S3C2410_BWSCON_DW3_8

                           | S3C2410_BWSCON_DW4_8;

 

因为原作者用的CS1,CS2,CS3,CS5,我这里CS5变成了CS4,所以0x30333<<要变成0x03333

(5)驱动正常后,参照linux-2.6.32.2\drivers\serial\8250_exar_st16c554.c,又看了mach-mini2440.c的源文件,编写了8250_exar_sc16c554.c驱动(恢复了mach-mini2440.c8250.c中关于串口部分的原貌见附件),功能测试正常。

 

3、关于8250_exar_sc16c554.

 

硬件平台:s3c2440 自制印制板   

操作系统:linux-2.6.32.2

编 译 器:gcc-linux-arm4.3.2

 

 

 


#include <linux/module.h>
#include <linux/init.h>
#include<linux/serial_8250.h>

#include<mach/regs-mem.h>
#include <mach/map.h>

 

#definePORT(_base,_irq)                   \
     .iobase   = (unsignedlong)_base,   \
       .mapbase  = (resource_size_t)_base, \
       .irq     = (unsignedint)_irq,    \
       .irqflags =IRQF_TRIGGER_RISING,   \
       .uartclk  =16000000,       \
       .iotype   =UPIO_MEM,    \
       .flags    =(UPF_BOOT_AUTOCONF | UPF_IOREMAP), \
       .regshift = 0, \
}

 


static struct plat_serial8250_port exar_data[] = {
      PORT(S3C2410_CS1 + 0x0, IRQ_EINT0),
      PORT(S3C2410_CS2 + 0x0, IRQ_EINT1),
      PORT(S3C2410_CS3 + 0x0, IRQ_EINT2),
      PORT(S3C2410_CS4 + 0x0, IRQ_EINT3),
      { },
};

 

static struct platform_device exar_device = {
 .name   ="serial8250",
 .id   =PLAT8250_DEV_EXAR_ST16C554,
 .dev   ={
  .platform_data =exar_data,
 },
};

 

static int __init exar_init(void)
{

      *((volatile unsigned int *)S3C2410_BWSCON) =
((*((volatile unsigned int *)S3C2410_BWSCON)) &~(0x03333<<4))
                           | S3C2410_BWSCON_DW1_8
                           | S3C2410_BWSCON_DW2_8
                           | S3C2410_BWSCON_DW3_8
                           | S3C2410_BWSCON_DW4_8;
                           
 returnplatform_device_register(&exar_device);
}

module_init(exar_init);

MODULE_AUTHOR("Kou Jinqiao");
MODULE_DESCRIPTION("8250 serial probe module for Exarcards-sc16c554");
MODULE_LICENSE("GPL");

 

 

8250_exar_sc16c554.c放入linux/drivers/serial/下,修改Makefile文件,重新makemenuconfig 选中8250_exar_sc16c554,然后make zImage即可。

这几天移植在linux内核下调试16C554,扩展四串口驱动,用的是linux内核自带的8250.c驱动。
(1)8250.c内自带serial8250_init(),它在内核初始化时完成驱动的注册,所以我们需要添加的是设备资源。
(2)在arch/arm/mach-s3c2410/mach-smdk2410.c中添加四串口设备:
    staticstruct plat_serial8250_port my2410_st16c554_8250_data[] = {
     { //ARM体系结构中将IO和MEMORY统一编址,
    //因此这里使用的是Memory地址                   
       .mapbase = (unsigned long)S3C2410_CS1 +0x0FC0,   
       .irq               =IRQ_EINT2,                 
       .uartclk         =1843200,   
       .iotype          =UPIO_MEM32,        
       .flags            = (UPF_BOOT_AUTOCONF |UPF_IOREMAP),     
       .regshift        = 0,
       },
 //PORT(S3C2410_CS1 + 0x0, IRQ_EINT0),
      { //ARM体系结构中将IO和MEMORY统一编址,
    //因此这里使用的是Memory地址                   
       .mapbase = (unsigned long)S3C2410_CS1 +0x0FA0,   
       .irq               =IRQ_EINT8,                 
       .uartclk         =1843200,   
       .iotype          =UPIO_MEM32,        
       .flags            = (UPF_BOOT_AUTOCONF |UPF_IOREMAP),     
       .regshift        = 0,
        },
//PORT(S3C2410_CS2 + 0x0, IRQ_EINT1),
      { //ARM体系结构中将IO和MEMORY统一编址,
    //因此这里使用的是Memory地址                   
       .mapbase = (unsigned long)S3C2410_CS1 +0x0F60,   
       .irq               =IRQ_EINT11,                 
       .uartclk         =1843200,   
       .iotype          =UPIO_MEM32,        
       .flags            = (UPF_BOOT_AUTOCONF |UPF_IOREMAP),     
       .regshift        = 0,
        },
      //PORT(S3C2410_CS3 + 0x0, IRQ_EINT2),
        { //ARM体系结构中将IO和MEMORY统一编址,
    //因此这里使用的是Memory地址                   
       .mapbase = (unsigned long)S3C2410_CS1 +0x0EE0,   
       .irq               =IRQ_EINT19,                 
       .uartclk         =1843200,   
       .iotype          =UPIO_MEM32,        
       .flags            = (UPF_BOOT_AUTOCONF |UPF_IOREMAP),     
       .regshift        = 0,
        },
      //PORT(S3C2410_CS5 + 0x0, IRQ_EINT3),
      { },
};
 
static struct platform_device my2410_device_st16c554 = {
    .name            = "serial8250",
    .id                = PLAT8250_DEV_PLATFORM,
    .dev              = {
           .platform_data      = &my2410_st16c554_8250_data,
    },
};
然后在smdk2410_devices中添加上面定义的设备。
static struct platform_device *smdk2410_devices[] __initdata ={
 &s3c_device_usb,
 &s3c_device_lcd,
 &s3c_device_wdt,
 &s3c_device_i2c,
 &s3c_device_iis,
     &s3c_device_nand,
     &my2410_device_st16c554,
}; 
(3)下面就要修改8250.c
   首先在serial8250_init()中,serial8250_isa_devs =platform_device_register_simple("serial8250",PLAT8250_DEV_PLATFORM,NULL,0)这个函数有点诡异,我起先对它没有修改,但是内核启动之后设备总是注册不成功,找了找原因,实在不知道其中的PLAT8250_DEV_PLATFORM是什么意思,故把它改成-1,再次启动内核,貌似有了点进展。
   但是在内核启动的过程中,总是停止在serial8250_config_port()中autoconfig()中的serial_in()中,找到源代码查看,发现serial_in()中的readl()出了问题。readl()是访问内存空间虚拟地址的一个函数,在调用它之前必须将I/O空间映射到虚拟内存空间,所以估计是没有映射。
    找到:
static int serial8250_request_std_resource(struct uart_8250_port*up)
{
 unsigned int size = 8<<up->port.regshift;
 int ret = 0;
       printk("the port's size is %d",size);
 switch (up->port.iotype) {
 case UPIO_MEM:
  if(!up->port.mapbase)
   break;
  if(!request_mem_region(up->port.mapbase, size,"serial")) {
   ret =-EBUSY;
   break;
  }
  if(up->port.flags & UPF_IOREMAP){
   up->port.membase= ioremap(up->port.mapbase, size);
   if(!up->port.membase) {
    release_mem_region(up->port.mapbase,size);
    ret= -ENOMEM;
   }
  }
  break;
 case UPIO_HUB6:
 case UPIO_PORT:
  if(!request_region(up->port.iobase, size,"serial"))
   ret =-EBUSY;
  break;
 }
 return ret;
}
 
发现里面的iotype没有我们想要的UPIO_MEM32,所以没有进行request_mem_region和ioremap,故将UPIO_MEM改为UPIO_MEM32。
   再次编译,启动,可以注册了,下一步就要进行测试。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值