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