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

嵌入式Linux

开发平台:

C/C++

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