162306a36Sopenharmony_ci/* [xirc2ps_cs.c wk 03.11.99] (1.40 1999/11/18 00:06:03) 262306a36Sopenharmony_ci * Xircom CreditCard Ethernet Adapter IIps driver 362306a36Sopenharmony_ci * Xircom Realport 10/100 (RE-100) driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * This driver supports various Xircom CreditCard Ethernet adapters 662306a36Sopenharmony_ci * including the CE2, CE IIps, RE-10, CEM28, CEM33, CE33, CEM56, 762306a36Sopenharmony_ci * CE3-100, CE3B, RE-100, REM10BT, and REM56G-100. 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * 2000-09-24 <psheer@icon.co.za> The Xircom CE3B-100 may not 1062306a36Sopenharmony_ci * autodetect the media properly. In this case use the 1162306a36Sopenharmony_ci * if_port=1 (for 10BaseT) or if_port=4 (for 100BaseT) options 1262306a36Sopenharmony_ci * to force the media type. 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * Written originally by Werner Koch based on David Hinds' skeleton of the 1562306a36Sopenharmony_ci * PCMCIA driver. 1662306a36Sopenharmony_ci * 1762306a36Sopenharmony_ci * Copyright (c) 1997,1998 Werner Koch (dd9jn) 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * This driver is free software; you can redistribute it and/or modify 2062306a36Sopenharmony_ci * it under the terms of the GNU General Public License as published by 2162306a36Sopenharmony_ci * the Free Software Foundation; either version 2 of the License, or 2262306a36Sopenharmony_ci * (at your option) any later version. 2362306a36Sopenharmony_ci * 2462306a36Sopenharmony_ci * It is distributed in the hope that it will be useful, 2562306a36Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 2662306a36Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 2762306a36Sopenharmony_ci * GNU General Public License for more details. 2862306a36Sopenharmony_ci * 2962306a36Sopenharmony_ci * You should have received a copy of the GNU General Public License 3062306a36Sopenharmony_ci * along with this program; if not, see <http://www.gnu.org/licenses/>. 3162306a36Sopenharmony_ci * 3262306a36Sopenharmony_ci * 3362306a36Sopenharmony_ci * ALTERNATIVELY, this driver may be distributed under the terms of 3462306a36Sopenharmony_ci * the following license, in which case the provisions of this license 3562306a36Sopenharmony_ci * are required INSTEAD OF the GNU General Public License. (This clause 3662306a36Sopenharmony_ci * is necessary due to a potential bad interaction between the GPL and 3762306a36Sopenharmony_ci * the restrictions contained in a BSD-style copyright.) 3862306a36Sopenharmony_ci * 3962306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 4062306a36Sopenharmony_ci * modification, are permitted provided that the following conditions 4162306a36Sopenharmony_ci * are met: 4262306a36Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright 4362306a36Sopenharmony_ci * notice, and the entire permission notice in its entirety, 4462306a36Sopenharmony_ci * including the disclaimer of warranties. 4562306a36Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright 4662306a36Sopenharmony_ci * notice, this list of conditions and the following disclaimer in the 4762306a36Sopenharmony_ci * documentation and/or other materials provided with the distribution. 4862306a36Sopenharmony_ci * 3. The name of the author may not be used to endorse or promote 4962306a36Sopenharmony_ci * products derived from this software without specific prior 5062306a36Sopenharmony_ci * written permission. 5162306a36Sopenharmony_ci * 5262306a36Sopenharmony_ci * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED 5362306a36Sopenharmony_ci * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 5462306a36Sopenharmony_ci * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 5562306a36Sopenharmony_ci * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 5662306a36Sopenharmony_ci * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 5762306a36Sopenharmony_ci * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 5862306a36Sopenharmony_ci * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 5962306a36Sopenharmony_ci * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 6062306a36Sopenharmony_ci * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 6162306a36Sopenharmony_ci * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 6262306a36Sopenharmony_ci * OF THE POSSIBILITY OF SUCH DAMAGE. 6362306a36Sopenharmony_ci */ 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci#include <linux/module.h> 6862306a36Sopenharmony_ci#include <linux/kernel.h> 6962306a36Sopenharmony_ci#include <linux/init.h> 7062306a36Sopenharmony_ci#include <linux/ptrace.h> 7162306a36Sopenharmony_ci#include <linux/slab.h> 7262306a36Sopenharmony_ci#include <linux/string.h> 7362306a36Sopenharmony_ci#include <linux/timer.h> 7462306a36Sopenharmony_ci#include <linux/interrupt.h> 7562306a36Sopenharmony_ci#include <linux/in.h> 7662306a36Sopenharmony_ci#include <linux/delay.h> 7762306a36Sopenharmony_ci#include <linux/ethtool.h> 7862306a36Sopenharmony_ci#include <linux/netdevice.h> 7962306a36Sopenharmony_ci#include <linux/etherdevice.h> 8062306a36Sopenharmony_ci#include <linux/skbuff.h> 8162306a36Sopenharmony_ci#include <linux/if_arp.h> 8262306a36Sopenharmony_ci#include <linux/ioport.h> 8362306a36Sopenharmony_ci#include <linux/bitops.h> 8462306a36Sopenharmony_ci#include <linux/mii.h> 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci#include <pcmcia/cistpl.h> 8762306a36Sopenharmony_ci#include <pcmcia/cisreg.h> 8862306a36Sopenharmony_ci#include <pcmcia/ciscode.h> 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci#include <asm/io.h> 9162306a36Sopenharmony_ci#include <linux/uaccess.h> 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci#ifndef MANFID_COMPAQ 9462306a36Sopenharmony_ci #define MANFID_COMPAQ 0x0138 9562306a36Sopenharmony_ci #define MANFID_COMPAQ2 0x0183 /* is this correct? */ 9662306a36Sopenharmony_ci#endif 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci#include <pcmcia/ds.h> 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci/* Time in jiffies before concluding Tx hung */ 10162306a36Sopenharmony_ci#define TX_TIMEOUT ((400*HZ)/1000) 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci/**************** 10462306a36Sopenharmony_ci * Some constants used to access the hardware 10562306a36Sopenharmony_ci */ 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci/* Register offsets and value constans */ 10862306a36Sopenharmony_ci#define XIRCREG_CR 0 /* Command register (wr) */ 10962306a36Sopenharmony_cienum xirc_cr { 11062306a36Sopenharmony_ci TransmitPacket = 0x01, 11162306a36Sopenharmony_ci SoftReset = 0x02, 11262306a36Sopenharmony_ci EnableIntr = 0x04, 11362306a36Sopenharmony_ci ForceIntr = 0x08, 11462306a36Sopenharmony_ci ClearTxFIFO = 0x10, 11562306a36Sopenharmony_ci ClearRxOvrun = 0x20, 11662306a36Sopenharmony_ci RestartTx = 0x40 11762306a36Sopenharmony_ci}; 11862306a36Sopenharmony_ci#define XIRCREG_ESR 0 /* Ethernet status register (rd) */ 11962306a36Sopenharmony_cienum xirc_esr { 12062306a36Sopenharmony_ci FullPktRcvd = 0x01, /* full packet in receive buffer */ 12162306a36Sopenharmony_ci PktRejected = 0x04, /* a packet has been rejected */ 12262306a36Sopenharmony_ci TxPktPend = 0x08, /* TX Packet Pending */ 12362306a36Sopenharmony_ci IncorPolarity = 0x10, 12462306a36Sopenharmony_ci MediaSelect = 0x20 /* set if TP, clear if AUI */ 12562306a36Sopenharmony_ci}; 12662306a36Sopenharmony_ci#define XIRCREG_PR 1 /* Page Register select */ 12762306a36Sopenharmony_ci#define XIRCREG_EDP 4 /* Ethernet Data Port Register */ 12862306a36Sopenharmony_ci#define XIRCREG_ISR 6 /* Ethernet Interrupt Status Register */ 12962306a36Sopenharmony_cienum xirc_isr { 13062306a36Sopenharmony_ci TxBufOvr = 0x01, /* TX Buffer Overflow */ 13162306a36Sopenharmony_ci PktTxed = 0x02, /* Packet Transmitted */ 13262306a36Sopenharmony_ci MACIntr = 0x04, /* MAC Interrupt occurred */ 13362306a36Sopenharmony_ci TxResGrant = 0x08, /* Tx Reservation Granted */ 13462306a36Sopenharmony_ci RxFullPkt = 0x20, /* Rx Full Packet */ 13562306a36Sopenharmony_ci RxPktRej = 0x40, /* Rx Packet Rejected */ 13662306a36Sopenharmony_ci ForcedIntr= 0x80 /* Forced Interrupt */ 13762306a36Sopenharmony_ci}; 13862306a36Sopenharmony_ci#define XIRCREG1_IMR0 12 /* Ethernet Interrupt Mask Register (on page 1)*/ 13962306a36Sopenharmony_ci#define XIRCREG1_IMR1 13 14062306a36Sopenharmony_ci#define XIRCREG0_TSO 8 /* Transmit Space Open Register (on page 0)*/ 14162306a36Sopenharmony_ci#define XIRCREG0_TRS 10 /* Transmit reservation Size Register (page 0)*/ 14262306a36Sopenharmony_ci#define XIRCREG0_DO 12 /* Data Offset Register (page 0) (wr) */ 14362306a36Sopenharmony_ci#define XIRCREG0_RSR 12 /* Receive Status Register (page 0) (rd) */ 14462306a36Sopenharmony_cienum xirc_rsr { 14562306a36Sopenharmony_ci PhyPkt = 0x01, /* set:physical packet, clear: multicast packet */ 14662306a36Sopenharmony_ci BrdcstPkt = 0x02, /* set if it is a broadcast packet */ 14762306a36Sopenharmony_ci PktTooLong = 0x04, /* set if packet length > 1518 */ 14862306a36Sopenharmony_ci AlignErr = 0x10, /* incorrect CRC and last octet not complete */ 14962306a36Sopenharmony_ci CRCErr = 0x20, /* incorrect CRC and last octet is complete */ 15062306a36Sopenharmony_ci PktRxOk = 0x80 /* received ok */ 15162306a36Sopenharmony_ci}; 15262306a36Sopenharmony_ci#define XIRCREG0_PTR 13 /* packets transmitted register (rd) */ 15362306a36Sopenharmony_ci#define XIRCREG0_RBC 14 /* receive byte count regsister (rd) */ 15462306a36Sopenharmony_ci#define XIRCREG1_ECR 14 /* ethernet configurationn register */ 15562306a36Sopenharmony_cienum xirc_ecr { 15662306a36Sopenharmony_ci FullDuplex = 0x04, /* enable full duplex mode */ 15762306a36Sopenharmony_ci LongTPMode = 0x08, /* adjust for longer lengths of TP cable */ 15862306a36Sopenharmony_ci DisablePolCor = 0x10,/* disable auto polarity correction */ 15962306a36Sopenharmony_ci DisableLinkPulse = 0x20, /* disable link pulse generation */ 16062306a36Sopenharmony_ci DisableAutoTx = 0x40, /* disable auto-transmit */ 16162306a36Sopenharmony_ci}; 16262306a36Sopenharmony_ci#define XIRCREG2_RBS 8 /* receive buffer start register */ 16362306a36Sopenharmony_ci#define XIRCREG2_LED 10 /* LED Configuration register */ 16462306a36Sopenharmony_ci/* values for the leds: Bits 2-0 for led 1 16562306a36Sopenharmony_ci * 0 disabled Bits 5-3 for led 2 16662306a36Sopenharmony_ci * 1 collision 16762306a36Sopenharmony_ci * 2 noncollision 16862306a36Sopenharmony_ci * 3 link_detected 16962306a36Sopenharmony_ci * 4 incor_polarity 17062306a36Sopenharmony_ci * 5 jabber 17162306a36Sopenharmony_ci * 6 auto_assertion 17262306a36Sopenharmony_ci * 7 rx_tx_activity 17362306a36Sopenharmony_ci */ 17462306a36Sopenharmony_ci#define XIRCREG2_MSR 12 /* Mohawk specific register */ 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci#define XIRCREG4_GPR0 8 /* General Purpose Register 0 */ 17762306a36Sopenharmony_ci#define XIRCREG4_GPR1 9 /* General Purpose Register 1 */ 17862306a36Sopenharmony_ci#define XIRCREG2_GPR2 13 /* General Purpose Register 2 (page2!)*/ 17962306a36Sopenharmony_ci#define XIRCREG4_BOV 10 /* Bonding Version Register */ 18062306a36Sopenharmony_ci#define XIRCREG4_LMA 12 /* Local Memory Address Register */ 18162306a36Sopenharmony_ci#define XIRCREG4_LMD 14 /* Local Memory Data Port */ 18262306a36Sopenharmony_ci/* MAC register can only by accessed with 8 bit operations */ 18362306a36Sopenharmony_ci#define XIRCREG40_CMD0 8 /* Command Register (wr) */ 18462306a36Sopenharmony_cienum xirc_cmd { /* Commands */ 18562306a36Sopenharmony_ci Transmit = 0x01, 18662306a36Sopenharmony_ci EnableRecv = 0x04, 18762306a36Sopenharmony_ci DisableRecv = 0x08, 18862306a36Sopenharmony_ci Abort = 0x10, 18962306a36Sopenharmony_ci Online = 0x20, 19062306a36Sopenharmony_ci IntrAck = 0x40, 19162306a36Sopenharmony_ci Offline = 0x80 19262306a36Sopenharmony_ci}; 19362306a36Sopenharmony_ci#define XIRCREG5_RHSA0 10 /* Rx Host Start Address */ 19462306a36Sopenharmony_ci#define XIRCREG40_RXST0 9 /* Receive Status Register */ 19562306a36Sopenharmony_ci#define XIRCREG40_TXST0 11 /* Transmit Status Register 0 */ 19662306a36Sopenharmony_ci#define XIRCREG40_TXST1 12 /* Transmit Status Register 10 */ 19762306a36Sopenharmony_ci#define XIRCREG40_RMASK0 13 /* Receive Mask Register */ 19862306a36Sopenharmony_ci#define XIRCREG40_TMASK0 14 /* Transmit Mask Register 0 */ 19962306a36Sopenharmony_ci#define XIRCREG40_TMASK1 15 /* Transmit Mask Register 0 */ 20062306a36Sopenharmony_ci#define XIRCREG42_SWC0 8 /* Software Configuration 0 */ 20162306a36Sopenharmony_ci#define XIRCREG42_SWC1 9 /* Software Configuration 1 */ 20262306a36Sopenharmony_ci#define XIRCREG42_BOC 10 /* Back-Off Configuration */ 20362306a36Sopenharmony_ci#define XIRCREG44_TDR0 8 /* Time Domain Reflectometry 0 */ 20462306a36Sopenharmony_ci#define XIRCREG44_TDR1 9 /* Time Domain Reflectometry 1 */ 20562306a36Sopenharmony_ci#define XIRCREG44_RXBC_LO 10 /* Rx Byte Count 0 (rd) */ 20662306a36Sopenharmony_ci#define XIRCREG44_RXBC_HI 11 /* Rx Byte Count 1 (rd) */ 20762306a36Sopenharmony_ci#define XIRCREG45_REV 15 /* Revision Register (rd) */ 20862306a36Sopenharmony_ci#define XIRCREG50_IA 8 /* Individual Address (8-13) */ 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_cistatic const char *if_names[] = { "Auto", "10BaseT", "10Base2", "AUI", "100BaseT" }; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci/* card types */ 21362306a36Sopenharmony_ci#define XIR_UNKNOWN 0 /* unknown: not supported */ 21462306a36Sopenharmony_ci#define XIR_CE 1 /* (prodid 1) different hardware: not supported */ 21562306a36Sopenharmony_ci#define XIR_CE2 2 /* (prodid 2) */ 21662306a36Sopenharmony_ci#define XIR_CE3 3 /* (prodid 3) */ 21762306a36Sopenharmony_ci#define XIR_CEM 4 /* (prodid 1) different hardware: not supported */ 21862306a36Sopenharmony_ci#define XIR_CEM2 5 /* (prodid 2) */ 21962306a36Sopenharmony_ci#define XIR_CEM3 6 /* (prodid 3) */ 22062306a36Sopenharmony_ci#define XIR_CEM33 7 /* (prodid 4) */ 22162306a36Sopenharmony_ci#define XIR_CEM56M 8 /* (prodid 5) */ 22262306a36Sopenharmony_ci#define XIR_CEM56 9 /* (prodid 6) */ 22362306a36Sopenharmony_ci#define XIR_CM28 10 /* (prodid 3) modem only: not supported here */ 22462306a36Sopenharmony_ci#define XIR_CM33 11 /* (prodid 4) modem only: not supported here */ 22562306a36Sopenharmony_ci#define XIR_CM56 12 /* (prodid 5) modem only: not supported here */ 22662306a36Sopenharmony_ci#define XIR_CG 13 /* (prodid 1) GSM modem only: not supported */ 22762306a36Sopenharmony_ci#define XIR_CBE 14 /* (prodid 1) cardbus ethernet: not supported */ 22862306a36Sopenharmony_ci/*====================================================================*/ 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci/* Module parameters */ 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ciMODULE_DESCRIPTION("Xircom PCMCIA ethernet driver"); 23362306a36Sopenharmony_ciMODULE_LICENSE("Dual MPL/GPL"); 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0) 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ciINT_MODULE_PARM(if_port, 0); 23862306a36Sopenharmony_ciINT_MODULE_PARM(full_duplex, 0); 23962306a36Sopenharmony_ciINT_MODULE_PARM(do_sound, 1); 24062306a36Sopenharmony_ciINT_MODULE_PARM(lockup_hack, 0); /* anti lockup hack */ 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci/*====================================================================*/ 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci/* We do not process more than these number of bytes during one 24562306a36Sopenharmony_ci * interrupt. (Of course we receive complete packets, so this is not 24662306a36Sopenharmony_ci * an exact value). 24762306a36Sopenharmony_ci * Something between 2000..22000; first value gives best interrupt latency, 24862306a36Sopenharmony_ci * the second enables the usage of the complete on-chip buffer. We use the 24962306a36Sopenharmony_ci * high value as the initial value. 25062306a36Sopenharmony_ci */ 25162306a36Sopenharmony_cistatic unsigned maxrx_bytes = 22000; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci/* MII management prototypes */ 25462306a36Sopenharmony_cistatic void mii_idle(unsigned int ioaddr); 25562306a36Sopenharmony_cistatic void mii_putbit(unsigned int ioaddr, unsigned data); 25662306a36Sopenharmony_cistatic int mii_getbit(unsigned int ioaddr); 25762306a36Sopenharmony_cistatic void mii_wbits(unsigned int ioaddr, unsigned data, int len); 25862306a36Sopenharmony_cistatic unsigned mii_rd(unsigned int ioaddr, u_char phyaddr, u_char phyreg); 25962306a36Sopenharmony_cistatic void mii_wr(unsigned int ioaddr, u_char phyaddr, u_char phyreg, 26062306a36Sopenharmony_ci unsigned data, int len); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_cistatic int has_ce2_string(struct pcmcia_device * link); 26362306a36Sopenharmony_cistatic int xirc2ps_config(struct pcmcia_device * link); 26462306a36Sopenharmony_cistatic void xirc2ps_release(struct pcmcia_device * link); 26562306a36Sopenharmony_cistatic void xirc2ps_detach(struct pcmcia_device *p_dev); 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_cistatic irqreturn_t xirc2ps_interrupt(int irq, void *dev_id); 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_cistruct local_info { 27062306a36Sopenharmony_ci struct net_device *dev; 27162306a36Sopenharmony_ci struct pcmcia_device *p_dev; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci int card_type; 27462306a36Sopenharmony_ci int probe_port; 27562306a36Sopenharmony_ci int silicon; /* silicon revision. 0=old CE2, 1=Scipper, 4=Mohawk */ 27662306a36Sopenharmony_ci int mohawk; /* a CE3 type card */ 27762306a36Sopenharmony_ci int dingo; /* a CEM56 type card */ 27862306a36Sopenharmony_ci int new_mii; /* has full 10baseT/100baseT MII */ 27962306a36Sopenharmony_ci int modem; /* is a multi function card (i.e with a modem) */ 28062306a36Sopenharmony_ci void __iomem *dingo_ccr; /* only used for CEM56 cards */ 28162306a36Sopenharmony_ci unsigned last_ptr_value; /* last packets transmitted value */ 28262306a36Sopenharmony_ci const char *manf_str; 28362306a36Sopenharmony_ci struct work_struct tx_timeout_task; 28462306a36Sopenharmony_ci}; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci/**************** 28762306a36Sopenharmony_ci * Some more prototypes 28862306a36Sopenharmony_ci */ 28962306a36Sopenharmony_cistatic netdev_tx_t do_start_xmit(struct sk_buff *skb, 29062306a36Sopenharmony_ci struct net_device *dev); 29162306a36Sopenharmony_cistatic void xirc_tx_timeout(struct net_device *dev, unsigned int txqueue); 29262306a36Sopenharmony_cistatic void xirc2ps_tx_timeout_task(struct work_struct *work); 29362306a36Sopenharmony_cistatic void set_addresses(struct net_device *dev); 29462306a36Sopenharmony_cistatic void set_multicast_list(struct net_device *dev); 29562306a36Sopenharmony_cistatic int set_card_type(struct pcmcia_device *link); 29662306a36Sopenharmony_cistatic int do_config(struct net_device *dev, struct ifmap *map); 29762306a36Sopenharmony_cistatic int do_open(struct net_device *dev); 29862306a36Sopenharmony_cistatic int do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); 29962306a36Sopenharmony_cistatic const struct ethtool_ops netdev_ethtool_ops; 30062306a36Sopenharmony_cistatic void hardreset(struct net_device *dev); 30162306a36Sopenharmony_cistatic void do_reset(struct net_device *dev, int full); 30262306a36Sopenharmony_cistatic int init_mii(struct net_device *dev); 30362306a36Sopenharmony_cistatic void do_powerdown(struct net_device *dev); 30462306a36Sopenharmony_cistatic int do_stop(struct net_device *dev); 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci/*=============== Helper functions =========================*/ 30762306a36Sopenharmony_ci#define SelectPage(pgnr) outb((pgnr), ioaddr + XIRCREG_PR) 30862306a36Sopenharmony_ci#define GetByte(reg) ((unsigned)inb(ioaddr + (reg))) 30962306a36Sopenharmony_ci#define GetWord(reg) ((unsigned)inw(ioaddr + (reg))) 31062306a36Sopenharmony_ci#define PutByte(reg,value) outb((value), ioaddr+(reg)) 31162306a36Sopenharmony_ci#define PutWord(reg,value) outw((value), ioaddr+(reg)) 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci/*====== Functions used for debugging =================================*/ 31462306a36Sopenharmony_ci#if 0 /* reading regs may change system status */ 31562306a36Sopenharmony_cistatic void 31662306a36Sopenharmony_ciPrintRegisters(struct net_device *dev) 31762306a36Sopenharmony_ci{ 31862306a36Sopenharmony_ci unsigned int ioaddr = dev->base_addr; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci if (pc_debug > 1) { 32162306a36Sopenharmony_ci int i, page; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci printk(KERN_DEBUG pr_fmt("Register common: ")); 32462306a36Sopenharmony_ci for (i = 0; i < 8; i++) 32562306a36Sopenharmony_ci pr_cont(" %2.2x", GetByte(i)); 32662306a36Sopenharmony_ci pr_cont("\n"); 32762306a36Sopenharmony_ci for (page = 0; page <= 8; page++) { 32862306a36Sopenharmony_ci printk(KERN_DEBUG pr_fmt("Register page %2x: "), page); 32962306a36Sopenharmony_ci SelectPage(page); 33062306a36Sopenharmony_ci for (i = 8; i < 16; i++) 33162306a36Sopenharmony_ci pr_cont(" %2.2x", GetByte(i)); 33262306a36Sopenharmony_ci pr_cont("\n"); 33362306a36Sopenharmony_ci } 33462306a36Sopenharmony_ci for (page=0x40 ; page <= 0x5f; page++) { 33562306a36Sopenharmony_ci if (page == 0x43 || (page >= 0x46 && page <= 0x4f) || 33662306a36Sopenharmony_ci (page >= 0x51 && page <=0x5e)) 33762306a36Sopenharmony_ci continue; 33862306a36Sopenharmony_ci printk(KERN_DEBUG pr_fmt("Register page %2x: "), page); 33962306a36Sopenharmony_ci SelectPage(page); 34062306a36Sopenharmony_ci for (i = 8; i < 16; i++) 34162306a36Sopenharmony_ci pr_cont(" %2.2x", GetByte(i)); 34262306a36Sopenharmony_ci pr_cont("\n"); 34362306a36Sopenharmony_ci } 34462306a36Sopenharmony_ci } 34562306a36Sopenharmony_ci} 34662306a36Sopenharmony_ci#endif /* 0 */ 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci/*============== MII Management functions ===============*/ 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci/**************** 35162306a36Sopenharmony_ci * Turn around for read 35262306a36Sopenharmony_ci */ 35362306a36Sopenharmony_cistatic void 35462306a36Sopenharmony_cimii_idle(unsigned int ioaddr) 35562306a36Sopenharmony_ci{ 35662306a36Sopenharmony_ci PutByte(XIRCREG2_GPR2, 0x04|0); /* drive MDCK low */ 35762306a36Sopenharmony_ci udelay(1); 35862306a36Sopenharmony_ci PutByte(XIRCREG2_GPR2, 0x04|1); /* and drive MDCK high */ 35962306a36Sopenharmony_ci udelay(1); 36062306a36Sopenharmony_ci} 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci/**************** 36362306a36Sopenharmony_ci * Write a bit to MDI/O 36462306a36Sopenharmony_ci */ 36562306a36Sopenharmony_cistatic void 36662306a36Sopenharmony_cimii_putbit(unsigned int ioaddr, unsigned data) 36762306a36Sopenharmony_ci{ 36862306a36Sopenharmony_ci #if 1 36962306a36Sopenharmony_ci if (data) { 37062306a36Sopenharmony_ci PutByte(XIRCREG2_GPR2, 0x0c|2|0); /* set MDIO */ 37162306a36Sopenharmony_ci udelay(1); 37262306a36Sopenharmony_ci PutByte(XIRCREG2_GPR2, 0x0c|2|1); /* and drive MDCK high */ 37362306a36Sopenharmony_ci udelay(1); 37462306a36Sopenharmony_ci } else { 37562306a36Sopenharmony_ci PutByte(XIRCREG2_GPR2, 0x0c|0|0); /* clear MDIO */ 37662306a36Sopenharmony_ci udelay(1); 37762306a36Sopenharmony_ci PutByte(XIRCREG2_GPR2, 0x0c|0|1); /* and drive MDCK high */ 37862306a36Sopenharmony_ci udelay(1); 37962306a36Sopenharmony_ci } 38062306a36Sopenharmony_ci #else 38162306a36Sopenharmony_ci if (data) { 38262306a36Sopenharmony_ci PutWord(XIRCREG2_GPR2-1, 0x0e0e); 38362306a36Sopenharmony_ci udelay(1); 38462306a36Sopenharmony_ci PutWord(XIRCREG2_GPR2-1, 0x0f0f); 38562306a36Sopenharmony_ci udelay(1); 38662306a36Sopenharmony_ci } else { 38762306a36Sopenharmony_ci PutWord(XIRCREG2_GPR2-1, 0x0c0c); 38862306a36Sopenharmony_ci udelay(1); 38962306a36Sopenharmony_ci PutWord(XIRCREG2_GPR2-1, 0x0d0d); 39062306a36Sopenharmony_ci udelay(1); 39162306a36Sopenharmony_ci } 39262306a36Sopenharmony_ci #endif 39362306a36Sopenharmony_ci} 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci/**************** 39662306a36Sopenharmony_ci * Get a bit from MDI/O 39762306a36Sopenharmony_ci */ 39862306a36Sopenharmony_cistatic int 39962306a36Sopenharmony_cimii_getbit(unsigned int ioaddr) 40062306a36Sopenharmony_ci{ 40162306a36Sopenharmony_ci unsigned d; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci PutByte(XIRCREG2_GPR2, 4|0); /* drive MDCK low */ 40462306a36Sopenharmony_ci udelay(1); 40562306a36Sopenharmony_ci d = GetByte(XIRCREG2_GPR2); /* read MDIO */ 40662306a36Sopenharmony_ci PutByte(XIRCREG2_GPR2, 4|1); /* drive MDCK high again */ 40762306a36Sopenharmony_ci udelay(1); 40862306a36Sopenharmony_ci return d & 0x20; /* read MDIO */ 40962306a36Sopenharmony_ci} 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_cistatic void 41262306a36Sopenharmony_cimii_wbits(unsigned int ioaddr, unsigned data, int len) 41362306a36Sopenharmony_ci{ 41462306a36Sopenharmony_ci unsigned m = 1 << (len-1); 41562306a36Sopenharmony_ci for (; m; m >>= 1) 41662306a36Sopenharmony_ci mii_putbit(ioaddr, data & m); 41762306a36Sopenharmony_ci} 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_cistatic unsigned 42062306a36Sopenharmony_cimii_rd(unsigned int ioaddr, u_char phyaddr, u_char phyreg) 42162306a36Sopenharmony_ci{ 42262306a36Sopenharmony_ci int i; 42362306a36Sopenharmony_ci unsigned data=0, m; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci SelectPage(2); 42662306a36Sopenharmony_ci for (i=0; i < 32; i++) /* 32 bit preamble */ 42762306a36Sopenharmony_ci mii_putbit(ioaddr, 1); 42862306a36Sopenharmony_ci mii_wbits(ioaddr, 0x06, 4); /* Start and opcode for read */ 42962306a36Sopenharmony_ci mii_wbits(ioaddr, phyaddr, 5); /* PHY address to be accessed */ 43062306a36Sopenharmony_ci mii_wbits(ioaddr, phyreg, 5); /* PHY register to read */ 43162306a36Sopenharmony_ci mii_idle(ioaddr); /* turn around */ 43262306a36Sopenharmony_ci mii_getbit(ioaddr); 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci for (m = 1<<15; m; m >>= 1) 43562306a36Sopenharmony_ci if (mii_getbit(ioaddr)) 43662306a36Sopenharmony_ci data |= m; 43762306a36Sopenharmony_ci mii_idle(ioaddr); 43862306a36Sopenharmony_ci return data; 43962306a36Sopenharmony_ci} 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_cistatic void 44262306a36Sopenharmony_cimii_wr(unsigned int ioaddr, u_char phyaddr, u_char phyreg, unsigned data, 44362306a36Sopenharmony_ci int len) 44462306a36Sopenharmony_ci{ 44562306a36Sopenharmony_ci int i; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci SelectPage(2); 44862306a36Sopenharmony_ci for (i=0; i < 32; i++) /* 32 bit preamble */ 44962306a36Sopenharmony_ci mii_putbit(ioaddr, 1); 45062306a36Sopenharmony_ci mii_wbits(ioaddr, 0x05, 4); /* Start and opcode for write */ 45162306a36Sopenharmony_ci mii_wbits(ioaddr, phyaddr, 5); /* PHY address to be accessed */ 45262306a36Sopenharmony_ci mii_wbits(ioaddr, phyreg, 5); /* PHY Register to write */ 45362306a36Sopenharmony_ci mii_putbit(ioaddr, 1); /* turn around */ 45462306a36Sopenharmony_ci mii_putbit(ioaddr, 0); 45562306a36Sopenharmony_ci mii_wbits(ioaddr, data, len); /* And write the data */ 45662306a36Sopenharmony_ci mii_idle(ioaddr); 45762306a36Sopenharmony_ci} 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci/*============= Main bulk of functions =========================*/ 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_cistatic const struct net_device_ops netdev_ops = { 46262306a36Sopenharmony_ci .ndo_open = do_open, 46362306a36Sopenharmony_ci .ndo_stop = do_stop, 46462306a36Sopenharmony_ci .ndo_start_xmit = do_start_xmit, 46562306a36Sopenharmony_ci .ndo_tx_timeout = xirc_tx_timeout, 46662306a36Sopenharmony_ci .ndo_set_config = do_config, 46762306a36Sopenharmony_ci .ndo_eth_ioctl = do_ioctl, 46862306a36Sopenharmony_ci .ndo_set_rx_mode = set_multicast_list, 46962306a36Sopenharmony_ci .ndo_set_mac_address = eth_mac_addr, 47062306a36Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 47162306a36Sopenharmony_ci}; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_cistatic int 47462306a36Sopenharmony_cixirc2ps_probe(struct pcmcia_device *link) 47562306a36Sopenharmony_ci{ 47662306a36Sopenharmony_ci struct net_device *dev; 47762306a36Sopenharmony_ci struct local_info *local; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci dev_dbg(&link->dev, "attach()\n"); 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci /* Allocate the device structure */ 48262306a36Sopenharmony_ci dev = alloc_etherdev(sizeof(struct local_info)); 48362306a36Sopenharmony_ci if (!dev) 48462306a36Sopenharmony_ci return -ENOMEM; 48562306a36Sopenharmony_ci local = netdev_priv(dev); 48662306a36Sopenharmony_ci local->dev = dev; 48762306a36Sopenharmony_ci local->p_dev = link; 48862306a36Sopenharmony_ci link->priv = dev; 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci /* General socket configuration */ 49162306a36Sopenharmony_ci link->config_index = 1; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci /* Fill in card specific entries */ 49462306a36Sopenharmony_ci dev->netdev_ops = &netdev_ops; 49562306a36Sopenharmony_ci dev->ethtool_ops = &netdev_ethtool_ops; 49662306a36Sopenharmony_ci dev->watchdog_timeo = TX_TIMEOUT; 49762306a36Sopenharmony_ci INIT_WORK(&local->tx_timeout_task, xirc2ps_tx_timeout_task); 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci return xirc2ps_config(link); 50062306a36Sopenharmony_ci} /* xirc2ps_attach */ 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_cistatic void 50362306a36Sopenharmony_cixirc2ps_detach(struct pcmcia_device *link) 50462306a36Sopenharmony_ci{ 50562306a36Sopenharmony_ci struct net_device *dev = link->priv; 50662306a36Sopenharmony_ci struct local_info *local = netdev_priv(dev); 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci netif_carrier_off(dev); 50962306a36Sopenharmony_ci netif_tx_disable(dev); 51062306a36Sopenharmony_ci cancel_work_sync(&local->tx_timeout_task); 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci dev_dbg(&link->dev, "detach\n"); 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci unregister_netdev(dev); 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci xirc2ps_release(link); 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci free_netdev(dev); 51962306a36Sopenharmony_ci} /* xirc2ps_detach */ 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci/**************** 52262306a36Sopenharmony_ci * Detect the type of the card. s is the buffer with the data of tuple 0x20 52362306a36Sopenharmony_ci * Returns: 0 := not supported 52462306a36Sopenharmony_ci * mediaid=11 and prodid=47 52562306a36Sopenharmony_ci * Media-Id bits: 52662306a36Sopenharmony_ci * Ethernet 0x01 52762306a36Sopenharmony_ci * Tokenring 0x02 52862306a36Sopenharmony_ci * Arcnet 0x04 52962306a36Sopenharmony_ci * Wireless 0x08 53062306a36Sopenharmony_ci * Modem 0x10 53162306a36Sopenharmony_ci * GSM only 0x20 53262306a36Sopenharmony_ci * Prod-Id bits: 53362306a36Sopenharmony_ci * Pocket 0x10 53462306a36Sopenharmony_ci * External 0x20 53562306a36Sopenharmony_ci * Creditcard 0x40 53662306a36Sopenharmony_ci * Cardbus 0x80 53762306a36Sopenharmony_ci * 53862306a36Sopenharmony_ci */ 53962306a36Sopenharmony_cistatic int 54062306a36Sopenharmony_ciset_card_type(struct pcmcia_device *link) 54162306a36Sopenharmony_ci{ 54262306a36Sopenharmony_ci struct net_device *dev = link->priv; 54362306a36Sopenharmony_ci struct local_info *local = netdev_priv(dev); 54462306a36Sopenharmony_ci u8 *buf; 54562306a36Sopenharmony_ci unsigned int cisrev, mediaid, prodid; 54662306a36Sopenharmony_ci size_t len; 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci len = pcmcia_get_tuple(link, CISTPL_MANFID, &buf); 54962306a36Sopenharmony_ci if (len < 5) { 55062306a36Sopenharmony_ci dev_err(&link->dev, "invalid CIS -- sorry\n"); 55162306a36Sopenharmony_ci return 0; 55262306a36Sopenharmony_ci } 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci cisrev = buf[2]; 55562306a36Sopenharmony_ci mediaid = buf[3]; 55662306a36Sopenharmony_ci prodid = buf[4]; 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci dev_dbg(&link->dev, "cisrev=%02x mediaid=%02x prodid=%02x\n", 55962306a36Sopenharmony_ci cisrev, mediaid, prodid); 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci local->mohawk = 0; 56262306a36Sopenharmony_ci local->dingo = 0; 56362306a36Sopenharmony_ci local->modem = 0; 56462306a36Sopenharmony_ci local->card_type = XIR_UNKNOWN; 56562306a36Sopenharmony_ci if (!(prodid & 0x40)) { 56662306a36Sopenharmony_ci pr_notice("Oops: Not a creditcard\n"); 56762306a36Sopenharmony_ci return 0; 56862306a36Sopenharmony_ci } 56962306a36Sopenharmony_ci if (!(mediaid & 0x01)) { 57062306a36Sopenharmony_ci pr_notice("Not an Ethernet card\n"); 57162306a36Sopenharmony_ci return 0; 57262306a36Sopenharmony_ci } 57362306a36Sopenharmony_ci if (mediaid & 0x10) { 57462306a36Sopenharmony_ci local->modem = 1; 57562306a36Sopenharmony_ci switch(prodid & 15) { 57662306a36Sopenharmony_ci case 1: local->card_type = XIR_CEM ; break; 57762306a36Sopenharmony_ci case 2: local->card_type = XIR_CEM2 ; break; 57862306a36Sopenharmony_ci case 3: local->card_type = XIR_CEM3 ; break; 57962306a36Sopenharmony_ci case 4: local->card_type = XIR_CEM33 ; break; 58062306a36Sopenharmony_ci case 5: local->card_type = XIR_CEM56M; 58162306a36Sopenharmony_ci local->mohawk = 1; 58262306a36Sopenharmony_ci break; 58362306a36Sopenharmony_ci case 6: 58462306a36Sopenharmony_ci case 7: /* 7 is the RealPort 10/56 */ 58562306a36Sopenharmony_ci local->card_type = XIR_CEM56 ; 58662306a36Sopenharmony_ci local->mohawk = 1; 58762306a36Sopenharmony_ci local->dingo = 1; 58862306a36Sopenharmony_ci break; 58962306a36Sopenharmony_ci } 59062306a36Sopenharmony_ci } else { 59162306a36Sopenharmony_ci switch(prodid & 15) { 59262306a36Sopenharmony_ci case 1: local->card_type = has_ce2_string(link)? XIR_CE2 : XIR_CE ; 59362306a36Sopenharmony_ci break; 59462306a36Sopenharmony_ci case 2: local->card_type = XIR_CE2; break; 59562306a36Sopenharmony_ci case 3: local->card_type = XIR_CE3; 59662306a36Sopenharmony_ci local->mohawk = 1; 59762306a36Sopenharmony_ci break; 59862306a36Sopenharmony_ci } 59962306a36Sopenharmony_ci } 60062306a36Sopenharmony_ci if (local->card_type == XIR_CE || local->card_type == XIR_CEM) { 60162306a36Sopenharmony_ci pr_notice("Sorry, this is an old CE card\n"); 60262306a36Sopenharmony_ci return 0; 60362306a36Sopenharmony_ci } 60462306a36Sopenharmony_ci if (local->card_type == XIR_UNKNOWN) 60562306a36Sopenharmony_ci pr_notice("unknown card (mediaid=%02x prodid=%02x)\n", mediaid, prodid); 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci return 1; 60862306a36Sopenharmony_ci} 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci/**************** 61162306a36Sopenharmony_ci * There are some CE2 cards out which claim to be a CE card. 61262306a36Sopenharmony_ci * This function looks for a "CE2" in the 3rd version field. 61362306a36Sopenharmony_ci * Returns: true if this is a CE2 61462306a36Sopenharmony_ci */ 61562306a36Sopenharmony_cistatic int 61662306a36Sopenharmony_cihas_ce2_string(struct pcmcia_device * p_dev) 61762306a36Sopenharmony_ci{ 61862306a36Sopenharmony_ci if (p_dev->prod_id[2] && strstr(p_dev->prod_id[2], "CE2")) 61962306a36Sopenharmony_ci return 1; 62062306a36Sopenharmony_ci return 0; 62162306a36Sopenharmony_ci} 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_cistatic int 62462306a36Sopenharmony_cixirc2ps_config_modem(struct pcmcia_device *p_dev, void *priv_data) 62562306a36Sopenharmony_ci{ 62662306a36Sopenharmony_ci unsigned int ioaddr; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci if ((p_dev->resource[0]->start & 0xf) == 8) 62962306a36Sopenharmony_ci return -ENODEV; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci p_dev->resource[0]->end = 16; 63262306a36Sopenharmony_ci p_dev->resource[1]->end = 8; 63362306a36Sopenharmony_ci p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; 63462306a36Sopenharmony_ci p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_16; 63562306a36Sopenharmony_ci p_dev->resource[1]->flags &= ~IO_DATA_PATH_WIDTH; 63662306a36Sopenharmony_ci p_dev->resource[1]->flags |= IO_DATA_PATH_WIDTH_8; 63762306a36Sopenharmony_ci p_dev->io_lines = 10; 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci p_dev->resource[1]->start = p_dev->resource[0]->start; 64062306a36Sopenharmony_ci for (ioaddr = 0x300; ioaddr < 0x400; ioaddr += 0x10) { 64162306a36Sopenharmony_ci p_dev->resource[0]->start = ioaddr; 64262306a36Sopenharmony_ci if (!pcmcia_request_io(p_dev)) 64362306a36Sopenharmony_ci return 0; 64462306a36Sopenharmony_ci } 64562306a36Sopenharmony_ci return -ENODEV; 64662306a36Sopenharmony_ci} 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_cistatic int 64962306a36Sopenharmony_cixirc2ps_config_check(struct pcmcia_device *p_dev, void *priv_data) 65062306a36Sopenharmony_ci{ 65162306a36Sopenharmony_ci int *pass = priv_data; 65262306a36Sopenharmony_ci resource_size_t tmp = p_dev->resource[1]->start; 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci tmp += (*pass ? (p_dev->config_index & 0x20 ? -24 : 8) 65562306a36Sopenharmony_ci : (p_dev->config_index & 0x20 ? 8 : -24)); 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci if ((p_dev->resource[0]->start & 0xf) == 8) 65862306a36Sopenharmony_ci return -ENODEV; 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci p_dev->resource[0]->end = 18; 66162306a36Sopenharmony_ci p_dev->resource[1]->end = 8; 66262306a36Sopenharmony_ci p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; 66362306a36Sopenharmony_ci p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_16; 66462306a36Sopenharmony_ci p_dev->resource[1]->flags &= ~IO_DATA_PATH_WIDTH; 66562306a36Sopenharmony_ci p_dev->resource[1]->flags |= IO_DATA_PATH_WIDTH_8; 66662306a36Sopenharmony_ci p_dev->io_lines = 10; 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci p_dev->resource[1]->start = p_dev->resource[0]->start; 66962306a36Sopenharmony_ci p_dev->resource[0]->start = tmp; 67062306a36Sopenharmony_ci return pcmcia_request_io(p_dev); 67162306a36Sopenharmony_ci} 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_cistatic int pcmcia_get_mac_ce(struct pcmcia_device *p_dev, 67562306a36Sopenharmony_ci tuple_t *tuple, 67662306a36Sopenharmony_ci void *priv) 67762306a36Sopenharmony_ci{ 67862306a36Sopenharmony_ci struct net_device *dev = priv; 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci if (tuple->TupleDataLen != 13) 68162306a36Sopenharmony_ci return -EINVAL; 68262306a36Sopenharmony_ci if ((tuple->TupleData[0] != 2) || (tuple->TupleData[1] != 1) || 68362306a36Sopenharmony_ci (tuple->TupleData[2] != 6)) 68462306a36Sopenharmony_ci return -EINVAL; 68562306a36Sopenharmony_ci /* another try (James Lehmer's CE2 version 4.1)*/ 68662306a36Sopenharmony_ci dev_addr_mod(dev, 2, &tuple->TupleData[2], 4); 68762306a36Sopenharmony_ci return 0; 68862306a36Sopenharmony_ci}; 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_cistatic int 69262306a36Sopenharmony_cixirc2ps_config(struct pcmcia_device * link) 69362306a36Sopenharmony_ci{ 69462306a36Sopenharmony_ci struct net_device *dev = link->priv; 69562306a36Sopenharmony_ci struct local_info *local = netdev_priv(dev); 69662306a36Sopenharmony_ci unsigned int ioaddr; 69762306a36Sopenharmony_ci int err; 69862306a36Sopenharmony_ci u8 *buf; 69962306a36Sopenharmony_ci size_t len; 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci local->dingo_ccr = NULL; 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci dev_dbg(&link->dev, "config\n"); 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci /* Is this a valid card */ 70662306a36Sopenharmony_ci if (link->has_manf_id == 0) { 70762306a36Sopenharmony_ci pr_notice("manfid not found in CIS\n"); 70862306a36Sopenharmony_ci goto failure; 70962306a36Sopenharmony_ci } 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci switch (link->manf_id) { 71262306a36Sopenharmony_ci case MANFID_XIRCOM: 71362306a36Sopenharmony_ci local->manf_str = "Xircom"; 71462306a36Sopenharmony_ci break; 71562306a36Sopenharmony_ci case MANFID_ACCTON: 71662306a36Sopenharmony_ci local->manf_str = "Accton"; 71762306a36Sopenharmony_ci break; 71862306a36Sopenharmony_ci case MANFID_COMPAQ: 71962306a36Sopenharmony_ci case MANFID_COMPAQ2: 72062306a36Sopenharmony_ci local->manf_str = "Compaq"; 72162306a36Sopenharmony_ci break; 72262306a36Sopenharmony_ci case MANFID_INTEL: 72362306a36Sopenharmony_ci local->manf_str = "Intel"; 72462306a36Sopenharmony_ci break; 72562306a36Sopenharmony_ci case MANFID_TOSHIBA: 72662306a36Sopenharmony_ci local->manf_str = "Toshiba"; 72762306a36Sopenharmony_ci break; 72862306a36Sopenharmony_ci default: 72962306a36Sopenharmony_ci pr_notice("Unknown Card Manufacturer ID: 0x%04x\n", 73062306a36Sopenharmony_ci (unsigned)link->manf_id); 73162306a36Sopenharmony_ci goto failure; 73262306a36Sopenharmony_ci } 73362306a36Sopenharmony_ci dev_dbg(&link->dev, "found %s card\n", local->manf_str); 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci if (!set_card_type(link)) { 73662306a36Sopenharmony_ci pr_notice("this card is not supported\n"); 73762306a36Sopenharmony_ci goto failure; 73862306a36Sopenharmony_ci } 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci /* get the ethernet address from the CIS */ 74162306a36Sopenharmony_ci err = pcmcia_get_mac_from_cis(link, dev); 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci /* not found: try to get the node-id from tuple 0x89 */ 74462306a36Sopenharmony_ci if (err) { 74562306a36Sopenharmony_ci len = pcmcia_get_tuple(link, 0x89, &buf); 74662306a36Sopenharmony_ci /* data layout looks like tuple 0x22 */ 74762306a36Sopenharmony_ci if (buf && len == 8) { 74862306a36Sopenharmony_ci if (*buf == CISTPL_FUNCE_LAN_NODE_ID) 74962306a36Sopenharmony_ci dev_addr_mod(dev, 2, &buf[2], 4); 75062306a36Sopenharmony_ci else 75162306a36Sopenharmony_ci err = -1; 75262306a36Sopenharmony_ci } 75362306a36Sopenharmony_ci kfree(buf); 75462306a36Sopenharmony_ci } 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci if (err) 75762306a36Sopenharmony_ci err = pcmcia_loop_tuple(link, CISTPL_FUNCE, pcmcia_get_mac_ce, dev); 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci if (err) { 76062306a36Sopenharmony_ci pr_notice("node-id not found in CIS\n"); 76162306a36Sopenharmony_ci goto failure; 76262306a36Sopenharmony_ci } 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci if (local->modem) { 76562306a36Sopenharmony_ci int pass; 76662306a36Sopenharmony_ci link->config_flags |= CONF_AUTO_SET_IO; 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci if (local->dingo) { 76962306a36Sopenharmony_ci /* Take the Modem IO port from the CIS and scan for a free 77062306a36Sopenharmony_ci * Ethernet port */ 77162306a36Sopenharmony_ci if (!pcmcia_loop_config(link, xirc2ps_config_modem, NULL)) 77262306a36Sopenharmony_ci goto port_found; 77362306a36Sopenharmony_ci } else { 77462306a36Sopenharmony_ci /* We do 2 passes here: The first one uses the regular mapping and 77562306a36Sopenharmony_ci * the second tries again, thereby considering that the 32 ports are 77662306a36Sopenharmony_ci * mirrored every 32 bytes. Actually we use a mirrored port for 77762306a36Sopenharmony_ci * the Mako if (on the first pass) the COR bit 5 is set. 77862306a36Sopenharmony_ci */ 77962306a36Sopenharmony_ci for (pass=0; pass < 2; pass++) 78062306a36Sopenharmony_ci if (!pcmcia_loop_config(link, xirc2ps_config_check, 78162306a36Sopenharmony_ci &pass)) 78262306a36Sopenharmony_ci goto port_found; 78362306a36Sopenharmony_ci /* if special option: 78462306a36Sopenharmony_ci * try to configure as Ethernet only. 78562306a36Sopenharmony_ci * .... */ 78662306a36Sopenharmony_ci } 78762306a36Sopenharmony_ci pr_notice("no ports available\n"); 78862306a36Sopenharmony_ci } else { 78962306a36Sopenharmony_ci link->io_lines = 10; 79062306a36Sopenharmony_ci link->resource[0]->end = 16; 79162306a36Sopenharmony_ci link->resource[0]->flags |= IO_DATA_PATH_WIDTH_16; 79262306a36Sopenharmony_ci for (ioaddr = 0x300; ioaddr < 0x400; ioaddr += 0x10) { 79362306a36Sopenharmony_ci link->resource[0]->start = ioaddr; 79462306a36Sopenharmony_ci if (!(err = pcmcia_request_io(link))) 79562306a36Sopenharmony_ci goto port_found; 79662306a36Sopenharmony_ci } 79762306a36Sopenharmony_ci link->resource[0]->start = 0; /* let CS decide */ 79862306a36Sopenharmony_ci if ((err = pcmcia_request_io(link))) 79962306a36Sopenharmony_ci goto config_error; 80062306a36Sopenharmony_ci } 80162306a36Sopenharmony_ci port_found: 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci /**************** 80462306a36Sopenharmony_ci * Now allocate an interrupt line. Note that this does not 80562306a36Sopenharmony_ci * actually assign a handler to the interrupt. 80662306a36Sopenharmony_ci */ 80762306a36Sopenharmony_ci if ((err=pcmcia_request_irq(link, xirc2ps_interrupt))) 80862306a36Sopenharmony_ci goto config_error; 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci link->config_flags |= CONF_ENABLE_IRQ; 81162306a36Sopenharmony_ci if (do_sound) 81262306a36Sopenharmony_ci link->config_flags |= CONF_ENABLE_SPKR; 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci if ((err = pcmcia_enable_device(link))) 81562306a36Sopenharmony_ci goto config_error; 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci if (local->dingo) { 81862306a36Sopenharmony_ci /* Reset the modem's BAR to the correct value 81962306a36Sopenharmony_ci * This is necessary because in the RequestConfiguration call, 82062306a36Sopenharmony_ci * the base address of the ethernet port (BasePort1) is written 82162306a36Sopenharmony_ci * to the BAR registers of the modem. 82262306a36Sopenharmony_ci */ 82362306a36Sopenharmony_ci err = pcmcia_write_config_byte(link, CISREG_IOBASE_0, (u8) 82462306a36Sopenharmony_ci link->resource[1]->start & 0xff); 82562306a36Sopenharmony_ci if (err) 82662306a36Sopenharmony_ci goto config_error; 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci err = pcmcia_write_config_byte(link, CISREG_IOBASE_1, 82962306a36Sopenharmony_ci (link->resource[1]->start >> 8) & 0xff); 83062306a36Sopenharmony_ci if (err) 83162306a36Sopenharmony_ci goto config_error; 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci /* There is no config entry for the Ethernet part which 83462306a36Sopenharmony_ci * is at 0x0800. So we allocate a window into the attribute 83562306a36Sopenharmony_ci * memory and write direct to the CIS registers 83662306a36Sopenharmony_ci */ 83762306a36Sopenharmony_ci link->resource[2]->flags = WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_AM | 83862306a36Sopenharmony_ci WIN_ENABLE; 83962306a36Sopenharmony_ci link->resource[2]->start = link->resource[2]->end = 0; 84062306a36Sopenharmony_ci if ((err = pcmcia_request_window(link, link->resource[2], 0))) 84162306a36Sopenharmony_ci goto config_error; 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci local->dingo_ccr = ioremap(link->resource[2]->start, 0x1000) + 0x0800; 84462306a36Sopenharmony_ci if ((err = pcmcia_map_mem_page(link, link->resource[2], 0))) 84562306a36Sopenharmony_ci goto config_error; 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci /* Setup the CCRs; there are no infos in the CIS about the Ethernet 84862306a36Sopenharmony_ci * part. 84962306a36Sopenharmony_ci */ 85062306a36Sopenharmony_ci writeb(0x47, local->dingo_ccr + CISREG_COR); 85162306a36Sopenharmony_ci ioaddr = link->resource[0]->start; 85262306a36Sopenharmony_ci writeb(ioaddr & 0xff , local->dingo_ccr + CISREG_IOBASE_0); 85362306a36Sopenharmony_ci writeb((ioaddr >> 8)&0xff , local->dingo_ccr + CISREG_IOBASE_1); 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci #if 0 85662306a36Sopenharmony_ci { 85762306a36Sopenharmony_ci u_char tmp; 85862306a36Sopenharmony_ci pr_info("ECOR:"); 85962306a36Sopenharmony_ci for (i=0; i < 7; i++) { 86062306a36Sopenharmony_ci tmp = readb(local->dingo_ccr + i*2); 86162306a36Sopenharmony_ci pr_cont(" %02x", tmp); 86262306a36Sopenharmony_ci } 86362306a36Sopenharmony_ci pr_cont("\n"); 86462306a36Sopenharmony_ci pr_info("DCOR:"); 86562306a36Sopenharmony_ci for (i=0; i < 4; i++) { 86662306a36Sopenharmony_ci tmp = readb(local->dingo_ccr + 0x20 + i*2); 86762306a36Sopenharmony_ci pr_cont(" %02x", tmp); 86862306a36Sopenharmony_ci } 86962306a36Sopenharmony_ci pr_cont("\n"); 87062306a36Sopenharmony_ci pr_info("SCOR:"); 87162306a36Sopenharmony_ci for (i=0; i < 10; i++) { 87262306a36Sopenharmony_ci tmp = readb(local->dingo_ccr + 0x40 + i*2); 87362306a36Sopenharmony_ci pr_cont(" %02x", tmp); 87462306a36Sopenharmony_ci } 87562306a36Sopenharmony_ci pr_cont("\n"); 87662306a36Sopenharmony_ci } 87762306a36Sopenharmony_ci #endif 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci writeb(0x01, local->dingo_ccr + 0x20); 88062306a36Sopenharmony_ci writeb(0x0c, local->dingo_ccr + 0x22); 88162306a36Sopenharmony_ci writeb(0x00, local->dingo_ccr + 0x24); 88262306a36Sopenharmony_ci writeb(0x00, local->dingo_ccr + 0x26); 88362306a36Sopenharmony_ci writeb(0x00, local->dingo_ccr + 0x28); 88462306a36Sopenharmony_ci } 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci /* The if_port symbol can be set when the module is loaded */ 88762306a36Sopenharmony_ci local->probe_port=0; 88862306a36Sopenharmony_ci if (!if_port) { 88962306a36Sopenharmony_ci local->probe_port = dev->if_port = 1; 89062306a36Sopenharmony_ci } else if ((if_port >= 1 && if_port <= 2) || 89162306a36Sopenharmony_ci (local->mohawk && if_port==4)) 89262306a36Sopenharmony_ci dev->if_port = if_port; 89362306a36Sopenharmony_ci else 89462306a36Sopenharmony_ci pr_notice("invalid if_port requested\n"); 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci /* we can now register the device with the net subsystem */ 89762306a36Sopenharmony_ci dev->irq = link->irq; 89862306a36Sopenharmony_ci dev->base_addr = link->resource[0]->start; 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci if (local->dingo) 90162306a36Sopenharmony_ci do_reset(dev, 1); /* a kludge to make the cem56 work */ 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci SET_NETDEV_DEV(dev, &link->dev); 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci if ((err=register_netdev(dev))) { 90662306a36Sopenharmony_ci pr_notice("register_netdev() failed\n"); 90762306a36Sopenharmony_ci goto config_error; 90862306a36Sopenharmony_ci } 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci /* give some infos about the hardware */ 91162306a36Sopenharmony_ci netdev_info(dev, "%s: port %#3lx, irq %d, hwaddr %pM\n", 91262306a36Sopenharmony_ci local->manf_str, (u_long)dev->base_addr, (int)dev->irq, 91362306a36Sopenharmony_ci dev->dev_addr); 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci return 0; 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci config_error: 91862306a36Sopenharmony_ci xirc2ps_release(link); 91962306a36Sopenharmony_ci return -ENODEV; 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci failure: 92262306a36Sopenharmony_ci return -ENODEV; 92362306a36Sopenharmony_ci} /* xirc2ps_config */ 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_cistatic void 92662306a36Sopenharmony_cixirc2ps_release(struct pcmcia_device *link) 92762306a36Sopenharmony_ci{ 92862306a36Sopenharmony_ci dev_dbg(&link->dev, "release\n"); 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci if (link->resource[2]->end) { 93162306a36Sopenharmony_ci struct net_device *dev = link->priv; 93262306a36Sopenharmony_ci struct local_info *local = netdev_priv(dev); 93362306a36Sopenharmony_ci if (local->dingo) 93462306a36Sopenharmony_ci iounmap(local->dingo_ccr - 0x0800); 93562306a36Sopenharmony_ci } 93662306a36Sopenharmony_ci pcmcia_disable_device(link); 93762306a36Sopenharmony_ci} /* xirc2ps_release */ 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci/*====================================================================*/ 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_cistatic int xirc2ps_suspend(struct pcmcia_device *link) 94362306a36Sopenharmony_ci{ 94462306a36Sopenharmony_ci struct net_device *dev = link->priv; 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci if (link->open) { 94762306a36Sopenharmony_ci netif_device_detach(dev); 94862306a36Sopenharmony_ci do_powerdown(dev); 94962306a36Sopenharmony_ci } 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci return 0; 95262306a36Sopenharmony_ci} 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_cistatic int xirc2ps_resume(struct pcmcia_device *link) 95562306a36Sopenharmony_ci{ 95662306a36Sopenharmony_ci struct net_device *dev = link->priv; 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci if (link->open) { 95962306a36Sopenharmony_ci do_reset(dev,1); 96062306a36Sopenharmony_ci netif_device_attach(dev); 96162306a36Sopenharmony_ci } 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci return 0; 96462306a36Sopenharmony_ci} 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ci/*====================================================================*/ 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci/**************** 97062306a36Sopenharmony_ci * This is the Interrupt service route. 97162306a36Sopenharmony_ci */ 97262306a36Sopenharmony_cistatic irqreturn_t 97362306a36Sopenharmony_cixirc2ps_interrupt(int irq, void *dev_id) 97462306a36Sopenharmony_ci{ 97562306a36Sopenharmony_ci struct net_device *dev = (struct net_device *)dev_id; 97662306a36Sopenharmony_ci struct local_info *lp = netdev_priv(dev); 97762306a36Sopenharmony_ci unsigned int ioaddr; 97862306a36Sopenharmony_ci u_char saved_page; 97962306a36Sopenharmony_ci unsigned bytes_rcvd; 98062306a36Sopenharmony_ci unsigned int_status, eth_status, rx_status, tx_status; 98162306a36Sopenharmony_ci unsigned rsr, pktlen; 98262306a36Sopenharmony_ci ulong start_ticks = jiffies; /* fixme: jiffies rollover every 497 days 98362306a36Sopenharmony_ci * is this something to worry about? 98462306a36Sopenharmony_ci * -- on a laptop? 98562306a36Sopenharmony_ci */ 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci if (!netif_device_present(dev)) 98862306a36Sopenharmony_ci return IRQ_HANDLED; 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci ioaddr = dev->base_addr; 99162306a36Sopenharmony_ci if (lp->mohawk) { /* must disable the interrupt */ 99262306a36Sopenharmony_ci PutByte(XIRCREG_CR, 0); 99362306a36Sopenharmony_ci } 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci pr_debug("%s: interrupt %d at %#x.\n", dev->name, irq, ioaddr); 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci saved_page = GetByte(XIRCREG_PR); 99862306a36Sopenharmony_ci /* Read the ISR to see whats the cause for the interrupt. 99962306a36Sopenharmony_ci * This also clears the interrupt flags on CE2 cards 100062306a36Sopenharmony_ci */ 100162306a36Sopenharmony_ci int_status = GetByte(XIRCREG_ISR); 100262306a36Sopenharmony_ci bytes_rcvd = 0; 100362306a36Sopenharmony_ci loop_entry: 100462306a36Sopenharmony_ci if (int_status == 0xff) { /* card may be ejected */ 100562306a36Sopenharmony_ci pr_debug("%s: interrupt %d for dead card\n", dev->name, irq); 100662306a36Sopenharmony_ci goto leave; 100762306a36Sopenharmony_ci } 100862306a36Sopenharmony_ci eth_status = GetByte(XIRCREG_ESR); 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci SelectPage(0x40); 101162306a36Sopenharmony_ci rx_status = GetByte(XIRCREG40_RXST0); 101262306a36Sopenharmony_ci PutByte(XIRCREG40_RXST0, (~rx_status & 0xff)); 101362306a36Sopenharmony_ci tx_status = GetByte(XIRCREG40_TXST0); 101462306a36Sopenharmony_ci tx_status |= GetByte(XIRCREG40_TXST1) << 8; 101562306a36Sopenharmony_ci PutByte(XIRCREG40_TXST0, 0); 101662306a36Sopenharmony_ci PutByte(XIRCREG40_TXST1, 0); 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci pr_debug("%s: ISR=%#2.2x ESR=%#2.2x RSR=%#2.2x TSR=%#4.4x\n", 101962306a36Sopenharmony_ci dev->name, int_status, eth_status, rx_status, tx_status); 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci /***** receive section ******/ 102262306a36Sopenharmony_ci SelectPage(0); 102362306a36Sopenharmony_ci while (eth_status & FullPktRcvd) { 102462306a36Sopenharmony_ci rsr = GetByte(XIRCREG0_RSR); 102562306a36Sopenharmony_ci if (bytes_rcvd > maxrx_bytes && (rsr & PktRxOk)) { 102662306a36Sopenharmony_ci /* too many bytes received during this int, drop the rest of the 102762306a36Sopenharmony_ci * packets */ 102862306a36Sopenharmony_ci dev->stats.rx_dropped++; 102962306a36Sopenharmony_ci pr_debug("%s: RX drop, too much done\n", dev->name); 103062306a36Sopenharmony_ci } else if (rsr & PktRxOk) { 103162306a36Sopenharmony_ci struct sk_buff *skb; 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci pktlen = GetWord(XIRCREG0_RBC); 103462306a36Sopenharmony_ci bytes_rcvd += pktlen; 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ci pr_debug("rsr=%#02x packet_length=%u\n", rsr, pktlen); 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_ci /* 1 extra so we can use insw */ 103962306a36Sopenharmony_ci skb = netdev_alloc_skb(dev, pktlen + 3); 104062306a36Sopenharmony_ci if (!skb) { 104162306a36Sopenharmony_ci dev->stats.rx_dropped++; 104262306a36Sopenharmony_ci } else { /* okay get the packet */ 104362306a36Sopenharmony_ci skb_reserve(skb, 2); 104462306a36Sopenharmony_ci if (lp->silicon == 0 ) { /* work around a hardware bug */ 104562306a36Sopenharmony_ci unsigned rhsa; /* receive start address */ 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_ci SelectPage(5); 104862306a36Sopenharmony_ci rhsa = GetWord(XIRCREG5_RHSA0); 104962306a36Sopenharmony_ci SelectPage(0); 105062306a36Sopenharmony_ci rhsa += 3; /* skip control infos */ 105162306a36Sopenharmony_ci if (rhsa >= 0x8000) 105262306a36Sopenharmony_ci rhsa = 0; 105362306a36Sopenharmony_ci if (rhsa + pktlen > 0x8000) { 105462306a36Sopenharmony_ci unsigned i; 105562306a36Sopenharmony_ci u_char *buf = skb_put(skb, pktlen); 105662306a36Sopenharmony_ci for (i=0; i < pktlen ; i++, rhsa++) { 105762306a36Sopenharmony_ci buf[i] = GetByte(XIRCREG_EDP); 105862306a36Sopenharmony_ci if (rhsa == 0x8000) { 105962306a36Sopenharmony_ci rhsa = 0; 106062306a36Sopenharmony_ci i--; 106162306a36Sopenharmony_ci } 106262306a36Sopenharmony_ci } 106362306a36Sopenharmony_ci } else { 106462306a36Sopenharmony_ci insw(ioaddr+XIRCREG_EDP, 106562306a36Sopenharmony_ci skb_put(skb, pktlen), (pktlen+1)>>1); 106662306a36Sopenharmony_ci } 106762306a36Sopenharmony_ci } 106862306a36Sopenharmony_ci #if 0 106962306a36Sopenharmony_ci else if (lp->mohawk) { 107062306a36Sopenharmony_ci /* To use this 32 bit access we should use 107162306a36Sopenharmony_ci * a manual optimized loop 107262306a36Sopenharmony_ci * Also the words are swapped, we can get more 107362306a36Sopenharmony_ci * performance by using 32 bit access and swapping 107462306a36Sopenharmony_ci * the words in a register. Will need this for cardbus 107562306a36Sopenharmony_ci * 107662306a36Sopenharmony_ci * Note: don't forget to change the ALLOC_SKB to .. +3 107762306a36Sopenharmony_ci */ 107862306a36Sopenharmony_ci unsigned i; 107962306a36Sopenharmony_ci u_long *p = skb_put(skb, pktlen); 108062306a36Sopenharmony_ci register u_long a; 108162306a36Sopenharmony_ci unsigned int edpreg = ioaddr+XIRCREG_EDP-2; 108262306a36Sopenharmony_ci for (i=0; i < len ; i += 4, p++) { 108362306a36Sopenharmony_ci a = inl(edpreg); 108462306a36Sopenharmony_ci __asm__("rorl $16,%0\n\t" 108562306a36Sopenharmony_ci :"=q" (a) 108662306a36Sopenharmony_ci : "0" (a)); 108762306a36Sopenharmony_ci *p = a; 108862306a36Sopenharmony_ci } 108962306a36Sopenharmony_ci } 109062306a36Sopenharmony_ci #endif 109162306a36Sopenharmony_ci else { 109262306a36Sopenharmony_ci insw(ioaddr+XIRCREG_EDP, skb_put(skb, pktlen), 109362306a36Sopenharmony_ci (pktlen+1)>>1); 109462306a36Sopenharmony_ci } 109562306a36Sopenharmony_ci skb->protocol = eth_type_trans(skb, dev); 109662306a36Sopenharmony_ci netif_rx(skb); 109762306a36Sopenharmony_ci dev->stats.rx_packets++; 109862306a36Sopenharmony_ci dev->stats.rx_bytes += pktlen; 109962306a36Sopenharmony_ci if (!(rsr & PhyPkt)) 110062306a36Sopenharmony_ci dev->stats.multicast++; 110162306a36Sopenharmony_ci } 110262306a36Sopenharmony_ci } else { /* bad packet */ 110362306a36Sopenharmony_ci pr_debug("rsr=%#02x\n", rsr); 110462306a36Sopenharmony_ci } 110562306a36Sopenharmony_ci if (rsr & PktTooLong) { 110662306a36Sopenharmony_ci dev->stats.rx_frame_errors++; 110762306a36Sopenharmony_ci pr_debug("%s: Packet too long\n", dev->name); 110862306a36Sopenharmony_ci } 110962306a36Sopenharmony_ci if (rsr & CRCErr) { 111062306a36Sopenharmony_ci dev->stats.rx_crc_errors++; 111162306a36Sopenharmony_ci pr_debug("%s: CRC error\n", dev->name); 111262306a36Sopenharmony_ci } 111362306a36Sopenharmony_ci if (rsr & AlignErr) { 111462306a36Sopenharmony_ci dev->stats.rx_fifo_errors++; /* okay ? */ 111562306a36Sopenharmony_ci pr_debug("%s: Alignment error\n", dev->name); 111662306a36Sopenharmony_ci } 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci /* clear the received/dropped/error packet */ 111962306a36Sopenharmony_ci PutWord(XIRCREG0_DO, 0x8000); /* issue cmd: skip_rx_packet */ 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci /* get the new ethernet status */ 112262306a36Sopenharmony_ci eth_status = GetByte(XIRCREG_ESR); 112362306a36Sopenharmony_ci } 112462306a36Sopenharmony_ci if (rx_status & 0x10) { /* Receive overrun */ 112562306a36Sopenharmony_ci dev->stats.rx_over_errors++; 112662306a36Sopenharmony_ci PutByte(XIRCREG_CR, ClearRxOvrun); 112762306a36Sopenharmony_ci pr_debug("receive overrun cleared\n"); 112862306a36Sopenharmony_ci } 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_ci /***** transmit section ******/ 113162306a36Sopenharmony_ci if (int_status & PktTxed) { 113262306a36Sopenharmony_ci unsigned n, nn; 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ci n = lp->last_ptr_value; 113562306a36Sopenharmony_ci nn = GetByte(XIRCREG0_PTR); 113662306a36Sopenharmony_ci lp->last_ptr_value = nn; 113762306a36Sopenharmony_ci if (nn < n) /* rollover */ 113862306a36Sopenharmony_ci dev->stats.tx_packets += 256 - n; 113962306a36Sopenharmony_ci else if (n == nn) { /* happens sometimes - don't know why */ 114062306a36Sopenharmony_ci pr_debug("PTR not changed?\n"); 114162306a36Sopenharmony_ci } else 114262306a36Sopenharmony_ci dev->stats.tx_packets += lp->last_ptr_value - n; 114362306a36Sopenharmony_ci netif_wake_queue(dev); 114462306a36Sopenharmony_ci } 114562306a36Sopenharmony_ci if (tx_status & 0x0002) { /* Excessive collisions */ 114662306a36Sopenharmony_ci pr_debug("tx restarted due to excessive collisions\n"); 114762306a36Sopenharmony_ci PutByte(XIRCREG_CR, RestartTx); /* restart transmitter process */ 114862306a36Sopenharmony_ci } 114962306a36Sopenharmony_ci if (tx_status & 0x0040) 115062306a36Sopenharmony_ci dev->stats.tx_aborted_errors++; 115162306a36Sopenharmony_ci 115262306a36Sopenharmony_ci /* recalculate our work chunk so that we limit the duration of this 115362306a36Sopenharmony_ci * ISR to about 1/10 of a second. 115462306a36Sopenharmony_ci * Calculate only if we received a reasonable amount of bytes. 115562306a36Sopenharmony_ci */ 115662306a36Sopenharmony_ci if (bytes_rcvd > 1000) { 115762306a36Sopenharmony_ci u_long duration = jiffies - start_ticks; 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_ci if (duration >= HZ/10) { /* if more than about 1/10 second */ 116062306a36Sopenharmony_ci maxrx_bytes = (bytes_rcvd * (HZ/10)) / duration; 116162306a36Sopenharmony_ci if (maxrx_bytes < 2000) 116262306a36Sopenharmony_ci maxrx_bytes = 2000; 116362306a36Sopenharmony_ci else if (maxrx_bytes > 22000) 116462306a36Sopenharmony_ci maxrx_bytes = 22000; 116562306a36Sopenharmony_ci pr_debug("set maxrx=%u (rcvd=%u ticks=%lu)\n", 116662306a36Sopenharmony_ci maxrx_bytes, bytes_rcvd, duration); 116762306a36Sopenharmony_ci } else if (!duration && maxrx_bytes < 22000) { 116862306a36Sopenharmony_ci /* now much faster */ 116962306a36Sopenharmony_ci maxrx_bytes += 2000; 117062306a36Sopenharmony_ci if (maxrx_bytes > 22000) 117162306a36Sopenharmony_ci maxrx_bytes = 22000; 117262306a36Sopenharmony_ci pr_debug("set maxrx=%u\n", maxrx_bytes); 117362306a36Sopenharmony_ci } 117462306a36Sopenharmony_ci } 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_ci leave: 117762306a36Sopenharmony_ci if (lockup_hack) { 117862306a36Sopenharmony_ci if (int_status != 0xff && (int_status = GetByte(XIRCREG_ISR)) != 0) 117962306a36Sopenharmony_ci goto loop_entry; 118062306a36Sopenharmony_ci } 118162306a36Sopenharmony_ci SelectPage(saved_page); 118262306a36Sopenharmony_ci PutByte(XIRCREG_CR, EnableIntr); /* re-enable interrupts */ 118362306a36Sopenharmony_ci /* Instead of dropping packets during a receive, we could 118462306a36Sopenharmony_ci * force an interrupt with this command: 118562306a36Sopenharmony_ci * PutByte(XIRCREG_CR, EnableIntr|ForceIntr); 118662306a36Sopenharmony_ci */ 118762306a36Sopenharmony_ci return IRQ_HANDLED; 118862306a36Sopenharmony_ci} /* xirc2ps_interrupt */ 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_ci/*====================================================================*/ 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_cistatic void 119362306a36Sopenharmony_cixirc2ps_tx_timeout_task(struct work_struct *work) 119462306a36Sopenharmony_ci{ 119562306a36Sopenharmony_ci struct local_info *local = 119662306a36Sopenharmony_ci container_of(work, struct local_info, tx_timeout_task); 119762306a36Sopenharmony_ci struct net_device *dev = local->dev; 119862306a36Sopenharmony_ci /* reset the card */ 119962306a36Sopenharmony_ci do_reset(dev,1); 120062306a36Sopenharmony_ci netif_trans_update(dev); /* prevent tx timeout */ 120162306a36Sopenharmony_ci netif_wake_queue(dev); 120262306a36Sopenharmony_ci} 120362306a36Sopenharmony_ci 120462306a36Sopenharmony_cistatic void 120562306a36Sopenharmony_cixirc_tx_timeout(struct net_device *dev, unsigned int txqueue) 120662306a36Sopenharmony_ci{ 120762306a36Sopenharmony_ci struct local_info *lp = netdev_priv(dev); 120862306a36Sopenharmony_ci dev->stats.tx_errors++; 120962306a36Sopenharmony_ci netdev_notice(dev, "transmit timed out\n"); 121062306a36Sopenharmony_ci schedule_work(&lp->tx_timeout_task); 121162306a36Sopenharmony_ci} 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_cistatic netdev_tx_t 121462306a36Sopenharmony_cido_start_xmit(struct sk_buff *skb, struct net_device *dev) 121562306a36Sopenharmony_ci{ 121662306a36Sopenharmony_ci struct local_info *lp = netdev_priv(dev); 121762306a36Sopenharmony_ci unsigned int ioaddr = dev->base_addr; 121862306a36Sopenharmony_ci int okay; 121962306a36Sopenharmony_ci unsigned freespace; 122062306a36Sopenharmony_ci unsigned pktlen = skb->len; 122162306a36Sopenharmony_ci 122262306a36Sopenharmony_ci pr_debug("do_start_xmit(skb=%p, dev=%p) len=%u\n", 122362306a36Sopenharmony_ci skb, dev, pktlen); 122462306a36Sopenharmony_ci 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_ci /* adjust the packet length to min. required 122762306a36Sopenharmony_ci * and hope that the buffer is large enough 122862306a36Sopenharmony_ci * to provide some random data. 122962306a36Sopenharmony_ci * fixme: For Mohawk we can change this by sending 123062306a36Sopenharmony_ci * a larger packetlen than we actually have; the chip will 123162306a36Sopenharmony_ci * pad this in his buffer with random bytes 123262306a36Sopenharmony_ci */ 123362306a36Sopenharmony_ci if (pktlen < ETH_ZLEN) 123462306a36Sopenharmony_ci { 123562306a36Sopenharmony_ci if (skb_padto(skb, ETH_ZLEN)) 123662306a36Sopenharmony_ci return NETDEV_TX_OK; 123762306a36Sopenharmony_ci pktlen = ETH_ZLEN; 123862306a36Sopenharmony_ci } 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_ci netif_stop_queue(dev); 124162306a36Sopenharmony_ci SelectPage(0); 124262306a36Sopenharmony_ci PutWord(XIRCREG0_TRS, (u_short)pktlen+2); 124362306a36Sopenharmony_ci freespace = GetWord(XIRCREG0_TSO); 124462306a36Sopenharmony_ci okay = freespace & 0x8000; 124562306a36Sopenharmony_ci freespace &= 0x7fff; 124662306a36Sopenharmony_ci /* TRS doesn't work - (indeed it is eliminated with sil-rev 1) */ 124762306a36Sopenharmony_ci okay = pktlen +2 < freespace; 124862306a36Sopenharmony_ci pr_debug("%s: avail. tx space=%u%s\n", 124962306a36Sopenharmony_ci dev->name, freespace, okay ? " (okay)":" (not enough)"); 125062306a36Sopenharmony_ci if (!okay) { /* not enough space */ 125162306a36Sopenharmony_ci return NETDEV_TX_BUSY; /* upper layer may decide to requeue this packet */ 125262306a36Sopenharmony_ci } 125362306a36Sopenharmony_ci /* send the packet */ 125462306a36Sopenharmony_ci PutWord(XIRCREG_EDP, (u_short)pktlen); 125562306a36Sopenharmony_ci outsw(ioaddr+XIRCREG_EDP, skb->data, pktlen>>1); 125662306a36Sopenharmony_ci if (pktlen & 1) 125762306a36Sopenharmony_ci PutByte(XIRCREG_EDP, skb->data[pktlen-1]); 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_ci if (lp->mohawk) 126062306a36Sopenharmony_ci PutByte(XIRCREG_CR, TransmitPacket|EnableIntr); 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ci dev_kfree_skb (skb); 126362306a36Sopenharmony_ci dev->stats.tx_bytes += pktlen; 126462306a36Sopenharmony_ci netif_start_queue(dev); 126562306a36Sopenharmony_ci return NETDEV_TX_OK; 126662306a36Sopenharmony_ci} 126762306a36Sopenharmony_ci 126862306a36Sopenharmony_cistruct set_address_info { 126962306a36Sopenharmony_ci int reg_nr; 127062306a36Sopenharmony_ci int page_nr; 127162306a36Sopenharmony_ci int mohawk; 127262306a36Sopenharmony_ci unsigned int ioaddr; 127362306a36Sopenharmony_ci}; 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_cistatic void set_address(struct set_address_info *sa_info, const char *addr) 127662306a36Sopenharmony_ci{ 127762306a36Sopenharmony_ci unsigned int ioaddr = sa_info->ioaddr; 127862306a36Sopenharmony_ci int i; 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_ci for (i = 0; i < 6; i++) { 128162306a36Sopenharmony_ci if (sa_info->reg_nr > 15) { 128262306a36Sopenharmony_ci sa_info->reg_nr = 8; 128362306a36Sopenharmony_ci sa_info->page_nr++; 128462306a36Sopenharmony_ci SelectPage(sa_info->page_nr); 128562306a36Sopenharmony_ci } 128662306a36Sopenharmony_ci if (sa_info->mohawk) 128762306a36Sopenharmony_ci PutByte(sa_info->reg_nr++, addr[5 - i]); 128862306a36Sopenharmony_ci else 128962306a36Sopenharmony_ci PutByte(sa_info->reg_nr++, addr[i]); 129062306a36Sopenharmony_ci } 129162306a36Sopenharmony_ci} 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_ci/**************** 129462306a36Sopenharmony_ci * Set all addresses: This first one is the individual address, 129562306a36Sopenharmony_ci * the next 9 addresses are taken from the multicast list and 129662306a36Sopenharmony_ci * the rest is filled with the individual address. 129762306a36Sopenharmony_ci */ 129862306a36Sopenharmony_cistatic void set_addresses(struct net_device *dev) 129962306a36Sopenharmony_ci{ 130062306a36Sopenharmony_ci unsigned int ioaddr = dev->base_addr; 130162306a36Sopenharmony_ci struct local_info *lp = netdev_priv(dev); 130262306a36Sopenharmony_ci struct netdev_hw_addr *ha; 130362306a36Sopenharmony_ci struct set_address_info sa_info; 130462306a36Sopenharmony_ci int i; 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_ci /* 130762306a36Sopenharmony_ci * Setup the info structure so that by first set_address call it will do 130862306a36Sopenharmony_ci * SelectPage with the right page number. Hence these ones here. 130962306a36Sopenharmony_ci */ 131062306a36Sopenharmony_ci sa_info.reg_nr = 15 + 1; 131162306a36Sopenharmony_ci sa_info.page_nr = 0x50 - 1; 131262306a36Sopenharmony_ci sa_info.mohawk = lp->mohawk; 131362306a36Sopenharmony_ci sa_info.ioaddr = ioaddr; 131462306a36Sopenharmony_ci 131562306a36Sopenharmony_ci set_address(&sa_info, dev->dev_addr); 131662306a36Sopenharmony_ci i = 0; 131762306a36Sopenharmony_ci netdev_for_each_mc_addr(ha, dev) { 131862306a36Sopenharmony_ci if (i++ == 9) 131962306a36Sopenharmony_ci break; 132062306a36Sopenharmony_ci set_address(&sa_info, ha->addr); 132162306a36Sopenharmony_ci } 132262306a36Sopenharmony_ci while (i++ < 9) 132362306a36Sopenharmony_ci set_address(&sa_info, dev->dev_addr); 132462306a36Sopenharmony_ci SelectPage(0); 132562306a36Sopenharmony_ci} 132662306a36Sopenharmony_ci 132762306a36Sopenharmony_ci/**************** 132862306a36Sopenharmony_ci * Set or clear the multicast filter for this adaptor. 132962306a36Sopenharmony_ci * We can filter up to 9 addresses, if more are requested we set 133062306a36Sopenharmony_ci * multicast promiscuous mode. 133162306a36Sopenharmony_ci */ 133262306a36Sopenharmony_ci 133362306a36Sopenharmony_cistatic void 133462306a36Sopenharmony_ciset_multicast_list(struct net_device *dev) 133562306a36Sopenharmony_ci{ 133662306a36Sopenharmony_ci unsigned int ioaddr = dev->base_addr; 133762306a36Sopenharmony_ci unsigned value; 133862306a36Sopenharmony_ci 133962306a36Sopenharmony_ci SelectPage(0x42); 134062306a36Sopenharmony_ci value = GetByte(XIRCREG42_SWC1) & 0xC0; 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci if (dev->flags & IFF_PROMISC) { /* snoop */ 134362306a36Sopenharmony_ci PutByte(XIRCREG42_SWC1, value | 0x06); /* set MPE and PME */ 134462306a36Sopenharmony_ci } else if (netdev_mc_count(dev) > 9 || (dev->flags & IFF_ALLMULTI)) { 134562306a36Sopenharmony_ci PutByte(XIRCREG42_SWC1, value | 0x02); /* set MPE */ 134662306a36Sopenharmony_ci } else if (!netdev_mc_empty(dev)) { 134762306a36Sopenharmony_ci /* the chip can filter 9 addresses perfectly */ 134862306a36Sopenharmony_ci PutByte(XIRCREG42_SWC1, value | 0x01); 134962306a36Sopenharmony_ci SelectPage(0x40); 135062306a36Sopenharmony_ci PutByte(XIRCREG40_CMD0, Offline); 135162306a36Sopenharmony_ci set_addresses(dev); 135262306a36Sopenharmony_ci SelectPage(0x40); 135362306a36Sopenharmony_ci PutByte(XIRCREG40_CMD0, EnableRecv | Online); 135462306a36Sopenharmony_ci } else { /* standard usage */ 135562306a36Sopenharmony_ci PutByte(XIRCREG42_SWC1, value | 0x00); 135662306a36Sopenharmony_ci } 135762306a36Sopenharmony_ci SelectPage(0); 135862306a36Sopenharmony_ci} 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_cistatic int 136162306a36Sopenharmony_cido_config(struct net_device *dev, struct ifmap *map) 136262306a36Sopenharmony_ci{ 136362306a36Sopenharmony_ci struct local_info *local = netdev_priv(dev); 136462306a36Sopenharmony_ci 136562306a36Sopenharmony_ci pr_debug("do_config(%p)\n", dev); 136662306a36Sopenharmony_ci if (map->port != 255 && map->port != dev->if_port) { 136762306a36Sopenharmony_ci if (map->port > 4) 136862306a36Sopenharmony_ci return -EINVAL; 136962306a36Sopenharmony_ci if (!map->port) { 137062306a36Sopenharmony_ci local->probe_port = 1; 137162306a36Sopenharmony_ci dev->if_port = 1; 137262306a36Sopenharmony_ci } else { 137362306a36Sopenharmony_ci local->probe_port = 0; 137462306a36Sopenharmony_ci dev->if_port = map->port; 137562306a36Sopenharmony_ci } 137662306a36Sopenharmony_ci netdev_info(dev, "switching to %s port\n", if_names[dev->if_port]); 137762306a36Sopenharmony_ci do_reset(dev,1); /* not the fine way :-) */ 137862306a36Sopenharmony_ci } 137962306a36Sopenharmony_ci return 0; 138062306a36Sopenharmony_ci} 138162306a36Sopenharmony_ci 138262306a36Sopenharmony_ci/**************** 138362306a36Sopenharmony_ci * Open the driver 138462306a36Sopenharmony_ci */ 138562306a36Sopenharmony_cistatic int 138662306a36Sopenharmony_cido_open(struct net_device *dev) 138762306a36Sopenharmony_ci{ 138862306a36Sopenharmony_ci struct local_info *lp = netdev_priv(dev); 138962306a36Sopenharmony_ci struct pcmcia_device *link = lp->p_dev; 139062306a36Sopenharmony_ci 139162306a36Sopenharmony_ci dev_dbg(&link->dev, "do_open(%p)\n", dev); 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_ci /* Check that the PCMCIA card is still here. */ 139462306a36Sopenharmony_ci /* Physical device present signature. */ 139562306a36Sopenharmony_ci if (!pcmcia_dev_present(link)) 139662306a36Sopenharmony_ci return -ENODEV; 139762306a36Sopenharmony_ci 139862306a36Sopenharmony_ci /* okay */ 139962306a36Sopenharmony_ci link->open++; 140062306a36Sopenharmony_ci 140162306a36Sopenharmony_ci netif_start_queue(dev); 140262306a36Sopenharmony_ci do_reset(dev,1); 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_ci return 0; 140562306a36Sopenharmony_ci} 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_cistatic void netdev_get_drvinfo(struct net_device *dev, 140862306a36Sopenharmony_ci struct ethtool_drvinfo *info) 140962306a36Sopenharmony_ci{ 141062306a36Sopenharmony_ci strscpy(info->driver, "xirc2ps_cs", sizeof(info->driver)); 141162306a36Sopenharmony_ci snprintf(info->bus_info, sizeof(info->bus_info), "PCMCIA 0x%lx", 141262306a36Sopenharmony_ci dev->base_addr); 141362306a36Sopenharmony_ci} 141462306a36Sopenharmony_ci 141562306a36Sopenharmony_cistatic const struct ethtool_ops netdev_ethtool_ops = { 141662306a36Sopenharmony_ci .get_drvinfo = netdev_get_drvinfo, 141762306a36Sopenharmony_ci}; 141862306a36Sopenharmony_ci 141962306a36Sopenharmony_cistatic int 142062306a36Sopenharmony_cido_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) 142162306a36Sopenharmony_ci{ 142262306a36Sopenharmony_ci struct local_info *local = netdev_priv(dev); 142362306a36Sopenharmony_ci unsigned int ioaddr = dev->base_addr; 142462306a36Sopenharmony_ci struct mii_ioctl_data *data = if_mii(rq); 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_ci pr_debug("%s: ioctl(%-.6s, %#04x) %04x %04x %04x %04x\n", 142762306a36Sopenharmony_ci dev->name, rq->ifr_ifrn.ifrn_name, cmd, 142862306a36Sopenharmony_ci data->phy_id, data->reg_num, data->val_in, data->val_out); 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_ci if (!local->mohawk) 143162306a36Sopenharmony_ci return -EOPNOTSUPP; 143262306a36Sopenharmony_ci 143362306a36Sopenharmony_ci switch(cmd) { 143462306a36Sopenharmony_ci case SIOCGMIIPHY: /* Get the address of the PHY in use. */ 143562306a36Sopenharmony_ci data->phy_id = 0; /* we have only this address */ 143662306a36Sopenharmony_ci fallthrough; 143762306a36Sopenharmony_ci case SIOCGMIIREG: /* Read the specified MII register. */ 143862306a36Sopenharmony_ci data->val_out = mii_rd(ioaddr, data->phy_id & 0x1f, 143962306a36Sopenharmony_ci data->reg_num & 0x1f); 144062306a36Sopenharmony_ci break; 144162306a36Sopenharmony_ci case SIOCSMIIREG: /* Write the specified MII register */ 144262306a36Sopenharmony_ci mii_wr(ioaddr, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in, 144362306a36Sopenharmony_ci 16); 144462306a36Sopenharmony_ci break; 144562306a36Sopenharmony_ci default: 144662306a36Sopenharmony_ci return -EOPNOTSUPP; 144762306a36Sopenharmony_ci } 144862306a36Sopenharmony_ci return 0; 144962306a36Sopenharmony_ci} 145062306a36Sopenharmony_ci 145162306a36Sopenharmony_cistatic void 145262306a36Sopenharmony_cihardreset(struct net_device *dev) 145362306a36Sopenharmony_ci{ 145462306a36Sopenharmony_ci struct local_info *local = netdev_priv(dev); 145562306a36Sopenharmony_ci unsigned int ioaddr = dev->base_addr; 145662306a36Sopenharmony_ci 145762306a36Sopenharmony_ci SelectPage(4); 145862306a36Sopenharmony_ci udelay(1); 145962306a36Sopenharmony_ci PutByte(XIRCREG4_GPR1, 0); /* clear bit 0: power down */ 146062306a36Sopenharmony_ci msleep(40); /* wait 40 msec */ 146162306a36Sopenharmony_ci if (local->mohawk) 146262306a36Sopenharmony_ci PutByte(XIRCREG4_GPR1, 1); /* set bit 0: power up */ 146362306a36Sopenharmony_ci else 146462306a36Sopenharmony_ci PutByte(XIRCREG4_GPR1, 1 | 4); /* set bit 0: power up, bit 2: AIC */ 146562306a36Sopenharmony_ci msleep(20); /* wait 20 msec */ 146662306a36Sopenharmony_ci} 146762306a36Sopenharmony_ci 146862306a36Sopenharmony_cistatic void 146962306a36Sopenharmony_cido_reset(struct net_device *dev, int full) 147062306a36Sopenharmony_ci{ 147162306a36Sopenharmony_ci struct local_info *local = netdev_priv(dev); 147262306a36Sopenharmony_ci unsigned int ioaddr = dev->base_addr; 147362306a36Sopenharmony_ci unsigned value; 147462306a36Sopenharmony_ci 147562306a36Sopenharmony_ci pr_debug("%s: do_reset(%p,%d)\n", dev->name, dev, full); 147662306a36Sopenharmony_ci 147762306a36Sopenharmony_ci hardreset(dev); 147862306a36Sopenharmony_ci PutByte(XIRCREG_CR, SoftReset); /* set */ 147962306a36Sopenharmony_ci msleep(20); /* wait 20 msec */ 148062306a36Sopenharmony_ci PutByte(XIRCREG_CR, 0); /* clear */ 148162306a36Sopenharmony_ci msleep(40); /* wait 40 msec */ 148262306a36Sopenharmony_ci if (local->mohawk) { 148362306a36Sopenharmony_ci SelectPage(4); 148462306a36Sopenharmony_ci /* set pin GP1 and GP2 to output (0x0c) 148562306a36Sopenharmony_ci * set GP1 to low to power up the ML6692 (0x00) 148662306a36Sopenharmony_ci * set GP2 to high to power up the 10Mhz chip (0x02) 148762306a36Sopenharmony_ci */ 148862306a36Sopenharmony_ci PutByte(XIRCREG4_GPR0, 0x0e); 148962306a36Sopenharmony_ci } 149062306a36Sopenharmony_ci 149162306a36Sopenharmony_ci /* give the circuits some time to power up */ 149262306a36Sopenharmony_ci msleep(500); /* about 500ms */ 149362306a36Sopenharmony_ci 149462306a36Sopenharmony_ci local->last_ptr_value = 0; 149562306a36Sopenharmony_ci local->silicon = local->mohawk ? (GetByte(XIRCREG4_BOV) & 0x70) >> 4 149662306a36Sopenharmony_ci : (GetByte(XIRCREG4_BOV) & 0x30) >> 4; 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_ci if (local->probe_port) { 149962306a36Sopenharmony_ci if (!local->mohawk) { 150062306a36Sopenharmony_ci SelectPage(4); 150162306a36Sopenharmony_ci PutByte(XIRCREG4_GPR0, 4); 150262306a36Sopenharmony_ci local->probe_port = 0; 150362306a36Sopenharmony_ci } 150462306a36Sopenharmony_ci } else if (dev->if_port == 2) { /* enable 10Base2 */ 150562306a36Sopenharmony_ci SelectPage(0x42); 150662306a36Sopenharmony_ci PutByte(XIRCREG42_SWC1, 0xC0); 150762306a36Sopenharmony_ci } else { /* enable 10BaseT */ 150862306a36Sopenharmony_ci SelectPage(0x42); 150962306a36Sopenharmony_ci PutByte(XIRCREG42_SWC1, 0x80); 151062306a36Sopenharmony_ci } 151162306a36Sopenharmony_ci msleep(40); /* wait 40 msec to let it complete */ 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_ci #if 0 151462306a36Sopenharmony_ci { 151562306a36Sopenharmony_ci SelectPage(0); 151662306a36Sopenharmony_ci value = GetByte(XIRCREG_ESR); /* read the ESR */ 151762306a36Sopenharmony_ci pr_debug("%s: ESR is: %#02x\n", dev->name, value); 151862306a36Sopenharmony_ci } 151962306a36Sopenharmony_ci #endif 152062306a36Sopenharmony_ci 152162306a36Sopenharmony_ci /* setup the ECR */ 152262306a36Sopenharmony_ci SelectPage(1); 152362306a36Sopenharmony_ci PutByte(XIRCREG1_IMR0, 0xff); /* allow all ints */ 152462306a36Sopenharmony_ci PutByte(XIRCREG1_IMR1, 1 ); /* and Set TxUnderrunDetect */ 152562306a36Sopenharmony_ci value = GetByte(XIRCREG1_ECR); 152662306a36Sopenharmony_ci #if 0 152762306a36Sopenharmony_ci if (local->mohawk) 152862306a36Sopenharmony_ci value |= DisableLinkPulse; 152962306a36Sopenharmony_ci PutByte(XIRCREG1_ECR, value); 153062306a36Sopenharmony_ci #endif 153162306a36Sopenharmony_ci pr_debug("%s: ECR is: %#02x\n", dev->name, value); 153262306a36Sopenharmony_ci 153362306a36Sopenharmony_ci SelectPage(0x42); 153462306a36Sopenharmony_ci PutByte(XIRCREG42_SWC0, 0x20); /* disable source insertion */ 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_ci if (local->silicon != 1) { 153762306a36Sopenharmony_ci /* set the local memory dividing line. 153862306a36Sopenharmony_ci * The comments in the sample code say that this is only 153962306a36Sopenharmony_ci * settable with the scipper version 2 which is revision 0. 154062306a36Sopenharmony_ci * Always for CE3 cards 154162306a36Sopenharmony_ci */ 154262306a36Sopenharmony_ci SelectPage(2); 154362306a36Sopenharmony_ci PutWord(XIRCREG2_RBS, 0x2000); 154462306a36Sopenharmony_ci } 154562306a36Sopenharmony_ci 154662306a36Sopenharmony_ci if (full) 154762306a36Sopenharmony_ci set_addresses(dev); 154862306a36Sopenharmony_ci 154962306a36Sopenharmony_ci /* Hardware workaround: 155062306a36Sopenharmony_ci * The receive byte pointer after reset is off by 1 so we need 155162306a36Sopenharmony_ci * to move the offset pointer back to 0. 155262306a36Sopenharmony_ci */ 155362306a36Sopenharmony_ci SelectPage(0); 155462306a36Sopenharmony_ci PutWord(XIRCREG0_DO, 0x2000); /* change offset command, off=0 */ 155562306a36Sopenharmony_ci 155662306a36Sopenharmony_ci /* setup MAC IMRs and clear status registers */ 155762306a36Sopenharmony_ci SelectPage(0x40); /* Bit 7 ... bit 0 */ 155862306a36Sopenharmony_ci PutByte(XIRCREG40_RMASK0, 0xff); /* ROK, RAB, rsv, RO, CRC, AE, PTL, MP */ 155962306a36Sopenharmony_ci PutByte(XIRCREG40_TMASK0, 0xff); /* TOK, TAB, SQE, LL, TU, JAB, EXC, CRS */ 156062306a36Sopenharmony_ci PutByte(XIRCREG40_TMASK1, 0xb0); /* rsv, rsv, PTD, EXT, rsv,rsv,rsv, rsv*/ 156162306a36Sopenharmony_ci PutByte(XIRCREG40_RXST0, 0x00); /* ROK, RAB, REN, RO, CRC, AE, PTL, MP */ 156262306a36Sopenharmony_ci PutByte(XIRCREG40_TXST0, 0x00); /* TOK, TAB, SQE, LL, TU, JAB, EXC, CRS */ 156362306a36Sopenharmony_ci PutByte(XIRCREG40_TXST1, 0x00); /* TEN, rsv, PTD, EXT, retry_counter:4 */ 156462306a36Sopenharmony_ci 156562306a36Sopenharmony_ci if (full && local->mohawk && init_mii(dev)) { 156662306a36Sopenharmony_ci if (dev->if_port == 4 || local->dingo || local->new_mii) { 156762306a36Sopenharmony_ci netdev_info(dev, "MII selected\n"); 156862306a36Sopenharmony_ci SelectPage(2); 156962306a36Sopenharmony_ci PutByte(XIRCREG2_MSR, GetByte(XIRCREG2_MSR) | 0x08); 157062306a36Sopenharmony_ci msleep(20); 157162306a36Sopenharmony_ci } else { 157262306a36Sopenharmony_ci netdev_info(dev, "MII detected; using 10mbs\n"); 157362306a36Sopenharmony_ci SelectPage(0x42); 157462306a36Sopenharmony_ci if (dev->if_port == 2) /* enable 10Base2 */ 157562306a36Sopenharmony_ci PutByte(XIRCREG42_SWC1, 0xC0); 157662306a36Sopenharmony_ci else /* enable 10BaseT */ 157762306a36Sopenharmony_ci PutByte(XIRCREG42_SWC1, 0x80); 157862306a36Sopenharmony_ci msleep(40); /* wait 40 msec to let it complete */ 157962306a36Sopenharmony_ci } 158062306a36Sopenharmony_ci if (full_duplex) 158162306a36Sopenharmony_ci PutByte(XIRCREG1_ECR, GetByte(XIRCREG1_ECR | FullDuplex)); 158262306a36Sopenharmony_ci } else { /* No MII */ 158362306a36Sopenharmony_ci SelectPage(0); 158462306a36Sopenharmony_ci value = GetByte(XIRCREG_ESR); /* read the ESR */ 158562306a36Sopenharmony_ci dev->if_port = (value & MediaSelect) ? 1 : 2; 158662306a36Sopenharmony_ci } 158762306a36Sopenharmony_ci 158862306a36Sopenharmony_ci /* configure the LEDs */ 158962306a36Sopenharmony_ci SelectPage(2); 159062306a36Sopenharmony_ci if (dev->if_port == 1 || dev->if_port == 4) /* TP: Link and Activity */ 159162306a36Sopenharmony_ci PutByte(XIRCREG2_LED, 0x3b); 159262306a36Sopenharmony_ci else /* Coax: Not-Collision and Activity */ 159362306a36Sopenharmony_ci PutByte(XIRCREG2_LED, 0x3a); 159462306a36Sopenharmony_ci 159562306a36Sopenharmony_ci if (local->dingo) 159662306a36Sopenharmony_ci PutByte(0x0b, 0x04); /* 100 Mbit LED */ 159762306a36Sopenharmony_ci 159862306a36Sopenharmony_ci /* enable receiver and put the mac online */ 159962306a36Sopenharmony_ci if (full) { 160062306a36Sopenharmony_ci set_multicast_list(dev); 160162306a36Sopenharmony_ci SelectPage(0x40); 160262306a36Sopenharmony_ci PutByte(XIRCREG40_CMD0, EnableRecv | Online); 160362306a36Sopenharmony_ci } 160462306a36Sopenharmony_ci 160562306a36Sopenharmony_ci /* setup Ethernet IMR and enable interrupts */ 160662306a36Sopenharmony_ci SelectPage(1); 160762306a36Sopenharmony_ci PutByte(XIRCREG1_IMR0, 0xff); 160862306a36Sopenharmony_ci udelay(1); 160962306a36Sopenharmony_ci SelectPage(0); 161062306a36Sopenharmony_ci PutByte(XIRCREG_CR, EnableIntr); 161162306a36Sopenharmony_ci if (local->modem && !local->dingo) { /* do some magic */ 161262306a36Sopenharmony_ci if (!(GetByte(0x10) & 0x01)) 161362306a36Sopenharmony_ci PutByte(0x10, 0x11); /* unmask master-int bit */ 161462306a36Sopenharmony_ci } 161562306a36Sopenharmony_ci 161662306a36Sopenharmony_ci if (full) 161762306a36Sopenharmony_ci netdev_info(dev, "media %s, silicon revision %d\n", 161862306a36Sopenharmony_ci if_names[dev->if_port], local->silicon); 161962306a36Sopenharmony_ci /* We should switch back to page 0 to avoid a bug in revision 0 162062306a36Sopenharmony_ci * where regs with offset below 8 can't be read after an access 162162306a36Sopenharmony_ci * to the MAC registers */ 162262306a36Sopenharmony_ci SelectPage(0); 162362306a36Sopenharmony_ci} 162462306a36Sopenharmony_ci 162562306a36Sopenharmony_ci/**************** 162662306a36Sopenharmony_ci * Initialize the Media-Independent-Interface 162762306a36Sopenharmony_ci * Returns: True if we have a good MII 162862306a36Sopenharmony_ci */ 162962306a36Sopenharmony_cistatic int 163062306a36Sopenharmony_ciinit_mii(struct net_device *dev) 163162306a36Sopenharmony_ci{ 163262306a36Sopenharmony_ci struct local_info *local = netdev_priv(dev); 163362306a36Sopenharmony_ci unsigned int ioaddr = dev->base_addr; 163462306a36Sopenharmony_ci unsigned control, status, linkpartner; 163562306a36Sopenharmony_ci int i; 163662306a36Sopenharmony_ci 163762306a36Sopenharmony_ci if (if_port == 4 || if_port == 1) { /* force 100BaseT or 10BaseT */ 163862306a36Sopenharmony_ci dev->if_port = if_port; 163962306a36Sopenharmony_ci local->probe_port = 0; 164062306a36Sopenharmony_ci return 1; 164162306a36Sopenharmony_ci } 164262306a36Sopenharmony_ci 164362306a36Sopenharmony_ci status = mii_rd(ioaddr, 0, 1); 164462306a36Sopenharmony_ci if ((status & 0xff00) != 0x7800) 164562306a36Sopenharmony_ci return 0; /* No MII */ 164662306a36Sopenharmony_ci 164762306a36Sopenharmony_ci local->new_mii = (mii_rd(ioaddr, 0, 2) != 0xffff); 164862306a36Sopenharmony_ci 164962306a36Sopenharmony_ci if (local->probe_port) 165062306a36Sopenharmony_ci control = 0x1000; /* auto neg */ 165162306a36Sopenharmony_ci else if (dev->if_port == 4) 165262306a36Sopenharmony_ci control = 0x2000; /* no auto neg, 100mbs mode */ 165362306a36Sopenharmony_ci else 165462306a36Sopenharmony_ci control = 0x0000; /* no auto neg, 10mbs mode */ 165562306a36Sopenharmony_ci mii_wr(ioaddr, 0, 0, control, 16); 165662306a36Sopenharmony_ci udelay(100); 165762306a36Sopenharmony_ci control = mii_rd(ioaddr, 0, 0); 165862306a36Sopenharmony_ci 165962306a36Sopenharmony_ci if (control & 0x0400) { 166062306a36Sopenharmony_ci netdev_notice(dev, "can't take PHY out of isolation mode\n"); 166162306a36Sopenharmony_ci local->probe_port = 0; 166262306a36Sopenharmony_ci return 0; 166362306a36Sopenharmony_ci } 166462306a36Sopenharmony_ci 166562306a36Sopenharmony_ci if (local->probe_port) { 166662306a36Sopenharmony_ci /* according to the DP83840A specs the auto negotiation process 166762306a36Sopenharmony_ci * may take up to 3.5 sec, so we use this also for our ML6692 166862306a36Sopenharmony_ci * Fixme: Better to use a timer here! 166962306a36Sopenharmony_ci */ 167062306a36Sopenharmony_ci for (i=0; i < 35; i++) { 167162306a36Sopenharmony_ci msleep(100); /* wait 100 msec */ 167262306a36Sopenharmony_ci status = mii_rd(ioaddr, 0, 1); 167362306a36Sopenharmony_ci if ((status & 0x0020) && (status & 0x0004)) 167462306a36Sopenharmony_ci break; 167562306a36Sopenharmony_ci } 167662306a36Sopenharmony_ci 167762306a36Sopenharmony_ci if (!(status & 0x0020)) { 167862306a36Sopenharmony_ci netdev_info(dev, "autonegotiation failed; using 10mbs\n"); 167962306a36Sopenharmony_ci if (!local->new_mii) { 168062306a36Sopenharmony_ci control = 0x0000; 168162306a36Sopenharmony_ci mii_wr(ioaddr, 0, 0, control, 16); 168262306a36Sopenharmony_ci udelay(100); 168362306a36Sopenharmony_ci SelectPage(0); 168462306a36Sopenharmony_ci dev->if_port = (GetByte(XIRCREG_ESR) & MediaSelect) ? 1 : 2; 168562306a36Sopenharmony_ci } 168662306a36Sopenharmony_ci } else { 168762306a36Sopenharmony_ci linkpartner = mii_rd(ioaddr, 0, 5); 168862306a36Sopenharmony_ci netdev_info(dev, "MII link partner: %04x\n", linkpartner); 168962306a36Sopenharmony_ci if (linkpartner & 0x0080) { 169062306a36Sopenharmony_ci dev->if_port = 4; 169162306a36Sopenharmony_ci } else 169262306a36Sopenharmony_ci dev->if_port = 1; 169362306a36Sopenharmony_ci } 169462306a36Sopenharmony_ci } 169562306a36Sopenharmony_ci 169662306a36Sopenharmony_ci return 1; 169762306a36Sopenharmony_ci} 169862306a36Sopenharmony_ci 169962306a36Sopenharmony_cistatic void 170062306a36Sopenharmony_cido_powerdown(struct net_device *dev) 170162306a36Sopenharmony_ci{ 170262306a36Sopenharmony_ci 170362306a36Sopenharmony_ci unsigned int ioaddr = dev->base_addr; 170462306a36Sopenharmony_ci 170562306a36Sopenharmony_ci pr_debug("do_powerdown(%p)\n", dev); 170662306a36Sopenharmony_ci 170762306a36Sopenharmony_ci SelectPage(4); 170862306a36Sopenharmony_ci PutByte(XIRCREG4_GPR1, 0); /* clear bit 0: power down */ 170962306a36Sopenharmony_ci SelectPage(0); 171062306a36Sopenharmony_ci} 171162306a36Sopenharmony_ci 171262306a36Sopenharmony_cistatic int 171362306a36Sopenharmony_cido_stop(struct net_device *dev) 171462306a36Sopenharmony_ci{ 171562306a36Sopenharmony_ci unsigned int ioaddr = dev->base_addr; 171662306a36Sopenharmony_ci struct local_info *lp = netdev_priv(dev); 171762306a36Sopenharmony_ci struct pcmcia_device *link = lp->p_dev; 171862306a36Sopenharmony_ci 171962306a36Sopenharmony_ci dev_dbg(&link->dev, "do_stop(%p)\n", dev); 172062306a36Sopenharmony_ci 172162306a36Sopenharmony_ci if (!link) 172262306a36Sopenharmony_ci return -ENODEV; 172362306a36Sopenharmony_ci 172462306a36Sopenharmony_ci netif_stop_queue(dev); 172562306a36Sopenharmony_ci 172662306a36Sopenharmony_ci SelectPage(0); 172762306a36Sopenharmony_ci PutByte(XIRCREG_CR, 0); /* disable interrupts */ 172862306a36Sopenharmony_ci SelectPage(0x01); 172962306a36Sopenharmony_ci PutByte(XIRCREG1_IMR0, 0x00); /* forbid all ints */ 173062306a36Sopenharmony_ci SelectPage(4); 173162306a36Sopenharmony_ci PutByte(XIRCREG4_GPR1, 0); /* clear bit 0: power down */ 173262306a36Sopenharmony_ci SelectPage(0); 173362306a36Sopenharmony_ci 173462306a36Sopenharmony_ci link->open--; 173562306a36Sopenharmony_ci return 0; 173662306a36Sopenharmony_ci} 173762306a36Sopenharmony_ci 173862306a36Sopenharmony_cistatic const struct pcmcia_device_id xirc2ps_ids[] = { 173962306a36Sopenharmony_ci PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0089, 0x110a), 174062306a36Sopenharmony_ci PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0138, 0x110a), 174162306a36Sopenharmony_ci PCMCIA_PFC_DEVICE_PROD_ID13(0, "Xircom", "CEM28", 0x2e3ee845, 0x0ea978ea), 174262306a36Sopenharmony_ci PCMCIA_PFC_DEVICE_PROD_ID13(0, "Xircom", "CEM33", 0x2e3ee845, 0x80609023), 174362306a36Sopenharmony_ci PCMCIA_PFC_DEVICE_PROD_ID13(0, "Xircom", "CEM56", 0x2e3ee845, 0xa650c32a), 174462306a36Sopenharmony_ci PCMCIA_PFC_DEVICE_PROD_ID13(0, "Xircom", "REM10", 0x2e3ee845, 0x76df1d29), 174562306a36Sopenharmony_ci PCMCIA_PFC_DEVICE_PROD_ID13(0, "Xircom", "XEM5600", 0x2e3ee845, 0xf1403719), 174662306a36Sopenharmony_ci PCMCIA_PFC_DEVICE_PROD_ID12(0, "Xircom", "CreditCard Ethernet+Modem II", 0x2e3ee845, 0xeca401bf), 174762306a36Sopenharmony_ci PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x010a), 174862306a36Sopenharmony_ci PCMCIA_DEVICE_PROD_ID13("Toshiba Information Systems", "TPCENET", 0x1b3b94fe, 0xf381c1a2), 174962306a36Sopenharmony_ci PCMCIA_DEVICE_PROD_ID13("Xircom", "CE3-10/100", 0x2e3ee845, 0x0ec0ac37), 175062306a36Sopenharmony_ci PCMCIA_DEVICE_PROD_ID13("Xircom", "PS-CE2-10", 0x2e3ee845, 0x947d9073), 175162306a36Sopenharmony_ci PCMCIA_DEVICE_PROD_ID13("Xircom", "R2E-100BTX", 0x2e3ee845, 0x2464a6e3), 175262306a36Sopenharmony_ci PCMCIA_DEVICE_PROD_ID13("Xircom", "RE-10", 0x2e3ee845, 0x3e08d609), 175362306a36Sopenharmony_ci PCMCIA_DEVICE_PROD_ID13("Xircom", "XE2000", 0x2e3ee845, 0xf7188e46), 175462306a36Sopenharmony_ci PCMCIA_DEVICE_PROD_ID12("Compaq", "Ethernet LAN Card", 0x54f7c49c, 0x9fd2f0a2), 175562306a36Sopenharmony_ci PCMCIA_DEVICE_PROD_ID12("Compaq", "Netelligent 10/100 PC Card", 0x54f7c49c, 0xefe96769), 175662306a36Sopenharmony_ci PCMCIA_DEVICE_PROD_ID12("Intel", "EtherExpress(TM) PRO/100 PC Card Mobile Adapter16", 0x816cc815, 0x174397db), 175762306a36Sopenharmony_ci PCMCIA_DEVICE_PROD_ID12("Toshiba", "10/100 Ethernet PC Card", 0x44a09d9c, 0xb44deecf), 175862306a36Sopenharmony_ci /* also matches CFE-10 cards! */ 175962306a36Sopenharmony_ci /* PCMCIA_DEVICE_MANF_CARD(0x0105, 0x010a), */ 176062306a36Sopenharmony_ci PCMCIA_DEVICE_NULL, 176162306a36Sopenharmony_ci}; 176262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pcmcia, xirc2ps_ids); 176362306a36Sopenharmony_ci 176462306a36Sopenharmony_ci 176562306a36Sopenharmony_cistatic struct pcmcia_driver xirc2ps_cs_driver = { 176662306a36Sopenharmony_ci .owner = THIS_MODULE, 176762306a36Sopenharmony_ci .name = "xirc2ps_cs", 176862306a36Sopenharmony_ci .probe = xirc2ps_probe, 176962306a36Sopenharmony_ci .remove = xirc2ps_detach, 177062306a36Sopenharmony_ci .id_table = xirc2ps_ids, 177162306a36Sopenharmony_ci .suspend = xirc2ps_suspend, 177262306a36Sopenharmony_ci .resume = xirc2ps_resume, 177362306a36Sopenharmony_ci}; 177462306a36Sopenharmony_cimodule_pcmcia_driver(xirc2ps_cs_driver); 177562306a36Sopenharmony_ci 177662306a36Sopenharmony_ci#ifndef MODULE 177762306a36Sopenharmony_cistatic int __init setup_xirc2ps_cs(char *str) 177862306a36Sopenharmony_ci{ 177962306a36Sopenharmony_ci /* if_port, full_duplex, do_sound, lockup_hack 178062306a36Sopenharmony_ci */ 178162306a36Sopenharmony_ci int ints[10] = { -1 }; 178262306a36Sopenharmony_ci 178362306a36Sopenharmony_ci str = get_options(str, ARRAY_SIZE(ints), ints); 178462306a36Sopenharmony_ci 178562306a36Sopenharmony_ci#define MAYBE_SET(X,Y) if (ints[0] >= Y && ints[Y] != -1) { X = ints[Y]; } 178662306a36Sopenharmony_ci MAYBE_SET(if_port, 3); 178762306a36Sopenharmony_ci MAYBE_SET(full_duplex, 4); 178862306a36Sopenharmony_ci MAYBE_SET(do_sound, 5); 178962306a36Sopenharmony_ci MAYBE_SET(lockup_hack, 6); 179062306a36Sopenharmony_ci#undef MAYBE_SET 179162306a36Sopenharmony_ci 179262306a36Sopenharmony_ci return 1; 179362306a36Sopenharmony_ci} 179462306a36Sopenharmony_ci 179562306a36Sopenharmony_ci__setup("xirc2ps_cs=", setup_xirc2ps_cs); 179662306a36Sopenharmony_ci#endif 1797