Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 | /* Code to support devices on the DIO (and eventually DIO-II) bus * Copyright (C) 05/1998 Peter Maydell <pmaydell@chiark.greenend.org.uk> * * This code has basically these routines at the moment: * int dio_find(u_int deviceid) * Search the list of DIO devices and return the select code * of the next unconfigured device found that matches the given device ID. * Note that the deviceid parameter should be the encoded ID. * This means that framebuffers should pass it as * DIO_ENCODE_ID(DIO_ID_FBUFFER,DIO_ID2_TOPCAT) * (or whatever); everybody else just uses DIO_ID_FOOBAR. * void *dio_scodetoviraddr(int scode) * Return the virtual address corresponding to the given select code. * NB: DIO-II devices will have to be mapped in in this routine! * int dio_scodetoipl(int scode) * Every DIO card has a fixed interrupt priority level. This function * returns it, whatever it is. * const char *dio_scodetoname(int scode) * Return a character string describing this board [might be "" if * not CONFIG_DIO_CONSTANTS] * void dio_config_board(int scode) mark board as configured in the list * void dio_unconfig_board(int scode) mark board as no longer configured * * This file is based on the way the Amiga port handles Zorro II cards, * although we aren't so complicated... */ #include <linux/config.h> #include <linux/kernel.h> #include <linux/types.h> #include <linux/dio.h> #include <linux/slab.h> /* kmalloc() */ #include <linux/init.h> #include <asm/hwtest.h> /* hwreg_present() */ #include <asm/io.h> /* readb() */ /* not a real config option yet! */ #define CONFIG_DIO_CONSTANTS #ifdef CONFIG_DIO_CONSTANTS /* We associate each numeric ID with an appropriate descriptive string * using a constant array of these structs. * FIXME: we should be able to arrange to throw away most of the strings * using the initdata stuff. Then we wouldn't need to worry about * carrying them around... * I think we do this by copying them into newly kmalloc()ed memory and * marking the names[] array as .initdata ? */ struct dioname { int id; const char *name; }; /* useful macro */ #define DIONAME(x) { DIO_ID_##x, DIO_DESC_##x } #define DIOFBNAME(x) { DIO_ENCODE_ID( DIO_ID_FBUFFER, DIO_ID2_##x), DIO_DESC2_##x } static struct dioname names[] = { DIONAME(DCA0), DIONAME(DCA0REM), DIONAME(DCA1), DIONAME(DCA1REM), DIONAME(DCM), DIONAME(DCMREM), DIONAME(LAN), DIONAME(FHPIB), DIONAME(NHPIB), DIONAME(IHPIB), DIONAME(SCSI0), DIONAME(SCSI1), DIONAME(SCSI2), DIONAME(SCSI3), DIONAME(FBUFFER), DIONAME(PARALLEL), DIONAME(VME), DIONAME(DCL), DIONAME(DCLREM), DIONAME(MISC0), DIONAME(MISC1), DIONAME(MISC2), DIONAME(MISC3), DIONAME(MISC4), DIONAME(MISC5), DIONAME(MISC6), DIONAME(MISC7), DIONAME(MISC8), DIONAME(MISC9), DIONAME(MISC10), DIONAME(MISC11), DIONAME(MISC12), DIONAME(MISC13), DIOFBNAME(GATORBOX), DIOFBNAME(TOPCAT), DIOFBNAME(RENAISSANCE), DIOFBNAME(LRCATSEYE), DIOFBNAME(HRCCATSEYE), DIOFBNAME(HRMCATSEYE), DIOFBNAME(DAVINCI), DIOFBNAME(XXXCATSEYE), DIOFBNAME(HYPERION), DIOFBNAME(XGENESIS), DIOFBNAME(TIGER), DIOFBNAME(YGENESIS) }; #undef DIONAME #undef DIOFBNAME #define NUMNAMES (sizeof(names) / sizeof(struct dioname)) static const char *unknowndioname = "unknown DIO board -- please email <pmaydell@chiark.greenend.org.uk>!"; static const char *dio_getname(int id) { /* return pointer to a constant string describing the board with given ID */ unsigned int i; for (i = 0; i < NUMNAMES; i++) if (names[i].id == id) return names[i].name; return unknowndioname; } #else static char dio_no_name[] = { 0 }; #define dio_getname(_id) (dio_no_name) #endif /* CONFIG_DIO_CONSTANTS */ /* We represent all the DIO boards in the system with a linked list of these structs. */ struct dioboard { struct dioboard *next; /* link to next struct in list */ int ipl; /* IPL of this board */ int configured; /* has this board been configured? */ int scode; /* select code of this board */ int id; /* encoded ID */ const char *name; }; static struct dioboard *blist = NULL; static int __init dio_find_slow(int deviceid) { /* Called to find a DIO device before the full bus scan has run. Basically * only used by the console driver. * We don't do the primary+secondary ID encoding thing here. Maybe we should. * (that would break the topcat detection, though. I need to think about * the whole primary/secondary ID thing.) */ int scode; u_char prid; for (scode = 0; scode < DIO_SCMAX; scode++) { void *va; if (DIO_SCINHOLE(scode)) continue; va = dio_scodetoviraddr(scode); if (!va || !hwreg_present(va + DIO_IDOFF)) continue; /* no board present at that select code */ /* We aren't very likely to want to use this to get at the IHPIB, * but maybe it's returning the same ID as the card we do want... */ if (!DIO_ISIHPIB(scode)) prid = DIO_ID(va); else prid = DIO_ID_IHPIB; if (prid == deviceid) return scode; } return 0; } /* Aargh: we use 0 for an error return code, but select code 0 exists! * FIXME (trivial, use -1, but requires changes to all the drivers :-< ) */ int dio_find(int deviceid) { if (blist) { /* fast way */ struct dioboard *b; for (b = blist; b; b = b->next) if (b->id == deviceid && b->configured == 0) return b->scode; return 0; } return dio_find_slow(deviceid); } /* This is the function that scans the DIO space and works out what * hardware is actually present. */ static int __init dio_init(void) { int scode; struct dioboard *b, *bprev = NULL; printk("Scanning for DIO devices...\n"); for (scode = 0; scode < DIO_SCMAX; ++scode) { u_char prid, secid = 0; /* primary, secondary ID bytes */ u_char *va; if (DIO_SCINHOLE(scode)) continue; va = dio_scodetoviraddr(scode); if (!va || !hwreg_present(va + DIO_IDOFF)) continue; /* no board present at that select code */ /* Found a board, allocate it an entry in the list */ b = kmalloc(sizeof(struct dioboard), GFP_KERNEL); /* read the ID byte(s) and encode if necessary. Note workaround * for broken internal HPIB devices... */ if (!DIO_ISIHPIB(scode)) prid = DIO_ID(va); else prid = DIO_ID_IHPIB; if (DIO_NEEDSSECID(prid)) { secid = DIO_SECID(va); b->id = DIO_ENCODE_ID(prid, secid); } else b->id = prid; b->configured = 0; b->scode = scode; b->ipl = DIO_IPL(va); b->name = dio_getname(b->id); printk("select code %3d: ipl %d: ID %02X", scode, b->ipl, prid); if (DIO_NEEDSSECID(b->id)) printk(":%02X", secid); printk(": %s\n", b->name); b->next = NULL; if (bprev) bprev->next = b; else blist = b; bprev = b; } return 0; } subsys_initcall(dio_init); /* Bear in mind that this is called in the very early stages of initialisation * in order to get the virtual address of the serial port for the console... */ void *dio_scodetoviraddr(int scode) { if (scode > DIOII_SCBASE) { printk("dio_scodetoviraddr: don't support DIO-II yet!\n"); return 0; } else if (scode > DIO_SCMAX || scode < 0) return 0; else if (DIO_SCINHOLE(scode)) return 0; else if (DIO_ISIHPIB(scode)) return (void*)DIO_IHPIBADDR; return (void*)(DIO_VIRADDRBASE + DIO_BASE + scode * 0x10000); } int dio_scodetoipl(int scode) { struct dioboard *b; for (b = blist; b; b = b->next) if (b->scode == scode) break; if (!b) { printk("dio_scodetoipl: bad select code %d\n", scode); return 0; } else return b->ipl; } const char *dio_scodetoname(int scode) { struct dioboard *b; for (b = blist; b; b = b->next) if (b->scode == scode) break; if (!b) { printk("dio_scodetoname: bad select code %d\n", scode); return NULL; } else return b->name; } void dio_config_board(int scode) { struct dioboard *b; for (b = blist; b; b = b->next) if (b->scode == scode) break; if (!b) printk("dio_config_board: bad select code %d\n", scode); else if (b->configured) printk("dio_config_board: board at select code %d already configured\n", scode); else b->configured = 1; } void dio_unconfig_board(int scode) { struct dioboard *b; for (b = blist; b; b = b->next) if (b->scode == scode) break; if (!b) printk("dio_unconfig_board: bad select code %d\n", scode); else if (!b->configured) printk("dio_unconfig_board: board at select code %d not configured\n", scode); else b->configured = 0; } |