int init_vfc_device(struct sbus_dev *sdev,struct vfc_dev *dev, int instance) { char devname[8]; if(dev == NULL) { printk(KERN_ERR "VFC: Bogus pointer passed\n"); return -ENOMEM; } printk("Initializing vfc%d\n",instance); dev->regs = NULL; dev->regs = (volatile struct vfc_regs *) sbus_ioremap(&sdev->resource[0], 0, sizeof(struct vfc_regs), vfcstr); dev->which_io = sdev->reg_addrs[0].which_io; dev->phys_regs = (struct vfc_regs *) sdev->reg_addrs[0].phys_addr; if (dev->regs == NULL) return -EIO; printk("vfc%d: registers mapped at phys_addr: 0x%lx\n virt_addr: 0x%lx\n", instance,(unsigned long)sdev->reg_addrs[0].phys_addr,(unsigned long)dev->regs); if (init_vfc_devstruct(dev, instance)) return -EINVAL; if (init_vfc_hw(dev)) return -EIO; sprintf (devname, "%d", instance); dev->de = devfs_register (devfs_handle, devname, DEVFS_FL_DEFAULT, VFC_MAJOR, instance, S_IFCHR | S_IRUSR | S_IWUSR, &vfc_fops, NULL); return 0; }
int init_vfc_device(struct sbus_dev *sdev,struct vfc_dev *dev, int instance) { if(dev == NULL) { printk(KERN_ERR "VFC: Bogus pointer passed\n"); return -ENOMEM; } printk("Initializing vfc%d\n",instance); dev->regs = NULL; dev->regs = (volatile struct vfc_regs __iomem *) sbus_ioremap(&sdev->resource[0], 0, sizeof(struct vfc_regs), vfcstr); dev->which_io = sdev->reg_addrs[0].which_io; dev->phys_regs = (struct vfc_regs *) sdev->reg_addrs[0].phys_addr; if (dev->regs == NULL) return -EIO; printk("vfc%d: registers mapped at phys_addr: 0x%lx\n virt_addr: 0x%lx\n", instance,(unsigned long)sdev->reg_addrs[0].phys_addr,(unsigned long)dev->regs); if (init_vfc_devstruct(dev, instance)) return -EINVAL; if (init_vfc_hw(dev)) return -EIO; return 0; }
void __init auxio_power_probe(void) { struct linux_prom_registers regs; int node; struct resource r; /* Attempt to find the sun4m power control node. */ node = prom_getchild(prom_root_node); node = prom_searchsiblings(node, "obio"); node = prom_getchild(node); node = prom_searchsiblings(node, "power"); if (node == 0 || node == -1) return; /* Map the power control register. */ if (prom_getproperty(node, "reg", (char *)®s, sizeof(regs)) <= 0) return; prom_apply_obio_ranges(®s, 1); memset(&r, 0, sizeof(r)); r.flags = regs.which_io & 0xF; r.start = regs.phys_addr; r.end = regs.phys_addr + regs.reg_size - 1; auxio_power_register = (unsigned char *) sbus_ioremap(&r, 0, regs.reg_size, "auxpower"); /* Display a quick message on the console. */ if (auxio_power_register) printk(KERN_INFO "Power off control detected.\n"); }
static int __devinit bw2_init_one(struct of_device *op) { struct device_node *dp = op->node; struct all_info *all; int linebytes, err; all = kzalloc(sizeof(*all), GFP_KERNEL); if (!all) return -ENOMEM; spin_lock_init(&all->par.lock); all->par.physbase = op->resource[0].start; all->par.which_io = op->resource[0].flags & IORESOURCE_BITS; sbusfb_fill_var(&all->info.var, dp->node, 1); linebytes = of_getintprop_default(dp, "linebytes", all->info.var.xres); all->info.var.red.length = all->info.var.green.length = all->info.var.blue.length = all->info.var.bits_per_pixel; all->info.var.red.offset = all->info.var.green.offset = all->info.var.blue.offset = 0; all->par.regs = of_ioremap(&op->resource[0], BWTWO_REGISTER_OFFSET, sizeof(struct bw2_regs), "bw2 regs"); if (!of_find_property(dp, "width", NULL)) bw2_do_default_mode(&all->par, &all->info, &linebytes); all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres); all->info.flags = FBINFO_DEFAULT; all->info.fbops = &bw2_ops; all->info.screen_base = sbus_ioremap(&op->resource[0], 0, all->par.fbsize, "bw2 ram"); all->info.par = &all->par; bw2_blank(0, &all->info); bw2_init_fix(&all->info, linebytes); err= register_framebuffer(&all->info); if (err < 0) { of_iounmap(all->par.regs, sizeof(struct bw2_regs)); of_iounmap(all->info.screen_base, all->par.fbsize); kfree(all); return err; } dev_set_drvdata(&op->dev, all); printk("%s: bwtwo at %lx:%lx\n", dp->full_name, all->par.which_io, all->par.physbase); return 0; }
/* Probe for the real time clock chip on Sun4 */ static __inline__ void sun4_clock_probe(void) { #ifdef CONFIG_SUN4 int temp; struct resource r; memset(&r, 0, sizeof(r)); if( idprom->id_machtype == (SM_SUN4 | SM_4_330) ) { sp_clock_typ = MSTK48T02; r.start = sun4_clock_physaddr; mstk48t02_regs = sbus_ioremap(&r, 0, sizeof(struct mostek48t02), NULL); mstk48t08_regs = NULL; /* To catch weirdness */ intersil_clock = NULL; /* just in case */ /* Kick start the clock if it is completely stopped. */ if (mostek_read(mstk48t02_regs + MOSTEK_SEC) & MSTK_STOP) kick_start_clock(); } else if( idprom->id_machtype == (SM_SUN4 | SM_4_260)) { /* intersil setup code */ printk("Clock: INTERSIL at %8x ",sun4_clock_physaddr); sp_clock_typ = INTERSIL; r.start = sun4_clock_physaddr; intersil_clock = (struct intersil *) sbus_ioremap(&r, 0, sizeof(*intersil_clock), "intersil"); mstk48t02_regs = 0; /* just be sure */ mstk48t08_regs = NULL; /* ditto */ /* initialise the clock */ intersil_intr(intersil_clock,INTERSIL_INT_100HZ); intersil_start(intersil_clock); intersil_read_intr(intersil_clock, temp); while (!(temp & 0x80)) intersil_read_intr(intersil_clock, temp); intersil_read_intr(intersil_clock, temp); while (!(temp & 0x80)) intersil_read_intr(intersil_clock, temp); intersil_stop(intersil_clock); } #endif }
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; }
void __init auxio_probe(void) { struct sbus_bus *sbus; struct sbus_dev *sdev = 0; for_each_sbus(sbus) { for_each_sbusdev(sdev, sbus) { if(!strcmp(sdev->prom_name, "auxio")) goto found_sdev; } } found_sdev: if (!sdev) { #ifdef CONFIG_PCI struct linux_ebus *ebus; struct linux_ebus_device *edev = 0; unsigned long led_auxio; for_each_ebus(ebus) { for_each_ebusdev(edev, ebus) { if (!strcmp(edev->prom_name, "auxio")) goto ebus_done; } } ebus_done: if (edev) { led_auxio = edev->resource[0].start; outl(0x01, led_auxio); return; } #endif if(central_bus || this_is_starfire) { auxio_register = 0UL; return; } prom_printf("Cannot find auxio node, cannot continue...\n"); prom_halt(); } /* Map the register both read and write */ auxio_register = sbus_ioremap(&sdev->resource[0], 0, sdev->reg_addrs[0].reg_size, "auxiliaryIO"); TURN_ON_LED; }
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. */ }
/* Probe this SBus DMA module(s) */ void __init dvma_init(struct sbus_bus *sbus) { struct sbus_dev *this_dev; struct sbus_dma *dma; struct sbus_dma *dchain; static int num_dma = 0; for_each_sbusdev(this_dev, sbus) { char *name = this_dev->prom_name; int hme = 0; if(!strcmp(name, "SUNW,fas")) hme = 1; else if(strcmp(name, "dma") && strcmp(name, "ledma") && strcmp(name, "espdma")) continue; /* Found one... */ dma = kmalloc(sizeof(struct sbus_dma), GFP_ATOMIC); dma->sdev = this_dev; /* Put at end of dma chain */ dchain = dma_chain; if(dchain) { while(dchain->next) dchain = dchain->next; dchain->next = dma; } else { /* We're the first in line */ dma_chain = dma; } dma->regs = sbus_ioremap(&dma->sdev->resource[0], 0, dma->sdev->resource[0].end - dma->sdev->resource[0].start + 1, "dma"); dma->node = dma->sdev->prom_node; init_one_dvma(dma, num_dma++); }
static int __init apc_probe(void) { struct sbus_bus *sbus = NULL; struct sbus_dev *sdev = NULL; int iTmp = 0; for_each_sbus(sbus) { for_each_sbusdev(sdev, sbus) { if (!strcmp(sdev->prom_name, APC_OBPNAME)) { goto sbus_done; } } } sbus_done: if (!sdev) { return -ENODEV; } apc_regsize = sdev->reg_addrs[0].reg_size; regs = sbus_ioremap(&sdev->resource[0], 0, apc_regsize, APC_OBPNAME); if(!regs) { printk(KERN_ERR "%s: unable to map registers\n", APC_DEVNAME); return -ENODEV; } iTmp = misc_register(&apc_miscdev); if (iTmp != 0) { printk(KERN_ERR "%s: unable to register device\n", APC_DEVNAME); apc_free(); return -ENODEV; } /* Assign power management IDLE handler */ if(!apc_no_idle) pm_idle = apc_swift_idle; printk(KERN_INFO "%s: power management initialized%s\n", APC_DEVNAME, apc_no_idle ? " (CPU idle disabled)" : ""); return 0; }
void __init auxio_probe(void) { struct sbus_bus *sbus; struct sbus_dev *sdev = NULL; for_each_sbus(sbus) { for_each_sbusdev(sdev, sbus) { if(!strcmp(sdev->prom_name, "auxio")) goto found_sdev; } } found_sdev: if (sdev) { auxio_devtype = AUXIO_TYPE_SBUS; auxio_register = sbus_ioremap(&sdev->resource[0], 0, sdev->reg_addrs[0].reg_size, "auxiliaryIO"); } #ifdef CONFIG_PCI else { struct linux_ebus *ebus; struct linux_ebus_device *edev = NULL; for_each_ebus(ebus) { for_each_ebusdev(edev, ebus) { if (!strcmp(edev->prom_name, "auxio")) goto ebus_done; } } ebus_done: if (edev) { auxio_devtype = AUXIO_TYPE_EBUS; auxio_register = ioremap(edev->resource[0].start, sizeof(u32)); } } auxio_set_led(AUXIO_LED_ON); #endif }
void __init iommu_init(int iommund, struct sbus_bus *sbus) { unsigned int impl, vers; unsigned long tmp; struct iommu_struct *iommu; struct linux_prom_registers iommu_promregs[PROMREG_MAX]; struct resource r; unsigned long *bitmap; iommu = kmalloc(sizeof(struct iommu_struct), GFP_ATOMIC); if (!iommu) { prom_printf("Unable to allocate iommu structure\n"); prom_halt(); } prom_getproperty(iommund, "reg", (void *) iommu_promregs, sizeof(iommu_promregs)); memset(&r, 0, sizeof(r)); r.flags = iommu_promregs[0].which_io; r.start = iommu_promregs[0].phys_addr; iommu->regs = (struct iommu_regs *) sbus_ioremap(&r, 0, PAGE_SIZE * 3, "iommu_regs"); if(!iommu->regs) { prom_printf("Cannot map IOMMU registers\n"); prom_halt(); } impl = (iommu->regs->control & IOMMU_CTRL_IMPL) >> 28; vers = (iommu->regs->control & IOMMU_CTRL_VERS) >> 24; tmp = iommu->regs->control; tmp &= ~(IOMMU_CTRL_RNGE); tmp |= (IOMMU_RNGE_256MB | IOMMU_CTRL_ENAB); iommu->regs->control = tmp; iommu_invalidate(iommu->regs); iommu->start = IOMMU_START; iommu->end = 0xffffffff; /* Allocate IOMMU page table */ /* Stupid alignment constraints give me a headache. We need 256K or 512K or 1M or 2M area aligned to its size and current gfp will fortunately give it to us. */ tmp = __get_free_pages(GFP_KERNEL, IOMMU_ORDER); if (!tmp) { prom_printf("Unable to allocate iommu table [0x%08x]\n", IOMMU_NPTES*sizeof(iopte_t)); prom_halt(); } iommu->page_table = (iopte_t *)tmp; /* Initialize new table. */ memset(iommu->page_table, 0, IOMMU_NPTES*sizeof(iopte_t)); flush_cache_all(); flush_tlb_all(); iommu->regs->base = __pa((unsigned long) iommu->page_table) >> 4; iommu_invalidate(iommu->regs); bitmap = kmalloc(IOMMU_NPTES>>3, GFP_KERNEL); if (!bitmap) { prom_printf("Unable to allocate iommu bitmap [%d]\n", (int)(IOMMU_NPTES>>3)); prom_halt(); }
void __init sun4m_init_IRQ(void) { int ie_node,i; struct linux_prom_registers int_regs[PROMREG_MAX]; int num_regs; struct resource r; int mid; local_irq_disable(); if((ie_node = prom_searchsiblings(prom_getchild(prom_root_node), "obio")) == 0 || (ie_node = prom_getchild (ie_node)) == 0 || (ie_node = prom_searchsiblings (ie_node, "interrupt")) == 0) { prom_printf("Cannot find /obio/interrupt node\n"); prom_halt(); } num_regs = prom_getproperty(ie_node, "reg", (char *) int_regs, sizeof(int_regs)); num_regs = (num_regs/sizeof(struct linux_prom_registers)); /* Apply the obio ranges to these registers. */ prom_apply_obio_ranges(int_regs, num_regs); int_regs[4].phys_addr = int_regs[num_regs-1].phys_addr; int_regs[4].reg_size = int_regs[num_regs-1].reg_size; int_regs[4].which_io = int_regs[num_regs-1].which_io; for(ie_node = 1; ie_node < 4; ie_node++) { int_regs[ie_node].phys_addr = int_regs[ie_node-1].phys_addr + PAGE_SIZE; int_regs[ie_node].reg_size = int_regs[ie_node-1].reg_size; int_regs[ie_node].which_io = int_regs[ie_node-1].which_io; } memset((char *)&r, 0, sizeof(struct resource)); /* Map the interrupt registers for all possible cpus. */ r.flags = int_regs[0].which_io; r.start = int_regs[0].phys_addr; sun4m_interrupts = (struct sun4m_intregs *) sbus_ioremap(&r, 0, PAGE_SIZE*SUN4M_NCPUS, "interrupts_percpu"); /* Map the system interrupt control registers. */ r.flags = int_regs[4].which_io; r.start = int_regs[4].phys_addr; sbus_ioremap(&r, 0, int_regs[4].reg_size, "interrupts_system"); sun4m_interrupts->set = ~SUN4M_INT_MASKALL; for (i = 0; !cpu_find_by_instance(i, NULL, &mid); i++) sun4m_interrupts->cpu_intregs[mid].clear = ~0x17fff; if (!cpu_find_by_instance(1, NULL, NULL)) { /* system wide interrupts go to cpu 0, this should always * be safe because it is guaranteed to be fitted or OBP doesn't * come up * * Not sure, but writing here on SLAVIO systems may puke * so I don't do it unless there is more than 1 cpu. */ irq_rcvreg = (unsigned long *) &sun4m_interrupts->undirected_target; sun4m_interrupts->undirected_target = 0; } BTFIXUPSET_CALL(sbint_to_irq, sun4m_sbint_to_irq, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(enable_irq, sun4m_enable_irq, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(disable_irq, sun4m_disable_irq, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(enable_pil_irq, sun4m_enable_pil_irq, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(disable_pil_irq, sun4m_disable_pil_irq, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(clear_clock_irq, sun4m_clear_clock_irq, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(clear_profile_irq, sun4m_clear_profile_irq, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(load_profile_irq, sun4m_load_profile_irq, BTFIXUPCALL_NORM); sparc_init_timers = sun4m_init_timers; #ifdef CONFIG_SMP BTFIXUPSET_CALL(set_cpu_int, sun4m_send_ipi, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(clear_cpu_int, sun4m_clear_ipi, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(set_irq_udt, sun4m_set_udt, BTFIXUPCALL_NORM); #endif /* Cannot enable interrupts until OBP ticker is disabled. */ }
static void __init sun4m_init_timers(irqreturn_t (*counter_fn)(int, void *, struct pt_regs *)) { int reg_count, irq, cpu; struct linux_prom_registers cnt_regs[PROMREG_MAX]; int obio_node, cnt_node; struct resource r; cnt_node = 0; if((obio_node = prom_searchsiblings (prom_getchild(prom_root_node), "obio")) == 0 || (obio_node = prom_getchild (obio_node)) == 0 || (cnt_node = prom_searchsiblings (obio_node, "counter")) == 0) { prom_printf("Cannot find /obio/counter node\n"); prom_halt(); } reg_count = prom_getproperty(cnt_node, "reg", (void *) cnt_regs, sizeof(cnt_regs)); reg_count = (reg_count/sizeof(struct linux_prom_registers)); /* Apply the obio ranges to the timer registers. */ prom_apply_obio_ranges(cnt_regs, reg_count); cnt_regs[4].phys_addr = cnt_regs[reg_count-1].phys_addr; cnt_regs[4].reg_size = cnt_regs[reg_count-1].reg_size; cnt_regs[4].which_io = cnt_regs[reg_count-1].which_io; for(obio_node = 1; obio_node < 4; obio_node++) { cnt_regs[obio_node].phys_addr = cnt_regs[obio_node-1].phys_addr + PAGE_SIZE; cnt_regs[obio_node].reg_size = cnt_regs[obio_node-1].reg_size; cnt_regs[obio_node].which_io = cnt_regs[obio_node-1].which_io; } memset((char*)&r, 0, sizeof(struct resource)); /* Map the per-cpu Counter registers. */ r.flags = cnt_regs[0].which_io; r.start = cnt_regs[0].phys_addr; sun4m_timers = (struct sun4m_timer_regs *) sbus_ioremap(&r, 0, PAGE_SIZE*SUN4M_NCPUS, "sun4m_cpu_cnt"); /* Map the system Counter register. */ /* XXX Here we expect consequent calls to yeld adjusent maps. */ r.flags = cnt_regs[4].which_io; r.start = cnt_regs[4].phys_addr; sbus_ioremap(&r, 0, cnt_regs[4].reg_size, "sun4m_sys_cnt"); sun4m_timers->l10_timer_limit = (((1000000/HZ) + 1) << 10); master_l10_counter = &sun4m_timers->l10_cur_count; master_l10_limit = &sun4m_timers->l10_timer_limit; irq = request_irq(TIMER_IRQ, counter_fn, (IRQF_DISABLED | SA_STATIC_ALLOC), "timer", NULL); if (irq) { prom_printf("time_init: unable to attach IRQ%d\n",TIMER_IRQ); prom_halt(); } if (!cpu_find_by_instance(1, NULL, NULL)) { for(cpu = 0; cpu < 4; cpu++) sun4m_timers->cpu_timers[cpu].l14_timer_limit = 0; sun4m_interrupts->set = SUN4M_INT_E14; } else { sun4m_timers->cpu_timers[0].l14_timer_limit = 0; } #ifdef CONFIG_SMP { unsigned long flags; extern unsigned long lvl14_save[4]; struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (14 - 1)]; /* For SMP we use the level 14 ticker, however the bootup code * has copied the firmwares level 14 vector into boot cpu's * trap table, we must fix this now or we get squashed. */ local_irq_save(flags); trap_table->inst_one = lvl14_save[0]; trap_table->inst_two = lvl14_save[1]; trap_table->inst_three = lvl14_save[2]; trap_table->inst_four = lvl14_save[3]; local_flush_cache_all(); local_irq_restore(flags); } #endif }
char __init *cgthreefb_init(struct fb_info_sbusfb *fb) { struct fb_fix_screeninfo *fix = &fb->fix; struct display *disp = &fb->disp; struct fbtype *type = &fb->type; struct sbus_dev *sdev = fb->sbdp; unsigned long phys = sdev->reg_addrs[0].phys_addr; int cgRDI = strstr(fb->sbdp->prom_name, "cgRDI") != NULL; #ifndef FBCON_HAS_CFB8 return NULL; #endif if (!fb->s.cg3.regs) { fb->s.cg3.regs = (struct cg3_regs *) sbus_ioremap(&sdev->resource[0], CG3_REGS_OFFSET, sizeof(struct cg3_regs), "cg3 regs"); if (cgRDI) { char buffer[40]; char *p; int ww, hh; *buffer = 0; prom_getstring (fb->prom_node, "params", buffer, sizeof(buffer)); if (*buffer) { ww = simple_strtoul (buffer, &p, 10); if (ww && *p == 'x') { hh = simple_strtoul (p + 1, &p, 10); if (hh && *p == '-') { if (type->fb_width != ww || type->fb_height != hh) { type->fb_width = ww; type->fb_height = hh; return SBUSFBINIT_SIZECHANGE; } } } } } } strcpy(fb->info.modename, "CGthree"); strcpy(fix->id, "CGthree"); fix->line_length = fb->var.xres_virtual; fix->accel = FB_ACCEL_SUN_CGTHREE; disp->scrollmode = SCROLL_YREDRAW; if (!disp->screen_base) { disp->screen_base = (char *) sbus_ioremap(&sdev->resource[0], CG3_RAM_OFFSET, type->fb_size, "cg3 ram"); } disp->screen_base += fix->line_length * fb->y_margin + fb->x_margin; fb->dispsw = fbcon_cfb8; fb->margins = cg3_margins; fb->loadcmap = cg3_loadcmap; fb->blank = cg3_blank; fb->unblank = cg3_unblank; fb->physbase = phys; fb->mmap_map = cg3_mmap_map; #ifdef __sparc_v9__ sprintf(idstring, "%s at %016lx", cgRDI ? "cgRDI" : "cgthree", phys); #else sprintf(idstring, "%s at %x.%08lx", cgRDI ? "cgRDI" : "cgthree", fb->iospace, phys); #endif if (!prom_getbool(fb->prom_node, "width")) { /* Ugh, broken PROM didn't initialize us. * Let's deal with this ourselves. */ enum cg3_type type; u8 *p; if (cgRDI) type = CG3_RDI; else { u8 status = sbus_readb(&fb->s.cg3.regs->status), mon; if ((status & CG3_SR_ID_MASK) == CG3_SR_ID_COLOR) { mon = status & CG3_SR_RES_MASK; if (mon == CG3_SR_1152_900_76_A || mon == CG3_SR_1152_900_76_B) type = CG3_AT_76HZ; else type = CG3_AT_66HZ; } else { prom_printf("cgthree: can't handle SR %02x\n", status); prom_halt(); return NULL; /* fool gcc. */ } } for (p = cg3_regvals[type]; *p; p += 2) { u8 *regp = &((u8 *)fb->s.cg3.regs)[p[0]]; sbus_writeb(p[1], regp); } for (p = cg3_dacvals; *p; p += 2) { volatile u8 *regp; regp = (volatile u8 *)&fb->s.cg3.regs->cmap.addr; sbus_writeb(p[0], regp); regp = (volatile u8 *)&fb->s.cg3.regs->cmap.control; sbus_writeb(p[1], regp); } } return idstring; }
static void __iomem *map_bpp(struct sbus_dev *dev, int idx) { return sbus_ioremap(&dev->resource[0], 0, BPP_SIZE, "bpp"); }
/* Probe for the mostek real time clock chip. */ static __inline__ void clock_probe(void) { struct linux_prom_registers clk_reg[2]; char model[128]; register int node, cpuunit, bootbus; struct resource r; cpuunit = bootbus = 0; memset(&r, 0, sizeof(r)); /* Determine the correct starting PROM node for the probe. */ node = prom_getchild(prom_root_node); switch (sparc_cpu_model) { case sun4c: break; case sun4m: node = prom_getchild(prom_searchsiblings(node, "obio")); break; case sun4d: node = prom_getchild(bootbus = prom_searchsiblings(prom_getchild(cpuunit = prom_searchsiblings(node, "cpu-unit")), "bootbus")); break; default: prom_printf("CLOCK: Unsupported architecture!\n"); prom_halt(); } /* Find the PROM node describing the real time clock. */ sp_clock_typ = MSTK_INVALID; node = prom_searchsiblings(node,"eeprom"); if (!node) { prom_printf("CLOCK: No clock found!\n"); prom_halt(); } /* Get the model name and setup everything up. */ model[0] = '\0'; prom_getstring(node, "model", model, sizeof(model)); if (strcmp(model, "mk48t02") == 0) { sp_clock_typ = MSTK48T02; if (prom_getproperty(node, "reg", (char *) clk_reg, sizeof(clk_reg)) == -1) { prom_printf("clock_probe: FAILED!\n"); prom_halt(); } if (sparc_cpu_model == sun4d) prom_apply_generic_ranges (bootbus, cpuunit, clk_reg, 1); else prom_apply_obio_ranges(clk_reg, 1); /* Map the clock register io area read-only */ r.flags = clk_reg[0].which_io; r.start = clk_reg[0].phys_addr; mstk48t02_regs = sbus_ioremap(&r, 0, sizeof(struct mostek48t02), "mk48t02"); mstk48t08_regs = NULL; /* To catch weirdness */ } else if (strcmp(model, "mk48t08") == 0) { sp_clock_typ = MSTK48T08; if(prom_getproperty(node, "reg", (char *) clk_reg, sizeof(clk_reg)) == -1) { prom_printf("clock_probe: FAILED!\n"); prom_halt(); } if (sparc_cpu_model == sun4d) prom_apply_generic_ranges (bootbus, cpuunit, clk_reg, 1); else prom_apply_obio_ranges(clk_reg, 1); /* Map the clock register io area read-only */ /* XXX r/o attribute is somewhere in r.flags */ r.flags = clk_reg[0].which_io; r.start = clk_reg[0].phys_addr; mstk48t08_regs = (struct mostek48t08 *) sbus_ioremap(&r, 0, sizeof(struct mostek48t08), "mk48t08"); mstk48t02_regs = &mstk48t08_regs->regs; } else { prom_printf("CLOCK: Unknown model name '%s'\n",model); prom_halt(); } /* Report a low battery voltage condition. */ if (has_low_battery()) printk(KERN_CRIT "NVRAM: Low battery voltage!\n"); /* Kick start the clock if it is completely stopped. */ if (mostek_read(mstk48t02_regs + MOSTEK_SEC) & MSTK_STOP) kick_start_clock(); }
char * __init leofb_init(struct fb_info_sbusfb *fb) { struct fb_fix_screeninfo *fix = &fb->fix; struct fb_var_screeninfo *var = &fb->var; struct display *disp = &fb->disp; struct fbtype *type = &fb->type; struct sbus_dev *sdev = fb->sbdp; unsigned long phys = sdev->reg_addrs[0].phys_addr; struct fb_wid_item wi; struct fb_wid_list wl; int i; register struct leo_lc_ss0_usr *us; register struct leo_ld *ss; struct fb_ops *fbops; u32 tmp; strcpy(fb->info.modename, "Leo"); strcpy(fix->id, "Leo"); fix->visual = FB_VISUAL_TRUECOLOR; fix->line_length = 8192; fix->accel = FB_ACCEL_SUN_LEO; var->bits_per_pixel = 32; var->green.offset = 8; var->blue.offset = 16; var->accel_flags = FB_ACCELF_TEXT; fbops = kmalloc(sizeof(*fbops), GFP_KERNEL); if (fbops == NULL) return NULL; *fbops = *fb->info.fbops; fbops->fb_rasterimg = leo_rasterimg; fb->info.fbops = fbops; disp->scrollmode = SCROLL_YREDRAW; if (!disp->screen_base) { disp->screen_base = (char *) sbus_ioremap(&sdev->resource[0], LEO_OFF_SS0, 0x800000, "leo ram"); } disp->screen_base += 8192 * fb->y_margin + 4 * fb->x_margin; us = fb->s.leo.lc_ss0_usr = (struct leo_lc_ss0_usr *) sbus_ioremap(&sdev->resource[0], LEO_OFF_LC_SS0_USR, 0x1000, "leolc ss0usr"); fb->s.leo.ld_ss0 = (struct leo_ld_ss0 *) sbus_ioremap(&sdev->resource[0], LEO_OFF_LD_SS0, 0x1000, "leold ss0"); ss = (struct leo_ld *) fb->s.leo.ld_ss0; fb->s.leo.ld_ss1 = (struct leo_ld_ss1 *) sbus_ioremap(&sdev->resource[0], LEO_OFF_LD_SS1, 0x1000, "leold ss1"); fb->s.leo.lx_krn = (struct leo_lx_krn *) sbus_ioremap(&sdev->resource[0], LEO_OFF_LX_KRN, 0x1000, "leolx krn"); fb->s.leo.cursor = (struct leo_cursor *) sbus_ioremap(&sdev->resource[0], LEO_OFF_LX_CURSOR, sizeof(struct leo_cursor), "leolx cursor"); fb->dispsw = leo_dispsw; fb->s.leo.extent = (type->fb_width-1) | ((type->fb_height-1) << 16); wl.wl_count = 1; wl.wl_list = &wi; wi.wi_type = FB_WID_DBL_8; wi.wi_index = 0; wi.wi_values [0] = 0x2c0; leo_wid_put (fb, &wl); wi.wi_index = 1; wi.wi_values [0] = 0x30; leo_wid_put (fb, &wl); wi.wi_index = 2; wi.wi_values [0] = 0x20; leo_wid_put (fb, &wl); wi.wi_type = FB_WID_DBL_24; wi.wi_index = 1; wi.wi_values [0] = 0x30; leo_wid_put (fb, &wl); tmp = sbus_readl(&fb->s.leo.ld_ss1->ss1_misc); tmp |= LEO_SS1_MISC_ENABLE; sbus_writel(tmp, &fb->s.leo.ld_ss1->ss1_misc); sbus_writel(0xffffffff, &ss->wid); sbus_writel(0xffff, &ss->wmask); sbus_writel(0, &ss->vclipmin); sbus_writel(fb->s.leo.extent, &ss->vclipmax); sbus_writel(0, &ss->fg); sbus_writel(0xff000000, &ss->planemask); sbus_writel(0x310850, &ss->rop); sbus_writel(0, &ss->widclip); sbus_writel((type->fb_width-1) | ((type->fb_height-1) << 11), &us->extent); sbus_writel(4, &us->addrspace); sbus_writel(0x80000000, &us->fill); sbus_writel(0, &us->fontt); do { i = sbus_readl(&us->csr); } while (i & 0x20000000); fb->margins = leo_margins; fb->loadcmap = leo_loadcmap; fb->setcursor = leo_setcursor; fb->setcursormap = leo_setcursormap; fb->setcurshape = leo_setcurshape; fb->restore_palette = leo_restore_palette; fb->switch_from_graph = leo_switch_from_graph; fb->fill = leo_fill; fb->blank = leo_blank; fb->unblank = leo_unblank; fb->physbase = phys; fb->mmap_map = leo_mmap_map; #ifdef __sparc_v9__ sprintf(idstring, "leo at %016lx", phys); #else sprintf(idstring, "leo at %x.%08lx", fb->iospace, phys); #endif return idstring; }
static int __init init_one_port(struct sbus_dev *sdev) { struct parport *p; /* at least in theory there may be a "we don't dma" case */ struct parport_operations *ops; unsigned long base; int irq, dma, err, size; struct bpp_regs *regs; unsigned char value_tcr; dprintk((KERN_DEBUG "init_one_port(%p): ranges, alloc_io, ", sdev)); irq = sdev->irqs[0]; base = sbus_ioremap(&sdev->resource[0], 0, sdev->reg_addrs[0].reg_size, "sunbpp"); size = sdev->reg_addrs[0].reg_size; dma = PARPORT_DMA_NONE; dprintk(("alloc(ppops), ")); ops = kmalloc (sizeof (struct parport_operations), GFP_KERNEL); if (!ops) { sbus_iounmap(base, size); return 0; } memcpy (ops, &parport_sunbpp_ops, sizeof (struct parport_operations)); dprintk(("register_port\n")); if (!(p = parport_register_port(base, irq, dma, ops))) { kfree(ops); sbus_iounmap(base, size); return 0; } p->size = size; dprintk((KERN_DEBUG "init_one_port: request_irq(%08x:%p:%x:%s:%p) ", p->irq, parport_sunbpp_interrupt, SA_SHIRQ, p->name, p)); if ((err = request_irq(p->irq, parport_sunbpp_interrupt, SA_SHIRQ, p->name, p)) != 0) { dprintk(("ERROR %d\n", err)); parport_unregister_port(p); kfree(ops); sbus_iounmap(base, size); return err; } else { dprintk(("OK\n")); parport_sunbpp_enable_irq(p); } regs = (struct bpp_regs *)p->base; dprintk((KERN_DEBUG "forward\n")); value_tcr = sbus_readb(®s->p_tcr); value_tcr &= ~P_TCR_DIR; sbus_writeb(value_tcr, ®s->p_tcr); printk(KERN_INFO "%s: sunbpp at 0x%lx\n", p->name, p->base); parport_proc_register(p); parport_announce_port (p); return 1; }
static int __init init_one_port(struct sbus_dev *sdev) { struct parport *p; /* at least in theory there may be a "we don't dma" case */ struct parport_operations *ops; void __iomem *base; int irq, dma, err = 0, size; struct bpp_regs __iomem *regs; unsigned char value_tcr; Node *node; dprintk((KERN_DEBUG "init_one_port(%p): ranges, alloc_io, ", sdev)); node = kmalloc(sizeof(Node), GFP_KERNEL); if (!node) goto out0; irq = sdev->irqs[0]; base = sbus_ioremap(&sdev->resource[0], 0, sdev->reg_addrs[0].reg_size, "sunbpp"); if (!base) goto out1; size = sdev->reg_addrs[0].reg_size; dma = PARPORT_DMA_NONE; dprintk(("alloc(ppops), ")); ops = kmalloc (sizeof (struct parport_operations), GFP_KERNEL); if (!ops) goto out2; memcpy (ops, &parport_sunbpp_ops, sizeof (struct parport_operations)); dprintk(("register_port\n")); if (!(p = parport_register_port((unsigned long)base, irq, dma, ops))) goto out3; p->size = size; dprintk((KERN_DEBUG "init_one_port: request_irq(%08x:%p:%x:%s:%p) ", p->irq, parport_sunbpp_interrupt, SA_SHIRQ, p->name, p)); if ((err = request_irq(p->irq, parport_sunbpp_interrupt, SA_SHIRQ, p->name, p)) != 0) { dprintk(("ERROR %d\n", err)); goto out4; } dprintk(("OK\n")); parport_sunbpp_enable_irq(p); regs = (struct bpp_regs __iomem *)p->base; dprintk((KERN_DEBUG "forward\n")); value_tcr = sbus_readb(®s->p_tcr); value_tcr &= ~P_TCR_DIR; sbus_writeb(value_tcr, ®s->p_tcr); printk(KERN_INFO "%s: sunbpp at 0x%lx\n", p->name, p->base); node->port = p; list_add(&node->list, &port_list); parport_announce_port (p); return 1; out4: parport_put_port(p); out3: kfree(ops); out2: sbus_iounmap(base, size); out1: kfree(node); out0: return err; }
static int __init myri_ether_init(struct net_device *dev, struct sbus_dev *sdev, int num) { static unsigned version_printed = 0; struct myri_eth *mp; unsigned char prop_buf[32]; int i; DET(("myri_ether_init(%p,%p,%d):\n", dev, sdev, num)); dev = init_etherdev(0, sizeof(struct myri_eth)); if (version_printed++ == 0) printk(version); printk("%s: MyriCOM MyriNET Ethernet ", dev->name); mp = (struct myri_eth *) dev->priv; mp->myri_sdev = sdev; /* Clean out skb arrays. */ for (i = 0; i < (RX_RING_SIZE + 1); i++) mp->rx_skbs[i] = NULL; for (i = 0; i < TX_RING_SIZE; i++) mp->tx_skbs[i] = NULL; /* First check for EEPROM information. */ i = prom_getproperty(sdev->prom_node, "myrinet-eeprom-info", (char *)&mp->eeprom, sizeof(struct myri_eeprom)); DET(("prom_getprop(myrinet-eeprom-info) returns %d\n", i)); if (i == 0 || i == -1) { /* No eeprom property, must cook up the values ourselves. */ DET(("No EEPROM: ")); mp->eeprom.bus_type = BUS_TYPE_SBUS; mp->eeprom.cpuvers = prom_getintdefault(sdev->prom_node,"cpu_version",0); mp->eeprom.cval = prom_getintdefault(sdev->prom_node,"clock_value",0); mp->eeprom.ramsz = prom_getintdefault(sdev->prom_node,"sram_size",0); DET(("cpuvers[%d] cval[%d] ramsz[%d]\n", mp->eeprom.cpuvers, mp->eeprom.cval, mp->eeprom.ramsz)); if (mp->eeprom.cpuvers == 0) { DET(("EEPROM: cpuvers was zero, setting to %04x\n",CPUVERS_2_3)); mp->eeprom.cpuvers = CPUVERS_2_3; } if (mp->eeprom.cpuvers < CPUVERS_3_0) { DET(("EEPROM: cpuvers < CPUVERS_3_0, clockval set to zero.\n")); mp->eeprom.cval = 0; } if (mp->eeprom.ramsz == 0) { DET(("EEPROM: ramsz == 0, setting to 128k\n")); mp->eeprom.ramsz = (128 * 1024); } i = prom_getproperty(sdev->prom_node, "myrinet-board-id", &prop_buf[0], 10); DET(("EEPROM: prom_getprop(myrinet-board-id) returns %d\n", i)); if ((i != 0) && (i != -1)) memcpy(&mp->eeprom.id[0], &prop_buf[0], 6); else set_boardid_from_idprom(mp, num); i = prom_getproperty(sdev->prom_node, "fpga_version", &mp->eeprom.fvers[0], 32); DET(("EEPROM: prom_getprop(fpga_version) returns %d\n", i)); if (i == 0 || i == -1) memset(&mp->eeprom.fvers[0], 0, 32); if (mp->eeprom.cpuvers == CPUVERS_4_1) { DET(("EEPROM: cpuvers CPUVERS_4_1, ")); if (mp->eeprom.ramsz == (128 * 1024)) { DET(("ramsize 128k, setting to 256k, ")); mp->eeprom.ramsz = (256 * 1024); } if ((mp->eeprom.cval==0x40414041)||(mp->eeprom.cval==0x90449044)){ DET(("changing cval from %08x to %08x ", mp->eeprom.cval, 0x50e450e4)); mp->eeprom.cval = 0x50e450e4; } DET(("\n")); } } #ifdef DEBUG_DETECT dump_eeprom(mp); #endif for (i = 0; i < 6; i++) printk("%2.2x%c", dev->dev_addr[i] = mp->eeprom.id[i], i == 5 ? ' ' : ':'); printk("\n"); determine_reg_space_size(mp); /* Map in the MyriCOM register/localram set. */ if (mp->eeprom.cpuvers < CPUVERS_4_0) { /* XXX Makes no sense, if control reg is non-existant this * XXX driver cannot function at all... maybe pre-4.0 is * XXX only a valid version for PCI cards? Ask feldy... */ DET(("Mapping regs for cpuvers < CPUVERS_4_0\n")); mp->regs = sbus_ioremap(&sdev->resource[0], 0, mp->reg_size, "MyriCOM Regs"); if (!mp->regs) { printk("MyriCOM: Cannot map MyriCOM registers.\n"); return -ENODEV; } mp->lanai = (unsigned short *) (mp->regs + (256 * 1024)); mp->lanai3 = (unsigned int *) mp->lanai; mp->lregs = (unsigned long) &mp->lanai[0x10000]; } else { DET(("Mapping regs for cpuvers >= CPUVERS_4_0\n")); mp->cregs = sbus_ioremap(&sdev->resource[0], 0, PAGE_SIZE, "MyriCOM Control Regs"); mp->lregs = sbus_ioremap(&sdev->resource[0], (256 * 1024), PAGE_SIZE, "MyriCOM LANAI Regs"); mp->lanai = (unsigned short *) sbus_ioremap(&sdev->resource[0], (512 * 1024), mp->eeprom.ramsz, "MyriCOM SRAM"); mp->lanai3 = (unsigned int *) mp->lanai; } DET(("Registers mapped: cregs[%lx] lregs[%lx] lanai[%p] lanai3[%p]\n", mp->cregs, mp->lregs, mp->lanai, mp->lanai3)); if (mp->eeprom.cpuvers >= CPUVERS_4_0) mp->shmem_base = 0xf000; else mp->shmem_base = 0x8000; DET(("Shared memory base is %04x, ", mp->shmem_base)); mp->shmem = (struct myri_shmem *) &mp->lanai[mp->shmem_base]; DET(("shmem mapped at %p\n", mp->shmem)); mp->rqack = &mp->shmem->channel.recvqa; mp->rq = &mp->shmem->channel.recvq; mp->sq = &mp->shmem->channel.sendq; /* Reset the board. */ DET(("Resetting LANAI\n")); myri_reset_off(mp->lregs, mp->cregs); myri_reset_on(mp->cregs); /* Turn IRQ's off. */ myri_disable_irq(mp->lregs, mp->cregs); /* Reset once more. */ myri_reset_on(mp->cregs); /* Get the supported DVMA burst sizes from our SBUS. */ mp->myri_bursts = prom_getintdefault(mp->myri_sdev->bus->prom_node, "burst-sizes", 0x00); if (!sbus_can_burst64(sdev)) mp->myri_bursts &= ~(DMA_BURST64); DET(("MYRI bursts %02x\n", mp->myri_bursts)); /* Encode SBUS interrupt level in second control register. */ i = prom_getint(sdev->prom_node, "interrupts"); if (i == 0) i = 4; DET(("prom_getint(interrupts)==%d, irqlvl set to %04x\n", i, (1 << i))); sbus_writel((1 << i), mp->cregs + MYRICTRL_IRQLVL); mp->dev = dev; dev->open = &myri_open; dev->stop = &myri_close; dev->hard_start_xmit = &myri_start_xmit; dev->tx_timeout = &myri_tx_timeout; dev->watchdog_timeo = 5*HZ; dev->get_stats = &myri_get_stats; dev->set_multicast_list = &myri_set_multicast; dev->irq = sdev->irqs[0]; /* Register interrupt handler now. */ DET(("Requesting MYRIcom IRQ line.\n")); if (request_irq(dev->irq, &myri_interrupt, SA_SHIRQ, "MyriCOM Ethernet", (void *) dev)) { printk("MyriCOM: Cannot register interrupt handler.\n"); return -ENODEV; } DET(("ether_setup()\n")); ether_setup(dev); dev->mtu = MYRINET_MTU; dev->change_mtu = myri_change_mtu; dev->hard_header = myri_header; dev->rebuild_header = myri_rebuild_header; dev->hard_header_len = (ETH_HLEN + MYRI_PAD_LEN); dev->hard_header_cache = myri_header_cache; dev->header_cache_update= myri_header_cache_update; /* Load code onto the LANai. */ DET(("Loading LANAI firmware\n")); myri_load_lanai(mp); #ifdef MODULE dev->ifindex = dev_new_index(); mp->next_module = root_myri_dev; root_myri_dev = mp; #endif return 0; }
static int __devinit init_one_port(struct sbus_dev *sdev) { struct parport *p; /* at least in theory there may be a "we don't dma" case */ struct parport_operations *ops; void __iomem *base; int irq, dma, err = 0, size; struct bpp_regs __iomem *regs; unsigned char value_tcr; irq = sdev->irqs[0]; base = sbus_ioremap(&sdev->resource[0], 0, sdev->reg_addrs[0].reg_size, "sunbpp"); if (!base) return -ENODEV; size = sdev->reg_addrs[0].reg_size; dma = PARPORT_DMA_NONE; ops = kmalloc(sizeof(struct parport_operations), GFP_KERNEL); if (!ops) goto out_unmap; memcpy (ops, &parport_sunbpp_ops, sizeof (struct parport_operations)); dprintk(("register_port\n")); if (!(p = parport_register_port((unsigned long)base, irq, dma, ops))) goto out_free_ops; p->size = size; p->dev = &sdev->ofdev.dev; if ((err = request_irq(p->irq, parport_sunbpp_interrupt, IRQF_SHARED, p->name, p)) != 0) { goto out_put_port; } parport_sunbpp_enable_irq(p); regs = (struct bpp_regs __iomem *)p->base; value_tcr = sbus_readb(®s->p_tcr); value_tcr &= ~P_TCR_DIR; sbus_writeb(value_tcr, ®s->p_tcr); printk(KERN_INFO "%s: sunbpp at 0x%lx\n", p->name, p->base); dev_set_drvdata(&sdev->ofdev.dev, p); parport_announce_port(p); return 0; out_put_port: parport_put_port(p); out_free_ops: kfree(ops); out_unmap: sbus_iounmap(base, size); return err; }