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 (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24
25/*
26 * SD card host support.  This is the API that host drivers access.
27 */
28
29#include <sys/types.h>
30#include <sys/conf.h>
31#include <sys/cmn_err.h>
32#include <sys/varargs.h>
33#include <sys/ddi.h>
34#include <sys/sunddi.h>
35#include <sys/sdcard/sda.h>
36#include <sys/sdcard/sda_impl.h>
37
38/*
39 * Implementation.
40 */
41
42void
43sda_host_init_ops(struct dev_ops *devops)
44{
45	bd_mod_init(devops);
46}
47
48void
49sda_host_fini_ops(struct dev_ops *devops)
50{
51	bd_mod_fini(devops);
52}
53
54sda_host_t *
55sda_host_alloc(dev_info_t *dip, int nslot, sda_ops_t *ops, ddi_dma_attr_t *dma)
56{
57	sda_host_t	*h;
58
59	if (ops->so_version != SDA_OPS_VERSION) {
60		return (NULL);
61	}
62
63	h = kmem_zalloc(sizeof (*h), KM_SLEEP);
64	h->h_nslot = nslot;
65	h->h_slots = kmem_zalloc(sizeof (sda_slot_t) * nslot, KM_SLEEP);
66	h->h_dma = dma;
67	h->h_dip = dip;
68
69	/* initialize each slot */
70	for (int i = 0; i < nslot; i++) {
71		sda_slot_t *slot = &h->h_slots[i];
72
73		slot->s_hostp = h;
74		slot->s_slot_num = i;
75		slot->s_ops = *ops;
76
77		sda_slot_init(slot);
78	}
79
80	return (h);
81}
82
83void
84sda_host_free(sda_host_t *h)
85{
86	for (int i = 0; i < h->h_nslot; i++) {
87		sda_slot_fini(&h->h_slots[i]);
88	}
89
90	kmem_free(h->h_slots, sizeof (sda_slot_t) * h->h_nslot);
91	kmem_free(h, sizeof (*h));
92}
93
94void
95sda_host_set_private(sda_host_t *h, int num, void *private)
96{
97	h->h_slots[num].s_prv = private;
98}
99
100int
101sda_host_attach(sda_host_t *h)
102{
103	/*
104	 * Attach slots.
105	 */
106	for (int i = 0; i < h->h_nslot; i++) {
107
108		sda_slot_attach(&h->h_slots[i]);
109
110		/*
111		 * Initiate card detection.
112		 */
113		sda_host_detect(h, i);
114	}
115
116	return (DDI_SUCCESS);
117}
118
119void
120sda_host_detach(sda_host_t *h)
121{
122	/*
123	 * Detach slots.
124	 */
125	for (int i = 0; i < h->h_nslot; i++) {
126		sda_slot_detach(&h->h_slots[i]);
127	}
128}
129
130void
131sda_host_suspend(sda_host_t *h)
132{
133	for (int i = 0; i < h->h_nslot; i++) {
134		sda_slot_suspend(&h->h_slots[i]);
135	}
136}
137
138void
139sda_host_resume(sda_host_t *h)
140{
141	for (int i = 0; i < h->h_nslot; i++) {
142		sda_slot_resume(&h->h_slots[i]);
143	}
144}
145
146void
147sda_host_transfer(sda_host_t *h, int num, sda_err_t errno)
148{
149	sda_slot_transfer(&h->h_slots[num], errno);
150}
151
152void
153sda_host_detect(sda_host_t *h, int num)
154{
155	sda_slot_detect(&h->h_slots[num]);
156}
157
158void
159sda_host_fault(sda_host_t *h, int num, sda_fault_t fail)
160{
161	sda_slot_fault(&h->h_slots[num], fail);
162}
163
164void
165sda_host_log(sda_host_t *h, int snum, const char *fmt, ...)
166{
167	va_list	ap;
168
169	va_start(ap, fmt);
170	if (h != NULL) {
171		sda_slot_log(&h->h_slots[snum], fmt, ap);
172	} else {
173		sda_slot_log(NULL, fmt, ap);
174	}
175	va_end(ap);
176}
177