10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 51756Sszhou * Common Development and Distribution License (the "License"). 61756Sszhou * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 221756Sszhou * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 270Sstevel@tonic-gate 280Sstevel@tonic-gate /* 290Sstevel@tonic-gate * ISA bus nexus driver 300Sstevel@tonic-gate */ 310Sstevel@tonic-gate 320Sstevel@tonic-gate #include <sys/types.h> 330Sstevel@tonic-gate #include <sys/cmn_err.h> 340Sstevel@tonic-gate #include <sys/conf.h> 350Sstevel@tonic-gate #include <sys/modctl.h> 360Sstevel@tonic-gate #include <sys/autoconf.h> 370Sstevel@tonic-gate #include <sys/errno.h> 380Sstevel@tonic-gate #include <sys/debug.h> 390Sstevel@tonic-gate #include <sys/kmem.h> 40*2007Sml40262 #include <sys/psm.h> 410Sstevel@tonic-gate #include <sys/ddidmareq.h> 420Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 430Sstevel@tonic-gate #include <sys/dma_engine.h> 440Sstevel@tonic-gate #include <sys/ddi.h> 450Sstevel@tonic-gate #include <sys/sunddi.h> 460Sstevel@tonic-gate #include <sys/sunndi.h> 470Sstevel@tonic-gate #include <sys/acpi/acpi_enum.h> 480Sstevel@tonic-gate 490Sstevel@tonic-gate extern int isa_resource_setup(void); 500Sstevel@tonic-gate static char USED_RESOURCES[] = "used-resources"; 510Sstevel@tonic-gate static void isa_alloc_nodes(dev_info_t *); 52*2007Sml40262 static void enumerate_BIOS_serial(dev_info_t *); 53*2007Sml40262 54*2007Sml40262 #define BIOS_DATA_AREA 0x400 550Sstevel@tonic-gate /* 560Sstevel@tonic-gate * #define ISA_DEBUG 1 570Sstevel@tonic-gate */ 580Sstevel@tonic-gate 590Sstevel@tonic-gate /* 600Sstevel@tonic-gate * Local data 610Sstevel@tonic-gate */ 620Sstevel@tonic-gate static ddi_dma_lim_t ISA_dma_limits = { 630Sstevel@tonic-gate 0, /* address low */ 640Sstevel@tonic-gate 0x00ffffff, /* address high */ 650Sstevel@tonic-gate 0, /* counter max */ 660Sstevel@tonic-gate 1, /* burstsize */ 670Sstevel@tonic-gate DMA_UNIT_8, /* minimum xfer */ 680Sstevel@tonic-gate 0, /* dma speed */ 690Sstevel@tonic-gate (uint_t)DMALIM_VER0, /* version */ 700Sstevel@tonic-gate 0x0000ffff, /* address register */ 710Sstevel@tonic-gate 0x0000ffff, /* counter register */ 720Sstevel@tonic-gate 1, /* sector size */ 730Sstevel@tonic-gate 0x00000001, /* scatter/gather list length */ 740Sstevel@tonic-gate (uint_t)0xffffffff /* request size */ 750Sstevel@tonic-gate }; 760Sstevel@tonic-gate 770Sstevel@tonic-gate static ddi_dma_attr_t ISA_dma_attr = { 780Sstevel@tonic-gate DMA_ATTR_V0, 790Sstevel@tonic-gate (unsigned long long)0, 800Sstevel@tonic-gate (unsigned long long)0x00ffffff, 810Sstevel@tonic-gate 0x0000ffff, 820Sstevel@tonic-gate 1, 830Sstevel@tonic-gate 1, 840Sstevel@tonic-gate 1, 850Sstevel@tonic-gate (unsigned long long)0xffffffff, 860Sstevel@tonic-gate (unsigned long long)0x0000ffff, 870Sstevel@tonic-gate 1, 880Sstevel@tonic-gate 1, 890Sstevel@tonic-gate 0 900Sstevel@tonic-gate }; 910Sstevel@tonic-gate 920Sstevel@tonic-gate 930Sstevel@tonic-gate /* 940Sstevel@tonic-gate * Config information 950Sstevel@tonic-gate */ 960Sstevel@tonic-gate 970Sstevel@tonic-gate static int 980Sstevel@tonic-gate isa_dma_allochdl(dev_info_t *, dev_info_t *, ddi_dma_attr_t *, 990Sstevel@tonic-gate int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *); 1000Sstevel@tonic-gate 1010Sstevel@tonic-gate static int 1020Sstevel@tonic-gate isa_dma_mctl(dev_info_t *, dev_info_t *, ddi_dma_handle_t, enum ddi_dma_ctlops, 1030Sstevel@tonic-gate off_t *, size_t *, caddr_t *, uint_t); 1040Sstevel@tonic-gate 1050Sstevel@tonic-gate static int 1060Sstevel@tonic-gate isa_ctlops(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, void *, void *); 1070Sstevel@tonic-gate 1080Sstevel@tonic-gate struct bus_ops isa_bus_ops = { 1090Sstevel@tonic-gate BUSO_REV, 1100Sstevel@tonic-gate i_ddi_bus_map, 1110Sstevel@tonic-gate NULL, 1120Sstevel@tonic-gate NULL, 1130Sstevel@tonic-gate NULL, 1140Sstevel@tonic-gate i_ddi_map_fault, 1150Sstevel@tonic-gate ddi_dma_map, 1160Sstevel@tonic-gate isa_dma_allochdl, 1170Sstevel@tonic-gate ddi_dma_freehdl, 1180Sstevel@tonic-gate ddi_dma_bindhdl, 1190Sstevel@tonic-gate ddi_dma_unbindhdl, 1200Sstevel@tonic-gate ddi_dma_flush, 1210Sstevel@tonic-gate ddi_dma_win, 1220Sstevel@tonic-gate isa_dma_mctl, 1230Sstevel@tonic-gate isa_ctlops, 1240Sstevel@tonic-gate ddi_bus_prop_op, 1250Sstevel@tonic-gate NULL, /* (*bus_get_eventcookie)(); */ 1260Sstevel@tonic-gate NULL, /* (*bus_add_eventcall)(); */ 1270Sstevel@tonic-gate NULL, /* (*bus_remove_eventcall)(); */ 1280Sstevel@tonic-gate NULL, /* (*bus_post_event)(); */ 1290Sstevel@tonic-gate NULL, /* (*bus_intr_ctl)(); */ 1300Sstevel@tonic-gate NULL, /* (*bus_config)(); */ 1310Sstevel@tonic-gate NULL, /* (*bus_unconfig)(); */ 1320Sstevel@tonic-gate NULL, /* (*bus_fm_init)(); */ 1330Sstevel@tonic-gate NULL, /* (*bus_fm_fini)(); */ 1340Sstevel@tonic-gate NULL, /* (*bus_fm_access_enter)(); */ 1350Sstevel@tonic-gate NULL, /* (*bus_fm_access_exit)(); */ 1360Sstevel@tonic-gate NULL, /* (*bus_power)(); */ 1370Sstevel@tonic-gate i_ddi_intr_ops /* (*bus_intr_op)(); */ 1380Sstevel@tonic-gate }; 1390Sstevel@tonic-gate 1400Sstevel@tonic-gate 1410Sstevel@tonic-gate static int isa_attach(dev_info_t *devi, ddi_attach_cmd_t cmd); 1420Sstevel@tonic-gate 1430Sstevel@tonic-gate /* 1440Sstevel@tonic-gate * Internal isa ctlops support routines 1450Sstevel@tonic-gate */ 1460Sstevel@tonic-gate static int isa_initchild(dev_info_t *child); 1470Sstevel@tonic-gate 1480Sstevel@tonic-gate struct dev_ops isa_ops = { 1490Sstevel@tonic-gate DEVO_REV, /* devo_rev, */ 1500Sstevel@tonic-gate 0, /* refcnt */ 1510Sstevel@tonic-gate ddi_no_info, /* info */ 1520Sstevel@tonic-gate nulldev, /* identify */ 1530Sstevel@tonic-gate nulldev, /* probe */ 1540Sstevel@tonic-gate isa_attach, /* attach */ 1550Sstevel@tonic-gate nodev, /* detach */ 1560Sstevel@tonic-gate nodev, /* reset */ 1570Sstevel@tonic-gate (struct cb_ops *)0, /* driver operations */ 1580Sstevel@tonic-gate &isa_bus_ops /* bus operations */ 1590Sstevel@tonic-gate 1600Sstevel@tonic-gate }; 1610Sstevel@tonic-gate 1620Sstevel@tonic-gate /* 1630Sstevel@tonic-gate * Module linkage information for the kernel. 1640Sstevel@tonic-gate */ 1650Sstevel@tonic-gate 1660Sstevel@tonic-gate static struct modldrv modldrv = { 1670Sstevel@tonic-gate &mod_driverops, /* Type of module. This is ISA bus driver */ 1680Sstevel@tonic-gate "isa nexus driver for 'ISA' %I%", 1690Sstevel@tonic-gate &isa_ops, /* driver ops */ 1700Sstevel@tonic-gate }; 1710Sstevel@tonic-gate 1720Sstevel@tonic-gate static struct modlinkage modlinkage = { 1730Sstevel@tonic-gate MODREV_1, 1740Sstevel@tonic-gate &modldrv, 1750Sstevel@tonic-gate NULL 1760Sstevel@tonic-gate }; 1770Sstevel@tonic-gate 1780Sstevel@tonic-gate int 1790Sstevel@tonic-gate _init(void) 1800Sstevel@tonic-gate { 1810Sstevel@tonic-gate return (mod_install(&modlinkage)); 1820Sstevel@tonic-gate } 1830Sstevel@tonic-gate 1840Sstevel@tonic-gate int 1850Sstevel@tonic-gate _fini(void) 1860Sstevel@tonic-gate { 1870Sstevel@tonic-gate return (mod_remove(&modlinkage)); 1880Sstevel@tonic-gate } 1890Sstevel@tonic-gate 1900Sstevel@tonic-gate int 1910Sstevel@tonic-gate _info(struct modinfo *modinfop) 1920Sstevel@tonic-gate { 1930Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 1940Sstevel@tonic-gate } 1950Sstevel@tonic-gate 1960Sstevel@tonic-gate static int 1970Sstevel@tonic-gate isa_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 1980Sstevel@tonic-gate { 1990Sstevel@tonic-gate int rval; 2000Sstevel@tonic-gate 2010Sstevel@tonic-gate if (cmd != DDI_ATTACH) 2020Sstevel@tonic-gate return (DDI_FAILURE); 2030Sstevel@tonic-gate 2040Sstevel@tonic-gate if ((rval = i_dmae_init(devi)) == DDI_SUCCESS) { 2050Sstevel@tonic-gate ddi_report_dev(devi); 2060Sstevel@tonic-gate /* 2070Sstevel@tonic-gate * Enumerate children -- invoking ACPICA 2080Sstevel@tonic-gate * This is normally in bus_config(), but we need this 2090Sstevel@tonic-gate * to happen earlier to boot. 2100Sstevel@tonic-gate */ 2110Sstevel@tonic-gate isa_alloc_nodes(devi); 2120Sstevel@tonic-gate } 2130Sstevel@tonic-gate return (rval); 2140Sstevel@tonic-gate } 2150Sstevel@tonic-gate 2160Sstevel@tonic-gate static int 2170Sstevel@tonic-gate isa_dma_allochdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_attr_t *dma_attr, 2180Sstevel@tonic-gate int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *handlep) 2190Sstevel@tonic-gate { 2200Sstevel@tonic-gate ddi_dma_attr_merge(dma_attr, &ISA_dma_attr); 2210Sstevel@tonic-gate return (ddi_dma_allochdl(dip, rdip, dma_attr, waitfp, arg, handlep)); 2220Sstevel@tonic-gate } 2230Sstevel@tonic-gate 2240Sstevel@tonic-gate static int 2250Sstevel@tonic-gate isa_dma_mctl(dev_info_t *dip, dev_info_t *rdip, 2260Sstevel@tonic-gate ddi_dma_handle_t handle, enum ddi_dma_ctlops request, 2270Sstevel@tonic-gate off_t *offp, size_t *lenp, caddr_t *objp, uint_t flags) 2280Sstevel@tonic-gate { 2290Sstevel@tonic-gate int rval; 2300Sstevel@tonic-gate ddi_dma_lim_t defalt; 2310Sstevel@tonic-gate int arg = (int)(uintptr_t)objp; 2320Sstevel@tonic-gate 2330Sstevel@tonic-gate switch (request) { 2340Sstevel@tonic-gate 2350Sstevel@tonic-gate case DDI_DMA_E_PROG: 2360Sstevel@tonic-gate return (i_dmae_prog(rdip, (struct ddi_dmae_req *)offp, 2370Sstevel@tonic-gate (ddi_dma_cookie_t *)lenp, arg)); 2380Sstevel@tonic-gate 2390Sstevel@tonic-gate case DDI_DMA_E_ACQUIRE: 2400Sstevel@tonic-gate return (i_dmae_acquire(rdip, arg, (int(*)(caddr_t))offp, 2410Sstevel@tonic-gate (caddr_t)lenp)); 2420Sstevel@tonic-gate 2430Sstevel@tonic-gate case DDI_DMA_E_FREE: 2440Sstevel@tonic-gate return (i_dmae_free(rdip, arg)); 2450Sstevel@tonic-gate 2460Sstevel@tonic-gate case DDI_DMA_E_STOP: 2470Sstevel@tonic-gate i_dmae_stop(rdip, arg); 2480Sstevel@tonic-gate return (DDI_SUCCESS); 2490Sstevel@tonic-gate 2500Sstevel@tonic-gate case DDI_DMA_E_ENABLE: 2510Sstevel@tonic-gate i_dmae_enable(rdip, arg); 2520Sstevel@tonic-gate return (DDI_SUCCESS); 2530Sstevel@tonic-gate 2540Sstevel@tonic-gate case DDI_DMA_E_DISABLE: 2550Sstevel@tonic-gate i_dmae_disable(rdip, arg); 2560Sstevel@tonic-gate return (DDI_SUCCESS); 2570Sstevel@tonic-gate 2580Sstevel@tonic-gate case DDI_DMA_E_GETCNT: 2590Sstevel@tonic-gate i_dmae_get_chan_stat(rdip, arg, NULL, (int *)lenp); 2600Sstevel@tonic-gate return (DDI_SUCCESS); 2610Sstevel@tonic-gate 2620Sstevel@tonic-gate case DDI_DMA_E_SWSETUP: 2630Sstevel@tonic-gate return (i_dmae_swsetup(rdip, (struct ddi_dmae_req *)offp, 2640Sstevel@tonic-gate (ddi_dma_cookie_t *)lenp, arg)); 2650Sstevel@tonic-gate 2660Sstevel@tonic-gate case DDI_DMA_E_SWSTART: 2670Sstevel@tonic-gate i_dmae_swstart(rdip, arg); 2680Sstevel@tonic-gate return (DDI_SUCCESS); 2690Sstevel@tonic-gate 2700Sstevel@tonic-gate case DDI_DMA_E_GETLIM: 2710Sstevel@tonic-gate bcopy(&ISA_dma_limits, objp, sizeof (ddi_dma_lim_t)); 2720Sstevel@tonic-gate return (DDI_SUCCESS); 2730Sstevel@tonic-gate 2740Sstevel@tonic-gate case DDI_DMA_E_GETATTR: 2750Sstevel@tonic-gate bcopy(&ISA_dma_attr, objp, sizeof (ddi_dma_attr_t)); 2760Sstevel@tonic-gate return (DDI_SUCCESS); 2770Sstevel@tonic-gate 2780Sstevel@tonic-gate case DDI_DMA_E_1STPTY: 2790Sstevel@tonic-gate { 2800Sstevel@tonic-gate struct ddi_dmae_req req1stpty = 2810Sstevel@tonic-gate { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 2820Sstevel@tonic-gate if (arg == 0) { 2830Sstevel@tonic-gate req1stpty.der_command = DMAE_CMD_TRAN; 2840Sstevel@tonic-gate req1stpty.der_trans = DMAE_TRANS_DMND; 2850Sstevel@tonic-gate } else { 2860Sstevel@tonic-gate req1stpty.der_trans = DMAE_TRANS_CSCD; 2870Sstevel@tonic-gate } 2880Sstevel@tonic-gate return (i_dmae_prog(rdip, &req1stpty, NULL, arg)); 2890Sstevel@tonic-gate } 2900Sstevel@tonic-gate 2910Sstevel@tonic-gate case DDI_DMA_IOPB_ALLOC: /* get contiguous DMA-able memory */ 2920Sstevel@tonic-gate case DDI_DMA_SMEM_ALLOC: 2930Sstevel@tonic-gate if (!offp) { 2940Sstevel@tonic-gate defalt = ISA_dma_limits; 2950Sstevel@tonic-gate offp = (off_t *)&defalt; 2960Sstevel@tonic-gate } 2970Sstevel@tonic-gate /*FALLTHROUGH*/ 2980Sstevel@tonic-gate default: 2990Sstevel@tonic-gate rval = ddi_dma_mctl(dip, rdip, handle, request, offp, 3000Sstevel@tonic-gate lenp, objp, flags); 3010Sstevel@tonic-gate } 3020Sstevel@tonic-gate return (rval); 3030Sstevel@tonic-gate } 3040Sstevel@tonic-gate 3050Sstevel@tonic-gate /* 3060Sstevel@tonic-gate * Check if driver should be treated as an old pre 2.6 driver 3070Sstevel@tonic-gate */ 3080Sstevel@tonic-gate static int 3090Sstevel@tonic-gate old_driver(dev_info_t *dip) 3100Sstevel@tonic-gate { 3110Sstevel@tonic-gate extern int ignore_hardware_nodes; /* force flag from ddi_impl.c */ 3120Sstevel@tonic-gate 3130Sstevel@tonic-gate if (ndi_dev_is_persistent_node(dip)) { 3140Sstevel@tonic-gate if (ignore_hardware_nodes) 3150Sstevel@tonic-gate return (1); 3160Sstevel@tonic-gate if (ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 3170Sstevel@tonic-gate "ignore-hardware-nodes", -1) != -1) 3180Sstevel@tonic-gate return (1); 3190Sstevel@tonic-gate } 3200Sstevel@tonic-gate return (0); 3210Sstevel@tonic-gate } 3220Sstevel@tonic-gate 3230Sstevel@tonic-gate typedef struct { 3240Sstevel@tonic-gate uint32_t phys_hi; 3250Sstevel@tonic-gate uint32_t phys_lo; 3260Sstevel@tonic-gate uint32_t size; 3270Sstevel@tonic-gate } isa_regs_t; 3280Sstevel@tonic-gate 3290Sstevel@tonic-gate /* 3300Sstevel@tonic-gate * Return non-zero if device in tree is a PnP isa device 3310Sstevel@tonic-gate */ 3320Sstevel@tonic-gate static int 3330Sstevel@tonic-gate is_pnpisa(dev_info_t *dip) 3340Sstevel@tonic-gate { 3350Sstevel@tonic-gate isa_regs_t *isa_regs; 3360Sstevel@tonic-gate int proplen, pnpisa; 3370Sstevel@tonic-gate 3380Sstevel@tonic-gate if (ndi_dev_is_persistent_node(dip) == 0) 3390Sstevel@tonic-gate return (0); 3400Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg", 3410Sstevel@tonic-gate (caddr_t)&isa_regs, &proplen) != DDI_PROP_SUCCESS) { 3420Sstevel@tonic-gate return (0); 3430Sstevel@tonic-gate } 3440Sstevel@tonic-gate pnpisa = isa_regs[0].phys_hi & 0x80000000; 3450Sstevel@tonic-gate /* 3460Sstevel@tonic-gate * free the memory allocated by ddi_getlongprop(). 3470Sstevel@tonic-gate */ 3480Sstevel@tonic-gate kmem_free(isa_regs, proplen); 3490Sstevel@tonic-gate if (pnpisa) 3500Sstevel@tonic-gate return (1); 3510Sstevel@tonic-gate else 3520Sstevel@tonic-gate return (0); 3530Sstevel@tonic-gate } 3540Sstevel@tonic-gate 3550Sstevel@tonic-gate /*ARGSUSED*/ 3560Sstevel@tonic-gate static int 3570Sstevel@tonic-gate isa_ctlops(dev_info_t *dip, dev_info_t *rdip, 3580Sstevel@tonic-gate ddi_ctl_enum_t ctlop, void *arg, void *result) 3590Sstevel@tonic-gate { 3600Sstevel@tonic-gate switch (ctlop) { 3610Sstevel@tonic-gate case DDI_CTLOPS_REPORTDEV: 3620Sstevel@tonic-gate if (rdip == (dev_info_t *)0) 3630Sstevel@tonic-gate return (DDI_FAILURE); 3640Sstevel@tonic-gate cmn_err(CE_CONT, "?ISA-device: %s%d\n", 3650Sstevel@tonic-gate ddi_driver_name(rdip), ddi_get_instance(rdip)); 3660Sstevel@tonic-gate return (DDI_SUCCESS); 3670Sstevel@tonic-gate 3680Sstevel@tonic-gate case DDI_CTLOPS_INITCHILD: 3690Sstevel@tonic-gate /* 3700Sstevel@tonic-gate * older drivers aren't expecting the "standard" device 3710Sstevel@tonic-gate * node format used by the hardware nodes. these drivers 3720Sstevel@tonic-gate * only expect their own properties set in their driver.conf 3730Sstevel@tonic-gate * files. so they tell us not to call them with hardware 3740Sstevel@tonic-gate * nodes by setting the property "ignore-hardware-nodes". 3750Sstevel@tonic-gate */ 3760Sstevel@tonic-gate if (old_driver((dev_info_t *)arg)) { 3770Sstevel@tonic-gate return (DDI_NOT_WELL_FORMED); 3780Sstevel@tonic-gate } 3790Sstevel@tonic-gate 3800Sstevel@tonic-gate return (isa_initchild((dev_info_t *)arg)); 3810Sstevel@tonic-gate 3820Sstevel@tonic-gate case DDI_CTLOPS_UNINITCHILD: 3830Sstevel@tonic-gate impl_ddi_sunbus_removechild((dev_info_t *)arg); 3840Sstevel@tonic-gate return (DDI_SUCCESS); 3850Sstevel@tonic-gate 3860Sstevel@tonic-gate case DDI_CTLOPS_SIDDEV: 3870Sstevel@tonic-gate /* 3880Sstevel@tonic-gate * All ISA devices need to do confirming probes 3890Sstevel@tonic-gate * unless they are PnP ISA. 3900Sstevel@tonic-gate */ 3910Sstevel@tonic-gate if (is_pnpisa(dip)) 3920Sstevel@tonic-gate return (DDI_SUCCESS); 3930Sstevel@tonic-gate else 3940Sstevel@tonic-gate return (DDI_FAILURE); 3950Sstevel@tonic-gate 3960Sstevel@tonic-gate default: 3970Sstevel@tonic-gate return (ddi_ctlops(dip, rdip, ctlop, arg, result)); 3980Sstevel@tonic-gate } 3990Sstevel@tonic-gate } 4000Sstevel@tonic-gate 4010Sstevel@tonic-gate static void 4020Sstevel@tonic-gate isa_vendor(uint32_t id, char *vendor) 4030Sstevel@tonic-gate { 4040Sstevel@tonic-gate vendor[0] = '@' + ((id >> 26) & 0x1f); 4050Sstevel@tonic-gate vendor[1] = '@' + ((id >> 21) & 0x1f); 4060Sstevel@tonic-gate vendor[2] = '@' + ((id >> 16) & 0x1f); 4070Sstevel@tonic-gate vendor[3] = 0; 4080Sstevel@tonic-gate } 4090Sstevel@tonic-gate 4100Sstevel@tonic-gate /* 4110Sstevel@tonic-gate * Name a child 4120Sstevel@tonic-gate */ 4130Sstevel@tonic-gate static int 4140Sstevel@tonic-gate isa_name_child(dev_info_t *child, char *name, int namelen) 4150Sstevel@tonic-gate { 4160Sstevel@tonic-gate char vendor[8]; 4170Sstevel@tonic-gate int device; 4180Sstevel@tonic-gate uint32_t serial; 4190Sstevel@tonic-gate int func; 4200Sstevel@tonic-gate int bustype; 4210Sstevel@tonic-gate uint32_t base; 4220Sstevel@tonic-gate int proplen; 4230Sstevel@tonic-gate int pnpisa = 0; 4240Sstevel@tonic-gate isa_regs_t *isa_regs; 4250Sstevel@tonic-gate 4260Sstevel@tonic-gate void make_ddi_ppd(dev_info_t *, struct ddi_parent_private_data **); 4270Sstevel@tonic-gate 4280Sstevel@tonic-gate /* 4290Sstevel@tonic-gate * older drivers aren't expecting the "standard" device 4300Sstevel@tonic-gate * node format used by the hardware nodes. these drivers 4310Sstevel@tonic-gate * only expect their own properties set in their driver.conf 4320Sstevel@tonic-gate * files. so they tell us not to call them with hardware 4330Sstevel@tonic-gate * nodes by setting the property "ignore-hardware-nodes". 4340Sstevel@tonic-gate */ 4350Sstevel@tonic-gate if (old_driver(child)) 4360Sstevel@tonic-gate return (DDI_FAILURE); 4370Sstevel@tonic-gate 4380Sstevel@tonic-gate /* 4390Sstevel@tonic-gate * Fill in parent-private data 4400Sstevel@tonic-gate */ 4410Sstevel@tonic-gate if (ddi_get_parent_data(child) == NULL) { 4420Sstevel@tonic-gate struct ddi_parent_private_data *pdptr; 4430Sstevel@tonic-gate make_ddi_ppd(child, &pdptr); 4440Sstevel@tonic-gate ddi_set_parent_data(child, pdptr); 4450Sstevel@tonic-gate } 4460Sstevel@tonic-gate 4470Sstevel@tonic-gate if (ndi_dev_is_persistent_node(child) == 0) { 4480Sstevel@tonic-gate /* 4490Sstevel@tonic-gate * For .conf nodes, generate name from parent private data 4500Sstevel@tonic-gate */ 4510Sstevel@tonic-gate name[0] = '\0'; 4520Sstevel@tonic-gate if (sparc_pd_getnreg(child) > 0) { 4530Sstevel@tonic-gate (void) snprintf(name, namelen, "%x,%x", 4540Sstevel@tonic-gate (uint_t)sparc_pd_getreg(child, 0)->regspec_bustype, 4550Sstevel@tonic-gate (uint_t)sparc_pd_getreg(child, 0)->regspec_addr); 4560Sstevel@tonic-gate } 4570Sstevel@tonic-gate return (DDI_SUCCESS); 4580Sstevel@tonic-gate } 4590Sstevel@tonic-gate 4600Sstevel@tonic-gate /* 4610Sstevel@tonic-gate * For hw nodes, look up "reg" property 4620Sstevel@tonic-gate */ 4630Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "reg", 4640Sstevel@tonic-gate (caddr_t)&isa_regs, &proplen) != DDI_PROP_SUCCESS) { 4650Sstevel@tonic-gate return (DDI_FAILURE); 4660Sstevel@tonic-gate } 4670Sstevel@tonic-gate 4680Sstevel@tonic-gate /* 4690Sstevel@tonic-gate * extract the device identifications 4700Sstevel@tonic-gate */ 4710Sstevel@tonic-gate pnpisa = isa_regs[0].phys_hi & 0x80000000; 4720Sstevel@tonic-gate if (pnpisa) { 4730Sstevel@tonic-gate isa_vendor(isa_regs[0].phys_hi, vendor); 4740Sstevel@tonic-gate device = isa_regs[0].phys_hi & 0xffff; 4750Sstevel@tonic-gate serial = isa_regs[0].phys_lo; 4760Sstevel@tonic-gate func = (isa_regs[0].size >> 24) & 0xff; 4770Sstevel@tonic-gate if (func != 0) 4780Sstevel@tonic-gate (void) snprintf(name, namelen, "pnp%s,%04x,%x,%x", 4790Sstevel@tonic-gate vendor, device, serial, func); 4800Sstevel@tonic-gate else 4810Sstevel@tonic-gate (void) snprintf(name, namelen, "pnp%s,%04x,%x", 4820Sstevel@tonic-gate vendor, device, serial); 4830Sstevel@tonic-gate } else { 4840Sstevel@tonic-gate bustype = isa_regs[0].phys_hi; 4850Sstevel@tonic-gate base = isa_regs[0].phys_lo; 4860Sstevel@tonic-gate (void) sprintf(name, "%x,%x", bustype, base); 4870Sstevel@tonic-gate } 4880Sstevel@tonic-gate 4890Sstevel@tonic-gate /* 4900Sstevel@tonic-gate * free the memory allocated by ddi_getlongprop(). 4910Sstevel@tonic-gate */ 4920Sstevel@tonic-gate kmem_free(isa_regs, proplen); 4930Sstevel@tonic-gate 4940Sstevel@tonic-gate return (DDI_SUCCESS); 4950Sstevel@tonic-gate } 4960Sstevel@tonic-gate 4970Sstevel@tonic-gate static int 4980Sstevel@tonic-gate isa_initchild(dev_info_t *child) 4990Sstevel@tonic-gate { 5000Sstevel@tonic-gate char name[80]; 5010Sstevel@tonic-gate 5020Sstevel@tonic-gate if (isa_name_child(child, name, 80) != DDI_SUCCESS) 5030Sstevel@tonic-gate return (DDI_FAILURE); 5040Sstevel@tonic-gate ddi_set_name_addr(child, name); 5050Sstevel@tonic-gate 5060Sstevel@tonic-gate if (ndi_dev_is_persistent_node(child) != 0) 5070Sstevel@tonic-gate return (DDI_SUCCESS); 5080Sstevel@tonic-gate 5090Sstevel@tonic-gate /* 5100Sstevel@tonic-gate * This is a .conf node, try merge properties onto a 5110Sstevel@tonic-gate * hw node with the same name. 5120Sstevel@tonic-gate */ 5130Sstevel@tonic-gate if (ndi_merge_node(child, isa_name_child) == DDI_SUCCESS) { 5140Sstevel@tonic-gate /* 5150Sstevel@tonic-gate * Return failure to remove node 5160Sstevel@tonic-gate */ 5170Sstevel@tonic-gate impl_ddi_sunbus_removechild(child); 5180Sstevel@tonic-gate return (DDI_FAILURE); 5190Sstevel@tonic-gate } 5200Sstevel@tonic-gate /* 5210Sstevel@tonic-gate * Cannot merge node, permit pseudo children 5220Sstevel@tonic-gate */ 5230Sstevel@tonic-gate return (DDI_SUCCESS); 5240Sstevel@tonic-gate } 5250Sstevel@tonic-gate 5260Sstevel@tonic-gate /* 5270Sstevel@tonic-gate * called when ACPI enumeration is not used 5280Sstevel@tonic-gate */ 5290Sstevel@tonic-gate static void 5300Sstevel@tonic-gate add_known_used_resources(void) 5310Sstevel@tonic-gate { 5320Sstevel@tonic-gate /* needs to be in increasing order */ 5330Sstevel@tonic-gate int intr[] = {0x1, 0x3, 0x4, 0x6, 0x7, 0xc}; 5340Sstevel@tonic-gate int dma[] = {0x2}; 5350Sstevel@tonic-gate int io[] = {0x60, 0x1, 0x64, 0x1, 0x2f8, 0x8, 0x378, 0x8, 0x3f0, 0x10, 5360Sstevel@tonic-gate 0x778, 0x4}; 5370Sstevel@tonic-gate dev_info_t *usedrdip; 5380Sstevel@tonic-gate 5390Sstevel@tonic-gate usedrdip = ddi_find_devinfo(USED_RESOURCES, -1, 0); 5400Sstevel@tonic-gate 5410Sstevel@tonic-gate if (usedrdip == NULL) { 5420Sstevel@tonic-gate (void) ndi_devi_alloc_sleep(ddi_root_node(), USED_RESOURCES, 543789Sahrens (pnode_t)DEVI_SID_NODEID, &usedrdip); 5440Sstevel@tonic-gate } 5450Sstevel@tonic-gate 5460Sstevel@tonic-gate (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, usedrdip, 5470Sstevel@tonic-gate "interrupts", (int *)intr, (int)(sizeof (intr) / sizeof (int))); 5480Sstevel@tonic-gate (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, usedrdip, 5490Sstevel@tonic-gate "io-space", (int *)io, (int)(sizeof (io) / sizeof (int))); 5500Sstevel@tonic-gate (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, usedrdip, 5510Sstevel@tonic-gate "dma-channels", (int *)dma, (int)(sizeof (dma) / sizeof (int))); 5520Sstevel@tonic-gate (void) ndi_devi_bind_driver(usedrdip, 0); 5530Sstevel@tonic-gate 5540Sstevel@tonic-gate } 5550Sstevel@tonic-gate 5560Sstevel@tonic-gate static void 5570Sstevel@tonic-gate isa_alloc_nodes(dev_info_t *isa_dip) 5580Sstevel@tonic-gate { 5590Sstevel@tonic-gate static int alloced = 0; 5600Sstevel@tonic-gate int circ, i; 5610Sstevel@tonic-gate dev_info_t *xdip; 5620Sstevel@tonic-gate 5630Sstevel@tonic-gate /* hard coded isa stuff */ 5640Sstevel@tonic-gate struct regspec asy_regs[] = { 5650Sstevel@tonic-gate {1, 0x3f8, 0x8}, 5660Sstevel@tonic-gate {1, 0x2f8, 0x8} 5670Sstevel@tonic-gate }; 5680Sstevel@tonic-gate int asy_intrs[] = {0x4, 0x3}; 5690Sstevel@tonic-gate 5700Sstevel@tonic-gate struct regspec i8042_regs[] = { 5710Sstevel@tonic-gate {1, 0x60, 0x1}, 5720Sstevel@tonic-gate {1, 0x64, 0x1} 5730Sstevel@tonic-gate }; 5740Sstevel@tonic-gate int i8042_intrs[] = {0x1, 0xc}; 5750Sstevel@tonic-gate char *acpi_prop; 5760Sstevel@tonic-gate int acpi_enum = 1; /* ACPI is default to be on */ 5770Sstevel@tonic-gate 5780Sstevel@tonic-gate if (alloced) 5790Sstevel@tonic-gate return; 5800Sstevel@tonic-gate 5810Sstevel@tonic-gate ndi_devi_enter(isa_dip, &circ); 5820Sstevel@tonic-gate if (alloced) { /* just in case we are multi-threaded */ 5830Sstevel@tonic-gate ndi_devi_exit(isa_dip, circ); 5840Sstevel@tonic-gate return; 5850Sstevel@tonic-gate } 5860Sstevel@tonic-gate alloced = 1; 5870Sstevel@tonic-gate 5880Sstevel@tonic-gate if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(), 5890Sstevel@tonic-gate DDI_PROP_DONTPASS, "acpi-enum", &acpi_prop) == DDI_PROP_SUCCESS) { 5900Sstevel@tonic-gate acpi_enum = strcmp("off", acpi_prop); 5910Sstevel@tonic-gate ddi_prop_free(acpi_prop); 5920Sstevel@tonic-gate } 5930Sstevel@tonic-gate 5940Sstevel@tonic-gate if (acpi_enum) { 5950Sstevel@tonic-gate if (acpi_isa_device_enum(isa_dip)) { 5960Sstevel@tonic-gate ndi_devi_exit(isa_dip, circ); 5970Sstevel@tonic-gate if (isa_resource_setup() != NDI_SUCCESS) { 5980Sstevel@tonic-gate cmn_err(CE_WARN, "isa nexus: isa " 5990Sstevel@tonic-gate "resource setup failed"); 6000Sstevel@tonic-gate } 601*2007Sml40262 602*2007Sml40262 /* serial ports? */ 603*2007Sml40262 enumerate_BIOS_serial(isa_dip); 6040Sstevel@tonic-gate return; 6050Sstevel@tonic-gate } 6060Sstevel@tonic-gate cmn_err(CE_NOTE, "!Solaris did not detect ACPI BIOS"); 6070Sstevel@tonic-gate } 6080Sstevel@tonic-gate cmn_err(CE_NOTE, "!ACPI is off"); 6090Sstevel@tonic-gate 6100Sstevel@tonic-gate /* serial ports */ 6110Sstevel@tonic-gate for (i = 0; i < 2; i++) { 6120Sstevel@tonic-gate ndi_devi_alloc_sleep(isa_dip, "asy", 613789Sahrens (pnode_t)DEVI_SID_NODEID, &xdip); 6140Sstevel@tonic-gate (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, xdip, 6150Sstevel@tonic-gate "reg", (int *)&asy_regs[i], 3); 6160Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, xdip, 6170Sstevel@tonic-gate "interrupts", asy_intrs[i]); 6180Sstevel@tonic-gate (void) ndi_devi_bind_driver(xdip, 0); 6190Sstevel@tonic-gate } 6200Sstevel@tonic-gate 6210Sstevel@tonic-gate /* i8042 node */ 6220Sstevel@tonic-gate ndi_devi_alloc_sleep(isa_dip, "i8042", 623789Sahrens (pnode_t)DEVI_SID_NODEID, &xdip); 6240Sstevel@tonic-gate (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, xdip, 6250Sstevel@tonic-gate "reg", (int *)i8042_regs, 6); 6260Sstevel@tonic-gate (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, xdip, 6270Sstevel@tonic-gate "interrupts", (int *)i8042_intrs, 2); 6280Sstevel@tonic-gate (void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip, 6290Sstevel@tonic-gate "unit-address", "1,60"); 6300Sstevel@tonic-gate (void) ndi_devi_bind_driver(xdip, 0); 6310Sstevel@tonic-gate 6320Sstevel@tonic-gate add_known_used_resources(); 6330Sstevel@tonic-gate 6340Sstevel@tonic-gate ndi_devi_exit(isa_dip, circ); 6350Sstevel@tonic-gate 6360Sstevel@tonic-gate } 637*2007Sml40262 638*2007Sml40262 /* 639*2007Sml40262 * On some machines, serial port 2 isn't listed in the ACPI table. 640*2007Sml40262 * This function goes through the BIOS data area and makes sure all 641*2007Sml40262 * the serial ports there are in the dev_info tree. If any are missing, 642*2007Sml40262 * this function will add them. 643*2007Sml40262 */ 644*2007Sml40262 645*2007Sml40262 static int num_BIOS_serial = 2; /* number of BIOS serial ports to look at */ 646*2007Sml40262 647*2007Sml40262 static void 648*2007Sml40262 enumerate_BIOS_serial(dev_info_t *isa_dip) 649*2007Sml40262 { 650*2007Sml40262 ushort_t *bios_data; 651*2007Sml40262 int i; 652*2007Sml40262 dev_info_t *xdip; 653*2007Sml40262 int found; 654*2007Sml40262 int ret; 655*2007Sml40262 struct regspec *tmpregs; 656*2007Sml40262 int tmpregs_len; 657*2007Sml40262 static struct regspec tmp_asy_regs[] = { 658*2007Sml40262 {1, 0x3f8, 0x8}, 659*2007Sml40262 }; 660*2007Sml40262 static int default_asy_intrs[] = { 4, 3, 4, 3 }; 661*2007Sml40262 static size_t size = 4; 662*2007Sml40262 663*2007Sml40262 /* 664*2007Sml40262 * The first four 2-byte quantities of the BIOS data area contain 665*2007Sml40262 * the base I/O addresses of the first four serial ports. 666*2007Sml40262 */ 667*2007Sml40262 bios_data = (ushort_t *)psm_map_new((paddr_t)BIOS_DATA_AREA, size, 668*2007Sml40262 PSM_PROT_READ); 669*2007Sml40262 for (i = 0; i < num_BIOS_serial; i++) { 670*2007Sml40262 if (bios_data[i] == 0) { 671*2007Sml40262 /* no COM[i]: port */ 672*2007Sml40262 continue; 673*2007Sml40262 } 674*2007Sml40262 675*2007Sml40262 /* Look for it in the dev_info tree */ 676*2007Sml40262 found = 0; 677*2007Sml40262 for (xdip = ddi_get_child(isa_dip); xdip != NULL; 678*2007Sml40262 xdip = ddi_get_next_sibling(xdip)) { 679*2007Sml40262 if (strncmp(ddi_node_name(xdip), "asy", 3) != 0) { 680*2007Sml40262 /* skip non asy */ 681*2007Sml40262 continue; 682*2007Sml40262 } 683*2007Sml40262 684*2007Sml40262 /* Match by addr */ 685*2007Sml40262 ret = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, xdip, 686*2007Sml40262 DDI_PROP_DONTPASS, "reg", (int **)&tmpregs, 687*2007Sml40262 (uint_t *)&tmpregs_len); 688*2007Sml40262 if (ret != DDI_PROP_SUCCESS) { 689*2007Sml40262 /* error */ 690*2007Sml40262 continue; 691*2007Sml40262 } 692*2007Sml40262 693*2007Sml40262 if (tmpregs->regspec_addr == bios_data[i]) 694*2007Sml40262 found = 1; 695*2007Sml40262 696*2007Sml40262 /* 697*2007Sml40262 * Free the memory allocated by 698*2007Sml40262 * ddi_prop_lookup_int_array(). 699*2007Sml40262 */ 700*2007Sml40262 ddi_prop_free(tmpregs); 701*2007Sml40262 } 702*2007Sml40262 703*2007Sml40262 /* If not found, then add it */ 704*2007Sml40262 if (!found) { 705*2007Sml40262 ndi_devi_alloc_sleep(isa_dip, "asy", 706*2007Sml40262 (pnode_t)DEVI_SID_NODEID, &xdip); 707*2007Sml40262 (void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip, 708*2007Sml40262 "compatible", "PNP0500"); 709*2007Sml40262 /* This should be gotten from master file: */ 710*2007Sml40262 (void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip, 711*2007Sml40262 "model", "Standard PC COM port"); 712*2007Sml40262 tmp_asy_regs[0].regspec_addr = bios_data[i]; 713*2007Sml40262 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, xdip, 714*2007Sml40262 "reg", (int *)&tmp_asy_regs[0], 3); 715*2007Sml40262 (void) ndi_prop_update_int(DDI_DEV_T_NONE, xdip, 716*2007Sml40262 "interrupts", default_asy_intrs[i]); 717*2007Sml40262 (void) ndi_devi_bind_driver(xdip, 0); 718*2007Sml40262 } 719*2007Sml40262 } 720*2007Sml40262 721*2007Sml40262 psm_unmap((caddr_t)bios_data, size); 722*2007Sml40262 } 723