1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * SD card host support. This is the API that host drivers access. 28 */ 29 30 #include <sys/types.h> 31 #include <sys/conf.h> 32 #include <sys/cmn_err.h> 33 #include <sys/varargs.h> 34 #include <sys/ddi.h> 35 #include <sys/sunddi.h> 36 #include <sys/sdcard/sda.h> 37 #include <sys/sdcard/sda_impl.h> 38 39 /* 40 * Static Variables. 41 */ 42 43 static struct bus_ops sda_host_bus_ops = { 44 BUSO_REV, /* busops_rev */ 45 nullbusmap, /* bus_map */ 46 NULL, /* bus_get_intrspec (OBSOLETE) */ 47 NULL, /* bus_add_intrspec (OBSOLETE) */ 48 NULL, /* bus_remove_intrspec (OBSOLETE) */ 49 i_ddi_map_fault, /* bus_map_fault */ 50 ddi_dma_map, /* bus_dma_map */ 51 ddi_dma_allochdl, /* bus_dma_allochdl */ 52 ddi_dma_freehdl, /* bus_dma_freehdl */ 53 ddi_dma_bindhdl, /* bus_dma_bindhdl */ 54 ddi_dma_unbindhdl, /* bus_dma_unbindhdl */ 55 ddi_dma_flush, /* bus_dma_flush */ 56 ddi_dma_win, /* bus_dma_win */ 57 ddi_dma_mctl, /* bus_dma_ctl */ 58 sda_nexus_bus_ctl, /* bus_ctl */ 59 ddi_bus_prop_op, /* bus_prop_op */ 60 NULL, /* bus_get_eventcookie */ 61 NULL, /* bus_add_eventcall */ 62 NULL, /* bus_remove_eventcall */ 63 NULL, /* bus_post_event */ 64 NULL, /* bus_intr_ctl (OBSOLETE) */ 65 NULL, /* sda_nexus_bus_config, */ /* bus_config */ 66 NULL, /* sda_nexus_bus_unconfig, */ /* bus_unconfig */ 67 NULL, /* bus_fm_init */ 68 NULL, /* bus_fm_fini */ 69 NULL, /* bus_fm_access_enter */ 70 NULL, /* bus_fm_access_exit */ 71 NULL, /* bus_power */ 72 NULL, /* bus_intr_op */ 73 }; 74 75 static struct cb_ops sda_host_cb_ops = { 76 sda_nexus_open, /* cb_open */ 77 sda_nexus_close, /* cb_close */ 78 nodev, /* cb_strategy */ 79 nodev, /* cb_print */ 80 nodev, /* cb_dump */ 81 nodev, /* cb_read */ 82 nodev, /* cb_write */ 83 sda_nexus_ioctl, /* cb_ioctl */ 84 nodev, /* cb_devmap */ 85 nodev, /* cb_mmap */ 86 nodev, /* cb_segmap */ 87 nochpoll, /* cb_poll */ 88 ddi_prop_op, /* cb_prop_op */ 89 NULL, /* cb_str */ 90 D_MP, /* cb_flag */ 91 CB_REV, /* cb_rev */ 92 nodev, /* cb_aread */ 93 nodev, /* cb_awrite */ 94 }; 95 96 /* 97 * Implementation. 98 */ 99 100 void 101 sda_host_init_ops(struct dev_ops *devops) 102 { 103 devops->devo_getinfo = sda_nexus_getinfo; 104 devops->devo_cb_ops = &sda_host_cb_ops; 105 devops->devo_bus_ops = &sda_host_bus_ops; 106 } 107 108 void 109 sda_host_fini_ops(struct dev_ops *devops) 110 { 111 devops->devo_bus_ops = NULL; 112 } 113 114 sda_host_t * 115 sda_host_alloc(dev_info_t *dip, int nslot, sda_ops_t *ops, ddi_dma_attr_t *dma) 116 { 117 sda_host_t *h; 118 int i; 119 120 if (ops->so_version != SDA_OPS_VERSION) { 121 return (NULL); 122 } 123 124 h = kmem_zalloc(sizeof (*h), KM_SLEEP); 125 h->h_nslot = nslot; 126 h->h_slots = kmem_zalloc(sizeof (sda_slot_t) * nslot, KM_SLEEP); 127 h->h_dma = dma; 128 h->h_dip = dip; 129 130 /* initialize each slot */ 131 for (i = 0; i < nslot; i++) { 132 sda_slot_t *slot = &h->h_slots[i]; 133 134 slot->s_hostp = h; 135 slot->s_slot_num = i; 136 slot->s_ops = *ops; 137 138 sda_slot_init(slot); 139 } 140 141 return (h); 142 } 143 144 void 145 sda_host_free(sda_host_t *h) 146 { 147 int i; 148 149 for (i = 0; i < h->h_nslot; i++) { 150 sda_slot_fini(&h->h_slots[i]); 151 } 152 153 kmem_free(h->h_slots, sizeof (sda_slot_t) * h->h_nslot); 154 kmem_free(h, sizeof (*h)); 155 } 156 157 void 158 sda_host_set_private(sda_host_t *h, int num, void *private) 159 { 160 h->h_slots[num].s_prv = private; 161 } 162 163 int 164 sda_host_attach(sda_host_t *h) 165 { 166 int i; 167 168 /* 169 * Attach slots. 170 */ 171 for (i = 0; i < h->h_nslot; i++) { 172 173 sda_slot_attach(&h->h_slots[i]); 174 175 /* 176 * Initiate card detection. 177 */ 178 sda_host_detect(h, i); 179 } 180 181 /* 182 * Register (create) nexus minor nodes. 183 */ 184 sda_nexus_register(h); 185 186 return (DDI_SUCCESS); 187 } 188 189 void 190 sda_host_detach(sda_host_t *h) 191 { 192 int i; 193 194 /* 195 * Unregister nexus minor nodes. 196 */ 197 sda_nexus_unregister(h); 198 199 /* 200 * Detach slots. 201 */ 202 for (i = 0; i < h->h_nslot; i++) { 203 sda_slot_detach(&h->h_slots[i]); 204 } 205 } 206 207 void 208 sda_host_transfer(sda_host_t *h, int num, sda_err_t errno) 209 { 210 sda_slot_transfer(&h->h_slots[num], errno); 211 } 212 213 void 214 sda_host_detect(sda_host_t *h, int num) 215 { 216 sda_slot_detect(&h->h_slots[num]); 217 } 218 219 void 220 sda_host_fault(sda_host_t *h, int num, sda_fault_t fail) 221 { 222 sda_slot_fault(&h->h_slots[num], fail); 223 } 224 225 void 226 sda_host_log(sda_host_t *h, int snum, const char *fmt, ...) 227 { 228 va_list ap; 229 230 va_start(ap, fmt); 231 if (h != NULL) { 232 sda_slot_log(&h->h_slots[snum], fmt, ap); 233 } else { 234 sda_slot_log(NULL, fmt, ap); 235 } 236 va_end(ap); 237 } 238