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