home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / KERNEL-S / V1.2 / LINUX-1.2 / LINUX-1 / linux / drivers / char / mem.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-03-07  |  8.7 KB  |  399 lines

  1. /*
  2.  *  linux/drivers/char/mem.c
  3.  *
  4.  *  Copyright (C) 1991, 1992  Linus Torvalds
  5.  */
  6.  
  7. #include <linux/config.h>
  8. #include <linux/types.h>
  9. #include <linux/errno.h>
  10. #include <linux/sched.h>
  11. #include <linux/kernel.h>
  12. #include <linux/major.h>
  13. #include <linux/tty.h>
  14. #include <linux/mouse.h>
  15. #include <linux/tpqic02.h>
  16. #include <linux/malloc.h>
  17. #include <linux/mman.h>
  18. #include <linux/mm.h>
  19.  
  20. #include <asm/segment.h>
  21. #include <asm/io.h>
  22. #include <asm/pgtable.h>
  23.  
  24. #ifdef CONFIG_SOUND
  25. extern long soundcard_init(long mem_start);
  26. #endif
  27.  
  28. static int read_ram(struct inode * inode, struct file * file,char * buf, int count)
  29. {
  30.     return -EIO;
  31. }
  32.  
  33. static int write_ram(struct inode * inode, struct file * file,char * buf, int count)
  34. {
  35.     return -EIO;
  36. }
  37.  
  38. static int read_mem(struct inode * inode, struct file * file,char * buf, int count)
  39. {
  40.     unsigned long p = file->f_pos;
  41.     int read;
  42.  
  43.     if (count < 0)
  44.         return -EINVAL;
  45.     if (p >= high_memory)
  46.         return 0;
  47.     if (count > high_memory - p)
  48.         count = high_memory - p;
  49.     read = 0;
  50.     while (p < PAGE_SIZE && count > 0) {
  51.         put_fs_byte(0,buf);
  52.         buf++;
  53.         p++;
  54.         count--;
  55.         read++;
  56.     }
  57.     memcpy_tofs(buf,(void *) p,count);
  58.     read += count;
  59.     file->f_pos += read;
  60.     return read;
  61. }
  62.  
  63. static int write_mem(struct inode * inode, struct file * file,char * buf, int count)
  64. {
  65.     unsigned long p = file->f_pos;
  66.     int written;
  67.  
  68.     if (count < 0)
  69.         return -EINVAL;
  70.     if (p >= high_memory)
  71.         return 0;
  72.     if (count > high_memory - p)
  73.         count = high_memory - p;
  74.     written = 0;
  75.     while (p < PAGE_SIZE && count > 0) {
  76.         /* Hmm. Do something? */
  77.         buf++;
  78.         p++;
  79.         count--;
  80.         written++;
  81.     }
  82.     memcpy_fromfs((void *) p,buf,count);
  83.     written += count;
  84.     file->f_pos += written;
  85.     return count;
  86. }
  87.  
  88. static int mmap_mem(struct inode * inode, struct file * file, struct vm_area_struct * vma)
  89. {
  90.     if (vma->vm_offset & ~PAGE_MASK)
  91.         return -ENXIO;
  92. #if defined(__i386__)
  93.     /*
  94.      * hmm.. This disables high-memory caching, as the XFree86 team
  95.      * wondered about that at one time.
  96.      * The surround logic should disable caching for the high device
  97.      * addresses anyway, but right now this seems still needed.
  98.      */
  99.     if (x86 > 3 && vma->vm_offset >= high_memory)
  100.         pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
  101. #endif
  102.     if (remap_page_range(vma->vm_start, vma->vm_offset, vma->vm_end - vma->vm_start, vma->vm_page_prot))
  103.         return -EAGAIN;
  104.     vma->vm_inode = inode;
  105.     inode->i_count++;
  106.     return 0;
  107. }
  108.  
  109. static int read_kmem(struct inode *inode, struct file *file, char *buf, int count)
  110. {
  111.     int read1, read2;
  112.  
  113.     read1 = read_mem(inode, file, buf, count);
  114.     if (read1 < 0)
  115.         return read1;
  116.     read2 = vread(buf + read1, (char *) ((unsigned long) file->f_pos), count - read1);
  117.     if (read2 < 0)
  118.         return read2;
  119.     file->f_pos += read2;
  120.     return read1 + read2;
  121. }
  122.  
  123. static int read_port(struct inode * inode,struct file * file,char * buf, int count)
  124. {
  125.     unsigned int i = file->f_pos;
  126.     char * tmp = buf;
  127.  
  128.     while (count-- > 0 && i < 65536) {
  129.         put_fs_byte(inb(i),tmp);
  130.         i++;
  131.         tmp++;
  132.     }
  133.     file->f_pos = i;
  134.     return tmp-buf;
  135. }
  136.  
  137. static int write_port(struct inode * inode,struct file * file,char * buf, int count)
  138. {
  139.     unsigned int i = file->f_pos;
  140.     char * tmp = buf;
  141.  
  142.     while (count-- > 0 && i < 65536) {
  143.         outb(get_fs_byte(tmp),i);
  144.         i++;
  145.         tmp++;
  146.     }
  147.     file->f_pos = i;
  148.     return tmp-buf;
  149. }
  150.  
  151. static int read_null(struct inode * node,struct file * file,char * buf,int count)
  152. {
  153.     return 0;
  154. }
  155.  
  156. static int write_null(struct inode * inode,struct file * file,char * buf, int count)
  157. {
  158.     return count;
  159. }
  160.  
  161. static int read_zero(struct inode * node,struct file * file,char * buf,int count)
  162. {
  163.     int left;
  164.  
  165.     for (left = count; left > 0; left--) {
  166.         put_fs_byte(0,buf);
  167.         buf++;
  168.     }
  169.     return count;
  170. }
  171.  
  172. static int mmap_zero(struct inode * inode, struct file * file, struct vm_area_struct * vma)
  173. {
  174.     if (vma->vm_flags & VM_SHARED)
  175.         return -EINVAL;
  176.     if (zeromap_page_range(vma->vm_start, vma->vm_end - vma->vm_start, vma->vm_page_prot))
  177.         return -EAGAIN;
  178.     return 0;
  179. }
  180.  
  181. static int read_full(struct inode * node,struct file * file,char * buf,int count)
  182. {
  183.     return count;
  184. }
  185.  
  186. static int write_full(struct inode * inode,struct file * file,char * buf, int count)
  187. {
  188.     return -ENOSPC;
  189. }
  190.  
  191. /*
  192.  * Special lseek() function for /dev/null and /dev/zero.  Most notably, you can fopen()
  193.  * both devices with "a" now.  This was previously impossible.  SRB.
  194.  */
  195.  
  196. static int null_lseek(struct inode * inode, struct file * file, off_t offset, int orig)
  197. {
  198.     return file->f_pos=0;
  199. }
  200. /*
  201.  * The memory devices use the full 32 bits of the offset, and so we cannot
  202.  * check against negative addresses: they are ok. The return value is weird,
  203.  * though, in that case (0).
  204.  *
  205.  * also note that seeking relative to the "end of file" isn't supported:
  206.  * it has no meaning, so it returns -EINVAL.
  207.  */
  208. static int memory_lseek(struct inode * inode, struct file * file, off_t offset, int orig)
  209. {
  210.     switch (orig) {
  211.         case 0:
  212.             file->f_pos = offset;
  213.             return file->f_pos;
  214.         case 1:
  215.             file->f_pos += offset;
  216.             return file->f_pos;
  217.         default:
  218.             return -EINVAL;
  219.     }
  220.     if (file->f_pos < 0)
  221.         return 0;
  222.     return file->f_pos;
  223. }
  224.  
  225. #define write_kmem    write_mem
  226. #define mmap_kmem    mmap_mem
  227. #define zero_lseek    null_lseek
  228. #define write_zero    write_null
  229.  
  230. static struct file_operations ram_fops = {
  231.     memory_lseek,
  232.     read_ram,
  233.     write_ram,
  234.     NULL,        /* ram_readdir */
  235.     NULL,        /* ram_select */
  236.     NULL,        /* ram_ioctl */
  237.     NULL,        /* ram_mmap */
  238.     NULL,        /* no special open code */
  239.     NULL,        /* no special release code */
  240.     NULL        /* fsync */
  241. };
  242.  
  243. static struct file_operations mem_fops = {
  244.     memory_lseek,
  245.     read_mem,
  246.     write_mem,
  247.     NULL,        /* mem_readdir */
  248.     NULL,        /* mem_select */
  249.     NULL,        /* mem_ioctl */
  250.     mmap_mem,
  251.     NULL,        /* no special open code */
  252.     NULL,        /* no special release code */
  253.     NULL        /* fsync */
  254. };
  255.  
  256. static struct file_operations kmem_fops = {
  257.     memory_lseek,
  258.     read_kmem,
  259.     write_kmem,
  260.     NULL,        /* kmem_readdir */
  261.     NULL,        /* kmem_select */
  262.     NULL,        /* kmem_ioctl */
  263.     mmap_kmem,
  264.     NULL,        /* no special open code */
  265.     NULL,        /* no special release code */
  266.     NULL        /* fsync */
  267. };
  268.  
  269. static struct file_operations null_fops = {
  270.     null_lseek,
  271.     read_null,
  272.     write_null,
  273.     NULL,        /* null_readdir */
  274.     NULL,        /* null_select */
  275.     NULL,        /* null_ioctl */
  276.     NULL,        /* null_mmap */
  277.     NULL,        /* no special open code */
  278.     NULL,        /* no special release code */
  279.     NULL        /* fsync */
  280. };
  281.  
  282. static struct file_operations port_fops = {
  283.     memory_lseek,
  284.     read_port,
  285.     write_port,
  286.     NULL,        /* port_readdir */
  287.     NULL,        /* port_select */
  288.     NULL,        /* port_ioctl */
  289.     NULL,        /* port_mmap */
  290.     NULL,        /* no special open code */
  291.     NULL,        /* no special release code */
  292.     NULL        /* fsync */
  293. };
  294.  
  295. static struct file_operations zero_fops = {
  296.     zero_lseek,
  297.     read_zero,
  298.     write_zero,
  299.     NULL,        /* zero_readdir */
  300.     NULL,        /* zero_select */
  301.     NULL,        /* zero_ioctl */
  302.     mmap_zero,
  303.     NULL,        /* no special open code */
  304.     NULL        /* no special release code */
  305. };
  306.  
  307. static struct file_operations full_fops = {
  308.     memory_lseek,
  309.     read_full,
  310.     write_full,
  311.     NULL,        /* full_readdir */
  312.     NULL,        /* full_select */
  313.     NULL,        /* full_ioctl */    
  314.     NULL,        /* full_mmap */
  315.     NULL,        /* no special open code */
  316.     NULL        /* no special release code */
  317. };
  318.  
  319. static int memory_open(struct inode * inode, struct file * filp)
  320. {
  321.     switch (MINOR(inode->i_rdev)) {
  322.         case 0:
  323.             filp->f_op = &ram_fops;
  324.             break;
  325.         case 1:
  326.             filp->f_op = &mem_fops;
  327.             break;
  328.         case 2:
  329.             filp->f_op = &kmem_fops;
  330.             break;
  331.         case 3:
  332.             filp->f_op = &null_fops;
  333.             break;
  334.         case 4:
  335.             filp->f_op = &port_fops;
  336.             break;
  337.         case 5:
  338.             filp->f_op = &zero_fops;
  339.             break;
  340.         case 7:
  341.             filp->f_op = &full_fops;
  342.             break;
  343.         default:
  344.             return -ENODEV;
  345.     }
  346.     if (filp->f_op && filp->f_op->open)
  347.         return filp->f_op->open(inode,filp);
  348.     return 0;
  349. }
  350.  
  351. static struct file_operations memory_fops = {
  352.     NULL,        /* lseek */
  353.     NULL,        /* read */
  354.     NULL,        /* write */
  355.     NULL,        /* readdir */
  356.     NULL,        /* select */
  357.     NULL,        /* ioctl */
  358.     NULL,        /* mmap */
  359.     memory_open,    /* just a selector for the real open */
  360.     NULL,        /* release */
  361.     NULL        /* fsync */
  362. };
  363.  
  364. #ifdef CONFIG_FTAPE
  365. char* ftape_big_buffer;
  366. #endif
  367.  
  368. long chr_dev_init(long mem_start, long mem_end)
  369. {
  370.     if (register_chrdev(MEM_MAJOR,"mem",&memory_fops))
  371.         printk("unable to get major %d for memory devs\n", MEM_MAJOR);
  372.     mem_start = tty_init(mem_start);
  373. #ifdef CONFIG_PRINTER
  374.     mem_start = lp_init(mem_start);
  375. #endif
  376. #if defined (CONFIG_BUSMOUSE) || defined (CONFIG_82C710_MOUSE) || \
  377.     defined (CONFIG_PSMOUSE) || defined (CONFIG_MS_BUSMOUSE) || \
  378.     defined (CONFIG_ATIXL_BUSMOUSE)
  379.     mem_start = mouse_init(mem_start);
  380. #endif
  381. #ifdef CONFIG_SOUND
  382.     mem_start = soundcard_init(mem_start);
  383. #endif
  384. #if CONFIG_QIC02_TAPE
  385.     mem_start = qic02_tape_init(mem_start);
  386. #endif
  387. /*
  388.  *      Rude way to allocate kernel memory buffer for tape device
  389.  */
  390. #ifdef CONFIG_FTAPE
  391.         /* allocate NR_FTAPE_BUFFERS 32Kb buffers at aligned address */
  392.         ftape_big_buffer= (char*) ((mem_start + 0x7fff) & ~0x7fff);
  393.         printk( "ftape: allocated %d buffers aligned at: %p\n",
  394.                NR_FTAPE_BUFFERS, ftape_big_buffer);
  395.         mem_start = (long) ftape_big_buffer + NR_FTAPE_BUFFERS * 0x8000;
  396. #endif 
  397.     return mem_start;
  398. }
  399.