Home | History | Annotate | Download | only in impl
      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