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