xref: /illumos-gate/usr/src/uts/common/io/sdcard/impl/sda_host.c (revision e9af4bc0b1cc30cea75d6ad4aa2fde97d985e9be)
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