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

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