home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / KERNEL-S / V1.0 / LINUX-1.0 / LINUX-1 / linux / drivers / char / mem.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-01-30  |  9.3 KB  |  427 lines

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