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/conf.h>
20 #include <sys/malloc.h>
21 #include <sys/lock.h>
22 #include <sys/mutex.h>
23 #include <sys/sysctl.h>
24 #include <sys/taskqueue.h>
25 #include <sys/fcntl.h>
26 #include <sys/poll.h>
27 #include <sys/selinfo.h>
28 #include <sys/uio.h>
29 #include <sys/mbuf.h>
30
31 #include <dev/firewire/firewire.h>
32 #include <dev/firewire/firewirereg.h>
33 #include <dev/firewire/iec13213.h>
34 #include <dev/firewire/fwcam.h>
35 #include <dev/firewire/fw_helpers.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 void fwcam_identify(driver_t *, device_t);
56 static int fwcam_probe(device_t);
57 static int fwcam_attach(device_t);
58 static int fwcam_detach(device_t);
59 static void fwcam_post_busreset(void *);
60 static void fwcam_probe_task(void *, int);
61 static void fwcam_post_explore(void *);
62 static int fwcam_iso_start(struct fwcam_softc *);
63 static void fwcam_iso_stop(struct fwcam_softc *);
64 static void fwcam_iso_input(struct fw_xferq *);
65
66 static d_open_t fwcam_cdev_open;
67 static d_close_t fwcam_cdev_close;
68 static d_read_t fwcam_cdev_read;
69 static d_poll_t fwcam_cdev_poll;
70 static d_ioctl_t fwcam_cdev_ioctl;
71
72 static struct cdevsw fwcam_cdevsw = {
73 .d_version = D_VERSION,
74 .d_flags = D_TRACKCLOSE,
75 .d_open = fwcam_cdev_open,
76 .d_close = fwcam_cdev_close,
77 .d_read = fwcam_cdev_read,
78 .d_poll = fwcam_cdev_poll,
79 .d_ioctl = fwcam_cdev_ioctl,
80 .d_name = "fwcam",
81 };
82
83 static uint32_t
fwcam_find_iidc(struct fw_device * fwdev)84 fwcam_find_iidc(struct fw_device *fwdev)
85 {
86 struct crom_context cc;
87 struct csrreg *reg;
88 uint32_t cmd_base;
89
90 if (!crom_has_specver(fwdev->csrrom, CSRVAL_1394TA, CSR_PROTCAM130) &&
91 !crom_has_specver(fwdev->csrrom, CSRVAL_1394TA, CSR_PROTCAM120) &&
92 !crom_has_specver(fwdev->csrrom, CSRVAL_1394TA, CSR_PROTCAM104))
93 return (0);
94
95 cmd_base = 0;
96 crom_init_context(&cc, fwdev->csrrom);
97 reg = crom_search_key(&cc, IIDC_CROM_CMD_BASE);
98 if (reg != NULL && reg->val != 0)
99 cmd_base = reg->val;
100
101 return (cmd_base);
102 }
103
104 static int
fwcam_read_quadlet(struct fwcam_softc * sc,uint32_t offset,uint32_t * val)105 fwcam_read_quadlet(struct fwcam_softc *sc, uint32_t offset, uint32_t *val)
106 {
107 uint16_t dst;
108 uint8_t spd;
109 int err;
110
111 FWCAM_LOCK(sc);
112 if (sc->fwdev == NULL) {
113 FWCAM_UNLOCK(sc);
114 return (ENXIO);
115 }
116 dst = FWLOCALBUS | sc->fwdev->dst;
117 spd = min(sc->fwdev->speed, FWSPD_S400);
118 FWCAM_UNLOCK(sc);
119
120 err = fw_read_quadlet(sc->fd.fc, M_FWCAM, dst, spd,
121 sc->cmd_hi, sc->cmd_lo + offset, val);
122 if (err)
123 FWCAM_DEBUG(1, "read_quadlet: offset=0x%x err=%d\n",
124 offset, err);
125 return (err);
126 }
127
128 static int
fwcam_write_quadlet(struct fwcam_softc * sc,uint32_t offset,uint32_t val)129 fwcam_write_quadlet(struct fwcam_softc *sc, uint32_t offset, uint32_t val)
130 {
131 uint16_t dst;
132 uint8_t spd;
133 int err;
134
135 FWCAM_LOCK(sc);
136 if (sc->fwdev == NULL) {
137 FWCAM_UNLOCK(sc);
138 return (ENXIO);
139 }
140 dst = FWLOCALBUS | sc->fwdev->dst;
141 spd = min(sc->fwdev->speed, FWSPD_S400);
142 FWCAM_UNLOCK(sc);
143
144 err = fw_write_quadlet(sc->fd.fc, M_FWCAM, dst, spd,
145 sc->cmd_hi, sc->cmd_lo + offset, val);
146 if (err)
147 FWCAM_DEBUG(1, "write_quadlet: offset=0x%x err=%d\n",
148 offset, err);
149 return (err);
150 }
151
152 #if 0
153 static const char *
154 fwcam_format_name(int format)
155 {
156 static const char *names[] = {
157 "VGA (Format_0)",
158 "Super VGA 1 (Format_1)",
159 "Super VGA 2 (Format_2)",
160 "Reserved",
161 "Reserved",
162 "Reserved",
163 "Still Image (Format_6)",
164 "Partial Image (Format_7)",
165 };
166
167 if (format >= 0 && format <= 7)
168 return (names[format]);
169 return ("Unknown");
170 }
171 #endif
172
173 static int
fwcam_read_capabilities(struct fwcam_softc * sc)174 fwcam_read_capabilities(struct fwcam_softc *sc)
175 {
176 int err;
177
178 err = fwcam_read_quadlet(sc, IIDC_V_FORMAT_INQ, &sc->formats);
179 if (err) {
180 device_printf(sc->fd.dev,
181 "failed to read V_FORMAT_INQ: %d\n", err);
182 return (err);
183 }
184
185 err = fwcam_read_quadlet(sc, IIDC_BASIC_FUNC_INQ, &sc->basic_func);
186 if (err) {
187 device_printf(sc->fd.dev,
188 "failed to read BASIC_FUNC_INQ: %d\n", err);
189 return (err);
190 }
191
192 err = fwcam_read_quadlet(sc, IIDC_FEATURE_HI_INQ, &sc->features_hi);
193 if (err)
194 sc->features_hi = 0;
195
196 err = fwcam_read_quadlet(sc, IIDC_FEATURE_LO_INQ, &sc->features_lo);
197 if (err)
198 sc->features_lo = 0;
199
200 return (0);
201 }
202
203 static int
fwcam_power_on(struct fwcam_softc * sc)204 fwcam_power_on(struct fwcam_softc *sc)
205 {
206 uint32_t val;
207 int err, retries;
208
209 err = fwcam_read_quadlet(sc, IIDC_BASIC_FUNC_INQ, &val);
210 if (err) {
211 device_printf(sc->fd.dev,
212 "cannot read BASIC_FUNC_INQ: %d\n", err);
213 return (err);
214 }
215
216 if ((val & IIDC_CAM_POWER_CTRL) == 0) {
217 FWCAM_DEBUG(1, "no power control, assuming powered\n");
218 return (0);
219 }
220
221 err = fwcam_read_quadlet(sc, IIDC_CAMERA_POWER, &val);
222 if (err == 0 && (val & IIDC_POWER_ON)) {
223 FWCAM_DEBUG(1, "camera already powered on\n");
224 return (0);
225 }
226
227 err = fwcam_write_quadlet(sc, IIDC_CAMERA_POWER, IIDC_POWER_ON);
228 if (err) {
229 device_printf(sc->fd.dev,
230 "failed to write CAMERA_POWER: %d\n", err);
231 return (err);
232 }
233
234 for (retries = 0; retries < 50; retries++) {
235 pause("fwcampw", hz / 10);
236
237 if (sc->state == FWCAM_STATE_DETACHING)
238 return (ENXIO);
239
240 err = fwcam_read_quadlet(sc, IIDC_CAMERA_POWER, &val);
241 if (err)
242 continue; /* read may fail while powering up */
243
244 if (val & IIDC_POWER_ON)
245 return (0);
246 }
247
248 device_printf(sc->fd.dev, "camera power-on timeout (5s)\n");
249 return (ETIMEDOUT);
250 }
251
252 static void
fwcam_probe_task(void * arg,int pending __unused)253 fwcam_probe_task(void *arg, int pending __unused)
254 {
255 struct fwcam_softc *sc = (struct fwcam_softc *)arg;
256 int err;
257
258 if (sc->state == FWCAM_STATE_DETACHING || sc->fwdev == NULL)
259 return;
260
261 err = fwcam_power_on(sc);
262 if (err) {
263 device_printf(sc->fd.dev,
264 "power-on failed (%d), trying to read anyway\n", err);
265 }
266
267 if (sc->state == FWCAM_STATE_DETACHING)
268 return;
269
270 if (fwcam_read_capabilities(sc) == 0) {
271 uint32_t val;
272
273 if (fwcam_read_quadlet(sc, IIDC_CUR_V_FORMAT, &val) == 0)
274 sc->cur_format = (val >> 29) & 0x7;
275 if (fwcam_read_quadlet(sc, IIDC_CUR_V_MODE, &val) == 0)
276 sc->cur_mode = (val >> 29) & 0x7;
277 if (fwcam_read_quadlet(sc, IIDC_CUR_V_FRM_RATE, &val) == 0)
278 sc->cur_framerate = (val >> 29) & 0x7;
279
280 FWCAM_LOCK(sc);
281 if (sc->state == FWCAM_STATE_DETACHING) {
282 FWCAM_UNLOCK(sc);
283 return;
284 }
285 sc->state = FWCAM_STATE_PROBED;
286 FWCAM_UNLOCK(sc);
287
288 if (sc->open_count > 0 &&
289 sc->state != FWCAM_STATE_DETACHING)
290 fwcam_iso_start(sc);
291 }
292 }
293
294 /*
295 * Compute expected frame size for current format/mode.
296 * Format_0 (VGA) modes:
297 * Mode 0: 160x120 YUV444 = 160*120*3 = 57600
298 * Mode 1: 320x240 YUV422 = 320*240*2 = 153600
299 * Mode 2: 640x480 YUV411 = 640*480*3/2 = 460800
300 * Mode 3: 640x480 YUV422 = 640*480*2 = 614400
301 * Mode 4: 640x480 RGB8 = 640*480*3 = 921600
302 * Mode 5: 640x480 Mono8 = 640*480 = 307200
303 */
304 static uint32_t
fwcam_frame_size(struct fwcam_softc * sc)305 fwcam_frame_size(struct fwcam_softc *sc)
306 {
307 static const uint32_t fmt0_sizes[] = {
308 160 * 120 * 3, /* mode 0: YUV444 */
309 320 * 240 * 2, /* mode 1: YUV422 */
310 640 * 480 * 3 / 2, /* mode 2: YUV411 */
311 640 * 480 * 2, /* mode 3: YUV422 */
312 640 * 480 * 3, /* mode 4: RGB8 */
313 640 * 480, /* mode 5: Mono8 */
314 };
315
316 if (sc->cur_format == IIDC_FMT_VGA && sc->cur_mode < nitems(fmt0_sizes))
317 return (fmt0_sizes[sc->cur_mode]);
318
319 /* Default to largest VGA mode */
320 return (FWCAM_MAX_FRAME_SIZE);
321 }
322
323 static int
fwcam_iso_start(struct fwcam_softc * sc)324 fwcam_iso_start(struct fwcam_softc *sc)
325 {
326 struct firewire_comm *fc = sc->fd.fc;
327 struct fw_xferq *xferq;
328 uint32_t val;
329 int dma_ch, err;
330
331 mtx_assert(&sc->mtx, MA_NOTOWNED);
332
333 FWCAM_LOCK(sc);
334 if (sc->dma_ch >= 0 || sc->state == FWCAM_STATE_STREAMING) {
335 FWCAM_UNLOCK(sc);
336 return (0); /* already running or starting */
337 }
338 if (sc->state == FWCAM_STATE_DETACHING) {
339 FWCAM_UNLOCK(sc);
340 return (ENXIO);
341 }
342 FWCAM_UNLOCK(sc);
343
344 dma_ch = fw_open_isodma(fc, 0);
345 if (dma_ch < 0) {
346 device_printf(sc->fd.dev, "no IR DMA channel available\n");
347 return (EBUSY);
348 }
349
350 FWCAM_LOCK(sc);
351 if (sc->dma_ch >= 0) {
352 FWCAM_UNLOCK(sc);
353 fc->ir[dma_ch]->flag &= ~FWXFERQ_OPEN;
354 return (0);
355 }
356 FWCAM_UNLOCK(sc);
357
358 xferq = fc->ir[dma_ch];
359 xferq->flag |= FWXFERQ_EXTBUF | FWXFERQ_HANDLER | FWXFERQ_STREAM;
360
361 sc->iso_channel = (uint8_t)(iso_channel & FWXFERQ_CHTAGMASK);
362 xferq->flag &= ~FWXFERQ_CHTAGMASK;
363 xferq->flag |= sc->iso_channel & FWXFERQ_CHTAGMASK;
364
365 xferq->sc = (caddr_t)sc;
366 xferq->hand = fwcam_iso_input;
367 xferq->bnchunk = FWCAM_ISO_NCHUNK;
368 xferq->bnpacket = 1;
369 xferq->psize = FWCAM_ISO_PKTSIZE;
370 xferq->queued = 0;
371 xferq->buf = NULL;
372
373 xferq->bulkxfer = malloc(sizeof(struct fw_bulkxfer) * xferq->bnchunk,
374 M_FWCAM, M_WAITOK | M_ZERO);
375
376 fw_iso_init_chunks(xferq);
377
378 sc->frame_size = fwcam_frame_size(sc);
379 sc->frame_buf = malloc(sc->frame_size, M_FWCAM, M_WAITOK | M_ZERO);
380 sc->read_buf = malloc(sc->frame_size, M_FWCAM, M_WAITOK | M_ZERO);
381 sc->frame_offset = 0;
382 sc->frame_ready = 0;
383 sc->frame_dropped = 0;
384
385 val = ((uint32_t)sc->iso_channel << IIDC_ISO_CH_SHIFT) |
386 ((uint32_t)sc->iso_speed << IIDC_ISO_SPEED_SHIFT);
387 err = fwcam_write_quadlet(sc, IIDC_ISO_CHANNEL, val);
388 if (err) {
389 device_printf(sc->fd.dev,
390 "failed to set ISO_CHANNEL: %d\n", err);
391 goto fail;
392 }
393
394 err = fwcam_write_quadlet(sc, IIDC_ISO_EN, IIDC_ISO_EN_ON);
395 if (err) {
396 device_printf(sc->fd.dev,
397 "failed to enable ISO: %d\n", err);
398 goto fail;
399 }
400
401 err = fc->irx_enable(fc, dma_ch);
402 if (err) {
403 device_printf(sc->fd.dev,
404 "failed to start IR DMA: %d\n", err);
405 fwcam_write_quadlet(sc, IIDC_ISO_EN, 0);
406 goto fail;
407 }
408
409 FWCAM_LOCK(sc);
410 if (sc->state == FWCAM_STATE_DETACHING) {
411 FWCAM_UNLOCK(sc);
412 fc->irx_disable(fc, dma_ch);
413 fwcam_write_quadlet(sc, IIDC_ISO_EN, 0);
414 err = ENXIO;
415 goto fail;
416 }
417 sc->dma_ch = dma_ch;
418 sc->state = FWCAM_STATE_STREAMING;
419 FWCAM_UNLOCK(sc);
420
421 return (0);
422
423 fail:
424 fw_iso_free_chunks(xferq, M_FWCAM);
425 xferq->flag &= ~(FWXFERQ_MODEMASK | FWXFERQ_OPEN | FWXFERQ_STREAM |
426 FWXFERQ_EXTBUF | FWXFERQ_HANDLER | FWXFERQ_CHTAGMASK);
427 xferq->hand = NULL;
428
429 free(sc->frame_buf, M_FWCAM);
430 free(sc->read_buf, M_FWCAM);
431 sc->frame_buf = NULL;
432 sc->read_buf = NULL;
433 sc->dma_ch = -1;
434
435 return (err);
436 }
437
438 static void
fwcam_iso_stop(struct fwcam_softc * sc)439 fwcam_iso_stop(struct fwcam_softc *sc)
440 {
441 struct firewire_comm *fc = sc->fd.fc;
442 struct fw_xferq *xferq;
443 int dma_ch;
444
445 FWCAM_LOCK(sc);
446 dma_ch = sc->dma_ch;
447 if (dma_ch < 0) {
448 FWCAM_UNLOCK(sc);
449 return;
450 }
451 sc->dma_ch = -1; /* claim ownership of teardown */
452 FWCAM_UNLOCK(sc);
453
454 xferq = fc->ir[dma_ch];
455
456 if (xferq->flag & FWXFERQ_RUNNING)
457 fc->irx_disable(fc, dma_ch);
458
459 if (sc->fwdev != NULL)
460 fwcam_write_quadlet(sc, IIDC_ISO_EN, 0);
461
462 FWCAM_LOCK(sc);
463 fw_iso_wait_inactive_locked(&sc->mtx, &sc->iso_active, "fwcamis");
464 sc->frame_ready = 0;
465 while (sc->read_in_progress)
466 msleep(&sc->read_in_progress, &sc->mtx, PWAIT, "fwcamst", hz);
467 FWCAM_UNLOCK(sc);
468
469 xferq->flag &= ~(FWXFERQ_MODEMASK | FWXFERQ_OPEN | FWXFERQ_STREAM |
470 FWXFERQ_EXTBUF | FWXFERQ_HANDLER | FWXFERQ_CHTAGMASK);
471 xferq->hand = NULL;
472
473 fw_iso_free_chunks(xferq, M_FWCAM);
474
475 free(sc->frame_buf, M_FWCAM);
476 free(sc->read_buf, M_FWCAM);
477 sc->frame_buf = NULL;
478 sc->read_buf = NULL;
479 }
480
481 static void
fwcam_iso_input(struct fw_xferq * xferq)482 fwcam_iso_input(struct fw_xferq *xferq)
483 {
484 struct fwcam_softc *sc = (struct fwcam_softc *)xferq->sc;
485 struct fw_bulkxfer *sxfer;
486 struct fw_pkt *fp;
487 struct mbuf *m;
488 uint8_t *payload;
489 uint32_t plen;
490 uint8_t *tmp;
491 int dma_ch;
492
493 FWCAM_LOCK(sc);
494 dma_ch = sc->dma_ch;
495 if (dma_ch < 0 || sc->frame_buf == NULL) {
496 FWCAM_UNLOCK(sc);
497 return;
498 }
499 sc->iso_active = 1;
500 FWCAM_UNLOCK(sc);
501
502 while ((sxfer = STAILQ_FIRST(&xferq->stvalid)) != NULL) {
503 STAILQ_REMOVE_HEAD(&xferq->stvalid, link);
504
505 m = fw_iso_dequeue(xferq, sxfer, sc->fd.fc);
506 if (m == NULL)
507 continue;
508
509 fp = mtod(m, struct fw_pkt *);
510 plen = fp->mode.stream.len;
511 if (plen == 0) {
512 m_freem(m);
513 continue; /* empty packet (padding) */
514 }
515
516 if (fp->mode.stream.sy == 1) {
517 if (sc->frame_offset > 0) {
518 if (sc->frame_offset == sc->frame_size) {
519 FWCAM_LOCK(sc);
520 if (sc->read_in_progress) {
521 sc->frame_dropped++;
522 } else {
523 if (sc->frame_ready)
524 sc->frame_dropped++;
525 tmp = sc->read_buf;
526 sc->read_buf = sc->frame_buf;
527 sc->frame_buf = tmp;
528 sc->frame_ready = 1;
529 wakeup(sc);
530 selwakeup(&sc->rsel);
531 }
532 FWCAM_UNLOCK(sc);
533 } else {
534 sc->frame_dropped++;
535 }
536 }
537 sc->frame_offset = 0;
538 }
539
540 if (m->m_len < 4) {
541 m_freem(m);
542 continue;
543 }
544 payload = mtod(m, uint8_t *) + 4;
545 if (plen > (uint32_t)(m->m_len - 4))
546 plen = m->m_len - 4;
547
548 if (sc->frame_offset + plen <= sc->frame_size) {
549 memcpy(sc->frame_buf + sc->frame_offset, payload, plen);
550 sc->frame_offset += plen;
551 } else {
552 sc->frame_dropped++;
553 sc->frame_offset = 0;
554 }
555
556 m_freem(m);
557 }
558
559 fw_iso_rearm_done(xferq, sc->fd.fc, &sc->mtx, &sc->iso_active,
560 &sc->dma_ch, dma_ch);
561 }
562
563 static int
fwcam_cdev_open(struct cdev * dev,int oflags,int devtype,struct thread * td)564 fwcam_cdev_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
565 {
566 struct fwcam_softc *sc = dev->si_drv1;
567 int err = 0;
568
569 FWCAM_LOCK(sc);
570 if (sc->state == FWCAM_STATE_DETACHING) {
571 FWCAM_UNLOCK(sc);
572 return (ENXIO);
573 }
574 if (sc->state != FWCAM_STATE_PROBED &&
575 sc->state != FWCAM_STATE_STREAMING) {
576 FWCAM_UNLOCK(sc);
577 return (EAGAIN); /* not yet probed */
578 }
579
580 sc->open_count++;
581 if (sc->open_count == 1 && sc->state == FWCAM_STATE_PROBED) {
582 FWCAM_UNLOCK(sc);
583 err = fwcam_iso_start(sc);
584 if (err) {
585 FWCAM_LOCK(sc);
586 sc->open_count--;
587 FWCAM_UNLOCK(sc);
588 }
589 } else {
590 FWCAM_UNLOCK(sc);
591 }
592 return (err);
593 }
594
595 static int
fwcam_cdev_close(struct cdev * dev,int fflag,int devtype,struct thread * td)596 fwcam_cdev_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
597 {
598 struct fwcam_softc *sc = dev->si_drv1;
599
600 FWCAM_LOCK(sc);
601 sc->open_count--;
602 if (sc->open_count <= 0) {
603 sc->open_count = 0;
604 if (sc->state == FWCAM_STATE_STREAMING) {
605 FWCAM_UNLOCK(sc);
606 fwcam_iso_stop(sc);
607 FWCAM_LOCK(sc);
608 if (sc->state != FWCAM_STATE_DETACHING)
609 sc->state = FWCAM_STATE_PROBED;
610 }
611 }
612 FWCAM_UNLOCK(sc);
613 return (0);
614 }
615
616 static int
fwcam_cdev_read(struct cdev * dev,struct uio * uio,int ioflag)617 fwcam_cdev_read(struct cdev *dev, struct uio *uio, int ioflag)
618 {
619 struct fwcam_softc *sc = dev->si_drv1;
620 int err;
621
622 FWCAM_LOCK(sc);
623 while (!sc->frame_ready) {
624 if (sc->state != FWCAM_STATE_STREAMING) {
625 FWCAM_UNLOCK(sc);
626 return (ENXIO);
627 }
628 if (ioflag & FNONBLOCK) {
629 FWCAM_UNLOCK(sc);
630 return (EAGAIN);
631 }
632 err = msleep(sc, &sc->mtx, PCATCH, "fwcamrd", 5 * hz);
633 if (err) {
634 FWCAM_UNLOCK(sc);
635 return (err);
636 }
637 }
638
639 sc->frame_ready = 0;
640 if (sc->read_buf == NULL) {
641 FWCAM_UNLOCK(sc);
642 return (ENXIO);
643 }
644 sc->read_in_progress = 1;
645 FWCAM_UNLOCK(sc);
646
647 err = uiomove(sc->read_buf,
648 MIN(uio->uio_resid, sc->frame_size), uio);
649
650 FWCAM_LOCK(sc);
651 sc->read_in_progress = 0;
652 wakeup(&sc->read_in_progress);
653 FWCAM_UNLOCK(sc);
654
655 return (err);
656 }
657
658 static int
fwcam_cdev_poll(struct cdev * dev,int events,struct thread * td)659 fwcam_cdev_poll(struct cdev *dev, int events, struct thread *td)
660 {
661 struct fwcam_softc *sc = dev->si_drv1;
662 int revents = 0;
663
664 FWCAM_LOCK(sc);
665 if (events & (POLLIN | POLLRDNORM)) {
666 if (sc->frame_ready)
667 revents |= events & (POLLIN | POLLRDNORM);
668 else
669 selrecord(td, &sc->rsel);
670 }
671 FWCAM_UNLOCK(sc);
672 return (revents);
673 }
674
675 static const uint32_t fwcam_feat_inq[] = {
676 [FWCAM_FEAT_BRIGHTNESS] = IIDC_BRIGHTNESS_INQ,
677 [FWCAM_FEAT_AUTO_EXPOSURE] = IIDC_AUTO_EXPOSURE_INQ,
678 [FWCAM_FEAT_SHARPNESS] = IIDC_SHARPNESS_INQ,
679 [FWCAM_FEAT_WHITE_BALANCE] = IIDC_WHITE_BAL_INQ,
680 [FWCAM_FEAT_HUE] = IIDC_HUE_INQ,
681 [FWCAM_FEAT_SATURATION] = IIDC_SATURATION_INQ,
682 [FWCAM_FEAT_GAMMA] = IIDC_GAMMA_INQ,
683 [FWCAM_FEAT_SHUTTER] = IIDC_SHUTTER_INQ,
684 [FWCAM_FEAT_GAIN] = IIDC_GAIN_INQ,
685 [FWCAM_FEAT_IRIS] = IIDC_IRIS_INQ,
686 [FWCAM_FEAT_FOCUS] = IIDC_FOCUS_INQ,
687 [FWCAM_FEAT_TEMPERATURE] = IIDC_TEMPERATURE_INQ,
688 [FWCAM_FEAT_TRIGGER] = IIDC_TRIGGER_INQ,
689 };
690
691 static const uint32_t fwcam_feat_ctrl[] = {
692 [FWCAM_FEAT_BRIGHTNESS] = IIDC_BRIGHTNESS,
693 [FWCAM_FEAT_AUTO_EXPOSURE] = IIDC_AUTO_EXPOSURE,
694 [FWCAM_FEAT_SHARPNESS] = IIDC_SHARPNESS,
695 [FWCAM_FEAT_WHITE_BALANCE] = IIDC_WHITE_BALANCE,
696 [FWCAM_FEAT_HUE] = IIDC_HUE,
697 [FWCAM_FEAT_SATURATION] = IIDC_SATURATION,
698 [FWCAM_FEAT_GAMMA] = IIDC_GAMMA,
699 [FWCAM_FEAT_SHUTTER] = IIDC_SHUTTER,
700 [FWCAM_FEAT_GAIN] = IIDC_GAIN,
701 [FWCAM_FEAT_IRIS] = IIDC_IRIS,
702 [FWCAM_FEAT_FOCUS] = IIDC_FOCUS,
703 [FWCAM_FEAT_TEMPERATURE] = IIDC_TEMPERATURE,
704 [FWCAM_FEAT_TRIGGER] = IIDC_TRIGGER_MODE,
705 [FWCAM_FEAT_ZOOM] = IIDC_ZOOM,
706 [FWCAM_FEAT_PAN] = IIDC_PAN,
707 [FWCAM_FEAT_TILT] = IIDC_TILT,
708 };
709
710 static int
fwcam_get_feature(struct fwcam_softc * sc,struct fwcam_feature * feat)711 fwcam_get_feature(struct fwcam_softc *sc, struct fwcam_feature *feat)
712 {
713 uint32_t inq, ctrl;
714 int err;
715
716 if (feat->id >= FWCAM_FEAT_MAX)
717 return (EINVAL);
718
719 feat->flags = 0;
720 feat->min = 0;
721 feat->max = 0;
722 if (feat->id < nitems(fwcam_feat_inq) &&
723 fwcam_feat_inq[feat->id] != 0) {
724 err = fwcam_read_quadlet(sc, fwcam_feat_inq[feat->id], &inq);
725 if (err)
726 return (err);
727
728 if (inq & (1 << 31))
729 feat->flags |= FWCAM_FEATF_PRESENT;
730 if (inq & (1 << 28))
731 feat->flags |= FWCAM_FEATF_ONOFF;
732 if (inq & (1 << 27))
733 feat->flags |= FWCAM_FEATF_AUTO;
734 if (inq & (1 << 26))
735 feat->flags |= FWCAM_FEATF_MANUAL;
736 feat->min = (inq >> 12) & 0xfff;
737 feat->max = inq & 0xfff;
738 }
739
740 if (feat->id >= nitems(fwcam_feat_ctrl) ||
741 fwcam_feat_ctrl[feat->id] == 0)
742 return (EINVAL);
743
744 err = fwcam_read_quadlet(sc, fwcam_feat_ctrl[feat->id], &ctrl);
745 if (err)
746 return (err);
747
748 feat->value = ctrl & 0xfff;
749 /* White balance has U/B in bits [20:31] and V/R in bits [8:19] */
750 if (feat->id == FWCAM_FEAT_WHITE_BALANCE)
751 feat->value2 = (ctrl >> 12) & 0xfff;
752 else
753 feat->value2 = 0;
754
755 return (0);
756 }
757
758 static int
fwcam_set_feature(struct fwcam_softc * sc,struct fwcam_feature * feat)759 fwcam_set_feature(struct fwcam_softc *sc, struct fwcam_feature *feat)
760 {
761 uint32_t ctrl, val;
762 int err;
763
764 if (feat->id >= FWCAM_FEAT_MAX)
765 return (EINVAL);
766 if (feat->id >= nitems(fwcam_feat_ctrl) ||
767 fwcam_feat_ctrl[feat->id] == 0)
768 return (EINVAL);
769
770 err = fwcam_read_quadlet(sc, fwcam_feat_ctrl[feat->id], &ctrl);
771 if (err)
772 return (err);
773
774 if (feat->id == FWCAM_FEAT_WHITE_BALANCE) {
775 /* White balance: value=V/R (low 12), value2=U/B (high 12) */
776 val = (ctrl & 0xff000000) |
777 ((feat->value2 & 0xfff) << 12) |
778 (feat->value & 0xfff);
779 } else {
780 /* Preserve upper bits, set new value in lower 12 */
781 val = (ctrl & 0xfffff000) | (feat->value & 0xfff);
782 }
783
784 return (fwcam_write_quadlet(sc, fwcam_feat_ctrl[feat->id], val));
785 }
786
787 static int
fwcam_cdev_ioctl(struct cdev * dev,u_long cmd,caddr_t data,int fflag,struct thread * td)788 fwcam_cdev_ioctl(struct cdev *dev, u_long cmd, caddr_t data,
789 int fflag, struct thread *td)
790 {
791 struct fwcam_softc *sc = dev->si_drv1;
792 struct fwcam_mode *mode;
793 struct fwcam_feature *feat;
794 struct fwcam_info *info;
795 int err;
796
797 if (sc->fwdev == NULL)
798 return (ENXIO);
799
800 switch (cmd) {
801 case FWCAM_GMODE:
802 mode = (struct fwcam_mode *)data;
803 mode->format = sc->cur_format;
804 mode->mode = sc->cur_mode;
805 mode->framerate = sc->cur_framerate;
806 mode->frame_size = sc->frame_size ?
807 sc->frame_size : fwcam_frame_size(sc);
808 return (0);
809
810 case FWCAM_SMODE:
811 {
812 int was_streaming = 0;
813
814 mode = (struct fwcam_mode *)data;
815 if (mode->format > 7 || mode->mode > 7 || mode->framerate > 7)
816 return (EINVAL);
817
818 if (mode->format != IIDC_FMT_VGA)
819 return (EINVAL);
820 if (!(sc->formats & (1 << (31 - mode->format))))
821 return (EINVAL);
822
823 FWCAM_LOCK(sc);
824 if (sc->state == FWCAM_STATE_DETACHING) {
825 FWCAM_UNLOCK(sc);
826 return (ENXIO);
827 }
828 if (sc->state == FWCAM_STATE_STREAMING) {
829 was_streaming = 1;
830 FWCAM_UNLOCK(sc);
831 fwcam_iso_stop(sc);
832 FWCAM_LOCK(sc);
833 if (sc->state != FWCAM_STATE_DETACHING)
834 sc->state = FWCAM_STATE_PROBED;
835 }
836 FWCAM_UNLOCK(sc);
837
838 err = fwcam_write_quadlet(sc, IIDC_CUR_V_FORMAT,
839 (uint32_t)mode->format << 29);
840 if (err == 0)
841 err = fwcam_write_quadlet(sc, IIDC_CUR_V_MODE,
842 (uint32_t)mode->mode << 29);
843 if (err == 0)
844 err = fwcam_write_quadlet(sc, IIDC_CUR_V_FRM_RATE,
845 (uint32_t)mode->framerate << 29);
846
847 if (err == 0) {
848 sc->cur_format = mode->format;
849 sc->cur_mode = mode->mode;
850 sc->cur_framerate = mode->framerate;
851 mode->frame_size = fwcam_frame_size(sc);
852 }
853
854 if (was_streaming)
855 fwcam_iso_start(sc);
856 return (err);
857 }
858
859 case FWCAM_GFEAT:
860 feat = (struct fwcam_feature *)data;
861 return (fwcam_get_feature(sc, feat));
862
863 case FWCAM_SFEAT:
864 feat = (struct fwcam_feature *)data;
865 return (fwcam_set_feature(sc, feat));
866
867 case FWCAM_GINFO:
868 info = (struct fwcam_info *)data;
869 info->formats = sc->formats;
870 info->basic_func = sc->basic_func;
871 info->features_hi = sc->features_hi;
872 info->features_lo = sc->features_lo;
873 info->cur_format = sc->cur_format;
874 info->cur_mode = sc->cur_mode;
875 info->cur_framerate = sc->cur_framerate;
876 info->state = sc->state;
877 info->frame_size = sc->frame_size ?
878 sc->frame_size : fwcam_frame_size(sc);
879 info->frame_dropped = sc->frame_dropped;
880 info->iso_channel = sc->iso_channel;
881 info->_pad[0] = info->_pad[1] = info->_pad[2] = 0;
882 return (0);
883
884 default:
885 return (ENOTTY);
886 }
887 }
888
889 static void
fwcam_post_explore(void * arg)890 fwcam_post_explore(void *arg)
891 {
892 struct fwcam_softc *sc = (struct fwcam_softc *)arg;
893 struct fw_device *fwdev;
894 uint32_t cmd_base;
895 int was_streaming, err;
896
897 FWCAM_LOCK(sc);
898
899 if (sc->state == FWCAM_STATE_DETACHING) {
900 FWCAM_UNLOCK(sc);
901 return;
902 }
903
904 if (sc->fwdev != NULL) {
905 STAILQ_FOREACH(fwdev, &sc->fd.fc->devices, link) {
906 if (fwdev == sc->fwdev &&
907 fwdev->status == FWDEVATTACHED)
908 break;
909 }
910 if (fwdev == NULL) {
911 was_streaming = (sc->state == FWCAM_STATE_STREAMING);
912 device_printf(sc->fd.dev, "camera disconnected%s\n",
913 was_streaming ? " (was streaming)" : "");
914 sc->fwdev = NULL;
915 sc->state = FWCAM_STATE_IDLE;
916 wakeup(sc); /* unblock readers */
917 selwakeup(&sc->rsel);
918 FWCAM_UNLOCK(sc);
919
920 if (was_streaming)
921 fwcam_iso_stop(sc);
922 FWCAM_LOCK(sc);
923 }
924 }
925
926 if (sc->fwdev == NULL) {
927 STAILQ_FOREACH(fwdev, &sc->fd.fc->devices, link) {
928 if (fwdev->status != FWDEVATTACHED)
929 continue;
930
931 cmd_base = fwcam_find_iidc(fwdev);
932 if (cmd_base == 0)
933 continue;
934
935 sc->fwdev = fwdev;
936 sc->cmd_hi = 0xffff;
937 sc->cmd_lo = 0xf0000000 | (cmd_base << 2);
938
939 FWCAM_UNLOCK(sc);
940 err = taskqueue_enqueue(taskqueue_thread,
941 &sc->probe_task);
942 if (err)
943 device_printf(sc->fd.dev,
944 "taskqueue_enqueue failed: %d\n", err);
945 return;
946 }
947 }
948
949 FWCAM_UNLOCK(sc);
950 }
951
952 static void
fwcam_post_busreset(void * arg __unused)953 fwcam_post_busreset(void *arg __unused)
954 {
955
956 }
957
958 static void
fwcam_identify(driver_t * driver,device_t parent)959 fwcam_identify(driver_t *driver, device_t parent)
960 {
961
962 if (device_find_child(parent, "fwcam", DEVICE_UNIT_ANY) == NULL)
963 BUS_ADD_CHILD(parent, 0, "fwcam", DEVICE_UNIT_ANY);
964 }
965
966 static int
fwcam_probe(device_t dev)967 fwcam_probe(device_t dev)
968 {
969
970 device_set_desc(dev, "IIDC Digital Camera over FireWire");
971 return (0);
972 }
973
974 static int
fwcam_attach(device_t dev)975 fwcam_attach(device_t dev)
976 {
977 struct fwcam_softc *sc;
978
979 sc = device_get_softc(dev);
980 sc->fd.dev = dev;
981 sc->fd.fc = device_get_ivars(dev);
982 mtx_init(&sc->mtx, "fwcam", NULL, MTX_DEF);
983
984 sc->fwdev = NULL;
985 sc->state = FWCAM_STATE_IDLE;
986 sc->dma_ch = -1;
987 sc->iso_active = 0;
988 sc->open_count = 0;
989 knlist_init_mtx(&sc->rsel.si_note, &sc->mtx);
990 TASK_INIT(&sc->probe_task, 0, fwcam_probe_task, sc);
991
992 sc->cdev = make_dev(&fwcam_cdevsw, device_get_unit(dev),
993 UID_ROOT, GID_OPERATOR, 0660, "fwcam%d", device_get_unit(dev));
994 sc->cdev->si_drv1 = sc;
995
996 sc->fd.post_busreset = fwcam_post_busreset;
997 sc->fd.post_explore = fwcam_post_explore;
998
999 fwcam_post_explore(sc);
1000
1001 return (0);
1002 }
1003
1004 static int
fwcam_detach(device_t dev)1005 fwcam_detach(device_t dev)
1006 {
1007 struct fwcam_softc *sc;
1008
1009 sc = device_get_softc(dev);
1010
1011 FWCAM_LOCK(sc);
1012 sc->state = FWCAM_STATE_DETACHING;
1013 wakeup(sc); /* wake any sleeping readers */
1014 FWCAM_UNLOCK(sc);
1015
1016 taskqueue_drain(taskqueue_thread, &sc->probe_task);
1017 fwcam_iso_stop(sc);
1018
1019 if (sc->cdev != NULL)
1020 destroy_dev(sc->cdev);
1021
1022 seldrain(&sc->rsel);
1023 knlist_destroy(&sc->rsel.si_note);
1024
1025 FWCAM_LOCK(sc);
1026 sc->fwdev = NULL;
1027 FWCAM_UNLOCK(sc);
1028
1029 mtx_destroy(&sc->mtx);
1030
1031 return (0);
1032 }
1033
1034 static device_method_t fwcam_methods[] = {
1035 DEVMETHOD(device_identify, fwcam_identify),
1036 DEVMETHOD(device_probe, fwcam_probe),
1037 DEVMETHOD(device_attach, fwcam_attach),
1038 DEVMETHOD(device_detach, fwcam_detach),
1039
1040 DEVMETHOD_END
1041 };
1042
1043 static driver_t fwcam_driver = {
1044 "fwcam",
1045 fwcam_methods,
1046 sizeof(struct fwcam_softc),
1047 };
1048
1049 DRIVER_MODULE(fwcam, firewire, fwcam_driver, 0, 0);
1050 MODULE_VERSION(fwcam, 1);
1051 MODULE_DEPEND(fwcam, firewire, 1, 1, 1);
1052