xref: /freebsd/sys/dev/firewire/fwcam.c (revision f5dc2263ab1be8a35a7e27e82103f9ccd41ae584)
1 /*
2  * Copyright (c) 2026 Abdelkader Boudih <freebsd@seuros.com>
3  *
4  * SPDX-License-Identifier: BSD-2-Clause
5  */
6 
7 /*
8  * fwcam(4) - IIDC 1394-based Digital Camera driver
9  *
10  * Implements the IIDC v1.30 specification (TA Document 1999023) for
11  * FireWire digital cameras.
12  */
13 
14 #include <sys/param.h>
15 #include <sys/systm.h>
16 #include <sys/module.h>
17 #include <sys/bus.h>
18 #include <sys/kernel.h>
19 #include <sys/malloc.h>
20 #include <sys/lock.h>
21 #include <sys/mutex.h>
22 #include <sys/sysctl.h>
23 #include <sys/taskqueue.h>
24 #include <sys/mbuf.h>
25 #include <sys/videoio.h>
26 
27 #include <dev/firewire/firewire.h>
28 #include <dev/firewire/firewirereg.h>
29 #include <dev/firewire/iec13213.h>
30 #include <dev/firewire/fwcam.h>
31 #include <dev/firewire/fw_helpers.h>
32 
33 #include <dev/video/video.h>
34 
35 #include "video_if.h"
36 
37 static MALLOC_DEFINE(M_FWCAM, "fwcam", "IIDC FireWire Camera");
38 
39 static int debug = 0;
40 static int iso_channel = 0;
41 SYSCTL_DECL(_hw_firewire);
42 static SYSCTL_NODE(_hw_firewire, OID_AUTO, fwcam, CTLFLAG_RD | CTLFLAG_MPSAFE,
43     0, "IIDC Camera");
44 SYSCTL_INT(_hw_firewire_fwcam, OID_AUTO, debug, CTLFLAG_RWTUN, &debug, 0,
45     "fwcam debug level");
46 SYSCTL_INT(_hw_firewire_fwcam, OID_AUTO, iso_channel, CTLFLAG_RWTUN,
47     &iso_channel, 0, "ISO channel for isochronous receive (default 0)");
48 
49 #define FWCAM_DEBUG(lev, fmt, ...)					\
50 	do {								\
51 		if (debug >= (lev))					\
52 			printf("fwcam: " fmt, ## __VA_ARGS__);		\
53 	} while (0)
54 
55 static int	fwcam_probe(device_t);
56 static int	fwcam_attach(device_t);
57 static int	fwcam_detach(device_t);
58 static void	fwcam_probe_task(void *, int);
59 static int	fwcam_iso_start(struct fwcam_softc *);
60 static void	fwcam_iso_stop(struct fwcam_softc *);
61 static void	fwcam_iso_input(struct fw_xferq *);
62 static void	fwcam_frame_done(struct fwcam_softc *);
63 
64 static int	fwcam_hw_open(device_t);
65 static int	fwcam_hw_querycap(device_t, struct video_caps *);
66 static int	fwcam_hw_enum_format(device_t, uint32_t, struct video_format *);
67 static int	fwcam_hw_get_format(device_t, struct video_format *);
68 static int	fwcam_hw_try_format(device_t, struct video_format *);
69 static int	fwcam_hw_set_format(device_t, const struct video_format *);
70 static int	fwcam_hw_enum_framesizes(device_t, struct video_frmsizeenum *);
71 static int	fwcam_hw_enum_input(device_t, uint32_t, struct video_input *);
72 static int	fwcam_hw_get_input(device_t, uint32_t *);
73 static int	fwcam_hw_set_input(device_t, uint32_t);
74 static int	fwcam_hw_query_control(device_t, struct video_control_desc *);
75 static int	fwcam_hw_get_control(device_t, struct video_control *);
76 static int	fwcam_hw_set_control(device_t, const struct video_control *);
77 static int	fwcam_hw_start_stream(device_t);
78 static void	fwcam_hw_stop_stream(device_t);
79 
80 /*
81  * Format_0 (VGA) mode descriptors for V4L2 mapping.
82  */
83 struct fwcam_v4l2_mode {
84 	uint32_t	pixelformat;	/* V4L2 fourcc */
85 	uint32_t	width;
86 	uint32_t	height;
87 	uint32_t	bytesperline;
88 	uint32_t	sizeimage;
89 };
90 
91 static const struct fwcam_v4l2_mode fwcam_fmt0_v4l2[] = {
92 	/* mode 0: 160x120 YUV444 (24bpp packed) */
93 	{ V4L2_PIX_FMT_YUV444, 160, 120, 160 * 3, 160 * 120 * 3 },
94 	/* mode 1: 320x240 YUV422 (UYVY, 16bpp packed) */
95 	{ V4L2_PIX_FMT_UYVY,   320, 240, 320 * 2, 320 * 240 * 2 },
96 	/* mode 2: 640x480 YUV411 (12bpp) */
97 	{ V4L2_PIX_FMT_Y41P,   640, 480, 640 * 3 / 2, 640 * 480 * 3 / 2 },
98 	/* mode 3: 640x480 YUV422 (UYVY, 16bpp packed) */
99 	{ V4L2_PIX_FMT_UYVY,   640, 480, 640 * 2, 640 * 480 * 2 },
100 	/* mode 4: 640x480 RGB8 (24bpp) */
101 	{ V4L2_PIX_FMT_RGB24,  640, 480, 640 * 3, 640 * 480 * 3 },
102 	/* mode 5: 640x480 Mono8 */
103 	{ V4L2_PIX_FMT_GREY,   640, 480, 640, 640 * 480 },
104 	/* mode 6: 640x480 Mono16 */
105 	{ V4L2_PIX_FMT_Y16,    640, 480, 640 * 2, 640 * 480 * 2 },
106 };
107 
108 #define	FWCAM_FMT0_V4L2_NMODES	nitems(fwcam_fmt0_v4l2)
109 
110 /*
111  * Search a CSR directory for the IIDC command base register (key 0x40).
112  * The iSight places cmd_base inside a logical_unit_directory nested
113  * within the IIDC unit directory, so we recurse into sub-directories
114  * up to max_depth levels.
115  */
116 static uint32_t
117 fwcam_search_dir_cmd_base(uint32_t *csrrom, uint32_t dir_qoff,
118     uint32_t rom_quads, int max_depth)
119 {
120 	struct csrdirectory *dir;
121 	struct csrreg *reg;
122 	uint32_t dir_len, sub_qoff, val;
123 	int i;
124 
125 	if (dir_qoff >= rom_quads || max_depth <= 0)
126 		return (0);
127 	dir = (struct csrdirectory *)&csrrom[dir_qoff];
128 	dir_len = dir->crc_len;
129 	if (dir_qoff + 1 + dir_len > rom_quads)
130 		return (0);
131 	if (!crom_crc_valid((uint32_t *)&dir->entry[0], dir_len, dir->crc)) {
132 		if (firewire_debug)
133 			printf("fwcam: bad CRC in directory at 0x%x\n",
134 			    dir_qoff);
135 	}
136 
137 	for (i = 0; i < (int)dir_len; i++) {
138 		if (dir_qoff + 1 + i >= rom_quads)
139 			break;
140 		reg = &dir->entry[i];
141 		if (reg->key == IIDC_CROM_CMD_BASE && reg->val != 0)
142 			return (reg->val);
143 		if ((reg->key & CSRTYPE_MASK) == CSRTYPE_D) {
144 			sub_qoff = dir_qoff + 1 + i + reg->val;
145 			val = fwcam_search_dir_cmd_base(csrrom, sub_qoff,
146 			    rom_quads, max_depth - 1);
147 			if (val != 0)
148 				return (val);
149 		}
150 	}
151 	return (0);
152 }
153 
154 /*
155  * Extract IIDC command base register from the unit directory.
156  * Searches the unit directory and any sub-directories (the iSight
157  * places cmd_base inside a logical_unit_directory).
158  */
159 static uint32_t
160 fwcam_find_iidc_cmd_base(struct fw_unit *unit)
161 {
162 
163 	return (fwcam_search_dir_cmd_base(unit->fwdev->csrrom,
164 	    unit->dir_offset / 4, CSRROMSIZE / 4, 2));
165 }
166 
167 static int
168 fwcam_read_quadlet(struct fwcam_softc *sc, uint32_t offset, uint32_t *val)
169 {
170 	uint16_t dst;
171 	uint8_t spd;
172 	int err;
173 
174 	FWCAM_LOCK(sc);
175 	if (sc->fwdev == NULL) {
176 		FWCAM_UNLOCK(sc);
177 		return (ENXIO);
178 	}
179 	dst = FWLOCALBUS | sc->fwdev->dst;
180 	spd = min(sc->fwdev->speed, FWSPD_S400);
181 	FWCAM_UNLOCK(sc);
182 
183 	err = fw_read_quadlet(sc->fd.fc, M_FWCAM, dst, spd,
184 	    sc->cmd_hi, sc->cmd_lo + offset, val);
185 	if (err)
186 		FWCAM_DEBUG(1, "read_quadlet: offset=0x%x err=%d\n",
187 		    offset, err);
188 	return (err);
189 }
190 
191 static int
192 fwcam_write_quadlet(struct fwcam_softc *sc, uint32_t offset, uint32_t val)
193 {
194 	uint16_t dst;
195 	uint8_t spd;
196 	int err;
197 
198 	FWCAM_LOCK(sc);
199 	if (sc->fwdev == NULL) {
200 		FWCAM_UNLOCK(sc);
201 		return (ENXIO);
202 	}
203 	dst = FWLOCALBUS | sc->fwdev->dst;
204 	spd = min(sc->fwdev->speed, FWSPD_S400);
205 	FWCAM_UNLOCK(sc);
206 
207 	err = fw_write_quadlet(sc->fd.fc, M_FWCAM, dst, spd,
208 	    sc->cmd_hi, sc->cmd_lo + offset, val);
209 	if (err)
210 		FWCAM_DEBUG(1, "write_quadlet: offset=0x%x err=%d\n",
211 		    offset, err);
212 	return (err);
213 }
214 
215 static int
216 fwcam_read_capabilities(struct fwcam_softc *sc)
217 {
218 	int err, f, m;
219 
220 	err = fwcam_read_quadlet(sc, IIDC_V_FORMAT_INQ, &sc->formats);
221 	if (err) {
222 		device_printf(sc->fd.dev,
223 		    "failed to read V_FORMAT_INQ: %d\n", err);
224 		return (err);
225 	}
226 
227 	err = fwcam_read_quadlet(sc, IIDC_BASIC_FUNC_INQ, &sc->basic_func);
228 	if (err) {
229 		device_printf(sc->fd.dev,
230 		    "failed to read BASIC_FUNC_INQ: %d\n", err);
231 		return (err);
232 	}
233 
234 	/* Read mode and rate inquiry registers for each supported format */
235 	for (f = 0; f < 8; f++) {
236 		if (!(sc->formats & (1 << (31 - f)))) {
237 			sc->modes[f] = 0;
238 			continue;
239 		}
240 		err = fwcam_read_quadlet(sc, IIDC_V_MODE_INQ(f),
241 		    &sc->modes[f]);
242 		if (err) {
243 			sc->modes[f] = 0;
244 			continue;
245 		}
246 		for (m = 0; m < 8; m++) {
247 			if (!(sc->modes[f] & (1 << (31 - m)))) {
248 				sc->rates[f][m] = 0;
249 				continue;
250 			}
251 			err = fwcam_read_quadlet(sc, IIDC_V_RATE_INQ(f, m),
252 			    &sc->rates[f][m]);
253 			if (err)
254 				sc->rates[f][m] = 0;
255 		}
256 	}
257 
258 	err = fwcam_read_quadlet(sc, IIDC_FEATURE_HI_INQ, &sc->features_hi);
259 	if (err)
260 		sc->features_hi = 0;
261 
262 	err = fwcam_read_quadlet(sc, IIDC_FEATURE_LO_INQ, &sc->features_lo);
263 	if (err)
264 		sc->features_lo = 0;
265 
266 	return (0);
267 }
268 
269 static int
270 fwcam_power_on(struct fwcam_softc *sc)
271 {
272 	uint32_t val;
273 	int err, retries;
274 
275 	err = fwcam_read_quadlet(sc, IIDC_BASIC_FUNC_INQ, &val);
276 	if (err) {
277 		device_printf(sc->fd.dev,
278 		    "cannot read BASIC_FUNC_INQ: %d\n", err);
279 		return (err);
280 	}
281 
282 	if ((val & IIDC_CAM_POWER_CTRL) == 0) {
283 		FWCAM_DEBUG(1, "no power control, assuming powered\n");
284 		return (0);
285 	}
286 
287 	err = fwcam_read_quadlet(sc, IIDC_CAMERA_POWER, &val);
288 	if (err == 0 && (val & IIDC_POWER_ON)) {
289 		FWCAM_DEBUG(1, "camera already powered on\n");
290 		return (0);
291 	}
292 
293 	err = fwcam_write_quadlet(sc, IIDC_CAMERA_POWER, IIDC_POWER_ON);
294 	if (err) {
295 		device_printf(sc->fd.dev,
296 		    "failed to write CAMERA_POWER: %d\n", err);
297 		return (err);
298 	}
299 
300 	for (retries = 0; retries < 50; retries++) {
301 		pause("fwcampw", hz / 10);
302 
303 		if (sc->state == FWCAM_STATE_DETACHING)
304 			return (ENXIO);
305 
306 		err = fwcam_read_quadlet(sc, IIDC_CAMERA_POWER, &val);
307 		if (err)
308 			continue;	/* read may fail while powering up */
309 
310 		if (val & IIDC_POWER_ON)
311 			return (0);
312 	}
313 
314 	device_printf(sc->fd.dev, "camera power-on timeout (5s)\n");
315 	return (ETIMEDOUT);
316 }
317 
318 static void
319 fwcam_probe_task(void *arg, int pending __unused)
320 {
321 	struct fwcam_softc *sc = (struct fwcam_softc *)arg;
322 	int err;
323 
324 	if (sc->state == FWCAM_STATE_DETACHING || sc->fwdev == NULL)
325 		return;
326 
327 	err = fwcam_power_on(sc);
328 	if (err) {
329 		device_printf(sc->fd.dev,
330 		    "power-on failed (%d), trying to read anyway\n", err);
331 	}
332 
333 	if (sc->state == FWCAM_STATE_DETACHING)
334 		return;
335 
336 	if (fwcam_read_capabilities(sc) == 0) {
337 		uint32_t val;
338 
339 		if (fwcam_read_quadlet(sc, IIDC_CUR_V_FORMAT, &val) == 0)
340 			sc->cur_format = (val >> 29) & 0x7;
341 		if (fwcam_read_quadlet(sc, IIDC_CUR_V_MODE, &val) == 0)
342 			sc->cur_mode = (val >> 29) & 0x7;
343 		if (fwcam_read_quadlet(sc, IIDC_CUR_V_FRM_RATE, &val) == 0)
344 			sc->cur_framerate = (val >> 29) & 0x7;
345 
346 		FWCAM_LOCK(sc);
347 		if (sc->state == FWCAM_STATE_DETACHING) {
348 			FWCAM_UNLOCK(sc);
349 			return;
350 		}
351 		sc->state = FWCAM_STATE_PROBED;
352 		wakeup(sc);
353 		FWCAM_UNLOCK(sc);
354 
355 		if (sc->dma_ch >= 0 &&
356 		    sc->state != FWCAM_STATE_DETACHING)
357 			fwcam_iso_start(sc);
358 	} else {
359 		FWCAM_LOCK(sc);
360 		if (sc->state == FWCAM_STATE_PROBING)
361 			sc->state = FWCAM_STATE_IDLE;
362 		wakeup(sc);
363 		FWCAM_UNLOCK(sc);
364 	}
365 }
366 
367 /*
368  * Compute expected frame size for current format/mode.
369  * Format_0 (VGA) modes:
370  *   Mode 0: 160x120 YUV444  = 160*120*3 = 57600
371  *   Mode 1: 320x240 YUV422  = 320*240*2 = 153600
372  *   Mode 2: 640x480 YUV411  = 640*480*3/2 = 460800
373  *   Mode 3: 640x480 YUV422  = 640*480*2 = 614400
374  *   Mode 4: 640x480 RGB8    = 640*480*3 = 921600
375  *   Mode 5: 640x480 Mono8   = 640*480 = 307200
376  */
377 static uint32_t
378 fwcam_frame_size(struct fwcam_softc *sc)
379 {
380 
381 	if (sc->cur_format == IIDC_FMT_VGA &&
382 	    sc->cur_mode < FWCAM_FMT0_V4L2_NMODES)
383 		return (fwcam_fmt0_v4l2[sc->cur_mode].sizeimage);
384 
385 	/* Default to largest VGA mode */
386 	return (FWCAM_MAX_FRAME_SIZE);
387 }
388 
389 static int
390 fwcam_iso_start(struct fwcam_softc *sc)
391 {
392 	struct firewire_comm *fc = sc->fd.fc;
393 	struct fw_xferq *xferq;
394 	uint32_t val;
395 	int dma_ch, err;
396 
397 	mtx_assert(&sc->mtx, MA_NOTOWNED);
398 
399 	FWCAM_LOCK(sc);
400 	if (sc->dma_ch >= 0 || sc->state == FWCAM_STATE_STREAMING) {
401 		FWCAM_UNLOCK(sc);
402 		return (0);	/* already running or starting */
403 	}
404 	if (sc->state == FWCAM_STATE_DETACHING) {
405 		FWCAM_UNLOCK(sc);
406 		return (ENXIO);
407 	}
408 	FWCAM_UNLOCK(sc);
409 
410 	dma_ch = fw_open_isodma(fc, 0);
411 	if (dma_ch < 0) {
412 		device_printf(sc->fd.dev, "no IR DMA channel available\n");
413 		return (EBUSY);
414 	}
415 
416 	FWCAM_LOCK(sc);
417 	if (sc->dma_ch >= 0) {
418 		FWCAM_UNLOCK(sc);
419 		fc->ir[dma_ch]->flag &= ~FWXFERQ_OPEN;
420 		return (0);
421 	}
422 	FWCAM_UNLOCK(sc);
423 
424 	xferq = fc->ir[dma_ch];
425 	xferq->flag |= FWXFERQ_EXTBUF | FWXFERQ_HANDLER | FWXFERQ_STREAM;
426 
427 	sc->iso_channel = (uint8_t)(iso_channel & FWXFERQ_CHTAGMASK);
428 	xferq->flag &= ~FWXFERQ_CHTAGMASK;
429 	xferq->flag |= sc->iso_channel & FWXFERQ_CHTAGMASK;
430 
431 	xferq->sc = (caddr_t)sc;
432 	xferq->hand = fwcam_iso_input;
433 	xferq->bnchunk = FWCAM_ISO_NCHUNK;
434 	xferq->bnpacket = 1;
435 	xferq->psize = FWCAM_ISO_PKTSIZE;
436 	xferq->queued = 0;
437 	xferq->buf = NULL;
438 
439 	xferq->bulkxfer = malloc(sizeof(struct fw_bulkxfer) * xferq->bnchunk,
440 	    M_FWCAM, M_WAITOK | M_ZERO);
441 
442 	fw_iso_init_chunks(xferq);
443 
444 	sc->frame_size = fwcam_frame_size(sc);
445 	sc->frame_buf = malloc(sc->frame_size, M_FWCAM, M_WAITOK | M_ZERO);
446 	sc->frame_offset = 0;
447 	sc->frame_dropped = 0;
448 
449 	/* IIDC spec s3.1: set video mode registers before ISO enable */
450 	err = fwcam_write_quadlet(sc, IIDC_CUR_V_FORMAT,
451 	    (uint32_t)sc->cur_format << IIDC_CUR_V_SHIFT);
452 	if (err) {
453 		device_printf(sc->fd.dev,
454 		    "failed to set CUR_V_FORMAT: %d\n", err);
455 		goto fail;
456 	}
457 	err = fwcam_write_quadlet(sc, IIDC_CUR_V_MODE,
458 	    (uint32_t)sc->cur_mode << IIDC_CUR_V_SHIFT);
459 	if (err) {
460 		device_printf(sc->fd.dev,
461 		    "failed to set CUR_V_MODE: %d\n", err);
462 		goto fail;
463 	}
464 	err = fwcam_write_quadlet(sc, IIDC_CUR_V_FRM_RATE,
465 	    (uint32_t)sc->cur_framerate << IIDC_CUR_V_SHIFT);
466 	if (err) {
467 		device_printf(sc->fd.dev,
468 		    "failed to set CUR_V_FRM_RATE: %d\n", err);
469 		goto fail;
470 	}
471 
472 	/* Check Vmode_Error_Status - camera rejects ISO_EN on error */
473 	err = fwcam_read_quadlet(sc, IIDC_VMODE_ERR_STATUS, &val);
474 	if (err == 0 && (val & IIDC_VMODE_ERROR)) {
475 		device_printf(sc->fd.dev,
476 		    "Vmode_Error_Status set: format=%d mode=%d rate=%d "
477 		    "speed=%d\n", sc->cur_format, sc->cur_mode,
478 		    sc->cur_framerate, sc->iso_speed);
479 		err = EINVAL;
480 		goto fail;
481 	}
482 
483 	val = ((uint32_t)sc->iso_channel << IIDC_ISO_CH_SHIFT) |
484 	    ((uint32_t)sc->iso_speed << IIDC_ISO_SPEED_SHIFT);
485 	err = fwcam_write_quadlet(sc, IIDC_ISO_CHANNEL, val);
486 	if (err) {
487 		device_printf(sc->fd.dev,
488 		    "failed to set ISO_CHANNEL: %d\n", err);
489 		goto fail;
490 	}
491 
492 	err = fwcam_write_quadlet(sc, IIDC_ISO_EN, IIDC_ISO_EN_ON);
493 	if (err == EIO) {
494 		/*
495 		 * Cameras with a lens cover might power down the sensor
496 		 * when the cover is closed and reject streaming requests.
497 		 * Try to re-power and retry once before giving up.
498 		 */
499 		err = fwcam_power_on(sc);
500 		if (err == 0)
501 			err = fwcam_write_quadlet(sc, IIDC_ISO_EN,
502 			    IIDC_ISO_EN_ON);
503 		if (err) {
504 			device_printf(sc->fd.dev,
505 			    "ISO enable refused (lens cover closed?)\n");
506 			goto fail;
507 		}
508 	} else if (err) {
509 		device_printf(sc->fd.dev,
510 		    "failed to enable ISO: %d\n", err);
511 		goto fail;
512 	}
513 
514 	err = fc->irx_enable(fc, dma_ch);
515 	if (err) {
516 		device_printf(sc->fd.dev,
517 		    "failed to start IR DMA: %d\n", err);
518 		fwcam_write_quadlet(sc, IIDC_ISO_EN, 0);
519 		goto fail;
520 	}
521 
522 	FWCAM_LOCK(sc);
523 	if (sc->state == FWCAM_STATE_DETACHING) {
524 		FWCAM_UNLOCK(sc);
525 		fc->irx_disable(fc, dma_ch);
526 		fwcam_write_quadlet(sc, IIDC_ISO_EN, 0);
527 		err = ENXIO;
528 		goto fail;
529 	}
530 	sc->dma_ch = dma_ch;
531 	sc->state = FWCAM_STATE_STREAMING;
532 	FWCAM_UNLOCK(sc);
533 
534 	return (0);
535 
536 fail:
537 	fw_iso_free_chunks(xferq, M_FWCAM);
538 	xferq->flag &= ~(FWXFERQ_MODEMASK | FWXFERQ_OPEN | FWXFERQ_STREAM |
539 	    FWXFERQ_EXTBUF | FWXFERQ_HANDLER | FWXFERQ_CHTAGMASK);
540 	xferq->hand = NULL;
541 
542 	free(sc->frame_buf, M_FWCAM);
543 	sc->frame_buf = NULL;
544 	sc->dma_ch = -1;
545 
546 	return (err);
547 }
548 
549 static void
550 fwcam_iso_stop(struct fwcam_softc *sc)
551 {
552 	struct firewire_comm *fc = sc->fd.fc;
553 	struct fw_xferq *xferq;
554 	int dma_ch;
555 
556 	FWCAM_LOCK(sc);
557 	dma_ch = sc->dma_ch;
558 	if (dma_ch < 0) {
559 		FWCAM_UNLOCK(sc);
560 		return;
561 	}
562 	sc->dma_ch = -1;	/* claim ownership of teardown */
563 	FWCAM_UNLOCK(sc);
564 
565 	xferq = fc->ir[dma_ch];
566 
567 	if (xferq->flag & FWXFERQ_RUNNING)
568 		fc->irx_disable(fc, dma_ch);
569 
570 	if (sc->fwdev != NULL)
571 		fwcam_write_quadlet(sc, IIDC_ISO_EN, 0);
572 
573 	FWCAM_LOCK(sc);
574 	fw_iso_wait_inactive_locked(&sc->mtx, &sc->iso_active, "fwcamis");
575 	FWCAM_UNLOCK(sc);
576 
577 	xferq->flag &= ~(FWXFERQ_MODEMASK | FWXFERQ_OPEN | FWXFERQ_STREAM |
578 	    FWXFERQ_EXTBUF | FWXFERQ_HANDLER | FWXFERQ_CHTAGMASK);
579 	xferq->hand = NULL;
580 
581 	fw_iso_free_chunks(xferq, M_FWCAM);
582 
583 	free(sc->frame_buf, M_FWCAM);
584 	sc->frame_buf = NULL;
585 }
586 
587 static void
588 fwcam_frame_done(struct fwcam_softc *sc)
589 {
590 	struct video_buf *vb;
591 
592 	vb = video_buf_acquire(sc->sc_vd);
593 	if (vb == NULL)
594 		return;
595 
596 	if (video_buf_write(vb, 0, sc->frame_buf, sc->frame_offset) != 0) {
597 		video_buf_error(vb);
598 		return;
599 	}
600 	video_buf_done(vb, sc->frame_offset, sc->sc_sequence++);
601 }
602 
603 static void
604 fwcam_iso_input(struct fw_xferq *xferq)
605 {
606 	struct fwcam_softc *sc = (struct fwcam_softc *)xferq->sc;
607 	struct fw_bulkxfer *sxfer;
608 	struct fw_pkt *fp;
609 	struct mbuf *m;
610 	uint8_t *payload;
611 	uint32_t plen;
612 	int dma_ch;
613 
614 	FWCAM_LOCK(sc);
615 	dma_ch = sc->dma_ch;
616 	if (dma_ch < 0 || sc->frame_buf == NULL) {
617 		FWCAM_UNLOCK(sc);
618 		return;
619 	}
620 	sc->iso_active = 1;
621 	FWCAM_UNLOCK(sc);
622 
623 	while ((sxfer = STAILQ_FIRST(&xferq->stvalid)) != NULL) {
624 		STAILQ_REMOVE_HEAD(&xferq->stvalid, link);
625 
626 		m = fw_iso_dequeue(xferq, sxfer, sc->fd.fc);
627 		if (m == NULL)
628 			continue;
629 
630 		fp = mtod(m, struct fw_pkt *);
631 		plen = fp->mode.stream.len;
632 		if (plen == 0) {
633 			m_freem(m);
634 			continue;	/* empty packet (padding) */
635 		}
636 
637 		if (fp->mode.stream.sy == 1) {
638 			if (sc->frame_offset > 0 &&
639 			    sc->frame_offset == sc->frame_size) {
640 				fwcam_frame_done(sc);
641 			} else if (sc->frame_offset > 0) {
642 				struct video_buf *vb;
643 
644 				vb = video_buf_acquire(sc->sc_vd);
645 				if (vb != NULL)
646 					video_buf_error(vb);
647 				sc->frame_dropped++;
648 			}
649 			sc->frame_offset = 0;
650 		}
651 
652 		if (m->m_len < 4) {
653 			m_freem(m);
654 			continue;
655 		}
656 		payload = mtod(m, uint8_t *) + 4;
657 		if (plen > (uint32_t)(m->m_len - 4))
658 			plen = m->m_len - 4;
659 
660 		if (sc->frame_offset + plen <= sc->frame_size) {
661 			memcpy(sc->frame_buf + sc->frame_offset, payload, plen);
662 			sc->frame_offset += plen;
663 		} else {
664 			struct video_buf *vb;
665 
666 			vb = video_buf_acquire(sc->sc_vd);
667 			if (vb != NULL)
668 				video_buf_error(vb);
669 			sc->frame_dropped++;
670 			sc->frame_offset = 0;
671 		}
672 
673 		m_freem(m);
674 	}
675 
676 	fw_iso_rearm_done(xferq, sc->fd.fc, &sc->mtx, &sc->iso_active,
677 	    &sc->dma_ch, dma_ch);
678 }
679 
680 static const uint32_t fwcam_feat_inq[] = {
681 	[FWCAM_FEAT_BRIGHTNESS]   = IIDC_BRIGHTNESS_INQ,
682 	[FWCAM_FEAT_AUTO_EXPOSURE] = IIDC_AUTO_EXPOSURE_INQ,
683 	[FWCAM_FEAT_SHARPNESS]    = IIDC_SHARPNESS_INQ,
684 	[FWCAM_FEAT_WHITE_BALANCE] = IIDC_WHITE_BAL_INQ,
685 	[FWCAM_FEAT_HUE]         = IIDC_HUE_INQ,
686 	[FWCAM_FEAT_SATURATION]  = IIDC_SATURATION_INQ,
687 	[FWCAM_FEAT_GAMMA]       = IIDC_GAMMA_INQ,
688 	[FWCAM_FEAT_SHUTTER]     = IIDC_SHUTTER_INQ,
689 	[FWCAM_FEAT_GAIN]        = IIDC_GAIN_INQ,
690 	[FWCAM_FEAT_IRIS]        = IIDC_IRIS_INQ,
691 	[FWCAM_FEAT_FOCUS]       = IIDC_FOCUS_INQ,
692 	[FWCAM_FEAT_TEMPERATURE] = IIDC_TEMPERATURE_INQ,
693 	[FWCAM_FEAT_TRIGGER]     = IIDC_TRIGGER_INQ,
694 };
695 
696 static const uint32_t fwcam_feat_ctrl[] = {
697 	[FWCAM_FEAT_BRIGHTNESS]   = IIDC_BRIGHTNESS,
698 	[FWCAM_FEAT_AUTO_EXPOSURE] = IIDC_AUTO_EXPOSURE,
699 	[FWCAM_FEAT_SHARPNESS]    = IIDC_SHARPNESS,
700 	[FWCAM_FEAT_WHITE_BALANCE] = IIDC_WHITE_BALANCE,
701 	[FWCAM_FEAT_HUE]         = IIDC_HUE,
702 	[FWCAM_FEAT_SATURATION]  = IIDC_SATURATION,
703 	[FWCAM_FEAT_GAMMA]       = IIDC_GAMMA,
704 	[FWCAM_FEAT_SHUTTER]     = IIDC_SHUTTER,
705 	[FWCAM_FEAT_GAIN]        = IIDC_GAIN,
706 	[FWCAM_FEAT_IRIS]        = IIDC_IRIS,
707 	[FWCAM_FEAT_FOCUS]       = IIDC_FOCUS,
708 	[FWCAM_FEAT_TEMPERATURE] = IIDC_TEMPERATURE,
709 	[FWCAM_FEAT_TRIGGER]     = IIDC_TRIGGER_MODE,
710 	[FWCAM_FEAT_ZOOM]        = IIDC_ZOOM,
711 	[FWCAM_FEAT_PAN]         = IIDC_PAN,
712 	[FWCAM_FEAT_TILT]        = IIDC_TILT,
713 };
714 
715 /*
716  * Map IIDC feature IDs to V4L2 control IDs.
717  */
718 static const uint32_t fwcam_feat_v4l2[] = {
719 	[FWCAM_FEAT_BRIGHTNESS]    = V4L2_CID_BRIGHTNESS,
720 	[FWCAM_FEAT_AUTO_EXPOSURE] = V4L2_CID_EXPOSURE_AUTO,
721 	[FWCAM_FEAT_SHARPNESS]     = V4L2_CID_SHARPNESS,
722 	[FWCAM_FEAT_WHITE_BALANCE] = V4L2_CID_AUTO_WHITE_BALANCE,
723 	[FWCAM_FEAT_HUE]          = V4L2_CID_HUE,
724 	[FWCAM_FEAT_SATURATION]   = V4L2_CID_SATURATION,
725 	[FWCAM_FEAT_GAMMA]        = V4L2_CID_GAMMA,
726 	[FWCAM_FEAT_SHUTTER]      = V4L2_CID_EXPOSURE_ABSOLUTE,
727 	[FWCAM_FEAT_GAIN]         = V4L2_CID_GAIN,
728 	[FWCAM_FEAT_FOCUS]        = V4L2_CID_FOCUS_ABSOLUTE,
729 };
730 
731 #define	FWCAM_V4L2_CTRL_COUNT	nitems(fwcam_feat_v4l2)
732 
733 /*
734  * Find the IIDC feature ID for a V4L2 control ID.
735  * Returns -1 if not found.
736  */
737 static int
738 fwcam_find_feat_by_v4l2(uint32_t v4l2_id)
739 {
740 	int i;
741 
742 	for (i = 0; i < (int)FWCAM_V4L2_CTRL_COUNT; i++) {
743 		if (fwcam_feat_v4l2[i] == v4l2_id)
744 			return (i);
745 	}
746 	return (-1);
747 }
748 
749 static int
750 fwcam_get_feature(struct fwcam_softc *sc, struct fwcam_feature *feat)
751 {
752 	uint32_t inq, ctrl;
753 	int err;
754 
755 	if (feat->id >= FWCAM_FEAT_MAX)
756 		return (EINVAL);
757 
758 	feat->flags = 0;
759 	feat->min = 0;
760 	feat->max = 0;
761 	if (feat->id < nitems(fwcam_feat_inq) &&
762 	    fwcam_feat_inq[feat->id] != 0) {
763 		err = fwcam_read_quadlet(sc, fwcam_feat_inq[feat->id], &inq);
764 		if (err)
765 			return (err);
766 
767 		if (inq & (1 << 31))
768 			feat->flags |= FWCAM_FEATF_PRESENT;
769 		if (inq & (1 << 28))
770 			feat->flags |= FWCAM_FEATF_ONOFF;
771 		if (inq & (1 << 27))
772 			feat->flags |= FWCAM_FEATF_AUTO;
773 		if (inq & (1 << 26))
774 			feat->flags |= FWCAM_FEATF_MANUAL;
775 		feat->min = (inq >> 12) & 0xfff;
776 		feat->max = inq & 0xfff;
777 	}
778 
779 	if (feat->id >= nitems(fwcam_feat_ctrl) ||
780 	    fwcam_feat_ctrl[feat->id] == 0)
781 		return (EINVAL);
782 
783 	err = fwcam_read_quadlet(sc, fwcam_feat_ctrl[feat->id], &ctrl);
784 	if (err)
785 		return (err);
786 
787 	feat->value = ctrl & 0xfff;
788 	/* White balance has U/B in bits [20:31] and V/R in bits [8:19] */
789 	if (feat->id == FWCAM_FEAT_WHITE_BALANCE)
790 		feat->value2 = (ctrl >> 12) & 0xfff;
791 	else
792 		feat->value2 = 0;
793 
794 	return (0);
795 }
796 
797 static int
798 fwcam_set_feature(struct fwcam_softc *sc, struct fwcam_feature *feat)
799 {
800 	uint32_t ctrl, val;
801 	int err;
802 
803 	if (feat->id >= FWCAM_FEAT_MAX)
804 		return (EINVAL);
805 	if (feat->id >= nitems(fwcam_feat_ctrl) ||
806 	    fwcam_feat_ctrl[feat->id] == 0)
807 		return (EINVAL);
808 
809 	err = fwcam_read_quadlet(sc, fwcam_feat_ctrl[feat->id], &ctrl);
810 	if (err)
811 		return (err);
812 
813 	if (feat->id == FWCAM_FEAT_WHITE_BALANCE) {
814 		/* White balance: value=V/R (low 12), value2=U/B (high 12) */
815 		val = (ctrl & 0xff000000) |
816 		    ((feat->value2 & 0xfff) << 12) |
817 		    (feat->value & 0xfff);
818 	} else {
819 		/* Preserve upper bits, set new value in lower 12 */
820 		val = (ctrl & 0xfffff000) | (feat->value & 0xfff);
821 	}
822 
823 	return (fwcam_write_quadlet(sc, fwcam_feat_ctrl[feat->id], val));
824 }
825 
826 /*
827  * Ensure the camera has been probed (powered on, capabilities read).
828  * Called from hw callbacks that need device state.
829  */
830 static int
831 fwcam_ensure_probed(struct fwcam_softc *sc)
832 {
833 	int err;
834 
835 	FWCAM_LOCK(sc);
836 	if (sc->state == FWCAM_STATE_DETACHING) {
837 		FWCAM_UNLOCK(sc);
838 		return (ENXIO);
839 	}
840 
841 	if (sc->state == FWCAM_STATE_IDLE) {
842 		sc->state = FWCAM_STATE_PROBING;
843 		FWCAM_UNLOCK(sc);
844 		taskqueue_enqueue(taskqueue_thread, &sc->probe_task);
845 		FWCAM_LOCK(sc);
846 	}
847 
848 	while (sc->state == FWCAM_STATE_PROBING) {
849 		err = msleep(sc, &sc->mtx, PCATCH, "fwcampr", 10 * hz);
850 		if (err) {
851 			FWCAM_UNLOCK(sc);
852 			return (err == EWOULDBLOCK ? ETIMEDOUT : err);
853 		}
854 	}
855 
856 	if (sc->state != FWCAM_STATE_PROBED &&
857 	    sc->state != FWCAM_STATE_STREAMING) {
858 		FWCAM_UNLOCK(sc);
859 		return (ENXIO);
860 	}
861 
862 	FWCAM_UNLOCK(sc);
863 	return (0);
864 }
865 
866 static int
867 fwcam_hw_open(device_t dev)
868 {
869 	struct fwcam_softc *sc = device_get_softc(dev);
870 
871 	return (fwcam_ensure_probed(sc));
872 }
873 
874 static int
875 fwcam_hw_querycap(device_t dev, struct video_caps *caps)
876 {
877 
878 	bzero(caps, sizeof(*caps));
879 	strlcpy(caps->driver, "fwcam", sizeof(caps->driver));
880 	strlcpy(caps->card, "IIDC FireWire Camera", sizeof(caps->card));
881 	strlcpy(caps->bus_info, "firewire", sizeof(caps->bus_info));
882 	caps->version = (1 << 16) | (0 << 8) | 0;	/* 1.0.0 */
883 	caps->capabilities = VIDEO_CAP_CAPTURE |
884 	    VIDEO_CAP_READWRITE | VIDEO_CAP_STREAMING;
885 
886 	return (0);
887 }
888 
889 /*
890  * Map a sequential enum index to an IIDC mode number.
891  * Returns -1 if index is out of range.
892  */
893 static int
894 fwcam_index_to_mode(struct fwcam_softc *sc, uint32_t index)
895 {
896 	int m;
897 	uint32_t count = 0;
898 
899 	if (!(sc->formats & IIDC_FORMAT_VGA))
900 		return (-1);
901 
902 	for (m = 0; m < (int)FWCAM_FMT0_V4L2_NMODES; m++) {
903 		if (sc->modes[IIDC_FMT_VGA] & (1 << (31 - m))) {
904 			if (count == index)
905 				return (m);
906 			count++;
907 		}
908 	}
909 	return (-1);
910 }
911 
912 static int
913 fwcam_hw_enum_format(device_t dev, uint32_t index, struct video_format *fmt)
914 {
915 	struct fwcam_softc *sc = device_get_softc(dev);
916 	const struct fwcam_v4l2_mode *vm;
917 	int m;
918 
919 	m = fwcam_index_to_mode(sc, index);
920 	if (m < 0)
921 		return (EINVAL);
922 
923 	vm = &fwcam_fmt0_v4l2[m];
924 
925 	bzero(fmt, sizeof(*fmt));
926 	fmt->pixelformat = vm->pixelformat;
927 	fmt->width = vm->width;
928 	fmt->height = vm->height;
929 	fmt->bytesperline = vm->bytesperline;
930 	fmt->sizeimage = vm->sizeimage;
931 	fmt->field = V4L2_FIELD_NONE;
932 
933 	return (0);
934 }
935 
936 static int
937 fwcam_hw_get_format(device_t dev, struct video_format *fmt)
938 {
939 	struct fwcam_softc *sc = device_get_softc(dev);
940 	const struct fwcam_v4l2_mode *vm;
941 
942 	if (sc->cur_format != IIDC_FMT_VGA ||
943 	    sc->cur_mode >= FWCAM_FMT0_V4L2_NMODES)
944 		return (EIO);
945 
946 	vm = &fwcam_fmt0_v4l2[sc->cur_mode];
947 
948 	bzero(fmt, sizeof(*fmt));
949 	fmt->pixelformat = vm->pixelformat;
950 	fmt->width = vm->width;
951 	fmt->height = vm->height;
952 	fmt->bytesperline = vm->bytesperline;
953 	fmt->sizeimage = vm->sizeimage;
954 	fmt->field = V4L2_FIELD_NONE;
955 
956 	return (0);
957 }
958 
959 /*
960  * Find the IIDC mode that best matches a V4L2 format request.
961  * Returns -1 if no match.
962  */
963 static int
964 fwcam_find_mode_for_format(struct fwcam_softc *sc,
965     const struct video_format *fmt)
966 {
967 	int m, best = -1;
968 
969 	if (!(sc->formats & IIDC_FORMAT_VGA))
970 		return (-1);
971 
972 	for (m = 0; m < (int)FWCAM_FMT0_V4L2_NMODES; m++) {
973 		if (!(sc->modes[IIDC_FMT_VGA] & (1 << (31 - m))))
974 			continue;
975 		if (fwcam_fmt0_v4l2[m].pixelformat == fmt->pixelformat &&
976 		    fwcam_fmt0_v4l2[m].width == fmt->width &&
977 		    fwcam_fmt0_v4l2[m].height == fmt->height) {
978 			best = m;
979 			break;
980 		}
981 	}
982 
983 	/* If exact match failed, try matching just pixelformat */
984 	if (best < 0) {
985 		for (m = 0; m < (int)FWCAM_FMT0_V4L2_NMODES; m++) {
986 			if (!(sc->modes[IIDC_FMT_VGA] & (1 << (31 - m))))
987 				continue;
988 			if (fwcam_fmt0_v4l2[m].pixelformat ==
989 			    fmt->pixelformat) {
990 				best = m;
991 				break;
992 			}
993 		}
994 	}
995 
996 	return (best);
997 }
998 
999 static int
1000 fwcam_hw_try_format(device_t dev, struct video_format *fmt)
1001 {
1002 	struct fwcam_softc *sc = device_get_softc(dev);
1003 	const struct fwcam_v4l2_mode *vm;
1004 	int m;
1005 
1006 	m = fwcam_find_mode_for_format(sc, fmt);
1007 	if (m < 0)
1008 		return (EINVAL);
1009 
1010 	vm = &fwcam_fmt0_v4l2[m];
1011 
1012 	fmt->pixelformat = vm->pixelformat;
1013 	fmt->width = vm->width;
1014 	fmt->height = vm->height;
1015 	fmt->bytesperline = vm->bytesperline;
1016 	fmt->sizeimage = vm->sizeimage;
1017 	fmt->field = V4L2_FIELD_NONE;
1018 
1019 	return (0);
1020 }
1021 
1022 static int
1023 fwcam_hw_set_format(device_t dev, const struct video_format *fmt)
1024 {
1025 	struct fwcam_softc *sc = device_get_softc(dev);
1026 	int m, err;
1027 
1028 	m = fwcam_find_mode_for_format(sc, fmt);
1029 	if (m < 0)
1030 		return (EINVAL);
1031 
1032 	if (!(sc->rates[IIDC_FMT_VGA][m] &
1033 	    (1 << (31 - sc->cur_framerate)))) {
1034 		/* Current framerate not supported in new mode, pick first */
1035 		int r;
1036 		for (r = 0; r < 8; r++) {
1037 			if (sc->rates[IIDC_FMT_VGA][m] & (1 << (31 - r))) {
1038 				sc->cur_framerate = r;
1039 				break;
1040 			}
1041 		}
1042 	}
1043 
1044 	err = fwcam_write_quadlet(sc, IIDC_CUR_V_FORMAT,
1045 	    (uint32_t)IIDC_FMT_VGA << IIDC_CUR_V_SHIFT);
1046 	if (err == 0)
1047 		err = fwcam_write_quadlet(sc, IIDC_CUR_V_MODE,
1048 		    (uint32_t)m << IIDC_CUR_V_SHIFT);
1049 	if (err == 0)
1050 		err = fwcam_write_quadlet(sc, IIDC_CUR_V_FRM_RATE,
1051 		    (uint32_t)sc->cur_framerate << IIDC_CUR_V_SHIFT);
1052 
1053 	if (err == 0) {
1054 		sc->cur_format = IIDC_FMT_VGA;
1055 		sc->cur_mode = m;
1056 	}
1057 
1058 	return (err);
1059 }
1060 
1061 static int
1062 fwcam_hw_enum_framesizes(device_t dev, struct video_frmsizeenum *fse)
1063 {
1064 	struct fwcam_softc *sc = device_get_softc(dev);
1065 	int m;
1066 	uint32_t count = 0;
1067 
1068 	if (!(sc->formats & IIDC_FORMAT_VGA))
1069 		return (EINVAL);
1070 
1071 	for (m = 0; m < (int)FWCAM_FMT0_V4L2_NMODES; m++) {
1072 		if (!(sc->modes[IIDC_FMT_VGA] & (1 << (31 - m))))
1073 			continue;
1074 		if (fwcam_fmt0_v4l2[m].pixelformat != fse->pixelformat)
1075 			continue;
1076 		if (count == fse->index) {
1077 			fse->type = V4L2_FRMSIZE_TYPE_DISCRETE;
1078 			fse->discrete.width = fwcam_fmt0_v4l2[m].width;
1079 			fse->discrete.height = fwcam_fmt0_v4l2[m].height;
1080 			return (0);
1081 		}
1082 		count++;
1083 	}
1084 
1085 	return (EINVAL);
1086 }
1087 
1088 static int
1089 fwcam_hw_enum_input(device_t dev, uint32_t index, struct video_input *inp)
1090 {
1091 
1092 	if (index != 0)
1093 		return (EINVAL);
1094 
1095 	bzero(inp, sizeof(*inp));
1096 	inp->index = 0;
1097 	strlcpy(inp->name, "IIDC Camera", sizeof(inp->name));
1098 	inp->type = VIDEO_INPUT_TYPE_CAMERA;
1099 
1100 	return (0);
1101 }
1102 
1103 static int
1104 fwcam_hw_get_input(device_t dev, uint32_t *index)
1105 {
1106 
1107 	*index = 0;
1108 	return (0);
1109 }
1110 
1111 static int
1112 fwcam_hw_set_input(device_t dev, uint32_t index)
1113 {
1114 
1115 	if (index != 0)
1116 		return (EINVAL);
1117 	return (0);
1118 }
1119 
1120 static int
1121 fwcam_hw_query_control(device_t dev, struct video_control_desc *qc)
1122 {
1123 	struct fwcam_softc *sc = device_get_softc(dev);
1124 	struct fwcam_feature feat;
1125 	int fid;
1126 
1127 	fid = fwcam_find_feat_by_v4l2(qc->id);
1128 	if (fid < 0)
1129 		return (EINVAL);
1130 
1131 	feat.id = fid;
1132 	if (fwcam_get_feature(sc, &feat) != 0)
1133 		return (EINVAL);
1134 
1135 	if (!(feat.flags & FWCAM_FEATF_PRESENT))
1136 		return (EINVAL);
1137 
1138 	qc->type = V4L2_CTRL_TYPE_INTEGER;
1139 	strlcpy(qc->name, fwcam_feat_names[fid], sizeof(qc->name));
1140 	qc->minimum = feat.min;
1141 	qc->maximum = feat.max;
1142 	qc->step = 1;
1143 	qc->default_value = feat.min;
1144 	qc->flags = 0;
1145 
1146 	return (0);
1147 }
1148 
1149 static int
1150 fwcam_hw_get_control(device_t dev, struct video_control *ctrl)
1151 {
1152 	struct fwcam_softc *sc = device_get_softc(dev);
1153 	struct fwcam_feature feat;
1154 	int fid;
1155 
1156 	fid = fwcam_find_feat_by_v4l2(ctrl->id);
1157 	if (fid < 0)
1158 		return (EINVAL);
1159 
1160 	feat.id = fid;
1161 	if (fwcam_get_feature(sc, &feat) != 0)
1162 		return (EINVAL);
1163 
1164 	ctrl->value = feat.value;
1165 	return (0);
1166 }
1167 
1168 static int
1169 fwcam_hw_set_control(device_t dev, const struct video_control *ctrl)
1170 {
1171 	struct fwcam_softc *sc = device_get_softc(dev);
1172 	struct fwcam_feature feat;
1173 	int fid;
1174 
1175 	fid = fwcam_find_feat_by_v4l2(ctrl->id);
1176 	if (fid < 0)
1177 		return (EINVAL);
1178 
1179 	feat.id = fid;
1180 	feat.value = ctrl->value;
1181 	feat.value2 = 0;
1182 	return (fwcam_set_feature(sc, &feat));
1183 }
1184 
1185 static int
1186 fwcam_hw_start_stream(device_t dev)
1187 {
1188 	struct fwcam_softc *sc = device_get_softc(dev);
1189 	int err;
1190 
1191 	err = fwcam_ensure_probed(sc);
1192 	if (err)
1193 		return (err);
1194 
1195 	sc->sc_sequence = 0;
1196 
1197 	return (fwcam_iso_start(sc));
1198 }
1199 
1200 static void
1201 fwcam_hw_stop_stream(device_t dev)
1202 {
1203 	struct fwcam_softc *sc = device_get_softc(dev);
1204 
1205 	fwcam_iso_stop(sc);
1206 
1207 	FWCAM_LOCK(sc);
1208 	if (sc->state != FWCAM_STATE_DETACHING)
1209 		sc->state = FWCAM_STATE_PROBED;
1210 	FWCAM_UNLOCK(sc);
1211 }
1212 
1213 static int
1214 fwcam_probe(device_t dev)
1215 {
1216 	struct fw_unit *unit;
1217 
1218 	unit = fw_get_unit(dev);
1219 	if (unit == NULL)
1220 		return (ENXIO);
1221 
1222 	if (unit->spec_id != CSRVAL_1394TA)
1223 		return (ENXIO);
1224 	if (unit->sw_version != CSR_PROTCAM130 &&
1225 	    unit->sw_version != CSR_PROTCAM120 &&
1226 	    unit->sw_version != CSR_PROTCAM104)
1227 		return (ENXIO);
1228 
1229 	device_set_desc(dev, "IIDC Digital Camera over FireWire");
1230 	return (BUS_PROBE_DEFAULT);
1231 }
1232 
1233 static int
1234 fwcam_attach(device_t dev)
1235 {
1236 	struct fwcam_softc *sc;
1237 	struct fw_unit *unit;
1238 	uint32_t cmd_base;
1239 	int err;
1240 
1241 	unit = fw_get_unit(dev);
1242 	if (unit == NULL || unit->fwdev == NULL)
1243 		return (ENXIO);
1244 
1245 	cmd_base = fwcam_find_iidc_cmd_base(unit);
1246 	if (cmd_base == 0) {
1247 		device_printf(dev, "no IIDC command base in unit directory\n");
1248 		return (ENXIO);
1249 	}
1250 
1251 	sc = device_get_softc(dev);
1252 	sc->fd.dev = dev;
1253 	sc->fd.fc = fw_get_comm(dev);
1254 	mtx_init(&sc->mtx, "fwcam", NULL, MTX_DEF);
1255 
1256 	sc->fwdev = unit->fwdev;
1257 	sc->cmd_hi = 0xffff;
1258 	sc->cmd_lo = 0xf0000000 | (cmd_base << 2);
1259 	sc->iso_speed = min(unit->fwdev->speed, FWSPD_S400);
1260 	sc->state = FWCAM_STATE_IDLE;
1261 	sc->dma_ch = -1;
1262 	sc->iso_active = 0;
1263 	sc->sc_sequence = 0;
1264 	TASK_INIT(&sc->probe_task, 0, fwcam_probe_task, sc);
1265 
1266 	err = video_register(dev, &sc->sc_vd);
1267 	if (err != 0) {
1268 		device_printf(dev, "failed to register video device\n");
1269 		mtx_destroy(&sc->mtx);
1270 		return (err);
1271 	}
1272 
1273 	return (0);
1274 }
1275 
1276 static int
1277 fwcam_detach(device_t dev)
1278 {
1279 	struct fwcam_softc *sc;
1280 
1281 	sc = device_get_softc(dev);
1282 
1283 	if (sc->sc_vd != NULL)
1284 		video_unregister(sc->sc_vd);
1285 
1286 	FWCAM_LOCK(sc);
1287 	sc->state = FWCAM_STATE_DETACHING;
1288 	wakeup(sc);
1289 	FWCAM_UNLOCK(sc);
1290 
1291 	taskqueue_drain(taskqueue_thread, &sc->probe_task);
1292 	fwcam_iso_stop(sc);
1293 
1294 	FWCAM_LOCK(sc);
1295 	sc->fwdev = NULL;
1296 	FWCAM_UNLOCK(sc);
1297 
1298 	mtx_destroy(&sc->mtx);
1299 
1300 	return (0);
1301 }
1302 
1303 static device_method_t fwcam_methods[] = {
1304 	DEVMETHOD(device_probe,		fwcam_probe),
1305 	DEVMETHOD(device_attach,	fwcam_attach),
1306 	DEVMETHOD(device_detach,	fwcam_detach),
1307 
1308 	/* video(4) interface */
1309 	DEVMETHOD(video_open,		fwcam_hw_open),
1310 	DEVMETHOD(video_querycap,	fwcam_hw_querycap),
1311 	DEVMETHOD(video_enum_format,	fwcam_hw_enum_format),
1312 	DEVMETHOD(video_get_format,	fwcam_hw_get_format),
1313 	DEVMETHOD(video_try_format,	fwcam_hw_try_format),
1314 	DEVMETHOD(video_set_format,	fwcam_hw_set_format),
1315 	DEVMETHOD(video_enum_framesizes, fwcam_hw_enum_framesizes),
1316 	DEVMETHOD(video_enum_input,	fwcam_hw_enum_input),
1317 	DEVMETHOD(video_get_input,	fwcam_hw_get_input),
1318 	DEVMETHOD(video_set_input,	fwcam_hw_set_input),
1319 	DEVMETHOD(video_query_control,	fwcam_hw_query_control),
1320 	DEVMETHOD(video_get_control,	fwcam_hw_get_control),
1321 	DEVMETHOD(video_set_control,	fwcam_hw_set_control),
1322 	DEVMETHOD(video_start_stream,	fwcam_hw_start_stream),
1323 	DEVMETHOD(video_stop_stream,	fwcam_hw_stop_stream),
1324 
1325 	DEVMETHOD_END
1326 };
1327 
1328 static driver_t fwcam_driver = {
1329 	"fwcam",
1330 	fwcam_methods,
1331 	sizeof(struct fwcam_softc),
1332 };
1333 
1334 DRIVER_MODULE(fwcam, firewire, fwcam_driver, 0, 0);
1335 MODULE_VERSION(fwcam, 1);
1336 MODULE_DEPEND(fwcam, firewire, 1, 1, 1);
1337 MODULE_DEPEND(fwcam, video, 1, 1, 1);
1338