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