1 /* $NetBSD: eeprom.c,v 1.4 1994/12/12 18:59:04 gwr Exp $ */ 2 3 /* 4 * Copyright (c) 1994 Gordon W. Ross 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 /* 31 * Access functions for the EEPROM (Electrically Eraseable PROM) 32 * The main reason for the existence of this module is to 33 * handle the painful task of updating the EEPROM contents. 34 * After a write, it must not be touched for 10 milliseconds. 35 * (See the Sun-3 Architecture Manual sec. 5.9) 36 */ 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/device.h> 41 #include <sys/conf.h> 42 #include <sys/buf.h> 43 #include <sys/malloc.h> 44 45 #include <machine/autoconf.h> 46 #include <machine/obio.h> 47 #include <machine/eeprom.h> 48 49 #define HZ 100 50 51 static int ee_update(caddr_t buf, int off, int cnt); 52 53 static char *eeprom_va; 54 static int ee_busy, ee_want; 55 56 int eeprom_match __P((struct device *, void *vcf, void *args)); 57 void eeprom_attach __P((struct device *, struct device *, void *)); 58 59 struct cfdriver eepromcd = { 60 NULL, "eeprom", eeprom_match, eeprom_attach, 61 DV_DULL, sizeof(struct device), 0 }; 62 63 /* Called very earyl by internal_configure. */ 64 void eeprom_init() 65 { 66 eeprom_va = obio_find_mapping(OBIO_EEPROM, OBIO_EEPROM_SIZE); 67 } 68 69 int eeprom_match(parent, vcf, args) 70 struct device *parent; 71 void *vcf, *args; 72 { 73 struct cfdata *cf = vcf; 74 struct confargs *ca = args; 75 76 /* This driver only supports one unit. */ 77 if (cf->cf_unit != 0) 78 return (0); 79 if (eeprom_va == NULL) 80 return (0); 81 if (ca->ca_paddr == -1) 82 ca->ca_paddr = OBIO_EEPROM; 83 return (1); 84 } 85 86 void eeprom_attach(parent, self, args) 87 struct device *parent; 88 struct device *self; 89 void *args; 90 { 91 struct confargs *ca = args; 92 93 printf("\n"); 94 } 95 96 97 static int ee_take() /* Take the lock. */ 98 { 99 int error = 0; 100 while (ee_busy) { 101 ee_want = 1; 102 error = tsleep(&ee_busy, PZERO | PCATCH, "eeprom", 0); 103 ee_want = 0; 104 if (error) /* interrupted */ 105 goto out; 106 } 107 ee_busy = 1; 108 out: 109 return error; 110 } 111 112 static void ee_give() /* Give the lock. */ 113 { 114 ee_busy = 0; 115 if (ee_want) { 116 ee_want = 0; 117 wakeup(&ee_busy); 118 } 119 } 120 121 int eeprom_uio(struct uio *uio) 122 { 123 int error; 124 int off; /* NOT off_t */ 125 u_int cnt; 126 caddr_t va; 127 caddr_t buf = (caddr_t)0; 128 129 off = uio->uio_offset; 130 if (off >= OBIO_EEPROM_SIZE) 131 return (EFAULT); 132 133 cnt = uio->uio_resid; 134 if (cnt > (OBIO_EEPROM_SIZE - off)) 135 cnt = (OBIO_EEPROM_SIZE - off); 136 137 if ((error = ee_take()) != 0) 138 return (error); 139 140 if (eeprom_va == NULL) { 141 error = ENXIO; 142 goto out; 143 } 144 145 va = eeprom_va; 146 if (uio->uio_rw != UIO_READ) { 147 /* Write requires a temporary buffer. */ 148 buf = malloc(OBIO_EEPROM_SIZE, M_DEVBUF, M_WAITOK); 149 if (!buf) { 150 error = EAGAIN; 151 goto out; 152 } 153 va = buf; 154 } 155 156 if ((error = uiomove(va + off, (int)cnt, uio)) != 0) 157 goto out; 158 159 if (uio->uio_rw != UIO_READ) 160 error = ee_update(buf, off, cnt); 161 162 out: 163 if (buf) 164 free(buf, M_DEVBUF); 165 ee_give(); 166 return (error); 167 } 168 169 /* 170 * Update the EEPROM from the passed buf. 171 */ 172 static int ee_update(char *buf, int off, int cnt) 173 { 174 volatile char *ep; 175 char *bp; 176 177 if (eeprom_va == NULL) 178 return (ENXIO); 179 180 ep = eeprom_va + off; 181 bp = buf + off; 182 183 while (cnt > 0) { 184 /* 185 * DO NOT WRITE IT UNLESS WE HAVE TO because the 186 * EEPROM has a limited number of write cycles. 187 * After some number of writes it just fails! 188 */ 189 if (*ep != *bp) { 190 *ep = *bp; 191 /* 192 * We have written the EEPROM, so now we must 193 * sleep for at least 10 milliseconds while 194 * holding the lock to prevent all access to 195 * the EEPROM while it recovers. 196 */ 197 (void)tsleep(eeprom_va, PZERO-1, "eeprom", HZ/50); 198 } 199 /* Make sure the write worked. */ 200 if (*ep != *bp) 201 return (EIO); 202 ep++; 203 bp++; 204 cnt--; 205 } 206 } 207 208 /* 209 * Read a byte out of the EEPROM. This is called from 210 * things like the zs driver very early to find out 211 * which device should be used as the console. 212 */ 213 int ee_get_byte(int off, int canwait) 214 { 215 int c = -1; 216 if ((off < 0) || (off >= OBIO_EEPROM_SIZE)) 217 goto out; 218 if (eeprom_va == NULL) 219 goto out; 220 221 if (canwait) { 222 if (ee_take()) 223 goto out; 224 } else { 225 if (ee_busy) 226 goto out; 227 } 228 229 c = eeprom_va[off] & 0xFF; 230 231 if (canwait) 232 ee_give(); 233 out: 234 return c; 235 } 236