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