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