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);