<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Ubuntu on Sysadmin Tales</title>
    <link>https://blog.ssb-tech.net/tags/ubuntu/</link>
    <description>Recent content in Ubuntu on Sysadmin Tales</description>
    <generator>Hugo</generator>
    <language>en-us</language>
    <lastBuildDate>Fri, 02 Oct 2026 21:39:10 -0400</lastBuildDate>
    <atom:link href="https://blog.ssb-tech.net/tags/ubuntu/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Setting up brscan-skey with the Brother DS-940DW on Ubuntu</title>
      <link>https://blog.ssb-tech.net/posts/linux-scanning-ds940dw/</link>
      <pubDate>Fri, 13 Jun 2025 18:58:09 -0400</pubDate>
      <guid>https://blog.ssb-tech.net/posts/linux-scanning-ds940dw/</guid>
      <description>&lt;h1 id=&#34;setting-up-brscan-skey-with-the-brother-ds-940dw-on-ubuntu&#34;&gt;Setting up brscan-skey with the Brother DS-940DW on Ubuntu&lt;/h1&gt;&#xA;&lt;h2 id=&#34;overview&#34;&gt;Overview&lt;/h2&gt;&#xA;&lt;p&gt;The Brother DS-940DW is a little handheld mobile scanner. Getting it working on Linux in a way where you can actually use the Start/Stop button on the scanner to scan things was a bit of a bear, so I thought I&amp;rsquo;d document how I did it.&lt;/p&gt;&#xA;&lt;p&gt;Part of the issue is that brscan-skey depends on the old version of &lt;code&gt;libsane&lt;/code&gt;, and does not work with &lt;code&gt;libsane1&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;solving-the-dependency-problem&#34;&gt;Solving the dependency problem&lt;/h2&gt;&#xA;&lt;p&gt;First, install the provided driver from the &lt;a href=&#34;https://support.brother.com/g/b/downloadlist.aspx?c=us&amp;amp;lang=en&amp;amp;prod=ds940dw_us_eu_as&amp;amp;os=128&#34;&gt;support page for the DS-940DW&lt;/a&gt;&#xA;You can grab the scan-key-tool deb package from &lt;a href=&#34;https://download.brother.com/welcome/dlf006652/brscan-skey-0.3.4-0.amd64.deb&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Going by &lt;a href=&#34;https://support.brother.com/g/b/faqend.aspx?c=as_ot&amp;amp;lang=en&amp;amp;prod=dcpl2600d_eu_as&amp;amp;faqid=faq00100811_000&#34;&gt;this Brother support article&lt;/a&gt;, I was able to get brscan-skey installed.&lt;/p&gt;&#xA;&lt;h3 id=&#34;steps&#34;&gt;Steps&lt;/h3&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;sudo su&#xA;apt update&#xA;apt install sane libsane1 sane-utils imagemagick&#xA;wget -c http://jp.archive.ubuntu.com/ubuntu/pool/universe/s/sane-backends/libsane_1.1.1-5_amd64.deb&#xA;dpkg -i libsane_1.1.1-5_amd64.deb&#xA;apt install evince&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;configure-scanning&#34;&gt;Configure scanning&lt;/h2&gt;&#xA;&lt;p&gt;I had all sorts of fun figuring out how this all works, and honestly it&amp;rsquo;s pretty simple.&lt;/p&gt;&#xA;&lt;p&gt;Pressing the Start/Stop button on the scanner while brscan-skey is running calls this shell script:&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;/opt/brother/scanner/brscan-skey/script/scantofile.sh&lt;/code&gt;&lt;/p&gt;&#xA;&lt;p&gt;You can have it do whatever you want by editing the script.&lt;/p&gt;&#xA;&lt;p&gt;By default it uses psutils and pod2pdf, and a bunch of other utilities to scan first to PostScript, then convert it to PDF.&lt;/p&gt;&#xA;&lt;p&gt;I don&amp;rsquo;t often have the need to scan complex documents, so I simplified this quite a bit, as I&amp;rsquo;ll show you here in second.&lt;/p&gt;&#xA;&lt;p&gt;But before we do anything, we need to add some udev rules.&lt;/p&gt;&#xA;&lt;p&gt;Create a file at &lt;code&gt;/etc/udev/rules.d/NN-brother-mfp-brscan5-1.0.2-2.rules&lt;/code&gt; with the following content:&lt;/p&gt;&#xA;&lt;h3 id=&#34;udev-rules&#34;&gt;udev rules&lt;/h3&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;ACTION!=&amp;#34;add&amp;#34;, GOTO=&amp;#34;brother_mfp_end&amp;#34;&#xA;SUBSYSTEM==&amp;#34;usb&amp;#34;, GOTO=&amp;#34;brother_mfp_udev_1&amp;#34;&#xA;SUBSYSTEM!=&amp;#34;usb_device&amp;#34;, GOTO=&amp;#34;brother_mfp_end&amp;#34;&#xA;LABEL=&amp;#34;brother_mfp_udev_1&amp;#34;&#xA;&#xA;ATTRS{idVendor}==&amp;#34;04f9&amp;#34;, GOTO=&amp;#34;brother_mfp_udev_2&amp;#34;&#xA;GOTO=&amp;#34;brother_mfp_end&amp;#34;&#xA;LABEL=&amp;#34;brother_mfp_udev_2&amp;#34;&#xA;&#xA;ATTRS{bInterfaceClass}!=&amp;#34;0ff&amp;#34;, GOTO=&amp;#34;brother_mfp_end&amp;#34;&#xA;ATTRS{bInterfaceSubClass}!=&amp;#34;0ff&amp;#34;, GOTO=&amp;#34;brother_mfp_end&amp;#34;&#xA;ATTRS{bInterfaceProtocol}!=&amp;#34;0ff&amp;#34;, GOTO=&amp;#34;brother_mfp_end&amp;#34;&#xA;&#xA;MODE=&amp;#34;0666&amp;#34;&#xA;GROUP=&amp;#34;scanner&amp;#34;&#xA;ENV{libsane_matched}=&amp;#34;yes&amp;#34;&#xA;LABEL=&amp;#34;brother_mfp_end&amp;#34;&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Reload udev rules:&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;sudo udevadm control --reload &amp;amp;&amp;amp; sudo udevadm trigger&lt;/code&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;scanner-group&#34;&gt;Scanner group&lt;/h3&gt;&#xA;&lt;p&gt;You&amp;rsquo;ll also want to add the user you want doing the scanning to the scanner group.&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;sudo usermod -aG scanner &amp;lt;username&amp;gt;&lt;/code&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;systemd-service&#34;&gt;Systemd service&lt;/h3&gt;&#xA;&lt;p&gt;I created a systemd service to run brscan-skey at boot.&lt;/p&gt;&#xA;&lt;p&gt;Create the following at &lt;code&gt;/etc/systemd/system/brscan-skey.service&lt;/code&gt;&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;[Unit]&#xA;Description=Brother scan-key-tool&#xA;&#xA;[Service]&#xA;User=scott&#xA;Type=forking&#xA;ExecStart=/opt/brother/scanner/brscan-skey/brscan-skey&#xA;ExecStop=/opt/brother/scanner/brscan-skey/brscan-skey --terminate&#xA;&#xA;[Install]&#xA;WantedBy=multi-user.target&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Run the following commands:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;sudo systemctl daemon-reload&#xA;sudo systemctl enable --now brscan-skey.service&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You may need to reboot. I did.&lt;/p&gt;&#xA;&lt;h3 id=&#34;simple-scantofilesh-script&#34;&gt;Simple scantofile.sh script&lt;/h3&gt;&#xA;&lt;p&gt;First make a backup of the existing script, just in case.&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;sudo mv /opt/brother/scanner/brscan-skey/script/scantofile.sh /opt/brother/scanner/brscan-skey/script/scantofile.sh.bak&lt;/code&gt;&lt;/p&gt;&#xA;&lt;p&gt;Now we create our own version:&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;sudo vim /opt/brother/scanner/brscan-skey/script/scantofile.sh&lt;/code&gt;&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#! /bin/sh&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;set +o noclobber&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;BASE&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;$HOME/brscan&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pdf_name&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;date | sed s/&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39; &amp;#39;&lt;/span&gt;/&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;_&amp;#39;&lt;/span&gt;/g | sed s/&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;\:&amp;#39;&lt;/span&gt;/&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;_&amp;#39;&lt;/span&gt;/g&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;output_full&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$BASE&lt;span style=&#34;color:#e6db74&#34;&gt;/&lt;/span&gt;$pdf_name&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# scan the image in using scanimage&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;scanimage -x 215.9 -y 279.4 --format&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;png &amp;gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$output_full&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;.png&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Convert to PDF using imagemagick&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;convert &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$output_full&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;.png &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$output_full&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;.pdf&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Created file &lt;/span&gt;$output_full&lt;span style=&#34;color:#e6db74&#34;&gt;.pdf&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Cleanup&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rm &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$output_full&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;.png&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;My script assumes a lot of things. It assumes that you&amp;rsquo;re using letter size paper, for one. This was a really quick and dirty hack - maybe I&amp;rsquo;ll refactor this in the future.&lt;/p&gt;&#xA;&lt;h2 id=&#34;future-goals&#34;&gt;Future goals&lt;/h2&gt;&#xA;&lt;p&gt;My goal for getting this working was to have a small, low power x86 PC that just runs this and nothing else. It&amp;rsquo;s connected via WiFi so I can put it anywhere, and hopefully make it so that I &lt;em&gt;actually use it&lt;/em&gt;.&lt;/p&gt;&#xA;&lt;p&gt;I have it exposing an NFS share that I&amp;rsquo;m going to mount as an ingestion folder for &lt;a href=&#34;https://docs.paperless-ngx.com/&#34;&gt;Paperless-NGX&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Maybe I&amp;rsquo;ll create another blog post soon showing how I got that set up.&lt;/p&gt;&#xA;</description>
    </item>
  </channel>
</rss>
