LoveUnix » 编程开发 & Rational » 测试中断,但是申请空的i/o资源却总是不成功,看看哪里出错?!! 先谢了!
让LU留住您的每

一天 让LU博客留住您的每一天
2005-11-18 15:13 ling
测试中断,但是申请空的i/o资源却总是不成功,看看哪里出错?!! 先谢了!

程序源代码如下,改至linux设备驱动程序的示例 short,就是只保留它的中断部分,
但每次加载模块,都说资源忙,申请不成功. 而且对该资源好像有破 huai--------???????why???

code:
/*
* Simple Hardware Operations and Raw Tests
* simpleirq.c -- a brief example of interrupt handling ("simple_irq")
*/

#ifndef __KERNEL__
#  define __KERNEL__
#endif
#ifndef MODULE
#  define MODULE
#endif


#include <linux/config.h>
#include <linux/module.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/slab.h>   /*<linux/malloc.h>*/
#include <linux/mm.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/tqueue.h>

#include <asm/uaccess.h>
#include <asm/io.h>


#define SIMPLE_NR_PORTS 8 /* use 8 ports by default */

/*
* all of the parameters have no "simple_" prefix, to save typing when
* specifying them at load time
*/
static int major = 0; /* dynamic by default */
MODULE_PARM(major, "i");


/* default is the first printer port on PC's. "simple_base" is there too
   because it's what we want to use in the code */
static unsigned long base = 0x378;
unsigned long simple_base = 0;
MODULE_PARM(base, "l");

/* Since simple_base is vremapped in case use_mem==1, remember the phys addr. */
unsigned long simple_phys;

/* The interrupt line is undefined by default. "simple_irq" is as above */
static int irq = -1;
volatile int simple_irq = -1;
MODULE_PARM(irq, "i");

unsigned long simple_buffer = 0;
unsigned long volatile simple_head;
volatile unsigned long simple_tail;
DECLARE_WAIT_QUEUE_HEAD(simple_queue);


/*
* Atomicly increment an index into simple_buffer
*/
static inline void simple_incr_bp(volatile unsigned long *index, int delta)
{
    unsigned long newone = *index + delta;
    barrier ();  /* Don't optimize these two together */
    *index = ( newone >= (simple_buffer + PAGE_SIZE)) ? simple_buffer : newone;
}


/*
* 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 simple_open (struct inode *inode, struct file *filp)
{
     MOD_INC_USE_COUNT;
      return 0;
}



int simple_release (struct inode *inode, struct file *filp)
{
    MOD_DEC_USE_COUNT;
    return 0;
}



/* then,  the interrupt-related device */

ssize_t simple_i_read (struct file *filp, char *buf, size_t count, loff_t *f_pos)
{
    int count0;

    while (simple_head == simple_tail)
    {
        interruptible_sleep_on(&simple_queue);
        if (signal_pending (current))  /* a signal arrived */
          return -ERESTARTSYS; /* tell the fs layer to handle it */
        /* else, loop */
    }
    /* count0 is the number of readable data bytes */
    count0 = simple_head - simple_tail;
    if (count0 < 0) /* wrapped */
        count0 = simple_buffer + PAGE_SIZE - simple_tail;
    if (count0 < count)
        count = count0;

    if (copy_to_user(buf, (char *)simple_tail, count))
        return -EFAULT;
    simple_incr_bp (&simple_tail, count);
    return count;
}

ssize_t simple_i_write (struct file *filp, const char *buf, size_t count,
                loff_t *f_pos)
{
    int written = 0, odd = *f_pos & 1;
    unsigned long address = simple_base; /* output to the parallel data latch */

    while (written < count)
      outb(0xff * ((++written + odd) & 1), address); //send interrupt
   
    *f_pos += count;
    return written;
}


struct file_operations simple_i_fops = {
    read: simple_i_read,
    write: simple_i_write,
    open: simple_open,
    release: simple_release,
};

void simple_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
    struct timeval tv;
    int written;

    do_gettimeofday(&tv);

    /* Write a 16 byte record. Assume PAGE_SIZE is a multiple of 16 */
    written = sprintf((char *)simple_head,"%08u.%06u\n",
                          (int)(tv.tv_sec % 100000000), (int)(tv.tv_usec));
    simple_incr_bp(&simple_head, written);
    wake_up_interruptible(&simple_queue); /* awake any reading process */
}



/* Finally, init and cleanup */

int simple_init(void)
{
    int result;

    /*
     * first, sort out the base/simple_base ambiguity: we'd better
     * use simple_base in the code, for clarity, but allow setting
     * just "base" at load time. Same for "irq".
     */
    simple_base = base;
    simple_irq = irq;

    /* Set up owner pointers.*/
   
    SET_MODULE_OWNER(&simple_i_fops);

    /* Get our needed resources. */
    result = check_region(simple_base, SIMPLE_NR_PORTS);
    if (result)
    {
        printk(KERN_INFO "simple: can't get I/O port address 0x%lx\n",
               simple_base);
        return result;
    }
    request_region(simple_base, SIMPLE_NR_PORTS, "simpleirq");
   
    result = register_chrdev(major, "simpleirq", &simple_i_fops);
    if (result < 0)
    {
        printk(KERN_INFO "simple: can't get major number\n");
        release_region(simple_base,SIMPLE_NR_PORTS);
        return result;
    }
    if (major == 0)
      major = result; /* dynamic */

    simple_buffer = __get_free_pages(GFP_KERNEL,0); /* never fails */
    simple_head = simple_tail = simple_buffer;

   
    /*
     * Now we deal with the interrupt: either kernel-based
     * autodetection, DIY detection or default number
     */

    if (simple_irq < 0) /* not yet specified: force the default on */
        switch(simple_base)
       {
          case 0x378: simple_irq = 7; break;
          case 0x278: simple_irq = 2; break;
          case 0x3bc: simple_irq = 5; break;
        }

   
    if (simple_irq >= 0)
    {
        result = request_irq(simple_irq, simple_interrupt,
                             SA_INTERRUPT, "simpleirq", NULL);
        if (result)
        {
            printk(KERN_INFO "simple: can't get assigned irq %i\n",
                   simple_irq);
            simple_irq = -1;
        }
        else { /* actually enable it -- assume this *is* a parallel port */
            outb(0x10,simple_base+2);
        }
    }
}

void simple_cleanup(void)
{
    if (simple_irq >= 0) {
        outb(0x0, simple_base + 2);   /* disable the interrupt */
        free_irq(simple_irq, NULL);
        
    }
        
    unregister_chrdev(major, "simpleirq");
    release_region(simple_base,SIMPLE_NR_PORTS);
    if (simple_buffer)
       free_page(simple_buffer);
}

module_init(simple_init);
module_exit(simple_cleanup);


$gcc -I/usr/src/linux-2.4.18-3/include -D__KERNEL__ -DMODULE -DLINUX -c  simpleirq.c
$insmod simpleirq.o
Warning: loading simpleirq.o will taint the kernel: no license
simpleirq.o: init_module: Device or resource busy
Hint: insmod errors can be caused by incorrect module parameters, including invalid IO or IRQ parameters

$cat /var/log/messages
.....
can't get I/O port address 0x378

$cat  /proc/ioports  
Segmentation fault
$cat /proc/interrupts
Segmentation fault
$cat /proc/devices
Segmentation fault

2005-11-22 13:41 ling
怎么都没人响应呢?

怎么都没人响应呢? 是问题没有讲清楚吗?
各位斑竹、各位高手请你们显身啊?!!!

2007-7-8 23:06 fang3651
在linux启动的时候,提问是否需要确认模块连接关系,这时按键盘I,系统会询问你是否需要启动你需要的模块。当询问服务cups,选择N,打印设备服务模块不会启动,即模块parport和parpoer_pc不会自动启动,这时我们的模块就能申请到0X378io资源.

2007-7-9 18:49 oraix
Device or resource busy
can't get I/O port address 0x378
楼上说的应该有关系, 设备已经被占用
Segmentation fault的问题可能是有bug导致的, 2.6.14 and 2.6.14.2的版本有这个问题, 或者是有驱动卸载的时候退出不干净

2007-8-29 18:20 bobopro
linux的i/o端口

当卸载了parport_pc、lpt等模块后,腾出了0x378端口,默认的short模块倒是能装载了,0x378也出现在/pro/ioport中,但并口的输出始终为5.05V,why?????
我用outp.c也试过了,当未卸载parport_pc模块时,并口的输出是可控的,此时0=0.07V,1=4.60V;但卸载parport_pc后,outp.c的输出也固定在5.05V。
linux的i/o端口控制究竟是怎么回事?????

页: [1]


Powered by Discuz! Archiver 5.5.0  © 2001-2006 Comsenz Inc.