linux-old/drivers/mtd/maps/sun_uflash.c
<<
>>
Prefs
   1/* $Id: sun_uflash.c,v 1.4 2001/10/02 15:05:14 dwmw2 Exp $
   2 *
   3 * sun_uflash - Driver implementation for user-programmable flash
   4 * present on many Sun Microsystems SME boardsets.
   5 *
   6 * This driver does NOT provide access to the OBP-flash for
   7 * safety reasons-- use <linux>/drivers/sbus/char/flash.c instead.
   8 *
   9 * Copyright (c) 2001 Eric Brower (ebrower@usa.net)
  10 *
  11 */
  12
  13#include <linux/kernel.h>
  14#include <linux/module.h>
  15#include <linux/version.h>
  16#include <linux/fs.h>
  17#include <linux/errno.h>
  18#include <linux/init.h>
  19#include <linux/ioport.h>
  20#include <asm/ebus.h>
  21#include <asm/oplib.h>
  22#include <asm/uaccess.h>
  23#include <asm/io.h>
  24
  25#include <linux/mtd/mtd.h>
  26#include <linux/mtd/map.h>
  27
  28#define UFLASH_OBPNAME  "flashprom"
  29#define UFLASH_DEVNAME  "userflash"
  30
  31#define UFLASH_WINDOW_SIZE      0x200000
  32#define UFLASH_BUSWIDTH         1                       /* EBus is 8-bit */
  33
  34MODULE_AUTHOR
  35        ("Eric Brower <ebrower@usa.net>");
  36MODULE_DESCRIPTION
  37        ("User-programmable flash device on Sun Microsystems boardsets");
  38MODULE_SUPPORTED_DEVICE
  39        ("userflash");
  40MODULE_LICENSE
  41        ("GPL");
  42
  43static LIST_HEAD(device_list);
  44struct uflash_dev {
  45        char *                  name;   /* device name */
  46        struct map_info         map;    /* mtd map info */
  47        struct mtd_info *       mtd;    /* mtd info */
  48        struct list_head        list;
  49};
  50
  51__u8 uflash_read8(struct map_info *map, unsigned long ofs)
  52{
  53        return(__raw_readb(map->map_priv_1 + ofs));
  54}
  55
  56__u16 uflash_read16(struct map_info *map, unsigned long ofs)
  57{
  58        return(__raw_readw(map->map_priv_1 + ofs));
  59}
  60
  61__u32 uflash_read32(struct map_info *map, unsigned long ofs)
  62{
  63        return(__raw_readl(map->map_priv_1 + ofs));
  64}
  65
  66void uflash_copy_from(struct map_info *map, void *to, unsigned long from, 
  67                      ssize_t len)
  68{
  69        memcpy_fromio(to, map->map_priv_1 + from, len);
  70}
  71
  72void uflash_write8(struct map_info *map, __u8 d, unsigned long adr)
  73{
  74        __raw_writeb(d, map->map_priv_1 + adr);
  75}
  76
  77void uflash_write16(struct map_info *map, __u16 d, unsigned long adr)
  78{
  79        __raw_writew(d, map->map_priv_1 + adr);
  80}
  81
  82void uflash_write32(struct map_info *map, __u32 d, unsigned long adr)
  83{
  84        __raw_writel(d, map->map_priv_1 + adr);
  85}
  86
  87void uflash_copy_to(struct map_info *map, unsigned long to, const void *from,
  88                    ssize_t len)
  89{
  90        memcpy_toio(map->map_priv_1 + to, from, len);
  91}
  92
  93struct map_info uflash_map_templ = {
  94                name:           "SUNW,???-????",
  95                size:           UFLASH_WINDOW_SIZE,
  96                buswidth:       UFLASH_BUSWIDTH,
  97                read8:          uflash_read8,
  98                read16:         uflash_read16,
  99                read32:         uflash_read32,
 100                copy_from:      uflash_copy_from,
 101                write8:         uflash_write8,
 102                write16:        uflash_write16,
 103                write32:        uflash_write32,
 104                copy_to:        uflash_copy_to
 105};
 106
 107int uflash_devinit(struct linux_ebus_device* edev)
 108{
 109        int iTmp, nregs;
 110        struct linux_prom_registers regs[2];
 111        struct uflash_dev *pdev;
 112
 113        iTmp = prom_getproperty(
 114                edev->prom_node, "reg", (void *)regs, sizeof(regs));
 115        if ((iTmp % sizeof(regs[0])) != 0) {
 116                printk("%s: Strange reg property size %d\n", 
 117                        UFLASH_DEVNAME, iTmp);
 118                return -ENODEV;
 119        }
 120
 121        nregs = iTmp / sizeof(regs[0]);
 122
 123        if (nregs != 1) {
 124                /* Non-CFI userflash device-- once I find one we
 125                 * can work on supporting it.
 126                 */
 127                printk("%s: unsupported device at 0x%lx (%d regs): " \
 128                        "email ebrower@usa.net\n", 
 129                        UFLASH_DEVNAME, edev->resource[0].start, nregs);
 130                return -ENODEV;
 131        }
 132
 133        if(0 == (pdev = kmalloc(sizeof(struct uflash_dev), GFP_KERNEL))) {
 134                printk("%s: unable to kmalloc new device\n", UFLASH_DEVNAME);
 135                return(-ENOMEM);
 136        }
 137        
 138        /* copy defaults and tweak parameters */
 139        memcpy(&pdev->map, &uflash_map_templ, sizeof(uflash_map_templ));
 140        pdev->map.size = regs[0].reg_size;
 141
 142        iTmp = prom_getproplen(edev->prom_node, "model");
 143        pdev->name = kmalloc(iTmp, GFP_KERNEL);
 144        prom_getstring(edev->prom_node, "model", pdev->name, iTmp);
 145        if(0 != pdev->name && 0 < strlen(pdev->name)) {
 146                pdev->map.name = pdev->name;
 147        }
 148
 149        pdev->map.map_priv_1 = 
 150                (unsigned long)ioremap_nocache(edev->resource[0].start, pdev->map.size);
 151        if(0 == pdev->map.map_priv_1) {
 152                printk("%s: failed to map device\n", __FUNCTION__);
 153                kfree(pdev->name);
 154                kfree(pdev);
 155                return(-1);
 156        }
 157
 158        /* MTD registration */
 159        pdev->mtd = do_map_probe("cfi_probe", &pdev->map);
 160        if(0 == pdev->mtd) {
 161                iounmap((void *)pdev->map.map_priv_1);
 162                kfree(pdev->name);
 163                kfree(pdev);
 164                return(-ENXIO);
 165        }
 166
 167        list_add(&pdev->list, &device_list);
 168
 169        pdev->mtd->module = THIS_MODULE;
 170
 171        add_mtd_device(pdev->mtd);
 172        return(0);
 173}
 174
 175static int __init uflash_init(void)
 176{
 177        struct linux_ebus *ebus = NULL;
 178        struct linux_ebus_device *edev = NULL;
 179
 180        for_each_ebus(ebus) {
 181                for_each_ebusdev(edev, ebus) {
 182                        if (!strcmp(edev->prom_name, UFLASH_OBPNAME)) {
 183                                if(0 > prom_getproplen(edev->prom_node, "user")) {
 184                                        DEBUG(2, "%s: ignoring device at 0x%lx\n",
 185                                                        UFLASH_DEVNAME, edev->resource[0].start);
 186                                } else {
 187                                        uflash_devinit(edev);
 188                                }
 189                        }
 190                }
 191        }
 192
 193        if(list_empty(&device_list)) {
 194                printk("%s: unable to locate device\n", UFLASH_DEVNAME);
 195                return -ENODEV;
 196        }
 197        return(0);
 198}
 199
 200static void __exit uflash_cleanup(void)
 201{
 202        struct list_head *udevlist;
 203        struct uflash_dev *udev;
 204
 205        list_for_each(udevlist, &device_list) {
 206                udev = list_entry(udevlist, struct uflash_dev, list);
 207                DEBUG(2, "%s: removing device %s\n", 
 208                        UFLASH_DEVNAME, udev->name);
 209
 210                if(0 != udev->mtd) {
 211                        del_mtd_device(udev->mtd);
 212                        map_destroy(udev->mtd);
 213                }
 214                if(0 != udev->map.map_priv_1) {
 215                        iounmap((void*)udev->map.map_priv_1);
 216                        udev->map.map_priv_1 = 0;
 217                }
 218                if(0 != udev->name) {
 219                        kfree(udev->name);
 220                }
 221                kfree(udev);
 222        }       
 223}
 224
 225module_init(uflash_init);
 226module_exit(uflash_cleanup);
 227
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.