• 硬件通信


    1. 内存空间与io空间是对 cup 处理器地址空间的划分,在一个 cup的指令体系中内存空间和io空间的访问指令是不一样的。

     2. 与硬件通信的流程参考 ldd3 实例代码

    #include <linux/config.h>
    #include <linux/module.h>
    #include <linux/moduleparam.h>
    #include <linux/init.h>
    
    #include <linux/sched.h>
    #include <linux/kernel.h>    /* printk() */
    #include <linux/fs.h>        /* everything... */
    #include <linux/errno.h>    /* error codes */
    #include <linux/delay.h>    /* udelay */
    #include <linux/kdev_t.h>
    #include <linux/slab.h>
    #include <linux/mm.h>
    #include <linux/ioport.h>
    #include <linux/interrupt.h>
    #include <linux/workqueue.h>
    #include <linux/poll.h>
    #include <linux/wait.h>
    
    #include <asm/io.h>
    
    #define SHORT_NR_PORTS    8    /* use 8 ports by default */
    
    /*
     * all of the parameters have no "short_" prefix, to save typing when
     * specifying them at load time
     */
    static int major = 0;    /* dynamic by default */
    module_param(major, int, 0);
    
    static int use_mem = 0;    /* default is I/O-mapped */
    module_param(use_mem, int, 0);
    
    
    /* default is the first printer port on PC's. "short_base" is there too
       because it's what we want to use in the code */
    static unsigned long base = 0x378;
    unsigned long short_base = 0;
    module_param(base, long, 0);
    
    
    
    MODULE_AUTHOR ("Alessandro Rubini");
    MODULE_LICENSE("Dual BSD/GPL");
    
    
    
    
    /*
     * The devices with low minor numbers write/read burst of data to/from
     * specific I/O ports (by default the parallel ones).
     * 
     * The device with 128 as minor number returns ascii strings telling
     * when interrupts have been received. Writing to the device toggles
     * 00/FF on the parallel data lines. If there is a loopback wire, this
     * generates interrupts.  
     */
    
    int short_open (struct inode *inode, struct file *filp)
    {
    
        return 0;
    }
    
    
    int short_release (struct inode *inode, struct file *filp)
    {
        return 0;
    }
    
    
    /* first, the port-oriented device */
    
    enum short_modes {SHORT_DEFAULT=0, SHORT_PAUSE, SHORT_STRING, SHORT_MEMORY};
    
    
    ssize_t do_short_read (struct inode *inode, struct file *filp, char __user *buf,
            size_t count, loff_t *f_pos)
    {
        int retval = count, minor = iminor (inode);
        unsigned long port = short_base + (minor&0x0f);
        void *address = (void *) short_base + (minor&0x0f);
        int mode = (minor&0x70) >> 4;
        unsigned char *kbuf = kmalloc(count, GFP_KERNEL), *ptr;
        
        if (!kbuf)
            return -ENOMEM;
        ptr = kbuf;
    
        if (use_mem)
            mode = SHORT_MEMORY;
        
        switch(mode) {
            case SHORT_STRING:
            insb(port, ptr, count);
            rmb();
            break;
    
            case SHORT_DEFAULT:
            while (count--) {
                *(ptr++) = inb(port);
                rmb();
            }
            break;
    
            case SHORT_MEMORY:
            
        
                while (count--) {
                *ptr++ = ioread8(address);
                rmb();
    break;        }   case SHORT_PAUSE:
            while (count--) {
                *(ptr++) = inb_p(port);
                rmb();
            }
            break;
        
            
          default: /* no more modes defined by now */
            retval = -EINVAL;
            break;
        }  
          
        if ((retval > 0) && copy_to_user(buf, kbuf, retval))
            retval = -EFAULT;
        kfree(kbuf);      
        return retval;
    }
    
    
    /*
     * Version-specific methods for the fops structure.  FIXME don't need anymore.
     */
    ssize_t short_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
    {
        return do_short_read(filp->f_dentry->d_inode, filp, buf, count, f_pos);
    }
    
    
    
    ssize_t do_short_write (struct inode *inode, struct file *filp, const char __user *buf,
            size_t count, loff_t *f_pos)
    {
        int retval = count, minor = iminor(inode);
        unsigned long port = short_base + (minor&0x0f);
        void *address = (void *) short_base + (minor&0x0f);
        int mode = (minor&0x70) >> 4;
        unsigned char *kbuf = kmalloc(count, GFP_KERNEL), *ptr;
    
        if (!kbuf)
            return -ENOMEM;
        if (copy_from_user(kbuf, buf, count))
            return -EFAULT;
        ptr = kbuf;
    
        if (use_mem)
            mode = SHORT_MEMORY;
    
        switch(mode) {
        case SHORT_PAUSE:
            while (count--) {
                outb_p(*(ptr++), port);
                wmb();
            }
            break;
    
        case SHORT_STRING:
            outsb(port, ptr, count);
            wmb();
            break;
    
        case SHORT_DEFAULT:
            while (count--) {
                outb(*(ptr++), port);
                wmb();
            }
            break;
    
        case SHORT_MEMORY:
            while (count--) {
                iowrite8(*ptr++, address);
                wmb();
            }
            break;
    
        default: /* no more modes defined by now */
            retval = -EINVAL;
            break;
        }
        kfree(kbuf);
        return retval;
    }
    
    
    ssize_t short_write(struct file *filp, const char __user *buf, size_t count,
            loff_t *f_pos)
    {
        return do_short_write(filp->f_dentry->d_inode, filp, buf, count, f_pos);
    }
    
    
    
    
    unsigned int short_poll(struct file *filp, poll_table *wait)
    {
        return POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM;
    }
    
    
    
    
    
    
    struct file_operations short_fops = {
        .owner     = THIS_MODULE,
        .read     = short_read,
        .write     = short_write,
        .poll     = short_poll,
        .open     = short_open,
        .release = short_release,
    };
    
    
    
    
    
    /* Finally, init and cleanup */
    
    int short_init(void)
    {
        int result;
    
        /*
         * first, sort out the base/short_base ambiguity: we'd better
         * use short_base in the code, for clarity, but allow setting
         * just "base" at load time. Same for "irq".
         */
        short_base = base;
    
        /* Get our needed resources. */
        if (!use_mem) {
            if (! request_region(short_base, SHORT_NR_PORTS, "short")) {
                printk(KERN_INFO "short: can't get I/O port address 0x%lx
    ",
                        short_base);
                return -ENODEV;
            }
    
        } else {
            if (! request_mem_region(short_base, SHORT_NR_PORTS, "short")) {
                printk(KERN_INFO "short: can't get I/O mem address 0x%lx
    ",
                        short_base);
                return -ENODEV;
            }
    
            /* also, ioremap it */
            short_base = (unsigned long) ioremap(short_base, SHORT_NR_PORTS);
            /* Hmm... we should check the return value */
        }
        /* Here we register our device - should not fail thereafter */
        result = register_chrdev(major, "short", &short_fops);
        if (result < 0) {
            printk(KERN_INFO "short: can't get major number
    ");
            release_region(short_base,SHORT_NR_PORTS);  /* FIXME - use-mem case? */
            return result;
        }
        if (major == 0) major = result; /* dynamic */
        
    
        /*
         * Now we deal with the interrupt: either kernel-based
         * autodetection, DIY detection or default number
         */
    
    
    
    
    void short_cleanup(void)
    {
        
    
        unregister_chrdev(major, "short");
        if (use_mem) {
            iounmap((void __iomem *)short_base);
            release_mem_region(short_base, SHORT_NR_PORTS);
        } else {
            release_region(short_base,SHORT_NR_PORTS);
        }
    }
    
    module_init(short_init);
    module_exit(short_cleanup);
    View Code
  • 相关阅读:
    Java实现 LeetCode 437 路径总和 III(三)
    Java实现 LeetCode 436 寻找右区间
    Java实现 LeetCode 436 寻找右区间
    Java实现 LeetCode 436 寻找右区间
    Java实现 LeetCode 435 无重叠区间
    Java实现 LeetCode 435 无重叠区间
    Makefile第一讲:一个简单的Makefile
    GCC常用参数
    GCC参数详解
    linux .o,.a,.so文件解析
  • 原文地址:https://www.cnblogs.com/youngvoice/p/4846767.html
Copyright © 2020-2023  润新知