silly.c
上传用户:wudi5211
上传日期:2010-01-21
资源大小:607k
文件大小:8k
源码类别:

嵌入式Linux

开发平台:

C/C++

  1. /*
  2.  * silly.c -- Simple Tool for Unloading and Printing ISA Data
  3.  *
  4.  * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
  5.  * Copyright (C) 2001 O'Reilly & Associates
  6.  *
  7.  * The source code in this file can be freely used, adapted,
  8.  * and redistributed in source or binary form, so long as an
  9.  * acknowledgment appears in derived source files.  The citation
  10.  * should list that the code comes from the book "Linux Device
  11.  * Drivers" by Alessandro Rubini and Jonathan Corbet, published
  12.  * by O'Reilly & Associates.   No warranty is attached;
  13.  * we cannot take responsibility for errors or fitness for use.
  14.  *
  15.  * $Id: silly.c,v 1.17 2001/07/18 22:28:16 rubini Exp $
  16.  */
  17. /* =========================> BIG FAT WARNING:
  18.  * This will only work on architectures with an ISA memory range.
  19.  * It won't work on other computers.
  20.  */
  21. #ifndef __KERNEL__
  22. #  define __KERNEL__
  23. #endif
  24. #ifndef MODULE
  25. #  define MODULE
  26. #endif
  27. #include <linux/module.h>
  28. #include <linux/version.h>
  29. #include <linux/sched.h>
  30. #include <linux/kernel.h> /* printk() */
  31. #include <linux/fs.h>     /* everything... */
  32. #include <linux/errno.h>  /* error codes */
  33. #include <linux/tqueue.h>
  34. #include <linux/malloc.h>
  35. #include <linux/mm.h>
  36. #include <linux/ioport.h>
  37. #include <asm/io.h>
  38. #include "sysdep.h"  /* linux 2.0, 2.2, 2.4 compatibility macros */
  39. int silly_major = 0;
  40. MODULE_PARM(silly_major, "i");
  41. MODULE_AUTHOR("Alessandro Rubini");
  42. /*
  43.  * The devices access the 640k-1M memory.
  44.  * minor 0 uses readb/writeb
  45.  * minor 1 uses readw/writew
  46.  * minor 2 uses readl/writel
  47.  * minor 3 uses memcpy_fromio()/memcpy_toio()
  48.  */
  49. /*
  50.  * Here's our address range, and a place to store the ioremap'd base.
  51.  */
  52. #define ISA_BASE    0xA0000
  53. #define ISA_MAX    0x100000  /* for general memory access */
  54. #define VIDEO_MAX   0xC0000  /* for vga access */
  55. #define VGA_BASE    0xb8000
  56. static void *io_base;
  57. int silly_open(struct inode *inode, struct file *filp)
  58. {
  59.     MOD_INC_USE_COUNT;
  60.     return 0;
  61. }
  62. #ifdef LINUX_20
  63. void silly_release(struct inode *inode, struct file *filp)
  64. {
  65.     MOD_DEC_USE_COUNT;
  66. }
  67. #else
  68. int silly_release(struct inode *inode, struct file *filp)
  69. {
  70.     MOD_DEC_USE_COUNT;
  71.     return 0;
  72. }
  73. #endif /* LINUX_20 */
  74. enum silly_modes {M_8=0, M_16, M_32, M_memcpy};
  75. ssize_t silly_read(struct file *filp, char *buf, size_t count, loff_t *f_pos)
  76. {
  77.     int retval;
  78.     int mode = MINOR(INODE_FROM_F(filp)->i_rdev);
  79.     void *add;
  80.     unsigned long isa_addr = ISA_BASE + *f_pos;
  81.     unsigned char *kbuf, *ptr;
  82.     if (isa_addr + count > ISA_MAX) /* range: 0xA0000-0x100000 */
  83. count = ISA_MAX - isa_addr;
  84.     /*
  85.      * too big an f_pos (caused by a malicious lseek())
  86.      * would result in a negative count
  87.      */
  88.     if (count < 0) return 0;
  89.     kbuf = kmalloc(count, GFP_KERNEL);
  90.     if (!kbuf) return -ENOMEM;
  91.     ptr=kbuf;
  92.     retval=count;
  93.    /*
  94.     * Convert our address into our remapped area.
  95.     */
  96.     add = io_base + (isa_addr - ISA_BASE);
  97.     /*
  98.      * kbuf is aligned, but the reads might not. In order not to
  99.      * drive me mad with unaligned leading and trailing bytes,
  100.      * I downgrade the `mode' if unaligned xfers are requested.
  101.      */
  102.     if (mode==M_32 && ((isa_addr | count) & 3))
  103.         mode = M_16;
  104.     if (mode==M_16 && ((isa_addr | count) & 1))
  105.         mode = M_8;
  106.     switch(mode) {
  107.       case M_32: 
  108.         while (count >= 4) {
  109.             *(u32 *)ptr = readl(add);
  110.             add+=4; count-=4; ptr+=4;
  111.         }
  112.         break;
  113.             
  114.       case M_16: 
  115.         while (count >= 2) {
  116.             *(u16 *)ptr = readw(add);
  117.             add+=2; count-=2; ptr+=2;
  118.         }
  119.         break;
  120.             
  121.       case M_8: 
  122.         while (count) {
  123.             *ptr = readb(add);
  124.             add++; count--; ptr++;
  125.         }
  126.         break;
  127.       case M_memcpy:
  128.         memcpy_fromio(ptr, add, count);
  129.         break;
  130.       default:
  131.         return -EINVAL;
  132.     }
  133.     if ( (retval > 0) && copy_to_user(buf, kbuf, retval))
  134. retval = -EFAULT;
  135.     kfree(kbuf);
  136.     *f_pos += retval;
  137.     return retval;
  138. }
  139. ssize_t silly_write(struct file *filp, const char *buf, size_t count,
  140.     loff_t *f_pos)
  141. {
  142.     int retval;
  143.     int mode = MINOR(INODE_FROM_F(filp)->i_rdev);
  144.     unsigned long isa_addr = ISA_BASE + *f_pos;
  145.     unsigned char *kbuf, *ptr;
  146.     void *add;
  147.     /*
  148.      * Writing is dangerous.
  149.      * Allow root-only, independently of device permissions
  150.      */
  151.     if (!capable (CAP_SYS_RAWIO)) return -EPERM;
  152.     if (isa_addr + count > ISA_MAX) /* range: 0xA0000-0x100000 */
  153. count = ISA_MAX - isa_addr;
  154.     /*
  155.      * too big an f_pos (caused by a malicious lseek())
  156.      * results in a negative count
  157.      */
  158.     if (count < 0) return 0;
  159.     kbuf = kmalloc(count, GFP_KERNEL);
  160.     if (!kbuf) return -ENOMEM;
  161.     ptr=kbuf;
  162.     retval=count;
  163.     /*
  164.      * kbuf is aligned, but the writes might not. In order not to
  165.      * drive me mad with unaligned leading and trailing bytes,
  166.      * I downgrade the `mode' if unaligned xfers are requested.
  167.      */
  168.     if (mode==M_32 && ((isa_addr | count) & 3))
  169.         mode = M_16;
  170.     if (mode==M_16 && ((isa_addr | count) & 1))
  171.         mode = M_8;
  172.     if (copy_from_user(kbuf, buf, count)) {
  173. kfree(kbuf); return -EFAULT;
  174.     }
  175.     ptr=kbuf;
  176.     /*
  177.      * Switch over to our remapped address space.
  178.      */
  179.     add = io_base + (isa_addr - ISA_BASE);
  180.     switch(mode) {
  181.       case M_32: 
  182.         while (count >= 4) {
  183.             writel(*(u32 *)ptr, add);
  184.             add+=4; count-=4; ptr+=4;
  185.         }
  186.         break;
  187.             
  188.       case M_16: 
  189.         while (count >= 2) {
  190.             writew(*(u16 *)ptr, add);
  191.             add+=2; count-=2; ptr+=2;
  192.         }
  193.         break;
  194.             
  195.       case M_8: 
  196.         while (count) {
  197.             writeb(*ptr, add);
  198.             add++; count--; ptr++;
  199.         }
  200.         break;
  201.       case M_memcpy:
  202.         memcpy_toio(add, ptr, count);
  203.         break;
  204.       default:
  205.         return -EINVAL;
  206.     }
  207.     *f_pos += retval;
  208.     kfree(kbuf);
  209.     return retval;
  210. }
  211. #ifdef __USE_OLD_SELECT__
  212. int silly_poll(struct inode *inode, struct file *filp,
  213.                   int mode, select_table *table)
  214. {
  215.     return mode==SEL_EX ? 0 : 1; /* readable, writable, not-exceptionable */
  216. }
  217. #define poll select /* to use as the method field in the fops structure */
  218. #else
  219. unsigned int silly_poll(struct file *filp, poll_table *wait)
  220. {
  221.     return POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM;
  222. }
  223. #endif /* __USE_OLD_SELECT__ */
  224. /*
  225.  * Done, now wrappers for 2.0 and the fops structure
  226.  */
  227. #ifdef LINUX_20
  228. int silly_read_20(struct inode *ino, struct file *f, char *buf, int count)
  229. {
  230.     return (int)silly_read(f, buf, count, &f->f_pos);
  231. }
  232. int silly_write_20(struct inode *ino, struct file *f, const char *b, int c)
  233. {
  234.     return (int)silly_write(f, b, c, &f->f_pos);
  235. }
  236. void silly_release_20(struct inode *ino, struct file *f)
  237. {
  238.     silly_release(ino, f);
  239. }
  240. #define silly_read silly_read_20
  241. #define silly_write silly_write_20
  242. #define silly_release silly_release_20
  243. #define poll select
  244. #endif
  245. struct file_operations silly_fops = {
  246.     read:     silly_read,
  247.     write:    silly_write,
  248.     poll:     silly_poll,
  249.     open:     silly_open,
  250.     release:  silly_release,
  251. };
  252. int silly_init(void)
  253. {
  254.     int result = register_chrdev(silly_major, "silly", &silly_fops);
  255.     if (result < 0) {
  256.         printk(KERN_INFO "silly: can't get major numbern");
  257.         return result;
  258.     }
  259.     if (silly_major == 0)
  260.             silly_major = result; /* dynamic */
  261.     SET_MODULE_OWNER(&silly_fops);
  262. /*
  263.  * Set up our I/O range.
  264.  */
  265.     /* this line appears in silly_init */
  266.     io_base = ioremap(ISA_BASE, ISA_MAX - ISA_BASE);
  267.     return 0;
  268. }
  269. void silly_cleanup(void)
  270. {
  271.     iounmap(io_base);
  272.     unregister_chrdev(silly_major, "silly");
  273. }
  274. module_init(silly_init);
  275. module_exit(silly_cleanup);