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 119 if (ops->so_version != SDA_OPS_VERSION) { 120 return (NULL); 121 } 122 123 h = kmem_zalloc(sizeof (*h), KM_SLEEP); 124 h->h_nslot = nslot; 125 h->h_slots = kmem_zalloc(sizeof (sda_slot_t) * nslot, KM_SLEEP); 126 h->h_dma = dma; 127 h->h_dip = dip; 128 129 /* initialize each slot */ 130 for (int i = 0; i < nslot; i++) { 131 sda_slot_t *slot = &h->h_slots[i]; 132 133 slot->s_hostp = h; 134 slot->s_slot_num = i; 135 slot->s_ops = *ops; 136 137 sda_slot_init(slot); 138 } 139 140 return (h); 141 } 142 143 void 144 sda_host_free(sda_host_t *h) 145 { 146 for (int i = 0; i < h->h_nslot; i++) { 147 sda_slot_fini(&h->h_slots[i]); 148 } 149 150 kmem_free(h->h_slots, sizeof (sda_slot_t) * h->h_nslot); 151 kmem_free(h, sizeof (*h)); 152 } 153 154 void 155 sda_host_set_private(sda_host_t *h, int num, void *private) 156 { 157 h->h_slots[num].s_prv = private; 158 } 159 160 int 161 sda_host_attach(sda_host_t *h) 162 { 163 /* 164 * Attach slots. 165 */ 166 for (int i = 0; i < h->h_nslot; i++) { 167 168 sda_slot_attach(&h->h_slots[i]); 169 170 /* 171 * Initiate card detection. 172 */ 173 sda_host_detect(h, i); 174 } 175 176 /* 177 * Register (create) nexus minor nodes. 178 */ 179 sda_nexus_register(h); 180 181 return (DDI_SUCCESS); 182 } 183 184 void 185 sda_host_detach(sda_host_t *h) 186 { 187 /* 188 * Unregister nexus minor nodes. 189 */ 190 sda_nexus_unregister(h); 191 192 /* 193 * Detach slots. 194 */ 195 for (int i = 0; i < h->h_nslot; i++) { 196 sda_slot_detach(&h->h_slots[i]); 197 } 198 } 199 200 void 201 sda_host_suspend(sda_host_t *h) 202 { 203 for (int i = 0; i < h->h_nslot; i++) { 204 sda_slot_suspend(&h->h_slots[i]); 205 } 206 } 207 208 void 209 sda_host_resume(sda_host_t *h) 210 { 211 for (int i = 0; i < h->h_nslot; i++) { 212 sda_slot_resume(&h->h_slots[i]); 213 } 214 } 215 216 void 217 sda_host_transfer(sda_host_t *h, int num, sda_err_t errno) 218 { 219 sda_slot_transfer(&h->h_slots[num], errno); 220 } 221 222 void 223 sda_host_detect(sda_host_t *h, int num) 224 { 225 sda_slot_detect(&h->h_slots[num]); 226 } 227 228 void 229 sda_host_fault(sda_host_t *h, int num, sda_fault_t fail) 230 { 231 sda_slot_fault(&h->h_slots[num], fail); 232 } 233 234 void 235 sda_host_log(sda_host_t *h, int snum, const char *fmt, ...) 236 { 237 va_list ap; 238 239 va_start(ap, fmt); 240 if (h != NULL) { 241 sda_slot_log(&h->h_slots[snum], fmt, ap); 242 } else { 243 sda_slot_log(NULL, fmt, ap); 244 } 245 va_end(ap); 246 } 247