LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 691|回复: 1

一个近乎真是的字符模块驱动(转载)

[复制链接]
发表于 2006-12-11 17:33:02 | 显示全部楼层 |阅读模式
../include/linux/foo.h

  1. /*
  2. *  /usr/include/linux/foo.h
  3. *
  4. *  Copyright (C) 1997  Fernando Matia
  5. */

  6. /*
  7. *     foo.h
  8. *
  9. * Header file for foo.c
  10. *
  11. */

  12. #ifndef _FOO_H
  13. #define _FOO_H

  14. #include <sys/ioctl.h>      /* For _IO macros */

  15. #define OK   0

  16. #define NOT_PRESENT 0
  17. #define DEV_READY   1
  18. #define DEV_IN_USE  2

  19. /* 0x09 has been set arbitrarily by Fernando Matia */
  20. #define FOO_MAGIC   0x09
  21. #define FOO_RESET   _IO(FOO_MAGIC, 0x01)
  22. #define FOO_SET     _IOW(FOO_MAGIC, 0x02, int)
  23. #define FOO_GET     _IOR(FOO_MAGIC, 0x03, int)

  24. /* These are some hardware specific defines for the PC's */
  25. /* 8259 interrupt controller chips                       */
  26. #define MASTER_8259    0x20
  27. #define SLAVE_8259     0xa0
  28. #define TOUCH_INT      0x0c           /* irq 12          */
  29. #define TOUCH_8259     SLAVE_8259     /* int cont addr   */
  30. #define TOUCH_MASK     0x10           /* int bit mask    */

  31. /* This is the FOO card's base address */
  32. #define FOO_IO_BASE_ADDRESS  0x1c0   /* address of first 8255 */

  33. /* These are the ports available on the card */
  34. #define FOO_PORT_1        (FOO_IO_BASE_ADDRESS)
  35. #define FOO_PORT_2        (FOO_IO_BASE_ADDRESS + 1)
  36. #define FOO_PORT_3        (FOO_IO_BASE_ADDRESS + 2)
  37. #define FOO_PORT_4        (FOO_IO_BASE_ADDRESS + 3)

  38. #define FOO_NUM_PORTS     4
  39. #define FOO_TESTPORT      FOO_PORT_3              /* Port to test hard */
  40. #define FOO_DUMMYVAL      0x8a                    /* Value to write    */

  41. int foo_init(void);

  42. #endif /* _FOO_H */
复制代码

../driver/char/foo.c

  1. /*
  2. *  linux/drivers/foo.c
  3. *
  4. *  Copyright (C) 1997  Fernando Matia
  5. */

  6. /*
  7. *        foo.c
  8. *
  9. * This module exports the foo io functions:
  10. *
  11. *     'foo_open()'
  12. *     'foo_write()'
  13. *     'foo_read()'
  14. *     'foo_ioctl()'
  15. *     'foo_release()'
  16. *
  17. */

  18. #undef  FOO_DEBUG               /* Do you want to debug the driver?       */
  19. #define FOO_NAME "foo"          /* A name for the driver                  */

  20. #include <linux/foo.h>          /* foo driver definitions and structures  */
  21. #include <linux/sched.h>        /* For request_irq() & free_irq()         */
  22. #include <linux/errno.h>        /* For error numbers                      */
  23. #include <linux/kernel.h>       /* For printk()                           */
  24. #include <linux/time.h>         /* For struct timeval                     */
  25. #include <linux/major.h>        /* For major devices numbers              */
  26. #include <linux/fs.h>           /* For struct file_operations             */
  27.                                 /* and register_*dev()                    */
  28. #include <asm/segment.h>        /* For memcpy_*fs()                       */
  29. #include <asm/io.h>             /* For inb*() and outb*                   */
  30. #include <asm/system.h>         /* For assembler nop, cli and sti         */
  31. extern unsigned long int loops_per_sec;  /* Used in delay.h by udealy()   */
  32. #include <asm/delay.h>          /* For udelay() < 1ms                     */
  33. #include <linux/ioport.h>       /* For check_region(), request_region(),  */
  34.                                 /* release_region() and get_ioport_list() */
  35. #include <linux/mm.h>           /* verify_area() and VERIFY_READ or WRITE */

  36. static int foo_status = NOT_PRESENT;        /* Status of the device       */
  37. static int foo_x;                           /* Driver internal data       */
  38. static long foo_y;

  39. static char init_8259_M_imr, init_8259_S_imr; /* Interrupt mask registers */


  40. /**************************************************************************/
  41. /* ----  TIMING SPECIFIC FUNCTIONS -------------------------------------- */
  42. /**************************************************************************/

  43. /* shdel is a short delay calculated.                                     */
  44. /* If used in an int routine keep the delay VERY small.                   */
  45. static void vshdel(unsigned int cmsecs)  /* Call with # of 10 usecs delays*/
  46. {
  47.     udelay(cmsecs*10);
  48. }


  49. /**************************************************************************/
  50. /* ----  CARD SPECIFIC FUNCTIONS ---------------------------------------- */
  51. /**************************************************************************/

  52. static void Write_port(int *value)
  53. {
  54.     outb_p(*value, FOO_PORT_1);
  55. }

  56. static void Read_port(long *value)
  57. {
  58.     *value = (float) (inb_p(FOO_PORT_4) << 8);
  59.     vshdel(200);
  60.     *value += (float) inb_p(FOO_PORT_3);
  61.     *value = foo_x * 100;
  62. }


  63. /*************************************************************************/
  64. /* ---- Interrupt FUNCTIONS -------------------------------------------- */
  65. /*************************************************************************/

  66. /* Mask an interrupt */
  67. static void mask_interrupt(unsigned char mask, unsigned short ad8259)
  68. {
  69.     /* This sets the 8259 mask bit high to disable the interrupt */
  70.     outb_p(inb_p(ad8259+1) | mask, ad8259+1);
  71. }

  72. /* Unmask an interrupt                                                   */
  73. /* It takes the mask byte holding a 1 in the appropriate bit for the int */
  74. /* to unmask and the base address of the 8259 chip.                      */
  75. static void unmask_interrupt(unsigned char mask, unsigned short ad8259)
  76. {
  77.     /* This sets the 8259 mask bit low to enable the interrupt */
  78.     outb_p(inb_p(ad8259+1) & (~mask), ad8259+1);
  79. }

  80. static void touch_irq_routine(int irq, void *dev_id, struct pt_regs *regs)
  81. {
  82.     cli();
  83.     /* Do an E-stop or something... */
  84.     sti();
  85. }

  86. /* This installs the touch interrupt at the IRQ specified by TOUCH_INT.  */
  87. static int install_touch(void)
  88. {
  89.     int error;

  90.     cli();  /* Stop interrupts */
  91.     error = request_irq(TOUCH_INT, touch_irq_routine, SA_INTERRUPT,
  92.                         FOO_NAME, NULL);
  93.     switch( error ) {
  94.         case  OK    : break;
  95.         case -EINVAL:
  96.         case -EBUSY :
  97.         default     : return error;
  98.         }
  99.     unmask_interrupt(TOUCH_MASK, TOUCH_8259);            /* Mask off */
  100.     sti();

  101.     return OK;
  102. }

  103. static void remove_touch(void)
  104. {
  105.     cli();                                    /* Turn off interrupts */
  106.     free_irq(TOUCH_INT, NULL);
  107.     mask_interrupt(TOUCH_MASK, TOUCH_8259);               /* Mask on */
  108.     sti();                                      /* Turn ints back on */
  109. }

  110. /**************************************************************************/
  111. /* ----  DRIVER SPECIFIC FUNCTIONS -------------------------------------- */
  112. /**************************************************************************/

  113. static int foo_read(struct inode *inode, struct file *file,
  114.                      char *buf, int count)
  115. {
  116.     int num_bytes;     /* Number of bytes to return */

  117.     Read_port(&foo_y);
  118.     num_bytes = sizeof(long);
  119.     memcpy_tofs(buf, (char *) &foo_y, num_bytes);

  120.     /* Successful return point */
  121.     return num_bytes;
  122. }

  123. static int foo_write(struct inode *inode, struct file *file,
  124.                       const char *buf, int count)
  125. {
  126.     int num_bytes;     /* Number of bytes to read */

  127.     num_bytes = sizeof(int);
  128.     memcpy_fromfs((char *) &foo_x, buf, num_bytes);
  129.     Write_port(&foo_x);

  130.     /* Successful return point */
  131.     return num_bytes;
  132. }

  133. static int foo_ioctl(struct inode *inode, struct file *file,
  134.                       unsigned int cmd, unsigned long arg)
  135. {
  136.     int error;
  137.     int num;
  138. #ifdef FOO_DEBUG
  139.     printk("cmd = 0x%08x\n", cmd);
  140.     printk("arg = %lu\n", arg);
  141. #endif
  142.     switch( cmd ) {
  143.         case FOO_RESET     : foo_y = foo_x = 0;
  144.                              break;
  145.         case FOO_SET       : error = verify_area(VERIFY_READ,
  146.                                     (void *) arg, sizeof(int));
  147.                              if( error ) return error;
  148.                              num = get_fs_byte((int *) arg);
  149.                              foo_y = (long) num * (long) foo_x;
  150.                              break;
  151.         case FOO_GET       : error = verify_area(VERIFY_WRITE,
  152.                                     (void *) arg, sizeof(int));
  153.                              if( error ) return error;
  154.                                     num = foo_x;
  155.                              put_fs_byte(num, (int *) arg);
  156.                              break;
  157.         default            : return -ENOSYS; /* Function not implem. */
  158.         }

  159.     return OK;
  160. }

  161. /* This open funtion hasn't been designed to be openned by two  */
  162. /* processes at the same time. We check this through DEV_IN_USE.*/
  163. static int foo_open(struct inode *inode, struct file *file)
  164. {
  165.     /* Initialization check result */
  166.     switch( foo_status ) {
  167.         case NOT_PRESENT: return -ENXIO;  /* No such device */
  168.         case DEV_IN_USE : return -EBUSY;  /* Device busy    */
  169.         case DEV_READY  : break;          /* Device ready   */
  170.         default         : return -ENXIO;  /* Unknown status */
  171.         }

  172.     /* Gets the initial values of the two 8259 ports */
  173.     init_8259_M_imr = inb_p(MASTER_8259);
  174.     init_8259_S_imr = inb_p(SLAVE_8259);

  175.     /* Install irq handlers */
  176.     if( install_touch() ) {    /* Install touch irq handler */
  177.         return -EPERM;
  178.         }

  179.     /* Successful return point */
  180.     foo_status = DEV_IN_USE;
  181.     return OK;
  182. }

  183. static void foo_release(struct inode *inode, struct file *file)
  184. {
  185.     /* Release irq handlers */
  186.     remove_touch();            /* Release touch interrupt */

  187.     /* Restore the initial values of the two 8259 ports */
  188.     outb_p(init_8259_M_imr, MASTER_8259);
  189.     outb_p(init_8259_S_imr, SLAVE_8259);

  190.     /* Successful return point */
  191.     foo_status = DEV_READY;
  192.     return;
  193.     }

  194.     static struct file_operations foo_fops = { /* Driver available functions */
  195.         NULL,           /* foo_lseek   */
  196.         foo_read,       /* foo_read    */
  197.         foo_write,      /* foo_write   */
  198.         NULL,           /* foo_readdir */
  199.         NULL,           /* foo_select  */
  200.         foo_ioctl,      /* foo_ioctl   */
  201.         NULL,           /* foo_mmap    */
  202.         foo_open,       /* foo_open    */
  203.         foo_release     /* foo_release */
  204.         };

  205. int foo_init(void)
  206. {
  207. #ifdef FOO_DEBUG
  208.     int len;
  209.     char buf[4096];
  210. #endif

  211.     /* Ask for a free major device number */
  212.     if( register_chrdev(FOO_MAJOR, FOO_NAME, &foo_fops)) {
  213.         printk("unable to get major %d for FOO\n", FOO_MAJOR);
  214.         return -EIO;
  215.         }

  216.     /* Test if IO address is free */
  217.     if( check_region(FOO_IO_BASE_ADDRESS, FOO_NUM_PORTS)) {
  218.         printk("FOO error: IO address already in use\n");
  219.         foo_status = NOT_PRESENT;
  220.         unregister_chrdev(FOO_MAJOR, FOO_NAME);
  221.         return -EIO;
  222.         }

  223.     /* Register IO address */
  224.     request_region(FOO_IO_BASE_ADDRESS, FOO_NUM_PORTS, "foo");

  225. #ifdef FOO_DEBUG
  226.     /* Get IO port list */
  227.     len = get_ioport_list(buf);
  228.     buf[len] = '\0';
  229.     printk("FOO port list:\n%s\n", buf);
  230. #endif

  231.     /* Test if hardware is present                               */
  232.     Write a dummy value to a test port and read back to check */
  233.     outb_p(FOO_DUMMYVAL, FOO_TESTPORT);
  234.     vshdel(50);
  235.     if( FOO_DUMMYVAL != inb_p(FOO_TESTPORT) ) {
  236.         printk("FOO error: foo card not detected\n");
  237.         foo_status = NOT_PRESENT;
  238.         release_region(FOO_IO_BASE_ADDRESS, FOO_NUM_PORTS);
  239.         unregister_chrdev(FOO_MAJOR, FOO_NAME);
  240.         return -EIO;
  241.         }

  242.     /* Test irq handlers */
  243.     if( install_touch() ) { /* Test touch handler */
  244.         printk("FOO error: cannot install touch irq handler\n");
  245.         foo_status = NOT_PRESENT;
  246.         release_region(FOO_IO_BASE_ADDRESS, FOO_NUM_PORTS);
  247.         unregister_chrdev(FOO_MAJOR, FOO_NAME);
  248.         return -EIO;
  249.         }
  250.     remove_touch();

  251.     /* Initialize driver internal data */
  252.     foo_x = 0;
  253.     foo_y = 0;

  254.     /* Successful return point */
  255.     printk("FOO: driver initialized with major %d\n", FOO_MAJOR);
  256.     foo_status = DEV_READY;
  257.     return OK;
  258.     }

复制代码


footest.c

  1. /*
  2. *  footest.c
  3. *
  4. *  Copyright (C) 1997  Fernando Matia
  5. */

  6. /*
  7. *  Example for /dev/foo testing
  8. */

  9. #include <stdio.h>           /* For printf(), scanf(), etc             */
  10. #include <sys/types.h>       /* For open() y read()                    */
  11. #include <unistd.h>          /* For read() y close()                   */
  12. #include <sys/stat.h>        /* For open()                             */
  13. #include <fcntl.h>           /* For open()                             */
  14. #include <sys/ioctl.h>       /* For ioctl()                            */
  15. #include <linux/foo.h>       /* foo_struct Structure and y definitions */

  16. int fd;                      /* File descriptor for the driver         */
  17. long output;                 /* Value which returns the driver         */
  18. int input;                   /* Input value to the driver              */
  19. int factor;                  /* Multiplication factor                  */

  20. void main()
  21. {
  22.     if( (fd = open("/dev/foo", O_RDWR, 0)) < 0) {
  23.         printf("Error opening foo\n");
  24.         exit(1);
  25.         }

  26.     if( read(fd, (char *) &output, sizeof(long)) < 0) {
  27.         printf("Error reading from foo\n");
  28.         close(fd);
  29.         exit(1);
  30.         }
  31.     printf("Output = %d\n", output);

  32.     input = 70;
  33.     if( write(fd, (char *) &input, sizeof(int)) < 0) {
  34.         printf("Error writing to foo\n");
  35.         close(fd);
  36.         exit(1);
  37.         }

  38.     if( read(fd, (char *) &output, sizeof(long)) < 0) {
  39.         printf("Error reading from foo\n");
  40.         close(fd);
  41.         exit(1);
  42.         }
  43.     printf("Output = %d\n", output);

  44.     factor = 20;
  45.     if( ioctl(fd, FOO_SET, (char *) &factor) ) {
  46.         printf("Error using ioctl\n");
  47.         close(fd);
  48.         exit(0);
  49.         }

  50.     if( read(fd, (char *) &output, sizeof(long)) < 0) {
  51.         printf("Error reading from foo\n");
  52.         close(fd);
  53.         exit(1);
  54.         }
  55.     printf("Output = %d\n", output);

  56.     if( ioctl(fd, FOO_RESET) ) {
  57.         printf("Error using ioctl\n");
  58.         close(fd);
  59.         exit(0);
  60.         }

  61.     if( read(fd, (char *) &output, sizeof(long)) < 0) {
  62.         printf("Error reading from foo\n");
  63.         close(fd);
  64.         exit(1);
  65.         }
  66.     printf("Output = %d\n", output);

  67.     if( ioctl(fd, FOO_GET, &input) ) {
  68.         printf("Error using ioctl\n");
  69.         close(fd);
  70.         exit(0);
  71.         }
  72.     printf("Input = %d\n", input);

  73.     if( close(fd) ) {
  74.         printf("Error closing foo\n");
  75.         exit(1);
  76.         }

  77.     exit(0);
  78. }
复制代码


http://www.linuxjournal.com/article/2476
发表于 2007-1-3 10:44:54 | 显示全部楼层
good! thanks
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表