Annotation of Gnu-Mach/linux/pcmcia-cs/clients/pcnet_cs.c, revision 1.1

1.1     ! root        1: /*======================================================================
        !             2: 
        !             3:     A PCMCIA ethernet driver for NS8390-based cards
        !             4: 
        !             5:     This driver supports the D-Link DE-650 and Linksys EthernetCard
        !             6:     cards, the newer D-Link and Linksys combo cards, Accton EN2212
        !             7:     cards, the RPTI EP400, and the PreMax PE-200 in non-shared-memory
        !             8:     mode, and the IBM Credit Card Adapter, the NE4100, the Thomas
        !             9:     Conrad ethernet card, and the Kingston KNE-PCM/x in shared-memory
        !            10:     mode.  It will also handle the Socket EA card in either mode.
        !            11: 
        !            12:     Copyright (C) 1999 David A. Hinds -- [email protected]
        !            13: 
        !            14:     pcnet_cs.c 1.153 2003/11/09 18:53:09
        !            15:     
        !            16:     The network driver code is based on Donald Becker's NE2000 code:
        !            17: 
        !            18:     Written 1992,1993 by Donald Becker.
        !            19:     Copyright 1993 United States Government as represented by the
        !            20:     Director, National Security Agency.  This software may be used and
        !            21:     distributed according to the terms of the GNU General Public License,
        !            22:     incorporated herein by reference.
        !            23:     Donald Becker may be reached at [email protected]
        !            24: 
        !            25:     Based also on Keith Moore's changes to Don Becker's code, for IBM
        !            26:     CCAE support.  Drivers merged back together, and shared-memory
        !            27:     Socket EA support added, by Ken Raeburn, September 1995.
        !            28: 
        !            29: ======================================================================*/
        !            30: 
        !            31: #include <linux/kernel.h>
        !            32: #include <linux/module.h>
        !            33: #include <linux/init.h>
        !            34: #include <linux/sched.h>
        !            35: #include <linux/ptrace.h>
        !            36: #include <linux/slab.h>
        !            37: #include <linux/string.h>
        !            38: #include <linux/timer.h>
        !            39: #include <linux/delay.h>
        !            40: #include <asm/io.h>
        !            41: #include <asm/system.h>
        !            42: #include <asm/byteorder.h>
        !            43: #include <asm/uaccess.h>
        !            44: 
        !            45: #include <linux/netdevice.h>
        !            46: #include <../drivers/net/8390.h>
        !            47: 
        !            48: #include <pcmcia/version.h>
        !            49: #include <pcmcia/cs_types.h>
        !            50: #include <pcmcia/cs.h>
        !            51: #include <pcmcia/cistpl.h>
        !            52: #include <pcmcia/ciscode.h>
        !            53: #include <pcmcia/ds.h>
        !            54: #include <pcmcia/cisreg.h>
        !            55: 
        !            56: #define PCNET_CMD      0x00
        !            57: #define PCNET_DATAPORT 0x10    /* NatSemi-defined port window offset. */
        !            58: #define PCNET_RESET    0x1f    /* Issue a read to reset, a write to clear. */
        !            59: #define PCNET_MISC     0x18    /* For IBM CCAE and Socket EA cards */
        !            60: 
        !            61: #define PCNET_START_PG 0x40    /* First page of TX buffer */
        !            62: #define PCNET_STOP_PG  0x80    /* Last page +1 of RX ring */
        !            63: 
        !            64: /* Socket EA cards have a larger packet buffer */
        !            65: #define SOCKET_START_PG        0x01
        !            66: #define SOCKET_STOP_PG 0xff
        !            67: 
        !            68: #define PCNET_RDC_TIMEOUT (2*HZ/100)   /* Max wait in jiffies for Tx RDC */
        !            69: 
        !            70: static char *if_names[] = { "auto", "10baseT", "10base2"};
        !            71: 
        !            72: #ifdef PCMCIA_DEBUG
        !            73: static int pc_debug = PCMCIA_DEBUG;
        !            74: MODULE_PARM(pc_debug, "i");
        !            75: #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
        !            76: static char *version =
        !            77: "pcnet_cs.c 1.153 2003/11/09 18:53:09 (David Hinds)";
        !            78: #else
        !            79: #define DEBUG(n, args...)
        !            80: #endif
        !            81: 
        !            82: /*====================================================================*/
        !            83: 
        !            84: /* Module parameters */
        !            85: 
        !            86: MODULE_AUTHOR("David Hinds <[email protected]>");
        !            87: MODULE_DESCRIPTION("NE2000 compatible PCMCIA ethernet driver");
        !            88: MODULE_LICENSE("GPL");
        !            89: 
        !            90: #define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i")
        !            91: 
        !            92: /* Bit map of interrupts to choose from */
        !            93: INT_MODULE_PARM(irq_mask,      0xdeb8);
        !            94: static int irq_list[4] = { -1 };
        !            95: MODULE_PARM(irq_list, "1-4i");
        !            96: 
        !            97: INT_MODULE_PARM(if_port,       1);     /* Transceiver type */
        !            98: INT_MODULE_PARM(use_big_buf,   1);     /* use 64K packet buffer? */
        !            99: INT_MODULE_PARM(mem_speed,     0);     /* shared mem speed, in ns */
        !           100: INT_MODULE_PARM(delay_output,  0);     /* pause after xmit? */
        !           101: INT_MODULE_PARM(delay_time,    4);     /* in usec */
        !           102: INT_MODULE_PARM(use_shmem,     -1);    /* use shared memory? */
        !           103: INT_MODULE_PARM(full_duplex,   0);     /* full duplex? */
        !           104: 
        !           105: /* Ugh!  Let the user hardwire the hardware address for queer cards */
        !           106: static int hw_addr[6] = { 0, /* ... */ };
        !           107: MODULE_PARM(hw_addr, "6i");
        !           108: 
        !           109: /*====================================================================*/
        !           110: 
        !           111: static void mii_phy_probe(struct net_device *dev);
        !           112: static void pcnet_config(dev_link_t *link);
        !           113: static void pcnet_release(u_long arg);
        !           114: static int pcnet_event(event_t event, int priority,
        !           115:                       event_callback_args_t *args);
        !           116: static int pcnet_open(struct net_device *dev);
        !           117: static int pcnet_close(struct net_device *dev);
        !           118: static int ei_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
        !           119: static void ei_irq_wrapper(int irq, void *dev_id, struct pt_regs *regs);
        !           120: static void ei_watchdog(u_long arg);
        !           121: static void pcnet_reset_8390(struct net_device *dev);
        !           122: static int set_config(struct net_device *dev, struct ifmap *map);
        !           123: static int setup_shmem_window(dev_link_t *link, int start_pg,
        !           124:                              int stop_pg, int cm_offset);
        !           125: static int setup_dma_config(dev_link_t *link, int start_pg,
        !           126:                            int stop_pg);
        !           127: 
        !           128: static dev_link_t *pcnet_attach(void);
        !           129: static void pcnet_detach(dev_link_t *);
        !           130: 
        !           131: static dev_info_t dev_info = "pcnet_cs";
        !           132: static dev_link_t *dev_list;
        !           133: 
        !           134: /*====================================================================*/
        !           135: 
        !           136: typedef struct hw_info_t {
        !           137:     u_int      offset;
        !           138:     u_char     a0, a1, a2;
        !           139:     u_int      flags;
        !           140: } hw_info_t;
        !           141: 
        !           142: #define DELAY_OUTPUT   0x01
        !           143: #define HAS_MISC_REG   0x02
        !           144: #define USE_BIG_BUF    0x04
        !           145: #define HAS_IBM_MISC   0x08
        !           146: #define IS_DL10019     0x10
        !           147: #define IS_DL10022     0x20
        !           148: #define HAS_MII                0x40
        !           149: #define USE_SHMEM      0x80    /* autodetected */
        !           150: 
        !           151: #define AM79C9XX_HOME_PHY      0x00006B90  /* HomePNA PHY */
        !           152: #define AM79C9XX_ETH_PHY       0x00006B70  /* 10baseT PHY */
        !           153: #define MII_PHYID_REV_MASK     0xfffffff0
        !           154: #define MII_PHYID_REG1         0x02
        !           155: #define MII_PHYID_REG2         0x03
        !           156: 
        !           157: static hw_info_t hw_info[] = {
        !           158:     { /* Accton EN2212 */ 0x0ff0, 0x00, 0x00, 0xe8, DELAY_OUTPUT }, 
        !           159:     { /* Allied Telesis LA-PCM */ 0x0ff0, 0x00, 0x00, 0xf4, 0 },
        !           160:     { /* APEX MultiCard */ 0x03f4, 0x00, 0x20, 0xe5, 0 },
        !           161:     { /* ASANTE FriendlyNet */ 0x4910, 0x00, 0x00, 0x94,
        !           162:       DELAY_OUTPUT | HAS_IBM_MISC },
        !           163:     { /* Danpex EN-6200P2 */ 0x0110, 0x00, 0x40, 0xc7, 0 },
        !           164:     { /* DataTrek NetCard */ 0x0ff0, 0x00, 0x20, 0xe8, 0 },
        !           165:     { /* Dayna CommuniCard E */ 0x0110, 0x00, 0x80, 0x19, 0 },
        !           166:     { /* D-Link DE-650 */ 0x0040, 0x00, 0x80, 0xc8, 0 },
        !           167:     { /* EP-210 Ethernet */ 0x0110, 0x00, 0x40, 0x33, 0 },
        !           168:     { /* EP4000 Ethernet */ 0x01c0, 0x00, 0x00, 0xb4, 0 },
        !           169:     { /* Epson EEN10B */ 0x0ff0, 0x00, 0x00, 0x48,
        !           170:       HAS_MISC_REG | HAS_IBM_MISC },
        !           171:     { /* ELECOM Laneed LD-CDWA */ 0xb8, 0x08, 0x00, 0x42, 0 },
        !           172:     { /* Hypertec Ethernet */ 0x01c0, 0x00, 0x40, 0x4c, 0 },
        !           173:     { /* IBM CCAE */ 0x0ff0, 0x08, 0x00, 0x5a,
        !           174:       HAS_MISC_REG | HAS_IBM_MISC },
        !           175:     { /* IBM CCAE */ 0x0ff0, 0x00, 0x04, 0xac,
        !           176:       HAS_MISC_REG | HAS_IBM_MISC },
        !           177:     { /* IBM CCAE */ 0x0ff0, 0x00, 0x06, 0x29,
        !           178:       HAS_MISC_REG | HAS_IBM_MISC },
        !           179:     { /* IBM FME */ 0x0374, 0x08, 0x00, 0x5a,
        !           180:       HAS_MISC_REG | HAS_IBM_MISC },
        !           181:     { /* IBM FME */ 0x0374, 0x00, 0x04, 0xac,
        !           182:       HAS_MISC_REG | HAS_IBM_MISC },
        !           183:     { /* Kansai KLA-PCM/T */ 0x0ff0, 0x00, 0x60, 0x87,
        !           184:       HAS_MISC_REG | HAS_IBM_MISC },
        !           185:     { /* NSC DP83903 */ 0x0374, 0x08, 0x00, 0x17,
        !           186:       HAS_MISC_REG | HAS_IBM_MISC },
        !           187:     { /* NSC DP83903 */ 0x0374, 0x00, 0xc0, 0xa8,
        !           188:       HAS_MISC_REG | HAS_IBM_MISC },
        !           189:     { /* NSC DP83903 */ 0x0374, 0x00, 0xa0, 0xb0,
        !           190:       HAS_MISC_REG | HAS_IBM_MISC },
        !           191:     { /* NSC DP83903 */ 0x0198, 0x00, 0x20, 0xe0,
        !           192:       HAS_MISC_REG | HAS_IBM_MISC },
        !           193:     { /* I-O DATA PCLA/T */ 0x0ff0, 0x00, 0xa0, 0xb0, 0 },
        !           194:     { /* Katron PE-520 */ 0x0110, 0x00, 0x40, 0xf6, 0 },
        !           195:     { /* Kingston KNE-PCM/x */ 0x0ff0, 0x00, 0xc0, 0xf0,
        !           196:       HAS_MISC_REG | HAS_IBM_MISC },
        !           197:     { /* Kingston KNE-PCM/x */ 0x0ff0, 0xe2, 0x0c, 0x0f,
        !           198:       HAS_MISC_REG | HAS_IBM_MISC },
        !           199:     { /* Kingston KNE-PC2 */ 0x0180, 0x00, 0xc0, 0xf0, 0 },
        !           200:     { /* Maxtech PCN2000 */ 0x5000, 0x00, 0x00, 0xe8, 0 },
        !           201:     { /* NDC Instant-Link */ 0x003a, 0x00, 0x80, 0xc6, 0 },
        !           202:     { /* NE2000 Compatible */ 0x0ff0, 0x00, 0xa0, 0x0c, 0 },
        !           203:     { /* Network General Sniffer */ 0x0ff0, 0x00, 0x00, 0x65,
        !           204:       HAS_MISC_REG | HAS_IBM_MISC },
        !           205:     { /* Panasonic VEL211 */ 0x0ff0, 0x00, 0x80, 0x45, 
        !           206:       HAS_MISC_REG | HAS_IBM_MISC },
        !           207:     { /* PreMax PE-200 */ 0x07f0, 0x00, 0x20, 0xe0, 0 },
        !           208:     { /* RPTI EP400 */ 0x0110, 0x00, 0x40, 0x95, 0 },
        !           209:     { /* SCM Ethernet */ 0x0ff0, 0x00, 0x20, 0xcb, 0 },
        !           210:     { /* Socket EA */ 0x4000, 0x00, 0xc0, 0x1b,
        !           211:       DELAY_OUTPUT | HAS_MISC_REG | USE_BIG_BUF },
        !           212:     { /* Socket LP-E CF+ */ 0x01c0, 0x00, 0xc0, 0x1b, 0 },
        !           213:     { /* SuperSocket RE450T */ 0x0110, 0x00, 0xe0, 0x98, 0 },
        !           214:     { /* Volktek NPL-402CT */ 0x0060, 0x00, 0x40, 0x05, 0 },
        !           215:     { /* NEC PC-9801N-J12 */ 0x0ff0, 0x00, 0x00, 0x4c, 0 },
        !           216:     { /* PCMCIA Technology OEM */ 0x01c8, 0x00, 0xa0, 0x0c, 0 }
        !           217: };
        !           218: 
        !           219: #define NR_INFO                (sizeof(hw_info)/sizeof(hw_info_t))
        !           220: 
        !           221: static hw_info_t default_info = { 0, 0, 0, 0, 0 };
        !           222: static hw_info_t dl10019_info = { 0, 0, 0, 0, IS_DL10019|HAS_MII };
        !           223: static hw_info_t dl10022_info = { 0, 0, 0, 0, IS_DL10022|HAS_MII };
        !           224: 
        !           225: typedef struct pcnet_dev_t {
        !           226:     struct net_device  dev;    /* so &dev == &pcnet_dev_t */
        !           227:     dev_link_t         link;
        !           228:     dev_node_t         node;
        !           229:     u_int              flags;
        !           230:     caddr_t            base;
        !           231:     struct timer_list  watchdog;
        !           232:     int                        stale, fast_poll;
        !           233:     u_char             phy_id;
        !           234:     u_char             eth_phy, pna_phy;
        !           235:     u_short            link_status;
        !           236:     u_long             mii_reset;
        !           237: } pcnet_dev_t;
        !           238: 
        !           239: /*======================================================================
        !           240: 
        !           241:     This bit of code is used to avoid unregistering network devices
        !           242:     at inappropriate times.  2.2 and later kernels are fairly picky
        !           243:     about when this can happen.
        !           244:     
        !           245: ======================================================================*/
        !           246: 
        !           247: static void flush_stale_links(void)
        !           248: {
        !           249:     dev_link_t *link, *next;
        !           250:     for (link = dev_list; link; link = next) {
        !           251:        next = link->next;
        !           252:        if (link->state & DEV_STALE_LINK)
        !           253:            pcnet_detach(link);
        !           254:     }
        !           255: }
        !           256: 
        !           257: /*====================================================================*/
        !           258: 
        !           259: static void cs_error(client_handle_t handle, int func, int ret)
        !           260: {
        !           261:     error_info_t err = { func, ret };
        !           262:     CardServices(ReportError, handle, &err);
        !           263: }
        !           264: 
        !           265: /*======================================================================
        !           266: 
        !           267:     We never need to do anything when a pcnet device is "initialized"
        !           268:     by the net software, because we only register already-found cards.
        !           269: 
        !           270: ======================================================================*/
        !           271: 
        !           272: static int pcnet_init(struct net_device *dev)
        !           273: {
        !           274:     return 0;
        !           275: }
        !           276: 
        !           277: /*======================================================================
        !           278: 
        !           279:     pcnet_attach() creates an "instance" of the driver, allocating
        !           280:     local data structures for one device.  The device is registered
        !           281:     with Card Services.
        !           282: 
        !           283: ======================================================================*/
        !           284: 
        !           285: static dev_link_t *pcnet_attach(void)
        !           286: {
        !           287:     pcnet_dev_t *info;
        !           288:     dev_link_t *link;
        !           289:     struct net_device *dev;
        !           290:     client_reg_t client_reg;
        !           291:     int i, ret;
        !           292: 
        !           293:     DEBUG(0, "pcnet_attach()\n");
        !           294:     flush_stale_links();
        !           295: 
        !           296:     /* Create new ethernet device */
        !           297:     info = kmalloc(sizeof(*info), GFP_KERNEL);
        !           298:     if (!info) return NULL;
        !           299:     memset(info, 0, sizeof(*info));
        !           300:     link = &info->link; dev = &info->dev;
        !           301:     link->priv = info;
        !           302: 
        !           303:     init_timer(&link->release);
        !           304:     link->release.function = &pcnet_release;
        !           305:     link->release.data = (u_long)link;
        !           306:     link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
        !           307:     link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
        !           308:     if (irq_list[0] == -1)
        !           309:        link->irq.IRQInfo2 = irq_mask;
        !           310:     else
        !           311:        for (i = 0; i < 4; i++)
        !           312:            link->irq.IRQInfo2 |= 1 << irq_list[i];
        !           313:     link->conf.Attributes = CONF_ENABLE_IRQ;
        !           314:     link->conf.IntType = INT_MEMORY_AND_IO;
        !           315: 
        !           316:     ethdev_init(dev);
        !           317:     init_dev_name(dev, info->node);
        !           318:     dev->init = &pcnet_init;
        !           319:     dev->open = &pcnet_open;
        !           320:     dev->stop = &pcnet_close;
        !           321:     dev->set_config = &set_config;
        !           322: 
        !           323:     /* Register with Card Services */
        !           324:     link->next = dev_list;
        !           325:     dev_list = link;
        !           326:     client_reg.dev_info = &dev_info;
        !           327:     client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
        !           328:     client_reg.EventMask =
        !           329:        CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
        !           330:        CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
        !           331:        CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
        !           332:     client_reg.event_handler = &pcnet_event;
        !           333:     client_reg.Version = 0x0210;
        !           334:     client_reg.event_callback_args.client_data = link;
        !           335:     ret = CardServices(RegisterClient, &link->handle, &client_reg);
        !           336:     if (ret != CS_SUCCESS) {
        !           337:        cs_error(link->handle, RegisterClient, ret);
        !           338:        pcnet_detach(link);
        !           339:        return NULL;
        !           340:     }
        !           341: 
        !           342:     return link;
        !           343: } /* pcnet_attach */
        !           344: 
        !           345: /*======================================================================
        !           346: 
        !           347:     This deletes a driver "instance".  The device is de-registered
        !           348:     with Card Services.  If it has been released, all local data
        !           349:     structures are freed.  Otherwise, the structures will be freed
        !           350:     when the device is released.
        !           351: 
        !           352: ======================================================================*/
        !           353: 
        !           354: static void pcnet_detach(dev_link_t *link)
        !           355: {
        !           356:     pcnet_dev_t *info = link->priv;
        !           357:     dev_link_t **linkp;
        !           358: 
        !           359:     DEBUG(0, "pcnet_detach(0x%p)\n", link);
        !           360: 
        !           361:     /* Locate device structure */
        !           362:     for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
        !           363:        if (*linkp == link) break;
        !           364:     if (*linkp == NULL)
        !           365:        return;
        !           366: 
        !           367:     del_timer(&link->release);
        !           368:     if (link->state & DEV_CONFIG) {
        !           369:        pcnet_release((u_long)link);
        !           370:        if (link->state & DEV_STALE_CONFIG) {
        !           371:            link->state |= DEV_STALE_LINK;
        !           372:            return;
        !           373:        }
        !           374:     }
        !           375: 
        !           376:     if (link->handle)
        !           377:        CardServices(DeregisterClient, link->handle);
        !           378: 
        !           379:     /* Unlink device structure, free bits */
        !           380:     *linkp = link->next;
        !           381:     if (link->dev)
        !           382:        unregister_netdev(&info->dev);
        !           383:     kfree(info);
        !           384: 
        !           385: } /* pcnet_detach */
        !           386: 
        !           387: /*======================================================================
        !           388: 
        !           389:     This probes for a card's hardware address, for card types that
        !           390:     encode this information in their CIS.
        !           391: 
        !           392: ======================================================================*/
        !           393: 
        !           394: static hw_info_t *get_hwinfo(dev_link_t *link)
        !           395: {
        !           396:     struct net_device *dev = link->priv;
        !           397:     win_req_t req;
        !           398:     memreq_t mem;
        !           399:     u_char *base, *virt;
        !           400:     int i, j;
        !           401: 
        !           402:     /* Allocate a small memory window */
        !           403:     req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
        !           404:     req.Base = 0; req.Size = 0;
        !           405:     req.AccessSpeed = 0;
        !           406:     link->win = (window_handle_t)link->handle;
        !           407:     i = CardServices(RequestWindow, &link->win, &req);
        !           408:     if (i != CS_SUCCESS) {
        !           409:        cs_error(link->handle, RequestWindow, i);
        !           410:        return NULL;
        !           411:     }
        !           412: 
        !           413:     virt = ioremap(req.Base, req.Size);
        !           414:     mem.Page = 0;
        !           415:     for (i = 0; i < NR_INFO; i++) {
        !           416:        mem.CardOffset = hw_info[i].offset & ~(req.Size-1);
        !           417:        CardServices(MapMemPage, link->win, &mem);
        !           418:        base = &virt[hw_info[i].offset & (req.Size-1)];
        !           419:        if ((readb(base+0) == hw_info[i].a0) &&
        !           420:            (readb(base+2) == hw_info[i].a1) &&
        !           421:            (readb(base+4) == hw_info[i].a2))
        !           422:            break;
        !           423:     }
        !           424:     if (i < NR_INFO) {
        !           425:        for (j = 0; j < 6; j++)
        !           426:            dev->dev_addr[j] = readb(base + (j<<1));
        !           427:     }
        !           428:     
        !           429:     iounmap(virt);
        !           430:     j = CardServices(ReleaseWindow, link->win);
        !           431:     if (j != CS_SUCCESS)
        !           432:        cs_error(link->handle, ReleaseWindow, j);
        !           433:     return (i < NR_INFO) ? hw_info+i : NULL;
        !           434: } /* get_hwinfo */
        !           435: 
        !           436: /*======================================================================
        !           437: 
        !           438:     This probes for a card's hardware address by reading the PROM.
        !           439:     It checks the address against a list of known types, then falls
        !           440:     back to a simple NE2000 clone signature check.
        !           441: 
        !           442: ======================================================================*/
        !           443: 
        !           444: static hw_info_t *get_prom(dev_link_t *link)
        !           445: {
        !           446:     struct net_device *dev = link->priv;
        !           447:     ioaddr_t ioaddr = dev->base_addr;
        !           448:     u_char prom[32];
        !           449:     int i, j;
        !           450: 
        !           451:     /* This is lifted straight from drivers/net/ne.c */
        !           452:     struct {
        !           453:        u_char value, offset;
        !           454:     } program_seq[] = {
        !           455:        {E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD}, /* Select page 0*/
        !           456:        {0x48,  EN0_DCFG},      /* Set byte-wide (0x48) access. */
        !           457:        {0x00,  EN0_RCNTLO},    /* Clear the count regs. */
        !           458:        {0x00,  EN0_RCNTHI},
        !           459:        {0x00,  EN0_IMR},       /* Mask completion irq. */
        !           460:        {0xFF,  EN0_ISR},
        !           461:        {E8390_RXOFF, EN0_RXCR},        /* 0x20  Set to monitor */
        !           462:        {E8390_TXOFF, EN0_TXCR},        /* 0x02  and loopback mode. */
        !           463:        {32,    EN0_RCNTLO},
        !           464:        {0x00,  EN0_RCNTHI},
        !           465:        {0x00,  EN0_RSARLO},    /* DMA starting at 0x0000. */
        !           466:        {0x00,  EN0_RSARHI},
        !           467:        {E8390_RREAD+E8390_START, E8390_CMD},
        !           468:     };
        !           469: 
        !           470:     pcnet_reset_8390(dev);
        !           471:     mdelay(10);
        !           472: 
        !           473:     for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++)
        !           474:        outb_p(program_seq[i].value, ioaddr + program_seq[i].offset);
        !           475: 
        !           476:     for (i = 0; i < 32; i++)
        !           477:        prom[i] = inb(ioaddr + PCNET_DATAPORT);
        !           478:     for (i = 0; i < NR_INFO; i++) {
        !           479:        if ((prom[0] == hw_info[i].a0) &&
        !           480:            (prom[2] == hw_info[i].a1) &&
        !           481:            (prom[4] == hw_info[i].a2))
        !           482:            break;
        !           483:     }
        !           484:     if ((i < NR_INFO) || ((prom[28] == 0x57) && (prom[30] == 0x57))) {
        !           485:        for (j = 0; j < 6; j++)
        !           486:            dev->dev_addr[j] = prom[j<<1];
        !           487:        return (i < NR_INFO) ? hw_info+i : &default_info;
        !           488:     }
        !           489:     return NULL;
        !           490: } /* get_prom */
        !           491: 
        !           492: /*======================================================================
        !           493: 
        !           494:     For DL10019 based cards, like the Linksys EtherFast
        !           495: 
        !           496: ======================================================================*/
        !           497: 
        !           498: static hw_info_t *get_dl10019(dev_link_t *link)
        !           499: {
        !           500:     struct net_device *dev = link->priv;
        !           501:     int i;
        !           502:     u_char sum;
        !           503: 
        !           504:     for (sum = 0, i = 0x14; i < 0x1c; i++)
        !           505:        sum += inb_p(dev->base_addr + i);
        !           506:     if (sum != 0xff)
        !           507:        return NULL;
        !           508:     for (i = 0; i < 6; i++)
        !           509:        dev->dev_addr[i] = inb_p(dev->base_addr + 0x14 + i);
        !           510:     i = inb(dev->base_addr + 0x1f);
        !           511:     return ((i == 0x91)||(i == 0x99)) ? &dl10022_info : &dl10019_info;
        !           512: }
        !           513: 
        !           514: /*======================================================================
        !           515: 
        !           516:     For Asix AX88190 based cards
        !           517: 
        !           518: ======================================================================*/
        !           519: 
        !           520: static hw_info_t *get_ax88190(dev_link_t *link)
        !           521: {
        !           522:     struct net_device *dev = link->priv;
        !           523:     ioaddr_t ioaddr = dev->base_addr;
        !           524:     int i, j;
        !           525: 
        !           526:     /* Not much of a test, but the alternatives are messy */
        !           527:     if (link->conf.ConfigBase != 0x03c0)
        !           528:        return NULL;
        !           529: 
        !           530:     outb_p(0x01, ioaddr + EN0_DCFG);   /* Set word-wide access. */
        !           531:     outb_p(0x00, ioaddr + EN0_RSARLO); /* DMA starting at 0x0400. */
        !           532:     outb_p(0x04, ioaddr + EN0_RSARHI);
        !           533:     outb_p(E8390_RREAD+E8390_START, ioaddr + E8390_CMD);
        !           534: 
        !           535:     for (i = 0; i < 6; i += 2) {
        !           536:        j = inw(ioaddr + PCNET_DATAPORT);
        !           537:        dev->dev_addr[i] = j & 0xff;
        !           538:        dev->dev_addr[i+1] = j >> 8;
        !           539:     }
        !           540:     printk(KERN_NOTICE "pcnet_cs: this is an AX88190 card!\n");
        !           541:     printk(KERN_NOTICE "pcnet_cs: use axnet_cs instead.\n");
        !           542:     return NULL;
        !           543: }
        !           544: 
        !           545: /*======================================================================
        !           546: 
        !           547:     This should be totally unnecessary... but when we can't figure
        !           548:     out the hardware address any other way, we'll let the user hard
        !           549:     wire it when the module is initialized.
        !           550: 
        !           551: ======================================================================*/
        !           552: 
        !           553: static hw_info_t *get_hwired(dev_link_t *link)
        !           554: {
        !           555:     struct net_device *dev = link->priv;
        !           556:     int i;
        !           557: 
        !           558:     for (i = 0; i < 6; i++)
        !           559:        if (hw_addr[i] != 0) break;
        !           560:     if (i == 6)
        !           561:        return NULL;
        !           562: 
        !           563:     for (i = 0; i < 6; i++)
        !           564:        dev->dev_addr[i] = hw_addr[i];
        !           565: 
        !           566:     return &default_info;
        !           567: } /* get_hwired */
        !           568: 
        !           569: /*======================================================================
        !           570: 
        !           571:     pcnet_config() is scheduled to run after a CARD_INSERTION event
        !           572:     is received, to configure the PCMCIA socket, and to make the
        !           573:     ethernet device available to the system.
        !           574: 
        !           575: ======================================================================*/
        !           576: 
        !           577: #define CS_CHECK(fn, args...) \
        !           578: while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
        !           579: 
        !           580: #define CFG_CHECK(fn, args...) \
        !           581: if (CardServices(fn, args) != 0) goto next_entry
        !           582: 
        !           583: static int try_io_port(dev_link_t *link)
        !           584: {
        !           585:     int j, ret;
        !           586:     if (link->io.NumPorts1 == 32) {
        !           587:        link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
        !           588:        if (link->io.NumPorts2 > 0) {
        !           589:            /* for master/slave multifunction cards */
        !           590:            link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
        !           591:            link->irq.Attributes = 
        !           592:                IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED;
        !           593:        }
        !           594:     } else {
        !           595:        /* This should be two 16-port windows */
        !           596:        link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
        !           597:        link->io.Attributes2 = IO_DATA_PATH_WIDTH_16;
        !           598:     }
        !           599:     if (link->io.BasePort1 == 0) {
        !           600:        link->io.IOAddrLines = 16;
        !           601:        for (j = 0; j < 0x400; j += 0x20) {
        !           602:            link->io.BasePort1 = j ^ 0x300;
        !           603:            link->io.BasePort2 = (j ^ 0x300) + 0x10;
        !           604:            ret = CardServices(RequestIO, link->handle, &link->io);
        !           605:            if (ret == CS_SUCCESS) return ret;
        !           606:        }
        !           607:        return ret;
        !           608:     } else {
        !           609:        return CardServices(RequestIO, link->handle, &link->io);
        !           610:     }
        !           611: }
        !           612: 
        !           613: static void pcnet_config(dev_link_t *link)
        !           614: {
        !           615:     client_handle_t handle = link->handle;
        !           616:     pcnet_dev_t *info = link->priv;
        !           617:     struct net_device *dev = &info->dev;
        !           618:     tuple_t tuple;
        !           619:     cisparse_t parse;
        !           620:     int i, last_ret, last_fn, start_pg, stop_pg, cm_offset;
        !           621:     int manfid = 0, prodid = 0, has_shmem = 0;
        !           622:     u_short buf[64];
        !           623:     config_info_t conf;
        !           624:     hw_info_t *hw_info;
        !           625: 
        !           626:     DEBUG(0, "pcnet_config(0x%p)\n", link);
        !           627: 
        !           628:     tuple.Attributes = 0;
        !           629:     tuple.TupleData = (cisdata_t *)buf;
        !           630:     tuple.TupleDataMax = sizeof(buf);
        !           631:     tuple.TupleOffset = 0;
        !           632:     tuple.DesiredTuple = CISTPL_CONFIG;
        !           633:     CS_CHECK(GetFirstTuple, handle, &tuple);
        !           634:     CS_CHECK(GetTupleData, handle, &tuple);
        !           635:     CS_CHECK(ParseTuple, handle, &tuple, &parse);
        !           636:     link->conf.ConfigBase = parse.config.base;
        !           637:     link->conf.Present = parse.config.rmask[0];
        !           638: 
        !           639:     /* Configure card */
        !           640:     link->state |= DEV_CONFIG;
        !           641: 
        !           642:     /* Look up current Vcc */
        !           643:     CS_CHECK(GetConfigurationInfo, handle, &conf);
        !           644:     link->conf.Vcc = conf.Vcc;
        !           645: 
        !           646:     tuple.DesiredTuple = CISTPL_MANFID;
        !           647:     tuple.Attributes = TUPLE_RETURN_COMMON;
        !           648:     if ((CardServices(GetFirstTuple, handle, &tuple) == CS_SUCCESS) &&
        !           649:        (CardServices(GetTupleData, handle, &tuple) == CS_SUCCESS)) {
        !           650:        manfid = le16_to_cpu(buf[0]);
        !           651:        prodid = le16_to_cpu(buf[1]);
        !           652:     }
        !           653:     
        !           654:     tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
        !           655:     tuple.Attributes = 0;
        !           656:     CS_CHECK(GetFirstTuple, handle, &tuple);
        !           657:     while (last_ret == CS_SUCCESS) {
        !           658:        cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
        !           659:        cistpl_io_t *io = &(parse.cftable_entry.io);
        !           660:        
        !           661:        CFG_CHECK(GetTupleData, handle, &tuple);
        !           662:        CFG_CHECK(ParseTuple, handle, &tuple, &parse);
        !           663:        if ((cfg->index == 0) || (cfg->io.nwin == 0))
        !           664:            goto next_entry;
        !           665:        
        !           666:        link->conf.ConfigIndex = cfg->index;
        !           667:        /* For multifunction cards, by convention, we configure the
        !           668:           network function with window 0, and serial with window 1 */
        !           669:        if (io->nwin > 1) {
        !           670:            i = (io->win[1].len > io->win[0].len);
        !           671:            link->io.BasePort2 = io->win[1-i].base;
        !           672:            link->io.NumPorts2 = io->win[1-i].len;
        !           673:        } else {
        !           674:            i = link->io.NumPorts2 = 0;
        !           675:        }
        !           676:        has_shmem = ((cfg->mem.nwin == 1) &&
        !           677:                     (cfg->mem.win[0].len >= 0x4000));
        !           678:        link->io.BasePort1 = io->win[i].base;
        !           679:        link->io.NumPorts1 = io->win[i].len;
        !           680:        link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
        !           681:        if (link->io.NumPorts1 + link->io.NumPorts2 >= 32) {
        !           682:            last_ret = try_io_port(link);
        !           683:            if (last_ret == CS_SUCCESS) break;
        !           684:        }
        !           685:     next_entry:
        !           686:        last_ret = CardServices(GetNextTuple, handle, &tuple);
        !           687:     }
        !           688:     if (last_ret != CS_SUCCESS) {
        !           689:        cs_error(handle, RequestIO, last_ret);
        !           690:        goto failed;
        !           691:     }
        !           692: 
        !           693:     CS_CHECK(RequestIRQ, handle, &link->irq);
        !           694:     
        !           695:     if (link->io.NumPorts2 == 8) {
        !           696:        link->conf.Attributes |= CONF_ENABLE_SPKR;
        !           697:        link->conf.Status = CCSR_AUDIO_ENA;
        !           698:     }
        !           699:     if ((manfid == MANFID_IBM) &&
        !           700:        (prodid == PRODID_IBM_HOME_AND_AWAY))
        !           701:        link->conf.ConfigIndex |= 0x10;
        !           702:     
        !           703:     CS_CHECK(RequestConfiguration, handle, &link->conf);
        !           704:     dev->irq = link->irq.AssignedIRQ;
        !           705:     dev->base_addr = link->io.BasePort1;
        !           706:     if (info->flags & HAS_MISC_REG) {
        !           707:        if ((if_port == 1) || (if_port == 2))
        !           708:            dev->if_port = if_port;
        !           709:        else
        !           710:            printk(KERN_NOTICE "pcnet_cs: invalid if_port requested\n");
        !           711:     } else {
        !           712:        dev->if_port = 0;
        !           713:     }
        !           714:     if (register_netdev(dev) != 0) {
        !           715:        printk(KERN_NOTICE "pcnet_cs: register_netdev() failed\n");
        !           716:        goto failed;
        !           717:     }
        !           718: 
        !           719:     hw_info = get_hwinfo(link);
        !           720:     if (hw_info == NULL)
        !           721:        hw_info = get_prom(link);
        !           722:     if (hw_info == NULL)
        !           723:        hw_info = get_dl10019(link);
        !           724:     if (hw_info == NULL)
        !           725:        hw_info = get_ax88190(link);
        !           726:     if (hw_info == NULL)
        !           727:        hw_info = get_hwired(link);
        !           728:     
        !           729:     if (hw_info == NULL) {
        !           730:        printk(KERN_NOTICE "pcnet_cs: unable to read hardware net"
        !           731:               " address for io base %#3lx\n", dev->base_addr);
        !           732:        unregister_netdev(dev);
        !           733:        goto failed;
        !           734:     }
        !           735: 
        !           736:     info->flags = hw_info->flags;
        !           737:     /* Check for user overrides */
        !           738:     info->flags |= (delay_output) ? DELAY_OUTPUT : 0;
        !           739:     if ((manfid == MANFID_SOCKET) &&
        !           740:        ((prodid == PRODID_SOCKET_LPE) ||
        !           741:         (prodid == PRODID_SOCKET_LPE_CF) ||
        !           742:         (prodid == PRODID_SOCKET_EIO)))
        !           743:        info->flags &= ~USE_BIG_BUF;
        !           744:     if (!use_big_buf)
        !           745:        info->flags &= ~USE_BIG_BUF;
        !           746:     
        !           747:     if (info->flags & USE_BIG_BUF) {
        !           748:        start_pg = SOCKET_START_PG;
        !           749:        stop_pg = SOCKET_STOP_PG;
        !           750:        cm_offset = 0x10000;
        !           751:     } else {
        !           752:        start_pg = PCNET_START_PG;
        !           753:        stop_pg = PCNET_STOP_PG;
        !           754:        cm_offset = 0;
        !           755:     }
        !           756: 
        !           757:     /* has_shmem is ignored if use_shmem != -1 */
        !           758:     if ((use_shmem == 0) || (!has_shmem && (use_shmem == -1)) ||
        !           759:        (setup_shmem_window(link, start_pg, stop_pg, cm_offset) != 0))
        !           760:        setup_dma_config(link, start_pg, stop_pg);
        !           761: 
        !           762:     ei_status.name = "NE2000";
        !           763:     ei_status.word16 = 1;
        !           764:     ei_status.reset_8390 = &pcnet_reset_8390;
        !           765: 
        !           766:     copy_dev_name(info->node, dev);
        !           767:     link->dev = &info->node;
        !           768: 
        !           769:     if (info->flags & (IS_DL10019|IS_DL10022)) {
        !           770:        u_char id = inb(dev->base_addr + 0x1a);
        !           771:        dev->do_ioctl = &ei_ioctl;
        !           772:        mii_phy_probe(dev);
        !           773:        if ((id == 0x30) && !info->pna_phy && (info->eth_phy == 4))
        !           774:            info->eth_phy = 0;
        !           775:        printk(KERN_INFO "%s: NE2000 (DL100%d rev %02x): ",
        !           776:               dev->name, ((info->flags & IS_DL10022) ? 22 : 19), id);
        !           777:        if (info->pna_phy)
        !           778:            printk("PNA, ");
        !           779:     } else
        !           780:        printk(KERN_INFO "%s: NE2000 Compatible: ", dev->name);
        !           781:     printk("io %#3lx, irq %d,", dev->base_addr, dev->irq);
        !           782:     if (info->flags & USE_SHMEM)
        !           783:        printk (" mem %#5lx,", dev->mem_start);
        !           784:     if (info->flags & HAS_MISC_REG)
        !           785:        printk(" %s xcvr,", if_names[dev->if_port]);
        !           786:     printk(" hw_addr ");
        !           787:     for (i = 0; i < 6; i++)
        !           788:        printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
        !           789:     link->state &= ~DEV_CONFIG_PENDING;
        !           790:     return;
        !           791: 
        !           792: cs_failed:
        !           793:     cs_error(link->handle, last_fn, last_ret);
        !           794: failed:
        !           795:     pcnet_release((u_long)link);
        !           796:     link->state &= ~DEV_CONFIG_PENDING;
        !           797:     return;
        !           798: } /* pcnet_config */
        !           799: 
        !           800: /*======================================================================
        !           801: 
        !           802:     After a card is removed, pcnet_release() will unregister the net
        !           803:     device, and release the PCMCIA configuration.  If the device is
        !           804:     still open, this will be postponed until it is closed.
        !           805: 
        !           806: ======================================================================*/
        !           807: 
        !           808: static void pcnet_release(u_long arg)
        !           809: {
        !           810:     dev_link_t *link = (dev_link_t *)arg;
        !           811:     pcnet_dev_t *info = link->priv;
        !           812: 
        !           813:     DEBUG(0, "pcnet_release(0x%p)\n", link);
        !           814: 
        !           815:     if (link->open) {
        !           816:        DEBUG(1, "pcnet_cs: release postponed, '%s' still open\n",
        !           817:              info->node.dev_name);
        !           818:        link->state |= DEV_STALE_CONFIG;
        !           819:        return;
        !           820:     }
        !           821: 
        !           822:     if (info->flags & USE_SHMEM) {
        !           823:        iounmap(info->base);
        !           824:        CardServices(ReleaseWindow, link->win);
        !           825:     }
        !           826:     CardServices(ReleaseConfiguration, link->handle);
        !           827:     CardServices(ReleaseIO, link->handle, &link->io);
        !           828:     CardServices(ReleaseIRQ, link->handle, &link->irq);
        !           829: 
        !           830:     link->state &= ~DEV_CONFIG;
        !           831: 
        !           832: } /* pcnet_release */
        !           833: 
        !           834: /*======================================================================
        !           835: 
        !           836:     The card status event handler.  Mostly, this schedules other
        !           837:     stuff to run after an event is received.  A CARD_REMOVAL event
        !           838:     also sets some flags to discourage the net drivers from trying
        !           839:     to talk to the card any more.
        !           840: 
        !           841: ======================================================================*/
        !           842: 
        !           843: static int pcnet_event(event_t event, int priority,
        !           844:                       event_callback_args_t *args)
        !           845: {
        !           846:     dev_link_t *link = args->client_data;
        !           847:     pcnet_dev_t *info = link->priv;
        !           848: 
        !           849:     DEBUG(2, "pcnet_event(0x%06x)\n", event);
        !           850: 
        !           851:     switch (event) {
        !           852:     case CS_EVENT_CARD_REMOVAL:
        !           853:        link->state &= ~DEV_PRESENT;
        !           854:        if (link->state & DEV_CONFIG) {
        !           855:            netif_device_detach(&info->dev);
        !           856:            mod_timer(&link->release, jiffies + HZ/20);
        !           857:        }
        !           858:        break;
        !           859:     case CS_EVENT_CARD_INSERTION:
        !           860:        link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
        !           861:        pcnet_config(link);
        !           862:        break;
        !           863:     case CS_EVENT_PM_SUSPEND:
        !           864:        link->state |= DEV_SUSPEND;
        !           865:        /* Fall through... */
        !           866:     case CS_EVENT_RESET_PHYSICAL:
        !           867:        if (link->state & DEV_CONFIG) {
        !           868:            if (link->open)
        !           869:                netif_device_detach(&info->dev);
        !           870:            CardServices(ReleaseConfiguration, link->handle);
        !           871:        }
        !           872:        break;
        !           873:     case CS_EVENT_PM_RESUME:
        !           874:        link->state &= ~DEV_SUSPEND;
        !           875:        /* Fall through... */
        !           876:     case CS_EVENT_CARD_RESET:
        !           877:        if (link->state & DEV_CONFIG) {
        !           878:            CardServices(RequestConfiguration, link->handle, &link->conf);
        !           879:            if (link->open) {
        !           880:                pcnet_reset_8390(&info->dev);
        !           881:                NS8390_init(&info->dev, 1);
        !           882:                netif_device_attach(&info->dev);
        !           883:            }
        !           884:        }
        !           885:        break;
        !           886:     }
        !           887:     return 0;
        !           888: } /* pcnet_event */
        !           889: 
        !           890: /*======================================================================
        !           891: 
        !           892:     MII interface support for DL10019 and DL10022 based cards
        !           893: 
        !           894:     On the DL10019, the MII IO direction bit is 0x10; on the DL10022
        !           895:     it is 0x20.  Setting both bits seems to work on both card types.
        !           896: 
        !           897: ======================================================================*/
        !           898: 
        !           899: #define DLINK_GPIO             0x1c
        !           900: #define DLINK_DIAG             0x1d
        !           901: #define DLINK_EEPROM           0x1e
        !           902: 
        !           903: #define MDIO_SHIFT_CLK         0x80
        !           904: #define MDIO_DATA_OUT          0x40
        !           905: #define MDIO_DIR_WRITE         0x30
        !           906: #define MDIO_DATA_WRITE0       (MDIO_DIR_WRITE)
        !           907: #define MDIO_DATA_WRITE1       (MDIO_DIR_WRITE | MDIO_DATA_OUT)
        !           908: #define MDIO_DATA_READ         0x10
        !           909: #define MDIO_MASK              0x0f
        !           910: 
        !           911: static void mdio_sync(ioaddr_t addr)
        !           912: {
        !           913:     int bits, mask = inb(addr) & MDIO_MASK;
        !           914:     for (bits = 0; bits < 32; bits++) {
        !           915:        outb(mask | MDIO_DATA_WRITE1, addr);
        !           916:        outb(mask | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, addr);
        !           917:     }
        !           918: }
        !           919: 
        !           920: static int mdio_read(ioaddr_t addr, int phy_id, int loc)
        !           921: {
        !           922:     u_int cmd = (0x06<<10)|(phy_id<<5)|loc;
        !           923:     int i, retval = 0, mask = inb(addr) & MDIO_MASK;
        !           924: 
        !           925:     mdio_sync(addr);
        !           926:     for (i = 13; i >= 0; i--) {
        !           927:        int dat = (cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
        !           928:        outb(mask | dat, addr);
        !           929:        outb(mask | dat | MDIO_SHIFT_CLK, addr);
        !           930:     }
        !           931:     for (i = 19; i > 0; i--) {
        !           932:        outb(mask, addr);
        !           933:        retval = (retval << 1) | ((inb(addr) & MDIO_DATA_READ) != 0);
        !           934:        outb(mask | MDIO_SHIFT_CLK, addr);
        !           935:     }
        !           936:     return (retval>>1) & 0xffff;
        !           937: }
        !           938: 
        !           939: static void mdio_write(ioaddr_t addr, int phy_id, int loc, int value)
        !           940: {
        !           941:     u_int cmd = (0x05<<28)|(phy_id<<23)|(loc<<18)|(1<<17)|value;
        !           942:     int i, mask = inb(addr) & MDIO_MASK;
        !           943: 
        !           944:     mdio_sync(addr);
        !           945:     for (i = 31; i >= 0; i--) {
        !           946:        int dat = (cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
        !           947:        outb(mask | dat, addr);
        !           948:        outb(mask | dat | MDIO_SHIFT_CLK, addr);
        !           949:     }
        !           950:     for (i = 1; i >= 0; i--) {
        !           951:        outb(mask, addr);
        !           952:        outb(mask | MDIO_SHIFT_CLK, addr);
        !           953:     }
        !           954: }
        !           955: 
        !           956: static void mdio_reset(ioaddr_t addr, int phy_id)
        !           957: {
        !           958:     outb_p(0x08, addr);
        !           959:     outb_p(0x0c, addr);
        !           960:     outb_p(0x08, addr);
        !           961:     outb_p(0x0c, addr);
        !           962:     outb_p(0x00, addr);
        !           963: }
        !           964: 
        !           965: /*======================================================================
        !           966: 
        !           967:     EEPROM access routines for DL10019 and DL10022 based cards
        !           968: 
        !           969: ======================================================================*/
        !           970: 
        !           971: #define EE_EEP         0x40
        !           972: #define EE_ASIC                0x10
        !           973: #define EE_CS          0x08
        !           974: #define EE_CK          0x04
        !           975: #define EE_DO          0x02
        !           976: #define EE_DI          0x01
        !           977: #define EE_ADOT                0x01    /* DataOut for ASIC */
        !           978: #define EE_READ_CMD    0x06    
        !           979: 
        !           980: #define DL19FDUPLX     0x0400  /* DL10019 Full duplex mode */
        !           981: 
        !           982: static int read_eeprom(ioaddr_t ioaddr, int location)
        !           983: {
        !           984:     int i, retval = 0;
        !           985:     ioaddr_t ee_addr = ioaddr + DLINK_EEPROM;
        !           986:     int read_cmd = location | (EE_READ_CMD << 8);
        !           987: 
        !           988:     outb(0, ee_addr);
        !           989:     outb(EE_EEP|EE_CS, ee_addr);
        !           990: 
        !           991:     /* Shift the read command bits out. */
        !           992:     for (i = 10; i >= 0; i--) {
        !           993:        short dataval = (read_cmd & (1 << i)) ? EE_DO : 0;
        !           994:        outb_p(EE_EEP|EE_CS|dataval, ee_addr);
        !           995:        outb_p(EE_EEP|EE_CS|dataval|EE_CK, ee_addr);
        !           996:     }
        !           997:     outb(EE_EEP|EE_CS, ee_addr);
        !           998: 
        !           999:     for (i = 16; i > 0; i--) {
        !          1000:        outb_p(EE_EEP|EE_CS | EE_CK, ee_addr);
        !          1001:        retval = (retval << 1) | ((inb(ee_addr) & EE_DI) ? 1 : 0);
        !          1002:        outb_p(EE_EEP|EE_CS, ee_addr);
        !          1003:     }
        !          1004: 
        !          1005:     /* Terminate the EEPROM access. */
        !          1006:     outb(0, ee_addr);
        !          1007:     return retval;
        !          1008: }
        !          1009: 
        !          1010: /*
        !          1011:     The internal ASIC registers can be changed by EEPROM READ access
        !          1012:     with EE_ASIC bit set.
        !          1013:     In ASIC mode, EE_ADOT is used to output the data to the ASIC.
        !          1014: */ 
        !          1015: 
        !          1016: static void write_asic(ioaddr_t ioaddr, int location, short asic_data)
        !          1017: {
        !          1018:        int i;
        !          1019:        ioaddr_t ee_addr = ioaddr + DLINK_EEPROM;
        !          1020:        short dataval;
        !          1021:        int read_cmd = location | (EE_READ_CMD << 8);
        !          1022: 
        !          1023:        asic_data |= read_eeprom(ioaddr, location);
        !          1024: 
        !          1025:        outb(0, ee_addr);
        !          1026:        outb(EE_ASIC|EE_CS|EE_DI, ee_addr);
        !          1027:        
        !          1028:        read_cmd = read_cmd >> 1;
        !          1029: 
        !          1030:        /* Shift the read command bits out. */
        !          1031:        for (i = 9; i >= 0; i--) {
        !          1032:                dataval = (read_cmd & (1 << i)) ? EE_DO : 0;
        !          1033:                outb_p(EE_ASIC|EE_CS|EE_DI|dataval, ee_addr);
        !          1034:                outb_p(EE_ASIC|EE_CS|EE_DI|dataval|EE_CK, ee_addr);
        !          1035:                outb_p(EE_ASIC|EE_CS|EE_DI|dataval, ee_addr);
        !          1036:        }
        !          1037:        // sync
        !          1038:        outb(EE_ASIC|EE_CS, ee_addr);
        !          1039:        outb(EE_ASIC|EE_CS|EE_CK, ee_addr);
        !          1040:        outb(EE_ASIC|EE_CS, ee_addr);
        !          1041: 
        !          1042:        for (i = 15; i >= 0; i--) {
        !          1043:                dataval = (asic_data & (1 << i)) ? EE_ADOT : 0;
        !          1044:                outb_p(EE_ASIC|EE_CS|dataval, ee_addr);
        !          1045:                outb_p(EE_ASIC|EE_CS|dataval|EE_CK, ee_addr);
        !          1046:                outb_p(EE_ASIC|EE_CS|dataval, ee_addr);
        !          1047:        }
        !          1048: 
        !          1049:        /* Terminate the ASIC access. */
        !          1050:        outb(EE_ASIC|EE_DI, ee_addr);
        !          1051:        outb(EE_ASIC|EE_DI| EE_CK, ee_addr);
        !          1052:        outb(EE_ASIC|EE_DI, ee_addr);
        !          1053: 
        !          1054:        outb(0, ee_addr);
        !          1055: }
        !          1056: 
        !          1057: /*====================================================================*/
        !          1058: 
        !          1059: static void set_misc_reg(struct net_device *dev)
        !          1060: {
        !          1061:     ioaddr_t nic_base = dev->base_addr;
        !          1062:     pcnet_dev_t *info = (pcnet_dev_t *)dev;
        !          1063:     u_char tmp;
        !          1064:     
        !          1065:     if (info->flags & HAS_MISC_REG) {
        !          1066:        tmp = inb_p(nic_base + PCNET_MISC) & ~3;
        !          1067:        if (dev->if_port == 2)
        !          1068:            tmp |= 1;
        !          1069:        if (info->flags & USE_BIG_BUF)
        !          1070:            tmp |= 2;
        !          1071:        if (info->flags & HAS_IBM_MISC)
        !          1072:            tmp |= 8;
        !          1073:        outb_p(tmp, nic_base + PCNET_MISC);
        !          1074:     }
        !          1075:     if (info->flags & IS_DL10022) {
        !          1076:        if (info->flags & HAS_MII) {
        !          1077:            mdio_reset(nic_base + DLINK_GPIO, info->eth_phy);
        !          1078:            /* Restart MII autonegotiation */
        !          1079:            mdio_write(nic_base + DLINK_GPIO, info->eth_phy, 0, 0x0000);
        !          1080:            mdio_write(nic_base + DLINK_GPIO, info->eth_phy, 0, 0x1200);
        !          1081:            info->mii_reset = jiffies;
        !          1082:        } else {
        !          1083:            outb(full_duplex ? 4 : 0, nic_base + DLINK_DIAG);
        !          1084:        }
        !          1085:     }
        !          1086: }
        !          1087: 
        !          1088: /*====================================================================*/
        !          1089: 
        !          1090: static void mii_phy_probe(struct net_device *dev)
        !          1091: {
        !          1092:     pcnet_dev_t *info = (pcnet_dev_t *)dev;    
        !          1093:     ioaddr_t mii_addr = dev->base_addr + DLINK_GPIO;
        !          1094:     int i;
        !          1095:     u_int tmp, phyid;
        !          1096: 
        !          1097:     for (i = 31; i >= 0; i--) {
        !          1098:        tmp = mdio_read(mii_addr, i, 1);
        !          1099:        if ((tmp == 0) || (tmp == 0xffff))
        !          1100:            continue;
        !          1101:        tmp = mdio_read(mii_addr, i, MII_PHYID_REG1);
        !          1102:        phyid = tmp << 16;
        !          1103:        phyid |= mdio_read(mii_addr, i, MII_PHYID_REG2);
        !          1104:        phyid &= MII_PHYID_REV_MASK;
        !          1105:        DEBUG(0, "%s: MII at %d is 0x%08x\n", dev->name, i, phyid);
        !          1106:        if (phyid == AM79C9XX_HOME_PHY) {
        !          1107:            info->pna_phy = i;
        !          1108:        } else if (phyid != AM79C9XX_ETH_PHY) {
        !          1109:            info->eth_phy = i;
        !          1110:        }
        !          1111:     }
        !          1112: }
        !          1113: 
        !          1114: static int pcnet_open(struct net_device *dev)
        !          1115: {
        !          1116:     pcnet_dev_t *info = (pcnet_dev_t *)dev;
        !          1117:     dev_link_t *link = &info->link;
        !          1118:     
        !          1119:     DEBUG(2, "pcnet_open('%s')\n", dev->name);
        !          1120: 
        !          1121:     if (!DEV_OK(link))
        !          1122:        return -ENODEV;
        !          1123: 
        !          1124:     link->open++;
        !          1125:     MOD_INC_USE_COUNT;
        !          1126: 
        !          1127:     set_misc_reg(dev);
        !          1128:     request_irq(dev->irq, ei_irq_wrapper, SA_SHIRQ, dev_info, dev);
        !          1129: 
        !          1130:     info->phy_id = info->eth_phy;
        !          1131:     info->link_status = 0x00;
        !          1132:     info->watchdog.function = &ei_watchdog;
        !          1133:     info->watchdog.data = (u_long)info;
        !          1134:     info->watchdog.expires = jiffies + HZ;
        !          1135:     add_timer(&info->watchdog);
        !          1136: 
        !          1137:     return ei_open(dev);
        !          1138: } /* pcnet_open */
        !          1139: 
        !          1140: /*====================================================================*/
        !          1141: 
        !          1142: static int pcnet_close(struct net_device *dev)
        !          1143: {
        !          1144:     pcnet_dev_t *info = (pcnet_dev_t *)dev;
        !          1145:     dev_link_t *link = &info->link;
        !          1146: 
        !          1147:     DEBUG(2, "pcnet_close('%s')\n", dev->name);
        !          1148: 
        !          1149:     ei_close(dev);
        !          1150:     free_irq(dev->irq, dev);
        !          1151:     
        !          1152:     link->open--;
        !          1153:     netif_stop_queue(dev);
        !          1154:     netif_mark_down(dev);
        !          1155:     del_timer(&info->watchdog);
        !          1156:     if (link->state & DEV_STALE_CONFIG)
        !          1157:        mod_timer(&link->release, jiffies + HZ/20);
        !          1158: 
        !          1159:     MOD_DEC_USE_COUNT;
        !          1160: 
        !          1161:     return 0;
        !          1162: } /* pcnet_close */
        !          1163: 
        !          1164: /*======================================================================
        !          1165: 
        !          1166:     Hard reset the card.  This used to pause for the same period that
        !          1167:     a 8390 reset command required, but that shouldn't be necessary.
        !          1168: 
        !          1169: ======================================================================*/
        !          1170: 
        !          1171: static void pcnet_reset_8390(struct net_device *dev)
        !          1172: {
        !          1173:     ioaddr_t nic_base = dev->base_addr;
        !          1174:     int i;
        !          1175: 
        !          1176:     ei_status.txing = ei_status.dmaing = 0;
        !          1177: 
        !          1178:     outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, nic_base + E8390_CMD);
        !          1179: 
        !          1180:     outb(inb(nic_base + PCNET_RESET), nic_base + PCNET_RESET);
        !          1181: 
        !          1182:     for (i = 0; i < 100; i++) {
        !          1183:        if ((inb_p(nic_base+EN0_ISR) & ENISR_RESET) != 0)
        !          1184:            break;
        !          1185:        udelay(100);
        !          1186:     }
        !          1187:     outb_p(ENISR_RESET, nic_base + EN0_ISR); /* Ack intr. */
        !          1188:     
        !          1189:     if (i == 100)
        !          1190:        printk(KERN_ERR "%s: pcnet_reset_8390() did not complete.\n",
        !          1191:               dev->name);
        !          1192:     set_misc_reg(dev);
        !          1193:     
        !          1194: } /* pcnet_reset_8390 */
        !          1195: 
        !          1196: /*====================================================================*/
        !          1197: 
        !          1198: static int set_config(struct net_device *dev, struct ifmap *map)
        !          1199: {
        !          1200:     pcnet_dev_t *info = (pcnet_dev_t *)dev;
        !          1201:     if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) {
        !          1202:        if (!(info->flags & HAS_MISC_REG))
        !          1203:            return -EOPNOTSUPP;
        !          1204:        else if ((map->port < 1) || (map->port > 2))
        !          1205:            return -EINVAL;
        !          1206:        dev->if_port = map->port;
        !          1207:        printk(KERN_INFO "%s: switched to %s port\n",
        !          1208:               dev->name, if_names[dev->if_port]);
        !          1209:        NS8390_init(dev, 1);
        !          1210:     }
        !          1211:     return 0;
        !          1212: }
        !          1213: 
        !          1214: /*====================================================================*/
        !          1215: 
        !          1216: static void ei_irq_wrapper(int irq, void *dev_id, struct pt_regs *regs)
        !          1217: {
        !          1218:     pcnet_dev_t *info = dev_id;
        !          1219:     info->stale = 0;
        !          1220:     ei_interrupt(irq, dev_id, regs);
        !          1221: }
        !          1222: 
        !          1223: static void ei_watchdog(u_long arg)
        !          1224: {
        !          1225:     pcnet_dev_t *info = (pcnet_dev_t *)(arg);
        !          1226:     struct net_device *dev = &info->dev;
        !          1227:     ioaddr_t nic_base = dev->base_addr;
        !          1228:     ioaddr_t mii_addr = nic_base + DLINK_GPIO;
        !          1229:     u_short link;
        !          1230: 
        !          1231:     if (!netif_device_present(dev)) goto reschedule;
        !          1232: 
        !          1233:     /* Check for pending interrupt with expired latency timer: with
        !          1234:        this, we can limp along even if the interrupt is blocked */
        !          1235:     outb_p(E8390_NODMA+E8390_PAGE0, nic_base + E8390_CMD);
        !          1236:     if (info->stale++ && (inb_p(nic_base + EN0_ISR) & ENISR_ALL)) {
        !          1237:        if (!info->fast_poll)
        !          1238:            printk(KERN_INFO "%s: interrupt(s) dropped!\n", dev->name);
        !          1239:        ei_irq_wrapper(dev->irq, dev, NULL);
        !          1240:        info->fast_poll = HZ;
        !          1241:     }
        !          1242:     if (info->fast_poll) {
        !          1243:        info->fast_poll--;
        !          1244:        info->watchdog.expires = jiffies + 1;
        !          1245:        add_timer(&info->watchdog);
        !          1246:        return;
        !          1247:     }
        !          1248: 
        !          1249:     if (!(info->flags & HAS_MII))
        !          1250:        goto reschedule;
        !          1251: 
        !          1252:     mdio_read(mii_addr, info->phy_id, 1);
        !          1253:     link = mdio_read(mii_addr, info->phy_id, 1);
        !          1254:     if (!link || (link == 0xffff)) {
        !          1255:        if (info->eth_phy) {
        !          1256:            info->phy_id = info->eth_phy = 0;
        !          1257:        } else {
        !          1258:            printk(KERN_INFO "%s: MII is missing!\n", dev->name);
        !          1259:            info->flags &= ~HAS_MII;
        !          1260:        }
        !          1261:        goto reschedule;
        !          1262:     }
        !          1263: 
        !          1264:     link &= 0x0004;
        !          1265:     if (link != info->link_status) {
        !          1266:        u_short p = mdio_read(mii_addr, info->phy_id, 5);
        !          1267:        printk(KERN_INFO "%s: %s link beat\n", dev->name,
        !          1268:               (link) ? "found" : "lost");
        !          1269:        if (link && (info->flags & IS_DL10022)) {
        !          1270:            /* Disable collision detection on full duplex links */
        !          1271:            outb((p & 0x0140) ? 4 : 0, nic_base + DLINK_DIAG);
        !          1272:        } else if (link && (info->flags & IS_DL10019)) {
        !          1273:            /* Disable collision detection on full duplex links */
        !          1274:            write_asic(dev->base_addr, 4, (p & 0x140) ? DL19FDUPLX : 0);
        !          1275:        }
        !          1276:        if (link) {
        !          1277:            if (info->phy_id == info->eth_phy) {
        !          1278:                if (p)
        !          1279:                    printk(KERN_INFO "%s: autonegotiation complete: "
        !          1280:                           "%sbaseT-%cD selected\n", dev->name,
        !          1281:                           ((p & 0x0180) ? "100" : "10"),
        !          1282:                           ((p & 0x0140) ? 'F' : 'H'));
        !          1283:                else
        !          1284:                    printk(KERN_INFO "%s: link partner did not "
        !          1285:                           "autonegotiate\n", dev->name);
        !          1286:            }
        !          1287:            NS8390_init(dev, 1);
        !          1288:        }
        !          1289:        info->link_status = link;
        !          1290:     }
        !          1291:     if (info->pna_phy && (jiffies - info->mii_reset > 6*HZ)) {
        !          1292:        link = mdio_read(mii_addr, info->eth_phy, 1) & 0x0004;
        !          1293:        if (((info->phy_id == info->pna_phy) && link) ||
        !          1294:            ((info->phy_id != info->pna_phy) && !link)) {
        !          1295:            /* isolate this MII and try flipping to the other one */
        !          1296:            mdio_write(mii_addr, info->phy_id, 0, 0x0400);
        !          1297:            info->phy_id ^= info->pna_phy ^ info->eth_phy;
        !          1298:            printk(KERN_INFO "%s: switched to %s transceiver\n", dev->name,
        !          1299:                   (info->phy_id == info->eth_phy) ? "ethernet" : "PNA");
        !          1300:            mdio_write(mii_addr, info->phy_id, 0,
        !          1301:                       (info->phy_id == info->eth_phy) ? 0x1000 : 0);
        !          1302:            info->link_status = 0;
        !          1303:            info->mii_reset = jiffies;
        !          1304:        }
        !          1305:     }
        !          1306: 
        !          1307: reschedule:
        !          1308:     info->watchdog.expires = jiffies + HZ;
        !          1309:     add_timer(&info->watchdog);
        !          1310: }
        !          1311: 
        !          1312: /*====================================================================*/
        !          1313: 
        !          1314: static int ei_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
        !          1315: {
        !          1316:     pcnet_dev_t *info = (pcnet_dev_t *)dev;
        !          1317:     u16 *data = (u16 *)&rq->ifr_data;
        !          1318:     ioaddr_t mii_addr = dev->base_addr + DLINK_GPIO;
        !          1319:     switch (cmd) {
        !          1320:     case SIOCDEVPRIVATE:
        !          1321:        data[0] = info->phy_id;
        !          1322:     case SIOCDEVPRIVATE+1:
        !          1323:        data[3] = mdio_read(mii_addr, data[0], data[1] & 0x1f);
        !          1324:        return 0;
        !          1325:     case SIOCDEVPRIVATE+2:
        !          1326:        if (!capable(CAP_NET_ADMIN))
        !          1327:            return -EPERM;
        !          1328:        mdio_write(mii_addr, data[0], data[1] & 0x1f, data[2]);
        !          1329:        return 0;
        !          1330:     }
        !          1331:     return -EOPNOTSUPP;
        !          1332: }
        !          1333: 
        !          1334: /*====================================================================*/
        !          1335: 
        !          1336: static void dma_get_8390_hdr(struct net_device *dev,
        !          1337:                             struct e8390_pkt_hdr *hdr,
        !          1338:                             int ring_page)
        !          1339: {
        !          1340:     ioaddr_t nic_base = dev->base_addr;
        !          1341: 
        !          1342:     if (ei_status.dmaing) {
        !          1343:        printk(KERN_NOTICE "%s: DMAing conflict in dma_block_input."
        !          1344:               "[DMAstat:%1x][irqlock:%1x]\n",
        !          1345:               dev->name, ei_status.dmaing, ei_status.irqlock);
        !          1346:        return;
        !          1347:     }
        !          1348:     
        !          1349:     ei_status.dmaing |= 0x01;
        !          1350:     outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base + PCNET_CMD);
        !          1351:     outb_p(sizeof(struct e8390_pkt_hdr), nic_base + EN0_RCNTLO);
        !          1352:     outb_p(0, nic_base + EN0_RCNTHI);
        !          1353:     outb_p(0, nic_base + EN0_RSARLO);          /* On page boundary */
        !          1354:     outb_p(ring_page, nic_base + EN0_RSARHI);
        !          1355:     outb_p(E8390_RREAD+E8390_START, nic_base + PCNET_CMD);
        !          1356: 
        !          1357:     insw(nic_base + PCNET_DATAPORT, hdr,
        !          1358:         sizeof(struct e8390_pkt_hdr)>>1);
        !          1359:     /* Fix for big endian systems */
        !          1360:     hdr->count = le16_to_cpu(hdr->count);
        !          1361: 
        !          1362:     outb_p(ENISR_RDC, nic_base + EN0_ISR);     /* Ack intr. */
        !          1363:     ei_status.dmaing &= ~0x01;
        !          1364: }
        !          1365: 
        !          1366: /*====================================================================*/
        !          1367: 
        !          1368: static void dma_block_input(struct net_device *dev, int count,
        !          1369:                            struct sk_buff *skb, int ring_offset)
        !          1370: {
        !          1371:     ioaddr_t nic_base = dev->base_addr;
        !          1372:     int xfer_count = count;
        !          1373:     char *buf = skb->data;
        !          1374: 
        !          1375: #ifdef PCMCIA_DEBUG
        !          1376:     if ((ei_debug > 4) && (count != 4))
        !          1377:        printk(KERN_DEBUG "%s: [bi=%d]\n", dev->name, count+4);
        !          1378: #endif
        !          1379:     if (ei_status.dmaing) {
        !          1380:        printk(KERN_NOTICE "%s: DMAing conflict in dma_block_input."
        !          1381:               "[DMAstat:%1x][irqlock:%1x]\n",
        !          1382:               dev->name, ei_status.dmaing, ei_status.irqlock);
        !          1383:        return;
        !          1384:     }
        !          1385:     ei_status.dmaing |= 0x01;
        !          1386:     outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base + PCNET_CMD);
        !          1387:     outb_p(count & 0xff, nic_base + EN0_RCNTLO);
        !          1388:     outb_p(count >> 8, nic_base + EN0_RCNTHI);
        !          1389:     outb_p(ring_offset & 0xff, nic_base + EN0_RSARLO);
        !          1390:     outb_p(ring_offset >> 8, nic_base + EN0_RSARHI);
        !          1391:     outb_p(E8390_RREAD+E8390_START, nic_base + PCNET_CMD);
        !          1392: 
        !          1393:     insw(nic_base + PCNET_DATAPORT,buf,count>>1);
        !          1394:     if (count & 0x01)
        !          1395:        buf[count-1] = inb(nic_base + PCNET_DATAPORT), xfer_count++;
        !          1396: 
        !          1397:     /* This was for the ALPHA version only, but enough people have
        !          1398:        encountering problems that it is still here. */
        !          1399: #ifdef PCMCIA_DEBUG
        !          1400:     if (ei_debug > 4) {                /* DMA termination address check... */
        !          1401:        int addr, tries = 20;
        !          1402:        do {
        !          1403:            /* DON'T check for 'inb_p(EN0_ISR) & ENISR_RDC' here
        !          1404:               -- it's broken for Rx on some cards! */
        !          1405:            int high = inb_p(nic_base + EN0_RSARHI);
        !          1406:            int low = inb_p(nic_base + EN0_RSARLO);
        !          1407:            addr = (high << 8) + low;
        !          1408:            if (((ring_offset + xfer_count) & 0xff) == (addr & 0xff))
        !          1409:                break;
        !          1410:        } while (--tries > 0);
        !          1411:        if (tries <= 0)
        !          1412:            printk(KERN_NOTICE "%s: RX transfer address mismatch,"
        !          1413:                   "%#4.4x (expected) vs. %#4.4x (actual).\n",
        !          1414:                   dev->name, ring_offset + xfer_count, addr);
        !          1415:     }
        !          1416: #endif
        !          1417:     outb_p(ENISR_RDC, nic_base + EN0_ISR);     /* Ack intr. */
        !          1418:     ei_status.dmaing &= ~0x01;
        !          1419: } /* dma_block_input */
        !          1420: 
        !          1421: /*====================================================================*/
        !          1422: 
        !          1423: static void dma_block_output(struct net_device *dev, int count,
        !          1424:                             const u_char *buf, const int start_page)
        !          1425: {
        !          1426:     ioaddr_t nic_base = dev->base_addr;
        !          1427:     pcnet_dev_t *info = (pcnet_dev_t *)dev;
        !          1428: #ifdef PCMCIA_DEBUG
        !          1429:     int retries = 0;
        !          1430: #endif
        !          1431:     u_long dma_start;
        !          1432: 
        !          1433: #ifdef PCMCIA_DEBUG
        !          1434:     if (ei_debug > 4)
        !          1435:        printk(KERN_DEBUG "%s: [bo=%d]\n", dev->name, count);
        !          1436: #endif
        !          1437: 
        !          1438:     /* Round the count up for word writes.  Do we need to do this?
        !          1439:        What effect will an odd byte count have on the 8390?
        !          1440:        I should check someday. */
        !          1441:     if (count & 0x01)
        !          1442:        count++;
        !          1443:     if (ei_status.dmaing) {
        !          1444:        printk(KERN_NOTICE "%s: DMAing conflict in dma_block_output."
        !          1445:               "[DMAstat:%1x][irqlock:%1x]\n",
        !          1446:               dev->name, ei_status.dmaing, ei_status.irqlock);
        !          1447:        return;
        !          1448:     }
        !          1449:     ei_status.dmaing |= 0x01;
        !          1450:     /* We should already be in page 0, but to be safe... */
        !          1451:     outb_p(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base+PCNET_CMD);
        !          1452: 
        !          1453: #ifdef PCMCIA_DEBUG
        !          1454:   retry:
        !          1455: #endif
        !          1456: 
        !          1457:     outb_p(ENISR_RDC, nic_base + EN0_ISR);
        !          1458: 
        !          1459:     /* Now the normal output. */
        !          1460:     outb_p(count & 0xff, nic_base + EN0_RCNTLO);
        !          1461:     outb_p(count >> 8,   nic_base + EN0_RCNTHI);
        !          1462:     outb_p(0x00, nic_base + EN0_RSARLO);
        !          1463:     outb_p(start_page, nic_base + EN0_RSARHI);
        !          1464: 
        !          1465:     outb_p(E8390_RWRITE+E8390_START, nic_base + PCNET_CMD);
        !          1466:     outsw(nic_base + PCNET_DATAPORT, buf, count>>1);
        !          1467: 
        !          1468:     dma_start = jiffies;
        !          1469: 
        !          1470: #ifdef PCMCIA_DEBUG
        !          1471:     /* This was for the ALPHA version only, but enough people have
        !          1472:        encountering problems that it is still here. */
        !          1473:     if (ei_debug > 4) {        /* DMA termination address check... */
        !          1474:        int addr, tries = 20;
        !          1475:        do {
        !          1476:            int high = inb_p(nic_base + EN0_RSARHI);
        !          1477:            int low = inb_p(nic_base + EN0_RSARLO);
        !          1478:            addr = (high << 8) + low;
        !          1479:            if ((start_page << 8) + count == addr)
        !          1480:                break;
        !          1481:        } while (--tries > 0);
        !          1482:        if (tries <= 0) {
        !          1483:            printk(KERN_NOTICE "%s: Tx packet transfer address mismatch,"
        !          1484:                   "%#4.4x (expected) vs. %#4.4x (actual).\n",
        !          1485:                   dev->name, (start_page << 8) + count, addr);
        !          1486:            if (retries++ == 0)
        !          1487:                goto retry;
        !          1488:        }
        !          1489:     }
        !          1490: #endif
        !          1491: 
        !          1492:     while ((inb_p(nic_base + EN0_ISR) & ENISR_RDC) == 0)
        !          1493:        if (jiffies - dma_start > PCNET_RDC_TIMEOUT) {
        !          1494:            printk(KERN_NOTICE "%s: timeout waiting for Tx RDC.\n",
        !          1495:                   dev->name);
        !          1496:            pcnet_reset_8390(dev);
        !          1497:            NS8390_init(dev, 1);
        !          1498:            break;
        !          1499:        }
        !          1500: 
        !          1501:     outb_p(ENISR_RDC, nic_base + EN0_ISR);     /* Ack intr. */
        !          1502:     if (info->flags & DELAY_OUTPUT)
        !          1503:        udelay((long)delay_time);
        !          1504:     ei_status.dmaing &= ~0x01;
        !          1505: }
        !          1506: 
        !          1507: /*====================================================================*/
        !          1508: 
        !          1509: static int setup_dma_config(dev_link_t *link, int start_pg,
        !          1510:                            int stop_pg)
        !          1511: {
        !          1512:     struct net_device *dev = link->priv;
        !          1513: 
        !          1514:     ei_status.tx_start_page = start_pg;
        !          1515:     ei_status.rx_start_page = start_pg + TX_PAGES;
        !          1516:     ei_status.stop_page = stop_pg;
        !          1517: 
        !          1518:     /* set up block i/o functions */
        !          1519:     ei_status.get_8390_hdr = &dma_get_8390_hdr;
        !          1520:     ei_status.block_input = &dma_block_input;
        !          1521:     ei_status.block_output = &dma_block_output;
        !          1522: 
        !          1523:     return 0;
        !          1524: }
        !          1525: 
        !          1526: /*====================================================================*/
        !          1527: 
        !          1528: static void copyin(u_char *dest, u_char *src, int c)
        !          1529: {
        !          1530:     u_short *d = (u_short *)dest, *s = (u_short *)src;
        !          1531:     int odd;
        !          1532: 
        !          1533:     if (c <= 0)
        !          1534:        return;
        !          1535:     odd = (c & 1); c >>= 1;
        !          1536: 
        !          1537:     if (c) {
        !          1538:        do { *d++ = readw_ns(s++); } while (--c);
        !          1539:     }
        !          1540:     /* get last byte by fetching a word and masking */
        !          1541:     if (odd)
        !          1542:        *((u_char *)d) = readw(s) & 0xff;
        !          1543: }
        !          1544: 
        !          1545: static void copyout(u_char *dest, const u_char *src, int c)
        !          1546: {
        !          1547:     u_short *d = (u_short *)dest, *s = (u_short *)src;
        !          1548:     int odd;
        !          1549: 
        !          1550:     if (c <= 0)
        !          1551:        return;
        !          1552:     odd = (c & 1); c >>= 1;
        !          1553: 
        !          1554:     if (c) {
        !          1555:        do { writew_ns(*s++, d++); } while (--c);
        !          1556:     }
        !          1557:     /* copy last byte doing a read-modify-write */
        !          1558:     if (odd)
        !          1559:        writew((readw(d) & 0xff00) | *(u_char *)s, d);
        !          1560: }
        !          1561: 
        !          1562: /*====================================================================*/
        !          1563: 
        !          1564: static void shmem_get_8390_hdr(struct net_device *dev,
        !          1565:                               struct e8390_pkt_hdr *hdr,
        !          1566:                               int ring_page)
        !          1567: {
        !          1568:     void *xfer_start = (void *)(dev->rmem_start + (ring_page << 8)
        !          1569:                                - (ei_status.rx_start_page << 8));
        !          1570:     
        !          1571:     copyin((void *)hdr, xfer_start, sizeof(struct e8390_pkt_hdr));
        !          1572:     /* Fix for big endian systems */
        !          1573:     hdr->count = le16_to_cpu(hdr->count);
        !          1574: }
        !          1575: 
        !          1576: /*====================================================================*/
        !          1577: 
        !          1578: static void shmem_block_input(struct net_device *dev, int count,
        !          1579:                              struct sk_buff *skb, int ring_offset)
        !          1580: {
        !          1581:     void *xfer_start = (void *)(dev->rmem_start + ring_offset
        !          1582:                                - (ei_status.rx_start_page << 8));
        !          1583:     char *buf = skb->data;
        !          1584:     
        !          1585:     if (xfer_start + count > (void *)dev->rmem_end) {
        !          1586:        /* We must wrap the input move. */
        !          1587:        int semi_count = (void*)dev->rmem_end - xfer_start;
        !          1588:        copyin(buf, xfer_start, semi_count);
        !          1589:        buf += semi_count;
        !          1590:        ring_offset = ei_status.rx_start_page << 8;
        !          1591:        xfer_start = (void *)dev->rmem_start;
        !          1592:        count -= semi_count;
        !          1593:     }
        !          1594:     copyin(buf, xfer_start, count);
        !          1595: }
        !          1596: 
        !          1597: /*====================================================================*/
        !          1598: 
        !          1599: static void shmem_block_output(struct net_device *dev, int count,
        !          1600:                               const u_char *buf, const int start_page)
        !          1601: {
        !          1602:     void *shmem = (void *)dev->mem_start + (start_page << 8);
        !          1603:     shmem -= ei_status.tx_start_page << 8;
        !          1604:     copyout(shmem, buf, count);
        !          1605: }
        !          1606: 
        !          1607: /*====================================================================*/
        !          1608: 
        !          1609: static int setup_shmem_window(dev_link_t *link, int start_pg,
        !          1610:                              int stop_pg, int cm_offset)
        !          1611: {
        !          1612:     struct net_device *dev = link->priv;
        !          1613:     pcnet_dev_t *info = link->priv;
        !          1614:     win_req_t req;
        !          1615:     memreq_t mem;
        !          1616:     int i, window_size, offset, last_ret, last_fn;
        !          1617: 
        !          1618:     window_size = (stop_pg - start_pg) << 8;
        !          1619:     if (window_size > 32 * 1024)
        !          1620:        window_size = 32 * 1024;
        !          1621: 
        !          1622:     /* Make sure it's a power of two.  */
        !          1623:     while ((window_size & (window_size - 1)) != 0)
        !          1624:        window_size += window_size & ~(window_size - 1);
        !          1625: 
        !          1626:     /* Allocate a memory window */
        !          1627:     req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE;
        !          1628:     req.Attributes |= WIN_USE_WAIT;
        !          1629:     req.Base = 0; req.Size = window_size;
        !          1630:     req.AccessSpeed = mem_speed;
        !          1631:     link->win = (window_handle_t)link->handle;
        !          1632:     CS_CHECK(RequestWindow, &link->win, &req);
        !          1633: 
        !          1634:     mem.CardOffset = (start_pg << 8) + cm_offset;
        !          1635:     offset = mem.CardOffset % window_size;
        !          1636:     mem.CardOffset -= offset;
        !          1637:     mem.Page = 0;
        !          1638:     CS_CHECK(MapMemPage, link->win, &mem);
        !          1639: 
        !          1640:     /* Try scribbling on the buffer */
        !          1641:     info->base = ioremap(req.Base, window_size);
        !          1642:     for (i = 0; i < (TX_PAGES<<8); i += 2)
        !          1643:        writew_ns((i>>1), info->base+offset+i);
        !          1644:     udelay(100);
        !          1645:     for (i = 0; i < (TX_PAGES<<8); i += 2)
        !          1646:        if (readw_ns(info->base+offset+i) != (i>>1)) break;
        !          1647:     pcnet_reset_8390(dev);
        !          1648:     if (i != (TX_PAGES<<8)) {
        !          1649:        iounmap(info->base);
        !          1650:        CardServices(ReleaseWindow, link->win);
        !          1651:        info->base = NULL; link->win = NULL;
        !          1652:        goto failed;
        !          1653:     }
        !          1654:     
        !          1655:     dev->mem_start = (u_long)info->base + offset;
        !          1656:     dev->rmem_start = dev->mem_start + (TX_PAGES<<8);
        !          1657:     dev->mem_end = dev->rmem_end = (u_long)info->base + req.Size;
        !          1658: 
        !          1659:     ei_status.tx_start_page = start_pg;
        !          1660:     ei_status.rx_start_page = start_pg + TX_PAGES;
        !          1661:     ei_status.stop_page = start_pg + ((req.Size - offset) >> 8);
        !          1662: 
        !          1663:     /* set up block i/o functions */
        !          1664:     ei_status.get_8390_hdr = &shmem_get_8390_hdr;
        !          1665:     ei_status.block_input = &shmem_block_input;
        !          1666:     ei_status.block_output = &shmem_block_output;
        !          1667: 
        !          1668:     info->flags |= USE_SHMEM;
        !          1669:     return 0;
        !          1670: 
        !          1671: cs_failed:
        !          1672:     cs_error(link->handle, last_fn, last_ret);
        !          1673: failed:
        !          1674:     return 1;
        !          1675: }
        !          1676: 
        !          1677: /*====================================================================*/
        !          1678: 
        !          1679: static int __init init_pcnet_cs(void)
        !          1680: {
        !          1681:     servinfo_t serv;
        !          1682:     DEBUG(0, "%s\n", version);
        !          1683:     CardServices(GetCardServicesInfo, &serv);
        !          1684:     if (serv.Revision != CS_RELEASE_CODE) {
        !          1685:        printk(KERN_NOTICE "pcnet_cs: Card Services release "
        !          1686:               "does not match!\n");
        !          1687:        return -EINVAL;
        !          1688:     }
        !          1689:     register_pccard_driver(&dev_info, &pcnet_attach, &pcnet_detach);
        !          1690:     return 0;
        !          1691: }
        !          1692: 
        !          1693: static void __exit exit_pcnet_cs(void)
        !          1694: {
        !          1695:     DEBUG(0, "pcnet_cs: unloading\n");
        !          1696:     unregister_pccard_driver(&dev_info);
        !          1697:     while (dev_list != NULL)
        !          1698:        pcnet_detach(dev_list);
        !          1699: }
        !          1700: 
        !          1701: module_init(init_pcnet_cs);
        !          1702: module_exit(exit_pcnet_cs);

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.