塩田紳二のPDAレポート

SL-C3000のUSBホスト機能を使う



●USBホスト機能を使う

シャープ SL-C3000

 SL-C3000で利用できるUSBホストケーブルを入手したので、いろいろとためしてみた。その結果、USBメモリの利用も可能であることがわかった。ただし、多少の設定が必要である。ここでは、その手順などを紹介したい。

 SL-C3000に採用されているLinuxでは、USBのドライバはローダブルモジュールという形式でサポートされている。これは、必要に応じてドライバをあとから読み込む仕組みである。SL-C3000は、ミニAケーブルを装着した段階で、USBホスト機能が動作し、コア部分のモジュールが組み込まれる。さらにUSBデバイスを装着することで、必要なドライバが読み込まれる。

 SL-C3000では、標準状態では、USBキーボードだけが利用できる状態になっている。USBメモリに関しては、必要なローダブルモジュールは用意されているが、ファイルシステムとして利用するためのプログラムがなく、手動でマウントすることで利用が可能になる。短いプログラム(スクリプト)を組み込むことで、自動的にファイルシステムとして利用することは可能である。ここでは、その方法を紹介する。

入手したUSBホストケーブル。一方がミニA(オス)、もう一方がシリーズA(メス)になっているもの ミニAコネクタ部分。下側が狭まるような形になっている

■■ 注意 ■■

 Linuxのコマンドを使うため、ある程度はLinuxの知識が必要。たとえば、ファイルのコピーやリネームなど、ファイルを書き換えるときにバックアップするような作業ができないなら危険なのでやらないほうがよい。最悪の場合、Zaurusが起動し無くなる可能性もある。本文中では、記述が繁雑になることを避けるため、このような基本的なLinuxコマンドについては解説していないし、手順も省略してある(たとえばrootになる方法など)。
 また、プログラムのインストールなどにより、SL-C3000内部のファイル状態が変わっている可能性もあり、そのような場合、ここで示した作業を行なっても動作しない可能性がある。ここで示した方法は、筆者が調査した結果に基づき、例として示したもので、すべてのケースで完全に動作することを保証するものではない。
 どのようなことが起こっても、PC Watchおよび筆者は責任を取ることができない。作業はすべて自己責任で行って欲しい。

 USBメモリ(USBマスストレージデバイス)は、Linuxでは、SCSIエミュレーションを介して利用する。つまり、USBメモリをSCSIドライブのようにみせかけ、これをLinuxのファイルシステムとして扱うわけである。

 Linuxでは、こうした外部記憶デバイス(ブロックデバイス)は、単にドライバを組み込むだけでなく、マウントという作業を行ってはじめて、ファイルシステムとして見えるようになる。簡単にいえば、USBメモリは、接続しただけでは、マウントされていない状態のため、自動的にマウント、アンマウント(マウントしたものを取り外す処理)できるようにすれば、USBメモリが簡単に扱えるようになる。

 Linuxのデバイスは、/dev/XXXXという名前で扱われる。これは、devファイルシステムと呼ばれ、デバイス名がファイルシステムと同じくディレクトリ構造になっている。具体的には、/devというディレクトリの下に各種のデバイスを表す特殊なファイルが置かれている。

 SCSIデバイスには、/dev/sd?という名称が付けられ、?の部分は、a、b、c……となる。これが1つのSCSIチャネルに接続されるドライブに対応している。通常、HDDは、パーティションを設定して利用する。SCSIデバイス上のパーティションは、これに数字を付け、

 /dev/sda1、sda2……

 として表現する。デバイス自体を表す/dev/sdaと個々のパーティションを表す/dev/sda1を混同しないように注意してほしい。

 さて、パーティションが1つしかないUSBメモリを1つだけ接続すると/dev/sda1となる。接続しているSCSIデバイスのパーティションを調べるには、以下のコマンドを使う。

fdisk -l /dev/sda

 このコマンドを使えば、指定したデバイス上のすべてのパーティションが表示される。なお、後述するようにUSBメモリの中には、マスターブートレコードにあるパーティションテーブルがきちんと初期化されていないものがある。

 パーティションが1つだけなので、Windowsでは、こうしたUSBメモリも認識してしまう。しかし、Linuxでは、さまざまなパーティション形式を扱うため、マスターブートレコードが正しくないと、きちんとデバイスを認識できない。

 このSCSIエミュレーションは、該当のローダブルモジュールがロードされている間は、USBデバイスを外しても有効である。再度、同じUSBメモリを装着したときに同じ対応になるためだ。しかし、一度ローダブルモジュールを解放してやると、その対応関係が失われ、次に装着したUSBメモリが最初のSCSIデバイスである/dev/sdaとなる。

 なので、一度でもUSBメモリをSL-C3000に接続した場合、ローダブルモジュールを解放しておかないと割当てが変わってしまう可能性がある。これには、SL-C3000を再起動させてもよい。

●USBを扱うためのコマンドなど

 具体的な作業に入る前に、SL-C3000でUSBデバイスを扱う場合に必要になりそうなコマンドなどを簡単に解説しておこう。

・lsusb

 lsusbコマンドは、接続されているUSBデバイスに関する情報を表示するためのもの。書式は、

lsusb
lsusb -v
lsusb -v -s デバイス番号

 である。最初の形式は、すべてのUSBデバイスの簡単な表示を行なうもので、2番目のものは、詳細な表示を行なう。3番目の形式は、特定のデバイス(lsusbで表示されるDevice:以下の数字で特定)の情報を表示するためのもの。以下に実行例を示す。ここで行頭の#はrootの場合のプロンプトである(以後同様)。

[実行例]


# lsusb
Bus 001 Device 001: ID 0000:0000
Bus 001 Device 008: ID 0451:2046 Texas Instruments, Inc. TUSB2046 Hub
Bus 001 Device 013: ID 08ec:0010 M-Systems Flash Disk Pioneers DiskOnKey
# lsusb -v -s 013

Bus 001 Device 013: ID 08ec:0010 M-Systems Flash Disk Pioneers DiskOnKey
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               1.10
  bDeviceClass            0 Interface
  bDeviceSubClass         0
  bDeviceProtocol         0
  bMaxPacketSize0        64
  idVendor           0x08ec M-Systems Flash Disk Pioneers
  idProduct          0x0010 DiskOnKey
  bcdDevice            2.00
    :
    :
 以下省略

・procファイルシステム

/proc/bus/usb /proc/scsi

 /procファイルシステムは、カーネル内部の情報などをファイルシステムとしてアクセスできるようにしてあるもの。このようにすることで多数のパラメータを専用のAPIではなく、ファイルシステムのアクセスで読み書きできる。

 これには通常のファイル用コマンド(cdやls、moreなど)が利用できるし、プログラム中からはopenやreadなどのファイル用の関数が利用できる。Windowsでいえばレジストリみたいなものである。

 このうち、USB関連としては、/proc/bus/usbディレクトリが対応し、SCSI関連の情報は、/proc/scsiにある。ディレクトリの表示には、lsコマンドが、ファイルの表示にはmoreまたはcatプログラムが利用できる。ただし、多くのファイルはテキストとして表示可能だが、中にはバイナリファイルもある。

 USBデバイスを接続すると/proc/bus/usbには、以下のようなディレクトリ、ファイルが現れる。なお、テキスト形式のファイルは、moreコマンドで内容を表示できる。

/proc/bus/usb/001/         最初のUSBインターフェイス
/proc/bus/usb/001/001      最初のUSBデバイス(ホストコントローラ)バイナリファイル
/proc/bus/usb/001/その他   他のUSBデバイス バイナリファイル
/proc/bus/usb/devices      デバイスの情報 テキスト
/proc/bus/usb/drivers      ドライバの情報 テキスト
 /prc/scsiのほうは、
/proc/scsi/scsi             SCSIデバイスに関する情報 テキスト
/proc/scsi/sg               その他のさまざまな情報 テキスト
/proc/scsi/usb-storage-0/   usb-storageデバイスのSCSIエミュレーション情報
/proc/scsi/usb-storage-0/0  最初のデバイス テキスト

 となっている。

・マウント

 Linuxで、パーティションをマウントするには、mountコマンドを使う。

mount [option] パーティション マウントポイント

 パーティションの指定は、「/dev/sda1」などとして行なう。マウントポイントは、そのパーティション内のファイルシステム(ディレクトリツリー)をどのディレクトリに接続するのかを指定する。マウントポイントは、ディレクトリとしてあらかじめ作っておく必要がある。通常は、/mnt以下が使われる。

 オプションは、ファイルシステムやファイルシステム固有のものを指定する。なお、手動で操作するときに毎回、オプションを指定するのは面倒なので、/etc/fstabというファイルにマウント方法を記述しておく。このようにすると、以後のマウント操作は、

mount マウントポイント

 とするだけで行なえる。このfstabは、起動時にファイルシステムを構築するためのもので、これが壊れてしまうと、SL-C3000のHDDやフラッシュメモリがまったく見えなくなってしまう。作業する時には、既存の行を壊さないように十分注意されたい。

 現在のマウント状態は、mountコマンドを引数なしで実行するかdfコマンドを使う。前者は、マウント状態などを表示し、後者は、マウントされたファイルシステムの容量などを表示できる。

[実行例]

# df
Filesystem           1k-blocks      Used Available Use% Mounted on
rootfs                    5120      5120         0 100% /
/dev/root                 5120      5120         0 100% /
/dev/mtdblock3            4096      1936      2160  47% /home
/dev/ram1                   44        29        15  66% /dev
none                      1024       132       892  13% /dev/shm
/dev/hda1                99521     50360     44022  53% /hdd1
/dev/hda2               398282     24412    353307   6% /hdd2
/dev/hda3              3478852   1301588   2177264  37% /hdd3
/dev/mmcda1             248960     78864    170096  32% /usr/mnt.rom/card
/dev/sda1                31528         0     31528   0% /home/system/var/mnt/usbmem
# mount
rootfs on / type rootfs (rw)
/dev/root on / type jffs2 (ro)
/proc on /proc type proc (rw)
/dev/mtdblock3 on /home type jffs2 (rw,noatime)
/dev/ram1 on /dev type minix (rw)
none on /dev/shm type tmpfs (rw)
/dev/hda1 on /hdd1 type ext3 (ro,noatime)
/dev/hda2 on /hdd2 type ext3 (rw,noatime)
/dev/hda3 on /hdd3 type vfat (rw,noatime)
none on /dev/pts type devpts (rw)
/dev/mmcda1 on /usr/mnt.rom/card type vfat (rw,noatime)
none on /proc/bus/usb type usbdevfs (rw)
/dev/sda1 on /home/system/var/mnt/usbmem type vfat (rw,noatime)
#

・ローダブルモジュール関連

 現在ロードされているローダブルモジュールを表示させるには、lsmodコマンドを使う。また、ロードされているローダブルモジュールを解放(アンロード)するには、

rmmod モジュール名

 とする。なお、現在稼働中のモジュールはアンロードすることができない。ローダブルモジュールの組み込みは、USBメモリ(USBマスストレージ)に関しては自動的に行なわれる(実際には、後述するusb.agentsプログラム内で行なわれる)。

●USBメモリについて

 ここでUSBメモリについてちょっとした注意を述べておこう。筆者の手元にあったUSBメモリのうち、SL-C3000で正しく扱えなかったものがいくつかあった。原因は、マスターブートレコード(MBR)にあるパーティションテーブルに不正な値が書き込まれていることだった。

 パーティションが1つしかない場合、Windowsは、こうしたUSBメモリでも認識してしまう。Windowsは、特定のパーティション形式にしか対応していないため、正規の方法を使わなくともパーティションの認識ができるからである。

 しかし、非Microsoft系のパーティション形式にも対応しているLinuxでは、正しいパーティションテーブルがないとパーティションを認識できない。これを接続してしまうと最悪、mount時にプログラムが戻ってこなくなるなどの問題が発生する。なので、SL-C3000で使う前にほかのマシンで一度調べておいたほうがいいだろう。

 パーティションテーブルを調べるには、Microsoftが提供しているdiskmapプログラムが利用できる(Windows用のコンソールコマンド)。これは、以下のURLから入手可能である。使い方は、付属のドキュメントを参照のこと。

□Diskmapプログラム
http://www.microsoft.com/windows2000/techinfo/reskit/tools/existing/diskmap-o.asp

 このようなUSBメモリをSL-C3000に接続してしまうと最悪、プログラムが停止状態となり、再起動が必要になってしまうこともある。できれば、事前にMBRをチェックしておこう。以下に実行例を示す。

[実行例]MBRがおかしい場合

C:\Program Files\Resource Kit>diskmap /d5
Cylinders  HeadsPerCylinder SectorsPerHead BytesPerSector MediaType
        3               255             63            512      11
TrackSize = 32256, CylinderSize = 8225280, DiskSize = 24675840 (23MB)

Signature = 0x00000001
     StartingOffset    PartitionLength StartingSector PartitionNumber
                              31981568              0               1

MBR:
         Starting               Ending       System    Relative    Total
  Cylinder Head Sector  Cylinder Head Sector   ID      Sector      Sectors
       357  116   40         357   32   45     0x72   778135908 1141509631
       288  115   43         367  114   50     0x65   168689522 1936028240
       366   32   33         357   32   43     0x79  1869881465 1936028192
       372   97   50           0   10    0     0x0d           0 3637226496

[実行例]MBRが正しい場合

C:\Program Files\Resource Kit>diskmap /d5
Cylinders  HeadsPerCylinder SectorsPerHead BytesPerSector MediaType
        3               255             63            512      11
TrackSize = 32256, CylinderSize = 8225280, DiskSize = 24675840 (23MB)

Signature = 0x00000000
     StartingOffset    PartitionLength StartingSector PartitionNumber
              16384           32555008             32               1

MBR:
         Starting               Ending       System    Relative    Total
  Cylinder Head Sector  Cylinder Head Sector   ID      Sector      Sectors
         0    1    1         993    1   32     0x04          32      63584
         0    0    0           0    0    0     0x00           0          0
         0    0    0           0    0    0     0x00           0          0
         0    0    0           0    0    0     0x00           0          0

 なお、MBRがおかしい場合、パーティションを再度作り直せば大丈夫だったが、Windows XPでは、XPのインストールCDに入っているDISKPROBEなどが必要となる(\SUPPORT\TOOLSにある)。あるいはLinux側でパーティションを設定し、再度ファイルシステムを構築してもよい。

●手動でUSBメモリをマウントして使う

 とりあえず、手動でUSBメモリをマウントする方法を試してみることにしよう。後述するスクリプトは、この手順を自動化するものである。なお、以後の操作は、rootで行なう。行頭の#はrootの場合のプロンプトである。

 まず、マウントポイントを作る。手順は、

[実行例]

# cd /mnt
# mkdir usbmem

 である。/mntディレクトリを使うのは慣例的なもので、理論的にはどこでもよい。なお、SL-C3000では、このディレクトリは、/home/system/var/mntになる。SL-C3000では、ファイルシステムがリードオンリーのフラッシュメモリ、書き込み可能なフラッシュメモリと3つのHDD上のパーティションの3つから構成されているため、複雑なリンクが貼られている。このために、実際にファイルが存在するディレクトリが違っている場合がある。

 ここで、SL-C3000にUSBメモリを接続してみる。USBメモリにインジケータがあるなら、光るはずである。

 ローダブルモジュールが正しく動作していれば、/proc/scsi以下にusb-storage-0というディレクトリができているはずだ。

[実行例]

# ls /proc/scsi/
scsi           sg             usb-storage-0
#

 この状態で、USBメモリは、/dev/sdaに割り当てられているはずだ。ではパーティションをみてみよう。

[実行例]

# fdisk -l /dev/sda

Disk /dev/sda: 32 MB, 32587776 bytes
2 heads, 32 sectors/track, 994 cylinders
Units = cylinders of 64 * 512 = 32768 bytes

   Device Boot    Start       End    Blocks   Id  System
/dev/sda1             1       994     31792    4  FAT16 <32M

 この実行結果から、USBメモリのパーティションは1つで、それは/dev/sda1であることがわかる。

 では、いよいよマウントしてみる。

[実行例]

# mount -t vfat /dev/sda1 /mnt/usbmem
# df
Filesystem           1k-blocks      Used Available Use% Mounted on
rootfs                    5120      5120         0 100% /
/dev/root                 5120      5120         0 100% /
/dev/mtdblock3            4096      1928      2168  47% /home
/dev/ram1                   44        29        15  66% /dev
none                      1024       124       900  12% /dev/shm
/dev/hda1                99521     50360     44022  53% /hdd1
/dev/hda2               398282     24412    353307   6% /hdd2
/dev/hda3              3478852   1301588   2177264  37% /hdd3
/dev/mmcda1             248960     78864    170096  32% /usr/mnt.rom/card
/dev/sda1                31528         0     31528   0% /home/system/var/mnt/usbmem
【写真01】USBメモリをマウントすると、Zaurusのホーム画面で/dev/sda1が見えるようになる

 一番最後の行に、/dev/sda1が/home/system/var/mnt/usbmemにマウントされていることが表示されている。この状態で、/mnt/usbmemの中をみれば、そこがUSBメモリとなる。なお、ここでは、細かいオプション指定をしていないので、日本語のファイル名は正しく表示されないし、root以外は書き込みもできない。オプション指定については後述する。

 また、この時点で、SL-C3000のホーム画面のファイルタブには、(写真01)のように/dev/sda1が表示される。この状態では、SDカードなどと同じように利用できる。

 USBメモリを取り外したい場合には、アンマウント処理を行なう。もし、何かエラーが表示されたら、USBメモリ内のファイルがオープン途中であったり、カレントディレクトリになっている可能性がある。プログラムを全部終了させるなどして、USBメモリを使っているプロセスがないようにする。

[実行例]

# cd /
# umount /mnt/usbmem

 最後にローダブルモジュールをアンロードする。これにより、USBメモリ用ドライバと/dev/sdaとの関係が無くなり、次回接続したUSBメモリに/dev/sdaが割り当てられるようになる。

[実行例]

# rmmod usb-storage
#

 以上が、USBメモリを手動で利用するための手順である。USBメモリを使うたびに、毎回、ターミナルを起動してこの手順を繰り返すのは大変である。しかし、Linuxには、こうした作業を自動化するための仕組みが用意されている。

●USBデバイスの管理

 では、次に、SL-C3000のLinuxでUSBデバイスがどのように扱われるのかを見ていくことにしよう。

 Linux 2.4では、hotplugという機構が組み込まれ、これを使ってUSBの抜き差しを管理している。多くのLinuxディストリビューションでは、このhotplug部分にmurasakiなどのマネージャを採用しているが、SL-C3000には、素のままのhotplug機構が使われている。なお、この機構は、ZaurusのUSBドライブ機能(ZaurusがUSB大容量ストレージクライアントとなる機能)でも使われている。このため、murasakiなどをインストールすると、USBドライブ機能が利用できなくなる可能性がある。

 hotplugは、以下のような手順でUSBデバイスに必要なモジュールをロードし、関連プログラムを起動する。

1.USBデバイスの接続をカーネルが検出すると/sbin/hotplugが起動される。
 設定としては、/proc/sys/kernel/hotplugで指定されているプログラムが起動される。また、標準の/sbin/hotplugプログラムは、シェルスクリプトである。

2./sbin/hotplugは、デバイスの種類を判別し/etc/hotplug/デバイス.agentを起動する
 USBの場合には、/etc/hotplug/usb.agents

 usb.agentsが、各種のUSBデバイスを判別し、必要に応じた処理を行なう。ただし、標準では、前述のようにUSBキーボードにしか対応していない。usb.agentsもシェルスクリプトで、以下のような動作を行なう。

1.デバイスを判定する
 usb.distmap、usb.handmap、usb.usermapからデバイスの種類を判定する。

2.必要なローダブルモジュールをロードする(hotplug.functionのload_device)

3.デバイスに応じて/etc/hotplug/usb以下のSubsystemプログラムが起動される
 USBメモリが接続された場合には、/etc/hotplug/usb/usb-storageが起動される

4.デバイスが切り離された場合には、REMOVERと呼ばれるプログラムが起動
 これは、/etc/hotplug/usb以下のSubsystemプログラムで用意しておく

 つまり、USBメモリを利用するためには、SubsystemプログラムとREMOVERを用意し、Subsystemプログラムの中でマウントの処理とREMOVERの登録を行なう。また、REMOVERでは、アンマウント処理とローダブルモジュールの解放を行なう。

 事前の準備としては、マウントポイントを作成しておき、マウントオプションなどを指定した行をfstabに追加しておく。

 USBメモリと対応するSCSIデバイスとの対応を判定するのが困難であるため、制限として同時に接続できるUSBメモリは1つだけにした。複数のUSBメモリを接続しても、このスクリプトで自動マウント/アンマウントできるのは、最初に接続したUSBメモリだけで、2個目からは無視される。

 本来、実際のデバイスとエミュレーションされたSCSIデバイスの対応は、scsi_infoプログラムなどを使って判定できるはずだが、SL-C3000では、usb-storageでSCSIデバイスをエミュレーションさせたときにSCSI_IDの割当てがかならずゼロになってしまい、USBメモリとSCSIデバイスの対応を判定することができなかった。

 どのUSBメモリもSCSI_IDがゼロになってしまうので、区別ができないのである。SCSI_IDは、1つのSCSIチャンネルに接続されるデバイスが持つ番号で、SCSIのHDDなどではDIPスイッチなどで設定するもの。つまり、デバイス側がSCSIドライバに報告するものであって、後から割り当てるものではない。このため、usb-storageによるSCSIエミュレーションでは、自分が何番目に装着されたのかがわからないと、SCSI_IDを報告できないため、ゼロになってしまうのだと思われる。

 今回は、最初に装着したUSBメモリが必ず/dev/sdaになるように、アンマウントしたあとにローダブルモジュールをアンロード(メモリから削除)している。このようにしているため、2つ目のUSBメモリが接続されているとき、それがマウントされていなければ、1つ目のUSBメモリを抜いた段階でデバイスが見えなくなってしまう。

 マウントされていないのでデータなどを失う危険はないが、USBメモリを使えるようにするには、抜き差しを行なう必要がある(insmodコマンドでローダブルモジュールをインストールしてもよい)。なお、2つ目のUSBメモリをマウントしているとデバイスがビジーとなるためにrmmodがエラーになり、アンロードは行なわれない。

 アンロードが行なわれない限り、USBメモリとSCSIデバイス名との対応は固定されているため、一度/dev/sdbなどに割り当てられたUSBメモリは、再度装着しても同じSCSIデバイス名が使われてしまう。

 とういわけなので、2つ以上のUSBメモリを同時に利用するのは、できれば避けたほうがよく、やむを得ない場合は、スクリプトの動作などを理解した上で行なって欲しい。使い勝手の点でいえば、SL-C3000はHDDを内蔵しているため、2つのUSBメモリを同時に装着してコピーをしなくても、一旦HDDにコピーすればすむ。というわけでこの仕様でも十分だと思われる。

●実際の作業

 以下の作業は、rootで行なう。なお、root状態では、ほとんどのファイルを削除可能なので、非常に危険なため、注意すること。

 また、ファイルの編集には、viエディタを利用する。Zaurus用のGUIエディタでも編集作業はできるが、ファイル所有者やグループなどの属性、行末コードなどが変わってしまう可能性があるので注意されたい。

・マウントポイントの作成

 まず、マウントポイントを作成しておく。ここでは、usbmemとし、/mntディレクトリに作成した。このディレクトリには、“usbstorage”という名前のディレクトリがあるが、SL-C3000がどのような使い方をするかわからないので、別途マウントポイントを作成した。また、前項の「手動でUSBメモリをマウントして使う」ですでにマウントポイントを作った人は、再度作業をする必要はない。

cd /mnt
mkdir usbmem

・Subsystemプログラム

 【リスト01】のプログラムを/etc/hotplug/usbにusb-storageというファイル名で/etc/hotplug/usbに置く(viを使って入力する)。

【リスト01】

#!/bin/sh
# Created by Shinji Shioda
. /etc/hotplug/hotplug.functions
if [ ! -L /var/run/usb/%proc%bus%usb%* ]; then
  mesg Try to Mount
  mount /mnt/usbmem
  if [ $? = 0 ]; then
    ln -s /etc/hotplug/usb/usb-storage.off $REMOVER
    mesg make REMOVER in $REMOVER
  fi
fi

 置いた後に以下の作業を行ない実行属性を付ける。

cd /etc/hotplug/usb
chmod 755 usb-storage

・REMOVERプログラム

 同様に【リスト02】のプログラムを/etc/hotplug/usb/usb-storage.offとして作成する。その後、同じように実行属性を付ける。

【リスト02】

#!/bin/sh
# Created by Shinji Shioda
. /etc/hotplug/hotplug.functions
mesg Removing /mnt/usbmem
umount /mnt/usbmem
rmmod usb-storage

・fstabの記述

 /etc/fstabに以下の行(1行)を追加する。後半はほとんどオプション指定である。noautoだけがfstab専用のオプションで、あとのオプションは、すべてmountコマンドをコマンドラインから実行する場合の引数として付けるもの。

/dev/sda1       /mnt/usbmem     vfat    noauto,umask=000,noatime,iocharset=utf8,codepage=932    0  0

 この行と同等のことをコマンドラインで直接指定する場合には、

# mount -t vfat -o umask=000,noatime,iocharset=utf8,codepage=932 /dev/sda1 /mnt/usbmem

 とする。これでは面倒なので、上記のようにfstabに予めマウント方法を指定しておくわけだ。

 すべてが正しいことを確認したら、USBメモリを接続する。その後少し時間を置いてからdfコマンドもしくは、mountコマンドで/dev/sda1が/mnt/usbmemにマウントされているかどうかを確認する。マウントされていれば、

ls /mnt/usbmem

 でUSBメモリのルートディレクトリの内容が表示できるはずである。

 その後、/mnt/usbmem以下のファイルやディレクトリを利用しているプログラムがないことを確認して、USBメモリを抜く。ただしくアンマウントされたかどうかをdfやmountコマンドで確認する。

 なお、間違いがないにも関わらずマウントできない場合には、前述のマスターブートレコードを調べたり、/proc/bus/usb、/proc/scsiなどを使って状態を確認する。まれにマウントやアンマウントがうまく行かないこともあるかもしれない。USBメモリが接続されていない状態で/var/run/usbにシンボリックリンク(%proc%bus%usb%001%0??というファイル名)が残っているとマウント処理が行なえないのでこれを削除する。

●プログラムの説明

 ここでは、簡単にスクリプトの内容を解説しておく。プログラムは/bin/sh、つまりUnixオリジナルのBourne シェルで記述されている。

 Subsystemプログラム【リスト01】は、環境変数で各種のパラメータを渡される。渡される引数は、【表01】のようなものである。また、このプログラムが呼び出される前の段階で、すでにローダブルモジュールが組み込まれており、デバイスのタイプ(キーボードなのか、USBメモリなのかなど)が判定されている。なので、/etc/hotplug/usb/usb-storageでは、USBメモリの処理だけを行なえばよい。

【表01】
環境変数注釈
ACTIONadd/removeUSBデバイスではaddまたはremoveのどちらか*1
PRODUCTidVendor/idProduct/bdcDevice左記の値(16進)を/で区切ったもの
TYPEbDeviceClass/bDeviceSubClass/bDeviceProtocol左記の値(16進)を/で区切ったもの
INTERFACEbInterfaceClass/bInterfaceSubClass/bInterfaceProtocol左記の値(16進)を/で区切ったもの
DEVFSusbdevfsへのパス/proc/bus/usbが渡される
DEVICEusbdevfs内のデバイスへのパス(/proc/bus/usb/00x/00x)デバイスに対応する/porc/bus/usb内のファイルへのパス
*1:removeはusb.agents内で処理されるため実際にはaddしか来ない

 実際に行なうのは、マウント操作で、すでにfstabに設定が行なわれているため、

mount /mnt/usbmem

 を実行する。これが成功したら、次のif文の内部が実行されることになる。

 ここでは、/var/run/usb以下にREMOVERプログラムへのシンボリックリンクを作っている。/var/run/usb/以下にあるREMOVERプログラムは、USBメモリを抜いたときに自動的に実行され、その後、削除される。この処理は、/etc/hotplug/usg.agents内で行なわれるため、ここではリンクのみを作っている。

 REMOVERプログラム(usb-storage.off。【リスト02】)は、アンマウントを行ない、ローダブルモジュールを解放する。rmmodは、デバイスがビジーであるときは失敗するが、これは、2つ目以降のUSBメモリが装着されてマウントされていることを意味する。なので、エラー処理は行なっていない。

 なお、mesgは、3行目で読み込んでいる/etc/hotplug/hotplug.functionsで定義されているデバッグ用の関数である。

●新規にusb-storageを登録する

 標準状態で多くのメーカーのUSBメモリが登録されているが、デジカメなどのUSBマスストレージはほとんど登録されていない。これらを使うには、/etc/hotplug/usb.distmapへの登録が必要である。

 ここでは、筆者手持ちのカシオのQV-R4を接続してみることにした。まず、デジカメをUSBマスストレージになるようにしてSL-C3000に接続してみる。この状態で、dfもしくはmountコマンドでマウントされたかどうかを確認する。すでにデータが登録されているなら、マウントが行なわれているはずである。しかし、QV-R4は登録されていなかった。

 まず、lsusbで情報を取得する。

[実行例]lsusb

# lsusb
Bus 001 Device 001: ID 0000:0000
Bus 001 Device 027: ID 07cf:1001 Casio Computer Co., Ltd QV-8000SX/5700/3000EX Digicam

 メーカー名などが表示されているので、2つ目がQV-R4のものだとわかる。プロダクツ名は、lsusbが表示しているので必ずしも正しくない(/usr/share/usb.idsファイルを元に表示を行なっている)。デバイスから取得したベンダー名文字列データなどを見るには/proc/bus/usb/devicesを表示させるといいだろう。

 ここで必要なのは、ID以下の2つの16進数である。この出力では、07cfがメーカー名を表すベンダーコード、コロンの次が製品を表すプロダクツコード(1001)だ。表記は16進数になっている。

 登録を行なうにはこの2つの値を使ってusb.distmapにデータを追加する。usb.dismapは、13個のフィールドをスペースで区切って1レコード分としたデータベースファイルである。行の先頭がデバイスのカテゴリで、USBマスストレージは、“usb-storage”である。

 各フィールドの意味を【表02】に示す。先頭がusbモジュール名、2つ目がmatch_flagsと呼ばれ、後続のフィールドのうちどれを比較してどれを無視するのかを指定するもの。

【表02】
フィールド名意味
usbmoduleUSBモジュールの名称
match_flags判定に以後のどのフィールドを使うかの指定
idVendorベンダー(メーカー)コード
idProduct製品コード
bcdDevice_loデバイスバージョンの下限*1
bcdDevice_hiデバイスバージョンの上限*1
bDeviceClassデバイスクラス
bDeviceSubClassデバイスサブクラス
bDeviceProtocolプロトコルコード
bInterfaceClassインターフェイスクラス
bInterfaceSubClassインターフェイスサブクラス
bInterfaceProtocolインターフェイスプロトコル
driver_infoデバイス固有の情報(通常は使われない)
*1:bcdDevice_loとbcdDevice_hiは、2つの値で範囲を示す。bcdDeviceの値がこの範囲内にあるかどうかを判定するために使われる。

 フィールドとの対応は、【表03】のようになっている。この値は、判定したいフィールドに対応する値を表から求め、それを足したものを使う。たとえば、idVendorとidProductsだけを使う場合には、0x0001+0x0002=0x0003を指定する。また、bcdDevice_loとbcdDevice_hiは、bcdDevice値の下限と上限を指定するもので、指定した場合、bcdDevice_lo <= bcdDevice < bcdDevice_hiとして判定が行なわれる。上限値の判定が“<”でのみ行なわれる点に注意。また、先頭フィールド以外はすべて16進数表記で先頭に0xを付ける。

【表03】
フィールド対応する値(ビット)
idVendor0x0001
idProduct0x0002
bcdDevice_lo0x0004
bcdDevice_hi0x0008
bDeviceClass0x0010
bDeviceSubClass0x0020
bDeviceProtocol0x0040
bInterfaceClass0x0080
bInterfaceSubClass0x0100
bInterfaceProtocol0x0020
判定に利用したいフィールドに対応した値をすべて足したものがmatch flagsの値となる
例 idVendorとidProductの場合

 QV-R4では、ベンダーコード(idVendor)とプロダクツコード(idProducts)だけで判定するようにしてみた。なので、match_flagsとしては0x0003を使う。

 具体的には、/etc/hotplug/usb.distmapに以下のような行を追加する。

usb-storage          0x0003 0x07cf   0x1001    0x0000       0x0000       0x00         0x00            0x00            0x08            0x06            0x50            0x00000000

 作業としては、既存の行をコピーし、それを書き換えるほうがいいだろう。

 なお、細かくフィールドを設定するには、lsusb -vコマンドを使えば、各フィールドに対応したデータが得られる。

 usb.distmapを書き換えたら、デジカメを接続しなおす。追加データが正しければ、usb-storageとして認識され、マウントが行なわれるはずである。

●USBホスト対応といえないジレンマ

 SL-C3000のコネクタは、USB On The Go(OTG)で規定されたミニABコネクタある。OTGでは、限定されたホスト機能を持つとされていて、すべてのUSBクライアントに対応する必要はない。だが、対象となるクライアント機器を公開しなければならないとされている。OTGは、デジカメなどがプリンタを接続して印刷するような場合を想定しているためだ。

 また、OTGでの接続では、OTG独自のプロトコルが定義されていて、これをサポートする必要がある(これがSL-C3000に実装されているかどうかは不明)。

 Zaurusのようなコンピュータ本体の場合、ドライバを組み込めばいくらでも対応が可能であり、PXA-270のホスト機能は、基本的にはPC用のものと同等だ。つまり、ハードウェア的にはフル機能のホストインターフェイスを持っているが、何が接続できるのかは、組み込まれたドライバ次第である。

 こうした状況があるためにOTGともいえず、かといって完全なホストともいえない状態でり、メーカーとしても、ホスト機能があるとは言い難いのであろう。しかし、最低限必要なファイルやコマンドなどは用意されているので、ユーザーレベルでいろいろと検証していくことで今後はさまざまな機器が使えるようになるのではないかと思われる。

 さて、USBメモリの使い心地だが、PCにそのまま装着できるので、カードリーダーが必要となるCFやSDカードに比べると便利である。ホーム画面からもデバイスが直接見えるのでGUIでのファイル操作も可能だ。なお、SL-C3000には、USBハブも接続できるため、電源容量が心配な場合に、ハブをセルフパワーにして接続すればいいだろう。

 最後にくどいようだが、今回の記事の内容には、理解せずに実行するとZaurusが動作不能になる可能性があるものが含まれており、自己責任ということを理解したうえで、行なってほしい。なお、今回掲載したスクリプトなどは、短いものでもあり、自由に改変して使っていただいてかまわない。

□関連記事
【11月15日】【塩田】HDD内蔵PDA「シャープ SL-C3000」内部構造編
http://pc.watch.impress.co.jp/docs/2004/1115/pda38.htm
【11月12日】【塩田】初のHDD内蔵PDA「シャープ SL-C3000」を試す
http://pc.watch.impress.co.jp/docs/2004/1112/pda37.htm

バックナンバー

(2004年11月22日)

[Text by 塩田紳二]


【PC Watchホームページ】


PC Watch編集部 pc-watch-info@impress.co.jp 個別にご回答することはいたしかねます。

Copyright (c) 2004 Impress Corporation All rights reserved.