Using Linear Flash PCMCIA Cards on Modern Desktop Computers

Stuart Schmitt, 3 January 2021

Introduction

While PCMCIA linear flash is an obsolete technology, numerous devices using these cards remain in service. In the Linux world, linear flash cards are a type of Memory Technology Device, or MTD. Wonderfully, MTDs are still fully supported.

The Linux MTD implementation is an excellent alternative to Windows options. Many people resort to using antiquated laptop computers from the early 2000s running Windows 2000 or XP. There, one can use an abandoned program called Memory Card Explorer. Obtaining and maintaining such old hardware is burdensome, and the unsupported operating system poses a security threat.

Disclaimer: I am not an expert in MTDs or PCI bridges. I likely cannot provide any support for your efforts. I wrote this document because I have found no other guides that were either up-to-date or comprehensive.

Contents

  1. Hardware and software requirements
  2. Configuration
  3. Operation
  4. Appendix: System logs

Hardware and software requirements

  1. Desktop computer
  2. PCI Express to PCI bridge
  3. PCI to PCMCIA adapter
  4. GNU/Linux

Configuration

  1. Install your hardware.
  2. Install the necessary software packages. On Ubuntu, run sudo apt install mtd-utils pcmciautils.
  3. Use lspci -v to identify the PCMCIA adapter's memory window and I/O base addresses. For example, the relevant snippet of output on my system was the following:
    08:00.0 CardBus bridge: Texas Instruments PCI1410 PC card Cardbus Controller (rev 01)
    	Subsystem: SCM Microsystems PCI1410 PC card Cardbus Controller
    	Flags: bus master, medium devsel, latency 168, IRQ 19
    	Memory at a4000000 (32-bit, non-prefetchable) [size=4K]
    	Bus: primary=08, secondary=09, subordinate=09, sec-latency=176
    	Memory window 0: a2000000-a3ffffff (prefetchable)
    	Memory window 1: a4080000-a40fffff
    	I/O window 0: 00003000-000030ff
    	I/O window 1: 00003400-000034ff
    	16-bit legacy interface ports at 0001
    	Capabilities: [a0] Power Management version 1
    	Kernel driver in use: yenta_cardbus
    	Kernel modules: yenta_socket
    
  4. Note the Memory window and I/O window entries, and add them to /etc/pcmcia/config.opts with 0x prefixes:
    include memory 0xa2000000-0xa3ffffff
    include memory 0xa4000000-0xa40fffff
    include port 0x3000-0x30ff
    include port 0x3400-0x34ff
    
    You probably only need those lines in /etc/pcmcia/config.opts and nothing else. You do not need device, module, or card directives; those were used in pre-2.6.13 Linux PCMCIA implementations.

    While it looks like the two contiguous memory windows could be combined in to a single include directive, do not do it. It will not work, and I don't know why.
  5. At this point, you may want to insert a card and reboot. If everything works as intended, you will find a new device entry /dev/mtd0. That's your card!
  6. Check your card voltage with sudo pccardctl status:
    Socket 0:
      3.3V
     16-bit
     PC Card
      Subdevice 0 (function 0) bound to driver "pcmciamtd"
    
    In my example, the card is recognized as a 3.3 V device. However, I know that all of my cards are 5 V cards. Writing (“programming”) may be unsuccessful at 3.3 V. This is apparently a common issue; the programming voltage can be overridden with options supplied to the pcmciamtd kernel device. Since I don't anticipate ever using 3.3 V cards, I hard-coded the option into my system configuration:
    sudo bash -c 'echo "options pcmciamtd vpp=50 setvpp=1" > /etc/modprobe.d/pcmciamtd.conf'
    
    Caution: Only do this if you are sure it is the right thing to do. 5 V will damage cards that are designed for 3.3 V.

The next three steps are optional, for convenience of using MTD cards without root privileges.

  1. Add a “flash” group for users who can write cards. Either use addgroup or edit /etc/group.
  2. Create a udev rule to set permissions for members of “flash”:
    SUBSYSTEM=="mtd", MODE="0660", GROUP="flash"
    
    For example,
    sudo bash -c 'echo "SUBSYSTEM==\"mtd\", MODE=\"0660\", GROUP=\"flash\"" > /etc/udev/rules.d/99-pcmciamtd.rules'
    
  3. Modify the sudoers list (with sudo visudo) to give permission to members of “flash” to use pccardctl:
    %flash ALL=(ALL) NOPASSWD: /sbin/pccardctl
    

If things are not working, I'm sorry. Best of luck figuring it out. Possibly the syslog output below will be helpful.

Operation

  1. When using a card for the first time, examine its details using mtd_debug info /dev/mtd0:
    schmitt@electra:~/card_bin$ mtd_debug info /dev/mtd0
    mtd.type = MTD_NORFLASH
    mtd.flags = MTD_CAP_NORFLASH
    mtd.size = 33554432 (32M)
    mtd.erasesize = 262144 (256K)
    mtd.writesize = 1 
    mtd.oobsize = 0 
    regions = 1
    
    region[0].offset = 0x00000000
    region[0].erasesize = 262144 (256K)
    region[0].numblocks = 128
    region[0].regionindex = 0
    
    Note the mtd.size value. You may find that useful for reading and writing.
  2. To read a card, you have a some choices:
    pv -s [size] < /dev/mtd0 > [output filename]
    dd status=progress if=/dev/mtd0 of=[output filename]
    mtd_debug read /dev/mtd0 0 [size] [output filename]
    cat /dev/mtd0 > [output filename]
    I favor pv because it has a status bar:
    schmitt@electra:~/card_bin$ pv -s 33554432 < /dev/mtd0 > read.bin
    10.6MiB 0:00:09 [1.19MiB/s] [====================>                                     ] 33% ETA 0:00:18
    
  3. Writing a card involves first erasing and then writing. Unlike reading, you must use MTD-specific programs to write flash cards. I am aware of two options:
    flashcp -v [input filename] /dev/mtd0
    mtd_debug erase /dev/mtd0 0 [size]   followed by   mtd_debug write /dev/mtd0 0 [size] [input filename]
    The first option is probably the easiest, and it also reads back the data to ensure a successful copy:
    schmitt@electra:~/card_bin$ flashcp -v new_image.bin /dev/mtd0
    Erasing blocks: 128/128 (100%)
    Writing data: 32768k/32768k (100%)
    Verifying data: 32768k/32768k (100%)
    
    Direct tools such as dd, pv, and cat will corrupt the data due to the flash chip's NOR operation, and the card will be unusable until erased.
  4. Finally, eject the card:
    schmitt@electra:~/card_bin$ sudo pccardctl eject
    
    You are now able to remove the card and insert another. The udev system should detect the card insertion. This also means that you can insert a card at any time after system boot.

    I have found that the PCMCIA system will freeze the computer on reboot/shutdown if a linear flash card has been present at any time since boot but is now absent. Therefore, if you have completed your session of working with linear flash cards, it is safer to power down the system before removing the last linear flash card.

Appendix: System logs

Successful startup of the PCMCIA and MTD systems:

Jan  1 15:42:30 electra kernel: [    4.943633] yenta_cardbus 0000:08:00.0: CardBus bridge found [133f:3000]
Jan  1 15:42:30 electra kernel: [    4.943663] yenta_cardbus 0000:08:00.0: can't claim BAR 16 [mem 0xa0000000-0xa1ffffff]: no compatible bridge window
Jan  1 15:42:30 electra kernel: [    4.943663] yenta_cardbus 0000:08:00.0: Preassigned resource 3 busy or not available, reconfiguring...
Jan  1 15:42:30 electra kernel: [    4.943665] yenta_cardbus 0000:08:00.0: CardBus bridge to [bus 09]
Jan  1 15:42:30 electra kernel: [    4.943666] yenta_cardbus 0000:08:00.0:   bridge window [io  0x3000-0x30ff]
Jan  1 15:42:30 electra kernel: [    4.943670] yenta_cardbus 0000:08:00.0:   bridge window [io  0x3400-0x34ff]
Jan  1 15:42:30 electra kernel: [    4.943675] yenta_cardbus 0000:08:00.0:   bridge window [mem 0xa2000000-0xa3ffffff pref]
Jan  1 15:42:30 electra kernel: [    4.943679] yenta_cardbus 0000:08:00.0:   bridge window [mem size 0x00080000]
Jan  1 15:42:30 electra kernel: [    4.943688] yenta_cardbus 0000:08:00.0: Enabling burst memory read transactions
Jan  1 15:42:30 electra kernel: [    4.943693] yenta_cardbus 0000:08:00.0: Using CSCINT to route CSC interrupts to PCI
Jan  1 15:42:30 electra kernel: [    4.943693] yenta_cardbus 0000:08:00.0: Routing CardBus interrupts to PCI
Jan  1 15:42:30 electra kernel: [    4.943698] yenta_cardbus 0000:08:00.0: TI: mfunc 0x00001d92, devctl 0x02
Jan  1 15:42:30 electra kernel: [    5.189184] yenta_cardbus 0000:08:00.0: ISA IRQ mask 0x0000, PCI irq 19
Jan  1 15:42:30 electra kernel: [    5.189187] yenta_cardbus 0000:08:00.0: Socket status: 10000051
Jan  1 15:42:30 electra kernel: [    5.189189] yenta_cardbus 0000:08:00.0: pcmcia: parent PCI bridge window: [io  0x3000-0x4fff]
Jan  1 15:42:30 electra kernel: [    5.189190] yenta_cardbus 0000:08:00.0: pcmcia: parent PCI bridge window: [mem 0xa2000000-0xa40fffff]
Jan  1 15:42:30 electra kernel: [    5.189191] pcmcia_socket pcmcia_socket0: cs: memory probe 0xa2000000-0xa40fffff:
Jan  1 15:42:30 electra kernel: [    5.189193]  excluding 0xa2000000-0xa40fffff
Jan  1 15:42:30 electra kernel: [    5.189195] yenta_cardbus 0000:08:00.0: pcmcia: parent PCI bridge window: [mem 0xa0000000-0xa1ffffff 64bit pref
Jan  1 15:42:30 electra kernel: [    5.189195] pcmcia_socket pcmcia_socket0: cs: memory probe 0xa0000000-0xa1ffffff:
Jan  1 15:42:30 electra kernel: [    5.189197]  excluding 0xa0000000-0xa1ffffff
Jan  1 15:42:30 electra kernel: [    5.204854] pcmcia_socket pcmcia_socket0: cs: memory probe 0xa2000000-0xa3ffffff:
Jan  1 15:42:30 electra kernel: [    5.204857]  excluding 0xa2000000-0xa3ffffff
Jan  1 15:42:30 electra kernel: [    5.204865] pcmcia_socket pcmcia_socket0: cs: memory probe 0xa4000000-0xa40fffff:
Jan  1 15:42:30 electra kernel: [    5.204865]  excluding 0xa4000000-0xa400ffff 0xa4080000-0xa40fffff
Jan  1 15:42:30 electra kernel: [    6.104489] pcmcia_socket pcmcia_socket0: pccard: PCMCIA card inserted into slot 0
Jan  1 15:42:30 electra kernel: [    6.104490] pcmcia_socket pcmcia_socket0: cs: memory probe 0xa4010000-0xa407ffff:
Jan  1 15:42:30 electra kernel: [    6.118285]  excluding 0xa407c000-0xa4081fff
Jan  1 15:42:30 electra kernel: [    6.118708] pcmcia 0.0: pcmcia: registering new device pcmcia0.0 (IRQ: 19)
Jan  1 15:42:30 electra kernel: [    6.130737] pcmciamtd 0.0: pcmcia: could not parse base and rmask0 of CIS
Jan  1 15:42:30 electra kernel: [    6.135487] MR032FLF14PCG 32MB FLASH CARD SERIES SV+   : Found 2 x16 devices at 0x0 in 16-bit bank. Manufacture
Jan  1 15:42:30 electra kernel: [    6.136850] Intel/Sharp Extended Query Table at 0x0031
Jan  1 15:42:30 electra kernel: [    6.136912] Intel/Sharp Extended Query Table at 0x0031
Jan  1 15:42:30 electra kernel: [    6.136977] Using buffer write method
Jan  1 15:42:30 electra kernel: [    6.136978] cfi_cmdset_0001: Erase suspend on write enabled
Jan  1 15:42:30 electra kernel: [    6.136978] erase region 0: offset=0x0,size=0x40000,blocks=128
Jan  1 15:42:30 electra kernel: [    6.138560] pcmciamtd 0.0: mtd0: MR032FLF14PCG 32MB FLASH CARD SERIES SV+   

Unsuccessful startup due to use of an ASM1083 bridge:

Jan  1 11:16:42 electra kernel: [   71.465297] yenta_cardbus 0000:03:00.0: CardBus bridge found [123f:3000]
Jan  1 11:16:42 electra kernel: [   71.465340] yenta_cardbus 0000:03:00.0: Using INTVAL to route CSC interrupts to PCI
Jan  1 11:16:42 electra kernel: [   71.465340] yenta_cardbus 0000:03:00.0: Routing CardBus interrupts to ISA
Jan  1 11:16:42 electra kernel: [   71.465344] yenta_cardbus 0000:03:00.0: TI: mfunc 0x00001c92, devctl 0x02
Jan  1 11:16:42 electra kernel: [   71.465346] yenta_cardbus 0000:03:00.0: Yenta TI: no PCI interrupts. Fish. Please report.
Jan  1 11:16:42 electra kernel: [   71.465349] yenta_cardbus 0000:03:00.0: no PCI IRQ, CardBus support disabled for this socket.
Jan  1 11:16:42 electra kernel: [   71.465349] yenta_cardbus 0000:03:00.0: check your BIOS CardBus, BIOS IRQ or ACPI settings.
Jan  1 11:16:43 electra kernel: [   71.601137] yenta_cardbus 0000:03:00.0: ISA IRQ mask 0x0000, PCI irq 0
Jan  1 11:16:43 electra kernel: [   71.601147] yenta_cardbus 0000:03:00.0: Socket status: 10000051
Jan  1 11:16:43 electra kernel: [   71.601158] yenta_cardbus 0000:03:00.0: pcmcia: parent PCI bridge window: [io  0x3000-0x4fff]
Jan  1 11:16:43 electra kernel: [   71.601161] yenta_cardbus 0000:03:00.0: pcmcia: parent PCI bridge window: [mem 0xa2000000-0xa40fffff]
Jan  1 11:16:43 electra kernel: [   71.601166] pcmcia_socket pcmcia_socket0: cs: memory probe 0xa2000000-0xa40fffff:
Jan  1 11:16:43 electra kernel: [   71.601176]  excluding 0xa2000000-0xa40fffff
Jan  1 11:16:43 electra kernel: [   71.601182] yenta_cardbus 0000:03:00.0: pcmcia: parent PCI bridge window: [mem 0xa0000000-0xa1ffffff 64bit pref
Jan  1 11:16:43 electra kernel: [   71.601185] pcmcia_socket pcmcia_socket0: cs: memory probe 0xa0000000-0xa1ffffff:
Jan  1 11:16:43 electra kernel: [   71.601193]  excluding 0xa0000000-0xa1ffffff
Jan  1 11:16:43 electra kernel: [   71.610999] pcmcia_socket pcmcia_socket0: cs: memory probe 0xa2000000-0xa3ffffff:
Jan  1 11:16:43 electra kernel: [   71.611010]  excluding 0xa2000000-0xa3ffffff
Jan  1 11:16:43 electra kernel: [   71.611047] pcmcia_socket pcmcia_socket0: cs: memory probe 0xa4000000-0xa40fffff:
Jan  1 11:16:43 electra kernel: [   71.611050]  excluding 0xa4000000-0xa400ffff 0xa4080000-0xa40fffff