xref: /freebsd/sys/dev/firewire/fwcam.c (revision a8165edb50ab323241fa622f720d724bc5f22150)
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
fwcam_search_dir_cmd_base(uint32_t * csrrom,uint32_t dir_qoff,uint32_t rom_quads,int max_depth)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
fwcam_find_iidc_cmd_base(struct fw_unit * unit)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
fwcam_read_quadlet(struct fwcam_softc * sc,uint32_t offset,uint32_t * val)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
fwcam_write_quadlet(struct fwcam_softc * sc,uint32_t offset,uint32_t val)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
fwcam_read_capabilities(struct fwcam_softc * sc)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
fwcam_power_on(struct fwcam_softc * sc)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
fwcam_probe_task(void * arg,int pending __unused)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
fwcam_frame_size(struct fwcam_softc * sc)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
fwcam_iso_start(struct fwcam_softc * sc)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 	if (xferq->flag & FWXFERQ_RUNNING)
538 		fc->irx_disable(fc, dma_ch);
539 
540 	fw_iso_free_chunks(xferq, M_FWCAM);
541 	xferq->flag &= ~(FWXFERQ_MODEMASK | FWXFERQ_OPEN | FWXFERQ_STREAM |
542 	    FWXFERQ_EXTBUF | FWXFERQ_HANDLER | FWXFERQ_CHTAGMASK);
543 	xferq->hand = NULL;
544 
545 	free(sc->frame_buf, M_FWCAM);
546 	sc->frame_buf = NULL;
547 	sc->dma_ch = -1;
548 
549 	return (err);
550 }
551 
552 static void
fwcam_iso_stop(struct fwcam_softc * sc)553 fwcam_iso_stop(struct fwcam_softc *sc)
554 {
555 	struct firewire_comm *fc = sc->fd.fc;
556 	struct fw_xferq *xferq;
557 	int dma_ch;
558 
559 	FWCAM_LOCK(sc);
560 	dma_ch = sc->dma_ch;
561 	if (dma_ch < 0) {
562 		FWCAM_UNLOCK(sc);
563 		return;
564 	}
565 	sc->dma_ch = -1;	/* claim ownership of teardown */
566 	FWCAM_UNLOCK(sc);
567 
568 	xferq = fc->ir[dma_ch];
569 
570 	if (xferq->flag & FWXFERQ_RUNNING)
571 		fc->irx_disable(fc, dma_ch);
572 
573 	if (sc->fwdev != NULL)
574 		fwcam_write_quadlet(sc, IIDC_ISO_EN, 0);
575 
576 	FWCAM_LOCK(sc);
577 	fw_iso_wait_inactive_locked(&sc->mtx, &sc->iso_active, "fwcamis");
578 	FWCAM_UNLOCK(sc);
579 
580 	xferq->flag &= ~(FWXFERQ_MODEMASK | FWXFERQ_OPEN | FWXFERQ_STREAM |
581 	    FWXFERQ_EXTBUF | FWXFERQ_HANDLER | FWXFERQ_CHTAGMASK);
582 	xferq->hand = NULL;
583 
584 	fw_iso_free_chunks(xferq, M_FWCAM);
585 
586 	free(sc->frame_buf, M_FWCAM);
587 	sc->frame_buf = NULL;
588 }
589 
590 static void
fwcam_frame_done(struct fwcam_softc * sc)591 fwcam_frame_done(struct fwcam_softc *sc)
592 {
593 	struct video_buf *vb;
594 
595 	vb = video_buf_acquire(sc->sc_vd);
596 	if (vb == NULL)
597 		return;
598 
599 	if (video_buf_write(vb, 0, sc->frame_buf, sc->frame_offset) != 0) {
600 		video_buf_error(vb);
601 		return;
602 	}
603 	video_buf_done(vb, sc->frame_offset, sc->sc_sequence++);
604 }
605 
606 static void
fwcam_iso_input(struct fw_xferq * xferq)607 fwcam_iso_input(struct fw_xferq *xferq)
608 {
609 	struct fwcam_softc *sc = (struct fwcam_softc *)xferq->sc;
610 	struct fw_bulkxfer *sxfer;
611 	struct fw_pkt *fp;
612 	struct mbuf *m;
613 	uint8_t *payload;
614 	uint32_t plen;
615 	int dma_ch;
616 
617 	FWCAM_LOCK(sc);
618 	dma_ch = sc->dma_ch;
619 	if (dma_ch < 0 || sc->frame_buf == NULL) {
620 		FWCAM_UNLOCK(sc);
621 		return;
622 	}
623 	sc->iso_active = 1;
624 	FWCAM_UNLOCK(sc);
625 
626 	while ((sxfer = STAILQ_FIRST(&xferq->stvalid)) != NULL) {
627 		STAILQ_REMOVE_HEAD(&xferq->stvalid, link);
628 
629 		m = fw_iso_dequeue(xferq, sxfer, sc->fd.fc);
630 		if (m == NULL)
631 			continue;
632 
633 		fp = mtod(m, struct fw_pkt *);
634 		plen = fp->mode.stream.len;
635 		if (plen == 0) {
636 			m_freem(m);
637 			continue;	/* empty packet (padding) */
638 		}
639 
640 		if (fp->mode.stream.sy == 1) {
641 			if (sc->frame_offset > 0 &&
642 			    sc->frame_offset == sc->frame_size) {
643 				fwcam_frame_done(sc);
644 			} else if (sc->frame_offset > 0) {
645 				struct video_buf *vb;
646 
647 				vb = video_buf_acquire(sc->sc_vd);
648 				if (vb != NULL)
649 					video_buf_error(vb);
650 				sc->frame_dropped++;
651 			}
652 			sc->frame_offset = 0;
653 		}
654 
655 		if (m->m_len < 4) {
656 			m_freem(m);
657 			continue;
658 		}
659 		payload = mtod(m, uint8_t *) + 4;
660 		if (plen > (uint32_t)(m->m_len - 4))
661 			plen = m->m_len - 4;
662 
663 		if (sc->frame_offset + plen <= sc->frame_size) {
664 			memcpy(sc->frame_buf + sc->frame_offset, payload, plen);
665 			sc->frame_offset += plen;
666 		} else {
667 			struct video_buf *vb;
668 
669 			vb = video_buf_acquire(sc->sc_vd);
670 			if (vb != NULL)
671 				video_buf_error(vb);
672 			sc->frame_dropped++;
673 			sc->frame_offset = 0;
674 		}
675 
676 		m_freem(m);
677 	}
678 
679 	fw_iso_rearm_done(xferq, sc->fd.fc, &sc->mtx, &sc->iso_active,
680 	    &sc->dma_ch, dma_ch);
681 }
682 
683 static const uint32_t fwcam_feat_inq[] = {
684 	[FWCAM_FEAT_BRIGHTNESS]   = IIDC_BRIGHTNESS_INQ,
685 	[FWCAM_FEAT_AUTO_EXPOSURE] = IIDC_AUTO_EXPOSURE_INQ,
686 	[FWCAM_FEAT_SHARPNESS]    = IIDC_SHARPNESS_INQ,
687 	[FWCAM_FEAT_WHITE_BALANCE] = IIDC_WHITE_BAL_INQ,
688 	[FWCAM_FEAT_HUE]         = IIDC_HUE_INQ,
689 	[FWCAM_FEAT_SATURATION]  = IIDC_SATURATION_INQ,
690 	[FWCAM_FEAT_GAMMA]       = IIDC_GAMMA_INQ,
691 	[FWCAM_FEAT_SHUTTER]     = IIDC_SHUTTER_INQ,
692 	[FWCAM_FEAT_GAIN]        = IIDC_GAIN_INQ,
693 	[FWCAM_FEAT_IRIS]        = IIDC_IRIS_INQ,
694 	[FWCAM_FEAT_FOCUS]       = IIDC_FOCUS_INQ,
695 	[FWCAM_FEAT_TEMPERATURE] = IIDC_TEMPERATURE_INQ,
696 	[FWCAM_FEAT_TRIGGER]     = IIDC_TRIGGER_INQ,
697 };
698 
699 static const uint32_t fwcam_feat_ctrl[] = {
700 	[FWCAM_FEAT_BRIGHTNESS]   = IIDC_BRIGHTNESS,
701 	[FWCAM_FEAT_AUTO_EXPOSURE] = IIDC_AUTO_EXPOSURE,
702 	[FWCAM_FEAT_SHARPNESS]    = IIDC_SHARPNESS,
703 	[FWCAM_FEAT_WHITE_BALANCE] = IIDC_WHITE_BALANCE,
704 	[FWCAM_FEAT_HUE]         = IIDC_HUE,
705 	[FWCAM_FEAT_SATURATION]  = IIDC_SATURATION,
706 	[FWCAM_FEAT_GAMMA]       = IIDC_GAMMA,
707 	[FWCAM_FEAT_SHUTTER]     = IIDC_SHUTTER,
708 	[FWCAM_FEAT_GAIN]        = IIDC_GAIN,
709 	[FWCAM_FEAT_IRIS]        = IIDC_IRIS,
710 	[FWCAM_FEAT_FOCUS]       = IIDC_FOCUS,
711 	[FWCAM_FEAT_TEMPERATURE] = IIDC_TEMPERATURE,
712 	[FWCAM_FEAT_TRIGGER]     = IIDC_TRIGGER_MODE,
713 	[FWCAM_FEAT_ZOOM]        = IIDC_ZOOM,
714 	[FWCAM_FEAT_PAN]         = IIDC_PAN,
715 	[FWCAM_FEAT_TILT]        = IIDC_TILT,
716 };
717 
718 /*
719  * Map IIDC feature IDs to V4L2 control IDs.
720  */
721 static const uint32_t fwcam_feat_v4l2[] = {
722 	[FWCAM_FEAT_BRIGHTNESS]    = V4L2_CID_BRIGHTNESS,
723 	[FWCAM_FEAT_AUTO_EXPOSURE] = V4L2_CID_EXPOSURE_AUTO,
724 	[FWCAM_FEAT_SHARPNESS]     = V4L2_CID_SHARPNESS,
725 	[FWCAM_FEAT_WHITE_BALANCE] = V4L2_CID_AUTO_WHITE_BALANCE,
726 	[FWCAM_FEAT_HUE]          = V4L2_CID_HUE,
727 	[FWCAM_FEAT_SATURATION]   = V4L2_CID_SATURATION,
728 	[FWCAM_FEAT_GAMMA]        = V4L2_CID_GAMMA,
729 	[FWCAM_FEAT_SHUTTER]      = V4L2_CID_EXPOSURE_ABSOLUTE,
730 	[FWCAM_FEAT_GAIN]         = V4L2_CID_GAIN,
731 	[FWCAM_FEAT_FOCUS]        = V4L2_CID_FOCUS_ABSOLUTE,
732 };
733 
734 #define	FWCAM_V4L2_CTRL_COUNT	nitems(fwcam_feat_v4l2)
735 
736 /*
737  * Find the IIDC feature ID for a V4L2 control ID.
738  * Returns -1 if not found.
739  */
740 static int
fwcam_find_feat_by_v4l2(uint32_t v4l2_id)741 fwcam_find_feat_by_v4l2(uint32_t v4l2_id)
742 {
743 	int i;
744 
745 	for (i = 0; i < (int)FWCAM_V4L2_CTRL_COUNT; i++) {
746 		if (fwcam_feat_v4l2[i] == v4l2_id)
747 			return (i);
748 	}
749 	return (-1);
750 }
751 
752 static int
fwcam_get_feature(struct fwcam_softc * sc,struct fwcam_feature * feat)753 fwcam_get_feature(struct fwcam_softc *sc, struct fwcam_feature *feat)
754 {
755 	uint32_t inq, ctrl;
756 	int err;
757 
758 	if (feat->id >= FWCAM_FEAT_MAX)
759 		return (EINVAL);
760 
761 	feat->flags = 0;
762 	feat->min = 0;
763 	feat->max = 0;
764 	if (feat->id < nitems(fwcam_feat_inq) &&
765 	    fwcam_feat_inq[feat->id] != 0) {
766 		err = fwcam_read_quadlet(sc, fwcam_feat_inq[feat->id], &inq);
767 		if (err)
768 			return (err);
769 
770 		if (inq & (1 << 31))
771 			feat->flags |= FWCAM_FEATF_PRESENT;
772 		if (inq & (1 << 28))
773 			feat->flags |= FWCAM_FEATF_ONOFF;
774 		if (inq & (1 << 27))
775 			feat->flags |= FWCAM_FEATF_AUTO;
776 		if (inq & (1 << 26))
777 			feat->flags |= FWCAM_FEATF_MANUAL;
778 		feat->min = (inq >> 12) & 0xfff;
779 		feat->max = inq & 0xfff;
780 	}
781 
782 	if (feat->id >= nitems(fwcam_feat_ctrl) ||
783 	    fwcam_feat_ctrl[feat->id] == 0)
784 		return (EINVAL);
785 
786 	err = fwcam_read_quadlet(sc, fwcam_feat_ctrl[feat->id], &ctrl);
787 	if (err)
788 		return (err);
789 
790 	feat->value = ctrl & 0xfff;
791 	/* White balance has U/B in bits [20:31] and V/R in bits [8:19] */
792 	if (feat->id == FWCAM_FEAT_WHITE_BALANCE)
793 		feat->value2 = (ctrl >> 12) & 0xfff;
794 	else
795 		feat->value2 = 0;
796 
797 	return (0);
798 }
799 
800 static int
fwcam_set_feature(struct fwcam_softc * sc,struct fwcam_feature * feat)801 fwcam_set_feature(struct fwcam_softc *sc, struct fwcam_feature *feat)
802 {
803 	uint32_t ctrl, val;
804 	int err;
805 
806 	if (feat->id >= FWCAM_FEAT_MAX)
807 		return (EINVAL);
808 	if (feat->id >= nitems(fwcam_feat_ctrl) ||
809 	    fwcam_feat_ctrl[feat->id] == 0)
810 		return (EINVAL);
811 
812 	err = fwcam_read_quadlet(sc, fwcam_feat_ctrl[feat->id], &ctrl);
813 	if (err)
814 		return (err);
815 
816 	if (feat->id == FWCAM_FEAT_WHITE_BALANCE) {
817 		/* White balance: value=V/R (low 12), value2=U/B (high 12) */
818 		val = (ctrl & 0xff000000) |
819 		    ((feat->value2 & 0xfff) << 12) |
820 		    (feat->value & 0xfff);
821 	} else {
822 		/* Preserve upper bits, set new value in lower 12 */
823 		val = (ctrl & 0xfffff000) | (feat->value & 0xfff);
824 	}
825 
826 	return (fwcam_write_quadlet(sc, fwcam_feat_ctrl[feat->id], val));
827 }
828 
829 /*
830  * Ensure the camera has been probed (powered on, capabilities read).
831  * Called from hw callbacks that need device state.
832  */
833 static int
fwcam_ensure_probed(struct fwcam_softc * sc)834 fwcam_ensure_probed(struct fwcam_softc *sc)
835 {
836 	int err;
837 
838 	FWCAM_LOCK(sc);
839 	if (sc->state == FWCAM_STATE_DETACHING) {
840 		FWCAM_UNLOCK(sc);
841 		return (ENXIO);
842 	}
843 
844 	if (sc->state == FWCAM_STATE_IDLE) {
845 		sc->state = FWCAM_STATE_PROBING;
846 		FWCAM_UNLOCK(sc);
847 		taskqueue_enqueue(taskqueue_thread, &sc->probe_task);
848 		FWCAM_LOCK(sc);
849 	}
850 
851 	while (sc->state == FWCAM_STATE_PROBING) {
852 		err = msleep(sc, &sc->mtx, PCATCH, "fwcampr", 10 * hz);
853 		if (err) {
854 			FWCAM_UNLOCK(sc);
855 			return (err == EWOULDBLOCK ? ETIMEDOUT : err);
856 		}
857 	}
858 
859 	if (sc->state != FWCAM_STATE_PROBED &&
860 	    sc->state != FWCAM_STATE_STREAMING) {
861 		FWCAM_UNLOCK(sc);
862 		return (ENXIO);
863 	}
864 
865 	FWCAM_UNLOCK(sc);
866 	return (0);
867 }
868 
869 static int
fwcam_hw_open(device_t dev)870 fwcam_hw_open(device_t dev)
871 {
872 	struct fwcam_softc *sc = device_get_softc(dev);
873 
874 	return (fwcam_ensure_probed(sc));
875 }
876 
877 static int
fwcam_hw_querycap(device_t dev,struct video_caps * caps)878 fwcam_hw_querycap(device_t dev, struct video_caps *caps)
879 {
880 
881 	bzero(caps, sizeof(*caps));
882 	strlcpy(caps->driver, "fwcam", sizeof(caps->driver));
883 	strlcpy(caps->card, "IIDC FireWire Camera", sizeof(caps->card));
884 	strlcpy(caps->bus_info, "firewire", sizeof(caps->bus_info));
885 	caps->version = (1 << 16) | (0 << 8) | 0;	/* 1.0.0 */
886 	caps->capabilities = VIDEO_CAP_CAPTURE |
887 	    VIDEO_CAP_READWRITE | VIDEO_CAP_STREAMING;
888 
889 	return (0);
890 }
891 
892 /*
893  * Map a sequential enum index to an IIDC mode number.
894  * Returns -1 if index is out of range.
895  */
896 static int
fwcam_index_to_mode(struct fwcam_softc * sc,uint32_t index)897 fwcam_index_to_mode(struct fwcam_softc *sc, uint32_t index)
898 {
899 	int m;
900 	uint32_t count = 0;
901 
902 	if (!(sc->formats & IIDC_FORMAT_VGA))
903 		return (-1);
904 
905 	for (m = 0; m < (int)FWCAM_FMT0_V4L2_NMODES; m++) {
906 		if (sc->modes[IIDC_FMT_VGA] & (1 << (31 - m))) {
907 			if (count == index)
908 				return (m);
909 			count++;
910 		}
911 	}
912 	return (-1);
913 }
914 
915 static int
fwcam_hw_enum_format(device_t dev,uint32_t index,struct video_format * fmt)916 fwcam_hw_enum_format(device_t dev, uint32_t index, struct video_format *fmt)
917 {
918 	struct fwcam_softc *sc = device_get_softc(dev);
919 	const struct fwcam_v4l2_mode *vm;
920 	int m;
921 
922 	m = fwcam_index_to_mode(sc, index);
923 	if (m < 0)
924 		return (EINVAL);
925 
926 	vm = &fwcam_fmt0_v4l2[m];
927 
928 	bzero(fmt, sizeof(*fmt));
929 	fmt->pixelformat = vm->pixelformat;
930 	fmt->width = vm->width;
931 	fmt->height = vm->height;
932 	fmt->bytesperline = vm->bytesperline;
933 	fmt->sizeimage = vm->sizeimage;
934 	fmt->field = V4L2_FIELD_NONE;
935 
936 	return (0);
937 }
938 
939 static int
fwcam_hw_get_format(device_t dev,struct video_format * fmt)940 fwcam_hw_get_format(device_t dev, struct video_format *fmt)
941 {
942 	struct fwcam_softc *sc = device_get_softc(dev);
943 	const struct fwcam_v4l2_mode *vm;
944 
945 	if (sc->cur_format != IIDC_FMT_VGA ||
946 	    sc->cur_mode >= FWCAM_FMT0_V4L2_NMODES)
947 		return (EIO);
948 
949 	vm = &fwcam_fmt0_v4l2[sc->cur_mode];
950 
951 	bzero(fmt, sizeof(*fmt));
952 	fmt->pixelformat = vm->pixelformat;
953 	fmt->width = vm->width;
954 	fmt->height = vm->height;
955 	fmt->bytesperline = vm->bytesperline;
956 	fmt->sizeimage = vm->sizeimage;
957 	fmt->field = V4L2_FIELD_NONE;
958 
959 	return (0);
960 }
961 
962 /*
963  * Find the IIDC mode that best matches a V4L2 format request.
964  * Returns -1 if no match.
965  */
966 static int
fwcam_find_mode_for_format(struct fwcam_softc * sc,const struct video_format * fmt)967 fwcam_find_mode_for_format(struct fwcam_softc *sc,
968     const struct video_format *fmt)
969 {
970 	int m, best = -1;
971 
972 	if (!(sc->formats & IIDC_FORMAT_VGA))
973 		return (-1);
974 
975 	for (m = 0; m < (int)FWCAM_FMT0_V4L2_NMODES; m++) {
976 		if (!(sc->modes[IIDC_FMT_VGA] & (1 << (31 - m))))
977 			continue;
978 		if (fwcam_fmt0_v4l2[m].pixelformat == fmt->pixelformat &&
979 		    fwcam_fmt0_v4l2[m].width == fmt->width &&
980 		    fwcam_fmt0_v4l2[m].height == fmt->height) {
981 			best = m;
982 			break;
983 		}
984 	}
985 
986 	/* If exact match failed, try matching just pixelformat */
987 	if (best < 0) {
988 		for (m = 0; m < (int)FWCAM_FMT0_V4L2_NMODES; m++) {
989 			if (!(sc->modes[IIDC_FMT_VGA] & (1 << (31 - m))))
990 				continue;
991 			if (fwcam_fmt0_v4l2[m].pixelformat ==
992 			    fmt->pixelformat) {
993 				best = m;
994 				break;
995 			}
996 		}
997 	}
998 
999 	return (best);
1000 }
1001 
1002 static int
fwcam_hw_try_format(device_t dev,struct video_format * fmt)1003 fwcam_hw_try_format(device_t dev, struct video_format *fmt)
1004 {
1005 	struct fwcam_softc *sc = device_get_softc(dev);
1006 	const struct fwcam_v4l2_mode *vm;
1007 	int m;
1008 
1009 	m = fwcam_find_mode_for_format(sc, fmt);
1010 	if (m < 0)
1011 		return (EINVAL);
1012 
1013 	vm = &fwcam_fmt0_v4l2[m];
1014 
1015 	fmt->pixelformat = vm->pixelformat;
1016 	fmt->width = vm->width;
1017 	fmt->height = vm->height;
1018 	fmt->bytesperline = vm->bytesperline;
1019 	fmt->sizeimage = vm->sizeimage;
1020 	fmt->field = V4L2_FIELD_NONE;
1021 
1022 	return (0);
1023 }
1024 
1025 static int
fwcam_hw_set_format(device_t dev,const struct video_format * fmt)1026 fwcam_hw_set_format(device_t dev, const struct video_format *fmt)
1027 {
1028 	struct fwcam_softc *sc = device_get_softc(dev);
1029 	int m, err;
1030 
1031 	m = fwcam_find_mode_for_format(sc, fmt);
1032 	if (m < 0)
1033 		return (EINVAL);
1034 
1035 	if (!(sc->rates[IIDC_FMT_VGA][m] &
1036 	    (1 << (31 - sc->cur_framerate)))) {
1037 		/* Current framerate not supported in new mode, pick first */
1038 		int r;
1039 		for (r = 0; r < 8; r++) {
1040 			if (sc->rates[IIDC_FMT_VGA][m] & (1 << (31 - r))) {
1041 				sc->cur_framerate = r;
1042 				break;
1043 			}
1044 		}
1045 	}
1046 
1047 	err = fwcam_write_quadlet(sc, IIDC_CUR_V_FORMAT,
1048 	    (uint32_t)IIDC_FMT_VGA << IIDC_CUR_V_SHIFT);
1049 	if (err == 0)
1050 		err = fwcam_write_quadlet(sc, IIDC_CUR_V_MODE,
1051 		    (uint32_t)m << IIDC_CUR_V_SHIFT);
1052 	if (err == 0)
1053 		err = fwcam_write_quadlet(sc, IIDC_CUR_V_FRM_RATE,
1054 		    (uint32_t)sc->cur_framerate << IIDC_CUR_V_SHIFT);
1055 
1056 	if (err == 0) {
1057 		sc->cur_format = IIDC_FMT_VGA;
1058 		sc->cur_mode = m;
1059 	}
1060 
1061 	return (err);
1062 }
1063 
1064 static int
fwcam_hw_enum_framesizes(device_t dev,struct video_frmsizeenum * fse)1065 fwcam_hw_enum_framesizes(device_t dev, struct video_frmsizeenum *fse)
1066 {
1067 	struct fwcam_softc *sc = device_get_softc(dev);
1068 	int m;
1069 	uint32_t count = 0;
1070 
1071 	if (!(sc->formats & IIDC_FORMAT_VGA))
1072 		return (EINVAL);
1073 
1074 	for (m = 0; m < (int)FWCAM_FMT0_V4L2_NMODES; m++) {
1075 		if (!(sc->modes[IIDC_FMT_VGA] & (1 << (31 - m))))
1076 			continue;
1077 		if (fwcam_fmt0_v4l2[m].pixelformat != fse->pixelformat)
1078 			continue;
1079 		if (count == fse->index) {
1080 			fse->type = V4L2_FRMSIZE_TYPE_DISCRETE;
1081 			fse->discrete.width = fwcam_fmt0_v4l2[m].width;
1082 			fse->discrete.height = fwcam_fmt0_v4l2[m].height;
1083 			return (0);
1084 		}
1085 		count++;
1086 	}
1087 
1088 	return (EINVAL);
1089 }
1090 
1091 static int
fwcam_hw_enum_input(device_t dev,uint32_t index,struct video_input * inp)1092 fwcam_hw_enum_input(device_t dev, uint32_t index, struct video_input *inp)
1093 {
1094 
1095 	if (index != 0)
1096 		return (EINVAL);
1097 
1098 	bzero(inp, sizeof(*inp));
1099 	inp->index = 0;
1100 	strlcpy(inp->name, "IIDC Camera", sizeof(inp->name));
1101 	inp->type = VIDEO_INPUT_TYPE_CAMERA;
1102 
1103 	return (0);
1104 }
1105 
1106 static int
fwcam_hw_get_input(device_t dev,uint32_t * index)1107 fwcam_hw_get_input(device_t dev, uint32_t *index)
1108 {
1109 
1110 	*index = 0;
1111 	return (0);
1112 }
1113 
1114 static int
fwcam_hw_set_input(device_t dev,uint32_t index)1115 fwcam_hw_set_input(device_t dev, uint32_t index)
1116 {
1117 
1118 	if (index != 0)
1119 		return (EINVAL);
1120 	return (0);
1121 }
1122 
1123 static int
fwcam_hw_query_control(device_t dev,struct video_control_desc * qc)1124 fwcam_hw_query_control(device_t dev, struct video_control_desc *qc)
1125 {
1126 	struct fwcam_softc *sc = device_get_softc(dev);
1127 	struct fwcam_feature feat;
1128 	int fid;
1129 
1130 	fid = fwcam_find_feat_by_v4l2(qc->id);
1131 	if (fid < 0)
1132 		return (EINVAL);
1133 
1134 	feat.id = fid;
1135 	if (fwcam_get_feature(sc, &feat) != 0)
1136 		return (EINVAL);
1137 
1138 	if (!(feat.flags & FWCAM_FEATF_PRESENT))
1139 		return (EINVAL);
1140 
1141 	qc->type = V4L2_CTRL_TYPE_INTEGER;
1142 	strlcpy(qc->name, fwcam_feat_names[fid], sizeof(qc->name));
1143 	qc->minimum = feat.min;
1144 	qc->maximum = feat.max;
1145 	qc->step = 1;
1146 	qc->default_value = feat.min;
1147 	qc->flags = 0;
1148 
1149 	return (0);
1150 }
1151 
1152 static int
fwcam_hw_get_control(device_t dev,struct video_control * ctrl)1153 fwcam_hw_get_control(device_t dev, struct video_control *ctrl)
1154 {
1155 	struct fwcam_softc *sc = device_get_softc(dev);
1156 	struct fwcam_feature feat;
1157 	int fid;
1158 
1159 	fid = fwcam_find_feat_by_v4l2(ctrl->id);
1160 	if (fid < 0)
1161 		return (EINVAL);
1162 
1163 	feat.id = fid;
1164 	if (fwcam_get_feature(sc, &feat) != 0)
1165 		return (EINVAL);
1166 
1167 	ctrl->value = feat.value;
1168 	return (0);
1169 }
1170 
1171 static int
fwcam_hw_set_control(device_t dev,const struct video_control * ctrl)1172 fwcam_hw_set_control(device_t dev, const struct video_control *ctrl)
1173 {
1174 	struct fwcam_softc *sc = device_get_softc(dev);
1175 	struct fwcam_feature feat;
1176 	int fid;
1177 
1178 	fid = fwcam_find_feat_by_v4l2(ctrl->id);
1179 	if (fid < 0)
1180 		return (EINVAL);
1181 
1182 	feat.id = fid;
1183 	feat.value = ctrl->value;
1184 	feat.value2 = 0;
1185 	return (fwcam_set_feature(sc, &feat));
1186 }
1187 
1188 static int
fwcam_hw_start_stream(device_t dev)1189 fwcam_hw_start_stream(device_t dev)
1190 {
1191 	struct fwcam_softc *sc = device_get_softc(dev);
1192 	int err;
1193 
1194 	err = fwcam_ensure_probed(sc);
1195 	if (err)
1196 		return (err);
1197 
1198 	sc->sc_sequence = 0;
1199 
1200 	return (fwcam_iso_start(sc));
1201 }
1202 
1203 static void
fwcam_hw_stop_stream(device_t dev)1204 fwcam_hw_stop_stream(device_t dev)
1205 {
1206 	struct fwcam_softc *sc = device_get_softc(dev);
1207 
1208 	fwcam_iso_stop(sc);
1209 
1210 	FWCAM_LOCK(sc);
1211 	if (sc->state != FWCAM_STATE_DETACHING)
1212 		sc->state = FWCAM_STATE_PROBED;
1213 	FWCAM_UNLOCK(sc);
1214 }
1215 
1216 static int
fwcam_probe(device_t dev)1217 fwcam_probe(device_t dev)
1218 {
1219 	struct fw_unit *unit;
1220 
1221 	unit = fw_get_unit(dev);
1222 	if (unit == NULL)
1223 		return (ENXIO);
1224 
1225 	if (unit->spec_id != CSRVAL_1394TA)
1226 		return (ENXIO);
1227 	if (unit->sw_version != CSR_PROTCAM130 &&
1228 	    unit->sw_version != CSR_PROTCAM120 &&
1229 	    unit->sw_version != CSR_PROTCAM104)
1230 		return (ENXIO);
1231 
1232 	device_set_desc(dev, "IIDC Digital Camera over FireWire");
1233 	return (BUS_PROBE_DEFAULT);
1234 }
1235 
1236 static int
fwcam_attach(device_t dev)1237 fwcam_attach(device_t dev)
1238 {
1239 	struct fwcam_softc *sc;
1240 	struct fw_unit *unit;
1241 	uint32_t cmd_base;
1242 	int err;
1243 
1244 	unit = fw_get_unit(dev);
1245 	if (unit == NULL || unit->fwdev == NULL)
1246 		return (ENXIO);
1247 
1248 	cmd_base = fwcam_find_iidc_cmd_base(unit);
1249 	if (cmd_base == 0) {
1250 		device_printf(dev, "no IIDC command base in unit directory\n");
1251 		return (ENXIO);
1252 	}
1253 
1254 	sc = device_get_softc(dev);
1255 	sc->fd.dev = dev;
1256 	sc->fd.fc = fw_get_comm(dev);
1257 	mtx_init(&sc->mtx, "fwcam", NULL, MTX_DEF);
1258 
1259 	sc->fwdev = unit->fwdev;
1260 	sc->cmd_hi = 0xffff;
1261 	sc->cmd_lo = 0xf0000000 | (cmd_base << 2);
1262 	sc->iso_speed = min(unit->fwdev->speed, FWSPD_S400);
1263 	sc->state = FWCAM_STATE_IDLE;
1264 	sc->dma_ch = -1;
1265 	sc->iso_active = 0;
1266 	sc->sc_sequence = 0;
1267 	TASK_INIT(&sc->probe_task, 0, fwcam_probe_task, sc);
1268 
1269 	err = video_register(dev, &sc->sc_vd);
1270 	if (err != 0) {
1271 		device_printf(dev, "failed to register video device\n");
1272 		mtx_destroy(&sc->mtx);
1273 		return (err);
1274 	}
1275 
1276 	return (0);
1277 }
1278 
1279 static int
fwcam_detach(device_t dev)1280 fwcam_detach(device_t dev)
1281 {
1282 	struct fwcam_softc *sc;
1283 
1284 	sc = device_get_softc(dev);
1285 
1286 	if (sc->sc_vd != NULL)
1287 		video_unregister(sc->sc_vd);
1288 
1289 	FWCAM_LOCK(sc);
1290 	sc->state = FWCAM_STATE_DETACHING;
1291 	wakeup(sc);
1292 	FWCAM_UNLOCK(sc);
1293 
1294 	taskqueue_drain(taskqueue_thread, &sc->probe_task);
1295 	fwcam_iso_stop(sc);
1296 
1297 	FWCAM_LOCK(sc);
1298 	sc->fwdev = NULL;
1299 	FWCAM_UNLOCK(sc);
1300 
1301 	mtx_destroy(&sc->mtx);
1302 
1303 	return (0);
1304 }
1305 
1306 static device_method_t fwcam_methods[] = {
1307 	DEVMETHOD(device_probe,		fwcam_probe),
1308 	DEVMETHOD(device_attach,	fwcam_attach),
1309 	DEVMETHOD(device_detach,	fwcam_detach),
1310 
1311 	/* video(4) interface */
1312 	DEVMETHOD(video_open,		fwcam_hw_open),
1313 	DEVMETHOD(video_querycap,	fwcam_hw_querycap),
1314 	DEVMETHOD(video_enum_format,	fwcam_hw_enum_format),
1315 	DEVMETHOD(video_get_format,	fwcam_hw_get_format),
1316 	DEVMETHOD(video_try_format,	fwcam_hw_try_format),
1317 	DEVMETHOD(video_set_format,	fwcam_hw_set_format),
1318 	DEVMETHOD(video_enum_framesizes, fwcam_hw_enum_framesizes),
1319 	DEVMETHOD(video_enum_input,	fwcam_hw_enum_input),
1320 	DEVMETHOD(video_get_input,	fwcam_hw_get_input),
1321 	DEVMETHOD(video_set_input,	fwcam_hw_set_input),
1322 	DEVMETHOD(video_query_control,	fwcam_hw_query_control),
1323 	DEVMETHOD(video_get_control,	fwcam_hw_get_control),
1324 	DEVMETHOD(video_set_control,	fwcam_hw_set_control),
1325 	DEVMETHOD(video_start_stream,	fwcam_hw_start_stream),
1326 	DEVMETHOD(video_stop_stream,	fwcam_hw_stop_stream),
1327 
1328 	DEVMETHOD_END
1329 };
1330 
1331 static driver_t fwcam_driver = {
1332 	"fwcam",
1333 	fwcam_methods,
1334 	sizeof(struct fwcam_softc),
1335 };
1336 
1337 DRIVER_MODULE(fwcam, firewire, fwcam_driver, 0, 0);
1338 MODULE_VERSION(fwcam, 1);
1339 MODULE_DEPEND(fwcam, firewire, 1, 1, 1);
1340 MODULE_DEPEND(fwcam, video, 1, 1, 1);
1341