xref: /netbsd-src/sys/dev/usb/pseye.c (revision 404fbe5fb94ca1e054339640cabb2801ce52dd30)
1 /* $NetBSD: pseye.c,v 1.10 2008/10/15 06:51:20 wrstuden 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.10 2008/10/15 06:51:20 wrstuden 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 
54 #include <uvm/uvm_extern.h>
55 
56 #include <dev/usb/usb.h>
57 #include <dev/usb/usbdi.h>
58 #include <dev/usb/usbdi_util.h>
59 #include <dev/usb/usbdevs.h>
60 
61 #include <dev/video_if.h>
62 
63 #define PRI_PSEYE	PRI_BIO
64 
65 /* Bulk-in buffer length */
66 #define PSEYE_BULKIN_BUFLEN	(640 * 480 * 2)
67 
68 /* SCCB/sensor interface */
69 #define PSEYE_SCCB_ADDRESS	0xf1
70 #define PSEYE_SCCB_SUBADDR	0xf2
71 #define PSEYE_SCCB_WRITE	0xf3
72 #define PSEYE_SCCB_READ		0xf4
73 #define PSEYE_SCCB_OPERATION	0xf5
74 #define PSEYE_SCCB_STATUS	0xf6
75 
76 #define PSEYE_SCCB_OP_WRITE_3	0x37
77 #define PSEYE_SCCB_OP_WRITE_2	0x33
78 #define PSEYE_SCCB_OP_READ_2	0xf9
79 
80 struct pseye_softc {
81 	USBBASEDEVICE		sc_dev;
82 
83 	usbd_device_handle	sc_udev;
84 	usbd_interface_handle	sc_iface;
85 
86 	device_t		sc_videodev;
87 	char			sc_running;
88 
89 	kcondvar_t		sc_cv;
90 	kmutex_t		sc_mtx;
91 
92 	usbd_pipe_handle	sc_bulkin_pipe;
93 	usbd_xfer_handle	sc_bulkin_xfer;
94 	int			sc_bulkin;
95 	uint8_t			*sc_bulkin_buffer;
96 	int			sc_bulkin_bufferlen;
97 
98 	char			sc_dying;
99 };
100 
101 static int	pseye_match(device_t, cfdata_t, void *);
102 static void	pseye_attach(device_t, device_t, void *);
103 static int	pseye_detach(device_t, int);
104 static void	pseye_childdet(device_t, device_t);
105 static int	pseye_activate(device_t, enum devact);
106 
107 static void	pseye_init(struct pseye_softc *);
108 static void	pseye_sccb_init(struct pseye_softc *);
109 static void	pseye_stop(struct pseye_softc *);
110 static void	pseye_start(struct pseye_softc *);
111 static void	pseye_led(struct pseye_softc *, bool);
112 static uint8_t	pseye_getreg(struct pseye_softc *, uint16_t);
113 static void	pseye_setreg(struct pseye_softc *, uint16_t, uint8_t);
114 static void	pseye_setregv(struct pseye_softc *, uint16_t, uint8_t);
115 static void	pseye_sccb_setreg(struct pseye_softc *, uint8_t, uint8_t);
116 static bool	pseye_sccb_status(struct pseye_softc *);
117 
118 static int	pseye_init_pipes(struct pseye_softc *);
119 static int	pseye_close_pipes(struct pseye_softc *);
120 
121 static usbd_status	pseye_get_frame(struct pseye_softc *);
122 
123 /* video(9) API */
124 static int		pseye_open(void *, int);
125 static void		pseye_close(void *);
126 static const char *	pseye_get_devname(void *);
127 static int		pseye_enum_format(void *, uint32_t,
128 					  struct video_format *);
129 static int		pseye_get_format(void *, struct video_format *);
130 static int		pseye_set_format(void *, struct video_format *);
131 static int		pseye_try_format(void *, struct video_format *);
132 static int		pseye_start_transfer(void *);
133 static int		pseye_stop_transfer(void *);
134 
135 CFATTACH_DECL2_NEW(pseye, sizeof(struct pseye_softc),
136     pseye_match, pseye_attach, pseye_detach, pseye_activate,
137     NULL, pseye_childdet);
138 
139 static const struct video_hw_if pseye_hw_if = {
140 	.open = pseye_open,
141 	.close = pseye_close,
142 	.get_devname = pseye_get_devname,
143 	.enum_format = pseye_enum_format,
144 	.get_format = pseye_get_format,
145 	.set_format = pseye_set_format,
146 	.try_format = pseye_try_format,
147 	.start_transfer = pseye_start_transfer,
148 	.stop_transfer = pseye_stop_transfer,
149 	.control_iter_init = NULL,
150 	.control_iter_next = NULL,
151 	.get_control_desc_group = NULL,
152 	.get_control_group = NULL,
153 	.set_control_group = NULL,
154 };
155 
156 static int
157 pseye_match(device_t parent, cfdata_t match, void *opaque)
158 {
159 	struct usbif_attach_arg *uaa = opaque;
160 
161 	if (uaa->class != UICLASS_VENDOR)
162 		return UMATCH_NONE;
163 
164 	if (uaa->vendor == USB_VENDOR_OMNIVISION2) {
165 		switch (uaa->product) {
166 		case USB_PRODUCT_OMNIVISION2_PSEYE:
167 			if (uaa->ifaceno != 0)
168 				return UMATCH_NONE;
169 			return UMATCH_VENDOR_PRODUCT;
170 		}
171 	}
172 
173 	return UMATCH_NONE;
174 }
175 
176 static void
177 pseye_attach(device_t parent, device_t self, void *opaque)
178 {
179 	struct pseye_softc *sc = device_private(self);
180 	struct usbif_attach_arg *uaa = opaque;
181 	usbd_device_handle dev = uaa->device;
182 	usb_interface_descriptor_t *id = NULL;
183 	usb_endpoint_descriptor_t *ed = NULL, *ed_bulkin = NULL;
184 	char *devinfo;
185 	int i;
186 
187 	devinfo = usbd_devinfo_alloc(dev, 0);
188 	aprint_naive("\n");
189 	aprint_normal(": %s\n", devinfo);
190 	usbd_devinfo_free(devinfo);
191 
192 	sc->sc_dev = self;
193 	sc->sc_udev = dev;
194 	sc->sc_iface = uaa->iface;
195 	sc->sc_bulkin_bufferlen = PSEYE_BULKIN_BUFLEN;
196 
197 	sc->sc_dying = sc->sc_running = 0;
198 	cv_init(&sc->sc_cv, device_xname(self));
199 	mutex_init(&sc->sc_mtx, MUTEX_DEFAULT, IPL_NONE);
200 
201 	id = usbd_get_interface_descriptor(sc->sc_iface);
202 	if (id == NULL) {
203 		aprint_error_dev(self, "failed to get interface descriptor\n");
204 		sc->sc_dying = 1;
205 		return;
206 	}
207 
208 	for (i = 0; i < id->bNumEndpoints; i++) {
209 		ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
210 		if (ed == NULL) {
211 			aprint_error_dev(self, "couldn't get ep %d\n", i);
212 			sc->sc_dying = 1;
213 			return;
214 		}
215 
216 		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
217 		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
218 			ed_bulkin = ed;
219 			break;
220 		}
221 	}
222 
223 	if (ed_bulkin == NULL) {
224 		aprint_error_dev(self, "no bulk-in endpoint found\n");
225 		sc->sc_dying = 1;
226 		return;
227 	}
228 
229 	sc->sc_bulkin = ed_bulkin->bEndpointAddress;
230 
231 	sc->sc_bulkin_xfer = usbd_alloc_xfer(sc->sc_udev);
232 	if (sc->sc_bulkin_xfer == NULL) {
233 		sc->sc_dying = 1;
234 		return;
235 	}
236 	sc->sc_bulkin_buffer = usbd_alloc_buffer(sc->sc_bulkin_xfer,
237 	    sc->sc_bulkin_bufferlen);
238 	if (sc->sc_bulkin_buffer == NULL) {
239 		usbd_free_xfer(sc->sc_bulkin_xfer);
240 		sc->sc_bulkin_xfer = NULL;
241 		sc->sc_dying = 1;
242 		return;
243 	}
244 
245 	pseye_init(sc);
246 
247 	if (!pmf_device_register(self, NULL, NULL))
248 		aprint_error_dev(self, "couldn't establish power handler\n");
249 
250 	sc->sc_videodev = video_attach_mi(&pseye_hw_if, self);
251 	if (sc->sc_videodev == NULL) {
252 		aprint_error_dev(self, "couldn't attach video layer\n");
253 		sc->sc_dying = 1;
254 		return;
255 	}
256 
257 	usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
258 	    USBDEV(self));
259 
260 }
261 
262 static int
263 pseye_detach(device_t self, int flags)
264 {
265 	struct pseye_softc *sc = device_private(self);
266 
267 	sc->sc_dying = 1;
268 
269 	pmf_device_deregister(self);
270 
271 	if (sc->sc_videodev != NULL) {
272 		config_detach(sc->sc_videodev, flags);
273 		sc->sc_videodev = NULL;
274 	}
275 
276 	if (sc->sc_bulkin_xfer != NULL) {
277 		usbd_free_xfer(sc->sc_bulkin_xfer);
278 		sc->sc_bulkin_xfer = NULL;
279 	}
280 
281 	if (sc->sc_bulkin_pipe != NULL) {
282 		usbd_abort_pipe(sc->sc_bulkin_pipe);
283 		sc->sc_bulkin_pipe = NULL;
284 	}
285 
286 	mutex_enter(&sc->sc_mtx);
287 	if (sc->sc_running) {
288 		sc->sc_running = 0;
289 		cv_wait_sig(&sc->sc_cv, &sc->sc_mtx);
290 	}
291 	mutex_exit(&sc->sc_mtx);
292 
293 	cv_destroy(&sc->sc_cv);
294 	mutex_destroy(&sc->sc_mtx);
295 
296 	usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
297 	    USBDEV(sc->sc_dev));
298 
299 	return 0;
300 }
301 
302 int
303 pseye_activate(device_ptr_t self, enum devact act)
304 {
305 	struct pseye_softc *sc = device_private(self);
306 	int rv;
307 
308 	rv = 0;
309 
310 	switch (act) {
311 	case DVACT_ACTIVATE:
312 		break;
313 	case DVACT_DEACTIVATE:
314 		sc->sc_dying = 1;
315 		break;
316 	}
317 
318 	return rv;
319 }
320 
321 static void
322 pseye_childdet(device_t self, device_t child)
323 {
324 	struct pseye_softc *sc = device_private(self);
325 
326 	if (sc->sc_videodev) {
327 		KASSERT(sc->sc_videodev == child);
328 		sc->sc_videodev = NULL;
329 	}
330 }
331 
332 /*
333  * Device access
334  */
335 
336 static void
337 pseye_init(struct pseye_softc *sc)
338 {
339 	pseye_sccb_init(sc);
340 
341 	pseye_setregv(sc, 0xc2, 0x0c);
342 	pseye_setregv(sc, 0x88, 0xf8);
343 	pseye_setregv(sc, 0xc3, 0x69);
344 	pseye_setregv(sc, 0x89, 0xff);
345 	pseye_setregv(sc, 0x76, 0x03);
346 	pseye_setregv(sc, 0x92, 0x01);
347 	pseye_setregv(sc, 0x93, 0x18);
348 	pseye_setregv(sc, 0x94, 0x10);
349 	pseye_setregv(sc, 0x95, 0x10);
350 	pseye_setregv(sc, 0xe2, 0x00);
351 	pseye_setregv(sc, 0xe7, 0x3e);
352 
353 	pseye_setreg(sc, 0x1c, 0x0a);
354 	pseye_setreg(sc, 0x1d, 0x22);
355 	pseye_setreg(sc, 0x1d, 0x06);
356 	pseye_setregv(sc, 0x96, 0x00);
357 
358 	pseye_setreg(sc, 0x97, 0x20);
359 	pseye_setreg(sc, 0x97, 0x20);
360 	pseye_setreg(sc, 0x97, 0x20);
361 	pseye_setreg(sc, 0x97, 0x0a);
362 	pseye_setreg(sc, 0x97, 0x3f);
363 	pseye_setreg(sc, 0x97, 0x4a);
364 	pseye_setreg(sc, 0x97, 0x20);
365 	pseye_setreg(sc, 0x97, 0x15);
366 	pseye_setreg(sc, 0x97, 0x0b);
367 
368 	pseye_setregv(sc, 0x8e, 0x40);
369 	pseye_setregv(sc, 0x1f, 0x81);
370 	pseye_setregv(sc, 0x34, 0x05);
371 	pseye_setregv(sc, 0xe3, 0x04);
372 	pseye_setregv(sc, 0x88, 0x00);
373 	pseye_setregv(sc, 0x89, 0x00);
374 	pseye_setregv(sc, 0x76, 0x00);
375 	pseye_setregv(sc, 0xe7, 0x2e);
376 	pseye_setregv(sc, 0x31, 0xf9);
377 	pseye_setregv(sc, 0x25, 0x42);
378 	pseye_setregv(sc, 0x21, 0xf0);
379 
380 	pseye_setreg(sc, 0x1c, 0x00);
381 	pseye_setreg(sc, 0x1d, 0x40);
382 	pseye_setreg(sc, 0x1d, 0x02);
383 	pseye_setreg(sc, 0x1d, 0x00);
384 	pseye_setreg(sc, 0x1d, 0x02);
385 	pseye_setreg(sc, 0x1d, 0x57);
386 	pseye_setreg(sc, 0x1d, 0xff);
387 
388 	pseye_setregv(sc, 0x8d, 0x1c);
389 	pseye_setregv(sc, 0x8e, 0x80);
390 	pseye_setregv(sc, 0xe5, 0x04);
391 
392 	pseye_sccb_setreg(sc, 0x12, 0x80);
393 	pseye_sccb_setreg(sc, 0x11, 0x01);
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 
405 	pseye_sccb_setreg(sc, 0x3d, 0x03);
406 	pseye_sccb_setreg(sc, 0x17, 0x26);
407 	pseye_sccb_setreg(sc, 0x18, 0xa0);
408 	pseye_sccb_setreg(sc, 0x19, 0x07);
409 	pseye_sccb_setreg(sc, 0x1a, 0xf0);
410 	pseye_sccb_setreg(sc, 0x32, 0x00);
411 	pseye_sccb_setreg(sc, 0x29, 0xa0);
412 	pseye_sccb_setreg(sc, 0x2c, 0xf0);
413 	pseye_sccb_setreg(sc, 0x65, 0x20);
414 	pseye_sccb_setreg(sc, 0x11, 0x01);
415 	pseye_sccb_setreg(sc, 0x42, 0x7f);
416 	pseye_sccb_setreg(sc, 0x63, 0xe0);
417 	pseye_sccb_setreg(sc, 0x64, 0xff);
418 	pseye_sccb_setreg(sc, 0x66, 0x00);
419 	pseye_sccb_setreg(sc, 0x13, 0xf0);
420 	pseye_sccb_setreg(sc, 0x0d, 0x41);
421 	pseye_sccb_setreg(sc, 0x0f, 0xc5);
422 	pseye_sccb_setreg(sc, 0x14, 0x11);
423 
424 	pseye_sccb_setreg(sc, 0x22, 0x7f);
425 	pseye_sccb_setreg(sc, 0x23, 0x03);
426 	pseye_sccb_setreg(sc, 0x24, 0x40);
427 	pseye_sccb_setreg(sc, 0x25, 0x30);
428 	pseye_sccb_setreg(sc, 0x26, 0xa1);
429 	pseye_sccb_setreg(sc, 0x2a, 0x00);
430 	pseye_sccb_setreg(sc, 0x2b, 0x00);
431 	pseye_sccb_setreg(sc, 0x6b, 0xaa);
432 	pseye_sccb_setreg(sc, 0x13, 0xff);
433 
434 	pseye_sccb_setreg(sc, 0x90, 0x05);
435 	pseye_sccb_setreg(sc, 0x91, 0x01);
436 	pseye_sccb_setreg(sc, 0x92, 0x03);
437 	pseye_sccb_setreg(sc, 0x93, 0x00);
438 	pseye_sccb_setreg(sc, 0x94, 0x60);
439 	pseye_sccb_setreg(sc, 0x95, 0x3c);
440 	pseye_sccb_setreg(sc, 0x96, 0x24);
441 	pseye_sccb_setreg(sc, 0x97, 0x1e);
442 	pseye_sccb_setreg(sc, 0x98, 0x62);
443 	pseye_sccb_setreg(sc, 0x99, 0x80);
444 	pseye_sccb_setreg(sc, 0x9a, 0x1e);
445 	pseye_sccb_setreg(sc, 0x9b, 0x08);
446 	pseye_sccb_setreg(sc, 0x9c, 0x20);
447 	pseye_sccb_setreg(sc, 0x9e, 0x81);
448 
449 	pseye_sccb_setreg(sc, 0xa6, 0x04);
450 	pseye_sccb_setreg(sc, 0x7e, 0x0c);
451 	pseye_sccb_setreg(sc, 0x7f, 0x16);
452 
453 	pseye_sccb_setreg(sc, 0x80, 0x2a);
454 	pseye_sccb_setreg(sc, 0x81, 0x4e);
455 	pseye_sccb_setreg(sc, 0x82, 0x61);
456 	pseye_sccb_setreg(sc, 0x83, 0x6f);
457 	pseye_sccb_setreg(sc, 0x84, 0x7b);
458 	pseye_sccb_setreg(sc, 0x85, 0x86);
459 	pseye_sccb_setreg(sc, 0x86, 0x8e);
460 	pseye_sccb_setreg(sc, 0x87, 0x97);
461 	pseye_sccb_setreg(sc, 0x88, 0xa4);
462 	pseye_sccb_setreg(sc, 0x89, 0xaf);
463 	pseye_sccb_setreg(sc, 0x8a, 0xc5);
464 	pseye_sccb_setreg(sc, 0x8b, 0xd7);
465 	pseye_sccb_setreg(sc, 0x8c, 0xe8);
466 	pseye_sccb_setreg(sc, 0x8d, 0x20);
467 
468 	pseye_sccb_setreg(sc, 0x0c, 0x90);
469 
470 	pseye_setregv(sc, 0xc0, 0x50);
471 	pseye_setregv(sc, 0xc1, 0x3c);
472 	pseye_setregv(sc, 0xc2, 0x0c);
473 
474 	pseye_sccb_setreg(sc, 0x2b, 0x00);
475 	pseye_sccb_setreg(sc, 0x22, 0x7f);
476 	pseye_sccb_setreg(sc, 0x23, 0x03);
477 	pseye_sccb_setreg(sc, 0x11, 0x01);
478 	pseye_sccb_setreg(sc, 0x0c, 0xd0);
479 	pseye_sccb_setreg(sc, 0x64, 0xff);
480 	pseye_sccb_setreg(sc, 0x0d, 0x41);
481 
482 	pseye_sccb_setreg(sc, 0x14, 0x41);
483 	pseye_sccb_setreg(sc, 0x0e, 0xcd);
484 	pseye_sccb_setreg(sc, 0xac, 0xbf);
485 	pseye_sccb_setreg(sc, 0x8e, 0x00);
486 	pseye_sccb_setreg(sc, 0x0c, 0xd0);
487 
488 	pseye_stop(sc);
489 }
490 
491 static void
492 pseye_sccb_init(struct pseye_softc *sc)
493 {
494 	pseye_setregv(sc, 0xe7, 0x3a);
495 	pseye_setreg(sc, PSEYE_SCCB_ADDRESS, 0x60);
496 	pseye_setreg(sc, PSEYE_SCCB_ADDRESS, 0x60);
497 	pseye_setreg(sc, PSEYE_SCCB_ADDRESS, 0x60);
498 	pseye_setreg(sc, PSEYE_SCCB_ADDRESS, 0x42);
499 }
500 
501 static void
502 pseye_stop(struct pseye_softc *sc)
503 {
504 	pseye_led(sc, false);
505 	pseye_setreg(sc, 0xe0, 0x09);
506 }
507 
508 static void
509 pseye_start(struct pseye_softc *sc)
510 {
511 	pseye_led(sc, true);
512 	pseye_setreg(sc, 0xe0, 0x00);
513 }
514 
515 static void
516 pseye_led(struct pseye_softc *sc, bool enabled)
517 {
518 	uint8_t val;
519 
520 	val = pseye_getreg(sc, 0x21);
521 	pseye_setreg(sc, 0x21, val | 0x80);
522 
523 	val = pseye_getreg(sc, 0x23);
524 	if (enabled == true)
525 		val |= 0x80;
526 	else
527 		val &= ~0x80;
528 	pseye_setreg(sc, 0x23, val);
529 }
530 
531 static uint8_t
532 pseye_getreg(struct pseye_softc *sc, uint16_t reg)
533 {
534 	usb_device_request_t req;
535 	usbd_status err;
536 	uint8_t buf;
537 
538 	req.bmRequestType = UT_READ_VENDOR_DEVICE;
539 	req.bRequest = 1;
540 	USETW(req.wValue, 0x0000);
541 	USETW(req.wIndex, reg);
542 	USETW(req.wLength, 1);
543 
544 	err = usbd_do_request(sc->sc_udev, &req, &buf);
545 	if (err) {
546 		aprint_error_dev(sc->sc_dev, "couldn't read reg 0x%04x: %s\n",
547 		    reg, usbd_errstr(err));
548 		return 0xff;
549 	}
550 
551 	return buf;
552 }
553 
554 static void
555 pseye_setreg(struct pseye_softc *sc, uint16_t reg, uint8_t val)
556 {
557 	usb_device_request_t req;
558 	usbd_status err;
559 
560 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
561 	req.bRequest = 1;
562 	USETW(req.wValue, 0x0000);
563 	USETW(req.wIndex, reg);
564 	USETW(req.wLength, 1);
565 
566 	err = usbd_do_request(sc->sc_udev, &req, &val);
567 	if (err)
568 		aprint_error_dev(sc->sc_dev, "couldn't write reg 0x%04x: %s\n",
569 		    reg, usbd_errstr(err));
570 }
571 
572 static void
573 pseye_setregv(struct pseye_softc *sc, uint16_t reg, uint8_t val)
574 {
575 	pseye_setreg(sc, reg, val);
576 	if (pseye_getreg(sc, reg) != val)
577 		aprint_error_dev(sc->sc_dev, "couldn't verify reg 0x%04x\n",
578 		    reg);
579 }
580 
581 static void
582 pseye_sccb_setreg(struct pseye_softc *sc, uint8_t reg, uint8_t val)
583 {
584 	pseye_setreg(sc, PSEYE_SCCB_SUBADDR, reg);
585 	pseye_setreg(sc, PSEYE_SCCB_WRITE, val);
586 	pseye_setreg(sc, PSEYE_SCCB_OPERATION, PSEYE_SCCB_OP_WRITE_3);
587 
588 	if (pseye_sccb_status(sc) == false)
589 		aprint_error_dev(sc->sc_dev, "couldn't write sccb reg 0x%04x\n",
590 		    reg);
591 }
592 
593 static bool
594 pseye_sccb_status(struct pseye_softc *sc)
595 {
596 	int retry = 5;
597 	uint8_t reg;
598 
599 	while (retry-- >= 0) {
600 		reg = pseye_getreg(sc, PSEYE_SCCB_STATUS);
601 		if (reg == 0x00)
602 			return true;
603 		else if (reg == 0x04)
604 			return false;
605 	}
606 
607 	aprint_error_dev(sc->sc_dev, "timeout reading sccb status\n");
608 	return false;
609 }
610 
611 static usbd_status
612 pseye_get_frame(struct pseye_softc *sc)
613 {
614 	uint32_t len = sc->sc_bulkin_bufferlen;
615 
616 	if (sc->sc_dying)
617 		return USBD_IOERROR;
618 
619 	return usbd_bulk_transfer(sc->sc_bulkin_xfer, sc->sc_bulkin_pipe,
620 	    USBD_SHORT_XFER_OK|USBD_NO_COPY, 50,
621 	    sc->sc_bulkin_buffer, &len, "pseyerb");
622 }
623 
624 static int
625 pseye_init_pipes(struct pseye_softc *sc)
626 {
627 	usbd_status err;
628 
629 	if (sc->sc_dying)
630 		return EIO;
631 
632 	err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkin, 0,
633 	    &sc->sc_bulkin_pipe);
634 	if (err) {
635 		aprint_error_dev(sc->sc_dev, "couldn't open bulk-in pipe: %s\n",
636 		    usbd_errstr(err));
637 		return ENOMEM;
638 	}
639 
640 	pseye_start(sc);
641 
642 	return 0;
643 }
644 
645 int
646 pseye_close_pipes(struct pseye_softc *sc)
647 {
648 	if (sc->sc_bulkin_pipe != NULL) {
649 		usbd_abort_pipe(sc->sc_bulkin_pipe);
650 		usbd_close_pipe(sc->sc_bulkin_pipe);
651 		sc->sc_bulkin_pipe = NULL;
652 	}
653 
654 	pseye_stop(sc);
655 
656 	return 0;
657 }
658 
659 static void
660 pseye_transfer_thread(void *opaque)
661 {
662 	struct pseye_softc *sc = opaque;
663 	int error;
664 	struct video_payload payload;
665 
666 	payload.frameno = 0;
667 
668 	while (sc->sc_running) {
669 		error = pseye_get_frame(sc);
670 		if (error == USBD_NORMAL_COMPLETION) {
671 			payload.data = sc->sc_bulkin_buffer;
672 			payload.size = sc->sc_bulkin_bufferlen;
673 			payload.frameno = (payload.frameno + 1) & 1;
674 			payload.end_of_frame = 1;
675 			video_submit_payload(sc->sc_videodev, &payload);
676 		}
677 	}
678 
679 	mutex_enter(&sc->sc_mtx);
680 	cv_broadcast(&sc->sc_cv);
681 	mutex_exit(&sc->sc_mtx);
682 
683 	kthread_exit(0);
684 }
685 
686 /* video(9) API implementations */
687 static int
688 pseye_open(void *opaque, int flags)
689 {
690 	struct pseye_softc *sc = opaque;
691 
692 	if (sc->sc_dying)
693 		return EIO;
694 
695 	return pseye_init_pipes(sc);
696 }
697 
698 static void
699 pseye_close(void *opaque)
700 {
701 	struct pseye_softc *sc = opaque;
702 
703 	pseye_close_pipes(sc);
704 }
705 
706 static const char *
707 pseye_get_devname(void *opaque)
708 {
709 	return "PLAYSTATION(R) Eye";
710 }
711 
712 static int
713 pseye_enum_format(void *opaque, uint32_t index, struct video_format *format)
714 {
715 	if (index != 0)
716 		return EINVAL;
717 	return pseye_get_format(opaque, format);
718 }
719 
720 static int
721 pseye_get_format(void *opaque, struct video_format *format)
722 {
723 	format->pixel_format = VIDEO_FORMAT_YUY2; /* XXX actually YUYV */
724 	format->width = 640;
725 	format->height = 480;
726 	format->aspect_x = 4;
727 	format->aspect_y = 3;
728 	format->sample_size = format->width * format->height * 2;
729 	format->stride = format->width * 2;
730 	format->color.primaries = VIDEO_COLOR_PRIMARIES_UNSPECIFIED;
731 	format->color.gamma_function = VIDEO_GAMMA_FUNCTION_UNSPECIFIED;
732 	format->color.matrix_coeff = VIDEO_MATRIX_COEFF_UNSPECIFIED;
733 	format->interlace_flags = VIDEO_INTERLACE_ON;
734 	format->priv = 0;
735 
736 	return 0;
737 }
738 
739 static int
740 pseye_set_format(void *opaque, struct video_format *format)
741 {
742 #if notyet
743 	if (format->pixel_format != VIDEO_FORMAT_YUYV)
744 		return EINVAL;
745 	if (format->width != 640 || format->height != 480)
746 		return EINVAL;
747 #endif
748 	/* XXX */
749 	return pseye_get_format(opaque, format);
750 }
751 
752 static int
753 pseye_try_format(void *opaque, struct video_format *format)
754 {
755 	return pseye_get_format(opaque, format);
756 }
757 
758 static int
759 pseye_start_transfer(void *opaque)
760 {
761 	struct pseye_softc *sc = opaque;
762 	int err = 0;
763 
764 	mutex_enter(&sc->sc_mtx);
765 	if (sc->sc_running == 0) {
766 		sc->sc_running = 1;
767 		err = kthread_create(PRI_PSEYE, 0, NULL, pseye_transfer_thread,
768 		    opaque, NULL, device_xname(sc->sc_dev));
769 	} else
770 		aprint_error_dev(sc->sc_dev, "transfer already in progress\n");
771 	mutex_exit(&sc->sc_mtx);
772 
773 	return err;
774 }
775 
776 static int
777 pseye_stop_transfer(void *opaque)
778 {
779 	struct pseye_softc *sc = opaque;
780 
781 	mutex_enter(&sc->sc_mtx);
782 	if (sc->sc_running) {
783 		sc->sc_running = 0;
784 		cv_wait_sig(&sc->sc_cv, &sc->sc_mtx);
785 	}
786 	mutex_exit(&sc->sc_mtx);
787 
788 	return 0;
789 }
790