NetBSD/sys/lkm/arch/mac68k/iwm/iwm_mod.c

240 lines
5.9 KiB
C

/* $NetBSD: iwm_mod.c,v 1.4 1999/03/31 20:45:06 scottr Exp $ */
/*
* Copyright (c) 1997, 1998 Hauke Fath. 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.
* 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.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
*/
/*
* Sony (floppy disk) driver for Macintosh m68k, module entry.
* This is derived from Terry Lambert's LKM examples.
*/
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/systm.h>
#include <sys/conf.h>
#include <sys/mount.h>
#include <sys/exec.h>
#include <sys/lkm.h>
#include <sys/file.h>
#include <sys/errno.h>
#include "iwm_mod.h"
/*
* From kern/kern_lkm.c
* XXX If it's used outside, it should appear in the header!
*/
int lkmexists __P((struct lkm_table *));
int lkmdispatch __P((struct lkm_table *, int));
/* The module entry */
int iwmfd_lkmentry __P((struct lkm_table *lkmtp, int cmd, int ver));
/* local */
static int load_module __P((struct lkm_table * lkmtp, int cmd));
static int unload_module __P((struct lkm_table * lkmtp, int cmd));
/*
* Provide standard device driver entry points
* (Macros are in <sys/conf.h>, the variables {b,c}devsw[] live in
* arch/mac68k/mac68k/conf.c).
*
* XXX Macros in <sys/conf.h> don't compile cleanly with -Werror.
*/
static struct bdevsw newBDevEntry = {
fdopen,
fdclose,
fdstrategy,
fdioctl,
(dev_type_dump((*))) fddump,
fdsize,
D_DISK
};
static struct cdevsw newCDevEntry = {
fdopen,
fdclose,
fdread,
fdwrite,
fdioctl,
(dev_type_stop((*))) enodev,
0,
seltrue,
(dev_type_mmap((*))) enodev,
D_DISK
};
/*
* Store away the old device driver switch entries for cleanup when we unload.
*/
static struct bdevsw oldBDevEntry;
static struct cdevsw oldCDevEntry;
static struct lkm_misc _module = {
LM_MISC,
LKM_VERSION,
"iwmfd_lkmentry"
};
/*
* These functions are called each time the module is loaded or unloaded.
*
* Although the LKM interface provides an instance for device drivers,
* we have to roll our own for a disk driver: We need to patch both,
* block _and_ character driver entries.
*/
/*
* load_module
*
* Check if already loaded and patch device driver switch table entries.
*/
static int
load_module (lkmtp, cmd)
struct lkm_table *lkmtp;
int cmd;
{
int i;
int err;
struct lkm_misc *args;
i = 0;
args = lkmtp->private.lkm_misc;
#ifdef DEBUG
printf("iwm: Calling iwmModuleHandler()...\n");
#endif
/* Don't load twice! (lkmexists() is exported by kern_lkm.c) */
err = (0 == lkmexists(lkmtp)) ? 0 : EEXIST;
if (!err) {
/*
* We would like to see the block device in slot #21
* and the char device in slot #43.
* For now, we enforce this.
*/
/* save old -- we must provide our own data area */
memcpy(&oldBDevEntry, &bdevsw[21], sizeof(struct bdevsw));
memcpy(&oldCDevEntry, &cdevsw[43], sizeof(struct cdevsw));
/* replace with new */
memcpy(&bdevsw[21], &newBDevEntry, sizeof(struct bdevsw));
memcpy(&cdevsw[43], &newCDevEntry, sizeof(struct cdevsw));
/*
* If we wanted to allocate device nodes in /dev,
* we could export the numbers here.
* For the floppy devices, we assume they
* have already been allocated by /dev/MAKEDEV.
*/
args->lkm_offset = i;
err = fd_mod_init();
}
if (!err) {
printf("IWM floppy disk driver kernel module.\n");
printf("Copyright (c) 1996-1998 Hauke Fath. ");
printf("All rights reserved.\n");
}
return (err);
}
/*
* unload_module
*
* Free any occupied resources and restore patched device driver
* switch entries.
*/
static int
unload_module(lkmtp, cmd)
struct lkm_table *lkmtp;
int cmd;
{
int i;
int err;
struct lkm_misc *args;
i = 0;
err = 0;
args = lkmtp->private.lkm_misc;
#ifdef DEBUG
printf("iwm: Calling unloadModule()...\n");
#endif
i = args->lkm_offset; /* current slot, unused */
fd_mod_free();
/* replace current slot contents with old contents */
memcpy(&bdevsw[21], &oldBDevEntry, sizeof(struct bdevsw));
memcpy(&cdevsw[43], &oldCDevEntry, sizeof(struct cdevsw));
return (err);
}
/*
* iwmfd_lkmentry
*
* External entry point; should generally match name of .o file.
*
* XXX The DISPATCH macro from <sys/lkm.h> that was originally used here
* does not compile noiselessly with -Werror.
*/
int
iwmfd_lkmentry (lkmtp, cmd, ver)
struct lkm_table *lkmtp;
int cmd;
int ver;
{
int err;
err = (ver == LKM_VERSION) ? 0 : EINVAL; /* version mismatch */
if (!err) {
switch (cmd) {
case LKM_E_LOAD:
lkmtp->private.lkm_any = (struct lkm_any *) & _module;
err = load_module(lkmtp, cmd);
break;
case LKM_E_UNLOAD:
err = unload_module(lkmtp, cmd);
break;
case LKM_E_STAT:
err = lkm_nofunc(lkmtp, cmd);
break;
}
}
if (!err)
err = lkmdispatch(lkmtp, cmd);
return (err);
}