diff options
Diffstat (limited to 'sys/i386/isa/wfd.c')
-rw-r--r-- | sys/i386/isa/wfd.c | 780 |
1 files changed, 780 insertions, 0 deletions
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 */ |