From d5ca6ad6dab83572dbdafbdec34d129d5da5a1c1 Mon Sep 17 00:00:00 2001 From: Thomas Schwinge Date: Wed, 26 Jul 2006 23:13:52 +0000 Subject: 2006-07-27 Stefan Siegl * 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/glue/ds.c | 454 +++++++++++++++++++++++++++++++++++ linux/pcmcia-cs/glue/pcmcia.c | 121 ++++++++++ linux/pcmcia-cs/glue/pcmcia_glue.h | 271 +++++++++++++++++++++ linux/pcmcia-cs/glue/wireless_glue.h | 167 +++++++++++++ 4 files changed, 1013 insertions(+) create mode 100644 linux/pcmcia-cs/glue/ds.c create mode 100644 linux/pcmcia-cs/glue/pcmcia.c create mode 100644 linux/pcmcia-cs/glue/pcmcia_glue.h create mode 100644 linux/pcmcia-cs/glue/wireless_glue.h (limited to 'linux/pcmcia-cs/glue') 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 . + * + * 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 + +/* + * 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 +#undef event_t + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include + +#include + +/* 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, ¬ify); + 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 . + * + * 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 +#include + +#include + +#include +#include +#include +#include + +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 . + * + * 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 +#define PCMCIA_DEBUG 4 +/* Maximum number of sockets supported by the glue code. */ +#define MAX_SOCKS 8 + + +/* + * Linux kernel version handling. + */ +#include +#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 +#include + + +/* + * ioremap and iounmap + */ +#include +#include +#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 +#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 +#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 . */ +#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 +#include + + +/* + * 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 + * . + */ +#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 . + * + * 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 + + +/* + * 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 */ -- cgit v1.2.3