Keep Faith

统计

ARM移植

最新评论

2007年6月2日 #

捕捉键盘输入的简单办法

比较有效的键盘输入捕捉方法为使用hook函数,然后这种方法比较复杂,今天在网上早到一种新的简单的捕捉方法。
即可以在PreTranslateMessage(MSG* pMsg)中进行处理:
如:
{
    // TODO: Add your specialized code here and/or call the base class
    if(pMsg->message == WM_KEYDOWN) {
        switch(pMsg->wParam) {
        case VK_LEFT:
            *Command=0x01;
            SendSocket.SendTo(Command,1,LINKPORT,videoconfig.m_ipaddress);
            break;
        case VK_RIGHT:
            *Command=0x02;
            SendSocket.SendTo(Command,1,LINKPORT,videoconfig.m_ipaddress);
            break;
        case VK_DOWN:
            *Command=0x04;
            SendSocket.SendTo(Command,1,LINKPORT,videoconfig.m_ipaddress);
            break;
        case VK_UP:
            *Command=0x03;
            SendSocket.SendTo(Command,1,LINKPORT,videoconfig.m_ipaddress);
            break;
        case VK_SPACE:
            *Command=0x05;
            SendSocket.SendTo(Command,1,LINKPORT,videoconfig.m_ipaddress);
        }
        return TRUE;
    }

posted @ 2007-06-02 22:18 sardis 阅读(784) | 评论 (0)编辑 收藏

linux的实时性问题

通过这几天的测试,发现linux的实时性还是有很大问题的。。
编写了一个红外遥控程序,通过GPIO产生红外遥控数据,一般
红外遥控采用如下编码方式:
'1'为560us有效加560*3us无效输出。
'0'为560us有效加560us无效输出。
在linux下编写了驱动,起初是通过udelay延时进行时序控制。
发现当CPU占用率增加时,时序完全没有保证。
随后采用linux的sys_timer进行时序控制,通过调用
s3c2410_gettimeoffset读取timer4的计数器计数值进行延时控制,
效果还是不好,后来自己使用了timer3进行时序控制,通过
timer3中断对时序进行控制,但测试发现,当无线网卡以及usb摄像头都
工作时,进入中断都有很大的延时,还是满足时序要求。

最后没有办法,只能外接一个单片机进行时序控制,然后arm板通过串口与单片机通信,
完成红外控制。linux毕竟还不是实时系统,完成这种对时序有较高要求的任务是还是有
所欠缺。

posted @ 2007-06-02 22:12 sardis 阅读(2140) | 评论 (3)编辑 收藏

2007年5月30日 #

设备文件的访问控制

对设备文件的访问控制主要通过open函数实现:
某些设备同一时间只允许一个进程打开该设备即(独享),这是可以通过atomic_t变量实现:
    static atomic_t cleanerCtl_available = ATOMIC_INIT(1);
int cleanerCtl_open(struct inode *inode, struct file *filp)
{
    struct cleanerCtl_dev *dev; /* device information */


    if(!atomic_dec_and_test(&cleanerCtl_available)) {
        atomic_inc(&cleanerCtl_available);
        return -EBUSY;      //already open one device
    }

    dev = container_of(inode->i_cdev, struct cleanerCtl_dev, cdev);
    filp->private_data = dev; /* for other methods */
    return 0;
}
这样在release 函数中需要调用
atomic_inc函数对cleanerCtl_available进行释放。

另一些访问控制包括,单用户访问,读写权限控制等。
对于单用户访问,可以利用全局current->uid记录下打开该设备的用户id,然后进一步处理
对于读写权限控制,则可对filp->f_flags进行处理。

posted @ 2007-05-30 21:32 sardis 阅读(355) | 评论 (0)编辑 收藏

PD6710 遇到的问题

这几天在linux2.6.13中调试PD6710时发现:MAPING ENABLE寄存器出现读写错误,使用AXD进行调试后,进一步发现,当
PCMCIA卡未插入时,读写一切正常,在PCMCIA卡插入以后,寄存器就有可能出现读写错误,分析原因可能有以下几点:

1.PD6710芯片自身问题,是不是插入PCMCIA卡以后就会出现这种问题。(但是这种情况并未在google中搜到)。可以进行的下一步验证工作 为:对其它寄存器进行读写,看是否会出现同样的问题。如果没有的话,则这种猜测的可能性较高,如果出现同样的读写错误,那么就基本可以排除这种可能。
2.电源问题,因为插入PCMCIA卡之后,电流增大对电源芯片造成更大的负载,是不是在这种情况下,由于电源不够好,可能造成读写错误。
3.PCMCIA802.11b卡的电器干扰。插入无线网卡之后,射频的干扰是否会对系统板造成影响。(但为什么在2.4的内核中就没有唇线问题呢?因为电路板布线问题? (2.4内核跑通的板子和这块板子不同,在PCMCIA插座底部进行了大面积敷地))
4.寄存器配置问题。

明天准备做的工作,包括读写其它寄存器,调整读写时序,降低读写时钟,使用以前试验成功的2.4内核进行测试.

<<<<----------------
一天以后:
今天早上按照昨天的计划进行了测试,发现是时序的问题,很有可能是由于电器干扰或者电源负载导致插上板子后时序条件不满足,造成读写错误.在修改了HCLK后,插入板后读写正常.

posted @ 2007-05-30 21:27 sardis 阅读(689) | 评论 (0)编辑 收藏

s3c2410的linux 2.6.13下的无线网卡移植

折腾了一个多星期,终于完成了2.6.13下的无线网卡移植..

我们所使用了复旦大学CAT实验室自制的系统板,其采用S3C2410为核心,通过PD6710进行PCMCIA总线扩展,无线网卡采用的是清华同方的TFW1000.
硬件介绍:
PD6710接在nGCS1空间,使用A20进行IO与MEM空间的分隔.因此地址分配如下:
    A20=1, I/O area (A26 should have been used.)
    A20=0, mem area
    AEN=nGCS1,

    absolute address       
    0x08000000~0x080FFFFF: memory area
    0x08100000~0x081FFFFF: I/O area

中断:
card IRQ使用IRQ3,并连接到s3c2410的EINT4管脚.
manager IRQ没有使用.

主要的移植工作包括:
1.在./arch/arm/mach-s3c2410/mach-smdk2410.c中添加以上虚拟地址映射,代码如下:
//>>>>----------Modified by Zengyi 2007-5-23
  { (u32)S3C24XX_VA_ISA_WORD, pCF_IO_BASE, SZ_1M, MT_DEVICE },
  { (u32)S3C24XX_VA_ISA_BYTE, pCF_IO_BASE, SZ_1M, MT_DEVICE },

  { (u32)vCF_MEM_BASE,                    pCF_MEM_BASE,  SZ_1M, MT_DEVICE },
  { (u32)vCF_IO_BASE,                     pCF_IO_BASE,   SZ_1M, MT_DEVICE },
//<<<<----------Modify End
其中,S3C24XX_VA_ISA_WORD以及S3C24XX_VA_ISA_BYTE的映射主要是为了将isa的io空间读取映射到PD6710的io区域,
例如,调用inb(0x00)是,将等效于调用((uchar*)(pCF_IO_BASE).这样可以保证PD6710中部分代码不用修改,但是需要注意的
是如果还是其他驱动程序调用inb等函数时,将会产生问题,这是建立将以上两个映射取消,然后修改驱动函数中的inb函数调用.
2.(可选),修改系统时钟,由于板子电器特性问题,pd6710在memory时钟为200MHz时,会出现读写错误,因此不得不降低系统时钟,将时钟 修改为180MHz, memory时钟为90MHz.主要的修改/arch/arm/mach-s3c2410/s3c2410.c:
unsigned long mpllvalue = (0x52<<12)|(0x01<<4)|(0x01); //Set Clock to 180MHz, PD6710 can't work well in 200MHz
__raw_writel(mpllvalue,S3C2410_MPLLCON);

3.因为PD6710为82365兼容芯片,因此其驱动在./driver/pcmcia/i82365.c文件中,主要需要进行如下修改:
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 */
主要是修改一些默认参数,setup_time,cmd_time ,recov_time,均设为PD6710手册上所标记的默认值.(不知道为什么如果
上电后读出来的值并不是手册上的默认值,所以我们手动置为默认值).
b. 在 cirrus_set_state函数中添加:
//>>>>----------- Added by Zengyi 2007_5_29
    //flush fifo first
    i365_set(s, PD67_FIFO_CTL , 0x80);
    //>>>>----------- end of add
    for (i = 0; i < 6; i++)
        i365_set(s, PD67_TIME_SETUP(0)+i, p->timer[i]);
   这是按照手册上的要求,修改TIME寄存器之前需要将FIFO清空.
c.  在add_pcic函数中添加如下部分(重要):
    //>>>>------------- Add by Zengyi 2007_5_23
    #ifdef CONFIG_ARCH_SMDK2410_CATLAB
    /* Use SS_CAP_STATIC_MAP which disables the memory resource
       database check and SS_CAP_PAGE_REGS which disable io port
       maximun limit 0xffff */
    t[i].socket.features |= SS_CAP_PCCARD | SS_CAP_STATIC_MAP | SS_CAP_PAGE_REGS;
    /* We just pass up an offset which is applied to client-requested
       base I/O addresses in alloc_io_space() */
    t[i].socket.io_offset = vCF_IO_BASE;
    /* Map Size */
    t[i].socket.map_size = 0x1000;
    /* Do not use ISA irq */
    t[i].socket.irq_mask = 0;
    t[i].socket.pci_irq = IRQ_CF_RDY;
    /* Card Detect IRQ */
    t[i].cs_irq = 0;
    /* Enable Management Interrupt for card detect */
    t[i].intr = I365_INTR_ENA;
    /* PD6710 IRQ3 is only connected to IRQ_CF_RDY */
    t[i].intr |= 3 << 0;

#else

    t[i].socket.features |= SS_CAP_PCCARD;
    t[i].socket.map_size = 0x1000;
    t[i].socket.irq_mask = mask;
    t[i].cs_irq = isa_irq;
#endif
//>>>>------------- end of add

以上部分的作用主要是
设置socket.为STATIC MAP的, 设置io_offset 为新的虚拟地址,配置pci_irq 外部中断 EINT4, 配置使用PD6710的IRQ3作为PC CARD的card IRQ.

d. 在isa_probe函数中,直接添加一个pcic,因为我们只有一个pcic.
//<<<<----------------Add by Zengyi 2007_5_23
#ifdef CONFIG_ARCH_SMDK2410_CATLAB
    /* There is just one socket */
    add_socket(i365_base, 0, id);
    add_pcic(1, id);
#else
//>>>>----------------end of Add

e. 由于我们设置了socket为STATIC MAP,因此我们IO/MEMORY的映射需要自己手动完成:
在pcic_init函数中,可以修改
pccard_io_map io = { 0, 0, 0, 0, 0x100 }; 先设置好一段IO映射,但是我们现在还没有enable.
enable的操作本来应该在set_io_map函数中,但是有些上层的驱动并不会调用set_io_map函数(如我们的orinoco驱动),因此
我们选择在i365_set_socket函数中调用:
 /* IO card, RESET flag, IO interrupt */
    reg = t->intr;
    //reg |= state->io_irq;
    reg |= (state->flags & SS_RESET) ? 0 : I365_PC_RESET;
    reg |= (state->flags & SS_IOCARD) ? I365_PC_IOCARD : 0;
    i365_set(sock, I365_INTCTL, reg);
    //<<<<----------------- Added by Zengyi 2007_5_28
    if(reg & I365_PC_IOCARD) {
        //Enable IO MAP
        i365_bset(0, I365_ADDRWIN, I365_ENA_IO(0));
    }
    //>>>>------------------ end of Add
即,如果在set_socket的参数
state->flags中设置了SS_IOCARD那么,我们就把IO MAP0使能.

f. 修改set_mem_map函数(相当重要!!!)
在函数的开头部分添加:

//<<<<------------- Added by Zengyi 2007_5_25
#ifdef CONFIG_ARCH_SMDK2410_CATLAB
  if(mem->res == NULL) {
    printk(KERN_DEBUG "Make resource ourseleves\n");
    mem->res = claim_region(NULL,pCF_MEM_BASE,SZ_1M,IORESOURCE_MEM,"PD6710 Mem");
  } else {
    //i365_get_mem_map(sock,mem);
  }
  while (mem->res->start >= pCF_MEM_BASE) mem->res->start -= pCF_MEM_BASE;
  while (mem->res->end >= pCF_MEM_BASE) mem->res->end -= pCF_MEM_BASE;
#endif
//>>>>------------- end of Add
在函数尾添加:
//<<<<----------------- Add by Zengyi 2007_5_24
#ifdef CONFIG_ARCH_SMDK2410_CATLAB
    mem->res->start += pCF_MEM_BASE;
    mem->res->end += pCF_MEM_BASE;
#endif

    mem->static_start = mem->res->start;
该步骤的作用有以下部分:
首先检测mem->res是否非空,这一点不知道是不是2.6.13内核的bug,因为当设置为STATIC_MAP时,调用 pcmcia_validate_mem后会将s->mem->res置为NULL,这样接下来如pccard_validate_cis等 就可能会传递NULL指针
给set_mem_map函数,因此如果我们发现mem->res为NULL时则需要自己生成mem->res.
  while (mem->res->start >= pCF_MEM_BASE) mem->res->start -= pCF_MEM_BASE;
  while (mem->res->end >= pCF_MEM_BASE) mem->res->end -= pCF_MEM_BASE;
以及
    mem->res->start += pCF_MEM_BASE;
    mem->res->end += pCF_MEM_BASE;
的作用是对硬件地址的偏移进行调整,记住我们PD6710的mem空间为
0x08000000~0x080FFFFF.
mem->static_start = mem->res->start; 是重新设置mem->static_start .因为当设置为STATIC_MAP时,
上层函数会调用set_cis_map,而在该函数中会调用
s->cis_virt = ioremap(mem->static_start, s->map_size);
重新生成
s->cis_virt.
static void __iomem *
set_cis_map(struct pcmcia_socket *s, unsigned int card_offset, unsigned int flags)
{
    pccard_mem_map *mem = &s->cis_mem;
    int ret;

    if (!(s->features & SS_CAP_STATIC_MAP) && (mem->res == NULL)) {
        mem->res = pcmcia_find_mem_region(0, s->map_size, s->map_size, 0, s);
        if (mem->res == NULL) {
            printk(KERN_NOTICE "cs: unable to map card memory!\n");
            return NULL;
        }
        s->cis_virt = NULL;
    }

    if (!(s->features & SS_CAP_STATIC_MAP) && (!s->cis_virt))
        s->cis_virt = ioremap(mem->res->start, s->map_size);

    mem->card_start = card_offset;
    mem->flags = flags;

    ret = s->ops->set_mem_map(s, mem);
    if (ret) {
        iounmap(s->cis_virt);
        s->cis_virt = NULL;
        return NULL;
    }

    if (s->features & SS_CAP_STATIC_MAP) {
        if (s->cis_virt)
            iounmap(s->cis_virt);
        s->cis_virt = ioremap(mem->static_start, s->map_size);
    }


    return s->cis_virt;
}

g. 在init_i82365中添加S3C2410 bank1 以及中断配置代码:
//>>>---------Add by Zengyi 2007_5_23
#ifdef CONFIG_ARCH_SMDK2410_CATLAB
        volatile unsigned int regval;
        void __iomem *port;
//      printk(KERN_ERR "init_pd6710 start!\n");
        port=S3C2410_BWSCON;
//      printk(KERN_ALERT "Register BWSCON's address is %#x\n",port);

        //regval=inl_p(port);
        regval = __raw_readl(port);
        //printk(KERN_ALERT "BWSCON's value before change is %#x\n",regval);

        regval=(regval &(0xffffff0f))|(S3C2410_BWSCON_ST1|S3C2410_BWSCON_WS1|S3C2410_BWSCON_DW1_16);
        //outl_p(regval,port);
        __raw_writel(regval,port);
        //regval = __raw_readl(port);
        //printk(KERN_ALERT "BWSCON's value after change is %#x\n",regval);

        port=S3C2410_BANKCON1;
        //regval = __raw_readw(port);
        //printk(KERN_ALERT "BANKCON1's value before change is 0x%#x\n",regval);
//      printk(KERN_ERR "BWSCON step is OK!\n");
        regval=S3C2410_BANKCON_Tacs1|S3C2410_BANKCON_Tcos4|S3C2410_BANKCON_Tacc14|
               S3C2410_BANKCON_Tcoh1|S3C2410_BANKCON_Tcah1|S3C2410_BANKCON_Tacp6|S3C2410_BANKCON_PMCnorm;
        //regval=S3C2410_BANKCON_Tacs4|S3C2410_BANKCON_Tcos4|S3C2410_BANKCON_Tacc14|
        //        S3C2410_BANKCON_Tcoh4|S3C2410_BANKCON_Tcah4|S3C2410_BANKCON_Tacp6|S3C2410_BANKCON_PMCnorm;

        //outl_p(regval,port);
        __raw_writew(regval,port);

        //regval = __raw_readw(port);
        //printk(KERN_ALERT "BANKCON1's value after change is %#x\n",regval);

//      printk(KERN_ERR "BWSCON1 step is OK!\n");
        if(IRQ_nCF_INS!=0)
        {
                set_irq_type(IRQ_nCF_INS,IRQT_FALLING);
        }
//      printk(KERN_ERR " set_irq_type(IRQ_nCF_INS) is ok\n");
        set_irq_type(IRQ_CF_RDY,IRQT_RISING);
        s3c2410_gpio_pullup(S3C2410_GPF4,0);
        printk(KERN_ALERT "init_pd6710 has successfully finished!\n");

#endif /* CONFIG_ARCH_SMDK2410_CATLAB */

4.修改rsrc_nonstatic.c文件:
//>>>>---------- Modified by Zengyi 2007_5_27
//INT_MODULE_PARM(probe_mem,    1);     /* memory probe? */
INT_MODULE_PARM(probe_mem,  0);     /* memory probe? */
//>>>>---------- end of modify
#ifdef CONFIG_PCMCIA_PROBE
//>>>>---------- Modified by Zengyi 2007_5_27
//INT_MODULE_PARM(probe_io, 1);     /* IO port probe? */
INT_MODULE_PARM(probe_io,   0);     /* IO port probe? */
//>>>>---------- end of modify
INT_MODULE_PARM(mem_limit,  0x10000);
#endif

主要是将probe_io以及probe_mem均设为0,因为我们使用的是static的地址,因此没有必要进行probe.

在修改好以上文件后,在make menuconfig 中将PCMCIA,以及i386支持编入内核,重新编译后的内核就可以
认出我们PD6710.

5.交叉编译cardmgr程序.可以在pcmcia-cs网站中找到.
6.编译orinoco驱动. 选项为Network device support下的Wireless LAN (non-hamradio),<*> Hermes chipset 802.11b support (Orinoco/Prism2/Symbol) 以及<*> Hermes PCMCIA card support.
使用linux 2.6.13中的orinoco驱动时会出现如下错误:
hermes @ e1000000: BAP1 offset error: reg=0x3c id=0xbc offset=0x0
eth1: error -5 reading Rx descriptor. Frame dropped.
但是换成2.4内核中的orinoco驱动后就没有这个错误了.具体原因还没有发现.
7.重新启动以后,无线网卡便可成功启动.


posted @ 2007-05-30 21:21 sardis 阅读(1531) | 评论 (4)编辑 收藏

2007年5月22日 #

字符驱动编写

在linux2.6的内核下编写字符驱动主要的流程为:
在init函数中调用:
register_chrdev_region或者是
alloc_chrdev_region进行设备主,次设备号的注册或申请,如果规定了
主次设备号请使用register_chrdev_region函数,否则可以使用alloc_chrdev_region进行申请。
2.6的内核使用dev_t结构对主次设备号进行管理。
字符设备的注册在2.6内核中则使用了新的cdev_add函数,
可以使用cdev_init函数对cdev结构进行初始化。

cdev_init(&dev->cdev, &cleanerCtl_fops);
dev->cdev.owner = THIS_MODULE;
dev->cdev.ops = &cleanerCtl_fops;
err = cdev_add (&dev->cdev, devno, 1);

同理在exit函数中则可使用
cdev_del(&cleanerCtl_device->cdev);
以及
unregister_chrdev_region(devno, cleanerCtl_nr_devs);

posted @ 2007-05-22 23:08 sardis 阅读(477) | 评论 (0)编辑 收藏

仅列出标题