?? short.c
字號(hào):
short_head += sprintf((char *)short_head,"bh after %6i\n",savecount); if (short_head == short_buffer + PAGE_SIZE) short_head = short_buffer; /* wrap */ /* * 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__ */
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -