/* Acquire an integer property and return its value. Returns -1 * on failure. */ inline int prom_getint(int node, const char *prop) { int intprop; if (prom_getproperty(node, prop, (char *) &intprop, sizeof(int)) != -1) return intprop; return -1; }
/* Acquire a property whose value is a string, returns a null * string on error. The char pointer is the user supplied string * buffer. */ void prom_getstring(int node, const char *prop, char *user_buf, int ubuf_size) { int len; len = prom_getproperty(node, prop, user_buf, ubuf_size); if (len != -1) return; user_buf[0] = 0; }
/* Acquire an integer property and return its value. Returns -1 * on failure. */ int prom_getint(int node, char *prop) { static int intprop; if(prom_getproperty(node, prop, (char *) &intprop, sizeof(int)) != -1) return intprop; return -1; }
/* Does the device at node 'node' have name 'name'? * YES = 1 NO = 0 */ int prom_nodematch(int node, char *name) { int error; static char namebuf[128]; error = prom_getproperty(node, "name", namebuf, sizeof(namebuf)); if (error == -1) return 0; if(strcmp(namebuf, name) == 0) return 1; return 0; }
__initfunc(unsigned long device_scan(unsigned long mem_start)) { char node_str[128]; int nd, prom_node_cpu, thismid; int cpu_nds[NR_CPUS]; /* One node for each cpu */ int cpu_ctr = 0; prom_getstring(prom_root_node, "device_type", node_str, sizeof(node_str)); if(strcmp(node_str, "cpu") == 0) { cpu_nds[0] = prom_root_node; linux_cpus[0].prom_node = prom_root_node; linux_cpus[0].mid = 0; cpu_ctr++; } else { int scan; scan = prom_getchild(prom_root_node); prom_printf("root child is %08x\n", (unsigned) scan); nd = 0; while((scan = prom_getsibling(scan)) != 0) { prom_getstring(scan, "device_type", node_str, sizeof(node_str)); if(strcmp(node_str, "cpu") == 0) { cpu_nds[cpu_ctr] = scan; linux_cpus[cpu_ctr].prom_node = scan; prom_getproperty(scan, "upa-portid", (char *) &thismid, sizeof(thismid)); linux_cpus[cpu_ctr].mid = thismid; #ifdef __SMP__ prom_printf("Found CPU %d (node=%08x,mid=%d)\n", cpu_ctr, (unsigned) scan, thismid); printk("Found CPU %d (node=%08x,mid=%d)\n", cpu_ctr, (unsigned) scan, thismid); #endif cpu_ctr++; } }; if(cpu_ctr == 0) { prom_printf("No CPU nodes found, cannot continue.\n"); prom_halt(); } #ifdef __SMP__ printk("Found %d CPU prom device tree node(s).\n", cpu_ctr); #endif }; prom_node_cpu = cpu_nds[0]; linux_num_cpus = cpu_ctr; prom_cpu_nodes[0] = prom_node_cpu; cpu_probe(); return central_probe(mem_start); }
static void __init ebus_ranges_init(struct linux_ebus *ebus) { int success; ebus->num_ebus_ranges = 0; success = prom_getproperty(ebus->prom_node, "ranges", (char *)ebus->ebus_ranges, sizeof(ebus->ebus_ranges)); if (success != -1) ebus->num_ebus_ranges = (success/sizeof(struct linux_prom_ebus_ranges)); }
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; const char *name; if (tmp) { p = tmp; memset(p, 0, sizeof(*p) + 32); tmp = NULL; } else { p = prom_early_alloc(sizeof(struct property) + 32); p->unique_id = prom_unique_id++; } p->name = (char *) (p + 1); 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 { if (prev == NULL) { name = prom_firstprop(node, p->name); } else { name = prom_nextprop(node, prev, p->name); } if (!name || strlen(name) == 0) { tmp = p; return NULL; } #ifdef CONFIG_SPARC32 strcpy(p->name, name); #endif p->length = prom_getproplen(node, p->name); if (p->length <= 0) { p->length = 0; } else { int len; p->value = prom_early_alloc(p->length + 1); len = prom_getproperty(node, p->name, p->value, p->length); if (len <= 0) p->length = 0; ((unsigned char *)p->value)[p->length] = '\0'; } } return p; }
enum prom_output_device prom_query_output_device(void) { int st_p; char propb[64]; int propl; st_p = prom_inst2pkg(prom_stdout); propl = prom_getproperty(st_p, "device_type", propb, sizeof(propb)); if (propl >= 0 && propl == sizeof("display") && strncmp("display", propb, sizeof("display")) == 0) return PROMDEV_OSCREEN; if(strncmp("serial", propb, 6)) return PROMDEV_O_UNK; /* FIXME: Is there any better way how to find out? */ memset(propb, 0, sizeof(propb)); st_p = prom_finddevice ("/options"); prom_getproperty(st_p, "output-device", propb, sizeof(propb)); /* * If we get here with propb == 'screen', we are on ttya, as * the PROM defaulted to this due to 'no input device'. */ if (!strncmp(propb, "screen", 6)) return PROMDEV_OTTYA; if (!strncmp (propb, "rsc", 3)) return PROMDEV_ORSC; if (!strncmp (propb, "virtual-console", 3)) return PROMDEV_OVCONS; if (strncmp (propb, "tty", 3) || !propb[3]) return PROMDEV_O_UNK; switch (propb[3]) { case 'a': return PROMDEV_OTTYA; case 'b': return PROMDEV_OTTYB; default: return PROMDEV_O_UNK; } }
static void __init ebus_intmap_init(struct linux_ebus *ebus) { int success; ebus->num_ebus_intmap = 0; success = prom_getproperty(ebus->prom_node, "interrupt-map", (char *)ebus->ebus_intmap, sizeof(ebus->ebus_intmap)); if (success == -1) return; ebus->num_ebus_intmap = (success/sizeof(struct linux_prom_ebus_intmap)); success = prom_getproperty(ebus->prom_node, "interrupt-map-mask", (char *)&ebus->ebus_intmask, sizeof(ebus->ebus_intmask)); if (success == -1) { prom_printf("%s: can't get interrupt-map-mask\n", __FUNCTION__); prom_halt(); } }
/* Get the idprom and stuff it into buffer 'idbuf'. Returns the * format type. 'num_bytes' is the number of bytes that your idbuf * has space for. Returns 0xff on error. */ unsigned char prom_get_idprom(char *idbuf, int num_bytes) { int len; len = prom_getproplen(prom_root_node, "idprom"); if((len>num_bytes) || (len==-1)) return 0xff; if(!prom_getproperty(prom_root_node, "idprom", idbuf, num_bytes)) return idbuf[0]; return 0xff; }
void prom_ranges_init(void) { int node, obio_node, sbus_node; int success; num_obio_ranges = 0; num_sbus_ranges = 0; /* Check for obio and sbus ranges. */ node = prom_getchild(prom_root_node); obio_node = prom_searchsiblings(node, "obio"); sbus_node = prom_searchsiblings(node, "iommu"); if(sbus_node) { sbus_node = prom_getchild(sbus_node); sbus_node = prom_searchsiblings(sbus_node, "sbus"); } if(obio_node) { success = prom_getproperty(obio_node, "ranges", (char *) promlib_obio_ranges, sizeof(promlib_obio_ranges)); if(success != -1) num_obio_ranges = (success/sizeof(struct linux_prom_ranges)); } if(sbus_node) { success = prom_getproperty(sbus_node, "ranges", (char *) promlib_sbus_ranges, sizeof(promlib_sbus_ranges)); if(success != -1) num_sbus_ranges = (success/sizeof(struct linux_prom_ranges)); } if(num_obio_ranges || num_sbus_ranges) prom_printf("PROMLIB: obio_ranges %d sbus_ranges %d\n", num_obio_ranges, num_sbus_ranges); return; }
/* * XXX This functions appears to be a distorted version of * prom_sbus_ranges_init(), with all sun4d stuff cut away. * Ask DaveM what is going on here, how is sun4d supposed to work... XXX */ static void __init sbus_bus_ranges_init(int parent_node, struct sbus_bus *sbus) { int len; len = prom_getproperty(sbus->prom_node, "ranges", (char *) sbus->sbus_ranges, sizeof(sbus->sbus_ranges)); if (len == -1 || len == 0) { sbus->num_sbus_ranges = 0; return; } sbus->num_sbus_ranges = len / sizeof(struct linux_prom_ranges); }
static char * __init get_one_property(phandle node, const char *name) { char *buf = "<NULL>"; int len; len = prom_getproplen(node, name); if (len > 0) { buf = prom_early_alloc(len); len = prom_getproperty(node, name, buf, len); } return buf; }
/* Query for input device type */ enum prom_input_device prom_query_input_device(void) { int st_p; char propb[64]; st_p = prom_inst2pkg(prom_stdin); if(prom_node_has_property(st_p, "keyboard")) return PROMDEV_IKBD; prom_getproperty(st_p, "device_type", propb, sizeof(propb)); if(strncmp(propb, "serial", 6)) return PROMDEV_I_UNK; /* FIXME: Is there any better way how to find out? */ memset(propb, 0, sizeof(propb)); st_p = prom_finddevice ("/options"); prom_getproperty(st_p, "input-device", propb, sizeof(propb)); /* * If we get here with propb == 'keyboard', we are on ttya, as * the PROM defaulted to this due to 'no input device'. */ if (!strncmp(propb, "keyboard", 8)) return PROMDEV_ITTYA; if (!strncmp (propb, "rsc", 3)) return PROMDEV_IRSC; if (!strncmp (propb, "virtual-console", 3)) return PROMDEV_IVCONS; if (strncmp (propb, "tty", 3) || !propb[3]) return PROMDEV_I_UNK; switch (propb[3]) { case 'a': return PROMDEV_ITTYA; case 'b': return PROMDEV_ITTYB; default: return PROMDEV_I_UNK; } }
void __init auxio_probe(void) { int node, auxio_nd; struct linux_prom_registers auxregs[1]; struct resource r; switch (sparc_cpu_model) { case sun4d: case sun4: auxio_register = 0; return; default: break; } node = prom_getchild(prom_root_node); auxio_nd = prom_searchsiblings(node, "auxiliary-io"); if(!auxio_nd) { node = prom_searchsiblings(node, "obio"); node = prom_getchild(node); auxio_nd = prom_searchsiblings(node, "auxio"); if(!auxio_nd) { #ifdef CONFIG_PCI /* There may be auxio on Ebus */ auxio_register = 0; return; #else if(prom_searchsiblings(node, "leds")) { /* VME chassis sun4m machine, no auxio exists. */ auxio_register = 0; return; } prom_printf("Cannot find auxio node, cannot continue...\n"); prom_halt(); #endif } } prom_getproperty(auxio_nd, "reg", (char *) auxregs, sizeof(auxregs)); prom_apply_obio_ranges(auxregs, 0x1); /* Map the register both read and write */ r.flags = auxregs[0].which_io & 0xF; r.start = auxregs[0].phys_addr; r.end = auxregs[0].phys_addr + auxregs[0].reg_size - 1; auxio_register = (unsigned char *) sbus_ioremap(&r, 0, auxregs[0].reg_size, "auxio"); /* Fix the address on sun4m and sun4c. */ if((((unsigned long) auxregs[0].phys_addr) & 3) == 3 || sparc_cpu_model == sun4c) auxio_register = (unsigned char *) ((int)auxio_register | 3); TURN_ON_LED; }
const char *promcon_startup(void) { const char *display_desc = "PROM"; int node; char buf[40]; node = prom_getchild(prom_root_node); node = prom_searchsiblings(node, "options"); if (prom_getproperty(node, "screen-#columns", buf, 40) != -1) { pw = simple_strtoul(buf, NULL, 0); if (pw < 10 || pw > 256) pw = 80; pw--; } if (prom_getproperty(node, "screen-#rows", buf, 40) != -1) { ph = simple_strtoul(buf, NULL, 0); if (ph < 10 || ph > 256) ph = 34; ph--; } promcon_puts("\033[H\033[J", 6); return display_desc; }
/* Acquire an integer property and return its value. Returns -1 * on failure. */ int prom_getint(int node, char *prop) { static int intprop; #if CONFIG_AP1000 printk("prom_getint(%s) -> -1\n",prop); return -1; #endif if(prom_getproperty(node, prop, (char *) &intprop, sizeof(int)) != -1) return intprop; return -1; }
/* Acquire a property whose value is a string, returns a null * string on error. The char pointer is the user supplied string * buffer. */ void prom_getstring(int node, char *prop, char *user_buf, int ubuf_size) { int len; #if CONFIG_AP1000 printk("prom_getstring(%s) -> .\n",prop); return; #endif len = prom_getproperty(node, prop, user_buf, ubuf_size); if(len != -1) return; user_buf[0] = 0; return; }
void __init auxio_probe(void) { phandle node, auxio_nd; struct linux_prom_registers auxregs[1]; struct resource r; switch (sparc_cpu_model) { case sparc_leon: case sun4d: case sun4: return; default: break; } node = prom_getchild(prom_root_node); auxio_nd = prom_searchsiblings(node, "auxiliary-io"); if(!auxio_nd) { node = prom_searchsiblings(node, "obio"); node = prom_getchild(node); auxio_nd = prom_searchsiblings(node, "auxio"); if(!auxio_nd) { #ifdef CONFIG_PCI return; #else if(prom_searchsiblings(node, "leds")) { return; } prom_printf("Cannot find auxio node, cannot continue...\n"); prom_halt(); #endif } } if(prom_getproperty(auxio_nd, "reg", (char *) auxregs, sizeof(auxregs)) <= 0) return; prom_apply_obio_ranges(auxregs, 0x1); r.flags = auxregs[0].which_io & 0xF; r.start = auxregs[0].phys_addr; r.end = auxregs[0].phys_addr + auxregs[0].reg_size - 1; auxio_register = of_ioremap(&r, 0, auxregs[0].reg_size, "auxio"); if((((unsigned long) auxregs[0].phys_addr) & 3) == 3 || sparc_cpu_model == sun4c) auxio_register += (3 - ((unsigned long)auxio_register & 3)); set_auxio(AUXIO_LED, 0); }
static char *serial(char *buffer) { int node = prom_getchild(prom_root_node); int len; node = prom_searchsiblings(node, "options"); *buffer = 0; len = prom_getproperty(node, "system-board-serial#", buffer, 256); if(len > 0) buffer[len] = 0; if (!*buffer) return "4512348717234"; else return buffer; }
/* Function Description: Initialize monitor channel with channel desc, * decoding tables, monitor type, optional properties. * Return: None. */ static void envctrl_init_adc(struct i2c_child_t *pchild, int node) { char chnls_desc[CHANNEL_DESC_SZ]; int i = 0, len; char *pos = chnls_desc; /* Firmware describe channels into a stream separated by a '\0'. */ len = prom_getproperty(node, "channels-description", chnls_desc, CHANNEL_DESC_SZ); chnls_desc[CHANNEL_DESC_SZ - 1] = '\0'; while (len > 0) { int l = strlen(pos) + 1; envctrl_set_mon(pchild, pos, i++); len -= l; pos += l; } /* Get optional properties. */ len = prom_getproperty(node, "warning-temp", (char *)&warning_temperature, sizeof(warning_temperature)); len = prom_getproperty(node, "shutdown-temp", (char *)&shutdown_temperature, sizeof(shutdown_temperature)); }
static void __init read_obp_memory(const char *property, struct linux_prom64_registers *regs, int *num_ents) { int node = prom_finddevice("/memory"); int prop_size = prom_getproplen(node, property); int ents, ret, i; ents = prop_size / sizeof(struct linux_prom64_registers); if (ents > MAX_BANKS) { prom_printf("The machine has more %s property entries than " "this kernel can support (%d).\n", property, MAX_BANKS); prom_halt(); } ret = prom_getproperty(node, property, (char *) regs, prop_size); if (ret == -1) { prom_printf("Couldn't get %s property from /memory.\n"); prom_halt(); } *num_ents = ents; /* Sanitize what we got from the firmware, by page aligning * everything. */ for (i = 0; i < ents; i++) { unsigned long base, size; base = regs[i].phys_addr; size = regs[i].reg_size; size &= PAGE_MASK; if (base & ~PAGE_MASK) { unsigned long new_base = PAGE_ALIGN(base); size -= new_base - base; if ((long) size < 0L) size = 0UL; base = new_base; } regs[i].phys_addr = base; regs[i].reg_size = size; } sort(regs, ents, sizeof(struct linux_prom64_registers), cmp_p64, NULL); }
/* Search siblings at 'node_start' for a node with name * 'nodename'. Return node if successful, zero if not. */ int prom_searchsiblings(int node_start, char *nodename) { int thisnode, error; for(thisnode = node_start; thisnode; thisnode=prom_getsibling(thisnode)) { error = prom_getproperty(thisnode, "name", promlib_buf, sizeof(promlib_buf)); /* Should this ever happen? */ if(error == -1) continue; if(strcmp(nodename, promlib_buf)==0) return thisnode; } return 0; }
static int __init prom_meminit_v2(void) { struct linux_prom_registers reg[64]; int node, size, num_ents, i; node = prom_searchsiblings(prom_getchild(prom_root_node), "memory"); size = prom_getproperty(node, "available", (char *) reg, sizeof(reg)); num_ents = size / sizeof(struct linux_prom_registers); for (i = 0; i < num_ents; i++) { sp_banks[i].base_addr = reg[i].phys_addr; sp_banks[i].num_bytes = reg[i].reg_size; } return num_ents; }
int prom_finddevice(char *name) { char nbuf[128]; char *s = name, *d; int node = prom_root_node, node2; unsigned int which_io, phys_addr; struct linux_prom_registers reg[PROMREG_MAX]; while (*s++) { if (!*s) return node; /* path '.../' is legal */ node = prom_getchild(node); for (d = nbuf; *s != 0 && *s != '@' && *s != '/';) *d++ = *s++; *d = 0; node = prom_searchsiblings(node, nbuf); if (!node) return 0; if (*s == '@') { if (isxdigit(s[1]) && s[2] == ',') { which_io = simple_strtoul(s+1, NULL, 16); phys_addr = simple_strtoul(s+3, &d, 16); if (d != s + 3 && (!*d || *d == '/') && d <= s + 3 + 8) { node2 = node; while (node2 && node2 != -1) { if (prom_getproperty (node2, "reg", (char *)reg, sizeof (reg)) > 0) { if (which_io == reg[0].which_io && phys_addr == reg[0].phys_addr) { node = node2; break; } } node2 = prom_getsibling(node2); if (!node2 || node2 == -1) break; node2 = prom_searchsiblings(prom_getsibling(node2), nbuf); } } } while (*s != 0 && *s != '/') s++; } } return node; }
__initfunc(static int pdev_to_pnode(struct linux_pbm_info *pbm, struct pci_dev *pdev)) { struct linux_prom_pci_registers regs[PROMREG_MAX]; int err; int node = prom_getchild(pbm->prom_node); while(node) { err = prom_getproperty(node, "reg", (char *)®s[0], sizeof(regs)); if(err != 0 && err != -1) { unsigned long devfn = (regs[0].which_io >> 8) & 0xff; if(devfn == pdev->devfn) return node; /* Match */ } node = prom_getsibling(node); }
/* Search siblings at 'node_start' for a node with name * 'nodename'. Return node if successful, zero if not. */ phandle prom_searchsiblings(phandle node_start, const char *nodename) { phandle thisnode; int error; char promlib_buf[128]; for(thisnode = node_start; thisnode; thisnode=prom_getsibling(thisnode)) { error = prom_getproperty(thisnode, "name", promlib_buf, sizeof(promlib_buf)); /* Should this ever happen? */ if(error == -1) continue; if(strcmp(nodename, promlib_buf)==0) return thisnode; } return 0; }
void __init fill_ebus_device(int node, struct linux_ebus_device *dev) { struct linux_prom_registers regs[PROMREG_MAX]; struct linux_ebus_child *child; int irqs[PROMINTR_MAX]; char lbuf[128]; int i, n, len; unsigned long baseaddr; dev->prom_node = node; prom_getstring(node, "name", lbuf, sizeof(lbuf)); strcpy(dev->prom_name, lbuf); len = prom_getproperty(node, "reg", (void *)regs, sizeof(regs)); if (len % sizeof(struct linux_prom_registers)) { prom_printf("UGH: proplen for %s was %d, need multiple of %d\n", dev->prom_name, len, (int)sizeof(struct linux_prom_registers)); panic(__FUNCTION__); } dev->num_addrs = len / sizeof(struct linux_prom_registers); for (i = 0; i < dev->num_addrs; i++) { /* * XXX Collect JE-1 PROM * * Example - JS-E with 3.11: * /ebus * regs * 0x00000000, 0x0, 0x00000000, 0x0, 0x00000000, * 0x82000010, 0x0, 0xf0000000, 0x0, 0x01000000, * 0x82000014, 0x0, 0x38800000, 0x0, 0x00800000, * ranges * 0x00, 0x00000000, 0x02000010, 0x0, 0x0, 0x01000000, * 0x01, 0x01000000, 0x02000014, 0x0, 0x0, 0x00800000, * /ebus/8042 * regs * 0x00000001, 0x00300060, 0x00000008, * 0x00000001, 0x00300060, 0x00000008, */ n = regs[i].which_io; if (n >= 4) { /* XXX This is copied from old JE-1 by Gleb. */ n = (regs[i].which_io - 0x10) >> 2; } else {
static char *platform(char *buffer) { int len; *buffer = 0; len = prom_getproperty(prom_root_node, "name", buffer, 256); if(len > 0) buffer[len] = 0; if (*buffer) { char *p; for (p = buffer; *p; p++) if (*p == '/' || *p == ' ') *p = '_'; return buffer; } return "sun4u"; }
void __init sun4c_init_IRQ(void) { struct linux_prom_registers int_regs[2]; int ie_node; if (ARCH_SUN4) { interrupt_enable = (char *) ioremap(sun4_ie_physaddr, PAGE_SIZE); } else { struct resource phyres; ie_node = prom_searchsiblings (prom_getchild(prom_root_node), "interrupt-enable"); if(ie_node == 0) panic("Cannot find /interrupt-enable node"); /* Depending on the "address" property is bad news... */ prom_getproperty(ie_node, "reg", (char *) int_regs, sizeof(int_regs)); memset(&phyres, 0, sizeof(struct resource)); phyres.flags = int_regs[0].which_io; phyres.start = int_regs[0].phys_addr; interrupt_enable = (char *) sbus_ioremap(&phyres, 0, int_regs[0].reg_size, "sun4c_intr"); } BTFIXUPSET_CALL(sbint_to_irq, sun4c_sbint_to_irq, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(enable_irq, sun4c_enable_irq, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(disable_irq, sun4c_disable_irq, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(enable_pil_irq, sun4c_enable_irq, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(disable_pil_irq, sun4c_disable_irq, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(clear_clock_irq, sun4c_clear_clock_irq, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(clear_profile_irq, sun4c_clear_profile_irq, BTFIXUPCALL_NOP); BTFIXUPSET_CALL(load_profile_irq, sun4c_load_profile_irq, BTFIXUPCALL_NOP); BTFIXUPSET_CALL(__irq_itoa, sun4m_irq_itoa, BTFIXUPCALL_NORM); sparc_init_timers = sun4c_init_timers; #ifdef CONFIG_SMP BTFIXUPSET_CALL(set_cpu_int, sun4c_nop, BTFIXUPCALL_NOP); BTFIXUPSET_CALL(clear_cpu_int, sun4c_nop, BTFIXUPCALL_NOP); BTFIXUPSET_CALL(set_irq_udt, sun4c_nop, BTFIXUPCALL_NOP); #endif *interrupt_enable = (SUN4C_INT_ENABLE); /* Cannot enable interrupts until OBP ticker is disabled. */ }