LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 4621|回复: 4

关于linux驱动 io映射 ioremap(附代码)

[复制链接]
发表于 2007-10-9 15:28:47 | 显示全部楼层 |阅读模式
这是我在2.6下写的一个pc104的驱动, io映射, 只是实现读写功能, 但是pc104没有反映(用示波器直接测地址,数据引脚),pc104是16位的, 在x86上运行的,  不知道是ioremap()用错了,还是什么问题, 请高手指点:
#ifndef __KERNEL__
   #define __KERNEL__
#endif

#ifndef MODULE
   #define MODULE
#endif

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/sched.h>
#include <asm/io.h>
#include <linux/interrupt.h>
//#include <linux/cdev.h>
#include <linux/poll.h>
#include <linux/wait.h>
//#include <asm/arch/irqs.h>
#include <linux/mm.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/ioport.h>
#include <asm/uaccess.h>
#include  "pc1044.h"

MODULE_LICENSE("GPL");
MODULE_AUTHOR("GOLDSEA");

#define  pc104_major 126
#define  pc104_minor 0
#define  DEVICENAME  "pc1044"
#define pc104_type   unsigned int
#define pc104_base  0x0210              //物理地址
#define size 16
#define port_len unsigned int

unsigned short rbaseadd;                   //ioremap后的地址

static int pc104_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);
static int pc104_open(struct inode *inode, struct file *filp);
static int pc104_release(struct inode *inode, struct file *filp);


static struct file_operations pc104_fops =
{
    .owner = THIS_MODULE,
    .ioctl = pc104_ioctl,
    .open = pc104_open,
    .release = pc104_release,
};

static int __init pc104_init(void)
{
    int result;
    result = register_chrdev(pc104_major, DEVICENAME, &pc104_fops);
    if (result < 0)
    {
        printk(KERN_ERR DEVICENAME": Unable to get major %d\n", pc104_major);
       // return result;
    }
    else
    {
        printk(KERN_ERR DEVICENAME": init OK !\n");
        request_region(pc104_base, size, DEVICENAME);
        rbaseadd = (unsigned int)ioremap(pc104_base, size);
     // #define ReadPort0  inw *(rbaseadd + 0);
        #define  raddr0   (pc104_type *)(rbaseadd + 0)
        #define  raddr1   (pc104_type *)(rbaseadd + 0x02)
        #define  raddr2   (pc104_type *)(rbaseadd + 0x04)
        #define  raddr3   (pc104_type *)(rbaseadd + 0x06)
        #define  raddr4   (pc104_type *)(rbaseadd + 0x08)
        #define  raddr5   (pc104_type *)(rbaseadd + 0x0a)
        #define  raddr6   (pc104_type *)(rbaseadd + 0x0c)
        #define  raddr7   (pc104_type *)(rbaseadd + 0x0e)
        #define  raddr8   (pc104_type *)(rbaseadd + 0x10)
        printk("base addr is %x\n, raddr0 is %x\n, raddr1 is %x\n",rbaseadd, (unsigned int)raddr0, (unsigned int)raddr1);
    }
  
    return result;
}

static void __exit pc104_exit(void)
{
    int result;
    result = unregister_chrdev(pc104_major, DEVICENAME);
    if(result < 0)
    {
        printk(KERN_ERR DEVICENAME": unregister failure!\n");
    }
    else
    {
        printk(KERN_ERR DEVICENAME": unregister success !\n");
        iounmap(raddr0);
        release_region(pc104_base, size);
        printk("ports are freed successfully!\n");
    }
  
}

static int pc104_open(struct inode *inode, struct file *filp)
{
    int num;
  //  unsigned int usage = 0;
   
    num =MINOR (inode -> i_rdev);
    if(num != pc104_minor)
    {
        return -ENODEV;
    }
    //MOD_INC_USE_COUNT;
    //int try_module_get(&module);
//   usage++;
   
    return 0;
}

static int pc104_release(struct inode *inode, struct file *filp)
{
    int num;
    num = MINOR(inode -> i_rdev);
   
    if(num != pc104_minor)
    {
        return -ENODEV;
    }
   // MOD_DEC_USE_COUNT;
  //  usage--;
    return 0;
}


static int pc104_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
{

    int num;
    u16 temp;

    num = MINOR(inode ->i_rdev);
    if(num != pc104_minor)
    {
        return -ENOTTY;
    }
    if(_IOC_TYPE(cmd) != PC104_IOC_MAGIC)
    {
        return -ENOTTY;
    }
    if(_IOC_NR(cmd) >= PC104_MAX)
    {
        return -ENOTTY;
    }
   
    switch(cmd)
    {
        case READ0:     
             temp = inw((port_len)*raddr0);
             put_user(temp, (unsigned long *)arg);
             break;

        case READ1:
             temp = inw((port_len)*raddr1);
             put_user(temp, (unsigned long *)arg);
             break;

        case READ2:
             temp = inw((port_len)*raddr2);
             put_user(temp, (unsigned long *)arg);
             break;

        case READ3:
             temp = inw((port_len)*raddr3);
             put_user(temp, (unsigned long *)arg);
             break;

        case READ4:
             temp = inw((port_len)*raddr4);
             put_user(temp, (unsigned long *)arg);
             break;
        case WRITE5:
             get_user(temp, (unsigned long *)arg);
             outw(temp, (port_len)*raddr0);
             break;
        case WRITE6:
             get_user(temp, (unsigned long *)arg);
             outw(temp, (port_len)*raddr1);
             break;
        case WRITE7:
             get_user(temp, (unsigned long*)arg);
             outw(temp, (port_len)*raddr2);
             break;
        case WRITE8:
             get_user(temp, (unsigned long *)arg);
             outw(temp, (port_len)*raddr3);
             break;
        default:
            return -ENOTTY;
    }
    return 0;
}

module_init(pc104_init);
module_exit(pc104_exit);
发表于 2007-10-9 17:30:11 | 显示全部楼层
是 PC104 还是 PC104+ ?
PC104 对应于 ISA,PC104+ 对应于 PCI 内核都有实现,
可以考虑在内核的 PCI 驱动上做你的高层驱动免得麻烦啊。

不过,我对这个问题倒是很有兴趣,自动化和数控上用 PC104 很多,
研究一下直接操作也不错。呵呵。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2007-10-11 08:21:27 | 显示全部楼层
问题解决了, request_region之后, 直接inw outw ,无需ioremap
回复 支持 反对

使用道具 举报

发表于 2009-8-31 14:42:35 | 显示全部楼层
最近正在做,有资料和源码发我一份了,非常感谢。
回复 支持 反对

使用道具 举报

发表于 2009-8-31 14:45:17 | 显示全部楼层
忘了邮件号码了:li_feiqing@126.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表