misc/060tsys/t12devpat.s
;----------------------------------------------------------------
;
;	デバイスドライバのハイメモリ対策
;
;----------------------------------------------------------------

	.include	t02const.equ
	.include	t08debug.equ

;__DEBUG__	equ	1

	.cpu	68060

;----------------------------------------------------------------
;デバイスドライバを呼び出す(キャッシュおよびローカルメモリ対策)
;	Human302での手順(68000,68030)
;		$0000DEFA
;			データキャッシュをOFFにする
;			([6,a1])を呼び出す
;			([10,a1])を呼び出す
;			データキャッシュと命令キャッシュをフラッシュする
;			キャッシュモードを復元する
;<a1.l:デバイスヘッダ
;<a5.l:リクエストヘッダ
;?d0
callDevice::
;ドライバ自身のRAMDISKドライバの呼び出しは特別扱いで高速化
	cmpa.l	#deviceHeader,a1
	beq	ramdiskGo
;RAMDISKがないときはここからスタート
callDeviceNoRamdisk::
;キャラクタデバイスのときはキャッシュのみ処置
	tst.w	(4,a1)			;デバイスタイプ
	bmi	characterDevice		;キャラクタデバイス
;ブロックデバイス,特殊デバイス
	movem.l	d1-d7/a0-a3/a5-a6,-(sp)
;特殊デバイスを区別する
	btst.b	#13-8,(4,a1)
	bne	specialDevice		;特殊デバイス
;----------------------------------------------------------------
;ブロックデバイスの呼び出し
;	転送とディスク交換チェックは-npが指定されていなければキャッシュ操作を伴う
;	その他のコマンドは無条件にキャッシュ操作を伴う
blockDevice:
	moveq.l	#0,d0
	move.b	(2,a5),d0		;コマンド
	cmp.b	#$0D,d0
	bcc	unknownCommand
	jsr	([@f,pc,d0.l*4])
	movem.l	(sp)+,d1-d7/a0-a3/a5-a6
	rts

@@:	.dc.l	deviceGoPush		;00	初期化
	.dc.l	deviceGoPush		;01	ディスク交換チェック
	.dc.l	deviceGoPush		;02	ディスク交換処理
	.dc.l	ioctrlRead		;03	IOCTRLによる入力
	.dc.l	blockRead		;04	入力
	.dc.l	deviceGoPush		;05	ドライブコントロール&センス
					;	(キャッシュ制御しないとFORMAT.Xが動かない)
	.dc.l	deviceGoPush		;06	エラー
	.dc.l	deviceGoPush		;07	エラー
	.dc.l	blockWrite		;08	出力(VERIFY OFF時)
	.dc.l	blockWrite		;09	出力(VERIFY ON時)
	.dc.l	deviceGoPush		;0A	エラー
	.dc.l	deviceGoPush		;0B	未使用
	.dc.l	ioctrlWrite		;0C	IOCTRLによる出力

;----------------------------------------------------------------
;特殊デバイスの呼び出し
;	初期化と未定義のコマンドは無条件にキャッシュ操作を伴う
;	その他のコマンドは-npが指定されていなければキャッシュ操作を伴う
specialDevice:
	moveq.l	#$7F,d0
	and.b	(2,a5),d0		;コマンド(verifyフラグを除去)
	sub.b	#$40,d0
	bcs	unknownCommand
	cmp.b	#$59-$40,d0
	bcc	unknownCommand
	jsr	([@f,pc,d0.l*4])
	movem.l	(sp)+,d1-d7/a0-a3/a5-a6
	rts

@@:	.dc.l	deviceGoPush		;40	initialize
	.dc.l	deviceGoPush		;41	chdir
	.dc.l	deviceGoPush		;42	mkdir
	.dc.l	deviceGoPush		;43	rmdir
	.dc.l	deviceGoPush		;44	rename
	.dc.l	deviceGoPush		;45	delete
	.dc.l	deviceGoPush		;46	chmod
	.dc.l	deviceGoPush		;47	files
	.dc.l	deviceGoPush		;48	nfiles
	.dc.l	deviceGoPush		;49	create/newfile
	.dc.l	deviceGoPush		;4A	open
	.dc.l	deviceGoPush		;4B	close
	.dc.l	specialRead		;4C	read
	.dc.l	specialWrite		;4D	write
	.dc.l	deviceGoPush		;4E	seek
	.dc.l	deviceGoPush		;4F	filedate
	.dc.l	deviceGoPush		;50	dskfre
	.dc.l	deviceGoPush		;51	drvctrl
	.dc.l	deviceGoPush		;52	getdpb
	.dc.l	deviceGoPush		;53	diskred
	.dc.l	deviceGoPush		;54	diskwrt
	.dc.l	deviceGoPush		;55	special_ctrl
	.dc.l	deviceGoPush		;56	fflush
	.dc.l	deviceGoPush		;57	mediacheck
	.dc.l	deviceGoPush		;58	lock

;----------------------------------------------------------------
;未対応のコマンド
;	無条件にキャッシュ操作を伴う
unknownCommand:
	movem.l	(sp)+,d1-d7/a0-a3/a5-a6
	bra	deviceGoPush

;----------------------------------------------------------------
;キャラクタデバイスの呼び出し
;	初期化は無条件にキャッシュ操作を伴う
;	その他のコマンドは-npが指定されていなければキャッシュ操作を伴う
;<a1.l:デバイスヘッダ
;<a5.l:リクエストヘッダ
;?d0
characterDevice:
	tst.b	(2,a5)			;コマンド
	beq	deviceGoPush		;初期化
;----------------------------------------------------------------
;デバイスの処理を実行する(-npが指定されていなければキャッシュ操作を伴う)
;<a1.l:デバイスヘッダ
;<a5.l:リクエストヘッダ
;?d0
deviceGo:
	tst.b	deviceCacheNoPush
	beq	deviceGoPush		;-npが指定されていない
	move.l	a0,-(sp)
	movea.l	([$1C28.w]),a0
	tst.b	(pDeviceNoPush,a0)
	movea.l	(sp)+,a0
	beq	deviceGoPush		;-npを適用できないプロセス
;----------------------------------------------------------------
;デバイスの処理を実行する(キャッシュ操作を伴わない)
;<a1.l:デバイスヘッダ
;<a5.l:リクエストヘッダ
;?d0
deviceGoGo:
	move.l	d2,-(sp)
	moveq.l	#0,d2			;9SCDRV.X 3.14+2のバグを回避する
	jsr	([6,a1])		;ストラテジルーチンを呼ぶ
	jsr	([10,a1])		;インタラプトルーチンを呼ぶ
	move.l	(sp)+,d2
	rts

;----------------------------------------------------------------
specialRead:				;現在未対応
specialWrite:				;現在未対応
;----------------------------------------------------------------
;デバイスの処理を実行する(キャッシュ操作を伴う)
;<a1.l:デバイスヘッダ
;<a5.l:リクエストヘッダ
;?d0
deviceGoPush:
	PUSH_CACR_DISABLE_DC	d0
	bsr	deviceGoGo
	CACHE_FLUSH	d0
	POP_CACR	d0
	rts

;----------------------------------------------------------------
;RAMDISKの処理を実行する
;	データキャッシュをプッシュしない
;	コマンドコード毎の処理を直接呼び出す
;	requestHeaderを設定しないのでコマンド内でrequestHeaderを使わないこと
;<a1.l:デバイスヘッダ
;<a5.l:リクエストヘッダ
;?d0
ramdiskGo:
	moveq.l	#0,d0
	move.b	(2,a5),d0		;コマンドコード
	jsr	([deviceJumpTable,pc,d0.l*4])	;コマンドの処理を呼ぶ
	move.b	d0,(3,a5)		;エラーコード(下位)
	lsr.w	#8,d0
	move.b	d0,(4,a5)		;エラーコード(上位)
	rts

;----------------------------------------------------------------
;ブロックデバイスへの書き込み
;<a1.l:デバイスヘッダ
;<a5.l:リクエストヘッダ
blockWrite:
	tst.b	patchDevice
	beq	deviceGo		;ローカルメモリ対策をしないときはキャッシュのみ処置

  debug '|blockWrite(top,siz,ptr,head) ',4,(22,a5),(18,a5),(14,a5),([14,a5])
	lea.l	(blockWriteTransfer,pc),a2	;ブロックデバイスへの出力
	moveq.l	#1,d0
	bra	blockTransfer

;----------------------------------------------------------------
;ブロックデバイスからの読み出し
;<a1.l:デバイスヘッダ
;<a5.l:リクエストヘッダ
blockRead:
	tst.b	patchDevice
	beq	deviceGo		;ローカルメモリ対策をしないときはキャッシュのみ処置

  debug '|blockRead(top,siz,ptr) ',3,(22,a5),(18,a5),(14,a5)
	lea.l	(blockReadTransfer,pc),a2	;ブロックデバイスからの入力
	moveq.l	#0,d0
;ブロックデバイスの入出力
;<d0.l:転送方向
;	0	デバイスから読み出し(メモリへ書き込み)
;	1	デバイスへ書き込み(メモリから読み出し)
;<a1.l:デバイスヘッダ
;<a2.l:転送ルーチン
;<a5.l:リクエストヘッダ
blockTransfer:
	move.l	(18,a5),d6		;転送セクタ数
	beq	deviceGo		;転送セクタ数が0のときは何もしない
;内部DPBテーブルを求める
	bsr	searchInnerDpb		;デバイスヘッダとユニット番号から内部DPBテーブルを探す
	bmi	deviceGo		;内部DPBテーブルが見つからない(念のため)
;<a0.l:内部DPBテーブル
  debug 'inner dpb=',1,a0
  debugByte 'drive,unit=',2,(iDrive,a0),(iUnit,a0)
  debug 'device header=',1,(iDeviceHeader,a0)
  debugByte 'media byte=',1,(iMediaByte,a0)
  debugByte 'byte per sect2=',1,(iBytePerSect2,a0)
;メディアバイト一覧
;	$F0	SCSI MO (IBM format)
;	$F4	SCSI DAT
;	$F5	SCSI CD-ROM
;	$F6	SCSI MO
;	$F7	SCSI HD
;	$F8	SASI HD
;	$F9	RAM / SRAM / ROM
;	$FA	2HD 1.44MB
;	$FB	2DD 640KB
;	$FC	2DD 720KB
;	$FD	2HC 1.2MB
;	$FE	2HD 1.2MB
;メディアバイトが$F0~$F7のとき,SCSI IOCSにパッチがあたっていれば
;SCSI IOCS側でソフト転送になるので一時バッファを媒介しなくてよい
	moveq.l	#$10,d3
	add.b	(iMediaByte,a0),d3	;メディアバイト
;	bcc	@f
	subq.b	#8,d3
	bcc	@f
	tst.b	patchIocsScsi
	bne	deviceGo
@@:
	move.b	(iBytePerSect2,a0),d3	;セクタ数をバイト数に変換するときのシフトカウント
	cmp.b	#8,d3
	blo	deviceGo		;1セクタが256バイト未満(念のため)
	move.l	tempBufferSize,d4	;一時バッファのバイト数
	lsr.l	d3,d4			;一時バッファのセクタ数
	move.l	(14,a5),d5		;目的のバッファの先頭アドレス
	and.l	#LOGICAL_MASK,d5	;_DISKRED/_DISKWRTの拡張モードではbit31が
					;セットされたまま入ってくる
	move.l	(22,a5),d7		;先頭のセクタ番号
;<d0.l:転送方向
;	0	デバイスから読み出し(メモリへ書き込み)
;	1	デバイスへ書き込み(メモリから読み出し)
;<d3.b:セクタ数をバイト数に変換するときのシフトカウント
;<d4.l:一時バッファのセクタ数
;<d5.l:目的のバッファの先頭アドレス
;<d6.l:転送セクタ数
;<d7.l:先頭のセクタ番号
;<a0.l:内部DPBテーブル
;<a1.l:デバイスヘッダ
;<a2.l:転送ルーチン
;<a5.l:リクエストヘッダ
;目的のバッファがDMA転送可能かどうか調べる
;	物理アドレスが論理アドレスと異なる場合はDMA転送不可
;	物理アドレスがローカルメモリを指している場合もDMA転送不可
	move.l	d5,d1			;先頭
	move.l	d6,d2			;セクタ数
	lsl.l	d3,d2			;バイト数
	add.l	d5,d2			;末尾+1
;<d0.l:転送方向
;	0	デバイスから読み出し(メモリへ書き込み)
;	1	デバイスへ書き込み(メモリから読み出し)
;<d1.l:バッファの先頭
;<d2.l:バッファの末尾+1
	bsr	dmaAccessCheck
	bpl	deviceGo		;DMA転送可能な領域なので何もしない
;----------------------------------------------------------------
;一時バッファを使った転送処理(ブロックデバイスの入出力)
;新しいリクエストヘッダを確保する
	lea.l	(-26,sp),sp
	movea.l	a5,a6			;元のリクエストヘッダ
	movea.l	sp,a5			;新しいリクエストヘッダ
;<a5.l:新しいリクエストヘッダ
;<a6.l:元のリクエストヘッダ
;転送ループ
blockTransferLoop:
;新しいリクエストヘッダを作る
	move.w	(a6),(a5)		;定数,ユニット番号
	movem.l	(2,a6),d0-d2		;コマンドコード
	movem.l	d0-d2,(2,a5)
;パラメータを設定する
	sub.l	d4,d6			;残りの転送セクタ数
	bcc	@f
	add.l	d6,d4			;今回の転送セクタ数
	moveq.l	#0,d6
@@:	movea.l	tempBufferStart,a0	;一時バッファの先頭アドレス
	move.l	a0,(14,a5)		;転送アドレス
	move.l	d4,(18,a5)		;セクタ数
	move.l	d7,(22,a5)		;セクタ番号
	add.l	d4,d7			;次のセクタ番号
;入出力の実行
;<d3.b:セクタ数をバイト数に変換するときのシフトカウント
;<d4.l:今回の転送セクタ数
;<d5.l:目的のバッファのアドレス
;<d6.l:残りの転送セクタ数
;<d7.l:次のセクタ番号
;<a0.l:一時バッファの先頭アドレス
;<a1.l:デバイスヘッダ
;<a2.l:転送ルーチン
;<a5.l:新しいリクエストヘッダ(構築済み)
;<a6.l:元のリクエストヘッダ
	jsr	(a2)			;入力または出力の実行
	tst.l	d6
	bne	blockTransferLoop
;エラーコードを元のリクエストヘッダにコピーして終わり
blockTransferEnd:
	move.b	(3,a5),(3,a6)		;エラーコード(下位)
	move.b	(4,a5),(4,a6)		;エラーコード(上位)
	movea.l	a6,a5
	lea.l	(26,sp),sp
;一時バッファを使った転送処理終わり
	rts

;エラー発生時は続きを処理せずに終了
blockTransferError:
	addq.l	#4,sp
	bra	blockTransferEnd

;----------------------------------------------------------------
;ブロックデバイスからの入力
;<d3.b:セクタ数をバイト数に変換するときのシフトカウント
;<d4.l:今回の転送セクタ数
;<d5.l:目的のバッファのアドレス
;<a0.l:一時バッファの先頭アドレス
;<a1.l:デバイスヘッダ
;<a5.l:新しいリクエストヘッダ(構築済み)
;>d5.l:目的のバッファの次のアドレス
;*d5,?d0/a0
blockReadTransfer:
  debug '|blockReadTransfer(ptr,tmp,(top,siz,ptr)) ',5,d5,a0,(22,a5),(18,a5),(14,a5)
;デバイスの処理を実行する
	bsr	deviceGo		;デバイスの処理を実行する(キャッシュ操作を伴う)
	tst.b	(3,a5)			;エラーチェック
	bne	blockTransferError	;エラーが発生したので中止する
;一時バッファから目的のバッファにコピーする
	moveq.l	#$0F,d0
	and.l	d5,d0
					;元  先,デバイスヘッダ
					;d5→a0,a1
	exg.l	d5,a1			;a1→a0,d5
	bsr	blockTransferSub
	exg.l	d5,a1			;d5→a0,a1
	rts

;----------------------------------------------------------------
;ブロックデバイスへの出力
;<d3.b:セクタ数をバイト数に変換するときのシフトカウント
;<d4.l:今回の転送セクタ数
;<d5.l:目的のバッファのアドレス
;<a0.l:一時バッファの先頭アドレス
;<a1.l:デバイスヘッダ
;<a5.l:新しいリクエストヘッダ(構築済み)
;>d5.l:目的のバッファの次のアドレス
;*d5,?d0/a0
blockWriteTransfer:
  debug '|blockWriteTransfer(ptr,tmp,(top,siz,ptr,head)) ',6,d5,a0,(22,a5),(18,a5),(14,a5),([14,a5])
;目的のバッファから一時バッファにコピーする
	moveq.l	#$0F,d0
	and.l	d5,d0
					;元  先,デバイスヘッダ
					;d5→a0,a1
	exg.l	d5,a1			;a1→a0,d5
	exg.l	a0,a1			;a0→a1,d5
	bsr	blockTransferSub
	movea.l	d5,a1			;a0→??,a1
	move.l	a0,d5			;d5→??,a1
;デバイスの処理を実行する
	bsr	deviceGo		;デバイスの処理を実行する(キャッシュ操作を伴う)
	tst.b	(3,a5)			;エラーチェック
	bne	blockTransferError	;エラーが発生したので中止する
	rts

;----------------------------------------------------------------
;転送サブルーチン
;<d0.l:0のときmove16を使う
;<d3.b:セクタ数をバイト数に変換するときのシフトカウント
;<d4.l:今回の転送セクタ数
;<a0.l:転送元の先頭アドレス
;<a1.l:転送先の先頭アドレス
;>a0.l:転送元の次のアドレス
;>a1.l:転送先の次のアドレス
;*a0-a1,?d0
blockTransferSub:
  debug '|blockTransferSub(src,dst) ',2,a0,a1
	tst.l	d0
	bne	blockTransferSub1
	cmpi.b	#4,$0CBC.W
	blo	blockTransferSub1
;move16を使って転送する
	move.l	d4,d0			;セクタ数
	lsl.l	d3,d0			;バイト数
;<d0.l:転送バイト数
;<a0.l:転送元のアドレス(16の倍数)
;<a1.l:転送先のアドレス(16の倍数)
	lsr.l	#8,d0			;バイト数/256
@@:
  .rept 16
	move16	(a0)+,(a1)+		;256バイトずつコピーする
  .endm
	subq.l	#1,d0
	bne	@b
	rts

;moveを使って転送する
blockTransferSub1:
	move.l	d4,d0			;セクタ数
	lsl.l	d3,d0			;バイト数
;<d0.l:転送バイト数
;<a0.l:転送元のアドレス
;<a1.l:転送先のアドレス
	lsr.l	#8,d0			;バイト数/256
@@:
  .rept 64
	move.l	(a0)+,(a1)+		;256バイトずつコピーする
  .endm
	subq.l	#1,d0
	bne	@b
	rts

;----------------------------------------------------------------
;ブロックデバイスからのIOCTRLによる書き込み
;<a1.l:デバイスヘッダ
;<a5.l:リクエストヘッダ
ioctrlWrite:
	tst.b	patchDevice
	beq	deviceGo		;ローカルメモリ対策をしないときはキャッシュのみ処置

	lea.l	(ioctrlWriteTransfer,pc),a2	;ブロックデバイスへのIOCTRLによる出力
	moveq.l	#1,d0
	bra	ioctrlTransfer

;----------------------------------------------------------------
;ブロックデバイスからのIOCTRLによる読み出し
;<a1.l:デバイスヘッダ
;<a5.l:リクエストヘッダ
ioctrlRead:
	tst.b	patchDevice
	beq	deviceGo		;ローカルメモリ対策をしないときはキャッシュのみ処置

	lea.l	(ioctrlReadTransfer,pc),a2	;ブロックデバイスからのIOCTRLによる入力
	moveq.l	#0,d0
;ブロックデバイスのIOCTRLによる入出力
;<d0.l:転送方向
;	0	デバイスから読み出し(メモリへ書き込み)
;	1	デバイスへ書き込み(メモリから読み出し)
;<a1.l:デバイスヘッダ
;<a2.l:転送ルーチン
;<a5.l:リクエストヘッダ
ioctrlTransfer:
	move.l	(18,a5),d6		;転送バイト数
	beq	deviceGo		;転送バイト数が0のときは何もしない
	move.l	tempBufferSize,d4	;一時バッファのバイト数
	move.l	(14,a5),d5		;目的のバッファの先頭アドレス
	and.l	#LOGICAL_MASK,d5	;念のため
;<d0.l:転送方向
;	0	デバイスから読み出し(メモリへ書き込み)
;	1	デバイスへ書き込み(メモリから読み出し)
;<d4.l:一時バッファのバイト数
;<d5.l:目的のバッファの先頭アドレス
;<d6.l:転送バイト数
;<a1.l:デバイスヘッダ
;<a2.l:転送ルーチン
;<a5.l:リクエストヘッダ
;目的のバッファがDMA転送可能かどうか調べる
;	物理アドレスが論理アドレスと異なる場合はDMA転送不可
;	物理アドレスがローカルメモリを指している場合もDMA転送不可
	move.l	d5,d1			;先頭
	move.l	d6,d2			;セクタ数
	add.l	d5,d2			;末尾+1
;<d0.l:転送方向
;	0	デバイスから読み出し(メモリへ書き込み)
;	1	デバイスへ書き込み(メモリから読み出し)
;<d1.l:バッファの先頭
;<d2.l:バッファの末尾+1
	bsr	dmaAccessCheck
	bpl	deviceGo		;DMA転送可能な領域なので何もしない
;----------------------------------------------------------------
;一時バッファを使った転送処理(ブロックデバイスのIOCTRLによる入出力)
;新しいリクエストヘッダを確保する
	lea.l	(-26,sp),sp
	movea.l	a5,a6			;元のリクエストヘッダ
	movea.l	sp,a5			;新しいリクエストヘッダ
;<a5.l:新しいリクエストヘッダ
;<a6.l:元のリクエストヘッダ
;転送ループ
ioctrlTransferLoop:
;新しいリクエストヘッダを作る
	move.w	(a6),(a5)		;定数,ユニット番号
	movem.l	(2,a6),d0-d2		;コマンドコード
	movem.l	d0-d2,(2,a5)
;パラメータを設定する
	sub.l	d4,d6			;残りの転送バイト数
	bcc	@f
	add.l	d6,d4			;今回の転送バイト数
	moveq.l	#0,d6
@@:	movea.l	tempBufferStart,a0	;一時バッファの先頭アドレス
	move.l	a0,(14,a5)		;転送アドレス
	move.l	d4,(18,a5)		;バイト数
					;(22,a5)は設定しない
;入出力の実行
;<d4.l:今回の転送バイト数
;<d5.l:目的のバッファのアドレス
;<d6.l:残りの転送バイト数
;<a0.l:一時バッファの先頭アドレス
;<a1.l:デバイスヘッダ
;<a2.l:転送ルーチン
;<a5.l:新しいリクエストヘッダ(構築済み)
;<a6.l:元のリクエストヘッダ
	jsr	(a2)			;入力または出力の実行
	tst.l	d6
	bne	ioctrlTransferLoop
;エラーコードを元のリクエストヘッダにコピーして終わり
ioctrlTransferEnd:
	move.w	(3,a5),(3,a6)		;エラーコード
	movea.l	a6,a5
	lea.l	(26,sp),sp
;一時バッファを使った転送処理終わり
	rts

;エラー発生時は続きを処理せずに終了
ioctrlTransferError:
	addq.l	#4,sp
	bra	ioctrlTransferEnd

;----------------------------------------------------------------
;ブロックデバイスからのIOCTRLによる入力
;<d4.l:今回の転送バイト数
;<d5.l:目的のバッファのアドレス
;<a0.l:一時バッファの先頭アドレス
;<a1.l:デバイスヘッダ
;<a5.l:新しいリクエストヘッダ(構築済み)
;>d5.l:目的のバッファの次のアドレス
;*d5,?d0/a0
ioctrlReadTransfer:
;デバイスの処理を実行する
	bsr	deviceGo		;デバイスの処理を実行する(キャッシュ操作を伴う)
	tst.b	(3,a5)			;エラーチェック
	bne	ioctrlTransferError	;エラーが発生したので中止する
;一時バッファから目的のバッファにコピーする
					;元  先,デバイスヘッダ
					;d5→a0,a1
	exg.l	d5,a1			;a1→a0,d5
	bsr	ioctrlTransferSub
	exg.l	d5,a1			;d5→a0,a1
	rts

;----------------------------------------------------------------
;ブロックデバイスへのIOCTRLによる出力
;<d4.l:今回の転送バイト数
;<d5.l:目的のバッファのアドレス
;<a0.l:一時バッファの先頭アドレス
;<a1.l:デバイスヘッダ
;<a5.l:新しいリクエストヘッダ(構築済み)
;>d5.l:目的のバッファの次のアドレス
;*d5,?d0/a0
ioctrlWriteTransfer:
;目的のバッファから一時バッファにコピーする
					;元  先,デバイスヘッダ
					;d5→a0,a1
	exg.l	d5,a1			;a1→a0,d5
	exg.l	a0,a1			;a0→a1,d5
	bsr	ioctrlTransferSub
	movea.l	d5,a1			;a0→??,a1
	move.l	a0,d5			;d5→??,a1
;デバイスの処理を実行する
	bsr	deviceGo		;デバイスの処理を実行する(キャッシュ操作を伴う)
	tst.b	(3,a5)			;エラーチェック
	bne	ioctrlTransferError	;エラーが発生したので中止する
	rts

;----------------------------------------------------------------
;転送サブルーチン
;<d4.l:今回の転送バイト数
;<a0.l:転送元の先頭アドレス
;<a1.l:転送先の先頭アドレス
;>a0.l:転送元の次のアドレス
;>a1.l:転送先の次のアドレス
;*a0-a1,?d0
ioctrlTransferSub:
	move.l	d4,d0			;バイト数
;<d0.l:転送バイト数
;<a0.l:転送元のアドレス
;<a1.l:転送先のアドレス
@@:	move.b	(a0)+,(a1)+
	subq.l	#1,d0
	bne	@b
	rts

;----------------------------------------------------------------
;デバイスヘッダとユニット番号から内部DPBテーブルを探す
;<a1.l:デバイスヘッダ
;<a5.l:リクエストヘッダ
;>a0.l:内部DPBテーブル
;	-1	見つからなかった
;>n-flag:pl=見つかった,mi=見つからなかった
searchInnerDpb:
	move.l	d0,-(sp)
	move.b	(1,a5),d0		;ユニット番号
	movea.l	$1C3C.w,a0		;[$1C3C.w].l:内部DPBテーブルの先頭アドレス
	cmpa.l	(2,a0),a1		;デバイスヘッダ
	beq	3f
1:	movea.l	(6,a0),a0		;次の内部DPBテーブル
	tst.l	a0
	bmi	9f			;見つからなかった(見つからないはずはないが念のため)
2:	cmpa.l	(2,a0),a1		;デバイスヘッダ
	bne	1b
;デバイスヘッダが一致した
3:	cmp.b	(1,a0),d0		;ユニット番号を比較
	bne	1b			;ユニット番号が異なる
9:	move.l	(sp)+,d0
	tst.l	a0			;デバイスヘッダまたは-1
	rts