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 if (xferq->flag & FWXFERQ_RUNNING) 538 fc->irx_disable(fc, dma_ch); 539 540 fw_iso_free_chunks(xferq, M_FWCAM); 541 xferq->flag &= ~(FWXFERQ_MODEMASK | FWXFERQ_OPEN | FWXFERQ_STREAM | 542 FWXFERQ_EXTBUF | FWXFERQ_HANDLER | FWXFERQ_CHTAGMASK); 543 xferq->hand = NULL; 544 545 free(sc->frame_buf, M_FWCAM); 546 sc->frame_buf = NULL; 547 sc->dma_ch = -1; 548 549 return (err); 550 } 551 552 static void 553 fwcam_iso_stop(struct fwcam_softc *sc) 554 { 555 struct firewire_comm *fc = sc->fd.fc; 556 struct fw_xferq *xferq; 557 int dma_ch; 558 559 FWCAM_LOCK(sc); 560 dma_ch = sc->dma_ch; 561 if (dma_ch < 0) { 562 FWCAM_UNLOCK(sc); 563 return; 564 } 565 sc->dma_ch = -1; /* claim ownership of teardown */ 566 FWCAM_UNLOCK(sc); 567 568 xferq = fc->ir[dma_ch]; 569 570 if (xferq->flag & FWXFERQ_RUNNING) 571 fc->irx_disable(fc, dma_ch); 572 573 if (sc->fwdev != NULL) 574 fwcam_write_quadlet(sc, IIDC_ISO_EN, 0); 575 576 FWCAM_LOCK(sc); 577 fw_iso_wait_inactive_locked(&sc->mtx, &sc->iso_active, "fwcamis"); 578 FWCAM_UNLOCK(sc); 579 580 xferq->flag &= ~(FWXFERQ_MODEMASK | FWXFERQ_OPEN | FWXFERQ_STREAM | 581 FWXFERQ_EXTBUF | FWXFERQ_HANDLER | FWXFERQ_CHTAGMASK); 582 xferq->hand = NULL; 583 584 fw_iso_free_chunks(xferq, M_FWCAM); 585 586 free(sc->frame_buf, M_FWCAM); 587 sc->frame_buf = NULL; 588 } 589 590 static void 591 fwcam_frame_done(struct fwcam_softc *sc) 592 { 593 struct video_buf *vb; 594 595 vb = video_buf_acquire(sc->sc_vd); 596 if (vb == NULL) 597 return; 598 599 if (video_buf_write(vb, 0, sc->frame_buf, sc->frame_offset) != 0) { 600 video_buf_error(vb); 601 return; 602 } 603 video_buf_done(vb, sc->frame_offset, sc->sc_sequence++); 604 } 605 606 static void 607 fwcam_iso_input(struct fw_xferq *xferq) 608 { 609 struct fwcam_softc *sc = (struct fwcam_softc *)xferq->sc; 610 struct fw_bulkxfer *sxfer; 611 struct fw_pkt *fp; 612 struct mbuf *m; 613 uint8_t *payload; 614 uint32_t plen; 615 int dma_ch; 616 617 FWCAM_LOCK(sc); 618 dma_ch = sc->dma_ch; 619 if (dma_ch < 0 || sc->frame_buf == NULL) { 620 FWCAM_UNLOCK(sc); 621 return; 622 } 623 sc->iso_active = 1; 624 FWCAM_UNLOCK(sc); 625 626 while ((sxfer = STAILQ_FIRST(&xferq->stvalid)) != NULL) { 627 STAILQ_REMOVE_HEAD(&xferq->stvalid, link); 628 629 m = fw_iso_dequeue(xferq, sxfer, sc->fd.fc); 630 if (m == NULL) 631 continue; 632 633 fp = mtod(m, struct fw_pkt *); 634 plen = fp->mode.stream.len; 635 if (plen == 0) { 636 m_freem(m); 637 continue; /* empty packet (padding) */ 638 } 639 640 if (fp->mode.stream.sy == 1) { 641 if (sc->frame_offset > 0 && 642 sc->frame_offset == sc->frame_size) { 643 fwcam_frame_done(sc); 644 } else if (sc->frame_offset > 0) { 645 struct video_buf *vb; 646 647 vb = video_buf_acquire(sc->sc_vd); 648 if (vb != NULL) 649 video_buf_error(vb); 650 sc->frame_dropped++; 651 } 652 sc->frame_offset = 0; 653 } 654 655 if (m->m_len < 4) { 656 m_freem(m); 657 continue; 658 } 659 payload = mtod(m, uint8_t *) + 4; 660 if (plen > (uint32_t)(m->m_len - 4)) 661 plen = m->m_len - 4; 662 663 if (sc->frame_offset + plen <= sc->frame_size) { 664 memcpy(sc->frame_buf + sc->frame_offset, payload, plen); 665 sc->frame_offset += plen; 666 } else { 667 struct video_buf *vb; 668 669 vb = video_buf_acquire(sc->sc_vd); 670 if (vb != NULL) 671 video_buf_error(vb); 672 sc->frame_dropped++; 673 sc->frame_offset = 0; 674 } 675 676 m_freem(m); 677 } 678 679 fw_iso_rearm_done(xferq, sc->fd.fc, &sc->mtx, &sc->iso_active, 680 &sc->dma_ch, dma_ch); 681 } 682 683 static const uint32_t fwcam_feat_inq[] = { 684 [FWCAM_FEAT_BRIGHTNESS] = IIDC_BRIGHTNESS_INQ, 685 [FWCAM_FEAT_AUTO_EXPOSURE] = IIDC_AUTO_EXPOSURE_INQ, 686 [FWCAM_FEAT_SHARPNESS] = IIDC_SHARPNESS_INQ, 687 [FWCAM_FEAT_WHITE_BALANCE] = IIDC_WHITE_BAL_INQ, 688 [FWCAM_FEAT_HUE] = IIDC_HUE_INQ, 689 [FWCAM_FEAT_SATURATION] = IIDC_SATURATION_INQ, 690 [FWCAM_FEAT_GAMMA] = IIDC_GAMMA_INQ, 691 [FWCAM_FEAT_SHUTTER] = IIDC_SHUTTER_INQ, 692 [FWCAM_FEAT_GAIN] = IIDC_GAIN_INQ, 693 [FWCAM_FEAT_IRIS] = IIDC_IRIS_INQ, 694 [FWCAM_FEAT_FOCUS] = IIDC_FOCUS_INQ, 695 [FWCAM_FEAT_TEMPERATURE] = IIDC_TEMPERATURE_INQ, 696 [FWCAM_FEAT_TRIGGER] = IIDC_TRIGGER_INQ, 697 }; 698 699 static const uint32_t fwcam_feat_ctrl[] = { 700 [FWCAM_FEAT_BRIGHTNESS] = IIDC_BRIGHTNESS, 701 [FWCAM_FEAT_AUTO_EXPOSURE] = IIDC_AUTO_EXPOSURE, 702 [FWCAM_FEAT_SHARPNESS] = IIDC_SHARPNESS, 703 [FWCAM_FEAT_WHITE_BALANCE] = IIDC_WHITE_BALANCE, 704 [FWCAM_FEAT_HUE] = IIDC_HUE, 705 [FWCAM_FEAT_SATURATION] = IIDC_SATURATION, 706 [FWCAM_FEAT_GAMMA] = IIDC_GAMMA, 707 [FWCAM_FEAT_SHUTTER] = IIDC_SHUTTER, 708 [FWCAM_FEAT_GAIN] = IIDC_GAIN, 709 [FWCAM_FEAT_IRIS] = IIDC_IRIS, 710 [FWCAM_FEAT_FOCUS] = IIDC_FOCUS, 711 [FWCAM_FEAT_TEMPERATURE] = IIDC_TEMPERATURE, 712 [FWCAM_FEAT_TRIGGER] = IIDC_TRIGGER_MODE, 713 [FWCAM_FEAT_ZOOM] = IIDC_ZOOM, 714 [FWCAM_FEAT_PAN] = IIDC_PAN, 715 [FWCAM_FEAT_TILT] = IIDC_TILT, 716 }; 717 718 /* 719 * Map IIDC feature IDs to V4L2 control IDs. 720 */ 721 static const uint32_t fwcam_feat_v4l2[] = { 722 [FWCAM_FEAT_BRIGHTNESS] = V4L2_CID_BRIGHTNESS, 723 [FWCAM_FEAT_AUTO_EXPOSURE] = V4L2_CID_EXPOSURE_AUTO, 724 [FWCAM_FEAT_SHARPNESS] = V4L2_CID_SHARPNESS, 725 [FWCAM_FEAT_WHITE_BALANCE] = V4L2_CID_AUTO_WHITE_BALANCE, 726 [FWCAM_FEAT_HUE] = V4L2_CID_HUE, 727 [FWCAM_FEAT_SATURATION] = V4L2_CID_SATURATION, 728 [FWCAM_FEAT_GAMMA] = V4L2_CID_GAMMA, 729 [FWCAM_FEAT_SHUTTER] = V4L2_CID_EXPOSURE_ABSOLUTE, 730 [FWCAM_FEAT_GAIN] = V4L2_CID_GAIN, 731 [FWCAM_FEAT_FOCUS] = V4L2_CID_FOCUS_ABSOLUTE, 732 }; 733 734 #define FWCAM_V4L2_CTRL_COUNT nitems(fwcam_feat_v4l2) 735 736 /* 737 * Find the IIDC feature ID for a V4L2 control ID. 738 * Returns -1 if not found. 739 */ 740 static int 741 fwcam_find_feat_by_v4l2(uint32_t v4l2_id) 742 { 743 int i; 744 745 for (i = 0; i < (int)FWCAM_V4L2_CTRL_COUNT; i++) { 746 if (fwcam_feat_v4l2[i] == v4l2_id) 747 return (i); 748 } 749 return (-1); 750 } 751 752 static int 753 fwcam_get_feature(struct fwcam_softc *sc, struct fwcam_feature *feat) 754 { 755 uint32_t inq, ctrl; 756 int err; 757 758 if (feat->id >= FWCAM_FEAT_MAX) 759 return (EINVAL); 760 761 feat->flags = 0; 762 feat->min = 0; 763 feat->max = 0; 764 if (feat->id < nitems(fwcam_feat_inq) && 765 fwcam_feat_inq[feat->id] != 0) { 766 err = fwcam_read_quadlet(sc, fwcam_feat_inq[feat->id], &inq); 767 if (err) 768 return (err); 769 770 if (inq & (1 << 31)) 771 feat->flags |= FWCAM_FEATF_PRESENT; 772 if (inq & (1 << 28)) 773 feat->flags |= FWCAM_FEATF_ONOFF; 774 if (inq & (1 << 27)) 775 feat->flags |= FWCAM_FEATF_AUTO; 776 if (inq & (1 << 26)) 777 feat->flags |= FWCAM_FEATF_MANUAL; 778 feat->min = (inq >> 12) & 0xfff; 779 feat->max = inq & 0xfff; 780 } 781 782 if (feat->id >= nitems(fwcam_feat_ctrl) || 783 fwcam_feat_ctrl[feat->id] == 0) 784 return (EINVAL); 785 786 err = fwcam_read_quadlet(sc, fwcam_feat_ctrl[feat->id], &ctrl); 787 if (err) 788 return (err); 789 790 feat->value = ctrl & 0xfff; 791 /* White balance has U/B in bits [20:31] and V/R in bits [8:19] */ 792 if (feat->id == FWCAM_FEAT_WHITE_BALANCE) 793 feat->value2 = (ctrl >> 12) & 0xfff; 794 else 795 feat->value2 = 0; 796 797 return (0); 798 } 799 800 static int 801 fwcam_set_feature(struct fwcam_softc *sc, struct fwcam_feature *feat) 802 { 803 uint32_t ctrl, val; 804 int err; 805 806 if (feat->id >= FWCAM_FEAT_MAX) 807 return (EINVAL); 808 if (feat->id >= nitems(fwcam_feat_ctrl) || 809 fwcam_feat_ctrl[feat->id] == 0) 810 return (EINVAL); 811 812 err = fwcam_read_quadlet(sc, fwcam_feat_ctrl[feat->id], &ctrl); 813 if (err) 814 return (err); 815 816 if (feat->id == FWCAM_FEAT_WHITE_BALANCE) { 817 /* White balance: value=V/R (low 12), value2=U/B (high 12) */ 818 val = (ctrl & 0xff000000) | 819 ((feat->value2 & 0xfff) << 12) | 820 (feat->value & 0xfff); 821 } else { 822 /* Preserve upper bits, set new value in lower 12 */ 823 val = (ctrl & 0xfffff000) | (feat->value & 0xfff); 824 } 825 826 return (fwcam_write_quadlet(sc, fwcam_feat_ctrl[feat->id], val)); 827 } 828 829 /* 830 * Ensure the camera has been probed (powered on, capabilities read). 831 * Called from hw callbacks that need device state. 832 */ 833 static int 834 fwcam_ensure_probed(struct fwcam_softc *sc) 835 { 836 int err; 837 838 FWCAM_LOCK(sc); 839 if (sc->state == FWCAM_STATE_DETACHING) { 840 FWCAM_UNLOCK(sc); 841 return (ENXIO); 842 } 843 844 if (sc->state == FWCAM_STATE_IDLE) { 845 sc->state = FWCAM_STATE_PROBING; 846 FWCAM_UNLOCK(sc); 847 taskqueue_enqueue(taskqueue_thread, &sc->probe_task); 848 FWCAM_LOCK(sc); 849 } 850 851 while (sc->state == FWCAM_STATE_PROBING) { 852 err = msleep(sc, &sc->mtx, PCATCH, "fwcampr", 10 * hz); 853 if (err) { 854 FWCAM_UNLOCK(sc); 855 return (err == EWOULDBLOCK ? ETIMEDOUT : err); 856 } 857 } 858 859 if (sc->state != FWCAM_STATE_PROBED && 860 sc->state != FWCAM_STATE_STREAMING) { 861 FWCAM_UNLOCK(sc); 862 return (ENXIO); 863 } 864 865 FWCAM_UNLOCK(sc); 866 return (0); 867 } 868 869 static int 870 fwcam_hw_open(device_t dev) 871 { 872 struct fwcam_softc *sc = device_get_softc(dev); 873 874 return (fwcam_ensure_probed(sc)); 875 } 876 877 static int 878 fwcam_hw_querycap(device_t dev, struct video_caps *caps) 879 { 880 881 bzero(caps, sizeof(*caps)); 882 strlcpy(caps->driver, "fwcam", sizeof(caps->driver)); 883 strlcpy(caps->card, "IIDC FireWire Camera", sizeof(caps->card)); 884 strlcpy(caps->bus_info, "firewire", sizeof(caps->bus_info)); 885 caps->version = (1 << 16) | (0 << 8) | 0; /* 1.0.0 */ 886 caps->capabilities = VIDEO_CAP_CAPTURE | 887 VIDEO_CAP_READWRITE | VIDEO_CAP_STREAMING; 888 889 return (0); 890 } 891 892 /* 893 * Map a sequential enum index to an IIDC mode number. 894 * Returns -1 if index is out of range. 895 */ 896 static int 897 fwcam_index_to_mode(struct fwcam_softc *sc, uint32_t index) 898 { 899 int m; 900 uint32_t count = 0; 901 902 if (!(sc->formats & IIDC_FORMAT_VGA)) 903 return (-1); 904 905 for (m = 0; m < (int)FWCAM_FMT0_V4L2_NMODES; m++) { 906 if (sc->modes[IIDC_FMT_VGA] & (1 << (31 - m))) { 907 if (count == index) 908 return (m); 909 count++; 910 } 911 } 912 return (-1); 913 } 914 915 static int 916 fwcam_hw_enum_format(device_t dev, uint32_t index, struct video_format *fmt) 917 { 918 struct fwcam_softc *sc = device_get_softc(dev); 919 const struct fwcam_v4l2_mode *vm; 920 int m; 921 922 m = fwcam_index_to_mode(sc, index); 923 if (m < 0) 924 return (EINVAL); 925 926 vm = &fwcam_fmt0_v4l2[m]; 927 928 bzero(fmt, sizeof(*fmt)); 929 fmt->pixelformat = vm->pixelformat; 930 fmt->width = vm->width; 931 fmt->height = vm->height; 932 fmt->bytesperline = vm->bytesperline; 933 fmt->sizeimage = vm->sizeimage; 934 fmt->field = V4L2_FIELD_NONE; 935 936 return (0); 937 } 938 939 static int 940 fwcam_hw_get_format(device_t dev, struct video_format *fmt) 941 { 942 struct fwcam_softc *sc = device_get_softc(dev); 943 const struct fwcam_v4l2_mode *vm; 944 945 if (sc->cur_format != IIDC_FMT_VGA || 946 sc->cur_mode >= FWCAM_FMT0_V4L2_NMODES) 947 return (EIO); 948 949 vm = &fwcam_fmt0_v4l2[sc->cur_mode]; 950 951 bzero(fmt, sizeof(*fmt)); 952 fmt->pixelformat = vm->pixelformat; 953 fmt->width = vm->width; 954 fmt->height = vm->height; 955 fmt->bytesperline = vm->bytesperline; 956 fmt->sizeimage = vm->sizeimage; 957 fmt->field = V4L2_FIELD_NONE; 958 959 return (0); 960 } 961 962 /* 963 * Find the IIDC mode that best matches a V4L2 format request. 964 * Returns -1 if no match. 965 */ 966 static int 967 fwcam_find_mode_for_format(struct fwcam_softc *sc, 968 const struct video_format *fmt) 969 { 970 int m, best = -1; 971 972 if (!(sc->formats & IIDC_FORMAT_VGA)) 973 return (-1); 974 975 for (m = 0; m < (int)FWCAM_FMT0_V4L2_NMODES; m++) { 976 if (!(sc->modes[IIDC_FMT_VGA] & (1 << (31 - m)))) 977 continue; 978 if (fwcam_fmt0_v4l2[m].pixelformat == fmt->pixelformat && 979 fwcam_fmt0_v4l2[m].width == fmt->width && 980 fwcam_fmt0_v4l2[m].height == fmt->height) { 981 best = m; 982 break; 983 } 984 } 985 986 /* If exact match failed, try matching just pixelformat */ 987 if (best < 0) { 988 for (m = 0; m < (int)FWCAM_FMT0_V4L2_NMODES; m++) { 989 if (!(sc->modes[IIDC_FMT_VGA] & (1 << (31 - m)))) 990 continue; 991 if (fwcam_fmt0_v4l2[m].pixelformat == 992 fmt->pixelformat) { 993 best = m; 994 break; 995 } 996 } 997 } 998 999 return (best); 1000 } 1001 1002 static int 1003 fwcam_hw_try_format(device_t dev, struct video_format *fmt) 1004 { 1005 struct fwcam_softc *sc = device_get_softc(dev); 1006 const struct fwcam_v4l2_mode *vm; 1007 int m; 1008 1009 m = fwcam_find_mode_for_format(sc, fmt); 1010 if (m < 0) 1011 return (EINVAL); 1012 1013 vm = &fwcam_fmt0_v4l2[m]; 1014 1015 fmt->pixelformat = vm->pixelformat; 1016 fmt->width = vm->width; 1017 fmt->height = vm->height; 1018 fmt->bytesperline = vm->bytesperline; 1019 fmt->sizeimage = vm->sizeimage; 1020 fmt->field = V4L2_FIELD_NONE; 1021 1022 return (0); 1023 } 1024 1025 static int 1026 fwcam_hw_set_format(device_t dev, const struct video_format *fmt) 1027 { 1028 struct fwcam_softc *sc = device_get_softc(dev); 1029 int m, err; 1030 1031 m = fwcam_find_mode_for_format(sc, fmt); 1032 if (m < 0) 1033 return (EINVAL); 1034 1035 if (!(sc->rates[IIDC_FMT_VGA][m] & 1036 (1 << (31 - sc->cur_framerate)))) { 1037 /* Current framerate not supported in new mode, pick first */ 1038 int r; 1039 for (r = 0; r < 8; r++) { 1040 if (sc->rates[IIDC_FMT_VGA][m] & (1 << (31 - r))) { 1041 sc->cur_framerate = r; 1042 break; 1043 } 1044 } 1045 } 1046 1047 err = fwcam_write_quadlet(sc, IIDC_CUR_V_FORMAT, 1048 (uint32_t)IIDC_FMT_VGA << IIDC_CUR_V_SHIFT); 1049 if (err == 0) 1050 err = fwcam_write_quadlet(sc, IIDC_CUR_V_MODE, 1051 (uint32_t)m << IIDC_CUR_V_SHIFT); 1052 if (err == 0) 1053 err = fwcam_write_quadlet(sc, IIDC_CUR_V_FRM_RATE, 1054 (uint32_t)sc->cur_framerate << IIDC_CUR_V_SHIFT); 1055 1056 if (err == 0) { 1057 sc->cur_format = IIDC_FMT_VGA; 1058 sc->cur_mode = m; 1059 } 1060 1061 return (err); 1062 } 1063 1064 static int 1065 fwcam_hw_enum_framesizes(device_t dev, struct video_frmsizeenum *fse) 1066 { 1067 struct fwcam_softc *sc = device_get_softc(dev); 1068 int m; 1069 uint32_t count = 0; 1070 1071 if (!(sc->formats & IIDC_FORMAT_VGA)) 1072 return (EINVAL); 1073 1074 for (m = 0; m < (int)FWCAM_FMT0_V4L2_NMODES; m++) { 1075 if (!(sc->modes[IIDC_FMT_VGA] & (1 << (31 - m)))) 1076 continue; 1077 if (fwcam_fmt0_v4l2[m].pixelformat != fse->pixelformat) 1078 continue; 1079 if (count == fse->index) { 1080 fse->type = V4L2_FRMSIZE_TYPE_DISCRETE; 1081 fse->discrete.width = fwcam_fmt0_v4l2[m].width; 1082 fse->discrete.height = fwcam_fmt0_v4l2[m].height; 1083 return (0); 1084 } 1085 count++; 1086 } 1087 1088 return (EINVAL); 1089 } 1090 1091 static int 1092 fwcam_hw_enum_input(device_t dev, uint32_t index, struct video_input *inp) 1093 { 1094 1095 if (index != 0) 1096 return (EINVAL); 1097 1098 bzero(inp, sizeof(*inp)); 1099 inp->index = 0; 1100 strlcpy(inp->name, "IIDC Camera", sizeof(inp->name)); 1101 inp->type = VIDEO_INPUT_TYPE_CAMERA; 1102 1103 return (0); 1104 } 1105 1106 static int 1107 fwcam_hw_get_input(device_t dev, uint32_t *index) 1108 { 1109 1110 *index = 0; 1111 return (0); 1112 } 1113 1114 static int 1115 fwcam_hw_set_input(device_t dev, uint32_t index) 1116 { 1117 1118 if (index != 0) 1119 return (EINVAL); 1120 return (0); 1121 } 1122 1123 static int 1124 fwcam_hw_query_control(device_t dev, struct video_control_desc *qc) 1125 { 1126 struct fwcam_softc *sc = device_get_softc(dev); 1127 struct fwcam_feature feat; 1128 int fid; 1129 1130 fid = fwcam_find_feat_by_v4l2(qc->id); 1131 if (fid < 0) 1132 return (EINVAL); 1133 1134 feat.id = fid; 1135 if (fwcam_get_feature(sc, &feat) != 0) 1136 return (EINVAL); 1137 1138 if (!(feat.flags & FWCAM_FEATF_PRESENT)) 1139 return (EINVAL); 1140 1141 qc->type = V4L2_CTRL_TYPE_INTEGER; 1142 strlcpy(qc->name, fwcam_feat_names[fid], sizeof(qc->name)); 1143 qc->minimum = feat.min; 1144 qc->maximum = feat.max; 1145 qc->step = 1; 1146 qc->default_value = feat.min; 1147 qc->flags = 0; 1148 1149 return (0); 1150 } 1151 1152 static int 1153 fwcam_hw_get_control(device_t dev, struct video_control *ctrl) 1154 { 1155 struct fwcam_softc *sc = device_get_softc(dev); 1156 struct fwcam_feature feat; 1157 int fid; 1158 1159 fid = fwcam_find_feat_by_v4l2(ctrl->id); 1160 if (fid < 0) 1161 return (EINVAL); 1162 1163 feat.id = fid; 1164 if (fwcam_get_feature(sc, &feat) != 0) 1165 return (EINVAL); 1166 1167 ctrl->value = feat.value; 1168 return (0); 1169 } 1170 1171 static int 1172 fwcam_hw_set_control(device_t dev, const struct video_control *ctrl) 1173 { 1174 struct fwcam_softc *sc = device_get_softc(dev); 1175 struct fwcam_feature feat; 1176 int fid; 1177 1178 fid = fwcam_find_feat_by_v4l2(ctrl->id); 1179 if (fid < 0) 1180 return (EINVAL); 1181 1182 feat.id = fid; 1183 feat.value = ctrl->value; 1184 feat.value2 = 0; 1185 return (fwcam_set_feature(sc, &feat)); 1186 } 1187 1188 static int 1189 fwcam_hw_start_stream(device_t dev) 1190 { 1191 struct fwcam_softc *sc = device_get_softc(dev); 1192 int err; 1193 1194 err = fwcam_ensure_probed(sc); 1195 if (err) 1196 return (err); 1197 1198 sc->sc_sequence = 0; 1199 1200 return (fwcam_iso_start(sc)); 1201 } 1202 1203 static void 1204 fwcam_hw_stop_stream(device_t dev) 1205 { 1206 struct fwcam_softc *sc = device_get_softc(dev); 1207 1208 fwcam_iso_stop(sc); 1209 1210 FWCAM_LOCK(sc); 1211 if (sc->state != FWCAM_STATE_DETACHING) 1212 sc->state = FWCAM_STATE_PROBED; 1213 FWCAM_UNLOCK(sc); 1214 } 1215 1216 static int 1217 fwcam_probe(device_t dev) 1218 { 1219 struct fw_unit *unit; 1220 1221 unit = fw_get_unit(dev); 1222 if (unit == NULL) 1223 return (ENXIO); 1224 1225 if (unit->spec_id != CSRVAL_1394TA) 1226 return (ENXIO); 1227 if (unit->sw_version != CSR_PROTCAM130 && 1228 unit->sw_version != CSR_PROTCAM120 && 1229 unit->sw_version != CSR_PROTCAM104) 1230 return (ENXIO); 1231 1232 device_set_desc(dev, "IIDC Digital Camera over FireWire"); 1233 return (BUS_PROBE_DEFAULT); 1234 } 1235 1236 static int 1237 fwcam_attach(device_t dev) 1238 { 1239 struct fwcam_softc *sc; 1240 struct fw_unit *unit; 1241 uint32_t cmd_base; 1242 int err; 1243 1244 unit = fw_get_unit(dev); 1245 if (unit == NULL || unit->fwdev == NULL) 1246 return (ENXIO); 1247 1248 cmd_base = fwcam_find_iidc_cmd_base(unit); 1249 if (cmd_base == 0) { 1250 device_printf(dev, "no IIDC command base in unit directory\n"); 1251 return (ENXIO); 1252 } 1253 1254 sc = device_get_softc(dev); 1255 sc->fd.dev = dev; 1256 sc->fd.fc = fw_get_comm(dev); 1257 mtx_init(&sc->mtx, "fwcam", NULL, MTX_DEF); 1258 1259 sc->fwdev = unit->fwdev; 1260 sc->cmd_hi = 0xffff; 1261 sc->cmd_lo = 0xf0000000 | (cmd_base << 2); 1262 sc->iso_speed = min(unit->fwdev->speed, FWSPD_S400); 1263 sc->state = FWCAM_STATE_IDLE; 1264 sc->dma_ch = -1; 1265 sc->iso_active = 0; 1266 sc->sc_sequence = 0; 1267 TASK_INIT(&sc->probe_task, 0, fwcam_probe_task, sc); 1268 1269 err = video_register(dev, &sc->sc_vd); 1270 if (err != 0) { 1271 device_printf(dev, "failed to register video device\n"); 1272 mtx_destroy(&sc->mtx); 1273 return (err); 1274 } 1275 1276 return (0); 1277 } 1278 1279 static int 1280 fwcam_detach(device_t dev) 1281 { 1282 struct fwcam_softc *sc; 1283 1284 sc = device_get_softc(dev); 1285 1286 if (sc->sc_vd != NULL) 1287 video_unregister(sc->sc_vd); 1288 1289 FWCAM_LOCK(sc); 1290 sc->state = FWCAM_STATE_DETACHING; 1291 wakeup(sc); 1292 FWCAM_UNLOCK(sc); 1293 1294 taskqueue_drain(taskqueue_thread, &sc->probe_task); 1295 fwcam_iso_stop(sc); 1296 1297 FWCAM_LOCK(sc); 1298 sc->fwdev = NULL; 1299 FWCAM_UNLOCK(sc); 1300 1301 mtx_destroy(&sc->mtx); 1302 1303 return (0); 1304 } 1305 1306 static device_method_t fwcam_methods[] = { 1307 DEVMETHOD(device_probe, fwcam_probe), 1308 DEVMETHOD(device_attach, fwcam_attach), 1309 DEVMETHOD(device_detach, fwcam_detach), 1310 1311 /* video(4) interface */ 1312 DEVMETHOD(video_open, fwcam_hw_open), 1313 DEVMETHOD(video_querycap, fwcam_hw_querycap), 1314 DEVMETHOD(video_enum_format, fwcam_hw_enum_format), 1315 DEVMETHOD(video_get_format, fwcam_hw_get_format), 1316 DEVMETHOD(video_try_format, fwcam_hw_try_format), 1317 DEVMETHOD(video_set_format, fwcam_hw_set_format), 1318 DEVMETHOD(video_enum_framesizes, fwcam_hw_enum_framesizes), 1319 DEVMETHOD(video_enum_input, fwcam_hw_enum_input), 1320 DEVMETHOD(video_get_input, fwcam_hw_get_input), 1321 DEVMETHOD(video_set_input, fwcam_hw_set_input), 1322 DEVMETHOD(video_query_control, fwcam_hw_query_control), 1323 DEVMETHOD(video_get_control, fwcam_hw_get_control), 1324 DEVMETHOD(video_set_control, fwcam_hw_set_control), 1325 DEVMETHOD(video_start_stream, fwcam_hw_start_stream), 1326 DEVMETHOD(video_stop_stream, fwcam_hw_stop_stream), 1327 1328 DEVMETHOD_END 1329 }; 1330 1331 static driver_t fwcam_driver = { 1332 "fwcam", 1333 fwcam_methods, 1334 sizeof(struct fwcam_softc), 1335 }; 1336 1337 DRIVER_MODULE(fwcam, firewire, fwcam_driver, 0, 0); 1338 MODULE_VERSION(fwcam, 1); 1339 MODULE_DEPEND(fwcam, firewire, 1, 1, 1); 1340 MODULE_DEPEND(fwcam, video, 1, 1, 1); 1341