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

嵌入式Linux

开发平台:

C/C++

  1. /*
  2.  * silly.c -- Simple Tool for Unloading and Printing ISA Data (v2.1)
  3.  *
  4.  * Tested with 2.0 on the x86?
  5.  * 
  6.  * This module won't work on the sparc, where there's no concept of I/O space
  7.  *
  8.  */
  9. #ifndef __KERNEL__
  10. #  define __KERNEL__
  11. #endif
  12. #ifndef MODULE
  13. #  define MODULE
  14. #endif
  15. #ifdef __sparc__
  16. #  error "This module can't run on the Sparc platform"
  17. #else
  18. #define __NO_VERSION__ /* don't define kernel_verion in module.h */
  19. #include <linux/module.h>
  20. #include <linux/version.h>
  21. char kernel_version [] = UTS_RELEASE;
  22. #include <linux/sched.h>
  23. #include <linux/kernel.h> /* printk() */
  24. #include <linux/fs.h>     /* everything... */
  25. #include <linux/errno.h>  /* error codes */
  26. #include <linux/tqueue.h>
  27. #include <linux/malloc.h>
  28. #include <linux/mm.h>
  29. #include <linux/ioport.h>
  30. #include <asm/io.h>
  31. #include <asm/segment.h>  /* memcpy to/from fs */
  32. #include "sysdep-2.1.h"
  33. int silly_major = 0;
  34. static int lines=25, columns=80; /* can be changed at load time */
  35. /*
  36.  * The devices access the 640k-1M memory.
  37.  * minor 0 uses readb/writeb
  38.  * minor 1 uses readw/writew
  39.  * minor 2 uses readl/writel
  40.  * minor 3 uses memcpy_fromio()/memcpy_toio()
  41.  * minor 4 uses readl/writel over VGA mem (0xb8000-0xc0000)
  42.  * minor 5 only drops letters in the VGA buffer
  43.  */
  44. static int silly_joke_write(int count);
  45. int silly_open (struct inode *inode, struct file *filp)
  46. {
  47.     MOD_INC_USE_COUNT;
  48.     return 0;
  49. }
  50. release_t silly_release (struct inode *inode, struct file *filp)
  51. {
  52.     MOD_DEC_USE_COUNT;
  53.     release_return(0);
  54. }
  55. enum silly_modes {M_8=0, M_16, M_32, M_memcpy, M_vga, M_joke};
  56. read_write_t silly_read (struct inode *inode, struct file *filp,
  57.                 char *buf, count_t count)
  58. {
  59.     int retval;
  60.     int mode = MINOR(inode->i_rdev);
  61.     unsigned long add = 0xA0000 + filp->f_pos;
  62.     unsigned char *kbuf, *ptr;
  63.     if (mode == M_joke) return 0;  /* no read on /dev/silliest */
  64.     if (mode == M_vga) {
  65.         add = 0xB8000 + filp->f_pos; /* range: 0xB8000-0xC0000 */
  66.         if (add + count > 0xC0000)
  67.             count = 0xC0000 - add;
  68.         mode = M_32; /* and fall back to normal xfer */
  69.     }
  70.     else 
  71.         if (add + count > 0x100000) /* range: 0xA0000-0x100000 */
  72.             count = 0x100000 - add;
  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.      * kbuf is aligned, but the reads might not. In order not to
  84.      * drive me mad with unaligned leading and trailing bytes,
  85.      * I downgrade the `mode' if unaligned xfers are requested.
  86.      */
  87.     if (mode==M_32 && ((add | count) & 3))
  88.         mode = M_16;
  89.     if (mode==M_16 && ((add | count) & 1))
  90.         mode = M_8;
  91.     switch(mode) {
  92.       case M_32: 
  93.         while (count >= 4) {
  94.             *(u32 *)ptr = readl(add);
  95.             add+=4; count-=4; ptr+=4;
  96.         }
  97.         break;
  98.             
  99.       case M_16: 
  100.         while (count >= 2) {
  101.             *(u16 *)ptr = readw(add);
  102.             add+=2; count-=2; ptr+=2;
  103.         }
  104.         break;
  105.             
  106.       case M_8: 
  107.         while (count) {
  108.             *ptr = readb(add);
  109.             add++; count--; ptr++;
  110.         }
  111.         break;
  112.       case M_memcpy:
  113.         memcpy_fromio(ptr, add, count);
  114.         break;
  115.       default:
  116.         return -EINVAL;
  117.     }
  118.     if (retval > 0)
  119.         copy_to_user(buf, kbuf, retval);
  120.     kfree(kbuf);
  121.     filp->f_pos += retval;
  122.     return retval;
  123. }
  124. read_write_t silly_write (struct inode *inode, struct file *filp,
  125.                 const char *buf, count_t count)
  126. {
  127.     int retval;
  128.     int mode = MINOR(inode->i_rdev);
  129.     unsigned long add = 0xA0000 + filp->f_pos;
  130.     unsigned char *kbuf, *ptr;
  131.     /*
  132.      * Writing is dangerous.
  133.      * Allow root-only, independently of device permissions
  134.      */
  135.     if (!suser()) return -EPERM;
  136.     if (mode == M_joke)
  137.         return silly_joke_write(count);
  138.     if (mode == M_vga) {
  139.         add = 0xB8000 + filp->f_pos; /* range: 0xB8000-0xC0000 */
  140.         if (add + count > 0xC0000)
  141.             count = 0xC0000 - add;
  142.         mode = M_32; /* and fall back to normal xfer */
  143.     }
  144.     else 
  145.         if (add + count > 0x100000) /* range: 0xA0000-0x100000 */
  146.             count = 0x100000 - add;
  147.     /*
  148.      * too big an f_pos (caused by a malicious lseek())
  149.      * results in a negative count
  150.      */
  151.     if (count < 0) return 0;
  152.     kbuf = kmalloc(count, GFP_KERNEL);
  153.     if (!kbuf) return -ENOMEM;
  154.     ptr=kbuf;
  155.     retval=count;
  156.     /*
  157.      * kbuf is aligned, but the writes might not. In order not to
  158.      * drive me mad with unaligned leading and trailing bytes,
  159.      * I downgrade the `mode' if unaligned xfers are requested.
  160.      */
  161.     if (mode==M_32 && ((add | count) & 3))
  162.         mode = M_16;
  163.     if (mode==M_16 && ((add | count) & 1))
  164.         mode = M_8;
  165.     copy_from_user(kbuf, buf, count);
  166.     ptr=kbuf;
  167.     switch(mode) {
  168.       case M_32: 
  169.         while (count >= 4) {
  170.             writel(*(u32 *)ptr, add);
  171.             add+=4; count-=4; ptr+=4;
  172.         }
  173.         break;
  174.             
  175.       case M_16: 
  176.         while (count >= 2) {
  177.             writel(*(u16 *)ptr, add);
  178.             add+=2; count-=2; ptr+=2;
  179.         }
  180.         break;
  181.             
  182.       case M_8: 
  183.         while (count) {
  184.             writeb(*ptr, add);
  185.             add++; count--; ptr++;
  186.         }
  187.         break;
  188.       case M_memcpy:
  189.         memcpy_toio(add, ptr, count);
  190.         break;
  191.       default:
  192.         return -EINVAL;
  193.     }
  194.     filp->f_pos += retval;
  195.     return retval;
  196. }
  197. #ifdef __USE_OLD_SELECT__
  198. int silly_poll (struct inode *inode, struct file *filp,
  199.                   int mode, select_table *table)
  200. {
  201.     return mode==SEL_EX ? 0 : 1; /* readable, writable, not-exceptionable */
  202. }
  203. #else
  204. unsigned int silly_poll (struct file *filp, poll_table *wait)
  205. {
  206.     return (POLLIN | POLLHUP);
  207. }
  208. #endif
  209. /*
  210.  * Dropping letters: use the timer queue to drop 10 rows per second.
  211.  * Put the writing process to sleep, and don't manage more than 1 writer.
  212.  *
  213.  * Note that this isn't meant to show how to access the text buffer:
  214.  * it must *not* be accessed this way. Look at selection.c for information
  215.  * about the text buffer.
  216.  */
  217. struct wait_queue *jokeq;
  218. struct tq_struct silly_task;
  219. void silly_timerfn(void *ptr)
  220. {
  221.     unsigned long place = (unsigned long)ptr;
  222.     char *ch, *ch2;
  223.     static int time;
  224.     ch = (char *)(0xb8000 + place*2);  /* two bytes every char-cell */
  225.     ch2 = ch + columns * 2;
  226.     if (place >= lines*columns || readb(ch) == ' ' || readb(ch2) != ' ') {
  227.         /* printk("not goodn"); */
  228.         wake_up_interruptible(&jokeq);
  229.         return;
  230.     }
  231.     /* don't do it everytime, only ten times per second */
  232.     if (time++ >= HZ/10) {
  233.         time = 0;
  234.         /* ("in queue: place %4i (%i,%i) -- %x %xn", place, place%columns,
  235.                place/columns, (int)ch, (int)ch2); */
  236.         place += columns;
  237.         writeb(readb(ch),ch2); writeb(' ',ch); /* down one */
  238.         silly_task.data = (void *)place;
  239.     }
  240.     queue_task(&silly_task, &tq_timer);
  241.     return;
  242. }    
  243. static int silly_joke_write(int count)
  244. {
  245.     int i, j;
  246.     unsigned long place;
  247.     char *ch, *ch2;
  248.     
  249.     for (i=0; i<count; i++) {
  250.         /* choose a place with any algorithm */
  251.         place = (unsigned int)(jiffies * 443) % (lines * columns);
  252.         for (j=0; j<50; j++) { /* try 50 times */
  253.             ch = (char *)(0xb8000 + place*2);
  254.             ch2 = ch + 2*columns;
  255.             if (readb(ch) == ' ' || readb(ch2) != ' ') {
  256.                 place *= 331; place %= (lines * columns);
  257.                 continue;
  258.             }
  259.             break;
  260.         }
  261.         silly_task.routine = silly_timerfn;
  262.         silly_task.data = (void *)place;
  263.         queue_task(&silly_task, &tq_timer);
  264.         interruptible_sleep_on(&jokeq);
  265.         if (current->signal & ~current->blocked)
  266.             return -ERESTARTSYS;
  267.     }
  268.     return i;
  269. }
  270. /*
  271.  * Done, the rest is normal
  272.  */
  273. struct file_operations silly_fops = {
  274.     NULL,          /* silly_lseek */
  275.     silly_read,
  276.     silly_write,
  277.     NULL,          /* silly_readdir */
  278.     silly_poll,
  279.     NULL,          /* silly_ioctl */
  280.     NULL,          /* silly_mmap */
  281.     silly_open,
  282.     silly_release,
  283.     NULL,          /* silly_fsync */
  284.     NULL,          /* silly_fasync */
  285.                    /* nothing more, fill with NULLs */
  286. };
  287. int init_module(void)
  288. {
  289.     int result = register_chrdev(silly_major, "silly", &silly_fops);
  290.     if (result < 0) {
  291.         printk(KERN_INFO "silly: can't get major numbern");
  292.         return result;
  293.     }
  294.     if (silly_major == 0) silly_major = result; /* dynamic */
  295.     return 0;
  296. }
  297. void cleanup_module(void)
  298. {
  299.     unregister_chrdev(silly_major, "silly");
  300. }
  301. #endif /* __386__ */