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/stat.h>
29 #include <sys/conf.h>
30 #include <sys/modctl.h>
31 #include <sys/sunddi.h>
32 #include <sys/callb.h>
33 #include <sys/strlog.h>
34 #include <sys/file.h>
35 #include <sys/lom_io.h>
36 #include <sys/ddi.h>
37 #include <sys/time.h>
38
39 #define LOMIOCALCTL_OLD _IOW('a', 4, ts_aldata_t)
40 #define LOMIOCALSTATE_OLD _IOWR('a', 5, ts_aldata_t)
41
42 struct tsalarm_softc {
43 dev_info_t *dip;
44 kmutex_t mutex;
45 };
46
47 #define getsoftc(minor) \
48 ((struct tsalarm_softc *)ddi_get_soft_state(statep, (minor)))
49 /*
50 * Driver entry points
51 */
52
53 /* dev_ops and cb_ops entry point function declarations */
54
55 static int tsalarm_attach(dev_info_t *, ddi_attach_cmd_t);
56 static int tsalarm_detach(dev_info_t *, ddi_detach_cmd_t);
57 static int tsalarm_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
58
59 static int tsalarm_open(dev_t *, int, int, cred_t *);
60 static int tsalarm_close(dev_t, int, int, cred_t *);
61 static int tsalarm_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
62
63 static struct cb_ops tsalarm_cb_ops = {
64 tsalarm_open, /* open */
65 tsalarm_close, /* close */
66 nodev, /* strategy() */
67 nodev, /* print() */
68 nodev, /* dump() */
69 nodev, /* read() */
70 nodev, /* write() */
71 tsalarm_ioctl, /* ioctl() */
72 nodev, /* devmap() */
73 nodev, /* mmap() */
74 ddi_segmap, /* segmap() */
75 nochpoll, /* poll() */
76 ddi_prop_op, /* prop_op() */
77 NULL, /* cb_str */
78 D_NEW | D_MP /* cb_flag */
79 };
80
81
82 static struct dev_ops tsalarm_ops = {
83 DEVO_REV,
84 0, /* ref count */
85 tsalarm_getinfo, /* getinfo() */
86 nulldev, /* identify() */
87 nulldev, /* probe() */
88 tsalarm_attach, /* attach() */
89 tsalarm_detach, /* detach */
90 nodev, /* reset */
91 &tsalarm_cb_ops, /* pointer to cb_ops structure */
92 (struct bus_ops *)NULL,
93 nulldev, /* power() */
94 ddi_quiesce_not_needed, /* quiesce() */
95 };
96
97 /*
98 * Loadable module support.
99 */
100 extern struct mod_ops mod_driverops;
101 static void *statep;
102
103 static struct modldrv modldrv = {
104 &mod_driverops, /* Type of module. This is a driver */
105 "tsalarm control driver", /* Name of the module */
106 &tsalarm_ops /* pointer to the dev_ops structure */
107 };
108
109 static struct modlinkage modlinkage = {
110 MODREV_1,
111 &modldrv,
112 NULL
113 };
114
115 extern int rmclomv_alarm_get(int alarm_type, int *alarm_state);
116 extern int rmclomv_alarm_set(int alarm_type, int new_state);
117
118 int
_init(void)119 _init(void)
120 {
121 int e;
122
123 if (e = ddi_soft_state_init(&statep,
124 sizeof (struct tsalarm_softc), 1)) {
125 return (e);
126 }
127
128 if ((e = mod_install(&modlinkage)) != 0) {
129 ddi_soft_state_fini(&statep);
130 }
131
132 return (e);
133 }
134
135
136 int
_fini(void)137 _fini(void)
138 {
139 int e;
140
141 if ((e = mod_remove(&modlinkage)) != 0) {
142 return (e);
143 }
144
145 ddi_soft_state_fini(&statep);
146
147 return (DDI_SUCCESS);
148 }
149
150
151 int
_info(struct modinfo * modinfop)152 _info(struct modinfo *modinfop)
153 {
154 return (mod_info(&modlinkage, modinfop));
155 }
156
157
158 /* ARGSUSED */
159 static int
tsalarm_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** result)160 tsalarm_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
161 {
162 int inst = getminor((dev_t)arg);
163 int retval = DDI_SUCCESS;
164 struct tsalarm_softc *softc;
165
166 switch (cmd) {
167
168 case DDI_INFO_DEVT2DEVINFO:
169 if ((softc = getsoftc(inst)) == NULL) {
170 *result = (void *)NULL;
171 retval = DDI_FAILURE;
172 } else {
173 *result = (void *)softc->dip;
174 }
175 break;
176
177 case DDI_INFO_DEVT2INSTANCE:
178 *result = (void *)(uintptr_t)inst;
179 break;
180
181 default:
182 retval = DDI_FAILURE;
183 }
184
185 return (retval);
186 }
187
188 static int
tsalarm_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)189 tsalarm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
190 {
191
192 int inst;
193 struct tsalarm_softc *softc = NULL;
194
195 switch (cmd) {
196
197 case DDI_ATTACH:
198 inst = ddi_get_instance(dip);
199 /*
200 * Allocate a soft state structure for this instance.
201 */
202 if (ddi_soft_state_zalloc(statep, inst) != DDI_SUCCESS)
203 goto attach_failed;
204
205 softc = getsoftc(inst);
206 softc->dip = dip;
207 mutex_init(&softc->mutex, NULL, MUTEX_DRIVER, NULL);
208 /*
209 * Create minor node. The minor device number, inst, has no
210 * meaning. The model number above, which will be added to
211 * the device's softc, is used to direct peculiar behavior.
212 */
213 if (ddi_create_minor_node(dip, "lom", S_IFCHR, 0,
214 DDI_PSEUDO, 0) == DDI_FAILURE)
215 goto attach_failed;
216
217 ddi_report_dev(dip);
218 return (DDI_SUCCESS);
219
220 case DDI_RESUME:
221 return (DDI_SUCCESS);
222
223 default:
224 return (DDI_FAILURE);
225 }
226
227 attach_failed:
228 /* Free soft state, if allocated. remove minor node if added earlier */
229 if (softc) {
230 mutex_destroy(&softc->mutex);
231 ddi_soft_state_free(statep, inst);
232 }
233
234 ddi_remove_minor_node(dip, NULL);
235
236 return (DDI_FAILURE);
237 }
238
239 static int
tsalarm_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)240 tsalarm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
241 {
242 int inst;
243 struct tsalarm_softc *softc;
244
245 switch (cmd) {
246
247 case DDI_DETACH:
248 inst = ddi_get_instance(dip);
249 if ((softc = getsoftc(inst)) == NULL)
250 return (DDI_FAILURE);
251 /*
252 * Free the soft state and remove minor node added earlier.
253 */
254 ddi_remove_minor_node(dip, NULL);
255 mutex_destroy(&softc->mutex);
256 ddi_soft_state_free(statep, inst);
257 return (DDI_SUCCESS);
258
259 case DDI_SUSPEND:
260 return (DDI_SUCCESS);
261
262 default:
263 return (DDI_FAILURE);
264
265 }
266 }
267
268 /* ARGSUSED */
269 static int
tsalarm_open(dev_t * devp,int flag,int otyp,cred_t * credp)270 tsalarm_open(dev_t *devp, int flag, int otyp, cred_t *credp)
271 {
272 int inst = getminor(*devp);
273
274 return (getsoftc(inst) == NULL ? ENXIO : 0);
275 }
276
277
278 /* ARGSUSED */
279 static int
tsalarm_close(dev_t dev,int flag,int otyp,cred_t * credp)280 tsalarm_close(dev_t dev, int flag, int otyp, cred_t *credp)
281 {
282 int inst = getminor(dev);
283
284 return (getsoftc(inst) == NULL ? ENXIO : 0);
285 }
286
287
288 /* ARGSUSED */
289 static int
tsalarm_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)290 tsalarm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
291 cred_t *credp, int *rvalp)
292 {
293 int inst = getminor(dev);
294 struct tsalarm_softc *softc;
295 int retval = 0;
296 ts_aldata_t ts_alinfo;
297 int alarm_type, alarm_state = 0;
298
299 if ((softc = getsoftc(inst)) == NULL)
300 return (ENXIO);
301
302 mutex_enter(&softc->mutex);
303
304 switch (cmd) {
305
306 case LOMIOCALSTATE:
307 case LOMIOCALSTATE_OLD:
308 {
309 if (ddi_copyin((caddr_t)arg, (caddr_t)&ts_alinfo,
310 sizeof (ts_aldata_t), mode) != 0) {
311 retval = EFAULT;
312 goto end;
313 }
314
315 alarm_type = ts_alinfo.alarm_no;
316 if ((alarm_type < ALARM_CRITICAL) ||
317 (alarm_type > ALARM_USER)) {
318 retval = EINVAL;
319 goto end;
320 }
321
322 retval = rmclomv_alarm_get(alarm_type, &alarm_state);
323
324 if (retval != 0)
325 goto end;
326
327 if ((alarm_state != 0) && (alarm_state != 1)) {
328 retval = EIO;
329 goto end;
330 }
331
332 ts_alinfo.alarm_state = alarm_state;
333 if (ddi_copyout((caddr_t)&ts_alinfo, (caddr_t)arg,
334 sizeof (ts_aldata_t), mode) != 0) {
335 retval = EFAULT;
336 goto end;
337 }
338
339 }
340 break;
341
342 case LOMIOCALCTL:
343 case LOMIOCALCTL_OLD:
344 {
345 if (ddi_copyin((caddr_t)arg, (caddr_t)&ts_alinfo,
346 sizeof (ts_aldata_t), mode) != 0) {
347 retval = EFAULT;
348 goto end;
349 }
350
351 alarm_type = ts_alinfo.alarm_no;
352 alarm_state = ts_alinfo.alarm_state;
353
354 if ((alarm_type < ALARM_CRITICAL) ||
355 (alarm_type > ALARM_USER)) {
356 retval = EINVAL;
357 goto end;
358 }
359 if ((alarm_state < ALARM_OFF) ||
360 (alarm_state > ALARM_ON)) {
361 retval = EINVAL;
362 goto end;
363 }
364
365 retval = rmclomv_alarm_set(alarm_type, alarm_state);
366 }
367 break;
368
369 default:
370 retval = EINVAL;
371 break;
372 }
373
374 end:
375 mutex_exit(&softc->mutex);
376
377 return (retval);
378 }
379