ugen.c revision 7492:2387323b838f
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 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 22 * Use is subject to license terms. 23 */ 24 25 26/* 27 * UGEN: USB Generic Driver 28 * 29 * The "Universal Generic Driver" (UGEN) for USB devices provides interfaces 30 * to talk to USB devices. This is very useful for Point of Sale sale 31 * devices and other simple devices like USB scanner, USB palm pilot. 32 * The UGEN provides a system call interface to USB devices enabling 33 * a USB device vendor to write an application for his 34 * device instead of writing a driver. This facilitates the vendor to write 35 * device management s/w quickly in userland. 36 * 37 * UGEN supports read/write/poll entry points. An application can be written 38 * using read/write/aioread/aiowrite/poll system calls to communicate 39 * with the device. 40 */ 41#include <sys/usb/usba/usbai_version.h> 42#include <sys/usb/usba.h> 43#include <sys/usb/usba/usba_ugen.h> 44#include <sys/usb/clients/ugen/ugend.h> 45 46/* Global variables */ 47static void *ugen_skel_statep; 48 49/* Prototypes declarations for the entry points */ 50static int ugen_skel_getinfo(dev_info_t *, ddi_info_cmd_t, 51 void *, void **); 52static int ugen_skel_open(dev_t *, int, int, cred_t *); 53static int ugen_skel_close(dev_t, int, int, cred_t *); 54static int ugen_skel_attach(dev_info_t *, ddi_attach_cmd_t); 55static int ugen_skel_detach(dev_info_t *, ddi_detach_cmd_t); 56static int ugen_skel_power(dev_info_t *, int, int); 57static int ugen_skel_read(dev_t, struct uio *, cred_t *); 58static int ugen_skel_write(dev_t, struct uio *, cred_t *); 59static int ugen_skel_poll(dev_t, short, int, short *, 60 struct pollhead **); 61 62static int ugen_skel_disconnect_ev_cb(dev_info_t *); 63static int ugen_skel_reconnect_ev_cb(dev_info_t *); 64 65/* event support */ 66static usb_event_t ugen_skel_events = { 67 ugen_skel_disconnect_ev_cb, 68 ugen_skel_reconnect_ev_cb, 69 NULL, NULL 70}; 71 72/* Driver cb_ops structure */ 73static struct cb_ops ugen_skel_cb_ops = { 74 ugen_skel_open, /* open */ 75 ugen_skel_close, /* close */ 76 nodev, /* strategy */ 77 nodev, /* print */ 78 nodev, /* dump */ 79 ugen_skel_read, /* read */ 80 ugen_skel_write, /* write */ 81 nodev, /* ioctl */ 82 nodev, /* devmap */ 83 nodev, /* mmap */ 84 nodev, /* segmap */ 85 ugen_skel_poll, /* poll */ 86 ddi_prop_op, /* cb_prop_op */ 87 0, /* streamtab */ 88 D_MP, /* Driver compatibility flag */ 89 CB_REV, /* revision */ 90 nodev, /* aread */ 91 nodev /* awrite */ 92}; 93 94/* 95 * Modloading support 96 * driver dev_ops structure 97 */ 98static struct dev_ops ugen_skel_ops = { 99 DEVO_REV, /* devo_rev, */ 100 0, /* refct */ 101 ugen_skel_getinfo, /* info */ 102 nulldev, /* indetify */ 103 nulldev, /* probe */ 104 ugen_skel_attach, /* attach */ 105 ugen_skel_detach, /* detach */ 106 nodev, /* reset */ 107 &ugen_skel_cb_ops, /* driver operations */ 108 NULL, /* bus operations */ 109 ugen_skel_power /* power */ 110}; 111 112static struct modldrv modldrv = { 113 &mod_driverops, /* Module type */ 114 "USB Generic driver", /* Name of the module. */ 115 &ugen_skel_ops, /* driver ops */ 116}; 117 118static struct modlinkage modlinkage = { 119 MODREV_1, 120 (void *)&modldrv, 121 NULL 122}; 123 124 125int 126_init() 127{ 128 int rval; 129 130 if ((rval = ddi_soft_state_init(&ugen_skel_statep, 131 sizeof (ugen_skel_state_t), UGEN_INSTANCES)) != 0) { 132 133 return (rval); 134 } 135 136 if ((rval = mod_install(&modlinkage)) != 0) { 137 ddi_soft_state_fini(&ugen_skel_statep); 138 139 return (rval); 140 } 141 142 return (rval); 143} 144 145 146int 147_fini() 148{ 149 int rval; 150 151 if ((rval = mod_remove(&modlinkage)) != 0) { 152 153 return (rval); 154 } 155 ddi_soft_state_fini(&ugen_skel_statep); 156 157 return (rval); 158} 159 160 161int 162_info(struct modinfo *modinfop) 163{ 164 return (mod_info(&modlinkage, modinfop)); 165} 166 167 168/*ARGSUSED*/ 169static int 170ugen_skel_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 171 void **result) 172{ 173 int rval = DDI_FAILURE; 174 int instance = 175 UGEN_MINOR_TO_INSTANCE(getminor((dev_t)arg)); 176 ugen_skel_state_t *ugen_skelp; 177 178 switch (infocmd) { 179 case DDI_INFO_DEVT2DEVINFO: 180 ugen_skelp = ddi_get_soft_state(ugen_skel_statep, instance); 181 if (ugen_skelp != NULL) { 182 *result = ugen_skelp->ugen_skel_dip; 183 if (*result != NULL) { 184 rval = DDI_SUCCESS; 185 } 186 } else { 187 *result = NULL; 188 } 189 190 break; 191 case DDI_INFO_DEVT2INSTANCE: 192 *result = (void *)(uintptr_t)instance; 193 rval = DDI_SUCCESS; 194 195 break; 196 default: 197 198 break; 199 } 200 201 return (rval); 202} 203 204 205/* 206 * ugen_skel_attach() 207 */ 208static int 209ugen_skel_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 210{ 211 ugen_skel_state_t *ugen_skelp; 212 int instance; /* Driver instance number */ 213 int rval; 214 usb_ugen_info_t usb_ugen_info; 215 216 /* Get instance number */ 217 instance = ddi_get_instance(dip); 218 219 switch (cmd) { 220 case DDI_ATTACH: 221 222 break; 223 case DDI_RESUME: 224 ugen_skelp = ddi_get_soft_state(ugen_skel_statep, instance); 225 if (ugen_skelp == NULL) { 226 227 return (DDI_FAILURE); 228 } 229 230 rval = usb_ugen_attach(ugen_skelp->ugen_skel_hdl, cmd); 231 232 return (rval == USB_SUCCESS ? DDI_SUCCESS : DDI_FAILURE); 233 default: 234 235 return (DDI_FAILURE); 236 } 237 238 if (ddi_soft_state_zalloc(ugen_skel_statep, instance) == 239 DDI_SUCCESS) { 240 ugen_skelp = ddi_get_soft_state(ugen_skel_statep, 241 instance); 242 } 243 if (ugen_skelp == NULL) { 244 245 return (DDI_FAILURE); 246 } 247 248 if ((rval = usb_client_attach(dip, USBDRV_VERSION, 0)) != 249 USB_SUCCESS) { 250 251 goto fail; 252 } 253 254 ugen_skelp->ugen_skel_dip = dip; 255 ugen_skelp->ugen_skel_instance = instance; 256 257 /* get a ugen handle */ 258 bzero(&usb_ugen_info, sizeof (usb_ugen_info)); 259 usb_ugen_info.usb_ugen_flags = 260 USB_UGEN_ENABLE_PM | USB_UGEN_REMOVE_CHILDREN; 261 usb_ugen_info.usb_ugen_minor_node_ugen_bits_mask = 262 (dev_t)UGEN_MINOR_UGEN_BITS_MASK; 263 usb_ugen_info.usb_ugen_minor_node_instance_mask = 264 (dev_t)~UGEN_MINOR_UGEN_BITS_MASK; 265 ugen_skelp->ugen_skel_hdl = usb_ugen_get_hdl(dip, 266 &usb_ugen_info); 267 268 if (usb_ugen_attach(ugen_skelp->ugen_skel_hdl, cmd) != USB_SUCCESS) { 269 270 goto fail; 271 } 272 273 /* register for hotplug events */ 274 if (usb_register_event_cbs(dip, &ugen_skel_events, 0) != USB_SUCCESS) { 275 276 goto fail; 277 } 278 279 ddi_report_dev(dip); 280 281 return (DDI_SUCCESS); 282 283fail: 284 if (ugen_skelp) { 285 usb_unregister_event_cbs(dip, &ugen_skel_events); 286 usb_ugen_release_hdl(ugen_skelp-> 287 ugen_skel_hdl); 288 ddi_soft_state_free(ugen_skel_statep, 289 ugen_skelp->ugen_skel_instance); 290 usb_client_detach(dip, NULL); 291 } 292 293 return (DDI_FAILURE); 294} 295 296 297/* 298 * ugen_skel_detach() 299 */ 300static int 301ugen_skel_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 302{ 303 int rval = USB_FAILURE; 304 ugen_skel_state_t *ugen_skelp = ddi_get_soft_state(ugen_skel_statep, 305 ddi_get_instance(dip)); 306 307 if (ugen_skelp) { 308 switch (cmd) { 309 case DDI_DETACH: 310 rval = usb_ugen_detach(ugen_skelp->ugen_skel_hdl, cmd); 311 if (rval == USB_SUCCESS) { 312 usb_unregister_event_cbs(dip, 313 &ugen_skel_events); 314 usb_ugen_release_hdl(ugen_skelp-> 315 ugen_skel_hdl); 316 ddi_soft_state_free(ugen_skel_statep, 317 ugen_skelp->ugen_skel_instance); 318 usb_client_detach(dip, NULL); 319 } 320 321 break; 322 case DDI_SUSPEND: 323 rval = usb_ugen_detach(ugen_skelp->ugen_skel_hdl, cmd); 324 325 break; 326 default: 327 328 break; 329 } 330 } 331 332 return (rval == USB_SUCCESS ? DDI_SUCCESS : DDI_FAILURE); 333} 334 335 336/* 337 * ugen_skel_disconnect_ev_cb: 338 */ 339static int 340ugen_skel_disconnect_ev_cb(dev_info_t *dip) 341{ 342 ugen_skel_state_t *ugen_skelp = ddi_get_soft_state(ugen_skel_statep, 343 ddi_get_instance(dip)); 344 345 return (usb_ugen_disconnect_ev_cb(ugen_skelp->ugen_skel_hdl)); 346} 347 348 349/* 350 * ugen_skel_reconnect_ev_cb: 351 */ 352static int 353ugen_skel_reconnect_ev_cb(dev_info_t *dip) 354{ 355 ugen_skel_state_t *ugen_skelp = ddi_get_soft_state(ugen_skel_statep, 356 ddi_get_instance(dip)); 357 358 return (usb_ugen_reconnect_ev_cb(ugen_skelp->ugen_skel_hdl)); 359} 360 361 362/* 363 * ugen_skel_open: 364 */ 365static int 366ugen_skel_open(dev_t *devp, int flag, int sflag, cred_t *cr) 367{ 368 ugen_skel_state_t *ugen_skelp; 369 370 if ((ugen_skelp = ddi_get_soft_state(ugen_skel_statep, 371 UGEN_MINOR_TO_INSTANCE(getminor(*devp)))) == NULL) { 372 /* deferred detach */ 373 374 return (ENXIO); 375 } 376 377 return (usb_ugen_open(ugen_skelp->ugen_skel_hdl, devp, flag, 378 sflag, cr)); 379} 380 381 382/* 383 * ugen_skel_close() 384 */ 385static int 386ugen_skel_close(dev_t dev, int flag, int otype, cred_t *cr) 387{ 388 ugen_skel_state_t *ugen_skelp = ddi_get_soft_state(ugen_skel_statep, 389 UGEN_MINOR_TO_INSTANCE(getminor(dev))); 390 391 return (usb_ugen_close(ugen_skelp->ugen_skel_hdl, dev, flag, 392 otype, cr)); 393} 394 395 396/* 397 * ugen_skel_read/write() 398 */ 399static int 400ugen_skel_read(dev_t dev, struct uio *uiop, cred_t *credp) 401{ 402 ugen_skel_state_t *ugen_skelp = ddi_get_soft_state(ugen_skel_statep, 403 UGEN_MINOR_TO_INSTANCE(getminor(dev))); 404 if (ugen_skelp == NULL) { 405 406 return (ENXIO); 407 } 408 409 return (usb_ugen_read(ugen_skelp->ugen_skel_hdl, dev, 410 uiop, credp)); 411} 412 413 414static int 415ugen_skel_write(dev_t dev, struct uio *uiop, cred_t *credp) 416{ 417 ugen_skel_state_t *ugen_skelp = ddi_get_soft_state(ugen_skel_statep, 418 UGEN_MINOR_TO_INSTANCE(getminor(dev))); 419 if (ugen_skelp == NULL) { 420 421 return (ENXIO); 422 } 423 return (usb_ugen_write(ugen_skelp->ugen_skel_hdl, 424 dev, uiop, credp)); 425} 426 427 428/* 429 * ugen_skel_poll 430 */ 431static int 432ugen_skel_poll(dev_t dev, short events, 433 int anyyet, short *reventsp, struct pollhead **phpp) 434{ 435 ugen_skel_state_t *ugen_skelp = ddi_get_soft_state(ugen_skel_statep, 436 UGEN_MINOR_TO_INSTANCE(getminor(dev))); 437 if (ugen_skelp == NULL) { 438 439 return (ENXIO); 440 } 441 442 return (usb_ugen_poll(ugen_skelp->ugen_skel_hdl, dev, events, 443 anyyet, reventsp, phpp)); 444} 445 446 447/* 448 * ugen_skel_power: 449 * PM entry point 450 */ 451static int 452ugen_skel_power(dev_info_t *dip, int comp, int level) 453{ 454 int rval; 455 456 ugen_skel_state_t *ugen_skelp = ddi_get_soft_state(ugen_skel_statep, 457 ddi_get_instance(dip)); 458 if (ugen_skelp == NULL) { 459 460 return (DDI_FAILURE); 461 } 462 rval = usb_ugen_power(ugen_skelp->ugen_skel_hdl, comp, level); 463 464 return (rval == USB_SUCCESS ? DDI_SUCCESS : DDI_FAILURE); 465} 466