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

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