amr_linux.c revision 155953
1/*- 2 * Copyright (c) 2005 Paul Saab 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 */ 27 28#include <sys/cdefs.h> 29__FBSDID("$FreeBSD: head/sys/dev/amr/amr_linux.c 155953 2006-02-23 18:05:38Z jhb $"); 30 31#include <sys/param.h> 32#include <sys/systm.h> 33#include <sys/conf.h> 34#include <sys/kernel.h> 35#include <sys/module.h> 36#include <sys/bio.h> 37 38#if defined(__amd64__) /* Assume amd64 wants 32 bit Linux */ 39#include <machine/../linux32/linux.h> 40#include <machine/../linux32/linux32_proto.h> 41#else 42#include <machine/../linux/linux.h> 43#include <machine/../linux/linux_proto.h> 44#endif 45#include <compat/linux/linux_ioctl.h> 46 47#include <sys/bus.h> 48#include <sys/stat.h> 49 50#include <machine/bus.h> 51 52#include <dev/amr/amrreg.h> 53#include <dev/amr/amrvar.h> 54 55/* There are multiple ioctl number ranges that need to be handled */ 56#define AMR_LINUX_IOCTL_MIN 0x00000 57#define AMR_LINUX_IOCTL_MAX 0x50000 58 59static linux_ioctl_function_t amr_linux_ioctl; 60static struct linux_ioctl_handler amr_linux_handler = {amr_linux_ioctl, 61 AMR_LINUX_IOCTL_MIN, 62 AMR_LINUX_IOCTL_MAX}; 63 64SYSINIT (amr_register, SI_SUB_KLD, SI_ORDER_MIDDLE, 65 linux_ioctl_register_handler, &amr_linux_handler); 66SYSUNINIT(amr_unregister, SI_SUB_KLD, SI_ORDER_MIDDLE, 67 linux_ioctl_unregister_handler, &amr_linux_handler); 68 69static d_open_t amr_linux_open; 70static d_close_t amr_linux_close; 71 72static int amr_linux_isopen; 73static struct cdev * amr_linux_dev_t; 74 75static struct cdevsw megadev_cdevsw = { 76 .d_version = D_VERSION, 77 .d_flags = D_NEEDGIANT, 78 .d_open = amr_linux_open, 79 .d_close = amr_linux_close, 80 .d_name = "megadev", 81}; 82 83 84static int 85amr_linux_open(struct cdev * dev, int flags, int fmt, d_thread_t *td) 86{ 87 88 amr_linux_isopen++; 89 return (0); 90}; 91 92static int 93amr_linux_close(struct cdev * dev, int flags, int fmt, d_thread_t *td) 94{ 95 96 amr_linux_isopen--; 97 return (0); 98}; 99 100static int 101amr_linux_init(void) 102{ 103 devclass_t devclass; 104 struct amr_softc *sc; 105 int i, linux_no_adapters, max_unit; 106 107 devclass = devclass_find("amr"); 108 if (devclass == NULL) 109 return (0); 110 111 max_unit = devclass_get_maxunit(devclass); 112 if (max_unit == 0) 113 return (0); 114 115 for (i = 0; i < max_unit; i++) { 116 sc = devclass_get_softc(devclass, i); 117 if (sc == NULL) 118 break; 119 } 120 121 linux_no_adapters = i; 122 for (i = 0; i < linux_no_adapters; i++) { 123 sc = devclass_get_softc(devclass, i); 124 if (sc == NULL) 125 break; 126 sc->amr_linux_no_adapters = linux_no_adapters; 127 } 128 129 return (linux_no_adapters); 130} 131 132static int 133amr_linux_modevent(module_t mod, int cmd, void *data) 134{ 135 136 switch (cmd) { 137 case MOD_LOAD: 138 if (amr_linux_init() == 0) 139 return (ENXIO); 140 141 if (amr_linux_dev_t) 142 return (EEXIST); 143 144 amr_linux_dev_t = make_dev(&megadev_cdevsw, 0, UID_ROOT, 145 GID_OPERATOR, S_IRUSR | S_IWUSR, "megadev%d", 0); 146 if (amr_linux_dev_t == NULL) 147 return (ENXIO); 148 break; 149 150 case MOD_UNLOAD: 151 if (amr_linux_isopen) 152 return (EBUSY); 153 if (amr_linux_dev_t) 154 destroy_dev(amr_linux_dev_t); 155 break; 156 157 default: 158 return (EINVAL); 159 } 160 return (0); 161} 162 163static moduledata_t amr_linux_mod = {"amr_linux", amr_linux_modevent, NULL}; 164DECLARE_MODULE(amr_linux, amr_linux_mod, SI_SUB_PSEUDO, SI_ORDER_MIDDLE); 165MODULE_DEPEND(amr, linux, 1, 1, 1); 166 167static int 168amr_linux_ioctl(d_thread_t *p, struct linux_ioctl_args *args) 169{ 170 devclass_t devclass; 171 struct amr_softc *sc; 172 struct amr_linux_ioctl ali; 173 int adapter, error; 174 175 devclass = devclass_find("amr"); 176 if (devclass == NULL) 177 return (ENOENT); 178 179 error = copyin((caddr_t)args->arg, &ali, sizeof(ali)); 180 if (error) 181 return (error); 182 if (ali.ui.fcs.opcode == 0x82) 183 adapter = 0; 184 else 185 adapter = (ali.ui.fcs.adapno) ^ 'm' << 8; 186 187 sc = devclass_get_softc(devclass, adapter); 188 if (sc == NULL) 189 return (ENOENT); 190 191 return (amr_linux_ioctl_int(sc->amr_dev_t, args->cmd, 192 (caddr_t)args->arg, 0, p)); 193} 194