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