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 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <sys/stat.h> /* ddi_create_minor_node S_IFCHR */ 28 #include <sys/modctl.h> /* for modldrv */ 29 #include <sys/open.h> /* for open params. */ 30 #include <sys/types.h> 31 #include <sys/kmem.h> 32 #include <sys/sunddi.h> 33 #include <sys/conf.h> /* req. by dev_ops flags MTSAFE etc. */ 34 #include <sys/ddi.h> 35 #include <sys/file.h> 36 #include <sys/note.h> 37 38 #include <sys/i2c/clients/ltc1427_impl.h> 39 40 static void *ltc1427soft_statep; 41 42 43 static int ltc1427_do_attach(dev_info_t *); 44 static int ltc1427_do_detach(dev_info_t *); 45 static int ltc1427_do_resume(void); 46 static int ltc1427_do_suspend(void); 47 48 /* 49 * cb ops (only need ioctl) 50 */ 51 static int ltc1427_open(dev_t *, int, int, cred_t *); 52 static int ltc1427_close(dev_t, int, int, cred_t *); 53 static int ltc1427_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 54 55 static struct cb_ops ltc1427_cbops = { 56 ltc1427_open, /* open */ 57 ltc1427_close, /* close */ 58 nodev, /* strategy */ 59 nodev, /* print */ 60 nodev, /* dump */ 61 nodev, /* read */ 62 nodev, /* write */ 63 ltc1427_ioctl, /* ioctl */ 64 nodev, /* devmap */ 65 nodev, /* mmap */ 66 nodev, /* segmap */ 67 nochpoll, /* poll */ 68 ddi_prop_op, /* cb_prop_op */ 69 NULL, /* streamtab */ 70 D_NEW | D_MP | D_HOTPLUG, /* Driver compatibility flag */ 71 CB_REV, /* rev */ 72 nodev, /* int (*cb_aread)() */ 73 nodev /* int (*cb_awrite)() */ 74 }; 75 76 /* 77 * dev ops 78 */ 79 static int ltc1427_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 80 static int ltc1427_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 81 82 static struct dev_ops ltc1427_ops = { 83 DEVO_REV, 84 0, 85 ddi_getinfo_1to1, 86 nulldev, 87 nulldev, 88 ltc1427_attach, 89 ltc1427_detach, 90 nodev, 91 <c1427_cbops, 92 NULL, 93 NULL, 94 ddi_quiesce_not_needed, /* quiesce */ 95 }; 96 97 extern struct mod_ops mod_driverops; 98 99 static struct modldrv ltc1427_modldrv = { 100 &mod_driverops, /* type of module - driver */ 101 "LTC1427 i2c device driver", 102 <c1427_ops 103 }; 104 105 static struct modlinkage ltc1427_modlinkage = { 106 MODREV_1, 107 <c1427_modldrv, 108 0 109 }; 110 111 112 int 113 _init(void) 114 { 115 int error; 116 117 error = mod_install(<c1427_modlinkage); 118 119 if (!error) 120 (void) ddi_soft_state_init(<c1427soft_statep, 121 sizeof (struct ltc1427_unit), 1); 122 return (error); 123 } 124 125 int 126 _fini(void) 127 { 128 int error; 129 130 error = mod_remove(<c1427_modlinkage); 131 if (!error) 132 ddi_soft_state_fini(<c1427soft_statep); 133 134 return (error); 135 } 136 137 int 138 _info(struct modinfo *modinfop) 139 { 140 return (mod_info(<c1427_modlinkage, modinfop)); 141 } 142 143 static int 144 ltc1427_open(dev_t *devp, int flags, int otyp, cred_t *credp) 145 { 146 _NOTE(ARGUNUSED(credp)) 147 148 struct ltc1427_unit *unitp; 149 int instance; 150 int error = 0; 151 152 instance = getminor(*devp); 153 154 if (instance < 0) { 155 return (ENXIO); 156 } 157 158 unitp = (struct ltc1427_unit *) 159 ddi_get_soft_state(ltc1427soft_statep, instance); 160 161 if (unitp == NULL) { 162 return (ENXIO); 163 } 164 165 if (otyp != OTYP_CHR) { 166 return (EINVAL); 167 } 168 169 mutex_enter(&unitp->ltc1427_mutex); 170 171 if (flags & FEXCL) { 172 if (unitp->ltc1427_oflag != 0) { 173 error = EBUSY; 174 } else { 175 unitp->ltc1427_oflag = FEXCL; 176 } 177 } else { 178 if (unitp->ltc1427_oflag == FEXCL) { 179 error = EBUSY; 180 } else { 181 unitp->ltc1427_oflag = FOPEN; 182 } 183 } 184 185 mutex_exit(&unitp->ltc1427_mutex); 186 187 return (error); 188 } 189 190 static int 191 ltc1427_close(dev_t dev, int flags, int otyp, cred_t *credp) 192 { 193 _NOTE(ARGUNUSED(flags, otyp, credp)) 194 195 struct ltc1427_unit *unitp; 196 int instance; 197 198 instance = getminor(dev); 199 200 if (instance < 0) { 201 return (ENXIO); 202 } 203 204 unitp = (struct ltc1427_unit *) 205 ddi_get_soft_state(ltc1427soft_statep, instance); 206 207 if (unitp == NULL) { 208 return (ENXIO); 209 } 210 211 mutex_enter(&unitp->ltc1427_mutex); 212 213 unitp->ltc1427_oflag = 0; 214 215 mutex_exit(&unitp->ltc1427_mutex); 216 return (DDI_SUCCESS); 217 } 218 219 static int 220 ltc1427_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, 221 cred_t *credp, int *rvalp) 222 { 223 _NOTE(ARGUNUSED(credp, rvalp)) 224 225 struct ltc1427_unit *unitp; 226 int instance; 227 int err = 0; 228 i2c_transfer_t *i2c_tran_pointer; 229 int32_t fan_speed; 230 231 if (arg == (intptr_t)NULL) { 232 D2CMN_ERR((CE_WARN, "LTC1427: ioctl: arg passed in to ioctl " 233 "= NULL\n")); 234 err = EINVAL; 235 return (err); 236 } 237 instance = getminor(dev); 238 unitp = (struct ltc1427_unit *) 239 ddi_get_soft_state(ltc1427soft_statep, instance); 240 241 mutex_enter(&unitp->ltc1427_mutex); 242 243 switch (cmd) { 244 case I2C_GET_OUTPUT: 245 D1CMN_ERR((CE_NOTE, "current_set_flag = %d\n", 246 unitp->current_set_flag)); 247 if (unitp->current_set_flag == 0) { 248 err = EIO; 249 break; 250 } else { 251 if (ddi_copyout((caddr_t)&unitp->current_value, 252 (caddr_t)arg, sizeof (int32_t), 253 mode) != DDI_SUCCESS) { 254 D2CMN_ERR((CE_WARN, 255 "%s: Failed in I2C_GET_OUTPUT " 256 "ddi_copyout routine\n", 257 unitp->ltc1427_name)); 258 err = EFAULT; 259 break; 260 } 261 } 262 break; 263 264 case I2C_SET_OUTPUT: 265 if (ddi_copyin((caddr_t)arg, (caddr_t)&fan_speed, 266 sizeof (int32_t), mode) != DDI_SUCCESS) { 267 D2CMN_ERR((CE_WARN, 268 "%s: Failed in I2C_SET_OUTPUT " 269 "ioctl before switch\n", 270 unitp->ltc1427_name)); 271 err = EFAULT; 272 break; 273 } 274 275 (void) i2c_transfer_alloc(unitp->ltc1427_hdl, 276 &i2c_tran_pointer, 2, 0, I2C_SLEEP); 277 if (i2c_tran_pointer == NULL) { 278 D2CMN_ERR((CE_WARN, 279 "%s: Failed in I2C_SET_OUTPUT " 280 "i2c_transfer_pointer not allocated\n", 281 unitp->ltc1427_name)); 282 err = ENOMEM; 283 break; 284 } 285 i2c_tran_pointer->i2c_flags = I2C_WR; 286 i2c_tran_pointer->i2c_wbuf[0] = 287 (uchar_t)((fan_speed >> 8) & 0x03); 288 i2c_tran_pointer->i2c_wbuf[1] = 289 (uchar_t)((fan_speed) & 0x000000ff); 290 291 err = i2c_transfer(unitp->ltc1427_hdl, i2c_tran_pointer); 292 if (!err) { 293 unitp->current_value = fan_speed; 294 unitp->current_set_flag = 1; 295 } 296 i2c_transfer_free(unitp->ltc1427_hdl, i2c_tran_pointer); 297 break; 298 299 default: 300 D2CMN_ERR((CE_WARN, "%s: Invalid IOCTL cmd: %x\n", 301 unitp->ltc1427_name, cmd)); 302 err = EINVAL; 303 } 304 305 mutex_exit(&unitp->ltc1427_mutex); 306 return (err); 307 } 308 309 static int 310 ltc1427_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 311 { 312 switch (cmd) { 313 case DDI_ATTACH: 314 return (ltc1427_do_attach(dip)); 315 case DDI_RESUME: 316 return (ltc1427_do_resume()); 317 default: 318 return (DDI_FAILURE); 319 } 320 } 321 322 static int 323 ltc1427_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 324 { 325 switch (cmd) { 326 case DDI_DETACH: 327 return (ltc1427_do_detach(dip)); 328 case DDI_SUSPEND: 329 return (ltc1427_do_suspend()); 330 default: 331 return (DDI_FAILURE); 332 } 333 } 334 335 static int 336 ltc1427_do_attach(dev_info_t *dip) 337 { 338 struct ltc1427_unit *unitp; 339 int instance; 340 341 instance = ddi_get_instance(dip); 342 343 if (ddi_soft_state_zalloc(ltc1427soft_statep, instance) != 0) { 344 cmn_err(CE_WARN, "%s%d: failed to zalloc softstate\n", 345 ddi_get_name(dip), instance); 346 return (DDI_FAILURE); 347 } 348 349 unitp = ddi_get_soft_state(ltc1427soft_statep, instance); 350 351 if (unitp == NULL) { 352 cmn_err(CE_WARN, "%s%d: unitp not filled\n", 353 ddi_get_name(dip), instance); 354 return (ENOMEM); 355 } 356 357 (void) snprintf(unitp->ltc1427_name, sizeof (unitp->ltc1427_name), 358 "%s%d", ddi_node_name(dip), instance); 359 360 if (ddi_create_minor_node(dip, "ltc1427", S_IFCHR, instance, 361 "ddi_i2c:adio", 0) == DDI_FAILURE) { 362 cmn_err(CE_WARN, "%s ddi_create_minor_node failed for " 363 "%s\n", unitp->ltc1427_name, "ltc1427"); 364 ddi_soft_state_free(ltc1427soft_statep, instance); 365 366 return (DDI_FAILURE); 367 } 368 369 if (i2c_client_register(dip, &unitp->ltc1427_hdl) != I2C_SUCCESS) { 370 ddi_remove_minor_node(dip, NULL); 371 ddi_soft_state_free(ltc1427soft_statep, instance); 372 373 return (DDI_FAILURE); 374 } 375 376 mutex_init(&unitp->ltc1427_mutex, NULL, MUTEX_DRIVER, NULL); 377 378 return (DDI_SUCCESS); 379 } 380 381 static int 382 ltc1427_do_resume() 383 { 384 int ret = DDI_SUCCESS; 385 386 return (ret); 387 } 388 389 static int 390 ltc1427_do_suspend() 391 { 392 int ret = DDI_SUCCESS; 393 394 return (ret); 395 } 396 397 static int 398 ltc1427_do_detach(dev_info_t *dip) 399 { 400 struct ltc1427_unit *unitp; 401 int instance; 402 403 instance = ddi_get_instance(dip); 404 405 unitp = ddi_get_soft_state(ltc1427soft_statep, instance); 406 407 if (unitp == NULL) { 408 cmn_err(CE_WARN, "%s%d: unitp not filled\n", 409 ddi_get_name(dip), instance); 410 return (ENOMEM); 411 } 412 413 i2c_client_unregister(unitp->ltc1427_hdl); 414 415 ddi_remove_minor_node(dip, NULL); 416 417 mutex_destroy(&unitp->ltc1427_mutex); 418 419 ddi_soft_state_free(ltc1427soft_statep, instance); 420 421 return (DDI_SUCCESS); 422 } 423