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

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