📄 aironet4500_cs.c
字号:
/* * Aironet 4500 Pcmcia driver * * Elmer Joandi, Januar 1999 * Copyright Elmer Joandi, all rights restricted * * * Revision 0.1 ,started 30.12.1998 * * */#define DRV_NAME "aironet4500_cs"#define DRV_VERSION "0.1"static const char *awc_version =DRV_NAME ".c v" DRV_VERSION " 1/1/99 Elmer Joandi, elmer@ylenurme.ee.\n";#include <linux/module.h>#include <linux/init.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/ptrace.h>#include <linux/slab.h>#include <linux/string.h>#include <linux/timer.h>#include <linux/interrupt.h>#include <linux/in.h>#include <linux/ethtool.h>#include <asm/uaccess.h>#include <asm/io.h>#include <asm/system.h>#include <asm/bitops.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/skbuff.h>#include <linux/if_arp.h>#include <linux/ioport.h>#include <pcmcia/version.h>#include <pcmcia/cs_types.h>#include <pcmcia/cs.h>#include <pcmcia/cistpl.h>#include <pcmcia/cisreg.h>#include <pcmcia/ciscode.h>#if LINUX_VERSION_CODE < 0x20300#ifdef MODULE#include <pcmcia/k_compat.h>#endif#endif#include <pcmcia/ds.h>#include "../aironet4500.h"static u_int irq_mask = 0x5eF8;static int awc_ports[] = {0x140,0x100,0xc0, 0x80 };#if LINUX_VERSION_CODE > 0x20100MODULE_PARM(irq_mask, "i");#endif#define RUN_AT(x) (jiffies+(x))#ifdef PCMCIA_DEBUGstatic int pc_debug = PCMCIA_DEBUG;MODULE_PARM(pc_debug, "i");#define PC_DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)static char *version ="aironet4500_cs.c v0.1 1/1/99 Elmer Joandi, elmer@ylenurme.ee.\n";#else#define PC_DEBUG(n, args...)#endif/* Index of functions. */static dev_info_t dev_info = "aironet4500_cs";static dev_link_t *awc_attach(void);static void awc_detach(dev_link_t *);static void awc_release(u_long arg);static int awc_event(event_t event, int priority, event_callback_args_t *args);static dev_link_t *dev_list;static void cs_error(client_handle_t handle, int func, int ret){#if CS_RELEASE_CODE < 0x2911 CardServices(ReportError, dev_info, (void *)func, (void *)ret);#else error_info_t err = { func, ret }; CardServices(ReportError, handle, &err);#endif}#define CFG_CHECK(fn, args...) if (CardServices(fn, args) != 0) goto next_entrystatic void flush_stale_links(void){ dev_link_t *link, *next; for (link = dev_list; link; link = next) { next = link->next; if (link->state & DEV_STALE_LINK) awc_detach(link); }}/* We never need to do anything when a awc device is "initialized" by the net software, because we only register already-found cards.*/static int awc_pcmcia_init(struct net_device *dev){ return awc_init(dev);}static int awc_pcmcia_open(struct net_device *dev){ dev_link_t *link; int status; for (link = dev_list; link; link = link->next) if (link->priv == dev) break; if (!DEV_OK(link)) return -ENODEV; status = awc_open(dev); if (!status ) link->open++; return status;}static int awc_pcmcia_close(struct net_device *dev){// int ioaddr = dev->base_addr; dev_link_t *link; int ret; for (link = dev_list; link; link = link->next) if (link->priv == dev) break; if (link == NULL) return -ENODEV; PC_DEBUG(2, "%s: closing device.\n", dev->name); link->open--; ret = awc_close(dev); if (link->state & DEV_STALE_CONFIG) { link->release.expires = RUN_AT( HZ/20 ); link->state |= DEV_RELEASE_PENDING; add_timer(&link->release); } return ret;}static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr){ u32 ethcmd; /* dev_ioctl() in ../../net/core/dev.c has already checked capable(CAP_NET_ADMIN), so don't bother with that here. */ if (get_user(ethcmd, (u32 *)useraddr)) return -EFAULT; switch (ethcmd) { case ETHTOOL_GDRVINFO: { struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO }; strcpy (info.driver, DRV_NAME); strcpy (info.version, DRV_VERSION); sprintf(info.bus_info, "PCMCIA 0x%lx", dev->base_addr); if (copy_to_user (useraddr, &info, sizeof (info))) return -EFAULT; return 0; }#ifdef PCMCIA_DEBUG /* get message-level */ case ETHTOOL_GMSGLVL: { struct ethtool_value edata = {ETHTOOL_GMSGLVL}; edata.data = pc_debug; if (copy_to_user(useraddr, &edata, sizeof(edata))) return -EFAULT; return 0; } /* set message-level */ case ETHTOOL_SMSGLVL: { struct ethtool_value edata; if (copy_from_user(&edata, useraddr, sizeof(edata))) return -EFAULT; pc_debug = edata.data; return 0; }#endif default: break; } return -EOPNOTSUPP;}static int awc_ioctl(struct net_device *dev, struct ifreq *rq, int cmd){ switch (cmd) { case SIOCETHTOOL: return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); default: return -EOPNOTSUPP; } return 0;}/* awc_attach() creates an "instance" of the driver, allocating local data structures for one device. The device is registered with Card Services.*/static dev_link_t *awc_attach(void){ client_reg_t client_reg; dev_link_t *link = NULL; struct net_device *dev = NULL; int ret; PC_DEBUG(0, "awc_attach()\n"); flush_stale_links(); /* Create the PC card device object. */ link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); if (!link) return NULL; memset(link, 0, sizeof(struct dev_link_t)); link->dev = kmalloc(sizeof(struct dev_node_t), GFP_KERNEL); if (!link->dev) { kfree(link); return NULL; } memset(link->dev, 0, sizeof(struct dev_node_t)); link->release.function = &awc_release; link->release.data = (u_long)link;// link->io.NumPorts1 = 32; link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;// link->io.IOAddrLines = 5; link->irq.Attributes = IRQ_HANDLE_PRESENT ; // |IRQ_TYPE_EXCLUSIVE ; link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID; link->irq.IRQInfo2 = irq_mask; link->irq.Handler = &awc_interrupt; link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.Vcc = 50; link->conf.IntType = INT_MEMORY_AND_IO; link->conf.ConfigIndex = 1; link->conf.Present = PRESENT_OPTION; /* Create the network device object. */ dev = kmalloc(sizeof(struct net_device ), GFP_KERNEL);// dev = init_etherdev(0, sizeof(struct awc_private) ); if (!dev ) { printk(KERN_CRIT "out of mem on dev alloc \n"); kfree(link->dev); kfree(link); return NULL; }; memset(dev,0,sizeof(struct net_device)); dev->priv = kmalloc(sizeof(struct awc_private), GFP_KERNEL); if (!dev->priv ) {printk(KERN_CRIT "out of mem on dev priv alloc \n"); return NULL;}; memset(dev->priv,0,sizeof(struct awc_private)); // link->dev->minor = dev->minor;// link->dev->major = dev->major; /* The 4500-specific entries in the device structure. */// dev->tx_queue_len = tx_queue_len; dev->hard_start_xmit = &awc_start_xmit;// dev->set_config = &awc_config_misiganes,aga mitte awc_config; dev->get_stats = &awc_get_stats;// dev->set_multicast_list = &awc_set_multicast_list; dev->do_ioctl = &awc_ioctl; strcpy(dev->name, ((struct awc_private *)dev->priv)->node.dev_name); ether_setup(dev); dev->init = &awc_pcmcia_init; dev->open = &awc_pcmcia_open; dev->stop = &awc_pcmcia_close; link->priv = dev;#if CS_RELEASE_CODE > 0x2911 link->irq.Instance = dev;#endif /* Register with Card Services */ link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; client_reg.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; client_reg.event_handler = &awc_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = CardServices(RegisterClient, &link->handle, &client_reg); if (ret != 0) { cs_error(link->handle, RegisterClient, ret); awc_detach(link); return NULL; } return link;} /* awc_attach *//* This deletes a driver "instance". The device is de-registered with Card Services. If it has been released, all local data structures are freed. Otherwise, the structures will be freed when the device is released.*/static void awc_detach(dev_link_t *link){ dev_link_t **linkp; long flags; int i=0; DEBUG(0, "awc_detach(0x%p)\n", link); /* Locate device structure */ for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) if (*linkp == link) break; if (*linkp == NULL)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -