📄 mem.c
字号:
/* * linux/arch/arm/drivers/char/mem.c * * Copyright (C) 1991, 1992 Linus Torvalds * * Modifications for ARM Copyright (C) 1995, 1996 Russell King */#include <linux/config.h>#include <linux/types.h>#include <linux/errno.h>#include <linux/sched.h>#include <linux/kernel.h>#include <linux/major.h>#include <linux/tty.h>#include <linux/miscdevice.h>#include <linux/tpqic02.h>#include <linux/malloc.h>#include <linux/mman.h>#include <linux/mm.h>#include <linux/random.h>#include <asm/segment.h>#include <asm/io.h>#include <asm/pgtable.h>extern int con_fb_read(char *buf, unsigned long pos, int count);extern int con_fb_write(const char *buf, unsigned long pos, int count);extern int con_fb_mmap(unsigned long vma_start, unsigned long vma_offset, unsigned long vma_end, pgprot_t prot);#ifdef CONFIG_SOUNDvoid soundcard_init(void);#endifstatic int read_ram(struct inode * inode, struct file * file, char * buf, int count){ return -EIO;}static int write_ram(struct inode * inode, struct file * file, const char * buf, int count){ return -EIO;}static int read_mem(struct inode * inode, struct file * file, char * buf, int count){ unsigned long p = file->f_pos; p += PAGE_OFFSET; if (count < 0) return -EINVAL; if (MAP_NR(p) >= max_mapnr) return 0; if (count > high_memory - p) count = high_memory - p; memcpy_tofs(buf,(void *) p,count); file->f_pos += count; return count;}static int write_mem(struct inode * inode, struct file * file, const char * buf, int count){ unsigned long p = file->f_pos; p += PAGE_OFFSET; if (count < 0) return -EINVAL; if (MAP_NR(p) >= max_mapnr) return 0; if (count > high_memory - p) count = high_memory - p; memcpy_fromfs((void *) p,buf,count); file->f_pos += count; return count;}static int mmap_mem(struct inode * inode, struct file * file, struct vm_area_struct * vma){#ifndef NO_MM if (vma->vm_offset & ~PAGE_MASK) return -ENXIO; /* * This disables memory caching/buffering */#if defined(CONFIG_CPU_ARM6) || defined(CONFIG_CPU_SA110) if (MAP_NR(vma->vm_offset) >= max_mapnr) pgprot_val(vma->vm_page_prot) &= ~(PTE_CACHEABLE | PTE_BUFFERABLE);#endif if (remap_page_range(vma->vm_start, vma->vm_offset, vma->vm_end - vma->vm_start, vma->vm_page_prot)) return -EAGAIN; vma->vm_inode = inode; inode->i_count++;#else vma->vm_start = file->f_pos+PAGE_OFFSET+vma->vm_offset;#endif /* !NO_MM */ return 0;}static int read_fb(struct inode * inode, struct file *file, char *buf, int count){ if (count < 0) return -EINVAL; count = con_fb_read(buf, file->f_pos, count); if (count > 0) file->f_pos += count; return count;}static int write_fb(struct inode * inode, struct file * file, const char * buf, int count){ if (count < 0) return -EINVAL; count = con_fb_write(buf, file->f_pos, count); if (count > 0) file->f_pos += count; return count;}static int mmap_fb(struct inode * inode, struct file * file, struct vm_area_struct * vma){ int ret; #ifndef NO_MM if (vma->vm_offset & ~PAGE_MASK) return -ENXIO; ret = con_fb_mmap(vma->vm_start, vma->vm_offset, vma->vm_end, vma->vm_page_prot); if (ret) return ret; vma->vm_inode = inode; inode->i_count ++;#else ret = con_fb_mmap(vma->vm_start, vma->vm_offset, vma->vm_end, __pgprot(0)); if (ret) return ret;#endif return 0;}static int read_kmem(struct inode *inode, struct file *file, char *buf, int count){ int read1, read2; read1 = read_mem(inode, file, buf, count); if (read1 < 0) return read1; read2 = vread(buf + read1, (char *) ((unsigned long) file->f_pos), count - read1); if (read2 < 0) return read2; file->f_pos += read2; return read1 + read2;}static int read_port(struct inode * inode, struct file * file,char * buf, int count){ unsigned int i = file->f_pos; char * tmp = buf; while (count-- > 0 && (i < 65536 || (i > 0x80000000 && i < 0x84000000))) { put_user(inb(i),tmp); i++; tmp++; } file->f_pos = i; return tmp-buf;}static int write_port(struct inode * inode, struct file * file, const char * buf, int count){ unsigned int i = file->f_pos; const char * tmp = buf; while (count-- > 0 && (i < 65536 || (i > 0x80000000 && i < 0x84000000))) { outb(get_user(tmp),i); i++; tmp++; } file->f_pos = i; return tmp-buf;}static int read_null(struct inode * node, struct file * file, char * buf, int count){ return 0;}static int write_null(struct inode * inode, struct file * file, const char * buf, int count){ return count;}static int read_zero(struct inode * node, struct file * file, char * buf, int count){ int left; for (left = count; left > 0; left--) { put_user(0,buf); buf++; if (need_resched) schedule(); } return count;}static int mmap_zero(struct inode * inode, struct file * file, struct vm_area_struct * vma){#ifndef NO_MM if (vma->vm_flags & VM_SHARED) return -EINVAL; if (zeromap_page_range(vma->vm_start, vma->vm_end - vma->vm_start, vma->vm_page_prot)) return -EAGAIN; return 0;#else /* !NO_MM */ /* FIXME: trivial calloc() implementation is feasible */ return -ENOSYS;#endif /* !NO_MM */}static int read_full(struct inode * node, struct file * file, char * buf,int count){ file->f_pos += count; return count;}static int write_full(struct inode * inode, struct file * file, const char * buf, int count){ return -ENOSPC;}/* * Special lseek() function for /dev/null and /dev/zero. Most notably, you can fopen() * both devices with "a" now. This was previously impossible. SRB. */static int null_lseek(struct inode * inode, struct file * file, off_t offset, int orig){ return file->f_pos=0;}/* * The memory devices use the full 32/64 bits of the offset, and so we cannot * check against negative addresses: they are ok. The return value is weird, * though, in that case (0). * * also note that seeking relative to the "end of file" isn't supported: * it has no meaning, so it returns -EINVAL. */static int memory_lseek(struct inode * inode, struct file * file, off_t offset, int orig){ switch (orig) { case 0: file->f_pos = offset; return file->f_pos; case 1: file->f_pos += offset; return file->f_pos; default: return -EINVAL; } if (file->f_pos < 0) return 0; return file->f_pos;}#define write_kmem write_mem#define mmap_kmem mmap_mem#define zero_lseek null_lseek#define write_zero write_nullstatic struct file_operations ram_fops = { memory_lseek, read_ram, write_ram, NULL, /* ram_readdir */ NULL, /* ram_select */ NULL, /* ram_ioctl */ NULL, /* ram_mmap */ NULL, /* no special open code */ NULL, /* no special release code */ NULL /* fsync */};static struct file_operations mem_fops = { memory_lseek, read_mem, write_mem, NULL, /* mem_readdir */ NULL, /* mem_select */ NULL, /* mem_ioctl */ mmap_mem, NULL, /* no special open code */ NULL, /* no special release code */ NULL /* fsync */};static struct file_operations fb_fops = { memory_lseek, read_fb, write_fb, NULL, /* mem_readdir */ NULL, /* mem_select */ NULL, /* mem_ioctl */ mmap_fb, NULL, /* no special open code */ NULL, /* no special release code */ NULL /* fsync */};static struct file_operations kmem_fops = { memory_lseek, read_kmem, write_kmem, NULL, /* kmem_readdir */ NULL, /* kmem_select */ NULL, /* kmem_ioctl */ mmap_kmem, NULL, /* no special open code */ NULL, /* no special release code */ NULL /* fsync */};static struct file_operations null_fops = { null_lseek, read_null, write_null, NULL, /* null_readdir */ NULL, /* null_select */ NULL, /* null_ioctl */ NULL, /* null_mmap */ NULL, /* no special open code */ NULL, /* no special release code */ NULL /* fsync */};static struct file_operations port_fops = { memory_lseek, read_port, write_port, NULL, /* port_readdir */ NULL, /* port_select */ NULL, /* port_ioctl */ NULL, /* port_mmap */ NULL, /* no special open code */ NULL, /* no special release code */ NULL /* fsync */};static struct file_operations zero_fops = { zero_lseek, read_zero, write_zero, NULL, /* zero_readdir */ NULL, /* zero_select */ NULL, /* zero_ioctl */ mmap_zero, NULL, /* no special open code */ NULL /* no special release code */};static struct file_operations full_fops = { memory_lseek, read_full, write_full, NULL, /* full_readdir */ NULL, /* full_select */ NULL, /* full_ioctl */ NULL, /* full_mmap */ NULL, /* no special open code */ NULL /* no special release code */};static int memory_open(struct inode * inode, struct file * filp){ switch (MINOR(inode->i_rdev)) { case 0: filp->f_op = &ram_fops; break; case 1: filp->f_op = &mem_fops; break; case 2: filp->f_op = &kmem_fops; break; case 3: filp->f_op = &null_fops; break; case 4: filp->f_op = &port_fops; break; case 5: filp->f_op = &zero_fops; break; case 7: filp->f_op = &full_fops; break; case 8: filp->f_op = &random_fops; break; case 9: filp->f_op = &urandom_fops; break; case 128: filp->f_op = &fb_fops; break; default: return -ENXIO; } if (filp->f_op && filp->f_op->open) return filp->f_op->open(inode,filp); return 0;}static struct file_operations memory_fops = { NULL, /* lseek */ NULL, /* read */ NULL, /* write */ NULL, /* readdir */ NULL, /* select */ NULL, /* ioctl */ NULL, /* mmap */ memory_open, /* just a selector for the real open */ NULL, /* release */ NULL /* fsync */};int chr_dev_init(void){ if (register_chrdev(MEM_MAJOR,"mem",&memory_fops)) printk("unable to get major %d for memory devs\n", MEM_MAJOR); rand_initialize(); tty_init();#ifdef CONFIG_PRINTER lp_init();#endif#if defined(CONFIG_MOUSE) || defined(CONFIG_SOFT_WATCHDOG) misc_init();#endif#ifdef CONFIG_SOUND soundcard_init();#endif return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -