summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--etc/MAKEDEV33
-rw-r--r--etc/disktab9
-rw-r--r--etc/etc.i386/MAKEDEV33
-rw-r--r--etc/etc.i386/disktab9
-rw-r--r--sys/amd64/conf/GENERIC5
-rw-r--r--sys/conf/NOTES6
-rw-r--r--sys/conf/files.i3863
-rw-r--r--sys/conf/majors4
-rw-r--r--sys/i386/conf/GENERIC5
-rw-r--r--sys/i386/conf/LINT6
-rw-r--r--sys/i386/conf/NOTES6
-rw-r--r--sys/i386/conf/devices.i3863
-rw-r--r--sys/i386/conf/files.i3863
-rw-r--r--sys/i386/conf/majors.i3864
-rw-r--r--sys/i386/isa/atapi.c15
-rw-r--r--sys/i386/isa/atapi.h1
-rw-r--r--sys/i386/isa/wd.c4
-rw-r--r--sys/i386/isa/wfd.c780
-rw-r--r--sys/pc98/pc98/atapi.h1
-rw-r--r--sys/pc98/pc98/wfd.c780
20 files changed, 1681 insertions, 29 deletions
diff --git a/etc/MAKEDEV b/etc/MAKEDEV
index 03b5ae4..0f65cb6 100644
--- a/etc/MAKEDEV
+++ b/etc/MAKEDEV
@@ -37,6 +37,7 @@
#
# Disks:
# wd* "Winchester" disk drives (ST506,IDE,ESDI,RLL,...)
+# wfd* "IDE floppy" disk drives (LS-120)
# fd* "floppy" disk drives (3 1/2", 5 1/4")
# sd* "SCSI disks"
# cd* "SCSI CD-ROM disks"
@@ -106,7 +107,7 @@
# perfmon CPU performance-monitoring counters
# pci PCI configuration-space access from user mode
#
-# $Id: MAKEDEV,v 1.148 1998/01/03 11:53:52 jkh Exp $
+# $Id: MAKEDEV,v 1.149 1998/01/09 18:32:51 steve Exp $
#
PATH=/sbin:/bin/:/usr/bin:/usr/sbin:$PATH
@@ -260,17 +261,27 @@ wt*)
;;
# Individual slices.
-od*s*|sd*s*|vn*s*|wd*s*)
+od*s*|sd*s*|vn*s*|wd*s*|wfd*s*)
umask $disk_umask
case $i in
od*s*) name=od; blk=20; chr=70;;
sd*s*) name=sd; blk=4; chr=13;;
wd*s*) name=wd; blk=0; chr=3;;
vn*s*) name=vn; blk=15; chr=43;;
+ wfd*s*) name=wfd; blk=24; chr=87;;
+ esac
+ case $i in
+ wfd*s*)
+ unit=`expr $i : '...\([0-9]*\)s'`
+ slice=`expr $i : '...[0-9]*s\([0-9]*\)'`
+ part=`expr $i : '...[0-9]*s[0-9]*\(.*\)'`
+ ;;
+ *)
+ unit=`expr $i : '..\([0-9]*\)s'`
+ slice=`expr $i : '..[0-9]*s\([0-9]*\)'`
+ part=`expr $i : '..[0-9]*s[0-9]*\(.*\)'`
+ ;;
esac
- unit=`expr $i : '..\([0-9]*\)s'`
- slice=`expr $i : '..[0-9]*s\([0-9]*\)'`
- part=`expr $i : '..[0-9]*s[0-9]*\(.*\)'`
case $unit in
[0-9]|[0-9][0-9]|[0-4][0-9][0-9]|50[0-9]|51[0-1])
case $slice in
@@ -419,15 +430,23 @@ ft*)
umask 77
;;
-od*|sd*|vn*|wd*)
+od*|sd*|vn*|wd*|wfd*)
umask $disk_umask
case $i in
od*) name=od; blk=20; chr=70;;
sd*) name=sd; blk=4; chr=13;;
vn*) name=vn; blk=15; chr=43;;
wd*) name=wd; blk=0; chr=3;;
+ wfd*) name=wfd; blk=24; chr=87;;
+ esac
+ case $i in
+ wfd*)
+ unit=`expr $i : '...\(.*\)'`
+ ;;
+ *)
+ unit=`expr $i : '..\(.*\)'`
+ ;;
esac
- unit=`expr $i : '..\(.*\)'`
case $unit in
[0-9]|[0-9][0-9]|[0-4][0-9][0-9]|50[0-9]|51[0-1])
for slicepartname in s0h s1 s2 s3 s4
diff --git a/etc/disktab b/etc/disktab
index 08824c4..9947370 100644
--- a/etc/disktab
+++ b/etc/disktab
@@ -99,6 +99,15 @@ fd1720:\
:pc#3444:oc#0:bc#4096:fc#512:
#
+# LS-120 floppy-format.
+#
+fd120m|floppy120|floppy120m|3.5in LS-120 Floppy:\
+ :ty=floppy:se#512:nt#8:rm#300:ns#32:nc#963:\
+ :pa#246528:oa#0:ba#4096:fa#512:\
+ :pb#246528:ob#0:bb#4096:fb#512:\
+ :pc#246528:oc#0:bc#4096:fc#512:
+
+#
# Harddisk formats
#
qp120at|Quantum Peripherals 120MB IDE:\
diff --git a/etc/etc.i386/MAKEDEV b/etc/etc.i386/MAKEDEV
index 03b5ae4..0f65cb6 100644
--- a/etc/etc.i386/MAKEDEV
+++ b/etc/etc.i386/MAKEDEV
@@ -37,6 +37,7 @@
#
# Disks:
# wd* "Winchester" disk drives (ST506,IDE,ESDI,RLL,...)
+# wfd* "IDE floppy" disk drives (LS-120)
# fd* "floppy" disk drives (3 1/2", 5 1/4")
# sd* "SCSI disks"
# cd* "SCSI CD-ROM disks"
@@ -106,7 +107,7 @@
# perfmon CPU performance-monitoring counters
# pci PCI configuration-space access from user mode
#
-# $Id: MAKEDEV,v 1.148 1998/01/03 11:53:52 jkh Exp $
+# $Id: MAKEDEV,v 1.149 1998/01/09 18:32:51 steve Exp $
#
PATH=/sbin:/bin/:/usr/bin:/usr/sbin:$PATH
@@ -260,17 +261,27 @@ wt*)
;;
# Individual slices.
-od*s*|sd*s*|vn*s*|wd*s*)
+od*s*|sd*s*|vn*s*|wd*s*|wfd*s*)
umask $disk_umask
case $i in
od*s*) name=od; blk=20; chr=70;;
sd*s*) name=sd; blk=4; chr=13;;
wd*s*) name=wd; blk=0; chr=3;;
vn*s*) name=vn; blk=15; chr=43;;
+ wfd*s*) name=wfd; blk=24; chr=87;;
+ esac
+ case $i in
+ wfd*s*)
+ unit=`expr $i : '...\([0-9]*\)s'`
+ slice=`expr $i : '...[0-9]*s\([0-9]*\)'`
+ part=`expr $i : '...[0-9]*s[0-9]*\(.*\)'`
+ ;;
+ *)
+ unit=`expr $i : '..\([0-9]*\)s'`
+ slice=`expr $i : '..[0-9]*s\([0-9]*\)'`
+ part=`expr $i : '..[0-9]*s[0-9]*\(.*\)'`
+ ;;
esac
- unit=`expr $i : '..\([0-9]*\)s'`
- slice=`expr $i : '..[0-9]*s\([0-9]*\)'`
- part=`expr $i : '..[0-9]*s[0-9]*\(.*\)'`
case $unit in
[0-9]|[0-9][0-9]|[0-4][0-9][0-9]|50[0-9]|51[0-1])
case $slice in
@@ -419,15 +430,23 @@ ft*)
umask 77
;;
-od*|sd*|vn*|wd*)
+od*|sd*|vn*|wd*|wfd*)
umask $disk_umask
case $i in
od*) name=od; blk=20; chr=70;;
sd*) name=sd; blk=4; chr=13;;
vn*) name=vn; blk=15; chr=43;;
wd*) name=wd; blk=0; chr=3;;
+ wfd*) name=wfd; blk=24; chr=87;;
+ esac
+ case $i in
+ wfd*)
+ unit=`expr $i : '...\(.*\)'`
+ ;;
+ *)
+ unit=`expr $i : '..\(.*\)'`
+ ;;
esac
- unit=`expr $i : '..\(.*\)'`
case $unit in
[0-9]|[0-9][0-9]|[0-4][0-9][0-9]|50[0-9]|51[0-1])
for slicepartname in s0h s1 s2 s3 s4
diff --git a/etc/etc.i386/disktab b/etc/etc.i386/disktab
index 08824c4..9947370 100644
--- a/etc/etc.i386/disktab
+++ b/etc/etc.i386/disktab
@@ -99,6 +99,15 @@ fd1720:\
:pc#3444:oc#0:bc#4096:fc#512:
#
+# LS-120 floppy-format.
+#
+fd120m|floppy120|floppy120m|3.5in LS-120 Floppy:\
+ :ty=floppy:se#512:nt#8:rm#300:ns#32:nc#963:\
+ :pa#246528:oa#0:ba#4096:fa#512:\
+ :pb#246528:ob#0:bb#4096:fb#512:\
+ :pc#246528:oc#0:bc#4096:fc#512:
+
+#
# Harddisk formats
#
qp120at|Quantum Peripherals 120MB IDE:\
diff --git a/sys/amd64/conf/GENERIC b/sys/amd64/conf/GENERIC
index 14db321..c89dee9 100644
--- a/sys/amd64/conf/GENERIC
+++ b/sys/amd64/conf/GENERIC
@@ -11,7 +11,7 @@
# device lines is present in the ./LINT configuration file. If you are
# in doubt as to the purpose or necessity of a line, check first in LINT.
#
-# $Id: GENERIC,v 1.101 1997/10/31 22:10:02 jseger Exp $
+# $Id: GENERIC,v 1.102 1998/01/11 02:16:38 jkh Exp $
machine "i386"
cpu "I386_CPU"
@@ -58,7 +58,8 @@ disk wd3 at wdc1 drive 1
options ATAPI #Enable ATAPI support for IDE bus
options ATAPI_STATIC #Don't do it as an LKM
-device wcd0 #IDE CD-ROM
+device wcd0 #IDE CD-ROM
+device wfd0 #IDE Floppy (e.g. LS-120)
# A single entry for any of these controllers (ncr, ahb, ahc, amd) is
# sufficient for any number of installed devices.
diff --git a/sys/conf/NOTES b/sys/conf/NOTES
index 7c19703..3c1f8c9 100644
--- a/sys/conf/NOTES
+++ b/sys/conf/NOTES
@@ -2,7 +2,7 @@
# LINT -- config file for checking all the sources, tries to pull in
# as much of the source tree as it can.
#
-# $Id: LINT,v 1.390 1997/12/31 21:46:17 obrien Exp $
+# $Id: LINT,v 1.391 1998/01/14 19:41:36 phk Exp $
#
# NB: You probably don't want to try running a kernel built from this
# file. Instead, you should start from GENERIC, and add options from
@@ -833,6 +833,10 @@ options ATAPI_STATIC #Don't do it as an LKM
# IDE CD-ROM driver - requires wdc controller and ATAPI option
device wcd0
+# IDE floppy driver - requires wdc controller and ATAPI option
+device wfd0
+
+
#
# Standard floppy disk controllers and floppy tapes: `fdc', `fd', and `ft'
#
diff --git a/sys/conf/files.i386 b/sys/conf/files.i386
index 885dd0c..e3867f4 100644
--- a/sys/conf/files.i386
+++ b/sys/conf/files.i386
@@ -1,7 +1,7 @@
# This file tells config what files go into building a kernel,
# files marked standard are always included.
#
-# $Id: files.i386,v 1.184 1998/01/08 23:13:19 jmg Exp $
+# $Id: files.i386,v 1.185 1998/01/15 07:30:54 gibbs Exp $
#
# The long compile-with and dependency lines are required because of
# limitations in config: backslash-newline doesn't work in strings, and
@@ -240,6 +240,7 @@ i386/isa/atapi.c optional atapi device-driver
i386/isa/wcd.c optional wcd device-driver
i386/isa/wd7000.c optional wds device-driver
i386/isa/wt.c optional wt device-driver
+i386/isa/wfd.c optional wfd device-driver
i386/linux/imgact_linux.c optional compat_linux
i386/linux/linux_dummy.c optional compat_linux
i386/linux/linux_file.c optional compat_linux
diff --git a/sys/conf/majors b/sys/conf/majors
index 270a024..75cac8c 100644
--- a/sys/conf/majors
+++ b/sys/conf/majors
@@ -1,4 +1,4 @@
-$Id: majors.i386,v 1.22 1997/11/17 07:58:23 jmg Exp $
+$Id: majors.i386,v 1.23 1997/12/09 10:51:11 jamil Exp $
Hopefully, this list will one day be obsoleted by DEVFS, but for now
this is the current allocation of device major numbers.
@@ -37,6 +37,7 @@ blkdev name comments
21 ccd concatenated disk
22 gd Geometry disk.
23 worm SCSI "worm type"
+24 wfd ATAPI Floppy client of "ata"
chrdev name comments
0 cn console
1 ctty /dev/tty
@@ -125,3 +126,4 @@ chrdev name comments
84 ttxt Unitext teletext decoder (arg@arg1.demon.co.uk)
85 vesa VESA support device (j_mini@efn.org)
86 alog Industrial Computer Source AIO8-P driver
+87 wfd ATAPI floppy client of "ata"
diff --git a/sys/i386/conf/GENERIC b/sys/i386/conf/GENERIC
index 14db321..c89dee9 100644
--- a/sys/i386/conf/GENERIC
+++ b/sys/i386/conf/GENERIC
@@ -11,7 +11,7 @@
# device lines is present in the ./LINT configuration file. If you are
# in doubt as to the purpose or necessity of a line, check first in LINT.
#
-# $Id: GENERIC,v 1.101 1997/10/31 22:10:02 jseger Exp $
+# $Id: GENERIC,v 1.102 1998/01/11 02:16:38 jkh Exp $
machine "i386"
cpu "I386_CPU"
@@ -58,7 +58,8 @@ disk wd3 at wdc1 drive 1
options ATAPI #Enable ATAPI support for IDE bus
options ATAPI_STATIC #Don't do it as an LKM
-device wcd0 #IDE CD-ROM
+device wcd0 #IDE CD-ROM
+device wfd0 #IDE Floppy (e.g. LS-120)
# A single entry for any of these controllers (ncr, ahb, ahc, amd) is
# sufficient for any number of installed devices.
diff --git a/sys/i386/conf/LINT b/sys/i386/conf/LINT
index 7c19703..3c1f8c9 100644
--- a/sys/i386/conf/LINT
+++ b/sys/i386/conf/LINT
@@ -2,7 +2,7 @@
# LINT -- config file for checking all the sources, tries to pull in
# as much of the source tree as it can.
#
-# $Id: LINT,v 1.390 1997/12/31 21:46:17 obrien Exp $
+# $Id: LINT,v 1.391 1998/01/14 19:41:36 phk Exp $
#
# NB: You probably don't want to try running a kernel built from this
# file. Instead, you should start from GENERIC, and add options from
@@ -833,6 +833,10 @@ options ATAPI_STATIC #Don't do it as an LKM
# IDE CD-ROM driver - requires wdc controller and ATAPI option
device wcd0
+# IDE floppy driver - requires wdc controller and ATAPI option
+device wfd0
+
+
#
# Standard floppy disk controllers and floppy tapes: `fdc', `fd', and `ft'
#
diff --git a/sys/i386/conf/NOTES b/sys/i386/conf/NOTES
index 7c19703..3c1f8c9 100644
--- a/sys/i386/conf/NOTES
+++ b/sys/i386/conf/NOTES
@@ -2,7 +2,7 @@
# LINT -- config file for checking all the sources, tries to pull in
# as much of the source tree as it can.
#
-# $Id: LINT,v 1.390 1997/12/31 21:46:17 obrien Exp $
+# $Id: LINT,v 1.391 1998/01/14 19:41:36 phk Exp $
#
# NB: You probably don't want to try running a kernel built from this
# file. Instead, you should start from GENERIC, and add options from
@@ -833,6 +833,10 @@ options ATAPI_STATIC #Don't do it as an LKM
# IDE CD-ROM driver - requires wdc controller and ATAPI option
device wcd0
+# IDE floppy driver - requires wdc controller and ATAPI option
+device wfd0
+
+
#
# Standard floppy disk controllers and floppy tapes: `fdc', `fd', and `ft'
#
diff --git a/sys/i386/conf/devices.i386 b/sys/i386/conf/devices.i386
index 6e93c0c..93e3cf5 100644
--- a/sys/i386/conf/devices.i386
+++ b/sys/i386/conf/devices.i386
@@ -1,6 +1,6 @@
# This file tells what major numbers the various possible swap devices have.
#
-# $Id$
+# $Id: devices.i386,v 1.11 1997/02/22 09:31:40 peter Exp $
#
wd 0
dk 1
@@ -15,3 +15,4 @@ scd 16
pcd 17
wcd 19
od 20
+wfd 24
diff --git a/sys/i386/conf/files.i386 b/sys/i386/conf/files.i386
index 885dd0c..e3867f4 100644
--- a/sys/i386/conf/files.i386
+++ b/sys/i386/conf/files.i386
@@ -1,7 +1,7 @@
# This file tells config what files go into building a kernel,
# files marked standard are always included.
#
-# $Id: files.i386,v 1.184 1998/01/08 23:13:19 jmg Exp $
+# $Id: files.i386,v 1.185 1998/01/15 07:30:54 gibbs Exp $
#
# The long compile-with and dependency lines are required because of
# limitations in config: backslash-newline doesn't work in strings, and
@@ -240,6 +240,7 @@ i386/isa/atapi.c optional atapi device-driver
i386/isa/wcd.c optional wcd device-driver
i386/isa/wd7000.c optional wds device-driver
i386/isa/wt.c optional wt device-driver
+i386/isa/wfd.c optional wfd device-driver
i386/linux/imgact_linux.c optional compat_linux
i386/linux/linux_dummy.c optional compat_linux
i386/linux/linux_file.c optional compat_linux
diff --git a/sys/i386/conf/majors.i386 b/sys/i386/conf/majors.i386
index 270a024..75cac8c 100644
--- a/sys/i386/conf/majors.i386
+++ b/sys/i386/conf/majors.i386
@@ -1,4 +1,4 @@
-$Id: majors.i386,v 1.22 1997/11/17 07:58:23 jmg Exp $
+$Id: majors.i386,v 1.23 1997/12/09 10:51:11 jamil Exp $
Hopefully, this list will one day be obsoleted by DEVFS, but for now
this is the current allocation of device major numbers.
@@ -37,6 +37,7 @@ blkdev name comments
21 ccd concatenated disk
22 gd Geometry disk.
23 worm SCSI "worm type"
+24 wfd ATAPI Floppy client of "ata"
chrdev name comments
0 cn console
1 ctty /dev/tty
@@ -125,3 +126,4 @@ chrdev name comments
84 ttxt Unitext teletext decoder (arg@arg1.demon.co.uk)
85 vesa VESA support device (j_mini@efn.org)
86 alog Industrial Computer Source AIO8-P driver
+87 wfd ATAPI floppy client of "ata"
diff --git a/sys/i386/isa/atapi.c b/sys/i386/isa/atapi.c
index 2a7025f..56fbbfb 100644
--- a/sys/i386/isa/atapi.c
+++ b/sys/i386/isa/atapi.c
@@ -104,6 +104,7 @@
#ifndef ATAPI_MODULE
# include "wcd.h"
+# include "wfd.h"
/* # include "wmt.h" -- add your driver here */
/* # include "wmd.h" -- add your driver here */
#endif
@@ -169,6 +170,7 @@ static int atapi_start_cmd (struct atapi *ata, struct atapicmd *ac);
static int atapi_wait_cmd (struct atapi *ata, struct atapicmd *ac);
extern int wdstart (int ctrlr);
+extern int wfdattach(struct atapi*, int, struct atapi_params*, int);
extern int wcdattach(struct atapi*, int, struct atapi_params*, int);
/*
@@ -217,6 +219,8 @@ int atapi_attach (int ctlr, int unit, int port)
case AT_DRQT_ACCEL: printf (", accel"); break;
default: printf (", drq%d", ap->drqtype);
}
+ if (ata->slow)
+ ata->intrcmd = 0;
/* overlap operation supported */
if (ap->ovlapflag)
@@ -270,6 +274,14 @@ int atapi_attach (int ctlr, int unit, int port)
break;
case AT_TYPE_DIRECT: /* direct-access */
+#if NWFD > 0
+ /* ATAPI Floppy(LS-120) */
+ if (wfdattach (ata, unit, ap, ata->debug) >= 0) {
+ /* Device attached successfully. */
+ ata->attached[unit] = 1;
+ return (1);
+ }
+#endif
case AT_TYPE_CDROM: /* CD-ROM device */
#if NWCD > 0
/* ATAPI CD-ROM */
@@ -316,6 +328,7 @@ static char *cmdname (u_char cmd)
case 0x1e: return ("PREVENT_ALLOW");
case 0x25: return ("READ_CAPACITY");
case 0x28: return ("READ_BIG");
+ case 0x2a: return ("WRITE_BIG");
case 0x43: return ("READ_TOC");
case 0x42: return ("READ_SUBCHANNEL");
case 0x55: return ("MODE_SELECT_BIG");
@@ -479,7 +492,7 @@ static struct atapicmd *atapi_alloc (struct atapi *ata)
struct atapicmd *ac;
while (! ata->free)
- tsleep ((caddr_t)ata, PRIBIO, "atacmd", 0);
+ tsleep ((caddr_t)ata, PRIBIO, "atacmd", 100);
ac = ata->free;
ata->free = ac->next;
ac->busy = 1;
diff --git a/sys/i386/isa/atapi.h b/sys/i386/isa/atapi.h
index c61dad5..ca9b871 100644
--- a/sys/i386/isa/atapi.h
+++ b/sys/i386/isa/atapi.h
@@ -111,6 +111,7 @@
#define ATAPI_PREVENT_ALLOW 0x1e /* prevent/allow media removal */
#define ATAPI_READ_CAPACITY 0x25 /* get volume capacity */
#define ATAPI_READ_BIG 0x28 /* read data */
+#define ATAPI_WRITE_BIG 0x2a /* write data */
#define ATAPI_READ_TOC 0x43 /* get table of contents */
#define ATAPI_READ_SUBCHANNEL 0x42 /* get subchannel info */
#define ATAPI_MODE_SELECT_BIG 0x55 /* set device parameters */
diff --git a/sys/i386/isa/wd.c b/sys/i386/isa/wd.c
index 6bfa987..8812a6b 100644
--- a/sys/i386/isa/wd.c
+++ b/sys/i386/isa/wd.c
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)wd.c 7.2 (Berkeley) 5/9/91
- * $Id: wd.c,v 1.145 1997/12/02 21:06:32 phk Exp $
+ * $Id: wd.c,v 1.146 1997/12/06 14:27:20 bde Exp $
*/
/* TODO:
@@ -357,7 +357,7 @@ reset_ok:
* drive 2. (This seems to contradict the ATA spec.)
*/
du->dk_error = inb(du->dk_port + wd_error);
- if(du->dk_error != 0x01) {
+ if(du->dk_error != 0x01 && du->dk_error != 0) {
if(du->dk_error & 0x80) { /* drive 1 failure */
/* first set the DRV bit */
diff --git a/sys/i386/isa/wfd.c b/sys/i386/isa/wfd.c
new file mode 100644
index 0000000..3f67134
--- /dev/null
+++ b/sys/i386/isa/wfd.c
@@ -0,0 +1,780 @@
+/*
+ * Copyright (c) 1997,1998 Junichi Satoh <junichi@astec.co.jp>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer as
+ * the first lines of this file unmodified.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Junichi Satoh ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL Junichi Satoh BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: wfd.c,v 1.6 1998/01/06 15:54:53 junichi Exp junichi $
+ */
+
+/*
+ * ATAPI Floppy, LS-120 driver
+ */
+
+#include "wdc.h"
+#include "wfd.h"
+#include "opt_atapi.h"
+
+#if NWFD > 0 && NWDC > 0 && defined (ATAPI)
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/conf.h>
+#include <sys/file.h>
+#include <sys/fcntl.h>
+#include <sys/proc.h>
+#include <sys/malloc.h>
+#include <sys/buf.h>
+#include <sys/disklabel.h>
+#include <sys/diskslice.h>
+#include <sys/cdio.h>
+#include <machine/ioctl_fd.h>
+#ifdef DEVFS
+#include <sys/devfsext.h>
+#endif /*DEVFS*/
+
+#include <i386/isa/atapi.h>
+#include <i386/isa/fdc.h>
+
+static d_open_t wfdbopen;
+static d_close_t wfdbclose;
+static d_ioctl_t wfdioctl;
+static d_strategy_t wfdstrategy;
+
+#define CDEV_MAJOR 87
+#define BDEV_MAJOR 24
+static struct cdevsw wfd_cdevsw;
+static struct bdevsw wfd_bdevsw =
+ { wfdbopen, wfdbclose, wfdstrategy, wfdioctl, /*22*/
+ nodump, nopsize, 0, "wfd", &wfd_cdevsw, -1 };
+
+#ifndef ATAPI_STATIC
+static
+#endif
+int wfdattach(struct atapi*, int, struct atapi_params*, int);
+
+#define NUNIT (NWDC*2) /* Max. number of devices */
+#define UNIT(d) ((minor(d) >> 3) & 3) /* Unit part of minor device number */
+
+#define F_BOPEN 0x0001 /* The block device is opened */
+#define F_MEDIA_CHANGED 0x0002 /* The media have changed since open */
+#define F_DEBUG 0x0004 /* Print debug info */
+
+/*
+ * LS-120 Capabilities and Mechanical Status Page
+ */
+struct cappage {
+ /* Mode data header */
+ u_short data_length;
+ u_char medium_type;
+#define MDT_UNKNOWN 0x00
+#define MDT_NO_DISC 0x70
+#define MDT_DOOR_OPEN 0x71
+#define MDT_FMT_ERROR 0x72
+
+#define MDT_2DD_UN 0x10
+#define MDT_2DD 0x11
+#define MDT_2HD_UN 0x20
+#define MDT_2HD_12_98 0x22
+#define MDT_2HD_12 0x23
+#define MDT_2HD_144 0x24
+#define MDT_LS120 0x31
+
+ unsigned reserved0 :7;
+ unsigned wp :1; /* Write protect */
+ u_char reserved1[4];
+
+ /* Capabilities page */
+ unsigned page_code :6; /* Page code - Should be 0x5 */
+#define CAP_PAGE 0x05
+ unsigned reserved1_6 :1; /* Reserved */
+ unsigned ps :1; /* The device is capable of savi
+ng the page */
+ u_char page_length; /* Page Length - Should be 0x1e */
+ u_short transfer_rate; /* In kilobits per second */
+ u_char heads, sectors; /* Number of heads, Number of sectors per track */
+ u_short sector_size; /* Byes per sector */
+ u_short cyls; /* Number of cylinders */
+ u_char reserved10[10];
+ u_char motor_delay; /* Motor off delay */
+ u_char reserved21[7];
+ u_short rpm; /* Rotations per minute */
+ u_char reserved30[2];
+};
+
+/* misuse a flag to identify format operation */
+#define B_FORMAT B_XXX
+
+struct wfd {
+ struct atapi *ata; /* Controller structure */
+ int unit; /* IDE bus drive unit */
+ int lun; /* Logical device unit */
+ int flags; /* Device state flags */
+ int refcnt; /* The number of raw opens */
+ struct buf_queue_head buf_queue; /* Queue of i/o requests */
+ struct atapi_params *param; /* Drive parameters table */
+ struct cappage cap; /* Capabilities page info */
+ char description[80]; /* Device description */
+#ifdef DEVFS
+ void *cdevs;
+ void *bdevs;
+#endif
+ struct diskslices *dk_slices; /* virtual drives */
+};
+
+struct wfd *wfdtab[NUNIT]; /* Drive info by unit number */
+static int wfdnlun = 0; /* Number of configured drives */
+
+static void wfd_start (struct wfd *t);
+static void wfd_done (struct wfd *t, struct buf *bp, int resid,
+ struct atapires result);
+static void wfd_error (struct wfd *t, struct atapires result);
+static int wfd_request_wait (struct wfd *t, u_char cmd, u_char a1, u_char a2,
+ u_char a3, u_char a4, u_char a5, u_char a6, u_char a7, u_char a8,
+ u_char a9, char *addr, int count);
+static void wfd_describe (struct wfd *t);
+static int wfd_eject (struct wfd *t, int closeit);
+static void wfdstrategy1(struct buf *bp);
+
+/*
+ * Dump the array in hexadecimal format for debugging purposes.
+ */
+static void wfd_dump (int lun, char *label, void *data, int len)
+{
+ u_char *p = data;
+
+ printf ("wfd%d: %s %x", lun, label, *p++);
+ while (--len > 0)
+ printf ("-%x", *p++);
+ printf ("\n");
+}
+
+#ifndef ATAPI_STATIC
+static
+#endif
+int
+wfdattach (struct atapi *ata, int unit, struct atapi_params *ap, int debug)
+{
+ struct wfd *t;
+ struct atapires result;
+ int lun, i;
+
+#ifdef DEVFS
+ int mynor;
+#endif
+ if (wfdnlun >= NUNIT) {
+ printf ("wfd: too many units\n");
+ return (0);
+ }
+ if (!atapi_request_immediate) {
+ printf("wfd: configuration error, ATAPI core code not present!\n");
+ printf("wfd: check `options ATAPI_STATIC' in your kernel config file!\n");
+ return (0);
+ }
+ t = malloc (sizeof (struct wfd), M_TEMP, M_NOWAIT);
+ if (! t) {
+ printf ("wfd: out of memory\n");
+ return (0);
+ }
+ wfdtab[wfdnlun] = t;
+ bzero (t, sizeof (struct wfd));
+ bufq_init(&t->buf_queue);
+ t->ata = ata;
+ t->unit = unit;
+ lun = t->lun = wfdnlun++;
+ t->param = ap;
+ t->flags = F_MEDIA_CHANGED;
+ t->refcnt = 0;
+ if (debug) {
+ t->flags |= F_DEBUG;
+ /* Print params. */
+ wfd_dump (t->lun, "info", ap, sizeof *ap);
+ }
+
+ /* Get drive capabilities. */
+ /* Do it twice to avoid the stale media changed state. */
+ for (i = 0; i < 2; i++) {
+ result = atapi_request_immediate (ata, unit, ATAPI_MODE_SENSE,
+ 0, CAP_PAGE, 0, 0, 0, 0,
+ sizeof (t->cap) >> 8, sizeof (t->cap),
+ 0, 0, 0, 0, 0, 0, 0, (char*) &t->cap, sizeof (t->cap));
+ }
+
+ if (result.code == RES_ERR &&
+ (result.error & AER_SKEY) == AER_SK_UNIT_ATTENTION)
+ result = atapi_request_immediate (ata, unit, ATAPI_MODE_SENSE,
+ 0, CAP_PAGE, 0, 0, 0, 0, sizeof (t->cap) >> 8,
+ sizeof (t->cap), 0, 0, 0, 0, 0, 0, 0,
+ (char*) &t->cap, sizeof (t->cap));
+
+ /* Some drives have shorter capabilities page. */
+ if (result.code == RES_UNDERRUN)
+ result.code = 0;
+
+ if (result.code == 0) {
+ wfd_describe (t);
+ if (t->flags & F_DEBUG)
+ wfd_dump (t->lun, "cap", &t->cap, sizeof t->cap);
+ } else
+ return -1;
+
+#ifdef DEVFS
+ mynor = dkmakeminor(unit, WHOLE_DISK_SLICE, RAW_PART);
+ t->bdevs = devfs_add_devswf(&wfd_bdevsw, mynor,
+ DV_BLK, UID_ROOT, GID_OPERATOR, 0640,
+ "wfd%d", unit);
+ t->cdevs = devfs_add_devswf(&wfd_cdevsw, mynor,
+ DV_CHR, UID_ROOT, GID_OPERATOR, 0640,
+ "rwfd%d", unit);
+#endif /* DEVFS */
+ return (1);
+}
+
+void wfd_describe (struct wfd *t)
+{
+ int no_print = 0;
+
+ t->cap.cyls = ntohs (t->cap.cyls);
+ t->cap.sector_size = ntohs (t->cap.sector_size);
+
+ printf ("wfd%d: ", t->lun);
+ switch (t->cap.medium_type) {
+ case MDT_UNKNOWN:
+ printf ("medium type unknown (no disk)");
+ no_print = 1;
+ break;
+ case MDT_2DD_UN:
+ printf ("2DD(capacity unknown) floppy disk loaded");
+ no_print = 1;
+ break;
+ case MDT_2DD:
+ printf ("720KB floppy disk loaded");
+ break;
+ case MDT_2HD_UN:
+ printf ("2HD(capacity unknown) floppy disk loaded");
+ no_print = 1;
+ break;
+ case MDT_2HD_12_98:
+ printf ("1.25MB(PC-9801 format) floppy disk loaded");
+ break;
+ case MDT_2HD_12:
+ printf ("1.2MB floppy disk loaded");
+ break;
+ case MDT_2HD_144:
+ printf ("1.44MB floppy disk loaded");
+ break;
+ case MDT_LS120:
+ printf ("120MB floppy disk loaded");
+ break;
+ case MDT_NO_DISC:
+ printf ("no disc inside");
+ no_print = 1;
+ break;
+ case MDT_DOOR_OPEN:
+ printf ("door open");
+ no_print = 1;
+ break;
+ case MDT_FMT_ERROR:
+ printf ("medium format error");
+ no_print = 1;
+ break;
+ default:
+ printf ("medium type=0x%x", t->cap.medium_type);
+ break;
+ }
+ if (t->cap.wp)
+ printf(", write protected");
+ printf ("\n");
+
+ if (!no_print) {
+ printf ("wfd%d: ", t->lun);
+ printf ("%lu cyls", t->cap.cyls);
+ printf (", %lu heads, %lu S/T", t->cap.heads, t->cap.sectors);
+ printf (", %lu B/S", t->cap.sector_size);
+ printf ("\n");
+ }
+}
+
+int wfdbopen (dev_t dev, int flags, int fmt, struct proc *p)
+{
+ int lun = UNIT(dev);
+ struct wfd *t;
+ struct atapires result;
+ int errcode = 0;
+ struct disklabel label;
+
+ /* Check that the device number is legal
+ * and the ATAPI driver is loaded. */
+ if (lun >= wfdnlun || ! atapi_request_immediate) {
+ printf("ENXIO lun=%d, wfdnlun=%d, im=%d\n", lun, wfdnlun, atapi_request_immediate);
+ return (ENXIO);
+ }
+ t = wfdtab[lun];
+
+ t->flags &= ~F_MEDIA_CHANGED;
+ /* Lock the media. */
+ wfd_request_wait (t, ATAPI_PREVENT_ALLOW,
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
+
+ /* Sense the media type */
+ result = atapi_request_wait (t->ata, t->unit, ATAPI_MODE_SENSE,
+ 0, CAP_PAGE, 0, 0, 0, 0,
+ sizeof (t->cap) >> 8, sizeof (t->cap),
+ 0, 0, 0, 0, 0, 0, 0,
+ (char*) &t->cap, sizeof (t->cap));
+ if (result.code)
+ printf ("wfd%d: Sense the media type is failed.\n", t->lun);
+ else {
+ t->cap.cyls = ntohs (t->cap.cyls);
+ t->cap.sector_size = ntohs (t->cap.sector_size);
+ }
+
+ /* Build label for whole disk. */
+ bzero(&label, sizeof label);
+ label.d_secsize = t->cap.sector_size;
+ label.d_nsectors = t->cap.sectors;
+ label.d_ntracks = t->cap.heads;
+ label.d_ncylinders = t->cap.cyls;
+ label.d_secpercyl = t->cap.heads * t->cap.sectors;
+ label.d_rpm = 720;
+ label.d_secperunit = label.d_secpercyl * t->cap.cyls;
+
+ /* Initialize slice tables. */
+ errcode = dsopen("wfd", dev, fmt, &t->dk_slices, &label, wfdstrategy1,
+ (ds_setgeom_t *)NULL, &wfd_bdevsw, &wfd_cdevsw);
+ if (errcode != 0)
+ return errcode;
+
+ t->flags |= F_BOPEN;
+ return (0);
+}
+
+/*
+ * Close the device. Only called if we are the LAST
+ * occurence of an open device.
+ */
+int wfdbclose (dev_t dev, int flags, int fmt, struct proc *p)
+{
+ int lun = UNIT(dev);
+ struct wfd *t = wfdtab[lun];
+
+ dsclose(dev, fmt, t->dk_slices);
+ if(!dsisopen(t->dk_slices)) {
+ /* If we were the last open of the entire device, release it. */
+ if (! t->refcnt)
+ wfd_request_wait (t, ATAPI_PREVENT_ALLOW,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ t->flags &= ~F_BOPEN;
+ }
+ return (0);
+}
+
+static void
+wfdstrategy1(struct buf *bp)
+{
+ /*
+ * XXX - do something to make wdstrategy() but not this block while
+ * we're doing dsinit() and dsioctl().
+ */
+ wfdstrategy(bp);
+}
+
+/*
+ * Actually translate the requested transfer into one the physical driver can
+ * understand. The transfer is described by a buf and will include only one
+ * physical transfer.
+ */
+void wfdstrategy (struct buf *bp)
+{
+ int lun = UNIT(bp->b_dev);
+ struct wfd *t = wfdtab[lun];
+ int x;
+
+ /* If it's a null transfer, return immediatly. */
+ if (bp->b_bcount == 0) {
+ bp->b_resid = 0;
+ biodone (bp);
+ return;
+ }
+
+ /* Process transfer request. */
+ bp->b_pblkno = bp->b_blkno;
+ bp->b_resid = bp->b_bcount;
+
+ /*
+ * Do bounds checking, adjust transfer, and set b_pblkno.
+ */
+ if (dscheck(bp, t->dk_slices) <= 0) {
+ biodone(bp);
+ return;
+ }
+ bp->b_blkno = bp->b_pblkno;
+
+ x = splbio();
+
+ /* Place it in the queue of disk activities for this disk. */
+ bufqdisksort (&t->buf_queue, bp);
+
+ /* Tell the device to get going on the transfer if it's
+ * not doing anything, otherwise just wait for completion. */
+ wfd_start (t);
+ splx(x);
+}
+
+/*
+ * Look to see if there is a buf waiting for the device
+ * and that the device is not already busy. If both are true,
+ * It dequeues the buf and creates an ATAPI command to perform the
+ * transfer in the buf.
+ * The bufs are queued by the strategy routine (wfdstrategy).
+ * Must be called at the correct (splbio) level.
+ */
+static void wfd_start (struct wfd *t)
+{
+ struct buf *bp = bufq_first(&t->buf_queue);
+ u_long blkno, nblk;
+ u_char op_code;
+ long count;
+
+ /* See if there is a buf to do and we are not already doing one. */
+ if (! bp)
+ return;
+
+ /* Unqueue the request. */
+ bufq_remove(&t->buf_queue, bp);
+
+ /* We have a buf, now we should make a command
+ * First, translate the block to absolute and put it in terms of the
+ * logical blocksize of the device.
+ * What if something asks for 512 bytes not on a 2k boundary? */
+ blkno = bp->b_blkno / (t->cap.sector_size / 512);
+ nblk = (bp->b_bcount + (t->cap.sector_size - 1)) / t->cap.sector_size;
+
+ if(bp->b_flags & B_READ) {
+ op_code = ATAPI_READ_BIG;
+ count = bp->b_bcount;
+ } else {
+ op_code = ATAPI_WRITE_BIG;
+ count = -bp->b_bcount;
+ }
+
+ atapi_request_callback (t->ata, t->unit, op_code, 0,
+ blkno>>24, blkno>>16, blkno>>8, blkno, 0, nblk>>8, nblk, 0, 0,
+ 0, 0, 0, 0, 0, (u_char*) bp->b_data, count,
+ (void*)wfd_done, t, bp);
+}
+
+static void wfd_done (struct wfd *t, struct buf *bp, int resid,
+ struct atapires result)
+{
+ if (result.code) {
+ wfd_error (t, result);
+ bp->b_error = EIO;
+ bp->b_flags |= B_ERROR;
+ } else
+ bp->b_resid = resid;
+ biodone (bp);
+ wfd_start (t);
+}
+
+static void wfd_error (struct wfd *t, struct atapires result)
+{
+ if (result.code != RES_ERR)
+ return;
+ switch (result.error & AER_SKEY) {
+ case AER_SK_NOT_READY:
+ if (result.error & ~AER_SKEY) {
+ /* Not Ready */
+ printf ("wfd%d: not ready\n", t->lun);
+ return;
+ }
+ /* Tray open. */
+ if (! (t->flags & F_MEDIA_CHANGED))
+ printf ("wfd%d: tray open\n", t->lun);
+ t->flags |= F_MEDIA_CHANGED;
+ return;
+
+ case AER_SK_UNIT_ATTENTION:
+ /* Media changed. */
+ if (! (t->flags & F_MEDIA_CHANGED))
+ printf ("wfd%d: media changed\n", t->lun);
+ t->flags |= F_MEDIA_CHANGED;
+ return;
+
+ case AER_SK_ILLEGAL_REQUEST:
+ /* Unknown command or invalid command arguments. */
+ if (t->flags & F_DEBUG)
+ printf ("wfd%d: invalid command\n", t->lun);
+ return;
+ }
+ printf ("wfd%d: i/o error, status=%b, error=%b\n", t->lun,
+ result.status, ARS_BITS, result.error, AER_BITS);
+}
+
+static int wfd_request_wait (struct wfd *t, u_char cmd, u_char a1, u_char a2,
+ u_char a3, u_char a4, u_char a5, u_char a6, u_char a7, u_char a8,
+ u_char a9, char *addr, int count)
+{
+ struct atapires result;
+
+ result = atapi_request_wait (t->ata, t->unit, cmd,
+ a1, a2, a3, a4, a5, a6, a7, a8, a9, 0, 0, 0, 0, 0, 0,
+ addr, count);
+ if (result.code) {
+ wfd_error (t, result);
+ return (EIO);
+ }
+ return (0);
+}
+
+/*
+ * Perform special action on behalf of the user.
+ * Knows about the internals of this device
+ */
+int wfdioctl (dev_t dev, int cmd, caddr_t addr, int flag, struct proc *p)
+{
+ int lun = UNIT(dev);
+ struct wfd *t = wfdtab[lun];
+ int error = 0;
+
+ struct disklabel *dl;
+ char buffer[DEV_BSIZE];
+
+ error = dsioctl("wfd", dev, cmd, addr, flag, &t->dk_slices,
+ wfdstrategy1, (ds_setgeom_t *)NULL);
+ if (error != -1)
+ return (error);
+
+ if (t->flags & F_MEDIA_CHANGED)
+ switch (cmd) {
+ case CDIOCSETDEBUG:
+ case CDIOCCLRDEBUG:
+ case CDIOCRESET:
+ /* These ops are media change transparent. */
+ break;
+ default:
+ /* Lock the media. */
+ wfd_request_wait (t, ATAPI_PREVENT_ALLOW,
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
+ break;
+ }
+ switch (cmd) {
+ case CDIOCSETDEBUG:
+ if (p->p_cred->pc_ucred->cr_uid)
+ return (EPERM);
+ t->flags |= F_DEBUG;
+ atapi_debug (t->ata, 1);
+ return 0;
+ case CDIOCCLRDEBUG:
+ if (p->p_cred->pc_ucred->cr_uid)
+ return (EPERM);
+ t->flags &= ~F_DEBUG;
+ atapi_debug (t->ata, 0);
+ return 0;
+ case CDIOCRESET:
+ if (p->p_cred->pc_ucred->cr_uid)
+ return (EPERM);
+ return wfd_request_wait (t, ATAPI_TEST_UNIT_READY,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ case CDIOCEJECT:
+ /* Don't allow eject if the device is opened
+ * by somebody (not us) in block mode. */
+ if ((t->flags & F_BOPEN) && t->refcnt)
+ return (EBUSY);
+ return wfd_eject (t, 0);
+ case CDIOCCLOSE:
+ if ((t->flags & F_BOPEN) && t->refcnt)
+ return (0);
+ return wfd_eject (t, 1);
+ default:
+ return (ENOTTY);
+ }
+ return (error);
+}
+
+static int wfd_eject (struct wfd *t, int closeit)
+{
+ struct atapires result;
+
+ /* Try to stop the disc. */
+ result = atapi_request_wait (t->ata, t->unit, ATAPI_START_STOP,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+
+ if (result.code == RES_ERR &&
+ ((result.error & AER_SKEY) == AER_SK_NOT_READY ||
+ (result.error & AER_SKEY) == AER_SK_UNIT_ATTENTION)) {
+ int err;
+
+ if (!closeit)
+ return (0);
+ /*
+ * The disc was unloaded.
+ * Load it (close tray).
+ * Read the table of contents.
+ */
+ err = wfd_request_wait (t, ATAPI_START_STOP,
+ 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0);
+ if (err)
+ return (err);
+
+ /* Lock the media. */
+ wfd_request_wait (t, ATAPI_PREVENT_ALLOW,
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
+
+ return (0);
+ }
+
+ if (result.code) {
+ wfd_error (t, result);
+ return (EIO);
+ }
+
+ if (closeit)
+ return (0);
+
+ /* Give it some time to stop spinning. */
+ tsleep ((caddr_t)&lbolt, PRIBIO, "wfdej1", 0);
+ tsleep ((caddr_t)&lbolt, PRIBIO, "wfdej2", 0);
+
+ /* Unlock. */
+ wfd_request_wait (t, ATAPI_PREVENT_ALLOW,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+
+ /* Eject. */
+ t->flags |= F_MEDIA_CHANGED;
+ return wfd_request_wait (t, ATAPI_START_STOP,
+ 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0);
+}
+
+#ifdef WFD_MODULE
+/*
+ * Loadable ATAPI Floppy driver stubs.
+ */
+#include <sys/exec.h>
+#include <sys/sysent.h>
+#include <sys/lkm.h>
+
+/*
+ * Construct lkm_dev structures (see lkm.h).
+ * Our bdevsw/cdevsw slot numbers are 19/69.
+ */
+
+
+MOD_DEV(wfd, LM_DT_BLOCK, BDEV_MAJOR, &wfd_bdevsw);
+MOD_DEV(rwfd, LM_DT_CHAR, CDEV_MAJOR, &wfd_cdevsw);
+
+/*
+ * Function called when loading the driver.
+ */
+int wfd_load (struct lkm_table *lkmtp, int cmd)
+{
+ struct atapi *ata;
+ int n, u;
+
+ if (! atapi_start)
+ /* No ATAPI driver available. */
+ return EPROTONOSUPPORT;
+ n = 0;
+ for (ata=atapi_tab; ata<atapi_tab+2; ++ata)
+ if (ata->port)
+ for (u=0; u<2; ++u)
+ /* Probing controller ata->ctrlr, unit u. */
+ if (ata->params[u] && ! ata->attached[u] &&
+ wfdattach (ata, u, ata->params[u],
+ ata->debug) >= 0)
+ {
+ /* Drive found. */
+ ata->attached[u] = 1;
+ ++n;
+ }
+ if (! n)
+ /* No IDE Floppies found. */
+ return ENXIO;
+ return 0;
+}
+
+/*
+ * Function called when unloading the driver.
+ */
+int wfd_unload (struct lkm_table *lkmtp, int cmd)
+{
+ struct wfd **t;
+
+ for (t=wfdtab; t<wfdtab+wfdnlun; ++t)
+ if (((*t)->flags & F_BOPEN) || (*t)->refcnt)
+ /* The device is opened, cannot unload the driver. */
+ return EBUSY;
+ for (t=wfdtab; t<wfdtab+wfdnlun; ++t) {
+ (*t)->ata->attached[(*t)->unit] = 0;
+ free (*t, M_TEMP);
+ }
+ wfdnlun = 0;
+ bzero (wfdtab, sizeof(wfdtab));
+ return 0;
+}
+
+/*
+ * Dispatcher function for the module (load/unload/stat).
+ */
+int wfd_mod (struct lkm_table *lkmtp, int cmd, int ver)
+{
+ int err = 0;
+
+ if (ver != LKM_VERSION)
+ return EINVAL;
+
+ if (cmd == LKM_E_LOAD)
+ err = wfd_load (lkmtp, cmd);
+ else if (cmd == LKM_E_UNLOAD)
+ err = wfd_unload (lkmtp, cmd);
+ if (err)
+ return err;
+
+ /* XXX Poking around in the LKM internals like this is bad.
+ */
+ /* Register the cdevsw entry. */
+ lkmtp->private.lkm_dev = & MOD_PRIVATE(rwfd);
+ err = lkmdispatch (lkmtp, cmd);
+ if (err)
+ return err;
+
+ /* Register the bdevsw entry. */
+ lkmtp->private.lkm_dev = & MOD_PRIVATE(wfd);
+ return lkmdispatch (lkmtp, cmd);
+}
+#endif /* WFD_MODULE */
+
+static wfd_devsw_installed = 0;
+
+static void wfd_drvinit(void *unused)
+{
+ if( ! wfd_devsw_installed ) {
+ bdevsw_add_generic(BDEV_MAJOR, CDEV_MAJOR, &wfd_bdevsw);
+ wfd_devsw_installed = 1;
+ }
+}
+
+SYSINIT(wfddev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,wfd_drvinit,NULL)
+
+
+#endif /* NWFD && NWDC && ATAPI */
diff --git a/sys/pc98/pc98/atapi.h b/sys/pc98/pc98/atapi.h
index c61dad5..ca9b871 100644
--- a/sys/pc98/pc98/atapi.h
+++ b/sys/pc98/pc98/atapi.h
@@ -111,6 +111,7 @@
#define ATAPI_PREVENT_ALLOW 0x1e /* prevent/allow media removal */
#define ATAPI_READ_CAPACITY 0x25 /* get volume capacity */
#define ATAPI_READ_BIG 0x28 /* read data */
+#define ATAPI_WRITE_BIG 0x2a /* write data */
#define ATAPI_READ_TOC 0x43 /* get table of contents */
#define ATAPI_READ_SUBCHANNEL 0x42 /* get subchannel info */
#define ATAPI_MODE_SELECT_BIG 0x55 /* set device parameters */
diff --git a/sys/pc98/pc98/wfd.c b/sys/pc98/pc98/wfd.c
new file mode 100644
index 0000000..3f67134
--- /dev/null
+++ b/sys/pc98/pc98/wfd.c
@@ -0,0 +1,780 @@
+/*
+ * Copyright (c) 1997,1998 Junichi Satoh <junichi@astec.co.jp>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer as
+ * the first lines of this file unmodified.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Junichi Satoh ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL Junichi Satoh BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: wfd.c,v 1.6 1998/01/06 15:54:53 junichi Exp junichi $
+ */
+
+/*
+ * ATAPI Floppy, LS-120 driver
+ */
+
+#include "wdc.h"
+#include "wfd.h"
+#include "opt_atapi.h"
+
+#if NWFD > 0 && NWDC > 0 && defined (ATAPI)
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/conf.h>
+#include <sys/file.h>
+#include <sys/fcntl.h>
+#include <sys/proc.h>
+#include <sys/malloc.h>
+#include <sys/buf.h>
+#include <sys/disklabel.h>
+#include <sys/diskslice.h>
+#include <sys/cdio.h>
+#include <machine/ioctl_fd.h>
+#ifdef DEVFS
+#include <sys/devfsext.h>
+#endif /*DEVFS*/
+
+#include <i386/isa/atapi.h>
+#include <i386/isa/fdc.h>
+
+static d_open_t wfdbopen;
+static d_close_t wfdbclose;
+static d_ioctl_t wfdioctl;
+static d_strategy_t wfdstrategy;
+
+#define CDEV_MAJOR 87
+#define BDEV_MAJOR 24
+static struct cdevsw wfd_cdevsw;
+static struct bdevsw wfd_bdevsw =
+ { wfdbopen, wfdbclose, wfdstrategy, wfdioctl, /*22*/
+ nodump, nopsize, 0, "wfd", &wfd_cdevsw, -1 };
+
+#ifndef ATAPI_STATIC
+static
+#endif
+int wfdattach(struct atapi*, int, struct atapi_params*, int);
+
+#define NUNIT (NWDC*2) /* Max. number of devices */
+#define UNIT(d) ((minor(d) >> 3) & 3) /* Unit part of minor device number */
+
+#define F_BOPEN 0x0001 /* The block device is opened */
+#define F_MEDIA_CHANGED 0x0002 /* The media have changed since open */
+#define F_DEBUG 0x0004 /* Print debug info */
+
+/*
+ * LS-120 Capabilities and Mechanical Status Page
+ */
+struct cappage {
+ /* Mode data header */
+ u_short data_length;
+ u_char medium_type;
+#define MDT_UNKNOWN 0x00
+#define MDT_NO_DISC 0x70
+#define MDT_DOOR_OPEN 0x71
+#define MDT_FMT_ERROR 0x72
+
+#define MDT_2DD_UN 0x10
+#define MDT_2DD 0x11
+#define MDT_2HD_UN 0x20
+#define MDT_2HD_12_98 0x22
+#define MDT_2HD_12 0x23
+#define MDT_2HD_144 0x24
+#define MDT_LS120 0x31
+
+ unsigned reserved0 :7;
+ unsigned wp :1; /* Write protect */
+ u_char reserved1[4];
+
+ /* Capabilities page */
+ unsigned page_code :6; /* Page code - Should be 0x5 */
+#define CAP_PAGE 0x05
+ unsigned reserved1_6 :1; /* Reserved */
+ unsigned ps :1; /* The device is capable of savi
+ng the page */
+ u_char page_length; /* Page Length - Should be 0x1e */
+ u_short transfer_rate; /* In kilobits per second */
+ u_char heads, sectors; /* Number of heads, Number of sectors per track */
+ u_short sector_size; /* Byes per sector */
+ u_short cyls; /* Number of cylinders */
+ u_char reserved10[10];
+ u_char motor_delay; /* Motor off delay */
+ u_char reserved21[7];
+ u_short rpm; /* Rotations per minute */
+ u_char reserved30[2];
+};
+
+/* misuse a flag to identify format operation */
+#define B_FORMAT B_XXX
+
+struct wfd {
+ struct atapi *ata; /* Controller structure */
+ int unit; /* IDE bus drive unit */
+ int lun; /* Logical device unit */
+ int flags; /* Device state flags */
+ int refcnt; /* The number of raw opens */
+ struct buf_queue_head buf_queue; /* Queue of i/o requests */
+ struct atapi_params *param; /* Drive parameters table */
+ struct cappage cap; /* Capabilities page info */
+ char description[80]; /* Device description */
+#ifdef DEVFS
+ void *cdevs;
+ void *bdevs;
+#endif
+ struct diskslices *dk_slices; /* virtual drives */
+};
+
+struct wfd *wfdtab[NUNIT]; /* Drive info by unit number */
+static int wfdnlun = 0; /* Number of configured drives */
+
+static void wfd_start (struct wfd *t);
+static void wfd_done (struct wfd *t, struct buf *bp, int resid,
+ struct atapires result);
+static void wfd_error (struct wfd *t, struct atapires result);
+static int wfd_request_wait (struct wfd *t, u_char cmd, u_char a1, u_char a2,
+ u_char a3, u_char a4, u_char a5, u_char a6, u_char a7, u_char a8,
+ u_char a9, char *addr, int count);
+static void wfd_describe (struct wfd *t);
+static int wfd_eject (struct wfd *t, int closeit);
+static void wfdstrategy1(struct buf *bp);
+
+/*
+ * Dump the array in hexadecimal format for debugging purposes.
+ */
+static void wfd_dump (int lun, char *label, void *data, int len)
+{
+ u_char *p = data;
+
+ printf ("wfd%d: %s %x", lun, label, *p++);
+ while (--len > 0)
+ printf ("-%x", *p++);
+ printf ("\n");
+}
+
+#ifndef ATAPI_STATIC
+static
+#endif
+int
+wfdattach (struct atapi *ata, int unit, struct atapi_params *ap, int debug)
+{
+ struct wfd *t;
+ struct atapires result;
+ int lun, i;
+
+#ifdef DEVFS
+ int mynor;
+#endif
+ if (wfdnlun >= NUNIT) {
+ printf ("wfd: too many units\n");
+ return (0);
+ }
+ if (!atapi_request_immediate) {
+ printf("wfd: configuration error, ATAPI core code not present!\n");
+ printf("wfd: check `options ATAPI_STATIC' in your kernel config file!\n");
+ return (0);
+ }
+ t = malloc (sizeof (struct wfd), M_TEMP, M_NOWAIT);
+ if (! t) {
+ printf ("wfd: out of memory\n");
+ return (0);
+ }
+ wfdtab[wfdnlun] = t;
+ bzero (t, sizeof (struct wfd));
+ bufq_init(&t->buf_queue);
+ t->ata = ata;
+ t->unit = unit;
+ lun = t->lun = wfdnlun++;
+ t->param = ap;
+ t->flags = F_MEDIA_CHANGED;
+ t->refcnt = 0;
+ if (debug) {
+ t->flags |= F_DEBUG;
+ /* Print params. */
+ wfd_dump (t->lun, "info", ap, sizeof *ap);
+ }
+
+ /* Get drive capabilities. */
+ /* Do it twice to avoid the stale media changed state. */
+ for (i = 0; i < 2; i++) {
+ result = atapi_request_immediate (ata, unit, ATAPI_MODE_SENSE,
+ 0, CAP_PAGE, 0, 0, 0, 0,
+ sizeof (t->cap) >> 8, sizeof (t->cap),
+ 0, 0, 0, 0, 0, 0, 0, (char*) &t->cap, sizeof (t->cap));
+ }
+
+ if (result.code == RES_ERR &&
+ (result.error & AER_SKEY) == AER_SK_UNIT_ATTENTION)
+ result = atapi_request_immediate (ata, unit, ATAPI_MODE_SENSE,
+ 0, CAP_PAGE, 0, 0, 0, 0, sizeof (t->cap) >> 8,
+ sizeof (t->cap), 0, 0, 0, 0, 0, 0, 0,
+ (char*) &t->cap, sizeof (t->cap));
+
+ /* Some drives have shorter capabilities page. */
+ if (result.code == RES_UNDERRUN)
+ result.code = 0;
+
+ if (result.code == 0) {
+ wfd_describe (t);
+ if (t->flags & F_DEBUG)
+ wfd_dump (t->lun, "cap", &t->cap, sizeof t->cap);
+ } else
+ return -1;
+
+#ifdef DEVFS
+ mynor = dkmakeminor(unit, WHOLE_DISK_SLICE, RAW_PART);
+ t->bdevs = devfs_add_devswf(&wfd_bdevsw, mynor,
+ DV_BLK, UID_ROOT, GID_OPERATOR, 0640,
+ "wfd%d", unit);
+ t->cdevs = devfs_add_devswf(&wfd_cdevsw, mynor,
+ DV_CHR, UID_ROOT, GID_OPERATOR, 0640,
+ "rwfd%d", unit);
+#endif /* DEVFS */
+ return (1);
+}
+
+void wfd_describe (struct wfd *t)
+{
+ int no_print = 0;
+
+ t->cap.cyls = ntohs (t->cap.cyls);
+ t->cap.sector_size = ntohs (t->cap.sector_size);
+
+ printf ("wfd%d: ", t->lun);
+ switch (t->cap.medium_type) {
+ case MDT_UNKNOWN:
+ printf ("medium type unknown (no disk)");
+ no_print = 1;
+ break;
+ case MDT_2DD_UN:
+ printf ("2DD(capacity unknown) floppy disk loaded");
+ no_print = 1;
+ break;
+ case MDT_2DD:
+ printf ("720KB floppy disk loaded");
+ break;
+ case MDT_2HD_UN:
+ printf ("2HD(capacity unknown) floppy disk loaded");
+ no_print = 1;
+ break;
+ case MDT_2HD_12_98:
+ printf ("1.25MB(PC-9801 format) floppy disk loaded");
+ break;
+ case MDT_2HD_12:
+ printf ("1.2MB floppy disk loaded");
+ break;
+ case MDT_2HD_144:
+ printf ("1.44MB floppy disk loaded");
+ break;
+ case MDT_LS120:
+ printf ("120MB floppy disk loaded");
+ break;
+ case MDT_NO_DISC:
+ printf ("no disc inside");
+ no_print = 1;
+ break;
+ case MDT_DOOR_OPEN:
+ printf ("door open");
+ no_print = 1;
+ break;
+ case MDT_FMT_ERROR:
+ printf ("medium format error");
+ no_print = 1;
+ break;
+ default:
+ printf ("medium type=0x%x", t->cap.medium_type);
+ break;
+ }
+ if (t->cap.wp)
+ printf(", write protected");
+ printf ("\n");
+
+ if (!no_print) {
+ printf ("wfd%d: ", t->lun);
+ printf ("%lu cyls", t->cap.cyls);
+ printf (", %lu heads, %lu S/T", t->cap.heads, t->cap.sectors);
+ printf (", %lu B/S", t->cap.sector_size);
+ printf ("\n");
+ }
+}
+
+int wfdbopen (dev_t dev, int flags, int fmt, struct proc *p)
+{
+ int lun = UNIT(dev);
+ struct wfd *t;
+ struct atapires result;
+ int errcode = 0;
+ struct disklabel label;
+
+ /* Check that the device number is legal
+ * and the ATAPI driver is loaded. */
+ if (lun >= wfdnlun || ! atapi_request_immediate) {
+ printf("ENXIO lun=%d, wfdnlun=%d, im=%d\n", lun, wfdnlun, atapi_request_immediate);
+ return (ENXIO);
+ }
+ t = wfdtab[lun];
+
+ t->flags &= ~F_MEDIA_CHANGED;
+ /* Lock the media. */
+ wfd_request_wait (t, ATAPI_PREVENT_ALLOW,
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
+
+ /* Sense the media type */
+ result = atapi_request_wait (t->ata, t->unit, ATAPI_MODE_SENSE,
+ 0, CAP_PAGE, 0, 0, 0, 0,
+ sizeof (t->cap) >> 8, sizeof (t->cap),
+ 0, 0, 0, 0, 0, 0, 0,
+ (char*) &t->cap, sizeof (t->cap));
+ if (result.code)
+ printf ("wfd%d: Sense the media type is failed.\n", t->lun);
+ else {
+ t->cap.cyls = ntohs (t->cap.cyls);
+ t->cap.sector_size = ntohs (t->cap.sector_size);
+ }
+
+ /* Build label for whole disk. */
+ bzero(&label, sizeof label);
+ label.d_secsize = t->cap.sector_size;
+ label.d_nsectors = t->cap.sectors;
+ label.d_ntracks = t->cap.heads;
+ label.d_ncylinders = t->cap.cyls;
+ label.d_secpercyl = t->cap.heads * t->cap.sectors;
+ label.d_rpm = 720;
+ label.d_secperunit = label.d_secpercyl * t->cap.cyls;
+
+ /* Initialize slice tables. */
+ errcode = dsopen("wfd", dev, fmt, &t->dk_slices, &label, wfdstrategy1,
+ (ds_setgeom_t *)NULL, &wfd_bdevsw, &wfd_cdevsw);
+ if (errcode != 0)
+ return errcode;
+
+ t->flags |= F_BOPEN;
+ return (0);
+}
+
+/*
+ * Close the device. Only called if we are the LAST
+ * occurence of an open device.
+ */
+int wfdbclose (dev_t dev, int flags, int fmt, struct proc *p)
+{
+ int lun = UNIT(dev);
+ struct wfd *t = wfdtab[lun];
+
+ dsclose(dev, fmt, t->dk_slices);
+ if(!dsisopen(t->dk_slices)) {
+ /* If we were the last open of the entire device, release it. */
+ if (! t->refcnt)
+ wfd_request_wait (t, ATAPI_PREVENT_ALLOW,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ t->flags &= ~F_BOPEN;
+ }
+ return (0);
+}
+
+static void
+wfdstrategy1(struct buf *bp)
+{
+ /*
+ * XXX - do something to make wdstrategy() but not this block while
+ * we're doing dsinit() and dsioctl().
+ */
+ wfdstrategy(bp);
+}
+
+/*
+ * Actually translate the requested transfer into one the physical driver can
+ * understand. The transfer is described by a buf and will include only one
+ * physical transfer.
+ */
+void wfdstrategy (struct buf *bp)
+{
+ int lun = UNIT(bp->b_dev);
+ struct wfd *t = wfdtab[lun];
+ int x;
+
+ /* If it's a null transfer, return immediatly. */
+ if (bp->b_bcount == 0) {
+ bp->b_resid = 0;
+ biodone (bp);
+ return;
+ }
+
+ /* Process transfer request. */
+ bp->b_pblkno = bp->b_blkno;
+ bp->b_resid = bp->b_bcount;
+
+ /*
+ * Do bounds checking, adjust transfer, and set b_pblkno.
+ */
+ if (dscheck(bp, t->dk_slices) <= 0) {
+ biodone(bp);
+ return;
+ }
+ bp->b_blkno = bp->b_pblkno;
+
+ x = splbio();
+
+ /* Place it in the queue of disk activities for this disk. */
+ bufqdisksort (&t->buf_queue, bp);
+
+ /* Tell the device to get going on the transfer if it's
+ * not doing anything, otherwise just wait for completion. */
+ wfd_start (t);
+ splx(x);
+}
+
+/*
+ * Look to see if there is a buf waiting for the device
+ * and that the device is not already busy. If both are true,
+ * It dequeues the buf and creates an ATAPI command to perform the
+ * transfer in the buf.
+ * The bufs are queued by the strategy routine (wfdstrategy).
+ * Must be called at the correct (splbio) level.
+ */
+static void wfd_start (struct wfd *t)
+{
+ struct buf *bp = bufq_first(&t->buf_queue);
+ u_long blkno, nblk;
+ u_char op_code;
+ long count;
+
+ /* See if there is a buf to do and we are not already doing one. */
+ if (! bp)
+ return;
+
+ /* Unqueue the request. */
+ bufq_remove(&t->buf_queue, bp);
+
+ /* We have a buf, now we should make a command
+ * First, translate the block to absolute and put it in terms of the
+ * logical blocksize of the device.
+ * What if something asks for 512 bytes not on a 2k boundary? */
+ blkno = bp->b_blkno / (t->cap.sector_size / 512);
+ nblk = (bp->b_bcount + (t->cap.sector_size - 1)) / t->cap.sector_size;
+
+ if(bp->b_flags & B_READ) {
+ op_code = ATAPI_READ_BIG;
+ count = bp->b_bcount;
+ } else {
+ op_code = ATAPI_WRITE_BIG;
+ count = -bp->b_bcount;
+ }
+
+ atapi_request_callback (t->ata, t->unit, op_code, 0,
+ blkno>>24, blkno>>16, blkno>>8, blkno, 0, nblk>>8, nblk, 0, 0,
+ 0, 0, 0, 0, 0, (u_char*) bp->b_data, count,
+ (void*)wfd_done, t, bp);
+}
+
+static void wfd_done (struct wfd *t, struct buf *bp, int resid,
+ struct atapires result)
+{
+ if (result.code) {
+ wfd_error (t, result);
+ bp->b_error = EIO;
+ bp->b_flags |= B_ERROR;
+ } else
+ bp->b_resid = resid;
+ biodone (bp);
+ wfd_start (t);
+}
+
+static void wfd_error (struct wfd *t, struct atapires result)
+{
+ if (result.code != RES_ERR)
+ return;
+ switch (result.error & AER_SKEY) {
+ case AER_SK_NOT_READY:
+ if (result.error & ~AER_SKEY) {
+ /* Not Ready */
+ printf ("wfd%d: not ready\n", t->lun);
+ return;
+ }
+ /* Tray open. */
+ if (! (t->flags & F_MEDIA_CHANGED))
+ printf ("wfd%d: tray open\n", t->lun);
+ t->flags |= F_MEDIA_CHANGED;
+ return;
+
+ case AER_SK_UNIT_ATTENTION:
+ /* Media changed. */
+ if (! (t->flags & F_MEDIA_CHANGED))
+ printf ("wfd%d: media changed\n", t->lun);
+ t->flags |= F_MEDIA_CHANGED;
+ return;
+
+ case AER_SK_ILLEGAL_REQUEST:
+ /* Unknown command or invalid command arguments. */
+ if (t->flags & F_DEBUG)
+ printf ("wfd%d: invalid command\n", t->lun);
+ return;
+ }
+ printf ("wfd%d: i/o error, status=%b, error=%b\n", t->lun,
+ result.status, ARS_BITS, result.error, AER_BITS);
+}
+
+static int wfd_request_wait (struct wfd *t, u_char cmd, u_char a1, u_char a2,
+ u_char a3, u_char a4, u_char a5, u_char a6, u_char a7, u_char a8,
+ u_char a9, char *addr, int count)
+{
+ struct atapires result;
+
+ result = atapi_request_wait (t->ata, t->unit, cmd,
+ a1, a2, a3, a4, a5, a6, a7, a8, a9, 0, 0, 0, 0, 0, 0,
+ addr, count);
+ if (result.code) {
+ wfd_error (t, result);
+ return (EIO);
+ }
+ return (0);
+}
+
+/*
+ * Perform special action on behalf of the user.
+ * Knows about the internals of this device
+ */
+int wfdioctl (dev_t dev, int cmd, caddr_t addr, int flag, struct proc *p)
+{
+ int lun = UNIT(dev);
+ struct wfd *t = wfdtab[lun];
+ int error = 0;
+
+ struct disklabel *dl;
+ char buffer[DEV_BSIZE];
+
+ error = dsioctl("wfd", dev, cmd, addr, flag, &t->dk_slices,
+ wfdstrategy1, (ds_setgeom_t *)NULL);
+ if (error != -1)
+ return (error);
+
+ if (t->flags & F_MEDIA_CHANGED)
+ switch (cmd) {
+ case CDIOCSETDEBUG:
+ case CDIOCCLRDEBUG:
+ case CDIOCRESET:
+ /* These ops are media change transparent. */
+ break;
+ default:
+ /* Lock the media. */
+ wfd_request_wait (t, ATAPI_PREVENT_ALLOW,
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
+ break;
+ }
+ switch (cmd) {
+ case CDIOCSETDEBUG:
+ if (p->p_cred->pc_ucred->cr_uid)
+ return (EPERM);
+ t->flags |= F_DEBUG;
+ atapi_debug (t->ata, 1);
+ return 0;
+ case CDIOCCLRDEBUG:
+ if (p->p_cred->pc_ucred->cr_uid)
+ return (EPERM);
+ t->flags &= ~F_DEBUG;
+ atapi_debug (t->ata, 0);
+ return 0;
+ case CDIOCRESET:
+ if (p->p_cred->pc_ucred->cr_uid)
+ return (EPERM);
+ return wfd_request_wait (t, ATAPI_TEST_UNIT_READY,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ case CDIOCEJECT:
+ /* Don't allow eject if the device is opened
+ * by somebody (not us) in block mode. */
+ if ((t->flags & F_BOPEN) && t->refcnt)
+ return (EBUSY);
+ return wfd_eject (t, 0);
+ case CDIOCCLOSE:
+ if ((t->flags & F_BOPEN) && t->refcnt)
+ return (0);
+ return wfd_eject (t, 1);
+ default:
+ return (ENOTTY);
+ }
+ return (error);
+}
+
+static int wfd_eject (struct wfd *t, int closeit)
+{
+ struct atapires result;
+
+ /* Try to stop the disc. */
+ result = atapi_request_wait (t->ata, t->unit, ATAPI_START_STOP,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+
+ if (result.code == RES_ERR &&
+ ((result.error & AER_SKEY) == AER_SK_NOT_READY ||
+ (result.error & AER_SKEY) == AER_SK_UNIT_ATTENTION)) {
+ int err;
+
+ if (!closeit)
+ return (0);
+ /*
+ * The disc was unloaded.
+ * Load it (close tray).
+ * Read the table of contents.
+ */
+ err = wfd_request_wait (t, ATAPI_START_STOP,
+ 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0);
+ if (err)
+ return (err);
+
+ /* Lock the media. */
+ wfd_request_wait (t, ATAPI_PREVENT_ALLOW,
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
+
+ return (0);
+ }
+
+ if (result.code) {
+ wfd_error (t, result);
+ return (EIO);
+ }
+
+ if (closeit)
+ return (0);
+
+ /* Give it some time to stop spinning. */
+ tsleep ((caddr_t)&lbolt, PRIBIO, "wfdej1", 0);
+ tsleep ((caddr_t)&lbolt, PRIBIO, "wfdej2", 0);
+
+ /* Unlock. */
+ wfd_request_wait (t, ATAPI_PREVENT_ALLOW,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+
+ /* Eject. */
+ t->flags |= F_MEDIA_CHANGED;
+ return wfd_request_wait (t, ATAPI_START_STOP,
+ 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0);
+}
+
+#ifdef WFD_MODULE
+/*
+ * Loadable ATAPI Floppy driver stubs.
+ */
+#include <sys/exec.h>
+#include <sys/sysent.h>
+#include <sys/lkm.h>
+
+/*
+ * Construct lkm_dev structures (see lkm.h).
+ * Our bdevsw/cdevsw slot numbers are 19/69.
+ */
+
+
+MOD_DEV(wfd, LM_DT_BLOCK, BDEV_MAJOR, &wfd_bdevsw);
+MOD_DEV(rwfd, LM_DT_CHAR, CDEV_MAJOR, &wfd_cdevsw);
+
+/*
+ * Function called when loading the driver.
+ */
+int wfd_load (struct lkm_table *lkmtp, int cmd)
+{
+ struct atapi *ata;
+ int n, u;
+
+ if (! atapi_start)
+ /* No ATAPI driver available. */
+ return EPROTONOSUPPORT;
+ n = 0;
+ for (ata=atapi_tab; ata<atapi_tab+2; ++ata)
+ if (ata->port)
+ for (u=0; u<2; ++u)
+ /* Probing controller ata->ctrlr, unit u. */
+ if (ata->params[u] && ! ata->attached[u] &&
+ wfdattach (ata, u, ata->params[u],
+ ata->debug) >= 0)
+ {
+ /* Drive found. */
+ ata->attached[u] = 1;
+ ++n;
+ }
+ if (! n)
+ /* No IDE Floppies found. */
+ return ENXIO;
+ return 0;
+}
+
+/*
+ * Function called when unloading the driver.
+ */
+int wfd_unload (struct lkm_table *lkmtp, int cmd)
+{
+ struct wfd **t;
+
+ for (t=wfdtab; t<wfdtab+wfdnlun; ++t)
+ if (((*t)->flags & F_BOPEN) || (*t)->refcnt)
+ /* The device is opened, cannot unload the driver. */
+ return EBUSY;
+ for (t=wfdtab; t<wfdtab+wfdnlun; ++t) {
+ (*t)->ata->attached[(*t)->unit] = 0;
+ free (*t, M_TEMP);
+ }
+ wfdnlun = 0;
+ bzero (wfdtab, sizeof(wfdtab));
+ return 0;
+}
+
+/*
+ * Dispatcher function for the module (load/unload/stat).
+ */
+int wfd_mod (struct lkm_table *lkmtp, int cmd, int ver)
+{
+ int err = 0;
+
+ if (ver != LKM_VERSION)
+ return EINVAL;
+
+ if (cmd == LKM_E_LOAD)
+ err = wfd_load (lkmtp, cmd);
+ else if (cmd == LKM_E_UNLOAD)
+ err = wfd_unload (lkmtp, cmd);
+ if (err)
+ return err;
+
+ /* XXX Poking around in the LKM internals like this is bad.
+ */
+ /* Register the cdevsw entry. */
+ lkmtp->private.lkm_dev = & MOD_PRIVATE(rwfd);
+ err = lkmdispatch (lkmtp, cmd);
+ if (err)
+ return err;
+
+ /* Register the bdevsw entry. */
+ lkmtp->private.lkm_dev = & MOD_PRIVATE(wfd);
+ return lkmdispatch (lkmtp, cmd);
+}
+#endif /* WFD_MODULE */
+
+static wfd_devsw_installed = 0;
+
+static void wfd_drvinit(void *unused)
+{
+ if( ! wfd_devsw_installed ) {
+ bdevsw_add_generic(BDEV_MAJOR, CDEV_MAJOR, &wfd_bdevsw);
+ wfd_devsw_installed = 1;
+ }
+}
+
+SYSINIT(wfddev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,wfd_drvinit,NULL)
+
+
+#endif /* NWFD && NWDC && ATAPI */
OpenPOWER on IntegriCloud