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

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