11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Driver for high-speed SCC boards (those with DMA support)
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 1997-2000 Klaus Kudielka
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * S5SCC/DMA support by Janko Koleznik S52HI
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License as published by
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the Free Software Foundation; either version 2 of the License, or
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (at your option) any later version.
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is distributed in the hope that it will be useful,
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * GNU General Public License for more details.
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * You should have received a copy of the GNU General Public License
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * along with this program; if not, write to the Free Software
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
241977f032722c27ee3730284582fd3991ad9ac81bJiri Slaby#include <linux/bitops.h>
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h>
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/if_arp.h>
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/in.h>
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h>
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h>
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mm.h>
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/netdevice.h>
355a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/rtnetlink.h>
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sockios.h>
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/workqueue.h>
3960063497a95e716c9a689af3be2687d261f115b4Arun Sharma#include <linux/atomic.h>
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/dma.h>
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h>
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/irq.h>
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h>
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/ax25.h>
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "z8530.h"
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Number of buffers per channel */
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define NUM_TX_BUF      2	/* NUM_TX_BUF >= 1 (min. 2 recommended) */
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define NUM_RX_BUF      6	/* NUM_RX_BUF >= 1 (min. 2 recommended) */
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BUF_SIZE        1576	/* BUF_SIZE >= mtu + hard_header_len */
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Cards supported */
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define HW_PI           { "Ottawa PI", 0x300, 0x20, 0x10, 8, \
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                            0, 8, 1843200, 3686400 }
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define HW_PI2          { "Ottawa PI2", 0x300, 0x20, 0x10, 8, \
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    0, 8, 3686400, 7372800 }
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define HW_TWIN         { "Gracilis PackeTwin", 0x200, 0x10, 0x10, 32, \
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    0, 4, 6144000, 6144000 }
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define HW_S5           { "S5SCC/DMA", 0x200, 0x10, 0x10, 32, \
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                          0, 8, 4915200, 9830400 }
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define HARDWARE        { HW_PI, HW_PI2, HW_TWIN, HW_S5 }
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMR_0_HZ        25600	/* Frequency of timer 0 */
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TYPE_PI         0
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TYPE_PI2        1
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TYPE_TWIN       2
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TYPE_S5         3
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define NUM_TYPES       4
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MAX_NUM_DEVS    32
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* SCC chips supported */
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Z8530           0
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Z85C30          1
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Z85230          2
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CHIPNAMES       { "Z8530", "Z85C30", "Z85230" }
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* I/O registers */
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 8530 registers relative to card base */
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SCCB_CMD        0x00
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SCCB_DATA       0x01
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SCCA_CMD        0x02
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SCCA_DATA       0x03
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 8253/8254 registers relative to card base */
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMR_CNT0        0x00
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMR_CNT1        0x01
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMR_CNT2        0x02
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMR_CTRL        0x03
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Additional PI/PI2 registers relative to card base */
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PI_DREQ_MASK    0x04
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Additional PackeTwin registers relative to card base */
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TWIN_INT_REG    0x08
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TWIN_CLR_TMR1   0x09
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TWIN_CLR_TMR2   0x0a
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TWIN_SPARE_1    0x0b
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TWIN_DMA_CFG    0x08
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TWIN_SERIAL_CFG 0x09
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TWIN_DMA_CLR_FF 0x0a
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TWIN_SPARE_2    0x0b
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* PackeTwin I/O register values */
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* INT_REG */
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TWIN_SCC_MSK       0x01
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TWIN_TMR1_MSK      0x02
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TWIN_TMR2_MSK      0x04
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TWIN_INT_MSK       0x07
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* SERIAL_CFG */
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TWIN_DTRA_ON       0x01
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TWIN_DTRB_ON       0x02
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TWIN_EXTCLKA       0x04
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TWIN_EXTCLKB       0x08
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TWIN_LOOPA_ON      0x10
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TWIN_LOOPB_ON      0x20
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TWIN_EI            0x80
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* DMA_CFG */
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TWIN_DMA_HDX_T1    0x08
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TWIN_DMA_HDX_R1    0x0a
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TWIN_DMA_HDX_T3    0x14
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TWIN_DMA_HDX_R3    0x16
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TWIN_DMA_FDX_T3R1  0x1b
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TWIN_DMA_FDX_T1R3  0x1d
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Status values */
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IDLE      0
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TX_HEAD   1
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TX_DATA   2
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TX_PAUSE  3
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TX_TAIL   4
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RTS_OFF   5
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define WAIT      6
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DCD_ON    7
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RX_ON     8
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DCD_OFF   9
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Ioctls */
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SIOCGSCCPARAM SIOCDEVPRIVATE
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SIOCSSCCPARAM (SIOCDEVPRIVATE+1)
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Data types */
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct scc_param {
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int pclk_hz;		/* frequency of BRG input (don't change) */
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int brg_tc;		/* BRG terminal count; BRG disabled if < 0 */
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int nrzi;		/* 0 (nrz), 1 (nrzi) */
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int clocks;		/* see dmascc_cfg documentation */
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int txdelay;		/* [1/TMR_0_HZ] */
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int txtimeout;		/* [1/HZ] */
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int txtail;		/* [1/TMR_0_HZ] */
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int waittime;		/* [1/TMR_0_HZ] */
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int slottime;		/* [1/TMR_0_HZ] */
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int persist;		/* 1 ... 256 */
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int dma;		/* -1 (disable), 0, 1, 3 */
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int txpause;		/* [1/TMR_0_HZ] */
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int rtsoff;		/* [1/TMR_0_HZ] */
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int dcdon;		/* [1/TMR_0_HZ] */
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int dcdoff;		/* [1/TMR_0_HZ] */
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct scc_hardware {
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char *name;
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int io_region;
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int io_delta;
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int io_size;
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int num_devs;
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int scc_offset;
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int tmr_offset;
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int tmr_hz;
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int pclk_hz;
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct scc_priv {
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int type;
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int chip;
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev;
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct scc_info *info;
19913c0582d91ab63087a30addcfe42874541ca2689Stephen Hemminger
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int channel;
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int card_base, scc_cmd, scc_data;
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int tmr_cnt, tmr_ctrl, tmr_mode;
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct scc_param param;
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char rx_buf[NUM_RX_BUF][BUF_SIZE];
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int rx_len[NUM_RX_BUF];
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int rx_ptr;
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct work_struct rx_work;
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int rx_head, rx_tail, rx_count;
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int rx_over;
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char tx_buf[NUM_TX_BUF][BUF_SIZE];
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int tx_len[NUM_TX_BUF];
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int tx_ptr;
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int tx_head, tx_tail, tx_count;
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int state;
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long tx_start;
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int rr0;
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spinlock_t *register_lock;	/* Per scc_info */
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spinlock_t ring_lock;
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct scc_info {
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int irq_used;
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int twin_serial_cfg;
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev[2];
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct scc_priv priv[2];
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct scc_info *next;
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spinlock_t register_lock;	/* Per device register lock */
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Function declarations */
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int setup_adapter(int card_base, int type, int n) __init;
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void write_scc(struct scc_priv *priv, int reg, int val);
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void write_scc_data(struct scc_priv *priv, int val, int fast);
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int read_scc(struct scc_priv *priv, int reg);
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int read_scc_data(struct scc_priv *priv);
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int scc_open(struct net_device *dev);
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int scc_close(struct net_device *dev);
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int scc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int scc_send_packet(struct sk_buff *skb, struct net_device *dev);
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int scc_set_mac_address(struct net_device *dev, void *sa);
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void tx_on(struct scc_priv *priv);
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void rx_on(struct scc_priv *priv);
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void rx_off(struct scc_priv *priv);
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void start_timer(struct scc_priv *priv, int t, int r15);
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline unsigned char random(void);
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void z8530_isr(struct scc_info *info);
2527d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t scc_isr(int irq, void *dev_id);
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rx_isr(struct scc_priv *priv);
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void special_condition(struct scc_priv *priv, int rc);
2557a87b6c228b8d0cc54b9faa159732fcb2a6c9d0cAl Virostatic void rx_bh(struct work_struct *);
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void tx_isr(struct scc_priv *priv);
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void es_isr(struct scc_priv *priv);
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void tm_isr(struct scc_priv *priv);
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Initialization variables */
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int io[MAX_NUM_DEVS] __initdata = { 0, };
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
265cd8d627a6b66d9755637b4dad2083864a9bfce9aRandy Dunlap/* Beware! hw[] is also used in dmascc_exit(). */
266cd8d627a6b66d9755637b4dad2083864a9bfce9aRandy Dunlapstatic struct scc_hardware hw[NUM_TYPES] = HARDWARE;
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Global variables */
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct scc_info *first;
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned long rand;
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Klaus Kudielka");
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("Driver for high-speed SCC boards");
2778d3b33f67fdc0fb364a1ef6d8fbbea7c2e4e6c98Rusty Russellmodule_param_array(io, int, NULL, 0);
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit dmascc_exit(void)
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct scc_info *info;
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (first) {
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info = first;
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Unregister devices */
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i < 2; i++)
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			unregister_netdev(info->dev[i]);
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Reset board */
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (info->priv[0].type == TYPE_TWIN)
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			outb(0, info->dev[0]->base_addr + TWIN_SERIAL_CFG);
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		write_scc(&info->priv[0], R9, FHWRES);
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		release_region(info->dev[0]->base_addr,
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       hw[info->priv[0].type].io_size);
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i < 2; i++)
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			free_netdev(info->dev[i]);
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Free memory */
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		first = info->next;
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(info);
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init dmascc_init(void)
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int h, i, j, n;
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int base[MAX_NUM_DEVS], tcmd[MAX_NUM_DEVS], t0[MAX_NUM_DEVS],
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    t1[MAX_NUM_DEVS];
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned t_val;
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long time, start[MAX_NUM_DEVS], delay[MAX_NUM_DEVS],
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    counting[MAX_NUM_DEVS];
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Initialize random number generator */
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rand = jiffies;
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Cards found = 0 */
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	n = 0;
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Warning message */
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!io[0])
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_INFO "dmascc: autoprobing (dangerous)\n");
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Run autodetection for each card type */
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (h = 0; h < NUM_TYPES; h++) {
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (io[0]) {
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* User-specified I/O address regions */
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (i = 0; i < hw[h].num_devs; i++)
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				base[i] = 0;
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (i = 0; i < MAX_NUM_DEVS && io[i]; i++) {
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				j = (io[i] -
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     hw[h].io_region) / hw[h].io_delta;
3358e95a2026f3b43f7c3d676adaccd2de9532e8dccJoe Perches				if (j >= 0 && j < hw[h].num_devs &&
3368e95a2026f3b43f7c3d676adaccd2de9532e8dccJoe Perches				    hw[h].io_region +
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    j * hw[h].io_delta == io[i]) {
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					base[j] = io[i];
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Default I/O address regions */
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (i = 0; i < hw[h].num_devs; i++) {
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				base[i] =
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    hw[h].io_region + i * hw[h].io_delta;
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Check valid I/O address regions */
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i < hw[h].num_devs; i++)
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (base[i]) {
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (!request_region
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    (base[i], hw[h].io_size, "dmascc"))
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					base[i] = 0;
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				else {
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					tcmd[i] =
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					    base[i] + hw[h].tmr_offset +
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					    TMR_CTRL;
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					t0[i] =
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					    base[i] + hw[h].tmr_offset +
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					    TMR_CNT0;
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					t1[i] =
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					    base[i] + hw[h].tmr_offset +
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					    TMR_CNT1;
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Start timers */
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i < hw[h].num_devs; i++)
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (base[i]) {
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* Timer 0: LSB+MSB, Mode 3, TMR_0_HZ */
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				outb(0x36, tcmd[i]);
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				outb((hw[h].tmr_hz / TMR_0_HZ) & 0xFF,
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     t0[i]);
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				outb((hw[h].tmr_hz / TMR_0_HZ) >> 8,
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     t0[i]);
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* Timer 1: LSB+MSB, Mode 0, HZ/10 */
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				outb(0x70, tcmd[i]);
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				outb((TMR_0_HZ / HZ * 10) & 0xFF, t1[i]);
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				outb((TMR_0_HZ / HZ * 10) >> 8, t1[i]);
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				start[i] = jiffies;
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				delay[i] = 0;
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				counting[i] = 1;
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* Timer 2: LSB+MSB, Mode 0 */
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				outb(0xb0, tcmd[i]);
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		time = jiffies;
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Wait until counter registers are loaded */
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		udelay(2000000 / TMR_0_HZ);
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Timing loop */
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		while (jiffies - time < 13) {
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (i = 0; i < hw[h].num_devs; i++)
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (base[i] && counting[i]) {
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					/* Read back Timer 1: latch; read LSB; read MSB */
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					outb(0x40, tcmd[i]);
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					t_val =
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					    inb(t1[i]) + (inb(t1[i]) << 8);
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					/* Also check whether counter did wrap */
4008e95a2026f3b43f7c3d676adaccd2de9532e8dccJoe Perches					if (t_val == 0 ||
4018e95a2026f3b43f7c3d676adaccd2de9532e8dccJoe Perches					    t_val > TMR_0_HZ / HZ * 10)
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						counting[i] = 0;
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					delay[i] = jiffies - start[i];
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Evaluate measurements */
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i < hw[h].num_devs; i++)
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (base[i]) {
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if ((delay[i] >= 9 && delay[i] <= 11) &&
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    /* Ok, we have found an adapter */
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    (setup_adapter(base[i], h, n) == 0))
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					n++;
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				else
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					release_region(base[i],
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						       hw[h].io_size);
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}			/* NUM_TYPES */
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* If any adapter was successfully initialized, return ok */
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (n)
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* If no adapter found, return error */
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(KERN_INFO "dmascc: no adapters found\n");
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -EIO;
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(dmascc_init);
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(dmascc_exit);
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
433e2fdbc039aeac4ce614ee29f4b14bcef5ba000ddAdrian Bunkstatic void __init dev_setup(struct net_device *dev)
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->type = ARPHRD_AX25;
436c4bc7ee2e474819d3932e8d726fdf7cb0bdc00c1Ralf Baechle	dev->hard_header_len = AX25_MAX_HEADER_LEN;
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->mtu = 1500;
438c4bc7ee2e474819d3932e8d726fdf7cb0bdc00c1Ralf Baechle	dev->addr_len = AX25_ADDR_LEN;
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->tx_queue_len = 64;
44015b1c0e822f578306332d4f4c449250db5c5dcebRalf Baechle	memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN);
44115b1c0e822f578306332d4f4c449250db5c5dcebRalf Baechle	memcpy(dev->dev_addr, &ax25_defaddr, AX25_ADDR_LEN);
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
44452db625079e8f231a3e53e89871bd5adb66e8464Stephen Hemmingerstatic const struct net_device_ops scc_netdev_ops = {
44552db625079e8f231a3e53e89871bd5adb66e8464Stephen Hemminger	.ndo_open = scc_open,
44652db625079e8f231a3e53e89871bd5adb66e8464Stephen Hemminger	.ndo_stop = scc_close,
44752db625079e8f231a3e53e89871bd5adb66e8464Stephen Hemminger	.ndo_start_xmit = scc_send_packet,
44852db625079e8f231a3e53e89871bd5adb66e8464Stephen Hemminger	.ndo_do_ioctl = scc_ioctl,
4493e8af307bfe3b6318a1aaaf8ce18d0af7ddf2ea2Alexander Beregalov	.ndo_set_mac_address = scc_set_mac_address,
45052db625079e8f231a3e53e89871bd5adb66e8464Stephen Hemminger};
45152db625079e8f231a3e53e89871bd5adb66e8464Stephen Hemminger
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init setup_adapter(int card_base, int type, int n)
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i, irq, chip;
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct scc_info *info;
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev;
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct scc_priv *priv;
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long time;
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int irqs;
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int tmr_base = card_base + hw[type].tmr_offset;
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int scc_base = card_base + hw[type].scc_offset;
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char *chipnames[] = CHIPNAMES;
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
464dd00cc486ab1c17049a535413d1751ef3482141cYoann Padioleau	/* Initialize what is necessary for write_scc and write_scc_data */
465dd00cc486ab1c17049a535413d1751ef3482141cYoann Padioleau	info = kzalloc(sizeof(struct scc_info), GFP_KERNEL | GFP_DMA);
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!info) {
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "dmascc: "
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "could not allocate memory for %s at %#3x\n",
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       hw[type].name, card_base);
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info->dev[0] = alloc_netdev(0, "", dev_setup);
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!info->dev[0]) {
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "dmascc: "
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "could not allocate memory for %s at %#3x\n",
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       hw[type].name, card_base);
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out1;
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info->dev[1] = alloc_netdev(0, "", dev_setup);
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!info->dev[1]) {
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "dmascc: "
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "could not allocate memory for %s at %#3x\n",
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       hw[type].name, card_base);
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out2;
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_init(&info->register_lock);
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	priv = &info->priv[0];
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	priv->type = type;
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	priv->card_base = card_base;
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	priv->scc_cmd = scc_base + SCCA_CMD;
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	priv->scc_data = scc_base + SCCA_DATA;
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	priv->register_lock = &info->register_lock;
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Reset SCC */
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_scc(priv, R9, FHWRES | MIE | NV);
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Determine type of chip by enabling SDLC/HDLC enhancements */
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_scc(priv, R15, SHDLCE);
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!read_scc(priv, R15)) {
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* WR7' not present. This is an ordinary Z8530 SCC. */
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		chip = Z8530;
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Put one character in TX FIFO */
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		write_scc_data(priv, 0, 0);
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (read_scc(priv, R0) & Tx_BUF_EMP) {
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* TX FIFO not full. This is a Z85230 ESCC with a 4-byte FIFO. */
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			chip = Z85230;
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* TX FIFO full. This is a Z85C30 SCC with a 1-byte FIFO. */
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			chip = Z85C30;
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_scc(priv, R15, 0);
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Start IRQ auto-detection */
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	irqs = probe_irq_on();
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Enable interrupts */
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (type == TYPE_TWIN) {
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb(0, card_base + TWIN_DMA_CFG);
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		inb(card_base + TWIN_CLR_TMR1);
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		inb(card_base + TWIN_CLR_TMR2);
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info->twin_serial_cfg = TWIN_EI;
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb(info->twin_serial_cfg, card_base + TWIN_SERIAL_CFG);
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		write_scc(priv, R15, CTSIE);
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		write_scc(priv, R0, RES_EXT_INT);
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		write_scc(priv, R1, EXT_INT_ENAB);
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Start timer */
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(1, tmr_base + TMR_CNT1);
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0, tmr_base + TMR_CNT1);
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Wait and detect IRQ */
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	time = jiffies;
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (jiffies - time < 2 + HZ / TMR_0_HZ);
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	irq = probe_irq_off(irqs);
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Clear pending interrupt, disable interrupts */
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (type == TYPE_TWIN) {
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		inb(card_base + TWIN_CLR_TMR1);
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		write_scc(priv, R1, 0);
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		write_scc(priv, R15, 0);
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		write_scc(priv, R0, RES_EXT_INT);
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (irq <= 0) {
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "dmascc: could not find irq of %s at %#3x (irq=%d)\n",
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       hw[type].name, card_base, irq);
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out3;
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Set up data structures */
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < 2; i++) {
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev = info->dev[i];
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv = &info->priv[i];
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->type = type;
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->chip = chip;
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->dev = dev;
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->info = info;
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->channel = i;
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_lock_init(&priv->ring_lock);
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->register_lock = &info->register_lock;
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->card_base = card_base;
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->scc_cmd = scc_base + (i ? SCCB_CMD : SCCA_CMD);
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->scc_data = scc_base + (i ? SCCB_DATA : SCCA_DATA);
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->tmr_cnt = tmr_base + (i ? TMR_CNT2 : TMR_CNT1);
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->tmr_ctrl = tmr_base + TMR_CTRL;
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->tmr_mode = i ? 0xb0 : 0x70;
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->param.pclk_hz = hw[type].pclk_hz;
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->param.brg_tc = -1;
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->param.clocks = TCTRxCP | RCRTxCP;
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->param.persist = 256;
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->param.dma = -1;
5827a87b6c228b8d0cc54b9faa159732fcb2a6c9d0cAl Viro		INIT_WORK(&priv->rx_work, rx_bh);
583f4bdd264b43cc60dccb617afce2859dffdd7a935Wang Chen		dev->ml_priv = priv;
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sprintf(dev->name, "dmascc%i", 2 * n + i);
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->base_addr = card_base;
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->irq = irq;
58752db625079e8f231a3e53e89871bd5adb66e8464Stephen Hemminger		dev->netdev_ops = &scc_netdev_ops;
5883b04ddde02cf1b6f14f2697da5c20eca5715017fStephen Hemminger		dev->header_ops = &ax25_header_ops;
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (register_netdev(info->dev[0])) {
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "dmascc: could not register %s\n",
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       info->dev[0]->name);
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out3;
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (register_netdev(info->dev[1])) {
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "dmascc: could not register %s\n",
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       info->dev[1]->name);
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out4;
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info->next = first;
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	first = info;
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(KERN_INFO "dmascc: found %s (%s) at %#3x, irq %d\n",
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       hw[type].name, chipnames[chip], card_base, irq);
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds      out4:
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unregister_netdev(info->dev[0]);
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds      out3:
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (info->priv[0].type == TYPE_TWIN)
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb(0, info->dev[0]->base_addr + TWIN_SERIAL_CFG);
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_scc(&info->priv[0], R9, FHWRES);
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	free_netdev(info->dev[1]);
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds      out2:
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	free_netdev(info->dev[0]);
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds      out1:
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(info);
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds      out:
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -1;
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Driver functions */
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void write_scc(struct scc_priv *priv, int reg, int val)
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (priv->type) {
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case TYPE_S5:
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (reg)
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			outb(reg, priv->scc_cmd);
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb(val, priv->scc_cmd);
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case TYPE_TWIN:
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (reg)
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			outb_p(reg, priv->scc_cmd);
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb_p(val, priv->scc_cmd);
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_lock_irqsave(priv->register_lock, flags);
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb_p(0, priv->card_base + PI_DREQ_MASK);
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (reg)
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			outb_p(reg, priv->scc_cmd);
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb_p(val, priv->scc_cmd);
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb(1, priv->card_base + PI_DREQ_MASK);
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(priv->register_lock, flags);
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void write_scc_data(struct scc_priv *priv, int val, int fast)
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (priv->type) {
6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case TYPE_S5:
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb(val, priv->scc_data);
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case TYPE_TWIN:
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb_p(val, priv->scc_data);
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (fast)
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			outb_p(val, priv->scc_data);
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else {
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			spin_lock_irqsave(priv->register_lock, flags);
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			outb_p(0, priv->card_base + PI_DREQ_MASK);
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			outb_p(val, priv->scc_data);
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			outb(1, priv->card_base + PI_DREQ_MASK);
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			spin_unlock_irqrestore(priv->register_lock, flags);
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int read_scc(struct scc_priv *priv, int reg)
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int rc;
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (priv->type) {
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case TYPE_S5:
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (reg)
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			outb(reg, priv->scc_cmd);
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return inb(priv->scc_cmd);
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case TYPE_TWIN:
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (reg)
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			outb_p(reg, priv->scc_cmd);
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return inb_p(priv->scc_cmd);
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_lock_irqsave(priv->register_lock, flags);
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb_p(0, priv->card_base + PI_DREQ_MASK);
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (reg)
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			outb_p(reg, priv->scc_cmd);
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rc = inb_p(priv->scc_cmd);
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb(1, priv->card_base + PI_DREQ_MASK);
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(priv->register_lock, flags);
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return rc;
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int read_scc_data(struct scc_priv *priv)
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int rc;
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (priv->type) {
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case TYPE_S5:
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return inb(priv->scc_data);
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case TYPE_TWIN:
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return inb_p(priv->scc_data);
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_lock_irqsave(priv->register_lock, flags);
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb_p(0, priv->card_base + PI_DREQ_MASK);
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rc = inb_p(priv->scc_data);
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb(1, priv->card_base + PI_DREQ_MASK);
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(priv->register_lock, flags);
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return rc;
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int scc_open(struct net_device *dev)
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
726f4bdd264b43cc60dccb617afce2859dffdd7a935Wang Chen	struct scc_priv *priv = dev->ml_priv;
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct scc_info *info = priv->info;
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int card_base = priv->card_base;
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Request IRQ if not already used by other channel */
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!info->irq_used) {
7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (request_irq(dev->irq, scc_isr, 0, "dmascc", info)) {
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EAGAIN;
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info->irq_used++;
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Request DMA if required */
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (priv->param.dma >= 0) {
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (request_dma(priv->param.dma, "dmascc")) {
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (--info->irq_used == 0)
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				free_irq(dev->irq, info);
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EAGAIN;
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			unsigned long flags = claim_dma_lock();
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			clear_dma_ff(priv->param.dma);
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			release_dma_lock(flags);
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Initialize local variables */
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	priv->rx_ptr = 0;
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	priv->rx_over = 0;
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	priv->rx_head = priv->rx_tail = priv->rx_count = 0;
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	priv->state = IDLE;
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	priv->tx_head = priv->tx_tail = priv->tx_count = 0;
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	priv->tx_ptr = 0;
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Reset channel */
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_scc(priv, R9, (priv->channel ? CHRB : CHRA) | MIE | NV);
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* X1 clock, SDLC mode */
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_scc(priv, R4, SDLC | X1CLK);
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* DMA */
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_scc(priv, R1, EXT_INT_ENAB | WT_FN_RDYFN);
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* 8 bit RX char, RX disable */
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_scc(priv, R3, Rx8);
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* 8 bit TX char, TX disable */
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_scc(priv, R5, Tx8);
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* SDLC address field */
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_scc(priv, R6, 0);
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* SDLC flag */
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_scc(priv, R7, FLAG);
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (priv->chip) {
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case Z85C30:
7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Select WR7' */
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		write_scc(priv, R15, SHDLCE);
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Auto EOM reset */
7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		write_scc(priv, R7, AUTOEOM);
7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		write_scc(priv, R15, 0);
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case Z85230:
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Select WR7' */
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		write_scc(priv, R15, SHDLCE);
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* The following bits are set (see 2.5.2.1):
7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   - Automatic EOM reset
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   - Interrupt request if RX FIFO is half full
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   This bit should be ignored in DMA mode (according to the
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   documentation), but actually isn't. The receiver doesn't work if
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   it is set. Thus, we have to clear it in DMA mode.
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   - Interrupt/DMA request if TX FIFO is completely empty
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   a) If set, the ESCC behaves as if it had no TX FIFO (Z85C30
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   compatibility).
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   b) If cleared, DMA requests may follow each other very quickly,
7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   filling up the TX FIFO.
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   Advantage: TX works even in case of high bus latency.
7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   Disadvantage: Edge-triggered DMA request circuitry may miss
7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   a request. No more data is delivered, resulting
7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   in a TX FIFO underrun.
7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   Both PI2 and S5SCC/DMA seem to work fine with TXFIFOE cleared.
8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   The PackeTwin doesn't. I don't know about the PI, but let's
8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   assume it behaves like the PI2.
8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (priv->param.dma >= 0) {
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (priv->type == TYPE_TWIN)
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				write_scc(priv, R7, AUTOEOM | TXFIFOE);
8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			else
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				write_scc(priv, R7, AUTOEOM);
8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			write_scc(priv, R7, AUTOEOM | RXFIFOH);
8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		write_scc(priv, R15, 0);
8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Preset CRC, NRZ(I) encoding */
8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_scc(priv, R10, CRCPS | (priv->param.nrzi ? NRZI : NRZ));
8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Configure baud rate generator */
8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (priv->param.brg_tc >= 0) {
8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Program BR generator */
8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		write_scc(priv, R12, priv->param.brg_tc & 0xFF);
8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		write_scc(priv, R13, (priv->param.brg_tc >> 8) & 0xFF);
8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* BRG source = SYS CLK; enable BRG; DTR REQ function (required by
8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   PackeTwin, not connected on the PI2); set DPLL source to BRG */
8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		write_scc(priv, R14, SSBR | DTRREQ | BRSRC | BRENABL);
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Enable DPLL */
8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		write_scc(priv, R14, SEARCH | DTRREQ | BRSRC | BRENABL);
8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Disable BR generator */
8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		write_scc(priv, R14, DTRREQ | BRSRC);
8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Configure clocks */
8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (priv->type == TYPE_TWIN) {
8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Disable external TX clock receiver */
8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb((info->twin_serial_cfg &=
8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      ~(priv->channel ? TWIN_EXTCLKB : TWIN_EXTCLKA)),
8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		     card_base + TWIN_SERIAL_CFG);
8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_scc(priv, R11, priv->param.clocks);
8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((priv->type == TYPE_TWIN) && !(priv->param.clocks & TRxCOI)) {
8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Enable external TX clock receiver */
8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb((info->twin_serial_cfg |=
8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      (priv->channel ? TWIN_EXTCLKB : TWIN_EXTCLKA)),
8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		     card_base + TWIN_SERIAL_CFG);
8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Configure PackeTwin */
8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (priv->type == TYPE_TWIN) {
8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Assert DTR, enable interrupts */
8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb((info->twin_serial_cfg |= TWIN_EI |
8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      (priv->channel ? TWIN_DTRB_ON : TWIN_DTRA_ON)),
8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		     card_base + TWIN_SERIAL_CFG);
8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Read current status */
8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	priv->rr0 = read_scc(priv, R0);
8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Enable DCD interrupt */
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_scc(priv, R15, DCDIE);
8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	netif_start_queue(dev);
8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int scc_close(struct net_device *dev)
8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
868f4bdd264b43cc60dccb617afce2859dffdd7a935Wang Chen	struct scc_priv *priv = dev->ml_priv;
8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct scc_info *info = priv->info;
8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int card_base = priv->card_base;
8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	netif_stop_queue(dev);
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (priv->type == TYPE_TWIN) {
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Drop DTR */
8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb((info->twin_serial_cfg &=
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      (priv->channel ? ~TWIN_DTRB_ON : ~TWIN_DTRA_ON)),
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		     card_base + TWIN_SERIAL_CFG);
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Reset channel, free DMA and IRQ */
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_scc(priv, R9, (priv->channel ? CHRB : CHRA) | MIE | NV);
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (priv->param.dma >= 0) {
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (priv->type == TYPE_TWIN)
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			outb(0, card_base + TWIN_DMA_CFG);
8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		free_dma(priv->param.dma);
8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (--info->irq_used == 0)
8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		free_irq(dev->irq, info);
8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int scc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
897f4bdd264b43cc60dccb617afce2859dffdd7a935Wang Chen	struct scc_priv *priv = dev->ml_priv;
8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (cmd) {
9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case SIOCGSCCPARAM:
9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (copy_to_user
9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    (ifr->ifr_data, &priv->param,
9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		     sizeof(struct scc_param)))
9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EFAULT;
9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case SIOCSSCCPARAM:
9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!capable(CAP_NET_ADMIN))
9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EPERM;
9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (netif_running(dev))
9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EAGAIN;
9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (copy_from_user
9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    (&priv->param, ifr->ifr_data,
9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		     sizeof(struct scc_param)))
9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EFAULT;
9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int scc_send_packet(struct sk_buff *skb, struct net_device *dev)
9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
924f4bdd264b43cc60dccb617afce2859dffdd7a935Wang Chen	struct scc_priv *priv = dev->ml_priv;
9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Temporarily stop the scheduler feeding us packets */
9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	netif_stop_queue(dev);
9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Transfer data to DMA buffer */
9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i = priv->tx_head;
933d626f62b11e00c16e81e4308ab93d3f13551812aArnaldo Carvalho de Melo	skb_copy_from_linear_data_offset(skb, 1, priv->tx_buf[i], skb->len - 1);
9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	priv->tx_len[i] = skb->len - 1;
9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Clear interrupts while we touch our circular buffers */
9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&priv->ring_lock, flags);
9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Move the ring buffer's head */
9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	priv->tx_head = (i + 1) % NUM_TX_BUF;
9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	priv->tx_count++;
9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* If we just filled up the last buffer, leave queue stopped.
9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   The higher layers must wait until we have a DMA buffer
9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   to accept the data. */
9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (priv->tx_count < NUM_TX_BUF)
9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		netif_wake_queue(dev);
9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Set new TX state */
9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (priv->state == IDLE) {
9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Assert RTS, start timer */
9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->state = TX_HEAD;
9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->tx_start = jiffies;
9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		write_scc(priv, R5, TxCRC_ENAB | RTS | TxENAB | Tx8);
9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		write_scc(priv, R15, 0);
9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		start_timer(priv, priv->param.txdelay, 0);
9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Turn interrupts back on and free buffer */
9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&priv->ring_lock, flags);
9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev_kfree_skb(skb);
9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9636ed106549d17474ca17a16057f4c0ed4eba5a7caPatrick McHardy	return NETDEV_TX_OK;
9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int scc_set_mac_address(struct net_device *dev, void *sa)
9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memcpy(dev->dev_addr, ((struct sockaddr *) sa)->sa_data,
9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       dev->addr_len);
9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void tx_on(struct scc_priv *priv)
9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i, n;
9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (priv->param.dma >= 0) {
9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		n = (priv->chip == Z85230) ? 3 : 1;
9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Program DMA controller */
9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		flags = claim_dma_lock();
9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		set_dma_mode(priv->param.dma, DMA_MODE_WRITE);
9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		set_dma_addr(priv->param.dma,
9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     (int) priv->tx_buf[priv->tx_tail] + n);
9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		set_dma_count(priv->param.dma,
9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      priv->tx_len[priv->tx_tail] - n);
9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		release_dma_lock(flags);
9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Enable TX underrun interrupt */
9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		write_scc(priv, R15, TxUIE);
9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Configure DREQ */
9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (priv->type == TYPE_TWIN)
9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			outb((priv->param.dma ==
9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      1) ? TWIN_DMA_HDX_T1 : TWIN_DMA_HDX_T3,
9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     priv->card_base + TWIN_DMA_CFG);
9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			write_scc(priv, R1,
9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  EXT_INT_ENAB | WT_FN_RDYFN |
10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  WT_RDY_ENAB);
10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Write first byte(s) */
10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_lock_irqsave(priv->register_lock, flags);
10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i < n; i++)
10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			write_scc_data(priv,
10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				       priv->tx_buf[priv->tx_tail][i], 1);
10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		enable_dma(priv->param.dma);
10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(priv->register_lock, flags);
10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		write_scc(priv, R15, TxUIE);
10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		write_scc(priv, R1,
10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  EXT_INT_ENAB | WT_FN_RDYFN | TxINT_ENAB);
10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tx_isr(priv);
10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Reset EOM latch if we do not have the AUTOEOM feature */
10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (priv->chip == Z8530)
10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		write_scc(priv, R0, RES_EOM_L);
10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void rx_on(struct scc_priv *priv)
10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Clear RX FIFO */
10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (read_scc(priv, R0) & Rx_CH_AV)
10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		read_scc_data(priv);
10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	priv->rx_over = 0;
10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (priv->param.dma >= 0) {
10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Program DMA controller */
10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		flags = claim_dma_lock();
10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		set_dma_mode(priv->param.dma, DMA_MODE_READ);
10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		set_dma_addr(priv->param.dma,
10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     (int) priv->rx_buf[priv->rx_head]);
10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		set_dma_count(priv->param.dma, BUF_SIZE);
10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		release_dma_lock(flags);
10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		enable_dma(priv->param.dma);
10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Configure PackeTwin DMA */
10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (priv->type == TYPE_TWIN) {
10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			outb((priv->param.dma ==
10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      1) ? TWIN_DMA_HDX_R1 : TWIN_DMA_HDX_R3,
10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     priv->card_base + TWIN_DMA_CFG);
10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Sp. cond. intr. only, ext int enable, RX DMA enable */
10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		write_scc(priv, R1, EXT_INT_ENAB | INT_ERR_Rx |
10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  WT_RDY_RT | WT_FN_RDYFN | WT_RDY_ENAB);
10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Reset current frame */
10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->rx_ptr = 0;
10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Intr. on all Rx characters and Sp. cond., ext int enable */
10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		write_scc(priv, R1, EXT_INT_ENAB | INT_ALL_Rx | WT_RDY_RT |
10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  WT_FN_RDYFN);
10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_scc(priv, R0, ERR_RES);
10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_scc(priv, R3, RxENABLE | Rx8 | RxCRC_ENAB);
10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void rx_off(struct scc_priv *priv)
10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Disable receiver */
10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_scc(priv, R3, Rx8);
10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Disable DREQ / RX interrupt */
10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (priv->param.dma >= 0 && priv->type == TYPE_TWIN)
10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb(0, priv->card_base + TWIN_DMA_CFG);
10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		write_scc(priv, R1, EXT_INT_ENAB | WT_FN_RDYFN);
10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Disable DMA */
10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (priv->param.dma >= 0)
10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		disable_dma(priv->param.dma);
10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void start_timer(struct scc_priv *priv, int t, int r15)
10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(priv->tmr_mode, priv->tmr_ctrl);
10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (t == 0) {
10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tm_isr(priv);
10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else if (t > 0) {
10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb(t & 0xFF, priv->tmr_cnt);
10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb((t >> 8) & 0xFF, priv->tmr_cnt);
10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (priv->type != TYPE_TWIN) {
10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			write_scc(priv, R15, r15 | CTSIE);
10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			priv->rr0 |= CTS;
10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline unsigned char random(void)
10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* See "Numerical Recipes in C", second edition, p. 284 */
10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rand = rand * 1664525L + 1013904223L;
10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (unsigned char) (rand >> 24);
10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void z8530_isr(struct scc_info *info)
10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int is, i = 100;
10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while ((is = read_scc(&info->priv[0], R3)) && i--) {
11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (is & CHARxIP) {
11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rx_isr(&info->priv[0]);
11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else if (is & CHATxIP) {
11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			tx_isr(&info->priv[0]);
11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else if (is & CHAEXT) {
11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			es_isr(&info->priv[0]);
11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else if (is & CHBRxIP) {
11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rx_isr(&info->priv[1]);
11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else if (is & CHBTxIP) {
11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			tx_isr(&info->priv[1]);
11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			es_isr(&info->priv[1]);
11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		write_scc(&info->priv[0], R0, RES_H_IUS);
11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		i++;
11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (i < 0) {
11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "dmascc: stuck in ISR with RR3=0x%02x.\n",
11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       is);
11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Ok, no interrupts pending from this 8530. The INT line should
11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   be inactive now. */
11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11267d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t scc_isr(int irq, void *dev_id)
11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct scc_info *info = dev_id;
11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock(info->priv[0].register_lock);
11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* At this point interrupts are enabled, and the interrupt under service
11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   is already acknowledged, but masked off.
11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   Interrupt processing: We loop until we know that the IRQ line is
11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   low. If another positive edge occurs afterwards during the ISR,
11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   another interrupt will be triggered by the interrupt controller
11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   as soon as the IRQ level is enabled again (see asm/irq.h).
11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   Bottom-half handlers will be processed after scc_isr(). This is
11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   important, since we only have small ringbuffers and want new data
11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   to be fetched/delivered immediately. */
11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (info->priv[0].type == TYPE_TWIN) {
11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int is, card_base = info->priv[0].card_base;
11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		while ((is = ~inb(card_base + TWIN_INT_REG)) &
11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       TWIN_INT_MSK) {
11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (is & TWIN_SCC_MSK) {
11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				z8530_isr(info);
11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else if (is & TWIN_TMR1_MSK) {
11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				inb(card_base + TWIN_CLR_TMR1);
11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				tm_isr(&info->priv[0]);
11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				inb(card_base + TWIN_CLR_TMR2);
11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				tm_isr(&info->priv[1]);
11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else
11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		z8530_isr(info);
11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock(info->priv[0].register_lock);
11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return IRQ_HANDLED;
11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rx_isr(struct scc_priv *priv)
11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (priv->param.dma >= 0) {
11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Check special condition and perform error reset. See 2.4.7.5. */
11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		special_condition(priv, read_scc(priv, R1));
11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		write_scc(priv, R0, ERR_RES);
11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Check special condition for each character. Error reset not necessary.
11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   Same algorithm for SCC and ESCC. See 2.4.7.1 and 2.4.7.4. */
11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int rc;
11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		while (read_scc(priv, R0) & Rx_CH_AV) {
11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rc = read_scc(priv, R1);
11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (priv->rx_ptr < BUF_SIZE)
11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				priv->rx_buf[priv->rx_head][priv->
11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							    rx_ptr++] =
11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    read_scc_data(priv);
11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			else {
11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				priv->rx_over = 2;
11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				read_scc_data(priv);
11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			special_condition(priv, rc);
11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void special_condition(struct scc_priv *priv, int rc)
11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int cb;
11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* See Figure 2-15. Only overrun and EOF need to be checked. */
11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rc & Rx_OVR) {
11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Receiver overrun */
11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->rx_over = 1;
12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (priv->param.dma < 0)
12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			write_scc(priv, R0, ERR_RES);
12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else if (rc & END_FR) {
12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* End of frame. Get byte count */
12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (priv->param.dma >= 0) {
12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			flags = claim_dma_lock();
12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cb = BUF_SIZE - get_dma_residue(priv->param.dma) -
12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    2;
12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			release_dma_lock(flags);
12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cb = priv->rx_ptr - 2;
12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (priv->rx_over) {
12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* We had an overrun */
121413c0582d91ab63087a30addcfe42874541ca2689Stephen Hemminger			priv->dev->stats.rx_errors++;
12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (priv->rx_over == 2)
121613c0582d91ab63087a30addcfe42874541ca2689Stephen Hemminger				priv->dev->stats.rx_length_errors++;
12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			else
121813c0582d91ab63087a30addcfe42874541ca2689Stephen Hemminger				priv->dev->stats.rx_fifo_errors++;
12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			priv->rx_over = 0;
12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else if (rc & CRC_ERR) {
12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Count invalid CRC only if packet length >= minimum */
12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (cb >= 15) {
122313c0582d91ab63087a30addcfe42874541ca2689Stephen Hemminger				priv->dev->stats.rx_errors++;
122413c0582d91ab63087a30addcfe42874541ca2689Stephen Hemminger				priv->dev->stats.rx_crc_errors++;
12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (cb >= 15) {
12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (priv->rx_count < NUM_RX_BUF - 1) {
12291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					/* Put good frame in FIFO */
12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					priv->rx_len[priv->rx_head] = cb;
12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					priv->rx_head =
12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					    (priv->rx_head +
12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					     1) % NUM_RX_BUF;
12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					priv->rx_count++;
12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					schedule_work(&priv->rx_work);
12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				} else {
123713c0582d91ab63087a30addcfe42874541ca2689Stephen Hemminger					priv->dev->stats.rx_errors++;
123813c0582d91ab63087a30addcfe42874541ca2689Stephen Hemminger					priv->dev->stats.rx_over_errors++;
12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Get ready for new frame */
12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (priv->param.dma >= 0) {
12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			flags = claim_dma_lock();
12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			set_dma_addr(priv->param.dma,
12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     (int) priv->rx_buf[priv->rx_head]);
12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			set_dma_count(priv->param.dma, BUF_SIZE);
12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			release_dma_lock(flags);
12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			priv->rx_ptr = 0;
12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12567a87b6c228b8d0cc54b9faa159732fcb2a6c9d0cAl Virostatic void rx_bh(struct work_struct *ugli_api)
12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12587a87b6c228b8d0cc54b9faa159732fcb2a6c9d0cAl Viro	struct scc_priv *priv = container_of(ugli_api, struct scc_priv, rx_work);
12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i = priv->rx_tail;
12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int cb;
12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sk_buff *skb;
12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *data;
12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&priv->ring_lock, flags);
12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (priv->rx_count) {
12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(&priv->ring_lock, flags);
12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cb = priv->rx_len[i];
12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Allocate buffer */
12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		skb = dev_alloc_skb(cb + 1);
12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (skb == NULL) {
12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Drop packet */
127313c0582d91ab63087a30addcfe42874541ca2689Stephen Hemminger			priv->dev->stats.rx_dropped++;
12741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Fill buffer */
12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data = skb_put(skb, cb + 1);
12771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data[0] = 0;
12781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			memcpy(&data[1], priv->rx_buf[i], cb);
127956cb515628e6a831bb76783f282a71f7285dad33Arnaldo Carvalho de Melo			skb->protocol = ax25_type_trans(skb, priv->dev);
12801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			netif_rx(skb);
128113c0582d91ab63087a30addcfe42874541ca2689Stephen Hemminger			priv->dev->stats.rx_packets++;
128213c0582d91ab63087a30addcfe42874541ca2689Stephen Hemminger			priv->dev->stats.rx_bytes += cb;
12831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_lock_irqsave(&priv->ring_lock, flags);
12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Move tail */
12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->rx_tail = i = (i + 1) % NUM_RX_BUF;
12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->rx_count--;
12881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&priv->ring_lock, flags);
12901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void tx_isr(struct scc_priv *priv)
12941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i = priv->tx_tail, p = priv->tx_ptr;
12961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Suspend TX interrupts if we don't want to send anything.
12981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   See Figure 2-22. */
12991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (p == priv->tx_len[i]) {
13001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		write_scc(priv, R0, RES_Tx_P);
13011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
13021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Write characters */
13051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while ((read_scc(priv, R0) & Tx_BUF_EMP) && p < priv->tx_len[i]) {
13061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		write_scc_data(priv, priv->tx_buf[i][p++], 0);
13071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Reset EOM latch of Z8530 */
13101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!priv->tx_ptr && p && priv->chip == Z8530)
13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		write_scc(priv, R0, RES_EOM_L);
13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	priv->tx_ptr = p;
13141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void es_isr(struct scc_priv *priv)
13181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i, rr0, drr0, res;
13201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
13211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Read status, reset interrupt bit (open latches) */
13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rr0 = read_scc(priv, R0);
13241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_scc(priv, R0, RES_EXT_INT);
13251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	drr0 = priv->rr0 ^ rr0;
13261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	priv->rr0 = rr0;
13271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Transmit underrun (2.4.9.6). We can't check the TxEOM flag, since
13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   it might have already been cleared again by AUTOEOM. */
13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (priv->state == TX_DATA) {
13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Get remaining bytes */
13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		i = priv->tx_tail;
13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (priv->param.dma >= 0) {
13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			disable_dma(priv->param.dma);
13351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			flags = claim_dma_lock();
13361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			res = get_dma_residue(priv->param.dma);
13371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			release_dma_lock(flags);
13381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
13391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			res = priv->tx_len[i] - priv->tx_ptr;
13401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			priv->tx_ptr = 0;
13411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
13421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Disable DREQ / TX interrupt */
13431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (priv->param.dma >= 0 && priv->type == TYPE_TWIN)
13441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			outb(0, priv->card_base + TWIN_DMA_CFG);
13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			write_scc(priv, R1, EXT_INT_ENAB | WT_FN_RDYFN);
13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (res) {
13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Update packet statistics */
134913c0582d91ab63087a30addcfe42874541ca2689Stephen Hemminger			priv->dev->stats.tx_errors++;
135013c0582d91ab63087a30addcfe42874541ca2689Stephen Hemminger			priv->dev->stats.tx_fifo_errors++;
13511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Other underrun interrupts may already be waiting */
13521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			write_scc(priv, R0, RES_EXT_INT);
13531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			write_scc(priv, R0, RES_EXT_INT);
13541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
13551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Update packet statistics */
135613c0582d91ab63087a30addcfe42874541ca2689Stephen Hemminger			priv->dev->stats.tx_packets++;
135713c0582d91ab63087a30addcfe42874541ca2689Stephen Hemminger			priv->dev->stats.tx_bytes += priv->tx_len[i];
13581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Remove frame from FIFO */
13591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			priv->tx_tail = (i + 1) % NUM_TX_BUF;
13601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			priv->tx_count--;
13611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Inform upper layers */
13621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			netif_wake_queue(priv->dev);
13631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
13641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Switch state */
13651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		write_scc(priv, R15, 0);
13661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (priv->tx_count &&
13671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    (jiffies - priv->tx_start) < priv->param.txtimeout) {
13681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			priv->state = TX_PAUSE;
13691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			start_timer(priv, priv->param.txpause, 0);
13701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
13711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			priv->state = TX_TAIL;
13721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			start_timer(priv, priv->param.txtail, 0);
13731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* DCD transition */
13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (drr0 & DCD) {
13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (rr0 & DCD) {
13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			switch (priv->state) {
13801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case IDLE:
13811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case WAIT:
13821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				priv->state = DCD_ON;
13831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				write_scc(priv, R15, 0);
13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				start_timer(priv, priv->param.dcdon, 0);
13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
13861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
13871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			switch (priv->state) {
13881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case RX_ON:
13891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				rx_off(priv);
13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				priv->state = DCD_OFF;
13911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				write_scc(priv, R15, 0);
13921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				start_timer(priv, priv->param.dcdoff, 0);
13931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
13941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
13951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* CTS transition */
13981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((drr0 & CTS) && (~rr0 & CTS) && priv->type != TYPE_TWIN)
13991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tm_isr(priv);
14001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void tm_isr(struct scc_priv *priv)
14051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
14061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (priv->state) {
14071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case TX_HEAD:
14081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case TX_PAUSE:
14091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tx_on(priv);
14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->state = TX_DATA;
14111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
14121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case TX_TAIL:
14131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		write_scc(priv, R5, TxCRC_ENAB | Tx8);
14141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->state = RTS_OFF;
14151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (priv->type != TYPE_TWIN)
14161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			write_scc(priv, R15, 0);
14171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		start_timer(priv, priv->param.rtsoff, 0);
14181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
14191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case RTS_OFF:
14201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		write_scc(priv, R15, DCDIE);
14211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->rr0 = read_scc(priv, R0);
14221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (priv->rr0 & DCD) {
142313c0582d91ab63087a30addcfe42874541ca2689Stephen Hemminger			priv->dev->stats.collisions++;
14241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rx_on(priv);
14251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			priv->state = RX_ON;
14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
14271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			priv->state = WAIT;
14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			start_timer(priv, priv->param.waittime, DCDIE);
14291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
14301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
14311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case WAIT:
14321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (priv->tx_count) {
14331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			priv->state = TX_HEAD;
14341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			priv->tx_start = jiffies;
14351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			write_scc(priv, R5,
14361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  TxCRC_ENAB | RTS | TxENAB | Tx8);
14371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			write_scc(priv, R15, 0);
14381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			start_timer(priv, priv->param.txdelay, 0);
14391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
14401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			priv->state = IDLE;
14411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (priv->type != TYPE_TWIN)
14421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				write_scc(priv, R15, DCDIE);
14431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
14441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
14451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case DCD_ON:
14461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case DCD_OFF:
14471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		write_scc(priv, R15, DCDIE);
14481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		priv->rr0 = read_scc(priv, R0);
14491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (priv->rr0 & DCD) {
14501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rx_on(priv);
14511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			priv->state = RX_ON;
14521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
14531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			priv->state = WAIT;
14541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			start_timer(priv,
14551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    random() / priv->param.persist *
14561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    priv->param.slottime, DCDIE);
14571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
14581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
14591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1461