Project Description

The DeckLink Mini Recorder 4K is a PCI Express capture card featuring one 6G-SDI and one HDMI 2.0a connection. It can record all formats uncompressed up to 2160p30. The big difference with this card compared to many other capture cards is that it captures all the raw data uncompressed. This allows for it to be used for automatic testing of graphics cards.

Blackmagic provides a Linux driver for this card but it is proprietary and provides only a custom interface/SDK to access the card. We need this to be a fully functional V4L2 device and preferably work on non x86_64 architectures.

The existing driver consists of a proprietary blob and an open shim. To reverse engineer the device I plan to use tracing on the shim part of the proprietary driver.

Goal for this Hackweek

The goal would be to have a working V4L2 device driver that can eventually be upstreamed into the kernel.

Resources

DeckLink - Techical Specifications https://www.blackmagicdesign.com/products/decklink/techspecs/W-DLK-33

Looking for hackers with the skills:

Nothing? Add some keywords!

This project is part of:

Hack Week 20 Hack Week 21

Activity

  • over 2 years ago: cakeisamadeupdrug liked this project.
  • over 2 years ago: ybonatakis liked this project.
  • over 2 years ago: dmdiss liked this project.
  • over 3 years ago: vliaskovitis liked this project.
  • almost 4 years ago: patrikjakobsson started this project.
  • almost 4 years ago: patrikjakobsson originated this project.

  • Comments

    • patrikjakobsson
      over 2 years ago by patrikjakobsson | Reply

      This is the second hackweek I'm working on this project. I'm using a black-box approach to reverse engineer the hardware. By tracing all the accesses to the hardware I can deduce what the registers do and hopefully write a device driver that can control enough of the hardware to support it as a V4L2 device.

    • patrikjakobsson
      over 2 years ago by patrikjakobsson | Reply

      Hackweek 21 has come and gone. I got quite a bit further but unfortunately haven't figured out enough to start streaming data from the device.

      The driver consists of a binary blog which connects to a shim-layer that interacts with the linux kernel. I'm using a blackbox approach to reverse engineering the driver. In all relevant calls (eg. mmio) into the shim-layer I add a printk of the function name and parameters of interest. I also add a trace dump that my kernel log parser can pick up. With this method it is possible to see the function names of the binary blob functions that are calling the shim. This helps me to figure out the purpose of the registers.

      All this information ends up in the kernel log and I have written a special parser to collect all this information in a readable format.

      Here's a snippet of what the parsed output look like:

      310 1,615.2875 ioread32() reg = SET_VIDEO_INPUT_SOURCE_2_0x84 val = 0x10 _ZN21BlackmagicIOPCIDevice12memoryRead32Ehy+0x32/0x34 ? _raw_spin_unlock_irqrestore+0xa/0x2e ... 311 1,615.2882 iowrite32() reg = SET_VIDEO_INPUT_SOURCE_2_0x84 val = 0x16 _ZN21BlackmagicIOPCIDevice13memoryWrite32Ehyj+0x33/0x36 ? _raw_spin_unlock_irqrestore+0xa/0x2e ... 312 1,615.2889 iowrite32() reg = IER_0x44 val = 0xc67f3c0f _ZN21BlackmagicIOPCIDevice13memoryWrite32Ehyj+0x33/0x36 ? _ZN23RegisterAccessInterface13writeToDeviceEjj+0x16/0x18 ... 313 1,615.2895 ioread32() reg = DETECTED_INPUT_MODE_0x9c val = 0x403 _ZN21BlackmagicIOPCIDevice12memoryRead32Ehy+0x32/0x34 ? _ZN23RegisterAccessInterface14readFromDeviceEj+0x11/0x14 ... 314 1,615.2908 ioread32() reg = GET_DETECTED_INPUT_MODE_0x228 val = 0x0 _ZN21BlackmagicIOPCIDevice12memoryRead32Ehy+0x32/0x34 ? _ZN23RegisterAccessInterface14readFromDeviceEj+0x11/0x14 ... 315 1,615.2921 ioread32() reg = DETECTED_INPUT_MODE_0x9c val = 0x403 _ZN21BlackmagicIOPCIDevice12memoryRead32Ehy+0x32/0x34 ? _ZN23RegisterAccessInterface14readFromDeviceEj+0x11/0x14 ... 316 1,615.2934 ioread32() reg = VIDEO_INPUT_MODE_0x1bc val = 0x0 317 1,615.2934 ioread32() reg = ISR_0x40 val = 0x1000 318 1,615.2949 ioread32() reg = VIDEO_INPUT_MODE_0x1bc val = 0x0 _ZN21BlackmagicIOPCIDevice12memoryRead32Ehy+0x32/0x34 ? _ZN23RegisterAccessInterface14readFromDeviceEj+0x11/0x14 ... 319 1,615.2968 ioread32() reg = STATUS_MONITOR_0x108 val = 0x0 _ZN21BlackmagicIOPCIDevice12memoryRead32Ehy+0x32/0x34 ? _ZN23RegisterAccessInterface14readFromDeviceEj+0x11/0x14 ... 320 1,615.2980 ioread32() reg = DETECTED_INPUT_MODE_0x9c val = 0x403 _ZN21BlackmagicIOPCIDevice12memoryRead32Ehy+0x32/0x34 ? _ZN23RegisterAccessInterface14readFromDeviceEj+0x11/0x14 ... 321 1,615.2993 ioread32() reg = GET_DETECTED_INPUT_MODE_0x228 val = 0x0 _ZN21BlackmagicIOPCIDevice12memoryRead32Ehy+0x32/0x34 ? _ZN23RegisterAccessInterface14readFromDeviceEj+0x11/0x14 ... The output is colored to provide readability but this is not shown in the example above. The format is pretty simple but needs some explaining. The first column (ie 310) is the row number of the entire log. If you pass the row number to the parser it will show additional details of that specific trace (see example below). The second column is the timestamp in seconds. The third column is the function name which follows by the relevant function parameters (ie reg, val, etc...). After that comes the context of the backtrace (ie or ). After that follow the first couple of lines from the backtrace.

      Here's an example of a detailed view of a trace:

      ``` 0 1,615.2968 ioread32() reg = STATUSMONITOR0x108 val = 0x0

          _ZN21BlackmagicIOPCIDevice12memoryRead32Ehy+0x32/0x34
          ? _ZN23RegisterAccessInterface14readFromDeviceEj+0x11/0x14
          ? _ZN23RegisterAccessInterface12readRegisterEj+0x27/0x2a
          ? _ZN19VideoHardwareDevice12updateStatusEP13StatusMonitor+0x273/0x402
          ? _ZN8OSObjectC2EPK11OSMetaClass+0xe/0x20
          ? _ZN19VideoHardwareDevice7messageEjP9IOServicePv+0x22d8/0x22f6
          ? _ZN20OSCollectionIterator14withCollectionEPK12OSCollection+0x31/0x48
          ? _ZNK8OSObject6retainEv+0x2c/0x36
          ? _ZNK15OSMetaClassBase8metaCastEPK11OSMetaClass+0x13/0x34
          ? _ZN9IOService14messageClientsEjPvl+0x67/0x86
          ? _ZN18BlackmagicIODriver7messageEjP9IOServicePv+0x29d/0x37c
          ? console_unlock+0x2d5/0x4b0
          ? _ZN13StatusMonitorD0Ev+0x20/0x20
          ? _ZN13StatusMonitor22statusUpdateTimerFiredEP8OSObjectP18IOTimerEventSource+0x31/0x48
          ? _ZN10IOWorkLoop9runActionEPFiP8OSObjectPvS2_S2_S2_ES1_S2_S2_S2_S2_+0x44/0x66
          ? _ZN13StatusMonitor7messageEjP9IOServicePv+0xf4/0x108
          ? _ZN18BlackmagicIODriver7messageEjP9IOServicePv+0x358/0x37c
          ? _ZN19VideoHardwareDevice16enableVideoInputEv+0x8d/0x96
          ? _ZN19VideoInputInterface6enableEP15UserClientClassjb+0x77/0xd8
          ? _ZN15UserClientClass12drawFrameNowEP29BlackmagicOutputFrameParamRecj+0x2e/0x34
          ? _ZN15UserClientClass16enableVideoInputEj+0x2a/0x36
          ? _ZNK4Util20UserClientDispatcher10DispatcherINS0_18ScalarSetScalarGetILj1ELj0EEEM15UserClientClassFijEEclEPS4_P25IOExternalMetho+0x4e/0x56
          ? _ZN15UserClientClass14externalMethodEjP25IOExternalMethodArgumentsP24IOExternalMethodDispatchP8OSObjectPv+0x576/0x98c
          ? _ZN18IoctlMessageKernel6unpackEv+0x146/0x150
          ? _ZN20UserClientClassLinux5ioctlEjm+0xae/0xe0
          ? bmio_client_ioctl+0xc/0xe
          ? bmio_ioctl+0x16/0x30
          ? __x64_sys_ioctl+0x8e/0xd0
          ? do_syscall_64+0x67/0x80
          ? do_syscall_64+0x5b/0x80
          ? do_user_addr_fault+0x1ff/0x730
          ? exc_page_fault+0x71/0x170
          ? entry_SYSCALL_64_after_hwframe+0x44/0xae
      

      ```

    • patrikjakobsson
      over 2 years ago by patrikjakobsson | Reply

      At the very end of a trace there is a summary that shows all the accessed registers and how they were used. This is also very useful for trying to figure out which bits are being used for different operations.

      Here's an example output of the summary:

      ISR_0x40 R 0x1000 0x800 0x400 0x20000 0x2 SET_VIDEO_INPUT_SOURCE_2_0x84 RW 0x10 0x16 0x16 0x10 IER_0x44 W 0xc67f3c0f 0xc67f300f DETECTED_INPUT_MODE_0x9c R 0x403 GET_DETECTED_INPUT_MODE_0x228 R 0x0 VIDEO_INPUT_MODE_0x1bc R 0x0 STATUS_MONITOR_0x108 R 0x0 SET_VIDEO_INPUT_PIXEL_FORMAT_0x94 RW 0x0 0x40e 0x40e 0x1040e DMA_CTL_0x20 RW 0x30 0xb0 0xb8 0xb0 0xb8 0xb2 0x30 DMA_TRANS_2_0x18 W 0x1 DMA_TRANS_3_0x1c W 0x4c281000 DMA_TRANS_5_0x3c W 0x20 SET_NEXT_INPUT_FRAME_2_0x90 W 0x4000000 0x491e600 0x523cc00 SET_NEXT_INPUT_FRAME_1_0x74 W 0x43f4800 0x4d12e00 0x5631400 DMA_UNK_0x8 W 0x1 DMA_ADDR_0xc W 0x3781000 0xb9c1000 0x10d01000 0x18141000 DMA_LEN_0x34 W 0x30 0x40 0x50 AUDIO_INPUT_WRITE_SAMPLE_POSITION_0xa0 R 0x6400000 0xc800000 REG_OFFSET=4200000

      The names of the registers are made up by me based on what they seem to be used for. They may of may not be correct at this point. I will provide more information on what I know about the mode detection, dma transfers and irq handling in a later post.

    Similar Projects

    This project is one of its kind!