1 /* 2 * Copyright (c) 2026 Abdelkader Boudih <freebsd@seuros.com> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7 /* 8 * fwcam(4) - IIDC 1394-based Digital Camera driver 9 * 10 * Implements the IIDC v1.30 specification (TA Document 1999023) for 11 * FireWire digital cameras. 12 */ 13 14 #include <sys/param.h> 15 #include <sys/systm.h> 16 #include <sys/module.h> 17 #include <sys/bus.h> 18 #include <sys/kernel.h> 19 #include <sys/malloc.h> 20 #include <sys/lock.h> 21 #include <sys/mutex.h> 22 #include <sys/sysctl.h> 23 #include <sys/taskqueue.h> 24 #include <sys/mbuf.h> 25 #include <sys/videoio.h> 26 27 #include <dev/firewire/firewire.h> 28 #include <dev/firewire/firewirereg.h> 29 #include <dev/firewire/iec13213.h> 30 #include <dev/firewire/fwcam.h> 31 #include <dev/firewire/fw_helpers.h> 32 33 #include <dev/video/video.h> 34 35 #include "video_if.h" 36 37 static MALLOC_DEFINE(M_FWCAM, "fwcam", "IIDC FireWire Camera"); 38 39 static int debug = 0; 40 static int iso_channel = 0; 41 SYSCTL_DECL(_hw_firewire); 42 static SYSCTL_NODE(_hw_firewire, OID_AUTO, fwcam, CTLFLAG_RD | CTLFLAG_MPSAFE, 43 0, "IIDC Camera"); 44 SYSCTL_INT(_hw_firewire_fwcam, OID_AUTO, debug, CTLFLAG_RWTUN, &debug, 0, 45 "fwcam debug level"); 46 SYSCTL_INT(_hw_firewire_fwcam, OID_AUTO, iso_channel, CTLFLAG_RWTUN, 47 &iso_channel, 0, "ISO channel for isochronous receive (default 0)"); 48 49 #define FWCAM_DEBUG(lev, fmt, ...) \ 50 do { \ 51 if (debug >= (lev)) \ 52 printf("fwcam: " fmt, ## __VA_ARGS__); \ 53 } while (0) 54 55 static int fwcam_probe(device_t); 56 static int fwcam_attach(device_t); 57 static int fwcam_detach(device_t); 58 static void fwcam_probe_task(void *, int); 59 static int fwcam_iso_start(struct fwcam_softc *); 60 static void fwcam_iso_stop(struct fwcam_softc *); 61 static void fwcam_iso_input(struct fw_xferq *); 62 static void fwcam_frame_done(struct fwcam_softc *); 63 64 static int fwcam_hw_open(device_t); 65 static int fwcam_hw_querycap(device_t, struct video_caps *); 66 static int fwcam_hw_enum_format(device_t, uint32_t, struct video_format *); 67 static int fwcam_hw_get_format(device_t, struct video_format *); 68 static int fwcam_hw_try_format(device_t, struct video_format *); 69 static int fwcam_hw_set_format(device_t, const struct video_format *); 70 static int fwcam_hw_enum_framesizes(device_t, struct video_frmsizeenum *); 71 static int fwcam_hw_enum_input(device_t, uint32_t, struct video_input *); 72 static int fwcam_hw_get_input(device_t, uint32_t *); 73 static int fwcam_hw_set_input(device_t, uint32_t); 74 static int fwcam_hw_query_control(device_t, struct video_control_desc *); 75 static int fwcam_hw_get_control(device_t, struct video_control *); 76 static int fwcam_hw_set_control(device_t, const struct video_control *); 77 static int fwcam_hw_start_stream(device_t); 78 static void fwcam_hw_stop_stream(device_t); 79 80 /* 81 * Format_0 (VGA) mode descriptors for V4L2 mapping. 82 */ 83 struct fwcam_v4l2_mode { 84 uint32_t pixelformat; /* V4L2 fourcc */ 85 uint32_t width; 86 uint32_t height; 87 uint32_t bytesperline; 88 uint32_t sizeimage; 89 }; 90 91 static const struct fwcam_v4l2_mode fwcam_fmt0_v4l2[] = { 92 /* mode 0: 160x120 YUV444 (24bpp packed) */ 93 { V4L2_PIX_FMT_YUV444, 160, 120, 160 * 3, 160 * 120 * 3 }, 94 /* mode 1: 320x240 YUV422 (UYVY, 16bpp packed) */ 95 { V4L2_PIX_FMT_UYVY, 320, 240, 320 * 2, 320 * 240 * 2 }, 96 /* mode 2: 640x480 YUV411 (12bpp) */ 97 { V4L2_PIX_FMT_Y41P, 640, 480, 640 * 3 / 2, 640 * 480 * 3 / 2 }, 98 /* mode 3: 640x480 YUV422 (UYVY, 16bpp packed) */ 99 { V4L2_PIX_FMT_UYVY, 640, 480, 640 * 2, 640 * 480 * 2 }, 100 /* mode 4: 640x480 RGB8 (24bpp) */ 101 { V4L2_PIX_FMT_RGB24, 640, 480, 640 * 3, 640 * 480 * 3 }, 102 /* mode 5: 640x480 Mono8 */ 103 { V4L2_PIX_FMT_GREY, 640, 480, 640, 640 * 480 }, 104 /* mode 6: 640x480 Mono16 */ 105 { V4L2_PIX_FMT_Y16, 640, 480, 640 * 2, 640 * 480 * 2 }, 106 }; 107 108 #define FWCAM_FMT0_V4L2_NMODES nitems(fwcam_fmt0_v4l2) 109 110 /* 111 * Search a CSR directory for the IIDC command base register (key 0x40). 112 * The iSight places cmd_base inside a logical_unit_directory nested 113 * within the IIDC unit directory, so we recurse into sub-directories 114 * up to max_depth levels. 115 */ 116 static uint32_t 117 fwcam_search_dir_cmd_base(uint32_t *csrrom, uint32_t dir_qoff, 118 uint32_t rom_quads, int max_depth) 119 { 120 struct csrdirectory *dir; 121 struct csrreg *reg; 122 uint32_t dir_len, sub_qoff, val; 123 int i; 124 125 if (dir_qoff >= rom_quads || max_depth <= 0) 126 return (0); 127 dir = (struct csrdirectory *)&csrrom[dir_qoff]; 128 dir_len = dir->crc_len; 129 if (dir_qoff + 1 + dir_len > rom_quads) 130 return (0); 131 if (!crom_crc_valid((uint32_t *)&dir->entry[0], dir_len, dir->crc)) { 132 if (firewire_debug) 133 printf("fwcam: bad CRC in directory at 0x%x\n", 134 dir_qoff); 135 } 136 137 for (i = 0; i < (int)dir_len; i++) { 138 if (dir_qoff + 1 + i >= rom_quads) 139 break; 140 reg = &dir->entry[i]; 141 if (reg->key == IIDC_CROM_CMD_BASE && reg->val != 0) 142 return (reg->val); 143 if ((reg->key & CSRTYPE_MASK) == CSRTYPE_D) { 144 sub_qoff = dir_qoff + 1 + i + reg->val; 145 val = fwcam_search_dir_cmd_base(csrrom, sub_qoff, 146 rom_quads, max_depth - 1); 147 if (val != 0) 148 return (val); 149 } 150 } 151 return (0); 152 } 153 154 /* 155 * Extract IIDC command base register from the unit directory. 156 * Searches the unit directory and any sub-directories (the iSight 157 * places cmd_base inside a logical_unit_directory). 158 */ 159 static uint32_t 160 fwcam_find_iidc_cmd_base(struct fw_unit *unit) 161 { 162 163 return (fwcam_search_dir_cmd_base(unit->fwdev->csrrom, 164 unit->dir_offset / 4, CSRROMSIZE / 4, 2)); 165 } 166 167 static int 168 fwcam_read_quadlet(struct fwcam_softc *sc, uint32_t offset, uint32_t *val) 169 { 170 uint16_t dst; 171 uint8_t spd; 172 int err; 173 174 FWCAM_LOCK(sc); 175 if (sc->fwdev == NULL) { 176 FWCAM_UNLOCK(sc); 177 return (ENXIO); 178 } 179 dst = FWLOCALBUS | sc->fwdev->dst; 180 spd = min(sc->fwdev->speed, FWSPD_S400); 181 FWCAM_UNLOCK(sc); 182 183 err = fw_read_quadlet(sc->fd.fc, M_FWCAM, dst, spd, 184 sc->cmd_hi, sc->cmd_lo + offset, val); 185 if (err) 186 FWCAM_DEBUG(1, "read_quadlet: offset=0x%x err=%d\n", 187 offset, err); 188 return (err); 189 } 190 191 static int 192 fwcam_write_quadlet(struct fwcam_softc *sc, uint32_t offset, uint32_t val) 193 { 194 uint16_t dst; 195 uint8_t spd; 196 int err; 197 198 FWCAM_LOCK(sc); 199 if (sc->fwdev == NULL) { 200 FWCAM_UNLOCK(sc); 201 return (ENXIO); 202 } 203 dst = FWLOCALBUS | sc->fwdev->dst; 204 spd = min(sc->fwdev->speed, FWSPD_S400); 205 FWCAM_UNLOCK(sc); 206 207 err = fw_write_quadlet(sc->fd.fc, M_FWCAM, dst, spd, 208 sc->cmd_hi, sc->cmd_lo + offset, val); 209 if (err) 210 FWCAM_DEBUG(1, "write_quadlet: offset=0x%x err=%d\n", 211 offset, err); 212 return (err); 213 } 214 215 static int 216 fwcam_read_capabilities(struct fwcam_softc *sc) 217 { 218 int err, f, m; 219 220 err = fwcam_read_quadlet(sc, IIDC_V_FORMAT_INQ, &sc->formats); 221 if (err) { 222 device_printf(sc->fd.dev, 223 "failed to read V_FORMAT_INQ: %d\n", err); 224 return (err); 225 } 226 227 err = fwcam_read_quadlet(sc, IIDC_BASIC_FUNC_INQ, &sc->basic_func); 228 if (err) { 229 device_printf(sc->fd.dev, 230 "failed to read BASIC_FUNC_INQ: %d\n", err); 231 return (err); 232 } 233 234 /* Read mode and rate inquiry registers for each supported format */ 235 for (f = 0; f < 8; f++) { 236 if (!(sc->formats & (1 << (31 - f)))) { 237 sc->modes[f] = 0; 238 continue; 239 } 240 err = fwcam_read_quadlet(sc, IIDC_V_MODE_INQ(f), 241 &sc->modes[f]); 242 if (err) { 243 sc->modes[f] = 0; 244 continue; 245 } 246 for (m = 0; m < 8; m++) { 247 if (!(sc->modes[f] & (1 << (31 - m)))) { 248 sc->rates[f][m] = 0; 249 continue; 250 } 251 err = fwcam_read_quadlet(sc, IIDC_V_RATE_INQ(f, m), 252 &sc->rates[f][m]); 253 if (err) 254 sc->rates[f][m] = 0; 255 } 256 } 257 258 err = fwcam_read_quadlet(sc, IIDC_FEATURE_HI_INQ, &sc->features_hi); 259 if (err) 260 sc->features_hi = 0; 261 262 err = fwcam_read_quadlet(sc, IIDC_FEATURE_LO_INQ, &sc->features_lo); 263 if (err) 264 sc->features_lo = 0; 265 266 return (0); 267 } 268 269 static int 270 fwcam_power_on(struct fwcam_softc *sc) 271 { 272 uint32_t val; 273 int err, retries; 274 275 err = fwcam_read_quadlet(sc, IIDC_BASIC_FUNC_INQ, &val); 276 if (err) { 277 device_printf(sc->fd.dev, 278 "cannot read BASIC_FUNC_INQ: %d\n", err); 279 return (err); 280 } 281 282 if ((val & IIDC_CAM_POWER_CTRL) == 0) { 283 FWCAM_DEBUG(1, "no power control, assuming powered\n"); 284 return (0); 285 } 286 287 err = fwcam_read_quadlet(sc, IIDC_CAMERA_POWER, &val); 288 if (err == 0 && (val & IIDC_POWER_ON)) { 289 FWCAM_DEBUG(1, "camera already powered on\n"); 290 return (0); 291 } 292 293 err = fwcam_write_quadlet(sc, IIDC_CAMERA_POWER, IIDC_POWER_ON); 294 if (err) { 295 device_printf(sc->fd.dev, 296 "failed to write CAMERA_POWER: %d\n", err); 297 return (err); 298 } 299 300 for (retries = 0; retries < 50; retries++) { 301 pause("fwcampw", hz / 10); 302 303 if (sc->state == FWCAM_STATE_DETACHING) 304 return (ENXIO); 305 306 err = fwcam_read_quadlet(sc, IIDC_CAMERA_POWER, &val); 307 if (err) 308 continue; /* read may fail while powering up */ 309 310 if (val & IIDC_POWER_ON) 311 return (0); 312 } 313 314 device_printf(sc->fd.dev, "camera power-on timeout (5s)\n"); 315 return (ETIMEDOUT); 316 } 317 318 static void 319 fwcam_probe_task(void *arg, int pending __unused) 320 { 321 struct fwcam_softc *sc = (struct fwcam_softc *)arg; 322 int err; 323 324 if (sc->state == FWCAM_STATE_DETACHING || sc->fwdev == NULL) 325 return; 326 327 err = fwcam_power_on(sc); 328 if (err) { 329 device_printf(sc->fd.dev, 330 "power-on failed (%d), trying to read anyway\n", err); 331 } 332 333 if (sc->state == FWCAM_STATE_DETACHING) 334 return; 335 336 if (fwcam_read_capabilities(sc) == 0) { 337 uint32_t val; 338 339 if (fwcam_read_quadlet(sc, IIDC_CUR_V_FORMAT, &val) == 0) 340 sc->cur_format = (val >> 29) & 0x7; 341 if (fwcam_read_quadlet(sc, IIDC_CUR_V_MODE, &val) == 0) 342 sc->cur_mode = (val >> 29) & 0x7; 343 if (fwcam_read_quadlet(sc, IIDC_CUR_V_FRM_RATE, &val) == 0) 344 sc->cur_framerate = (val >> 29) & 0x7; 345 346 FWCAM_LOCK(sc); 347 if (sc->state == FWCAM_STATE_DETACHING) { 348 FWCAM_UNLOCK(sc); 349 return; 350 } 351 sc->state = FWCAM_STATE_PROBED; 352 wakeup(sc); 353 FWCAM_UNLOCK(sc); 354 355 if (sc->dma_ch >= 0 && 356 sc->state != FWCAM_STATE_DETACHING) 357 fwcam_iso_start(sc); 358 } else { 359 FWCAM_LOCK(sc); 360 if (sc->state == FWCAM_STATE_PROBING) 361 sc->state = FWCAM_STATE_IDLE; 362 wakeup(sc); 363 FWCAM_UNLOCK(sc); 364 } 365 } 366 367 /* 368 * Compute expected frame size for current format/mode. 369 * Format_0 (VGA) modes: 370 * Mode 0: 160x120 YUV444 = 160*120*3 = 57600 371 * Mode 1: 320x240 YUV422 = 320*240*2 = 153600 372 * Mode 2: 640x480 YUV411 = 640*480*3/2 = 460800 373 * Mode 3: 640x480 YUV422 = 640*480*2 = 614400 374 * Mode 4: 640x480 RGB8 = 640*480*3 = 921600 375 * Mode 5: 640x480 Mono8 = 640*480 = 307200 376 */ 377 static uint32_t 378 fwcam_frame_size(struct fwcam_softc *sc) 379 { 380 381 if (sc->cur_format == IIDC_FMT_VGA && 382 sc->cur_mode < FWCAM_FMT0_V4L2_NMODES) 383 return (fwcam_fmt0_v4l2[sc->cur_mode].sizeimage); 384 385 /* Default to largest VGA mode */ 386 return (FWCAM_MAX_FRAME_SIZE); 387 } 388 389 static int 390 fwcam_iso_start(struct fwcam_softc *sc) 391 { 392 struct firewire_comm *fc = sc->fd.fc; 393 struct fw_xferq *xferq; 394 uint32_t val; 395 int dma_ch, err; 396 397 mtx_assert(&sc->mtx, MA_NOTOWNED); 398 399 FWCAM_LOCK(sc); 400 if (sc->dma_ch >= 0 || sc->state == FWCAM_STATE_STREAMING) { 401 FWCAM_UNLOCK(sc); 402 return (0); /* already running or starting */ 403 } 404 if (sc->state == FWCAM_STATE_DETACHING) { 405 FWCAM_UNLOCK(sc); 406 return (ENXIO); 407 } 408 FWCAM_UNLOCK(sc); 409 410 dma_ch = fw_open_isodma(fc, 0); 411 if (dma_ch < 0) { 412 device_printf(sc->fd.dev, "no IR DMA channel available\n"); 413 return (EBUSY); 414 } 415 416 FWCAM_LOCK(sc); 417 if (sc->dma_ch >= 0) { 418 FWCAM_UNLOCK(sc); 419 fc->ir[dma_ch]->flag &= ~FWXFERQ_OPEN; 420 return (0); 421 } 422 FWCAM_UNLOCK(sc); 423 424 xferq = fc->ir[dma_ch]; 425 xferq->flag |= FWXFERQ_EXTBUF | FWXFERQ_HANDLER | FWXFERQ_STREAM; 426 427 sc->iso_channel = (uint8_t)(iso_channel & FWXFERQ_CHTAGMASK); 428 xferq->flag &= ~FWXFERQ_CHTAGMASK; 429 xferq->flag |= sc->iso_channel & FWXFERQ_CHTAGMASK; 430 431 xferq->sc = (caddr_t)sc; 432 xferq->hand = fwcam_iso_input; 433 xferq->bnchunk = FWCAM_ISO_NCHUNK; 434 xferq->bnpacket = 1; 435 xferq->psize = FWCAM_ISO_PKTSIZE; 436 xferq->queued = 0; 437 xferq->buf = NULL; 438 439 xferq->bulkxfer = malloc(sizeof(struct fw_bulkxfer) * xferq->bnchunk, 440 M_FWCAM, M_WAITOK | M_ZERO); 441 442 fw_iso_init_chunks(xferq); 443 444 sc->frame_size = fwcam_frame_size(sc); 445 sc->frame_buf = malloc(sc->frame_size, M_FWCAM, M_WAITOK | M_ZERO); 446 sc->frame_offset = 0; 447 sc->frame_dropped = 0; 448 449 /* IIDC spec s3.1: set video mode registers before ISO enable */ 450 err = fwcam_write_quadlet(sc, IIDC_CUR_V_FORMAT, 451 (uint32_t)sc->cur_format << IIDC_CUR_V_SHIFT); 452 if (err) { 453 device_printf(sc->fd.dev, 454 "failed to set CUR_V_FORMAT: %d\n", err); 455 goto fail; 456 } 457 err = fwcam_write_quadlet(sc, IIDC_CUR_V_MODE, 458 (uint32_t)sc->cur_mode << IIDC_CUR_V_SHIFT); 459 if (err) { 460 device_printf(sc->fd.dev, 461 "failed to set CUR_V_MODE: %d\n", err); 462 goto fail; 463 } 464 err = fwcam_write_quadlet(sc, IIDC_CUR_V_FRM_RATE, 465 (uint32_t)sc->cur_framerate << IIDC_CUR_V_SHIFT); 466 if (err) { 467 device_printf(sc->fd.dev, 468 "failed to set CUR_V_FRM_RATE: %d\n", err); 469 goto fail; 470 } 471 472 /* Check Vmode_Error_Status - camera rejects ISO_EN on error */ 473 err = fwcam_read_quadlet(sc, IIDC_VMODE_ERR_STATUS, &val); 474 if (err == 0 && (val & IIDC_VMODE_ERROR)) { 475 device_printf(sc->fd.dev, 476 "Vmode_Error_Status set: format=%d mode=%d rate=%d " 477 "speed=%d\n", sc->cur_format, sc->cur_mode, 478 sc->cur_framerate, sc->iso_speed); 479 err = EINVAL; 480 goto fail; 481 } 482 483 val = ((uint32_t)sc->iso_channel << IIDC_ISO_CH_SHIFT) | 484 ((uint32_t)sc->iso_speed << IIDC_ISO_SPEED_SHIFT); 485 err = fwcam_write_quadlet(sc, IIDC_ISO_CHANNEL, val); 486 if (err) { 487 device_printf(sc->fd.dev, 488 "failed to set ISO_CHANNEL: %d\n", err); 489 goto fail; 490 } 491 492 err = fwcam_write_quadlet(sc, IIDC_ISO_EN, IIDC_ISO_EN_ON); 493 if (err == EIO) { 494 /* 495 * Cameras with a lens cover might power down the sensor 496 * when the cover is closed and reject streaming requests. 497 * Try to re-power and retry once before giving up. 498 */ 499 err = fwcam_power_on(sc); 500 if (err == 0) 501 err = fwcam_write_quadlet(sc, IIDC_ISO_EN, 502 IIDC_ISO_EN_ON); 503 if (err) { 504 device_printf(sc->fd.dev, 505 "ISO enable refused (lens cover closed?)\n"); 506 goto fail; 507 } 508 } else if (err) { 509 device_printf(sc->fd.dev, 510 "failed to enable ISO: %d\n", err); 511 goto fail; 512 } 513 514 err = fc->irx_enable(fc, dma_ch); 515 if (err) { 516 device_printf(sc->fd.dev, 517 "failed to start IR DMA: %d\n", err); 518 fwcam_write_quadlet(sc, IIDC_ISO_EN, 0); 519 goto fail; 520 } 521 522 FWCAM_LOCK(sc); 523 if (sc->state == FWCAM_STATE_DETACHING) { 524 FWCAM_UNLOCK(sc); 525 fc->irx_disable(fc, dma_ch); 526 fwcam_write_quadlet(sc, IIDC_ISO_EN, 0); 527 err = ENXIO; 528 goto fail; 529 } 530 sc->dma_ch = dma_ch; 531 sc->state = FWCAM_STATE_STREAMING; 532 FWCAM_UNLOCK(sc); 533 534 return (0); 535 536 fail: 537 fw_iso_free_chunks(xferq, M_FWCAM); 538 xferq->flag &= ~(FWXFERQ_MODEMASK | FWXFERQ_OPEN | FWXFERQ_STREAM | 539 FWXFERQ_EXTBUF | FWXFERQ_HANDLER | FWXFERQ_CHTAGMASK); 540 xferq->hand = NULL; 541 542 free(sc->frame_buf, M_FWCAM); 543 sc->frame_buf = NULL; 544 sc->dma_ch = -1; 545 546 return (err); 547 } 548 549 static void 550 fwcam_iso_stop(struct fwcam_softc *sc) 551 { 552 struct firewire_comm *fc = sc->fd.fc; 553 struct fw_xferq *xferq; 554 int dma_ch; 555 556 FWCAM_LOCK(sc); 557 dma_ch = sc->dma_ch; 558 if (dma_ch < 0) { 559 FWCAM_UNLOCK(sc); 560 return; 561 } 562 sc->dma_ch = -1; /* claim ownership of teardown */ 563 FWCAM_UNLOCK(sc); 564 565 xferq = fc->ir[dma_ch]; 566 567 if (xferq->flag & FWXFERQ_RUNNING) 568 fc->irx_disable(fc, dma_ch); 569 570 if (sc->fwdev != NULL) 571 fwcam_write_quadlet(sc, IIDC_ISO_EN, 0); 572 573 FWCAM_LOCK(sc); 574 fw_iso_wait_inactive_locked(&sc->mtx, &sc->iso_active, "fwcamis"); 575 FWCAM_UNLOCK(sc); 576 577 xferq->flag &= ~(FWXFERQ_MODEMASK | FWXFERQ_OPEN | FWXFERQ_STREAM | 578 FWXFERQ_EXTBUF | FWXFERQ_HANDLER | FWXFERQ_CHTAGMASK); 579 xferq->hand = NULL; 580 581 fw_iso_free_chunks(xferq, M_FWCAM); 582 583 free(sc->frame_buf, M_FWCAM); 584 sc->frame_buf = NULL; 585 } 586 587 static void 588 fwcam_frame_done(struct fwcam_softc *sc) 589 { 590 struct video_buf *vb; 591 592 vb = video_buf_acquire(sc->sc_vd); 593 if (vb == NULL) 594 return; 595 596 if (video_buf_write(vb, 0, sc->frame_buf, sc->frame_offset) != 0) { 597 video_buf_error(vb); 598 return; 599 } 600 video_buf_done(vb, sc->frame_offset, sc->sc_sequence++); 601 } 602 603 static void 604 fwcam_iso_input(struct fw_xferq *xferq) 605 { 606 struct fwcam_softc *sc = (struct fwcam_softc *)xferq->sc; 607 struct fw_bulkxfer *sxfer; 608 struct fw_pkt *fp; 609 struct mbuf *m; 610 uint8_t *payload; 611 uint32_t plen; 612 int dma_ch; 613 614 FWCAM_LOCK(sc); 615 dma_ch = sc->dma_ch; 616 if (dma_ch < 0 || sc->frame_buf == NULL) { 617 FWCAM_UNLOCK(sc); 618 return; 619 } 620 sc->iso_active = 1; 621 FWCAM_UNLOCK(sc); 622 623 while ((sxfer = STAILQ_FIRST(&xferq->stvalid)) != NULL) { 624 STAILQ_REMOVE_HEAD(&xferq->stvalid, link); 625 626 m = fw_iso_dequeue(xferq, sxfer, sc->fd.fc); 627 if (m == NULL) 628 continue; 629 630 fp = mtod(m, struct fw_pkt *); 631 plen = fp->mode.stream.len; 632 if (plen == 0) { 633 m_freem(m); 634 continue; /* empty packet (padding) */ 635 } 636 637 if (fp->mode.stream.sy == 1) { 638 if (sc->frame_offset > 0 && 639 sc->frame_offset == sc->frame_size) { 640 fwcam_frame_done(sc); 641 } else if (sc->frame_offset > 0) { 642 struct video_buf *vb; 643 644 vb = video_buf_acquire(sc->sc_vd); 645 if (vb != NULL) 646 video_buf_error(vb); 647 sc->frame_dropped++; 648 } 649 sc->frame_offset = 0; 650 } 651 652 if (m->m_len < 4) { 653 m_freem(m); 654 continue; 655 } 656 payload = mtod(m, uint8_t *) + 4; 657 if (plen > (uint32_t)(m->m_len - 4)) 658 plen = m->m_len - 4; 659 660 if (sc->frame_offset + plen <= sc->frame_size) { 661 memcpy(sc->frame_buf + sc->frame_offset, payload, plen); 662 sc->frame_offset += plen; 663 } else { 664 struct video_buf *vb; 665 666 vb = video_buf_acquire(sc->sc_vd); 667 if (vb != NULL) 668 video_buf_error(vb); 669 sc->frame_dropped++; 670 sc->frame_offset = 0; 671 } 672 673 m_freem(m); 674 } 675 676 fw_iso_rearm_done(xferq, sc->fd.fc, &sc->mtx, &sc->iso_active, 677 &sc->dma_ch, dma_ch); 678 } 679 680 static const uint32_t fwcam_feat_inq[] = { 681 [FWCAM_FEAT_BRIGHTNESS] = IIDC_BRIGHTNESS_INQ, 682 [FWCAM_FEAT_AUTO_EXPOSURE] = IIDC_AUTO_EXPOSURE_INQ, 683 [FWCAM_FEAT_SHARPNESS] = IIDC_SHARPNESS_INQ, 684 [FWCAM_FEAT_WHITE_BALANCE] = IIDC_WHITE_BAL_INQ, 685 [FWCAM_FEAT_HUE] = IIDC_HUE_INQ, 686 [FWCAM_FEAT_SATURATION] = IIDC_SATURATION_INQ, 687 [FWCAM_FEAT_GAMMA] = IIDC_GAMMA_INQ, 688 [FWCAM_FEAT_SHUTTER] = IIDC_SHUTTER_INQ, 689 [FWCAM_FEAT_GAIN] = IIDC_GAIN_INQ, 690 [FWCAM_FEAT_IRIS] = IIDC_IRIS_INQ, 691 [FWCAM_FEAT_FOCUS] = IIDC_FOCUS_INQ, 692 [FWCAM_FEAT_TEMPERATURE] = IIDC_TEMPERATURE_INQ, 693 [FWCAM_FEAT_TRIGGER] = IIDC_TRIGGER_INQ, 694 }; 695 696 static const uint32_t fwcam_feat_ctrl[] = { 697 [FWCAM_FEAT_BRIGHTNESS] = IIDC_BRIGHTNESS, 698 [FWCAM_FEAT_AUTO_EXPOSURE] = IIDC_AUTO_EXPOSURE, 699 [FWCAM_FEAT_SHARPNESS] = IIDC_SHARPNESS, 700 [FWCAM_FEAT_WHITE_BALANCE] = IIDC_WHITE_BALANCE, 701 [FWCAM_FEAT_HUE] = IIDC_HUE, 702 [FWCAM_FEAT_SATURATION] = IIDC_SATURATION, 703 [FWCAM_FEAT_GAMMA] = IIDC_GAMMA, 704 [FWCAM_FEAT_SHUTTER] = IIDC_SHUTTER, 705 [FWCAM_FEAT_GAIN] = IIDC_GAIN, 706 [FWCAM_FEAT_IRIS] = IIDC_IRIS, 707 [FWCAM_FEAT_FOCUS] = IIDC_FOCUS, 708 [FWCAM_FEAT_TEMPERATURE] = IIDC_TEMPERATURE, 709 [FWCAM_FEAT_TRIGGER] = IIDC_TRIGGER_MODE, 710 [FWCAM_FEAT_ZOOM] = IIDC_ZOOM, 711 [FWCAM_FEAT_PAN] = IIDC_PAN, 712 [FWCAM_FEAT_TILT] = IIDC_TILT, 713 }; 714 715 /* 716 * Map IIDC feature IDs to V4L2 control IDs. 717 */ 718 static const uint32_t fwcam_feat_v4l2[] = { 719 [FWCAM_FEAT_BRIGHTNESS] = V4L2_CID_BRIGHTNESS, 720 [FWCAM_FEAT_AUTO_EXPOSURE] = V4L2_CID_EXPOSURE_AUTO, 721 [FWCAM_FEAT_SHARPNESS] = V4L2_CID_SHARPNESS, 722 [FWCAM_FEAT_WHITE_BALANCE] = V4L2_CID_AUTO_WHITE_BALANCE, 723 [FWCAM_FEAT_HUE] = V4L2_CID_HUE, 724 [FWCAM_FEAT_SATURATION] = V4L2_CID_SATURATION, 725 [FWCAM_FEAT_GAMMA] = V4L2_CID_GAMMA, 726 [FWCAM_FEAT_SHUTTER] = V4L2_CID_EXPOSURE_ABSOLUTE, 727 [FWCAM_FEAT_GAIN] = V4L2_CID_GAIN, 728 [FWCAM_FEAT_FOCUS] = V4L2_CID_FOCUS_ABSOLUTE, 729 }; 730 731 #define FWCAM_V4L2_CTRL_COUNT nitems(fwcam_feat_v4l2) 732 733 /* 734 * Find the IIDC feature ID for a V4L2 control ID. 735 * Returns -1 if not found. 736 */ 737 static int 738 fwcam_find_feat_by_v4l2(uint32_t v4l2_id) 739 { 740 int i; 741 742 for (i = 0; i < (int)FWCAM_V4L2_CTRL_COUNT; i++) { 743 if (fwcam_feat_v4l2[i] == v4l2_id) 744 return (i); 745 } 746 return (-1); 747 } 748 749 static int 750 fwcam_get_feature(struct fwcam_softc *sc, struct fwcam_feature *feat) 751 { 752 uint32_t inq, ctrl; 753 int err; 754 755 if (feat->id >= FWCAM_FEAT_MAX) 756 return (EINVAL); 757 758 feat->flags = 0; 759 feat->min = 0; 760 feat->max = 0; 761 if (feat->id < nitems(fwcam_feat_inq) && 762 fwcam_feat_inq[feat->id] != 0) { 763 err = fwcam_read_quadlet(sc, fwcam_feat_inq[feat->id], &inq); 764 if (err) 765 return (err); 766 767 if (inq & (1 << 31)) 768 feat->flags |= FWCAM_FEATF_PRESENT; 769 if (inq & (1 << 28)) 770 feat->flags |= FWCAM_FEATF_ONOFF; 771 if (inq & (1 << 27)) 772 feat->flags |= FWCAM_FEATF_AUTO; 773 if (inq & (1 << 26)) 774 feat->flags |= FWCAM_FEATF_MANUAL; 775 feat->min = (inq >> 12) & 0xfff; 776 feat->max = inq & 0xfff; 777 } 778 779 if (feat->id >= nitems(fwcam_feat_ctrl) || 780 fwcam_feat_ctrl[feat->id] == 0) 781 return (EINVAL); 782 783 err = fwcam_read_quadlet(sc, fwcam_feat_ctrl[feat->id], &ctrl); 784 if (err) 785 return (err); 786 787 feat->value = ctrl & 0xfff; 788 /* White balance has U/B in bits [20:31] and V/R in bits [8:19] */ 789 if (feat->id == FWCAM_FEAT_WHITE_BALANCE) 790 feat->value2 = (ctrl >> 12) & 0xfff; 791 else 792 feat->value2 = 0; 793 794 return (0); 795 } 796 797 static int 798 fwcam_set_feature(struct fwcam_softc *sc, struct fwcam_feature *feat) 799 { 800 uint32_t ctrl, val; 801 int err; 802 803 if (feat->id >= FWCAM_FEAT_MAX) 804 return (EINVAL); 805 if (feat->id >= nitems(fwcam_feat_ctrl) || 806 fwcam_feat_ctrl[feat->id] == 0) 807 return (EINVAL); 808 809 err = fwcam_read_quadlet(sc, fwcam_feat_ctrl[feat->id], &ctrl); 810 if (err) 811 return (err); 812 813 if (feat->id == FWCAM_FEAT_WHITE_BALANCE) { 814 /* White balance: value=V/R (low 12), value2=U/B (high 12) */ 815 val = (ctrl & 0xff000000) | 816 ((feat->value2 & 0xfff) << 12) | 817 (feat->value & 0xfff); 818 } else { 819 /* Preserve upper bits, set new value in lower 12 */ 820 val = (ctrl & 0xfffff000) | (feat->value & 0xfff); 821 } 822 823 return (fwcam_write_quadlet(sc, fwcam_feat_ctrl[feat->id], val)); 824 } 825 826 /* 827 * Ensure the camera has been probed (powered on, capabilities read). 828 * Called from hw callbacks that need device state. 829 */ 830 static int 831 fwcam_ensure_probed(struct fwcam_softc *sc) 832 { 833 int err; 834 835 FWCAM_LOCK(sc); 836 if (sc->state == FWCAM_STATE_DETACHING) { 837 FWCAM_UNLOCK(sc); 838 return (ENXIO); 839 } 840 841 if (sc->state == FWCAM_STATE_IDLE) { 842 sc->state = FWCAM_STATE_PROBING; 843 FWCAM_UNLOCK(sc); 844 taskqueue_enqueue(taskqueue_thread, &sc->probe_task); 845 FWCAM_LOCK(sc); 846 } 847 848 while (sc->state == FWCAM_STATE_PROBING) { 849 err = msleep(sc, &sc->mtx, PCATCH, "fwcampr", 10 * hz); 850 if (err) { 851 FWCAM_UNLOCK(sc); 852 return (err == EWOULDBLOCK ? ETIMEDOUT : err); 853 } 854 } 855 856 if (sc->state != FWCAM_STATE_PROBED && 857 sc->state != FWCAM_STATE_STREAMING) { 858 FWCAM_UNLOCK(sc); 859 return (ENXIO); 860 } 861 862 FWCAM_UNLOCK(sc); 863 return (0); 864 } 865 866 static int 867 fwcam_hw_open(device_t dev) 868 { 869 struct fwcam_softc *sc = device_get_softc(dev); 870 871 return (fwcam_ensure_probed(sc)); 872 } 873 874 static int 875 fwcam_hw_querycap(device_t dev, struct video_caps *caps) 876 { 877 878 bzero(caps, sizeof(*caps)); 879 strlcpy(caps->driver, "fwcam", sizeof(caps->driver)); 880 strlcpy(caps->card, "IIDC FireWire Camera", sizeof(caps->card)); 881 strlcpy(caps->bus_info, "firewire", sizeof(caps->bus_info)); 882 caps->version = (1 << 16) | (0 << 8) | 0; /* 1.0.0 */ 883 caps->capabilities = VIDEO_CAP_CAPTURE | 884 VIDEO_CAP_READWRITE | VIDEO_CAP_STREAMING; 885 886 return (0); 887 } 888 889 /* 890 * Map a sequential enum index to an IIDC mode number. 891 * Returns -1 if index is out of range. 892 */ 893 static int 894 fwcam_index_to_mode(struct fwcam_softc *sc, uint32_t index) 895 { 896 int m; 897 uint32_t count = 0; 898 899 if (!(sc->formats & IIDC_FORMAT_VGA)) 900 return (-1); 901 902 for (m = 0; m < (int)FWCAM_FMT0_V4L2_NMODES; m++) { 903 if (sc->modes[IIDC_FMT_VGA] & (1 << (31 - m))) { 904 if (count == index) 905 return (m); 906 count++; 907 } 908 } 909 return (-1); 910 } 911 912 static int 913 fwcam_hw_enum_format(device_t dev, uint32_t index, struct video_format *fmt) 914 { 915 struct fwcam_softc *sc = device_get_softc(dev); 916 const struct fwcam_v4l2_mode *vm; 917 int m; 918 919 m = fwcam_index_to_mode(sc, index); 920 if (m < 0) 921 return (EINVAL); 922 923 vm = &fwcam_fmt0_v4l2[m]; 924 925 bzero(fmt, sizeof(*fmt)); 926 fmt->pixelformat = vm->pixelformat; 927 fmt->width = vm->width; 928 fmt->height = vm->height; 929 fmt->bytesperline = vm->bytesperline; 930 fmt->sizeimage = vm->sizeimage; 931 fmt->field = V4L2_FIELD_NONE; 932 933 return (0); 934 } 935 936 static int 937 fwcam_hw_get_format(device_t dev, struct video_format *fmt) 938 { 939 struct fwcam_softc *sc = device_get_softc(dev); 940 const struct fwcam_v4l2_mode *vm; 941 942 if (sc->cur_format != IIDC_FMT_VGA || 943 sc->cur_mode >= FWCAM_FMT0_V4L2_NMODES) 944 return (EIO); 945 946 vm = &fwcam_fmt0_v4l2[sc->cur_mode]; 947 948 bzero(fmt, sizeof(*fmt)); 949 fmt->pixelformat = vm->pixelformat; 950 fmt->width = vm->width; 951 fmt->height = vm->height; 952 fmt->bytesperline = vm->bytesperline; 953 fmt->sizeimage = vm->sizeimage; 954 fmt->field = V4L2_FIELD_NONE; 955 956 return (0); 957 } 958 959 /* 960 * Find the IIDC mode that best matches a V4L2 format request. 961 * Returns -1 if no match. 962 */ 963 static int 964 fwcam_find_mode_for_format(struct fwcam_softc *sc, 965 const struct video_format *fmt) 966 { 967 int m, best = -1; 968 969 if (!(sc->formats & IIDC_FORMAT_VGA)) 970 return (-1); 971 972 for (m = 0; m < (int)FWCAM_FMT0_V4L2_NMODES; m++) { 973 if (!(sc->modes[IIDC_FMT_VGA] & (1 << (31 - m)))) 974 continue; 975 if (fwcam_fmt0_v4l2[m].pixelformat == fmt->pixelformat && 976 fwcam_fmt0_v4l2[m].width == fmt->width && 977 fwcam_fmt0_v4l2[m].height == fmt->height) { 978 best = m; 979 break; 980 } 981 } 982 983 /* If exact match failed, try matching just pixelformat */ 984 if (best < 0) { 985 for (m = 0; m < (int)FWCAM_FMT0_V4L2_NMODES; m++) { 986 if (!(sc->modes[IIDC_FMT_VGA] & (1 << (31 - m)))) 987 continue; 988 if (fwcam_fmt0_v4l2[m].pixelformat == 989 fmt->pixelformat) { 990 best = m; 991 break; 992 } 993 } 994 } 995 996 return (best); 997 } 998 999 static int 1000 fwcam_hw_try_format(device_t dev, struct video_format *fmt) 1001 { 1002 struct fwcam_softc *sc = device_get_softc(dev); 1003 const struct fwcam_v4l2_mode *vm; 1004 int m; 1005 1006 m = fwcam_find_mode_for_format(sc, fmt); 1007 if (m < 0) 1008 return (EINVAL); 1009 1010 vm = &fwcam_fmt0_v4l2[m]; 1011 1012 fmt->pixelformat = vm->pixelformat; 1013 fmt->width = vm->width; 1014 fmt->height = vm->height; 1015 fmt->bytesperline = vm->bytesperline; 1016 fmt->sizeimage = vm->sizeimage; 1017 fmt->field = V4L2_FIELD_NONE; 1018 1019 return (0); 1020 } 1021 1022 static int 1023 fwcam_hw_set_format(device_t dev, const struct video_format *fmt) 1024 { 1025 struct fwcam_softc *sc = device_get_softc(dev); 1026 int m, err; 1027 1028 m = fwcam_find_mode_for_format(sc, fmt); 1029 if (m < 0) 1030 return (EINVAL); 1031 1032 if (!(sc->rates[IIDC_FMT_VGA][m] & 1033 (1 << (31 - sc->cur_framerate)))) { 1034 /* Current framerate not supported in new mode, pick first */ 1035 int r; 1036 for (r = 0; r < 8; r++) { 1037 if (sc->rates[IIDC_FMT_VGA][m] & (1 << (31 - r))) { 1038 sc->cur_framerate = r; 1039 break; 1040 } 1041 } 1042 } 1043 1044 err = fwcam_write_quadlet(sc, IIDC_CUR_V_FORMAT, 1045 (uint32_t)IIDC_FMT_VGA << IIDC_CUR_V_SHIFT); 1046 if (err == 0) 1047 err = fwcam_write_quadlet(sc, IIDC_CUR_V_MODE, 1048 (uint32_t)m << IIDC_CUR_V_SHIFT); 1049 if (err == 0) 1050 err = fwcam_write_quadlet(sc, IIDC_CUR_V_FRM_RATE, 1051 (uint32_t)sc->cur_framerate << IIDC_CUR_V_SHIFT); 1052 1053 if (err == 0) { 1054 sc->cur_format = IIDC_FMT_VGA; 1055 sc->cur_mode = m; 1056 } 1057 1058 return (err); 1059 } 1060 1061 static int 1062 fwcam_hw_enum_framesizes(device_t dev, struct video_frmsizeenum *fse) 1063 { 1064 struct fwcam_softc *sc = device_get_softc(dev); 1065 int m; 1066 uint32_t count = 0; 1067 1068 if (!(sc->formats & IIDC_FORMAT_VGA)) 1069 return (EINVAL); 1070 1071 for (m = 0; m < (int)FWCAM_FMT0_V4L2_NMODES; m++) { 1072 if (!(sc->modes[IIDC_FMT_VGA] & (1 << (31 - m)))) 1073 continue; 1074 if (fwcam_fmt0_v4l2[m].pixelformat != fse->pixelformat) 1075 continue; 1076 if (count == fse->index) { 1077 fse->type = V4L2_FRMSIZE_TYPE_DISCRETE; 1078 fse->discrete.width = fwcam_fmt0_v4l2[m].width; 1079 fse->discrete.height = fwcam_fmt0_v4l2[m].height; 1080 return (0); 1081 } 1082 count++; 1083 } 1084 1085 return (EINVAL); 1086 } 1087 1088 static int 1089 fwcam_hw_enum_input(device_t dev, uint32_t index, struct video_input *inp) 1090 { 1091 1092 if (index != 0) 1093 return (EINVAL); 1094 1095 bzero(inp, sizeof(*inp)); 1096 inp->index = 0; 1097 strlcpy(inp->name, "IIDC Camera", sizeof(inp->name)); 1098 inp->type = VIDEO_INPUT_TYPE_CAMERA; 1099 1100 return (0); 1101 } 1102 1103 static int 1104 fwcam_hw_get_input(device_t dev, uint32_t *index) 1105 { 1106 1107 *index = 0; 1108 return (0); 1109 } 1110 1111 static int 1112 fwcam_hw_set_input(device_t dev, uint32_t index) 1113 { 1114 1115 if (index != 0) 1116 return (EINVAL); 1117 return (0); 1118 } 1119 1120 static int 1121 fwcam_hw_query_control(device_t dev, struct video_control_desc *qc) 1122 { 1123 struct fwcam_softc *sc = device_get_softc(dev); 1124 struct fwcam_feature feat; 1125 int fid; 1126 1127 fid = fwcam_find_feat_by_v4l2(qc->id); 1128 if (fid < 0) 1129 return (EINVAL); 1130 1131 feat.id = fid; 1132 if (fwcam_get_feature(sc, &feat) != 0) 1133 return (EINVAL); 1134 1135 if (!(feat.flags & FWCAM_FEATF_PRESENT)) 1136 return (EINVAL); 1137 1138 qc->type = V4L2_CTRL_TYPE_INTEGER; 1139 strlcpy(qc->name, fwcam_feat_names[fid], sizeof(qc->name)); 1140 qc->minimum = feat.min; 1141 qc->maximum = feat.max; 1142 qc->step = 1; 1143 qc->default_value = feat.min; 1144 qc->flags = 0; 1145 1146 return (0); 1147 } 1148 1149 static int 1150 fwcam_hw_get_control(device_t dev, struct video_control *ctrl) 1151 { 1152 struct fwcam_softc *sc = device_get_softc(dev); 1153 struct fwcam_feature feat; 1154 int fid; 1155 1156 fid = fwcam_find_feat_by_v4l2(ctrl->id); 1157 if (fid < 0) 1158 return (EINVAL); 1159 1160 feat.id = fid; 1161 if (fwcam_get_feature(sc, &feat) != 0) 1162 return (EINVAL); 1163 1164 ctrl->value = feat.value; 1165 return (0); 1166 } 1167 1168 static int 1169 fwcam_hw_set_control(device_t dev, const struct video_control *ctrl) 1170 { 1171 struct fwcam_softc *sc = device_get_softc(dev); 1172 struct fwcam_feature feat; 1173 int fid; 1174 1175 fid = fwcam_find_feat_by_v4l2(ctrl->id); 1176 if (fid < 0) 1177 return (EINVAL); 1178 1179 feat.id = fid; 1180 feat.value = ctrl->value; 1181 feat.value2 = 0; 1182 return (fwcam_set_feature(sc, &feat)); 1183 } 1184 1185 static int 1186 fwcam_hw_start_stream(device_t dev) 1187 { 1188 struct fwcam_softc *sc = device_get_softc(dev); 1189 int err; 1190 1191 err = fwcam_ensure_probed(sc); 1192 if (err) 1193 return (err); 1194 1195 sc->sc_sequence = 0; 1196 1197 return (fwcam_iso_start(sc)); 1198 } 1199 1200 static void 1201 fwcam_hw_stop_stream(device_t dev) 1202 { 1203 struct fwcam_softc *sc = device_get_softc(dev); 1204 1205 fwcam_iso_stop(sc); 1206 1207 FWCAM_LOCK(sc); 1208 if (sc->state != FWCAM_STATE_DETACHING) 1209 sc->state = FWCAM_STATE_PROBED; 1210 FWCAM_UNLOCK(sc); 1211 } 1212 1213 static int 1214 fwcam_probe(device_t dev) 1215 { 1216 struct fw_unit *unit; 1217 1218 unit = fw_get_unit(dev); 1219 if (unit == NULL) 1220 return (ENXIO); 1221 1222 if (unit->spec_id != CSRVAL_1394TA) 1223 return (ENXIO); 1224 if (unit->sw_version != CSR_PROTCAM130 && 1225 unit->sw_version != CSR_PROTCAM120 && 1226 unit->sw_version != CSR_PROTCAM104) 1227 return (ENXIO); 1228 1229 device_set_desc(dev, "IIDC Digital Camera over FireWire"); 1230 return (BUS_PROBE_DEFAULT); 1231 } 1232 1233 static int 1234 fwcam_attach(device_t dev) 1235 { 1236 struct fwcam_softc *sc; 1237 struct fw_unit *unit; 1238 uint32_t cmd_base; 1239 int err; 1240 1241 unit = fw_get_unit(dev); 1242 if (unit == NULL || unit->fwdev == NULL) 1243 return (ENXIO); 1244 1245 cmd_base = fwcam_find_iidc_cmd_base(unit); 1246 if (cmd_base == 0) { 1247 device_printf(dev, "no IIDC command base in unit directory\n"); 1248 return (ENXIO); 1249 } 1250 1251 sc = device_get_softc(dev); 1252 sc->fd.dev = dev; 1253 sc->fd.fc = fw_get_comm(dev); 1254 mtx_init(&sc->mtx, "fwcam", NULL, MTX_DEF); 1255 1256 sc->fwdev = unit->fwdev; 1257 sc->cmd_hi = 0xffff; 1258 sc->cmd_lo = 0xf0000000 | (cmd_base << 2); 1259 sc->iso_speed = min(unit->fwdev->speed, FWSPD_S400); 1260 sc->state = FWCAM_STATE_IDLE; 1261 sc->dma_ch = -1; 1262 sc->iso_active = 0; 1263 sc->sc_sequence = 0; 1264 TASK_INIT(&sc->probe_task, 0, fwcam_probe_task, sc); 1265 1266 err = video_register(dev, &sc->sc_vd); 1267 if (err != 0) { 1268 device_printf(dev, "failed to register video device\n"); 1269 mtx_destroy(&sc->mtx); 1270 return (err); 1271 } 1272 1273 return (0); 1274 } 1275 1276 static int 1277 fwcam_detach(device_t dev) 1278 { 1279 struct fwcam_softc *sc; 1280 1281 sc = device_get_softc(dev); 1282 1283 if (sc->sc_vd != NULL) 1284 video_unregister(sc->sc_vd); 1285 1286 FWCAM_LOCK(sc); 1287 sc->state = FWCAM_STATE_DETACHING; 1288 wakeup(sc); 1289 FWCAM_UNLOCK(sc); 1290 1291 taskqueue_drain(taskqueue_thread, &sc->probe_task); 1292 fwcam_iso_stop(sc); 1293 1294 FWCAM_LOCK(sc); 1295 sc->fwdev = NULL; 1296 FWCAM_UNLOCK(sc); 1297 1298 mtx_destroy(&sc->mtx); 1299 1300 return (0); 1301 } 1302 1303 static device_method_t fwcam_methods[] = { 1304 DEVMETHOD(device_probe, fwcam_probe), 1305 DEVMETHOD(device_attach, fwcam_attach), 1306 DEVMETHOD(device_detach, fwcam_detach), 1307 1308 /* video(4) interface */ 1309 DEVMETHOD(video_open, fwcam_hw_open), 1310 DEVMETHOD(video_querycap, fwcam_hw_querycap), 1311 DEVMETHOD(video_enum_format, fwcam_hw_enum_format), 1312 DEVMETHOD(video_get_format, fwcam_hw_get_format), 1313 DEVMETHOD(video_try_format, fwcam_hw_try_format), 1314 DEVMETHOD(video_set_format, fwcam_hw_set_format), 1315 DEVMETHOD(video_enum_framesizes, fwcam_hw_enum_framesizes), 1316 DEVMETHOD(video_enum_input, fwcam_hw_enum_input), 1317 DEVMETHOD(video_get_input, fwcam_hw_get_input), 1318 DEVMETHOD(video_set_input, fwcam_hw_set_input), 1319 DEVMETHOD(video_query_control, fwcam_hw_query_control), 1320 DEVMETHOD(video_get_control, fwcam_hw_get_control), 1321 DEVMETHOD(video_set_control, fwcam_hw_set_control), 1322 DEVMETHOD(video_start_stream, fwcam_hw_start_stream), 1323 DEVMETHOD(video_stop_stream, fwcam_hw_stop_stream), 1324 1325 DEVMETHOD_END 1326 }; 1327 1328 static driver_t fwcam_driver = { 1329 "fwcam", 1330 fwcam_methods, 1331 sizeof(struct fwcam_softc), 1332 }; 1333 1334 DRIVER_MODULE(fwcam, firewire, fwcam_driver, 0, 0); 1335 MODULE_VERSION(fwcam, 1); 1336 MODULE_DEPEND(fwcam, firewire, 1, 1, 1); 1337 MODULE_DEPEND(fwcam, video, 1, 1, 1); 1338