1 /* $NetBSD: pseye.c,v 1.11 2009/02/03 13:31:24 jmcneill Exp $ */ 2 3 /*- 4 * Copyright (c) 2008 Jared D. McNeill <jmcneill@invisible.ca> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /* 30 * Sony PLAYSTATION(R) Eye Driver 31 * 32 * The only documentation we have for this part is based on a series 33 * of forum postings by Jim Paris on ps2dev.org. Many thanks for 34 * figuring this one out. 35 * 36 * URL: http://forums.ps2dev.org/viewtopic.php?t=9238 37 */ 38 39 #include <sys/cdefs.h> 40 __KERNEL_RCSID(0, "$NetBSD: pseye.c,v 1.11 2009/02/03 13:31:24 jmcneill Exp $"); 41 42 #include <sys/param.h> 43 #include <sys/systm.h> 44 #include <sys/device.h> 45 #include <sys/malloc.h> 46 #include <sys/fcntl.h> 47 #include <sys/conf.h> 48 #include <sys/poll.h> 49 #include <sys/bus.h> 50 #include <sys/mutex.h> 51 #include <sys/kthread.h> 52 #include <sys/condvar.h> 53 #include <sys/module.h> 54 55 #include <uvm/uvm_extern.h> 56 57 #include <dev/usb/usb.h> 58 #include <dev/usb/usbdi.h> 59 #include <dev/usb/usbdi_util.h> 60 #include <dev/usb/usbdevs.h> 61 62 #include <dev/video_if.h> 63 64 #define PRI_PSEYE PRI_BIO 65 66 /* Bulk-in buffer length */ 67 #define PSEYE_BULKIN_BUFLEN (640 * 480 * 2) 68 69 /* SCCB/sensor interface */ 70 #define PSEYE_SCCB_ADDRESS 0xf1 71 #define PSEYE_SCCB_SUBADDR 0xf2 72 #define PSEYE_SCCB_WRITE 0xf3 73 #define PSEYE_SCCB_READ 0xf4 74 #define PSEYE_SCCB_OPERATION 0xf5 75 #define PSEYE_SCCB_STATUS 0xf6 76 77 #define PSEYE_SCCB_OP_WRITE_3 0x37 78 #define PSEYE_SCCB_OP_WRITE_2 0x33 79 #define PSEYE_SCCB_OP_READ_2 0xf9 80 81 struct pseye_softc { 82 USBBASEDEVICE sc_dev; 83 84 usbd_device_handle sc_udev; 85 usbd_interface_handle sc_iface; 86 87 device_t sc_videodev; 88 char sc_running; 89 90 kcondvar_t sc_cv; 91 kmutex_t sc_mtx; 92 93 usbd_pipe_handle sc_bulkin_pipe; 94 usbd_xfer_handle sc_bulkin_xfer; 95 int sc_bulkin; 96 uint8_t *sc_bulkin_buffer; 97 int sc_bulkin_bufferlen; 98 99 char sc_dying; 100 }; 101 102 static int pseye_match(device_t, cfdata_t, void *); 103 static void pseye_attach(device_t, device_t, void *); 104 static int pseye_detach(device_t, int); 105 static void pseye_childdet(device_t, device_t); 106 static int pseye_activate(device_t, enum devact); 107 108 static void pseye_init(struct pseye_softc *); 109 static void pseye_sccb_init(struct pseye_softc *); 110 static void pseye_stop(struct pseye_softc *); 111 static void pseye_start(struct pseye_softc *); 112 static void pseye_led(struct pseye_softc *, bool); 113 static uint8_t pseye_getreg(struct pseye_softc *, uint16_t); 114 static void pseye_setreg(struct pseye_softc *, uint16_t, uint8_t); 115 static void pseye_setregv(struct pseye_softc *, uint16_t, uint8_t); 116 static void pseye_sccb_setreg(struct pseye_softc *, uint8_t, uint8_t); 117 static bool pseye_sccb_status(struct pseye_softc *); 118 119 static int pseye_init_pipes(struct pseye_softc *); 120 static int pseye_close_pipes(struct pseye_softc *); 121 122 static usbd_status pseye_get_frame(struct pseye_softc *); 123 124 /* video(9) API */ 125 static int pseye_open(void *, int); 126 static void pseye_close(void *); 127 static const char * pseye_get_devname(void *); 128 static int pseye_enum_format(void *, uint32_t, 129 struct video_format *); 130 static int pseye_get_format(void *, struct video_format *); 131 static int pseye_set_format(void *, struct video_format *); 132 static int pseye_try_format(void *, struct video_format *); 133 static int pseye_start_transfer(void *); 134 static int pseye_stop_transfer(void *); 135 136 CFATTACH_DECL2_NEW(pseye, sizeof(struct pseye_softc), 137 pseye_match, pseye_attach, pseye_detach, pseye_activate, 138 NULL, pseye_childdet); 139 140 static const struct video_hw_if pseye_hw_if = { 141 .open = pseye_open, 142 .close = pseye_close, 143 .get_devname = pseye_get_devname, 144 .enum_format = pseye_enum_format, 145 .get_format = pseye_get_format, 146 .set_format = pseye_set_format, 147 .try_format = pseye_try_format, 148 .start_transfer = pseye_start_transfer, 149 .stop_transfer = pseye_stop_transfer, 150 .control_iter_init = NULL, 151 .control_iter_next = NULL, 152 .get_control_desc_group = NULL, 153 .get_control_group = NULL, 154 .set_control_group = NULL, 155 }; 156 157 static int 158 pseye_match(device_t parent, cfdata_t match, void *opaque) 159 { 160 struct usbif_attach_arg *uaa = opaque; 161 162 if (uaa->class != UICLASS_VENDOR) 163 return UMATCH_NONE; 164 165 if (uaa->vendor == USB_VENDOR_OMNIVISION2) { 166 switch (uaa->product) { 167 case USB_PRODUCT_OMNIVISION2_PSEYE: 168 if (uaa->ifaceno != 0) 169 return UMATCH_NONE; 170 return UMATCH_VENDOR_PRODUCT; 171 } 172 } 173 174 return UMATCH_NONE; 175 } 176 177 static void 178 pseye_attach(device_t parent, device_t self, void *opaque) 179 { 180 struct pseye_softc *sc = device_private(self); 181 struct usbif_attach_arg *uaa = opaque; 182 usbd_device_handle dev = uaa->device; 183 usb_interface_descriptor_t *id = NULL; 184 usb_endpoint_descriptor_t *ed = NULL, *ed_bulkin = NULL; 185 char *devinfo; 186 int i; 187 188 devinfo = usbd_devinfo_alloc(dev, 0); 189 aprint_naive("\n"); 190 aprint_normal(": %s\n", devinfo); 191 usbd_devinfo_free(devinfo); 192 193 sc->sc_dev = self; 194 sc->sc_udev = dev; 195 sc->sc_iface = uaa->iface; 196 sc->sc_bulkin_bufferlen = PSEYE_BULKIN_BUFLEN; 197 198 sc->sc_dying = sc->sc_running = 0; 199 cv_init(&sc->sc_cv, device_xname(self)); 200 mutex_init(&sc->sc_mtx, MUTEX_DEFAULT, IPL_NONE); 201 202 id = usbd_get_interface_descriptor(sc->sc_iface); 203 if (id == NULL) { 204 aprint_error_dev(self, "failed to get interface descriptor\n"); 205 sc->sc_dying = 1; 206 return; 207 } 208 209 for (i = 0; i < id->bNumEndpoints; i++) { 210 ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i); 211 if (ed == NULL) { 212 aprint_error_dev(self, "couldn't get ep %d\n", i); 213 sc->sc_dying = 1; 214 return; 215 } 216 217 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && 218 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { 219 ed_bulkin = ed; 220 break; 221 } 222 } 223 224 if (ed_bulkin == NULL) { 225 aprint_error_dev(self, "no bulk-in endpoint found\n"); 226 sc->sc_dying = 1; 227 return; 228 } 229 230 sc->sc_bulkin = ed_bulkin->bEndpointAddress; 231 232 sc->sc_bulkin_xfer = usbd_alloc_xfer(sc->sc_udev); 233 if (sc->sc_bulkin_xfer == NULL) { 234 sc->sc_dying = 1; 235 return; 236 } 237 sc->sc_bulkin_buffer = usbd_alloc_buffer(sc->sc_bulkin_xfer, 238 sc->sc_bulkin_bufferlen); 239 if (sc->sc_bulkin_buffer == NULL) { 240 usbd_free_xfer(sc->sc_bulkin_xfer); 241 sc->sc_bulkin_xfer = NULL; 242 sc->sc_dying = 1; 243 return; 244 } 245 246 pseye_init(sc); 247 248 if (!pmf_device_register(self, NULL, NULL)) 249 aprint_error_dev(self, "couldn't establish power handler\n"); 250 251 sc->sc_videodev = video_attach_mi(&pseye_hw_if, self); 252 if (sc->sc_videodev == NULL) { 253 aprint_error_dev(self, "couldn't attach video layer\n"); 254 sc->sc_dying = 1; 255 return; 256 } 257 258 usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev, 259 USBDEV(self)); 260 261 } 262 263 static int 264 pseye_detach(device_t self, int flags) 265 { 266 struct pseye_softc *sc = device_private(self); 267 268 sc->sc_dying = 1; 269 270 pmf_device_deregister(self); 271 272 if (sc->sc_videodev != NULL) { 273 config_detach(sc->sc_videodev, flags); 274 sc->sc_videodev = NULL; 275 } 276 277 if (sc->sc_bulkin_xfer != NULL) { 278 usbd_free_xfer(sc->sc_bulkin_xfer); 279 sc->sc_bulkin_xfer = NULL; 280 } 281 282 if (sc->sc_bulkin_pipe != NULL) { 283 usbd_abort_pipe(sc->sc_bulkin_pipe); 284 sc->sc_bulkin_pipe = NULL; 285 } 286 287 mutex_enter(&sc->sc_mtx); 288 if (sc->sc_running) { 289 sc->sc_running = 0; 290 cv_wait_sig(&sc->sc_cv, &sc->sc_mtx); 291 } 292 mutex_exit(&sc->sc_mtx); 293 294 cv_destroy(&sc->sc_cv); 295 mutex_destroy(&sc->sc_mtx); 296 297 usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, 298 USBDEV(sc->sc_dev)); 299 300 return 0; 301 } 302 303 int 304 pseye_activate(device_ptr_t self, enum devact act) 305 { 306 struct pseye_softc *sc = device_private(self); 307 int rv; 308 309 rv = 0; 310 311 switch (act) { 312 case DVACT_ACTIVATE: 313 break; 314 case DVACT_DEACTIVATE: 315 sc->sc_dying = 1; 316 break; 317 } 318 319 return rv; 320 } 321 322 static void 323 pseye_childdet(device_t self, device_t child) 324 { 325 struct pseye_softc *sc = device_private(self); 326 327 if (sc->sc_videodev) { 328 KASSERT(sc->sc_videodev == child); 329 sc->sc_videodev = NULL; 330 } 331 } 332 333 /* 334 * Device access 335 */ 336 337 static void 338 pseye_init(struct pseye_softc *sc) 339 { 340 pseye_sccb_init(sc); 341 342 pseye_setregv(sc, 0xc2, 0x0c); 343 pseye_setregv(sc, 0x88, 0xf8); 344 pseye_setregv(sc, 0xc3, 0x69); 345 pseye_setregv(sc, 0x89, 0xff); 346 pseye_setregv(sc, 0x76, 0x03); 347 pseye_setregv(sc, 0x92, 0x01); 348 pseye_setregv(sc, 0x93, 0x18); 349 pseye_setregv(sc, 0x94, 0x10); 350 pseye_setregv(sc, 0x95, 0x10); 351 pseye_setregv(sc, 0xe2, 0x00); 352 pseye_setregv(sc, 0xe7, 0x3e); 353 354 pseye_setreg(sc, 0x1c, 0x0a); 355 pseye_setreg(sc, 0x1d, 0x22); 356 pseye_setreg(sc, 0x1d, 0x06); 357 pseye_setregv(sc, 0x96, 0x00); 358 359 pseye_setreg(sc, 0x97, 0x20); 360 pseye_setreg(sc, 0x97, 0x20); 361 pseye_setreg(sc, 0x97, 0x20); 362 pseye_setreg(sc, 0x97, 0x0a); 363 pseye_setreg(sc, 0x97, 0x3f); 364 pseye_setreg(sc, 0x97, 0x4a); 365 pseye_setreg(sc, 0x97, 0x20); 366 pseye_setreg(sc, 0x97, 0x15); 367 pseye_setreg(sc, 0x97, 0x0b); 368 369 pseye_setregv(sc, 0x8e, 0x40); 370 pseye_setregv(sc, 0x1f, 0x81); 371 pseye_setregv(sc, 0x34, 0x05); 372 pseye_setregv(sc, 0xe3, 0x04); 373 pseye_setregv(sc, 0x88, 0x00); 374 pseye_setregv(sc, 0x89, 0x00); 375 pseye_setregv(sc, 0x76, 0x00); 376 pseye_setregv(sc, 0xe7, 0x2e); 377 pseye_setregv(sc, 0x31, 0xf9); 378 pseye_setregv(sc, 0x25, 0x42); 379 pseye_setregv(sc, 0x21, 0xf0); 380 381 pseye_setreg(sc, 0x1c, 0x00); 382 pseye_setreg(sc, 0x1d, 0x40); 383 pseye_setreg(sc, 0x1d, 0x02); 384 pseye_setreg(sc, 0x1d, 0x00); 385 pseye_setreg(sc, 0x1d, 0x02); 386 pseye_setreg(sc, 0x1d, 0x57); 387 pseye_setreg(sc, 0x1d, 0xff); 388 389 pseye_setregv(sc, 0x8d, 0x1c); 390 pseye_setregv(sc, 0x8e, 0x80); 391 pseye_setregv(sc, 0xe5, 0x04); 392 393 pseye_sccb_setreg(sc, 0x12, 0x80); 394 pseye_sccb_setreg(sc, 0x11, 0x01); 395 pseye_sccb_setreg(sc, 0x11, 0x01); 396 pseye_sccb_setreg(sc, 0x11, 0x01); 397 pseye_sccb_setreg(sc, 0x11, 0x01); 398 pseye_sccb_setreg(sc, 0x11, 0x01); 399 pseye_sccb_setreg(sc, 0x11, 0x01); 400 pseye_sccb_setreg(sc, 0x11, 0x01); 401 pseye_sccb_setreg(sc, 0x11, 0x01); 402 pseye_sccb_setreg(sc, 0x11, 0x01); 403 pseye_sccb_setreg(sc, 0x11, 0x01); 404 pseye_sccb_setreg(sc, 0x11, 0x01); 405 406 pseye_sccb_setreg(sc, 0x3d, 0x03); 407 pseye_sccb_setreg(sc, 0x17, 0x26); 408 pseye_sccb_setreg(sc, 0x18, 0xa0); 409 pseye_sccb_setreg(sc, 0x19, 0x07); 410 pseye_sccb_setreg(sc, 0x1a, 0xf0); 411 pseye_sccb_setreg(sc, 0x32, 0x00); 412 pseye_sccb_setreg(sc, 0x29, 0xa0); 413 pseye_sccb_setreg(sc, 0x2c, 0xf0); 414 pseye_sccb_setreg(sc, 0x65, 0x20); 415 pseye_sccb_setreg(sc, 0x11, 0x01); 416 pseye_sccb_setreg(sc, 0x42, 0x7f); 417 pseye_sccb_setreg(sc, 0x63, 0xe0); 418 pseye_sccb_setreg(sc, 0x64, 0xff); 419 pseye_sccb_setreg(sc, 0x66, 0x00); 420 pseye_sccb_setreg(sc, 0x13, 0xf0); 421 pseye_sccb_setreg(sc, 0x0d, 0x41); 422 pseye_sccb_setreg(sc, 0x0f, 0xc5); 423 pseye_sccb_setreg(sc, 0x14, 0x11); 424 425 pseye_sccb_setreg(sc, 0x22, 0x7f); 426 pseye_sccb_setreg(sc, 0x23, 0x03); 427 pseye_sccb_setreg(sc, 0x24, 0x40); 428 pseye_sccb_setreg(sc, 0x25, 0x30); 429 pseye_sccb_setreg(sc, 0x26, 0xa1); 430 pseye_sccb_setreg(sc, 0x2a, 0x00); 431 pseye_sccb_setreg(sc, 0x2b, 0x00); 432 pseye_sccb_setreg(sc, 0x6b, 0xaa); 433 pseye_sccb_setreg(sc, 0x13, 0xff); 434 435 pseye_sccb_setreg(sc, 0x90, 0x05); 436 pseye_sccb_setreg(sc, 0x91, 0x01); 437 pseye_sccb_setreg(sc, 0x92, 0x03); 438 pseye_sccb_setreg(sc, 0x93, 0x00); 439 pseye_sccb_setreg(sc, 0x94, 0x60); 440 pseye_sccb_setreg(sc, 0x95, 0x3c); 441 pseye_sccb_setreg(sc, 0x96, 0x24); 442 pseye_sccb_setreg(sc, 0x97, 0x1e); 443 pseye_sccb_setreg(sc, 0x98, 0x62); 444 pseye_sccb_setreg(sc, 0x99, 0x80); 445 pseye_sccb_setreg(sc, 0x9a, 0x1e); 446 pseye_sccb_setreg(sc, 0x9b, 0x08); 447 pseye_sccb_setreg(sc, 0x9c, 0x20); 448 pseye_sccb_setreg(sc, 0x9e, 0x81); 449 450 pseye_sccb_setreg(sc, 0xa6, 0x04); 451 pseye_sccb_setreg(sc, 0x7e, 0x0c); 452 pseye_sccb_setreg(sc, 0x7f, 0x16); 453 454 pseye_sccb_setreg(sc, 0x80, 0x2a); 455 pseye_sccb_setreg(sc, 0x81, 0x4e); 456 pseye_sccb_setreg(sc, 0x82, 0x61); 457 pseye_sccb_setreg(sc, 0x83, 0x6f); 458 pseye_sccb_setreg(sc, 0x84, 0x7b); 459 pseye_sccb_setreg(sc, 0x85, 0x86); 460 pseye_sccb_setreg(sc, 0x86, 0x8e); 461 pseye_sccb_setreg(sc, 0x87, 0x97); 462 pseye_sccb_setreg(sc, 0x88, 0xa4); 463 pseye_sccb_setreg(sc, 0x89, 0xaf); 464 pseye_sccb_setreg(sc, 0x8a, 0xc5); 465 pseye_sccb_setreg(sc, 0x8b, 0xd7); 466 pseye_sccb_setreg(sc, 0x8c, 0xe8); 467 pseye_sccb_setreg(sc, 0x8d, 0x20); 468 469 pseye_sccb_setreg(sc, 0x0c, 0x90); 470 471 pseye_setregv(sc, 0xc0, 0x50); 472 pseye_setregv(sc, 0xc1, 0x3c); 473 pseye_setregv(sc, 0xc2, 0x0c); 474 475 pseye_sccb_setreg(sc, 0x2b, 0x00); 476 pseye_sccb_setreg(sc, 0x22, 0x7f); 477 pseye_sccb_setreg(sc, 0x23, 0x03); 478 pseye_sccb_setreg(sc, 0x11, 0x01); 479 pseye_sccb_setreg(sc, 0x0c, 0xd0); 480 pseye_sccb_setreg(sc, 0x64, 0xff); 481 pseye_sccb_setreg(sc, 0x0d, 0x41); 482 483 pseye_sccb_setreg(sc, 0x14, 0x41); 484 pseye_sccb_setreg(sc, 0x0e, 0xcd); 485 pseye_sccb_setreg(sc, 0xac, 0xbf); 486 pseye_sccb_setreg(sc, 0x8e, 0x00); 487 pseye_sccb_setreg(sc, 0x0c, 0xd0); 488 489 pseye_stop(sc); 490 } 491 492 static void 493 pseye_sccb_init(struct pseye_softc *sc) 494 { 495 pseye_setregv(sc, 0xe7, 0x3a); 496 pseye_setreg(sc, PSEYE_SCCB_ADDRESS, 0x60); 497 pseye_setreg(sc, PSEYE_SCCB_ADDRESS, 0x60); 498 pseye_setreg(sc, PSEYE_SCCB_ADDRESS, 0x60); 499 pseye_setreg(sc, PSEYE_SCCB_ADDRESS, 0x42); 500 } 501 502 static void 503 pseye_stop(struct pseye_softc *sc) 504 { 505 pseye_led(sc, false); 506 pseye_setreg(sc, 0xe0, 0x09); 507 } 508 509 static void 510 pseye_start(struct pseye_softc *sc) 511 { 512 pseye_led(sc, true); 513 pseye_setreg(sc, 0xe0, 0x00); 514 } 515 516 static void 517 pseye_led(struct pseye_softc *sc, bool enabled) 518 { 519 uint8_t val; 520 521 val = pseye_getreg(sc, 0x21); 522 pseye_setreg(sc, 0x21, val | 0x80); 523 524 val = pseye_getreg(sc, 0x23); 525 if (enabled == true) 526 val |= 0x80; 527 else 528 val &= ~0x80; 529 pseye_setreg(sc, 0x23, val); 530 } 531 532 static uint8_t 533 pseye_getreg(struct pseye_softc *sc, uint16_t reg) 534 { 535 usb_device_request_t req; 536 usbd_status err; 537 uint8_t buf; 538 539 req.bmRequestType = UT_READ_VENDOR_DEVICE; 540 req.bRequest = 1; 541 USETW(req.wValue, 0x0000); 542 USETW(req.wIndex, reg); 543 USETW(req.wLength, 1); 544 545 err = usbd_do_request(sc->sc_udev, &req, &buf); 546 if (err) { 547 aprint_error_dev(sc->sc_dev, "couldn't read reg 0x%04x: %s\n", 548 reg, usbd_errstr(err)); 549 return 0xff; 550 } 551 552 return buf; 553 } 554 555 static void 556 pseye_setreg(struct pseye_softc *sc, uint16_t reg, uint8_t val) 557 { 558 usb_device_request_t req; 559 usbd_status err; 560 561 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 562 req.bRequest = 1; 563 USETW(req.wValue, 0x0000); 564 USETW(req.wIndex, reg); 565 USETW(req.wLength, 1); 566 567 err = usbd_do_request(sc->sc_udev, &req, &val); 568 if (err) 569 aprint_error_dev(sc->sc_dev, "couldn't write reg 0x%04x: %s\n", 570 reg, usbd_errstr(err)); 571 } 572 573 static void 574 pseye_setregv(struct pseye_softc *sc, uint16_t reg, uint8_t val) 575 { 576 pseye_setreg(sc, reg, val); 577 if (pseye_getreg(sc, reg) != val) 578 aprint_error_dev(sc->sc_dev, "couldn't verify reg 0x%04x\n", 579 reg); 580 } 581 582 static void 583 pseye_sccb_setreg(struct pseye_softc *sc, uint8_t reg, uint8_t val) 584 { 585 pseye_setreg(sc, PSEYE_SCCB_SUBADDR, reg); 586 pseye_setreg(sc, PSEYE_SCCB_WRITE, val); 587 pseye_setreg(sc, PSEYE_SCCB_OPERATION, PSEYE_SCCB_OP_WRITE_3); 588 589 if (pseye_sccb_status(sc) == false) 590 aprint_error_dev(sc->sc_dev, "couldn't write sccb reg 0x%04x\n", 591 reg); 592 } 593 594 static bool 595 pseye_sccb_status(struct pseye_softc *sc) 596 { 597 int retry = 5; 598 uint8_t reg; 599 600 while (retry-- >= 0) { 601 reg = pseye_getreg(sc, PSEYE_SCCB_STATUS); 602 if (reg == 0x00) 603 return true; 604 else if (reg == 0x04) 605 return false; 606 } 607 608 aprint_error_dev(sc->sc_dev, "timeout reading sccb status\n"); 609 return false; 610 } 611 612 static usbd_status 613 pseye_get_frame(struct pseye_softc *sc) 614 { 615 uint32_t len = sc->sc_bulkin_bufferlen; 616 617 if (sc->sc_dying) 618 return USBD_IOERROR; 619 620 return usbd_bulk_transfer(sc->sc_bulkin_xfer, sc->sc_bulkin_pipe, 621 USBD_SHORT_XFER_OK|USBD_NO_COPY, 50, 622 sc->sc_bulkin_buffer, &len, "pseyerb"); 623 } 624 625 static int 626 pseye_init_pipes(struct pseye_softc *sc) 627 { 628 usbd_status err; 629 630 if (sc->sc_dying) 631 return EIO; 632 633 err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkin, 0, 634 &sc->sc_bulkin_pipe); 635 if (err) { 636 aprint_error_dev(sc->sc_dev, "couldn't open bulk-in pipe: %s\n", 637 usbd_errstr(err)); 638 return ENOMEM; 639 } 640 641 pseye_start(sc); 642 643 return 0; 644 } 645 646 int 647 pseye_close_pipes(struct pseye_softc *sc) 648 { 649 if (sc->sc_bulkin_pipe != NULL) { 650 usbd_abort_pipe(sc->sc_bulkin_pipe); 651 usbd_close_pipe(sc->sc_bulkin_pipe); 652 sc->sc_bulkin_pipe = NULL; 653 } 654 655 pseye_stop(sc); 656 657 return 0; 658 } 659 660 static void 661 pseye_transfer_thread(void *opaque) 662 { 663 struct pseye_softc *sc = opaque; 664 int error; 665 struct video_payload payload; 666 667 payload.frameno = 0; 668 669 while (sc->sc_running) { 670 error = pseye_get_frame(sc); 671 if (error == USBD_NORMAL_COMPLETION) { 672 payload.data = sc->sc_bulkin_buffer; 673 payload.size = sc->sc_bulkin_bufferlen; 674 payload.frameno = (payload.frameno + 1) & 1; 675 payload.end_of_frame = 1; 676 video_submit_payload(sc->sc_videodev, &payload); 677 } 678 } 679 680 mutex_enter(&sc->sc_mtx); 681 cv_broadcast(&sc->sc_cv); 682 mutex_exit(&sc->sc_mtx); 683 684 kthread_exit(0); 685 } 686 687 /* video(9) API implementations */ 688 static int 689 pseye_open(void *opaque, int flags) 690 { 691 struct pseye_softc *sc = opaque; 692 693 if (sc->sc_dying) 694 return EIO; 695 696 return pseye_init_pipes(sc); 697 } 698 699 static void 700 pseye_close(void *opaque) 701 { 702 struct pseye_softc *sc = opaque; 703 704 pseye_close_pipes(sc); 705 } 706 707 static const char * 708 pseye_get_devname(void *opaque) 709 { 710 return "PLAYSTATION(R) Eye"; 711 } 712 713 static int 714 pseye_enum_format(void *opaque, uint32_t index, struct video_format *format) 715 { 716 if (index != 0) 717 return EINVAL; 718 return pseye_get_format(opaque, format); 719 } 720 721 static int 722 pseye_get_format(void *opaque, struct video_format *format) 723 { 724 format->pixel_format = VIDEO_FORMAT_YUY2; /* XXX actually YUYV */ 725 format->width = 640; 726 format->height = 480; 727 format->aspect_x = 4; 728 format->aspect_y = 3; 729 format->sample_size = format->width * format->height * 2; 730 format->stride = format->width * 2; 731 format->color.primaries = VIDEO_COLOR_PRIMARIES_UNSPECIFIED; 732 format->color.gamma_function = VIDEO_GAMMA_FUNCTION_UNSPECIFIED; 733 format->color.matrix_coeff = VIDEO_MATRIX_COEFF_UNSPECIFIED; 734 format->interlace_flags = VIDEO_INTERLACE_ON; 735 format->priv = 0; 736 737 return 0; 738 } 739 740 static int 741 pseye_set_format(void *opaque, struct video_format *format) 742 { 743 #if notyet 744 if (format->pixel_format != VIDEO_FORMAT_YUYV) 745 return EINVAL; 746 if (format->width != 640 || format->height != 480) 747 return EINVAL; 748 #endif 749 /* XXX */ 750 return pseye_get_format(opaque, format); 751 } 752 753 static int 754 pseye_try_format(void *opaque, struct video_format *format) 755 { 756 return pseye_get_format(opaque, format); 757 } 758 759 static int 760 pseye_start_transfer(void *opaque) 761 { 762 struct pseye_softc *sc = opaque; 763 int err = 0; 764 765 mutex_enter(&sc->sc_mtx); 766 if (sc->sc_running == 0) { 767 sc->sc_running = 1; 768 err = kthread_create(PRI_PSEYE, 0, NULL, pseye_transfer_thread, 769 opaque, NULL, device_xname(sc->sc_dev)); 770 } else 771 aprint_error_dev(sc->sc_dev, "transfer already in progress\n"); 772 mutex_exit(&sc->sc_mtx); 773 774 return err; 775 } 776 777 static int 778 pseye_stop_transfer(void *opaque) 779 { 780 struct pseye_softc *sc = opaque; 781 782 mutex_enter(&sc->sc_mtx); 783 if (sc->sc_running) { 784 sc->sc_running = 0; 785 cv_wait_sig(&sc->sc_cv, &sc->sc_mtx); 786 } 787 mutex_exit(&sc->sc_mtx); 788 789 return 0; 790 } 791 792 #ifdef _MODULE 793 794 MODULE(MODULE_CLASS_DRIVER, pseye, NULL); 795 796 static const struct cfiattrdata videobuscf_iattrdata = { 797 "videobus", 0, { { NULL, NULL, 0 }, } 798 }; 799 static const struct cfiattrdata * const pseye_attrs[] = { 800 &videobuscf_iattrdata, NULL 801 }; 802 CFDRIVER_DECL(pseye, DV_DULL, pseye_attrs); 803 extern struct cfattach video_ca; 804 static int pseyeloc[6] = { -1, -1, -1, -1, -1, -1 }; 805 static struct cfparent uhubparent = { 806 "usbifif", NULL, DVUNIT_ANY 807 }; 808 static struct cfdata pseye_cfdata[] = { 809 { 810 .cf_name = "pseye", 811 .cf_atname = "pseye", 812 .cf_unit = 0, 813 .cf_fstate = FSTATE_STAR, 814 .cf_loc = pseyeloc, 815 .cf_flags = 0, 816 .cf_pspec = &uhubparent, 817 }, 818 { NULL } 819 }; 820 821 static int 822 pseye_modcmd(modcmd_t cmd, void *opaque) 823 { 824 int err; 825 826 switch (cmd) { 827 case MODULE_CMD_INIT: 828 err = config_cfdriver_attach(&pseye_cd); 829 if (err) 830 return err; 831 err = config_cfattach_attach("pseye", &pseye_ca); 832 if (err) { 833 config_cfdriver_detach(&pseye_cd); 834 return err; 835 } 836 err = config_cfdata_attach(pseye_cfdata, 1); 837 if (err) { 838 config_cfattach_detach("pseye", &pseye_ca); 839 config_cfdriver_detach(&pseye_cd); 840 return err; 841 } 842 return 0; 843 case MODULE_CMD_FINI: 844 err = config_cfdata_detach(pseye_cfdata); 845 if (err) 846 return err; 847 config_cfattach_detach("pseye", &pseye_ca); 848 config_cfdriver_detach(&pseye_cd); 849 return 0; 850 default: 851 return ENOTTY; 852 } 853 } 854 855 #endif /* !_MODULE */ 856