summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog5
-rw-r--r--linux/pcmcia-cs/glue/ds.c454
-rw-r--r--linux/pcmcia-cs/glue/pcmcia.c121
-rw-r--r--linux/pcmcia-cs/glue/pcmcia_glue.h271
-rw-r--r--linux/pcmcia-cs/glue/wireless_glue.h167
5 files changed, 1018 insertions, 0 deletions
diff --git a/ChangeLog b/ChangeLog
index 88e9b33..db0e195 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,10 @@
2006-07-27 Stefan Siegl <stesie@brokenpipe.de>
+ * linux/pcmcia-cs/glue/ds.c: New file.
+ * linux/pcmcia-cs/glue/pcmcia.c: Likewise.
+ * linux/pcmcia-cs/glue/pcmcia_glue.h: Likewise.
+ * linux/pcmcia-cs/glue/wireless_glue.h: Likewise.
+
* linux/pcmcia-cs/clients/xirc2ps_cs.c (busy_loop): Replace the code by
a call to __udelay.
* linux/pcmcia-cs/include/linux/init.h: Adapt to our Linux environment.
diff --git a/linux/pcmcia-cs/glue/ds.c b/linux/pcmcia-cs/glue/ds.c
new file mode 100644
index 0000000..7baa29e
--- /dev/null
+++ b/linux/pcmcia-cs/glue/ds.c
@@ -0,0 +1,454 @@
+/*
+ * pcmcia-socket `device' driver
+ *
+ * Copyright (C) 2006 Free Software Foundation, Inc.
+ * Written by Stefan Siegl <stesie@brokenpipe.de>.
+ *
+ * This file is part of GNU Mach.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* This file is included from linux/pcmcia-cs/modules/ds.c. */
+
+/*
+ * Prepare the namespace for inclusion of Mach header files.
+ */
+#undef PAGE_SHIFT
+#undef kfree
+
+/*
+ * <kern/sched_prim.h> defines another event_t which is not used in this
+ * file, so name it mach_event_t to avoid a clash.
+ */
+#define event_t mach_event_t
+#include <kern/sched_prim.h>
+#undef event_t
+
+#include <mach/port.h>
+#include <mach/notify.h>
+#include <mach/mig_errors.h>
+
+#include <ipc/ipc_port.h>
+#include <ipc/ipc_space.h>
+
+#include <device/device_types.h>
+#include <device/device_port.h>
+#include <device/io_req.h>
+#include <device/ds_routines.h>
+
+#include <i386at/device_emul.h>
+
+#include <device_reply.h>
+
+/* Eliminate the queue_empty macro from Mach header files. */
+#undef queue_empty
+
+struct device_emulation_ops linux_pcmcia_emulation_ops;
+
+/*
+ * We have our very own device emulation stack because we need to carry a
+ * pointer from the open call via read until the final close call: a
+ * pointer to the user's event queue.
+ */
+struct mach_socket_device {
+ /*
+ * Pointer to the mach_device we have allocated. This must be the
+ * first entry in this struct, in order to be able to cast to
+ * mach_device.
+ */
+ struct mach_device mach_dev;
+
+ /*
+ * Pointer to the user info of pcmcia data services.
+ */
+ user_info_t *user;
+
+ /*
+ * Cache for carrying data from set_status to get_status calls. This
+ * is needed for write ioctls.
+ */
+ ds_ioctl_arg_t carry;
+};
+
+
+static void
+device_deallocate(void *p)
+{
+ mach_device_t device = (mach_device_t) p;
+
+ simple_lock(&device->ref_lock);
+ if (--device->ref_count > 0)
+ {
+ simple_unlock(&device->ref_lock);
+ return;
+ }
+
+ simple_unlock(&device->ref_lock);
+
+ /*
+ * do what the original ds_release would do, ...
+ */
+ socket_t i = device->dev_number;
+ socket_info_t *s;
+ user_info_t *user, **link;
+
+ s = &socket_table[i];
+ user = ((struct mach_socket_device *) device)->user;
+
+ /* allow to access the device again ... */
+ if(device->flag & D_WRITE)
+ s->state &= ~SOCKET_BUSY;
+
+ /* Unlink user data structure */
+ for (link = &s->user; *link; link = &(*link)->next)
+ if (*link == user) break;
+
+ if(link)
+ {
+ *link = user->next;
+ user->user_magic = 0;
+ kfree(user);
+ }
+
+ /* now finally reap the device */
+ kfree(device);
+}
+
+/*
+ * Return the send right associated with this socket device incarnation.
+ */
+static ipc_port_t
+dev_to_port(void *d)
+{
+ struct mach_device *dev = d;
+
+ if(! dev)
+ return IP_NULL;
+
+ ipc_port_t port = ipc_port_make_send(dev->port);
+
+ device_deallocate(dev);
+ return port;
+}
+
+
+static inline int
+atoi(const char *ptr)
+{
+ if(! ptr)
+ return 0;
+
+ int i = 0;
+ while(*ptr >= '0' && *ptr <= '9')
+ i = i * 10 + *(ptr ++) - '0';
+
+ return i;
+}
+
+
+/*
+ * Try to open the per-socket pseudo device `socket%d'.
+ */
+static io_return_t
+device_open (ipc_port_t reply_port, mach_msg_type_name_t reply_port_type,
+ dev_mode_t mode, char *name, device_t *devp /* out */)
+{
+ if(! socket_table)
+ return D_NO_SUCH_DEVICE;
+
+ if(strlen(name) < 7 || strncmp(name, "socket", 6))
+ return D_NO_SUCH_DEVICE;
+
+ socket_t i = atoi(name + 6);
+ if(i >= MAX_SOCKS || i >= sockets)
+ return D_NO_SUCH_DEVICE;
+
+ io_return_t err = D_SUCCESS;
+
+ struct mach_device *dev;
+ dev = kmalloc(sizeof(struct mach_socket_device), GFP_KERNEL);
+ if(! dev)
+ {
+ err = D_NO_MEMORY;
+ goto out;
+ }
+
+ memset(dev, 0, sizeof(struct mach_socket_device));
+ mach_device_reference(dev);
+
+ /* now do, what ds_open would do if it would be in charge */
+ socket_info_t *s = &socket_table[i];
+
+ if(mode & D_WRITE)
+ {
+ if(s->state & SOCKET_BUSY)
+ {
+ err = D_ALREADY_OPEN;
+ goto out;
+ }
+ else
+ s->state |= SOCKET_BUSY;
+ }
+
+ user_info_t *user = kmalloc(sizeof(user_info_t), GFP_KERNEL);
+ if(! user)
+ {
+ err = D_NO_MEMORY;
+ goto out;
+ }
+
+ user->event_tail = user->event_head = 0;
+ user->next = s->user;
+ user->user_magic = USER_MAGIC;
+ s->user = user;
+
+ ((struct mach_socket_device *) dev)->user = user;
+
+ if(s->state & SOCKET_PRESENT)
+ queue_event(user, CS_EVENT_CARD_INSERTION);
+
+ /* just set up the rest of our mach_device now ... */
+ dev->dev.emul_ops = &linux_pcmcia_emulation_ops;
+ dev->dev.emul_data = dev;
+
+ dev->dev_number = i;
+ dev->flag = mode;
+
+ dev->port = ipc_port_alloc_kernel();
+ if(dev->port == IP_NULL)
+ {
+ err = KERN_RESOURCE_SHORTAGE;
+ goto out;
+ }
+
+ mach_device_reference(dev);
+ ipc_kobject_set(dev->port, (ipc_kobject_t) &dev->dev, IKOT_DEVICE);
+
+ /* request no-senders notifications on device port */
+ ipc_port_t notify = ipc_port_make_sonce(dev->port);
+ ip_lock(dev->port);
+ ipc_port_nsrequest(dev->port, 1, notify, &notify);
+ assert (notify == IP_NULL);
+
+ out:
+ if(err)
+ {
+ if(dev)
+ {
+ if(dev->port != IP_NULL)
+ {
+ ipc_kobject_set(dev->port, IKO_NULL, IKOT_NONE);
+ ipc_port_dealloc_kernel(dev->port);
+ }
+
+ kfree(dev);
+ dev = NULL;
+ }
+ }
+ else
+ dev->state = DEV_STATE_OPEN;
+
+ *devp = &dev->dev;
+
+ if (IP_VALID (reply_port))
+ ds_device_open_reply(reply_port, reply_port_type,
+ err, dev_to_port(dev));
+ return MIG_NO_REPLY;
+}
+
+
+/*
+ * Close the device DEV.
+ */
+static int
+device_close (void *devp)
+{
+ struct mach_device *dev = (struct mach_device *) devp;
+
+ dev->state = DEV_STATE_CLOSING;
+
+ /* check whether there is a blocked read request pending,
+ * in that case, abort that one before closing
+ */
+ while(dev->ref_count > 2)
+ {
+ socket_t i = dev->dev_number;
+ socket_info_t *s = &socket_table[i];
+ wake_up_interruptible(&s->queue);
+
+ /* wait for device_read to exit */
+ return D_INVALID_OPERATION;
+ }
+
+ dev_port_remove(dev);
+ ipc_port_dealloc_kernel(dev->port);
+
+ return 0;
+}
+
+static io_return_t
+device_read(void *d, ipc_port_t reply_port,
+ mach_msg_type_name_t reply_port_type, dev_mode_t mode,
+ recnum_t recnum, int bytes_wanted,
+ io_buf_ptr_t *data, unsigned int *data_count)
+{
+ struct mach_device *dev = (struct mach_device *) d;
+
+ if(dev->state != DEV_STATE_OPEN)
+ return D_NO_SUCH_DEVICE;
+
+ if(! IP_VALID(reply_port)) {
+ printk(KERN_INFO "ds: device_read: invalid reply port.\n");
+ return (MIG_NO_REPLY); /* no sense in doing anything */
+ }
+
+ /* prepare an io request structure */
+ io_req_t ior;
+ io_req_alloc(ior, 0);
+
+ ior->io_device = dev;
+ ior->io_unit = dev->dev_number;
+ ior->io_op = IO_READ | IO_CALL;
+ ior->io_mode = mode;
+ ior->io_recnum = recnum;
+ ior->io_data = 0;
+ ior->io_count = bytes_wanted;
+ ior->io_alloc_size = 0;
+ ior->io_residual = 0;
+ ior->io_error = 0;
+ ior->io_done = ds_read_done;
+ ior->io_reply_port = reply_port;
+ ior->io_reply_port_type = reply_port_type;
+
+ /*
+ * The ior keeps an extra reference for the device.
+ */
+ mach_device_reference(dev);
+
+ /* do the read finally */
+ io_return_t result = D_SUCCESS;
+
+ result = device_read_alloc(ior, ior->io_count);
+ if(result != KERN_SUCCESS)
+ goto out;
+
+ socket_t i = dev->dev_number;
+ socket_info_t *s = &socket_table[i];
+ user_info_t *user = ((struct mach_socket_device *) dev)->user;
+
+ if(ior->io_count < 4)
+ return D_INVALID_SIZE;
+
+ if(CHECK_USER(user))
+ {
+ result = D_IO_ERROR;
+ goto out;
+ }
+
+ while(queue_empty(user))
+ {
+ if(ior->io_mode & D_NOWAIT)
+ {
+ result = D_WOULD_BLOCK;
+ goto out;
+ }
+ else
+ interruptible_sleep_on(&s->queue);
+
+ if(dev->state == DEV_STATE_CLOSING)
+ {
+ result = D_DEVICE_DOWN;
+ goto out;
+ }
+ }
+
+ event_t ev = get_queued_event(user);
+ memcpy(ior->io_data, &ev, sizeof(event_t));
+
+ ior->io_residual = ior->io_count - sizeof(event_t);
+
+ out:
+ /*
+ * Return result via ds_read_done.
+ */
+ ior->io_error = result;
+ (void) ds_read_done(ior);
+ io_req_free(ior);
+
+ return (MIG_NO_REPLY); /* reply has already been sent. */
+}
+
+
+static io_return_t
+device_set_status(void *d, dev_flavor_t req, dev_status_t arg,
+ mach_msg_type_number_t sz)
+{
+ struct mach_socket_device *dev = (struct mach_socket_device *) d;
+
+ if(sz * sizeof(int) > sizeof(ds_ioctl_arg_t))
+ return D_INVALID_OPERATION;
+
+ if(dev->mach_dev.state != DEV_STATE_OPEN)
+ return D_NO_SUCH_DEVICE;
+
+ unsigned int ioctl_sz = (req & IOCSIZE_MASK) >> IOCSIZE_SHIFT;
+ memcpy(&dev->carry, arg, ioctl_sz);
+
+ return D_SUCCESS;
+}
+
+static io_return_t
+device_get_status(void *d, dev_flavor_t req, dev_status_t arg,
+ mach_msg_type_number_t *sz)
+{
+ struct mach_socket_device *dev = (struct mach_socket_device *) d;
+
+ if(dev->mach_dev.state != DEV_STATE_OPEN)
+ return D_NO_SUCH_DEVICE;
+
+ struct inode inode;
+ inode.i_rdev = dev->mach_dev.dev_number;
+ int ret = ds_ioctl(&inode, NULL, req, (u_long) &dev->carry);
+
+ if(ret)
+ return D_IO_ERROR;
+
+ unsigned int ioctl_sz = (req & IOCSIZE_MASK) >> IOCSIZE_SHIFT;
+ if(req & IOC_OUT) memcpy(arg, &dev->carry, ioctl_sz);
+
+ return D_SUCCESS;
+}
+
+
+struct device_emulation_ops linux_pcmcia_emulation_ops =
+ {
+ mach_device_reference,
+ device_deallocate,
+ dev_to_port,
+ device_open,
+ device_close,
+ NULL, /* device_write */
+ NULL, /* write_inband */
+ device_read,
+ NULL, /* read_inband */
+ device_set_status,
+ device_get_status,
+ NULL, /* set_filter */
+ NULL, /* map */
+ NULL, /* no_senders */
+ NULL, /* write_trap */
+ NULL /* writev_trap */
+ };
diff --git a/linux/pcmcia-cs/glue/pcmcia.c b/linux/pcmcia-cs/glue/pcmcia.c
new file mode 100644
index 0000000..3beebe3
--- /dev/null
+++ b/linux/pcmcia-cs/glue/pcmcia.c
@@ -0,0 +1,121 @@
+/*
+ * pcmcia bridge initialization
+ *
+ * Copyright (C) 2006 Free Software Foundation, Inc.
+ * Written by Stefan Siegl <stesie@brokenpipe.de>.
+ *
+ * This file is part of GNU Mach.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/proc_fs.h>
+#include <linux/pci.h>
+
+#include <asm/spinlock.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/ss.h>
+#include <pcmcia/cs.h>
+
+extern int init_pcmcia_cs(void);
+extern int init_i82365(void);
+extern int init_pcmcia_ds(void);
+
+extern int pcmcia_modinit_pcnet_cs(void);
+extern int pcmcia_modinit_3c589_cs(void);
+extern int pcmcia_modinit_3c574_cs(void);
+extern int pcmcia_modinit_3c575_cb(void);
+extern int pcmcia_modinit_axnet_cs(void);
+extern int pcmcia_modinit_eepro100_cb(void);
+extern int pcmcia_modinit_epic_cb(void);
+extern int pcmcia_modinit_fmvj18x_cs(void);
+extern int pcmcia_modinit_nmclan_cs(void);
+extern int pcmcia_modinit_smc91c92_cs(void);
+extern int pcmcia_modinit_tulip_cb(void);
+extern int pcmcia_modinit_xirc2ps_cs(void);
+
+extern int pcmcia_modinit_orinoco_cs(void);
+
+/*
+ * pcmcia bridge initialisation.
+ */
+void
+pcmcia_init(void)
+{
+ init_pcmcia_cs();
+
+#ifdef CONFIG_I82365
+ init_i82365();
+#endif
+
+ init_pcmcia_ds();
+
+ /*
+ * Call te initialization routines of each driver.
+ */
+#ifdef CONFIG_PCNET_CS
+ pcmcia_modinit_pcnet_cs();
+#endif
+
+#ifdef CONFIG_3C589_CS
+ pcmcia_modinit_3c589_cs();
+#endif
+
+#ifdef CONFIG_3C574_CS
+ pcmcia_modinit_3c574_cs();
+#endif
+
+#ifdef CONFIG_3C575_CB
+ pcmcia_modinit_3c575_cb();
+#endif
+
+#ifdef CONFIG_AXNET_CS
+ pcmcia_modinit_axnet_cs();
+#endif
+
+#ifdef CONFIG_EEPRO100_CB
+ pcmcia_modinit_eepro100_cb();
+#endif
+
+#ifdef CONFIG_EPIC_CB
+ pcmcia_modinit_epic_cb();
+#endif
+
+#ifdef CONFIG_FMVJ18X_CS
+ pcmcia_modinit_fmvj18x_cs();
+#endif
+
+#ifdef CONFIG_NMCLAN_CS
+ pcmcia_modinit_nmclan_cs();
+#endif
+
+#ifdef CONFIG_SMC91C92_CS
+ pcmcia_modinit_smc91c92_cs();
+#endif
+
+#ifdef CONFIG_TULIP_CB
+ pcmcia_modinit_tulip_cb();
+#endif
+
+#ifdef CONFIG_XIRC2PS_CS
+ pcmcia_modinit_xirc2ps_cs();
+#endif
+
+#ifdef CONFIG_ORINOCO_CS
+ pcmcia_modinit_orinoco_cs();
+#endif
+}
diff --git a/linux/pcmcia-cs/glue/pcmcia_glue.h b/linux/pcmcia-cs/glue/pcmcia_glue.h
new file mode 100644
index 0000000..4784645
--- /dev/null
+++ b/linux/pcmcia-cs/glue/pcmcia_glue.h
@@ -0,0 +1,271 @@
+/*
+ * pcmcia card services glue code
+ *
+ * Copyright (C) 2006 Free Software Foundation, Inc.
+ * Written by Stefan Siegl <stesie@brokenpipe.de>.
+ *
+ * This file is part of GNU Mach.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _PCMCIA_GLUE_H
+#define _PCMCIA_GLUE_H
+
+/*
+ * pcmcia glue configuration
+ */
+#include <device-drivers.h>
+#define PCMCIA_DEBUG 4
+/* Maximum number of sockets supported by the glue code. */
+#define MAX_SOCKS 8
+
+
+/*
+ * Linux kernel version handling.
+ */
+#include <linux/version.h>
+#define UTS_VERSION "" /* Hm. */
+#define KERNEL_VERSION(v,p,s) (((v)<<16)+(p<<8)+s)
+
+
+/*
+ * Some cardbus drivers want `CARDBUS' to be defined.
+ */
+#ifdef CONFIG_CARDBUS
+#define CARDBUS 1
+#endif
+
+
+/*
+ * Some includes.
+ */
+#include <linux/malloc.h>
+#include <pcmcia/driver_ops.h>
+
+
+/*
+ * ioremap and iounmap
+ */
+#include <linux/pci.h>
+#include <linux/compatmac.h>
+#define iounmap(x) (((long)x<0x100000)?0:vfree ((void*)x))
+
+
+/*
+ * These are implemented in rsrc_mgr.c.
+ */
+extern int check_mem_region(u_long base, u_long num);
+extern void request_mem_region(u_long base, u_long num, char *name);
+extern void release_mem_region(u_long base, u_long num);
+
+
+/*
+ * Timer and delaying functions.
+ */
+#include <linux/delay.h>
+#define mod_timer(a, b) \
+ do { del_timer(a); (a)->expires = (b); add_timer(a); } while (0)
+#define mdelay(x) \
+ do { int i; for (i=0;i<x;i++) __udelay(1000); } while (0)
+
+
+/*
+ * GNU Mach's Linux glue code doesn't have
+ * `interruptible_sleep_on_timeout'. For the moment let's use the
+ * non-timeout variant. :-/
+ */
+#define interruptible_sleep_on_timeout(w,t) \
+ interruptible_sleep_on(w)
+
+/*
+ * The macro implementation relies on current_set symbol, which doesn't
+ * appear to be available on GNU Mach. TODO: How to fix this properly?
+ */
+#undef signal_pending
+#define signal_pending(c) \
+ 0
+
+
+/*
+ * Byte order stuff. TODO: This does not work on big endian systems,
+ * does it? Move to asm-i386?
+ */
+#include <asm/byteorder.h>
+#ifndef le16_to_cpu
+#define le16_to_cpu(x) (x)
+#define le32_to_cpu(x) (x)
+#endif
+#ifndef cpu_to_le16
+#define cpu_to_le16(val) (val)
+#define cpu_to_le32(val) (val)
+#endif
+
+
+/*
+ * There is no `wake_up_interruptible' on GNU Mach. Use plain `wake_up'
+ * for the moment. TODO.
+ */
+#define wake_up_interruptible wake_up
+
+
+/* Eliminate the 4-arg versions from <linux/compatmac.h>. */
+#undef pci_read_config_word
+#undef pci_read_config_dword
+
+#define bus_number(pci_dev) ((pci_dev)->bus->number)
+#define devfn_number(pci_dev) ((pci_dev)->devfn)
+
+#define pci_read_config_byte(pdev, where, valp) \
+ pcibios_read_config_byte(bus_number(pdev), devfn_number(pdev), where, valp)
+#define pci_read_config_word(pdev, where, valp) \
+ pcibios_read_config_word(bus_number(pdev), devfn_number(pdev), where, valp)
+#define pci_read_config_dword(pdev, where, valp) \
+ pcibios_read_config_dword(bus_number(pdev), devfn_number(pdev), where, valp)
+#define pci_write_config_byte(pdev, where, val) \
+ pcibios_write_config_byte(bus_number(pdev), devfn_number(pdev), where, val)
+#define pci_write_config_word(pdev, where, val) \
+ pcibios_write_config_word(bus_number(pdev), devfn_number(pdev), where, val)
+#define pci_write_config_dword(pdev, where, val) \
+ pcibios_write_config_dword(bus_number(pdev), devfn_number(pdev), where, val)
+
+
+/*
+ * From pcmcia-cs/include/linux/pci.h.
+ */
+#define pci_for_each_dev(p) for (p = pci_devices; p; p = p->next)
+
+
+
+/*
+ * These are defined in pci_fixup.c.
+ */
+extern struct pci_dev *pci_find_slot(u_int bus, u_int devfn);
+extern struct pci_dev *pci_find_class(u_int class, struct pci_dev *from);
+extern int pci_set_power_state(struct pci_dev *dev, int state);
+extern int pci_enable_device(struct pci_dev *dev);
+
+extern u32 pci_irq_mask;
+
+
+#ifdef PCMCIA_CLIENT
+/*
+ * Worse enough, we need to have `mach_device' as well (at least in ds.c)
+ * and this one is typedef'd to `device', therefore we cannot just
+ * include `netdevice.h' when we're compiling the core.
+ *
+ * For compilation of the clients `PCMCIA_CLIENT' is defined through the
+ * Makefile.
+ */
+#include <linux/netdevice.h>
+#include <linux/kcomp.h>
+
+
+/*
+ * init_dev_name and copy_dev_name glue (for `PCMCIA_CLIENT's only).
+ */
+static inline void
+init_dev_name(struct net_device *dev, dev_node_t node)
+{
+ /* just allocate some space for the device name,
+ * register_netdev will happily provide one to us
+ */
+ dev->name = kmalloc(8, GFP_KERNEL);
+ dev->name[0] = 0;
+
+ /*
+ * dev->init needs to be initialized in order for register_netdev to work
+ */
+ int stub(struct device *dev)
+ {
+ (void) dev;
+ return 0;
+ }
+ dev->init = stub;
+}
+
+#define copy_dev_name(node, dev) do { } while (0)
+#endif /* PCMCIA_CLIENT */
+
+
+/*
+ * Some network interface glue, additional to the one from
+ * <linux/kcomp.h>.
+ */
+#define netif_mark_up(dev) do { (dev)->start = 1; } while (0)
+#define netif_mark_down(dev) do { (dev)->start = 0; } while (0)
+#define netif_carrier_on(dev) do { dev->flags |= IFF_RUNNING; } while (0)
+#define netif_carrier_off(dev) do { dev->flags &= ~IFF_RUNNING; } while (0)
+#define tx_timeout_check(dev, tx_timeout) \
+ do { if (test_and_set_bit(0, (void *)&(dev)->tbusy) != 0) { \
+ if (jiffies - (dev)->trans_start < TX_TIMEOUT) return 1; \
+ tx_timeout(dev); \
+ } } while (0)
+
+
+/*
+ * Some `struct netdevice' interface glue (from the pcmcia-cs package).
+ */
+#define skb_tx_check(dev, skb) \
+ do { if (skb == NULL) { dev_tint(dev); return 0; } \
+ if (skb->len <= 0) return 0; } while (0)
+#define tx_timeout_check(dev, tx_timeout) \
+ do { if (test_and_set_bit(0, (void *)&(dev)->tbusy) != 0) { \
+ if (jiffies - (dev)->trans_start < TX_TIMEOUT) return 1; \
+ tx_timeout(dev); \
+ } } while (0)
+#define DEV_KFREE_SKB(skb) dev_kfree_skb(skb, FREE_WRITE)
+#define net_device_stats enet_statistics
+#define add_rx_bytes(stats, n) do { int x; x = (n); } while (0)
+#define add_tx_bytes(stats, n) do { int x; x = (n); } while (0)
+
+
+
+/*
+ * TODO: This is i386 dependent.
+ */
+#define readw_ns(p) readw(p)
+#define writew_ns(v,p) writew(v,p)
+
+
+
+
+/*
+ * We compile everything directly into the GNU Mach kernel, there are no
+ * modules.
+ */
+#define MODULE_PARM(a,b)
+#define MODULE_AUTHOR(a)
+#define MODULE_DESCRIPTION(a)
+#define MODULE_LICENSE(a)
+
+#define module_init(a) \
+ void pcmcia_mod ## a (void) { a(); return; }
+#define module_exit(a)
+
+/*
+ * Debugging convenience.
+ */
+extern void Debugger(void);
+
+
+/*
+ * TODO: We don't have `disable_irq_nosync', do we need it? This is used
+ * by the axnet_cs client driver only.
+ */
+#define disable_irq_nosync(irq) disable_irq(irq)
+
+
+#endif /* _PCMCIA_GLUE_H */
diff --git a/linux/pcmcia-cs/glue/wireless_glue.h b/linux/pcmcia-cs/glue/wireless_glue.h
new file mode 100644
index 0000000..f61f1ec
--- /dev/null
+++ b/linux/pcmcia-cs/glue/wireless_glue.h
@@ -0,0 +1,167 @@
+/*
+ * wireless network glue code
+ *
+ * Copyright (C) 2006 Free Software Foundation, Inc.
+ * Written by Stefan Siegl <stesie@brokenpipe.de>.
+ *
+ * This file is part of GNU Mach.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _WIRELESS_GLUE_H
+#define _WIRELESS_GLUE_H
+
+/*
+ * Wireless glue configuration.
+ */
+#include <device-drivers.h>
+
+
+/*
+ * Include the pcmcia glue as well, in case the kernel is configured for
+ * it.
+ */
+#ifdef CONFIG_PCMCIA
+#define PCMCIA_CLIENT
+#include "pcmcia_glue.h"
+#endif
+
+
+/*
+ * Definition of a `BUG' function: write message and panic out.
+ */
+#ifndef BUG
+#define BUG() \
+ do { printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
+ *(int *)0=0; } while (0)
+#endif
+
+
+/*
+ * We compile everything directly into the GNU Mach kernel, there are no
+ * modules.
+ */
+#define SET_MODULE_OWNER(a) do{ } while(0)
+#define EXPORT_SYMBOL(a)
+
+
+
+/*
+ * We need some `schedule_task' replacement. This is defined in
+ * kernel/context.c in the Linux kernel.
+ */
+static inline int
+schedule_task(struct tq_struct *task)
+{
+ printk(KERN_INFO "schedule_task: not implemented, task=%p\n", task);
+ Debugger();
+ return 0; /* fail */
+}
+
+
+/*
+ * min() and max() macros that also do strict type-checking. See the
+ * "unnecessary" pointer comparison.
+ */
+#define min(x,y) ({ \
+ const typeof(x) _x = (x); \
+ const typeof(y) _y = (y); \
+ (void) (&_x == &_y); \
+ _x < _y ? _x : _y; })
+
+#define max(x,y) ({ \
+ const typeof(x) _x = (x); \
+ const typeof(y) _y = (y); \
+ (void) (&_x == &_y); \
+ _x > _y ? _x : _y; })
+
+/*
+ * ... and if you can't take the strict types, you can specify one
+ * yourself.
+ */
+#define min_t(type,x,y) \
+ ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; })
+#define max_t(type,x,y) \
+ ({ type __x = (x); type __y = (y); __x > __y ? __x: __y; })
+
+
+#define DEV_KFREE_SKB(skb) dev_kfree_skb(skb, FREE_WRITE)
+
+
+/*
+ * TODO: this is i386 specific.
+ */
+#define le16_to_cpus(x) do { } while(0)
+
+
+/*
+ * Some wireless drivers check for a return value from `copy_to_user',
+ * however the `memcpy_tofs' implementation does return void.
+ */
+#undef copy_to_user
+#define copy_to_user(a,b,c) ((memcpy_tofs(a,b,c)), 0)
+
+
+/*
+ * Some more macros that are available on 2.2 and 2.4 Linux kernels.
+ */
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+
+/*
+ * TQUEUE glue.
+ */
+#define PREPARE_TQUEUE(_tq, _routine, _data) \
+ do { \
+ (_tq)->routine = _routine; \
+ (_tq)->data = _data; \
+ } while (0)
+#define INIT_TQUEUE(_tq, _routine, _data) \
+ do { \
+ (_tq)->next = 0; \
+ (_tq)->sync = 0; \
+ PREPARE_TQUEUE((_tq), (_routine), (_data)); \
+ } while (0)
+
+
+/*
+ * `etherdev' allocator.
+ */
+static inline struct net_device *
+alloc_etherdev(int sz)
+{
+ struct net_device *dev;
+ sz += sizeof(*dev) + 31;
+
+ if (!(dev = kmalloc(sz, GFP_KERNEL)))
+ return NULL;
+ memset(dev, 0, sz);
+
+ if (sz)
+ dev->priv = (void *)(((long)dev + sizeof(*dev) + 31) & ~31);
+
+ /* just allocate some space for the device name,
+ * register_netdev will happily provide one to us
+ */
+ dev->name = kmalloc(8, GFP_KERNEL);
+ dev->name[0] = 0;
+
+ ether_setup(dev);
+ return dev;
+}
+
+
+#endif /* _WIRELESS_GLUE_H */