xref: /freebsd/sys/dev/firewire/fwdv.c (revision 23a6997e3071cea8d8fc5238792fdd0ad5b5dc9a)
1 /*
2  * Copyright (c) 2026 Abdelkader Boudih <freebsd@seuros.com>
3  *
4  * SPDX-License-Identifier: BSD-2-Clause
5  */
6 
7 /*
8  * fwdv(4) - AV/C DV capture driver for FireWire camcorders
9  *
10  * References:
11  *   AV/C General Specification 4.1 (TA Document 2001012)
12  *   IEC 61883-1, IEC 61883-2
13  */
14 
15 #include <sys/param.h>
16 #include <sys/systm.h>
17 #include <sys/module.h>
18 #include <sys/bus.h>
19 #include <sys/kernel.h>
20 #include <sys/conf.h>
21 #include <sys/malloc.h>
22 #include <sys/lock.h>
23 #include <sys/mutex.h>
24 #include <sys/sysctl.h>
25 #include <sys/taskqueue.h>
26 #include <sys/fcntl.h>
27 #include <sys/poll.h>
28 #include <sys/selinfo.h>
29 #include <sys/uio.h>
30 #include <sys/mbuf.h>
31 
32 #include <dev/firewire/firewire.h>
33 #include <dev/firewire/firewirereg.h>
34 #include <dev/firewire/iec13213.h>
35 #include <dev/firewire/iec68113.h>
36 #include <dev/firewire/fwdv.h>
37 #include <dev/firewire/fw_helpers.h>
38 
39 static MALLOC_DEFINE(M_FWDV, "fwdv", "AV/C DV over FireWire");
40 
41 static int debug = 0;
42 static int iso_channel = FWDV_DEFAULT_ISO_CH;
43 SYSCTL_DECL(_hw_firewire);
44 static SYSCTL_NODE(_hw_firewire, OID_AUTO, fwdv, CTLFLAG_RD | CTLFLAG_MPSAFE,
45     0, "AV/C DV");
46 SYSCTL_INT(_hw_firewire_fwdv, OID_AUTO, debug, CTLFLAG_RWTUN, &debug, 0,
47     "fwdv debug level");
48 SYSCTL_INT(_hw_firewire_fwdv, OID_AUTO, iso_channel, CTLFLAG_RWTUN,
49     &iso_channel, 0, "ISO channel for DV receive");
50 
51 #define FWDV_DEBUG(lev, fmt, ...)					\
52 	do {								\
53 		if (debug >= (lev))					\
54 			printf("fwdv: " fmt, ## __VA_ARGS__);		\
55 	} while (0)
56 
57 static void	fwdv_identify(driver_t *, device_t);
58 static int	fwdv_probe(device_t);
59 static int	fwdv_attach(device_t);
60 static int	fwdv_detach(device_t);
61 static void	fwdv_post_busreset(void *);
62 static void	fwdv_post_explore(void *);
63 static void	fwdv_probe_task(void *, int);
64 
65 static int	fwdv_avc_command(struct fwdv_softc *, const uint8_t *, int,
66 		    uint8_t *, int *);
67 static int	fwdv_avc_unit_info(struct fwdv_softc *);
68 static int	fwdv_avc_play(struct fwdv_softc *);
69 static int	fwdv_avc_stop(struct fwdv_softc *);
70 
71 static int	fwdv_read_opcr(struct fwdv_softc *, int, uint32_t *);
72 
73 static int	fwdv_iso_start(struct fwdv_softc *);
74 static void	fwdv_iso_stop(struct fwdv_softc *);
75 static void	fwdv_iso_input(struct fw_xferq *);
76 
77 static void	fwdv_fcp_handler(struct fw_xfer *);
78 
79 static d_open_t		fwdv_cdev_open;
80 static d_close_t	fwdv_cdev_close;
81 static d_read_t		fwdv_cdev_read;
82 static d_poll_t		fwdv_cdev_poll;
83 static d_ioctl_t	fwdv_cdev_ioctl;
84 
85 static struct cdevsw fwdv_cdevsw = {
86 	.d_version =	D_VERSION,
87 	.d_flags =	D_TRACKCLOSE,
88 	.d_open =	fwdv_cdev_open,
89 	.d_close =	fwdv_cdev_close,
90 	.d_read =	fwdv_cdev_read,
91 	.d_poll =	fwdv_cdev_poll,
92 	.d_ioctl =	fwdv_cdev_ioctl,
93 	.d_name =	"fwdv",
94 };
95 
96 static int
97 fwdv_read_quadlet(struct fwdv_softc *sc, uint16_t addr_hi, uint32_t addr_lo,
98     uint32_t *val)
99 {
100 	uint16_t dst;
101 	uint8_t spd;
102 
103 	FWDV_LOCK(sc);
104 	if (sc->fwdev == NULL) {
105 		FWDV_UNLOCK(sc);
106 		return (ENXIO);
107 	}
108 	dst = FWLOCALBUS | sc->fwdev->dst;
109 	spd = min(sc->fwdev->speed, FWSPD_S400);
110 	FWDV_UNLOCK(sc);
111 
112 	return (fw_read_quadlet(sc->fd.fc, M_FWDV, dst, spd,
113 	    addr_hi, addr_lo, val));
114 }
115 
116 static void
117 fwdv_fcp_handler(struct fw_xfer *xfer)
118 {
119 	struct fwdv_softc *sc = (struct fwdv_softc *)xfer->sc;
120 	struct fw_pkt *fp;
121 	uint16_t src_id;
122 	int len;
123 
124 	fp = &xfer->recv.hdr;
125 
126 	if (xfer->resp != 0) {
127 		FWDV_DEBUG(1, "FCP response error: %d\n", xfer->resp);
128 		goto done;
129 	}
130 
131 	len = fp->mode.wreqb.len;
132 	if (len < 4 || len > FCP_MAX_FRAME_LEN) {
133 		FWDV_DEBUG(1, "FCP response bad len: %d\n", len);
134 		goto done;
135 	}
136 
137 	if (xfer->recv.pay_len < 4) {
138 		FWDV_DEBUG(1, "FCP response short payload: %d\n",
139 		    xfer->recv.pay_len);
140 		goto done;
141 	}
142 	if (xfer->recv.pay_len < len)
143 		len = xfer->recv.pay_len;
144 
145 	src_id = fp->mode.wreqb.src;
146 	FWDV_LOCK(sc);
147 	if (sc->fwdev == NULL ||
148 	    (FWLOCALBUS | sc->fwdev->dst) != src_id) {
149 		FWDV_UNLOCK(sc);
150 		FWDV_DEBUG(2, "FCP response from unknown node 0x%04x\n",
151 		    src_id);
152 		goto done;
153 	}
154 
155 	if (xfer->recv.payload != NULL) {
156 		memcpy(sc->fcp_resp, xfer->recv.payload,
157 		    min(len, FCP_MAX_FRAME_LEN));
158 		sc->fcp_resp_len = len;
159 		sc->fcp_resp_ready = 1;
160 		wakeup(&sc->fcp_resp_ready);
161 	}
162 	FWDV_UNLOCK(sc);
163 
164 done:
165 	STAILQ_INSERT_TAIL(&sc->fcp_bind.xferlist, xfer, link);
166 }
167 
168 static int
169 fwdv_avc_command(struct fwdv_softc *sc, const uint8_t *cmd, int cmd_len,
170     uint8_t *resp, int *resp_len)
171 {
172 	struct fw_xfer *xfer;
173 	struct fw_pkt *fp;
174 	uint16_t dst;
175 	uint8_t spd;
176 	int err, padded_len;
177 
178 	FWDV_LOCK(sc);
179 	while (sc->avc_busy) {
180 		if (sc->state == FWDV_STATE_DETACHING) {
181 			FWDV_UNLOCK(sc);
182 			return (ENXIO);
183 		}
184 		msleep(&sc->avc_busy, &sc->mtx, PWAIT, "fwdvavc", hz);
185 	}
186 	sc->avc_busy = 1;
187 
188 	if (sc->fwdev == NULL) {
189 		sc->avc_busy = 0;
190 		wakeup(&sc->avc_busy);
191 		FWDV_UNLOCK(sc);
192 		return (ENXIO);
193 	}
194 	dst = FWLOCALBUS | sc->fwdev->dst;
195 	spd = min(sc->fwdev->speed, FWSPD_S400);
196 	FWDV_UNLOCK(sc);
197 
198 	padded_len = roundup2(cmd_len, 4);
199 
200 	xfer = fw_xfer_alloc_buf(M_FWDV, padded_len, 0);
201 	if (xfer == NULL) {
202 		err = ENOMEM;
203 		goto done;
204 	}
205 
206 	xfer->fc = sc->fd.fc;
207 	xfer->hand = fw_xferwake;
208 
209 	fp = &xfer->send.hdr;
210 	fp->mode.wreqb.tcode = FWTCODE_WREQB;
211 	fp->mode.wreqb.dst = dst;
212 	fp->mode.wreqb.dest_hi = FCP_COMMAND_ADDR >> 32;
213 	fp->mode.wreqb.dest_lo = FCP_COMMAND_ADDR & 0xffffffff;
214 	fp->mode.wreqb.len = padded_len;
215 	fp->mode.wreqb.extcode = 0;
216 	xfer->send.spd = spd;
217 	xfer->send.pay_len = padded_len;
218 
219 	memcpy(xfer->send.payload, cmd, cmd_len);
220 	if (padded_len > cmd_len)
221 		memset((uint8_t *)xfer->send.payload + cmd_len, 0,
222 		    padded_len - cmd_len);
223 
224 	FWDV_LOCK(sc);
225 	sc->fcp_resp_ready = 0;
226 	sc->fcp_resp_len = 0;
227 	FWDV_UNLOCK(sc);
228 
229 	FWDV_DEBUG(2, "AVC cmd: %02x %02x %02x %02x (len=%d)\n",
230 	    cmd[0], cmd[1], cmd_len > 2 ? cmd[2] : 0,
231 	    cmd_len > 3 ? cmd[3] : 0, cmd_len);
232 
233 	err = fw_xfer_request_wait(xfer->fc, xfer, 2 * hz);
234 	if (err != 0) {
235 		fw_xfer_free_buf(xfer);
236 		goto done;
237 	}
238 
239 	if (xfer->resp != 0 ||
240 	    xfer->recv.hdr.mode.wres.rtcode != FWRCODE_COMPLETE) {
241 		FWDV_DEBUG(1, "FCP write failed: resp=%d rtcode=%d\n",
242 		    xfer->resp, xfer->recv.hdr.mode.wres.rtcode);
243 		err = EIO;
244 	}
245 	fw_xfer_free_buf(xfer);
246 	if (err != 0)
247 		goto done;
248 
249 	FWDV_LOCK(sc);
250 	for (int interim_retry = 0; interim_retry < 3; interim_retry++) {
251 		while (!sc->fcp_resp_ready) {
252 			if (sc->state == FWDV_STATE_DETACHING ||
253 			    sc->fwdev == NULL) {
254 				err = ENXIO;
255 				goto done_locked;
256 			}
257 			err = msleep(&sc->fcp_resp_ready, &sc->mtx, PCATCH,
258 			    "fwdvfcp", 3 * hz);
259 			if (err) {
260 				err = (err == EWOULDBLOCK) ? ETIMEDOUT : err;
261 				goto done_locked;
262 			}
263 		}
264 
265 		if (sc->fcp_resp_len >= 1 &&
266 		    (sc->fcp_resp[0] >> 4) == AVC_RESP_INTERIM) {
267 			FWDV_DEBUG(2, "AVC INTERIM, waiting for final\n");
268 			sc->fcp_resp_ready = 0;
269 			if (interim_retry == 2) {
270 				FWDV_DEBUG(1, "AVC INTERIM timeout\n");
271 				err = ETIMEDOUT;
272 				goto done_locked;
273 			}
274 			continue;
275 		}
276 		break;
277 	}
278 
279 	if (resp != NULL && resp_len != NULL) {
280 		int copy_len = min(sc->fcp_resp_len, *resp_len);
281 		memcpy(resp, sc->fcp_resp, copy_len);
282 		*resp_len = copy_len;
283 	}
284 	FWDV_UNLOCK(sc);
285 
286 	FWDV_DEBUG(2, "AVC resp: %02x %02x %02x %02x (len=%d)\n",
287 	    sc->fcp_resp[0], sc->fcp_resp[1],
288 	    sc->fcp_resp_len > 2 ? sc->fcp_resp[2] : 0,
289 	    sc->fcp_resp_len > 3 ? sc->fcp_resp[3] : 0,
290 	    sc->fcp_resp_len);
291 
292 	FWDV_LOCK(sc);
293 	sc->avc_busy = 0;
294 	wakeup(&sc->avc_busy);
295 	FWDV_UNLOCK(sc);
296 
297 	return (0);
298 
299 done_locked:
300 	sc->avc_busy = 0;
301 	wakeup(&sc->avc_busy);
302 	FWDV_UNLOCK(sc);
303 	return (err);
304 
305 done:
306 	FWDV_LOCK(sc);
307 	sc->avc_busy = 0;
308 	wakeup(&sc->avc_busy);
309 	FWDV_UNLOCK(sc);
310 	return (err);
311 }
312 
313 static int
314 fwdv_avc_unit_info(struct fwdv_softc *sc)
315 {
316 	uint8_t cmd[8], resp[8];
317 	int resp_len, err;
318 
319 	cmd[0] = (AVC_CTYPE_STATUS << 4) | 0;
320 	cmd[1] = AVC_ADDR_UNIT;
321 	cmd[2] = AVC_OP_UNIT_INFO;
322 	cmd[3] = 0xff;
323 	cmd[4] = 0xff;
324 	cmd[5] = 0xff;
325 	cmd[6] = 0xff;
326 	cmd[7] = 0xff;
327 
328 	resp_len = sizeof(resp);
329 	err = fwdv_avc_command(sc, cmd, 8, resp, &resp_len);
330 	if (err)
331 		return (err);
332 
333 	if (resp_len < 8) {
334 		device_printf(sc->fd.dev,
335 		    "UNIT INFO: short response (%d bytes)\n", resp_len);
336 		return (EIO);
337 	}
338 	if ((resp[0] >> 4) != AVC_RESP_STABLE) {
339 		device_printf(sc->fd.dev,
340 		    "UNIT INFO: unexpected response 0x%02x\n", resp[0]);
341 		return (EIO);
342 	}
343 
344 	FWDV_DEBUG(1, "UNIT INFO: unit_type=0x%02x, company_id=%02x%02x%02x\n",
345 	    resp[4] >> 3, resp[5], resp[6], resp[7]);
346 
347 	return (0);
348 }
349 
350 static int
351 fwdv_avc_tape_control(struct fwdv_softc *sc, uint8_t opcode, uint8_t operand,
352     const char *name)
353 {
354 	uint8_t cmd[4], resp[4];
355 	int resp_len, err;
356 
357 	cmd[0] = (AVC_CTYPE_CONTROL << 4) | 0;
358 	cmd[1] = AVC_ADDR_TAPE0;
359 	cmd[2] = opcode;
360 	cmd[3] = operand;
361 
362 	resp_len = sizeof(resp);
363 	err = fwdv_avc_command(sc, cmd, 4, resp, &resp_len);
364 	if (err)
365 		return (err);
366 	if (resp_len < 1)
367 		return (EIO);
368 
369 	if ((resp[0] >> 4) != AVC_RESP_ACCEPTED) {
370 		device_printf(sc->fd.dev, "%s rejected: 0x%02x\n",
371 		    name, resp[0]);
372 		return (EIO);
373 	}
374 
375 	FWDV_DEBUG(1, "%s accepted\n", name);
376 	return (0);
377 }
378 
379 static int
380 fwdv_avc_play(struct fwdv_softc *sc)
381 {
382 
383 	return (fwdv_avc_tape_control(sc, AVC_OP_PLAY, AVC_PLAY_FWD, "PLAY"));
384 }
385 
386 static int
387 fwdv_avc_stop(struct fwdv_softc *sc)
388 {
389 
390 	return (fwdv_avc_tape_control(sc, AVC_OP_WIND, AVC_WIND_STOP, "STOP"));
391 }
392 
393 static int
394 fwdv_read_opcr(struct fwdv_softc *sc, int plug, uint32_t *val)
395 {
396 
397 	return (fwdv_read_quadlet(sc, CSR_BASE_HI,
398 	    CSR_BASE_LO | PCR_oPCR(plug), val));
399 }
400 
401 static int
402 fwdv_iso_start(struct fwdv_softc *sc)
403 {
404 	struct firewire_comm *fc = sc->fd.fc;
405 	struct fw_xferq *xferq;
406 	uint32_t opcr_val;
407 	int dma_ch, err;
408 	uint8_t ch;
409 
410 	mtx_assert(&sc->mtx, MA_NOTOWNED);
411 
412 	FWDV_LOCK(sc);
413 	if (sc->dma_ch >= 0 || sc->state == FWDV_STATE_STREAMING) {
414 		FWDV_UNLOCK(sc);
415 		return (0);
416 	}
417 	if (sc->state == FWDV_STATE_DETACHING) {
418 		FWDV_UNLOCK(sc);
419 		return (ENXIO);
420 	}
421 	FWDV_UNLOCK(sc);
422 
423 	ch = (uint8_t)(iso_channel & ISO_CHANNEL_MASK);
424 	err = fwdv_read_opcr(sc, 0, &opcr_val);
425 	if (err == 0 && (opcr_val & OPCR_ONLINE)) {
426 		uint8_t dev_ch = (opcr_val & OPCR_CHANNEL_MASK) >>
427 		    OPCR_CHANNEL_SHIFT;
428 		if (dev_ch < ISO_CHANNEL_MAX) {
429 			ch = dev_ch;
430 			FWDV_DEBUG(1, "oPCR[0] channel=%d\n", ch);
431 		}
432 	}
433 
434 	dma_ch = fw_open_isodma(fc, 0);
435 	if (dma_ch < 0) {
436 		device_printf(sc->fd.dev, "no IR DMA channel available\n");
437 		return (EBUSY);
438 	}
439 
440 	FWDV_LOCK(sc);
441 	if (sc->dma_ch >= 0) {
442 		FWDV_UNLOCK(sc);
443 		fc->ir[dma_ch]->flag &= ~FWXFERQ_OPEN;
444 		return (0);
445 	}
446 	FWDV_UNLOCK(sc);
447 
448 	xferq = fc->ir[dma_ch];
449 	xferq->flag |= FWXFERQ_EXTBUF | FWXFERQ_HANDLER | FWXFERQ_STREAM;
450 	sc->iso_channel = ch;
451 	xferq->flag &= ~FWXFERQ_CHTAGMASK;
452 	xferq->flag |= (ch & ISO_CHANNEL_MASK) | (1 << 6);
453 
454 	xferq->sc = (caddr_t)sc;
455 	xferq->hand = fwdv_iso_input;
456 	xferq->bnchunk = FWDV_ISO_NCHUNK;
457 	xferq->bnpacket = 1;
458 	xferq->psize = FWDV_ISO_PKTSIZE;
459 	xferq->queued = 0;
460 	xferq->buf = NULL;
461 
462 	xferq->bulkxfer = malloc(sizeof(struct fw_bulkxfer) * xferq->bnchunk,
463 	    M_FWDV, M_WAITOK | M_ZERO);
464 
465 	fw_iso_init_chunks(xferq);
466 
467 	sc->frame_size = FWDV_MAX_FRAME_SIZE;
468 	sc->frame_buf = malloc(sc->frame_size, M_FWDV, M_WAITOK | M_ZERO);
469 	sc->read_buf = malloc(sc->frame_size, M_FWDV, M_WAITOK | M_ZERO);
470 	sc->frame_offset = 0;
471 	sc->frame_ready = 0;
472 	sc->frame_dropped = 0;
473 	sc->frame_count = 0;
474 	sc->dv_detected = 0;
475 
476 	err = fc->irx_enable(fc, dma_ch);
477 	if (err) {
478 		device_printf(sc->fd.dev, "failed to start IR DMA: %d\n", err);
479 		goto fail;
480 	}
481 
482 	FWDV_LOCK(sc);
483 	if (sc->state == FWDV_STATE_DETACHING || sc->fwdev == NULL) {
484 		FWDV_UNLOCK(sc);
485 		fc->irx_disable(fc, dma_ch);
486 		err = ENXIO;
487 		goto fail;
488 	}
489 	sc->dma_ch = dma_ch;
490 	sc->state = FWDV_STATE_STREAMING;
491 	wakeup(sc);
492 	FWDV_UNLOCK(sc);
493 
494 	return (0);
495 
496 fail:
497 	fw_iso_free_chunks(xferq, M_FWDV);
498 	xferq->flag &= ~(FWXFERQ_MODEMASK | FWXFERQ_OPEN | FWXFERQ_STREAM |
499 	    FWXFERQ_EXTBUF | FWXFERQ_HANDLER | FWXFERQ_CHTAGMASK);
500 	xferq->hand = NULL;
501 
502 	free(sc->frame_buf, M_FWDV);
503 	free(sc->read_buf, M_FWDV);
504 	sc->frame_buf = NULL;
505 	sc->read_buf = NULL;
506 	sc->dma_ch = -1;
507 
508 	return (err);
509 }
510 
511 static void
512 fwdv_iso_stop(struct fwdv_softc *sc)
513 {
514 	struct firewire_comm *fc = sc->fd.fc;
515 	struct fw_xferq *xferq;
516 	int dma_ch;
517 
518 	FWDV_LOCK(sc);
519 	dma_ch = sc->dma_ch;
520 	if (dma_ch < 0) {
521 		FWDV_UNLOCK(sc);
522 		return;
523 	}
524 	sc->dma_ch = -1;
525 	FWDV_UNLOCK(sc);
526 
527 	xferq = fc->ir[dma_ch];
528 
529 	if (xferq->flag & FWXFERQ_RUNNING)
530 		fc->irx_disable(fc, dma_ch);
531 
532 	FWDV_LOCK(sc);
533 	fw_iso_wait_inactive_locked(&sc->mtx, &sc->iso_active, "fwdvis");
534 	sc->frame_ready = 0;
535 	while (sc->read_in_progress)
536 		msleep(&sc->read_in_progress, &sc->mtx, PWAIT, "fwdvst", hz);
537 	FWDV_UNLOCK(sc);
538 
539 	xferq->flag &= ~(FWXFERQ_MODEMASK | FWXFERQ_OPEN | FWXFERQ_STREAM |
540 	    FWXFERQ_EXTBUF | FWXFERQ_HANDLER | FWXFERQ_CHTAGMASK);
541 	xferq->hand = NULL;
542 
543 	fw_iso_free_chunks(xferq, M_FWDV);
544 
545 	free(sc->frame_buf, M_FWDV);
546 	free(sc->read_buf, M_FWDV);
547 	sc->frame_buf = NULL;
548 	sc->read_buf = NULL;
549 }
550 
551 static void
552 fwdv_iso_input(struct fw_xferq *xferq)
553 {
554 	struct fwdv_softc *sc = (struct fwdv_softc *)xferq->sc;
555 	struct fw_bulkxfer *sxfer;
556 	struct fw_pkt *fp;
557 	struct ciphdr *ciph;
558 	struct dvdbc *dv;
559 	struct mbuf *m;
560 	uint8_t *ptr, *end;
561 	uint32_t plen;
562 	uint8_t *tmp;
563 	int dma_ch;
564 
565 	FWDV_LOCK(sc);
566 	dma_ch = sc->dma_ch;
567 	if (dma_ch < 0 || sc->frame_buf == NULL) {
568 		FWDV_UNLOCK(sc);
569 		return;
570 	}
571 	sc->iso_active = 1;
572 	FWDV_UNLOCK(sc);
573 
574 	while ((sxfer = STAILQ_FIRST(&xferq->stvalid)) != NULL) {
575 		STAILQ_REMOVE_HEAD(&xferq->stvalid, link);
576 
577 		m = fw_iso_dequeue(xferq, sxfer, sc->fd.fc);
578 		if (m == NULL)
579 			continue;
580 
581 		fp = mtod(m, struct fw_pkt *);
582 		plen = fp->mode.stream.len;
583 		if (plen <= sizeof(struct ciphdr)) {
584 			m_freem(m);
585 			continue;
586 		}
587 
588 		if (m->m_len < (int)(4 + sizeof(struct ciphdr))) {
589 			m_freem(m);
590 			continue;
591 		}
592 
593 		ciph = (struct ciphdr *)(mtod(m, uint8_t *) + 4);
594 
595 		if (ciph->fmt != CIP_FMT_DVCR) {
596 			m_freem(m);
597 			continue;
598 		}
599 
600 		if (!sc->dv_detected) {
601 			sc->dv_system = ciph->fdf.dv.fs;
602 			sc->dv_detected = 1;
603 			if (ciph->fdf.dv.stype == CIP_STYPE_HD) {
604 				sc->frame_size = DV_DVCPRO_HD_FRAME;
605 			} else {
606 				sc->frame_size = sc->dv_system ?
607 				    DV_SD_PAL_FRAME : DV_SD_NTSC_FRAME;
608 			}
609 			printf("fwdv: DV stype=%d %s detected (frame=%u)\n",
610 			    ciph->fdf.dv.stype,
611 			    sc->dv_system ? "PAL" : "NTSC",
612 			    sc->frame_size);
613 		}
614 
615 		ptr = (uint8_t *)(ciph + 1);
616 		end = mtod(m, uint8_t *) + 4 + plen;
617 		if (end > mtod(m, uint8_t *) + m->m_len)
618 			end = mtod(m, uint8_t *) + m->m_len;
619 
620 		while (ptr + DV_DIF_BLOCK_SIZE <= end) {
621 			dv = (struct dvdbc *)ptr;
622 
623 			if (dv->sct == DV_SCT_HEADER && dv->dseq == 0) {
624 				if (sc->frame_offset > 0) {
625 					if (sc->frame_offset >= sc->frame_size) {
626 						FWDV_LOCK(sc);
627 						if (sc->read_in_progress) {
628 							sc->frame_dropped++;
629 						} else {
630 							if (sc->frame_ready)
631 								sc->frame_dropped++;
632 							tmp = sc->read_buf;
633 							sc->read_buf =
634 							    sc->frame_buf;
635 							sc->frame_buf = tmp;
636 							sc->frame_ready = 1;
637 							sc->frame_count++;
638 							wakeup(sc);
639 							selwakeup(&sc->rsel);
640 						}
641 						FWDV_UNLOCK(sc);
642 					} else {
643 						sc->frame_dropped++;
644 					}
645 				}
646 				sc->frame_offset = 0;
647 
648 				if (sc->dv_system == 1 &&
649 				    (dv->payload[0] & DV_DSF_12) == 0)
650 					dv->payload[0] |= DV_DSF_12;
651 			}
652 
653 			if (sc->frame_offset + DV_DIF_BLOCK_SIZE <=
654 			    sc->frame_size) {
655 				memcpy(sc->frame_buf + sc->frame_offset,
656 				    ptr, DV_DIF_BLOCK_SIZE);
657 				sc->frame_offset += DV_DIF_BLOCK_SIZE;
658 			} else {
659 				sc->frame_dropped++;
660 				sc->frame_offset = 0;
661 			}
662 
663 			ptr += DV_DIF_BLOCK_SIZE;
664 		}
665 
666 		m_freem(m);
667 	}
668 
669 	fw_iso_rearm_done(xferq, sc->fd.fc, &sc->mtx, &sc->iso_active,
670 	    &sc->dma_ch, dma_ch);
671 }
672 
673 static int
674 fwdv_cdev_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
675 {
676 	struct fwdv_softc *sc = dev->si_drv1;
677 	int err = 0;
678 
679 	FWDV_LOCK(sc);
680 	if (sc->state == FWDV_STATE_DETACHING) {
681 		FWDV_UNLOCK(sc);
682 		return (ENXIO);
683 	}
684 	while (sc->state == FWDV_STATE_STARTING) {
685 		err = msleep(sc, &sc->mtx, PCATCH, "fwdvst", 5 * hz);
686 		if (err) {
687 			FWDV_UNLOCK(sc);
688 			return (err == EWOULDBLOCK ? EAGAIN : err);
689 		}
690 	}
691 	if (sc->state == FWDV_STATE_DETACHING) {
692 		FWDV_UNLOCK(sc);
693 		return (ENXIO);
694 	}
695 	if (sc->state != FWDV_STATE_PROBED &&
696 	    sc->state != FWDV_STATE_STREAMING) {
697 		FWDV_UNLOCK(sc);
698 		return (EAGAIN);
699 	}
700 
701 	sc->open_count++;
702 	if (sc->open_count == 1 && sc->state == FWDV_STATE_PROBED) {
703 		sc->state = FWDV_STATE_STARTING;
704 		FWDV_UNLOCK(sc);
705 		err = fwdv_iso_start(sc);
706 		if (err) {
707 			FWDV_LOCK(sc);
708 			sc->open_count--;
709 			if (sc->state == FWDV_STATE_STARTING) {
710 				sc->state = FWDV_STATE_PROBED;
711 				wakeup(sc);
712 			}
713 			FWDV_UNLOCK(sc);
714 		}
715 	} else {
716 		FWDV_UNLOCK(sc);
717 	}
718 	return (err);
719 }
720 
721 static int
722 fwdv_cdev_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
723 {
724 	struct fwdv_softc *sc = dev->si_drv1;
725 
726 	FWDV_LOCK(sc);
727 	sc->open_count--;
728 	if (sc->open_count <= 0) {
729 		sc->open_count = 0;
730 		if (sc->state == FWDV_STATE_STREAMING) {
731 			FWDV_UNLOCK(sc);
732 			fwdv_iso_stop(sc);
733 			FWDV_LOCK(sc);
734 			if (sc->state != FWDV_STATE_DETACHING)
735 				sc->state = FWDV_STATE_PROBED;
736 		}
737 	}
738 	FWDV_UNLOCK(sc);
739 	return (0);
740 }
741 
742 static int
743 fwdv_cdev_read(struct cdev *dev, struct uio *uio, int ioflag)
744 {
745 	struct fwdv_softc *sc = dev->si_drv1;
746 	int err;
747 
748 	FWDV_LOCK(sc);
749 	while (!sc->frame_ready) {
750 		if (sc->state != FWDV_STATE_STREAMING) {
751 			FWDV_UNLOCK(sc);
752 			return (ENXIO);
753 		}
754 		if (ioflag & FNONBLOCK) {
755 			FWDV_UNLOCK(sc);
756 			return (EAGAIN);
757 		}
758 		err = msleep(sc, &sc->mtx, PCATCH, "fwdvrd", 0);
759 		if (err) {
760 			FWDV_UNLOCK(sc);
761 			return (err);
762 		}
763 	}
764 
765 	sc->read_in_progress = 1;
766 	sc->frame_ready = 0;
767 	FWDV_UNLOCK(sc);
768 
769 	err = uiomove(sc->read_buf, min(uio->uio_resid, sc->frame_size),
770 	    uio);
771 
772 	FWDV_LOCK(sc);
773 	sc->read_in_progress = 0;
774 	wakeup(&sc->read_in_progress);
775 	FWDV_UNLOCK(sc);
776 
777 	return (err);
778 }
779 
780 static int
781 fwdv_cdev_poll(struct cdev *dev, int events, struct thread *td)
782 {
783 	struct fwdv_softc *sc = dev->si_drv1;
784 	int revents = 0;
785 
786 	FWDV_LOCK(sc);
787 	if (sc->state != FWDV_STATE_STREAMING) {
788 		revents = POLLHUP;
789 	} else if (events & (POLLIN | POLLRDNORM)) {
790 		if (sc->frame_ready)
791 			revents |= events & (POLLIN | POLLRDNORM);
792 		else
793 			selrecord(td, &sc->rsel);
794 	}
795 	FWDV_UNLOCK(sc);
796 
797 	return (revents);
798 }
799 
800 static int
801 fwdv_cdev_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
802     struct thread *td)
803 {
804 	struct fwdv_softc *sc = dev->si_drv1;
805 	struct fwdv_info *info;
806 
807 	switch (cmd) {
808 	case FWDV_GINFO:
809 		info = (struct fwdv_info *)data;
810 		memset(info, 0, sizeof(*info));
811 		FWDV_LOCK(sc);
812 		info->state = sc->state;
813 		info->iso_channel = sc->iso_channel;
814 		info->dv_system = sc->dv_detected ? sc->dv_system : 0xff;
815 		info->frame_size = sc->frame_size;
816 		info->frame_count = sc->frame_count;
817 		info->frame_dropped = sc->frame_dropped;
818 		info->eui_hi = sc->eui_hi;
819 		info->eui_lo = sc->eui_lo;
820 		strlcpy(info->vendor, sc->vendor, sizeof(info->vendor));
821 		strlcpy(info->model, sc->model, sizeof(info->model));
822 		FWDV_UNLOCK(sc);
823 		return (0);
824 
825 	case FWDV_PLAY:
826 		return (fwdv_avc_play(sc));
827 
828 	case FWDV_STOP:
829 		return (fwdv_avc_stop(sc));
830 
831 	case FWDV_FFWD:
832 		return (fwdv_avc_tape_control(sc, AVC_OP_WIND,
833 		    AVC_WIND_FFWD, "FFWD"));
834 
835 	case FWDV_REW:
836 		return (fwdv_avc_tape_control(sc, AVC_OP_WIND,
837 		    AVC_WIND_REW, "REW"));
838 
839 	default:
840 		return (ENOTTY);
841 	}
842 }
843 
844 static void
845 fwdv_parse_identity(struct fwdv_softc *sc)
846 {
847 	struct fw_device *fwdev = sc->fwdev;
848 	struct crom_context cc;
849 
850 	sc->vendor[0] = '\0';
851 	sc->model[0] = '\0';
852 
853 	if (fwdev == NULL)
854 		return;
855 
856 	crom_init_context(&cc, fwdev->csrrom);
857 
858 	crom_search_key(&cc, CSRKEY_VENDOR);
859 	crom_next(&cc);
860 	crom_parse_text(&cc, sc->vendor, sizeof(sc->vendor));
861 
862 	crom_search_key(&cc, CSRKEY_MODEL);
863 	crom_next(&cc);
864 	crom_parse_text(&cc, sc->model, sizeof(sc->model));
865 
866 }
867 
868 static void
869 fwdv_post_explore(void *arg)
870 {
871 	struct fwdv_softc *sc = (struct fwdv_softc *)arg;
872 	struct fw_device *fwdev;
873 	int was_streaming;
874 
875 	FWDV_LOCK(sc);
876 
877 	if (sc->state == FWDV_STATE_DETACHING) {
878 		FWDV_UNLOCK(sc);
879 		return;
880 	}
881 
882 	if (sc->fwdev != NULL) {
883 		STAILQ_FOREACH(fwdev, &sc->fd.fc->devices, link) {
884 			if (fwdev == sc->fwdev &&
885 			    fwdev->status == FWDEVATTACHED)
886 				break;
887 		}
888 		if (fwdev == NULL) {
889 			was_streaming = (sc->state == FWDV_STATE_STREAMING);
890 			device_printf(sc->fd.dev, "AV/C device disconnected%s\n",
891 			    was_streaming ? " (was streaming)" : "");
892 			sc->fwdev = NULL;
893 			sc->state = FWDV_STATE_IDLE;
894 			wakeup(sc);
895 			selwakeup(&sc->rsel);
896 			FWDV_UNLOCK(sc);
897 			if (was_streaming)
898 				fwdv_iso_stop(sc);
899 			FWDV_LOCK(sc);
900 		}
901 	}
902 
903 	if (sc->fwdev == NULL) {
904 		STAILQ_FOREACH(fwdev, &sc->fd.fc->devices, link) {
905 			if (fwdev->status != FWDEVATTACHED)
906 				continue;
907 
908 			if (!crom_has_specver(fwdev->csrrom,
909 			    CSRVAL_1394TA, CSR_PROTAVC))
910 				continue;
911 
912 			sc->fwdev = fwdev;
913 			sc->eui_hi = fwdev->eui.hi;
914 			sc->eui_lo = fwdev->eui.lo;
915 
916 			FWDV_UNLOCK(sc);
917 
918 			if (taskqueue_enqueue(taskqueue_thread,
919 			    &sc->probe_task) != 0) {
920 				device_printf(sc->fd.dev,
921 				    "probe task enqueue failed\n");
922 				FWDV_LOCK(sc);
923 				sc->fwdev = NULL;
924 				FWDV_UNLOCK(sc);
925 			}
926 			return;
927 		}
928 	}
929 
930 	FWDV_UNLOCK(sc);
931 }
932 
933 static void
934 fwdv_probe_task(void *arg, int pending __unused)
935 {
936 	struct fwdv_softc *sc = (struct fwdv_softc *)arg;
937 	int err, restart;
938 
939 	FWDV_LOCK(sc);
940 	if (sc->state == FWDV_STATE_DETACHING || sc->fwdev == NULL) {
941 		FWDV_UNLOCK(sc);
942 		return;
943 	}
944 	FWDV_UNLOCK(sc);
945 
946 	fwdv_parse_identity(sc);
947 	err = fwdv_avc_unit_info(sc);
948 	if (err) {
949 		device_printf(sc->fd.dev,
950 		    "UNIT INFO failed (%d), device may not be ready\n", err);
951 	}
952 
953 	FWDV_LOCK(sc);
954 	if (sc->state == FWDV_STATE_DETACHING || sc->fwdev == NULL) {
955 		FWDV_UNLOCK(sc);
956 		return;
957 	}
958 	sc->state = FWDV_STATE_PROBED;
959 	restart = (sc->open_count > 0);
960 	FWDV_UNLOCK(sc);
961 
962 	if (restart)
963 		fwdv_iso_start(sc);
964 }
965 
966 static void
967 fwdv_post_busreset(void *arg __unused)
968 {
969 
970 }
971 
972 static void
973 fwdv_identify(driver_t *driver, device_t parent)
974 {
975 
976 	if (device_find_child(parent, "fwdv", DEVICE_UNIT_ANY) == NULL)
977 		BUS_ADD_CHILD(parent, 0, "fwdv", DEVICE_UNIT_ANY);
978 }
979 
980 static int
981 fwdv_probe(device_t dev)
982 {
983 
984 	device_set_desc(dev, "AV/C DV Capture over FireWire");
985 	return (0);
986 }
987 
988 static int
989 fwdv_attach(device_t dev)
990 {
991 	struct fwdv_softc *sc;
992 	struct firewire_comm *fc;
993 	int err;
994 
995 	sc = device_get_softc(dev);
996 	sc->fd.dev = dev;
997 	sc->fd.fc = device_get_ivars(dev);
998 	fc = sc->fd.fc;
999 	mtx_init(&sc->mtx, "fwdv", NULL, MTX_DEF);
1000 
1001 	sc->fwdev = NULL;
1002 	sc->state = FWDV_STATE_IDLE;
1003 	sc->dma_ch = -1;
1004 	sc->open_count = 0;
1005 	sc->dv_system = 0;
1006 	sc->dv_detected = 0;
1007 	sc->avc_busy = 0;
1008 	sc->iso_active = 0;
1009 	knlist_init_mtx(&sc->rsel.si_note, &sc->mtx);
1010 	TASK_INIT(&sc->probe_task, 0, fwdv_probe_task, sc);
1011 
1012 	sc->cdev = make_dev(&fwdv_cdevsw, device_get_unit(dev),
1013 	    UID_ROOT, GID_OPERATOR, 0660, "fwdv%d", device_get_unit(dev));
1014 	if (sc->cdev == NULL) {
1015 		device_printf(dev, "make_dev failed\n");
1016 		knlist_destroy(&sc->rsel.si_note);
1017 		mtx_destroy(&sc->mtx);
1018 		return (ENXIO);
1019 	}
1020 	sc->cdev->si_drv1 = sc;
1021 
1022 	STAILQ_INIT(&sc->fcp_bind.xferlist);
1023 	sc->fcp_bind.start = FCP_RESPONSE_ADDR;
1024 	sc->fcp_bind.end = FCP_RESPONSE_ADDR + FCP_MAX_FRAME_LEN - 1;
1025 	sc->fcp_bind.sc = sc;
1026 	if (fw_xferlist_add(&sc->fcp_bind.xferlist, M_FWDV,
1027 	    0, FCP_MAX_FRAME_LEN, FWDV_FCP_XFERS, fc, sc,
1028 	    fwdv_fcp_handler) < FWDV_FCP_XFERS) {
1029 		device_printf(dev, "fw_xferlist_add: allocation failed\n");
1030 		fw_xferlist_remove(&sc->fcp_bind.xferlist);
1031 		destroy_dev(sc->cdev);
1032 		knlist_destroy(&sc->rsel.si_note);
1033 		mtx_destroy(&sc->mtx);
1034 		return (ENOMEM);
1035 	}
1036 
1037 	err = fw_bindadd(fc, &sc->fcp_bind);
1038 	if (err) {
1039 		device_printf(dev, "fw_bindadd failed: %d\n", err);
1040 		fw_xferlist_remove(&sc->fcp_bind.xferlist);
1041 		destroy_dev(sc->cdev);
1042 		knlist_destroy(&sc->rsel.si_note);
1043 		mtx_destroy(&sc->mtx);
1044 		return (err);
1045 	}
1046 
1047 	sc->fd.post_busreset = fwdv_post_busreset;
1048 	sc->fd.post_explore = fwdv_post_explore;
1049 
1050 	fwdv_post_explore(sc);
1051 
1052 	return (0);
1053 }
1054 
1055 static int
1056 fwdv_detach(device_t dev)
1057 {
1058 	struct fwdv_softc *sc;
1059 
1060 	sc = device_get_softc(dev);
1061 
1062 	FWDV_LOCK(sc);
1063 	sc->state = FWDV_STATE_DETACHING;
1064 	wakeup(sc);
1065 	wakeup(&sc->fcp_resp_ready);
1066 	wakeup(&sc->avc_busy);
1067 	FWDV_UNLOCK(sc);
1068 
1069 	taskqueue_drain(taskqueue_thread, &sc->probe_task);
1070 	fwdv_iso_stop(sc);
1071 
1072 	fw_bindremove(sc->fd.fc, &sc->fcp_bind);
1073 	fw_xferlist_remove(&sc->fcp_bind.xferlist);
1074 
1075 	if (sc->cdev != NULL)
1076 		destroy_dev(sc->cdev);
1077 
1078 	seldrain(&sc->rsel);
1079 	knlist_destroy(&sc->rsel.si_note);
1080 	mtx_destroy(&sc->mtx);
1081 
1082 	return (0);
1083 }
1084 
1085 static device_method_t fwdv_methods[] = {
1086 	DEVMETHOD(device_identify,	fwdv_identify),
1087 	DEVMETHOD(device_probe,		fwdv_probe),
1088 	DEVMETHOD(device_attach,	fwdv_attach),
1089 	DEVMETHOD(device_detach,	fwdv_detach),
1090 	DEVMETHOD_END
1091 };
1092 
1093 static driver_t fwdv_driver = {
1094 	"fwdv",
1095 	fwdv_methods,
1096 	sizeof(struct fwdv_softc)
1097 };
1098 
1099 DRIVER_MODULE(fwdv, firewire, fwdv_driver, NULL, NULL);
1100 MODULE_VERSION(fwdv, 1);
1101 MODULE_DEPEND(fwdv, firewire, 1, 1, 1);
1102