Support for the D-Link DCS-930L Webcam

I was working on getting the DCS-930L camera support working several years back on the old forum, but eventually gave up due to USB issues that prevented the camera to work. Having a bunch of these cameras and with D-Link not having released a firmware for the last 5 years I decided to give this another shot, and after a ton of issues finally managed to get it working without requiring soldering a serial console to it. I know this is a 4/32 device and that support for these in general is going away, but hopefully there's still an opportunity to keep these working.

The Wiki page is quite outdated (I can see if I can update it later on), but as stated in the forum thread above one of the biggest challenges with this device is the stock firmware layout. In the stock firmware there is only one partition listed as "Kernel" or "Firmware" depending on version, in addition to the bootloader, config and factory settings partitions:

Creating 4 MTD partitions on "Ralink SoC physically mapped flash":
0x00000000-0x00030000 : "Bootloader"
0x00030000-0x00040000 : "Config"
0x00040000-0x00050000 : "Factory"
0x00050000-0x00400000 : "Kernel"

Problem here though is that while not showing up in the bootlog above this partition is actually split into two, and the kernel one is only 1MB in size. So any attempt to flash this device with a kernel bigger than that will fail as long as you do it through the emergency web interface, which without soldering is the only practical way of doing it. I spent a lot of time trying to slim down the current kernel in 19.07 to get below this limit, and finally managed to build one that was just a few KB below the limit. Sadly I despite much testing could not get this one to properly read the partitions after flashing it through the emergency web interface, where I got this on the serial console:

VFS: Cannot open root device "(null)" or unknown-block(0,0): error -6
Please append a correct "root=" boot option; here are the available partitions:
1f00             192 mtdblock0 
 (driver?)
1f01              64 mtdblock1 
 (driver?)
1f02              64 mtdblock2 
 (driver?)
1f03            3776 mtdblock3 
 (driver?)
Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)
Rebooting in 1 seconds..

I initially thought I had just slimmed it down too much, but oddly enough booting with the current official initramfs kernel over TFTP gives the same error. Having worked on this device years back I did have an old firmware though that I knew booted. Flashing that one through the emergency web interface worked. Turns out that ssh wasn't working in that image without a root password set, but luckily telnet did, allowing me to not have to have serial access. Through telnet I logged into the device and could then scp a more proper firmware to the device and flash it through sysupgrade. The initial 1MB kernel limitation is only an issue when using the emergency web interface, so now I could re-flash again with a more proper firmware:

killall: telnetd: no process killed
Sending TERM to remaining processes ... ntpd ubusd urngd logd rpcd netifd 
Sending KILL to remaining processes ... 
Performing system upgrade...
Unlocking firmware ...

Writing from <stdin> to firmware ...     
Upgrade completed
Rebooting system...
umount: can't unmount /dev: Resource busy
umount: can't unmount /tmp: Resource busy
umount: can't unmount /: Ireboot: Restarting system
þ
 
U-Boot 1.1.3
            
Board: Ralink APSoC DRAM:  32 MB
relocate_code Pointer at: 81fac000
config usb..                      
******************************
Software System Reset Occurred
******************************
flash_protect ON: from 0xBF000000 to 0xBF021767
flash_protect ON: from 0xBF030000 to 0xBF030FFF
============================================   
Ralink UBoot Version: 3.5.2.0                
-------------------------------------------- 
ASIC 3052_MP2 (Port5<->None)                 
DRAM component: 256 Mbits SDR
DRAM bus: 16 bit             
Total memory: 32 MBytes
Flash component: NOR Flash
============================================ 
icache: sets:256, ways:4, linesz:32 ,total:32768
dcache: sets:128, ways:4, linesz:32 ,total:16384 
                                                 
 ##### The CPU freq = 320 MHZ #### 
 estimate memory size =32 Mbytes   
                                
Signature: DCS-930                  Release 1.11 (2011-05-31)
                                                             

Please choose the operation: 
   1: Load system code to SDRAM via TFTP. 
   2: Load system code then write to Flash via TFTP. 
   3: Boot system code via Flash (default).          
   4: Entr boot command line interface.    
   7: Load Boot Loader code then write to Flash via Serial. 
   9: Load Boot Loader code then write to Flash via TFTP.   
 0                                                        
   
3: System Boot system code via Flash.
## Booting image at bf050000 ...     
   Image Name:   MIPS OpenWrt Linux-4.14.215
   Created:      2021-01-19  13:10:02 UTC   
   Image Type:   MIPS Linux Kernel Image (lzma compressed)
   Data Size:    1256560 Bytes =  1.2 MB                  
   Load Address: 80000000               
   Entry Point:  80000000
   Verifying Checksum ... OK
   Uncompressing Kernel Image ... OK
No initrd                           
## Transferring control to Linux (at address 80000000) ...
## Giving linux memsize in MB, 32                         
                                 
Starting kernel ...
                   
Linux version 4.14.215 (builder@buildhost) (gcc version 7.5.0 (OpenWrt GCC 7.5.0 r11278-8055e38794)) #0 Tue Jan 19 13:10:02 2021
SoC Type: Ralink RT3350 id:1 rev:2
bootconsole [early0] enabled
CPU0 revision is: 0001964c (MIPS 24KEc)
MIPS: machine is D-Link DCS-930
Determined physical RAM map:
 memory: 02000000 @ 00000000 (usable)
Initrd not found or empty - disabling initrd
Primary instruction cache 32kB, VIPT, 4-way, linesize 32 bytes.
Primary data cache 16kB, 4-way, VIPT, no aliases, linesize 32 bytes
Zone ranges:
  Normal   [mem 0x0000000000000000-0x0000000001ffffff]
Movable zone start for each node
Early memory node ranges
  node   0: [mem 0x0000000000000000-0x0000000001ffffff]
Initmem setup node 0 [mem 0x0000000000000000-0x0000000001ffffff]
random: get_random_bytes called from 0x803926ec with crng_init=0
Built 1 zonelists, mobility grouping on.  Total pages: 8128
Kernel command line: console=ttyS0,57600 rootfstype=squashfs,jffs2
PID hash table entries: 128 (order: -3, 512 bytes)
Dentry cache hash table entries: 4096 (order: 2, 16384 bytes)
Inode-cache hash table entries: 2048 (order: 1, 8192 bytes)
Writing ErrCtl register=0002f9d0
Readback ErrCtl register=0002f9d0
Memory: 27348K/32768K available (3070K kernel code, 167K rwdata, 412K rodata, 1208K init, 196K bss, 5420K reserved, 0K cma-reserv)
SLUB: HWalign=32, Order=0-3, MinObjects=0, CPUs=1, Nodes=1
NR_IRQS: 256
CPU Clock: 320MHz
timer_probe: no matching timers found
clocksource: MIPS: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 11945377789 ns
sched_clock: 32 bits at 160MHz, resolution 6ns, wraps every 13421772796ns
Calibrating delay loop... 212.58 BogoMIPS (lpj=1062912)
pid_max: default: 32768 minimum: 301
Mount-cache hash table entries: 1024 (order: 0, 4096 bytes)
Mountpoint-cache hash table entries: 1024 (order: 0, 4096 bytes)
clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 19112604462750000 ns
futex hash table entries: 256 (order: -1, 3072 bytes)
pinctrl core: initialized pinctrl subsystem
NET: Registered protocol family 16
rt2880_gpio 10000600.gpio: registering 24 gpios
rt2880_gpio 10000600.gpio: registering 24 irq handlers
clocksource: Switched to clocksource MIPS
NET: Registered protocol family 2
TCP established hash table entries: 1024 (order: 0, 4096 bytes)
TCP bind hash table entries: 1024 (order: 0, 4096 bytes)
TCP: Hash tables configured (established 1024 bind 1024)
UDP hash table entries: 256 (order: 0, 4096 bytes)
UDP-Lite hash table entries: 256 (order: 0, 4096 bytes)
NET: Registered protocol family 1
rt-timer 10000100.timer: maximum frequency is 3255Hz
workingset: timestamp_bits=30 max_order=13 bucket_order=0
squashfs: version 4.0 (2009/01/31) Phillip Lougher
jffs2: version 2.2 (NAND) (SUMMARY) (LZMA) (RTIME) (CMODE_PRIORITY) (c) 2001-2006 Red Hat, Inc.
io scheduler noop registered
io scheduler deadline registered (default)
Serial: 8250/16550 driver, 16 ports, IRQ sharing enabled
console [ttyS0] disabled
10000c00.uartlite: ttyS0 at MMIO 0x10000c00 (irq = 20, base_baud = 6666666) is a Palmchip BK-3103
console [ttyS0] enabled
console [ttyS0] enabled
bootconsole [early0] disabled
bootconsole [early0] disabled
1f000000.cfi: Found 1 x16 devices at 0x0 in 16-bit bank. Manufacturer ID 0x0000c2 Chip ID 0x0022a8
Amd/Fujitsu Extended Query Table at 0x0040
  Amd/Fujitsu Extended Query version 1.1.
number of CFI chips: 1
4 fixed-partitions partitions found on MTD device 1f000000.cfi
Creating 4 MTD partitions on "1f000000.cfi":
0x000000000000-0x000000030000 : "u-boot"
0x000000030000-0x000000040000 : "u-boot-env"
0x000000040000-0x000000050000 : "factory"
0x000000050000-0x000000400000 : "firmware"
2 uimage-fw partitions found on MTD device firmware
Creating 2 MTD partitions on "firmware":
0x000000000000-0x000000132cb0 : "kernel"
0x000000132cb0-0x0000003b0000 : "rootfs"
mtd: device 5 (rootfs) set to be root filesystem
1 squashfs-split partitions found on MTD device rootfs
0x000000340000-0x0000003b0000 : "rootfs_data"
libphy: Fixed MDIO Bus: probed
rt3050-esw 10110000.esw: link changed 0x01
mtk_soc_eth 10100000.ethernet eth0: mediatek frame engine at 0xb0100000, irq 5
rt2880_wdt 10000120.watchdog: Initialized
NET: Registered protocol family 17
bridge: filtering via arp/ip/ip6tables is no longer available by default. Update your scripts to load br_netfilter if you need th.
8021q: 802.1Q VLAN Support v1.8
VFS: Mounted root (squashfs filesystem) readonly on device 31:5.
Freeing unused kernel memory: 1208K
This architecture does not have kernel memory protection.
random: fast init done
init: Console is alive
init: - watchdog -
kmodloader: loading kernel modules from /etc/modules-boot.d/*
usbcore: registered new interface driver usbfs
usbcore: registered new interface driver hub
usbcore: registered new device driver usb
dwc2 101c0000.otg: Configuration mismatch. dr_mode forced to host
dwc2 101c0000.otg: DWC OTG Controller
dwc2 101c0000.otg: new USB bus registered, assigned bus number 1
dwc2 101c0000.otg: irq 26, io mem 0x101c0000
hub 1-0:1.0: USB hub found
hub 1-0:1.0: 1 port detected
kmodloader: done loading kernel modules from /etc/modules-boot.d/*
init: - preinit -
usb 1-1: new full-speed USB device number 2 using dwc2
8021q: adding VLAN 0 to HW filter on device eth0
Press the [f] key and hit [enter] to enter failsafe mode
Press the [1], [2], [3] or [4] key and hit [enter] to select the debug level
random: procd: uninitialized urandom read (4 bytes read)
mount_root: jffs2 not ready yet, using temporary tmpfs overlay
urandom-seed: Seed file not found (/etc/urandom.seed)
procd: - early -
procd: - watchdog -
open: No such file or directory
random: jshn: uninitialized urandom read (4 bytes read)
random: ubusd: uninitialized urandom read (4 bytes read)
random: ubus: uninitialized urandom read (4 bytes read)
Command failed: Not found
procd: - init -
Please press Enter to activate this console.
kmodloader: loading kernel modules from /etc/modules.d/*
i2c /dev entries driver
Linux video capture interface: v2.00
Loading modules backported from Linux version v4.19.161-0-gdaefdc9eb24b
Backport generated by backports.git v4.19.161-1-0-g4bb568fe
nf_conntrack version 0.5.0 (1024 buckets, 4096 max)
xt_time: kernel timezone is -0000
ip_tables: (C) 2000-2006 Netfilter Core Team
usbcore: registered new interface driver snd-usb-audio
urngd: v1.0.2 started.
uvcvideo: Found UVC 1.00 device <unnamed> (1b3b:2970)
uvcvideo: UVC non compliance - GET_DEF(PROBE) not supported. Enabling workaround.
input: UVC Camera (1b3b:2970) as /devices/platform/101c0000.otg/usb1/1-1/1-1:1.0/input/input0
usbcore: registered new interface driver uvcvideo
USB Video Class driver (1.1.1)
rt2800_wmac 10180000.wmac: loaded eeprom from mtd device "factory"
ieee80211 phy0: rt2x00_set_rt: Info - RT chipset 2872, rev 0200 detected
ieee80211 phy0: rt2x00_set_rf: Info - RF chipset 0005 detected
kmodloader: done loading kernel modules from /etc/modules.d/*
random: crng init done
random: 6 urandom warning(s) missed due to ratelimiting
jffs2_scan_eraseblock(): End of filesystem marker found at 0x0
jffs2_build_filesystem(): unlocking the mtd device... 
done.
jffs2_build_filesystem(): erasing all blocks after the end marker... 
8021q: adding VLAN 0 to HW filter on device eth0
br-lan: port 1(eth0) entered blocking state
br-lan: port 1(eth0) entered disabled state
device eth0 entered promiscuous mode
br-lan: port 1(eth0) entered blocking state
br-lan: port 1(eth0) entered forwarding state
done.
jffs2: notice: (986) jffs2_build_xattr_subsystem: complete building xattr subsystem, 0 of xdatum (0 unchecked, 0 orphan) and 0 of.
overlayfs: upper fs does not support tmpfile.

To fit the new firmware onto the small flash I had to slim it down considerably, but not having the 1MB kernel limit anymore it was not any issues building a firmware that is fully functional for it's intended use case. With networking + wireless, ssh and mjpg-streamer built in I still have about 500KB left for the JFFS2 partition. I have removed anything not strictly needed to run the camera part, like LUCI and also took out IPv6 support. I did the steps above on a second DCS-930 A1 device lacking serial console, and it worked fine there too.

mjpg-streamer requires a bit of configuration changes to work, I will try to work that into the firmware itself to not waste JFFS2 space changing it. Here's the config I have for it now:

root@OpenWrt:~# cat /etc/config/mjpg-streamer 

config mjpg-streamer 'core'
	option enabled '1'
	option input 'uvc'
	option output 'http'
	option device '/dev/video0'
	option resolution '640x480'
	option fps '5'
	option led 'auto'
	option www '/www/webcam'
	option port '8080'

Streaming works really well, it consumes 10-20% CPU only, doing a continuous stream over HTTP. I will stream to Zoneminder so I can do the motion detection there, but in the past I know people have successfully run motion on the camera as well. Oddly enough mjpg_streamer seems to do some sort of motion detection on it's own too:

user.notice root: webcam motion event

For anyone interested I'll make my old firmware available for initial flashing, and the config for the new one too. I will give it another shot getting a version based on 19.07 compiled as well, but it will be so slimmed down that it will probably still be hard to provide it as an official factory image. Since it is only needed once maybe that isn't a big issue though. Creating a working official sysupgrade image should be doable though I think.

1 Like

If anyone wants to try out the approach outlined above, then here are some links to the images I used. Note that this most likely will only work on DCS-930L revision A! If you have the B1 version then it probably will not work. Use all of it at your own risk, this is highly experimental at this stage :slight_smile:

Note that this image is over 5 years old (Barrier Breaker, r39854) and guaranteed to be full of security holes! It is only for getting OpenWrt onto the camera initially, don't run this image on any type of network that you don't fully trust. I have successfully flashed this one on two cameras of A1 and A3 HW revision respectively. To flash use a paperclip to hold in reset when powering on the camera, and then go to http://192.168.0.20/ where you find the emergency web interface. I had some problems using it with a regular browser, instead I used curl as per another post:

curl -F firmware=@/tmp/openwrt-ramips-rt305x-dcs-930-squashfs-factory.bin http://192.168.0.20/

If flashing works the camera should reboot after a minute (red and blue leds flashing). Once the front led starts blinking green the kernel has been successfully loaded and the camera is booting. When the light is steady green the camera should be reachable. Default network config will put it at 192.168.1.1. As mentioned ssh login does not work, but telnet does. Once logged in either scp in the next image, or set a password to allow scp from the outside.

Before going to the next stage it can be good to check in /proc/mtd that all partitions show up. If rootfs and rootfs_data are listed it should probably be ok to proceed.I upgraded without keeping settings, otherwise you most likely will inherit some ancient settings from the initial firmware:

sysupgrade -n -v /tmp/openwrt/openwrt-19.07.6-ramips-rt305x-dcs-930-squashfs-sysupgrade.bin

After a minute or so the device should reboot, and if the upgrade was successful boot up with leds going green again. If you see the front led going red and the back one blue in 10 or so second intervals something went wrong and it cannot boot. You can revert back to either the D-Link firmware or the initial one above through the emergency web interface in that case.

If the reboot works then you should have a functioning camera, if enabling mjpg-streamer. You can try it manually as well with the following:

mjpg_streamer -i "/usr/lib/input_uvc.so -n -r 640x480 -d /dev/video0" -o "/usr/lib/output_http.so -p 8080 -w /www/webcam

The network is hardcoded to 192.168.1.1, changing this to DHCP or adding a default route + DNS is needed to get NTP to work, unless you have an NTP server on the local network.

Curious, so the partition layout itself is actually allowing for kernels larger than 1 MB in OpenWrt master, but the Emergency Webinterface flashing does not?

I just checked the .dts again, and it seems like this commit

removed the fixed partition layout by adding "denx,uImage" to the firmware partition, thus allowing for larger size kernels!? However this change was in December 2018, and maybe I had used the stable image for testing back in March 2019, even though it might have been fixed in snapshots already at that time :thinking:

Guess I should really dig out my cams again :slight_smile: I also have DCS-5020L, which seems to be built on a similar platform, but requires stepper motor control via GPIOs...

Thanks for fiddling with mjpeg-streamer to make it work! I never even made it this far...

Yep that's correct, it only seems to be a limitation in the emergency web interface, and I'm guessing probably also if trying to flash from D-Links upgrade interface when the camera is running. Once you have OpenWrt running it will happily support any kernel size, as long as the total image size does not become too big.

I looked that earlier, but I think all that was done was to add that line. Looking at the file the partition layout is still there: https://github.com/openwrt/openwrt/blob/d70ec3008d4cd0540a9f6c88fb7e786107f1679a/target/linux/ramips/dts/DCS-930.dts. I tried compiling without compatible = "denx,uimage";but that made no difference.

Seems like some good work has been done already at https://openwrt.org/toh/d-link/d-link_dcs-5020l_a1, 8MB flash would make things a lot simpler :slight_smile: I have a few DCS-930 B1 that I want to get working as well, and then also a DCS-933L A1.

Thanks, I have a DCS-932L revision B2 here and just flashed the v18 factory image for dcs-930l-b1 with curl (web interface says invalid file, emergency did not work with Firefox as expeceted).

Flashing worked fine, now it's stuck in a bootloop :slight_smile:

So I think I'll need to solder UART to this one...

Did you make any changes to the Barrier Breaker initial image, or was it just meant to be a first-step for flashing to the latest version you built?

Okay, I was stupid to assume v18 were Barrier Breaker, though it's actually v14 :innocent:

Turns out the 93xL were only supported since Chaos Calmer, but that doesn't work either...

I think it's curious that D-Link factory images contain the bootloader, while OpenWrt starts with the kernel and rootfs I think.

Or maybe DCS-932L is not supported by DCS-930L image (unlike DCS-930 A1 also works for DCS-932) :thinking:

I think all of these models should be treated just like new devices, i.e. start from scratch for supporting these, create a shared .dtsi and code to create factory images that are flashable by OEM Web UI, and finally see which parts might be salvageable from the current implementation... :man_shrugging:

// edit...
I wonder why there are no factory or sysupgrade images for newer versions. Booted v18 initramfs via tftp successfully, copied v19 factory via scp and flashed with sysupgrade -f (since no metadata is appended to factory, and there is no sysupgrade image available)...

Bricked again, Bad Data CRC.
I guess this requires even further wasting of time :slight_smile:

I think that unfortunately none of the stock firmwares work :confused: Going back all the way to Barrier Breaker the kernel was still too big, although I think someone in the original thread on the old forum had one working for B1 that was posted.

It was quite heavily modified I think, to shrink the kernel down to be less than 1MB. I did a bit of digging, and while it most likely would not work now I found the config file I used back then here. I don't think that one would compile now though, unless going back to to using code that old.

Yeah I think the same kernel size issues exist there too I'm afraid.

Yep that part is a bit weird. In how the emergency web interface works it seems to take an image that has to be exactly 4194304 bytes in size, but then drop the first 64 bytes for the header (which makes sense), but then also drops the next 327680 bytes that I think corresponds to the size of the bootloader, factory and u-boot-env partitions. Here's what a working image looks like with binwalk:

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             uImage header, header size: 64 bytes, header CRC: 0x74584AF1, created: 2015-04-25 23:00:59, image size: 2805198 bytes, Data Address: 0x80000000, Entry Point: 0x80000000, data CRC: 0x320AC441, OS: Linux, CPU: MIPS, image type: OS Kernel Image, compression type: lzma, image name: "MIPS OpenWrt Linux-3.10.32"
64            0x40            LZMA compressed data, properties: 0x6D, dictionary size: 8388608 bytes, uncompressed size: 2880980 bytes
327680        0x50000         uImage header, header size: 64 bytes, header CRC: 0x74584AF1, created: 2015-04-25 23:00:59, image size: 2805198 bytes, Data Address: 0x80000000, Entry Point: 0x80000000, data CRC: 0x320AC441, OS: Linux, CPU: MIPS, image type: OS Kernel Image, compression type: lzma, image name: "MIPS OpenWrt Linux-3.10.32"
327744        0x50040         LZMA compressed data, properties: 0x6D, dictionary size: 8388608 bytes, uncompressed size: 2880980 bytes
1376256       0x150000        Squashfs filesystem, little endian, version 4.0, compression:xz, size: 1756686 bytes, 644 inodes, blocksize: 262144 bytes, created: 2015-04-25 22:59:11

The images built by OpenWrt actually just concatenates the image twice, with the first 327680 bytes then getting silently dropped by the web interface. I think that part could probably just as well contain random data, only reason it was concatenated think was to get the uImage header at the start.

The L part at the end was only that it supported some sort of D-Link cloud solution, I think the HW is more or less the same. I have one DCS-930 and one DCS-930L, and they both work with the same A1 image.

Yep, so my plan (will probably not have time until the weekend though) is to try to get my 19.07 image booting on a A1 camera to begin with. It almost worked, only issue was that it could not find the partitions inside the firmware partition. When I gave up an compiled a version that was not slimmed down to <1MB that part worked, and I think it might have been due to a small patch I applied. If I get an 19.07 version working from the emergency web interface I think it should from there onward be quite straightforward to compile one for B1 as well.

I think that was intentional unfortunately, found a commit by someone that cleared out a bunch of devices from getting FW's built that only bricked devices. It's probably also due to the 4/32 device support going away. There was one sysupgrade for 19.07.5 I think though, so maybe that would work? You could probably go back earlier in time as well, anything that boots and has sysupgrade should work :slight_smile:

That's great! Did you solder serial to it, or how did you get TFTP to work?

Yes, I had to solder serial. Also makes it a lot easier to even just get an idea of what's happening within the device...:slight_smile:

So, I'll need to go back to the latest sysupgrade image available, which would be 17.01.7...Why the hell is it even possible to provide factory but not sysupgrade (nevermind, the factory wouldn't be working either of course, but still it's weird)

Maybe only the v17 initramfs should be for flashing to v17 :thinking:

I'll try to dig out more cameras at the weekend and see which revisions they are, thanks a lot for your insights on this so far!

Sounds great, having serial there will make things a lot easier. I had a little bit of time to try recompiling 19.06.7, and finally managed to build a kernel that is small emough, actually boots and can detect all partitions:

root@OpenWrt:/# cat /etc/openwrt_release 
DISTRIB_ID='OpenWrt'
DISTRIB_RELEASE='19.07.7'
DISTRIB_REVISION='r11306-c4a6851c72'
DISTRIB_TARGET='ramips/rt305x'
DISTRIB_ARCH='mipsel_24kc'
DISTRIB_DESCRIPTION='OpenWrt 19.07.7 r11306-c4a6851c72'
DISTRIB_TAINTS='no-all no-ipv6 mklibs busybox'
root@OpenWrt:/# cat /proc/mtd 
dev:    size   erasesize  name
mtd0: 00030000 00010000 "u-boot"
mtd1: 00010000 00010000 "u-boot-env"
mtd2: 00010000 00010000 "factory"
mtd3: 003b0000 00010000 "firmware"
mtd4: 00132cb0 00010000 "kernel"
mtd5: 0027d350 00010000 "rootfs"
mtd6: 00070000 00010000 "rootfs_data"

I have only booted this one over TFTP so far though, but it looks promising. Since the factory image isn't built automatically anymore I will have to manually create it. I had some luck with this previously (but then it couldn't find the partitions), so hopefully this could lead to a working initial factory image, that then also quite easily can be port to the B1 version as well.

Tried now with an image I manually assembled, but sadly I still got the same issue finding all partitions:

Entering program & boot linux.
Erase linux block (0xbf050000 ~ 0xbf25ffff)
                                           
 b_end =BF3FFFFF
Erase Flash from 0xbf050000 to 0xbf25ffff in Bank # 1 
***********Erased 33 sectors                          
                            
 Copy linux image[0 byte] to Flash[0xBF050000].... 
Copy to Flash...                                   
 Copy 2097156 byte to Flash... 
 addr = 0xBF0B2832 ,cnt=1693650 
 addr = 0xBF115066 ,cnt=1290142 
 addr = 0xBF17789A ,cnt=886634  
 addr = 0xBF1DA0CE ,cnt=483126 
 addr = 0xBF23C902 ,cnt=79618 done
## Booting image at bf050000 ...  
   Image Name:   testimage 8
   Created:      2021-02-25  21:18:50 UTC
   Image Type:   MIPS Linux Kernel Image (lzma compressed)
   Data Size:    2097092 Bytes =  2 MB                    
   Load Address: 80000000             
   Entry Point:  80000000
   Verifying Checksum ... OK
   Uncompressing Kernel Image ... OK
No initrd                           
## Transferring control to Linux (at address 80000000) ...
## Giving linux memsize in MB, 32                         
                                 
Starting kernel ...
                   
Linux version 4.14.221 (builder@buildhost) (gcc version 7.5.0 (OpenWrt GCC 7.5.0 r11278-8055e38794)) #0 Mon Feb 15 15:22:37 2021
SoC Type: Ralink RT3350 id:1 rev:2
bootconsole [early0] enabled
CPU0 revision is: 0001964c (MIPS 24KEc)
MIPS: machine is D-Link DCS-930
Determined physical RAM map:
 memory: 02000000 @ 00000000 (usable)
Primary instruction cache 32kB, VIPT, 4-way, linesize 32 bytes.
Primary data cache 16kB, 4-way, VIPT, no aliases, linesize 32 bytes
Zone ranges:
  Normal   [mem 0x0000000000000000-0x0000000001ffffff]
Movable zone start for each node
Early memory node ranges
  node   0: [mem 0x0000000000000000-0x0000000001ffffff]
Initmem setup node 0 [mem 0x0000000000000000-0x0000000001ffffff]
random: get_random_bytes called from 0x802f36ec with crng_init=0
Built 1 zonelists, mobility grouping on.  Total pages: 8128
Kernel command line: console=ttyS0,57600
PID hash table entries: 128 (order: -3, 512 bytes)
Dentry cache hash table entries: 4096 (order: 2, 16384 bytes)
Inode-cache hash table entries: 2048 (order: 1, 8192 bytes)
Writing ErrCtl register=0002f9d0
Readback ErrCtl register=0002f9d0
Memory: 28000K/32768K available (2524K kernel code, 152K rwdata, 336K rodata, 1204K init, 186K bss, 4768K reserved, 0K cma-reserv)
SLUB: HWalign=32, Order=0-3, MinObjects=0, CPUs=1, Nodes=1
NR_IRQS: 256
CPU Clock: 320MHz
timer_probe: no matching timers found
clocksource: MIPS: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 11945377789 ns
sched_clock: 32 bits at 160MHz, resolution 6ns, wraps every 13421772796ns
Calibrating delay loop... 212.58 BogoMIPS (lpj=1062912)
pid_max: default: 32768 minimum: 301
Mount-cache hash table entries: 1024 (order: 0, 4096 bytes)
Mountpoint-cache hash table entries: 1024 (order: 0, 4096 bytes)
clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 19112604462750000 ns
futex hash table entries: 256 (order: -1, 3072 bytes)
pinctrl core: initialized pinctrl subsystem
NET: Registered protocol family 16
rt2880_gpio 10000600.gpio: registering 24 gpios
rt2880_gpio 10000600.gpio: registering 24 irq handlers
clocksource: Switched to clocksource MIPS
NET: Registered protocol family 2
TCP established hash table entries: 1024 (order: 0, 4096 bytes)
TCP bind hash table entries: 1024 (order: 0, 4096 bytes)
TCP: Hash tables configured (established 1024 bind 1024)
UDP hash table entries: 256 (order: 0, 4096 bytes)
UDP-Lite hash table entries: 256 (order: 0, 4096 bytes)
NET: Registered protocol family 1
rt-timer 10000100.timer: maximum frequency is 3255Hz
workingset: timestamp_bits=30 max_order=13 bucket_order=0
squashfs: version 4.0 (2009/01/31) Phillip Lougher
io scheduler noop registered
io scheduler deadline registered (default)
Serial: 8250/16550 driver, 2 ports, IRQ sharing disabled
console [ttyS0] disabled
10000c00.uartlite: ttyS0 at MMIO 0x10000c00 (irq = 20, base_baud = 6666666) is a Palmchip BK-3103
console [ttyS0] enabled
console [ttyS0] enabled
bootconsole [early0] disabled
bootconsole [early0] disabled
1f000000.cfi: Found 1 x16 devices at 0x0 in 16-bit bank. Manufacturer ID 0x0000c2 Chip ID 0x0022a8
Amd/Fujitsu Extended Query Table at 0x0040
  Amd/Fujitsu Extended Query version 1.1.
number of CFI chips: 1
4 fixed-partitions partitions found on MTD device 1f000000.cfi
Creating 4 MTD partitions on "1f000000.cfi":
0x000000000000-0x000000030000 : "u-boot"
0x000000030000-0x000000040000 : "u-boot-env"
0x000000040000-0x000000050000 : "factory"
0x000000050000-0x000000400000 : "firmware"
libphy: Fixed MDIO Bus: probed
rt3050-esw 10110000.esw: link changed 0x01
mtk_soc_eth 10100000.ethernet eth0: mediatek frame engine at 0xb0100000, irq 5
rt2880_wdt 10000120.watchdog: Initialized
NET: Registered protocol family 17
VFS: Cannot open root device "(null)" or unknown-block(0,0): error -6
Please append a correct "root=" boot option; here are the available partitions:
1f00             192 mtdblock0 
 (driver?)
1f01              64 mtdblock1 
 (driver?)
1f02              64 mtdblock2 
 (driver?)
1f03            3776 mtdblock3 
 (driver?)
Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)
Rebooting in 1 seconds..

This is quite strange really, since it works with the same kernel over TFTP from what I can see. Will try to debug more, maybe there's a boot parameter missing or something like that.

Upon booting up again on a the image over TFTP the partitions actually seems to have changed:

root@OpenWrt:/# cat /proc/mtd 
dev:    size   erasesize  name
mtd0: 00030000 00010000 "u-boot"
mtd1: 00010000 00010000 "u-boot-env"
mtd2: 00010000 00010000 "factory"
mtd3: 003b0000 00010000 "firmware"

Prior to reflashing it the layout looked correct:

root@OpenWrt:/# cat /proc/mtd 
dev:    size   erasesize  name
mtd0: 00030000 00010000 "u-boot"
mtd1: 00010000 00010000 "u-boot-env"
mtd2: 00010000 00010000 "factory"
mtd3: 003b0000 00010000 "firmware"
mtd4: 00132cb0 00010000 "kernel"
mtd5: 0027d350 00010000 "rootfs"
mtd6: 00070000 00010000 "rootfs_data"

So something actually seems to go wrong when the emergency web interface writes the image, not successfully getting the rootfs and rootfs_data partitions setup. At least that means it's not a driver issue I guess.