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. sh$ cat -n pio.h 1 #ifndef _PIO_IO_H 2 #define _PIO_IO_H 3 4 #ifdef __cplusplus 5 extern "C" { 6 #endif 7 8 /* 9 * commands for pio_ioctl 10 */ 11 #define PIO_IOC ('p' << 8) 12 #define PIO_GET_CSR (PIO_IOC | 1) 13 #define PIO_SET_CSR (PIO_IOC | 2) 14 15 /* 16 * CSR definition 17 */ 18 typedef uint8_t Pio_csr; 19 20 /* 21 * bit definitions for CSR 22 */ 23 #define PIO_ENABLE 0x01 24 #define PIO_INTR_ENABLE 0x02 25 #define PIO_INTR_CLEAR 0x04 26 #define PIO_RESERVED1 0x08 27 #define PIO_RESERVED2 0x10 28 #define PIO_RESERVED3 0x20 29 #define PIO_DEV_READY 0x40 30 #define PIO_IDLE_INTR 0x80 31 32 /* 33 * useful combinations of the above 34 */ 35 #define PIO_RESET 0x00 36 37 #ifdef __cplusplus 38 } 39 #endif 40 41 #endif /* _PIO_IO_H */ sh$ cat -n pio_32.c 1 /* 2 * Sample Code: pio_32.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 * This is a 32bit sample code, which can be built in/run on 17 * 32bit environment correctly. But, this driver need do some 18 * modification to be the 64bit and 32bit common driver. 19 */ 20 typedef struct pio { /* per-unit structure */ 21 dev_info_t *dip; 22 kcondvar_t cv; 23 kmutex_t mutex; 24 int pio_state; /* driver state */ 25 ddi_iblock_cookie_t iblock_cookie; /* for mutexes */ 26 ddi_acc_handle_t csr_handle; /* access handle to csr */ 27 ddi_acc_handle_t data_handle; /* access handle to data */ 28 Pio_csr *csr; /* mapped to CSR on device */ 29 uint_32 *data; /* data register on device */ 30 int size; 31 int *addr; 32 ddi_umem_cookie_t umem_cookie; 33 } Pio; 34 35 #define PIO_OPEN 0x01 /* pio_state */ 36 37 static void *pio_softstate; /* opaque handle top of state structs */ 38 39 static int pio_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 40 static int pio_attach(dev_info_t *, ddi_attach_cmd_t); 41 static int pio_open(dev_t *, int, int, cred_t *); 42 static int pio_close(dev_t, int, int, cred_t *); 43 static int pio_write(dev_t, struct uio *, cred_t *); 44 static int pio_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 45 static uint_t pio_intr(caddr_t); 46 static int pio_detach(dev_info_t *, ddi_detach_cmd_t); 47 48 static struct cb_ops pio_cb_ops = { 49 pio_open, 50 pio_close, 51 nodev, /* not a block driver */ 52 nodev, /* no print routine */ 53 nodev, /* no dump routine */ 54 nodev, /* no read routine; write-only device */ 55 pio_write, 56 pio_ioctl, 57 nodev, /* no devmap routine */ 58 nodev, /* no mmap routine */ 59 nodev, /* no segmap routine */ 60 nochpoll, /* no chpoll routine */ 61 ddi_prop_op, 62 0, /* not a STREAMS driver */ 63 D_NEW | D_MP, /* safe for multi-thread/multi-processor */ 64 }; 65 66 static struct dev_ops pio_ops = { 67 DEVO_REV, /* devo_rev */ 68 0, /* devo_refcnt */ 69 pio_getinfo, /* devo_getinfo */ 70 nulldev, /* devo_identify */ 71 nulldev, /* devo_probe */ 72 pio_attach, /* devo_attach */ 73 pio_detach, /* devo_detach */ 74 nodev, /* devo_reset */ 75 &pio_cb_ops, /* devo_cb_ops */ 76 (struct bus_ops *)0, /* devo_bus_ops */ 77 NULL, /* devo_power */ 78 }; 79 80 static struct modldrv modldrv = { 81 &mod_driverops, 82 "sample PIO driver 1.2", 83 &pio_ops, 84 }; 85 86 static struct modlinkage modlinkage = { 87 MODREV_1, /* MODREV_1 manual */ 88 (void *)&modldrv, /* device driver linkage */ 89 NULL, /* list terminator */ 90 }; 91 92 int 93 _init(void) 94 { 95 int error; 96 97 ddi_soft_state_init(&pio_softstate, sizeof (Pio), 1); 98 if ((error = mod_install(&modlinkage)) != 0) 99 ddi_soft_state_fini(&pio_softstate); 100 101 return (error); 102 } 103 104 int 105 _info(struct modinfo *modinfop) 106 { 107 return (mod_info(&modlinkage, modinfop)); 108 } 109 110 int 111 _fini(void) 112 { 113 int status; 114 115 if ((status = mod_remove(&modlinkage)) != 0) 116 return (status); 117 ddi_soft_state_fini(&pio_softstate); 118 119 return (status); 120 } 121 122 static int 123 pio_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 124 { 125 int instance; 126 Pio *pio_p; 127 ddi_device_acc_attr_t dev_acc_attr; /* device access attributes */ 128 129 switch (cmd) { 130 case DDI_ATTACH: 131 instance = ddi_get_instance(dip); 132 ddi_soft_state_zalloc(pio_softstate, instance); 133 134 pio_p = ddi_get_soft_state(pio_softstate, instance); 135 ddi_set_driver_private(dip, (caddr_t)pio_p); 136 pio_p->dip = dip; 137 pio_p->size = 600 * 1024; 138 pio_p->addr = (void*)ddi_umem_alloc( 139 pio_p->size, DDI_UMEM_NOSLEEP, &pio_p->umem_cookie); 140 141 ddi_get_iblock_cookie(dip, 0, &pio_p->iblock_cookie); 142 mutex_init(&pio_p->mutex, NULL, MUTEX_DRIVER, 143 pio_p->iblock_cookie); 144 ddi_add_intr(dip, 0, &pio_p->iblock_cookie, NULL, 145 pio_intr, (caddr_t)instance); 146 147 dev_acc_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 148 dev_acc_attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 149 dev_acc_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 150 151 ddi_regs_map_setup(dip, 0, (caddr_t *)&(pio_p->csr), 0, 152 sizeof (Pio_csr), &dev_acc_attr, &pio_p->csr_handle); 153 ddi_regs_map_setup(dip, 1, (caddr_t *)&(pio_p->data), 0, 154 sizeof (uchar_t), &dev_acc_attr, &pio_p->data_handle); 155 ddi_create_minor_node(dip, ddi_get_name(dip), S_IFCHR, 156 instance, DDI_PSEUDO, 0); 157 ddi_putl(pio_p->csr_handle, pio_p->csr, PIO_RESET); 158 ddi_report_dev(dip); 159 return (DDI_SUCCESS); 160 case DDI_SUSPEND: 161 case DDI_PM_SUSPEND: 162 return (DDI_SUCCESS); 163 default: 164 return (DDI_FAILURE); 165 } 166 } 167 168 static int 169 pio_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 170 { 171 int error = DDI_SUCCESS; 172 Pio *pio_p; 173 int instance = getminor((dev_t)arg); 174 175 switch (infocmd) { 176 case DDI_INFO_DEVT2DEVINFO: 177 pio_p = ddi_get_soft_state(pio_softstate, instance); 178 mutex_enter(&pio_p->mutex); 179 *result = pio_p->dip; 180 mutex_exit(&pio_p->mutex); 181 break; 182 case DDI_INFO_DEVT2INSTANCE: 183 *result = (void *)instance; 184 break; 185 default: 186 *result = NULL; 187 error = DDI_FAILURE; 188 } 189 return (error); 190 } 191 192 static int 193 pio_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 194 { 195 Pio *pio_p; 196 int instance; 197 198 switch (cmd) { 199 case DDI_DETACH: 200 instance = ddi_get_instance(dip); 201 pio_p = ddi_get_soft_state(pio_softstate, instance); 202 ddi_putl(pio_p->csr_handle, pio_p->csr, PIO_RESET); 203 ddi_umem_free(pio_p->umem_cookie); 204 ddi_remove_minor_node(dip, NULL); 205 ddi_regs_map_free(&pio_p->csr_handle); 206 ddi_regs_map_free(&pio_p->data_handle); 207 ddi_remove_intr(pio_p->dip, 0, pio_p->iblock_cookie); 208 mutex_destroy(&pio_p->mutex); 209 ddi_soft_state_free(pio_softstate, instance); 210 /* FALL THROUGH */ 211 case DDI_SUSPEND: 212 case DDI_PM_SUSPEND: 213 return (DDI_SUCCESS); 214 default: 215 return (DDI_FAILURE); 216 } 217 } 218 219 static int 220 pio_open(dev_t *dev, int openflags, int otyp, cred_t *credp) 221 { 222 int retval = 0; 223 Pio *pio_p; 224 225 pio_p = ddi_get_soft_state(pio_softstate, getminor(*dev)); 226 227 mutex_enter(&pio_p->mutex); 228 pio_p->pio_state |= PIO_OPEN; 229 ddi_putl(pio_p->csr_handle, pio_p->csr, PIO_ENABLE); 230 mutex_exit(&pio_p->mutex); 231 232 return (retval); 233 } 234 235 static int 236 pio_close(dev_t dev, int openflags, int otyp, cred_t *credp) 237 { 238 Pio *pio_p; 239 240 pio_p = ddi_get_soft_state(pio_softstate, getminor(dev)); 241 242 mutex_enter(&pio_p->mutex); 243 pio_p->pio_state &= ~PIO_OPEN; 244 ddi_putl(pio_p->csr_handle, pio_p->csr, PIO_RESET); 245 mutex_exit(&pio_p->mutex); 246 247 return (0); 248 } 249 250 static int 251 pio_write(dev_t dev, struct uio *uiop, cred_t *credp) 252 { 253 int retval; 254 int error = 0; 255 Pio *pio_p; 256 257 pio_p = ddi_get_soft_state(pio_softstate, getminor(dev)); 258 259 mutex_enter(&pio_p->mutex); 260 ddi_putl(pio_p->csr_handle, pio_p->csr, 261 (ddi_getl(pio_p->csr_handle, pio_p->csr) | PIO_INTR_ENABLE)); 262 while (uiop->uio_resid > 0) { 263 cv_wait(&pio_p->cv, &pio_p->mutex); 264 retval = uwritec(uiop); 265 ddi_putl(pio_p->data_handle, pio_p->data, (uint32_t)retval); 266 } 267 ddi_putl(pio_p->csr_handle, pio_p->csr, 268 (ddi_getl(pio_p->csr_handle, pio_p->csr) & ~PIO_INTR_ENABLE)); 269 270 uiomove(pio_p->addr + uiop->uio_offset, 271 min(uiop->uio_resid, pio_p->size - uiop->uio_offset), 272 UIO_WRITE, uiop); 273 mutex_exit(&pio_p->mutex); 274 275 return (error); 276 } 277 278 static int 279 pio_ioctl(dev_t dev, int cmd, intptr_t arg, int flags, 280 cred_t *credp, int *rvalp) 281 { 282 Pio *pio_p; 283 int retval = 0; 284 uint32_t tmp; 285 286 pio_p = ddi_get_soft_state(pio_softstate, getminor(dev)); 287 288 switch (cmd) { 289 case PIO_GET_CSR: 290 mutex_enter(&pio_p->mutex); 291 tmp = ddi_getl(pio_p->csr_handle, pio_p->csr); 292 mutex_exit(&pio_p->mutex); 293 if (ddi_copyout((const void *)&tmp, 294 (void *)arg, sizeof (uint32_t), flags) != 0) 295 retval = EFAULT; 296 break; 297 case PIO_SET_CSR: 298 mutex_enter(&pio_p->mutex); 299 ddi_putl(pio_p->csr_handle, pio_p->csr, (uint32_t)arg); 300 mutex_exit(&pio_p->mutex); 301 break; 302 default: 303 retval = ENOTTY; 304 break; 305 } 306 return (retval); 307 } 308 309 static uint_t 310 pio_intr(caddr_t instance) 311 { 312 Pio *pio_p; 313 uint_t serviced = DDI_INTR_UNCLAIMED; 314 315 pio_p = ddi_get_soft_state(pio_softstate, (uint_t)instance); 316 317 mutex_enter(&pio_p->mutex); 318 if (ddi_getl(pio_p->csr_handle, pio_p->csr) & PIO_IDLE_INTR) { 319 serviced = DDI_INTR_CLAIMED; 320 ddi_putl(pio_p->csr_handle, pio_p->csr, 321 (ddi_getl(pio_p->csr_handle, pio_p->csr)|PIO_INTR_CLEAR)); 322 cv_signal(&pio_p->cv); 323 } 324 mutex_exit(&pio_p->mutex); 325 326 return (serviced); 327 }