This Time Self-Hosted
dark mode light mode Search

You know that your health took a bad turn when…

… your medical records folder is ten times thicker than the job contracts folder. I was cleaning up through the paperwork yesterday and today, and there are so many things.. Luckily I have most of my CT scans in digital format, beside the last one I did at the ER last week, and a cerebral CT from a few months ago. But the release paperwork I had only in printed form, which I needed to scan and “PDFize” on Tuesday to send to my GP — nice to have one who’s reachable via e-mail.

It’s the scanning that actually made me think a bit. I have the scanner a bit far from my workstation; to scan a five pages document I have to prepare the scanimage command in batch mode on the workstation, then walk all around my desk to get to the scanner, and then get my arm around the monitor to press the return key on the keyboard to start the scan.

The annoying thing is that the scanner has four buttons on it, that should be made just for the task of starting the scan. Unfortunately these buttons don’t work out of the box on Linux at all. There is a package, called scanbuttond that polls for them through libusb and then execute a custom script when they are pressed. But as you can guess, polling means it uses a lot of CPU, and the fact that they run a generic script makes it less integrable in a desktop environment. Of course it would be easy to port scanbuttond to submit the read buttons back into the kerel input subsystem so that they appear as generic events, but… I think this should be a task well suited for a kernel module, hooking them up directly in the input subsystem, so that evdev could pick them up and then a program could just wait for them as shortcuts to have some action.

I tried looking into writing something before, but I ended up stuck in a problem: would a kernel module interfacing with the scanner interfere with libusb access by sane itself? Last time I enquired Greg KH, he asked me to proivde lsusb -vv output but, sorry Greg, work piled up and I forgot about all of it (until yesterday when I had to scan some more documents). Well, if anybody wants to take a look, this is it for my current scanner:

Bus 001 Device 003: ID 04b8:0121 Seiko Epson Corp. Perfection 2480 Photo
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               2.00
  bDeviceClass          255 Vendor Specific Class
  bDeviceSubClass       255 Vendor Specific Subclass
  bDeviceProtocol       255 Vendor Specific Protocol
  bMaxPacketSize0        64
  idVendor           0x04b8 Seiko Epson Corp.
  idProduct          0x0121 Perfection 2480 Photo
  bcdDevice            0.00
  iManufacturer           1 EPSON
  iProduct                2 EPSON Scanner
  iSerial                 0 
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength           39
    bNumInterfaces          1
    bConfigurationValue     1
    iConfiguration          0 
    bmAttributes         0xc0
      Self Powered
    MaxPower              100mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           3
      bInterfaceClass       255 Vendor Specific Class
      bInterfaceSubClass    255 Vendor Specific Subclass
      bInterfaceProtocol    255 Vendor Specific Protocol
      iInterface              0 
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x81  EP 1 IN
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0200  1x 512 bytes
        bInterval               0
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x02  EP 2 OUT
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0200  1x 512 bytes
        bInterval               0
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x83  EP 3 IN
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0008  1x 8 bytes
        bInterval              16
Device Qualifier (for other device speed):
  bLength                10
  bDescriptorType         6
  bcdUSB               2.00
  bDeviceClass          255 Vendor Specific Class
  bDeviceSubClass       255 Vendor Specific Subclass
  bDeviceProtocol       255 Vendor Specific Protocol
  bMaxPacketSize0        64
  bNumConfigurations      1
Device Status:     0x0001
  Self Powered

Can anybody tell if it would be possible for a kernel module and sane to access it at once? 🙂

If there is the chance, I might look at it once I feel better. I haven’t written or touched a kernel module in so much time that I’m feeling like doing some work in that regard. And the code to actually get the data out of the scanner should be present in scanbuttond already, it’s just a matter of getting it “pushed in” rather than “polled for”.

Once I could get the buttons working, I’d probably be working on a GTK-based frontend for scanimage with handling of those, so I could just use those rather than having to set it up manually. Although the nice thing of scanimage is that, through that, tiffcp and tiff2pdf, I can quickly create a multi-page PDF of the scan (the first command creates a multi-page TIFF file, the second converts it to PDF), and if I do the scan in lineart (the perfect solution for B/W text) it also is tremendously small in size. I should try to have the same result with my frontend. My idea would be a light frontend written in Ruby, calling the commands directly.

Oh well, at any rate, this will have to wait till I’m feeling really better, or maybe it’s just unfeasible because of the way it’d need to access the scanner from kernel and libusb.

Comments 3
  1. There is only one interface so you can only drive it once. If a kernel driver has claimed the interface, a userspace app such as scanbuttond or sane will not be able to.Same applies for userspace. If one application has claimed the interface, another app will not be able to use the device. scanbuttond works around this by only having the device open and interface claimed for very short periods of time.

  2. What made me think about that is that @lomoco@ and similar projects can change some settings in Logitech mice, and they seem to act on the same HID interface as used by the kernel (unless the kernel uses the HID BP, which I doubt since I disabled it). That would be a single USB interface driven by both kernel _and_ libusb…

  3. The difference is that lomoco uses the control pipe only, which is not part of any interface (so no interface needs to be claimed).

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.