?? ircard_cs.c
字號:
/********************************************************************* * * Filename: ircard_cs.c * Version: 0.8 * Description: IrDA FIR device driver for the IRDATA IRCARD which is * using the IBM 31T1502 controller chip * Status: Experimental. * Author: Dag Brattli <dagb@cs.uit.no> * Created at: Fri Apr 2 00:01:11 1999 * Modified at: Fri Aug 27 12:30:00 1999 * Modified by: Dag Brattli <dagb@cs.uit.no> * * Copyright (c) 1999 Dag Brattli, All Rights Reserved. * * 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 of * the License, 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, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * ********************************************************************/#include <pcmcia/config.h>#include <pcmcia/k_compat.h>#include <linux/autoconf.h> /* Very important! */#include <linux/kernel.h>#include <linux/sched.h>#include <linux/ptrace.h>#include <linux/malloc.h>#include <linux/string.h>#include <linux/timer.h>#include <linux/delay.h>#include <linux/ioport.h>#include <asm/io.h>#include <asm/system.h>#include <net/irda/irda.h>#include <net/irda/irmod.h>#include <net/irda/irda_device.h>#include <net/irda/irport.h>#include <net/irda/wrapper.h>#include <pcmcia/version.h>#include <pcmcia/cs_types.h>#include <pcmcia/cs.h>#include <pcmcia/cistpl.h>#include <pcmcia/cisreg.h>#include <pcmcia/ds.h>#include <pcmcia/mem_op.h>#include "ircard_cs.h"#if LINUX_VERSION_CODE < VERSION(2,3,14)#define net_device device#endifstatic char *version = "ircard_cs.c 0.1 Fri Apr 2 11:21:27 1999 (Dag Brattli)";/* Parameters that can be set with 'insmod' *//* The old way: bit map of interrupts to choose from *//* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4, and 3 */static u_int irq_mask = 0xdeb8;/* Newer, simpler way of listing specific interrupts */static int irq_list[4] = { -1 };/* The IBM 31T1100A tranceiver needs at least 120 us */static int qos_mtt_bits = 0x0f; /* We have to set it to 500 us */MODULE_PARM(irq_mask, "i");MODULE_PARM(irq_list, "1-4i");MODULE_PARM(qos_mtt_bits, "i");static void ircard_config(dev_link_t *link);static void ircard_release(u_long arg);static int ircard_event(event_t event, int priority, event_callback_args_t *args);static dev_link_t *ircard_attach(void);static void ircard_detach(dev_link_t *);static int ircard_probe(struct irda_device *idev);static void ircard_change_speed(struct irda_device *idev, __u32 speed);static int ircard_hard_xmit(struct sk_buff *skb, struct net_device *dev);static void ircard_dma_write(struct irda_device *idev, int iobase);static int ircard_receive(struct irda_device *idev, int iobase);static void ircard_interrupt(int irq, void *dev_id, struct pt_regs *regs);static int ircard_is_receiving(struct irda_device *idev);static void ircard_wait_until_sent(struct irda_device *idev);static int ircard_net_close(struct net_device *dev);static int ircard_net_open(struct net_device *dev);static int ircard_net_init(struct net_device *dev);static dev_info_t dev_info = "ircard_cs";static dev_link_t *dev_list = NULL;static void cs_error(client_handle_t handle, int func, int ret){ error_info_t err = { func, ret }; CardServices(ReportError, handle, &err);}/* * Function ircard_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 *ircard_attach(void){ client_reg_t client_reg; dev_link_t *link; struct ircard_cb *self; int ret, i; DEBUG(0, __FUNCTION__ "()\n"); /* Initialize the dev_link_t structure */ link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); memset(link, 0, sizeof(struct dev_link_t)); link->release.function = &ircard_release; link->release.data = (u_long)link; /* Interrupt setup */ link->irq.Attributes = IRQ_TYPE_EXCLUSIVE|IRQ_HANDLE_PRESENT; link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID; if (irq_list[0] == -1) link->irq.IRQInfo2 = irq_mask; else for (i = 0; i < 4; i++) link->irq.IRQInfo2 |= 1 << irq_list[i]; link->irq.Handler = &ircard_interrupt; /* * General socket configuration defaults can go here. In this * client, we assume very little, and rely on the CIS for almost * everything. In most clients, many details (i.e., number, sizes, * and attributes of IO windows) are fixed by the nature of the * device, and can be hard-wired here. */ link->conf.Attributes = 0; link->conf.Vcc = 50; link->conf.IntType = INT_MEMORY_AND_IO; /* Allocate space for private device-specific data */ self = kmalloc(sizeof(struct ircard_cb), GFP_KERNEL); memset(self, 0, sizeof(struct ircard_cb)); self->magic = IRCARD_MAGIC; link->priv = self; link->irq.Instance = &self->idev; /* 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 = &ircard_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); ircard_detach(link); return NULL; } return link;}/* * Function ircard_detach (link) * * 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 ircard_detach(dev_link_t *link){ dev_link_t **linkp; struct ircard_cb *self; struct irda_device *idev; DEBUG(0, __FUNCTION__ "(0x%p)\n", link); self = (struct ircard_cb *) link->priv; idev = &self->idev; /* Locate device structure */ for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) if (*linkp == link) break; if (*linkp == NULL) return; /* * If the device is currently configured and active, we won't * actually delete it yet. Instead, it is marked so that when * the release() function is called, that will trigger a proper * detach(). */ if (link->state & DEV_CONFIG) {#ifdef PCMCIA_DEBUG printk(KERN_DEBUG "ircard_cs: detach postponed, '%s' " "still locked\n", link->dev->dev_name);#endif link->state |= DEV_STALE_LINK; return; } /* Break the link with Card Services */ if (link->handle) CardServices(DeregisterClient, link->handle); /* Unlink device structure, free pieces */ *linkp = link->next; if (self) { /* Close irport */ irport_stop(idev, idev->io.iobase2); irda_device_close(idev); kfree_s(self, sizeof(struct ircard_cb)); } kfree_s(link, sizeof(struct dev_link_t)); }#define CS_CHECK(fn, args...) \while ((last_ret=CardServices(last_fn=(fn),args))!=0) goto cs_failed#define CFG_CHECK(fn, args...) \if (CardServices(fn, args) != 0) goto next_entry/* * Function ircard_config (link) * * Configure the card and prepare for IO * */static void ircard_config(dev_link_t *link){ struct irda_device *idev; struct ircard_cb *self; client_handle_t handle; tuple_t tuple; cisparse_t parse; int last_fn, last_ret; u_char buf[64]; win_req_t req; memreq_t map; handle = link->handle; self = (struct ircard_cb *) link->priv; ASSERT(self != NULL, return;); ASSERT(self->magic == IRCARD_MAGIC, return;); DEBUG(0, __FUNCTION__ "(0x%p)\n", link); /* * This reads the card's CONFIG tuple to find its configuration * registers. */ tuple.DesiredTuple = CISTPL_CONFIG; tuple.Attributes = 0; tuple.TupleData = buf; tuple.TupleDataMax = sizeof(buf); tuple.TupleOffset = 0; CS_CHECK(GetFirstTuple, handle, &tuple); CS_CHECK(GetTupleData, handle, &tuple); CS_CHECK(ParseTuple, handle, &tuple, &parse); link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; DEBUG(0, __FUNCTION__ "() present=%x\n", link->conf.Present); /* Configure card */ link->state |= DEV_CONFIG; /* * In this loop, we scan the CIS for configuration table entries, * each of which describes a valid card configuration, including * voltage, IO window, memory window, and interrupt settings. * * We make no assumptions about the card to be configured: we use * just the information available in the CIS. In an ideal world, * this would work for any PCMCIA card, but it requires a complete * and accurate CIS. In practice, a driver usually "knows" most of * these things without consulting the CIS, and most client drivers * will only use the CIS to fill in implementation-defined details. * */ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; CS_CHECK(GetFirstTuple, handle, &tuple); while (1) { cistpl_cftable_entry_t dflt = { 0 }; cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); CFG_CHECK(GetTupleData, handle, &tuple); CFG_CHECK(ParseTuple, handle, &tuple, &parse); if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg; if (cfg->index == 0) goto next_entry; link->conf.ConfigIndex = cfg->index; /* Does this card need audio output? */ if (cfg->flags & CISTPL_CFTABLE_AUDIO) { link->conf.Attributes |= CONF_ENABLE_SPKR; link->conf.Status = CCSR_AUDIO_ENA; } /* * Use power settings for Vcc and Vpp if present * * Note that the CIS values need to be rescaled */ if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) link->conf.Vcc = cfg->vcc.param[CISTPL_POWER_VNOM]/10000; else if (dflt.vcc.present & (1<<CISTPL_POWER_VNOM)) link->conf.Vcc = dflt.vcc.param[CISTPL_POWER_VNOM]/10000; if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM)) link->conf.Vpp1 = link->conf.Vpp2 = cfg->vpp1.param[CISTPL_POWER_VNOM]/10000; else if (dflt.vpp1.present & (1<<CISTPL_POWER_VNOM)) link->conf.Vpp1 = link->conf.Vpp2 = dflt.vpp1.param[CISTPL_POWER_VNOM]/10000; /* Do we need to allocate an interrupt? */ if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) link->conf.Attributes |= CONF_ENABLE_IRQ; /* IO window settings */ link->io.NumPorts1 = link->io.NumPorts2 = 0; if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io; link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; if (!(io->flags & CISTPL_IO_8BIT)) link->io.Attributes1 = IO_DATA_PATH_WIDTH_16; if (!(io->flags & CISTPL_IO_16BIT)) link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; link->io.BasePort1 = io->win[0].base; link->io.NumPorts1 = io->win[0].len; if (io->nwin > 1) { link->io.Attributes2 = link->io.Attributes1; link->io.BasePort2 = io->win[1].base; link->io.NumPorts2 = io->win[1].len; } } /* This reserves IO space but doesn't actually enable it */ CFG_CHECK(RequestIO, link->handle, &link->io); /* * Now set up a common memory window, if needed. There is * room in the dev_link_t structure for one memory window * handle, but if the base addresses need to be saved, or * if multiple windows are needed, the info should go in * the private data structure for this device. * * Note that the memory window base is a physical address, * and needs to be mapped to virtual space with ioremap() * before it is used. */ if ((cfg->mem.nwin > 0) || (dflt.mem.nwin > 0)) { cistpl_mem_t *mem = (cfg->mem.nwin) ? &cfg->mem : &dflt.mem; req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM| WIN_ENABLE/*|WIN_USE_WAIT*/|WIN_MAP_BELOW_1MB; req.Base = 0; /*mem->win[0].host_addr;*/ req.Size = mem->win[0].len; req.Size = 0x8000; req.AccessSpeed = 0; link->win = (window_handle_t)link->handle; CFG_CHECK(RequestWindow, &link->win, &req); map.Page = 0; map.CardOffset = mem->win[0].card_addr; CFG_CHECK(MapMemPage, link->win, &map); } /* If we got this far, we're cool! */ break; next_entry: CS_CHECK(GetNextTuple, handle, &tuple); } /* * Allocate an interrupt line. Note that this does not assign a * handler to the interrupt, unless the 'Handler' member of the * irq structure is initialized. */ if (link->conf.Attributes & CONF_ENABLE_IRQ) CS_CHECK(RequestIRQ, link->handle, &link->irq); /* * This actually configures the PCMCIA socket -- setting up * the I/O windows and the interrupt mapping, and putting the * card and host interface into "Memory and IO" mode. */ CS_CHECK(RequestConfiguration, link->handle, &link->conf); /* * At this point, the dev_node_t structure(s) need to be * initialized and arranged in a linked list at link->dev. */ sprintf(self->node.dev_name, "ircard0"); self->node.major = self->node.minor = 0; link->dev = &self->node; /* Finally, report what we've done */ printk(KERN_INFO "%s: index 0x%02x: Vcc %d.%d", self->node.dev_name, link->conf.ConfigIndex, link->conf.Vcc/10, link->conf.Vcc%10); if (link->conf.Vpp1) printk(", Vpp %d.%d", link->conf.Vpp1/10, link->conf.Vpp1%10); if (link->conf.Attributes & CONF_ENABLE_IRQ) printk(", irq %d", link->irq.AssignedIRQ); if (link->io.NumPorts1) printk(", io 0x%04x-0x%04x", link->io.BasePort1, link->io.BasePort1+link->io.NumPorts1-1); if (link->io.NumPorts2) printk(" & 0x%04x-0x%04x", link->io.BasePort2, link->io.BasePort2+link->io.NumPorts2-1); if (link->win) printk(", mem 0x%06lx-0x%06lx", req.Base, req.Base+req.Size-1); printk("\n"); /* Look up the irda device */ idev = &self->idev; /* Initialize IO */ idev->io.iobase = link->io.BasePort1+8; idev->io.iobase2 = link->io.BasePort1; /* Used by irport */ idev->io.irq = link->irq.AssignedIRQ; idev->io.io_ext = 8; idev->io.io_ext2 = 8; /* Used by irport */ idev->io.membase = (int) ioremap(req.Base, req.Size); idev->io.fifo_size = 16; idev->io.baudrate = 9600; DEBUG(0, __FUNCTION__ "(), membase=%08x\n", idev->io.membase); /* Reset Tx queue info */ self->tx_q.len = self->tx_q.ptr = self->tx_q.free = 0;
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -