17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5a9fb0ae8Srw * Common Development and Distribution License (the "License"). 6a9fb0ae8Srw * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 2211c2b4c0Srw * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate /* 277c478bd9Sstevel@tonic-gate * PCMCIA NEXUS 287c478bd9Sstevel@tonic-gate * The PCMCIA module is a generalized interface for 297c478bd9Sstevel@tonic-gate * implementing PCMCIA nexus drivers. It preserves 307c478bd9Sstevel@tonic-gate * the logical socket name space while allowing multiple 317c478bd9Sstevel@tonic-gate * instances of the hardware to be properly represented 327c478bd9Sstevel@tonic-gate * in the device tree. 337c478bd9Sstevel@tonic-gate * 347c478bd9Sstevel@tonic-gate * The nexus also exports events to an event manager 357c478bd9Sstevel@tonic-gate * driver if it has registered. 367c478bd9Sstevel@tonic-gate */ 377c478bd9Sstevel@tonic-gate 387c478bd9Sstevel@tonic-gate #include <sys/types.h> 397c478bd9Sstevel@tonic-gate #include <sys/systm.h> 407c478bd9Sstevel@tonic-gate #include <sys/user.h> 417c478bd9Sstevel@tonic-gate #include <sys/buf.h> 427c478bd9Sstevel@tonic-gate #include <sys/file.h> 437c478bd9Sstevel@tonic-gate #include <sys/uio.h> 447c478bd9Sstevel@tonic-gate #include <sys/conf.h> 457c478bd9Sstevel@tonic-gate #include <sys/stat.h> 467c478bd9Sstevel@tonic-gate #include <sys/autoconf.h> 477c478bd9Sstevel@tonic-gate #include <sys/vtoc.h> 487c478bd9Sstevel@tonic-gate #include <sys/dkio.h> 497c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 507c478bd9Sstevel@tonic-gate #include <sys/debug.h> 517c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 527c478bd9Sstevel@tonic-gate #include <sys/sunndi.h> 537c478bd9Sstevel@tonic-gate #include <sys/cred.h> 547c478bd9Sstevel@tonic-gate #include <sys/kstat.h> 557c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 567c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 577c478bd9Sstevel@tonic-gate #include <sys/kobj.h> 587c478bd9Sstevel@tonic-gate #include <sys/callb.h> 597c478bd9Sstevel@tonic-gate #include <sys/param.h> 607c478bd9Sstevel@tonic-gate #include <sys/thread.h> 617c478bd9Sstevel@tonic-gate #include <sys/proc.h> 627c478bd9Sstevel@tonic-gate 637c478bd9Sstevel@tonic-gate #include <sys/pctypes.h> 647c478bd9Sstevel@tonic-gate #include <sys/pcmcia.h> 657c478bd9Sstevel@tonic-gate #include <sys/sservice.h> 667c478bd9Sstevel@tonic-gate #include <pcmcia/sys/cs_types.h> 677c478bd9Sstevel@tonic-gate #include <pcmcia/sys/cis.h> 687c478bd9Sstevel@tonic-gate #include <pcmcia/sys/cis_handlers.h> 697c478bd9Sstevel@tonic-gate #include <pcmcia/sys/cs.h> 707c478bd9Sstevel@tonic-gate #include <pcmcia/sys/cs_priv.h> 717c478bd9Sstevel@tonic-gate 727c478bd9Sstevel@tonic-gate #ifdef sparc 737c478bd9Sstevel@tonic-gate #include <sys/ddi_subrdefs.h> 747a364d25Sschwartz 757a364d25Sschwartz #elif defined(__x86) || defined(__amd64) 767a364d25Sschwartz #include <sys/mach_intr.h> 777c478bd9Sstevel@tonic-gate #endif 787c478bd9Sstevel@tonic-gate 797c478bd9Sstevel@tonic-gate #undef SocketServices 807c478bd9Sstevel@tonic-gate 817c478bd9Sstevel@tonic-gate /* some bus specific stuff */ 827c478bd9Sstevel@tonic-gate 837c478bd9Sstevel@tonic-gate /* need PCI regspec size for worst case at present */ 847c478bd9Sstevel@tonic-gate #include <sys/pci.h> 857c478bd9Sstevel@tonic-gate 867c478bd9Sstevel@tonic-gate typedef struct pcmcia_logical_socket { 877c478bd9Sstevel@tonic-gate int ls_socket; /* adapter's socket number */ 887c478bd9Sstevel@tonic-gate uint32_t ls_flags; 897c478bd9Sstevel@tonic-gate struct pcmcia_adapter *ls_adapter; 907c478bd9Sstevel@tonic-gate pcmcia_if_t *ls_if; 917c478bd9Sstevel@tonic-gate dev_info_t *ls_sockdrv; 927c478bd9Sstevel@tonic-gate dev_info_t *ls_dip[PCMCIA_MAX_FUNCTIONS]; 937c478bd9Sstevel@tonic-gate dev_info_t *ls_mfintr_dip; 947c478bd9Sstevel@tonic-gate int ls_functions; 957c478bd9Sstevel@tonic-gate uint32_t ls_cs_events; 967c478bd9Sstevel@tonic-gate uint32_t ls_intr_pri; 977c478bd9Sstevel@tonic-gate uint32_t ls_intr_vec; 987c478bd9Sstevel@tonic-gate int ls_intrrefs; 997c478bd9Sstevel@tonic-gate struct intrspec ls_intrspec; /* MFC intrspec */ 1007c478bd9Sstevel@tonic-gate inthandler_t *ls_inthandlers; /* for multifunction cards */ 1017c478bd9Sstevel@tonic-gate ddi_iblock_cookie_t ls_iblk; 1027c478bd9Sstevel@tonic-gate ddi_idevice_cookie_t ls_idev; 1037c478bd9Sstevel@tonic-gate kmutex_t ls_ilock; 1047c478bd9Sstevel@tonic-gate int ls_error; /* error for CS return */ 1057c478bd9Sstevel@tonic-gate } pcmcia_logical_socket_t; 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate /* 1087c478bd9Sstevel@tonic-gate * entry points used by the true nexus 1097c478bd9Sstevel@tonic-gate */ 1107c478bd9Sstevel@tonic-gate int pcmcia_detach(dev_info_t *, ddi_detach_cmd_t); 1117c478bd9Sstevel@tonic-gate int pcmcia_ctlops(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, void *, void *); 1127c478bd9Sstevel@tonic-gate int pcmcia_prop_op(dev_t, dev_info_t *, dev_info_t *, ddi_prop_op_t, 1137c478bd9Sstevel@tonic-gate int, char *, caddr_t, int *); 1147c478bd9Sstevel@tonic-gate void pcmcia_set_assigned(dev_info_t *, int, ra_return_t *); 1157c478bd9Sstevel@tonic-gate int pcmcia_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op, 1167c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, void *result); 1177c478bd9Sstevel@tonic-gate 1187c478bd9Sstevel@tonic-gate /* 1197c478bd9Sstevel@tonic-gate * prototypes used internally by the nexus and sometimes Card Services 1207c478bd9Sstevel@tonic-gate */ 1217c478bd9Sstevel@tonic-gate int SocketServices(int function, ...); 1227c478bd9Sstevel@tonic-gate 1237c478bd9Sstevel@tonic-gate 1247c478bd9Sstevel@tonic-gate void *CISParser(int function, ...); 1257c478bd9Sstevel@tonic-gate extern void *(*cis_parser)(int, ...); 1267c478bd9Sstevel@tonic-gate 1277c478bd9Sstevel@tonic-gate struct regspec *pcmcia_cons_regspec(dev_info_t *, int, uchar_t *, 1287c478bd9Sstevel@tonic-gate ra_return_t *); 1297c478bd9Sstevel@tonic-gate 1307c478bd9Sstevel@tonic-gate static int (*pcmcia_card_services)(int, ...) = NULL; 1317c478bd9Sstevel@tonic-gate 1327c478bd9Sstevel@tonic-gate /* 1337c478bd9Sstevel@tonic-gate * variables used in the logical/physical mappings 1347c478bd9Sstevel@tonic-gate * that the nexus common code maintains. 1357c478bd9Sstevel@tonic-gate */ 1367c478bd9Sstevel@tonic-gate struct pcmcia_adapter *pcmcia_adapters[PCMCIA_MAX_ADAPTERS]; 1377c478bd9Sstevel@tonic-gate int pcmcia_num_adapters; 1387c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t *pcmcia_sockets[PCMCIA_MAX_SOCKETS]; 1397c478bd9Sstevel@tonic-gate int pcmcia_num_sockets; 1407c478bd9Sstevel@tonic-gate pcmcia_logical_window_t *pcmcia_windows[PCMCIA_MAX_WINDOWS]; 1417c478bd9Sstevel@tonic-gate int pcmcia_num_windows; 1427c478bd9Sstevel@tonic-gate struct power_entry pcmcia_power_table[PCMCIA_MAX_POWER]; 1437c478bd9Sstevel@tonic-gate int pcmcia_num_power; 1447c478bd9Sstevel@tonic-gate 1457c478bd9Sstevel@tonic-gate struct pcmcia_mif *pcmcia_mif_handlers = NULL; 1467c478bd9Sstevel@tonic-gate pcm_dev_node_t *pcmcia_devnodes = NULL; 1477c478bd9Sstevel@tonic-gate 1487c478bd9Sstevel@tonic-gate kmutex_t pcmcia_global_lock; 1497c478bd9Sstevel@tonic-gate kcondvar_t pcmcia_condvar; 1507c478bd9Sstevel@tonic-gate kmutex_t pcmcia_enum_lock; 1517c478bd9Sstevel@tonic-gate 1527c478bd9Sstevel@tonic-gate /* 1537c478bd9Sstevel@tonic-gate * Mapping of the device "type" to names acceptable to 1547c478bd9Sstevel@tonic-gate * the DDI 1557c478bd9Sstevel@tonic-gate */ 1567c478bd9Sstevel@tonic-gate static char *pcmcia_dev_type[] = { 1577c478bd9Sstevel@tonic-gate "multifunction", 1587c478bd9Sstevel@tonic-gate "byte", 1597c478bd9Sstevel@tonic-gate "serial", 1607c478bd9Sstevel@tonic-gate "parallel", 1617c478bd9Sstevel@tonic-gate "block", 1627c478bd9Sstevel@tonic-gate "display", 1637c478bd9Sstevel@tonic-gate "network", 1647c478bd9Sstevel@tonic-gate "block", 1657c478bd9Sstevel@tonic-gate "byte" 1667c478bd9Sstevel@tonic-gate }; 1677c478bd9Sstevel@tonic-gate 1687c478bd9Sstevel@tonic-gate char *pcmcia_default_pm_mode = "parental-suspend-resume"; 1697c478bd9Sstevel@tonic-gate 1707c478bd9Sstevel@tonic-gate /* 1717c478bd9Sstevel@tonic-gate * generic names from the approved list: 1727c478bd9Sstevel@tonic-gate * disk tape pci sbus scsi token-ring isa keyboard display mouse 1737c478bd9Sstevel@tonic-gate * audio ethernet timer memory parallel serial rtc nvram scanner 1747c478bd9Sstevel@tonic-gate * floppy(controller) fddi isdn atm ide pccard video-in video-out 1757c478bd9Sstevel@tonic-gate * in some cases there will need to be device class dependent names. 1767c478bd9Sstevel@tonic-gate * network -> ethernet, token-ring, etc. 1777c478bd9Sstevel@tonic-gate * this list is a first guess and is used when all else fails. 1787c478bd9Sstevel@tonic-gate */ 1797c478bd9Sstevel@tonic-gate 1807c478bd9Sstevel@tonic-gate char *pcmcia_generic_names[] = { 1817c478bd9Sstevel@tonic-gate "multifunction", 1827c478bd9Sstevel@tonic-gate "memory", 1837c478bd9Sstevel@tonic-gate "serial", 1847c478bd9Sstevel@tonic-gate "parallel", 1857c478bd9Sstevel@tonic-gate "disk", 1867c478bd9Sstevel@tonic-gate "video", /* no spec for video-out yet */ 1877c478bd9Sstevel@tonic-gate "network", 1887c478bd9Sstevel@tonic-gate "aims", 1897c478bd9Sstevel@tonic-gate "scsi", 1907c478bd9Sstevel@tonic-gate "security" 1917c478bd9Sstevel@tonic-gate }; 1927c478bd9Sstevel@tonic-gate 1937c478bd9Sstevel@tonic-gate #define PCM_GENNAME_SIZE (sizeof (pcmcia_generic_names) / \ 1947c478bd9Sstevel@tonic-gate sizeof (char *)) 1957c478bd9Sstevel@tonic-gate #define PCMCIA_MAP_IO 0x0 1967c478bd9Sstevel@tonic-gate #define PCMCIA_MAP_MEM 0x1 1978134ee03Srw #define PPB_SUBTRACTIVE ((PCI_CLASS_BRIDGE << 16) | (PCI_BRIDGE_PCI << 8) | \ 1988134ee03Srw (PCI_BRIDGE_PCI_IF_SUBDECODE)) 1997c478bd9Sstevel@tonic-gate 2007c478bd9Sstevel@tonic-gate /* 2017c478bd9Sstevel@tonic-gate * The following should be 2^^n - 1 2027c478bd9Sstevel@tonic-gate */ 2037c478bd9Sstevel@tonic-gate #define PCMCIA_SOCKET_BITS 0x7f 2047c478bd9Sstevel@tonic-gate 2057c478bd9Sstevel@tonic-gate #ifdef PCMCIA_DEBUG 2067c478bd9Sstevel@tonic-gate int pcmcia_debug = 0x0; 2077c478bd9Sstevel@tonic-gate static void pcmcia_dump_minors(dev_info_t *); 2087c478bd9Sstevel@tonic-gate #endif 2097c478bd9Sstevel@tonic-gate 2107c478bd9Sstevel@tonic-gate static f_tt *pcmcia_cs_event = NULL; 2117c478bd9Sstevel@tonic-gate int pcmcia_timer_id; 2127c478bd9Sstevel@tonic-gate dev_info_t *pcmcia_dip; 2137c478bd9Sstevel@tonic-gate /* 2147c478bd9Sstevel@tonic-gate * XXX - See comments in cs.c 2157c478bd9Sstevel@tonic-gate */ 2167c478bd9Sstevel@tonic-gate static f_tt *pcmcia_cis_parser = NULL; 2177c478bd9Sstevel@tonic-gate 2187c478bd9Sstevel@tonic-gate extern struct pc_socket_services pc_socket_services; 2197c478bd9Sstevel@tonic-gate 2207c478bd9Sstevel@tonic-gate /* some function declarations */ 2217c478bd9Sstevel@tonic-gate static int pcm_adapter_callback(dev_info_t *, int, int, int); 2227c478bd9Sstevel@tonic-gate extern void pcmcia_init_adapter(anp_t *, dev_info_t *); 2237c478bd9Sstevel@tonic-gate extern void pcmcia_find_cards(anp_t *); 2247c478bd9Sstevel@tonic-gate extern void pcmcia_merge_power(struct power_entry *); 2257c478bd9Sstevel@tonic-gate extern void pcmcia_do_resume(int, pcmcia_logical_socket_t *); 2267c478bd9Sstevel@tonic-gate extern void pcmcia_resume(int, pcmcia_logical_socket_t *); 2277c478bd9Sstevel@tonic-gate extern void pcmcia_do_suspend(int, pcmcia_logical_socket_t *); 2287c478bd9Sstevel@tonic-gate extern void pcm_event_manager(int, int, void *); 2297c478bd9Sstevel@tonic-gate static void pcmcia_create_dev_info(int); 2307c478bd9Sstevel@tonic-gate static int pcmcia_create_device(ss_make_device_node_t *); 2317c478bd9Sstevel@tonic-gate static void pcmcia_init_devinfo(dev_info_t *, struct pcm_device_info *); 2327c478bd9Sstevel@tonic-gate void pcmcia_fix_string(char *str); 2337c478bd9Sstevel@tonic-gate dev_info_t *pcmcia_number_socket(dev_info_t *, int); 2347c478bd9Sstevel@tonic-gate static int pcmcia_merge_conf(dev_info_t *); 2357c478bd9Sstevel@tonic-gate static uint32_t pcmcia_mfc_intr(caddr_t, caddr_t); 2367c478bd9Sstevel@tonic-gate void pcmcia_free_resources(dev_info_t *); 2377c478bd9Sstevel@tonic-gate static void pcmcia_ppd_free(struct pcmcia_parent_private *ppd); 2387c478bd9Sstevel@tonic-gate int pcmcia_get_intr(dev_info_t *, int); 2397c478bd9Sstevel@tonic-gate int pcmcia_return_intr(dev_info_t *, int); 2408134ee03Srw int pcmcia_ra_alloc(dev_info_t *, ndi_ra_request_t *, ra_return_t *, char *, 2418134ee03Srw dev_info_t **); 2427c478bd9Sstevel@tonic-gate int pcmcia_ra_free(dev_info_t *, ra_return_t *, char *); 2437c478bd9Sstevel@tonic-gate 2447c478bd9Sstevel@tonic-gate extern int cs_init(void); 2457c478bd9Sstevel@tonic-gate extern int cs_deinit(void); 2467c478bd9Sstevel@tonic-gate extern void cisp_init(void); 2477c478bd9Sstevel@tonic-gate extern void cis_deinit(void); 2487c478bd9Sstevel@tonic-gate 2497c478bd9Sstevel@tonic-gate /* 2507c478bd9Sstevel@tonic-gate * non-DDI compliant functions are listed here 2517c478bd9Sstevel@tonic-gate * some will be declared while others that have 2527c478bd9Sstevel@tonic-gate * entries in .h files. All will be commented on. 2537c478bd9Sstevel@tonic-gate * 2547c478bd9Sstevel@tonic-gate * with declarations: 2557c478bd9Sstevel@tonic-gate * ddi_add_child 2567c478bd9Sstevel@tonic-gate * ddi_binding_name 2577c478bd9Sstevel@tonic-gate * ddi_bus_prop_op 2587c478bd9Sstevel@tonic-gate * ddi_ctlops 2597c478bd9Sstevel@tonic-gate * ddi_find_devinfo 2607c478bd9Sstevel@tonic-gate * ddi_get_name_addr 2617c478bd9Sstevel@tonic-gate * ddi_get_parent_data 2627c478bd9Sstevel@tonic-gate * ddi_hold_installed_driver 2637c478bd9Sstevel@tonic-gate * ddi_name_to_major 2647c478bd9Sstevel@tonic-gate * ddi_node_name 2657c478bd9Sstevel@tonic-gate * ddi_pathname 2667c478bd9Sstevel@tonic-gate * ddi_rele_driver 2677c478bd9Sstevel@tonic-gate * ddi_set_name_addr 2687c478bd9Sstevel@tonic-gate * ddi_set_parent_data 2697c478bd9Sstevel@tonic-gate * ddi_unorphan_devs 2707c478bd9Sstevel@tonic-gate * i_ddi_bind_node_to_driver 2717c478bd9Sstevel@tonic-gate * i_ddi_bind_node_to_driver 2727c478bd9Sstevel@tonic-gate * i_ddi_bus_map 2737c478bd9Sstevel@tonic-gate * i_ddi_map_fault 2747c478bd9Sstevel@tonic-gate * i_ddi_mem_alloc 2757c478bd9Sstevel@tonic-gate * i_ddi_mem_alloc 2767c478bd9Sstevel@tonic-gate * i_ddi_mem_free 2777c478bd9Sstevel@tonic-gate * i_ddi_mem_free 2787c478bd9Sstevel@tonic-gate * modload 2797c478bd9Sstevel@tonic-gate * modunload 2807c478bd9Sstevel@tonic-gate */ 2817c478bd9Sstevel@tonic-gate 2827c478bd9Sstevel@tonic-gate extern void ddi_unorphan_devs(major_t); 2837c478bd9Sstevel@tonic-gate 2847c478bd9Sstevel@tonic-gate /* Card&Socket Services entry points */ 2857c478bd9Sstevel@tonic-gate static int GetCookiesAndDip(sservice_t *); 2867c478bd9Sstevel@tonic-gate static int SSGetAdapter(get_adapter_t *); 2877c478bd9Sstevel@tonic-gate static int SSGetPage(get_page_t *); 2887c478bd9Sstevel@tonic-gate static int SSGetSocket(get_socket_t *); 2897c478bd9Sstevel@tonic-gate static int SSGetStatus(get_ss_status_t *); 2907c478bd9Sstevel@tonic-gate static int SSGetWindow(get_window_t *); 2917c478bd9Sstevel@tonic-gate static int SSInquireAdapter(inquire_adapter_t *); 2927c478bd9Sstevel@tonic-gate static int SSInquireSocket(inquire_socket_t *); 2937c478bd9Sstevel@tonic-gate static int SSInquireWindow(inquire_window_t *); 2947c478bd9Sstevel@tonic-gate static int SSResetSocket(int, int); 2957c478bd9Sstevel@tonic-gate static int SSSetPage(set_page_t *); 2967c478bd9Sstevel@tonic-gate static int SSSetSocket(set_socket_t *); 2977c478bd9Sstevel@tonic-gate static int SSSetWindow(set_window_t *); 2987c478bd9Sstevel@tonic-gate static int SSSetIRQHandler(set_irq_handler_t *); 2997c478bd9Sstevel@tonic-gate static int SSClearIRQHandler(clear_irq_handler_t *); 3007c478bd9Sstevel@tonic-gate 3017c478bd9Sstevel@tonic-gate static struct modldrv modlmisc = { 3027c478bd9Sstevel@tonic-gate &mod_miscops, /* Type of module. This one is a driver */ 303*39b361b2SRichard Bean "PCMCIA Nexus Support", /* Name of the module. */ 3047c478bd9Sstevel@tonic-gate }; 3057c478bd9Sstevel@tonic-gate 3067c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 3077c478bd9Sstevel@tonic-gate MODREV_1, (void *)&modlmisc, NULL 3087c478bd9Sstevel@tonic-gate }; 3097c478bd9Sstevel@tonic-gate 3107c478bd9Sstevel@tonic-gate int 3117c478bd9Sstevel@tonic-gate _init() 3127c478bd9Sstevel@tonic-gate { 3137c478bd9Sstevel@tonic-gate int ret; 3147c478bd9Sstevel@tonic-gate 3157c478bd9Sstevel@tonic-gate cisp_init(); 3167c478bd9Sstevel@tonic-gate 3177c478bd9Sstevel@tonic-gate if (cs_init() != CS_SUCCESS) { 3187c478bd9Sstevel@tonic-gate if (cs_deinit() != CS_SUCCESS) 3197c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia: _init cs_deinit error\n"); 3207c478bd9Sstevel@tonic-gate return (-1); 3217c478bd9Sstevel@tonic-gate } 3227c478bd9Sstevel@tonic-gate 3237c478bd9Sstevel@tonic-gate mutex_init(&pcmcia_global_lock, NULL, MUTEX_DEFAULT, NULL); 3247c478bd9Sstevel@tonic-gate cv_init(&pcmcia_condvar, NULL, CV_DRIVER, NULL); 3257c478bd9Sstevel@tonic-gate mutex_init(&pcmcia_enum_lock, NULL, MUTEX_DEFAULT, NULL); 3267c478bd9Sstevel@tonic-gate 3277c478bd9Sstevel@tonic-gate if ((ret = mod_install(&modlinkage)) != 0) { 3287c478bd9Sstevel@tonic-gate mutex_destroy(&pcmcia_global_lock); 3297c478bd9Sstevel@tonic-gate cv_destroy(&pcmcia_condvar); 3307c478bd9Sstevel@tonic-gate mutex_destroy(&pcmcia_enum_lock); 3317c478bd9Sstevel@tonic-gate } 3327c478bd9Sstevel@tonic-gate return (ret); 3337c478bd9Sstevel@tonic-gate } 3347c478bd9Sstevel@tonic-gate 3357c478bd9Sstevel@tonic-gate int 3367c478bd9Sstevel@tonic-gate _fini() 3377c478bd9Sstevel@tonic-gate { 3387c478bd9Sstevel@tonic-gate int ret; 3397c478bd9Sstevel@tonic-gate 3407c478bd9Sstevel@tonic-gate if ((ret = mod_remove(&modlinkage)) == 0) { 3417c478bd9Sstevel@tonic-gate mutex_destroy(&pcmcia_global_lock); 3427c478bd9Sstevel@tonic-gate cv_destroy(&pcmcia_condvar); 3437c478bd9Sstevel@tonic-gate mutex_destroy(&pcmcia_enum_lock); 3447c478bd9Sstevel@tonic-gate cis_deinit(); 3457c478bd9Sstevel@tonic-gate if (cs_deinit() != CS_SUCCESS) { 3467c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia: _fini cs_deinit error\n"); 3477c478bd9Sstevel@tonic-gate } 3487c478bd9Sstevel@tonic-gate } 3497c478bd9Sstevel@tonic-gate return (ret); 3507c478bd9Sstevel@tonic-gate } 3517c478bd9Sstevel@tonic-gate 3527c478bd9Sstevel@tonic-gate int 3537c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 3547c478bd9Sstevel@tonic-gate { 3557c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 3567c478bd9Sstevel@tonic-gate } 3577c478bd9Sstevel@tonic-gate 3587c478bd9Sstevel@tonic-gate extern pri_t minclsyspri; 3597c478bd9Sstevel@tonic-gate 3607c478bd9Sstevel@tonic-gate /* 3617c478bd9Sstevel@tonic-gate * pcmcia_attach() 3627c478bd9Sstevel@tonic-gate * the attach routine must make sure that everything needed is present 3637c478bd9Sstevel@tonic-gate * including real hardware. The sequence of events is: 3647c478bd9Sstevel@tonic-gate * attempt to load all adapter drivers 3657c478bd9Sstevel@tonic-gate * attempt to load Card Services (which _depends_on pcmcia) 3667c478bd9Sstevel@tonic-gate * initialize logical sockets 3677c478bd9Sstevel@tonic-gate * report the nexus exists 3687c478bd9Sstevel@tonic-gate */ 3697c478bd9Sstevel@tonic-gate 3707c478bd9Sstevel@tonic-gate int 3717c478bd9Sstevel@tonic-gate pcmcia_attach(dev_info_t *dip, anp_t *adapter) 3727c478bd9Sstevel@tonic-gate { 3737c478bd9Sstevel@tonic-gate int count, done, i; 3747c478bd9Sstevel@tonic-gate 3757c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 3767c478bd9Sstevel@tonic-gate if (pcmcia_debug) { 3777c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia_attach: dip=0x%p adapter=0x%p\n", 3787c478bd9Sstevel@tonic-gate (void *)dip, (void *)adapter); 3797c478bd9Sstevel@tonic-gate } 3807c478bd9Sstevel@tonic-gate #endif 3817c478bd9Sstevel@tonic-gate 3827c478bd9Sstevel@tonic-gate pcmcia_dip = dip; 3837c478bd9Sstevel@tonic-gate 3847c478bd9Sstevel@tonic-gate mutex_enter(&pcmcia_enum_lock); 3857c478bd9Sstevel@tonic-gate mutex_enter(&pcmcia_global_lock); 3867c478bd9Sstevel@tonic-gate if (pcmcia_num_adapters == 0) { 3877c478bd9Sstevel@tonic-gate pcmcia_cis_parser = (f_tt *)CISParser; 3887c478bd9Sstevel@tonic-gate cis_parser = (void *(*)(int, ...)) CISParser; 3897c478bd9Sstevel@tonic-gate pcmcia_cs_event = (f_tt *)cs_event; 3907c478bd9Sstevel@tonic-gate cs_socket_services = SocketServices; 3917c478bd9Sstevel@tonic-gate /* tell CS we are up with basic init level */ 3927c478bd9Sstevel@tonic-gate (void) cs_event(PCE_SS_INIT_STATE, PCE_SS_STATE_INIT, 0); 3937c478bd9Sstevel@tonic-gate } 3947c478bd9Sstevel@tonic-gate 3957c478bd9Sstevel@tonic-gate (void) ddi_prop_update_string(DDI_DEV_T_NONE, dip, 3967c478bd9Sstevel@tonic-gate PCM_DEVICETYPE, "pccard"); 3977c478bd9Sstevel@tonic-gate 3987c478bd9Sstevel@tonic-gate ddi_report_dev(dip); /* directory/device naming */ 3997c478bd9Sstevel@tonic-gate 4007c478bd9Sstevel@tonic-gate /* 4017c478bd9Sstevel@tonic-gate * now setup any power management stuff necessary. 4027c478bd9Sstevel@tonic-gate * we do it here in order to ensure that all PC Card nexi 4037c478bd9Sstevel@tonic-gate * implement it. 4047c478bd9Sstevel@tonic-gate */ 4057c478bd9Sstevel@tonic-gate 4067c478bd9Sstevel@tonic-gate if (pm_create_components(dip, 1) != DDI_SUCCESS) { 4077c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s: not power managed\n", 4087c478bd9Sstevel@tonic-gate ddi_get_name_addr(dip)); 4097c478bd9Sstevel@tonic-gate } else { 4107c478bd9Sstevel@tonic-gate pm_set_normal_power(dip, 0, 1); 4117c478bd9Sstevel@tonic-gate } 4127c478bd9Sstevel@tonic-gate 4137c478bd9Sstevel@tonic-gate /* 4147c478bd9Sstevel@tonic-gate * setup the info necessary for Card Services/SocketServices 4157c478bd9Sstevel@tonic-gate * and notify CS when ready. 4167c478bd9Sstevel@tonic-gate */ 4177c478bd9Sstevel@tonic-gate 4187c478bd9Sstevel@tonic-gate pcmcia_free_resources(dip); 4197c478bd9Sstevel@tonic-gate pcmcia_init_adapter(adapter, dip); 4207c478bd9Sstevel@tonic-gate /* exit mutex so CS can run for any cards found */ 4217c478bd9Sstevel@tonic-gate mutex_exit(&pcmcia_global_lock); 4227c478bd9Sstevel@tonic-gate 4237c478bd9Sstevel@tonic-gate /* 4247c478bd9Sstevel@tonic-gate * make sure the devices are identified before 4257c478bd9Sstevel@tonic-gate * returning. We do this by checking each socket to see if 4267c478bd9Sstevel@tonic-gate * a card is present. If there is one, and there isn't a dip, 4277c478bd9Sstevel@tonic-gate * we can't be done. We scan the list of sockets doing the 4287c478bd9Sstevel@tonic-gate * check. if we aren't done, wait for a condition variable to 4297c478bd9Sstevel@tonic-gate * wakeup. 4307c478bd9Sstevel@tonic-gate * Because we can miss a wakeup and because things can 4317c478bd9Sstevel@tonic-gate * take time, we do eventually give up and have a timeout. 4327c478bd9Sstevel@tonic-gate */ 4337c478bd9Sstevel@tonic-gate 4347c478bd9Sstevel@tonic-gate for (count = 0, done = 0; 4357c478bd9Sstevel@tonic-gate done == 0 && count < max(pcmcia_num_sockets, 16); 4367c478bd9Sstevel@tonic-gate count++) { 4377c478bd9Sstevel@tonic-gate done = 1; 4387c478bd9Sstevel@tonic-gate /* block CS while checking so we don't miss anything */ 4397c478bd9Sstevel@tonic-gate mutex_enter(&pcmcia_global_lock); 4407c478bd9Sstevel@tonic-gate for (i = 0; i < pcmcia_num_sockets; i++) { 4417c478bd9Sstevel@tonic-gate get_ss_status_t status; 4427c478bd9Sstevel@tonic-gate if (pcmcia_sockets[i] == NULL) 4437c478bd9Sstevel@tonic-gate continue; 4447c478bd9Sstevel@tonic-gate bzero(&status, sizeof (status)); 4457c478bd9Sstevel@tonic-gate status.socket = i; 4467c478bd9Sstevel@tonic-gate if (SSGetStatus(&status) == SUCCESS) { 4477c478bd9Sstevel@tonic-gate if (status.CardState & SBM_CD && 4487c478bd9Sstevel@tonic-gate pcmcia_sockets[i]->ls_dip[0] == NULL) { 4497c478bd9Sstevel@tonic-gate done = 0; 4507c478bd9Sstevel@tonic-gate } 4517c478bd9Sstevel@tonic-gate } 4527c478bd9Sstevel@tonic-gate } 4537c478bd9Sstevel@tonic-gate /* only wait if we aren't done with this set */ 4547c478bd9Sstevel@tonic-gate if (!done) { 4557c478bd9Sstevel@tonic-gate mutex_exit(&pcmcia_global_lock); 4567c478bd9Sstevel@tonic-gate delay(10); /* give up CPU for a time */ 4577c478bd9Sstevel@tonic-gate mutex_enter(&pcmcia_global_lock); 4587c478bd9Sstevel@tonic-gate } 4597c478bd9Sstevel@tonic-gate mutex_exit(&pcmcia_global_lock); 4607c478bd9Sstevel@tonic-gate } 4617c478bd9Sstevel@tonic-gate 4627c478bd9Sstevel@tonic-gate mutex_exit(&pcmcia_enum_lock); 4637c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 4647c478bd9Sstevel@tonic-gate } 4657c478bd9Sstevel@tonic-gate 4667c478bd9Sstevel@tonic-gate /* 4677c478bd9Sstevel@tonic-gate * pcmcia_detach 4687c478bd9Sstevel@tonic-gate * unload everything and then detach the nexus 4697c478bd9Sstevel@tonic-gate */ 4707c478bd9Sstevel@tonic-gate /* ARGSUSED */ 4717c478bd9Sstevel@tonic-gate int 4727c478bd9Sstevel@tonic-gate pcmcia_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 4737c478bd9Sstevel@tonic-gate { 4747c478bd9Sstevel@tonic-gate switch (cmd) { 4757c478bd9Sstevel@tonic-gate case DDI_DETACH: 4767c478bd9Sstevel@tonic-gate pm_destroy_components(dip); 4777c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 4787c478bd9Sstevel@tonic-gate 4797c478bd9Sstevel@tonic-gate /* 4807c478bd9Sstevel@tonic-gate * resume from a checkpoint 4817c478bd9Sstevel@tonic-gate * We don't do anything special here since the adapter 4827c478bd9Sstevel@tonic-gate * driver will generate resume events that we intercept 4837c478bd9Sstevel@tonic-gate * and convert to insert events. 4847c478bd9Sstevel@tonic-gate */ 4857c478bd9Sstevel@tonic-gate case DDI_SUSPEND: 4867c478bd9Sstevel@tonic-gate case DDI_PM_SUSPEND: 4877c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 4887c478bd9Sstevel@tonic-gate 4897c478bd9Sstevel@tonic-gate default: 4907c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 4917c478bd9Sstevel@tonic-gate } 4927c478bd9Sstevel@tonic-gate } 4937c478bd9Sstevel@tonic-gate 4947c478bd9Sstevel@tonic-gate /* 4957c478bd9Sstevel@tonic-gate * card_services_error() 4967c478bd9Sstevel@tonic-gate * used to make 2.4/2.5 drivers get an error when 4977c478bd9Sstevel@tonic-gate * they try to initialize. 4987c478bd9Sstevel@tonic-gate */ 4997c478bd9Sstevel@tonic-gate static int 5007c478bd9Sstevel@tonic-gate card_services_error() 5017c478bd9Sstevel@tonic-gate { 5027c478bd9Sstevel@tonic-gate return (CS_BAD_VERSION); 5037c478bd9Sstevel@tonic-gate } 5047c478bd9Sstevel@tonic-gate static int (*cs_error_ptr)() = card_services_error; 5057c478bd9Sstevel@tonic-gate 5067c478bd9Sstevel@tonic-gate /* 5077c478bd9Sstevel@tonic-gate * pcmcia_ctlops 5087c478bd9Sstevel@tonic-gate * handle the nexus control operations for the cases where 5097c478bd9Sstevel@tonic-gate * a PC Card driver gets called and we need to modify the 5107c478bd9Sstevel@tonic-gate * devinfo structure or otherwise do bus specific operations 5117c478bd9Sstevel@tonic-gate */ 5127c478bd9Sstevel@tonic-gate int 5137c478bd9Sstevel@tonic-gate pcmcia_ctlops(dev_info_t *dip, dev_info_t *rdip, 5147c478bd9Sstevel@tonic-gate ddi_ctl_enum_t ctlop, void *arg, void *result) 5157c478bd9Sstevel@tonic-gate { 5167c478bd9Sstevel@tonic-gate int e; 5177c478bd9Sstevel@tonic-gate char name[64]; 5187c478bd9Sstevel@tonic-gate struct pcmcia_parent_private *ppd; 5197c478bd9Sstevel@tonic-gate power_req_t *pm; 5207c478bd9Sstevel@tonic-gate 5217c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 5227c478bd9Sstevel@tonic-gate if (pcmcia_debug) { 5237c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia_ctlops(%p, %p, %d, %p, %p)\n", 5247c478bd9Sstevel@tonic-gate (void *)dip, (void *)rdip, ctlop, (void *)arg, 5257c478bd9Sstevel@tonic-gate (void *)result); 5267c478bd9Sstevel@tonic-gate if (rdip != NULL && ddi_get_name(rdip) != NULL) 5277c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "\t[%s]\n", ddi_get_name(rdip)); 5287c478bd9Sstevel@tonic-gate } 5297c478bd9Sstevel@tonic-gate #endif 5307c478bd9Sstevel@tonic-gate 5317c478bd9Sstevel@tonic-gate switch (ctlop) { 5327c478bd9Sstevel@tonic-gate case DDI_CTLOPS_REPORTDEV: 5337c478bd9Sstevel@tonic-gate if (rdip == (dev_info_t *)0) 5347c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 5357c478bd9Sstevel@tonic-gate 5367c478bd9Sstevel@tonic-gate if (strcmp("pcs", ddi_node_name(rdip)) == 0) 5377c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "?PCCard socket %d at %s@%s\n", 5387c478bd9Sstevel@tonic-gate ddi_get_instance(rdip), 5397c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_name_addr(dip)); 5407c478bd9Sstevel@tonic-gate else 5417c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "?%s%d at %s@%s in socket %d\n", 5427c478bd9Sstevel@tonic-gate ddi_driver_name(rdip), 5437c478bd9Sstevel@tonic-gate ddi_get_instance(rdip), 5447c478bd9Sstevel@tonic-gate ddi_driver_name(dip), 5457c478bd9Sstevel@tonic-gate ddi_get_name_addr(dip), 5467c478bd9Sstevel@tonic-gate CS_GET_SOCKET_NUMBER( 5477c478bd9Sstevel@tonic-gate ddi_getprop(DDI_DEV_T_NONE, rdip, 5487c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, 5497c478bd9Sstevel@tonic-gate PCM_DEV_SOCKET, -1))); 5507c478bd9Sstevel@tonic-gate 5517c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 5527c478bd9Sstevel@tonic-gate 5537c478bd9Sstevel@tonic-gate case DDI_CTLOPS_INITCHILD: 5547c478bd9Sstevel@tonic-gate /* 5557c478bd9Sstevel@tonic-gate * we get control here before the child is called. 5567c478bd9Sstevel@tonic-gate * we can change things if necessary. This is where 5577c478bd9Sstevel@tonic-gate * the CardServices hook gets planted. 5587c478bd9Sstevel@tonic-gate */ 5597c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 5607c478bd9Sstevel@tonic-gate if (pcmcia_debug) { 5617c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia: init child: %s(%d) @%p\n", 5627c478bd9Sstevel@tonic-gate ddi_node_name(arg), ddi_get_instance(arg), 5637c478bd9Sstevel@tonic-gate (void *)arg); 5647c478bd9Sstevel@tonic-gate if (DEVI(arg)->devi_binding_name != NULL) 5657c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "\tbinding_name=%s\n", 5667c478bd9Sstevel@tonic-gate DEVI(arg)->devi_binding_name); 5677c478bd9Sstevel@tonic-gate if (DEVI(arg)->devi_node_name != NULL) 5687c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "\tnode_name=%s\n", 5697c478bd9Sstevel@tonic-gate DEVI(arg)->devi_node_name); 5707c478bd9Sstevel@tonic-gate } 5717c478bd9Sstevel@tonic-gate #endif 5727c478bd9Sstevel@tonic-gate 5737c478bd9Sstevel@tonic-gate ppd = (struct pcmcia_parent_private *) 5747c478bd9Sstevel@tonic-gate ddi_get_parent_data((dev_info_t *)arg); 5757c478bd9Sstevel@tonic-gate if (ppd == NULL) 5767c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 5777c478bd9Sstevel@tonic-gate 5787c478bd9Sstevel@tonic-gate if (strcmp("pcs", ddi_node_name((dev_info_t *)arg)) == 0) { 5797c478bd9Sstevel@tonic-gate if (ppd == NULL) 5807c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 5817c478bd9Sstevel@tonic-gate (void) sprintf(name, "%x", 5827c478bd9Sstevel@tonic-gate (int)ppd->ppd_reg[0].phys_hi); 5837c478bd9Sstevel@tonic-gate ddi_set_name_addr((dev_info_t *)arg, name); 5847c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 5857c478bd9Sstevel@tonic-gate } 5867c478bd9Sstevel@tonic-gate 5877c478bd9Sstevel@tonic-gate /* 5887c478bd9Sstevel@tonic-gate * We don't want driver.conf files that stay in 5897c478bd9Sstevel@tonic-gate * pseudo device form. It is acceptable to have 5907c478bd9Sstevel@tonic-gate * .conf files add properties only. 5917c478bd9Sstevel@tonic-gate */ 5927c478bd9Sstevel@tonic-gate if (ndi_dev_is_persistent_node((dev_info_t *)arg) == 0) { 5937c478bd9Sstevel@tonic-gate (void) pcmcia_merge_conf((dev_info_t *)arg); 5947c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: %s.conf invalid", 5957c478bd9Sstevel@tonic-gate ddi_get_name((dev_info_t *)arg), 5967c478bd9Sstevel@tonic-gate ddi_get_instance((dev_info_t *)arg), 5977c478bd9Sstevel@tonic-gate ddi_get_name((dev_info_t *)arg)); 5987c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 5997c478bd9Sstevel@tonic-gate } 6007c478bd9Sstevel@tonic-gate 6017c478bd9Sstevel@tonic-gate 6027c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 6037c478bd9Sstevel@tonic-gate if (pcmcia_debug && ppd != NULL) { 6047c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "\tnreg=%x, intr=%x, socket=%x," 6057c478bd9Sstevel@tonic-gate " function=%x, active=%x, flags=%x\n", 6067c478bd9Sstevel@tonic-gate ppd->ppd_nreg, ppd->ppd_intr, 6077c478bd9Sstevel@tonic-gate ppd->ppd_socket, ppd->ppd_function, 6087c478bd9Sstevel@tonic-gate ppd->ppd_active, ppd->ppd_flags); 6097c478bd9Sstevel@tonic-gate } 6107c478bd9Sstevel@tonic-gate #endif 6117c478bd9Sstevel@tonic-gate 6127c478bd9Sstevel@tonic-gate /* 6137c478bd9Sstevel@tonic-gate * make sure names are relative to socket number 6147c478bd9Sstevel@tonic-gate */ 6157c478bd9Sstevel@tonic-gate if (ppd->ppd_function > 0) { 6167c478bd9Sstevel@tonic-gate int sock; 6177c478bd9Sstevel@tonic-gate int func; 6187c478bd9Sstevel@tonic-gate sock = ppd->ppd_socket; 6197c478bd9Sstevel@tonic-gate func = ppd->ppd_function; 6207c478bd9Sstevel@tonic-gate (void) sprintf(name, "%x,%x", sock, func); 6217c478bd9Sstevel@tonic-gate } else { 6227c478bd9Sstevel@tonic-gate (void) sprintf(name, "%x", ppd->ppd_socket); 6237c478bd9Sstevel@tonic-gate } 6247c478bd9Sstevel@tonic-gate ddi_set_name_addr((dev_info_t *)arg, name); 6257c478bd9Sstevel@tonic-gate 6267c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 6277c478bd9Sstevel@tonic-gate if (pcmcia_debug) 6287c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia: system init done for %s [%s] " 6297c478bd9Sstevel@tonic-gate "nodeid: %x @%s\n", 6307c478bd9Sstevel@tonic-gate ddi_get_name(arg), ddi_get_name_addr(arg), 6317c478bd9Sstevel@tonic-gate DEVI(arg)->devi_nodeid, name); 6327c478bd9Sstevel@tonic-gate if (pcmcia_debug > 1) 6337c478bd9Sstevel@tonic-gate pcmcia_dump_minors((dev_info_t *)arg); 6347c478bd9Sstevel@tonic-gate #endif 6357c478bd9Sstevel@tonic-gate 6367c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 6377c478bd9Sstevel@tonic-gate 6387c478bd9Sstevel@tonic-gate case DDI_CTLOPS_UNINITCHILD: 6397c478bd9Sstevel@tonic-gate 6407c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 6417c478bd9Sstevel@tonic-gate if (pcmcia_debug) { 6427c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia: uninit child: %s(%d) @%p\n", 6437c478bd9Sstevel@tonic-gate ddi_node_name(arg), ddi_get_instance(arg), 6447c478bd9Sstevel@tonic-gate (void *)arg); 6457c478bd9Sstevel@tonic-gate if (DEVI(arg)->devi_binding_name != NULL) 6467c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "\tbinding_name=%s\n", 6477c478bd9Sstevel@tonic-gate DEVI(arg)->devi_binding_name); 6487c478bd9Sstevel@tonic-gate if (DEVI(arg)->devi_node_name != NULL) 6497c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "\tnode_name=%s\n", 6507c478bd9Sstevel@tonic-gate DEVI(arg)->devi_node_name); 6517c478bd9Sstevel@tonic-gate } 6527c478bd9Sstevel@tonic-gate #endif 6537c478bd9Sstevel@tonic-gate 6547c478bd9Sstevel@tonic-gate ddi_set_name_addr((dev_info_t *)arg, NULL); 6557c478bd9Sstevel@tonic-gate ddi_remove_minor_node((dev_info_t *)arg, NULL); 6567c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 6577c478bd9Sstevel@tonic-gate 6587c478bd9Sstevel@tonic-gate case DDI_CTLOPS_SLAVEONLY: 6597c478bd9Sstevel@tonic-gate /* PCMCIA devices can't ever be busmaster until CardBus */ 6607c478bd9Sstevel@tonic-gate ppd = (struct pcmcia_parent_private *) 6617c478bd9Sstevel@tonic-gate ddi_get_parent_data(rdip); 6627c478bd9Sstevel@tonic-gate if (ppd != NULL && ppd->ppd_flags & PPD_CB_BUSMASTER) 6637c478bd9Sstevel@tonic-gate return (DDI_FAILURE); /* at most */ 6647c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 6657c478bd9Sstevel@tonic-gate 6667c478bd9Sstevel@tonic-gate case DDI_CTLOPS_SIDDEV: 6677c478bd9Sstevel@tonic-gate /* in general this is true. */ 6687c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 6697c478bd9Sstevel@tonic-gate 6707c478bd9Sstevel@tonic-gate case DDI_CTLOPS_NREGS: 6717c478bd9Sstevel@tonic-gate ppd = (struct pcmcia_parent_private *) 6727c478bd9Sstevel@tonic-gate ddi_get_parent_data(rdip); 6737c478bd9Sstevel@tonic-gate if (ppd != NULL) 6747c478bd9Sstevel@tonic-gate *((uint32_t *)result) = (ppd->ppd_nreg); 6757c478bd9Sstevel@tonic-gate else 6767c478bd9Sstevel@tonic-gate *((uint32_t *)result) = 0; 6777c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 6787c478bd9Sstevel@tonic-gate 6797c478bd9Sstevel@tonic-gate case DDI_CTLOPS_REGSIZE: 6807c478bd9Sstevel@tonic-gate ppd = (struct pcmcia_parent_private *) 6817c478bd9Sstevel@tonic-gate ddi_get_parent_data(rdip); 6827c478bd9Sstevel@tonic-gate if (ppd != NULL && ppd->ppd_nreg > 0) 6837c478bd9Sstevel@tonic-gate *((off_t *)result) = sizeof (struct pcm_regs); 6847c478bd9Sstevel@tonic-gate else 6857c478bd9Sstevel@tonic-gate *((off_t *)result) = 0; 6867c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 6877c478bd9Sstevel@tonic-gate 6887c478bd9Sstevel@tonic-gate case DDI_CTLOPS_POWER: 6897c478bd9Sstevel@tonic-gate ppd = (struct pcmcia_parent_private *) 6907c478bd9Sstevel@tonic-gate ddi_get_parent_data(rdip); 6917c478bd9Sstevel@tonic-gate 6927c478bd9Sstevel@tonic-gate if (ppd == NULL) 6937c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 6947c478bd9Sstevel@tonic-gate /* 6957c478bd9Sstevel@tonic-gate * if this is not present, don't bother (claim success) 6967c478bd9Sstevel@tonic-gate * since it is already in the right state. Don't 6977c478bd9Sstevel@tonic-gate * do any resume either since the card insertion will 6987c478bd9Sstevel@tonic-gate * happen independently. 6997c478bd9Sstevel@tonic-gate */ 7007c478bd9Sstevel@tonic-gate if (!ppd->ppd_active) 7017c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 7027c478bd9Sstevel@tonic-gate for (e = 0; e < pcmcia_num_adapters; e++) 7037c478bd9Sstevel@tonic-gate if (pcmcia_adapters[e] == 7047c478bd9Sstevel@tonic-gate pcmcia_sockets[ppd->ppd_socket]->ls_adapter) 7057c478bd9Sstevel@tonic-gate break; 7067c478bd9Sstevel@tonic-gate if (e == pcmcia_num_adapters) 7077c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 7087c478bd9Sstevel@tonic-gate pm = (power_req_t *)arg; 7097c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 7107c478bd9Sstevel@tonic-gate if (pcmcia_debug) { 7117c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "power: %d: %p, %d, %d [%s]\n", 7127c478bd9Sstevel@tonic-gate pm->request_type, 7137c478bd9Sstevel@tonic-gate (void *)pm->req.set_power_req.who, 7147c478bd9Sstevel@tonic-gate pm->req.set_power_req.cmpt, 7157c478bd9Sstevel@tonic-gate pm->req.set_power_req.level, 7167c478bd9Sstevel@tonic-gate ddi_get_name_addr(rdip)); 7177c478bd9Sstevel@tonic-gate } 7187c478bd9Sstevel@tonic-gate #endif 7197c478bd9Sstevel@tonic-gate e = ppd->ppd_socket; 7207c478bd9Sstevel@tonic-gate switch (pm->request_type) { 7217c478bd9Sstevel@tonic-gate case PMR_SUSPEND: 7227c478bd9Sstevel@tonic-gate if (!(pcmcia_sockets[e]->ls_flags & 7237c478bd9Sstevel@tonic-gate PCS_SUSPENDED)) { 7247c478bd9Sstevel@tonic-gate pcmcia_do_suspend(ppd->ppd_socket, 7257c478bd9Sstevel@tonic-gate pcmcia_sockets[e]); 7267c478bd9Sstevel@tonic-gate } 7277c478bd9Sstevel@tonic-gate ppd->ppd_flags |= PPD_SUSPENDED; 7287c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 7297c478bd9Sstevel@tonic-gate case PMR_RESUME: 7307c478bd9Sstevel@tonic-gate /* for now, we just succeed since the rest is done */ 7317c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 7327c478bd9Sstevel@tonic-gate case PMR_SET_POWER: 7337c478bd9Sstevel@tonic-gate /* 7347c478bd9Sstevel@tonic-gate * not sure how to handle power control 7357c478bd9Sstevel@tonic-gate * for now, we let the child handle it itself 7367c478bd9Sstevel@tonic-gate */ 7377c478bd9Sstevel@tonic-gate (void) pcmcia_power(pm->req.set_power_req.who, 7387c478bd9Sstevel@tonic-gate pm->req.set_power_req.cmpt, 7397c478bd9Sstevel@tonic-gate pm->req.set_power_req.level); 7407c478bd9Sstevel@tonic-gate break; 7417c478bd9Sstevel@tonic-gate default: 7427c478bd9Sstevel@tonic-gate break; 7437c478bd9Sstevel@tonic-gate } 7447c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 7457c478bd9Sstevel@tonic-gate /* These CTLOPS will need to be implemented for new form */ 7467c478bd9Sstevel@tonic-gate /* let CardServices know about this */ 74711c2b4c0Srw case DDI_CTLOPS_DETACH: 74811c2b4c0Srw return (DDI_SUCCESS); 74911c2b4c0Srw case DDI_CTLOPS_ATTACH: 75011c2b4c0Srw return (DDI_SUCCESS); 7517c478bd9Sstevel@tonic-gate 7527c478bd9Sstevel@tonic-gate default: 7537c478bd9Sstevel@tonic-gate /* if we don't understand, pass up the tree */ 7547c478bd9Sstevel@tonic-gate /* most things default to general ops */ 7557c478bd9Sstevel@tonic-gate return (ddi_ctlops(dip, rdip, ctlop, arg, result)); 7567c478bd9Sstevel@tonic-gate } 7577c478bd9Sstevel@tonic-gate } 7587c478bd9Sstevel@tonic-gate 7597c478bd9Sstevel@tonic-gate struct pcmcia_props { 7607c478bd9Sstevel@tonic-gate char *name; 7617c478bd9Sstevel@tonic-gate int len; 7627c478bd9Sstevel@tonic-gate int prop; 7637c478bd9Sstevel@tonic-gate } pcmcia_internal_props[] = { 7647c478bd9Sstevel@tonic-gate { PCM_DEV_ACTIVE, 0, PCMCIA_PROP_ACTIVE }, 7657c478bd9Sstevel@tonic-gate { PCM_DEV_R2TYPE, 0, PCMCIA_PROP_R2TYPE }, 7667c478bd9Sstevel@tonic-gate { PCM_DEV_CARDBUS, 0, PCMCIA_PROP_CARDBUS }, 7677c478bd9Sstevel@tonic-gate { CS_PROP, sizeof (void *), PCMCIA_PROP_OLDCS }, 7687c478bd9Sstevel@tonic-gate { "reg", 0, PCMCIA_PROP_REG }, 7697c478bd9Sstevel@tonic-gate { "interrupts", sizeof (int), PCMCIA_PROP_INTR }, 7707c478bd9Sstevel@tonic-gate { "pm-hardware-state", 0, PCMCIA_PROP_DEFAULT_PM }, 7717c478bd9Sstevel@tonic-gate }; 7727c478bd9Sstevel@tonic-gate 7737c478bd9Sstevel@tonic-gate /* 7747c478bd9Sstevel@tonic-gate * pcmcia_prop_decode(name) 7757c478bd9Sstevel@tonic-gate * decode the name and determine if this is a property 7767c478bd9Sstevel@tonic-gate * we construct on the fly, one we have on the prop list 7777c478bd9Sstevel@tonic-gate * or one that requires calling the CIS code. 7787c478bd9Sstevel@tonic-gate */ 7797c478bd9Sstevel@tonic-gate static int 7807c478bd9Sstevel@tonic-gate pcmcia_prop_decode(char *name) 7817c478bd9Sstevel@tonic-gate { 7827c478bd9Sstevel@tonic-gate int i; 7837c478bd9Sstevel@tonic-gate if (strncmp(name, "cistpl_", 7) == 0) 7847c478bd9Sstevel@tonic-gate return (PCMCIA_PROP_CIS); 7857c478bd9Sstevel@tonic-gate 7867c478bd9Sstevel@tonic-gate for (i = 0; i < (sizeof (pcmcia_internal_props) / 7877c478bd9Sstevel@tonic-gate sizeof (struct pcmcia_props)); i++) { 7887c478bd9Sstevel@tonic-gate if (strcmp(name, pcmcia_internal_props[i].name) == 0) 7897c478bd9Sstevel@tonic-gate return (i); 7907c478bd9Sstevel@tonic-gate } 7917c478bd9Sstevel@tonic-gate 7927c478bd9Sstevel@tonic-gate return (PCMCIA_PROP_UNKNOWN); 7937c478bd9Sstevel@tonic-gate } 7947c478bd9Sstevel@tonic-gate 7957c478bd9Sstevel@tonic-gate /* 7967c478bd9Sstevel@tonic-gate * pcmcia_prop_op() 7977c478bd9Sstevel@tonic-gate * we don't have properties in PROM per se so look for them 7987c478bd9Sstevel@tonic-gate * only in the devinfo node. Future may allow us to find 7997c478bd9Sstevel@tonic-gate * certain CIS tuples via this interface if a user asks for 8007c478bd9Sstevel@tonic-gate * a property of the form "cistpl-<tuplename>" but not yet. 8017c478bd9Sstevel@tonic-gate * 8027c478bd9Sstevel@tonic-gate * The addition of 1275 properties adds to the necessity. 8037c478bd9Sstevel@tonic-gate */ 8047c478bd9Sstevel@tonic-gate int 8057c478bd9Sstevel@tonic-gate pcmcia_prop_op(dev_t dev, dev_info_t *dip, dev_info_t *ch_dip, 8067c478bd9Sstevel@tonic-gate ddi_prop_op_t prop_op, int mod_flags, 8077c478bd9Sstevel@tonic-gate char *name, caddr_t valuep, int *lengthp) 8087c478bd9Sstevel@tonic-gate { 8097c478bd9Sstevel@tonic-gate int len, proplen, which, flags; 8107c478bd9Sstevel@tonic-gate caddr_t buff, propptr; 8117c478bd9Sstevel@tonic-gate struct pcmcia_parent_private *ppd; 8127c478bd9Sstevel@tonic-gate 8137c478bd9Sstevel@tonic-gate len = *lengthp; 8147c478bd9Sstevel@tonic-gate ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(ch_dip); 8157c478bd9Sstevel@tonic-gate 8167c478bd9Sstevel@tonic-gate switch (which = pcmcia_prop_decode(name)) { 8177c478bd9Sstevel@tonic-gate default: 8187c478bd9Sstevel@tonic-gate if (ppd == NULL) 8197c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 8207c478bd9Sstevel@tonic-gate 8217c478bd9Sstevel@tonic-gate /* note that proplen may get modified */ 8227c478bd9Sstevel@tonic-gate proplen = pcmcia_internal_props[which].len; 8237c478bd9Sstevel@tonic-gate switch (pcmcia_internal_props[which].prop) { 8247c478bd9Sstevel@tonic-gate case PCMCIA_PROP_DEFAULT_PM: 8257c478bd9Sstevel@tonic-gate propptr = pcmcia_default_pm_mode; 8267c478bd9Sstevel@tonic-gate proplen = strlen(propptr) + 1; 8277c478bd9Sstevel@tonic-gate break; 8287c478bd9Sstevel@tonic-gate case PCMCIA_PROP_OLDCS: 8297c478bd9Sstevel@tonic-gate propptr = (caddr_t)&cs_error_ptr; 8307c478bd9Sstevel@tonic-gate break; 8317c478bd9Sstevel@tonic-gate case PCMCIA_PROP_REG: 8327c478bd9Sstevel@tonic-gate propptr = (caddr_t)ppd->ppd_reg; 8337c478bd9Sstevel@tonic-gate proplen = ppd->ppd_nreg * sizeof (struct pcm_regs); 8347c478bd9Sstevel@tonic-gate break; 8357c478bd9Sstevel@tonic-gate case PCMCIA_PROP_INTR: 8367c478bd9Sstevel@tonic-gate propptr = (caddr_t)&ppd->ppd_intr; 8377c478bd9Sstevel@tonic-gate break; 8387c478bd9Sstevel@tonic-gate 8397c478bd9Sstevel@tonic-gate /* the next set are boolean values */ 8407c478bd9Sstevel@tonic-gate case PCMCIA_PROP_ACTIVE: 8417c478bd9Sstevel@tonic-gate propptr = NULL; 8427c478bd9Sstevel@tonic-gate if (!ppd->ppd_active) { 8437c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 8447c478bd9Sstevel@tonic-gate } 8457c478bd9Sstevel@tonic-gate break; 8467c478bd9Sstevel@tonic-gate case PCMCIA_PROP_R2TYPE: 8477c478bd9Sstevel@tonic-gate propptr = NULL; 8487c478bd9Sstevel@tonic-gate if (ppd->ppd_flags & PPD_CARD_CARDBUS) 8497c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 8507c478bd9Sstevel@tonic-gate break; 8517c478bd9Sstevel@tonic-gate case PCMCIA_PROP_CARDBUS: 8527c478bd9Sstevel@tonic-gate propptr = NULL; 8537c478bd9Sstevel@tonic-gate if (!(ppd->ppd_flags * PPD_CARD_CARDBUS)) 8547c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 8557c478bd9Sstevel@tonic-gate break; 8567c478bd9Sstevel@tonic-gate } 8577c478bd9Sstevel@tonic-gate 8587c478bd9Sstevel@tonic-gate break; 8597c478bd9Sstevel@tonic-gate 8607c478bd9Sstevel@tonic-gate case PCMCIA_PROP_CIS: 8617c478bd9Sstevel@tonic-gate /* 8627c478bd9Sstevel@tonic-gate * once we have the lookup code in place 8637c478bd9Sstevel@tonic-gate * it is sufficient to break out of the switch 8647c478bd9Sstevel@tonic-gate * once proplen and propptr are set. 8657c478bd9Sstevel@tonic-gate * The common prop_op code deals with the rest. 8667c478bd9Sstevel@tonic-gate */ 8677c478bd9Sstevel@tonic-gate case PCMCIA_PROP_UNKNOWN: 8687c478bd9Sstevel@tonic-gate return (ddi_bus_prop_op(dev, dip, ch_dip, prop_op, 8697c478bd9Sstevel@tonic-gate mod_flags | DDI_PROP_NOTPROM, 8707c478bd9Sstevel@tonic-gate name, valuep, lengthp)); 8717c478bd9Sstevel@tonic-gate } 8727c478bd9Sstevel@tonic-gate 8737c478bd9Sstevel@tonic-gate if (prop_op == PROP_LEN) { 8747c478bd9Sstevel@tonic-gate /* just the length */ 8757c478bd9Sstevel@tonic-gate *lengthp = proplen; 8767c478bd9Sstevel@tonic-gate return (DDI_PROP_SUCCESS); 8777c478bd9Sstevel@tonic-gate } 8787c478bd9Sstevel@tonic-gate switch (prop_op) { 8797c478bd9Sstevel@tonic-gate case PROP_LEN_AND_VAL_ALLOC: 8807c478bd9Sstevel@tonic-gate if (mod_flags & DDI_PROP_CANSLEEP) 8817c478bd9Sstevel@tonic-gate flags = KM_SLEEP; 8827c478bd9Sstevel@tonic-gate else 8837c478bd9Sstevel@tonic-gate flags = KM_NOSLEEP; 8847c478bd9Sstevel@tonic-gate buff = kmem_alloc((size_t)proplen, flags); 8857c478bd9Sstevel@tonic-gate if (buff == NULL) 8867c478bd9Sstevel@tonic-gate return (DDI_PROP_NO_MEMORY); 8877c478bd9Sstevel@tonic-gate *(caddr_t *)valuep = (caddr_t)buff; 8887c478bd9Sstevel@tonic-gate break; 8897c478bd9Sstevel@tonic-gate case PROP_LEN_AND_VAL_BUF: 8907c478bd9Sstevel@tonic-gate buff = (caddr_t)valuep; 8917c478bd9Sstevel@tonic-gate if (len < proplen) 8927c478bd9Sstevel@tonic-gate return (DDI_PROP_BUF_TOO_SMALL); 8937c478bd9Sstevel@tonic-gate break; 8947c478bd9Sstevel@tonic-gate default: 8957c478bd9Sstevel@tonic-gate break; 8967c478bd9Sstevel@tonic-gate } 8977c478bd9Sstevel@tonic-gate 8987c478bd9Sstevel@tonic-gate if (proplen > 0) 8997c478bd9Sstevel@tonic-gate bcopy(propptr, buff, proplen); 9007c478bd9Sstevel@tonic-gate *lengthp = proplen; 9017c478bd9Sstevel@tonic-gate return (DDI_PROP_SUCCESS); 9027c478bd9Sstevel@tonic-gate } 9037c478bd9Sstevel@tonic-gate 9047c478bd9Sstevel@tonic-gate 9057c478bd9Sstevel@tonic-gate struct regspec * 9067c478bd9Sstevel@tonic-gate pcmcia_rnum_to_regspec(dev_info_t *dip, int rnumber) 9077c478bd9Sstevel@tonic-gate { 9087c478bd9Sstevel@tonic-gate struct pcmcia_parent_private *ppd; 9097c478bd9Sstevel@tonic-gate ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(dip); 9107c478bd9Sstevel@tonic-gate if (ppd->ppd_nreg < rnumber) 9117c478bd9Sstevel@tonic-gate return (NULL); 9127c478bd9Sstevel@tonic-gate return ((struct regspec *)&ppd->ppd_reg[rnumber]); 9137c478bd9Sstevel@tonic-gate } 9147c478bd9Sstevel@tonic-gate 9157c478bd9Sstevel@tonic-gate struct regspec * 9167c478bd9Sstevel@tonic-gate pcmcia_rnum_to_mapped(dev_info_t *dip, int rnumber) 9177c478bd9Sstevel@tonic-gate { 9187c478bd9Sstevel@tonic-gate struct pcmcia_parent_private *ppd; 9197c478bd9Sstevel@tonic-gate ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(dip); 9207c478bd9Sstevel@tonic-gate if (ppd->ppd_nreg < rnumber) 9217c478bd9Sstevel@tonic-gate return (NULL); 9220d282d13Srw if (ppd->ppd_assigned == NULL) 9230d282d13Srw return (NULL); 9247c478bd9Sstevel@tonic-gate if (ppd->ppd_assigned[rnumber].phys_len == 0) 9257c478bd9Sstevel@tonic-gate return (NULL); 9267c478bd9Sstevel@tonic-gate else 9277c478bd9Sstevel@tonic-gate return ((struct regspec *)&ppd->ppd_assigned[rnumber]); 9287c478bd9Sstevel@tonic-gate } 9297c478bd9Sstevel@tonic-gate 9307c478bd9Sstevel@tonic-gate int 9317c478bd9Sstevel@tonic-gate pcmcia_find_rnum(dev_info_t *dip, struct regspec *reg) 9327c478bd9Sstevel@tonic-gate { 9337c478bd9Sstevel@tonic-gate struct pcmcia_parent_private *ppd; 9347c478bd9Sstevel@tonic-gate struct regspec *regp; 9357c478bd9Sstevel@tonic-gate int i; 9367c478bd9Sstevel@tonic-gate 9377c478bd9Sstevel@tonic-gate ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(dip); 9387c478bd9Sstevel@tonic-gate if (ppd == NULL) 9397c478bd9Sstevel@tonic-gate return (-1); 9407c478bd9Sstevel@tonic-gate for (regp = (struct regspec *)ppd->ppd_reg, i = 0; 9417c478bd9Sstevel@tonic-gate i < ppd->ppd_nreg; i++, regp++) { 9427c478bd9Sstevel@tonic-gate if (bcmp(reg, regp, sizeof (struct regspec)) == 0) 9437c478bd9Sstevel@tonic-gate return (i); 9447c478bd9Sstevel@tonic-gate } 9457c478bd9Sstevel@tonic-gate for (regp = (struct regspec *)ppd->ppd_assigned, i = 0; 9467c478bd9Sstevel@tonic-gate i < ppd->ppd_nreg; i++, regp++) { 9477c478bd9Sstevel@tonic-gate if (bcmp(reg, regp, sizeof (struct regspec)) == 0) 9487c478bd9Sstevel@tonic-gate return (i); 9497c478bd9Sstevel@tonic-gate } 9507c478bd9Sstevel@tonic-gate 9517c478bd9Sstevel@tonic-gate return (-1); 9527c478bd9Sstevel@tonic-gate } 9537c478bd9Sstevel@tonic-gate 9547c478bd9Sstevel@tonic-gate int 9557c478bd9Sstevel@tonic-gate pcmcia_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, 9567c478bd9Sstevel@tonic-gate off_t offset, off_t len, caddr_t *vaddrp) 9577c478bd9Sstevel@tonic-gate { 9587c478bd9Sstevel@tonic-gate struct pcm_regs *regs, *mregs = NULL, tmp_reg; 9597c478bd9Sstevel@tonic-gate ddi_map_req_t mr = *mp; 9607c478bd9Sstevel@tonic-gate ra_return_t ret; 9617c478bd9Sstevel@tonic-gate int check, rnum = -1; 9627c478bd9Sstevel@tonic-gate uint32_t base; 9637c478bd9Sstevel@tonic-gate uchar_t regbuf[sizeof (pci_regspec_t)]; 9647c478bd9Sstevel@tonic-gate 9657c478bd9Sstevel@tonic-gate mp = &mr; /* a copy of original request */ 9667c478bd9Sstevel@tonic-gate 9677c478bd9Sstevel@tonic-gate /* check for register number */ 9687c478bd9Sstevel@tonic-gate switch (mp->map_type) { 9697c478bd9Sstevel@tonic-gate case DDI_MT_REGSPEC: 9707c478bd9Sstevel@tonic-gate regs = (struct pcm_regs *)mp->map_obj.rp; 9717c478bd9Sstevel@tonic-gate mregs = (struct pcm_regs *)mp->map_obj.rp; 9727c478bd9Sstevel@tonic-gate /* 9737c478bd9Sstevel@tonic-gate * when using regspec, must not be relocatable 9747c478bd9Sstevel@tonic-gate * and should be from assigned space. 9757c478bd9Sstevel@tonic-gate */ 9767c478bd9Sstevel@tonic-gate if (!PC_REG_RELOC(regs->phys_hi)) 9777c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 9787c478bd9Sstevel@tonic-gate rnum = pcmcia_find_rnum(rdip, (struct regspec *)mregs); 9797c478bd9Sstevel@tonic-gate break; 9807c478bd9Sstevel@tonic-gate case DDI_MT_RNUMBER: 9817c478bd9Sstevel@tonic-gate regs = (struct pcm_regs *) 9827c478bd9Sstevel@tonic-gate pcmcia_rnum_to_regspec(rdip, mp->map_obj.rnumber); 9837c478bd9Sstevel@tonic-gate mregs = (struct pcm_regs *) 9847c478bd9Sstevel@tonic-gate pcmcia_rnum_to_mapped(rdip, mp->map_obj.rnumber); 9857c478bd9Sstevel@tonic-gate rnum = mp->map_obj.rnumber; 9867c478bd9Sstevel@tonic-gate if (regs == NULL) 9877c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 9887c478bd9Sstevel@tonic-gate mp->map_type = DDI_MT_REGSPEC; 9897c478bd9Sstevel@tonic-gate mp->map_obj.rp = (struct regspec *)mregs; 9907c478bd9Sstevel@tonic-gate break; 9917c478bd9Sstevel@tonic-gate default: 9927c478bd9Sstevel@tonic-gate return (DDI_ME_INVAL); 9937c478bd9Sstevel@tonic-gate } 9947c478bd9Sstevel@tonic-gate 9957c478bd9Sstevel@tonic-gate /* basic sanity checks */ 9967c478bd9Sstevel@tonic-gate switch (mp->map_op) { 9977c478bd9Sstevel@tonic-gate default: 9987c478bd9Sstevel@tonic-gate return (DDI_ME_UNIMPLEMENTED); 9997c478bd9Sstevel@tonic-gate case DDI_MO_UNMAP: 10007c478bd9Sstevel@tonic-gate if (mregs == NULL) 10017c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 10027c478bd9Sstevel@tonic-gate regs = mregs; 10037c478bd9Sstevel@tonic-gate break; 10047c478bd9Sstevel@tonic-gate case DDI_MO_MAP_LOCKED: 10057c478bd9Sstevel@tonic-gate case DDI_MO_MAP_HANDLE: 10067c478bd9Sstevel@tonic-gate panic("unsupported bus operation"); 10077c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 10087c478bd9Sstevel@tonic-gate } 10097c478bd9Sstevel@tonic-gate 10107c478bd9Sstevel@tonic-gate /* 10117c478bd9Sstevel@tonic-gate * we need a private copy for manipulation and 10127c478bd9Sstevel@tonic-gate * calculation of the correct ranges 10137c478bd9Sstevel@tonic-gate */ 10147c478bd9Sstevel@tonic-gate tmp_reg = *regs; 10157c478bd9Sstevel@tonic-gate mp->map_obj.rp = (struct regspec *)(regs = &tmp_reg); 10167c478bd9Sstevel@tonic-gate base = regs->phys_lo; 10177c478bd9Sstevel@tonic-gate if (base == 0 && offset != 0) { 10187c478bd9Sstevel@tonic-gate /* 10197c478bd9Sstevel@tonic-gate * for now this is an error. What does it really mean 10207c478bd9Sstevel@tonic-gate * to ask for an offset from an address that hasn't 10217c478bd9Sstevel@tonic-gate * been allocated yet. 10227c478bd9Sstevel@tonic-gate */ 10237c478bd9Sstevel@tonic-gate return (DDI_ME_INVAL); 10247c478bd9Sstevel@tonic-gate } 10257c478bd9Sstevel@tonic-gate regs->phys_lo += (uint32_t)offset; 10267c478bd9Sstevel@tonic-gate if (len != 0) { 10277c478bd9Sstevel@tonic-gate if (len > regs->phys_len) { 10287c478bd9Sstevel@tonic-gate return (DDI_ME_INVAL); 10297c478bd9Sstevel@tonic-gate } 10307c478bd9Sstevel@tonic-gate regs->phys_len = len; 10317c478bd9Sstevel@tonic-gate } 10327c478bd9Sstevel@tonic-gate 10337c478bd9Sstevel@tonic-gate /* 10347c478bd9Sstevel@tonic-gate * basic sanity is checked so now make sure 10357c478bd9Sstevel@tonic-gate * we can actually allocate something for this 10367c478bd9Sstevel@tonic-gate * request and then convert to a "standard" 10377c478bd9Sstevel@tonic-gate * regspec for the next layer up (pci/isa/rootnex/etc.) 10387c478bd9Sstevel@tonic-gate */ 10397c478bd9Sstevel@tonic-gate 10407c478bd9Sstevel@tonic-gate switch (PC_GET_REG_TYPE(regs->phys_hi)) { 10417c478bd9Sstevel@tonic-gate case PC_REG_SPACE_IO: 10427c478bd9Sstevel@tonic-gate check = PCA_RES_NEED_IO; 10437c478bd9Sstevel@tonic-gate break; 10447c478bd9Sstevel@tonic-gate case PC_REG_SPACE_MEMORY: 10457c478bd9Sstevel@tonic-gate check = PCA_RES_NEED_MEM; 10467c478bd9Sstevel@tonic-gate break; 10477c478bd9Sstevel@tonic-gate default: 10487c478bd9Sstevel@tonic-gate /* not a valid register type */ 10497c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 10507c478bd9Sstevel@tonic-gate } 10517c478bd9Sstevel@tonic-gate 10527c478bd9Sstevel@tonic-gate mr.map_type = DDI_MT_REGSPEC; 10537c478bd9Sstevel@tonic-gate ret.ra_addr_hi = 0; 10547c478bd9Sstevel@tonic-gate ret.ra_addr_lo = regs->phys_lo; 10557c478bd9Sstevel@tonic-gate ret.ra_len = regs->phys_len; 10567c478bd9Sstevel@tonic-gate mr.map_obj.rp = pcmcia_cons_regspec(dip, 10577c478bd9Sstevel@tonic-gate (check == PCA_RES_NEED_IO) ? 10587c478bd9Sstevel@tonic-gate PCMCIA_MAP_IO : PCMCIA_MAP_MEM, 10597c478bd9Sstevel@tonic-gate regbuf, &ret); 10607c478bd9Sstevel@tonic-gate switch (mp->map_op) { 10617c478bd9Sstevel@tonic-gate case DDI_MO_UNMAP: 10627c478bd9Sstevel@tonic-gate pcmcia_set_assigned(rdip, rnum, NULL); 10637c478bd9Sstevel@tonic-gate break; 10647c478bd9Sstevel@tonic-gate default: 10657c478bd9Sstevel@tonic-gate break; 10667c478bd9Sstevel@tonic-gate } 10677c478bd9Sstevel@tonic-gate return (ddi_map(dip, &mr, (off_t)0, (off_t)0, vaddrp)); 10687c478bd9Sstevel@tonic-gate } 10697c478bd9Sstevel@tonic-gate 10707c478bd9Sstevel@tonic-gate /* 10717c478bd9Sstevel@tonic-gate * pcmcia_cons_regspec() 10727c478bd9Sstevel@tonic-gate * based on parent's bus type, construct a regspec that is usable 10737c478bd9Sstevel@tonic-gate * by that parent to map the resource into the system. 10747c478bd9Sstevel@tonic-gate */ 10757c478bd9Sstevel@tonic-gate #define PTYPE_PCI 1 10767c478bd9Sstevel@tonic-gate #define PTYPE_ISA 0 10777c478bd9Sstevel@tonic-gate struct regspec * 10787c478bd9Sstevel@tonic-gate pcmcia_cons_regspec(dev_info_t *dip, int type, uchar_t *buff, ra_return_t *ret) 10797c478bd9Sstevel@tonic-gate { 10807c478bd9Sstevel@tonic-gate int ptype = -1, len, bus; 10817c478bd9Sstevel@tonic-gate char device_type[MODMAXNAMELEN + 1]; 10827c478bd9Sstevel@tonic-gate dev_info_t *pdip; 10837c478bd9Sstevel@tonic-gate struct regspec *defreg; 10847c478bd9Sstevel@tonic-gate pci_regspec_t *pcireg; 10857c478bd9Sstevel@tonic-gate 10867c478bd9Sstevel@tonic-gate pdip = ddi_get_parent(dip); 10877c478bd9Sstevel@tonic-gate if (pdip != ddi_root_node()) { 10887c478bd9Sstevel@tonic-gate /* we're not a child of root so find out what */ 10897c478bd9Sstevel@tonic-gate len = sizeof (device_type); 10907c478bd9Sstevel@tonic-gate if (ddi_prop_op(DDI_DEV_T_ANY, pdip, PROP_LEN_AND_VAL_BUF, 0, 10917c478bd9Sstevel@tonic-gate "device_type", (caddr_t)device_type, &len) == 10927c478bd9Sstevel@tonic-gate DDI_PROP_SUCCESS) { 10937c478bd9Sstevel@tonic-gate /* check things out */ 10947c478bd9Sstevel@tonic-gate if (strcmp(device_type, "pci") == 0) 10957c478bd9Sstevel@tonic-gate ptype = PTYPE_PCI; 10967c478bd9Sstevel@tonic-gate else if (strcmp(device_type, "isa") == 0) 10977c478bd9Sstevel@tonic-gate ptype = PTYPE_ISA; 10987c478bd9Sstevel@tonic-gate } 10997c478bd9Sstevel@tonic-gate } 11007c478bd9Sstevel@tonic-gate switch (ptype) { 11017c478bd9Sstevel@tonic-gate case PTYPE_PCI: 11027c478bd9Sstevel@tonic-gate /* XXX need to look at carefully */ 1103a3282898Scth if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 11047c478bd9Sstevel@tonic-gate "reg", (caddr_t)&pcireg, &len) == DDI_SUCCESS) { 11057c478bd9Sstevel@tonic-gate bus = PCI_REG_BUS_G(pcireg->pci_phys_hi); 11067c478bd9Sstevel@tonic-gate kmem_free(pcireg, len); 11077c478bd9Sstevel@tonic-gate } else { 11087c478bd9Sstevel@tonic-gate bus = 0; 11097c478bd9Sstevel@tonic-gate } 11107c478bd9Sstevel@tonic-gate pcireg = (pci_regspec_t *)buff; 11117c478bd9Sstevel@tonic-gate pcireg->pci_phys_hi = (type == PCMCIA_MAP_IO ? PCI_ADDR_IO : 11127c478bd9Sstevel@tonic-gate PCI_ADDR_MEM32) | PCI_RELOCAT_B | (bus << 16); 11137c478bd9Sstevel@tonic-gate pcireg->pci_phys_mid = ret->ra_addr_hi; 11147c478bd9Sstevel@tonic-gate pcireg->pci_phys_low = ret->ra_addr_lo; 11157c478bd9Sstevel@tonic-gate if (type == PCMCIA_MAP_IO) 11167c478bd9Sstevel@tonic-gate pcireg->pci_phys_low &= 0xFFFF; 11177c478bd9Sstevel@tonic-gate pcireg->pci_size_hi = 0; 11187c478bd9Sstevel@tonic-gate pcireg->pci_size_low = ret->ra_len; 11197c478bd9Sstevel@tonic-gate break; 11207c478bd9Sstevel@tonic-gate default: 11217c478bd9Sstevel@tonic-gate /* default case is to use struct regspec */ 11227c478bd9Sstevel@tonic-gate defreg = (struct regspec *)buff; 11237c478bd9Sstevel@tonic-gate defreg->regspec_bustype = type == PCMCIA_MAP_IO ? 1 : 0; 11247c478bd9Sstevel@tonic-gate defreg->regspec_addr = ret->ra_addr_lo; 11257c478bd9Sstevel@tonic-gate defreg->regspec_size = ret->ra_len; 11267c478bd9Sstevel@tonic-gate break; 11277c478bd9Sstevel@tonic-gate } 11287c478bd9Sstevel@tonic-gate return ((struct regspec *)buff); 11297c478bd9Sstevel@tonic-gate } 11307c478bd9Sstevel@tonic-gate 11317c478bd9Sstevel@tonic-gate /* 11327c478bd9Sstevel@tonic-gate * pcmcia_init_adapter 11337c478bd9Sstevel@tonic-gate * Initialize the per-adapter structures and check to see if 11347c478bd9Sstevel@tonic-gate * there are possible other instances coming. 11357c478bd9Sstevel@tonic-gate */ 11367c478bd9Sstevel@tonic-gate void 11377c478bd9Sstevel@tonic-gate pcmcia_init_adapter(anp_t *adapter, dev_info_t *dip) 11387c478bd9Sstevel@tonic-gate { 11397c478bd9Sstevel@tonic-gate int i, n; 11407c478bd9Sstevel@tonic-gate pcmcia_if_t *ls_if; 11417c478bd9Sstevel@tonic-gate 11427c478bd9Sstevel@tonic-gate i = pcmcia_num_adapters++; 11437c478bd9Sstevel@tonic-gate pcmcia_adapters[i] = kmem_zalloc(sizeof (struct pcmcia_adapter), 11447c478bd9Sstevel@tonic-gate KM_SLEEP); 11457c478bd9Sstevel@tonic-gate pcmcia_adapters[i]->pca_dip = dip; 11467c478bd9Sstevel@tonic-gate /* should this be pca_winshift??? */ 11477c478bd9Sstevel@tonic-gate pcmcia_adapters[i]->pca_module = ddi_name_to_major(ddi_get_name(dip)); 11487c478bd9Sstevel@tonic-gate pcmcia_adapters[i]->pca_unit = ddi_get_instance(dip); 11497c478bd9Sstevel@tonic-gate pcmcia_adapters[i]->pca_iblock = adapter->an_iblock; 11507c478bd9Sstevel@tonic-gate pcmcia_adapters[i]->pca_idev = adapter->an_idev; 11517c478bd9Sstevel@tonic-gate pcmcia_adapters[i]->pca_if = ls_if = adapter->an_if; 11527c478bd9Sstevel@tonic-gate pcmcia_adapters[i]->pca_number = i; 11537c478bd9Sstevel@tonic-gate (void) strcpy(pcmcia_adapters[i]->pca_name, ddi_get_name(dip)); 11547c478bd9Sstevel@tonic-gate pcmcia_adapters[i]-> 11557c478bd9Sstevel@tonic-gate pca_name[sizeof (pcmcia_adapters[i]->pca_name) - 1] = NULL; 11567c478bd9Sstevel@tonic-gate 11577c478bd9Sstevel@tonic-gate if (ls_if != NULL) { 11587c478bd9Sstevel@tonic-gate inquire_adapter_t conf; 11597c478bd9Sstevel@tonic-gate int sock, win; 11607c478bd9Sstevel@tonic-gate 11617c478bd9Sstevel@tonic-gate if (ls_if->pcif_inquire_adapter != NULL) 11627c478bd9Sstevel@tonic-gate GET_CONFIG(ls_if, dip, &conf); 11637c478bd9Sstevel@tonic-gate 11647c478bd9Sstevel@tonic-gate /* resources - assume worst case and fix from there */ 11657c478bd9Sstevel@tonic-gate pcmcia_adapters[i]->pca_flags = PCA_RES_NEED_IRQ | 11667c478bd9Sstevel@tonic-gate PCA_RES_NEED_IO | PCA_RES_NEED_MEM; 11677c478bd9Sstevel@tonic-gate /* indicate first socket not initialized */ 11687c478bd9Sstevel@tonic-gate pcmcia_adapters[i]->pca_first_socket = -1; 11697c478bd9Sstevel@tonic-gate 11707c478bd9Sstevel@tonic-gate if (conf.ResourceFlags & RES_OWN_IRQ) 11717c478bd9Sstevel@tonic-gate pcmcia_adapters[i]->pca_flags &= ~PCA_RES_NEED_IRQ; 11727c478bd9Sstevel@tonic-gate if (conf.ResourceFlags & RES_OWN_IO) 11737c478bd9Sstevel@tonic-gate pcmcia_adapters[i]->pca_flags &= ~PCA_RES_NEED_IO; 11747c478bd9Sstevel@tonic-gate if (conf.ResourceFlags & RES_OWN_MEM) 11757c478bd9Sstevel@tonic-gate pcmcia_adapters[i]->pca_flags &= ~PCA_RES_NEED_MEM; 11767c478bd9Sstevel@tonic-gate if (conf.ResourceFlags & RES_IRQ_SHAREABLE) 11777c478bd9Sstevel@tonic-gate pcmcia_adapters[i]->pca_flags |= PCA_IRQ_SHAREABLE; 11787c478bd9Sstevel@tonic-gate if (conf.ResourceFlags & RES_IRQ_NEXUS) 11797c478bd9Sstevel@tonic-gate pcmcia_adapters[i]->pca_flags |= PCA_IRQ_SMI_SHARE; 11807c478bd9Sstevel@tonic-gate 11817c478bd9Sstevel@tonic-gate /* need to know interrupt limitations */ 11827c478bd9Sstevel@tonic-gate if (conf.ActiveLow) { 11837c478bd9Sstevel@tonic-gate pcmcia_adapters[i]->pca_avail_intr = conf.ActiveLow; 11847c478bd9Sstevel@tonic-gate pcmcia_adapters[i]->pca_flags |= PCA_IRQ_ISA; 11857c478bd9Sstevel@tonic-gate } else 11867c478bd9Sstevel@tonic-gate pcmcia_adapters[i]->pca_avail_intr = conf.ActiveHigh; 11877c478bd9Sstevel@tonic-gate 11887c478bd9Sstevel@tonic-gate /* power entries for adapter */ 11897c478bd9Sstevel@tonic-gate pcmcia_adapters[i]->pca_power = 11907c478bd9Sstevel@tonic-gate conf.power_entry; 11917c478bd9Sstevel@tonic-gate pcmcia_adapters[i]->pca_numpower = 11927c478bd9Sstevel@tonic-gate conf.NumPower; 11937c478bd9Sstevel@tonic-gate 11947c478bd9Sstevel@tonic-gate for (n = 0; n < conf.NumPower; n++) 11957c478bd9Sstevel@tonic-gate pcmcia_merge_power(&conf.power_entry[n]); 11967c478bd9Sstevel@tonic-gate 11977c478bd9Sstevel@tonic-gate /* now setup the per socket info */ 11987c478bd9Sstevel@tonic-gate for (sock = 0; sock < conf.NumSockets; 11997c478bd9Sstevel@tonic-gate sock++) { 12007c478bd9Sstevel@tonic-gate dev_info_t *sockdrv = NULL; 12017c478bd9Sstevel@tonic-gate sockdrv = pcmcia_number_socket(dip, sock); 12027c478bd9Sstevel@tonic-gate if (sockdrv == NULL) 12037c478bd9Sstevel@tonic-gate n = sock + pcmcia_num_sockets; 12047c478bd9Sstevel@tonic-gate else { 12057c478bd9Sstevel@tonic-gate n = ddi_get_instance(sockdrv); 12067c478bd9Sstevel@tonic-gate } 12077c478bd9Sstevel@tonic-gate /* make sure we know first socket on adapter */ 12087c478bd9Sstevel@tonic-gate if (pcmcia_adapters[i]->pca_first_socket == -1) 12097c478bd9Sstevel@tonic-gate pcmcia_adapters[i]->pca_first_socket = n; 12107c478bd9Sstevel@tonic-gate 12117c478bd9Sstevel@tonic-gate /* 12127c478bd9Sstevel@tonic-gate * the number of sockets is weird. 12137c478bd9Sstevel@tonic-gate * we might have only two sockets but 12147c478bd9Sstevel@tonic-gate * due to persistence of instances we 12157c478bd9Sstevel@tonic-gate * will need to call them something other 12167c478bd9Sstevel@tonic-gate * than 0 and 1. So, we use the largest 12177c478bd9Sstevel@tonic-gate * instance number as the number and 12187c478bd9Sstevel@tonic-gate * have some that just don't get used. 12197c478bd9Sstevel@tonic-gate */ 12207c478bd9Sstevel@tonic-gate if (n >= pcmcia_num_sockets) 12217c478bd9Sstevel@tonic-gate pcmcia_num_sockets = n + 1; 12227c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 12237c478bd9Sstevel@tonic-gate if (pcmcia_debug) { 12247c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 12257c478bd9Sstevel@tonic-gate "pcmcia_init: new socket added %d " 12267c478bd9Sstevel@tonic-gate "(%d)\n", 12277c478bd9Sstevel@tonic-gate n, pcmcia_num_sockets); 12287c478bd9Sstevel@tonic-gate } 12297c478bd9Sstevel@tonic-gate #endif 12307c478bd9Sstevel@tonic-gate 12317c478bd9Sstevel@tonic-gate pcmcia_sockets[n] = 12327c478bd9Sstevel@tonic-gate kmem_zalloc(sizeof (pcmcia_logical_socket_t), 12337c478bd9Sstevel@tonic-gate KM_SLEEP); 12347c478bd9Sstevel@tonic-gate pcmcia_sockets[n]->ls_socket = sock; 12357c478bd9Sstevel@tonic-gate pcmcia_sockets[n]->ls_if = ls_if; 12367c478bd9Sstevel@tonic-gate pcmcia_sockets[n]->ls_adapter = 12377c478bd9Sstevel@tonic-gate pcmcia_adapters[i]; 12387c478bd9Sstevel@tonic-gate pcmcia_sockets[n]->ls_cs_events = 0L; 12397c478bd9Sstevel@tonic-gate pcmcia_sockets[n]->ls_sockdrv = sockdrv; 12407c478bd9Sstevel@tonic-gate /* Prototype of intrspec */ 12417c478bd9Sstevel@tonic-gate pcmcia_sockets[n]->ls_intr_pri = 12427c478bd9Sstevel@tonic-gate adapter->an_ipl; 12437c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 12447c478bd9Sstevel@tonic-gate if (pcmcia_debug) 12457c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 12467c478bd9Sstevel@tonic-gate "phys sock %d, log sock %d\n", 12477c478bd9Sstevel@tonic-gate sock, n); 12487c478bd9Sstevel@tonic-gate #endif 12497c478bd9Sstevel@tonic-gate mutex_init(&pcmcia_sockets[n]->ls_ilock, NULL, 12507c478bd9Sstevel@tonic-gate MUTEX_DRIVER, *adapter->an_iblock); 12517c478bd9Sstevel@tonic-gate } 12527c478bd9Sstevel@tonic-gate 12537c478bd9Sstevel@tonic-gate pcmcia_adapters[i]->pca_numsockets = conf.NumSockets; 12547c478bd9Sstevel@tonic-gate /* now setup the per window information */ 12557c478bd9Sstevel@tonic-gate for (win = 0; win < conf.NumWindows; win++) { 12567c478bd9Sstevel@tonic-gate n = win + pcmcia_num_windows; 12577c478bd9Sstevel@tonic-gate pcmcia_windows[n] = 12587c478bd9Sstevel@tonic-gate kmem_zalloc(sizeof (pcmcia_logical_window_t), 12597c478bd9Sstevel@tonic-gate KM_SLEEP); 12607c478bd9Sstevel@tonic-gate pcmcia_windows[n]->lw_window = win; 12617c478bd9Sstevel@tonic-gate pcmcia_windows[n]->lw_if = ls_if; 12627c478bd9Sstevel@tonic-gate pcmcia_windows[n]->lw_adapter = 12637c478bd9Sstevel@tonic-gate pcmcia_adapters[i]; 12647c478bd9Sstevel@tonic-gate } 12657c478bd9Sstevel@tonic-gate pcmcia_num_windows += conf.NumWindows; 12667c478bd9Sstevel@tonic-gate SET_CALLBACK(ls_if, dip, 12677c478bd9Sstevel@tonic-gate pcm_adapter_callback, i); 12687c478bd9Sstevel@tonic-gate 12697c478bd9Sstevel@tonic-gate /* now tell CS about each socket */ 12707c478bd9Sstevel@tonic-gate for (sock = 0; sock < pcmcia_num_sockets; sock++) { 12717c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 12727c478bd9Sstevel@tonic-gate if (pcmcia_debug) { 12737c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 12747c478bd9Sstevel@tonic-gate "pcmcia_init: notify CS socket %d " 12757c478bd9Sstevel@tonic-gate "sockp=%p\n", 12767c478bd9Sstevel@tonic-gate sock, (void *)pcmcia_sockets[sock]); 12777c478bd9Sstevel@tonic-gate } 12787c478bd9Sstevel@tonic-gate #endif 12797c478bd9Sstevel@tonic-gate if (pcmcia_sockets[sock] == NULL || 12807c478bd9Sstevel@tonic-gate (pcmcia_sockets[sock]->ls_flags & 12817c478bd9Sstevel@tonic-gate PCS_SOCKET_ADDED)) { 12827c478bd9Sstevel@tonic-gate /* skip the ones that are done already */ 12837c478bd9Sstevel@tonic-gate continue; 12847c478bd9Sstevel@tonic-gate } 12857c478bd9Sstevel@tonic-gate pcmcia_sockets[sock]->ls_flags |= PCS_SOCKET_ADDED; 12867c478bd9Sstevel@tonic-gate if (cs_event(PCE_ADD_SOCKET, sock, 0) != 12877c478bd9Sstevel@tonic-gate CS_SUCCESS) { 12887c478bd9Sstevel@tonic-gate /* flag socket as broken */ 12897c478bd9Sstevel@tonic-gate pcmcia_sockets[sock]->ls_flags = 0; 12907c478bd9Sstevel@tonic-gate } else { 12917c478bd9Sstevel@tonic-gate pcm_event_manager(PCE_ADD_SOCKET, 12927c478bd9Sstevel@tonic-gate sock, NULL); 12937c478bd9Sstevel@tonic-gate } 12947c478bd9Sstevel@tonic-gate } 12957c478bd9Sstevel@tonic-gate 12967c478bd9Sstevel@tonic-gate } 12977c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 12987c478bd9Sstevel@tonic-gate if (pcmcia_debug) { 12997c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "logical sockets:\n"); 13007c478bd9Sstevel@tonic-gate for (i = 0; i < pcmcia_num_sockets; i++) { 13017c478bd9Sstevel@tonic-gate if (pcmcia_sockets[i] == NULL) 13027c478bd9Sstevel@tonic-gate continue; 13037c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 13047c478bd9Sstevel@tonic-gate "\t%d: phys sock=%d, if=%p, adapt=%p\n", 13057c478bd9Sstevel@tonic-gate i, pcmcia_sockets[i]->ls_socket, 13067c478bd9Sstevel@tonic-gate (void *)pcmcia_sockets[i]->ls_if, 13077c478bd9Sstevel@tonic-gate (void *)pcmcia_sockets[i]->ls_adapter); 13087c478bd9Sstevel@tonic-gate } 13097c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "logical windows:\n"); 13107c478bd9Sstevel@tonic-gate for (i = 0; i < pcmcia_num_windows; i++) { 13117c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 13127c478bd9Sstevel@tonic-gate "\t%d: phys_window=%d, if=%p, adapt=%p\n", 13137c478bd9Sstevel@tonic-gate i, pcmcia_windows[i]->lw_window, 13147c478bd9Sstevel@tonic-gate (void *)pcmcia_windows[i]->lw_if, 13157c478bd9Sstevel@tonic-gate (void *)pcmcia_windows[i]->lw_adapter); 13167c478bd9Sstevel@tonic-gate } 13177c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "\tpcmcia_num_power=%d\n", pcmcia_num_power); 13187c478bd9Sstevel@tonic-gate for (n = 0; n < pcmcia_num_power; n++) 13197c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 13207c478bd9Sstevel@tonic-gate "\t\tPowerLevel: %d\tValidSignals: %x\n", 13217c478bd9Sstevel@tonic-gate pcmcia_power_table[n].PowerLevel, 13227c478bd9Sstevel@tonic-gate pcmcia_power_table[n].ValidSignals); 13237c478bd9Sstevel@tonic-gate } 13247c478bd9Sstevel@tonic-gate #endif 13257c478bd9Sstevel@tonic-gate } 13267c478bd9Sstevel@tonic-gate 13277c478bd9Sstevel@tonic-gate /* 13287c478bd9Sstevel@tonic-gate * pcmcia_find_cards() 13297c478bd9Sstevel@tonic-gate * check the adapter to see if there are cards present at 13307c478bd9Sstevel@tonic-gate * driver attach time. If there are, generate an artificial 13317c478bd9Sstevel@tonic-gate * card insertion event to get CS running and the PC Card ultimately 13327c478bd9Sstevel@tonic-gate * identified. 13337c478bd9Sstevel@tonic-gate */ 13347c478bd9Sstevel@tonic-gate void 13357c478bd9Sstevel@tonic-gate pcmcia_find_cards(anp_t *adapt) 13367c478bd9Sstevel@tonic-gate { 13377c478bd9Sstevel@tonic-gate int i; 13387c478bd9Sstevel@tonic-gate get_ss_status_t status; 13397c478bd9Sstevel@tonic-gate for (i = 0; i < pcmcia_num_sockets; i++) { 13407c478bd9Sstevel@tonic-gate if (pcmcia_sockets[i] && 13417c478bd9Sstevel@tonic-gate pcmcia_sockets[i]->ls_if == adapt->an_if) { 13427c478bd9Sstevel@tonic-gate /* check the status */ 13437c478bd9Sstevel@tonic-gate status.socket = i; 13447c478bd9Sstevel@tonic-gate if (SSGetStatus(&status) == SUCCESS && 1345a9fb0ae8Srw status.IFType != IF_CARDBUS && 13467c478bd9Sstevel@tonic-gate status.CardState & SBM_CD && 13477c478bd9Sstevel@tonic-gate pcmcia_sockets[i]->ls_dip[0] == NULL) { 13487c478bd9Sstevel@tonic-gate (void) cs_event(PCE_CARD_INSERT, i, 0); 13497c478bd9Sstevel@tonic-gate delay(1); 13507c478bd9Sstevel@tonic-gate } 13517c478bd9Sstevel@tonic-gate } 13527c478bd9Sstevel@tonic-gate } 13537c478bd9Sstevel@tonic-gate } 13547c478bd9Sstevel@tonic-gate 13557c478bd9Sstevel@tonic-gate /* 13567c478bd9Sstevel@tonic-gate * pcmcia_number_socket(dip, adapt) 13577c478bd9Sstevel@tonic-gate * we determine socket number by creating a driver for each 13587c478bd9Sstevel@tonic-gate * socket on the adapter and then forcing it to attach. This 13597c478bd9Sstevel@tonic-gate * results in an instance being assigned which becomes the 13607c478bd9Sstevel@tonic-gate * logical socket number. If it fails, then we are the first 13617c478bd9Sstevel@tonic-gate * set of sockets and renumbering occurs later. We do this 13627c478bd9Sstevel@tonic-gate * one socket at a time and return the dev_info_t so the 13637c478bd9Sstevel@tonic-gate * instance number can be used. 13647c478bd9Sstevel@tonic-gate */ 13657c478bd9Sstevel@tonic-gate dev_info_t * 13667c478bd9Sstevel@tonic-gate pcmcia_number_socket(dev_info_t *dip, int localsocket) 13677c478bd9Sstevel@tonic-gate { 13687c478bd9Sstevel@tonic-gate dev_info_t *child = NULL; 13697c478bd9Sstevel@tonic-gate struct pcmcia_parent_private *ppd; 13707c478bd9Sstevel@tonic-gate 1371fa9e4066Sahrens if (ndi_devi_alloc(dip, "pcs", (pnode_t)DEVI_SID_NODEID, 13727c478bd9Sstevel@tonic-gate &child) == NDI_SUCCESS) { 13737c478bd9Sstevel@tonic-gate ppd = kmem_zalloc(sizeof (struct pcmcia_parent_private), 13747c478bd9Sstevel@tonic-gate KM_SLEEP); 13757c478bd9Sstevel@tonic-gate ppd->ppd_reg = kmem_zalloc(sizeof (struct pcm_regs), KM_SLEEP); 13767c478bd9Sstevel@tonic-gate ppd->ppd_nreg = 1; 13777c478bd9Sstevel@tonic-gate ppd->ppd_reg[0].phys_hi = localsocket; 13787c478bd9Sstevel@tonic-gate ddi_set_parent_data(child, (caddr_t)ppd); 13797c478bd9Sstevel@tonic-gate if (ndi_devi_online(child, 0) != NDI_SUCCESS) { 1380981012acSrw kmem_free(ppd->ppd_reg, sizeof (struct pcm_regs)); 1381981012acSrw kmem_free(ppd, sizeof (struct pcmcia_parent_private)); 13827c478bd9Sstevel@tonic-gate (void) ndi_devi_free(child); 13837c478bd9Sstevel@tonic-gate child = NULL; 13847c478bd9Sstevel@tonic-gate } 13857c478bd9Sstevel@tonic-gate } 13867c478bd9Sstevel@tonic-gate return (child); 13877c478bd9Sstevel@tonic-gate } 13887c478bd9Sstevel@tonic-gate 13897c478bd9Sstevel@tonic-gate /* 13907c478bd9Sstevel@tonic-gate * pcm_phys_to_log_socket() 13917c478bd9Sstevel@tonic-gate * from an adapter and socket number return the logical socket 13927c478bd9Sstevel@tonic-gate */ 13937c478bd9Sstevel@tonic-gate int 13947c478bd9Sstevel@tonic-gate pcm_phys_to_log_socket(struct pcmcia_adapter *adapt, int socket) 13957c478bd9Sstevel@tonic-gate { 13967c478bd9Sstevel@tonic-gate register pcmcia_logical_socket_t *sockp; 13977c478bd9Sstevel@tonic-gate int i; 13987c478bd9Sstevel@tonic-gate 13997c478bd9Sstevel@tonic-gate for (i = 0, sockp = pcmcia_sockets[0]; 14007c478bd9Sstevel@tonic-gate i < pcmcia_num_sockets; i++, sockp = pcmcia_sockets[i]) { 14017c478bd9Sstevel@tonic-gate if (sockp == NULL) 14027c478bd9Sstevel@tonic-gate continue; 14037c478bd9Sstevel@tonic-gate if (sockp->ls_socket == socket && sockp->ls_adapter == adapt) 14047c478bd9Sstevel@tonic-gate break; 14057c478bd9Sstevel@tonic-gate } 14067c478bd9Sstevel@tonic-gate if (i >= pcmcia_num_sockets) { 14077c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 14087c478bd9Sstevel@tonic-gate if (pcmcia_debug) 14097c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 14107c478bd9Sstevel@tonic-gate "\tbad socket/adapter: %x/%p != %x/%x\n", 14117c478bd9Sstevel@tonic-gate socket, (void *)adapt, pcmcia_num_sockets, 14127c478bd9Sstevel@tonic-gate pcmcia_num_adapters); 14137c478bd9Sstevel@tonic-gate #endif 14147c478bd9Sstevel@tonic-gate return (-1); 14157c478bd9Sstevel@tonic-gate } 14167c478bd9Sstevel@tonic-gate 14177c478bd9Sstevel@tonic-gate return (i); /* want logical socket */ 14187c478bd9Sstevel@tonic-gate } 14197c478bd9Sstevel@tonic-gate 14207c478bd9Sstevel@tonic-gate /* 14217c478bd9Sstevel@tonic-gate * pcm_adapter_callback() 14227c478bd9Sstevel@tonic-gate * this function is called back by the adapter driver at interrupt time. 14237c478bd9Sstevel@tonic-gate * It is here that events should get generated for the event manager if it 14247c478bd9Sstevel@tonic-gate * is present. It would also be the time where a device information 14257c478bd9Sstevel@tonic-gate * tree could be constructed for a card that was added in if we 14267c478bd9Sstevel@tonic-gate * choose to create them dynamically. 14277c478bd9Sstevel@tonic-gate */ 14287c478bd9Sstevel@tonic-gate 14297c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 14307c478bd9Sstevel@tonic-gate char *cblist[] = { 14317c478bd9Sstevel@tonic-gate "removal", 14327c478bd9Sstevel@tonic-gate "insert", 14337c478bd9Sstevel@tonic-gate "ready", 14347c478bd9Sstevel@tonic-gate "battery-warn", 14357c478bd9Sstevel@tonic-gate "battery-dead", 14367c478bd9Sstevel@tonic-gate "status-change", 14377c478bd9Sstevel@tonic-gate "write-protect", "reset", "unlock", "client-info", "eject-complete", 14387c478bd9Sstevel@tonic-gate "eject-request", "erase-complete", "exclusive-complete", 14397c478bd9Sstevel@tonic-gate "exclusive-request", "insert-complete", "insert-request", 14407c478bd9Sstevel@tonic-gate "reset-complete", "reset-request", "timer-expired", 14417c478bd9Sstevel@tonic-gate "resume", "suspend" 14427c478bd9Sstevel@tonic-gate }; 14437c478bd9Sstevel@tonic-gate #endif 14447c478bd9Sstevel@tonic-gate 14457c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 14467c478bd9Sstevel@tonic-gate static int 14477c478bd9Sstevel@tonic-gate pcm_adapter_callback(dev_info_t *dip, int adapter, int event, int socket) 14487c478bd9Sstevel@tonic-gate { 14497c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t *sockp; 14507c478bd9Sstevel@tonic-gate 14517c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 14527c478bd9Sstevel@tonic-gate if (pcmcia_debug) { 14537c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcm_adapter_callback: %p %x %x %x: ", 14547c478bd9Sstevel@tonic-gate (void *)dip, adapter, event, socket); 14557c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "[%s]\n", cblist[event]); 14567c478bd9Sstevel@tonic-gate } 14577c478bd9Sstevel@tonic-gate #endif 14587c478bd9Sstevel@tonic-gate 14597c478bd9Sstevel@tonic-gate if (adapter >= pcmcia_num_adapters || adapter < 0) { 14607c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 14617c478bd9Sstevel@tonic-gate if (pcmcia_debug) 14627c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "\tbad adapter number: %d : %d\n", 14637c478bd9Sstevel@tonic-gate adapter, pcmcia_num_adapters); 14647c478bd9Sstevel@tonic-gate #endif 14657c478bd9Sstevel@tonic-gate return (1); 14667c478bd9Sstevel@tonic-gate } 14677c478bd9Sstevel@tonic-gate 14687c478bd9Sstevel@tonic-gate /* get the logical socket since that is what CS knows */ 14697c478bd9Sstevel@tonic-gate socket = pcm_phys_to_log_socket(pcmcia_adapters[adapter], socket); 14707c478bd9Sstevel@tonic-gate if (socket == -1) { 14717c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pcmcia callback - bad logical socket\n"); 14727c478bd9Sstevel@tonic-gate return (0); 14737c478bd9Sstevel@tonic-gate } 14747c478bd9Sstevel@tonic-gate sockp = pcmcia_sockets[socket]; 14757c478bd9Sstevel@tonic-gate switch (event) { 14767c478bd9Sstevel@tonic-gate case -1: /* special case of adapter going away */ 14777c478bd9Sstevel@tonic-gate case PCE_CARD_INSERT: 14787c478bd9Sstevel@tonic-gate sockp->ls_cs_events |= PCE_E2M(PCE_CARD_INSERT) | 14797c478bd9Sstevel@tonic-gate PCE_E2M(PCE_CARD_REMOVAL); 14807c478bd9Sstevel@tonic-gate break; 14817c478bd9Sstevel@tonic-gate case PCE_CARD_REMOVAL: 14827c478bd9Sstevel@tonic-gate /* disable interrupts at this point */ 14837c478bd9Sstevel@tonic-gate sockp->ls_cs_events |= PCE_E2M(PCE_CARD_INSERT) | 14847c478bd9Sstevel@tonic-gate PCE_E2M(PCE_CARD_REMOVAL); 14857c478bd9Sstevel@tonic-gate /* remove children that never attached */ 14867c478bd9Sstevel@tonic-gate 14877c478bd9Sstevel@tonic-gate break; 14887c478bd9Sstevel@tonic-gate case PCE_PM_RESUME: 14897c478bd9Sstevel@tonic-gate pcmcia_do_resume(socket, sockp); 14907c478bd9Sstevel@tonic-gate /* event = PCE_CARD_INSERT; */ 14917c478bd9Sstevel@tonic-gate break; 14927c478bd9Sstevel@tonic-gate case PCE_PM_SUSPEND: 14937c478bd9Sstevel@tonic-gate pcmcia_do_suspend(socket, sockp); 14947c478bd9Sstevel@tonic-gate /* event = PCE_CARD_REMOVAL; */ 14957c478bd9Sstevel@tonic-gate break; 14967c478bd9Sstevel@tonic-gate default: 14977c478bd9Sstevel@tonic-gate /* nothing to do */ 14987c478bd9Sstevel@tonic-gate break; 14997c478bd9Sstevel@tonic-gate } 15007c478bd9Sstevel@tonic-gate 15017c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 15027c478bd9Sstevel@tonic-gate if (pcmcia_debug) { 15037c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 15047c478bd9Sstevel@tonic-gate "\tevent %d, event mask=%x, match=%x (log socket=%d)\n", 15057c478bd9Sstevel@tonic-gate event, 15067c478bd9Sstevel@tonic-gate (int)sockp->ls_cs_events, 15077c478bd9Sstevel@tonic-gate (int)(sockp->ls_cs_events & PCE_E2M(event)), socket); 15087c478bd9Sstevel@tonic-gate } 15097c478bd9Sstevel@tonic-gate #endif 15107c478bd9Sstevel@tonic-gate 15117c478bd9Sstevel@tonic-gate if (pcmcia_cs_event && sockp->ls_cs_events & (1 << event)) { 15127c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 15137c478bd9Sstevel@tonic-gate if (pcmcia_debug) 15147c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "\tcalling CS event handler (%p) " 15157c478bd9Sstevel@tonic-gate "with event=%d\n", 15167c478bd9Sstevel@tonic-gate (void *)pcmcia_cs_event, event); 15177c478bd9Sstevel@tonic-gate #endif 15187c478bd9Sstevel@tonic-gate CS_EVENT(event, socket, 0); 15197c478bd9Sstevel@tonic-gate } 15207c478bd9Sstevel@tonic-gate 15217c478bd9Sstevel@tonic-gate /* let the event manager(s) know about the event */ 15227c478bd9Sstevel@tonic-gate pcm_event_manager(event, socket, NULL); 15237c478bd9Sstevel@tonic-gate 15247c478bd9Sstevel@tonic-gate return (0); 15257c478bd9Sstevel@tonic-gate } 15267c478bd9Sstevel@tonic-gate 15277c478bd9Sstevel@tonic-gate /* 15287c478bd9Sstevel@tonic-gate * pcm_event_manager() 15297c478bd9Sstevel@tonic-gate * checks for registered management driver callback handlers 15307c478bd9Sstevel@tonic-gate * if there are any, call them if the event warrants it 15317c478bd9Sstevel@tonic-gate */ 15327c478bd9Sstevel@tonic-gate void 15337c478bd9Sstevel@tonic-gate pcm_event_manager(int event, int socket, void *arg) 15347c478bd9Sstevel@tonic-gate { 15357c478bd9Sstevel@tonic-gate struct pcmcia_mif *mif; 15367c478bd9Sstevel@tonic-gate 15377c478bd9Sstevel@tonic-gate for (mif = pcmcia_mif_handlers; mif != NULL; mif = mif->mif_next) { 15387c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 15397c478bd9Sstevel@tonic-gate if (pcmcia_debug) 15407c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 15417c478bd9Sstevel@tonic-gate "pcm_event_manager: event=%d, mif_events=%x" 15427c478bd9Sstevel@tonic-gate " (tst:%d)\n", 15437c478bd9Sstevel@tonic-gate event, (int)*(uint32_t *)mif->mif_events, 15447c478bd9Sstevel@tonic-gate PR_GET(mif->mif_events, event)); 15457c478bd9Sstevel@tonic-gate #endif 15467c478bd9Sstevel@tonic-gate if (PR_GET(mif->mif_events, event)) { 15477c478bd9Sstevel@tonic-gate mif->mif_function(mif->mif_id, event, socket, arg); 15487c478bd9Sstevel@tonic-gate } 15497c478bd9Sstevel@tonic-gate } 15507c478bd9Sstevel@tonic-gate 15517c478bd9Sstevel@tonic-gate } 15527c478bd9Sstevel@tonic-gate 15537c478bd9Sstevel@tonic-gate /* 15547c478bd9Sstevel@tonic-gate * pcm_search_devinfo(dev_info_t *, pcm_device_info *, int) 15557c478bd9Sstevel@tonic-gate * search for an immediate child node to the nexus and not siblings of nexus 15567c478bd9Sstevel@tonic-gate * and not grandchildren. We follow the same sequence that name binding 15577c478bd9Sstevel@tonic-gate * follows so we match same class of device (modem == modem) and don't 15587c478bd9Sstevel@tonic-gate * have to depend on features that might not exist. 15597c478bd9Sstevel@tonic-gate */ 15607c478bd9Sstevel@tonic-gate dev_info_t * 15617c478bd9Sstevel@tonic-gate pcm_search_devinfo(dev_info_t *self, struct pcm_device_info *info, int socket) 15627c478bd9Sstevel@tonic-gate { 15637c478bd9Sstevel@tonic-gate char bf[256]; 15647c478bd9Sstevel@tonic-gate struct pcmcia_parent_private *ppd; 15657c478bd9Sstevel@tonic-gate dev_info_t *dip; 1566b9ccdc5aScth int circ; 15677c478bd9Sstevel@tonic-gate 15687c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 15697c478bd9Sstevel@tonic-gate if (pcmcia_debug) 15707c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 15717c478bd9Sstevel@tonic-gate "pcm_search_devinfo: socket=%x [%s|%s|%s] pd_flags=%x\n", 15727c478bd9Sstevel@tonic-gate socket, info->pd_bind_name, info->pd_generic_name, 15737c478bd9Sstevel@tonic-gate info->pd_vers1_name, info->pd_flags); 15747c478bd9Sstevel@tonic-gate #endif 15757c478bd9Sstevel@tonic-gate 1576b9ccdc5aScth ndi_devi_enter(self, &circ); 15777c478bd9Sstevel@tonic-gate /* do searches in compatible property order */ 15787c478bd9Sstevel@tonic-gate for (dip = (dev_info_t *)DEVI(self)->devi_child; 15797c478bd9Sstevel@tonic-gate dip != NULL; 15807c478bd9Sstevel@tonic-gate dip = (dev_info_t *)DEVI(dip)->devi_sibling) { 15817c478bd9Sstevel@tonic-gate int ppd_socket; 15827c478bd9Sstevel@tonic-gate ppd = (struct pcmcia_parent_private *) 15837c478bd9Sstevel@tonic-gate ddi_get_parent_data(dip); 15847c478bd9Sstevel@tonic-gate if (ppd == NULL) { 15857c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 15867c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "No parent private data\n"); 15877c478bd9Sstevel@tonic-gate #endif 15887c478bd9Sstevel@tonic-gate continue; 15897c478bd9Sstevel@tonic-gate } 15907c478bd9Sstevel@tonic-gate ppd_socket = CS_MAKE_SOCKET_NUMBER(ppd->ppd_socket, 15917c478bd9Sstevel@tonic-gate ppd->ppd_function); 15927c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 15937c478bd9Sstevel@tonic-gate if (pcmcia_debug) { 15947c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "\tbind=[%s], node=[%s]\n", 15957c478bd9Sstevel@tonic-gate DEVI(dip)->devi_binding_name, 15967c478bd9Sstevel@tonic-gate DEVI(dip)->devi_node_name); 15977c478bd9Sstevel@tonic-gate } 15987c478bd9Sstevel@tonic-gate #endif 15997c478bd9Sstevel@tonic-gate if (info->pd_flags & PCM_NAME_VERS1) { 16007c478bd9Sstevel@tonic-gate (void) strcpy(bf, info->pd_vers1_name); 16017c478bd9Sstevel@tonic-gate pcmcia_fix_string(bf); 16027c478bd9Sstevel@tonic-gate if (DEVI(dip)->devi_binding_name && 16037c478bd9Sstevel@tonic-gate strcmp(DEVI(dip)->devi_binding_name, bf) == 0 && 16047c478bd9Sstevel@tonic-gate socket == ppd_socket) 16057c478bd9Sstevel@tonic-gate break; 16067c478bd9Sstevel@tonic-gate } 16077c478bd9Sstevel@tonic-gate if ((info->pd_flags & (PCM_NAME_1275 | PCM_MULTI_FUNCTION)) == 16087c478bd9Sstevel@tonic-gate (PCM_NAME_1275 | PCM_MULTI_FUNCTION)) { 16097c478bd9Sstevel@tonic-gate (void) sprintf(bf, "%s,%x", info->pd_bind_name, 16107c478bd9Sstevel@tonic-gate info->pd_function); 16117c478bd9Sstevel@tonic-gate if (strcmp(bf, DEVI(dip)->devi_binding_name) == 0 && 16127c478bd9Sstevel@tonic-gate socket == ppd->ppd_socket) 16137c478bd9Sstevel@tonic-gate break; 16147c478bd9Sstevel@tonic-gate } 16157c478bd9Sstevel@tonic-gate if (info->pd_flags & PCM_NAME_1275) { 16167c478bd9Sstevel@tonic-gate if (DEVI(dip)->devi_binding_name && 16177c478bd9Sstevel@tonic-gate strcmp(DEVI(dip)->devi_binding_name, 16187c478bd9Sstevel@tonic-gate info->pd_bind_name) == 0 && 16197c478bd9Sstevel@tonic-gate socket == ppd_socket) 16207c478bd9Sstevel@tonic-gate break; 16217c478bd9Sstevel@tonic-gate } 16227c478bd9Sstevel@tonic-gate if (info->pd_flags & PCM_NAME_GENERIC) { 16237c478bd9Sstevel@tonic-gate (void) sprintf(bf, "%s,%s", PCMDEV_NAMEPREF, 16247c478bd9Sstevel@tonic-gate info->pd_generic_name); 16257c478bd9Sstevel@tonic-gate if (DEVI(dip)->devi_binding_name && 16267c478bd9Sstevel@tonic-gate strcmp(DEVI(dip)->devi_binding_name, bf) == 0 && 16277c478bd9Sstevel@tonic-gate socket == ppd_socket) 16287c478bd9Sstevel@tonic-gate break; 16297c478bd9Sstevel@tonic-gate } 16307c478bd9Sstevel@tonic-gate if (info->pd_flags & PCM_NAME_GENERIC) { 16317c478bd9Sstevel@tonic-gate if (DEVI(dip)->devi_binding_name && 16327c478bd9Sstevel@tonic-gate strcmp(DEVI(dip)->devi_binding_name, 16337c478bd9Sstevel@tonic-gate info->pd_generic_name) == 0 && 16347c478bd9Sstevel@tonic-gate socket == ppd_socket) 16357c478bd9Sstevel@tonic-gate break; 16367c478bd9Sstevel@tonic-gate } 16377c478bd9Sstevel@tonic-gate if (info->pd_flags & PCM_NO_CONFIG) { 16387c478bd9Sstevel@tonic-gate if (DEVI(dip)->devi_binding_name && 16397c478bd9Sstevel@tonic-gate strcmp(DEVI(dip)->devi_binding_name, 16407c478bd9Sstevel@tonic-gate "pccard,memory") == 0 && 16417c478bd9Sstevel@tonic-gate socket == ppd_socket) 16427c478bd9Sstevel@tonic-gate break; 16437c478bd9Sstevel@tonic-gate } 16447c478bd9Sstevel@tonic-gate } 1645b9ccdc5aScth ndi_devi_exit(self, circ); 16467c478bd9Sstevel@tonic-gate return (dip); 16477c478bd9Sstevel@tonic-gate } 16487c478bd9Sstevel@tonic-gate 16497c478bd9Sstevel@tonic-gate /* 16507c478bd9Sstevel@tonic-gate * pcm_find_devinfo() 16517c478bd9Sstevel@tonic-gate * this is a wrapper around DDI calls to "find" any 16527c478bd9Sstevel@tonic-gate * devinfo node and then from there find the one associated 16537c478bd9Sstevel@tonic-gate * with the socket 16547c478bd9Sstevel@tonic-gate */ 16557c478bd9Sstevel@tonic-gate dev_info_t * 16567c478bd9Sstevel@tonic-gate pcm_find_devinfo(dev_info_t *pdip, struct pcm_device_info *info, int socket) 16577c478bd9Sstevel@tonic-gate { 16587c478bd9Sstevel@tonic-gate dev_info_t *dip; 16597c478bd9Sstevel@tonic-gate 16607c478bd9Sstevel@tonic-gate dip = pcm_search_devinfo(pdip, info, socket); 16617c478bd9Sstevel@tonic-gate if (dip == NULL) 16627c478bd9Sstevel@tonic-gate return (NULL); 16637c478bd9Sstevel@tonic-gate /* 16647c478bd9Sstevel@tonic-gate * we have at least a base level dip 16657c478bd9Sstevel@tonic-gate * see if there is one (this or a sibling) 16667c478bd9Sstevel@tonic-gate * that has the correct socket number 16677c478bd9Sstevel@tonic-gate * if there is, return that one else 16687c478bd9Sstevel@tonic-gate * NULL so a new one is created 16697c478bd9Sstevel@tonic-gate */ 16707c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 16717c478bd9Sstevel@tonic-gate if (pcmcia_debug) 16727c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "find: initial dip = %p, socket=%d, name=%s " 16737c478bd9Sstevel@tonic-gate "(instance=%d, socket=%d, name=%s)\n", 16747c478bd9Sstevel@tonic-gate (void *)dip, socket, info->pd_bind_name, 16757c478bd9Sstevel@tonic-gate ddi_get_instance(dip), 16767c478bd9Sstevel@tonic-gate ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 16777c478bd9Sstevel@tonic-gate PCM_DEV_SOCKET, -1), 16787c478bd9Sstevel@tonic-gate ddi_get_name(dip)); 16797c478bd9Sstevel@tonic-gate #endif 16807c478bd9Sstevel@tonic-gate 16817c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 16827c478bd9Sstevel@tonic-gate if (pcmcia_debug && dip != NULL) 16837c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "\treturning non-NULL dip (%s)\n", 16847c478bd9Sstevel@tonic-gate ddi_get_name(dip)); 16857c478bd9Sstevel@tonic-gate #endif 16867c478bd9Sstevel@tonic-gate return (dip); 16877c478bd9Sstevel@tonic-gate } 16887c478bd9Sstevel@tonic-gate 16897c478bd9Sstevel@tonic-gate /* 16907c478bd9Sstevel@tonic-gate * pcm_find_parent_dip(socket) 16917c478bd9Sstevel@tonic-gate * find the correct parent dip for this logical socket 16927c478bd9Sstevel@tonic-gate */ 16937c478bd9Sstevel@tonic-gate dev_info_t * 16947c478bd9Sstevel@tonic-gate pcm_find_parent_dip(int socket) 16957c478bd9Sstevel@tonic-gate { 16967c478bd9Sstevel@tonic-gate if ((socket < 0 || socket >= pcmcia_num_sockets) || 16977c478bd9Sstevel@tonic-gate pcmcia_sockets[socket] == NULL) 16987c478bd9Sstevel@tonic-gate return (NULL); 16997c478bd9Sstevel@tonic-gate return (pcmcia_sockets[socket]->ls_adapter->pca_dip); 17007c478bd9Sstevel@tonic-gate } 17017c478bd9Sstevel@tonic-gate 17027c478bd9Sstevel@tonic-gate /* 17037c478bd9Sstevel@tonic-gate * pcmcia_set_em_handler() 17047c478bd9Sstevel@tonic-gate * This is called by the management and event driver to tell 17057c478bd9Sstevel@tonic-gate * the nexus what to call. Multiple drivers are allowed 17067c478bd9Sstevel@tonic-gate * but normally only one will exist. 17077c478bd9Sstevel@tonic-gate */ 17087c478bd9Sstevel@tonic-gate int 17097c478bd9Sstevel@tonic-gate pcmcia_set_em_handler(int (*handler)(), caddr_t events, int elen, 17107c478bd9Sstevel@tonic-gate uint32_t id, void **cs, void **ss) 17117c478bd9Sstevel@tonic-gate { 17127c478bd9Sstevel@tonic-gate struct pcmcia_mif *mif, *tmp; 17137c478bd9Sstevel@tonic-gate 17147c478bd9Sstevel@tonic-gate if (handler == NULL) { 17157c478bd9Sstevel@tonic-gate /* NULL means remove the handler based on the ID */ 17167c478bd9Sstevel@tonic-gate if (pcmcia_mif_handlers == NULL) 17177c478bd9Sstevel@tonic-gate return (0); 17187c478bd9Sstevel@tonic-gate mutex_enter(&pcmcia_global_lock); 17197c478bd9Sstevel@tonic-gate if (pcmcia_mif_handlers->mif_id == id) { 17207c478bd9Sstevel@tonic-gate mif = pcmcia_mif_handlers; 17217c478bd9Sstevel@tonic-gate pcmcia_mif_handlers = mif->mif_next; 17227c478bd9Sstevel@tonic-gate kmem_free(mif, sizeof (struct pcmcia_mif)); 17237c478bd9Sstevel@tonic-gate } else { 17247c478bd9Sstevel@tonic-gate for (mif = pcmcia_mif_handlers; 17257c478bd9Sstevel@tonic-gate mif->mif_next != NULL && 17267c478bd9Sstevel@tonic-gate mif->mif_next->mif_id != id; 17277c478bd9Sstevel@tonic-gate mif = mif->mif_next) 17287c478bd9Sstevel@tonic-gate ; 17297c478bd9Sstevel@tonic-gate if (mif->mif_next != NULL && 17307c478bd9Sstevel@tonic-gate mif->mif_next->mif_id == id) { 17317c478bd9Sstevel@tonic-gate tmp = mif->mif_next; 17327c478bd9Sstevel@tonic-gate mif->mif_next = tmp->mif_next; 17337c478bd9Sstevel@tonic-gate kmem_free(tmp, sizeof (struct pcmcia_mif)); 17347c478bd9Sstevel@tonic-gate } 17357c478bd9Sstevel@tonic-gate } 17367c478bd9Sstevel@tonic-gate mutex_exit(&pcmcia_global_lock); 17377c478bd9Sstevel@tonic-gate } else { 17387c478bd9Sstevel@tonic-gate 17397c478bd9Sstevel@tonic-gate if (pcmcia_num_adapters == 0) { 17407c478bd9Sstevel@tonic-gate return (ENXIO); 17417c478bd9Sstevel@tonic-gate } 17427c478bd9Sstevel@tonic-gate if (elen > EM_EVENTSIZE) 17437c478bd9Sstevel@tonic-gate return (EINVAL); 17447c478bd9Sstevel@tonic-gate 17457c478bd9Sstevel@tonic-gate mif = (struct pcmcia_mif *) 17467c478bd9Sstevel@tonic-gate kmem_zalloc(sizeof (struct pcmcia_mif), 17477c478bd9Sstevel@tonic-gate KM_NOSLEEP); 17487c478bd9Sstevel@tonic-gate if (mif == NULL) 17497c478bd9Sstevel@tonic-gate return (ENOSPC); 17507c478bd9Sstevel@tonic-gate 17517c478bd9Sstevel@tonic-gate mif->mif_function = (void (*)())handler; 17527c478bd9Sstevel@tonic-gate bcopy(events, mif->mif_events, elen); 17537c478bd9Sstevel@tonic-gate mif->mif_id = id; 17547c478bd9Sstevel@tonic-gate mutex_enter(&pcmcia_global_lock); 17557c478bd9Sstevel@tonic-gate mif->mif_next = pcmcia_mif_handlers; 17567c478bd9Sstevel@tonic-gate pcmcia_mif_handlers = mif; 17577c478bd9Sstevel@tonic-gate if (cs != NULL) 17587c478bd9Sstevel@tonic-gate *cs = (void *)pcmcia_card_services; 17597c478bd9Sstevel@tonic-gate if (ss != NULL) { 17607c478bd9Sstevel@tonic-gate *ss = (void *)SocketServices; 17617c478bd9Sstevel@tonic-gate } 17627c478bd9Sstevel@tonic-gate 17637c478bd9Sstevel@tonic-gate mutex_exit(&pcmcia_global_lock); 17647c478bd9Sstevel@tonic-gate } 17657c478bd9Sstevel@tonic-gate return (0); 17667c478bd9Sstevel@tonic-gate } 17677c478bd9Sstevel@tonic-gate 17687c478bd9Sstevel@tonic-gate /* 17697c478bd9Sstevel@tonic-gate * pcm_fix_bits(uchar_t *data, int num, int dir) 17707c478bd9Sstevel@tonic-gate * shift socket bits left(0) or right(0) 17717c478bd9Sstevel@tonic-gate * This is used when mapping logical and physical 17727c478bd9Sstevel@tonic-gate */ 17737c478bd9Sstevel@tonic-gate void 17747c478bd9Sstevel@tonic-gate pcm_fix_bits(socket_enum_t src, socket_enum_t dst, int num, int dir) 17757c478bd9Sstevel@tonic-gate { 17767c478bd9Sstevel@tonic-gate int i; 17777c478bd9Sstevel@tonic-gate 17787c478bd9Sstevel@tonic-gate PR_ZERO(dst); 17797c478bd9Sstevel@tonic-gate 17807c478bd9Sstevel@tonic-gate if (dir == 0) { 17817c478bd9Sstevel@tonic-gate /* LEFT */ 17827c478bd9Sstevel@tonic-gate for (i = 0; i <= (sizeof (dst) * PR_WORDSIZE) - num; i++) { 17837c478bd9Sstevel@tonic-gate if (PR_GET(src, i)) 17847c478bd9Sstevel@tonic-gate PR_SET(dst, i + num); 17857c478bd9Sstevel@tonic-gate } 17867c478bd9Sstevel@tonic-gate } else { 17877c478bd9Sstevel@tonic-gate /* RIGHT */ 17887c478bd9Sstevel@tonic-gate for (i = num; i < sizeof (dst) * PR_WORDSIZE; i++) { 17897c478bd9Sstevel@tonic-gate if (PR_GET(src, i)) 17907c478bd9Sstevel@tonic-gate PR_SET(dst, i - num); 17917c478bd9Sstevel@tonic-gate } 17927c478bd9Sstevel@tonic-gate } 17937c478bd9Sstevel@tonic-gate } 17947c478bd9Sstevel@tonic-gate 17957c478bd9Sstevel@tonic-gate uint32_t 17967c478bd9Sstevel@tonic-gate genmask(int len) 17977c478bd9Sstevel@tonic-gate { 17987c478bd9Sstevel@tonic-gate uint32_t mask; 17997c478bd9Sstevel@tonic-gate for (mask = 0; len > 0; len--) { 18007c478bd9Sstevel@tonic-gate mask |= 1 << (len - 1); 18017c478bd9Sstevel@tonic-gate } 18027c478bd9Sstevel@tonic-gate return (mask); 18037c478bd9Sstevel@tonic-gate } 18047c478bd9Sstevel@tonic-gate 18057c478bd9Sstevel@tonic-gate int 18067c478bd9Sstevel@tonic-gate genp2(int val) 18077c478bd9Sstevel@tonic-gate { 18087c478bd9Sstevel@tonic-gate int i; 18097c478bd9Sstevel@tonic-gate if (val == 0) 18107c478bd9Sstevel@tonic-gate return (0); 18117c478bd9Sstevel@tonic-gate for (i = 0; i < 32; i++) 18127c478bd9Sstevel@tonic-gate if (val > (1 << i)) 18137c478bd9Sstevel@tonic-gate return (i); 18147c478bd9Sstevel@tonic-gate return (0); 18157c478bd9Sstevel@tonic-gate } 18167c478bd9Sstevel@tonic-gate 18177c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 18187c478bd9Sstevel@tonic-gate char *ssfuncs[128] = { 18197c478bd9Sstevel@tonic-gate "GetAdapter", "GetPage", "GetSocket", "GetStatus", "GetWindow", 18207c478bd9Sstevel@tonic-gate "InquireAdapter", "InquireSocket", "InquireWindow", "ResetSocket", 18217c478bd9Sstevel@tonic-gate "SetPage", "SetAdapter", "SetSocket", "SetWindow", "SetIRQHandler", 18227c478bd9Sstevel@tonic-gate "ClearIRQHandler", 18237c478bd9Sstevel@tonic-gate /* 15 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 18247c478bd9Sstevel@tonic-gate /* 25 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 18257c478bd9Sstevel@tonic-gate /* 35 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 18267c478bd9Sstevel@tonic-gate /* 45 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 18277c478bd9Sstevel@tonic-gate /* 55 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 18287c478bd9Sstevel@tonic-gate /* 65 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 18297c478bd9Sstevel@tonic-gate /* 75 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 18307c478bd9Sstevel@tonic-gate /* 85 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 18317c478bd9Sstevel@tonic-gate /* 95 */ NULL, NULL, NULL, 18327c478bd9Sstevel@tonic-gate "CSIsActiveDip", 18337c478bd9Sstevel@tonic-gate "CSInitDev", "CSRegister", "CSCISInit", "CSUnregister", 18347c478bd9Sstevel@tonic-gate "CISGetAddress", "CISSetAddress", "CSCardRemoved", "CSGetCookiesAndDip" 18357c478bd9Sstevel@tonic-gate }; 18367c478bd9Sstevel@tonic-gate #endif 18377c478bd9Sstevel@tonic-gate 18387c478bd9Sstevel@tonic-gate /* 18397c478bd9Sstevel@tonic-gate * SocketServices 18407c478bd9Sstevel@tonic-gate * general entrypoint for Card Services to find 18417c478bd9Sstevel@tonic-gate * Socket Services. Finding the entry requires 18427c478bd9Sstevel@tonic-gate * a _depends_on[] relationship. 18437c478bd9Sstevel@tonic-gate * 18447c478bd9Sstevel@tonic-gate * In some cases, the work is done locally but usually 18457c478bd9Sstevel@tonic-gate * the parameters are adjusted and the adapter driver 18467c478bd9Sstevel@tonic-gate * code asked to do the work. 18477c478bd9Sstevel@tonic-gate */ 18487c478bd9Sstevel@tonic-gate int 18497c478bd9Sstevel@tonic-gate SocketServices(int function, ...) 18507c478bd9Sstevel@tonic-gate { 18517c478bd9Sstevel@tonic-gate va_list arglist; 18527c478bd9Sstevel@tonic-gate uint32_t args[16]; 18537c478bd9Sstevel@tonic-gate csregister_t *reg; 18547c478bd9Sstevel@tonic-gate sservice_t *serv; 18557c478bd9Sstevel@tonic-gate dev_info_t *dip; 18567c478bd9Sstevel@tonic-gate int socket, func; 18577c478bd9Sstevel@tonic-gate int error = SUCCESS; 18587c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t *sockp; 18597c478bd9Sstevel@tonic-gate 18607c478bd9Sstevel@tonic-gate va_start(arglist, function); 18617c478bd9Sstevel@tonic-gate 18627c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 18637c478bd9Sstevel@tonic-gate if (pcmcia_debug > 1) 18647c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "SocketServices called for function %d [%s]\n", 18657c478bd9Sstevel@tonic-gate function, 18667c478bd9Sstevel@tonic-gate ((function < 128) && ssfuncs[function] != NULL) ? 18677c478bd9Sstevel@tonic-gate ssfuncs[function] : "UNKNOWN"); 18687c478bd9Sstevel@tonic-gate #endif 18697c478bd9Sstevel@tonic-gate switch (function) { 18707c478bd9Sstevel@tonic-gate case CSRegister: 18717c478bd9Sstevel@tonic-gate case CISGetAddress: 18727c478bd9Sstevel@tonic-gate case CISSetAddress: 18737c478bd9Sstevel@tonic-gate 18747c478bd9Sstevel@tonic-gate reg = va_arg(arglist, csregister_t *); 18757c478bd9Sstevel@tonic-gate 18767c478bd9Sstevel@tonic-gate if (reg->cs_magic != PCCS_MAGIC || 18777c478bd9Sstevel@tonic-gate reg->cs_version != PCCS_VERSION) { 18787c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 18797c478bd9Sstevel@tonic-gate "pcmcia: CSRegister (%x, %x, %p, %p) *ERROR*", 18807c478bd9Sstevel@tonic-gate reg->cs_magic, reg->cs_version, 18817c478bd9Sstevel@tonic-gate (void *)reg->cs_card_services, 18827c478bd9Sstevel@tonic-gate (void *)reg->cs_event); 18837c478bd9Sstevel@tonic-gate error = BAD_FUNCTION; 18847c478bd9Sstevel@tonic-gate break; 18857c478bd9Sstevel@tonic-gate } 18867c478bd9Sstevel@tonic-gate 18877c478bd9Sstevel@tonic-gate switch (function) { 18887c478bd9Sstevel@tonic-gate case CISGetAddress: 18897c478bd9Sstevel@tonic-gate reg->cs_event = pcmcia_cis_parser; 18907c478bd9Sstevel@tonic-gate break; 18917c478bd9Sstevel@tonic-gate case CISSetAddress: 18927c478bd9Sstevel@tonic-gate pcmcia_cis_parser = reg->cs_event; 18937c478bd9Sstevel@tonic-gate break; 18947c478bd9Sstevel@tonic-gate case CSRegister: 18957c478bd9Sstevel@tonic-gate break; 18967c478bd9Sstevel@tonic-gate } 18977c478bd9Sstevel@tonic-gate break; 18987c478bd9Sstevel@tonic-gate 18997c478bd9Sstevel@tonic-gate case CSUnregister: 19007c478bd9Sstevel@tonic-gate break; 19017c478bd9Sstevel@tonic-gate 19027c478bd9Sstevel@tonic-gate case CSCISInit: 19037c478bd9Sstevel@tonic-gate args[0] = va_arg(arglist, int); 19047c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 19057c478bd9Sstevel@tonic-gate if (pcmcia_debug) 19067c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 19077c478bd9Sstevel@tonic-gate "CSCISInit: CIS is initialized on socket %d\n", 19087c478bd9Sstevel@tonic-gate (int)args[0]); 19097c478bd9Sstevel@tonic-gate #endif 19107c478bd9Sstevel@tonic-gate /* 19117c478bd9Sstevel@tonic-gate * now that the CIS has been parsed (there may not 19127c478bd9Sstevel@tonic-gate * be one but the work is done) we can create the 19137c478bd9Sstevel@tonic-gate * device information structures. 19147c478bd9Sstevel@tonic-gate * 19157c478bd9Sstevel@tonic-gate * we serialize the node creation to avoid problems 19167c478bd9Sstevel@tonic-gate * with initial probe/attach of nexi. 19177c478bd9Sstevel@tonic-gate */ 19187c478bd9Sstevel@tonic-gate 19197c478bd9Sstevel@tonic-gate mutex_enter(&pcmcia_global_lock); 19207c478bd9Sstevel@tonic-gate pcmcia_create_dev_info(args[0]); 19217c478bd9Sstevel@tonic-gate cv_broadcast(&pcmcia_condvar); /* wakeup the nexus attach */ 19227c478bd9Sstevel@tonic-gate mutex_exit(&pcmcia_global_lock); 19237c478bd9Sstevel@tonic-gate break; 19247c478bd9Sstevel@tonic-gate 19257c478bd9Sstevel@tonic-gate case CSInitDev: 19267c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 19277c478bd9Sstevel@tonic-gate if (pcmcia_debug) 19287c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "CSInitDev: initialize device\n"); 19297c478bd9Sstevel@tonic-gate #endif 19307c478bd9Sstevel@tonic-gate /* 19317c478bd9Sstevel@tonic-gate * this is where we create the /devices entries 19327c478bd9Sstevel@tonic-gate * that let us out into the world 19337c478bd9Sstevel@tonic-gate */ 19347c478bd9Sstevel@tonic-gate 19357c478bd9Sstevel@tonic-gate (void) pcmcia_create_device(va_arg(arglist, 19367c478bd9Sstevel@tonic-gate ss_make_device_node_t *)); 19377c478bd9Sstevel@tonic-gate break; 19387c478bd9Sstevel@tonic-gate 19397c478bd9Sstevel@tonic-gate case CSCardRemoved: 19407c478bd9Sstevel@tonic-gate args[0] = va_arg(arglist, uint32_t); 19417c478bd9Sstevel@tonic-gate socket = CS_GET_SOCKET_NUMBER(args[0]); 19427c478bd9Sstevel@tonic-gate func = CS_GET_FUNCTION_NUMBER(args[0]); 19437c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 19447c478bd9Sstevel@tonic-gate if (pcmcia_debug) 19457c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 19467c478bd9Sstevel@tonic-gate "CSCardRemoved! (socket=%d)\n", (int)args[0]); 19477c478bd9Sstevel@tonic-gate #endif 19487c478bd9Sstevel@tonic-gate if (socket >= pcmcia_num_sockets) 19497c478bd9Sstevel@tonic-gate break; 19507c478bd9Sstevel@tonic-gate 19517c478bd9Sstevel@tonic-gate sockp = pcmcia_sockets[socket]; 19527c478bd9Sstevel@tonic-gate if (sockp == NULL) { 19537c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 19547c478bd9Sstevel@tonic-gate "pcmcia: bad socket = %x", socket); 19557c478bd9Sstevel@tonic-gate break; 19567c478bd9Sstevel@tonic-gate } 19577c478bd9Sstevel@tonic-gate 195811c2b4c0Srw if (!(sockp->ls_flags & PCS_SUSPENDED)) { 195911c2b4c0Srw for (func = 0; func < sockp->ls_functions; func++) { 196011c2b4c0Srw /* 196111c2b4c0Srw * break the association of dip and socket 196211c2b4c0Srw * for all functions on that socket 196311c2b4c0Srw */ 196411c2b4c0Srw dip = sockp->ls_dip[func]; 196511c2b4c0Srw sockp->ls_dip[func] = NULL; 196611c2b4c0Srw if (dip != NULL) { 196711c2b4c0Srw struct pcmcia_parent_private *ppd; 196811c2b4c0Srw ppd = (struct pcmcia_parent_private *) 196911c2b4c0Srw ddi_get_parent_data(dip); 197011c2b4c0Srw ppd->ppd_active = 0; 197111c2b4c0Srw (void) ndi_devi_offline(dip, 197211c2b4c0Srw NDI_DEVI_REMOVE); 197311c2b4c0Srw 197411c2b4c0Srw pcmcia_ppd_free(ppd); 197511c2b4c0Srw } 19767c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 197711c2b4c0Srw else { 197811c2b4c0Srw if (pcmcia_debug) 197911c2b4c0Srw cmn_err(CE_CONT, 198011c2b4c0Srw "CardRemoved: no " 198111c2b4c0Srw "dip present " 198211c2b4c0Srw "on socket %d!\n", 198311c2b4c0Srw (int)args[0]); 198411c2b4c0Srw } 19857c478bd9Sstevel@tonic-gate #endif 198611c2b4c0Srw } 198711c2b4c0Srw } else { 19887c478bd9Sstevel@tonic-gate mutex_enter(&pcmcia_global_lock); 19897c478bd9Sstevel@tonic-gate sockp->ls_flags &= ~PCS_SUSPENDED; 19907c478bd9Sstevel@tonic-gate cv_broadcast(&pcmcia_condvar); 19917c478bd9Sstevel@tonic-gate mutex_exit(&pcmcia_global_lock); 19927c478bd9Sstevel@tonic-gate } 19937c478bd9Sstevel@tonic-gate break; 19947c478bd9Sstevel@tonic-gate 19957c478bd9Sstevel@tonic-gate case CSGetCookiesAndDip: 19967c478bd9Sstevel@tonic-gate serv = va_arg(arglist, sservice_t *); 19977c478bd9Sstevel@tonic-gate if (serv != NULL) 19987c478bd9Sstevel@tonic-gate error = GetCookiesAndDip(serv); 19997c478bd9Sstevel@tonic-gate else 20007c478bd9Sstevel@tonic-gate error = BAD_SOCKET; 20017c478bd9Sstevel@tonic-gate break; 20027c478bd9Sstevel@tonic-gate 20037c478bd9Sstevel@tonic-gate case CSGetActiveDip: 20047c478bd9Sstevel@tonic-gate /* 20057c478bd9Sstevel@tonic-gate * get the dip associated with the card currently 20067c478bd9Sstevel@tonic-gate * in the specified socket 20077c478bd9Sstevel@tonic-gate */ 20087c478bd9Sstevel@tonic-gate args[0] = va_arg(arglist, uint32_t); 20097c478bd9Sstevel@tonic-gate socket = CS_GET_SOCKET_NUMBER(args[0]); 20107c478bd9Sstevel@tonic-gate func = CS_GET_FUNCTION_NUMBER(args[0]); 20117c478bd9Sstevel@tonic-gate error = (long)pcmcia_sockets[socket]->ls_dip[func]; 20127c478bd9Sstevel@tonic-gate break; 20137c478bd9Sstevel@tonic-gate 20147c478bd9Sstevel@tonic-gate /* 20157c478bd9Sstevel@tonic-gate * the remaining entries are SocketServices calls 20167c478bd9Sstevel@tonic-gate */ 20177c478bd9Sstevel@tonic-gate case SS_GetAdapter: 20187c478bd9Sstevel@tonic-gate error = SSGetAdapter(va_arg(arglist, get_adapter_t *)); 20197c478bd9Sstevel@tonic-gate break; 20207c478bd9Sstevel@tonic-gate case SS_GetPage: 20217c478bd9Sstevel@tonic-gate error = SSGetPage(va_arg(arglist, get_page_t *)); 20227c478bd9Sstevel@tonic-gate break; 20237c478bd9Sstevel@tonic-gate case SS_GetSocket: 20247c478bd9Sstevel@tonic-gate error = SSGetSocket(va_arg(arglist, get_socket_t *)); 20257c478bd9Sstevel@tonic-gate break; 20267c478bd9Sstevel@tonic-gate case SS_GetStatus: 20277c478bd9Sstevel@tonic-gate error = SSGetStatus(va_arg(arglist, get_ss_status_t *)); 20287c478bd9Sstevel@tonic-gate break; 20297c478bd9Sstevel@tonic-gate case SS_GetWindow: 20307c478bd9Sstevel@tonic-gate error = SSGetWindow(va_arg(arglist, get_window_t *)); 20317c478bd9Sstevel@tonic-gate break; 20327c478bd9Sstevel@tonic-gate case SS_InquireAdapter: 20337c478bd9Sstevel@tonic-gate error = SSInquireAdapter(va_arg(arglist, inquire_adapter_t *)); 20347c478bd9Sstevel@tonic-gate break; 20357c478bd9Sstevel@tonic-gate case SS_InquireSocket: 20367c478bd9Sstevel@tonic-gate error = SSInquireSocket(va_arg(arglist, inquire_socket_t *)); 20377c478bd9Sstevel@tonic-gate break; 20387c478bd9Sstevel@tonic-gate case SS_InquireWindow: 20397c478bd9Sstevel@tonic-gate error = SSInquireWindow(va_arg(arglist, inquire_window_t *)); 20407c478bd9Sstevel@tonic-gate break; 20417c478bd9Sstevel@tonic-gate case SS_ResetSocket: 20427c478bd9Sstevel@tonic-gate args[0] = va_arg(arglist, uint32_t); 20437c478bd9Sstevel@tonic-gate args[1] = va_arg(arglist, int); 20447c478bd9Sstevel@tonic-gate error = SSResetSocket(args[0], args[1]); 20457c478bd9Sstevel@tonic-gate break; 20467c478bd9Sstevel@tonic-gate case SS_SetPage: 20477c478bd9Sstevel@tonic-gate error = SSSetPage(va_arg(arglist, set_page_t *)); 20487c478bd9Sstevel@tonic-gate break; 20497c478bd9Sstevel@tonic-gate case SS_SetSocket: 20507c478bd9Sstevel@tonic-gate error = SSSetSocket(va_arg(arglist, set_socket_t *)); 20517c478bd9Sstevel@tonic-gate break; 20527c478bd9Sstevel@tonic-gate case SS_SetWindow: 20537c478bd9Sstevel@tonic-gate error = SSSetWindow(va_arg(arglist, set_window_t *)); 20547c478bd9Sstevel@tonic-gate break; 20557c478bd9Sstevel@tonic-gate case SS_SetIRQHandler: 20567c478bd9Sstevel@tonic-gate error = SSSetIRQHandler(va_arg(arglist, set_irq_handler_t *)); 20577c478bd9Sstevel@tonic-gate break; 20587c478bd9Sstevel@tonic-gate case SS_ClearIRQHandler: 20597c478bd9Sstevel@tonic-gate error = SSClearIRQHandler(va_arg(arglist, 20607c478bd9Sstevel@tonic-gate clear_irq_handler_t *)); 20617c478bd9Sstevel@tonic-gate break; 20627c478bd9Sstevel@tonic-gate default: 20637c478bd9Sstevel@tonic-gate error = BAD_FUNCTION; 20647c478bd9Sstevel@tonic-gate break; 20657c478bd9Sstevel@tonic-gate } 20667c478bd9Sstevel@tonic-gate va_end(arglist); 20677c478bd9Sstevel@tonic-gate return (error); 20687c478bd9Sstevel@tonic-gate } 20697c478bd9Sstevel@tonic-gate 20707c478bd9Sstevel@tonic-gate /* 20717c478bd9Sstevel@tonic-gate * pcmcia_merge_power() 20727c478bd9Sstevel@tonic-gate * The adapters may have different power tables so it 20737c478bd9Sstevel@tonic-gate * is necessary to construct a single power table that 20747c478bd9Sstevel@tonic-gate * can be used throughout the system. The result is 20757c478bd9Sstevel@tonic-gate * a merger of all capabilities. The nexus adds 20767c478bd9Sstevel@tonic-gate * power table entries one at a time. 20777c478bd9Sstevel@tonic-gate */ 20787c478bd9Sstevel@tonic-gate void 20797c478bd9Sstevel@tonic-gate pcmcia_merge_power(struct power_entry *power) 20807c478bd9Sstevel@tonic-gate { 20817c478bd9Sstevel@tonic-gate int i; 20827c478bd9Sstevel@tonic-gate struct power_entry pwr; 20837c478bd9Sstevel@tonic-gate 20847c478bd9Sstevel@tonic-gate pwr = *power; 20857c478bd9Sstevel@tonic-gate 20867c478bd9Sstevel@tonic-gate for (i = 0; i < pcmcia_num_power; i++) { 20877c478bd9Sstevel@tonic-gate if (pwr.PowerLevel == pcmcia_power_table[i].PowerLevel) { 20887c478bd9Sstevel@tonic-gate if (pwr.ValidSignals == 20897c478bd9Sstevel@tonic-gate pcmcia_power_table[i].ValidSignals) { 20907c478bd9Sstevel@tonic-gate return; 20917c478bd9Sstevel@tonic-gate } else { 20927c478bd9Sstevel@tonic-gate /* partial match */ 20937c478bd9Sstevel@tonic-gate pwr.ValidSignals &= 20947c478bd9Sstevel@tonic-gate ~pcmcia_power_table[i].ValidSignals; 20957c478bd9Sstevel@tonic-gate } 20967c478bd9Sstevel@tonic-gate } 20977c478bd9Sstevel@tonic-gate } 20987c478bd9Sstevel@tonic-gate /* what's left becomes a new entry */ 20997c478bd9Sstevel@tonic-gate if (pcmcia_num_power == PCMCIA_MAX_POWER) 21007c478bd9Sstevel@tonic-gate return; 21017c478bd9Sstevel@tonic-gate pcmcia_power_table[pcmcia_num_power++] = pwr; 21027c478bd9Sstevel@tonic-gate } 21037c478bd9Sstevel@tonic-gate 21047c478bd9Sstevel@tonic-gate /* 21057c478bd9Sstevel@tonic-gate * pcmcia_do_suspend() 21067c478bd9Sstevel@tonic-gate * tell CS that a suspend has happened by passing a 21077c478bd9Sstevel@tonic-gate * card removal event. Then cleanup the socket state 21087c478bd9Sstevel@tonic-gate * to fake the cards being removed so resume works 21097c478bd9Sstevel@tonic-gate */ 21107c478bd9Sstevel@tonic-gate void 21117c478bd9Sstevel@tonic-gate pcmcia_do_suspend(int socket, pcmcia_logical_socket_t *sockp) 21127c478bd9Sstevel@tonic-gate { 21137c478bd9Sstevel@tonic-gate get_ss_status_t stat; 21147c478bd9Sstevel@tonic-gate struct pcmcia_adapter *adapt; 21157c478bd9Sstevel@tonic-gate pcmcia_if_t *ls_if; 21167c478bd9Sstevel@tonic-gate dev_info_t *dip; 21177c478bd9Sstevel@tonic-gate int i; 21187c478bd9Sstevel@tonic-gate 21197c478bd9Sstevel@tonic-gate #ifdef XXX 21207c478bd9Sstevel@tonic-gate if (pcmcia_cs_event == NULL) { 21217c478bd9Sstevel@tonic-gate return; 21227c478bd9Sstevel@tonic-gate } 21237c478bd9Sstevel@tonic-gate #endif 21247c478bd9Sstevel@tonic-gate 21257c478bd9Sstevel@tonic-gate ls_if = sockp->ls_if; 21267c478bd9Sstevel@tonic-gate adapt = sockp->ls_adapter; 21277c478bd9Sstevel@tonic-gate 21287c478bd9Sstevel@tonic-gate if (ls_if == NULL || ls_if->pcif_get_status == NULL) { 21297c478bd9Sstevel@tonic-gate return; 21307c478bd9Sstevel@tonic-gate } 21317c478bd9Sstevel@tonic-gate 21327c478bd9Sstevel@tonic-gate stat.socket = socket; 21337c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 21347c478bd9Sstevel@tonic-gate if (pcmcia_debug) { 21357c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 21367c478bd9Sstevel@tonic-gate "pcmcia_do_suspend(%d, %p)\n", socket, (void *)sockp); 21377c478bd9Sstevel@tonic-gate } 21387c478bd9Sstevel@tonic-gate #endif 21397c478bd9Sstevel@tonic-gate 21407c478bd9Sstevel@tonic-gate if (GET_STATUS(ls_if, adapt->pca_dip, &stat) != SUCCESS) 21417c478bd9Sstevel@tonic-gate return; 21427c478bd9Sstevel@tonic-gate 21437c478bd9Sstevel@tonic-gate /* 21447c478bd9Sstevel@tonic-gate * If there is a card in the socket, then we need to send 21457c478bd9Sstevel@tonic-gate * everyone a PCE_CARD_REMOVAL event, and remove the 21467c478bd9Sstevel@tonic-gate * card active property. 21477c478bd9Sstevel@tonic-gate */ 21487c478bd9Sstevel@tonic-gate 21497c478bd9Sstevel@tonic-gate for (i = 0; i < sockp->ls_functions; i++) { 21507c478bd9Sstevel@tonic-gate struct pcmcia_parent_private *ppd; 21517c478bd9Sstevel@tonic-gate dip = sockp->ls_dip[i]; 21527c478bd9Sstevel@tonic-gate if (dip != NULL) { 21537c478bd9Sstevel@tonic-gate ppd = (struct pcmcia_parent_private *) 21547c478bd9Sstevel@tonic-gate ddi_get_parent_data(dip); 21557c478bd9Sstevel@tonic-gate ppd->ppd_flags |= PPD_SUSPENDED; 21567c478bd9Sstevel@tonic-gate } 21577c478bd9Sstevel@tonic-gate #if 0 21587c478bd9Sstevel@tonic-gate sockp->ls_dip[i] = NULL; 21597c478bd9Sstevel@tonic-gate #endif 21607c478bd9Sstevel@tonic-gate } 21617c478bd9Sstevel@tonic-gate sockp->ls_flags |= PCS_SUSPENDED; 21627c478bd9Sstevel@tonic-gate 21637c478bd9Sstevel@tonic-gate if (pcmcia_cs_event && 21647c478bd9Sstevel@tonic-gate (sockp->ls_cs_events & (1 << PCE_PM_SUSPEND))) { 21657c478bd9Sstevel@tonic-gate CS_EVENT(PCE_PM_SUSPEND, socket, 0); 21667c478bd9Sstevel@tonic-gate } 21677c478bd9Sstevel@tonic-gate pcm_event_manager(PCE_PM_SUSPEND, socket, NULL); 21687c478bd9Sstevel@tonic-gate } 21697c478bd9Sstevel@tonic-gate 21707c478bd9Sstevel@tonic-gate /* 21717c478bd9Sstevel@tonic-gate * pcmcia_do_resume() 21727c478bd9Sstevel@tonic-gate * tell CS that a suspend has happened by passing a 21737c478bd9Sstevel@tonic-gate * card removal event. Then cleanup the socket state 21747c478bd9Sstevel@tonic-gate * to fake the cards being removed so resume works 21757c478bd9Sstevel@tonic-gate */ 21767c478bd9Sstevel@tonic-gate void 21777c478bd9Sstevel@tonic-gate pcmcia_do_resume(int socket, pcmcia_logical_socket_t *sockp) 21787c478bd9Sstevel@tonic-gate { 21797c478bd9Sstevel@tonic-gate get_ss_status_t stat; 21807c478bd9Sstevel@tonic-gate struct pcmcia_adapter *adapt; 21817c478bd9Sstevel@tonic-gate pcmcia_if_t *ls_if; 21827c478bd9Sstevel@tonic-gate 21837c478bd9Sstevel@tonic-gate #ifdef XXX 21847c478bd9Sstevel@tonic-gate if (pcmcia_cs_event == NULL) { 21857c478bd9Sstevel@tonic-gate return; 21867c478bd9Sstevel@tonic-gate } 21877c478bd9Sstevel@tonic-gate #endif 21887c478bd9Sstevel@tonic-gate 21897c478bd9Sstevel@tonic-gate ls_if = sockp->ls_if; 21907c478bd9Sstevel@tonic-gate adapt = sockp->ls_adapter; 21917c478bd9Sstevel@tonic-gate 21927c478bd9Sstevel@tonic-gate if (ls_if == NULL || ls_if->pcif_get_status == NULL) { 21937c478bd9Sstevel@tonic-gate return; 21947c478bd9Sstevel@tonic-gate } 21957c478bd9Sstevel@tonic-gate 21967c478bd9Sstevel@tonic-gate stat.socket = socket; 21977c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 21987c478bd9Sstevel@tonic-gate if (pcmcia_debug) { 21997c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 22007c478bd9Sstevel@tonic-gate "pcmcia_do_resume(%d, %p)\n", socket, (void *)sockp); 22017c478bd9Sstevel@tonic-gate } 22027c478bd9Sstevel@tonic-gate #endif 22037c478bd9Sstevel@tonic-gate if (GET_STATUS(ls_if, adapt->pca_dip, &stat) == 22047c478bd9Sstevel@tonic-gate SUCCESS) { 22057c478bd9Sstevel@tonic-gate 22067c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 22077c478bd9Sstevel@tonic-gate if (pcmcia_debug) 22087c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "\tsocket=%x, CardState=%x\n", 22097c478bd9Sstevel@tonic-gate socket, stat.CardState); 22107c478bd9Sstevel@tonic-gate #endif 22117c478bd9Sstevel@tonic-gate #if 0 22127c478bd9Sstevel@tonic-gate /* now have socket info -- do we have events? */ 22137c478bd9Sstevel@tonic-gate if ((stat.CardState & SBM_CD) == SBM_CD) { 22147c478bd9Sstevel@tonic-gate if (pcmcia_cs_event && 22157c478bd9Sstevel@tonic-gate (sockp->ls_cs_events & (1 << PCE_CARD_INSERT))) { 22167c478bd9Sstevel@tonic-gate CS_EVENT(PCE_CARD_INSERT, socket, 0); 22177c478bd9Sstevel@tonic-gate } 22187c478bd9Sstevel@tonic-gate 22197c478bd9Sstevel@tonic-gate /* we should have card removed from CS soon */ 22207c478bd9Sstevel@tonic-gate pcm_event_manager(PCE_CARD_INSERT, socket, NULL); 22217c478bd9Sstevel@tonic-gate } 22227c478bd9Sstevel@tonic-gate #else 22237c478bd9Sstevel@tonic-gate if (pcmcia_cs_event && 22247c478bd9Sstevel@tonic-gate (sockp->ls_cs_events & (1 << PCE_PM_SUSPEND))) { 22257c478bd9Sstevel@tonic-gate CS_EVENT(PCE_PM_RESUME, socket, 0); 22267c478bd9Sstevel@tonic-gate CS_EVENT(PCE_CARD_REMOVAL, socket, 0); 22277c478bd9Sstevel@tonic-gate if ((stat.CardState & SBM_CD) == SBM_CD) 22287c478bd9Sstevel@tonic-gate CS_EVENT(PCE_CARD_INSERT, socket, 0); 22297c478bd9Sstevel@tonic-gate } 22307c478bd9Sstevel@tonic-gate #endif 22317c478bd9Sstevel@tonic-gate } 22327c478bd9Sstevel@tonic-gate } 22337c478bd9Sstevel@tonic-gate 22347c478bd9Sstevel@tonic-gate /* 22357c478bd9Sstevel@tonic-gate * pcmcia_map_power_set() 22367c478bd9Sstevel@tonic-gate * Given a power table entry and level, find it in the 22377c478bd9Sstevel@tonic-gate * master table and return the index in the adapter table. 22387c478bd9Sstevel@tonic-gate */ 22397c478bd9Sstevel@tonic-gate static int 22407c478bd9Sstevel@tonic-gate pcmcia_map_power_set(struct pcmcia_adapter *adapt, int level, int which) 22417c478bd9Sstevel@tonic-gate { 22427c478bd9Sstevel@tonic-gate int plevel, i; 22437c478bd9Sstevel@tonic-gate struct power_entry *pwr = (struct power_entry *)adapt->pca_power; 22447c478bd9Sstevel@tonic-gate plevel = pcmcia_power_table[level].PowerLevel; 22457c478bd9Sstevel@tonic-gate /* mask = pcmcia_power_table[level].ValidSignals; */ 22467c478bd9Sstevel@tonic-gate for (i = 0; i < adapt->pca_numpower; i++) 22477c478bd9Sstevel@tonic-gate if (plevel == pwr[i].PowerLevel && 22487c478bd9Sstevel@tonic-gate pwr[i].ValidSignals & which) 22497c478bd9Sstevel@tonic-gate return (i); 22507c478bd9Sstevel@tonic-gate return (0); 22517c478bd9Sstevel@tonic-gate } 22527c478bd9Sstevel@tonic-gate 22537c478bd9Sstevel@tonic-gate /* 22547c478bd9Sstevel@tonic-gate * pcmcia_map_power_get() 22557c478bd9Sstevel@tonic-gate * Given an adapter power entry, find the appropriate index 22567c478bd9Sstevel@tonic-gate * in the master table. 22577c478bd9Sstevel@tonic-gate */ 22587c478bd9Sstevel@tonic-gate static int 22597c478bd9Sstevel@tonic-gate pcmcia_map_power_get(struct pcmcia_adapter *adapt, int level, int which) 22607c478bd9Sstevel@tonic-gate { 22617c478bd9Sstevel@tonic-gate int plevel, i; 22627c478bd9Sstevel@tonic-gate struct power_entry *pwr = (struct power_entry *)adapt->pca_power; 22637c478bd9Sstevel@tonic-gate plevel = pwr[level].PowerLevel; 22647c478bd9Sstevel@tonic-gate /* mask = pwr[level].ValidSignals; */ 22657c478bd9Sstevel@tonic-gate for (i = 0; i < pcmcia_num_power; i++) 22667c478bd9Sstevel@tonic-gate if (plevel == pcmcia_power_table[i].PowerLevel && 22677c478bd9Sstevel@tonic-gate pcmcia_power_table[i].ValidSignals & which) 22687c478bd9Sstevel@tonic-gate return (i); 22697c478bd9Sstevel@tonic-gate return (0); 22707c478bd9Sstevel@tonic-gate } 22717c478bd9Sstevel@tonic-gate 22727c478bd9Sstevel@tonic-gate /* 22737c478bd9Sstevel@tonic-gate * XXX - SS really needs a way to allow the caller to express 22747c478bd9Sstevel@tonic-gate * interest in PCE_CARD_STATUS_CHANGE events. 22757c478bd9Sstevel@tonic-gate */ 22767c478bd9Sstevel@tonic-gate static uint32_t 22777c478bd9Sstevel@tonic-gate pcm_event_map[32] = { 22787c478bd9Sstevel@tonic-gate PCE_E2M(PCE_CARD_WRITE_PROTECT)|PCE_E2M(PCE_CARD_STATUS_CHANGE), 22797c478bd9Sstevel@tonic-gate PCE_E2M(PCE_CARD_UNLOCK)|PCE_E2M(PCE_CARD_STATUS_CHANGE), 22807c478bd9Sstevel@tonic-gate PCE_E2M(PCE_EJECTION_REQUEST)|PCE_E2M(PCE_CARD_STATUS_CHANGE), 22817c478bd9Sstevel@tonic-gate PCE_E2M(PCE_INSERTION_REQUEST)|PCE_E2M(PCE_CARD_STATUS_CHANGE), 22827c478bd9Sstevel@tonic-gate PCE_E2M(PCE_CARD_BATTERY_WARN)|PCE_E2M(PCE_CARD_STATUS_CHANGE), 22837c478bd9Sstevel@tonic-gate PCE_E2M(PCE_CARD_BATTERY_DEAD)|PCE_E2M(PCE_CARD_STATUS_CHANGE), 22847c478bd9Sstevel@tonic-gate PCE_E2M(PCE_CARD_READY)|PCE_E2M(PCE_CARD_STATUS_CHANGE), 22857c478bd9Sstevel@tonic-gate PCE_E2M(PCE_CARD_REMOVAL)|PCE_E2M(PCE_CARD_INSERT)| 22867c478bd9Sstevel@tonic-gate PCE_E2M(PCE_CARD_STATUS_CHANGE), 22877c478bd9Sstevel@tonic-gate PCE_E2M(PCE_PM_SUSPEND)|PCE_E2M(PCE_PM_RESUME), 22887c478bd9Sstevel@tonic-gate }; 22897c478bd9Sstevel@tonic-gate 22907c478bd9Sstevel@tonic-gate static int 22917c478bd9Sstevel@tonic-gate pcm_mapevents(uint32_t eventmask) 22927c478bd9Sstevel@tonic-gate { 22937c478bd9Sstevel@tonic-gate uint32_t mask; 22947c478bd9Sstevel@tonic-gate int i; 22957c478bd9Sstevel@tonic-gate 22967c478bd9Sstevel@tonic-gate for (i = 0, mask = 0; eventmask && i < 32; i++) { 22977c478bd9Sstevel@tonic-gate if (eventmask & (1 << i)) { 22987c478bd9Sstevel@tonic-gate mask |= pcm_event_map[i]; 22997c478bd9Sstevel@tonic-gate eventmask &= ~(1 << i); 23007c478bd9Sstevel@tonic-gate } 23017c478bd9Sstevel@tonic-gate } 23027c478bd9Sstevel@tonic-gate return (mask); 23037c478bd9Sstevel@tonic-gate } 23047c478bd9Sstevel@tonic-gate 23057c478bd9Sstevel@tonic-gate 23067c478bd9Sstevel@tonic-gate /* 23077c478bd9Sstevel@tonic-gate * PCMCIA Generic Naming Support 23087c478bd9Sstevel@tonic-gate * 23097c478bd9Sstevel@tonic-gate * With 2.6, PCMCIA naming moves to the 1275 and generic naming model. 23107c478bd9Sstevel@tonic-gate * Consequently, the whole naming mechanism is to be changed. This is 23117c478bd9Sstevel@tonic-gate * not backward compatible with the current names but that isn't a problem 23127c478bd9Sstevel@tonic-gate * due to so few drivers existing. 23137c478bd9Sstevel@tonic-gate * 23147c478bd9Sstevel@tonic-gate * For cards with a device_id tuple, a generic name will be used. 23157c478bd9Sstevel@tonic-gate * if there is no device_id, then the 1275 name will be used if possible. 23167c478bd9Sstevel@tonic-gate * The 1275 name is of the form pccardNNNN,MMMM from the manfid tuple. 23177c478bd9Sstevel@tonic-gate * if there is not manfid tuple, an attempt will be made to bind the 23187c478bd9Sstevel@tonic-gate * node to the version_1 strings. 23197c478bd9Sstevel@tonic-gate * 23207c478bd9Sstevel@tonic-gate * In all cases, a "compatible" property is created with a number 23217c478bd9Sstevel@tonic-gate * of names. The most generic name will be last in the list. 23227c478bd9Sstevel@tonic-gate */ 23237c478bd9Sstevel@tonic-gate 23247c478bd9Sstevel@tonic-gate /* 23257c478bd9Sstevel@tonic-gate * pcmcia_fix_string() 23267c478bd9Sstevel@tonic-gate * want to avoid special characters in alias strings so convert 23277c478bd9Sstevel@tonic-gate * to something innocuous 23287c478bd9Sstevel@tonic-gate */ 23297c478bd9Sstevel@tonic-gate 23307c478bd9Sstevel@tonic-gate void 23317c478bd9Sstevel@tonic-gate pcmcia_fix_string(char *str) 23327c478bd9Sstevel@tonic-gate { 23337c478bd9Sstevel@tonic-gate for (; str && *str; str++) { 23347c478bd9Sstevel@tonic-gate switch (*str) { 23357c478bd9Sstevel@tonic-gate case ' ': 23367c478bd9Sstevel@tonic-gate case '\t': 23377c478bd9Sstevel@tonic-gate *str = '_'; 23387c478bd9Sstevel@tonic-gate break; 23397c478bd9Sstevel@tonic-gate } 23407c478bd9Sstevel@tonic-gate } 23417c478bd9Sstevel@tonic-gate } 23427c478bd9Sstevel@tonic-gate 23437c478bd9Sstevel@tonic-gate void 23447c478bd9Sstevel@tonic-gate pcmcia_1275_name(int socket, struct pcm_device_info *info, 23457c478bd9Sstevel@tonic-gate client_handle_t handle) 23467c478bd9Sstevel@tonic-gate { 23477c478bd9Sstevel@tonic-gate cistpl_manfid_t manfid; 23487c478bd9Sstevel@tonic-gate cistpl_jedec_t jedec; 23497c478bd9Sstevel@tonic-gate tuple_t tuple; 23507c478bd9Sstevel@tonic-gate int i; 23517c478bd9Sstevel@tonic-gate 23527c478bd9Sstevel@tonic-gate tuple.Socket = socket; 23537c478bd9Sstevel@tonic-gate 23547c478bd9Sstevel@tonic-gate /* get MANFID if it exists -- this is most important form */ 23557c478bd9Sstevel@tonic-gate tuple.DesiredTuple = CISTPL_MANFID; 23567c478bd9Sstevel@tonic-gate tuple.Attributes = 0; 23577c478bd9Sstevel@tonic-gate if ((i = csx_GetFirstTuple(handle, &tuple)) == 23587c478bd9Sstevel@tonic-gate SUCCESS) { 23597c478bd9Sstevel@tonic-gate i = csx_Parse_CISTPL_MANFID(handle, &tuple, 23607c478bd9Sstevel@tonic-gate &manfid); 23617c478bd9Sstevel@tonic-gate if (i == SUCCESS) { 23627c478bd9Sstevel@tonic-gate (void) sprintf(info->pd_bind_name, "%s%x,%x", 23637c478bd9Sstevel@tonic-gate PCMDEV_NAMEPREF, 23647c478bd9Sstevel@tonic-gate manfid.manf, manfid.card); 23657c478bd9Sstevel@tonic-gate info->pd_flags |= PCM_NAME_1275; 23667c478bd9Sstevel@tonic-gate } 23677c478bd9Sstevel@tonic-gate } else { 23687c478bd9Sstevel@tonic-gate tuple.Attributes = 0; 23697c478bd9Sstevel@tonic-gate tuple.DesiredTuple = CISTPL_JEDEC_A; 23707c478bd9Sstevel@tonic-gate if ((i = csx_GetFirstTuple(handle, &tuple)) == 23717c478bd9Sstevel@tonic-gate SUCCESS) { 23727c478bd9Sstevel@tonic-gate i = csx_Parse_CISTPL_JEDEC_A(handle, &tuple, 23737c478bd9Sstevel@tonic-gate &jedec); 23747c478bd9Sstevel@tonic-gate if (i == SUCCESS) { 23757c478bd9Sstevel@tonic-gate (void) sprintf(info->pd_bind_name, "%s%x,%x", 23767c478bd9Sstevel@tonic-gate PCMDEV_NAMEPREF, 23777c478bd9Sstevel@tonic-gate jedec.jid[0].id, jedec.jid[0].info); 23787c478bd9Sstevel@tonic-gate info->pd_flags |= PCM_NAME_1275; 23797c478bd9Sstevel@tonic-gate } 23807c478bd9Sstevel@tonic-gate } 23817c478bd9Sstevel@tonic-gate } 23827c478bd9Sstevel@tonic-gate } 23837c478bd9Sstevel@tonic-gate 23847c478bd9Sstevel@tonic-gate void 23857c478bd9Sstevel@tonic-gate pcmcia_vers1_name(int socket, struct pcm_device_info *info, 23867c478bd9Sstevel@tonic-gate client_handle_t handle) 23877c478bd9Sstevel@tonic-gate { 23887c478bd9Sstevel@tonic-gate cistpl_vers_1_t vers1; 23897c478bd9Sstevel@tonic-gate tuple_t tuple; 23907c478bd9Sstevel@tonic-gate int which = 0; 23917c478bd9Sstevel@tonic-gate int i, len, space; 23927c478bd9Sstevel@tonic-gate 23937c478bd9Sstevel@tonic-gate tuple.Socket = socket; 23947c478bd9Sstevel@tonic-gate info->pd_vers1_name[0] = '\0'; 23957c478bd9Sstevel@tonic-gate 23967c478bd9Sstevel@tonic-gate /* Version 1 strings */ 23977c478bd9Sstevel@tonic-gate tuple.DesiredTuple = CISTPL_VERS_1; 23987c478bd9Sstevel@tonic-gate tuple.Attributes = 0; 23997c478bd9Sstevel@tonic-gate if (!which && 24007c478bd9Sstevel@tonic-gate (i = csx_GetFirstTuple(handle, &tuple)) == 24017c478bd9Sstevel@tonic-gate SUCCESS) { 24027c478bd9Sstevel@tonic-gate i = csx_Parse_CISTPL_VERS_1(handle, &tuple, &vers1); 24037c478bd9Sstevel@tonic-gate if (i == SUCCESS) { 24047c478bd9Sstevel@tonic-gate for (i = 0, len = 0, space = 0; i < vers1.ns; i++) { 24057c478bd9Sstevel@tonic-gate if ((space + len + strlen(info->pd_vers1_name)) >= 24067c478bd9Sstevel@tonic-gate sizeof (info->pd_vers1_name)) 24077c478bd9Sstevel@tonic-gate break; 24087c478bd9Sstevel@tonic-gate if (space) { 24097c478bd9Sstevel@tonic-gate info->pd_vers1_name[len++] = ','; 24107c478bd9Sstevel@tonic-gate } 24117c478bd9Sstevel@tonic-gate (void) strcpy(info->pd_vers1_name + len, 24127c478bd9Sstevel@tonic-gate (char *)vers1.pi[i]); 24137c478bd9Sstevel@tonic-gate len += strlen((char *)vers1.pi[i]); 24147c478bd9Sstevel@tonic-gate /* strip trailing spaces off of string */ 24157c478bd9Sstevel@tonic-gate while (info->pd_vers1_name[len - 1] == ' ' && 24167c478bd9Sstevel@tonic-gate len > 0) 24177c478bd9Sstevel@tonic-gate len--; 24187c478bd9Sstevel@tonic-gate space = 1; 24197c478bd9Sstevel@tonic-gate } 24207c478bd9Sstevel@tonic-gate info->pd_vers1_name[len] = '\0'; 24217c478bd9Sstevel@tonic-gate info->pd_flags |= PCM_NAME_VERS1; 24227c478bd9Sstevel@tonic-gate } 24237c478bd9Sstevel@tonic-gate } 24247c478bd9Sstevel@tonic-gate } 24257c478bd9Sstevel@tonic-gate 24267c478bd9Sstevel@tonic-gate 24277c478bd9Sstevel@tonic-gate int 24287c478bd9Sstevel@tonic-gate pcmcia_get_funce(client_handle_t handle, tuple_t *tuple) 24297c478bd9Sstevel@tonic-gate { 24307c478bd9Sstevel@tonic-gate int ret = 0; 24317c478bd9Sstevel@tonic-gate 24327c478bd9Sstevel@tonic-gate tuple->Attributes = 0; 24337c478bd9Sstevel@tonic-gate while (csx_GetNextTuple(handle, tuple) == SUCCESS) { 24347c478bd9Sstevel@tonic-gate if (tuple->TupleCode == CISTPL_FUNCID) { 24357c478bd9Sstevel@tonic-gate break; 24367c478bd9Sstevel@tonic-gate } 24377c478bd9Sstevel@tonic-gate if (tuple->TupleCode == CISTPL_FUNCE) { 24387c478bd9Sstevel@tonic-gate ret = 1; 24397c478bd9Sstevel@tonic-gate break; 24407c478bd9Sstevel@tonic-gate } 24417c478bd9Sstevel@tonic-gate tuple->Attributes = 0; 24427c478bd9Sstevel@tonic-gate } 24437c478bd9Sstevel@tonic-gate return (ret); 24447c478bd9Sstevel@tonic-gate } 24457c478bd9Sstevel@tonic-gate 24467c478bd9Sstevel@tonic-gate char *pcmcia_lan_types[] = { 24477c478bd9Sstevel@tonic-gate "arcnet", 24487c478bd9Sstevel@tonic-gate "ethernet", 24497c478bd9Sstevel@tonic-gate "token-ring", 24507c478bd9Sstevel@tonic-gate "localtalk", 24517c478bd9Sstevel@tonic-gate "fddi", 24527c478bd9Sstevel@tonic-gate "atm", 24537c478bd9Sstevel@tonic-gate "wireless", 24547c478bd9Sstevel@tonic-gate "reserved" 24557c478bd9Sstevel@tonic-gate }; 24567c478bd9Sstevel@tonic-gate 24577c478bd9Sstevel@tonic-gate void 24587c478bd9Sstevel@tonic-gate pcmcia_generic_name(int socket, struct pcm_device_info *info, 24597c478bd9Sstevel@tonic-gate client_handle_t handle) 24607c478bd9Sstevel@tonic-gate { 24617c478bd9Sstevel@tonic-gate cistpl_funcid_t funcid; 24627c478bd9Sstevel@tonic-gate cistpl_funce_t funce; 24637c478bd9Sstevel@tonic-gate tuple_t tuple; 24647c478bd9Sstevel@tonic-gate int which = 0; 24657c478bd9Sstevel@tonic-gate int i; 24667c478bd9Sstevel@tonic-gate 24677c478bd9Sstevel@tonic-gate tuple.Socket = socket; 24687c478bd9Sstevel@tonic-gate 24697c478bd9Sstevel@tonic-gate tuple.DesiredTuple = CISTPL_FUNCID; 24707c478bd9Sstevel@tonic-gate tuple.Attributes = 0; 24717c478bd9Sstevel@tonic-gate if ((i = csx_GetFirstTuple(handle, &tuple)) == 24727c478bd9Sstevel@tonic-gate SUCCESS) { 24737c478bd9Sstevel@tonic-gate /* 24747c478bd9Sstevel@tonic-gate * need to make sure that CISTPL_FUNCID is not 24757c478bd9Sstevel@tonic-gate * present in both a global and local CIS for MF 24767c478bd9Sstevel@tonic-gate * cards. 3COM seems to do this erroneously 24777c478bd9Sstevel@tonic-gate */ 24787c478bd9Sstevel@tonic-gate 24797c478bd9Sstevel@tonic-gate if (info->pd_flags & PCM_MULTI_FUNCTION && 24807c478bd9Sstevel@tonic-gate tuple.Flags & CISTPLF_GLOBAL_CIS) { 24817c478bd9Sstevel@tonic-gate tuple_t ltuple; 24827c478bd9Sstevel@tonic-gate ltuple = tuple; 24837c478bd9Sstevel@tonic-gate ltuple.DesiredTuple = CISTPL_FUNCID; 24847c478bd9Sstevel@tonic-gate ltuple.Attributes = 0; 24857c478bd9Sstevel@tonic-gate if ((i = csx_GetNextTuple(handle, <uple)) == 24867c478bd9Sstevel@tonic-gate SUCCESS) { 24877c478bd9Sstevel@tonic-gate /* this is the per-function funcid */ 24887c478bd9Sstevel@tonic-gate tuple = ltuple; 24897c478bd9Sstevel@tonic-gate } 24907c478bd9Sstevel@tonic-gate } 24917c478bd9Sstevel@tonic-gate 24927c478bd9Sstevel@tonic-gate i = csx_Parse_CISTPL_FUNCID(handle, &tuple, &funcid); 24937c478bd9Sstevel@tonic-gate if (i == SUCCESS) { 24947c478bd9Sstevel@tonic-gate /* in case no function extension */ 24957c478bd9Sstevel@tonic-gate if (funcid.function < PCM_GENNAME_SIZE) 24967c478bd9Sstevel@tonic-gate (void) strcpy(info->pd_generic_name, 24977c478bd9Sstevel@tonic-gate pcmcia_generic_names[funcid.function]); 24987c478bd9Sstevel@tonic-gate else 24997c478bd9Sstevel@tonic-gate (void) sprintf(info->pd_generic_name, 25007c478bd9Sstevel@tonic-gate "class,%x", 25017c478bd9Sstevel@tonic-gate funcid.function); 25027c478bd9Sstevel@tonic-gate } 25037c478bd9Sstevel@tonic-gate info->pd_type = funcid.function; 25047c478bd9Sstevel@tonic-gate switch (funcid.function) { 25057c478bd9Sstevel@tonic-gate case TPLFUNC_LAN: 25067c478bd9Sstevel@tonic-gate which = pcmcia_get_funce(handle, &tuple); 25077c478bd9Sstevel@tonic-gate if (which) { 25087c478bd9Sstevel@tonic-gate i = csx_Parse_CISTPL_FUNCE(handle, 25097c478bd9Sstevel@tonic-gate &tuple, 25107c478bd9Sstevel@tonic-gate &funce, TPLFUNC_LAN); 25117c478bd9Sstevel@tonic-gate if (i == SUCCESS) { 25127c478bd9Sstevel@tonic-gate i = funce.data.lan.tech; 25137c478bd9Sstevel@tonic-gate if (i > sizeof (pcmcia_lan_types) / 25147c478bd9Sstevel@tonic-gate sizeof (char *)) { 25157c478bd9Sstevel@tonic-gate break; 25167c478bd9Sstevel@tonic-gate } 25177c478bd9Sstevel@tonic-gate (void) strcpy(info->pd_generic_name, 25187c478bd9Sstevel@tonic-gate pcmcia_lan_types[i]); 25197c478bd9Sstevel@tonic-gate } 25207c478bd9Sstevel@tonic-gate } 25217c478bd9Sstevel@tonic-gate break; 25227c478bd9Sstevel@tonic-gate case TPLFUNC_VIDEO: 25237c478bd9Sstevel@tonic-gate #ifdef future_pcmcia_spec 25247c478bd9Sstevel@tonic-gate which = pcmcia_get_funce(handle, &tuple); 25257c478bd9Sstevel@tonic-gate if (which) { 25267c478bd9Sstevel@tonic-gate i = csx_Parse_CISTPL_FUNCE(handle, 25277c478bd9Sstevel@tonic-gate &tuple, 25287c478bd9Sstevel@tonic-gate &funce, TPLFUNC_VIDEO); 25297c478bd9Sstevel@tonic-gate if (i == SUCCESS) { 25307c478bd9Sstevel@tonic-gate i = funce.video.tech; 25317c478bd9Sstevel@tonic-gate if (i > sizeof (pcmcia_lan_types) / 25327c478bd9Sstevel@tonic-gate sizeof (char *)) { 25337c478bd9Sstevel@tonic-gate break; 25347c478bd9Sstevel@tonic-gate } 25357c478bd9Sstevel@tonic-gate (void) strcpy(info->pd_generic_names, 25367c478bd9Sstevel@tonic-gate pcmcia_lan_types[i]); 25377c478bd9Sstevel@tonic-gate } 25387c478bd9Sstevel@tonic-gate } 25397c478bd9Sstevel@tonic-gate #endif 25407c478bd9Sstevel@tonic-gate break; 25417c478bd9Sstevel@tonic-gate } 25427c478bd9Sstevel@tonic-gate info->pd_flags |= PCM_NAME_GENERIC; 25437c478bd9Sstevel@tonic-gate } else { 25447c478bd9Sstevel@tonic-gate /* if no FUNCID, do we have CONFIG */ 25457c478bd9Sstevel@tonic-gate tuple.DesiredTuple = CISTPL_CONFIG; 25467c478bd9Sstevel@tonic-gate tuple.Attributes = 0; 25477c478bd9Sstevel@tonic-gate if (csx_GetFirstTuple(handle, &tuple) != SUCCESS) { 25487c478bd9Sstevel@tonic-gate info->pd_flags |= PCM_NO_CONFIG | PCM_NAME_GENERIC; 25497c478bd9Sstevel@tonic-gate (void) strcpy(info->pd_generic_name, 25507c478bd9Sstevel@tonic-gate pcmcia_generic_names[PCM_TYPE_MEMORY]); 25517c478bd9Sstevel@tonic-gate info->pd_type = PCM_TYPE_MEMORY; 25527c478bd9Sstevel@tonic-gate } 25537c478bd9Sstevel@tonic-gate } 25547c478bd9Sstevel@tonic-gate } 25557c478bd9Sstevel@tonic-gate 25567c478bd9Sstevel@tonic-gate 25577c478bd9Sstevel@tonic-gate /* 25587c478bd9Sstevel@tonic-gate * pcmcia_add_compatible() 25597c478bd9Sstevel@tonic-gate * add the cached compatible property list. 25607c478bd9Sstevel@tonic-gate */ 25617c478bd9Sstevel@tonic-gate void 25627c478bd9Sstevel@tonic-gate pcmcia_add_compatible(dev_info_t *dip, struct pcm_device_info *info) 25637c478bd9Sstevel@tonic-gate { 25647c478bd9Sstevel@tonic-gate int length = 0, i; 25657c478bd9Sstevel@tonic-gate char buff[MAXNAMELEN]; 25667c478bd9Sstevel@tonic-gate char *compat_name[8]; 25677c478bd9Sstevel@tonic-gate int ci = 0; 25687c478bd9Sstevel@tonic-gate 25697c478bd9Sstevel@tonic-gate bzero(compat_name, sizeof (compat_name)); 25707c478bd9Sstevel@tonic-gate 25717c478bd9Sstevel@tonic-gate if (info->pd_flags & PCM_NAME_VERS1) { 25727c478bd9Sstevel@tonic-gate (void) sprintf(buff, "%s,%s", PCMDEV_NAMEPREF, 25737c478bd9Sstevel@tonic-gate info->pd_vers1_name); 25747c478bd9Sstevel@tonic-gate pcmcia_fix_string(buff); /* don't want spaces */ 25757c478bd9Sstevel@tonic-gate length = strlen(buff) + 1; 25767c478bd9Sstevel@tonic-gate compat_name[ci] = kmem_alloc(length, KM_SLEEP); 25777c478bd9Sstevel@tonic-gate (void) strcpy(compat_name[ci++], buff); 25787c478bd9Sstevel@tonic-gate } 25797c478bd9Sstevel@tonic-gate 25807c478bd9Sstevel@tonic-gate if ((info->pd_flags & (PCM_NAME_1275 | PCM_MULTI_FUNCTION)) == 25817c478bd9Sstevel@tonic-gate (PCM_NAME_1275 | PCM_MULTI_FUNCTION)) { 25827c478bd9Sstevel@tonic-gate (void) sprintf(buff, "%s,%x", info->pd_bind_name, 25837c478bd9Sstevel@tonic-gate info->pd_function); 25847c478bd9Sstevel@tonic-gate length = strlen(buff) + 1; 25857c478bd9Sstevel@tonic-gate compat_name[ci] = kmem_alloc(length, KM_SLEEP); 25867c478bd9Sstevel@tonic-gate (void) strcpy(compat_name[ci++], buff); 25877c478bd9Sstevel@tonic-gate } 25887c478bd9Sstevel@tonic-gate 25897c478bd9Sstevel@tonic-gate if (info->pd_flags & PCM_NAME_1275) { 25907c478bd9Sstevel@tonic-gate length = strlen(info->pd_bind_name) + 1; 25917c478bd9Sstevel@tonic-gate compat_name[ci] = kmem_alloc(length, KM_SLEEP); 25927c478bd9Sstevel@tonic-gate (void) strcpy(compat_name[ci++], info->pd_bind_name); 25937c478bd9Sstevel@tonic-gate } 25947c478bd9Sstevel@tonic-gate 25957c478bd9Sstevel@tonic-gate if (info->pd_flags & PCM_NAME_GENERIC) { 25967c478bd9Sstevel@tonic-gate if (strncmp(info->pd_generic_name, "class,", 6) == 0) { 25977c478bd9Sstevel@tonic-gate /* no generic without "pccard" */ 25987c478bd9Sstevel@tonic-gate (void) sprintf(buff, "%s%s", PCMDEV_NAMEPREF, 25997c478bd9Sstevel@tonic-gate info->pd_generic_name); 26007c478bd9Sstevel@tonic-gate } else { 26017c478bd9Sstevel@tonic-gate /* first pccard,generic-name */ 26027c478bd9Sstevel@tonic-gate (void) sprintf(buff, "%s,%s", PCMDEV_NAMEPREF, 26037c478bd9Sstevel@tonic-gate info->pd_generic_name); 26047c478bd9Sstevel@tonic-gate } 26057c478bd9Sstevel@tonic-gate length = strlen(buff) + 1; 26067c478bd9Sstevel@tonic-gate compat_name[ci] = kmem_alloc(length, KM_SLEEP); 26077c478bd9Sstevel@tonic-gate (void) strcpy(compat_name[ci++], buff); 26087c478bd9Sstevel@tonic-gate 26097c478bd9Sstevel@tonic-gate /* now the simple generic name */ 26107c478bd9Sstevel@tonic-gate length = strlen(info->pd_generic_name) + 1; 26117c478bd9Sstevel@tonic-gate compat_name[ci] = kmem_alloc(length, KM_SLEEP); 26127c478bd9Sstevel@tonic-gate (void) strcpy(compat_name[ci++], info->pd_generic_name); 26137c478bd9Sstevel@tonic-gate } 26147c478bd9Sstevel@tonic-gate 26157c478bd9Sstevel@tonic-gate if (info->pd_flags & PCM_NO_CONFIG) { 26167c478bd9Sstevel@tonic-gate char *mem = "pccard,memory"; 26177c478bd9Sstevel@tonic-gate /* 26187c478bd9Sstevel@tonic-gate * I/O cards are required to have a config tuple. 26197c478bd9Sstevel@tonic-gate * there are some that violate the spec and don't 26207c478bd9Sstevel@tonic-gate * but it is most likely that this is a memory card 26217c478bd9Sstevel@tonic-gate * so tag it as such. "memory" is more general 26227c478bd9Sstevel@tonic-gate * than other things so needs to come last. 26237c478bd9Sstevel@tonic-gate */ 26247c478bd9Sstevel@tonic-gate length = strlen(mem) + 1; 26257c478bd9Sstevel@tonic-gate compat_name[ci] = kmem_alloc(length, KM_SLEEP); 26267c478bd9Sstevel@tonic-gate (void) strcpy(compat_name[ci++], mem); 26277c478bd9Sstevel@tonic-gate } 26287c478bd9Sstevel@tonic-gate 26297c478bd9Sstevel@tonic-gate if (ci == 0) 26307c478bd9Sstevel@tonic-gate return; 26317c478bd9Sstevel@tonic-gate 26327c478bd9Sstevel@tonic-gate if (ndi_prop_update_string_array(DDI_DEV_T_NONE, dip, 26337c478bd9Sstevel@tonic-gate "compatible", (char **)compat_name, ci) != DDI_PROP_SUCCESS) 26347c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pcmcia: unable to create compatible prop"); 26357c478bd9Sstevel@tonic-gate 26367c478bd9Sstevel@tonic-gate for (i = 0; i < ci; i++) 26377c478bd9Sstevel@tonic-gate kmem_free(compat_name[i], strlen(compat_name[i]) + 1); 26387c478bd9Sstevel@tonic-gate } 26397c478bd9Sstevel@tonic-gate /* 26407c478bd9Sstevel@tonic-gate * CIS parsing and other PC Card specific code 26417c478bd9Sstevel@tonic-gate */ 26427c478bd9Sstevel@tonic-gate 26437c478bd9Sstevel@tonic-gate /* 26447c478bd9Sstevel@tonic-gate * pcmcia_get_mem_regs() 26457c478bd9Sstevel@tonic-gate */ 26467c478bd9Sstevel@tonic-gate static int 26477c478bd9Sstevel@tonic-gate pcmcia_get_mem_regs(struct pcm_regs *regs, struct pcm_device_info *info, 26487c478bd9Sstevel@tonic-gate int type, int pctype) 26497c478bd9Sstevel@tonic-gate { 26507c478bd9Sstevel@tonic-gate int num_regs = 0; 26517c478bd9Sstevel@tonic-gate tuple_t tuple; 26527c478bd9Sstevel@tonic-gate cistpl_device_t device; 26537c478bd9Sstevel@tonic-gate uint32_t curr_base; 26547c478bd9Sstevel@tonic-gate int ret, len; 26557c478bd9Sstevel@tonic-gate int space; 26567c478bd9Sstevel@tonic-gate 26577c478bd9Sstevel@tonic-gate /* 26587c478bd9Sstevel@tonic-gate * current plan for reg spec: 26597c478bd9Sstevel@tonic-gate * device_a will be accumulated to determine max size of 26607c478bd9Sstevel@tonic-gate * attribute memory. device for common. Then config 26617c478bd9Sstevel@tonic-gate * tuples to get a worst case I/O size. 26627c478bd9Sstevel@tonic-gate */ 26637c478bd9Sstevel@tonic-gate bzero(&tuple, sizeof (tuple)); 26647c478bd9Sstevel@tonic-gate tuple.Socket = info->pd_socket; 26657c478bd9Sstevel@tonic-gate 26667c478bd9Sstevel@tonic-gate tuple.DesiredTuple = (cisdata_t)type; 26677c478bd9Sstevel@tonic-gate 26687c478bd9Sstevel@tonic-gate space = (type == CISTPL_DEVICE_A) ? PC_REG_SPACE_ATTRIBUTE : 26697c478bd9Sstevel@tonic-gate PC_REG_SPACE_MEMORY; 26707c478bd9Sstevel@tonic-gate if ((ret = csx_GetFirstTuple(info->pd_handle, &tuple)) == CS_SUCCESS) { 26717c478bd9Sstevel@tonic-gate bzero(&device, sizeof (device)); 26727c478bd9Sstevel@tonic-gate 26737c478bd9Sstevel@tonic-gate if (type == CISTPL_DEVICE) 26747c478bd9Sstevel@tonic-gate ret = csx_Parse_CISTPL_DEVICE(info->pd_handle, &tuple, 26757c478bd9Sstevel@tonic-gate &device); 26767c478bd9Sstevel@tonic-gate else 26777c478bd9Sstevel@tonic-gate ret = csx_Parse_CISTPL_DEVICE_A(info->pd_handle, &tuple, 26787c478bd9Sstevel@tonic-gate &device); 26797c478bd9Sstevel@tonic-gate 26807c478bd9Sstevel@tonic-gate if (ret == CS_SUCCESS) { 26817c478bd9Sstevel@tonic-gate curr_base = 0; 26827c478bd9Sstevel@tonic-gate for (ret = 0; ret < device.num_devices; 26837c478bd9Sstevel@tonic-gate ret++) { 26847c478bd9Sstevel@tonic-gate /* need to order these for real mem first */ 26857c478bd9Sstevel@tonic-gate if (device.devnode[ret].type != 26867c478bd9Sstevel@tonic-gate CISTPL_DEVICE_DTYPE_NULL) { 26877c478bd9Sstevel@tonic-gate /* how to represent types??? */ 26887c478bd9Sstevel@tonic-gate regs[num_regs].phys_hi = 26897c478bd9Sstevel@tonic-gate PC_REG_PHYS_HI(0, 0, 26907c478bd9Sstevel@tonic-gate pctype, 26917c478bd9Sstevel@tonic-gate space, 26927c478bd9Sstevel@tonic-gate info->pd_socket, 26937c478bd9Sstevel@tonic-gate info->pd_function, 26947c478bd9Sstevel@tonic-gate 0); 26957c478bd9Sstevel@tonic-gate regs[num_regs].phys_lo = curr_base; 26967c478bd9Sstevel@tonic-gate len = device.devnode[ret].size_in_bytes; 26977c478bd9Sstevel@tonic-gate curr_base += len; 26987c478bd9Sstevel@tonic-gate regs[num_regs].phys_len = len; 26997c478bd9Sstevel@tonic-gate num_regs++; 27007c478bd9Sstevel@tonic-gate } else { 27017c478bd9Sstevel@tonic-gate /* 27027c478bd9Sstevel@tonic-gate * NULL device is a "hole" 27037c478bd9Sstevel@tonic-gate */ 27047c478bd9Sstevel@tonic-gate curr_base += 27057c478bd9Sstevel@tonic-gate device.devnode[ret].size_in_bytes; 27067c478bd9Sstevel@tonic-gate } 27077c478bd9Sstevel@tonic-gate } 27087c478bd9Sstevel@tonic-gate } 27097c478bd9Sstevel@tonic-gate } 27107c478bd9Sstevel@tonic-gate return (num_regs); 27117c478bd9Sstevel@tonic-gate } 27127c478bd9Sstevel@tonic-gate 27137c478bd9Sstevel@tonic-gate /* 27147c478bd9Sstevel@tonic-gate * 27157c478bd9Sstevel@tonic-gate */ 27167c478bd9Sstevel@tonic-gate static int 27177c478bd9Sstevel@tonic-gate pcmcia_get_io_regs(struct pcm_regs *regs, struct pcm_device_info *info, 27187c478bd9Sstevel@tonic-gate int pctype) 27197c478bd9Sstevel@tonic-gate { 27207c478bd9Sstevel@tonic-gate int num_regs = 0; 27217c478bd9Sstevel@tonic-gate tuple_t tuple; 27227c478bd9Sstevel@tonic-gate uint32_t curr_base; 27237c478bd9Sstevel@tonic-gate int len, curr, i, curr_len; 27247c478bd9Sstevel@tonic-gate cistpl_config_t config; 27257c478bd9Sstevel@tonic-gate cistpl_cftable_entry_t cftable; 27267c478bd9Sstevel@tonic-gate struct pcm_regs tmp[16]; 27277c478bd9Sstevel@tonic-gate int found = 0; 27287c478bd9Sstevel@tonic-gate 27297c478bd9Sstevel@tonic-gate bzero(&tuple, sizeof (tuple)); 27307c478bd9Sstevel@tonic-gate tuple.DesiredTuple = CISTPL_CONFIG; 27317c478bd9Sstevel@tonic-gate tuple.Socket = info->pd_socket; 27327c478bd9Sstevel@tonic-gate tuple.Attributes = 0; 27337c478bd9Sstevel@tonic-gate curr_base = 0; 27347c478bd9Sstevel@tonic-gate len = 0; 27357c478bd9Sstevel@tonic-gate 27367c478bd9Sstevel@tonic-gate if (csx_GetFirstTuple(info->pd_handle, &tuple) == CS_SUCCESS) { 27377c478bd9Sstevel@tonic-gate if (csx_Parse_CISTPL_CONFIG(info->pd_handle, 27387c478bd9Sstevel@tonic-gate &tuple, &config) != CS_SUCCESS) { 27397c478bd9Sstevel@tonic-gate info->pd_flags |= PCM_NO_CONFIG; /* must be memory */ 27407c478bd9Sstevel@tonic-gate return (0); 27417c478bd9Sstevel@tonic-gate } 27427c478bd9Sstevel@tonic-gate curr = 0; 27437c478bd9Sstevel@tonic-gate 27447c478bd9Sstevel@tonic-gate tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; 27457c478bd9Sstevel@tonic-gate tuple.Socket = info->pd_socket; 27467c478bd9Sstevel@tonic-gate tuple.Attributes = 0; 27477c478bd9Sstevel@tonic-gate bzero(tmp, sizeof (tmp)); 27487c478bd9Sstevel@tonic-gate while (csx_GetNextTuple(info->pd_handle, 27497c478bd9Sstevel@tonic-gate &tuple) == CS_SUCCESS) { 27507c478bd9Sstevel@tonic-gate bzero(&cftable, sizeof (cftable)); 27517c478bd9Sstevel@tonic-gate if (csx_Parse_CISTPL_CFTABLE_ENTRY(info->pd_handle, 27527c478bd9Sstevel@tonic-gate &tuple, &cftable) == 27537c478bd9Sstevel@tonic-gate CS_SUCCESS) { 27547c478bd9Sstevel@tonic-gate if (cftable.flags & CISTPL_CFTABLE_TPCE_FS_IO) { 27557c478bd9Sstevel@tonic-gate /* we have an I/O entry */ 27567c478bd9Sstevel@tonic-gate if (cftable.io.flags & 27577c478bd9Sstevel@tonic-gate CISTPL_CFTABLE_TPCE_FS_IO_RANGE) { 27587c478bd9Sstevel@tonic-gate len = cftable.io.addr_lines; 27597c478bd9Sstevel@tonic-gate if (len != 0) 27607c478bd9Sstevel@tonic-gate len = 1 << len; 27617c478bd9Sstevel@tonic-gate for (i = 0; i < cftable.io.ranges && curr < 16; i++) { 27627c478bd9Sstevel@tonic-gate curr_base = cftable.io.range[i].addr; 27637c478bd9Sstevel@tonic-gate curr_len = cftable.io.range[i].length; 27647c478bd9Sstevel@tonic-gate if (curr_len == 0) 27657c478bd9Sstevel@tonic-gate curr_len = len; 27667c478bd9Sstevel@tonic-gate if (len != 0 || cftable.io.addr_lines == 0) { 27677c478bd9Sstevel@tonic-gate /* we have potential relocation */ 27687c478bd9Sstevel@tonic-gate int mask; 27697c478bd9Sstevel@tonic-gate mask = cftable.io.addr_lines ? 27707c478bd9Sstevel@tonic-gate cftable.io.addr_lines : 27717c478bd9Sstevel@tonic-gate genp2(len); 27727c478bd9Sstevel@tonic-gate mask = genmask(mask); 27737c478bd9Sstevel@tonic-gate if ((mask & curr_base) == 0) { 27747c478bd9Sstevel@tonic-gate /* more accurate length */ 27757c478bd9Sstevel@tonic-gate regs->phys_len = curr_len; 27767c478bd9Sstevel@tonic-gate regs->phys_lo = 0; 27777c478bd9Sstevel@tonic-gate regs->phys_hi = 27787c478bd9Sstevel@tonic-gate PC_REG_PHYS_HI(0, 27797c478bd9Sstevel@tonic-gate 0, 27807c478bd9Sstevel@tonic-gate pctype, 27817c478bd9Sstevel@tonic-gate PC_REG_SPACE_IO, 27827c478bd9Sstevel@tonic-gate info->pd_socket, 27837c478bd9Sstevel@tonic-gate info->pd_function, 27847c478bd9Sstevel@tonic-gate 0); 27857c478bd9Sstevel@tonic-gate num_regs++; 27867c478bd9Sstevel@tonic-gate found = 2; 27877c478bd9Sstevel@tonic-gate break; 27887c478bd9Sstevel@tonic-gate } 27897c478bd9Sstevel@tonic-gate } 27907c478bd9Sstevel@tonic-gate tmp[curr].phys_len = curr_len; 27917c478bd9Sstevel@tonic-gate tmp[curr].phys_lo = curr_base; 27927c478bd9Sstevel@tonic-gate curr++; 27937c478bd9Sstevel@tonic-gate found = 1; 27947c478bd9Sstevel@tonic-gate } 27957c478bd9Sstevel@tonic-gate if (found == 2) 27967c478bd9Sstevel@tonic-gate break; 27977c478bd9Sstevel@tonic-gate } else { 27987c478bd9Sstevel@tonic-gate /* no I/O range so just a mask */ 27997c478bd9Sstevel@tonic-gate regs->phys_len = 1 << cftable.io.addr_lines; 28007c478bd9Sstevel@tonic-gate regs->phys_hi = 28017c478bd9Sstevel@tonic-gate PC_REG_PHYS_HI(0, 28027c478bd9Sstevel@tonic-gate 0, 28037c478bd9Sstevel@tonic-gate pctype, 28047c478bd9Sstevel@tonic-gate PC_REG_SPACE_IO, 28057c478bd9Sstevel@tonic-gate info->pd_socket, 28067c478bd9Sstevel@tonic-gate info->pd_function, 28077c478bd9Sstevel@tonic-gate 0); 28087c478bd9Sstevel@tonic-gate regs->phys_lo = 0; 28097c478bd9Sstevel@tonic-gate num_regs++; 28107c478bd9Sstevel@tonic-gate regs++; 28117c478bd9Sstevel@tonic-gate /* quit on "good" entry */ 28127c478bd9Sstevel@tonic-gate break; 28137c478bd9Sstevel@tonic-gate } 28147c478bd9Sstevel@tonic-gate /* was this the last CFTABLE Entry? */ 28157c478bd9Sstevel@tonic-gate if (config.last == cftable.index) 28167c478bd9Sstevel@tonic-gate break; 28177c478bd9Sstevel@tonic-gate } 28187c478bd9Sstevel@tonic-gate } 28197c478bd9Sstevel@tonic-gate } 28207c478bd9Sstevel@tonic-gate if (found == 1) { 28217c478bd9Sstevel@tonic-gate /* 28227c478bd9Sstevel@tonic-gate * have some non-relocatable values 28237c478bd9Sstevel@tonic-gate * so we include them all for now 28247c478bd9Sstevel@tonic-gate */ 28257c478bd9Sstevel@tonic-gate for (i = 0; i < curr && num_regs < 8; i++) { 28267c478bd9Sstevel@tonic-gate regs->phys_len = tmp[i].phys_len; 28277c478bd9Sstevel@tonic-gate regs->phys_lo = tmp[i].phys_lo; 28287c478bd9Sstevel@tonic-gate regs->phys_hi = PC_REG_PHYS_HI(1, 0, pctype, 28297c478bd9Sstevel@tonic-gate PC_REG_SPACE_IO, info->pd_socket, 28307c478bd9Sstevel@tonic-gate info->pd_function, 0); 28317c478bd9Sstevel@tonic-gate regs++; 28327c478bd9Sstevel@tonic-gate num_regs++; 28337c478bd9Sstevel@tonic-gate } 28347c478bd9Sstevel@tonic-gate } 28357c478bd9Sstevel@tonic-gate } 28367c478bd9Sstevel@tonic-gate return (num_regs); 28377c478bd9Sstevel@tonic-gate } 28387c478bd9Sstevel@tonic-gate 28397c478bd9Sstevel@tonic-gate /* 28407c478bd9Sstevel@tonic-gate * pcmcia_create_regs() 28417c478bd9Sstevel@tonic-gate * create a valid set of regspecs for the card 28427c478bd9Sstevel@tonic-gate * The first one is always for CIS access and naming 28437c478bd9Sstevel@tonic-gate */ 28447c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 28457c478bd9Sstevel@tonic-gate static void 28467c478bd9Sstevel@tonic-gate pcmcia_find_regs(dev_info_t *dip, struct pcm_device_info *info, 28477c478bd9Sstevel@tonic-gate struct pcmcia_parent_private *ppd) 28487c478bd9Sstevel@tonic-gate { 28497c478bd9Sstevel@tonic-gate struct pcm_regs regs[32]; /* assume worst case */ 28507c478bd9Sstevel@tonic-gate int num_regs = 0; 28517c478bd9Sstevel@tonic-gate int len; 28527c478bd9Sstevel@tonic-gate int bustype; 28537c478bd9Sstevel@tonic-gate 28547c478bd9Sstevel@tonic-gate if (ppd->ppd_flags & PPD_CARD_CARDBUS) { 28557c478bd9Sstevel@tonic-gate /* always have a CIS map */ 28567c478bd9Sstevel@tonic-gate regs[0].phys_hi = PC_REG_PHYS_HI(0, 0, PC_REG_TYPE_CARDBUS, 28577c478bd9Sstevel@tonic-gate PC_REG_SPACE_CONFIG, 28587c478bd9Sstevel@tonic-gate info->pd_socket, 28597c478bd9Sstevel@tonic-gate info->pd_function, 0); 28607c478bd9Sstevel@tonic-gate bustype = PC_REG_TYPE_CARDBUS; 28617c478bd9Sstevel@tonic-gate } else { 28627c478bd9Sstevel@tonic-gate /* always have a CIS map */ 28637c478bd9Sstevel@tonic-gate regs[0].phys_hi = PC_REG_PHYS_HI(0, 0, PC_REG_TYPE_16BIT, 28647c478bd9Sstevel@tonic-gate PC_REG_SPACE_ATTRIBUTE, 28657c478bd9Sstevel@tonic-gate info->pd_socket, 28667c478bd9Sstevel@tonic-gate info->pd_function, 0); 28677c478bd9Sstevel@tonic-gate bustype = PC_REG_TYPE_16BIT; 28687c478bd9Sstevel@tonic-gate } 28697c478bd9Sstevel@tonic-gate regs[0].phys_lo = 0; /* always starts at zero */ 28707c478bd9Sstevel@tonic-gate regs[0].phys_len = 0; 28717c478bd9Sstevel@tonic-gate num_regs++; 28727c478bd9Sstevel@tonic-gate /* 28737c478bd9Sstevel@tonic-gate * need to search CIS for other memory instances 28747c478bd9Sstevel@tonic-gate */ 28757c478bd9Sstevel@tonic-gate 28767c478bd9Sstevel@tonic-gate if (info->pd_flags & PCM_OTHER_NOCIS) { 28777c478bd9Sstevel@tonic-gate /* special case of memory only card without CIS */ 28787c478bd9Sstevel@tonic-gate regs[1].phys_hi = PC_REG_PHYS_HI(0, 0, PC_REG_TYPE_16BIT, 28797c478bd9Sstevel@tonic-gate PC_REG_SPACE_MEMORY, 28807c478bd9Sstevel@tonic-gate info->pd_socket, 28817c478bd9Sstevel@tonic-gate info->pd_function, 0); 28827c478bd9Sstevel@tonic-gate regs[1].phys_lo = 0; 28837c478bd9Sstevel@tonic-gate regs[1].phys_len = PCM_MAX_R2_MEM; 28847c478bd9Sstevel@tonic-gate num_regs++; 28857c478bd9Sstevel@tonic-gate } else { 28867c478bd9Sstevel@tonic-gate /* 28877c478bd9Sstevel@tonic-gate * want to get any other memory and/or I/O regions 28887c478bd9Sstevel@tonic-gate * on the card and represent them here. 28897c478bd9Sstevel@tonic-gate */ 28907c478bd9Sstevel@tonic-gate num_regs += pcmcia_get_mem_regs(®s[num_regs], info, 28917c478bd9Sstevel@tonic-gate CISTPL_DEVICE_A, bustype); 28927c478bd9Sstevel@tonic-gate num_regs += pcmcia_get_mem_regs(®s[num_regs], info, 28937c478bd9Sstevel@tonic-gate CISTPL_DEVICE, bustype); 28947c478bd9Sstevel@tonic-gate 28957c478bd9Sstevel@tonic-gate /* now look for an I/O space to configure */ 28967c478bd9Sstevel@tonic-gate num_regs += pcmcia_get_io_regs(®s[num_regs], info, 28977c478bd9Sstevel@tonic-gate bustype); 28987c478bd9Sstevel@tonic-gate 28997c478bd9Sstevel@tonic-gate } 29007c478bd9Sstevel@tonic-gate 29017c478bd9Sstevel@tonic-gate len = num_regs * sizeof (uint32_t) * 3; 29027c478bd9Sstevel@tonic-gate ppd->ppd_nreg = num_regs; 29037c478bd9Sstevel@tonic-gate ppd->ppd_reg = kmem_alloc(len, KM_SLEEP); 29047c478bd9Sstevel@tonic-gate bcopy(regs, ppd->ppd_reg, len); 29057c478bd9Sstevel@tonic-gate len = sizeof (struct pcm_regs) * ppd->ppd_nreg; 29067c478bd9Sstevel@tonic-gate ppd->ppd_assigned = kmem_zalloc(len, KM_SLEEP); 29077c478bd9Sstevel@tonic-gate } 29087c478bd9Sstevel@tonic-gate 29097c478bd9Sstevel@tonic-gate 29107c478bd9Sstevel@tonic-gate /* 29117c478bd9Sstevel@tonic-gate * pcmcia_need_intr() 29127c478bd9Sstevel@tonic-gate * check to see if an interrupt tuple exists. 29137c478bd9Sstevel@tonic-gate * existence means we need one in the intrspec. 29147c478bd9Sstevel@tonic-gate */ 29157c478bd9Sstevel@tonic-gate static int 29167c478bd9Sstevel@tonic-gate pcmcia_need_intr(int socket, struct pcm_device_info *info) 29177c478bd9Sstevel@tonic-gate { 29187c478bd9Sstevel@tonic-gate cistpl_config_t config; 29197c478bd9Sstevel@tonic-gate cistpl_cftable_entry_t cftable; 29207c478bd9Sstevel@tonic-gate tuple_t tuple; 29217c478bd9Sstevel@tonic-gate int i; 29227c478bd9Sstevel@tonic-gate 29237c478bd9Sstevel@tonic-gate bzero(&tuple, sizeof (tuple)); 29247c478bd9Sstevel@tonic-gate tuple.DesiredTuple = CISTPL_CONFIG; 29257c478bd9Sstevel@tonic-gate tuple.Socket = socket; 29267c478bd9Sstevel@tonic-gate tuple.Attributes = 0; 29277c478bd9Sstevel@tonic-gate if (csx_GetFirstTuple(info->pd_handle, &tuple) != CS_SUCCESS) { 29287c478bd9Sstevel@tonic-gate return (0); 29297c478bd9Sstevel@tonic-gate } 29307c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 29317c478bd9Sstevel@tonic-gate if (pcmcia_debug) { 29327c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia_need_intr: have config tuple\n"); 29337c478bd9Sstevel@tonic-gate } 29347c478bd9Sstevel@tonic-gate #endif 29357c478bd9Sstevel@tonic-gate bzero(&config, sizeof (config)); 29367c478bd9Sstevel@tonic-gate if (csx_Parse_CISTPL_CONFIG(info->pd_handle, 29377c478bd9Sstevel@tonic-gate &tuple, &config) != CS_SUCCESS) { 29387c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pcmcia: config failed to parse\n"); 29397c478bd9Sstevel@tonic-gate return (0); 29407c478bd9Sstevel@tonic-gate } 29417c478bd9Sstevel@tonic-gate 29427c478bd9Sstevel@tonic-gate for (cftable.index = (int)-1, i = -1; 29437c478bd9Sstevel@tonic-gate i != config.last; i = cftable.index) { 29447c478bd9Sstevel@tonic-gate tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; 29457c478bd9Sstevel@tonic-gate tuple.Attributes = 0; 29467c478bd9Sstevel@tonic-gate if (csx_GetNextTuple(info->pd_handle, 29477c478bd9Sstevel@tonic-gate &tuple) != CS_SUCCESS) { 29487c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pcmcia: get cftable failed\n"); 29497c478bd9Sstevel@tonic-gate break; 29507c478bd9Sstevel@tonic-gate } 29517c478bd9Sstevel@tonic-gate bzero(&cftable, sizeof (cftable)); 29527c478bd9Sstevel@tonic-gate if (csx_Parse_CISTPL_CFTABLE_ENTRY(info->pd_handle, 29537c478bd9Sstevel@tonic-gate &tuple, &cftable) != 29547c478bd9Sstevel@tonic-gate CS_SUCCESS) { 29557c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pcmcia: parse cftable failed\n"); 29567c478bd9Sstevel@tonic-gate break; 29577c478bd9Sstevel@tonic-gate } 29587c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 29597c478bd9Sstevel@tonic-gate if (pcmcia_debug) 29607c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "\t%x: flags=%x (%x)\n", 29617c478bd9Sstevel@tonic-gate i, cftable.flags, 29627c478bd9Sstevel@tonic-gate cftable.flags & CISTPL_CFTABLE_TPCE_FS_IRQ); 29637c478bd9Sstevel@tonic-gate #endif 29647c478bd9Sstevel@tonic-gate if (cftable.flags & CISTPL_CFTABLE_TPCE_FS_IRQ) 29657c478bd9Sstevel@tonic-gate return (1); 29667c478bd9Sstevel@tonic-gate } 29677c478bd9Sstevel@tonic-gate return (0); 29687c478bd9Sstevel@tonic-gate 29697c478bd9Sstevel@tonic-gate } 29707c478bd9Sstevel@tonic-gate 29717c478bd9Sstevel@tonic-gate /* 29727c478bd9Sstevel@tonic-gate * pcmcia_num_funcs() 29737c478bd9Sstevel@tonic-gate * look for a CISTPL_LONGLINK_MFC 29747c478bd9Sstevel@tonic-gate * if there is one, return the number of functions 29757c478bd9Sstevel@tonic-gate * if there isn't one, then there is one function 29767c478bd9Sstevel@tonic-gate */ 29777c478bd9Sstevel@tonic-gate static int 29787c478bd9Sstevel@tonic-gate pcmcia_num_funcs(int socket, client_handle_t handle) 29797c478bd9Sstevel@tonic-gate { 29807c478bd9Sstevel@tonic-gate int count = 1; 29817c478bd9Sstevel@tonic-gate cistpl_longlink_mfc_t mfc; 29827c478bd9Sstevel@tonic-gate tuple_t tuple; 29837c478bd9Sstevel@tonic-gate 29847c478bd9Sstevel@tonic-gate bzero(&tuple, sizeof (tuple_t)); 29857c478bd9Sstevel@tonic-gate tuple.DesiredTuple = CISTPL_LONGLINK_MFC; 29867c478bd9Sstevel@tonic-gate tuple.Socket = socket; 29877c478bd9Sstevel@tonic-gate tuple.Attributes = 0; 29887c478bd9Sstevel@tonic-gate if (csx_GetFirstTuple(handle, &tuple) == CS_SUCCESS) { 29897c478bd9Sstevel@tonic-gate /* this is a multifunction card */ 29907c478bd9Sstevel@tonic-gate if (csx_ParseTuple(handle, &tuple, (cisparse_t *)&mfc, 29917c478bd9Sstevel@tonic-gate CISTPL_LONGLINK_MFC) == CS_SUCCESS) { 29927c478bd9Sstevel@tonic-gate count = mfc.nfuncs; 29937c478bd9Sstevel@tonic-gate } 29947c478bd9Sstevel@tonic-gate } 29957c478bd9Sstevel@tonic-gate return (count); 29967c478bd9Sstevel@tonic-gate } 29977c478bd9Sstevel@tonic-gate 29987c478bd9Sstevel@tonic-gate client_handle_t pcmcia_cs_handle; 29997c478bd9Sstevel@tonic-gate 30007c478bd9Sstevel@tonic-gate /* 30017c478bd9Sstevel@tonic-gate * pcmcia_create_dev_info(socket) 30027c478bd9Sstevel@tonic-gate * either find or create the device information structure 30037c478bd9Sstevel@tonic-gate * for the card(s) just inserted. We don't care about removal yet. 30047c478bd9Sstevel@tonic-gate * In any case, we will only do this at CS request 30057c478bd9Sstevel@tonic-gate */ 30067c478bd9Sstevel@tonic-gate static void 30077c478bd9Sstevel@tonic-gate pcmcia_create_dev_info(int socket) 30087c478bd9Sstevel@tonic-gate { 30097c478bd9Sstevel@tonic-gate struct pcm_device_info card_info; 30107c478bd9Sstevel@tonic-gate client_reg_t reg; 30117c478bd9Sstevel@tonic-gate cisinfo_t cisinfo; 30127c478bd9Sstevel@tonic-gate int i; 30137c478bd9Sstevel@tonic-gate dev_info_t *pdip; 30147c478bd9Sstevel@tonic-gate static int handle_def = 0; 30157c478bd9Sstevel@tonic-gate 30167c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 30177c478bd9Sstevel@tonic-gate if (pcmcia_debug) 30187c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "create dev_info_t for device in socket %d\n", 30197c478bd9Sstevel@tonic-gate socket); 30207c478bd9Sstevel@tonic-gate #endif 30217c478bd9Sstevel@tonic-gate 30227c478bd9Sstevel@tonic-gate /* 30237c478bd9Sstevel@tonic-gate * before we can do anything else, we need the parent 30247c478bd9Sstevel@tonic-gate * devinfo of the socket. This gets things in the right 30257c478bd9Sstevel@tonic-gate * place in the device tree. 30267c478bd9Sstevel@tonic-gate */ 30277c478bd9Sstevel@tonic-gate 30287c478bd9Sstevel@tonic-gate pdip = pcm_find_parent_dip(socket); 30297c478bd9Sstevel@tonic-gate if (pdip == NULL) 30307c478bd9Sstevel@tonic-gate return; 30317c478bd9Sstevel@tonic-gate 30327c478bd9Sstevel@tonic-gate /* Card Services calls needed to get CIS info */ 30337c478bd9Sstevel@tonic-gate reg.dip = NULL; 30347c478bd9Sstevel@tonic-gate reg.Attributes = INFO_SOCKET_SERVICES; 30357c478bd9Sstevel@tonic-gate reg.EventMask = 0; 30367c478bd9Sstevel@tonic-gate reg.event_handler = NULL; 30377c478bd9Sstevel@tonic-gate reg.Version = CS_VERSION; 30387c478bd9Sstevel@tonic-gate 30397c478bd9Sstevel@tonic-gate bzero(&card_info, sizeof (card_info)); 30407c478bd9Sstevel@tonic-gate 30417c478bd9Sstevel@tonic-gate if (handle_def == 0) { 30427c478bd9Sstevel@tonic-gate if (csx_RegisterClient(&pcmcia_cs_handle, 30437c478bd9Sstevel@tonic-gate ®) != CS_SUCCESS) { 30447c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 30457c478bd9Sstevel@tonic-gate if (pcmcia_debug) 30467c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 30477c478bd9Sstevel@tonic-gate "pcmcia: RegisterClient failed\n"); 30487c478bd9Sstevel@tonic-gate #endif 30497c478bd9Sstevel@tonic-gate return; 30507c478bd9Sstevel@tonic-gate } 30517c478bd9Sstevel@tonic-gate handle_def++; 30527c478bd9Sstevel@tonic-gate } 30537c478bd9Sstevel@tonic-gate card_info.pd_handle = pcmcia_cs_handle; 30547c478bd9Sstevel@tonic-gate 30557c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 30567c478bd9Sstevel@tonic-gate if (pcmcia_debug) 30577c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 30587c478bd9Sstevel@tonic-gate "pcmcia_create_dev_info: handle = %x\n", 30597c478bd9Sstevel@tonic-gate (int)card_info.pd_handle); 30607c478bd9Sstevel@tonic-gate #endif 30617c478bd9Sstevel@tonic-gate card_info.pd_type = -1; /* no type to start */ 30627c478bd9Sstevel@tonic-gate card_info.pd_socket = socket; 30637c478bd9Sstevel@tonic-gate card_info.pd_function = 0; 30647c478bd9Sstevel@tonic-gate pcmcia_sockets[socket]->ls_functions = 1; /* default */ 30657c478bd9Sstevel@tonic-gate 30667c478bd9Sstevel@tonic-gate cisinfo.Socket = socket; 30677c478bd9Sstevel@tonic-gate 30687c478bd9Sstevel@tonic-gate if ((i = csx_ValidateCIS(card_info.pd_handle, 30697c478bd9Sstevel@tonic-gate &cisinfo)) != SUCCESS || 30707c478bd9Sstevel@tonic-gate cisinfo.Tuples == 0) { 30717c478bd9Sstevel@tonic-gate /* no CIS means memory */ 30727c478bd9Sstevel@tonic-gate (void) strcpy(card_info.pd_generic_name, "memory"); 30737c478bd9Sstevel@tonic-gate card_info.pd_flags |= PCM_NAME_GENERIC | 30747c478bd9Sstevel@tonic-gate PCM_OTHER_NOCIS | PCM_NAME_1275; 30757c478bd9Sstevel@tonic-gate (void) strcpy(card_info.pd_bind_name, "pccard,memory"); 30767c478bd9Sstevel@tonic-gate (void) strcpy(card_info.pd_generic_name, "memory"); 30777c478bd9Sstevel@tonic-gate card_info.pd_type = PCM_TYPE_MEMORY; 30787c478bd9Sstevel@tonic-gate } else { 30797c478bd9Sstevel@tonic-gate int functions, lsocket; 30807c478bd9Sstevel@tonic-gate card_info.pd_tuples = cisinfo.Tuples; 30817c478bd9Sstevel@tonic-gate 30827c478bd9Sstevel@tonic-gate /* 30837c478bd9Sstevel@tonic-gate * how many functions on the card? 30847c478bd9Sstevel@tonic-gate * we need to know and then we do one 30857c478bd9Sstevel@tonic-gate * child node for each function using 30867c478bd9Sstevel@tonic-gate * the function specific tuples. 30877c478bd9Sstevel@tonic-gate */ 30887c478bd9Sstevel@tonic-gate lsocket = CS_MAKE_SOCKET_NUMBER(socket, CS_GLOBAL_CIS); 30897c478bd9Sstevel@tonic-gate functions = pcmcia_num_funcs(lsocket, 30907c478bd9Sstevel@tonic-gate card_info.pd_handle); 30917c478bd9Sstevel@tonic-gate pcmcia_sockets[socket]->ls_functions = functions; 30927c478bd9Sstevel@tonic-gate if (functions > 1) { 30937c478bd9Sstevel@tonic-gate card_info.pd_flags |= PCM_MULTI_FUNCTION; 30947c478bd9Sstevel@tonic-gate } 30957c478bd9Sstevel@tonic-gate for (i = 0; i < functions; i++) { 30967c478bd9Sstevel@tonic-gate register int flags; 30977c478bd9Sstevel@tonic-gate lsocket = CS_MAKE_SOCKET_NUMBER(socket, i); 30987c478bd9Sstevel@tonic-gate card_info.pd_socket = socket; 30997c478bd9Sstevel@tonic-gate card_info.pd_function = i; 31007c478bd9Sstevel@tonic-gate /* 31017c478bd9Sstevel@tonic-gate * new name construction 31027c478bd9Sstevel@tonic-gate */ 31037c478bd9Sstevel@tonic-gate if (functions != 1) { 31047c478bd9Sstevel@tonic-gate /* need per function handle */ 31057c478bd9Sstevel@tonic-gate card_info.pd_function = i; 31067c478bd9Sstevel@tonic-gate /* get new handle */ 31077c478bd9Sstevel@tonic-gate } 31087c478bd9Sstevel@tonic-gate pcmcia_1275_name(lsocket, &card_info, 31097c478bd9Sstevel@tonic-gate card_info.pd_handle); 31107c478bd9Sstevel@tonic-gate pcmcia_vers1_name(lsocket, &card_info, 31117c478bd9Sstevel@tonic-gate card_info.pd_handle); 31127c478bd9Sstevel@tonic-gate pcmcia_generic_name(lsocket, &card_info, 31137c478bd9Sstevel@tonic-gate card_info.pd_handle); 31147c478bd9Sstevel@tonic-gate flags = card_info.pd_flags; 31157c478bd9Sstevel@tonic-gate if (!(flags & PCM_NAME_1275)) { 31167c478bd9Sstevel@tonic-gate if (flags & PCM_NAME_VERS1) { 31177c478bd9Sstevel@tonic-gate (void) strcpy(card_info.pd_bind_name, 31187c478bd9Sstevel@tonic-gate PCMDEV_NAMEPREF); 31197c478bd9Sstevel@tonic-gate card_info.pd_bind_name[sizeof (PCMDEV_NAMEPREF)] = 31207c478bd9Sstevel@tonic-gate ','; 31217c478bd9Sstevel@tonic-gate (void) strncpy(card_info.pd_bind_name + 31227c478bd9Sstevel@tonic-gate sizeof (PCMDEV_NAMEPREF), 31237c478bd9Sstevel@tonic-gate card_info.pd_vers1_name, 31247c478bd9Sstevel@tonic-gate MODMAXNAMELEN - 31257c478bd9Sstevel@tonic-gate sizeof (PCMDEV_NAMEPREF)); 31267c478bd9Sstevel@tonic-gate pcmcia_fix_string(card_info.pd_bind_name); 31277c478bd9Sstevel@tonic-gate } else { 31287c478bd9Sstevel@tonic-gate /* 31297c478bd9Sstevel@tonic-gate * have a CIS but not the right info 31307c478bd9Sstevel@tonic-gate * so treat as generic "pccard" 31317c478bd9Sstevel@tonic-gate */ 31327c478bd9Sstevel@tonic-gate (void) strcpy(card_info.pd_generic_name, 31337c478bd9Sstevel@tonic-gate "pccard,memory"); 31347c478bd9Sstevel@tonic-gate card_info.pd_flags |= PCM_NAME_GENERIC; 31357c478bd9Sstevel@tonic-gate (void) strcpy(card_info.pd_bind_name, 31367c478bd9Sstevel@tonic-gate "pccard,memory"); 31377c478bd9Sstevel@tonic-gate } 31387c478bd9Sstevel@tonic-gate } 31397c478bd9Sstevel@tonic-gate pcmcia_init_devinfo(pdip, &card_info); 31407c478bd9Sstevel@tonic-gate } 31417c478bd9Sstevel@tonic-gate return; 31427c478bd9Sstevel@tonic-gate } 31437c478bd9Sstevel@tonic-gate 31447c478bd9Sstevel@tonic-gate pcmcia_init_devinfo(pdip, &card_info); 31457c478bd9Sstevel@tonic-gate } 31467c478bd9Sstevel@tonic-gate 31477c478bd9Sstevel@tonic-gate /* 31487c478bd9Sstevel@tonic-gate * pcmcia_init_devinfo() 31497c478bd9Sstevel@tonic-gate * if there isn't a device info structure, create one 31507c478bd9Sstevel@tonic-gate * if there is, we don't do much. 31517c478bd9Sstevel@tonic-gate * 31527c478bd9Sstevel@tonic-gate * Note: this will need updating as 1275 finalizes their spec. 31537c478bd9Sstevel@tonic-gate */ 31547c478bd9Sstevel@tonic-gate static void 31557c478bd9Sstevel@tonic-gate pcmcia_init_devinfo(dev_info_t *pdip, struct pcm_device_info *info) 31567c478bd9Sstevel@tonic-gate { 31577c478bd9Sstevel@tonic-gate int unit; 31587c478bd9Sstevel@tonic-gate dev_info_t *dip; 31597c478bd9Sstevel@tonic-gate char *name; 31607c478bd9Sstevel@tonic-gate struct pcmcia_parent_private *ppd; 31617c478bd9Sstevel@tonic-gate 31627c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 31637c478bd9Sstevel@tonic-gate if (pcmcia_debug) 31647c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "init_devinfo(%s, %d)\n", info->pd_bind_name, 31657c478bd9Sstevel@tonic-gate info->pd_socket); 31667c478bd9Sstevel@tonic-gate #endif 31677c478bd9Sstevel@tonic-gate 31687c478bd9Sstevel@tonic-gate /* 31697c478bd9Sstevel@tonic-gate * find out if there is already an instance of this 31707c478bd9Sstevel@tonic-gate * device. We don't want to create a new one unnecessarily 31717c478bd9Sstevel@tonic-gate */ 31727c478bd9Sstevel@tonic-gate unit = CS_MAKE_SOCKET_NUMBER(info->pd_socket, info->pd_function); 31737c478bd9Sstevel@tonic-gate 31747c478bd9Sstevel@tonic-gate dip = pcm_find_devinfo(pdip, info, unit); 31757c478bd9Sstevel@tonic-gate if ((dip != NULL) && (ddi_getprop(DDI_DEV_T_NONE, dip, 31767c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, PCM_DEV_SOCKET, -1) != -1)) { 31777c478bd9Sstevel@tonic-gate /* it already exist but isn't a .conf file */ 31787c478bd9Sstevel@tonic-gate 31797c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 31807c478bd9Sstevel@tonic-gate if (pcmcia_debug) 31817c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "\tfound existing device node (%s)\n", 31827c478bd9Sstevel@tonic-gate ddi_get_name(dip)); 31837c478bd9Sstevel@tonic-gate #endif 31847c478bd9Sstevel@tonic-gate if (strlen(info->pd_vers1_name) > 0) 31857c478bd9Sstevel@tonic-gate (void) ndi_prop_update_string(DDI_DEV_T_NONE, 31867c478bd9Sstevel@tonic-gate dip, PCM_DEV_MODEL, info->pd_vers1_name); 31877c478bd9Sstevel@tonic-gate 31887c478bd9Sstevel@tonic-gate ppd = (struct pcmcia_parent_private *) 31897c478bd9Sstevel@tonic-gate ddi_get_parent_data(dip); 31907c478bd9Sstevel@tonic-gate 31917c478bd9Sstevel@tonic-gate pcmcia_sockets[info->pd_socket]->ls_dip[info->pd_function] = 31927c478bd9Sstevel@tonic-gate dip; 31937c478bd9Sstevel@tonic-gate 31947c478bd9Sstevel@tonic-gate ppd->ppd_active = 1; 31957c478bd9Sstevel@tonic-gate 31967c478bd9Sstevel@tonic-gate if (ndi_devi_online(dip, 0) == NDI_FAILURE) { 31977c478bd9Sstevel@tonic-gate pcmcia_sockets[info->pd_socket]-> \ 31987c478bd9Sstevel@tonic-gate ls_dip[info->pd_function] = NULL; 31997c478bd9Sstevel@tonic-gate ppd->ppd_active = 0; 32007c478bd9Sstevel@tonic-gate } 32017c478bd9Sstevel@tonic-gate } else { 32027c478bd9Sstevel@tonic-gate 32037c478bd9Sstevel@tonic-gate char *dtype; 32047c478bd9Sstevel@tonic-gate 32057c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 32067c478bd9Sstevel@tonic-gate if (pcmcia_debug) 32077c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia: create child [%s](%d): %s\n", 32087c478bd9Sstevel@tonic-gate info->pd_bind_name, info->pd_socket, 32097c478bd9Sstevel@tonic-gate info->pd_generic_name); 32107c478bd9Sstevel@tonic-gate #endif 32117c478bd9Sstevel@tonic-gate 32127c478bd9Sstevel@tonic-gate if (info->pd_flags & PCM_NAME_GENERIC) 32137c478bd9Sstevel@tonic-gate name = info->pd_generic_name; 32147c478bd9Sstevel@tonic-gate else 32157c478bd9Sstevel@tonic-gate name = info->pd_bind_name; 32167c478bd9Sstevel@tonic-gate 3217fa9e4066Sahrens if (ndi_devi_alloc(pdip, name, (pnode_t)DEVI_SID_NODEID, 32187c478bd9Sstevel@tonic-gate &dip) != 32197c478bd9Sstevel@tonic-gate NDI_SUCCESS) { 32207c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 32217c478bd9Sstevel@tonic-gate "pcmcia: unable to create device [%s](%d)\n", 32227c478bd9Sstevel@tonic-gate name, info->pd_socket); 32237c478bd9Sstevel@tonic-gate return; 32247c478bd9Sstevel@tonic-gate } 32257c478bd9Sstevel@tonic-gate /* 32267c478bd9Sstevel@tonic-gate * construct the "compatible" property if the device 32277c478bd9Sstevel@tonic-gate * has a generic name 32287c478bd9Sstevel@tonic-gate */ 32297c478bd9Sstevel@tonic-gate pcmcia_add_compatible(dip, info); 32307c478bd9Sstevel@tonic-gate 32317c478bd9Sstevel@tonic-gate ppd = kmem_zalloc(sizeof (struct pcmcia_parent_private), 32327c478bd9Sstevel@tonic-gate KM_SLEEP); 32337c478bd9Sstevel@tonic-gate 32347c478bd9Sstevel@tonic-gate ppd->ppd_socket = info->pd_socket; 32357c478bd9Sstevel@tonic-gate ppd->ppd_function = info->pd_function; 32367c478bd9Sstevel@tonic-gate 32377c478bd9Sstevel@tonic-gate /* 32387c478bd9Sstevel@tonic-gate * add the "socket" property 32397c478bd9Sstevel@tonic-gate * the value of this property contains the logical PCMCIA 32407c478bd9Sstevel@tonic-gate * socket number the device has been inserted in, along 32417c478bd9Sstevel@tonic-gate * with the function # if the device is part of a 32427c478bd9Sstevel@tonic-gate * multi-function device. 32437c478bd9Sstevel@tonic-gate */ 32447c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, dip, 32457c478bd9Sstevel@tonic-gate PCM_DEV_SOCKET, unit); 32467c478bd9Sstevel@tonic-gate 32477c478bd9Sstevel@tonic-gate if (info->pd_flags & PCM_MULTI_FUNCTION) 32487c478bd9Sstevel@tonic-gate ppd->ppd_flags |= PPD_CARD_MULTI; 32497c478bd9Sstevel@tonic-gate 32507c478bd9Sstevel@tonic-gate /* 32517c478bd9Sstevel@tonic-gate * determine all the properties we need for PPD 32527c478bd9Sstevel@tonic-gate * then create the properties 32537c478bd9Sstevel@tonic-gate */ 32547c478bd9Sstevel@tonic-gate /* socket is unique */ 32557c478bd9Sstevel@tonic-gate pcmcia_find_regs(dip, info, ppd); 32567c478bd9Sstevel@tonic-gate 32577c478bd9Sstevel@tonic-gate ppd->ppd_intr = pcmcia_need_intr(unit, info); 32587c478bd9Sstevel@tonic-gate 32597c478bd9Sstevel@tonic-gate if (ppd->ppd_nreg > 0) 32607c478bd9Sstevel@tonic-gate (void) ddi_prop_update_int_array(DDI_DEV_T_NONE, dip, 32617c478bd9Sstevel@tonic-gate "reg", (int *)ppd->ppd_reg, ppd->ppd_nreg * 32627c478bd9Sstevel@tonic-gate sizeof (struct pcm_regs) / sizeof (int)); 32637c478bd9Sstevel@tonic-gate if (ppd->ppd_intr) { 32647c478bd9Sstevel@tonic-gate (void) ddi_prop_update_int(DDI_DEV_T_NONE, dip, 32657c478bd9Sstevel@tonic-gate "interrupts", ppd->ppd_intr); 32667c478bd9Sstevel@tonic-gate ppd->ppd_intrspec = 32677c478bd9Sstevel@tonic-gate kmem_zalloc(sizeof (struct intrspec), KM_SLEEP); 32687c478bd9Sstevel@tonic-gate } 32697c478bd9Sstevel@tonic-gate 32707c478bd9Sstevel@tonic-gate /* set parent private - our own format */ 32717c478bd9Sstevel@tonic-gate ddi_set_parent_data(dip, (caddr_t)ppd); 32727c478bd9Sstevel@tonic-gate 32737c478bd9Sstevel@tonic-gate /* init the device type */ 32747c478bd9Sstevel@tonic-gate if (info->pd_type >= 0 && 32757c478bd9Sstevel@tonic-gate info->pd_type < (sizeof (pcmcia_dev_type) / 32767c478bd9Sstevel@tonic-gate (sizeof (char *)))) 32777c478bd9Sstevel@tonic-gate dtype = pcmcia_dev_type[info->pd_type]; 32787c478bd9Sstevel@tonic-gate else 32797c478bd9Sstevel@tonic-gate dtype = "unknown"; 32807c478bd9Sstevel@tonic-gate 32817c478bd9Sstevel@tonic-gate if (strlen(info->pd_vers1_name) > 0) 32827c478bd9Sstevel@tonic-gate (void) ndi_prop_update_string(DDI_DEV_T_NONE, 32837c478bd9Sstevel@tonic-gate dip, PCM_DEV_MODEL, info->pd_vers1_name); 32847c478bd9Sstevel@tonic-gate 32857c478bd9Sstevel@tonic-gate (void) ndi_prop_update_string(DDI_DEV_T_NONE, dip, 32867c478bd9Sstevel@tonic-gate PCM_DEVICETYPE, dtype); 32877c478bd9Sstevel@tonic-gate 32887c478bd9Sstevel@tonic-gate /* set PC Card as active and present in socket */ 32897c478bd9Sstevel@tonic-gate pcmcia_sockets[info->pd_socket]->ls_dip[info->pd_function] = 32907c478bd9Sstevel@tonic-gate dip; 32917c478bd9Sstevel@tonic-gate 32927c478bd9Sstevel@tonic-gate ppd->ppd_active = 1; 32937c478bd9Sstevel@tonic-gate 32947c478bd9Sstevel@tonic-gate /* 32957c478bd9Sstevel@tonic-gate * We should not call ndi_devi_online here if 32967c478bd9Sstevel@tonic-gate * pcmcia attach is in progress. This causes a deadlock. 32977c478bd9Sstevel@tonic-gate */ 32987c478bd9Sstevel@tonic-gate if (pcmcia_dip != dip) { 32997c478bd9Sstevel@tonic-gate if (ndi_devi_online_async(dip, 0) 33007c478bd9Sstevel@tonic-gate != NDI_SUCCESS) { 33017c478bd9Sstevel@tonic-gate pcmcia_sockets[info->pd_socket]->\ 33027c478bd9Sstevel@tonic-gate ls_dip[info->pd_function] = NULL; 33037c478bd9Sstevel@tonic-gate pcmcia_ppd_free(ppd); 33047c478bd9Sstevel@tonic-gate (void) ndi_devi_free(dip); 33057c478bd9Sstevel@tonic-gate return; 33067c478bd9Sstevel@tonic-gate } 33077c478bd9Sstevel@tonic-gate } 33087c478bd9Sstevel@tonic-gate 33097c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 33107c478bd9Sstevel@tonic-gate if (pcmcia_debug) 33117c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "\tjust added \"active\" to %s in %d\n", 33127c478bd9Sstevel@tonic-gate ddi_get_name(dip), info->pd_socket); 33137c478bd9Sstevel@tonic-gate #endif 33147c478bd9Sstevel@tonic-gate } 33157c478bd9Sstevel@tonic-gate 33167c478bd9Sstevel@tonic-gate /* 33177c478bd9Sstevel@tonic-gate * inform the event manager that a child was added 33187c478bd9Sstevel@tonic-gate * to the device tree. 33197c478bd9Sstevel@tonic-gate */ 33207c478bd9Sstevel@tonic-gate pcm_event_manager(PCE_DEV_IDENT, unit, ddi_get_name(dip)); 33217c478bd9Sstevel@tonic-gate 33227c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 33237c478bd9Sstevel@tonic-gate if (pcmcia_debug > 1) { 33247c478bd9Sstevel@tonic-gate pcmcia_dump_minors(dip); 33257c478bd9Sstevel@tonic-gate } 33267c478bd9Sstevel@tonic-gate #endif 33277c478bd9Sstevel@tonic-gate } 33287c478bd9Sstevel@tonic-gate 33297c478bd9Sstevel@tonic-gate /* 33307c478bd9Sstevel@tonic-gate * free any allocated parent-private data 33317c478bd9Sstevel@tonic-gate */ 33327c478bd9Sstevel@tonic-gate static void 33337c478bd9Sstevel@tonic-gate pcmcia_ppd_free(struct pcmcia_parent_private *ppd) 33347c478bd9Sstevel@tonic-gate { 33357c478bd9Sstevel@tonic-gate size_t len; 33367c478bd9Sstevel@tonic-gate 33377c478bd9Sstevel@tonic-gate if (ppd->ppd_nreg != 0) { 33387c478bd9Sstevel@tonic-gate len = ppd->ppd_nreg * sizeof (uint32_t) * 3; 33397c478bd9Sstevel@tonic-gate kmem_free(ppd->ppd_reg, len); 33407c478bd9Sstevel@tonic-gate len = sizeof (struct pcm_regs) * ppd->ppd_nreg; 33417c478bd9Sstevel@tonic-gate kmem_free(ppd->ppd_assigned, len); 33427c478bd9Sstevel@tonic-gate } 33437c478bd9Sstevel@tonic-gate 33447c478bd9Sstevel@tonic-gate /* 33457c478bd9Sstevel@tonic-gate * pcmcia only allocates 1 intrspec today 33467c478bd9Sstevel@tonic-gate */ 33477c478bd9Sstevel@tonic-gate if (ppd->ppd_intr != 0) { 33487c478bd9Sstevel@tonic-gate len = sizeof (struct intrspec) * ppd->ppd_intr; 33497c478bd9Sstevel@tonic-gate kmem_free(ppd->ppd_intrspec, len); 33507c478bd9Sstevel@tonic-gate } 33517c478bd9Sstevel@tonic-gate 33527c478bd9Sstevel@tonic-gate kmem_free(ppd, sizeof (*ppd)); 33537c478bd9Sstevel@tonic-gate } 33547c478bd9Sstevel@tonic-gate 33557c478bd9Sstevel@tonic-gate 33567c478bd9Sstevel@tonic-gate /* 33577c478bd9Sstevel@tonic-gate * pcmcia_get_devinfo(socket) 33587c478bd9Sstevel@tonic-gate * entry point to allow finding the device info structure 33597c478bd9Sstevel@tonic-gate * for a given logical socket. Used by event manager 33607c478bd9Sstevel@tonic-gate */ 33617c478bd9Sstevel@tonic-gate dev_info_t * 33627c478bd9Sstevel@tonic-gate pcmcia_get_devinfo(int socket) 33637c478bd9Sstevel@tonic-gate { 33647c478bd9Sstevel@tonic-gate int func = CS_GET_FUNCTION_NUMBER(socket); 33657c478bd9Sstevel@tonic-gate socket = CS_GET_SOCKET_NUMBER(socket); 33667c478bd9Sstevel@tonic-gate if (pcmcia_sockets[socket]) 33677c478bd9Sstevel@tonic-gate return (pcmcia_sockets[socket]->ls_dip[func]); 33687c478bd9Sstevel@tonic-gate return ((dev_info_t *)NULL); 33697c478bd9Sstevel@tonic-gate } 33707c478bd9Sstevel@tonic-gate 33717c478bd9Sstevel@tonic-gate /* 33727c478bd9Sstevel@tonic-gate * CSGetCookiesAndDip() 33737c478bd9Sstevel@tonic-gate * get info needed by CS to setup soft interrupt handler and provide 33747c478bd9Sstevel@tonic-gate * socket-specific adapter information 33757c478bd9Sstevel@tonic-gate */ 33767c478bd9Sstevel@tonic-gate static int 33777c478bd9Sstevel@tonic-gate GetCookiesAndDip(sservice_t *serv) 33787c478bd9Sstevel@tonic-gate { 33797c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t *socket; 33807c478bd9Sstevel@tonic-gate csss_adapter_info_t *ai; 33817c478bd9Sstevel@tonic-gate int sock; 33827c478bd9Sstevel@tonic-gate 33837c478bd9Sstevel@tonic-gate sock = CS_GET_SOCKET_NUMBER(serv->get_cookies.socket); 33847c478bd9Sstevel@tonic-gate 33857c478bd9Sstevel@tonic-gate if (sock >= pcmcia_num_sockets || 33867c478bd9Sstevel@tonic-gate (int)serv->get_cookies.socket < 0) 33877c478bd9Sstevel@tonic-gate return (BAD_SOCKET); 33887c478bd9Sstevel@tonic-gate 33897c478bd9Sstevel@tonic-gate socket = pcmcia_sockets[sock]; 33907c478bd9Sstevel@tonic-gate ai = &serv->get_cookies.adapter_info; 33917c478bd9Sstevel@tonic-gate serv->get_cookies.dip = socket->ls_adapter->pca_dip; 33927c478bd9Sstevel@tonic-gate serv->get_cookies.iblock = socket->ls_adapter->pca_iblock; 33937c478bd9Sstevel@tonic-gate serv->get_cookies.idevice = socket->ls_adapter->pca_idev; 33947c478bd9Sstevel@tonic-gate 33957c478bd9Sstevel@tonic-gate /* 33967c478bd9Sstevel@tonic-gate * Setup the adapter info for Card Services 33977c478bd9Sstevel@tonic-gate */ 33987c478bd9Sstevel@tonic-gate (void) strcpy(ai->name, socket->ls_adapter->pca_name); 33997c478bd9Sstevel@tonic-gate ai->major = socket->ls_adapter->pca_module; 34007c478bd9Sstevel@tonic-gate ai->minor = socket->ls_adapter->pca_unit; 34017c478bd9Sstevel@tonic-gate ai->number = socket->ls_adapter->pca_number; 34027c478bd9Sstevel@tonic-gate ai->num_sockets = socket->ls_adapter->pca_numsockets; 34037c478bd9Sstevel@tonic-gate ai->first_socket = socket->ls_adapter->pca_first_socket; 34047c478bd9Sstevel@tonic-gate 34057c478bd9Sstevel@tonic-gate return (SUCCESS); 34067c478bd9Sstevel@tonic-gate } 34077c478bd9Sstevel@tonic-gate 34087c478bd9Sstevel@tonic-gate /* 34097c478bd9Sstevel@tonic-gate * Note: 34107c478bd9Sstevel@tonic-gate * The following functions that start with 'SS' 34117c478bd9Sstevel@tonic-gate * implement SocketServices interfaces. They 34127c478bd9Sstevel@tonic-gate * simply map the socket and/or window number to 34137c478bd9Sstevel@tonic-gate * the adapter specific number based on the general 34147c478bd9Sstevel@tonic-gate * value that CardServices uses. 34157c478bd9Sstevel@tonic-gate * 34167c478bd9Sstevel@tonic-gate * See the descriptions in SocketServices for 34177c478bd9Sstevel@tonic-gate * details. Also refer to specific adapter drivers 34187c478bd9Sstevel@tonic-gate * for implementation reference. 34197c478bd9Sstevel@tonic-gate */ 34207c478bd9Sstevel@tonic-gate 34217c478bd9Sstevel@tonic-gate static int 34227c478bd9Sstevel@tonic-gate SSGetAdapter(get_adapter_t *adapter) 34237c478bd9Sstevel@tonic-gate { 34247c478bd9Sstevel@tonic-gate int n; 34257c478bd9Sstevel@tonic-gate get_adapter_t info; 34267c478bd9Sstevel@tonic-gate 34277c478bd9Sstevel@tonic-gate adapter->state = (unsigned)0xFFFFFFFF; 34287c478bd9Sstevel@tonic-gate adapter->SCRouting = 0xFFFFFFFF; 34297c478bd9Sstevel@tonic-gate 34307c478bd9Sstevel@tonic-gate for (n = 0; n < pcmcia_num_adapters; n++) { 34317c478bd9Sstevel@tonic-gate GET_ADAPTER(pcmcia_adapters[n]->pca_if, 34327c478bd9Sstevel@tonic-gate pcmcia_adapters[n]->pca_dip, &info); 34337c478bd9Sstevel@tonic-gate adapter->state &= info.state; 34347c478bd9Sstevel@tonic-gate adapter->SCRouting &= info.SCRouting; 34357c478bd9Sstevel@tonic-gate } 34367c478bd9Sstevel@tonic-gate 34377c478bd9Sstevel@tonic-gate return (SUCCESS); 34387c478bd9Sstevel@tonic-gate } 34397c478bd9Sstevel@tonic-gate 34407c478bd9Sstevel@tonic-gate static int 34417c478bd9Sstevel@tonic-gate SSGetPage(get_page_t *page) 34427c478bd9Sstevel@tonic-gate { 34437c478bd9Sstevel@tonic-gate pcmcia_logical_window_t *window; 34447c478bd9Sstevel@tonic-gate get_page_t newpage; 34457c478bd9Sstevel@tonic-gate int retval, win; 34467c478bd9Sstevel@tonic-gate 34477c478bd9Sstevel@tonic-gate if (page->window > pcmcia_num_windows) { 34487c478bd9Sstevel@tonic-gate return (BAD_WINDOW); 34497c478bd9Sstevel@tonic-gate } 34507c478bd9Sstevel@tonic-gate 34517c478bd9Sstevel@tonic-gate window = pcmcia_windows[page->window]; 34527c478bd9Sstevel@tonic-gate newpage = *page; 34537c478bd9Sstevel@tonic-gate win = newpage.window = window->lw_window; /* real window */ 34547c478bd9Sstevel@tonic-gate 34557c478bd9Sstevel@tonic-gate retval = GET_PAGE(window->lw_if, window->lw_adapter->pca_dip, 34567c478bd9Sstevel@tonic-gate &newpage); 34577c478bd9Sstevel@tonic-gate if (retval == SUCCESS) { 34587c478bd9Sstevel@tonic-gate *page = newpage; 34597c478bd9Sstevel@tonic-gate page->window = win; 34607c478bd9Sstevel@tonic-gate } 34617c478bd9Sstevel@tonic-gate return (retval); 34627c478bd9Sstevel@tonic-gate } 34637c478bd9Sstevel@tonic-gate 34647c478bd9Sstevel@tonic-gate static int 34657c478bd9Sstevel@tonic-gate SSGetSocket(get_socket_t *socket) 34667c478bd9Sstevel@tonic-gate { 34677c478bd9Sstevel@tonic-gate int retval, sock; 34687c478bd9Sstevel@tonic-gate get_socket_t newsocket; 34697c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t *sockp; 34707c478bd9Sstevel@tonic-gate 34717c478bd9Sstevel@tonic-gate sock = socket->socket; 34727c478bd9Sstevel@tonic-gate if (sock > pcmcia_num_sockets || 34737c478bd9Sstevel@tonic-gate (sockp = pcmcia_sockets[sock]) == NULL) { 34747c478bd9Sstevel@tonic-gate return (BAD_SOCKET); 34757c478bd9Sstevel@tonic-gate } 34767c478bd9Sstevel@tonic-gate 34777c478bd9Sstevel@tonic-gate newsocket = *socket; 34787c478bd9Sstevel@tonic-gate newsocket.socket = sockp->ls_socket; 34797c478bd9Sstevel@tonic-gate retval = GET_SOCKET(sockp->ls_if, sockp->ls_adapter->pca_dip, 34807c478bd9Sstevel@tonic-gate &newsocket); 34817c478bd9Sstevel@tonic-gate if (retval == SUCCESS) { 34827c478bd9Sstevel@tonic-gate newsocket.VccLevel = pcmcia_map_power_get(sockp->ls_adapter, 34837c478bd9Sstevel@tonic-gate newsocket.VccLevel, 34847c478bd9Sstevel@tonic-gate VCC); 34857c478bd9Sstevel@tonic-gate newsocket.Vpp1Level = pcmcia_map_power_get(sockp->ls_adapter, 34867c478bd9Sstevel@tonic-gate newsocket.Vpp1Level, 34877c478bd9Sstevel@tonic-gate VPP1); 34887c478bd9Sstevel@tonic-gate newsocket.Vpp2Level = pcmcia_map_power_get(sockp->ls_adapter, 34897c478bd9Sstevel@tonic-gate newsocket.Vpp2Level, 34907c478bd9Sstevel@tonic-gate VPP2); 34917c478bd9Sstevel@tonic-gate *socket = newsocket; 34927c478bd9Sstevel@tonic-gate socket->socket = sock; 34937c478bd9Sstevel@tonic-gate } 34947c478bd9Sstevel@tonic-gate 34957c478bd9Sstevel@tonic-gate return (retval); 34967c478bd9Sstevel@tonic-gate } 34977c478bd9Sstevel@tonic-gate 34987c478bd9Sstevel@tonic-gate static int 34997c478bd9Sstevel@tonic-gate SSGetStatus(get_ss_status_t *status) 35007c478bd9Sstevel@tonic-gate { 35017c478bd9Sstevel@tonic-gate get_ss_status_t newstat; 35027c478bd9Sstevel@tonic-gate int sock, retval; 35037c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t *sockp; 35047c478bd9Sstevel@tonic-gate 35057c478bd9Sstevel@tonic-gate sock = status->socket; 35067c478bd9Sstevel@tonic-gate if (sock > pcmcia_num_sockets || 35077c478bd9Sstevel@tonic-gate (sockp = pcmcia_sockets[sock]) == NULL) { 35087c478bd9Sstevel@tonic-gate return (BAD_SOCKET); 35097c478bd9Sstevel@tonic-gate } 35107c478bd9Sstevel@tonic-gate 35117c478bd9Sstevel@tonic-gate newstat = *status; 35127c478bd9Sstevel@tonic-gate newstat.socket = sockp->ls_socket; 35137c478bd9Sstevel@tonic-gate retval = GET_STATUS(sockp->ls_if, sockp->ls_adapter->pca_dip, 35147c478bd9Sstevel@tonic-gate &newstat); 35157c478bd9Sstevel@tonic-gate if (retval == SUCCESS) { 35167c478bd9Sstevel@tonic-gate *status = newstat; 35177c478bd9Sstevel@tonic-gate status->socket = sock; 35187c478bd9Sstevel@tonic-gate } 35197c478bd9Sstevel@tonic-gate 35207c478bd9Sstevel@tonic-gate return (retval); 35217c478bd9Sstevel@tonic-gate } 35227c478bd9Sstevel@tonic-gate 35237c478bd9Sstevel@tonic-gate static int 35247c478bd9Sstevel@tonic-gate SSGetWindow(get_window_t *window) 35257c478bd9Sstevel@tonic-gate { 35267c478bd9Sstevel@tonic-gate int win, retval; 35277c478bd9Sstevel@tonic-gate get_window_t newwin; 35287c478bd9Sstevel@tonic-gate pcmcia_logical_window_t *winp; 35297c478bd9Sstevel@tonic-gate 35307c478bd9Sstevel@tonic-gate win = window->window; 35317c478bd9Sstevel@tonic-gate winp = pcmcia_windows[win]; 35327c478bd9Sstevel@tonic-gate newwin = *window; 35337c478bd9Sstevel@tonic-gate newwin.window = winp->lw_window; 35347c478bd9Sstevel@tonic-gate 35357c478bd9Sstevel@tonic-gate retval = GET_WINDOW(winp->lw_if, winp->lw_adapter->pca_dip, 35367c478bd9Sstevel@tonic-gate &newwin); 35377c478bd9Sstevel@tonic-gate if (retval == SUCCESS) { 35387c478bd9Sstevel@tonic-gate newwin.socket = winp->lw_socket; 35397c478bd9Sstevel@tonic-gate newwin.window = win; 35407c478bd9Sstevel@tonic-gate *window = newwin; 35417c478bd9Sstevel@tonic-gate } 35427c478bd9Sstevel@tonic-gate return (retval); 35437c478bd9Sstevel@tonic-gate } 35447c478bd9Sstevel@tonic-gate 35457c478bd9Sstevel@tonic-gate /* 35467c478bd9Sstevel@tonic-gate * SSInquireAdapter() 35477c478bd9Sstevel@tonic-gate * Get the capabilities of the "generic" adapter 35487c478bd9Sstevel@tonic-gate * we are exporting to CS. 35497c478bd9Sstevel@tonic-gate */ 35507c478bd9Sstevel@tonic-gate static int 35517c478bd9Sstevel@tonic-gate SSInquireAdapter(inquire_adapter_t *adapter) 35527c478bd9Sstevel@tonic-gate { 35537c478bd9Sstevel@tonic-gate adapter->NumSockets = pcmcia_num_sockets; 35547c478bd9Sstevel@tonic-gate adapter->NumWindows = pcmcia_num_windows; 35557c478bd9Sstevel@tonic-gate adapter->NumEDCs = 0; 35567c478bd9Sstevel@tonic-gate /* 35577c478bd9Sstevel@tonic-gate * notes: Adapter Capabilities are going to be difficult to 35587c478bd9Sstevel@tonic-gate * determine with reliability. Fortunately, most of them 35597c478bd9Sstevel@tonic-gate * don't matter under Solaris or can be handled transparently 35607c478bd9Sstevel@tonic-gate */ 35617c478bd9Sstevel@tonic-gate adapter->AdpCaps = 0; /* need to fix these */ 35627c478bd9Sstevel@tonic-gate /* 35637c478bd9Sstevel@tonic-gate * interrupts need a little work. For x86, the valid IRQs will 35647c478bd9Sstevel@tonic-gate * be restricted to those that the system has exported to the nexus. 35657c478bd9Sstevel@tonic-gate * for SPARC, it will be the DoRight values. 35667c478bd9Sstevel@tonic-gate */ 35677c478bd9Sstevel@tonic-gate adapter->ActiveHigh = 0; 35687c478bd9Sstevel@tonic-gate adapter->ActiveLow = 0; 35697c478bd9Sstevel@tonic-gate adapter->power_entry = pcmcia_power_table; /* until we resolve this */ 35707c478bd9Sstevel@tonic-gate adapter->NumPower = pcmcia_num_power; 35717c478bd9Sstevel@tonic-gate return (SUCCESS); 35727c478bd9Sstevel@tonic-gate } 35737c478bd9Sstevel@tonic-gate 35747c478bd9Sstevel@tonic-gate static int 35757c478bd9Sstevel@tonic-gate SSInquireSocket(inquire_socket_t *socket) 35767c478bd9Sstevel@tonic-gate { 35777c478bd9Sstevel@tonic-gate int retval, sock; 35787c478bd9Sstevel@tonic-gate inquire_socket_t newsocket; 35797c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t *sockp; 35807c478bd9Sstevel@tonic-gate 35817c478bd9Sstevel@tonic-gate sock = socket->socket; 35827c478bd9Sstevel@tonic-gate if (sock > pcmcia_num_sockets || 35837c478bd9Sstevel@tonic-gate (sockp = pcmcia_sockets[sock]) == NULL) 35847c478bd9Sstevel@tonic-gate return (BAD_SOCKET); 35857c478bd9Sstevel@tonic-gate newsocket = *socket; 35867c478bd9Sstevel@tonic-gate newsocket.socket = sockp->ls_socket; 35877c478bd9Sstevel@tonic-gate retval = INQUIRE_SOCKET(sockp->ls_if, sockp->ls_adapter->pca_dip, 35887c478bd9Sstevel@tonic-gate &newsocket); 35897c478bd9Sstevel@tonic-gate if (retval == SUCCESS) { 35907c478bd9Sstevel@tonic-gate *socket = newsocket; 35917c478bd9Sstevel@tonic-gate socket->socket = sock; 35927c478bd9Sstevel@tonic-gate } 35937c478bd9Sstevel@tonic-gate return (retval); 35947c478bd9Sstevel@tonic-gate } 35957c478bd9Sstevel@tonic-gate 35967c478bd9Sstevel@tonic-gate static int 35977c478bd9Sstevel@tonic-gate SSInquireWindow(inquire_window_t *window) 35987c478bd9Sstevel@tonic-gate { 35997c478bd9Sstevel@tonic-gate int retval, win; 36007c478bd9Sstevel@tonic-gate pcmcia_logical_window_t *winp; 36017c478bd9Sstevel@tonic-gate inquire_window_t newwin; 36027c478bd9Sstevel@tonic-gate int slide; 36037c478bd9Sstevel@tonic-gate 36047c478bd9Sstevel@tonic-gate win = window->window; 36057c478bd9Sstevel@tonic-gate if (win > pcmcia_num_windows) 36067c478bd9Sstevel@tonic-gate return (BAD_WINDOW); 36077c478bd9Sstevel@tonic-gate 36087c478bd9Sstevel@tonic-gate winp = pcmcia_windows[win]; 36097c478bd9Sstevel@tonic-gate newwin = *window; 36107c478bd9Sstevel@tonic-gate newwin.window = winp->lw_window; 36117c478bd9Sstevel@tonic-gate retval = INQUIRE_WINDOW(winp->lw_if, winp->lw_adapter->pca_dip, 36127c478bd9Sstevel@tonic-gate &newwin); 36137c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 36147c478bd9Sstevel@tonic-gate if (pcmcia_debug > 1) 36157c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "SSInquireWindow: win=%d, pwin=%d\n", 36167c478bd9Sstevel@tonic-gate win, newwin.window); 36177c478bd9Sstevel@tonic-gate #endif 36187c478bd9Sstevel@tonic-gate if (retval == SUCCESS) { 36197c478bd9Sstevel@tonic-gate *window = newwin; 36207c478bd9Sstevel@tonic-gate /* just in case */ 36217c478bd9Sstevel@tonic-gate window->iowin_char.IOWndCaps &= ~WC_BASE; 36227c478bd9Sstevel@tonic-gate slide = winp->lw_adapter->pca_first_socket; 36237c478bd9Sstevel@tonic-gate /* 36247c478bd9Sstevel@tonic-gate * note that sockets are relative to the adapter. 36257c478bd9Sstevel@tonic-gate * we have to adjust the bits to show a logical 36267c478bd9Sstevel@tonic-gate * version. 36277c478bd9Sstevel@tonic-gate */ 36287c478bd9Sstevel@tonic-gate 36297c478bd9Sstevel@tonic-gate pcm_fix_bits(newwin.Sockets, window->Sockets, slide, 0); 36307c478bd9Sstevel@tonic-gate 36317c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 36327c478bd9Sstevel@tonic-gate if (pcmcia_debug > 1) { 36337c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "iw: orig bits=%x, new bits=%x\n", 36347c478bd9Sstevel@tonic-gate (int)*(uint32_t *)newwin.Sockets, 36357c478bd9Sstevel@tonic-gate (int)*(uint32_t *)window->Sockets); 36367c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "\t%x.%x.%x\n", window->WndCaps, 36377c478bd9Sstevel@tonic-gate window->mem_win_char.MemWndCaps, 36387c478bd9Sstevel@tonic-gate window->mem_win_char.MinSize); 36397c478bd9Sstevel@tonic-gate } 36407c478bd9Sstevel@tonic-gate #endif 36417c478bd9Sstevel@tonic-gate window->window = win; 36427c478bd9Sstevel@tonic-gate } 36437c478bd9Sstevel@tonic-gate return (retval); 36447c478bd9Sstevel@tonic-gate } 36457c478bd9Sstevel@tonic-gate 36467c478bd9Sstevel@tonic-gate static int 36477c478bd9Sstevel@tonic-gate SSResetSocket(int socket, int mode) 36487c478bd9Sstevel@tonic-gate { 36497c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t *sockp; 36507c478bd9Sstevel@tonic-gate 36517c478bd9Sstevel@tonic-gate if (socket >= pcmcia_num_sockets || 36527c478bd9Sstevel@tonic-gate (sockp = pcmcia_sockets[socket]) == NULL) 36537c478bd9Sstevel@tonic-gate return (BAD_SOCKET); 36547c478bd9Sstevel@tonic-gate 36557c478bd9Sstevel@tonic-gate return (RESET_SOCKET(sockp->ls_if, sockp->ls_adapter->pca_dip, 36567c478bd9Sstevel@tonic-gate sockp->ls_socket, mode)); 36577c478bd9Sstevel@tonic-gate } 36587c478bd9Sstevel@tonic-gate 36597c478bd9Sstevel@tonic-gate static int 36607c478bd9Sstevel@tonic-gate SSSetPage(set_page_t *page) 36617c478bd9Sstevel@tonic-gate { 36627c478bd9Sstevel@tonic-gate int window, retval; 36637c478bd9Sstevel@tonic-gate set_page_t newpage; 36647c478bd9Sstevel@tonic-gate pcmcia_logical_window_t *winp; 36657c478bd9Sstevel@tonic-gate 36667c478bd9Sstevel@tonic-gate window = page->window; 36677c478bd9Sstevel@tonic-gate if (window > pcmcia_num_windows) { 36687c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 36697c478bd9Sstevel@tonic-gate if (pcmcia_debug > 1) 36707c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "SSSetPage: window=%d (of %d)\n", 36717c478bd9Sstevel@tonic-gate window, pcmcia_num_windows); 36727c478bd9Sstevel@tonic-gate #endif 36737c478bd9Sstevel@tonic-gate return (BAD_WINDOW); 36747c478bd9Sstevel@tonic-gate } 36757c478bd9Sstevel@tonic-gate 36767c478bd9Sstevel@tonic-gate winp = pcmcia_windows[window]; 36777c478bd9Sstevel@tonic-gate newpage = *page; 36787c478bd9Sstevel@tonic-gate newpage.window = winp->lw_window; 36797c478bd9Sstevel@tonic-gate retval = SET_PAGE(winp->lw_if, winp->lw_adapter->pca_dip, &newpage); 36807c478bd9Sstevel@tonic-gate if (retval == SUCCESS) { 36817c478bd9Sstevel@tonic-gate newpage.window = window; 36827c478bd9Sstevel@tonic-gate *page = newpage; 36837c478bd9Sstevel@tonic-gate } 36847c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 36857c478bd9Sstevel@tonic-gate if ((pcmcia_debug > 1) && retval != SUCCESS) 36867c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "\tSetPage: returning error %x\n", retval); 36877c478bd9Sstevel@tonic-gate #endif 36887c478bd9Sstevel@tonic-gate return (retval); 36897c478bd9Sstevel@tonic-gate } 36907c478bd9Sstevel@tonic-gate 36917c478bd9Sstevel@tonic-gate static int 36927c478bd9Sstevel@tonic-gate SSSetWindow(set_window_t *win) 36937c478bd9Sstevel@tonic-gate { 36947c478bd9Sstevel@tonic-gate int socket, window, retval, func; 36957c478bd9Sstevel@tonic-gate set_window_t newwin; 36967c478bd9Sstevel@tonic-gate pcmcia_logical_window_t *winp; 36977c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t *sockp; 36987c478bd9Sstevel@tonic-gate 36997c478bd9Sstevel@tonic-gate window = win->window; 37007c478bd9Sstevel@tonic-gate if (window > pcmcia_num_windows) 37017c478bd9Sstevel@tonic-gate return (BAD_WINDOW); 37027c478bd9Sstevel@tonic-gate 37037c478bd9Sstevel@tonic-gate socket = CS_GET_SOCKET_NUMBER(win->socket); 37047c478bd9Sstevel@tonic-gate func = CS_GET_FUNCTION_NUMBER(win->socket); 37057c478bd9Sstevel@tonic-gate 37067c478bd9Sstevel@tonic-gate if (socket > pcmcia_num_sockets || 37077c478bd9Sstevel@tonic-gate (sockp = pcmcia_sockets[socket]) == NULL) { 37087c478bd9Sstevel@tonic-gate return (BAD_SOCKET); 37097c478bd9Sstevel@tonic-gate } 37107c478bd9Sstevel@tonic-gate 37117c478bd9Sstevel@tonic-gate winp = pcmcia_windows[window]; 37127c478bd9Sstevel@tonic-gate winp->lw_socket = win->socket; /* reverse map */ 37137c478bd9Sstevel@tonic-gate newwin = *win; 37147c478bd9Sstevel@tonic-gate newwin.window = winp->lw_window; 37157c478bd9Sstevel@tonic-gate newwin.socket = sockp->ls_socket; 37167c478bd9Sstevel@tonic-gate newwin.child = sockp->ls_dip[func]; /* so we carry the dip around */ 37177c478bd9Sstevel@tonic-gate 37187c478bd9Sstevel@tonic-gate retval = SET_WINDOW(winp->lw_if, winp->lw_adapter->pca_dip, &newwin); 37197c478bd9Sstevel@tonic-gate if (retval == SUCCESS) { 37207c478bd9Sstevel@tonic-gate newwin.window = window; 37217c478bd9Sstevel@tonic-gate newwin.socket = winp->lw_socket; 37227c478bd9Sstevel@tonic-gate *win = newwin; 37237c478bd9Sstevel@tonic-gate } 37247c478bd9Sstevel@tonic-gate return (retval); 37257c478bd9Sstevel@tonic-gate } 37267c478bd9Sstevel@tonic-gate 37277c478bd9Sstevel@tonic-gate static int 37287c478bd9Sstevel@tonic-gate SSSetSocket(set_socket_t *socket) 37297c478bd9Sstevel@tonic-gate { 37307c478bd9Sstevel@tonic-gate int sock, retval; 37317c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t *sockp; 37327c478bd9Sstevel@tonic-gate set_socket_t newsock; 37337c478bd9Sstevel@tonic-gate 37347c478bd9Sstevel@tonic-gate sock = socket->socket; 37357c478bd9Sstevel@tonic-gate if (sock > pcmcia_num_sockets || 37367c478bd9Sstevel@tonic-gate (sockp = pcmcia_sockets[sock]) == NULL) { 37377c478bd9Sstevel@tonic-gate return (BAD_SOCKET); 37387c478bd9Sstevel@tonic-gate } 37397c478bd9Sstevel@tonic-gate 37407c478bd9Sstevel@tonic-gate newsock = *socket; 37417c478bd9Sstevel@tonic-gate /* note: we force CS to always get insert/removal events */ 37427c478bd9Sstevel@tonic-gate sockp->ls_cs_events = pcm_mapevents(newsock.SCIntMask) | 37437c478bd9Sstevel@tonic-gate PCE_E2M(PCE_CARD_INSERT) | PCE_E2M(PCE_CARD_REMOVAL); 37447c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 37457c478bd9Sstevel@tonic-gate if (pcmcia_debug > 1) 37467c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 37477c478bd9Sstevel@tonic-gate "SetSocket: SCIntMask = %x\n", newsock.SCIntMask); 37487c478bd9Sstevel@tonic-gate #endif 37497c478bd9Sstevel@tonic-gate newsock.socket = sockp->ls_socket; 37507c478bd9Sstevel@tonic-gate newsock.VccLevel = pcmcia_map_power_set(sockp->ls_adapter, 37517c478bd9Sstevel@tonic-gate newsock.VccLevel, VCC); 37527c478bd9Sstevel@tonic-gate newsock.Vpp1Level = pcmcia_map_power_set(sockp->ls_adapter, 37537c478bd9Sstevel@tonic-gate newsock.Vpp1Level, VPP1); 37547c478bd9Sstevel@tonic-gate newsock.Vpp2Level = pcmcia_map_power_set(sockp->ls_adapter, 37557c478bd9Sstevel@tonic-gate newsock.Vpp2Level, VPP2); 37567c478bd9Sstevel@tonic-gate retval = SET_SOCKET(sockp->ls_if, sockp->ls_adapter->pca_dip, 37577c478bd9Sstevel@tonic-gate &newsock); 37587c478bd9Sstevel@tonic-gate if (retval == SUCCESS) { 37597c478bd9Sstevel@tonic-gate newsock.socket = sock; 37607c478bd9Sstevel@tonic-gate newsock.VccLevel = pcmcia_map_power_get(sockp->ls_adapter, 37617c478bd9Sstevel@tonic-gate newsock.VccLevel, 37627c478bd9Sstevel@tonic-gate VCC); 37637c478bd9Sstevel@tonic-gate newsock.Vpp1Level = pcmcia_map_power_get(sockp->ls_adapter, 37647c478bd9Sstevel@tonic-gate newsock.Vpp1Level, 37657c478bd9Sstevel@tonic-gate VPP1); 37667c478bd9Sstevel@tonic-gate newsock.Vpp2Level = pcmcia_map_power_get(sockp->ls_adapter, 37677c478bd9Sstevel@tonic-gate newsock.Vpp2Level, 37687c478bd9Sstevel@tonic-gate VPP2); 37697c478bd9Sstevel@tonic-gate *socket = newsock; 37707c478bd9Sstevel@tonic-gate if (socket->IREQRouting & IRQ_ENABLE) { 37717c478bd9Sstevel@tonic-gate sockp->ls_flags |= PCS_IRQ_ENABLED; 37727c478bd9Sstevel@tonic-gate } else { 37737c478bd9Sstevel@tonic-gate sockp->ls_flags &= ~PCS_IRQ_ENABLED; 37747c478bd9Sstevel@tonic-gate } 37757c478bd9Sstevel@tonic-gate } 37767c478bd9Sstevel@tonic-gate return (retval); 37777c478bd9Sstevel@tonic-gate } 37787c478bd9Sstevel@tonic-gate 37797c478bd9Sstevel@tonic-gate /* 37807c478bd9Sstevel@tonic-gate * SSSetIRQHandler() 37817c478bd9Sstevel@tonic-gate * arrange for IRQ to be allocated if appropriate and always 37827c478bd9Sstevel@tonic-gate * arrange that PC Card interrupt handlers get called. 37837c478bd9Sstevel@tonic-gate */ 37847c478bd9Sstevel@tonic-gate static int 37857c478bd9Sstevel@tonic-gate SSSetIRQHandler(set_irq_handler_t *handler) 37867c478bd9Sstevel@tonic-gate { 37877c478bd9Sstevel@tonic-gate int sock, retval, func; 37887c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t *sockp; 37897c478bd9Sstevel@tonic-gate struct pcmcia_parent_private *ppd; 37907c478bd9Sstevel@tonic-gate dev_info_t *dip; 37917c478bd9Sstevel@tonic-gate ddi_iblock_cookie_t iblk; 37927c478bd9Sstevel@tonic-gate ddi_idevice_cookie_t idev; 37937c478bd9Sstevel@tonic-gate 37947c478bd9Sstevel@tonic-gate sock = CS_GET_SOCKET_NUMBER(handler->socket); 37957c478bd9Sstevel@tonic-gate func = CS_GET_FUNCTION_NUMBER(handler->socket); 37967c478bd9Sstevel@tonic-gate if (sock > pcmcia_num_sockets || 37977c478bd9Sstevel@tonic-gate (sockp = pcmcia_sockets[sock]) == NULL) { 37987c478bd9Sstevel@tonic-gate return (BAD_SOCKET); 37997c478bd9Sstevel@tonic-gate } 38007c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 38017c478bd9Sstevel@tonic-gate if (pcmcia_debug) { 38027c478bd9Sstevel@tonic-gate 38037c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "SSSetIRQHandler: socket=%x, function=%x\n", 38047c478bd9Sstevel@tonic-gate sock, func); 38057c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "\thandler(%p): socket=%x, irq=%x, id=%x\n", 38067c478bd9Sstevel@tonic-gate (void *)handler->handler, handler->socket, handler->irq, 38077c478bd9Sstevel@tonic-gate handler->handler_id); 38087c478bd9Sstevel@tonic-gate } 38097c478bd9Sstevel@tonic-gate #endif 38107c478bd9Sstevel@tonic-gate dip = sockp->ls_dip[func]; 38117c478bd9Sstevel@tonic-gate 38127c478bd9Sstevel@tonic-gate ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(dip); 38137c478bd9Sstevel@tonic-gate 38147c478bd9Sstevel@tonic-gate handler->iblk_cookie = &iblk; 38157c478bd9Sstevel@tonic-gate handler->idev_cookie = &idev; 38167c478bd9Sstevel@tonic-gate 38177c478bd9Sstevel@tonic-gate retval = ddi_add_intr(dip, 0, handler->iblk_cookie, 38187c478bd9Sstevel@tonic-gate handler->idev_cookie, 38197c478bd9Sstevel@tonic-gate (uint32_t(*)(caddr_t)) handler->handler, 38207c478bd9Sstevel@tonic-gate handler->arg1); 38217c478bd9Sstevel@tonic-gate 38227c478bd9Sstevel@tonic-gate if (retval == DDI_SUCCESS) { 38237c478bd9Sstevel@tonic-gate handler->iblk_cookie = &sockp->ls_iblk; 38247c478bd9Sstevel@tonic-gate handler->idev_cookie = &sockp->ls_idev; 38257c478bd9Sstevel@tonic-gate handler->irq = ppd->ppd_intrspec->intrspec_vec; 38267c478bd9Sstevel@tonic-gate retval = SUCCESS; 38277c478bd9Sstevel@tonic-gate } else { 38287c478bd9Sstevel@tonic-gate retval = sockp->ls_error; 38297c478bd9Sstevel@tonic-gate } 38307c478bd9Sstevel@tonic-gate return (retval); 38317c478bd9Sstevel@tonic-gate } 38327c478bd9Sstevel@tonic-gate 38337c478bd9Sstevel@tonic-gate /* 38347c478bd9Sstevel@tonic-gate * SSClearIRQHandler() 38357c478bd9Sstevel@tonic-gate * Arrange to have the interrupt handler specified removed 38367c478bd9Sstevel@tonic-gate * from the interrupt list. 38377c478bd9Sstevel@tonic-gate */ 38387c478bd9Sstevel@tonic-gate static int 38397c478bd9Sstevel@tonic-gate SSClearIRQHandler(clear_irq_handler_t *handler) 38407c478bd9Sstevel@tonic-gate { 38417c478bd9Sstevel@tonic-gate int sock, func; 38427c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t *sockp; 38437c478bd9Sstevel@tonic-gate dev_info_t *dip; 38447c478bd9Sstevel@tonic-gate 38457c478bd9Sstevel@tonic-gate sock = CS_GET_SOCKET_NUMBER(handler->socket); 38467c478bd9Sstevel@tonic-gate func = CS_GET_FUNCTION_NUMBER(handler->socket); 38477c478bd9Sstevel@tonic-gate 38487c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 38497c478bd9Sstevel@tonic-gate if (pcmcia_debug) { 38507c478bd9Sstevel@tonic-gate 38517c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 38527c478bd9Sstevel@tonic-gate "SSClearIRQHandler: socket=%x, function=%x\n", 38537c478bd9Sstevel@tonic-gate sock, func); 38547c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 38557c478bd9Sstevel@tonic-gate "\thandler(%p): socket=%x, id=%x\n", 38567c478bd9Sstevel@tonic-gate (void *)handler, handler->socket, 38577c478bd9Sstevel@tonic-gate handler->handler_id); 38587c478bd9Sstevel@tonic-gate } 38597c478bd9Sstevel@tonic-gate #endif 38607c478bd9Sstevel@tonic-gate 38617c478bd9Sstevel@tonic-gate if (sock > pcmcia_num_sockets || 38627c478bd9Sstevel@tonic-gate (sockp = pcmcia_sockets[sock]) == NULL) { 38637c478bd9Sstevel@tonic-gate return (BAD_SOCKET); 38647c478bd9Sstevel@tonic-gate } 38657c478bd9Sstevel@tonic-gate dip = sockp->ls_dip[func]; 38667c478bd9Sstevel@tonic-gate if (dip) { 38677c478bd9Sstevel@tonic-gate ddi_remove_intr(dip, 0, NULL); 38687c478bd9Sstevel@tonic-gate return (SUCCESS); 38697c478bd9Sstevel@tonic-gate } 38707c478bd9Sstevel@tonic-gate return (BAD_SOCKET); 38717c478bd9Sstevel@tonic-gate } 38727c478bd9Sstevel@tonic-gate 38737c478bd9Sstevel@tonic-gate 38747c478bd9Sstevel@tonic-gate /* 38757c478bd9Sstevel@tonic-gate * pcm_pathname() 38767c478bd9Sstevel@tonic-gate * make a partial path from dip. 38777c478bd9Sstevel@tonic-gate * used to mknods relative to /devices/pcmcia/ 38787c478bd9Sstevel@tonic-gate * 38797c478bd9Sstevel@tonic-gate * XXX - we now use ddi_get_name_addr to get the "address" portion 38807c478bd9Sstevel@tonic-gate * of the name; that way, we only have to modify the name creation 38817c478bd9Sstevel@tonic-gate * algorithm in one place 38827c478bd9Sstevel@tonic-gate */ 38837c478bd9Sstevel@tonic-gate static void 38847c478bd9Sstevel@tonic-gate pcm_pathname(dev_info_t *dip, char *name, char *path) 38857c478bd9Sstevel@tonic-gate { 38867c478bd9Sstevel@tonic-gate (void) sprintf(path, "%s@%s:%s", ddi_node_name(dip), 38877c478bd9Sstevel@tonic-gate ddi_get_name_addr(dip), name); 38887c478bd9Sstevel@tonic-gate } 38897c478bd9Sstevel@tonic-gate 38907c478bd9Sstevel@tonic-gate /* 38917c478bd9Sstevel@tonic-gate * pcmcia_create_device() 38927c478bd9Sstevel@tonic-gate * create the /devices entries for the driver 38937c478bd9Sstevel@tonic-gate * it is assumed that the PC Card driver will do a 38947c478bd9Sstevel@tonic-gate * RegisterClient for each subdevice. 38957c478bd9Sstevel@tonic-gate * The device type string is encoded here to match 38967c478bd9Sstevel@tonic-gate * the standardized names when possible. 38977c478bd9Sstevel@tonic-gate * XXX - note that we may need to provide a way for the 38987c478bd9Sstevel@tonic-gate * caller to specify the complete name string that 38997c478bd9Sstevel@tonic-gate * we pass to ddi_set_name_addr 39007c478bd9Sstevel@tonic-gate */ 39017c478bd9Sstevel@tonic-gate static int 39027c478bd9Sstevel@tonic-gate pcmcia_create_device(ss_make_device_node_t *init) 39037c478bd9Sstevel@tonic-gate { 39047c478bd9Sstevel@tonic-gate int err = SUCCESS; 39057c478bd9Sstevel@tonic-gate struct pcm_make_dev device; 39067c478bd9Sstevel@tonic-gate struct dev_ops *ops; 39077c478bd9Sstevel@tonic-gate major_t major; 39087c478bd9Sstevel@tonic-gate 39097c478bd9Sstevel@tonic-gate /* 39107c478bd9Sstevel@tonic-gate * Now that we have the name, create it. 39117c478bd9Sstevel@tonic-gate */ 39127c478bd9Sstevel@tonic-gate 39137c478bd9Sstevel@tonic-gate bzero(&device, sizeof (device)); 39147c478bd9Sstevel@tonic-gate if (init->flags & SS_CSINITDEV_CREATE_DEVICE) { 39157c478bd9Sstevel@tonic-gate if ((err = ddi_create_minor_node(init->dip, 39167c478bd9Sstevel@tonic-gate init->name, 39177c478bd9Sstevel@tonic-gate init->spec_type, 39187c478bd9Sstevel@tonic-gate init->minor_num, 39197c478bd9Sstevel@tonic-gate init->node_type, 39207c478bd9Sstevel@tonic-gate 0)) != DDI_SUCCESS) { 39217c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 39227c478bd9Sstevel@tonic-gate if (pcmcia_debug) 39237c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 39247c478bd9Sstevel@tonic-gate "pcmcia_create_device: failed " 39257c478bd9Sstevel@tonic-gate "create\n"); 39267c478bd9Sstevel@tonic-gate #endif 39277c478bd9Sstevel@tonic-gate return (BAD_ATTRIBUTE); 39287c478bd9Sstevel@tonic-gate } 39297c478bd9Sstevel@tonic-gate 39307c478bd9Sstevel@tonic-gate major = ddi_name_to_major(ddi_binding_name(init->dip)); 39317c478bd9Sstevel@tonic-gate ops = ddi_get_driver(init->dip); 39327c478bd9Sstevel@tonic-gate LOCK_DEV_OPS(&devnamesp[major].dn_lock); 39337c478bd9Sstevel@tonic-gate INCR_DEV_OPS_REF(ops); 39347c478bd9Sstevel@tonic-gate (void) ddi_pathname(init->dip, device.path); 39357c478bd9Sstevel@tonic-gate DECR_DEV_OPS_REF(ops); 39367c478bd9Sstevel@tonic-gate UNLOCK_DEV_OPS(&devnamesp[major].dn_lock); 39377c478bd9Sstevel@tonic-gate (void) sprintf(device.path + strlen(device.path), ":%s", 39387c478bd9Sstevel@tonic-gate init->name); 39397c478bd9Sstevel@tonic-gate 39407c478bd9Sstevel@tonic-gate (void) strcpy(device.driver, ddi_binding_name(init->dip)); 39417c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 39427c478bd9Sstevel@tonic-gate if (pcmcia_debug) 39437c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 39447c478bd9Sstevel@tonic-gate "pcmcia_create_device: created %s " 39457c478bd9Sstevel@tonic-gate "from %s [%s]\n", 39467c478bd9Sstevel@tonic-gate device.path, init->name, device.driver); 39477c478bd9Sstevel@tonic-gate #endif 39487c478bd9Sstevel@tonic-gate device.dev = 39497c478bd9Sstevel@tonic-gate makedevice(ddi_name_to_major(ddi_get_name(init->dip)), 39507c478bd9Sstevel@tonic-gate init->minor_num); 39517c478bd9Sstevel@tonic-gate device.flags |= (init->flags & SS_CSINITDEV_MORE_DEVICES) ? 39527c478bd9Sstevel@tonic-gate PCM_EVENT_MORE : 0; 39537c478bd9Sstevel@tonic-gate device.type = init->spec_type; 39547c478bd9Sstevel@tonic-gate device.op = SS_CSINITDEV_CREATE_DEVICE; 39557c478bd9Sstevel@tonic-gate device.socket = ddi_getprop(DDI_DEV_T_ANY, init->dip, 39567c478bd9Sstevel@tonic-gate DDI_PROP_CANSLEEP, PCM_DEV_SOCKET, 39577c478bd9Sstevel@tonic-gate -1); 39587c478bd9Sstevel@tonic-gate } else if (init->flags & SS_CSINITDEV_REMOVE_DEVICE) { 39597c478bd9Sstevel@tonic-gate device.op = SS_CSINITDEV_REMOVE_DEVICE; 39607c478bd9Sstevel@tonic-gate device.socket = ddi_getprop(DDI_DEV_T_ANY, init->dip, 39617c478bd9Sstevel@tonic-gate DDI_PROP_CANSLEEP, PCM_DEV_SOCKET, 39627c478bd9Sstevel@tonic-gate -1); 39637c478bd9Sstevel@tonic-gate if (init->name != NULL) 39647c478bd9Sstevel@tonic-gate (void) strcpy(device.path, init->name); 39657c478bd9Sstevel@tonic-gate device.dev = 39667c478bd9Sstevel@tonic-gate makedevice(ddi_name_to_major(ddi_get_name(init->dip)), 39677c478bd9Sstevel@tonic-gate 0); 39687c478bd9Sstevel@tonic-gate ddi_remove_minor_node(init->dip, init->name); 39697c478bd9Sstevel@tonic-gate } 39707c478bd9Sstevel@tonic-gate 39717c478bd9Sstevel@tonic-gate /* 39727c478bd9Sstevel@tonic-gate * we send an event for ALL devices created. 39737c478bd9Sstevel@tonic-gate * To do otherwise ties us to using drvconfig 39747c478bd9Sstevel@tonic-gate * forever. There are relatively few devices 39757c478bd9Sstevel@tonic-gate * ever created so no need to do otherwise. 39767c478bd9Sstevel@tonic-gate * The existence of the event manager must never 39777c478bd9Sstevel@tonic-gate * be visible to a PCMCIA device driver. 39787c478bd9Sstevel@tonic-gate */ 39797c478bd9Sstevel@tonic-gate pcm_event_manager(PCE_INIT_DEV, device.socket, &device); 39807c478bd9Sstevel@tonic-gate 39817c478bd9Sstevel@tonic-gate return (err); 39827c478bd9Sstevel@tonic-gate } 39837c478bd9Sstevel@tonic-gate 39847c478bd9Sstevel@tonic-gate /* 39857c478bd9Sstevel@tonic-gate * pcmcia_get_minors() 39867c478bd9Sstevel@tonic-gate * We need to traverse the minor node list of the 39877c478bd9Sstevel@tonic-gate * dip if there are any. This takes two passes; 39887c478bd9Sstevel@tonic-gate * one to get the count and buffer size and the 39897c478bd9Sstevel@tonic-gate * other to actually copy the data into the buffer. 39907c478bd9Sstevel@tonic-gate * The framework requires that the dip be locked 39917c478bd9Sstevel@tonic-gate * during this time to avoid breakage as well as the 39927c478bd9Sstevel@tonic-gate * driver being locked. 39937c478bd9Sstevel@tonic-gate */ 39947c478bd9Sstevel@tonic-gate int 39957c478bd9Sstevel@tonic-gate pcmcia_get_minors(dev_info_t *dip, struct pcm_make_dev **minors) 39967c478bd9Sstevel@tonic-gate { 3997b9ccdc5aScth int circ; 39987c478bd9Sstevel@tonic-gate int count = 0; 39997c478bd9Sstevel@tonic-gate struct ddi_minor_data *dp; 40007c478bd9Sstevel@tonic-gate struct pcm_make_dev *md; 40017c478bd9Sstevel@tonic-gate int socket; 40027c478bd9Sstevel@tonic-gate major_t major; 40037c478bd9Sstevel@tonic-gate struct dev_ops *ops; 40047c478bd9Sstevel@tonic-gate 40057c478bd9Sstevel@tonic-gate socket = ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 40067c478bd9Sstevel@tonic-gate PCM_DEV_SOCKET, -1); 4007b9ccdc5aScth ndi_devi_enter(dip, &circ); 40087c478bd9Sstevel@tonic-gate if (DEVI(dip)->devi_minor != (struct ddi_minor_data *)NULL) { 40097c478bd9Sstevel@tonic-gate for (dp = DEVI(dip)->devi_minor; 40107c478bd9Sstevel@tonic-gate dp != (struct ddi_minor_data *)NULL; 40117c478bd9Sstevel@tonic-gate dp = dp->next) { 40127c478bd9Sstevel@tonic-gate count++; /* have one more */ 40137c478bd9Sstevel@tonic-gate } 40147c478bd9Sstevel@tonic-gate /* we now know how many nodes to allocate */ 40157c478bd9Sstevel@tonic-gate md = kmem_zalloc(count * sizeof (struct pcm_make_dev), 40167c478bd9Sstevel@tonic-gate KM_NOSLEEP); 40177c478bd9Sstevel@tonic-gate if (md != NULL) { 40187c478bd9Sstevel@tonic-gate *minors = md; 40197c478bd9Sstevel@tonic-gate for (dp = DEVI(dip)->devi_minor; 40207c478bd9Sstevel@tonic-gate dp != (struct ddi_minor_data *)NULL; 40217c478bd9Sstevel@tonic-gate dp = dp->next, md++) { 40227c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 40237c478bd9Sstevel@tonic-gate if (pcmcia_debug > 1) { 40247c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 40257c478bd9Sstevel@tonic-gate "pcmcia_get_minors: name=%s," 40267c478bd9Sstevel@tonic-gate "socket=%d, stype=%x, " 40277c478bd9Sstevel@tonic-gate "ntype=%s, dev_t=%x", 40287c478bd9Sstevel@tonic-gate dp->ddm_name, 40297c478bd9Sstevel@tonic-gate socket, 40307c478bd9Sstevel@tonic-gate dp->ddm_spec_type, 40317c478bd9Sstevel@tonic-gate dp->ddm_node_type, 40327c478bd9Sstevel@tonic-gate (int)dp->ddm_dev); 40337c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 40347c478bd9Sstevel@tonic-gate "\tbind name = %s\n", 40357c478bd9Sstevel@tonic-gate ddi_binding_name(dip)); 40367c478bd9Sstevel@tonic-gate } 40377c478bd9Sstevel@tonic-gate #endif 40387c478bd9Sstevel@tonic-gate md->socket = socket; 40397c478bd9Sstevel@tonic-gate md->op = SS_CSINITDEV_CREATE_DEVICE; 40407c478bd9Sstevel@tonic-gate md->dev = dp->ddm_dev; 40417c478bd9Sstevel@tonic-gate md->type = dp->ddm_spec_type; 40427c478bd9Sstevel@tonic-gate (void) strcpy(md->driver, 40437c478bd9Sstevel@tonic-gate ddi_binding_name(dip)); 40447c478bd9Sstevel@tonic-gate major = ddi_name_to_major(md->driver); 40457c478bd9Sstevel@tonic-gate ops = ddi_get_driver(dip); 40467c478bd9Sstevel@tonic-gate LOCK_DEV_OPS(&devnamesp[major].dn_lock); 40477c478bd9Sstevel@tonic-gate pcm_pathname(dip, dp->ddm_name, md->path); 40487c478bd9Sstevel@tonic-gate INCR_DEV_OPS_REF(ops); 40497c478bd9Sstevel@tonic-gate (void) ddi_pathname(dip, md->path); 40507c478bd9Sstevel@tonic-gate DECR_DEV_OPS_REF(ops); 40517c478bd9Sstevel@tonic-gate UNLOCK_DEV_OPS(&devnamesp[major].dn_lock); 40527c478bd9Sstevel@tonic-gate (void) sprintf(md->path + strlen(md->path), 40537c478bd9Sstevel@tonic-gate ":%s", dp->ddm_name); 40547c478bd9Sstevel@tonic-gate if (dp->next == NULL) 40557c478bd9Sstevel@tonic-gate /* no more */ 40567c478bd9Sstevel@tonic-gate md->flags |= PCM_EVENT_MORE; 40577c478bd9Sstevel@tonic-gate } 40587c478bd9Sstevel@tonic-gate } else { 40597c478bd9Sstevel@tonic-gate count = 0; 40607c478bd9Sstevel@tonic-gate } 40617c478bd9Sstevel@tonic-gate } 4062b9ccdc5aScth ndi_devi_exit(dip, circ); 40637c478bd9Sstevel@tonic-gate return (count); 40647c478bd9Sstevel@tonic-gate } 40657c478bd9Sstevel@tonic-gate 40667c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 40677c478bd9Sstevel@tonic-gate static char *ddmtypes[] = { "minor", "alias", "default", "internal" }; 40687c478bd9Sstevel@tonic-gate 40697c478bd9Sstevel@tonic-gate static void 40707c478bd9Sstevel@tonic-gate pcmcia_dump_minors(dev_info_t *dip) 40717c478bd9Sstevel@tonic-gate { 4072b9ccdc5aScth int circ; 40737c478bd9Sstevel@tonic-gate int count = 0; 40747c478bd9Sstevel@tonic-gate struct ddi_minor_data *dp; 40757c478bd9Sstevel@tonic-gate int unit, major; 40767c478bd9Sstevel@tonic-gate dev_info_t *np; 40777c478bd9Sstevel@tonic-gate 40787c478bd9Sstevel@tonic-gate unit = ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 40797c478bd9Sstevel@tonic-gate PCM_DEV_SOCKET, -1); 40807c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 40817c478bd9Sstevel@tonic-gate "pcmcia_dump_minors: dip=%p, socket=%d\n", (void *)dip, unit); 40827c478bd9Sstevel@tonic-gate 40837c478bd9Sstevel@tonic-gate major = ddi_driver_major(dip); 40847c478bd9Sstevel@tonic-gate if (major != -1) { 40857c478bd9Sstevel@tonic-gate for (np = devnamesp[major].dn_head; np != NULL; 40867c478bd9Sstevel@tonic-gate np = (dev_info_t *)DEVI(np)->devi_next) { 40877c478bd9Sstevel@tonic-gate char *cf2 = ""; 40887c478bd9Sstevel@tonic-gate char *cur = ""; 4089a9fb0ae8Srw if (i_ddi_node_state(np) == DS_READY) 4090a9fb0ae8Srw cf2 = "DS_READY"; 40917c478bd9Sstevel@tonic-gate if (np == dip) 40927c478bd9Sstevel@tonic-gate cur = "CUR"; 40937c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "\tsibs: %s %s %s\n", 40947c478bd9Sstevel@tonic-gate ddi_binding_name(np), cf2, cur); 40957c478bd9Sstevel@tonic-gate 4096b9ccdc5aScth ndi_devi_enter(np, &circ); 40977c478bd9Sstevel@tonic-gate if (DEVI(np)->devi_minor != 40987c478bd9Sstevel@tonic-gate (struct ddi_minor_data *)NULL) { 40997c478bd9Sstevel@tonic-gate for (dp = DEVI(np)->devi_minor; 41007c478bd9Sstevel@tonic-gate dp != (struct ddi_minor_data *)NULL; 41017c478bd9Sstevel@tonic-gate dp = dp->next) { 41027c478bd9Sstevel@tonic-gate count++; /* have one more */ 41037c478bd9Sstevel@tonic-gate } 41047c478bd9Sstevel@tonic-gate for (dp = DEVI(dip)->devi_minor; 41057c478bd9Sstevel@tonic-gate dp != (struct ddi_minor_data *)NULL; 41067c478bd9Sstevel@tonic-gate dp = dp->next) { 41077c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "\ttype=%s, name=%s," 41087c478bd9Sstevel@tonic-gate "socket=%d, stype=%x, " 41097c478bd9Sstevel@tonic-gate "ntype=%s, dev_t=%x", 41107c478bd9Sstevel@tonic-gate ddmtypes[dp->type], 41117c478bd9Sstevel@tonic-gate dp->ddm_name, 41127c478bd9Sstevel@tonic-gate unit, 41137c478bd9Sstevel@tonic-gate dp->ddm_spec_type, 41147c478bd9Sstevel@tonic-gate dp->ddm_node_type, 41157c478bd9Sstevel@tonic-gate (int)dp->ddm_dev); 41167c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "\tbind name = %s\n", 41177c478bd9Sstevel@tonic-gate ddi_binding_name(np)); 41187c478bd9Sstevel@tonic-gate } 41197c478bd9Sstevel@tonic-gate } 4120b9ccdc5aScth ndi_devi_exit(np, circ); 41217c478bd9Sstevel@tonic-gate } 41227c478bd9Sstevel@tonic-gate } 41237c478bd9Sstevel@tonic-gate } 41247c478bd9Sstevel@tonic-gate #endif 41257c478bd9Sstevel@tonic-gate 41267c478bd9Sstevel@tonic-gate /* 41277c478bd9Sstevel@tonic-gate * experimental merging code 41287c478bd9Sstevel@tonic-gate * what are the things that we should merge on? 41297c478bd9Sstevel@tonic-gate * match something by name in the "compatible" property 41307c478bd9Sstevel@tonic-gate * restrict to a specific "socket" 41317c478bd9Sstevel@tonic-gate * restrict to a specific "instance" 41327c478bd9Sstevel@tonic-gate */ 41337c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 41347c478bd9Sstevel@tonic-gate static int 41357c478bd9Sstevel@tonic-gate pcmcia_merge_conf(dev_info_t *dip) 41367c478bd9Sstevel@tonic-gate { 41377c478bd9Sstevel@tonic-gate return (0); /* merge failed */ 41387c478bd9Sstevel@tonic-gate } 41397c478bd9Sstevel@tonic-gate 41407c478bd9Sstevel@tonic-gate /* 41417c478bd9Sstevel@tonic-gate * pcmcia_mfc_intr() 41427c478bd9Sstevel@tonic-gate * Multifunction Card interrupt handler 41437c478bd9Sstevel@tonic-gate * While some adapters share interrupts at the lowest 41447c478bd9Sstevel@tonic-gate * level, some can't. In order to be consistent, we 41457c478bd9Sstevel@tonic-gate * split multifunction cards out with this intercept and 41467c478bd9Sstevel@tonic-gate * allow the low level to do what is best for it. 41477c478bd9Sstevel@tonic-gate * the arg is a pcmcia_socket structure and all interrupts 41487c478bd9Sstevel@tonic-gate * are per-socket in this case. We also have the option 41497c478bd9Sstevel@tonic-gate * to optimize if the cards support it. It also means 41507c478bd9Sstevel@tonic-gate * that we can use the INTRACK mode if it proves desirable 41517c478bd9Sstevel@tonic-gate */ 41527c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 41537c478bd9Sstevel@tonic-gate static uint32_t 41547c478bd9Sstevel@tonic-gate pcmcia_mfc_intr(caddr_t arg1, caddr_t arg2) 41557c478bd9Sstevel@tonic-gate { 41567c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t *sockp; 41577c478bd9Sstevel@tonic-gate inthandler_t *intr, *first; 41587c478bd9Sstevel@tonic-gate int done, result; 41597c478bd9Sstevel@tonic-gate 41607c478bd9Sstevel@tonic-gate sockp = (pcmcia_logical_socket_t *)arg1; 41617c478bd9Sstevel@tonic-gate 41627c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 41637c478bd9Sstevel@tonic-gate if (pcmcia_debug > 1) { 41647c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia_mfc_intr sockp=%p" 41657c478bd9Sstevel@tonic-gate " ls_inthandlers=%p\n" 41667c478bd9Sstevel@tonic-gate "\t ls_flags=0x%x PCS_IRQ_ENABLED=0x%x \n", 41677c478bd9Sstevel@tonic-gate (void *) sockp, (void *) sockp->ls_inthandlers, 41687c478bd9Sstevel@tonic-gate sockp->ls_flags, PCS_IRQ_ENABLED); 41697c478bd9Sstevel@tonic-gate } 41707c478bd9Sstevel@tonic-gate #endif 41717c478bd9Sstevel@tonic-gate 41727c478bd9Sstevel@tonic-gate if (sockp == NULL || sockp->ls_inthandlers == NULL || 41737c478bd9Sstevel@tonic-gate !(sockp->ls_flags & PCS_IRQ_ENABLED)) 41747c478bd9Sstevel@tonic-gate return (DDI_INTR_UNCLAIMED); 41757c478bd9Sstevel@tonic-gate 41767c478bd9Sstevel@tonic-gate mutex_enter(&sockp->ls_ilock); 41777c478bd9Sstevel@tonic-gate for (done = 0, result = 0, first = intr = sockp->ls_inthandlers; 41787c478bd9Sstevel@tonic-gate intr != NULL && !done; intr = intr->next) { 41797c478bd9Sstevel@tonic-gate result |= intr->intr(intr->arg1, intr->arg2); 41807c478bd9Sstevel@tonic-gate if (intr->next == first) 41817c478bd9Sstevel@tonic-gate done++; 41827c478bd9Sstevel@tonic-gate } 41837c478bd9Sstevel@tonic-gate if (intr == NULL) { 41847c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pcmcia_mfc_intr: bad MFC handler list"); 41857c478bd9Sstevel@tonic-gate } 41867c478bd9Sstevel@tonic-gate if (sockp->ls_inthandlers) 41877c478bd9Sstevel@tonic-gate sockp->ls_inthandlers = sockp->ls_inthandlers->next; 41887c478bd9Sstevel@tonic-gate 41897c478bd9Sstevel@tonic-gate mutex_exit(&sockp->ls_ilock); 41907c478bd9Sstevel@tonic-gate return (result ? DDI_INTR_CLAIMED : DDI_INTR_UNCLAIMED); 41917c478bd9Sstevel@tonic-gate } 41927c478bd9Sstevel@tonic-gate 41937c478bd9Sstevel@tonic-gate /* 41947c478bd9Sstevel@tonic-gate * pcmcia_power(dip) 41957c478bd9Sstevel@tonic-gate * control power for nexus and children 41967c478bd9Sstevel@tonic-gate */ 41977c478bd9Sstevel@tonic-gate int 41987c478bd9Sstevel@tonic-gate pcmcia_power(dev_info_t *dip, int component, int level) 41997c478bd9Sstevel@tonic-gate { 42007c478bd9Sstevel@tonic-gate #if 0 42017c478bd9Sstevel@tonic-gate anp_t *anp = (anp_t *)ddi_get_driver_private(dip); 42027c478bd9Sstevel@tonic-gate int i; 42037c478bd9Sstevel@tonic-gate /* 42047c478bd9Sstevel@tonic-gate * for now, we only have one component. Should there be one per-socket? 42057c478bd9Sstevel@tonic-gate * the level is only one (power on or off) 42067c478bd9Sstevel@tonic-gate */ 42077c478bd9Sstevel@tonic-gate if (component != 0 || level > 1) 42087c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 42097c478bd9Sstevel@tonic-gate 42107c478bd9Sstevel@tonic-gate for (i = 0; i < pcic->pc_numsockets; i++) { 42117c478bd9Sstevel@tonic-gate if (pcic->pc_callback) 42127c478bd9Sstevel@tonic-gate PC_CALLBACK(dip, pcic->pc_cb_arg, 42137c478bd9Sstevel@tonic-gate (level == 0) ? PCE_PM_SUSPEND : 42147c478bd9Sstevel@tonic-gate PCE_PM_RESUME, 42157c478bd9Sstevel@tonic-gate i); 42167c478bd9Sstevel@tonic-gate } 42177c478bd9Sstevel@tonic-gate #else 42187c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pcmcia_power: component=%d, level=%d for %s", 42197c478bd9Sstevel@tonic-gate component, level, ddi_get_name_addr(dip)); 42207c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 42217c478bd9Sstevel@tonic-gate #endif 42227c478bd9Sstevel@tonic-gate } 42237c478bd9Sstevel@tonic-gate 42247c478bd9Sstevel@tonic-gate void 42257c478bd9Sstevel@tonic-gate pcmcia_begin_resume(dev_info_t *dip) 42267c478bd9Sstevel@tonic-gate { 42277c478bd9Sstevel@tonic-gate int i; 42287c478bd9Sstevel@tonic-gate struct pcmcia_adapter *adapt = NULL; 42297c478bd9Sstevel@tonic-gate for (i = 0; i < pcmcia_num_adapters; i++) { 42307c478bd9Sstevel@tonic-gate if (pcmcia_adapters[i]->pca_dip == dip) { 42317c478bd9Sstevel@tonic-gate adapt = pcmcia_adapters[i]; 42327c478bd9Sstevel@tonic-gate break; 42337c478bd9Sstevel@tonic-gate } 42347c478bd9Sstevel@tonic-gate } 42357c478bd9Sstevel@tonic-gate if (adapt == NULL) 42367c478bd9Sstevel@tonic-gate return; 42377c478bd9Sstevel@tonic-gate 42387c478bd9Sstevel@tonic-gate for (i = 0; i < adapt->pca_numsockets; i++) { 42397c478bd9Sstevel@tonic-gate int s; 42407c478bd9Sstevel@tonic-gate s = adapt->pca_first_socket + i; 42417c478bd9Sstevel@tonic-gate if (pcmcia_sockets[s]->ls_flags & PCS_SUSPENDED) { 42427c478bd9Sstevel@tonic-gate if (pcmcia_sockets[s]->ls_flags & 42437c478bd9Sstevel@tonic-gate (1 << PCE_PM_RESUME)) { 42447c478bd9Sstevel@tonic-gate (void) cs_event(PCE_PM_RESUME, s, 0); 42457c478bd9Sstevel@tonic-gate pcm_event_manager(PCE_PM_RESUME, s, NULL); 42467c478bd9Sstevel@tonic-gate } 42477c478bd9Sstevel@tonic-gate (void) cs_event(PCE_CARD_REMOVAL, s, 0); 42487c478bd9Sstevel@tonic-gate pcm_event_manager(PCE_CARD_REMOVAL, s, NULL); 42497c478bd9Sstevel@tonic-gate } 42507c478bd9Sstevel@tonic-gate } 42517c478bd9Sstevel@tonic-gate } 42527c478bd9Sstevel@tonic-gate 425311c2b4c0Srw /* 425411c2b4c0Srw * mark a cardbus card as "suspended" in the pcmcia module 425511c2b4c0Srw */ 425611c2b4c0Srw void 425711c2b4c0Srw pcmcia_cb_suspended(int socket) 425811c2b4c0Srw { 425911c2b4c0Srw mutex_enter(&pcmcia_global_lock); 426011c2b4c0Srw pcmcia_sockets[socket]->ls_flags |= PCS_SUSPENDED; 426111c2b4c0Srw mutex_exit(&pcmcia_global_lock); 426211c2b4c0Srw 426311c2b4c0Srw } 426411c2b4c0Srw 426511c2b4c0Srw /* 426611c2b4c0Srw * mark a cardbus card as "resumed" in the pcmcia module 426711c2b4c0Srw */ 426811c2b4c0Srw void 426911c2b4c0Srw pcmcia_cb_resumed(int socket) 427011c2b4c0Srw { 427111c2b4c0Srw if (pcmcia_sockets[socket]->ls_flags & PCS_SUSPENDED) { 427211c2b4c0Srw mutex_enter(&pcmcia_global_lock); 427311c2b4c0Srw pcmcia_sockets[socket]->ls_flags &= ~PCS_SUSPENDED; 427411c2b4c0Srw cv_broadcast(&pcmcia_condvar); 427511c2b4c0Srw mutex_exit(&pcmcia_global_lock); 427611c2b4c0Srw #ifdef PCMCIA_DEBUG 427711c2b4c0Srw if (pcmcia_debug) { 427811c2b4c0Srw cmn_err(CE_NOTE, "pcmcia_cb_resume RESUMED"); 427911c2b4c0Srw } 428011c2b4c0Srw #endif 428111c2b4c0Srw } 428211c2b4c0Srw 428311c2b4c0Srw } 428411c2b4c0Srw 42857c478bd9Sstevel@tonic-gate void 42867c478bd9Sstevel@tonic-gate pcmcia_wait_insert(dev_info_t *dip) 42877c478bd9Sstevel@tonic-gate { 42887c478bd9Sstevel@tonic-gate int i, f, tries, done; 42897c478bd9Sstevel@tonic-gate clock_t tm; 42907c478bd9Sstevel@tonic-gate struct pcmcia_adapter *adapt = NULL; 42917c478bd9Sstevel@tonic-gate anp_t *nexus; 42927c478bd9Sstevel@tonic-gate 42937c478bd9Sstevel@tonic-gate for (i = 0; i < pcmcia_num_adapters; i++) { 42947c478bd9Sstevel@tonic-gate if (pcmcia_adapters[i]->pca_dip == dip) { 42957c478bd9Sstevel@tonic-gate adapt = pcmcia_adapters[i]; 42967c478bd9Sstevel@tonic-gate break; 42977c478bd9Sstevel@tonic-gate } 42987c478bd9Sstevel@tonic-gate } 42997c478bd9Sstevel@tonic-gate if (adapt == NULL) 43007c478bd9Sstevel@tonic-gate return; 43017c478bd9Sstevel@tonic-gate 43027c478bd9Sstevel@tonic-gate for (tries = adapt->pca_numsockets * 10; tries > 0; tries--) { 43037c478bd9Sstevel@tonic-gate done = 1; 43047c478bd9Sstevel@tonic-gate mutex_enter(&pcmcia_global_lock); 43057c478bd9Sstevel@tonic-gate for (i = 0; i < adapt->pca_numsockets; i++) { 43067c478bd9Sstevel@tonic-gate int s; 43077c478bd9Sstevel@tonic-gate s = adapt->pca_first_socket + i; 43087c478bd9Sstevel@tonic-gate for (f = 0; f < PCMCIA_MAX_FUNCTIONS; f++) 43097c478bd9Sstevel@tonic-gate if (pcmcia_sockets[s] && 43107c478bd9Sstevel@tonic-gate pcmcia_sockets[s]->ls_flags & 43117c478bd9Sstevel@tonic-gate PCS_SUSPENDED) { 431211c2b4c0Srw 431311c2b4c0Srw #ifdef PCMCIA_DEBUG 431411c2b4c0Srw if (pcmcia_debug) { 431511c2b4c0Srw cmn_err(CE_NOTE, 431611c2b4c0Srw "pcmcia_wait_insert: " 431711c2b4c0Srw "socket in SUSPENDED state"); 431811c2b4c0Srw } 431911c2b4c0Srw #endif 43207c478bd9Sstevel@tonic-gate done = 0; 43217c478bd9Sstevel@tonic-gate break; 43227c478bd9Sstevel@tonic-gate } 43237c478bd9Sstevel@tonic-gate } 43247c478bd9Sstevel@tonic-gate if (!done) { 43257c478bd9Sstevel@tonic-gate tm = ddi_get_lbolt(); 43267c478bd9Sstevel@tonic-gate (void) cv_timedwait(&pcmcia_condvar, 43277c478bd9Sstevel@tonic-gate &pcmcia_global_lock, 43287c478bd9Sstevel@tonic-gate tm + drv_usectohz(100000)); 43297c478bd9Sstevel@tonic-gate } else { 43307c478bd9Sstevel@tonic-gate tries = 0; 43317c478bd9Sstevel@tonic-gate } 43327c478bd9Sstevel@tonic-gate mutex_exit(&pcmcia_global_lock); 43337c478bd9Sstevel@tonic-gate } 43347c478bd9Sstevel@tonic-gate 433511c2b4c0Srw if (tries == 0) { 433611c2b4c0Srw cmn_err(CE_NOTE, "pcmcia_wait_insert timed out"); 433711c2b4c0Srw } 433811c2b4c0Srw 43397c478bd9Sstevel@tonic-gate nexus = (anp_t *)ddi_get_driver_private(dip); 43407c478bd9Sstevel@tonic-gate pcmcia_find_cards(nexus); 43417c478bd9Sstevel@tonic-gate } 43427c478bd9Sstevel@tonic-gate 43437c478bd9Sstevel@tonic-gate int 43447c478bd9Sstevel@tonic-gate pcmcia_map_reg(dev_info_t *pdip, dev_info_t *dip, ra_return_t *ra, 43457c478bd9Sstevel@tonic-gate uint32_t state, caddr_t *base, 43467c478bd9Sstevel@tonic-gate ddi_acc_handle_t *handle, ddi_device_acc_attr_t *attrib, 43477c478bd9Sstevel@tonic-gate uint32_t req_base) 43487c478bd9Sstevel@tonic-gate { 43497c478bd9Sstevel@tonic-gate struct pcmcia_parent_private *ppd; 43507c478bd9Sstevel@tonic-gate int rnum = 0, type = PCMCIA_MAP_MEM; 43517c478bd9Sstevel@tonic-gate ddi_map_req_t mr; 43527c478bd9Sstevel@tonic-gate ddi_acc_hdl_t *hp; 43537c478bd9Sstevel@tonic-gate int result; 43547c478bd9Sstevel@tonic-gate struct regspec *reg; 43557c478bd9Sstevel@tonic-gate ddi_device_acc_attr_t attr; 43567c478bd9Sstevel@tonic-gate 43577c478bd9Sstevel@tonic-gate if (dip != NULL) { 43587c478bd9Sstevel@tonic-gate ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(dip); 43597c478bd9Sstevel@tonic-gate if (ppd == NULL) 43607c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 43617c478bd9Sstevel@tonic-gate for (rnum = 1; rnum < ppd->ppd_nreg; rnum++) { 43627c478bd9Sstevel@tonic-gate struct pcm_regs *p; 43637c478bd9Sstevel@tonic-gate p = &ppd->ppd_reg[rnum]; 43647c478bd9Sstevel@tonic-gate if (state & WS_IO) { 43657c478bd9Sstevel@tonic-gate /* need I/O */ 43667c478bd9Sstevel@tonic-gate type = PCMCIA_MAP_IO; 43677c478bd9Sstevel@tonic-gate /* 43687c478bd9Sstevel@tonic-gate * We want to find an IO regspec. When we 43697c478bd9Sstevel@tonic-gate * find one, it either has to match 43707c478bd9Sstevel@tonic-gate * the caller's requested base address 43717c478bd9Sstevel@tonic-gate * or it has to be relocatable. 43727c478bd9Sstevel@tonic-gate * We match on the requested base address 43737c478bd9Sstevel@tonic-gate * rather than the allocated base 43747c478bd9Sstevel@tonic-gate * address so that we handle the case 43757c478bd9Sstevel@tonic-gate * of adapters that have IO window base 43767c478bd9Sstevel@tonic-gate * relocation registers. 43777c478bd9Sstevel@tonic-gate */ 43787c478bd9Sstevel@tonic-gate if ((p->phys_hi & 43797c478bd9Sstevel@tonic-gate PC_REG_SPACE(PC_REG_SPACE_IO)) && 43807c478bd9Sstevel@tonic-gate ((req_base == p->phys_lo) || 43817c478bd9Sstevel@tonic-gate !(p->phys_hi & PC_REG_RELOC(1)))) 43827c478bd9Sstevel@tonic-gate break; 43837c478bd9Sstevel@tonic-gate } else { 43847c478bd9Sstevel@tonic-gate /* need memory */ 43857c478bd9Sstevel@tonic-gate type = PCMCIA_MAP_MEM; 43867c478bd9Sstevel@tonic-gate if (p->phys_hi & 43877c478bd9Sstevel@tonic-gate PC_REG_SPACE(PC_REG_SPACE_MEMORY| 43887c478bd9Sstevel@tonic-gate PC_REG_SPACE_ATTRIBUTE)) 43897c478bd9Sstevel@tonic-gate break; 43907c478bd9Sstevel@tonic-gate } 43917c478bd9Sstevel@tonic-gate } 43927c478bd9Sstevel@tonic-gate if (rnum >= ppd->ppd_nreg) 43937c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 43947c478bd9Sstevel@tonic-gate } else if (state & WS_IO) { 43957c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 43967c478bd9Sstevel@tonic-gate } 43977c478bd9Sstevel@tonic-gate 43987c478bd9Sstevel@tonic-gate reg = kmem_zalloc(sizeof (pci_regspec_t), KM_SLEEP); 43997c478bd9Sstevel@tonic-gate reg = pcmcia_cons_regspec(pdip, type, (uchar_t *)reg, ra); 44007c478bd9Sstevel@tonic-gate 44017c478bd9Sstevel@tonic-gate if (attrib == NULL || 44027c478bd9Sstevel@tonic-gate attrib->devacc_attr_version != DDI_DEVICE_ATTR_V0) { 44037c478bd9Sstevel@tonic-gate attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 44047c478bd9Sstevel@tonic-gate attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC; 44057c478bd9Sstevel@tonic-gate attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 44067c478bd9Sstevel@tonic-gate } else { 44077c478bd9Sstevel@tonic-gate attr = *attrib; 44087c478bd9Sstevel@tonic-gate } 44097c478bd9Sstevel@tonic-gate /* 44107c478bd9Sstevel@tonic-gate * Allocate and initialize the common elements of data access handle. 44117c478bd9Sstevel@tonic-gate */ 44127c478bd9Sstevel@tonic-gate *handle = impl_acc_hdl_alloc(KM_SLEEP, NULL); 44137c478bd9Sstevel@tonic-gate hp = impl_acc_hdl_get(*handle); 44147c478bd9Sstevel@tonic-gate hp->ah_vers = VERS_ACCHDL; 44157c478bd9Sstevel@tonic-gate hp->ah_dip = dip != NULL ? dip : pdip; 44167c478bd9Sstevel@tonic-gate hp->ah_rnumber = rnum; 44177c478bd9Sstevel@tonic-gate hp->ah_offset = 0; 44187c478bd9Sstevel@tonic-gate hp->ah_len = ra->ra_len; 44197c478bd9Sstevel@tonic-gate hp->ah_acc = attr; 44207c478bd9Sstevel@tonic-gate 44217c478bd9Sstevel@tonic-gate /* 44227c478bd9Sstevel@tonic-gate * Set up the mapping request and call to parent. 44237c478bd9Sstevel@tonic-gate */ 44247c478bd9Sstevel@tonic-gate mr.map_op = DDI_MO_MAP_LOCKED; 44257c478bd9Sstevel@tonic-gate mr.map_type = DDI_MT_REGSPEC; 44267c478bd9Sstevel@tonic-gate mr.map_obj.rp = reg; 44277c478bd9Sstevel@tonic-gate mr.map_prot = PROT_READ | PROT_WRITE; 44287c478bd9Sstevel@tonic-gate mr.map_flags = DDI_MF_KERNEL_MAPPING; 44297c478bd9Sstevel@tonic-gate mr.map_handlep = hp; 44307c478bd9Sstevel@tonic-gate mr.map_vers = DDI_MAP_VERSION; 44317c478bd9Sstevel@tonic-gate 44327c478bd9Sstevel@tonic-gate result = ddi_map(pdip, &mr, 0, ra->ra_len, base); 44337c478bd9Sstevel@tonic-gate if (result != DDI_SUCCESS) { 44347c478bd9Sstevel@tonic-gate impl_acc_hdl_free(*handle); 44357c478bd9Sstevel@tonic-gate *handle = (ddi_acc_handle_t)NULL; 44367c478bd9Sstevel@tonic-gate } else { 44377c478bd9Sstevel@tonic-gate hp->ah_addr = *base; 44387c478bd9Sstevel@tonic-gate if (mr.map_op == DDI_MO_UNMAP) 44397c478bd9Sstevel@tonic-gate ra = NULL; 44407c478bd9Sstevel@tonic-gate if (dip != NULL) 44417c478bd9Sstevel@tonic-gate pcmcia_set_assigned(dip, rnum, ra); 44427c478bd9Sstevel@tonic-gate } 44437c478bd9Sstevel@tonic-gate 4444981012acSrw kmem_free(reg, sizeof (pci_regspec_t)); 4445981012acSrw 44467c478bd9Sstevel@tonic-gate return (result); 44477c478bd9Sstevel@tonic-gate } 44487c478bd9Sstevel@tonic-gate 44497c478bd9Sstevel@tonic-gate struct pcmcia_adapter * 44507c478bd9Sstevel@tonic-gate pcmcia_get_adapter(dev_info_t *dip) 44517c478bd9Sstevel@tonic-gate { 44527c478bd9Sstevel@tonic-gate int i; 44537c478bd9Sstevel@tonic-gate 44547c478bd9Sstevel@tonic-gate for (i = 0; i < pcmcia_num_adapters; i++) { 44557c478bd9Sstevel@tonic-gate if (pcmcia_adapters[i] && 44567c478bd9Sstevel@tonic-gate pcmcia_adapters[i]->pca_dip == dip) { 44577c478bd9Sstevel@tonic-gate return (pcmcia_adapters[i]); 44587c478bd9Sstevel@tonic-gate } 44597c478bd9Sstevel@tonic-gate } 44607c478bd9Sstevel@tonic-gate return (NULL); 44617c478bd9Sstevel@tonic-gate } 44627c478bd9Sstevel@tonic-gate 44637c478bd9Sstevel@tonic-gate 44647c478bd9Sstevel@tonic-gate void 44657c478bd9Sstevel@tonic-gate pcmcia_set_assigned(dev_info_t *dip, int rnum, ra_return_t *ret) 44667c478bd9Sstevel@tonic-gate { 44677c478bd9Sstevel@tonic-gate struct pcmcia_parent_private *ppd; 44687c478bd9Sstevel@tonic-gate struct pcm_regs *reg, *assign; 44697c478bd9Sstevel@tonic-gate 44707c478bd9Sstevel@tonic-gate ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(dip); 44717c478bd9Sstevel@tonic-gate if (ppd) { 44727c478bd9Sstevel@tonic-gate reg = &ppd->ppd_reg[rnum]; 44737c478bd9Sstevel@tonic-gate assign = &ppd->ppd_assigned[rnum]; 44747c478bd9Sstevel@tonic-gate if (ret) { 44757c478bd9Sstevel@tonic-gate if (assign->phys_hi == 0) { 44767c478bd9Sstevel@tonic-gate assign->phys_hi = reg->phys_hi; 44777c478bd9Sstevel@tonic-gate assign->phys_lo = ret->ra_addr_lo; 44787c478bd9Sstevel@tonic-gate assign->phys_len = ret->ra_len; 44797c478bd9Sstevel@tonic-gate } else if (assign->phys_lo != ret->ra_addr_lo) { 44807c478bd9Sstevel@tonic-gate #ifdef PCMCIA_DEBUG 44817c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pcmcia: bad address:" 44827c478bd9Sstevel@tonic-gate "%s=<%x,%x>", 44837c478bd9Sstevel@tonic-gate ddi_get_name_addr(dip), 44847c478bd9Sstevel@tonic-gate ret->ra_addr_lo, assign->phys_lo); 44857c478bd9Sstevel@tonic-gate #else 44867c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "!pcmcia: bad address:" 44877c478bd9Sstevel@tonic-gate "%s=<%x,%x>", 44887c478bd9Sstevel@tonic-gate ddi_get_name_addr(dip), 44897c478bd9Sstevel@tonic-gate ret->ra_addr_lo, (int)assign->phys_lo); 44907c478bd9Sstevel@tonic-gate #endif 44917c478bd9Sstevel@tonic-gate } 44927c478bd9Sstevel@tonic-gate assign->phys_hi = PC_INCR_REFCNT(assign->phys_hi); 44937c478bd9Sstevel@tonic-gate } else { 44947c478bd9Sstevel@tonic-gate int i; 44957c478bd9Sstevel@tonic-gate assign->phys_hi = PC_DECR_REFCNT(assign->phys_hi); 44967c478bd9Sstevel@tonic-gate i = PC_GET_REG_REFCNT(assign->phys_hi); 44977c478bd9Sstevel@tonic-gate if (i == 0) { 44987c478bd9Sstevel@tonic-gate assign->phys_hi = 0; 44997c478bd9Sstevel@tonic-gate assign->phys_lo = 0; 45007c478bd9Sstevel@tonic-gate assign->phys_len = 0; 45017c478bd9Sstevel@tonic-gate } 45027c478bd9Sstevel@tonic-gate } 45037c478bd9Sstevel@tonic-gate } 45047c478bd9Sstevel@tonic-gate } 45057c478bd9Sstevel@tonic-gate 45067c478bd9Sstevel@tonic-gate int 45078134ee03Srw pcmcia_alloc_mem(dev_info_t *dip, ndi_ra_request_t *req, ra_return_t *ret, 45088134ee03Srw dev_info_t **res_dip) 45097c478bd9Sstevel@tonic-gate { 45108134ee03Srw return (pcmcia_ra_alloc(dip, req, ret, NDI_RA_TYPE_MEM, res_dip)); 45117c478bd9Sstevel@tonic-gate } 45127c478bd9Sstevel@tonic-gate 45137c478bd9Sstevel@tonic-gate int 45148134ee03Srw pcmcia_alloc_io(dev_info_t *dip, ndi_ra_request_t *req, ra_return_t *ret, 45158134ee03Srw dev_info_t **res_dip) 45167c478bd9Sstevel@tonic-gate { 45178134ee03Srw return (pcmcia_ra_alloc(dip, req, ret, NDI_RA_TYPE_IO, res_dip)); 45188134ee03Srw } 45198134ee03Srw 45208134ee03Srw static boolean_t 45218134ee03Srw is_subtractv(dev_info_t *dip) 45228134ee03Srw { 45238134ee03Srw uint_t class; 45248134ee03Srw 45258134ee03Srw if (dip == NULL) 45268134ee03Srw return (B_FALSE); 45278134ee03Srw class = ddi_getprop(DDI_DEV_T_ANY, dip, 45288134ee03Srw DDI_PROP_CANSLEEP|DDI_PROP_DONTPASS, 45298134ee03Srw "class-code", 0xff); 45308134ee03Srw if (class == PPB_SUBTRACTIVE) { 45318134ee03Srw return (B_TRUE); 45328134ee03Srw } 45338134ee03Srw return (B_FALSE); 45348134ee03Srw } 45358134ee03Srw 45368134ee03Srw /* 45378134ee03Srw * pcmcia_pci_alloc() 45388134ee03Srw * allocate mem or I/O resource from the ancestor of the cardbus bridge. 45398134ee03Srw * First start from the parent node. If the parent is a subtractive 45408134ee03Srw * decode bridge and it does not have the requested resource, go up the 45418134ee03Srw * device tree to find the resource. 45428134ee03Srw * 45438134ee03Srw * dip the parent node of the cardbus bridge 45448134ee03Srw * 45458134ee03Srw * res_dip returns a pointer to the node from which the 45468134ee03Srw * resource is obtained. *res_dip could point to 45478134ee03Srw * the parent or a higher level ancestor. *res_dip 45488134ee03Srw * should be saved by the caller and later passed 45498134ee03Srw * to pcmcia_ra_free(); 45508134ee03Srw */ 45518134ee03Srw int 45528134ee03Srw pcmcia_pci_alloc(dev_info_t *dip, ndi_ra_request_t *req, ra_return_t *ret, 45538134ee03Srw char *type, dev_info_t **res_dip) 45548134ee03Srw { 45558134ee03Srw uint64_t base = 0; 45568134ee03Srw uint64_t len = 0; 45578134ee03Srw 45588134ee03Srw if ((ndi_ra_alloc(dip, req, &base, &len, type, NDI_RA_PASS) 45598134ee03Srw == NDI_FAILURE) || 45608134ee03Srw ((base >> 32) != 0)) { 45618134ee03Srw if (is_subtractv(dip)) { 45628134ee03Srw return (pcmcia_pci_alloc(ddi_get_parent(dip), 45638134ee03Srw req, ret, type, res_dip)); 45648134ee03Srw 45658134ee03Srw } else { 45668134ee03Srw ret->ra_addr_hi = 0; 45678134ee03Srw ret->ra_addr_lo = 0; 45688134ee03Srw ret->ra_len = 0; 45698134ee03Srw return (DDI_FAILURE); 45708134ee03Srw } 45718134ee03Srw } 45728134ee03Srw ret->ra_addr_lo = base & 0xffffffff; 45738134ee03Srw ret->ra_addr_hi = 0; 45748134ee03Srw ret->ra_len = len; 45758134ee03Srw *res_dip = dip; 45768134ee03Srw return (DDI_SUCCESS); 45777c478bd9Sstevel@tonic-gate } 45787c478bd9Sstevel@tonic-gate 45797c478bd9Sstevel@tonic-gate int 45807c478bd9Sstevel@tonic-gate pcmcia_ra_alloc(dev_info_t *dip, ndi_ra_request_t *req, ra_return_t *ret, 45818134ee03Srw char *type, dev_info_t **res_dip) 45827c478bd9Sstevel@tonic-gate { 45837c478bd9Sstevel@tonic-gate uint64_t base = 0; 45847c478bd9Sstevel@tonic-gate uint64_t len = 0; 45857c478bd9Sstevel@tonic-gate 45867c478bd9Sstevel@tonic-gate /* 45877c478bd9Sstevel@tonic-gate * Allocate space from busra resource list 45887c478bd9Sstevel@tonic-gate * should not return an address > 32 bits 45897c478bd9Sstevel@tonic-gate */ 45907c478bd9Sstevel@tonic-gate 45917c478bd9Sstevel@tonic-gate if ((ndi_ra_alloc(dip, req, &base, &len, type, NDI_RA_PASS) 45927c478bd9Sstevel@tonic-gate == NDI_FAILURE) || 45937c478bd9Sstevel@tonic-gate ((base >> 32) != 0)) { 45948134ee03Srw return (pcmcia_pci_alloc(ddi_get_parent(dip), req, ret, 45958134ee03Srw type, res_dip)); 45967c478bd9Sstevel@tonic-gate } else { 45977c478bd9Sstevel@tonic-gate ret->ra_addr_lo = base & 0xffffffff; 45988134ee03Srw ret->ra_addr_hi = 0; 45997c478bd9Sstevel@tonic-gate ret->ra_len = len; 46008134ee03Srw *res_dip = dip; 46018134ee03Srw return (DDI_SUCCESS); 46027c478bd9Sstevel@tonic-gate } 46037c478bd9Sstevel@tonic-gate } 46047c478bd9Sstevel@tonic-gate 46057c478bd9Sstevel@tonic-gate int 46067c478bd9Sstevel@tonic-gate pcmcia_free_mem(dev_info_t *dip, ra_return_t *ret) 46077c478bd9Sstevel@tonic-gate { 46087c478bd9Sstevel@tonic-gate return (pcmcia_ra_free(dip, ret, NDI_RA_TYPE_MEM)); 46097c478bd9Sstevel@tonic-gate } 46107c478bd9Sstevel@tonic-gate 46117c478bd9Sstevel@tonic-gate int 46127c478bd9Sstevel@tonic-gate pcmcia_free_io(dev_info_t *dip, ra_return_t *ret) 46137c478bd9Sstevel@tonic-gate { 46147c478bd9Sstevel@tonic-gate return (pcmcia_ra_free(dip, ret, NDI_RA_TYPE_IO)); 46157c478bd9Sstevel@tonic-gate } 46167c478bd9Sstevel@tonic-gate 46177c478bd9Sstevel@tonic-gate int 46187c478bd9Sstevel@tonic-gate pcmcia_ra_free(dev_info_t *dip, ra_return_t *ret, char *type) 46197c478bd9Sstevel@tonic-gate { 462081ea8c75Srw if (dip == (dev_info_t *)-1) 462181ea8c75Srw return (DDI_FAILURE); 46227c478bd9Sstevel@tonic-gate if (ndi_ra_free(dip, (uint64_t)ret->ra_addr_lo, (uint64_t)ret->ra_len, 46237c478bd9Sstevel@tonic-gate type, NDI_RA_PASS) == NDI_SUCCESS) { 46247c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 46257c478bd9Sstevel@tonic-gate } else { 46267c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 46277c478bd9Sstevel@tonic-gate } 46287c478bd9Sstevel@tonic-gate } 46297c478bd9Sstevel@tonic-gate 46307c478bd9Sstevel@tonic-gate 46317c478bd9Sstevel@tonic-gate /* 46327c478bd9Sstevel@tonic-gate * when the low level device configuration does resource assignment 46337c478bd9Sstevel@tonic-gate * (devconf) then free the allocated resources so we can reassign them 46347c478bd9Sstevel@tonic-gate * later. Walk the child list to get them. 46357c478bd9Sstevel@tonic-gate */ 46367c478bd9Sstevel@tonic-gate void 46377c478bd9Sstevel@tonic-gate pcmcia_free_resources(dev_info_t *self) 46387c478bd9Sstevel@tonic-gate { 46397c478bd9Sstevel@tonic-gate struct regspec *assigned; 46407c478bd9Sstevel@tonic-gate int len; 46417c478bd9Sstevel@tonic-gate dev_info_t *dip; 4642b9ccdc5aScth int circ; 46437c478bd9Sstevel@tonic-gate 4644b9ccdc5aScth ndi_devi_enter(self, &circ); 46457c478bd9Sstevel@tonic-gate /* do searches in compatible property order */ 46467c478bd9Sstevel@tonic-gate for (dip = (dev_info_t *)DEVI(self)->devi_child; 46477c478bd9Sstevel@tonic-gate dip != NULL; 46487c478bd9Sstevel@tonic-gate dip = (dev_info_t *)DEVI(dip)->devi_sibling) { 46497c478bd9Sstevel@tonic-gate len = 0; 4650a3282898Scth if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 46517c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS|DDI_PROP_CANSLEEP, 46527c478bd9Sstevel@tonic-gate "assigned-addresses", 46537c478bd9Sstevel@tonic-gate (caddr_t)&assigned, 46547c478bd9Sstevel@tonic-gate &len) == DDI_PROP_SUCCESS) { 46557c478bd9Sstevel@tonic-gate /* 46567c478bd9Sstevel@tonic-gate * if there are assigned resources at this point, 46577c478bd9Sstevel@tonic-gate * then the OBP or devconf have assigned them and 46587c478bd9Sstevel@tonic-gate * they need to be freed. 46597c478bd9Sstevel@tonic-gate */ 46607c478bd9Sstevel@tonic-gate kmem_free(assigned, len); 46617c478bd9Sstevel@tonic-gate } 46627c478bd9Sstevel@tonic-gate } 4663b9ccdc5aScth ndi_devi_exit(self, circ); 46647c478bd9Sstevel@tonic-gate } 46657c478bd9Sstevel@tonic-gate 46667c478bd9Sstevel@tonic-gate /* 46677c478bd9Sstevel@tonic-gate * this is the equivalent of pcm_get_intr using ra_allocs. 46687c478bd9Sstevel@tonic-gate * returns -1 if failed, otherwise returns the allocated irq. 46697c478bd9Sstevel@tonic-gate * The input request, if less than zero it means not a specific 46707c478bd9Sstevel@tonic-gate * irq requested. If larger then 0 then we are requesting that specific 46717c478bd9Sstevel@tonic-gate * irq 46727c478bd9Sstevel@tonic-gate */ 46737c478bd9Sstevel@tonic-gate int 46747c478bd9Sstevel@tonic-gate pcmcia_get_intr(dev_info_t *dip, int request) 46757c478bd9Sstevel@tonic-gate { 46767c478bd9Sstevel@tonic-gate ndi_ra_request_t req; 46777c478bd9Sstevel@tonic-gate uint64_t base; 46787c478bd9Sstevel@tonic-gate uint64_t len; 46797c478bd9Sstevel@tonic-gate int err; 46807c478bd9Sstevel@tonic-gate 46817c478bd9Sstevel@tonic-gate bzero(&req, sizeof (req)); 46827c478bd9Sstevel@tonic-gate base = 0; 46837c478bd9Sstevel@tonic-gate len = 1; 46847c478bd9Sstevel@tonic-gate if (request >= 0) { 46857c478bd9Sstevel@tonic-gate req.ra_flags = NDI_RA_ALLOC_SPECIFIED; 46867c478bd9Sstevel@tonic-gate req.ra_len = 1; 46877c478bd9Sstevel@tonic-gate req.ra_addr = (uint64_t)request; 46887c478bd9Sstevel@tonic-gate } 46897c478bd9Sstevel@tonic-gate 46907c478bd9Sstevel@tonic-gate req.ra_boundbase = 0; 46917c478bd9Sstevel@tonic-gate req.ra_boundlen = 0xffffffffUL; 46927c478bd9Sstevel@tonic-gate req.ra_flags |= NDI_RA_ALLOC_BOUNDED; 46937c478bd9Sstevel@tonic-gate 46947c478bd9Sstevel@tonic-gate err = ndi_ra_alloc(dip, &req, &base, &len, NDI_RA_TYPE_INTR, 46957c478bd9Sstevel@tonic-gate NDI_RA_PASS); 46967c478bd9Sstevel@tonic-gate 46977c478bd9Sstevel@tonic-gate if (err == NDI_FAILURE) { 46987c478bd9Sstevel@tonic-gate return (-1); 46997c478bd9Sstevel@tonic-gate } else { 47007c478bd9Sstevel@tonic-gate return ((int)base); 47017c478bd9Sstevel@tonic-gate } 47027c478bd9Sstevel@tonic-gate } 47037c478bd9Sstevel@tonic-gate 47047c478bd9Sstevel@tonic-gate 47057c478bd9Sstevel@tonic-gate int 47067c478bd9Sstevel@tonic-gate pcmcia_return_intr(dev_info_t *dip, int request) 47077c478bd9Sstevel@tonic-gate { 47087c478bd9Sstevel@tonic-gate if ((ndi_ra_free(dip, (uint64_t)request, 1, NDI_RA_TYPE_INTR, 47097c478bd9Sstevel@tonic-gate NDI_RA_PASS)) == NDI_SUCCESS) { 47107c478bd9Sstevel@tonic-gate return (0); 47117c478bd9Sstevel@tonic-gate } else 47127c478bd9Sstevel@tonic-gate return (-1); 47137c478bd9Sstevel@tonic-gate 47147c478bd9Sstevel@tonic-gate } 47157c478bd9Sstevel@tonic-gate 47167c478bd9Sstevel@tonic-gate #ifdef sparc 47177c478bd9Sstevel@tonic-gate 47187c478bd9Sstevel@tonic-gate int 47197c478bd9Sstevel@tonic-gate pcmcia_add_intr_impl(dev_info_t *dip, dev_info_t *rdip, 47207c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp) 47217c478bd9Sstevel@tonic-gate { 47227c478bd9Sstevel@tonic-gate 47237c478bd9Sstevel@tonic-gate struct pcmcia_parent_private *ppd; 47247c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t *sockp; 47257c478bd9Sstevel@tonic-gate int socket, ret; 47267c478bd9Sstevel@tonic-gate struct pcmcia_adapter *adapt; 47277c478bd9Sstevel@tonic-gate set_irq_handler_t handler; 47287c478bd9Sstevel@tonic-gate struct intrspec *pispec; 47297c478bd9Sstevel@tonic-gate 47307c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 47317c478bd9Sstevel@tonic-gate if (pcmcia_debug) { 47327c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 47337c478bd9Sstevel@tonic-gate "pcmcia_add_intr_impl() entered " 47347c478bd9Sstevel@tonic-gate "dip=%p rdip=%p hdlp=%p \n", 47357c478bd9Sstevel@tonic-gate (void *)dip, (void *)rdip, (void *)hdlp); 47367c478bd9Sstevel@tonic-gate } 47377c478bd9Sstevel@tonic-gate #endif 47387c478bd9Sstevel@tonic-gate 47397c478bd9Sstevel@tonic-gate ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(rdip); 47407c478bd9Sstevel@tonic-gate socket = ppd->ppd_socket; 47417c478bd9Sstevel@tonic-gate sockp = pcmcia_sockets[socket]; 47427c478bd9Sstevel@tonic-gate adapt = sockp->ls_adapter; 47437c478bd9Sstevel@tonic-gate 47447c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 47457c478bd9Sstevel@tonic-gate if (pcmcia_debug) { 47467c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia_add_intr_impl()" 47477c478bd9Sstevel@tonic-gate " ppd_flags=0X%x PPD_CARD_MULTI=0X%x\n" 47487c478bd9Sstevel@tonic-gate " ppd_intrspec=%p ls_inthandlers=%p\n", 47497c478bd9Sstevel@tonic-gate ppd->ppd_flags, PPD_CARD_MULTI, 47507c478bd9Sstevel@tonic-gate (void *) ppd->ppd_intrspec, 47517c478bd9Sstevel@tonic-gate (void *)sockp->ls_inthandlers); 47527c478bd9Sstevel@tonic-gate } 47537c478bd9Sstevel@tonic-gate #endif 47547c478bd9Sstevel@tonic-gate 47557c478bd9Sstevel@tonic-gate /* 47567c478bd9Sstevel@tonic-gate * calculate IPL level when we support multiple levels 47577c478bd9Sstevel@tonic-gate */ 47587c478bd9Sstevel@tonic-gate pispec = ppd->ppd_intrspec; 47597c478bd9Sstevel@tonic-gate if (pispec == NULL) { 47607c478bd9Sstevel@tonic-gate sockp->ls_error = BAD_IRQ; 47617c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 47627c478bd9Sstevel@tonic-gate } 47637c478bd9Sstevel@tonic-gate 47647c478bd9Sstevel@tonic-gate handler.socket = sockp->ls_socket; 47657c478bd9Sstevel@tonic-gate handler.irq = 0; /* default case */ 47667c478bd9Sstevel@tonic-gate handler.handler = (f_tt *)hdlp->ih_cb_func; 47677c478bd9Sstevel@tonic-gate handler.arg1 = hdlp->ih_cb_arg1; 47687c478bd9Sstevel@tonic-gate handler.arg2 = hdlp->ih_cb_arg2; 4769360e6f5eSmathue handler.handler_id = (uint32_t)(uintptr_t)rdip; 47707c478bd9Sstevel@tonic-gate 47717c478bd9Sstevel@tonic-gate /* 47727c478bd9Sstevel@tonic-gate * check if multifunction and do the right thing 47737c478bd9Sstevel@tonic-gate * we put an intercept in between the mfc handler and 47747c478bd9Sstevel@tonic-gate * us so we can catch and process. We might be able 47757c478bd9Sstevel@tonic-gate * to optimize this depending on the card features 47767c478bd9Sstevel@tonic-gate * (a future option). 47777c478bd9Sstevel@tonic-gate */ 47787c478bd9Sstevel@tonic-gate if (ppd->ppd_flags & PPD_CARD_MULTI) { 47797c478bd9Sstevel@tonic-gate inthandler_t *intr; 47807c478bd9Sstevel@tonic-gate /* 47817c478bd9Sstevel@tonic-gate * note that the first function is a special 47827c478bd9Sstevel@tonic-gate * case since it sets things up. We fall through 47837c478bd9Sstevel@tonic-gate * to the lower code and get the hardware set up. 47847c478bd9Sstevel@tonic-gate * subsequent times we just lock the list and insert 47857c478bd9Sstevel@tonic-gate * the handler and all is well. 47867c478bd9Sstevel@tonic-gate */ 47877c478bd9Sstevel@tonic-gate intr = kmem_zalloc(sizeof (inthandler_t), KM_NOSLEEP); 47887c478bd9Sstevel@tonic-gate if (intr == NULL) { 47897c478bd9Sstevel@tonic-gate sockp->ls_error = BAD_IRQ; 47907c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 47917c478bd9Sstevel@tonic-gate } 47927c478bd9Sstevel@tonic-gate intr->intr = hdlp->ih_cb_func; 4793360e6f5eSmathue intr->handler_id = (uint_t)(uintptr_t)rdip; 47947c478bd9Sstevel@tonic-gate intr->arg1 = hdlp->ih_cb_arg1; 47957c478bd9Sstevel@tonic-gate intr->arg2 = hdlp->ih_cb_arg2; 47967c478bd9Sstevel@tonic-gate intr->socket = socket; 47977c478bd9Sstevel@tonic-gate 47987c478bd9Sstevel@tonic-gate mutex_enter(&sockp->ls_ilock); 47997c478bd9Sstevel@tonic-gate if (sockp->ls_inthandlers == NULL) { 48007c478bd9Sstevel@tonic-gate intr->next = intr->prev = intr; 48017c478bd9Sstevel@tonic-gate sockp->ls_inthandlers = intr; 48027c478bd9Sstevel@tonic-gate sockp->ls_mfintr_dip = rdip; 48037c478bd9Sstevel@tonic-gate mutex_exit(&sockp->ls_ilock); 48047c478bd9Sstevel@tonic-gate 48057c478bd9Sstevel@tonic-gate /* 48067c478bd9Sstevel@tonic-gate * replace first function handler with 48077c478bd9Sstevel@tonic-gate * the mfc handler 48087c478bd9Sstevel@tonic-gate */ 48097c478bd9Sstevel@tonic-gate handler.handler = (f_tt *)pcmcia_mfc_intr; 48107c478bd9Sstevel@tonic-gate handler.arg1 = (caddr_t)sockp; 48117c478bd9Sstevel@tonic-gate handler.arg2 = NULL; 48127c478bd9Sstevel@tonic-gate } else { 48137c478bd9Sstevel@tonic-gate insque(intr, sockp->ls_inthandlers); 48147c478bd9Sstevel@tonic-gate mutex_exit(&sockp->ls_ilock); 48157c478bd9Sstevel@tonic-gate 48167c478bd9Sstevel@tonic-gate pispec->intrspec_vec = sockp->ls_intr_vec; 48177c478bd9Sstevel@tonic-gate pispec->intrspec_pri = sockp->ls_intr_pri; 48187c478bd9Sstevel@tonic-gate hdlp->ih_pri = sockp->ls_intr_pri; 48197c478bd9Sstevel@tonic-gate 48207c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 48217c478bd9Sstevel@tonic-gate } 48227c478bd9Sstevel@tonic-gate } 48237c478bd9Sstevel@tonic-gate 48247c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 48257c478bd9Sstevel@tonic-gate if (pcmcia_debug) { 48267c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia_add_intr_impl() let adapter do it\n"); 48277c478bd9Sstevel@tonic-gate } 48287c478bd9Sstevel@tonic-gate #endif 48297c478bd9Sstevel@tonic-gate pispec->intrspec_func = (uint32_t (*)())handler.handler; 48307c478bd9Sstevel@tonic-gate 48317c478bd9Sstevel@tonic-gate /* set default IPL then check for override */ 48327c478bd9Sstevel@tonic-gate 48337c478bd9Sstevel@tonic-gate pispec->intrspec_pri = sockp->ls_intr_pri; 48347c478bd9Sstevel@tonic-gate hdlp->ih_pri = pispec->intrspec_pri; 48357c478bd9Sstevel@tonic-gate 48367c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 48377c478bd9Sstevel@tonic-gate if (pcmcia_debug) { 48387c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia_add_intr_impl() socket=%d irq=%d" 48397c478bd9Sstevel@tonic-gate " handler_id=0X%x handler=%p arg1=%p arg2=%p\n", 48407c478bd9Sstevel@tonic-gate handler.socket, handler.irq, 48417c478bd9Sstevel@tonic-gate handler.handler_id, (void *)handler.handler, handler.arg1, 48427c478bd9Sstevel@tonic-gate handler.arg2); 48437c478bd9Sstevel@tonic-gate } 48447c478bd9Sstevel@tonic-gate #endif 48457c478bd9Sstevel@tonic-gate 48467c478bd9Sstevel@tonic-gate if ((ret = SET_IRQ(sockp->ls_if, adapt->pca_dip, &handler)) != 48477c478bd9Sstevel@tonic-gate SUCCESS) { 48487c478bd9Sstevel@tonic-gate sockp->ls_error = ret; 48497c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 48507c478bd9Sstevel@tonic-gate } 48517c478bd9Sstevel@tonic-gate 48527c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 48537c478bd9Sstevel@tonic-gate if (pcmcia_debug) { 48547c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia_add_intr_impl()" 48557c478bd9Sstevel@tonic-gate " iblk_cookie=%p idev_cookie=%p\n" 48567c478bd9Sstevel@tonic-gate " ls_flags=0X%x PCS_COOKIES_VALID=0X%x\n", 48577c478bd9Sstevel@tonic-gate (void *)handler.iblk_cookie, 48587c478bd9Sstevel@tonic-gate (void *)handler.idev_cookie, 48597c478bd9Sstevel@tonic-gate sockp->ls_flags, PCS_COOKIES_VALID); 48607c478bd9Sstevel@tonic-gate } 48617c478bd9Sstevel@tonic-gate #endif 48627c478bd9Sstevel@tonic-gate 48637c478bd9Sstevel@tonic-gate if (!(sockp->ls_flags & PCS_COOKIES_VALID)) { 4864360e6f5eSmathue hdlp->ih_pri = (uint_t)(uintptr_t)*handler.iblk_cookie; 48657c478bd9Sstevel@tonic-gate sockp->ls_iblk = *handler.iblk_cookie; 48667c478bd9Sstevel@tonic-gate sockp->ls_idev = *handler.idev_cookie; 48677c478bd9Sstevel@tonic-gate sockp->ls_flags |= PCS_COOKIES_VALID; 48687c478bd9Sstevel@tonic-gate } 48697c478bd9Sstevel@tonic-gate 48707c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 48717c478bd9Sstevel@tonic-gate } 48727c478bd9Sstevel@tonic-gate 48737c478bd9Sstevel@tonic-gate void 48747c478bd9Sstevel@tonic-gate pcmcia_remove_intr_impl(dev_info_t *dip, dev_info_t *rdip, 48757c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp) 48767c478bd9Sstevel@tonic-gate { 48777c478bd9Sstevel@tonic-gate 48787c478bd9Sstevel@tonic-gate struct pcmcia_parent_private *ppd; 48797c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t *sockp; 48807c478bd9Sstevel@tonic-gate clear_irq_handler_t handler; 48817c478bd9Sstevel@tonic-gate struct intrspec *pispec; 48827c478bd9Sstevel@tonic-gate int socket; 48837c478bd9Sstevel@tonic-gate 48847c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 48857c478bd9Sstevel@tonic-gate if (pcmcia_debug) { 48867c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia_remove_intr_impl() entered" 48877c478bd9Sstevel@tonic-gate " dip=%p rdip=%p hdlp=%p\n", 48887c478bd9Sstevel@tonic-gate (void *)dip, (void *)rdip, (void *)hdlp); 48897c478bd9Sstevel@tonic-gate } 48907c478bd9Sstevel@tonic-gate #endif 48917c478bd9Sstevel@tonic-gate 48927c478bd9Sstevel@tonic-gate ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(rdip); 48937c478bd9Sstevel@tonic-gate socket = ppd->ppd_socket; 48947c478bd9Sstevel@tonic-gate sockp = pcmcia_sockets[socket]; 48957c478bd9Sstevel@tonic-gate pispec = ppd->ppd_intrspec; 48967c478bd9Sstevel@tonic-gate 48977c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 48987c478bd9Sstevel@tonic-gate if (pcmcia_debug) { 48997c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia_remove_intr_impl()" 49007c478bd9Sstevel@tonic-gate " ls_inthandlers=%p ls_intrspec=%p\n", 49017c478bd9Sstevel@tonic-gate (void *)sockp->ls_inthandlers, 49027c478bd9Sstevel@tonic-gate (void *)&sockp->ls_intrspec); 49037c478bd9Sstevel@tonic-gate } 49047c478bd9Sstevel@tonic-gate #endif 49057c478bd9Sstevel@tonic-gate 49067c478bd9Sstevel@tonic-gate /* first handle the multifunction case since it is simple */ 49077c478bd9Sstevel@tonic-gate mutex_enter(&sockp->ls_ilock); 4908a195726fSgovinda if (sockp->ls_inthandlers != NULL) { 49097c478bd9Sstevel@tonic-gate /* we must be MFC */ 49107c478bd9Sstevel@tonic-gate inthandler_t *intr; 49117c478bd9Sstevel@tonic-gate int remhandler = 0; 49127c478bd9Sstevel@tonic-gate intr = sockp->ls_inthandlers; 49137c478bd9Sstevel@tonic-gate 49147c478bd9Sstevel@tonic-gate /* Check if there is only one handler left */ 49157c478bd9Sstevel@tonic-gate if ((intr->next == intr) && (intr->prev == intr)) { 4916360e6f5eSmathue if (intr->handler_id == (unsigned)(uintptr_t)rdip) { 49177c478bd9Sstevel@tonic-gate sockp->ls_inthandlers = NULL; 49187c478bd9Sstevel@tonic-gate remhandler++; 49197c478bd9Sstevel@tonic-gate kmem_free(intr, sizeof (inthandler_t)); 49207c478bd9Sstevel@tonic-gate } 49217c478bd9Sstevel@tonic-gate } else { 49227c478bd9Sstevel@tonic-gate inthandler_t *first; 49237c478bd9Sstevel@tonic-gate int done; 49247c478bd9Sstevel@tonic-gate 49257c478bd9Sstevel@tonic-gate for (done = 0, first = intr; !done; intr = intr->next) { 49267c478bd9Sstevel@tonic-gate if (intr->next == first) 49277c478bd9Sstevel@tonic-gate done++; 4928360e6f5eSmathue if (intr->handler_id == 4929360e6f5eSmathue (unsigned)(uintptr_t)rdip) { 49307c478bd9Sstevel@tonic-gate done++; 49317c478bd9Sstevel@tonic-gate 49327c478bd9Sstevel@tonic-gate /* 49337c478bd9Sstevel@tonic-gate * If we're about to remove the 49347c478bd9Sstevel@tonic-gate * handler at the head of 49357c478bd9Sstevel@tonic-gate * the list, make the next 49367c478bd9Sstevel@tonic-gate * handler in line the head. 49377c478bd9Sstevel@tonic-gate */ 49387c478bd9Sstevel@tonic-gate if (sockp->ls_inthandlers == intr) 49397c478bd9Sstevel@tonic-gate sockp->ls_inthandlers = 49407c478bd9Sstevel@tonic-gate intr->next; 49417c478bd9Sstevel@tonic-gate 49427c478bd9Sstevel@tonic-gate remque(intr); 49437c478bd9Sstevel@tonic-gate kmem_free(intr, sizeof (inthandler_t)); 49447c478bd9Sstevel@tonic-gate break; 49457c478bd9Sstevel@tonic-gate } /* handler_id */ 49467c478bd9Sstevel@tonic-gate } /* for */ 49477c478bd9Sstevel@tonic-gate } /* intr->next */ 49487c478bd9Sstevel@tonic-gate 49497c478bd9Sstevel@tonic-gate if (!remhandler) { 49507c478bd9Sstevel@tonic-gate mutex_exit(&sockp->ls_ilock); 49517c478bd9Sstevel@tonic-gate return; 49527c478bd9Sstevel@tonic-gate } 49537c478bd9Sstevel@tonic-gate 49547c478bd9Sstevel@tonic-gate /* need to get the dip that was used to add the handler */ 49557c478bd9Sstevel@tonic-gate rdip = sockp->ls_mfintr_dip; 49567c478bd9Sstevel@tonic-gate } 49577c478bd9Sstevel@tonic-gate 4958a195726fSgovinda mutex_exit(&sockp->ls_ilock); 49597c478bd9Sstevel@tonic-gate 49607c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 49617c478bd9Sstevel@tonic-gate if (pcmcia_debug) { 49627c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia_remove_intr_impl()" 49637c478bd9Sstevel@tonic-gate " pispec=%p rdip=%p\n", 49647c478bd9Sstevel@tonic-gate (void *)pispec, (void *)rdip); 49657c478bd9Sstevel@tonic-gate } 49667c478bd9Sstevel@tonic-gate #endif 49677c478bd9Sstevel@tonic-gate 49687c478bd9Sstevel@tonic-gate handler.socket = sockp->ls_socket; 4969360e6f5eSmathue handler.handler_id = (uint32_t)(uintptr_t)rdip; 49707c478bd9Sstevel@tonic-gate handler.handler = (f_tt *)pispec->intrspec_func; 49717c478bd9Sstevel@tonic-gate CLEAR_IRQ(sockp->ls_if, dip, &handler); 49727c478bd9Sstevel@tonic-gate } 49737c478bd9Sstevel@tonic-gate 49747c478bd9Sstevel@tonic-gate 49757c478bd9Sstevel@tonic-gate /* Consolidated interrupt processing interface */ 49767c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 49777c478bd9Sstevel@tonic-gate int 49787c478bd9Sstevel@tonic-gate pcmcia_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op, 49797c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, void *result) 49807c478bd9Sstevel@tonic-gate { 4981a195726fSgovinda int ret = DDI_SUCCESS; 49827c478bd9Sstevel@tonic-gate 49837c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 49847c478bd9Sstevel@tonic-gate if (pcmcia_debug) { 49857c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia_intr_ops() intr_op=%d\n", 49867c478bd9Sstevel@tonic-gate (int)intr_op); 49877c478bd9Sstevel@tonic-gate } 49887c478bd9Sstevel@tonic-gate #endif 49897c478bd9Sstevel@tonic-gate 49907c478bd9Sstevel@tonic-gate switch (intr_op) { 49917c478bd9Sstevel@tonic-gate case DDI_INTROP_GETCAP: 4992a195726fSgovinda *(int *)result = DDI_INTR_FLAG_LEVEL; 49937c478bd9Sstevel@tonic-gate break; 49947c478bd9Sstevel@tonic-gate case DDI_INTROP_SETCAP: 49957c478bd9Sstevel@tonic-gate ret = DDI_ENOTSUP; 49967c478bd9Sstevel@tonic-gate break; 49977c478bd9Sstevel@tonic-gate case DDI_INTROP_ALLOC: 49987c478bd9Sstevel@tonic-gate *(int *)result = hdlp->ih_scratch1; 49997c478bd9Sstevel@tonic-gate break; 50007c478bd9Sstevel@tonic-gate case DDI_INTROP_FREE: 50017c478bd9Sstevel@tonic-gate break; 50027c478bd9Sstevel@tonic-gate case DDI_INTROP_GETPRI: 50037c478bd9Sstevel@tonic-gate if (pcmcia_add_intr_impl(dip, rdip, hdlp) != DDI_SUCCESS) 50047c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 50057c478bd9Sstevel@tonic-gate *(int *)result = hdlp->ih_pri; 50067c478bd9Sstevel@tonic-gate pcmcia_remove_intr_impl(dip, rdip, hdlp); 50077c478bd9Sstevel@tonic-gate break; 50087c478bd9Sstevel@tonic-gate case DDI_INTROP_SETPRI: 50097c478bd9Sstevel@tonic-gate break; 50107c478bd9Sstevel@tonic-gate case DDI_INTROP_ADDISR: 50117c478bd9Sstevel@tonic-gate ret = pcmcia_add_intr_impl(dip, rdip, hdlp); 50127c478bd9Sstevel@tonic-gate break; 50137c478bd9Sstevel@tonic-gate case DDI_INTROP_REMISR: 50147c478bd9Sstevel@tonic-gate pcmcia_remove_intr_impl(dip, rdip, hdlp); 50157c478bd9Sstevel@tonic-gate break; 50167c478bd9Sstevel@tonic-gate case DDI_INTROP_ENABLE: 50177c478bd9Sstevel@tonic-gate case DDI_INTROP_DISABLE: 50187c478bd9Sstevel@tonic-gate break; 50197c478bd9Sstevel@tonic-gate case DDI_INTROP_NINTRS: 50207c478bd9Sstevel@tonic-gate case DDI_INTROP_NAVAIL: 5021a54f81fbSanish *(int *)result = i_ddi_get_intx_nintrs(rdip); 50227c478bd9Sstevel@tonic-gate break; 50237c478bd9Sstevel@tonic-gate case DDI_INTROP_SUPPORTED_TYPES: 50247c478bd9Sstevel@tonic-gate /* PCI nexus driver supports only fixed interrupts */ 5025a54f81fbSanish *(int *)result = i_ddi_get_intx_nintrs(rdip) ? 50267c478bd9Sstevel@tonic-gate DDI_INTR_TYPE_FIXED : 0; 50277c478bd9Sstevel@tonic-gate break; 50287c478bd9Sstevel@tonic-gate default: 50297c478bd9Sstevel@tonic-gate ret = DDI_ENOTSUP; 50307c478bd9Sstevel@tonic-gate break; 50317c478bd9Sstevel@tonic-gate } 50327c478bd9Sstevel@tonic-gate 50337c478bd9Sstevel@tonic-gate return (ret); 50347c478bd9Sstevel@tonic-gate } 50357c478bd9Sstevel@tonic-gate 50367c478bd9Sstevel@tonic-gate #elif defined(__x86) || defined(__amd64) 50377c478bd9Sstevel@tonic-gate 50387c478bd9Sstevel@tonic-gate static struct intrspec *pcmcia_intr_get_ispec(dev_info_t *, int, 50397c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t **); 50407c478bd9Sstevel@tonic-gate static struct intrspec *pcmcia_intr_add_isr(dev_info_t *, dev_info_t *, 50417c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *); 50427c478bd9Sstevel@tonic-gate static int pcmcia_intr_enable_isr(dev_info_t *, dev_info_t *, 50437c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *); 50447c478bd9Sstevel@tonic-gate static void pcmcia_intr_remove_isr(dev_info_t *, dev_info_t *, 50457c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *); 50467c478bd9Sstevel@tonic-gate static void pcmcia_intr_disable_isr(dev_info_t *, dev_info_t *, 50477c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *); 50487c478bd9Sstevel@tonic-gate 50497c478bd9Sstevel@tonic-gate /* 50507c478bd9Sstevel@tonic-gate * pcmcia_intr_get_ispec: 50517c478bd9Sstevel@tonic-gate * This is mostly copied from older 'pcmcia_get_intrspec' function 50527c478bd9Sstevel@tonic-gate */ 50537c478bd9Sstevel@tonic-gate static struct intrspec * 50547c478bd9Sstevel@tonic-gate pcmcia_intr_get_ispec(dev_info_t *rdip, int inum, 50557c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t **sockp) 50567c478bd9Sstevel@tonic-gate { 50577c478bd9Sstevel@tonic-gate int socket; 50587c478bd9Sstevel@tonic-gate struct intrspec *intrspec; 50597c478bd9Sstevel@tonic-gate struct pcmcia_parent_private *ppd; 50607c478bd9Sstevel@tonic-gate 50617c478bd9Sstevel@tonic-gate if ((int)inum > 0 || (ddi_getprop(DDI_DEV_T_ANY, rdip, 50627c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "interrupts", -1) < 0)) 50637c478bd9Sstevel@tonic-gate return (NULL); 50647c478bd9Sstevel@tonic-gate 50657c478bd9Sstevel@tonic-gate ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(rdip); 50667c478bd9Sstevel@tonic-gate if (ppd == NULL || ppd->ppd_intrspec == NULL) 50677c478bd9Sstevel@tonic-gate return (NULL); 50687c478bd9Sstevel@tonic-gate 50697c478bd9Sstevel@tonic-gate if ((socket = ppd->ppd_socket) < 0) 50707c478bd9Sstevel@tonic-gate return (NULL); 50717c478bd9Sstevel@tonic-gate 50727c478bd9Sstevel@tonic-gate if ((*sockp = pcmcia_sockets[socket]) == NULL) 50737c478bd9Sstevel@tonic-gate return (NULL); 50747c478bd9Sstevel@tonic-gate 50757c478bd9Sstevel@tonic-gate intrspec = ppd->ppd_intrspec; 50767c478bd9Sstevel@tonic-gate if (intrspec->intrspec_vec == 0 && (*sockp)->ls_intr_vec != 0) 50777c478bd9Sstevel@tonic-gate intrspec->intrspec_vec = (*sockp)->ls_intr_vec; 50787c478bd9Sstevel@tonic-gate 50797c478bd9Sstevel@tonic-gate return (intrspec); 50807c478bd9Sstevel@tonic-gate } 50817c478bd9Sstevel@tonic-gate 50827c478bd9Sstevel@tonic-gate static struct intrspec * 50837c478bd9Sstevel@tonic-gate pcmcia_intr_add_isr(dev_info_t *dip, dev_info_t *rdip, 50847c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp) 50857c478bd9Sstevel@tonic-gate { 50867c478bd9Sstevel@tonic-gate int socket; 50877c478bd9Sstevel@tonic-gate struct intrspec *ispecp; 50887c478bd9Sstevel@tonic-gate struct pcmcia_adapter *adapt; 50897c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t *sockp; 50907c478bd9Sstevel@tonic-gate struct pcmcia_parent_private *ppd; 50917c478bd9Sstevel@tonic-gate 50927c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 50937c478bd9Sstevel@tonic-gate if (pcmcia_debug) 50947c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia_intr_add_isr: " 50957c478bd9Sstevel@tonic-gate "dip=0x%p rdip=0x%p hdlp=0x%p\n", 50967c478bd9Sstevel@tonic-gate (void *)dip, (void *)rdip, (void *)hdlp); 50977c478bd9Sstevel@tonic-gate #endif /* PCMCIA_DEBUG */ 50987c478bd9Sstevel@tonic-gate 50997c478bd9Sstevel@tonic-gate ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(rdip); 51007c478bd9Sstevel@tonic-gate socket = ppd->ppd_socket; 51017c478bd9Sstevel@tonic-gate sockp = pcmcia_sockets[socket]; 51027c478bd9Sstevel@tonic-gate adapt = sockp->ls_adapter; 51037c478bd9Sstevel@tonic-gate 51047c478bd9Sstevel@tonic-gate ispecp = ppd->ppd_intrspec; 51057c478bd9Sstevel@tonic-gate if (ispecp == NULL) { 51067c478bd9Sstevel@tonic-gate sockp->ls_error = BAD_IRQ; 51077c478bd9Sstevel@tonic-gate return (ispecp); 51087c478bd9Sstevel@tonic-gate } 51097c478bd9Sstevel@tonic-gate 51107c478bd9Sstevel@tonic-gate /* 51117c478bd9Sstevel@tonic-gate * check if multifunction and do the right thing 51127c478bd9Sstevel@tonic-gate * we put an intercept in between the mfc handler and us so we can 51137c478bd9Sstevel@tonic-gate * catch and process. We might be able to optimize this depending 51147c478bd9Sstevel@tonic-gate * on the card features (a future option). 51157c478bd9Sstevel@tonic-gate */ 51167c478bd9Sstevel@tonic-gate if (ppd->ppd_flags & PPD_CARD_MULTI && 51177c478bd9Sstevel@tonic-gate hdlp->ih_cb_func != pcmcia_mfc_intr) { 51187c478bd9Sstevel@tonic-gate inthandler_t *intr; 51197c478bd9Sstevel@tonic-gate 51207c478bd9Sstevel@tonic-gate /* 51217c478bd9Sstevel@tonic-gate * note that the first function is a special case since it 51227c478bd9Sstevel@tonic-gate * sets things up. We fall through to the lower code and 51237c478bd9Sstevel@tonic-gate * get the hardware set up. Subsequent times we just lock 51247c478bd9Sstevel@tonic-gate * the list and insert the handler and all is well. 51257c478bd9Sstevel@tonic-gate */ 51267c478bd9Sstevel@tonic-gate intr = kmem_zalloc(sizeof (inthandler_t), KM_NOSLEEP); 51277c478bd9Sstevel@tonic-gate if (intr == NULL) { 51287c478bd9Sstevel@tonic-gate sockp->ls_error = BAD_IRQ; 51297c478bd9Sstevel@tonic-gate return (NULL); 51307c478bd9Sstevel@tonic-gate } 51317c478bd9Sstevel@tonic-gate 51327c478bd9Sstevel@tonic-gate intr->intr = (uint32_t (*)())hdlp->ih_cb_func; 51337c478bd9Sstevel@tonic-gate intr->handler_id = (uint32_t)(uintptr_t)rdip; 51347c478bd9Sstevel@tonic-gate intr->arg1 = hdlp->ih_cb_arg1; 51357c478bd9Sstevel@tonic-gate intr->arg2 = hdlp->ih_cb_arg2; 51367c478bd9Sstevel@tonic-gate intr->socket = socket; 51377c478bd9Sstevel@tonic-gate mutex_enter(&sockp->ls_ilock); 51387c478bd9Sstevel@tonic-gate if (sockp->ls_inthandlers == NULL) { 51397c478bd9Sstevel@tonic-gate intr->next = intr->prev = intr; 51407c478bd9Sstevel@tonic-gate sockp->ls_inthandlers = intr; 51417c478bd9Sstevel@tonic-gate sockp->ls_mfintr_dip = rdip; 51427c478bd9Sstevel@tonic-gate } else { 51437c478bd9Sstevel@tonic-gate insque(intr, sockp->ls_inthandlers); 51447c478bd9Sstevel@tonic-gate } 51457c478bd9Sstevel@tonic-gate mutex_exit(&sockp->ls_ilock); 51467c478bd9Sstevel@tonic-gate return (ispecp); 51477c478bd9Sstevel@tonic-gate } 51487c478bd9Sstevel@tonic-gate 51497c478bd9Sstevel@tonic-gate /* 51507c478bd9Sstevel@tonic-gate * Do we need to allocate an IRQ at this point or not? 51517c478bd9Sstevel@tonic-gate */ 51527c478bd9Sstevel@tonic-gate if (adapt->pca_flags & PCA_RES_NEED_IRQ) { 51537c478bd9Sstevel@tonic-gate int i, irq; 51547c478bd9Sstevel@tonic-gate 51557c478bd9Sstevel@tonic-gate /* 51567c478bd9Sstevel@tonic-gate * this adapter needs IRQ allocations 51577c478bd9Sstevel@tonic-gate * this is only necessary if it is the first function on the 51587c478bd9Sstevel@tonic-gate * card being setup. The socket will keep the allocation info 51597c478bd9Sstevel@tonic-gate */ 51607c478bd9Sstevel@tonic-gate /* all functions use same intrspec except mfc handler */ 51617c478bd9Sstevel@tonic-gate if (hdlp->ih_cb_func == pcmcia_mfc_intr) { 51627c478bd9Sstevel@tonic-gate /* 51637c478bd9Sstevel@tonic-gate * We treat this special in order to allow things to 51647c478bd9Sstevel@tonic-gate * work properly for MFC cards. The intrspec for the 51657c478bd9Sstevel@tonic-gate * mfc dispatcher is intercepted and taken from the 51667c478bd9Sstevel@tonic-gate * logical socket in order to not be trying to 51677c478bd9Sstevel@tonic-gate * multiplex the meaning when ENABLE is called. 51687c478bd9Sstevel@tonic-gate */ 51697c478bd9Sstevel@tonic-gate ispecp = &sockp->ls_intrspec; 51707a364d25Sschwartz ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispecp; 51717c478bd9Sstevel@tonic-gate } 51727c478bd9Sstevel@tonic-gate 51737c478bd9Sstevel@tonic-gate if (adapt->pca_flags & PCA_IRQ_ISA) { 51747c478bd9Sstevel@tonic-gate for (irq = -1, i = 1; irq == -1 && i < 16; i++) { 51757c478bd9Sstevel@tonic-gate /* find available and usable IRQ level */ 51767c478bd9Sstevel@tonic-gate if (adapt->pca_avail_intr & (1 << i)) 51777c478bd9Sstevel@tonic-gate irq = pcmcia_get_intr(dip, i); 51787c478bd9Sstevel@tonic-gate } 51797c478bd9Sstevel@tonic-gate } 51807c478bd9Sstevel@tonic-gate if (irq < 0) { 51817c478bd9Sstevel@tonic-gate sockp->ls_error = NO_RESOURCE; 51827c478bd9Sstevel@tonic-gate return (NULL); 51837c478bd9Sstevel@tonic-gate } 51847c478bd9Sstevel@tonic-gate hdlp->ih_vector = sockp->ls_intr_vec = irq; 51857c478bd9Sstevel@tonic-gate 51867c478bd9Sstevel@tonic-gate 51877c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 51887c478bd9Sstevel@tonic-gate if (pcmcia_debug) 51897c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "allocated irq=%x\n", irq); 51907c478bd9Sstevel@tonic-gate #endif /* PCMCIA_DEBUG */ 51917c478bd9Sstevel@tonic-gate 51927c478bd9Sstevel@tonic-gate ispecp->intrspec_vec = sockp->ls_intr_vec; 51937c478bd9Sstevel@tonic-gate ispecp->intrspec_pri = sockp->ls_intr_pri; 51947c478bd9Sstevel@tonic-gate return (ispecp); 51957c478bd9Sstevel@tonic-gate } 51967c478bd9Sstevel@tonic-gate 51977c478bd9Sstevel@tonic-gate if (ispecp->intrspec_func != NULL) 51987c478bd9Sstevel@tonic-gate ispecp->intrspec_func = hdlp->ih_cb_func; 51997c478bd9Sstevel@tonic-gate 52007c478bd9Sstevel@tonic-gate /* set default IPL then check for override */ 52017c478bd9Sstevel@tonic-gate ispecp->intrspec_pri = sockp->ls_intr_pri; 52027c478bd9Sstevel@tonic-gate return (ispecp); 52037c478bd9Sstevel@tonic-gate } 52047c478bd9Sstevel@tonic-gate 52057c478bd9Sstevel@tonic-gate 52067c478bd9Sstevel@tonic-gate static int 52077c478bd9Sstevel@tonic-gate pcmcia_intr_enable_isr(dev_info_t *dip, dev_info_t *rdip, 52087c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp) 52097c478bd9Sstevel@tonic-gate { 52107c478bd9Sstevel@tonic-gate int socket, ret; 52117c478bd9Sstevel@tonic-gate int irq = 0; /* default case */ 52127c478bd9Sstevel@tonic-gate dev_info_t *parent = ddi_root_node(); 52137c478bd9Sstevel@tonic-gate struct intrspec *ispecp; 52147c478bd9Sstevel@tonic-gate set_irq_handler_t handler; 52157c478bd9Sstevel@tonic-gate struct pcmcia_adapter *adapt; 52167c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t *sockp; 52177c478bd9Sstevel@tonic-gate struct pcmcia_parent_private *ppd; 52187c478bd9Sstevel@tonic-gate 52197c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 52207c478bd9Sstevel@tonic-gate if (pcmcia_debug) 52217c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia_intr_enable_isr: " 52227c478bd9Sstevel@tonic-gate "dip=0x%p rdip=0x%p hdlp=0x%p\n", 52237c478bd9Sstevel@tonic-gate (void *)dip, (void *)rdip, (void *)hdlp); 52247c478bd9Sstevel@tonic-gate #endif /* PCMCIA_DEBUG */ 52257c478bd9Sstevel@tonic-gate 52267c478bd9Sstevel@tonic-gate ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(rdip); 52277c478bd9Sstevel@tonic-gate socket = ppd->ppd_socket; 52287c478bd9Sstevel@tonic-gate sockp = pcmcia_sockets[socket]; 52297c478bd9Sstevel@tonic-gate adapt = sockp->ls_adapter; 52307c478bd9Sstevel@tonic-gate 52317c478bd9Sstevel@tonic-gate ispecp = ppd->ppd_intrspec; 52327c478bd9Sstevel@tonic-gate ASSERT(ispecp); 52337c478bd9Sstevel@tonic-gate 52347c478bd9Sstevel@tonic-gate mutex_enter(&sockp->ls_ilock); 52357c478bd9Sstevel@tonic-gate if ((sockp->ls_inthandlers != NULL) && 52367a364d25Sschwartz ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp != 52377a364d25Sschwartz &sockp->ls_intrspec) { 52387c478bd9Sstevel@tonic-gate inthandler_t *intr = sockp->ls_inthandlers; 52397c478bd9Sstevel@tonic-gate 52407c478bd9Sstevel@tonic-gate ASSERT(ppd->ppd_flags & PPD_CARD_MULTI); 52417c478bd9Sstevel@tonic-gate 52427c478bd9Sstevel@tonic-gate /* Only one handler. So, call ddi_add_intr on it */ 52437c478bd9Sstevel@tonic-gate if ((intr->next == intr) && (intr->prev == intr)) { 52447c478bd9Sstevel@tonic-gate hdlp->ih_cb_func = pcmcia_mfc_intr; 52457c478bd9Sstevel@tonic-gate hdlp->ih_cb_arg1 = (caddr_t)sockp; 52467c478bd9Sstevel@tonic-gate hdlp->ih_cb_arg2 = NULL; 52477c478bd9Sstevel@tonic-gate 52487c478bd9Sstevel@tonic-gate ret = (*(DEVI(parent)->devi_ops->devo_bus_ops-> 52497c478bd9Sstevel@tonic-gate bus_intr_op))(parent, rdip, DDI_INTROP_ENABLE, 52507c478bd9Sstevel@tonic-gate hdlp, NULL); 52517c478bd9Sstevel@tonic-gate 52527c478bd9Sstevel@tonic-gate if (ret == DDI_FAILURE) { 52537c478bd9Sstevel@tonic-gate sockp->ls_inthandlers = NULL; 52547c478bd9Sstevel@tonic-gate kmem_free(intr, sizeof (inthandler_t)); 52557c478bd9Sstevel@tonic-gate sockp->ls_error = BAD_IRQ; 52567c478bd9Sstevel@tonic-gate mutex_exit(&sockp->ls_ilock); 52577c478bd9Sstevel@tonic-gate return (ret); 52587c478bd9Sstevel@tonic-gate } 52597c478bd9Sstevel@tonic-gate } 52607c478bd9Sstevel@tonic-gate mutex_exit(&sockp->ls_ilock); 52617c478bd9Sstevel@tonic-gate hdlp->ih_vector = ispecp->intrspec_vec = sockp->ls_intr_vec; 52627c478bd9Sstevel@tonic-gate hdlp->ih_pri = sockp->ls_intr_pri; 5263abdbd06dSagiri sockp->ls_iblk = (ddi_iblock_cookie_t)(uintptr_t) 52647c478bd9Sstevel@tonic-gate sockp->ls_intr_pri; 52657c478bd9Sstevel@tonic-gate sockp->ls_idev.idev_vector = (ushort_t)hdlp->ih_vector; 52667c478bd9Sstevel@tonic-gate sockp->ls_idev.idev_priority = (ushort_t)sockp->ls_intr_pri; 52677c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 52687c478bd9Sstevel@tonic-gate } 52697c478bd9Sstevel@tonic-gate mutex_exit(&sockp->ls_ilock); 52707c478bd9Sstevel@tonic-gate 52717c478bd9Sstevel@tonic-gate if (adapt->pca_flags & PCA_RES_NEED_IRQ) { 52727c478bd9Sstevel@tonic-gate if (hdlp->ih_cb_func == pcmcia_mfc_intr) 52737c478bd9Sstevel@tonic-gate ispecp = (struct intrspec *)&sockp->ls_intrspec; 52747c478bd9Sstevel@tonic-gate 52757c478bd9Sstevel@tonic-gate /* XXX: remove it later as this is done in _add_isr as well */ 52767c478bd9Sstevel@tonic-gate ispecp->intrspec_vec = sockp->ls_intr_vec; 52777c478bd9Sstevel@tonic-gate ispecp->intrspec_pri = sockp->ls_intr_pri; 52787c478bd9Sstevel@tonic-gate 52797c478bd9Sstevel@tonic-gate /* Enable interrupts */ 52807c478bd9Sstevel@tonic-gate ret = (*(DEVI(parent)->devi_ops->devo_bus_ops->bus_intr_op))( 52817c478bd9Sstevel@tonic-gate parent, rdip, DDI_INTROP_ENABLE, hdlp, NULL); 52827c478bd9Sstevel@tonic-gate 5283abdbd06dSagiri sockp->ls_iblk = (ddi_iblock_cookie_t)(uintptr_t) 52847c478bd9Sstevel@tonic-gate sockp->ls_intr_pri; 52857c478bd9Sstevel@tonic-gate sockp->ls_idev.idev_vector = (ushort_t)sockp->ls_intr_vec; 52867c478bd9Sstevel@tonic-gate sockp->ls_idev.idev_priority = (ushort_t)sockp->ls_intr_pri; 52877c478bd9Sstevel@tonic-gate 52887c478bd9Sstevel@tonic-gate if (ret != DDI_SUCCESS) 52897c478bd9Sstevel@tonic-gate sockp->ls_error = BAD_IRQ; 52907c478bd9Sstevel@tonic-gate return (ret); 52917c478bd9Sstevel@tonic-gate } 52927c478bd9Sstevel@tonic-gate 52937c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 52947c478bd9Sstevel@tonic-gate if (pcmcia_debug) 52957c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia_intr_enable_isr; let adapter do it\n"); 52967c478bd9Sstevel@tonic-gate #endif /* PCMCIA_DEBUG */ 52977c478bd9Sstevel@tonic-gate 52987c478bd9Sstevel@tonic-gate handler.socket = sockp->ls_socket; 52997c478bd9Sstevel@tonic-gate handler.irq = irq; 53007c478bd9Sstevel@tonic-gate handler.handler = (f_tt *)hdlp->ih_cb_func; 53017c478bd9Sstevel@tonic-gate handler.arg1 = hdlp->ih_cb_arg1; 53027c478bd9Sstevel@tonic-gate handler.arg2 = hdlp->ih_cb_arg2; 53037c478bd9Sstevel@tonic-gate handler.handler_id = (uint32_t)(uintptr_t)rdip; 53047c478bd9Sstevel@tonic-gate if (ispecp->intrspec_func != NULL) 53057c478bd9Sstevel@tonic-gate ispecp->intrspec_func = hdlp->ih_cb_func; 53067c478bd9Sstevel@tonic-gate 53077c478bd9Sstevel@tonic-gate /* set default IPL then check for override */ 53087c478bd9Sstevel@tonic-gate ispecp->intrspec_pri = sockp->ls_intr_pri; 53097c478bd9Sstevel@tonic-gate 53107c478bd9Sstevel@tonic-gate if ((ret = SET_IRQ(sockp->ls_if, adapt->pca_dip, &handler)) != 53117c478bd9Sstevel@tonic-gate SUCCESS) { 53127c478bd9Sstevel@tonic-gate sockp->ls_error = ret; 53137c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 53147c478bd9Sstevel@tonic-gate } 53157c478bd9Sstevel@tonic-gate ispecp->intrspec_func = hdlp->ih_cb_func; 53167c478bd9Sstevel@tonic-gate if (!(sockp->ls_flags & PCS_COOKIES_VALID)) { 53177c478bd9Sstevel@tonic-gate sockp->ls_iblk = *handler.iblk_cookie; 53187c478bd9Sstevel@tonic-gate sockp->ls_idev = *handler.idev_cookie; 53197c478bd9Sstevel@tonic-gate sockp->ls_flags |= PCS_COOKIES_VALID; 53207c478bd9Sstevel@tonic-gate } 53217c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 53227c478bd9Sstevel@tonic-gate } 53237c478bd9Sstevel@tonic-gate 53247c478bd9Sstevel@tonic-gate /* ARGSUSED */ 53257c478bd9Sstevel@tonic-gate static void 53267c478bd9Sstevel@tonic-gate pcmcia_intr_remove_isr(dev_info_t *dip, dev_info_t *rdip, 53277c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp) 53287c478bd9Sstevel@tonic-gate { 53297c478bd9Sstevel@tonic-gate int done, remhandler = 0; 53307c478bd9Sstevel@tonic-gate inthandler_t *intr, *first; 53317c478bd9Sstevel@tonic-gate struct intrspec *ispecp; 53327c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t *sockp; 53337c478bd9Sstevel@tonic-gate 53347c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 53357c478bd9Sstevel@tonic-gate if (pcmcia_debug) 53367c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia_intr_remove_isr: " 53377c478bd9Sstevel@tonic-gate "dip=0x%p rdip=0x%p hdlp=0x%p\n", 53387c478bd9Sstevel@tonic-gate (void *)dip, (void *)rdip, (void *)hdlp); 53397c478bd9Sstevel@tonic-gate #endif /* PCMCIA_DEBUG */ 53407c478bd9Sstevel@tonic-gate 53417c478bd9Sstevel@tonic-gate ispecp = pcmcia_intr_get_ispec(rdip, hdlp->ih_inum, &sockp); 53427c478bd9Sstevel@tonic-gate ASSERT(ispecp); 53437c478bd9Sstevel@tonic-gate 53447c478bd9Sstevel@tonic-gate /* first handle the multifunction case since it is simple */ 53457c478bd9Sstevel@tonic-gate mutex_enter(&sockp->ls_ilock); 53467c478bd9Sstevel@tonic-gate if (sockp->ls_inthandlers != NULL && 53477a364d25Sschwartz ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp != 53487a364d25Sschwartz &sockp->ls_intrspec) { 53497c478bd9Sstevel@tonic-gate 53507c478bd9Sstevel@tonic-gate intr = sockp->ls_inthandlers; 53517c478bd9Sstevel@tonic-gate 53527c478bd9Sstevel@tonic-gate /* Check if there is only one handler left */ 53537c478bd9Sstevel@tonic-gate if ((intr->next == intr) && (intr->prev == intr)) { 53547c478bd9Sstevel@tonic-gate if (intr->handler_id == (uint32_t)(uintptr_t)rdip) { 53557c478bd9Sstevel@tonic-gate sockp->ls_inthandlers = NULL; 53567c478bd9Sstevel@tonic-gate remhandler++; 53577c478bd9Sstevel@tonic-gate kmem_free(intr, sizeof (inthandler_t)); 53587c478bd9Sstevel@tonic-gate } 53597c478bd9Sstevel@tonic-gate 53607c478bd9Sstevel@tonic-gate } else { 53617c478bd9Sstevel@tonic-gate for (done = 0, first = intr; !done; intr = intr->next) { 53627c478bd9Sstevel@tonic-gate if (intr->next == first) 53637c478bd9Sstevel@tonic-gate done++; 53647c478bd9Sstevel@tonic-gate if (intr->handler_id == 53657c478bd9Sstevel@tonic-gate (uint32_t)(uintptr_t)rdip) { 53667c478bd9Sstevel@tonic-gate done++; 53677c478bd9Sstevel@tonic-gate 53687c478bd9Sstevel@tonic-gate /* 53697c478bd9Sstevel@tonic-gate * If we're about to remove the handler 53707c478bd9Sstevel@tonic-gate * at the head of the list, make the 53717c478bd9Sstevel@tonic-gate * next handler in line the head. 53727c478bd9Sstevel@tonic-gate */ 53737c478bd9Sstevel@tonic-gate if (sockp->ls_inthandlers == intr) 53747c478bd9Sstevel@tonic-gate sockp->ls_inthandlers = intr->next; 53757c478bd9Sstevel@tonic-gate 53767c478bd9Sstevel@tonic-gate remque(intr); 53777c478bd9Sstevel@tonic-gate kmem_free(intr, sizeof (inthandler_t)); 53787c478bd9Sstevel@tonic-gate break; 53797c478bd9Sstevel@tonic-gate } /* handler_id */ 53807c478bd9Sstevel@tonic-gate } /* end of for */ 53817c478bd9Sstevel@tonic-gate } /* end of if intr->next */ 53827c478bd9Sstevel@tonic-gate 53837c478bd9Sstevel@tonic-gate if (!remhandler) { 53847c478bd9Sstevel@tonic-gate mutex_exit(&sockp->ls_ilock); 53857c478bd9Sstevel@tonic-gate return; 53867c478bd9Sstevel@tonic-gate } 53877c478bd9Sstevel@tonic-gate } 53887c478bd9Sstevel@tonic-gate mutex_exit(&sockp->ls_ilock); 53897c478bd9Sstevel@tonic-gate 53907c478bd9Sstevel@tonic-gate if (sockp->ls_adapter->pca_flags & PCA_RES_NEED_IRQ) { 53917c478bd9Sstevel@tonic-gate sockp->ls_intr_vec = 0; 53927c478bd9Sstevel@tonic-gate ispecp->intrspec_vec = 0; 53937c478bd9Sstevel@tonic-gate } 53947c478bd9Sstevel@tonic-gate } 53957c478bd9Sstevel@tonic-gate 53967c478bd9Sstevel@tonic-gate 53977c478bd9Sstevel@tonic-gate static void 53987c478bd9Sstevel@tonic-gate pcmcia_intr_disable_isr(dev_info_t *dip, dev_info_t *rdip, 53997c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp) 54007c478bd9Sstevel@tonic-gate { 54017c478bd9Sstevel@tonic-gate int socket, ret; 54027c478bd9Sstevel@tonic-gate dev_info_t *parent; 54037c478bd9Sstevel@tonic-gate struct intrspec *ispecp; 54047c478bd9Sstevel@tonic-gate clear_irq_handler_t handler; 54057c478bd9Sstevel@tonic-gate struct pcmcia_adapter *adapt; 54067c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t *sockp; 54077c478bd9Sstevel@tonic-gate struct pcmcia_parent_private *ppd; 54087a364d25Sschwartz ihdl_plat_t *ihdl_plat_datap = 54097a364d25Sschwartz (ihdl_plat_t *)hdlp->ih_private; 54107c478bd9Sstevel@tonic-gate 54117c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 54127c478bd9Sstevel@tonic-gate if (pcmcia_debug) 54137c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia_intr_disable_isr: " 54147c478bd9Sstevel@tonic-gate "dip=0x%p rdip=0x%p hdlp=0x%p\n", 54157c478bd9Sstevel@tonic-gate (void *)dip, (void *)rdip, (void *)hdlp); 54167c478bd9Sstevel@tonic-gate #endif /* PCMCIA_DEBUG */ 54177c478bd9Sstevel@tonic-gate 54187c478bd9Sstevel@tonic-gate ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(rdip); 54197c478bd9Sstevel@tonic-gate socket = ppd->ppd_socket; 54207c478bd9Sstevel@tonic-gate sockp = pcmcia_sockets[socket]; 54217c478bd9Sstevel@tonic-gate adapt = sockp->ls_adapter; 54227c478bd9Sstevel@tonic-gate ispecp = ppd->ppd_intrspec; 54237c478bd9Sstevel@tonic-gate ASSERT(ispecp); 54247c478bd9Sstevel@tonic-gate 54257c478bd9Sstevel@tonic-gate mutex_enter(&sockp->ls_ilock); 54267c478bd9Sstevel@tonic-gate if (sockp->ls_inthandlers != NULL && 54277a364d25Sschwartz ihdl_plat_datap->ip_ispecp != &sockp->ls_intrspec) { 54287c478bd9Sstevel@tonic-gate inthandler_t *intr = sockp->ls_inthandlers; 54297c478bd9Sstevel@tonic-gate 54307c478bd9Sstevel@tonic-gate /* Check if there is only one handler left */ 54317c478bd9Sstevel@tonic-gate if ((intr->next == intr) && (intr->prev == intr)) { 54327c478bd9Sstevel@tonic-gate if (intr->handler_id != (uint32_t)(uintptr_t)rdip) 54337c478bd9Sstevel@tonic-gate /* 54347c478bd9Sstevel@tonic-gate * need to get the dip that was 54357c478bd9Sstevel@tonic-gate * used to add the handler 54367c478bd9Sstevel@tonic-gate */ 54377c478bd9Sstevel@tonic-gate rdip = sockp->ls_mfintr_dip; 54387c478bd9Sstevel@tonic-gate ispecp = (struct intrspec *)&sockp->ls_intrspec; 54397c478bd9Sstevel@tonic-gate } else { 54407c478bd9Sstevel@tonic-gate /* Don't call cleanup if list still has members */ 54417c478bd9Sstevel@tonic-gate mutex_exit(&sockp->ls_ilock); 54427c478bd9Sstevel@tonic-gate return; 54437c478bd9Sstevel@tonic-gate } 54447c478bd9Sstevel@tonic-gate } 54457c478bd9Sstevel@tonic-gate mutex_exit(&sockp->ls_ilock); 54467c478bd9Sstevel@tonic-gate 54477a364d25Sschwartz if (ihdl_plat_datap->ip_ispecp == 54487c478bd9Sstevel@tonic-gate (struct intrspec *)&sockp->ls_intrspec) 54497a364d25Sschwartz ispecp = ihdl_plat_datap->ip_ispecp; 54507c478bd9Sstevel@tonic-gate 54517c478bd9Sstevel@tonic-gate if (adapt->pca_flags & PCA_RES_NEED_IRQ) { 54527c478bd9Sstevel@tonic-gate ret = ispecp->intrspec_vec; 54537c478bd9Sstevel@tonic-gate parent = ddi_root_node(); 54547c478bd9Sstevel@tonic-gate ret = (*(DEVI(parent)->devi_ops->devo_bus_ops->bus_intr_op))( 54557c478bd9Sstevel@tonic-gate parent, rdip, DDI_INTROP_DISABLE, hdlp, NULL); 54567c478bd9Sstevel@tonic-gate (void) pcmcia_return_intr(dip, hdlp->ih_vector); 54577c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 54587c478bd9Sstevel@tonic-gate if (pcmcia_debug) 54597c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia_intr_disable_isr: " 54607c478bd9Sstevel@tonic-gate "INTROP_DISABLE returned %x\n", ret); 54617c478bd9Sstevel@tonic-gate #endif /* PCMCIA_DEBUG */ 54627c478bd9Sstevel@tonic-gate } else { 54637c478bd9Sstevel@tonic-gate handler.socket = sockp->ls_socket; 54647c478bd9Sstevel@tonic-gate handler.handler_id = (uint32_t)(uintptr_t)rdip; 54657c478bd9Sstevel@tonic-gate handler.handler = (f_tt *)ispecp->intrspec_func; 54667c478bd9Sstevel@tonic-gate ret = CLEAR_IRQ(sockp->ls_if, dip, &handler); 54677c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 54687c478bd9Sstevel@tonic-gate if (pcmcia_debug) 54697c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia_intr_disable_isr: " 54707c478bd9Sstevel@tonic-gate "CLEAR_IRQ returned %x\n", ret); 54717c478bd9Sstevel@tonic-gate #endif /* PCMCIA_DEBUG */ 54727c478bd9Sstevel@tonic-gate } 54737c478bd9Sstevel@tonic-gate } 54747c478bd9Sstevel@tonic-gate 54757c478bd9Sstevel@tonic-gate /* Consolidated interrupt processing interface */ 54767c478bd9Sstevel@tonic-gate int 54777c478bd9Sstevel@tonic-gate pcmcia_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op, 54787c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, void *result) 54797c478bd9Sstevel@tonic-gate { 54807c478bd9Sstevel@tonic-gate struct intrspec *ispecp; 54817c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t *sockp; 54827c478bd9Sstevel@tonic-gate 54837c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 54847c478bd9Sstevel@tonic-gate if (pcmcia_debug) 54857c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia_intr_ops: " 54867c478bd9Sstevel@tonic-gate "dip=0x%p rdip=0x%p op=0x%x hdlp=0x%p\n", 54877c478bd9Sstevel@tonic-gate (void *)dip, (void *)rdip, intr_op, (void *)hdlp); 54887c478bd9Sstevel@tonic-gate #endif /* PCMCIA_DEBUG */ 54897c478bd9Sstevel@tonic-gate 54907c478bd9Sstevel@tonic-gate switch (intr_op) { 54917c478bd9Sstevel@tonic-gate case DDI_INTROP_SUPPORTED_TYPES: 54927c478bd9Sstevel@tonic-gate if (ddi_get_parent_data(rdip) == NULL) { 54937c478bd9Sstevel@tonic-gate *(int *)result = 0; 54947c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 54957c478bd9Sstevel@tonic-gate } 54967c478bd9Sstevel@tonic-gate *(int *)result = DDI_INTR_TYPE_FIXED; 54977c478bd9Sstevel@tonic-gate break; 54987c478bd9Sstevel@tonic-gate case DDI_INTROP_GETCAP: 5499a195726fSgovinda *(int *)result = DDI_INTR_FLAG_LEVEL; 55007c478bd9Sstevel@tonic-gate break; 55017c478bd9Sstevel@tonic-gate case DDI_INTROP_NINTRS: 55027c478bd9Sstevel@tonic-gate case DDI_INTROP_NAVAIL: 5503a54f81fbSanish if (i_ddi_get_intx_nintrs(rdip) == 0) { 55047c478bd9Sstevel@tonic-gate *(int *)result = 0; 55057c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 55067c478bd9Sstevel@tonic-gate } 55077c478bd9Sstevel@tonic-gate *(int *)result = 1; /* for PCMCIA there is only one intr */ 55087c478bd9Sstevel@tonic-gate break; 55097c478bd9Sstevel@tonic-gate case DDI_INTROP_ALLOC: 55107c478bd9Sstevel@tonic-gate if ((ispecp = pcmcia_intr_get_ispec(rdip, hdlp->ih_inum, 55117c478bd9Sstevel@tonic-gate &sockp)) == NULL) 55127c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 55137c478bd9Sstevel@tonic-gate *(int *)result = hdlp->ih_scratch1; 55147c478bd9Sstevel@tonic-gate break; 55157c478bd9Sstevel@tonic-gate case DDI_INTROP_FREE: 55167c478bd9Sstevel@tonic-gate break; 55177c478bd9Sstevel@tonic-gate case DDI_INTROP_GETPRI: 55187c478bd9Sstevel@tonic-gate ispecp = pcmcia_intr_get_ispec(rdip, hdlp->ih_inum, &sockp); 55197c478bd9Sstevel@tonic-gate if (ispecp == NULL) { 55207c478bd9Sstevel@tonic-gate *(int *)result = 0; 55217c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 55227c478bd9Sstevel@tonic-gate } 55237c478bd9Sstevel@tonic-gate 55247c478bd9Sstevel@tonic-gate *(int *)result = ispecp->intrspec_pri = sockp->ls_intr_pri; 55257c478bd9Sstevel@tonic-gate break; 55267c478bd9Sstevel@tonic-gate case DDI_INTROP_SETPRI: 55277c478bd9Sstevel@tonic-gate if (*(int *)result > LOCK_LEVEL) 55287c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 55297c478bd9Sstevel@tonic-gate ispecp = pcmcia_intr_get_ispec(rdip, hdlp->ih_inum, &sockp); 55307c478bd9Sstevel@tonic-gate ASSERT(ispecp); 55317c478bd9Sstevel@tonic-gate ispecp->intrspec_pri = sockp->ls_intr_pri = *(int *)result; 55327c478bd9Sstevel@tonic-gate break; 55337c478bd9Sstevel@tonic-gate case DDI_INTROP_ADDISR: 55347c478bd9Sstevel@tonic-gate if ((ispecp = pcmcia_intr_add_isr(dip, rdip, hdlp)) == NULL) 55357c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 55367a364d25Sschwartz ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispecp; 55377c478bd9Sstevel@tonic-gate break; 55387c478bd9Sstevel@tonic-gate case DDI_INTROP_REMISR: 55397c478bd9Sstevel@tonic-gate pcmcia_intr_remove_isr(dip, rdip, hdlp); 55407c478bd9Sstevel@tonic-gate break; 55417c478bd9Sstevel@tonic-gate case DDI_INTROP_ENABLE: 55427c478bd9Sstevel@tonic-gate if (pcmcia_intr_enable_isr(dip, rdip, hdlp) != DDI_SUCCESS) 55437c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 55447c478bd9Sstevel@tonic-gate break; 55457c478bd9Sstevel@tonic-gate case DDI_INTROP_DISABLE: 55467c478bd9Sstevel@tonic-gate pcmcia_intr_disable_isr(dip, rdip, hdlp); 55477c478bd9Sstevel@tonic-gate break; 55487c478bd9Sstevel@tonic-gate default: 55497c478bd9Sstevel@tonic-gate return (DDI_ENOTSUP); 55507c478bd9Sstevel@tonic-gate } 55517c478bd9Sstevel@tonic-gate 55527c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 55537c478bd9Sstevel@tonic-gate } 55547c478bd9Sstevel@tonic-gate #endif 5555