[MAC80211]: remove IEEE80211_CONF_SSID_HIDDEN
[safe/jmp/linux-2.6] / drivers / char / mem.c
index a85f3a3..bbee97f 100644 (file)
@@ -8,7 +8,6 @@
  *  Shared /dev/zero mmaping support, Feb 2000, Kanoj Sarcar <kanoj@sgi.com>
  */
 
-#include <linux/config.h>
 #include <linux/mm.h>
 #include <linux/miscdevice.h>
 #include <linux/slab.h>
 #include <linux/raw.h>
 #include <linux/tty.h>
 #include <linux/capability.h>
-#include <linux/smp_lock.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/ptrace.h>
 #include <linux/device.h>
 #include <linux/highmem.h>
 #include <linux/crash_dump.h>
 #include <linux/backing-dev.h>
 #include <linux/bootmem.h>
+#include <linux/splice.h>
+#include <linux/pfn.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -76,6 +75,13 @@ static inline int uncached_access(struct file *file, unsigned long addr)
         * On ia64, we ignore O_SYNC because we cannot tolerate memory attribute aliases.
         */
        return !(efi_mem_attributes(addr) & EFI_MEMORY_WB);
+#elif defined(CONFIG_MIPS)
+       {
+               extern int __uncached_access(struct file *file,
+                                            unsigned long addr);
+
+               return __uncached_access(file, addr);
+       }
 #else
        /*
         * Accessing memory above the top the kernel knows about or through a file pointer
@@ -88,17 +94,16 @@ static inline int uncached_access(struct file *file, unsigned long addr)
 }
 
 #ifndef ARCH_HAS_VALID_PHYS_ADDR_RANGE
-static inline int valid_phys_addr_range(unsigned long addr, size_t *count)
+static inline int valid_phys_addr_range(unsigned long addr, size_t count)
 {
-       unsigned long end_mem;
-
-       end_mem = __pa(high_memory);
-       if (addr >= end_mem)
+       if (addr + count > __pa(high_memory))
                return 0;
 
-       if (*count > end_mem - addr)
-               *count = end_mem - addr;
+       return 1;
+}
 
+static inline int valid_mmap_phys_addr_range(unsigned long pfn, size_t size)
+{
        return 1;
 }
 #endif
@@ -114,7 +119,7 @@ static ssize_t read_mem(struct file * file, char __user * buf,
        ssize_t read, sz;
        char *ptr;
 
-       if (!valid_phys_addr_range(p, &count))
+       if (!valid_phys_addr_range(p, count))
                return -EFAULT;
        read = 0;
 #ifdef __ARCH_HAS_NO_PAGE_ZERO_MAPPED
@@ -172,7 +177,7 @@ static ssize_t write_mem(struct file * file, const char __user * buf,
        unsigned long copied;
        void *ptr;
 
-       if (!valid_phys_addr_range(p, &count))
+       if (!valid_phys_addr_range(p, count))
                return -EFAULT;
 
        written = 0;
@@ -211,11 +216,9 @@ static ssize_t write_mem(struct file * file, const char __user * buf,
 
                copied = copy_from_user(ptr, buf, sz);
                if (copied) {
-                       ssize_t ret;
-
-                       ret = written + (sz - copied);
-                       if (ret)
-                               return ret;
+                       written += sz - copied;
+                       if (written)
+                               break;
                        return -EFAULT;
                }
                buf += sz;
@@ -228,26 +231,65 @@ static ssize_t write_mem(struct file * file, const char __user * buf,
        return written;
 }
 
+#ifndef __HAVE_PHYS_MEM_ACCESS_PROT
+static pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
+                                    unsigned long size, pgprot_t vma_prot)
+{
+#ifdef pgprot_noncached
+       unsigned long offset = pfn << PAGE_SHIFT;
+
+       if (uncached_access(file, offset))
+               return pgprot_noncached(vma_prot);
+#endif
+       return vma_prot;
+}
+#endif
+
+#ifndef CONFIG_MMU
+static unsigned long get_unmapped_area_mem(struct file *file,
+                                          unsigned long addr,
+                                          unsigned long len,
+                                          unsigned long pgoff,
+                                          unsigned long flags)
+{
+       if (!valid_mmap_phys_addr_range(pgoff, len))
+               return (unsigned long) -EINVAL;
+       return pgoff << PAGE_SHIFT;
+}
+
+/* can't do an in-place private mapping if there's no MMU */
+static inline int private_mapping_ok(struct vm_area_struct *vma)
+{
+       return vma->vm_flags & VM_MAYSHARE;
+}
+#else
+#define get_unmapped_area_mem  NULL
+
+static inline int private_mapping_ok(struct vm_area_struct *vma)
+{
+       return 1;
+}
+#endif
+
 static int mmap_mem(struct file * file, struct vm_area_struct * vma)
 {
-#if defined(__HAVE_PHYS_MEM_ACCESS_PROT)
+       size_t size = vma->vm_end - vma->vm_start;
+
+       if (!valid_mmap_phys_addr_range(vma->vm_pgoff, size))
+               return -EINVAL;
+
+       if (!private_mapping_ok(vma))
+               return -ENOSYS;
+
        vma->vm_page_prot = phys_mem_access_prot(file, vma->vm_pgoff,
-                                                vma->vm_end - vma->vm_start,
+                                                size,
                                                 vma->vm_page_prot);
-#elif defined(pgprot_noncached)
-       unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
-       int uncached;
-
-       uncached = uncached_access(file, offset);
-       if (uncached)
-               vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-#endif
 
        /* Remap-pfn-range will mark the range VM_IO and VM_RESERVED */
        if (remap_pfn_range(vma,
                            vma->vm_start,
                            vma->vm_pgoff,
-                           vma->vm_end-vma->vm_start,
+                           size,
                            vma->vm_page_prot))
                return -EAGAIN;
        return 0;
@@ -441,11 +483,9 @@ do_write_kmem(void *p, unsigned long realp, const char __user * buf,
 
                copied = copy_from_user(ptr, buf, sz);
                if (copied) {
-                       ssize_t ret;
-
-                       ret = written + (sz - copied);
-                       if (ret)
-                               return ret;
+                       written += sz - copied;
+                       if (written)
+                               break;
                        return -EFAULT;
                }
                buf += sz;
@@ -499,11 +539,10 @@ static ssize_t write_kmem(struct file * file, const char __user * buf,
                        if (len) {
                                written = copy_from_user(kbuf, buf, len);
                                if (written) {
-                                       ssize_t ret;
-
+                                       if (wrote + virtr)
+                                               break;
                                        free_page((unsigned long)kbuf);
-                                       ret = wrote + virtr + (len - written);
-                                       return ret ? ret : -EFAULT;
+                                       return -EFAULT;
                                }
                        }
                        len = vwrite(kbuf, (char *)p, len);
@@ -519,7 +558,7 @@ static ssize_t write_kmem(struct file * file, const char __user * buf,
        return virtr + wrote;
 }
 
-#if (defined(CONFIG_ISA) || !defined(__mc68000__)) && (!defined(CONFIG_PPC_ISERIES) || defined(CONFIG_PCI))
+#ifdef CONFIG_DEVPORT
 static ssize_t read_port(struct file * file, char __user * buf,
                         size_t count, loff_t *ppos)
 {
@@ -548,8 +587,11 @@ static ssize_t write_port(struct file * file, const char __user * buf,
                return -EFAULT;
        while (count-- > 0 && i < 65536) {
                char c;
-               if (__get_user(c, tmp)) 
+               if (__get_user(c, tmp)) {
+                       if (tmp > buf)
+                               break;
                        return -EFAULT; 
+               }
                outb(c,i);
                i++;
                tmp++;
@@ -571,6 +613,18 @@ static ssize_t write_null(struct file * file, const char __user * buf,
        return count;
 }
 
+static int pipe_to_null(struct pipe_inode_info *info, struct pipe_buffer *buf,
+                       struct splice_desc *sd)
+{
+       return sd->len;
+}
+
+static ssize_t splice_write_null(struct pipe_inode_info *pipe,struct file *out,
+                                loff_t *ppos, size_t len, unsigned int flags)
+{
+       return splice_from_pipe(pipe, out, ppos, len, flags, pipe_to_null);
+}
+
 #ifdef CONFIG_MMU
 /*
  * For fun, we are using the MMU for this.
@@ -598,7 +652,8 @@ static inline size_t read_zero_pagealigned(char __user * buf, size_t size)
                        count = size;
 
                zap_page_range(vma, addr, count, NULL);
-               zeromap_page_range(vma, addr, count, PAGE_COPY);
+               if (zeromap_page_range(vma, addr, count, PAGE_COPY))
+                       break;
 
                size -= count;
                buf += count;
@@ -665,11 +720,14 @@ out:
 
 static int mmap_zero(struct file * file, struct vm_area_struct * vma)
 {
+       int err;
+
        if (vma->vm_flags & VM_SHARED)
                return shmem_zero_setup(vma);
-       if (zeromap_page_range(vma, vma->vm_start, vma->vm_end - vma->vm_start, vma->vm_page_prot))
-               return -EAGAIN;
-       return 0;
+       err = zeromap_page_range(vma, vma->vm_start,
+                       vma->vm_end - vma->vm_start, vma->vm_page_prot);
+       BUG_ON(err == -EEXIST);
+       return err;
 }
 #else /* CONFIG_MMU */
 static ssize_t read_zero(struct file * file, char * buf, 
@@ -726,7 +784,7 @@ static loff_t memory_lseek(struct file * file, loff_t offset, int orig)
 {
        loff_t ret;
 
-       down(&file->f_dentry->d_inode->i_sem);
+       mutex_lock(&file->f_path.dentry->d_inode->i_mutex);
        switch (orig) {
                case 0:
                        file->f_pos = offset;
@@ -741,7 +799,7 @@ static loff_t memory_lseek(struct file * file, loff_t offset, int orig)
                default:
                        ret = -EINVAL;
        }
-       up(&file->f_dentry->d_inode->i_sem);
+       mutex_unlock(&file->f_path.dentry->d_inode->i_mutex);
        return ret;
 }
 
@@ -758,30 +816,33 @@ static int open_port(struct inode * inode, struct file * filp)
 #define open_kmem      open_mem
 #define open_oldmem    open_mem
 
-static struct file_operations mem_fops = {
+static const struct file_operations mem_fops = {
        .llseek         = memory_lseek,
        .read           = read_mem,
        .write          = write_mem,
        .mmap           = mmap_mem,
        .open           = open_mem,
+       .get_unmapped_area = get_unmapped_area_mem,
 };
 
-static struct file_operations kmem_fops = {
+static const struct file_operations kmem_fops = {
        .llseek         = memory_lseek,
        .read           = read_kmem,
        .write          = write_kmem,
        .mmap           = mmap_kmem,
        .open           = open_kmem,
+       .get_unmapped_area = get_unmapped_area_mem,
 };
 
-static struct file_operations null_fops = {
+static const struct file_operations null_fops = {
        .llseek         = null_lseek,
        .read           = read_null,
        .write          = write_null,
+       .splice_write   = splice_write_null,
 };
 
-#if (defined(CONFIG_ISA) || !defined(__mc68000__)) && (!defined(CONFIG_PPC_ISERIES) || defined(CONFIG_PCI))
-static struct file_operations port_fops = {
+#ifdef CONFIG_DEVPORT
+static const struct file_operations port_fops = {
        .llseek         = memory_lseek,
        .read           = read_port,
        .write          = write_port,
@@ -789,25 +850,29 @@ static struct file_operations port_fops = {
 };
 #endif
 
-static struct file_operations zero_fops = {
+static const struct file_operations zero_fops = {
        .llseek         = zero_lseek,
        .read           = read_zero,
        .write          = write_zero,
        .mmap           = mmap_zero,
 };
 
+/*
+ * capabilities for /dev/zero
+ * - permits private mappings, "copies" are taken of the source of zeros
+ */
 static struct backing_dev_info zero_bdi = {
        .capabilities   = BDI_CAP_MAP_COPY,
 };
 
-static struct file_operations full_fops = {
+static const struct file_operations full_fops = {
        .llseek         = full_lseek,
        .read           = read_full,
        .write          = write_full,
 };
 
 #ifdef CONFIG_CRASH_DUMP
-static struct file_operations oldmem_fops = {
+static const struct file_operations oldmem_fops = {
        .read   = read_oldmem,
        .open   = open_oldmem,
 };
@@ -834,7 +899,7 @@ static ssize_t kmsg_write(struct file * file, const char __user * buf,
        return ret;
 }
 
-static struct file_operations kmsg_fops = {
+static const struct file_operations kmsg_fops = {
        .write =        kmsg_write,
 };
 
@@ -843,14 +908,18 @@ static int memory_open(struct inode * inode, struct file * filp)
        switch (iminor(inode)) {
                case 1:
                        filp->f_op = &mem_fops;
+                       filp->f_mapping->backing_dev_info =
+                               &directly_mappable_cdev_bdi;
                        break;
                case 2:
                        filp->f_op = &kmem_fops;
+                       filp->f_mapping->backing_dev_info =
+                               &directly_mappable_cdev_bdi;
                        break;
                case 3:
                        filp->f_op = &null_fops;
                        break;
-#if (defined(CONFIG_ISA) || !defined(__mc68000__)) && (!defined(CONFIG_PPC_ISERIES) || defined(CONFIG_PCI))
+#ifdef CONFIG_DEVPORT
                case 4:
                        filp->f_op = &port_fops;
                        break;
@@ -884,7 +953,7 @@ static int memory_open(struct inode * inode, struct file * filp)
        return 0;
 }
 
-static struct file_operations memory_fops = {
+static const struct file_operations memory_fops = {
        .open           = memory_open,  /* just a selector for the real open */
 };
 
@@ -892,12 +961,12 @@ static const struct {
        unsigned int            minor;
        char                    *name;
        umode_t                 mode;
-       struct file_operations  *fops;
+       const struct file_operations    *fops;
 } devlist[] = { /* list of minor devices */
        {1, "mem",     S_IRUSR | S_IWUSR | S_IRGRP, &mem_fops},
        {2, "kmem",    S_IRUSR | S_IWUSR | S_IRGRP, &kmem_fops},
        {3, "null",    S_IRUGO | S_IWUGO,           &null_fops},
-#if (defined(CONFIG_ISA) || !defined(__mc68000__)) && (!defined(CONFIG_PPC_ISERIES) || defined(CONFIG_PCI))
+#ifdef CONFIG_DEVPORT
        {4, "port",    S_IRUSR | S_IWUSR | S_IRGRP, &port_fops},
 #endif
        {5, "zero",    S_IRUGO | S_IWUGO,           &zero_fops},
@@ -920,14 +989,11 @@ static int __init chr_dev_init(void)
                printk("unable to get major %d for memory devs\n", MEM_MAJOR);
 
        mem_class = class_create(THIS_MODULE, "mem");
-       for (i = 0; i < ARRAY_SIZE(devlist); i++) {
-               class_device_create(mem_class, NULL,
-                                       MKDEV(MEM_MAJOR, devlist[i].minor),
-                                       NULL, devlist[i].name);
-               devfs_mk_cdev(MKDEV(MEM_MAJOR, devlist[i].minor),
-                               S_IFCHR | devlist[i].mode, devlist[i].name);
-       }
-       
+       for (i = 0; i < ARRAY_SIZE(devlist); i++)
+               device_create(mem_class, NULL,
+                             MKDEV(MEM_MAJOR, devlist[i].minor),
+                             devlist[i].name);
+
        return 0;
 }