ロード トップ 参照元 逆検索 検索 ヘルプ

[logo] Linuxメモ


SuzKiti:不定期にっき

Linux のカーネルを いじるとき の Tips など。


usb_card_reader/Linuxメモ USBカードリーダ

Linux で、CF などの USB カードリーダ/ライタを使う方法について

装置は、ADTEC の AD-MCR/W

これを Linux につなぐと

cat /proc/scsi/scsi
Attached devices: 
Host: scsi0 Channel: 00 Id: 00 Lun: 00
  Vendor: Y-E DATA Model: CF Card Reader   Rev: 1.01
  Type:   Direct-Access                    ANSI SCSI revision: 02

というふうに CF が scsi として見える。

さて、MMC などはどうやって使うノダロウ?

LUN として見えるだろうと思い

とやってみた。

そうすると ..

cat /proc/scsi/scsi
Attached devices: 
Host: scsi0 Channel: 00 Id: 00 Lun: 00
  Vendor: Y-E DATA Model: CF Card Reader   Rev: 1.01
  Type:   Direct-Access                    ANSI SCSI revision: 02
Host: scsi0 Channel: 00 Id: 00 Lun: 01
  Vendor: Y-E DATA Model: SM Card Reader   Rev: 1.01
  Type:   Direct-Access                    ANSI SCSI revision: 02
Host: scsi0 Channel: 00 Id: 00 Lun: 02
  Vendor: Y-E DATA Model: MS Card Reader   Rev: 1.01
  Type:   Direct-Access                    ANSI SCSI revision: 02
Host: scsi0 Channel: 00 Id: 00 Lun: 03
  Vendor: Y-E DATA Model: SD Card Reader   Rev: 1.01
  Type:   Direct-Access                    ANSI SCSI revision: 02

このように、4 つの LUN があって使えることがわかった。 ソフト的には 4 つの LUN があって同時に使用できるが、MMC/SD と メモリースティックは、1つのスロットなので、同時にはつかえない。

USB の Mass Storage device ならなんでも使えるのではないようだ。

おなじ ADTEC の AD-CFR/W2 でためしてみる。

こいつは、DataFAB 製の chip を使っているようだ。

となる。

が出ていない。

そういえば、 linux の config で DATAFAB を使えるようにするというメニューがある。 CONFIG_USB_STORAGE_DATAFAB 。

これをキーにして、grep かけてみると .. どうも DATAFAB の USB mass は、drivers/usb/storage の unusual_devs.h に登録してないと使えなさそうだ。

#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
                    vendorName, productName,useProtocol, useTransport, \
                    initFunction, flags) \

という定義らしい。id_vender, id_product は 0xc3c, 0x11 なので 適当に作ってみる。

そして、ランプもついた。

ところが ...

SCSI device sda: 62720 512-byte hdwr sectors (32 MB)
sda: Write Protect is off
 sda: sda1

と続くはずの Disk の probe のメッセージが出ない。 ... 上の定義はまちがっているということだ。

中をあけて、chip の上に datafab の刻印があったので、 他の Datafab ものと 同じ ようにしてみたんだが ... ダメなのか。

US_PR_DATAFAB というのは、DATAFAB 特有のやりかたをするということだ。 ひょっとしたら それは昔のデバイスに対するもので、 こいつは、一般的な手続きで、やれば良いのかも知れない。


カーネルスタック拡張

Linux は、カーネルはスレッドとして動作する。したがって スタックのサイズは 固定であり スタックがオーバーフローすることは許されない。 ( このことは Linux に限らずカーネル一般の制限である。)

カーネルで、スタックがオーバーフローすれば、システム全体が止まる 危険がある。

さて linux(i386) のカーネルスタックはつぎのような構造になっている。

         +------------------+           ----
         | task_struct      | 約 1.5KB   ↑
         +------------------+
         |                  |
         |                  |            8KB
         |    ↑            |
         |   stack          |            ↓
         +------------------+           ----

ようするに、6.5K バイトほどしかない。この上で、システムコールのサービス を行い、さらに割り込みが来たら、スタックをつみあげて割り込み処理をおこなう。

スタックは、ほんとうに いかなるときもオーバフローしないのであろうか?

しらべてみると、カーネルのスタックのサイズを 16k にする パッチが、2002/2 月頃 出ていた。

... このようなパッチがあるということは、 実際にオーバフローがおきているのかもしれない。

kernel/exit.c の部分をみると、現状のカーネルでどこまでスタックを 使っているのかが分かるようになっているようだ。

まだ、つくりさしのパッチ(2.4.17 用)

上のパッチとあんまりかわらない。... しかも変なことをしているので、 動かないかも。

簡単に違いをかくと、task_struct にマークをいれてあって、 schedule() で、それが 壊れたことを検出すると BUG() で落ちる。

BUG() の先で やっぱり スタックつかって コードが動くわけなので、 その分の 緩衝 領域を設けてある。... その量を 8K にしてみたので、 task_struct のサイズが、9.5KB にもなってしまっている。

そのサイズを 1K バイトぐらいにするのが適切なのだが... わざと極端な 設定にしている。


proc を使ったツール

カーネルの データを見る.. とか カーネルの変数をちょっと変更してみる だとか ... そういうことができるツールを モジュールで組み込みたい

.. となると userland のインターフェイスは、proc が便利。

以下では 2 つの例 と コンパイルのやりかたのメモ

#include <linux/config.h>
#include <linux/module.h>

#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/timex.h>
#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <asm/uaccess.h>


struct test_struct {
	int ibuf_len;
	char ibuf[128];
	int obuf_len;
	char obuf[512];
} test_data;

static int test_read_proc(char *, char **,off_t, int, int *, void *);
static int test_write_proc(struct file *, const char *, unsigned long, void *);

static int test_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data)
{
	struct test_struct *p = (struct test_struct *)data;
	int len;

	if (!p) return -EINVAL;
	len = p->obuf_len - (int)off;
	if (len < 0) return -EINVAL;
	if (len > count) {
		len = count;
	}
	memcpy(page, p->obuf+(int)off, len);
	return len;
}


static int test_write_proc(struct file *file, const char *buffer, unsigned long count, void *data)
{
	struct test_struct *p = (struct test_struct *)data;
	long len;

	if (!p) return -EINVAL;
	len = count;
	if (len > 128) len = 128;
	if (copy_from_user(p->ibuf,buffer,len)) return -EFAULT;
	memcpy(p->obuf,p->ibuf,(int)len);
	p->obuf_len = len;
	return count;
}

static struct proc_dir_entry *test_entry;

int __init test_init(void) {

	test_data.ibuf_len = 0;
	test_data.obuf_len = 10;

	test_entry = create_proc_entry("testa", 0600, NULL);
	if (!test_entry) return -ENOMEM;

	test_entry->nlink = 1;
	test_entry->data = (void *)&test_data;
	test_entry->read_proc = test_read_proc;
	test_entry->write_proc = test_write_proc;
	return 0;
}

void test_exit(void) {
	remove_proc_entry("testa", NULL);
	test_entry = NULL;
}

/* no EXPORT_SYMBOL(xxx); */

module_init(test_init);
module_exit(test_exit);

#include <linux/config.h>
#include <linux/module.h>

#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/timex.h>
#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <asm/uaccess.h>


struct test_struct {
	int state;
	struct semaphore lock;
	int ibuf_len;
	char ibuf[128];
	int obuf_len;
	char obuf[128];
} test_data;

static int test_read_proc(char *, char **,off_t, int, int *, void *);
static int test_write_proc(struct file *, const char *, unsigned long, void *);
static void callback_done(struct test_struct *);

static int test_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data)
{
	struct test_struct *p = (struct test_struct *)data;
	int len;

	if (!p) return -EINVAL;
	while (p->state == 1) {	/* wait for call_back */
		down(&p->lock);
		up(&p->lock);
	}
	if (p->state != 2) return -EINVAL;
	len = p->obuf_len - (int)off;
	if (len < 0) return -EINVAL;
	if (len > count) {
		len = count;
	}
	memcpy(page, p->obuf+(int)off, len);
	return len;
}


static void callback_done(struct test_struct *p) {
	int len = p->ibuf_len;

	memcpy(p->obuf,p->ibuf,(int)len);
	p->obuf_len = len;
	p->state = 2;
	up(&p->lock);
	MOD_DEC_USE_COUNT;
}

static int test_write_proc(struct file *file, const char *buffer, unsigned long count, void *data)
{
	struct test_struct *p = (struct test_struct *)data;
	long len;

	if (!p) return -EINVAL;
	if ((p->state != 0) && (p->state != 2)) return -EINVAL;

	len = count;
	if (len > 128) len = 128;
	if (copy_from_user(p->ibuf,buffer,len)) return -EFAULT;
	p->ibuf_len = len;

	MOD_INC_USE_COUNT;
	down(&p->lock);
	p->state = 1;
	callback_done(p);	/* test  */
	return count;
}

static struct proc_dir_entry *test_dir_entry;
static struct proc_dir_entry *test_entry;

int __init test_init(void) {

	test_dir_entry = proc_mkdir("suz", NULL);
	if (!test_dir_entry) return -ENOMEM;

	test_data.ibuf_len = 0;
	test_data.obuf_len = 10; /* for test */
	test_data.state = 2; /* for test */
	init_MUTEX(&(test_data.lock));

	test_entry = create_proc_entry("test", 0600, test_dir_entry);
	if (!test_entry) return -ENOMEM;

	test_entry->nlink = 1;
	test_entry->data = (void *)&test_data;
	test_entry->read_proc = test_read_proc;
	test_entry->write_proc = test_write_proc;
	return 0;
}

void test_exit(void) {
	remove_proc_entry("test", test_dir_entry);
	remove_proc_entry("suz", NULL);
	test_dir_entry = NULL;
	test_entry = NULL;
}

/* no EXPORT_SYMBOL(xxx); */

module_init(test_init);
module_exit(test_exit);

cc -D__KERNEL__  -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer \
 -fno-strict-aliasing -pipe -fno-strength-reduce -m486 -malign-loops=2 \
-malign-jumps=2 -malign-functions=2 -DCPU=586 -DMODULE -DMODVERSIONS \
-include /usr/include/linux/modversions.h   -c $1

gcc -D__KERNEL__ -Wall -Wstrict-prototypes -Wno-trigraphs -O2 \
	-fomit-frame-pointer -fno-strict-aliasing -fno-common \
	-pipe  -march=i686 -DMODULE -DMODVERSIONS  \
	-include /usr/include/linux/modversions.h \
	-DEXPORT_SYMTAB -c $1

(最終更新 Thu Mar 30 18:53:17 2006)