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

📄 short.c

📁 LINUX设备驱动程序第二版配套源码 LINUX设备驱动程序第二版配套源码 Alessandro rubini&Jonathan corbet著 中国电力出版社 魏永明 骆刚 姜君译 69元
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * short.c -- Simple Hardware Operations and Raw Tests * short.c -- also a brief example of interrupt handling ("short int") * * untested (by now) the hardware r/w * * Tested with 2.0.18 (intel & alpha -- but no irq available for me) * This module won't work on the sparc, where there's no concept of I/O space *  *********/#ifndef __KERNEL__#  define __KERNEL__#endif#ifndef MODULE#  define MODULE#endif#ifdef __sparc__#  error "This module can't compile on the Sparc platform"#else#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/malloc.h>#include <linux/mm.h>#include <linux/ioport.h>#include <linux/interrupt.h>#include <linux/tqueue.h>#include <asm/io.h>#include <asm/segment.h>#include "sysdep.h"int short_major = 0;#ifdef __alpha__int short_base = 0x3bc; /* Hmm.... FIXME */#elseint short_base = 0x378; /* intel: default to lp0 */#endifint short_irq = -1;unsigned long short_buffer = 0;unsigned long volatile short_head;volatile unsigned long short_tail;struct wait_queue *short_queue;static int probe = 0; /* select at load time how to probe irq line */static int bh = 0; /* select at load time whether a bottom-half is used */static int share = 0; /* select at load time whether install a shared irq *//* * 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){    extern struct file_operations short_i_fops;    MOD_INC_USE_COUNT;    if (MINOR(inode->i_rdev) & 0x80) {        filp->f_op = &short_i_fops; /* the interrupt-driven node */    }    return 0;}void short_release (struct inode *inode, struct file *filp){    MOD_DEC_USE_COUNT;}/* first, the port-oriented device */enum short_modes {SHORT_DEFAULT=0, SHORT_PAUSE, SHORT_STRING};read_write_t short_read (struct inode *inode, struct file *filp,                char *buf, count_t count){    int retval = count;    unsigned port = short_base + (MINOR(inode->i_rdev)&0x0f);    int mode = (MINOR(inode->i_rdev)&0x70) >> 4;    unsigned char *kbuf=kmalloc(count, GFP_KERNEL), *ptr;        if (!kbuf) return -ENOMEM;    ptr=kbuf;    switch(mode) {      case SHORT_STRING:#ifndef __alpha__ /* Alpha doesn'e export insb: fall through */        insb(port, ptr, count);        break;#endif      case SHORT_DEFAULT:        while (count--)            *(ptr++) = inb(port);        break;      case SHORT_PAUSE:        while (count--)            *(ptr++) = inb_p(port);        break;      default: /* no more modes defined by now */        retval = -EINVAL;        break;    }    if (retval > 0)        memcpy_tofs(buf, kbuf, retval);    kfree(kbuf);    return retval;}read_write_t short_write (struct inode *inode, struct file *filp,                const char *buf, count_t count){    int retval = count;    unsigned port = short_base + (MINOR(inode->i_rdev)&0x0f);    int mode = (MINOR(inode->i_rdev)&0x70) >> 4;    unsigned char *kbuf=kmalloc(count, GFP_KERNEL), *ptr;    if (!kbuf) return -ENOMEM;    memcpy_fromfs(kbuf, buf, count);    ptr=kbuf;    switch(mode) {      case SHORT_PAUSE:        while (count--)            outb_p(*(ptr++), port);        break;      case SHORT_STRING:#ifndef __alpha__ /* Alpha doesn't export insb: fall through  */        outsb(port, ptr, count);        break;#endif      case SHORT_DEFAULT:        while (count--)            outb(*(ptr++), port);        break;      default: /* no more modes defined by now */        retval = -EINVAL;        break;    }    kfree(kbuf);    return retval;}int short_select (struct inode *inode, struct file *filp,                  int mode, select_table *table){    return mode==SEL_EX ? 0 : 1; /* readable, writable, not-exceptionable */}struct file_operations short_fops = {    NULL,          /* short_lseek */    short_read,    short_write,    NULL,          /* short_readdir */    short_select,    NULL,          /* short_ioctl */    NULL,          /* short_mmap */    short_open,    short_release,    NULL,          /* short_fsync */    NULL,          /* short_fasync */                   /* nothing more, fill with NULLs */};/* then,  the interrupt-related device */read_write_t short_i_read (struct inode *inode, struct file *filp,                char *buf, count_t count){    int count0;    while (short_head == short_tail) {        interruptible_sleep_on(&short_queue);        if (current->signal & ~current->blocked) /* a signal arrived */          return -ERESTARTSYS; /* tell the fs layer to handle it */        /* else, loop */    }    /* count0 is the number of readable data bytes */    count0 = short_head - short_tail;    if (count0 < 0) /* wrapped */        count0 = short_buffer + PAGE_SIZE - short_tail;    if (count0 < count) count = count0;    memcpy_tofs(buf, (char *)short_tail, count);    short_tail += count;    if (short_tail == short_buffer + PAGE_SIZE)        short_tail = short_buffer;    return count;}read_write_t short_i_write (struct inode *inode, struct file *filp,                const char *buf, count_t count){    int written = 0, odd = filp->f_pos & 1;    unsigned port = short_base; /* output to the parallel data latch */    while (written < count)        outb(0xff * ((++written + odd) & 1), port);    filp->f_pos += count;    return written;}struct file_operations short_i_fops = {    NULL,          /* short_i_lseek */    short_i_read,    short_i_write,    NULL,          /* short_i_readdir */    NULL,          /* short_i_select */    NULL,          /* short_i_ioctl */    NULL,          /* short_i_mmap */    short_open,    short_release,    NULL,          /* short_i_fsync */    NULL,          /* short_i_fasync */                   /* nothing more, fill with NULLs */};/* * The interrupt handler has a different prototype whether it * is compiled with kernels older or newer than 1.3.70 */#if LINUX_VERSION_CODE < VERSION_CODE(1,3,70)void short_interrupt(int irq, struct pt_regs *regs)#elsevoid short_interrupt(int irq, void *dev_id, struct pt_regs *regs)#endif{    struct timeval tv;    do_gettimeofday(&tv);    /* Write a 16 byte record. Assume PAGE_SIZE is a multiple of 16 */    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 */}/* * The following two functions are equivalent to the previous one, * but split in top and bottom half. First, a few needed variables */#define NR_TIMEVAL 512 /* length of the array of time values */struct timeval tv_data[NR_TIMEVAL]; /* too lazy to allocate it */volatile struct timeval *tv_head=tv_data;struct timeval *tv_tail=tv_data;static struct tq_struct short_task; /* 0 by now, filled by init_module code */int short_bh_count = 0;void short_bottom_half(void *unused){    int savecount = short_bh_count;    short_bh_count = 0; /* we have already been removed from the queue */    /*     * The bottom half reads the tv array, filled by the top half,     * and prints it to the circular text buffer, which is then consumed     * by reading processes     */    /* First write the number of interrupts that occurred before this bh */    short_head += sprintf((char *)short_head,"bh after %6i\n",savecount);    if (short_head == short_buffer + PAGE_SIZE)        short_head = short_buffer; /* wrap */

⌨️ 快捷键说明

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