USB-SCSIデバイスドライバ _ 外部仕様

イントロダクション

PC/LinuxのUSB接続でVME操作をする方法を述べる。本システムの開発目的は「ユーザビリティ」の追求である。中性子実験施設(KENS)では、マッキントッシュを使用したUSBを使用したVME機器の操作がすでに行われている。しかし、他の研究施設ではPCが多く使用されており、特にソースコードが公開され、安定性に定評のあるLinux上で使用できるようにすることに意義がある。

USB自体は事実上の標準で、ほとんど全てのコンピュータに標準装備されていて、これを使用して小規模の実験のデータ収集ができることは有用である。このことは中性子実験施設で十分に実証されている。

この開発ではUSB-SCSI変換アダプタを使用し、次にSCSI-VME変換モジュールを使用して、VME測定機器を操作する。USB-SCSI変換アダプタは自作のもの(KENS製)と、ロジテック社のLUB-SCの両方が使用できる。SCSI-VME変換モジュールもKENS製である。

Hardware Preparation

USBインターフェース付きのPC。

USB-SCSI変換アダプタ。ロジテック社のLUB-SC、またはKENS製USB-SCSI変換アダプタ。

KENS製SCSI-VME変換モジュール(8ビット、16ビットデータ幅のみ対応)。

VME電源クレート。VME機器。

Software Preparation

Linux、カーネル2.4.0以上。

USB-VME用ドライバ:u_scsi.c、u_scsi.o

USB-VME用ライブラリ:u_slib.c、u_slib.o

インストレーション

Hardware Preparation

VME電源クレートの一番左端スロットにSCSI-VME変換モジュールを装着する。

USB-SCSI変換アダプタをVME電源クレートに接続する。

PC のUSBインターフェースにUSBケーブルでUSB-SCSI変換アダプタをつなぐ。

Software Preparation

USB-VME用ドライバu_scsi.oをmakeし、insmodする。

USB-VME用ライブラリu_slib.oをmakeする。

キャラクタ型ドライバノードをメジャー番号180、マイナー番号128で作る。

ユーザインターフェースの詳細(Linux用USB-VMEライブラリ:u_slib.c)

Introduction

USB-SCSI変換アダプタとSCSI-VME変換モジュールを使用してVME操作を行なう。このライブラリの関数は大きく3つに分けられる。VMEデバイスのopenやcloseのセットアップ関数、VME機器とデータ転送を行なう関数、SCSI情報を得る関数である。データ転送を行なう関数はマッキントッシュと同じ形式とした。

セットアップ関数

int usb_open()

USBをオープンし、使用できるようにする。省略可。

単一オープンなので、他のプロセスが使用中は-BUSYを返す。0の時使用可。

int usb_close()

USBをクローズする。使用中を解除。

VME機器とデータ転送を行なう関数

int usb_scsirwsub(int sid, int rw, long add, int len, char *buf)

USBとSCSIポートを通してVME機器とキャラクタ配列データ転送を行なう。

まだオープンしていない場合、usb_open()を呼ぶ。

sid:SCSI ID。0~7。

rw:0の時データ読み取り(SCSIオペレーションコード=0x28)、

1の時データ書き込み(SCSIオペレーションコード=0x2a)。

add:VMEアドレス。32ビット長。

len:転送を行なう転送バイト数。16ビット長。

2バイト以上でビッグエンデアンから、リトルエンデアンへの変換も行なう。

buf:転送を行なうキャラクタ配列データ。

SCSI情報を得る関数

int usb_inquiry(int sid, int len, char *buf)

USBを通してSCSIのinquiry命令を実行し、SCSI情報を得る。

(SCSIオペレーションコード=0x12)。

まだオープンしていない場合、usb_open()を呼ぶ。

sid:SCSI ID。0~7。

len:読み取りを行なう転送バイト数。通常36。

buf:読み取りを行なうキャラクタ配列データ。

デバイスドライバの使用方法

カーネルコンパイル前に、Xウインドウ上で下記設定プログラムでUSBを有効にする。

# cd /usr/src/linux ; make xconfig

カーネルコンパイル後に、USBドライバをカーネルに組み込む

# insmod u_scsi.o

ユーザモードで、ライブラリ:u_slib.oとテストプログラムをリンクする。ここでのテストプログラムは中性子用の時間分析器TA17VMEモジュールをメモリとして使用し、書き込み、読み取りを繰り返し、検査するプログラムである。128Kバイトのメモリを書き、読み、検査後、1秒スリープし、エラーが出るまで繰り返す。

テストプログラムソースコード:u_loop.c

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <sys/ioctl.h>

#include <unistd.h>

#include <stdio.h>

#define MAXLEN 4000

main()

{

int i, err, sid, count, loop, num;

char buf[50];

long address, li, dbuf[MAXLEN];

printf("This is a memory test program.\n");

printf("SCSI ID : "); // SCSI IDの入力

scanf("%d",&sid);

if(sid<0 || sid>7) {

printf("bad SCSI ID!\n");

return -1;

}

printf("TA module's VME-address (0~) : ");

scanf("%d",&li); // TAモジュールのVMEアドレスの入力

address = li * 0x10000 + 0x4000;

printf("count (long) : ");

scanf("%d",&count); // データ転送バイト数の入力

if(count<1 || count>MAXLEN) count = MAXLEN;

usb_inquiry(sid,36,buf); // SCSIのinquiryデータの入力

printf("inquiry = %s\n",&buf[8]);

loop = 0;

buf[0] = 0;

do {

for(err=num=0 ; num<8 ; num++) {

buf[1] = num;

usb_scsirwsub(sid,1,4,2,buf); // アドレス設定、測定停止モード

for(i=num ; i<count ; i++)

dbuf[i] = i; // 書き込むデータの設定

usb_scsirwsubL(sid, 1, address, count, dbuf);

// VMEモジュールへ、データ書き込み

for(i=0 ; i<count ; i++)

dbuf[i] = 0; // データ領域のクリア

buf[1] = 0x80 + num;

usb_scsirwsub(sid,1,4,2,buf); // アドレス設定、測定開始モード

usb_scsirwsubL(sid, 0, address, count, dbuf);

// VMEモジュールから、データ読み取り

for(i=num ; i<count ; i++)

if(dbuf[i] != i) { // 読み取ったデータの検査

printf(" %d",dbuf[i]);

err++;

}

}

buf[1] = 0;

usb_scsirwsub(sid,1,4,2,buf); // アドレス設定、測定停止モード

usb_close(); // USBをクローズし、使用中を解除

printf("\nloop=%d address=0x%x count=%d error=%d\n"

,loop++ ,address ,count ,err);

sleep(1); // 1秒のスリープ

} while(!err); // エラーがなければ、いつまでも続ける

}

USB-SCSIデバイスドライバ _ 内部仕様

概要

PC/LinuxのUSB接続でVME操作をする方法を述べている。本システムの開発目的は「ユーザビリティ」の追求である。ここではUSB-SCSIデバイスドライバの構成、仕様を詳しく説明する。

一般ユーザが使用できるUSB関数(u_slib.c)

int usb_open()

int usb_scsirwsub(int sid, int rw, long add, long len, char *buf)

int usb_inquiry(int sid, int len, char *buf)

int usb_close()

USB関数が使用するドライバ関数(u_scsi.c)

int open(char *fname, int fmode)

USBをオープンし、使用できるようにする。

ファイル識別番号を正の整数で返す。他のプロセスが使用中は-BUSYを返す。

fname:/dev内に作成したデバイスノード名。"/dev/<ノード名>"。

fmode:デバイスのアクセス方法を規定。

int ioctl(int fid, unsigned int cmd, unsigned long arg)

USBとSCSIポートを通してVMEアクセスのための設定を、argを使って行なう。

fid:ファイル識別番号。

cmd、arg:cmd=1の時、arg=SCSI ID、

cmd=2の時、arg=SCSIの動作指示、0/1/2=read/write/inquiry、

cmd=3の時、arg=VMEアドレス、32ビット長。

int read(int fid, char *buf, int len)

fid:ファイル識別番号。

buf:読み取りを行なうキャラクタ配列データ。

len:読み取りを行なう転送バイト数。

int write(int fid, char *buf, int len)

fid:ファイル識別番号。

buf:書き込みを行なうキャラクタ配列データ。

len:書き込みを行なう転送バイト数。

int close(int fid)

USBをクローズする。使用中を解除。

 

主なドライバ関数(s_scsi.c)

static int recv_data(struct file *file, const unsigned char *buf, int len)

static unsigned int

scsi_write(struct file *file, unsigned const char *buf, int len)

static unsigned int

scsi_read(struct file *file, unsigned char *buf, int len)

static unsigned int

scsi_inquiry(struct file *file, unsigned char *buf, int len)

static ssize_t

file_operation_read(struct file *file, char *buf, size_t len, loff_t *ppos)

static ssize_t

file_operation_write(struct file *file,const char *buf,size_t len,loff_t *ppos)

static int

file_operation_ioctl(struct inode *inode, struct file *file,

unsigned int cmd, unsigned long arg)

static int

file_operation_open(struct inode *inode, struct file *file)

static int

file_operation_release(struct inode *inode, struct file *file)

static struct file_operations

usb_xscsi_file_operations = {

owner: THIS_MODULE,

read: file_operation_read,

write: file_operation_write,

ioctl: file_operation_ioctl,

open: file_operation_open,

release: file_operation_release,

};

 

static void *device_probe(struct usb_device *dev, unsigned int ifnum)

static void device_dissconnect(struct usb_device *dev, void *ptr)

static struct usb_driver

driver_table = {

"usb-xscsi",

device_probe,

device_dissconnect,

{ NULL, NULL },

&usb_xscsi_file_operations,

USB_XSCSI_MINOR_BASE

};

int __init usb_xscsi_module_init(void)

void __exit usb_xscsi_module_cleanup(void)

module_init (usb_xscsi_module_init);

module_exit (usb_xscsi_module_cleanup);