⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 short.c

📁 LINUX设备驱动程序第二版配套源码 LINUX设备驱动程序第二版配套源码 Alessandro rubini&Jonathan corbet著 中国电力出版社 魏永明 骆刚 姜君译 69元
💻 C
📖 第 1 页 / 共 2 页
字号:
    /*     * Then, write the time values. Write exactly 16 bytes at a time,     * so it aligns with PAGE_SIZE     */    do {        short_head += sprintf((char *)short_head,"%08u.%06u\n",                              (int)(tv_tail->tv_sec % 100000000),                              (int)(tv_tail->tv_usec));        if (short_head == short_buffer + PAGE_SIZE)            short_head = short_buffer; /* wrap */                tv_tail++;        if (tv_tail == (tv_data + NR_TIMEVAL) )             tv_tail = tv_data; /* wrap */            } while (tv_tail != tv_head);    wake_up_interruptible(&short_queue); /* awake any reading process */}/* * use two implementations: before version 1.3.70 you couldn't * re-enqueue tasks, and "dev_id" was missing. I like re-enqueueing, * so I'd better keep the modern version clean */#if LINUX_VERSION_CODE < VERSION_CODE(1,3,70) /* old */void short_bh_interrupt(int irq, struct pt_regs *regs){    do_gettimeofday(tv_head);    tv_head++;    if (tv_head == (tv_data + NR_TIMEVAL) )         tv_head = tv_data; /* wrap */    /* Queue the bh. Don't re-enqueue */    if (!short_bh_count)        queue_task_irq_off(&short_task, &tq_immediate);    mark_bh(IMMEDIATE_BH);    short_bh_count++; /* record that an interrupt arrived */}#else /* recent */void short_bh_interrupt(int irq, void *dev_id, struct pt_regs *regs){    do_gettimeofday(tv_head);    tv_head++;    if (tv_head == (tv_data + NR_TIMEVAL) )         tv_head = tv_data; /* wrap */    /* Queue the bh. Don't care for multiple enqueueing */    queue_task_irq_off(&short_task, &tq_immediate);    mark_bh(IMMEDIATE_BH);    short_bh_count++; /* record that an interrupt arrived */}#endif#if LINUX_VERSION_CODE < VERSION_CODE(1,3,70)void short_sh_interrupt(int irq, struct pt_regs *regs){    void *dev_id = NULL;#elsevoid short_sh_interrupt(int irq, void *dev_id, struct pt_regs *regs){#endif    int value;    struct timeval tv;    /* If it wasn't short, return immediately */    value = inb(short_base);    if (!(value & 0x80)) return;            /* clear the interrupting bit */    outb(value & 0x7F, short_base);    /* the rest is unchanged */    do_gettimeofday(&tv);    short_head += sprintf((char *)short_head,"%08u.%06u\n",                          (int)(tv.tv_sec % 100000000), (int)(tv.tv_usec));    if (short_head == short_buffer + PAGE_SIZE)        short_head = short_buffer; /* wrap */    wake_up_interruptible(&short_queue); /* awake any reading process */}#if LINUX_VERSION_CODE >= VERSION_CODE(1,3,30)void short_kernelprobe(void){    int count = 0;    do {        unsigned long mask;        mask = probe_irq_on();        outb_p(0x10,short_base+2); /* enable reporting */        outb_p(0x00,short_base);   /* clear the bit */        outb_p(0xFF,short_base);   /* set the bit: interrupt! */        outb_p(0x00,short_base+2); /* disable reporting */        short_irq = probe_irq_off(mask);        if (short_irq == 0) { /* none of them? */            printk(KERN_INFO "short: no irq reported by probe\n");            short_irq = -1;        }        /*         * if more than one line has been activated, the result is         * negative. We should service the interrupt (no need for lpt port)         * and loop over again. Loop at most five times, then give up         */    } while (short_irq < 0 && count++ < 5);    if (short_irq < 0)        printk("short: probe failed %i times, giving up\n", count);}#elsevoid short_kernelprobe(void){    printk(KERN_WARNING "short: kernel probing not available before 1.3.30\n");}#endif /* 1.3.30 */#if LINUX_VERSION_CODE < VERSION_CODE(1,3,70)void short_probing(int irq, struct pt_regs *regs)#elsevoid short_probing(int irq, void *dev_id, struct pt_regs *regs)#endif{    if (short_irq == 0) short_irq = irq;    /* found */    if (short_irq != irq) short_irq = -irq; /* ambiguous */}void short_selfprobe(void){    int trials[] = {3, 5, 7, 9, 0};    int tried[]  = {0, 0, 0, 0, 0};    int i, count = 0;     /*      * install the probing handler for all possible lines. Remember      * the result (0 for success, or -EBUSY) in order to only free      * what has been acquired      */    for (i=0; trials[i]; i++)        tried[i] = request_irq(trials[i], short_probing,                               SA_INTERRUPT, "short probe", NULL);    do {        short_irq = 0; /* none got, yet */        outb_p(0x10,short_base+2); /* enable */        outb_p(0x00,short_base);        outb_p(0xFF,short_base); /* toggle the bit */        outb_p(0x10,short_base+2); /* disable */        /* the value has been set by the handler */        if (short_irq == 0) { /* none of them? */            printk(KERN_INFO "short: no irq reported by probe\n");        }        /*         * If more than one line has been activated, the result is         * negative. We should service the interrupt (but the lpt port         * doesn't need it) and loop over again. Do it at most 5 times         */    } while (short_irq <=0 && count++ < 5);    /* end of loop, uninstall the handler */    for (i=0; trials[i]; i++)        if (tried[i] == 0)            free_irq(trials[i], NULL);    if (short_irq < 0)        printk("short: probe failed %i times, giving up\n", count);}int init_module(void){    int result = check_region(short_base,4);    if (result) {        printk(KERN_INFO "short: can't get I/O address 0x%x\n",short_base);        return result;    }    request_region(short_base,4,"short");    result = register_chrdev(short_major, "short", &short_fops);    if (result < 0) {        printk(KERN_INFO "short: can't get major number\n");        release_region(short_base,4);        return result;    }    if (short_major == 0) short_major = result; /* dynamic */    short_buffer = __get_free_page(GFP_KERNEL); /* never fails */    short_head = short_tail = short_buffer;    /*     * Fill the short_task structure, used for the bottom half handler     */    short_task.routine = short_bottom_half;    short_task.data = NULL; /* unused */    /*     * Now we deal with the interrupt: either kernel-based     * autodetection, DIY detection or default number     */    if (short_irq < 0 && probe == 1)        short_kernelprobe();    if (short_irq < 0 && probe == 2)        short_selfprobe();    if (short_irq < 0) /* not yet specified: force the default on */        switch(short_base) {          case 0x378: short_irq = 7; break;          case 0x278: short_irq = 2; break;          case 0x3bc: short_irq = 5; break;        }    /*     * If shared has been specified, installed the shared handler     * instead of the normal one. Do it first, before a -EBUSY will     * force short_irq to -1.     */    if (short_irq >= 0 && share > 0) {        free_irq(short_irq,NULL);        result = request_irq(short_irq, short_sh_interrupt,                             SA_SHIRQ | SA_INTERRUPT,"short",                             short_sh_interrupt);        if (result) {            printk(KERN_INFO "short: can't get assigned irq %i\n", short_irq);            short_irq = -1;        }        else { /* actually enable it -- assume this *is* a parallel port */            outb(0x10,short_base+2);        }        return 0; /* the rest of the function only installs handlers */    }    if (short_irq >= 0) {        result = request_irq(short_irq, short_interrupt,                             SA_INTERRUPT, "short", NULL);        if (result) {            printk(KERN_INFO "short: can't get assigned irq %i\n",                   short_irq);            short_irq = -1;        }        else { /* actually enable it -- assume this *is* a parallel port */            outb(0x10,short_base+2);        }    }    /*     * Ok, now change the interrupt handler if using top/bottom halves     * has been requested     */    if (short_irq >= 0 && bh > 0) {        free_irq(short_irq,NULL);        result = request_irq(short_irq, short_bh_interrupt,                             SA_INTERRUPT,"short-bh", NULL);        if (result) {            printk(KERN_INFO "short-bh: can't get assigned irq %i\n",                   short_irq);            short_irq = -1;        }    }    return 0;}void cleanup_module(void){    if (short_irq >= 0) {        if (!share) free_irq(short_irq, NULL);        else free_irq(short_irq, short_sh_interrupt);    }            unregister_chrdev(short_major, "short");    release_region(short_base,4);    if (short_buffer) free_page(short_buffer);}#endif /* __sparc__ */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -