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#include <sys/types.h>
28#include <sys/byteorder.h>
29#include <sys/systm.h>
30#include <sys/ddi.h>
31#include <sys/sunddi.h>
32
33int pcs_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
34int pcs_attach(dev_info_t *, ddi_attach_cmd_t);
35int pcs_detach(dev_info_t *, ddi_detach_cmd_t);
36dev_info_t *pcs_dip;
37
38static struct dev_ops pcs_devops = {
39	DEVO_REV,
40	0,
41	pcs_getinfo,
42	nulldev,
43	nulldev,
44	pcs_attach,
45	pcs_detach,
46	nulldev,
47	NULL,
48	NULL,
49	NULL,
50	ddi_quiesce_not_needed,		/* quiesce */
51};
52/*
53 * This is the loadable module wrapper.
54 */
55#include <sys/modctl.h>
56
57extern struct mod_ops mod_driverops;
58
59static struct modldrv modldrv = {
60	&mod_driverops,		/* Type of module. This one is a driver */
61	"PCMCIA Socket Driver",	/* Name of the module. */
62	&pcs_devops,		/* driver ops */
63};
64
65static struct modlinkage modlinkage = {
66	MODREV_1, (void *)&modldrv, NULL
67};
68
69struct pcs_inst {
70	dev_info_t *dip;
71} *pcs_instances;
72
73int
74_init()
75{
76	int ret;
77	if ((ret = ddi_soft_state_init((void **)&pcs_instances,
78	    sizeof (struct pcs_inst), 1)) != 0)
79		return (ret);
80	if ((ret = mod_install(&modlinkage)) != 0) {
81		ddi_soft_state_fini((void **)&pcs_instances);
82	}
83	return (ret);
84}
85
86int
87_fini()
88{
89	int ret;
90	ret = mod_remove(&modlinkage);
91	if (ret == 0) {
92		ddi_soft_state_fini((void **)&pcs_instances);
93	}
94	return (ret);
95}
96
97int
98_info(struct modinfo *modinfop)
99{
100	return (mod_info(&modlinkage, modinfop));
101}
102
103int
104pcs_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
105{
106	int error = DDI_SUCCESS;
107	int inum;
108	struct pcs_inst *inst;
109#ifdef lint
110	dip = dip;
111#endif
112
113	switch (cmd) {
114	case DDI_INFO_DEVT2DEVINFO:
115		inum = getminor((dev_t)arg);
116		inst = (struct pcs_inst *)ddi_get_soft_state(pcs_instances,
117		    inum);
118		if (inst == NULL)
119			error = DDI_FAILURE;
120		else
121			*result = inst->dip;
122		break;
123	case DDI_INFO_DEVT2INSTANCE:
124		inum = getminor((dev_t)arg);
125		inst = (struct pcs_inst *)ddi_get_soft_state(pcs_instances,
126		    inum);
127		if (inst == NULL)
128			error = DDI_FAILURE;
129		else
130			*result = (void *)(uintptr_t)inum;
131		break;
132	default:
133		error = DDI_FAILURE;
134	}
135	return (error);
136}
137
138int
139pcs_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
140{
141	int ret = DDI_SUCCESS;
142	int inum;
143	struct pcs_inst *inst;
144
145	switch (cmd) {
146	case DDI_RESUME:
147		return (DDI_SUCCESS);
148	case DDI_ATTACH:
149		break;
150	default:
151		return (DDI_FAILURE);
152	}
153
154	inum = ddi_get_instance(dip);
155
156	if (ddi_soft_state_zalloc(pcs_instances, inum) == DDI_SUCCESS) {
157		inst = (struct pcs_inst *)ddi_get_soft_state(pcs_instances,
158		    inum);
159		if (inst == NULL)
160			ret = DDI_FAILURE;
161		else
162			inst->dip = dip;
163	}
164
165	return (ret);
166}
167
168int
169pcs_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
170{
171	switch (cmd) {
172	case DDI_DETACH:
173		ddi_soft_state_free(pcs_instances, ddi_get_instance(dip));
174		return (DDI_SUCCESS);
175
176	case DDI_SUSPEND:
177	case DDI_PM_SUSPEND:
178		return (DDI_SUCCESS);
179	default:
180		break;
181	}
182	return (DDI_FAILURE);
183}
184