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 /* 22582c04d6Srui wang - Sun Microsystems - Beijing China * Copyright 2009 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 */ 30339b361b2SRichard 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) { 3185c066ec2SJerry Gilliam if (cs_deinit() != CS_SUCCESS) 3195c066ec2SJerry Gilliam cmn_err(CE_CONT, "pcmcia: _init cs_deinit error\n"); 3205c066ec2SJerry Gilliam 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 36589b43686SBayard Bell * attempt to load Card Services 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", 4085c066ec2SJerry Gilliam 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, 5143f068ebdSToomas Soome 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", 5245c066ec2SJerry Gilliam (void *)dip, (void *)rdip, ctlop, (void *)arg, 5255c066ec2SJerry Gilliam (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", 5385c066ec2SJerry Gilliam ddi_get_instance(rdip), 5395c066ec2SJerry Gilliam 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", 5425c066ec2SJerry Gilliam ddi_driver_name(rdip), 5435c066ec2SJerry Gilliam ddi_get_instance(rdip), 5445c066ec2SJerry Gilliam ddi_driver_name(dip), 5455c066ec2SJerry Gilliam ddi_get_name_addr(dip), 5465c066ec2SJerry Gilliam CS_GET_SOCKET_NUMBER( 5475c066ec2SJerry Gilliam ddi_getprop(DDI_DEV_T_NONE, rdip, 5485c066ec2SJerry Gilliam DDI_PROP_DONTPASS, 5495c066ec2SJerry Gilliam 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", 5625c066ec2SJerry Gilliam ddi_node_name(arg), ddi_get_instance(arg), 5635c066ec2SJerry Gilliam (void *)arg); 5647c478bd9Sstevel@tonic-gate if (DEVI(arg)->devi_binding_name != NULL) 5657c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "\tbinding_name=%s\n", 5665c066ec2SJerry Gilliam 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", 5695c066ec2SJerry Gilliam DEVI(arg)->devi_node_name); 5707c478bd9Sstevel@tonic-gate } 5717c478bd9Sstevel@tonic-gate #endif 5727c478bd9Sstevel@tonic-gate 5737c478bd9Sstevel@tonic-gate ppd = (struct pcmcia_parent_private *) 5745c066ec2SJerry Gilliam 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", 5955c066ec2SJerry Gilliam ddi_get_name((dev_info_t *)arg), 5965c066ec2SJerry Gilliam ddi_get_instance((dev_info_t *)arg), 5975c066ec2SJerry Gilliam 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," 6055c066ec2SJerry Gilliam " function=%x, active=%x, flags=%x\n", 6065c066ec2SJerry Gilliam ppd->ppd_nreg, ppd->ppd_intr, 6075c066ec2SJerry Gilliam ppd->ppd_socket, ppd->ppd_function, 6085c066ec2SJerry Gilliam 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] " 6295c066ec2SJerry Gilliam "nodeid: %x @%s\n", 6305c066ec2SJerry Gilliam ddi_get_name(arg), ddi_get_name_addr(arg), 6315c066ec2SJerry Gilliam 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", 6435c066ec2SJerry Gilliam ddi_node_name(arg), ddi_get_instance(arg), 6445c066ec2SJerry Gilliam (void *)arg); 6457c478bd9Sstevel@tonic-gate if (DEVI(arg)->devi_binding_name != NULL) 6467c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "\tbinding_name=%s\n", 6475c066ec2SJerry Gilliam 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", 6505c066ec2SJerry Gilliam 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 *) 6615c066ec2SJerry Gilliam 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 *) 6725c066ec2SJerry Gilliam 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 *) 6815c066ec2SJerry Gilliam 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 *) 6905c066ec2SJerry Gilliam 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", 7125c066ec2SJerry Gilliam pm->request_type, 7135c066ec2SJerry Gilliam (void *)pm->req.set_power_req.who, 7145c066ec2SJerry Gilliam pm->req.set_power_req.cmpt, 7155c066ec2SJerry Gilliam pm->req.set_power_req.level, 7165c066ec2SJerry Gilliam 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, 7385c066ec2SJerry Gilliam pm->req.set_power_req.cmpt, 7395c066ec2SJerry Gilliam 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; 853*2990a173SToomas Soome if ((ppd->ppd_flags & PPD_CARD_CARDBUS) == 0) 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, 9563f068ebdSToomas Soome 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 *) 9825c066ec2SJerry Gilliam pcmcia_rnum_to_regspec(rdip, mp->map_obj.rnumber); 9837c478bd9Sstevel@tonic-gate mregs = (struct pcm_regs *) 9845c066ec2SJerry Gilliam 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, 10915c066ec2SJerry Gilliam "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, 11045c066ec2SJerry Gilliam "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 : 11125c066ec2SJerry Gilliam 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??? */ 11475c066ec2SJerry Gilliam pcmcia_adapters[i]->pca_module = ddi_driver_major(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]-> 11555c066ec2SJerry Gilliam 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 | 11665c066ec2SJerry Gilliam 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 */ 11895c066ec2SJerry Gilliam pcmcia_adapters[i]->pca_power = conf.power_entry; 11905c066ec2SJerry Gilliam pcmcia_adapters[i]->pca_numpower = conf.NumPower; 11917c478bd9Sstevel@tonic-gate 11927c478bd9Sstevel@tonic-gate for (n = 0; n < conf.NumPower; n++) 11937c478bd9Sstevel@tonic-gate pcmcia_merge_power(&conf.power_entry[n]); 11947c478bd9Sstevel@tonic-gate 11957c478bd9Sstevel@tonic-gate /* now setup the per socket info */ 11967c478bd9Sstevel@tonic-gate for (sock = 0; sock < conf.NumSockets; 11977c478bd9Sstevel@tonic-gate sock++) { 11987c478bd9Sstevel@tonic-gate dev_info_t *sockdrv = NULL; 11997c478bd9Sstevel@tonic-gate sockdrv = pcmcia_number_socket(dip, sock); 12007c478bd9Sstevel@tonic-gate if (sockdrv == NULL) 12017c478bd9Sstevel@tonic-gate n = sock + pcmcia_num_sockets; 12027c478bd9Sstevel@tonic-gate else { 12037c478bd9Sstevel@tonic-gate n = ddi_get_instance(sockdrv); 12047c478bd9Sstevel@tonic-gate } 12057c478bd9Sstevel@tonic-gate /* make sure we know first socket on adapter */ 12067c478bd9Sstevel@tonic-gate if (pcmcia_adapters[i]->pca_first_socket == -1) 12077c478bd9Sstevel@tonic-gate pcmcia_adapters[i]->pca_first_socket = n; 12087c478bd9Sstevel@tonic-gate 12097c478bd9Sstevel@tonic-gate /* 12107c478bd9Sstevel@tonic-gate * the number of sockets is weird. 12117c478bd9Sstevel@tonic-gate * we might have only two sockets but 12127c478bd9Sstevel@tonic-gate * due to persistence of instances we 12137c478bd9Sstevel@tonic-gate * will need to call them something other 12147c478bd9Sstevel@tonic-gate * than 0 and 1. So, we use the largest 12157c478bd9Sstevel@tonic-gate * instance number as the number and 12167c478bd9Sstevel@tonic-gate * have some that just don't get used. 12177c478bd9Sstevel@tonic-gate */ 12187c478bd9Sstevel@tonic-gate if (n >= pcmcia_num_sockets) 12197c478bd9Sstevel@tonic-gate pcmcia_num_sockets = n + 1; 12207c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 12217c478bd9Sstevel@tonic-gate if (pcmcia_debug) { 12227c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 12235c066ec2SJerry Gilliam "pcmcia_init: new socket added %d " 12245c066ec2SJerry Gilliam "(%d)\n", 12255c066ec2SJerry Gilliam n, pcmcia_num_sockets); 12267c478bd9Sstevel@tonic-gate } 12277c478bd9Sstevel@tonic-gate #endif 12287c478bd9Sstevel@tonic-gate 12297c478bd9Sstevel@tonic-gate pcmcia_sockets[n] = 12305c066ec2SJerry Gilliam kmem_zalloc(sizeof (pcmcia_logical_socket_t), 12315c066ec2SJerry Gilliam KM_SLEEP); 12327c478bd9Sstevel@tonic-gate pcmcia_sockets[n]->ls_socket = sock; 12337c478bd9Sstevel@tonic-gate pcmcia_sockets[n]->ls_if = ls_if; 12347c478bd9Sstevel@tonic-gate pcmcia_sockets[n]->ls_adapter = 12355c066ec2SJerry Gilliam pcmcia_adapters[i]; 12367c478bd9Sstevel@tonic-gate pcmcia_sockets[n]->ls_cs_events = 0L; 12377c478bd9Sstevel@tonic-gate pcmcia_sockets[n]->ls_sockdrv = sockdrv; 12387c478bd9Sstevel@tonic-gate /* Prototype of intrspec */ 12395c066ec2SJerry Gilliam pcmcia_sockets[n]->ls_intr_pri = adapter->an_ipl; 12407c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 12417c478bd9Sstevel@tonic-gate if (pcmcia_debug) 12427c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 12435c066ec2SJerry Gilliam "phys sock %d, log sock %d\n", 12445c066ec2SJerry Gilliam sock, n); 12457c478bd9Sstevel@tonic-gate #endif 12467c478bd9Sstevel@tonic-gate mutex_init(&pcmcia_sockets[n]->ls_ilock, NULL, 12475c066ec2SJerry Gilliam MUTEX_DRIVER, *adapter->an_iblock); 12487c478bd9Sstevel@tonic-gate } 12497c478bd9Sstevel@tonic-gate 12507c478bd9Sstevel@tonic-gate pcmcia_adapters[i]->pca_numsockets = conf.NumSockets; 12517c478bd9Sstevel@tonic-gate /* now setup the per window information */ 12527c478bd9Sstevel@tonic-gate for (win = 0; win < conf.NumWindows; win++) { 12537c478bd9Sstevel@tonic-gate n = win + pcmcia_num_windows; 12547c478bd9Sstevel@tonic-gate pcmcia_windows[n] = 12555c066ec2SJerry Gilliam kmem_zalloc(sizeof (pcmcia_logical_window_t), 12565c066ec2SJerry Gilliam KM_SLEEP); 12577c478bd9Sstevel@tonic-gate pcmcia_windows[n]->lw_window = win; 12587c478bd9Sstevel@tonic-gate pcmcia_windows[n]->lw_if = ls_if; 12597c478bd9Sstevel@tonic-gate pcmcia_windows[n]->lw_adapter = 12605c066ec2SJerry Gilliam pcmcia_adapters[i]; 12617c478bd9Sstevel@tonic-gate } 12627c478bd9Sstevel@tonic-gate pcmcia_num_windows += conf.NumWindows; 12637c478bd9Sstevel@tonic-gate SET_CALLBACK(ls_if, dip, 12647c478bd9Sstevel@tonic-gate pcm_adapter_callback, i); 12657c478bd9Sstevel@tonic-gate 12667c478bd9Sstevel@tonic-gate /* now tell CS about each socket */ 12677c478bd9Sstevel@tonic-gate for (sock = 0; sock < pcmcia_num_sockets; sock++) { 12687c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 12697c478bd9Sstevel@tonic-gate if (pcmcia_debug) { 12707c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 12715c066ec2SJerry Gilliam "pcmcia_init: notify CS socket %d " 12725c066ec2SJerry Gilliam "sockp=%p\n", 12735c066ec2SJerry Gilliam sock, (void *)pcmcia_sockets[sock]); 12747c478bd9Sstevel@tonic-gate } 12757c478bd9Sstevel@tonic-gate #endif 12767c478bd9Sstevel@tonic-gate if (pcmcia_sockets[sock] == NULL || 12777c478bd9Sstevel@tonic-gate (pcmcia_sockets[sock]->ls_flags & 12785c066ec2SJerry Gilliam PCS_SOCKET_ADDED)) { 12797c478bd9Sstevel@tonic-gate /* skip the ones that are done already */ 12807c478bd9Sstevel@tonic-gate continue; 12817c478bd9Sstevel@tonic-gate } 12827c478bd9Sstevel@tonic-gate pcmcia_sockets[sock]->ls_flags |= PCS_SOCKET_ADDED; 12837c478bd9Sstevel@tonic-gate if (cs_event(PCE_ADD_SOCKET, sock, 0) != 12847c478bd9Sstevel@tonic-gate CS_SUCCESS) { 12857c478bd9Sstevel@tonic-gate /* flag socket as broken */ 12867c478bd9Sstevel@tonic-gate pcmcia_sockets[sock]->ls_flags = 0; 12877c478bd9Sstevel@tonic-gate } else { 12887c478bd9Sstevel@tonic-gate pcm_event_manager(PCE_ADD_SOCKET, 12897c478bd9Sstevel@tonic-gate sock, NULL); 12907c478bd9Sstevel@tonic-gate } 12917c478bd9Sstevel@tonic-gate } 12927c478bd9Sstevel@tonic-gate 12937c478bd9Sstevel@tonic-gate } 12947c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 12957c478bd9Sstevel@tonic-gate if (pcmcia_debug) { 12967c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "logical sockets:\n"); 12977c478bd9Sstevel@tonic-gate for (i = 0; i < pcmcia_num_sockets; i++) { 12987c478bd9Sstevel@tonic-gate if (pcmcia_sockets[i] == NULL) 12997c478bd9Sstevel@tonic-gate continue; 13007c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 13015c066ec2SJerry Gilliam "\t%d: phys sock=%d, if=%p, adapt=%p\n", 13025c066ec2SJerry Gilliam i, pcmcia_sockets[i]->ls_socket, 13035c066ec2SJerry Gilliam (void *)pcmcia_sockets[i]->ls_if, 13045c066ec2SJerry Gilliam (void *)pcmcia_sockets[i]->ls_adapter); 13057c478bd9Sstevel@tonic-gate } 13067c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "logical windows:\n"); 13077c478bd9Sstevel@tonic-gate for (i = 0; i < pcmcia_num_windows; i++) { 13087c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 13095c066ec2SJerry Gilliam "\t%d: phys_window=%d, if=%p, adapt=%p\n", 13105c066ec2SJerry Gilliam i, pcmcia_windows[i]->lw_window, 13115c066ec2SJerry Gilliam (void *)pcmcia_windows[i]->lw_if, 13125c066ec2SJerry Gilliam (void *)pcmcia_windows[i]->lw_adapter); 13137c478bd9Sstevel@tonic-gate } 13147c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "\tpcmcia_num_power=%d\n", pcmcia_num_power); 13157c478bd9Sstevel@tonic-gate for (n = 0; n < pcmcia_num_power; n++) 13167c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 13175c066ec2SJerry Gilliam "\t\tPowerLevel: %d\tValidSignals: %x\n", 13185c066ec2SJerry Gilliam pcmcia_power_table[n].PowerLevel, 13195c066ec2SJerry Gilliam pcmcia_power_table[n].ValidSignals); 13207c478bd9Sstevel@tonic-gate } 13217c478bd9Sstevel@tonic-gate #endif 13227c478bd9Sstevel@tonic-gate } 13237c478bd9Sstevel@tonic-gate 13247c478bd9Sstevel@tonic-gate /* 13257c478bd9Sstevel@tonic-gate * pcmcia_find_cards() 13267c478bd9Sstevel@tonic-gate * check the adapter to see if there are cards present at 13277c478bd9Sstevel@tonic-gate * driver attach time. If there are, generate an artificial 13287c478bd9Sstevel@tonic-gate * card insertion event to get CS running and the PC Card ultimately 13297c478bd9Sstevel@tonic-gate * identified. 13307c478bd9Sstevel@tonic-gate */ 13317c478bd9Sstevel@tonic-gate void 13327c478bd9Sstevel@tonic-gate pcmcia_find_cards(anp_t *adapt) 13337c478bd9Sstevel@tonic-gate { 13347c478bd9Sstevel@tonic-gate int i; 13357c478bd9Sstevel@tonic-gate get_ss_status_t status; 13367c478bd9Sstevel@tonic-gate for (i = 0; i < pcmcia_num_sockets; i++) { 13377c478bd9Sstevel@tonic-gate if (pcmcia_sockets[i] && 13387c478bd9Sstevel@tonic-gate pcmcia_sockets[i]->ls_if == adapt->an_if) { 13397c478bd9Sstevel@tonic-gate /* check the status */ 13407c478bd9Sstevel@tonic-gate status.socket = i; 13417c478bd9Sstevel@tonic-gate if (SSGetStatus(&status) == SUCCESS && 1342a9fb0ae8Srw status.IFType != IF_CARDBUS && 13437c478bd9Sstevel@tonic-gate status.CardState & SBM_CD && 13447c478bd9Sstevel@tonic-gate pcmcia_sockets[i]->ls_dip[0] == NULL) { 13457c478bd9Sstevel@tonic-gate (void) cs_event(PCE_CARD_INSERT, i, 0); 13467c478bd9Sstevel@tonic-gate delay(1); 13477c478bd9Sstevel@tonic-gate } 13487c478bd9Sstevel@tonic-gate } 13497c478bd9Sstevel@tonic-gate } 13507c478bd9Sstevel@tonic-gate } 13517c478bd9Sstevel@tonic-gate 13527c478bd9Sstevel@tonic-gate /* 13537c478bd9Sstevel@tonic-gate * pcmcia_number_socket(dip, adapt) 13547c478bd9Sstevel@tonic-gate * we determine socket number by creating a driver for each 13557c478bd9Sstevel@tonic-gate * socket on the adapter and then forcing it to attach. This 13567c478bd9Sstevel@tonic-gate * results in an instance being assigned which becomes the 13577c478bd9Sstevel@tonic-gate * logical socket number. If it fails, then we are the first 13587c478bd9Sstevel@tonic-gate * set of sockets and renumbering occurs later. We do this 13597c478bd9Sstevel@tonic-gate * one socket at a time and return the dev_info_t so the 13607c478bd9Sstevel@tonic-gate * instance number can be used. 13617c478bd9Sstevel@tonic-gate */ 13627c478bd9Sstevel@tonic-gate dev_info_t * 13637c478bd9Sstevel@tonic-gate pcmcia_number_socket(dev_info_t *dip, int localsocket) 13647c478bd9Sstevel@tonic-gate { 13657c478bd9Sstevel@tonic-gate dev_info_t *child = NULL; 13667c478bd9Sstevel@tonic-gate struct pcmcia_parent_private *ppd; 13677c478bd9Sstevel@tonic-gate 1368fa9e4066Sahrens if (ndi_devi_alloc(dip, "pcs", (pnode_t)DEVI_SID_NODEID, 13697c478bd9Sstevel@tonic-gate &child) == NDI_SUCCESS) { 13707c478bd9Sstevel@tonic-gate ppd = kmem_zalloc(sizeof (struct pcmcia_parent_private), 13717c478bd9Sstevel@tonic-gate KM_SLEEP); 13727c478bd9Sstevel@tonic-gate ppd->ppd_reg = kmem_zalloc(sizeof (struct pcm_regs), KM_SLEEP); 13737c478bd9Sstevel@tonic-gate ppd->ppd_nreg = 1; 13747c478bd9Sstevel@tonic-gate ppd->ppd_reg[0].phys_hi = localsocket; 13757c478bd9Sstevel@tonic-gate ddi_set_parent_data(child, (caddr_t)ppd); 13767c478bd9Sstevel@tonic-gate if (ndi_devi_online(child, 0) != NDI_SUCCESS) { 1377981012acSrw kmem_free(ppd->ppd_reg, sizeof (struct pcm_regs)); 1378981012acSrw kmem_free(ppd, sizeof (struct pcmcia_parent_private)); 13797c478bd9Sstevel@tonic-gate (void) ndi_devi_free(child); 13807c478bd9Sstevel@tonic-gate child = NULL; 13817c478bd9Sstevel@tonic-gate } 13827c478bd9Sstevel@tonic-gate } 13837c478bd9Sstevel@tonic-gate return (child); 13847c478bd9Sstevel@tonic-gate } 13857c478bd9Sstevel@tonic-gate 13867c478bd9Sstevel@tonic-gate /* 13877c478bd9Sstevel@tonic-gate * pcm_phys_to_log_socket() 13887c478bd9Sstevel@tonic-gate * from an adapter and socket number return the logical socket 13897c478bd9Sstevel@tonic-gate */ 13907c478bd9Sstevel@tonic-gate int 13917c478bd9Sstevel@tonic-gate pcm_phys_to_log_socket(struct pcmcia_adapter *adapt, int socket) 13927c478bd9Sstevel@tonic-gate { 13937c478bd9Sstevel@tonic-gate register pcmcia_logical_socket_t *sockp; 13947c478bd9Sstevel@tonic-gate int i; 13957c478bd9Sstevel@tonic-gate 13967c478bd9Sstevel@tonic-gate for (i = 0, sockp = pcmcia_sockets[0]; 13975c066ec2SJerry Gilliam i < pcmcia_num_sockets; i++, sockp = pcmcia_sockets[i]) { 13987c478bd9Sstevel@tonic-gate if (sockp == NULL) 13997c478bd9Sstevel@tonic-gate continue; 14007c478bd9Sstevel@tonic-gate if (sockp->ls_socket == socket && sockp->ls_adapter == adapt) 14017c478bd9Sstevel@tonic-gate break; 14027c478bd9Sstevel@tonic-gate } 14037c478bd9Sstevel@tonic-gate if (i >= pcmcia_num_sockets) { 14047c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 14057c478bd9Sstevel@tonic-gate if (pcmcia_debug) 14067c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 14075c066ec2SJerry Gilliam "\tbad socket/adapter: %x/%p != %x/%x\n", 14085c066ec2SJerry Gilliam socket, (void *)adapt, pcmcia_num_sockets, 14095c066ec2SJerry Gilliam pcmcia_num_adapters); 14107c478bd9Sstevel@tonic-gate #endif 14117c478bd9Sstevel@tonic-gate return (-1); 14127c478bd9Sstevel@tonic-gate } 14137c478bd9Sstevel@tonic-gate 14147c478bd9Sstevel@tonic-gate return (i); /* want logical socket */ 14157c478bd9Sstevel@tonic-gate } 14167c478bd9Sstevel@tonic-gate 14177c478bd9Sstevel@tonic-gate /* 14187c478bd9Sstevel@tonic-gate * pcm_adapter_callback() 14197c478bd9Sstevel@tonic-gate * this function is called back by the adapter driver at interrupt time. 14207c478bd9Sstevel@tonic-gate * It is here that events should get generated for the event manager if it 14217c478bd9Sstevel@tonic-gate * is present. It would also be the time where a device information 14227c478bd9Sstevel@tonic-gate * tree could be constructed for a card that was added in if we 14237c478bd9Sstevel@tonic-gate * choose to create them dynamically. 14247c478bd9Sstevel@tonic-gate */ 14257c478bd9Sstevel@tonic-gate 14267c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 14277c478bd9Sstevel@tonic-gate char *cblist[] = { 14287c478bd9Sstevel@tonic-gate "removal", 14297c478bd9Sstevel@tonic-gate "insert", 14307c478bd9Sstevel@tonic-gate "ready", 14317c478bd9Sstevel@tonic-gate "battery-warn", 14327c478bd9Sstevel@tonic-gate "battery-dead", 14337c478bd9Sstevel@tonic-gate "status-change", 14347c478bd9Sstevel@tonic-gate "write-protect", "reset", "unlock", "client-info", "eject-complete", 14357c478bd9Sstevel@tonic-gate "eject-request", "erase-complete", "exclusive-complete", 14367c478bd9Sstevel@tonic-gate "exclusive-request", "insert-complete", "insert-request", 14377c478bd9Sstevel@tonic-gate "reset-complete", "reset-request", "timer-expired", 14387c478bd9Sstevel@tonic-gate "resume", "suspend" 14397c478bd9Sstevel@tonic-gate }; 14407c478bd9Sstevel@tonic-gate #endif 14417c478bd9Sstevel@tonic-gate 14427c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 14437c478bd9Sstevel@tonic-gate static int 14447c478bd9Sstevel@tonic-gate pcm_adapter_callback(dev_info_t *dip, int adapter, int event, int socket) 14457c478bd9Sstevel@tonic-gate { 14467c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t *sockp; 14477c478bd9Sstevel@tonic-gate 14487c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 14497c478bd9Sstevel@tonic-gate if (pcmcia_debug) { 14507c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcm_adapter_callback: %p %x %x %x: ", 14515c066ec2SJerry Gilliam (void *)dip, adapter, event, socket); 14527c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "[%s]\n", cblist[event]); 14537c478bd9Sstevel@tonic-gate } 14547c478bd9Sstevel@tonic-gate #endif 14557c478bd9Sstevel@tonic-gate 14567c478bd9Sstevel@tonic-gate if (adapter >= pcmcia_num_adapters || adapter < 0) { 14577c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 14587c478bd9Sstevel@tonic-gate if (pcmcia_debug) 14597c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "\tbad adapter number: %d : %d\n", 14605c066ec2SJerry Gilliam adapter, pcmcia_num_adapters); 14617c478bd9Sstevel@tonic-gate #endif 14627c478bd9Sstevel@tonic-gate return (1); 14637c478bd9Sstevel@tonic-gate } 14647c478bd9Sstevel@tonic-gate 14657c478bd9Sstevel@tonic-gate /* get the logical socket since that is what CS knows */ 14667c478bd9Sstevel@tonic-gate socket = pcm_phys_to_log_socket(pcmcia_adapters[adapter], socket); 14677c478bd9Sstevel@tonic-gate if (socket == -1) { 14687c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pcmcia callback - bad logical socket\n"); 14697c478bd9Sstevel@tonic-gate return (0); 14707c478bd9Sstevel@tonic-gate } 14717c478bd9Sstevel@tonic-gate sockp = pcmcia_sockets[socket]; 14727c478bd9Sstevel@tonic-gate switch (event) { 14737c478bd9Sstevel@tonic-gate case -1: /* special case of adapter going away */ 14747c478bd9Sstevel@tonic-gate case PCE_CARD_INSERT: 14757c478bd9Sstevel@tonic-gate sockp->ls_cs_events |= PCE_E2M(PCE_CARD_INSERT) | 14765c066ec2SJerry Gilliam PCE_E2M(PCE_CARD_REMOVAL); 14777c478bd9Sstevel@tonic-gate break; 14787c478bd9Sstevel@tonic-gate case PCE_CARD_REMOVAL: 14797c478bd9Sstevel@tonic-gate /* disable interrupts at this point */ 14807c478bd9Sstevel@tonic-gate sockp->ls_cs_events |= PCE_E2M(PCE_CARD_INSERT) | 14815c066ec2SJerry Gilliam PCE_E2M(PCE_CARD_REMOVAL); 14827c478bd9Sstevel@tonic-gate /* remove children that never attached */ 14837c478bd9Sstevel@tonic-gate 14847c478bd9Sstevel@tonic-gate break; 14857c478bd9Sstevel@tonic-gate case PCE_PM_RESUME: 14867c478bd9Sstevel@tonic-gate pcmcia_do_resume(socket, sockp); 14877c478bd9Sstevel@tonic-gate /* event = PCE_CARD_INSERT; */ 14887c478bd9Sstevel@tonic-gate break; 14897c478bd9Sstevel@tonic-gate case PCE_PM_SUSPEND: 14907c478bd9Sstevel@tonic-gate pcmcia_do_suspend(socket, sockp); 14917c478bd9Sstevel@tonic-gate /* event = PCE_CARD_REMOVAL; */ 14927c478bd9Sstevel@tonic-gate break; 14937c478bd9Sstevel@tonic-gate default: 14947c478bd9Sstevel@tonic-gate /* nothing to do */ 14957c478bd9Sstevel@tonic-gate break; 14967c478bd9Sstevel@tonic-gate } 14977c478bd9Sstevel@tonic-gate 14987c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 14997c478bd9Sstevel@tonic-gate if (pcmcia_debug) { 15007c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 15015c066ec2SJerry Gilliam "\tevent %d, event mask=%x, match=%x (log socket=%d)\n", 15025c066ec2SJerry Gilliam event, 15035c066ec2SJerry Gilliam (int)sockp->ls_cs_events, 15045c066ec2SJerry Gilliam (int)(sockp->ls_cs_events & PCE_E2M(event)), socket); 15057c478bd9Sstevel@tonic-gate } 15067c478bd9Sstevel@tonic-gate #endif 15077c478bd9Sstevel@tonic-gate 15087c478bd9Sstevel@tonic-gate if (pcmcia_cs_event && sockp->ls_cs_events & (1 << event)) { 15097c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 15107c478bd9Sstevel@tonic-gate if (pcmcia_debug) 15117c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "\tcalling CS event handler (%p) " 15125c066ec2SJerry Gilliam "with event=%d\n", 15135c066ec2SJerry Gilliam (void *)pcmcia_cs_event, event); 15147c478bd9Sstevel@tonic-gate #endif 15157c478bd9Sstevel@tonic-gate CS_EVENT(event, socket, 0); 15167c478bd9Sstevel@tonic-gate } 15177c478bd9Sstevel@tonic-gate 15187c478bd9Sstevel@tonic-gate /* let the event manager(s) know about the event */ 15197c478bd9Sstevel@tonic-gate pcm_event_manager(event, socket, NULL); 15207c478bd9Sstevel@tonic-gate 15217c478bd9Sstevel@tonic-gate return (0); 15227c478bd9Sstevel@tonic-gate } 15237c478bd9Sstevel@tonic-gate 15247c478bd9Sstevel@tonic-gate /* 15257c478bd9Sstevel@tonic-gate * pcm_event_manager() 15267c478bd9Sstevel@tonic-gate * checks for registered management driver callback handlers 15277c478bd9Sstevel@tonic-gate * if there are any, call them if the event warrants it 15287c478bd9Sstevel@tonic-gate */ 15297c478bd9Sstevel@tonic-gate void 15307c478bd9Sstevel@tonic-gate pcm_event_manager(int event, int socket, void *arg) 15317c478bd9Sstevel@tonic-gate { 15327c478bd9Sstevel@tonic-gate struct pcmcia_mif *mif; 15337c478bd9Sstevel@tonic-gate 15347c478bd9Sstevel@tonic-gate for (mif = pcmcia_mif_handlers; mif != NULL; mif = mif->mif_next) { 15357c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 15367c478bd9Sstevel@tonic-gate if (pcmcia_debug) 15377c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 15385c066ec2SJerry Gilliam "pcm_event_manager: event=%d, mif_events=%x" 15395c066ec2SJerry Gilliam " (tst:%d)\n", 15405c066ec2SJerry Gilliam event, (int)*(uint32_t *)mif->mif_events, 15415c066ec2SJerry Gilliam PR_GET(mif->mif_events, event)); 15427c478bd9Sstevel@tonic-gate #endif 15437c478bd9Sstevel@tonic-gate if (PR_GET(mif->mif_events, event)) { 15447c478bd9Sstevel@tonic-gate mif->mif_function(mif->mif_id, event, socket, arg); 15457c478bd9Sstevel@tonic-gate } 15467c478bd9Sstevel@tonic-gate } 15477c478bd9Sstevel@tonic-gate 15487c478bd9Sstevel@tonic-gate } 15497c478bd9Sstevel@tonic-gate 15507c478bd9Sstevel@tonic-gate /* 15517c478bd9Sstevel@tonic-gate * pcm_search_devinfo(dev_info_t *, pcm_device_info *, int) 15527c478bd9Sstevel@tonic-gate * search for an immediate child node to the nexus and not siblings of nexus 15537c478bd9Sstevel@tonic-gate * and not grandchildren. We follow the same sequence that name binding 15547c478bd9Sstevel@tonic-gate * follows so we match same class of device (modem == modem) and don't 15557c478bd9Sstevel@tonic-gate * have to depend on features that might not exist. 15567c478bd9Sstevel@tonic-gate */ 15577c478bd9Sstevel@tonic-gate dev_info_t * 15587c478bd9Sstevel@tonic-gate pcm_search_devinfo(dev_info_t *self, struct pcm_device_info *info, int socket) 15597c478bd9Sstevel@tonic-gate { 15607c478bd9Sstevel@tonic-gate char bf[256]; 15617c478bd9Sstevel@tonic-gate struct pcmcia_parent_private *ppd; 15627c478bd9Sstevel@tonic-gate dev_info_t *dip; 1563b9ccdc5aScth int circ; 15647c478bd9Sstevel@tonic-gate 15657c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 15667c478bd9Sstevel@tonic-gate if (pcmcia_debug) 15677c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 15687c478bd9Sstevel@tonic-gate "pcm_search_devinfo: socket=%x [%s|%s|%s] pd_flags=%x\n", 15697c478bd9Sstevel@tonic-gate socket, info->pd_bind_name, info->pd_generic_name, 15707c478bd9Sstevel@tonic-gate info->pd_vers1_name, info->pd_flags); 15717c478bd9Sstevel@tonic-gate #endif 15727c478bd9Sstevel@tonic-gate 1573b9ccdc5aScth ndi_devi_enter(self, &circ); 15747c478bd9Sstevel@tonic-gate /* do searches in compatible property order */ 15757c478bd9Sstevel@tonic-gate for (dip = (dev_info_t *)DEVI(self)->devi_child; 15767c478bd9Sstevel@tonic-gate dip != NULL; 15777c478bd9Sstevel@tonic-gate dip = (dev_info_t *)DEVI(dip)->devi_sibling) { 15787c478bd9Sstevel@tonic-gate int ppd_socket; 15797c478bd9Sstevel@tonic-gate ppd = (struct pcmcia_parent_private *) 15805c066ec2SJerry Gilliam ddi_get_parent_data(dip); 15817c478bd9Sstevel@tonic-gate if (ppd == NULL) { 15827c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 15837c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "No parent private data\n"); 15847c478bd9Sstevel@tonic-gate #endif 15857c478bd9Sstevel@tonic-gate continue; 15867c478bd9Sstevel@tonic-gate } 15877c478bd9Sstevel@tonic-gate ppd_socket = CS_MAKE_SOCKET_NUMBER(ppd->ppd_socket, 15887c478bd9Sstevel@tonic-gate ppd->ppd_function); 15897c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 15907c478bd9Sstevel@tonic-gate if (pcmcia_debug) { 15917c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "\tbind=[%s], node=[%s]\n", 15925c066ec2SJerry Gilliam DEVI(dip)->devi_binding_name, 15935c066ec2SJerry Gilliam DEVI(dip)->devi_node_name); 15947c478bd9Sstevel@tonic-gate } 15957c478bd9Sstevel@tonic-gate #endif 15967c478bd9Sstevel@tonic-gate if (info->pd_flags & PCM_NAME_VERS1) { 15977c478bd9Sstevel@tonic-gate (void) strcpy(bf, info->pd_vers1_name); 15987c478bd9Sstevel@tonic-gate pcmcia_fix_string(bf); 15997c478bd9Sstevel@tonic-gate if (DEVI(dip)->devi_binding_name && 16007c478bd9Sstevel@tonic-gate strcmp(DEVI(dip)->devi_binding_name, bf) == 0 && 16017c478bd9Sstevel@tonic-gate socket == ppd_socket) 16027c478bd9Sstevel@tonic-gate break; 16037c478bd9Sstevel@tonic-gate } 16047c478bd9Sstevel@tonic-gate if ((info->pd_flags & (PCM_NAME_1275 | PCM_MULTI_FUNCTION)) == 16057c478bd9Sstevel@tonic-gate (PCM_NAME_1275 | PCM_MULTI_FUNCTION)) { 16067c478bd9Sstevel@tonic-gate (void) sprintf(bf, "%s,%x", info->pd_bind_name, 16075c066ec2SJerry Gilliam info->pd_function); 16087c478bd9Sstevel@tonic-gate if (strcmp(bf, DEVI(dip)->devi_binding_name) == 0 && 16097c478bd9Sstevel@tonic-gate socket == ppd->ppd_socket) 16107c478bd9Sstevel@tonic-gate break; 16117c478bd9Sstevel@tonic-gate } 16127c478bd9Sstevel@tonic-gate if (info->pd_flags & PCM_NAME_1275) { 16137c478bd9Sstevel@tonic-gate if (DEVI(dip)->devi_binding_name && 16147c478bd9Sstevel@tonic-gate strcmp(DEVI(dip)->devi_binding_name, 16155c066ec2SJerry Gilliam info->pd_bind_name) == 0 && 16167c478bd9Sstevel@tonic-gate socket == ppd_socket) 16177c478bd9Sstevel@tonic-gate break; 16187c478bd9Sstevel@tonic-gate } 16197c478bd9Sstevel@tonic-gate if (info->pd_flags & PCM_NAME_GENERIC) { 16207c478bd9Sstevel@tonic-gate (void) sprintf(bf, "%s,%s", PCMDEV_NAMEPREF, 16215c066ec2SJerry Gilliam info->pd_generic_name); 16227c478bd9Sstevel@tonic-gate if (DEVI(dip)->devi_binding_name && 16237c478bd9Sstevel@tonic-gate strcmp(DEVI(dip)->devi_binding_name, bf) == 0 && 16247c478bd9Sstevel@tonic-gate socket == ppd_socket) 16257c478bd9Sstevel@tonic-gate break; 16267c478bd9Sstevel@tonic-gate } 16277c478bd9Sstevel@tonic-gate if (info->pd_flags & PCM_NAME_GENERIC) { 16287c478bd9Sstevel@tonic-gate if (DEVI(dip)->devi_binding_name && 16297c478bd9Sstevel@tonic-gate strcmp(DEVI(dip)->devi_binding_name, 16305c066ec2SJerry Gilliam info->pd_generic_name) == 0 && 16317c478bd9Sstevel@tonic-gate socket == ppd_socket) 16327c478bd9Sstevel@tonic-gate break; 16337c478bd9Sstevel@tonic-gate } 16347c478bd9Sstevel@tonic-gate if (info->pd_flags & PCM_NO_CONFIG) { 16357c478bd9Sstevel@tonic-gate if (DEVI(dip)->devi_binding_name && 16367c478bd9Sstevel@tonic-gate strcmp(DEVI(dip)->devi_binding_name, 16375c066ec2SJerry Gilliam "pccard,memory") == 0 && 16387c478bd9Sstevel@tonic-gate socket == ppd_socket) 16397c478bd9Sstevel@tonic-gate break; 16407c478bd9Sstevel@tonic-gate } 16417c478bd9Sstevel@tonic-gate } 1642b9ccdc5aScth ndi_devi_exit(self, circ); 16437c478bd9Sstevel@tonic-gate return (dip); 16447c478bd9Sstevel@tonic-gate } 16457c478bd9Sstevel@tonic-gate 16467c478bd9Sstevel@tonic-gate /* 16477c478bd9Sstevel@tonic-gate * pcm_find_devinfo() 16487c478bd9Sstevel@tonic-gate * this is a wrapper around DDI calls to "find" any 16497c478bd9Sstevel@tonic-gate * devinfo node and then from there find the one associated 16507c478bd9Sstevel@tonic-gate * with the socket 16517c478bd9Sstevel@tonic-gate */ 16527c478bd9Sstevel@tonic-gate dev_info_t * 16537c478bd9Sstevel@tonic-gate pcm_find_devinfo(dev_info_t *pdip, struct pcm_device_info *info, int socket) 16547c478bd9Sstevel@tonic-gate { 16557c478bd9Sstevel@tonic-gate dev_info_t *dip; 16567c478bd9Sstevel@tonic-gate 16577c478bd9Sstevel@tonic-gate dip = pcm_search_devinfo(pdip, info, socket); 16587c478bd9Sstevel@tonic-gate if (dip == NULL) 16597c478bd9Sstevel@tonic-gate return (NULL); 16607c478bd9Sstevel@tonic-gate /* 16617c478bd9Sstevel@tonic-gate * we have at least a base level dip 16627c478bd9Sstevel@tonic-gate * see if there is one (this or a sibling) 16637c478bd9Sstevel@tonic-gate * that has the correct socket number 16647c478bd9Sstevel@tonic-gate * if there is, return that one else 16657c478bd9Sstevel@tonic-gate * NULL so a new one is created 16667c478bd9Sstevel@tonic-gate */ 16677c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 16687c478bd9Sstevel@tonic-gate if (pcmcia_debug) 16697c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "find: initial dip = %p, socket=%d, name=%s " 16705c066ec2SJerry Gilliam "(instance=%d, socket=%d, name=%s)\n", 16715c066ec2SJerry Gilliam (void *)dip, socket, info->pd_bind_name, 16725c066ec2SJerry Gilliam ddi_get_instance(dip), 16735c066ec2SJerry Gilliam ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 16745c066ec2SJerry Gilliam PCM_DEV_SOCKET, -1), 16755c066ec2SJerry Gilliam ddi_get_name(dip)); 16767c478bd9Sstevel@tonic-gate #endif 16777c478bd9Sstevel@tonic-gate 16787c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 16797c478bd9Sstevel@tonic-gate if (pcmcia_debug && dip != NULL) 16807c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "\treturning non-NULL dip (%s)\n", 16815c066ec2SJerry Gilliam ddi_get_name(dip)); 16827c478bd9Sstevel@tonic-gate #endif 16837c478bd9Sstevel@tonic-gate return (dip); 16847c478bd9Sstevel@tonic-gate } 16857c478bd9Sstevel@tonic-gate 16867c478bd9Sstevel@tonic-gate /* 16877c478bd9Sstevel@tonic-gate * pcm_find_parent_dip(socket) 16887c478bd9Sstevel@tonic-gate * find the correct parent dip for this logical socket 16897c478bd9Sstevel@tonic-gate */ 16907c478bd9Sstevel@tonic-gate dev_info_t * 16917c478bd9Sstevel@tonic-gate pcm_find_parent_dip(int socket) 16927c478bd9Sstevel@tonic-gate { 16937c478bd9Sstevel@tonic-gate if ((socket < 0 || socket >= pcmcia_num_sockets) || 16947c478bd9Sstevel@tonic-gate pcmcia_sockets[socket] == NULL) 16957c478bd9Sstevel@tonic-gate return (NULL); 16967c478bd9Sstevel@tonic-gate return (pcmcia_sockets[socket]->ls_adapter->pca_dip); 16977c478bd9Sstevel@tonic-gate } 16987c478bd9Sstevel@tonic-gate 16997c478bd9Sstevel@tonic-gate /* 17007c478bd9Sstevel@tonic-gate * pcmcia_set_em_handler() 17017c478bd9Sstevel@tonic-gate * This is called by the management and event driver to tell 17027c478bd9Sstevel@tonic-gate * the nexus what to call. Multiple drivers are allowed 17037c478bd9Sstevel@tonic-gate * but normally only one will exist. 17047c478bd9Sstevel@tonic-gate */ 17057c478bd9Sstevel@tonic-gate int 17067c478bd9Sstevel@tonic-gate pcmcia_set_em_handler(int (*handler)(), caddr_t events, int elen, 17073f068ebdSToomas Soome uint32_t id, void **cs, void **ss) 17087c478bd9Sstevel@tonic-gate { 17097c478bd9Sstevel@tonic-gate struct pcmcia_mif *mif, *tmp; 17107c478bd9Sstevel@tonic-gate 17117c478bd9Sstevel@tonic-gate if (handler == NULL) { 17127c478bd9Sstevel@tonic-gate /* NULL means remove the handler based on the ID */ 17137c478bd9Sstevel@tonic-gate if (pcmcia_mif_handlers == NULL) 17147c478bd9Sstevel@tonic-gate return (0); 17157c478bd9Sstevel@tonic-gate mutex_enter(&pcmcia_global_lock); 17167c478bd9Sstevel@tonic-gate if (pcmcia_mif_handlers->mif_id == id) { 17177c478bd9Sstevel@tonic-gate mif = pcmcia_mif_handlers; 17187c478bd9Sstevel@tonic-gate pcmcia_mif_handlers = mif->mif_next; 17197c478bd9Sstevel@tonic-gate kmem_free(mif, sizeof (struct pcmcia_mif)); 17207c478bd9Sstevel@tonic-gate } else { 17217c478bd9Sstevel@tonic-gate for (mif = pcmcia_mif_handlers; 17227c478bd9Sstevel@tonic-gate mif->mif_next != NULL && 17237c478bd9Sstevel@tonic-gate mif->mif_next->mif_id != id; 17247c478bd9Sstevel@tonic-gate mif = mif->mif_next) 17257c478bd9Sstevel@tonic-gate ; 17267c478bd9Sstevel@tonic-gate if (mif->mif_next != NULL && 17277c478bd9Sstevel@tonic-gate mif->mif_next->mif_id == id) { 17287c478bd9Sstevel@tonic-gate tmp = mif->mif_next; 17297c478bd9Sstevel@tonic-gate mif->mif_next = tmp->mif_next; 17307c478bd9Sstevel@tonic-gate kmem_free(tmp, sizeof (struct pcmcia_mif)); 17317c478bd9Sstevel@tonic-gate } 17327c478bd9Sstevel@tonic-gate } 17337c478bd9Sstevel@tonic-gate mutex_exit(&pcmcia_global_lock); 17347c478bd9Sstevel@tonic-gate } else { 17357c478bd9Sstevel@tonic-gate 17367c478bd9Sstevel@tonic-gate if (pcmcia_num_adapters == 0) { 17377c478bd9Sstevel@tonic-gate return (ENXIO); 17387c478bd9Sstevel@tonic-gate } 17397c478bd9Sstevel@tonic-gate if (elen > EM_EVENTSIZE) 17407c478bd9Sstevel@tonic-gate return (EINVAL); 17417c478bd9Sstevel@tonic-gate 17427c478bd9Sstevel@tonic-gate mif = (struct pcmcia_mif *) 17435c066ec2SJerry Gilliam kmem_zalloc(sizeof (struct pcmcia_mif), KM_NOSLEEP); 17447c478bd9Sstevel@tonic-gate if (mif == NULL) 17457c478bd9Sstevel@tonic-gate return (ENOSPC); 17467c478bd9Sstevel@tonic-gate 17477c478bd9Sstevel@tonic-gate mif->mif_function = (void (*)())handler; 17487c478bd9Sstevel@tonic-gate bcopy(events, mif->mif_events, elen); 17497c478bd9Sstevel@tonic-gate mif->mif_id = id; 17507c478bd9Sstevel@tonic-gate mutex_enter(&pcmcia_global_lock); 17517c478bd9Sstevel@tonic-gate mif->mif_next = pcmcia_mif_handlers; 17527c478bd9Sstevel@tonic-gate pcmcia_mif_handlers = mif; 17537c478bd9Sstevel@tonic-gate if (cs != NULL) 17547c478bd9Sstevel@tonic-gate *cs = (void *)pcmcia_card_services; 17557c478bd9Sstevel@tonic-gate if (ss != NULL) { 17567c478bd9Sstevel@tonic-gate *ss = (void *)SocketServices; 17577c478bd9Sstevel@tonic-gate } 17587c478bd9Sstevel@tonic-gate 17597c478bd9Sstevel@tonic-gate mutex_exit(&pcmcia_global_lock); 17607c478bd9Sstevel@tonic-gate } 17617c478bd9Sstevel@tonic-gate return (0); 17627c478bd9Sstevel@tonic-gate } 17637c478bd9Sstevel@tonic-gate 17647c478bd9Sstevel@tonic-gate /* 17657c478bd9Sstevel@tonic-gate * pcm_fix_bits(uchar_t *data, int num, int dir) 17667c478bd9Sstevel@tonic-gate * shift socket bits left(0) or right(0) 17677c478bd9Sstevel@tonic-gate * This is used when mapping logical and physical 17687c478bd9Sstevel@tonic-gate */ 17697c478bd9Sstevel@tonic-gate void 17707c478bd9Sstevel@tonic-gate pcm_fix_bits(socket_enum_t src, socket_enum_t dst, int num, int dir) 17717c478bd9Sstevel@tonic-gate { 17727c478bd9Sstevel@tonic-gate int i; 17737c478bd9Sstevel@tonic-gate 17747c478bd9Sstevel@tonic-gate PR_ZERO(dst); 17757c478bd9Sstevel@tonic-gate 17767c478bd9Sstevel@tonic-gate if (dir == 0) { 17777c478bd9Sstevel@tonic-gate /* LEFT */ 177824a150c1SToomas Soome for (i = 0; i <= PCMCIA_MAX_SOCKETS - num; i++) { 17797c478bd9Sstevel@tonic-gate if (PR_GET(src, i)) 17807c478bd9Sstevel@tonic-gate PR_SET(dst, i + num); 17817c478bd9Sstevel@tonic-gate } 17827c478bd9Sstevel@tonic-gate } else { 17837c478bd9Sstevel@tonic-gate /* RIGHT */ 178424a150c1SToomas Soome for (i = num; i < PCMCIA_MAX_SOCKETS; i++) { 17857c478bd9Sstevel@tonic-gate if (PR_GET(src, i)) 17865c066ec2SJerry Gilliam PR_SET(dst, i - num); 17877c478bd9Sstevel@tonic-gate } 17887c478bd9Sstevel@tonic-gate } 17897c478bd9Sstevel@tonic-gate } 17907c478bd9Sstevel@tonic-gate 17917c478bd9Sstevel@tonic-gate uint32_t 17927c478bd9Sstevel@tonic-gate genmask(int len) 17937c478bd9Sstevel@tonic-gate { 17947c478bd9Sstevel@tonic-gate uint32_t mask; 17957c478bd9Sstevel@tonic-gate for (mask = 0; len > 0; len--) { 17967c478bd9Sstevel@tonic-gate mask |= 1 << (len - 1); 17977c478bd9Sstevel@tonic-gate } 17987c478bd9Sstevel@tonic-gate return (mask); 17997c478bd9Sstevel@tonic-gate } 18007c478bd9Sstevel@tonic-gate 18017c478bd9Sstevel@tonic-gate int 18027c478bd9Sstevel@tonic-gate genp2(int val) 18037c478bd9Sstevel@tonic-gate { 18047c478bd9Sstevel@tonic-gate int i; 18057c478bd9Sstevel@tonic-gate if (val == 0) 18067c478bd9Sstevel@tonic-gate return (0); 18077c478bd9Sstevel@tonic-gate for (i = 0; i < 32; i++) 18087c478bd9Sstevel@tonic-gate if (val > (1 << i)) 18097c478bd9Sstevel@tonic-gate return (i); 18107c478bd9Sstevel@tonic-gate return (0); 18117c478bd9Sstevel@tonic-gate } 18127c478bd9Sstevel@tonic-gate 18137c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 18147c478bd9Sstevel@tonic-gate char *ssfuncs[128] = { 18157c478bd9Sstevel@tonic-gate "GetAdapter", "GetPage", "GetSocket", "GetStatus", "GetWindow", 18167c478bd9Sstevel@tonic-gate "InquireAdapter", "InquireSocket", "InquireWindow", "ResetSocket", 18177c478bd9Sstevel@tonic-gate "SetPage", "SetAdapter", "SetSocket", "SetWindow", "SetIRQHandler", 18187c478bd9Sstevel@tonic-gate "ClearIRQHandler", 18197c478bd9Sstevel@tonic-gate /* 15 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 18207c478bd9Sstevel@tonic-gate /* 25 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 18217c478bd9Sstevel@tonic-gate /* 35 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 18227c478bd9Sstevel@tonic-gate /* 45 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 18237c478bd9Sstevel@tonic-gate /* 55 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 18247c478bd9Sstevel@tonic-gate /* 65 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 18257c478bd9Sstevel@tonic-gate /* 75 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 18267c478bd9Sstevel@tonic-gate /* 85 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 18277c478bd9Sstevel@tonic-gate /* 95 */ NULL, NULL, NULL, 18287c478bd9Sstevel@tonic-gate "CSIsActiveDip", 18297c478bd9Sstevel@tonic-gate "CSInitDev", "CSRegister", "CSCISInit", "CSUnregister", 18307c478bd9Sstevel@tonic-gate "CISGetAddress", "CISSetAddress", "CSCardRemoved", "CSGetCookiesAndDip" 18317c478bd9Sstevel@tonic-gate }; 18327c478bd9Sstevel@tonic-gate #endif 18337c478bd9Sstevel@tonic-gate 18347c478bd9Sstevel@tonic-gate /* 18357c478bd9Sstevel@tonic-gate * SocketServices 18367c478bd9Sstevel@tonic-gate * general entrypoint for Card Services to find 18377c478bd9Sstevel@tonic-gate * Socket Services. Finding the entry requires 18387c478bd9Sstevel@tonic-gate * a _depends_on[] relationship. 18397c478bd9Sstevel@tonic-gate * 18407c478bd9Sstevel@tonic-gate * In some cases, the work is done locally but usually 18417c478bd9Sstevel@tonic-gate * the parameters are adjusted and the adapter driver 18427c478bd9Sstevel@tonic-gate * code asked to do the work. 18437c478bd9Sstevel@tonic-gate */ 18447c478bd9Sstevel@tonic-gate int 18457c478bd9Sstevel@tonic-gate SocketServices(int function, ...) 18467c478bd9Sstevel@tonic-gate { 18477c478bd9Sstevel@tonic-gate va_list arglist; 18487c478bd9Sstevel@tonic-gate uint32_t args[16]; 18497c478bd9Sstevel@tonic-gate csregister_t *reg; 18507c478bd9Sstevel@tonic-gate sservice_t *serv; 18517c478bd9Sstevel@tonic-gate dev_info_t *dip; 18527c478bd9Sstevel@tonic-gate int socket, func; 18537c478bd9Sstevel@tonic-gate int error = SUCCESS; 18547c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t *sockp; 18557c478bd9Sstevel@tonic-gate 18567c478bd9Sstevel@tonic-gate va_start(arglist, function); 18577c478bd9Sstevel@tonic-gate 18587c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 18597c478bd9Sstevel@tonic-gate if (pcmcia_debug > 1) 18607c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "SocketServices called for function %d [%s]\n", 18615c066ec2SJerry Gilliam function, 18625c066ec2SJerry Gilliam ((function < 128) && ssfuncs[function] != NULL) ? 18635c066ec2SJerry Gilliam ssfuncs[function] : "UNKNOWN"); 18647c478bd9Sstevel@tonic-gate #endif 18657c478bd9Sstevel@tonic-gate switch (function) { 18667c478bd9Sstevel@tonic-gate case CSRegister: 18677c478bd9Sstevel@tonic-gate case CISGetAddress: 18687c478bd9Sstevel@tonic-gate case CISSetAddress: 18697c478bd9Sstevel@tonic-gate 18707c478bd9Sstevel@tonic-gate reg = va_arg(arglist, csregister_t *); 18717c478bd9Sstevel@tonic-gate 18727c478bd9Sstevel@tonic-gate if (reg->cs_magic != PCCS_MAGIC || 18737c478bd9Sstevel@tonic-gate reg->cs_version != PCCS_VERSION) { 18747c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 18755c066ec2SJerry Gilliam "pcmcia: CSRegister (%x, %x, %p, %p) *ERROR*", 18765c066ec2SJerry Gilliam reg->cs_magic, reg->cs_version, 18775c066ec2SJerry Gilliam (void *)reg->cs_card_services, 18785c066ec2SJerry Gilliam (void *)reg->cs_event); 18797c478bd9Sstevel@tonic-gate error = BAD_FUNCTION; 18807c478bd9Sstevel@tonic-gate break; 18817c478bd9Sstevel@tonic-gate } 18827c478bd9Sstevel@tonic-gate 18837c478bd9Sstevel@tonic-gate switch (function) { 18847c478bd9Sstevel@tonic-gate case CISGetAddress: 18857c478bd9Sstevel@tonic-gate reg->cs_event = pcmcia_cis_parser; 18867c478bd9Sstevel@tonic-gate break; 18877c478bd9Sstevel@tonic-gate case CISSetAddress: 18887c478bd9Sstevel@tonic-gate pcmcia_cis_parser = reg->cs_event; 18897c478bd9Sstevel@tonic-gate break; 18907c478bd9Sstevel@tonic-gate case CSRegister: 18917c478bd9Sstevel@tonic-gate break; 18927c478bd9Sstevel@tonic-gate } 18937c478bd9Sstevel@tonic-gate break; 18947c478bd9Sstevel@tonic-gate 18957c478bd9Sstevel@tonic-gate case CSUnregister: 18967c478bd9Sstevel@tonic-gate break; 18977c478bd9Sstevel@tonic-gate 18987c478bd9Sstevel@tonic-gate case CSCISInit: 18997c478bd9Sstevel@tonic-gate args[0] = va_arg(arglist, int); 19007c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 19017c478bd9Sstevel@tonic-gate if (pcmcia_debug) 19027c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 19035c066ec2SJerry Gilliam "CSCISInit: CIS is initialized on socket %d\n", 19045c066ec2SJerry Gilliam (int)args[0]); 19057c478bd9Sstevel@tonic-gate #endif 19067c478bd9Sstevel@tonic-gate /* 19077c478bd9Sstevel@tonic-gate * now that the CIS has been parsed (there may not 19087c478bd9Sstevel@tonic-gate * be one but the work is done) we can create the 19097c478bd9Sstevel@tonic-gate * device information structures. 19107c478bd9Sstevel@tonic-gate * 19117c478bd9Sstevel@tonic-gate * we serialize the node creation to avoid problems 19127c478bd9Sstevel@tonic-gate * with initial probe/attach of nexi. 19137c478bd9Sstevel@tonic-gate */ 19147c478bd9Sstevel@tonic-gate 19157c478bd9Sstevel@tonic-gate mutex_enter(&pcmcia_global_lock); 19167c478bd9Sstevel@tonic-gate pcmcia_create_dev_info(args[0]); 19177c478bd9Sstevel@tonic-gate cv_broadcast(&pcmcia_condvar); /* wakeup the nexus attach */ 19187c478bd9Sstevel@tonic-gate mutex_exit(&pcmcia_global_lock); 19197c478bd9Sstevel@tonic-gate break; 19207c478bd9Sstevel@tonic-gate 19217c478bd9Sstevel@tonic-gate case CSInitDev: 19227c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 19237c478bd9Sstevel@tonic-gate if (pcmcia_debug) 19247c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "CSInitDev: initialize device\n"); 19257c478bd9Sstevel@tonic-gate #endif 19267c478bd9Sstevel@tonic-gate /* 19277c478bd9Sstevel@tonic-gate * this is where we create the /devices entries 19287c478bd9Sstevel@tonic-gate * that let us out into the world 19297c478bd9Sstevel@tonic-gate */ 19307c478bd9Sstevel@tonic-gate 19317c478bd9Sstevel@tonic-gate (void) pcmcia_create_device(va_arg(arglist, 19327c478bd9Sstevel@tonic-gate ss_make_device_node_t *)); 19337c478bd9Sstevel@tonic-gate break; 19347c478bd9Sstevel@tonic-gate 19357c478bd9Sstevel@tonic-gate case CSCardRemoved: 19367c478bd9Sstevel@tonic-gate args[0] = va_arg(arglist, uint32_t); 19377c478bd9Sstevel@tonic-gate socket = CS_GET_SOCKET_NUMBER(args[0]); 19387c478bd9Sstevel@tonic-gate func = CS_GET_FUNCTION_NUMBER(args[0]); 19397c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 19407c478bd9Sstevel@tonic-gate if (pcmcia_debug) 19417c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 19425c066ec2SJerry Gilliam "CSCardRemoved! (socket=%d)\n", (int)args[0]); 19437c478bd9Sstevel@tonic-gate #endif 19447c478bd9Sstevel@tonic-gate if (socket >= pcmcia_num_sockets) 19457c478bd9Sstevel@tonic-gate break; 19467c478bd9Sstevel@tonic-gate 19477c478bd9Sstevel@tonic-gate sockp = pcmcia_sockets[socket]; 19487c478bd9Sstevel@tonic-gate if (sockp == NULL) { 19497c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 19507c478bd9Sstevel@tonic-gate "pcmcia: bad socket = %x", socket); 19517c478bd9Sstevel@tonic-gate break; 19527c478bd9Sstevel@tonic-gate } 19537c478bd9Sstevel@tonic-gate 195411c2b4c0Srw if (!(sockp->ls_flags & PCS_SUSPENDED)) { 195511c2b4c0Srw for (func = 0; func < sockp->ls_functions; func++) { 195611c2b4c0Srw /* 195711c2b4c0Srw * break the association of dip and socket 195811c2b4c0Srw * for all functions on that socket 195911c2b4c0Srw */ 196011c2b4c0Srw dip = sockp->ls_dip[func]; 196111c2b4c0Srw sockp->ls_dip[func] = NULL; 196211c2b4c0Srw if (dip != NULL) { 196311c2b4c0Srw struct pcmcia_parent_private *ppd; 196411c2b4c0Srw ppd = (struct pcmcia_parent_private *) 196511c2b4c0Srw ddi_get_parent_data(dip); 196611c2b4c0Srw ppd->ppd_active = 0; 196711c2b4c0Srw (void) ndi_devi_offline(dip, 196811c2b4c0Srw NDI_DEVI_REMOVE); 196911c2b4c0Srw 197011c2b4c0Srw pcmcia_ppd_free(ppd); 197111c2b4c0Srw } 19727c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 197311c2b4c0Srw else { 197411c2b4c0Srw if (pcmcia_debug) 197511c2b4c0Srw cmn_err(CE_CONT, 197611c2b4c0Srw "CardRemoved: no " 197711c2b4c0Srw "dip present " 197811c2b4c0Srw "on socket %d!\n", 197911c2b4c0Srw (int)args[0]); 198011c2b4c0Srw } 19817c478bd9Sstevel@tonic-gate #endif 198211c2b4c0Srw } 198311c2b4c0Srw } else { 19847c478bd9Sstevel@tonic-gate mutex_enter(&pcmcia_global_lock); 19857c478bd9Sstevel@tonic-gate sockp->ls_flags &= ~PCS_SUSPENDED; 19867c478bd9Sstevel@tonic-gate cv_broadcast(&pcmcia_condvar); 19877c478bd9Sstevel@tonic-gate mutex_exit(&pcmcia_global_lock); 19887c478bd9Sstevel@tonic-gate } 19897c478bd9Sstevel@tonic-gate break; 19907c478bd9Sstevel@tonic-gate 19917c478bd9Sstevel@tonic-gate case CSGetCookiesAndDip: 19927c478bd9Sstevel@tonic-gate serv = va_arg(arglist, sservice_t *); 19937c478bd9Sstevel@tonic-gate if (serv != NULL) 19947c478bd9Sstevel@tonic-gate error = GetCookiesAndDip(serv); 19957c478bd9Sstevel@tonic-gate else 19967c478bd9Sstevel@tonic-gate error = BAD_SOCKET; 19977c478bd9Sstevel@tonic-gate break; 19987c478bd9Sstevel@tonic-gate 19997c478bd9Sstevel@tonic-gate case CSGetActiveDip: 20007c478bd9Sstevel@tonic-gate /* 20017c478bd9Sstevel@tonic-gate * get the dip associated with the card currently 20027c478bd9Sstevel@tonic-gate * in the specified socket 20037c478bd9Sstevel@tonic-gate */ 20047c478bd9Sstevel@tonic-gate args[0] = va_arg(arglist, uint32_t); 20057c478bd9Sstevel@tonic-gate socket = CS_GET_SOCKET_NUMBER(args[0]); 20067c478bd9Sstevel@tonic-gate func = CS_GET_FUNCTION_NUMBER(args[0]); 20077c478bd9Sstevel@tonic-gate error = (long)pcmcia_sockets[socket]->ls_dip[func]; 20087c478bd9Sstevel@tonic-gate break; 20097c478bd9Sstevel@tonic-gate 20107c478bd9Sstevel@tonic-gate /* 20117c478bd9Sstevel@tonic-gate * the remaining entries are SocketServices calls 20127c478bd9Sstevel@tonic-gate */ 20137c478bd9Sstevel@tonic-gate case SS_GetAdapter: 20147c478bd9Sstevel@tonic-gate error = SSGetAdapter(va_arg(arglist, get_adapter_t *)); 20157c478bd9Sstevel@tonic-gate break; 20167c478bd9Sstevel@tonic-gate case SS_GetPage: 20177c478bd9Sstevel@tonic-gate error = SSGetPage(va_arg(arglist, get_page_t *)); 20187c478bd9Sstevel@tonic-gate break; 20197c478bd9Sstevel@tonic-gate case SS_GetSocket: 20207c478bd9Sstevel@tonic-gate error = SSGetSocket(va_arg(arglist, get_socket_t *)); 20217c478bd9Sstevel@tonic-gate break; 20227c478bd9Sstevel@tonic-gate case SS_GetStatus: 20237c478bd9Sstevel@tonic-gate error = SSGetStatus(va_arg(arglist, get_ss_status_t *)); 20247c478bd9Sstevel@tonic-gate break; 20257c478bd9Sstevel@tonic-gate case SS_GetWindow: 20267c478bd9Sstevel@tonic-gate error = SSGetWindow(va_arg(arglist, get_window_t *)); 20277c478bd9Sstevel@tonic-gate break; 20287c478bd9Sstevel@tonic-gate case SS_InquireAdapter: 20297c478bd9Sstevel@tonic-gate error = SSInquireAdapter(va_arg(arglist, inquire_adapter_t *)); 20307c478bd9Sstevel@tonic-gate break; 20317c478bd9Sstevel@tonic-gate case SS_InquireSocket: 20327c478bd9Sstevel@tonic-gate error = SSInquireSocket(va_arg(arglist, inquire_socket_t *)); 20337c478bd9Sstevel@tonic-gate break; 20347c478bd9Sstevel@tonic-gate case SS_InquireWindow: 20357c478bd9Sstevel@tonic-gate error = SSInquireWindow(va_arg(arglist, inquire_window_t *)); 20367c478bd9Sstevel@tonic-gate break; 20377c478bd9Sstevel@tonic-gate case SS_ResetSocket: 20387c478bd9Sstevel@tonic-gate args[0] = va_arg(arglist, uint32_t); 20397c478bd9Sstevel@tonic-gate args[1] = va_arg(arglist, int); 20407c478bd9Sstevel@tonic-gate error = SSResetSocket(args[0], args[1]); 20417c478bd9Sstevel@tonic-gate break; 20427c478bd9Sstevel@tonic-gate case SS_SetPage: 20437c478bd9Sstevel@tonic-gate error = SSSetPage(va_arg(arglist, set_page_t *)); 20447c478bd9Sstevel@tonic-gate break; 20457c478bd9Sstevel@tonic-gate case SS_SetSocket: 20467c478bd9Sstevel@tonic-gate error = SSSetSocket(va_arg(arglist, set_socket_t *)); 20477c478bd9Sstevel@tonic-gate break; 20487c478bd9Sstevel@tonic-gate case SS_SetWindow: 20497c478bd9Sstevel@tonic-gate error = SSSetWindow(va_arg(arglist, set_window_t *)); 20507c478bd9Sstevel@tonic-gate break; 20517c478bd9Sstevel@tonic-gate case SS_SetIRQHandler: 20527c478bd9Sstevel@tonic-gate error = SSSetIRQHandler(va_arg(arglist, set_irq_handler_t *)); 20537c478bd9Sstevel@tonic-gate break; 20547c478bd9Sstevel@tonic-gate case SS_ClearIRQHandler: 20557c478bd9Sstevel@tonic-gate error = SSClearIRQHandler(va_arg(arglist, 20567c478bd9Sstevel@tonic-gate clear_irq_handler_t *)); 20577c478bd9Sstevel@tonic-gate break; 20587c478bd9Sstevel@tonic-gate default: 20597c478bd9Sstevel@tonic-gate error = BAD_FUNCTION; 20607c478bd9Sstevel@tonic-gate break; 20617c478bd9Sstevel@tonic-gate } 20627c478bd9Sstevel@tonic-gate va_end(arglist); 20637c478bd9Sstevel@tonic-gate return (error); 20647c478bd9Sstevel@tonic-gate } 20657c478bd9Sstevel@tonic-gate 20667c478bd9Sstevel@tonic-gate /* 20677c478bd9Sstevel@tonic-gate * pcmcia_merge_power() 20687c478bd9Sstevel@tonic-gate * The adapters may have different power tables so it 20697c478bd9Sstevel@tonic-gate * is necessary to construct a single power table that 20707c478bd9Sstevel@tonic-gate * can be used throughout the system. The result is 20717c478bd9Sstevel@tonic-gate * a merger of all capabilities. The nexus adds 20727c478bd9Sstevel@tonic-gate * power table entries one at a time. 20737c478bd9Sstevel@tonic-gate */ 20747c478bd9Sstevel@tonic-gate void 20757c478bd9Sstevel@tonic-gate pcmcia_merge_power(struct power_entry *power) 20767c478bd9Sstevel@tonic-gate { 20777c478bd9Sstevel@tonic-gate int i; 20787c478bd9Sstevel@tonic-gate struct power_entry pwr; 20797c478bd9Sstevel@tonic-gate 20807c478bd9Sstevel@tonic-gate pwr = *power; 20817c478bd9Sstevel@tonic-gate 20827c478bd9Sstevel@tonic-gate for (i = 0; i < pcmcia_num_power; i++) { 20837c478bd9Sstevel@tonic-gate if (pwr.PowerLevel == pcmcia_power_table[i].PowerLevel) { 20847c478bd9Sstevel@tonic-gate if (pwr.ValidSignals == 20855c066ec2SJerry Gilliam pcmcia_power_table[i].ValidSignals) { 20867c478bd9Sstevel@tonic-gate return; 20877c478bd9Sstevel@tonic-gate } else { 20887c478bd9Sstevel@tonic-gate /* partial match */ 20897c478bd9Sstevel@tonic-gate pwr.ValidSignals &= 20905c066ec2SJerry Gilliam ~pcmcia_power_table[i].ValidSignals; 20917c478bd9Sstevel@tonic-gate } 20927c478bd9Sstevel@tonic-gate } 20937c478bd9Sstevel@tonic-gate } 20947c478bd9Sstevel@tonic-gate /* what's left becomes a new entry */ 20957c478bd9Sstevel@tonic-gate if (pcmcia_num_power == PCMCIA_MAX_POWER) 20967c478bd9Sstevel@tonic-gate return; 20977c478bd9Sstevel@tonic-gate pcmcia_power_table[pcmcia_num_power++] = pwr; 20987c478bd9Sstevel@tonic-gate } 20997c478bd9Sstevel@tonic-gate 21007c478bd9Sstevel@tonic-gate /* 21017c478bd9Sstevel@tonic-gate * pcmcia_do_suspend() 21027c478bd9Sstevel@tonic-gate * tell CS that a suspend has happened by passing a 21037c478bd9Sstevel@tonic-gate * card removal event. Then cleanup the socket state 21047c478bd9Sstevel@tonic-gate * to fake the cards being removed so resume works 21057c478bd9Sstevel@tonic-gate */ 21067c478bd9Sstevel@tonic-gate void 21077c478bd9Sstevel@tonic-gate pcmcia_do_suspend(int socket, pcmcia_logical_socket_t *sockp) 21087c478bd9Sstevel@tonic-gate { 21097c478bd9Sstevel@tonic-gate get_ss_status_t stat; 21107c478bd9Sstevel@tonic-gate struct pcmcia_adapter *adapt; 21117c478bd9Sstevel@tonic-gate pcmcia_if_t *ls_if; 21127c478bd9Sstevel@tonic-gate dev_info_t *dip; 21137c478bd9Sstevel@tonic-gate int i; 21147c478bd9Sstevel@tonic-gate 21157c478bd9Sstevel@tonic-gate #ifdef XXX 21167c478bd9Sstevel@tonic-gate if (pcmcia_cs_event == NULL) { 21177c478bd9Sstevel@tonic-gate return; 21187c478bd9Sstevel@tonic-gate } 21197c478bd9Sstevel@tonic-gate #endif 21207c478bd9Sstevel@tonic-gate 21217c478bd9Sstevel@tonic-gate ls_if = sockp->ls_if; 21227c478bd9Sstevel@tonic-gate adapt = sockp->ls_adapter; 21237c478bd9Sstevel@tonic-gate 21247c478bd9Sstevel@tonic-gate if (ls_if == NULL || ls_if->pcif_get_status == NULL) { 21257c478bd9Sstevel@tonic-gate return; 21267c478bd9Sstevel@tonic-gate } 21277c478bd9Sstevel@tonic-gate 21287c478bd9Sstevel@tonic-gate stat.socket = socket; 21297c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 21307c478bd9Sstevel@tonic-gate if (pcmcia_debug) { 21317c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 21325c066ec2SJerry Gilliam "pcmcia_do_suspend(%d, %p)\n", socket, (void *)sockp); 21337c478bd9Sstevel@tonic-gate } 21347c478bd9Sstevel@tonic-gate #endif 21357c478bd9Sstevel@tonic-gate 21367c478bd9Sstevel@tonic-gate if (GET_STATUS(ls_if, adapt->pca_dip, &stat) != SUCCESS) 21377c478bd9Sstevel@tonic-gate return; 21387c478bd9Sstevel@tonic-gate 21397c478bd9Sstevel@tonic-gate /* 21407c478bd9Sstevel@tonic-gate * If there is a card in the socket, then we need to send 21417c478bd9Sstevel@tonic-gate * everyone a PCE_CARD_REMOVAL event, and remove the 21427c478bd9Sstevel@tonic-gate * card active property. 21437c478bd9Sstevel@tonic-gate */ 21447c478bd9Sstevel@tonic-gate 21457c478bd9Sstevel@tonic-gate for (i = 0; i < sockp->ls_functions; i++) { 21467c478bd9Sstevel@tonic-gate struct pcmcia_parent_private *ppd; 21477c478bd9Sstevel@tonic-gate dip = sockp->ls_dip[i]; 21487c478bd9Sstevel@tonic-gate if (dip != NULL) { 21497c478bd9Sstevel@tonic-gate ppd = (struct pcmcia_parent_private *) 21505c066ec2SJerry Gilliam ddi_get_parent_data(dip); 21517c478bd9Sstevel@tonic-gate ppd->ppd_flags |= PPD_SUSPENDED; 21527c478bd9Sstevel@tonic-gate } 21537c478bd9Sstevel@tonic-gate #if 0 21547c478bd9Sstevel@tonic-gate sockp->ls_dip[i] = NULL; 21557c478bd9Sstevel@tonic-gate #endif 21567c478bd9Sstevel@tonic-gate } 21577c478bd9Sstevel@tonic-gate sockp->ls_flags |= PCS_SUSPENDED; 21587c478bd9Sstevel@tonic-gate 21597c478bd9Sstevel@tonic-gate if (pcmcia_cs_event && 21607c478bd9Sstevel@tonic-gate (sockp->ls_cs_events & (1 << PCE_PM_SUSPEND))) { 21617c478bd9Sstevel@tonic-gate CS_EVENT(PCE_PM_SUSPEND, socket, 0); 21627c478bd9Sstevel@tonic-gate } 21637c478bd9Sstevel@tonic-gate pcm_event_manager(PCE_PM_SUSPEND, socket, NULL); 21647c478bd9Sstevel@tonic-gate } 21657c478bd9Sstevel@tonic-gate 21667c478bd9Sstevel@tonic-gate /* 21677c478bd9Sstevel@tonic-gate * pcmcia_do_resume() 21687c478bd9Sstevel@tonic-gate * tell CS that a suspend has happened by passing a 21697c478bd9Sstevel@tonic-gate * card removal event. Then cleanup the socket state 21707c478bd9Sstevel@tonic-gate * to fake the cards being removed so resume works 21717c478bd9Sstevel@tonic-gate */ 21727c478bd9Sstevel@tonic-gate void 21737c478bd9Sstevel@tonic-gate pcmcia_do_resume(int socket, pcmcia_logical_socket_t *sockp) 21747c478bd9Sstevel@tonic-gate { 21757c478bd9Sstevel@tonic-gate get_ss_status_t stat; 21767c478bd9Sstevel@tonic-gate struct pcmcia_adapter *adapt; 21777c478bd9Sstevel@tonic-gate pcmcia_if_t *ls_if; 21787c478bd9Sstevel@tonic-gate 21797c478bd9Sstevel@tonic-gate #ifdef XXX 21807c478bd9Sstevel@tonic-gate if (pcmcia_cs_event == NULL) { 21817c478bd9Sstevel@tonic-gate return; 21827c478bd9Sstevel@tonic-gate } 21837c478bd9Sstevel@tonic-gate #endif 21847c478bd9Sstevel@tonic-gate 21857c478bd9Sstevel@tonic-gate ls_if = sockp->ls_if; 21867c478bd9Sstevel@tonic-gate adapt = sockp->ls_adapter; 21877c478bd9Sstevel@tonic-gate 21887c478bd9Sstevel@tonic-gate if (ls_if == NULL || ls_if->pcif_get_status == NULL) { 21897c478bd9Sstevel@tonic-gate return; 21907c478bd9Sstevel@tonic-gate } 21917c478bd9Sstevel@tonic-gate 21927c478bd9Sstevel@tonic-gate stat.socket = socket; 21937c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 21947c478bd9Sstevel@tonic-gate if (pcmcia_debug) { 21957c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 21965c066ec2SJerry Gilliam "pcmcia_do_resume(%d, %p)\n", socket, (void *)sockp); 21977c478bd9Sstevel@tonic-gate } 21987c478bd9Sstevel@tonic-gate #endif 21997c478bd9Sstevel@tonic-gate if (GET_STATUS(ls_if, adapt->pca_dip, &stat) == 22007c478bd9Sstevel@tonic-gate SUCCESS) { 22017c478bd9Sstevel@tonic-gate 22027c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 22037c478bd9Sstevel@tonic-gate if (pcmcia_debug) 22047c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "\tsocket=%x, CardState=%x\n", 22055c066ec2SJerry Gilliam socket, stat.CardState); 22067c478bd9Sstevel@tonic-gate #endif 22077c478bd9Sstevel@tonic-gate #if 0 22087c478bd9Sstevel@tonic-gate /* now have socket info -- do we have events? */ 22097c478bd9Sstevel@tonic-gate if ((stat.CardState & SBM_CD) == SBM_CD) { 22107c478bd9Sstevel@tonic-gate if (pcmcia_cs_event && 22117c478bd9Sstevel@tonic-gate (sockp->ls_cs_events & (1 << PCE_CARD_INSERT))) { 22127c478bd9Sstevel@tonic-gate CS_EVENT(PCE_CARD_INSERT, socket, 0); 22137c478bd9Sstevel@tonic-gate } 22147c478bd9Sstevel@tonic-gate 22157c478bd9Sstevel@tonic-gate /* we should have card removed from CS soon */ 22167c478bd9Sstevel@tonic-gate pcm_event_manager(PCE_CARD_INSERT, socket, NULL); 22177c478bd9Sstevel@tonic-gate } 22187c478bd9Sstevel@tonic-gate #else 22197c478bd9Sstevel@tonic-gate if (pcmcia_cs_event && 22207c478bd9Sstevel@tonic-gate (sockp->ls_cs_events & (1 << PCE_PM_SUSPEND))) { 22217c478bd9Sstevel@tonic-gate CS_EVENT(PCE_PM_RESUME, socket, 0); 22227c478bd9Sstevel@tonic-gate CS_EVENT(PCE_CARD_REMOVAL, socket, 0); 22237c478bd9Sstevel@tonic-gate if ((stat.CardState & SBM_CD) == SBM_CD) 22247c478bd9Sstevel@tonic-gate CS_EVENT(PCE_CARD_INSERT, socket, 0); 22257c478bd9Sstevel@tonic-gate } 22267c478bd9Sstevel@tonic-gate #endif 22277c478bd9Sstevel@tonic-gate } 22287c478bd9Sstevel@tonic-gate } 22297c478bd9Sstevel@tonic-gate 22307c478bd9Sstevel@tonic-gate /* 22317c478bd9Sstevel@tonic-gate * pcmcia_map_power_set() 22327c478bd9Sstevel@tonic-gate * Given a power table entry and level, find it in the 22337c478bd9Sstevel@tonic-gate * master table and return the index in the adapter table. 22347c478bd9Sstevel@tonic-gate */ 22357c478bd9Sstevel@tonic-gate static int 22367c478bd9Sstevel@tonic-gate pcmcia_map_power_set(struct pcmcia_adapter *adapt, int level, int which) 22377c478bd9Sstevel@tonic-gate { 22387c478bd9Sstevel@tonic-gate int plevel, i; 22397c478bd9Sstevel@tonic-gate struct power_entry *pwr = (struct power_entry *)adapt->pca_power; 22407c478bd9Sstevel@tonic-gate plevel = pcmcia_power_table[level].PowerLevel; 22417c478bd9Sstevel@tonic-gate /* mask = pcmcia_power_table[level].ValidSignals; */ 22427c478bd9Sstevel@tonic-gate for (i = 0; i < adapt->pca_numpower; i++) 22437c478bd9Sstevel@tonic-gate if (plevel == pwr[i].PowerLevel && 22447c478bd9Sstevel@tonic-gate pwr[i].ValidSignals & which) 22457c478bd9Sstevel@tonic-gate return (i); 22467c478bd9Sstevel@tonic-gate return (0); 22477c478bd9Sstevel@tonic-gate } 22487c478bd9Sstevel@tonic-gate 22497c478bd9Sstevel@tonic-gate /* 22507c478bd9Sstevel@tonic-gate * pcmcia_map_power_get() 22517c478bd9Sstevel@tonic-gate * Given an adapter power entry, find the appropriate index 22527c478bd9Sstevel@tonic-gate * in the master table. 22537c478bd9Sstevel@tonic-gate */ 22547c478bd9Sstevel@tonic-gate static int 22557c478bd9Sstevel@tonic-gate pcmcia_map_power_get(struct pcmcia_adapter *adapt, int level, int which) 22567c478bd9Sstevel@tonic-gate { 22577c478bd9Sstevel@tonic-gate int plevel, i; 22587c478bd9Sstevel@tonic-gate struct power_entry *pwr = (struct power_entry *)adapt->pca_power; 22597c478bd9Sstevel@tonic-gate plevel = pwr[level].PowerLevel; 22607c478bd9Sstevel@tonic-gate /* mask = pwr[level].ValidSignals; */ 22617c478bd9Sstevel@tonic-gate for (i = 0; i < pcmcia_num_power; i++) 22627c478bd9Sstevel@tonic-gate if (plevel == pcmcia_power_table[i].PowerLevel && 22637c478bd9Sstevel@tonic-gate pcmcia_power_table[i].ValidSignals & which) 22647c478bd9Sstevel@tonic-gate return (i); 22657c478bd9Sstevel@tonic-gate return (0); 22667c478bd9Sstevel@tonic-gate } 22677c478bd9Sstevel@tonic-gate 22687c478bd9Sstevel@tonic-gate /* 22697c478bd9Sstevel@tonic-gate * XXX - SS really needs a way to allow the caller to express 22707c478bd9Sstevel@tonic-gate * interest in PCE_CARD_STATUS_CHANGE events. 22717c478bd9Sstevel@tonic-gate */ 22727c478bd9Sstevel@tonic-gate static uint32_t 22737c478bd9Sstevel@tonic-gate pcm_event_map[32] = { 22747c478bd9Sstevel@tonic-gate PCE_E2M(PCE_CARD_WRITE_PROTECT)|PCE_E2M(PCE_CARD_STATUS_CHANGE), 22757c478bd9Sstevel@tonic-gate PCE_E2M(PCE_CARD_UNLOCK)|PCE_E2M(PCE_CARD_STATUS_CHANGE), 22767c478bd9Sstevel@tonic-gate PCE_E2M(PCE_EJECTION_REQUEST)|PCE_E2M(PCE_CARD_STATUS_CHANGE), 22777c478bd9Sstevel@tonic-gate PCE_E2M(PCE_INSERTION_REQUEST)|PCE_E2M(PCE_CARD_STATUS_CHANGE), 22787c478bd9Sstevel@tonic-gate PCE_E2M(PCE_CARD_BATTERY_WARN)|PCE_E2M(PCE_CARD_STATUS_CHANGE), 22797c478bd9Sstevel@tonic-gate PCE_E2M(PCE_CARD_BATTERY_DEAD)|PCE_E2M(PCE_CARD_STATUS_CHANGE), 22807c478bd9Sstevel@tonic-gate PCE_E2M(PCE_CARD_READY)|PCE_E2M(PCE_CARD_STATUS_CHANGE), 22817c478bd9Sstevel@tonic-gate PCE_E2M(PCE_CARD_REMOVAL)|PCE_E2M(PCE_CARD_INSERT)| 22827c478bd9Sstevel@tonic-gate PCE_E2M(PCE_CARD_STATUS_CHANGE), 22837c478bd9Sstevel@tonic-gate PCE_E2M(PCE_PM_SUSPEND)|PCE_E2M(PCE_PM_RESUME), 22847c478bd9Sstevel@tonic-gate }; 22857c478bd9Sstevel@tonic-gate 22867c478bd9Sstevel@tonic-gate static int 22877c478bd9Sstevel@tonic-gate pcm_mapevents(uint32_t eventmask) 22887c478bd9Sstevel@tonic-gate { 22897c478bd9Sstevel@tonic-gate uint32_t mask; 22907c478bd9Sstevel@tonic-gate int i; 22917c478bd9Sstevel@tonic-gate 22927c478bd9Sstevel@tonic-gate for (i = 0, mask = 0; eventmask && i < 32; i++) { 22937c478bd9Sstevel@tonic-gate if (eventmask & (1 << i)) { 22947c478bd9Sstevel@tonic-gate mask |= pcm_event_map[i]; 22957c478bd9Sstevel@tonic-gate eventmask &= ~(1 << i); 22967c478bd9Sstevel@tonic-gate } 22977c478bd9Sstevel@tonic-gate } 22987c478bd9Sstevel@tonic-gate return (mask); 22997c478bd9Sstevel@tonic-gate } 23007c478bd9Sstevel@tonic-gate 23017c478bd9Sstevel@tonic-gate 23027c478bd9Sstevel@tonic-gate /* 23037c478bd9Sstevel@tonic-gate * PCMCIA Generic Naming Support 23047c478bd9Sstevel@tonic-gate * 23057c478bd9Sstevel@tonic-gate * With 2.6, PCMCIA naming moves to the 1275 and generic naming model. 23067c478bd9Sstevel@tonic-gate * Consequently, the whole naming mechanism is to be changed. This is 23077c478bd9Sstevel@tonic-gate * not backward compatible with the current names but that isn't a problem 23087c478bd9Sstevel@tonic-gate * due to so few drivers existing. 23097c478bd9Sstevel@tonic-gate * 23107c478bd9Sstevel@tonic-gate * For cards with a device_id tuple, a generic name will be used. 23117c478bd9Sstevel@tonic-gate * if there is no device_id, then the 1275 name will be used if possible. 23127c478bd9Sstevel@tonic-gate * The 1275 name is of the form pccardNNNN,MMMM from the manfid tuple. 23137c478bd9Sstevel@tonic-gate * if there is not manfid tuple, an attempt will be made to bind the 23147c478bd9Sstevel@tonic-gate * node to the version_1 strings. 23157c478bd9Sstevel@tonic-gate * 23167c478bd9Sstevel@tonic-gate * In all cases, a "compatible" property is created with a number 23177c478bd9Sstevel@tonic-gate * of names. The most generic name will be last in the list. 23187c478bd9Sstevel@tonic-gate */ 23197c478bd9Sstevel@tonic-gate 23207c478bd9Sstevel@tonic-gate /* 23217c478bd9Sstevel@tonic-gate * pcmcia_fix_string() 23227c478bd9Sstevel@tonic-gate * want to avoid special characters in alias strings so convert 23237c478bd9Sstevel@tonic-gate * to something innocuous 23247c478bd9Sstevel@tonic-gate */ 23257c478bd9Sstevel@tonic-gate 23267c478bd9Sstevel@tonic-gate void 23277c478bd9Sstevel@tonic-gate pcmcia_fix_string(char *str) 23287c478bd9Sstevel@tonic-gate { 23297c478bd9Sstevel@tonic-gate for (; str && *str; str++) { 23307c478bd9Sstevel@tonic-gate switch (*str) { 23317c478bd9Sstevel@tonic-gate case ' ': 23327c478bd9Sstevel@tonic-gate case '\t': 23337c478bd9Sstevel@tonic-gate *str = '_'; 23347c478bd9Sstevel@tonic-gate break; 23357c478bd9Sstevel@tonic-gate } 23367c478bd9Sstevel@tonic-gate } 23377c478bd9Sstevel@tonic-gate } 23387c478bd9Sstevel@tonic-gate 23397c478bd9Sstevel@tonic-gate void 23407c478bd9Sstevel@tonic-gate pcmcia_1275_name(int socket, struct pcm_device_info *info, 23413f068ebdSToomas Soome client_handle_t handle) 23427c478bd9Sstevel@tonic-gate { 23437c478bd9Sstevel@tonic-gate cistpl_manfid_t manfid; 23447c478bd9Sstevel@tonic-gate cistpl_jedec_t jedec; 23457c478bd9Sstevel@tonic-gate tuple_t tuple; 23467c478bd9Sstevel@tonic-gate int i; 23477c478bd9Sstevel@tonic-gate 23487c478bd9Sstevel@tonic-gate tuple.Socket = socket; 23497c478bd9Sstevel@tonic-gate 23507c478bd9Sstevel@tonic-gate /* get MANFID if it exists -- this is most important form */ 23517c478bd9Sstevel@tonic-gate tuple.DesiredTuple = CISTPL_MANFID; 23527c478bd9Sstevel@tonic-gate tuple.Attributes = 0; 23537c478bd9Sstevel@tonic-gate if ((i = csx_GetFirstTuple(handle, &tuple)) == 23547c478bd9Sstevel@tonic-gate SUCCESS) { 23557c478bd9Sstevel@tonic-gate i = csx_Parse_CISTPL_MANFID(handle, &tuple, 23567c478bd9Sstevel@tonic-gate &manfid); 23577c478bd9Sstevel@tonic-gate if (i == SUCCESS) { 23587c478bd9Sstevel@tonic-gate (void) sprintf(info->pd_bind_name, "%s%x,%x", 23595c066ec2SJerry Gilliam PCMDEV_NAMEPREF, 23605c066ec2SJerry Gilliam manfid.manf, manfid.card); 23617c478bd9Sstevel@tonic-gate info->pd_flags |= PCM_NAME_1275; 23627c478bd9Sstevel@tonic-gate } 23637c478bd9Sstevel@tonic-gate } else { 23647c478bd9Sstevel@tonic-gate tuple.Attributes = 0; 23657c478bd9Sstevel@tonic-gate tuple.DesiredTuple = CISTPL_JEDEC_A; 23667c478bd9Sstevel@tonic-gate if ((i = csx_GetFirstTuple(handle, &tuple)) == 23677c478bd9Sstevel@tonic-gate SUCCESS) { 23687c478bd9Sstevel@tonic-gate i = csx_Parse_CISTPL_JEDEC_A(handle, &tuple, 23697c478bd9Sstevel@tonic-gate &jedec); 23707c478bd9Sstevel@tonic-gate if (i == SUCCESS) { 23717c478bd9Sstevel@tonic-gate (void) sprintf(info->pd_bind_name, "%s%x,%x", 23725c066ec2SJerry Gilliam PCMDEV_NAMEPREF, 23735c066ec2SJerry Gilliam jedec.jid[0].id, jedec.jid[0].info); 23747c478bd9Sstevel@tonic-gate info->pd_flags |= PCM_NAME_1275; 23757c478bd9Sstevel@tonic-gate } 23767c478bd9Sstevel@tonic-gate } 23777c478bd9Sstevel@tonic-gate } 23787c478bd9Sstevel@tonic-gate } 23797c478bd9Sstevel@tonic-gate 23807c478bd9Sstevel@tonic-gate void 23817c478bd9Sstevel@tonic-gate pcmcia_vers1_name(int socket, struct pcm_device_info *info, 2382d3d50737SRafael Vanoni client_handle_t handle) 23837c478bd9Sstevel@tonic-gate { 23847c478bd9Sstevel@tonic-gate cistpl_vers_1_t vers1; 23857c478bd9Sstevel@tonic-gate tuple_t tuple; 23867c478bd9Sstevel@tonic-gate int which = 0; 23877c478bd9Sstevel@tonic-gate int i, len, space; 23887c478bd9Sstevel@tonic-gate 23897c478bd9Sstevel@tonic-gate tuple.Socket = socket; 23907c478bd9Sstevel@tonic-gate info->pd_vers1_name[0] = '\0'; 23917c478bd9Sstevel@tonic-gate 23927c478bd9Sstevel@tonic-gate /* Version 1 strings */ 23937c478bd9Sstevel@tonic-gate tuple.DesiredTuple = CISTPL_VERS_1; 23947c478bd9Sstevel@tonic-gate tuple.Attributes = 0; 23957c478bd9Sstevel@tonic-gate if (!which && 23965c066ec2SJerry Gilliam (i = csx_GetFirstTuple(handle, &tuple)) == SUCCESS) { 23977c478bd9Sstevel@tonic-gate i = csx_Parse_CISTPL_VERS_1(handle, &tuple, &vers1); 23987c478bd9Sstevel@tonic-gate if (i == SUCCESS) { 2399d3d50737SRafael Vanoni /* BEGIN CSTYLED */ 24007c478bd9Sstevel@tonic-gate for (i = 0, len = 0, space = 0; i < vers1.ns; i++) { 24017c478bd9Sstevel@tonic-gate if ((space + len + strlen(info->pd_vers1_name)) >= 24027c478bd9Sstevel@tonic-gate sizeof (info->pd_vers1_name)) 24037c478bd9Sstevel@tonic-gate break; 24047c478bd9Sstevel@tonic-gate if (space) { 24057c478bd9Sstevel@tonic-gate info->pd_vers1_name[len++] = ','; 24067c478bd9Sstevel@tonic-gate } 24077c478bd9Sstevel@tonic-gate (void) strcpy(info->pd_vers1_name + len, 24087c478bd9Sstevel@tonic-gate (char *)vers1.pi[i]); 24097c478bd9Sstevel@tonic-gate len += strlen((char *)vers1.pi[i]); 24107c478bd9Sstevel@tonic-gate /* strip trailing spaces off of string */ 24117c478bd9Sstevel@tonic-gate while (info->pd_vers1_name[len - 1] == ' ' && 24127c478bd9Sstevel@tonic-gate len > 0) 24137c478bd9Sstevel@tonic-gate len--; 24147c478bd9Sstevel@tonic-gate space = 1; 24157c478bd9Sstevel@tonic-gate } 2416d3d50737SRafael Vanoni /* END CSTYLED */ 24177c478bd9Sstevel@tonic-gate info->pd_vers1_name[len] = '\0'; 24187c478bd9Sstevel@tonic-gate info->pd_flags |= PCM_NAME_VERS1; 24197c478bd9Sstevel@tonic-gate } 24207c478bd9Sstevel@tonic-gate } 24217c478bd9Sstevel@tonic-gate } 24227c478bd9Sstevel@tonic-gate 24237c478bd9Sstevel@tonic-gate 24247c478bd9Sstevel@tonic-gate int 24257c478bd9Sstevel@tonic-gate pcmcia_get_funce(client_handle_t handle, tuple_t *tuple) 24267c478bd9Sstevel@tonic-gate { 24277c478bd9Sstevel@tonic-gate int ret = 0; 24287c478bd9Sstevel@tonic-gate 24297c478bd9Sstevel@tonic-gate tuple->Attributes = 0; 24307c478bd9Sstevel@tonic-gate while (csx_GetNextTuple(handle, tuple) == SUCCESS) { 24317c478bd9Sstevel@tonic-gate if (tuple->TupleCode == CISTPL_FUNCID) { 24327c478bd9Sstevel@tonic-gate break; 24337c478bd9Sstevel@tonic-gate } 24347c478bd9Sstevel@tonic-gate if (tuple->TupleCode == CISTPL_FUNCE) { 24357c478bd9Sstevel@tonic-gate ret = 1; 24367c478bd9Sstevel@tonic-gate break; 24377c478bd9Sstevel@tonic-gate } 24387c478bd9Sstevel@tonic-gate tuple->Attributes = 0; 24397c478bd9Sstevel@tonic-gate } 24407c478bd9Sstevel@tonic-gate return (ret); 24417c478bd9Sstevel@tonic-gate } 24427c478bd9Sstevel@tonic-gate 24437c478bd9Sstevel@tonic-gate char *pcmcia_lan_types[] = { 24447c478bd9Sstevel@tonic-gate "arcnet", 24457c478bd9Sstevel@tonic-gate "ethernet", 24467c478bd9Sstevel@tonic-gate "token-ring", 24477c478bd9Sstevel@tonic-gate "localtalk", 24487c478bd9Sstevel@tonic-gate "fddi", 24497c478bd9Sstevel@tonic-gate "atm", 24507c478bd9Sstevel@tonic-gate "wireless", 24517c478bd9Sstevel@tonic-gate "reserved" 24527c478bd9Sstevel@tonic-gate }; 24537c478bd9Sstevel@tonic-gate 24547c478bd9Sstevel@tonic-gate void 24557c478bd9Sstevel@tonic-gate pcmcia_generic_name(int socket, struct pcm_device_info *info, 24563f068ebdSToomas Soome client_handle_t handle) 24577c478bd9Sstevel@tonic-gate { 24587c478bd9Sstevel@tonic-gate cistpl_funcid_t funcid; 24597c478bd9Sstevel@tonic-gate cistpl_funce_t funce; 24607c478bd9Sstevel@tonic-gate tuple_t tuple; 24617c478bd9Sstevel@tonic-gate int which = 0; 24627c478bd9Sstevel@tonic-gate int i; 24637c478bd9Sstevel@tonic-gate 24647c478bd9Sstevel@tonic-gate tuple.Socket = socket; 24657c478bd9Sstevel@tonic-gate 24667c478bd9Sstevel@tonic-gate tuple.DesiredTuple = CISTPL_FUNCID; 24677c478bd9Sstevel@tonic-gate tuple.Attributes = 0; 24687c478bd9Sstevel@tonic-gate if ((i = csx_GetFirstTuple(handle, &tuple)) == 24697c478bd9Sstevel@tonic-gate SUCCESS) { 24707c478bd9Sstevel@tonic-gate /* 24717c478bd9Sstevel@tonic-gate * need to make sure that CISTPL_FUNCID is not 24727c478bd9Sstevel@tonic-gate * present in both a global and local CIS for MF 24737c478bd9Sstevel@tonic-gate * cards. 3COM seems to do this erroneously 24747c478bd9Sstevel@tonic-gate */ 24757c478bd9Sstevel@tonic-gate 24767c478bd9Sstevel@tonic-gate if (info->pd_flags & PCM_MULTI_FUNCTION && 24777c478bd9Sstevel@tonic-gate tuple.Flags & CISTPLF_GLOBAL_CIS) { 24787c478bd9Sstevel@tonic-gate tuple_t ltuple; 24797c478bd9Sstevel@tonic-gate ltuple = tuple; 24807c478bd9Sstevel@tonic-gate ltuple.DesiredTuple = CISTPL_FUNCID; 24817c478bd9Sstevel@tonic-gate ltuple.Attributes = 0; 24827c478bd9Sstevel@tonic-gate if ((i = csx_GetNextTuple(handle, <uple)) == 24837c478bd9Sstevel@tonic-gate SUCCESS) { 24847c478bd9Sstevel@tonic-gate /* this is the per-function funcid */ 24857c478bd9Sstevel@tonic-gate tuple = ltuple; 24867c478bd9Sstevel@tonic-gate } 24877c478bd9Sstevel@tonic-gate } 24887c478bd9Sstevel@tonic-gate 24897c478bd9Sstevel@tonic-gate i = csx_Parse_CISTPL_FUNCID(handle, &tuple, &funcid); 24907c478bd9Sstevel@tonic-gate if (i == SUCCESS) { 24917c478bd9Sstevel@tonic-gate /* in case no function extension */ 24927c478bd9Sstevel@tonic-gate if (funcid.function < PCM_GENNAME_SIZE) 24937c478bd9Sstevel@tonic-gate (void) strcpy(info->pd_generic_name, 24947c478bd9Sstevel@tonic-gate pcmcia_generic_names[funcid.function]); 24957c478bd9Sstevel@tonic-gate else 24967c478bd9Sstevel@tonic-gate (void) sprintf(info->pd_generic_name, 24975c066ec2SJerry Gilliam "class,%x", 24985c066ec2SJerry Gilliam funcid.function); 24997c478bd9Sstevel@tonic-gate } 25007c478bd9Sstevel@tonic-gate info->pd_type = funcid.function; 25017c478bd9Sstevel@tonic-gate switch (funcid.function) { 25027c478bd9Sstevel@tonic-gate case TPLFUNC_LAN: 25037c478bd9Sstevel@tonic-gate which = pcmcia_get_funce(handle, &tuple); 25047c478bd9Sstevel@tonic-gate if (which) { 25057c478bd9Sstevel@tonic-gate i = csx_Parse_CISTPL_FUNCE(handle, 25067c478bd9Sstevel@tonic-gate &tuple, 25077c478bd9Sstevel@tonic-gate &funce, TPLFUNC_LAN); 25087c478bd9Sstevel@tonic-gate if (i == SUCCESS) { 25097c478bd9Sstevel@tonic-gate i = funce.data.lan.tech; 2510582c04d6Srui wang - Sun Microsystems - Beijing China if (i >= sizeof (pcmcia_lan_types) / 25117c478bd9Sstevel@tonic-gate sizeof (char *)) { 25127c478bd9Sstevel@tonic-gate break; 25137c478bd9Sstevel@tonic-gate } 25147c478bd9Sstevel@tonic-gate (void) strcpy(info->pd_generic_name, 25155c066ec2SJerry Gilliam pcmcia_lan_types[i]); 25167c478bd9Sstevel@tonic-gate } 25177c478bd9Sstevel@tonic-gate } 25187c478bd9Sstevel@tonic-gate break; 25197c478bd9Sstevel@tonic-gate case TPLFUNC_VIDEO: 25207c478bd9Sstevel@tonic-gate #ifdef future_pcmcia_spec 25217c478bd9Sstevel@tonic-gate which = pcmcia_get_funce(handle, &tuple); 25227c478bd9Sstevel@tonic-gate if (which) { 25237c478bd9Sstevel@tonic-gate i = csx_Parse_CISTPL_FUNCE(handle, 25247c478bd9Sstevel@tonic-gate &tuple, 25257c478bd9Sstevel@tonic-gate &funce, TPLFUNC_VIDEO); 25267c478bd9Sstevel@tonic-gate if (i == SUCCESS) { 25277c478bd9Sstevel@tonic-gate i = funce.video.tech; 25287c478bd9Sstevel@tonic-gate if (i > sizeof (pcmcia_lan_types) / 25297c478bd9Sstevel@tonic-gate sizeof (char *)) { 25307c478bd9Sstevel@tonic-gate break; 25317c478bd9Sstevel@tonic-gate } 25327c478bd9Sstevel@tonic-gate (void) strcpy(info->pd_generic_names, 25335c066ec2SJerry Gilliam pcmcia_lan_types[i]); 25347c478bd9Sstevel@tonic-gate } 25357c478bd9Sstevel@tonic-gate } 25367c478bd9Sstevel@tonic-gate #endif 25377c478bd9Sstevel@tonic-gate break; 25387c478bd9Sstevel@tonic-gate } 25397c478bd9Sstevel@tonic-gate info->pd_flags |= PCM_NAME_GENERIC; 25407c478bd9Sstevel@tonic-gate } else { 25417c478bd9Sstevel@tonic-gate /* if no FUNCID, do we have CONFIG */ 25427c478bd9Sstevel@tonic-gate tuple.DesiredTuple = CISTPL_CONFIG; 25437c478bd9Sstevel@tonic-gate tuple.Attributes = 0; 25447c478bd9Sstevel@tonic-gate if (csx_GetFirstTuple(handle, &tuple) != SUCCESS) { 25457c478bd9Sstevel@tonic-gate info->pd_flags |= PCM_NO_CONFIG | PCM_NAME_GENERIC; 25467c478bd9Sstevel@tonic-gate (void) strcpy(info->pd_generic_name, 25475c066ec2SJerry Gilliam pcmcia_generic_names[PCM_TYPE_MEMORY]); 25487c478bd9Sstevel@tonic-gate info->pd_type = PCM_TYPE_MEMORY; 25497c478bd9Sstevel@tonic-gate } 25507c478bd9Sstevel@tonic-gate } 25517c478bd9Sstevel@tonic-gate } 25527c478bd9Sstevel@tonic-gate 25537c478bd9Sstevel@tonic-gate 25547c478bd9Sstevel@tonic-gate /* 25557c478bd9Sstevel@tonic-gate * pcmcia_add_compatible() 25567c478bd9Sstevel@tonic-gate * add the cached compatible property list. 25577c478bd9Sstevel@tonic-gate */ 25587c478bd9Sstevel@tonic-gate void 25597c478bd9Sstevel@tonic-gate pcmcia_add_compatible(dev_info_t *dip, struct pcm_device_info *info) 25607c478bd9Sstevel@tonic-gate { 25617c478bd9Sstevel@tonic-gate int length = 0, i; 25627c478bd9Sstevel@tonic-gate char buff[MAXNAMELEN]; 25637c478bd9Sstevel@tonic-gate char *compat_name[8]; 25647c478bd9Sstevel@tonic-gate int ci = 0; 25657c478bd9Sstevel@tonic-gate 25667c478bd9Sstevel@tonic-gate bzero(compat_name, sizeof (compat_name)); 25677c478bd9Sstevel@tonic-gate 25687c478bd9Sstevel@tonic-gate if (info->pd_flags & PCM_NAME_VERS1) { 25697c478bd9Sstevel@tonic-gate (void) sprintf(buff, "%s,%s", PCMDEV_NAMEPREF, 25707c478bd9Sstevel@tonic-gate info->pd_vers1_name); 25717c478bd9Sstevel@tonic-gate pcmcia_fix_string(buff); /* don't want spaces */ 25727c478bd9Sstevel@tonic-gate length = strlen(buff) + 1; 25737c478bd9Sstevel@tonic-gate compat_name[ci] = kmem_alloc(length, KM_SLEEP); 25747c478bd9Sstevel@tonic-gate (void) strcpy(compat_name[ci++], buff); 25757c478bd9Sstevel@tonic-gate } 25767c478bd9Sstevel@tonic-gate 25777c478bd9Sstevel@tonic-gate if ((info->pd_flags & (PCM_NAME_1275 | PCM_MULTI_FUNCTION)) == 25787c478bd9Sstevel@tonic-gate (PCM_NAME_1275 | PCM_MULTI_FUNCTION)) { 25797c478bd9Sstevel@tonic-gate (void) sprintf(buff, "%s,%x", info->pd_bind_name, 25807c478bd9Sstevel@tonic-gate info->pd_function); 25817c478bd9Sstevel@tonic-gate length = strlen(buff) + 1; 25827c478bd9Sstevel@tonic-gate compat_name[ci] = kmem_alloc(length, KM_SLEEP); 25837c478bd9Sstevel@tonic-gate (void) strcpy(compat_name[ci++], buff); 25847c478bd9Sstevel@tonic-gate } 25857c478bd9Sstevel@tonic-gate 25867c478bd9Sstevel@tonic-gate if (info->pd_flags & PCM_NAME_1275) { 25877c478bd9Sstevel@tonic-gate length = strlen(info->pd_bind_name) + 1; 25887c478bd9Sstevel@tonic-gate compat_name[ci] = kmem_alloc(length, KM_SLEEP); 25897c478bd9Sstevel@tonic-gate (void) strcpy(compat_name[ci++], info->pd_bind_name); 25907c478bd9Sstevel@tonic-gate } 25917c478bd9Sstevel@tonic-gate 25927c478bd9Sstevel@tonic-gate if (info->pd_flags & PCM_NAME_GENERIC) { 25937c478bd9Sstevel@tonic-gate if (strncmp(info->pd_generic_name, "class,", 6) == 0) { 25947c478bd9Sstevel@tonic-gate /* no generic without "pccard" */ 25957c478bd9Sstevel@tonic-gate (void) sprintf(buff, "%s%s", PCMDEV_NAMEPREF, 25965c066ec2SJerry Gilliam info->pd_generic_name); 25977c478bd9Sstevel@tonic-gate } else { 25987c478bd9Sstevel@tonic-gate /* first pccard,generic-name */ 25997c478bd9Sstevel@tonic-gate (void) sprintf(buff, "%s,%s", PCMDEV_NAMEPREF, 26005c066ec2SJerry Gilliam info->pd_generic_name); 26017c478bd9Sstevel@tonic-gate } 26027c478bd9Sstevel@tonic-gate length = strlen(buff) + 1; 26037c478bd9Sstevel@tonic-gate compat_name[ci] = kmem_alloc(length, KM_SLEEP); 26047c478bd9Sstevel@tonic-gate (void) strcpy(compat_name[ci++], buff); 26057c478bd9Sstevel@tonic-gate 26067c478bd9Sstevel@tonic-gate /* now the simple generic name */ 26077c478bd9Sstevel@tonic-gate length = strlen(info->pd_generic_name) + 1; 26087c478bd9Sstevel@tonic-gate compat_name[ci] = kmem_alloc(length, KM_SLEEP); 26097c478bd9Sstevel@tonic-gate (void) strcpy(compat_name[ci++], info->pd_generic_name); 26107c478bd9Sstevel@tonic-gate } 26117c478bd9Sstevel@tonic-gate 26127c478bd9Sstevel@tonic-gate if (info->pd_flags & PCM_NO_CONFIG) { 26137c478bd9Sstevel@tonic-gate char *mem = "pccard,memory"; 26147c478bd9Sstevel@tonic-gate /* 26157c478bd9Sstevel@tonic-gate * I/O cards are required to have a config tuple. 26167c478bd9Sstevel@tonic-gate * there are some that violate the spec and don't 26177c478bd9Sstevel@tonic-gate * but it is most likely that this is a memory card 26187c478bd9Sstevel@tonic-gate * so tag it as such. "memory" is more general 26197c478bd9Sstevel@tonic-gate * than other things so needs to come last. 26207c478bd9Sstevel@tonic-gate */ 26217c478bd9Sstevel@tonic-gate length = strlen(mem) + 1; 26227c478bd9Sstevel@tonic-gate compat_name[ci] = kmem_alloc(length, KM_SLEEP); 26237c478bd9Sstevel@tonic-gate (void) strcpy(compat_name[ci++], mem); 26247c478bd9Sstevel@tonic-gate } 26257c478bd9Sstevel@tonic-gate 26267c478bd9Sstevel@tonic-gate if (ci == 0) 26277c478bd9Sstevel@tonic-gate return; 26287c478bd9Sstevel@tonic-gate 26297c478bd9Sstevel@tonic-gate if (ndi_prop_update_string_array(DDI_DEV_T_NONE, dip, 26307c478bd9Sstevel@tonic-gate "compatible", (char **)compat_name, ci) != DDI_PROP_SUCCESS) 26317c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pcmcia: unable to create compatible prop"); 26327c478bd9Sstevel@tonic-gate 26337c478bd9Sstevel@tonic-gate for (i = 0; i < ci; i++) 26347c478bd9Sstevel@tonic-gate kmem_free(compat_name[i], strlen(compat_name[i]) + 1); 26357c478bd9Sstevel@tonic-gate } 26367c478bd9Sstevel@tonic-gate /* 26377c478bd9Sstevel@tonic-gate * CIS parsing and other PC Card specific code 26387c478bd9Sstevel@tonic-gate */ 26397c478bd9Sstevel@tonic-gate 26407c478bd9Sstevel@tonic-gate /* 26417c478bd9Sstevel@tonic-gate * pcmcia_get_mem_regs() 26427c478bd9Sstevel@tonic-gate */ 26437c478bd9Sstevel@tonic-gate static int 26447c478bd9Sstevel@tonic-gate pcmcia_get_mem_regs(struct pcm_regs *regs, struct pcm_device_info *info, 26453f068ebdSToomas Soome int type, int pctype) 26467c478bd9Sstevel@tonic-gate { 26477c478bd9Sstevel@tonic-gate int num_regs = 0; 26487c478bd9Sstevel@tonic-gate tuple_t tuple; 26497c478bd9Sstevel@tonic-gate cistpl_device_t device; 26507c478bd9Sstevel@tonic-gate uint32_t curr_base; 26517c478bd9Sstevel@tonic-gate int ret, len; 26527c478bd9Sstevel@tonic-gate int space; 26537c478bd9Sstevel@tonic-gate 26547c478bd9Sstevel@tonic-gate /* 26557c478bd9Sstevel@tonic-gate * current plan for reg spec: 26567c478bd9Sstevel@tonic-gate * device_a will be accumulated to determine max size of 26577c478bd9Sstevel@tonic-gate * attribute memory. device for common. Then config 26587c478bd9Sstevel@tonic-gate * tuples to get a worst case I/O size. 26597c478bd9Sstevel@tonic-gate */ 26607c478bd9Sstevel@tonic-gate bzero(&tuple, sizeof (tuple)); 26617c478bd9Sstevel@tonic-gate tuple.Socket = info->pd_socket; 26627c478bd9Sstevel@tonic-gate 26637c478bd9Sstevel@tonic-gate tuple.DesiredTuple = (cisdata_t)type; 26647c478bd9Sstevel@tonic-gate 26657c478bd9Sstevel@tonic-gate space = (type == CISTPL_DEVICE_A) ? PC_REG_SPACE_ATTRIBUTE : 26665c066ec2SJerry Gilliam PC_REG_SPACE_MEMORY; 26677c478bd9Sstevel@tonic-gate if ((ret = csx_GetFirstTuple(info->pd_handle, &tuple)) == CS_SUCCESS) { 26687c478bd9Sstevel@tonic-gate bzero(&device, sizeof (device)); 26697c478bd9Sstevel@tonic-gate 26707c478bd9Sstevel@tonic-gate if (type == CISTPL_DEVICE) 26717c478bd9Sstevel@tonic-gate ret = csx_Parse_CISTPL_DEVICE(info->pd_handle, &tuple, 26727c478bd9Sstevel@tonic-gate &device); 26737c478bd9Sstevel@tonic-gate else 26747c478bd9Sstevel@tonic-gate ret = csx_Parse_CISTPL_DEVICE_A(info->pd_handle, &tuple, 26757c478bd9Sstevel@tonic-gate &device); 26767c478bd9Sstevel@tonic-gate 26777c478bd9Sstevel@tonic-gate if (ret == CS_SUCCESS) { 2678d3d50737SRafael Vanoni curr_base = 0; 2679d3d50737SRafael Vanoni for (ret = 0; ret < device.num_devices; ret++) { 2680d3d50737SRafael Vanoni /* need to order these for real mem first */ 2681d3d50737SRafael Vanoni if (device.devnode[ret].type != 2682d3d50737SRafael Vanoni CISTPL_DEVICE_DTYPE_NULL) { 2683d3d50737SRafael Vanoni /* how to represent types??? */ 2684d3d50737SRafael Vanoni regs[num_regs].phys_hi = 2685d3d50737SRafael Vanoni PC_REG_PHYS_HI(0, 0, 26867c478bd9Sstevel@tonic-gate pctype, 26877c478bd9Sstevel@tonic-gate space, 26887c478bd9Sstevel@tonic-gate info->pd_socket, 26897c478bd9Sstevel@tonic-gate info->pd_function, 26907c478bd9Sstevel@tonic-gate 0); 2691d3d50737SRafael Vanoni regs[num_regs].phys_lo = curr_base; 2692d3d50737SRafael Vanoni len = device.devnode[ret].size_in_bytes; 2693d3d50737SRafael Vanoni curr_base += len; 2694d3d50737SRafael Vanoni regs[num_regs].phys_len = len; 2695d3d50737SRafael Vanoni num_regs++; 2696d3d50737SRafael Vanoni } else { 2697d3d50737SRafael Vanoni /* 2698d3d50737SRafael Vanoni * NULL device is a "hole" 2699d3d50737SRafael Vanoni */ 2700d3d50737SRafael Vanoni curr_base += 27017c478bd9Sstevel@tonic-gate device.devnode[ret].size_in_bytes; 2702d3d50737SRafael Vanoni } 27037c478bd9Sstevel@tonic-gate } 2704d3d50737SRafael Vanoni } 27057c478bd9Sstevel@tonic-gate } 27067c478bd9Sstevel@tonic-gate return (num_regs); 27077c478bd9Sstevel@tonic-gate } 27087c478bd9Sstevel@tonic-gate 27097c478bd9Sstevel@tonic-gate /* 27107c478bd9Sstevel@tonic-gate * 27117c478bd9Sstevel@tonic-gate */ 27127c478bd9Sstevel@tonic-gate static int 27137c478bd9Sstevel@tonic-gate pcmcia_get_io_regs(struct pcm_regs *regs, struct pcm_device_info *info, 27143f068ebdSToomas Soome int pctype) 27157c478bd9Sstevel@tonic-gate { 27167c478bd9Sstevel@tonic-gate int num_regs = 0; 27177c478bd9Sstevel@tonic-gate tuple_t tuple; 27187c478bd9Sstevel@tonic-gate uint32_t curr_base; 27197c478bd9Sstevel@tonic-gate int len, curr, i, curr_len; 27207c478bd9Sstevel@tonic-gate cistpl_config_t config; 27217c478bd9Sstevel@tonic-gate cistpl_cftable_entry_t cftable; 27227c478bd9Sstevel@tonic-gate struct pcm_regs tmp[16]; 27237c478bd9Sstevel@tonic-gate int found = 0; 27247c478bd9Sstevel@tonic-gate 27257c478bd9Sstevel@tonic-gate bzero(&tuple, sizeof (tuple)); 27267c478bd9Sstevel@tonic-gate tuple.DesiredTuple = CISTPL_CONFIG; 27277c478bd9Sstevel@tonic-gate tuple.Socket = info->pd_socket; 27287c478bd9Sstevel@tonic-gate tuple.Attributes = 0; 27297c478bd9Sstevel@tonic-gate curr_base = 0; 27307c478bd9Sstevel@tonic-gate len = 0; 27317c478bd9Sstevel@tonic-gate 27327c478bd9Sstevel@tonic-gate if (csx_GetFirstTuple(info->pd_handle, &tuple) == CS_SUCCESS) { 2733d3d50737SRafael Vanoni if (csx_Parse_CISTPL_CONFIG(info->pd_handle, 2734d3d50737SRafael Vanoni &tuple, &config) != CS_SUCCESS) { 2735d3d50737SRafael Vanoni info->pd_flags |= PCM_NO_CONFIG; /* must be memory */ 2736d3d50737SRafael Vanoni return (0); 2737d3d50737SRafael Vanoni } 2738d3d50737SRafael Vanoni curr = 0; 2739d3d50737SRafael Vanoni 2740d3d50737SRafael Vanoni tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; 2741d3d50737SRafael Vanoni tuple.Socket = info->pd_socket; 2742d3d50737SRafael Vanoni tuple.Attributes = 0; 2743d3d50737SRafael Vanoni bzero(tmp, sizeof (tmp)); 27447c478bd9Sstevel@tonic-gate 27455c066ec2SJerry Gilliam while (csx_GetNextTuple(info->pd_handle, &tuple) == CS_SUCCESS) { 2746d3d50737SRafael Vanoni bzero(&cftable, sizeof (cftable)); 2747d3d50737SRafael Vanoni 2748d3d50737SRafael Vanoni if (csx_Parse_CISTPL_CFTABLE_ENTRY(info->pd_handle, 2749d3d50737SRafael Vanoni &tuple, &cftable) == CS_SUCCESS) { 2750d3d50737SRafael Vanoni 2751d3d50737SRafael Vanoni /* BEGIN CSTYLED */ 27527c478bd9Sstevel@tonic-gate if (cftable.flags & CISTPL_CFTABLE_TPCE_FS_IO) { 27537c478bd9Sstevel@tonic-gate /* we have an I/O entry */ 27547c478bd9Sstevel@tonic-gate if (cftable.io.flags & 27557c478bd9Sstevel@tonic-gate CISTPL_CFTABLE_TPCE_FS_IO_RANGE) { 27567c478bd9Sstevel@tonic-gate len = cftable.io.addr_lines; 27577c478bd9Sstevel@tonic-gate if (len != 0) 27587c478bd9Sstevel@tonic-gate len = 1 << len; 27597c478bd9Sstevel@tonic-gate for (i = 0; i < cftable.io.ranges && curr < 16; i++) { 27607c478bd9Sstevel@tonic-gate curr_base = cftable.io.range[i].addr; 27617c478bd9Sstevel@tonic-gate curr_len = cftable.io.range[i].length; 27627c478bd9Sstevel@tonic-gate if (curr_len == 0) 27637c478bd9Sstevel@tonic-gate curr_len = len; 27647c478bd9Sstevel@tonic-gate if (len != 0 || cftable.io.addr_lines == 0) { 27657c478bd9Sstevel@tonic-gate /* we have potential relocation */ 27667c478bd9Sstevel@tonic-gate int mask; 27677c478bd9Sstevel@tonic-gate mask = cftable.io.addr_lines ? 27685c066ec2SJerry Gilliam cftable.io.addr_lines : genp2(len); 27697c478bd9Sstevel@tonic-gate mask = genmask(mask); 27707c478bd9Sstevel@tonic-gate if ((mask & curr_base) == 0) { 27717c478bd9Sstevel@tonic-gate /* more accurate length */ 27727c478bd9Sstevel@tonic-gate regs->phys_len = curr_len; 27737c478bd9Sstevel@tonic-gate regs->phys_lo = 0; 27747c478bd9Sstevel@tonic-gate regs->phys_hi = 27757c478bd9Sstevel@tonic-gate PC_REG_PHYS_HI(0, 27765c066ec2SJerry Gilliam 0, 27775c066ec2SJerry Gilliam pctype, 27785c066ec2SJerry Gilliam PC_REG_SPACE_IO, 27795c066ec2SJerry Gilliam info->pd_socket, 27805c066ec2SJerry Gilliam info->pd_function, 27815c066ec2SJerry Gilliam 0); 27827c478bd9Sstevel@tonic-gate num_regs++; 27837c478bd9Sstevel@tonic-gate found = 2; 27847c478bd9Sstevel@tonic-gate break; 27857c478bd9Sstevel@tonic-gate } 27867c478bd9Sstevel@tonic-gate } 27877c478bd9Sstevel@tonic-gate tmp[curr].phys_len = curr_len; 27887c478bd9Sstevel@tonic-gate tmp[curr].phys_lo = curr_base; 27897c478bd9Sstevel@tonic-gate curr++; 27907c478bd9Sstevel@tonic-gate found = 1; 27917c478bd9Sstevel@tonic-gate } 27927c478bd9Sstevel@tonic-gate if (found == 2) 27937c478bd9Sstevel@tonic-gate break; 27947c478bd9Sstevel@tonic-gate } else { 27957c478bd9Sstevel@tonic-gate /* no I/O range so just a mask */ 27967c478bd9Sstevel@tonic-gate regs->phys_len = 1 << cftable.io.addr_lines; 27977c478bd9Sstevel@tonic-gate regs->phys_hi = 27985c066ec2SJerry Gilliam PC_REG_PHYS_HI(0, 27995c066ec2SJerry Gilliam 0, 28005c066ec2SJerry Gilliam pctype, 28015c066ec2SJerry Gilliam PC_REG_SPACE_IO, 28025c066ec2SJerry Gilliam info->pd_socket, 28035c066ec2SJerry Gilliam info->pd_function, 28045c066ec2SJerry Gilliam 0); 28057c478bd9Sstevel@tonic-gate regs->phys_lo = 0; 28067c478bd9Sstevel@tonic-gate num_regs++; 28077c478bd9Sstevel@tonic-gate regs++; 28087c478bd9Sstevel@tonic-gate /* quit on "good" entry */ 28097c478bd9Sstevel@tonic-gate break; 28107c478bd9Sstevel@tonic-gate } 28117c478bd9Sstevel@tonic-gate /* was this the last CFTABLE Entry? */ 28127c478bd9Sstevel@tonic-gate if (config.last == cftable.index) 28137c478bd9Sstevel@tonic-gate break; 28147c478bd9Sstevel@tonic-gate } 2815d3d50737SRafael Vanoni /* END CSTYLE */ 2816d3d50737SRafael Vanoni } 28177c478bd9Sstevel@tonic-gate } 28187c478bd9Sstevel@tonic-gate if (found == 1) { 28197c478bd9Sstevel@tonic-gate /* 28207c478bd9Sstevel@tonic-gate * have some non-relocatable values 28217c478bd9Sstevel@tonic-gate * so we include them all for now 28227c478bd9Sstevel@tonic-gate */ 28237c478bd9Sstevel@tonic-gate for (i = 0; i < curr && num_regs < 8; i++) { 28247c478bd9Sstevel@tonic-gate regs->phys_len = tmp[i].phys_len; 28257c478bd9Sstevel@tonic-gate regs->phys_lo = tmp[i].phys_lo; 28267c478bd9Sstevel@tonic-gate regs->phys_hi = PC_REG_PHYS_HI(1, 0, pctype, 28277c478bd9Sstevel@tonic-gate PC_REG_SPACE_IO, info->pd_socket, 28287c478bd9Sstevel@tonic-gate info->pd_function, 0); 28297c478bd9Sstevel@tonic-gate regs++; 28307c478bd9Sstevel@tonic-gate num_regs++; 28317c478bd9Sstevel@tonic-gate } 28327c478bd9Sstevel@tonic-gate } 28337c478bd9Sstevel@tonic-gate } 28347c478bd9Sstevel@tonic-gate return (num_regs); 28357c478bd9Sstevel@tonic-gate } 28367c478bd9Sstevel@tonic-gate 28377c478bd9Sstevel@tonic-gate /* 28387c478bd9Sstevel@tonic-gate * pcmcia_create_regs() 28397c478bd9Sstevel@tonic-gate * create a valid set of regspecs for the card 28407c478bd9Sstevel@tonic-gate * The first one is always for CIS access and naming 28417c478bd9Sstevel@tonic-gate */ 28427c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 28437c478bd9Sstevel@tonic-gate static void 28447c478bd9Sstevel@tonic-gate pcmcia_find_regs(dev_info_t *dip, struct pcm_device_info *info, 28457c478bd9Sstevel@tonic-gate struct pcmcia_parent_private *ppd) 28467c478bd9Sstevel@tonic-gate { 28477c478bd9Sstevel@tonic-gate struct pcm_regs regs[32]; /* assume worst case */ 28487c478bd9Sstevel@tonic-gate int num_regs = 0; 28497c478bd9Sstevel@tonic-gate int len; 28507c478bd9Sstevel@tonic-gate int bustype; 28517c478bd9Sstevel@tonic-gate 28527c478bd9Sstevel@tonic-gate if (ppd->ppd_flags & PPD_CARD_CARDBUS) { 28537c478bd9Sstevel@tonic-gate /* always have a CIS map */ 28547c478bd9Sstevel@tonic-gate regs[0].phys_hi = PC_REG_PHYS_HI(0, 0, PC_REG_TYPE_CARDBUS, 28555c066ec2SJerry Gilliam PC_REG_SPACE_CONFIG, 28565c066ec2SJerry Gilliam info->pd_socket, 28575c066ec2SJerry Gilliam info->pd_function, 0); 28587c478bd9Sstevel@tonic-gate bustype = PC_REG_TYPE_CARDBUS; 28597c478bd9Sstevel@tonic-gate } else { 28607c478bd9Sstevel@tonic-gate /* always have a CIS map */ 28617c478bd9Sstevel@tonic-gate regs[0].phys_hi = PC_REG_PHYS_HI(0, 0, PC_REG_TYPE_16BIT, 28625c066ec2SJerry Gilliam PC_REG_SPACE_ATTRIBUTE, 28635c066ec2SJerry Gilliam info->pd_socket, 28645c066ec2SJerry Gilliam info->pd_function, 0); 28657c478bd9Sstevel@tonic-gate bustype = PC_REG_TYPE_16BIT; 28667c478bd9Sstevel@tonic-gate } 28677c478bd9Sstevel@tonic-gate regs[0].phys_lo = 0; /* always starts at zero */ 28687c478bd9Sstevel@tonic-gate regs[0].phys_len = 0; 28697c478bd9Sstevel@tonic-gate num_regs++; 28707c478bd9Sstevel@tonic-gate /* 28717c478bd9Sstevel@tonic-gate * need to search CIS for other memory instances 28727c478bd9Sstevel@tonic-gate */ 28737c478bd9Sstevel@tonic-gate 28747c478bd9Sstevel@tonic-gate if (info->pd_flags & PCM_OTHER_NOCIS) { 28757c478bd9Sstevel@tonic-gate /* special case of memory only card without CIS */ 28767c478bd9Sstevel@tonic-gate regs[1].phys_hi = PC_REG_PHYS_HI(0, 0, PC_REG_TYPE_16BIT, 28775c066ec2SJerry Gilliam PC_REG_SPACE_MEMORY, 28785c066ec2SJerry Gilliam info->pd_socket, 28795c066ec2SJerry Gilliam info->pd_function, 0); 28807c478bd9Sstevel@tonic-gate regs[1].phys_lo = 0; 28817c478bd9Sstevel@tonic-gate regs[1].phys_len = PCM_MAX_R2_MEM; 28827c478bd9Sstevel@tonic-gate num_regs++; 28837c478bd9Sstevel@tonic-gate } else { 28847c478bd9Sstevel@tonic-gate /* 28857c478bd9Sstevel@tonic-gate * want to get any other memory and/or I/O regions 28867c478bd9Sstevel@tonic-gate * on the card and represent them here. 28877c478bd9Sstevel@tonic-gate */ 28887c478bd9Sstevel@tonic-gate num_regs += pcmcia_get_mem_regs(®s[num_regs], info, 28895c066ec2SJerry Gilliam CISTPL_DEVICE_A, bustype); 28907c478bd9Sstevel@tonic-gate num_regs += pcmcia_get_mem_regs(®s[num_regs], info, 28915c066ec2SJerry Gilliam CISTPL_DEVICE, bustype); 28927c478bd9Sstevel@tonic-gate 28937c478bd9Sstevel@tonic-gate /* now look for an I/O space to configure */ 28947c478bd9Sstevel@tonic-gate num_regs += pcmcia_get_io_regs(®s[num_regs], info, 28955c066ec2SJerry Gilliam bustype); 28967c478bd9Sstevel@tonic-gate 28977c478bd9Sstevel@tonic-gate } 28987c478bd9Sstevel@tonic-gate 28997c478bd9Sstevel@tonic-gate len = num_regs * sizeof (uint32_t) * 3; 29007c478bd9Sstevel@tonic-gate ppd->ppd_nreg = num_regs; 29017c478bd9Sstevel@tonic-gate ppd->ppd_reg = kmem_alloc(len, KM_SLEEP); 29027c478bd9Sstevel@tonic-gate bcopy(regs, ppd->ppd_reg, len); 29037c478bd9Sstevel@tonic-gate len = sizeof (struct pcm_regs) * ppd->ppd_nreg; 29047c478bd9Sstevel@tonic-gate ppd->ppd_assigned = kmem_zalloc(len, KM_SLEEP); 29057c478bd9Sstevel@tonic-gate } 29067c478bd9Sstevel@tonic-gate 29077c478bd9Sstevel@tonic-gate 29087c478bd9Sstevel@tonic-gate /* 29097c478bd9Sstevel@tonic-gate * pcmcia_need_intr() 29107c478bd9Sstevel@tonic-gate * check to see if an interrupt tuple exists. 29117c478bd9Sstevel@tonic-gate * existence means we need one in the intrspec. 29127c478bd9Sstevel@tonic-gate */ 29137c478bd9Sstevel@tonic-gate static int 29147c478bd9Sstevel@tonic-gate pcmcia_need_intr(int socket, struct pcm_device_info *info) 29157c478bd9Sstevel@tonic-gate { 29167c478bd9Sstevel@tonic-gate cistpl_config_t config; 29177c478bd9Sstevel@tonic-gate cistpl_cftable_entry_t cftable; 29187c478bd9Sstevel@tonic-gate tuple_t tuple; 29197c478bd9Sstevel@tonic-gate int i; 29207c478bd9Sstevel@tonic-gate 29217c478bd9Sstevel@tonic-gate bzero(&tuple, sizeof (tuple)); 29227c478bd9Sstevel@tonic-gate tuple.DesiredTuple = CISTPL_CONFIG; 29237c478bd9Sstevel@tonic-gate tuple.Socket = socket; 29247c478bd9Sstevel@tonic-gate tuple.Attributes = 0; 29257c478bd9Sstevel@tonic-gate if (csx_GetFirstTuple(info->pd_handle, &tuple) != CS_SUCCESS) { 29267c478bd9Sstevel@tonic-gate return (0); 29277c478bd9Sstevel@tonic-gate } 29287c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 29297c478bd9Sstevel@tonic-gate if (pcmcia_debug) { 29307c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia_need_intr: have config tuple\n"); 29317c478bd9Sstevel@tonic-gate } 29327c478bd9Sstevel@tonic-gate #endif 29337c478bd9Sstevel@tonic-gate bzero(&config, sizeof (config)); 29347c478bd9Sstevel@tonic-gate if (csx_Parse_CISTPL_CONFIG(info->pd_handle, 29357c478bd9Sstevel@tonic-gate &tuple, &config) != CS_SUCCESS) { 29367c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pcmcia: config failed to parse\n"); 29377c478bd9Sstevel@tonic-gate return (0); 29387c478bd9Sstevel@tonic-gate } 29397c478bd9Sstevel@tonic-gate 29407c478bd9Sstevel@tonic-gate for (cftable.index = (int)-1, i = -1; 29415c066ec2SJerry Gilliam i != config.last; i = cftable.index) { 29427c478bd9Sstevel@tonic-gate tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; 29437c478bd9Sstevel@tonic-gate tuple.Attributes = 0; 29447c478bd9Sstevel@tonic-gate if (csx_GetNextTuple(info->pd_handle, 29457c478bd9Sstevel@tonic-gate &tuple) != CS_SUCCESS) { 29467c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pcmcia: get cftable failed\n"); 29477c478bd9Sstevel@tonic-gate break; 29487c478bd9Sstevel@tonic-gate } 29497c478bd9Sstevel@tonic-gate bzero(&cftable, sizeof (cftable)); 29507c478bd9Sstevel@tonic-gate if (csx_Parse_CISTPL_CFTABLE_ENTRY(info->pd_handle, 29517c478bd9Sstevel@tonic-gate &tuple, &cftable) != 29527c478bd9Sstevel@tonic-gate CS_SUCCESS) { 29537c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pcmcia: parse cftable failed\n"); 29547c478bd9Sstevel@tonic-gate break; 29557c478bd9Sstevel@tonic-gate } 29567c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 29577c478bd9Sstevel@tonic-gate if (pcmcia_debug) 29587c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "\t%x: flags=%x (%x)\n", 29595c066ec2SJerry Gilliam i, cftable.flags, 29605c066ec2SJerry Gilliam cftable.flags & CISTPL_CFTABLE_TPCE_FS_IRQ); 29617c478bd9Sstevel@tonic-gate #endif 29627c478bd9Sstevel@tonic-gate if (cftable.flags & CISTPL_CFTABLE_TPCE_FS_IRQ) 29637c478bd9Sstevel@tonic-gate return (1); 29647c478bd9Sstevel@tonic-gate } 29657c478bd9Sstevel@tonic-gate return (0); 29667c478bd9Sstevel@tonic-gate 29677c478bd9Sstevel@tonic-gate } 29687c478bd9Sstevel@tonic-gate 29697c478bd9Sstevel@tonic-gate /* 29707c478bd9Sstevel@tonic-gate * pcmcia_num_funcs() 29717c478bd9Sstevel@tonic-gate * look for a CISTPL_LONGLINK_MFC 29727c478bd9Sstevel@tonic-gate * if there is one, return the number of functions 29737c478bd9Sstevel@tonic-gate * if there isn't one, then there is one function 29747c478bd9Sstevel@tonic-gate */ 29757c478bd9Sstevel@tonic-gate static int 29767c478bd9Sstevel@tonic-gate pcmcia_num_funcs(int socket, client_handle_t handle) 29777c478bd9Sstevel@tonic-gate { 29787c478bd9Sstevel@tonic-gate int count = 1; 29797c478bd9Sstevel@tonic-gate cistpl_longlink_mfc_t mfc; 29807c478bd9Sstevel@tonic-gate tuple_t tuple; 29817c478bd9Sstevel@tonic-gate 29827c478bd9Sstevel@tonic-gate bzero(&tuple, sizeof (tuple_t)); 29837c478bd9Sstevel@tonic-gate tuple.DesiredTuple = CISTPL_LONGLINK_MFC; 29847c478bd9Sstevel@tonic-gate tuple.Socket = socket; 29857c478bd9Sstevel@tonic-gate tuple.Attributes = 0; 29867c478bd9Sstevel@tonic-gate if (csx_GetFirstTuple(handle, &tuple) == CS_SUCCESS) { 29877c478bd9Sstevel@tonic-gate /* this is a multifunction card */ 29887c478bd9Sstevel@tonic-gate if (csx_ParseTuple(handle, &tuple, (cisparse_t *)&mfc, 29897c478bd9Sstevel@tonic-gate CISTPL_LONGLINK_MFC) == CS_SUCCESS) { 29907c478bd9Sstevel@tonic-gate count = mfc.nfuncs; 29917c478bd9Sstevel@tonic-gate } 29927c478bd9Sstevel@tonic-gate } 29937c478bd9Sstevel@tonic-gate return (count); 29947c478bd9Sstevel@tonic-gate } 29957c478bd9Sstevel@tonic-gate 29967c478bd9Sstevel@tonic-gate client_handle_t pcmcia_cs_handle; 29977c478bd9Sstevel@tonic-gate 29987c478bd9Sstevel@tonic-gate /* 29997c478bd9Sstevel@tonic-gate * pcmcia_create_dev_info(socket) 30007c478bd9Sstevel@tonic-gate * either find or create the device information structure 30017c478bd9Sstevel@tonic-gate * for the card(s) just inserted. We don't care about removal yet. 30027c478bd9Sstevel@tonic-gate * In any case, we will only do this at CS request 30037c478bd9Sstevel@tonic-gate */ 30047c478bd9Sstevel@tonic-gate static void 30057c478bd9Sstevel@tonic-gate pcmcia_create_dev_info(int socket) 30067c478bd9Sstevel@tonic-gate { 30077c478bd9Sstevel@tonic-gate struct pcm_device_info card_info; 30087c478bd9Sstevel@tonic-gate client_reg_t reg; 30097c478bd9Sstevel@tonic-gate cisinfo_t cisinfo; 30107c478bd9Sstevel@tonic-gate int i; 30117c478bd9Sstevel@tonic-gate dev_info_t *pdip; 30127c478bd9Sstevel@tonic-gate static int handle_def = 0; 30137c478bd9Sstevel@tonic-gate 30147c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 30157c478bd9Sstevel@tonic-gate if (pcmcia_debug) 30167c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "create dev_info_t for device in socket %d\n", 30175c066ec2SJerry Gilliam socket); 30187c478bd9Sstevel@tonic-gate #endif 30197c478bd9Sstevel@tonic-gate 30207c478bd9Sstevel@tonic-gate /* 30217c478bd9Sstevel@tonic-gate * before we can do anything else, we need the parent 30227c478bd9Sstevel@tonic-gate * devinfo of the socket. This gets things in the right 30237c478bd9Sstevel@tonic-gate * place in the device tree. 30247c478bd9Sstevel@tonic-gate */ 30257c478bd9Sstevel@tonic-gate 30267c478bd9Sstevel@tonic-gate pdip = pcm_find_parent_dip(socket); 30277c478bd9Sstevel@tonic-gate if (pdip == NULL) 30287c478bd9Sstevel@tonic-gate return; 30297c478bd9Sstevel@tonic-gate 30307c478bd9Sstevel@tonic-gate /* Card Services calls needed to get CIS info */ 30317c478bd9Sstevel@tonic-gate reg.dip = NULL; 30327c478bd9Sstevel@tonic-gate reg.Attributes = INFO_SOCKET_SERVICES; 30337c478bd9Sstevel@tonic-gate reg.EventMask = 0; 30347c478bd9Sstevel@tonic-gate reg.event_handler = NULL; 30357c478bd9Sstevel@tonic-gate reg.Version = CS_VERSION; 30367c478bd9Sstevel@tonic-gate 30377c478bd9Sstevel@tonic-gate bzero(&card_info, sizeof (card_info)); 30387c478bd9Sstevel@tonic-gate 30397c478bd9Sstevel@tonic-gate if (handle_def == 0) { 30407c478bd9Sstevel@tonic-gate if (csx_RegisterClient(&pcmcia_cs_handle, 30417c478bd9Sstevel@tonic-gate ®) != CS_SUCCESS) { 30427c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 30437c478bd9Sstevel@tonic-gate if (pcmcia_debug) 30447c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 30455c066ec2SJerry Gilliam "pcmcia: RegisterClient failed\n"); 30467c478bd9Sstevel@tonic-gate #endif 30477c478bd9Sstevel@tonic-gate return; 30487c478bd9Sstevel@tonic-gate } 30497c478bd9Sstevel@tonic-gate handle_def++; 30507c478bd9Sstevel@tonic-gate } 30517c478bd9Sstevel@tonic-gate card_info.pd_handle = pcmcia_cs_handle; 30527c478bd9Sstevel@tonic-gate 30537c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 30547c478bd9Sstevel@tonic-gate if (pcmcia_debug) 30557c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 30565c066ec2SJerry Gilliam "pcmcia_create_dev_info: handle = %x\n", 30575c066ec2SJerry Gilliam (int)card_info.pd_handle); 30587c478bd9Sstevel@tonic-gate #endif 30597c478bd9Sstevel@tonic-gate card_info.pd_type = -1; /* no type to start */ 30607c478bd9Sstevel@tonic-gate card_info.pd_socket = socket; 30617c478bd9Sstevel@tonic-gate card_info.pd_function = 0; 30627c478bd9Sstevel@tonic-gate pcmcia_sockets[socket]->ls_functions = 1; /* default */ 30637c478bd9Sstevel@tonic-gate 30647c478bd9Sstevel@tonic-gate cisinfo.Socket = socket; 30657c478bd9Sstevel@tonic-gate 30667c478bd9Sstevel@tonic-gate if ((i = csx_ValidateCIS(card_info.pd_handle, 30677c478bd9Sstevel@tonic-gate &cisinfo)) != SUCCESS || 30687c478bd9Sstevel@tonic-gate cisinfo.Tuples == 0) { 30697c478bd9Sstevel@tonic-gate /* no CIS means memory */ 30707c478bd9Sstevel@tonic-gate (void) strcpy(card_info.pd_generic_name, "memory"); 30717c478bd9Sstevel@tonic-gate card_info.pd_flags |= PCM_NAME_GENERIC | 30725c066ec2SJerry Gilliam PCM_OTHER_NOCIS | PCM_NAME_1275; 30737c478bd9Sstevel@tonic-gate (void) strcpy(card_info.pd_bind_name, "pccard,memory"); 30747c478bd9Sstevel@tonic-gate (void) strcpy(card_info.pd_generic_name, "memory"); 30757c478bd9Sstevel@tonic-gate card_info.pd_type = PCM_TYPE_MEMORY; 30767c478bd9Sstevel@tonic-gate } else { 30777c478bd9Sstevel@tonic-gate int functions, lsocket; 30787c478bd9Sstevel@tonic-gate card_info.pd_tuples = cisinfo.Tuples; 30797c478bd9Sstevel@tonic-gate 30807c478bd9Sstevel@tonic-gate /* 30817c478bd9Sstevel@tonic-gate * how many functions on the card? 30827c478bd9Sstevel@tonic-gate * we need to know and then we do one 30837c478bd9Sstevel@tonic-gate * child node for each function using 30847c478bd9Sstevel@tonic-gate * the function specific tuples. 30857c478bd9Sstevel@tonic-gate */ 30867c478bd9Sstevel@tonic-gate lsocket = CS_MAKE_SOCKET_NUMBER(socket, CS_GLOBAL_CIS); 30877c478bd9Sstevel@tonic-gate functions = pcmcia_num_funcs(lsocket, 30887c478bd9Sstevel@tonic-gate card_info.pd_handle); 30897c478bd9Sstevel@tonic-gate pcmcia_sockets[socket]->ls_functions = functions; 30907c478bd9Sstevel@tonic-gate if (functions > 1) { 30917c478bd9Sstevel@tonic-gate card_info.pd_flags |= PCM_MULTI_FUNCTION; 30927c478bd9Sstevel@tonic-gate } 30937c478bd9Sstevel@tonic-gate for (i = 0; i < functions; i++) { 3094d3d50737SRafael Vanoni register int flags; 3095d3d50737SRafael Vanoni lsocket = CS_MAKE_SOCKET_NUMBER(socket, i); 3096d3d50737SRafael Vanoni card_info.pd_socket = socket; 3097d3d50737SRafael Vanoni card_info.pd_function = i; 30987c478bd9Sstevel@tonic-gate /* 30997c478bd9Sstevel@tonic-gate * new name construction 31007c478bd9Sstevel@tonic-gate */ 3101d3d50737SRafael Vanoni if (functions != 1) { 3102d3d50737SRafael Vanoni /* need per function handle */ 3103d3d50737SRafael Vanoni card_info.pd_function = i; 3104d3d50737SRafael Vanoni /* get new handle */ 3105d3d50737SRafael Vanoni } 3106d3d50737SRafael Vanoni pcmcia_1275_name(lsocket, &card_info, 31077c478bd9Sstevel@tonic-gate card_info.pd_handle); 3108d3d50737SRafael Vanoni pcmcia_vers1_name(lsocket, &card_info, 31097c478bd9Sstevel@tonic-gate card_info.pd_handle); 3110d3d50737SRafael Vanoni pcmcia_generic_name(lsocket, &card_info, 31117c478bd9Sstevel@tonic-gate card_info.pd_handle); 3112d3d50737SRafael Vanoni flags = card_info.pd_flags; 3113d3d50737SRafael Vanoni if (!(flags & PCM_NAME_1275)) { 3114d3d50737SRafael Vanoni if (flags & PCM_NAME_VERS1) { 3115d3d50737SRafael Vanoni (void) strcpy(card_info.pd_bind_name, 3116d3d50737SRafael Vanoni PCMDEV_NAMEPREF); 3117d3d50737SRafael Vanoni card_info.pd_bind_name[ 3118d3d50737SRafael Vanoni sizeof (PCMDEV_NAMEPREF)] = ','; 3119d3d50737SRafael Vanoni (void) strncpy(card_info.pd_bind_name + 3120d3d50737SRafael Vanoni sizeof (PCMDEV_NAMEPREF), 3121d3d50737SRafael Vanoni card_info.pd_vers1_name, 3122d3d50737SRafael Vanoni MODMAXNAMELEN - 3123d3d50737SRafael Vanoni sizeof (PCMDEV_NAMEPREF)); 3124d3d50737SRafael Vanoni pcmcia_fix_string(card_info.pd_bind_name); 3125d3d50737SRafael Vanoni } else { 3126d3d50737SRafael Vanoni /* 3127d3d50737SRafael Vanoni * have a CIS but not the right info 3128d3d50737SRafael Vanoni * so treat as generic "pccard" 3129d3d50737SRafael Vanoni */ 3130d3d50737SRafael Vanoni (void) strcpy(card_info.pd_generic_name, 3131d3d50737SRafael Vanoni "pccard,memory"); 3132d3d50737SRafael Vanoni card_info.pd_flags |= PCM_NAME_GENERIC; 3133d3d50737SRafael Vanoni (void) strcpy(card_info.pd_bind_name, 3134d3d50737SRafael Vanoni "pccard,memory"); 3135d3d50737SRafael Vanoni } 31367c478bd9Sstevel@tonic-gate } 3137d3d50737SRafael Vanoni pcmcia_init_devinfo(pdip, &card_info); 31387c478bd9Sstevel@tonic-gate } 31397c478bd9Sstevel@tonic-gate return; 31407c478bd9Sstevel@tonic-gate } 31417c478bd9Sstevel@tonic-gate 31427c478bd9Sstevel@tonic-gate pcmcia_init_devinfo(pdip, &card_info); 31437c478bd9Sstevel@tonic-gate } 31447c478bd9Sstevel@tonic-gate 31457c478bd9Sstevel@tonic-gate /* 31467c478bd9Sstevel@tonic-gate * pcmcia_init_devinfo() 31477c478bd9Sstevel@tonic-gate * if there isn't a device info structure, create one 31487c478bd9Sstevel@tonic-gate * if there is, we don't do much. 31497c478bd9Sstevel@tonic-gate * 31507c478bd9Sstevel@tonic-gate * Note: this will need updating as 1275 finalizes their spec. 31517c478bd9Sstevel@tonic-gate */ 31527c478bd9Sstevel@tonic-gate static void 31537c478bd9Sstevel@tonic-gate pcmcia_init_devinfo(dev_info_t *pdip, struct pcm_device_info *info) 31547c478bd9Sstevel@tonic-gate { 31557c478bd9Sstevel@tonic-gate int unit; 31567c478bd9Sstevel@tonic-gate dev_info_t *dip; 31577c478bd9Sstevel@tonic-gate char *name; 31587c478bd9Sstevel@tonic-gate struct pcmcia_parent_private *ppd; 31597c478bd9Sstevel@tonic-gate 31607c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 31617c478bd9Sstevel@tonic-gate if (pcmcia_debug) 31627c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "init_devinfo(%s, %d)\n", info->pd_bind_name, 31635c066ec2SJerry Gilliam info->pd_socket); 31647c478bd9Sstevel@tonic-gate #endif 31657c478bd9Sstevel@tonic-gate 31667c478bd9Sstevel@tonic-gate /* 31677c478bd9Sstevel@tonic-gate * find out if there is already an instance of this 31687c478bd9Sstevel@tonic-gate * device. We don't want to create a new one unnecessarily 31697c478bd9Sstevel@tonic-gate */ 31707c478bd9Sstevel@tonic-gate unit = CS_MAKE_SOCKET_NUMBER(info->pd_socket, info->pd_function); 31717c478bd9Sstevel@tonic-gate 31727c478bd9Sstevel@tonic-gate dip = pcm_find_devinfo(pdip, info, unit); 31737c478bd9Sstevel@tonic-gate if ((dip != NULL) && (ddi_getprop(DDI_DEV_T_NONE, dip, 31747c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, PCM_DEV_SOCKET, -1) != -1)) { 31757c478bd9Sstevel@tonic-gate /* it already exist but isn't a .conf file */ 31767c478bd9Sstevel@tonic-gate 31777c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 31787c478bd9Sstevel@tonic-gate if (pcmcia_debug) 31797c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "\tfound existing device node (%s)\n", 31805c066ec2SJerry Gilliam ddi_get_name(dip)); 31817c478bd9Sstevel@tonic-gate #endif 31827c478bd9Sstevel@tonic-gate if (strlen(info->pd_vers1_name) > 0) 31837c478bd9Sstevel@tonic-gate (void) ndi_prop_update_string(DDI_DEV_T_NONE, 31847c478bd9Sstevel@tonic-gate dip, PCM_DEV_MODEL, info->pd_vers1_name); 31857c478bd9Sstevel@tonic-gate 31867c478bd9Sstevel@tonic-gate ppd = (struct pcmcia_parent_private *) 31875c066ec2SJerry Gilliam ddi_get_parent_data(dip); 31887c478bd9Sstevel@tonic-gate 31897c478bd9Sstevel@tonic-gate pcmcia_sockets[info->pd_socket]->ls_dip[info->pd_function] = 31907c478bd9Sstevel@tonic-gate dip; 31917c478bd9Sstevel@tonic-gate 31927c478bd9Sstevel@tonic-gate ppd->ppd_active = 1; 31937c478bd9Sstevel@tonic-gate 31947c478bd9Sstevel@tonic-gate if (ndi_devi_online(dip, 0) == NDI_FAILURE) { 31957c478bd9Sstevel@tonic-gate pcmcia_sockets[info->pd_socket]-> \ 31967c478bd9Sstevel@tonic-gate ls_dip[info->pd_function] = NULL; 31977c478bd9Sstevel@tonic-gate ppd->ppd_active = 0; 31987c478bd9Sstevel@tonic-gate } 31997c478bd9Sstevel@tonic-gate } else { 32007c478bd9Sstevel@tonic-gate 32017c478bd9Sstevel@tonic-gate char *dtype; 32027c478bd9Sstevel@tonic-gate 32037c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 32047c478bd9Sstevel@tonic-gate if (pcmcia_debug) 32057c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia: create child [%s](%d): %s\n", 32067c478bd9Sstevel@tonic-gate info->pd_bind_name, info->pd_socket, 32077c478bd9Sstevel@tonic-gate info->pd_generic_name); 32087c478bd9Sstevel@tonic-gate #endif 32097c478bd9Sstevel@tonic-gate 32107c478bd9Sstevel@tonic-gate if (info->pd_flags & PCM_NAME_GENERIC) 32117c478bd9Sstevel@tonic-gate name = info->pd_generic_name; 32127c478bd9Sstevel@tonic-gate else 32137c478bd9Sstevel@tonic-gate name = info->pd_bind_name; 32147c478bd9Sstevel@tonic-gate 3215fa9e4066Sahrens if (ndi_devi_alloc(pdip, name, (pnode_t)DEVI_SID_NODEID, 32167c478bd9Sstevel@tonic-gate &dip) != 32177c478bd9Sstevel@tonic-gate NDI_SUCCESS) { 32187c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 32197c478bd9Sstevel@tonic-gate "pcmcia: unable to create device [%s](%d)\n", 32207c478bd9Sstevel@tonic-gate name, info->pd_socket); 32217c478bd9Sstevel@tonic-gate return; 32227c478bd9Sstevel@tonic-gate } 32237c478bd9Sstevel@tonic-gate /* 32247c478bd9Sstevel@tonic-gate * construct the "compatible" property if the device 32257c478bd9Sstevel@tonic-gate * has a generic name 32267c478bd9Sstevel@tonic-gate */ 32277c478bd9Sstevel@tonic-gate pcmcia_add_compatible(dip, info); 32287c478bd9Sstevel@tonic-gate 32297c478bd9Sstevel@tonic-gate ppd = kmem_zalloc(sizeof (struct pcmcia_parent_private), 32305c066ec2SJerry Gilliam KM_SLEEP); 32317c478bd9Sstevel@tonic-gate 32327c478bd9Sstevel@tonic-gate ppd->ppd_socket = info->pd_socket; 32337c478bd9Sstevel@tonic-gate ppd->ppd_function = info->pd_function; 32347c478bd9Sstevel@tonic-gate 32357c478bd9Sstevel@tonic-gate /* 32367c478bd9Sstevel@tonic-gate * add the "socket" property 32377c478bd9Sstevel@tonic-gate * the value of this property contains the logical PCMCIA 32387c478bd9Sstevel@tonic-gate * socket number the device has been inserted in, along 32397c478bd9Sstevel@tonic-gate * with the function # if the device is part of a 32407c478bd9Sstevel@tonic-gate * multi-function device. 32417c478bd9Sstevel@tonic-gate */ 32427c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, dip, 32437c478bd9Sstevel@tonic-gate PCM_DEV_SOCKET, unit); 32447c478bd9Sstevel@tonic-gate 32457c478bd9Sstevel@tonic-gate if (info->pd_flags & PCM_MULTI_FUNCTION) 32467c478bd9Sstevel@tonic-gate ppd->ppd_flags |= PPD_CARD_MULTI; 32477c478bd9Sstevel@tonic-gate 32487c478bd9Sstevel@tonic-gate /* 32497c478bd9Sstevel@tonic-gate * determine all the properties we need for PPD 32507c478bd9Sstevel@tonic-gate * then create the properties 32517c478bd9Sstevel@tonic-gate */ 32527c478bd9Sstevel@tonic-gate /* socket is unique */ 32537c478bd9Sstevel@tonic-gate pcmcia_find_regs(dip, info, ppd); 32547c478bd9Sstevel@tonic-gate 32557c478bd9Sstevel@tonic-gate ppd->ppd_intr = pcmcia_need_intr(unit, info); 32567c478bd9Sstevel@tonic-gate 32577c478bd9Sstevel@tonic-gate if (ppd->ppd_nreg > 0) 32587c478bd9Sstevel@tonic-gate (void) ddi_prop_update_int_array(DDI_DEV_T_NONE, dip, 32597c478bd9Sstevel@tonic-gate "reg", (int *)ppd->ppd_reg, ppd->ppd_nreg * 32607c478bd9Sstevel@tonic-gate sizeof (struct pcm_regs) / sizeof (int)); 32617c478bd9Sstevel@tonic-gate if (ppd->ppd_intr) { 32627c478bd9Sstevel@tonic-gate (void) ddi_prop_update_int(DDI_DEV_T_NONE, dip, 32637c478bd9Sstevel@tonic-gate "interrupts", ppd->ppd_intr); 32647c478bd9Sstevel@tonic-gate ppd->ppd_intrspec = 32657c478bd9Sstevel@tonic-gate kmem_zalloc(sizeof (struct intrspec), KM_SLEEP); 32667c478bd9Sstevel@tonic-gate } 32677c478bd9Sstevel@tonic-gate 32687c478bd9Sstevel@tonic-gate /* set parent private - our own format */ 32697c478bd9Sstevel@tonic-gate ddi_set_parent_data(dip, (caddr_t)ppd); 32707c478bd9Sstevel@tonic-gate 32717c478bd9Sstevel@tonic-gate /* init the device type */ 32727c478bd9Sstevel@tonic-gate if (info->pd_type >= 0 && 32737c478bd9Sstevel@tonic-gate info->pd_type < (sizeof (pcmcia_dev_type) / 32747c478bd9Sstevel@tonic-gate (sizeof (char *)))) 32757c478bd9Sstevel@tonic-gate dtype = pcmcia_dev_type[info->pd_type]; 32767c478bd9Sstevel@tonic-gate else 32777c478bd9Sstevel@tonic-gate dtype = "unknown"; 32787c478bd9Sstevel@tonic-gate 32797c478bd9Sstevel@tonic-gate if (strlen(info->pd_vers1_name) > 0) 32807c478bd9Sstevel@tonic-gate (void) ndi_prop_update_string(DDI_DEV_T_NONE, 32817c478bd9Sstevel@tonic-gate dip, PCM_DEV_MODEL, info->pd_vers1_name); 32827c478bd9Sstevel@tonic-gate 32837c478bd9Sstevel@tonic-gate (void) ndi_prop_update_string(DDI_DEV_T_NONE, dip, 32847c478bd9Sstevel@tonic-gate PCM_DEVICETYPE, dtype); 32857c478bd9Sstevel@tonic-gate 32867c478bd9Sstevel@tonic-gate /* set PC Card as active and present in socket */ 32877c478bd9Sstevel@tonic-gate pcmcia_sockets[info->pd_socket]->ls_dip[info->pd_function] = 32885c066ec2SJerry Gilliam dip; 32897c478bd9Sstevel@tonic-gate 32907c478bd9Sstevel@tonic-gate ppd->ppd_active = 1; 32917c478bd9Sstevel@tonic-gate 32927c478bd9Sstevel@tonic-gate /* 32937c478bd9Sstevel@tonic-gate * We should not call ndi_devi_online here if 32947c478bd9Sstevel@tonic-gate * pcmcia attach is in progress. This causes a deadlock. 32957c478bd9Sstevel@tonic-gate */ 32967c478bd9Sstevel@tonic-gate if (pcmcia_dip != dip) { 32977c478bd9Sstevel@tonic-gate if (ndi_devi_online_async(dip, 0) 32987c478bd9Sstevel@tonic-gate != NDI_SUCCESS) { 32997c478bd9Sstevel@tonic-gate pcmcia_sockets[info->pd_socket]->\ 33005c066ec2SJerry Gilliam ls_dip[info->pd_function] = NULL; 33017c478bd9Sstevel@tonic-gate pcmcia_ppd_free(ppd); 33027c478bd9Sstevel@tonic-gate (void) ndi_devi_free(dip); 33037c478bd9Sstevel@tonic-gate return; 33047c478bd9Sstevel@tonic-gate } 33057c478bd9Sstevel@tonic-gate } 33067c478bd9Sstevel@tonic-gate 33077c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 33087c478bd9Sstevel@tonic-gate if (pcmcia_debug) 33097c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "\tjust added \"active\" to %s in %d\n", 33105c066ec2SJerry Gilliam ddi_get_name(dip), info->pd_socket); 33117c478bd9Sstevel@tonic-gate #endif 33127c478bd9Sstevel@tonic-gate } 33137c478bd9Sstevel@tonic-gate 33147c478bd9Sstevel@tonic-gate /* 33157c478bd9Sstevel@tonic-gate * inform the event manager that a child was added 33167c478bd9Sstevel@tonic-gate * to the device tree. 33177c478bd9Sstevel@tonic-gate */ 33187c478bd9Sstevel@tonic-gate pcm_event_manager(PCE_DEV_IDENT, unit, ddi_get_name(dip)); 33197c478bd9Sstevel@tonic-gate 33207c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 33217c478bd9Sstevel@tonic-gate if (pcmcia_debug > 1) { 33227c478bd9Sstevel@tonic-gate pcmcia_dump_minors(dip); 33237c478bd9Sstevel@tonic-gate } 33247c478bd9Sstevel@tonic-gate #endif 33257c478bd9Sstevel@tonic-gate } 33267c478bd9Sstevel@tonic-gate 33277c478bd9Sstevel@tonic-gate /* 33287c478bd9Sstevel@tonic-gate * free any allocated parent-private data 33297c478bd9Sstevel@tonic-gate */ 33307c478bd9Sstevel@tonic-gate static void 33317c478bd9Sstevel@tonic-gate pcmcia_ppd_free(struct pcmcia_parent_private *ppd) 33327c478bd9Sstevel@tonic-gate { 33337c478bd9Sstevel@tonic-gate size_t len; 33347c478bd9Sstevel@tonic-gate 33357c478bd9Sstevel@tonic-gate if (ppd->ppd_nreg != 0) { 33367c478bd9Sstevel@tonic-gate len = ppd->ppd_nreg * sizeof (uint32_t) * 3; 33377c478bd9Sstevel@tonic-gate kmem_free(ppd->ppd_reg, len); 33387c478bd9Sstevel@tonic-gate len = sizeof (struct pcm_regs) * ppd->ppd_nreg; 33397c478bd9Sstevel@tonic-gate kmem_free(ppd->ppd_assigned, len); 33407c478bd9Sstevel@tonic-gate } 33417c478bd9Sstevel@tonic-gate 33427c478bd9Sstevel@tonic-gate /* 33437c478bd9Sstevel@tonic-gate * pcmcia only allocates 1 intrspec today 33447c478bd9Sstevel@tonic-gate */ 33457c478bd9Sstevel@tonic-gate if (ppd->ppd_intr != 0) { 33467c478bd9Sstevel@tonic-gate len = sizeof (struct intrspec) * ppd->ppd_intr; 33477c478bd9Sstevel@tonic-gate kmem_free(ppd->ppd_intrspec, len); 33487c478bd9Sstevel@tonic-gate } 33497c478bd9Sstevel@tonic-gate 33507c478bd9Sstevel@tonic-gate kmem_free(ppd, sizeof (*ppd)); 33517c478bd9Sstevel@tonic-gate } 33527c478bd9Sstevel@tonic-gate 33537c478bd9Sstevel@tonic-gate 33547c478bd9Sstevel@tonic-gate /* 33557c478bd9Sstevel@tonic-gate * pcmcia_get_devinfo(socket) 33567c478bd9Sstevel@tonic-gate * entry point to allow finding the device info structure 33577c478bd9Sstevel@tonic-gate * for a given logical socket. Used by event manager 33587c478bd9Sstevel@tonic-gate */ 33597c478bd9Sstevel@tonic-gate dev_info_t * 33607c478bd9Sstevel@tonic-gate pcmcia_get_devinfo(int socket) 33617c478bd9Sstevel@tonic-gate { 33627c478bd9Sstevel@tonic-gate int func = CS_GET_FUNCTION_NUMBER(socket); 33637c478bd9Sstevel@tonic-gate socket = CS_GET_SOCKET_NUMBER(socket); 33647c478bd9Sstevel@tonic-gate if (pcmcia_sockets[socket]) 33657c478bd9Sstevel@tonic-gate return (pcmcia_sockets[socket]->ls_dip[func]); 33667c478bd9Sstevel@tonic-gate return ((dev_info_t *)NULL); 33677c478bd9Sstevel@tonic-gate } 33687c478bd9Sstevel@tonic-gate 33697c478bd9Sstevel@tonic-gate /* 33707c478bd9Sstevel@tonic-gate * CSGetCookiesAndDip() 33717c478bd9Sstevel@tonic-gate * get info needed by CS to setup soft interrupt handler and provide 33727c478bd9Sstevel@tonic-gate * socket-specific adapter information 33737c478bd9Sstevel@tonic-gate */ 33747c478bd9Sstevel@tonic-gate static int 33757c478bd9Sstevel@tonic-gate GetCookiesAndDip(sservice_t *serv) 33767c478bd9Sstevel@tonic-gate { 33777c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t *socket; 33787c478bd9Sstevel@tonic-gate csss_adapter_info_t *ai; 33797c478bd9Sstevel@tonic-gate int sock; 33807c478bd9Sstevel@tonic-gate 33817c478bd9Sstevel@tonic-gate sock = CS_GET_SOCKET_NUMBER(serv->get_cookies.socket); 33827c478bd9Sstevel@tonic-gate 33837c478bd9Sstevel@tonic-gate if (sock >= pcmcia_num_sockets || 33847c478bd9Sstevel@tonic-gate (int)serv->get_cookies.socket < 0) 33857c478bd9Sstevel@tonic-gate return (BAD_SOCKET); 33867c478bd9Sstevel@tonic-gate 33877c478bd9Sstevel@tonic-gate socket = pcmcia_sockets[sock]; 33887c478bd9Sstevel@tonic-gate ai = &serv->get_cookies.adapter_info; 33897c478bd9Sstevel@tonic-gate serv->get_cookies.dip = socket->ls_adapter->pca_dip; 33907c478bd9Sstevel@tonic-gate serv->get_cookies.iblock = socket->ls_adapter->pca_iblock; 33917c478bd9Sstevel@tonic-gate serv->get_cookies.idevice = socket->ls_adapter->pca_idev; 33927c478bd9Sstevel@tonic-gate 33937c478bd9Sstevel@tonic-gate /* 33947c478bd9Sstevel@tonic-gate * Setup the adapter info for Card Services 33957c478bd9Sstevel@tonic-gate */ 33967c478bd9Sstevel@tonic-gate (void) strcpy(ai->name, socket->ls_adapter->pca_name); 33977c478bd9Sstevel@tonic-gate ai->major = socket->ls_adapter->pca_module; 33987c478bd9Sstevel@tonic-gate ai->minor = socket->ls_adapter->pca_unit; 33997c478bd9Sstevel@tonic-gate ai->number = socket->ls_adapter->pca_number; 34007c478bd9Sstevel@tonic-gate ai->num_sockets = socket->ls_adapter->pca_numsockets; 34017c478bd9Sstevel@tonic-gate ai->first_socket = socket->ls_adapter->pca_first_socket; 34027c478bd9Sstevel@tonic-gate 34037c478bd9Sstevel@tonic-gate return (SUCCESS); 34047c478bd9Sstevel@tonic-gate } 34057c478bd9Sstevel@tonic-gate 34067c478bd9Sstevel@tonic-gate /* 34077c478bd9Sstevel@tonic-gate * Note: 34087c478bd9Sstevel@tonic-gate * The following functions that start with 'SS' 34097c478bd9Sstevel@tonic-gate * implement SocketServices interfaces. They 34107c478bd9Sstevel@tonic-gate * simply map the socket and/or window number to 34117c478bd9Sstevel@tonic-gate * the adapter specific number based on the general 34127c478bd9Sstevel@tonic-gate * value that CardServices uses. 34137c478bd9Sstevel@tonic-gate * 34147c478bd9Sstevel@tonic-gate * See the descriptions in SocketServices for 34157c478bd9Sstevel@tonic-gate * details. Also refer to specific adapter drivers 34167c478bd9Sstevel@tonic-gate * for implementation reference. 34177c478bd9Sstevel@tonic-gate */ 34187c478bd9Sstevel@tonic-gate 34197c478bd9Sstevel@tonic-gate static int 34207c478bd9Sstevel@tonic-gate SSGetAdapter(get_adapter_t *adapter) 34217c478bd9Sstevel@tonic-gate { 34227c478bd9Sstevel@tonic-gate int n; 34237c478bd9Sstevel@tonic-gate get_adapter_t info; 34247c478bd9Sstevel@tonic-gate 34257c478bd9Sstevel@tonic-gate adapter->state = (unsigned)0xFFFFFFFF; 34267c478bd9Sstevel@tonic-gate adapter->SCRouting = 0xFFFFFFFF; 34277c478bd9Sstevel@tonic-gate 34287c478bd9Sstevel@tonic-gate for (n = 0; n < pcmcia_num_adapters; n++) { 34297c478bd9Sstevel@tonic-gate GET_ADAPTER(pcmcia_adapters[n]->pca_if, 34305c066ec2SJerry Gilliam pcmcia_adapters[n]->pca_dip, &info); 34317c478bd9Sstevel@tonic-gate adapter->state &= info.state; 34327c478bd9Sstevel@tonic-gate adapter->SCRouting &= info.SCRouting; 34337c478bd9Sstevel@tonic-gate } 34347c478bd9Sstevel@tonic-gate 34357c478bd9Sstevel@tonic-gate return (SUCCESS); 34367c478bd9Sstevel@tonic-gate } 34377c478bd9Sstevel@tonic-gate 34387c478bd9Sstevel@tonic-gate static int 34397c478bd9Sstevel@tonic-gate SSGetPage(get_page_t *page) 34407c478bd9Sstevel@tonic-gate { 34417c478bd9Sstevel@tonic-gate pcmcia_logical_window_t *window; 34427c478bd9Sstevel@tonic-gate get_page_t newpage; 34437c478bd9Sstevel@tonic-gate int retval, win; 34447c478bd9Sstevel@tonic-gate 34457c478bd9Sstevel@tonic-gate if (page->window > pcmcia_num_windows) { 34467c478bd9Sstevel@tonic-gate return (BAD_WINDOW); 34477c478bd9Sstevel@tonic-gate } 34487c478bd9Sstevel@tonic-gate 34497c478bd9Sstevel@tonic-gate window = pcmcia_windows[page->window]; 34507c478bd9Sstevel@tonic-gate newpage = *page; 34517c478bd9Sstevel@tonic-gate win = newpage.window = window->lw_window; /* real window */ 34527c478bd9Sstevel@tonic-gate 34537c478bd9Sstevel@tonic-gate retval = GET_PAGE(window->lw_if, window->lw_adapter->pca_dip, 34545c066ec2SJerry Gilliam &newpage); 34557c478bd9Sstevel@tonic-gate if (retval == SUCCESS) { 34567c478bd9Sstevel@tonic-gate *page = newpage; 34577c478bd9Sstevel@tonic-gate page->window = win; 34587c478bd9Sstevel@tonic-gate } 34597c478bd9Sstevel@tonic-gate return (retval); 34607c478bd9Sstevel@tonic-gate } 34617c478bd9Sstevel@tonic-gate 34627c478bd9Sstevel@tonic-gate static int 34637c478bd9Sstevel@tonic-gate SSGetSocket(get_socket_t *socket) 34647c478bd9Sstevel@tonic-gate { 34657c478bd9Sstevel@tonic-gate int retval, sock; 34667c478bd9Sstevel@tonic-gate get_socket_t newsocket; 34677c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t *sockp; 34687c478bd9Sstevel@tonic-gate 34697c478bd9Sstevel@tonic-gate sock = socket->socket; 34707c478bd9Sstevel@tonic-gate if (sock > pcmcia_num_sockets || 34715c066ec2SJerry Gilliam (sockp = pcmcia_sockets[sock]) == NULL) { 34727c478bd9Sstevel@tonic-gate return (BAD_SOCKET); 34737c478bd9Sstevel@tonic-gate } 34747c478bd9Sstevel@tonic-gate 34757c478bd9Sstevel@tonic-gate newsocket = *socket; 34767c478bd9Sstevel@tonic-gate newsocket.socket = sockp->ls_socket; 34777c478bd9Sstevel@tonic-gate retval = GET_SOCKET(sockp->ls_if, sockp->ls_adapter->pca_dip, 34787c478bd9Sstevel@tonic-gate &newsocket); 34797c478bd9Sstevel@tonic-gate if (retval == SUCCESS) { 34807c478bd9Sstevel@tonic-gate newsocket.VccLevel = pcmcia_map_power_get(sockp->ls_adapter, 34817c478bd9Sstevel@tonic-gate newsocket.VccLevel, 34827c478bd9Sstevel@tonic-gate VCC); 34837c478bd9Sstevel@tonic-gate newsocket.Vpp1Level = pcmcia_map_power_get(sockp->ls_adapter, 34847c478bd9Sstevel@tonic-gate newsocket.Vpp1Level, 34857c478bd9Sstevel@tonic-gate VPP1); 34867c478bd9Sstevel@tonic-gate newsocket.Vpp2Level = pcmcia_map_power_get(sockp->ls_adapter, 34877c478bd9Sstevel@tonic-gate newsocket.Vpp2Level, 34887c478bd9Sstevel@tonic-gate VPP2); 34897c478bd9Sstevel@tonic-gate *socket = newsocket; 34907c478bd9Sstevel@tonic-gate socket->socket = sock; 34917c478bd9Sstevel@tonic-gate } 34927c478bd9Sstevel@tonic-gate 34937c478bd9Sstevel@tonic-gate return (retval); 34947c478bd9Sstevel@tonic-gate } 34957c478bd9Sstevel@tonic-gate 34967c478bd9Sstevel@tonic-gate static int 34977c478bd9Sstevel@tonic-gate SSGetStatus(get_ss_status_t *status) 34987c478bd9Sstevel@tonic-gate { 34997c478bd9Sstevel@tonic-gate get_ss_status_t newstat; 35007c478bd9Sstevel@tonic-gate int sock, retval; 35017c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t *sockp; 35027c478bd9Sstevel@tonic-gate 35037c478bd9Sstevel@tonic-gate sock = status->socket; 35047c478bd9Sstevel@tonic-gate if (sock > pcmcia_num_sockets || 35055c066ec2SJerry Gilliam (sockp = pcmcia_sockets[sock]) == NULL) { 35067c478bd9Sstevel@tonic-gate return (BAD_SOCKET); 35077c478bd9Sstevel@tonic-gate } 35087c478bd9Sstevel@tonic-gate 35097c478bd9Sstevel@tonic-gate newstat = *status; 35107c478bd9Sstevel@tonic-gate newstat.socket = sockp->ls_socket; 35117c478bd9Sstevel@tonic-gate retval = GET_STATUS(sockp->ls_if, sockp->ls_adapter->pca_dip, 35127c478bd9Sstevel@tonic-gate &newstat); 35137c478bd9Sstevel@tonic-gate if (retval == SUCCESS) { 35147c478bd9Sstevel@tonic-gate *status = newstat; 35157c478bd9Sstevel@tonic-gate status->socket = sock; 35167c478bd9Sstevel@tonic-gate } 35177c478bd9Sstevel@tonic-gate 35187c478bd9Sstevel@tonic-gate return (retval); 35197c478bd9Sstevel@tonic-gate } 35207c478bd9Sstevel@tonic-gate 35217c478bd9Sstevel@tonic-gate static int 35227c478bd9Sstevel@tonic-gate SSGetWindow(get_window_t *window) 35237c478bd9Sstevel@tonic-gate { 35247c478bd9Sstevel@tonic-gate int win, retval; 35257c478bd9Sstevel@tonic-gate get_window_t newwin; 35267c478bd9Sstevel@tonic-gate pcmcia_logical_window_t *winp; 35277c478bd9Sstevel@tonic-gate 35287c478bd9Sstevel@tonic-gate win = window->window; 35297c478bd9Sstevel@tonic-gate winp = pcmcia_windows[win]; 35307c478bd9Sstevel@tonic-gate newwin = *window; 35317c478bd9Sstevel@tonic-gate newwin.window = winp->lw_window; 35327c478bd9Sstevel@tonic-gate 35337c478bd9Sstevel@tonic-gate retval = GET_WINDOW(winp->lw_if, winp->lw_adapter->pca_dip, 35347c478bd9Sstevel@tonic-gate &newwin); 35357c478bd9Sstevel@tonic-gate if (retval == SUCCESS) { 35367c478bd9Sstevel@tonic-gate newwin.socket = winp->lw_socket; 35377c478bd9Sstevel@tonic-gate newwin.window = win; 35387c478bd9Sstevel@tonic-gate *window = newwin; 35397c478bd9Sstevel@tonic-gate } 35407c478bd9Sstevel@tonic-gate return (retval); 35417c478bd9Sstevel@tonic-gate } 35427c478bd9Sstevel@tonic-gate 35437c478bd9Sstevel@tonic-gate /* 35447c478bd9Sstevel@tonic-gate * SSInquireAdapter() 35457c478bd9Sstevel@tonic-gate * Get the capabilities of the "generic" adapter 35467c478bd9Sstevel@tonic-gate * we are exporting to CS. 35477c478bd9Sstevel@tonic-gate */ 35487c478bd9Sstevel@tonic-gate static int 35497c478bd9Sstevel@tonic-gate SSInquireAdapter(inquire_adapter_t *adapter) 35507c478bd9Sstevel@tonic-gate { 35517c478bd9Sstevel@tonic-gate adapter->NumSockets = pcmcia_num_sockets; 35527c478bd9Sstevel@tonic-gate adapter->NumWindows = pcmcia_num_windows; 35537c478bd9Sstevel@tonic-gate adapter->NumEDCs = 0; 35547c478bd9Sstevel@tonic-gate /* 35557c478bd9Sstevel@tonic-gate * notes: Adapter Capabilities are going to be difficult to 35567c478bd9Sstevel@tonic-gate * determine with reliability. Fortunately, most of them 35577c478bd9Sstevel@tonic-gate * don't matter under Solaris or can be handled transparently 35587c478bd9Sstevel@tonic-gate */ 35597c478bd9Sstevel@tonic-gate adapter->AdpCaps = 0; /* need to fix these */ 35607c478bd9Sstevel@tonic-gate /* 35617c478bd9Sstevel@tonic-gate * interrupts need a little work. For x86, the valid IRQs will 35627c478bd9Sstevel@tonic-gate * be restricted to those that the system has exported to the nexus. 35637c478bd9Sstevel@tonic-gate * for SPARC, it will be the DoRight values. 35647c478bd9Sstevel@tonic-gate */ 35657c478bd9Sstevel@tonic-gate adapter->ActiveHigh = 0; 35667c478bd9Sstevel@tonic-gate adapter->ActiveLow = 0; 35677c478bd9Sstevel@tonic-gate adapter->power_entry = pcmcia_power_table; /* until we resolve this */ 35687c478bd9Sstevel@tonic-gate adapter->NumPower = pcmcia_num_power; 35697c478bd9Sstevel@tonic-gate return (SUCCESS); 35707c478bd9Sstevel@tonic-gate } 35717c478bd9Sstevel@tonic-gate 35727c478bd9Sstevel@tonic-gate static int 35737c478bd9Sstevel@tonic-gate SSInquireSocket(inquire_socket_t *socket) 35747c478bd9Sstevel@tonic-gate { 35757c478bd9Sstevel@tonic-gate int retval, sock; 35767c478bd9Sstevel@tonic-gate inquire_socket_t newsocket; 35777c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t *sockp; 35787c478bd9Sstevel@tonic-gate 35797c478bd9Sstevel@tonic-gate sock = socket->socket; 35807c478bd9Sstevel@tonic-gate if (sock > pcmcia_num_sockets || 35815c066ec2SJerry Gilliam (sockp = pcmcia_sockets[sock]) == NULL) 35827c478bd9Sstevel@tonic-gate return (BAD_SOCKET); 35837c478bd9Sstevel@tonic-gate newsocket = *socket; 35847c478bd9Sstevel@tonic-gate newsocket.socket = sockp->ls_socket; 35857c478bd9Sstevel@tonic-gate retval = INQUIRE_SOCKET(sockp->ls_if, sockp->ls_adapter->pca_dip, 35867c478bd9Sstevel@tonic-gate &newsocket); 35877c478bd9Sstevel@tonic-gate if (retval == SUCCESS) { 35887c478bd9Sstevel@tonic-gate *socket = newsocket; 35897c478bd9Sstevel@tonic-gate socket->socket = sock; 35907c478bd9Sstevel@tonic-gate } 35917c478bd9Sstevel@tonic-gate return (retval); 35927c478bd9Sstevel@tonic-gate } 35937c478bd9Sstevel@tonic-gate 35947c478bd9Sstevel@tonic-gate static int 35957c478bd9Sstevel@tonic-gate SSInquireWindow(inquire_window_t *window) 35967c478bd9Sstevel@tonic-gate { 35977c478bd9Sstevel@tonic-gate int retval, win; 35987c478bd9Sstevel@tonic-gate pcmcia_logical_window_t *winp; 35997c478bd9Sstevel@tonic-gate inquire_window_t newwin; 36007c478bd9Sstevel@tonic-gate int slide; 36017c478bd9Sstevel@tonic-gate 36027c478bd9Sstevel@tonic-gate win = window->window; 36037c478bd9Sstevel@tonic-gate if (win > pcmcia_num_windows) 36047c478bd9Sstevel@tonic-gate return (BAD_WINDOW); 36057c478bd9Sstevel@tonic-gate 36067c478bd9Sstevel@tonic-gate winp = pcmcia_windows[win]; 36077c478bd9Sstevel@tonic-gate newwin = *window; 36087c478bd9Sstevel@tonic-gate newwin.window = winp->lw_window; 36097c478bd9Sstevel@tonic-gate retval = INQUIRE_WINDOW(winp->lw_if, winp->lw_adapter->pca_dip, 36107c478bd9Sstevel@tonic-gate &newwin); 36117c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 36127c478bd9Sstevel@tonic-gate if (pcmcia_debug > 1) 36137c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "SSInquireWindow: win=%d, pwin=%d\n", 36145c066ec2SJerry Gilliam win, newwin.window); 36157c478bd9Sstevel@tonic-gate #endif 36167c478bd9Sstevel@tonic-gate if (retval == SUCCESS) { 36177c478bd9Sstevel@tonic-gate *window = newwin; 36187c478bd9Sstevel@tonic-gate /* just in case */ 36197c478bd9Sstevel@tonic-gate window->iowin_char.IOWndCaps &= ~WC_BASE; 36207c478bd9Sstevel@tonic-gate slide = winp->lw_adapter->pca_first_socket; 36217c478bd9Sstevel@tonic-gate /* 36227c478bd9Sstevel@tonic-gate * note that sockets are relative to the adapter. 36237c478bd9Sstevel@tonic-gate * we have to adjust the bits to show a logical 36247c478bd9Sstevel@tonic-gate * version. 36257c478bd9Sstevel@tonic-gate */ 36267c478bd9Sstevel@tonic-gate 36277c478bd9Sstevel@tonic-gate pcm_fix_bits(newwin.Sockets, window->Sockets, slide, 0); 36287c478bd9Sstevel@tonic-gate 36297c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 36307c478bd9Sstevel@tonic-gate if (pcmcia_debug > 1) { 36317c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "iw: orig bits=%x, new bits=%x\n", 36325c066ec2SJerry Gilliam (int)*(uint32_t *)newwin.Sockets, 36335c066ec2SJerry Gilliam (int)*(uint32_t *)window->Sockets); 36347c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "\t%x.%x.%x\n", window->WndCaps, 36355c066ec2SJerry Gilliam window->mem_win_char.MemWndCaps, 36365c066ec2SJerry Gilliam window->mem_win_char.MinSize); 36377c478bd9Sstevel@tonic-gate } 36387c478bd9Sstevel@tonic-gate #endif 36397c478bd9Sstevel@tonic-gate window->window = win; 36407c478bd9Sstevel@tonic-gate } 36417c478bd9Sstevel@tonic-gate return (retval); 36427c478bd9Sstevel@tonic-gate } 36437c478bd9Sstevel@tonic-gate 36447c478bd9Sstevel@tonic-gate static int 36457c478bd9Sstevel@tonic-gate SSResetSocket(int socket, int mode) 36467c478bd9Sstevel@tonic-gate { 36477c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t *sockp; 36487c478bd9Sstevel@tonic-gate 36497c478bd9Sstevel@tonic-gate if (socket >= pcmcia_num_sockets || 36505c066ec2SJerry Gilliam (sockp = pcmcia_sockets[socket]) == NULL) 36517c478bd9Sstevel@tonic-gate return (BAD_SOCKET); 36527c478bd9Sstevel@tonic-gate 36537c478bd9Sstevel@tonic-gate return (RESET_SOCKET(sockp->ls_if, sockp->ls_adapter->pca_dip, 36547c478bd9Sstevel@tonic-gate sockp->ls_socket, mode)); 36557c478bd9Sstevel@tonic-gate } 36567c478bd9Sstevel@tonic-gate 36577c478bd9Sstevel@tonic-gate static int 36587c478bd9Sstevel@tonic-gate SSSetPage(set_page_t *page) 36597c478bd9Sstevel@tonic-gate { 36607c478bd9Sstevel@tonic-gate int window, retval; 36617c478bd9Sstevel@tonic-gate set_page_t newpage; 36627c478bd9Sstevel@tonic-gate pcmcia_logical_window_t *winp; 36637c478bd9Sstevel@tonic-gate 36647c478bd9Sstevel@tonic-gate window = page->window; 36657c478bd9Sstevel@tonic-gate if (window > pcmcia_num_windows) { 36667c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 36677c478bd9Sstevel@tonic-gate if (pcmcia_debug > 1) 36687c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "SSSetPage: window=%d (of %d)\n", 36695c066ec2SJerry Gilliam window, pcmcia_num_windows); 36707c478bd9Sstevel@tonic-gate #endif 36717c478bd9Sstevel@tonic-gate return (BAD_WINDOW); 36727c478bd9Sstevel@tonic-gate } 36737c478bd9Sstevel@tonic-gate 36747c478bd9Sstevel@tonic-gate winp = pcmcia_windows[window]; 36757c478bd9Sstevel@tonic-gate newpage = *page; 36767c478bd9Sstevel@tonic-gate newpage.window = winp->lw_window; 36777c478bd9Sstevel@tonic-gate retval = SET_PAGE(winp->lw_if, winp->lw_adapter->pca_dip, &newpage); 36787c478bd9Sstevel@tonic-gate if (retval == SUCCESS) { 36797c478bd9Sstevel@tonic-gate newpage.window = window; 36807c478bd9Sstevel@tonic-gate *page = newpage; 36817c478bd9Sstevel@tonic-gate } 36827c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 36837c478bd9Sstevel@tonic-gate if ((pcmcia_debug > 1) && retval != SUCCESS) 36847c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "\tSetPage: returning error %x\n", retval); 36857c478bd9Sstevel@tonic-gate #endif 36867c478bd9Sstevel@tonic-gate return (retval); 36877c478bd9Sstevel@tonic-gate } 36887c478bd9Sstevel@tonic-gate 36897c478bd9Sstevel@tonic-gate static int 36907c478bd9Sstevel@tonic-gate SSSetWindow(set_window_t *win) 36917c478bd9Sstevel@tonic-gate { 36927c478bd9Sstevel@tonic-gate int socket, window, retval, func; 36937c478bd9Sstevel@tonic-gate set_window_t newwin; 36947c478bd9Sstevel@tonic-gate pcmcia_logical_window_t *winp; 36957c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t *sockp; 36967c478bd9Sstevel@tonic-gate 36977c478bd9Sstevel@tonic-gate window = win->window; 36987c478bd9Sstevel@tonic-gate if (window > pcmcia_num_windows) 36997c478bd9Sstevel@tonic-gate return (BAD_WINDOW); 37007c478bd9Sstevel@tonic-gate 37017c478bd9Sstevel@tonic-gate socket = CS_GET_SOCKET_NUMBER(win->socket); 37027c478bd9Sstevel@tonic-gate func = CS_GET_FUNCTION_NUMBER(win->socket); 37037c478bd9Sstevel@tonic-gate 37047c478bd9Sstevel@tonic-gate if (socket > pcmcia_num_sockets || 37055c066ec2SJerry Gilliam (sockp = pcmcia_sockets[socket]) == NULL) { 37067c478bd9Sstevel@tonic-gate return (BAD_SOCKET); 37077c478bd9Sstevel@tonic-gate } 37087c478bd9Sstevel@tonic-gate 37097c478bd9Sstevel@tonic-gate winp = pcmcia_windows[window]; 37107c478bd9Sstevel@tonic-gate winp->lw_socket = win->socket; /* reverse map */ 37117c478bd9Sstevel@tonic-gate newwin = *win; 37127c478bd9Sstevel@tonic-gate newwin.window = winp->lw_window; 37137c478bd9Sstevel@tonic-gate newwin.socket = sockp->ls_socket; 37147c478bd9Sstevel@tonic-gate newwin.child = sockp->ls_dip[func]; /* so we carry the dip around */ 37157c478bd9Sstevel@tonic-gate 37167c478bd9Sstevel@tonic-gate retval = SET_WINDOW(winp->lw_if, winp->lw_adapter->pca_dip, &newwin); 37177c478bd9Sstevel@tonic-gate if (retval == SUCCESS) { 37187c478bd9Sstevel@tonic-gate newwin.window = window; 37197c478bd9Sstevel@tonic-gate newwin.socket = winp->lw_socket; 37207c478bd9Sstevel@tonic-gate *win = newwin; 37217c478bd9Sstevel@tonic-gate } 37227c478bd9Sstevel@tonic-gate return (retval); 37237c478bd9Sstevel@tonic-gate } 37247c478bd9Sstevel@tonic-gate 37257c478bd9Sstevel@tonic-gate static int 37267c478bd9Sstevel@tonic-gate SSSetSocket(set_socket_t *socket) 37277c478bd9Sstevel@tonic-gate { 37287c478bd9Sstevel@tonic-gate int sock, retval; 37297c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t *sockp; 37307c478bd9Sstevel@tonic-gate set_socket_t newsock; 37317c478bd9Sstevel@tonic-gate 37327c478bd9Sstevel@tonic-gate sock = socket->socket; 37337c478bd9Sstevel@tonic-gate if (sock > pcmcia_num_sockets || 37345c066ec2SJerry Gilliam (sockp = pcmcia_sockets[sock]) == NULL) { 37357c478bd9Sstevel@tonic-gate return (BAD_SOCKET); 37367c478bd9Sstevel@tonic-gate } 37377c478bd9Sstevel@tonic-gate 37387c478bd9Sstevel@tonic-gate newsock = *socket; 37397c478bd9Sstevel@tonic-gate /* note: we force CS to always get insert/removal events */ 37407c478bd9Sstevel@tonic-gate sockp->ls_cs_events = pcm_mapevents(newsock.SCIntMask) | 37416dea387aSQin Michael Li PCE_E2M(PCE_CARD_INSERT) | PCE_E2M(PCE_CARD_REMOVAL) | 37426dea387aSQin Michael Li PCE_E2M(PCE_PM_SUSPEND); 37437c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 37447c478bd9Sstevel@tonic-gate if (pcmcia_debug > 1) 37457c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 37465c066ec2SJerry Gilliam "SetSocket: SCIntMask = %x\n", newsock.SCIntMask); 37477c478bd9Sstevel@tonic-gate #endif 37487c478bd9Sstevel@tonic-gate newsock.socket = sockp->ls_socket; 37497c478bd9Sstevel@tonic-gate newsock.VccLevel = pcmcia_map_power_set(sockp->ls_adapter, 37507c478bd9Sstevel@tonic-gate newsock.VccLevel, VCC); 37517c478bd9Sstevel@tonic-gate newsock.Vpp1Level = pcmcia_map_power_set(sockp->ls_adapter, 37527c478bd9Sstevel@tonic-gate newsock.Vpp1Level, VPP1); 37537c478bd9Sstevel@tonic-gate newsock.Vpp2Level = pcmcia_map_power_set(sockp->ls_adapter, 37547c478bd9Sstevel@tonic-gate newsock.Vpp2Level, VPP2); 37557c478bd9Sstevel@tonic-gate retval = SET_SOCKET(sockp->ls_if, sockp->ls_adapter->pca_dip, 37567c478bd9Sstevel@tonic-gate &newsock); 37577c478bd9Sstevel@tonic-gate if (retval == SUCCESS) { 37587c478bd9Sstevel@tonic-gate newsock.socket = sock; 37597c478bd9Sstevel@tonic-gate newsock.VccLevel = pcmcia_map_power_get(sockp->ls_adapter, 37607c478bd9Sstevel@tonic-gate newsock.VccLevel, 37617c478bd9Sstevel@tonic-gate VCC); 37627c478bd9Sstevel@tonic-gate newsock.Vpp1Level = pcmcia_map_power_get(sockp->ls_adapter, 37637c478bd9Sstevel@tonic-gate newsock.Vpp1Level, 37647c478bd9Sstevel@tonic-gate VPP1); 37657c478bd9Sstevel@tonic-gate newsock.Vpp2Level = pcmcia_map_power_get(sockp->ls_adapter, 37667c478bd9Sstevel@tonic-gate newsock.Vpp2Level, 37677c478bd9Sstevel@tonic-gate VPP2); 37687c478bd9Sstevel@tonic-gate *socket = newsock; 37697c478bd9Sstevel@tonic-gate if (socket->IREQRouting & IRQ_ENABLE) { 37707c478bd9Sstevel@tonic-gate sockp->ls_flags |= PCS_IRQ_ENABLED; 37717c478bd9Sstevel@tonic-gate } else { 37727c478bd9Sstevel@tonic-gate sockp->ls_flags &= ~PCS_IRQ_ENABLED; 37737c478bd9Sstevel@tonic-gate } 37747c478bd9Sstevel@tonic-gate } 37757c478bd9Sstevel@tonic-gate return (retval); 37767c478bd9Sstevel@tonic-gate } 37777c478bd9Sstevel@tonic-gate 37787c478bd9Sstevel@tonic-gate /* 37797c478bd9Sstevel@tonic-gate * SSSetIRQHandler() 37807c478bd9Sstevel@tonic-gate * arrange for IRQ to be allocated if appropriate and always 37817c478bd9Sstevel@tonic-gate * arrange that PC Card interrupt handlers get called. 37827c478bd9Sstevel@tonic-gate */ 37837c478bd9Sstevel@tonic-gate static int 37847c478bd9Sstevel@tonic-gate SSSetIRQHandler(set_irq_handler_t *handler) 37857c478bd9Sstevel@tonic-gate { 37867c478bd9Sstevel@tonic-gate int sock, retval, func; 37877c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t *sockp; 37887c478bd9Sstevel@tonic-gate struct pcmcia_parent_private *ppd; 37897c478bd9Sstevel@tonic-gate dev_info_t *dip; 37907c478bd9Sstevel@tonic-gate ddi_iblock_cookie_t iblk; 37917c478bd9Sstevel@tonic-gate ddi_idevice_cookie_t idev; 37927c478bd9Sstevel@tonic-gate 37937c478bd9Sstevel@tonic-gate sock = CS_GET_SOCKET_NUMBER(handler->socket); 37947c478bd9Sstevel@tonic-gate func = CS_GET_FUNCTION_NUMBER(handler->socket); 37957c478bd9Sstevel@tonic-gate if (sock > pcmcia_num_sockets || 37965c066ec2SJerry Gilliam (sockp = pcmcia_sockets[sock]) == NULL) { 37977c478bd9Sstevel@tonic-gate return (BAD_SOCKET); 37987c478bd9Sstevel@tonic-gate } 37997c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 38007c478bd9Sstevel@tonic-gate if (pcmcia_debug) { 38017c478bd9Sstevel@tonic-gate 38027c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "SSSetIRQHandler: socket=%x, function=%x\n", 38035c066ec2SJerry Gilliam sock, func); 38047c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "\thandler(%p): socket=%x, irq=%x, id=%x\n", 38055c066ec2SJerry Gilliam (void *)handler->handler, handler->socket, handler->irq, 38065c066ec2SJerry Gilliam handler->handler_id); 38077c478bd9Sstevel@tonic-gate } 38087c478bd9Sstevel@tonic-gate #endif 38097c478bd9Sstevel@tonic-gate dip = sockp->ls_dip[func]; 38107c478bd9Sstevel@tonic-gate 38117c478bd9Sstevel@tonic-gate ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(dip); 38127c478bd9Sstevel@tonic-gate 38137c478bd9Sstevel@tonic-gate handler->iblk_cookie = &iblk; 38147c478bd9Sstevel@tonic-gate handler->idev_cookie = &idev; 38157c478bd9Sstevel@tonic-gate 38167c478bd9Sstevel@tonic-gate retval = ddi_add_intr(dip, 0, handler->iblk_cookie, 38177c478bd9Sstevel@tonic-gate handler->idev_cookie, 38187c478bd9Sstevel@tonic-gate (uint32_t(*)(caddr_t)) handler->handler, 38197c478bd9Sstevel@tonic-gate handler->arg1); 38207c478bd9Sstevel@tonic-gate 38217c478bd9Sstevel@tonic-gate if (retval == DDI_SUCCESS) { 38227c478bd9Sstevel@tonic-gate handler->iblk_cookie = &sockp->ls_iblk; 38237c478bd9Sstevel@tonic-gate handler->idev_cookie = &sockp->ls_idev; 38247c478bd9Sstevel@tonic-gate handler->irq = ppd->ppd_intrspec->intrspec_vec; 38257c478bd9Sstevel@tonic-gate retval = SUCCESS; 38267c478bd9Sstevel@tonic-gate } else { 38277c478bd9Sstevel@tonic-gate retval = sockp->ls_error; 38287c478bd9Sstevel@tonic-gate } 38297c478bd9Sstevel@tonic-gate return (retval); 38307c478bd9Sstevel@tonic-gate } 38317c478bd9Sstevel@tonic-gate 38327c478bd9Sstevel@tonic-gate /* 38337c478bd9Sstevel@tonic-gate * SSClearIRQHandler() 38347c478bd9Sstevel@tonic-gate * Arrange to have the interrupt handler specified removed 38357c478bd9Sstevel@tonic-gate * from the interrupt list. 38367c478bd9Sstevel@tonic-gate */ 38377c478bd9Sstevel@tonic-gate static int 38387c478bd9Sstevel@tonic-gate SSClearIRQHandler(clear_irq_handler_t *handler) 38397c478bd9Sstevel@tonic-gate { 38407c478bd9Sstevel@tonic-gate int sock, func; 38417c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t *sockp; 38427c478bd9Sstevel@tonic-gate dev_info_t *dip; 38437c478bd9Sstevel@tonic-gate 38447c478bd9Sstevel@tonic-gate sock = CS_GET_SOCKET_NUMBER(handler->socket); 38457c478bd9Sstevel@tonic-gate func = CS_GET_FUNCTION_NUMBER(handler->socket); 38467c478bd9Sstevel@tonic-gate 38477c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 38487c478bd9Sstevel@tonic-gate if (pcmcia_debug) { 38497c478bd9Sstevel@tonic-gate 38507c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 38515c066ec2SJerry Gilliam "SSClearIRQHandler: socket=%x, function=%x\n", 38525c066ec2SJerry Gilliam sock, func); 38537c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 38545c066ec2SJerry Gilliam "\thandler(%p): socket=%x, id=%x\n", 38555c066ec2SJerry Gilliam (void *)handler, handler->socket, 38565c066ec2SJerry Gilliam handler->handler_id); 38577c478bd9Sstevel@tonic-gate } 38587c478bd9Sstevel@tonic-gate #endif 38597c478bd9Sstevel@tonic-gate 38607c478bd9Sstevel@tonic-gate if (sock > pcmcia_num_sockets || 38615c066ec2SJerry Gilliam (sockp = pcmcia_sockets[sock]) == NULL) { 38627c478bd9Sstevel@tonic-gate return (BAD_SOCKET); 38637c478bd9Sstevel@tonic-gate } 38647c478bd9Sstevel@tonic-gate dip = sockp->ls_dip[func]; 38657c478bd9Sstevel@tonic-gate if (dip) { 38667c478bd9Sstevel@tonic-gate ddi_remove_intr(dip, 0, NULL); 38677c478bd9Sstevel@tonic-gate return (SUCCESS); 38687c478bd9Sstevel@tonic-gate } 38697c478bd9Sstevel@tonic-gate return (BAD_SOCKET); 38707c478bd9Sstevel@tonic-gate } 38717c478bd9Sstevel@tonic-gate 38727c478bd9Sstevel@tonic-gate 38737c478bd9Sstevel@tonic-gate /* 38747c478bd9Sstevel@tonic-gate * pcm_pathname() 38757c478bd9Sstevel@tonic-gate * make a partial path from dip. 38767c478bd9Sstevel@tonic-gate * used to mknods relative to /devices/pcmcia/ 38777c478bd9Sstevel@tonic-gate * 38787c478bd9Sstevel@tonic-gate * XXX - we now use ddi_get_name_addr to get the "address" portion 38797c478bd9Sstevel@tonic-gate * of the name; that way, we only have to modify the name creation 38807c478bd9Sstevel@tonic-gate * algorithm in one place 38817c478bd9Sstevel@tonic-gate */ 38827c478bd9Sstevel@tonic-gate static void 38837c478bd9Sstevel@tonic-gate pcm_pathname(dev_info_t *dip, char *name, char *path) 38847c478bd9Sstevel@tonic-gate { 38857c478bd9Sstevel@tonic-gate (void) sprintf(path, "%s@%s:%s", ddi_node_name(dip), 38867c478bd9Sstevel@tonic-gate ddi_get_name_addr(dip), name); 38877c478bd9Sstevel@tonic-gate } 38887c478bd9Sstevel@tonic-gate 38897c478bd9Sstevel@tonic-gate /* 38907c478bd9Sstevel@tonic-gate * pcmcia_create_device() 38917c478bd9Sstevel@tonic-gate * create the /devices entries for the driver 38927c478bd9Sstevel@tonic-gate * it is assumed that the PC Card driver will do a 38937c478bd9Sstevel@tonic-gate * RegisterClient for each subdevice. 38947c478bd9Sstevel@tonic-gate * The device type string is encoded here to match 38957c478bd9Sstevel@tonic-gate * the standardized names when possible. 38967c478bd9Sstevel@tonic-gate * XXX - note that we may need to provide a way for the 38977c478bd9Sstevel@tonic-gate * caller to specify the complete name string that 38987c478bd9Sstevel@tonic-gate * we pass to ddi_set_name_addr 38997c478bd9Sstevel@tonic-gate */ 39007c478bd9Sstevel@tonic-gate static int 39017c478bd9Sstevel@tonic-gate pcmcia_create_device(ss_make_device_node_t *init) 39027c478bd9Sstevel@tonic-gate { 39037c478bd9Sstevel@tonic-gate int err = SUCCESS; 39047c478bd9Sstevel@tonic-gate struct pcm_make_dev device; 39057c478bd9Sstevel@tonic-gate struct dev_ops *ops; 39067c478bd9Sstevel@tonic-gate major_t major; 39077c478bd9Sstevel@tonic-gate 39087c478bd9Sstevel@tonic-gate /* 39097c478bd9Sstevel@tonic-gate * Now that we have the name, create it. 39107c478bd9Sstevel@tonic-gate */ 39117c478bd9Sstevel@tonic-gate 39127c478bd9Sstevel@tonic-gate bzero(&device, sizeof (device)); 39137c478bd9Sstevel@tonic-gate if (init->flags & SS_CSINITDEV_CREATE_DEVICE) { 39147c478bd9Sstevel@tonic-gate if ((err = ddi_create_minor_node(init->dip, 39157c478bd9Sstevel@tonic-gate init->name, 39167c478bd9Sstevel@tonic-gate init->spec_type, 39177c478bd9Sstevel@tonic-gate init->minor_num, 39187c478bd9Sstevel@tonic-gate init->node_type, 39197c478bd9Sstevel@tonic-gate 0)) != DDI_SUCCESS) { 39207c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 39217c478bd9Sstevel@tonic-gate if (pcmcia_debug) 39227c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 39235c066ec2SJerry Gilliam "pcmcia_create_device: failed " 39245c066ec2SJerry Gilliam "create\n"); 39257c478bd9Sstevel@tonic-gate #endif 39267c478bd9Sstevel@tonic-gate return (BAD_ATTRIBUTE); 39277c478bd9Sstevel@tonic-gate } 39287c478bd9Sstevel@tonic-gate 39295c066ec2SJerry Gilliam major = ddi_driver_major(init->dip); 39307c478bd9Sstevel@tonic-gate ops = ddi_get_driver(init->dip); 39317c478bd9Sstevel@tonic-gate LOCK_DEV_OPS(&devnamesp[major].dn_lock); 39327c478bd9Sstevel@tonic-gate INCR_DEV_OPS_REF(ops); 39337c478bd9Sstevel@tonic-gate (void) ddi_pathname(init->dip, device.path); 39347c478bd9Sstevel@tonic-gate DECR_DEV_OPS_REF(ops); 39357c478bd9Sstevel@tonic-gate UNLOCK_DEV_OPS(&devnamesp[major].dn_lock); 39367c478bd9Sstevel@tonic-gate (void) sprintf(device.path + strlen(device.path), ":%s", 39377c478bd9Sstevel@tonic-gate init->name); 39387c478bd9Sstevel@tonic-gate 39397c478bd9Sstevel@tonic-gate (void) strcpy(device.driver, ddi_binding_name(init->dip)); 39407c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 39417c478bd9Sstevel@tonic-gate if (pcmcia_debug) 39427c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 39435c066ec2SJerry Gilliam "pcmcia_create_device: created %s " 39445c066ec2SJerry Gilliam "from %s [%s]\n", 39455c066ec2SJerry Gilliam device.path, init->name, device.driver); 39467c478bd9Sstevel@tonic-gate #endif 39477c478bd9Sstevel@tonic-gate device.dev = 39485c066ec2SJerry Gilliam makedevice(ddi_driver_major(init->dip), init->minor_num); 39497c478bd9Sstevel@tonic-gate device.flags |= (init->flags & SS_CSINITDEV_MORE_DEVICES) ? 39507c478bd9Sstevel@tonic-gate PCM_EVENT_MORE : 0; 39517c478bd9Sstevel@tonic-gate device.type = init->spec_type; 39527c478bd9Sstevel@tonic-gate device.op = SS_CSINITDEV_CREATE_DEVICE; 39537c478bd9Sstevel@tonic-gate device.socket = ddi_getprop(DDI_DEV_T_ANY, init->dip, 39547c478bd9Sstevel@tonic-gate DDI_PROP_CANSLEEP, PCM_DEV_SOCKET, 39557c478bd9Sstevel@tonic-gate -1); 39567c478bd9Sstevel@tonic-gate } else if (init->flags & SS_CSINITDEV_REMOVE_DEVICE) { 39577c478bd9Sstevel@tonic-gate device.op = SS_CSINITDEV_REMOVE_DEVICE; 39587c478bd9Sstevel@tonic-gate device.socket = ddi_getprop(DDI_DEV_T_ANY, init->dip, 39597c478bd9Sstevel@tonic-gate DDI_PROP_CANSLEEP, PCM_DEV_SOCKET, 39607c478bd9Sstevel@tonic-gate -1); 39617c478bd9Sstevel@tonic-gate if (init->name != NULL) 39627c478bd9Sstevel@tonic-gate (void) strcpy(device.path, init->name); 39635c066ec2SJerry Gilliam device.dev = makedevice(ddi_driver_major(init->dip), 0); 39647c478bd9Sstevel@tonic-gate ddi_remove_minor_node(init->dip, init->name); 39657c478bd9Sstevel@tonic-gate } 39667c478bd9Sstevel@tonic-gate 39677c478bd9Sstevel@tonic-gate /* 39687c478bd9Sstevel@tonic-gate * we send an event for ALL devices created. 39697c478bd9Sstevel@tonic-gate * To do otherwise ties us to using drvconfig 39707c478bd9Sstevel@tonic-gate * forever. There are relatively few devices 39717c478bd9Sstevel@tonic-gate * ever created so no need to do otherwise. 39727c478bd9Sstevel@tonic-gate * The existence of the event manager must never 39737c478bd9Sstevel@tonic-gate * be visible to a PCMCIA device driver. 39747c478bd9Sstevel@tonic-gate */ 39757c478bd9Sstevel@tonic-gate pcm_event_manager(PCE_INIT_DEV, device.socket, &device); 39767c478bd9Sstevel@tonic-gate 39777c478bd9Sstevel@tonic-gate return (err); 39787c478bd9Sstevel@tonic-gate } 39797c478bd9Sstevel@tonic-gate 39807c478bd9Sstevel@tonic-gate /* 39817c478bd9Sstevel@tonic-gate * pcmcia_get_minors() 39827c478bd9Sstevel@tonic-gate * We need to traverse the minor node list of the 39837c478bd9Sstevel@tonic-gate * dip if there are any. This takes two passes; 39847c478bd9Sstevel@tonic-gate * one to get the count and buffer size and the 39857c478bd9Sstevel@tonic-gate * other to actually copy the data into the buffer. 39867c478bd9Sstevel@tonic-gate * The framework requires that the dip be locked 39877c478bd9Sstevel@tonic-gate * during this time to avoid breakage as well as the 39887c478bd9Sstevel@tonic-gate * driver being locked. 39897c478bd9Sstevel@tonic-gate */ 39907c478bd9Sstevel@tonic-gate int 39917c478bd9Sstevel@tonic-gate pcmcia_get_minors(dev_info_t *dip, struct pcm_make_dev **minors) 39927c478bd9Sstevel@tonic-gate { 3993b9ccdc5aScth int circ; 39947c478bd9Sstevel@tonic-gate int count = 0; 39957c478bd9Sstevel@tonic-gate struct ddi_minor_data *dp; 39967c478bd9Sstevel@tonic-gate struct pcm_make_dev *md; 39977c478bd9Sstevel@tonic-gate int socket; 39987c478bd9Sstevel@tonic-gate major_t major; 39997c478bd9Sstevel@tonic-gate struct dev_ops *ops; 40007c478bd9Sstevel@tonic-gate 40017c478bd9Sstevel@tonic-gate socket = ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 40027c478bd9Sstevel@tonic-gate PCM_DEV_SOCKET, -1); 4003b9ccdc5aScth ndi_devi_enter(dip, &circ); 40047c478bd9Sstevel@tonic-gate if (DEVI(dip)->devi_minor != (struct ddi_minor_data *)NULL) { 40057c478bd9Sstevel@tonic-gate for (dp = DEVI(dip)->devi_minor; 40065c066ec2SJerry Gilliam dp != (struct ddi_minor_data *)NULL; 40075c066ec2SJerry Gilliam dp = dp->next) { 40087c478bd9Sstevel@tonic-gate count++; /* have one more */ 40097c478bd9Sstevel@tonic-gate } 40107c478bd9Sstevel@tonic-gate /* we now know how many nodes to allocate */ 40117c478bd9Sstevel@tonic-gate md = kmem_zalloc(count * sizeof (struct pcm_make_dev), 40127c478bd9Sstevel@tonic-gate KM_NOSLEEP); 40137c478bd9Sstevel@tonic-gate if (md != NULL) { 40147c478bd9Sstevel@tonic-gate *minors = md; 40157c478bd9Sstevel@tonic-gate for (dp = DEVI(dip)->devi_minor; 40165c066ec2SJerry Gilliam dp != (struct ddi_minor_data *)NULL; 40175c066ec2SJerry Gilliam dp = dp->next, md++) { 40187c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 40197c478bd9Sstevel@tonic-gate if (pcmcia_debug > 1) { 40207c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 40215c066ec2SJerry Gilliam "pcmcia_get_minors: name=%s," 40225c066ec2SJerry Gilliam "socket=%d, stype=%x, " 40235c066ec2SJerry Gilliam "ntype=%s, dev_t=%x", 40245c066ec2SJerry Gilliam dp->ddm_name, 40255c066ec2SJerry Gilliam socket, 40265c066ec2SJerry Gilliam dp->ddm_spec_type, 40275c066ec2SJerry Gilliam dp->ddm_node_type, 40285c066ec2SJerry Gilliam (int)dp->ddm_dev); 40297c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 40305c066ec2SJerry Gilliam "\tbind name = %s\n", 40315c066ec2SJerry Gilliam ddi_binding_name(dip)); 40327c478bd9Sstevel@tonic-gate } 40337c478bd9Sstevel@tonic-gate #endif 40347c478bd9Sstevel@tonic-gate md->socket = socket; 40357c478bd9Sstevel@tonic-gate md->op = SS_CSINITDEV_CREATE_DEVICE; 40367c478bd9Sstevel@tonic-gate md->dev = dp->ddm_dev; 40377c478bd9Sstevel@tonic-gate md->type = dp->ddm_spec_type; 40387c478bd9Sstevel@tonic-gate (void) strcpy(md->driver, 40397c478bd9Sstevel@tonic-gate ddi_binding_name(dip)); 40405c066ec2SJerry Gilliam major = ddi_driver_major(dip); 40417c478bd9Sstevel@tonic-gate ops = ddi_get_driver(dip); 40427c478bd9Sstevel@tonic-gate LOCK_DEV_OPS(&devnamesp[major].dn_lock); 40437c478bd9Sstevel@tonic-gate pcm_pathname(dip, dp->ddm_name, md->path); 40447c478bd9Sstevel@tonic-gate INCR_DEV_OPS_REF(ops); 40457c478bd9Sstevel@tonic-gate (void) ddi_pathname(dip, md->path); 40467c478bd9Sstevel@tonic-gate DECR_DEV_OPS_REF(ops); 40477c478bd9Sstevel@tonic-gate UNLOCK_DEV_OPS(&devnamesp[major].dn_lock); 40487c478bd9Sstevel@tonic-gate (void) sprintf(md->path + strlen(md->path), 40495c066ec2SJerry Gilliam ":%s", dp->ddm_name); 40507c478bd9Sstevel@tonic-gate if (dp->next == NULL) 40517c478bd9Sstevel@tonic-gate /* no more */ 40527c478bd9Sstevel@tonic-gate md->flags |= PCM_EVENT_MORE; 40537c478bd9Sstevel@tonic-gate } 40547c478bd9Sstevel@tonic-gate } else { 40557c478bd9Sstevel@tonic-gate count = 0; 40567c478bd9Sstevel@tonic-gate } 40577c478bd9Sstevel@tonic-gate } 4058b9ccdc5aScth ndi_devi_exit(dip, circ); 40597c478bd9Sstevel@tonic-gate return (count); 40607c478bd9Sstevel@tonic-gate } 40617c478bd9Sstevel@tonic-gate 40627c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 40637c478bd9Sstevel@tonic-gate static char *ddmtypes[] = { "minor", "alias", "default", "internal" }; 40647c478bd9Sstevel@tonic-gate 40657c478bd9Sstevel@tonic-gate static void 40667c478bd9Sstevel@tonic-gate pcmcia_dump_minors(dev_info_t *dip) 40677c478bd9Sstevel@tonic-gate { 4068b9ccdc5aScth int circ; 40697c478bd9Sstevel@tonic-gate int count = 0; 40707c478bd9Sstevel@tonic-gate struct ddi_minor_data *dp; 40717c478bd9Sstevel@tonic-gate int unit, major; 40727c478bd9Sstevel@tonic-gate dev_info_t *np; 40737c478bd9Sstevel@tonic-gate 40747c478bd9Sstevel@tonic-gate unit = ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 40757c478bd9Sstevel@tonic-gate PCM_DEV_SOCKET, -1); 40767c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 40775c066ec2SJerry Gilliam "pcmcia_dump_minors: dip=%p, socket=%d\n", (void *)dip, unit); 40787c478bd9Sstevel@tonic-gate 40797c478bd9Sstevel@tonic-gate major = ddi_driver_major(dip); 40807c478bd9Sstevel@tonic-gate if (major != -1) { 40817c478bd9Sstevel@tonic-gate for (np = devnamesp[major].dn_head; np != NULL; 40827c478bd9Sstevel@tonic-gate np = (dev_info_t *)DEVI(np)->devi_next) { 40837c478bd9Sstevel@tonic-gate char *cf2 = ""; 40847c478bd9Sstevel@tonic-gate char *cur = ""; 4085a9fb0ae8Srw if (i_ddi_node_state(np) == DS_READY) 4086a9fb0ae8Srw cf2 = "DS_READY"; 40877c478bd9Sstevel@tonic-gate if (np == dip) 40887c478bd9Sstevel@tonic-gate cur = "CUR"; 40897c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "\tsibs: %s %s %s\n", 40905c066ec2SJerry Gilliam ddi_binding_name(np), cf2, cur); 40917c478bd9Sstevel@tonic-gate 4092b9ccdc5aScth ndi_devi_enter(np, &circ); 40937c478bd9Sstevel@tonic-gate if (DEVI(np)->devi_minor != 40947c478bd9Sstevel@tonic-gate (struct ddi_minor_data *)NULL) { 40957c478bd9Sstevel@tonic-gate for (dp = DEVI(np)->devi_minor; 40967c478bd9Sstevel@tonic-gate dp != (struct ddi_minor_data *)NULL; 40977c478bd9Sstevel@tonic-gate dp = dp->next) { 40987c478bd9Sstevel@tonic-gate count++; /* have one more */ 40997c478bd9Sstevel@tonic-gate } 41007c478bd9Sstevel@tonic-gate for (dp = DEVI(dip)->devi_minor; 41017c478bd9Sstevel@tonic-gate dp != (struct ddi_minor_data *)NULL; 41027c478bd9Sstevel@tonic-gate dp = dp->next) { 41037c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "\ttype=%s, name=%s," 41045c066ec2SJerry Gilliam "socket=%d, stype=%x, " 41055c066ec2SJerry Gilliam "ntype=%s, dev_t=%x", 41065c066ec2SJerry Gilliam ddmtypes[dp->type], 41075c066ec2SJerry Gilliam dp->ddm_name, 41085c066ec2SJerry Gilliam unit, 41095c066ec2SJerry Gilliam dp->ddm_spec_type, 41105c066ec2SJerry Gilliam dp->ddm_node_type, 41115c066ec2SJerry Gilliam (int)dp->ddm_dev); 41127c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "\tbind name = %s\n", 41135c066ec2SJerry Gilliam ddi_binding_name(np)); 41147c478bd9Sstevel@tonic-gate } 41157c478bd9Sstevel@tonic-gate } 4116b9ccdc5aScth ndi_devi_exit(np, circ); 41177c478bd9Sstevel@tonic-gate } 41187c478bd9Sstevel@tonic-gate } 41197c478bd9Sstevel@tonic-gate } 41207c478bd9Sstevel@tonic-gate #endif 41217c478bd9Sstevel@tonic-gate 41227c478bd9Sstevel@tonic-gate /* 41237c478bd9Sstevel@tonic-gate * experimental merging code 41247c478bd9Sstevel@tonic-gate * what are the things that we should merge on? 41257c478bd9Sstevel@tonic-gate * match something by name in the "compatible" property 41267c478bd9Sstevel@tonic-gate * restrict to a specific "socket" 41277c478bd9Sstevel@tonic-gate * restrict to a specific "instance" 41287c478bd9Sstevel@tonic-gate */ 41297c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 41307c478bd9Sstevel@tonic-gate static int 41317c478bd9Sstevel@tonic-gate pcmcia_merge_conf(dev_info_t *dip) 41327c478bd9Sstevel@tonic-gate { 41337c478bd9Sstevel@tonic-gate return (0); /* merge failed */ 41347c478bd9Sstevel@tonic-gate } 41357c478bd9Sstevel@tonic-gate 41367c478bd9Sstevel@tonic-gate /* 41377c478bd9Sstevel@tonic-gate * pcmcia_mfc_intr() 41387c478bd9Sstevel@tonic-gate * Multifunction Card interrupt handler 41397c478bd9Sstevel@tonic-gate * While some adapters share interrupts at the lowest 41407c478bd9Sstevel@tonic-gate * level, some can't. In order to be consistent, we 41417c478bd9Sstevel@tonic-gate * split multifunction cards out with this intercept and 41427c478bd9Sstevel@tonic-gate * allow the low level to do what is best for it. 41437c478bd9Sstevel@tonic-gate * the arg is a pcmcia_socket structure and all interrupts 41447c478bd9Sstevel@tonic-gate * are per-socket in this case. We also have the option 41457c478bd9Sstevel@tonic-gate * to optimize if the cards support it. It also means 41467c478bd9Sstevel@tonic-gate * that we can use the INTRACK mode if it proves desirable 41477c478bd9Sstevel@tonic-gate */ 41487c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 41497c478bd9Sstevel@tonic-gate static uint32_t 41507c478bd9Sstevel@tonic-gate pcmcia_mfc_intr(caddr_t arg1, caddr_t arg2) 41517c478bd9Sstevel@tonic-gate { 41527c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t *sockp; 41537c478bd9Sstevel@tonic-gate inthandler_t *intr, *first; 41547c478bd9Sstevel@tonic-gate int done, result; 41557c478bd9Sstevel@tonic-gate 41567c478bd9Sstevel@tonic-gate sockp = (pcmcia_logical_socket_t *)arg1; 41577c478bd9Sstevel@tonic-gate 41587c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 41597c478bd9Sstevel@tonic-gate if (pcmcia_debug > 1) { 41607c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia_mfc_intr sockp=%p" 41617c478bd9Sstevel@tonic-gate " ls_inthandlers=%p\n" 41627c478bd9Sstevel@tonic-gate "\t ls_flags=0x%x PCS_IRQ_ENABLED=0x%x \n", 41637c478bd9Sstevel@tonic-gate (void *) sockp, (void *) sockp->ls_inthandlers, 41647c478bd9Sstevel@tonic-gate sockp->ls_flags, PCS_IRQ_ENABLED); 41657c478bd9Sstevel@tonic-gate } 41667c478bd9Sstevel@tonic-gate #endif 41677c478bd9Sstevel@tonic-gate 41687c478bd9Sstevel@tonic-gate if (sockp == NULL || sockp->ls_inthandlers == NULL || 41697c478bd9Sstevel@tonic-gate !(sockp->ls_flags & PCS_IRQ_ENABLED)) 41707c478bd9Sstevel@tonic-gate return (DDI_INTR_UNCLAIMED); 41717c478bd9Sstevel@tonic-gate 41727c478bd9Sstevel@tonic-gate mutex_enter(&sockp->ls_ilock); 41737c478bd9Sstevel@tonic-gate for (done = 0, result = 0, first = intr = sockp->ls_inthandlers; 41745c066ec2SJerry Gilliam intr != NULL && !done; intr = intr->next) { 41757c478bd9Sstevel@tonic-gate result |= intr->intr(intr->arg1, intr->arg2); 41767c478bd9Sstevel@tonic-gate if (intr->next == first) 41777c478bd9Sstevel@tonic-gate done++; 41787c478bd9Sstevel@tonic-gate } 41797c478bd9Sstevel@tonic-gate if (intr == NULL) { 41807c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pcmcia_mfc_intr: bad MFC handler list"); 41817c478bd9Sstevel@tonic-gate } 41827c478bd9Sstevel@tonic-gate if (sockp->ls_inthandlers) 41837c478bd9Sstevel@tonic-gate sockp->ls_inthandlers = sockp->ls_inthandlers->next; 41847c478bd9Sstevel@tonic-gate 41857c478bd9Sstevel@tonic-gate mutex_exit(&sockp->ls_ilock); 41867c478bd9Sstevel@tonic-gate return (result ? DDI_INTR_CLAIMED : DDI_INTR_UNCLAIMED); 41877c478bd9Sstevel@tonic-gate } 41887c478bd9Sstevel@tonic-gate 41897c478bd9Sstevel@tonic-gate /* 41907c478bd9Sstevel@tonic-gate * pcmcia_power(dip) 41917c478bd9Sstevel@tonic-gate * control power for nexus and children 41927c478bd9Sstevel@tonic-gate */ 41937c478bd9Sstevel@tonic-gate int 41947c478bd9Sstevel@tonic-gate pcmcia_power(dev_info_t *dip, int component, int level) 41957c478bd9Sstevel@tonic-gate { 41967c478bd9Sstevel@tonic-gate #if 0 41977c478bd9Sstevel@tonic-gate anp_t *anp = (anp_t *)ddi_get_driver_private(dip); 41987c478bd9Sstevel@tonic-gate int i; 41997c478bd9Sstevel@tonic-gate /* 42007c478bd9Sstevel@tonic-gate * for now, we only have one component. Should there be one per-socket? 42017c478bd9Sstevel@tonic-gate * the level is only one (power on or off) 42027c478bd9Sstevel@tonic-gate */ 42037c478bd9Sstevel@tonic-gate if (component != 0 || level > 1) 42047c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 42057c478bd9Sstevel@tonic-gate 42067c478bd9Sstevel@tonic-gate for (i = 0; i < pcic->pc_numsockets; i++) { 42077c478bd9Sstevel@tonic-gate if (pcic->pc_callback) 42087c478bd9Sstevel@tonic-gate PC_CALLBACK(dip, pcic->pc_cb_arg, 42097c478bd9Sstevel@tonic-gate (level == 0) ? PCE_PM_SUSPEND : 42107c478bd9Sstevel@tonic-gate PCE_PM_RESUME, 42117c478bd9Sstevel@tonic-gate i); 42127c478bd9Sstevel@tonic-gate } 42137c478bd9Sstevel@tonic-gate #else 42147c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pcmcia_power: component=%d, level=%d for %s", 42155c066ec2SJerry Gilliam component, level, ddi_get_name_addr(dip)); 42167c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 42177c478bd9Sstevel@tonic-gate #endif 42187c478bd9Sstevel@tonic-gate } 42197c478bd9Sstevel@tonic-gate 42207c478bd9Sstevel@tonic-gate void 42217c478bd9Sstevel@tonic-gate pcmcia_begin_resume(dev_info_t *dip) 42227c478bd9Sstevel@tonic-gate { 42237c478bd9Sstevel@tonic-gate int i; 42247c478bd9Sstevel@tonic-gate struct pcmcia_adapter *adapt = NULL; 42257c478bd9Sstevel@tonic-gate for (i = 0; i < pcmcia_num_adapters; i++) { 42267c478bd9Sstevel@tonic-gate if (pcmcia_adapters[i]->pca_dip == dip) { 42277c478bd9Sstevel@tonic-gate adapt = pcmcia_adapters[i]; 42287c478bd9Sstevel@tonic-gate break; 42297c478bd9Sstevel@tonic-gate } 42307c478bd9Sstevel@tonic-gate } 42317c478bd9Sstevel@tonic-gate if (adapt == NULL) 42327c478bd9Sstevel@tonic-gate return; 42337c478bd9Sstevel@tonic-gate 42347c478bd9Sstevel@tonic-gate for (i = 0; i < adapt->pca_numsockets; i++) { 42357c478bd9Sstevel@tonic-gate int s; 42367c478bd9Sstevel@tonic-gate s = adapt->pca_first_socket + i; 42377c478bd9Sstevel@tonic-gate if (pcmcia_sockets[s]->ls_flags & PCS_SUSPENDED) { 42387c478bd9Sstevel@tonic-gate if (pcmcia_sockets[s]->ls_flags & 42397c478bd9Sstevel@tonic-gate (1 << PCE_PM_RESUME)) { 42407c478bd9Sstevel@tonic-gate (void) cs_event(PCE_PM_RESUME, s, 0); 42417c478bd9Sstevel@tonic-gate pcm_event_manager(PCE_PM_RESUME, s, NULL); 42427c478bd9Sstevel@tonic-gate } 42437c478bd9Sstevel@tonic-gate (void) cs_event(PCE_CARD_REMOVAL, s, 0); 42447c478bd9Sstevel@tonic-gate pcm_event_manager(PCE_CARD_REMOVAL, s, NULL); 42457c478bd9Sstevel@tonic-gate } 42467c478bd9Sstevel@tonic-gate } 42477c478bd9Sstevel@tonic-gate } 42487c478bd9Sstevel@tonic-gate 424911c2b4c0Srw /* 425011c2b4c0Srw * mark a cardbus card as "suspended" in the pcmcia module 425111c2b4c0Srw */ 425211c2b4c0Srw void 425311c2b4c0Srw pcmcia_cb_suspended(int socket) 425411c2b4c0Srw { 425511c2b4c0Srw mutex_enter(&pcmcia_global_lock); 425611c2b4c0Srw pcmcia_sockets[socket]->ls_flags |= PCS_SUSPENDED; 425711c2b4c0Srw mutex_exit(&pcmcia_global_lock); 425811c2b4c0Srw 425911c2b4c0Srw } 426011c2b4c0Srw 426111c2b4c0Srw /* 426211c2b4c0Srw * mark a cardbus card as "resumed" in the pcmcia module 426311c2b4c0Srw */ 426411c2b4c0Srw void 426511c2b4c0Srw pcmcia_cb_resumed(int socket) 426611c2b4c0Srw { 426711c2b4c0Srw if (pcmcia_sockets[socket]->ls_flags & PCS_SUSPENDED) { 426811c2b4c0Srw mutex_enter(&pcmcia_global_lock); 426911c2b4c0Srw pcmcia_sockets[socket]->ls_flags &= ~PCS_SUSPENDED; 427011c2b4c0Srw cv_broadcast(&pcmcia_condvar); 427111c2b4c0Srw mutex_exit(&pcmcia_global_lock); 427211c2b4c0Srw #ifdef PCMCIA_DEBUG 427311c2b4c0Srw if (pcmcia_debug) { 427411c2b4c0Srw cmn_err(CE_NOTE, "pcmcia_cb_resume RESUMED"); 427511c2b4c0Srw } 427611c2b4c0Srw #endif 427711c2b4c0Srw } 427811c2b4c0Srw 427911c2b4c0Srw } 428011c2b4c0Srw 42817c478bd9Sstevel@tonic-gate void 42827c478bd9Sstevel@tonic-gate pcmcia_wait_insert(dev_info_t *dip) 42837c478bd9Sstevel@tonic-gate { 42847c478bd9Sstevel@tonic-gate int i, f, tries, done; 42857c478bd9Sstevel@tonic-gate struct pcmcia_adapter *adapt = NULL; 42867c478bd9Sstevel@tonic-gate anp_t *nexus; 42877c478bd9Sstevel@tonic-gate 42887c478bd9Sstevel@tonic-gate for (i = 0; i < pcmcia_num_adapters; i++) { 42897c478bd9Sstevel@tonic-gate if (pcmcia_adapters[i]->pca_dip == dip) { 42907c478bd9Sstevel@tonic-gate adapt = pcmcia_adapters[i]; 42917c478bd9Sstevel@tonic-gate break; 42927c478bd9Sstevel@tonic-gate } 42937c478bd9Sstevel@tonic-gate } 42947c478bd9Sstevel@tonic-gate if (adapt == NULL) 42957c478bd9Sstevel@tonic-gate return; 42967c478bd9Sstevel@tonic-gate 42977c478bd9Sstevel@tonic-gate for (tries = adapt->pca_numsockets * 10; tries > 0; tries--) { 42987c478bd9Sstevel@tonic-gate done = 1; 42997c478bd9Sstevel@tonic-gate mutex_enter(&pcmcia_global_lock); 43007c478bd9Sstevel@tonic-gate for (i = 0; i < adapt->pca_numsockets; i++) { 43017c478bd9Sstevel@tonic-gate int s; 43027c478bd9Sstevel@tonic-gate s = adapt->pca_first_socket + i; 43037c478bd9Sstevel@tonic-gate for (f = 0; f < PCMCIA_MAX_FUNCTIONS; f++) 43047c478bd9Sstevel@tonic-gate if (pcmcia_sockets[s] && 43057c478bd9Sstevel@tonic-gate pcmcia_sockets[s]->ls_flags & 43067c478bd9Sstevel@tonic-gate PCS_SUSPENDED) { 430711c2b4c0Srw 430811c2b4c0Srw #ifdef PCMCIA_DEBUG 430911c2b4c0Srw if (pcmcia_debug) { 431011c2b4c0Srw cmn_err(CE_NOTE, 43115c066ec2SJerry Gilliam "pcmcia_wait_insert: " 43125c066ec2SJerry Gilliam "socket in SUSPENDED " 43135c066ec2SJerry Gilliam "state"); 431411c2b4c0Srw } 431511c2b4c0Srw #endif 43167c478bd9Sstevel@tonic-gate done = 0; 43177c478bd9Sstevel@tonic-gate break; 43187c478bd9Sstevel@tonic-gate } 43197c478bd9Sstevel@tonic-gate } 43207c478bd9Sstevel@tonic-gate if (!done) { 4321d3d50737SRafael Vanoni (void) cv_reltimedwait(&pcmcia_condvar, 4322d3d50737SRafael Vanoni &pcmcia_global_lock, drv_usectohz(100000), 4323d3d50737SRafael Vanoni TR_CLOCK_TICK); 43247c478bd9Sstevel@tonic-gate } else { 43257c478bd9Sstevel@tonic-gate tries = 0; 43267c478bd9Sstevel@tonic-gate } 43277c478bd9Sstevel@tonic-gate mutex_exit(&pcmcia_global_lock); 43287c478bd9Sstevel@tonic-gate } 43297c478bd9Sstevel@tonic-gate 433011c2b4c0Srw if (tries == 0) { 433111c2b4c0Srw cmn_err(CE_NOTE, "pcmcia_wait_insert timed out"); 433211c2b4c0Srw } 433311c2b4c0Srw 43347c478bd9Sstevel@tonic-gate nexus = (anp_t *)ddi_get_driver_private(dip); 43357c478bd9Sstevel@tonic-gate pcmcia_find_cards(nexus); 43367c478bd9Sstevel@tonic-gate } 43377c478bd9Sstevel@tonic-gate 43387c478bd9Sstevel@tonic-gate int 43397c478bd9Sstevel@tonic-gate pcmcia_map_reg(dev_info_t *pdip, dev_info_t *dip, ra_return_t *ra, 43407c478bd9Sstevel@tonic-gate uint32_t state, caddr_t *base, 43417c478bd9Sstevel@tonic-gate ddi_acc_handle_t *handle, ddi_device_acc_attr_t *attrib, 43427c478bd9Sstevel@tonic-gate uint32_t req_base) 43437c478bd9Sstevel@tonic-gate { 43447c478bd9Sstevel@tonic-gate struct pcmcia_parent_private *ppd; 43457c478bd9Sstevel@tonic-gate int rnum = 0, type = PCMCIA_MAP_MEM; 43467c478bd9Sstevel@tonic-gate ddi_map_req_t mr; 43477c478bd9Sstevel@tonic-gate ddi_acc_hdl_t *hp; 43487c478bd9Sstevel@tonic-gate int result; 43497c478bd9Sstevel@tonic-gate struct regspec *reg; 43507c478bd9Sstevel@tonic-gate ddi_device_acc_attr_t attr; 43517c478bd9Sstevel@tonic-gate 43527c478bd9Sstevel@tonic-gate if (dip != NULL) { 43537c478bd9Sstevel@tonic-gate ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(dip); 43547c478bd9Sstevel@tonic-gate if (ppd == NULL) 43557c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 43567c478bd9Sstevel@tonic-gate for (rnum = 1; rnum < ppd->ppd_nreg; rnum++) { 43577c478bd9Sstevel@tonic-gate struct pcm_regs *p; 43587c478bd9Sstevel@tonic-gate p = &ppd->ppd_reg[rnum]; 43597c478bd9Sstevel@tonic-gate if (state & WS_IO) { 43607c478bd9Sstevel@tonic-gate /* need I/O */ 43617c478bd9Sstevel@tonic-gate type = PCMCIA_MAP_IO; 43627c478bd9Sstevel@tonic-gate /* 43637c478bd9Sstevel@tonic-gate * We want to find an IO regspec. When we 43647c478bd9Sstevel@tonic-gate * find one, it either has to match 43657c478bd9Sstevel@tonic-gate * the caller's requested base address 43667c478bd9Sstevel@tonic-gate * or it has to be relocatable. 43677c478bd9Sstevel@tonic-gate * We match on the requested base address 43687c478bd9Sstevel@tonic-gate * rather than the allocated base 43697c478bd9Sstevel@tonic-gate * address so that we handle the case 43707c478bd9Sstevel@tonic-gate * of adapters that have IO window base 43717c478bd9Sstevel@tonic-gate * relocation registers. 43727c478bd9Sstevel@tonic-gate */ 43737c478bd9Sstevel@tonic-gate if ((p->phys_hi & 43747c478bd9Sstevel@tonic-gate PC_REG_SPACE(PC_REG_SPACE_IO)) && 43755c066ec2SJerry Gilliam ((req_base == p->phys_lo) || 43765c066ec2SJerry Gilliam !(p->phys_hi & PC_REG_RELOC(1)))) 43775c066ec2SJerry Gilliam break; 43787c478bd9Sstevel@tonic-gate } else { 43797c478bd9Sstevel@tonic-gate /* need memory */ 43807c478bd9Sstevel@tonic-gate type = PCMCIA_MAP_MEM; 43817c478bd9Sstevel@tonic-gate if (p->phys_hi & 43827c478bd9Sstevel@tonic-gate PC_REG_SPACE(PC_REG_SPACE_MEMORY| 43837c478bd9Sstevel@tonic-gate PC_REG_SPACE_ATTRIBUTE)) 43847c478bd9Sstevel@tonic-gate break; 43857c478bd9Sstevel@tonic-gate } 43867c478bd9Sstevel@tonic-gate } 43877c478bd9Sstevel@tonic-gate if (rnum >= ppd->ppd_nreg) 43887c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 43897c478bd9Sstevel@tonic-gate } else if (state & WS_IO) { 43907c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 43917c478bd9Sstevel@tonic-gate } 43927c478bd9Sstevel@tonic-gate 43937c478bd9Sstevel@tonic-gate reg = kmem_zalloc(sizeof (pci_regspec_t), KM_SLEEP); 43947c478bd9Sstevel@tonic-gate reg = pcmcia_cons_regspec(pdip, type, (uchar_t *)reg, ra); 43957c478bd9Sstevel@tonic-gate 43967c478bd9Sstevel@tonic-gate if (attrib == NULL || 43977c478bd9Sstevel@tonic-gate attrib->devacc_attr_version != DDI_DEVICE_ATTR_V0) { 43987c478bd9Sstevel@tonic-gate attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 43997c478bd9Sstevel@tonic-gate attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC; 44007c478bd9Sstevel@tonic-gate attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 44017c478bd9Sstevel@tonic-gate } else { 44027c478bd9Sstevel@tonic-gate attr = *attrib; 44037c478bd9Sstevel@tonic-gate } 44047c478bd9Sstevel@tonic-gate /* 44057c478bd9Sstevel@tonic-gate * Allocate and initialize the common elements of data access handle. 44067c478bd9Sstevel@tonic-gate */ 44077c478bd9Sstevel@tonic-gate *handle = impl_acc_hdl_alloc(KM_SLEEP, NULL); 44087c478bd9Sstevel@tonic-gate hp = impl_acc_hdl_get(*handle); 44097c478bd9Sstevel@tonic-gate hp->ah_vers = VERS_ACCHDL; 44107c478bd9Sstevel@tonic-gate hp->ah_dip = dip != NULL ? dip : pdip; 44117c478bd9Sstevel@tonic-gate hp->ah_rnumber = rnum; 44127c478bd9Sstevel@tonic-gate hp->ah_offset = 0; 44137c478bd9Sstevel@tonic-gate hp->ah_len = ra->ra_len; 44147c478bd9Sstevel@tonic-gate hp->ah_acc = attr; 44157c478bd9Sstevel@tonic-gate 44167c478bd9Sstevel@tonic-gate /* 44177c478bd9Sstevel@tonic-gate * Set up the mapping request and call to parent. 44187c478bd9Sstevel@tonic-gate */ 44197c478bd9Sstevel@tonic-gate mr.map_op = DDI_MO_MAP_LOCKED; 44207c478bd9Sstevel@tonic-gate mr.map_type = DDI_MT_REGSPEC; 44217c478bd9Sstevel@tonic-gate mr.map_obj.rp = reg; 44227c478bd9Sstevel@tonic-gate mr.map_prot = PROT_READ | PROT_WRITE; 44237c478bd9Sstevel@tonic-gate mr.map_flags = DDI_MF_KERNEL_MAPPING; 44247c478bd9Sstevel@tonic-gate mr.map_handlep = hp; 44257c478bd9Sstevel@tonic-gate mr.map_vers = DDI_MAP_VERSION; 44267c478bd9Sstevel@tonic-gate 44277c478bd9Sstevel@tonic-gate result = ddi_map(pdip, &mr, 0, ra->ra_len, base); 44287c478bd9Sstevel@tonic-gate if (result != DDI_SUCCESS) { 44297c478bd9Sstevel@tonic-gate impl_acc_hdl_free(*handle); 44307c478bd9Sstevel@tonic-gate *handle = (ddi_acc_handle_t)NULL; 44317c478bd9Sstevel@tonic-gate } else { 44327c478bd9Sstevel@tonic-gate hp->ah_addr = *base; 44337c478bd9Sstevel@tonic-gate if (mr.map_op == DDI_MO_UNMAP) 44347c478bd9Sstevel@tonic-gate ra = NULL; 44357c478bd9Sstevel@tonic-gate if (dip != NULL) 44367c478bd9Sstevel@tonic-gate pcmcia_set_assigned(dip, rnum, ra); 44377c478bd9Sstevel@tonic-gate } 44387c478bd9Sstevel@tonic-gate 4439981012acSrw kmem_free(reg, sizeof (pci_regspec_t)); 4440981012acSrw 44417c478bd9Sstevel@tonic-gate return (result); 44427c478bd9Sstevel@tonic-gate } 44437c478bd9Sstevel@tonic-gate 44447c478bd9Sstevel@tonic-gate struct pcmcia_adapter * 44457c478bd9Sstevel@tonic-gate pcmcia_get_adapter(dev_info_t *dip) 44467c478bd9Sstevel@tonic-gate { 44477c478bd9Sstevel@tonic-gate int i; 44487c478bd9Sstevel@tonic-gate 44497c478bd9Sstevel@tonic-gate for (i = 0; i < pcmcia_num_adapters; i++) { 44507c478bd9Sstevel@tonic-gate if (pcmcia_adapters[i] && 44517c478bd9Sstevel@tonic-gate pcmcia_adapters[i]->pca_dip == dip) { 44527c478bd9Sstevel@tonic-gate return (pcmcia_adapters[i]); 44537c478bd9Sstevel@tonic-gate } 44547c478bd9Sstevel@tonic-gate } 44557c478bd9Sstevel@tonic-gate return (NULL); 44567c478bd9Sstevel@tonic-gate } 44577c478bd9Sstevel@tonic-gate 44587c478bd9Sstevel@tonic-gate 44597c478bd9Sstevel@tonic-gate void 44607c478bd9Sstevel@tonic-gate pcmcia_set_assigned(dev_info_t *dip, int rnum, ra_return_t *ret) 44617c478bd9Sstevel@tonic-gate { 44627c478bd9Sstevel@tonic-gate struct pcmcia_parent_private *ppd; 44637c478bd9Sstevel@tonic-gate struct pcm_regs *reg, *assign; 44647c478bd9Sstevel@tonic-gate 44657c478bd9Sstevel@tonic-gate ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(dip); 44667c478bd9Sstevel@tonic-gate if (ppd) { 44677c478bd9Sstevel@tonic-gate reg = &ppd->ppd_reg[rnum]; 44687c478bd9Sstevel@tonic-gate assign = &ppd->ppd_assigned[rnum]; 44697c478bd9Sstevel@tonic-gate if (ret) { 44707c478bd9Sstevel@tonic-gate if (assign->phys_hi == 0) { 44717c478bd9Sstevel@tonic-gate assign->phys_hi = reg->phys_hi; 44727c478bd9Sstevel@tonic-gate assign->phys_lo = ret->ra_addr_lo; 44737c478bd9Sstevel@tonic-gate assign->phys_len = ret->ra_len; 44747c478bd9Sstevel@tonic-gate } else if (assign->phys_lo != ret->ra_addr_lo) { 44757c478bd9Sstevel@tonic-gate #ifdef PCMCIA_DEBUG 44767c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pcmcia: bad address:" 44775c066ec2SJerry Gilliam "%s=<%x,%x>", 44785c066ec2SJerry Gilliam ddi_get_name_addr(dip), 44795c066ec2SJerry Gilliam ret->ra_addr_lo, assign->phys_lo); 44807c478bd9Sstevel@tonic-gate #else 44817c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "!pcmcia: bad address:" 44825c066ec2SJerry Gilliam "%s=<%x,%x>", 44835c066ec2SJerry Gilliam ddi_get_name_addr(dip), 44845c066ec2SJerry Gilliam ret->ra_addr_lo, (int)assign->phys_lo); 44857c478bd9Sstevel@tonic-gate #endif 44867c478bd9Sstevel@tonic-gate } 44877c478bd9Sstevel@tonic-gate assign->phys_hi = PC_INCR_REFCNT(assign->phys_hi); 44887c478bd9Sstevel@tonic-gate } else { 44897c478bd9Sstevel@tonic-gate int i; 44907c478bd9Sstevel@tonic-gate assign->phys_hi = PC_DECR_REFCNT(assign->phys_hi); 44917c478bd9Sstevel@tonic-gate i = PC_GET_REG_REFCNT(assign->phys_hi); 44927c478bd9Sstevel@tonic-gate if (i == 0) { 44937c478bd9Sstevel@tonic-gate assign->phys_hi = 0; 44947c478bd9Sstevel@tonic-gate assign->phys_lo = 0; 44957c478bd9Sstevel@tonic-gate assign->phys_len = 0; 44967c478bd9Sstevel@tonic-gate } 44977c478bd9Sstevel@tonic-gate } 44987c478bd9Sstevel@tonic-gate } 44997c478bd9Sstevel@tonic-gate } 45007c478bd9Sstevel@tonic-gate 45017c478bd9Sstevel@tonic-gate int 45028134ee03Srw pcmcia_alloc_mem(dev_info_t *dip, ndi_ra_request_t *req, ra_return_t *ret, 45038134ee03Srw dev_info_t **res_dip) 45047c478bd9Sstevel@tonic-gate { 45058134ee03Srw return (pcmcia_ra_alloc(dip, req, ret, NDI_RA_TYPE_MEM, res_dip)); 45067c478bd9Sstevel@tonic-gate } 45077c478bd9Sstevel@tonic-gate 45087c478bd9Sstevel@tonic-gate int 45098134ee03Srw pcmcia_alloc_io(dev_info_t *dip, ndi_ra_request_t *req, ra_return_t *ret, 45108134ee03Srw dev_info_t **res_dip) 45117c478bd9Sstevel@tonic-gate { 45128134ee03Srw return (pcmcia_ra_alloc(dip, req, ret, NDI_RA_TYPE_IO, res_dip)); 45138134ee03Srw } 45148134ee03Srw 45158134ee03Srw static boolean_t 45168134ee03Srw is_subtractv(dev_info_t *dip) 45178134ee03Srw { 45188134ee03Srw uint_t class; 45198134ee03Srw 45208134ee03Srw if (dip == NULL) 45218134ee03Srw return (B_FALSE); 45228134ee03Srw class = ddi_getprop(DDI_DEV_T_ANY, dip, 45235c066ec2SJerry Gilliam DDI_PROP_CANSLEEP|DDI_PROP_DONTPASS, 45245c066ec2SJerry Gilliam "class-code", 0xff); 45258134ee03Srw if (class == PPB_SUBTRACTIVE) { 45268134ee03Srw return (B_TRUE); 45278134ee03Srw } 45288134ee03Srw return (B_FALSE); 45298134ee03Srw } 45308134ee03Srw 45318134ee03Srw /* 45328134ee03Srw * pcmcia_pci_alloc() 45338134ee03Srw * allocate mem or I/O resource from the ancestor of the cardbus bridge. 45348134ee03Srw * First start from the parent node. If the parent is a subtractive 45358134ee03Srw * decode bridge and it does not have the requested resource, go up the 45368134ee03Srw * device tree to find the resource. 45378134ee03Srw * 45388134ee03Srw * dip the parent node of the cardbus bridge 45398134ee03Srw * 45408134ee03Srw * res_dip returns a pointer to the node from which the 45418134ee03Srw * resource is obtained. *res_dip could point to 45428134ee03Srw * the parent or a higher level ancestor. *res_dip 45438134ee03Srw * should be saved by the caller and later passed 45448134ee03Srw * to pcmcia_ra_free(); 45458134ee03Srw */ 45468134ee03Srw int 45478134ee03Srw pcmcia_pci_alloc(dev_info_t *dip, ndi_ra_request_t *req, ra_return_t *ret, 45488134ee03Srw char *type, dev_info_t **res_dip) 45498134ee03Srw { 45508134ee03Srw uint64_t base = 0; 45518134ee03Srw uint64_t len = 0; 45528134ee03Srw 45538134ee03Srw if ((ndi_ra_alloc(dip, req, &base, &len, type, NDI_RA_PASS) 45545c066ec2SJerry Gilliam == NDI_FAILURE) || 45558134ee03Srw ((base >> 32) != 0)) { 45568134ee03Srw if (is_subtractv(dip)) { 45578134ee03Srw return (pcmcia_pci_alloc(ddi_get_parent(dip), 45585c066ec2SJerry Gilliam req, ret, type, res_dip)); 45598134ee03Srw 45608134ee03Srw } else { 45618134ee03Srw ret->ra_addr_hi = 0; 45628134ee03Srw ret->ra_addr_lo = 0; 45638134ee03Srw ret->ra_len = 0; 45648134ee03Srw return (DDI_FAILURE); 45658134ee03Srw } 45668134ee03Srw } 45678134ee03Srw ret->ra_addr_lo = base & 0xffffffff; 45688134ee03Srw ret->ra_addr_hi = 0; 45698134ee03Srw ret->ra_len = len; 45708134ee03Srw *res_dip = dip; 45718134ee03Srw return (DDI_SUCCESS); 45727c478bd9Sstevel@tonic-gate } 45737c478bd9Sstevel@tonic-gate 45747c478bd9Sstevel@tonic-gate int 45757c478bd9Sstevel@tonic-gate pcmcia_ra_alloc(dev_info_t *dip, ndi_ra_request_t *req, ra_return_t *ret, 45768134ee03Srw char *type, dev_info_t **res_dip) 45777c478bd9Sstevel@tonic-gate { 45787c478bd9Sstevel@tonic-gate uint64_t base = 0; 45797c478bd9Sstevel@tonic-gate uint64_t len = 0; 45807c478bd9Sstevel@tonic-gate 45817c478bd9Sstevel@tonic-gate /* 45827c478bd9Sstevel@tonic-gate * Allocate space from busra resource list 45837c478bd9Sstevel@tonic-gate * should not return an address > 32 bits 45847c478bd9Sstevel@tonic-gate */ 45857c478bd9Sstevel@tonic-gate 45867c478bd9Sstevel@tonic-gate if ((ndi_ra_alloc(dip, req, &base, &len, type, NDI_RA_PASS) 45875c066ec2SJerry Gilliam == NDI_FAILURE) || 45887c478bd9Sstevel@tonic-gate ((base >> 32) != 0)) { 45898134ee03Srw return (pcmcia_pci_alloc(ddi_get_parent(dip), req, ret, 45905c066ec2SJerry Gilliam type, res_dip)); 45917c478bd9Sstevel@tonic-gate } else { 45927c478bd9Sstevel@tonic-gate ret->ra_addr_lo = base & 0xffffffff; 45938134ee03Srw ret->ra_addr_hi = 0; 45947c478bd9Sstevel@tonic-gate ret->ra_len = len; 45958134ee03Srw *res_dip = dip; 45968134ee03Srw return (DDI_SUCCESS); 45977c478bd9Sstevel@tonic-gate } 45987c478bd9Sstevel@tonic-gate } 45997c478bd9Sstevel@tonic-gate 46007c478bd9Sstevel@tonic-gate int 46017c478bd9Sstevel@tonic-gate pcmcia_free_mem(dev_info_t *dip, ra_return_t *ret) 46027c478bd9Sstevel@tonic-gate { 46037c478bd9Sstevel@tonic-gate return (pcmcia_ra_free(dip, ret, NDI_RA_TYPE_MEM)); 46047c478bd9Sstevel@tonic-gate } 46057c478bd9Sstevel@tonic-gate 46067c478bd9Sstevel@tonic-gate int 46077c478bd9Sstevel@tonic-gate pcmcia_free_io(dev_info_t *dip, ra_return_t *ret) 46087c478bd9Sstevel@tonic-gate { 46097c478bd9Sstevel@tonic-gate return (pcmcia_ra_free(dip, ret, NDI_RA_TYPE_IO)); 46107c478bd9Sstevel@tonic-gate } 46117c478bd9Sstevel@tonic-gate 46127c478bd9Sstevel@tonic-gate int 46137c478bd9Sstevel@tonic-gate pcmcia_ra_free(dev_info_t *dip, ra_return_t *ret, char *type) 46147c478bd9Sstevel@tonic-gate { 461581ea8c75Srw if (dip == (dev_info_t *)-1) 461681ea8c75Srw return (DDI_FAILURE); 46177c478bd9Sstevel@tonic-gate if (ndi_ra_free(dip, (uint64_t)ret->ra_addr_lo, (uint64_t)ret->ra_len, 46187c478bd9Sstevel@tonic-gate type, NDI_RA_PASS) == NDI_SUCCESS) { 46197c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 46207c478bd9Sstevel@tonic-gate } else { 46217c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 46227c478bd9Sstevel@tonic-gate } 46237c478bd9Sstevel@tonic-gate } 46247c478bd9Sstevel@tonic-gate 46257c478bd9Sstevel@tonic-gate 46267c478bd9Sstevel@tonic-gate /* 46277c478bd9Sstevel@tonic-gate * when the low level device configuration does resource assignment 46287c478bd9Sstevel@tonic-gate * (devconf) then free the allocated resources so we can reassign them 46297c478bd9Sstevel@tonic-gate * later. Walk the child list to get them. 46307c478bd9Sstevel@tonic-gate */ 46317c478bd9Sstevel@tonic-gate void 46327c478bd9Sstevel@tonic-gate pcmcia_free_resources(dev_info_t *self) 46337c478bd9Sstevel@tonic-gate { 46347c478bd9Sstevel@tonic-gate struct regspec *assigned; 46357c478bd9Sstevel@tonic-gate int len; 46367c478bd9Sstevel@tonic-gate dev_info_t *dip; 4637b9ccdc5aScth int circ; 46387c478bd9Sstevel@tonic-gate 4639b9ccdc5aScth ndi_devi_enter(self, &circ); 46407c478bd9Sstevel@tonic-gate /* do searches in compatible property order */ 46417c478bd9Sstevel@tonic-gate for (dip = (dev_info_t *)DEVI(self)->devi_child; 46427c478bd9Sstevel@tonic-gate dip != NULL; 46437c478bd9Sstevel@tonic-gate dip = (dev_info_t *)DEVI(dip)->devi_sibling) { 46447c478bd9Sstevel@tonic-gate len = 0; 4645a3282898Scth if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 46467c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS|DDI_PROP_CANSLEEP, 46477c478bd9Sstevel@tonic-gate "assigned-addresses", 46487c478bd9Sstevel@tonic-gate (caddr_t)&assigned, 46497c478bd9Sstevel@tonic-gate &len) == DDI_PROP_SUCCESS) { 46507c478bd9Sstevel@tonic-gate /* 46517c478bd9Sstevel@tonic-gate * if there are assigned resources at this point, 46527c478bd9Sstevel@tonic-gate * then the OBP or devconf have assigned them and 46537c478bd9Sstevel@tonic-gate * they need to be freed. 46547c478bd9Sstevel@tonic-gate */ 46557c478bd9Sstevel@tonic-gate kmem_free(assigned, len); 46567c478bd9Sstevel@tonic-gate } 46577c478bd9Sstevel@tonic-gate } 4658b9ccdc5aScth ndi_devi_exit(self, circ); 46597c478bd9Sstevel@tonic-gate } 46607c478bd9Sstevel@tonic-gate 46617c478bd9Sstevel@tonic-gate /* 46627c478bd9Sstevel@tonic-gate * this is the equivalent of pcm_get_intr using ra_allocs. 46637c478bd9Sstevel@tonic-gate * returns -1 if failed, otherwise returns the allocated irq. 46647c478bd9Sstevel@tonic-gate * The input request, if less than zero it means not a specific 46657c478bd9Sstevel@tonic-gate * irq requested. If larger then 0 then we are requesting that specific 46667c478bd9Sstevel@tonic-gate * irq 46677c478bd9Sstevel@tonic-gate */ 46687c478bd9Sstevel@tonic-gate int 46697c478bd9Sstevel@tonic-gate pcmcia_get_intr(dev_info_t *dip, int request) 46707c478bd9Sstevel@tonic-gate { 46717c478bd9Sstevel@tonic-gate ndi_ra_request_t req; 46727c478bd9Sstevel@tonic-gate uint64_t base; 46737c478bd9Sstevel@tonic-gate uint64_t len; 46747c478bd9Sstevel@tonic-gate int err; 46757c478bd9Sstevel@tonic-gate 46767c478bd9Sstevel@tonic-gate bzero(&req, sizeof (req)); 46777c478bd9Sstevel@tonic-gate base = 0; 46787c478bd9Sstevel@tonic-gate len = 1; 46797c478bd9Sstevel@tonic-gate if (request >= 0) { 46807c478bd9Sstevel@tonic-gate req.ra_flags = NDI_RA_ALLOC_SPECIFIED; 46817c478bd9Sstevel@tonic-gate req.ra_len = 1; 46827c478bd9Sstevel@tonic-gate req.ra_addr = (uint64_t)request; 46837c478bd9Sstevel@tonic-gate } 46847c478bd9Sstevel@tonic-gate 46857c478bd9Sstevel@tonic-gate req.ra_boundbase = 0; 46867c478bd9Sstevel@tonic-gate req.ra_boundlen = 0xffffffffUL; 46877c478bd9Sstevel@tonic-gate req.ra_flags |= NDI_RA_ALLOC_BOUNDED; 46887c478bd9Sstevel@tonic-gate 46897c478bd9Sstevel@tonic-gate err = ndi_ra_alloc(dip, &req, &base, &len, NDI_RA_TYPE_INTR, 46907c478bd9Sstevel@tonic-gate NDI_RA_PASS); 46917c478bd9Sstevel@tonic-gate 46927c478bd9Sstevel@tonic-gate if (err == NDI_FAILURE) { 46937c478bd9Sstevel@tonic-gate return (-1); 46947c478bd9Sstevel@tonic-gate } else { 46957c478bd9Sstevel@tonic-gate return ((int)base); 46967c478bd9Sstevel@tonic-gate } 46977c478bd9Sstevel@tonic-gate } 46987c478bd9Sstevel@tonic-gate 46997c478bd9Sstevel@tonic-gate 47007c478bd9Sstevel@tonic-gate int 47017c478bd9Sstevel@tonic-gate pcmcia_return_intr(dev_info_t *dip, int request) 47027c478bd9Sstevel@tonic-gate { 47037c478bd9Sstevel@tonic-gate if ((ndi_ra_free(dip, (uint64_t)request, 1, NDI_RA_TYPE_INTR, 47047c478bd9Sstevel@tonic-gate NDI_RA_PASS)) == NDI_SUCCESS) { 47057c478bd9Sstevel@tonic-gate return (0); 47067c478bd9Sstevel@tonic-gate } else 47077c478bd9Sstevel@tonic-gate return (-1); 47087c478bd9Sstevel@tonic-gate 47097c478bd9Sstevel@tonic-gate } 47107c478bd9Sstevel@tonic-gate 47117c478bd9Sstevel@tonic-gate #ifdef sparc 47127c478bd9Sstevel@tonic-gate 47137c478bd9Sstevel@tonic-gate int 47147c478bd9Sstevel@tonic-gate pcmcia_add_intr_impl(dev_info_t *dip, dev_info_t *rdip, 47157c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp) 47167c478bd9Sstevel@tonic-gate { 47177c478bd9Sstevel@tonic-gate 47187c478bd9Sstevel@tonic-gate struct pcmcia_parent_private *ppd; 47197c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t *sockp; 47207c478bd9Sstevel@tonic-gate int socket, ret; 47217c478bd9Sstevel@tonic-gate struct pcmcia_adapter *adapt; 47227c478bd9Sstevel@tonic-gate set_irq_handler_t handler; 47237c478bd9Sstevel@tonic-gate struct intrspec *pispec; 47247c478bd9Sstevel@tonic-gate 47257c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 47267c478bd9Sstevel@tonic-gate if (pcmcia_debug) { 47277c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 47287c478bd9Sstevel@tonic-gate "pcmcia_add_intr_impl() entered " 47297c478bd9Sstevel@tonic-gate "dip=%p rdip=%p hdlp=%p \n", 47307c478bd9Sstevel@tonic-gate (void *)dip, (void *)rdip, (void *)hdlp); 47317c478bd9Sstevel@tonic-gate } 47327c478bd9Sstevel@tonic-gate #endif 47337c478bd9Sstevel@tonic-gate 47347c478bd9Sstevel@tonic-gate ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(rdip); 47357c478bd9Sstevel@tonic-gate socket = ppd->ppd_socket; 47367c478bd9Sstevel@tonic-gate sockp = pcmcia_sockets[socket]; 47377c478bd9Sstevel@tonic-gate adapt = sockp->ls_adapter; 47387c478bd9Sstevel@tonic-gate 47397c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 47407c478bd9Sstevel@tonic-gate if (pcmcia_debug) { 47417c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia_add_intr_impl()" 47427c478bd9Sstevel@tonic-gate " ppd_flags=0X%x PPD_CARD_MULTI=0X%x\n" 47437c478bd9Sstevel@tonic-gate " ppd_intrspec=%p ls_inthandlers=%p\n", 47447c478bd9Sstevel@tonic-gate ppd->ppd_flags, PPD_CARD_MULTI, 47457c478bd9Sstevel@tonic-gate (void *) ppd->ppd_intrspec, 47467c478bd9Sstevel@tonic-gate (void *)sockp->ls_inthandlers); 47477c478bd9Sstevel@tonic-gate } 47487c478bd9Sstevel@tonic-gate #endif 47497c478bd9Sstevel@tonic-gate 47507c478bd9Sstevel@tonic-gate /* 47517c478bd9Sstevel@tonic-gate * calculate IPL level when we support multiple levels 47527c478bd9Sstevel@tonic-gate */ 47537c478bd9Sstevel@tonic-gate pispec = ppd->ppd_intrspec; 47547c478bd9Sstevel@tonic-gate if (pispec == NULL) { 47557c478bd9Sstevel@tonic-gate sockp->ls_error = BAD_IRQ; 47567c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 47577c478bd9Sstevel@tonic-gate } 47587c478bd9Sstevel@tonic-gate 47597c478bd9Sstevel@tonic-gate handler.socket = sockp->ls_socket; 47607c478bd9Sstevel@tonic-gate handler.irq = 0; /* default case */ 47617c478bd9Sstevel@tonic-gate handler.handler = (f_tt *)hdlp->ih_cb_func; 47627c478bd9Sstevel@tonic-gate handler.arg1 = hdlp->ih_cb_arg1; 47637c478bd9Sstevel@tonic-gate handler.arg2 = hdlp->ih_cb_arg2; 4764360e6f5eSmathue handler.handler_id = (uint32_t)(uintptr_t)rdip; 47657c478bd9Sstevel@tonic-gate 47667c478bd9Sstevel@tonic-gate /* 47677c478bd9Sstevel@tonic-gate * check if multifunction and do the right thing 47687c478bd9Sstevel@tonic-gate * we put an intercept in between the mfc handler and 47697c478bd9Sstevel@tonic-gate * us so we can catch and process. We might be able 47707c478bd9Sstevel@tonic-gate * to optimize this depending on the card features 47717c478bd9Sstevel@tonic-gate * (a future option). 47727c478bd9Sstevel@tonic-gate */ 47737c478bd9Sstevel@tonic-gate if (ppd->ppd_flags & PPD_CARD_MULTI) { 47747c478bd9Sstevel@tonic-gate inthandler_t *intr; 47757c478bd9Sstevel@tonic-gate /* 47767c478bd9Sstevel@tonic-gate * note that the first function is a special 47777c478bd9Sstevel@tonic-gate * case since it sets things up. We fall through 47787c478bd9Sstevel@tonic-gate * to the lower code and get the hardware set up. 47797c478bd9Sstevel@tonic-gate * subsequent times we just lock the list and insert 47807c478bd9Sstevel@tonic-gate * the handler and all is well. 47817c478bd9Sstevel@tonic-gate */ 47827c478bd9Sstevel@tonic-gate intr = kmem_zalloc(sizeof (inthandler_t), KM_NOSLEEP); 47837c478bd9Sstevel@tonic-gate if (intr == NULL) { 47847c478bd9Sstevel@tonic-gate sockp->ls_error = BAD_IRQ; 47857c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 47867c478bd9Sstevel@tonic-gate } 47877c478bd9Sstevel@tonic-gate intr->intr = hdlp->ih_cb_func; 4788360e6f5eSmathue intr->handler_id = (uint_t)(uintptr_t)rdip; 47897c478bd9Sstevel@tonic-gate intr->arg1 = hdlp->ih_cb_arg1; 47907c478bd9Sstevel@tonic-gate intr->arg2 = hdlp->ih_cb_arg2; 47917c478bd9Sstevel@tonic-gate intr->socket = socket; 47927c478bd9Sstevel@tonic-gate 47937c478bd9Sstevel@tonic-gate mutex_enter(&sockp->ls_ilock); 47947c478bd9Sstevel@tonic-gate if (sockp->ls_inthandlers == NULL) { 47957c478bd9Sstevel@tonic-gate intr->next = intr->prev = intr; 47967c478bd9Sstevel@tonic-gate sockp->ls_inthandlers = intr; 47977c478bd9Sstevel@tonic-gate sockp->ls_mfintr_dip = rdip; 47987c478bd9Sstevel@tonic-gate mutex_exit(&sockp->ls_ilock); 47997c478bd9Sstevel@tonic-gate 48007c478bd9Sstevel@tonic-gate /* 48017c478bd9Sstevel@tonic-gate * replace first function handler with 48027c478bd9Sstevel@tonic-gate * the mfc handler 48037c478bd9Sstevel@tonic-gate */ 48047c478bd9Sstevel@tonic-gate handler.handler = (f_tt *)pcmcia_mfc_intr; 48057c478bd9Sstevel@tonic-gate handler.arg1 = (caddr_t)sockp; 48067c478bd9Sstevel@tonic-gate handler.arg2 = NULL; 48077c478bd9Sstevel@tonic-gate } else { 48087c478bd9Sstevel@tonic-gate insque(intr, sockp->ls_inthandlers); 48097c478bd9Sstevel@tonic-gate mutex_exit(&sockp->ls_ilock); 48107c478bd9Sstevel@tonic-gate 48117c478bd9Sstevel@tonic-gate pispec->intrspec_vec = sockp->ls_intr_vec; 48127c478bd9Sstevel@tonic-gate pispec->intrspec_pri = sockp->ls_intr_pri; 48137c478bd9Sstevel@tonic-gate hdlp->ih_pri = sockp->ls_intr_pri; 48147c478bd9Sstevel@tonic-gate 48157c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 48167c478bd9Sstevel@tonic-gate } 48177c478bd9Sstevel@tonic-gate } 48187c478bd9Sstevel@tonic-gate 48197c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 48207c478bd9Sstevel@tonic-gate if (pcmcia_debug) { 48217c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia_add_intr_impl() let adapter do it\n"); 48227c478bd9Sstevel@tonic-gate } 48237c478bd9Sstevel@tonic-gate #endif 48247c478bd9Sstevel@tonic-gate pispec->intrspec_func = (uint32_t (*)())handler.handler; 48257c478bd9Sstevel@tonic-gate 48267c478bd9Sstevel@tonic-gate /* set default IPL then check for override */ 48277c478bd9Sstevel@tonic-gate 48287c478bd9Sstevel@tonic-gate pispec->intrspec_pri = sockp->ls_intr_pri; 48297c478bd9Sstevel@tonic-gate hdlp->ih_pri = pispec->intrspec_pri; 48307c478bd9Sstevel@tonic-gate 48317c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 48327c478bd9Sstevel@tonic-gate if (pcmcia_debug) { 48337c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia_add_intr_impl() socket=%d irq=%d" 48347c478bd9Sstevel@tonic-gate " handler_id=0X%x handler=%p arg1=%p arg2=%p\n", 48357c478bd9Sstevel@tonic-gate handler.socket, handler.irq, 48367c478bd9Sstevel@tonic-gate handler.handler_id, (void *)handler.handler, handler.arg1, 48377c478bd9Sstevel@tonic-gate handler.arg2); 48387c478bd9Sstevel@tonic-gate } 48397c478bd9Sstevel@tonic-gate #endif 48407c478bd9Sstevel@tonic-gate 48417c478bd9Sstevel@tonic-gate if ((ret = SET_IRQ(sockp->ls_if, adapt->pca_dip, &handler)) != 48427c478bd9Sstevel@tonic-gate SUCCESS) { 48437c478bd9Sstevel@tonic-gate sockp->ls_error = ret; 48447c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 48457c478bd9Sstevel@tonic-gate } 48467c478bd9Sstevel@tonic-gate 48477c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 48487c478bd9Sstevel@tonic-gate if (pcmcia_debug) { 48497c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia_add_intr_impl()" 48507c478bd9Sstevel@tonic-gate " iblk_cookie=%p idev_cookie=%p\n" 48517c478bd9Sstevel@tonic-gate " ls_flags=0X%x PCS_COOKIES_VALID=0X%x\n", 48527c478bd9Sstevel@tonic-gate (void *)handler.iblk_cookie, 48537c478bd9Sstevel@tonic-gate (void *)handler.idev_cookie, 48547c478bd9Sstevel@tonic-gate sockp->ls_flags, PCS_COOKIES_VALID); 48557c478bd9Sstevel@tonic-gate } 48567c478bd9Sstevel@tonic-gate #endif 48577c478bd9Sstevel@tonic-gate 48587c478bd9Sstevel@tonic-gate if (!(sockp->ls_flags & PCS_COOKIES_VALID)) { 4859360e6f5eSmathue hdlp->ih_pri = (uint_t)(uintptr_t)*handler.iblk_cookie; 48607c478bd9Sstevel@tonic-gate sockp->ls_iblk = *handler.iblk_cookie; 48617c478bd9Sstevel@tonic-gate sockp->ls_idev = *handler.idev_cookie; 48627c478bd9Sstevel@tonic-gate sockp->ls_flags |= PCS_COOKIES_VALID; 48637c478bd9Sstevel@tonic-gate } 48647c478bd9Sstevel@tonic-gate 48657c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 48667c478bd9Sstevel@tonic-gate } 48677c478bd9Sstevel@tonic-gate 48687c478bd9Sstevel@tonic-gate void 48697c478bd9Sstevel@tonic-gate pcmcia_remove_intr_impl(dev_info_t *dip, dev_info_t *rdip, 48707c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp) 48717c478bd9Sstevel@tonic-gate { 48727c478bd9Sstevel@tonic-gate 48737c478bd9Sstevel@tonic-gate struct pcmcia_parent_private *ppd; 48747c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t *sockp; 48757c478bd9Sstevel@tonic-gate clear_irq_handler_t handler; 48767c478bd9Sstevel@tonic-gate struct intrspec *pispec; 48777c478bd9Sstevel@tonic-gate int socket; 48787c478bd9Sstevel@tonic-gate 48797c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 48807c478bd9Sstevel@tonic-gate if (pcmcia_debug) { 48817c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia_remove_intr_impl() entered" 48827c478bd9Sstevel@tonic-gate " dip=%p rdip=%p hdlp=%p\n", 48837c478bd9Sstevel@tonic-gate (void *)dip, (void *)rdip, (void *)hdlp); 48847c478bd9Sstevel@tonic-gate } 48857c478bd9Sstevel@tonic-gate #endif 48867c478bd9Sstevel@tonic-gate 48877c478bd9Sstevel@tonic-gate ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(rdip); 48887c478bd9Sstevel@tonic-gate socket = ppd->ppd_socket; 48897c478bd9Sstevel@tonic-gate sockp = pcmcia_sockets[socket]; 48907c478bd9Sstevel@tonic-gate pispec = ppd->ppd_intrspec; 48917c478bd9Sstevel@tonic-gate 48927c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 48937c478bd9Sstevel@tonic-gate if (pcmcia_debug) { 48947c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia_remove_intr_impl()" 48957c478bd9Sstevel@tonic-gate " ls_inthandlers=%p ls_intrspec=%p\n", 48967c478bd9Sstevel@tonic-gate (void *)sockp->ls_inthandlers, 48977c478bd9Sstevel@tonic-gate (void *)&sockp->ls_intrspec); 48987c478bd9Sstevel@tonic-gate } 48997c478bd9Sstevel@tonic-gate #endif 49007c478bd9Sstevel@tonic-gate 49017c478bd9Sstevel@tonic-gate /* first handle the multifunction case since it is simple */ 49027c478bd9Sstevel@tonic-gate mutex_enter(&sockp->ls_ilock); 4903a195726fSgovinda if (sockp->ls_inthandlers != NULL) { 49047c478bd9Sstevel@tonic-gate /* we must be MFC */ 49057c478bd9Sstevel@tonic-gate inthandler_t *intr; 49067c478bd9Sstevel@tonic-gate int remhandler = 0; 49077c478bd9Sstevel@tonic-gate intr = sockp->ls_inthandlers; 49087c478bd9Sstevel@tonic-gate 49097c478bd9Sstevel@tonic-gate /* Check if there is only one handler left */ 49107c478bd9Sstevel@tonic-gate if ((intr->next == intr) && (intr->prev == intr)) { 4911360e6f5eSmathue if (intr->handler_id == (unsigned)(uintptr_t)rdip) { 49127c478bd9Sstevel@tonic-gate sockp->ls_inthandlers = NULL; 49137c478bd9Sstevel@tonic-gate remhandler++; 49147c478bd9Sstevel@tonic-gate kmem_free(intr, sizeof (inthandler_t)); 49157c478bd9Sstevel@tonic-gate } 49167c478bd9Sstevel@tonic-gate } else { 49177c478bd9Sstevel@tonic-gate inthandler_t *first; 49187c478bd9Sstevel@tonic-gate int done; 49197c478bd9Sstevel@tonic-gate 49207c478bd9Sstevel@tonic-gate for (done = 0, first = intr; !done; intr = intr->next) { 49217c478bd9Sstevel@tonic-gate if (intr->next == first) 49227c478bd9Sstevel@tonic-gate done++; 4923360e6f5eSmathue if (intr->handler_id == 4924360e6f5eSmathue (unsigned)(uintptr_t)rdip) { 49257c478bd9Sstevel@tonic-gate done++; 49267c478bd9Sstevel@tonic-gate 49277c478bd9Sstevel@tonic-gate /* 49287c478bd9Sstevel@tonic-gate * If we're about to remove the 49297c478bd9Sstevel@tonic-gate * handler at the head of 49307c478bd9Sstevel@tonic-gate * the list, make the next 49317c478bd9Sstevel@tonic-gate * handler in line the head. 49327c478bd9Sstevel@tonic-gate */ 49337c478bd9Sstevel@tonic-gate if (sockp->ls_inthandlers == intr) 49347c478bd9Sstevel@tonic-gate sockp->ls_inthandlers = 49357c478bd9Sstevel@tonic-gate intr->next; 49367c478bd9Sstevel@tonic-gate 49377c478bd9Sstevel@tonic-gate remque(intr); 49387c478bd9Sstevel@tonic-gate kmem_free(intr, sizeof (inthandler_t)); 49397c478bd9Sstevel@tonic-gate break; 49407c478bd9Sstevel@tonic-gate } /* handler_id */ 49417c478bd9Sstevel@tonic-gate } /* for */ 49427c478bd9Sstevel@tonic-gate } /* intr->next */ 49437c478bd9Sstevel@tonic-gate 49447c478bd9Sstevel@tonic-gate if (!remhandler) { 49457c478bd9Sstevel@tonic-gate mutex_exit(&sockp->ls_ilock); 49467c478bd9Sstevel@tonic-gate return; 49477c478bd9Sstevel@tonic-gate } 49487c478bd9Sstevel@tonic-gate 49497c478bd9Sstevel@tonic-gate /* need to get the dip that was used to add the handler */ 49507c478bd9Sstevel@tonic-gate rdip = sockp->ls_mfintr_dip; 49517c478bd9Sstevel@tonic-gate } 49527c478bd9Sstevel@tonic-gate 4953a195726fSgovinda mutex_exit(&sockp->ls_ilock); 49547c478bd9Sstevel@tonic-gate 49557c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 49567c478bd9Sstevel@tonic-gate if (pcmcia_debug) { 49577c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia_remove_intr_impl()" 49587c478bd9Sstevel@tonic-gate " pispec=%p rdip=%p\n", 49597c478bd9Sstevel@tonic-gate (void *)pispec, (void *)rdip); 49607c478bd9Sstevel@tonic-gate } 49617c478bd9Sstevel@tonic-gate #endif 49627c478bd9Sstevel@tonic-gate 49637c478bd9Sstevel@tonic-gate handler.socket = sockp->ls_socket; 4964360e6f5eSmathue handler.handler_id = (uint32_t)(uintptr_t)rdip; 49657c478bd9Sstevel@tonic-gate handler.handler = (f_tt *)pispec->intrspec_func; 49667c478bd9Sstevel@tonic-gate CLEAR_IRQ(sockp->ls_if, dip, &handler); 49677c478bd9Sstevel@tonic-gate } 49687c478bd9Sstevel@tonic-gate 49697c478bd9Sstevel@tonic-gate 49707c478bd9Sstevel@tonic-gate /* Consolidated interrupt processing interface */ 49717c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 49727c478bd9Sstevel@tonic-gate int 49737c478bd9Sstevel@tonic-gate pcmcia_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op, 49747c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, void *result) 49757c478bd9Sstevel@tonic-gate { 4976a195726fSgovinda int ret = DDI_SUCCESS; 49777c478bd9Sstevel@tonic-gate 49787c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 49797c478bd9Sstevel@tonic-gate if (pcmcia_debug) { 49807c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia_intr_ops() intr_op=%d\n", 49817c478bd9Sstevel@tonic-gate (int)intr_op); 49827c478bd9Sstevel@tonic-gate } 49837c478bd9Sstevel@tonic-gate #endif 49847c478bd9Sstevel@tonic-gate 49857c478bd9Sstevel@tonic-gate switch (intr_op) { 49867c478bd9Sstevel@tonic-gate case DDI_INTROP_GETCAP: 4987a195726fSgovinda *(int *)result = DDI_INTR_FLAG_LEVEL; 49887c478bd9Sstevel@tonic-gate break; 49897c478bd9Sstevel@tonic-gate case DDI_INTROP_SETCAP: 49907c478bd9Sstevel@tonic-gate ret = DDI_ENOTSUP; 49917c478bd9Sstevel@tonic-gate break; 49927c478bd9Sstevel@tonic-gate case DDI_INTROP_ALLOC: 49937c478bd9Sstevel@tonic-gate *(int *)result = hdlp->ih_scratch1; 49947c478bd9Sstevel@tonic-gate break; 49957c478bd9Sstevel@tonic-gate case DDI_INTROP_FREE: 49967c478bd9Sstevel@tonic-gate break; 49977c478bd9Sstevel@tonic-gate case DDI_INTROP_GETPRI: 49987c478bd9Sstevel@tonic-gate if (pcmcia_add_intr_impl(dip, rdip, hdlp) != DDI_SUCCESS) 49997c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 50007c478bd9Sstevel@tonic-gate *(int *)result = hdlp->ih_pri; 50017c478bd9Sstevel@tonic-gate pcmcia_remove_intr_impl(dip, rdip, hdlp); 50027c478bd9Sstevel@tonic-gate break; 50037c478bd9Sstevel@tonic-gate case DDI_INTROP_SETPRI: 50047c478bd9Sstevel@tonic-gate break; 50057c478bd9Sstevel@tonic-gate case DDI_INTROP_ADDISR: 50067c478bd9Sstevel@tonic-gate ret = pcmcia_add_intr_impl(dip, rdip, hdlp); 50077c478bd9Sstevel@tonic-gate break; 50087c478bd9Sstevel@tonic-gate case DDI_INTROP_REMISR: 50097c478bd9Sstevel@tonic-gate pcmcia_remove_intr_impl(dip, rdip, hdlp); 50107c478bd9Sstevel@tonic-gate break; 50117c478bd9Sstevel@tonic-gate case DDI_INTROP_ENABLE: 50127c478bd9Sstevel@tonic-gate case DDI_INTROP_DISABLE: 50137c478bd9Sstevel@tonic-gate break; 50147c478bd9Sstevel@tonic-gate case DDI_INTROP_NINTRS: 50157c478bd9Sstevel@tonic-gate case DDI_INTROP_NAVAIL: 5016a54f81fbSanish *(int *)result = i_ddi_get_intx_nintrs(rdip); 50177c478bd9Sstevel@tonic-gate break; 50187c478bd9Sstevel@tonic-gate case DDI_INTROP_SUPPORTED_TYPES: 50197c478bd9Sstevel@tonic-gate /* PCI nexus driver supports only fixed interrupts */ 5020a54f81fbSanish *(int *)result = i_ddi_get_intx_nintrs(rdip) ? 50217c478bd9Sstevel@tonic-gate DDI_INTR_TYPE_FIXED : 0; 50227c478bd9Sstevel@tonic-gate break; 50237c478bd9Sstevel@tonic-gate default: 50247c478bd9Sstevel@tonic-gate ret = DDI_ENOTSUP; 50257c478bd9Sstevel@tonic-gate break; 50267c478bd9Sstevel@tonic-gate } 50277c478bd9Sstevel@tonic-gate 50287c478bd9Sstevel@tonic-gate return (ret); 50297c478bd9Sstevel@tonic-gate } 50307c478bd9Sstevel@tonic-gate 50317c478bd9Sstevel@tonic-gate #elif defined(__x86) || defined(__amd64) 50327c478bd9Sstevel@tonic-gate 50337c478bd9Sstevel@tonic-gate static struct intrspec *pcmcia_intr_get_ispec(dev_info_t *, int, 50347c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t **); 50357c478bd9Sstevel@tonic-gate static struct intrspec *pcmcia_intr_add_isr(dev_info_t *, dev_info_t *, 50367c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *); 50377c478bd9Sstevel@tonic-gate static int pcmcia_intr_enable_isr(dev_info_t *, dev_info_t *, 50387c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *); 50397c478bd9Sstevel@tonic-gate static void pcmcia_intr_remove_isr(dev_info_t *, dev_info_t *, 50407c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *); 50417c478bd9Sstevel@tonic-gate static void pcmcia_intr_disable_isr(dev_info_t *, dev_info_t *, 50427c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *); 50437c478bd9Sstevel@tonic-gate 50447c478bd9Sstevel@tonic-gate /* 50457c478bd9Sstevel@tonic-gate * pcmcia_intr_get_ispec: 50467c478bd9Sstevel@tonic-gate * This is mostly copied from older 'pcmcia_get_intrspec' function 50477c478bd9Sstevel@tonic-gate */ 50487c478bd9Sstevel@tonic-gate static struct intrspec * 50497c478bd9Sstevel@tonic-gate pcmcia_intr_get_ispec(dev_info_t *rdip, int inum, 50507c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t **sockp) 50517c478bd9Sstevel@tonic-gate { 50527c478bd9Sstevel@tonic-gate int socket; 50537c478bd9Sstevel@tonic-gate struct intrspec *intrspec; 50547c478bd9Sstevel@tonic-gate struct pcmcia_parent_private *ppd; 50557c478bd9Sstevel@tonic-gate 50567c478bd9Sstevel@tonic-gate if ((int)inum > 0 || (ddi_getprop(DDI_DEV_T_ANY, rdip, 50577c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "interrupts", -1) < 0)) 50587c478bd9Sstevel@tonic-gate return (NULL); 50597c478bd9Sstevel@tonic-gate 50607c478bd9Sstevel@tonic-gate ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(rdip); 50617c478bd9Sstevel@tonic-gate if (ppd == NULL || ppd->ppd_intrspec == NULL) 50627c478bd9Sstevel@tonic-gate return (NULL); 50637c478bd9Sstevel@tonic-gate 50647c478bd9Sstevel@tonic-gate if ((socket = ppd->ppd_socket) < 0) 50657c478bd9Sstevel@tonic-gate return (NULL); 50667c478bd9Sstevel@tonic-gate 50677c478bd9Sstevel@tonic-gate if ((*sockp = pcmcia_sockets[socket]) == NULL) 50687c478bd9Sstevel@tonic-gate return (NULL); 50697c478bd9Sstevel@tonic-gate 50707c478bd9Sstevel@tonic-gate intrspec = ppd->ppd_intrspec; 50717c478bd9Sstevel@tonic-gate if (intrspec->intrspec_vec == 0 && (*sockp)->ls_intr_vec != 0) 50727c478bd9Sstevel@tonic-gate intrspec->intrspec_vec = (*sockp)->ls_intr_vec; 50737c478bd9Sstevel@tonic-gate 50747c478bd9Sstevel@tonic-gate return (intrspec); 50757c478bd9Sstevel@tonic-gate } 50767c478bd9Sstevel@tonic-gate 50777c478bd9Sstevel@tonic-gate static struct intrspec * 50787c478bd9Sstevel@tonic-gate pcmcia_intr_add_isr(dev_info_t *dip, dev_info_t *rdip, 50797c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp) 50807c478bd9Sstevel@tonic-gate { 50817c478bd9Sstevel@tonic-gate int socket; 50827c478bd9Sstevel@tonic-gate struct intrspec *ispecp; 50837c478bd9Sstevel@tonic-gate struct pcmcia_adapter *adapt; 50847c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t *sockp; 50857c478bd9Sstevel@tonic-gate struct pcmcia_parent_private *ppd; 50867c478bd9Sstevel@tonic-gate 50877c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 50887c478bd9Sstevel@tonic-gate if (pcmcia_debug) 50897c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia_intr_add_isr: " 50907c478bd9Sstevel@tonic-gate "dip=0x%p rdip=0x%p hdlp=0x%p\n", 50917c478bd9Sstevel@tonic-gate (void *)dip, (void *)rdip, (void *)hdlp); 50927c478bd9Sstevel@tonic-gate #endif /* PCMCIA_DEBUG */ 50937c478bd9Sstevel@tonic-gate 50947c478bd9Sstevel@tonic-gate ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(rdip); 50957c478bd9Sstevel@tonic-gate socket = ppd->ppd_socket; 50967c478bd9Sstevel@tonic-gate sockp = pcmcia_sockets[socket]; 50977c478bd9Sstevel@tonic-gate adapt = sockp->ls_adapter; 50987c478bd9Sstevel@tonic-gate 50997c478bd9Sstevel@tonic-gate ispecp = ppd->ppd_intrspec; 51007c478bd9Sstevel@tonic-gate if (ispecp == NULL) { 51017c478bd9Sstevel@tonic-gate sockp->ls_error = BAD_IRQ; 51027c478bd9Sstevel@tonic-gate return (ispecp); 51037c478bd9Sstevel@tonic-gate } 51047c478bd9Sstevel@tonic-gate 51057c478bd9Sstevel@tonic-gate /* 51067c478bd9Sstevel@tonic-gate * check if multifunction and do the right thing 51077c478bd9Sstevel@tonic-gate * we put an intercept in between the mfc handler and us so we can 51087c478bd9Sstevel@tonic-gate * catch and process. We might be able to optimize this depending 51097c478bd9Sstevel@tonic-gate * on the card features (a future option). 51107c478bd9Sstevel@tonic-gate */ 51117c478bd9Sstevel@tonic-gate if (ppd->ppd_flags & PPD_CARD_MULTI && 51127c478bd9Sstevel@tonic-gate hdlp->ih_cb_func != pcmcia_mfc_intr) { 51137c478bd9Sstevel@tonic-gate inthandler_t *intr; 51147c478bd9Sstevel@tonic-gate 51157c478bd9Sstevel@tonic-gate /* 51167c478bd9Sstevel@tonic-gate * note that the first function is a special case since it 51177c478bd9Sstevel@tonic-gate * sets things up. We fall through to the lower code and 51187c478bd9Sstevel@tonic-gate * get the hardware set up. Subsequent times we just lock 51197c478bd9Sstevel@tonic-gate * the list and insert the handler and all is well. 51207c478bd9Sstevel@tonic-gate */ 51217c478bd9Sstevel@tonic-gate intr = kmem_zalloc(sizeof (inthandler_t), KM_NOSLEEP); 51227c478bd9Sstevel@tonic-gate if (intr == NULL) { 51237c478bd9Sstevel@tonic-gate sockp->ls_error = BAD_IRQ; 51247c478bd9Sstevel@tonic-gate return (NULL); 51257c478bd9Sstevel@tonic-gate } 51267c478bd9Sstevel@tonic-gate 51277c478bd9Sstevel@tonic-gate intr->intr = (uint32_t (*)())hdlp->ih_cb_func; 51287c478bd9Sstevel@tonic-gate intr->handler_id = (uint32_t)(uintptr_t)rdip; 51297c478bd9Sstevel@tonic-gate intr->arg1 = hdlp->ih_cb_arg1; 51307c478bd9Sstevel@tonic-gate intr->arg2 = hdlp->ih_cb_arg2; 51317c478bd9Sstevel@tonic-gate intr->socket = socket; 51327c478bd9Sstevel@tonic-gate mutex_enter(&sockp->ls_ilock); 51337c478bd9Sstevel@tonic-gate if (sockp->ls_inthandlers == NULL) { 51347c478bd9Sstevel@tonic-gate intr->next = intr->prev = intr; 51357c478bd9Sstevel@tonic-gate sockp->ls_inthandlers = intr; 51367c478bd9Sstevel@tonic-gate sockp->ls_mfintr_dip = rdip; 51377c478bd9Sstevel@tonic-gate } else { 51387c478bd9Sstevel@tonic-gate insque(intr, sockp->ls_inthandlers); 51397c478bd9Sstevel@tonic-gate } 51407c478bd9Sstevel@tonic-gate mutex_exit(&sockp->ls_ilock); 51417c478bd9Sstevel@tonic-gate return (ispecp); 51427c478bd9Sstevel@tonic-gate } 51437c478bd9Sstevel@tonic-gate 51447c478bd9Sstevel@tonic-gate /* 51457c478bd9Sstevel@tonic-gate * Do we need to allocate an IRQ at this point or not? 51467c478bd9Sstevel@tonic-gate */ 51477c478bd9Sstevel@tonic-gate if (adapt->pca_flags & PCA_RES_NEED_IRQ) { 51487c478bd9Sstevel@tonic-gate int i, irq; 51497c478bd9Sstevel@tonic-gate 51507c478bd9Sstevel@tonic-gate /* 51517c478bd9Sstevel@tonic-gate * this adapter needs IRQ allocations 51527c478bd9Sstevel@tonic-gate * this is only necessary if it is the first function on the 51537c478bd9Sstevel@tonic-gate * card being setup. The socket will keep the allocation info 51547c478bd9Sstevel@tonic-gate */ 51557c478bd9Sstevel@tonic-gate /* all functions use same intrspec except mfc handler */ 51567c478bd9Sstevel@tonic-gate if (hdlp->ih_cb_func == pcmcia_mfc_intr) { 51577c478bd9Sstevel@tonic-gate /* 51587c478bd9Sstevel@tonic-gate * We treat this special in order to allow things to 51597c478bd9Sstevel@tonic-gate * work properly for MFC cards. The intrspec for the 51607c478bd9Sstevel@tonic-gate * mfc dispatcher is intercepted and taken from the 51617c478bd9Sstevel@tonic-gate * logical socket in order to not be trying to 51627c478bd9Sstevel@tonic-gate * multiplex the meaning when ENABLE is called. 51637c478bd9Sstevel@tonic-gate */ 51647c478bd9Sstevel@tonic-gate ispecp = &sockp->ls_intrspec; 51657a364d25Sschwartz ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispecp; 51667c478bd9Sstevel@tonic-gate } 51677c478bd9Sstevel@tonic-gate 51687c478bd9Sstevel@tonic-gate if (adapt->pca_flags & PCA_IRQ_ISA) { 51697c478bd9Sstevel@tonic-gate for (irq = -1, i = 1; irq == -1 && i < 16; i++) { 51707c478bd9Sstevel@tonic-gate /* find available and usable IRQ level */ 51717c478bd9Sstevel@tonic-gate if (adapt->pca_avail_intr & (1 << i)) 51727c478bd9Sstevel@tonic-gate irq = pcmcia_get_intr(dip, i); 51737c478bd9Sstevel@tonic-gate } 51747c478bd9Sstevel@tonic-gate } 51757c478bd9Sstevel@tonic-gate if (irq < 0) { 51767c478bd9Sstevel@tonic-gate sockp->ls_error = NO_RESOURCE; 51777c478bd9Sstevel@tonic-gate return (NULL); 51787c478bd9Sstevel@tonic-gate } 51797c478bd9Sstevel@tonic-gate hdlp->ih_vector = sockp->ls_intr_vec = irq; 51807c478bd9Sstevel@tonic-gate 51817c478bd9Sstevel@tonic-gate 51827c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 51837c478bd9Sstevel@tonic-gate if (pcmcia_debug) 51847c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "allocated irq=%x\n", irq); 51857c478bd9Sstevel@tonic-gate #endif /* PCMCIA_DEBUG */ 51867c478bd9Sstevel@tonic-gate 51877c478bd9Sstevel@tonic-gate ispecp->intrspec_vec = sockp->ls_intr_vec; 51887c478bd9Sstevel@tonic-gate ispecp->intrspec_pri = sockp->ls_intr_pri; 51897c478bd9Sstevel@tonic-gate return (ispecp); 51907c478bd9Sstevel@tonic-gate } 51917c478bd9Sstevel@tonic-gate 51927c478bd9Sstevel@tonic-gate if (ispecp->intrspec_func != NULL) 51937c478bd9Sstevel@tonic-gate ispecp->intrspec_func = hdlp->ih_cb_func; 51947c478bd9Sstevel@tonic-gate 51957c478bd9Sstevel@tonic-gate /* set default IPL then check for override */ 51967c478bd9Sstevel@tonic-gate ispecp->intrspec_pri = sockp->ls_intr_pri; 51977c478bd9Sstevel@tonic-gate return (ispecp); 51987c478bd9Sstevel@tonic-gate } 51997c478bd9Sstevel@tonic-gate 52007c478bd9Sstevel@tonic-gate 52017c478bd9Sstevel@tonic-gate static int 52027c478bd9Sstevel@tonic-gate pcmcia_intr_enable_isr(dev_info_t *dip, dev_info_t *rdip, 52037c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp) 52047c478bd9Sstevel@tonic-gate { 52057c478bd9Sstevel@tonic-gate int socket, ret; 52067c478bd9Sstevel@tonic-gate int irq = 0; /* default case */ 52077c478bd9Sstevel@tonic-gate dev_info_t *parent = ddi_root_node(); 52087c478bd9Sstevel@tonic-gate struct intrspec *ispecp; 52097c478bd9Sstevel@tonic-gate set_irq_handler_t handler; 52107c478bd9Sstevel@tonic-gate struct pcmcia_adapter *adapt; 52117c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t *sockp; 52127c478bd9Sstevel@tonic-gate struct pcmcia_parent_private *ppd; 52137c478bd9Sstevel@tonic-gate 52147c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 52157c478bd9Sstevel@tonic-gate if (pcmcia_debug) 52167c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia_intr_enable_isr: " 52177c478bd9Sstevel@tonic-gate "dip=0x%p rdip=0x%p hdlp=0x%p\n", 52187c478bd9Sstevel@tonic-gate (void *)dip, (void *)rdip, (void *)hdlp); 52197c478bd9Sstevel@tonic-gate #endif /* PCMCIA_DEBUG */ 52207c478bd9Sstevel@tonic-gate 52217c478bd9Sstevel@tonic-gate ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(rdip); 52227c478bd9Sstevel@tonic-gate socket = ppd->ppd_socket; 52237c478bd9Sstevel@tonic-gate sockp = pcmcia_sockets[socket]; 52247c478bd9Sstevel@tonic-gate adapt = sockp->ls_adapter; 52257c478bd9Sstevel@tonic-gate 52267c478bd9Sstevel@tonic-gate ispecp = ppd->ppd_intrspec; 52277c478bd9Sstevel@tonic-gate ASSERT(ispecp); 52287c478bd9Sstevel@tonic-gate 52297c478bd9Sstevel@tonic-gate mutex_enter(&sockp->ls_ilock); 52307c478bd9Sstevel@tonic-gate if ((sockp->ls_inthandlers != NULL) && 52317a364d25Sschwartz ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp != 52327a364d25Sschwartz &sockp->ls_intrspec) { 52337c478bd9Sstevel@tonic-gate inthandler_t *intr = sockp->ls_inthandlers; 52347c478bd9Sstevel@tonic-gate 52357c478bd9Sstevel@tonic-gate ASSERT(ppd->ppd_flags & PPD_CARD_MULTI); 52367c478bd9Sstevel@tonic-gate 52377c478bd9Sstevel@tonic-gate /* Only one handler. So, call ddi_add_intr on it */ 52387c478bd9Sstevel@tonic-gate if ((intr->next == intr) && (intr->prev == intr)) { 52397c478bd9Sstevel@tonic-gate hdlp->ih_cb_func = pcmcia_mfc_intr; 52407c478bd9Sstevel@tonic-gate hdlp->ih_cb_arg1 = (caddr_t)sockp; 52417c478bd9Sstevel@tonic-gate hdlp->ih_cb_arg2 = NULL; 52427c478bd9Sstevel@tonic-gate 52437c478bd9Sstevel@tonic-gate ret = (*(DEVI(parent)->devi_ops->devo_bus_ops-> 52447c478bd9Sstevel@tonic-gate bus_intr_op))(parent, rdip, DDI_INTROP_ENABLE, 52457c478bd9Sstevel@tonic-gate hdlp, NULL); 52467c478bd9Sstevel@tonic-gate 52477c478bd9Sstevel@tonic-gate if (ret == DDI_FAILURE) { 52487c478bd9Sstevel@tonic-gate sockp->ls_inthandlers = NULL; 52497c478bd9Sstevel@tonic-gate kmem_free(intr, sizeof (inthandler_t)); 52507c478bd9Sstevel@tonic-gate sockp->ls_error = BAD_IRQ; 52517c478bd9Sstevel@tonic-gate mutex_exit(&sockp->ls_ilock); 52527c478bd9Sstevel@tonic-gate return (ret); 52537c478bd9Sstevel@tonic-gate } 52547c478bd9Sstevel@tonic-gate } 52557c478bd9Sstevel@tonic-gate mutex_exit(&sockp->ls_ilock); 52567c478bd9Sstevel@tonic-gate hdlp->ih_vector = ispecp->intrspec_vec = sockp->ls_intr_vec; 52577c478bd9Sstevel@tonic-gate hdlp->ih_pri = sockp->ls_intr_pri; 5258abdbd06dSagiri sockp->ls_iblk = (ddi_iblock_cookie_t)(uintptr_t) 52597c478bd9Sstevel@tonic-gate sockp->ls_intr_pri; 52607c478bd9Sstevel@tonic-gate sockp->ls_idev.idev_vector = (ushort_t)hdlp->ih_vector; 52617c478bd9Sstevel@tonic-gate sockp->ls_idev.idev_priority = (ushort_t)sockp->ls_intr_pri; 52627c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 52637c478bd9Sstevel@tonic-gate } 52647c478bd9Sstevel@tonic-gate mutex_exit(&sockp->ls_ilock); 52657c478bd9Sstevel@tonic-gate 52667c478bd9Sstevel@tonic-gate if (adapt->pca_flags & PCA_RES_NEED_IRQ) { 52677c478bd9Sstevel@tonic-gate if (hdlp->ih_cb_func == pcmcia_mfc_intr) 52687c478bd9Sstevel@tonic-gate ispecp = (struct intrspec *)&sockp->ls_intrspec; 52697c478bd9Sstevel@tonic-gate 52707c478bd9Sstevel@tonic-gate /* XXX: remove it later as this is done in _add_isr as well */ 52717c478bd9Sstevel@tonic-gate ispecp->intrspec_vec = sockp->ls_intr_vec; 52727c478bd9Sstevel@tonic-gate ispecp->intrspec_pri = sockp->ls_intr_pri; 52737c478bd9Sstevel@tonic-gate 52747c478bd9Sstevel@tonic-gate /* Enable interrupts */ 52757c478bd9Sstevel@tonic-gate ret = (*(DEVI(parent)->devi_ops->devo_bus_ops->bus_intr_op))( 52767c478bd9Sstevel@tonic-gate parent, rdip, DDI_INTROP_ENABLE, hdlp, NULL); 52777c478bd9Sstevel@tonic-gate 5278abdbd06dSagiri sockp->ls_iblk = (ddi_iblock_cookie_t)(uintptr_t) 52797c478bd9Sstevel@tonic-gate sockp->ls_intr_pri; 52807c478bd9Sstevel@tonic-gate sockp->ls_idev.idev_vector = (ushort_t)sockp->ls_intr_vec; 52817c478bd9Sstevel@tonic-gate sockp->ls_idev.idev_priority = (ushort_t)sockp->ls_intr_pri; 52827c478bd9Sstevel@tonic-gate 52837c478bd9Sstevel@tonic-gate if (ret != DDI_SUCCESS) 52847c478bd9Sstevel@tonic-gate sockp->ls_error = BAD_IRQ; 52857c478bd9Sstevel@tonic-gate return (ret); 52867c478bd9Sstevel@tonic-gate } 52877c478bd9Sstevel@tonic-gate 52887c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 52897c478bd9Sstevel@tonic-gate if (pcmcia_debug) 52907c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia_intr_enable_isr; let adapter do it\n"); 52917c478bd9Sstevel@tonic-gate #endif /* PCMCIA_DEBUG */ 52927c478bd9Sstevel@tonic-gate 52937c478bd9Sstevel@tonic-gate handler.socket = sockp->ls_socket; 52947c478bd9Sstevel@tonic-gate handler.irq = irq; 52957c478bd9Sstevel@tonic-gate handler.handler = (f_tt *)hdlp->ih_cb_func; 52967c478bd9Sstevel@tonic-gate handler.arg1 = hdlp->ih_cb_arg1; 52977c478bd9Sstevel@tonic-gate handler.arg2 = hdlp->ih_cb_arg2; 52987c478bd9Sstevel@tonic-gate handler.handler_id = (uint32_t)(uintptr_t)rdip; 52997c478bd9Sstevel@tonic-gate if (ispecp->intrspec_func != NULL) 53007c478bd9Sstevel@tonic-gate ispecp->intrspec_func = hdlp->ih_cb_func; 53017c478bd9Sstevel@tonic-gate 53027c478bd9Sstevel@tonic-gate /* set default IPL then check for override */ 53037c478bd9Sstevel@tonic-gate ispecp->intrspec_pri = sockp->ls_intr_pri; 53047c478bd9Sstevel@tonic-gate 53057c478bd9Sstevel@tonic-gate if ((ret = SET_IRQ(sockp->ls_if, adapt->pca_dip, &handler)) != 53067c478bd9Sstevel@tonic-gate SUCCESS) { 53077c478bd9Sstevel@tonic-gate sockp->ls_error = ret; 53087c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 53097c478bd9Sstevel@tonic-gate } 53107c478bd9Sstevel@tonic-gate ispecp->intrspec_func = hdlp->ih_cb_func; 53117c478bd9Sstevel@tonic-gate if (!(sockp->ls_flags & PCS_COOKIES_VALID)) { 53127c478bd9Sstevel@tonic-gate sockp->ls_iblk = *handler.iblk_cookie; 53137c478bd9Sstevel@tonic-gate sockp->ls_idev = *handler.idev_cookie; 53147c478bd9Sstevel@tonic-gate sockp->ls_flags |= PCS_COOKIES_VALID; 53157c478bd9Sstevel@tonic-gate } 53167c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 53177c478bd9Sstevel@tonic-gate } 53187c478bd9Sstevel@tonic-gate 53197c478bd9Sstevel@tonic-gate /* ARGSUSED */ 53207c478bd9Sstevel@tonic-gate static void 53217c478bd9Sstevel@tonic-gate pcmcia_intr_remove_isr(dev_info_t *dip, dev_info_t *rdip, 53227c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp) 53237c478bd9Sstevel@tonic-gate { 53247c478bd9Sstevel@tonic-gate int done, remhandler = 0; 53257c478bd9Sstevel@tonic-gate inthandler_t *intr, *first; 53267c478bd9Sstevel@tonic-gate struct intrspec *ispecp; 53277c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t *sockp; 53287c478bd9Sstevel@tonic-gate 53297c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 53307c478bd9Sstevel@tonic-gate if (pcmcia_debug) 53317c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia_intr_remove_isr: " 53327c478bd9Sstevel@tonic-gate "dip=0x%p rdip=0x%p hdlp=0x%p\n", 53337c478bd9Sstevel@tonic-gate (void *)dip, (void *)rdip, (void *)hdlp); 53347c478bd9Sstevel@tonic-gate #endif /* PCMCIA_DEBUG */ 53357c478bd9Sstevel@tonic-gate 53367c478bd9Sstevel@tonic-gate ispecp = pcmcia_intr_get_ispec(rdip, hdlp->ih_inum, &sockp); 53377c478bd9Sstevel@tonic-gate ASSERT(ispecp); 53387c478bd9Sstevel@tonic-gate 53397c478bd9Sstevel@tonic-gate /* first handle the multifunction case since it is simple */ 53407c478bd9Sstevel@tonic-gate mutex_enter(&sockp->ls_ilock); 53417c478bd9Sstevel@tonic-gate if (sockp->ls_inthandlers != NULL && 53427a364d25Sschwartz ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp != 53437a364d25Sschwartz &sockp->ls_intrspec) { 53447c478bd9Sstevel@tonic-gate 53457c478bd9Sstevel@tonic-gate intr = sockp->ls_inthandlers; 53467c478bd9Sstevel@tonic-gate 53477c478bd9Sstevel@tonic-gate /* Check if there is only one handler left */ 53487c478bd9Sstevel@tonic-gate if ((intr->next == intr) && (intr->prev == intr)) { 53497c478bd9Sstevel@tonic-gate if (intr->handler_id == (uint32_t)(uintptr_t)rdip) { 53507c478bd9Sstevel@tonic-gate sockp->ls_inthandlers = NULL; 53517c478bd9Sstevel@tonic-gate remhandler++; 53527c478bd9Sstevel@tonic-gate kmem_free(intr, sizeof (inthandler_t)); 53537c478bd9Sstevel@tonic-gate } 53547c478bd9Sstevel@tonic-gate 53557c478bd9Sstevel@tonic-gate } else { 53567c478bd9Sstevel@tonic-gate for (done = 0, first = intr; !done; intr = intr->next) { 53577c478bd9Sstevel@tonic-gate if (intr->next == first) 53587c478bd9Sstevel@tonic-gate done++; 53597c478bd9Sstevel@tonic-gate if (intr->handler_id == 53607c478bd9Sstevel@tonic-gate (uint32_t)(uintptr_t)rdip) { 53617c478bd9Sstevel@tonic-gate done++; 53627c478bd9Sstevel@tonic-gate 53637c478bd9Sstevel@tonic-gate /* 53647c478bd9Sstevel@tonic-gate * If we're about to remove the handler 53657c478bd9Sstevel@tonic-gate * at the head of the list, make the 53667c478bd9Sstevel@tonic-gate * next handler in line the head. 53677c478bd9Sstevel@tonic-gate */ 53687c478bd9Sstevel@tonic-gate if (sockp->ls_inthandlers == intr) 53695c066ec2SJerry Gilliam sockp->ls_inthandlers = 53705c066ec2SJerry Gilliam intr->next; 53717c478bd9Sstevel@tonic-gate 53727c478bd9Sstevel@tonic-gate remque(intr); 53737c478bd9Sstevel@tonic-gate kmem_free(intr, sizeof (inthandler_t)); 53747c478bd9Sstevel@tonic-gate break; 53757c478bd9Sstevel@tonic-gate } /* handler_id */ 53767c478bd9Sstevel@tonic-gate } /* end of for */ 53777c478bd9Sstevel@tonic-gate } /* end of if intr->next */ 53787c478bd9Sstevel@tonic-gate 53797c478bd9Sstevel@tonic-gate if (!remhandler) { 53807c478bd9Sstevel@tonic-gate mutex_exit(&sockp->ls_ilock); 53817c478bd9Sstevel@tonic-gate return; 53827c478bd9Sstevel@tonic-gate } 53837c478bd9Sstevel@tonic-gate } 53847c478bd9Sstevel@tonic-gate mutex_exit(&sockp->ls_ilock); 53857c478bd9Sstevel@tonic-gate 53867c478bd9Sstevel@tonic-gate if (sockp->ls_adapter->pca_flags & PCA_RES_NEED_IRQ) { 53877c478bd9Sstevel@tonic-gate sockp->ls_intr_vec = 0; 53887c478bd9Sstevel@tonic-gate ispecp->intrspec_vec = 0; 53897c478bd9Sstevel@tonic-gate } 53907c478bd9Sstevel@tonic-gate } 53917c478bd9Sstevel@tonic-gate 53927c478bd9Sstevel@tonic-gate 53937c478bd9Sstevel@tonic-gate static void 53947c478bd9Sstevel@tonic-gate pcmcia_intr_disable_isr(dev_info_t *dip, dev_info_t *rdip, 53957c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp) 53967c478bd9Sstevel@tonic-gate { 53977c478bd9Sstevel@tonic-gate int socket, ret; 53987c478bd9Sstevel@tonic-gate dev_info_t *parent; 53997c478bd9Sstevel@tonic-gate struct intrspec *ispecp; 54007c478bd9Sstevel@tonic-gate clear_irq_handler_t handler; 54017c478bd9Sstevel@tonic-gate struct pcmcia_adapter *adapt; 54027c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t *sockp; 54037c478bd9Sstevel@tonic-gate struct pcmcia_parent_private *ppd; 54047a364d25Sschwartz ihdl_plat_t *ihdl_plat_datap = 54055c066ec2SJerry Gilliam (ihdl_plat_t *)hdlp->ih_private; 54067c478bd9Sstevel@tonic-gate 54077c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 54087c478bd9Sstevel@tonic-gate if (pcmcia_debug) 54097c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia_intr_disable_isr: " 54107c478bd9Sstevel@tonic-gate "dip=0x%p rdip=0x%p hdlp=0x%p\n", 54117c478bd9Sstevel@tonic-gate (void *)dip, (void *)rdip, (void *)hdlp); 54127c478bd9Sstevel@tonic-gate #endif /* PCMCIA_DEBUG */ 54137c478bd9Sstevel@tonic-gate 54147c478bd9Sstevel@tonic-gate ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(rdip); 54157c478bd9Sstevel@tonic-gate socket = ppd->ppd_socket; 54167c478bd9Sstevel@tonic-gate sockp = pcmcia_sockets[socket]; 54177c478bd9Sstevel@tonic-gate adapt = sockp->ls_adapter; 54187c478bd9Sstevel@tonic-gate ispecp = ppd->ppd_intrspec; 54197c478bd9Sstevel@tonic-gate ASSERT(ispecp); 54207c478bd9Sstevel@tonic-gate 54217c478bd9Sstevel@tonic-gate mutex_enter(&sockp->ls_ilock); 54227c478bd9Sstevel@tonic-gate if (sockp->ls_inthandlers != NULL && 54237a364d25Sschwartz ihdl_plat_datap->ip_ispecp != &sockp->ls_intrspec) { 54247c478bd9Sstevel@tonic-gate inthandler_t *intr = sockp->ls_inthandlers; 54257c478bd9Sstevel@tonic-gate 54267c478bd9Sstevel@tonic-gate /* Check if there is only one handler left */ 54277c478bd9Sstevel@tonic-gate if ((intr->next == intr) && (intr->prev == intr)) { 54283f068ebdSToomas Soome if (intr->handler_id != (uint32_t)(uintptr_t)rdip) { 54297c478bd9Sstevel@tonic-gate /* 54307c478bd9Sstevel@tonic-gate * need to get the dip that was 54317c478bd9Sstevel@tonic-gate * used to add the handler 54327c478bd9Sstevel@tonic-gate */ 54337c478bd9Sstevel@tonic-gate rdip = sockp->ls_mfintr_dip; 54343f068ebdSToomas Soome } 54353f068ebdSToomas Soome ispecp = (struct intrspec *)&sockp->ls_intrspec; 54367c478bd9Sstevel@tonic-gate } else { 54377c478bd9Sstevel@tonic-gate /* Don't call cleanup if list still has members */ 54387c478bd9Sstevel@tonic-gate mutex_exit(&sockp->ls_ilock); 54397c478bd9Sstevel@tonic-gate return; 54407c478bd9Sstevel@tonic-gate } 54417c478bd9Sstevel@tonic-gate } 54427c478bd9Sstevel@tonic-gate mutex_exit(&sockp->ls_ilock); 54437c478bd9Sstevel@tonic-gate 54447a364d25Sschwartz if (ihdl_plat_datap->ip_ispecp == 54457c478bd9Sstevel@tonic-gate (struct intrspec *)&sockp->ls_intrspec) 54467a364d25Sschwartz ispecp = ihdl_plat_datap->ip_ispecp; 54477c478bd9Sstevel@tonic-gate 54487c478bd9Sstevel@tonic-gate if (adapt->pca_flags & PCA_RES_NEED_IRQ) { 54497c478bd9Sstevel@tonic-gate ret = ispecp->intrspec_vec; 54507c478bd9Sstevel@tonic-gate parent = ddi_root_node(); 54517c478bd9Sstevel@tonic-gate ret = (*(DEVI(parent)->devi_ops->devo_bus_ops->bus_intr_op))( 54527c478bd9Sstevel@tonic-gate parent, rdip, DDI_INTROP_DISABLE, hdlp, NULL); 54537c478bd9Sstevel@tonic-gate (void) pcmcia_return_intr(dip, hdlp->ih_vector); 54547c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 54557c478bd9Sstevel@tonic-gate if (pcmcia_debug) 54567c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia_intr_disable_isr: " 54577c478bd9Sstevel@tonic-gate "INTROP_DISABLE returned %x\n", ret); 54587c478bd9Sstevel@tonic-gate #endif /* PCMCIA_DEBUG */ 54597c478bd9Sstevel@tonic-gate } else { 54607c478bd9Sstevel@tonic-gate handler.socket = sockp->ls_socket; 54617c478bd9Sstevel@tonic-gate handler.handler_id = (uint32_t)(uintptr_t)rdip; 54627c478bd9Sstevel@tonic-gate handler.handler = (f_tt *)ispecp->intrspec_func; 54637c478bd9Sstevel@tonic-gate ret = CLEAR_IRQ(sockp->ls_if, dip, &handler); 54647c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 54657c478bd9Sstevel@tonic-gate if (pcmcia_debug) 54667c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia_intr_disable_isr: " 54677c478bd9Sstevel@tonic-gate "CLEAR_IRQ returned %x\n", ret); 54687c478bd9Sstevel@tonic-gate #endif /* PCMCIA_DEBUG */ 54697c478bd9Sstevel@tonic-gate } 54707c478bd9Sstevel@tonic-gate } 54717c478bd9Sstevel@tonic-gate 54727c478bd9Sstevel@tonic-gate /* Consolidated interrupt processing interface */ 54737c478bd9Sstevel@tonic-gate int 54747c478bd9Sstevel@tonic-gate pcmcia_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op, 54757c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, void *result) 54767c478bd9Sstevel@tonic-gate { 54777c478bd9Sstevel@tonic-gate struct intrspec *ispecp; 54787c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t *sockp; 54797c478bd9Sstevel@tonic-gate 54807c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 54817c478bd9Sstevel@tonic-gate if (pcmcia_debug) 54827c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia_intr_ops: " 54837c478bd9Sstevel@tonic-gate "dip=0x%p rdip=0x%p op=0x%x hdlp=0x%p\n", 54847c478bd9Sstevel@tonic-gate (void *)dip, (void *)rdip, intr_op, (void *)hdlp); 54857c478bd9Sstevel@tonic-gate #endif /* PCMCIA_DEBUG */ 54867c478bd9Sstevel@tonic-gate 54877c478bd9Sstevel@tonic-gate switch (intr_op) { 54887c478bd9Sstevel@tonic-gate case DDI_INTROP_SUPPORTED_TYPES: 54897c478bd9Sstevel@tonic-gate if (ddi_get_parent_data(rdip) == NULL) { 54907c478bd9Sstevel@tonic-gate *(int *)result = 0; 54917c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 54927c478bd9Sstevel@tonic-gate } 54937c478bd9Sstevel@tonic-gate *(int *)result = DDI_INTR_TYPE_FIXED; 54947c478bd9Sstevel@tonic-gate break; 54957c478bd9Sstevel@tonic-gate case DDI_INTROP_GETCAP: 5496a195726fSgovinda *(int *)result = DDI_INTR_FLAG_LEVEL; 54977c478bd9Sstevel@tonic-gate break; 54987c478bd9Sstevel@tonic-gate case DDI_INTROP_NINTRS: 54997c478bd9Sstevel@tonic-gate case DDI_INTROP_NAVAIL: 5500a54f81fbSanish if (i_ddi_get_intx_nintrs(rdip) == 0) { 55017c478bd9Sstevel@tonic-gate *(int *)result = 0; 55027c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 55037c478bd9Sstevel@tonic-gate } 55047c478bd9Sstevel@tonic-gate *(int *)result = 1; /* for PCMCIA there is only one intr */ 55057c478bd9Sstevel@tonic-gate break; 55067c478bd9Sstevel@tonic-gate case DDI_INTROP_ALLOC: 55077c478bd9Sstevel@tonic-gate if ((ispecp = pcmcia_intr_get_ispec(rdip, hdlp->ih_inum, 55087c478bd9Sstevel@tonic-gate &sockp)) == NULL) 55097c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 55107c478bd9Sstevel@tonic-gate *(int *)result = hdlp->ih_scratch1; 55117c478bd9Sstevel@tonic-gate break; 55127c478bd9Sstevel@tonic-gate case DDI_INTROP_FREE: 55137c478bd9Sstevel@tonic-gate break; 55147c478bd9Sstevel@tonic-gate case DDI_INTROP_GETPRI: 55157c478bd9Sstevel@tonic-gate ispecp = pcmcia_intr_get_ispec(rdip, hdlp->ih_inum, &sockp); 55167c478bd9Sstevel@tonic-gate if (ispecp == NULL) { 55177c478bd9Sstevel@tonic-gate *(int *)result = 0; 55187c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 55197c478bd9Sstevel@tonic-gate } 55207c478bd9Sstevel@tonic-gate 55217c478bd9Sstevel@tonic-gate *(int *)result = ispecp->intrspec_pri = sockp->ls_intr_pri; 55227c478bd9Sstevel@tonic-gate break; 55237c478bd9Sstevel@tonic-gate case DDI_INTROP_SETPRI: 55247c478bd9Sstevel@tonic-gate if (*(int *)result > LOCK_LEVEL) 55257c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 55267c478bd9Sstevel@tonic-gate ispecp = pcmcia_intr_get_ispec(rdip, hdlp->ih_inum, &sockp); 55277c478bd9Sstevel@tonic-gate ASSERT(ispecp); 55287c478bd9Sstevel@tonic-gate ispecp->intrspec_pri = sockp->ls_intr_pri = *(int *)result; 55297c478bd9Sstevel@tonic-gate break; 55307c478bd9Sstevel@tonic-gate case DDI_INTROP_ADDISR: 55317c478bd9Sstevel@tonic-gate if ((ispecp = pcmcia_intr_add_isr(dip, rdip, hdlp)) == NULL) 55327c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 55337a364d25Sschwartz ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispecp; 55347c478bd9Sstevel@tonic-gate break; 55357c478bd9Sstevel@tonic-gate case DDI_INTROP_REMISR: 55367c478bd9Sstevel@tonic-gate pcmcia_intr_remove_isr(dip, rdip, hdlp); 55377c478bd9Sstevel@tonic-gate break; 55387c478bd9Sstevel@tonic-gate case DDI_INTROP_ENABLE: 55397c478bd9Sstevel@tonic-gate if (pcmcia_intr_enable_isr(dip, rdip, hdlp) != DDI_SUCCESS) 55407c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 55417c478bd9Sstevel@tonic-gate break; 55427c478bd9Sstevel@tonic-gate case DDI_INTROP_DISABLE: 55437c478bd9Sstevel@tonic-gate pcmcia_intr_disable_isr(dip, rdip, hdlp); 55447c478bd9Sstevel@tonic-gate break; 55457c478bd9Sstevel@tonic-gate default: 55467c478bd9Sstevel@tonic-gate return (DDI_ENOTSUP); 55477c478bd9Sstevel@tonic-gate } 55487c478bd9Sstevel@tonic-gate 55497c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 55507c478bd9Sstevel@tonic-gate } 55517c478bd9Sstevel@tonic-gate #endif 5552