Copyright 2004 Sun Microsystems, Inc. ALL RIGHTS RESERVED Use of this software is authorized pursuant to the terms of the license found at http://developers.sun.com/berkeley_license.html Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistribution of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistribution in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of Sun Microsystems, Inc. or the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission. This software is provided "AS IS," without a warranty of any kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. You acknowledge that this software is not designed, licensed or intended for use in the design, construction, operation or maintenance of any nuclear facility. 1 /* 2 * Sample Code: pio.c 3 */ 4 #include 5 #include 6 #include 7 #include 8 #include 9 #include 10 #include 11 #include 12 13 #include "pio_io.h" 14 15 /* 16 * ************************************************************************* 17 * General Rule: Use fixed-width DDI common functions. 18 * Change ddi_putl and ddi_getl to ddiput32 and ddi_get32. 19 * ************************************************************************* 20 */ 21 typedef struct pio { /* per-unit structure */ 22 dev_info_t *dip; 23 kcondvar_t cv; 24 kmutex_t mutex; 25 int pio_state; /* driver state */ 26 ddi_iblock_cookie_t iblock_cookie; /* for mutexes */ 27 ddi_acc_handle_t csr_handle; /* access handle to csr */ 28 ddi_acc_handle_t data_handle; /* access handle to data */ 29 Pio_csr *csr; /* mapped to CSR on device */ 30 uint_32 *data; /* data register on device */ 31 /* 32 * Below two variables is changed from the simple int type. 33 * Old Version: 34 int size; 35 int *addr; 36 */ 37 size_t size; /* change to size_t to be 32/64bit free */ 38 caddr_t *addr; /* change to caddr_t to be 32/64bit free */ 39 40 ddi_umem_cookie_t umem_cookie; 41 } Pio; 42 43 #define PIO_OPEN 0x01 /* pio_state */ 44 45 static void *pio_softstate; /* opaque handle top of state structs */ 46 47 static int pio_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 48 static int pio_attach(dev_info_t *, ddi_attach_cmd_t); 49 static int pio_open(dev_t *, int, int, cred_t *); 50 static int pio_close(dev_t, int, int, cred_t *); 51 static int pio_write(dev_t, struct uio *, cred_t *); 52 static int pio_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 53 static uint_t pio_intr(caddr_t); 54 static int pio_detach(dev_info_t *, ddi_detach_cmd_t); 55 56 static struct cb_ops pio_cb_ops = { 57 pio_open, 58 pio_close, 59 nodev, /* not a block driver */ 60 nodev, /* no print routine */ 61 nodev, /* no dump routine */ 62 nodev, /* no read routine; write-only device */ 63 pio_write, 64 pio_ioctl, 65 nodev, /* no devmap routine */ 66 nodev, /* no mmap routine */ 67 nodev, /* no segmap routine */ 68 nochpoll, /* no chpoll routine */ 69 ddi_prop_op, 70 0, /* not a STREAMS driver */ 71 D_NEW | D_MP, /* safe for multi-thread/multi-processor */ 72 }; 73 74 static struct dev_ops pio_ops = { 75 DEVO_REV, /* devo_rev */ 76 0, /* devo_refcnt */ 77 pio_getinfo, /* devo_getinfo */ 78 nulldev, /* devo_identify */ 79 nulldev, /* devo_probe */ 80 pio_attach, /* devo_attach */ 81 pio_detach, /* devo_detach */ 82 nodev, /* devo_reset */ 83 &pio_cb_ops, /* devo_cb_ops */ 84 (struct bus_ops *)0, /* devo_bus_ops */ 85 NULL, /* devo_power */ 86 }; 87 88 static struct modldrv modldrv = { 89 &mod_driverops, 90 "sample PIO driver 1.2", 91 &pio_ops, 92 }; 93 94 static struct modlinkage modlinkage = { 95 MODREV_1, /* MODREV_1 manual */ 96 (void *)&modldrv, /* device driver linkage */ 97 NULL, /* list terminator */ 98 }; 99 100 int 101 _init(void) 102 { 103 int error; 104 105 ddi_soft_state_init(&pio_softstate, sizeof (Pio), 1); 106 if ((error = mod_install(&modlinkage)) != 0) 107 ddi_soft_state_fini(&pio_softstate); 108 109 return (error); 110 } 111 112 int 113 _info(struct modinfo *modinfop) 114 { 115 return (mod_info(&modlinkage, modinfop)); 116 } 117 118 int 119 _fini(void) 120 { 121 int status; 122 123 if ((status = mod_remove(&modlinkage)) != 0) 124 return (status); 125 ddi_soft_state_fini(&pio_softstate); 126 127 return (status); 128 } 129 130 static int 131 pio_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 132 { 133 int instance; 134 Pio *pio_p; 135 ddi_device_acc_attr_t dev_acc_attr; /* device access attributes */ 136 137 switch (cmd) { 138 case DDI_ATTACH: 139 instance = ddi_get_instance(dip); 140 ddi_soft_state_zalloc(pio_softstate, instance); 141 142 pio_p = ddi_get_soft_state(pio_softstate, instance); 143 ddi_set_driver_private(dip, (caddr_t)pio_p); 144 pio_p->dip = dip; 145 pio_p->size = 600 * 1024; 146 pio_p->addr = (void*)ddi_umem_alloc( 147 pio_p->size, DDI_UMEM_NOSLEEP, &pio_p->umem_cookie); 148 149 ddi_get_iblock_cookie(dip, 0, &pio_p->iblock_cookie); 150 mutex_init(&pio_p->mutex, NULL, MUTEX_DRIVER, 151 pio_p->iblock_cookie); 152 ddi_add_intr(dip, 0, &pio_p->iblock_cookie, NULL, 153 pio_intr, (caddr_t)instance); 154 155 dev_acc_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 156 dev_acc_attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 157 dev_acc_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 158 159 ddi_regs_map_setup(dip, 0, (caddr_t *)&(pio_p->csr), 0, 160 sizeof (Pio_csr), &dev_acc_attr, &pio_p->csr_handle); 161 ddi_regs_map_setup(dip, 1, (caddr_t *)&(pio_p->data), 0, 162 sizeof (uchar_t), &dev_acc_attr, &pio_p->data_handle); 163 ddi_create_minor_node(dip, ddi_get_name(dip), S_IFCHR, 164 instance, DDI_PSEUDO, 0); 165 /* 166 * Old version is: 167 ddi_putl(pio_p->csr_handle, pio_p->csr, PIO_RESET); 168 * 169 * General Rule: replace ddi_putl with ddi_put32 170 */ 171 ddi_put32(pio_p->csr_handle, pio_p->csr, PIO_RESET); 172 173 ddi_report_dev(dip); 174 return (DDI_SUCCESS); 175 case DDI_RESUME: 176 case DDI_PM_RESUME: 177 return (DDI_SUCCESS); 178 default: 179 return (DDI_FAILURE); 180 } 181 } 182 183 static int 184 pio_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 185 { 186 int error = DDI_SUCCESS; 187 Pio *pio_p; 188 189 /* 190 * Old version is: 191 int instance = getminor((dev_t)arg); 192 * 193 * But it has the potential problem. Because the prototype of getminor 194 * is: minor_t getminor(dev_t); 195 * minor_t is one of the system derived types, which is 32-bit length 196 * on 32-bit system and 64-bit length on 64-bit system. So there is an 197 * incompatible type to variable instance. The type of instance should 198 * change to minor_t. 199 * 200 * Therefore, replace with the following line: 201 */ 202 minor_t instance = getminor((dev_t)arg); 203 204 switch (infocmd) { 205 case DDI_INFO_DEVT2DEVINFO: 206 pio_p = ddi_get_soft_state(pio_softstate, instance); 207 mutex_enter(&pio_p->mutex); 208 *result = pio_p->dip; 209 mutex_exit(&pio_p->mutex); 210 break; 211 case DDI_INFO_DEVT2INSTANCE: 212 *result = (void *)instance; 213 break; 214 default: 215 *result = NULL; 216 error = DDI_FAILURE; 217 } 218 return (error); 219 } 220 221 static int 222 pio_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 223 { 224 Pio *pio_p; 225 int instance; 226 227 switch (cmd) { 228 case DDI_DETACH: 229 instance = ddi_get_instance(dip); 230 pio_p = ddi_get_soft_state(pio_softstate, instance); 231 /* 232 * Old version is: 233 ddi_putl(pio_p->csr_handle, pio_p->csr, PIO_RESET); 234 * 235 * General Rule: replace ddi_putl with ddi_put32 236 */ 237 ddi_put32(pio_p->csr_handle, pio_p->csr, PIO_RESET); 238 239 ddi_umem_free(pio_p->umem_cookie); 240 ddi_remove_minor_node(dip, NULL); 241 ddi_regs_map_free(&pio_p->csr_handle); 242 ddi_regs_map_free(&pio_p->data_handle); 243 ddi_remove_intr(pio_p->dip, 0, pio_p->iblock_cookie); 244 mutex_destroy(&pio_p->mutex); 245 ddi_soft_state_free(pio_softstate, instance); 246 /* FALL THROUGH */ 247 case DDI_SUSPEND: 248 case DDI_PM_SUSPEND: 249 return (DDI_SUCCESS); 250 default: 251 return (DDI_FAILURE); 252 } 253 } 254 255 static int 256 pio_open(dev_t *dev, int openflags, int otyp, cred_t *credp) 257 { 258 int retval = 0; 259 Pio *pio_p; 260 261 pio_p = ddi_get_soft_state(pio_softstate, getminor(*dev)); 262 263 mutex_enter(&pio_p->mutex); 264 pio_p->pio_state |= PIO_OPEN; 265 /* 266 * Old version is: 267 ddi_putl(pio_p->csr_handle, pio_p->csr, PIO_ENABLE); 268 * 269 * General Rule: replace ddi_putl to ddi_put32 270 */ 271 ddi_put32(pio_p->csr_handle, pio_p->csr, PIO_ENABLE); 272 mutex_exit(&pio_p->mutex); 273 274 return (retval); 275 } 276 277 static int 278 pio_close(dev_t dev, int openflags, int otyp, cred_t *credp) 279 { 280 Pio *pio_p; 281 282 pio_p = ddi_get_soft_state(pio_softstate, getminor(dev)); 283 284 mutex_enter(&pio_p->mutex); 285 pio_p->pio_state &= ~PIO_OPEN; 286 /* 287 * Old version is: 288 ddi_putl(pio_p->csr_handle, pio_p->csr, PIO_RESET); 289 * 290 * General Rule: replace ddi_putl to ddi_put32 291 */ 292 ddi_put32(pio_p->csr_handle, pio_p->csr, PIO_RESET); 293 mutex_exit(&pio_p->mutex); 294 295 return (0); 296 } 297 298 static int 299 pio_write(dev_t dev, struct uio *uiop, cred_t *credp) 300 { 301 int retval; 302 int error = 0; 303 Pio *pio_p; 304 305 pio_p = ddi_get_soft_state(pio_softstate, getminor(dev)); 306 307 mutex_enter(&pio_p->mutex); 308 /* 309 * Old version is: 310 ddi_putl(pio_p->csr_handle, pio_p->csr, 311 (ddi_getl(pio_p->csr_handle, pio_p->csr) | PIO_INTR_ENABLE)); 312 * 313 * General Rule: replace ddi_putl with ddi_put32. 314 * And replace ddi_getl with ddi_get32. 315 */ 316 ddi_put32(pio_p->csr_handle, pio_p->csr, 317 (ddi_get32(pio_p->csr_handle, pio_p->csr) | PIO_INTR_ENABLE)); 318 319 while (uiop->uio_resid > 0) { 320 cv_wait(&pio_p->cv, &pio_p->mutex); 321 retval = uwritec(uiop); 322 /* 323 * Old version is: 324 ddi_putl(pio_p->data_handle, pio_p->data, (uint32_t)retval); 325 * 326 * General Rule: replace ddi_putl with ddi_put32 327 */ 328 ddi_put32(pio_p->data_handle, pio_p->data, (uint32_t)retval); 329 } 330 /* 331 * Old version is: 332 ddi_putl(pio_p->csr_handle, pio_p->csr, 333 (ddi_getl(pio_p->csr_handle, pio_p->csr) & ~PIO_INTR_ENABLE)); 334 * 335 * General Rule: replace ddi_putl with ddi_put32. 336 * And replace ddi_getl with ddi_get32. 337 */ 338 ddi_put32(pio_p->csr_handle, pio_p->csr, 339 (ddi_get32(pio_p->csr_handle, pio_p->csr) & ~PIO_INTR_ENABLE)); 340 341 /* 342 * Old version: 343 uiomove(pio_p->addr + uiop->uio_offset, 344 min(uiop->uio_resid, pio_p->size - uiop->uio_offset), 345 UIO_WRITE, uiop); 346 * 347 * Since the prototype of uiomove is: 348 * int uiomove(caddr_t address, size_t nbytes, 349 * enum uio_rw rwflag, uio_t *uio_p); 350 * 351 * The old function call has two potential problems. 352 * 353 * Problem 1: the first argument 354 * The type of ''pio_p->addr'' is int *, which points to 32-bit integer 355 * but caddr_t is a pointer to 64-bit integer. The arithmetic 356 * operation on them is different, which causes a problem in porting. 357 * So we should change the type of ''pio_p->addr'' to caddr_t, which is 358 * for 32 and 64 bit address. 359 * 360 * problem 2: the second argument 361 * The return value of min is int. However, it is incompatbile 362 * with size_t on 64-bit system. So we should write a new version 363 * min function for 64-bit system. 364 * 365 * So, it is replaced with the new version as following: 366 */ 367 #ifdef VERSION_64BIT 368 uiomove(pio_p->addr + uiop->uio_offset, 369 (size_t)min_64(uiop->uio_resid, pio_p->size - uiop->uio_offset), 370 UIO_WRITE, uiop); 371 #else 372 uiomove(pio_p->addr + uiop->uio_offset, 373 (size_t)min(uiop->uio_resid, pio_p->size - uiop->uio_offset), 374 UIO_WRITE, uiop); 375 #endif 376 377 mutex_exit(&pio_p->mutex); 378 return (error); 379 } 380 381 #ifdef VERSION_64BIT 382 /* 383 * This is a newly added function for 64-bit version only, which is not used in 384 * the old version. The return value is uint64_t. 385 */ 386 uint64_t 387 min_64(uint64_t int1, uint64_t int2) 388 { 389 return ((int1 < int2) ? (int1) : (int2)); 390 } 391 #endif 392 393 static int 394 pio_ioctl(dev_t dev, int cmd, intptr_t arg, int flags, 395 cred_t *credp, int *rvalp) 396 { 397 Pio *pio_p; 398 int retval = 0; 399 uint32_t tmp; 400 401 pio_p = ddi_get_soft_state(pio_softstate, getminor(dev)); 402 403 switch (cmd) { 404 case PIO_GET_CSR: 405 mutex_enter(&pio_p->mutex); 406 /* 407 * Old version is: 408 tmp = ddi_getl(pio_p->csr_handle, pio_p->csr); 409 * 410 * General Rule: replace ddi_getl to ddi_get32. 411 */ 412 tmp = ddi_get32(pio_p->csr_handle, pio_p->csr); 413 mutex_exit(&pio_p->mutex); 414 415 /* 416 * In this case branch, data sharing may has potential 417 * problem. The old version is: 418 419 if (ddi_copyout((const void *)&tmp, 420 (void *)arg, sizeof (uint32_t), flags) != 0) 421 retval = EFAULT; 422 423 * Since we share variables tmp with user application. 424 * The driver should make it safe for both 32-bit and 425 * 64-bit system, by using ddi_model_convert_from(). 426 * 427 * New version follows: 428 */ 429 #ifdef _MULTI_DATAMODEL 430 switch (ddi_model_convert_from(flags & FMODELS)) { 431 case DDI_MODEL_ILP32: 432 if (ddi_copyout((const void *)&tmp, (void *)arg, 433 sizeof (Pio_csr), flags) != 0) 434 retval = EFAULT; 435 break; 436 case DDI_MODEL_NONE: 437 if (ddi_copyout((const void *)&tmp, (void *)arg, 438 sizeof (uint32_t), flags) != 0) 439 retval = EFAULT; 440 break; 441 } 442 #else 443 if (ddi_copyout((const void *)&tmp, 444 (void *)arg, sizeof (uint32_t), flags) != 0) 445 retval = EFAULT; 446 #endif 447 448 break; 449 case PIO_SET_CSR: 450 mutex_enter(&pio_p->mutex); 451 /* 452 * Old version is: 453 ddi_putl(pio_p->csr_handle, pio_p->csr, (uint32_t)arg); 454 * 455 * General Rule: replace ddi_putl to ddi_put32 456 */ 457 ddi_put32(pio_p->csr_handle, pio_p->csr, (uint32_t)arg); 458 mutex_exit(&pio_p->mutex); 459 break; 460 default: 461 retval = ENOTTY; 462 break; 463 } 464 return (retval); 465 } 466 467 static uint_t 468 pio_intr(caddr_t instance) 469 { 470 Pio *pio_p; 471 uint_t serviced = DDI_INTR_UNCLAIMED; 472 473 pio_p = ddi_get_soft_state(pio_softstate, (uint_t)instance); 474 475 mutex_enter(&pio_p->mutex); 476 /* 477 * Old version is: 478 if (ddi_getl(pio_p->csr_handle, pio_p->csr) & PIO_IDLE_INTR) { 479 * 480 * General Rule: replace ddi_getl to ddi_get32. 481 */ 482 if (ddi_get32(pio_p->csr_handle, pio_p->csr) & PIO_IDLE_INTR) { 483 serviced = DDI_INTR_CLAIMED; 484 /* 485 * Old version is: 486 ddi_putl(pio_p->csr_handle, pio_p->csr, 487 (ddi_getl(pio_p->csr_handle, pio_p->csr)|PIO_INTR_CLEAR)); 488 * 489 * General Rule: replace ddi_putl to ddi_put32. 490 * And, replace ddi_getl to ddi_get32 491 */ 492 ddi_put32(pio_p->csr_handle, pio_p->csr, 493 (ddi_get32(pio_p->csr_handle, pio_p->csr)|PIO_INTR_CLEAR)); 494 cv_signal(&pio_p->cv); 495 } 496 mutex_exit(&pio_p->mutex); 497 498 return (serviced); 499 }