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 /* 22*582c04d6Srui 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 3657c478bd9Sstevel@tonic-gate * attempt to load Card Services (which _depends_on pcmcia) 3667c478bd9Sstevel@tonic-gate * initialize logical sockets 3677c478bd9Sstevel@tonic-gate * report the nexus exists 3687c478bd9Sstevel@tonic-gate */ 3697c478bd9Sstevel@tonic-gate 3707c478bd9Sstevel@tonic-gate int 3717c478bd9Sstevel@tonic-gate pcmcia_attach(dev_info_t *dip, anp_t *adapter) 3727c478bd9Sstevel@tonic-gate { 3737c478bd9Sstevel@tonic-gate int count, done, i; 3747c478bd9Sstevel@tonic-gate 3757c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 3767c478bd9Sstevel@tonic-gate if (pcmcia_debug) { 3777c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia_attach: dip=0x%p adapter=0x%p\n", 3787c478bd9Sstevel@tonic-gate (void *)dip, (void *)adapter); 3797c478bd9Sstevel@tonic-gate } 3807c478bd9Sstevel@tonic-gate #endif 3817c478bd9Sstevel@tonic-gate 3827c478bd9Sstevel@tonic-gate pcmcia_dip = dip; 3837c478bd9Sstevel@tonic-gate 3847c478bd9Sstevel@tonic-gate mutex_enter(&pcmcia_enum_lock); 3857c478bd9Sstevel@tonic-gate mutex_enter(&pcmcia_global_lock); 3867c478bd9Sstevel@tonic-gate if (pcmcia_num_adapters == 0) { 3877c478bd9Sstevel@tonic-gate pcmcia_cis_parser = (f_tt *)CISParser; 3887c478bd9Sstevel@tonic-gate cis_parser = (void *(*)(int, ...)) CISParser; 3897c478bd9Sstevel@tonic-gate pcmcia_cs_event = (f_tt *)cs_event; 3907c478bd9Sstevel@tonic-gate cs_socket_services = SocketServices; 3917c478bd9Sstevel@tonic-gate /* tell CS we are up with basic init level */ 3927c478bd9Sstevel@tonic-gate (void) cs_event(PCE_SS_INIT_STATE, PCE_SS_STATE_INIT, 0); 3937c478bd9Sstevel@tonic-gate } 3947c478bd9Sstevel@tonic-gate 3957c478bd9Sstevel@tonic-gate (void) ddi_prop_update_string(DDI_DEV_T_NONE, dip, 3967c478bd9Sstevel@tonic-gate PCM_DEVICETYPE, "pccard"); 3977c478bd9Sstevel@tonic-gate 3987c478bd9Sstevel@tonic-gate ddi_report_dev(dip); /* directory/device naming */ 3997c478bd9Sstevel@tonic-gate 4007c478bd9Sstevel@tonic-gate /* 4017c478bd9Sstevel@tonic-gate * now setup any power management stuff necessary. 4027c478bd9Sstevel@tonic-gate * we do it here in order to ensure that all PC Card nexi 4037c478bd9Sstevel@tonic-gate * implement it. 4047c478bd9Sstevel@tonic-gate */ 4057c478bd9Sstevel@tonic-gate 4067c478bd9Sstevel@tonic-gate if (pm_create_components(dip, 1) != DDI_SUCCESS) { 4077c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s: not power managed\n", 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, 5147c478bd9Sstevel@tonic-gate ddi_ctl_enum_t ctlop, void *arg, void *result) 5157c478bd9Sstevel@tonic-gate { 5167c478bd9Sstevel@tonic-gate int e; 5177c478bd9Sstevel@tonic-gate char name[64]; 5187c478bd9Sstevel@tonic-gate struct pcmcia_parent_private *ppd; 5197c478bd9Sstevel@tonic-gate power_req_t *pm; 5207c478bd9Sstevel@tonic-gate 5217c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 5227c478bd9Sstevel@tonic-gate if (pcmcia_debug) { 5237c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia_ctlops(%p, %p, %d, %p, %p)\n", 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; 8537c478bd9Sstevel@tonic-gate if (!(ppd->ppd_flags * PPD_CARD_CARDBUS)) 8547c478bd9Sstevel@tonic-gate return (DDI_PROP_NOT_FOUND); 8557c478bd9Sstevel@tonic-gate break; 8567c478bd9Sstevel@tonic-gate } 8577c478bd9Sstevel@tonic-gate 8587c478bd9Sstevel@tonic-gate break; 8597c478bd9Sstevel@tonic-gate 8607c478bd9Sstevel@tonic-gate case PCMCIA_PROP_CIS: 8617c478bd9Sstevel@tonic-gate /* 8627c478bd9Sstevel@tonic-gate * once we have the lookup code in place 8637c478bd9Sstevel@tonic-gate * it is sufficient to break out of the switch 8647c478bd9Sstevel@tonic-gate * once proplen and propptr are set. 8657c478bd9Sstevel@tonic-gate * The common prop_op code deals with the rest. 8667c478bd9Sstevel@tonic-gate */ 8677c478bd9Sstevel@tonic-gate case PCMCIA_PROP_UNKNOWN: 8687c478bd9Sstevel@tonic-gate return (ddi_bus_prop_op(dev, dip, ch_dip, prop_op, 8697c478bd9Sstevel@tonic-gate mod_flags | DDI_PROP_NOTPROM, 8707c478bd9Sstevel@tonic-gate name, valuep, lengthp)); 8717c478bd9Sstevel@tonic-gate } 8727c478bd9Sstevel@tonic-gate 8737c478bd9Sstevel@tonic-gate if (prop_op == PROP_LEN) { 8747c478bd9Sstevel@tonic-gate /* just the length */ 8757c478bd9Sstevel@tonic-gate *lengthp = proplen; 8767c478bd9Sstevel@tonic-gate return (DDI_PROP_SUCCESS); 8777c478bd9Sstevel@tonic-gate } 8787c478bd9Sstevel@tonic-gate switch (prop_op) { 8797c478bd9Sstevel@tonic-gate case PROP_LEN_AND_VAL_ALLOC: 8807c478bd9Sstevel@tonic-gate if (mod_flags & DDI_PROP_CANSLEEP) 8817c478bd9Sstevel@tonic-gate flags = KM_SLEEP; 8827c478bd9Sstevel@tonic-gate else 8837c478bd9Sstevel@tonic-gate flags = KM_NOSLEEP; 8847c478bd9Sstevel@tonic-gate buff = kmem_alloc((size_t)proplen, flags); 8857c478bd9Sstevel@tonic-gate if (buff == NULL) 8867c478bd9Sstevel@tonic-gate return (DDI_PROP_NO_MEMORY); 8877c478bd9Sstevel@tonic-gate *(caddr_t *)valuep = (caddr_t)buff; 8887c478bd9Sstevel@tonic-gate break; 8897c478bd9Sstevel@tonic-gate case PROP_LEN_AND_VAL_BUF: 8907c478bd9Sstevel@tonic-gate buff = (caddr_t)valuep; 8917c478bd9Sstevel@tonic-gate if (len < proplen) 8927c478bd9Sstevel@tonic-gate return (DDI_PROP_BUF_TOO_SMALL); 8937c478bd9Sstevel@tonic-gate break; 8947c478bd9Sstevel@tonic-gate default: 8957c478bd9Sstevel@tonic-gate break; 8967c478bd9Sstevel@tonic-gate } 8977c478bd9Sstevel@tonic-gate 8987c478bd9Sstevel@tonic-gate if (proplen > 0) 8997c478bd9Sstevel@tonic-gate bcopy(propptr, buff, proplen); 9007c478bd9Sstevel@tonic-gate *lengthp = proplen; 9017c478bd9Sstevel@tonic-gate return (DDI_PROP_SUCCESS); 9027c478bd9Sstevel@tonic-gate } 9037c478bd9Sstevel@tonic-gate 9047c478bd9Sstevel@tonic-gate 9057c478bd9Sstevel@tonic-gate struct regspec * 9067c478bd9Sstevel@tonic-gate pcmcia_rnum_to_regspec(dev_info_t *dip, int rnumber) 9077c478bd9Sstevel@tonic-gate { 9087c478bd9Sstevel@tonic-gate struct pcmcia_parent_private *ppd; 9097c478bd9Sstevel@tonic-gate ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(dip); 9107c478bd9Sstevel@tonic-gate if (ppd->ppd_nreg < rnumber) 9117c478bd9Sstevel@tonic-gate return (NULL); 9127c478bd9Sstevel@tonic-gate return ((struct regspec *)&ppd->ppd_reg[rnumber]); 9137c478bd9Sstevel@tonic-gate } 9147c478bd9Sstevel@tonic-gate 9157c478bd9Sstevel@tonic-gate struct regspec * 9167c478bd9Sstevel@tonic-gate pcmcia_rnum_to_mapped(dev_info_t *dip, int rnumber) 9177c478bd9Sstevel@tonic-gate { 9187c478bd9Sstevel@tonic-gate struct pcmcia_parent_private *ppd; 9197c478bd9Sstevel@tonic-gate ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(dip); 9207c478bd9Sstevel@tonic-gate if (ppd->ppd_nreg < rnumber) 9217c478bd9Sstevel@tonic-gate return (NULL); 9220d282d13Srw if (ppd->ppd_assigned == NULL) 9230d282d13Srw return (NULL); 9247c478bd9Sstevel@tonic-gate if (ppd->ppd_assigned[rnumber].phys_len == 0) 9257c478bd9Sstevel@tonic-gate return (NULL); 9267c478bd9Sstevel@tonic-gate else 9277c478bd9Sstevel@tonic-gate return ((struct regspec *)&ppd->ppd_assigned[rnumber]); 9287c478bd9Sstevel@tonic-gate } 9297c478bd9Sstevel@tonic-gate 9307c478bd9Sstevel@tonic-gate int 9317c478bd9Sstevel@tonic-gate pcmcia_find_rnum(dev_info_t *dip, struct regspec *reg) 9327c478bd9Sstevel@tonic-gate { 9337c478bd9Sstevel@tonic-gate struct pcmcia_parent_private *ppd; 9347c478bd9Sstevel@tonic-gate struct regspec *regp; 9357c478bd9Sstevel@tonic-gate int i; 9367c478bd9Sstevel@tonic-gate 9377c478bd9Sstevel@tonic-gate ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(dip); 9387c478bd9Sstevel@tonic-gate if (ppd == NULL) 9397c478bd9Sstevel@tonic-gate return (-1); 9407c478bd9Sstevel@tonic-gate for (regp = (struct regspec *)ppd->ppd_reg, i = 0; 9417c478bd9Sstevel@tonic-gate i < ppd->ppd_nreg; i++, regp++) { 9427c478bd9Sstevel@tonic-gate if (bcmp(reg, regp, sizeof (struct regspec)) == 0) 9437c478bd9Sstevel@tonic-gate return (i); 9447c478bd9Sstevel@tonic-gate } 9457c478bd9Sstevel@tonic-gate for (regp = (struct regspec *)ppd->ppd_assigned, i = 0; 9467c478bd9Sstevel@tonic-gate i < ppd->ppd_nreg; i++, regp++) { 9477c478bd9Sstevel@tonic-gate if (bcmp(reg, regp, sizeof (struct regspec)) == 0) 9487c478bd9Sstevel@tonic-gate return (i); 9497c478bd9Sstevel@tonic-gate } 9507c478bd9Sstevel@tonic-gate 9517c478bd9Sstevel@tonic-gate return (-1); 9527c478bd9Sstevel@tonic-gate } 9537c478bd9Sstevel@tonic-gate 9547c478bd9Sstevel@tonic-gate int 9557c478bd9Sstevel@tonic-gate pcmcia_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, 9567c478bd9Sstevel@tonic-gate off_t offset, off_t len, caddr_t *vaddrp) 9577c478bd9Sstevel@tonic-gate { 9587c478bd9Sstevel@tonic-gate struct pcm_regs *regs, *mregs = NULL, tmp_reg; 9597c478bd9Sstevel@tonic-gate ddi_map_req_t mr = *mp; 9607c478bd9Sstevel@tonic-gate ra_return_t ret; 9617c478bd9Sstevel@tonic-gate int check, rnum = -1; 9627c478bd9Sstevel@tonic-gate uint32_t base; 9637c478bd9Sstevel@tonic-gate uchar_t regbuf[sizeof (pci_regspec_t)]; 9647c478bd9Sstevel@tonic-gate 9657c478bd9Sstevel@tonic-gate mp = &mr; /* a copy of original request */ 9667c478bd9Sstevel@tonic-gate 9677c478bd9Sstevel@tonic-gate /* check for register number */ 9687c478bd9Sstevel@tonic-gate switch (mp->map_type) { 9697c478bd9Sstevel@tonic-gate case DDI_MT_REGSPEC: 9707c478bd9Sstevel@tonic-gate regs = (struct pcm_regs *)mp->map_obj.rp; 9717c478bd9Sstevel@tonic-gate mregs = (struct pcm_regs *)mp->map_obj.rp; 9727c478bd9Sstevel@tonic-gate /* 9737c478bd9Sstevel@tonic-gate * when using regspec, must not be relocatable 9747c478bd9Sstevel@tonic-gate * and should be from assigned space. 9757c478bd9Sstevel@tonic-gate */ 9767c478bd9Sstevel@tonic-gate if (!PC_REG_RELOC(regs->phys_hi)) 9777c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 9787c478bd9Sstevel@tonic-gate rnum = pcmcia_find_rnum(rdip, (struct regspec *)mregs); 9797c478bd9Sstevel@tonic-gate break; 9807c478bd9Sstevel@tonic-gate case DDI_MT_RNUMBER: 9817c478bd9Sstevel@tonic-gate regs = (struct pcm_regs *) 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, 17077c478bd9Sstevel@tonic-gate 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 */ 17787c478bd9Sstevel@tonic-gate for (i = 0; i <= (sizeof (dst) * PR_WORDSIZE) - 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 */ 17847c478bd9Sstevel@tonic-gate for (i = num; i < sizeof (dst) * PR_WORDSIZE; 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, 23417c478bd9Sstevel@tonic-gate 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, 23827c478bd9Sstevel@tonic-gate 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) { 23997c478bd9Sstevel@tonic-gate for (i = 0, len = 0, space = 0; i < vers1.ns; i++) { 24007c478bd9Sstevel@tonic-gate if ((space + len + strlen(info->pd_vers1_name)) >= 24017c478bd9Sstevel@tonic-gate sizeof (info->pd_vers1_name)) 24027c478bd9Sstevel@tonic-gate break; 24037c478bd9Sstevel@tonic-gate if (space) { 24047c478bd9Sstevel@tonic-gate info->pd_vers1_name[len++] = ','; 24057c478bd9Sstevel@tonic-gate } 24067c478bd9Sstevel@tonic-gate (void) strcpy(info->pd_vers1_name + len, 24077c478bd9Sstevel@tonic-gate (char *)vers1.pi[i]); 24087c478bd9Sstevel@tonic-gate len += strlen((char *)vers1.pi[i]); 24097c478bd9Sstevel@tonic-gate /* strip trailing spaces off of string */ 24107c478bd9Sstevel@tonic-gate while (info->pd_vers1_name[len - 1] == ' ' && 24117c478bd9Sstevel@tonic-gate len > 0) 24127c478bd9Sstevel@tonic-gate len--; 24137c478bd9Sstevel@tonic-gate space = 1; 24147c478bd9Sstevel@tonic-gate } 24157c478bd9Sstevel@tonic-gate info->pd_vers1_name[len] = '\0'; 24167c478bd9Sstevel@tonic-gate info->pd_flags |= PCM_NAME_VERS1; 24177c478bd9Sstevel@tonic-gate } 24187c478bd9Sstevel@tonic-gate } 24197c478bd9Sstevel@tonic-gate } 24207c478bd9Sstevel@tonic-gate 24217c478bd9Sstevel@tonic-gate 24227c478bd9Sstevel@tonic-gate int 24237c478bd9Sstevel@tonic-gate pcmcia_get_funce(client_handle_t handle, tuple_t *tuple) 24247c478bd9Sstevel@tonic-gate { 24257c478bd9Sstevel@tonic-gate int ret = 0; 24267c478bd9Sstevel@tonic-gate 24277c478bd9Sstevel@tonic-gate tuple->Attributes = 0; 24287c478bd9Sstevel@tonic-gate while (csx_GetNextTuple(handle, tuple) == SUCCESS) { 24297c478bd9Sstevel@tonic-gate if (tuple->TupleCode == CISTPL_FUNCID) { 24307c478bd9Sstevel@tonic-gate break; 24317c478bd9Sstevel@tonic-gate } 24327c478bd9Sstevel@tonic-gate if (tuple->TupleCode == CISTPL_FUNCE) { 24337c478bd9Sstevel@tonic-gate ret = 1; 24347c478bd9Sstevel@tonic-gate break; 24357c478bd9Sstevel@tonic-gate } 24367c478bd9Sstevel@tonic-gate tuple->Attributes = 0; 24377c478bd9Sstevel@tonic-gate } 24387c478bd9Sstevel@tonic-gate return (ret); 24397c478bd9Sstevel@tonic-gate } 24407c478bd9Sstevel@tonic-gate 24417c478bd9Sstevel@tonic-gate char *pcmcia_lan_types[] = { 24427c478bd9Sstevel@tonic-gate "arcnet", 24437c478bd9Sstevel@tonic-gate "ethernet", 24447c478bd9Sstevel@tonic-gate "token-ring", 24457c478bd9Sstevel@tonic-gate "localtalk", 24467c478bd9Sstevel@tonic-gate "fddi", 24477c478bd9Sstevel@tonic-gate "atm", 24487c478bd9Sstevel@tonic-gate "wireless", 24497c478bd9Sstevel@tonic-gate "reserved" 24507c478bd9Sstevel@tonic-gate }; 24517c478bd9Sstevel@tonic-gate 24527c478bd9Sstevel@tonic-gate void 24537c478bd9Sstevel@tonic-gate pcmcia_generic_name(int socket, struct pcm_device_info *info, 24547c478bd9Sstevel@tonic-gate client_handle_t handle) 24557c478bd9Sstevel@tonic-gate { 24567c478bd9Sstevel@tonic-gate cistpl_funcid_t funcid; 24577c478bd9Sstevel@tonic-gate cistpl_funce_t funce; 24587c478bd9Sstevel@tonic-gate tuple_t tuple; 24597c478bd9Sstevel@tonic-gate int which = 0; 24607c478bd9Sstevel@tonic-gate int i; 24617c478bd9Sstevel@tonic-gate 24627c478bd9Sstevel@tonic-gate tuple.Socket = socket; 24637c478bd9Sstevel@tonic-gate 24647c478bd9Sstevel@tonic-gate tuple.DesiredTuple = CISTPL_FUNCID; 24657c478bd9Sstevel@tonic-gate tuple.Attributes = 0; 24667c478bd9Sstevel@tonic-gate if ((i = csx_GetFirstTuple(handle, &tuple)) == 24677c478bd9Sstevel@tonic-gate SUCCESS) { 24687c478bd9Sstevel@tonic-gate /* 24697c478bd9Sstevel@tonic-gate * need to make sure that CISTPL_FUNCID is not 24707c478bd9Sstevel@tonic-gate * present in both a global and local CIS for MF 24717c478bd9Sstevel@tonic-gate * cards. 3COM seems to do this erroneously 24727c478bd9Sstevel@tonic-gate */ 24737c478bd9Sstevel@tonic-gate 24747c478bd9Sstevel@tonic-gate if (info->pd_flags & PCM_MULTI_FUNCTION && 24757c478bd9Sstevel@tonic-gate tuple.Flags & CISTPLF_GLOBAL_CIS) { 24767c478bd9Sstevel@tonic-gate tuple_t ltuple; 24777c478bd9Sstevel@tonic-gate ltuple = tuple; 24787c478bd9Sstevel@tonic-gate ltuple.DesiredTuple = CISTPL_FUNCID; 24797c478bd9Sstevel@tonic-gate ltuple.Attributes = 0; 24807c478bd9Sstevel@tonic-gate if ((i = csx_GetNextTuple(handle, <uple)) == 24817c478bd9Sstevel@tonic-gate SUCCESS) { 24827c478bd9Sstevel@tonic-gate /* this is the per-function funcid */ 24837c478bd9Sstevel@tonic-gate tuple = ltuple; 24847c478bd9Sstevel@tonic-gate } 24857c478bd9Sstevel@tonic-gate } 24867c478bd9Sstevel@tonic-gate 24877c478bd9Sstevel@tonic-gate i = csx_Parse_CISTPL_FUNCID(handle, &tuple, &funcid); 24887c478bd9Sstevel@tonic-gate if (i == SUCCESS) { 24897c478bd9Sstevel@tonic-gate /* in case no function extension */ 24907c478bd9Sstevel@tonic-gate if (funcid.function < PCM_GENNAME_SIZE) 24917c478bd9Sstevel@tonic-gate (void) strcpy(info->pd_generic_name, 24927c478bd9Sstevel@tonic-gate pcmcia_generic_names[funcid.function]); 24937c478bd9Sstevel@tonic-gate else 24947c478bd9Sstevel@tonic-gate (void) sprintf(info->pd_generic_name, 24955c066ec2SJerry Gilliam "class,%x", 24965c066ec2SJerry Gilliam funcid.function); 24977c478bd9Sstevel@tonic-gate } 24987c478bd9Sstevel@tonic-gate info->pd_type = funcid.function; 24997c478bd9Sstevel@tonic-gate switch (funcid.function) { 25007c478bd9Sstevel@tonic-gate case TPLFUNC_LAN: 25017c478bd9Sstevel@tonic-gate which = pcmcia_get_funce(handle, &tuple); 25027c478bd9Sstevel@tonic-gate if (which) { 25037c478bd9Sstevel@tonic-gate i = csx_Parse_CISTPL_FUNCE(handle, 25047c478bd9Sstevel@tonic-gate &tuple, 25057c478bd9Sstevel@tonic-gate &funce, TPLFUNC_LAN); 25067c478bd9Sstevel@tonic-gate if (i == SUCCESS) { 25077c478bd9Sstevel@tonic-gate i = funce.data.lan.tech; 2508*582c04d6Srui wang - Sun Microsystems - Beijing China if (i >= sizeof (pcmcia_lan_types) / 25097c478bd9Sstevel@tonic-gate sizeof (char *)) { 25107c478bd9Sstevel@tonic-gate break; 25117c478bd9Sstevel@tonic-gate } 25127c478bd9Sstevel@tonic-gate (void) strcpy(info->pd_generic_name, 25135c066ec2SJerry Gilliam pcmcia_lan_types[i]); 25147c478bd9Sstevel@tonic-gate } 25157c478bd9Sstevel@tonic-gate } 25167c478bd9Sstevel@tonic-gate break; 25177c478bd9Sstevel@tonic-gate case TPLFUNC_VIDEO: 25187c478bd9Sstevel@tonic-gate #ifdef future_pcmcia_spec 25197c478bd9Sstevel@tonic-gate which = pcmcia_get_funce(handle, &tuple); 25207c478bd9Sstevel@tonic-gate if (which) { 25217c478bd9Sstevel@tonic-gate i = csx_Parse_CISTPL_FUNCE(handle, 25227c478bd9Sstevel@tonic-gate &tuple, 25237c478bd9Sstevel@tonic-gate &funce, TPLFUNC_VIDEO); 25247c478bd9Sstevel@tonic-gate if (i == SUCCESS) { 25257c478bd9Sstevel@tonic-gate i = funce.video.tech; 25267c478bd9Sstevel@tonic-gate if (i > sizeof (pcmcia_lan_types) / 25277c478bd9Sstevel@tonic-gate sizeof (char *)) { 25287c478bd9Sstevel@tonic-gate break; 25297c478bd9Sstevel@tonic-gate } 25307c478bd9Sstevel@tonic-gate (void) strcpy(info->pd_generic_names, 25315c066ec2SJerry Gilliam pcmcia_lan_types[i]); 25327c478bd9Sstevel@tonic-gate } 25337c478bd9Sstevel@tonic-gate } 25347c478bd9Sstevel@tonic-gate #endif 25357c478bd9Sstevel@tonic-gate break; 25367c478bd9Sstevel@tonic-gate } 25377c478bd9Sstevel@tonic-gate info->pd_flags |= PCM_NAME_GENERIC; 25387c478bd9Sstevel@tonic-gate } else { 25397c478bd9Sstevel@tonic-gate /* if no FUNCID, do we have CONFIG */ 25407c478bd9Sstevel@tonic-gate tuple.DesiredTuple = CISTPL_CONFIG; 25417c478bd9Sstevel@tonic-gate tuple.Attributes = 0; 25427c478bd9Sstevel@tonic-gate if (csx_GetFirstTuple(handle, &tuple) != SUCCESS) { 25437c478bd9Sstevel@tonic-gate info->pd_flags |= PCM_NO_CONFIG | PCM_NAME_GENERIC; 25447c478bd9Sstevel@tonic-gate (void) strcpy(info->pd_generic_name, 25455c066ec2SJerry Gilliam pcmcia_generic_names[PCM_TYPE_MEMORY]); 25467c478bd9Sstevel@tonic-gate info->pd_type = PCM_TYPE_MEMORY; 25477c478bd9Sstevel@tonic-gate } 25487c478bd9Sstevel@tonic-gate } 25497c478bd9Sstevel@tonic-gate } 25507c478bd9Sstevel@tonic-gate 25517c478bd9Sstevel@tonic-gate 25527c478bd9Sstevel@tonic-gate /* 25537c478bd9Sstevel@tonic-gate * pcmcia_add_compatible() 25547c478bd9Sstevel@tonic-gate * add the cached compatible property list. 25557c478bd9Sstevel@tonic-gate */ 25567c478bd9Sstevel@tonic-gate void 25577c478bd9Sstevel@tonic-gate pcmcia_add_compatible(dev_info_t *dip, struct pcm_device_info *info) 25587c478bd9Sstevel@tonic-gate { 25597c478bd9Sstevel@tonic-gate int length = 0, i; 25607c478bd9Sstevel@tonic-gate char buff[MAXNAMELEN]; 25617c478bd9Sstevel@tonic-gate char *compat_name[8]; 25627c478bd9Sstevel@tonic-gate int ci = 0; 25637c478bd9Sstevel@tonic-gate 25647c478bd9Sstevel@tonic-gate bzero(compat_name, sizeof (compat_name)); 25657c478bd9Sstevel@tonic-gate 25667c478bd9Sstevel@tonic-gate if (info->pd_flags & PCM_NAME_VERS1) { 25677c478bd9Sstevel@tonic-gate (void) sprintf(buff, "%s,%s", PCMDEV_NAMEPREF, 25687c478bd9Sstevel@tonic-gate info->pd_vers1_name); 25697c478bd9Sstevel@tonic-gate pcmcia_fix_string(buff); /* don't want spaces */ 25707c478bd9Sstevel@tonic-gate length = strlen(buff) + 1; 25717c478bd9Sstevel@tonic-gate compat_name[ci] = kmem_alloc(length, KM_SLEEP); 25727c478bd9Sstevel@tonic-gate (void) strcpy(compat_name[ci++], buff); 25737c478bd9Sstevel@tonic-gate } 25747c478bd9Sstevel@tonic-gate 25757c478bd9Sstevel@tonic-gate if ((info->pd_flags & (PCM_NAME_1275 | PCM_MULTI_FUNCTION)) == 25767c478bd9Sstevel@tonic-gate (PCM_NAME_1275 | PCM_MULTI_FUNCTION)) { 25777c478bd9Sstevel@tonic-gate (void) sprintf(buff, "%s,%x", info->pd_bind_name, 25787c478bd9Sstevel@tonic-gate info->pd_function); 25797c478bd9Sstevel@tonic-gate length = strlen(buff) + 1; 25807c478bd9Sstevel@tonic-gate compat_name[ci] = kmem_alloc(length, KM_SLEEP); 25817c478bd9Sstevel@tonic-gate (void) strcpy(compat_name[ci++], buff); 25827c478bd9Sstevel@tonic-gate } 25837c478bd9Sstevel@tonic-gate 25847c478bd9Sstevel@tonic-gate if (info->pd_flags & PCM_NAME_1275) { 25857c478bd9Sstevel@tonic-gate length = strlen(info->pd_bind_name) + 1; 25867c478bd9Sstevel@tonic-gate compat_name[ci] = kmem_alloc(length, KM_SLEEP); 25877c478bd9Sstevel@tonic-gate (void) strcpy(compat_name[ci++], info->pd_bind_name); 25887c478bd9Sstevel@tonic-gate } 25897c478bd9Sstevel@tonic-gate 25907c478bd9Sstevel@tonic-gate if (info->pd_flags & PCM_NAME_GENERIC) { 25917c478bd9Sstevel@tonic-gate if (strncmp(info->pd_generic_name, "class,", 6) == 0) { 25927c478bd9Sstevel@tonic-gate /* no generic without "pccard" */ 25937c478bd9Sstevel@tonic-gate (void) sprintf(buff, "%s%s", PCMDEV_NAMEPREF, 25945c066ec2SJerry Gilliam info->pd_generic_name); 25957c478bd9Sstevel@tonic-gate } else { 25967c478bd9Sstevel@tonic-gate /* first pccard,generic-name */ 25977c478bd9Sstevel@tonic-gate (void) sprintf(buff, "%s,%s", PCMDEV_NAMEPREF, 25985c066ec2SJerry Gilliam info->pd_generic_name); 25997c478bd9Sstevel@tonic-gate } 26007c478bd9Sstevel@tonic-gate length = strlen(buff) + 1; 26017c478bd9Sstevel@tonic-gate compat_name[ci] = kmem_alloc(length, KM_SLEEP); 26027c478bd9Sstevel@tonic-gate (void) strcpy(compat_name[ci++], buff); 26037c478bd9Sstevel@tonic-gate 26047c478bd9Sstevel@tonic-gate /* now the simple generic name */ 26057c478bd9Sstevel@tonic-gate length = strlen(info->pd_generic_name) + 1; 26067c478bd9Sstevel@tonic-gate compat_name[ci] = kmem_alloc(length, KM_SLEEP); 26077c478bd9Sstevel@tonic-gate (void) strcpy(compat_name[ci++], info->pd_generic_name); 26087c478bd9Sstevel@tonic-gate } 26097c478bd9Sstevel@tonic-gate 26107c478bd9Sstevel@tonic-gate if (info->pd_flags & PCM_NO_CONFIG) { 26117c478bd9Sstevel@tonic-gate char *mem = "pccard,memory"; 26127c478bd9Sstevel@tonic-gate /* 26137c478bd9Sstevel@tonic-gate * I/O cards are required to have a config tuple. 26147c478bd9Sstevel@tonic-gate * there are some that violate the spec and don't 26157c478bd9Sstevel@tonic-gate * but it is most likely that this is a memory card 26167c478bd9Sstevel@tonic-gate * so tag it as such. "memory" is more general 26177c478bd9Sstevel@tonic-gate * than other things so needs to come last. 26187c478bd9Sstevel@tonic-gate */ 26197c478bd9Sstevel@tonic-gate length = strlen(mem) + 1; 26207c478bd9Sstevel@tonic-gate compat_name[ci] = kmem_alloc(length, KM_SLEEP); 26217c478bd9Sstevel@tonic-gate (void) strcpy(compat_name[ci++], mem); 26227c478bd9Sstevel@tonic-gate } 26237c478bd9Sstevel@tonic-gate 26247c478bd9Sstevel@tonic-gate if (ci == 0) 26257c478bd9Sstevel@tonic-gate return; 26267c478bd9Sstevel@tonic-gate 26277c478bd9Sstevel@tonic-gate if (ndi_prop_update_string_array(DDI_DEV_T_NONE, dip, 26287c478bd9Sstevel@tonic-gate "compatible", (char **)compat_name, ci) != DDI_PROP_SUCCESS) 26297c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pcmcia: unable to create compatible prop"); 26307c478bd9Sstevel@tonic-gate 26317c478bd9Sstevel@tonic-gate for (i = 0; i < ci; i++) 26327c478bd9Sstevel@tonic-gate kmem_free(compat_name[i], strlen(compat_name[i]) + 1); 26337c478bd9Sstevel@tonic-gate } 26347c478bd9Sstevel@tonic-gate /* 26357c478bd9Sstevel@tonic-gate * CIS parsing and other PC Card specific code 26367c478bd9Sstevel@tonic-gate */ 26377c478bd9Sstevel@tonic-gate 26387c478bd9Sstevel@tonic-gate /* 26397c478bd9Sstevel@tonic-gate * pcmcia_get_mem_regs() 26407c478bd9Sstevel@tonic-gate */ 26417c478bd9Sstevel@tonic-gate static int 26427c478bd9Sstevel@tonic-gate pcmcia_get_mem_regs(struct pcm_regs *regs, struct pcm_device_info *info, 26437c478bd9Sstevel@tonic-gate int type, int pctype) 26447c478bd9Sstevel@tonic-gate { 26457c478bd9Sstevel@tonic-gate int num_regs = 0; 26467c478bd9Sstevel@tonic-gate tuple_t tuple; 26477c478bd9Sstevel@tonic-gate cistpl_device_t device; 26487c478bd9Sstevel@tonic-gate uint32_t curr_base; 26497c478bd9Sstevel@tonic-gate int ret, len; 26507c478bd9Sstevel@tonic-gate int space; 26517c478bd9Sstevel@tonic-gate 26527c478bd9Sstevel@tonic-gate /* 26537c478bd9Sstevel@tonic-gate * current plan for reg spec: 26547c478bd9Sstevel@tonic-gate * device_a will be accumulated to determine max size of 26557c478bd9Sstevel@tonic-gate * attribute memory. device for common. Then config 26567c478bd9Sstevel@tonic-gate * tuples to get a worst case I/O size. 26577c478bd9Sstevel@tonic-gate */ 26587c478bd9Sstevel@tonic-gate bzero(&tuple, sizeof (tuple)); 26597c478bd9Sstevel@tonic-gate tuple.Socket = info->pd_socket; 26607c478bd9Sstevel@tonic-gate 26617c478bd9Sstevel@tonic-gate tuple.DesiredTuple = (cisdata_t)type; 26627c478bd9Sstevel@tonic-gate 26637c478bd9Sstevel@tonic-gate space = (type == CISTPL_DEVICE_A) ? PC_REG_SPACE_ATTRIBUTE : 26645c066ec2SJerry Gilliam PC_REG_SPACE_MEMORY; 26657c478bd9Sstevel@tonic-gate if ((ret = csx_GetFirstTuple(info->pd_handle, &tuple)) == CS_SUCCESS) { 26667c478bd9Sstevel@tonic-gate bzero(&device, sizeof (device)); 26677c478bd9Sstevel@tonic-gate 26687c478bd9Sstevel@tonic-gate if (type == CISTPL_DEVICE) 26697c478bd9Sstevel@tonic-gate ret = csx_Parse_CISTPL_DEVICE(info->pd_handle, &tuple, 26707c478bd9Sstevel@tonic-gate &device); 26717c478bd9Sstevel@tonic-gate else 26727c478bd9Sstevel@tonic-gate ret = csx_Parse_CISTPL_DEVICE_A(info->pd_handle, &tuple, 26737c478bd9Sstevel@tonic-gate &device); 26747c478bd9Sstevel@tonic-gate 26757c478bd9Sstevel@tonic-gate if (ret == CS_SUCCESS) { 26767c478bd9Sstevel@tonic-gate curr_base = 0; 26777c478bd9Sstevel@tonic-gate for (ret = 0; ret < device.num_devices; 26787c478bd9Sstevel@tonic-gate ret++) { 26797c478bd9Sstevel@tonic-gate /* need to order these for real mem first */ 26807c478bd9Sstevel@tonic-gate if (device.devnode[ret].type != 26817c478bd9Sstevel@tonic-gate CISTPL_DEVICE_DTYPE_NULL) { 26827c478bd9Sstevel@tonic-gate /* how to represent types??? */ 26837c478bd9Sstevel@tonic-gate regs[num_regs].phys_hi = 26847c478bd9Sstevel@tonic-gate PC_REG_PHYS_HI(0, 0, 26857c478bd9Sstevel@tonic-gate pctype, 26867c478bd9Sstevel@tonic-gate space, 26877c478bd9Sstevel@tonic-gate info->pd_socket, 26887c478bd9Sstevel@tonic-gate info->pd_function, 26897c478bd9Sstevel@tonic-gate 0); 26907c478bd9Sstevel@tonic-gate regs[num_regs].phys_lo = curr_base; 26917c478bd9Sstevel@tonic-gate len = device.devnode[ret].size_in_bytes; 26927c478bd9Sstevel@tonic-gate curr_base += len; 26937c478bd9Sstevel@tonic-gate regs[num_regs].phys_len = len; 26947c478bd9Sstevel@tonic-gate num_regs++; 26957c478bd9Sstevel@tonic-gate } else { 26967c478bd9Sstevel@tonic-gate /* 26977c478bd9Sstevel@tonic-gate * NULL device is a "hole" 26987c478bd9Sstevel@tonic-gate */ 26997c478bd9Sstevel@tonic-gate curr_base += 27007c478bd9Sstevel@tonic-gate device.devnode[ret].size_in_bytes; 27017c478bd9Sstevel@tonic-gate } 27027c478bd9Sstevel@tonic-gate } 27037c478bd9Sstevel@tonic-gate } 27047c478bd9Sstevel@tonic-gate } 27057c478bd9Sstevel@tonic-gate return (num_regs); 27067c478bd9Sstevel@tonic-gate } 27077c478bd9Sstevel@tonic-gate 27087c478bd9Sstevel@tonic-gate /* 27097c478bd9Sstevel@tonic-gate * 27107c478bd9Sstevel@tonic-gate */ 27117c478bd9Sstevel@tonic-gate static int 27127c478bd9Sstevel@tonic-gate pcmcia_get_io_regs(struct pcm_regs *regs, struct pcm_device_info *info, 27137c478bd9Sstevel@tonic-gate int pctype) 27147c478bd9Sstevel@tonic-gate { 27157c478bd9Sstevel@tonic-gate int num_regs = 0; 27167c478bd9Sstevel@tonic-gate tuple_t tuple; 27177c478bd9Sstevel@tonic-gate uint32_t curr_base; 27187c478bd9Sstevel@tonic-gate int len, curr, i, curr_len; 27197c478bd9Sstevel@tonic-gate cistpl_config_t config; 27207c478bd9Sstevel@tonic-gate cistpl_cftable_entry_t cftable; 27217c478bd9Sstevel@tonic-gate struct pcm_regs tmp[16]; 27227c478bd9Sstevel@tonic-gate int found = 0; 27237c478bd9Sstevel@tonic-gate 27247c478bd9Sstevel@tonic-gate bzero(&tuple, sizeof (tuple)); 27257c478bd9Sstevel@tonic-gate tuple.DesiredTuple = CISTPL_CONFIG; 27267c478bd9Sstevel@tonic-gate tuple.Socket = info->pd_socket; 27277c478bd9Sstevel@tonic-gate tuple.Attributes = 0; 27287c478bd9Sstevel@tonic-gate curr_base = 0; 27297c478bd9Sstevel@tonic-gate len = 0; 27307c478bd9Sstevel@tonic-gate 27317c478bd9Sstevel@tonic-gate if (csx_GetFirstTuple(info->pd_handle, &tuple) == CS_SUCCESS) { 27327c478bd9Sstevel@tonic-gate if (csx_Parse_CISTPL_CONFIG(info->pd_handle, 27337c478bd9Sstevel@tonic-gate &tuple, &config) != CS_SUCCESS) { 27347c478bd9Sstevel@tonic-gate info->pd_flags |= PCM_NO_CONFIG; /* must be memory */ 27357c478bd9Sstevel@tonic-gate return (0); 27367c478bd9Sstevel@tonic-gate } 27377c478bd9Sstevel@tonic-gate curr = 0; 27387c478bd9Sstevel@tonic-gate 27397c478bd9Sstevel@tonic-gate tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; 27407c478bd9Sstevel@tonic-gate tuple.Socket = info->pd_socket; 27417c478bd9Sstevel@tonic-gate tuple.Attributes = 0; 27427c478bd9Sstevel@tonic-gate bzero(tmp, sizeof (tmp)); 27435c066ec2SJerry Gilliam while (csx_GetNextTuple(info->pd_handle, &tuple) == CS_SUCCESS) { 27447c478bd9Sstevel@tonic-gate bzero(&cftable, sizeof (cftable)); 27457c478bd9Sstevel@tonic-gate if (csx_Parse_CISTPL_CFTABLE_ENTRY(info->pd_handle, 27467c478bd9Sstevel@tonic-gate &tuple, &cftable) == 27477c478bd9Sstevel@tonic-gate CS_SUCCESS) { 27487c478bd9Sstevel@tonic-gate if (cftable.flags & CISTPL_CFTABLE_TPCE_FS_IO) { 27497c478bd9Sstevel@tonic-gate /* we have an I/O entry */ 27507c478bd9Sstevel@tonic-gate if (cftable.io.flags & 27517c478bd9Sstevel@tonic-gate CISTPL_CFTABLE_TPCE_FS_IO_RANGE) { 27527c478bd9Sstevel@tonic-gate len = cftable.io.addr_lines; 27537c478bd9Sstevel@tonic-gate if (len != 0) 27547c478bd9Sstevel@tonic-gate len = 1 << len; 27557c478bd9Sstevel@tonic-gate for (i = 0; i < cftable.io.ranges && curr < 16; i++) { 27567c478bd9Sstevel@tonic-gate curr_base = cftable.io.range[i].addr; 27577c478bd9Sstevel@tonic-gate curr_len = cftable.io.range[i].length; 27587c478bd9Sstevel@tonic-gate if (curr_len == 0) 27597c478bd9Sstevel@tonic-gate curr_len = len; 27607c478bd9Sstevel@tonic-gate if (len != 0 || cftable.io.addr_lines == 0) { 27617c478bd9Sstevel@tonic-gate /* we have potential relocation */ 27627c478bd9Sstevel@tonic-gate int mask; 27637c478bd9Sstevel@tonic-gate mask = cftable.io.addr_lines ? 27645c066ec2SJerry Gilliam cftable.io.addr_lines : genp2(len); 27657c478bd9Sstevel@tonic-gate mask = genmask(mask); 27667c478bd9Sstevel@tonic-gate if ((mask & curr_base) == 0) { 27677c478bd9Sstevel@tonic-gate /* more accurate length */ 27687c478bd9Sstevel@tonic-gate regs->phys_len = curr_len; 27697c478bd9Sstevel@tonic-gate regs->phys_lo = 0; 27707c478bd9Sstevel@tonic-gate regs->phys_hi = 27717c478bd9Sstevel@tonic-gate PC_REG_PHYS_HI(0, 27725c066ec2SJerry Gilliam 0, 27735c066ec2SJerry Gilliam pctype, 27745c066ec2SJerry Gilliam PC_REG_SPACE_IO, 27755c066ec2SJerry Gilliam info->pd_socket, 27765c066ec2SJerry Gilliam info->pd_function, 27775c066ec2SJerry Gilliam 0); 27787c478bd9Sstevel@tonic-gate num_regs++; 27797c478bd9Sstevel@tonic-gate found = 2; 27807c478bd9Sstevel@tonic-gate break; 27817c478bd9Sstevel@tonic-gate } 27827c478bd9Sstevel@tonic-gate } 27837c478bd9Sstevel@tonic-gate tmp[curr].phys_len = curr_len; 27847c478bd9Sstevel@tonic-gate tmp[curr].phys_lo = curr_base; 27857c478bd9Sstevel@tonic-gate curr++; 27867c478bd9Sstevel@tonic-gate found = 1; 27877c478bd9Sstevel@tonic-gate } 27887c478bd9Sstevel@tonic-gate if (found == 2) 27897c478bd9Sstevel@tonic-gate break; 27907c478bd9Sstevel@tonic-gate } else { 27917c478bd9Sstevel@tonic-gate /* no I/O range so just a mask */ 27927c478bd9Sstevel@tonic-gate regs->phys_len = 1 << cftable.io.addr_lines; 27937c478bd9Sstevel@tonic-gate regs->phys_hi = 27945c066ec2SJerry Gilliam PC_REG_PHYS_HI(0, 27955c066ec2SJerry Gilliam 0, 27965c066ec2SJerry Gilliam pctype, 27975c066ec2SJerry Gilliam PC_REG_SPACE_IO, 27985c066ec2SJerry Gilliam info->pd_socket, 27995c066ec2SJerry Gilliam info->pd_function, 28005c066ec2SJerry Gilliam 0); 28017c478bd9Sstevel@tonic-gate regs->phys_lo = 0; 28027c478bd9Sstevel@tonic-gate num_regs++; 28037c478bd9Sstevel@tonic-gate regs++; 28047c478bd9Sstevel@tonic-gate /* quit on "good" entry */ 28057c478bd9Sstevel@tonic-gate break; 28067c478bd9Sstevel@tonic-gate } 28077c478bd9Sstevel@tonic-gate /* was this the last CFTABLE Entry? */ 28087c478bd9Sstevel@tonic-gate if (config.last == cftable.index) 28097c478bd9Sstevel@tonic-gate break; 28107c478bd9Sstevel@tonic-gate } 28117c478bd9Sstevel@tonic-gate } 28127c478bd9Sstevel@tonic-gate } 28137c478bd9Sstevel@tonic-gate if (found == 1) { 28147c478bd9Sstevel@tonic-gate /* 28157c478bd9Sstevel@tonic-gate * have some non-relocatable values 28167c478bd9Sstevel@tonic-gate * so we include them all for now 28177c478bd9Sstevel@tonic-gate */ 28187c478bd9Sstevel@tonic-gate for (i = 0; i < curr && num_regs < 8; i++) { 28197c478bd9Sstevel@tonic-gate regs->phys_len = tmp[i].phys_len; 28207c478bd9Sstevel@tonic-gate regs->phys_lo = tmp[i].phys_lo; 28217c478bd9Sstevel@tonic-gate regs->phys_hi = PC_REG_PHYS_HI(1, 0, pctype, 28227c478bd9Sstevel@tonic-gate PC_REG_SPACE_IO, info->pd_socket, 28237c478bd9Sstevel@tonic-gate info->pd_function, 0); 28247c478bd9Sstevel@tonic-gate regs++; 28257c478bd9Sstevel@tonic-gate num_regs++; 28267c478bd9Sstevel@tonic-gate } 28277c478bd9Sstevel@tonic-gate } 28287c478bd9Sstevel@tonic-gate } 28297c478bd9Sstevel@tonic-gate return (num_regs); 28307c478bd9Sstevel@tonic-gate } 28317c478bd9Sstevel@tonic-gate 28327c478bd9Sstevel@tonic-gate /* 28337c478bd9Sstevel@tonic-gate * pcmcia_create_regs() 28347c478bd9Sstevel@tonic-gate * create a valid set of regspecs for the card 28357c478bd9Sstevel@tonic-gate * The first one is always for CIS access and naming 28367c478bd9Sstevel@tonic-gate */ 28377c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 28387c478bd9Sstevel@tonic-gate static void 28397c478bd9Sstevel@tonic-gate pcmcia_find_regs(dev_info_t *dip, struct pcm_device_info *info, 28407c478bd9Sstevel@tonic-gate struct pcmcia_parent_private *ppd) 28417c478bd9Sstevel@tonic-gate { 28427c478bd9Sstevel@tonic-gate struct pcm_regs regs[32]; /* assume worst case */ 28437c478bd9Sstevel@tonic-gate int num_regs = 0; 28447c478bd9Sstevel@tonic-gate int len; 28457c478bd9Sstevel@tonic-gate int bustype; 28467c478bd9Sstevel@tonic-gate 28477c478bd9Sstevel@tonic-gate if (ppd->ppd_flags & PPD_CARD_CARDBUS) { 28487c478bd9Sstevel@tonic-gate /* always have a CIS map */ 28497c478bd9Sstevel@tonic-gate regs[0].phys_hi = PC_REG_PHYS_HI(0, 0, PC_REG_TYPE_CARDBUS, 28505c066ec2SJerry Gilliam PC_REG_SPACE_CONFIG, 28515c066ec2SJerry Gilliam info->pd_socket, 28525c066ec2SJerry Gilliam info->pd_function, 0); 28537c478bd9Sstevel@tonic-gate bustype = PC_REG_TYPE_CARDBUS; 28547c478bd9Sstevel@tonic-gate } else { 28557c478bd9Sstevel@tonic-gate /* always have a CIS map */ 28567c478bd9Sstevel@tonic-gate regs[0].phys_hi = PC_REG_PHYS_HI(0, 0, PC_REG_TYPE_16BIT, 28575c066ec2SJerry Gilliam PC_REG_SPACE_ATTRIBUTE, 28585c066ec2SJerry Gilliam info->pd_socket, 28595c066ec2SJerry Gilliam info->pd_function, 0); 28607c478bd9Sstevel@tonic-gate bustype = PC_REG_TYPE_16BIT; 28617c478bd9Sstevel@tonic-gate } 28627c478bd9Sstevel@tonic-gate regs[0].phys_lo = 0; /* always starts at zero */ 28637c478bd9Sstevel@tonic-gate regs[0].phys_len = 0; 28647c478bd9Sstevel@tonic-gate num_regs++; 28657c478bd9Sstevel@tonic-gate /* 28667c478bd9Sstevel@tonic-gate * need to search CIS for other memory instances 28677c478bd9Sstevel@tonic-gate */ 28687c478bd9Sstevel@tonic-gate 28697c478bd9Sstevel@tonic-gate if (info->pd_flags & PCM_OTHER_NOCIS) { 28707c478bd9Sstevel@tonic-gate /* special case of memory only card without CIS */ 28717c478bd9Sstevel@tonic-gate regs[1].phys_hi = PC_REG_PHYS_HI(0, 0, PC_REG_TYPE_16BIT, 28725c066ec2SJerry Gilliam PC_REG_SPACE_MEMORY, 28735c066ec2SJerry Gilliam info->pd_socket, 28745c066ec2SJerry Gilliam info->pd_function, 0); 28757c478bd9Sstevel@tonic-gate regs[1].phys_lo = 0; 28767c478bd9Sstevel@tonic-gate regs[1].phys_len = PCM_MAX_R2_MEM; 28777c478bd9Sstevel@tonic-gate num_regs++; 28787c478bd9Sstevel@tonic-gate } else { 28797c478bd9Sstevel@tonic-gate /* 28807c478bd9Sstevel@tonic-gate * want to get any other memory and/or I/O regions 28817c478bd9Sstevel@tonic-gate * on the card and represent them here. 28827c478bd9Sstevel@tonic-gate */ 28837c478bd9Sstevel@tonic-gate num_regs += pcmcia_get_mem_regs(®s[num_regs], info, 28845c066ec2SJerry Gilliam CISTPL_DEVICE_A, bustype); 28857c478bd9Sstevel@tonic-gate num_regs += pcmcia_get_mem_regs(®s[num_regs], info, 28865c066ec2SJerry Gilliam CISTPL_DEVICE, bustype); 28877c478bd9Sstevel@tonic-gate 28887c478bd9Sstevel@tonic-gate /* now look for an I/O space to configure */ 28897c478bd9Sstevel@tonic-gate num_regs += pcmcia_get_io_regs(®s[num_regs], info, 28905c066ec2SJerry Gilliam bustype); 28917c478bd9Sstevel@tonic-gate 28927c478bd9Sstevel@tonic-gate } 28937c478bd9Sstevel@tonic-gate 28947c478bd9Sstevel@tonic-gate len = num_regs * sizeof (uint32_t) * 3; 28957c478bd9Sstevel@tonic-gate ppd->ppd_nreg = num_regs; 28967c478bd9Sstevel@tonic-gate ppd->ppd_reg = kmem_alloc(len, KM_SLEEP); 28977c478bd9Sstevel@tonic-gate bcopy(regs, ppd->ppd_reg, len); 28987c478bd9Sstevel@tonic-gate len = sizeof (struct pcm_regs) * ppd->ppd_nreg; 28997c478bd9Sstevel@tonic-gate ppd->ppd_assigned = kmem_zalloc(len, KM_SLEEP); 29007c478bd9Sstevel@tonic-gate } 29017c478bd9Sstevel@tonic-gate 29027c478bd9Sstevel@tonic-gate 29037c478bd9Sstevel@tonic-gate /* 29047c478bd9Sstevel@tonic-gate * pcmcia_need_intr() 29057c478bd9Sstevel@tonic-gate * check to see if an interrupt tuple exists. 29067c478bd9Sstevel@tonic-gate * existence means we need one in the intrspec. 29077c478bd9Sstevel@tonic-gate */ 29087c478bd9Sstevel@tonic-gate static int 29097c478bd9Sstevel@tonic-gate pcmcia_need_intr(int socket, struct pcm_device_info *info) 29107c478bd9Sstevel@tonic-gate { 29117c478bd9Sstevel@tonic-gate cistpl_config_t config; 29127c478bd9Sstevel@tonic-gate cistpl_cftable_entry_t cftable; 29137c478bd9Sstevel@tonic-gate tuple_t tuple; 29147c478bd9Sstevel@tonic-gate int i; 29157c478bd9Sstevel@tonic-gate 29167c478bd9Sstevel@tonic-gate bzero(&tuple, sizeof (tuple)); 29177c478bd9Sstevel@tonic-gate tuple.DesiredTuple = CISTPL_CONFIG; 29187c478bd9Sstevel@tonic-gate tuple.Socket = socket; 29197c478bd9Sstevel@tonic-gate tuple.Attributes = 0; 29207c478bd9Sstevel@tonic-gate if (csx_GetFirstTuple(info->pd_handle, &tuple) != CS_SUCCESS) { 29217c478bd9Sstevel@tonic-gate return (0); 29227c478bd9Sstevel@tonic-gate } 29237c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 29247c478bd9Sstevel@tonic-gate if (pcmcia_debug) { 29257c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia_need_intr: have config tuple\n"); 29267c478bd9Sstevel@tonic-gate } 29277c478bd9Sstevel@tonic-gate #endif 29287c478bd9Sstevel@tonic-gate bzero(&config, sizeof (config)); 29297c478bd9Sstevel@tonic-gate if (csx_Parse_CISTPL_CONFIG(info->pd_handle, 29307c478bd9Sstevel@tonic-gate &tuple, &config) != CS_SUCCESS) { 29317c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pcmcia: config failed to parse\n"); 29327c478bd9Sstevel@tonic-gate return (0); 29337c478bd9Sstevel@tonic-gate } 29347c478bd9Sstevel@tonic-gate 29357c478bd9Sstevel@tonic-gate for (cftable.index = (int)-1, i = -1; 29365c066ec2SJerry Gilliam i != config.last; i = cftable.index) { 29377c478bd9Sstevel@tonic-gate tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; 29387c478bd9Sstevel@tonic-gate tuple.Attributes = 0; 29397c478bd9Sstevel@tonic-gate if (csx_GetNextTuple(info->pd_handle, 29407c478bd9Sstevel@tonic-gate &tuple) != CS_SUCCESS) { 29417c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pcmcia: get cftable failed\n"); 29427c478bd9Sstevel@tonic-gate break; 29437c478bd9Sstevel@tonic-gate } 29447c478bd9Sstevel@tonic-gate bzero(&cftable, sizeof (cftable)); 29457c478bd9Sstevel@tonic-gate if (csx_Parse_CISTPL_CFTABLE_ENTRY(info->pd_handle, 29467c478bd9Sstevel@tonic-gate &tuple, &cftable) != 29477c478bd9Sstevel@tonic-gate CS_SUCCESS) { 29487c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pcmcia: parse cftable failed\n"); 29497c478bd9Sstevel@tonic-gate break; 29507c478bd9Sstevel@tonic-gate } 29517c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 29527c478bd9Sstevel@tonic-gate if (pcmcia_debug) 29537c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "\t%x: flags=%x (%x)\n", 29545c066ec2SJerry Gilliam i, cftable.flags, 29555c066ec2SJerry Gilliam cftable.flags & CISTPL_CFTABLE_TPCE_FS_IRQ); 29567c478bd9Sstevel@tonic-gate #endif 29577c478bd9Sstevel@tonic-gate if (cftable.flags & CISTPL_CFTABLE_TPCE_FS_IRQ) 29587c478bd9Sstevel@tonic-gate return (1); 29597c478bd9Sstevel@tonic-gate } 29607c478bd9Sstevel@tonic-gate return (0); 29617c478bd9Sstevel@tonic-gate 29627c478bd9Sstevel@tonic-gate } 29637c478bd9Sstevel@tonic-gate 29647c478bd9Sstevel@tonic-gate /* 29657c478bd9Sstevel@tonic-gate * pcmcia_num_funcs() 29667c478bd9Sstevel@tonic-gate * look for a CISTPL_LONGLINK_MFC 29677c478bd9Sstevel@tonic-gate * if there is one, return the number of functions 29687c478bd9Sstevel@tonic-gate * if there isn't one, then there is one function 29697c478bd9Sstevel@tonic-gate */ 29707c478bd9Sstevel@tonic-gate static int 29717c478bd9Sstevel@tonic-gate pcmcia_num_funcs(int socket, client_handle_t handle) 29727c478bd9Sstevel@tonic-gate { 29737c478bd9Sstevel@tonic-gate int count = 1; 29747c478bd9Sstevel@tonic-gate cistpl_longlink_mfc_t mfc; 29757c478bd9Sstevel@tonic-gate tuple_t tuple; 29767c478bd9Sstevel@tonic-gate 29777c478bd9Sstevel@tonic-gate bzero(&tuple, sizeof (tuple_t)); 29787c478bd9Sstevel@tonic-gate tuple.DesiredTuple = CISTPL_LONGLINK_MFC; 29797c478bd9Sstevel@tonic-gate tuple.Socket = socket; 29807c478bd9Sstevel@tonic-gate tuple.Attributes = 0; 29817c478bd9Sstevel@tonic-gate if (csx_GetFirstTuple(handle, &tuple) == CS_SUCCESS) { 29827c478bd9Sstevel@tonic-gate /* this is a multifunction card */ 29837c478bd9Sstevel@tonic-gate if (csx_ParseTuple(handle, &tuple, (cisparse_t *)&mfc, 29847c478bd9Sstevel@tonic-gate CISTPL_LONGLINK_MFC) == CS_SUCCESS) { 29857c478bd9Sstevel@tonic-gate count = mfc.nfuncs; 29867c478bd9Sstevel@tonic-gate } 29877c478bd9Sstevel@tonic-gate } 29887c478bd9Sstevel@tonic-gate return (count); 29897c478bd9Sstevel@tonic-gate } 29907c478bd9Sstevel@tonic-gate 29917c478bd9Sstevel@tonic-gate client_handle_t pcmcia_cs_handle; 29927c478bd9Sstevel@tonic-gate 29937c478bd9Sstevel@tonic-gate /* 29947c478bd9Sstevel@tonic-gate * pcmcia_create_dev_info(socket) 29957c478bd9Sstevel@tonic-gate * either find or create the device information structure 29967c478bd9Sstevel@tonic-gate * for the card(s) just inserted. We don't care about removal yet. 29977c478bd9Sstevel@tonic-gate * In any case, we will only do this at CS request 29987c478bd9Sstevel@tonic-gate */ 29997c478bd9Sstevel@tonic-gate static void 30007c478bd9Sstevel@tonic-gate pcmcia_create_dev_info(int socket) 30017c478bd9Sstevel@tonic-gate { 30027c478bd9Sstevel@tonic-gate struct pcm_device_info card_info; 30037c478bd9Sstevel@tonic-gate client_reg_t reg; 30047c478bd9Sstevel@tonic-gate cisinfo_t cisinfo; 30057c478bd9Sstevel@tonic-gate int i; 30067c478bd9Sstevel@tonic-gate dev_info_t *pdip; 30077c478bd9Sstevel@tonic-gate static int handle_def = 0; 30087c478bd9Sstevel@tonic-gate 30097c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 30107c478bd9Sstevel@tonic-gate if (pcmcia_debug) 30117c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "create dev_info_t for device in socket %d\n", 30125c066ec2SJerry Gilliam socket); 30137c478bd9Sstevel@tonic-gate #endif 30147c478bd9Sstevel@tonic-gate 30157c478bd9Sstevel@tonic-gate /* 30167c478bd9Sstevel@tonic-gate * before we can do anything else, we need the parent 30177c478bd9Sstevel@tonic-gate * devinfo of the socket. This gets things in the right 30187c478bd9Sstevel@tonic-gate * place in the device tree. 30197c478bd9Sstevel@tonic-gate */ 30207c478bd9Sstevel@tonic-gate 30217c478bd9Sstevel@tonic-gate pdip = pcm_find_parent_dip(socket); 30227c478bd9Sstevel@tonic-gate if (pdip == NULL) 30237c478bd9Sstevel@tonic-gate return; 30247c478bd9Sstevel@tonic-gate 30257c478bd9Sstevel@tonic-gate /* Card Services calls needed to get CIS info */ 30267c478bd9Sstevel@tonic-gate reg.dip = NULL; 30277c478bd9Sstevel@tonic-gate reg.Attributes = INFO_SOCKET_SERVICES; 30287c478bd9Sstevel@tonic-gate reg.EventMask = 0; 30297c478bd9Sstevel@tonic-gate reg.event_handler = NULL; 30307c478bd9Sstevel@tonic-gate reg.Version = CS_VERSION; 30317c478bd9Sstevel@tonic-gate 30327c478bd9Sstevel@tonic-gate bzero(&card_info, sizeof (card_info)); 30337c478bd9Sstevel@tonic-gate 30347c478bd9Sstevel@tonic-gate if (handle_def == 0) { 30357c478bd9Sstevel@tonic-gate if (csx_RegisterClient(&pcmcia_cs_handle, 30367c478bd9Sstevel@tonic-gate ®) != CS_SUCCESS) { 30377c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 30387c478bd9Sstevel@tonic-gate if (pcmcia_debug) 30397c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 30405c066ec2SJerry Gilliam "pcmcia: RegisterClient failed\n"); 30417c478bd9Sstevel@tonic-gate #endif 30427c478bd9Sstevel@tonic-gate return; 30437c478bd9Sstevel@tonic-gate } 30447c478bd9Sstevel@tonic-gate handle_def++; 30457c478bd9Sstevel@tonic-gate } 30467c478bd9Sstevel@tonic-gate card_info.pd_handle = pcmcia_cs_handle; 30477c478bd9Sstevel@tonic-gate 30487c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 30497c478bd9Sstevel@tonic-gate if (pcmcia_debug) 30507c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 30515c066ec2SJerry Gilliam "pcmcia_create_dev_info: handle = %x\n", 30525c066ec2SJerry Gilliam (int)card_info.pd_handle); 30537c478bd9Sstevel@tonic-gate #endif 30547c478bd9Sstevel@tonic-gate card_info.pd_type = -1; /* no type to start */ 30557c478bd9Sstevel@tonic-gate card_info.pd_socket = socket; 30567c478bd9Sstevel@tonic-gate card_info.pd_function = 0; 30577c478bd9Sstevel@tonic-gate pcmcia_sockets[socket]->ls_functions = 1; /* default */ 30587c478bd9Sstevel@tonic-gate 30597c478bd9Sstevel@tonic-gate cisinfo.Socket = socket; 30607c478bd9Sstevel@tonic-gate 30617c478bd9Sstevel@tonic-gate if ((i = csx_ValidateCIS(card_info.pd_handle, 30627c478bd9Sstevel@tonic-gate &cisinfo)) != SUCCESS || 30637c478bd9Sstevel@tonic-gate cisinfo.Tuples == 0) { 30647c478bd9Sstevel@tonic-gate /* no CIS means memory */ 30657c478bd9Sstevel@tonic-gate (void) strcpy(card_info.pd_generic_name, "memory"); 30667c478bd9Sstevel@tonic-gate card_info.pd_flags |= PCM_NAME_GENERIC | 30675c066ec2SJerry Gilliam PCM_OTHER_NOCIS | PCM_NAME_1275; 30687c478bd9Sstevel@tonic-gate (void) strcpy(card_info.pd_bind_name, "pccard,memory"); 30697c478bd9Sstevel@tonic-gate (void) strcpy(card_info.pd_generic_name, "memory"); 30707c478bd9Sstevel@tonic-gate card_info.pd_type = PCM_TYPE_MEMORY; 30717c478bd9Sstevel@tonic-gate } else { 30727c478bd9Sstevel@tonic-gate int functions, lsocket; 30737c478bd9Sstevel@tonic-gate card_info.pd_tuples = cisinfo.Tuples; 30747c478bd9Sstevel@tonic-gate 30757c478bd9Sstevel@tonic-gate /* 30767c478bd9Sstevel@tonic-gate * how many functions on the card? 30777c478bd9Sstevel@tonic-gate * we need to know and then we do one 30787c478bd9Sstevel@tonic-gate * child node for each function using 30797c478bd9Sstevel@tonic-gate * the function specific tuples. 30807c478bd9Sstevel@tonic-gate */ 30817c478bd9Sstevel@tonic-gate lsocket = CS_MAKE_SOCKET_NUMBER(socket, CS_GLOBAL_CIS); 30827c478bd9Sstevel@tonic-gate functions = pcmcia_num_funcs(lsocket, 30837c478bd9Sstevel@tonic-gate card_info.pd_handle); 30847c478bd9Sstevel@tonic-gate pcmcia_sockets[socket]->ls_functions = functions; 30857c478bd9Sstevel@tonic-gate if (functions > 1) { 30867c478bd9Sstevel@tonic-gate card_info.pd_flags |= PCM_MULTI_FUNCTION; 30877c478bd9Sstevel@tonic-gate } 30887c478bd9Sstevel@tonic-gate for (i = 0; i < functions; i++) { 30897c478bd9Sstevel@tonic-gate register int flags; 30907c478bd9Sstevel@tonic-gate lsocket = CS_MAKE_SOCKET_NUMBER(socket, i); 30917c478bd9Sstevel@tonic-gate card_info.pd_socket = socket; 30927c478bd9Sstevel@tonic-gate card_info.pd_function = i; 30937c478bd9Sstevel@tonic-gate /* 30947c478bd9Sstevel@tonic-gate * new name construction 30957c478bd9Sstevel@tonic-gate */ 30967c478bd9Sstevel@tonic-gate if (functions != 1) { 30977c478bd9Sstevel@tonic-gate /* need per function handle */ 30987c478bd9Sstevel@tonic-gate card_info.pd_function = i; 30997c478bd9Sstevel@tonic-gate /* get new handle */ 31007c478bd9Sstevel@tonic-gate } 31017c478bd9Sstevel@tonic-gate pcmcia_1275_name(lsocket, &card_info, 31027c478bd9Sstevel@tonic-gate card_info.pd_handle); 31037c478bd9Sstevel@tonic-gate pcmcia_vers1_name(lsocket, &card_info, 31047c478bd9Sstevel@tonic-gate card_info.pd_handle); 31057c478bd9Sstevel@tonic-gate pcmcia_generic_name(lsocket, &card_info, 31067c478bd9Sstevel@tonic-gate card_info.pd_handle); 31077c478bd9Sstevel@tonic-gate flags = card_info.pd_flags; 31087c478bd9Sstevel@tonic-gate if (!(flags & PCM_NAME_1275)) { 31097c478bd9Sstevel@tonic-gate if (flags & PCM_NAME_VERS1) { 31107c478bd9Sstevel@tonic-gate (void) strcpy(card_info.pd_bind_name, 31117c478bd9Sstevel@tonic-gate PCMDEV_NAMEPREF); 31127c478bd9Sstevel@tonic-gate card_info.pd_bind_name[sizeof (PCMDEV_NAMEPREF)] = 31137c478bd9Sstevel@tonic-gate ','; 31147c478bd9Sstevel@tonic-gate (void) strncpy(card_info.pd_bind_name + 31157c478bd9Sstevel@tonic-gate sizeof (PCMDEV_NAMEPREF), 31167c478bd9Sstevel@tonic-gate card_info.pd_vers1_name, 31177c478bd9Sstevel@tonic-gate MODMAXNAMELEN - 31187c478bd9Sstevel@tonic-gate sizeof (PCMDEV_NAMEPREF)); 31197c478bd9Sstevel@tonic-gate pcmcia_fix_string(card_info.pd_bind_name); 31207c478bd9Sstevel@tonic-gate } else { 31217c478bd9Sstevel@tonic-gate /* 31227c478bd9Sstevel@tonic-gate * have a CIS but not the right info 31237c478bd9Sstevel@tonic-gate * so treat as generic "pccard" 31247c478bd9Sstevel@tonic-gate */ 31257c478bd9Sstevel@tonic-gate (void) strcpy(card_info.pd_generic_name, 31265c066ec2SJerry Gilliam "pccard,memory"); 31277c478bd9Sstevel@tonic-gate card_info.pd_flags |= PCM_NAME_GENERIC; 31287c478bd9Sstevel@tonic-gate (void) strcpy(card_info.pd_bind_name, 31295c066ec2SJerry Gilliam "pccard,memory"); 31307c478bd9Sstevel@tonic-gate } 31317c478bd9Sstevel@tonic-gate } 31327c478bd9Sstevel@tonic-gate pcmcia_init_devinfo(pdip, &card_info); 31337c478bd9Sstevel@tonic-gate } 31347c478bd9Sstevel@tonic-gate return; 31357c478bd9Sstevel@tonic-gate } 31367c478bd9Sstevel@tonic-gate 31377c478bd9Sstevel@tonic-gate pcmcia_init_devinfo(pdip, &card_info); 31387c478bd9Sstevel@tonic-gate } 31397c478bd9Sstevel@tonic-gate 31407c478bd9Sstevel@tonic-gate /* 31417c478bd9Sstevel@tonic-gate * pcmcia_init_devinfo() 31427c478bd9Sstevel@tonic-gate * if there isn't a device info structure, create one 31437c478bd9Sstevel@tonic-gate * if there is, we don't do much. 31447c478bd9Sstevel@tonic-gate * 31457c478bd9Sstevel@tonic-gate * Note: this will need updating as 1275 finalizes their spec. 31467c478bd9Sstevel@tonic-gate */ 31477c478bd9Sstevel@tonic-gate static void 31487c478bd9Sstevel@tonic-gate pcmcia_init_devinfo(dev_info_t *pdip, struct pcm_device_info *info) 31497c478bd9Sstevel@tonic-gate { 31507c478bd9Sstevel@tonic-gate int unit; 31517c478bd9Sstevel@tonic-gate dev_info_t *dip; 31527c478bd9Sstevel@tonic-gate char *name; 31537c478bd9Sstevel@tonic-gate struct pcmcia_parent_private *ppd; 31547c478bd9Sstevel@tonic-gate 31557c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 31567c478bd9Sstevel@tonic-gate if (pcmcia_debug) 31577c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "init_devinfo(%s, %d)\n", info->pd_bind_name, 31585c066ec2SJerry Gilliam info->pd_socket); 31597c478bd9Sstevel@tonic-gate #endif 31607c478bd9Sstevel@tonic-gate 31617c478bd9Sstevel@tonic-gate /* 31627c478bd9Sstevel@tonic-gate * find out if there is already an instance of this 31637c478bd9Sstevel@tonic-gate * device. We don't want to create a new one unnecessarily 31647c478bd9Sstevel@tonic-gate */ 31657c478bd9Sstevel@tonic-gate unit = CS_MAKE_SOCKET_NUMBER(info->pd_socket, info->pd_function); 31667c478bd9Sstevel@tonic-gate 31677c478bd9Sstevel@tonic-gate dip = pcm_find_devinfo(pdip, info, unit); 31687c478bd9Sstevel@tonic-gate if ((dip != NULL) && (ddi_getprop(DDI_DEV_T_NONE, dip, 31697c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, PCM_DEV_SOCKET, -1) != -1)) { 31707c478bd9Sstevel@tonic-gate /* it already exist but isn't a .conf file */ 31717c478bd9Sstevel@tonic-gate 31727c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 31737c478bd9Sstevel@tonic-gate if (pcmcia_debug) 31747c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "\tfound existing device node (%s)\n", 31755c066ec2SJerry Gilliam ddi_get_name(dip)); 31767c478bd9Sstevel@tonic-gate #endif 31777c478bd9Sstevel@tonic-gate if (strlen(info->pd_vers1_name) > 0) 31787c478bd9Sstevel@tonic-gate (void) ndi_prop_update_string(DDI_DEV_T_NONE, 31797c478bd9Sstevel@tonic-gate dip, PCM_DEV_MODEL, info->pd_vers1_name); 31807c478bd9Sstevel@tonic-gate 31817c478bd9Sstevel@tonic-gate ppd = (struct pcmcia_parent_private *) 31825c066ec2SJerry Gilliam ddi_get_parent_data(dip); 31837c478bd9Sstevel@tonic-gate 31847c478bd9Sstevel@tonic-gate pcmcia_sockets[info->pd_socket]->ls_dip[info->pd_function] = 31857c478bd9Sstevel@tonic-gate dip; 31867c478bd9Sstevel@tonic-gate 31877c478bd9Sstevel@tonic-gate ppd->ppd_active = 1; 31887c478bd9Sstevel@tonic-gate 31897c478bd9Sstevel@tonic-gate if (ndi_devi_online(dip, 0) == NDI_FAILURE) { 31907c478bd9Sstevel@tonic-gate pcmcia_sockets[info->pd_socket]-> \ 31917c478bd9Sstevel@tonic-gate ls_dip[info->pd_function] = NULL; 31927c478bd9Sstevel@tonic-gate ppd->ppd_active = 0; 31937c478bd9Sstevel@tonic-gate } 31947c478bd9Sstevel@tonic-gate } else { 31957c478bd9Sstevel@tonic-gate 31967c478bd9Sstevel@tonic-gate char *dtype; 31977c478bd9Sstevel@tonic-gate 31987c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 31997c478bd9Sstevel@tonic-gate if (pcmcia_debug) 32007c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia: create child [%s](%d): %s\n", 32017c478bd9Sstevel@tonic-gate info->pd_bind_name, info->pd_socket, 32027c478bd9Sstevel@tonic-gate info->pd_generic_name); 32037c478bd9Sstevel@tonic-gate #endif 32047c478bd9Sstevel@tonic-gate 32057c478bd9Sstevel@tonic-gate if (info->pd_flags & PCM_NAME_GENERIC) 32067c478bd9Sstevel@tonic-gate name = info->pd_generic_name; 32077c478bd9Sstevel@tonic-gate else 32087c478bd9Sstevel@tonic-gate name = info->pd_bind_name; 32097c478bd9Sstevel@tonic-gate 3210fa9e4066Sahrens if (ndi_devi_alloc(pdip, name, (pnode_t)DEVI_SID_NODEID, 32117c478bd9Sstevel@tonic-gate &dip) != 32127c478bd9Sstevel@tonic-gate NDI_SUCCESS) { 32137c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 32147c478bd9Sstevel@tonic-gate "pcmcia: unable to create device [%s](%d)\n", 32157c478bd9Sstevel@tonic-gate name, info->pd_socket); 32167c478bd9Sstevel@tonic-gate return; 32177c478bd9Sstevel@tonic-gate } 32187c478bd9Sstevel@tonic-gate /* 32197c478bd9Sstevel@tonic-gate * construct the "compatible" property if the device 32207c478bd9Sstevel@tonic-gate * has a generic name 32217c478bd9Sstevel@tonic-gate */ 32227c478bd9Sstevel@tonic-gate pcmcia_add_compatible(dip, info); 32237c478bd9Sstevel@tonic-gate 32247c478bd9Sstevel@tonic-gate ppd = kmem_zalloc(sizeof (struct pcmcia_parent_private), 32255c066ec2SJerry Gilliam KM_SLEEP); 32267c478bd9Sstevel@tonic-gate 32277c478bd9Sstevel@tonic-gate ppd->ppd_socket = info->pd_socket; 32287c478bd9Sstevel@tonic-gate ppd->ppd_function = info->pd_function; 32297c478bd9Sstevel@tonic-gate 32307c478bd9Sstevel@tonic-gate /* 32317c478bd9Sstevel@tonic-gate * add the "socket" property 32327c478bd9Sstevel@tonic-gate * the value of this property contains the logical PCMCIA 32337c478bd9Sstevel@tonic-gate * socket number the device has been inserted in, along 32347c478bd9Sstevel@tonic-gate * with the function # if the device is part of a 32357c478bd9Sstevel@tonic-gate * multi-function device. 32367c478bd9Sstevel@tonic-gate */ 32377c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, dip, 32387c478bd9Sstevel@tonic-gate PCM_DEV_SOCKET, unit); 32397c478bd9Sstevel@tonic-gate 32407c478bd9Sstevel@tonic-gate if (info->pd_flags & PCM_MULTI_FUNCTION) 32417c478bd9Sstevel@tonic-gate ppd->ppd_flags |= PPD_CARD_MULTI; 32427c478bd9Sstevel@tonic-gate 32437c478bd9Sstevel@tonic-gate /* 32447c478bd9Sstevel@tonic-gate * determine all the properties we need for PPD 32457c478bd9Sstevel@tonic-gate * then create the properties 32467c478bd9Sstevel@tonic-gate */ 32477c478bd9Sstevel@tonic-gate /* socket is unique */ 32487c478bd9Sstevel@tonic-gate pcmcia_find_regs(dip, info, ppd); 32497c478bd9Sstevel@tonic-gate 32507c478bd9Sstevel@tonic-gate ppd->ppd_intr = pcmcia_need_intr(unit, info); 32517c478bd9Sstevel@tonic-gate 32527c478bd9Sstevel@tonic-gate if (ppd->ppd_nreg > 0) 32537c478bd9Sstevel@tonic-gate (void) ddi_prop_update_int_array(DDI_DEV_T_NONE, dip, 32547c478bd9Sstevel@tonic-gate "reg", (int *)ppd->ppd_reg, ppd->ppd_nreg * 32557c478bd9Sstevel@tonic-gate sizeof (struct pcm_regs) / sizeof (int)); 32567c478bd9Sstevel@tonic-gate if (ppd->ppd_intr) { 32577c478bd9Sstevel@tonic-gate (void) ddi_prop_update_int(DDI_DEV_T_NONE, dip, 32587c478bd9Sstevel@tonic-gate "interrupts", ppd->ppd_intr); 32597c478bd9Sstevel@tonic-gate ppd->ppd_intrspec = 32607c478bd9Sstevel@tonic-gate kmem_zalloc(sizeof (struct intrspec), KM_SLEEP); 32617c478bd9Sstevel@tonic-gate } 32627c478bd9Sstevel@tonic-gate 32637c478bd9Sstevel@tonic-gate /* set parent private - our own format */ 32647c478bd9Sstevel@tonic-gate ddi_set_parent_data(dip, (caddr_t)ppd); 32657c478bd9Sstevel@tonic-gate 32667c478bd9Sstevel@tonic-gate /* init the device type */ 32677c478bd9Sstevel@tonic-gate if (info->pd_type >= 0 && 32687c478bd9Sstevel@tonic-gate info->pd_type < (sizeof (pcmcia_dev_type) / 32697c478bd9Sstevel@tonic-gate (sizeof (char *)))) 32707c478bd9Sstevel@tonic-gate dtype = pcmcia_dev_type[info->pd_type]; 32717c478bd9Sstevel@tonic-gate else 32727c478bd9Sstevel@tonic-gate dtype = "unknown"; 32737c478bd9Sstevel@tonic-gate 32747c478bd9Sstevel@tonic-gate if (strlen(info->pd_vers1_name) > 0) 32757c478bd9Sstevel@tonic-gate (void) ndi_prop_update_string(DDI_DEV_T_NONE, 32767c478bd9Sstevel@tonic-gate dip, PCM_DEV_MODEL, info->pd_vers1_name); 32777c478bd9Sstevel@tonic-gate 32787c478bd9Sstevel@tonic-gate (void) ndi_prop_update_string(DDI_DEV_T_NONE, dip, 32797c478bd9Sstevel@tonic-gate PCM_DEVICETYPE, dtype); 32807c478bd9Sstevel@tonic-gate 32817c478bd9Sstevel@tonic-gate /* set PC Card as active and present in socket */ 32827c478bd9Sstevel@tonic-gate pcmcia_sockets[info->pd_socket]->ls_dip[info->pd_function] = 32835c066ec2SJerry Gilliam dip; 32847c478bd9Sstevel@tonic-gate 32857c478bd9Sstevel@tonic-gate ppd->ppd_active = 1; 32867c478bd9Sstevel@tonic-gate 32877c478bd9Sstevel@tonic-gate /* 32887c478bd9Sstevel@tonic-gate * We should not call ndi_devi_online here if 32897c478bd9Sstevel@tonic-gate * pcmcia attach is in progress. This causes a deadlock. 32907c478bd9Sstevel@tonic-gate */ 32917c478bd9Sstevel@tonic-gate if (pcmcia_dip != dip) { 32927c478bd9Sstevel@tonic-gate if (ndi_devi_online_async(dip, 0) 32937c478bd9Sstevel@tonic-gate != NDI_SUCCESS) { 32947c478bd9Sstevel@tonic-gate pcmcia_sockets[info->pd_socket]->\ 32955c066ec2SJerry Gilliam ls_dip[info->pd_function] = NULL; 32967c478bd9Sstevel@tonic-gate pcmcia_ppd_free(ppd); 32977c478bd9Sstevel@tonic-gate (void) ndi_devi_free(dip); 32987c478bd9Sstevel@tonic-gate return; 32997c478bd9Sstevel@tonic-gate } 33007c478bd9Sstevel@tonic-gate } 33017c478bd9Sstevel@tonic-gate 33027c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 33037c478bd9Sstevel@tonic-gate if (pcmcia_debug) 33047c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "\tjust added \"active\" to %s in %d\n", 33055c066ec2SJerry Gilliam ddi_get_name(dip), info->pd_socket); 33067c478bd9Sstevel@tonic-gate #endif 33077c478bd9Sstevel@tonic-gate } 33087c478bd9Sstevel@tonic-gate 33097c478bd9Sstevel@tonic-gate /* 33107c478bd9Sstevel@tonic-gate * inform the event manager that a child was added 33117c478bd9Sstevel@tonic-gate * to the device tree. 33127c478bd9Sstevel@tonic-gate */ 33137c478bd9Sstevel@tonic-gate pcm_event_manager(PCE_DEV_IDENT, unit, ddi_get_name(dip)); 33147c478bd9Sstevel@tonic-gate 33157c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 33167c478bd9Sstevel@tonic-gate if (pcmcia_debug > 1) { 33177c478bd9Sstevel@tonic-gate pcmcia_dump_minors(dip); 33187c478bd9Sstevel@tonic-gate } 33197c478bd9Sstevel@tonic-gate #endif 33207c478bd9Sstevel@tonic-gate } 33217c478bd9Sstevel@tonic-gate 33227c478bd9Sstevel@tonic-gate /* 33237c478bd9Sstevel@tonic-gate * free any allocated parent-private data 33247c478bd9Sstevel@tonic-gate */ 33257c478bd9Sstevel@tonic-gate static void 33267c478bd9Sstevel@tonic-gate pcmcia_ppd_free(struct pcmcia_parent_private *ppd) 33277c478bd9Sstevel@tonic-gate { 33287c478bd9Sstevel@tonic-gate size_t len; 33297c478bd9Sstevel@tonic-gate 33307c478bd9Sstevel@tonic-gate if (ppd->ppd_nreg != 0) { 33317c478bd9Sstevel@tonic-gate len = ppd->ppd_nreg * sizeof (uint32_t) * 3; 33327c478bd9Sstevel@tonic-gate kmem_free(ppd->ppd_reg, len); 33337c478bd9Sstevel@tonic-gate len = sizeof (struct pcm_regs) * ppd->ppd_nreg; 33347c478bd9Sstevel@tonic-gate kmem_free(ppd->ppd_assigned, len); 33357c478bd9Sstevel@tonic-gate } 33367c478bd9Sstevel@tonic-gate 33377c478bd9Sstevel@tonic-gate /* 33387c478bd9Sstevel@tonic-gate * pcmcia only allocates 1 intrspec today 33397c478bd9Sstevel@tonic-gate */ 33407c478bd9Sstevel@tonic-gate if (ppd->ppd_intr != 0) { 33417c478bd9Sstevel@tonic-gate len = sizeof (struct intrspec) * ppd->ppd_intr; 33427c478bd9Sstevel@tonic-gate kmem_free(ppd->ppd_intrspec, len); 33437c478bd9Sstevel@tonic-gate } 33447c478bd9Sstevel@tonic-gate 33457c478bd9Sstevel@tonic-gate kmem_free(ppd, sizeof (*ppd)); 33467c478bd9Sstevel@tonic-gate } 33477c478bd9Sstevel@tonic-gate 33487c478bd9Sstevel@tonic-gate 33497c478bd9Sstevel@tonic-gate /* 33507c478bd9Sstevel@tonic-gate * pcmcia_get_devinfo(socket) 33517c478bd9Sstevel@tonic-gate * entry point to allow finding the device info structure 33527c478bd9Sstevel@tonic-gate * for a given logical socket. Used by event manager 33537c478bd9Sstevel@tonic-gate */ 33547c478bd9Sstevel@tonic-gate dev_info_t * 33557c478bd9Sstevel@tonic-gate pcmcia_get_devinfo(int socket) 33567c478bd9Sstevel@tonic-gate { 33577c478bd9Sstevel@tonic-gate int func = CS_GET_FUNCTION_NUMBER(socket); 33587c478bd9Sstevel@tonic-gate socket = CS_GET_SOCKET_NUMBER(socket); 33597c478bd9Sstevel@tonic-gate if (pcmcia_sockets[socket]) 33607c478bd9Sstevel@tonic-gate return (pcmcia_sockets[socket]->ls_dip[func]); 33617c478bd9Sstevel@tonic-gate return ((dev_info_t *)NULL); 33627c478bd9Sstevel@tonic-gate } 33637c478bd9Sstevel@tonic-gate 33647c478bd9Sstevel@tonic-gate /* 33657c478bd9Sstevel@tonic-gate * CSGetCookiesAndDip() 33667c478bd9Sstevel@tonic-gate * get info needed by CS to setup soft interrupt handler and provide 33677c478bd9Sstevel@tonic-gate * socket-specific adapter information 33687c478bd9Sstevel@tonic-gate */ 33697c478bd9Sstevel@tonic-gate static int 33707c478bd9Sstevel@tonic-gate GetCookiesAndDip(sservice_t *serv) 33717c478bd9Sstevel@tonic-gate { 33727c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t *socket; 33737c478bd9Sstevel@tonic-gate csss_adapter_info_t *ai; 33747c478bd9Sstevel@tonic-gate int sock; 33757c478bd9Sstevel@tonic-gate 33767c478bd9Sstevel@tonic-gate sock = CS_GET_SOCKET_NUMBER(serv->get_cookies.socket); 33777c478bd9Sstevel@tonic-gate 33787c478bd9Sstevel@tonic-gate if (sock >= pcmcia_num_sockets || 33797c478bd9Sstevel@tonic-gate (int)serv->get_cookies.socket < 0) 33807c478bd9Sstevel@tonic-gate return (BAD_SOCKET); 33817c478bd9Sstevel@tonic-gate 33827c478bd9Sstevel@tonic-gate socket = pcmcia_sockets[sock]; 33837c478bd9Sstevel@tonic-gate ai = &serv->get_cookies.adapter_info; 33847c478bd9Sstevel@tonic-gate serv->get_cookies.dip = socket->ls_adapter->pca_dip; 33857c478bd9Sstevel@tonic-gate serv->get_cookies.iblock = socket->ls_adapter->pca_iblock; 33867c478bd9Sstevel@tonic-gate serv->get_cookies.idevice = socket->ls_adapter->pca_idev; 33877c478bd9Sstevel@tonic-gate 33887c478bd9Sstevel@tonic-gate /* 33897c478bd9Sstevel@tonic-gate * Setup the adapter info for Card Services 33907c478bd9Sstevel@tonic-gate */ 33917c478bd9Sstevel@tonic-gate (void) strcpy(ai->name, socket->ls_adapter->pca_name); 33927c478bd9Sstevel@tonic-gate ai->major = socket->ls_adapter->pca_module; 33937c478bd9Sstevel@tonic-gate ai->minor = socket->ls_adapter->pca_unit; 33947c478bd9Sstevel@tonic-gate ai->number = socket->ls_adapter->pca_number; 33957c478bd9Sstevel@tonic-gate ai->num_sockets = socket->ls_adapter->pca_numsockets; 33967c478bd9Sstevel@tonic-gate ai->first_socket = socket->ls_adapter->pca_first_socket; 33977c478bd9Sstevel@tonic-gate 33987c478bd9Sstevel@tonic-gate return (SUCCESS); 33997c478bd9Sstevel@tonic-gate } 34007c478bd9Sstevel@tonic-gate 34017c478bd9Sstevel@tonic-gate /* 34027c478bd9Sstevel@tonic-gate * Note: 34037c478bd9Sstevel@tonic-gate * The following functions that start with 'SS' 34047c478bd9Sstevel@tonic-gate * implement SocketServices interfaces. They 34057c478bd9Sstevel@tonic-gate * simply map the socket and/or window number to 34067c478bd9Sstevel@tonic-gate * the adapter specific number based on the general 34077c478bd9Sstevel@tonic-gate * value that CardServices uses. 34087c478bd9Sstevel@tonic-gate * 34097c478bd9Sstevel@tonic-gate * See the descriptions in SocketServices for 34107c478bd9Sstevel@tonic-gate * details. Also refer to specific adapter drivers 34117c478bd9Sstevel@tonic-gate * for implementation reference. 34127c478bd9Sstevel@tonic-gate */ 34137c478bd9Sstevel@tonic-gate 34147c478bd9Sstevel@tonic-gate static int 34157c478bd9Sstevel@tonic-gate SSGetAdapter(get_adapter_t *adapter) 34167c478bd9Sstevel@tonic-gate { 34177c478bd9Sstevel@tonic-gate int n; 34187c478bd9Sstevel@tonic-gate get_adapter_t info; 34197c478bd9Sstevel@tonic-gate 34207c478bd9Sstevel@tonic-gate adapter->state = (unsigned)0xFFFFFFFF; 34217c478bd9Sstevel@tonic-gate adapter->SCRouting = 0xFFFFFFFF; 34227c478bd9Sstevel@tonic-gate 34237c478bd9Sstevel@tonic-gate for (n = 0; n < pcmcia_num_adapters; n++) { 34247c478bd9Sstevel@tonic-gate GET_ADAPTER(pcmcia_adapters[n]->pca_if, 34255c066ec2SJerry Gilliam pcmcia_adapters[n]->pca_dip, &info); 34267c478bd9Sstevel@tonic-gate adapter->state &= info.state; 34277c478bd9Sstevel@tonic-gate adapter->SCRouting &= info.SCRouting; 34287c478bd9Sstevel@tonic-gate } 34297c478bd9Sstevel@tonic-gate 34307c478bd9Sstevel@tonic-gate return (SUCCESS); 34317c478bd9Sstevel@tonic-gate } 34327c478bd9Sstevel@tonic-gate 34337c478bd9Sstevel@tonic-gate static int 34347c478bd9Sstevel@tonic-gate SSGetPage(get_page_t *page) 34357c478bd9Sstevel@tonic-gate { 34367c478bd9Sstevel@tonic-gate pcmcia_logical_window_t *window; 34377c478bd9Sstevel@tonic-gate get_page_t newpage; 34387c478bd9Sstevel@tonic-gate int retval, win; 34397c478bd9Sstevel@tonic-gate 34407c478bd9Sstevel@tonic-gate if (page->window > pcmcia_num_windows) { 34417c478bd9Sstevel@tonic-gate return (BAD_WINDOW); 34427c478bd9Sstevel@tonic-gate } 34437c478bd9Sstevel@tonic-gate 34447c478bd9Sstevel@tonic-gate window = pcmcia_windows[page->window]; 34457c478bd9Sstevel@tonic-gate newpage = *page; 34467c478bd9Sstevel@tonic-gate win = newpage.window = window->lw_window; /* real window */ 34477c478bd9Sstevel@tonic-gate 34487c478bd9Sstevel@tonic-gate retval = GET_PAGE(window->lw_if, window->lw_adapter->pca_dip, 34495c066ec2SJerry Gilliam &newpage); 34507c478bd9Sstevel@tonic-gate if (retval == SUCCESS) { 34517c478bd9Sstevel@tonic-gate *page = newpage; 34527c478bd9Sstevel@tonic-gate page->window = win; 34537c478bd9Sstevel@tonic-gate } 34547c478bd9Sstevel@tonic-gate return (retval); 34557c478bd9Sstevel@tonic-gate } 34567c478bd9Sstevel@tonic-gate 34577c478bd9Sstevel@tonic-gate static int 34587c478bd9Sstevel@tonic-gate SSGetSocket(get_socket_t *socket) 34597c478bd9Sstevel@tonic-gate { 34607c478bd9Sstevel@tonic-gate int retval, sock; 34617c478bd9Sstevel@tonic-gate get_socket_t newsocket; 34627c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t *sockp; 34637c478bd9Sstevel@tonic-gate 34647c478bd9Sstevel@tonic-gate sock = socket->socket; 34657c478bd9Sstevel@tonic-gate if (sock > pcmcia_num_sockets || 34665c066ec2SJerry Gilliam (sockp = pcmcia_sockets[sock]) == NULL) { 34677c478bd9Sstevel@tonic-gate return (BAD_SOCKET); 34687c478bd9Sstevel@tonic-gate } 34697c478bd9Sstevel@tonic-gate 34707c478bd9Sstevel@tonic-gate newsocket = *socket; 34717c478bd9Sstevel@tonic-gate newsocket.socket = sockp->ls_socket; 34727c478bd9Sstevel@tonic-gate retval = GET_SOCKET(sockp->ls_if, sockp->ls_adapter->pca_dip, 34737c478bd9Sstevel@tonic-gate &newsocket); 34747c478bd9Sstevel@tonic-gate if (retval == SUCCESS) { 34757c478bd9Sstevel@tonic-gate newsocket.VccLevel = pcmcia_map_power_get(sockp->ls_adapter, 34767c478bd9Sstevel@tonic-gate newsocket.VccLevel, 34777c478bd9Sstevel@tonic-gate VCC); 34787c478bd9Sstevel@tonic-gate newsocket.Vpp1Level = pcmcia_map_power_get(sockp->ls_adapter, 34797c478bd9Sstevel@tonic-gate newsocket.Vpp1Level, 34807c478bd9Sstevel@tonic-gate VPP1); 34817c478bd9Sstevel@tonic-gate newsocket.Vpp2Level = pcmcia_map_power_get(sockp->ls_adapter, 34827c478bd9Sstevel@tonic-gate newsocket.Vpp2Level, 34837c478bd9Sstevel@tonic-gate VPP2); 34847c478bd9Sstevel@tonic-gate *socket = newsocket; 34857c478bd9Sstevel@tonic-gate socket->socket = sock; 34867c478bd9Sstevel@tonic-gate } 34877c478bd9Sstevel@tonic-gate 34887c478bd9Sstevel@tonic-gate return (retval); 34897c478bd9Sstevel@tonic-gate } 34907c478bd9Sstevel@tonic-gate 34917c478bd9Sstevel@tonic-gate static int 34927c478bd9Sstevel@tonic-gate SSGetStatus(get_ss_status_t *status) 34937c478bd9Sstevel@tonic-gate { 34947c478bd9Sstevel@tonic-gate get_ss_status_t newstat; 34957c478bd9Sstevel@tonic-gate int sock, retval; 34967c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t *sockp; 34977c478bd9Sstevel@tonic-gate 34987c478bd9Sstevel@tonic-gate sock = status->socket; 34997c478bd9Sstevel@tonic-gate if (sock > pcmcia_num_sockets || 35005c066ec2SJerry Gilliam (sockp = pcmcia_sockets[sock]) == NULL) { 35017c478bd9Sstevel@tonic-gate return (BAD_SOCKET); 35027c478bd9Sstevel@tonic-gate } 35037c478bd9Sstevel@tonic-gate 35047c478bd9Sstevel@tonic-gate newstat = *status; 35057c478bd9Sstevel@tonic-gate newstat.socket = sockp->ls_socket; 35067c478bd9Sstevel@tonic-gate retval = GET_STATUS(sockp->ls_if, sockp->ls_adapter->pca_dip, 35077c478bd9Sstevel@tonic-gate &newstat); 35087c478bd9Sstevel@tonic-gate if (retval == SUCCESS) { 35097c478bd9Sstevel@tonic-gate *status = newstat; 35107c478bd9Sstevel@tonic-gate status->socket = sock; 35117c478bd9Sstevel@tonic-gate } 35127c478bd9Sstevel@tonic-gate 35137c478bd9Sstevel@tonic-gate return (retval); 35147c478bd9Sstevel@tonic-gate } 35157c478bd9Sstevel@tonic-gate 35167c478bd9Sstevel@tonic-gate static int 35177c478bd9Sstevel@tonic-gate SSGetWindow(get_window_t *window) 35187c478bd9Sstevel@tonic-gate { 35197c478bd9Sstevel@tonic-gate int win, retval; 35207c478bd9Sstevel@tonic-gate get_window_t newwin; 35217c478bd9Sstevel@tonic-gate pcmcia_logical_window_t *winp; 35227c478bd9Sstevel@tonic-gate 35237c478bd9Sstevel@tonic-gate win = window->window; 35247c478bd9Sstevel@tonic-gate winp = pcmcia_windows[win]; 35257c478bd9Sstevel@tonic-gate newwin = *window; 35267c478bd9Sstevel@tonic-gate newwin.window = winp->lw_window; 35277c478bd9Sstevel@tonic-gate 35287c478bd9Sstevel@tonic-gate retval = GET_WINDOW(winp->lw_if, winp->lw_adapter->pca_dip, 35297c478bd9Sstevel@tonic-gate &newwin); 35307c478bd9Sstevel@tonic-gate if (retval == SUCCESS) { 35317c478bd9Sstevel@tonic-gate newwin.socket = winp->lw_socket; 35327c478bd9Sstevel@tonic-gate newwin.window = win; 35337c478bd9Sstevel@tonic-gate *window = newwin; 35347c478bd9Sstevel@tonic-gate } 35357c478bd9Sstevel@tonic-gate return (retval); 35367c478bd9Sstevel@tonic-gate } 35377c478bd9Sstevel@tonic-gate 35387c478bd9Sstevel@tonic-gate /* 35397c478bd9Sstevel@tonic-gate * SSInquireAdapter() 35407c478bd9Sstevel@tonic-gate * Get the capabilities of the "generic" adapter 35417c478bd9Sstevel@tonic-gate * we are exporting to CS. 35427c478bd9Sstevel@tonic-gate */ 35437c478bd9Sstevel@tonic-gate static int 35447c478bd9Sstevel@tonic-gate SSInquireAdapter(inquire_adapter_t *adapter) 35457c478bd9Sstevel@tonic-gate { 35467c478bd9Sstevel@tonic-gate adapter->NumSockets = pcmcia_num_sockets; 35477c478bd9Sstevel@tonic-gate adapter->NumWindows = pcmcia_num_windows; 35487c478bd9Sstevel@tonic-gate adapter->NumEDCs = 0; 35497c478bd9Sstevel@tonic-gate /* 35507c478bd9Sstevel@tonic-gate * notes: Adapter Capabilities are going to be difficult to 35517c478bd9Sstevel@tonic-gate * determine with reliability. Fortunately, most of them 35527c478bd9Sstevel@tonic-gate * don't matter under Solaris or can be handled transparently 35537c478bd9Sstevel@tonic-gate */ 35547c478bd9Sstevel@tonic-gate adapter->AdpCaps = 0; /* need to fix these */ 35557c478bd9Sstevel@tonic-gate /* 35567c478bd9Sstevel@tonic-gate * interrupts need a little work. For x86, the valid IRQs will 35577c478bd9Sstevel@tonic-gate * be restricted to those that the system has exported to the nexus. 35587c478bd9Sstevel@tonic-gate * for SPARC, it will be the DoRight values. 35597c478bd9Sstevel@tonic-gate */ 35607c478bd9Sstevel@tonic-gate adapter->ActiveHigh = 0; 35617c478bd9Sstevel@tonic-gate adapter->ActiveLow = 0; 35627c478bd9Sstevel@tonic-gate adapter->power_entry = pcmcia_power_table; /* until we resolve this */ 35637c478bd9Sstevel@tonic-gate adapter->NumPower = pcmcia_num_power; 35647c478bd9Sstevel@tonic-gate return (SUCCESS); 35657c478bd9Sstevel@tonic-gate } 35667c478bd9Sstevel@tonic-gate 35677c478bd9Sstevel@tonic-gate static int 35687c478bd9Sstevel@tonic-gate SSInquireSocket(inquire_socket_t *socket) 35697c478bd9Sstevel@tonic-gate { 35707c478bd9Sstevel@tonic-gate int retval, sock; 35717c478bd9Sstevel@tonic-gate inquire_socket_t newsocket; 35727c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t *sockp; 35737c478bd9Sstevel@tonic-gate 35747c478bd9Sstevel@tonic-gate sock = socket->socket; 35757c478bd9Sstevel@tonic-gate if (sock > pcmcia_num_sockets || 35765c066ec2SJerry Gilliam (sockp = pcmcia_sockets[sock]) == NULL) 35777c478bd9Sstevel@tonic-gate return (BAD_SOCKET); 35787c478bd9Sstevel@tonic-gate newsocket = *socket; 35797c478bd9Sstevel@tonic-gate newsocket.socket = sockp->ls_socket; 35807c478bd9Sstevel@tonic-gate retval = INQUIRE_SOCKET(sockp->ls_if, sockp->ls_adapter->pca_dip, 35817c478bd9Sstevel@tonic-gate &newsocket); 35827c478bd9Sstevel@tonic-gate if (retval == SUCCESS) { 35837c478bd9Sstevel@tonic-gate *socket = newsocket; 35847c478bd9Sstevel@tonic-gate socket->socket = sock; 35857c478bd9Sstevel@tonic-gate } 35867c478bd9Sstevel@tonic-gate return (retval); 35877c478bd9Sstevel@tonic-gate } 35887c478bd9Sstevel@tonic-gate 35897c478bd9Sstevel@tonic-gate static int 35907c478bd9Sstevel@tonic-gate SSInquireWindow(inquire_window_t *window) 35917c478bd9Sstevel@tonic-gate { 35927c478bd9Sstevel@tonic-gate int retval, win; 35937c478bd9Sstevel@tonic-gate pcmcia_logical_window_t *winp; 35947c478bd9Sstevel@tonic-gate inquire_window_t newwin; 35957c478bd9Sstevel@tonic-gate int slide; 35967c478bd9Sstevel@tonic-gate 35977c478bd9Sstevel@tonic-gate win = window->window; 35987c478bd9Sstevel@tonic-gate if (win > pcmcia_num_windows) 35997c478bd9Sstevel@tonic-gate return (BAD_WINDOW); 36007c478bd9Sstevel@tonic-gate 36017c478bd9Sstevel@tonic-gate winp = pcmcia_windows[win]; 36027c478bd9Sstevel@tonic-gate newwin = *window; 36037c478bd9Sstevel@tonic-gate newwin.window = winp->lw_window; 36047c478bd9Sstevel@tonic-gate retval = INQUIRE_WINDOW(winp->lw_if, winp->lw_adapter->pca_dip, 36057c478bd9Sstevel@tonic-gate &newwin); 36067c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 36077c478bd9Sstevel@tonic-gate if (pcmcia_debug > 1) 36087c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "SSInquireWindow: win=%d, pwin=%d\n", 36095c066ec2SJerry Gilliam win, newwin.window); 36107c478bd9Sstevel@tonic-gate #endif 36117c478bd9Sstevel@tonic-gate if (retval == SUCCESS) { 36127c478bd9Sstevel@tonic-gate *window = newwin; 36137c478bd9Sstevel@tonic-gate /* just in case */ 36147c478bd9Sstevel@tonic-gate window->iowin_char.IOWndCaps &= ~WC_BASE; 36157c478bd9Sstevel@tonic-gate slide = winp->lw_adapter->pca_first_socket; 36167c478bd9Sstevel@tonic-gate /* 36177c478bd9Sstevel@tonic-gate * note that sockets are relative to the adapter. 36187c478bd9Sstevel@tonic-gate * we have to adjust the bits to show a logical 36197c478bd9Sstevel@tonic-gate * version. 36207c478bd9Sstevel@tonic-gate */ 36217c478bd9Sstevel@tonic-gate 36227c478bd9Sstevel@tonic-gate pcm_fix_bits(newwin.Sockets, window->Sockets, slide, 0); 36237c478bd9Sstevel@tonic-gate 36247c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 36257c478bd9Sstevel@tonic-gate if (pcmcia_debug > 1) { 36267c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "iw: orig bits=%x, new bits=%x\n", 36275c066ec2SJerry Gilliam (int)*(uint32_t *)newwin.Sockets, 36285c066ec2SJerry Gilliam (int)*(uint32_t *)window->Sockets); 36297c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "\t%x.%x.%x\n", window->WndCaps, 36305c066ec2SJerry Gilliam window->mem_win_char.MemWndCaps, 36315c066ec2SJerry Gilliam window->mem_win_char.MinSize); 36327c478bd9Sstevel@tonic-gate } 36337c478bd9Sstevel@tonic-gate #endif 36347c478bd9Sstevel@tonic-gate window->window = win; 36357c478bd9Sstevel@tonic-gate } 36367c478bd9Sstevel@tonic-gate return (retval); 36377c478bd9Sstevel@tonic-gate } 36387c478bd9Sstevel@tonic-gate 36397c478bd9Sstevel@tonic-gate static int 36407c478bd9Sstevel@tonic-gate SSResetSocket(int socket, int mode) 36417c478bd9Sstevel@tonic-gate { 36427c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t *sockp; 36437c478bd9Sstevel@tonic-gate 36447c478bd9Sstevel@tonic-gate if (socket >= pcmcia_num_sockets || 36455c066ec2SJerry Gilliam (sockp = pcmcia_sockets[socket]) == NULL) 36467c478bd9Sstevel@tonic-gate return (BAD_SOCKET); 36477c478bd9Sstevel@tonic-gate 36487c478bd9Sstevel@tonic-gate return (RESET_SOCKET(sockp->ls_if, sockp->ls_adapter->pca_dip, 36497c478bd9Sstevel@tonic-gate sockp->ls_socket, mode)); 36507c478bd9Sstevel@tonic-gate } 36517c478bd9Sstevel@tonic-gate 36527c478bd9Sstevel@tonic-gate static int 36537c478bd9Sstevel@tonic-gate SSSetPage(set_page_t *page) 36547c478bd9Sstevel@tonic-gate { 36557c478bd9Sstevel@tonic-gate int window, retval; 36567c478bd9Sstevel@tonic-gate set_page_t newpage; 36577c478bd9Sstevel@tonic-gate pcmcia_logical_window_t *winp; 36587c478bd9Sstevel@tonic-gate 36597c478bd9Sstevel@tonic-gate window = page->window; 36607c478bd9Sstevel@tonic-gate if (window > pcmcia_num_windows) { 36617c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 36627c478bd9Sstevel@tonic-gate if (pcmcia_debug > 1) 36637c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "SSSetPage: window=%d (of %d)\n", 36645c066ec2SJerry Gilliam window, pcmcia_num_windows); 36657c478bd9Sstevel@tonic-gate #endif 36667c478bd9Sstevel@tonic-gate return (BAD_WINDOW); 36677c478bd9Sstevel@tonic-gate } 36687c478bd9Sstevel@tonic-gate 36697c478bd9Sstevel@tonic-gate winp = pcmcia_windows[window]; 36707c478bd9Sstevel@tonic-gate newpage = *page; 36717c478bd9Sstevel@tonic-gate newpage.window = winp->lw_window; 36727c478bd9Sstevel@tonic-gate retval = SET_PAGE(winp->lw_if, winp->lw_adapter->pca_dip, &newpage); 36737c478bd9Sstevel@tonic-gate if (retval == SUCCESS) { 36747c478bd9Sstevel@tonic-gate newpage.window = window; 36757c478bd9Sstevel@tonic-gate *page = newpage; 36767c478bd9Sstevel@tonic-gate } 36777c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 36787c478bd9Sstevel@tonic-gate if ((pcmcia_debug > 1) && retval != SUCCESS) 36797c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "\tSetPage: returning error %x\n", retval); 36807c478bd9Sstevel@tonic-gate #endif 36817c478bd9Sstevel@tonic-gate return (retval); 36827c478bd9Sstevel@tonic-gate } 36837c478bd9Sstevel@tonic-gate 36847c478bd9Sstevel@tonic-gate static int 36857c478bd9Sstevel@tonic-gate SSSetWindow(set_window_t *win) 36867c478bd9Sstevel@tonic-gate { 36877c478bd9Sstevel@tonic-gate int socket, window, retval, func; 36887c478bd9Sstevel@tonic-gate set_window_t newwin; 36897c478bd9Sstevel@tonic-gate pcmcia_logical_window_t *winp; 36907c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t *sockp; 36917c478bd9Sstevel@tonic-gate 36927c478bd9Sstevel@tonic-gate window = win->window; 36937c478bd9Sstevel@tonic-gate if (window > pcmcia_num_windows) 36947c478bd9Sstevel@tonic-gate return (BAD_WINDOW); 36957c478bd9Sstevel@tonic-gate 36967c478bd9Sstevel@tonic-gate socket = CS_GET_SOCKET_NUMBER(win->socket); 36977c478bd9Sstevel@tonic-gate func = CS_GET_FUNCTION_NUMBER(win->socket); 36987c478bd9Sstevel@tonic-gate 36997c478bd9Sstevel@tonic-gate if (socket > pcmcia_num_sockets || 37005c066ec2SJerry Gilliam (sockp = pcmcia_sockets[socket]) == NULL) { 37017c478bd9Sstevel@tonic-gate return (BAD_SOCKET); 37027c478bd9Sstevel@tonic-gate } 37037c478bd9Sstevel@tonic-gate 37047c478bd9Sstevel@tonic-gate winp = pcmcia_windows[window]; 37057c478bd9Sstevel@tonic-gate winp->lw_socket = win->socket; /* reverse map */ 37067c478bd9Sstevel@tonic-gate newwin = *win; 37077c478bd9Sstevel@tonic-gate newwin.window = winp->lw_window; 37087c478bd9Sstevel@tonic-gate newwin.socket = sockp->ls_socket; 37097c478bd9Sstevel@tonic-gate newwin.child = sockp->ls_dip[func]; /* so we carry the dip around */ 37107c478bd9Sstevel@tonic-gate 37117c478bd9Sstevel@tonic-gate retval = SET_WINDOW(winp->lw_if, winp->lw_adapter->pca_dip, &newwin); 37127c478bd9Sstevel@tonic-gate if (retval == SUCCESS) { 37137c478bd9Sstevel@tonic-gate newwin.window = window; 37147c478bd9Sstevel@tonic-gate newwin.socket = winp->lw_socket; 37157c478bd9Sstevel@tonic-gate *win = newwin; 37167c478bd9Sstevel@tonic-gate } 37177c478bd9Sstevel@tonic-gate return (retval); 37187c478bd9Sstevel@tonic-gate } 37197c478bd9Sstevel@tonic-gate 37207c478bd9Sstevel@tonic-gate static int 37217c478bd9Sstevel@tonic-gate SSSetSocket(set_socket_t *socket) 37227c478bd9Sstevel@tonic-gate { 37237c478bd9Sstevel@tonic-gate int sock, retval; 37247c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t *sockp; 37257c478bd9Sstevel@tonic-gate set_socket_t newsock; 37267c478bd9Sstevel@tonic-gate 37277c478bd9Sstevel@tonic-gate sock = socket->socket; 37287c478bd9Sstevel@tonic-gate if (sock > pcmcia_num_sockets || 37295c066ec2SJerry Gilliam (sockp = pcmcia_sockets[sock]) == NULL) { 37307c478bd9Sstevel@tonic-gate return (BAD_SOCKET); 37317c478bd9Sstevel@tonic-gate } 37327c478bd9Sstevel@tonic-gate 37337c478bd9Sstevel@tonic-gate newsock = *socket; 37347c478bd9Sstevel@tonic-gate /* note: we force CS to always get insert/removal events */ 37357c478bd9Sstevel@tonic-gate sockp->ls_cs_events = pcm_mapevents(newsock.SCIntMask) | 37365c066ec2SJerry Gilliam PCE_E2M(PCE_CARD_INSERT) | PCE_E2M(PCE_CARD_REMOVAL); 37377c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 37387c478bd9Sstevel@tonic-gate if (pcmcia_debug > 1) 37397c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 37405c066ec2SJerry Gilliam "SetSocket: SCIntMask = %x\n", newsock.SCIntMask); 37417c478bd9Sstevel@tonic-gate #endif 37427c478bd9Sstevel@tonic-gate newsock.socket = sockp->ls_socket; 37437c478bd9Sstevel@tonic-gate newsock.VccLevel = pcmcia_map_power_set(sockp->ls_adapter, 37447c478bd9Sstevel@tonic-gate newsock.VccLevel, VCC); 37457c478bd9Sstevel@tonic-gate newsock.Vpp1Level = pcmcia_map_power_set(sockp->ls_adapter, 37467c478bd9Sstevel@tonic-gate newsock.Vpp1Level, VPP1); 37477c478bd9Sstevel@tonic-gate newsock.Vpp2Level = pcmcia_map_power_set(sockp->ls_adapter, 37487c478bd9Sstevel@tonic-gate newsock.Vpp2Level, VPP2); 37497c478bd9Sstevel@tonic-gate retval = SET_SOCKET(sockp->ls_if, sockp->ls_adapter->pca_dip, 37507c478bd9Sstevel@tonic-gate &newsock); 37517c478bd9Sstevel@tonic-gate if (retval == SUCCESS) { 37527c478bd9Sstevel@tonic-gate newsock.socket = sock; 37537c478bd9Sstevel@tonic-gate newsock.VccLevel = pcmcia_map_power_get(sockp->ls_adapter, 37547c478bd9Sstevel@tonic-gate newsock.VccLevel, 37557c478bd9Sstevel@tonic-gate VCC); 37567c478bd9Sstevel@tonic-gate newsock.Vpp1Level = pcmcia_map_power_get(sockp->ls_adapter, 37577c478bd9Sstevel@tonic-gate newsock.Vpp1Level, 37587c478bd9Sstevel@tonic-gate VPP1); 37597c478bd9Sstevel@tonic-gate newsock.Vpp2Level = pcmcia_map_power_get(sockp->ls_adapter, 37607c478bd9Sstevel@tonic-gate newsock.Vpp2Level, 37617c478bd9Sstevel@tonic-gate VPP2); 37627c478bd9Sstevel@tonic-gate *socket = newsock; 37637c478bd9Sstevel@tonic-gate if (socket->IREQRouting & IRQ_ENABLE) { 37647c478bd9Sstevel@tonic-gate sockp->ls_flags |= PCS_IRQ_ENABLED; 37657c478bd9Sstevel@tonic-gate } else { 37667c478bd9Sstevel@tonic-gate sockp->ls_flags &= ~PCS_IRQ_ENABLED; 37677c478bd9Sstevel@tonic-gate } 37687c478bd9Sstevel@tonic-gate } 37697c478bd9Sstevel@tonic-gate return (retval); 37707c478bd9Sstevel@tonic-gate } 37717c478bd9Sstevel@tonic-gate 37727c478bd9Sstevel@tonic-gate /* 37737c478bd9Sstevel@tonic-gate * SSSetIRQHandler() 37747c478bd9Sstevel@tonic-gate * arrange for IRQ to be allocated if appropriate and always 37757c478bd9Sstevel@tonic-gate * arrange that PC Card interrupt handlers get called. 37767c478bd9Sstevel@tonic-gate */ 37777c478bd9Sstevel@tonic-gate static int 37787c478bd9Sstevel@tonic-gate SSSetIRQHandler(set_irq_handler_t *handler) 37797c478bd9Sstevel@tonic-gate { 37807c478bd9Sstevel@tonic-gate int sock, retval, func; 37817c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t *sockp; 37827c478bd9Sstevel@tonic-gate struct pcmcia_parent_private *ppd; 37837c478bd9Sstevel@tonic-gate dev_info_t *dip; 37847c478bd9Sstevel@tonic-gate ddi_iblock_cookie_t iblk; 37857c478bd9Sstevel@tonic-gate ddi_idevice_cookie_t idev; 37867c478bd9Sstevel@tonic-gate 37877c478bd9Sstevel@tonic-gate sock = CS_GET_SOCKET_NUMBER(handler->socket); 37887c478bd9Sstevel@tonic-gate func = CS_GET_FUNCTION_NUMBER(handler->socket); 37897c478bd9Sstevel@tonic-gate if (sock > pcmcia_num_sockets || 37905c066ec2SJerry Gilliam (sockp = pcmcia_sockets[sock]) == NULL) { 37917c478bd9Sstevel@tonic-gate return (BAD_SOCKET); 37927c478bd9Sstevel@tonic-gate } 37937c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 37947c478bd9Sstevel@tonic-gate if (pcmcia_debug) { 37957c478bd9Sstevel@tonic-gate 37967c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "SSSetIRQHandler: socket=%x, function=%x\n", 37975c066ec2SJerry Gilliam sock, func); 37987c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "\thandler(%p): socket=%x, irq=%x, id=%x\n", 37995c066ec2SJerry Gilliam (void *)handler->handler, handler->socket, handler->irq, 38005c066ec2SJerry Gilliam handler->handler_id); 38017c478bd9Sstevel@tonic-gate } 38027c478bd9Sstevel@tonic-gate #endif 38037c478bd9Sstevel@tonic-gate dip = sockp->ls_dip[func]; 38047c478bd9Sstevel@tonic-gate 38057c478bd9Sstevel@tonic-gate ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(dip); 38067c478bd9Sstevel@tonic-gate 38077c478bd9Sstevel@tonic-gate handler->iblk_cookie = &iblk; 38087c478bd9Sstevel@tonic-gate handler->idev_cookie = &idev; 38097c478bd9Sstevel@tonic-gate 38107c478bd9Sstevel@tonic-gate retval = ddi_add_intr(dip, 0, handler->iblk_cookie, 38117c478bd9Sstevel@tonic-gate handler->idev_cookie, 38127c478bd9Sstevel@tonic-gate (uint32_t(*)(caddr_t)) handler->handler, 38137c478bd9Sstevel@tonic-gate handler->arg1); 38147c478bd9Sstevel@tonic-gate 38157c478bd9Sstevel@tonic-gate if (retval == DDI_SUCCESS) { 38167c478bd9Sstevel@tonic-gate handler->iblk_cookie = &sockp->ls_iblk; 38177c478bd9Sstevel@tonic-gate handler->idev_cookie = &sockp->ls_idev; 38187c478bd9Sstevel@tonic-gate handler->irq = ppd->ppd_intrspec->intrspec_vec; 38197c478bd9Sstevel@tonic-gate retval = SUCCESS; 38207c478bd9Sstevel@tonic-gate } else { 38217c478bd9Sstevel@tonic-gate retval = sockp->ls_error; 38227c478bd9Sstevel@tonic-gate } 38237c478bd9Sstevel@tonic-gate return (retval); 38247c478bd9Sstevel@tonic-gate } 38257c478bd9Sstevel@tonic-gate 38267c478bd9Sstevel@tonic-gate /* 38277c478bd9Sstevel@tonic-gate * SSClearIRQHandler() 38287c478bd9Sstevel@tonic-gate * Arrange to have the interrupt handler specified removed 38297c478bd9Sstevel@tonic-gate * from the interrupt list. 38307c478bd9Sstevel@tonic-gate */ 38317c478bd9Sstevel@tonic-gate static int 38327c478bd9Sstevel@tonic-gate SSClearIRQHandler(clear_irq_handler_t *handler) 38337c478bd9Sstevel@tonic-gate { 38347c478bd9Sstevel@tonic-gate int sock, func; 38357c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t *sockp; 38367c478bd9Sstevel@tonic-gate dev_info_t *dip; 38377c478bd9Sstevel@tonic-gate 38387c478bd9Sstevel@tonic-gate sock = CS_GET_SOCKET_NUMBER(handler->socket); 38397c478bd9Sstevel@tonic-gate func = CS_GET_FUNCTION_NUMBER(handler->socket); 38407c478bd9Sstevel@tonic-gate 38417c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 38427c478bd9Sstevel@tonic-gate if (pcmcia_debug) { 38437c478bd9Sstevel@tonic-gate 38447c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 38455c066ec2SJerry Gilliam "SSClearIRQHandler: socket=%x, function=%x\n", 38465c066ec2SJerry Gilliam sock, func); 38477c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 38485c066ec2SJerry Gilliam "\thandler(%p): socket=%x, id=%x\n", 38495c066ec2SJerry Gilliam (void *)handler, handler->socket, 38505c066ec2SJerry Gilliam handler->handler_id); 38517c478bd9Sstevel@tonic-gate } 38527c478bd9Sstevel@tonic-gate #endif 38537c478bd9Sstevel@tonic-gate 38547c478bd9Sstevel@tonic-gate if (sock > pcmcia_num_sockets || 38555c066ec2SJerry Gilliam (sockp = pcmcia_sockets[sock]) == NULL) { 38567c478bd9Sstevel@tonic-gate return (BAD_SOCKET); 38577c478bd9Sstevel@tonic-gate } 38587c478bd9Sstevel@tonic-gate dip = sockp->ls_dip[func]; 38597c478bd9Sstevel@tonic-gate if (dip) { 38607c478bd9Sstevel@tonic-gate ddi_remove_intr(dip, 0, NULL); 38617c478bd9Sstevel@tonic-gate return (SUCCESS); 38627c478bd9Sstevel@tonic-gate } 38637c478bd9Sstevel@tonic-gate return (BAD_SOCKET); 38647c478bd9Sstevel@tonic-gate } 38657c478bd9Sstevel@tonic-gate 38667c478bd9Sstevel@tonic-gate 38677c478bd9Sstevel@tonic-gate /* 38687c478bd9Sstevel@tonic-gate * pcm_pathname() 38697c478bd9Sstevel@tonic-gate * make a partial path from dip. 38707c478bd9Sstevel@tonic-gate * used to mknods relative to /devices/pcmcia/ 38717c478bd9Sstevel@tonic-gate * 38727c478bd9Sstevel@tonic-gate * XXX - we now use ddi_get_name_addr to get the "address" portion 38737c478bd9Sstevel@tonic-gate * of the name; that way, we only have to modify the name creation 38747c478bd9Sstevel@tonic-gate * algorithm in one place 38757c478bd9Sstevel@tonic-gate */ 38767c478bd9Sstevel@tonic-gate static void 38777c478bd9Sstevel@tonic-gate pcm_pathname(dev_info_t *dip, char *name, char *path) 38787c478bd9Sstevel@tonic-gate { 38797c478bd9Sstevel@tonic-gate (void) sprintf(path, "%s@%s:%s", ddi_node_name(dip), 38807c478bd9Sstevel@tonic-gate ddi_get_name_addr(dip), name); 38817c478bd9Sstevel@tonic-gate } 38827c478bd9Sstevel@tonic-gate 38837c478bd9Sstevel@tonic-gate /* 38847c478bd9Sstevel@tonic-gate * pcmcia_create_device() 38857c478bd9Sstevel@tonic-gate * create the /devices entries for the driver 38867c478bd9Sstevel@tonic-gate * it is assumed that the PC Card driver will do a 38877c478bd9Sstevel@tonic-gate * RegisterClient for each subdevice. 38887c478bd9Sstevel@tonic-gate * The device type string is encoded here to match 38897c478bd9Sstevel@tonic-gate * the standardized names when possible. 38907c478bd9Sstevel@tonic-gate * XXX - note that we may need to provide a way for the 38917c478bd9Sstevel@tonic-gate * caller to specify the complete name string that 38927c478bd9Sstevel@tonic-gate * we pass to ddi_set_name_addr 38937c478bd9Sstevel@tonic-gate */ 38947c478bd9Sstevel@tonic-gate static int 38957c478bd9Sstevel@tonic-gate pcmcia_create_device(ss_make_device_node_t *init) 38967c478bd9Sstevel@tonic-gate { 38977c478bd9Sstevel@tonic-gate int err = SUCCESS; 38987c478bd9Sstevel@tonic-gate struct pcm_make_dev device; 38997c478bd9Sstevel@tonic-gate struct dev_ops *ops; 39007c478bd9Sstevel@tonic-gate major_t major; 39017c478bd9Sstevel@tonic-gate 39027c478bd9Sstevel@tonic-gate /* 39037c478bd9Sstevel@tonic-gate * Now that we have the name, create it. 39047c478bd9Sstevel@tonic-gate */ 39057c478bd9Sstevel@tonic-gate 39067c478bd9Sstevel@tonic-gate bzero(&device, sizeof (device)); 39077c478bd9Sstevel@tonic-gate if (init->flags & SS_CSINITDEV_CREATE_DEVICE) { 39087c478bd9Sstevel@tonic-gate if ((err = ddi_create_minor_node(init->dip, 39097c478bd9Sstevel@tonic-gate init->name, 39107c478bd9Sstevel@tonic-gate init->spec_type, 39117c478bd9Sstevel@tonic-gate init->minor_num, 39127c478bd9Sstevel@tonic-gate init->node_type, 39137c478bd9Sstevel@tonic-gate 0)) != DDI_SUCCESS) { 39147c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 39157c478bd9Sstevel@tonic-gate if (pcmcia_debug) 39167c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 39175c066ec2SJerry Gilliam "pcmcia_create_device: failed " 39185c066ec2SJerry Gilliam "create\n"); 39197c478bd9Sstevel@tonic-gate #endif 39207c478bd9Sstevel@tonic-gate return (BAD_ATTRIBUTE); 39217c478bd9Sstevel@tonic-gate } 39227c478bd9Sstevel@tonic-gate 39235c066ec2SJerry Gilliam major = ddi_driver_major(init->dip); 39247c478bd9Sstevel@tonic-gate ops = ddi_get_driver(init->dip); 39257c478bd9Sstevel@tonic-gate LOCK_DEV_OPS(&devnamesp[major].dn_lock); 39267c478bd9Sstevel@tonic-gate INCR_DEV_OPS_REF(ops); 39277c478bd9Sstevel@tonic-gate (void) ddi_pathname(init->dip, device.path); 39287c478bd9Sstevel@tonic-gate DECR_DEV_OPS_REF(ops); 39297c478bd9Sstevel@tonic-gate UNLOCK_DEV_OPS(&devnamesp[major].dn_lock); 39307c478bd9Sstevel@tonic-gate (void) sprintf(device.path + strlen(device.path), ":%s", 39317c478bd9Sstevel@tonic-gate init->name); 39327c478bd9Sstevel@tonic-gate 39337c478bd9Sstevel@tonic-gate (void) strcpy(device.driver, ddi_binding_name(init->dip)); 39347c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 39357c478bd9Sstevel@tonic-gate if (pcmcia_debug) 39367c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 39375c066ec2SJerry Gilliam "pcmcia_create_device: created %s " 39385c066ec2SJerry Gilliam "from %s [%s]\n", 39395c066ec2SJerry Gilliam device.path, init->name, device.driver); 39407c478bd9Sstevel@tonic-gate #endif 39417c478bd9Sstevel@tonic-gate device.dev = 39425c066ec2SJerry Gilliam makedevice(ddi_driver_major(init->dip), init->minor_num); 39437c478bd9Sstevel@tonic-gate device.flags |= (init->flags & SS_CSINITDEV_MORE_DEVICES) ? 39447c478bd9Sstevel@tonic-gate PCM_EVENT_MORE : 0; 39457c478bd9Sstevel@tonic-gate device.type = init->spec_type; 39467c478bd9Sstevel@tonic-gate device.op = SS_CSINITDEV_CREATE_DEVICE; 39477c478bd9Sstevel@tonic-gate device.socket = ddi_getprop(DDI_DEV_T_ANY, init->dip, 39487c478bd9Sstevel@tonic-gate DDI_PROP_CANSLEEP, PCM_DEV_SOCKET, 39497c478bd9Sstevel@tonic-gate -1); 39507c478bd9Sstevel@tonic-gate } else if (init->flags & SS_CSINITDEV_REMOVE_DEVICE) { 39517c478bd9Sstevel@tonic-gate device.op = SS_CSINITDEV_REMOVE_DEVICE; 39527c478bd9Sstevel@tonic-gate device.socket = ddi_getprop(DDI_DEV_T_ANY, init->dip, 39537c478bd9Sstevel@tonic-gate DDI_PROP_CANSLEEP, PCM_DEV_SOCKET, 39547c478bd9Sstevel@tonic-gate -1); 39557c478bd9Sstevel@tonic-gate if (init->name != NULL) 39567c478bd9Sstevel@tonic-gate (void) strcpy(device.path, init->name); 39575c066ec2SJerry Gilliam device.dev = makedevice(ddi_driver_major(init->dip), 0); 39587c478bd9Sstevel@tonic-gate ddi_remove_minor_node(init->dip, init->name); 39597c478bd9Sstevel@tonic-gate } 39607c478bd9Sstevel@tonic-gate 39617c478bd9Sstevel@tonic-gate /* 39627c478bd9Sstevel@tonic-gate * we send an event for ALL devices created. 39637c478bd9Sstevel@tonic-gate * To do otherwise ties us to using drvconfig 39647c478bd9Sstevel@tonic-gate * forever. There are relatively few devices 39657c478bd9Sstevel@tonic-gate * ever created so no need to do otherwise. 39667c478bd9Sstevel@tonic-gate * The existence of the event manager must never 39677c478bd9Sstevel@tonic-gate * be visible to a PCMCIA device driver. 39687c478bd9Sstevel@tonic-gate */ 39697c478bd9Sstevel@tonic-gate pcm_event_manager(PCE_INIT_DEV, device.socket, &device); 39707c478bd9Sstevel@tonic-gate 39717c478bd9Sstevel@tonic-gate return (err); 39727c478bd9Sstevel@tonic-gate } 39737c478bd9Sstevel@tonic-gate 39747c478bd9Sstevel@tonic-gate /* 39757c478bd9Sstevel@tonic-gate * pcmcia_get_minors() 39767c478bd9Sstevel@tonic-gate * We need to traverse the minor node list of the 39777c478bd9Sstevel@tonic-gate * dip if there are any. This takes two passes; 39787c478bd9Sstevel@tonic-gate * one to get the count and buffer size and the 39797c478bd9Sstevel@tonic-gate * other to actually copy the data into the buffer. 39807c478bd9Sstevel@tonic-gate * The framework requires that the dip be locked 39817c478bd9Sstevel@tonic-gate * during this time to avoid breakage as well as the 39827c478bd9Sstevel@tonic-gate * driver being locked. 39837c478bd9Sstevel@tonic-gate */ 39847c478bd9Sstevel@tonic-gate int 39857c478bd9Sstevel@tonic-gate pcmcia_get_minors(dev_info_t *dip, struct pcm_make_dev **minors) 39867c478bd9Sstevel@tonic-gate { 3987b9ccdc5aScth int circ; 39887c478bd9Sstevel@tonic-gate int count = 0; 39897c478bd9Sstevel@tonic-gate struct ddi_minor_data *dp; 39907c478bd9Sstevel@tonic-gate struct pcm_make_dev *md; 39917c478bd9Sstevel@tonic-gate int socket; 39927c478bd9Sstevel@tonic-gate major_t major; 39937c478bd9Sstevel@tonic-gate struct dev_ops *ops; 39947c478bd9Sstevel@tonic-gate 39957c478bd9Sstevel@tonic-gate socket = ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 39967c478bd9Sstevel@tonic-gate PCM_DEV_SOCKET, -1); 3997b9ccdc5aScth ndi_devi_enter(dip, &circ); 39987c478bd9Sstevel@tonic-gate if (DEVI(dip)->devi_minor != (struct ddi_minor_data *)NULL) { 39997c478bd9Sstevel@tonic-gate for (dp = DEVI(dip)->devi_minor; 40005c066ec2SJerry Gilliam dp != (struct ddi_minor_data *)NULL; 40015c066ec2SJerry Gilliam dp = dp->next) { 40027c478bd9Sstevel@tonic-gate count++; /* have one more */ 40037c478bd9Sstevel@tonic-gate } 40047c478bd9Sstevel@tonic-gate /* we now know how many nodes to allocate */ 40057c478bd9Sstevel@tonic-gate md = kmem_zalloc(count * sizeof (struct pcm_make_dev), 40067c478bd9Sstevel@tonic-gate KM_NOSLEEP); 40077c478bd9Sstevel@tonic-gate if (md != NULL) { 40087c478bd9Sstevel@tonic-gate *minors = md; 40097c478bd9Sstevel@tonic-gate for (dp = DEVI(dip)->devi_minor; 40105c066ec2SJerry Gilliam dp != (struct ddi_minor_data *)NULL; 40115c066ec2SJerry Gilliam dp = dp->next, md++) { 40127c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 40137c478bd9Sstevel@tonic-gate if (pcmcia_debug > 1) { 40147c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 40155c066ec2SJerry Gilliam "pcmcia_get_minors: name=%s," 40165c066ec2SJerry Gilliam "socket=%d, stype=%x, " 40175c066ec2SJerry Gilliam "ntype=%s, dev_t=%x", 40185c066ec2SJerry Gilliam dp->ddm_name, 40195c066ec2SJerry Gilliam socket, 40205c066ec2SJerry Gilliam dp->ddm_spec_type, 40215c066ec2SJerry Gilliam dp->ddm_node_type, 40225c066ec2SJerry Gilliam (int)dp->ddm_dev); 40237c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 40245c066ec2SJerry Gilliam "\tbind name = %s\n", 40255c066ec2SJerry Gilliam ddi_binding_name(dip)); 40267c478bd9Sstevel@tonic-gate } 40277c478bd9Sstevel@tonic-gate #endif 40287c478bd9Sstevel@tonic-gate md->socket = socket; 40297c478bd9Sstevel@tonic-gate md->op = SS_CSINITDEV_CREATE_DEVICE; 40307c478bd9Sstevel@tonic-gate md->dev = dp->ddm_dev; 40317c478bd9Sstevel@tonic-gate md->type = dp->ddm_spec_type; 40327c478bd9Sstevel@tonic-gate (void) strcpy(md->driver, 40337c478bd9Sstevel@tonic-gate ddi_binding_name(dip)); 40345c066ec2SJerry Gilliam major = ddi_driver_major(dip); 40357c478bd9Sstevel@tonic-gate ops = ddi_get_driver(dip); 40367c478bd9Sstevel@tonic-gate LOCK_DEV_OPS(&devnamesp[major].dn_lock); 40377c478bd9Sstevel@tonic-gate pcm_pathname(dip, dp->ddm_name, md->path); 40387c478bd9Sstevel@tonic-gate INCR_DEV_OPS_REF(ops); 40397c478bd9Sstevel@tonic-gate (void) ddi_pathname(dip, md->path); 40407c478bd9Sstevel@tonic-gate DECR_DEV_OPS_REF(ops); 40417c478bd9Sstevel@tonic-gate UNLOCK_DEV_OPS(&devnamesp[major].dn_lock); 40427c478bd9Sstevel@tonic-gate (void) sprintf(md->path + strlen(md->path), 40435c066ec2SJerry Gilliam ":%s", dp->ddm_name); 40447c478bd9Sstevel@tonic-gate if (dp->next == NULL) 40457c478bd9Sstevel@tonic-gate /* no more */ 40467c478bd9Sstevel@tonic-gate md->flags |= PCM_EVENT_MORE; 40477c478bd9Sstevel@tonic-gate } 40487c478bd9Sstevel@tonic-gate } else { 40497c478bd9Sstevel@tonic-gate count = 0; 40507c478bd9Sstevel@tonic-gate } 40517c478bd9Sstevel@tonic-gate } 4052b9ccdc5aScth ndi_devi_exit(dip, circ); 40537c478bd9Sstevel@tonic-gate return (count); 40547c478bd9Sstevel@tonic-gate } 40557c478bd9Sstevel@tonic-gate 40567c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 40577c478bd9Sstevel@tonic-gate static char *ddmtypes[] = { "minor", "alias", "default", "internal" }; 40587c478bd9Sstevel@tonic-gate 40597c478bd9Sstevel@tonic-gate static void 40607c478bd9Sstevel@tonic-gate pcmcia_dump_minors(dev_info_t *dip) 40617c478bd9Sstevel@tonic-gate { 4062b9ccdc5aScth int circ; 40637c478bd9Sstevel@tonic-gate int count = 0; 40647c478bd9Sstevel@tonic-gate struct ddi_minor_data *dp; 40657c478bd9Sstevel@tonic-gate int unit, major; 40667c478bd9Sstevel@tonic-gate dev_info_t *np; 40677c478bd9Sstevel@tonic-gate 40687c478bd9Sstevel@tonic-gate unit = ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 40697c478bd9Sstevel@tonic-gate PCM_DEV_SOCKET, -1); 40707c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 40715c066ec2SJerry Gilliam "pcmcia_dump_minors: dip=%p, socket=%d\n", (void *)dip, unit); 40727c478bd9Sstevel@tonic-gate 40737c478bd9Sstevel@tonic-gate major = ddi_driver_major(dip); 40747c478bd9Sstevel@tonic-gate if (major != -1) { 40757c478bd9Sstevel@tonic-gate for (np = devnamesp[major].dn_head; np != NULL; 40767c478bd9Sstevel@tonic-gate np = (dev_info_t *)DEVI(np)->devi_next) { 40777c478bd9Sstevel@tonic-gate char *cf2 = ""; 40787c478bd9Sstevel@tonic-gate char *cur = ""; 4079a9fb0ae8Srw if (i_ddi_node_state(np) == DS_READY) 4080a9fb0ae8Srw cf2 = "DS_READY"; 40817c478bd9Sstevel@tonic-gate if (np == dip) 40827c478bd9Sstevel@tonic-gate cur = "CUR"; 40837c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "\tsibs: %s %s %s\n", 40845c066ec2SJerry Gilliam ddi_binding_name(np), cf2, cur); 40857c478bd9Sstevel@tonic-gate 4086b9ccdc5aScth ndi_devi_enter(np, &circ); 40877c478bd9Sstevel@tonic-gate if (DEVI(np)->devi_minor != 40887c478bd9Sstevel@tonic-gate (struct ddi_minor_data *)NULL) { 40897c478bd9Sstevel@tonic-gate for (dp = DEVI(np)->devi_minor; 40907c478bd9Sstevel@tonic-gate dp != (struct ddi_minor_data *)NULL; 40917c478bd9Sstevel@tonic-gate dp = dp->next) { 40927c478bd9Sstevel@tonic-gate count++; /* have one more */ 40937c478bd9Sstevel@tonic-gate } 40947c478bd9Sstevel@tonic-gate for (dp = DEVI(dip)->devi_minor; 40957c478bd9Sstevel@tonic-gate dp != (struct ddi_minor_data *)NULL; 40967c478bd9Sstevel@tonic-gate dp = dp->next) { 40977c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "\ttype=%s, name=%s," 40985c066ec2SJerry Gilliam "socket=%d, stype=%x, " 40995c066ec2SJerry Gilliam "ntype=%s, dev_t=%x", 41005c066ec2SJerry Gilliam ddmtypes[dp->type], 41015c066ec2SJerry Gilliam dp->ddm_name, 41025c066ec2SJerry Gilliam unit, 41035c066ec2SJerry Gilliam dp->ddm_spec_type, 41045c066ec2SJerry Gilliam dp->ddm_node_type, 41055c066ec2SJerry Gilliam (int)dp->ddm_dev); 41067c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "\tbind name = %s\n", 41075c066ec2SJerry Gilliam ddi_binding_name(np)); 41087c478bd9Sstevel@tonic-gate } 41097c478bd9Sstevel@tonic-gate } 4110b9ccdc5aScth ndi_devi_exit(np, circ); 41117c478bd9Sstevel@tonic-gate } 41127c478bd9Sstevel@tonic-gate } 41137c478bd9Sstevel@tonic-gate } 41147c478bd9Sstevel@tonic-gate #endif 41157c478bd9Sstevel@tonic-gate 41167c478bd9Sstevel@tonic-gate /* 41177c478bd9Sstevel@tonic-gate * experimental merging code 41187c478bd9Sstevel@tonic-gate * what are the things that we should merge on? 41197c478bd9Sstevel@tonic-gate * match something by name in the "compatible" property 41207c478bd9Sstevel@tonic-gate * restrict to a specific "socket" 41217c478bd9Sstevel@tonic-gate * restrict to a specific "instance" 41227c478bd9Sstevel@tonic-gate */ 41237c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 41247c478bd9Sstevel@tonic-gate static int 41257c478bd9Sstevel@tonic-gate pcmcia_merge_conf(dev_info_t *dip) 41267c478bd9Sstevel@tonic-gate { 41277c478bd9Sstevel@tonic-gate return (0); /* merge failed */ 41287c478bd9Sstevel@tonic-gate } 41297c478bd9Sstevel@tonic-gate 41307c478bd9Sstevel@tonic-gate /* 41317c478bd9Sstevel@tonic-gate * pcmcia_mfc_intr() 41327c478bd9Sstevel@tonic-gate * Multifunction Card interrupt handler 41337c478bd9Sstevel@tonic-gate * While some adapters share interrupts at the lowest 41347c478bd9Sstevel@tonic-gate * level, some can't. In order to be consistent, we 41357c478bd9Sstevel@tonic-gate * split multifunction cards out with this intercept and 41367c478bd9Sstevel@tonic-gate * allow the low level to do what is best for it. 41377c478bd9Sstevel@tonic-gate * the arg is a pcmcia_socket structure and all interrupts 41387c478bd9Sstevel@tonic-gate * are per-socket in this case. We also have the option 41397c478bd9Sstevel@tonic-gate * to optimize if the cards support it. It also means 41407c478bd9Sstevel@tonic-gate * that we can use the INTRACK mode if it proves desirable 41417c478bd9Sstevel@tonic-gate */ 41427c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 41437c478bd9Sstevel@tonic-gate static uint32_t 41447c478bd9Sstevel@tonic-gate pcmcia_mfc_intr(caddr_t arg1, caddr_t arg2) 41457c478bd9Sstevel@tonic-gate { 41467c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t *sockp; 41477c478bd9Sstevel@tonic-gate inthandler_t *intr, *first; 41487c478bd9Sstevel@tonic-gate int done, result; 41497c478bd9Sstevel@tonic-gate 41507c478bd9Sstevel@tonic-gate sockp = (pcmcia_logical_socket_t *)arg1; 41517c478bd9Sstevel@tonic-gate 41527c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 41537c478bd9Sstevel@tonic-gate if (pcmcia_debug > 1) { 41547c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia_mfc_intr sockp=%p" 41557c478bd9Sstevel@tonic-gate " ls_inthandlers=%p\n" 41567c478bd9Sstevel@tonic-gate "\t ls_flags=0x%x PCS_IRQ_ENABLED=0x%x \n", 41577c478bd9Sstevel@tonic-gate (void *) sockp, (void *) sockp->ls_inthandlers, 41587c478bd9Sstevel@tonic-gate sockp->ls_flags, PCS_IRQ_ENABLED); 41597c478bd9Sstevel@tonic-gate } 41607c478bd9Sstevel@tonic-gate #endif 41617c478bd9Sstevel@tonic-gate 41627c478bd9Sstevel@tonic-gate if (sockp == NULL || sockp->ls_inthandlers == NULL || 41637c478bd9Sstevel@tonic-gate !(sockp->ls_flags & PCS_IRQ_ENABLED)) 41647c478bd9Sstevel@tonic-gate return (DDI_INTR_UNCLAIMED); 41657c478bd9Sstevel@tonic-gate 41667c478bd9Sstevel@tonic-gate mutex_enter(&sockp->ls_ilock); 41677c478bd9Sstevel@tonic-gate for (done = 0, result = 0, first = intr = sockp->ls_inthandlers; 41685c066ec2SJerry Gilliam intr != NULL && !done; intr = intr->next) { 41697c478bd9Sstevel@tonic-gate result |= intr->intr(intr->arg1, intr->arg2); 41707c478bd9Sstevel@tonic-gate if (intr->next == first) 41717c478bd9Sstevel@tonic-gate done++; 41727c478bd9Sstevel@tonic-gate } 41737c478bd9Sstevel@tonic-gate if (intr == NULL) { 41747c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pcmcia_mfc_intr: bad MFC handler list"); 41757c478bd9Sstevel@tonic-gate } 41767c478bd9Sstevel@tonic-gate if (sockp->ls_inthandlers) 41777c478bd9Sstevel@tonic-gate sockp->ls_inthandlers = sockp->ls_inthandlers->next; 41787c478bd9Sstevel@tonic-gate 41797c478bd9Sstevel@tonic-gate mutex_exit(&sockp->ls_ilock); 41807c478bd9Sstevel@tonic-gate return (result ? DDI_INTR_CLAIMED : DDI_INTR_UNCLAIMED); 41817c478bd9Sstevel@tonic-gate } 41827c478bd9Sstevel@tonic-gate 41837c478bd9Sstevel@tonic-gate /* 41847c478bd9Sstevel@tonic-gate * pcmcia_power(dip) 41857c478bd9Sstevel@tonic-gate * control power for nexus and children 41867c478bd9Sstevel@tonic-gate */ 41877c478bd9Sstevel@tonic-gate int 41887c478bd9Sstevel@tonic-gate pcmcia_power(dev_info_t *dip, int component, int level) 41897c478bd9Sstevel@tonic-gate { 41907c478bd9Sstevel@tonic-gate #if 0 41917c478bd9Sstevel@tonic-gate anp_t *anp = (anp_t *)ddi_get_driver_private(dip); 41927c478bd9Sstevel@tonic-gate int i; 41937c478bd9Sstevel@tonic-gate /* 41947c478bd9Sstevel@tonic-gate * for now, we only have one component. Should there be one per-socket? 41957c478bd9Sstevel@tonic-gate * the level is only one (power on or off) 41967c478bd9Sstevel@tonic-gate */ 41977c478bd9Sstevel@tonic-gate if (component != 0 || level > 1) 41987c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 41997c478bd9Sstevel@tonic-gate 42007c478bd9Sstevel@tonic-gate for (i = 0; i < pcic->pc_numsockets; i++) { 42017c478bd9Sstevel@tonic-gate if (pcic->pc_callback) 42027c478bd9Sstevel@tonic-gate PC_CALLBACK(dip, pcic->pc_cb_arg, 42037c478bd9Sstevel@tonic-gate (level == 0) ? PCE_PM_SUSPEND : 42047c478bd9Sstevel@tonic-gate PCE_PM_RESUME, 42057c478bd9Sstevel@tonic-gate i); 42067c478bd9Sstevel@tonic-gate } 42077c478bd9Sstevel@tonic-gate #else 42087c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pcmcia_power: component=%d, level=%d for %s", 42095c066ec2SJerry Gilliam component, level, ddi_get_name_addr(dip)); 42107c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 42117c478bd9Sstevel@tonic-gate #endif 42127c478bd9Sstevel@tonic-gate } 42137c478bd9Sstevel@tonic-gate 42147c478bd9Sstevel@tonic-gate void 42157c478bd9Sstevel@tonic-gate pcmcia_begin_resume(dev_info_t *dip) 42167c478bd9Sstevel@tonic-gate { 42177c478bd9Sstevel@tonic-gate int i; 42187c478bd9Sstevel@tonic-gate struct pcmcia_adapter *adapt = NULL; 42197c478bd9Sstevel@tonic-gate for (i = 0; i < pcmcia_num_adapters; i++) { 42207c478bd9Sstevel@tonic-gate if (pcmcia_adapters[i]->pca_dip == dip) { 42217c478bd9Sstevel@tonic-gate adapt = pcmcia_adapters[i]; 42227c478bd9Sstevel@tonic-gate break; 42237c478bd9Sstevel@tonic-gate } 42247c478bd9Sstevel@tonic-gate } 42257c478bd9Sstevel@tonic-gate if (adapt == NULL) 42267c478bd9Sstevel@tonic-gate return; 42277c478bd9Sstevel@tonic-gate 42287c478bd9Sstevel@tonic-gate for (i = 0; i < adapt->pca_numsockets; i++) { 42297c478bd9Sstevel@tonic-gate int s; 42307c478bd9Sstevel@tonic-gate s = adapt->pca_first_socket + i; 42317c478bd9Sstevel@tonic-gate if (pcmcia_sockets[s]->ls_flags & PCS_SUSPENDED) { 42327c478bd9Sstevel@tonic-gate if (pcmcia_sockets[s]->ls_flags & 42337c478bd9Sstevel@tonic-gate (1 << PCE_PM_RESUME)) { 42347c478bd9Sstevel@tonic-gate (void) cs_event(PCE_PM_RESUME, s, 0); 42357c478bd9Sstevel@tonic-gate pcm_event_manager(PCE_PM_RESUME, s, NULL); 42367c478bd9Sstevel@tonic-gate } 42377c478bd9Sstevel@tonic-gate (void) cs_event(PCE_CARD_REMOVAL, s, 0); 42387c478bd9Sstevel@tonic-gate pcm_event_manager(PCE_CARD_REMOVAL, s, NULL); 42397c478bd9Sstevel@tonic-gate } 42407c478bd9Sstevel@tonic-gate } 42417c478bd9Sstevel@tonic-gate } 42427c478bd9Sstevel@tonic-gate 424311c2b4c0Srw /* 424411c2b4c0Srw * mark a cardbus card as "suspended" in the pcmcia module 424511c2b4c0Srw */ 424611c2b4c0Srw void 424711c2b4c0Srw pcmcia_cb_suspended(int socket) 424811c2b4c0Srw { 424911c2b4c0Srw mutex_enter(&pcmcia_global_lock); 425011c2b4c0Srw pcmcia_sockets[socket]->ls_flags |= PCS_SUSPENDED; 425111c2b4c0Srw mutex_exit(&pcmcia_global_lock); 425211c2b4c0Srw 425311c2b4c0Srw } 425411c2b4c0Srw 425511c2b4c0Srw /* 425611c2b4c0Srw * mark a cardbus card as "resumed" in the pcmcia module 425711c2b4c0Srw */ 425811c2b4c0Srw void 425911c2b4c0Srw pcmcia_cb_resumed(int socket) 426011c2b4c0Srw { 426111c2b4c0Srw if (pcmcia_sockets[socket]->ls_flags & PCS_SUSPENDED) { 426211c2b4c0Srw mutex_enter(&pcmcia_global_lock); 426311c2b4c0Srw pcmcia_sockets[socket]->ls_flags &= ~PCS_SUSPENDED; 426411c2b4c0Srw cv_broadcast(&pcmcia_condvar); 426511c2b4c0Srw mutex_exit(&pcmcia_global_lock); 426611c2b4c0Srw #ifdef PCMCIA_DEBUG 426711c2b4c0Srw if (pcmcia_debug) { 426811c2b4c0Srw cmn_err(CE_NOTE, "pcmcia_cb_resume RESUMED"); 426911c2b4c0Srw } 427011c2b4c0Srw #endif 427111c2b4c0Srw } 427211c2b4c0Srw 427311c2b4c0Srw } 427411c2b4c0Srw 42757c478bd9Sstevel@tonic-gate void 42767c478bd9Sstevel@tonic-gate pcmcia_wait_insert(dev_info_t *dip) 42777c478bd9Sstevel@tonic-gate { 42787c478bd9Sstevel@tonic-gate int i, f, tries, done; 42797c478bd9Sstevel@tonic-gate clock_t tm; 42807c478bd9Sstevel@tonic-gate struct pcmcia_adapter *adapt = NULL; 42817c478bd9Sstevel@tonic-gate anp_t *nexus; 42827c478bd9Sstevel@tonic-gate 42837c478bd9Sstevel@tonic-gate for (i = 0; i < pcmcia_num_adapters; i++) { 42847c478bd9Sstevel@tonic-gate if (pcmcia_adapters[i]->pca_dip == dip) { 42857c478bd9Sstevel@tonic-gate adapt = pcmcia_adapters[i]; 42867c478bd9Sstevel@tonic-gate break; 42877c478bd9Sstevel@tonic-gate } 42887c478bd9Sstevel@tonic-gate } 42897c478bd9Sstevel@tonic-gate if (adapt == NULL) 42907c478bd9Sstevel@tonic-gate return; 42917c478bd9Sstevel@tonic-gate 42927c478bd9Sstevel@tonic-gate for (tries = adapt->pca_numsockets * 10; tries > 0; tries--) { 42937c478bd9Sstevel@tonic-gate done = 1; 42947c478bd9Sstevel@tonic-gate mutex_enter(&pcmcia_global_lock); 42957c478bd9Sstevel@tonic-gate for (i = 0; i < adapt->pca_numsockets; i++) { 42967c478bd9Sstevel@tonic-gate int s; 42977c478bd9Sstevel@tonic-gate s = adapt->pca_first_socket + i; 42987c478bd9Sstevel@tonic-gate for (f = 0; f < PCMCIA_MAX_FUNCTIONS; f++) 42997c478bd9Sstevel@tonic-gate if (pcmcia_sockets[s] && 43007c478bd9Sstevel@tonic-gate pcmcia_sockets[s]->ls_flags & 43017c478bd9Sstevel@tonic-gate PCS_SUSPENDED) { 430211c2b4c0Srw 430311c2b4c0Srw #ifdef PCMCIA_DEBUG 430411c2b4c0Srw if (pcmcia_debug) { 430511c2b4c0Srw cmn_err(CE_NOTE, 43065c066ec2SJerry Gilliam "pcmcia_wait_insert: " 43075c066ec2SJerry Gilliam "socket in SUSPENDED " 43085c066ec2SJerry Gilliam "state"); 430911c2b4c0Srw } 431011c2b4c0Srw #endif 43117c478bd9Sstevel@tonic-gate done = 0; 43127c478bd9Sstevel@tonic-gate break; 43137c478bd9Sstevel@tonic-gate } 43147c478bd9Sstevel@tonic-gate } 43157c478bd9Sstevel@tonic-gate if (!done) { 43167c478bd9Sstevel@tonic-gate tm = ddi_get_lbolt(); 43177c478bd9Sstevel@tonic-gate (void) cv_timedwait(&pcmcia_condvar, 43187c478bd9Sstevel@tonic-gate &pcmcia_global_lock, 43197c478bd9Sstevel@tonic-gate tm + drv_usectohz(100000)); 43207c478bd9Sstevel@tonic-gate } else { 43217c478bd9Sstevel@tonic-gate tries = 0; 43227c478bd9Sstevel@tonic-gate } 43237c478bd9Sstevel@tonic-gate mutex_exit(&pcmcia_global_lock); 43247c478bd9Sstevel@tonic-gate } 43257c478bd9Sstevel@tonic-gate 432611c2b4c0Srw if (tries == 0) { 432711c2b4c0Srw cmn_err(CE_NOTE, "pcmcia_wait_insert timed out"); 432811c2b4c0Srw } 432911c2b4c0Srw 43307c478bd9Sstevel@tonic-gate nexus = (anp_t *)ddi_get_driver_private(dip); 43317c478bd9Sstevel@tonic-gate pcmcia_find_cards(nexus); 43327c478bd9Sstevel@tonic-gate } 43337c478bd9Sstevel@tonic-gate 43347c478bd9Sstevel@tonic-gate int 43357c478bd9Sstevel@tonic-gate pcmcia_map_reg(dev_info_t *pdip, dev_info_t *dip, ra_return_t *ra, 43367c478bd9Sstevel@tonic-gate uint32_t state, caddr_t *base, 43377c478bd9Sstevel@tonic-gate ddi_acc_handle_t *handle, ddi_device_acc_attr_t *attrib, 43387c478bd9Sstevel@tonic-gate uint32_t req_base) 43397c478bd9Sstevel@tonic-gate { 43407c478bd9Sstevel@tonic-gate struct pcmcia_parent_private *ppd; 43417c478bd9Sstevel@tonic-gate int rnum = 0, type = PCMCIA_MAP_MEM; 43427c478bd9Sstevel@tonic-gate ddi_map_req_t mr; 43437c478bd9Sstevel@tonic-gate ddi_acc_hdl_t *hp; 43447c478bd9Sstevel@tonic-gate int result; 43457c478bd9Sstevel@tonic-gate struct regspec *reg; 43467c478bd9Sstevel@tonic-gate ddi_device_acc_attr_t attr; 43477c478bd9Sstevel@tonic-gate 43487c478bd9Sstevel@tonic-gate if (dip != NULL) { 43497c478bd9Sstevel@tonic-gate ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(dip); 43507c478bd9Sstevel@tonic-gate if (ppd == NULL) 43517c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 43527c478bd9Sstevel@tonic-gate for (rnum = 1; rnum < ppd->ppd_nreg; rnum++) { 43537c478bd9Sstevel@tonic-gate struct pcm_regs *p; 43547c478bd9Sstevel@tonic-gate p = &ppd->ppd_reg[rnum]; 43557c478bd9Sstevel@tonic-gate if (state & WS_IO) { 43567c478bd9Sstevel@tonic-gate /* need I/O */ 43577c478bd9Sstevel@tonic-gate type = PCMCIA_MAP_IO; 43587c478bd9Sstevel@tonic-gate /* 43597c478bd9Sstevel@tonic-gate * We want to find an IO regspec. When we 43607c478bd9Sstevel@tonic-gate * find one, it either has to match 43617c478bd9Sstevel@tonic-gate * the caller's requested base address 43627c478bd9Sstevel@tonic-gate * or it has to be relocatable. 43637c478bd9Sstevel@tonic-gate * We match on the requested base address 43647c478bd9Sstevel@tonic-gate * rather than the allocated base 43657c478bd9Sstevel@tonic-gate * address so that we handle the case 43667c478bd9Sstevel@tonic-gate * of adapters that have IO window base 43677c478bd9Sstevel@tonic-gate * relocation registers. 43687c478bd9Sstevel@tonic-gate */ 43697c478bd9Sstevel@tonic-gate if ((p->phys_hi & 43707c478bd9Sstevel@tonic-gate PC_REG_SPACE(PC_REG_SPACE_IO)) && 43715c066ec2SJerry Gilliam ((req_base == p->phys_lo) || 43725c066ec2SJerry Gilliam !(p->phys_hi & PC_REG_RELOC(1)))) 43735c066ec2SJerry Gilliam break; 43747c478bd9Sstevel@tonic-gate } else { 43757c478bd9Sstevel@tonic-gate /* need memory */ 43767c478bd9Sstevel@tonic-gate type = PCMCIA_MAP_MEM; 43777c478bd9Sstevel@tonic-gate if (p->phys_hi & 43787c478bd9Sstevel@tonic-gate PC_REG_SPACE(PC_REG_SPACE_MEMORY| 43797c478bd9Sstevel@tonic-gate PC_REG_SPACE_ATTRIBUTE)) 43807c478bd9Sstevel@tonic-gate break; 43817c478bd9Sstevel@tonic-gate } 43827c478bd9Sstevel@tonic-gate } 43837c478bd9Sstevel@tonic-gate if (rnum >= ppd->ppd_nreg) 43847c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 43857c478bd9Sstevel@tonic-gate } else if (state & WS_IO) { 43867c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 43877c478bd9Sstevel@tonic-gate } 43887c478bd9Sstevel@tonic-gate 43897c478bd9Sstevel@tonic-gate reg = kmem_zalloc(sizeof (pci_regspec_t), KM_SLEEP); 43907c478bd9Sstevel@tonic-gate reg = pcmcia_cons_regspec(pdip, type, (uchar_t *)reg, ra); 43917c478bd9Sstevel@tonic-gate 43927c478bd9Sstevel@tonic-gate if (attrib == NULL || 43937c478bd9Sstevel@tonic-gate attrib->devacc_attr_version != DDI_DEVICE_ATTR_V0) { 43947c478bd9Sstevel@tonic-gate attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 43957c478bd9Sstevel@tonic-gate attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC; 43967c478bd9Sstevel@tonic-gate attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 43977c478bd9Sstevel@tonic-gate } else { 43987c478bd9Sstevel@tonic-gate attr = *attrib; 43997c478bd9Sstevel@tonic-gate } 44007c478bd9Sstevel@tonic-gate /* 44017c478bd9Sstevel@tonic-gate * Allocate and initialize the common elements of data access handle. 44027c478bd9Sstevel@tonic-gate */ 44037c478bd9Sstevel@tonic-gate *handle = impl_acc_hdl_alloc(KM_SLEEP, NULL); 44047c478bd9Sstevel@tonic-gate hp = impl_acc_hdl_get(*handle); 44057c478bd9Sstevel@tonic-gate hp->ah_vers = VERS_ACCHDL; 44067c478bd9Sstevel@tonic-gate hp->ah_dip = dip != NULL ? dip : pdip; 44077c478bd9Sstevel@tonic-gate hp->ah_rnumber = rnum; 44087c478bd9Sstevel@tonic-gate hp->ah_offset = 0; 44097c478bd9Sstevel@tonic-gate hp->ah_len = ra->ra_len; 44107c478bd9Sstevel@tonic-gate hp->ah_acc = attr; 44117c478bd9Sstevel@tonic-gate 44127c478bd9Sstevel@tonic-gate /* 44137c478bd9Sstevel@tonic-gate * Set up the mapping request and call to parent. 44147c478bd9Sstevel@tonic-gate */ 44157c478bd9Sstevel@tonic-gate mr.map_op = DDI_MO_MAP_LOCKED; 44167c478bd9Sstevel@tonic-gate mr.map_type = DDI_MT_REGSPEC; 44177c478bd9Sstevel@tonic-gate mr.map_obj.rp = reg; 44187c478bd9Sstevel@tonic-gate mr.map_prot = PROT_READ | PROT_WRITE; 44197c478bd9Sstevel@tonic-gate mr.map_flags = DDI_MF_KERNEL_MAPPING; 44207c478bd9Sstevel@tonic-gate mr.map_handlep = hp; 44217c478bd9Sstevel@tonic-gate mr.map_vers = DDI_MAP_VERSION; 44227c478bd9Sstevel@tonic-gate 44237c478bd9Sstevel@tonic-gate result = ddi_map(pdip, &mr, 0, ra->ra_len, base); 44247c478bd9Sstevel@tonic-gate if (result != DDI_SUCCESS) { 44257c478bd9Sstevel@tonic-gate impl_acc_hdl_free(*handle); 44267c478bd9Sstevel@tonic-gate *handle = (ddi_acc_handle_t)NULL; 44277c478bd9Sstevel@tonic-gate } else { 44287c478bd9Sstevel@tonic-gate hp->ah_addr = *base; 44297c478bd9Sstevel@tonic-gate if (mr.map_op == DDI_MO_UNMAP) 44307c478bd9Sstevel@tonic-gate ra = NULL; 44317c478bd9Sstevel@tonic-gate if (dip != NULL) 44327c478bd9Sstevel@tonic-gate pcmcia_set_assigned(dip, rnum, ra); 44337c478bd9Sstevel@tonic-gate } 44347c478bd9Sstevel@tonic-gate 4435981012acSrw kmem_free(reg, sizeof (pci_regspec_t)); 4436981012acSrw 44377c478bd9Sstevel@tonic-gate return (result); 44387c478bd9Sstevel@tonic-gate } 44397c478bd9Sstevel@tonic-gate 44407c478bd9Sstevel@tonic-gate struct pcmcia_adapter * 44417c478bd9Sstevel@tonic-gate pcmcia_get_adapter(dev_info_t *dip) 44427c478bd9Sstevel@tonic-gate { 44437c478bd9Sstevel@tonic-gate int i; 44447c478bd9Sstevel@tonic-gate 44457c478bd9Sstevel@tonic-gate for (i = 0; i < pcmcia_num_adapters; i++) { 44467c478bd9Sstevel@tonic-gate if (pcmcia_adapters[i] && 44477c478bd9Sstevel@tonic-gate pcmcia_adapters[i]->pca_dip == dip) { 44487c478bd9Sstevel@tonic-gate return (pcmcia_adapters[i]); 44497c478bd9Sstevel@tonic-gate } 44507c478bd9Sstevel@tonic-gate } 44517c478bd9Sstevel@tonic-gate return (NULL); 44527c478bd9Sstevel@tonic-gate } 44537c478bd9Sstevel@tonic-gate 44547c478bd9Sstevel@tonic-gate 44557c478bd9Sstevel@tonic-gate void 44567c478bd9Sstevel@tonic-gate pcmcia_set_assigned(dev_info_t *dip, int rnum, ra_return_t *ret) 44577c478bd9Sstevel@tonic-gate { 44587c478bd9Sstevel@tonic-gate struct pcmcia_parent_private *ppd; 44597c478bd9Sstevel@tonic-gate struct pcm_regs *reg, *assign; 44607c478bd9Sstevel@tonic-gate 44617c478bd9Sstevel@tonic-gate ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(dip); 44627c478bd9Sstevel@tonic-gate if (ppd) { 44637c478bd9Sstevel@tonic-gate reg = &ppd->ppd_reg[rnum]; 44647c478bd9Sstevel@tonic-gate assign = &ppd->ppd_assigned[rnum]; 44657c478bd9Sstevel@tonic-gate if (ret) { 44667c478bd9Sstevel@tonic-gate if (assign->phys_hi == 0) { 44677c478bd9Sstevel@tonic-gate assign->phys_hi = reg->phys_hi; 44687c478bd9Sstevel@tonic-gate assign->phys_lo = ret->ra_addr_lo; 44697c478bd9Sstevel@tonic-gate assign->phys_len = ret->ra_len; 44707c478bd9Sstevel@tonic-gate } else if (assign->phys_lo != ret->ra_addr_lo) { 44717c478bd9Sstevel@tonic-gate #ifdef PCMCIA_DEBUG 44727c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pcmcia: bad address:" 44735c066ec2SJerry Gilliam "%s=<%x,%x>", 44745c066ec2SJerry Gilliam ddi_get_name_addr(dip), 44755c066ec2SJerry Gilliam ret->ra_addr_lo, assign->phys_lo); 44767c478bd9Sstevel@tonic-gate #else 44777c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "!pcmcia: bad address:" 44785c066ec2SJerry Gilliam "%s=<%x,%x>", 44795c066ec2SJerry Gilliam ddi_get_name_addr(dip), 44805c066ec2SJerry Gilliam ret->ra_addr_lo, (int)assign->phys_lo); 44817c478bd9Sstevel@tonic-gate #endif 44827c478bd9Sstevel@tonic-gate } 44837c478bd9Sstevel@tonic-gate assign->phys_hi = PC_INCR_REFCNT(assign->phys_hi); 44847c478bd9Sstevel@tonic-gate } else { 44857c478bd9Sstevel@tonic-gate int i; 44867c478bd9Sstevel@tonic-gate assign->phys_hi = PC_DECR_REFCNT(assign->phys_hi); 44877c478bd9Sstevel@tonic-gate i = PC_GET_REG_REFCNT(assign->phys_hi); 44887c478bd9Sstevel@tonic-gate if (i == 0) { 44897c478bd9Sstevel@tonic-gate assign->phys_hi = 0; 44907c478bd9Sstevel@tonic-gate assign->phys_lo = 0; 44917c478bd9Sstevel@tonic-gate assign->phys_len = 0; 44927c478bd9Sstevel@tonic-gate } 44937c478bd9Sstevel@tonic-gate } 44947c478bd9Sstevel@tonic-gate } 44957c478bd9Sstevel@tonic-gate } 44967c478bd9Sstevel@tonic-gate 44977c478bd9Sstevel@tonic-gate int 44988134ee03Srw pcmcia_alloc_mem(dev_info_t *dip, ndi_ra_request_t *req, ra_return_t *ret, 44998134ee03Srw dev_info_t **res_dip) 45007c478bd9Sstevel@tonic-gate { 45018134ee03Srw return (pcmcia_ra_alloc(dip, req, ret, NDI_RA_TYPE_MEM, res_dip)); 45027c478bd9Sstevel@tonic-gate } 45037c478bd9Sstevel@tonic-gate 45047c478bd9Sstevel@tonic-gate int 45058134ee03Srw pcmcia_alloc_io(dev_info_t *dip, ndi_ra_request_t *req, ra_return_t *ret, 45068134ee03Srw dev_info_t **res_dip) 45077c478bd9Sstevel@tonic-gate { 45088134ee03Srw return (pcmcia_ra_alloc(dip, req, ret, NDI_RA_TYPE_IO, res_dip)); 45098134ee03Srw } 45108134ee03Srw 45118134ee03Srw static boolean_t 45128134ee03Srw is_subtractv(dev_info_t *dip) 45138134ee03Srw { 45148134ee03Srw uint_t class; 45158134ee03Srw 45168134ee03Srw if (dip == NULL) 45178134ee03Srw return (B_FALSE); 45188134ee03Srw class = ddi_getprop(DDI_DEV_T_ANY, dip, 45195c066ec2SJerry Gilliam DDI_PROP_CANSLEEP|DDI_PROP_DONTPASS, 45205c066ec2SJerry Gilliam "class-code", 0xff); 45218134ee03Srw if (class == PPB_SUBTRACTIVE) { 45228134ee03Srw return (B_TRUE); 45238134ee03Srw } 45248134ee03Srw return (B_FALSE); 45258134ee03Srw } 45268134ee03Srw 45278134ee03Srw /* 45288134ee03Srw * pcmcia_pci_alloc() 45298134ee03Srw * allocate mem or I/O resource from the ancestor of the cardbus bridge. 45308134ee03Srw * First start from the parent node. If the parent is a subtractive 45318134ee03Srw * decode bridge and it does not have the requested resource, go up the 45328134ee03Srw * device tree to find the resource. 45338134ee03Srw * 45348134ee03Srw * dip the parent node of the cardbus bridge 45358134ee03Srw * 45368134ee03Srw * res_dip returns a pointer to the node from which the 45378134ee03Srw * resource is obtained. *res_dip could point to 45388134ee03Srw * the parent or a higher level ancestor. *res_dip 45398134ee03Srw * should be saved by the caller and later passed 45408134ee03Srw * to pcmcia_ra_free(); 45418134ee03Srw */ 45428134ee03Srw int 45438134ee03Srw pcmcia_pci_alloc(dev_info_t *dip, ndi_ra_request_t *req, ra_return_t *ret, 45448134ee03Srw char *type, dev_info_t **res_dip) 45458134ee03Srw { 45468134ee03Srw uint64_t base = 0; 45478134ee03Srw uint64_t len = 0; 45488134ee03Srw 45498134ee03Srw if ((ndi_ra_alloc(dip, req, &base, &len, type, NDI_RA_PASS) 45505c066ec2SJerry Gilliam == NDI_FAILURE) || 45518134ee03Srw ((base >> 32) != 0)) { 45528134ee03Srw if (is_subtractv(dip)) { 45538134ee03Srw return (pcmcia_pci_alloc(ddi_get_parent(dip), 45545c066ec2SJerry Gilliam req, ret, type, res_dip)); 45558134ee03Srw 45568134ee03Srw } else { 45578134ee03Srw ret->ra_addr_hi = 0; 45588134ee03Srw ret->ra_addr_lo = 0; 45598134ee03Srw ret->ra_len = 0; 45608134ee03Srw return (DDI_FAILURE); 45618134ee03Srw } 45628134ee03Srw } 45638134ee03Srw ret->ra_addr_lo = base & 0xffffffff; 45648134ee03Srw ret->ra_addr_hi = 0; 45658134ee03Srw ret->ra_len = len; 45668134ee03Srw *res_dip = dip; 45678134ee03Srw return (DDI_SUCCESS); 45687c478bd9Sstevel@tonic-gate } 45697c478bd9Sstevel@tonic-gate 45707c478bd9Sstevel@tonic-gate int 45717c478bd9Sstevel@tonic-gate pcmcia_ra_alloc(dev_info_t *dip, ndi_ra_request_t *req, ra_return_t *ret, 45728134ee03Srw char *type, dev_info_t **res_dip) 45737c478bd9Sstevel@tonic-gate { 45747c478bd9Sstevel@tonic-gate uint64_t base = 0; 45757c478bd9Sstevel@tonic-gate uint64_t len = 0; 45767c478bd9Sstevel@tonic-gate 45777c478bd9Sstevel@tonic-gate /* 45787c478bd9Sstevel@tonic-gate * Allocate space from busra resource list 45797c478bd9Sstevel@tonic-gate * should not return an address > 32 bits 45807c478bd9Sstevel@tonic-gate */ 45817c478bd9Sstevel@tonic-gate 45827c478bd9Sstevel@tonic-gate if ((ndi_ra_alloc(dip, req, &base, &len, type, NDI_RA_PASS) 45835c066ec2SJerry Gilliam == NDI_FAILURE) || 45847c478bd9Sstevel@tonic-gate ((base >> 32) != 0)) { 45858134ee03Srw return (pcmcia_pci_alloc(ddi_get_parent(dip), req, ret, 45865c066ec2SJerry Gilliam type, res_dip)); 45877c478bd9Sstevel@tonic-gate } else { 45887c478bd9Sstevel@tonic-gate ret->ra_addr_lo = base & 0xffffffff; 45898134ee03Srw ret->ra_addr_hi = 0; 45907c478bd9Sstevel@tonic-gate ret->ra_len = len; 45918134ee03Srw *res_dip = dip; 45928134ee03Srw return (DDI_SUCCESS); 45937c478bd9Sstevel@tonic-gate } 45947c478bd9Sstevel@tonic-gate } 45957c478bd9Sstevel@tonic-gate 45967c478bd9Sstevel@tonic-gate int 45977c478bd9Sstevel@tonic-gate pcmcia_free_mem(dev_info_t *dip, ra_return_t *ret) 45987c478bd9Sstevel@tonic-gate { 45997c478bd9Sstevel@tonic-gate return (pcmcia_ra_free(dip, ret, NDI_RA_TYPE_MEM)); 46007c478bd9Sstevel@tonic-gate } 46017c478bd9Sstevel@tonic-gate 46027c478bd9Sstevel@tonic-gate int 46037c478bd9Sstevel@tonic-gate pcmcia_free_io(dev_info_t *dip, ra_return_t *ret) 46047c478bd9Sstevel@tonic-gate { 46057c478bd9Sstevel@tonic-gate return (pcmcia_ra_free(dip, ret, NDI_RA_TYPE_IO)); 46067c478bd9Sstevel@tonic-gate } 46077c478bd9Sstevel@tonic-gate 46087c478bd9Sstevel@tonic-gate int 46097c478bd9Sstevel@tonic-gate pcmcia_ra_free(dev_info_t *dip, ra_return_t *ret, char *type) 46107c478bd9Sstevel@tonic-gate { 461181ea8c75Srw if (dip == (dev_info_t *)-1) 461281ea8c75Srw return (DDI_FAILURE); 46137c478bd9Sstevel@tonic-gate if (ndi_ra_free(dip, (uint64_t)ret->ra_addr_lo, (uint64_t)ret->ra_len, 46147c478bd9Sstevel@tonic-gate type, NDI_RA_PASS) == NDI_SUCCESS) { 46157c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 46167c478bd9Sstevel@tonic-gate } else { 46177c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 46187c478bd9Sstevel@tonic-gate } 46197c478bd9Sstevel@tonic-gate } 46207c478bd9Sstevel@tonic-gate 46217c478bd9Sstevel@tonic-gate 46227c478bd9Sstevel@tonic-gate /* 46237c478bd9Sstevel@tonic-gate * when the low level device configuration does resource assignment 46247c478bd9Sstevel@tonic-gate * (devconf) then free the allocated resources so we can reassign them 46257c478bd9Sstevel@tonic-gate * later. Walk the child list to get them. 46267c478bd9Sstevel@tonic-gate */ 46277c478bd9Sstevel@tonic-gate void 46287c478bd9Sstevel@tonic-gate pcmcia_free_resources(dev_info_t *self) 46297c478bd9Sstevel@tonic-gate { 46307c478bd9Sstevel@tonic-gate struct regspec *assigned; 46317c478bd9Sstevel@tonic-gate int len; 46327c478bd9Sstevel@tonic-gate dev_info_t *dip; 4633b9ccdc5aScth int circ; 46347c478bd9Sstevel@tonic-gate 4635b9ccdc5aScth ndi_devi_enter(self, &circ); 46367c478bd9Sstevel@tonic-gate /* do searches in compatible property order */ 46377c478bd9Sstevel@tonic-gate for (dip = (dev_info_t *)DEVI(self)->devi_child; 46387c478bd9Sstevel@tonic-gate dip != NULL; 46397c478bd9Sstevel@tonic-gate dip = (dev_info_t *)DEVI(dip)->devi_sibling) { 46407c478bd9Sstevel@tonic-gate len = 0; 4641a3282898Scth if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 46427c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS|DDI_PROP_CANSLEEP, 46437c478bd9Sstevel@tonic-gate "assigned-addresses", 46447c478bd9Sstevel@tonic-gate (caddr_t)&assigned, 46457c478bd9Sstevel@tonic-gate &len) == DDI_PROP_SUCCESS) { 46467c478bd9Sstevel@tonic-gate /* 46477c478bd9Sstevel@tonic-gate * if there are assigned resources at this point, 46487c478bd9Sstevel@tonic-gate * then the OBP or devconf have assigned them and 46497c478bd9Sstevel@tonic-gate * they need to be freed. 46507c478bd9Sstevel@tonic-gate */ 46517c478bd9Sstevel@tonic-gate kmem_free(assigned, len); 46527c478bd9Sstevel@tonic-gate } 46537c478bd9Sstevel@tonic-gate } 4654b9ccdc5aScth ndi_devi_exit(self, circ); 46557c478bd9Sstevel@tonic-gate } 46567c478bd9Sstevel@tonic-gate 46577c478bd9Sstevel@tonic-gate /* 46587c478bd9Sstevel@tonic-gate * this is the equivalent of pcm_get_intr using ra_allocs. 46597c478bd9Sstevel@tonic-gate * returns -1 if failed, otherwise returns the allocated irq. 46607c478bd9Sstevel@tonic-gate * The input request, if less than zero it means not a specific 46617c478bd9Sstevel@tonic-gate * irq requested. If larger then 0 then we are requesting that specific 46627c478bd9Sstevel@tonic-gate * irq 46637c478bd9Sstevel@tonic-gate */ 46647c478bd9Sstevel@tonic-gate int 46657c478bd9Sstevel@tonic-gate pcmcia_get_intr(dev_info_t *dip, int request) 46667c478bd9Sstevel@tonic-gate { 46677c478bd9Sstevel@tonic-gate ndi_ra_request_t req; 46687c478bd9Sstevel@tonic-gate uint64_t base; 46697c478bd9Sstevel@tonic-gate uint64_t len; 46707c478bd9Sstevel@tonic-gate int err; 46717c478bd9Sstevel@tonic-gate 46727c478bd9Sstevel@tonic-gate bzero(&req, sizeof (req)); 46737c478bd9Sstevel@tonic-gate base = 0; 46747c478bd9Sstevel@tonic-gate len = 1; 46757c478bd9Sstevel@tonic-gate if (request >= 0) { 46767c478bd9Sstevel@tonic-gate req.ra_flags = NDI_RA_ALLOC_SPECIFIED; 46777c478bd9Sstevel@tonic-gate req.ra_len = 1; 46787c478bd9Sstevel@tonic-gate req.ra_addr = (uint64_t)request; 46797c478bd9Sstevel@tonic-gate } 46807c478bd9Sstevel@tonic-gate 46817c478bd9Sstevel@tonic-gate req.ra_boundbase = 0; 46827c478bd9Sstevel@tonic-gate req.ra_boundlen = 0xffffffffUL; 46837c478bd9Sstevel@tonic-gate req.ra_flags |= NDI_RA_ALLOC_BOUNDED; 46847c478bd9Sstevel@tonic-gate 46857c478bd9Sstevel@tonic-gate err = ndi_ra_alloc(dip, &req, &base, &len, NDI_RA_TYPE_INTR, 46867c478bd9Sstevel@tonic-gate NDI_RA_PASS); 46877c478bd9Sstevel@tonic-gate 46887c478bd9Sstevel@tonic-gate if (err == NDI_FAILURE) { 46897c478bd9Sstevel@tonic-gate return (-1); 46907c478bd9Sstevel@tonic-gate } else { 46917c478bd9Sstevel@tonic-gate return ((int)base); 46927c478bd9Sstevel@tonic-gate } 46937c478bd9Sstevel@tonic-gate } 46947c478bd9Sstevel@tonic-gate 46957c478bd9Sstevel@tonic-gate 46967c478bd9Sstevel@tonic-gate int 46977c478bd9Sstevel@tonic-gate pcmcia_return_intr(dev_info_t *dip, int request) 46987c478bd9Sstevel@tonic-gate { 46997c478bd9Sstevel@tonic-gate if ((ndi_ra_free(dip, (uint64_t)request, 1, NDI_RA_TYPE_INTR, 47007c478bd9Sstevel@tonic-gate NDI_RA_PASS)) == NDI_SUCCESS) { 47017c478bd9Sstevel@tonic-gate return (0); 47027c478bd9Sstevel@tonic-gate } else 47037c478bd9Sstevel@tonic-gate return (-1); 47047c478bd9Sstevel@tonic-gate 47057c478bd9Sstevel@tonic-gate } 47067c478bd9Sstevel@tonic-gate 47077c478bd9Sstevel@tonic-gate #ifdef sparc 47087c478bd9Sstevel@tonic-gate 47097c478bd9Sstevel@tonic-gate int 47107c478bd9Sstevel@tonic-gate pcmcia_add_intr_impl(dev_info_t *dip, dev_info_t *rdip, 47117c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp) 47127c478bd9Sstevel@tonic-gate { 47137c478bd9Sstevel@tonic-gate 47147c478bd9Sstevel@tonic-gate struct pcmcia_parent_private *ppd; 47157c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t *sockp; 47167c478bd9Sstevel@tonic-gate int socket, ret; 47177c478bd9Sstevel@tonic-gate struct pcmcia_adapter *adapt; 47187c478bd9Sstevel@tonic-gate set_irq_handler_t handler; 47197c478bd9Sstevel@tonic-gate struct intrspec *pispec; 47207c478bd9Sstevel@tonic-gate 47217c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 47227c478bd9Sstevel@tonic-gate if (pcmcia_debug) { 47237c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 47247c478bd9Sstevel@tonic-gate "pcmcia_add_intr_impl() entered " 47257c478bd9Sstevel@tonic-gate "dip=%p rdip=%p hdlp=%p \n", 47267c478bd9Sstevel@tonic-gate (void *)dip, (void *)rdip, (void *)hdlp); 47277c478bd9Sstevel@tonic-gate } 47287c478bd9Sstevel@tonic-gate #endif 47297c478bd9Sstevel@tonic-gate 47307c478bd9Sstevel@tonic-gate ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(rdip); 47317c478bd9Sstevel@tonic-gate socket = ppd->ppd_socket; 47327c478bd9Sstevel@tonic-gate sockp = pcmcia_sockets[socket]; 47337c478bd9Sstevel@tonic-gate adapt = sockp->ls_adapter; 47347c478bd9Sstevel@tonic-gate 47357c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 47367c478bd9Sstevel@tonic-gate if (pcmcia_debug) { 47377c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia_add_intr_impl()" 47387c478bd9Sstevel@tonic-gate " ppd_flags=0X%x PPD_CARD_MULTI=0X%x\n" 47397c478bd9Sstevel@tonic-gate " ppd_intrspec=%p ls_inthandlers=%p\n", 47407c478bd9Sstevel@tonic-gate ppd->ppd_flags, PPD_CARD_MULTI, 47417c478bd9Sstevel@tonic-gate (void *) ppd->ppd_intrspec, 47427c478bd9Sstevel@tonic-gate (void *)sockp->ls_inthandlers); 47437c478bd9Sstevel@tonic-gate } 47447c478bd9Sstevel@tonic-gate #endif 47457c478bd9Sstevel@tonic-gate 47467c478bd9Sstevel@tonic-gate /* 47477c478bd9Sstevel@tonic-gate * calculate IPL level when we support multiple levels 47487c478bd9Sstevel@tonic-gate */ 47497c478bd9Sstevel@tonic-gate pispec = ppd->ppd_intrspec; 47507c478bd9Sstevel@tonic-gate if (pispec == NULL) { 47517c478bd9Sstevel@tonic-gate sockp->ls_error = BAD_IRQ; 47527c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 47537c478bd9Sstevel@tonic-gate } 47547c478bd9Sstevel@tonic-gate 47557c478bd9Sstevel@tonic-gate handler.socket = sockp->ls_socket; 47567c478bd9Sstevel@tonic-gate handler.irq = 0; /* default case */ 47577c478bd9Sstevel@tonic-gate handler.handler = (f_tt *)hdlp->ih_cb_func; 47587c478bd9Sstevel@tonic-gate handler.arg1 = hdlp->ih_cb_arg1; 47597c478bd9Sstevel@tonic-gate handler.arg2 = hdlp->ih_cb_arg2; 4760360e6f5eSmathue handler.handler_id = (uint32_t)(uintptr_t)rdip; 47617c478bd9Sstevel@tonic-gate 47627c478bd9Sstevel@tonic-gate /* 47637c478bd9Sstevel@tonic-gate * check if multifunction and do the right thing 47647c478bd9Sstevel@tonic-gate * we put an intercept in between the mfc handler and 47657c478bd9Sstevel@tonic-gate * us so we can catch and process. We might be able 47667c478bd9Sstevel@tonic-gate * to optimize this depending on the card features 47677c478bd9Sstevel@tonic-gate * (a future option). 47687c478bd9Sstevel@tonic-gate */ 47697c478bd9Sstevel@tonic-gate if (ppd->ppd_flags & PPD_CARD_MULTI) { 47707c478bd9Sstevel@tonic-gate inthandler_t *intr; 47717c478bd9Sstevel@tonic-gate /* 47727c478bd9Sstevel@tonic-gate * note that the first function is a special 47737c478bd9Sstevel@tonic-gate * case since it sets things up. We fall through 47747c478bd9Sstevel@tonic-gate * to the lower code and get the hardware set up. 47757c478bd9Sstevel@tonic-gate * subsequent times we just lock the list and insert 47767c478bd9Sstevel@tonic-gate * the handler and all is well. 47777c478bd9Sstevel@tonic-gate */ 47787c478bd9Sstevel@tonic-gate intr = kmem_zalloc(sizeof (inthandler_t), KM_NOSLEEP); 47797c478bd9Sstevel@tonic-gate if (intr == NULL) { 47807c478bd9Sstevel@tonic-gate sockp->ls_error = BAD_IRQ; 47817c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 47827c478bd9Sstevel@tonic-gate } 47837c478bd9Sstevel@tonic-gate intr->intr = hdlp->ih_cb_func; 4784360e6f5eSmathue intr->handler_id = (uint_t)(uintptr_t)rdip; 47857c478bd9Sstevel@tonic-gate intr->arg1 = hdlp->ih_cb_arg1; 47867c478bd9Sstevel@tonic-gate intr->arg2 = hdlp->ih_cb_arg2; 47877c478bd9Sstevel@tonic-gate intr->socket = socket; 47887c478bd9Sstevel@tonic-gate 47897c478bd9Sstevel@tonic-gate mutex_enter(&sockp->ls_ilock); 47907c478bd9Sstevel@tonic-gate if (sockp->ls_inthandlers == NULL) { 47917c478bd9Sstevel@tonic-gate intr->next = intr->prev = intr; 47927c478bd9Sstevel@tonic-gate sockp->ls_inthandlers = intr; 47937c478bd9Sstevel@tonic-gate sockp->ls_mfintr_dip = rdip; 47947c478bd9Sstevel@tonic-gate mutex_exit(&sockp->ls_ilock); 47957c478bd9Sstevel@tonic-gate 47967c478bd9Sstevel@tonic-gate /* 47977c478bd9Sstevel@tonic-gate * replace first function handler with 47987c478bd9Sstevel@tonic-gate * the mfc handler 47997c478bd9Sstevel@tonic-gate */ 48007c478bd9Sstevel@tonic-gate handler.handler = (f_tt *)pcmcia_mfc_intr; 48017c478bd9Sstevel@tonic-gate handler.arg1 = (caddr_t)sockp; 48027c478bd9Sstevel@tonic-gate handler.arg2 = NULL; 48037c478bd9Sstevel@tonic-gate } else { 48047c478bd9Sstevel@tonic-gate insque(intr, sockp->ls_inthandlers); 48057c478bd9Sstevel@tonic-gate mutex_exit(&sockp->ls_ilock); 48067c478bd9Sstevel@tonic-gate 48077c478bd9Sstevel@tonic-gate pispec->intrspec_vec = sockp->ls_intr_vec; 48087c478bd9Sstevel@tonic-gate pispec->intrspec_pri = sockp->ls_intr_pri; 48097c478bd9Sstevel@tonic-gate hdlp->ih_pri = sockp->ls_intr_pri; 48107c478bd9Sstevel@tonic-gate 48117c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 48127c478bd9Sstevel@tonic-gate } 48137c478bd9Sstevel@tonic-gate } 48147c478bd9Sstevel@tonic-gate 48157c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 48167c478bd9Sstevel@tonic-gate if (pcmcia_debug) { 48177c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia_add_intr_impl() let adapter do it\n"); 48187c478bd9Sstevel@tonic-gate } 48197c478bd9Sstevel@tonic-gate #endif 48207c478bd9Sstevel@tonic-gate pispec->intrspec_func = (uint32_t (*)())handler.handler; 48217c478bd9Sstevel@tonic-gate 48227c478bd9Sstevel@tonic-gate /* set default IPL then check for override */ 48237c478bd9Sstevel@tonic-gate 48247c478bd9Sstevel@tonic-gate pispec->intrspec_pri = sockp->ls_intr_pri; 48257c478bd9Sstevel@tonic-gate hdlp->ih_pri = pispec->intrspec_pri; 48267c478bd9Sstevel@tonic-gate 48277c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 48287c478bd9Sstevel@tonic-gate if (pcmcia_debug) { 48297c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia_add_intr_impl() socket=%d irq=%d" 48307c478bd9Sstevel@tonic-gate " handler_id=0X%x handler=%p arg1=%p arg2=%p\n", 48317c478bd9Sstevel@tonic-gate handler.socket, handler.irq, 48327c478bd9Sstevel@tonic-gate handler.handler_id, (void *)handler.handler, handler.arg1, 48337c478bd9Sstevel@tonic-gate handler.arg2); 48347c478bd9Sstevel@tonic-gate } 48357c478bd9Sstevel@tonic-gate #endif 48367c478bd9Sstevel@tonic-gate 48377c478bd9Sstevel@tonic-gate if ((ret = SET_IRQ(sockp->ls_if, adapt->pca_dip, &handler)) != 48387c478bd9Sstevel@tonic-gate SUCCESS) { 48397c478bd9Sstevel@tonic-gate sockp->ls_error = ret; 48407c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 48417c478bd9Sstevel@tonic-gate } 48427c478bd9Sstevel@tonic-gate 48437c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 48447c478bd9Sstevel@tonic-gate if (pcmcia_debug) { 48457c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia_add_intr_impl()" 48467c478bd9Sstevel@tonic-gate " iblk_cookie=%p idev_cookie=%p\n" 48477c478bd9Sstevel@tonic-gate " ls_flags=0X%x PCS_COOKIES_VALID=0X%x\n", 48487c478bd9Sstevel@tonic-gate (void *)handler.iblk_cookie, 48497c478bd9Sstevel@tonic-gate (void *)handler.idev_cookie, 48507c478bd9Sstevel@tonic-gate sockp->ls_flags, PCS_COOKIES_VALID); 48517c478bd9Sstevel@tonic-gate } 48527c478bd9Sstevel@tonic-gate #endif 48537c478bd9Sstevel@tonic-gate 48547c478bd9Sstevel@tonic-gate if (!(sockp->ls_flags & PCS_COOKIES_VALID)) { 4855360e6f5eSmathue hdlp->ih_pri = (uint_t)(uintptr_t)*handler.iblk_cookie; 48567c478bd9Sstevel@tonic-gate sockp->ls_iblk = *handler.iblk_cookie; 48577c478bd9Sstevel@tonic-gate sockp->ls_idev = *handler.idev_cookie; 48587c478bd9Sstevel@tonic-gate sockp->ls_flags |= PCS_COOKIES_VALID; 48597c478bd9Sstevel@tonic-gate } 48607c478bd9Sstevel@tonic-gate 48617c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 48627c478bd9Sstevel@tonic-gate } 48637c478bd9Sstevel@tonic-gate 48647c478bd9Sstevel@tonic-gate void 48657c478bd9Sstevel@tonic-gate pcmcia_remove_intr_impl(dev_info_t *dip, dev_info_t *rdip, 48667c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp) 48677c478bd9Sstevel@tonic-gate { 48687c478bd9Sstevel@tonic-gate 48697c478bd9Sstevel@tonic-gate struct pcmcia_parent_private *ppd; 48707c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t *sockp; 48717c478bd9Sstevel@tonic-gate clear_irq_handler_t handler; 48727c478bd9Sstevel@tonic-gate struct intrspec *pispec; 48737c478bd9Sstevel@tonic-gate int socket; 48747c478bd9Sstevel@tonic-gate 48757c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 48767c478bd9Sstevel@tonic-gate if (pcmcia_debug) { 48777c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia_remove_intr_impl() entered" 48787c478bd9Sstevel@tonic-gate " dip=%p rdip=%p hdlp=%p\n", 48797c478bd9Sstevel@tonic-gate (void *)dip, (void *)rdip, (void *)hdlp); 48807c478bd9Sstevel@tonic-gate } 48817c478bd9Sstevel@tonic-gate #endif 48827c478bd9Sstevel@tonic-gate 48837c478bd9Sstevel@tonic-gate ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(rdip); 48847c478bd9Sstevel@tonic-gate socket = ppd->ppd_socket; 48857c478bd9Sstevel@tonic-gate sockp = pcmcia_sockets[socket]; 48867c478bd9Sstevel@tonic-gate pispec = ppd->ppd_intrspec; 48877c478bd9Sstevel@tonic-gate 48887c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 48897c478bd9Sstevel@tonic-gate if (pcmcia_debug) { 48907c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia_remove_intr_impl()" 48917c478bd9Sstevel@tonic-gate " ls_inthandlers=%p ls_intrspec=%p\n", 48927c478bd9Sstevel@tonic-gate (void *)sockp->ls_inthandlers, 48937c478bd9Sstevel@tonic-gate (void *)&sockp->ls_intrspec); 48947c478bd9Sstevel@tonic-gate } 48957c478bd9Sstevel@tonic-gate #endif 48967c478bd9Sstevel@tonic-gate 48977c478bd9Sstevel@tonic-gate /* first handle the multifunction case since it is simple */ 48987c478bd9Sstevel@tonic-gate mutex_enter(&sockp->ls_ilock); 4899a195726fSgovinda if (sockp->ls_inthandlers != NULL) { 49007c478bd9Sstevel@tonic-gate /* we must be MFC */ 49017c478bd9Sstevel@tonic-gate inthandler_t *intr; 49027c478bd9Sstevel@tonic-gate int remhandler = 0; 49037c478bd9Sstevel@tonic-gate intr = sockp->ls_inthandlers; 49047c478bd9Sstevel@tonic-gate 49057c478bd9Sstevel@tonic-gate /* Check if there is only one handler left */ 49067c478bd9Sstevel@tonic-gate if ((intr->next == intr) && (intr->prev == intr)) { 4907360e6f5eSmathue if (intr->handler_id == (unsigned)(uintptr_t)rdip) { 49087c478bd9Sstevel@tonic-gate sockp->ls_inthandlers = NULL; 49097c478bd9Sstevel@tonic-gate remhandler++; 49107c478bd9Sstevel@tonic-gate kmem_free(intr, sizeof (inthandler_t)); 49117c478bd9Sstevel@tonic-gate } 49127c478bd9Sstevel@tonic-gate } else { 49137c478bd9Sstevel@tonic-gate inthandler_t *first; 49147c478bd9Sstevel@tonic-gate int done; 49157c478bd9Sstevel@tonic-gate 49167c478bd9Sstevel@tonic-gate for (done = 0, first = intr; !done; intr = intr->next) { 49177c478bd9Sstevel@tonic-gate if (intr->next == first) 49187c478bd9Sstevel@tonic-gate done++; 4919360e6f5eSmathue if (intr->handler_id == 4920360e6f5eSmathue (unsigned)(uintptr_t)rdip) { 49217c478bd9Sstevel@tonic-gate done++; 49227c478bd9Sstevel@tonic-gate 49237c478bd9Sstevel@tonic-gate /* 49247c478bd9Sstevel@tonic-gate * If we're about to remove the 49257c478bd9Sstevel@tonic-gate * handler at the head of 49267c478bd9Sstevel@tonic-gate * the list, make the next 49277c478bd9Sstevel@tonic-gate * handler in line the head. 49287c478bd9Sstevel@tonic-gate */ 49297c478bd9Sstevel@tonic-gate if (sockp->ls_inthandlers == intr) 49307c478bd9Sstevel@tonic-gate sockp->ls_inthandlers = 49317c478bd9Sstevel@tonic-gate intr->next; 49327c478bd9Sstevel@tonic-gate 49337c478bd9Sstevel@tonic-gate remque(intr); 49347c478bd9Sstevel@tonic-gate kmem_free(intr, sizeof (inthandler_t)); 49357c478bd9Sstevel@tonic-gate break; 49367c478bd9Sstevel@tonic-gate } /* handler_id */ 49377c478bd9Sstevel@tonic-gate } /* for */ 49387c478bd9Sstevel@tonic-gate } /* intr->next */ 49397c478bd9Sstevel@tonic-gate 49407c478bd9Sstevel@tonic-gate if (!remhandler) { 49417c478bd9Sstevel@tonic-gate mutex_exit(&sockp->ls_ilock); 49427c478bd9Sstevel@tonic-gate return; 49437c478bd9Sstevel@tonic-gate } 49447c478bd9Sstevel@tonic-gate 49457c478bd9Sstevel@tonic-gate /* need to get the dip that was used to add the handler */ 49467c478bd9Sstevel@tonic-gate rdip = sockp->ls_mfintr_dip; 49477c478bd9Sstevel@tonic-gate } 49487c478bd9Sstevel@tonic-gate 4949a195726fSgovinda mutex_exit(&sockp->ls_ilock); 49507c478bd9Sstevel@tonic-gate 49517c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 49527c478bd9Sstevel@tonic-gate if (pcmcia_debug) { 49537c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia_remove_intr_impl()" 49547c478bd9Sstevel@tonic-gate " pispec=%p rdip=%p\n", 49557c478bd9Sstevel@tonic-gate (void *)pispec, (void *)rdip); 49567c478bd9Sstevel@tonic-gate } 49577c478bd9Sstevel@tonic-gate #endif 49587c478bd9Sstevel@tonic-gate 49597c478bd9Sstevel@tonic-gate handler.socket = sockp->ls_socket; 4960360e6f5eSmathue handler.handler_id = (uint32_t)(uintptr_t)rdip; 49617c478bd9Sstevel@tonic-gate handler.handler = (f_tt *)pispec->intrspec_func; 49627c478bd9Sstevel@tonic-gate CLEAR_IRQ(sockp->ls_if, dip, &handler); 49637c478bd9Sstevel@tonic-gate } 49647c478bd9Sstevel@tonic-gate 49657c478bd9Sstevel@tonic-gate 49667c478bd9Sstevel@tonic-gate /* Consolidated interrupt processing interface */ 49677c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 49687c478bd9Sstevel@tonic-gate int 49697c478bd9Sstevel@tonic-gate pcmcia_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op, 49707c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, void *result) 49717c478bd9Sstevel@tonic-gate { 4972a195726fSgovinda int ret = DDI_SUCCESS; 49737c478bd9Sstevel@tonic-gate 49747c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 49757c478bd9Sstevel@tonic-gate if (pcmcia_debug) { 49767c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia_intr_ops() intr_op=%d\n", 49777c478bd9Sstevel@tonic-gate (int)intr_op); 49787c478bd9Sstevel@tonic-gate } 49797c478bd9Sstevel@tonic-gate #endif 49807c478bd9Sstevel@tonic-gate 49817c478bd9Sstevel@tonic-gate switch (intr_op) { 49827c478bd9Sstevel@tonic-gate case DDI_INTROP_GETCAP: 4983a195726fSgovinda *(int *)result = DDI_INTR_FLAG_LEVEL; 49847c478bd9Sstevel@tonic-gate break; 49857c478bd9Sstevel@tonic-gate case DDI_INTROP_SETCAP: 49867c478bd9Sstevel@tonic-gate ret = DDI_ENOTSUP; 49877c478bd9Sstevel@tonic-gate break; 49887c478bd9Sstevel@tonic-gate case DDI_INTROP_ALLOC: 49897c478bd9Sstevel@tonic-gate *(int *)result = hdlp->ih_scratch1; 49907c478bd9Sstevel@tonic-gate break; 49917c478bd9Sstevel@tonic-gate case DDI_INTROP_FREE: 49927c478bd9Sstevel@tonic-gate break; 49937c478bd9Sstevel@tonic-gate case DDI_INTROP_GETPRI: 49947c478bd9Sstevel@tonic-gate if (pcmcia_add_intr_impl(dip, rdip, hdlp) != DDI_SUCCESS) 49957c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 49967c478bd9Sstevel@tonic-gate *(int *)result = hdlp->ih_pri; 49977c478bd9Sstevel@tonic-gate pcmcia_remove_intr_impl(dip, rdip, hdlp); 49987c478bd9Sstevel@tonic-gate break; 49997c478bd9Sstevel@tonic-gate case DDI_INTROP_SETPRI: 50007c478bd9Sstevel@tonic-gate break; 50017c478bd9Sstevel@tonic-gate case DDI_INTROP_ADDISR: 50027c478bd9Sstevel@tonic-gate ret = pcmcia_add_intr_impl(dip, rdip, hdlp); 50037c478bd9Sstevel@tonic-gate break; 50047c478bd9Sstevel@tonic-gate case DDI_INTROP_REMISR: 50057c478bd9Sstevel@tonic-gate pcmcia_remove_intr_impl(dip, rdip, hdlp); 50067c478bd9Sstevel@tonic-gate break; 50077c478bd9Sstevel@tonic-gate case DDI_INTROP_ENABLE: 50087c478bd9Sstevel@tonic-gate case DDI_INTROP_DISABLE: 50097c478bd9Sstevel@tonic-gate break; 50107c478bd9Sstevel@tonic-gate case DDI_INTROP_NINTRS: 50117c478bd9Sstevel@tonic-gate case DDI_INTROP_NAVAIL: 5012a54f81fbSanish *(int *)result = i_ddi_get_intx_nintrs(rdip); 50137c478bd9Sstevel@tonic-gate break; 50147c478bd9Sstevel@tonic-gate case DDI_INTROP_SUPPORTED_TYPES: 50157c478bd9Sstevel@tonic-gate /* PCI nexus driver supports only fixed interrupts */ 5016a54f81fbSanish *(int *)result = i_ddi_get_intx_nintrs(rdip) ? 50177c478bd9Sstevel@tonic-gate DDI_INTR_TYPE_FIXED : 0; 50187c478bd9Sstevel@tonic-gate break; 50197c478bd9Sstevel@tonic-gate default: 50207c478bd9Sstevel@tonic-gate ret = DDI_ENOTSUP; 50217c478bd9Sstevel@tonic-gate break; 50227c478bd9Sstevel@tonic-gate } 50237c478bd9Sstevel@tonic-gate 50247c478bd9Sstevel@tonic-gate return (ret); 50257c478bd9Sstevel@tonic-gate } 50267c478bd9Sstevel@tonic-gate 50277c478bd9Sstevel@tonic-gate #elif defined(__x86) || defined(__amd64) 50287c478bd9Sstevel@tonic-gate 50297c478bd9Sstevel@tonic-gate static struct intrspec *pcmcia_intr_get_ispec(dev_info_t *, int, 50307c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t **); 50317c478bd9Sstevel@tonic-gate static struct intrspec *pcmcia_intr_add_isr(dev_info_t *, dev_info_t *, 50327c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *); 50337c478bd9Sstevel@tonic-gate static int pcmcia_intr_enable_isr(dev_info_t *, dev_info_t *, 50347c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *); 50357c478bd9Sstevel@tonic-gate static void pcmcia_intr_remove_isr(dev_info_t *, dev_info_t *, 50367c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *); 50377c478bd9Sstevel@tonic-gate static void pcmcia_intr_disable_isr(dev_info_t *, dev_info_t *, 50387c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *); 50397c478bd9Sstevel@tonic-gate 50407c478bd9Sstevel@tonic-gate /* 50417c478bd9Sstevel@tonic-gate * pcmcia_intr_get_ispec: 50427c478bd9Sstevel@tonic-gate * This is mostly copied from older 'pcmcia_get_intrspec' function 50437c478bd9Sstevel@tonic-gate */ 50447c478bd9Sstevel@tonic-gate static struct intrspec * 50457c478bd9Sstevel@tonic-gate pcmcia_intr_get_ispec(dev_info_t *rdip, int inum, 50467c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t **sockp) 50477c478bd9Sstevel@tonic-gate { 50487c478bd9Sstevel@tonic-gate int socket; 50497c478bd9Sstevel@tonic-gate struct intrspec *intrspec; 50507c478bd9Sstevel@tonic-gate struct pcmcia_parent_private *ppd; 50517c478bd9Sstevel@tonic-gate 50527c478bd9Sstevel@tonic-gate if ((int)inum > 0 || (ddi_getprop(DDI_DEV_T_ANY, rdip, 50537c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "interrupts", -1) < 0)) 50547c478bd9Sstevel@tonic-gate return (NULL); 50557c478bd9Sstevel@tonic-gate 50567c478bd9Sstevel@tonic-gate ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(rdip); 50577c478bd9Sstevel@tonic-gate if (ppd == NULL || ppd->ppd_intrspec == NULL) 50587c478bd9Sstevel@tonic-gate return (NULL); 50597c478bd9Sstevel@tonic-gate 50607c478bd9Sstevel@tonic-gate if ((socket = ppd->ppd_socket) < 0) 50617c478bd9Sstevel@tonic-gate return (NULL); 50627c478bd9Sstevel@tonic-gate 50637c478bd9Sstevel@tonic-gate if ((*sockp = pcmcia_sockets[socket]) == NULL) 50647c478bd9Sstevel@tonic-gate return (NULL); 50657c478bd9Sstevel@tonic-gate 50667c478bd9Sstevel@tonic-gate intrspec = ppd->ppd_intrspec; 50677c478bd9Sstevel@tonic-gate if (intrspec->intrspec_vec == 0 && (*sockp)->ls_intr_vec != 0) 50687c478bd9Sstevel@tonic-gate intrspec->intrspec_vec = (*sockp)->ls_intr_vec; 50697c478bd9Sstevel@tonic-gate 50707c478bd9Sstevel@tonic-gate return (intrspec); 50717c478bd9Sstevel@tonic-gate } 50727c478bd9Sstevel@tonic-gate 50737c478bd9Sstevel@tonic-gate static struct intrspec * 50747c478bd9Sstevel@tonic-gate pcmcia_intr_add_isr(dev_info_t *dip, dev_info_t *rdip, 50757c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp) 50767c478bd9Sstevel@tonic-gate { 50777c478bd9Sstevel@tonic-gate int socket; 50787c478bd9Sstevel@tonic-gate struct intrspec *ispecp; 50797c478bd9Sstevel@tonic-gate struct pcmcia_adapter *adapt; 50807c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t *sockp; 50817c478bd9Sstevel@tonic-gate struct pcmcia_parent_private *ppd; 50827c478bd9Sstevel@tonic-gate 50837c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 50847c478bd9Sstevel@tonic-gate if (pcmcia_debug) 50857c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia_intr_add_isr: " 50867c478bd9Sstevel@tonic-gate "dip=0x%p rdip=0x%p hdlp=0x%p\n", 50877c478bd9Sstevel@tonic-gate (void *)dip, (void *)rdip, (void *)hdlp); 50887c478bd9Sstevel@tonic-gate #endif /* PCMCIA_DEBUG */ 50897c478bd9Sstevel@tonic-gate 50907c478bd9Sstevel@tonic-gate ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(rdip); 50917c478bd9Sstevel@tonic-gate socket = ppd->ppd_socket; 50927c478bd9Sstevel@tonic-gate sockp = pcmcia_sockets[socket]; 50937c478bd9Sstevel@tonic-gate adapt = sockp->ls_adapter; 50947c478bd9Sstevel@tonic-gate 50957c478bd9Sstevel@tonic-gate ispecp = ppd->ppd_intrspec; 50967c478bd9Sstevel@tonic-gate if (ispecp == NULL) { 50977c478bd9Sstevel@tonic-gate sockp->ls_error = BAD_IRQ; 50987c478bd9Sstevel@tonic-gate return (ispecp); 50997c478bd9Sstevel@tonic-gate } 51007c478bd9Sstevel@tonic-gate 51017c478bd9Sstevel@tonic-gate /* 51027c478bd9Sstevel@tonic-gate * check if multifunction and do the right thing 51037c478bd9Sstevel@tonic-gate * we put an intercept in between the mfc handler and us so we can 51047c478bd9Sstevel@tonic-gate * catch and process. We might be able to optimize this depending 51057c478bd9Sstevel@tonic-gate * on the card features (a future option). 51067c478bd9Sstevel@tonic-gate */ 51077c478bd9Sstevel@tonic-gate if (ppd->ppd_flags & PPD_CARD_MULTI && 51087c478bd9Sstevel@tonic-gate hdlp->ih_cb_func != pcmcia_mfc_intr) { 51097c478bd9Sstevel@tonic-gate inthandler_t *intr; 51107c478bd9Sstevel@tonic-gate 51117c478bd9Sstevel@tonic-gate /* 51127c478bd9Sstevel@tonic-gate * note that the first function is a special case since it 51137c478bd9Sstevel@tonic-gate * sets things up. We fall through to the lower code and 51147c478bd9Sstevel@tonic-gate * get the hardware set up. Subsequent times we just lock 51157c478bd9Sstevel@tonic-gate * the list and insert the handler and all is well. 51167c478bd9Sstevel@tonic-gate */ 51177c478bd9Sstevel@tonic-gate intr = kmem_zalloc(sizeof (inthandler_t), KM_NOSLEEP); 51187c478bd9Sstevel@tonic-gate if (intr == NULL) { 51197c478bd9Sstevel@tonic-gate sockp->ls_error = BAD_IRQ; 51207c478bd9Sstevel@tonic-gate return (NULL); 51217c478bd9Sstevel@tonic-gate } 51227c478bd9Sstevel@tonic-gate 51237c478bd9Sstevel@tonic-gate intr->intr = (uint32_t (*)())hdlp->ih_cb_func; 51247c478bd9Sstevel@tonic-gate intr->handler_id = (uint32_t)(uintptr_t)rdip; 51257c478bd9Sstevel@tonic-gate intr->arg1 = hdlp->ih_cb_arg1; 51267c478bd9Sstevel@tonic-gate intr->arg2 = hdlp->ih_cb_arg2; 51277c478bd9Sstevel@tonic-gate intr->socket = socket; 51287c478bd9Sstevel@tonic-gate mutex_enter(&sockp->ls_ilock); 51297c478bd9Sstevel@tonic-gate if (sockp->ls_inthandlers == NULL) { 51307c478bd9Sstevel@tonic-gate intr->next = intr->prev = intr; 51317c478bd9Sstevel@tonic-gate sockp->ls_inthandlers = intr; 51327c478bd9Sstevel@tonic-gate sockp->ls_mfintr_dip = rdip; 51337c478bd9Sstevel@tonic-gate } else { 51347c478bd9Sstevel@tonic-gate insque(intr, sockp->ls_inthandlers); 51357c478bd9Sstevel@tonic-gate } 51367c478bd9Sstevel@tonic-gate mutex_exit(&sockp->ls_ilock); 51377c478bd9Sstevel@tonic-gate return (ispecp); 51387c478bd9Sstevel@tonic-gate } 51397c478bd9Sstevel@tonic-gate 51407c478bd9Sstevel@tonic-gate /* 51417c478bd9Sstevel@tonic-gate * Do we need to allocate an IRQ at this point or not? 51427c478bd9Sstevel@tonic-gate */ 51437c478bd9Sstevel@tonic-gate if (adapt->pca_flags & PCA_RES_NEED_IRQ) { 51447c478bd9Sstevel@tonic-gate int i, irq; 51457c478bd9Sstevel@tonic-gate 51467c478bd9Sstevel@tonic-gate /* 51477c478bd9Sstevel@tonic-gate * this adapter needs IRQ allocations 51487c478bd9Sstevel@tonic-gate * this is only necessary if it is the first function on the 51497c478bd9Sstevel@tonic-gate * card being setup. The socket will keep the allocation info 51507c478bd9Sstevel@tonic-gate */ 51517c478bd9Sstevel@tonic-gate /* all functions use same intrspec except mfc handler */ 51527c478bd9Sstevel@tonic-gate if (hdlp->ih_cb_func == pcmcia_mfc_intr) { 51537c478bd9Sstevel@tonic-gate /* 51547c478bd9Sstevel@tonic-gate * We treat this special in order to allow things to 51557c478bd9Sstevel@tonic-gate * work properly for MFC cards. The intrspec for the 51567c478bd9Sstevel@tonic-gate * mfc dispatcher is intercepted and taken from the 51577c478bd9Sstevel@tonic-gate * logical socket in order to not be trying to 51587c478bd9Sstevel@tonic-gate * multiplex the meaning when ENABLE is called. 51597c478bd9Sstevel@tonic-gate */ 51607c478bd9Sstevel@tonic-gate ispecp = &sockp->ls_intrspec; 51617a364d25Sschwartz ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispecp; 51627c478bd9Sstevel@tonic-gate } 51637c478bd9Sstevel@tonic-gate 51647c478bd9Sstevel@tonic-gate if (adapt->pca_flags & PCA_IRQ_ISA) { 51657c478bd9Sstevel@tonic-gate for (irq = -1, i = 1; irq == -1 && i < 16; i++) { 51667c478bd9Sstevel@tonic-gate /* find available and usable IRQ level */ 51677c478bd9Sstevel@tonic-gate if (adapt->pca_avail_intr & (1 << i)) 51687c478bd9Sstevel@tonic-gate irq = pcmcia_get_intr(dip, i); 51697c478bd9Sstevel@tonic-gate } 51707c478bd9Sstevel@tonic-gate } 51717c478bd9Sstevel@tonic-gate if (irq < 0) { 51727c478bd9Sstevel@tonic-gate sockp->ls_error = NO_RESOURCE; 51737c478bd9Sstevel@tonic-gate return (NULL); 51747c478bd9Sstevel@tonic-gate } 51757c478bd9Sstevel@tonic-gate hdlp->ih_vector = sockp->ls_intr_vec = irq; 51767c478bd9Sstevel@tonic-gate 51777c478bd9Sstevel@tonic-gate 51787c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 51797c478bd9Sstevel@tonic-gate if (pcmcia_debug) 51807c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "allocated irq=%x\n", irq); 51817c478bd9Sstevel@tonic-gate #endif /* PCMCIA_DEBUG */ 51827c478bd9Sstevel@tonic-gate 51837c478bd9Sstevel@tonic-gate ispecp->intrspec_vec = sockp->ls_intr_vec; 51847c478bd9Sstevel@tonic-gate ispecp->intrspec_pri = sockp->ls_intr_pri; 51857c478bd9Sstevel@tonic-gate return (ispecp); 51867c478bd9Sstevel@tonic-gate } 51877c478bd9Sstevel@tonic-gate 51887c478bd9Sstevel@tonic-gate if (ispecp->intrspec_func != NULL) 51897c478bd9Sstevel@tonic-gate ispecp->intrspec_func = hdlp->ih_cb_func; 51907c478bd9Sstevel@tonic-gate 51917c478bd9Sstevel@tonic-gate /* set default IPL then check for override */ 51927c478bd9Sstevel@tonic-gate ispecp->intrspec_pri = sockp->ls_intr_pri; 51937c478bd9Sstevel@tonic-gate return (ispecp); 51947c478bd9Sstevel@tonic-gate } 51957c478bd9Sstevel@tonic-gate 51967c478bd9Sstevel@tonic-gate 51977c478bd9Sstevel@tonic-gate static int 51987c478bd9Sstevel@tonic-gate pcmcia_intr_enable_isr(dev_info_t *dip, dev_info_t *rdip, 51997c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp) 52007c478bd9Sstevel@tonic-gate { 52017c478bd9Sstevel@tonic-gate int socket, ret; 52027c478bd9Sstevel@tonic-gate int irq = 0; /* default case */ 52037c478bd9Sstevel@tonic-gate dev_info_t *parent = ddi_root_node(); 52047c478bd9Sstevel@tonic-gate struct intrspec *ispecp; 52057c478bd9Sstevel@tonic-gate set_irq_handler_t handler; 52067c478bd9Sstevel@tonic-gate struct pcmcia_adapter *adapt; 52077c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t *sockp; 52087c478bd9Sstevel@tonic-gate struct pcmcia_parent_private *ppd; 52097c478bd9Sstevel@tonic-gate 52107c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 52117c478bd9Sstevel@tonic-gate if (pcmcia_debug) 52127c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia_intr_enable_isr: " 52137c478bd9Sstevel@tonic-gate "dip=0x%p rdip=0x%p hdlp=0x%p\n", 52147c478bd9Sstevel@tonic-gate (void *)dip, (void *)rdip, (void *)hdlp); 52157c478bd9Sstevel@tonic-gate #endif /* PCMCIA_DEBUG */ 52167c478bd9Sstevel@tonic-gate 52177c478bd9Sstevel@tonic-gate ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(rdip); 52187c478bd9Sstevel@tonic-gate socket = ppd->ppd_socket; 52197c478bd9Sstevel@tonic-gate sockp = pcmcia_sockets[socket]; 52207c478bd9Sstevel@tonic-gate adapt = sockp->ls_adapter; 52217c478bd9Sstevel@tonic-gate 52227c478bd9Sstevel@tonic-gate ispecp = ppd->ppd_intrspec; 52237c478bd9Sstevel@tonic-gate ASSERT(ispecp); 52247c478bd9Sstevel@tonic-gate 52257c478bd9Sstevel@tonic-gate mutex_enter(&sockp->ls_ilock); 52267c478bd9Sstevel@tonic-gate if ((sockp->ls_inthandlers != NULL) && 52277a364d25Sschwartz ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp != 52287a364d25Sschwartz &sockp->ls_intrspec) { 52297c478bd9Sstevel@tonic-gate inthandler_t *intr = sockp->ls_inthandlers; 52307c478bd9Sstevel@tonic-gate 52317c478bd9Sstevel@tonic-gate ASSERT(ppd->ppd_flags & PPD_CARD_MULTI); 52327c478bd9Sstevel@tonic-gate 52337c478bd9Sstevel@tonic-gate /* Only one handler. So, call ddi_add_intr on it */ 52347c478bd9Sstevel@tonic-gate if ((intr->next == intr) && (intr->prev == intr)) { 52357c478bd9Sstevel@tonic-gate hdlp->ih_cb_func = pcmcia_mfc_intr; 52367c478bd9Sstevel@tonic-gate hdlp->ih_cb_arg1 = (caddr_t)sockp; 52377c478bd9Sstevel@tonic-gate hdlp->ih_cb_arg2 = NULL; 52387c478bd9Sstevel@tonic-gate 52397c478bd9Sstevel@tonic-gate ret = (*(DEVI(parent)->devi_ops->devo_bus_ops-> 52407c478bd9Sstevel@tonic-gate bus_intr_op))(parent, rdip, DDI_INTROP_ENABLE, 52417c478bd9Sstevel@tonic-gate hdlp, NULL); 52427c478bd9Sstevel@tonic-gate 52437c478bd9Sstevel@tonic-gate if (ret == DDI_FAILURE) { 52447c478bd9Sstevel@tonic-gate sockp->ls_inthandlers = NULL; 52457c478bd9Sstevel@tonic-gate kmem_free(intr, sizeof (inthandler_t)); 52467c478bd9Sstevel@tonic-gate sockp->ls_error = BAD_IRQ; 52477c478bd9Sstevel@tonic-gate mutex_exit(&sockp->ls_ilock); 52487c478bd9Sstevel@tonic-gate return (ret); 52497c478bd9Sstevel@tonic-gate } 52507c478bd9Sstevel@tonic-gate } 52517c478bd9Sstevel@tonic-gate mutex_exit(&sockp->ls_ilock); 52527c478bd9Sstevel@tonic-gate hdlp->ih_vector = ispecp->intrspec_vec = sockp->ls_intr_vec; 52537c478bd9Sstevel@tonic-gate hdlp->ih_pri = sockp->ls_intr_pri; 5254abdbd06dSagiri sockp->ls_iblk = (ddi_iblock_cookie_t)(uintptr_t) 52557c478bd9Sstevel@tonic-gate sockp->ls_intr_pri; 52567c478bd9Sstevel@tonic-gate sockp->ls_idev.idev_vector = (ushort_t)hdlp->ih_vector; 52577c478bd9Sstevel@tonic-gate sockp->ls_idev.idev_priority = (ushort_t)sockp->ls_intr_pri; 52587c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 52597c478bd9Sstevel@tonic-gate } 52607c478bd9Sstevel@tonic-gate mutex_exit(&sockp->ls_ilock); 52617c478bd9Sstevel@tonic-gate 52627c478bd9Sstevel@tonic-gate if (adapt->pca_flags & PCA_RES_NEED_IRQ) { 52637c478bd9Sstevel@tonic-gate if (hdlp->ih_cb_func == pcmcia_mfc_intr) 52647c478bd9Sstevel@tonic-gate ispecp = (struct intrspec *)&sockp->ls_intrspec; 52657c478bd9Sstevel@tonic-gate 52667c478bd9Sstevel@tonic-gate /* XXX: remove it later as this is done in _add_isr as well */ 52677c478bd9Sstevel@tonic-gate ispecp->intrspec_vec = sockp->ls_intr_vec; 52687c478bd9Sstevel@tonic-gate ispecp->intrspec_pri = sockp->ls_intr_pri; 52697c478bd9Sstevel@tonic-gate 52707c478bd9Sstevel@tonic-gate /* Enable interrupts */ 52717c478bd9Sstevel@tonic-gate ret = (*(DEVI(parent)->devi_ops->devo_bus_ops->bus_intr_op))( 52727c478bd9Sstevel@tonic-gate parent, rdip, DDI_INTROP_ENABLE, hdlp, NULL); 52737c478bd9Sstevel@tonic-gate 5274abdbd06dSagiri sockp->ls_iblk = (ddi_iblock_cookie_t)(uintptr_t) 52757c478bd9Sstevel@tonic-gate sockp->ls_intr_pri; 52767c478bd9Sstevel@tonic-gate sockp->ls_idev.idev_vector = (ushort_t)sockp->ls_intr_vec; 52777c478bd9Sstevel@tonic-gate sockp->ls_idev.idev_priority = (ushort_t)sockp->ls_intr_pri; 52787c478bd9Sstevel@tonic-gate 52797c478bd9Sstevel@tonic-gate if (ret != DDI_SUCCESS) 52807c478bd9Sstevel@tonic-gate sockp->ls_error = BAD_IRQ; 52817c478bd9Sstevel@tonic-gate return (ret); 52827c478bd9Sstevel@tonic-gate } 52837c478bd9Sstevel@tonic-gate 52847c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 52857c478bd9Sstevel@tonic-gate if (pcmcia_debug) 52867c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia_intr_enable_isr; let adapter do it\n"); 52877c478bd9Sstevel@tonic-gate #endif /* PCMCIA_DEBUG */ 52887c478bd9Sstevel@tonic-gate 52897c478bd9Sstevel@tonic-gate handler.socket = sockp->ls_socket; 52907c478bd9Sstevel@tonic-gate handler.irq = irq; 52917c478bd9Sstevel@tonic-gate handler.handler = (f_tt *)hdlp->ih_cb_func; 52927c478bd9Sstevel@tonic-gate handler.arg1 = hdlp->ih_cb_arg1; 52937c478bd9Sstevel@tonic-gate handler.arg2 = hdlp->ih_cb_arg2; 52947c478bd9Sstevel@tonic-gate handler.handler_id = (uint32_t)(uintptr_t)rdip; 52957c478bd9Sstevel@tonic-gate if (ispecp->intrspec_func != NULL) 52967c478bd9Sstevel@tonic-gate ispecp->intrspec_func = hdlp->ih_cb_func; 52977c478bd9Sstevel@tonic-gate 52987c478bd9Sstevel@tonic-gate /* set default IPL then check for override */ 52997c478bd9Sstevel@tonic-gate ispecp->intrspec_pri = sockp->ls_intr_pri; 53007c478bd9Sstevel@tonic-gate 53017c478bd9Sstevel@tonic-gate if ((ret = SET_IRQ(sockp->ls_if, adapt->pca_dip, &handler)) != 53027c478bd9Sstevel@tonic-gate SUCCESS) { 53037c478bd9Sstevel@tonic-gate sockp->ls_error = ret; 53047c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 53057c478bd9Sstevel@tonic-gate } 53067c478bd9Sstevel@tonic-gate ispecp->intrspec_func = hdlp->ih_cb_func; 53077c478bd9Sstevel@tonic-gate if (!(sockp->ls_flags & PCS_COOKIES_VALID)) { 53087c478bd9Sstevel@tonic-gate sockp->ls_iblk = *handler.iblk_cookie; 53097c478bd9Sstevel@tonic-gate sockp->ls_idev = *handler.idev_cookie; 53107c478bd9Sstevel@tonic-gate sockp->ls_flags |= PCS_COOKIES_VALID; 53117c478bd9Sstevel@tonic-gate } 53127c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 53137c478bd9Sstevel@tonic-gate } 53147c478bd9Sstevel@tonic-gate 53157c478bd9Sstevel@tonic-gate /* ARGSUSED */ 53167c478bd9Sstevel@tonic-gate static void 53177c478bd9Sstevel@tonic-gate pcmcia_intr_remove_isr(dev_info_t *dip, dev_info_t *rdip, 53187c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp) 53197c478bd9Sstevel@tonic-gate { 53207c478bd9Sstevel@tonic-gate int done, remhandler = 0; 53217c478bd9Sstevel@tonic-gate inthandler_t *intr, *first; 53227c478bd9Sstevel@tonic-gate struct intrspec *ispecp; 53237c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t *sockp; 53247c478bd9Sstevel@tonic-gate 53257c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 53267c478bd9Sstevel@tonic-gate if (pcmcia_debug) 53277c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia_intr_remove_isr: " 53287c478bd9Sstevel@tonic-gate "dip=0x%p rdip=0x%p hdlp=0x%p\n", 53297c478bd9Sstevel@tonic-gate (void *)dip, (void *)rdip, (void *)hdlp); 53307c478bd9Sstevel@tonic-gate #endif /* PCMCIA_DEBUG */ 53317c478bd9Sstevel@tonic-gate 53327c478bd9Sstevel@tonic-gate ispecp = pcmcia_intr_get_ispec(rdip, hdlp->ih_inum, &sockp); 53337c478bd9Sstevel@tonic-gate ASSERT(ispecp); 53347c478bd9Sstevel@tonic-gate 53357c478bd9Sstevel@tonic-gate /* first handle the multifunction case since it is simple */ 53367c478bd9Sstevel@tonic-gate mutex_enter(&sockp->ls_ilock); 53377c478bd9Sstevel@tonic-gate if (sockp->ls_inthandlers != NULL && 53387a364d25Sschwartz ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp != 53397a364d25Sschwartz &sockp->ls_intrspec) { 53407c478bd9Sstevel@tonic-gate 53417c478bd9Sstevel@tonic-gate intr = sockp->ls_inthandlers; 53427c478bd9Sstevel@tonic-gate 53437c478bd9Sstevel@tonic-gate /* Check if there is only one handler left */ 53447c478bd9Sstevel@tonic-gate if ((intr->next == intr) && (intr->prev == intr)) { 53457c478bd9Sstevel@tonic-gate if (intr->handler_id == (uint32_t)(uintptr_t)rdip) { 53467c478bd9Sstevel@tonic-gate sockp->ls_inthandlers = NULL; 53477c478bd9Sstevel@tonic-gate remhandler++; 53487c478bd9Sstevel@tonic-gate kmem_free(intr, sizeof (inthandler_t)); 53497c478bd9Sstevel@tonic-gate } 53507c478bd9Sstevel@tonic-gate 53517c478bd9Sstevel@tonic-gate } else { 53527c478bd9Sstevel@tonic-gate for (done = 0, first = intr; !done; intr = intr->next) { 53537c478bd9Sstevel@tonic-gate if (intr->next == first) 53547c478bd9Sstevel@tonic-gate done++; 53557c478bd9Sstevel@tonic-gate if (intr->handler_id == 53567c478bd9Sstevel@tonic-gate (uint32_t)(uintptr_t)rdip) { 53577c478bd9Sstevel@tonic-gate done++; 53587c478bd9Sstevel@tonic-gate 53597c478bd9Sstevel@tonic-gate /* 53607c478bd9Sstevel@tonic-gate * If we're about to remove the handler 53617c478bd9Sstevel@tonic-gate * at the head of the list, make the 53627c478bd9Sstevel@tonic-gate * next handler in line the head. 53637c478bd9Sstevel@tonic-gate */ 53647c478bd9Sstevel@tonic-gate if (sockp->ls_inthandlers == intr) 53655c066ec2SJerry Gilliam sockp->ls_inthandlers = 53665c066ec2SJerry Gilliam intr->next; 53677c478bd9Sstevel@tonic-gate 53687c478bd9Sstevel@tonic-gate remque(intr); 53697c478bd9Sstevel@tonic-gate kmem_free(intr, sizeof (inthandler_t)); 53707c478bd9Sstevel@tonic-gate break; 53717c478bd9Sstevel@tonic-gate } /* handler_id */ 53727c478bd9Sstevel@tonic-gate } /* end of for */ 53737c478bd9Sstevel@tonic-gate } /* end of if intr->next */ 53747c478bd9Sstevel@tonic-gate 53757c478bd9Sstevel@tonic-gate if (!remhandler) { 53767c478bd9Sstevel@tonic-gate mutex_exit(&sockp->ls_ilock); 53777c478bd9Sstevel@tonic-gate return; 53787c478bd9Sstevel@tonic-gate } 53797c478bd9Sstevel@tonic-gate } 53807c478bd9Sstevel@tonic-gate mutex_exit(&sockp->ls_ilock); 53817c478bd9Sstevel@tonic-gate 53827c478bd9Sstevel@tonic-gate if (sockp->ls_adapter->pca_flags & PCA_RES_NEED_IRQ) { 53837c478bd9Sstevel@tonic-gate sockp->ls_intr_vec = 0; 53847c478bd9Sstevel@tonic-gate ispecp->intrspec_vec = 0; 53857c478bd9Sstevel@tonic-gate } 53867c478bd9Sstevel@tonic-gate } 53877c478bd9Sstevel@tonic-gate 53887c478bd9Sstevel@tonic-gate 53897c478bd9Sstevel@tonic-gate static void 53907c478bd9Sstevel@tonic-gate pcmcia_intr_disable_isr(dev_info_t *dip, dev_info_t *rdip, 53917c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp) 53927c478bd9Sstevel@tonic-gate { 53937c478bd9Sstevel@tonic-gate int socket, ret; 53947c478bd9Sstevel@tonic-gate dev_info_t *parent; 53957c478bd9Sstevel@tonic-gate struct intrspec *ispecp; 53967c478bd9Sstevel@tonic-gate clear_irq_handler_t handler; 53977c478bd9Sstevel@tonic-gate struct pcmcia_adapter *adapt; 53987c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t *sockp; 53997c478bd9Sstevel@tonic-gate struct pcmcia_parent_private *ppd; 54007a364d25Sschwartz ihdl_plat_t *ihdl_plat_datap = 54015c066ec2SJerry Gilliam (ihdl_plat_t *)hdlp->ih_private; 54027c478bd9Sstevel@tonic-gate 54037c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 54047c478bd9Sstevel@tonic-gate if (pcmcia_debug) 54057c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia_intr_disable_isr: " 54067c478bd9Sstevel@tonic-gate "dip=0x%p rdip=0x%p hdlp=0x%p\n", 54077c478bd9Sstevel@tonic-gate (void *)dip, (void *)rdip, (void *)hdlp); 54087c478bd9Sstevel@tonic-gate #endif /* PCMCIA_DEBUG */ 54097c478bd9Sstevel@tonic-gate 54107c478bd9Sstevel@tonic-gate ppd = (struct pcmcia_parent_private *)ddi_get_parent_data(rdip); 54117c478bd9Sstevel@tonic-gate socket = ppd->ppd_socket; 54127c478bd9Sstevel@tonic-gate sockp = pcmcia_sockets[socket]; 54137c478bd9Sstevel@tonic-gate adapt = sockp->ls_adapter; 54147c478bd9Sstevel@tonic-gate ispecp = ppd->ppd_intrspec; 54157c478bd9Sstevel@tonic-gate ASSERT(ispecp); 54167c478bd9Sstevel@tonic-gate 54177c478bd9Sstevel@tonic-gate mutex_enter(&sockp->ls_ilock); 54187c478bd9Sstevel@tonic-gate if (sockp->ls_inthandlers != NULL && 54197a364d25Sschwartz ihdl_plat_datap->ip_ispecp != &sockp->ls_intrspec) { 54207c478bd9Sstevel@tonic-gate inthandler_t *intr = sockp->ls_inthandlers; 54217c478bd9Sstevel@tonic-gate 54227c478bd9Sstevel@tonic-gate /* Check if there is only one handler left */ 54237c478bd9Sstevel@tonic-gate if ((intr->next == intr) && (intr->prev == intr)) { 54247c478bd9Sstevel@tonic-gate if (intr->handler_id != (uint32_t)(uintptr_t)rdip) 54257c478bd9Sstevel@tonic-gate /* 54267c478bd9Sstevel@tonic-gate * need to get the dip that was 54277c478bd9Sstevel@tonic-gate * used to add the handler 54287c478bd9Sstevel@tonic-gate */ 54297c478bd9Sstevel@tonic-gate rdip = sockp->ls_mfintr_dip; 54307c478bd9Sstevel@tonic-gate ispecp = (struct intrspec *)&sockp->ls_intrspec; 54317c478bd9Sstevel@tonic-gate } else { 54327c478bd9Sstevel@tonic-gate /* Don't call cleanup if list still has members */ 54337c478bd9Sstevel@tonic-gate mutex_exit(&sockp->ls_ilock); 54347c478bd9Sstevel@tonic-gate return; 54357c478bd9Sstevel@tonic-gate } 54367c478bd9Sstevel@tonic-gate } 54377c478bd9Sstevel@tonic-gate mutex_exit(&sockp->ls_ilock); 54387c478bd9Sstevel@tonic-gate 54397a364d25Sschwartz if (ihdl_plat_datap->ip_ispecp == 54407c478bd9Sstevel@tonic-gate (struct intrspec *)&sockp->ls_intrspec) 54417a364d25Sschwartz ispecp = ihdl_plat_datap->ip_ispecp; 54427c478bd9Sstevel@tonic-gate 54437c478bd9Sstevel@tonic-gate if (adapt->pca_flags & PCA_RES_NEED_IRQ) { 54447c478bd9Sstevel@tonic-gate ret = ispecp->intrspec_vec; 54457c478bd9Sstevel@tonic-gate parent = ddi_root_node(); 54467c478bd9Sstevel@tonic-gate ret = (*(DEVI(parent)->devi_ops->devo_bus_ops->bus_intr_op))( 54477c478bd9Sstevel@tonic-gate parent, rdip, DDI_INTROP_DISABLE, hdlp, NULL); 54487c478bd9Sstevel@tonic-gate (void) pcmcia_return_intr(dip, hdlp->ih_vector); 54497c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 54507c478bd9Sstevel@tonic-gate if (pcmcia_debug) 54517c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia_intr_disable_isr: " 54527c478bd9Sstevel@tonic-gate "INTROP_DISABLE returned %x\n", ret); 54537c478bd9Sstevel@tonic-gate #endif /* PCMCIA_DEBUG */ 54547c478bd9Sstevel@tonic-gate } else { 54557c478bd9Sstevel@tonic-gate handler.socket = sockp->ls_socket; 54567c478bd9Sstevel@tonic-gate handler.handler_id = (uint32_t)(uintptr_t)rdip; 54577c478bd9Sstevel@tonic-gate handler.handler = (f_tt *)ispecp->intrspec_func; 54587c478bd9Sstevel@tonic-gate ret = CLEAR_IRQ(sockp->ls_if, dip, &handler); 54597c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 54607c478bd9Sstevel@tonic-gate if (pcmcia_debug) 54617c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia_intr_disable_isr: " 54627c478bd9Sstevel@tonic-gate "CLEAR_IRQ returned %x\n", ret); 54637c478bd9Sstevel@tonic-gate #endif /* PCMCIA_DEBUG */ 54647c478bd9Sstevel@tonic-gate } 54657c478bd9Sstevel@tonic-gate } 54667c478bd9Sstevel@tonic-gate 54677c478bd9Sstevel@tonic-gate /* Consolidated interrupt processing interface */ 54687c478bd9Sstevel@tonic-gate int 54697c478bd9Sstevel@tonic-gate pcmcia_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op, 54707c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, void *result) 54717c478bd9Sstevel@tonic-gate { 54727c478bd9Sstevel@tonic-gate struct intrspec *ispecp; 54737c478bd9Sstevel@tonic-gate pcmcia_logical_socket_t *sockp; 54747c478bd9Sstevel@tonic-gate 54757c478bd9Sstevel@tonic-gate #if defined(PCMCIA_DEBUG) 54767c478bd9Sstevel@tonic-gate if (pcmcia_debug) 54777c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pcmcia_intr_ops: " 54787c478bd9Sstevel@tonic-gate "dip=0x%p rdip=0x%p op=0x%x hdlp=0x%p\n", 54797c478bd9Sstevel@tonic-gate (void *)dip, (void *)rdip, intr_op, (void *)hdlp); 54807c478bd9Sstevel@tonic-gate #endif /* PCMCIA_DEBUG */ 54817c478bd9Sstevel@tonic-gate 54827c478bd9Sstevel@tonic-gate switch (intr_op) { 54837c478bd9Sstevel@tonic-gate case DDI_INTROP_SUPPORTED_TYPES: 54847c478bd9Sstevel@tonic-gate if (ddi_get_parent_data(rdip) == NULL) { 54857c478bd9Sstevel@tonic-gate *(int *)result = 0; 54867c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 54877c478bd9Sstevel@tonic-gate } 54887c478bd9Sstevel@tonic-gate *(int *)result = DDI_INTR_TYPE_FIXED; 54897c478bd9Sstevel@tonic-gate break; 54907c478bd9Sstevel@tonic-gate case DDI_INTROP_GETCAP: 5491a195726fSgovinda *(int *)result = DDI_INTR_FLAG_LEVEL; 54927c478bd9Sstevel@tonic-gate break; 54937c478bd9Sstevel@tonic-gate case DDI_INTROP_NINTRS: 54947c478bd9Sstevel@tonic-gate case DDI_INTROP_NAVAIL: 5495a54f81fbSanish if (i_ddi_get_intx_nintrs(rdip) == 0) { 54967c478bd9Sstevel@tonic-gate *(int *)result = 0; 54977c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 54987c478bd9Sstevel@tonic-gate } 54997c478bd9Sstevel@tonic-gate *(int *)result = 1; /* for PCMCIA there is only one intr */ 55007c478bd9Sstevel@tonic-gate break; 55017c478bd9Sstevel@tonic-gate case DDI_INTROP_ALLOC: 55027c478bd9Sstevel@tonic-gate if ((ispecp = pcmcia_intr_get_ispec(rdip, hdlp->ih_inum, 55037c478bd9Sstevel@tonic-gate &sockp)) == NULL) 55047c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 55057c478bd9Sstevel@tonic-gate *(int *)result = hdlp->ih_scratch1; 55067c478bd9Sstevel@tonic-gate break; 55077c478bd9Sstevel@tonic-gate case DDI_INTROP_FREE: 55087c478bd9Sstevel@tonic-gate break; 55097c478bd9Sstevel@tonic-gate case DDI_INTROP_GETPRI: 55107c478bd9Sstevel@tonic-gate ispecp = pcmcia_intr_get_ispec(rdip, hdlp->ih_inum, &sockp); 55117c478bd9Sstevel@tonic-gate if (ispecp == NULL) { 55127c478bd9Sstevel@tonic-gate *(int *)result = 0; 55137c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 55147c478bd9Sstevel@tonic-gate } 55157c478bd9Sstevel@tonic-gate 55167c478bd9Sstevel@tonic-gate *(int *)result = ispecp->intrspec_pri = sockp->ls_intr_pri; 55177c478bd9Sstevel@tonic-gate break; 55187c478bd9Sstevel@tonic-gate case DDI_INTROP_SETPRI: 55197c478bd9Sstevel@tonic-gate if (*(int *)result > LOCK_LEVEL) 55207c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 55217c478bd9Sstevel@tonic-gate ispecp = pcmcia_intr_get_ispec(rdip, hdlp->ih_inum, &sockp); 55227c478bd9Sstevel@tonic-gate ASSERT(ispecp); 55237c478bd9Sstevel@tonic-gate ispecp->intrspec_pri = sockp->ls_intr_pri = *(int *)result; 55247c478bd9Sstevel@tonic-gate break; 55257c478bd9Sstevel@tonic-gate case DDI_INTROP_ADDISR: 55267c478bd9Sstevel@tonic-gate if ((ispecp = pcmcia_intr_add_isr(dip, rdip, hdlp)) == NULL) 55277c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 55287a364d25Sschwartz ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispecp; 55297c478bd9Sstevel@tonic-gate break; 55307c478bd9Sstevel@tonic-gate case DDI_INTROP_REMISR: 55317c478bd9Sstevel@tonic-gate pcmcia_intr_remove_isr(dip, rdip, hdlp); 55327c478bd9Sstevel@tonic-gate break; 55337c478bd9Sstevel@tonic-gate case DDI_INTROP_ENABLE: 55347c478bd9Sstevel@tonic-gate if (pcmcia_intr_enable_isr(dip, rdip, hdlp) != DDI_SUCCESS) 55357c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 55367c478bd9Sstevel@tonic-gate break; 55377c478bd9Sstevel@tonic-gate case DDI_INTROP_DISABLE: 55387c478bd9Sstevel@tonic-gate pcmcia_intr_disable_isr(dip, rdip, hdlp); 55397c478bd9Sstevel@tonic-gate break; 55407c478bd9Sstevel@tonic-gate default: 55417c478bd9Sstevel@tonic-gate return (DDI_ENOTSUP); 55427c478bd9Sstevel@tonic-gate } 55437c478bd9Sstevel@tonic-gate 55447c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 55457c478bd9Sstevel@tonic-gate } 55467c478bd9Sstevel@tonic-gate #endif 5547