root/drivers/char/mem.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. read_ram
  2. write_ram
  3. read_mem
  4. write_mem
  5. mmap_mem
  6. read_kmem
  7. read_port
  8. write_port
  9. read_null
  10. write_null
  11. read_zero
  12. mmap_zero
  13. read_full
  14. write_full
  15. null_lseek
  16. memory_lseek
  17. memory_open
  18. chr_dev_init

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

/* [previous][next][first][last][top][bottom][index][help] */