Chinaunix首页 | 论坛 | 博客
  • 博客访问: 9131
  • 博文数量: 7
  • 博客积分: 280
  • 博客等级: 二等列兵
  • 技术积分: 65
  • 用 户 组: 普通用户
  • 注册时间: 2009-10-29 14:23
文章分类
文章存档

2010年(2)

2009年(5)

我的朋友
最近访客

分类: 嵌入式

2009-11-05 13:53:15

折腾了很久,终于完成了2.6.12下的无线网卡与CF卡驱动的移植.刚开始我用裸奔测试程序,确保了硬件无误后才参考一些网上资料开始移植驱动程序。但苦于网络上这方面的资料太少,而且还有偏差(这些偏差让我浪费了不少时间来Debug)。所以我也把自己的调试经验总结出来和大家分享。
首先要提醒一下大家,注意你操作的地址空间上的mmu设置,请关闭缓冲区,否则系统不能正确读取和操作PD6722的寄存器。

使用S3C2440为核心,通过PD6722进行PCMCIA总线扩展,一个socket接无线网卡,一个socke接CF卡。
硬件介绍:
PD6722接在nGCS2空间,使用A24进行IO与MEM空间的分隔.因此地址分配如下:
    A24=1, I/O area
    A24=0, mem area
    AEN=nGCS2,
    absolute address       
    0x10000000~0x10FFFFFF: 16M memory地址空间
    0x11000000~0x1100FFFF: 64k I/O地址空间
中断:
card IRQ使用IRQ3,并连接到s3c2440的EINT8管脚.
-INTR 连接到EINT3.
主要的移植工作包括:
1.在./arch/arm/mach-s3c2410/mach-smdk2410.c中添加以上虚拟地址映射,代码如下:
  { (u32)S3C24XX_VA_ISA_WORD, pCF_IO_BASE, SZ_1M, MT_DEVICE },
  { (u32)S3C24XX_VA_ISA_BYTE, pCF_IO_BASE, SZ_1M, MT_DEVICE },
  { 0xe2000000,0x10000000,SZ_16M,MT_DEVICE },
  { 0xe3000000,0x11000000,SZ_64K,MT_DEVICE },
其中,添加S3C24XX_VA_ISA_WORD以及S3C24XX_VA_ISA_BYTE的目的是为了将isa的io空间读取映射至PD6722的io区域,这样程序调用inb(0x00)时将等效于调用((uchar*)(pCF_IO_BASE).保证了PD6722中部分代码不用修改,但是需要注意的是,若其他驱动程序调用inb函数,此时可能会出现错误的访问,这时建议将以上两个映射取消,然后修改驱动函数中的inb函数调用.
后两行代码是用来给I/O与memory地址空间映射虚拟地址。虚拟地址只要不和系统中已分配出去的地址发生冲突就可以了。

3.因为PD6722为82365兼容芯片,因此其驱动在./driver/pcmcia/i82365.c文件中,主要需要进行如下修改:
在文件头增加以下几个头文件和宏定义:
#include
#include
#define IRQ_nCF_INS  IRQ_EINT3
#define IRQ_CF_RDY  IRQ_EINT8

a.  修改 
static int has_dma = -1;
static int has_led = -1;
static int has_ring = -1;
static int dynamic_mode = 1;
static int freq_bypass = -1;
static int setup_time = 1; /* default value*/
static int cmd_time = 6;  /*  default value*/
static int recov_time = 3; /*default value */
根据PD6722数据手册和网上资料,CLK引脚连接25M的时钟源时,freq_bypass应该设置为1,输入14.318M时设置为-1。但在我的系统中,CLK输入时钟就是25M,却必须设为-1才可以工作,到现在都一直很费解,如果谁知道原因请告诉我,不胜感激!
b. 在 cirrus_set_state函数中添加:
//>>>>-----------
    //flush fifo first
    i365_set(s, PD67_FIFO_CTL , 0x80);
//<<<<-----------
    for (i = 0; i < 6; i++)
        i365_set(s, PD67_TIME_SETUP(0)+i, p->timer[i]);
   这是按照手册上的要求,修改TIME寄存器之前需要将FIFO清空.
c.  修改add_pcic函数(重要):
    1、按下面修改这部分代码
    /* Scan for ISA interrupts */
    //mask = isa_scan(base, mask);
       
    /* Poll if only two interrupts available */
    if (!poll_interval) {
 u_int tmp = (mask & 0xff20);
 tmp = tmp & (tmp-1);
 if ((tmp & (tmp-1)) == 0)
     poll_interval = HZ;
    }
    /* Only try an ISA cs_irq if this is the first controller */
    if (!grab_irq && (cs_irq || !poll_interval)) {
 /* Avoid irq 12 unless it is explicitly requested */
 //u_int cs_mask = mask & ((cs_irq) ? (1< //for (cs_irq = 15; cs_irq > 0; cs_irq--)
  //   if ((cs_mask & (1 << cs_irq)) &&
 // (_check_irq(cs_irq, 0) == 0))
 // break;
 if (cs_irq) {
     grab_irq = 1;
     isa_irq = cs_irq;
     printk(" status change on irq %d\n", cs_irq);
 }
    }
   
    2、修改最后一个for循环语句
//>>>>-----------
 
    for (i = 0; i < ns; i++) {
 t[i].socket.features |= SS_CAP_PCCARD| SS_CAP_PAGE_REGS;
 t[i].socket.map_size = 0x1000;
 t[i].socket.irq_mask = mask;
 t[i].socket.pci_irq = IRQ_CF_RDY;
 t[i].cs_irq = isa_irq;
 t[i].intr = I365_INTR_ENA;
 t[i].intr |= 3 << 0;
    }
//<<<<-----------
配置pci_irq 外部中断 EINT8, 配置使用PD6722的IRQ3作为PC CARD的card IRQ.

f. 修改set_mem_map函数(相当重要!!!)
在函数的开头部分添加:
//>>>>-----------
    mem->res->start &= ~0x10000000;
    mem->res->end &= ~0x10000000;
//<<<<-----------
在函数尾添加:
//>>>>-----------
  mem->res->start |= 0x10000000;
  mem->res->end |= 0x10000000;
//<<<<-----------
两句的作用是对硬件地址的偏移进行调整,记住我们PD6722的mem空间为0x10000000~0x10FFFFFF.

g. 在init_i82365中添加S3C2410 bank1 以及中断配置代码:
//>>>>-----------
    unsigned int temp;
    temp  = __raw_readl(S3C2410_BWSCON);
    temp &= 0xFFFFF0FF;
    temp |= 0xd<<8;
    __raw_writel(temp,S3C2410_BWSCON);
    temp = ((B6710_Tacs<<13)+(B6710_Tcos<<11)+(B6710_Tacc<<8)+(B6710_Tcoh<<6)\
        +(B6710_Tah<<4)+(B6710_Tacp<<2)+(B6710_PMC));   
    __raw_writel(temp,S3C2410_BANKCON2);
   
    s3c2410_gpio_cfgpin(S3C2410_GPF3, S3C2410_GPF3_EINT3);
    s3c2410_gpio_cfgpin(S3C2410_GPG0, S3C2410_GPG0_EINT8);
    set_irq_type(IRQ_nCF_INS, IRQT_FALLING); //#define IRQ_nCF_INS  IRQ_EINT3
    set_irq_type(IRQ_CF_RDY, IRQT_RISING); //#define IRQ_CF_RDY  IRQ_EINT8
//<<<<-----------
其中的参数的值为:
#define B6710_Tacs (0x0) // 0clk
#define B6710_Tcos (0x3) // 4clk
#define B6710_Tacc (0x7) // 14clk
#define B6710_Tcoh (0x1) // 1clk
#define B6710_Tah (0x0) // 0clk
#define B6710_Tacp (0x3) // 6clk
#define B6710_PMC (0x0) // normal(1data)

然后编译内核,make menuconfig 里把PCMCIA/Cardbus support选项以及i82365 compatible bridge support选项选为y,即将cs.c ds.c和i82365.c等编译加载到内核里面。同时把Hermes chipset 802.11b support (Orinoco/Prism2/Symbol)和Hermes chipset 802.11b support (Orinoco/Prism2/Symbol)这两个选项也选为y,这一步是将无线网卡的驱动(hermes.o Orinoco.o Orinoco_pci.o)编译进内核。编译后即可正常启动。
 
5.交叉编译cardmgr程序.可以在pcmcia-cs网站中找到.我使用的是pcmcia-cs-3.2.8。
应用程序(Cardmgr、Cardctr1)用来记录、跟踪PCMCIA Card的插入/取出,并且加载/移去相应的Card Client驱动程序。我们需要交叉编译这两个应用程序。
首先,可以从下载pcmcia-cs-3.2.8的软件包,里面包含有PCMCIA的驱动,无线网卡的驱动,以及应用程序cardctl和cardmgr(负责管理PCMCIA的驱动,以及建立eth1等,这个必须要)。前两者都已经在内核中,直接用内核的就可以了,现在只需要交叉编译cardmgr和cardctl 就可以,以及采用一些里面的配置。
打开源代码里面的config.in文件,将原来的配置替换如下:
LINUX=/home/jb/linux-techor-xiyong
UCC=/usr/local/arm/3.3.2/bin/arm-linux-gcc-3.3.2
KCC=/usr/local/arm/3.3.2/bin/arm-linux-gcc-3.3.2
LD=/usr/local/arm/3.3.2/bin/arm-linux-ld
ARCH=arm
      和普通的应用程序一样,修改交叉编译的选项,编译出来cardmgr及cardctl,拷贝至板子的/sbin目录下。
同时把编译出来的etc文件夹内的所有文件拷贝到板子的文件系统/etc/pcmcia/路径下
修改/etc/pcmciaconfig.opts
只保留
include port 0x00-0xff
include memory 0x10010000-0x103fffff
两行,其余全部注释掉
这是给cardmgr提供探测的地址范围。
运行cardmgr启动应用程序
运行cardctl info ,获取卡的信息。
阅读(441) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~