diff options
-rw-r--r-- | arch/sparc/kernel/of_device.c | 2 | ||||
-rw-r--r-- | arch/sparc/kernel/prom.c | 106 | ||||
-rw-r--r-- | arch/sparc/lib/Makefile | 2 | ||||
-rw-r--r-- | arch/sparc/lib/iomap.c | 48 | ||||
-rw-r--r-- | arch/sparc64/kernel/auxio.c | 3 | ||||
-rw-r--r-- | arch/sparc64/kernel/irq.c | 61 | ||||
-rw-r--r-- | arch/sparc64/kernel/of_device.c | 3 | ||||
-rw-r--r-- | arch/sparc64/kernel/prom.c | 107 | ||||
-rw-r--r-- | arch/sparc64/mm/init.c | 1 | ||||
-rw-r--r-- | drivers/mtd/maps/sun_uflash.c | 195 | ||||
-rw-r--r-- | drivers/parport/parport_sunbpp.c | 2 | ||||
-rw-r--r-- | drivers/sbus/char/cpwatchdog.c | 2 | ||||
-rw-r--r-- | drivers/sbus/char/openprom.c | 593 | ||||
-rw-r--r-- | drivers/sbus/char/riowatchdog.c | 4 | ||||
-rw-r--r-- | fs/openpromfs/inode.c | 1158 | ||||
-rw-r--r-- | include/asm-sparc/io.h | 16 | ||||
-rw-r--r-- | include/asm-sparc/prom.h | 10 | ||||
-rw-r--r-- | include/asm-sparc64/dma-mapping.h | 43 | ||||
-rw-r--r-- | include/asm-sparc64/floppy.h | 50 | ||||
-rw-r--r-- | include/asm-sparc64/prom.h | 10 |
20 files changed, 1053 insertions, 1363 deletions
diff --git a/arch/sparc/kernel/of_device.c b/arch/sparc/kernel/of_device.c index 001b867..80a8094 100644 --- a/arch/sparc/kernel/of_device.c +++ b/arch/sparc/kernel/of_device.c @@ -138,6 +138,7 @@ struct bus_type ebus_bus_type = { .suspend = of_device_suspend, .resume = of_device_resume, }; +EXPORT_SYMBOL(ebus_bus_type); #endif #ifdef CONFIG_SBUS @@ -149,6 +150,7 @@ struct bus_type sbus_bus_type = { .suspend = of_device_suspend, .resume = of_device_resume, }; +EXPORT_SYMBOL(sbus_bus_type); #endif static int __init of_bus_driver_init(void) diff --git a/arch/sparc/kernel/prom.c b/arch/sparc/kernel/prom.c index 63b2b9b..946ce6d 100644 --- a/arch/sparc/kernel/prom.c +++ b/arch/sparc/kernel/prom.c @@ -27,6 +27,11 @@ static struct device_node *allnodes; +/* use when traversing tree through the allnext, child, sibling, + * or parent members of struct device_node. + */ +static DEFINE_RWLOCK(devtree_lock); + int of_device_is_compatible(struct device_node *device, const char *compat) { const char* cp; @@ -185,6 +190,54 @@ int of_getintprop_default(struct device_node *np, const char *name, int def) } EXPORT_SYMBOL(of_getintprop_default); +int of_set_property(struct device_node *dp, const char *name, void *val, int len) +{ + struct property **prevp; + void *new_val; + int err; + + new_val = kmalloc(len, GFP_KERNEL); + if (!new_val) + return -ENOMEM; + + memcpy(new_val, val, len); + + err = -ENODEV; + + write_lock(&devtree_lock); + prevp = &dp->properties; + while (*prevp) { + struct property *prop = *prevp; + + if (!strcmp(prop->name, name)) { + void *old_val = prop->value; + int ret; + + ret = prom_setprop(dp->node, name, val, len); + err = -EINVAL; + if (ret >= 0) { + prop->value = new_val; + prop->length = len; + + if (OF_IS_DYNAMIC(prop)) + kfree(old_val); + + OF_MARK_DYNAMIC(prop); + + err = 0; + } + break; + } + prevp = &(*prevp)->next; + } + write_unlock(&devtree_lock); + + /* XXX Upate procfs if necessary... */ + + return err; +} +EXPORT_SYMBOL(of_set_property); + static unsigned int prom_early_allocated; static void * __init prom_early_alloc(unsigned long size) @@ -354,7 +407,9 @@ static char * __init build_full_name(struct device_node *dp) return n; } -static struct property * __init build_one_prop(phandle node, char *prev) +static unsigned int unique_id; + +static struct property * __init build_one_prop(phandle node, char *prev, char *special_name, void *special_val, int special_len) { static struct property *tmp = NULL; struct property *p; @@ -364,25 +419,34 @@ static struct property * __init build_one_prop(phandle node, char *prev) p = tmp; memset(p, 0, sizeof(*p) + 32); tmp = NULL; - } else + } else { p = prom_early_alloc(sizeof(struct property) + 32); + p->unique_id = unique_id++; + } p->name = (char *) (p + 1); - if (prev == NULL) { - prom_firstprop(node, p->name); + if (special_name) { + p->length = special_len; + p->value = prom_early_alloc(special_len); + memcpy(p->value, special_val, special_len); } else { - prom_nextprop(node, prev, p->name); - } - if (strlen(p->name) == 0) { - tmp = p; - return NULL; - } - p->length = prom_getproplen(node, p->name); - if (p->length <= 0) { - p->length = 0; - } else { - p->value = prom_early_alloc(p->length); - len = prom_getproperty(node, p->name, p->value, p->length); + if (prev == NULL) { + prom_firstprop(node, p->name); + } else { + prom_nextprop(node, prev, p->name); + } + if (strlen(p->name) == 0) { + tmp = p; + return NULL; + } + p->length = prom_getproplen(node, p->name); + if (p->length <= 0) { + p->length = 0; + } else { + p->value = prom_early_alloc(p->length + 1); + prom_getproperty(node, p->name, p->value, p->length); + ((unsigned char *)p->value)[p->length] = '\0'; + } } return p; } @@ -391,9 +455,14 @@ static struct property * __init build_prop_list(phandle node) { struct property *head, *tail; - head = tail = build_one_prop(node, NULL); + head = tail = build_one_prop(node, NULL, + ".node", &node, sizeof(node)); + + tail->next = build_one_prop(node, NULL, NULL, NULL, 0); + tail = tail->next; while(tail) { - tail->next = build_one_prop(node, tail->name); + tail->next = build_one_prop(node, tail->name, + NULL, NULL, 0); tail = tail->next; } @@ -422,6 +491,7 @@ static struct device_node * __init create_node(phandle node) return NULL; dp = prom_early_alloc(sizeof(*dp)); + dp->unique_id = unique_id++; kref_init(&dp->kref); diff --git a/arch/sparc/lib/Makefile b/arch/sparc/lib/Makefile index fa50069..5db7e1d 100644 --- a/arch/sparc/lib/Makefile +++ b/arch/sparc/lib/Makefile @@ -9,3 +9,5 @@ lib-y := mul.o rem.o sdiv.o udiv.o umul.o urem.o ashrdi3.o memcpy.o memset.o \ strncpy_from_user.o divdi3.o udivdi3.o strlen_user.o \ copy_user.o locks.o atomic.o atomic32.o bitops.o \ lshrdi3.o ashldi3.o rwsem.o muldi3.o bitext.o + +obj-y += iomap.o diff --git a/arch/sparc/lib/iomap.c b/arch/sparc/lib/iomap.c new file mode 100644 index 0000000..54501c1 --- /dev/null +++ b/arch/sparc/lib/iomap.c @@ -0,0 +1,48 @@ +/* + * Implement the sparc iomap interfaces + */ +#include <linux/pci.h> +#include <linux/module.h> +#include <asm/io.h> + +/* Create a virtual mapping cookie for an IO port range */ +void __iomem *ioport_map(unsigned long port, unsigned int nr) +{ + return (void __iomem *) (unsigned long) port; +} + +void ioport_unmap(void __iomem *addr) +{ + /* Nothing to do */ +} +EXPORT_SYMBOL(ioport_map); +EXPORT_SYMBOL(ioport_unmap); + +/* Create a virtual mapping cookie for a PCI BAR (memory or IO) */ +void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen) +{ + unsigned long start = pci_resource_start(dev, bar); + unsigned long len = pci_resource_len(dev, bar); + unsigned long flags = pci_resource_flags(dev, bar); + + if (!len || !start) + return NULL; + if (maxlen && len > maxlen) + len = maxlen; + if (flags & IORESOURCE_IO) + return ioport_map(start, len); + if (flags & IORESOURCE_MEM) { + if (flags & IORESOURCE_CACHEABLE) + return ioremap(start, len); + return ioremap_nocache(start, len); + } + /* What? */ + return NULL; +} + +void pci_iounmap(struct pci_dev *dev, void __iomem * addr) +{ + /* nothing to do */ +} +EXPORT_SYMBOL(pci_iomap); +EXPORT_SYMBOL(pci_iounmap); diff --git a/arch/sparc64/kernel/auxio.c b/arch/sparc64/kernel/auxio.c index 2c42894..c2c69c1 100644 --- a/arch/sparc64/kernel/auxio.c +++ b/arch/sparc64/kernel/auxio.c @@ -6,6 +6,7 @@ */ #include <linux/config.h> +#include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/ioport.h> @@ -16,8 +17,8 @@ #include <asm/ebus.h> #include <asm/auxio.h> -/* This cannot be static, as it is referenced in irq.c */ void __iomem *auxio_register = NULL; +EXPORT_SYMBOL(auxio_register); enum auxio_type { AUXIO_TYPE_NODEV, diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c index 31e0fbb..cc89b06 100644 --- a/arch/sparc64/kernel/irq.c +++ b/arch/sparc64/kernel/irq.c @@ -563,67 +563,6 @@ void handler_irq(int irq, struct pt_regs *regs) irq_exit(); } -#ifdef CONFIG_BLK_DEV_FD -extern irqreturn_t floppy_interrupt(int, void *, struct pt_regs *); - -/* XXX No easy way to include asm/floppy.h XXX */ -extern unsigned char *pdma_vaddr; -extern unsigned long pdma_size; -extern volatile int doing_pdma; -extern unsigned long fdc_status; - -irqreturn_t sparc_floppy_irq(int irq, void *dev_cookie, struct pt_regs *regs) -{ - if (likely(doing_pdma)) { - void __iomem *stat = (void __iomem *) fdc_status; - unsigned char *vaddr = pdma_vaddr; - unsigned long size = pdma_size; - u8 val; - - while (size) { - val = readb(stat); - if (unlikely(!(val & 0x80))) { - pdma_vaddr = vaddr; - pdma_size = size; - return IRQ_HANDLED; - } - if (unlikely(!(val & 0x20))) { - pdma_vaddr = vaddr; - pdma_size = size; - doing_pdma = 0; - goto main_interrupt; - } - if (val & 0x40) { - /* read */ - *vaddr++ = readb(stat + 1); - } else { - unsigned char data = *vaddr++; - - /* write */ - writeb(data, stat + 1); - } - size--; - } - - pdma_vaddr = vaddr; - pdma_size = size; - - /* Send Terminal Count pulse to floppy controller. */ - val = readb(auxio_register); - val |= AUXIO_AUX1_FTCNT; - writeb(val, auxio_register); - val &= ~AUXIO_AUX1_FTCNT; - writeb(val, auxio_register); - - doing_pdma = 0; - } - -main_interrupt: - return floppy_interrupt(irq, dev_cookie, regs); -} -EXPORT_SYMBOL(sparc_floppy_irq); -#endif - struct sun5_timer { u64 count0; u64 limit0; diff --git a/arch/sparc64/kernel/of_device.c b/arch/sparc64/kernel/of_device.c index 566aa34..768475b 100644 --- a/arch/sparc64/kernel/of_device.c +++ b/arch/sparc64/kernel/of_device.c @@ -138,6 +138,7 @@ struct bus_type isa_bus_type = { .suspend = of_device_suspend, .resume = of_device_resume, }; +EXPORT_SYMBOL(isa_bus_type); struct bus_type ebus_bus_type = { .name = "ebus", @@ -147,6 +148,7 @@ struct bus_type ebus_bus_type = { .suspend = of_device_suspend, .resume = of_device_resume, }; +EXPORT_SYMBOL(ebus_bus_type); #endif #ifdef CONFIG_SBUS @@ -158,6 +160,7 @@ struct bus_type sbus_bus_type = { .suspend = of_device_suspend, .resume = of_device_resume, }; +EXPORT_SYMBOL(sbus_bus_type); #endif static int __init of_bus_driver_init(void) diff --git a/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c index e9d703e..8e87e7e 100644 --- a/arch/sparc64/kernel/prom.c +++ b/arch/sparc64/kernel/prom.c @@ -27,6 +27,11 @@ static struct device_node *allnodes; +/* use when traversing tree through the allnext, child, sibling, + * or parent members of struct device_node. + */ +static DEFINE_RWLOCK(devtree_lock); + int of_device_is_compatible(struct device_node *device, const char *compat) { const char* cp; @@ -185,6 +190,54 @@ int of_getintprop_default(struct device_node *np, const char *name, int def) } EXPORT_SYMBOL(of_getintprop_default); +int of_set_property(struct device_node *dp, const char *name, void *val, int len) +{ + struct property **prevp; + void *new_val; + int err; + + new_val = kmalloc(len, GFP_KERNEL); + if (!new_val) + return -ENOMEM; + + memcpy(new_val, val, len); + + err = -ENODEV; + + write_lock(&devtree_lock); + prevp = &dp->properties; + while (*prevp) { + struct property *prop = *prevp; + + if (!strcmp(prop->name, name)) { + void *old_val = prop->value; + int ret; + + ret = prom_setprop(dp->node, name, val, len); + err = -EINVAL; + if (ret >= 0) { + prop->value = new_val; + prop->length = len; + + if (OF_IS_DYNAMIC(prop)) + kfree(old_val); + + OF_MARK_DYNAMIC(prop); + + err = 0; + } + break; + } + prevp = &(*prevp)->next; + } + write_unlock(&devtree_lock); + + /* XXX Upate procfs if necessary... */ + + return err; +} +EXPORT_SYMBOL(of_set_property); + static unsigned int prom_early_allocated; static void * __init prom_early_alloc(unsigned long size) @@ -531,7 +584,9 @@ static char * __init build_full_name(struct device_node *dp) return n; } -static struct property * __init build_one_prop(phandle node, char *prev) +static unsigned int unique_id; + +static struct property * __init build_one_prop(phandle node, char *prev, char *special_name, void *special_val, int special_len) { static struct property *tmp = NULL; struct property *p; @@ -540,25 +595,35 @@ static struct property * __init build_one_prop(phandle node, char *prev) p = tmp; memset(p, 0, sizeof(*p) + 32); tmp = NULL; - } else + } else { p = prom_early_alloc(sizeof(struct property) + 32); + p->unique_id = unique_id++; + } p->name = (char *) (p + 1); - if (prev == NULL) { - prom_firstprop(node, p->name); + if (special_name) { + strcpy(p->name, special_name); + p->length = special_len; + p->value = prom_early_alloc(special_len); + memcpy(p->value, special_val, special_len); } else { - prom_nextprop(node, prev, p->name); - } - if (strlen(p->name) == 0) { - tmp = p; - return NULL; - } - p->length = prom_getproplen(node, p->name); - if (p->length <= 0) { - p->length = 0; - } else { - p->value = prom_early_alloc(p->length); - prom_getproperty(node, p->name, p->value, p->length); + if (prev == NULL) { + prom_firstprop(node, p->name); + } else { + prom_nextprop(node, prev, p->name); + } + if (strlen(p->name) == 0) { + tmp = p; + return NULL; + } + p->length = prom_getproplen(node, p->name); + if (p->length <= 0) { + p->length = 0; + } else { + p->value = prom_early_alloc(p->length + 1); + prom_getproperty(node, p->name, p->value, p->length); + ((unsigned char *)p->value)[p->length] = '\0'; + } } return p; } @@ -567,9 +632,14 @@ static struct property * __init build_prop_list(phandle node) { struct property *head, *tail; - head = tail = build_one_prop(node, NULL); + head = tail = build_one_prop(node, NULL, + ".node", &node, sizeof(node)); + + tail->next = build_one_prop(node, NULL, NULL, NULL, 0); + tail = tail->next; while(tail) { - tail->next = build_one_prop(node, tail->name); + tail->next = build_one_prop(node, tail->name, + NULL, NULL, 0); tail = tail->next; } @@ -598,6 +668,7 @@ static struct device_node * __init create_node(phandle node) return NULL; dp = prom_early_alloc(sizeof(*dp)); + dp->unique_id = unique_id++; kref_init(&dp->kref); diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index 5139934..5c2bcf3 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c @@ -1568,6 +1568,7 @@ pgprot_t PAGE_EXEC __read_mostly; unsigned long pg_iobits __read_mostly; unsigned long _PAGE_IE __read_mostly; +EXPORT_SYMBOL(_PAGE_IE); unsigned long _PAGE_E __read_mostly; EXPORT_SYMBOL(_PAGE_E); diff --git a/drivers/mtd/maps/sun_uflash.c b/drivers/mtd/maps/sun_uflash.c index 0758cb1..24a0315 100644 --- a/drivers/mtd/maps/sun_uflash.c +++ b/drivers/mtd/maps/sun_uflash.c @@ -18,6 +18,7 @@ #include <linux/ioport.h> #include <asm/ebus.h> #include <asm/oplib.h> +#include <asm/prom.h> #include <asm/uaccess.h> #include <asm/io.h> @@ -30,146 +31,140 @@ #define UFLASH_WINDOW_SIZE 0x200000 #define UFLASH_BUSWIDTH 1 /* EBus is 8-bit */ -MODULE_AUTHOR - ("Eric Brower <ebrower@usa.net>"); -MODULE_DESCRIPTION - ("User-programmable flash device on Sun Microsystems boardsets"); -MODULE_SUPPORTED_DEVICE - ("userflash"); -MODULE_LICENSE - ("GPL"); +MODULE_AUTHOR("Eric Brower <ebrower@usa.net>"); +MODULE_DESCRIPTION("User-programmable flash device on Sun Microsystems boardsets"); +MODULE_SUPPORTED_DEVICE("userflash"); +MODULE_LICENSE("GPL"); +MODULE_VERSION("2.0"); static LIST_HEAD(device_list); struct uflash_dev { - char * name; /* device name */ + char *name; /* device name */ struct map_info map; /* mtd map info */ - struct mtd_info * mtd; /* mtd info */ - struct list_head list; + struct mtd_info *mtd; /* mtd info */ }; struct map_info uflash_map_templ = { - .name = "SUNW,???-????", - .size = UFLASH_WINDOW_SIZE, - .bankwidth = UFLASH_BUSWIDTH, + .name = "SUNW,???-????", + .size = UFLASH_WINDOW_SIZE, + .bankwidth = UFLASH_BUSWIDTH, }; -int uflash_devinit(struct linux_ebus_device* edev) +int uflash_devinit(struct linux_ebus_device *edev, struct device_node *dp) { - int iTmp, nregs; - struct linux_prom_registers regs[2]; - struct uflash_dev *pdev; - - iTmp = prom_getproperty( - edev->prom_node, "reg", (void *)regs, sizeof(regs)); - if ((iTmp % sizeof(regs[0])) != 0) { - printk("%s: Strange reg property size %d\n", - UFLASH_DEVNAME, iTmp); - return -ENODEV; - } + struct uflash_dev *up; + struct resource *res; - nregs = iTmp / sizeof(regs[0]); + res = &edev->resource[0]; - if (nregs != 1) { + if (edev->num_addrs != 1) { /* Non-CFI userflash device-- once I find one we * can work on supporting it. */ printk("%s: unsupported device at 0x%lx (%d regs): " \ "email ebrower@usa.net\n", - UFLASH_DEVNAME, edev->resource[0].start, nregs); + dp->full_name, res->start, edev->num_addrs); + return -ENODEV; } - if(0 == (pdev = kmalloc(sizeof(struct uflash_dev), GFP_KERNEL))) { - printk("%s: unable to kmalloc new device\n", UFLASH_DEVNAME); - return(-ENOMEM); - } + up = kzalloc(sizeof(struct uflash_dev), GFP_KERNEL); + if (!up) + return -ENOMEM; /* copy defaults and tweak parameters */ - memcpy(&pdev->map, &uflash_map_templ, sizeof(uflash_map_templ)); - pdev->map.size = regs[0].reg_size; - - iTmp = prom_getproplen(edev->prom_node, "model"); - pdev->name = kmalloc(iTmp, GFP_KERNEL); - prom_getstring(edev->prom_node, "model", pdev->name, iTmp); - if(0 != pdev->name && 0 < strlen(pdev->name)) { - pdev->map.name = pdev->name; - } - pdev->map.phys = edev->resource[0].start; - pdev->map.virt = ioremap_nocache(edev->resource[0].start, pdev->map.size); - if(0 == pdev->map.virt) { - printk("%s: failed to map device\n", __FUNCTION__); - kfree(pdev->name); - kfree(pdev); - return(-1); + memcpy(&up->map, &uflash_map_templ, sizeof(uflash_map_templ)); + up->map.size = (res->end - res->start) + 1UL; + + up->name = of_get_property(dp, "model", NULL); + if (up->name && 0 < strlen(up->name)) + up->map.name = up->name; + + up->map.phys = res->start; + + up->map.virt = ioremap_nocache(res->start, up->map.size); + if (!up->map.virt) { + printk("%s: Failed to map device.\n", dp->full_name); + kfree(up); + + return -EINVAL; } - simple_map_init(&pdev->map); + simple_map_init(&up->map); /* MTD registration */ - pdev->mtd = do_map_probe("cfi_probe", &pdev->map); - if(0 == pdev->mtd) { - iounmap(pdev->map.virt); - kfree(pdev->name); - kfree(pdev); - return(-ENXIO); + up->mtd = do_map_probe("cfi_probe", &up->map); + if (!up->mtd) { + iounmap(up->map.virt); + kfree(up); + + return -ENXIO; } - list_add(&pdev->list, &device_list); + up->mtd->owner = THIS_MODULE; - pdev->mtd->owner = THIS_MODULE; + add_mtd_device(up->mtd); - add_mtd_device(pdev->mtd); - return(0); + dev_set_drvdata(&edev->ofdev.dev, up); + + return 0; } -static int __init uflash_init(void) +static int __devinit uflash_probe(struct of_device *dev, const struct of_device_id *match) { - struct linux_ebus *ebus = NULL; - struct linux_ebus_device *edev = NULL; - - for_each_ebus(ebus) { - for_each_ebusdev(edev, ebus) { - if (!strcmp(edev->prom_name, UFLASH_OBPNAME)) { - if(0 > prom_getproplen(edev->prom_node, "user")) { - DEBUG(2, "%s: ignoring device at 0x%lx\n", - UFLASH_DEVNAME, edev->resource[0].start); - } else { - uflash_devinit(edev); - } - } - } - } + struct linux_ebus_device *edev = to_ebus_device(&dev->dev); + struct device_node *dp = dev->node; - if(list_empty(&device_list)) { - printk("%s: unable to locate device\n", UFLASH_DEVNAME); + if (of_find_property(dp, "user", NULL)) return -ENODEV; - } - return(0); + + return uflash_devinit(edev, dp); } -static void __exit uflash_cleanup(void) +static int __devexit uflash_remove(struct of_device *dev) { - struct list_head *udevlist; - struct uflash_dev *udev; - - list_for_each(udevlist, &device_list) { - udev = list_entry(udevlist, struct uflash_dev, list); - DEBUG(2, "%s: removing device %s\n", - UFLASH_DEVNAME, udev->name); - - if(0 != udev->mtd) { - del_mtd_device(udev->mtd); - map_destroy(udev->mtd); - } - if(0 != udev->map.virt) { - iounmap(udev->map.virt); - udev->map.virt = NULL; - } - kfree(udev->name); - kfree(udev); + struct uflash_dev *up = dev_get_drvdata(&dev->dev); + + if (up->mtd) { + del_mtd_device(up->mtd); + map_destroy(up->mtd); } + if (up->map.virt) { + iounmap(up->map.virt); + up->map.virt = NULL; + } + + kfree(up); + + return 0; +} + +static struct of_device_id uflash_match[] = { + { + .name = UFLASH_OBPNAME, + }, + {}, +}; + +MODULE_DEVICE_TABLE(of, uflash_match); + +static struct of_platform_driver uflash_driver = { + .name = UFLASH_DEVNAME, + .match_table = uflash_match, + .probe = uflash_probe, + .remove = __devexit_p(uflash_remove), +}; + +static int __init uflash_init(void) +{ + return of_register_driver(&uflash_driver, &ebus_bus_type); +} + +static void __exit uflash_exit(void) +{ + of_unregister_driver(&uflash_driver); } module_init(uflash_init); -module_exit(uflash_cleanup); +module_exit(uflash_exit); diff --git a/drivers/parport/parport_sunbpp.c b/drivers/parport/parport_sunbpp.c index 69a4bbd..7c43c53 100644 --- a/drivers/parport/parport_sunbpp.c +++ b/drivers/parport/parport_sunbpp.c @@ -389,7 +389,7 @@ static struct of_device_id bpp_match[] = { {}, }; -MODULE_DEVICE_TABLE(of, qec_sbus_match); +MODULE_DEVICE_TABLE(of, bpp_match); static struct of_platform_driver bpp_sbus_driver = { .name = "bpp", diff --git a/drivers/sbus/char/cpwatchdog.c b/drivers/sbus/char/cpwatchdog.c index 5bf3dd9..21737b7 100644 --- a/drivers/sbus/char/cpwatchdog.c +++ b/drivers/sbus/char/cpwatchdog.c @@ -755,7 +755,7 @@ static int __init wd_init(void) for_each_ebus(ebus) { for_each_ebusdev(edev, ebus) { - if (!strcmp(edev->prom_name, WD_OBPNAME)) + if (!strcmp(edev->ofdev.node->name, WD_OBPNAME)) goto ebus_done; } } diff --git a/drivers/sbus/char/openprom.c b/drivers/sbus/char/openprom.c index cf5b476..d7e4bb4 100644 --- a/drivers/sbus/char/openprom.c +++ b/drivers/sbus/char/openprom.c @@ -29,8 +29,6 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#define PROMLIB_INTERNAL - #include <linux/config.h> #include <linux/module.h> #include <linux/kernel.h> @@ -39,10 +37,10 @@ #include <linux/slab.h> #include <linux/string.h> #include <linux/miscdevice.h> -#include <linux/smp_lock.h> #include <linux/init.h> #include <linux/fs.h> #include <asm/oplib.h> +#include <asm/prom.h> #include <asm/system.h> #include <asm/uaccess.h> #include <asm/openpromio.h> @@ -51,15 +49,20 @@ #include <asm/pbm.h> #endif +MODULE_AUTHOR("Thomas K. Dyas (tdyas@noc.rutgers.edu) and Eddie C. Dost (ecd@skynet.be)"); +MODULE_DESCRIPTION("OPENPROM Configuration Driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION("1.0"); + /* Private data kept by the driver for each descriptor. */ typedef struct openprom_private_data { - int current_node; /* Current node for SunOS ioctls. */ - int lastnode; /* Last valid node used by BSD ioctls. */ + struct device_node *current_node; /* Current node for SunOS ioctls. */ + struct device_node *lastnode; /* Last valid node used by BSD ioctls. */ } DATA; /* ID of the PROM node containing all of the EEPROM options. */ -static int options_node = 0; +static struct device_node *options_node; /* * Copy an openpromio structure into kernel space from user space. @@ -87,9 +90,8 @@ static int copyin(struct openpromio __user *info, struct openpromio **opp_p) if (bufsize > OPROMMAXPARAM) bufsize = OPROMMAXPARAM; - if (!(*opp_p = kmalloc(sizeof(int) + bufsize + 1, GFP_KERNEL))) + if (!(*opp_p = kzalloc(sizeof(int) + bufsize + 1, GFP_KERNEL))) return -ENOMEM; - memset(*opp_p, 0, sizeof(int) + bufsize + 1); if (copy_from_user(&(*opp_p)->oprom_array, &info->oprom_array, bufsize)) { @@ -107,10 +109,9 @@ static int getstrings(struct openpromio __user *info, struct openpromio **opp_p) if (!info || !opp_p) return -EFAULT; - if (!(*opp_p = kmalloc(sizeof(int) + OPROMMAXPARAM + 1, GFP_KERNEL))) + if (!(*opp_p = kzalloc(sizeof(int) + OPROMMAXPARAM + 1, GFP_KERNEL))) return -ENOMEM; - memset(*opp_p, 0, sizeof(int) + OPROMMAXPARAM + 1); (*opp_p)->oprom_size = 0; n = bufsize = 0; @@ -140,16 +141,164 @@ static int copyout(void __user *info, struct openpromio *opp, int len) return 0; } +static int opromgetprop(void __user *argp, struct device_node *dp, struct openpromio *op, int bufsize) +{ + void *pval; + int len; + + pval = of_get_property(dp, op->oprom_array, &len); + if (!pval || len <= 0 || len > bufsize) + return copyout(argp, op, sizeof(int)); + + memcpy(op->oprom_array, pval, len); + op->oprom_array[len] = '\0'; + op->oprom_size = len; + + return copyout(argp, op, sizeof(int) + bufsize); +} + +static int opromnxtprop(void __user *argp, struct device_node *dp, struct openpromio *op, int bufsize) +{ + struct property *prop; + int len; + + if (op->oprom_array[0] == '\0') { + prop = dp->properties; + if (!prop) + return copyout(argp, op, sizeof(int)); + len = strlen(prop->name); + } else { + prop = of_find_property(dp, op->oprom_array, NULL); + + if (!prop || + !prop->next || + (len = strlen(prop->next->name)) + 1 > bufsize) + return copyout(argp, op, sizeof(int)); + + prop = prop->next; + } + + memcpy(op->oprom_array, prop->name, len); + op->oprom_array[len] = '\0'; + op->oprom_size = ++len; + + return copyout(argp, op, sizeof(int) + bufsize); +} + +static int opromsetopt(struct device_node *dp, struct openpromio *op, int bufsize) +{ + char *buf = op->oprom_array + strlen(op->oprom_array) + 1; + int len = op->oprom_array + bufsize - buf; + + return of_set_property(options_node, op->oprom_array, buf, len); +} + +static int opromnext(void __user *argp, unsigned int cmd, struct device_node *dp, struct openpromio *op, int bufsize, DATA *data) +{ + phandle ph; + + BUILD_BUG_ON(sizeof(phandle) != sizeof(int)); + + if (bufsize < sizeof(phandle)) + return -EINVAL; + + ph = *((int *) op->oprom_array); + if (ph) { + dp = of_find_node_by_phandle(ph); + if (!dp) + return -EINVAL; + + switch (cmd) { + case OPROMNEXT: + dp = dp->sibling; + break; + + case OPROMCHILD: + dp = dp->child; + break; + + case OPROMSETCUR: + default: + break; + }; + } else { + /* Sibling of node zero is the root node. */ + if (cmd != OPROMNEXT) + return -EINVAL; + + dp = of_find_node_by_path("/"); + } + + ph = 0; + if (dp) + ph = dp->node; + + data->current_node = dp; + *((int *) op->oprom_array) = ph; + op->oprom_size = sizeof(phandle); + + return copyout(argp, op, bufsize + sizeof(int)); +} + +static int oprompci2node(void __user *argp, struct device_node *dp, struct openpromio *op, int bufsize, DATA *data) +{ + int err = -EINVAL; + + if (bufsize >= 2*sizeof(int)) { +#ifdef CONFIG_PCI + struct pci_dev *pdev; + struct pcidev_cookie *pcp; + pdev = pci_find_slot (((int *) op->oprom_array)[0], + ((int *) op->oprom_array)[1]); + + pcp = pdev->sysdata; + if (pcp != NULL) { + dp = pcp->prom_node; + data->current_node = dp; + *((int *)op->oprom_array) = dp->node; + op->oprom_size = sizeof(int); + err = copyout(argp, op, bufsize + sizeof(int)); + } +#endif + } + + return err; +} + +static int oprompath2node(void __user *argp, struct device_node *dp, struct openpromio *op, int bufsize, DATA *data) +{ + dp = of_find_node_by_path(op->oprom_array); + data->current_node = dp; + *((int *)op->oprom_array) = dp->node; + op->oprom_size = sizeof(int); + + return copyout(argp, op, bufsize + sizeof(int)); +} + +static int opromgetbootargs(void __user *argp, struct openpromio *op, int bufsize) +{ + char *buf = saved_command_line; + int len = strlen(buf); + + if (len > bufsize) + return -EINVAL; + + strcpy(op->oprom_array, buf); + op->oprom_size = len; + + return copyout(argp, op, bufsize + sizeof(int)); +} + /* * SunOS and Solaris /dev/openprom ioctl calls. */ static int openprom_sunos_ioctl(struct inode * inode, struct file * file, - unsigned int cmd, unsigned long arg, int node) + unsigned int cmd, unsigned long arg, + struct device_node *dp) { - DATA *data = (DATA *) file->private_data; - char buffer[OPROMMAXPARAM+1], *buf; + DATA *data = file->private_data; struct openpromio *opp; - int bufsize, len, error = 0; + int bufsize, error = 0; static int cnt; void __user *argp = (void __user *)arg; @@ -164,119 +313,35 @@ static int openprom_sunos_ioctl(struct inode * inode, struct file * file, switch (cmd) { case OPROMGETOPT: case OPROMGETPROP: - len = prom_getproplen(node, opp->oprom_array); - - if (len <= 0 || len > bufsize) { - error = copyout(argp, opp, sizeof(int)); - break; - } - - len = prom_getproperty(node, opp->oprom_array, buffer, bufsize); - - memcpy(opp->oprom_array, buffer, len); - opp->oprom_array[len] = '\0'; - opp->oprom_size = len; - - error = copyout(argp, opp, sizeof(int) + bufsize); + error = opromgetprop(argp, dp, opp, bufsize); break; case OPROMNXTOPT: case OPROMNXTPROP: - buf = prom_nextprop(node, opp->oprom_array, buffer); - - len = strlen(buf); - if (len == 0 || len + 1 > bufsize) { - error = copyout(argp, opp, sizeof(int)); - break; - } - - memcpy(opp->oprom_array, buf, len); - opp->oprom_array[len] = '\0'; - opp->oprom_size = ++len; - - error = copyout(argp, opp, sizeof(int) + bufsize); + error = opromnxtprop(argp, dp, opp, bufsize); break; case OPROMSETOPT: case OPROMSETOPT2: - buf = opp->oprom_array + strlen(opp->oprom_array) + 1; - len = opp->oprom_array + bufsize - buf; - - error = prom_setprop(options_node, opp->oprom_array, - buf, len); - - if (error < 0) - error = -EINVAL; + error = opromsetopt(dp, opp, bufsize); break; case OPROMNEXT: case OPROMCHILD: case OPROMSETCUR: - if (bufsize < sizeof(int)) { - error = -EINVAL; - break; - } - - node = *((int *) opp->oprom_array); - - switch (cmd) { - case OPROMNEXT: node = __prom_getsibling(node); break; - case OPROMCHILD: node = __prom_getchild(node); break; - case OPROMSETCUR: break; - } - - data->current_node = node; - *((int *)opp->oprom_array) = node; - opp->oprom_size = sizeof(int); - - error = copyout(argp, opp, bufsize + sizeof(int)); + error = opromnext(argp, cmd, dp, opp, bufsize, data); break; case OPROMPCI2NODE: - error = -EINVAL; - - if (bufsize >= 2*sizeof(int)) { -#ifdef CONFIG_PCI - struct pci_dev *pdev; - struct pcidev_cookie *pcp; - pdev = pci_find_slot (((int *) opp->oprom_array)[0], - ((int *) opp->oprom_array)[1]); - - pcp = pdev->sysdata; - if (pcp != NULL) { - node = pcp->prom_node->node; - data->current_node = node; - *((int *)opp->oprom_array) = node; - opp->oprom_size = sizeof(int); - error = copyout(argp, opp, bufsize + sizeof(int)); - } -#endif - } + error = oprompci2node(argp, dp, opp, bufsize, data); break; case OPROMPATH2NODE: - node = prom_finddevice(opp->oprom_array); - data->current_node = node; - *((int *)opp->oprom_array) = node; - opp->oprom_size = sizeof(int); - - error = copyout(argp, opp, bufsize + sizeof(int)); + error = oprompath2node(argp, dp, opp, bufsize, data); break; case OPROMGETBOOTARGS: - buf = saved_command_line; - - len = strlen(buf); - - if (len > bufsize) { - error = -EINVAL; - break; - } - - strcpy(opp->oprom_array, buf); - opp->oprom_size = len; - - error = copyout(argp, opp, bufsize + sizeof(int)); + error = opromgetbootargs(argp, opp, bufsize); break; case OPROMU2P: @@ -297,25 +362,14 @@ static int openprom_sunos_ioctl(struct inode * inode, struct file * file, return error; } - -/* Return nonzero if a specific node is in the PROM device tree. */ -static int intree(int root, int node) +static struct device_node *get_node(phandle n, DATA *data) { - for (; root != 0; root = prom_getsibling(root)) - if (root == node || intree(prom_getchild(root),node)) - return 1; - return 0; -} + struct device_node *dp = of_find_node_by_phandle(n); -/* Return nonzero if a specific node is "valid". */ -static int goodnode(int n, DATA *data) -{ - if (n == data->lastnode || n == prom_root_node || n == options_node) - return 1; - if (n == 0 || n == -1 || !intree(prom_root_node,n)) - return 0; - data->lastnode = n; - return 1; + if (dp) + data->lastnode = dp; + + return dp; } /* Copy in a whole string from userspace into kernelspace. */ @@ -330,7 +384,7 @@ static int copyin_string(char __user *user, size_t len, char **ptr) if (!tmp) return -ENOMEM; - if(copy_from_user(tmp, user, len)) { + if (copy_from_user(tmp, user, len)) { kfree(tmp); return -EFAULT; } @@ -345,162 +399,187 @@ static int copyin_string(char __user *user, size_t len, char **ptr) /* * NetBSD /dev/openprom ioctl calls. */ -static int openprom_bsd_ioctl(struct inode * inode, struct file * file, - unsigned int cmd, unsigned long arg) +static int opiocget(void __user *argp, DATA *data) { - DATA *data = (DATA *) file->private_data; - void __user *argp = (void __user *)arg; struct opiocdesc op; - int error, node, len; - char *str, *tmp; - char buffer[64]; - static int cnt; - - switch (cmd) { - case OPIOCGET: - if (copy_from_user(&op, argp, sizeof(op))) - return -EFAULT; - - if (!goodnode(op.op_nodeid,data)) - return -EINVAL; + struct device_node *dp; + char *str; + void *pval; + int err, len; - error = copyin_string(op.op_name, op.op_namelen, &str); - if (error) - return error; + if (copy_from_user(&op, argp, sizeof(op))) + return -EFAULT; - len = prom_getproplen(op.op_nodeid,str); + dp = get_node(op.op_nodeid, data); - if (len > op.op_buflen) { - kfree(str); - return -ENOMEM; - } + err = copyin_string(op.op_name, op.op_namelen, &str); + if (err) + return err; + pval = of_get_property(dp, str, &len); + err = 0; + if (!pval || len > op.op_buflen) { + err = -EINVAL; + } else { op.op_buflen = len; + if (copy_to_user(argp, &op, sizeof(op)) || + copy_to_user(op.op_buf, pval, len)) + err = -EFAULT; + } + kfree(str); - if (len <= 0) { - kfree(str); - /* Verified by the above copy_from_user */ - if (__copy_to_user(argp, &op, - sizeof(op))) - return -EFAULT; - return 0; - } + return err; +} - tmp = kmalloc(len + 1, GFP_KERNEL); - if (!tmp) { - kfree(str); - return -ENOMEM; - } +static int opiocnextprop(void __user *argp, DATA *data) +{ + struct opiocdesc op; + struct device_node *dp; + struct property *prop; + char *str; + int err, len; - cnt = prom_getproperty(op.op_nodeid, str, tmp, len); - if (cnt <= 0) { - error = -EINVAL; - } else { - tmp[len] = '\0'; + if (copy_from_user(&op, argp, sizeof(op))) + return -EFAULT; - if (__copy_to_user(argp, &op, sizeof(op)) != 0 || - copy_to_user(op.op_buf, tmp, len) != 0) - error = -EFAULT; - } + dp = get_node(op.op_nodeid, data); + if (!dp) + return -EINVAL; - kfree(tmp); - kfree(str); + err = copyin_string(op.op_name, op.op_namelen, &str); + if (err) + return err; - return error; + if (str[0] == '\0') { + prop = dp->properties; + } else { + prop = of_find_property(dp, str, NULL); + if (prop) + prop = prop->next; + } + kfree(str); - case OPIOCNEXTPROP: - if (copy_from_user(&op, argp, sizeof(op))) - return -EFAULT; + if (!prop) + len = 0; + else + len = prop->length; - if (!goodnode(op.op_nodeid,data)) - return -EINVAL; + if (len > op.op_buflen) + len = op.op_buflen; - error = copyin_string(op.op_name, op.op_namelen, &str); - if (error) - return error; + if (copy_to_user(argp, &op, sizeof(op))) + return -EFAULT; - tmp = prom_nextprop(op.op_nodeid,str,buffer); + if (len && + copy_to_user(op.op_buf, prop->value, len)) + return -EFAULT; - if (tmp) { - len = strlen(tmp); - if (len > op.op_buflen) - len = op.op_buflen; - else - op.op_buflen = len; - } else { - len = op.op_buflen = 0; - } + return 0; +} - if (!access_ok(VERIFY_WRITE, argp, sizeof(op))) { - kfree(str); - return -EFAULT; - } +static int opiocset(void __user *argp, DATA *data) +{ + struct opiocdesc op; + struct device_node *dp; + char *str, *tmp; + int err; - if (!access_ok(VERIFY_WRITE, op.op_buf, len)) { - kfree(str); - return -EFAULT; - } + if (copy_from_user(&op, argp, sizeof(op))) + return -EFAULT; + + dp = get_node(op.op_nodeid, data); + if (!dp) + return -EINVAL; - error = __copy_to_user(argp, &op, sizeof(op)); - if (!error) error = __copy_to_user(op.op_buf, tmp, len); + err = copyin_string(op.op_name, op.op_namelen, &str); + if (err) + return err; + err = copyin_string(op.op_buf, op.op_buflen, &tmp); + if (err) { kfree(str); + return err; + } - return error; + err = of_set_property(dp, str, tmp, op.op_buflen); - case OPIOCSET: - if (copy_from_user(&op, argp, sizeof(op))) - return -EFAULT; + kfree(str); + kfree(tmp); - if (!goodnode(op.op_nodeid,data)) - return -EINVAL; + return err; +} - error = copyin_string(op.op_name, op.op_namelen, &str); - if (error) - return error; +static int opiocgetnext(unsigned int cmd, void __user *argp) +{ + struct device_node *dp; + phandle nd; - error = copyin_string(op.op_buf, op.op_buflen, &tmp); - if (error) { - kfree(str); - return error; - } + BUILD_BUG_ON(sizeof(phandle) != sizeof(int)); - len = prom_setprop(op.op_nodeid,str,tmp,op.op_buflen+1); + if (copy_from_user(&nd, argp, sizeof(phandle))) + return -EFAULT; - if (len != op.op_buflen) + if (nd == 0) { + if (cmd != OPIOCGETNEXT) return -EINVAL; + dp = of_find_node_by_path("/"); + } else { + dp = of_find_node_by_phandle(nd); + nd = 0; + if (dp) { + if (cmd == OPIOCGETNEXT) + dp = dp->sibling; + else + dp = dp->child; + } + } + if (dp) + nd = dp->node; + if (copy_to_user(argp, &nd, sizeof(phandle))) + return -EFAULT; - kfree(str); - kfree(tmp); + return 0; +} - return 0; +static int openprom_bsd_ioctl(struct inode * inode, struct file * file, + unsigned int cmd, unsigned long arg) +{ + DATA *data = (DATA *) file->private_data; + void __user *argp = (void __user *)arg; + int err; - case OPIOCGETOPTNODE: - if (copy_to_user(argp, &options_node, sizeof(int))) - return -EFAULT; - return 0; + switch (cmd) { + case OPIOCGET: + err = opiocget(argp, data); + break; - case OPIOCGETNEXT: - case OPIOCGETCHILD: - if (copy_from_user(&node, argp, sizeof(int))) - return -EFAULT; + case OPIOCNEXTPROP: + err = opiocnextprop(argp, data); + break; - if (cmd == OPIOCGETNEXT) - node = __prom_getsibling(node); - else - node = __prom_getchild(node); + case OPIOCSET: + err = opiocset(argp, data); + break; + + case OPIOCGETOPTNODE: + BUILD_BUG_ON(sizeof(phandle) != sizeof(int)); - if (__copy_to_user(argp, &node, sizeof(int))) + if (copy_to_user(argp, &options_node->node, sizeof(phandle))) return -EFAULT; return 0; + case OPIOCGETNEXT: + case OPIOCGETCHILD: + err = opiocgetnext(cmd, argp); + break; + default: - if (cnt++ < 10) - printk(KERN_INFO "openprom_bsd_ioctl: cmd 0x%X\n", cmd); return -EINVAL; - } + }; + + return err; } @@ -511,7 +590,6 @@ static int openprom_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg) { DATA *data = (DATA *) file->private_data; - static int cnt; switch (cmd) { case OPROMGETOPT: @@ -563,10 +641,8 @@ static int openprom_ioctl(struct inode * inode, struct file * file, return openprom_bsd_ioctl(inode,file,cmd,arg); default: - if (cnt++ < 10) - printk("openprom_ioctl: cmd 0x%X, arg 0x%lX\n", cmd, arg); return -EINVAL; - } + }; } static long openprom_compat_ioctl(struct file *file, unsigned int cmd, @@ -594,9 +670,7 @@ static long openprom_compat_ioctl(struct file *file, unsigned int cmd, case OPROMSETCUR: case OPROMPCI2NODE: case OPROMPATH2NODE: - lock_kernel(); rval = openprom_ioctl(file->f_dentry->d_inode, file, cmd, arg); - lock_kernel(); break; } @@ -607,13 +681,13 @@ static int openprom_open(struct inode * inode, struct file * file) { DATA *data; - data = (DATA *) kmalloc(sizeof(DATA), GFP_KERNEL); + data = kmalloc(sizeof(DATA), GFP_KERNEL); if (!data) return -ENOMEM; - data->current_node = prom_root_node; - data->lastnode = prom_root_node; - file->private_data = (void *)data; + data->current_node = of_find_node_by_path("/"); + data->lastnode = data->current_node; + file->private_data = (void *) data; return 0; } @@ -634,24 +708,30 @@ static struct file_operations openprom_fops = { }; static struct miscdevice openprom_dev = { - SUN_OPENPROM_MINOR, "openprom", &openprom_fops + .minor = SUN_OPENPROM_MINOR, + .name = "openprom", + .fops = &openprom_fops, }; static int __init openprom_init(void) { - int error; + struct device_node *dp; + int err; - error = misc_register(&openprom_dev); - if (error) { - printk(KERN_ERR "openprom: unable to get misc minor\n"); - return error; - } + err = misc_register(&openprom_dev); + if (err) + return err; - options_node = prom_getchild(prom_root_node); - options_node = prom_searchsiblings(options_node,"options"); + dp = of_find_node_by_path("/"); + dp = dp->child; + while (dp) { + if (!strcmp(dp->name, "options")) + break; + dp = dp->sibling; + } + options_node = dp; - if (options_node == 0 || options_node == -1) { - printk(KERN_ERR "openprom: unable to find options node\n"); + if (!options_node) { misc_deregister(&openprom_dev); return -EIO; } @@ -666,4 +746,3 @@ static void __exit openprom_cleanup(void) module_init(openprom_init); module_exit(openprom_cleanup); -MODULE_LICENSE("GPL"); diff --git a/drivers/sbus/char/riowatchdog.c b/drivers/sbus/char/riowatchdog.c index d1babff..2a9cc82 100644 --- a/drivers/sbus/char/riowatchdog.c +++ b/drivers/sbus/char/riowatchdog.c @@ -211,7 +211,7 @@ static int __init riowd_bbc_init(void) for_each_ebus(ebus) { for_each_ebusdev(edev, ebus) { - if (!strcmp(edev->prom_name, "bbc")) + if (!strcmp(edev->ofdev.node->name, "bbc")) goto found_bbc; } } @@ -238,7 +238,7 @@ static int __init riowd_init(void) for_each_ebus(ebus) { for_each_ebusdev(edev, ebus) { - if (!strcmp(edev->prom_name, RIOWD_NAME)) + if (!strcmp(edev->ofdev.node->name, RIOWD_NAME)) goto ebus_done; } } diff --git a/fs/openpromfs/inode.c b/fs/openpromfs/inode.c index efc7c911..93a56bd 100644 --- a/fs/openpromfs/inode.c +++ b/fs/openpromfs/inode.c @@ -1,5 +1,4 @@ -/* $Id: inode.c,v 1.15 2001/11/12 09:43:39 davem Exp $ - * openpromfs.c: /proc/openprom handling routines +/* inode.c: /proc/openprom handling routines * * Copyright (C) 1996-1999 Jakub Jelinek (jakub@redhat.com) * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) @@ -12,762 +11,245 @@ #include <linux/openprom_fs.h> #include <linux/init.h> #include <linux/slab.h> -#include <linux/smp_lock.h> +#include <linux/seq_file.h> #include <asm/openprom.h> #include <asm/oplib.h> +#include <asm/prom.h> #include <asm/uaccess.h> -#define ALIASES_NNODES 64 - -typedef struct { - u16 parent; - u16 next; - u16 child; - u16 first_prop; - u32 node; -} openpromfs_node; - -typedef struct { -#define OPP_STRING 0x10 -#define OPP_STRINGLIST 0x20 -#define OPP_BINARY 0x40 -#define OPP_HEXSTRING 0x80 -#define OPP_DIRTY 0x01 -#define OPP_QUOTED 0x02 -#define OPP_NOTQUOTED 0x04 -#define OPP_ASCIIZ 0x08 - u32 flag; - u32 alloclen; - u32 len; - char *value; - char name[8]; -} openprom_property; - -static openpromfs_node *nodes; -static int alloced; -static u16 last_node; -static u16 first_prop; -static u16 options = 0xffff; -static u16 aliases = 0xffff; -static int aliases_nodes; -static char *alias_names [ALIASES_NNODES]; - -#define OPENPROM_ROOT_INO 16 -#define OPENPROM_FIRST_INO OPENPROM_ROOT_INO -#define NODE(ino) nodes[ino - OPENPROM_FIRST_INO] -#define NODE2INO(node) (node + OPENPROM_FIRST_INO) -#define NODEP2INO(no) (no + OPENPROM_FIRST_INO + last_node) - -static int openpromfs_create (struct inode *, struct dentry *, int, struct nameidata *); -static int openpromfs_readdir(struct file *, void *, filldir_t); -static struct dentry *openpromfs_lookup(struct inode *, struct dentry *dentry, struct nameidata *nd); -static int openpromfs_unlink (struct inode *, struct dentry *dentry); +static DEFINE_MUTEX(op_mutex); -static inline u16 ptr_nod(void *p) -{ - return (long)p & 0xFFFF; -} +#define OPENPROM_ROOT_INO 0 -static ssize_t nodenum_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) +enum op_inode_type { + op_inode_node, + op_inode_prop, +}; + +union op_inode_data { + struct device_node *node; + struct property *prop; +}; + +struct op_inode_info { + struct inode vfs_inode; + enum op_inode_type type; + union op_inode_data u; +}; + +static inline struct op_inode_info *OP_I(struct inode *inode) { - struct inode *inode = file->f_dentry->d_inode; - char buffer[10]; - - if (count < 0 || !inode->u.generic_ip) - return -EINVAL; - sprintf (buffer, "%8.8lx\n", (long)inode->u.generic_ip); - if (file->f_pos >= 9) - return 0; - if (count > 9 - file->f_pos) - count = 9 - file->f_pos; - if (copy_to_user(buf, buffer + file->f_pos, count)) - return -EFAULT; - *ppos += count; - return count; + return container_of(inode, struct op_inode_info, vfs_inode); } -static ssize_t property_read(struct file *filp, char __user *buf, - size_t count, loff_t *ppos) +static int is_string(unsigned char *p, int len) { - struct inode *inode = filp->f_dentry->d_inode; - int i, j, k; - u32 node; - char *p, *s; - u32 *q; - openprom_property *op; - char buffer[64]; - - if (!filp->private_data) { - node = nodes[ptr_nod(inode->u.generic_ip)].node; - i = ((u32)(long)inode->u.generic_ip) >> 16; - if (ptr_nod(inode->u.generic_ip) == aliases) { - if (i >= aliases_nodes) - p = NULL; - else - p = alias_names [i]; - } else - for (p = prom_firstprop (node, buffer); - i && p && *p; - p = prom_nextprop (node, p, buffer), i--) - /* nothing */ ; - if (!p || !*p) - return -EIO; - i = prom_getproplen (node, p); - if (i < 0) { - if (ptr_nod(inode->u.generic_ip) == aliases) - i = 0; - else - return -EIO; - } - k = i; - if (i < 64) i = 64; - filp->private_data = kmalloc (sizeof (openprom_property) - + (j = strlen (p)) + 2 * i, - GFP_KERNEL); - if (!filp->private_data) - return -ENOMEM; - op = filp->private_data; - op->flag = 0; - op->alloclen = 2 * i; - strcpy (op->name, p); - op->value = (char *)(((unsigned long)(op->name + j + 4)) & ~3); - op->len = k; - if (k && prom_getproperty (node, p, op->value, i) < 0) - return -EIO; - op->value [k] = 0; - if (k) { - for (s = NULL, p = op->value; p < op->value + k; p++) { - if ((*p >= ' ' && *p <= '~') || *p == '\n') { - op->flag |= OPP_STRING; - s = p; - continue; - } - if (p > op->value && !*p && s == p - 1) { - if (p < op->value + k - 1) - op->flag |= OPP_STRINGLIST; - else - op->flag |= OPP_ASCIIZ; - continue; - } - if (k == 1 && !*p) { - op->flag |= (OPP_STRING|OPP_ASCIIZ); - break; - } - op->flag &= ~(OPP_STRING|OPP_STRINGLIST); - if (k & 3) - op->flag |= OPP_HEXSTRING; - else - op->flag |= OPP_BINARY; - break; - } - if (op->flag & OPP_STRINGLIST) - op->flag &= ~(OPP_STRING); - if (op->flag & OPP_ASCIIZ) - op->len--; - } - } else - op = filp->private_data; - if (!count || !(op->len || (op->flag & OPP_ASCIIZ))) - return 0; - if (*ppos >= 0xffffff || count >= 0xffffff) - return -EINVAL; - if (op->flag & OPP_STRINGLIST) { - for (k = 0, p = op->value; p < op->value + op->len; p++) - if (!*p) - k++; - i = op->len + 4 * k + 3; - } else if (op->flag & OPP_STRING) { - i = op->len + 3; - } else if (op->flag & OPP_BINARY) { - i = (op->len * 9) >> 2; - } else { - i = (op->len << 1) + 1; - } - k = *ppos; - if (k >= i) return 0; - if (count > i - k) count = i - k; - if (op->flag & OPP_STRING) { - if (!k) { - if (put_user('\'', buf)) - return -EFAULT; - k++; - count--; - } + int i; - if (k + count >= i - 2) - j = i - 2 - k; - else - j = count; - - if (j >= 0) { - if (copy_to_user(buf + k - *ppos, - op->value + k - 1, j)) - return -EFAULT; - count -= j; - k += j; - } + for (i = 0; i < len; i++) { + unsigned char val = p[i]; - if (count) { - if (put_user('\'', &buf [k++ - *ppos])) - return -EFAULT; - } - if (count > 1) { - if (put_user('\n', &buf [k++ - *ppos])) - return -EFAULT; - } - } else if (op->flag & OPP_STRINGLIST) { - char *tmp; - - tmp = kmalloc (i, GFP_KERNEL); - if (!tmp) - return -ENOMEM; - - s = tmp; - *s++ = '\''; - for (p = op->value; p < op->value + op->len; p++) { - if (!*p) { - strcpy(s, "' + '"); - s += 5; - continue; - } - *s++ = *p; - } - strcpy(s, "'\n"); - - if (copy_to_user(buf, tmp + k, count)) - return -EFAULT; - - kfree(tmp); - k += count; - - } else if (op->flag & OPP_BINARY) { - char buffer[10]; - u32 *first, *last; - int first_off, last_cnt; - - first = ((u32 *)op->value) + k / 9; - first_off = k % 9; - last = ((u32 *)op->value) + (k + count - 1) / 9; - last_cnt = (k + count) % 9; - if (!last_cnt) last_cnt = 9; - - if (first == last) { - sprintf (buffer, "%08x.", *first); - if (copy_to_user(buf, buffer + first_off, - last_cnt - first_off)) - return -EFAULT; - buf += last_cnt - first_off; - } else { - for (q = first; q <= last; q++) { - sprintf (buffer, "%08x.", *q); - if (q == first) { - if (copy_to_user(buf, buffer + first_off, - 9 - first_off)) - return -EFAULT; - buf += 9 - first_off; - } else if (q == last) { - if (copy_to_user(buf, buffer, last_cnt)) - return -EFAULT; - buf += last_cnt; - } else { - if (copy_to_user(buf, buffer, 9)) - return -EFAULT; - buf += 9; - } - } - } + if ((i && !val) || + (val >= ' ' && val <= '~')) + continue; - if (last == (u32 *)(op->value + op->len - 4) && last_cnt == 9) { - if (put_user('\n', (buf - 1))) - return -EFAULT; - } + return 0; + } - k += count; + return 1; +} - } else if (op->flag & OPP_HEXSTRING) { - char buffer[3]; +static int property_show(struct seq_file *f, void *v) +{ + struct property *prop = f->private; + void *pval; + int len; - if ((k < i - 1) && (k & 1)) { - sprintf (buffer, "%02x", - (unsigned char) *(op->value + (k >> 1)) & 0xff); - if (put_user(buffer[1], &buf[k++ - *ppos])) - return -EFAULT; - count--; - } + len = prop->length; + pval = prop->value; - for (; (count > 1) && (k < i - 1); k += 2) { - sprintf (buffer, "%02x", - (unsigned char) *(op->value + (k >> 1)) & 0xff); - if (copy_to_user(buf + k - *ppos, buffer, 2)) - return -EFAULT; - count -= 2; - } + if (is_string(pval, len)) { + while (len > 0) { + int n = strlen(pval); - if (count && (k < i - 1)) { - sprintf (buffer, "%02x", - (unsigned char) *(op->value + (k >> 1)) & 0xff); - if (put_user(buffer[0], &buf[k++ - *ppos])) - return -EFAULT; - count--; - } + seq_printf(f, "%s", (char *) pval); - if (count) { - if (put_user('\n', &buf [k++ - *ppos])) - return -EFAULT; - } - } - count = k - *ppos; - *ppos = k; - return count; -} + /* Skip over the NULL byte too. */ + pval += n + 1; + len -= n + 1; -static ssize_t property_write(struct file *filp, const char __user *buf, - size_t count, loff_t *ppos) -{ - int i, j, k; - char *p; - u32 *q; - void *b; - openprom_property *op; - - if (*ppos >= 0xffffff || count >= 0xffffff) - return -EINVAL; - if (!filp->private_data) { - i = property_read (filp, NULL, 0, NULL); - if (i) - return i; - } - k = *ppos; - op = filp->private_data; - if (!(op->flag & OPP_STRING)) { - u32 *first, *last; - int first_off, last_cnt; - u32 mask, mask2; - char tmp [9]; - int forcelen = 0; - - j = k % 9; - for (i = 0; i < count; i++, j++) { - if (j == 9) j = 0; - if (!j) { - char ctmp; - if (get_user(ctmp, &buf[i])) - return -EFAULT; - if (ctmp != '.') { - if (ctmp != '\n') { - if (op->flag & OPP_BINARY) - return -EINVAL; - else - goto write_try_string; - } else { - count = i + 1; - forcelen = 1; - break; - } - } - } else { - char ctmp; - if (get_user(ctmp, &buf[i])) - return -EFAULT; - if (ctmp < '0' || - (ctmp > '9' && ctmp < 'A') || - (ctmp > 'F' && ctmp < 'a') || - ctmp > 'f') { - if (op->flag & OPP_BINARY) - return -EINVAL; - else - goto write_try_string; - } - } - } - op->flag |= OPP_BINARY; - tmp [8] = 0; - i = ((count + k + 8) / 9) << 2; - if (op->alloclen <= i) { - b = kmalloc (sizeof (openprom_property) + 2 * i, - GFP_KERNEL); - if (!b) - return -ENOMEM; - memcpy (b, filp->private_data, - sizeof (openprom_property) - + strlen (op->name) + op->alloclen); - memset (b + sizeof (openprom_property) - + strlen (op->name) + op->alloclen, - 0, 2 * i - op->alloclen); - op = b; - op->alloclen = 2*i; - b = filp->private_data; - filp->private_data = op; - kfree (b); + if (len > 0) + seq_printf(f, " + "); } - first = ((u32 *)op->value) + (k / 9); - first_off = k % 9; - last = (u32 *)(op->value + i); - last_cnt = (k + count) % 9; - if (first + 1 == last) { - memset (tmp, '0', 8); - if (copy_from_user(tmp + first_off, buf, - (count + first_off > 8) ? - 8 - first_off : count)) - return -EFAULT; - mask = 0xffffffff; - mask2 = 0xffffffff; - for (j = 0; j < first_off; j++) - mask >>= 1; - for (j = 8 - count - first_off; j > 0; j--) - mask2 <<= 1; - mask &= mask2; - if (mask) { - *first &= ~mask; - *first |= simple_strtoul (tmp, NULL, 16); - op->flag |= OPP_DIRTY; + } else { + if (len & 3) { + while (len) { + len--; + if (len) + seq_printf(f, "%02x.", + *(unsigned char *) pval); + else + seq_printf(f, "%02x", + *(unsigned char *) pval); + pval++; } } else { - op->flag |= OPP_DIRTY; - for (q = first; q < last; q++) { - if (q == first) { - if (first_off < 8) { - memset (tmp, '0', 8); - if (copy_from_user(tmp + first_off, - buf, - 8 - first_off)) - return -EFAULT; - mask = 0xffffffff; - for (j = 0; j < first_off; j++) - mask >>= 1; - *q &= ~mask; - *q |= simple_strtoul (tmp,NULL,16); - } - buf += 9; - } else if ((q == last - 1) && last_cnt - && (last_cnt < 8)) { - memset (tmp, '0', 8); - if (copy_from_user(tmp, buf, last_cnt)) - return -EFAULT; - mask = 0xffffffff; - for (j = 0; j < 8 - last_cnt; j++) - mask <<= 1; - *q &= ~mask; - *q |= simple_strtoul (tmp, NULL, 16); - buf += last_cnt; - } else { - char tchars[2 * sizeof(long) + 1]; - - if (copy_from_user(tchars, buf, sizeof(tchars) - 1)) - return -EFAULT; - tchars[sizeof(tchars) - 1] = '\0'; - *q = simple_strtoul (tchars, NULL, 16); - buf += 9; - } - } - } - if (!forcelen) { - if (op->len < i) - op->len = i; - } else - op->len = i; - *ppos += count; - } -write_try_string: - if (!(op->flag & OPP_BINARY)) { - if (!(op->flag & (OPP_QUOTED | OPP_NOTQUOTED))) { - char ctmp; - - /* No way, if somebody starts writing from the middle, - * we don't know whether he uses quotes around or not - */ - if (k > 0) - return -EINVAL; - if (get_user(ctmp, buf)) - return -EFAULT; - if (ctmp == '\'') { - op->flag |= OPP_QUOTED; - buf++; - count--; - (*ppos)++; - if (!count) { - op->flag |= OPP_STRING; - return 1; - } - } else - op->flag |= OPP_NOTQUOTED; - } - op->flag |= OPP_STRING; - if (op->alloclen <= count + *ppos) { - b = kmalloc (sizeof (openprom_property) - + 2 * (count + *ppos), GFP_KERNEL); - if (!b) - return -ENOMEM; - memcpy (b, filp->private_data, - sizeof (openprom_property) - + strlen (op->name) + op->alloclen); - memset (b + sizeof (openprom_property) - + strlen (op->name) + op->alloclen, - 0, 2*(count - *ppos) - op->alloclen); - op = b; - op->alloclen = 2*(count + *ppos); - b = filp->private_data; - filp->private_data = op; - kfree (b); - } - p = op->value + *ppos - ((op->flag & OPP_QUOTED) ? 1 : 0); - if (copy_from_user(p, buf, count)) - return -EFAULT; - op->flag |= OPP_DIRTY; - for (i = 0; i < count; i++, p++) - if (*p == '\n') { - *p = 0; - break; + while (len >= 4) { + len -= 4; + + if (len) + seq_printf(f, "%08x.", + *(unsigned int *) pval); + else + seq_printf(f, "%08x", + *(unsigned int *) pval); + pval += 4; } - if (i < count) { - op->len = p - op->value; - *ppos += i + 1; - if ((p > op->value) && (op->flag & OPP_QUOTED) - && (*(p - 1) == '\'')) - op->len--; - } else { - if (p - op->value > op->len) - op->len = p - op->value; - *ppos += count; } } - return *ppos - k; + seq_printf(f, "\n"); + + return 0; } -int property_release (struct inode *inode, struct file *filp) +static void *property_start(struct seq_file *f, loff_t *pos) { - openprom_property *op = filp->private_data; - int error; - u32 node; - - if (!op) - return 0; - lock_kernel(); - node = nodes[ptr_nod(inode->u.generic_ip)].node; - if (ptr_nod(inode->u.generic_ip) == aliases) { - if ((op->flag & OPP_DIRTY) && (op->flag & OPP_STRING)) { - char *p = op->name; - int i = (op->value - op->name) - strlen (op->name) - 1; - op->value [op->len] = 0; - *(op->value - 1) = ' '; - if (i) { - for (p = op->value - i - 2; p >= op->name; p--) - p[i] = *p; - p = op->name + i; - } - memcpy (p - 8, "nvalias ", 8); - prom_feval (p - 8); - } - } else if (op->flag & OPP_DIRTY) { - if (op->flag & OPP_STRING) { - op->value [op->len] = 0; - error = prom_setprop (node, op->name, - op->value, op->len + 1); - if (error <= 0) - printk (KERN_WARNING "openpromfs: " - "Couldn't write property %s\n", - op->name); - } else if ((op->flag & OPP_BINARY) || !op->len) { - error = prom_setprop (node, op->name, - op->value, op->len); - if (error <= 0) - printk (KERN_WARNING "openpromfs: " - "Couldn't write property %s\n", - op->name); - } else { - printk (KERN_WARNING "openpromfs: " - "Unknown property type of %s\n", - op->name); - } + if (*pos == 0) + return pos; + return NULL; +} + +static void *property_next(struct seq_file *f, void *v, loff_t *pos) +{ + (*pos)++; + return NULL; +} + +static void property_stop(struct seq_file *f, void *v) +{ + /* Nothing to do */ +} + +static struct seq_operations property_op = { + .start = property_start, + .next = property_next, + .stop = property_stop, + .show = property_show +}; + +static int property_open(struct inode *inode, struct file *file) +{ + struct op_inode_info *oi = OP_I(inode); + int ret; + + BUG_ON(oi->type != op_inode_prop); + + ret = seq_open(file, &property_op); + if (!ret) { + struct seq_file *m = file->private_data; + m->private = oi->u.prop; } - unlock_kernel(); - kfree (filp->private_data); - return 0; + return ret; } static const struct file_operations openpromfs_prop_ops = { - .read = property_read, - .write = property_write, - .release = property_release, + .open = property_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, }; -static const struct file_operations openpromfs_nodenum_ops = { - .read = nodenum_read, -}; +static int openpromfs_readdir(struct file *, void *, filldir_t); static const struct file_operations openprom_operations = { .read = generic_read_dir, .readdir = openpromfs_readdir, }; -static struct inode_operations openprom_alias_inode_operations = { - .create = openpromfs_create, - .lookup = openpromfs_lookup, - .unlink = openpromfs_unlink, -}; +static struct dentry *openpromfs_lookup(struct inode *, struct dentry *, struct nameidata *); static struct inode_operations openprom_inode_operations = { .lookup = openpromfs_lookup, }; -static int lookup_children(u16 n, const char * name, int len) +static struct dentry *openpromfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { - int ret; - u16 node; - for (; n != 0xffff; n = nodes[n].next) { - node = nodes[n].child; - if (node != 0xffff) { - char buffer[128]; - int i; - char *p; - - while (node != 0xffff) { - if (prom_getname (nodes[node].node, - buffer, 128) >= 0) { - i = strlen (buffer); - if ((len == i) - && !strncmp (buffer, name, len)) - return NODE2INO(node); - p = strchr (buffer, '@'); - if (p && (len == p - buffer) - && !strncmp (buffer, name, len)) - return NODE2INO(node); - } - node = nodes[node].next; - } - } else - continue; - ret = lookup_children (nodes[n].child, name, len); - if (ret) return ret; - } - return 0; -} - -static struct dentry *openpromfs_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd) -{ - int ino = 0; -#define OPFSL_DIR 0 -#define OPFSL_PROPERTY 1 -#define OPFSL_NODENUM 2 - int type = 0; - char buffer[128]; - char *p; + struct op_inode_info *ent_oi, *oi = OP_I(dir); + struct device_node *dp, *child; + struct property *prop; + enum op_inode_type ent_type; + union op_inode_data ent_data; const char *name; - u32 n; - u16 dirnode; - unsigned int len; - int i; struct inode *inode; - char buffer2[64]; + unsigned int ino; + int len; - inode = NULL; + BUG_ON(oi->type != op_inode_node); + + dp = oi->u.node; + name = dentry->d_name.name; len = dentry->d_name.len; - lock_kernel(); - if (name [0] == '.' && len == 5 && !strncmp (name + 1, "node", 4)) { - ino = NODEP2INO(NODE(dir->i_ino).first_prop); - type = OPFSL_NODENUM; - } - if (!ino) { - u16 node = NODE(dir->i_ino).child; - while (node != 0xffff) { - if (prom_getname (nodes[node].node, buffer, 128) >= 0) { - i = strlen (buffer); - if (len == i && !strncmp (buffer, name, len)) { - ino = NODE2INO(node); - type = OPFSL_DIR; - break; - } - p = strchr (buffer, '@'); - if (p && (len == p - buffer) - && !strncmp (buffer, name, len)) { - ino = NODE2INO(node); - type = OPFSL_DIR; - break; - } - } - node = nodes[node].next; - } - } - n = NODE(dir->i_ino).node; - dirnode = dir->i_ino - OPENPROM_FIRST_INO; - if (!ino) { - int j = NODEP2INO(NODE(dir->i_ino).first_prop); - if (dirnode != aliases) { - for (p = prom_firstprop (n, buffer2); - p && *p; - p = prom_nextprop (n, p, buffer2)) { - j++; - if ((len == strlen (p)) - && !strncmp (p, name, len)) { - ino = j; - type = OPFSL_PROPERTY; - break; - } - } - } else { - int k; - for (k = 0; k < aliases_nodes; k++) { - j++; - if (alias_names [k] - && (len == strlen (alias_names [k])) - && !strncmp (alias_names [k], name, len)) { - ino = j; - type = OPFSL_PROPERTY; - break; - } - } + + mutex_lock(&op_mutex); + + child = dp->child; + while (child) { + int n = strlen(child->path_component_name); + + if (len == n && + !strncmp(child->path_component_name, name, len)) { + ent_type = op_inode_node; + ent_data.node = child; + ino = child->unique_id; + goto found; } + child = child->sibling; } - if (!ino) { - ino = lookup_children (NODE(dir->i_ino).child, name, len); - if (ino) - type = OPFSL_DIR; - else { - unlock_kernel(); - return ERR_PTR(-ENOENT); + + prop = dp->properties; + while (prop) { + int n = strlen(prop->name); + + if (len == n && !strncmp(prop->name, name, len)) { + ent_type = op_inode_prop; + ent_data.prop = prop; + ino = prop->unique_id; + goto found; } + + prop = prop->next; } - inode = iget (dir->i_sb, ino); - unlock_kernel(); + + mutex_unlock(&op_mutex); + return ERR_PTR(-ENOENT); + +found: + inode = iget(dir->i_sb, ino); + mutex_unlock(&op_mutex); if (!inode) return ERR_PTR(-EINVAL); - switch (type) { - case OPFSL_DIR: + ent_oi = OP_I(inode); + ent_oi->type = ent_type; + ent_oi->u = ent_data; + + switch (ent_type) { + case op_inode_node: inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; - if (ino == OPENPROM_FIRST_INO + aliases) { - inode->i_mode |= S_IWUSR; - inode->i_op = &openprom_alias_inode_operations; - } else - inode->i_op = &openprom_inode_operations; + inode->i_op = &openprom_inode_operations; inode->i_fop = &openprom_operations; inode->i_nlink = 2; break; - case OPFSL_NODENUM: - inode->i_mode = S_IFREG | S_IRUGO; - inode->i_fop = &openpromfs_nodenum_ops; - inode->i_nlink = 1; - inode->u.generic_ip = (void *)(long)(n); - break; - case OPFSL_PROPERTY: - if ((dirnode == options) && (len == 17) - && !strncmp (name, "security-password", 17)) + case op_inode_prop: + if (!strcmp(dp->name, "options") && (len == 17) && + !strncmp (name, "security-password", 17)) inode->i_mode = S_IFREG | S_IRUSR | S_IWUSR; - else { + else inode->i_mode = S_IFREG | S_IRUGO; - if (dirnode == options || dirnode == aliases) { - if (len != 4 || strncmp (name, "name", 4)) - inode->i_mode |= S_IWUSR; - } - } inode->i_fop = &openpromfs_prop_ops; inode->i_nlink = 1; - if (inode->i_size < 0) - inode->i_size = 0; - inode->u.generic_ip = (void *)(long)(((u16)dirnode) | - (((u16)(ino - NODEP2INO(NODE(dir->i_ino).first_prop) - 1)) << 16)); + inode->i_size = ent_oi->u.prop->length; break; } @@ -781,237 +263,89 @@ static struct dentry *openpromfs_lookup(struct inode * dir, struct dentry *dentr static int openpromfs_readdir(struct file * filp, void * dirent, filldir_t filldir) { struct inode *inode = filp->f_dentry->d_inode; + struct op_inode_info *oi = OP_I(inode); + struct device_node *dp = oi->u.node; + struct device_node *child; + struct property *prop; unsigned int ino; - u32 n; - int i, j; - char buffer[128]; - u16 node; - char *p; - char buffer2[64]; - - lock_kernel(); + int i; + + mutex_lock(&op_mutex); ino = inode->i_ino; i = filp->f_pos; switch (i) { case 0: - if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0) goto out; + if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0) + goto out; i++; filp->f_pos++; /* fall thru */ case 1: - if (filldir(dirent, "..", 2, i, - (NODE(ino).parent == 0xffff) ? - OPENPROM_ROOT_INO : NODE2INO(NODE(ino).parent), DT_DIR) < 0) + if (filldir(dirent, "..", 2, i, + (dp->parent == NULL ? + OPENPROM_ROOT_INO : + dp->parent->unique_id), DT_DIR) < 0) goto out; i++; filp->f_pos++; /* fall thru */ default: i -= 2; - node = NODE(ino).child; - while (i && node != 0xffff) { - node = nodes[node].next; + + /* First, the children nodes as directories. */ + child = dp->child; + while (i && child) { + child = child->sibling; i--; } - while (node != 0xffff) { - if (prom_getname (nodes[node].node, buffer, 128) < 0) - goto out; - if (filldir(dirent, buffer, strlen(buffer), - filp->f_pos, NODE2INO(node), DT_DIR) < 0) + while (child) { + if (filldir(dirent, + child->path_component_name, + strlen(child->path_component_name), + filp->f_pos, child->unique_id, DT_DIR) < 0) goto out; + filp->f_pos++; - node = nodes[node].next; + child = child->sibling; } - j = NODEP2INO(NODE(ino).first_prop); - if (!i) { - if (filldir(dirent, ".node", 5, filp->f_pos, j, DT_REG) < 0) + + /* Next, the properties as files. */ + prop = dp->properties; + while (i && prop) { + prop = prop->next; + i--; + } + while (prop) { + if (filldir(dirent, prop->name, strlen(prop->name), + filp->f_pos, prop->unique_id, DT_REG) < 0) goto out; + filp->f_pos++; - } else - i--; - n = NODE(ino).node; - if (ino == OPENPROM_FIRST_INO + aliases) { - for (j++; i < aliases_nodes; i++, j++) { - if (alias_names [i]) { - if (filldir (dirent, alias_names [i], - strlen (alias_names [i]), - filp->f_pos, j, DT_REG) < 0) goto out; - filp->f_pos++; - } - } - } else { - for (p = prom_firstprop (n, buffer2); - p && *p; - p = prom_nextprop (n, p, buffer2)) { - j++; - if (i) i--; - else { - if (filldir(dirent, p, strlen(p), - filp->f_pos, j, DT_REG) < 0) - goto out; - filp->f_pos++; - } - } + prop = prop->next; } } out: - unlock_kernel(); - return 0; -} - -static int openpromfs_create (struct inode *dir, struct dentry *dentry, int mode, - struct nameidata *nd) -{ - char *p; - struct inode *inode; - - if (!dir) - return -ENOENT; - if (dentry->d_name.len > 256) - return -EINVAL; - p = kmalloc (dentry->d_name.len + 1, GFP_KERNEL); - if (!p) - return -ENOMEM; - strncpy (p, dentry->d_name.name, dentry->d_name.len); - p [dentry->d_name.len] = 0; - lock_kernel(); - if (aliases_nodes == ALIASES_NNODES) { - kfree(p); - unlock_kernel(); - return -EIO; - } - alias_names [aliases_nodes++] = p; - inode = iget (dir->i_sb, - NODEP2INO(NODE(dir->i_ino).first_prop) + aliases_nodes); - if (!inode) { - unlock_kernel(); - return -EINVAL; - } - inode->i_mode = S_IFREG | S_IRUGO | S_IWUSR; - inode->i_fop = &openpromfs_prop_ops; - inode->i_nlink = 1; - if (inode->i_size < 0) inode->i_size = 0; - inode->u.generic_ip = (void *)(long)(((u16)aliases) | - (((u16)(aliases_nodes - 1)) << 16)); - unlock_kernel(); - d_instantiate(dentry, inode); + mutex_unlock(&op_mutex); return 0; } -static int openpromfs_unlink (struct inode *dir, struct dentry *dentry) -{ - unsigned int len; - char *p; - const char *name; - int i; - - name = dentry->d_name.name; - len = dentry->d_name.len; - lock_kernel(); - for (i = 0; i < aliases_nodes; i++) - if ((strlen (alias_names [i]) == len) - && !strncmp (name, alias_names[i], len)) { - char buffer[512]; - - p = alias_names [i]; - alias_names [i] = NULL; - kfree (p); - strcpy (buffer, "nvunalias "); - memcpy (buffer + 10, name, len); - buffer [10 + len] = 0; - prom_feval (buffer); - } - unlock_kernel(); - return 0; -} +static kmem_cache_t *op_inode_cachep; -/* {{{ init section */ -static int __init check_space (u16 n) +static struct inode *openprom_alloc_inode(struct super_block *sb) { - unsigned long pages; + struct op_inode_info *oi; - if ((1 << alloced) * PAGE_SIZE < (n + 2) * sizeof(openpromfs_node)) { - pages = __get_free_pages (GFP_KERNEL, alloced + 1); - if (!pages) - return -1; + oi = kmem_cache_alloc(op_inode_cachep, SLAB_KERNEL); + if (!oi) + return NULL; - if (nodes) { - memcpy ((char *)pages, nodes, - (1 << alloced) * PAGE_SIZE); - free_pages ((unsigned long)nodes, alloced); - } - alloced++; - nodes = (openpromfs_node *)pages; - } - return 0; + return &oi->vfs_inode; } -static u16 __init get_nodes (u16 parent, u32 node) +static void openprom_destroy_inode(struct inode *inode) { - char *p; - u16 n = last_node++, i; - char buffer[64]; - - if (check_space (n) < 0) - return 0xffff; - nodes[n].parent = parent; - nodes[n].node = node; - nodes[n].next = 0xffff; - nodes[n].child = 0xffff; - nodes[n].first_prop = first_prop++; - if (!parent) { - char buffer[8]; - int j; - - if ((j = prom_getproperty (node, "name", buffer, 8)) >= 0) { - buffer[j] = 0; - if (!strcmp (buffer, "options")) - options = n; - else if (!strcmp (buffer, "aliases")) - aliases = n; - } - } - if (n != aliases) - for (p = prom_firstprop (node, buffer); - p && p != (char *)-1 && *p; - p = prom_nextprop (node, p, buffer)) - first_prop++; - else { - char *q; - for (p = prom_firstprop (node, buffer); - p && p != (char *)-1 && *p; - p = prom_nextprop (node, p, buffer)) { - if (aliases_nodes == ALIASES_NNODES) - break; - for (i = 0; i < aliases_nodes; i++) - if (!strcmp (p, alias_names [i])) - break; - if (i < aliases_nodes) - continue; - q = kmalloc (strlen (p) + 1, GFP_KERNEL); - if (!q) - return 0xffff; - strcpy (q, p); - alias_names [aliases_nodes++] = q; - } - first_prop += ALIASES_NNODES; - } - node = prom_getchild (node); - if (node) { - parent = get_nodes (n, node); - if (parent == 0xffff) - return 0xffff; - nodes[n].child = parent; - while ((node = prom_getsibling (node)) != 0) { - i = get_nodes (n, node); - if (i == 0xffff) - return 0xffff; - nodes[parent].next = i; - parent = i; - } - } - return n; + kmem_cache_free(op_inode_cachep, OP_I(inode)); } static void openprom_read_inode(struct inode * inode) @@ -1031,6 +365,8 @@ static int openprom_remount(struct super_block *sb, int *flags, char *data) } static struct super_operations openprom_sops = { + .alloc_inode = openprom_alloc_inode, + .destroy_inode = openprom_destroy_inode, .read_inode = openprom_read_inode, .statfs = simple_statfs, .remount_fs = openprom_remount, @@ -1038,7 +374,8 @@ static struct super_operations openprom_sops = { static int openprom_fill_super(struct super_block *s, void *data, int silent) { - struct inode * root_inode; + struct inode *root_inode; + struct op_inode_info *oi; s->s_flags |= MS_NOATIME; s->s_blocksize = 1024; @@ -1049,6 +386,11 @@ static int openprom_fill_super(struct super_block *s, void *data, int silent) root_inode = iget(s, OPENPROM_ROOT_INO); if (!root_inode) goto out_no_root; + + oi = OP_I(root_inode); + oi->type = op_inode_node; + oi->u.node = of_find_node_by_path("/"); + s->s_root = d_alloc_root(root_inode); if (!s->s_root) goto out_no_root; @@ -1073,29 +415,39 @@ static struct file_system_type openprom_fs_type = { .kill_sb = kill_anon_super, }; +static void op_inode_init_once(void *data, kmem_cache_t * cachep, unsigned long flags) +{ + struct op_inode_info *oi = (struct op_inode_info *) data; + + if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == + SLAB_CTOR_CONSTRUCTOR) + inode_init_once(&oi->vfs_inode); +} + static int __init init_openprom_fs(void) { - nodes = (openpromfs_node *)__get_free_pages(GFP_KERNEL, 0); - if (!nodes) { - printk (KERN_WARNING "openpromfs: can't get free page\n"); - return -EIO; - } - if (get_nodes (0xffff, prom_root_node) == 0xffff) { - printk (KERN_WARNING "openpromfs: couldn't setup tree\n"); - return -EIO; - } - nodes[last_node].first_prop = first_prop; - return register_filesystem(&openprom_fs_type); + int err; + + op_inode_cachep = kmem_cache_create("op_inode_cache", + sizeof(struct op_inode_info), + 0, + (SLAB_RECLAIM_ACCOUNT | + SLAB_MEM_SPREAD), + op_inode_init_once, NULL); + if (!op_inode_cachep) + return -ENOMEM; + + err = register_filesystem(&openprom_fs_type); + if (err) + kmem_cache_destroy(op_inode_cachep); + + return err; } static void __exit exit_openprom_fs(void) { - int i; unregister_filesystem(&openprom_fs_type); - free_pages ((unsigned long)nodes, alloced); - for (i = 0; i < aliases_nodes; i++) - kfree (alias_names [i]); - nodes = NULL; + kmem_cache_destroy(op_inode_cachep); } module_init(init_openprom_fs) diff --git a/include/asm-sparc/io.h b/include/asm-sparc/io.h index a42df20..cab0b85 100644 --- a/include/asm-sparc/io.h +++ b/include/asm-sparc/io.h @@ -249,6 +249,22 @@ extern void __iomem *ioremap(unsigned long offset, unsigned long size); #define ioremap_nocache(X,Y) ioremap((X),(Y)) extern void iounmap(volatile void __iomem *addr); +#define ioread8(X) readb(X) +#define ioread16(X) readw(X) +#define ioread32(X) readl(X) +#define iowrite8(val,X) writeb(val,X) +#define iowrite16(val,X) writew(val,X) +#define iowrite32(val,X) writel(val,X) + +/* Create a virtual mapping cookie for an IO port range */ +extern void __iomem *ioport_map(unsigned long port, unsigned int nr); +extern void ioport_unmap(void __iomem *); + +/* Create a virtual mapping cookie for a PCI BAR (memory or IO) */ +struct pci_dev; +extern void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max); +extern void pci_iounmap(struct pci_dev *dev, void __iomem *); + /* * Bus number may be in res->flags... somewhere. */ diff --git a/include/asm-sparc/prom.h b/include/asm-sparc/prom.h index c5e3d26..f9cf44c 100644 --- a/include/asm-sparc/prom.h +++ b/include/asm-sparc/prom.h @@ -35,6 +35,8 @@ struct property { int length; void *value; struct property *next; + unsigned long _flags; + unsigned int unique_id; }; struct device_node { @@ -58,8 +60,15 @@ struct device_node { struct kref kref; unsigned long _flags; void *data; + unsigned int unique_id; }; +/* flag descriptions */ +#define OF_DYNAMIC 1 /* node and properties were allocated via kmalloc */ + +#define OF_IS_DYNAMIC(x) test_bit(OF_DYNAMIC, &x->_flags) +#define OF_MARK_DYNAMIC(x) set_bit(OF_DYNAMIC, &x->_flags) + static inline void set_node_proc_entry(struct device_node *dn, struct proc_dir_entry *de) { dn->pde = de; @@ -88,6 +97,7 @@ extern struct property *of_find_property(struct device_node *np, extern int of_device_is_compatible(struct device_node *device, const char *); extern void *of_get_property(struct device_node *node, const char *name, int *lenp); +extern int of_set_property(struct device_node *node, const char *name, void *val, int len); extern int of_getintprop_default(struct device_node *np, const char *name, int def); diff --git a/include/asm-sparc64/dma-mapping.h b/include/asm-sparc64/dma-mapping.h index 3c2b5bc..0f5b89c 100644 --- a/include/asm-sparc64/dma-mapping.h +++ b/include/asm-sparc64/dma-mapping.h @@ -162,4 +162,47 @@ static inline void dma_free_coherent(struct device *dev, size_t size, #endif /* PCI */ + +/* Now for the API extensions over the pci_ one */ + +#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) +#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) +#define dma_is_consistent(d) (1) + +static inline int +dma_get_cache_alignment(void) +{ + /* no easy way to get cache size on all processors, so return + * the maximum possible, to be safe */ + return (1 << INTERNODE_CACHE_SHIFT); +} + +static inline void +dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle, + unsigned long offset, size_t size, + enum dma_data_direction direction) +{ + /* just sync everything, that's all the pci API can do */ + dma_sync_single_for_cpu(dev, dma_handle, offset+size, direction); +} + +static inline void +dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle, + unsigned long offset, size_t size, + enum dma_data_direction direction) +{ + /* just sync everything, that's all the pci API can do */ + dma_sync_single_for_device(dev, dma_handle, offset+size, direction); +} + +static inline void +dma_cache_sync(void *vaddr, size_t size, + enum dma_data_direction direction) +{ + /* could define this in terms of the dma_cache ... operations, + * but if you get this on a platform, you should convert the platform + * to using the generic device DMA API */ + BUG(); +} + #endif /* _ASM_SPARC64_DMA_MAPPING_H */ diff --git a/include/asm-sparc64/floppy.h b/include/asm-sparc64/floppy.h index f8d57bb..b591d0e 100644 --- a/include/asm-sparc64/floppy.h +++ b/include/asm-sparc64/floppy.h @@ -208,7 +208,55 @@ static void sun_fd_enable_dma(void) pdma_areasize = pdma_size; } -extern irqreturn_t sparc_floppy_irq(int, void *, struct pt_regs *); +irqreturn_t sparc_floppy_irq(int irq, void *dev_cookie, struct pt_regs *regs) +{ + if (likely(doing_pdma)) { + void __iomem *stat = (void __iomem *) fdc_status; + unsigned char *vaddr = pdma_vaddr; + unsigned long size = pdma_size; + u8 val; + + while (size) { + val = readb(stat); + if (unlikely(!(val & 0x80))) { + pdma_vaddr = vaddr; + pdma_size = size; + return IRQ_HANDLED; + } + if (unlikely(!(val & 0x20))) { + pdma_vaddr = vaddr; + pdma_size = size; + doing_pdma = 0; + goto main_interrupt; + } + if (val & 0x40) { + /* read */ + *vaddr++ = readb(stat + 1); + } else { + unsigned char data = *vaddr++; + + /* write */ + writeb(data, stat + 1); + } + size--; + } + + pdma_vaddr = vaddr; + pdma_size = size; + + /* Send Terminal Count pulse to floppy controller. */ + val = readb(auxio_register); + val |= AUXIO_AUX1_FTCNT; + writeb(val, auxio_register); + val &= ~AUXIO_AUX1_FTCNT; + writeb(val, auxio_register); + + doing_pdma = 0; + } + +main_interrupt: + return floppy_interrupt(irq, dev_cookie, regs); +} static int sun_fd_request_irq(void) { diff --git a/include/asm-sparc64/prom.h b/include/asm-sparc64/prom.h index 6d1556c..265614d 100644 --- a/include/asm-sparc64/prom.h +++ b/include/asm-sparc64/prom.h @@ -35,6 +35,8 @@ struct property { int length; void *value; struct property *next; + unsigned long _flags; + unsigned int unique_id; }; struct device_node { @@ -58,8 +60,15 @@ struct device_node { struct kref kref; unsigned long _flags; void *data; + unsigned int unique_id; }; +/* flag descriptions */ +#define OF_DYNAMIC 1 /* node and properties were allocated via kmalloc */ + +#define OF_IS_DYNAMIC(x) test_bit(OF_DYNAMIC, &x->_flags) +#define OF_MARK_DYNAMIC(x) set_bit(OF_DYNAMIC, &x->_flags) + static inline void set_node_proc_entry(struct device_node *dn, struct proc_dir_entry *de) { dn->pde = de; @@ -88,6 +97,7 @@ extern struct property *of_find_property(struct device_node *np, extern int of_device_is_compatible(struct device_node *device, const char *); extern void *of_get_property(struct device_node *node, const char *name, int *lenp); +extern int of_set_property(struct device_node *node, const char *name, void *val, int len); extern int of_getintprop_default(struct device_node *np, const char *name, int def); |