summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/Makefile6
-rw-r--r--drivers/ap1000/Makefile29
-rw-r--r--drivers/ap1000/am79c830.h276
-rw-r--r--drivers/ap1000/am79c864.h162
-rw-r--r--drivers/ap1000/ap.c307
-rw-r--r--drivers/ap1000/apfddi-reg.h14
-rw-r--r--drivers/ap1000/apfddi.c702
-rw-r--r--drivers/ap1000/apfddi.h142
-rw-r--r--drivers/ap1000/bif.c280
-rw-r--r--drivers/ap1000/ddv.c1008
-rw-r--r--drivers/ap1000/ddv_util.c116
-rw-r--r--drivers/ap1000/mac.c1177
-rw-r--r--drivers/ap1000/mac.h82
-rw-r--r--drivers/ap1000/plc.c393
-rw-r--r--drivers/ap1000/plc.h53
-rw-r--r--drivers/ap1000/ringbuf.c311
-rw-r--r--drivers/ap1000/smt-types.h167
-rw-r--r--drivers/block/cmd64x.c2
-rw-r--r--drivers/block/swim3.c40
-rw-r--r--drivers/block/swim_iop.c38
-rw-r--r--drivers/char/agp/agpgart_be.c81
-rw-r--r--drivers/char/agp/agpgart_fe.c3
-rw-r--r--drivers/char/generic_serial.c9
-rw-r--r--drivers/char/generic_serial.h3
-rw-r--r--drivers/char/joystick/joy-creative.c2
-rw-r--r--drivers/char/scc.h613
-rw-r--r--drivers/char/serial167.c100
-rw-r--r--drivers/char/tty_io.c21
-rw-r--r--drivers/char/vme_scc.c1136
-rw-r--r--drivers/i2c/Config.in22
-rw-r--r--drivers/i2c/i2c-core.c612
-rw-r--r--drivers/i2c/i2c-dev.c605
-rw-r--r--drivers/i2c/i2c-elektor.c213
-rw-r--r--drivers/i2c/i2c-pcf8584.h38
-rw-r--r--drivers/ieee1394/ieee1394_syms.c1
-rw-r--r--drivers/ieee1394/ieee1394_transactions.c24
-rw-r--r--drivers/ieee1394/ieee1394_transactions.h3
-rw-r--r--drivers/ieee1394/ohci1394.c462
-rw-r--r--drivers/ieee1394/ohci1394.h26
-rw-r--r--drivers/ieee1394/raw1394.c30
-rw-r--r--drivers/net/Makefile4
-rw-r--r--drivers/net/Space.c21
-rw-r--r--drivers/net/cs89x0.h8
-rw-r--r--drivers/net/daynaport.c451
-rw-r--r--drivers/net/irda/Config.in10
-rw-r--r--drivers/net/irda/Makefile12
-rw-r--r--drivers/net/irda/airport.c358
-rw-r--r--drivers/net/irda/irport.c61
-rw-r--r--drivers/net/irda/irtty.c10
-rw-r--r--drivers/net/irda/nsc-ircc.c (renamed from drivers/net/irda/nsc_fir.c)1018
-rw-r--r--drivers/net/irda/smc-ircc.c699
-rw-r--r--drivers/net/irda/toshoboe.c46
-rw-r--r--drivers/net/irda/w83977af_ir.c51
-rw-r--r--drivers/net/mac89x0.c678
-rw-r--r--drivers/net/macmace.c825
-rw-r--r--drivers/net/macsonic.c834
-rw-r--r--drivers/net/sun3lance.c21
-rw-r--r--drivers/net/sunbmac.c2
-rw-r--r--drivers/net/sunhme.c2
-rw-r--r--drivers/net/sunlance.c2
-rw-r--r--drivers/net/sunqe.c2
-rw-r--r--drivers/sbus/audio/cs4231.c2
-rw-r--r--drivers/sbus/audio/dbri.c2
-rw-r--r--drivers/sbus/char/zs.c14
-rw-r--r--drivers/scsi/esp.c2
-rw-r--r--drivers/scsi/scsi_merge.c2
-rw-r--r--drivers/scsi/sd.c55
-rw-r--r--drivers/sound/Config.in2
-rw-r--r--drivers/sound/Makefile4
-rw-r--r--drivers/sound/ac97_codec.c440
-rw-r--r--drivers/sound/ac97_codec.h157
-rw-r--r--drivers/sound/trident.c3055
-rw-r--r--drivers/sound/trident.h266
-rw-r--r--drivers/usb/Config.in1
-rw-r--r--drivers/usb/Makefile2
-rw-r--r--drivers/usb/acm.c36
-rw-r--r--drivers/usb/ov511.c2
-rw-r--r--drivers/usb/printer.c19
-rw-r--r--drivers/usb/scanner.c1
-rw-r--r--drivers/usb/uhci-debug.h399
-rw-r--r--drivers/usb/uhci.c2214
-rw-r--r--drivers/usb/uhci.h425
-rw-r--r--drivers/usb/usb-core.c3
-rw-r--r--drivers/usb/usb-serial.c8
-rw-r--r--drivers/usb/usb-uhci-debug.h195
-rw-r--r--drivers/usb/usb-uhci.c2
-rw-r--r--drivers/usb/usb.c47
-rw-r--r--drivers/usb/usb.h1
-rw-r--r--drivers/video/dn_accel.h9
-rw-r--r--drivers/video/dn_cfb4.c546
-rw-r--r--drivers/video/dn_cfb8.c594
-rw-r--r--drivers/video/dnfb.c394
92 files changed, 12940 insertions, 10383 deletions
diff --git a/drivers/Makefile b/drivers/Makefile
index 71ee973cf..def2731d2 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -11,7 +11,7 @@ SUB_DIRS := block char net parport sound misc
MOD_SUB_DIRS := $(SUB_DIRS)
ALL_SUB_DIRS := $(SUB_DIRS) pci sgi scsi sbus cdrom isdn pnp i2o ieee1394 \
macintosh video dio zorro fc4 usb \
- nubus tc ap1000 atm pcmcia i2c telephony
+ nubus tc atm pcmcia i2c telephony
ifdef CONFIG_DIO
SUB_DIRS += dio
@@ -137,10 +137,6 @@ SUB_DIRS += atm
MOD_SUB_DIRS += atm
endif
-ifeq ($(CONFIG_AP1000),y)
-SUB_DIRS += ap1000
-endif
-
ifeq ($(CONFIG_FC4),y)
SUB_DIRS += fc4
MOD_SUB_DIRS += fc4
diff --git a/drivers/ap1000/Makefile b/drivers/ap1000/Makefile
deleted file mode 100644
index 47f37720a..000000000
--- a/drivers/ap1000/Makefile
+++ /dev/null
@@ -1,29 +0,0 @@
-# File: drivers/ap1000/Makefile
-#
-# Makefile for the AP1000 drivers
-#
-
-L_TARGET := ap1000.a
-L_OBJS := bif.o apfddi.o mac.o plc.o ringbuf.o
-
-ifeq ($(CONFIG_APBLOCK),y)
-L_OBJS += ap.o
-else
- ifeq ($(CONFIG_APBLOCK),m)
- M_OBJS += ap.o
- endif
-endif
-
-ifeq ($(CONFIG_DDV),y)
-L_OBJS += ddv.o ddv_util.o
-else
- ifeq ($(CONFIG_DDV),m)
- M_OBJS += ddv.o ddv_util.o
- endif
-endif
-
-include $(TOPDIR)/Rules.make
-
-clean:
- rm -f core *.o *.a *.s
-
diff --git a/drivers/ap1000/am79c830.h b/drivers/ap1000/am79c830.h
deleted file mode 100644
index f9ba50910..000000000
--- a/drivers/ap1000/am79c830.h
+++ /dev/null
@@ -1,276 +0,0 @@
- /*
- * Copyright 1996 The Australian National University.
- * Copyright 1996 Fujitsu Laboratories Limited
- *
- * This software may be distributed under the terms of the Gnu
- * Public License version 2 or later
- */
-/*
- * Definitions for the AM79C830 FORMAC (Fiber Optic Ring MAC) chip.
- */
-
-typedef int formac_reg;
-
-struct formac {
- formac_reg cmdreg1; /* command register 1 */
- formac_reg cmdreg2; /* command register 2 */
-#define st1u cmdreg1 /* status reg 1, upper */
-#define st1l cmdreg2 /* status reg 1, lower */
- formac_reg st2u; /* status reg 2, upper */
- formac_reg st2l; /* status reg 2, lower */
- formac_reg imsk1u; /* interrupt mask 1, upper */
- formac_reg imsk1l; /* interrupt mask 1, lower */
- formac_reg imsk2u; /* interrupt mask 2, upper */
- formac_reg imsk2l; /* interrupt mask 2, lower */
- formac_reg said; /* short address, individual */
- formac_reg laim; /* long adrs, indiv, MS word */
- formac_reg laic; /* long adrs, indiv, middle word */
- formac_reg lail; /* long adrs, indiv, LS word */
- formac_reg sagp; /* short address, group */
- formac_reg lagm; /* short adrs, group, MS word */
- formac_reg lagc; /* short adrs, group, middle word */
- formac_reg lagl; /* short adrs, group, LS word */
- formac_reg mdreg1; /* mode reg 1 */
- formac_reg stmchn; /* state machine reg */
- formac_reg mir1; /* MAC information reg, upper */
- formac_reg mir0; /* MAC information reg, lower */
- formac_reg tmax; /* TMax value (2's-comp) */
- formac_reg tvx; /* TVX value (2's-comp) */
- formac_reg trt; /* TRT timer value */
- formac_reg tht; /* THT timer value */
- formac_reg tneg; /* current TNeg (2's-comp) */
- formac_reg tmrs; /* extra bits of tneg, trt, tht; late count */
- formac_reg treq0; /* our TReq (2's-comp), lower */
- formac_reg treq1; /* our TReq (2's-comp), upper */
- formac_reg pri0; /* priority reg for async queue 0 */
- formac_reg pri1; /* priority reg for async queue 1 */
- formac_reg pri2; /* priority reg for async queue 2 */
- formac_reg tsync; /* TSync value (2's-comp) */
- formac_reg mdreg2; /* mode reg 2 */
- formac_reg frmthr; /* frame threshold reg */
- formac_reg eacb; /* end address of claim/beacon area */
- formac_reg earv; /* end address of receive area */
- formac_reg eas; /* end address of sync queue */
- formac_reg eaa0; /* end address of async queue 0 */
- formac_reg eaa1; /* end address of async queue 1 */
- formac_reg eaa2; /* end address of async queue 2 */
- formac_reg sacl; /* start address of claim frame */
- formac_reg sabc; /* start address of beacon frame */
- formac_reg wpxsf; /* write pointer, special frames */
- formac_reg rpxsf; /* read pointer, special frames */
- formac_reg dummy1; /* not used */
- formac_reg rpr; /* read pointer, receive */
- formac_reg wpr; /* write pointer, receive */
- formac_reg swpr; /* shadow write pointer, receive */
- formac_reg wpxs; /* write pointer, sync queue */
- formac_reg wpxa0; /* write pointer, async queue 0 */
- formac_reg wpxa1; /* write pointer, async queue 1 */
- formac_reg wpxa2; /* write pointer, async queue 2 */
- formac_reg swpxs; /* shadow write pointer, sync queue */
- formac_reg swpxa0; /* shadow write pointer, async queue 0 */
- formac_reg swpxa1; /* shadow write pointer, async queue 1 */
- formac_reg swpxa2; /* shadow write pointer, async queue 2 */
- formac_reg rpxs; /* read pointer, sync queue */
- formac_reg rpxa0; /* read pointer, async queue 0 */
- formac_reg rpxa1; /* read pointer, async queue 1 */
- formac_reg rpxa2; /* read pointer, async queue 2 */
- formac_reg marr; /* memory address for random reads */
- formac_reg marw; /* memory address for random writes */
- formac_reg mdru; /* memory data register, upper */
- formac_reg mdrl; /* memory data register, lower */
- formac_reg tmsync; /* TSync timer value */
- formac_reg fcntr; /* frame counter */
- formac_reg lcntr; /* lost counter */
- formac_reg ecntr; /* error counter */
-};
-
-/* Values for cmdreg1 */
-#define C1_SOFTWARE_RESET 1
-#define C1_IRMEMWI 2
-#define C1_IRMEMWO 3
-#define C1_IDLE_LISTEN 4
-#define C1_CLAIM_LISTEN 5
-#define C1_BEACON_LISTEN 6
-#define C1_LOAD_TVX 7
-#define C1_SEND_NR_TOKEN 0x0c
-#define C1_SEND_R_TOKEN 0x0d
-#define C1_ENTER_SI_MODE 0x0e
-#define C1_EXIT_SI_MODE 0x0f
-#define C1_CLR_SYNCQ_LOCK 0x11
-#define C1_CLR_ASYNCQ0_LOCK 0x12
-#define C1_CLR_ASYNCQ1_LOCK 0x14
-#define C1_CLR_ASYNCQ2_LOCK 0x18
-#define C1_CLR_RECVQ_LOCK 0x20
-#define C1_CLR_ALL_LOCKS 0x3f
-
-/* Values for cmdreg2 */
-#define C2_XMIT_SYNCQ 1
-#define C2_XMIT_ASYNCQ0 2
-#define C2_XMIT_ASYNCQ1 4
-#define C2_XMIT_ASYNCQ2 8
-#define C2_ABORT_XMIT 0x10
-#define C2_RESET_XMITQS 0x20
-#define C2_SET_TAG 0x30
-#define C2_EN_RECV_FRAME 0x40
-
-/* Bits in (st1u << 16) + st1l (and (imsk1u << 16) + imsk1l) */
-#define S1_XMIT_ABORT 0x80000000
-#define S1_XABORT_ASYNC2 0x40000000
-#define S1_XABORT_ASYNC1 0x20000000
-#define S1_XABORT_ASYNC0 0x10000000
-#define S1_XABORT_SYNC 0x08000000
-#define S1_XBUF_FULL_SYNC 0x04000000
-#define S1_XBUF_FULL_ASYNC 0x02000000
-#define S1_XDONE_SYNC 0x01000000
-#define S1_END_CHAIN_ASYNC2 0x00800000
-#define S1_END_CHAIN_ASYNC1 0x00400000
-#define S1_END_CHAIN_ASYNC0 0x00200000
-#define S1_END_CHAIN_SYNC 0x00100000
-#define S1_END_FRAME_ASYNC2 0x00080000
-#define S1_END_FRAME_ASYNC1 0x00040000
-#define S1_END_FRAME_ASYNC0 0x00020000
-#define S1_END_FRAME_SYNC 0x00010000
-#define S1_BUF_UNDERRUN_ASYNC2 0x00008000
-#define S1_BUF_UNDERRUN_ASYNC1 0x00004000
-#define S1_BUF_UNDERRUN_ASYNC0 0x00002000
-#define S1_BUF_UNDERRUN_SYNC 0x00001000
-#define S1_PAR_ERROR_ASYNC2 0x00000800
-#define S1_PAR_ERROR_ASYNC1 0x00000400
-#define S1_PAR_ERROR_ASYNC0 0x00000200
-#define S1_PAR_ERROR_SYNC 0x00000100
-#define S1_XINSTR_FULL_ASYNC2 0x00000080
-#define S1_XINSTR_FULL_ASYNC1 0x00000040
-#define S1_XINSTR_FULL_ASYNC0 0x00000020
-#define S1_XINSTR_FULL_SYNC 0x00000010
-#define S1_QUEUE_LOCK_ASYNC2 0x00000008
-#define S1_QUEUE_LOCK_ASYNC1 0x00000004
-#define S1_QUEUE_LOCK_ASYNC0 0x00000002
-#define S1_QUEUE_LOCK_SYNC 0x00000001
-
-/* Bits in (st2u << 16) + st2l (and (imsk2u << 16) + imsk2l) */
-#define S2_RECV_COMPLETE 0x80000000
-#define S2_RECV_BUF_EMPTY 0x40000000
-#define S2_RECV_ABORT 0x20000000
-#define S2_RECV_BUF_FULL 0x10000000
-#define S2_RECV_FIFO_OVF 0x08000000
-#define S2_RECV_FRAME 0x04000000
-#define S2_RECV_FRCT_OVF 0x02000000
-#define S2_NP_SIMULT_LOAD 0x01000000
-#define S2_ERR_SPECIAL_FR 0x00800000
-#define S2_CLAIM_STATE 0x00400000
-#define S2_MY_CLAIM 0x00200000
-#define S2_HIGHER_CLAIM 0x00100000
-#define S2_LOWER_CLAIM 0x00080000
-#define S2_BEACON_STATE 0x00040000
-#define S2_MY_BEACON 0x00020000
-#define S2_OTHER_BEACON 0x00010000
-#define S2_RING_OP 0x00008000
-#define S2_MULTIPLE_DA 0x00004000
-#define S2_TOKEN_ERR 0x00002000
-#define S2_TOKEN_ISSUED 0x00001000
-#define S2_TVX_EXP 0x00000800
-#define S2_TRT_EXP 0x00000400
-#define S2_MISSED_FRAME 0x00000200
-#define S2_ADDRESS_DET 0x00000100
-#define S2_PHY_INVALID 0x00000080
-#define S2_LOST_CTR_OVF 0x00000040
-#define S2_ERR_CTR_OVF 0x00000020
-#define S2_FRAME_CTR_OVF 0x00000010
-#define S2_SHORT_IFG 0x00000008
-#define S2_DUPL_CLAIM 0x00000004
-#define S2_TRT_EXP_RECOV 0x00000002
-
-/* Bits in mdreg1 */
-#define M1_SINGLE_FRAME 0x8000
-#define M1_MODE 0x7000
-#define M1_MODE_INITIALIZE 0x0000
-#define M1_MODE_MEMORY 0x1000
-#define M1_MODE_ONLINE_SP 0x2000
-#define M1_MODE_ONLINE 0x3000
-#define M1_MODE_INT_LOOP 0x4000
-#define M1_MODE_EXT_LOOP 0x7000
-#define M1_SHORT_ADRS 0x0800
-#define M1_ADDET 0x0700
-#define M1_ADDET_NORM 0x0000
-#define M1_ADDET_METOO 0x0100
-#define M1_ADDET_NSA_NOTME 0x0200
-#define M1_ADDET_NSA 0x0300
-#define M1_ADDET_DISABLE_RECV 0x0400
-#define M1_ADDET_LIM_PROMISC 0x0600
-#define M1_ADDET_PROMISC 0x0700
-#define M1_SELECT_RA 0x0080
-#define M1_DISABLE_CARRY 0x0040
-#define M1_EXT_GRP 0x0030
-#define M1_EXT_GRP_MYGRP 0x0000
-#define M1_EXT_GRP_SOFT 0x0010
-#define M1_EXT_GRP_UPPER24 0x0020
-#define M1_EXT_GRP_UPPER16 0x0030
-#define M1_LOCK_XMIT_QS 0x0008
-#define M1_FULL_DUPLEX 0x0004
-#define M1_XMTINH_PIN 0x0002
-
-/* Bits in mdreg2 */
-#define M2_TAGMODE 0x8000
-#define M2_STRIP_FCS 0x4000
-#define M2_CHECK_PARITY 0x2000
-#define M2_EVEN_PARITY 0x1000
-#define M2_LSB_FIRST 0x0800
-#define M2_RCV_BYTE_BDRY_MASK 0x0600
-#define M2_RCV_BYTE_BDRY 0x0200
-#define M2_ENABLE_HSREQ 0x0100
-#define M2_ENABLE_NPDMA 0x0080
-#define M2_SYNC_NPDMA 0x0040
-#define M2_SYMBOL_CTRL 0x0020
-#define M2_RECV_BAD_FRAMES 0x0010
-#define M2_AFULL_MASK 0x000f
-#define M2_AFULL 0x0001
-
-/* Bits in stmchn */
-#define SM_REV_MASK 0xe000
-#define SM_REV 0x2000
-#define SM_SEND_IMM_MODE 0x1000
-#define SM_TOKEN_MODE 0x0c00
-#define SM_TOKEN_MODE_NR 0x0000
-#define SM_TOKEN_MODE_ENTER_R 0x0400
-#define SM_TOKEN_MODE_ENTER_NR 0x0800
-#define SM_TOKEN_MODE_R 0x0c00
-#define SM_RCV_STATE 0x0380
-#define SM_XMIT_STATE 0x0070
-#define SM_MDR_PENDING 0x0008
-#define SM_MDR_TAG 0x0004
-
-/* Bits in transmit descriptor */
-#define TD_MORE 0x80000000
-#define TD_MAGIC 0x40000000
-#define TD_BYTE_BDRY_MASK 0x18000000
-#define TD_BYTE_BDRY_1 0x08000000
-#define TD_XMIT_DONE 0x04000000
-#define TD_NO_FCS 0x02000000
-#define TD_XMIT_ABORT 0x01000000
-#define TD_BYTE_BDRY_LG 27
-
-/* Bits in pointer in buffer memory (nontag mode) */
-#define PT_MAGIC 0xa0000000
-
-/* Bits in receive status word */
-#define RS_VALID 0x80000000
-#define RS_ABORTED 0x40000000
-#define RS_SRC_ROUTE 0x10000000
-#define RS_E_INDIC 0x08000000
-#define RS_A_INDIC 0x04000000
-#define RS_C_INDIC 0x02000000
-#define RS_ERROR 0x01000000
-#define RS_ADDR_MATCH 0x00800000
-#define RS_FRAME_TYPE 0x00700000
-#define RS_FT_SMT 0x00000000
-#define RS_FT_LLC 0x00100000
-#define RS_FT_IMPL 0x00200000
-#define RS_FT_MAC 0x00400000
-#define RS_FT_LLC_SYNC 0x00500000
-#define RS_FT_IMPL_SYNC 0x00600000
-#define RS_BYTE_BDRY_MASK 0x00030000
-#define RS_BYTE_BDRY 0x00010000
-#define RS_BYTE_BDRY_LG 16
-
-#define RS_LENGTH 0x0000ffff
-
diff --git a/drivers/ap1000/am79c864.h b/drivers/ap1000/am79c864.h
deleted file mode 100644
index 0fef95791..000000000
--- a/drivers/ap1000/am79c864.h
+++ /dev/null
@@ -1,162 +0,0 @@
- /*
- * Copyright 1996 The Australian National University.
- * Copyright 1996 Fujitsu Laboratories Limited
- *
- * This software may be distributed under the terms of the Gnu
- * Public License version 2 or later
- */
-/*
- * Definitions for Am79c864 PLC (Physical Layer Controller)
- */
-
-typedef int plc_reg;
-
-struct plc {
- plc_reg ctrl_a;
- plc_reg ctrl_b;
- plc_reg intr_mask;
- plc_reg xmit_vector;
- plc_reg vec_length;
- plc_reg le_threshold;
- plc_reg c_min;
- plc_reg tl_min;
- plc_reg tb_min;
- plc_reg t_out;
- plc_reg dummy1;
- plc_reg lc_length;
- plc_reg t_scrub;
- plc_reg ns_max;
- plc_reg tpc_load;
- plc_reg tne_load;
- plc_reg status_a;
- plc_reg status_b;
- plc_reg tpc;
- plc_reg tne;
- plc_reg clk_div;
- plc_reg bist_sig;
- plc_reg rcv_vector;
- plc_reg intr_event;
- plc_reg viol_sym_ct;
- plc_reg min_idle_ct;
- plc_reg link_err_ct;
-};
-
-/* Bits in ctrl_a */
-#define CA_NOISE_TIMER 0x4000
-#define CA_TNE_16BIT 0x2000
-#define CA_TPC_16BIT 0x1000
-#define CA_REQ_SCRUB 0x0800
-#define CA_VSYM_INTR_MODE 0x0200
-#define CA_MINI_INTR_MODE 0x0100
-#define CA_LOOPBACK 0x0080
-#define CA_FOT_OFF 0x0040
-#define CA_EB_LOOP 0x0020
-#define CA_LM_LOOP 0x0010
-#define CA_BYPASS 0x0008
-#define CA_REM_LOOP 0x0004
-#define CA_RF_DISABLE 0x0002
-#define CA_RUN_BIST 0x0001
-
-/* Bits in ctrl_b */
-#define CB_CONFIG_CTRL 0x8000
-#define CB_MATCH_LS 0x7800
-#define CB_MATCH_LS_ANY 0x0000
-#define CB_MATCH_LS_QLS 0x4000
-#define CB_MATCH_LS_MLS 0x2000
-#define CB_MATCH_LS_HLS 0x1000
-#define CB_MATCH_LS_ILS 0x0800
-#define CB_MAINT_LS 0x0700
-#define CB_MAINT_LS_QLS 0x0000
-#define CB_MAINT_LS_ILS 0x0100
-#define CB_MAINT_LS_HLS 0x0200
-#define CB_MAINT_LS_MLS 0x0300
-#define CB_MAINT_LS_PDR 0x0600
-#define CB_CLASS_S 0x0080
-#define CB_PC_LCT 0x0060
-#define CB_PC_LCT_NONE 0x0000
-#define CB_PC_LCT_PDR 0x0020
-#define CB_PC_LCT_IDLE 0x0040
-#define CB_PC_LCT_LOOP 0x0060
-#define CB_PC_JOIN 0x0010
-#define CB_LONG_LCT 0x0008
-#define CB_PC_MAINT 0x0004
-#define CB_PCM_CTRL 0x0003
-#define CB_PC_START 0x0001
-#define CB_PC_TRACE 0x0002
-#define CB_PC_STOP 0x0003
-
-/* Bits in status_a */
-#define SA_SIG_DETECT 0x0400
-#define SA_PREV_LS 0x0300
-#define SA_PREV_LS_QLS 0x0000
-#define SA_PREV_LS_MLS 0x0100
-#define SA_PREV_LS_HLS 0x0200
-#define SA_PREV_LS_ILS 0x0300
-#define SA_LINE_ST 0x00e0
-#define SA_LINE_ST_NLS 0x0000
-#define SA_LINE_ST_ALS 0x0020
-#define SA_LINE_ST_ILS4 0x0060
-#define SA_LINE_ST_QLS 0x0080
-#define SA_LINE_ST_MLS 0x00a0
-#define SA_LINE_ST_HLS 0x00c0
-#define SA_LINE_ST_ILS 0x00e0
-#define SA_LSM_STATE 0x0010
-#define SA_UNKN_LINE_ST 0x0008
-#define SA_SYM_PAIR_CTR 0x0007
-
-/* Bits in status_b */
-#define SB_RF_STATE 0xc000
-#define SB_RF_STATE_REPEAT 0x0000
-#define SB_RF_STATE_IDLE 0x4000
-#define SB_RF_STATE_HALT1 0x8000
-#define SB_RF_STATE_HALT2 0xc000
-#define SB_PCI_STATE 0x3000
-#define SB_PCI_STATE_REMOVED 0x0000
-#define SB_PCI_STATE_INS_SCR 0x1000
-#define SB_PCI_STATE_REM_SCR 0x2000
-#define SB_PCI_STATE_INSERTED 0x3000
-#define SB_PCI_SCRUB 0x0800
-#define SB_PCM_STATE 0x0780
-#define SB_PCM_STATE_OFF 0x0000
-#define SB_PCM_STATE_BREAK 0x0080
-#define SB_PCM_STATE_TRACE 0x0100
-#define SB_PCM_STATE_CONNECT 0x0180
-#define SB_PCM_STATE_NEXT 0x0200
-#define SB_PCM_STATE_SIGNAL 0x0280
-#define SB_PCM_STATE_JOIN 0x0300
-#define SB_PCM_STATE_VERIFY 0x0380
-#define SB_PCM_STATE_ACTIVE 0x0400
-#define SB_PCM_STATE_MAIN 0x0480
-#define SB_PCM_SIGNALING 0x0040
-#define SB_LSF 0x0020
-#define SB_RCF 0x0010
-#define SB_TCF 0x0008
-#define SB_BREAK_REASON 0x0007
-#define SB_BREAK_REASON_NONE 0x0000
-#define SB_BREAK_REASON_START 0x0001
-#define SB_BREAK_REASON_T_OUT 0x0002
-#define SB_BREAK_REASON_NS_MAX 0x0003
-#define SB_BREAK_REASON_QLS 0x0004
-#define SB_BREAK_REASON_ILS 0x0005
-#define SB_BREAK_REASON_HLS 0x0006
-
-/* Bits in intr_event and intr_mask */
-#define IE_NP_ERROR 0x8000
-#define IE_SIGNAL_OFF 0x4000
-#define IE_LE_CTR 0x2000
-#define IE_MINI_CTR 0x1000
-#define IE_VSYM_CTR 0x0800
-#define IE_PHY_INVALID 0x0400
-#define IE_EBUF_ERR 0x0200
-#define IE_TNE_EXP 0x0100
-#define IE_TPC_EXP 0x0080
-#define IE_PCM_ENABLED 0x0040
-#define IE_PCM_BREAK 0x0020
-#define IE_SELF_TEST 0x0010
-#define IE_TRACE_PROP 0x0008
-#define IE_PCM_CODE 0x0004
-#define IE_LS_MATCH 0x0002
-#define IE_PARITY_ERR 0x0001
-
-/* Correct value for BIST signature */
-#define BIST_CORRECT 0x6ecd
diff --git a/drivers/ap1000/ap.c b/drivers/ap1000/ap.c
deleted file mode 100644
index 6e05d7cb5..000000000
--- a/drivers/ap1000/ap.c
+++ /dev/null
@@ -1,307 +0,0 @@
- /*
- * Copyright 1996 The Australian National University.
- * Copyright 1996 Fujitsu Laboratories Limited
- *
- * This software may be distributed under the terms of the Gnu
- * Public License version 2 or later
- */
-/*
- * ap.c - Single AP1000 block driver.
- *
- * (C) dwalsh, Pious project, DCS, ANU 1996
- *
- * This block driver is designed to simply to perform
- * io operations to the hosts file system.
- *
- * Heavily modified by tridge
- *
- */
-
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/fs.h>
-#include <linux/ext2_fs.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/module.h>
-#include <asm/uaccess.h>
-#include <asm/ap1000/apservice.h>
-
-#define AP_DEBUG 0
-
-#define MAJOR_NR APBLOCK_MAJOR
-#define AP_DRIVER 1
-#include <linux/blk.h>
-
-#define NUM_APDEVS 8
-#define MAX_REQUESTS 1
-
-static DECLARE_WAIT_QUEUE_HEAD(busy_wait);
-
-static int ap_blocksizes[NUM_APDEVS];
-static int ap_length[NUM_APDEVS];
-static int ap_fds[NUM_APDEVS];
-
-#define SECTOR_BLOCK_SHIFT 9
-#define AP_BLOCK_SHIFT 12 /* 4k blocks */
-#define AP_BLOCK_SIZE (1<<AP_BLOCK_SHIFT)
-
-static volatile int request_count = 0;
-
-static void ap_release(struct inode * inode, struct file * filp)
-{
- MOD_DEC_USE_COUNT;
-}
-
-static void ap_request(request_queue_t * q)
-{
- struct cap_request creq;
- unsigned int minor;
- int offset, len;
- struct request *req;
-
- if (request_count >= MAX_REQUESTS) return;
-
-repeat:
-
- if (!CURRENT) {
- return;
- }
-
- if (MAJOR(CURRENT->rq_dev) != MAJOR_NR) {
- panic(DEVICE_NAME ": request list destroyed");
- }
- if (CURRENT->bh) {
- if (!buffer_locked(CURRENT->bh)) {
- panic(DEVICE_NAME ": block not locked");
- }
- }
-
- req = CURRENT;
-
- minor = MINOR(req->rq_dev);
-
- if (minor >= NUM_APDEVS) {
- printk("apblock: request for invalid minor %d\n",minor);
- end_request(0);
- goto repeat;
- }
-
- offset = req->sector;
- len = req->current_nr_sectors;
-
- if ((offset + len) > ap_length[minor]) {
- printk("apblock: request for invalid sectors %d -> %d\n",
- offset,offset+len);
- end_request(0);
- goto repeat;
- }
-
- if (ap_fds[minor] == -1) {
- printk("apblock: minor %d not open\n",minor);
- end_request(0);
- goto repeat;
- }
-
- /* convert to our units */
- offset <<= SECTOR_BLOCK_SHIFT;
- len <<= SECTOR_BLOCK_SHIFT;
-
- /* setup a request for the host */
- creq.cid = mpp_cid();
- creq.size = sizeof(creq);
- creq.header = 0;
- creq.data[0] = (int)(req);
- creq.data[1] = ap_fds[minor];
- creq.data[2] = offset;
- creq.data[3] = len;
-
- switch (req->cmd) {
- case READ:
-#if AP_DEBUG
- printk("apblock: read req=0x%x len=%d offset=%d\n",
- req,len,offset);
-#endif
- creq.type = REQ_BREAD;
- if (bif_queue(&creq,0,0)) {
- return;
- }
- break;
-
- case WRITE:
-#if AP_DEBUG
- printk("apblock: write req=0x%x len=%d offset=%d\n",
- req,len,offset);
-#endif
- creq.type = REQ_BWRITE;
- creq.size += len;
- if (bif_queue_nocopy(&creq,req->buffer,creq.size - sizeof(creq))) {
- return;
- }
- break;
-
- default:
- printk("apblock: unknown ap op %d\n",req->cmd);
- end_request(0);
- return;
- }
-
- if (++request_count < MAX_REQUESTS)
- goto repeat;
-}
-
-/* this is called by ap1000/bif.c when a read/write has completed */
-void ap_complete(struct cap_request *creq)
-{
-#if AP_DEBUG
- struct request *req = (struct request *)(creq->data[0]);
-
- printk("request 0x%x complete\n",req);
-#endif
- end_request(1);
- request_count--;
- ap_request(NULL);
-}
-
-
-/* this is called by ap1000/bif.c to find a buffer to put a BREAD into
- using DMA */
-char *ap_buffer(struct cap_request *creq)
-{
- struct request *req = (struct request *)(creq->data[0]);
-
- return(req->buffer);
-}
-
-
-static int ap_open(struct inode * inode, struct file * filp)
-{
- struct cap_request creq;
- int minor;
- minor = DEVICE_NR(inode->i_rdev);
-
-#if AP_DEBUG
- printk("ap_open: minor=%x\n", minor);
-#endif
-
- if (minor >= NUM_APDEVS)
- return -ENODEV;
-
- /* if its already open then don't do anything */
- if (ap_fds[minor] != -1)
- return 0;
-
- /* send the open request to the front end */
- creq.cid = mpp_cid();
- creq.type = REQ_BOPEN;
- creq.header = 0;
- creq.size = sizeof(creq);
- creq.data[0] = minor;
-
- bif_queue(&creq,0,0);
-
- /* wait for the reply */
- while (ap_fds[minor] == -1)
- sleep_on(&busy_wait);
-
- return 0;
-}
-
-
-static int ap_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- if (!inode || !inode->i_rdev)
- return -EINVAL;
-
- switch (cmd) {
- case BLKGETSIZE: /* Return device size */
- if (put_user(ap_length[MINOR(inode->i_rdev)],(long *) arg))
- return -EFAULT;
- return 0;
-
- default:
- break;
- };
-
- return 0;
-}
-
-
-/* this is called by ap1000/bif.c when a open reply comes in */
-void ap_open_reply(struct cap_request *creq)
-{
- int minor = creq->data[0];
-
- ap_fds[minor] = creq->data[1];
- ap_length[minor] = creq->data[2] >> SECTOR_BLOCK_SHIFT;
-
-#if AP_DEBUG
- printk("ap opened minor %d length=%d fd=%d\n",
- minor,ap_length[minor],ap_fds[minor]);
-#endif
-
- wake_up(&busy_wait);
-}
-
-static struct block_device_operations ap_fops = {
- open: ap_open,
- release: ap_release,
- ioctl: ap_ioctl,
-};
-
-
-int ap_init(void)
-{
- int i;
- static int done = 0;
-
- if (done) return(1);
-
- if (register_blkdev(MAJOR_NR,"apblock",&ap_fops)) {
- printk("ap: unable to get major %d for ap block dev\n",MAJOR_NR);
- return -1;
- }
- printk("ap_init: register dev %d\n", MAJOR_NR);
- blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), &ap_request);
-
- for (i=0;i<NUM_APDEVS;i++) {
- ap_blocksizes[i] = AP_BLOCK_SIZE;
- ap_length[i] = 0;
- ap_fds[i] = -1;
- }
-
- blksize_size[MAJOR_NR] = ap_blocksizes;
-
- read_ahead[MAJOR_NR] = 32; /* 16k read ahead */
- for (i=0;i<NUM_APDEVS;i++)
- register_disk(NILL, MKDEV(MAJOR_NR,i), 1, &ap_fops, 0);
-
- return(0);
-}
-
-/* loadable module support */
-
-#ifdef MODULE
-
-int init_module(void)
-{
- int error = ap_init();
- if (!error)
- printk(KERN_INFO "APBLOCK: Loaded as module.\n");
- return error;
-}
-
-/* Before freeing the module, invalidate all of the protected buffers! */
-void cleanup_module(void)
-{
- int i;
-
- for (i = 0 ; i < NUM_APDEVS; i++)
- invalidate_buffers(MKDEV(MAJOR_NR, i));
-
- unregister_blkdev( MAJOR_NR, "apblock" );
- blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
-}
-
-#endif /* MODULE */
diff --git a/drivers/ap1000/apfddi-reg.h b/drivers/ap1000/apfddi-reg.h
deleted file mode 100644
index b3f25fb2a..000000000
--- a/drivers/ap1000/apfddi-reg.h
+++ /dev/null
@@ -1,14 +0,0 @@
- /*
- * Copyright 1996 The Australian National University.
- * Copyright 1996 Fujitsu Laboratories Limited
- *
- * This software may be distributed under the terms of the Gnu
- * Public License version 2 or later
- */
-/* FDDI register pointers */
-extern volatile struct formac *mac;
-extern volatile struct plc *plc;
-extern volatile int *csr0;
-extern volatile int *csr1;
-extern volatile int *buffer_mem;
-extern volatile int *fifo;
diff --git a/drivers/ap1000/apfddi.c b/drivers/ap1000/apfddi.c
deleted file mode 100644
index b215e8d03..000000000
--- a/drivers/ap1000/apfddi.c
+++ /dev/null
@@ -1,702 +0,0 @@
- /*
- * Copyright 1996 The Australian National University.
- * Copyright 1996 Fujitsu Laboratories Limited
- *
- * This software may be distributed under the terms of the Gnu
- * Public License version 2 or later
- */
-/*
- * $Id: apfddi.c,v 1.6 1996/12/18 01:45:51 tridge Exp $
- *
- * Network interface definitions for AP1000 fddi device.
- */
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/fs.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/socket.h>
-#include <linux/errno.h>
-#include <linux/fcntl.h>
-#include <linux/in.h>
-#include <linux/if_ether.h> /* For the statistics structure. */
-#include <linux/netdevice.h>
-#include <linux/if_arp.h>
-
-#include <asm/system.h>
-#include <asm/segment.h>
-#include <asm/io.h>
-
-#include <linux/inet.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <net/sock.h>
-
-#include <asm/ap1000/apservice.h>
-#include <asm/ap1000/apreg.h>
-#include <asm/irq.h>
-
-#include <net/arp.h>
-
-#include "apfddi.h"
-#include "smt-types.h"
-#include "mac.h"
-#include "plc.h"
-#include "am79c830.h"
-#include "apfddi-reg.h"
-
-volatile struct formac *mac;
-volatile struct plc *plc;
-volatile int *csr0;
-volatile int *csr1;
-volatile int *buffer_mem;
-volatile int *fifo;
-
-#define APFDDI_DEBUG 0
-
-#define APFDDI_IRQ 7
-
-#define T(x) (-SECS_TO_FDDI_TIME(x))
-
-struct plc_info plc_info = {
- pt_s, /* port_type */
- T(1.6e-3), /* c_min */
- T(50e-6), /* tl_min */
- T(5e-3), /* tb_min */
- T(100e-3), /* t_out */
- T(50e-3), /* lc_short */
- T(500e-3), /* lc_medium */
- T(5.0), /* lc_long */
- T(50.0), /* lc_extended */
- T(3.5e-3), /* t_scrub */
- T(1.3e-3), /* ns_max */
-};
-
-struct mac_info mac_info = {
- T(165e-3), /* tmax */
- T(3.5e-3), /* tvx */
- T(20e-3), /* treq */
- { 0x42, 0x59 }, /* s_address */
- { 0x42, 0x59, 0x10, 0x76, 0x88, 0x82 }, /* l_address */
- { 0 }, /* s_group_adrs */
- { 0 }, /* l_group_adrs */
- 0, /* rcv_own_frames */
- 1, /* only_good_frames */
-};
-
-u_char fddi_bitrev[256] = {
- 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
- 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
- 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
- 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
- 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
- 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
- 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
- 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
- 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
- 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
- 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
- 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
- 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
- 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
- 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
- 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
- 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
- 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
- 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
- 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
- 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
- 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
- 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
- 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
- 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
- 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
- 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
- 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
- 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
- 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
- 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
- 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
-};
-
-/* XXX our hardware address, canonical bit order */
-static u_char apfddi_saddr[6] = { 0x42, 0x9a, 0x08, 0x6e, 0x11, 0x41 };
-
-struct net_device *apfddi_device = NULL;
-struct net_device_stats *apfddi_stats = NULL;
-
-volatile struct apfddi_queue *apfddi_queue_top = NULL;
-
-void map_regs(void)
-{
- unsigned long reg_base_addr = 0xfbf00000;
-
- mac = (volatile struct formac *) (reg_base_addr + FORMAC);
- plc = (volatile struct plc *) (reg_base_addr + PLC);
- csr0 = (volatile int *) (reg_base_addr + CSR0);
- csr1 = (volatile int *) (reg_base_addr + CSR1);
- buffer_mem = (volatile int *) (reg_base_addr + BUFFER_MEM);
- fifo = (volatile int *) (reg_base_addr + FIFO);
-}
-
-int ring_op;
-
-void apfddi_startup(void)
-{
- int reason;
-
-#if APFDDI_DEBUG
- printk("In apfddi_startup\n");
-#endif
-
- *csr0 = CS0_LED0;
- ring_op = 0;
- if (*csr1 & 0xf078) {
- *csr1 = CS1_RESET_MAC | CS1_RESET_FIFO;
- *csr1 = 0;
- reason = 1;
- printk("resetting after power-on\n");
- } else {
- *csr1 = CS1_RESET_FIFO;
- *csr1 = 0;
- reason = plc_inited(&plc_info);
- if (reason)
- printk("resetting: plc reason %d\n", reason);
- }
- if (reason) {
-#if APFDDI_DEBUG
- printk("Calling plc_init\n");
-#endif
- plc_init(&plc_info);
-#if APFDDI_DEBUG
- printk("Calling mac_init\n");
-#endif
- mac_init(&mac_info);
- *csr0 |= CS0_LED1;
- pc_start(loop_none);
-
- } else {
- *csr0 |= CS0_LED2 | CS0_LED1;
- reason = mac_inited(&mac_info);
- if (reason) {
- printk("resetting mac: reason %d\n", reason);
- mac_init(&mac_info);
- mac_reset(loop_none);
- mac_claim();
- } else {
- ring_op = 1;
- *csr0 &= ~(CS0_LED0 | CS0_LED1 | CS0_LED2);
- }
- }
-}
-
-void apfddi_off(void)
-{
- *csr0 &= ~CS0_LED1;
- pc_stop();
-}
-
-void apfddi_sleep(void)
-{
- mac_sleep();
- plc_sleep();
-}
-
-void apfddi_poll(void)
-{
- if (*csr0 & CS0_PHY_IRQ)
- plc_poll();
- if (*csr0 & CS0_MAC_IRQ)
- mac_poll();
-}
-
-void set_cf_join(int on)
-{
- if (on) {
-#if APFDDI_DEBUG
- printk("apfddi: joined the ring!\n");
-#endif
- mac_reset(loop_none);
- *csr0 |= CS0_LED2;
- mac_claim();
- } else {
- mac_disable();
- ring_op = 0;
- *csr0 = (*csr0 & ~CS0_LED2) | CS0_LED1 | CS0_LED0;
- }
-}
-
-void set_ring_op(int up)
-{
- ring_op = up;
- if (up) {
-#if APFDDI_DEBUG
- printk("apfddi: ring operational!\n");
-#endif
- *csr0 &= ~(CS0_LED2 | CS0_LED1 | CS0_LED0);
- } else
- *csr0 |= CS0_LED2 | CS0_LED1 | CS0_LED0;
-}
-
-void rmt_event(int st)
-{
- if (st & (S2_BEACON_STATE|S2_MULTIPLE_DA|S2_TOKEN_ERR
- |S2_DUPL_CLAIM|S2_TRT_EXP_RECOV)) {
- printk("st2 = %x\n", st);
- }
-}
-
-
-int apfddi_init(struct net_device *dev);
-static void apfddi_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static int apfddi_xmit(struct sk_buff *skb, struct net_device *dev);
-int apfddi_rx(struct mac_buf *mbuf);
-static struct net_device_stats *apfddi_get_stats(struct net_device *dev);
-#if APFDDI_DEBUG
-void dump_packet(char *action, char *buf, int len, int seq);
-#endif
-
-/*
- * Create FDDI header for an arbitrary protocol layer
- *
- * saddr=NULL means use device source address (always will anyway)
- * daddr=NULL means leave destination address (eg unresolved arp)
- */
-static int apfddi_hard_header(struct sk_buff *skb, struct net_device *dev,
- unsigned short type, void *daddr,
- void *saddr, unsigned len)
-{
- struct fddi_header *fh;
- struct llc_header *lh;
- u_char *base_header;
- u_char *fd_daddr = (u_char *)daddr;
- int i;
-
-#if APFDDI_DEBUG
- printk("In apfddi_hard_header\n");
-#endif
-
- if (skb == NULL) {
- printk("Null skb in apfddi_hard_header... returning...\n");
- return 0;
- }
-
- switch(type) {
- case ETH_P_IP:
-#if APFDDI_DEBUG
- printk("apfddi_hard_header: Processing IP packet\n");
-#endif
- break;
- case ETH_P_ARP:
-#if APFDDI_DEBUG
- printk("apfddi_hard_header: Processing ARP packet\n");
-#endif
- break;
- case ETH_P_RARP:
-#if APFDDI_DEBUG
- printk("apfddi_hard_header: Processing RARP packet\n");
-#endif
- break;
- default:
- printk("apfddi_hard_header: I don't understand protocol %d (0x%x)\n",
- type, type);
- apfddi_stats->tx_errors++;
- return 0;
- }
-
- base_header = (u_char *)skb_push(skb, FDDI_HARDHDR_LEN-4);
- if (base_header == NULL) {
- printk("apfddi_hard_header: Memory squeeze, dropping packet.\n");
- apfddi_stats->tx_dropped++;
- return 0;
- }
- fh = (struct fddi_header *)(base_header + 3);
- lh = (struct llc_header *)((char *)fh + FDDI_HDRLEN);
-
- lh->llc_dsap = lh->llc_ssap = LLC_SNAP_LSAP;
- lh->snap_control = LLC_UI;
- lh->snap_org_code[0] = 0;
- lh->snap_org_code[1] = 0;
- lh->snap_org_code[2] = 0;
- lh->snap_ether_type = htons(type);
-
-#if APFDDI_DEBUG
- printk("snap_ether_type is %d (0x%x)\n", lh->snap_ether_type,
- lh->snap_ether_type);
-#endif
-
- fh->fddi_fc = FDDI_FC_LLC;
-
- /*
- * Fill in the source address.
- */
- for (i = 0; i < 6; i++)
- fh->fddi_shost[i] = fddi_bitrev[apfddi_saddr[i]];
-
- /*
- * Fill in the destination address.
- */
- if (daddr) {
-#if APFDDI_DEBUG
- printk("daddr is: ");
-#endif
- for (i = 0; i < 6; i++) {
- fh->fddi_dhost[i] = fddi_bitrev[fd_daddr[i]];
-#if APFDDI_DEBUG
- printk("%x(%x):",fh->fddi_dhost[i], fd_daddr[i]);
-#endif
- }
-#if APFDDI_DEBUG
- printk("\n");
-#endif
- return(FDDI_HARDHDR_LEN-4);
- }
- else {
-#if APFDDI_DEBUG
- printk("apfddi_hard_header, daddr was NULL\n");
-#endif
- return -(FDDI_HARDHDR_LEN-4);
- }
-}
-
-/*
- * Rebuild the FDDI header. This is called after an ARP (or in future
- * other address resolution) has completed on this sk_buff. We now let
- * ARP fill in the other fields.
- */
-static int apfddi_rebuild_header(void *buff, struct net_device *dev,
- unsigned long raddr, struct sk_buff *skb)
-{
- int i, status;
- struct fddi_header *fh = (struct fddi_header *)(buff+3);
-
-#if APFDDI_DEBUG
- printk("In apfddi_rebuild_header, dev is %x apfddi_device is %x\n", dev,
- apfddi_device);
- printk("rebuild header for fc 0x%x\n", fh->fddi_fc);
- printk("dest address is:\n");
- for (i = 0; i < 6; i++) printk("%x:", fh->fddi_dhost[i]);
-#endif
- status = arp_find(raddr, skb) ? 1 : 0;
-
- if (!status) {
-#if APFDDI_DEBUG
- printk("dest address is now:\n");
- for (i = 0; i < 6; i++) printk("%x:", fh->fddi_dhost[i]);
- printk("status is %d\n", status);
-#endif
- /*
- * Bit reverse the dest_address.
- */
- for (i = 0; i < 6; i++)
- fh->fddi_dhost[i] = fddi_bitrev[fh->fddi_dhost[i]];
- }
-#if APFDDI_DEBUG
- printk("\n");
-#endif
- return(status);
-}
-
-static int apfddi_set_mac_address(struct net_device *dev, void *addr)
-{
-#if APFDDI_DEBUG
- printk("In apfddi_set_mac_address\n");
-#endif
- return (0);
-}
-
-static void apfddi_set_multicast_list(struct net_device *dev)
-{
-#if APFDDI_DEBUG
- printk("In apfddi_set_multicast_list\n");
-#endif
-}
-
-static int apfddi_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
-{
-#if APFDDI_DEBUG
- printk("In apfddi_do_ioctl\n");
-#endif
- return (0);
-}
-
-static int apfddi_set_config(struct net_device *dev, struct ifmap *map)
-{
-#if APFDDI_DEBUG
- printk("In apfddi_set_config\n");
-#endif
- return (0);
-}
-
-/*
- * Opening the fddi device through ifconfig.
- */
-int apfddi_open(struct net_device *dev)
-{
- static int already_run = 0;
- unsigned flags;
- int res;
-
- if (already_run) {
- apfddi_startup();
- *csr0 |= CS0_INT_ENABLE;
- return 0;
- }
- already_run = 1;
-
- map_regs();
- apfddi_startup();
-
- save_flags(flags); cli();
- if ((res = request_irq(APFDDI_IRQ, apfddi_interrupt, SA_INTERRUPT,
- "apfddi", dev))) {
- printk("Failed to install apfddi handler error=%d\n", res);
- restore_flags(flags);
- return(0);
- }
- enable_irq(APFDDI_IRQ);
- restore_flags(flags);
-
-#if APFDDI_DEBUG
- printk("Installed apfddi interrupt handler\n");
-#endif
- *csr0 |= CS0_INT_ENABLE;
-#if APFDDI_DEBUG
- printk("Enabled fddi interrupts\n");
-#endif
-
- return 0;
-}
-
-/*
- * Stop the fddi device through ifconfig.
- */
-int apfddi_stop(struct net_device *dev)
-{
- *csr0 &= ~CS0_INT_ENABLE;
- apfddi_sleep();
- return 0;
-}
-
-
-/*
- * Initialise fddi network interface.
- */
-int apfddi_init(struct net_device *dev)
-{
- int i;
-
- /*
- * Check if this thing has already been initialised.
- */
- if (apfddi_device != NULL)
- return -ENODEV;
-
- printk("apfddi_init(): Initialising fddi interface\n");
-
- apfddi_device = dev;
-
- dev->open = apfddi_open;
- dev->stop = apfddi_stop;
- dev->hard_start_xmit = apfddi_xmit;
- dev->get_stats = apfddi_get_stats;
- dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_ATOMIC);
- if (dev->priv == NULL)
- return -ENOMEM;
- memset(dev->priv, 0, sizeof(struct net_device_stats));
- apfddi_stats = (struct net_device_stats *)apfddi_device->priv;
-
- /* Initialise the fddi device structure */
- for (i = 0; i < DEV_NUMBUFFS; i++)
- skb_queue_head_init(&dev->buffs[i]);
-
- dev->hard_header = apfddi_hard_header;
- dev->rebuild_header = apfddi_rebuild_header;
- dev->set_mac_address = apfddi_set_mac_address;
- dev->header_cache_update = NULL;
- dev->do_ioctl = apfddi_do_ioctl;
- dev->set_config = apfddi_set_config;
- dev->set_multicast_list = apfddi_set_multicast_list;
- dev->type = ARPHRD_ETHER;
- dev->hard_header_len = FDDI_HARDHDR_LEN;
- dev->mtu = FDDIMTU;
- dev->addr_len = 6;
- memcpy(dev->dev_addr, apfddi_saddr, sizeof(apfddi_saddr));
- dev->tx_queue_len = 100; /* XXX What should this be? */
- dev->irq = APFDDI_IRQ;
-
- memset(dev->broadcast, 0xFF, ETH_ALEN);
-
- return(0);
-}
-
-static void apfddi_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-#if APFDDI_DEBUG
- static int times = 0;
-#endif
- unsigned flags;
- save_flags(flags); cli();
-
-#if APFDDI_DEBUG
- printk("In apfddi_interrupt irq %d dev_id %p times %d\n",
- irq, dev_id, ++times);
-#endif
-
- apfddi_poll();
- restore_flags(flags);
-}
-
-#if APFDDI_DEBUG
-static char *flagbits[8] = {
- "fin", "syn", "rst", "push", "ack", "urg", "6", "7"
-};
-
-void dump_packet(action, buf, len, seq)
- char *action, *buf;
- int len, seq;
-{
- int i, flags;
- char *sep;
-
- printk("%s packet %d of %d bytes at %d:\n", action, seq,
- len, jiffies);
- printk(" from %x to %x pktid=%d ttl=%d pcol=%d len=%d\n",
- *(long *)(buf+12), *(long *)(buf+16), *(u_short *)(buf+4),
- *(unsigned char *)(buf+8), buf[9], *(u_short *)(buf+2));
- if( buf[9] == 6 || buf[9] == 17 ){
- /* TCP or UDP */
- printk(" sport=%d dport=%d",
- *(u_short *)(buf+20), *(u_short *)(buf+22));
- if( buf[9] == 6 ){
- printk(" seq=%d ack=%d win=%d flags=<",
- *(long *)(buf+24), *(long *)(buf+28),
- *(unsigned short *)(buf+34));
- flags = buf[33];
- sep = "";
- for (i = 7; i >= 0; --i) {
- if (flags & (1 << i)) {
- printk("%s%s", sep, flagbits[i]);
- sep = "+";
- }
- }
- printk(">");
- }
- printk("\n");
- }
-}
-#endif
-
-#if APFDDI_DEBUG
-static void apfddi_print_frame(struct sk_buff *skb)
-{
- int i;
- struct llc_header *lh;
- static int seq = 0;
-
-#if 0
- printk("skb->len is %d\n", skb->len);
- printk("fc is 0x%x\n", *(u_char *)(skb->data+3));
- printk("dest address is:\n");
- for (i = 0; i < 6; i++) {
- printk("%x:", fddi_bitrev[*(u_char *)(skb->data+4+i)]);
- }
- printk("\n");
- printk("source address is:\n");
- for (i = 0; i < 6; i++) {
- printk("%x:", fddi_bitrev[*(u_char *)(skb->data+10+i)]);
- }
- printk("\n");
-#endif
- lh = (struct llc_header *)(skb->data+16);
-#if 0
- printk("llc_dsp %d llc_ssap %d snap_control %d org_code [0]=%d [1]=%d [2]=%d ether_type=%d\n",
- lh->llc_dsap, lh->llc_ssap, lh->snap_control,
- lh->snap_org_code[0], lh->snap_org_code[1], lh->snap_org_code[2],
- lh->snap_ether_type);
-#endif
- if (lh->snap_ether_type == ETH_P_IP)
- dump_packet("apfddi_xmit:", skb->data+24, skb->len-24, seq++);
-}
-#endif
-
-/*
- * Transmitting packet over FDDI.
- */
-static int apfddi_xmit(struct sk_buff *skb, struct net_device *dev)
-{
- unsigned long flags;
-
-#if APFDDI_DEBUG
- printk("In apfddi_xmit\n");
-#endif
-
- /*
- * Check there is some work to do.
- */
- if (skb == NULL || dev == NULL)
- return(0);
-
-#if APFDDI_DEBUG
- printk("skb address is for apfddi 0x%x\n", skb);
-#endif
-
- /*
- * Check lock variable.
- */
- save_flags(flags); cli();
- if (dev->tbusy != 0) {
- restore_flags(flags);
- printk("apfddi_xmit: device busy\n");
- apfddi_stats->tx_errors++;
- return 1;
- }
- restore_flags(flags);
- dev->tbusy = 1;
-
- dev->trans_start = jiffies;
-
- skb->mac.raw = skb->data;
-
- /*
- * Append packet onto send queue.
- */
- if (mac_queue_append(skb)) {
- /*
- * No memory.
- */
- return 1;
- }
-
- /*
- * Process packet queue.
- */
- mac_process();
-
- apfddi_stats->tx_packets++;
- dev->tbusy = 0;
- return 0;
-}
-
-#if APFDDI_DEBUG
-void print_mbuf(struct mac_buf *mbuf)
-{
- printk("mac %p length=%d ptr=%p wraplen=%d wrapptr=%x fr_start=%d fr_end=%d\n",
- mbuf, mbuf->length, mbuf->ptr, mbuf->wraplen, mbuf->wrapptr,
- mbuf->fr_start, mbuf->fr_end);
-}
-#endif
-
-/*
- * Return statistics of fddi driver.
- */
-static struct net_device_stats *apfddi_get_stats(struct net_device *dev)
-{
- return((struct net_device_stats *)dev->priv);
-}
-
-
-
-
diff --git a/drivers/ap1000/apfddi.h b/drivers/ap1000/apfddi.h
deleted file mode 100644
index a77dd6160..000000000
--- a/drivers/ap1000/apfddi.h
+++ /dev/null
@@ -1,142 +0,0 @@
- /*
- * Copyright 1996 The Australian National University.
- * Copyright 1996 Fujitsu Laboratories Limited
- *
- * This software may be distributed under the terms of the Gnu
- * Public License version 2 or later
- */
-#define BUFFER_MEM 0x40000
-#define CSR0 0x60000
-#define CSR1 0x60004
-#define PLC 0x60080
-#define FORMAC 0x60200
-#define FIFO 0x68000
-
-/* Size of buffer memory */
-#define BUFFER_SIZE 32768 /* words; 128kB */
-
-/* Bits in CSR0 */
-#define CS0_INT_REQ 0x8000 /* board interrupt request asserted */
-#define CS0_MAC_IRQ 0x4000 /* FORMAC is requesting interrupt */
-#define CS0_PHY_IRQ 0x2000 /* PLC is requesting interrupt */
-#define CS0_LED2 0x1000 /* turn on led 2 */
-#define CS0_DO_IRQ 0x0200 /* request interrupt */
-#define CS0_INT_ENABLE 0x0100 /* enable interrupt requests */
-#define CS0_DMA_ENABLE 0x0080 /* enable DMA requests */
-#define CS0_DMA_RECV 0x0040 /* DMA requests are in receive dirn. */
-#define CS0_LED1 0x0010 /* turn on led 1 */
-#define CS0_LED0 0x0008 /* turn on led 0 (red) */
-#define CS0_HREQ 0x0007 /* host request to FORMAC */
-#define CS0_HREQ_WSPEC 0x0002 /* write special frames */
-#define CS0_HREQ_RECV 0x0003 /* read receive queue */
-#define CS0_HREQ_WS 0x0004 /* write synchronous queue */
-#define CS0_HREQ_WA0 0x0005 /* write async queue 0 */
-#define CS0_HREQ_WA1 0x0006 /* write async queue 1 */
-#define CS0_HREQ_WA2 0x0007 /* write async queue 2 */
-
-/* Bits in CSR1 */
-#define CS1_THIS_QAF 0x0800 /* this queue almost full */
-#define CS1_FIFO_TAG 0x0400 /* tag of word at head of fifo */
-#define CS1_BUF_RD_TAG 0x0200 /* tag of last word read from buffer */
-#define CS1_BUF_WR_TAG 0x0100 /* tag to write to buffer */
-#define CS1_TAGMODE 0x0080 /* enable tag mode */
-#define CS1_RESET_MAC 0x0040 /* reset FORMAC and PLC */
-#define CS1_RESET_FIFO 0x0020 /* reset FIFO */
-#define CS1_CLEAR_QAF 0x0010 /* clear queue-almost-full bits */
-#define CS1_FIFO_LEVEL 0x0007 /* # words in FIFO (0 - 4) */
-
-/*
- * FDDI Frame Control values.
- */
-#define FDDI_SMT 0x41
-#define FDDI_SMT_NSA 0x4f
-#define FDDI_FC_LLC 0x50
-#define FDDI_FC_LLC_MASK 0xf0
-
-/*
- * Unnumbered LLC format commands
- */
-#define LLC_UI 0x3
-#define LLC_UI_P 0x13
-#define LLC_DISC 0x43
-#define LLC_DISC_P 0x53
-#define LLC_UA 0x63
-#define LLC_UA_P 0x73
-#define LLC_TEST 0xe3
-#define LLC_TEST_P 0xf3
-#define LLC_FRMR 0x87
-#define LLC_FRMR_P 0x97
-#define LLC_DM 0x0f
-#define LLC_DM_P 0x1f
-#define LLC_XID 0xaf
-#define LLC_XID_P 0xbf
-#define LLC_SABME 0x6f
-#define LLC_SABME_P 0x7f
-
-/*
- * Supervisory LLC commands
- */
-#define LLC_RR 0x01
-#define LLC_RNR 0x05
-#define LLC_REJ 0x09
-
-/*
- * Info format - dummy only
- */
-#define LLC_INFO 0x00
-
-/*
- * ISO PDTR 10178 contains among others
- */
-#define LLC_X25_LSAP 0x7e
-#define LLC_SNAP_LSAP 0xaa
-#define LLC_ISO_LSAP 0xfe
-
-/*
- * Structure of the FDDI MAC header.
- */
-struct fddi_header {
- u_char fddi_fc; /* frame control field */
- u_char fddi_dhost[6]; /* destination address */
- u_char fddi_shost[6]; /* source address */
-};
-
-/*
- * Structure of LLC/SNAP header.
- */
-struct llc_header {
- u_char llc_dsap;
- u_char llc_ssap;
- u_char snap_control;
- u_char snap_org_code[3];
- u_short snap_ether_type;
-};
-
-#define FDDI_HDRLEN 13 /* sizeof(struct fddi_header) */
-#define LLC_SNAPLEN 8 /* bytes for LLC/SNAP header */
-#define FDDI_HARDHDR_LEN 28 /* Hard header size */
-
-#define FDDIMTU 4352
-
-
-/* Types of loopback we can do. */
-typedef enum {
- loop_none,
- loop_formac,
- loop_plc_lm,
- loop_plc_eb,
- loop_pdx
-} LoopbackType;
-
-/* Offset from fifo for writing word with tag. */
-#define FIFO_TAG 0x80
-
-#define MAX_FRAME_LEN 4500
-
-void set_ring_op(int up);
-void rmt_event(int st);
-void set_cf_join(int on);
-
-extern struct net_device *apfddi_device;
-extern struct net_device_stats *apfddi_stats;
-
diff --git a/drivers/ap1000/bif.c b/drivers/ap1000/bif.c
deleted file mode 100644
index 331ee0f26..000000000
--- a/drivers/ap1000/bif.c
+++ /dev/null
@@ -1,280 +0,0 @@
- /*
- * Copyright 1996 The Australian National University.
- * Copyright 1996 Fujitsu Laboratories Limited
- *
- * This software may be distributed under the terms of the Gnu
- * Public License version 2 or later
- */
-/*
- * $Id: bif.c,v 1.13 1996/12/18 01:45:52 tridge Exp $
- *
- * Network interface definitions for bif device.
- */
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/fs.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/socket.h>
-#include <linux/errno.h>
-#include <linux/fcntl.h>
-#include <linux/in.h>
-#include <linux/if_ether.h> /* For the statistics structure. */
-#include <linux/netdevice.h>
-#include <linux/if_arp.h> /* For ARPHRD_BIF */
-
-#include <asm/system.h>
-#include <asm/segment.h>
-#include <asm/io.h>
-
-#include <linux/inet.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <net/sock.h>
-
-#include <asm/ap1000/apservice.h>
-#include <asm/ap1000/apreg.h>
-
-#define BIF_DEBUG 0
-#if BIF_DEBUG
-static int seq = 0;
-#endif
-
-#define BIF_MTU 10240
-
-static struct net_device *bif_device = 0;
-static struct net_device_stats *bif_stats = 0;
-
-int bif_init(struct net_device *dev);
-int bif_open(struct net_device *dev);
-static int bif_xmit(struct sk_buff *skb, struct net_device *dev);
-int bif_rx(struct sk_buff *skb);
-int bif_stop(struct net_device *dev);
-static struct net_device_stats *bif_get_stats(struct net_device *dev);
-
-static int bif_hard_header(struct sk_buff *skb, struct net_device *dev,
- unsigned short type, void *daddr,
- void *saddr, unsigned len)
-{
-#if BIF_DEBUG
- printk("bif_hard_header()\n");
-#endif
-
- skb_push(skb,dev->hard_header_len);
-
- if (daddr) skb->arp = 1;
-
- /* tell IP how much space we took */
- return (dev->hard_header_len);
-}
-
-static int bif_rebuild_header(void *buff, struct net_device *dev,
- unsigned long raddr, struct sk_buff *skb)
-{
- /* this would normally be used to fill in hardware addresses after
- an ARP */
-#if BIF_DEBUG
- printk("bif_rebuild_header()\n");
-#endif
- if (skb) skb->arp = 1;
- return(0);
-}
-
-static int bif_set_mac_address(struct net_device *dev, void *addr)
-{
- printk("BIF: set_mac_address called\n");
- return (0);
-}
-
-static void bif_set_multicast_list(struct net_device *dev)
-{
- return;
-}
-
-static int bif_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
-{
- printk("BIF: Called do_ioctl\n");
- return (0);
-}
-
-static int bif_set_config(struct net_device *dev, struct ifmap *map)
-{
- printk("BIF: Called bif_set_config\n");
- return (0);
-}
-
-/*
- * Initialise bif network interface.
- */
-int bif_init(struct net_device *dev)
-{
- int i;
-
- printk("bif_init(): Initialising bif interface\n");
- bif_device = dev;
-
- dev->mtu = BIF_MTU;
- dev->tbusy = 0;
- dev->hard_start_xmit = bif_xmit;
- dev->hard_header = bif_hard_header;
- dev->hard_header_len = sizeof(struct cap_request);
- dev->addr_len = 0;
- dev->tx_queue_len = 50000; /* no limit (almost!) */
- dev->type = ARPHRD_BIF;
- dev->rebuild_header = bif_rebuild_header;
- dev->open = bif_open;
- dev->flags = IFF_NOARP; /* Don't use ARP on this device */
- dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL);
- if (dev->priv == NULL)
- return -ENOMEM;
- memset(dev->priv, 0, sizeof(struct net_device_stats));
- bif_stats = (struct net_device_stats *)bif_device->priv;
-
-
- dev->stop = bif_stop;
- dev->get_stats = bif_get_stats;
-
- dev->set_mac_address = bif_set_mac_address;
- dev->header_cache_update = NULL;
- dev->do_ioctl = bif_do_ioctl;
- dev->set_config = bif_set_config;
- dev->set_multicast_list = bif_set_multicast_list;
-
- memset(dev->broadcast, 0xFF, ETH_ALEN);
-
- dev_init_buffers(dev);
-
- return(0);
-}
-
-int bif_open(struct net_device *dev)
-{
- printk("In bif_open\n");
- dev->tbusy = 0;
- dev->start = 1;
- return 0;
-}
-
-#if BIF_DEBUG
-static void dump_packet(char *action, char *buf, int len, int seq)
-{
- int flags;
- char *sep;
-
- printk("%s packet %d of %d bytes at %d:\n", action, seq,
- len, (int)jiffies);
- printk(" from %x to %x pktid=%d ttl=%d pcol=%d len=%d\n",
- *(long *)(buf+12), *(long *)(buf+16), *(u_short *)(buf+4),
- *(unsigned char *)(buf+8), buf[9], *(u_short *)(buf+2));
- if( buf[9] == 6 || buf[9] == 17 ){
- /* TCP or UDP */
- printk(" sport=%d dport=%d",
- *(u_short *)(buf+20), *(u_short *)(buf+22));
- if( buf[9] == 6 ){
- printk(" seq=%d ack=%d win=%d flags=<",
- *(long *)(buf+24), *(long *)(buf+28),
- *(unsigned short *)(buf+34));
- flags = buf[33];
- sep = "";
- printk(">");
- }
- printk("\n");
- }
- else {
- printk(" protocol = %d\n", buf[9]);
- }
-}
-#endif
-
-
-static int bif_xmit(struct sk_buff *skb, struct net_device *dev)
-{
- extern int bif_send_ip(int cid,struct sk_buff *skb);
- extern int tnet_send_ip(int cid,struct sk_buff *skb);
- extern int msc_blocked, tnet_ip_enabled;
- u_long destip;
- int cid;
-
- if (skb == NULL || dev == NULL)
- return(0);
-
- destip = *(u_long *)(skb->data+sizeof(struct cap_request)+16);
- cid = ap_ip_to_cid(destip);
-
- skb->dev = dev;
- skb->mac.raw = skb->data;
-
- if (cid != -1 && tnet_ip_enabled && !msc_blocked) {
- tnet_send_ip(cid,skb);
- } else {
- bif_send_ip(cid, skb);
- }
-
- dev->tbusy = 0;
-
- bif_stats->tx_packets++;
-
- mark_bh(NET_BH);
-
- return 0;
-}
-
-
-/*
- * Receive a packet from the BIF - called from interrupt handler.
- */
-int bif_rx(struct sk_buff *skb)
-{
-#if BIF_DEBUG
- dump_packet("bif_rx:", skb->data, skb->len, seq++);
-#endif
-
- if (bif_device == NULL) {
- printk("bif: bif_device is NULL in bif_rx\n");
- dev_kfree_skb(skb);
- return 0;
- }
- skb->dev = bif_device;
- skb->protocol = ETH_P_IP;
-
-#if 1
- /* try disabling checksums on receive */
- if (ap_ip_to_cid(*(u_long *)(((char *)skb->data)+12)) != -1)
- skb->ip_summed = CHECKSUM_UNNECESSARY;
-#endif
-
- /*
- * Inform the network layer of the new packet.
- */
- skb->mac.raw = skb->data;
- netif_rx(skb);
-
- if (bif_stats == NULL) {
- printk("bif: bif_stats is NULL is bif_rx\n");
- return 0;
- }
- bif_stats->rx_packets++;
-
- return 0;
-}
-
-int bif_stop(struct net_device *dev)
-{
- printk("in bif_close\n");
-
- dev->tbusy = 1;
- dev->start = 0;
-
- return 0;
-}
-
-/*
- * Return statistics of bif driver.
- */
-static struct net_device_stats *bif_get_stats(struct net_device *dev)
-{
- return((struct net_device_stats *)dev->priv);
-}
-
diff --git a/drivers/ap1000/ddv.c b/drivers/ap1000/ddv.c
deleted file mode 100644
index 3e32c9c83..000000000
--- a/drivers/ap1000/ddv.c
+++ /dev/null
@@ -1,1008 +0,0 @@
- /*
- * Copyright 1996 The Australian National University.
- * Copyright 1996 Fujitsu Laboratories Limited
- *
- * This software may be distributed under the terms of the Gnu
- * Public License version 2 or later
- */
-/*
- * ddv.c - Single AP1000 block driver.
- *
- * This block driver performs io operations to the ddv option
- * board. (Hopefully:)
- *
- */
-
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/fs.h>
-#include <linux/ext2_fs.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/mm.h>
-#include <linux/malloc.h>
-#define __KERNEL_SYSCALLS__
-#include <linux/unistd.h>
-#include <linux/sched.h>
-#include <asm/pgtable.h>
-#include <asm/uaccess.h>
-#include <linux/module.h>
-#include <asm/ap1000/apreg.h>
-#include <asm/ap1000/DdvReqTable.h>
-
-#define MAJOR_NR DDV_MAJOR
-
-#include <linux/blk.h>
-#include <linux/genhd.h>
-#include <linux/hdreg.h>
-
-#define DDV_DEBUG 0
-#define AIR_DISK 1
-
-#define SECTOR_SIZE 512
-
-/* we can have lots of partitions */
-#define PARTN_BITS 6
-#define NUM_DDVDEVS (1<<PARTN_BITS)
-
-#define PARDISK_BASE (1<<5) /* partitions above this number are
- striped across all the cells */
-#define STRIPE_SHIFT 6
-#define STRIPE_SECTORS (1<<STRIPE_SHIFT) /* number of sectors per stripe */
-
-#define MAX_BNUM 16
-#define MAX_REQUEST (TABLE_SIZE - 2)
-#define REQUEST_LOW 16
-#define REQUEST_HIGH 4
-
-
-/* we fake up a block size larger than the physical block size to try
- to make things a bit more efficient */
-#define SECTOR_BLOCK_SHIFT 9
-
-#define SECTOR_MASK ((BLOCK_SIZE >> 9) - 1)
-
-/* try to read ahead a bit */
-#define DDV_READ_AHEAD 64
-
-static int have_ddv_board = 1;
-static unsigned num_options = 0;
-static unsigned this_option = 0;
-
-extern int ddv_get_mlist(unsigned mptr[],int bnum);
-extern int ddv_set_request(struct request *req,
- int request_type,int bnum,int mlist,int len,int offset);
-extern void ddv_load_kernel(char *opcodep);
-extern int ddv_restart_cpu(void);
-extern int ddv_mlist_available(void);
-static int ddv_revalidate(kdev_t dev, struct gendisk *gdev);
-static void ddv_geninit(void);
-static void ddv_release(struct inode * inode, struct file * filp);
-static void ddv_request1(void);
-
-
-static char *ddv_opcodep = NULL;
-static struct request *next_request = NULL;
-
-static DECLARE_WAIT_QUEUE_HEAD(busy_wait);
-
-static int ddv_blocksizes[NUM_DDVDEVS]; /* in bytes */
-int ddv_sect_length[NUM_DDVDEVS]; /* in sectors */
-int ddv_blk_length[NUM_DDVDEVS]; /* in blocks */
-
-/* these are used by the ddv_daemon, which services remote disk requests */
-static struct remote_request *rem_queue = NULL;
-static struct remote_request *rem_queue_end;
-static DECLARE_WAIT_QUEUE_HEAD(ddv_daemon_wait);
-
-static int opiu_kernel_loaded = 0;
-
-static struct {
- unsigned reads, writes, blocks, rq_started, rq_finished, errors;
- unsigned sectors_read, sectors_written;
-} ddv_stats;
-
-static struct hd_struct partition_tables[NUM_DDVDEVS];
-
-static struct gendisk ddv_gendisk = {
- MAJOR_NR, /* Major number */
- DEVICE_NAME, /* Major name */
- PARTN_BITS, /* Bits to shift to get real from partition */
- 1 << PARTN_BITS, /* Number of partitions per real */
- partition_tables,/* hd struct */
- ddv_blk_length, /* block sizes */
- 1, /* number */
- (void *) NULL, /* internal */
- NULL /* next */
-};
-
-struct ddv_geometry {
- unsigned char heads;
- unsigned char sectors;
- unsigned short cylinders;
- unsigned long start;
-};
-
-static struct ddv_geometry ddv_geometry;
-
-
-struct remote_request {
- union {
- struct remote_request *next;
- void (*fn)(void);
- } u;
- unsigned bnum; /* how many blocks does this contain */
- struct request *reqp; /* pointer to the request on the original cell */
- unsigned cell; /* what cell is the request from */
- struct request req; /* details of the request */
-};
-
-
-static void ddv_set_optadr(void)
-{
- unsigned addr = 0x11000000;
- OPT_IO(OBASE) = addr;
- MSC_IO(MSC_OPTADR) =
- ((addr & 0xff000000)>>16) |
- ((OPTION_BASE & 0xf0000000)>>24) |
- ((OPTION_BASE + 0x10000000)>>28);
- OPT_IO(PRST) = 0;
-}
-
-extern struct RequestTable *RTable;
-extern struct OPrintBufArray *PrintBufs;
-extern struct OAlignBufArray *AlignBufs;
-extern struct DiskInfo *DiskInfo;
-
-static void ddv_release(struct inode * inode, struct file * filp)
-{
-#if DEBUG
- printk("ddv_release started\n");
-#endif
-#if DEBUG
- printk("ddv_release done\n");
-#endif
-}
-
-
-static unsigned in_request = 0;
-static unsigned req_queued = 0;
-
-static void ddv_end_request(int uptodate,struct request *req)
-{
- struct buffer_head * bh;
-
- ddv_stats.rq_finished++;
-
-/* printk("ddv_end_request(%d,%p)\n",uptodate,req); */
-
- req->errors = 0;
- if (!uptodate) {
- printk("end_request: I/O error, dev %s, sector %lu\n",
- kdevname(req->rq_dev), req->sector);
- req->nr_sectors--;
- req->nr_sectors &= ~SECTOR_MASK;
- req->sector += (BLOCK_SIZE / SECTOR_SIZE);
- req->sector &= ~SECTOR_MASK;
- ddv_stats.errors++;
- }
-
- if ((bh = req->bh) != NULL) {
- req->bh = bh->b_reqnext;
- bh->b_reqnext = NULL;
- mark_buffer_uptodate(bh, uptodate);
- unlock_buffer(bh);
- if ((bh = req->bh) != NULL) {
- req->current_nr_sectors = bh->b_size >> 9;
- if (req->nr_sectors < req->current_nr_sectors) {
- req->nr_sectors = req->current_nr_sectors;
- printk("end_request: buffer-list destroyed\n");
- }
- req->buffer = bh->b_data;
- printk("WARNING: ddv: more sectors!\n");
- ddv_stats.errors++;
- return;
- }
- }
- if (req->sem != NULL)
- up(req->sem);
- req->rq_status = RQ_INACTIVE;
- wake_up(&wait_for_request);
-}
-
-
-/* check that a request is all OK to process */
-static int request_ok(struct request *req)
-{
- int minor;
- if (!req) return 0;
-
- if (MAJOR(req->rq_dev) != MAJOR_NR)
- panic(DEVICE_NAME ": bad major number\n");
- if (!buffer_locked(req->bh))
- panic(DEVICE_NAME ": block not locked");
-
- minor = MINOR(req->rq_dev);
- if (minor >= NUM_DDVDEVS) {
- printk("ddv_request: Invalid minor (%d)\n", minor);
- return 0;
- }
-
- if ((req->sector + req->current_nr_sectors) > ddv_sect_length[minor]) {
- printk("ddv: out of range minor=%d offset=%d len=%d sect_length=%d\n",
- minor,(int)req->sector,(int)req->current_nr_sectors,
- ddv_sect_length[minor]);
- return 0;
- }
-
- if (req->cmd != READ && req->cmd != WRITE) {
- printk("unknown request type %d\n",req->cmd);
- return 0;
- }
-
- /* it seems to be OK */
- return 1;
-}
-
-
-static void complete_request(struct request *req,int bnum)
-{
- while (bnum--) {
- ddv_end_request(1,req);
- req = req->next;
- }
-}
-
-
-static int completion_pointer = 0;
-
-static void check_completion(void)
-{
- int i,bnum;
- struct request *req;
-
- if (!RTable) return;
-
- for (;
- (i=completion_pointer) != RTable->ddv_pointer &&
- RTable->async_info[i].status == DDV_REQ_FREE;
- completion_pointer = INC_T(completion_pointer))
- {
- req = (struct request *)RTable->async_info[i].argv[7];
- bnum = RTable->async_info[i].bnum;
- if (!req || !bnum) {
- printk("%s(%d)\n",__FILE__,__LINE__);
- ddv_stats.errors++;
- continue;
- }
-
- RTable->async_info[i].status = 0;
- RTable->async_info[i].argv[7] = 0;
-
- complete_request(req,bnum);
- in_request--;
- }
-}
-
-
-static struct request *get_request_queue(struct request *oldq)
-{
- struct request *req,*req2;
-
- /* skip any non-active or bad requests */
- skip1:
- if (!(req = CURRENT))
- return oldq;
-
- if (req->rq_status != RQ_ACTIVE) {
- CURRENT = req->next;
- goto skip1;
- }
-
- if (!request_ok(req)) {
- ddv_end_request(0,req);
- CURRENT = req->next;
- goto skip1;
- }
-
- /* now grab as many as we can */
- req_queued++;
-
- for (req2 = req;
- req2->next &&
- req2->next->rq_status == RQ_ACTIVE &&
- request_ok(req2->next);
- req2 = req2->next)
- req_queued++;
-
- /* leave CURRENT pointing at the bad ones */
- CURRENT = req2->next;
-
- /* chop our list at that point */
- req2->next = NULL;
-
- if (!oldq)
- return req;
-
- for (req2=oldq;req2->next;req2=req2->next) ;
-
- req2->next = req;
-
- return oldq;
-}
-
-
-static void ddv_rem_complete(struct remote_request *rem)
-{
- unsigned flags;
- int bnum = rem->bnum;
- struct request *req = rem->reqp;
-
- complete_request(req,bnum);
- in_request--;
-
- save_flags(flags); cli();
- ddv_request1();
- restore_flags(flags);
-}
-
-
-/*
- * The background ddv daemon. This receives remote disk requests
- * and processes them via the normal block operations
- */
-static int ddv_daemon(void *unused)
-{
- current->session = 1;
- current->pgrp = 1;
- sprintf(current->comm, "ddv_daemon");
- spin_lock_irq(&current->sigmask_lock);
- sigfillset(&current->blocked); /* block all signals */
- recalc_sigpending(current);
- spin_unlock_irq(&current->sigmask_lock);
-
- /* Give it a realtime priority. */
- current->policy = SCHED_FIFO;
- current->priority = 32; /* Fixme --- we need to standardise our
- namings for POSIX.4 realtime scheduling
- priorities. */
-
- printk("Started ddv_daemon\n");
-
- while (1) {
- struct remote_request *rem;
- unsigned flags;
- struct buffer_head *bhlist[MAX_BNUM*4];
- int i,j,minor,len,shift,offset;
-
- save_flags(flags); cli();
-
- while (!rem_queue) {
- spin_lock(&current->sigmask_lock);
- flush_signals(current);
- spin_unlock(&current->sigmask_lock);
- interruptible_sleep_on(&ddv_daemon_wait);
- __sti(); cli();
- }
-
- rem = rem_queue;
- rem_queue = rem->u.next;
- restore_flags(flags);
-
-
- minor = MINOR(rem->req.rq_dev);
- len = rem->req.current_nr_sectors;
- offset = rem->req.sector;
-
- /* work out the conversion to the local block size from
- sectors */
- for (shift=0;
- (SECTOR_SIZE<<shift) != ddv_blocksizes[minor];
- shift++) ;
-
- /* do the request */
- for (i=0; len; i++) {
- bhlist[i] = getblk(rem->req.rq_dev,
- offset >> shift,
- ddv_blocksizes[minor]);
- if (!buffer_uptodate(bhlist[i]))
- ll_rw_block(READ,1,&bhlist[i]);
- offset += 1<<shift;
- len -= 1<<shift;
- }
-
- for (j=0;j<i;j++)
- if (!buffer_uptodate(bhlist[j]))
- wait_on_buffer(bhlist[j]);
-
-
- /* put() the data */
-
-
- /* release the buffers */
- for (j=0;j<i;j++)
- brelse(bhlist[j]);
-
- /* tell the originator that its done */
- rem->u.fn = ddv_rem_complete;
- tnet_rpc(rem->cell,rem,sizeof(int)*3,1);
- }
-}
-
-
-/* receive a remote disk request */
-static void ddv_rem_queue(char *data,unsigned size)
-{
- unsigned flags;
- struct remote_request *rem = (struct remote_request *)
- kmalloc(size,GFP_ATOMIC);
-
- if (!rem) {
- /* oh bugger! */
- ddv_stats.errors++;
- return;
- }
-
- memcpy(rem,data,size);
- rem->u.next = NULL;
-
- save_flags(flags); cli();
-
- /* add it to our remote request queue */
- if (!rem_queue)
- rem_queue = rem;
- else
- rem_queue_end->u.next = rem;
- rem_queue_end = rem;
-
- restore_flags(flags);
-
- wake_up(&ddv_daemon_wait);
-}
-
-
-/* which disk should this request go to */
-static inline unsigned pardisk_num(struct request *req)
-{
- int minor = MINOR(req->rq_dev);
- unsigned stripe;
- unsigned cell;
-
- if (minor < PARDISK_BASE)
- return this_option;
-
- stripe = req->sector >> STRIPE_SHIFT;
- cell = stripe % num_options;
-
- return cell;
-}
-
-
-/* check if a 2nd request can be tacked onto the first */
-static inline int contiguous(struct request *req1,struct request *req2)
-{
- if (req2->cmd != req1->cmd ||
- req2->rq_dev != req1->rq_dev ||
- req2->sector != req1->sector + req1->current_nr_sectors ||
- req2->current_nr_sectors != req1->current_nr_sectors)
- return 0;
- if (pardisk_num(req1) != pardisk_num(req2))
- return 0;
- return 1;
-}
-
-static void ddv_request1(void)
-{
- struct request *req,*req1,*req2;
- unsigned offset,len,req_num,mlist,bnum,available=0;
- static unsigned mptrs[MAX_BNUM];
- unsigned cell;
-
- if (in_request > REQUEST_HIGH)
- return;
-
- next_request = get_request_queue(next_request);
-
- while ((req = next_request)) {
- int minor;
-
- if (in_request >= MAX_REQUEST)
- return;
-
- if (in_request>1 && req_queued<REQUEST_LOW)
- return;
-
- /* make sure we have room for a request */
- available = ddv_mlist_available();
- if (available < 1) return;
- if (available > MAX_BNUM)
- available = MAX_BNUM;
-
- offset = req->sector;
- len = req->current_nr_sectors;
- minor = MINOR(req->rq_dev);
-
- mptrs[0] = (int)req->buffer;
-
- for (bnum=1,req1=req,req2=req->next;
- req2 && bnum<available && contiguous(req1,req2);
- req1=req2,req2=req2->next) {
- mptrs[bnum++] = (int)req2->buffer;
- }
-
- next_request = req2;
-
-
- req_queued -= bnum;
- ddv_stats.blocks += bnum;
- ddv_stats.rq_started += bnum;
-
- if (req->cmd == READ) {
- ddv_stats.reads++;
- ddv_stats.sectors_read += len*bnum;
- } else {
- ddv_stats.writes++;
- ddv_stats.sectors_written += len*bnum;
- }
-
- if (minor >= PARDISK_BASE) {
- /* translate the request to the normal partition */
- unsigned stripe;
- minor -= PARDISK_BASE;
-
- stripe = offset >> STRIPE_SHIFT;
- stripe /= num_options;
- offset = (stripe << STRIPE_SHIFT) +
- (offset & ((1<<STRIPE_SHIFT)-1));
-#if AIR_DISK
- /* like an air-guitar :-) */
- complete_request(req,bnum);
- continue;
-#endif
- }
-
- if ((cell=pardisk_num(req)) != this_option) {
- /* its a remote request */
- struct remote_request *rem;
- unsigned *remlist;
- unsigned size = sizeof(*rem) + sizeof(int)*bnum;
-
- rem = (struct remote_request *)kmalloc(size,GFP_ATOMIC);
- if (!rem) {
- /* hopefully we can get it on the next go */
- return;
- }
- remlist = (unsigned *)(rem+1);
-
- rem->u.fn = ddv_rem_queue;
- rem->cell = this_option;
- rem->bnum = bnum;
- rem->req = *req;
- rem->reqp = req;
- rem->req.rq_dev = MKDEV(MAJOR_NR,minor);
- rem->req.sector = offset;
- memcpy(remlist,mptrs,sizeof(mptrs[0])*bnum);
-
- if (tnet_rpc(cell,rem,size,1) != 0) {
- kfree_s(rem,size);
- return;
- }
- } else {
- /* its a local request */
- if ((mlist = ddv_get_mlist(mptrs,bnum)) == -1) {
- ddv_stats.errors++;
- panic("ddv: mlist corrupted");
- }
-
- req_num = RTable->cell_pointer;
- RTable->async_info[req_num].status =
- req->cmd==READ?DDV_RAWREAD_REQ:DDV_RAWWRITE_REQ;
- RTable->async_info[req_num].bnum = bnum;
- RTable->async_info[req_num].argv[0] = mlist;
- RTable->async_info[req_num].argv[1] = len;
- RTable->async_info[req_num].argv[2] = offset +
- partition_tables[minor].start_sect;
- RTable->async_info[req_num].argv[3] = bnum;
- RTable->async_info[req_num].argv[7] = (unsigned)req;
- RTable->cell_pointer = INC_T(RTable->cell_pointer);
-
- }
-
- in_request++;
- }
-}
-
-
-static void ddv_request(request_queue_t * q)
-{
- cli();
- ddv_request1();
- sti();
-}
-
-
-static void check_printbufs(void)
-{
- int i;
-
- if (!PrintBufs) return;
-
- while (PrintBufs->option_counter != PrintBufs->cell_counter) {
- i = PrintBufs->cell_counter;
- printk("opiu (%d): ",i);
- if (((unsigned)PrintBufs->bufs[i].fmt) > 0x100000)
- printk("Error: bad format in printk at %p\n",
- PrintBufs->bufs[i].fmt);
- else
- printk(PrintBufs->bufs[i].fmt + OPIBUS_BASE,
- PrintBufs->bufs[i].args[0],
- PrintBufs->bufs[i].args[1],
- PrintBufs->bufs[i].args[2],
- PrintBufs->bufs[i].args[3],
- PrintBufs->bufs[i].args[4],
- PrintBufs->bufs[i].args[5]);
- if (++PrintBufs->cell_counter == PRINT_BUFS)
- PrintBufs->cell_counter = 0;
- }
-}
-
-static void ddv_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
- unsigned long flags;
- save_flags(flags); cli();
- OPT_IO(IRC1) = 0x80000000;
-
- check_printbufs();
- check_completion();
-
- ddv_request1();
- restore_flags(flags);
-}
-
-static int ddv_open(struct inode * inode, struct file * filp)
-{
- int minor = MINOR(inode->i_rdev);
-
- if (!have_ddv_board || minor >= NUM_DDVDEVS)
- return -ENODEV;
-
- if (minor >= PARDISK_BASE) {
- ddv_sect_length[minor] = ddv_sect_length[minor - PARDISK_BASE];
- ddv_blk_length[minor] = ddv_blk_length[minor - PARDISK_BASE];
- }
-
- return 0;
-}
-
-
-static void ddv_open_reply(struct cap_request *creq)
-{
- int size = creq->size - sizeof(*creq);
- ddv_opcodep = (char *)kmalloc(size,GFP_ATOMIC);
- read_bif(ddv_opcodep, size);
-#if DEBUG
- printk("received opiu kernel of size %d\n",size);
-#endif
- if (size == 0)
- have_ddv_board = 0;
- wake_up(&busy_wait);
-}
-
-extern struct block_device_operations ddv_fops;
-
-static void ddv_load_opiu(void)
-{
- int i;
- struct cap_request creq;
-
- /* if the opiu kernel is already loaded then we don't do anything */
- if (!have_ddv_board || opiu_kernel_loaded)
- return;
-
- bif_register_request(REQ_DDVOPEN,ddv_open_reply);
-
- /* send the open request to the front end */
- creq.cid = mpp_cid();
- creq.type = REQ_DDVOPEN;
- creq.header = 0;
- creq.size = sizeof(creq);
-
- bif_queue(&creq,0,0);
-
- ddv_set_optadr();
-
- while (!ddv_opcodep)
- sleep_on(&busy_wait);
-
- if (!have_ddv_board)
- return;
-
- ddv_load_kernel(ddv_opcodep);
-
- kfree(ddv_opcodep);
- ddv_opcodep = NULL;
-
- if (ddv_restart_cpu())
- return;
-
- ddv_sect_length[0] = DiskInfo->blocks;
- ddv_blk_length[0] = DiskInfo->blocks >> 1;
- ddv_blocksizes[0] = BLOCK_SIZE;
-
- ddv_geometry.cylinders = ddv_sect_length[0] /
- (ddv_geometry.heads*ddv_geometry.sectors);
-
- register_disk(&ddv_gendisk, MKDEV(MAJOR_NR,0), 1<<PARTN_BITS,
- &ddv_fops, ddv_sect_length[0]);
-
- /* FIXME. The crap below is, well, crap. Pseudo-RAID and unsafe one */
- for (i=0;i<PARDISK_BASE;i++) {
- ddv_sect_length[i] = ddv_gendisk.part[i].nr_sects;
- ddv_blk_length[i] = ddv_gendisk.part[i].nr_sects >> 1;
- }
-
- /* setup the parallel partitions by multiplying the normal
- partition by the number of options */
- for (;i<NUM_DDVDEVS;i++) {
- ddv_sect_length[i] = ddv_sect_length[i-PARDISK_BASE]*num_options;
- ddv_blk_length[i] = ddv_blk_length[i-PARDISK_BASE]*num_options;
- ddv_gendisk.part[i].start_sect = ddv_gendisk.part[i-PARDISK_BASE].start_sect;
- ddv_gendisk.part[i].nr_sects = ddv_sect_length[i];
- }
-
-
- opiu_kernel_loaded = 1;
-}
-
-
-/*
- * This routine is called to flush all partitions and partition tables
- * for a changed disk, and then re-read the new partition table.
- */
-static int ddv_revalidate(kdev_t dev, struct gendisk *gdev)
-{
- int target;
- int max_p;
- int start;
- int i;
-
- target = DEVICE_NR(dev);
-
- max_p = gdev->max_p;
- start = target << gdev->minor_shift;
-
- printk("ddv_revalidate dev=%d target=%d max_p=%d start=%d\n",
- dev,target,max_p,start);
-
- for (i=max_p - 1; i >=0 ; i--) {
- int minor = start + i;
- kdev_t devi = MKDEV(gdev->major, minor);
- sync_dev(devi);
- invalidate_inodes(devi);
- invalidate_buffers(devi);
- gdev->part[minor].start_sect = 0;
- gdev->part[minor].nr_sects = 0;
- };
-
- ddv_sect_length[start] = DiskInfo->blocks;
- ddv_blk_length[start] = DiskInfo->blocks >> 1;
-
- grok_partitions(gdev, target, 1<<PARTN_BITS, ddv_sect_length[start]);
-
- printk("sect_length[%d]=%d blk_length[%d]=%d\n",
- start,ddv_sect_length[start],
- start,ddv_blk_length[start]);
-
- for (i=0;i<max_p;i++) {
- ddv_sect_length[start+i] = gdev->part[start+i].nr_sects;
- ddv_blk_length[start+i] = gdev->part[start+i].nr_sects >> 1;
- if (gdev->part[start+i].nr_sects)
- printk("partition[%d] start=%d length=%d\n",i,
- (int)gdev->part[start+i].start_sect,
- (int)gdev->part[start+i].nr_sects);
- }
-
- return 0;
-}
-
-
-
-
-static int ddv_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- int err;
- struct ddv_geometry *loc = (struct ddv_geometry *) arg;
- int dev;
- int minor = MINOR(inode->i_rdev);
-
- if ((!inode) || !(inode->i_rdev))
- return -EINVAL;
- dev = DEVICE_NR(inode->i_rdev);
-#if DEBUG
- printk("ddv_ioctl: cmd=%x dev=%x minor=%d\n", cmd, dev, minor);
-#endif
- switch (cmd) {
- case HDIO_GETGEO:
- printk("\tHDIO_GETGEO\n");
- if (!loc) return -EINVAL;
- if (put_user(ddv_geometry.heads, (char *) &loc->heads)) return -EFAULT;
- if (put_user(ddv_geometry.sectors, (char *) &loc->sectors)) return -EFAULT;
- if (put_user(ddv_geometry.cylinders, (short *) &loc->cylinders)) return -EFAULT;
- if (put_user(ddv_geometry.start, (long *) &loc->start)) return -EFAULT;
- return 0;
-
- case HDIO_GET_MULTCOUNT :
- printk("\tHDIO_GET_MULTCOUNT\n");
- return -EINVAL;
-
- case HDIO_GET_IDENTITY :
- printk("\tHDIO_GET_IDENTITY\n");
- return -EINVAL;
-
- case HDIO_GET_NOWERR :
- printk("\tHDIO_GET_NOWERR\n");
- return -EINVAL;
-
- case HDIO_SET_NOWERR :
- printk("\tHDIO_SET_NOWERR\n");
- return -EINVAL;
-
- case BLKRRPART:
- printk("\tBLKRRPART\n");
- if (!capable(CAP_SYS_ADMIN))
- return -EACCES;
- return ddv_revalidate(inode->i_rdev,&ddv_gendisk);
-
- case BLKGETSIZE: /* Return device size */
- if (put_user(ddv_sect_length[minor],(long *) arg)) return -EFAULT;
-#if DEBUG
- printk("BLKGETSIZE gave %d\n",ddv_sect_length[minor]);
-#endif
- return 0;
-
- default:
- printk("ddv_ioctl: Invalid cmd=%d(0x%x)\n", cmd, cmd);
- return -EINVAL;
- };
-}
-
-static struct block_device_operations ddv_fops = {
- open: ddv_open,
- release: ddv_release,
- ioctl: ddv_ioctl,
-};
-
-
-static void ddv_status(void)
-{
- if (!have_ddv_board) {
- printk("no ddv board\n");
- return;
- }
-
- printk("
-in_request %u req_queued %u
-MTable: start=%u end=%u
-Requests: started=%u finished=%u
-Requests: completion_pointer=%u ddv_pointer=%u cell_pointer=%u
-PrintBufs: option_counter=%u cell_counter=%u
-ddv_stats: reads=%u writes=%u blocks=%u
-ddv_stats: sectors_read=%u sectors_written=%u
-CURRENT=%p next_request=%p errors=%u
-",
- in_request,req_queued,
- RTable->start_mtable,RTable->end_mtable,
- ddv_stats.rq_started,ddv_stats.rq_finished,
- completion_pointer,RTable->ddv_pointer,RTable->cell_pointer,
- PrintBufs->option_counter,PrintBufs->cell_counter,
- ddv_stats.reads,ddv_stats.writes,ddv_stats.blocks,
- ddv_stats.sectors_read,ddv_stats.sectors_written,
- CURRENT,next_request,
- ddv_stats.errors);
-}
-
-
-int ddv_init(void)
-{
- int cid;
-
- cid = mpp_cid();
-
- if (register_blkdev(MAJOR_NR,DEVICE_NAME,&ddv_fops)) {
- printk("ap: unable to get major %d for ap block dev\n",
- MAJOR_NR);
- return -1;
- }
-
- printk("ddv_init: register dev %d\n", MAJOR_NR);
- blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
- read_ahead[MAJOR_NR] = DDV_READ_AHEAD;
-
- bif_add_debug_key('d',ddv_status,"DDV status");
- ddv_gendisk.next = gendisk_head;
- gendisk_head = &ddv_gendisk;
-
- num_options = mpp_num_cells();
- this_option = mpp_cid();
-
- kernel_thread(ddv_daemon, NULL, 0);
-
- ddv_geninit();
-
- return(0);
-}
-
-
-static void ddv_geninit(void)
-{
- int i;
- static int done = 0;
-
- if (done)
- printk("ddv_geninit already done!\n");
-
- done = 1;
-
- printk("ddv_geninit\n");
-
- /* request interrupt line 2 */
- if (request_irq(APOPT0_IRQ,ddv_interrupt,SA_INTERRUPT,"apddv",NULL)) {
- printk("Failed to install ddv interrupt handler\n");
- }
-
- for (i=0;i<NUM_DDVDEVS;i++) {
- ddv_blocksizes[i] = BLOCK_SIZE;
- ddv_sect_length[i] = 0;
- ddv_blk_length[i] = 0;
- }
-
- ddv_geometry.heads = 32;
- ddv_geometry.sectors = 32;
- ddv_geometry.cylinders = 1;
- ddv_geometry.start = 0;
-
- blksize_size[MAJOR_NR] = ddv_blocksizes;
-
- ddv_load_opiu();
-}
-
-
-/* loadable module support */
-
-#ifdef MODULE
-
-int init_module(void)
-{
- int error = ddv_init();
- if (!error)
- printk(KERN_INFO "DDV: Loaded as module.\n");
- return error;
-}
-
-/* Before freeing the module, invalidate all of the protected buffers! */
-void cleanup_module(void)
-{
- int i;
- struct gendisk ** gdp;
-
- for (i = 0 ; i < NUM_DDVDEVS; i++)
- invalidate_buffers(MKDEV(MAJOR_NR, i));
-
- /* reset the opiu */
- OPT_IO(OPIU_OP) = OPIU_RESET;
- OPT_IO(PRST) = PRST_IRST;
-
- unregister_blkdev( MAJOR_NR, DEVICE_NAME );
- for (gdp = &gendisk_head; *gdp; gdp = &((*gdp)->next))
- if (*gdp == &ddv_gendisk)
- break;
- if (*gdp)
- *gdp = (*gdp)->next;
- free_irq(APOPT0_IRQ, NULL);
- blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
-}
-
-#endif /* MODULE */
-
-
diff --git a/drivers/ap1000/ddv_util.c b/drivers/ap1000/ddv_util.c
deleted file mode 100644
index d6cf12216..000000000
--- a/drivers/ap1000/ddv_util.c
+++ /dev/null
@@ -1,116 +0,0 @@
- /*
- * Copyright 1996 The Australian National University.
- * Copyright 1996 Fujitsu Laboratories Limited
- *
- * This software may be distributed under the terms of the Gnu
- * Public License version 2 or later
- */
-#define __NO_VERSION__
-#include <linux/module.h>
-#include <linux/blk.h>
-#include <linux/genhd.h>
-#include <asm/pgtable.h>
-#include <asm/ap1000/apreg.h>
-#include <asm/ap1000/DdvReqTable.h>
-
-
-#define GENDISK_STRUCT ddv_gendisk
-
-struct RequestTable *RTable=NULL;
-struct OPrintBufArray *PrintBufs=NULL;
-struct OAlignBufArray *AlignBufs=NULL;
-struct DiskInfo *DiskInfo=NULL;
-
-extern int ddv_length[];
-
-int ddv_mlist_available(void)
-{
- int start = RTable->start_mtable;
- int end = RTable->end_mtable;
-
- if (start >= end)
- return (MTABLE_SIZE - start);
- return (end+1) - start;
-}
-
-
-int ddv_get_mlist(unsigned mptr[],int bnum)
-{
- int available = ddv_mlist_available();
- int i;
- int start = RTable->start_mtable;
-
- if (available < bnum) {
- return -1;
- }
-
- for (i = 0; i < bnum; i++) {
- unsigned phys = (unsigned)mmu_v2p((unsigned)mptr[i]);
- if (phys == -1)
- panic("bad address %x in ddv_get_mlist\n",mptr[i]);
- RTable->mtable[RTable->start_mtable] = phys;
- RTable->start_mtable = INC_ML(RTable->start_mtable);
- }
-
- return start;
-}
-
-
-
-void ddv_load_kernel(char *opcodep)
-{
- int tsize;
- char *p;
- struct exec *mhead;
-
- mhead = (struct exec *)opcodep;
- p = opcodep + sizeof(*mhead);
-
- tsize = (mhead->a_text + (PAGE_SIZE-1)) & ~(PAGE_SIZE-1);
- memcpy((char *)OPIBUS_BASE+mhead->a_entry,p,mhead->a_text);
- memcpy((char *)OPIBUS_BASE+mhead->a_entry+tsize,
- p+mhead->a_text,mhead->a_data);
- memset((char *)OPIBUS_BASE+mhead->a_entry+tsize+mhead->a_data,0,
- mhead->a_bss+PAGE_SIZE);
-
-#ifdef DDV_DEBUG
- printk("CELL(%d) loaded opiu kernel of size %ld %ld %ld (%ld)\n",
- ap_getcid(),
- mhead->a_text,mhead->a_data,mhead->a_bss,mhead->a_entry);
-#endif
-}
-
-
-int ddv_restart_cpu(void)
-{
- unsigned long timeout;
-
- OPT_IO(OPIU_OP) = OPIU_RESET;
- OPT_IO(PRST) = PRST_IRST;
- if (OPT_IO(PRST) != PRST_IRST) {
- printk("_iu_load reset release error.\n");
- return(-1);
- }
- for (timeout=jiffies + 10;
- time_before(jiffies, timeout) || (OPT_IO(PBUF0) == 0);
- ) /* wait */ ;
- if (OPT_IO(PBUF0) == 0) {
- printk("WARNING: option kernel didn't startup\n");
- return(-1);
- } else {
- printk("option kernel IU running\n");
- DiskInfo = (struct DiskInfo *)(OPT_IO(PBUF0) + OPIBUS_BASE);
- RTable = (struct RequestTable *)(DiskInfo->ptrs[0]+OPIBUS_BASE);
- PrintBufs = (struct OPrintBufArray *)(DiskInfo->ptrs[1]+OPIBUS_BASE);
- AlignBufs = (struct OAlignBufArray *)(DiskInfo->ptrs[2]+OPIBUS_BASE);
-
- printk("Disk capacity: %d blocks of size %d\n",
- (int)DiskInfo->blocks,(int)DiskInfo->blk_size);
-
- OPT_IO(PBUF0) = 0;
- }
- return(0);
-}
-
-
-
diff --git a/drivers/ap1000/mac.c b/drivers/ap1000/mac.c
deleted file mode 100644
index 8e85ff555..000000000
--- a/drivers/ap1000/mac.c
+++ /dev/null
@@ -1,1177 +0,0 @@
- /*
- * Copyright 1996 The Australian National University.
- * Copyright 1996 Fujitsu Laboratories Limited
- *
- * This software may be distributed under the terms of the Gnu
- * Public License version 2 or later
- */
-/*
- * Routines for controlling the FORMAC+
- */
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/skbuff.h>
-#include <linux/interrupt.h>
-#include <linux/if_ether.h> /* For the statistics structure. */
-#include <linux/netdevice.h>
-#include <linux/if_arp.h>
-#include <linux/inet.h>
-#include <net/sock.h>
-
-#include <asm/ap1000/apreg.h>
-#include <asm/ap1000/apservice.h>
-#include <asm/pgtable.h>
-
-#include "apfddi.h"
-#include "smt-types.h"
-#include "am79c830.h"
-#include "mac.h"
-#include "plc.h"
-#include "apfddi-reg.h"
-
-#define MAC_DEBUG 0
-
-/* Values for dma_state */
-#define IDLE 0
-#define XMITTING 1
-#define RECVING 2
-
-/*
- * Messages greater than this value are transferred to the FDDI send buffer
- * using DMA.
- */
-#define DMA_XMIT_THRESHOLD 64
-#define DMA_RECV_THRESHOLD 64
-
-/*
- * If the FDDI receive buffer is occupied by less than this value, then
- * sending has priority.
- */
-#define RECV_THRESHOLD (20*1024)
-
-#define DMA_RESET_MASKS ((AP_CLR_INTR_MASK<<DMA_INTR_NORMAL_SH) | \
- (AP_CLR_INTR_MASK<<DMA_INTR_ERROR_SH))
-
-#define DMA_INTR_REQS ((AP_INTR_REQ<<DMA_INTR_NORMAL_SH) | \
- (AP_INTR_REQ<<DMA_INTR_ERROR_SH))
-
-static void mac_print_state(void);
-
-typedef unsigned int mac_status_t;
-
-static volatile struct mac_queue *mac_queue_top = NULL;
-static volatile struct mac_queue *mac_queue_bottom = NULL;
-
-struct formac_state {
- LoopbackType loopback;
- int ring_op;
- int recv_ptr;
- int recv_empty;
- int recv_ovf;
- int xmit_ptr;
- int xmit_free;
- int xmit_start;
- int xmit_chains;
- int xmit_more_ptr;
- int frames_xmitted;
- int xmit_chain_start[3];
- int frames_recvd;
- int recv_aborted;
- int xmit_aborted;
- int wrong_bb;
- int recv_error;
- volatile struct mac_queue *cur_macq; /* Current queue el for send DMA */
- volatile struct mac_buf cur_mbuf; /* Current mac_buf for send DMA */
- struct sk_buff *cur_skb; /* skb for received packets by DMA */
- int dma_state;
-};
-
-#define SPFRAMES_SIZE 64 /* # words for special frames area */
-#define RECV_BUF_START SPFRAMES_SIZE
-#define RECV_BUF_END (BUFFER_SIZE / 2 + 2048)
-#define RECV_BUF_SIZE (RECV_BUF_END - RECV_BUF_START)
-#define XMIT_BUF_START RECV_BUF_END
-#define XMIT_BUF_END BUFFER_SIZE
-
-#define S2_RMT_EVENTS (S2_CLAIM_STATE | S2_MY_CLAIM | S2_HIGHER_CLAIM | \
- S2_LOWER_CLAIM | S2_BEACON_STATE | S2_MY_BEACON | \
- S2_OTHER_BEACON | S2_RING_OP | S2_MULTIPLE_DA | \
- S2_TOKEN_ERR | S2_DUPL_CLAIM | S2_TRT_EXP_RECOV)
-
-struct mac_info *this_mac_info;
-struct formac_state this_mac_state;
-
-int
-mac_init(struct mac_info *mip)
-{
- struct formac_state *msp = &this_mac_state;
-
- bif_add_debug_key('f',mac_print_state,"show FDDI mac state");
-
- this_mac_info = mip;
-
- mac->cmdreg1 = C1_SOFTWARE_RESET;
- mac->said = (mip->s_address[0] << 8) + mip->s_address[1];
- mac->laim = (mip->l_address[0] << 8) + mip->l_address[1];
- mac->laic = (mip->l_address[2] << 8) + mip->l_address[3];
- mac->lail = (mip->l_address[4] << 8) + mip->l_address[5];
- mac->sagp = (mip->s_group_adrs[0] << 8) + mip->s_group_adrs[1];
- mac->lagm = (mip->l_group_adrs[0] << 8) + mip->l_group_adrs[1];
- mac->lagc = (mip->l_group_adrs[2] << 8) + mip->l_group_adrs[3];
- mac->lagl = (mip->l_group_adrs[4] << 8) + mip->l_group_adrs[5];
- mac->tmax = mip->tmax >> 5;
- mac->tvx = (mip->tvx - 254) / 255; /* it's -ve, round downwards */
- mac->treq0 = mip->treq;
- mac->treq1 = mip->treq >> 16;
- mac->pri0 = ~0;
- mac->pri1 = ~0;
- mac->pri2 = ~0;
- mac->mdreg2 = /*M2_STRIP_FCS +*/ M2_CHECK_PARITY + M2_EVEN_PARITY
- + 3 * M2_RCV_BYTE_BDRY + M2_ENABLE_HSREQ
- + M2_ENABLE_NPDMA + M2_SYNC_NPDMA + M2_RECV_BAD_FRAMES;
- mac->eacb = RECV_BUF_START - 1;
- mac->earv = XMIT_BUF_START - 1;
- mac->eas = mac->earv;
- mac->eaa0 = BUFFER_SIZE - 1;
- mac->eaa1 = mac->eaa0;
- mac->eaa2 = mac->eaa1;
- mac->wpxsf = 0;
- mac->rpr = RECV_BUF_START;
- mac->wpr = RECV_BUF_START + 1;
- mac->swpr = RECV_BUF_START;
- mac->wpxs = mac->eas;
- mac->swpxs = mac->eas;
- mac->rpxs = mac->eas;
- mac->wpxa0 = XMIT_BUF_START;
- mac->rpxa0 = XMIT_BUF_START;
-
- memset(msp, 0, sizeof(*msp));
- msp->recv_ptr = RECV_BUF_START;
- msp->recv_empty = 1;
- msp->xmit_ptr = XMIT_BUF_START;
- msp->xmit_free = XMIT_BUF_START + 1;
- msp->xmit_start = XMIT_BUF_START;
- msp->xmit_chains = 0;
- msp->frames_xmitted = 0;
- msp->frames_recvd = 0;
- msp->recv_aborted = 0;
-
- mac->mdreg1 = M1_MODE_MEMORY;
-
- mac_make_spframes();
-
- return 0;
-}
-
-int
-mac_inited(struct mac_info *mip)
-{
- struct formac_state *msp = &this_mac_state;
- mac_status_t st1, st2;
-
- if (mac->said != (mip->s_address[0] << 8) + mip->s_address[1]
- || mac->laim != (mip->l_address[0] << 8) + mip->l_address[1]
- || mac->laic != (mip->l_address[2] << 8) + mip->l_address[3]
- || mac->lail != (mip->l_address[4] << 8) + mip->l_address[5]
- || mac->sagp != (mip->s_group_adrs[0] << 8) + mip->s_group_adrs[1]
- || mac->lagm != (mip->l_group_adrs[0] << 8) + mip->l_group_adrs[1]
- || mac->lagc != (mip->l_group_adrs[2] << 8) + mip->l_group_adrs[3]
- || mac->lagl != (mip->l_group_adrs[4] << 8) + mip->l_group_adrs[5])
- return 1;
- if ((mac->mdreg1 & ~M1_ADDET) != (M1_MODE_ONLINE | M1_SELECT_RA
- | M1_FULL_DUPLEX))
- return 3;
- if (mac->treq0 != (mip->treq & 0xffff)
- || mac->treq1 != ((unsigned)mip->treq >> 16))
- return 4;
-
- st1 = (mac->st1u << 16) + mac->st1l;
- st2 = (mac->st2u << 16) + mac->st2l;
- if ((st2 & S2_RING_OP) == 0)
- return 5;
-
- /* It's probably OK, reset some things to be safe. */
- this_mac_info = mip;
- *csr0 &= ~CS0_HREQ;
- mac->tmax = mip->tmax >> 5;
- mac->tvx = (mip->tvx - 254) / 255; /* it's -ve, round downwards */
- mac->pri0 = ~0;
- mac->pri1 = ~0;
- mac->pri2 = ~0;
- mac->mdreg2 = /*M2_STRIP_FCS +*/ M2_CHECK_PARITY + M2_EVEN_PARITY
- + 3 * M2_RCV_BYTE_BDRY + M2_ENABLE_HSREQ
- + M2_ENABLE_NPDMA + M2_SYNC_NPDMA + M2_RECV_BAD_FRAMES;
-
- /* clear out the receive queue */
- mac->mdreg1 = (mac->mdreg1 & ~M1_ADDET) | M1_ADDET_DISABLE_RECV;
- mac->rpr = RECV_BUF_START;
- mac->wpr = RECV_BUF_START + 1;
- mac->swpr = RECV_BUF_START;
-
- memset(msp, 0, sizeof(*msp));
- msp->recv_ptr = RECV_BUF_START;
- msp->recv_empty = 1;
-
- /* XXX reset transmit pointers */
- mac->cmdreg2 = C2_ABORT_XMIT;
- mac->cmdreg2 = C2_RESET_XMITQS;
- mac->wpxa0 = XMIT_BUF_START;
- mac->rpxa0 = XMIT_BUF_START;
- msp->xmit_ptr = XMIT_BUF_START;
- msp->xmit_free = XMIT_BUF_START + 1;
- msp->xmit_start = XMIT_BUF_START;
- msp->xmit_chains = 0;
-
- mac_make_spframes();
- mac->cmdreg1 = C1_CLR_ALL_LOCKS;
-
- msp->frames_xmitted = 0;
- msp->frames_recvd = 0;
- msp->recv_aborted = 0;
- msp->ring_op = 1;
-
- mac->mdreg1 = (mac->mdreg1 & ~M1_ADDET) | M1_ADDET_NSA;
- mac->imsk1u = ~(S1_XMIT_ABORT | S1_END_FRAME_ASYNC0) >> 16;
- mac->imsk1l = ~(S1_PAR_ERROR_ASYNC0 | S1_QUEUE_LOCK_ASYNC0);
- mac->imsk2u = ~(S2_RECV_COMPLETE | S2_RECV_BUF_FULL | S2_RECV_FIFO_OVF
- | S2_ERR_SPECIAL_FR | S2_RMT_EVENTS
- | S2_NP_SIMULT_LOAD) >> 16;
- mac->imsk2l = ~(S2_RMT_EVENTS | S2_MISSED_FRAME);
-
- return 0;
-}
-
-void mac_make_spframes(void)
-{
- volatile int *bp;
- struct mac_info *mip = this_mac_info;
- int sa;
- struct formac_state *msp = &this_mac_state;
-
- /* initialize memory to avoid parity errors */
- *csr0 &= ~CS0_HREQ;
- *csr1 &= ~CS1_BUF_WR_TAG;
- for (bp = &buffer_mem[BUFFER_SIZE]; bp > &buffer_mem[XMIT_BUF_START];)
- *--bp = 0xdeadbeef;
- for (; bp > buffer_mem;)
- *--bp = 0xfeedf00d;
- buffer_mem[msp->recv_ptr] = 0;
-
- bp = buffer_mem;
- *bp++ = 0; /* auto-void frame pointer (not used) */
-
- /* make claim frame */
- sa = bp - buffer_mem;
- *bp++ = 0xd8000011; /* claim frame descr. + length */
- *bp++ = 0xc3; /* FC value for claim frame, long addr */
- *bp++ = (mip->l_address[0] << 24) + (mip->l_address[1] << 16)
- + (mip->l_address[2] << 8) + mip->l_address[3];
- *bp++ = (mip->l_address[4] << 24) + (mip->l_address[5] << 16)
- + (mip->l_address[0] << 8) + mip->l_address[1];
- *bp++ = (mip->l_address[2] << 24) + (mip->l_address[3] << 16)
- + (mip->l_address[4] << 8) + mip->l_address[5];
- *bp++ = mip->treq;
- mac->sacl = bp - buffer_mem; /* points to pointer to claim frame */
- *bp++ = 0xa0000000 + sa; /* pointer to start of claim frame */
-
- /* make beacon frame */
- sa = bp - buffer_mem;
- *bp++ = 0xd8000011; /* beacon frame descr. + length */
- *bp++ = 0xc2; /* FC value for beacon frame, long addr */
- *bp++ = 0; /* DA = 0 */
- *bp++ = (mip->l_address[0] << 8) + mip->l_address[1];
- *bp++ = (mip->l_address[2] << 24) + (mip->l_address[3] << 16)
- + (mip->l_address[4] << 8) + mip->l_address[5];
- *bp++ = 0; /* beacon reason = failed claim */
- mac->sabc = bp - buffer_mem;
- *bp++ = 0xa0000000 + sa; /* pointer to start of beacon frame */
-}
-
-void mac_reset(LoopbackType loopback)
-{
- int mode;
- struct formac_state *msp = &this_mac_state;
-
- msp->loopback = loopback;
- switch (loopback) {
- case loop_none:
- mode = M1_MODE_ONLINE;
- break;
- case loop_formac:
- mode = M1_MODE_INT_LOOP;
- break;
- default:
- mode = M1_MODE_EXT_LOOP;
- break;
- }
- mac->mdreg1 = mode | M1_ADDET_NSA | M1_SELECT_RA | M1_FULL_DUPLEX;
- mac->cmdreg1 = C1_IDLE_LISTEN;
- mac->cmdreg1 = C1_CLR_ALL_LOCKS;
- mac->imsk1u = ~(S1_XMIT_ABORT | S1_END_FRAME_ASYNC0) >> 16;
- mac->imsk1l = ~(S1_PAR_ERROR_ASYNC0 | S1_QUEUE_LOCK_ASYNC0);
- mac->imsk2u = ~(S2_RECV_COMPLETE | S2_RECV_BUF_FULL | S2_RECV_FIFO_OVF
- | S2_ERR_SPECIAL_FR | S2_RMT_EVENTS
- | S2_NP_SIMULT_LOAD) >> 16;
- mac->imsk2l = ~(S2_RMT_EVENTS | S2_MISSED_FRAME);
-}
-
-void mac_claim(void)
-{
- mac->cmdreg1 = C1_CLAIM_LISTEN;
-}
-
-void mac_disable(void)
-{
- mac->mdreg1 = M1_MODE_MEMORY;
- mac->imsk1u = ~0;
- mac->imsk1l = ~0;
- mac->imsk2u = ~0;
- mac->imsk2l = ~0;
- mac->wpr = mac->swpr + 1;
- if (mac->wpr > mac->earv)
- mac->wpr = mac->eacb + 1;
- buffer_mem[mac->swpr] = 0;
-}
-
-void mac_stats(void)
-{
- struct formac_state *msp = &this_mac_state;
-
- if (msp->recv_ovf)
- printk("%d receive buffer overflows\n", msp->recv_ovf);
- if (msp->wrong_bb)
- printk("%d frames on wrong byte bdry\n", msp->wrong_bb);
- printk("%d frames transmitted, %d aborted\n", msp->frames_xmitted,
- msp->xmit_aborted);
- printk("%d frames received, %d aborted\n", msp->frames_recvd,
- msp->recv_aborted);
- printk("%d frames received with errors\n", msp->recv_error);
-}
-
-void mac_sleep(void)
-{
- /* disable the receiver */
- mac->mdreg1 = (mac->mdreg1 & ~M1_ADDET) | M1_ADDET_DISABLE_RECV;
-}
-
-void mac_poll(void)
-{
- mac_status_t st1, st2;
- struct formac_state *msp = &this_mac_state;
- int up, f, d, l, r, e, i;
-
- st1 = (mac->st1u << 16) + mac->st1l;
- st2 = (mac->st2u << 16) + mac->st2l;
-
- if (st2 & S2_NP_SIMULT_LOAD)
- panic("NP/formac simultaneous load!!!");
-
- up = (st2 & S2_RING_OP) != 0;
- if (up != msp->ring_op) {
- /* ring has come up or down */
- msp->ring_op = up;
- printk("mac: ring %s\n", up? "up": "down");
- set_ring_op(up);
- }
-
- if (up) {
- if (st1 & S1_XMIT_ABORT) {
- ++msp->xmit_aborted;
- if (st1 & S1_QUEUE_LOCK_ASYNC0) {
- printk("mac: xmit queue locked, resetting xmit buffer\n");
- mac->cmdreg2 = C2_RESET_XMITQS; /* XXX bit gross */
- mac->rpxa0 = XMIT_BUF_START;
- buffer_mem[XMIT_BUF_START] = 0;
- msp->xmit_ptr = XMIT_BUF_START;
- msp->xmit_start = XMIT_BUF_START;
- msp->xmit_chains = 0;
- mac->cmdreg1 = C1_CLR_ASYNCQ0_LOCK;
- st1 &= ~(S1_END_CHAIN_ASYNC0 | S1_END_FRAME_ASYNC0
- | S1_XINSTR_FULL_ASYNC0);
- } else
- st1 |= S1_END_FRAME_ASYNC0;
- } else if (st1 & S1_QUEUE_LOCK_ASYNC0) {
- printk("mac: xmit queue locked, why?\n");
- mac->cmdreg1 = C1_CLR_ASYNCQ0_LOCK;
- }
-
- if (st1 & S1_END_FRAME_ASYNC0) {
- /* advance xmit_start */
- e = msp->xmit_start;
- while (e != msp->xmit_ptr) {
- /* find the end of the current frame */
- f = buffer_mem[e]; /* read pointer */
- if (f == 0)
- break; /* huh?? */
- f &= 0xffff;
- d = buffer_mem[f]; /* read descriptor */
- l = ((d & 0xffff) + ((d >> TD_BYTE_BDRY_LG) & 3) + 3) >> 2;
- e = f + 1 + l; /* index of ptr at end of frame */
- r = mac->rpxa0;
- if ((r <= msp->xmit_ptr && r < e && e <= msp->xmit_ptr)
- || (r > msp->xmit_ptr && (r < e || e <= msp->xmit_ptr)))
- break; /* up to current frame */
- /* printk("frame @ %x done\n", msp->xmit_start); */
- msp->xmit_start = e;
- if ((st1 & S1_XMIT_ABORT) == 0)
- ++msp->frames_xmitted;
- if ((msp->xmit_chains == 1 && e == msp->xmit_ptr) ||
- (msp->xmit_chains > 1 && e == msp->xmit_chain_start[1])) {
- /* we've finished chain 0 */
- --msp->xmit_chains;
- for (i = 0; i < msp->xmit_chains; ++i)
- msp->xmit_chain_start[i] = msp->xmit_chain_start[i+1];
- if (msp->xmit_chains >= 2) {
- mac->cmdreg2 = C2_XMIT_ASYNCQ0;
- /* printk("mac_poll: xmit chain\n"); */
- }
- if (msp->xmit_chains == 0)
- *csr0 &= ~CS0_LED1;
- }
- }
- /*
- * Now that we have a bit more space in the transmit buffer,
- * see if we want to put another frame in.
- */
-#if MAC_DEBUG
- printk("Removed space in transmit buffer.\n");
-#endif
- mac_process();
- }
- }
-
- if (st2 & S2_RMT_EVENTS) {
- rmt_event(st2);
- }
-
- if (st2 & S2_RECV_COMPLETE) {
- /*
- * A frame has just finished arriving in the receive buffer.
- */
- *csr0 |= CS0_LED2;
- msp->recv_empty = 0;
-#if MAC_DEBUG
- printk("Frame has just trickled in...\n");
-#endif
- mac_process();
- }
-
- if (st2 & S2_RECV_BUF_FULL) {
- /*
- * receive buffer overflow: reset and unlock the receive buffer.
- */
-/* printk("mac: receive buffer full\n"); */
- mac->rpr = RECV_BUF_START;
- mac->wpr = RECV_BUF_START + 1;
- mac->swpr = RECV_BUF_START;
- msp->recv_ptr = RECV_BUF_START;
- msp->recv_empty = 1;
- buffer_mem[RECV_BUF_START] = 0;
- mac->cmdreg1 = C1_CLR_RECVQ_LOCK;
- ++msp->recv_ovf;
-
-#if 0
- } else if (st2 & S2_RECV_FIFO_OVF) {
- printk("mac: receive FIFO overflow\n");
- /* any further action required here? */
-
- } else if (st2 & S2_MISSED_FRAME) {
- printk("mac: missed frame\n");
-#endif
- }
-
- if (st2 & S2_ERR_SPECIAL_FR) {
- printk("mac: bug: error in special frame\n");
- mac_disable();
- }
-}
-
-void
-mac_xmit_alloc(sp, bb)
- struct mac_buf *sp;
- int bb;
-{
- int nwords;
-
- nwords = (sp->length + bb + 3) >> 2;
- sp->fr_start = mac_xalloc(nwords + 2);
- sp->fr_end = sp->fr_start + nwords + 1;
- sp->ptr = (char *) &buffer_mem[sp->fr_start + 1] + bb;
- buffer_mem[sp->fr_start] = TD_MAGIC + (bb << TD_BYTE_BDRY_LG) + sp->length;
-}
-
-void
-mac_queue_frame(sp)
- struct mac_buf *sp;
-{
- struct formac_state *msp = &this_mac_state;
-
- buffer_mem[sp->fr_end] = 0; /* null pointer at end of frame */
- buffer_mem[msp->xmit_ptr] = PT_MAGIC + sp->fr_start;
- if (msp->xmit_chains <= 2) {
- msp->xmit_chain_start[msp->xmit_chains] = msp->xmit_ptr;
- if (msp->xmit_chains < 2)
- mac->cmdreg2 = C2_XMIT_ASYNCQ0;
- ++msp->xmit_chains;
- } else {
- buffer_mem[msp->xmit_more_ptr] |= TD_MORE;
- }
- msp->xmit_ptr = sp->fr_end;
- msp->xmit_more_ptr = sp->fr_start;
- *csr0 |= CS0_LED1;
-}
-
-int
-mac_xalloc(int nwords)
-{
- int fr_start;
- struct formac_state *msp = &this_mac_state;
-
- /*
- * Find some room in the transmit buffer.
- */
- fr_start = msp->xmit_free;
- if (fr_start > msp->xmit_start) {
- if (fr_start + nwords > XMIT_BUF_END) {
- /* no space at end - see if we can start again from the front */
- fr_start = XMIT_BUF_START;
- if (fr_start + nwords > msp->xmit_start)
- panic("no space in xmit buffer (1)");
- }
- } else {
- if (fr_start + nwords > msp->xmit_start)
- panic("no space in xmit buffer (2)");
- }
-
- msp->xmit_free = fr_start + nwords;
-
- return fr_start;
-}
-
-int
-mac_recv_frame(sp)
- struct mac_buf *sp;
-{
- struct formac_state *msp = &this_mac_state;
- int status, bb, orig_recv_ptr;
-
- orig_recv_ptr = msp->recv_ptr;
- for (;;) {
- status = buffer_mem[msp->recv_ptr];
- if ((status & RS_VALID) == 0) {
- if (status != 0) {
- printk("recv buf out of sync: recv_ptr=%x status=%x\n",
- msp->recv_ptr, status);
- printk(" rpr=%x swpr=%x, buf[rpr]=%x\n", mac->rpr, mac->swpr,
- buffer_mem[mac->rpr]);
- msp->recv_ptr = mac->swpr;
- }
- *csr0 &= ~CS0_LED2;
- msp->recv_empty = 1;
- if (mac->rpr == orig_recv_ptr)
- mac->rpr = msp->recv_ptr;
- return 0;
- }
- if (status & RS_ABORTED)
- ++msp->recv_aborted;
- else {
- bb = (status >> RS_BYTE_BDRY_LG) & 3;
- if (bb != 3) {
- ++msp->wrong_bb;
- bb = 3;
- }
- if ((status & RS_ERROR) == 0)
- break;
- ++msp->recv_error;
- msp->recv_ptr += NWORDS((status & RS_LENGTH) + bb);
- }
- if (++msp->recv_ptr >= RECV_BUF_END)
- msp->recv_ptr -= RECV_BUF_SIZE;
- }
- ++msp->frames_recvd;
- if (mac->rpr == orig_recv_ptr)
- mac->rpr = msp->recv_ptr;
-
- sp->fr_start = msp->recv_ptr;
- sp->length = (status & RS_LENGTH) + bb; /* + 4 (status) - 4 (FCS) */
- sp->ptr = (void *) &buffer_mem[sp->fr_start];
- if ((msp->recv_ptr += NWORDS(sp->length) + 1) >= RECV_BUF_END)
- msp->recv_ptr -= RECV_BUF_SIZE;
- sp->fr_end = msp->recv_ptr;
- sp->wraplen = (RECV_BUF_END - sp->fr_start) * 4;
- sp->wrapptr = (void *) &buffer_mem[RECV_BUF_START];
-
- return 1;
-}
-
-void
-mac_discard_frame(sp)
- struct mac_buf *sp;
-{
- mac->rpr = sp->fr_end;
-}
-
-/*
- * Return the number of bytes free in the async 0 transmit queue.
- */
-int
-mac_xmit_space(void)
-{
- struct formac_state *msp = &this_mac_state;
- int nw;
-
- if (msp->xmit_free > msp->xmit_start) {
- nw = XMIT_BUF_END - msp->xmit_free;
- if (nw < msp->xmit_start - XMIT_BUF_START)
- nw = msp->xmit_start - XMIT_BUF_START;
- } else
- nw = msp->xmit_start - msp->xmit_free;
- return nw <= 2? 0: (nw - 2) << 2;
-}
-
-/*
- * Return the number of bytes of frames available in the receive queue.
- */
-int
-mac_recv_level(void)
-{
- int nw;
-
- nw = mac->swpr - mac->rpr;
- if (nw < 0)
- nw += mac->earv - mac->eacb;
- return nw << 2;
-}
-
-/*
- * Return 1 iff all transmission has been completed, 0 otherwise.
- */
-int mac_xmit_done(void)
-{
- struct formac_state *msp = &this_mac_state;
-
- return msp->xmit_chains == 0;
-}
-
-/*
- * Append skbuff packet to queue.
- */
-int mac_queue_append (struct sk_buff *skb)
-{
- struct mac_queue *el;
- unsigned flags;
- save_flags(flags); cli();
-
-#if MAC_DEBUG
- printk("Appending queue element skb 0x%x\n", skb);
-#endif
-
- if ((el = (struct mac_queue *)kmalloc(sizeof(*el), GFP_ATOMIC)) == NULL) {
- restore_flags(flags);
- return 1;
- }
- el->next = NULL;
- el->skb = skb;
-
- if (mac_queue_top == NULL) {
- mac_queue_top = mac_queue_bottom = el;
- }
- else {
- mac_queue_bottom->next = el;
- mac_queue_bottom = el;
- }
- restore_flags(flags);
- return 0;
-}
-
-/*
- * If the packet originated from the same FDDI subnet as we are on,
- * there is no need to perform checksumming as FDDI will does this
- * us.
- */
-#define CHECK_IF_CHECKSUM_REQUIRED(skb) \
- if ((skb)->protocol == ETH_P_IP) { \
- extern struct cap_init cap_init; \
- int *from_ip = (int *)((skb)->data+12); \
- int *to_ip = (int *)((skb)->data+16); \
- if ((*from_ip & cap_init.netmask) == (*to_ip & cap_init.netmask)) \
- (skb)->ip_summed = CHECKSUM_UNNECESSARY; \
- }
-
-/*
- * Try to send and/or recv frames.
- */
-void mac_process(void)
-{
- volatile struct dma_chan *dma = (volatile struct dma_chan *) DMA3;
- struct formac_state *msp = &this_mac_state;
- struct mac_queue *el;
- int nw=0, mrl = 0, fstart, send_buffer_full = 0;
- unsigned flags;
-
- save_flags(flags); cli();
-
-#if MAC_DEBUG
- printk("In mac_process()\n");
-#endif
-
- /*
- * Check if the DMA is being used.
- */
- if (msp->dma_state != IDLE) {
- restore_flags(flags);
- return;
- }
-
- while (mac_queue_top != NULL || /* Something to transmit */
- (mrl = mac_recv_level()) > 0) { /* Frames in receive buffer */
- send_buffer_full = 0;
-#if MAC_DEBUG
- printk("mac_process(): something to do... mqt %x mrl is %d\n",
- mac_queue_top, mrl);
-#endif
- if (mac_queue_top != NULL && mrl < RECV_THRESHOLD) {
- el = (struct mac_queue *)mac_queue_top;
-
- /*
- * Check there is enough space in the FDDI send buffer.
- */
- if (mac_xmit_space() < el->skb->len) {
-#if MAC_DEBUG
- printk("process_queue(): FDDI send buffer is full\n");
-#endif
- send_buffer_full = 1;
- }
- else {
-#if MAC_DEBUG
- printk("mac_process(): sending a frame\n");
-#endif
- /*
- * Update mac_queue_top.
- */
- mac_queue_top = mac_queue_top->next;
-
- /*
- * Allocate space in the FDDI send buffer.
- */
- msp->cur_mbuf.length = el->skb->len-3;
- mac_xmit_alloc((struct mac_buf *)&msp->cur_mbuf, 3);
-
- /*
- * If message size is greater than DMA_XMIT_THRESHOLD, send
- * using DMA, otherwise use memcpy().
- */
- if (el->skb->len > DMA_XMIT_THRESHOLD) {
- /*
- * Start the DMA.
- */
-#if MAC_DEBUG
- printk("mac_process(): Starting send DMA...\n");
-#endif
- nw = msp->cur_mbuf.fr_end - msp->cur_mbuf.fr_start + 1;
- mac->wpxa0 = msp->cur_mbuf.fr_start + 1;
-
- *csr0 |= CS0_HREQ_WA0;
-
- msp->cur_macq = el;
- msp->dma_state = XMITTING;
- dma->st = DMA_DMST_RST;
- dma->st = DMA_RESET_MASKS;
- dma->hskip = 1; /* skip = 0, count = 1 */
- dma->vskip = 1; /* skip = 0, count = 1 */
- dma->maddr = (u_char *)
- mmu_v2p((unsigned long)el->skb->data);
- dma->cmd = DMA_DCMD_ST + DMA_DCMD_TYP_AUTO +
- DMA_DCMD_TD_MD + nw;
- *csr0 &= ~CS0_DMA_RECV;
- *csr0 |= CS0_DMA_ENABLE;
-
- /*
- * Don't process any more packets since the DMA is
- * being used.
- */
- break;
- }
- else { /* el->skb->len <= DMA_XMIT_THRESHOLD */
- /*
- * Copy the data directly into the FDDI buffer.
- */
-#if MAC_DEBUG
- printk("mac_proces(): Copying send data...\n");
-#endif
- memcpy(msp->cur_mbuf.ptr - 3, el->skb->data,
- ROUND4(el->skb->len));
- mac_queue_frame((struct mac_buf *)&msp->cur_mbuf);
- dev_kfree_skb(el->skb);
- kfree_s(el, sizeof(*el));
- continue;
- }
- }
-
- /*
- * We have reached here if there is not enough space in the
- * send buffer. Try to receive some packets instead.
- */
- }
-
- if (mac_recv_frame((struct mac_buf *)&msp->cur_mbuf)) {
- volatile int fc, llc_header_word2;
- int pkt_len = 0;
-
-#if MAC_DEBUG
- printk("mac_process(): Receiving frames...\n");
-#endif
- /*
- * Get the fc, note only word accesses are allowed from the
- * FDDI buffers.
- */
- if (msp->cur_mbuf.wraplen > 4) {
- fc = *(int *)(msp->cur_mbuf.ptr+4);
- }
- else {
- /*
- * fc_word must be at the start of the FDDI buffer.
- */
-#if MAC_DEBUG
- printk("Grabbed fc_word from wrapptr, wraplen %d\n",
- msp->cur_mbuf.wraplen);
-#endif
- fc = *(int *)msp->cur_mbuf.wrapptr;
- }
- fc &= 0xff;
-
-#if MAC_DEBUG
- printk("fc is 0x%x\n", fc);
-#endif
- if (fc < 0x50 || fc > 0x57) {
- mac_discard_frame((struct mac_buf *)&msp->cur_mbuf);
- continue;
- }
-
- /*
- * Determine the size of the packet data and allocate a socket
- * buffer.
- */
- pkt_len = msp->cur_mbuf.length - FDDI_HARDHDR_LEN;
-#if MAC_DEBUG
- printk("Packet of length %d\n", pkt_len);
-#endif
- msp->cur_skb = dev_alloc_skb(ROUND4(pkt_len));
-
- if (msp->cur_skb == NULL) {
- printk("mac_process(): Memory squeeze, dropping packet.\n");
- apfddi_stats->rx_dropped++;
- restore_flags(flags);
- return;
- }
- msp->cur_skb->dev = apfddi_device;
-
- /*
- * Hardware header isn't copied to skbuff.
- */
- msp->cur_skb->mac.raw = msp->cur_skb->data;
- apfddi_stats->rx_packets++;
-
- /*
- * Determine protocol from llc header.
- */
- if (msp->cur_mbuf.wraplen < FDDI_HARDHDR_LEN) {
- llc_header_word2 = *(int *)(msp->cur_mbuf.wrapptr +
- (FDDI_HARDHDR_LEN -
- msp->cur_mbuf.wraplen - 4));
- }
- else {
- llc_header_word2 = *(int *)(msp->cur_mbuf.ptr +
- FDDI_HARDHDR_LEN - 4);
- }
- msp->cur_skb->protocol = llc_header_word2 & 0xFFFF;
-#if MAC_DEBUG
- printk("Got protocol 0x%x\n", msp->cur_skb->protocol);
-#endif
-
- /*
- * Copy data into socket buffer, which may be wrapped around the
- * FDDI buffer. Use memcpy if the size of the data is less
- * than DMA_RECV_THRESHOLD. Note if DMA is used, then wrap-
- * arounds are handled automatically.
- */
- if (pkt_len < DMA_RECV_THRESHOLD) {
- if (msp->cur_mbuf.length < msp->cur_mbuf.wraplen) {
- memcpy(skb_put(msp->cur_skb, ROUND4(pkt_len)),
- msp->cur_mbuf.ptr + FDDI_HARDHDR_LEN,
- ROUND4(pkt_len));
- }
- else if (msp->cur_mbuf.wraplen < FDDI_HARDHDR_LEN) {
-#if MAC_DEBUG
- printk("Wrap case 2\n");
-#endif
- memcpy(skb_put(msp->cur_skb, ROUND4(pkt_len)),
- msp->cur_mbuf.wrapptr +
- (FDDI_HARDHDR_LEN - msp->cur_mbuf.wraplen),
- ROUND4(pkt_len));
- }
- else {
-#if MAC_DEBUG
- printk("wrap case 3\n");
-#endif
- memcpy(skb_put(msp->cur_skb,
- ROUND4(msp->cur_mbuf.wraplen-
- FDDI_HARDHDR_LEN)),
- msp->cur_mbuf.ptr + FDDI_HARDHDR_LEN,
- ROUND4(msp->cur_mbuf.wraplen - FDDI_HARDHDR_LEN));
- memcpy(skb_put(msp->cur_skb,
- ROUND4(msp->cur_mbuf.length -
- msp->cur_mbuf.wraplen)),
- msp->cur_mbuf.wrapptr,
- ROUND4(msp->cur_mbuf.length -
- msp->cur_mbuf.wraplen));
- }
-
-#if MAC_DEBUG
- if (msp->cur_skb->protocol == ETH_P_IP) {
- dump_packet("apfddi_rx:", msp->cur_skb->data, pkt_len, 0);
- }
- else if (msp->cur_skb->protocol == ETH_P_ARP) {
- struct arphdr *arp = (struct arphdr *)msp->cur_skb->data;
- printk("arp->ar_op is 0x%x ar_hrd %d ar_pro 0x%x ar_hln %d ar_ln %d\n",
- arp->ar_op, arp->ar_hrd, arp->ar_pro, arp->ar_hln,
- arp->ar_pln);
- printk("sender hardware address: %x:%x:%x:%x:%x:%x\n",
- *((u_char *)msp->cur_skb->data+8),
- *((u_char *)msp->cur_skb->data+9),
- *((u_char *)msp->cur_skb->data+10),
- *((u_char *)msp->cur_skb->data+11),
- *((u_char *)msp->cur_skb->data+12),
- *((u_char *)msp->cur_skb->data+13));
- printk("sender IP number %d.%d.%d.%d\n",
- *((u_char *)msp->cur_skb->data+14),
- *((u_char *)msp->cur_skb->data+15),
- *((u_char *)msp->cur_skb->data+16),
- *((u_char *)msp->cur_skb->data+17));
- printk("receiver hardware address: %x:%x:%x:%x:%x:%x\n",
- *((u_char *)msp->cur_skb->data+18),
- *((u_char *)msp->cur_skb->data+19),
- *((u_char *)msp->cur_skb->data+20),
- *((u_char *)msp->cur_skb->data+21),
- *((u_char *)msp->cur_skb->data+22),
- *((u_char *)msp->cur_skb->data+23));
- printk("receiver IP number %d.%d.%d.%d\n",
- *((u_char *)msp->cur_skb->data+24),
- *((u_char *)msp->cur_skb->data+25),
- *((u_char *)msp->cur_skb->data+26),
- *((u_char *)msp->cur_skb->data+27));
- }
-#endif
- CHECK_IF_CHECKSUM_REQUIRED(msp->cur_skb);
-
- /*
- * Inform the network layer of the new packet.
- */
-#if MAC_DEBUG
- printk("Calling netif_rx()\n");
-#endif
- netif_rx(msp->cur_skb);
-
- /*
- * Remove frame from FDDI buffer.
- */
- mac_discard_frame((struct mac_buf *)&msp->cur_mbuf);
- continue;
- }
- else {
- /*
- * Set up dma and break.
- */
-#if MAC_DEBUG
- printk("mac_process(): Starting receive DMA...\n");
-#endif
- nw = NWORDS(pkt_len);
- msp->dma_state = RECVING;
- *csr0 &= ~(CS0_HREQ | CS0_DMA_ENABLE);
-/* *csr1 |= CS1_RESET_FIFO;
- *csr1 &= ~CS1_RESET_FIFO; */
- if ((*csr1 & CS1_FIFO_LEVEL) != 0) {
- int x;
- printk("fifo not empty! (csr1 = 0x%x) emptying...", *csr1);
- do {
- x = *fifo;
- } while ((*csr1 & CS1_FIFO_LEVEL) != 0);
- printk("done\n");
- }
- fstart = msp->cur_mbuf.fr_start + NWORDS(FDDI_HARDHDR_LEN);
- if (fstart >= RECV_BUF_END)
- fstart -= RECV_BUF_SIZE;
- mac->rpr = fstart;
-#if MAC_DEBUG
- printk("rpr=0x%x, nw=0x%x, stat=0x%x\n",
- mac->rpr, nw, buffer_mem[msp->cur_mbuf.fr_start]);
-#endif
- dma->st = DMA_DMST_RST;
- dma->st = DMA_RESET_MASKS;
- dma->hskip = 1; /* skip = 0, count = 1 */
- dma->vskip = 1; /* skip = 0, count = 1 */
- dma->maddr = (u_char *)
- mmu_v2p((unsigned long)
- skb_put(msp->cur_skb, ROUND4(pkt_len)));
- dma->cmd = DMA_DCMD_ST + DMA_DCMD_TYP_AUTO + DMA_DCMD_TD_DM
- + nw - 4;
- *csr0 |= CS0_HREQ_RECV | CS0_DMA_RECV;
- *csr0 |= CS0_DMA_ENABLE;
-#if MAC_DEBUG
- printk("mac_process(): DMA is away!\n");
-#endif
- break;
- }
- }
- else {
-#if MAC_DEBUG
- printk("mac_recv_frame failed\n");
-#endif
- if (msp->recv_empty && send_buffer_full)
- break;
- }
- }
- /*
- * Update mac_queue_bottom.
- */
- if (mac_queue_top == NULL)
- mac_queue_bottom = NULL;
-
-#if MAC_DEBUG
- printk("End of mac_process()\n");
-#endif
- restore_flags(flags);
-}
-
-
-#define DMA_IN(reg) (*(volatile unsigned *)(reg))
-#define DMA_OUT(reg,v) (*(volatile unsigned *)(reg) = (v))
-
-/*
- * DMA completion handler.
- */
-void mac_dma_complete(void)
-{
- volatile struct dma_chan *dma;
- struct formac_state *msp = &this_mac_state;
- unsigned a;
-
- a = DMA_IN(DMA3_DMST);
- if (!(a & DMA_INTR_REQS)) {
- if (msp->dma_state != IDLE && (a & DMA_DMST_AC) == 0) {
- printk("dma completed but no interrupt!\n");
- msp->dma_state = IDLE;
- }
- return;
- }
-
- DMA_OUT(DMA3_DMST,AP_CLR_INTR_REQ<<DMA_INTR_NORMAL_SH);
- DMA_OUT(DMA3_DMST,AP_CLR_INTR_REQ<<DMA_INTR_ERROR_SH);
-
- dma = (volatile struct dma_chan *) DMA3;
-
-#if MAC_DEBUG
- printk("In mac_dma_complete\n");
-#endif
-
- if (msp->dma_state == XMITTING && ((dma->st & DMA_DMST_AC) == 0)) {
- /*
- * Transmit DMA finished.
- */
- int i = 20;
-#if MAC_DEBUG
- printk("In mac_dma_complete for transmit complete\n");
-#endif
- while (*csr1 & CS1_FIFO_LEVEL) {
- if (--i <= 0) {
- printk("csr0=0x%x csr1=0x%x: fifo not emptying\n", *csr0,
- *csr1);
- return;
- }
- }
- *csr0 &= ~(CS0_HREQ | CS0_DMA_ENABLE);
- msp->dma_state = IDLE;
-#if MAC_DEBUG
- printk("mac_dma_complete(): Calling mac_queue_frame\n");
-#endif
- mac_queue_frame((struct mac_buf *)&msp->cur_mbuf);
- dev_kfree_skb(msp->cur_macq->skb);
- kfree_s((struct mac_buf *)msp->cur_macq, sizeof(*(msp->cur_macq)));
- msp->cur_macq = NULL;
-#if MAC_DEBUG
- printk("mac_dma_complete(): Calling mac_process()\n");
-#endif
- mac_process();
-#if MAC_DEBUG
- printk("End of mac_dma_complete transmitting\n");
-#endif
- }
- else if (msp->dma_state == RECVING && ((dma->st & DMA_DMST_AC) == 0)) {
- /*
- * Receive DMA finished. Copy the last four words from the
- * fifo into the buffer, after turning off the host requests.
- * We do this to avoid reading past the end of frame.
- */
- int *ip, i;
-
-#if MAC_DEBUG
- printk("In mac_dma_complete for receive complete\n");
-#endif
- msp->dma_state = IDLE;
- ip = (int *)mmu_p2v((unsigned long)dma->cmaddr);
-
-#if MAC_DEBUG
- printk("ip is 0x%x, skb->data is 0x%x\n", ip, msp->cur_skb->data);
-#endif
-
- *csr0 &= ~(CS0_DMA_ENABLE | CS0_HREQ);
-
- for (i = 0; (*csr1 & CS1_FIFO_LEVEL); ++i)
- ip[i] = *fifo;
- if (i != 4)
- printk("mac_dma_complete(): not four words remaining in fifo?\n");
-#if MAC_DEBUG
- printk("Copied last four words out of fifo\n");
-#endif
-
- /*
- * Remove the frame from the FDDI receive buffer.
- */
- mac_discard_frame((struct mac_buf *)&msp->cur_mbuf);
-
- CHECK_IF_CHECKSUM_REQUIRED(msp->cur_skb);
-
- /*
- * Now inject the packet into the network system.
- */
- netif_rx(msp->cur_skb);
-
-#if MAC_DEBUG
- dump_packet("mac_dma_complete:", msp->cur_skb->data, 0, 0);
-#endif
-
- /*
- * Check if any more frames can be processed.
- */
- mac_process();
-
-#if MAC_DEBUG
- printk("End of mac_dma_complete receiving\n");
-#endif
- }
-#if MAC_DEBUG
- printk("End of mac_dma_complete()\n");
-#endif
-}
-
-static void mac_print_state(void)
-{
- struct formac_state *msp = &this_mac_state;
-
- printk("DMA3_DMST is 0x%x dma_state is %d\n", DMA_IN(DMA3_DMST),
- msp->dma_state);
- printk("csr0 = 0x%x, csr1 = 0x%x\n", *csr0, *csr1);
-}
-
-
diff --git a/drivers/ap1000/mac.h b/drivers/ap1000/mac.h
deleted file mode 100644
index 85f02b4a3..000000000
--- a/drivers/ap1000/mac.h
+++ /dev/null
@@ -1,82 +0,0 @@
- /*
- * Copyright 1996 The Australian National University.
- * Copyright 1996 Fujitsu Laboratories Limited
- *
- * This software may be distributed under the terms of the Gnu
- * Public License version 2 or later
- */
-/*
- * Definitions of MAC state structures etc.
- */
-
-struct mac_info {
- TimerTwosComplement tmax;
- TimerTwosComplement tvx;
- TimerTwosComplement treq;
- ShortAddressType s_address;
- LongAddressType l_address;
- ShortAddressType s_group_adrs;
- LongAddressType l_group_adrs;
- int rcv_own_frames;
- int only_good_frames;
-};
-
-
-struct mac_buf {
- struct mac_buf *next;
- int ack;
- int length;
- void *ptr;
- int wraplen;
- void *wrapptr;
- int fr_start;
- int fr_end;
-};
-
-int mac_xmit_space(void);
-void mac_xmit_alloc(struct mac_buf *, int);
-void mac_queue_frame(struct mac_buf *);
-int mac_recv_frame(struct mac_buf *);
-void mac_discard_frame(struct mac_buf *);
-int mac_init(struct mac_info *mip);
-int mac_inited(struct mac_info *mip);
-void mac_reset(LoopbackType loopback);
-void mac_claim(void);
-void mac_sleep(void);
-void mac_poll(void);
-void mac_disable(void);
-void mac_make_spframes(void);
-int mac_xalloc(int nwords);
-int mac_xmit_dma(struct sk_buff *skb);
-void mac_dma_complete(void);
-void mac_process(void);
-int mac_queue_append(struct sk_buff *skb);
-
-struct dma_chan {
- int cmd; /* cmd << 16 + size */
- int st; /* status << 16 + current size */
- int hskip; /* hskip << 16 + hcnt */
- int vskip; /* vskip << 16 + vcnt */
- unsigned char *maddr; /* memory address */
- unsigned char *cmaddr; /* current memory address */
- int ccount; /* h_count << 16 + v_count */
- int *tblp; /* table pointer */
- int *ctblp; /* current table pointer */
- unsigned char *hdptr; /* header pointer */
-};
-
-#define ROUND4(x) (((x) + 3) & -4)
-#define ROUND8(x) (((x) + 7) & -8)
-#define ROUND16(x) (((x) + 15) & -16)
-#define ROUNDLINE(x) ROUND16(x)
-
-#define NWORDS(x) (((x) + 3) >> 2)
-#define NLINES(x) (((x) + 15) >> 4)
-
-/*
- * Queue element used to queue transmit requests on the FDDI.
- */
-struct mac_queue {
- volatile struct mac_queue *next;
- struct sk_buff *skb;
-};
diff --git a/drivers/ap1000/plc.c b/drivers/ap1000/plc.c
deleted file mode 100644
index b29b1a4c2..000000000
--- a/drivers/ap1000/plc.c
+++ /dev/null
@@ -1,393 +0,0 @@
- /*
- * Copyright 1996 The Australian National University.
- * Copyright 1996 Fujitsu Laboratories Limited
- *
- * This software may be distributed under the terms of the Gnu
- * Public License version 2 or later
- */
-/*
- * Routines for controlling the Am79c864 physical layer controller.
- *
- * This chip implements some parts of the FDDI SMT standard
- * (PCM: physical connection management, LEM: link error monitor, etc.)
- * as well as the FDDI PHY standard.
- */
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include "apfddi.h"
-#include "smt-types.h"
-#include "am79c864.h"
-#include "plc.h"
-#include "apfddi-reg.h"
-
-typedef enum {
- off,
- signalling,
- doing_lct,
- joining,
- active
-} PlcPhase;
-
-struct plc_state {
- LoopbackType loopback;
- char t_val[16];
- char r_val[16];
- int n;
- PortType peer_type;
- PlcPhase phase;
-};
-
-struct plc_info *this_plc_info;
-struct plc_state this_plc_state;
-
-void plc_init(struct plc_info *pip)
-{
- int class, x;
- struct plc_state *psp = &this_plc_state;
-
- this_plc_info = pip;
-
- /* first turn it off, clear registers */
- class = pip->port_type == pt_s? CB_CLASS_S: 0;
- plc->ctrl_b = CB_PC_STOP + class;
- plc->intr_mask = IE_NP_ERROR;
- x = plc->intr_event; /* these register clear when read */
- x = plc->viol_sym_ct;
- x = plc->min_idle_ct;
- x = plc->link_err_ct;
-
- /* initialize registers */
- plc->ctrl_a = 0;
- plc->ctrl_b = class;
- plc->c_min = pip->c_min >> 8;
- plc->tl_min = pip->tl_min >> 8;
- plc->tb_min = pip->tb_min >> 8;
- plc->t_out = pip->t_out >> 8;
- plc->t_scrub = pip->t_scrub >> 8;
- plc->ns_max = pip->ns_max >> 2;
-
- psp->phase = off;
-}
-
-int
-plc_inited(struct plc_info *pip)
-{
- int class, x;
- struct plc_state *psp = &this_plc_state;
-
- class = pip->port_type == pt_s? CB_CLASS_S: 0;
- if ((plc->ctrl_a & (CA_LOOPBACK|CA_FOT_OFF|CA_EB_LOOP|CA_LM_LOOP)) != 0)
- return 1;
- if ((plc->ctrl_b & (CB_CONFIG_CTRL|CB_CLASS_S|CB_PC_MAINT)) != class)
- return 2;
- if (plc->status_a & SA_SIG_DETECT)
- return 3;
- if ((plc->status_b & (SB_PCI_STATE|SB_PCM_STATE))
- != (SB_PCI_STATE_INSERTED|SB_PCM_STATE_ACTIVE))
- return 4;
-
- /* all seems OK, reset the timers and counters just to be sure */
- plc->intr_mask = IE_NP_ERROR;
- x = plc->intr_event; /* these register clear when read */
- x = plc->viol_sym_ct;
- x = plc->min_idle_ct;
- x = plc->link_err_ct;
-
- plc->c_min = pip->c_min >> 8;
- plc->tl_min = pip->tl_min >> 8;
- plc->tb_min = pip->tb_min >> 8;
- plc->t_out = pip->t_out >> 8;
- plc->t_scrub = pip->t_scrub >> 8;
- plc->ns_max = pip->ns_max >> 2;
-
- psp->phase = active;
- /* XXX should initialize other fields of this_plc_state */
-
- return 0;
-}
-
-void plc_sleep(void)
-{
-}
-
-void pc_start(LoopbackType loopback)
-{
- int x;
- struct plc_info *pip = this_plc_info;
- struct plc_state *psp = &this_plc_state;
-
- /* make sure it's off */
- plc->ctrl_b &= ~CB_PCM_CTRL;
- plc->ctrl_b |= CB_PC_STOP;
-
- /* set up loopback required */
- psp->loopback = loopback;
- x = 0;
- switch (loopback) {
- case loop_plc_lm:
- x = CA_LM_LOOP;
- break;
- case loop_plc_eb:
- x = CA_EB_LOOP;
- break;
- case loop_pdx:
- x = CA_LOOPBACK;
- break;
- default:
- x = 0;
- }
- plc->ctrl_a = x;
-
- /* set up bits to be exchanged */
- psp->t_val[0] = 0;
- psp->t_val[1] = ((int) pip->port_type >> 1) & 1;
- psp->t_val[2] = (int) pip->port_type & 1;
- psp->t_val[4] = 0; /* XXX assume we want short LCT */
- psp->t_val[5] = 0;
- psp->t_val[6] = 0; /* XXX too lazy to fire up my MAC for LCT */
- psp->t_val[8] = 0; /* XXX don't wanna local loop */
- psp->t_val[9] = 1; /* gotta MAC on port output */
-
- pc_restart();
-}
-
-void pc_restart(void)
-{
- struct plc_state *psp = &this_plc_state;
-
- if (psp->phase != off)
- printk("restarting pcm\n");
- if (psp->phase == active)
- set_cf_join(0); /* we're down :-( */
-
- psp->n = 0;
- plc->vec_length = 3 - 1;
- plc->xmit_vector = psp->t_val[0] + (psp->t_val[1] << 1)
- + (psp->t_val[2] << 2);
-
- plc->intr_mask = IE_NP_ERROR | IE_PCM_BREAK | IE_PCM_CODE;
- plc->ctrl_b &= ~CB_PCM_CTRL;
- plc->ctrl_b |= CB_PC_START; /* light blue paper and stand clear */
-
- psp->phase = signalling;
-}
-
-void pc_stop(void)
-{
- struct plc_state *psp = &this_plc_state;
-
- if (psp->phase == active)
- set_cf_join(0);
- plc->ctrl_b &= ~CB_PCM_CTRL;
- plc->ctrl_b |= CB_PC_STOP;
- plc->intr_mask = IE_NP_ERROR;
- psp->phase = off;
-}
-
-void plc_poll(void)
-{
- struct plc_state *psp = &this_plc_state;
- int events, i;
-
- if ((*csr0 & CS0_PHY_IRQ) == 0)
- return;
- events = plc->intr_event & plc->intr_mask;
- if (events & IE_NP_ERROR) {
- printk("plc: NP error!\n");
- }
- if (events & IE_PCM_BREAK) {
- i = plc->status_b & SB_BREAK_REASON;
- if (i > SB_BREAK_REASON_START) {
- if (psp->phase == signalling || psp->phase == doing_lct)
- pcm_dump_rtcodes();
- printk("pcm: break reason %d\n", i);
- if (psp->phase != off)
- pc_restart();
- /* XXX need to check for trace? */
- }
- }
- if (events & IE_PCM_CODE) {
- if (psp->phase == signalling)
- pcm_pseudo_code();
- else if (psp->phase == doing_lct)
- pcm_lct_done();
- else
- printk("XXX pcm_code interrupt in phase %d?\n", psp->phase);
- }
- if (events & IE_PCM_ENABLED) {
- if (psp->phase == joining)
- pcm_enabled();
- else
- printk("XXX pcm_enabled interrupt in phase %d?\n", psp->phase);
- }
- if (events & IE_TRACE_PROP) {
- if (psp->phase == active)
- pcm_trace_prop();
- else
- printk("XXX trace_prop interrupt in phase %d\n", psp->phase);
- }
-}
-
-void pcm_pseudo_code(void)
-{
- struct plc_info *pip = this_plc_info;
- struct plc_state *psp = &this_plc_state;
- int i, nb, lct, hislct;
-
- /* unpack the bits from the peer */
- nb = plc->vec_length + 1;
- i = plc->rcv_vector;
- do {
- psp->r_val[psp->n++] = i & 1;
- i >>= 1;
- } while (--nb > 0);
-
- /* send some more, do LCT, whatever */
- switch (psp->n) {
- case 3:
- /*
- * Got escape flag, port type; send compatibility,
- * LCT duration, MAC for LCT flag.
- */
- if (psp->r_val[0]) {
- /* help! what do I do now? */
- pcm_dump_rtcodes();
- pc_restart();
- break;
- }
- psp->peer_type = (PortType) ((psp->r_val[1] << 1) + psp->r_val[2]);
- /* XXX we're type S, we talk to anybody */
- psp->t_val[3] = 1;
-
- plc->vec_length = 4 - 1;
- plc->xmit_vector = psp->t_val[3] + (psp->t_val[4] << 1)
- + (psp->t_val[5] << 2) + (psp->t_val[6] << 3);
- break;
-
- case 7:
- /*
- * Got compatibility, LCT duration, MAC for LCT flag;
- * time to do the LCT.
- */
- lct = (psp->t_val[4] << 1) + psp->t_val[5];
- hislct = (psp->r_val[4] << 1) + psp->r_val[5];
- if (hislct > lct)
- lct = hislct;
-
- /* set LCT duration */
- switch (lct) {
- case 0:
- plc->lc_length = pip->lc_short >> 8;
- plc->ctrl_b &= ~CB_LONG_LCT;
- break;
- case 1:
- plc->lc_length = pip->lc_medium >> 8;
- plc->ctrl_b &= ~CB_LONG_LCT;
- break;
- case 2:
- plc->ctrl_b |= CB_LONG_LCT;
- /* XXX set up a timeout for pip->lc_long */
- break;
- case 3:
- plc->ctrl_b |= CB_LONG_LCT;
- /* XXX set up a timeout for pip->lc_extended */
- break;
- }
-
- /* start the LCT */
- i = plc->link_err_ct; /* clear the register */
- plc->ctrl_b &= ~CB_PC_LCT;
- /* XXX assume we're not using the MAC for LCT;
- if he's got a MAC, loop his stuff back, otherwise send idle. */
- if (psp->r_val[6])
- plc->ctrl_b |= CB_PC_LCT_LOOP;
- else
- plc->ctrl_b |= CB_PC_LCT_IDLE;
- psp->phase = doing_lct;
- break;
-
- case 8:
- /*
- * Got LCT result, send MAC for local loop and MAC on port
- * output flags.
- */
- if (psp->t_val[7] || psp->r_val[7]) {
- printk("LCT failed, restarting.\n");
- /* LCT failed - do at least a medium length test next time. */
- if (psp->t_val[4] == 0 && psp->t_val[5] == 0)
- psp->t_val[5] = 1;
- pcm_dump_rtcodes();
- pc_restart();
- break;
- }
- plc->vec_length = 2 - 1;
- plc->xmit_vector = psp->t_val[8] + (psp->t_val[9] << 1);
- break;
-
- case 10:
- /*
- * Got MAC for local loop and MAC on port output flags.
- * Let's join.
- */
- plc->intr_mask = IE_NP_ERROR | IE_PCM_BREAK | IE_PCM_ENABLED;
- plc->ctrl_b |= CB_PC_JOIN;
- psp->phase = joining;
- /* printk("pcm: joining\n"); */
- break;
-
- default:
- printk("pcm_pseudo_code bug: n = %d\n", psp->n);
- }
-}
-
-void pcm_lct_done(void)
-{
- struct plc_state *psp = &this_plc_state;
- int i;
-
- i = plc->link_err_ct;
- psp->t_val[7] = i > 0;
- printk("pcm: lct %s (%d errors)\n", psp->t_val[7]? "failed": "passed", i);
- plc->ctrl_b &= ~(CB_PC_LCT | CB_LONG_LCT);
- plc->vec_length = 1 - 1;
- plc->xmit_vector = psp->t_val[7];
- psp->phase = signalling;
-}
-
-void pcm_dump_rtcodes(void)
-{
- struct plc_state *psp = &this_plc_state;
- int i;
-
- if (psp->n > 0) {
- printk("pcm signalling interrupted after %d bits:\nt_val:", psp->n);
- for (i = 0; i < psp->n; ++i)
- printk(" %d", psp->t_val[i]);
- printk("\nr_val:");
- for (i = 0; i < psp->n; ++i)
- printk(" %d", psp->r_val[i]);
- printk("\n");
- }
-}
-
-void pcm_enabled(void)
-{
- struct plc_state *psp = &this_plc_state;
- int i;
-
- printk("pcm: enabled\n");
- psp->phase = active;
- i = plc->link_err_ct; /* clear the register */
- /* XXX should set up LEM here */
- /* XXX do we want to count violation symbols, minimum idle gaps,
- or elasticity buffer errors? */
- plc->intr_mask = IE_NP_ERROR | IE_PCM_BREAK | IE_TRACE_PROP;
- set_cf_join(1); /* we're up :-) */
-}
-
-void pcm_trace_prop(void)
-{
- /* XXX help! what do I do now? */
- pc_stop();
-}
diff --git a/drivers/ap1000/plc.h b/drivers/ap1000/plc.h
deleted file mode 100644
index f87783f57..000000000
--- a/drivers/ap1000/plc.h
+++ /dev/null
@@ -1,53 +0,0 @@
- /*
- * Copyright 1996 The Australian National University.
- * Copyright 1996 Fujitsu Laboratories Limited
- *
- * This software may be distributed under the terms of the Gnu
- * Public License version 2 or later
- */
-/*
- * Definitions for PLC state structures etc.
- */
-
-struct plc_info {
- PortType port_type;
- TimerTwosComplement c_min;
- TimerTwosComplement tl_min;
- TimerTwosComplement tb_min;
- TimerTwosComplement t_out;
- TimerTwosComplement lc_short;
- TimerTwosComplement lc_medium;
- TimerTwosComplement lc_long;
- TimerTwosComplement lc_extended;
- TimerTwosComplement t_scrub;
- TimerTwosComplement ns_max;
- Counter link_errors;
- Counter viol_syms;
- Counter mini_occur;
- int min_idle_gap;
- double link_error_rate;
-};
-
-void plc_init(struct plc_info *pip);
-int plc_inited(struct plc_info *pip);
-void pc_start(LoopbackType loopback);
-void plc_sleep(void);
-void plc_poll(void);
-void pc_stop(void);
-void pc_restart(void);
-void pcm_dump_rtcodes(void);
-void pcm_pseudo_code(void);
-void pcm_lct_done(void);
-void pcm_enabled(void);
-void pcm_trace_prop(void);
-
-
-
-
-
-
-
-
-
-
-
diff --git a/drivers/ap1000/ringbuf.c b/drivers/ap1000/ringbuf.c
deleted file mode 100644
index 8acb617b6..000000000
--- a/drivers/ap1000/ringbuf.c
+++ /dev/null
@@ -1,311 +0,0 @@
- /*
- * Copyright 1996 The Australian National University.
- * Copyright 1996 Fujitsu Laboratories Limited
- *
- * This software may be distributed under the terms of the Gnu
- * Public License version 2 or later
- */
-/*
- * linux/drivers/ap1000/ringbuf.c
- *
- * This provides the /proc/XX/ringbuf interface to the Tnet ring buffer
- */
-#define _APLIB_
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/malloc.h>
-#include <linux/mm.h>
-
-#include <asm/page.h>
-#include <asm/segment.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/uaccess.h>
-
-#include <asm/ap1000/pgtapmmu.h>
-#include <asm/ap1000/apreg.h>
-#include <asm/ap1000/apservice.h>
-
-
-/* we have a small number of reserved ring buffers to ensure that at
- least one parallel program can always run */
-#define RBUF_RESERVED 4
-#define RBUF_RESERVED_ORDER 5
-static struct {
- char *rb_ptr;
- char *shared_ptr;
- int used;
-} reserved_ringbuf[RBUF_RESERVED];
-
-
-void ap_ringbuf_init(void)
-{
- int i,j;
- char *rb_ptr, *shared_ptr;
- int rb_size = PAGE_SIZE * (1<<RBUF_RESERVED_ORDER);
-
- /* preallocate some ringbuffers */
- for (i=0;i<RBUF_RESERVED;i++) {
- if (!(rb_ptr = (char *)__get_free_pages(GFP_ATOMIC,RBUF_RESERVED_ORDER))) {
- printk("failed to preallocate ringbuf %d\n",i);
- return;
- }
- for (j = MAP_NR(rb_ptr); j <= MAP_NR(rb_ptr+rb_size-1); j++) {
- set_bit(PG_reserved,&mem_map[j].flags);
- }
-
- if (!(shared_ptr = (char *)__get_free_page(GFP_ATOMIC))) {
- printk("failed to preallocate shared ptr %d\n",i);
- return;
- }
- set_bit(PG_reserved,&mem_map[MAP_NR(shared_ptr)].flags);
-
- reserved_ringbuf[i].used = 0;
- reserved_ringbuf[i].rb_ptr = rb_ptr;
- reserved_ringbuf[i].shared_ptr = shared_ptr;
- }
-}
-
-
-
-void exit_ringbuf(struct task_struct *tsk)
-{
- int i;
-
- if (!tsk->ringbuf) return;
-
- if (tsk->ringbuf->ringbuf) {
- char *rb_ptr = tsk->ringbuf->ringbuf;
- char *shared_ptr = tsk->ringbuf->shared;
- int order = tsk->ringbuf->order;
- int rb_size = PAGE_SIZE * (1<<order);
-
- for (i=0;i<RBUF_RESERVED;i++)
- if (rb_ptr == reserved_ringbuf[i].rb_ptr) break;
-
- if (i < RBUF_RESERVED) {
- reserved_ringbuf[i].used = 0;
- } else {
- for (i = MAP_NR(rb_ptr); i <= MAP_NR(rb_ptr+rb_size-1); i++) {
- clear_bit(PG_reserved, &mem_map[i].flags);
- }
- free_pages((unsigned)rb_ptr,order);
-
- i = MAP_NR(shared_ptr);
- clear_bit(PG_reserved,&mem_map[i]);
- free_page((unsigned)shared_ptr);
- }
- }
-
- kfree_s(tsk->ringbuf,sizeof(*(tsk->ringbuf)));
- tsk->ringbuf = NULL;
-}
-
-
-/*
- * map the ring buffer into users memory
- */
-static int cap_map(int rb_size)
-{
- struct task_struct *tsk=current;
- int i;
- char *rb_ptr=NULL;
- char *shared_ptr=NULL;
- int order = 0;
- int error,old_uid;
-
- error = verify_area(VERIFY_WRITE,(char *)RBUF_VBASE,rb_size);
- if (error) return error;
-
- if (!MPP_IS_PAR_TASK(tsk->taskid)) {
- printk("ringbuf_mmap called from non-parallel task\n");
- return -EINVAL;
- }
-
-
- if (tsk->ringbuf) return -EINVAL;
-
- rb_size -= RBUF_RING_BUFFER_OFFSET;
- rb_size >>= 1;
-
- switch (rb_size/1024) {
- case 128:
- order = 5;
- break;
- case 512:
- order = 7;
- break;
- case 2048:
- order = 9;
- break;
- case 8192:
- order = 11;
- break;
- default:
- printk("ringbuf_mmap with invalid size %d\n",rb_size);
- return -EINVAL;
- }
-
- if (order == RBUF_RESERVED_ORDER) {
- for (i=0;i<RBUF_RESERVED;i++)
- if (!reserved_ringbuf[i].used) {
- rb_ptr = reserved_ringbuf[i].rb_ptr;
- shared_ptr = reserved_ringbuf[i].shared_ptr;
- reserved_ringbuf[i].used = 1;
- break;
- }
- }
-
- if (!rb_ptr) {
- rb_ptr = (char *)__get_free_pages(GFP_USER,order);
- if (!rb_ptr) return -ENOMEM;
-
- for (i = MAP_NR(rb_ptr); i <= MAP_NR(rb_ptr+rb_size-1); i++) {
- set_bit(PG_reserved,&mem_map[i].flags);
- }
-
- shared_ptr = (char *)__get_free_page(GFP_USER);
- if (!shared_ptr)
- return -ENOMEM;
- set_bit(PG_reserved,&mem_map[MAP_NR(shared_ptr)].flags);
- }
-
- if (!rb_ptr)
- return -ENOMEM;
-
- memset(rb_ptr,0,rb_size);
- memset(shared_ptr,0,PAGE_SIZE);
-
- if (remap_page_range(RBUF_VBASE + RBUF_RING_BUFFER_OFFSET,
- mmu_v2p((unsigned)rb_ptr),
- rb_size,APMMU_PAGE_SHARED))
- return -EAGAIN;
-
- if (remap_page_range(RBUF_VBASE + RBUF_RING_BUFFER_OFFSET + rb_size,
- mmu_v2p((unsigned)rb_ptr),
- rb_size,APMMU_PAGE_SHARED))
- return -EAGAIN;
-
- /* the shared area */
- if (remap_page_range(RBUF_VBASE + RBUF_SHARED_PAGE_OFF,
- mmu_v2p((unsigned)shared_ptr),
- PAGE_SIZE,APMMU_PAGE_SHARED))
- return -EAGAIN;
-
-#if 0
- /* lock the ringbuffer in memory */
- old_uid = current->euid;
- current->euid = 0;
- error = sys_mlock(RBUF_VBASE,2*rb_size+RBUF_RING_BUFFER_OFFSET);
- current->euid = old_uid;
- if (error) {
- printk("ringbuffer mlock failed\n");
- return error;
- }
-#endif
-
- /* the queue pages */
-#define MAP_QUEUE(offset,phys) \
- io_remap_page_range(RBUF_VBASE + offset, \
- phys<<PAGE_SHIFT,PAGE_SIZE,APMMU_PAGE_SHARED,0xa)
-
- MAP_QUEUE(RBUF_PUT_QUEUE, 0x00000);
- MAP_QUEUE(RBUF_GET_QUEUE, 0x00001);
- MAP_QUEUE(RBUF_SEND_QUEUE, 0x00040);
-
- MAP_QUEUE(RBUF_XY_QUEUE, 0x00640);
- MAP_QUEUE(RBUF_X_QUEUE, 0x00240);
- MAP_QUEUE(RBUF_Y_QUEUE, 0x00440);
- MAP_QUEUE(RBUF_XYG_QUEUE, 0x00600);
- MAP_QUEUE(RBUF_XG_QUEUE, 0x00200);
- MAP_QUEUE(RBUF_YG_QUEUE, 0x00400);
- MAP_QUEUE(RBUF_CSI_QUEUE, 0x02004);
- MAP_QUEUE(RBUF_FOP_QUEUE, 0x02005);
-
-#undef MAP_QUEUE
-
- if (!tsk->ringbuf) {
- tsk->ringbuf = (void *)kmalloc(sizeof(*(tsk->ringbuf)),GFP_ATOMIC);
- if (!tsk->ringbuf)
- return -ENOMEM;
- }
-
- memset(tsk->ringbuf,0,sizeof(*tsk->ringbuf));
- tsk->ringbuf->ringbuf = rb_ptr;
- tsk->ringbuf->shared = shared_ptr;
- tsk->ringbuf->order = order;
- tsk->ringbuf->write_ptr = mmu_v2p((unsigned)rb_ptr)<<1;
- tsk->ringbuf->vaddr = RBUF_VBASE;
-
- memset(tsk->ringbuf->vaddr+RBUF_SHARED_PAGE_OFF,0,PAGE_SIZE);
- {
- struct _kernel_cap_shared *_kernel =
- (struct _kernel_cap_shared *)tsk->ringbuf->vaddr;
- _kernel->rbuf_read_ptr = (rb_size>>5) - 1;
- }
-
- return 0;
-}
-
-
-static int
-ringbuf_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
- int numcells, *phys_cells;
- extern struct cap_init cap_init;
-
- switch (cmd) {
- case CAP_GETINIT:
- if (copy_to_user((char *)arg,(char *)&cap_init,sizeof(cap_init)))
- return -EFAULT;
- break;
-
- case CAP_SYNC:
- if (verify_area(VERIFY_READ, (void *) arg, sizeof(int)*2))
- return -EFAULT;
- if (get_user(numcells,(int *)arg)) return -EFAULT;
- if (get_user((unsigned)phys_cells,
- ((int *)arg)+1)) return -EFAULT;
- if (verify_area(VERIFY_READ,phys_cells,sizeof(int)*numcells))
- return -EFAULT;
- return ap_sync(numcells,phys_cells);
- break;
-
- case CAP_SETGANG:
- {
- int v;
- if (get_user(v,(int *)arg)) return -EFAULT;
- mpp_set_gang_factor(v);
- break;
- }
-
- case CAP_MAP:
- return cap_map(arg);
-
- default:
- printk("unknown ringbuf ioctl %d\n",cmd);
- return -EINVAL;
- }
- return 0;
-}
-
-
-static struct file_operations proc_ringbuf_operations = {
- NULL,
- NULL,
- NULL,
- NULL, /* readdir */
- NULL, /* poll */
- ringbuf_ioctl, /* ioctl */
- NULL, /* mmap */
- NULL, /* no special open code */
- NULL, /* flush */
- NULL, /* no special release code */
- NULL /* can't fsync */
-};
-
-struct inode_operations proc_ringbuf_inode_operations = {
- &proc_ringbuf_operations, /* default base directory file-ops */
-};
diff --git a/drivers/ap1000/smt-types.h b/drivers/ap1000/smt-types.h
deleted file mode 100644
index b17c83176..000000000
--- a/drivers/ap1000/smt-types.h
+++ /dev/null
@@ -1,167 +0,0 @@
- /*
- * Copyright 1996 The Australian National University.
- * Copyright 1996 Fujitsu Laboratories Limited
- *
- * This software may be distributed under the terms of the Gnu
- * Public License version 2 or later
- */
-/*
- * Definitions for FDDI Station Management.
- */
-
-/*
- * FDDI-COMMON types.
- */
-
-typedef unsigned int Counter; /* 32-bit event counter */
-
-typedef enum {
- cp_isolated,
- cp_local,
- cp_secondary,
- cp_primary,
- cp_concatenated,
- cp_thru
-} CurrentPath;
-
-typedef char Flag;
-
-typedef unsigned char LongAddressType[6];
-
-typedef enum {
- pt_a,
- pt_b,
- pt_s,
- pt_m,
- pt_none
-} PortType;
-
-typedef unsigned short ResourceId;
-
-typedef int Time; /* time in 80ns units */
-#define FDDI_TIME_UNIT 80e-9 /* 80 nanoseconds */
-#define SECS_TO_FDDI_TIME(s) ((int)((s)/FDDI_TIME_UNIT+0.99))
-
-typedef int TimerTwosComplement;
-
-/*
- * FDDI-SMT types.
- */
-typedef enum {
- ec_Out,
- ec_In,
- ec_Trace,
- ec_Leave,
- ec_Path_Test,
- ec_Insert,
- ec_Check,
- ec_Deinsert
-} ECMState;
-
-/*
- * FDDI-MAC types.
- */
-typedef enum {
- dat_none,
- dat_pass,
- dat_fail
-} DupAddressTest;
-
-typedef unsigned short DupCondition;
-#define DC_MYDUP 1
-#define DC_UNADUP 2
-
-typedef unsigned short FS_Functions;
-#define FSF_FS_REPEATING 1
-#define FSF_FS_SETTING 2
-#define FSF_FS_CLEARING 4
-
-typedef unsigned char NACondition;
-#define NAC_UNACHANGE 1
-#define NAC_DNACHANGE 2
-
-typedef enum {
- rmt_Isolated,
- rmt_Non_Op,
- rmt_Ring_Op,
- rmt_Detect,
- rmt_Non_Op_Dup,
- rmt_Ring_Op_Dup,
- rmt_Directed,
- rmt_Trace
-} RMTState;
-
-typedef unsigned char ShortAddressType[2];
-
-/*
- * FDDI-PATH types.
- */
-typedef unsigned short TraceStatus;
-#define TS_TRACEINITIATED 1
-#define TS_TRACEPROPAGATED 2
-#define TS_TRACETERMINATED 4
-#define TS_TRACETIMEOUT 8
-
-/*
- * FDDI-PORT types.
- */
-typedef enum {
- PC_Maint,
- PC_Enable,
- PC_Disable,
- PC_Start,
- PC_Stop
-} ActionType;
-
-typedef unsigned char ConnectionPolicies;
-#define PC_MAC_LCT 1
-#define PC_MAC_LOOP 2
-
-typedef enum {
- cs_disabled,
- cs_connecting,
- cs_standby,
- cs_active
-} ConnectState;
-
-typedef enum {
- ls_qls,
- ls_ils,
- ls_mls,
- ls_hls,
- ls_pdr,
- ls_lsu,
- ls_nls
-} LineState;
-
-typedef enum {
- pc_Off,
- pc_Break,
- pc_Trace,
- pc_Connect,
- pc_Next,
- pc_Signal,
- pc_Join,
- pc_Verify,
- pc_Active,
- pc_Maint
-} PCMState;
-
-typedef enum {
- pcw_none,
- pcw_mm,
- pcw_otherincompatible,
- pcw_pathnotavailable
-} PC_Withhold;
-
-typedef enum {
- pmd_multimode,
- pmd_single_mode1,
- pmd_single_mode2,
- pmd_sonet,
- pmd_low_cost_fiber,
- pmd_twisted_pair,
- pmd_unknown,
- pmd_unspecified
-} PMDClass;
-
diff --git a/drivers/block/cmd64x.c b/drivers/block/cmd64x.c
index 6346f216e..8f5f04aea 100644
--- a/drivers/block/cmd64x.c
+++ b/drivers/block/cmd64x.c
@@ -7,7 +7,7 @@
* on the 646U2 and not on the 646U.
*
* Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
- * Copyright (C) 1998 David S. Miller (davem@dm.cobaltmicro.com)
+ * Copyright (C) 1998 David S. Miller (davem@redhat.com)
* Copyright (C) 1999 Andre Hedrick (andre@suse.com)
*/
diff --git a/drivers/block/swim3.c b/drivers/block/swim3.c
index 3190c10b9..911bafe23 100644
--- a/drivers/block/swim3.c
+++ b/drivers/block/swim3.c
@@ -241,10 +241,6 @@ static int floppy_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long param);
static int floppy_open(struct inode *inode, struct file *filp);
static int floppy_release(struct inode *inode, struct file *filp);
-static ssize_t floppy_read(struct file *filp, char *buf,
- size_t count, loff_t *ppos);
-static ssize_t floppy_write(struct file *filp, const char *buf,
- size_t count, loff_t *ppos);
static int floppy_check_change(kdev_t dev);
static int floppy_revalidate(kdev_t dev);
static int swim3_add_device(struct device_node *swims);
@@ -988,42 +984,6 @@ static int floppy_revalidate(kdev_t dev)
return ret;
}
-static ssize_t floppy_read(struct file *filp, char *buf,
- size_t count, loff_t *ppos)
-{
- struct inode *inode = filp->f_dentry->d_inode;
- struct floppy_state *fs;
- int devnum = MINOR(inode->i_rdev);
-
- if (devnum >= floppy_count)
- return -ENODEV;
-
- fs = &floppy_states[devnum];
- if (fs->ejected)
- return -ENXIO;
- return block_read(filp, buf, count, ppos);
-}
-
-static ssize_t floppy_write(struct file * filp, const char * buf,
- size_t count, loff_t *ppos)
-{
- struct inode * inode = filp->f_dentry->d_inode;
- struct floppy_state *fs;
- int devnum = MINOR(inode->i_rdev);
-
- if (devnum >= floppy_count)
- return -ENODEV;
- check_disk_change(inode->i_rdev);
- fs = &floppy_states[devnum];
- if (fs->ejected)
- return -ENXIO;
- if (fs->write_prot < 0)
- fs->write_prot = swim3_readbit(fs, WRITE_PROT);
- if (fs->write_prot)
- return -EROFS;
- return block_write(filp, buf, count, ppos);
-}
-
static void floppy_off(unsigned int nr)
{
}
diff --git a/drivers/block/swim_iop.c b/drivers/block/swim_iop.c
index 6a74f9a0b..467cda26d 100644
--- a/drivers/block/swim_iop.c
+++ b/drivers/block/swim_iop.c
@@ -102,10 +102,6 @@ static void swimiop_receive(struct iop_msg *, struct pt_regs *);
static void swimiop_status_update(int, struct swim_drvstatus *);
static int swimiop_eject(struct floppy_state *fs);
-static ssize_t floppy_read(struct file *filp, char *buf,
- size_t count, loff_t *ppos);
-static ssize_t floppy_write(struct file *filp, const char *buf,
- size_t count, loff_t *ppos);
static int floppy_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long param);
static int floppy_open(struct inode *inode, struct file *filp);
@@ -338,40 +334,6 @@ static int swimiop_eject(struct floppy_state *fs)
return cmd->error;
}
-static ssize_t floppy_read(struct file *filp, char *buf,
- size_t count, loff_t *ppos)
-{
- struct inode *inode = filp->f_dentry->d_inode;
- struct floppy_state *fs;
- int devnum = MINOR(inode->i_rdev);
-
- if (devnum >= floppy_count)
- return -ENODEV;
-
- fs = &floppy_states[devnum];
- if (fs->ejected)
- return -ENXIO;
- return block_read(filp, buf, count, ppos);
-}
-
-static ssize_t floppy_write(struct file * filp, const char * buf,
- size_t count, loff_t *ppos)
-{
- struct inode * inode = filp->f_dentry->d_inode;
- struct floppy_state *fs;
- int devnum = MINOR(inode->i_rdev);
-
- if (devnum >= floppy_count)
- return -ENODEV;
- check_disk_change(inode->i_rdev);
- fs = &floppy_states[devnum];
- if (fs->ejected)
- return -ENXIO;
- if (fs->write_prot)
- return -EROFS;
- return block_write(filp, buf, count, ppos);
-}
-
static struct floppy_struct floppy_type =
{ 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,NULL }; /* 7 1.44MB 3.5" */
diff --git a/drivers/char/agp/agpgart_be.c b/drivers/char/agp/agpgart_be.c
index 27413489a..a83928a02 100644
--- a/drivers/char/agp/agpgart_be.c
+++ b/drivers/char/agp/agpgart_be.c
@@ -232,7 +232,6 @@ void agp_free_memory(agp_memory * curr)
}
if (curr->type != 0) {
agp_bridge.free_by_type(curr);
- MOD_DEC_USE_COUNT;
return;
}
if (curr->page_count != 0) {
@@ -260,15 +259,23 @@ agp_memory *agp_allocate_memory(size_t page_count, u32 type)
agp_bridge.max_memory_agp) {
return NULL;
}
+
if (type != 0) {
new = agp_bridge.alloc_by_type(page_count, type);
return new;
}
+ /* We always increase the module count, since free auto-decrements
+ * it
+ */
+
+ MOD_INC_USE_COUNT;
+
scratch_pages = (page_count + ENTRIES_PER_PAGE - 1) / ENTRIES_PER_PAGE;
new = agp_create_memory(scratch_pages);
if (new == NULL) {
+ MOD_DEC_USE_COUNT;
return NULL;
}
for (i = 0; i < page_count; i++) {
@@ -286,7 +293,6 @@ agp_memory *agp_allocate_memory(size_t page_count, u32 type)
new->page_count++;
}
- MOD_INC_USE_COUNT;
return new;
}
@@ -781,11 +787,13 @@ static aper_size_info_fixed intel_i810_sizes[] =
};
#define AGP_DCACHE_MEMORY 1
+#define AGP_PHYS_MEMORY 2
static gatt_mask intel_i810_masks[] =
{
{I810_PTE_VALID, 0},
- {(I810_PTE_VALID | I810_PTE_LOCAL), AGP_DCACHE_MEMORY}
+ {(I810_PTE_VALID | I810_PTE_LOCAL), AGP_DCACHE_MEMORY},
+ {I810_PTE_VALID, 0}
};
static struct _intel_i810_private {
@@ -896,7 +904,7 @@ static int intel_i810_insert_entries(agp_memory * mem, off_t pg_start,
if ((type == AGP_DCACHE_MEMORY) &&
(mem->type == AGP_DCACHE_MEMORY)) {
/* special insert */
-
+ CACHE_FLUSH();
for (i = pg_start;
i < (pg_start + mem->page_count); i++) {
OUTREG32(intel_i810_private.registers,
@@ -904,20 +912,24 @@ static int intel_i810_insert_entries(agp_memory * mem, off_t pg_start,
(i * 4096) | I810_PTE_LOCAL |
I810_PTE_VALID);
}
-
+ CACHE_FLUSH();
agp_bridge.tlb_flush(mem);
return 0;
}
+ if((type == AGP_PHYS_MEMORY) &&
+ (mem->type == AGP_PHYS_MEMORY)) {
+ goto insert;
+ }
return -EINVAL;
}
- if (mem->is_flushed == FALSE) {
- CACHE_FLUSH();
- mem->is_flushed = TRUE;
- }
+
+insert:
+ CACHE_FLUSH();
for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
OUTREG32(intel_i810_private.registers,
I810_PTE_BASE + (j * 4), mem->memory[i]);
}
+ CACHE_FLUSH();
agp_bridge.tlb_flush(mem);
return 0;
@@ -955,15 +967,55 @@ static agp_memory *intel_i810_alloc_by_type(size_t pg_count, int type)
new->page_count = pg_count;
new->num_scratch_pages = 0;
vfree(new->memory);
+ MOD_INC_USE_COUNT;
return new;
}
+ if(type == AGP_PHYS_MEMORY) {
+ /* The I810 requires a physical address to program
+ * it's mouse pointer into hardware. However the
+ * Xserver still writes to it through the agp
+ * aperture
+ */
+ if (pg_count != 1) {
+ return NULL;
+ }
+ new = agp_create_memory(1);
+
+ if (new == NULL) {
+ return NULL;
+ }
+ MOD_INC_USE_COUNT;
+ new->memory[0] = agp_alloc_page();
+
+ if (new->memory[0] == 0) {
+ /* Free this structure */
+ agp_free_memory(new);
+ return NULL;
+ }
+ new->memory[0] =
+ agp_bridge.mask_memory(
+ virt_to_phys((void *) new->memory[0]),
+ type);
+ new->page_count = 1;
+ new->num_scratch_pages = 1;
+ new->type = AGP_PHYS_MEMORY;
+ new->physical = virt_to_phys((void *) new->memory[0]);
+ return new;
+ }
+
return NULL;
}
static void intel_i810_free_by_type(agp_memory * curr)
{
agp_free_key(curr->key);
+ if(curr->type == AGP_PHYS_MEMORY) {
+ agp_destroy_page((unsigned long)
+ phys_to_virt(curr->memory[0]));
+ vfree(curr->memory);
+ }
kfree(curr);
+ MOD_DEC_USE_COUNT;
}
static unsigned long intel_i810_mask_memory(unsigned long addr, int type)
@@ -1916,7 +1968,7 @@ static struct agp_max_table maxes_table[9] =
static int agp_find_max(void)
{
- long memory, t, index, result;
+ long memory, index, result;
memory = virt_to_phys(high_memory) >> 20;
index = 1;
@@ -1926,16 +1978,15 @@ static int agp_find_max(void)
index++;
}
- t = (memory - maxes_table[index - 1].mem) /
- (maxes_table[index].mem - maxes_table[index - 1].mem);
-
result = maxes_table[index - 1].agp +
- (t * (maxes_table[index].agp - maxes_table[index - 1].agp));
+ ( (memory - maxes_table[index - 1].mem) *
+ (maxes_table[index].agp - maxes_table[index - 1].agp)) /
+ (maxes_table[index].mem - maxes_table[index - 1].mem);
printk(KERN_INFO "agpgart: Maximum main memory to use "
"for agp memory: %ldM\n", result);
result = result << (20 - PAGE_SHIFT);
- return result;
+ return result;
}
#define AGPGART_VERSION_MAJOR 0
diff --git a/drivers/char/agp/agpgart_fe.c b/drivers/char/agp/agpgart_fe.c
index e098b4bab..ef915259e 100644
--- a/drivers/char/agp/agpgart_fe.c
+++ b/drivers/char/agp/agpgart_fe.c
@@ -298,7 +298,7 @@ static agp_memory *agp_allocate_memory_wrap(size_t pg_count, u32 type)
agp_memory *memory;
memory = agp_allocate_memory(pg_count, type);
-
+ printk("memory : %p\n", memory);
if (memory == NULL) {
return NULL;
}
@@ -911,6 +911,7 @@ static int agpioc_allocate_wrap(agp_file_private * priv, unsigned long arg)
return -ENOMEM;
}
alloc.key = memory->key;
+ alloc.physical = memory->physical;
if (copy_to_user((void *) arg, &alloc, sizeof(agp_allocate))) {
agp_free_memory_wrap(memory);
diff --git a/drivers/char/generic_serial.c b/drivers/char/generic_serial.c
index f4ecc75a5..95a6c4370 100644
--- a/drivers/char/generic_serial.c
+++ b/drivers/char/generic_serial.c
@@ -103,10 +103,6 @@ static inline int copy_from_user(void *to,const void *from, int c)
#include "generic_serial.h"
-#ifndef MODULE
-extern void my_hd (unsigned char *ptr, int n);
-#endif
-
static char * tmp_buf;
static DECLARE_MUTEX(tmp_buf_sem);
@@ -119,8 +115,8 @@ int gs_debug = 0;
#define gs_dprintk(f, str...) /* nothing */
#endif
-#define func_enter() gs_dprintk (SX_DEBUG_FLOW, "gs: enter " __FUNCTION__ "\n")
-#define func_exit() gs_dprintk (SX_DEBUG_FLOW, "gs: exit " __FUNCTION__ "\n")
+#define func_enter() gs_dprintk (GS_DEBUG_FLOW, "gs: enter " __FUNCTION__ "\n")
+#define func_exit() gs_dprintk (GS_DEBUG_FLOW, "gs: exit " __FUNCTION__ "\n")
@@ -856,7 +852,6 @@ void gs_set_termios (struct tty_struct * tty,
if (gs_debug & GS_DEBUG_TERMIOS) {
gs_dprintk (GS_DEBUG_TERMIOS, "termios structure (%p):\n", tiosp);
- my_hd ((unsigned char *)tiosp, sizeof (struct termios));
}
#if 0
diff --git a/drivers/char/generic_serial.h b/drivers/char/generic_serial.h
index ca321af9b..2e44bee95 100644
--- a/drivers/char/generic_serial.h
+++ b/drivers/char/generic_serial.h
@@ -12,6 +12,8 @@
#ifndef GENERIC_SERIAL_H
#define GENERIC_SERIAL_H
+#define RS_EVENT_WRITE_WAKEUP 0
+
struct real_driver {
void (*disable_tx_interrupts) (void *);
void (*enable_tx_interrupts) (void *);
@@ -75,6 +77,7 @@ struct gs_port {
#define GS_DEBUG_TERMIOS 0x00000004
#define GS_DEBUG_STUFF 0x00000008
#define GS_DEBUG_CLOSE 0x00000010
+#define GS_DEBUG_FLOW 0x00000020
void gs_put_char(struct tty_struct *tty, unsigned char ch);
diff --git a/drivers/char/joystick/joy-creative.c b/drivers/char/joystick/joy-creative.c
index 7e97a677d..8faec5f82 100644
--- a/drivers/char/joystick/joy-creative.c
+++ b/drivers/char/joystick/joy-creative.c
@@ -66,7 +66,7 @@ static int js_cr_read_packet(int io, unsigned int *data)
int r[2], t[2], p[2];
int i, j, ret;
- for (i = 0; i < 2; i++); {
+ for (i = 0; i < 2; i++) {
r[i] = buf[i] = 0;
p[i] = t[i] = JS_CR_MAX_STROBE;
p[i] += JS_CR_MAX_STROBE;
diff --git a/drivers/char/scc.h b/drivers/char/scc.h
new file mode 100644
index 000000000..53a4cd2ae
--- /dev/null
+++ b/drivers/char/scc.h
@@ -0,0 +1,613 @@
+/*
+ * atari_SCC.h: Definitions for the Am8530 Serial Communications Controller
+ *
+ * Copyright 1994 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive
+ * for more details.
+ *
+ */
+
+
+#ifndef _SCC_H
+#define _SCC_H
+
+#include <linux/delay.h>
+
+/* Special configuration ioctls for the Atari SCC5380 Serial
+ * Communications Controller
+ */
+
+/* ioctl command codes */
+
+#define TIOCGATSCC 0x54c0 /* get SCC configuration */
+#define TIOCSATSCC 0x54c1 /* set SCC configuration */
+#define TIOCDATSCC 0x54c2 /* reset configuration to defaults */
+
+/* Clock sources */
+
+#define CLK_RTxC 0
+#define CLK_TRxC 1
+#define CLK_PCLK 2
+
+/* baud_bases for the common clocks in the Atari. These are the real
+ * frequencies divided by 16.
+ */
+
+#define SCC_BAUD_BASE_TIMC 19200 /* 0.3072 MHz from TT-MFP, Timer C */
+#define SCC_BAUD_BASE_BCLK 153600 /* 2.4576 MHz */
+#define SCC_BAUD_BASE_PCLK4 229500 /* 3.6720 MHz */
+#define SCC_BAUD_BASE_PCLK 503374 /* 8.0539763 MHz */
+#define SCC_BAUD_BASE_NONE 0 /* for not connected or unused
+ * clock sources */
+
+/* The SCC clock configuration structure */
+
+struct scc_clock_config {
+ unsigned RTxC_base; /* base_baud of RTxC */
+ unsigned TRxC_base; /* base_baud of TRxC */
+ unsigned PCLK_base; /* base_baud of PCLK, both channels! */
+ struct {
+ unsigned clksrc; /* CLK_RTxC, CLK_TRxC or CLK_PCLK */
+ unsigned divisor; /* divisor for base baud, valid values:
+ * see below */
+ } baud_table[17]; /* For 50, 75, 110, 135, 150, 200, 300,
+ * 600, 1200, 1800, 2400, 4800, 9600,
+ * 19200, 38400, 57600 and 115200 bps.
+ * The last two could be replaced by
+ * other rates > 38400 if they're not
+ * possible.
+ */
+};
+
+/* The following divisors are valid:
+ *
+ * - CLK_RTxC: 1 or even (1, 2 and 4 are the direct modes, > 4 use
+ * the BRG)
+ *
+ * - CLK_TRxC: 1, 2 or 4 (no BRG, only direct modes possible)
+ *
+ * - CLK_PCLK: >= 4 and even (no direct modes, only BRG)
+ *
+ */
+
+struct scc_port {
+ struct gs_port gs;
+ volatile unsigned char *ctrlp;
+ volatile unsigned char *datap;
+ int x_char; /* xon/xoff character */
+ int c_dcd;
+ int channel;
+ struct scc_port *port_a; /* Reference to port A and B */
+ struct scc_port *port_b; /* structs for reg access */
+};
+
+#define SCC_MAGIC 0x52696368
+
+/***********************************************************************/
+/* */
+/* Register Names */
+/* */
+/***********************************************************************/
+
+/* The SCC documentation gives no explicit names to the registers,
+ * they're just called WR0..15 and RR0..15. To make the source code
+ * better readable and make the transparent write reg read access (see
+ * below) possible, I christen them here with self-invented names.
+ * Note that (real) read registers are assigned numbers 16..31. WR7'
+ * has number 33.
+ */
+
+#define COMMAND_REG 0 /* wo */
+#define INT_AND_DMA_REG 1 /* wo */
+#define INT_VECTOR_REG 2 /* rw, common to both channels */
+#define RX_CTRL_REG 3 /* rw */
+#define AUX1_CTRL_REG 4 /* rw */
+#define TX_CTRL_REG 5 /* rw */
+#define SYNC_ADR_REG 6 /* wo */
+#define SYNC_CHAR_REG 7 /* wo */
+#define SDLC_OPTION_REG 33 /* wo */
+#define TX_DATA_REG 8 /* wo */
+#define MASTER_INT_CTRL 9 /* wo, common to both channels */
+#define AUX2_CTRL_REG 10 /* rw */
+#define CLK_CTRL_REG 11 /* wo */
+#define TIMER_LOW_REG 12 /* rw */
+#define TIMER_HIGH_REG 13 /* rw */
+#define DPLL_CTRL_REG 14 /* wo */
+#define INT_CTRL_REG 15 /* rw */
+
+#define STATUS_REG 16 /* ro */
+#define SPCOND_STATUS_REG 17 /* wo */
+/* RR2 is WR2 for Channel A, Channel B gives vector + current status: */
+#define CURR_VECTOR_REG 18 /* Ch. B only, Ch. A for rw */
+#define INT_PENDING_REG 19 /* Channel A only! */
+/* RR4 is WR4, if b6(MR7') == 1 */
+/* RR5 is WR5, if b6(MR7') == 1 */
+#define FS_FIFO_LOW_REG 22 /* ro */
+#define FS_FIFO_HIGH_REG 23 /* ro */
+#define RX_DATA_REG 24 /* ro */
+/* RR9 is WR3, if b6(MR7') == 1 */
+#define DPLL_STATUS_REG 26 /* ro */
+/* RR11 is WR10, if b6(MR7') == 1 */
+/* RR12 is WR12 */
+/* RR13 is WR13 */
+/* RR14 not present */
+/* RR15 is WR15 */
+
+
+/***********************************************************************/
+/* */
+/* Register Values */
+/* */
+/***********************************************************************/
+
+
+/* WR0: COMMAND_REG "CR" */
+
+#define CR_RX_CRC_RESET 0x40
+#define CR_TX_CRC_RESET 0x80
+#define CR_TX_UNDERRUN_RESET 0xc0
+
+#define CR_EXTSTAT_RESET 0x10
+#define CR_SEND_ABORT 0x18
+#define CR_ENAB_INT_NEXT_RX 0x20
+#define CR_TX_PENDING_RESET 0x28
+#define CR_ERROR_RESET 0x30
+#define CR_HIGHEST_IUS_RESET 0x38
+
+
+/* WR1: INT_AND_DMA_REG "IDR" */
+
+#define IDR_EXTSTAT_INT_ENAB 0x01
+#define IDR_TX_INT_ENAB 0x02
+#define IDR_PARERR_AS_SPCOND 0x04
+
+#define IDR_RX_INT_DISAB 0x00
+#define IDR_RX_INT_FIRST 0x08
+#define IDR_RX_INT_ALL 0x10
+#define IDR_RX_INT_SPCOND 0x18
+#define IDR_RX_INT_MASK 0x18
+
+#define IDR_WAITREQ_RX 0x20
+#define IDR_WAITREQ_IS_REQ 0x40
+#define IDR_WAITREQ_ENAB 0x80
+
+
+/* WR3: RX_CTRL_REG "RCR" */
+
+#define RCR_RX_ENAB 0x01
+#define RCR_DISCARD_SYNC_CHARS 0x02
+#define RCR_ADDR_SEARCH 0x04
+#define RCR_CRC_ENAB 0x08
+#define RCR_SEARCH_MODE 0x10
+#define RCR_AUTO_ENAB_MODE 0x20
+
+#define RCR_CHSIZE_MASK 0xc0
+#define RCR_CHSIZE_5 0x00
+#define RCR_CHSIZE_6 0x40
+#define RCR_CHSIZE_7 0x80
+#define RCR_CHSIZE_8 0xc0
+
+
+/* WR4: AUX1_CTRL_REG "A1CR" */
+
+#define A1CR_PARITY_MASK 0x03
+#define A1CR_PARITY_NONE 0x00
+#define A1CR_PARITY_ODD 0x01
+#define A1CR_PARITY_EVEN 0x03
+
+#define A1CR_MODE_MASK 0x0c
+#define A1CR_MODE_SYNCR 0x00
+#define A1CR_MODE_ASYNC_1 0x04
+#define A1CR_MODE_ASYNC_15 0x08
+#define A1CR_MODE_ASYNC_2 0x0c
+
+#define A1CR_SYNCR_MODE_MASK 0x30
+#define A1CR_SYNCR_MONOSYNC 0x00
+#define A1CR_SYNCR_BISYNC 0x10
+#define A1CR_SYNCR_SDLC 0x20
+#define A1CR_SYNCR_EXTCSYNC 0x30
+
+#define A1CR_CLKMODE_MASK 0xc0
+#define A1CR_CLKMODE_x1 0x00
+#define A1CR_CLKMODE_x16 0x40
+#define A1CR_CLKMODE_x32 0x80
+#define A1CR_CLKMODE_x64 0xc0
+
+
+/* WR5: TX_CTRL_REG "TCR" */
+
+#define TCR_TX_CRC_ENAB 0x01
+#define TCR_RTS 0x02
+#define TCR_USE_CRC_CCITT 0x00
+#define TCR_USE_CRC_16 0x04
+#define TCR_TX_ENAB 0x08
+#define TCR_SEND_BREAK 0x10
+
+#define TCR_CHSIZE_MASK 0x60
+#define TCR_CHSIZE_5 0x00
+#define TCR_CHSIZE_6 0x20
+#define TCR_CHSIZE_7 0x40
+#define TCR_CHSIZE_8 0x60
+
+#define TCR_DTR 0x80
+
+
+/* WR7': SLDC_OPTION_REG "SOR" */
+
+#define SOR_AUTO_TX_ENAB 0x01
+#define SOR_AUTO_EOM_RESET 0x02
+#define SOR_AUTO_RTS_MODE 0x04
+#define SOR_NRZI_DISAB_HIGH 0x08
+#define SOR_ALT_DTRREQ_TIMING 0x10
+#define SOR_READ_CRC_CHARS 0x20
+#define SOR_EXTENDED_REG_ACCESS 0x40
+
+
+/* WR9: MASTER_INT_CTRL "MIC" */
+
+#define MIC_VEC_INCL_STAT 0x01
+#define MIC_NO_VECTOR 0x02
+#define MIC_DISAB_LOWER_CHAIN 0x04
+#define MIC_MASTER_INT_ENAB 0x08
+#define MIC_STATUS_HIGH 0x10
+#define MIC_IGN_INTACK 0x20
+
+#define MIC_NO_RESET 0x00
+#define MIC_CH_A_RESET 0x40
+#define MIC_CH_B_RESET 0x80
+#define MIC_HARD_RESET 0xc0
+
+
+/* WR10: AUX2_CTRL_REG "A2CR" */
+
+#define A2CR_SYNC_6 0x01
+#define A2CR_LOOP_MODE 0x02
+#define A2CR_ABORT_ON_UNDERRUN 0x04
+#define A2CR_MARK_IDLE 0x08
+#define A2CR_GO_ACTIVE_ON_POLL 0x10
+
+#define A2CR_CODING_MASK 0x60
+#define A2CR_CODING_NRZ 0x00
+#define A2CR_CODING_NRZI 0x20
+#define A2CR_CODING_FM1 0x40
+#define A2CR_CODING_FM0 0x60
+
+#define A2CR_PRESET_CRC_1 0x80
+
+
+/* WR11: CLK_CTRL_REG "CCR" */
+
+#define CCR_TRxCOUT_MASK 0x03
+#define CCR_TRxCOUT_XTAL 0x00
+#define CCR_TRxCOUT_TXCLK 0x01
+#define CCR_TRxCOUT_BRG 0x02
+#define CCR_TRxCOUT_DPLL 0x03
+
+#define CCR_TRxC_OUTPUT 0x04
+
+#define CCR_TXCLK_MASK 0x18
+#define CCR_TXCLK_RTxC 0x00
+#define CCR_TXCLK_TRxC 0x08
+#define CCR_TXCLK_BRG 0x10
+#define CCR_TXCLK_DPLL 0x18
+
+#define CCR_RXCLK_MASK 0x60
+#define CCR_RXCLK_RTxC 0x00
+#define CCR_RXCLK_TRxC 0x20
+#define CCR_RXCLK_BRG 0x40
+#define CCR_RXCLK_DPLL 0x60
+
+#define CCR_RTxC_XTAL 0x80
+
+
+/* WR14: DPLL_CTRL_REG "DCR" */
+
+#define DCR_BRG_ENAB 0x01
+#define DCR_BRG_USE_PCLK 0x02
+#define DCR_DTRREQ_IS_REQ 0x04
+#define DCR_AUTO_ECHO 0x08
+#define DCR_LOCAL_LOOPBACK 0x10
+
+#define DCR_DPLL_EDGE_SEARCH 0x20
+#define DCR_DPLL_ERR_RESET 0x40
+#define DCR_DPLL_DISAB 0x60
+#define DCR_DPLL_CLK_BRG 0x80
+#define DCR_DPLL_CLK_RTxC 0xa0
+#define DCR_DPLL_FM 0xc0
+#define DCR_DPLL_NRZI 0xe0
+
+
+/* WR15: INT_CTRL_REG "ICR" */
+
+#define ICR_OPTIONREG_SELECT 0x01
+#define ICR_ENAB_BRG_ZERO_INT 0x02
+#define ICR_USE_FS_FIFO 0x04
+#define ICR_ENAB_DCD_INT 0x08
+#define ICR_ENAB_SYNC_INT 0x10
+#define ICR_ENAB_CTS_INT 0x20
+#define ICR_ENAB_UNDERRUN_INT 0x40
+#define ICR_ENAB_BREAK_INT 0x80
+
+
+/* RR0: STATUS_REG "SR" */
+
+#define SR_CHAR_AVAIL 0x01
+#define SR_BRG_ZERO 0x02
+#define SR_TX_BUF_EMPTY 0x04
+#define SR_DCD 0x08
+#define SR_SYNC_ABORT 0x10
+#define SR_CTS 0x20
+#define SR_TX_UNDERRUN 0x40
+#define SR_BREAK 0x80
+
+
+/* RR1: SPCOND_STATUS_REG "SCSR" */
+
+#define SCSR_ALL_SENT 0x01
+#define SCSR_RESIDUAL_MASK 0x0e
+#define SCSR_PARITY_ERR 0x10
+#define SCSR_RX_OVERRUN 0x20
+#define SCSR_CRC_FRAME_ERR 0x40
+#define SCSR_END_OF_FRAME 0x80
+
+
+/* RR3: INT_PENDING_REG "IPR" */
+
+#define IPR_B_EXTSTAT 0x01
+#define IPR_B_TX 0x02
+#define IPR_B_RX 0x04
+#define IPR_A_EXTSTAT 0x08
+#define IPR_A_TX 0x10
+#define IPR_A_RX 0x20
+
+
+/* RR7: FS_FIFO_HIGH_REG "FFHR" */
+
+#define FFHR_CNT_MASK 0x3f
+#define FFHR_IS_FROM_FIFO 0x40
+#define FFHR_FIFO_OVERRUN 0x80
+
+
+/* RR10: DPLL_STATUS_REG "DSR" */
+
+#define DSR_ON_LOOP 0x02
+#define DSR_ON_LOOP_SENDING 0x10
+#define DSR_TWO_CLK_MISSING 0x40
+#define DSR_ONE_CLK_MISSING 0x80
+
+/***********************************************************************/
+/* */
+/* Register Access */
+/* */
+/***********************************************************************/
+
+
+/* The SCC needs 3.5 PCLK cycles recovery time between to register
+ * accesses. PCLK runs with 8 MHz on an Atari, so this delay is 3.5 *
+ * 125 ns = 437.5 ns. This is too short for udelay().
+ * 10/16/95: A tstb mfp.par_dt_reg takes 600ns (sure?) and thus should be
+ * quite right
+ */
+
+#define scc_reg_delay() \
+ do { \
+ if (MACH_IS_MVME16x || MACH_IS_BVME6000 || MACH_IS_MVME147) \
+ __asm__ __volatile__ ( " nop; nop"); \
+ else if (MACH_IS_ATARI) \
+ __asm__ __volatile__ ( "tstb %0" : : "g" (*_scc_del) : "cc" );\
+ } while (0)
+
+extern unsigned char scc_shadow[2][16];
+
+/* The following functions should relax the somehow complicated
+ * register access of the SCC. _SCCwrite() stores all written values
+ * (except for WR0 and WR8) in shadow registers for later recall. This
+ * removes the burden of remembering written values as needed. The
+ * extra work of storing the value doesn't count, since a delay is
+ * needed after a SCC access anyway. Additionally, _SCCwrite() manages
+ * writes to WR0 and WR8 differently, because these can be accessed
+ * directly with less overhead. Another special case are WR7 and WR7'.
+ * _SCCwrite automatically checks what of this registers is selected
+ * and changes b0 of WR15 if needed.
+ *
+ * _SCCread() for standard read registers is straightforward, except
+ * for RR2 (split into two "virtual" registers: one for the value
+ * written to WR2 (from the shadow) and one for the vector including
+ * status from RR2, Ch. B) and RR3. The latter must be read from
+ * Channel A, because it reads as all zeros on Ch. B. RR0 and RR8 can
+ * be accessed directly as before.
+ *
+ * The two inline function contain complicated switch statements. But
+ * I rely on regno and final_delay being constants, so gcc can reduce
+ * the whole stuff to just some assembler statements.
+ *
+ * _SCCwrite and _SCCread aren't intended to be used directly under
+ * normal circumstances. The macros SCCread[_ND] and SCCwrite[_ND] are
+ * for that purpose. They assume that a local variable 'port' is
+ * declared and pointing to the port's scc_struct entry. The
+ * variants with "_NB" appended should be used if no other SCC
+ * accesses follow immediatly (within 0.5 usecs). They just skip the
+ * final delay nops.
+ *
+ * Please note that accesses to SCC registers should only take place
+ * when interrupts are turned off (at least if SCC interrupts are
+ * enabled). Otherwise, an interrupt could interfere with the
+ * two-stage accessing process.
+ *
+ */
+
+
+static __inline__ void _SCCwrite(
+ struct scc_port *port,
+ unsigned char *shadow,
+ volatile unsigned char *_scc_del,
+ int regno,
+ unsigned char val, int final_delay )
+{
+ switch( regno ) {
+
+ case COMMAND_REG:
+ /* WR0 can be written directly without pointing */
+ *port->ctrlp = val;
+ break;
+
+ case SYNC_CHAR_REG:
+ /* For WR7, first set b0 of WR15 to 0, if needed */
+ if (shadow[INT_CTRL_REG] & ICR_OPTIONREG_SELECT) {
+ *port->ctrlp = 15;
+ shadow[INT_CTRL_REG] &= ~ICR_OPTIONREG_SELECT;
+ scc_reg_delay();
+ *port->ctrlp = shadow[INT_CTRL_REG];
+ scc_reg_delay();
+ }
+ goto normal_case;
+
+ case SDLC_OPTION_REG:
+ /* For WR7', first set b0 of WR15 to 1, if needed */
+ if (!(shadow[INT_CTRL_REG] & ICR_OPTIONREG_SELECT)) {
+ *port->ctrlp = 15;
+ shadow[INT_CTRL_REG] |= ICR_OPTIONREG_SELECT;
+ scc_reg_delay();
+ *port->ctrlp = shadow[INT_CTRL_REG];
+ scc_reg_delay();
+ }
+ *port->ctrlp = 7;
+ shadow[8] = val; /* WR7' shadowed at WR8 */
+ scc_reg_delay();
+ *port->ctrlp = val;
+ break;
+
+ case TX_DATA_REG: /* WR8 */
+ /* TX_DATA_REG can be accessed directly on some h/w */
+ if (MACH_IS_MVME16x || MACH_IS_BVME6000 || MACH_IS_MVME147)
+ {
+ *port->ctrlp = regno;
+ scc_reg_delay();
+ *port->ctrlp = val;
+ }
+ else
+ *port->datap = val;
+ break;
+
+ case MASTER_INT_CTRL:
+ *port->ctrlp = regno;
+ val &= 0x3f; /* bits 6..7 are the reset commands */
+ scc_shadow[0][regno] = val;
+ scc_reg_delay();
+ *port->ctrlp = val;
+ break;
+
+ case DPLL_CTRL_REG:
+ *port->ctrlp = regno;
+ val &= 0x1f; /* bits 5..7 are the DPLL commands */
+ shadow[regno] = val;
+ scc_reg_delay();
+ *port->ctrlp = val;
+ break;
+
+ case 1 ... 6:
+ case 10 ... 13:
+ case 15:
+ normal_case:
+ *port->ctrlp = regno;
+ shadow[regno] = val;
+ scc_reg_delay();
+ *port->ctrlp = val;
+ break;
+
+ default:
+ printk( "Bad SCC write access to WR%d\n", regno );
+ break;
+
+ }
+
+ if (final_delay)
+ scc_reg_delay();
+}
+
+
+static __inline__ unsigned char _SCCread(
+ struct scc_port *port,
+ unsigned char *shadow,
+ volatile unsigned char *_scc_del,
+ int regno, int final_delay )
+{
+ unsigned char rv;
+
+ switch( regno ) {
+
+ /* --- real read registers --- */
+ case STATUS_REG:
+ rv = *port->ctrlp;
+ break;
+
+ case INT_PENDING_REG:
+ /* RR3: read only from Channel A! */
+ port = port->port_a;
+ goto normal_case;
+
+ case RX_DATA_REG:
+ /* RR8 can be accessed directly on some h/w */
+ if (MACH_IS_MVME16x || MACH_IS_BVME6000 || MACH_IS_MVME147)
+ {
+ *port->ctrlp = 8;
+ scc_reg_delay();
+ rv = *port->ctrlp;
+ }
+ else
+ rv = *port->datap;
+ break;
+
+ case CURR_VECTOR_REG:
+ /* RR2 (vector including status) from Ch. B */
+ port = port->port_b;
+ goto normal_case;
+
+ /* --- reading write registers: access the shadow --- */
+ case 1 ... 7:
+ case 10 ... 15:
+ return shadow[regno]; /* no final delay! */
+
+ /* WR7' is special, because it is shadowed at the place of WR8 */
+ case SDLC_OPTION_REG:
+ return shadow[8]; /* no final delay! */
+
+ /* WR9 is special too, because it is common for both channels */
+ case MASTER_INT_CTRL:
+ return scc_shadow[0][9]; /* no final delay! */
+
+ default:
+ printk( "Bad SCC read access to %cR%d\n", (regno & 16) ? 'R' : 'W',
+ regno & ~16 );
+ break;
+
+ case SPCOND_STATUS_REG:
+ case FS_FIFO_LOW_REG:
+ case FS_FIFO_HIGH_REG:
+ case DPLL_STATUS_REG:
+ normal_case:
+ *port->ctrlp = regno & 0x0f;
+ scc_reg_delay();
+ rv = *port->ctrlp;
+ break;
+
+ }
+
+ if (final_delay)
+ scc_reg_delay();
+ return rv;
+}
+
+#define SCC_ACCESS_INIT(port) \
+ unsigned char *_scc_shadow = &scc_shadow[port->channel][0]
+
+#define SCCwrite(reg,val) _SCCwrite(port,_scc_shadow,scc_del,(reg),(val),1)
+#define SCCwrite_NB(reg,val) _SCCwrite(port,_scc_shadow,scc_del,(reg),(val),0)
+#define SCCread(reg) _SCCread(port,_scc_shadow,scc_del,(reg),1)
+#define SCCread_NB(reg) _SCCread(port,_scc_shadow,scc_del,(reg),0)
+
+#define SCCmod(reg,and,or) SCCwrite((reg),(SCCread(reg)&(and))|(or))
+
+#endif /* _SCC_H */
diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c
index 5142c8495..885b236fd 100644
--- a/drivers/char/serial167.c
+++ b/drivers/char/serial167.c
@@ -43,6 +43,7 @@
#include <linux/tty.h>
#include <linux/interrupt.h>
#include <linux/serial.h>
+#include <linux/serialP.h>
#include <linux/string.h>
#include <linux/fcntl.h>
#include <linux/ptrace.h>
@@ -57,6 +58,8 @@
#include <asm/segment.h>
#include <asm/bitops.h>
#include <asm/mvme16xhw.h>
+#include <asm/bootinfo.h>
+#include <asm/setup.h>
#include <linux/types.h>
#include <linux/kernel.h>
@@ -144,7 +147,7 @@ static struct termios *serial_termios_locked[NR_PORTS];
* memory if large numbers of serial ports are open.
*/
static unsigned char *tmp_buf = 0;
-static struct semaphore tmp_buf_sem = MUTEX;
+DECLARE_MUTEX(tmp_buf_sem);
/*
* This is used to look up the divisor speeds and the timeouts
@@ -2501,8 +2504,8 @@ scrn[1] = '\0';
info->tqueue.data = info;
info->callout_termios =cy_callout_driver.init_termios;
info->normal_termios = cy_serial_driver.init_termios;
- info->open_wait = 0;
- info->close_wait = 0;
+ init_waitqueue_head(&info->open_wait);
+ init_waitqueue_head(&info->close_wait);
/* info->session */
/* info->pgrp */
/*** !!!!!!!! this may expose new bugs !!!!!!!!! *********/
@@ -2728,7 +2731,7 @@ void console_setup(char *str, int *ints)
* that serial167_init() doesn't leave the chip non-functional.
*/
-void serial167_write(struct console *co, const char *str, unsigned count)
+void serial167_console_write(struct console *co, const char *str, unsigned count)
{
volatile unsigned char *base_addr = (u_char *)BASE_ADDR;
unsigned long flags;
@@ -2788,6 +2791,95 @@ void serial167_write(struct console *co, const char *str, unsigned count)
restore_flags(flags);
}
+/* This is a hack; if there are multiple chars waiting in the chip we
+ * discard all but the last one, and return that. The cd2401 is not really
+ * designed to be driven in polled mode.
+ */
+
+int serial167_console_wait_key(struct console *co)
+{
+ volatile unsigned char *base_addr = (u_char *)BASE_ADDR;
+ unsigned long flags;
+ volatile u_char sink;
+ u_char ier;
+ int port;
+ int keypress = 0;
+
+ save_flags(flags); cli();
+
+ /* Ensure receiver is enabled! */
+
+ port = 0;
+ base_addr[CyCAR] = (u_char)port;
+ while (base_addr[CyCCR])
+ ;
+ base_addr[CyCCR] = CyENB_RCVR;
+ ier = base_addr[CyIER];
+ base_addr[CyIER] = CyRxData;
+
+ while (!keypress) {
+ if (pcc2chip[PccSCCRICR] & 0x20)
+ {
+ /* We have an Rx int. Acknowledge it */
+ sink = pcc2chip[PccRPIACKR];
+ if ((base_addr[CyLICR] >> 2) == port) {
+ int cnt = base_addr[CyRFOC];
+ while (cnt-- > 0)
+ {
+ keypress = base_addr[CyRDR];
+ }
+ base_addr[CyREOIR] = 0;
+ }
+ else
+ base_addr[CyREOIR] = CyNOTRANS;
+ }
+ }
+
+ base_addr[CyIER] = ier;
+
+ restore_flags(flags);
+
+ return keypress;
+}
+
+
+static kdev_t serial167_console_device(struct console *c)
+{
+ return MKDEV(TTY_MAJOR, 64 + c->index);
+}
+
+
+static int __init serial167_console_setup(struct console *co, char *options)
+{
+ return 0;
+}
+
+
+static struct console sercons = {
+ "ttyS",
+ serial167_console_write,
+ NULL,
+ serial167_console_device,
+ serial167_console_wait_key,
+ NULL,
+ serial167_console_setup,
+ CON_PRINTBUFFER,
+ -1,
+ 0,
+ NULL
+};
+
+
+void __init serial167_console_init(void)
+{
+ if (vme_brdtype == VME_TYPE_MVME166 ||
+ vme_brdtype == VME_TYPE_MVME167 ||
+ vme_brdtype == VME_TYPE_MVME177) {
+ mvme167_serial_console_setup(0);
+ register_console(&sercons);
+ }
+}
+
#ifdef CONFIG_REMOTE_DEBUG
void putDebugChar (int c)
{
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index c726f745c..b4194bb9b 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -128,6 +128,14 @@ static int tty_fasync(int fd, struct file * filp, int on);
#ifdef CONFIG_SX
extern int sx_init (void);
#endif
+#if defined(CONFIG_MVME162_SCC) || defined(CONFIG_BVME6000_SCC) || defined(CONFIG_MVME147_SCC)
+extern int vme_scc_init (void);
+extern long vme_scc_console_init(void);
+#endif
+#ifdef CONFIG_SERIAL167
+extern int serial167_init(void);
+extern long serial167_console_init(void);
+#endif
#ifdef CONFIG_8xx
extern console_8xx_init(void);
extern int rs_8xx_init(void);
@@ -2090,9 +2098,15 @@ void __init console_init(void)
#ifdef CONFIG_SERIAL_CONSOLE
#ifdef CONFIG_8xx
console_8xx_init();
-#else
+#elif defined(CONFIG_SERIAL)
serial_console_init();
#endif /* CONFIG_8xx */
+#if defined(CONFIG_MVME162_SCC) || defined(CONFIG_BVME6000_SCC) || defined(CONFIG_MVME147_SCC)
+ vme_scc_console_init();
+#endif
+#if defined(CONFIG_SERIAL167)
+ serial167_console_init();
+#endif
#endif
}
@@ -2176,6 +2190,9 @@ void __init tty_init(void)
#ifdef CONFIG_SERIAL
rs_init();
#endif
+#if defined(CONFIG_MVME162_SCC) || defined(CONFIG_BVME6000_SCC) || defined(CONFIG_MVME147_SCC)
+ vme_scc_init();
+#endif
#ifdef CONFIG_COMPUTONE
ip2_init();
#endif
@@ -2185,7 +2202,7 @@ void __init tty_init(void)
#ifdef CONFIG_ROCKETPORT
rp_init();
#endif
-#ifdef CONFIG_MVME16x
+#ifdef CONFIG_SERIAL167
serial167_init();
#endif
#ifdef CONFIG_CYCLADES
diff --git a/drivers/char/vme_scc.c b/drivers/char/vme_scc.c
new file mode 100644
index 000000000..15232f832
--- /dev/null
+++ b/drivers/char/vme_scc.c
@@ -0,0 +1,1136 @@
+/*
+ * drivers/char/vme_scc.c: MVME147, MVME162, BVME6000 SCC serial ports
+ * implementation.
+ * Copyright 1999 Richard Hirst <richard@sleepie.demon.co.uk>
+ *
+ * Based on atari_SCC.c which was
+ * Copyright 1994-95 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
+ * Partially based on PC-Linux serial.c by Linus Torvalds and Theodore Ts'o
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive
+ * for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/kdev_t.h>
+#include <asm/io.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/mm.h>
+#include <linux/serial.h>
+#include <linux/fcntl.h>
+#include <linux/major.h>
+#include <linux/delay.h>
+#include <linux/tqueue.h>
+#include <linux/version.h>
+#include <linux/malloc.h>
+#include <linux/miscdevice.h>
+#include <linux/console.h>
+#include <linux/init.h>
+#include <asm/setup.h>
+#include <asm/bootinfo.h>
+
+#ifdef CONFIG_MVME147_SCC
+#include <asm/mvme147hw.h>
+#endif
+#ifdef CONFIG_MVME162_SCC
+#include <asm/mvme16xhw.h>
+#endif
+#ifdef CONFIG_BVME6000_SCC
+#include <asm/bvme6000hw.h>
+#endif
+
+#include "generic_serial.h"
+#include "scc.h"
+
+
+#define CHANNEL_A 0
+#define CHANNEL_B 1
+
+#define SCC_MINOR_BASE 64
+
+/* Shadows for all SCC write registers */
+static unsigned char scc_shadow[2][16];
+
+/* Location to access for SCC register access delay */
+static volatile unsigned char *scc_del = NULL;
+
+/* To keep track of STATUS_REG state for detection of Ext/Status int source */
+static unsigned char scc_last_status_reg[2];
+
+/***************************** Prototypes *****************************/
+
+/* Function prototypes */
+static void scc_disable_tx_interrupts(void * ptr);
+static void scc_enable_tx_interrupts(void * ptr);
+static void scc_disable_rx_interrupts(void * ptr);
+static void scc_enable_rx_interrupts(void * ptr);
+static int scc_get_CD(void * ptr);
+static void scc_shutdown_port(void * ptr);
+static void scc_set_real_termios(void *ptr);
+static void scc_hungup(void *ptr);
+static void scc_close(void *ptr);
+static int scc_chars_in_buffer(void * ptr);
+static int scc_open(struct tty_struct * tty, struct file * filp);
+static int scc_ioctl(struct tty_struct * tty, struct file * filp,
+ unsigned int cmd, unsigned long arg);
+static void scc_throttle(struct tty_struct *tty);
+static void scc_unthrottle(struct tty_struct *tty);
+static void scc_tx_int(int irq, void *data, struct pt_regs *fp);
+static void scc_rx_int(int irq, void *data, struct pt_regs *fp);
+static void scc_stat_int(int irq, void *data, struct pt_regs *fp);
+static void scc_spcond_int(int irq, void *data, struct pt_regs *fp);
+static void scc_setsignals(struct scc_port *port, int dtr, int rts);
+static void scc_break_ctl(struct tty_struct *tty, int break_state);
+
+static struct tty_driver scc_driver, scc_callout_driver;
+
+static struct tty_struct *scc_table[2] = { NULL, };
+static struct termios * scc_termios[2];
+static struct termios * scc_termios_locked[2];
+struct scc_port scc_ports[2];
+
+int scc_refcount;
+int scc_initialized = 0;
+
+/*---------------------------------------------------------------------------
+ * Interface from generic_serial.c back here
+ *--------------------------------------------------------------------------*/
+
+static struct real_driver scc_real_driver = {
+ scc_disable_tx_interrupts,
+ scc_enable_tx_interrupts,
+ scc_disable_rx_interrupts,
+ scc_enable_rx_interrupts,
+ scc_get_CD,
+ scc_shutdown_port,
+ scc_set_real_termios,
+ scc_chars_in_buffer,
+ scc_close,
+ scc_hungup,
+ NULL
+};
+
+
+/*----------------------------------------------------------------------------
+ * vme_scc_init() and support functions
+ *---------------------------------------------------------------------------*/
+
+static int scc_init_drivers(void)
+{
+ int error;
+
+ memset(&scc_driver, 0, sizeof(scc_driver));
+ scc_driver.magic = TTY_DRIVER_MAGIC;
+ scc_driver.driver_name = "scc";
+ scc_driver.name = "ttyS";
+ scc_driver.major = TTY_MAJOR;
+ scc_driver.minor_start = SCC_MINOR_BASE;
+ scc_driver.num = 2;
+ scc_driver.type = TTY_DRIVER_TYPE_SERIAL;
+ scc_driver.subtype = SERIAL_TYPE_NORMAL;
+ scc_driver.init_termios = tty_std_termios;
+ scc_driver.init_termios.c_cflag =
+ B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ scc_driver.flags = TTY_DRIVER_REAL_RAW;
+ scc_driver.refcount = &scc_refcount;
+ scc_driver.table = scc_table;
+ scc_driver.termios = scc_termios;
+ scc_driver.termios_locked = scc_termios_locked;
+
+ scc_driver.open = scc_open;
+ scc_driver.close = gs_close;
+ scc_driver.write = gs_write;
+ scc_driver.put_char = gs_put_char;
+ scc_driver.flush_chars = gs_flush_chars;
+ scc_driver.write_room = gs_write_room;
+ scc_driver.chars_in_buffer = gs_chars_in_buffer;
+ scc_driver.flush_buffer = gs_flush_buffer;
+ scc_driver.ioctl = scc_ioctl;
+ scc_driver.throttle = scc_throttle;
+ scc_driver.unthrottle = scc_unthrottle;
+ scc_driver.set_termios = gs_set_termios;
+ scc_driver.stop = gs_stop;
+ scc_driver.start = gs_start;
+ scc_driver.hangup = gs_hangup;
+ scc_driver.break_ctl = scc_break_ctl;
+
+ scc_callout_driver = scc_driver;
+ scc_callout_driver.name = "cua";
+ scc_callout_driver.major = TTYAUX_MAJOR;
+ scc_callout_driver.subtype = SERIAL_TYPE_CALLOUT;
+
+ if ((error = tty_register_driver(&scc_driver))) {
+ printk(KERN_ERR "scc: Couldn't register scc driver, error = %d\n",
+ error);
+ return 1;
+ }
+ if ((error = tty_register_driver(&scc_callout_driver))) {
+ tty_unregister_driver(&scc_driver);
+ printk(KERN_ERR "scc: Couldn't register scc callout driver, error = %d\n",
+ error);
+ return 1;
+ }
+
+ return 0;
+}
+
+
+/* ports[] array is indexed by line no (i.e. [0] for ttyS0, [1] for ttyS1).
+ */
+
+static void scc_init_portstructs(void)
+{
+ struct scc_port *port;
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ port = scc_ports + i;
+ port->gs.callout_termios = tty_std_termios;
+ port->gs.normal_termios = tty_std_termios;
+ port->gs.magic = SCC_MAGIC;
+ port->gs.close_delay = HZ/2;
+ port->gs.closing_wait = 30 * HZ;
+ port->gs.rd = &scc_real_driver;
+#ifdef NEW_WRITE_LOCKING
+ port->gs.port_write_sem = MUTEX;
+#endif
+ init_waitqueue_head(&port->gs.open_wait);
+ init_waitqueue_head(&port->gs.close_wait);
+ }
+}
+
+
+#ifdef CONFIG_MVME147_SCC
+static int mvme147_scc_init(void)
+{
+ struct scc_port *port;
+
+ printk("SCC: MVME147 Serial Driver\n");
+ /* Init channel A */
+ port = &scc_ports[0];
+ port->channel = CHANNEL_A;
+ port->ctrlp = (volatile unsigned char *)M147_SCC_A_ADDR;
+ port->datap = port->ctrlp + 1;
+ port->port_a = &scc_ports[0];
+ port->port_b = &scc_ports[1];
+ request_irq(MVME147_IRQ_SCCA_TX, scc_tx_int, SA_INTERRUPT,
+ "SCC-A TX", port);
+ request_irq(MVME147_IRQ_SCCA_STAT, scc_stat_int, SA_INTERRUPT,
+ "SCC-A status", port);
+ request_irq(MVME147_IRQ_SCCA_RX, scc_rx_int, SA_INTERRUPT,
+ "SCC-A RX", port);
+ request_irq(MVME147_IRQ_SCCA_SPCOND, scc_spcond_int, SA_INTERRUPT,
+ "SCC-A special cond", port);
+ {
+ SCC_ACCESS_INIT(port);
+
+ /* disable interrupts for this channel */
+ SCCwrite(INT_AND_DMA_REG, 0);
+ /* Set the interrupt vector */
+ SCCwrite(INT_VECTOR_REG, MVME147_IRQ_SCC_BASE);
+ /* Interrupt parameters: vector includes status, status low */
+ SCCwrite(MASTER_INT_CTRL, MIC_VEC_INCL_STAT);
+ SCCmod(MASTER_INT_CTRL, 0xff, MIC_MASTER_INT_ENAB);
+ }
+
+ /* Init channel B */
+ port = &scc_ports[1];
+ port->channel = CHANNEL_B;
+ port->ctrlp = (volatile unsigned char *)M147_SCC_B_ADDR;
+ port->datap = port->ctrlp + 1;
+ port->port_a = &scc_ports[0];
+ port->port_b = &scc_ports[1];
+ request_irq(MVME147_IRQ_SCCB_TX, scc_tx_int, SA_INTERRUPT,
+ "SCC-B TX", port);
+ request_irq(MVME147_IRQ_SCCB_STAT, scc_stat_int, SA_INTERRUPT,
+ "SCC-B status", port);
+ request_irq(MVME147_IRQ_SCCB_RX, scc_rx_int, SA_INTERRUPT,
+ "SCC-B RX", port);
+ request_irq(MVME147_IRQ_SCCB_SPCOND, scc_spcond_int, SA_INTERRUPT,
+ "SCC-B special cond", port);
+ {
+ SCC_ACCESS_INIT(port);
+
+ /* disable interrupts for this channel */
+ SCCwrite(INT_AND_DMA_REG, 0);
+ }
+
+ /* Ensure interrupts are enabled in the PCC chip */
+ m147_pcc->serial_cntrl=PCC_LEVEL_SERIAL|PCC_INT_ENAB;
+
+ /* Initialise the tty driver structures and register */
+ scc_init_portstructs();
+ scc_init_drivers();
+
+ return 0;
+}
+#endif
+
+
+#ifdef CONFIG_MVME162_SCC
+static int mvme162_scc_init(void)
+{
+ struct scc_port *port;
+
+ if (!(mvme16x_config & MVME16x_CONFIG_GOT_SCCA))
+ return (-ENODEV);
+
+ printk("SCC: MVME162 Serial Driver\n");
+ /* Init channel A */
+ port = &scc_ports[0];
+ port->channel = CHANNEL_A;
+ port->ctrlp = (volatile unsigned char *)MVME_SCC_A_ADDR;
+ port->datap = port->ctrlp + 2;
+ port->port_a = &scc_ports[0];
+ port->port_b = &scc_ports[1];
+ request_irq(MVME162_IRQ_SCCA_TX, scc_tx_int, SA_INTERRUPT,
+ "SCC-A TX", port);
+ request_irq(MVME162_IRQ_SCCA_STAT, scc_stat_int, SA_INTERRUPT,
+ "SCC-A status", port);
+ request_irq(MVME162_IRQ_SCCA_RX, scc_rx_int, SA_INTERRUPT,
+ "SCC-A RX", port);
+ request_irq(MVME162_IRQ_SCCA_SPCOND, scc_spcond_int, SA_INTERRUPT,
+ "SCC-A special cond", port);
+ {
+ SCC_ACCESS_INIT(port);
+
+ /* disable interrupts for this channel */
+ SCCwrite(INT_AND_DMA_REG, 0);
+ /* Set the interrupt vector */
+ SCCwrite(INT_VECTOR_REG, MVME162_IRQ_SCC_BASE);
+ /* Interrupt parameters: vector includes status, status low */
+ SCCwrite(MASTER_INT_CTRL, MIC_VEC_INCL_STAT);
+ SCCmod(MASTER_INT_CTRL, 0xff, MIC_MASTER_INT_ENAB);
+ }
+
+ /* Init channel B */
+ port = &scc_ports[1];
+ port->channel = CHANNEL_B;
+ port->ctrlp = (volatile unsigned char *)MVME_SCC_B_ADDR;
+ port->datap = port->ctrlp + 2;
+ port->port_a = &scc_ports[0];
+ port->port_b = &scc_ports[1];
+ request_irq(MVME162_IRQ_SCCB_TX, scc_tx_int, SA_INTERRUPT,
+ "SCC-B TX", port);
+ request_irq(MVME162_IRQ_SCCB_STAT, scc_stat_int, SA_INTERRUPT,
+ "SCC-B status", port);
+ request_irq(MVME162_IRQ_SCCB_RX, scc_rx_int, SA_INTERRUPT,
+ "SCC-B RX", port);
+ request_irq(MVME162_IRQ_SCCB_SPCOND, scc_spcond_int, SA_INTERRUPT,
+ "SCC-B special cond", port);
+
+ {
+ SCC_ACCESS_INIT(port); /* Either channel will do */
+
+ /* disable interrupts for this channel */
+ SCCwrite(INT_AND_DMA_REG, 0);
+ }
+
+ /* Ensure interrupts are enabled in the MC2 chip */
+ *(volatile char *)0xfff4201d = 0x14;
+
+ /* Initialise the tty driver structures and register */
+ scc_init_portstructs();
+ scc_init_drivers();
+
+ return 0;
+}
+#endif
+
+
+#ifdef CONFIG_BVME6000_SCC
+static int bvme6000_scc_init(void)
+{
+ struct scc_port *port;
+
+ printk("SCC: BVME6000 Serial Driver\n");
+ /* Init channel A */
+ port = &scc_ports[0];
+ port->channel = CHANNEL_A;
+ port->ctrlp = (volatile unsigned char *)BVME_SCC_A_ADDR;
+ port->datap = port->ctrlp + 4;
+ port->port_a = &scc_ports[0];
+ port->port_b = &scc_ports[1];
+ request_irq(BVME_IRQ_SCCA_TX, scc_tx_int, SA_INTERRUPT,
+ "SCC-A TX", port);
+ request_irq(BVME_IRQ_SCCA_STAT, scc_stat_int, SA_INTERRUPT,
+ "SCC-A status", port);
+ request_irq(BVME_IRQ_SCCA_RX, scc_rx_int, SA_INTERRUPT,
+ "SCC-A RX", port);
+ request_irq(BVME_IRQ_SCCA_SPCOND, scc_spcond_int, SA_INTERRUPT,
+ "SCC-A special cond", port);
+ {
+ SCC_ACCESS_INIT(port);
+
+ /* disable interrupts for this channel */
+ SCCwrite(INT_AND_DMA_REG, 0);
+ /* Set the interrupt vector */
+ SCCwrite(INT_VECTOR_REG, BVME_IRQ_SCC_BASE);
+ /* Interrupt parameters: vector includes status, status low */
+ SCCwrite(MASTER_INT_CTRL, MIC_VEC_INCL_STAT);
+ SCCmod(MASTER_INT_CTRL, 0xff, MIC_MASTER_INT_ENAB);
+ }
+
+ /* Init channel B */
+ port = &scc_ports[1];
+ port->channel = CHANNEL_B;
+ port->ctrlp = (volatile unsigned char *)BVME_SCC_B_ADDR;
+ port->datap = port->ctrlp + 4;
+ port->port_a = &scc_ports[0];
+ port->port_b = &scc_ports[1];
+ request_irq(BVME_IRQ_SCCB_TX, scc_tx_int, SA_INTERRUPT,
+ "SCC-B TX", port);
+ request_irq(BVME_IRQ_SCCB_STAT, scc_stat_int, SA_INTERRUPT,
+ "SCC-B status", port);
+ request_irq(BVME_IRQ_SCCB_RX, scc_rx_int, SA_INTERRUPT,
+ "SCC-B RX", port);
+ request_irq(BVME_IRQ_SCCB_SPCOND, scc_spcond_int, SA_INTERRUPT,
+ "SCC-B special cond", port);
+
+ {
+ SCC_ACCESS_INIT(port); /* Either channel will do */
+
+ /* disable interrupts for this channel */
+ SCCwrite(INT_AND_DMA_REG, 0);
+ }
+
+ /* Initialise the tty driver structures and register */
+ scc_init_portstructs();
+ scc_init_drivers();
+
+ return 0;
+}
+#endif
+
+
+int vme_scc_init(void)
+{
+ int res = -ENODEV;
+ static int called = 0;
+
+ if (called)
+ return res;
+ called = 1;
+#ifdef CONFIG_MVME147_SCC
+ if (MACH_IS_MVME147)
+ res = mvme147_scc_init();
+#endif
+#ifdef CONFIG_MVME162_SCC
+ if (MACH_IS_MVME16x)
+ res = mvme162_scc_init();
+#endif
+#ifdef CONFIG_BVME6000_SCC
+ if (MACH_IS_BVME6000)
+ res = bvme6000_scc_init();
+#endif
+ return res;
+}
+
+
+/*---------------------------------------------------------------------------
+ * Interrupt handlers
+ *--------------------------------------------------------------------------*/
+
+static void scc_rx_int(int irq, void *data, struct pt_regs *fp)
+{
+ unsigned char ch;
+ struct scc_port *port = data;
+ struct tty_struct *tty = port->gs.tty;
+ SCC_ACCESS_INIT(port);
+
+ ch = SCCread_NB(RX_DATA_REG);
+ if (!tty) {
+ printk ("scc_rx_int with NULL tty!\n");
+ SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET);
+ return;
+ }
+ if (tty->flip.count < TTY_FLIPBUF_SIZE) {
+ *tty->flip.char_buf_ptr = ch;
+ *tty->flip.flag_buf_ptr = 0;
+ tty->flip.flag_buf_ptr++;
+ tty->flip.char_buf_ptr++;
+ tty->flip.count++;
+ }
+
+ /* Check if another character is already ready; in that case, the
+ * spcond_int() function must be used, because this character may have an
+ * error condition that isn't signalled by the interrupt vector used!
+ */
+ if (SCCread(INT_PENDING_REG) &
+ (port->channel == CHANNEL_A ? IPR_A_RX : IPR_B_RX)) {
+ scc_spcond_int (irq, data, fp);
+ return;
+ }
+
+ SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET);
+
+ tty_flip_buffer_push(tty);
+}
+
+
+static void scc_spcond_int(int irq, void *data, struct pt_regs *fp)
+{
+ struct scc_port *port = data;
+ struct tty_struct *tty = port->gs.tty;
+ unsigned char stat, ch, err;
+ int int_pending_mask = port->channel == CHANNEL_A ?
+ IPR_A_RX : IPR_B_RX;
+ SCC_ACCESS_INIT(port);
+
+ if (!tty) {
+ printk ("scc_spcond_int with NULL tty!\n");
+ SCCwrite(COMMAND_REG, CR_ERROR_RESET);
+ SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET);
+ return;
+ }
+ do {
+ stat = SCCread(SPCOND_STATUS_REG);
+ ch = SCCread_NB(RX_DATA_REG);
+
+ if (stat & SCSR_RX_OVERRUN)
+ err = TTY_OVERRUN;
+ else if (stat & SCSR_PARITY_ERR)
+ err = TTY_PARITY;
+ else if (stat & SCSR_CRC_FRAME_ERR)
+ err = TTY_FRAME;
+ else
+ err = 0;
+
+ if (tty->flip.count < TTY_FLIPBUF_SIZE) {
+ *tty->flip.char_buf_ptr = ch;
+ *tty->flip.flag_buf_ptr = err;
+ tty->flip.flag_buf_ptr++;
+ tty->flip.char_buf_ptr++;
+ tty->flip.count++;
+ }
+
+ /* ++TeSche: *All* errors have to be cleared manually,
+ * else the condition persists for the next chars
+ */
+ if (err)
+ SCCwrite(COMMAND_REG, CR_ERROR_RESET);
+
+ } while(SCCread(INT_PENDING_REG) & int_pending_mask);
+
+ SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET);
+
+ tty_flip_buffer_push(tty);
+}
+
+
+static void scc_tx_int(int irq, void *data, struct pt_regs *fp)
+{
+ struct scc_port *port = data;
+ SCC_ACCESS_INIT(port);
+
+ if (!port->gs.tty) {
+ printk ("scc_tx_int with NULL tty!\n");
+ SCCmod (INT_AND_DMA_REG, ~IDR_TX_INT_ENAB, 0);
+ SCCwrite(COMMAND_REG, CR_TX_PENDING_RESET);
+ SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET);
+ return;
+ }
+ while ((SCCread_NB(STATUS_REG) & SR_TX_BUF_EMPTY)) {
+ if (port->x_char) {
+ SCCwrite(TX_DATA_REG, port->x_char);
+ port->x_char = 0;
+ }
+ else if ((port->gs.xmit_cnt <= 0) || port->gs.tty->stopped ||
+ port->gs.tty->hw_stopped)
+ break;
+ else {
+ SCCwrite(TX_DATA_REG, port->gs.xmit_buf[port->gs.xmit_tail++]);
+ port->gs.xmit_tail = port->gs.xmit_tail & (SERIAL_XMIT_SIZE-1);
+ if (--port->gs.xmit_cnt <= 0)
+ break;
+ }
+ }
+ if ((port->gs.xmit_cnt <= 0) || port->gs.tty->stopped ||
+ port->gs.tty->hw_stopped) {
+ /* disable tx interrupts */
+ SCCmod (INT_AND_DMA_REG, ~IDR_TX_INT_ENAB, 0);
+ SCCwrite(COMMAND_REG, CR_TX_PENDING_RESET); /* disable tx_int on next tx underrun? */
+ port->gs.flags &= ~GS_TX_INTEN;
+ }
+ if (port->gs.tty && port->gs.xmit_cnt <= port->gs.wakeup_chars) {
+ if ((port->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+ port->gs.tty->ldisc.write_wakeup)
+ (port->gs.tty->ldisc.write_wakeup)(port->gs.tty);
+ wake_up_interruptible(&port->gs.tty->write_wait);
+ }
+
+ SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET);
+}
+
+
+static void scc_stat_int(int irq, void *data, struct pt_regs *fp)
+{
+ struct scc_port *port = data;
+ unsigned channel = port->channel;
+ unsigned char last_sr, sr, changed;
+ SCC_ACCESS_INIT(port);
+
+ last_sr = scc_last_status_reg[channel];
+ sr = scc_last_status_reg[channel] = SCCread_NB(STATUS_REG);
+ changed = last_sr ^ sr;
+
+ if (changed & SR_DCD) {
+ port->c_dcd = !!(sr & SR_DCD);
+ if (!(port->gs.flags & ASYNC_CHECK_CD))
+ ; /* Don't report DCD changes */
+ else if (port->c_dcd) {
+ if (~(port->gs.flags & ASYNC_NORMAL_ACTIVE) ||
+ ~(port->gs.flags & ASYNC_CALLOUT_ACTIVE)) {
+ /* Are we blocking in open?*/
+ wake_up_interruptible(&port->gs.open_wait);
+ }
+ }
+ else {
+ if (!((port->gs.flags & ASYNC_CALLOUT_ACTIVE) &&
+ (port->gs.flags & ASYNC_CALLOUT_NOHUP))) {
+ if (port->gs.tty)
+ tty_hangup (port->gs.tty);
+ }
+ }
+ }
+ SCCwrite(COMMAND_REG, CR_EXTSTAT_RESET);
+ SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET);
+}
+
+
+/*---------------------------------------------------------------------------
+ * generic_serial.c callback funtions
+ *--------------------------------------------------------------------------*/
+
+static void scc_disable_tx_interrupts(void *ptr)
+{
+ struct scc_port *port = ptr;
+ unsigned long flags;
+ SCC_ACCESS_INIT(port);
+
+ save_flags(flags);
+ cli();
+ SCCmod(INT_AND_DMA_REG, ~IDR_TX_INT_ENAB, 0);
+ port->gs.flags &= ~GS_TX_INTEN;
+ restore_flags(flags);
+}
+
+
+static void scc_enable_tx_interrupts(void *ptr)
+{
+ struct scc_port *port = ptr;
+ unsigned long flags;
+ SCC_ACCESS_INIT(port);
+
+ save_flags(flags);
+ cli();
+ SCCmod(INT_AND_DMA_REG, 0xff, IDR_TX_INT_ENAB);
+ /* restart the transmitter */
+ scc_tx_int (0, port, 0);
+ restore_flags(flags);
+}
+
+
+static void scc_disable_rx_interrupts(void *ptr)
+{
+ struct scc_port *port = ptr;
+ unsigned long flags;
+ SCC_ACCESS_INIT(port);
+
+ save_flags(flags);
+ cli();
+ SCCmod(INT_AND_DMA_REG,
+ ~(IDR_RX_INT_MASK|IDR_PARERR_AS_SPCOND|IDR_EXTSTAT_INT_ENAB), 0);
+ restore_flags(flags);
+}
+
+
+static void scc_enable_rx_interrupts(void *ptr)
+{
+ struct scc_port *port = ptr;
+ unsigned long flags;
+ SCC_ACCESS_INIT(port);
+
+ save_flags(flags);
+ cli();
+ SCCmod(INT_AND_DMA_REG, 0xff,
+ IDR_EXTSTAT_INT_ENAB|IDR_PARERR_AS_SPCOND|IDR_RX_INT_ALL);
+ restore_flags(flags);
+}
+
+
+static int scc_get_CD(void *ptr)
+{
+ struct scc_port *port = ptr;
+ unsigned channel = port->channel;
+
+ return !!(scc_last_status_reg[channel] & SR_DCD);
+}
+
+
+static void scc_shutdown_port(void *ptr)
+{
+ struct scc_port *port = ptr;
+
+ port->gs.flags &= ~ GS_ACTIVE;
+ if (port->gs.tty && port->gs.tty->termios->c_cflag & HUPCL) {
+ scc_setsignals (port, 0, 0);
+ }
+}
+
+
+static void scc_set_real_termios (void *ptr)
+{
+ /* the SCC has char sizes 5,7,6,8 in that order! */
+ static int chsize_map[4] = { 0, 2, 1, 3 };
+ unsigned cflag, baud, chsize, channel, brgval = 0;
+ unsigned long flags;
+ struct scc_port *port = ptr;
+ SCC_ACCESS_INIT(port);
+
+ if (!port->gs.tty || !port->gs.tty->termios) return;
+
+ channel = port->channel;
+
+ if (channel == CHANNEL_A)
+ return; /* Settings controlled by boot PROM */
+
+ cflag = port->gs.tty->termios->c_cflag;
+ baud = port->gs.baud;
+ chsize = (cflag & CSIZE) >> 4;
+
+ if (baud == 0) {
+ /* speed == 0 -> drop DTR */
+ save_flags(flags);
+ cli();
+ SCCmod(TX_CTRL_REG, ~TCR_DTR, 0);
+ restore_flags(flags);
+ return;
+ }
+ else if ((MACH_IS_MVME16x && (baud < 50 || baud > 38400)) ||
+ (MACH_IS_MVME147 && (baud < 50 || baud > 19200)) ||
+ (MACH_IS_BVME6000 &&(baud < 50 || baud > 76800))) {
+ printk("SCC: Bad speed requested, %d\n", baud);
+ return;
+ }
+
+ if (cflag & CLOCAL)
+ port->gs.flags &= ~ASYNC_CHECK_CD;
+ else
+ port->gs.flags |= ASYNC_CHECK_CD;
+
+#ifdef CONFIG_MVME147_SCC
+ if (MACH_IS_MVME147)
+ brgval = (M147_SCC_PCLK + baud/2) / (16 * 2 * baud) - 2;
+ else
+#endif
+#ifdef CONFIG_MVME162_SCC
+ if (MACH_IS_MVME16x)
+ brgval = (MVME_SCC_PCLK + baud/2) / (16 * 2 * baud) - 2;
+ else
+#endif
+#ifdef CONFIG_BVME6000_SCC
+ if (MACH_IS_BVME6000)
+ brgval = (BVME_SCC_RTxC + baud/2) / (16 * 2 * baud) - 2;
+#endif
+ /* Now we have all parameters and can go to set them: */
+ save_flags(flags);
+ cli();
+
+ /* receiver's character size and auto-enables */
+ SCCmod(RX_CTRL_REG, ~(RCR_CHSIZE_MASK|RCR_AUTO_ENAB_MODE),
+ (chsize_map[chsize] << 6) |
+ ((cflag & CRTSCTS) ? RCR_AUTO_ENAB_MODE : 0));
+ /* parity and stop bits (both, Tx and Rx), clock mode never changes */
+ SCCmod (AUX1_CTRL_REG,
+ ~(A1CR_PARITY_MASK | A1CR_MODE_MASK),
+ ((cflag & PARENB
+ ? (cflag & PARODD ? A1CR_PARITY_ODD : A1CR_PARITY_EVEN)
+ : A1CR_PARITY_NONE)
+ | (cflag & CSTOPB ? A1CR_MODE_ASYNC_2 : A1CR_MODE_ASYNC_1)));
+ /* sender's character size, set DTR for valid baud rate */
+ SCCmod(TX_CTRL_REG, ~TCR_CHSIZE_MASK, chsize_map[chsize] << 5 | TCR_DTR);
+ /* clock sources never change */
+ /* disable BRG before changing the value */
+ SCCmod(DPLL_CTRL_REG, ~DCR_BRG_ENAB, 0);
+ /* BRG value */
+ SCCwrite(TIMER_LOW_REG, brgval & 0xff);
+ SCCwrite(TIMER_HIGH_REG, (brgval >> 8) & 0xff);
+ /* BRG enable, and clock source never changes */
+ SCCmod(DPLL_CTRL_REG, 0xff, DCR_BRG_ENAB);
+
+ restore_flags(flags);
+}
+
+
+static int scc_chars_in_buffer (void *ptr)
+{
+ struct scc_port *port = ptr;
+ SCC_ACCESS_INIT(port);
+
+ return (SCCread (SPCOND_STATUS_REG) & SCSR_ALL_SENT) ? 0 : 1;
+}
+
+
+static void scc_hungup(void *ptr)
+{
+ scc_disable_tx_interrupts(ptr);
+ scc_disable_rx_interrupts(ptr);
+ MOD_DEC_USE_COUNT;
+}
+
+
+static void scc_close(void *ptr)
+{
+ scc_disable_tx_interrupts(ptr);
+ scc_disable_rx_interrupts(ptr);
+}
+
+
+/*---------------------------------------------------------------------------
+ * Internal support functions
+ *--------------------------------------------------------------------------*/
+
+static void scc_setsignals(struct scc_port *port, int dtr, int rts)
+{
+ unsigned long flags;
+ unsigned char t;
+ SCC_ACCESS_INIT(port);
+
+ save_flags(flags);
+ t = SCCread(TX_CTRL_REG);
+ if (dtr >= 0) t = dtr? (t | TCR_DTR): (t & ~TCR_DTR);
+ if (rts >= 0) t = rts? (t | TCR_RTS): (t & ~TCR_RTS);
+ SCCwrite(TX_CTRL_REG, t);
+ restore_flags(flags);
+}
+
+
+static void scc_send_xchar(struct tty_struct *tty, char ch)
+{
+ struct scc_port *port = (struct scc_port *)tty->driver_data;
+
+ port->x_char = ch;
+ if (ch)
+ scc_enable_tx_interrupts(port);
+}
+
+
+/*---------------------------------------------------------------------------
+ * Driver entrypoints referenced from above
+ *--------------------------------------------------------------------------*/
+
+static int scc_open (struct tty_struct * tty, struct file * filp)
+{
+ int line = MINOR(tty->device) - SCC_MINOR_BASE;
+ int retval;
+ struct scc_port *port = &scc_ports[line];
+ int i, channel = port->channel;
+ unsigned long flags;
+ SCC_ACCESS_INIT(port);
+#if defined(CONFIG_MVME162_SCC) || defined(CONFIG_MVME147_SCC)
+ static const struct {
+ unsigned reg, val;
+ } mvme_init_tab[] = {
+ /* Values for MVME162 and MVME147 */
+ /* no parity, 1 stop bit, async, 1:16 */
+ { AUX1_CTRL_REG, A1CR_PARITY_NONE|A1CR_MODE_ASYNC_1|A1CR_CLKMODE_x16 },
+ /* parity error is special cond, ints disabled, no DMA */
+ { INT_AND_DMA_REG, IDR_PARERR_AS_SPCOND | IDR_RX_INT_DISAB },
+ /* Rx 8 bits/char, no auto enable, Rx off */
+ { RX_CTRL_REG, RCR_CHSIZE_8 },
+ /* DTR off, Tx 8 bits/char, RTS off, Tx off */
+ { TX_CTRL_REG, TCR_CHSIZE_8 },
+ /* special features off */
+ { AUX2_CTRL_REG, 0 },
+ { CLK_CTRL_REG, CCR_RXCLK_BRG | CCR_TXCLK_BRG },
+ { DPLL_CTRL_REG, DCR_BRG_ENAB | DCR_BRG_USE_PCLK },
+ /* Start Rx */
+ { RX_CTRL_REG, RCR_RX_ENAB | RCR_CHSIZE_8 },
+ /* Start Tx */
+ { TX_CTRL_REG, TCR_TX_ENAB | TCR_RTS | TCR_DTR | TCR_CHSIZE_8 },
+ /* Ext/Stat ints: DCD only */
+ { INT_CTRL_REG, ICR_ENAB_DCD_INT },
+ /* Reset Ext/Stat ints */
+ { COMMAND_REG, CR_EXTSTAT_RESET },
+ /* ...again */
+ { COMMAND_REG, CR_EXTSTAT_RESET },
+ };
+#endif
+#if defined(CONFIG_BVME6000_SCC)
+ static const struct {
+ unsigned reg, val;
+ } bvme_init_tab[] = {
+ /* Values for BVME6000 */
+ /* no parity, 1 stop bit, async, 1:16 */
+ { AUX1_CTRL_REG, A1CR_PARITY_NONE|A1CR_MODE_ASYNC_1|A1CR_CLKMODE_x16 },
+ /* parity error is special cond, ints disabled, no DMA */
+ { INT_AND_DMA_REG, IDR_PARERR_AS_SPCOND | IDR_RX_INT_DISAB },
+ /* Rx 8 bits/char, no auto enable, Rx off */
+ { RX_CTRL_REG, RCR_CHSIZE_8 },
+ /* DTR off, Tx 8 bits/char, RTS off, Tx off */
+ { TX_CTRL_REG, TCR_CHSIZE_8 },
+ /* special features off */
+ { AUX2_CTRL_REG, 0 },
+ { CLK_CTRL_REG, CCR_RTxC_XTAL | CCR_RXCLK_BRG | CCR_TXCLK_BRG },
+ { DPLL_CTRL_REG, DCR_BRG_ENAB },
+ /* Start Rx */
+ { RX_CTRL_REG, RCR_RX_ENAB | RCR_CHSIZE_8 },
+ /* Start Tx */
+ { TX_CTRL_REG, TCR_TX_ENAB | TCR_RTS | TCR_DTR | TCR_CHSIZE_8 },
+ /* Ext/Stat ints: DCD only */
+ { INT_CTRL_REG, ICR_ENAB_DCD_INT },
+ /* Reset Ext/Stat ints */
+ { COMMAND_REG, CR_EXTSTAT_RESET },
+ /* ...again */
+ { COMMAND_REG, CR_EXTSTAT_RESET },
+ };
+#endif
+ if (!(port->gs.flags & ASYNC_INITIALIZED)) {
+ save_flags(flags);
+ cli();
+#if defined(CONFIG_MVME147_SCC) || defined(CONFIG_MVME162_SCC)
+ if (MACH_IS_MVME147 || MACH_IS_MVME16x) {
+ for (i=0; i<sizeof(mvme_init_tab)/sizeof(*mvme_init_tab); ++i)
+ SCCwrite(mvme_init_tab[i].reg, mvme_init_tab[i].val);
+ }
+#endif
+#if defined(CONFIG_BVME6000_SCC)
+ if (MACH_IS_BVME6000) {
+ for (i=0; i<sizeof(bvme_init_tab)/sizeof(*bvme_init_tab); ++i)
+ SCCwrite(bvme_init_tab[i].reg, bvme_init_tab[i].val);
+ }
+#endif
+
+ /* remember status register for detection of DCD and CTS changes */
+ scc_last_status_reg[channel] = SCCread(STATUS_REG);
+
+ port->c_dcd = 0; /* Prevent initial 1->0 interrupt */
+ scc_setsignals (port, 1,1);
+ restore_flags(flags);
+ }
+
+ tty->driver_data = port;
+ port->gs.tty = tty;
+ port->gs.count++;
+ retval = gs_init_port(&port->gs);
+ if (retval) {
+ port->gs.count--;
+ return retval;
+ }
+ port->gs.flags |= GS_ACTIVE;
+ if (port->gs.count == 1) {
+ MOD_INC_USE_COUNT;
+ }
+ retval = block_til_ready(port, filp);
+
+ if (retval) {
+ MOD_DEC_USE_COUNT;
+ port->gs.count--;
+ return retval;
+ }
+
+ if ((port->gs.count == 1) && (port->gs.flags & ASYNC_SPLIT_TERMIOS)) {
+ if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
+ *tty->termios = port->gs.normal_termios;
+ else
+ *tty->termios = port->gs.callout_termios;
+ scc_set_real_termios (port);
+ }
+
+ port->gs.session = current->session;
+ port->gs.pgrp = current->pgrp;
+ port->c_dcd = scc_get_CD (port);
+
+ scc_enable_rx_interrupts(port);
+
+ return 0;
+}
+
+
+static void scc_throttle (struct tty_struct * tty)
+{
+ struct scc_port *port = (struct scc_port *)tty->driver_data;
+ unsigned long flags;
+ SCC_ACCESS_INIT(port);
+
+ if (tty->termios->c_cflag & CRTSCTS) {
+ save_flags(flags);
+ cli();
+ SCCmod(TX_CTRL_REG, ~TCR_RTS, 0);
+ restore_flags(flags);
+ }
+ if (I_IXOFF(tty))
+ scc_send_xchar(tty, STOP_CHAR(tty));
+}
+
+
+static void scc_unthrottle (struct tty_struct * tty)
+{
+ struct scc_port *port = (struct scc_port *)tty->driver_data;
+ unsigned long flags;
+ SCC_ACCESS_INIT(port);
+
+ if (tty->termios->c_cflag & CRTSCTS) {
+ save_flags(flags);
+ cli();
+ SCCmod(TX_CTRL_REG, 0xff, TCR_RTS);
+ restore_flags(flags);
+ }
+ if (I_IXOFF(tty))
+ scc_send_xchar(tty, START_CHAR(tty));
+}
+
+
+static int scc_ioctl(struct tty_struct *tty, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ return -ENOIOCTLCMD;
+}
+
+
+static void scc_break_ctl(struct tty_struct *tty, int break_state)
+{
+ struct scc_port *port = (struct scc_port *)tty->driver_data;
+ unsigned long flags;
+ SCC_ACCESS_INIT(port);
+
+ save_flags(flags);
+ cli();
+ SCCmod(TX_CTRL_REG, ~TCR_SEND_BREAK,
+ break_state ? TCR_SEND_BREAK : 0);
+ restore_flags(flags);
+}
+
+
+/*---------------------------------------------------------------------------
+ * Serial console stuff...
+ *--------------------------------------------------------------------------*/
+
+#define scc_delay() do { __asm__ __volatile__ (" nop; nop"); } while (0)
+
+static void scc_ch_write (char ch)
+{
+ volatile char *p = NULL;
+
+#ifdef CONFIG_MVME147_SCC
+ if (MACH_IS_MVME147)
+ p = (volatile char *)M147_SCC_A_ADDR;
+#endif
+#ifdef CONFIG_MVME162_SCC
+ if (MACH_IS_MVME16x)
+ p = (volatile char *)MVME_SCC_A_ADDR;
+#endif
+#ifdef CONFIG_BVME6000_SCC
+ if (MACH_IS_BVME6000)
+ p = (volatile char *)BVME_SCC_A_ADDR;
+#endif
+
+ do {
+ scc_delay();
+ }
+ while (!(*p & 4));
+ scc_delay();
+ *p = 8;
+ scc_delay();
+ *p = ch;
+}
+
+
+static void scc_console_write (struct console *co, const char *str, unsigned count)
+{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+
+ while (count--)
+ {
+ if (*str == '\n')
+ scc_ch_write ('\r');
+ scc_ch_write (*str++);
+ }
+ restore_flags(flags);
+}
+
+
+static int scc_console_wait_key(struct console *co)
+{
+ unsigned long flags;
+ volatile char *p = NULL;
+ int c;
+
+#ifdef CONFIG_MVME147_SCC
+ if (MACH_IS_MVME147)
+ p = (volatile char *)M147_SCC_A_ADDR;
+#endif
+#ifdef CONFIG_MVME162_SCC
+ if (MACH_IS_MVME16x)
+ p = (volatile char *)MVME_SCC_A_ADDR;
+#endif
+#ifdef CONFIG_BVME6000_SCC
+ if (MACH_IS_BVME6000)
+ p = (volatile char *)BVME_SCC_A_ADDR;
+#endif
+
+ save_flags(flags);
+ cli();
+
+ /* wait for rx buf filled */
+ while ((*p & 0x01) == 0)
+ ;
+
+ *p = 8;
+ scc_delay();
+ c = *p;
+ restore_flags(flags);
+ return c;
+}
+
+
+static kdev_t scc_console_device(struct console *c)
+{
+ return MKDEV(TTY_MAJOR, SCC_MINOR_BASE + c->index);
+}
+
+
+static int __init scc_console_setup(struct console *co, char *options)
+{
+ return 0;
+}
+
+
+static struct console sercons = {
+ "ttyS",
+ scc_console_write,
+ NULL,
+ scc_console_device,
+ scc_console_wait_key,
+ NULL,
+ scc_console_setup,
+ CON_PRINTBUFFER,
+ -1,
+ 0,
+ NULL
+};
+
+
+void __init vme_scc_console_init(void)
+{
+ if (vme_brdtype == VME_TYPE_MVME147 ||
+ vme_brdtype == VME_TYPE_MVME162 ||
+ vme_brdtype == VME_TYPE_MVME172 ||
+ vme_brdtype == VME_TYPE_BVME4000 ||
+ vme_brdtype == VME_TYPE_BVME6000)
+ register_console(&sercons);
+}
+
diff --git a/drivers/i2c/Config.in b/drivers/i2c/Config.in
index ba533aac0..9050f3528 100644
--- a/drivers/i2c/Config.in
+++ b/drivers/i2c/Config.in
@@ -8,22 +8,22 @@ tristate 'I2C support' CONFIG_I2C
if [ "$CONFIG_I2C" != "n" ]; then
- dep_tristate 'I2C bit-banging interfaces' CONFIG_I2C_ALGOBIT $CONFIG_I2C
- if [ "$CONFIG_I2C_ALGOBIT" != "n" ]; then
- dep_tristate ' Philips style parallel port adapter' CONFIG_I2C_PHILIPSPAR $CONFIG_I2C_ALGOBIT
- dep_tristate ' ELV adapter' CONFIG_I2C_ELV $CONFIG_I2C_ALGOBIT
- dep_tristate ' Velleman K9000 adapter' CONFIG_I2C_VELLEMAN $CONFIG_I2C_ALGOBIT
- fi
+ dep_tristate 'I2C bit-banging interfaces' CONFIG_I2C_ALGOBIT $CONFIG_I2C
+ if [ "$CONFIG_I2C_ALGOBIT" != "n" ]; then
+ dep_tristate ' Philips style parallel port adapter' CONFIG_I2C_PHILIPSPAR $CONFIG_I2C_ALGOBIT
+ dep_tristate ' ELV adapter' CONFIG_I2C_ELV $CONFIG_I2C_ALGOBIT
+ dep_tristate ' Velleman K9000 adapter' CONFIG_I2C_VELLEMAN $CONFIG_I2C_ALGOBIT
+ fi
- dep_tristate 'I2C PCF 8584 interfaces' CONFIG_I2C_ALGOPCF $CONFIG_I2C
- if [ "$CONFIG_I2C_ALGOPCF" != "n" ]; then
- dep_tristate ' Elektor ISA card' CONFIG_I2C_ELEKTOR $CONFIG_I2C_ALGOPCF
- fi
+ dep_tristate 'I2C PCF 8584 interfaces' CONFIG_I2C_ALGOPCF $CONFIG_I2C
+ if [ "$CONFIG_I2C_ALGOPCF" != "n" ]; then
+ dep_tristate ' Elektor ISA card' CONFIG_I2C_ELEKTOR $CONFIG_I2C_ALGOPCF
+ fi
# This is needed for automatic patch generation: sensors code starts here
# This is needed for automatic patch generation: sensors code ends here
- dep_tristate 'I2C device interface' CONFIG_I2C_CHARDEV $CONFIG_I2C
+ dep_tristate 'I2C device interface' CONFIG_I2C_CHARDEV $CONFIG_I2C
fi
endmenu
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index 3d88b6c39..e74337f5b 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -20,7 +20,7 @@
/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi>.
All SMBus-related things are written by Frodo Looijaard <frodol@dds.nl> */
-/* $Id: i2c-core.c,v 1.44 1999/12/21 23:45:58 frodo Exp $ */
+/* $Id: i2c-core.c,v 1.48 2000/01/24 21:41:19 frodo Exp $ */
#include <linux/module.h>
#include <linux/kernel.h>
@@ -33,37 +33,14 @@
/* ----- compatibility stuff ----------------------------------------------- */
-/* 2.0.0 kernel compatibility */
-#if LINUX_VERSION_CODE < 0x020100
-#define MODULE_AUTHOR(noone)
-#define MODULE_DESCRIPTION(none)
-#define MODULE_PARM(no,param)
-#define MODULE_PARM_DESC(no,description)
-#define EXPORT_SYMBOL(noexport)
-#define EXPORT_NO_SYMBOLS
-#endif
-
#include <linux/version.h>
-#ifndef KERNEL_VERSION
-#define KERNEL_VERSION(a,b,c) (((a) << 16) | ((b) << 8) | (c))
-#endif
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,53)
#include <linux/init.h>
-#else
-#define __init
-#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
#define init_MUTEX(s) do { *(s) = MUTEX; } while(0)
#endif
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,4))
-#define copy_from_user memcpy_fromfs
-#define copy_to_user memcpy_tofs
-#else
#include <asm/uaccess.h>
-#endif
/* ----- global defines ---------------------------------------------------- */
@@ -83,8 +60,8 @@
/* ----- global variables -------------------------------------------------- */
/**** lock for writing to global variables: the adapter & driver list */
-struct semaphore adap_lock;
-struct semaphore driver_lock;
+struct semaphore adap_lock;
+struct semaphore driver_lock;
/**** adapter list */
static struct i2c_adapter *adapters[I2C_ADAP_MAX];
@@ -104,73 +81,29 @@ static void i2c_dummy_client(struct i2c_client *client);
*----------------------------------------------------
*/
-/* Note that quite some things changed within the 2.1 kernel series.
- Some things below are somewhat difficult to read because of this. */
-
#ifdef CONFIG_PROC_FS
static int i2cproc_init(void);
static int i2cproc_cleanup(void);
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) && \
- (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,27))
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,27))
static void monitor_bus_i2c(struct inode *inode, int fill);
#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) */
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29))
-
static ssize_t i2cproc_bus_read(struct file * file, char * buf,size_t count,
loff_t *ppos);
static int read_bus_i2c(char *buf, char **start, off_t offset, int len,
int *eof , void *private);
-#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) */
-
-static int i2cproc_bus_read(struct inode * inode, struct file * file,
- char * buf, int count);
-static int read_bus_i2c(char *buf, char **start, off_t offset, int len,
- int unused);
-
-static struct proc_dir_entry proc_bus_dir =
- {
- /* low_ino */ 0, /* Set by proc_register_dynamic */
- /* namelen */ 3,
- /* name */ "bus",
- /* mode */ S_IRUGO | S_IXUGO | S_IFDIR,
- /* nlink */ 2, /* Corrected by proc_register[_dynamic] */
- /* uid */ 0,
- /* gid */ 0,
- /* size */ 0,
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,0,36))
- /* ops */ &proc_dir_inode_operations,
-#endif
- };
-
-static struct proc_dir_entry proc_bus_i2c_dir =
- {
- /* low_ino */ 0, /* Set by proc_register_dynamic */
- /* namelen */ 3,
- /* name */ "i2c",
- /* mode */ S_IRUGO | S_IFREG,
- /* nlink */ 1,
- /* uid */ 0,
- /* gid */ 0,
- /* size */ 0,
- /* ops */ NULL,
- /* get_info */ &read_bus_i2c
- };
-
-#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */
-
/* To implement the dynamic /proc/bus/i2c-? files, we need our own
implementation of the read hook */
static struct file_operations i2cproc_operations = {
- NULL,
- i2cproc_bus_read,
+ NULL,
+ i2cproc_bus_read,
};
static struct inode_operations i2cproc_inode_operations = {
- &i2cproc_operations
+ &i2cproc_operations
};
static int i2cproc_initialized = 0;
@@ -183,7 +116,7 @@ static int i2cproc_initialized = 0;
#endif /* CONFIG_PROC_FS */
-/* ---------------------------------------------------
+/* ---------------------------------------------------
* registering functions
* ---------------------------------------------------
*/
@@ -222,55 +155,21 @@ int i2c_add_adapter(struct i2c_adapter *adap)
if (i2cproc_initialized) {
char name[8];
struct proc_dir_entry *proc_entry;
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29))
- int res;
-#endif
sprintf(name,"i2c-%d", i);
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29))
proc_entry = create_proc_entry(name,0,proc_bus);
if (! proc_entry) {
printk("i2c-core.o: Could not create /proc/bus/%s\n",
- name);
+ name);
return -ENOENT;
- }
+ }
proc_entry->ops = &i2cproc_inode_operations;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,27))
proc_entry->owner = THIS_MODULE;
-#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58))
+#else
proc_entry->fill_inode = &monitor_bus_i2c;
#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) */
-#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) */
- adap->proc_entry = NULL;
- if (!(proc_entry = kmalloc(sizeof(struct proc_dir_entry)+
- strlen(name)+1, GFP_KERNEL))) {
- printk("i2c-core.o: Out of memory!\n");
- return -ENOMEM;
- }
- memset(proc_entry,0,sizeof(struct proc_dir_entry));
- proc_entry->namelen = strlen(name);
- proc_entry->name = (char *) (proc_entry + 1);
- proc_entry->mode = S_IRUGO | S_IFREG;
- proc_entry->nlink = 1;
- proc_entry->ops = &i2cproc_inode_operations;
-
- /* Nasty stuff to keep GCC satisfied */
- {
- char *procname;
- (const char *) procname = proc_entry->name;
- strcpy (procname,name);
- }
-
- if ((res = proc_register_dynamic(&proc_bus_dir, proc_entry))) {
- printk("i2c-core.o: Could not create %s.\n",name);
- kfree(proc_entry);
- return res;
- }
-
- adap->proc_entry = proc_entry;
-#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */
-
adap->inode = proc_entry->low_ino;
}
@@ -283,7 +182,8 @@ int i2c_add_adapter(struct i2c_adapter *adap)
drivers[j]->attach_adapter(adap);
DRV_UNLOCK();
- DEB(printk("i2c-core.o: adapter %s registered as adapter %d.\n",adap->name,i));
+ DEB(printk("i2c-core.o: adapter %s registered as adapter %d.\n",
+ adap->name,i));
return 0;
}
@@ -306,23 +206,9 @@ int i2c_del_adapter(struct i2c_adapter *adap)
i2c_dummy_adapter(adap); /* actually i2c_dummy->del_adapter */
#ifdef CONFIG_PROC_FS
if (i2cproc_initialized) {
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29))
char name[8];
sprintf(name,"i2c-%d", i);
remove_proc_entry(name,proc_bus);
-#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) */
- int res;
- if (adapters[i]->proc_entry) {
- if ((res = proc_unregister(&proc_bus_dir,
- adapters[i]->proc_entry->low_ino))) {
- printk("i2c-core.o: Deregistration of /proc "
- "entry failed\n");
- ADAP_UNLOCK();
- return res;
- }
- kfree(adapters[i]->proc_entry);
- }
-#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */
}
#endif /* def CONFIG_PROC_FS */
@@ -344,7 +230,7 @@ int i2c_del_adapter(struct i2c_adapter *adap)
ADAP_UNLOCK();
DEB(printk("i2c-core.o: adapter unregistered: %s\n",adap->name));
- return 0;
+ return 0;
}
@@ -384,7 +270,8 @@ int i2c_add_driver(struct i2c_driver *driver)
driver->attach_adapter(adapters[i]);
for (j=0; j<I2C_CLIENT_MAX; j++)
if (adapters[i]->clients[j])
- driver->detach_client(adapters[i]->clients[j]);
+ driver->detach_client(
+ adapters[i]->clients[j]);
}
}
ADAP_UNLOCK();
@@ -418,7 +305,7 @@ int i2c_del_driver(struct i2c_driver *driver)
}
/* Have a look at each adapter, if clients of this driver are still
* attached. If so, detach them to be able to kill the driver
- * afterwards.
+ * afterwards.
*/
DEB2(printk("i2c-core.o: unregister_driver - looking for clients.\n"));
/* removing clients does not depend on the notify flag, else
@@ -453,11 +340,11 @@ int i2c_del_driver(struct i2c_driver *driver)
int i2c_check_addr (struct i2c_adapter *adapter, int addr)
{
- int i;
- for (i = 0; i < I2C_CLIENT_MAX ; i++)
- if (adapter->clients[i] && (adapter->clients[i]->addr == addr))
- return -EBUSY;
- return 0;
+ int i;
+ for (i = 0; i < I2C_CLIENT_MAX ; i++)
+ if (adapter->clients[i] && (adapter->clients[i]->addr == addr))
+ return -EBUSY;
+ return 0;
}
int i2c_attach_client(struct i2c_client *client)
@@ -465,8 +352,8 @@ int i2c_attach_client(struct i2c_client *client)
struct i2c_adapter *adapter = client->adapter;
int i;
- if (i2c_check_addr(client->adapter,client->addr))
- return -EBUSY;
+ if (i2c_check_addr(client->adapter,client->addr))
+ return -EBUSY;
for (i = 0; i < I2C_CLIENT_MAX; i++)
if (NULL == adapter->clients[i])
@@ -513,7 +400,7 @@ int i2c_detach_client(struct i2c_client *client)
i2c_dummy_client(client);
DEB(printk("i2c-core.o: client [%s] unregistered.\n",client->name));
- return 0;
+ return 0;
}
void i2c_inc_use_client(struct i2c_client *client)
@@ -543,26 +430,21 @@ void i2c_dec_use_client(struct i2c_client *client)
#ifdef CONFIG_PROC_FS
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) && \
- (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,27))
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,27))
/* Monitor access to /proc/bus/i2c*; make unloading i2c-proc impossible
if some process still uses it or some file in it */
void monitor_bus_i2c(struct inode *inode, int fill)
{
- if (fill)
- MOD_INC_USE_COUNT;
- else
- MOD_DEC_USE_COUNT;
+ if (fill)
+ MOD_INC_USE_COUNT;
+ else
+ MOD_DEC_USE_COUNT;
}
-#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) */
+#endif /* (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,37)) */
/* This function generates the output for /proc/bus/i2c */
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29))
int read_bus_i2c(char *buf, char **start, off_t offset, int len, int *eof,
void *private)
-#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) */
-int read_bus_i2c(char *buf, char **start, off_t offset, int len, int unused)
-#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */
{
int i;
int nr = 0;
@@ -571,7 +453,7 @@ int read_bus_i2c(char *buf, char **start, off_t offset, int len, int unused)
if (adapters[i]) {
nr += sprintf(buf+nr, "i2c-%d\t", i);
if (adapters[i]->algo->smbus_xfer) {
- if (adapters[i]->algo->master_xfer)
+ if (adapters[i]->algo->master_xfer)
nr += sprintf(buf+nr,"smbus/i2c");
else
nr += sprintf(buf+nr,"smbus ");
@@ -587,62 +469,55 @@ int read_bus_i2c(char *buf, char **start, off_t offset, int len, int unused)
}
/* This function generates the output for /proc/bus/i2c-? */
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29))
ssize_t i2cproc_bus_read(struct file * file, char * buf,size_t count,
loff_t *ppos)
{
- struct inode * inode = file->f_dentry->d_inode;
-#else (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29))
-int i2cproc_bus_read(struct inode * inode, struct file * file,char * buf,
- int count)
-{
-#endif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29))
- char *kbuf;
- struct i2c_client *client;
- int i,j,len=0;
-
- if (count < 0)
- return -EINVAL;
- if (count > 4000)
- count = 4000;
- for (i = 0; i < I2C_ADAP_MAX; i++)
- if (adapters[i]->inode == inode->i_ino) {
- /* We need a bit of slack in the kernel buffer; this makes the
- sprintf safe. */
- if (! (kbuf = kmalloc(count + 80,GFP_KERNEL)))
- return -ENOMEM;
- for (j = 0; j < I2C_CLIENT_MAX; j++)
- if ((client = adapters[i]->clients[j]))
- /* Filter out dummy clients */
- if (client->driver->id != I2C_DRIVERID_I2CDEV)
- len += sprintf(kbuf+len,"%02x\t%-32s\t%-32s\n",
- client->addr,
- client->name,client->driver->name);
- if (file->f_pos+len > count)
- len = count - file->f_pos;
- len = len - file->f_pos;
- if (len < 0)
- len = 0;
- copy_to_user (buf,kbuf+file->f_pos,len);
- file->f_pos += len;
- kfree(kbuf);
- return len;
- }
- return -ENOENT;
+ struct inode * inode = file->f_dentry->d_inode;
+ char *kbuf;
+ struct i2c_client *client;
+ int i,j,len=0;
+
+ if (count < 0)
+ return -EINVAL;
+ if (count > 4000)
+ count = 4000;
+ for (i = 0; i < I2C_ADAP_MAX; i++)
+ if (adapters[i]->inode == inode->i_ino) {
+ /* We need a bit of slack in the kernel buffer; this makes the
+ sprintf safe. */
+ if (! (kbuf = kmalloc(count + 80,GFP_KERNEL)))
+ return -ENOMEM;
+ for (j = 0; j < I2C_CLIENT_MAX; j++)
+ if ((client = adapters[i]->clients[j]))
+ /* Filter out dummy clients */
+ if (client->driver->id != I2C_DRIVERID_I2CDEV)
+ len += sprintf(kbuf+len,"%02x\t%-32s\t%-32s\n",
+ client->addr,
+ client->name,client->driver->name);
+ if (file->f_pos+len > count)
+ len = count - file->f_pos;
+ len = len - file->f_pos;
+ if (len < 0)
+ len = 0;
+ if (copy_to_user (buf,kbuf+file->f_pos,
+ len)) {
+ kfree(kbuf);
+ return -EFAULT;
+ }
+ file->f_pos += len;
+ kfree(kbuf);
+ return len;
+ }
+ return -ENOENT;
}
int i2cproc_init(void)
{
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29))
struct proc_dir_entry *proc_bus_i2c;
-#else
- int res;
-#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */
i2cproc_initialized = 0;
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29))
if (! proc_bus) {
printk("i2c-core.o: /proc/bus/ does not exist");
i2cproc_cleanup();
@@ -657,29 +532,10 @@ int i2cproc_init(void)
proc_bus_i2c->read_proc = &read_bus_i2c;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,27))
proc_bus_i2c->owner = THIS_MODULE;
-#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58))
+#else
proc_bus_i2c->fill_inode = &monitor_bus_i2c;
-#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,27)) */
i2cproc_initialized += 2;
-#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) */
- /* In Linux 2.0.x, there is no /proc/bus! But I hope no other module
- introduced it, or we are fucked. And 2.0.35 and earlier does not
- export proc_dir_inode_operations, so we grab it from proc_net,
- which also uses it. Not nice. */
- proc_bus_dir.ops = proc_net.ops;
- if ((res = proc_register_dynamic(&proc_root, &proc_bus_dir))) {
- printk("i2c-core.o: Could not create /proc/bus/");
- i2cproc_cleanup();
- return res;
- }
- i2cproc_initialized ++;
- if ((res = proc_register_dynamic(&proc_bus_dir, &proc_bus_i2c_dir))) {
- printk("i2c-core.o: Could not create /proc/bus/i2c\n");
- i2cproc_cleanup();
- return res;
- }
- i2cproc_initialized ++;
-#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */
return 0;
}
@@ -687,27 +543,8 @@ int i2cproc_cleanup(void)
{
if (i2cproc_initialized >= 1) {
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29))
remove_proc_entry("i2c",proc_bus);
i2cproc_initialized -= 2;
-#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) */
- int res;
- if (i2cproc_initialized >= 2) {
- if ((res = proc_unregister(&proc_bus_dir,
- proc_bus_i2c_dir.low_ino))) {
- printk("i2c-core.o: could not delete "
- "/proc/bus/i2c, module not removed.");
- return res;
- }
- i2cproc_initialized --;
- }
- if ((res = proc_unregister(&proc_root,proc_bus_dir.low_ino))) {
- printk("i2c-core.o: could not delete /proc/bus/, "
- "module not removed.");
- return res;
- }
- i2cproc_initialized --;
-#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */
}
return 0;
}
@@ -715,7 +552,7 @@ int i2cproc_cleanup(void)
#endif /* def CONFIG_PROC_FS */
-/* ---------------------------------------------------
+/* ---------------------------------------------------
* dummy driver notification
* ---------------------------------------------------
*/
@@ -724,16 +561,16 @@ static void i2c_dummy_adapter(struct i2c_adapter *adap)
{
int i;
for (i=0; i<I2C_DRIVER_MAX; i++)
- if (drivers[i] && (drivers[i]->flags & I2C_DF_DUMMY))
- drivers[i]->attach_adapter(adap);
+ if (drivers[i] && (drivers[i]->flags & I2C_DF_DUMMY))
+ drivers[i]->attach_adapter(adap);
}
static void i2c_dummy_client(struct i2c_client *client)
{
int i;
for (i=0; i<I2C_DRIVER_MAX; i++)
- if (drivers[i] && (drivers[i]->flags & I2C_DF_DUMMY))
- drivers[i]->detach_client(client);
+ if (drivers[i] && (drivers[i]->flags & I2C_DF_DUMMY))
+ drivers[i]->detach_client(client);
}
@@ -747,7 +584,8 @@ int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg msgs[],int num)
int ret;
if (adap->algo->master_xfer) {
- DEB2(printk("i2c-core.o: master_xfer: %s with %d msgs.\n",adap->name,num));
+ DEB2(printk("i2c-core.o: master_xfer: %s with %d msgs.\n",
+ adap->name,num));
I2C_LOCK(adap);
ret = adap->algo->master_xfer(adap,msgs,num);
@@ -756,7 +594,7 @@ int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg msgs[],int num)
return ret;
} else {
printk("i2c-core.o: I2C adapter %04x: I2C level transfers not supported\n",
- adap->id);
+ adap->id);
return -ENOSYS;
}
}
@@ -786,7 +624,7 @@ int i2c_master_send(struct i2c_client *client,const char *buf ,int count)
return (ret == 1 )? count : ret;
} else {
printk("i2c-core.o: I2C adapter %04x: I2C level transfers not supported\n",
- client->adapter->id);
+ client->adapter->id);
return -ENOSYS;
}
}
@@ -819,7 +657,7 @@ int i2c_master_recv(struct i2c_client *client, char *buf ,int count)
return (ret == 1 )? count : ret;
} else {
printk("i2c-core.o: I2C adapter %04x: I2C level transfers not supported\n",
- client->adapter->id);
+ client->adapter->id);
return -ENOSYS;
}
}
@@ -855,128 +693,124 @@ int i2c_probe(struct i2c_adapter *adapter,
struct i2c_client_address_data *address_data,
i2c_client_found_addr_proc *found_proc)
{
- int addr,i,found,err;
- int adap_id = i2c_adapter_id(adapter);
-
- /* Forget it if we can't probe using SMBUS_QUICK */
- if (! i2c_check_functionality(adapter,I2C_FUNC_SMBUS_QUICK))
- return -1;
-
- for (addr = 0x00;
- addr <= 0x7f;
- addr++) {
-
- /* Skip if already in use */
- if (i2c_check_addr(adapter,addr))
- continue;
-
- /* If it is in one of the force entries, we don't do any detection
- at all */
- found = 0;
-
- for (i = 0;
- !found && (address_data->force[i] != I2C_CLIENT_END);
- i += 3) {
- if (((adap_id == address_data->force[i]) ||
- (address_data->force[i] == ANY_I2C_BUS)) &&
- (addr == address_data->force[i+1])) {
- DEB2(printk("i2c-core.o: found force parameter for adapter %d, addr %04x\n",
- adap_id,addr));
- if ((err = found_proc(adapter,addr,0,0)))
- return err;
- found = 1;
- }
- }
- if (found)
- continue;
-
- /* If this address is in one of the ignores, we can forget about it
- right now */
- for (i = 0;
- !found && (address_data->ignore[i] != I2C_CLIENT_END);
- i += 2) {
- if (((adap_id == address_data->ignore[i]) ||
- ((address_data->ignore[i] == ANY_I2C_BUS))) &&
- (addr == address_data->ignore[i+1])) {
- DEB2(printk("i2c-core.o: found ignore parameter for adapter %d, "
- "addr %04x\n", adap_id ,addr));
- found = 1;
- }
- }
- for (i = 0;
- !found && (address_data->ignore_range[i] != I2C_CLIENT_END);
- i += 3) {
- if (((adap_id == address_data->ignore_range[i]) ||
- ((address_data->ignore_range[i]==ANY_I2C_BUS))) &&
- (addr >= address_data->ignore_range[i+1]) &&
- (addr <= address_data->ignore_range[i+2])) {
- DEB2(printk("i2c-core.o: found ignore_range parameter for adapter %d, "
- "addr %04x\n", adap_id,addr));
- found = 1;
- }
- }
- if (found)
- continue;
-
- /* Now, we will do a detection, but only if it is in the normal or
- probe entries */
- for (i = 0;
- !found && (address_data->normal_i2c[i] != I2C_CLIENT_END);
- i += 1) {
- if (addr == address_data->normal_i2c[i]) {
- found = 1;
- DEB2(printk("i2c-core.o: found normal i2c entry for adapter %d, "
- "addr %02x", adap_id,addr));
- }
- }
-
- for (i = 0;
- !found && (address_data->normal_i2c_range[i] != I2C_CLIENT_END);
- i += 2) {
- if ((addr >= address_data->normal_i2c_range[i]) &&
- (addr <= address_data->normal_i2c_range[i+1])) {
- found = 1;
- DEB2(printk("i2c-core.o: found normal i2c_range entry for adapter %d, "
- "addr %04x\n", adap_id,addr));
- }
- }
-
- for (i = 0;
- !found && (address_data->probe[i] != I2C_CLIENT_END);
- i += 2) {
- if (((adap_id == address_data->probe[i]) ||
- ((address_data->probe[i] == ANY_I2C_BUS))) &&
- (addr == address_data->probe[i+1])) {
- found = 1;
- DEB2(printk("i2c-core.o: found probe parameter for adapter %d, "
- "addr %04x\n", adap_id,addr));
- }
- }
- for (i = 0;
- !found && (address_data->probe_range[i] != I2C_CLIENT_END);
- i += 3) {
- if (((adap_id == address_data->probe_range[i]) ||
- (address_data->probe_range[i] == ANY_I2C_BUS)) &&
- (addr >= address_data->probe_range[i+1]) &&
- (addr <= address_data->probe_range[i+2])) {
- found = 1;
- DEB2(printk("i2c-core.o: found probe_range parameter for adapter %d, "
- "addr %04x\n", adap_id,addr));
- }
- }
- if (!found)
- continue;
-
- /* OK, so we really should examine this address. First check
- whether there is some client here at all! */
- if (i2c_smbus_xfer(adapter,addr,0,0,0,I2C_SMBUS_QUICK,NULL) >= 0)
- if ((err = found_proc(adapter,addr,0,-1)))
- return err;
- }
- return 0;
+ int addr,i,found,err;
+ int adap_id = i2c_adapter_id(adapter);
+
+ /* Forget it if we can't probe using SMBUS_QUICK */
+ if (! i2c_check_functionality(adapter,I2C_FUNC_SMBUS_QUICK))
+ return -1;
+
+ for (addr = 0x00; addr <= 0x7f; addr++) {
+
+ /* Skip if already in use */
+ if (i2c_check_addr(adapter,addr))
+ continue;
+
+ /* If it is in one of the force entries, we don't do any detection
+ at all */
+ found = 0;
+
+ for (i = 0; !found && (address_data->force[i] != I2C_CLIENT_END); i += 3) {
+ if (((adap_id == address_data->force[i]) ||
+ (address_data->force[i] == ANY_I2C_BUS)) &&
+ (addr == address_data->force[i+1])) {
+ DEB2(printk("i2c-core.o: found force parameter for adapter %d, addr %04x\n",
+ adap_id,addr));
+ if ((err = found_proc(adapter,addr,0,0)))
+ return err;
+ found = 1;
+ }
+ }
+ if (found)
+ continue;
+
+ /* If this address is in one of the ignores, we can forget about
+ it right now */
+ for (i = 0;
+ !found && (address_data->ignore[i] != I2C_CLIENT_END);
+ i += 2) {
+ if (((adap_id == address_data->ignore[i]) ||
+ ((address_data->ignore[i] == ANY_I2C_BUS))) &&
+ (addr == address_data->ignore[i+1])) {
+ DEB2(printk("i2c-core.o: found ignore parameter for adapter %d, "
+ "addr %04x\n", adap_id ,addr));
+ found = 1;
+ }
+ }
+ for (i = 0;
+ !found && (address_data->ignore_range[i] != I2C_CLIENT_END);
+ i += 3) {
+ if (((adap_id == address_data->ignore_range[i]) ||
+ ((address_data->ignore_range[i]==ANY_I2C_BUS))) &&
+ (addr >= address_data->ignore_range[i+1]) &&
+ (addr <= address_data->ignore_range[i+2])) {
+ DEB2(printk("i2c-core.o: found ignore_range parameter for adapter %d, "
+ "addr %04x\n", adap_id,addr));
+ found = 1;
+ }
+ }
+ if (found)
+ continue;
+
+ /* Now, we will do a detection, but only if it is in the normal or
+ probe entries */
+ for (i = 0;
+ !found && (address_data->normal_i2c[i] != I2C_CLIENT_END);
+ i += 1) {
+ if (addr == address_data->normal_i2c[i]) {
+ found = 1;
+ DEB2(printk("i2c-core.o: found normal i2c entry for adapter %d, "
+ "addr %02x", adap_id,addr));
+ }
+ }
+
+ for (i = 0;
+ !found && (address_data->normal_i2c_range[i] != I2C_CLIENT_END);
+ i += 2) {
+ if ((addr >= address_data->normal_i2c_range[i]) &&
+ (addr <= address_data->normal_i2c_range[i+1])) {
+ found = 1;
+ DEB2(printk("i2c-core.o: found normal i2c_range entry for adapter %d, "
+ "addr %04x\n", adap_id,addr));
+ }
+ }
+
+ for (i = 0;
+ !found && (address_data->probe[i] != I2C_CLIENT_END);
+ i += 2) {
+ if (((adap_id == address_data->probe[i]) ||
+ ((address_data->probe[i] == ANY_I2C_BUS))) &&
+ (addr == address_data->probe[i+1])) {
+ found = 1;
+ DEB2(printk("i2c-core.o: found probe parameter for adapter %d, "
+ "addr %04x\n", adap_id,addr));
+ }
+ }
+ for (i = 0;
+ !found && (address_data->probe_range[i] != I2C_CLIENT_END);
+ i += 3) {
+ if (((adap_id == address_data->probe_range[i]) ||
+ (address_data->probe_range[i] == ANY_I2C_BUS)) &&
+ (addr >= address_data->probe_range[i+1]) &&
+ (addr <= address_data->probe_range[i+2])) {
+ found = 1;
+ DEB2(printk("i2c-core.o: found probe_range parameter for adapter %d, "
+ "addr %04x\n", adap_id,addr));
+ }
+ }
+ if (!found)
+ continue;
+
+ /* OK, so we really should examine this address. First check
+ whether there is some client here at all! */
+ if (i2c_smbus_xfer(adapter,addr,0,0,0,I2C_SMBUS_QUICK,NULL) >= 0)
+ if ((err = found_proc(adapter,addr,0,-1)))
+ return err;
+ }
+ return 0;
}
-/* +++ frodo
+/*
* return id number for a specific adapter
*/
int i2c_adapter_id(struct i2c_adapter *adap)
@@ -993,14 +827,14 @@ int i2c_adapter_id(struct i2c_adapter *adap)
extern s32 i2c_smbus_write_quick(struct i2c_client * client, u8 value)
{
return i2c_smbus_xfer(client->adapter,client->addr,client->flags,
- value,0,I2C_SMBUS_QUICK,NULL);
+ value,0,I2C_SMBUS_QUICK,NULL);
}
extern s32 i2c_smbus_read_byte(struct i2c_client * client)
{
union i2c_smbus_data data;
if (i2c_smbus_xfer(client->adapter,client->addr,client->flags,
- I2C_SMBUS_READ,0,I2C_SMBUS_BYTE, &data))
+ I2C_SMBUS_READ,0,I2C_SMBUS_BYTE, &data))
return -1;
else
return 0x0FF & data.byte;
@@ -1009,26 +843,26 @@ extern s32 i2c_smbus_read_byte(struct i2c_client * client)
extern s32 i2c_smbus_write_byte(struct i2c_client * client, u8 value)
{
return i2c_smbus_xfer(client->adapter,client->addr,client->flags,
- I2C_SMBUS_WRITE,value, I2C_SMBUS_BYTE,NULL);
+ I2C_SMBUS_WRITE,value, I2C_SMBUS_BYTE,NULL);
}
extern s32 i2c_smbus_read_byte_data(struct i2c_client * client, u8 command)
{
union i2c_smbus_data data;
if (i2c_smbus_xfer(client->adapter,client->addr,client->flags,
- I2C_SMBUS_READ,command, I2C_SMBUS_BYTE_DATA,&data))
+ I2C_SMBUS_READ,command, I2C_SMBUS_BYTE_DATA,&data))
return -1;
else
return 0x0FF & data.byte;
}
-extern s32 i2c_smbus_write_byte_data(struct i2c_client * client,
- u8 command, u8 value)
+extern s32 i2c_smbus_write_byte_data(struct i2c_client * client, u8 command,
+ u8 value)
{
union i2c_smbus_data data;
data.byte = value;
return i2c_smbus_xfer(client->adapter,client->addr,client->flags,
- I2C_SMBUS_WRITE,command,
+ I2C_SMBUS_WRITE,command,
I2C_SMBUS_BYTE_DATA,&data);
}
@@ -1036,7 +870,7 @@ extern s32 i2c_smbus_read_word_data(struct i2c_client * client, u8 command)
{
union i2c_smbus_data data;
if (i2c_smbus_xfer(client->adapter,client->addr,client->flags,
- I2C_SMBUS_READ,command, I2C_SMBUS_WORD_DATA, &data))
+ I2C_SMBUS_READ,command, I2C_SMBUS_WORD_DATA, &data))
return -1;
else
return 0x0FFFF & data.word;
@@ -1048,8 +882,8 @@ extern s32 i2c_smbus_write_word_data(struct i2c_client * client,
union i2c_smbus_data data;
data.word = value;
return i2c_smbus_xfer(client->adapter,client->addr,client->flags,
- I2C_SMBUS_WRITE,command,
- I2C_SMBUS_WORD_DATA,&data);
+ I2C_SMBUS_WRITE,command,
+ I2C_SMBUS_WORD_DATA,&data);
}
extern s32 i2c_smbus_process_call(struct i2c_client * client,
@@ -1058,8 +892,8 @@ extern s32 i2c_smbus_process_call(struct i2c_client * client,
union i2c_smbus_data data;
data.word = value;
if (i2c_smbus_xfer(client->adapter,client->addr,client->flags,
- I2C_SMBUS_WRITE,command,
- I2C_SMBUS_PROC_CALL, &data))
+ I2C_SMBUS_WRITE,command,
+ I2C_SMBUS_PROC_CALL, &data))
return -1;
else
return 0x0FFFF & data.word;
@@ -1072,7 +906,7 @@ extern s32 i2c_smbus_read_block_data(struct i2c_client * client,
union i2c_smbus_data data;
int i;
if (i2c_smbus_xfer(client->adapter,client->addr,client->flags,
- I2C_SMBUS_READ,command,
+ I2C_SMBUS_READ,command,
I2C_SMBUS_BLOCK_DATA,&data))
return -1;
else {
@@ -1093,7 +927,7 @@ extern s32 i2c_smbus_write_block_data(struct i2c_client * client,
data.block[i] = values[i-1];
data.block[0] = length;
return i2c_smbus_xfer(client->adapter,client->addr,client->flags,
- I2C_SMBUS_WRITE,command,
+ I2C_SMBUS_WRITE,command,
I2C_SMBUS_BLOCK_DATA,&data);
}
@@ -1177,7 +1011,7 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr,
size);
return -1;
}
-
+
if (i2c_transfer(adapter, msg, num) < 0)
return -1;
@@ -1193,8 +1027,8 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr,
case I2C_SMBUS_PROC_CALL:
data->word = msgbuf1[0] | (msgbuf1[1] << 8);
break;
- }
- return 0;
+ }
+ return 0;
}
@@ -1203,7 +1037,7 @@ s32 i2c_smbus_xfer(struct i2c_adapter * adapter, u16 addr, unsigned short flags,
union i2c_smbus_data * data)
{
s32 res;
- flags = flags & I2C_M_TEN;
+ flags = flags & I2C_M_TEN;
if (adapter->algo->smbus_xfer) {
I2C_LOCK(adapter);
res = adapter->algo->smbus_xfer(adapter,addr,flags,read_write,
@@ -1211,7 +1045,7 @@ s32 i2c_smbus_xfer(struct i2c_adapter * adapter, u16 addr, unsigned short flags,
I2C_UNLOCK(adapter);
} else
res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write,
- command,size,data);
+ command,size,data);
return res;
}
@@ -1220,22 +1054,22 @@ s32 i2c_smbus_xfer(struct i2c_adapter * adapter, u16 addr, unsigned short flags,
backward compatibility. */
u32 i2c_get_functionality (struct i2c_adapter *adap)
{
- if (adap->algo->functionality)
- return adap->algo->functionality(adap);
- else
- return 0xffffffff;
+ if (adap->algo->functionality)
+ return adap->algo->functionality(adap);
+ else
+ return 0xffffffff;
}
int i2c_check_functionality (struct i2c_adapter *adap, u32 func)
{
- u32 adap_func = i2c_get_functionality (adap);
- return (func & adap_func) == func;
+ u32 adap_func = i2c_get_functionality (adap);
+ return (func & adap_func) == func;
}
static int __init i2c_init(void)
{
- printk("i2c-core.o: i2c core module\n");
+ printk("i2c-core.o: i2c core module\n");
memset(adapters,0,sizeof(adapters));
memset(drivers,0,sizeof(drivers));
adap_count=0;
diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c
index 088d730fc..c2c51bef4 100644
--- a/drivers/i2c/i2c-dev.c
+++ b/drivers/i2c/i2c-dev.c
@@ -23,7 +23,7 @@
But I have used so much of his original code and ideas that it seems
only fair to recognize him as co-author -- Frodo */
-/* $Id: i2c-dev.c,v 1.18 1999/12/21 23:45:58 frodo Exp $ */
+/* $Id: i2c-dev.c,v 1.25 2000/01/26 14:14:20 frodo Exp $ */
#include <linux/kernel.h>
#include <linux/module.h>
@@ -34,34 +34,8 @@
/* If you want debugging uncomment: */
/* #define DEBUG */
-#ifndef KERNEL_VERSION
-#define KERNEL_VERSION(a,b,c) (((a) << 16) | ((b) << 8) | (c))
-#endif
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,51)
#include <linux/init.h>
-#else
-#define __init
-#endif
-
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,4))
-#define copy_from_user memcpy_fromfs
-#define copy_to_user memcpy_tofs
-#define get_user_data(to,from) ((to) = get_user(from),0)
-#else
#include <asm/uaccess.h>
-#define get_user_data(to,from) get_user(to,from)
-#endif
-
-/* 2.0.0 kernel compatibility */
-#if LINUX_VERSION_CODE < 0x020100
-#define MODULE_AUTHOR(noone)
-#define MODULE_DESCRIPTION(none)
-#define MODULE_PARM(no,param)
-#define MODULE_PARM_DESC(no,description)
-#define EXPORT_SYMBOL(noexport)
-#define EXPORT_NO_SYMBOLS
-#endif
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
@@ -73,45 +47,18 @@ extern int cleanup_module(void);
/* struct file_operations changed too often in the 2.1 series for nice code */
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70))
static loff_t i2cdev_lseek (struct file *file, loff_t offset, int origin);
-#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,56))
-static long long i2cdev_lseek (struct file *file, long long offset, int origin);
-#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0))
-static long long i2cdev_llseek (struct inode *inode, struct file *file,
- long long offset, int origin);
-#else
-static int i2cdev_lseek (struct inode *inode, struct file *file, off_t offset,
- int origin);
-#endif
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70))
static ssize_t i2cdev_read (struct file *file, char *buf, size_t count,
loff_t *offset);
static ssize_t i2cdev_write (struct file *file, const char *buf, size_t count,
loff_t *offset);
-#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0))
-static long i2cdev_read (struct inode *inode, struct file *file, char *buf,
- unsigned long count);
-static long i2cdev_write (struct inode *inode, struct file *file,
- const char *buf, unsigned long offset);
-#else
-static int i2cdev_read(struct inode *inode, struct file *file, char *buf,
- int count);
-static int i2cdev_write(struct inode *inode, struct file *file,
- const char *buf, int count);
-#endif
static int i2cdev_ioctl (struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg);
static int i2cdev_open (struct inode *inode, struct file *file);
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,31))
static int i2cdev_release (struct inode *inode, struct file *file);
-#else
-static void i2cdev_release (struct inode *inode, struct file *file);
-#endif
-
static int i2cdev_attach_adapter(struct i2c_adapter *adap);
static int i2cdev_detach_client(struct i2c_client *client);
@@ -127,413 +74,349 @@ extern
static int i2cdev_cleanup(void);
static struct file_operations i2cdev_fops = {
- i2cdev_lseek,
- i2cdev_read,
- i2cdev_write,
- NULL, /* i2cdev_readdir */
- NULL, /* i2cdev_select */
- i2cdev_ioctl,
- NULL, /* i2cdev_mmap */
- i2cdev_open,
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,118)
- NULL, /* i2cdev_flush */
-#endif
- i2cdev_release,
+ i2cdev_lseek,
+ i2cdev_read,
+ i2cdev_write,
+ NULL, /* i2cdev_readdir */
+ NULL, /* i2cdev_select */
+ i2cdev_ioctl,
+ NULL, /* i2cdev_mmap */
+ i2cdev_open,
+ NULL, /* i2cdev_flush */
+ i2cdev_release,
};
#define I2CDEV_ADAPS_MAX I2C_ADAP_MAX
static struct i2c_adapter *i2cdev_adaps[I2CDEV_ADAPS_MAX];
static struct i2c_driver i2cdev_driver = {
- /* name */ "i2c-dev dummy driver",
- /* id */ I2C_DRIVERID_I2CDEV,
- /* flags */ I2C_DF_DUMMY,
- /* attach_adapter */ i2cdev_attach_adapter,
- /* detach_client */ i2cdev_detach_client,
- /* command */ i2cdev_command,
- /* inc_use */ NULL,
- /* dec_use */ NULL,
+ /* name */ "i2c-dev dummy driver",
+ /* id */ I2C_DRIVERID_I2CDEV,
+ /* flags */ I2C_DF_DUMMY,
+ /* attach_adapter */ i2cdev_attach_adapter,
+ /* detach_client */ i2cdev_detach_client,
+ /* command */ i2cdev_command,
+ /* inc_use */ NULL,
+ /* dec_use */ NULL,
};
static struct i2c_client i2cdev_client_template = {
- /* name */ "I2C /dev entry",
- /* id */ 1,
- /* flags */ 0,
- /* addr */ -1,
- /* adapter */ NULL,
- /* driver */ &i2cdev_driver,
- /* data */ NULL
+ /* name */ "I2C /dev entry",
+ /* id */ 1,
+ /* flags */ 0,
+ /* addr */ -1,
+ /* adapter */ NULL,
+ /* driver */ &i2cdev_driver,
+ /* data */ NULL
};
static int i2cdev_initialized;
/* Note that the lseek function is called llseek in 2.1 kernels. But things
are complicated enough as is. */
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70))
loff_t i2cdev_lseek (struct file *file, loff_t offset, int origin)
-#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,56))
-long long i2cdev_lseek (struct file *file, long long offset, int origin)
-#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0))
-long long i2cdev_llseek (struct inode *inode, struct file *file,
- long long offset, int origin)
-#else
-int i2cdev_lseek (struct inode *inode, struct file *file, off_t offset,
- int origin)
-#endif
{
#ifdef DEBUG
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,56))
- struct inode *inode = file->f_dentry->d_inode;
-#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70)) */
- printk("i2c-dev,o: i2c-%d lseek to %ld bytes relative to %d.\n",
- MINOR(inode->i_rdev),(long) offset,origin);
+ struct inode *inode = file->f_dentry->d_inode;
+ printk("i2c-dev,o: i2c-%d lseek to %ld bytes relative to %d.\n",
+ MINOR(inode->i_rdev),(long) offset,origin);
#endif /* DEBUG */
- return -ESPIPE;
+ return -ESPIPE;
}
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70))
static ssize_t i2cdev_read (struct file *file, char *buf, size_t count,
loff_t *offset)
-#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0))
-static long i2cdev_read (struct inode *inode, struct file *file, char *buf,
- unsigned long count)
-#else
-static int i2cdev_read(struct inode *inode, struct file *file, char *buf,
- int count)
-#endif
{
- char *tmp;
- int ret;
+ char *tmp;
+ int ret;
#ifdef DEBUG
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70))
- struct inode *inode = file->f_dentry->d_inode;
-#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70)) */
+ struct inode *inode = file->f_dentry->d_inode;
#endif /* DEBUG */
- struct i2c_client *client = (struct i2c_client *)file->private_data;
+ struct i2c_client *client = (struct i2c_client *)file->private_data;
- /* copy user space data to kernel space. */
- tmp = kmalloc(count,GFP_KERNEL);
- if (tmp==NULL)
- return -ENOMEM;
+ /* copy user space data to kernel space. */
+ tmp = kmalloc(count,GFP_KERNEL);
+ if (tmp==NULL)
+ return -ENOMEM;
#ifdef DEBUG
- printk("i2c-dev,o: i2c-%d reading %d bytes.\n",MINOR(inode->i_rdev),count);
+ printk("i2c-dev,o: i2c-%d reading %d bytes.\n",MINOR(inode->i_rdev),
+ count);
#endif
- ret = i2c_master_recv(client,tmp,count);
- copy_to_user(buf,tmp,count);
- kfree(tmp);
- return ret;
+ ret = i2c_master_recv(client,tmp,count);
+ if (! ret)
+ ret = copy_to_user(buf,tmp,count)?-EFAULT:0;
+ kfree(tmp);
+ return ret;
}
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70))
static ssize_t i2cdev_write (struct file *file, const char *buf, size_t count,
loff_t *offset)
-#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0))
-static long i2cdev_write (struct inode *inode, struct file *file,
- const char *buf, unsigned long offset)
-#else
-static int i2cdev_write(struct inode *inode, struct file *file,
- const char *buf, int count)
-#endif
{
- int ret;
- char *tmp;
- struct i2c_client *client = (struct i2c_client *)file->private_data;
+ int ret;
+ char *tmp;
+ struct i2c_client *client = (struct i2c_client *)file->private_data;
#ifdef DEBUG
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70))
- struct inode *inode = file->f_dentry->d_inode;
-#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70)) */
+ struct inode *inode = file->f_dentry->d_inode;
#endif /* DEBUG */
- /* copy user space data to kernel space. */
- tmp = kmalloc(count,GFP_KERNEL);
- if (tmp==NULL)
- return -ENOMEM;
- copy_from_user(tmp,buf,count);
+ /* copy user space data to kernel space. */
+ tmp = kmalloc(count,GFP_KERNEL);
+ if (tmp==NULL)
+ return -ENOMEM;
+ if (copy_from_user(tmp,buf,count)) {
+ kfree(tmp);
+ return -EFAULT;
+ }
#ifdef DEBUG
- printk("i2c-dev,o: i2c-%d writing %d bytes.\n",MINOR(inode->i_rdev),count);
+ printk("i2c-dev,o: i2c-%d writing %d bytes.\n",MINOR(inode->i_rdev),
+ count);
#endif
- ret = i2c_master_send(client,tmp,count);
- kfree(tmp);
- return ret;
+ ret = i2c_master_send(client,tmp,count);
+ kfree(tmp);
+ return ret;
}
int i2cdev_ioctl (struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg)
{
- struct i2c_client *client = (struct i2c_client *)file->private_data;
- struct i2c_smbus_ioctl_data data_arg;
- union i2c_smbus_data temp;
- int ver,datasize,res;
- unsigned long funcs;
+ struct i2c_client *client = (struct i2c_client *)file->private_data;
+ struct i2c_smbus_ioctl_data data_arg;
+ union i2c_smbus_data temp;
+ int datasize,res;
+ unsigned long funcs;
#ifdef DEBUG
- printk("i2c-dev.o: i2c-%d ioctl, cmd: 0x%x, arg: %lx.\n",
- MINOR(inode->i_rdev),cmd, arg);
+ printk("i2c-dev.o: i2c-%d ioctl, cmd: 0x%x, arg: %lx.\n",
+ MINOR(inode->i_rdev),cmd, arg);
#endif /* DEBUG */
- switch ( cmd ) {
- case I2C_SLAVE:
- case I2C_SLAVE_FORCE:
- if ((arg > 0x3ff) || (((client->flags & I2C_M_TEN) == 0) && arg > 0x7f))
- return -EINVAL;
- if ((cmd == I2C_SLAVE) && i2c_check_addr(client->adapter,arg))
- return -EBUSY;
- client->addr = arg;
- return 0;
- case I2C_TENBIT:
- if (arg)
- client->flags |= I2C_M_TEN;
- else
- client->flags &= ~I2C_M_TEN;
- return 0;
- case I2C_FUNCS:
- if (! arg) {
-#ifdef DEBUG
- printk("i2c-dev.o: NULL argument pointer in ioctl I2C_SMBUS.\n");
-#endif
- return -EINVAL;
- }
- if (verify_area(VERIFY_WRITE,(unsigned long *) arg,
- sizeof(unsigned long))) {
+ switch ( cmd ) {
+ case I2C_SLAVE:
+ case I2C_SLAVE_FORCE:
+ if ((arg > 0x3ff) ||
+ (((client->flags & I2C_M_TEN) == 0) && arg > 0x7f))
+ return -EINVAL;
+ if ((cmd == I2C_SLAVE) && i2c_check_addr(client->adapter,arg))
+ return -EBUSY;
+ client->addr = arg;
+ return 0;
+ case I2C_TENBIT:
+ if (arg)
+ client->flags |= I2C_M_TEN;
+ else
+ client->flags &= ~I2C_M_TEN;
+ return 0;
+ case I2C_FUNCS:
+ funcs = i2c_get_functionality(client->adapter);
+ return (copy_to_user((unsigned long *)arg,&funcs,
+ sizeof(unsigned long)))?-EFAULT:0;
+ case I2C_SMBUS:
+ copy_from_user_ret(&data_arg,
+ (struct i2c_smbus_ioctl_data *) arg,
+ sizeof(struct i2c_smbus_ioctl_data),
+ -EFAULT);
+ if ((data_arg.size != I2C_SMBUS_BYTE) &&
+ (data_arg.size != I2C_SMBUS_QUICK) &&
+ (data_arg.size != I2C_SMBUS_BYTE_DATA) &&
+ (data_arg.size != I2C_SMBUS_WORD_DATA) &&
+ (data_arg.size != I2C_SMBUS_PROC_CALL) &&
+ (data_arg.size != I2C_SMBUS_BLOCK_DATA)) {
#ifdef DEBUG
- printk("i2c-dev.o: invalid argument pointer (%ld) "
- "in IOCTL I2C_SMBUS.\n", arg);
+ printk("i2c-dev.o: size out of range (%x) in ioctl I2C_SMBUS.\n",
+ data_arg.size);
#endif
- return -EINVAL;
- }
-
- funcs = i2c_get_functionality(client->adapter);
- copy_to_user((unsigned long *)arg,&funcs,sizeof(unsigned long));
- return 0;
- case I2C_SMBUS:
- if (! arg) {
+ return -EINVAL;
+ }
+ /* Note that I2C_SMBUS_READ and I2C_SMBUS_WRITE are 0 and 1,
+ so the check is valid if size==I2C_SMBUS_QUICK too. */
+ if ((data_arg.read_write != I2C_SMBUS_READ) &&
+ (data_arg.read_write != I2C_SMBUS_WRITE)) {
#ifdef DEBUG
- printk("i2c-dev.o: NULL argument pointer in ioctl I2C_SMBUS.\n");
+ printk("i2c-dev.o: read_write out of range (%x) in ioctl I2C_SMBUS.\n",
+ data_arg.read_write);
#endif
- return -EINVAL;
- }
- if (verify_area(VERIFY_READ,(struct i2c_smbus_ioctl_data *) arg,
- sizeof(struct i2c_smbus_ioctl_data))) {
+ return -EINVAL;
+ }
+
+ /* Note that command values are always valid! */
+
+ if ((data_arg.size == I2C_SMBUS_QUICK) ||
+ ((data_arg.size == I2C_SMBUS_BYTE) &&
+ (data_arg.read_write == I2C_SMBUS_WRITE)))
+ /* These are special: we do not use data */
+ return i2c_smbus_xfer(client->adapter, client->addr,
+ client->flags,
+ data_arg.read_write,
+ data_arg.command,
+ data_arg.size, NULL);
+
+ if (data_arg.data == NULL) {
#ifdef DEBUG
- printk("i2c-dev.o: invalid argument pointer (%ld) "
- "in IOCTL I2C_SMBUS.\n", arg);
+ printk("i2c-dev.o: data is NULL pointer in ioctl I2C_SMBUS.\n");
#endif
- return -EINVAL;
- }
- copy_from_user(&data_arg,(struct i2c_smbus_ioctl_data *) arg,
- sizeof(struct i2c_smbus_ioctl_data));
- if ((data_arg.size != I2C_SMBUS_BYTE) &&
- (data_arg.size != I2C_SMBUS_QUICK) &&
- (data_arg.size != I2C_SMBUS_BYTE_DATA) &&
- (data_arg.size != I2C_SMBUS_WORD_DATA) &&
- (data_arg.size != I2C_SMBUS_PROC_CALL) &&
- (data_arg.size != I2C_SMBUS_BLOCK_DATA)) {
-#ifdef DEBUG
- printk("i2c-dev.o: size out of range (%x) in ioctl I2C_SMBUS.\n",
- data_arg.size);
-#endif
- return -EINVAL;
- }
- /* Note that I2C_SMBUS_READ and I2C_SMBUS_WRITE are 0 and 1,
- so the check is valid if size==I2C_SMBUS_QUICK too. */
- if ((data_arg.read_write != I2C_SMBUS_READ) &&
- (data_arg.read_write != I2C_SMBUS_WRITE)) {
-#ifdef DEBUG
- printk("i2c-dev.o: read_write out of range (%x) in ioctl I2C_SMBUS.\n",
- data_arg.read_write);
-#endif
- return -EINVAL;
- }
-
- /* Note that command values are always valid! */
-
- if ((data_arg.size == I2C_SMBUS_QUICK) ||
- ((data_arg.size == I2C_SMBUS_BYTE) &&
- (data_arg.read_write == I2C_SMBUS_WRITE)))
- /* These are special: we do not use data */
- return i2c_smbus_xfer(client->adapter, client->addr, client->flags,
- data_arg.read_write, data_arg.command,
- data_arg.size, NULL);
-
- if (data_arg.data == NULL) {
-#ifdef DEBUG
- printk("i2c-dev.o: data is NULL pointer in ioctl I2C_SMBUS.\n");
-#endif
- return -EINVAL;
- }
-
- /* This seems unlogical but it is not: if the user wants to read a
- value, we must write that value to user memory! */
- ver = ((data_arg.read_write == I2C_SMBUS_WRITE) &&
- (data_arg.size != I2C_SMBUS_PROC_CALL))?VERIFY_READ:VERIFY_WRITE;
-
- if ((data_arg.size == I2C_SMBUS_BYTE_DATA) || (data_arg.size == I2C_SMBUS_BYTE))
- datasize = sizeof(data_arg.data->byte);
- else if ((data_arg.size == I2C_SMBUS_WORD_DATA) ||
- (data_arg.size == I2C_SMBUS_PROC_CALL))
- datasize = sizeof(data_arg.data->word);
- else /* size == I2C_SMBUS_BLOCK_DATA */
- datasize = sizeof(data_arg.data->block);
-
- if (verify_area(ver,data_arg.data,datasize)) {
-#ifdef DEBUG
- printk("i2c-dev.o: invalid pointer data (%p) in ioctl I2C_SMBUS.\n",
- data_arg.data);
-#endif
- return -EINVAL;
- }
-
- if ((data_arg.size == I2C_SMBUS_PROC_CALL) ||
- (data_arg.read_write == I2C_SMBUS_WRITE))
- copy_from_user(&temp,data_arg.data,datasize);
- res = i2c_smbus_xfer(client->adapter,client->addr,client->flags,
- data_arg.read_write,
- data_arg.command,data_arg.size,&temp);
- if (! res && ((data_arg.size == I2C_SMBUS_PROC_CALL) ||
- (data_arg.read_write == I2C_SMBUS_READ)))
- copy_to_user(data_arg.data,&temp,datasize);
- return res;
-
- default:
- return i2c_control(client,cmd,arg);
- }
- return 0;
+ return -EINVAL;
+ }
+
+ if ((data_arg.size == I2C_SMBUS_BYTE_DATA) ||
+ (data_arg.size == I2C_SMBUS_BYTE))
+ datasize = sizeof(data_arg.data->byte);
+ else if ((data_arg.size == I2C_SMBUS_WORD_DATA) ||
+ (data_arg.size == I2C_SMBUS_PROC_CALL))
+ datasize = sizeof(data_arg.data->word);
+ else /* size == I2C_SMBUS_BLOCK_DATA */
+ datasize = sizeof(data_arg.data->block);
+
+ if ((data_arg.size == I2C_SMBUS_PROC_CALL) ||
+ (data_arg.read_write == I2C_SMBUS_WRITE))
+ copy_from_user_ret(&temp,data_arg.data,datasize,
+ -EFAULT);
+ res = i2c_smbus_xfer(client->adapter,client->addr,client->flags,
+ data_arg.read_write,
+ data_arg.command,data_arg.size,&temp);
+ if (! res && ((data_arg.size == I2C_SMBUS_PROC_CALL) ||
+ (data_arg.read_write == I2C_SMBUS_READ)))
+ copy_to_user_ret(data_arg.data,&temp,datasize,-EFAULT);
+ return res;
+
+ default:
+ return i2c_control(client,cmd,arg);
+ }
+ return 0;
}
int i2cdev_open (struct inode *inode, struct file *file)
{
- unsigned int minor = MINOR(inode->i_rdev);
- struct i2c_client *client;
+ unsigned int minor = MINOR(inode->i_rdev);
+ struct i2c_client *client;
- if ((minor >= I2CDEV_ADAPS_MAX) || ! (i2cdev_adaps[minor])) {
+ if ((minor >= I2CDEV_ADAPS_MAX) || ! (i2cdev_adaps[minor])) {
#ifdef DEBUG
- printk("i2c-dev.o: Trying to open unattached adapter i2c-%d\n",minor);
+ printk("i2c-dev.o: Trying to open unattached adapter i2c-%d\n",
+ minor);
#endif
- return -ENODEV;
- }
+ return -ENODEV;
+ }
- /* Note that we here allocate a client for later use, but we will *not*
- register this client! Yes, this is safe. No, it is not very clean. */
- if(! (client = kmalloc(sizeof(struct i2c_client),GFP_KERNEL)))
- return -ENOMEM;
- memcpy(client,&i2cdev_client_template,sizeof(struct i2c_client));
- client->adapter = i2cdev_adaps[minor];
- file->private_data = client;
+ /* Note that we here allocate a client for later use, but we will *not*
+ register this client! Yes, this is safe. No, it is not very clean. */
+ if(! (client = kmalloc(sizeof(struct i2c_client),GFP_KERNEL)))
+ return -ENOMEM;
+ memcpy(client,&i2cdev_client_template,sizeof(struct i2c_client));
+ client->adapter = i2cdev_adaps[minor];
+ file->private_data = client;
- i2cdev_adaps[minor]->inc_use(i2cdev_adaps[minor]);
- MOD_INC_USE_COUNT;
+ if (i2cdev_adaps[minor]->inc_use)
+ i2cdev_adaps[minor]->inc_use(i2cdev_adaps[minor]);
+ MOD_INC_USE_COUNT;
#ifdef DEBUG
- printk("i2c-dev.o: opened i2c-%d\n",minor);
+ printk("i2c-dev.o: opened i2c-%d\n",minor);
#endif
- return 0;
+ return 0;
}
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,31))
static int i2cdev_release (struct inode *inode, struct file *file)
-#else
-static void i2cdev_release (struct inode *inode, struct file *file)
-#endif
{
- unsigned int minor = MINOR(inode->i_rdev);
- kfree(file->private_data);
- file->private_data=NULL;
+ unsigned int minor = MINOR(inode->i_rdev);
+ kfree(file->private_data);
+ file->private_data=NULL;
#ifdef DEBUG
- printk("i2c-dev.o: Closed: i2c-%d\n", minor);
-#endif
- MOD_DEC_USE_COUNT;
- i2cdev_adaps[minor]->dec_use(i2cdev_adaps[minor]);
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,31))
- return 0;
+ printk("i2c-dev.o: Closed: i2c-%d\n", minor);
#endif
+ MOD_DEC_USE_COUNT;
+ if (i2cdev_adaps[minor]->dec_use)
+ i2cdev_adaps[minor]->dec_use(i2cdev_adaps[minor]);
+ return 0;
}
int i2cdev_attach_adapter(struct i2c_adapter *adap)
{
- int i;
-
- if ((i = i2c_adapter_id(adap)) < 0) {
- printk("i2c-dev.o: Unknown adapter ?!?\n");
- return -ENODEV;
- }
- if (i >= I2CDEV_ADAPS_MAX) {
- printk("i2c-dev.o: Adapter number too large?!? (%d)\n",i);
- return -ENODEV;
- }
-
- if (! i2cdev_adaps[i]) {
- i2cdev_adaps[i] = adap;
- printk("i2c-dev.o: Registered '%s' as minor %d\n",adap->name,i);
- } else {
- i2cdev_adaps[i] = NULL;
+ int i;
+
+ if ((i = i2c_adapter_id(adap)) < 0) {
+ printk("i2c-dev.o: Unknown adapter ?!?\n");
+ return -ENODEV;
+ }
+ if (i >= I2CDEV_ADAPS_MAX) {
+ printk("i2c-dev.o: Adapter number too large?!? (%d)\n",i);
+ return -ENODEV;
+ }
+
+ if (! i2cdev_adaps[i]) {
+ i2cdev_adaps[i] = adap;
+ printk("i2c-dev.o: Registered '%s' as minor %d\n",adap->name,i);
+ } else {
+ i2cdev_adaps[i] = NULL;
#ifdef DEBUG
- printk("i2c-dev.o: Adapter unregistered: %s\n",adap->name);
+ printk("i2c-dev.o: Adapter unregistered: %s\n",adap->name);
#endif
- }
+ }
- return 0;
+ return 0;
}
int i2cdev_detach_client(struct i2c_client *client)
{
- return 0;
+ return 0;
}
static int i2cdev_command(struct i2c_client *client, unsigned int cmd,
void *arg)
{
- return -1;
+ return -1;
}
int __init i2c_dev_init(void)
{
- int res;
-
- printk("i2c-dev.o: i2c /dev entries driver module\n");
-
- i2cdev_initialized = 0;
- if (register_chrdev(I2C_MAJOR,"i2c",&i2cdev_fops)) {
- printk("i2c-dev.o: unable to get major %d for i2c bus\n",I2C_MAJOR);
- return -EIO;
- }
- i2cdev_initialized ++;
-
- if ((res = i2c_add_driver(&i2cdev_driver))) {
- printk("i2c-dev.o: Driver registration failed, module not inserted.\n");
- i2cdev_cleanup();
- return res;
- }
- i2cdev_initialized ++;
- return 0;
+ int res;
+
+ printk("i2c-dev.o: i2c /dev entries driver module\n");
+
+ i2cdev_initialized = 0;
+ if (register_chrdev(I2C_MAJOR,"i2c",&i2cdev_fops)) {
+ printk("i2c-dev.o: unable to get major %d for i2c bus\n",
+ I2C_MAJOR);
+ return -EIO;
+ }
+ i2cdev_initialized ++;
+
+ if ((res = i2c_add_driver(&i2cdev_driver))) {
+ printk("i2c-dev.o: Driver registration failed, module not inserted.\n");
+ i2cdev_cleanup();
+ return res;
+ }
+ i2cdev_initialized ++;
+ return 0;
}
int i2cdev_cleanup(void)
{
- int res;
-
- if (i2cdev_initialized >= 2) {
- if ((res = i2c_del_driver(&i2cdev_driver))) {
- printk("i2c-dev.o: Driver deregistration failed, "
- "module not removed.\n");
- return res;
- }
- i2cdev_initialized ++;
- }
-
- if (i2cdev_initialized >= 1) {
- if ((res = unregister_chrdev(I2C_MAJOR,"i2c"))) {
- printk("i2c-dev.o: unable to release major %d for i2c bus\n",I2C_MAJOR);
- return res;
- }
- i2cdev_initialized --;
- }
- return 0;
+ int res;
+
+ if (i2cdev_initialized >= 2) {
+ if ((res = i2c_del_driver(&i2cdev_driver))) {
+ printk("i2c-dev.o: Driver deregistration failed, "
+ "module not removed.\n");
+ return res;
+ }
+ i2cdev_initialized ++;
+ }
+
+ if (i2cdev_initialized >= 1) {
+ if ((res = unregister_chrdev(I2C_MAJOR,"i2c"))) {
+ printk("i2c-dev.o: unable to release major %d for i2c bus\n",
+ I2C_MAJOR);
+ return res;
+ }
+ i2cdev_initialized --;
+ }
+ return 0;
}
EXPORT_NO_SYMBOLS;
@@ -545,12 +428,12 @@ MODULE_DESCRIPTION("I2C /dev entries driver");
int init_module(void)
{
- return i2c_dev_init();
+ return i2c_dev_init();
}
int cleanup_module(void)
{
- return i2cdev_cleanup();
+ return i2cdev_cleanup();
}
#endif /* def MODULE */
diff --git a/drivers/i2c/i2c-elektor.c b/drivers/i2c/i2c-elektor.c
index fb965df0f..ad7b9d41c 100644
--- a/drivers/i2c/i2c-elektor.c
+++ b/drivers/i2c/i2c-elektor.c
@@ -22,7 +22,7 @@
/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
Frodo Looijaard <frodol@dds.nl> */
-/* $Id: i2c-elektor.c,v 1.13 1999/12/21 23:45:58 frodo Exp $ */
+/* $Id: i2c-elektor.c,v 1.16 2000/01/24 02:06:33 mds Exp $ */
#include <linux/kernel.h>
#include <linux/ioport.h>
@@ -30,24 +30,10 @@
#include <linux/delay.h>
#include <linux/malloc.h>
#include <linux/version.h>
-#if LINUX_VERSION_CODE >= 0x020135
#include <linux/init.h>
-#else
-#define __init
-#endif
#include <asm/irq.h>
#include <asm/io.h>
-/* 2.0.0 kernel compatibility */
-#if LINUX_VERSION_CODE < 0x020100
-#define MODULE_AUTHOR(noone)
-#define MODULE_DESCRIPTION(none)
-#define MODULE_PARM(no,param)
-#define MODULE_PARM_DESC(no,description)
-#define EXPORT_SYMBOL(noexport)
-#define EXPORT_NO_SYMBOLS
-#endif
-
#include <linux/i2c.h>
#include <linux/i2c-algo-pcf.h>
#include <linux/i2c-elektor.h>
@@ -87,56 +73,48 @@ static int pcf_pending;
static void pcf_isa_setbyte(void *data, int ctl, int val)
{
- if (ctl) {
- if (gpi.pi_irq > 0) {
- DEB3(printk("i2c-elektor.o: Write control 0x%x\n", val|I2C_PCF_ENI));
- outb(val | I2C_PCF_ENI, CTRL);
- } else {
- DEB3(printk("i2c-elektor.o: Write control 0x%x\n", val));
- outb(val, CTRL);
- }
- } else {
- DEB3(printk("i2c-elektor.o: Write data 0x%x\n", val));
- outb(val, DATA);
- }
+ if (ctl) {
+ if (gpi.pi_irq > 0) {
+ DEB3(printk("i2c-elektor.o: Write control 0x%x\n",
+ val|I2C_PCF_ENI));
+ outb(val | I2C_PCF_ENI, CTRL);
+ } else {
+ DEB3(printk("i2c-elektor.o: Write control 0x%x\n", val));
+ outb(val, CTRL);
+ }
+ } else {
+ DEB3(printk("i2c-elektor.o: Write data 0x%x\n", val));
+ outb(val, DATA);
+ }
}
static int pcf_isa_getbyte(void *data, int ctl)
{
- int val;
-
- if (ctl) {
- val = inb(CTRL);
- DEB3(printk("i2c-elektor.o: Read control 0x%x\n", val));
- } else {
- val = inb(DATA);
- DEB3(printk("i2c-elektor.o: Read data 0x%x\n", val));
- }
- return (val);
+ int val;
+
+ if (ctl) {
+ val = inb(CTRL);
+ DEB3(printk("i2c-elektor.o: Read control 0x%x\n", val));
+ } else {
+ val = inb(DATA);
+ DEB3(printk("i2c-elektor.o: Read data 0x%x\n", val));
+ }
+ return (val);
}
static int pcf_isa_getown(void *data)
{
- return (gpi.pi_own);
+ return (gpi.pi_own);
}
static int pcf_isa_getclock(void *data)
{
- return (gpi.pi_clock);
+ return (gpi.pi_clock);
}
-#if LINUX_VERSION_CODE < 0x02017f
-static void schedule_timeout(int j)
-{
- current->state = TASK_INTERRUPTIBLE;
- current->timeout = jiffies + j;
- schedule();
-}
-#endif
-
#if 0
static void pcf_isa_sleep(unsigned long timeout)
{
@@ -147,64 +125,53 @@ static void pcf_isa_sleep(unsigned long timeout)
static void pcf_isa_waitforpin(void) {
- int timeout = 2;
-
- if (gpi.pi_irq > 0) {
- cli();
- if (pcf_pending == 0) {
-#if LINUX_VERSION_CODE < 0x02017f
- current->timeout = jiffies + timeout * HZ;
- interruptible_sleep_on(&pcf_wait);
-#else
- interruptible_sleep_on_timeout(&pcf_wait, timeout*HZ );
-#endif
- }
- else
- pcf_pending = 0;
- sti();
-#if LINUX_VERSION_CODE < 0x02017f
- current->timeout = 0;
-#endif
- }
- else {
- udelay(100);
- }
+ int timeout = 2;
+
+ if (gpi.pi_irq > 0) {
+ cli();
+ if (pcf_pending == 0) {
+ interruptible_sleep_on_timeout(&pcf_wait, timeout*HZ );
+ } else
+ pcf_pending = 0;
+ sti();
+ } else {
+ udelay(100);
+ }
}
static void pcf_isa_handler(int this_irq, void *dev_id, struct pt_regs *regs) {
-
- pcf_pending = 1;
- wake_up_interruptible(&pcf_wait);
+ pcf_pending = 1;
+ wake_up_interruptible(&pcf_wait);
}
static int pcf_isa_init(void)
{
- if (check_region(gpi.pi_base, 2) < 0 ) {
- return -ENODEV;
- } else {
- request_region(gpi.pi_base, 2, "i2c (isa bus adapter)");
- }
- if (gpi.pi_irq > 0) {
- if (request_irq(gpi.pi_irq, pcf_isa_handler, 0, "PCF8584", 0) < 0) {
- printk("i2c-elektor.o: Request irq%d failed\n", gpi.pi_irq);
- gpi.pi_irq = 0;
- }
- else
- enable_irq(gpi.pi_irq);
- }
- return 0;
+ if (check_region(gpi.pi_base, 2) < 0 ) {
+ return -ENODEV;
+ } else {
+ request_region(gpi.pi_base, 2, "i2c (isa bus adapter)");
+ }
+ if (gpi.pi_irq > 0) {
+ if (request_irq(gpi.pi_irq, pcf_isa_handler, 0, "PCF8584", 0)
+ < 0) {
+ printk("i2c-elektor.o: Request irq%d failed\n", gpi.pi_irq);
+ gpi.pi_irq = 0;
+ } else
+ enable_irq(gpi.pi_irq);
+ }
+ return 0;
}
static void pcf_isa_exit(void)
{
- if (gpi.pi_irq > 0) {
- disable_irq(gpi.pi_irq);
- free_irq(gpi.pi_irq, 0);
- }
- release_region(gpi.pi_base , 2);
+ if (gpi.pi_irq > 0) {
+ disable_irq(gpi.pi_irq);
+ free_irq(gpi.pi_irq, 0);
+ }
+ release_region(gpi.pi_base , 2);
}
@@ -222,14 +189,14 @@ static int pcf_isa_unreg(struct i2c_client *client)
static void pcf_isa_inc_use(struct i2c_adapter *adap)
{
#ifdef MODULE
- MOD_INC_USE_COUNT;
+ MOD_INC_USE_COUNT;
#endif
}
static void pcf_isa_dec_use(struct i2c_adapter *adap)
{
#ifdef MODULE
- MOD_DEC_USE_COUNT;
+ MOD_DEC_USE_COUNT;
#endif
}
@@ -262,41 +229,41 @@ static struct i2c_adapter pcf_isa_ops = {
int __init i2c_pcfisa_init(void)
{
- struct i2c_pcf_isa *pisa = &gpi;
+ struct i2c_pcf_isa *pisa = &gpi;
- printk("i2c-elektor.o: i2c pcf8584-isa adapter module\n");
- if (base == 0)
- pisa->pi_base = DEFAULT_BASE;
- else
- pisa->pi_base = base;
+ printk("i2c-elektor.o: i2c pcf8584-isa adapter module\n");
+ if (base == 0)
+ pisa->pi_base = DEFAULT_BASE;
+ else
+ pisa->pi_base = base;
- if (irq == 0)
- pisa->pi_irq = DEFAULT_IRQ;
- else
- pisa->pi_irq = irq;
+ if (irq == 0)
+ pisa->pi_irq = DEFAULT_IRQ;
+ else
+ pisa->pi_irq = irq;
- if (clock == 0)
- pisa->pi_clock = DEFAULT_CLOCK;
- else
- pisa->pi_clock = clock;
+ if (clock == 0)
+ pisa->pi_clock = DEFAULT_CLOCK;
+ else
+ pisa->pi_clock = clock;
- if (own == 0)
- pisa->pi_own = DEFAULT_OWN;
- else
- pisa->pi_own = own;
+ if (own == 0)
+ pisa->pi_own = DEFAULT_OWN;
+ else
+ pisa->pi_own = own;
- pcf_isa_data.data = (void *)pisa;
+ pcf_isa_data.data = (void *)pisa;
#if (LINUX_VERSION_CODE >= 0x020301)
- init_waitqueue_head(&pcf_wait);
+ init_waitqueue_head(&pcf_wait);
#endif
- if (pcf_isa_init() == 0) {
- if (i2c_pcf_add_bus(&pcf_isa_ops) < 0)
- return -ENODEV;
- } else {
- return -ENODEV;
- }
- printk("i2c-elektor.o: found device at %#x.\n", pisa->pi_base);
- return 0;
+ if (pcf_isa_init() == 0) {
+ if (i2c_pcf_add_bus(&pcf_isa_ops) < 0)
+ return -ENODEV;
+ } else {
+ return -ENODEV;
+ }
+ printk("i2c-elektor.o: found device at %#x.\n", pisa->pi_base);
+ return 0;
}
@@ -313,7 +280,7 @@ MODULE_PARM(own, "i");
int init_module(void)
{
- return i2c_pcfisa_init();
+ return i2c_pcfisa_init();
}
void cleanup_module(void)
diff --git a/drivers/i2c/i2c-pcf8584.h b/drivers/i2c/i2c-pcf8584.h
index 7dabbd9a9..9f0874012 100644
--- a/drivers/i2c/i2c-pcf8584.h
+++ b/drivers/i2c/i2c-pcf8584.h
@@ -21,20 +21,20 @@
/* With some changes from Frodo Looijaard <frodol@dds.nl> */
-/* $Id: i2c-pcf8584.h,v 1.2 1999/12/21 23:45:58 frodo Exp $ */
+/* $Id: i2c-pcf8584.h,v 1.3 2000/01/18 23:54:07 frodo Exp $ */
#ifndef I2C_PCF8584_H
#define I2C_PCF8584_H 1
/* ----- Control register bits ---------------------------------------- */
-#define I2C_PCF_PIN 0x80
-#define I2C_PCF_ESO 0x40
-#define I2C_PCF_ES1 0x20
-#define I2C_PCF_ES2 0x10
-#define I2C_PCF_ENI 0x08
-#define I2C_PCF_STA 0x04
-#define I2C_PCF_STO 0x02
-#define I2C_PCF_ACK 0x01
+#define I2C_PCF_PIN 0x80
+#define I2C_PCF_ESO 0x40
+#define I2C_PCF_ES1 0x20
+#define I2C_PCF_ES2 0x10
+#define I2C_PCF_ENI 0x08
+#define I2C_PCF_STA 0x04
+#define I2C_PCF_STO 0x02
+#define I2C_PCF_ACK 0x01
#define I2C_PCF_START (I2C_PCF_PIN | I2C_PCF_ESO | I2C_PCF_STA | I2C_PCF_ACK)
#define I2C_PCF_STOP (I2C_PCF_PIN | I2C_PCF_ESO | I2C_PCF_STO | I2C_PCF_ACK)
@@ -45,7 +45,7 @@
/*#define I2C_PCF_PIN 0x80 as above*/
#define I2C_PCF_INI 0x40 /* 1 if not initialized */
-#define I2C_PCF_STS 0x20
+#define I2C_PCF_STS 0x20
#define I2C_PCF_BER 0x10
#define I2C_PCF_AD0 0x08
#define I2C_PCF_LRB 0x08
@@ -54,17 +54,17 @@
#define I2C_PCF_BB 0x01
/* ----- Chip clock frequencies --------------------------------------- */
-#define I2C_PCF_CLK3 0x00
-#define I2C_PCF_CLK443 0x10
-#define I2C_PCF_CLK6 0x14
-#define I2C_PCF_CLK8 0x18
-#define I2C_PCF_CLK12 0x1c
+#define I2C_PCF_CLK3 0x00
+#define I2C_PCF_CLK443 0x10
+#define I2C_PCF_CLK6 0x14
+#define I2C_PCF_CLK 0x18
+#define I2C_PCF_CLK12 0x1c
/* ----- transmission frequencies ------------------------------------- */
-#define I2C_PCF_TRNS90 0x00 /* 90 kHz */
-#define I2C_PCF_TRNS45 0x01 /* 45 kHz */
-#define I2C_PCF_TRNS11 0x02 /* 11 kHz */
-#define I2C_PCF_TRNS15 0x03 /* 1.5 kHz */
+#define I2C_PCF_TRNS90 0x00 /* 90 kHz */
+#define I2C_PCF_TRNS45 0x01 /* 45 kHz */
+#define I2C_PCF_TRNS11 0x02 /* 11 kHz */
+#define I2C_PCF_TRNS15 0x03 /* 1.5 kHz */
/* ----- Access to internal registers according to ES1,ES2 ------------ */
diff --git a/drivers/ieee1394/ieee1394_syms.c b/drivers/ieee1394/ieee1394_syms.c
index e4d92fa0f..ee4bde182 100644
--- a/drivers/ieee1394/ieee1394_syms.c
+++ b/drivers/ieee1394/ieee1394_syms.c
@@ -39,6 +39,7 @@ EXPORT_SYMBOL(hpsb_make_readqpacket);
EXPORT_SYMBOL(hpsb_make_readbpacket);
EXPORT_SYMBOL(hpsb_make_writeqpacket);
EXPORT_SYMBOL(hpsb_make_writebpacket);
+EXPORT_SYMBOL(hpsb_make_lockpacket);
EXPORT_SYMBOL(hpsb_read);
EXPORT_SYMBOL(hpsb_write);
EXPORT_SYMBOL(hpsb_lock);
diff --git a/drivers/ieee1394/ieee1394_transactions.c b/drivers/ieee1394/ieee1394_transactions.c
index c50bce62a..e2eeffc68 100644
--- a/drivers/ieee1394/ieee1394_transactions.c
+++ b/drivers/ieee1394/ieee1394_transactions.c
@@ -329,6 +329,30 @@ struct hpsb_packet *hpsb_make_writebpacket(struct hpsb_host *host,
return p;
}
+struct hpsb_packet *hpsb_make_lockpacket(struct hpsb_host *host, nodeid_t node,
+ u64 addr, int extcode)
+{
+ struct hpsb_packet *p;
+
+ p = alloc_hpsb_packet(8);
+ if (!p) return NULL;
+
+ p->host = host;
+ p->tlabel = get_tlabel(host, node, 1);
+ p->node_id = node;
+
+ switch (extcode) {
+ case EXTCODE_FETCH_ADD:
+ case EXTCODE_LITTLE_ADD:
+ fill_async_lock(p, addr, extcode, 4);
+ break;
+ default:
+ fill_async_lock(p, addr, extcode, 8);
+ break;
+ }
+
+ return p;
+}
/*
* FIXME - these functions should probably read from / write to user space to
diff --git a/drivers/ieee1394/ieee1394_transactions.h b/drivers/ieee1394/ieee1394_transactions.h
index 136d4f7d9..ebec602a9 100644
--- a/drivers/ieee1394/ieee1394_transactions.h
+++ b/drivers/ieee1394/ieee1394_transactions.h
@@ -39,6 +39,9 @@ struct hpsb_packet *hpsb_make_writeqpacket(struct hpsb_host *host,
struct hpsb_packet *hpsb_make_writebpacket(struct hpsb_host *host,
nodeid_t node, u64 addr,
size_t length);
+struct hpsb_packet *hpsb_make_lockpacket(struct hpsb_host *host, nodeid_t node,
+ u64 addr, int extcode);
+
/*
* hpsb_packet_success - Make sense of the ack and reply codes and
diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c
index f39a8de86..4da40f6c4 100644
--- a/drivers/ieee1394/ohci1394.c
+++ b/drivers/ieee1394/ohci1394.c
@@ -1,5 +1,5 @@
/*
- * ti_ohci1394.c - Texas Instruments Ohci1394 driver
+ * ohci1394.c - driver for OHCI 1394 boards
* Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>
* Gord Peters <GordPeters@smarttech.com>
*
@@ -18,6 +18,7 @@
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
+#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
@@ -40,8 +41,6 @@
#include "ieee1394_core.h"
#include "ohci1394.h"
-#undef CONFIG_PROC_FS
-
/* print general (card independent) information */
#define PRINT_G(level, fmt, args...) \
printk(level "ohci1394: " fmt "\n" , ## args)
@@ -68,7 +67,6 @@ static int init_driver(void);
* IEEE-1394 functionality section *
***********************************/
-
#if 0 /* not needed at this time */
static int get_phy_reg(struct ti_ohci *ohci, int addr)
{
@@ -324,31 +322,53 @@ static int ohci_initialize(struct hpsb_host *host)
}
/* Initialize AR dma */
- ohci->AR_resp_prg->control=0x283C << 16 | AR_RESP_BUF_SIZE;
- ohci->AR_resp_prg->address=virt_to_bus(ohci->AR_resp_buf);
- ohci->AR_resp_prg->status=AR_RESP_BUF_SIZE;
- PRINT(KERN_INFO, ohci->id, "AR control: %x",
- ohci->AR_resp_prg->control);
- PRINT(KERN_INFO, ohci->id, "AR status: %x %d",
- ohci->AR_resp_prg->status & 0xffff,
- ohci->AR_resp_prg->status & 0xffff);
-
- /* Tell the controller where the AR program is */
- reg_write(ohci, OHCI1394_AsRspRcvCommandPtr,
- virt_to_bus(ohci->AR_resp_prg)|0x00000001);
+ /* make sure the context isn't running, dead, or active */
+ if (!(reg_read(ohci, OHCI1394_AsRspRcvContextControlSet) & 0x00008F00)) {
-#if 1
- /* Accept phy packets into AR request context */
- reg_write(ohci, OHCI1394_LinkControlSet, 0x00000400);
-#endif
+ /* initialize AR program */
+ for (i= 0; i < AR_RESP_NUM_DESC; i++) {
- /* Run AR context */
- reg_write(ohci, OHCI1394_AsRspRcvContextControlSet, 0x00008000);
+ /* end of descriptor list? */
+ if ((i + 1) < AR_RESP_NUM_DESC) {
+ ohci->AR_resp_prg[i]->control=
+ (0x283C << 16) | AR_RESP_BUF_SIZE;
+ ohci->AR_resp_prg[i]->branchAddress=
+ (virt_to_bus(ohci->AR_resp_prg[i + 1])
+ & 0xfffffff0) | 0x1;
+ } else {
+ ohci->AR_resp_prg[i]->control=
+ (0x283C << 16) | AR_RESP_BUF_SIZE;
+ ohci->AR_resp_prg[i]->branchAddress=
+ (virt_to_bus(ohci->AR_resp_prg[0])
+ & 0xfffffff0) | 0x1;
+ }
+
+ ohci->AR_resp_prg[i]->address=
+ virt_to_bus(ohci->AR_resp_buf[i]);
+ ohci->AR_resp_prg[i]->status= AR_RESP_BUF_SIZE;
+ }
+
+ /* Tell the controller where the first AR program is */
+ reg_write(ohci, OHCI1394_AsRspRcvCommandPtr,
+ virt_to_bus(ohci->AR_resp_prg[0]) | 0x1 );
+
+ /* Accept phy packets into AR request context */
+ reg_write(ohci, OHCI1394_LinkControlSet, 0x00000400);
+
+ /* Run AR context */
+ reg_write(ohci, OHCI1394_AsRspRcvContextControlSet, 0x00008000);
+ }
+
+ /* Specify AT retries */
+ reg_write(ohci, OHCI1394_ATRetries,
+ OHCI1394_MAX_AT_REQ_RETRIES |
+ (OHCI1394_MAX_AT_RESP_RETRIES<<4) |
+ (OHCI1394_MAX_PHYS_RESP_RETRIES<<8));
#ifndef __BIG_ENDIAN
- reg_write(ohci, OHCI1394_HCControlSet, 0x40000000);
-#else
reg_write(ohci, OHCI1394_HCControlClear, 0x40000000);
+#else
+ reg_write(ohci, OHCI1394_HCControlSet, 0x40000000);
#endif
/* Enable interrupts */
@@ -386,8 +406,9 @@ static void send_next_async(struct ti_ohci *ohci)
int i=0;
struct hpsb_packet *packet = ohci->async_queue;
struct dma_cmd prg;
+#if 0
quadlet_t *ptr = (quadlet_t *)ohci->AT_req_prg;
-
+#endif
//HPSB_TRACE();
/* stop the channel program if it's still running */
@@ -435,14 +456,14 @@ static void send_next_async(struct ti_ohci *ohci)
prg.status = 0;
memcpy(ohci->AT_req_prg, &prg, 16);
memcpy(ohci->AT_req_prg + 1, packet->header, 16);
-
+#if 0
PRINT(KERN_INFO, ohci->id,
"dma_cmd: %08x %08x %08x %08x",
*ptr, *(ptr+1), *(ptr+2), *(ptr+3));
PRINT(KERN_INFO, ohci->id,
"header: %08x %08x %08x %08x",
*(ptr+4), *(ptr+5), *(ptr+6), *(ptr+7));
-
+#endif
reg_write(ohci, OHCI1394_AsReqTrCommandPtr,
virt_to_bus(ohci->AT_req_prg)|0x2);
}
@@ -455,11 +476,11 @@ static void send_next_async(struct ti_ohci *ohci)
prg.branchAddress = 0;
prg.status = 0;
memcpy(ohci->AT_req_prg, &prg, 16);
-
+#if 0
PRINT(KERN_INFO, ohci->id,
"dma_cmd: %08x %08x %08x %08x",
*ptr, *(ptr+1), *(ptr+2), *(ptr+3));
-
+#endif
reg_write(ohci, OHCI1394_AsReqTrCommandPtr,
virt_to_bus(ohci->AT_req_prg)|0x2);
}
@@ -638,6 +659,26 @@ static int ohci_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg)
* Global stuff (interrupt handler, init/shutdown code) *
********************************************************/
+static void stop_ar_resp_context(struct ti_ohci *ohci, char *msg)
+{
+ int i=0;
+
+ /* stop the channel program if it's still running */
+ reg_write(ohci, OHCI1394_AsRspRcvContextControlClear, 0x8000);
+
+ /* Wait until it effectively stops */
+ while (reg_read(ohci, OHCI1394_AsRspRcvContextControlSet)
+ & 0x400) {
+ i++;
+ if (i>5000) {
+ PRINT(KERN_ERR, ohci->id,
+ "runaway loop in Dma Ar Resp. bailing out...");
+ break;
+ }
+ }
+ PRINT(KERN_ERR, ohci->id, "%s\n async response receive dma stopped\n", msg);
+}
+
static void ohci_irq_handler(int irq, void *dev_id,
struct pt_regs *regs_are_unused)
{
@@ -656,15 +697,14 @@ static void ohci_irq_handler(int irq, void *dev_id,
event,reg_read(ohci, OHCI1394_IntMaskSet)); */
if (event & OHCI1394_busReset) {
+#if 0
PRINT(KERN_INFO, ohci->id, "bus reset interrupt");
+#endif
if (!host->in_bus_reset) {
hpsb_bus_reset(host);
}
ohci->NumBusResets++;
}
- if (event & OHCI1394_reqTxComplete) {
- PRINT(KERN_INFO, ohci->id, "reqTxComplete int received");
- }
if (event & OHCI1394_RQPkt) {
PRINT(KERN_INFO, ohci->id, "RQPkt int received");
}
@@ -673,58 +713,55 @@ static void ohci_irq_handler(int irq, void *dev_id,
reg_read(ohci, OHCI1394_AsReqRcvContextControlSet));
}
if (event & OHCI1394_RSPkt) {
- int rcv_bytes;
- int i=0;
-
- /* we calculate the number of received bytes from the
- residual count field */
- rcv_bytes = AR_RESP_BUF_SIZE -
- (ohci->AR_resp_prg->status & 0xFFFF);
-
- PRINT(KERN_INFO, ohci->id, "AR_status 0x%x %d, %d bytes read",
- ohci->AR_resp_prg->status,
- ohci->AR_resp_prg->status & 0xffff,
- rcv_bytes);
-
- ohci->AR_resp_active = 0;
-
- if ((ohci->AR_resp_prg->status & 0x84000000)
- && (ohci->AR_resp_prg->status & 0xFFFF) >= 8 ) {
- hpsb_packet_received(host, ohci->AR_resp_buf,
- rcv_bytes);
- } else {
- //HPSB_TRACE();
- PRINT(KERN_ERR, ohci->id,
- "AR resp DMA program status value 0x%x is incorrect!",
- ohci->AR_resp_prg->status);
- }
-
-
- /* --------------- FIXME ---------------------------------
- this is a complete hack... we stop the dma prg
- and start it again so as to reset the dma buffer address
- Very slow, very bad design... to change ASAP */
-
- /* stop the channel program if it's still running */
- reg_write(ohci, OHCI1394_AsRspRcvContextControlClear, 0x8000);
-
- /* Wait until it effectively stops */
- while (reg_read(ohci, OHCI1394_AsRspRcvContextControlSet)
- & 0x400) {
- i++;
- if (i>5000) {
- PRINT(KERN_ERR, ohci->id,
- "runaway loop in DmaAT. bailing out...");
- break;
+ unsigned int idx,offset,rescount;
+
+ spin_lock(&ohci->AR_resp_lock);
+
+ idx = ohci->AR_resp_buf_th_ind;
+ offset = ohci->AR_resp_buf_th_offset;
+
+ rescount = ohci->AR_resp_prg[idx]->status&0xffff;
+ ohci->AR_resp_bytes_left += AR_RESP_BUF_SIZE - rescount - offset;
+ offset = AR_RESP_BUF_SIZE - rescount;
+
+ if (!rescount) { /* We cross a buffer boundary */
+ idx = (idx+1) % AR_RESP_NUM_DESC;
+
+#if 0
+ /* This bit of code does not work */
+ /* Let's see how many bytes were written in the async response
+ receive buf since last interrupt. This is done by finding
+ the next active context (See OHCI Spec p91) */
+ while (ohci->AR_resp_bytes_left <= AR_RESP_TOTAL_BUF_SIZE) {
+ if (ohci->AR_resp_prg[idx]->status&0x04000000) break;
+ idx = (idx+1) % AR_RESP_NUM_DESC;
+ PRINT(KERN_INFO,ohci->id,"crossing more than one buffer boundary !!!");
+ ohci->AR_resp_bytes_left += AR_RESP_BUF_SIZE;
}
+#endif
+ /* ASSUMPTION: only one buffer boundary is crossed */
+ rescount = ohci->AR_resp_prg[idx]->status&0xffff;
+ offset = AR_RESP_BUF_SIZE - rescount;
+ ohci->AR_resp_bytes_left += offset;
}
+ if (offset==AR_RESP_BUF_SIZE) {
+ offset=0;
+ idx = (idx+1) % AR_RESP_NUM_DESC;
+ }
+ ohci->AR_resp_buf_th_ind = idx;
+ ohci->AR_resp_buf_th_offset = offset;
- reg_write(ohci, OHCI1394_AsRspRcvCommandPtr,
- virt_to_bus(ohci->AR_resp_prg)|0x00000001);
- ohci->AR_resp_prg->status=AR_RESP_BUF_SIZE;
- reg_write(ohci, OHCI1394_AsRspRcvContextControlSet, 0x8000);
+ /* is buffer processing too slow? (all buffers used) */
+ if (ohci->AR_resp_bytes_left > AR_RESP_TOTAL_BUF_SIZE) {
+ stop_ar_resp_context(ohci,"async response receive processing too slow");
+ spin_unlock(&ohci->AR_resp_lock);
+ return;
+ }
+ spin_unlock(&ohci->AR_resp_lock);
- /* ---------------- end of FIXME --------------------------*/
+ /* queue bottom half in immediate queue */
+ queue_task(&ohci->AR_resp_pdl_task, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
}
if (event & OHCI1394_isochRx) {
quadlet_t isoRecvIntEvent;
@@ -826,8 +863,10 @@ static void ohci_irq_handler(int irq, void *dev_id,
send_next_async(ohci);
}
spin_unlock(&ohci->async_queue_lock);
+#if 0
PRINT(KERN_INFO,ohci->id,
"packet sent with ack code %d",ack);
+#endif
hpsb_packet_sent(host, packet, ack);
} else
PRINT(KERN_INFO,ohci->id,
@@ -839,6 +878,129 @@ static void ohci_irq_handler(int irq, void *dev_id,
ohci->NumInterrupts++;
}
+
+/* This is the bottom half that processes async response receive descriptor buffers. */
+static void ohci_ar_resp_proc_desc(void *data)
+{
+ quadlet_t *buf_ptr;
+ char *split_ptr;
+ unsigned int split_left;
+ struct ti_ohci *ohci= (struct ti_ohci*)data;
+ unsigned int packet_length;
+ unsigned int idx,offset,tcode;
+ unsigned long flags;
+ char msg[256];
+
+ spin_lock_irqsave(&ohci->AR_resp_lock, flags);
+
+ idx = ohci->AR_resp_buf_bh_ind;
+ offset = ohci->AR_resp_buf_bh_offset;
+
+ buf_ptr = ohci->AR_resp_buf[idx];
+ buf_ptr += offset/4;
+
+ while(ohci->AR_resp_bytes_left > 0) {
+
+ /* check to see if a fatal error occurred */
+ if ((ohci->AR_resp_prg[idx]->status >> 16) & 0x800) {
+ sprintf(msg,"fatal async response receive error -- status is %d",
+ ohci->AR_resp_prg[idx]->status & 0x1F);
+ stop_ar_resp_context(ohci, msg);
+ spin_unlock_irqrestore(&ohci->AR_resp_lock, flags);
+ return;
+ }
+
+ spin_unlock_irqrestore(&ohci->AR_resp_lock, flags);
+
+ /* Let's see what kind of packet is in there */
+ tcode = (buf_ptr[0]>>4)&0xf;
+ if (tcode==2) /* no-data receive */
+ packet_length=16;
+ else if (tcode==6) /* quadlet receive */
+ packet_length=20;
+ else if (tcode==7) { /* block receive */
+ /* Where is the data length ? */
+ if (offset+12>=AR_RESP_BUF_SIZE)
+ packet_length=(ohci->AR_resp_buf[(idx+1)%AR_RESP_NUM_DESC]
+ [3-(AR_RESP_BUF_SIZE-offset)/4]>>16)+20;
+ else
+ packet_length=(buf_ptr[3]>>16)+20;
+ if (packet_length % 4)
+ packet_length += 4 - (packet_length % 4);
+ }
+ else /* something is wrong */ {
+ sprintf(msg,"unexpected packet tcode %d in async response receive buffer",tcode);
+ stop_ar_resp_context(ohci,msg);
+ return;
+ }
+ if ((offset+packet_length)>AR_RESP_BUF_SIZE) {
+ /* we have a split packet */
+ if (packet_length>AR_RESP_SPLIT_PACKET_BUF_SIZE) {
+ sprintf(msg,"packet size %d bytes exceed split packet buffer size %d bytes",
+ packet_length,AR_RESP_SPLIT_PACKET_BUF_SIZE);
+ stop_ar_resp_context(ohci, msg);
+ return;
+ }
+ split_left = packet_length;
+ split_ptr = (char *)ohci->AR_resp_spb;
+ while (split_left>0) {
+ memcpy(split_ptr,buf_ptr,AR_RESP_BUF_SIZE-offset);
+ split_left -= AR_RESP_BUF_SIZE-offset;
+ split_ptr += AR_RESP_BUF_SIZE-offset;
+ ohci->AR_resp_prg[idx]->status = AR_RESP_BUF_SIZE;
+ idx = (idx+1) % AR_RESP_NUM_DESC;
+ buf_ptr = ohci->AR_resp_buf[idx];
+ offset=0;
+ while (split_left >= AR_RESP_BUF_SIZE) {
+ memcpy(split_ptr,buf_ptr,AR_RESP_BUF_SIZE);
+ split_ptr += AR_RESP_BUF_SIZE;
+ split_left -= AR_RESP_BUF_SIZE;
+ ohci->AR_resp_prg[idx]->status = AR_RESP_BUF_SIZE;
+ idx = (idx+1) % AR_RESP_NUM_DESC;
+ buf_ptr = ohci->AR_resp_buf[idx];
+ }
+ if (split_left>0) {
+ memcpy(split_ptr,buf_ptr,split_left);
+ offset = split_left;
+ split_left=0;
+ buf_ptr += split_left/4;
+ }
+ }
+#if 0
+ PRINT(KERN_INFO,ohci->id,"AR resp: received split packet tcode=%d length=%d",
+ tcode,packet_length);
+#endif
+ hpsb_packet_received(ohci->host, ohci->AR_resp_spb, packet_length);
+ ohci->AR_resp_bytes_left -= packet_length;
+ }
+ else {
+#if 0
+ PRINT(KERN_INFO,ohci->id,"AR resp: received packet tcode=%d length=%d",
+ tcode,packet_length);
+#endif
+ hpsb_packet_received(ohci->host, buf_ptr, packet_length);
+ offset += packet_length;
+ buf_ptr += packet_length/4;
+ ohci->AR_resp_bytes_left -= packet_length;
+ if (offset==AR_RESP_BUF_SIZE) {
+ ohci->AR_resp_prg[idx]->status = AR_RESP_BUF_SIZE;
+ idx = (idx+1) % AR_RESP_NUM_DESC;
+ buf_ptr = ohci->AR_resp_buf[idx];
+ offset=0;
+ }
+ }
+
+ }
+
+ if (ohci->AR_resp_bytes_left<0)
+ stop_ar_resp_context(ohci, "Sync problem in AR resp dma buffer");
+
+ ohci->AR_resp_buf_bh_ind = idx;
+ ohci->AR_resp_buf_bh_offset = offset;
+
+ spin_unlock_irqrestore(&ohci->AR_resp_lock, flags);
+}
+
/* This is the bottom half that processes iso receive descriptor buffers. */
static void ohci_ir_proc_desc(void *data)
{
@@ -1023,23 +1185,61 @@ static int add_card(struct pci_dev *dev)
FAIL("failed to allocate DMA buffer for self-id packets");
}
- /* AR dma buffer allocation */
- ohci->AR_resp_buf = kmalloc(AR_RESP_BUF_SIZE, GFP_KERNEL);
- if (ohci->AR_resp_buf != NULL) {
- memset(ohci->AR_resp_buf, 0, AR_RESP_BUF_SIZE);
- } else {
- FAIL("failed to allocate AR response DMA buffer");
+ /* AR dma buffer and program allocation */
+ ohci->AR_resp_buf=
+ kmalloc(AR_RESP_NUM_DESC * sizeof(quadlet_t*),
+ GFP_KERNEL);
+
+ if (ohci->AR_resp_buf == NULL) {
+ FAIL("failed to allocate AR response receive DMA buffer");
}
- /* AR dma program allocation */
- ohci->AR_resp_prg = (struct dma_cmd *) kmalloc(AR_RESP_PRG_SIZE,
- GFP_KERNEL);
- if (ohci->AR_resp_prg != NULL) {
- memset(ohci->AR_resp_prg, 0, AR_RESP_PRG_SIZE);
- } else {
- FAIL("failed to allocate AR response DMA program");
+ ohci->AR_resp_prg=
+ kmalloc(AR_RESP_NUM_DESC * sizeof(struct dma_cmd*),
+ GFP_KERNEL);
+
+ if (ohci->AR_resp_prg == NULL) {
+ FAIL("failed to allocate AR response receive DMA program");
+ }
+
+ ohci->AR_resp_spb= kmalloc(AR_RESP_SPLIT_PACKET_BUF_SIZE, GFP_KERNEL);
+
+ if (ohci->AR_resp_spb == NULL) {
+ FAIL("failed to allocate AR response split packet buffer");
+ }
+
+ for (i= 0; i < AR_RESP_NUM_DESC; i++) {
+ ohci->AR_resp_buf[i]= kmalloc(AR_RESP_BUF_SIZE, GFP_KERNEL);
+
+ if (ohci->AR_resp_buf[i] != NULL) {
+ memset(ohci->AR_resp_buf[i], 0, AR_RESP_BUF_SIZE);
+ } else {
+ FAIL("failed to allocate AR response DMA buffer");
+ }
+
+ ohci->AR_resp_prg[i]= kmalloc(sizeof(struct dma_cmd),
+ GFP_KERNEL);
+
+ if (ohci->AR_resp_prg[i] != NULL) {
+ memset(ohci->AR_resp_prg[i], 0,
+ sizeof(struct dma_cmd));
+ } else {
+ FAIL("failed to allocate AR response DMA buffer");
+ }
+
}
+ ohci->AR_resp_buf_th_ind = 0;
+ ohci->AR_resp_buf_th_offset = 0;
+ ohci->AR_resp_buf_bh_ind = 0;
+ ohci->AR_resp_buf_bh_offset = 0;
+ ohci->AR_resp_bytes_left = 0;
+ spin_lock_init(&ohci->AR_resp_lock);
+
+ /* initialize AR response receive task */
+ ohci->AR_resp_pdl_task.routine= ohci_ar_resp_proc_desc;
+ ohci->AR_resp_pdl_task.data= (void*)ohci;
+
/* AT dma program allocation */
ohci->AT_req_prg = (struct dma_cmd *) kmalloc(AT_REQ_PRG_SIZE,
GFP_KERNEL);
@@ -1129,8 +1329,12 @@ static int add_card(struct pci_dev *dev)
p += sprintf(p,fmt,reg_read(ohci, reg0),\
reg_read(ohci, reg1),reg_read(ohci, reg2));
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
+static int ohci_get_status(char *buf)
+#else
int ohci_get_info(char *buf, char **start, off_t fpos,
int length, int dummy)
+#endif
{
struct ti_ohci *ohci=&cards[0];
struct hpsb_host *host=ohci->host;
@@ -1165,15 +1369,23 @@ int ohci_get_info(char *buf, char **start, off_t fpos,
host->is_irm ? "iso_res_mgr" : "",
host->is_busmgr ? "bus_mgr" : "");
- p += sprintf(p,"\n### ohci data ###\n");
- p += sprintf(p,"AR_resp_buf : %p AR_resp_prg: %p\n",
- ohci->AR_resp_buf, ohci->AR_resp_prg);
-
+ p += sprintf(p,"\n---Iso Receive DMA---\n");
for (i= 0; i < IR_NUM_DESC; i++) {
p += sprintf(p, "IR_recv_buf[%d] : %p IR_recv_prg[%d]: %p\n",
i, ohci->IR_recv_buf[i], i, ohci->IR_recv_prg[i]);
}
+
+ p += sprintf(p,"\n---Async Reponse Receive DMA---\n");
+ for (i= 0; i < AR_RESP_NUM_DESC; i++) {
+ p += sprintf(p, "AR_resp_buf[%d] : %p AR_resp_prg[%d]: %p\n",
+ i, ohci->AR_resp_buf[i], i, ohci->AR_resp_prg[i]);
+ }
+ p += sprintf(p, "Current AR resp buf in irq handler: %d offset: %d\n",
+ ohci->AR_resp_buf_th_ind,ohci->AR_resp_buf_th_offset);
+ p += sprintf(p, "Current AR resp buf in bottom half: %d offset: %d\n",
+ ohci->AR_resp_buf_bh_ind,ohci->AR_resp_buf_bh_offset);
+
/* ----- Register Dump ----- */
p += sprintf(p,"\n### HC Register dump ###\n");
SR("Version : %08x GUID_ROM : %08x ATRetries : %08x\n",
@@ -1242,12 +1454,27 @@ int ohci_get_info(char *buf, char **start, off_t fpos,
phyreg&0x3f);
#endif
+#if 0
p += sprintf(p,"AR_resp_prg ctrl: %08x\n",ohci->AR_resp_prg->control);
p += sprintf(p,"AR_resp_prg status: %08x\n",ohci->AR_resp_prg->status);
+#endif
return p - buf;
}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
+static int ohci1394_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = ohci_get_status(page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+#else
struct proc_dir_entry ohci_proc_entry =
{
0, /* Inode number - dynamic */
@@ -1261,18 +1488,36 @@ struct proc_dir_entry ohci_proc_entry =
ohci_get_info, /* The read function for this file */
NULL
};
-#endif
+#endif /* LINUX_VERSION_CODE */
+#endif /* CONFIG_PROC_FS */
static void remove_card(struct ti_ohci *ohci)
{
if (ohci->registers)
iounmap(ohci->registers);
- if (ohci->AR_resp_buf)
- kfree(ohci->AR_resp_buf);
- if (ohci->AR_resp_prg)
- kfree(ohci->AR_resp_prg);
+
+ /* Free AR response buffers and programs */
+ if (ohci->AR_resp_buf) {
+ int i;
+ for (i= 0; i < AR_RESP_NUM_DESC; i++) {
+ kfree(ohci->AR_resp_buf[i]);
+ }
+ kfree(ohci->AR_resp_buf);
+ }
+ if (ohci->AR_resp_prg) {
+ int i;
+ for (i= 0; i < AR_RESP_NUM_DESC; i++) {
+ kfree(ohci->AR_resp_prg[i]);
+ }
+ kfree(ohci->AR_resp_prg);
+ }
+ kfree(ohci->AR_resp_spb);
+
+ /* Free AT request buffer and program */
if (ohci->AT_req_prg)
kfree(ohci->AT_req_prg);
+
+ /* Free Iso receive buffers and programs */
if (ohci->IR_recv_buf) {
int i;
for (i= 0; i < IR_NUM_DESC; i++) {
@@ -1288,11 +1533,16 @@ static void remove_card(struct ti_ohci *ohci)
kfree(ohci->IR_recv_prg);
}
kfree(ohci->IR_spb);
+
+ /* Free self-id buffer */
if (ohci->self_id_buffer)
kfree(ohci->self_id_buffer);
+
+ /* Free config rom */
if (ohci->csr_config_rom)
kfree(ohci->csr_config_rom);
+ /* Free the IRQ */
free_irq(ohci->dev->irq, ohci);
ohci->state = 0;
@@ -1327,11 +1577,15 @@ static int init_driver()
}
#ifdef CONFIG_PROC_FS
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
+ create_proc_read_entry ("ohci1394", 0, NULL, ohci1394_read_proc, NULL);
+#else
if (proc_register(&proc_root, &ohci_proc_entry)) {
PRINT_G(KERN_ERR, "unable to register proc file\n");
return -EIO;
}
#endif
+#endif
return 0;
}
@@ -1384,8 +1638,12 @@ void cleanup_module(void)
{
hpsb_unregister_lowlevel(get_ohci_template());
#ifdef CONFIG_PROC_FS
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
+ remove_proc_entry ("ohci1394", NULL);
+#else
proc_unregister(&proc_root, ohci_proc_entry.low_ino);
#endif
+#endif
PRINT_G(KERN_INFO, "removed " OHCI1394_DRIVER_NAME " module\n");
}
diff --git a/drivers/ieee1394/ohci1394.h b/drivers/ieee1394/ohci1394.h
index c6d7f469a..35d8fa2af 100644
--- a/drivers/ieee1394/ohci1394.h
+++ b/drivers/ieee1394/ohci1394.h
@@ -20,9 +20,15 @@
#define MAX_OHCI1394_CARDS 4
-#define AR_RESP_BUF_SIZE 4096
-#define AR_RESP_PRG_SIZE 256
-#define AT_REQ_PRG_SIZE 256
+#define OHCI1394_MAX_AT_REQ_RETRIES 1
+#define OHCI1394_MAX_AT_RESP_RETRIES 1
+#define OHCI1394_MAX_PHYS_RESP_RETRIES 4
+
+#define AR_RESP_NUM_DESC 4 /* number of AR resp descriptors */
+#define AR_RESP_BUF_SIZE 4096 /* size of AR resp buffers */
+#define AR_RESP_SPLIT_PACKET_BUF_SIZE 256 /* split packet buffer */
+#define AR_RESP_TOTAL_BUF_SIZE (AR_RESP_BUF_SIZE * AR_RESP_NUM_DESC)
+#define AT_REQ_PRG_SIZE 256
#define IR_RECV_BUF_SIZE 4096 /* 4096 bytes/buffer */
#define IR_SPLIT_PACKET_BUF_SIZE 8192 /* size of buffer for split packets */
@@ -49,8 +55,18 @@ struct ti_ohci {
quadlet_t *csr_config_rom; /* buffer for csr config rom */
/* asynchronous receive */
- struct dma_cmd *AR_resp_prg;
- quadlet_t *AR_resp_buf;
+ struct dma_cmd **AR_resp_prg;
+ quadlet_t **AR_resp_buf;
+ unsigned int AR_resp_buf_bh_ind;
+ unsigned int AR_resp_buf_bh_offset;
+ unsigned int AR_resp_buf_th_ind;
+ unsigned int AR_resp_buf_th_offset;
+ int AR_resp_bytes_left;
+ quadlet_t *AR_resp_spb;
+ spinlock_t AR_resp_lock;
+
+ /* async receive task */
+ struct tq_struct AR_resp_pdl_task;
/* asynchronous transmit */
struct dma_cmd *AT_req_prg;
diff --git a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c
index 596f95219..adc45896d 100644
--- a/drivers/ieee1394/raw1394.c
+++ b/drivers/ieee1394/raw1394.c
@@ -495,8 +495,8 @@ static int handle_local_request(struct file_info *fi,
if (req->req.length == 8) {
req->req.error = highlevel_lock(fi->host, req->data,
- addr, req->data[0],
- req->data[1],
+ addr, req->data[1],
+ req->data[0],
req->req.misc);
req->req.length = 4;
} else {
@@ -567,6 +567,32 @@ static int handle_remote_request(struct file_info *fi,
break;
case RAW1394_REQ_LOCK:
+ if ((req->req.misc != EXTCODE_FETCH_ADD)
+ && (req->req.misc != EXTCODE_LITTLE_ADD)) {
+ if (req->req.length != 4) {
+ req->req.error = RAW1394_ERROR_INVALID_ARG;
+ break;
+ }
+ } else {
+ if (req->req.length != 8) {
+ req->req.error = RAW1394_ERROR_INVALID_ARG;
+ break;
+ }
+ }
+
+ packet = hpsb_make_lockpacket(fi->host, node, addr,
+ req->req.misc);
+ if (!packet) return -ENOMEM;
+
+ if (copy_from_user(packet->data, req->req.sendb,
+ req->req.length)) {
+ req->req.error = RAW1394_ERROR_MEMFAULT;
+ break;
+ }
+
+ req->req.length = 4;
+ break;
+
case RAW1394_REQ_LOCK64:
default:
req->req.error = RAW1394_ERROR_STATE_ORDER;
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 03864c4ba..232075634 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -115,7 +115,7 @@ obj-$(CONFIG_NET) += Space.o setup.o net_init.o loopback.o
obj-$(CONFIG_SEEQ8005) += seeq8005.o
obj-$(CONFIG_ETHERTAP) += ethertap.o
obj-$(CONFIG_NET_SB1000) += sb1000.o
-obj-$(CONFIG_DAYNAPORT) += daynaport.o 8390.o
+obj-$(CONFIG_MAC8390) += daynaport.o 8390.o
obj-$(CONFIG_APNE) += apne.o 8390.o
obj-$(CONFIG_PCMCIA_PCNET) += 8390.o
obj-$(CONFIG_SHAPER) += shaper.o
@@ -248,6 +248,8 @@ obj-$(CONFIG_IPDDP) += ipddp.o
obj-$(CONFIG_RCPCI) += rcpci.o
obj-$(CONFIG_MACE) += mace.o
obj-$(CONFIG_MACSONIC) += macsonic.o
+obj-$(CONFIG_MACMACE) += macmace.o
+obj-$(CONFIG_MAC89x0) += mac89x0.o
obj-$(CONFIG_BMAC) += bmac.o
obj-$(CONFIG_NCR885E) += ncr885e.o
obj-$(CONFIG_ADAPTEC_STARFIRE) += starfire.o
diff --git a/drivers/net/Space.c b/drivers/net/Space.c
index dc18256ce..52c3a23d0 100644
--- a/drivers/net/Space.c
+++ b/drivers/net/Space.c
@@ -106,7 +106,13 @@ extern int dec_lance_probe(struct net_device *);
extern int mvme147lance_probe(struct net_device *dev);
extern int tc515_probe(struct net_device *dev);
extern int lance_probe(struct net_device *dev);
-extern int mac_onboard_sonic_probe(struct net_device *dev);
+extern int mace68k_probe(struct net_device *dev);
+extern int macsonic_probe(struct net_device *dev);
+extern int mac8390_probe(struct net_device *dev);
+extern int mac89x0_probe(struct net_device *dev);
+
+ /* Gigabit Ethernet adapters */
+ extern int yellowfin_probe(struct net_device *dev);
/* Detachable devices ("pocket adaptors") */
extern int atp_init(struct net_device *);
@@ -356,8 +362,17 @@ struct devprobe m68k_probes[] __initdata = {
#ifdef CONFIG_MVME147_NET /* MVME147 internal Ethernet */
{mvme147lance_probe, 0},
#endif
-#ifdef CONFIG_MACSONIC /* Mac 68k Quadra builtin Ethernet */
- {mac_onboard_sonic_probe, 0},
+#ifdef CONFIG_MACMACE /* Mac 68k Quadra AV builtin Ethernet */
+ {mace68k_probe, 0},
+#endif
+#ifdef CONFIG_MACSONIC /* Mac SONIC-based Ethernet of all sorts */
+ {macsonic_probe, 0},
+#endif
+#ifdef CONFIG_MAC8390 /* NuBus NS8390-based cards */
+ {mac8390_probe, 0},
+#endif
+#ifdef CONFIG_MAC89x0
+ {mac89x0_probe, 0},
#endif
{NULL, 0},
};
diff --git a/drivers/net/cs89x0.h b/drivers/net/cs89x0.h
index 42776088f..7e78805af 100644
--- a/drivers/net/cs89x0.h
+++ b/drivers/net/cs89x0.h
@@ -14,6 +14,8 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include <linux/config.h>
+
#define PP_ChipID 0x0000 /* offset 0h -> Corp -ID */
/* offset 2h -> Model/Product Number */
/* offset 3h -> Chip Revision Number */
@@ -77,6 +79,12 @@
#define ADD_MASK 0x3000 /* Mask it use of the ADD_PORT register */
#define ADD_SIG 0x3000 /* Expected ID signature */
+/* On Macs, we only need use the ISA I/O stuff until we do MEMORY_ON */
+#ifdef CONFIG_MAC
+#define LCSLOTBASE 0xfee00000
+#define MMIOBASE 0x40000
+#endif
+
#define CHIP_EISA_ID_SIG 0x630E /* Product ID Code for Crystal Chip (CS8900 spec 4.3) */
#ifdef IBMEIPKT
diff --git a/drivers/net/daynaport.c b/drivers/net/daynaport.c
index 02ebff8b6..724369bb8 100644
--- a/drivers/net/daynaport.c
+++ b/drivers/net/daynaport.c
@@ -1,4 +1,4 @@
-/* mac_ns8390.c: A Macintosh 8390 based ethernet driver for linux. */
+/* daynaport.c: A Macintosh 8390 based ethernet driver for linux. */
/*
Derived from code:
@@ -15,14 +15,20 @@
The block output routines may be wrong for non Dayna
cards
- Reading MAC addresses
-*/
+ Fix this driver so that it will attempt to use the info
+ (i.e. iobase, iosize) given to it by the new and improved
+ NuBus code.
+
+ Despite its misleading filename, this driver is not Dayna-specific
+ anymore. */
+/* Cabletron E6100 card support added by Tony Mantler (eek@escape.ca) April 1999 */
static const char *version =
- "mac_ns8390.c:v0.01 7/5/97 Alan Cox (Alan.Cox@linux.org)\n";
+ "daynaport.c: v0.02 1999-05-17 Alan Cox (Alan.Cox@linux.org) and others\n";
+static int version_printed = 0;
#include <linux/module.h>
-
+#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/errno.h>
@@ -31,20 +37,26 @@ static const char *version =
#include <asm/io.h>
#include <asm/system.h>
#include <asm/hwtest.h>
+#include <asm/macints.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include "8390.h"
-int ns8390_probe1(struct net_device *dev, int word16, char *name, int id, int prom);
+extern int console_loglevel;
+
+int ns8390_probe1(struct net_device *dev, int word16, char *name, int id,
+ int prom, struct nubus_dev *ndev);
static int ns8390_open(struct net_device *dev);
static void ns8390_no_reset(struct net_device *dev);
static int ns8390_close_card(struct net_device *dev);
+/* Interlan */
static void interlan_reset(struct net_device *dev);
+/* Dayna */
static void dayna_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
int ring_page);
static void dayna_block_input(struct net_device *dev, int count,
@@ -52,6 +64,7 @@ static void dayna_block_input(struct net_device *dev, int count,
static void dayna_block_output(struct net_device *dev, int count,
const unsigned char *buf, const int start_page);
+/* Sane (32-bit chunk memory read/write) */
static void sane_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
int ring_page);
static void sane_block_input(struct net_device *dev, int count,
@@ -59,6 +72,7 @@ static void sane_block_input(struct net_device *dev, int count,
static void sane_block_output(struct net_device *dev, int count,
const unsigned char *buf, const int start_page);
+/* Slow Sane (16-bit chunk memory read/write) */
static void slow_sane_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
int ring_page);
static void slow_sane_block_input(struct net_device *dev, int count,
@@ -71,6 +85,10 @@ static void slow_sane_block_output(struct net_device *dev, int count,
#define WD03_STOP_PG 0x20 /* Last page +1 of RX ring */
#define WD13_STOP_PG 0x40 /* Last page +1 of RX ring */
+#define CABLETRON_RX_START_PG 0x00 /* First page of RX buffer */
+#define CABLETRON_RX_STOP_PG 0x30 /* Last page +1 of RX ring */
+#define CABLETRON_TX_START_PG CABLETRON_RX_STOP_PG /* First page of TX buffer */
+
#define DAYNA_MAC_BASE 0xf0007
#define DAYNA_8390_BASE 0x80000 /* 3 */
@@ -81,9 +99,14 @@ static void slow_sane_block_output(struct net_device *dev, int count,
#define APPLE_8390_MEM 0xD0000
#define APPLE_MEMSIZE 8192 /* FIXME: need to dynamically check */
-#define KINETICS_8390_BASE 0x80003
-#define KINETICS_8390_MEM 0x00000
+#define KINETICS_MAC_BASE 0xf0004 /* first byte of each long */
+#define KINETICS_8390_BASE 0x80000
+#define KINETICS_8390_MEM 0x00000 /* first word of each long */
#define KINETICS_MEMSIZE 8192 /* FIXME: need to dynamically check */
+/*#define KINETICS_MEMSIZE (0x10000/2) * CSA: on the board I have, at least */
+
+#define CABLETRON_8390_BASE 0x90000
+#define CABLETRON_8390_MEM 0x00000
static int test_8390(volatile char *ptr, int scale)
{
@@ -113,34 +136,59 @@ static int test_8390(volatile char *ptr, int scale)
* Identify the species of NS8390 card/driver we need
*/
-#define NS8390_DAYNA 1
-#define NS8390_INTERLAN 2
-#define NS8390_KINETICS 3
-#define NS8390_APPLE 4
-#define NS8390_FARALLON 5
-#define NS8390_ASANTE 6
+enum mac8390_type {
+ NS8390_DAYNA,
+ NS8390_INTERLAN,
+ NS8390_KINETICS,
+ NS8390_APPLE,
+ NS8390_FARALLON,
+ NS8390_ASANTE,
+ NS8390_CABLETRON
+};
-int ns8390_ident(struct nubus_type *nb)
+int __init ns8390_ident(struct nubus_dev* ndev)
{
- /* It appears anything with a software type of 0 is an apple
- compatible - even if the hardware matches others */
-
- if(nb->DrSW==0x0001 || nb->DrSW==0x0109 || nb->DrSW==0x0000 || nb->DrSW==0x0100)
- return NS8390_APPLE;
-
+ /* This really needs to be tested and tested hard. */
+
+ /* Summary of what we know so far --
+ * SW: 0x0104 -- asante, 16 bit, back4_offsets
+ * SW: 0x010b -- daynaport, 16 bit, fwrd4_offsets
+ * SW: 0x010c -- farallon, 16 bit, back4_offsets, no long word access
+ * SW: 0x011a -- focus, [no details yet]
+ * SW: ?????? -- interlan, 16 bit, back4_offsets, funny reset
+ * SW: ?????? -- kinetics, 8 bit, back4_offsets
+ * -- so i've this hypothesis going that says DrSW&1 says whether the
+ * map is forward or backwards -- and maybe DrSW&256 says what the
+ * register spacing is -- for all cards that report a DrSW in some
+ * range.
+ * This would allow the "apple compatible" driver to drive many
+ * seemingly different types of cards. More DrSW info is needed
+ * to investigate this properly. [CSA, 21-May-1999]
+ */
/* Dayna ex Kinetics board */
- if(nb->DrHW==0x0103)
+ if(ndev->dr_sw == NUBUS_DRSW_DAYNA)
return NS8390_DAYNA;
-
- /* Asante board */
- if(nb->DrHW==0x0104)
+ if(ndev->dr_sw == NUBUS_DRSW_ASANTE)
return NS8390_ASANTE;
- if(nb->DrHW==0x0100)
- return NS8390_INTERLAN;
- if(nb->DrHW==0x0106)
- return NS8390_KINETICS;
- if(nb->DrSW==0x010C)
+ if(ndev->dr_sw == NUBUS_DRSW_FARALLON) /* farallon or sonic systems */
return NS8390_FARALLON;
+ if(ndev->dr_sw == NUBUS_DRSW_KINETICS)
+ return NS8390_KINETICS;
+ /* My ATI Engineering card with this combination crashes the */
+ /* driver trying to xmit packets. Best not touch it for now. */
+ /* - 1999-05-20 (funaho@jurai.org) */
+ if(ndev->dr_sw == NUBUS_DRSW_FOCUS)
+ return -1;
+
+ /* Check the HW on this one, because it shares the same DrSW as
+ the on-board SONIC chips */
+ if(ndev->dr_hw == NUBUS_DRHW_CABLETRON)
+ return NS8390_CABLETRON;
+ /* does anyone have one of these? */
+ if(ndev->dr_hw == NUBUS_DRHW_INTERLAN)
+ return NS8390_INTERLAN;
+
+ /* FIXME: what do genuine Apple boards look like? */
return -1;
}
@@ -148,7 +196,7 @@ int ns8390_ident(struct nubus_type *nb)
* Memory probe for 8390 cards
*/
-int apple_8390_mem_probe(volatile unsigned short *p)
+int __init apple_8390_mem_probe(volatile unsigned short *p)
{
int i, j;
/*
@@ -192,61 +240,79 @@ int apple_8390_mem_probe(volatile unsigned short *p)
/*
* Probe for 8390 cards.
* The ns8390_probe1() routine initializes the card and fills the
- * station address field. On entry base_addr is set, irq is set
- * (These come from the nubus probe code). dev->mem_start points
+ * station address field.
+ *
+ * The NuBus interface has changed! We now scan for these somewhat
+ * like how the PCI and Zorro drivers do. It's not clear whether
+ * this is actually better, but it makes things more consistent.
+ *
+ * dev->mem_start points
* at the memory ring, dev->mem_end gives the end of it.
*/
-int ns8390_probe(struct nubus_device_specifier *d, int slot, struct nubus_type *match)
+int __init mac8390_probe(struct net_device *dev)
{
- struct net_device *dev;
+ static int slots = 0;
volatile unsigned short *i;
volatile unsigned char *p;
int plen;
int id;
+ static struct nubus_dev* ndev = NULL;
+
+ /* Find the first card that hasn't already been seen */
+ while ((ndev = nubus_find_type(NUBUS_CAT_NETWORK,
+ NUBUS_TYPE_ETHERNET, ndev)) != NULL) {
+ /* Have we seen it already? */
+ if (slots & (1<<ndev->board->slot))
+ continue;
+ slots |= 1<<ndev->board->slot;
+
+ /* Is it one of ours? */
+ if ((id = ns8390_ident(ndev)) != -1)
+ break;
+ }
- if(match->category!=NUBUS_CAT_NETWORK || match->type!=1)
- return -ENODEV;
- /* Ok so it is an ethernet network device */
- if((id=ns8390_ident(match))==-1)
- {
- printk("Ethernet but type unknown %d\n",match->DrHW);
+ /* Hm. No more cards, then */
+ if (ndev == NULL)
return -ENODEV;
+
+ dev = init_etherdev(dev, 0);
+
+ if (!version_printed) {
+ printk(KERN_INFO "%s", version);
+ version_printed = 1;
}
- dev = init_etherdev(0, 0);
- if(dev==NULL)
- return -ENOMEM;
/*
* Dayna specific init
*/
if(id==NS8390_DAYNA)
{
- dev->base_addr=(int)(nubus_slot_addr(slot)+DAYNA_8390_BASE);
- dev->mem_start=(int)(nubus_slot_addr(slot)+DAYNA_8390_MEM);
- dev->mem_end=dev->mem_start+DAYNA_MEMSIZE; /* 8K it seems */
+ dev->base_addr = (int)(ndev->board->slot_addr+DAYNA_8390_BASE);
+ dev->mem_start = (int)(ndev->board->slot_addr+DAYNA_8390_MEM);
+ dev->mem_end = dev->mem_start+DAYNA_MEMSIZE; /* 8K it seems */
- printk("daynaport: testing board: ");
-
+ printk(KERN_INFO "%s: daynaport. testing board: ", dev->name);
+
printk("memory - ");
-
- i=(void *)dev->mem_start;
+
+ i = (void *)dev->mem_start;
memset((void *)i,0xAA, DAYNA_MEMSIZE);
while(i<(volatile unsigned short *)dev->mem_end)
{
if(*i!=0xAAAA)
goto membad;
- *i=0x5555;
- if(*i!=0x5555)
+ *i=0x5678; /* make sure we catch byte smearing */
+ if(*i!=0x5678)
goto membad;
i+=2; /* Skip a word */
}
-
+
printk("controller - ");
-
+
p=(void *)dev->base_addr;
plen=0;
-
+
while(plen<0x3FF00)
{
if(test_8390(p,0)==0)
@@ -263,26 +329,71 @@ int ns8390_probe(struct nubus_device_specifier *d, int slot, struct nubus_type *
if(plen==0x3FF00)
goto membad;
printk("OK\n");
- dev->irq=slot;
- if(ns8390_probe1(dev, 0, "dayna", id, -1)==0)
- return 0;
+ dev->irq = SLOT2IRQ(ndev->board->slot);
+ if(ns8390_probe1(dev, 0, "dayna", id, -1, ndev)==0)
+ return 0;
+ }
+ /* Cabletron */
+ if (id==NS8390_CABLETRON) {
+ int memsize = 16<<10; /* fix this */
+
+ dev->base_addr=(int)(ndev->board->slot_addr+CABLETRON_8390_BASE);
+ dev->mem_start=(int)(ndev->board->slot_addr+CABLETRON_8390_MEM);
+ dev->mem_end=dev->mem_start+memsize;
+ dev->irq = SLOT2IRQ(ndev->board->slot);
+
+ /* The base address is unreadable if 0x00 has been written to the command register */
+ /* Reset the chip by writing E8390_NODMA+E8390_PAGE0+E8390_STOP just to be sure */
+ i = (void *)dev->base_addr;
+ *i = 0x21;
+
+ printk(KERN_INFO "%s: cabletron: testing board: ", dev->name);
+ printk("%dK memory - ", memsize>>10);
+ i=(void *)dev->mem_start;
+ while(i<(volatile unsigned short *)(dev->mem_start+memsize))
+ {
+ *i=0xAAAA;
+ if(*i!=0xAAAA)
+ goto membad;
+ *i=0x5555;
+ if(*i!=0x5555)
+ goto membad;
+ i+=2; /* Skip a word */
+ }
+ printk("OK\n");
+
+ if(ns8390_probe1(dev, 1, "cabletron", id, -1, ndev)==0)
+ return 0;
}
/* Apple, Farallon, Asante */
- if(id==NS8390_APPLE|| id==NS8390_FARALLON || id==NS8390_ASANTE)
+ if(id==NS8390_APPLE || id==NS8390_FARALLON || id==NS8390_ASANTE)
{
int memsize;
-
- dev->base_addr=(int)(nubus_slot_addr(slot)+APPLE_8390_BASE);
- dev->mem_start=(int)(nubus_slot_addr(slot)+APPLE_8390_MEM);
-
+
+ dev->base_addr=(int)(ndev->board->slot_addr+APPLE_8390_BASE);
+ dev->mem_start=(int)(ndev->board->slot_addr+APPLE_8390_MEM);
+
memsize = apple_8390_mem_probe((void *)dev->mem_start);
-
+
dev->mem_end=dev->mem_start+memsize;
- dev->irq=slot;
- printk("apple/clone: testing board: ");
-
+ dev->irq = SLOT2IRQ(ndev->board->slot);
+
+ switch(id)
+ {
+ case NS8390_FARALLON:
+ printk(KERN_INFO "%s: farallon: testing board: ", dev->name);
+ break;
+ case NS8390_ASANTE:
+ printk(KERN_INFO "%s: asante: testing board: ", dev->name);
+ break;
+ case NS8390_APPLE:
+ default:
+ printk(KERN_INFO "%s: apple/clone: testing board: ", dev->name);
+ break;
+ }
+
printk("%dK memory - ", memsize>>10);
-
+
i=(void *)dev->mem_start;
memset((void *)i,0xAA, memsize);
while(i<(volatile unsigned short *)dev->mem_end)
@@ -295,51 +406,75 @@ int ns8390_probe(struct nubus_device_specifier *d, int slot, struct nubus_type *
i+=2; /* Skip a word */
}
printk("OK\n");
-
- if(id==NS8390_FARALLON)
+
+ switch (id)
{
- if(ns8390_probe1(dev, 1, "farallon", id, -1)==0)
+ case NS8390_FARALLON:
+ if(ns8390_probe1(dev, 1, "farallon", id, -1, ndev)==0)
return 0;
- }
- else
- {
- if(ns8390_probe1(dev, 1, "apple/clone", id, -1)==0)
- return 0;
+ break;
+ case NS8390_ASANTE:
+ if(ns8390_probe1(dev, 1, "asante", id, -1, ndev)==0)
+ return 0;
+ break;
+ case NS8390_APPLE:
+ default:
+ if(ns8390_probe1(dev, 1, "apple/clone", id, -1, ndev)==0)
+ return 0;
+ break;
}
}
/* Interlan */
if(id==NS8390_INTERLAN)
{
/* As apple and asante */
- dev->base_addr=(int)(nubus_slot_addr(slot)+APPLE_8390_BASE);
- dev->mem_start=(int)(nubus_slot_addr(slot)+APPLE_8390_MEM);
+ dev->base_addr=(int)(ndev->board->slot_addr+APPLE_8390_BASE);
+ dev->mem_start=(int)(ndev->board->slot_addr+APPLE_8390_MEM);
dev->mem_end=dev->mem_start+APPLE_MEMSIZE; /* 8K it seems */
- dev->irq=slot;
- if(ns8390_probe1(dev, 1, "interlan", id, -1)==0)
+ dev->irq = SLOT2IRQ(ndev->board->slot);
+ if(ns8390_probe1(dev, 1, "interlan", id, -1, ndev)==0)
return 0;
}
- /* Kinetics */
+ /* Kinetics (Shiva Etherport) */
if(id==NS8390_KINETICS)
{
- dev->base_addr=(int)(nubus_slot_addr(slot)+KINETICS_8390_BASE);
- dev->mem_start=(int)(nubus_slot_addr(slot)+KINETICS_8390_MEM);
+ dev->base_addr=(int)(ndev->board->slot_addr+KINETICS_8390_BASE);
+ dev->mem_start=(int)(ndev->board->slot_addr+KINETICS_8390_MEM);
dev->mem_end=dev->mem_start+KINETICS_MEMSIZE; /* 8K it seems */
- dev->irq=slot;
- if(ns8390_probe1(dev, 0, "kinetics", id, -1)==0)
+ dev->irq = SLOT2IRQ(ndev->board->slot);
+ if(ns8390_probe1(dev, 0, "kinetics", id, -1, ndev)==0)
return 0;
}
- kfree(dev);
+
+ /* We should hopefully not get here */
+ printk(KERN_ERR "Probe unsucessful.\n");
return -ENODEV;
-membad:
- printk("failed.\n");
- kfree(dev);
+
+ membad:
+ printk(KERN_ERR "failed at %p in %p - %p.\n", i,
+ (void *)dev->mem_start, (void *)dev->mem_end);
return -ENODEV;
}
-int ns8390_probe1(struct net_device *dev, int word16, char *model_name, int type, int promoff)
+int __init mac8390_ethernet_addr(struct nubus_dev* ndev,
+ unsigned char addr[6])
{
- static unsigned version_printed = 0;
+ struct nubus_dir dir;
+ struct nubus_dirent ent;
+
+ /* Get the functional resource for this device */
+ if (nubus_get_func_dir(ndev, &dir) == -1)
+ return -1;
+ if (nubus_find_rsrc(&dir, NUBUS_RESID_MAC_ADDRESS, &ent) == -1)
+ return -1;
+
+ nubus_get_rsrc_mem(addr, &ent, 6);
+ return 0;
+}
+int __init ns8390_probe1(struct net_device *dev, int word16, char *model_name,
+ int type, int promoff, struct nubus_dev *ndev)
+{
static u32 fwrd4_offsets[16]={
0, 4, 8, 12,
16, 20, 24, 28,
@@ -352,25 +487,19 @@ int ns8390_probe1(struct net_device *dev, int word16, char *model_name, int type
28, 24, 20, 16,
12, 8, 4, 0
};
+ static u32 fwrd2_offsets[16]={
+ 0, 2, 4, 6,
+ 8, 10, 12, 14,
+ 16, 18, 20, 22,
+ 24, 26, 28, 30
+ };
- unsigned char *prom=((unsigned char *)nubus_slot_addr(dev->irq))+promoff;
+ unsigned char *prom = (unsigned char*) ndev->board->slot_addr + promoff;
- if (ei_debug && version_printed++ == 0)
- printk(version);
-
- /* Snarf the interrupt now. There's no point in waiting since we cannot
- share a slot! and the board will usually be enabled. */
- if (nubus_request_irq(dev->irq, dev, ei_interrupt))
- {
- printk (" unable to get nubus IRQ %d.\n", dev->irq);
- return EAGAIN;
- }
-
/* Allocate dev->priv and fill in 8390 specific dev fields. */
if (ethdev_init(dev))
{
- printk (" unable to get memory for dev->priv.\n");
- nubus_free_irq(dev->irq);
+ printk ("%s: unable to get memory for dev->priv.\n", dev->name);
return -ENOMEM;
}
@@ -378,16 +507,25 @@ int ns8390_probe1(struct net_device *dev, int word16, char *model_name, int type
ei_status.name = model_name;
ei_status.word16 = word16;
- ei_status.tx_start_page = WD_START_PG;
- ei_status.rx_start_page = WD_START_PG + TX_PAGES;
- dev->rmem_start = dev->mem_start + TX_PAGES*256;
- ei_status.stop_page = (dev->mem_end - dev->mem_start)/256;
- dev->rmem_end = dev->mem_end;
+ if (type==NS8390_CABLETRON) {
+ /* Cabletron card puts the RX buffer before the TX buffer */
+ ei_status.tx_start_page = CABLETRON_TX_START_PG;
+ ei_status.rx_start_page = CABLETRON_RX_START_PG;
+ ei_status.stop_page = CABLETRON_RX_STOP_PG;
+ dev->rmem_start = dev->mem_start;
+ dev->rmem_end = dev->mem_start + CABLETRON_RX_STOP_PG*256;
+ } else {
+ ei_status.tx_start_page = WD_START_PG;
+ ei_status.rx_start_page = WD_START_PG + TX_PAGES;
+ ei_status.stop_page = (dev->mem_end - dev->mem_start)/256;
+ dev->rmem_start = dev->mem_start + TX_PAGES*256;
+ dev->rmem_end = dev->mem_end;
+ }
if(promoff==-1) /* Use nubus resources ? */
{
- if(nubus_ethernet_addr(dev->irq /* slot */, dev->dev_addr))
+ if(mac8390_ethernet_addr(ndev, dev->dev_addr))
{
printk("mac_ns8390: MAC address not in resources!\n");
return -ENODEV;
@@ -400,7 +538,7 @@ int ns8390_probe1(struct net_device *dev, int word16, char *model_name, int type
/* These should go in the end I hope */
if(type==NS8390_DAYNA)
x=2;
- if(type==NS8390_INTERLAN)
+ if(type==NS8390_INTERLAN || type==NS8390_KINETICS)
x=4;
while(i<6)
{
@@ -412,12 +550,24 @@ int ns8390_probe1(struct net_device *dev, int word16, char *model_name, int type
}
}
- printk(" %s, IRQ %d, shared memory at %#lx-%#lx.\n",
- model_name, dev->irq, dev->mem_start, dev->mem_end-1);
+ printk(KERN_INFO "%s: %s in slot %X (type %s)\n",
+ dev->name, ndev->board->name, ndev->board->slot, model_name);
+ printk(KERN_INFO "MAC ");
+ {
+ int i;
+ for (i = 0; i < 6; i++) {
+ printk("%2.2x", dev->dev_addr[i]);
+ if (i < 5)
+ printk(":");
+ }
+ }
+ printk(" IRQ %d, shared memory at %#lx-%#lx.\n",
+ dev->irq, dev->mem_start, dev->mem_end-1);
switch(type)
{
case NS8390_DAYNA: /* Dayna card */
+ case NS8390_KINETICS: /* Kinetics -- 8 bit config, but 16 bit mem */
/* 16 bit, 4 word offsets */
ei_status.reset_8390 = &ns8390_no_reset;
ei_status.block_input = &dayna_block_input;
@@ -425,6 +575,15 @@ int ns8390_probe1(struct net_device *dev, int word16, char *model_name, int type
ei_status.get_8390_hdr = &dayna_get_8390_hdr;
ei_status.reg_offset = fwrd4_offsets;
break;
+ case NS8390_CABLETRON: /* Cabletron */
+ /* 16 bit card, register map is short forward */
+ ei_status.reset_8390 = &ns8390_no_reset;
+ /* Ctron card won't accept 32bit values read or written to it */
+ ei_status.block_input = &slow_sane_block_input;
+ ei_status.block_output = &slow_sane_block_output;
+ ei_status.get_8390_hdr = &slow_sane_get_8390_hdr;
+ ei_status.reg_offset = fwrd2_offsets;
+ break;
case NS8390_FARALLON:
case NS8390_APPLE: /* Apple/Asante/Farallon */
/* 16 bit card, register map is reversed */
@@ -450,6 +609,8 @@ int ns8390_probe1(struct net_device *dev, int word16, char *model_name, int type
ei_status.get_8390_hdr = &sane_get_8390_hdr;
ei_status.reg_offset = back4_offsets;
break;
+#if 0 /* i think this suffered code rot. my kinetics card has much
+ * different settings. -- CSA [22-May-1999] */
case NS8390_KINETICS: /* Kinetics */
/* 8bit card, map is forward */
ei_status.reset_8390 = &ns8390_no_reset;
@@ -458,6 +619,7 @@ int ns8390_probe1(struct net_device *dev, int word16, char *model_name, int type
ei_status.get_8390_hdr = &sane_get_8390_hdr;
ei_status.reg_offset = back4_offsets;
break;
+#endif
default:
panic("Detected a card I can't drive - whoops\n");
}
@@ -472,6 +634,19 @@ int ns8390_probe1(struct net_device *dev, int word16, char *model_name, int type
static int ns8390_open(struct net_device *dev)
{
ei_open(dev);
+
+ /* At least on my card (a Focus Enhancements PDS card) I start */
+ /* getting interrupts right away, so the driver needs to be */
+ /* completely initialized before enabling the interrupt. */
+ /* - funaho@jurai.org (1999-05-17) */
+
+ /* Non-slow interrupt, works around issues with the SONIC driver */
+ if (request_irq(dev->irq, ei_interrupt, 0, "8390 Ethernet", dev))
+ {
+ printk ("%s: unable to get IRQ %d.\n", dev->name, dev->irq);
+ return EAGAIN;
+ }
+
MOD_INC_USE_COUNT;
return 0;
}
@@ -489,24 +664,19 @@ static int ns8390_close_card(struct net_device *dev)
{
if (ei_debug > 1)
printk("%s: Shutting down ethercard.\n", dev->name);
+ free_irq(dev->irq, dev);
ei_close(dev);
MOD_DEC_USE_COUNT;
return 0;
}
-struct nubus_device_specifier nubus_8390={
- ns8390_probe,
- NULL
-};
-
-
/*
* Interlan Specific Code Starts Here
*/
static void interlan_reset(struct net_device *dev)
{
- unsigned char *target=nubus_slot_addr(dev->irq);
+ unsigned char *target=nubus_slot_addr(IRQ2SLOT(dev->irq));
if (ei_debug > 1)
printk("Need to reset the NS8390 t=%lu...", jiffies);
ei_status.txing = 0;
@@ -531,16 +701,23 @@ static void interlan_reset(struct net_device *dev)
The only complications are that the ring buffer wraps.
*/
-static void dayna_cpu_memcpy(struct net_device *dev, void *to, int from, int count)
+static void dayna_memcpy_fromcard(struct net_device *dev, void *to, int from, int count)
{
volatile unsigned short *ptr;
unsigned short *target=to;
from<<=1; /* word, skip overhead */
ptr=(unsigned short *)(dev->mem_start+from);
+ /*
+ * Leading byte?
+ */
+ if (from&2) {
+ *((char *)target)++ = *(((char *)ptr++)-1);
+ count--;
+ }
while(count>=2)
{
*target++=*ptr++; /* Copy and */
- ptr++; /* Cruft and */
+ ptr++; /* skip cruft */
count-=2;
}
/*
@@ -554,16 +731,24 @@ static void dayna_cpu_memcpy(struct net_device *dev, void *to, int from, int cou
}
}
-static void cpu_dayna_memcpy(struct net_device *dev, int to, const void *from, int count)
+static void dayna_memcpy_tocard(struct net_device *dev, int to, const void *from, int count)
{
volatile unsigned short *ptr;
const unsigned short *src=from;
to<<=1; /* word, skip overhead */
ptr=(unsigned short *)(dev->mem_start+to);
+ /*
+ * Leading byte?
+ */
+ if (to&2) { /* avoid a byte write (stomps on other data) */
+ ptr[-1] = (ptr[-1]&0xFF00)|*((unsigned char *)src)++;
+ ptr++;
+ count--;
+ }
while(count>=2)
{
*ptr++=*src++; /* Copy and */
- ptr++; /* Cruft and */
+ ptr++; /* skip cruft */
count-=2;
}
/*
@@ -573,14 +758,15 @@ static void cpu_dayna_memcpy(struct net_device *dev, int to, const void *from, i
{
/* Big endian */
unsigned short v=*src;
- *((char *)ptr)=v>>8;
+ /* card doesn't like byte writes */
+ *ptr=(*ptr&0x00FF)|(v&0xFF00);
}
}
static void dayna_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
{
unsigned long hdr_start = (ring_page - WD_START_PG)<<8;
- dayna_cpu_memcpy(dev, (void *)hdr, hdr_start, 4);
+ dayna_memcpy_fromcard(dev, (void *)hdr, hdr_start, 4);
/* Register endianism - fix here rather than 8390.c */
hdr->count=(hdr->count&0xFF)<<8|(hdr->count>>8);
}
@@ -599,14 +785,14 @@ static void dayna_block_input(struct net_device *dev, int count, struct sk_buff
{
/* We must wrap the input move. */
int semi_count = dev->rmem_end - xfer_start;
- dayna_cpu_memcpy(dev, skb->data, xfer_base, semi_count);
+ dayna_memcpy_fromcard(dev, skb->data, xfer_base, semi_count);
count -= semi_count;
- dayna_cpu_memcpy(dev, skb->data + semi_count,
+ dayna_memcpy_fromcard(dev, skb->data + semi_count,
dev->rmem_start - dev->mem_start, count);
}
else
{
- dayna_cpu_memcpy(dev, skb->data, xfer_base, count);
+ dayna_memcpy_fromcard(dev, skb->data, xfer_base, count);
}
}
@@ -615,7 +801,7 @@ static void dayna_block_output(struct net_device *dev, int count, const unsigned
{
long shmem = (start_page - WD_START_PG)<<8;
- cpu_dayna_memcpy(dev, shmem, buf, count);
+ dayna_memcpy_tocard(dev, shmem, buf, count);
}
/*
@@ -739,6 +925,7 @@ static void slow_sane_block_output(struct net_device *dev, int count, const unsi
* Local variables:
* compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c daynaport.c"
* version-control: t
+ * c-basic-offset: 4
* tab-width: 4
* kept-new-versions: 5
* End:
diff --git a/drivers/net/irda/Config.in b/drivers/net/irda/Config.in
index da1df253c..da0b5f4be 100644
--- a/drivers/net/irda/Config.in
+++ b/drivers/net/irda/Config.in
@@ -6,10 +6,12 @@ dep_tristate 'IrTTY (uses Linux serial driver)' CONFIG_IRTTY_SIR $CONFIG_IRDA
dep_tristate 'IrPORT (IrDA serial driver)' CONFIG_IRPORT_SIR $CONFIG_IRDA
comment 'FIR device drivers'
-dep_tristate 'NSC PC87108/PC97338' CONFIG_NSC_FIR $CONFIG_IRDA
+dep_tristate 'NSC PC87108/PC87338' CONFIG_NSC_FIR $CONFIG_IRDA
dep_tristate 'Winbond W83977AF (IR)' CONFIG_WINBOND_FIR $CONFIG_IRDA
dep_tristate 'Toshiba Type-O IR Port' CONFIG_TOSHIBA_FIR $CONFIG_IRDA
-dep_tristate 'SMC IrCC' CONFIG_SMC_IRCC_FIR $CONFIG_IRDA
+if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
+dep_tristate 'SMC IrCC (Experimental)' CONFIG_SMC_IRCC_FIR $CONFIG_IRDA
+fi
comment 'Dongle support'
bool 'Serial dongle support' CONFIG_DONGLE
@@ -19,9 +21,7 @@ if [ "$CONFIG_DONGLE" != "n" ]; then
dep_tristate ' Tekram IrMate 210B dongle' CONFIG_TEKRAM_DONGLE $CONFIG_IRDA
dep_tristate ' Greenwich GIrBIL dongle' CONFIG_GIRBIL_DONGLE $CONFIG_IRDA
dep_tristate ' Parallax LiteLink dongle' CONFIG_LITELINK_DONGLE $CONFIG_IRDA
- dep_tristate ' Adaptec Airport 1000/2000 dongle' CONFIG_AIRPORT_DONGLE $CONFIG_IRDA
- dep_tristate ' Old Belkin dongle' CONFIG_OLD_BELKIN_DONGLE $CONFIG_IRDA
-
+ dep_tristate ' Old Belkin dongle' CONFIG_OLD_BELKIN_DONGLE $CONFIG_IRDA
fi
endmenu
diff --git a/drivers/net/irda/Makefile b/drivers/net/irda/Makefile
index bf5628ebd..291a27f05 100644
--- a/drivers/net/irda/Makefile
+++ b/drivers/net/irda/Makefile
@@ -29,10 +29,10 @@ else
endif
ifeq ($(CONFIG_NSC_FIR),y)
-L_OBJS += nsc_fir.o
+L_OBJS += nsc-ircc.o
else
ifeq ($(CONFIG_NSC_FIR),m)
- M_OBJS += nsc_fir.o
+ M_OBJS += nsc-ircc.o
endif
endif
@@ -118,14 +118,6 @@ else
endif
endif
-ifeq ($(CONFIG_AIRPORT_DONGLE),y)
-L_OBJS += airport.o
-else
- ifeq ($(CONFIG_AIRPORT_DONGLE),m)
- M_OBJS += airport.o
- endif
-endif
-
ifeq ($(CONFIG_OLD_BELKIN_DONGLE),y)
L_OBJS += old_belkin.o
else
diff --git a/drivers/net/irda/airport.c b/drivers/net/irda/airport.c
deleted file mode 100644
index b68378189..000000000
--- a/drivers/net/irda/airport.c
+++ /dev/null
@@ -1,358 +0,0 @@
-/*********************************************************************
- *
- * Filename: airport.c
- * Version: 0.2
- * Description: Implementation for the Adaptec Airport 1000 and 2000
- * dongles
- * Status: Experimental.
- * Author: Fons Botman <budely@tref.nl>
- * Created at: Wed May 19 23:14:34 CEST 1999
- * Based on: actisys.c by Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1998-1999 Fons Botman, All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * Neither Fons Botman nor anyone else admit liability nor
- * provide warranty for any of this software. This material is
- * provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/tty.h>
-#include <linux/sched.h>
-#include <linux/init.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/irmod.h>
-#include <net/irda/irda_device.h>
-
-static int airport_reset_wrapper(struct irda_task *task);
-static void airport_open(dongle_t *self, struct qos_info *qos);
-static void airport_close(dongle_t *self);
-static int airport_change_speed_wrapper(struct irda_task *task);
-
-static struct dongle_reg dongle = {
- Q_NULL,
- IRDA_AIRPORT_DONGLE,
- airport_open,
- airport_close,
- airport_reset_wrapper,
- airport_change_speed_wrapper,
-};
-
-int __init airport_init(void)
-{
- int ret;
-
- IRDA_DEBUG(2, __FUNCTION__ "()\n");
- ret = irda_device_register_dongle(&dongle);
- if (ret < 0)
- return ret;
- return 0;
-}
-
-void airport_cleanup(void)
-{
- IRDA_DEBUG(2, __FUNCTION__ "()\n");
- irda_device_unregister_dongle(&dongle);
-}
-
-static void airport_open(dongle_t *self, struct qos_info *qos)
-{
- qos->baud_rate.bits &=
- IR_2400|IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
- /* May need 1ms */
- qos->min_turn_time.bits = 0x07;
-
- MOD_INC_USE_COUNT;
-}
-
-static void airport_close(dongle_t *self)
-{
- IRDA_DEBUG(2, __FUNCTION__ "()\n");
- /* Power off dongle */
- self->set_dtr_rts(self->dev, FALSE, FALSE);
-
- MOD_DEC_USE_COUNT;
-}
-
-static void airport_set_command_mode(dongle_t *self)
-{
- IRDA_DEBUG(2, __FUNCTION__ "()\n");
- self->set_dtr_rts(self->dev, FALSE, TRUE);
-}
-
-static void airport_set_normal_mode(dongle_t *self)
-{
- IRDA_DEBUG(2, __FUNCTION__ "()\n");
- self->set_dtr_rts(self->dev, TRUE, TRUE);
-}
-
-void airport_write_char(dongle_t *self, unsigned char c)
-{
- int actual;
- IRDA_DEBUG(2, __FUNCTION__ "(,0x%x)\n", c & 0xff);
- actual = self->write(self->dev, &c, 1);
- ASSERT(actual == 1, return;);
-}
-
-#define JIFFIES_TO_MSECS(j) ((j)*1000/HZ)
-
-static int airport_waitfor_char(dongle_t *self, unsigned char c)
-{
- __u8 buf[100];
- int i, found = FALSE;
- int before;
- int len;
-
- IRDA_DEBUG(2, __FUNCTION__ "(,0x%x)\n", c);
-
- /* Sleep approx. 10 ms */
- before = jiffies;
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(MSECS_TO_JIFFIES(20));
- IRDA_DEBUG(4, __FUNCTION__ " waited %ldms\n",
- JIFFIES_TO_MSECS(jiffies - before));
-
- len = self->read(self->dev, buf, 100);
-
- for (i = 0; !found && i < len; i++ ) {
- /* IRDA_DEBUG(6, __FUNCTION__ " 0x02x\n", idev->rx_buff.data[i]); */
- found = c == buf[i];
- }
-
- IRDA_DEBUG(2, __FUNCTION__ " returns %s\n", (found ? "true" : "false"));
- return found;
-}
-
-static int airport_check_command_mode(dongle_t *self)
-{
- int i;
- int found = FALSE;
-
- IRDA_DEBUG(2, __FUNCTION__ "()\n");
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(MSECS_TO_JIFFIES(20));
- airport_set_command_mode(self);
-
- /* Loop until the time expires (200ms) or we get the magic char. */
-
- for ( i = 0 ; i < 25 ; i++ ) {
- airport_write_char(self, 0xff);
- if (airport_waitfor_char(self, 0xc3)) {
- found = TRUE;
- break;
- }
- }
-
- if (found) {
- IRDA_DEBUG(2, __FUNCTION__ " OK. (%d)\n", i);
- } else {
- IRDA_DEBUG(0, __FUNCTION__ " FAILED!\n");
- }
- return found;
-}
-
-static int airport_write_register(dongle_t *self, unsigned char reg)
-{
- int ok = FALSE;
- int i;
-
- IRDA_DEBUG(4, __FUNCTION__ "(,0x%x)\n", reg);
- airport_check_command_mode(self);
-
- for ( i = 0 ; i < 6 ; i++ ) {
- airport_write_char(self, reg);
- if (!airport_waitfor_char(self, reg))
- continue;
-
- /* Now read it back */
- airport_write_char(self, (reg << 4) | 0x0f);
- if (airport_waitfor_char(self, reg)) {
- ok = TRUE;
- break;
- }
- }
-
- airport_set_normal_mode(self);
- if (ok) {
- IRDA_DEBUG(4, __FUNCTION__ "(,0x%x) returns OK\n", reg);
- } else {
- IRDA_DEBUG(0, __FUNCTION__ "(,0x%x) returns False!\n", reg);
- }
- return ok;
-}
-
-
-/*
- * Function airport_change_speed (self, speed)
- *
- * Change speed of the Airport type IrDA dongles.
- */
-static void airport_change_speed(dongle_t *self, __u32 speed)
-{
- __u32 current_baudrate;
- int baudcode;
-
- IRDA_DEBUG(4, __FUNCTION__ "(,%d)\n", speed);
-
- ASSERT(self != NULL, return;);
-
- /* Find the correct baudrate code for the required baudrate */
- switch (speed) {
- case 2400: baudcode = 0x10; break;
- case 4800: baudcode = 0x20; break;
- case 9600: baudcode = 0x30; break;
- case 19200: baudcode = 0x40; break;
- case 38400: baudcode = 0x50; break;
- case 57600: baudcode = 0x60; break;
- case 115200: baudcode = 0x70; break;
- default:
- IRDA_DEBUG(0, __FUNCTION__ " bad baud rate: %d\n", speed);
- return;
- }
-
- current_baudrate = self->speed;
- IRDA_DEBUG(4, __FUNCTION__ " current baudrate: %d\n", current_baudrate);
-
- self->set_mode(self->dev, IRDA_RAW);
-
- /* Set the new speed in both registers */
- if (airport_write_register(self, baudcode)) {
- if (airport_write_register(self, baudcode|0x01)) {
- /* ok */
- } else {
- IRDA_DEBUG(0, __FUNCTION__
- " Cannot set new speed in second register\n");
- }
- } else {
- IRDA_DEBUG(0, __FUNCTION__
- " Cannot set new speed in first register\n");
- }
-
- self->set_mode(self->dev, IRDA_IRLAP);
-
- /* How do I signal an error in these functions? */
-
- IRDA_DEBUG(4, __FUNCTION__ " returning\n");
-}
-
-int airport_change_speed_wrapper(struct irda_task *task)
-{
- dongle_t *self = (dongle_t *) task->instance;
- __u32 speed = (__u32) task->param;
-
- irda_execute_as_process(self, (TODO_CALLBACK) airport_change_speed,
- speed);
-
- irda_task_next_state(task, IRDA_TASK_DONE);
-
- return 0;
-}
-
-/*
- * Function airport_reset (self)
- *
- * Reset the Airport type dongle. Warning, this function must only be
- * called with a process context!
- *
- */
-static void airport_reset(dongle_t *self)
-{
- int ok;
-
- IRDA_DEBUG(2, __FUNCTION__ "()\n");
- ASSERT(self != NULL, return;);
-
- self->set_mode(self->dev, IRDA_RAW);
-
- airport_set_normal_mode(self);
-
- /* Sleep 2000 ms */
- IRDA_DEBUG(2, __FUNCTION__ " waiting for powerup\n");
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(MSECS_TO_JIFFIES(2000));
- IRDA_DEBUG(2, __FUNCTION__ " finished waiting for powerup\n");
-
- /* set dongle speed to 9600 */
- ok = TRUE;
-
- if (ok)
- ok = airport_write_register(self, 0x30);
- if (!ok)
- MESSAGE(__FUNCTION__ "() dongle not connected?\n");
- if (ok)
- ok = airport_write_register(self, 0x31);
-
- if (ok)
- ok = airport_write_register(self, 0x02);
- if (ok)
- ok = airport_write_register(self, 0x03);
-
- if (ok) {
- ok = airport_check_command_mode(self);
-
- if (ok) {
- airport_write_char(self, 0x04);
- ok = airport_waitfor_char(self, 0x04);
- }
- airport_set_normal_mode(self);
- }
-
- self->set_mode(self->dev, IRDA_IRLAP);
-
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(MSECS_TO_JIFFIES(20));
- IRDA_DEBUG(4, __FUNCTION__ " waited 20ms\n");
-
- self->speed = 9600;
- if (!ok)
- MESSAGE(__FUNCTION__ "() failed.\n");
- IRDA_DEBUG(2, __FUNCTION__ " returning.\n");
-}
-
-int airport_reset_wrapper(struct irda_task *task)
-{
- dongle_t *self = (dongle_t *) task->instance;
-
- irda_execute_as_process(self, (TODO_CALLBACK) airport_reset, 0);
-
- irda_task_next_state(task, IRDA_TASK_DONE);
-
- return 0;
-}
-
-#ifdef MODULE
-
-MODULE_AUTHOR("Fons Botman <budely@tref.nl>");
-MODULE_DESCRIPTION("Adaptec Airport 1000 and 2000 dongle driver");
-
-/*
- * Function init_module (void)
- *
- * Initialize Airport module
- *
- */
-int init_module(void)
-{
- return airport_init();
-}
-
-/*
- * Function cleanup_module (void)
- *
- * Cleanup Airport module
- *
- */
-void cleanup_module(void)
-{
- airport_cleanup();
-}
-
-#endif
diff --git a/drivers/net/irda/irport.c b/drivers/net/irda/irport.c
index 352dddecc..d8832292a 100644
--- a/drivers/net/irda/irport.c
+++ b/drivers/net/irda/irport.c
@@ -6,7 +6,7 @@
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Sun Aug 3 13:49:59 1997
- * Modified at: Wed Jan 5 13:59:38 2000
+ * Modified at: Fri Jan 28 20:22:38 2000
* Modified by: Dag Brattli <dagb@cs.uit.no>
* Sources: serial.c by Linus Torvalds
*
@@ -161,20 +161,19 @@ irport_open(int i, unsigned int iobase, unsigned int irq)
self->index = i;
/* Initialize IO */
- self->io.iobase = iobase;
+ self->io.sir_base = iobase;
+ self->io.sir_ext = IO_EXTENT;
self->io.irq = irq;
- self->io.io_ext = IO_EXTENT;
self->io.fifo_size = 16;
/* Lock the port that we need */
- ret = check_region(self->io.iobase, self->io.io_ext);
+ ret = check_region(self->io.sir_base, self->io.sir_ext);
if (ret < 0) {
IRDA_DEBUG(0, __FUNCTION__ "(), can't get iobase of 0x%03x\n",
- self->io.iobase);
- /* irport_cleanup(self->self); */
+ self->io.sir_base);
return NULL;
}
- request_region(self->io.iobase, self->io.io_ext, driver_name);
+ request_region(self->io.sir_base, self->io.sir_ext, driver_name);
/* Initialize QoS for this device */
irda_init_max_qos_capabilies(&self->qos);
@@ -218,7 +217,6 @@ irport_open(int i, unsigned int iobase, unsigned int irq)
ERROR(__FUNCTION__ "(), dev_alloc() failed!\n");
return NULL;
}
-
self->netdev = dev;
/* May be overridden by piggyback drivers */
@@ -268,19 +266,19 @@ int irport_close(struct irport_cb *self)
/* Release the IO-port that this driver is using */
IRDA_DEBUG(0 , __FUNCTION__ "(), Releasing Region %03x\n",
- self->io.iobase);
- release_region(self->io.iobase, self->io.io_ext);
+ self->io.sir_base);
+ release_region(self->io.sir_base, self->io.sir_ext);
if (self->tx_buff.head)
kfree(self->tx_buff.head);
if (self->rx_buff.head)
kfree(self->rx_buff.head);
-
+
/* Remove ourselves */
dev_self[self->index] = NULL;
kfree(self);
-
+
return 0;
}
@@ -289,7 +287,7 @@ void irport_start(struct irport_cb *self)
unsigned long flags;
int iobase;
- iobase = self->io.iobase;
+ iobase = self->io.sir_base;
spin_lock_irqsave(&self->lock, flags);
@@ -310,7 +308,7 @@ void irport_stop(struct irport_cb *self)
unsigned long flags;
int iobase;
- iobase = self->io.iobase;
+ iobase = self->io.sir_base;
spin_lock_irqsave(&self->lock, flags);
@@ -355,7 +353,7 @@ void irport_change_speed(void *priv, __u32 speed)
ASSERT(self != NULL, return;);
- iobase = self->io.iobase;
+ iobase = self->io.sir_base;
/* Update accounting for new speed */
self->io.speed = speed;
@@ -431,7 +429,7 @@ int __irport_change_speed(struct irda_task *task)
break;
case IRDA_TASK_CHILD_INIT:
/* Go to default speed */
- irport_change_speed(self, 9600);
+ self->change_speed(self->priv, 9600);
/* Change speed of dongle */
if (irda_task_execute(self->dongle,
@@ -454,7 +452,7 @@ int __irport_change_speed(struct irda_task *task)
break;
case IRDA_TASK_CHILD_DONE:
/* Finally we are ready to change the speed */
- irport_change_speed(self, speed);
+ self->change_speed(self->priv, speed);
irda_task_next_state(task, IRDA_TASK_DONE);
break;
@@ -484,7 +482,7 @@ static void irport_write_wakeup(struct irport_cb *self)
IRDA_DEBUG(4, __FUNCTION__ "()\n");
- iobase = self->io.iobase;
+ iobase = self->io.sir_base;
/* Finished with frame? */
if (self->tx_buff.len > 0) {
@@ -598,7 +596,6 @@ int irport_hard_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct irport_cb *self;
unsigned long flags;
- int actual = 0;
int iobase;
__u32 speed;
@@ -607,7 +604,7 @@ int irport_hard_xmit(struct sk_buff *skb, struct net_device *dev)
self = (struct irport_cb *) dev->priv;
ASSERT(self != NULL, return 0;);
- iobase = self->io.iobase;
+ iobase = self->io.sir_base;
/* Lock transmit buffer */
if (irda_lock((void *) &dev->tbusy) == FALSE) {
@@ -617,7 +614,7 @@ int irport_hard_xmit(struct sk_buff *skb, struct net_device *dev)
WARNING("%s: transmit timed out\n", dev->name);
irport_start(self);
- irport_change_speed(self, self->io.speed );
+ self->change_speed(self->priv, self->io.speed);
dev->trans_start = jiffies;
}
@@ -635,8 +632,7 @@ int irport_hard_xmit(struct sk_buff *skb, struct net_device *dev)
self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data,
self->tx_buff.truesize);
- self->tx_buff.data += actual;
- self->tx_buff.len -= actual;
+ self->stats.tx_bytes += self->tx_buff.len;
/* Turn on transmit finished interrupt. Will fire immediately! */
outb(UART_IER_THRI, iobase+UART_IER);
@@ -661,7 +657,7 @@ static void irport_receive(struct irport_cb *self)
ASSERT(self != NULL, return;);
- iobase = self->io.iobase;
+ iobase = self->io.sir_base;
/*
* Receive all characters in Rx FIFO, unwrap and unstuff them.
@@ -702,15 +698,16 @@ void irport_interrupt(int irq, void *dev_id, struct pt_regs *regs)
dev->interrupt = 1;
- iobase = self->io.iobase;
+ iobase = self->io.sir_base;
iir = inb(iobase+UART_IIR) & UART_IIR_ID;
while (iir) {
/* Clear interrupt */
lsr = inb(iobase+UART_LSR);
- IRDA_DEBUG(4, __FUNCTION__ "(), iir=%02x, lsr=%02x, iobase=%#x\n",
- iir, lsr, iobase);
+ IRDA_DEBUG(4, __FUNCTION__
+ "(), iir=%02x, lsr=%02x, iobase=%#x\n",
+ iir, lsr, iobase);
switch (iir) {
case UART_IIR_RLSI:
@@ -765,7 +762,7 @@ int irport_net_open(struct net_device *dev)
ASSERT(dev != NULL, return -1;);
self = (struct irport_cb *) dev->priv;
- iobase = self->io.iobase;
+ iobase = self->io.sir_base;
if (request_irq(self->io.irq, self->interrupt, 0, dev->name,
(void *) dev))
@@ -809,7 +806,7 @@ int irport_net_close(struct net_device *dev)
ASSERT(self != NULL, return -1;);
- iobase = self->io.iobase;
+ iobase = self->io.sir_base;
/* Stop device */
dev->tbusy = 1;
@@ -840,7 +837,7 @@ void irport_wait_until_sent(struct irport_cb *self)
{
int iobase;
- iobase = self->io.iobase;
+ iobase = self->io.sir_base;
/* Wait until Tx FIFO is empty */
while (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) {
@@ -875,7 +872,7 @@ static int irport_set_dtr_rts(struct net_device *dev, int dtr, int rts)
ASSERT(self != NULL, return -1;);
- iobase = self->io.iobase;
+ iobase = self->io.sir_base;
if (dtr)
dtr = UART_MCR_DTR;
@@ -895,7 +892,7 @@ static int irport_raw_write(struct net_device *dev, __u8 *buf, int len)
ASSERT(self != NULL, return -1;);
- iobase = self->io.iobase;
+ iobase = self->io.sir_base;
/* Tx FIFO should be empty! */
if (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) {
diff --git a/drivers/net/irda/irtty.c b/drivers/net/irda/irtty.c
index 2ec4eba14..370a9c7fe 100644
--- a/drivers/net/irda/irtty.c
+++ b/drivers/net/irda/irtty.c
@@ -6,7 +6,7 @@
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Tue Dec 9 21:18:38 1997
- * Modified at: Wed Jan 5 14:00:13 2000
+ * Modified at: Fri Jan 14 21:02:27 2000
* Modified by: Dag Brattli <dagb@cs.uit.no>
* Sources: slip.c by Laurence Culhane, <loz@holmes.demon.co.uk>
* Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
@@ -233,6 +233,8 @@ static int irtty_open(struct tty_struct *tty)
ERROR(__FUNCTION__ "(), dev_alloc() failed!\n");
return -ENOMEM;
}
+ /* dev_alloc doesn't clear the struct */
+ memset(((__u8*)dev)+sizeof(char*),0,sizeof(struct net_device)-sizeof(char*));
dev->priv = (void *) self;
self->netdev = dev;
@@ -654,6 +656,7 @@ static int irtty_hard_xmit(struct sk_buff *skb, struct net_device *dev)
self->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
dev->trans_start = jiffies;
+ self->stats.tx_bytes += self->tx_buff.len;
if (self->tty->driver.write)
actual = self->tty->driver.write(self->tty, 0,
@@ -663,9 +666,6 @@ static int irtty_hard_xmit(struct sk_buff *skb, struct net_device *dev)
self->tx_buff.data += actual;
self->tx_buff.len -= actual;
- self->stats.tx_packets++;
- self->stats.tx_bytes += self->tx_buff.len;
-
dev_kfree_skb(skb);
return 0;
@@ -709,6 +709,8 @@ static void irtty_write_wakeup(struct tty_struct *tty)
self->tx_buff.data += actual;
self->tx_buff.len -= actual;
+
+ self->stats.tx_packets++;
} else {
/*
* Now serial buffer is almost free & we can start
diff --git a/drivers/net/irda/nsc_fir.c b/drivers/net/irda/nsc-ircc.c
index affd1d8fa..e8aaa8459 100644
--- a/drivers/net/irda/nsc_fir.c
+++ b/drivers/net/irda/nsc-ircc.c
@@ -1,12 +1,12 @@
/*********************************************************************
*
- * Filename: nsc_fir.c
+ * Filename: nsc-ircc.c
* Version: 1.0
* Description: Driver for the NSC PC'108 and PC'338 IrDA chipsets
* Status: Stable.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Sat Nov 7 21:43:15 1998
- * Modified at: Wed Jan 5 13:59:21 2000
+ * Modified at: Fri Jan 28 12:10:10 2000
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>
@@ -41,8 +41,9 @@
*
********************************************************************/
-#include <linux/module.h>
#include <linux/config.h>
+#include <linux/module.h>
+
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/skbuff.h>
@@ -67,29 +68,38 @@
#include <net/irda/irlap_frame.h>
#include <net/irda/irda_device.h>
-#include <net/irda/nsc_fir.h>
+#include <net/irda/nsc-ircc.h>
#define CHIP_IO_EXTENT 8
#define BROKEN_DONGLE_ID
-/*
- * Define if you have multiple NSC IrDA controllers in your machine. Not
- * enabled by default since some single chips detects at multiple addresses
- */
-#undef CONFIG_NSC_FIR_MULTIPLE
-
-static char *driver_name = "nsc_fir";
+static char *driver_name = "nsc-ircc";
/* Module parameters */
static int qos_mtt_bits = 0x07; /* 1 ms or more */
static int dongle_id = 0;
-static unsigned int io[] = { 0x2f8, 0x2f8, 0x2f8, 0x2f8, 0x2f8 };
-static unsigned int io2[] = { 0x150, 0x398, 0xea, 0x15c, 0x2e };
-static unsigned int irq[] = { 3, 3, 3, 3, 3 };
-static unsigned int dma[] = { 0, 0, 0, 0, 3 };
+/* Use BIOS settions by default, but user may supply module parameters */
+static unsigned int io[] = { ~0, ~0, ~0, ~0 };
+static unsigned int irq[] = { 0, 0, 0, 0, 0 };
+static unsigned int dma[] = { 0, 0, 0, 0, 0 };
+
+static int nsc_ircc_probe_108(nsc_chip_t *chip, chipio_t *info);
+static int nsc_ircc_probe_338(nsc_chip_t *chip, chipio_t *info);
+static int nsc_ircc_init_108(nsc_chip_t *chip, chipio_t *info);
+static int nsc_ircc_init_338(nsc_chip_t *chip, chipio_t *info);
+
+/* These are the known NSC chips */
+static nsc_chip_t chips[] = {
+ { "PC87108", { 0x150, 0x398, 0xea }, 0x05, 0x10, 0xf0,
+ nsc_ircc_probe_108, nsc_ircc_init_108 },
+ { "PC87338", { 0x398, 0x15c, 0x2e }, 0x08, 0xb0, 0xf0,
+ nsc_ircc_probe_338, nsc_ircc_init_338 },
+ { NULL }
+};
-static struct nsc_fir_cb *dev_self[] = { NULL, NULL, NULL, NULL, NULL };
+/* Max 4 instances for now */
+static struct nsc_ircc_cb *dev_self[] = { NULL, NULL, NULL, NULL };
static char *dongle_types[] = {
"Differential serial interface",
@@ -111,143 +121,182 @@ static char *dongle_types[] = {
};
/* Some prototypes */
-static int nsc_fir_open(int i, unsigned int iobase, unsigned int board_addr,
- unsigned int irq, unsigned int dma);
+static int nsc_ircc_open(int i, chipio_t *info);
#ifdef MODULE
-static int nsc_fir_close(struct nsc_fir_cb *self);
+static int nsc_ircc_close(struct nsc_ircc_cb *self);
#endif /* MODULE */
-static int nsc_fir_probe(int iobase, int board_addr, int irq, int dma);
-static void nsc_fir_pio_receive(struct nsc_fir_cb *self);
-static int nsc_fir_dma_receive(struct nsc_fir_cb *self);
-static int nsc_fir_dma_receive_complete(struct nsc_fir_cb *self, int iobase);
-static int nsc_fir_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev);
-static int nsc_fir_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev);
-static int nsc_fir_pio_write(int iobase, __u8 *buf, int len, int fifo_size);
-static void nsc_fir_dma_xmit(struct nsc_fir_cb *self, int iobase);
-static void nsc_fir_change_speed(struct nsc_fir_cb *self, __u32 baud);
-static void nsc_fir_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static int nsc_fir_is_receiving(struct nsc_fir_cb *self);
-static int nsc_fir_read_dongle_id (int iobase);
-static void nsc_fir_init_dongle_interface (int iobase, int dongle_id);
-
-static int nsc_fir_net_init(struct net_device *dev);
-static int nsc_fir_net_open(struct net_device *dev);
-static int nsc_fir_net_close(struct net_device *dev);
-static int nsc_fir_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static struct net_device_stats *nsc_fir_net_get_stats(struct net_device *dev);
+static int nsc_ircc_setup(chipio_t *info);
+static void nsc_ircc_pio_receive(struct nsc_ircc_cb *self);
+static int nsc_ircc_dma_receive(struct nsc_ircc_cb *self);
+static int nsc_ircc_dma_receive_complete(struct nsc_ircc_cb *self, int iobase);
+static int nsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev);
+static int nsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev);
+static int nsc_ircc_pio_write(int iobase, __u8 *buf, int len, int fifo_size);
+static void nsc_ircc_dma_xmit(struct nsc_ircc_cb *self, int iobase);
+static void nsc_ircc_change_speed(struct nsc_ircc_cb *self, __u32 baud);
+static void nsc_ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static int nsc_ircc_is_receiving(struct nsc_ircc_cb *self);
+static int nsc_ircc_read_dongle_id (int iobase);
+static void nsc_ircc_init_dongle_interface (int iobase, int dongle_id);
+
+static int nsc_ircc_net_init(struct net_device *dev);
+static int nsc_ircc_net_open(struct net_device *dev);
+static int nsc_ircc_net_close(struct net_device *dev);
+static int nsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static struct net_device_stats *nsc_ircc_net_get_stats(struct net_device *dev);
#ifdef CONFIG_APM
-static int nsc_fir_apmproc(apm_event_t event);
+static int nsc_ircc_apmproc(apm_event_t event);
#endif /* CONFIG_APM */
+
/*
- * Function nsc_fir_init ()
+ * Function nsc_ircc_init ()
*
* Initialize chip. Just try to find out how many chips we are dealing with
* and where they are
*/
-int __init nsc_fir_init(void)
+int __init nsc_ircc_init(void)
{
+ chipio_t info;
+ nsc_chip_t *chip;
int ret = -ENODEV;
- int ioaddr;
- int i;
+ int cfg_base;
+ int cfg, id;
+ int reg;
+ int i = 0;
+
+ /* Probe for all the NSC chipsets we know about */
+ for (chip=chips; chip->name ; chip++,i++) {
+ IRDA_DEBUG(2, __FUNCTION__"(), Probing for %s ...\n",
+ chip->name);
+
+ /* Try all config registers for this chip */
+ for (cfg=0; cfg<3; cfg++) {
+ cfg_base = chip->cfg[cfg];
+ if (!cfg_base)
+ continue;
+
+ memset(&info, 0, sizeof(chipio_t));
+ info.cfg_base = cfg_base;
+ info.fir_base = io[i];
+ info.dma = dma[i];
+ info.irq = irq[i];
+
+ /* Read index register */
+ reg = inb(cfg_base);
+ if (reg == 0xff) {
+ IRDA_DEBUG(2, __FUNCTION__
+ "() no chip at 0x%03x\n", cfg_base);
+ continue;
+ }
+
+ /* Read chip identification register */
+ outb(chip->cid_index, cfg_base);
+ id = inb(cfg_base+1);
+ if ((id & chip->cid_mask) == chip->cid_value) {
+ IRDA_DEBUG(2, __FUNCTION__
+ "() Found %s chip, revision=%d\n",
+ chip->name, id & ~chip->cid_mask);
+ /*
+ * If the user supplies the base address, then
+ * we init the chip, if not we probe the values
+ * set by the BIOS
+ */
+ if (io[i] < 2000) {
+ chip->init(chip, &info);
+ } else
+ chip->probe(chip, &info);
+ if (nsc_ircc_open(i, &info) == 0)
+ ret = 0;
+ i++;
+ } else {
+ IRDA_DEBUG(2, __FUNCTION__
+ "(), Wrong chip id=0x%02x\n", id);
+ }
+ }
+
+ }
#ifdef CONFIG_APM
- apm_register_callback(nsc_fir_apmproc);
+ /* Make sure at least one chip was found before enabling APM */
+ if (ret == 0)
+ apm_register_callback(nsc_ircc_apmproc);
#endif /* CONFIG_APM */
- for (i=0; (io[i] < 2000) && (i < 5); i++) {
- ioaddr = io[i];
- if (check_region(ioaddr, CHIP_IO_EXTENT) < 0)
- continue;
- if (nsc_fir_open(i, io[i], io2[i], irq[i], dma[i]) == 0)
- {
-#ifdef CONFIG_NSC_FIR_MULTIPLE
- ret = 0;
-#else
- return 0;
-#endif
- }
- }
-
return ret;
}
/*
- * Function nsc_fir_cleanup ()
+ * Function nsc_ircc_cleanup ()
*
* Close all configured chips
*
*/
#ifdef MODULE
-static void nsc_fir_cleanup(void)
+static void nsc_ircc_cleanup(void)
{
int i;
- IRDA_DEBUG(4, __FUNCTION__ "()\n");
-
#ifdef CONFIG_APM
- apm_unregister_callback(nsc_fir_apmproc);
+ apm_unregister_callback(nsc_ircc_apmproc);
#endif /* CONFIG_APM */
-
- for (i=0; i < 5; i++) {
+ for (i=0; i < 4; i++) {
if (dev_self[i])
- nsc_fir_close(dev_self[i]);
+ nsc_ircc_close(dev_self[i]);
}
}
#endif /* MODULE */
/*
- * Function nsc_fir_open (iobase, irq)
+ * Function nsc_ircc_open (iobase, irq)
*
* Open driver instance
*
*/
-static int
-nsc_fir_open(int i, unsigned int iobase, unsigned int board_addr,
- unsigned int irq, unsigned int dma)
+static int nsc_ircc_open(int i, chipio_t *info)
{
struct net_device *dev;
- struct nsc_fir_cb *self;
- int dongle_id;
+ struct nsc_ircc_cb *self;
int ret;
int err;
IRDA_DEBUG(2, __FUNCTION__ "()\n");
- if ((dongle_id = nsc_fir_probe(iobase, board_addr, irq, dma)) == -1)
+ if ((nsc_ircc_setup(info)) == -1)
return -1;
- /*
- * Allocate new instance of the driver
- */
- self = kmalloc(sizeof(struct nsc_fir_cb), GFP_KERNEL);
+ /* Allocate new instance of the driver */
+ self = kmalloc(sizeof(struct nsc_ircc_cb), GFP_KERNEL);
if (self == NULL) {
ERROR(__FUNCTION__ "(), can't allocate memory for "
"control block!\n");
return -ENOMEM;
}
- memset(self, 0, sizeof(struct nsc_fir_cb));
+ memset(self, 0, sizeof(struct nsc_ircc_cb));
spin_lock_init(&self->lock);
/* Need to store self somewhere */
dev_self[i] = self;
+ self->index = i;
/* Initialize IO */
- self->io.iobase = iobase;
- self->io.irq = irq;
- self->io.io_ext = CHIP_IO_EXTENT;
- self->io.dma = dma;
+ self->io.cfg_base = info->cfg_base;
+ self->io.fir_base = info->fir_base;
+ self->io.irq = info->irq;
+ self->io.fir_ext = CHIP_IO_EXTENT;
+ self->io.dma = info->dma;
self->io.fifo_size = 32;
-
- /* Lock the port that we need */
- ret = check_region(self->io.iobase, self->io.io_ext);
+
+ /* Reserve the ioports that we need */
+ ret = check_region(self->io.fir_base, self->io.fir_ext);
if (ret < 0) {
- IRDA_DEBUG(0, __FUNCTION__ "(), can't get iobase of 0x%03x\n",
- self->io.iobase);
- /* nsc_fir_cleanup(self->self); */
+ WARNING(__FUNCTION__ "(), can't get iobase of 0x%03x\n",
+ self->io.fir_base);
+ dev_self[i] = NULL;
+ kfree(self);
return -ENODEV;
}
- request_region(self->io.iobase, self->io.io_ext, driver_name);
+ request_region(self->io.fir_base, self->io.fir_ext, driver_name);
/* Initialize QoS for this device */
irda_init_max_qos_capabilies(&self->qos);
@@ -268,13 +317,16 @@ nsc_fir_open(int i, unsigned int iobase, unsigned int board_addr,
/* Allocate memory if needed */
self->rx_buff.head = (__u8 *) kmalloc(self->rx_buff.truesize,
GFP_KERNEL|GFP_DMA);
- if (self->rx_buff.head == NULL)
+ if (self->rx_buff.head == NULL) {
+ kfree(self);
return -ENOMEM;
+ }
memset(self->rx_buff.head, 0, self->rx_buff.truesize);
self->tx_buff.head = (__u8 *) kmalloc(self->tx_buff.truesize,
GFP_KERNEL|GFP_DMA);
if (self->tx_buff.head == NULL) {
+ kfree(self);
kfree(self->rx_buff.head);
return -ENOMEM;
}
@@ -298,12 +350,12 @@ nsc_fir_open(int i, unsigned int iobase, unsigned int board_addr,
self->netdev = dev;
/* Override the network functions we need to use */
- dev->init = nsc_fir_net_init;
- dev->hard_start_xmit = nsc_fir_hard_xmit_sir;
- dev->open = nsc_fir_net_open;
- dev->stop = nsc_fir_net_close;
- dev->do_ioctl = nsc_fir_net_ioctl;
- dev->get_stats = nsc_fir_net_get_stats;
+ dev->init = nsc_ircc_net_init;
+ dev->hard_start_xmit = nsc_ircc_hard_xmit_sir;
+ dev->open = nsc_ircc_net_open;
+ dev->stop = nsc_ircc_net_close;
+ dev->do_ioctl = nsc_ircc_net_ioctl;
+ dev->get_stats = nsc_ircc_net_get_stats;
rtnl_lock();
err = register_netdevice(dev);
@@ -312,23 +364,33 @@ nsc_fir_open(int i, unsigned int iobase, unsigned int board_addr,
ERROR(__FUNCTION__ "(), register_netdev() failed!\n");
return -1;
}
-
MESSAGE("IrDA: Registered device %s\n", dev->name);
+
+ /* Check if user has supplied the dongle id or not */
+ if (!dongle_id) {
+ dongle_id = nsc_ircc_read_dongle_id(self->io.fir_base);
+
+ MESSAGE("%s, Found dongle: %s\n", driver_name,
+ dongle_types[dongle_id]);
+ } else {
+ MESSAGE("%s, Using dongle: %s\n", driver_name,
+ dongle_types[dongle_id]);
+ }
self->io.dongle_id = dongle_id;
- nsc_fir_init_dongle_interface(iobase, dongle_id);
+ nsc_ircc_init_dongle_interface(self->io.fir_base, dongle_id);
return 0;
}
#ifdef MODULE
/*
- * Function nsc_fir_close (self)
+ * Function nsc_ircc_close (self)
*
* Close driver instance
*
*/
-static int nsc_fir_close(struct nsc_fir_cb *self)
+static int nsc_ircc_close(struct nsc_ircc_cb *self)
{
int iobase;
@@ -336,7 +398,7 @@ static int nsc_fir_close(struct nsc_fir_cb *self)
ASSERT(self != NULL, return -1;);
- iobase = self->io.iobase;
+ iobase = self->io.fir_base;
/* Remove netdevice */
if (self->netdev) {
@@ -347,8 +409,8 @@ static int nsc_fir_close(struct nsc_fir_cb *self)
/* Release the PORT that this driver is using */
IRDA_DEBUG(4, __FUNCTION__ "(), Releasing Region %03x\n",
- self->io.iobase);
- release_region(self->io.iobase, self->io.io_ext);
+ self->io.fir_base);
+ release_region(self->io.fir_base, self->io.fir_ext);
if (self->tx_buff.head)
kfree(self->tx_buff.head);
@@ -356,37 +418,39 @@ static int nsc_fir_close(struct nsc_fir_cb *self)
if (self->rx_buff.head)
kfree(self->rx_buff.head);
+ dev_self[self->index] = NULL;
kfree(self);
-
+
return 0;
}
#endif /* MODULE */
/*
- * Function nsc_fir_init_807 (iobase, board_addr, irq, dma)
+ * Function nsc_ircc_init_108 (iobase, cfg_base, irq, dma)
*
* Initialize the NSC '108 chip
*
*/
-static void nsc_fir_init_807(int iobase, int board_addr, int irq, int dma)
+static int nsc_ircc_init_108(nsc_chip_t *chip, chipio_t *info)
{
+ int cfg_base = info->cfg_base;
__u8 temp=0;
- outb(2, board_addr); /* Mode Control Register (MCTL) */
- outb(0x00, board_addr+1); /* Disable device */
+ outb(2, cfg_base); /* Mode Control Register (MCTL) */
+ outb(0x00, cfg_base+1); /* Disable device */
/* Base Address and Interrupt Control Register (BAIC) */
- outb(0, board_addr);
- switch (iobase) {
- case 0x3e8: outb(0x14, board_addr+1); break;
- case 0x2e8: outb(0x15, board_addr+1); break;
- case 0x3f8: outb(0x16, board_addr+1); break;
- case 0x2f8: outb(0x17, board_addr+1); break;
+ outb(0, cfg_base);
+ switch (info->fir_base) {
+ case 0x3e8: outb(0x14, cfg_base+1); break;
+ case 0x2e8: outb(0x15, cfg_base+1); break;
+ case 0x3f8: outb(0x16, cfg_base+1); break;
+ case 0x2f8: outb(0x17, cfg_base+1); break;
default: ERROR(__FUNCTION__ "(), invalid base_address");
}
/* Control Signal Routing Register (CSRT) */
- switch (irq) {
+ switch (info->irq) {
case 3: temp = 0x01; break;
case 4: temp = 0x02; break;
case 5: temp = 0x03; break;
@@ -396,90 +460,242 @@ static void nsc_fir_init_807(int iobase, int board_addr, int irq, int dma)
case 15: temp = 0x07; break;
default: ERROR(__FUNCTION__ "(), invalid irq");
}
- outb(1, board_addr);
+ outb(1, cfg_base);
- switch (dma) {
- case 0: outb(0x08+temp, board_addr+1); break;
- case 1: outb(0x10+temp, board_addr+1); break;
- case 3: outb(0x18+temp, board_addr+1); break;
+ switch (info->dma) {
+ case 0: outb(0x08+temp, cfg_base+1); break;
+ case 1: outb(0x10+temp, cfg_base+1); break;
+ case 3: outb(0x18+temp, cfg_base+1); break;
default: ERROR(__FUNCTION__ "(), invalid dma");
}
- outb(2, board_addr); /* Mode Control Register (MCTL) */
- outb(0x03, board_addr+1); /* Enable device */
+ outb(2, cfg_base); /* Mode Control Register (MCTL) */
+ outb(0x03, cfg_base+1); /* Enable device */
+
+ return 0;
+}
+
+/*
+ * Function nsc_ircc_probe_108 (chip, info)
+ *
+ *
+ *
+ */
+static int nsc_ircc_probe_108(nsc_chip_t *chip, chipio_t *info)
+{
+ int cfg_base = info->cfg_base;
+ int reg;
+
+ /* Read address and interrupt control register (BAIC) */
+ outb(CFG_BAIC, cfg_base);
+ reg = inb(cfg_base+1);
+
+ switch (reg & 0x03) {
+ case 0:
+ info->fir_base = 0x3e8;
+ break;
+ case 1:
+ info->fir_base = 0x2e8;
+ break;
+ case 2:
+ info->fir_base = 0x3f8;
+ break;
+ case 3:
+ info->fir_base = 0x2f8;
+ break;
+ }
+ info->sir_base = info->fir_base;
+ IRDA_DEBUG(2, __FUNCTION__ "(), probing fir_base=0x%03x\n",
+ info->fir_base);
+
+ /* Read control signals routing register (CSRT) */
+ outb(CFG_CSRT, cfg_base);
+ reg = inb(cfg_base+1);
+
+ switch (reg & 0x07) {
+ case 0:
+ info->irq = -1;
+ break;
+ case 1:
+ info->irq = 3;
+ break;
+ case 2:
+ info->irq = 4;
+ break;
+ case 3:
+ info->irq = 5;
+ break;
+ case 4:
+ info->irq = 7;
+ break;
+ case 5:
+ info->irq = 9;
+ break;
+ case 6:
+ info->irq = 11;
+ break;
+ case 7:
+ info->irq = 15;
+ break;
+ }
+ IRDA_DEBUG(2, __FUNCTION__ "(), probing irq=%d\n", info->irq);
+
+ /* Currently we only read Rx DMA but it will also be used for Tx */
+ switch ((reg >> 3) & 0x03) {
+ case 0:
+ info->dma = -1;
+ break;
+ case 1:
+ info->dma = 0;
+ break;
+ case 2:
+ info->dma = 1;
+ break;
+ case 3:
+ info->dma = 3;
+ break;
+ }
+ IRDA_DEBUG(2, __FUNCTION__ "(), probing dma=%d\n", info->dma);
+
+ /* Read mode control register (MCTL) */
+ outb(CFG_MCTL, cfg_base);
+ reg = inb(cfg_base+1);
+
+ info->enabled = reg & 0x01;
+ info->suspended = !((reg >> 1) & 0x01);
+
+ return 0;
}
/*
- * Function nsc_fir_init_338 (iobase, board_addr, irq, dma)
+ * Function nsc_ircc_init_338 (chip, info)
*
* Initialize the NSC '338 chip. Remember that the 87338 needs two
* consecutive writes to the data registers while CPU interrupts are
* disabled. The 97338 does not require this, but shouldn't be any
* harm if we do it anyway.
*/
-static void nsc_fir_init_338(int iobase, int board_addr, int irq, int dma)
+static int nsc_ircc_init_338(nsc_chip_t *chip, chipio_t *info)
{
/* No init yet */
+
+ return 0;
}
-static int nsc_fir_find_chip(int board_addr)
+/*
+ * Function nsc_ircc_probe_338 (chip, info)
+ *
+ *
+ *
+ */
+static int nsc_ircc_probe_338(nsc_chip_t *chip, chipio_t *info)
{
- __u8 index, id;
+ int cfg_base = info->cfg_base;
+ int reg, com = 0;
+ int pnp;
- IRDA_DEBUG(4, __FUNCTION__ "()\n");
+ /* Read funtion enable register (FER) */
+ outb(CFG_FER, cfg_base);
+ reg = inb(cfg_base+1);
- /* Read index register */
- index = inb(board_addr);
- if (index == 0xff) {
- IRDA_DEBUG(0, __FUNCTION__ "(), no chip at 0x%03x\n",
- board_addr);
- return -1;
- }
+ info->enabled = (reg >> 2) & 0x01;
+
+ /* Check if we are in Legacy or PnP mode */
+ outb(CFG_PNP0, cfg_base);
+ reg = inb(cfg_base+1);
+
+ pnp = (reg >> 4) & 0x01;
+ if (pnp) {
+ IRDA_DEBUG(2, "(), Chip is in PnP mode\n");
+ outb(0x46, cfg_base);
+ reg = (inb(cfg_base+1) & 0xfe) << 2;
+
+ outb(0x47, cfg_base);
+ reg |= ((inb(cfg_base+1) & 0xfc) << 8);
- /* Read chip identification register (SID) for the PC97338 */
- outb(8, board_addr);
- id = inb(board_addr+1);
- if ((id & 0xf0) == PC97338) {
- MESSAGE("%s, Found NSC PC97338 chip, revision=%d\n",
- driver_name, id & 0x0f);
- return PC97338;
- }
-
- /* Read device identification (DID) for the PC87108 */
- outb(5, board_addr);
- id = inb(board_addr+1);
- if ((id & 0xf0) == PC87108) {
- MESSAGE("%s, Found NSC PC87108 chip, revision=%d\n",
- driver_name, id & 0x0f);
- return PC87108;
+ info->fir_base = reg;
+ } else {
+ /* Read function address register (FAR) */
+ outb(CFG_FAR, cfg_base);
+ reg = inb(cfg_base+1);
+
+ switch ((reg >> 4) & 0x03) {
+ case 0:
+ info->fir_base = 0x3f8;
+ break;
+ case 1:
+ info->fir_base = 0x2f8;
+ break;
+ case 2:
+ com = 3;
+ break;
+ case 3:
+ com = 4;
+ break;
+ }
+
+ if (com) {
+ switch ((reg >> 6) & 0x03) {
+ case 0:
+ if (com == 3)
+ info->fir_base = 0x3e8;
+ else
+ info->fir_base = 0x2e8;
+ break;
+ case 1:
+ if (com == 3)
+ info->fir_base = 0x338;
+ else
+ info->fir_base = 0x238;
+ break;
+ case 2:
+ if (com == 3)
+ info->fir_base = 0x2e8;
+ else
+ info->fir_base = 0x2e0;
+ break;
+ case 3:
+ if (com == 3)
+ info->fir_base = 0x220;
+ else
+ info->fir_base = 0x228;
+ break;
+ }
+ }
}
+ info->sir_base = info->fir_base;
+
+ /* Read PnP register 1 (PNP1) */
+ outb(CFG_PNP1, cfg_base);
+ reg = inb(cfg_base+1);
+
+ info->irq = reg >> 4;
+
+ /* Read PnP register 3 (PNP3) */
+ outb(CFG_PNP3, cfg_base);
+ reg = inb(cfg_base+1);
+
+ info->dma = (reg & 0x07) - 1;
- return -1;
+ /* Read power and test register (PTR) */
+ outb(CFG_PTR, cfg_base);
+ reg = inb(cfg_base+1);
+
+ info->suspended = reg & 0x01;
+
+ return 0;
}
/*
- * Function nsc_fir_probe (iobase, board_addr, irq, dma)
+ * Function nsc_ircc_setup (info)
*
* Returns non-negative on success.
*
*/
-static int nsc_fir_probe(int iobase, int board_addr, int irq, int dma)
+static int nsc_ircc_setup(chipio_t *info)
{
int version;
- __u8 chip;
-
- chip = nsc_fir_find_chip(board_addr);
- switch (chip) {
- case PC87108:
- nsc_fir_init_807(iobase, board_addr, irq, dma);
- break;
- case PC97338:
- nsc_fir_init_338(iobase, board_addr, irq, dma);
- break;
- default:
- /* Found no chip */
- return -1;
- }
+ int iobase = info->fir_base;
/* Read the Module ID */
switch_bank(iobase, BANK3);
@@ -490,23 +706,13 @@ static int nsc_fir_probe(int iobase, int board_addr, int irq, int dma)
ERROR("%s, Wrong chip version %02x\n", driver_name, version);
return -1;
}
- MESSAGE("%s, Found chip at base=0x%04x\n", driver_name, board_addr);
+ MESSAGE("%s, Found chip at base=0x%03x\n", driver_name,
+ info->cfg_base);
/* Switch to advanced mode */
switch_bank(iobase, BANK2);
outb(ECR1_EXT_SL, iobase+ECR1);
switch_bank(iobase, BANK0);
-
- /* Check if user has supplied the dongle id or not */
- if (!dongle_id) {
- dongle_id = nsc_fir_read_dongle_id(iobase);
-
- MESSAGE("%s, Found dongle: %s\n", driver_name,
- dongle_types[dongle_id]);
- } else {
- MESSAGE("%s, Using dongle: %s\n", driver_name,
- dongle_types[dongle_id]);
- }
/* Set FIFO threshold to TX17, RX16, reset and enable FIFO's */
switch_bank(iobase, BANK0);
@@ -533,24 +739,21 @@ static int nsc_fir_probe(int iobase, int board_addr, int irq, int dma)
switch_bank(iobase, BANK0);
outb(IER_RXHDL_IE, iobase+IER);
- return dongle_id;
+ return 0;
}
/*
- * Function nsc_fir_read_dongle_id (void)
+ * Function nsc_ircc_read_dongle_id (void)
*
* Try to read dongle indentification. This procedure needs to be executed
* once after power-on/reset. It also needs to be used whenever you suspect
* that the user may have plugged/unplugged the IrDA Dongle.
- *
*/
-static int nsc_fir_read_dongle_id (int iobase)
+static int nsc_ircc_read_dongle_id (int iobase)
{
int dongle_id;
__u8 bank;
- IRDA_DEBUG(4, __FUNCTION__ "()\n");
-
bank = inb(iobase+BSR);
/* Select Bank 7 */
@@ -568,8 +771,7 @@ static int nsc_fir_read_dongle_id (int iobase)
#ifdef BROKEN_DONGLE_ID
if (dongle_id == 0x0a)
dongle_id = 0x09;
-#endif
-
+#endif
/* Go back to bank 0 before returning */
switch_bank(iobase, BANK0);
@@ -579,14 +781,14 @@ static int nsc_fir_read_dongle_id (int iobase)
}
/*
- * Function nsc_fir_init_dongle_interface (iobase, dongle_id)
+ * Function nsc_ircc_init_dongle_interface (iobase, dongle_id)
*
* This function initializes the dongle for the transceiver that is
* used. This procedure needs to be executed once after
* power-on/reset. It also needs to be used whenever you suspect that
* the dongle is changed.
*/
-static void nsc_fir_init_dongle_interface (int iobase, int dongle_id)
+static void nsc_ircc_init_dongle_interface (int iobase, int dongle_id)
{
int bank;
@@ -625,11 +827,11 @@ static void nsc_fir_init_dongle_interface (int iobase, int dongle_id)
dongle_types[dongle_id]);
break;
case 0x08: /* HP HSDL-2300, HP HSDL-3600/HSDL-3610 */
- IRDA_DEBUG(0, __FUNCTION__ "(), %s not supported yet\n",
- dongle_types[dongle_id]);
+ IRDA_DEBUG(0, __FUNCTION__ "(), %s\n",
+ dongle_types[dongle_id]);
break;
case 0x09: /* IBM31T1100 or Temic TFDS6000/TFDS6500 */
- outb_p(0x28, iobase+7); /* Set irsl[0-2] as output */
+ outb(0x28, iobase+7); /* Set irsl[0-2] as output */
break;
case 0x0A: /* same as */
case 0x0B: /* Reserved */
@@ -668,18 +870,16 @@ static void nsc_fir_init_dongle_interface (int iobase, int dongle_id)
} /* set_up_dongle_interface */
/*
- * Function nsc_fir_change_dongle_speed (iobase, speed, dongle_id)
+ * Function nsc_ircc_change_dongle_speed (iobase, speed, dongle_id)
*
* Change speed of the attach dongle
*
*/
-static void nsc_fir_change_dongle_speed(int iobase, int speed, int dongle_id)
+static void nsc_ircc_change_dongle_speed(int iobase, int speed, int dongle_id)
{
unsigned long flags;
__u8 bank;
- IRDA_DEBUG(4, __FUNCTION__ "()\n");
-
/* Save current bank */
bank = inb(iobase+BSR);
@@ -714,11 +914,14 @@ static void nsc_fir_change_dongle_speed(int iobase, int speed, int dongle_id)
dongle_types[dongle_id]);
break;
case 0x08: /* HP HSDL-2300, HP HSDL-3600/HSDL-3610 */
- IRDA_DEBUG(0, __FUNCTION__ "(), %s not supported yet\n",
+ IRDA_DEBUG(0, __FUNCTION__ "(), %s\n",
dongle_types[dongle_id]);
+ outb(0x00, iobase+4);
+ if (speed > 115200)
+ outb(0x01, iobase+4);
+ break;
case 0x09: /* IBM31T1100 or Temic TFDS6000/TFDS6500 */
- switch_bank(iobase, BANK7);
- outb_p(0x01, iobase+4);
+ outb(0x01, iobase+4);
if (speed == 4000000) {
save_flags(flags);
@@ -727,7 +930,7 @@ static void nsc_fir_change_dongle_speed(int iobase, int speed, int dongle_id)
outb(0x80, iobase+4);
restore_flags(flags);
} else
- outb_p(0x00, iobase+4);
+ outb(0x00, iobase+4);
break;
case 0x0A: /* same as */
case 0x0B: /* Reserved */
@@ -754,12 +957,12 @@ static void nsc_fir_change_dongle_speed(int iobase, int speed, int dongle_id)
}
/*
- * Function nsc_fir_change_speed (self, baud)
+ * Function nsc_ircc_change_speed (self, baud)
*
* Change the speed of the device
*
*/
-static void nsc_fir_change_speed(struct nsc_fir_cb *self, __u32 speed)
+static void nsc_ircc_change_speed(struct nsc_ircc_cb *self, __u32 speed)
{
struct net_device *dev = self->netdev;
__u8 mcr = MCR_SIR;
@@ -770,7 +973,7 @@ static void nsc_fir_change_speed(struct nsc_fir_cb *self, __u32 speed)
ASSERT(self != NULL, return;);
- iobase = self->io.iobase;
+ iobase = self->io.fir_base;
/* Update accounting for new speed */
self->io.speed = speed;
@@ -821,7 +1024,7 @@ static void nsc_fir_change_speed(struct nsc_fir_cb *self, __u32 speed)
outb(mcr | MCR_TX_DFR, iobase+MCR);
/* Give some hits to the transceiver */
- nsc_fir_change_dongle_speed(iobase, speed, self->io.dongle_id);
+ nsc_ircc_change_dongle_speed(iobase, speed, self->io.dongle_id);
/* Set FIFO threshold to TX17, RX16 */
switch_bank(iobase, BANK0);
@@ -844,12 +1047,12 @@ static void nsc_fir_change_speed(struct nsc_fir_cb *self, __u32 speed)
switch_bank(iobase, BANK0);
if (speed > 115200) {
/* Install FIR xmit handler */
- dev->hard_start_xmit = nsc_fir_hard_xmit_fir;
+ dev->hard_start_xmit = nsc_ircc_hard_xmit_fir;
outb(IER_SFIF_IE, iobase+IER);
- nsc_fir_dma_receive(self);
+ nsc_ircc_dma_receive(self);
} else {
/* Install SIR xmit handler */
- dev->hard_start_xmit = nsc_fir_hard_xmit_sir;
+ dev->hard_start_xmit = nsc_ircc_hard_xmit_sir;
outb(IER_RXHDL_IE, iobase+IER);
}
@@ -858,24 +1061,24 @@ static void nsc_fir_change_speed(struct nsc_fir_cb *self, __u32 speed)
}
/*
- * Function nsc_fir_hard_xmit (skb, dev)
+ * Function nsc_ircc_hard_xmit (skb, dev)
*
* Transmit the frame!
*
*/
-static int nsc_fir_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev)
+static int nsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev)
{
- struct nsc_fir_cb *self;
+ struct nsc_ircc_cb *self;
unsigned long flags;
int iobase;
__u32 speed;
__u8 bank;
- self = (struct nsc_fir_cb *) dev->priv;
+ self = (struct nsc_ircc_cb *) dev->priv;
ASSERT(self != NULL, return 0;);
- iobase = self->io.iobase;
+ iobase = self->io.fir_base;
/* Lock transmit buffer */
if (irda_lock((void *) &dev->tbusy) == FALSE)
@@ -894,6 +1097,8 @@ static int nsc_fir_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev)
self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data,
self->tx_buff.truesize);
+
+ self->stats.tx_bytes += self->tx_buff.len;
/* Add interrupt on tx low level (will fire immediately) */
switch_bank(iobase, BANK0);
@@ -909,20 +1114,17 @@ static int nsc_fir_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev)
return 0;
}
-static int nsc_fir_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev)
+static int nsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev)
{
- struct nsc_fir_cb *self;
+ struct nsc_ircc_cb *self;
unsigned long flags;
int iobase;
__u32 speed;
__u8 bank;
int mtt, diff;
- self = (struct nsc_fir_cb *) dev->priv;
-
- ASSERT(self != NULL, return 0;);
-
- iobase = self->io.iobase;
+ self = (struct nsc_ircc_cb *) dev->priv;
+ iobase = self->io.fir_base;
/* Lock transmit buffer */
if (irda_lock((void *) &dev->tbusy) == FALSE)
@@ -942,6 +1144,8 @@ static int nsc_fir_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev)
self->tx_fifo.queue[self->tx_fifo.free].len = skb->len;
self->tx_fifo.tail += skb->len;
+ self->stats.tx_bytes += skb->len;
+
memcpy(self->tx_fifo.queue[self->tx_fifo.free].start, skb->data,
skb->len);
@@ -950,10 +1154,11 @@ static int nsc_fir_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev)
/* Start transmit only if there is currently no transmit going on */
if (self->tx_fifo.len == 1) {
+ /* Check if we must wait the min turn time or not */
mtt = irda_get_mtt(skb);
if (mtt) {
/* Check how much time we have used already */
- do_gettimeofday(&self->now);
+ get_fast_time(&self->now);
diff = self->now.tv_usec - self->stamp.tv_usec;
if (diff < 0)
diff += 1000000;
@@ -963,9 +1168,15 @@ static int nsc_fir_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev)
*/
if (mtt > diff) {
mtt -= diff;
+
+ /*
+ * Use timer if delay larger than 125 us, and
+ * use udelay for smaller values which should
+ * be acceptable
+ */
if (mtt > 125) {
/* Adjust for timer resolution */
- mtt = mtt / 125 + 1;
+ mtt = mtt / 125;
/* Setup timer */
switch_bank(iobase, BANK4);
@@ -985,34 +1196,35 @@ static int nsc_fir_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev)
} else
udelay(mtt);
}
- }
-
+ }
/* Enable DMA interrupt */
switch_bank(iobase, BANK0);
outb(IER_DMA_IE, iobase+IER);
- nsc_fir_dma_xmit(self, iobase);
+
+ /* Transmit frame */
+ nsc_ircc_dma_xmit(self, iobase);
}
+ out:
/* Not busy transmitting anymore if window is not full */
- if (self->tx_fifo.len < MAX_WINDOW)
+ if (self->tx_fifo.free < MAX_TX_WINDOW)
dev->tbusy = 0;
- out:
+
/* Restore bank register */
outb(bank, iobase+BSR);
spin_unlock_irqrestore(&self->lock, flags);
-
dev_kfree_skb(skb);
return 0;
}
/*
- * Function nsc_fir_dma_xmit (self, iobase)
+ * Function nsc_ircc_dma_xmit (self, iobase)
*
* Transmit data using DMA
*
*/
-static void nsc_fir_dma_xmit(struct nsc_fir_cb *self, int iobase)
+static void nsc_ircc_dma_xmit(struct nsc_ircc_cb *self, int iobase)
{
int bsr;
@@ -1043,13 +1255,13 @@ static void nsc_fir_dma_xmit(struct nsc_fir_cb *self, int iobase)
}
/*
- * Function nsc_fir_pio_xmit (self, iobase)
+ * Function nsc_ircc_pio_xmit (self, iobase)
*
* Transmit data using PIO. Returns the number of bytes that actually
* got transfered
*
*/
-static int nsc_fir_pio_write(int iobase, __u8 *buf, int len, int fifo_size)
+static int nsc_ircc_pio_write(int iobase, __u8 *buf, int len, int fifo_size)
{
int actual = 0;
__u8 bank;
@@ -1064,6 +1276,7 @@ static int nsc_fir_pio_write(int iobase, __u8 *buf, int len, int fifo_size)
IRDA_DEBUG(4, __FUNCTION__
"(), warning, FIFO not empty yet!\n");
+ /* FIFO may still be filled to the Tx interrupt threshold */
fifo_size -= 17;
}
@@ -1083,13 +1296,13 @@ static int nsc_fir_pio_write(int iobase, __u8 *buf, int len, int fifo_size)
}
/*
- * Function nsc_fir_dma_xmit_complete (self)
+ * Function nsc_ircc_dma_xmit_complete (self)
*
* The transfer of a frame in finished. This function will only be called
* by the interrupt handler
*
*/
-static int nsc_fir_dma_xmit_complete(struct nsc_fir_cb *self)
+static int nsc_ircc_dma_xmit_complete(struct nsc_ircc_cb *self)
{
int iobase;
__u8 bank;
@@ -1097,7 +1310,7 @@ static int nsc_fir_dma_xmit_complete(struct nsc_fir_cb *self)
IRDA_DEBUG(2, __FUNCTION__ "()\n");
- iobase = self->io.iobase;
+ iobase = self->io.fir_base;
/* Save current bank */
bank = inb(iobase+BSR);
@@ -1115,11 +1328,11 @@ static int nsc_fir_dma_xmit_complete(struct nsc_fir_cb *self)
outb(ASCR_TXUR, iobase+ASCR);
} else {
self->stats.tx_packets++;
- self->stats.tx_bytes += self->tx_buff.len;
}
-
+
+ /* Check if we need to change the speed */
if (self->new_speed) {
- nsc_fir_change_speed(self, self->new_speed);
+ nsc_ircc_change_speed(self, self->new_speed);
self->new_speed = 0;
}
@@ -1129,17 +1342,24 @@ static int nsc_fir_dma_xmit_complete(struct nsc_fir_cb *self)
/* Any frames to be sent back-to-back? */
if (self->tx_fifo.len) {
- nsc_fir_dma_xmit(self, iobase);
+ nsc_ircc_dma_xmit(self, iobase);
/* Not finished yet! */
ret = FALSE;
+ } else {
+ /* Reset Tx FIFO info */
+ self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0;
+ self->tx_fifo.tail = self->tx_buff.head;
}
- /* Not busy transmitting anymore */
- self->netdev->tbusy = 0;
+ /* Make sure we have room for more frames */
+ if (self->tx_fifo.free < MAX_TX_WINDOW) {
+ /* Not busy transmitting anymore */
+ self->netdev->tbusy = 0;
- /* Tell the network layer, that we can accept more frames */
- mark_bh(NET_BH);
+ /* Tell the network layer, that we can accept more frames */
+ mark_bh(NET_BH);
+ }
/* Restore bank */
outb(bank, iobase+BSR);
@@ -1148,20 +1368,18 @@ static int nsc_fir_dma_xmit_complete(struct nsc_fir_cb *self)
}
/*
- * Function nsc_fir_dma_receive (self)
+ * Function nsc_ircc_dma_receive (self)
*
* Get ready for receiving a frame. The device will initiate a DMA
* if it starts to receive a frame.
*
*/
-static int nsc_fir_dma_receive(struct nsc_fir_cb *self)
+static int nsc_ircc_dma_receive(struct nsc_ircc_cb *self)
{
int iobase;
__u8 bsr;
- ASSERT(self != NULL, return -1;);
-
- iobase = self->io.iobase;
+ iobase = self->io.fir_base;
/* Reset Tx FIFO info */
self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0;
@@ -1184,7 +1402,9 @@ static int nsc_fir_dma_receive(struct nsc_fir_cb *self)
/* Reset Rx FIFO. This will also flush the ST_FIFO */
switch_bank(iobase, BANK0);
outb(FCR_RXSR|FCR_FIFO_EN, iobase+FCR);
- self->st_fifo.len = self->st_fifo.tail = self->st_fifo.head = 0;
+
+ self->st_fifo.len = self->st_fifo.pending_bytes = 0;
+ self->st_fifo.tail = self->st_fifo.head = 0;
setup_dma(self->io.dma, self->rx_buff.data, self->rx_buff.truesize,
DMA_RX_MODE);
@@ -1200,18 +1420,18 @@ static int nsc_fir_dma_receive(struct nsc_fir_cb *self)
}
/*
- * Function nsc_fir_dma_receive_complete (self)
+ * Function nsc_ircc_dma_receive_complete (self)
*
* Finished with receiving frames
*
*
*/
-static int nsc_fir_dma_receive_complete(struct nsc_fir_cb *self, int iobase)
+static int nsc_ircc_dma_receive_complete(struct nsc_ircc_cb *self, int iobase)
{
- struct sk_buff *skb;
struct st_fifo *st_fifo;
- __u8 bank;
+ struct sk_buff *skb;
__u8 status;
+ __u8 bank;
int len;
st_fifo = &self->st_fifo;
@@ -1219,22 +1439,27 @@ static int nsc_fir_dma_receive_complete(struct nsc_fir_cb *self, int iobase)
/* Save current bank */
bank = inb(iobase+BSR);
- /* Read status FIFO */
+ /* Read all entries in status FIFO */
switch_bank(iobase, BANK5);
while ((status = inb(iobase+FRM_ST)) & FRM_ST_VLD) {
- st_fifo->entries[st_fifo->tail].status = status;
+ /* We must empty the status FIFO no matter what */
+ len = inb(iobase+RFLFL) | ((inb(iobase+RFLFH) & 0x1f) << 8);
- st_fifo->entries[st_fifo->tail].len = inb(iobase+RFLFL);
- st_fifo->entries[st_fifo->tail].len |= inb(iobase+RFLFH) << 8;
-
+ if (st_fifo->tail >= MAX_RX_WINDOW)
+ continue;
+
+ st_fifo->entries[st_fifo->tail].status = status;
+ st_fifo->entries[st_fifo->tail].len = len;
+ st_fifo->pending_bytes += len;
st_fifo->tail++;
st_fifo->len++;
}
/* Try to process all entries in status FIFO */
- while (st_fifo->len) {
+ while (st_fifo->len > 0) {
/* Get first entry */
status = st_fifo->entries[st_fifo->head].status;
len = st_fifo->entries[st_fifo->head].len;
+ st_fifo->pending_bytes -= len;
st_fifo->head++;
st_fifo->len--;
@@ -1265,36 +1490,46 @@ static int nsc_fir_dma_receive_complete(struct nsc_fir_cb *self, int iobase)
if (status & FRM_ST_OVR2)
self->stats.rx_fifo_errors++;
} else {
- /* Check if we have transfered all data to memory */
- switch_bank(iobase, BANK0);
- if (inb(iobase+LSR) & LSR_RXDA) {
- /* Put this entry back in fifo */
- st_fifo->head--;
- st_fifo->len++;
- st_fifo->entries[st_fifo->head].status = status;
- st_fifo->entries[st_fifo->head].len = len;
-
- /* Restore bank register */
- outb(bank, iobase+BSR);
+ /*
+ * First we must make sure that the frame we
+ * want to deliver is all in main memory. If we
+ * cannot tell, then we check if the Rx FIFO is
+ * empty. If not then we will have to take a nap
+ * and try again later.
+ */
+ if (st_fifo->pending_bytes < self->io.fifo_size) {
+ switch_bank(iobase, BANK0);
+ if (inb(iobase+LSR) & LSR_RXDA) {
+ /* Put this entry back in fifo */
+ st_fifo->head--;
+ st_fifo->len++;
+ st_fifo->pending_bytes += len;
+ st_fifo->entries[st_fifo->head].status = status;
+ st_fifo->entries[st_fifo->head].len = len;
- return FALSE; /* I'll be back! */
+ /* Restore bank register */
+ outb(bank, iobase+BSR);
+
+ return FALSE; /* I'll be back! */
+ }
}
/*
- * Remember when we received this frame, so we can
+ * Remember the time we received this frame, so we can
* reduce the min turn time a bit since we will know
* how much time we have used for protocol processing
*/
- do_gettimeofday(&self->stamp);
+ get_fast_time(&self->stamp);
skb = dev_alloc_skb(len+1);
if (skb == NULL) {
WARNING(__FUNCTION__ "(), memory squeeze, "
"dropping frame.\n");
-
+ self->stats.rx_dropped++;
+
/* Restore bank register */
outb(bank, iobase+BSR);
-
+
return FALSE;
}
@@ -1312,6 +1547,7 @@ static int nsc_fir_dma_receive_complete(struct nsc_fir_cb *self, int iobase)
/* Move to next frame */
self->rx_buff.data += len;
+ self->stats.rx_bytes += len;
self->stats.rx_packets++;
skb->dev = self->netdev;
@@ -1327,21 +1563,17 @@ static int nsc_fir_dma_receive_complete(struct nsc_fir_cb *self, int iobase)
}
/*
- * Function nsc_fir_pio_receive (self)
+ * Function nsc_ircc_pio_receive (self)
*
* Receive all data in receiver FIFO
*
*/
-static void nsc_fir_pio_receive(struct nsc_fir_cb *self)
+static void nsc_ircc_pio_receive(struct nsc_ircc_cb *self)
{
- __u8 byte = 0x00;
+ __u8 byte;
int iobase;
- IRDA_DEBUG(4, __FUNCTION__ "()\n");
-
- ASSERT(self != NULL, return;);
-
- iobase = self->io.iobase;
+ iobase = self->io.fir_base;
/* Receive all characters in Rx FIFO */
do {
@@ -1352,20 +1584,19 @@ static void nsc_fir_pio_receive(struct nsc_fir_cb *self)
}
/*
- * Function nsc_fir_sir_interrupt (self, eir)
+ * Function nsc_ircc_sir_interrupt (self, eir)
*
* Handle SIR interrupt
*
*/
-static __u8 nsc_fir_sir_interrupt(struct nsc_fir_cb *self, int eir)
+static void nsc_ircc_sir_interrupt(struct nsc_ircc_cb *self, int eir)
{
int actual;
- __u8 new_ier = 0;
/* Check if transmit FIFO is low on data */
if (eir & EIR_TXLDL_EV) {
/* Write data left in transmit buffer */
- actual = nsc_fir_pio_write(self->io.iobase,
+ actual = nsc_ircc_pio_write(self->io.fir_base,
self->tx_buff.data,
self->tx_buff.len,
self->io.fifo_size);
@@ -1376,14 +1607,14 @@ static __u8 nsc_fir_sir_interrupt(struct nsc_fir_cb *self, int eir)
/* Check if finished */
if (self->tx_buff.len > 0)
- new_ier |= IER_TXLDL_IE;
+ self->ier = IER_TXLDL_IE;
else {
self->netdev->tbusy = 0; /* Unlock */
self->stats.tx_packets++;
mark_bh(NET_BH);
- new_ier |= IER_TXEMP_IE;
+ self->ier = IER_TXEMP_IE;
}
}
@@ -1392,56 +1623,62 @@ static __u8 nsc_fir_sir_interrupt(struct nsc_fir_cb *self, int eir)
/* Check if we need to change the speed? */
if (self->new_speed) {
IRDA_DEBUG(2, __FUNCTION__ "(), Changing speed!\n");
- nsc_fir_change_speed(self, self->new_speed);
+ nsc_ircc_change_speed(self, self->new_speed);
self->new_speed = 0;
- }
+ /* Check if we are going to FIR */
+ if (self->io.speed > 115200) {
+ /* Should wait for status FIFO interrupt */
+ self->ier = IER_SFIF_IE;
+
+ /* No need to do anymore SIR stuff */
+ return;
+ }
+ }
/* Turn around and get ready to receive some data */
self->io.direction = IO_RECV;
- new_ier |= IER_RXHDL_IE;
+ self->ier = IER_RXHDL_IE;
}
/* Rx FIFO threshold or timeout */
if (eir & EIR_RXHDL_EV) {
- nsc_fir_pio_receive(self);
+ nsc_ircc_pio_receive(self);
/* Keep receiving */
- new_ier |= IER_RXHDL_IE;
+ self->ier = IER_RXHDL_IE;
}
- return new_ier;
}
/*
- * Function nsc_fir_fir_interrupt (self, eir)
+ * Function nsc_ircc_fir_interrupt (self, eir)
*
* Handle MIR/FIR interrupt
*
*/
-static __u8 nsc_fir_fir_interrupt(struct nsc_fir_cb *self, int iobase, int eir)
+static void nsc_ircc_fir_interrupt(struct nsc_ircc_cb *self, int iobase,
+ int eir)
{
- __u8 new_ier = 0;
__u8 bank;
bank = inb(iobase+BSR);
- /* Status event, or end of frame detected in FIFO */
- if (eir & (EIR_SFIF_EV|EIR_LS_EV)) {
- if (nsc_fir_dma_receive_complete(self, iobase)) {
-
+ /* Status FIFO event*/
+ if (eir & EIR_SFIF_EV) {
+ if (nsc_ircc_dma_receive_complete(self, iobase)) {
/* Wait for next status FIFO interrupt */
- new_ier |= IER_SFIF_IE;
+ self->ier = IER_SFIF_IE;
} else {
- /* DMA not finished yet */
-
- /* Set timer value, resolution 125 us */
+ /*
+ * DMA not finished yet, so try again later, set
+ * timer value, resolution 125 us
+ */
switch_bank(iobase, BANK4);
- outb(0x0f, iobase+TMRL); /* 125 us * 15 */
+ outb(0x02, iobase+TMRL); /* 2 * 125 us */
outb(0x00, iobase+TMRH);
/* Start timer */
outb(IRCR1_TMR_EN, iobase+IRCR1);
-
- new_ier |= IER_TMR_IE;
+ self->ier = IER_TMR_IE | IER_SFIF_IE;
}
} else if (eir & EIR_TMR_EV) { /* Timer finished */
/* Disable timer */
@@ -1452,101 +1689,102 @@ static __u8 nsc_fir_fir_interrupt(struct nsc_fir_cb *self, int iobase, int eir)
switch_bank(iobase, BANK0);
outb(ASCR_CTE, iobase+ASCR);
- /* Check if this is a TX timer interrupt */
+ /* Check if this is a Tx timer interrupt */
if (self->io.direction == IO_XMIT) {
- nsc_fir_dma_xmit(self, iobase);
+ nsc_ircc_dma_xmit(self, iobase);
/* Interrupt on DMA */
- new_ier |= IER_DMA_IE;
+ self->ier = IER_DMA_IE;
} else {
/* Check if DMA has now finished */
- nsc_fir_dma_receive_complete(self, iobase);
+ nsc_ircc_dma_receive_complete(self, iobase);
- new_ier |= IER_SFIF_IE;
+ self->ier = IER_SFIF_IE;
}
- } else if (eir & EIR_DMA_EV) { /* Finished with transmission */
- if (nsc_fir_dma_xmit_complete(self)) {
+ } else if (eir & EIR_DMA_EV) {
+ /* Finished with all transmissions? */
+ if (nsc_ircc_dma_xmit_complete(self)) {
/* Check if there are more frames to be transmitted */
if (irda_device_txqueue_empty(self->netdev)) {
/* Prepare for receive */
- nsc_fir_dma_receive(self);
+ nsc_ircc_dma_receive(self);
- new_ier = IER_LS_IE|IER_SFIF_IE;
+ self->ier = IER_SFIF_IE;
}
} else {
/* Not finished yet, so interrupt on DMA again */
- new_ier |= IER_DMA_IE;
+ self->ier = IER_DMA_IE;
}
}
outb(bank, iobase+BSR);
-
- return new_ier;
}
/*
- * Function nsc_fir_interrupt (irq, dev_id, regs)
+ * Function nsc_ircc_interrupt (irq, dev_id, regs)
*
* An interrupt from the chip has arrived. Time to do some work
*
*/
-static void nsc_fir_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static void nsc_ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
struct net_device *dev = (struct net_device *) dev_id;
- struct nsc_fir_cb *self;
- __u8 bsr, eir, ier;
+ struct nsc_ircc_cb *self;
+ __u8 bsr, eir;
int iobase;
if (!dev) {
- printk(KERN_WARNING "%s: irq %d for unknown device.\n",
- driver_name, irq);
+ WARNING("%s: irq %d for unknown device.\n", driver_name, irq);
return;
}
- self = (struct nsc_fir_cb *) dev->priv;
+ self = (struct nsc_ircc_cb *) dev->priv;
spin_lock(&self->lock);
dev->interrupt = 1;
- iobase = self->io.iobase;
+ iobase = self->io.fir_base;
bsr = inb(iobase+BSR); /* Save current bank */
switch_bank(iobase, BANK0);
- ier = inb(iobase+IER);
- eir = inb(iobase+EIR) & ier; /* Mask out the interesting ones */
+ self->ier = inb(iobase+IER);
+ eir = inb(iobase+EIR) & self->ier; /* Mask out the interesting ones */
outb(0, iobase+IER); /* Disable interrupts */
if (eir) {
/* Dispatch interrupt handler for the current speed */
if (self->io.speed > 115200)
- ier = nsc_fir_fir_interrupt(self, iobase, eir);
+ nsc_ircc_fir_interrupt(self, iobase, eir);
else
- ier = nsc_fir_sir_interrupt(self, eir);
+ nsc_ircc_sir_interrupt(self, eir);
}
-
- outb(ier, iobase+IER); /* Restore interrupts */
- outb(bsr, iobase+BSR); /* Restore bank register */
+
+ outb(self->ier, iobase+IER); /* Restore interrupts */
+ outb(bsr, iobase+BSR); /* Restore bank register */
dev->interrupt = 0;
spin_unlock(&self->lock);
}
/*
- * Function nsc_fir_is_receiving (self)
+ * Function nsc_ircc_is_receiving (self)
*
* Return TRUE is we are currently receiving a frame
*
*/
-static int nsc_fir_is_receiving(struct nsc_fir_cb *self)
+static int nsc_ircc_is_receiving(struct nsc_ircc_cb *self)
{
+ unsigned long flags;
int status = FALSE;
int iobase;
__u8 bank;
ASSERT(self != NULL, return FALSE;);
+ spin_lock_irqsave(&self->lock, flags);
+
if (self->io.speed > 115200) {
- iobase = self->io.iobase;
+ iobase = self->io.fir_base;
/* Check if rx FIFO is not empty */
bank = inb(iobase+BSR);
@@ -1559,16 +1797,18 @@ static int nsc_fir_is_receiving(struct nsc_fir_cb *self)
} else
status = (self->rx_buff.state != OUTSIDE_FRAME);
+ spin_unlock_irqrestore(&self->lock, flags);
+
return status;
}
/*
- * Function nsc_fir_net_init (dev)
+ * Function nsc_ircc_net_init (dev)
*
* Initialize network device
*
*/
-static int nsc_fir_net_init(struct net_device *dev)
+static int nsc_ircc_net_init(struct net_device *dev)
{
IRDA_DEBUG(4, __FUNCTION__ "()\n");
@@ -1581,29 +1821,29 @@ static int nsc_fir_net_init(struct net_device *dev)
}
/*
- * Function nsc_fir_net_open (dev)
+ * Function nsc_ircc_net_open (dev)
*
* Start the device
*
*/
-static int nsc_fir_net_open(struct net_device *dev)
+static int nsc_ircc_net_open(struct net_device *dev)
{
- struct nsc_fir_cb *self;
+ struct nsc_ircc_cb *self;
int iobase;
__u8 bank;
IRDA_DEBUG(4, __FUNCTION__ "()\n");
ASSERT(dev != NULL, return -1;);
- self = (struct nsc_fir_cb *) dev->priv;
+ self = (struct nsc_ircc_cb *) dev->priv;
ASSERT(self != NULL, return 0;);
- iobase = self->io.iobase;
-
- if (request_irq(self->io.irq, nsc_fir_interrupt, 0, dev->name,
- (void *) dev))
- {
+ iobase = self->io.fir_base;
+
+ if (request_irq(self->io.irq, nsc_ircc_interrupt, 0, dev->name, dev)) {
+ WARNING("%s, unable to allocate irq=%d\n", driver_name,
+ self->io.irq);
return -EAGAIN;
}
/*
@@ -1611,6 +1851,8 @@ static int nsc_fir_net_open(struct net_device *dev)
* failure.
*/
if (request_dma(self->io.dma, dev->name)) {
+ WARNING("%s, unable to allocate dma=%d\n", driver_name,
+ self->io.dma);
free_irq(self->io.irq, self);
return -EAGAIN;
}
@@ -1642,22 +1884,22 @@ static int nsc_fir_net_open(struct net_device *dev)
}
/*
- * Function nsc_fir_net_close (dev)
+ * Function nsc_ircc_net_close (dev)
*
* Stop the device
*
*/
-static int nsc_fir_net_close(struct net_device *dev)
+static int nsc_ircc_net_close(struct net_device *dev)
{
- struct nsc_fir_cb *self;
+ struct nsc_ircc_cb *self;
int iobase;
__u8 bank;
IRDA_DEBUG(4, __FUNCTION__ "()\n");
ASSERT(dev != NULL, return -1;);
- self = (struct nsc_fir_cb *) dev->priv;
-
+
+ self = (struct nsc_ircc_cb *) dev->priv;
ASSERT(self != NULL, return 0;);
/* Stop device */
@@ -1669,7 +1911,7 @@ static int nsc_fir_net_close(struct net_device *dev)
irlap_close(self->irlap);
self->irlap = NULL;
- iobase = self->io.iobase;
+ iobase = self->io.fir_base;
disable_dma(self->io.dma);
@@ -1692,15 +1934,15 @@ static int nsc_fir_net_close(struct net_device *dev)
}
/*
- * Function nsc_fir_net_ioctl (dev, rq, cmd)
+ * Function nsc_ircc_net_ioctl (dev, rq, cmd)
*
* Process IOCTL commands for this device
*
*/
-static int nsc_fir_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+static int nsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
struct if_irda_req *irq = (struct if_irda_req *) rq;
- struct nsc_fir_cb *self;
+ struct nsc_ircc_cb *self;
unsigned long flags;
int ret = 0;
@@ -1718,13 +1960,13 @@ static int nsc_fir_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
switch (cmd) {
case SIOCSBANDWIDTH: /* Set bandwidth */
- nsc_fir_change_speed(self, irq->ifr_baudrate);
+ nsc_ircc_change_speed(self, irq->ifr_baudrate);
break;
case SIOCSMEDIABUSY: /* Set media busy */
irda_device_set_media_busy(self->netdev, TRUE);
break;
case SIOCGRECEIVING: /* Check if we are receiving right now */
- irq->ifr_receiving = nsc_fir_is_receiving(self);
+ irq->ifr_receiving = nsc_ircc_is_receiving(self);
break;
default:
ret = -EOPNOTSUPP;
@@ -1735,54 +1977,60 @@ static int nsc_fir_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
return ret;
}
-static struct net_device_stats *nsc_fir_net_get_stats(struct net_device *dev)
+static struct net_device_stats *nsc_ircc_net_get_stats(struct net_device *dev)
{
- struct nsc_fir_cb *self = (struct nsc_fir_cb *) dev->priv;
+ struct nsc_ircc_cb *self = (struct nsc_ircc_cb *) dev->priv;
return &self->stats;
}
#ifdef CONFIG_APM
-static void nsc_fir_suspend(struct nsc_fir_cb *self)
+static void nsc_ircc_suspend(struct nsc_ircc_cb *self)
{
- int i = 10;
-
MESSAGE("%s, Suspending\n", driver_name);
- if (self->suspend)
+ if (self->io.suspended)
return;
- self->suspend = 1;
-}
+ nsc_ircc_net_close(self->netdev);
+ self->io.suspended = 1;
+}
-static void nsc_fir_wakeup(struct nsc_fir_cb *self)
+static void nsc_ircc_wakeup(struct nsc_ircc_cb *self)
{
struct net_device *dev = self->netdev;
- unsigned long flags;
+ int iobase;
- if (!self->suspend)
+ if (!self->io.suspended)
return;
- save_flags(flags);
- cli();
+ iobase = self->io.fir_base;
- restore_flags(flags);
+ /* Switch to advanced mode */
+ switch_bank(iobase, BANK2);
+ outb(ECR1_EXT_SL, iobase+ECR1);
+ switch_bank(iobase, BANK0);
+
+ nsc_ircc_net_open(self->netdev);
+
MESSAGE("%s, Waking up\n", driver_name);
+
+ self->io.suspended = 0;
}
-static int nsc_fir_apmproc(apm_event_t event)
+static int nsc_ircc_apmproc(apm_event_t event)
{
- static int down = 0; /* Filter out double events */
+ static int down = 0; /* Filter out double events */
int i;
switch (event) {
case APM_SYS_SUSPEND:
case APM_USER_SUSPEND:
if (!down) {
- for (i = 0; i < 4; i++) {
+ for (i=0; i<4; i++) {
if (dev_self[i])
- nsc_fir_suspend(dev_self[i]);
+ nsc_ircc_suspend(dev_self[i]);
}
}
down = 1;
@@ -1790,9 +2038,9 @@ static int nsc_fir_apmproc(apm_event_t event)
case APM_NORMAL_RESUME:
case APM_CRITICAL_RESUME:
if (down) {
- for (i = 0; i < 4; i++) {
+ for (i=0; i<4; i++) {
if (dev_self[i])
- nsc_fir_wakeup(dev_self[i]);
+ nsc_ircc_wakeup(dev_self[i]);
}
}
down = 0;
@@ -1804,22 +2052,22 @@ static int nsc_fir_apmproc(apm_event_t event)
#ifdef MODULE
MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
-MODULE_DESCRIPTION("NSC FIR IrDA Device Driver");
+MODULE_DESCRIPTION("NSC IrDA Device Driver");
MODULE_PARM(qos_mtt_bits, "i");
-MODULE_PARM(io, "1-4i");
-MODULE_PARM(io2, "1-4i");
+MODULE_PARM(io, "1-4i");
MODULE_PARM(irq, "1-4i");
+MODULE_PARM(dma, "1-4i");
MODULE_PARM(dongle_id, "i");
int init_module(void)
{
- return nsc_fir_init();
+ return nsc_ircc_init();
}
void cleanup_module(void)
{
- nsc_fir_cleanup();
+ nsc_ircc_cleanup();
}
#endif /* MODULE */
diff --git a/drivers/net/irda/smc-ircc.c b/drivers/net/irda/smc-ircc.c
index 1d857c2b0..48b38227e 100644
--- a/drivers/net/irda/smc-ircc.c
+++ b/drivers/net/irda/smc-ircc.c
@@ -1,12 +1,12 @@
/*********************************************************************
*
* Filename: smc-ircc.c
- * Version: 0.3
+ * Version: 0.4
* Description: Driver for the SMC Infrared Communications Controller
* Status: Experimental.
* Author: Thomas Davis (tadavis@jps.net)
* Created at:
- * Modified at: Wed Jan 5 12:38:06 2000
+ * Modified at: Fri Jan 21 09:41:08 2000
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1999-2000 Dag Brattli
@@ -28,11 +28,12 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
- * SIO's: SMC FDC37N869, FDC37C669
+ * SIO's: SMC FDC37N869, FDC37C669, FDC37N958
* Applicable Models : Fujitsu Lifebook 635t, Sony PCG-505TX
*
********************************************************************/
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
@@ -44,11 +45,16 @@
#include <linux/malloc.h>
#include <linux/init.h>
#include <linux/rtnetlink.h>
+#include <linux/serial_reg.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <asm/byteorder.h>
+#ifdef CONFIG_APM
+#include <linux/apm_bios.h>
+#endif
+
#include <net/irda/wrapper.h>
#include <net/irda/irda.h>
#include <net/irda/irmod.h>
@@ -62,10 +68,10 @@ static char *driver_name = "smc-ircc";
#define CHIP_IO_EXTENT 8
-static unsigned int io[] = { 0x2e8, 0x140, 0x118, 0x240 };
-static unsigned int io2[] = { 0x2f8, 0x3e8, 0x2e8, 0x3e8 };
+static unsigned int io[] = { ~0, ~0 };
+static unsigned int io2[] = { 0, 0 };
-static struct ircc_cb *dev_self[] = { NULL, NULL, NULL, NULL};
+static struct ircc_cb *dev_self[] = { NULL, NULL};
/* Some prototypes */
static int ircc_open(int i, unsigned int iobase, unsigned int board_addr);
@@ -73,17 +79,30 @@ static int ircc_open(int i, unsigned int iobase, unsigned int board_addr);
static int ircc_close(struct ircc_cb *self);
#endif /* MODULE */
static int ircc_probe(int iobase, int board_addr);
-static int ircc_probe_smc(int *ioaddr, int *ioaddr2);
-static int ircc_dma_receive(struct ircc_cb *self);
-static int ircc_dma_receive_complete(struct ircc_cb *self, int iobase);
+static int ircc_probe_58(smc_chip_t *chip, chipio_t *info);
+static int ircc_probe_69(smc_chip_t *chip, chipio_t *info);
+static int ircc_dma_receive(struct ircc_cb *self, int iobase);
+static void ircc_dma_receive_complete(struct ircc_cb *self, int iobase);
static int ircc_hard_xmit(struct sk_buff *skb, struct net_device *dev);
-static void ircc_dma_xmit(struct ircc_cb *self, int iobase);
+static void ircc_dma_xmit(struct ircc_cb *self, int iobase, int bofs);
static void ircc_change_speed(void *priv, __u32 speed);
static void ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static int ircc_is_receiving(struct ircc_cb *self);
static int ircc_net_open(struct net_device *dev);
static int ircc_net_close(struct net_device *dev);
+#ifdef CONFIG_APM
+static int ircc_apmproc(apm_event_t event);
+#endif /* CONFIG_APM */
+
+/* These are the currently known SMC chipsets */
+static smc_chip_t chips[] =
+{
+ { "FDC37C669", 0x55, 0x55, 0x0d, 0x04, ircc_probe_69 },
+ { "FDC37N869", 0x55, 0x00, 0x0d, 0x29, ircc_probe_69 },
+ { "FDC37N958", 0x55, 0x55, 0x20, 0x09, ircc_probe_58 },
+ { NULL }
+};
static int ircc_irq=255;
static int ircc_dma=255;
@@ -102,26 +121,38 @@ static inline void register_bank(int iobase, int bank)
*/
int __init ircc_init(void)
{
- int ioaddr, ioaddr2;
+ static int smcreg[] = { 0x3f0, 0x370 };
+ smc_chip_t *chip;
+ chipio_t info;
+ int ret = -ENODEV;
int i;
IRDA_DEBUG(0, __FUNCTION__ "\n");
- for (i=0; (io[i] < 2000) && (i < 4); i++) {
- int ioaddr = io[i];
- if (check_region(ioaddr, CHIP_IO_EXTENT))
- continue;
- if (ircc_open(i, io[i], io2[i]) == 0)
- return 0;
- }
- /* last chance saloon, see what the controller says */
- if (ircc_probe_smc(&ioaddr, &ioaddr2) == 0) {
- if (check_region(ioaddr, CHIP_IO_EXTENT) == 0)
- if (ircc_open(0, ioaddr, ioaddr2) == 0)
- return 0;
+ /* Probe for all the NSC chipsets we know about */
+ for (chip=chips; chip->name ; chip++,i++) {
+ for (i=0; i<2; i++) {
+ info.cfg_base = smcreg[i];
+
+ /*
+ * First we check if the user has supplied any
+ * parameters which we should use instead of probed
+ * values
+ */
+ if (io[i] < 2000) {
+ info.fir_base = io[i];
+ info.sir_base = io2[i];
+ } else if (chip->probe(chip, &info) < 0)
+ continue;
+ if (check_region(info.fir_base, CHIP_IO_EXTENT) < 0)
+ continue;
+ if (check_region(info.sir_base, CHIP_IO_EXTENT) < 0)
+ continue;
+ if (ircc_open(i, info.fir_base, info.sir_base) == 0)
+ ret = 0;
+ }
}
-
- return -ENODEV;
+ return ret;
}
/*
@@ -137,7 +168,7 @@ static void ircc_cleanup(void)
IRDA_DEBUG(0, __FUNCTION__ "\n");
- for (i=0; i < 4; i++) {
+ for (i=0; i < 2; i++) {
if (dev_self[i])
ircc_close(dev_self[i]);
}
@@ -150,7 +181,7 @@ static void ircc_cleanup(void)
* Open driver instance
*
*/
-static int ircc_open(int i, unsigned int iobase, unsigned int iobase2)
+static int ircc_open(int i, unsigned int fir_base, unsigned int sir_base)
{
struct ircc_cb *self;
struct irport_cb *irport;
@@ -159,9 +190,9 @@ static int ircc_open(int i, unsigned int iobase, unsigned int iobase2)
IRDA_DEBUG(0, __FUNCTION__ "\n");
- if ((config = ircc_probe(iobase, iobase2)) == -1) {
+ if ((config = ircc_probe(fir_base, sir_base)) == -1) {
IRDA_DEBUG(0, __FUNCTION__
- "(), addr 0x%04x - no device found!\n", iobase);
+ "(), addr 0x%04x - no device found!\n", fir_base);
return -1;
}
@@ -180,7 +211,7 @@ static int ircc_open(int i, unsigned int iobase, unsigned int iobase2)
/* Need to store self somewhere */
dev_self[i] = self;
- irport = irport_open(0, iobase2, config >> 4 & 0x0f);
+ irport = irport_open(i, sir_base, config >> 4 & 0x0f);
if (!irport)
return -ENODEV;
@@ -190,34 +221,32 @@ static int ircc_open(int i, unsigned int iobase, unsigned int iobase2)
irport->priv = self;
/* Initialize IO */
- self->io.iobase = iobase;
- self->io.iobase2 = iobase2; /* Used by irport */
+ self->io.fir_base = fir_base;
+ self->io.sir_base = sir_base; /* Used by irport */
self->io.irq = config >> 4 & 0x0f;
if (ircc_irq < 255) {
MESSAGE("%s, Overriding IRQ - chip says %d, using %d\n",
driver_name, self->io.irq, ircc_irq);
self->io.irq = ircc_irq;
}
- self->io.io_ext = CHIP_IO_EXTENT;
- self->io.io_ext2 = 8; /* Used by irport */
+ self->io.fir_ext = CHIP_IO_EXTENT;
+ self->io.sir_ext = 8; /* Used by irport */
self->io.dma = config & 0x0f;
if (ircc_dma < 255) {
MESSAGE("%s, Overriding DMA - chip says %d, using %d\n",
driver_name, self->io.dma, ircc_dma);
self->io.dma = ircc_dma;
}
- self->io.fifo_size = 16;
/* Lock the port that we need */
- ret = check_region(self->io.iobase, self->io.io_ext);
+ ret = check_region(self->io.fir_base, self->io.fir_ext);
if (ret < 0) {
- IRDA_DEBUG(0, __FUNCTION__ ": can't get iobase of 0x%03x\n",
- self->io.iobase);
- /* ircc_cleanup(self->self); */
+ IRDA_DEBUG(0, __FUNCTION__ ": can't get fir_base of 0x%03x\n",
+ self->io.fir_base);
+ kfree(self);
return -ENODEV;
}
-
- request_region(self->io.iobase, self->io.io_ext, driver_name);
+ request_region(self->io.fir_base, self->io.fir_ext, driver_name);
/* Initialize QoS for this device */
irda_init_max_qos_capabilies(&irport->qos);
@@ -229,7 +258,7 @@ static int ircc_open(int i, unsigned int iobase, unsigned int iobase2)
irport->qos.min_turn_time.bits = 0x07;
irda_qos_bits_to_value(&irport->qos);
- irport->flags = IFF_FIR|IFF_SIR|IFF_DMA|IFF_PIO;
+ irport->flags = IFF_FIR|IFF_MIR|IFF_SIR|IFF_DMA|IFF_PIO;
/* Max DMA buffer size needed = (data_size + 6) * (window_size) + 6; */
self->rx_buff.truesize = 4000;
@@ -256,6 +285,7 @@ static int ircc_open(int i, unsigned int iobase, unsigned int iobase2)
/* Override the speed change function, since we must control it now */
irport->change_speed = &ircc_change_speed;
+ irport->interrupt = &ircc_interrupt;
self->netdev->open = &ircc_net_open;
self->netdev->stop = &ircc_net_close;
@@ -279,23 +309,26 @@ static int ircc_close(struct ircc_cb *self)
ASSERT(self != NULL, return -1;);
- iobase = self->io.iobase;
+ iobase = self->io.fir_base;
irport_close(self->irport);
+ /* Stop interrupts */
register_bank(iobase, 0);
outb(0, iobase+IRCC_IER);
outb(IRCC_MASTER_RESET, iobase+IRCC_MASTER);
-
+ outb(0x00, iobase+IRCC_MASTER);
+#if 0
+ /* Reset to SIR mode */
register_bank(iobase, 1);
-
outb(IRCC_CFGA_IRDA_SIR_A|IRCC_CFGA_TX_POLARITY, iobase+IRCC_SCE_CFGA);
outb(IRCC_CFGB_IR, iobase+IRCC_SCE_CFGB);
-
+#endif
/* Release the PORT that this driver is using */
- IRDA_DEBUG(0, __FUNCTION__ "(), releasing 0x%03x\n", self->io.iobase);
+ IRDA_DEBUG(0, __FUNCTION__ "(), releasing 0x%03x\n",
+ self->io.fir_base);
- release_region(self->io.iobase, self->io.io_ext);
+ release_region(self->io.fir_base, self->io.fir_ext);
if (self->tx_buff.head)
kfree(self->tx_buff.head);
@@ -310,58 +343,106 @@ static int ircc_close(struct ircc_cb *self)
#endif /* MODULE */
/*
- * Function ircc_probe_smc (ioaddr, ioaddr2)
+ * Function ircc_probe_69 (chip, info)
*
- * Probe the SMC Chip for an IrDA port
+ * Probes for the SMC FDC37C669 and FDC37N869
*
*/
-static int ircc_probe_smc(int *ioaddr, int *ioaddr2)
+static int ircc_probe_69(smc_chip_t *chip, chipio_t *info)
{
- static int smcreg[] = { 0x3f0, 0x370 };
+ int cfg_base = info->cfg_base;
__u8 devid, mode;
- __u8 conf_reg;
- int ret = -1;
+ int ret = -ENODEV;
int fir_io;
- int i;
IRDA_DEBUG(0, __FUNCTION__ "()\n");
- for (i = 0; i < 2 && ret == -1; i++) {
- conf_reg = smcreg[i];
-
- /* Enter configuration */
- outb(0x55, conf_reg);
- outb(0x55, conf_reg);
-
- outb(0x0d, conf_reg);
- devid = inb(conf_reg+1);
- IRDA_DEBUG(0, __FUNCTION__ "(), devid=0x%02x\n",devid);
+ /* Enter configuration */
+ outb(chip->entr1, cfg_base);
+ outb(chip->entr2, cfg_base);
+
+ outb(chip->cid_index, cfg_base);
+ devid = inb(cfg_base+1);
+ IRDA_DEBUG(0, __FUNCTION__ "(), devid=0x%02x\n",devid);
+
+ /* Check for expected device ID; are there others? */
+ if (devid == chip->cid_value) {
+ outb(0x0c, cfg_base);
+ mode = inb(cfg_base+1);
+ mode = (mode & 0x38) >> 3;
- /* Check for expected device ID; are there others? */
- if (devid == 0x29) {
- outb(0x0c, conf_reg);
- mode = inb(conf_reg+1);
- mode = (mode & 0x38) >> 3;
-
- /* Value for IR port */
- if (mode && mode < 4) {
- /* SIR iobase */
- outb(0x25, conf_reg);
- *ioaddr2 = inb(conf_reg+1) << 2;
-
- /* FIR iobase */
- outb(0x2b, conf_reg);
- fir_io = inb(conf_reg+1) << 3;
- if (fir_io) {
- ret = 0;
- *ioaddr = fir_io;
- }
+ /* Value for IR port */
+ if (mode && mode < 4) {
+ /* SIR iobase */
+ outb(0x25, cfg_base);
+ info->sir_base = inb(cfg_base+1) << 2;
+
+ /* FIR iobase */
+ outb(0x2b, cfg_base);
+ fir_io = inb(cfg_base+1) << 3;
+ if (fir_io) {
+ ret = 0;
+ info->fir_base = fir_io;
}
}
+ }
+
+ /* Exit configuration */
+ outb(0xaa, cfg_base);
+
+ return ret;
+}
+
+/*
+ * Function ircc_probe_58 (chip, info)
+ *
+ * Probes for the SMC FDC37N958
+ *
+ */
+static int ircc_probe_58(smc_chip_t *chip, chipio_t *info)
+{
+ int cfg_base = info->cfg_base;
+ __u8 devid;
+ int ret = -ENODEV;
+ int fir_io;
+
+ IRDA_DEBUG(0, __FUNCTION__ "()\n");
+
+ /* Enter configuration */
+ outb(chip->entr1, cfg_base);
+ outb(chip->entr2, cfg_base);
+
+ outb(chip->cid_index, cfg_base);
+ devid = inb(cfg_base+1);
+ IRDA_DEBUG(0, __FUNCTION__ "(), devid=0x%02x\n",devid);
+
+ /* Check for expected device ID; are there others? */
+ if (devid == chip->cid_value) {
+ /* Select logical device (UART2) */
+ outb(0x07, cfg_base);
+ outb(0x05, cfg_base + 1);
+
+ /* SIR iobase */
+ outb(0x60, cfg_base);
+ info->sir_base = inb(cfg_base + 1) << 8;
+ outb(0x61, cfg_base);
+ info->sir_base |= inb(cfg_base + 1);
+
+ /* Read FIR base */
+ outb(0x62, cfg_base);
+ fir_io = inb(cfg_base + 1) << 8;
+ outb(0x63, cfg_base);
+ fir_io |= inb(cfg_base + 1);
+ outb(0x2b, cfg_base);
+ if (fir_io) {
+ ret = 0;
+ info->fir_base = fir_io;
+ }
+ }
+
+ /* Exit configuration */
+ outb(0xaa, cfg_base);
- /* Exit configuration */
- outb(0xaa, conf_reg);
- }
return ret;
}
@@ -371,34 +452,32 @@ static int ircc_probe_smc(int *ioaddr, int *ioaddr2)
* Returns non-negative on success.
*
*/
-static int ircc_probe(int iobase, int iobase2)
+static int ircc_probe(int fir_base, int sir_base)
{
- int version = 1;
int low, high, chip, config, dma, irq;
-
- IRDA_DEBUG(0, __FUNCTION__ "\n");
+ int iobase = fir_base;
+ int version = 1;
- /* Power on device */
- outb(inb(iobase+IRCC_MASTER) & ~IRCC_MASTER_POWERDOWN,
- iobase+IRCC_MASTER);
+ IRDA_DEBUG(0, __FUNCTION__ "\n");
register_bank(iobase, 3);
- high = inb(iobase+IRCC_ID_HIGH);
- low = inb(iobase+IRCC_ID_LOW);
- chip = inb(iobase+IRCC_CHIP_ID);
+ high = inb(iobase+IRCC_ID_HIGH);
+ low = inb(iobase+IRCC_ID_LOW);
+ chip = inb(iobase+IRCC_CHIP_ID);
version = inb(iobase+IRCC_VERSION);
- config = inb(iobase+IRCC_INTERFACE);
- irq = config >> 4 & 0x0f;
- dma = config & 0x0f;
+ config = inb(iobase+IRCC_INTERFACE);
+ irq = config >> 4 & 0x0f;
+ dma = config & 0x0f;
if (high == 0x10 && low == 0xb8 && (chip == 0xf1 || chip == 0xf2)) {
- IRDA_DEBUG(0, "SMC IrDA Controller found; IrCC version %d.%d, "
- "port 0x%04x, dma %d, interrupt %d\n",
- chip & 0x0f, version, iobase, dma, irq);
+ MESSAGE("SMC IrDA Controller found; IrCC version %d.%d, "
+ "port 0x%03x, dma=%d, irq=%d\n",
+ chip & 0x0f, version, iobase, dma, irq);
} else
- return -1;
+ return -ENODEV;
- outb(0, iobase+IRCC_MASTER);
+ /* Power on device */
+ outb(0x00, iobase+IRCC_MASTER);
return config;
}
@@ -411,7 +490,7 @@ static int ircc_probe(int iobase, int iobase2)
*/
static void ircc_change_speed(void *priv, __u32 speed)
{
- int iobase, ir_mode, select, fast;
+ int iobase, ir_mode, ctrl, fast;
struct ircc_cb *self = (struct ircc_cb *) priv;
struct net_device *dev;
@@ -420,49 +499,39 @@ static void ircc_change_speed(void *priv, __u32 speed)
ASSERT(self != NULL, return;);
dev = self->netdev;
- iobase = self->io.iobase;
+ iobase = self->io.fir_base;
/* Update accounting for new speed */
self->io.speed = speed;
+ outb(IRCC_MASTER_RESET, iobase+IRCC_MASTER);
+ outb(0x00, iobase+IRCC_MASTER);
+
switch (speed) {
case 9600:
case 19200:
case 38400:
case 57600:
- case 115200:
- IRDA_DEBUG(0, __FUNCTION__
- "(), using irport to change speed to %d\n", speed);
-
- register_bank(iobase, 0);
- outb(0, iobase+IRCC_IER);
- outb(IRCC_MASTER_RESET, iobase+IRCC_MASTER);
- outb(IRCC_MASTER_INT_EN, iobase+IRCC_MASTER);
-
- dev->hard_start_xmit = &irport_hard_xmit;
-
- /* We must give the interrupt back to irport */
- self->irport->interrupt = irport_interrupt;
-
- irport_start(self->irport);
- irport_change_speed(self->irport, speed);
- return;
+ case 115200:
+ ir_mode = IRCC_CFGA_IRDA_SIR_A;
+ ctrl = 0;
+ fast = 0;
break;
case 576000:
ir_mode = IRCC_CFGA_IRDA_HDLC;
- select = 0;
+ ctrl = IRCC_CRC;
fast = 0;
IRDA_DEBUG(0, __FUNCTION__ "(), handling baud of 576000\n");
break;
case 1152000:
ir_mode = IRCC_CFGA_IRDA_HDLC;
- select = IRCC_1152;
+ ctrl = IRCC_1152 | IRCC_CRC;
fast = 0;
IRDA_DEBUG(0, __FUNCTION__ "(), handling baud of 1152000\n");
break;
case 4000000:
ir_mode = IRCC_CFGA_IRDA_4PPM;
- select = 0;
+ ctrl = IRCC_CRC;
fast = IRCC_LCR_A_FAST;
IRDA_DEBUG(0, __FUNCTION__ "(), handling baud of 4000000\n");
break;
@@ -471,39 +540,55 @@ static void ircc_change_speed(void *priv, __u32 speed)
speed);
return;
}
-
- outb(IRCC_MASTER_RESET, iobase+IRCC_MASTER);
-
+
register_bank(iobase, 0);
outb(0, iobase+IRCC_IER);
-
- irport_stop(self->irport);
+ outb(IRCC_MASTER_INT_EN, iobase+IRCC_MASTER);
+
+ /* Make special FIR init if necessary */
+ if (speed > 115200) {
+ irport_stop(self->irport);
- /* Install FIR transmit handler */
- dev->hard_start_xmit = &ircc_hard_xmit;
+ /* Install FIR transmit handler */
+ dev->hard_start_xmit = &ircc_hard_xmit;
- /* Need to steal the interrupt as well */
- self->irport->interrupt = &ircc_interrupt;
+ /*
+ * Don't know why we have to do this, but FIR interrupts
+ * stops working if we remove it.
+ */
+ /* outb(UART_MCR_OUT2, self->io.sir_base + UART_MCR); */
+ /* Be ready for incomming frames */
+ ircc_dma_receive(self, iobase);
+ } else {
+ /* Install SIR transmit handler */
+ dev->hard_start_xmit = &irport_hard_xmit;
+ irport_start(self->irport);
+
+ IRDA_DEBUG(0, __FUNCTION__
+ "(), using irport to change speed to %d\n", speed);
+ irport_change_speed(self->irport, speed);
+ }
dev->tbusy = 0;
-
+
register_bank(iobase, 1);
outb(((inb(iobase+IRCC_SCE_CFGA) & 0x87) | ir_mode),
iobase+IRCC_SCE_CFGA);
-
- outb(((inb(iobase+IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_IR),
- iobase+IRCC_SCE_CFGB);
+#ifdef SMC_669 /* Uses pin 88/89 for Rx/Tx */
+ outb(((inb(iobase+IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_COM),
+ iobase+IRCC_SCE_CFGB);
+#else
+ outb(((inb(iobase+IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_IR),
+ iobase+IRCC_SCE_CFGB);
+#endif
(void) inb(iobase+IRCC_FIFO_THRESHOLD);
outb(64, iobase+IRCC_FIFO_THRESHOLD);
-
+
register_bank(iobase, 4);
-
- outb((inb(iobase+IRCC_CONTROL) & 0x30) | select | IRCC_CRC,
- iobase+IRCC_CONTROL);
-
+ outb((inb(iobase+IRCC_CONTROL) & 0x30) | ctrl, iobase+IRCC_CONTROL);
+
register_bank(iobase, 0);
-
outb(fast, iobase+IRCC_LCR_A);
}
@@ -517,21 +602,20 @@ static int ircc_hard_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct irport_cb *irport;
struct ircc_cb *self;
+ unsigned long flags;
+ __u32 speed;
int iobase;
int mtt;
- __u32 speed;
irport = (struct irport_cb *) dev->priv;
self = (struct ircc_cb *) irport->priv;
-
ASSERT(self != NULL, return 0;);
- iobase = self->io.iobase;
+ iobase = self->io.fir_base;
- IRDA_DEBUG(2, __FUNCTION__ "(%ld), skb->len=%d\n", jiffies,
- (int) skb->len);
+ spin_lock_irqsave(&self->lock, flags);
- /* Check if we need to change the speed */
+ /* Check if we need to change the speed after this frame */
if ((speed = irda_get_speed(skb)) != self->io.speed)
self->new_speed = speed;
@@ -541,19 +625,28 @@ static int ircc_hard_xmit(struct sk_buff *skb, struct net_device *dev)
memcpy(self->tx_buff.head, skb->data, skb->len);
- /* Make sure that the length is a multiple of 16 bits */
- if (skb->len & 0x01)
- skb->len++;
-
self->tx_buff.len = skb->len;
self->tx_buff.data = self->tx_buff.head;
mtt = irda_get_mtt(skb);
- if (mtt)
- udelay(mtt);
-
- ircc_dma_xmit(self, iobase);
+ if (mtt) {
+ int bofs;
+
+ /*
+ * Compute who many BOFS (STA or PA's) we need to waste the
+ * min turn time given the speed of the link.
+ */
+ bofs = mtt * (self->io.speed / 1000) / 8000;
+ if (bofs > 4095)
+ bofs = 4095;
+
+ ircc_dma_xmit(self, iobase, bofs);
+ } else {
+ /* Transmit frame */
+ ircc_dma_xmit(self, iobase, 0);
+ }
+ spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb);
return 0;
@@ -565,44 +658,49 @@ static int ircc_hard_xmit(struct sk_buff *skb, struct net_device *dev)
* Transmit data using DMA
*
*/
-static void ircc_dma_xmit(struct ircc_cb *self, int iobase)
+static void ircc_dma_xmit(struct ircc_cb *self, int iobase, int bofs)
{
- IRDA_DEBUG(2, __FUNCTION__ "\n");
+ __u8 ctrl;
- ASSERT(self != NULL, return;);
-
- iobase = self->io.iobase;
+ IRDA_DEBUG(2, __FUNCTION__ "\n");
+#if 0
+ /* Disable Rx */
+ register_bank(iobase, 0);
+ outb(0x00, iobase+IRCC_LCR_B);
+#endif
+ register_bank(iobase, 1);
+ outb(inb(iobase+IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE,
+ iobase+IRCC_SCE_CFGB);
- setup_dma(self->io.dma, self->tx_buff.data, self->tx_buff.len,
- DMA_TX_MODE);
-
self->io.direction = IO_XMIT;
- outb(0x08, self->io.iobase2+4);
-
+ /* Set BOF additional count for generating the min turn time */
register_bank(iobase, 4);
- outb((inb(iobase+IRCC_CONTROL) & 0xf0), iobase+IRCC_CONTROL);
-
- outb(2, iobase+IRCC_BOF_COUNT_LO);
- outb(0, iobase+IRCC_BRICKWALL_CNT_LO);
-#if 1
- outb(self->tx_buff.len >> 8, iobase+IRCC_BRICKWALL_TX_CNT_HI);
+ outb(bofs & 0xff, iobase+IRCC_BOF_COUNT_LO);
+ ctrl = inb(iobase+IRCC_CONTROL) & 0xf0;
+ outb(ctrl | ((bofs >> 8) & 0x0f), iobase+IRCC_BOF_COUNT_HI);
+
+ /* Set max Tx frame size */
+ outb(self->tx_buff.len >> 8, iobase+IRCC_TX_SIZE_HI);
outb(self->tx_buff.len & 0xff, iobase+IRCC_TX_SIZE_LO);
-#else
- outb(0, iobase+IRCC_BRICKWALL_TX_CNT_HI);
- outb(0, iobase+IRCC_TX_SIZE_LO);
-#endif
+ /* Setup DMA controller (must be done after enabling chip DMA) */
+ setup_dma(self->io.dma, self->tx_buff.data, self->tx_buff.len,
+ DMA_TX_MODE);
+
+ outb(UART_MCR_OUT2, self->io.sir_base + UART_MCR);
+ /* Enable burst mode chip Tx DMA */
register_bank(iobase, 1);
- outb(inb(iobase+IRCC_SCE_CFGB) | IRCC_CFGB_DMA_ENABLE,
- iobase+IRCC_SCE_CFGB);
+ outb(inb(iobase+IRCC_SCE_CFGB) | IRCC_CFGB_DMA_ENABLE |
+ IRCC_CFGB_DMA_BURST, iobase+IRCC_SCE_CFGB);
+ /* Enable interrupt */
+ outb(IRCC_MASTER_INT_EN, iobase+IRCC_MASTER);
register_bank(iobase, 0);
-
outb(IRCC_IER_ACTIVE_FRAME | IRCC_IER_EOM, iobase+IRCC_IER);
- outb(IRCC_LCR_B_SCE_TRANSMIT|IRCC_LCR_B_SIP_ENABLE, iobase+IRCC_LCR_B);
- outb(IRCC_MASTER_INT_EN, iobase+IRCC_MASTER);
+ /* Enable transmit */
+ outb(IRCC_LCR_B_SCE_TRANSMIT|IRCC_LCR_B_SIP_ENABLE, iobase+IRCC_LCR_B);
}
/*
@@ -612,39 +710,36 @@ static void ircc_dma_xmit(struct ircc_cb *self, int iobase)
* by the interrupt handler
*
*/
-static void ircc_dma_xmit_complete(struct ircc_cb *self, int underrun)
+static void ircc_dma_xmit_complete(struct ircc_cb *self, int iobase)
{
- int iobase, d;
-
IRDA_DEBUG(2, __FUNCTION__ "\n");
-
- ASSERT(self != NULL, return;);
-
- register_bank(self->io.iobase, 1);
-
- outb(inb(self->io.iobase+IRCC_SCE_CFGB) & IRCC_CFGB_DMA_ENABLE,
- self->io.iobase+IRCC_SCE_CFGB);
-
- d = get_dma_residue(self->io.dma);
-
- IRDA_DEBUG(0, __FUNCTION__
- ": dma residue = %d, len=%d, sent=%d\n",
- d, self->tx_buff.len, self->tx_buff.len - d);
-
- iobase = self->io.iobase;
+#if 0
+ /* Disable Tx */
+ register_bank(iobase, 0);
+ outb(0x00, iobase+IRCC_LCR_B);
+#endif
+ register_bank(self->io.fir_base, 1);
+ outb(inb(self->io.fir_base+IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE,
+ self->io.fir_base+IRCC_SCE_CFGB);
/* Check for underrrun! */
- if (underrun) {
+ register_bank(iobase, 0);
+ if (inb(iobase+IRCC_LSR) & IRCC_LSR_UNDERRUN) {
self->irport->stats.tx_errors++;
- self->irport->stats.tx_fifo_errors++;
+ self->irport->stats.tx_fifo_errors++;
+
+ /* Reset error condition */
+ register_bank(iobase, 0);
+ outb(IRCC_MASTER_ERROR_RESET, iobase+IRCC_MASTER);
+ outb(0x00, iobase+IRCC_MASTER);
} else {
self->irport->stats.tx_packets++;
self->irport->stats.tx_bytes += self->tx_buff.len;
}
+ /* Check if it's time to change the speed */
if (self->new_speed) {
- ircc_change_speed(self, self->new_speed);
-
+ ircc_change_speed(self, self->new_speed);
self->new_speed = 0;
}
@@ -662,39 +757,31 @@ static void ircc_dma_xmit_complete(struct ircc_cb *self, int underrun)
* if it starts to receive a frame.
*
*/
-static int ircc_dma_receive(struct ircc_cb *self)
-{
- int iobase;
-
- IRDA_DEBUG(2, __FUNCTION__ "\n");
-
- ASSERT(self != NULL, return -1;);
-
- iobase= self->io.iobase;
+static int ircc_dma_receive(struct ircc_cb *self, int iobase)
+{
+ /* Turn off chip DMA */
+ //register_bank(iobase, 1);
+ //outb(inb(iobase+IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE,
+ // iobase+IRCC_SCE_CFGB);
setup_dma(self->io.dma, self->rx_buff.data, self->rx_buff.truesize,
- DMA_RX_MODE);
-
- /* driver->media_busy = FALSE; */
+ DMA_RX_MODE);
+ /* Set max Rx frame size */
+ register_bank(iobase, 4);
+ outb((2050 >> 8) & 0x0f, iobase+IRCC_RX_SIZE_HI);
+ outb(2050 & 0xff, iobase+IRCC_RX_SIZE_LO);
+
self->io.direction = IO_RECV;
self->rx_buff.data = self->rx_buff.head;
-#if 0
- self->rx_buff.offset = 0;
-#endif
-
- register_bank(iobase, 4);
- outb(inb(iobase+IRCC_CONTROL) & 0xf0, iobase+IRCC_CONTROL);
- outb(2, iobase+IRCC_BOF_COUNT_LO);
- outb(0, iobase+IRCC_BRICKWALL_CNT_LO);
- outb(0, iobase+IRCC_BRICKWALL_TX_CNT_HI);
- outb(0, iobase+IRCC_TX_SIZE_LO);
- outb(0, iobase+IRCC_RX_SIZE_HI);
- outb(0, iobase+IRCC_RX_SIZE_LO);
+ /* Setup DMA controller */
+
+ /* Enable receiver */
register_bank(iobase, 0);
outb(IRCC_LCR_B_SCE_RECEIVE | IRCC_LCR_B_SIP_ENABLE,
iobase+IRCC_LCR_B);
+ /* Enable burst mode chip Rx DMA */
register_bank(iobase, 1);
outb(inb(iobase+IRCC_SCE_CFGB) | IRCC_CFGB_DMA_ENABLE |
IRCC_CFGB_DMA_BURST, iobase+IRCC_SCE_CFGB);
@@ -709,45 +796,54 @@ static int ircc_dma_receive(struct ircc_cb *self)
*
*
*/
-static int ircc_dma_receive_complete(struct ircc_cb *self, int iobase)
+static void ircc_dma_receive_complete(struct ircc_cb *self, int iobase)
{
+ unsigned long flags;
struct sk_buff *skb;
int len, msgcnt;
IRDA_DEBUG(2, __FUNCTION__ "\n");
+#if 0
+ /* Disable Rx */
+ register_bank(iobase, 0);
+ outb(0x00, iobase+IRCC_LCR_B);
+#endif
+ register_bank(iobase, 0);
+ msgcnt = inb(iobase+IRCC_LCR_B) & 0x08;
- msgcnt = inb(self->io.iobase+IRCC_LCR_B) & 0x08;
-
- IRDA_DEBUG(0, __FUNCTION__ ": dma count = %d\n",
+ IRDA_DEBUG(2, __FUNCTION__ ": dma count = %d\n",
get_dma_residue(self->io.dma));
- len = self->rx_buff.truesize - get_dma_residue(self->io.dma) - 4;
-
- IRDA_DEBUG(0, __FUNCTION__ ": msgcnt = %d, len=%d\n", msgcnt, len);
+ len = self->rx_buff.truesize - get_dma_residue(self->io.dma);
+
+ /* Remove CRC */
+ if (self->io.speed < 4000000)
+ len -= 2;
+ else
+ len -= 4;
+
+ if ((len < 2) && (len > 2050)) {
+ WARNING(__FUNCTION__ "(), bogus len=%d\n", len);
+ return;
+ }
+ IRDA_DEBUG(2, __FUNCTION__ ": msgcnt = %d, len=%d\n", msgcnt, len);
skb = dev_alloc_skb(len+1);
if (!skb) {
WARNING(__FUNCTION__ "(), memory squeeze, dropping frame.\n");
- return FALSE;
- }
-
+ return;
+ }
/* Make sure IP header gets aligned */
skb_reserve(skb, 1);
- skb_put(skb, len);
- memcpy(skb->data, self->rx_buff.data, len);
+ memcpy(skb_put(skb, len), self->rx_buff.data, len);
self->irport->stats.rx_packets++;
+ self->irport->stats.rx_bytes += len;
skb->dev = self->netdev;
skb->mac.raw = skb->data;
skb->protocol = htons(ETH_P_IRDA);
netif_rx(skb);
-
- register_bank(self->io.iobase, 1);
- outb(inb(self->io.iobase+IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE,
- self->io.iobase+IRCC_SCE_CFGB);
-
- return TRUE;
}
/*
@@ -758,58 +854,54 @@ static int ircc_dma_receive_complete(struct ircc_cb *self, int iobase)
*/
static void ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
- int iobase, iir;
struct net_device *dev = (struct net_device *) dev_id;
+ struct irport_cb *irport;
struct ircc_cb *self;
+ int iobase, iir;
if (dev == NULL) {
printk(KERN_WARNING "%s: irq %d for unknown device.\n",
driver_name, irq);
return;
}
-
- self = (struct ircc_cb *) dev->priv;
+ irport = (struct irport_cb *) dev->priv;
+ ASSERT(irport != NULL, return;);
+ self = (struct ircc_cb *) irport->priv;
+ ASSERT(self != NULL, return;);
- iobase = self->io.iobase;
+ /* Check if we should use the SIR interrupt handler */
+ if (self->io.speed < 576000) {
+ irport_interrupt(irq, dev_id, regs);
+ return;
+ }
+ iobase = self->io.fir_base;
+ spin_lock(&self->lock);
dev->interrupt = 1;
- outb(0, iobase+IRCC_MASTER);
-
register_bank(iobase, 0);
iir = inb(iobase+IRCC_IIR);
/* Disable interrupts */
outb(0, iobase+IRCC_IER);
- IRDA_DEBUG(0, __FUNCTION__ "(), iir = 0x%02x\n", iir);
+ IRDA_DEBUG(2, __FUNCTION__ "(), iir = 0x%02x\n", iir);
if (iir & IRCC_IIR_EOM) {
- IRDA_DEBUG(0, __FUNCTION__ "(), IRCC_IIR_EOM\n");
-
if (self->io.direction == IO_RECV)
ircc_dma_receive_complete(self, iobase);
else
ircc_dma_xmit_complete(self, iobase);
- ircc_dma_receive(self);
- }
- if (iir & IRCC_IIR_ACTIVE_FRAME) {
- IRDA_DEBUG(0, __FUNCTION__ "(), IRCC_IIR_ACTIVE_FRAME\n");
- self->rx_buff.state = INSIDE_FRAME;
-#if 0
- ircc_dma_receive(self);
-#endif
- }
- if (iir & IRCC_IIR_RAW_MODE) {
- IRDA_DEBUG(0, __FUNCTION__ "(), IIR RAW mode interrupt.\n");
+ ircc_dma_receive(self, iobase);
}
+ /* Enable interrupts again */
register_bank(iobase, 0);
outb(IRCC_IER_ACTIVE_FRAME|IRCC_IER_EOM, iobase+IRCC_IER);
- outb(IRCC_MASTER_INT_EN, iobase+IRCC_MASTER);
dev->interrupt = 0;
+ spin_unlock(&self->lock);
}
/*
@@ -855,7 +947,7 @@ static int ircc_net_open(struct net_device *dev)
ASSERT(self != NULL, return 0;);
- iobase = self->io.iobase;
+ iobase = self->io.fir_base;
irport_net_open(dev); /* irport allocates the irq */
@@ -894,7 +986,7 @@ static int ircc_net_close(struct net_device *dev)
ASSERT(self != NULL, return 0;);
- iobase = self->io.iobase;
+ iobase = self->io.fir_base;
irport_net_close(dev);
@@ -907,6 +999,69 @@ static int ircc_net_close(struct net_device *dev)
return 0;
}
+#ifdef CONFIG_APM
+static void ircc_suspend(struct ircc_cb *self)
+{
+ int i = 10;
+
+ MESSAGE("%s, Suspending\n", driver_name);
+
+ if (self->io.suspended)
+ return;
+
+ ircc_net_close(self->netdev);
+
+ self->io.suspended = 1;
+}
+
+static void ircc_wakeup(struct ircc_cb *self)
+{
+ struct net_device *dev = self->netdev;
+ unsigned long flags;
+
+ if (!self->io.suspended)
+ return;
+
+ save_flags(flags);
+ cli();
+
+ ircc_net_open(self->netdev);
+
+ restore_flags(flags);
+ MESSAGE("%s, Waking up\n", driver_name);
+}
+
+static int ircc_apmproc(apm_event_t event)
+{
+ static int down = 0; /* Filter out double events */
+ int i;
+
+ switch (event) {
+ case APM_SYS_SUSPEND:
+ case APM_USER_SUSPEND:
+ if (!down) {
+ for (i=0; i<4; i++) {
+ if (dev_self[i])
+ ircc_suspend(dev_self[i]);
+ }
+ }
+ down = 1;
+ break;
+ case APM_NORMAL_RESUME:
+ case APM_CRITICAL_RESUME:
+ if (down) {
+ for (i=0; i<4; i++) {
+ if (dev_self[i])
+ ircc_wakeup(dev_self[i]);
+ }
+ }
+ down = 0;
+ break;
+ }
+ return 0;
+}
+#endif /* CONFIG_APM */
+
#ifdef MODULE
MODULE_AUTHOR("Thomas Davis <tadavis@jps.net>");
MODULE_DESCRIPTION("SMC IrCC controller driver");
diff --git a/drivers/net/irda/toshoboe.c b/drivers/net/irda/toshoboe.c
index cbf06af5f..a7b97af37 100644
--- a/drivers/net/irda/toshoboe.c
+++ b/drivers/net/irda/toshoboe.c
@@ -32,37 +32,6 @@
static char *rcsid = "$Id: toshoboe.c,v 1.91 1999/06/29 14:21:06 root Exp $";
-/*
- * $Log: toshoboe.c,v $
- * Revision 1.9 1999/06/29 14:21:06 root
- * *** empty log message ***
- *
- * Revision 1.8 1999/06/29 14:15:08 root
- * *** empty log message ***
- *
- * Revision 1.7 1999/06/29 13:46:42 root
- * *** empty log message ***
- *
- * Revision 1.6 1999/06/29 12:31:03 root
- * *** empty log message ***
- *
- * Revision 1.5 1999/05/12 12:24:39 root
- * *** empty log message ***
- *
- * Revision 1.4 1999/05/12 11:55:08 root
- * *** empty log message ***
- *
- * Revision 1.3 1999/05/09 01:33:12 root
- * *** empty log message ***
- *
- * Revision 1.2 1999/05/09 01:30:38 root
- * *** empty log message ***
- *
- * Revision 1.1 1999/05/09 01:25:04 root
- * Initial revision
- *
- */
-
/* Define this to have only one frame in the XMIT or RECV queue */
/* Toshiba's drivers do this, but it disables back to back tansfers */
/* I think that the chip may have some problems certainly, I have */
@@ -682,7 +651,7 @@ toshoboe_close (struct toshoboe_cb *self)
toshoboe_disablebm (self);
}
- release_region (self->io.iobase, self->io.io_ext);
+ release_region (self->io.sir_base, self->io.sir_ext);
for (i = 0; i < TX_SLOTS; ++i)
@@ -754,17 +723,17 @@ toshoboe_open (struct pci_dev *pci_dev)
self->pdev = pci_dev;
self->base = pci_dev->resource[0].start;
- self->io.iobase = self->base;
+ self->io.sir_base = self->base;
self->io.irq = pci_dev->irq;
- self->io.io_ext = CHIP_IO_EXTENT;
+ self->io.sir_ext = CHIP_IO_EXTENT;
self->io.speed = 9600;
/* Lock the port that we need */
- i = check_region (self->io.iobase, self->io.io_ext);
+ i = check_region (self->io.sir_base, self->io.sir_ext);
if (i < 0)
{
IRDA_DEBUG (0, __FUNCTION__ "(), can't get iobase of 0x%03x\n",
- self->io.iobase);
+ self->io.sir_base);
dev_self[i] = NULL;
kfree (self);
@@ -864,13 +833,12 @@ toshoboe_open (struct pci_dev *pci_dev)
}
- request_region (self->io.iobase, self->io.io_ext, driver_name);
+ request_region (self->io.sir_base, self->io.sir_ext, driver_name);
if (!(dev = dev_alloc("irda%d", &err))) {
ERROR(__FUNCTION__ "(), dev_alloc() failed!\n");
return -ENOMEM;
}
-
dev->priv = (void *) self;
self->netdev = dev;
@@ -1025,7 +993,7 @@ int __init toshoboe_init (void)
if (pci_dev)
{
printk (KERN_WARNING "ToshOboe: Found 701 chip at 0x%0lx irq %d\n",
- pci_dev->resource[0].start,
+ pci_dev->resource[0].start,
pci_dev->irq);
if (!toshoboe_open (pci_dev))
diff --git a/drivers/net/irda/w83977af_ir.c b/drivers/net/irda/w83977af_ir.c
index 1bc2d9fa9..7f781719c 100644
--- a/drivers/net/irda/w83977af_ir.c
+++ b/drivers/net/irda/w83977af_ir.c
@@ -6,7 +6,7 @@
* Status: Experimental.
* Author: Paul VanderSpek
* Created at: Wed Nov 4 11:46:16 1998
- * Modified at: Wed Jan 5 15:11:21 2000
+ * Modified at: Fri Jan 28 12:10:59 2000
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>
@@ -183,21 +183,21 @@ int w83977af_open(int i, unsigned int iobase, unsigned int irq,
dev_self[i] = self;
/* Initialize IO */
- self->io.iobase = iobase;
+ self->io.fir_base = iobase;
self->io.irq = irq;
- self->io.io_ext = CHIP_IO_EXTENT;
+ self->io.fir_ext = CHIP_IO_EXTENT;
self->io.dma = dma;
self->io.fifo_size = 32;
/* Lock the port that we need */
- ret = check_region(self->io.iobase, self->io.io_ext);
+ ret = check_region(self->io.fir_base, self->io.fir_ext);
if (ret < 0) {
IRDA_DEBUG(0, __FUNCTION__ "(), can't get iobase of 0x%03x\n",
- self->io.iobase);
+ self->io.fir_base);
/* w83977af_cleanup( self); */
return -ENODEV;
}
- request_region(self->io.iobase, self->io.io_ext, driver_name);
+ request_region(self->io.fir_base, self->io.fir_ext, driver_name);
/* Initialize QoS for this device */
irda_init_max_qos_capabilies(&self->qos);
@@ -243,9 +243,6 @@ int w83977af_open(int i, unsigned int iobase, unsigned int irq,
ERROR(__FUNCTION__ "(), dev_alloc() failed!\n");
return -ENOMEM;
}
- /* dev_alloc doesn't clear the struct, so lets do a little hack */
- memset(((__u8*)dev)+sizeof(char*),0,sizeof(struct net_device)-sizeof(char*));
-
dev->priv = (void *) self;
self->netdev = dev;
@@ -282,7 +279,7 @@ static int w83977af_close(struct w83977af_ir *self)
IRDA_DEBUG(0, __FUNCTION__ "()\n");
- iobase = self->io.iobase;
+ iobase = self->io.fir_base;
#ifdef CONFIG_USE_W977_PNP
/* enter PnP configuration mode */
@@ -301,14 +298,12 @@ static int w83977af_close(struct w83977af_ir *self)
rtnl_lock();
unregister_netdevice(self->netdev);
rtnl_unlock();
- /* Must free the old-style 2.2.x device */
- kfree(self->netdev);
}
/* Release the PORT that this driver is using */
IRDA_DEBUG(0 , __FUNCTION__ "(), Releasing Region %03x\n",
- self->io.iobase);
- release_region(self->io.iobase, self->io.io_ext);
+ self->io.fir_base);
+ release_region(self->io.fir_base, self->io.fir_ext);
if (self->tx_buff.head)
kfree(self->tx_buff.head);
@@ -426,7 +421,7 @@ void w83977af_change_speed(struct w83977af_ir *self, __u32 speed)
int iobase;
__u8 set;
- iobase = self->io.iobase;
+ iobase = self->io.fir_base;
/* Update accounting for new speed */
self->io.speed = speed;
@@ -510,7 +505,7 @@ int w83977af_hard_xmit(struct sk_buff *skb, struct net_device *dev)
self = (struct w83977af_ir *) dev->priv;
- iobase = self->io.iobase;
+ iobase = self->io.fir_base;
IRDA_DEBUG(4, __FUNCTION__ "(%ld), skb->len=%d\n", jiffies,
(int) skb->len);
@@ -692,7 +687,7 @@ void w83977af_dma_xmit_complete(struct w83977af_ir *self)
ASSERT(self != NULL, return;);
- iobase = self->io.iobase;
+ iobase = self->io.fir_base;
/* Save current set */
set = inb(iobase+SSR);
@@ -748,7 +743,7 @@ int w83977af_dma_receive(struct w83977af_ir *self)
IRDA_DEBUG(4, __FUNCTION__ "\n");
- iobase= self->io.iobase;
+ iobase= self->io.fir_base;
/* Save current set */
set = inb(iobase+SSR);
@@ -822,12 +817,12 @@ int w83977af_dma_receive_complete(struct w83977af_ir *self)
st_fifo = &self->st_fifo;
- iobase = self->io.iobase;
+ iobase = self->io.fir_base;
/* Save current set */
set = inb(iobase+SSR);
- iobase = self->io.iobase;
+ iobase = self->io.fir_base;
/* Read status FIFO */
switch_bank(iobase, SET5);
@@ -948,7 +943,7 @@ static void w83977af_pio_receive(struct w83977af_ir *self)
ASSERT(self != NULL, return;);
- iobase = self->io.iobase;
+ iobase = self->io.fir_base;
/* Receive all characters in Rx FIFO */
do {
@@ -973,11 +968,11 @@ static __u8 w83977af_sir_interrupt(struct w83977af_ir *self, int isr)
IRDA_DEBUG(4, __FUNCTION__ "(), isr=%#x\n", isr);
- iobase = self->io.iobase;
+ iobase = self->io.fir_base;
/* Transmit FIFO low on data */
if (isr & ISR_TXTH_I) {
/* Write data left in transmit buffer */
- actual = w83977af_pio_write(self->io.iobase,
+ actual = w83977af_pio_write(self->io.fir_base,
self->tx_buff.data,
self->tx_buff.len,
self->io.fifo_size);
@@ -1042,7 +1037,7 @@ static __u8 w83977af_fir_interrupt(struct w83977af_ir *self, int isr)
__u8 set;
int iobase;
- iobase = self->io.iobase;
+ iobase = self->io.fir_base;
set = inb(iobase+SSR);
/* End of frame detected in FIFO */
@@ -1131,7 +1126,7 @@ static void w83977af_interrupt(int irq, void *dev_id, struct pt_regs *regs)
dev->interrupt = 1;
- iobase = self->io.iobase;
+ iobase = self->io.fir_base;
/* Save current bank */
set = inb(iobase+SSR);
@@ -1171,7 +1166,7 @@ static int w83977af_is_receiving(struct w83977af_ir *self)
ASSERT(self != NULL, return FALSE;);
if (self->io.speed > 115200) {
- iobase = self->io.iobase;
+ iobase = self->io.fir_base;
/* Check if rx FIFO is not empty */
set = inb(iobase+SSR);
@@ -1225,7 +1220,7 @@ static int w83977af_net_open(struct net_device *dev)
ASSERT(self != NULL, return 0;);
- iobase = self->io.iobase;
+ iobase = self->io.fir_base;
if (request_irq(self->io.irq, w83977af_interrupt, 0, dev->name,
(void *) dev)) {
@@ -1290,7 +1285,7 @@ static int w83977af_net_close(struct net_device *dev)
ASSERT(self != NULL, return 0;);
- iobase = self->io.iobase;
+ iobase = self->io.fir_base;
/* Stop device */
dev->tbusy = 1;
diff --git a/drivers/net/mac89x0.c b/drivers/net/mac89x0.c
new file mode 100644
index 000000000..ce43ad752
--- /dev/null
+++ b/drivers/net/mac89x0.c
@@ -0,0 +1,678 @@
+/* cs89x0.c: A Crystal Semiconductor CS89[02]0 driver for linux. */
+/*
+ Written 1996 by Russell Nelson, with reference to skeleton.c
+ written 1993-1994 by Donald Becker.
+
+ This software may be used and distributed according to the terms
+ of the GNU Public License, incorporated herein by reference.
+
+ The author may be reached at nelson@crynwr.com, Crynwr
+ Software, 11 Grant St., Potsdam, NY 13676
+
+ Changelog:
+
+ Mike Cruse : mcruse@cti-ltd.com
+ : Changes for Linux 2.0 compatibility.
+ : Added dev_id parameter in net_interrupt(),
+ : request_irq() and free_irq(). Just NULL for now.
+
+ Mike Cruse : Added MOD_INC_USE_COUNT and MOD_DEC_USE_COUNT macros
+ : in net_open() and net_close() so kerneld would know
+ : that the module is in use and wouldn't eject the
+ : driver prematurely.
+
+ Mike Cruse : Rewrote init_module() and cleanup_module using 8390.c
+ : as an example. Disabled autoprobing in init_module(),
+ : not a good thing to do to other devices while Linux
+ : is running from all accounts.
+
+ Alan Cox : Removed 1.2 support, added 2.1 extra counters.
+
+ David Huggins-Daines <dhd@debian.org>
+
+ Split this off into mac89x0.c, and gutted it of all parts which are
+ not relevant to the existing CS8900 cards on the Macintosh
+ (i.e. basically the Daynaport CS and LC cards). To be precise:
+
+ * Removed all the media-detection stuff, because these cards are
+ TP-only.
+
+ * Lobotomized the ISA interrupt bogosity, because these cards use
+ a hardwired NuBus interrupt and a magic ISAIRQ value in the card.
+
+ * Basically eliminated everything not relevant to getting the
+ cards minimally functioning on the Macintosh.
+
+ I might add that these cards are badly designed even from the Mac
+ standpoint, in that Dayna, in their infinite wisdom, used NuBus slot
+ I/O space and NuBus interrupts for these cards, but neglected to
+ provide anything even remotely resembling a NuBus ROM. Therefore we
+ have to probe for them in a brain-damaged ISA-like fashion.
+*/
+
+static char *version =
+"cs89x0.c:v1.02 11/26/96 Russell Nelson <nelson@crynwr.com>\n";
+
+/* ======================= configure the driver here ======================= */
+
+/* use 0 for production, 1 for verification, >2 for debug */
+#ifndef NET_DEBUG
+#define NET_DEBUG 0
+#endif
+
+/* ======================= end of configuration ======================= */
+
+
+/* Always include 'config.h' first in case the user wants to turn on
+ or override something. */
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
+
+#define PRINTK(x) printk x
+
+/*
+ Sources:
+
+ Crynwr packet driver epktisa.
+
+ Crystal Semiconductor data sheets.
+
+*/
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/nubus.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/hwtest.h>
+#include <asm/macints.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include "cs89x0.h"
+
+static unsigned int net_debug = NET_DEBUG;
+
+/* Information that need to be kept for each board. */
+struct net_local {
+ struct net_device_stats stats;
+ int chip_type; /* one of: CS8900, CS8920, CS8920M */
+ char chip_revision; /* revision letter of the chip ('A'...) */
+ int send_cmd; /* the propercommand used to send a packet. */
+ int rx_mode;
+ int curr_rx_cfg;
+ int send_underrun; /* keep track of how many underruns in a row we get */
+ struct sk_buff *skb;
+};
+
+/* Index to functions, as function prototypes. */
+
+extern int mac89x0_probe(struct net_device *dev);
+extern void reset_chip(struct net_device *dev);
+static int net_open(struct net_device *dev);
+static int net_send_packet(struct sk_buff *skb, struct net_device *dev);
+static void net_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void set_multicast_list(struct net_device *dev);
+static void net_rx(struct net_device *dev);
+static int net_close(struct net_device *dev);
+static struct net_device_stats *net_get_stats(struct net_device *dev);
+static int set_mac_address(struct net_device *dev, void *addr);
+
+
+/* Example routines you must write ;->. */
+#define tx_done(dev) 1
+
+/* For reading/writing registers ISA-style */
+static int inline
+readreg_io(struct net_device *dev, int portno)
+{
+ writew(swab16(portno), dev->base_addr + ADD_PORT);
+ return swab16(readw(dev->base_addr + DATA_PORT));
+}
+
+static void inline
+writereg_io(struct net_device *dev, int portno, int value)
+{
+ writew(swab16(portno), dev->base_addr + ADD_PORT);
+ writew(swab16(value), dev->base_addr + DATA_PORT);
+}
+
+/* These are for reading/writing registers in shared memory */
+static int inline
+readreg(struct net_device *dev, int portno)
+{
+ return swab16(readw(dev->mem_start + portno));
+}
+
+static void inline
+writereg(struct net_device *dev, int portno, int value)
+{
+ writew(swab16(value), dev->mem_start + portno);
+}
+
+/* Probe for the CS8900 card in slot E. We won't bother looking
+ anywhere else until we have a really good reason to do so. */
+int __init mac89x0_probe(struct net_device *dev)
+{
+ static int once_is_enough = 0;
+ struct net_local *lp;
+ static unsigned version_printed = 0;
+ int i, slot;
+ unsigned rev_type = 0;
+ unsigned long ioaddr;
+ unsigned short sig;
+
+ if (once_is_enough)
+ return ENODEV;
+ once_is_enough = 1;
+
+ /* We might have to parameterize this later */
+ slot = 0xE;
+ /* Get out now if there's a real NuBus card in slot E */
+ if (nubus_find_slot(slot, NULL) != NULL)
+ return ENODEV;
+
+ /* The pseudo-ISA bits always live at offset 0x300 (gee,
+ wonder why...) */
+ ioaddr = (unsigned long)
+ nubus_slot_addr(slot) | (((slot&0xf) << 20) + DEFAULTIOBASE);
+ {
+ unsigned long flags;
+ int card_present;
+
+ save_flags(flags);
+ cli();
+ card_present = hwreg_present((void*) ioaddr+4)
+ && hwreg_present((void*) ioaddr + DATA_PORT);
+ restore_flags(flags);
+
+ if (!card_present)
+ return ENODEV;
+ }
+
+ writew(0, ioaddr + ADD_PORT);
+ sig = readw(ioaddr + DATA_PORT);
+ if (sig != swab16(CHIP_EISA_ID_SIG))
+ return ENODEV;
+
+ /* Initialize the net_device structure. */
+ if (dev->priv == NULL) {
+ dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);
+ memset(dev->priv, 0, sizeof(struct net_local));
+ }
+ lp = (struct net_local *)dev->priv;
+
+ /* Fill in the 'dev' fields. */
+ dev->base_addr = ioaddr;
+ dev->mem_start = (unsigned long)
+ nubus_slot_addr(slot) | (((slot&0xf) << 20) + MMIOBASE);
+ dev->mem_end = dev->mem_start + 0x1000;
+
+ /* Turn on shared memory */
+ writereg_io(dev, PP_BusCTL, MEMORY_ON);
+
+ /* get the chip type */
+ rev_type = readreg(dev, PRODUCT_ID_ADD);
+ lp->chip_type = rev_type &~ REVISON_BITS;
+ lp->chip_revision = ((rev_type & REVISON_BITS) >> 8) + 'A';
+
+ /* Check the chip type and revision in order to set the correct send command
+ CS8920 revision C and CS8900 revision F can use the faster send. */
+ lp->send_cmd = TX_AFTER_381;
+ if (lp->chip_type == CS8900 && lp->chip_revision >= 'F')
+ lp->send_cmd = TX_NOW;
+ if (lp->chip_type != CS8900 && lp->chip_revision >= 'C')
+ lp->send_cmd = TX_NOW;
+
+ if (net_debug && version_printed++ == 0)
+ printk(version);
+
+ printk(KERN_INFO "%s: cs89%c0%s rev %c found at %#8lx",
+ dev->name,
+ lp->chip_type==CS8900?'0':'2',
+ lp->chip_type==CS8920M?"M":"",
+ lp->chip_revision,
+ dev->base_addr);
+
+ /* Try to read the MAC address */
+ if ((readreg(dev, PP_SelfST) & (EEPROM_PRESENT | EEPROM_OK)) == 0) {
+ printk("\nmac89x0: No EEPROM, giving up now.\n");
+ return ENODEV;
+ } else {
+ for (i = 0; i < ETH_ALEN; i += 2) {
+ /* Big-endian (why??!) */
+ unsigned short s = readreg(dev, PP_IA + i);
+ dev->dev_addr[i] = s >> 8;
+ dev->dev_addr[i+1] = s & 0xff;
+ }
+ }
+
+ dev->irq = SLOT2IRQ(slot);
+ printk(" IRQ %d ADDR ", dev->irq);
+
+ /* print the ethernet address. */
+ for (i = 0; i < ETH_ALEN; i++)
+ printk("%2.2x%s", dev->dev_addr[i],
+ ((i < ETH_ALEN-1) ? ":" : ""));
+
+ dev->open = net_open;
+ dev->stop = net_close;
+ dev->hard_start_xmit = net_send_packet;
+ dev->get_stats = net_get_stats;
+ dev->set_multicast_list = &set_multicast_list;
+ dev->set_mac_address = &set_mac_address;
+
+ /* Fill in the fields of the net_device structure with ethernet values. */
+ ether_setup(dev);
+
+ printk("\n");
+ return 0;
+}
+
+/* This is useful for something, but I don't know what yet. */
+void __init reset_chip(struct net_device *dev)
+{
+ int reset_start_time;
+
+ writereg(dev, PP_SelfCTL, readreg(dev, PP_SelfCTL) | POWER_ON_RESET);
+
+ /* wait 30 ms */
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(30*HZ/1000);
+
+ /* Wait until the chip is reset */
+ reset_start_time = jiffies;
+ while( (readreg(dev, PP_SelfST) & INIT_DONE) == 0 && jiffies - reset_start_time < 2)
+ ;
+}
+
+/* Open/initialize the board. This is called (in the current kernel)
+ sometime after booting when the 'ifconfig' program is run.
+
+ This routine should set everything up anew at each open, even
+ registers that "should" only need to be set once at boot, so that
+ there is non-reboot way to recover if something goes wrong.
+ */
+static int
+net_open(struct net_device *dev)
+{
+ struct net_local *lp = (struct net_local *)dev->priv;
+ int i;
+
+ /* Disable the interrupt for now */
+ writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL) & ~ENABLE_IRQ);
+
+ /* Grab the interrupt */
+ if (request_irq(dev->irq, &net_interrupt, 0, "cs89x0", dev))
+ return -EAGAIN;
+
+ /* Set up the IRQ - Apparently magic */
+ if (lp->chip_type == CS8900)
+ writereg(dev, PP_CS8900_ISAINT, 0);
+ else
+ writereg(dev, PP_CS8920_ISAINT, 0);
+
+ /* set the Ethernet address */
+ for (i=0; i < ETH_ALEN/2; i++)
+ writereg(dev, PP_IA+i*2, dev->dev_addr[i*2] | (dev->dev_addr[i*2+1] << 8));
+
+ /* Turn on both receive and transmit operations */
+ writereg(dev, PP_LineCTL, readreg(dev, PP_LineCTL) | SERIAL_RX_ON | SERIAL_TX_ON);
+
+ /* Receive only error free packets addressed to this card */
+ lp->rx_mode = 0;
+ writereg(dev, PP_RxCTL, DEF_RX_ACCEPT);
+
+ lp->curr_rx_cfg = RX_OK_ENBL | RX_CRC_ERROR_ENBL;
+
+ writereg(dev, PP_RxCFG, lp->curr_rx_cfg);
+
+ writereg(dev, PP_TxCFG, TX_LOST_CRS_ENBL | TX_SQE_ERROR_ENBL | TX_OK_ENBL |
+ TX_LATE_COL_ENBL | TX_JBR_ENBL | TX_ANY_COL_ENBL | TX_16_COL_ENBL);
+
+ writereg(dev, PP_BufCFG, READY_FOR_TX_ENBL | RX_MISS_COUNT_OVRFLOW_ENBL |
+ TX_COL_COUNT_OVRFLOW_ENBL | TX_UNDERRUN_ENBL);
+
+ /* now that we've got our act together, enable everything */
+ writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL) | ENABLE_IRQ);
+ dev->tbusy = 0;
+ dev->interrupt = 0;
+ dev->start = 1;
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+static int
+net_send_packet(struct sk_buff *skb, struct net_device *dev)
+{
+ if (dev->tbusy) {
+ /* If we get here, some higher level has decided we are broken.
+ There should really be a "kick me" function call instead. */
+ int tickssofar = jiffies - dev->trans_start;
+ if (tickssofar < 5)
+ return 1;
+ if (net_debug > 0) printk("%s: transmit timed out, %s?\n", dev->name,
+ tx_done(dev) ? "IRQ conflict" : "network cable problem");
+ /* Try to restart the adaptor. */
+ dev->tbusy=0;
+ dev->trans_start = jiffies;
+ }
+
+ /* Block a timer-based transmit from overlapping. This could better be
+ done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
+ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
+ printk("%s: Transmitter access conflict.\n", dev->name);
+ else {
+ struct net_local *lp = (struct net_local *)dev->priv;
+ unsigned long flags;
+
+ if (net_debug > 3)
+ printk("%s: sent %d byte packet of type %x\n",
+ dev->name, skb->len,
+ (skb->data[ETH_ALEN+ETH_ALEN] << 8)
+ | skb->data[ETH_ALEN+ETH_ALEN+1]);
+
+ /* keep the upload from being interrupted, since we
+ ask the chip to start transmitting before the
+ whole packet has been completely uploaded. */
+ save_flags(flags);
+ cli();
+
+ /* initiate a transmit sequence */
+ writereg(dev, PP_TxCMD, lp->send_cmd);
+ writereg(dev, PP_TxLength, skb->len);
+
+ /* Test to see if the chip has allocated memory for the packet */
+ if ((readreg(dev, PP_BusST) & READY_FOR_TX_NOW) == 0) {
+ /* Gasp! It hasn't. But that shouldn't happen since
+ we're waiting for TxOk, so return 1 and requeue this packet. */
+ restore_flags(flags);
+ return 1;
+ }
+
+ /* Write the contents of the packet */
+ memcpy_toio(dev->mem_start + PP_TxFrame, skb->data, skb->len+1);
+
+ restore_flags(flags);
+ dev->trans_start = jiffies;
+ }
+ dev_kfree_skb (skb);
+
+ return 0;
+}
+
+/* The typical workload of the driver:
+ Handle the network interface interrupts. */
+static void net_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+ struct net_device *dev = dev_id;
+ struct net_local *lp;
+ int ioaddr, status;
+
+ if (dev == NULL) {
+ printk ("net_interrupt(): irq %d for unknown device.\n", irq);
+ return;
+ }
+ if (dev->interrupt)
+ printk("%s: Re-entering the interrupt handler.\n", dev->name);
+ dev->interrupt = 1;
+
+ ioaddr = dev->base_addr;
+ lp = (struct net_local *)dev->priv;
+
+ /* we MUST read all the events out of the ISQ, otherwise we'll never
+ get interrupted again. As a consequence, we can't have any limit
+ on the number of times we loop in the interrupt handler. The
+ hardware guarantees that eventually we'll run out of events. Of
+ course, if you're on a slow machine, and packets are arriving
+ faster than you can read them off, you're screwed. Hasta la
+ vista, baby! */
+ while ((status = swab16(readw(dev->base_addr + ISQ_PORT)))) {
+ if (net_debug > 4)printk("%s: event=%04x\n", dev->name, status);
+ switch(status & ISQ_EVENT_MASK) {
+ case ISQ_RECEIVER_EVENT:
+ /* Got a packet(s). */
+ net_rx(dev);
+ break;
+ case ISQ_TRANSMITTER_EVENT:
+ lp->stats.tx_packets++;
+ dev->tbusy = 0;
+ mark_bh(NET_BH); /* Inform upper layers. */
+ if ((status & TX_OK) == 0) lp->stats.tx_errors++;
+ if (status & TX_LOST_CRS) lp->stats.tx_carrier_errors++;
+ if (status & TX_SQE_ERROR) lp->stats.tx_heartbeat_errors++;
+ if (status & TX_LATE_COL) lp->stats.tx_window_errors++;
+ if (status & TX_16_COL) lp->stats.tx_aborted_errors++;
+ break;
+ case ISQ_BUFFER_EVENT:
+ if (status & READY_FOR_TX) {
+ /* we tried to transmit a packet earlier,
+ but inexplicably ran out of buffers.
+ That shouldn't happen since we only ever
+ load one packet. Shrug. Do the right
+ thing anyway. */
+ dev->tbusy = 0;
+ mark_bh(NET_BH); /* Inform upper layers. */
+ }
+ if (status & TX_UNDERRUN) {
+ if (net_debug > 0) printk("%s: transmit underrun\n", dev->name);
+ lp->send_underrun++;
+ if (lp->send_underrun == 3) lp->send_cmd = TX_AFTER_381;
+ else if (lp->send_underrun == 6) lp->send_cmd = TX_AFTER_ALL;
+ }
+ break;
+ case ISQ_RX_MISS_EVENT:
+ lp->stats.rx_missed_errors += (status >>6);
+ break;
+ case ISQ_TX_COL_EVENT:
+ lp->stats.collisions += (status >>6);
+ break;
+ }
+ }
+ dev->interrupt = 0;
+ return;
+}
+
+/* We have a good packet(s), get it/them out of the buffers. */
+static void
+net_rx(struct net_device *dev)
+{
+ struct net_local *lp = (struct net_local *)dev->priv;
+ struct sk_buff *skb;
+ int status, length;
+
+ status = readreg(dev, PP_RxStatus);
+ if ((status & RX_OK) == 0) {
+ lp->stats.rx_errors++;
+ if (status & RX_RUNT) lp->stats.rx_length_errors++;
+ if (status & RX_EXTRA_DATA) lp->stats.rx_length_errors++;
+ if (status & RX_CRC_ERROR) if (!(status & (RX_EXTRA_DATA|RX_RUNT)))
+ /* per str 172 */
+ lp->stats.rx_crc_errors++;
+ if (status & RX_DRIBBLE) lp->stats.rx_frame_errors++;
+ return;
+ }
+
+ length = readreg(dev, PP_RxLength);
+ /* Malloc up new buffer. */
+ skb = alloc_skb(length, GFP_ATOMIC);
+ if (skb == NULL) {
+ printk("%s: Memory squeeze, dropping packet.\n", dev->name);
+ lp->stats.rx_dropped++;
+ return;
+ }
+ skb->len = length;
+ skb->dev = dev;
+
+ memcpy_fromio(skb->data, dev->mem_start + PP_RxFrame, length);
+
+ if (net_debug > 3)printk("%s: received %d byte packet of type %x\n",
+ dev->name, length,
+ (skb->data[ETH_ALEN+ETH_ALEN] << 8)
+ | skb->data[ETH_ALEN+ETH_ALEN+1]);
+
+ skb->protocol=eth_type_trans(skb,dev);
+ netif_rx(skb);
+ lp->stats.rx_packets++;
+ lp->stats.rx_bytes+=skb->len;
+ return;
+}
+
+/* The inverse routine to net_open(). */
+static int
+net_close(struct net_device *dev)
+{
+
+ writereg(dev, PP_RxCFG, 0);
+ writereg(dev, PP_TxCFG, 0);
+ writereg(dev, PP_BufCFG, 0);
+ writereg(dev, PP_BusCTL, 0);
+
+ dev->start = 0;
+
+ free_irq(dev->irq, dev);
+
+ /* Update the statistics here. */
+
+ MOD_DEC_USE_COUNT;
+ return 0;
+
+}
+
+/* Get the current statistics. This may be called with the card open or
+ closed. */
+static struct net_device_stats *
+net_get_stats(struct net_device *dev)
+{
+ struct net_local *lp = (struct net_local *)dev->priv;
+
+ cli();
+ /* Update the statistics from the device registers. */
+ lp->stats.rx_missed_errors += (readreg(dev, PP_RxMiss) >> 6);
+ lp->stats.collisions += (readreg(dev, PP_TxCol) >> 6);
+ sti();
+
+ return &lp->stats;
+}
+
+static void set_multicast_list(struct net_device *dev)
+{
+ struct net_local *lp = (struct net_local *)dev->priv;
+
+ if(dev->flags&IFF_PROMISC)
+ {
+ lp->rx_mode = RX_ALL_ACCEPT;
+ }
+ else if((dev->flags&IFF_ALLMULTI)||dev->mc_list)
+ {
+ /* The multicast-accept list is initialized to accept-all, and we
+ rely on higher-level filtering for now. */
+ lp->rx_mode = RX_MULTCAST_ACCEPT;
+ }
+ else
+ lp->rx_mode = 0;
+
+ writereg(dev, PP_RxCTL, DEF_RX_ACCEPT | lp->rx_mode);
+
+ /* in promiscuous mode, we accept errored packets, so we have to enable interrupts on them also */
+ writereg(dev, PP_RxCFG, lp->curr_rx_cfg |
+ (lp->rx_mode == RX_ALL_ACCEPT? (RX_CRC_ERROR_ENBL|RX_RUNT_ENBL|RX_EXTRA_DATA_ENBL) : 0));
+}
+
+
+static int set_mac_address(struct net_device *dev, void *addr)
+{
+ int i;
+ if (dev->start)
+ return -EBUSY;
+ printk("%s: Setting MAC address to ", dev->name);
+ for (i = 0; i < 6; i++)
+ printk(" %2.2x", dev->dev_addr[i] = ((unsigned char *)addr)[i]);
+ printk(".\n");
+ /* set the Ethernet address */
+ for (i=0; i < ETH_ALEN/2; i++)
+ writereg(dev, PP_IA+i*2, dev->dev_addr[i*2] | (dev->dev_addr[i*2+1] << 8));
+
+ return 0;
+}
+
+#ifdef MODULE
+
+static char namespace[16] = "";
+static struct net_device dev_cs89x0 = {
+ NULL,
+ 0, 0, 0, 0,
+ 0, 0,
+ 0, 0, 0, NULL, NULL };
+
+static int debug=0;
+
+MODULE_PARM(debug, "i");
+
+EXPORT_NO_SYMBOLS;
+
+int
+init_module(void)
+{
+ struct net_local *lp;
+
+ net_debug = debug;
+ dev_cs89x0.name = namespace;
+ dev_cs89x0.init = mac89x0_probe;
+ dev_cs89x0.priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);
+ memset(dev_cs89x0.priv, 0, sizeof(struct net_local));
+ lp = (struct net_local *)dev_cs89x0.priv;
+
+ if (register_netdev(&dev_cs89x0) != 0) {
+ printk(KERN_WARNING "mac89x0.c: No card found\n");
+ return -ENXIO;
+ }
+ return 0;
+}
+
+void
+cleanup_module(void)
+{
+
+#endif
+#ifdef MODULE
+ writew(0, dev_cs89x0.base_addr + ADD_PORT);
+#endif
+#ifdef MODULE
+
+ if (dev_cs89x0.priv != NULL) {
+ /* Free up the private structure, or leak memory :-) */
+ unregister_netdev(&dev_cs89x0);
+ kfree(dev_cs89x0.priv);
+ dev_cs89x0.priv = NULL; /* gets re-allocated by cs89x0_probe1 */
+ }
+}
+#endif /* MODULE */
+
+/*
+ * Local variables:
+ * compile-command: "m68k-linux-gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -ffixed-a2 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -c -o mac89x0.o mac89x0.c"
+ * version-control: t
+ * kept-new-versions: 5
+ * c-indent-level: 8
+ * tab-width: 8
+ * End:
+ *
+ */
diff --git a/drivers/net/macmace.c b/drivers/net/macmace.c
new file mode 100644
index 000000000..a7c347a7d
--- /dev/null
+++ b/drivers/net/macmace.c
@@ -0,0 +1,825 @@
+/*
+ * Driver for the Macintosh 68K onboard MACE controller with PSC
+ * driven DMA. The MACE driver code is derived from mace.c. The
+ * Mac68k theory of operation is courtesy of the MacBSD wizards.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Copyright (C) 1996 Paul Mackerras.
+ * Copyright (C) 1998 Alan Cox <alan@redhat.com>
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/irq.h>
+#include <asm/macintosh.h>
+#include <asm/macints.h>
+#include <asm/mac_psc.h>
+#include "mace.h"
+
+#define N_RX_RING 8
+#define N_TX_RING 2
+#define MAX_TX_ACTIVE 1
+#define NCMDS_TX 1 /* dma commands per element in tx ring */
+#define RX_BUFLEN (ETH_FRAME_LEN + 8)
+#define TX_TIMEOUT HZ /* 1 second */
+
+/* Bits in transmit DMA status */
+#define TX_DMA_ERR 0x80
+
+/* The MACE is simply wired down on a Mac68K box */
+
+#define MACE_BASE (void *)(0x50F1C000)
+#define MACE_PROM (void *)(0x50F08001)
+
+struct mace68k_data
+{
+ volatile struct mace *mace;
+ volatile unsigned char *tx_ring;
+ volatile unsigned char *rx_ring;
+ int dma_intr;
+ unsigned char maccc;
+ struct net_device_stats stats;
+ struct timer_list tx_timeout;
+ int timeout_active;
+ int rx_slot, rx_done;
+ int tx_slot, tx_count;
+};
+
+struct mace_frame
+{
+ u16 len;
+ u16 status;
+ u16 rntpc;
+ u16 rcvcc;
+ u32 pad1;
+ u32 pad2;
+ u8 data[1];
+ /* And frame continues.. */
+};
+
+#define PRIV_BYTES sizeof(struct mace68k_data)
+
+extern void psc_debug_dump(void);
+
+static int mace68k_open(struct net_device *dev);
+static int mace68k_close(struct net_device *dev);
+static int mace68k_xmit_start(struct sk_buff *skb, struct net_device *dev);
+static struct net_device_stats *mace68k_stats(struct net_device *dev);
+static void mace68k_set_multicast(struct net_device *dev);
+static void mace68k_reset(struct net_device *dev);
+static int mace68k_set_address(struct net_device *dev, void *addr);
+static void mace68k_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void mace68k_dma_intr(int irq, void *dev_id, struct pt_regs *regs);
+static void mace68k_set_timeout(struct net_device *dev);
+static void mace68k_tx_timeout(unsigned long data);
+
+/*
+ * PSC DMA engine control. As you'd expect on a macintosh its
+ * more like a lawnmower engine supplied without instructions
+ *
+ * The basic theory of operation appears to be as follows.
+ *
+ * There are two sets of receive DMA registers and two sets
+ * of transmit DMA registers. Instead of the more traditional
+ * "ring buffer" approach the Mac68K DMA engine expects you
+ * to be loading one chain while the other runs, and then
+ * to flip register set. Each entry in the chain is a fixed
+ * length.
+ */
+
+/*
+ * Load a receive DMA channel with a base address and ring length
+ */
+
+static void psc_load_rxdma_base(int set, void *base)
+{
+ psc_write_word(PSC_ENETRD_CMD + set, 0x0100);
+ psc_write_long(PSC_ENETRD_ADDR + set, (u32)base);
+ psc_write_long(PSC_ENETRD_LEN + set, N_RX_RING);
+ psc_write_word(PSC_ENETRD_CMD + set, 0x9800);
+}
+
+/*
+ * Reset the receive DMA subsystem
+ */
+
+static void mace68k_rxdma_reset(struct net_device *dev)
+{
+ struct mace68k_data *mp = (struct mace68k_data *) dev->priv;
+ volatile struct mace *mace = mp->mace;
+ u8 mcc = mace->maccc;
+
+ /*
+ * Turn off receive
+ */
+
+ mcc&=~ENRCV;
+ mace->maccc=mcc;
+
+ /*
+ * Program the DMA
+ */
+
+ psc_write_word(PSC_ENETRD_CTL, 0x8800);
+ psc_load_rxdma_base(0x0, (void *)virt_to_bus(mp->rx_ring));
+ psc_write_word(PSC_ENETRD_CTL, 0x0400);
+
+ psc_write_word(PSC_ENETRD_CTL, 0x8800);
+ psc_load_rxdma_base(0x10, (void *)virt_to_bus(mp->rx_ring));
+ psc_write_word(PSC_ENETRD_CTL, 0x0400);
+
+ mace->maccc=mcc|ENRCV;
+
+#if 0
+ psc_write_word(PSC_ENETRD_CTL, 0x9800);
+ psc_write_word(PSC_ENETRD_CTL+0x10, 0x9800);
+#endif
+}
+
+/*
+ * Reset the transmit DMA subsystem
+ */
+
+static void mace68k_txdma_reset(struct net_device *dev)
+{
+ struct mace68k_data *mp = (struct mace68k_data *) dev->priv;
+ volatile struct mace *mace = mp->mace;
+ u8 mcc = mace->maccc;
+
+ psc_write_word(PSC_ENETWR_CTL,0x8800);
+
+ mace->maccc = mcc&~ENXMT;
+ psc_write_word(PSC_ENETWR_CTL,0x0400);
+ mace->maccc = mcc;
+}
+
+/*
+ * Disable DMA
+ */
+
+static void mace68k_dma_off(struct net_device *dev)
+{
+ psc_write_word(PSC_ENETRD_CTL, 0x8800);
+ psc_write_word(PSC_ENETRD_CTL, 0x1000);
+ psc_write_word(PSC_ENETRD_CMD, 0x1100);
+ psc_write_word(PSC_ENETRD_CMD+0x10, 0x1100);
+
+ psc_write_word(PSC_ENETWR_CTL, 0x8800);
+ psc_write_word(PSC_ENETWR_CTL, 0x1000);
+ psc_write_word(PSC_ENETWR_CMD, 0x1100);
+ psc_write_word(PSC_ENETWR_CMD+0x10, 0x1100);
+}
+
+/* Bit-reverse one byte of an ethernet hardware address. */
+
+static int bitrev(int b)
+{
+ int d = 0, i;
+
+ for (i = 0; i < 8; ++i, b >>= 1)
+ d = (d << 1) | (b & 1);
+ return d;
+}
+
+/*
+ * Not really much of a probe. The hardware table tells us if this
+ * model of Macintrash has a MACE (AV macintoshes)
+ */
+
+int mace68k_probe(struct net_device *unused)
+{
+ int j;
+ static int once=0;
+ struct mace68k_data *mp;
+ unsigned char *addr;
+ struct net_device *dev;
+ unsigned char checksum = 0;
+
+ /*
+ * There can be only one...
+ */
+
+ if (once) return -ENODEV;
+
+ once = 1;
+
+ if (macintosh_config->ether_type != MAC_ETHER_MACE) return -ENODEV;
+
+ printk("MACE ethernet should be present ");
+
+ dev = init_etherdev(0, PRIV_BYTES);
+ if(dev==NULL)
+ {
+ printk("no free memory.\n");
+ return -ENOMEM;
+ }
+ mp = (struct mace68k_data *) dev->priv;
+ dev->base_addr = (u32)MACE_BASE;
+ mp->mace = (volatile struct mace *) MACE_BASE;
+
+ printk("at 0x%p", mp->mace);
+
+ /*
+ * 16K RX ring and 4K TX ring should do nicely
+ */
+
+ mp->rx_ring=(void *)__get_free_pages(GFP_KERNEL, 2);
+ mp->tx_ring=(void *)__get_free_page(GFP_KERNEL);
+
+ printk(".");
+
+ if(mp->tx_ring==NULL || mp->rx_ring==NULL)
+ {
+ if(mp->tx_ring)
+ free_page((u32)mp->tx_ring);
+// if(mp->rx_ring)
+// __free_pages(mp->rx_ring,2);
+ printk("\nNo memory for ring buffers.\n");
+ return -ENOMEM;
+ }
+
+ /* We want the receive data to be uncached. We dont care about the
+ byte reading order */
+
+ printk(".");
+ kernel_set_cachemode((void *)mp->rx_ring, 16384, IOMAP_NOCACHE_NONSER);
+
+ printk(".");
+ /* The transmit buffer needs to be write through */
+ kernel_set_cachemode((void *)mp->tx_ring, 4096, IOMAP_WRITETHROUGH);
+
+ printk(" Ok\n");
+ dev->irq = IRQ_MAC_MACE;
+ printk(KERN_INFO "%s: MACE at", dev->name);
+
+ /*
+ * The PROM contains 8 bytes which total 0xFF when XOR'd
+ * together. Due to the usual peculiar apple brain damage
+ * the bytes are spaced out in a strange boundary and the
+ * bits are reversed.
+ */
+
+ addr = (void *)MACE_PROM;
+
+ for (j = 0; j < 6; ++j)
+ {
+ u8 v=bitrev(addr[j<<4]);
+ checksum^=v;
+ dev->dev_addr[j] = v;
+ printk("%c%.2x", (j ? ':' : ' '), dev->dev_addr[j]);
+ }
+ for (; j < 8; ++j)
+ {
+ checksum^=bitrev(addr[j<<4]);
+ }
+
+ if(checksum!=0xFF)
+ {
+ printk(" (invalid checksum)\n");
+ return -ENODEV;
+ }
+ printk("\n");
+
+ memset(&mp->stats, 0, sizeof(mp->stats));
+ init_timer(&mp->tx_timeout);
+ mp->timeout_active = 0;
+
+ dev->open = mace68k_open;
+ dev->stop = mace68k_close;
+ dev->hard_start_xmit = mace68k_xmit_start;
+ dev->get_stats = mace68k_stats;
+ dev->set_multicast_list = mace68k_set_multicast;
+ dev->set_mac_address = mace68k_set_address;
+
+ ether_setup(dev);
+
+ mp = (struct mace68k_data *) dev->priv;
+ mp->maccc = ENXMT | ENRCV;
+ mp->dma_intr = IRQ_MAC_MACE_DMA;
+
+ psc_write_word(PSC_ENETWR_CTL, 0x9000);
+ psc_write_word(PSC_ENETRD_CTL, 0x9000);
+ psc_write_word(PSC_ENETWR_CTL, 0x0400);
+ psc_write_word(PSC_ENETRD_CTL, 0x0400);
+
+ /* apple's driver doesn't seem to do this */
+ /* except at driver shutdown time... */
+#if 0
+ mace68k_dma_off(dev);
+#endif
+
+ return 0;
+}
+
+/*
+ * Reset a MACE controller
+ */
+
+static void mace68k_reset(struct net_device *dev)
+{
+ struct mace68k_data *mp = (struct mace68k_data *) dev->priv;
+ volatile struct mace *mb = mp->mace;
+ int i;
+
+ /* soft-reset the chip */
+ i = 200;
+ while (--i) {
+ mb->biucc = SWRST;
+ if (mb->biucc & SWRST) {
+ udelay(10);
+ continue;
+ }
+ break;
+ }
+ if (!i) {
+ printk(KERN_ERR "mace: cannot reset chip!\n");
+ return;
+ }
+
+ mb->biucc = XMTSP_64;
+ mb->imr = 0xff; /* disable all intrs for now */
+ i = mb->ir;
+ mb->maccc = 0; /* turn off tx, rx */
+ mb->utr = RTRD;
+ mb->fifocc = RCVFW_64;
+ mb->xmtfc = AUTO_PAD_XMIT; /* auto-pad short frames */
+
+ /* load up the hardware address */
+
+ mb->iac = ADDRCHG | PHYADDR;
+
+ while ((mb->iac & ADDRCHG) != 0);
+
+ for (i = 0; i < 6; ++i)
+ mb->padr = dev->dev_addr[i];
+
+ /* clear the multicast filter */
+ mb->iac = ADDRCHG | LOGADDR;
+
+ while ((mb->iac & ADDRCHG) != 0);
+
+ for (i = 0; i < 8; ++i)
+ mb->ladrf = 0;
+
+ mb->plscc = PORTSEL_GPSI + ENPLSIO;
+}
+
+/*
+ * Load the address on a mace controller.
+ */
+
+static int mace68k_set_address(struct net_device *dev, void *addr)
+{
+ unsigned char *p = addr;
+ struct mace68k_data *mp = (struct mace68k_data *) dev->priv;
+ volatile struct mace *mb = mp->mace;
+ int i;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+
+ /* load up the hardware address */
+ mb->iac = ADDRCHG | PHYADDR;
+ while ((mb->iac & ADDRCHG) != 0);
+
+ for (i = 0; i < 6; ++i)
+ mb->padr = dev->dev_addr[i] = p[i];
+ /* note: setting ADDRCHG clears ENRCV */
+ mb->maccc = mp->maccc;
+ restore_flags(flags);
+ return 0;
+}
+
+/*
+ * Open the Macintosh MACE. Most of this is playing with the DMA
+ * engine. The ethernet chip is quite friendly.
+ */
+
+static int mace68k_open(struct net_device *dev)
+{
+ struct mace68k_data *mp = (struct mace68k_data *) dev->priv;
+ volatile struct mace *mb = mp->mace;
+
+ /* reset the chip */
+ mace68k_reset(dev);
+
+ mp->rx_done = 0;
+ mace68k_rxdma_reset(dev);
+
+ /*
+ * The interrupt is fixed and comes off the PSC.
+ */
+
+ if (request_irq(dev->irq, mace68k_interrupt, 0, "68K MACE", dev))
+ {
+ printk(KERN_ERR "MACE: can't get irq %d\n", dev->irq);
+ return -EAGAIN;
+ }
+
+ /*
+ * Ditto the DMA interrupt.
+ */
+
+ if (request_irq(IRQ_MAC_MACE_DMA, mace68k_dma_intr, 0, "68K MACE DMA",
+ dev))
+ {
+ printk(KERN_ERR "MACE: can't get irq %d\n", IRQ_MAC_MACE_DMA);
+ return -EAGAIN;
+ }
+
+ /* Activate the Mac DMA engine */
+
+ mp->tx_slot = 0; /* Using register set 0 */
+ mp->tx_count = 1; /* 1 Buffer ready for use */
+ mace68k_txdma_reset(dev);
+
+ /* turn it on! */
+ mb->maccc = mp->maccc;
+ /* enable all interrupts except receive interrupts */
+ mb->imr = RCVINT;
+ return 0;
+}
+
+/*
+ * Shut down the mace and its interrupt channel
+ */
+
+static int mace68k_close(struct net_device *dev)
+{
+ struct mace68k_data *mp = (struct mace68k_data *) dev->priv;
+ volatile struct mace *mb = mp->mace;
+
+ /* disable rx and tx */
+ mb->maccc = 0;
+ mb->imr = 0xff; /* disable all intrs */
+
+ /* disable rx and tx dma */
+
+ mace68k_dma_off(dev);
+
+ free_irq(dev->irq, dev);
+ free_irq(IRQ_MAC_MACE_DMA, dev);
+ return 0;
+}
+
+static inline void mace68k_set_timeout(struct net_device *dev)
+{
+ struct mace68k_data *mp = (struct mace68k_data *) dev->priv;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ if (mp->timeout_active)
+ del_timer(&mp->tx_timeout);
+ mp->tx_timeout.expires = jiffies + TX_TIMEOUT;
+ mp->tx_timeout.function = mace68k_tx_timeout;
+ mp->tx_timeout.data = (unsigned long) dev;
+ add_timer(&mp->tx_timeout);
+ mp->timeout_active = 1;
+ restore_flags(flags);
+}
+
+/*
+ * Transmit a frame
+ */
+
+static int mace68k_xmit_start(struct sk_buff *skb, struct net_device *dev)
+{
+ struct mace68k_data *mp = (struct mace68k_data *) dev->priv;
+ /*
+ * This may need atomic types ???
+ */
+
+ printk("mace68k_xmit_start: mp->tx_count = %d, dev->tbusy = %d, mp->tx_ring = %p (%p)\n",
+ mp->tx_count, dev->tbusy,
+ mp->tx_ring, virt_to_bus(mp->tx_ring));
+ psc_debug_dump();
+
+ if(mp->tx_count == 0)
+ {
+ dev->tbusy=1;
+ mace68k_dma_intr(IRQ_MAC_MACE_DMA, dev, NULL);
+ return 1;
+ }
+ mp->tx_count--;
+
+ /*
+ * FIXME:
+ * This is hackish. The memcpy probably isnt needed but
+ * the rules for alignment are not known. Ideally we'd like
+ * to just blast the skb directly to ethernet. We also don't
+ * use the ring properly - just a one frame buffer. That
+ * also requires cache pushes ;).
+ */
+ memcpy((void *)mp->tx_ring, skb, skb->len);
+ psc_write_long(PSC_ENETWR_ADDR + mp->tx_slot, virt_to_bus(mp->tx_ring));
+ psc_write_long(PSC_ENETWR_LEN + mp->tx_slot, skb->len);
+ psc_write_word(PSC_ENETWR_CMD + mp->tx_slot, 0x9800);
+ mp->stats.tx_packets++;
+ mp->stats.tx_bytes+=skb->len;
+ dev_kfree_skb(skb);
+ return 0;
+}
+
+static struct net_device_stats *mace68k_stats(struct net_device *dev)
+{
+ struct mace68k_data *p = (struct mace68k_data *) dev->priv;
+ return &p->stats;
+}
+
+/*
+ * CRC polynomial - used in working out multicast filter bits.
+ */
+#define CRC_POLY 0xedb88320
+
+static void mace68k_set_multicast(struct net_device *dev)
+{
+ struct mace68k_data *mp = (struct mace68k_data *) dev->priv;
+ volatile struct mace *mb = mp->mace;
+ int i, j, k, b;
+ unsigned long crc;
+
+ mp->maccc &= ~PROM;
+ if (dev->flags & IFF_PROMISC)
+ {
+ mp->maccc |= PROM;
+ } else
+ {
+ unsigned char multicast_filter[8];
+ struct dev_mc_list *dmi = dev->mc_list;
+
+ if (dev->flags & IFF_ALLMULTI)
+ {
+ for (i = 0; i < 8; i++)
+ multicast_filter[i] = 0xff;
+ } else
+ {
+ for (i = 0; i < 8; i++)
+ multicast_filter[i] = 0;
+ for (i = 0; i < dev->mc_count; i++)
+ {
+ crc = ~0;
+ for (j = 0; j < 6; ++j)
+ {
+ b = dmi->dmi_addr[j];
+ for (k = 0; k < 8; ++k)
+ {
+ if ((crc ^ b) & 1)
+ crc = (crc >> 1) ^ CRC_POLY;
+ else
+ crc >>= 1;
+ b >>= 1;
+ }
+ }
+ j = crc >> 26; /* bit number in multicast_filter */
+ multicast_filter[j >> 3] |= 1 << (j & 7);
+ dmi = dmi->next;
+ }
+ }
+#if 0
+ printk("Multicast filter :");
+ for (i = 0; i < 8; i++)
+ printk("%02x ", multicast_filter[i]);
+ printk("\n");
+#endif
+
+ mb->iac = ADDRCHG | LOGADDR;
+ while ((mb->iac & ADDRCHG) != 0);
+
+ for (i = 0; i < 8; ++i)
+ mb->ladrf = multicast_filter[i];
+ }
+ /* reset maccc */
+ mb->maccc = mp->maccc;
+}
+
+/*
+ * Miscellaneous interrupts are handled here. We may end up
+ * having to bash the chip on the head for bad errors
+ */
+
+static void mace68k_handle_misc_intrs(struct mace68k_data *mp, int intr)
+{
+ volatile struct mace *mb = mp->mace;
+ static int mace68k_babbles, mace68k_jabbers;
+
+ if (intr & MPCO)
+ mp->stats.rx_missed_errors += 256;
+ mp->stats.rx_missed_errors += mb->mpc; /* reading clears it */
+ if (intr & RNTPCO)
+ mp->stats.rx_length_errors += 256;
+ mp->stats.rx_length_errors += mb->rntpc; /* reading clears it */
+ if (intr & CERR)
+ ++mp->stats.tx_heartbeat_errors;
+ if (intr & BABBLE)
+ if (mace68k_babbles++ < 4)
+ printk(KERN_DEBUG "mace: babbling transmitter\n");
+ if (intr & JABBER)
+ if (mace68k_jabbers++ < 4)
+ printk(KERN_DEBUG "mace: jabbering transceiver\n");
+}
+
+/*
+ * A transmit error has occured. (We kick the transmit side from
+ * the DMA completion)
+ */
+
+static void mace68k_xmit_error(struct net_device *dev)
+{
+ struct mace68k_data *mp = (struct mace68k_data *) dev->priv;
+ volatile struct mace *mb = mp->mace;
+ u8 xmtfs, xmtrc;
+
+ xmtfs = mb->xmtfs;
+ xmtrc = mb->xmtrc;
+
+ if(xmtfs & XMTSV)
+ {
+ if(xmtfs & UFLO)
+ {
+ printk("%s: DMA underrun.\n", dev->name);
+ mp->stats.tx_errors++;
+ mp->stats.tx_fifo_errors++;
+ mace68k_reset(dev);
+ }
+ if(xmtfs & RTRY)
+ mp->stats.collisions++;
+ }
+ mark_bh(NET_BH);
+}
+
+/*
+ * A receive interrupt occured.
+ */
+
+static void mace68k_recv_interrupt(struct net_device *dev)
+{
+// struct mace68k_data *mp = (struct mace68k_data *) dev->priv;
+// volatile struct mace *mb = mp->mace;
+}
+
+/*
+ * Process the chip interrupt
+ */
+
+static void mace68k_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct net_device *dev = (struct net_device *) dev_id;
+ struct mace68k_data *mp = (struct mace68k_data *) dev->priv;
+ volatile struct mace *mb = mp->mace;
+ u8 ir;
+
+ ir = mb->ir;
+ mace68k_handle_misc_intrs(mp, ir);
+
+ if(ir&XMTINT)
+ mace68k_xmit_error(dev);
+ if(ir&RCVINT)
+ mace68k_recv_interrupt(dev);
+}
+
+static void mace68k_tx_timeout(unsigned long data)
+{
+// struct net_device *dev = (struct net_device *) data;
+// struct mace68k_data *mp = (struct mace68k_data *) dev->priv;
+// volatile struct mace *mb = mp->mace;
+}
+
+/*
+ * Handle a newly arrived frame
+ */
+
+static void mace_dma_rx_frame(struct net_device *dev, struct mace_frame *mf)
+{
+ struct mace68k_data *mp = (struct mace68k_data *) dev->priv;
+ struct sk_buff *skb;
+
+ if(mf->status&RS_OFLO)
+ {
+ printk("%s: fifo overflow.\n", dev->name);
+ mp->stats.rx_errors++;
+ mp->stats.rx_fifo_errors++;
+ }
+ if(mf->status&(RS_CLSN|RS_FRAMERR|RS_FCSERR))
+ mp->stats.rx_errors++;
+
+ if(mf->status&RS_CLSN)
+ mp->stats.collisions++;
+ if(mf->status&RS_FRAMERR)
+ mp->stats.rx_frame_errors++;
+ if(mf->status&RS_FCSERR)
+ mp->stats.rx_crc_errors++;
+
+ skb = dev_alloc_skb(mf->len+2);
+ if(skb==NULL)
+ {
+ mp->stats.rx_dropped++;
+ return;
+ }
+ skb_reserve(skb,2);
+ memcpy(skb_put(skb, mf->len), mf->data, mf->len);
+
+ skb->protocol = eth_type_trans(skb, dev);
+ netif_rx(skb);
+ mp->stats.rx_packets++;
+ mp->stats.rx_bytes+=mf->len;
+}
+
+/*
+ * The PSC has passed us a DMA interrupt event.
+ */
+
+static void mace68k_dma_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct net_device *dev = (struct net_device *) dev_id;
+ struct mace68k_data *mp = (struct mace68k_data *) dev->priv;
+
+#if 0
+ u32 psc_status;
+
+ /* It seems this must be allowed to stabilise ?? */
+
+ while((psc_status=psc_read_long(0x0804))!=psc_read_long(0x0804));
+
+ /*
+ * Was this an ethernet event ?
+ */
+
+ if(psc_status&0x60000000)
+ {
+#endif
+ /*
+ * Process the read queue
+ */
+
+ u16 psc_status = psc_read_word(PSC_ENETRD_CTL);
+
+ printk("mace68k_dma_intr: PSC_ENETRD_CTL = %04X\n", (uint) psc_status);
+
+ if (psc_status & 0x2000) {
+ mace68k_rxdma_reset(dev);
+ mp->rx_done = 0;
+ } else if (psc_status & 0x100) {
+ int left;
+
+ psc_write_word(PSC_ENETRD_CMD + mp->rx_slot, 0x1100);
+ left=psc_read_long(PSC_ENETRD_LEN + mp->rx_slot);
+ /* read packets */
+
+ while(mp->rx_done < left)
+ {
+ struct mace_frame *mf=((struct mace_frame *)
+ mp->rx_ring)+mp->rx_done++;
+ mace_dma_rx_frame(dev, mf);
+ }
+
+ if(left == 0) /* Out of DMA room */
+ {
+ psc_load_rxdma_base(mp->rx_slot,
+ (void *)virt_to_phys(mp->rx_ring));
+ mp->rx_slot^=16;
+ mp->rx_done = 0;
+ }
+ else
+ {
+ psc_write_word(PSC_ENETRD_CMD+mp->rx_slot,
+ 0x9800);
+ }
+
+ }
+
+ /*
+ * Process the write queue
+ */
+
+ psc_status = psc_read_word(PSC_ENETWR_CTL);
+ printk("mace68k_dma_intr: PSC_ENETWR_CTL = %04X\n", (uint) psc_status);
+
+ /* apple's driver seems to loop over this until neither */
+ /* condition is true. - jmt */
+
+ if (psc_status & 0x2000) {
+ mace68k_txdma_reset(dev);
+ } else if (psc_status & 0x0100) {
+ psc_write_word(PSC_ENETWR_CMD + mp->tx_slot, 0x0100);
+ mp->tx_slot ^=16;
+ mp->tx_count++;
+ dev->tbusy = 0;
+ mark_bh(NET_BH);
+ }
+#if 0
+ }
+#endif
+}
diff --git a/drivers/net/macsonic.c b/drivers/net/macsonic.c
index d14ccf3fb..dbb9129d7 100644
--- a/drivers/net/macsonic.c
+++ b/drivers/net/macsonic.c
@@ -42,153 +42,245 @@
#include <asm/pgtable.h>
#include <asm/segment.h>
#include <asm/io.h>
+#include <asm/hwtest.h>
#include <asm/dma.h>
#include <asm/macintosh.h>
+#include <asm/macints.h>
+#include <asm/mac_via.h>
#include <linux/errno.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
-
-#include <config/macsonic.h>
+#include <linux/module.h>
#define SREGS_PAD(n) u16 n;
#include "sonic.h"
-extern int mac_onboard_sonic_probe(void);
+static int sonic_debug = 0;
+static int sonic_version_printed = 0;
-static int setup_debug = -1;
-static int setup_offset = -1;
-static int setup_shift = -1;
+extern int macsonic_probe(struct net_device* dev);
+extern int mac_onboard_sonic_probe(struct net_device* dev);
+extern int mac_nubus_sonic_probe(struct net_device* dev);
-/*
- * This seems to be the right default for the Q800
- */
+/* For onboard SONIC */
+#define ONBOARD_SONIC_REGISTERS 0x50F0A000
+#define ONBOARD_SONIC_PROM_BASE 0x50f08000
-static int reg_offset = 0;
-static int reg_shift = 0;
+enum macsonic_type {
+ MACSONIC_DUODOCK,
+ MACSONIC_APPLE,
+ MACSONIC_APPLE16,
+ MACSONIC_DAYNA,
+ MACSONIC_DAYNALINK
+};
-/*
- * Macros to access SONIC registers
- */
-
-#define MAC_SONIC_REGISTERS 0x50F0A000
-#define MAC_SONIC_PROM_BASE 0x50f08000
-#define MAC_SONIC_IRQ 9 /* Nubus 9 */
+/* For the built-in SONIC in the Duo Dock */
+#define DUODOCK_SONIC_REGISTERS 0xe10000
+#define DUODOCK_SONIC_PROM_BASE 0xe12000
-/*
- * FIXME: We may need to invert the byte ordering. These should
- * be ok for other aspects as they are uncached spaces.
- * The original macros from jazzsonic.c works for me
- * on my LC 630, YMMV /Andreas Ehliar
- */
+/* For Apple-style NuBus SONIC */
+#define APPLE_SONIC_REGISTERS 0
+#define APPLE_SONIC_PROM_BASE 0x40000
-#if 0
-#define SONIC_READ(reg) \
- *((volatile unsigned int *)base_addr+((reg)<<2)+2)
+/* Daynalink LC SONIC */
+#define DAYNALINK_PROM_BASE 0x400000
-#define SONIC_WRITE(reg,val) \
- *((volatile unsigned int *)base_addr+((reg)<<2)+2) = val
-#else
-#define SONIC_READ(reg) \
- *((volatile unsigned int *)base_addr+reg)
+/* For Dayna-style NuBus SONIC (haven't seen one yet) */
+#define DAYNA_SONIC_REGISTERS 0x180000
+/* This is what OpenBSD says. However, this is definitely in NuBus
+ ROM space so we should be able to get it by walking the NuBus
+ resource directories */
+#define DAYNA_SONIC_MAC_ADDR 0xffe004
-#define SONIC_WRITE(reg,val) \
- *((volatile unsigned int *)base_addr+reg) = val
-#endif
+#define SONIC_READ_PROM(addr) readb(prom_addr+addr)
+
+int __init macsonic_probe(struct net_device* dev)
+{
+ int rv;
+
+ /* This will catch fatal stuff like -ENOMEM as well as success */
+ if ((rv = mac_onboard_sonic_probe(dev)) != -ENODEV)
+ return rv;
+ return mac_nubus_sonic_probe(dev);
+}
-#define SONIC_READ_PROM(addr) \
- *((volatile unsigned char *)prom_addr+addr)
/*
- * Function : mac_sonic_setup(char *str, int *ints)
- *
- * Purpose : booter command line initialization of the overrides array,
- *
- * Inputs : str - unused, ints - array of integer parameters with ints[0]
- * equal to the number of ints.
- *
- * Currently unused in the new driver; need to add settable parameters to the
- * detect function.
- *
+ * For reversing the PROM address
*/
-void mac_sonic_setup(char *str, int *ints) {
- /* Format of macsonic parameter is:
- * macsonic=<debug>,<offset>,<shift>
- * Negative values mean don't change.
- */
-
- /* Grmbl... the standard parameter parsing can't handle negative numbers
- * :-( So let's do it ourselves!
- */
+static unsigned char nibbletab[] = {0, 8, 4, 12, 2, 10, 6, 14,
+ 1, 9, 5, 13, 3, 11, 7, 15};
- int i = ints[0]+1, fact;
+static inline void bit_reverse_addr(unsigned char addr[6])
+{
+ int i;
- while( str && (isdigit(*str) || *str == '-') && i <= 10) {
- if (*str == '-')
- fact = -1, ++str;
- else
- fact = 1;
- ints[i++] = simple_strtoul( str, NULL, 0 ) * fact;
- if ((str = strchr( str, ',' )) != NULL)
- ++str;
- }
- ints[0] = i-1;
-
- if (ints[0] < 1) {
- printk( "mac_sonic_setup: no arguments!\n" );
- return;
- }
+ for(i = 0; i < 6; i++)
+ addr[i] = ((nibbletab[addr[i] & 0xf] << 4) |
+ nibbletab[(addr[i] >> 4) &0xf]);
+}
+
+int __init macsonic_init(struct net_device* dev)
+{
+ struct sonic_local* lp = (struct sonic_local *)dev->priv;
+ int i;
- if (ints[0] >= 1) {
- /* 0 <= n <= 2 */
- if (ints[1] >= 0 && ints[1] <= 8)
- setup_debug = ints[1];
- else if (ints[1] > 16)
- printk( "mac_sonic_setup: invalid debug level %d !\n", ints[1] );
+ /* Allocate the entire chunk of memory for the descriptors.
+ Note that this cannot cross a 64K boundary. */
+ for (i = 0; i < 20; i++) {
+ unsigned long desc_base, desc_top;
+ if ((lp->sonic_desc =
+ kmalloc(SIZEOF_SONIC_DESC
+ * SONIC_BUS_SCALE(lp->dma_bitmode), GFP_DMA)) == NULL) {
+ printk(KERN_ERR "%s: couldn't allocate descriptor buffers\n", dev->name);
+ }
+ desc_base = (unsigned long) lp->sonic_desc;
+ desc_top = desc_base + SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode);
+ if ((desc_top & 0xffff) >= (desc_base & 0xffff))
+ break;
+ /* Hmm. try again (FIXME: does this actually work?) */
+ kfree(lp->sonic_desc);
+ printk(KERN_DEBUG
+ "%s: didn't get continguous chunk [%08lx - %08lx], trying again\n",
+ dev->name, desc_base, desc_top);
}
- if (ints[0] >= 2) {
- /* 0 <= n <= 2 */
- if (ints[2] >= 0 && ints[2] <= 16)
- setup_offset = ints[2];
- else if (ints[2] > 16)
- printk( "mac_sonic_setup: invalid offset %d !\n", ints[2] );
+
+ if (lp->sonic_desc == NULL) {
+ printk(KERN_ERR "%s: tried 20 times to allocate descriptor buffers, giving up.\n",
+ dev->name);
+ return -ENOMEM;
+ }
+
+ /* Now set up the pointers to point to the appropriate places */
+ lp->cda = lp->sonic_desc;
+ lp->tda = lp->cda + (SIZEOF_SONIC_CDA * SONIC_BUS_SCALE(lp->dma_bitmode));
+ lp->rda = lp->tda + (SIZEOF_SONIC_TD * SONIC_NUM_TDS
+ * SONIC_BUS_SCALE(lp->dma_bitmode));
+ lp->rra = lp->rda + (SIZEOF_SONIC_RD * SONIC_NUM_RDS
+ * SONIC_BUS_SCALE(lp->dma_bitmode));
+
+ /* FIXME, maybe we should use skbs */
+ if ((lp->rba = (char *)
+ kmalloc(SONIC_NUM_RRS * SONIC_RBSIZE, GFP_DMA)) == NULL) {
+ printk(KERN_ERR "%s: couldn't allocate receive buffers\n", dev->name);
+ return -ENOMEM;
}
- if (ints[0] >= 3) {
- /* 0 <= n <= 2 */
- if (ints[3] >= 0 && ints[3] <= 16)
- setup_shift = ints[3];
- else if (ints[3] > 16)
- printk( "mac_sonic_setup: invalid shift %d !\n", ints[3] );
+
+ {
+ int rs, ds;
+
+ /* almost always 12*4096, but let's not take chances */
+ rs = ((SONIC_NUM_RRS * SONIC_RBSIZE + 4095) / 4096) * 4096;
+ /* almost always under a page, but let's not take chances */
+ ds = ((SIZEOF_SONIC_DESC + 4095) / 4096) * 4096;
+ kernel_set_cachemode(lp->rba, rs, IOMAP_NOCACHE_SER);
+ kernel_set_cachemode(lp->sonic_desc, ds, IOMAP_NOCACHE_SER);
}
+
+#if 0
+ flush_cache_all();
+#endif
+
+ dev->open = sonic_open;
+ dev->stop = sonic_close;
+ dev->hard_start_xmit = sonic_send_packet;
+ dev->get_stats = sonic_get_stats;
+ dev->set_multicast_list = &sonic_multicast_list;
+
+ /*
+ * clear tally counter
+ */
+ sonic_write(dev, SONIC_CRCT, 0xffff);
+ sonic_write(dev, SONIC_FAET, 0xffff);
+ sonic_write(dev, SONIC_MPT, 0xffff);
+
+ /* Fill in the fields of the device structure with ethernet values. */
+ ether_setup(dev);
+ return 0;
}
-static int sonic_debug = 0;
+int __init mac_onboard_sonic_ethernet_addr(struct net_device* dev)
+{
+ const int prom_addr = ONBOARD_SONIC_PROM_BASE;
+ int i;
-/*
- * For reversing the PROM address
- */
+ /* On NuBus boards we can sometimes look in the ROM resources.
+ No such luck for comm-slot/onboard. */
+ for(i = 0; i < 6; i++)
+ dev->dev_addr[i] = SONIC_READ_PROM(i);
-static unsigned char nibbletab[] = {0, 8, 4, 12, 2, 10, 6, 14,
- 1, 9, 5, 13, 3, 11, 7, 15};
+ /* Most of the time, the address is bit-reversed. The NetBSD
+ source has a rather long and detailed historical account of
+ why this is so. */
+ if (memcmp(dev->dev_addr, "\x08\x00\x07", 3) &&
+ memcmp(dev->dev_addr, "\x00\xA0\x40", 3) &&
+ memcmp(dev->dev_addr, "\x00\x05\x02", 3))
+ bit_reverse_addr(dev->dev_addr);
+ else
+ return 0;
+
+ /* If we still have what seems to be a bogus address, we'll
+ look in the CAM. The top entry should be ours. */
+ /* Danger! This only works if MacOS has already initialized
+ the card... */
+ if (memcmp(dev->dev_addr, "\x08\x00\x07", 3) &&
+ memcmp(dev->dev_addr, "\x00\xA0\x40", 3) &&
+ memcmp(dev->dev_addr, "\x00\x05\x02", 3))
+ {
+ unsigned short val;
+
+ printk(KERN_INFO "macsonic: PROM seems to be wrong, trying CAM entry 15\n");
+
+ sonic_write(dev, SONIC_CMD, SONIC_CR_RST);
+ sonic_write(dev, SONIC_CEP, 15);
+
+ val = sonic_read(dev, SONIC_CAP2);
+ dev->dev_addr[5] = val >> 8;
+ dev->dev_addr[4] = val & 0xff;
+ val = sonic_read(dev, SONIC_CAP1);
+ dev->dev_addr[3] = val >> 8;
+ dev->dev_addr[2] = val & 0xff;
+ val = sonic_read(dev, SONIC_CAP0);
+ dev->dev_addr[1] = val >> 8;
+ dev->dev_addr[0] = val & 0xff;
+
+ printk(KERN_INFO "HW Address from CAM 15: ");
+ for (i = 0; i < 6; i++) {
+ printk("%2.2x", dev->dev_addr[i]);
+ if (i < 5)
+ printk(":");
+ }
+ printk("\n");
+ } else return 0;
-int __init mac_onboard_sonic_probe(void)
+ if (memcmp(dev->dev_addr, "\x08\x00\x07", 3) &&
+ memcmp(dev->dev_addr, "\x00\xA0\x40", 3) &&
+ memcmp(dev->dev_addr, "\x00\x05\x02", 3))
+ {
+ /*
+ * Still nonsense ... messed up someplace!
+ */
+ printk(KERN_ERR "macsonic: ERROR (INVALID MAC)\n");
+ return -EIO;
+ } else return 0;
+}
+
+int __init mac_onboard_sonic_probe(struct net_device* dev)
{
- struct net_device *dev;
- unsigned int silicon_revision;
- unsigned int val;
- struct sonic_local *lp;
+ /* Bwahahaha */
+ static int once_is_more_than_enough = 0;
+ struct sonic_local* lp;
int i;
- int base_addr = MAC_SONIC_REGISTERS;
- int prom_addr = MAC_SONIC_PROM_BASE;
- static int one=0;
- if (!MACH_IS_MAC)
+ if (once_is_more_than_enough)
return -ENODEV;
+ once_is_more_than_enough = 1;
- if(++one!=1) /* Only one is allowed */
+ if (!MACH_IS_MAC)
return -ENODEV;
printk(KERN_INFO "Checking for internal Macintosh ethernet (SONIC).. ");
@@ -198,288 +290,332 @@ int __init mac_onboard_sonic_probe(void)
printk("none.\n");
return -ENODEV;
}
-
- printk("yes\n");
-
- if (setup_debug >= 0)
- sonic_debug = setup_debug;
- /*
- * This may depend on the actual Mac model ... works for me.
- */
- reg_offset =
- (setup_offset >= 0) ? setup_offset : 0;
- reg_shift =
- (setup_shift >= 0) ? setup_shift : 0;
+ /* Bogus probing, on the models which may or may not have
+ Ethernet (BTW, the Ethernet *is* always at the same
+ address, and nothing else lives there, at least if Apple's
+ documentation is to be believed) */
+ if (macintosh_config->ident == MAC_MODEL_Q630 ||
+ macintosh_config->ident == MAC_MODEL_P588 ||
+ macintosh_config->ident == MAC_MODEL_C610) {
+ unsigned long flags;
+ int card_present;
+
+ save_flags(flags);
+ cli();
+ card_present = hwreg_present((void*)ONBOARD_SONIC_REGISTERS);
+ restore_flags(flags);
+
+ if (!card_present) {
+ printk("none.\n");
+ return -ENODEV;
+ }
+ }
- /*
- * get the Silicon Revision ID. If this is one of the known
- * one assume that we found a SONIC ethernet controller at
- * the expected location.
- * (This is not implemented in the Macintosh driver yet; need
- * to collect values from various sources. Mine is 0x4 ...)
- */
+ printk("yes\n");
- silicon_revision = SONIC_READ(SONIC_SR);
- if (sonic_debug > 1)
- printk("SONIC Silicon Revision = 0x%04x\n", silicon_revision);
+ if (dev) {
+ dev = init_etherdev(dev, sizeof(struct sonic_local));
+ /* methinks this will always be true but better safe than sorry */
+ if (dev->priv == NULL)
+ dev->priv = kmalloc(sizeof(struct sonic_local), GFP_KERNEL);
+ } else {
+ dev = init_etherdev(NULL, sizeof(struct sonic_local));
+ }
- /*
- * We need to allocate sonic_local later on, making sure it's
- * aligned on a 64k boundary. So, no space for dev->priv allocated
- * here ...
- */
- dev = init_etherdev(0,0);
-
- if(dev==NULL)
+ if (dev == NULL)
return -ENOMEM;
- printk("%s: %s found at 0x%08x, ",
- dev->name, "SONIC ethernet", base_addr);
+ lp = (struct sonic_local*) dev->priv;
+ memset(lp, 0, sizeof(struct sonic_local));
+ /* Danger! My arms are flailing wildly! You *must* set this
+ before using sonic_read() */
- if (sonic_debug > 1)
- printk("using offset %d shift %d,", reg_offset, reg_shift);
+ dev->base_addr = ONBOARD_SONIC_REGISTERS;
+ if (via_alt_mapping)
+ dev->irq = IRQ_AUTO_3;
+ else
+ dev->irq = IRQ_NUBUS_9;
- /* Fill in the 'dev' fields. */
- dev->base_addr = base_addr;
- dev->irq = MAC_SONIC_IRQ;
+ if (!sonic_version_printed) {
+ printk(KERN_INFO "%s", version);
+ sonic_version_printed = 1;
+ }
+ printk(KERN_INFO "%s: onboard / comm-slot SONIC at 0x%08lx\n",
+ dev->name, dev->base_addr);
+
+ /* Now do a song and dance routine in an attempt to determine
+ the bus width */
+
+ /* The PowerBook's SONIC is 16 bit always. */
+ if (macintosh_config->ident == MAC_MODEL_PB520) {
+ lp->reg_offset = 0;
+ lp->dma_bitmode = 0;
+ } else {
+ /* Some of the comm-slot cards are 16 bit. But some
+ of them are not. The 32-bit cards use offset 2 and
+ pad with zeroes or sometimes ones (I think...)
+ Therefore, if we try offset 0 and get a silicon
+ revision of 0, we assume 16 bit. */
+ int sr;
+
+ /* Technically this is not necessary since we zeroed
+ it above */
+ lp->reg_offset = 0;
+ lp->dma_bitmode = 0;
+ sr = sonic_read(dev, SONIC_SR);
+ if (sr == 0 || sr == 0xffff) {
+ lp->reg_offset = 2;
+ /* 83932 is 0x0004, 83934 is 0x0100 or 0x0101 */
+ sr = sonic_read(dev, SONIC_SR);
+ lp->dma_bitmode = 1;
+
+ }
+ printk(KERN_INFO
+ "%s: revision 0x%04x, using %d bit DMA and register offset %d\n",
+ dev->name, sr, lp->dma_bitmode?32:16, lp->reg_offset);
+ }
- /*
- * Put the sonic into software reset, then
- * retrieve and print the ethernet address.
- */
- SONIC_WRITE(SONIC_CMD, SONIC_CR_RST);
+ /* Software reset, then initialize control registers. */
+ sonic_write(dev, SONIC_CMD, SONIC_CR_RST);
+ sonic_write(dev, SONIC_DCR, SONIC_DCR_BMS |
+ SONIC_DCR_RFT1 | SONIC_DCR_TFT0 | SONIC_DCR_EXBUS |
+ (lp->dma_bitmode ? SONIC_DCR_DW : 0));
+ /* This *must* be written back to in order to restore the
+ extended programmable output bits */
+ sonic_write(dev, SONIC_DCR2, 0);
- /*
- * We can't trust MacOS to initialise things it seems.
- */
+ /* Clear *and* disable interrupts to be on the safe side */
+ sonic_write(dev, SONIC_ISR,0x7fff);
+ sonic_write(dev, SONIC_IMR,0);
- if (sonic_debug > 1)
- printk("SONIC_DCR was %X\n",SONIC_READ(SONIC_DCR));
-
- SONIC_WRITE(SONIC_DCR,
- SONIC_DCR_RFT1 | SONIC_DCR_TFT0 | SONIC_DCR_EXBUS | SONIC_DCR_DW);
+ /* Now look for the MAC address. */
+ if (mac_onboard_sonic_ethernet_addr(dev) != 0)
+ return -ENODEV;
- /*
- * We don't want floating spare IRQ's around, not on
- * level triggered systems!
- * Strange though - writing to the ISR only clears currently
- * pending IRQs, but doesn't disable them... Does this make
- * a difference?? Seems it does ...
- */
-#if 1
- SONIC_WRITE(SONIC_ISR,0x7fff);
- SONIC_WRITE(SONIC_IMR,0);
-#else
- SONIC_WRITE(SONIC_ISR, SONIC_IMR_DEFAULT);
-#endif
-
- /* This is how it is done in jazzsonic.c
- * It doesn't seem to work here though.
- */
- if (sonic_debug > 2) {
- printk("Retreiving CAM entry 0. This should be the HW address.\n");
-
- SONIC_WRITE(SONIC_CEP, 0);
- for (i = 0; i < 3; i++)
- {
- val = SONIC_READ(SONIC_CAP0 - i);
- dev->dev_addr[i * 2] = val;
- dev->dev_addr[i * 2 + 1] = val >> 8;
- }
+ printk(KERN_INFO "MAC ");
+ for (i = 0; i < 6; i++) {
+ printk("%2.2x", dev->dev_addr[i]);
+ if (i < 5)
+ printk(":");
+ }
- printk("HW Address from CAM 0: ");
- for (i = 0; i < 6; i++)
- {
- printk("%2.2x", dev->dev_addr[i]);
- if (i < 5)
- printk(":");
- }
- printk("\n");
+ printk(" IRQ %d\n", dev->irq);
- printk("Retreiving CAM entry 15. Another candidate...\n");
+ /* Shared init code */
+ return macsonic_init(dev);
+}
- /*
- * MacOS seems to use CAM entry 15 ...
- */
- SONIC_WRITE(SONIC_CEP, 15);
- for (i = 0; i < 3; i++)
- {
- val = SONIC_READ(SONIC_CAP0 - i);
- dev->dev_addr[i * 2] = val;
- dev->dev_addr[i * 2 + 1] = val >> 8;
- }
+int __init mac_nubus_sonic_ethernet_addr(struct net_device* dev,
+ unsigned long prom_addr,
+ int id)
+{
+ int i;
+ for(i = 0; i < 6; i++)
+ dev->dev_addr[i] = SONIC_READ_PROM(i);
+ /* For now we are going to assume that they're all bit-reversed */
+ bit_reverse_addr(dev->dev_addr);
- printk("HW Address from CAM 15: ");
- for (i = 0; i < 6; i++)
- {
- printk("%2.2x", dev->dev_addr[i]);
- if (i < 5)
- printk(":");
- }
- printk("\n");
- }
+ return 0;
+}
- /*
- * if we can read the PROM, we're safe :-)
- */
- if (sonic_debug > 1)
- printk("Retreiving HW address from the PROM: ");
-
- for(i=0;i<6;i++){
- dev->dev_addr[i]=SONIC_READ_PROM(i);
- }
- if (sonic_debug > 1) {
- for (i = 0; i < 6; i++)
- {
- printk("%2.2x", dev->dev_addr[i]);
- if (i < 5)
- printk(":");
- }
- printk("\n");
+int __init macsonic_ident(struct nubus_dev* ndev)
+{
+ if (ndev->dr_hw == NUBUS_DRHW_ASANTE_LC &&
+ ndev->dr_sw == NUBUS_DRSW_SONIC_LC)
+ return MACSONIC_DAYNALINK;
+ if (ndev->dr_hw == NUBUS_DRHW_SONIC &&
+ ndev->dr_sw == NUBUS_DRSW_APPLE) {
+ /* There has to be a better way to do this... */
+ if (strstr(ndev->board->name, "DuoDock"))
+ return MACSONIC_DUODOCK;
+ else
+ return MACSONIC_APPLE;
}
- /*
- * If its not one of these we have
- * screwed up on this Mac model
- */
+ return -1;
+}
- if (memcmp(dev->dev_addr, "\x08\x00\x07", 3) &&
- memcmp(dev->dev_addr, "\x00\xA0\x40", 3) &&
- memcmp(dev->dev_addr, "\x00\x05\x02", 3))
+int __init mac_nubus_sonic_probe(struct net_device* dev)
+{
+ static int slots = 0;
+ struct nubus_dev* ndev = NULL;
+ struct sonic_local* lp;
+ unsigned long base_addr, prom_addr;
+ u16 sonic_dcr;
+ int id;
+ int i;
+ int reg_offset, dma_bitmode;
+
+ /* Find the first SONIC that hasn't been initialized already */
+ while ((ndev = nubus_find_type(NUBUS_CAT_NETWORK,
+ NUBUS_TYPE_ETHERNET, ndev)) != NULL)
{
- /*
- * Try bit reversed
- */
- for(i=0;i<6;i++){
- val = SONIC_READ_PROM(i);
- dev->dev_addr[i]=(nibbletab[val & 0xf] << 4) |
- nibbletab[(val >> 4) &0xf];
- }
- if (sonic_debug > 1) {
- printk("Trying bit reversed: ");
- for (i = 0; i < 6; i++)
- {
- printk("%2.2x", dev->dev_addr[i]);
- if (i < 5)
- printk(":");
- }
- printk("\n");
- }
- if (memcmp(dev->dev_addr, "\x08\x00\x07", 3) &&
- memcmp(dev->dev_addr, "\x00\xA0\x40", 3) &&
- memcmp(dev->dev_addr, "\x00\x05\x02", 3))
- {
- /*
- * Still nonsense ... messed up someplace!
- */
- printk("ERROR (INVALID MAC)\n");
- return -EIO;
- }
+ /* Have we seen it already? */
+ if (slots & (1<<ndev->board->slot))
+ continue;
+ slots |= 1<<ndev->board->slot;
+
+ /* Is it one of ours? */
+ if ((id = macsonic_ident(ndev)) != -1)
+ break;
}
- printk(" MAC ");
- for (i = 0; i < 6; i++)
- {
+ if (ndev == NULL)
+ return -ENODEV;
+
+ switch (id) {
+ case MACSONIC_DUODOCK:
+ base_addr = ndev->board->slot_addr + DUODOCK_SONIC_REGISTERS;
+ prom_addr = ndev->board->slot_addr + DUODOCK_SONIC_PROM_BASE;
+ sonic_dcr = SONIC_DCR_EXBUS | SONIC_DCR_RFT0 | SONIC_DCR_RFT1
+ | SONIC_DCR_TFT0;
+ reg_offset = 2;
+ dma_bitmode = 1;
+ break;
+ case MACSONIC_APPLE:
+ base_addr = ndev->board->slot_addr + APPLE_SONIC_REGISTERS;
+ prom_addr = ndev->board->slot_addr + APPLE_SONIC_PROM_BASE;
+ sonic_dcr = SONIC_DCR_BMS | SONIC_DCR_RFT1 | SONIC_DCR_TFT0;
+ reg_offset = 0;
+ dma_bitmode = 1;
+ break;
+ case MACSONIC_APPLE16:
+ base_addr = ndev->board->slot_addr + APPLE_SONIC_REGISTERS;
+ prom_addr = ndev->board->slot_addr + APPLE_SONIC_PROM_BASE;
+ sonic_dcr = SONIC_DCR_EXBUS
+ | SONIC_DCR_RFT1 | SONIC_DCR_TFT0
+ | SONIC_DCR_PO1 | SONIC_DCR_BMS;
+ reg_offset = 0;
+ dma_bitmode = 0;
+ break;
+ case MACSONIC_DAYNALINK:
+ base_addr = ndev->board->slot_addr + APPLE_SONIC_REGISTERS;
+ prom_addr = ndev->board->slot_addr + DAYNALINK_PROM_BASE;
+ sonic_dcr = SONIC_DCR_RFT1 | SONIC_DCR_TFT0
+ | SONIC_DCR_PO1 | SONIC_DCR_BMS;
+ reg_offset = 0;
+ dma_bitmode = 0;
+ break;
+ case MACSONIC_DAYNA:
+ base_addr = ndev->board->slot_addr + DAYNA_SONIC_REGISTERS;
+ prom_addr = ndev->board->slot_addr + DAYNA_SONIC_MAC_ADDR;
+ sonic_dcr = SONIC_DCR_BMS
+ | SONIC_DCR_RFT1 | SONIC_DCR_TFT0 | SONIC_DCR_PO1;
+ reg_offset = 0;
+ dma_bitmode = 0;
+ break;
+ default:
+ printk(KERN_ERR "macsonic: WTF, id is %d\n", id);
+ return -ENODEV;
+ }
+
+ if (dev) {
+ dev = init_etherdev(dev, sizeof(struct sonic_local));
+ /* methinks this will always be true but better safe than sorry */
+ if (dev->priv == NULL)
+ dev->priv = kmalloc(sizeof(struct sonic_local), GFP_KERNEL);
+ } else {
+ dev = init_etherdev(NULL, sizeof(struct sonic_local));
+ }
+
+ if (dev == NULL)
+ return -ENOMEM;
+
+ lp = (struct sonic_local*) dev->priv;
+ memset(lp, 0, sizeof(struct sonic_local));
+ /* Danger! My arms are flailing wildly! You *must* set this
+ before using sonic_read() */
+ lp->reg_offset = reg_offset;
+ lp->dma_bitmode = dma_bitmode;
+ dev->base_addr = base_addr;
+ dev->irq = SLOT2IRQ(ndev->board->slot);
+
+ if (!sonic_version_printed) {
+ printk(KERN_INFO "%s", version);
+ sonic_version_printed = 1;
+ }
+ printk(KERN_INFO "%s: %s in slot %X\n",
+ dev->name, ndev->board->name, ndev->board->slot);
+ printk(KERN_INFO "%s: revision 0x%04x, using %d bit DMA and register offset %d\n",
+ dev->name, sonic_read(dev, SONIC_SR), dma_bitmode?32:16, reg_offset);
+
+ /* Software reset, then initialize control registers. */
+ sonic_write(dev, SONIC_CMD, SONIC_CR_RST);
+ sonic_write(dev, SONIC_DCR, sonic_dcr
+ | (dma_bitmode ? SONIC_DCR_DW : 0));
+
+ /* Clear *and* disable interrupts to be on the safe side */
+ sonic_write(dev, SONIC_ISR,0x7fff);
+ sonic_write(dev, SONIC_IMR,0);
+
+ /* Now look for the MAC address. */
+ if (mac_nubus_sonic_ethernet_addr(dev, prom_addr, id) != 0)
+ return -ENODEV;
+
+ printk(KERN_INFO "MAC ");
+ for (i = 0; i < 6; i++) {
printk("%2.2x", dev->dev_addr[i]);
if (i < 5)
printk(":");
}
+ printk(" IRQ %d\n", dev->irq);
- printk(" IRQ %d\n", MAC_SONIC_IRQ);
-
- /* Initialize the device structure. */
- if (dev->priv == NULL)
- {
- if (sonic_debug > 2) {
- printk("Allocating memory for dev->priv aka lp\n");
- printk("Memory to allocate: %d\n",sizeof(*lp));
- }
- /*
- * the memory be located in the same 64kb segment
- */
- lp = NULL;
- i = 0;
- do
- {
- lp = (struct sonic_local *) kmalloc(sizeof(*lp), GFP_KERNEL);
- if ((unsigned long) lp >> 16 != ((unsigned long) lp + sizeof(*lp)) >> 16)
- {
- /* FIXME, free the memory later */
- kfree(lp);
- lp = NULL;
- }
- }
- while (lp == NULL && i++ < 20);
+ /* Shared init code */
+ return macsonic_init(dev);
+}
- if (lp == NULL)
- {
- printk("%s: couldn't allocate memory for descriptors\n",
- dev->name);
- return -ENOMEM;
- }
+#ifdef MODULE
+static char namespace[16] = "";
+static struct net_device dev_macsonic = {
+ NULL,
+ 0, 0, 0, 0,
+ 0, 0,
+ 0, 0, 0, NULL, NULL };
- if (sonic_debug > 2) {
- printk("Memory allocated after %d tries\n",i);
- }
+MODULE_PARM(sonic_debug, "i");
- /* XXX sonic_local has the TDA, RRA, RDA, don't cache */
- kernel_set_cachemode((u32)lp, 8192, IOMAP_NOCACHE_SER);
- memset(lp, 0, sizeof(struct sonic_local));
+EXPORT_NO_SYMBOLS;
- lp->cda_laddr = (u32)lp;
- if (sonic_debug > 2) {
- printk("memory allocated for sonic at 0x%x\n",lp);
- }
- lp->tda_laddr = lp->cda_laddr + sizeof(lp->cda);
- lp->rra_laddr = lp->tda_laddr + sizeof(lp->tda);
- lp->rda_laddr = lp->rra_laddr + sizeof(lp->rra);
-
- /* allocate receive buffer area */
- /* FIXME, maybe we should use skbs */
- if ((lp->rba = (char *) kmalloc(SONIC_NUM_RRS * SONIC_RBSIZE, GFP_KERNEL)) == NULL)
- {
- printk("%s: couldn't allocate receive buffers\n", dev->name);
- return -ENOMEM;
- }
- /* XXX RBA written by Sonic, not cached either */
- kernel_set_cachemode((u32)lp->rba, 6*8192, IOMAP_NOCACHE_SER);
- lp->rba_laddr = (u32)lp->rba;
- flush_cache_all();
- dev->priv = (struct sonic_local *) lp;
- }
- lp = (struct sonic_local *) dev->priv;
- dev->open = sonic_open;
- dev->stop = sonic_close;
- dev->hard_start_xmit = sonic_send_packet;
- dev->get_stats = sonic_get_stats;
- dev->set_multicast_list = &sonic_multicast_list;
+int
+init_module(void)
+{
+ dev_macsonic.name = namespace;
+ dev_macsonic.init = macsonic_probe;
- /* Fill in the fields of the device structure with ethernet values. */
- ether_setup(dev);
+ if (register_netdev(&dev_macsonic) != 0) {
+ printk(KERN_WARNING "macsonic.c: No card found\n");
+ return -ENXIO;
+ }
return 0;
}
-/*
- * SONIC uses a nubus IRQ
- */
+void
+cleanup_module(void)
+{
+ if (dev_macsonic.priv != NULL) {
+ unregister_netdev(&dev_macsonic);
+ kfree(dev_macsonic.priv);
+ dev_macsonic.priv = NULL;
+ }
+}
+#endif /* MODULE */
-#define sonic_request_irq(irq, vec, flags, name, dev) \
- nubus_request_irq(irq, dev, vec)
-#define sonic_free_irq(irq,id) nubus_free_irq(irq)
-/*
- * No funnies on memory mapping.
- */
+#define vdma_alloc(foo, bar) ((u32)foo)
+#define vdma_free(baz)
+#define sonic_chiptomem(bat) (bat)
+#define PHYSADDR(quux) (quux)
-#define sonic_chiptomem(x) (x)
+#include "sonic.c"
/*
- * No VDMA on a Macintosh. So we need request no such facility.
+ * Local variables:
+ * compile-command: "m68k-linux-gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -ffixed-a2 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -c -o macsonic.o macsonic.c"
+ * version-control: t
+ * kept-new-versions: 5
+ * c-indent-level: 8
+ * tab-width: 8
+ * End:
+ *
*/
-
-#define vdma_alloc(x,y) ((u32)(x))
-#define vdma_free(x)
-#define PHYSADDR(x) (x)
-
-#include "sonic.c"
diff --git a/drivers/net/sun3lance.c b/drivers/net/sun3lance.c
index 4fff08b7f..006e36f4b 100644
--- a/drivers/net/sun3lance.c
+++ b/drivers/net/sun3lance.c
@@ -21,7 +21,7 @@
*/
-static char *version = "sun3lance.c: v1.0 12/12/96 Sam Creasey (sammy@users.qual.net)\n";
+static char *version = "sun3lance.c: v1.1 11/17/1999 Sam Creasey (sammy@oh.verio.com)\n";
#include <linux/module.h>
@@ -263,6 +263,8 @@ static int __init lance_probe( struct net_device *dev)
int i;
static int did_version = 0;
int found = 0;
+ volatile unsigned short *ioaddr_probe;
+ unsigned short tmp1, tmp2;
/* LANCE_OBIO can be found within the IO pmeg with some effort */
for(ioaddr = 0xfe00000; ioaddr < (0xfe00000 +
@@ -282,6 +284,23 @@ static int __init lance_probe( struct net_device *dev)
if(!found)
return 0;
+ /* test to see if there's really a lance here */
+ /* (CSRO_INIT shouldn't be readable) */
+
+ ioaddr_probe = (volatile unsigned short *)ioaddr;
+ tmp1 = ioaddr_probe[0];
+ tmp2 = ioaddr_probe[1];
+
+ ioaddr_probe[1] = CSR0;
+ ioaddr_probe[0] = CSR0_INIT | CSR0_STOP;
+
+ if(ioaddr_probe[0] != CSR0_STOP) {
+ ioaddr_probe[0] = tmp1;
+ ioaddr_probe[1] = tmp2;
+
+ return 0;
+ }
+
init_etherdev( dev, sizeof(struct lance_private) );
if (!dev->priv)
dev->priv = kmalloc( sizeof(struct lance_private), GFP_KERNEL );
diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c
index 10e466a5d..b86c8fdb6 100644
--- a/drivers/net/sunbmac.c
+++ b/drivers/net/sunbmac.c
@@ -1,4 +1,4 @@
-/* $Id: sunbmac.c,v 1.12 1999/12/15 14:07:58 davem Exp $
+/* $Id: sunbmac.c,v 1.13 2000/01/28 13:42:29 jj Exp $
* sunbmac.c: Driver for Sparc BigMAC 100baseT ethernet adapters.
*
* Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com)
diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c
index eb76a9fee..65d8315d9 100644
--- a/drivers/net/sunhme.c
+++ b/drivers/net/sunhme.c
@@ -1,4 +1,4 @@
-/* $Id: sunhme.c,v 1.84 1999/12/15 14:08:03 davem Exp $
+/* $Id: sunhme.c,v 1.85 2000/01/28 13:42:27 jj Exp $
* sunhme.c: Sparc HME/BigMac 10/100baseT half/full duplex auto switching,
* auto carrier detecting ethernet driver. Also known as the
* "Happy Meal Ethernet" found on SunSwift SBUS cards.
diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c
index 3c499ba38..45b671ae7 100644
--- a/drivers/net/sunlance.c
+++ b/drivers/net/sunlance.c
@@ -1,4 +1,4 @@
-/* $Id: sunlance.c,v 1.92 1999/12/15 14:08:09 davem Exp $
+/* $Id: sunlance.c,v 1.93 2000/01/28 13:42:31 jj Exp $
* lance.c: Linux/Sparc/Lance driver
*
* Written 1995, 1996 by Miguel de Icaza
diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c
index 2a170a0a6..53e0c756f 100644
--- a/drivers/net/sunqe.c
+++ b/drivers/net/sunqe.c
@@ -1,4 +1,4 @@
-/* $Id: sunqe.c,v 1.40 1999/12/15 14:08:13 davem Exp $
+/* $Id: sunqe.c,v 1.41 2000/01/28 13:42:30 jj Exp $
* sunqe.c: Sparc QuadEthernet 10baseT SBUS card driver.
* Once again I am out to prove that every ethernet
* controller out there can be most efficiently programmed
diff --git a/drivers/sbus/audio/cs4231.c b/drivers/sbus/audio/cs4231.c
index 442c25206..82e0fc494 100644
--- a/drivers/sbus/audio/cs4231.c
+++ b/drivers/sbus/audio/cs4231.c
@@ -1,4 +1,4 @@
-/* $Id: cs4231.c,v 1.41 1999/12/19 23:28:03 davem Exp $
+/* $Id: cs4231.c,v 1.42 2000/01/28 13:42:48 jj Exp $
* drivers/sbus/audio/cs4231.c
*
* Copyright 1996, 1997, 1998, 1999 Derrick J Brashear (shadow@andrew.cmu.edu)
diff --git a/drivers/sbus/audio/dbri.c b/drivers/sbus/audio/dbri.c
index 0b73b8e0d..a3f083ead 100644
--- a/drivers/sbus/audio/dbri.c
+++ b/drivers/sbus/audio/dbri.c
@@ -1,4 +1,4 @@
-/* $Id: dbri.c,v 1.17 2000/01/20 07:57:47 anton Exp $
+/* $Id: dbri.c,v 1.18 2000/01/28 13:42:50 jj Exp $
* drivers/sbus/audio/dbri.c
*
* Copyright (C) 1997 Rudolf Koenig (rfkoenig@immd4.informatik.uni-erlangen.de)
diff --git a/drivers/sbus/char/zs.c b/drivers/sbus/char/zs.c
index d0ec266c0..77f031cce 100644
--- a/drivers/sbus/char/zs.c
+++ b/drivers/sbus/char/zs.c
@@ -1,4 +1,4 @@
-/* $Id: zs.c,v 1.52 1999/12/15 14:29:20 davem Exp $
+/* $Id: zs.c,v 1.53 2000/01/29 01:29:38 anton Exp $
* zs.c: Zilog serial port driver for the Sparc.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -1928,7 +1928,7 @@ int zs_open(struct tty_struct *tty, struct file * filp)
static void show_serial_version(void)
{
- char *revision = "$Revision: 1.52 $";
+ char *revision = "$Revision: 1.53 $";
char *version, *p;
version = strchr(revision, ' ');
@@ -2076,11 +2076,6 @@ static struct sun_zslayout * __init get_zs(int chip)
static int irq = 0;
int chipid = chip;
-#if CONFIG_AP1000
- printk("No zs chip\n");
- return NULL;
-#endif
-
iospace = 0;
if(chip < 0 || chip >= NUM_SERIAL)
panic("get_zs bogon zs chip number");
@@ -2407,11 +2402,6 @@ int __init zs_init(void)
struct sun_serial *info;
char dummy;
-#if CONFIG_AP1000
- printk("not doing zs_init()\n");
- return 0;
-#endif
-
/* Setup base handler, and timer table. */
init_bh(SERIAL_BH, do_serial_bh);
timer_table[RS_TIMER].fn = zs_timer;
diff --git a/drivers/scsi/esp.c b/drivers/scsi/esp.c
index fd315c1f7..61ce25c36 100644
--- a/drivers/scsi/esp.c
+++ b/drivers/scsi/esp.c
@@ -1,4 +1,4 @@
-/* $Id: esp.c,v 1.89 1999/12/23 01:46:14 davem Exp $
+/* $Id: esp.c,v 1.90 2000/01/28 13:42:56 jj Exp $
* esp.c: EnhancedScsiProcessor Sun SCSI driver code.
*
* Copyright (C) 1995, 1998 David S. Miller (davem@caip.rutgers.edu)
diff --git a/drivers/scsi/scsi_merge.c b/drivers/scsi/scsi_merge.c
index 290d33d6c..119634641 100644
--- a/drivers/scsi/scsi_merge.c
+++ b/drivers/scsi/scsi_merge.c
@@ -87,7 +87,7 @@ static int dump_stats(struct request *req,
* Dump the information that we have. We know we have an
* inconsistency.
*/
- printk("nr_segments is %lx\n", req->nr_segments);
+ printk("nr_segments is %x\n", req->nr_segments);
printk("counted segments is %x\n", segments);
printk("Flags %d %d\n", use_clustering, dma_host);
for (bh = req->bh; bh->b_reqnext != NULL; bh = bh->b_reqnext)
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 0790a1978..ccbacf127 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -373,6 +373,7 @@ static int sd_init_command(Scsi_Cmnd * SCpnt)
static int sd_open(struct inode *inode, struct file *filp)
{
int target;
+ Scsi_Device * SDev;
target = DEVICE_NR(inode->i_rdev);
SCSI_LOG_HLQUEUE(1, printk("target=%d, max=%d\n", target, sd_template.dev_max));
@@ -412,13 +413,14 @@ static int sd_open(struct inode *inode, struct file *filp)
if ((rscsi_disks[target].write_prot) && (filp->f_mode & 2))
return -EROFS;
}
+ SDev = rscsi_disks[target].device;
/*
* It is possible that the disk changing stuff resulted in the device
* being taken offline. If this is the case, report this to the user,
* and don't pretend that
* the open actually succeeded.
*/
- if (!rscsi_disks[target].device->online) {
+ if (!SDev->online) {
return -ENXIO;
}
/*
@@ -428,13 +430,14 @@ static int sd_open(struct inode *inode, struct file *filp)
if (sd_sizes[SD_PARTITION(inode->i_rdev)] == 0)
return -ENXIO;
- if (rscsi_disks[target].device->removable)
- if (!rscsi_disks[target].device->access_count)
- sd_ioctl(inode, NULL, SCSI_IOCTL_DOORLOCK, 0);
+ if (SDev->removable)
+ if (!SDev->access_count)
+ if (scsi_block_when_processing_errors(SDev))
+ scsi_ioctl(SDev, SCSI_IOCTL_DOORLOCK, NULL);
- rscsi_disks[target].device->access_count++;
- if (rscsi_disks[target].device->host->hostt->module)
- __MOD_INC_USE_COUNT(rscsi_disks[target].device->host->hostt->module);
+ SDev->access_count++;
+ if (SDev->host->hostt->module)
+ __MOD_INC_USE_COUNT(SDev->host->hostt->module);
if (sd_template.module)
__MOD_INC_USE_COUNT(sd_template.module);
return 0;
@@ -443,17 +446,20 @@ static int sd_open(struct inode *inode, struct file *filp)
static int sd_release(struct inode *inode, struct file *file)
{
int target;
+ Scsi_Device * SDev;
target = DEVICE_NR(inode->i_rdev);
+ SDev = rscsi_disks[target].device;
- rscsi_disks[target].device->access_count--;
+ SDev->access_count--;
- if (rscsi_disks[target].device->removable) {
- if (!rscsi_disks[target].device->access_count)
- sd_ioctl(inode, NULL, SCSI_IOCTL_DOORUNLOCK, 0);
+ if (SDev->removable) {
+ if (!SDev->access_count)
+ if (scsi_block_when_processing_errors(SDev))
+ scsi_ioctl(SDev, SCSI_IOCTL_DOORUNLOCK, NULL);
}
- if (rscsi_disks[target].device->host->hostt->module)
- __MOD_DEC_USE_COUNT(rscsi_disks[target].device->host->hostt->module);
+ if (SDev->host->hostt->module)
+ __MOD_DEC_USE_COUNT(SDev->host->hostt->module);
if (sd_template.module)
__MOD_DEC_USE_COUNT(sd_template.module);
return 0;
@@ -580,17 +586,17 @@ static int check_scsidisk_media_change(kdev_t full_dev)
{
int retval;
int target;
- struct inode inode;
int flag = 0;
+ Scsi_Device * SDev;
target = DEVICE_NR(full_dev);
+ SDev = rscsi_disks[target].device;
- if (target >= sd_template.dev_max ||
- !rscsi_disks[target].device) {
+ if (target >= sd_template.dev_max || !SDev) {
printk("SCSI disk request error: invalid device.\n");
return 0;
}
- if (!rscsi_disks[target].device->removable)
+ if (!SDev->removable)
return 0;
/*
@@ -599,13 +605,12 @@ static int check_scsidisk_media_change(kdev_t full_dev)
* can deal with it then. It is only because of unrecoverable errors
* that we would ever take a device offline in the first place.
*/
- if (rscsi_disks[target].device->online == FALSE) {
+ if (SDev->online == FALSE) {
rscsi_disks[target].ready = 0;
- rscsi_disks[target].device->changed = 1;
+ SDev->changed = 1;
return 1; /* This will force a flush, if called from
* check_disk_change */
}
- inode.i_rdev = full_dev; /* This is all we really need here */
/* Using Start/Stop enables differentiation between drive with
* no cartridge loaded - NOT READY, drive with changed cartridge -
@@ -613,7 +618,9 @@ static int check_scsidisk_media_change(kdev_t full_dev)
* This also handles drives that auto spin down. eg iomega jaz 1GB
* as this will spin up the drive.
*/
- retval = sd_ioctl(&inode, NULL, SCSI_IOCTL_START_UNIT, 0);
+ retval = -ENODEV;
+ if (scsi_block_when_processing_errors(SDev))
+ retval = scsi_ioctl(SDev, SCSI_IOCTL_START_UNIT, NULL);
if (retval) { /* Unable to test, unit probably not ready.
* This usually means there is no disc in the
@@ -622,7 +629,7 @@ static int check_scsidisk_media_change(kdev_t full_dev)
* again. */
rscsi_disks[target].ready = 0;
- rscsi_disks[target].device->changed = 1;
+ SDev->changed = 1;
return 1; /* This will force a flush, if called from
* check_disk_change */
}
@@ -634,9 +641,9 @@ static int check_scsidisk_media_change(kdev_t full_dev)
rscsi_disks[target].ready = 1; /* FLOPTICAL */
- retval = rscsi_disks[target].device->changed;
+ retval = SDev->changed;
if (!flag)
- rscsi_disks[target].device->changed = 0;
+ SDev->changed = 0;
return retval;
}
diff --git a/drivers/sound/Config.in b/drivers/sound/Config.in
index 4859685c6..c218ca69d 100644
--- a/drivers/sound/Config.in
+++ b/drivers/sound/Config.in
@@ -26,7 +26,7 @@ if [ "$CONFIG_VISWS" = "y" ]; then
dep_tristate ' SGI Visual Workstation Sound' CONFIG_SOUND_VWSND $CONFIG_SOUND
fi
-dep_tristate ' Trident 4DWave-DX/NX' CONFIG_SOUND_TRIDENT $CONFIG_SOUND
+dep_tristate ' Trident 4DWave DX/NX or SiS 7018 PCI Audio Core' CONFIG_SOUND_TRIDENT $CONFIG_SOUND
dep_tristate ' Support for Turtle Beach MultiSound Classic, Tahiti, Monterey' CONFIG_SOUND_MSNDCLAS $CONFIG_SOUND
if [ "$CONFIG_SOUND_MSNDCLAS" = "y" -o "$CONFIG_SOUND_MSNDCLAS" = "m" ]; then
diff --git a/drivers/sound/Makefile b/drivers/sound/Makefile
index 50ba920b9..17f404531 100644
--- a/drivers/sound/Makefile
+++ b/drivers/sound/Makefile
@@ -25,7 +25,7 @@ endif
export-objs := ad1848.o audio_syms.o midi_syms.o mpu401.o \
msnd.o opl3.o sb_card.o sequencer_syms.o \
sound_core.o sound_syms.o uart401.o ad1816.o \
- nm256_audio.o ac97.o
+ nm256_audio.o ac97.o ac97_codec.o
@@ -84,7 +84,7 @@ obj-$(CONFIG_SOUND_ES1370) += es1370.o
obj-$(CONFIG_SOUND_ES1371) += es1371.o
obj-$(CONFIG_SOUND_ESSSOLO1) += esssolo1.o
obj-$(CONFIG_SOUND_MAESTRO) += maestro.o
-obj-$(CONFIG_SOUND_TRIDENT) += trident.o
+obj-$(CONFIG_SOUND_TRIDENT) += trident.o ac97_codec.o
# Declare multi-part drivers.
diff --git a/drivers/sound/ac97_codec.c b/drivers/sound/ac97_codec.c
new file mode 100644
index 000000000..a1177c6df
--- /dev/null
+++ b/drivers/sound/ac97_codec.c
@@ -0,0 +1,440 @@
+/*
+ * ac97_codec.c: Generic AC97 mixer module
+ *
+ * Derived from ac97 mixer in maestro and trident driver.
+ *
+ * Copyright 2000 Silicon Integrated System Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * History
+ * Jan 14 2000 Ollie Lho <ollie@sis.com.tw>
+ * Isloated from trident.c to support multiple ac97 codec
+ */
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+
+#include "ac97_codec.h"
+
+static int ac97_read_mixer(struct ac97_codec *codec, int oss_channel);
+static void ac97_write_mixer(struct ac97_codec *codec, int oss_channel,
+ unsigned int left, unsigned int right);
+static void ac97_set_mixer(struct ac97_codec *codec, unsigned int oss_mixer, unsigned int val );
+static int ac97_recmask_io(struct ac97_codec *codec, int rw, int mask);
+static int ac97_mixer_ioctl(struct ac97_codec *codec, unsigned int cmd, unsigned long arg);
+
+static struct {
+ unsigned int id;
+ char *name;
+ int (*init) (struct ac97_codec *codec);
+} snd_ac97_codec_ids[] = {
+ {0x414B4D00, "Asahi Kasei AK4540" , NULL},
+ {0x41445340, "Analog Devices AD1881" , NULL},
+ {0x43525900, "Cirrus Logic CS4297" , NULL},
+ {0x43525913, "Cirrus Logic CS4297A" , NULL},
+ {0x43525931, "Cirrus Logic CS4299" , NULL},
+ {0x4e534331, "National Semiconductor LM4549", NULL},
+ {0x83847600, "SigmaTel STAC????" , NULL},
+ {0x83847604, "SigmaTel STAC9701/3/4/5", NULL},
+ {0x83847605, "SigmaTel STAC9704" , NULL},
+ {0x83847608, "SigmaTel STAC9708" , NULL},
+ {0x83847609, "SigmaTel STAC9721/23" , NULL},
+ {0x00000000, NULL, NULL}
+};
+
+
+/* this table has default mixer values for all OSS mixers. */
+static struct mixer_defaults {
+ int mixer;
+ unsigned int value;
+} mixer_defaults[SOUND_MIXER_NRDEVICES] = {
+ /* all values 0 -> 100 in bytes */
+ {SOUND_MIXER_VOLUME, 0x3232},
+ {SOUND_MIXER_BASS, 0x3232},
+ {SOUND_MIXER_TREBLE, 0x3232},
+ {SOUND_MIXER_PCM, 0x3232},
+ {SOUND_MIXER_SPEAKER, 0x3232},
+ {SOUND_MIXER_LINE, 0x3232},
+ {SOUND_MIXER_MIC, 0x3232},
+ {SOUND_MIXER_CD, 0x3232},
+ {SOUND_MIXER_ALTPCM, 0x3232},
+ {SOUND_MIXER_IGAIN, 0x3232},
+ {SOUND_MIXER_LINE1, 0x3232},
+ {SOUND_MIXER_PHONEIN, 0x3232},
+ {SOUND_MIXER_PHONEOUT, 0x3232},
+ {SOUND_MIXER_VIDEO, 0x3232},
+ {-1,0}
+};
+
+/* table to scale scale from OSS mixer value to AC97 mixer register value */
+static struct ac97_mixer_hw {
+ unsigned char offset;
+ int scale;
+} ac97_hw[SOUND_MIXER_NRDEVICES]= {
+ [SOUND_MIXER_VOLUME] = {AC97_MASTER_VOL_STEREO,63},
+ [SOUND_MIXER_BASS] = {AC97_MASTER_TONE, 15},
+ [SOUND_MIXER_TREBLE] = {AC97_MASTER_TONE, 15},
+ [SOUND_MIXER_PCM] = {AC97_PCMOUT_VOL, 31},
+ [SOUND_MIXER_SPEAKER] = {AC97_PCBEEP_VOL, 15},
+ [SOUND_MIXER_LINE] = {AC97_LINEIN_VOL, 31},
+ [SOUND_MIXER_MIC] = {AC97_MIC_VOL, 31},
+ [SOUND_MIXER_CD] = {AC97_CD_VOL, 31},
+ [SOUND_MIXER_ALTPCM] = {AC97_HEADPHONE_VOL, 63},
+ [SOUND_MIXER_IGAIN] = {AC97_RECORD_GAIN, 31},
+ [SOUND_MIXER_LINE1] = {AC97_AUX_VOL, 31},
+ [SOUND_MIXER_PHONEIN] = {AC97_PHONE_VOL, 15},
+ [SOUND_MIXER_PHONEOUT] = {AC97_MASTER_VOL_MONO, 63},
+ [SOUND_MIXER_VIDEO] = {AC97_VIDEO_VOL, 31},
+};
+
+/* the following tables allow us to go from OSS <-> ac97 quickly. */
+enum ac97_recsettings {
+ AC97_REC_MIC=0,
+ AC97_REC_CD,
+ AC97_REC_VIDEO,
+ AC97_REC_AUX,
+ AC97_REC_LINE,
+ AC97_REC_STEREO, /* combination of all enabled outputs.. */
+ AC97_REC_MONO, /*.. or the mono equivalent */
+ AC97_REC_PHONE
+};
+
+static unsigned int ac97_rm2oss[] = {
+ [AC97_REC_MIC] = SOUND_MIXER_MIC,
+ [AC97_REC_CD] = SOUND_MIXER_CD,
+ [AC97_REC_VIDEO] = SOUND_MIXER_VIDEO,
+ [AC97_REC_AUX] = SOUND_MIXER_LINE1,
+ [AC97_REC_LINE] = SOUND_MIXER_LINE,
+ [AC97_REC_PHONE] = SOUND_MIXER_PHONEIN
+};
+
+/* indexed by bit position */
+static unsigned int ac97_oss_rm[] = {
+ [SOUND_MIXER_MIC] = AC97_REC_MIC,
+ [SOUND_MIXER_CD] = AC97_REC_CD,
+ [SOUND_MIXER_VIDEO] = AC97_REC_VIDEO,
+ [SOUND_MIXER_LINE1] = AC97_REC_AUX,
+ [SOUND_MIXER_LINE] = AC97_REC_LINE,
+ [SOUND_MIXER_PHONEIN] = AC97_REC_PHONE
+};
+
+/* reads the given OSS mixer from the ac97 the caller must have insured that the ac97 knows
+ about that given mixer, and should be holding a spinlock for the card */
+static int ac97_read_mixer(struct ac97_codec *codec, int oss_channel)
+{
+ u16 val;
+ int ret = 0;
+ struct ac97_mixer_hw *mh = &ac97_hw[oss_channel];
+
+ val = codec->codec_read(codec , mh->offset);
+
+ if (AC97_STEREO_MASK & (1 << oss_channel)) {
+ /* nice stereo mixers .. */
+ int left,right;
+
+ left = (val >> 8) & 0x7f;
+ right = val & 0x7f;
+
+ if (oss_channel == SOUND_MIXER_IGAIN) {
+ right = (right * 100) / mh->scale;
+ left = (left * 100) / mh->scale;
+ } else {
+ right = 100 - ((right * 100) / mh->scale);
+ left = 100 - ((left * 100) / mh->scale);
+ }
+
+ ret = left | (right << 8);
+ } else if (oss_channel == SOUND_MIXER_SPEAKER) {
+ ret = 100 - ((((val & 0x1e)>>1) * 100) / mh->scale);
+ } else if (oss_channel == SOUND_MIXER_MIC) {
+ ret = 100 - (((val & 0x1f) * 100) / mh->scale);
+ /* the low bit is optional in the tone sliders and masking
+ it lets us avoid the 0xf 'bypass'.. */
+ } else if (oss_channel == SOUND_MIXER_BASS) {
+ ret = 100 - ((((val >> 8) & 0xe) * 100) / mh->scale);
+ } else if (oss_channel == SOUND_MIXER_TREBLE) {
+ ret = 100 - (((val & 0xe) * 100) / mh->scale);
+ }
+
+#ifdef DEBUG
+ printk("ac97_codec: read OSS mixer %2d (ac97 register 0x%02x), "
+ "0x%04x -> 0x%04x\n", oss_channel, mh->offset, val, ret);
+#endif
+
+ return ret;
+}
+
+/* write the OSS encoded volume to the given OSS encoded mixer, again caller's job to
+ make sure all is well in arg land, call with spinlock held */
+static void ac97_write_mixer(struct ac97_codec *codec, int oss_channel,
+ unsigned int left, unsigned int right)
+{
+ u16 val = 0;
+ struct ac97_mixer_hw *mh = &ac97_hw[oss_channel];
+
+#ifdef DEBUG
+ printk("ac97_codec: wrote OSS mixer %2d (%s ac97 register 0x%02x), "
+ "left vol:%2d, right vol:%2d:",
+ oss_channel, codec->id ? "Secondary" : "Primary",
+ mh->offset, left, right);
+#endif
+
+ if (AC97_STEREO_MASK & (1 << oss_channel)) {
+ /* stereo mixers */
+ if (oss_channel == SOUND_MIXER_IGAIN) {
+ right = (right * mh->scale) / 100;
+ left = (left * mh->scale) / 100;
+ } else {
+ right = ((100 - right) * mh->scale) / 100;
+ left = ((100 - left) * mh->scale) / 100;
+ }
+ val = (left << 8) | right;
+ } else if (oss_channel == SOUND_MIXER_SPEAKER) {
+ val = (((100 - left) * mh->scale) / 100) << 1;
+ } else if (oss_channel == SOUND_MIXER_MIC) {
+ val = codec->codec_read(codec , mh->offset) & ~0x801f;
+ val |= (((100 - left) * mh->scale) / 100);
+ /* the low bit is optional in the tone sliders and masking
+ it lets us avoid the 0xf 'bypass'.. */
+ } else if (oss_channel == SOUND_MIXER_BASS) {
+ val = codec->codec_read(codec , mh->offset) & ~0x0f00;
+ val |= ((((100 - left) * mh->scale) / 100) << 8) & 0x0e00;
+ } else if (oss_channel == SOUND_MIXER_TREBLE) {
+ val = codec->codec_read(codec , mh->offset) & ~0x000f;
+ val |= (((100 - left) * mh->scale) / 100) & 0x000e;
+ }
+
+#ifdef DEBUG
+ printk(" 0x%04x", val);
+#endif
+ codec->codec_write(codec, mh->offset, val);
+
+#ifdef DEBUG
+ val = codec->codec_read(codec, mh->offset);
+ printk(" -> 0x%04x\n", val);
+#endif
+}
+
+/* a thin wrapper for write_mixer */
+static void ac97_set_mixer(struct ac97_codec *codec, unsigned int oss_mixer, unsigned int val )
+{
+ unsigned int left,right;
+
+ /* cleanse input a little */
+ right = ((val >> 8) & 0xff) ;
+ left = (val & 0xff) ;
+
+ if (right > 100) right = 100;
+ if (left > 100) left = 100;
+
+ codec->mixer_state[oss_mixer] = (right << 8) | left;
+ codec->write_mixer(codec, oss_mixer, left, right);
+}
+
+/* read or write the recmask, the ac97 can really have left and right recording
+ inputs independantly set, but OSS doesn't seem to want us to express that to
+ the user. the caller guarantees that we have a supported bit set, and they
+ must be holding the card's spinlock */
+static int ac97_recmask_io(struct ac97_codec *codec, int rw, int mask)
+{
+ unsigned int val;
+
+ if (rw) {
+ /* read it from the card */
+ val = codec->codec_read(codec, 0x1a) & 0x7;
+ return ac97_rm2oss[val];
+ }
+
+ /* else, write the first set in the mask as the
+ output */
+
+ val = ffs(mask);
+ val = ac97_oss_rm[val-1];
+ val |= val << 8; /* set both channels */
+
+#ifdef DEBUG
+ printk("ac97_codec: setting ac97 recmask to 0x%x\n", val);
+#endif
+
+ codec->codec_write(codec, 0x1a, val);
+
+ return 0;
+};
+
+static int ac97_mixer_ioctl(struct ac97_codec *codec, unsigned int cmd, unsigned long arg)
+{
+ int i, val = 0;
+
+ if (cmd == SOUND_MIXER_INFO) {
+ mixer_info info;
+ strncpy(info.id, codec->name, sizeof(info.id));
+ strncpy(info.name, codec->name, sizeof(info.name));
+ info.modify_counter = codec->modcnt;
+ if (copy_to_user((void *)arg, &info, sizeof(info)))
+ return -EFAULT;
+ return 0;
+ }
+ if (cmd == SOUND_OLD_MIXER_INFO) {
+ _old_mixer_info info;
+ strncpy(info.id, codec->name, sizeof(info.id));
+ strncpy(info.name, codec->name, sizeof(info.name));
+ if (copy_to_user((void *)arg, &info, sizeof(info)))
+ return -EFAULT;
+ return 0;
+ }
+
+ if (_IOC_TYPE(cmd) != 'M' || _IOC_SIZE(cmd) != sizeof(int))
+ return -EINVAL;
+
+ if (cmd == OSS_GETVERSION)
+ return put_user(SOUND_VERSION, (int *)arg);
+
+ if (_IOC_DIR(cmd) == _IOC_READ) {
+ switch (_IOC_NR(cmd)) {
+ case SOUND_MIXER_RECSRC: /* give them the current record source */
+ if (!codec->recmask_io) {
+ val = 0;
+ } else {
+ val = codec->recmask_io(codec, 1, 0);
+ }
+ break;
+
+ case SOUND_MIXER_DEVMASK: /* give them the supported mixers */
+ val = codec->supported_mixers;
+ break;
+
+ case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */
+ val = codec->record_sources;
+ break;
+
+ case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */
+ val = codec->stereo_mixers;
+ break;
+
+ case SOUND_MIXER_CAPS:
+ val = SOUND_CAP_EXCL_INPUT;
+ break;
+
+ default: /* read a specific mixer */
+ i = _IOC_NR(cmd);
+
+ if (!supported_mixer(codec, i))
+ return -EINVAL;
+
+ /* do we ever want to touch the hardware? */
+ /* val = codec->read_mixer(card,i); */
+ val = codec->mixer_state[i];
+ break;
+ }
+ return put_user(val,(int *)arg);
+ }
+
+ if (_IOC_DIR(cmd) == (_IOC_WRITE|_IOC_READ)) {
+ codec->modcnt++;
+ get_user_ret(val, (int *)arg, -EFAULT);
+
+ switch (_IOC_NR(cmd)) {
+ case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
+ if (!codec->recmask_io) return -EINVAL;
+ if (!(val &= codec->record_sources)) return -EINVAL;
+
+ codec->recmask_io(codec, 0, val);
+
+ return 0;
+ default: /* write a specific mixer */
+ i = _IOC_NR(cmd);
+
+ if (!supported_mixer(codec, i))
+ return -EINVAL;
+
+ ac97_set_mixer(codec, i, val);
+
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+
+int ac97_probe_codec(struct ac97_codec *codec)
+{
+ u16 id1, id2, cap;
+ int i;
+
+ /* probing AC97 codec, AC97 2.0 says that bit 15 of register 0x00 (reset) should
+ be read zero. Probing of AC97 in this way is not reliable, it is not even SAFE !! */
+ codec->codec_write(codec, AC97_RESET, 0L);
+ if ((cap = codec->codec_read(codec, AC97_RESET)) & 0x8000)
+ return 0;
+
+ id1 = codec->codec_read(codec, AC97_VENDOR_ID1);
+ id2 = codec->codec_read(codec, AC97_VENDOR_ID2);
+ for (i = 0; i < sizeof (snd_ac97_codec_ids); i++) {
+ if (snd_ac97_codec_ids[i].id == ((id1 << 16) | id2)) {
+ codec->name = snd_ac97_codec_ids[i].name;
+ codec->codec_init = snd_ac97_codec_ids[i].init;
+ break;
+ }
+ }
+ if (codec->name == NULL)
+ codec->name = "Unknown";
+ printk(KERN_INFO "ac97_codec: ac97 vendor id1: 0x%04x, id2: 0x%04x (%s)\n",
+ id1, id2, codec->name);
+ printk(KERN_INFO "ac97_codec: capability: 0x%04x\n", cap);
+
+ /* mixer masks */
+ codec->supported_mixers = AC97_SUPPORTED_MASK;
+ codec->stereo_mixers = AC97_STEREO_MASK;
+ codec->record_sources = AC97_RECORD_MASK;
+ if (!(cap & 0x04))
+ codec->supported_mixers &= ~(SOUND_MASK_BASS|SOUND_MASK_TREBLE);
+
+ /* generic OSS to AC97 wrapper */
+ codec->read_mixer = ac97_read_mixer;
+ codec->write_mixer = ac97_write_mixer;
+ codec->recmask_io = ac97_recmask_io;
+ codec->mixer_ioctl = ac97_mixer_ioctl;
+
+ /* initialize volume level */
+ codec->codec_write(codec, AC97_MASTER_VOL_STEREO, 0L);
+ codec->codec_write(codec, AC97_PCMOUT_VOL, 0L);
+
+ /* codec specific initialization for 4-6 channel output */
+ if (codec->id != 0 && codec->codec_init != NULL) {
+ codec->codec_init(codec);
+ }
+
+ /* initilize mixer channel volumes */
+ for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
+ struct mixer_defaults *md = &mixer_defaults[i];
+ if (md->mixer == -1)
+ break;
+ if (!supported_mixer(codec, md->mixer))
+ continue;
+ ac97_set_mixer(codec, md->mixer, md->value);
+ }
+
+ return 1;
+}
+
+static int sigmatel_init(struct ac97_codec * codec)
+{
+ codec->codec_write(codec, AC97_SURROUND_MASTER, 0L);
+ /* initialize SigmaTel STAC9721/23 */
+ codec->codec_write(codec, 0x74, 0x01);
+ return 1;
+}
+
+EXPORT_SYMBOL(ac97_probe_codec);
diff --git a/drivers/sound/ac97_codec.h b/drivers/sound/ac97_codec.h
new file mode 100644
index 000000000..36d2b052a
--- /dev/null
+++ b/drivers/sound/ac97_codec.h
@@ -0,0 +1,157 @@
+#ifndef _AC97_CODEC_H_
+#define _AC97_CODEC_H_
+
+#include "sound_config.h"
+#include "sound_calls.h"
+
+/* AC97 1.0 */
+#define AC97_RESET 0x0000 //
+#define AC97_MASTER_VOL_STEREO 0x0002 // Line Out
+#define AC97_HEADPHONE_VOL 0x0004 //
+#define AC97_MASTER_VOL_MONO 0x0006 // TAD Output
+#define AC97_MASTER_TONE 0x0008 //
+#define AC97_PCBEEP_VOL 0x000a // none
+#define AC97_PHONE_VOL 0x000c // TAD Input (mono)
+#define AC97_MIC_VOL 0x000e // MIC Input (mono)
+#define AC97_LINEIN_VOL 0x0010 // Line Input (stereo)
+#define AC97_CD_VOL 0x0012 // CD Input (stereo)
+#define AC97_VIDEO_VOL 0x0014 // none
+#define AC97_AUX_VOL 0x0016 // Aux Input (stereo)
+#define AC97_PCMOUT_VOL 0x0018 // Wave Output (stereo)
+#define AC97_RECORD_SELECT 0x001a //
+#define AC97_RECORD_GAIN 0x001c
+#define AC97_RECORD_GAIN_MIC 0x001e
+#define AC97_GENERAL_PURPOSE 0x0020
+#define AC97_3D_CONTROL 0x0022
+#define AC97_MODEM_RATE 0x0024
+#define AC97_POWER_CONTROL 0x0026
+
+/* AC'97 2.0 */
+#define AC97_EXTENDED_ID 0x0028 /* Extended Audio ID */
+#define AC97_EXTENDED_STATUS 0x002A /* Extended Audio Status */
+#define AC97_PCM_FRONT_DAC_RATE 0x002C /* PCM Front DAC Rate */
+#define AC97_PCM_SURR_DAC_RATE 0x002E /* PCM Surround DAC Rate */
+#define AC97_PCM_LFE_DAC_RATE 0x0030 /* PCM LFE DAC Rate */
+#define AC97_PCM_LR_DAC_RATE 0x0032 /* PCM LR DAC Rate */
+#define AC97_PCM_MIC_ADC_RATE 0x0034 /* PCM MIC ADC Rate */
+#define AC97_CENTER_LFE_MASTER 0x0036 /* Center + LFE Master Volume */
+#define AC97_SURROUND_MASTER 0x0038 /* Surround (Rear) Master Volume */
+#define AC97_RESERVED_3A 0x003A /* Reserved */
+
+/* range 0x3c-0x58 - MODEM */
+
+/* registers 0x005a - 0x007a are vendor reserved */
+
+#define AC97_VENDOR_ID1 0x007c
+#define AC97_VENDOR_ID2 0x007e
+
+/* volume control bit defines */
+#define AC97_MUTE 0x8000
+#define AC97_MICBOOST 0x0040
+#define AC97_LEFTVOL 0x3f00
+#define AC97_RIGHTVOL 0x003f
+
+/* record mux defines */
+#define AC97_RECMUX_MIC 0x0000
+#define AC97_RECMUX_CD 0x0101
+#define AC97_RECMUX_VIDEO 0x0202 /* not used */
+#define AC97_RECMUX_AUX 0x0303
+#define AC97_RECMUX_LINE 0x0404
+#define AC97_RECMUX_STEREO_MIX 0x0505
+#define AC97_RECMUX_MONO_MIX 0x0606
+#define AC97_RECMUX_PHONE 0x0707
+
+
+/* general purpose register bit defines */
+#define AC97_GP_LPBK 0x0080 /* Loopback mode */
+#define AC97_GP_MS 0x0100 /* Mic Select 0=Mic1, 1=Mic2 */
+#define AC97_GP_MIX 0x0200 /* Mono output select 0=Mix, 1=Mic */
+#define AC97_GP_RLBK 0x0400 /* Remote Loopback - Modem line codec */
+#define AC97_GP_LLBK 0x0800 /* Local Loopback - Modem Line codec */
+#define AC97_GP_LD 0x1000 /* Loudness 1=on */
+#define AC97_GP_3D 0x2000 /* 3D Enhancement 1=on */
+#define AC97_GP_ST 0x4000 /* Stereo Enhancement 1=on */
+#define AC97_GP_POP 0x8000 /* Pcm Out Path, 0=pre 3D, 1=post 3D */
+
+
+/* powerdown control and status bit defines */
+
+/* status */
+#define AC97_PWR_MDM 0x0010 /* Modem section ready */
+#define AC97_PWR_REF 0x0008 /* Vref nominal */
+#define AC97_PWR_ANL 0x0004 /* Analog section ready */
+#define AC97_PWR_DAC 0x0002 /* DAC section ready */
+#define AC97_PWR_ADC 0x0001 /* ADC section ready */
+
+/* control */
+#define AC97_PWR_PR0 0x0100 /* ADC and Mux powerdown */
+#define AC97_PWR_PR1 0x0200 /* DAC powerdown */
+#define AC97_PWR_PR2 0x0400 /* Output mixer powerdown (Vref on) */
+#define AC97_PWR_PR3 0x0800 /* Output mixer powerdown (Vref off) */
+#define AC97_PWR_PR4 0x1000 /* AC-link powerdown */
+#define AC97_PWR_PR5 0x2000 /* Internal Clk disable */
+#define AC97_PWR_PR6 0x4000 /* HP amp powerdown */
+#define AC97_PWR_PR7 0x8000 /* Modem off - if supported */
+
+/* useful power states */
+#define AC97_PWR_D0 0x0000 /* everything on */
+#define AC97_PWR_D1 AC97_PWR_PR0|AC97_PWR_PR1|AC97_PWR_PR4
+#define AC97_PWR_D2 AC97_PWR_PR0|AC97_PWR_PR1|AC97_PWR_PR2|AC97_PWR_PR3|AC97_PWR_PR4
+#define AC97_PWR_D3 AC97_PWR_PR0|AC97_PWR_PR1|AC97_PWR_PR2|AC97_PWR_PR3|AC97_PWR_PR4
+#define AC97_PWR_ANLOFF AC97_PWR_PR2|AC97_PWR_PR3 /* analog section off */
+
+/* Total number of defined registers. */
+#define AC97_REG_CNT 64
+
+
+/* OSS interface to the ac97s.. */
+#define AC97_STEREO_MASK (SOUND_MASK_VOLUME|SOUND_MASK_PCM|\
+ SOUND_MASK_LINE|SOUND_MASK_CD|\
+ SOUND_MIXER_ALTPCM|SOUND_MASK_IGAIN|\
+ SOUND_MASK_LINE1|SOUND_MASK_VIDEO)
+
+#define AC97_SUPPORTED_MASK (AC97_STEREO_MASK | \
+ SOUND_MASK_BASS|SOUND_MASK_TREBLE|\
+ SOUND_MASK_SPEAKER|SOUND_MASK_MIC|\
+ SOUND_MIXER_PHONEIN|SOUND_MIXER_PHONEOUT)
+
+#define AC97_RECORD_MASK (SOUND_MASK_MIC|\
+ SOUND_MASK_CD| SOUND_MASK_VIDEO| SOUND_MASK_LINE1| SOUND_MASK_LINE|\
+ SOUND_MASK_PHONEIN)
+
+#define supported_mixer(CODEC,FOO) ( CODEC->supported_mixers & (1<<FOO) )
+
+struct ac97_codec {
+ /* AC97 controller connected with */
+ void *private_data;
+
+ char *name;
+ int id;
+ int dev_mixer;
+
+ /* codec specific init/reset routines, used mainly for 4 or 6 channel support */
+ int (*codec_init) (struct ac97_codec *codec);
+
+ /* controller specific lower leverl ac97 accessing routines */
+ u16 (*codec_read) (struct ac97_codec *codec, u8 reg);
+ void (*codec_write) (struct ac97_codec *codec, u8 reg, u16 val);
+
+ /* OSS mixer masks */
+ int modcnt;
+ int supported_mixers;
+ int stereo_mixers;
+ int record_sources;
+
+ /* OSS mixer interface */
+ int (*read_mixer) (struct ac97_codec *codec, int oss_channel);
+ void (*write_mixer)(struct ac97_codec *codec, int oss_channel,
+ unsigned int left, unsigned int right);
+ int (*recmask_io) (struct ac97_codec *codec, int rw, int mask);
+ int (*mixer_ioctl)(struct ac97_codec *codec, unsigned int cmd, unsigned long arg);
+
+ /* saved OSS mixer states */
+ unsigned int mixer_state[SOUND_MIXER_NRDEVICES];
+};
+
+extern int ac97_probe_codec(struct ac97_codec *);
+#endif
diff --git a/drivers/sound/trident.c b/drivers/sound/trident.c
index c8c0cd0c3..2f808c92c 100644
--- a/drivers/sound/trident.c
+++ b/drivers/sound/trident.c
@@ -29,16 +29,36 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* History
+ * v0.11 Jan 27 2000 Ollie Lho
+ * DMA bug, scheduler latency, second try
+ * v0.10 Jan 24 2000 Ollie Lho
+ * DMA bug fixed, found kernel scheduling problem
+ * v0.09 Jan 20 2000 Ollie Lho
+ * Clean up of channel register access routine (prepare for channel binding)
+ * v0.08 Jan 14 2000 Ollie Lho
+ * Isolation of AC97 codec code
+ * v0.07 Jan 13 2000 Ollie Lho
+ * Get rid of ugly old low level access routines (e.g. CHRegs.lp****)
+ * v0.06 Jan 11 2000 Ollie Lho
+ * Preliminary support for dual (more ?) AC97 codecs
* v0.05 Jan 08 2000 Luca Montecchiani <m.luca@iname.com>
- * adapt to 2.3.x new __setup/__initcall
+ * adapt to 2.3.x new __setup/__init call
* v0.04 Dec 31 1999 Ollie Lho
- * Multiple Open, useing Middle Loop Interrupt to smooth playback
+ * Multiple Open, using Middle Loop Interrupt to smooth playback
* v0.03 Dec 24 1999 Ollie Lho
* mem leak in prog_dmabuf and dealloc_dmabuf removed
* v0.02 Dec 15 1999 Ollie Lho
* SiS 7018 support added, playback O.K.
* v0.01 Alan Cox et. al.
* Initial Release in kernel 2.3.30, does not work
+ *
+ * ToDo
+ * Clean up of low level channel register access code. (done)
+ * Fix the bug on dma buffer management in update_ptr, read/write, drain_dac (done)
+ * Dual AC97 codecs support (done partially, need channel binding to test)
+ * Recording support
+ * Mmap support
+ * "Channel Binding" ioctl extension
*/
#include <linux/config.h>
@@ -66,34 +86,40 @@
#endif
#include "trident.h"
-#include "ac97.h"
+#include "ac97_codec.h"
#undef DEBUG
-#define DRIVER_VERSION "0.05"
-
-#define TRIDENT_FMT_STEREO 0x01
-#define TRIDENT_FMT_16BIT 0x02
-#define TRIDENT_FMT_MASK 0x03
-#define TRIDENT_DAC_SHIFT 0
-#define TRIDENT_ADC_SHIFT 4
-
-#define TRIDENT_ENABLE_PE 1
-#define TRIDENT_ENABLE_RE 2
-#define DAC_RUNNING 1
-#define ADC_RUNNING 2
+#define DRIVER_VERSION "0.11"
+/* magic numbers to protect our data structures */
#define TRIDENT_CARD_MAGIC 0x5072696E /* "Prin" */
#define TRIDENT_STATE_MAGIC 0x63657373 /* "cess" */
-/* number of instances of opening /dev/dsp, can your CPU handle this ? */
-#define NR_DSPS 32
+/* The first 32 channels are called Bank A. They are (should be) reserved
+ for MIDI synthesizer. But since that is not supported yet, we can (ab)use
+ them to play PCM samples */
+#undef ABUSE_BANK_A
+
+/* maxinum number of instances of opening /dev/dspN, can your CPU handle this ?
+ NOTE: If /dev/dsp is opened O_RDWR (i.e. full duplex) it will consume 2 HW
+ channels */
+#ifdef ABUSE_BANK_A
+#define NR_HW_CH 64
+#else
+#define NR_HW_CH 32
+#endif
+
+/* maxinum nuber of AC97 codecs connected, AC97 2.0 defined 4, but 7018 and 4D-NX only
+ have 2 SDATA_IN lines (currently) */
+#define NR_AC97 2
+/* minor number of /dev/dspW */
#define SND_DEV_DSP16 5
static const unsigned sample_size[] = { 1, 2, 2, 4 };
static const unsigned sample_shift[] = { 0, 1, 1, 2 };
-static const char *sample_format[] = {"8 bits Mono", "8 bits Stereo", "16 bits Mono", "16 bits Stereo"};
+
static const char invalid_magic[] = KERN_CRIT "trident: invalid magic value in %s\n";
struct pci_audio_info {
@@ -108,52 +134,12 @@ static struct pci_audio_info pci_audio_devices[] = {
{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_7018, "SiS 7018 PCI Audio"}
};
-static struct {
- unsigned int id;
- char *name;
-} snd_ac97_codec_ids[] = {
- {0x414B4D00, "Asahi Kasei AK4540" },
- {0x41445340, "Analog Devices AD1881" },
- {0x43525900, "Cirrus Logic CS4297" },
- {0x43525913, "Cirrus Logic CS4297A" },
- {0x43525931, "Cirrus Logic CS4299" },
- {0x4e534331, "National Semiconductor LM4549"},
- {0x83847600, "SigmaTel STAC????" },
- {0x83847604, "SigmaTel STAC9701/3/4/5"},
- {0x83847605, "SigmaTel STAC9704" },
- {0x83847608, "SigmaTel STAC9708" },
- {0x83847609, "SigmaTel STAC9721/23" },
- {0x00000000, NULL}
-};
-
-typedef struct tChannelControl
-{
- // register data
- unsigned int * lpChStart;
- unsigned int * lpChStop;
- unsigned int * lpChAint;
- unsigned int * lpChAinten;
-
- // register addresses
- unsigned int * lpAChStart;
- unsigned int * lpAChStop;
- unsigned int * lpAChAint;
- unsigned int * lpAChAinten;
-
- unsigned int data[16];
-
-} CHANNELCONTROL;
-
/* "software" or virtual channel, an instance of opened /dev/dsp */
struct trident_state {
unsigned int magic;
struct trident_card *card; /* Card info */
- /* wave stuff */
- unsigned int rateadc, ratedac;
- unsigned char fmt, enable;
-
- /* single opne lock mechanism, should be removed */
+ /* single open lock mechanism, only used for recording */
struct semaphore open_sem;
wait_queue_head_t open_wait;
@@ -164,26 +150,33 @@ struct trident_state {
int virt;
struct dmabuf {
+ /* wave sample stuff */
+ unsigned int rate;
+ unsigned char fmt, enable;
+
+ /* hardware channel */
+ struct trident_channel *channel;
+
+ /* OSS buffer manangemeent stuff */
void *rawbuf;
unsigned buforder;
unsigned numfrag;
unsigned fragshift;
- /* hardware channel number */
- int chan;
+ /* our buffer acts like a circular ring */
+ unsigned hwptr; /* where dma last started, update by update_ptr */
+ unsigned swptr; /* where driver last clear/filled, updated by read/write */
+ int count; /* bytes to be comsumed by dma machine */
+ unsigned total_bytes; /* total bytes dmaed by hardware */
- /* XXX zab - swptr only in here so that it can be referenced by
- clear_advance, as far as I can tell :( */
- unsigned hwptr, swptr;
- unsigned total_bytes;
- int count;
- unsigned error; /* over/underrun */
- wait_queue_head_t wait;
+ unsigned error; /* number of over/underruns */
+ wait_queue_head_t wait; /* put process on wait queue when no more space in buffer */
/* redundant, but makes calculations easier */
unsigned fragsize;
unsigned dmasize;
unsigned fragsamples;
+
/* OSS stuff */
unsigned mapped:1;
unsigned ready:1;
@@ -192,44 +185,45 @@ struct trident_state {
int ossmaxfrags;
unsigned subdivision;
} dma_dac, dma_adc;
-
- u8 bDMAStart;
-
};
/* hardware channels */
struct trident_channel {
- int chan; /* channel number */
- u32 lba;
- u32 eso;
+ int num; /* channel number */
+ u32 lba; /* reg 0xe4 */
+ u32 eso; /* reg 0xe8 */
u32 delta;
- u16 attribute;
-
+ u16 attribute; /* reg 0xec */
+ u16 fm_vol;
+ u32 control; /* reg 0xf0 */
};
-struct trident_pcm_bank {
- /* registers to control bank operations */
+struct trident_pcm_bank_address {
u32 start;
u32 stop;
u32 aint;
u32 aint_en;
+};
+static struct trident_pcm_bank_address bank_a_addrs =
+{
+ T4D_START_A,
+ T4D_STOP_A,
+ T4D_AINT_A,
+ T4D_AINTEN_A
+};
+static struct trident_pcm_bank_address bank_b_addrs =
+{
+ T4D_START_B,
+ T4D_STOP_B,
+ T4D_AINT_B,
+ T4D_AINTEN_B
+};
+struct trident_pcm_bank {
+ /* register addresses to control bank operations */
+ struct trident_pcm_bank_address *addresses;
/* each bank has 32 channels */
u32 bitmap; /* channel allocation bitmap */
- //struct trident_channel channels[32];
-};
-
-struct trident_mixer {
- int modcnt;
- int supported_mixers;
- int stereo_mixers;
- int record_sources;
-
- /* the caller must guarantee arg sanity before calling these */
- /* int (*read_mixer)(struct trident_card *card, int index);*/
- void (*write_mixer)(struct trident_card *card,int mixer, unsigned int left,
- unsigned int right);
- int (*recmask_io)(struct trident_card *card,int rw,int mask);
- unsigned int mixer_state[SOUND_MIXER_NRDEVICES];
+ struct trident_channel channels[32];
};
struct trident_card {
@@ -239,7 +233,7 @@ struct trident_card {
struct trident_card *next;
/* The trident has a certain amount of cross channel interaction
- so we use a single per card lock */
+ so we use a single per card lock */
spinlock_t lock;
/* PCI device stuff */
@@ -249,286 +243,225 @@ struct trident_card {
/* soundcore stuff */
int dev_audio;
- int dev_mixer;
- struct trident_mixer mix;
- struct trident_state *channels[NR_DSPS];
+ /* structures for abstraction of hardware facilities, codecs, banks and channels*/
+ struct ac97_codec *ac97_codec[NR_AC97];
+ struct trident_pcm_bank banks[NR_BANKS];
+ struct trident_state *states[NR_HW_CH];
/* hardware resources */
unsigned long iobase;
u32 irq;
-
- /* hardware channel allocation bitmap */
- u32 bitmap[2];
-
- /* ugly stupid thing, remove ASAP */
- CHANNELCONTROL ChRegs;
- int ChanDwordCount;
};
static struct trident_card *devs = NULL;
-/*
- * Trident support library routines
- */
-
-/*---------------------------------------------------------------------------
- void ResetAinten( struct trident_state *trident, int ChannelNum)
-
- Description: This routine will disable interrupts and ack any
- existing interrupts for specified channel.
-
- Parameters: trident - pointer to target device class for 4DWave.
- ChannelNum - channel number
-
- returns: TRUE if everything went ok, else FALSE.
-
- ---------------------------------------------------------------------------*/
-
-static void ResetAinten(struct trident_card * trident, int ChannelNum)
-{
- unsigned int dwMask;
- unsigned int x = ChannelNum >> 5;
- unsigned int ChanDwordCount = trident->ChanDwordCount;
-
- IReadAinten(&trident->ChRegs);
- dwMask = 1 << (ChannelNum & 0x1f);
- trident->ChRegs.lpChAinten[x] &= ~dwMask;
- IWriteAinten(&trident->ChRegs);
- // Ack the channel in case the interrupt was set before we disable it.
- outl(dwMask, TRID_REG(trident, trident->ChRegs.lpAChAint[x]));
-}
+static void trident_ac97_set(struct ac97_codec *codec, u8 reg, u16 val);
+static u16 trident_ac97_get(struct ac97_codec *codec, u8 reg);
-/*---------------------------------------------------------------------------
- void EnableEndInterrupts( struct trident_card *trident)
-
- Description: This routine will enable end of loop interrupts.
- End of loop interrupts will occur when a running
- channel reaches ESO.
-
- Parameters: trident - pointer to target device class for 4DWave.
-
- returns: TRUE if everything went ok, else FALSE.
-
- ---------------------------------------------------------------------------*/
-
-static int trident_enable_end_interrupts(struct trident_card * trident)
+static int trident_open_mixdev(struct inode *inode, struct file *file);
+static int trident_release_mixdev(struct inode *inode, struct file *file);
+static int trident_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd,
+ unsigned long arg);
+static loff_t trident_llseek(struct file *file, loff_t offset, int origin);
+
+static int trident_enable_loop_interrupts(struct trident_card * card)
{
u32 global_control;
- global_control = inl(TRID_REG(trident, T4D_LFO_GC_CIR));
+ global_control = inl(TRID_REG(card, T4D_LFO_GC_CIR));
- switch (trident->pci_id)
+ switch (card->pci_id)
{
case PCI_DEVICE_ID_SI_7018:
- global_control |= (ENDLP_IE | BANK_B_EN);
+ global_control |= (ENDLP_IE | MIDLP_IE| BANK_B_EN);
break;
case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
- global_control |= ENDLP_IE;
+ global_control |= (ENDLP_IE | MIDLP_IE);
break;
default:
return FALSE;
}
- outl(global_control, TRID_REG(trident, T4D_LFO_GC_CIR));
+ outl(global_control, TRID_REG(card, T4D_LFO_GC_CIR));
#ifdef DEBUG
- printk("trident: Enable End Interrupts, globctl = 0x%08X\n", global_control);
+ printk("trident: Enable Loop Interrupts, globctl = 0x%08X\n",
+ global_control);
#endif
return (TRUE);
}
-static int trident_enable_middle_interrupts(struct trident_card * trident)
+static int trident_disable_loop_interrupts(struct trident_card * card)
{
u32 global_control;
- global_control = inl(TRID_REG(trident, T4D_LFO_GC_CIR));
-
- switch (trident->pci_id)
- {
- case PCI_DEVICE_ID_SI_7018:
- global_control |= (MIDLP_IE | BANK_B_EN);
- break;
- case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
- case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
- default:
- global_control |= MIDLP_IE;
- break;
- }
-
- outl(global_control, TRID_REG(trident, T4D_LFO_GC_CIR));
+ global_control = inl(TRID_REG(card, T4D_LFO_GC_CIR));
+ global_control &= ~(ENDLP_IE | MIDLP_IE);
+ outl(global_control, TRID_REG(card, T4D_LFO_GC_CIR));
#ifdef DEBUG
- printk("trident: Enable Middle Interrupts, globctl = 0x%08X\n", global_control);
+ printk("trident: Disabled Loop Interrupts, globctl = 0x%08X\n",
+ global_control);
#endif
return (TRUE);
}
-/*---------------------------------------------------------------------------
- void DisableEndInterrupts( struct trident_card *trident)
-
- Description: This routine will disable end of loop interrupts.
- End of loop interrupts will occur when a running
- channel reaches ESO.
-
- Parameters:
- trident - pointer to target device class for 4DWave.
-
- returns: TRUE if everything went ok, else FALSE.
-
- ---------------------------------------------------------------------------*/
-
-static int trident_disable_end_interrupts(struct trident_card * trident)
+
+static void trident_enable_voice_irq(struct trident_card * card, unsigned int channel)
{
- u32 global_control;
+ unsigned int mask = 1 << (channel & 0x1f);
+ struct trident_pcm_bank *bank = &card->banks[channel >> 5];
+ u32 reg, addr = bank->addresses->aint_en;
- global_control = inl(TRID_REG(trident, T4D_LFO_GC_CIR));
- global_control &= ~ENDLP_IE;
- outl(global_control, TRID_REG(trident, T4D_LFO_GC_CIR));
+ reg = inl(TRID_REG(card, addr));
+ reg |= mask;
+ outl(reg, TRID_REG(card, addr));
#ifdef DEBUG
- printk("trident: Disabled End Interrupts, globctl = 0x%08X\n", global_control);
+ reg = inl(TRID_REG(card, T4D_AINTEN_B));
+ printk("trident: enabled IRQ on channel %d, AINTEN_B = 0x%08x\n",
+ channel, reg);
#endif
- return (TRUE);
}
-static int trident_disable_middle_interrupts(struct trident_card * trident)
+static void trident_disable_voice_irq(struct trident_card * card, unsigned int channel)
{
- u32 global_control;
-
- global_control = inl(TRID_REG(trident, T4D_LFO_GC_CIR));
- global_control &= ~MIDLP_IE;
- outl(global_control, TRID_REG(trident, T4D_LFO_GC_CIR));
+ unsigned int mask = 1 << (channel & 0x1f);
+ struct trident_pcm_bank *bank = &card->banks[channel >> 5];
+ u32 reg, addr = bank->addresses->aint_en;
+
+ reg = inl(TRID_REG(card, addr));
+ reg &= ~mask;
+ outl(reg, TRID_REG(card, addr));
+
+ /* Ack the channel in case the interrupt was set before we disable it. */
+ outl(mask, TRID_REG(card, bank->addresses->aint));
#ifdef DEBUG
- printk("trident: Disabled Middle Interrupts, globctl = 0x%08X\n", global_control);
+ reg = inl(TRID_REG(card, T4D_AINTEN_B));
+ printk("trident: disabled IRQ on channel %d, AINTEN_B = 0x%08x\n",
+ channel, reg);
#endif
- return (TRUE);
}
-/*---------------------------------------------------------------------------
- void trident_enable_voice_irq( unsigned int HwChannel )
-
- Description: Enable an interrupt channel, any channel 0 thru n.
- This routine automatically handles the fact that there are
- more than 32 channels available.
-
- Parameters : HwChannel - Channel number 0 thru n.
- trident - pointer to target device class for 4DWave.
-
- Return Value: None.
-
- ---------------------------------------------------------------------------*/
-void trident_enable_voice_irq(struct trident_card * trident, unsigned int channel)
+
+static void trident_start_voice(struct trident_card * card, unsigned int channel)
{
- unsigned int bank, mask, ChanDwordCount;
+ unsigned int mask = 1 << (channel & 0x1f);
+ struct trident_pcm_bank *bank = &card->banks[channel >> 5];
+ u32 addr = bank->addresses->start;
+
+#ifdef DEBUG
u32 reg;
+#endif
- bank = channel >> 5;
- mask = 1 << (channel & 0x1f);
+ outl(mask, TRID_REG(card, addr));
- ChanDwordCount = trident->ChanDwordCount;
+#ifdef DEBUG
+ reg = inl(TRID_REG(card, T4D_START_B));
+ printk("trident: start voice on channel %d, START_B = 0x%08x\n",
+ channel, reg);
+#endif
+}
- IReadAinten(&trident->ChRegs);
- trident->ChRegs.lpChAinten[bank] |= mask;
- IWriteAinten(&trident->ChRegs);
+static void trident_stop_voice(struct trident_card * card, unsigned int channel)
+{
+ unsigned int mask = 1 << (channel & 0x1f);
+ struct trident_pcm_bank *bank = &card->banks[channel >> 5];
+ u32 addr = bank->addresses->stop;
#ifdef DEBUG
- reg = inl(TRID_REG(trident, T4D_AINTEN_B));
- printk("trident: enabled IRQ on channel %d\n", channel);
+ u32 reg;
+#endif
+
+ outl(mask, TRID_REG(card, addr));
+
+#ifdef DEBUG
+ reg = inl(TRID_REG(card, T4D_STOP_B));
+ printk("trident: stop voice on channel %d, STOP_B = 0x%08x\n",
+ channel, reg);
#endif
}
-/*---------------------------------------------------------------------------
- void trident_disable_voice_irq( unsigned int HwChannel )
-
- Description: Disable an interrupt channel, any channel 0 thru n.
- This routine automatically handles the fact that there are
- more than 32 channels available.
-
- Parameters : HwChannel - Channel number 0 thru n.
- trident - pointer to target device class for 4DWave.
-
- Return Value: None.
-
- ---------------------------------------------------------------------------*/
-void trident_disable_voice_irq(struct trident_card * trident, unsigned int channel)
+static int trident_check_channel_interrupt(struct trident_card * card, int channel)
{
- unsigned int bank, mask, ChanDwordCount;
- u32 reg;
+ unsigned int mask = 1 << (channel & 0x1f);
+ struct trident_pcm_bank *bank = &card->banks[channel >> 5];
+ u32 reg, addr = bank->addresses->aint;
- bank = channel >> 5;
- mask = 1 << (channel & 0x1f);
+ reg = inl(TRID_REG(card, addr));
+
+#ifdef DEBUG
+ if (reg & mask)
+ printk("trident: channel %d has interrupt, AINT_B = 0x%08x\n",
+ channel, reg);
+#endif
+ return (reg & mask) ? TRUE : FALSE;
+}
+
+static void trident_ack_channel_interrupt(struct trident_card * card, int channel)
+{
+ unsigned int mask = 1 << (channel & 0x1f);
+ struct trident_pcm_bank *bank = &card->banks[channel >> 5];
+ u32 reg, addr = bank->addresses->aint;
- ChanDwordCount = trident->ChanDwordCount;
- IReadAinten(&trident->ChRegs);
- trident->ChRegs.lpChAinten[bank] &= ~mask;
- IWriteAinten(&trident->ChRegs);
+ reg = inl(TRID_REG(card, addr));
+ reg &= mask;
+ outl(reg, TRID_REG(card, addr));
#ifdef DEBUG
- reg = inl(TRID_REG(trident, T4D_AINTEN_B));
- printk("trident: disabled IRQ on channel %d\n", channel);
+ reg = inl(TRID_REG(card, T4D_AINT_B));
+ printk("trident: Ack channel %d interrupt, AINT_B = 0x%08x\n",
+ channel, reg);
#endif
}
-/*---------------------------------------------------------------------------
- unsigned int AllocateChannelPCM( void )
-
- Description: Allocate hardware channel by reverse order (63-0).
-
- Parameters : trident - pointer to target device class for 4DWave.
-
- Return Value: hardware channel - 0-63 or -1 when no channel is available
-
- ---------------------------------------------------------------------------*/
-
-static int trident_alloc_pcm_channel(struct trident_card *trident)
+static struct trident_channel * trident_alloc_pcm_channel(struct trident_card *card)
{
+ struct trident_pcm_bank *bank;
int idx;
- if (trident->bitmap[BANK_B] == ~0UL) {
+ bank = &card->banks[BANK_B];
+ if (bank->bitmap == ~0UL) {
/* no more free channels avaliable */
printk(KERN_ERR "trident: no more channels available on Bank B.\n");
- return -1;
+#ifdef ABUSE_BANK_A
+ goto bank_a;
+#endif
+ return NULL;
}
for (idx = 31; idx >= 0; idx--) {
- if (!(trident->bitmap[BANK_B] & (1 << idx))) {
- trident->bitmap[BANK_B] |= 1 << idx;
- return idx + 32;
+ if (!(bank->bitmap & (1 << idx))) {
+ struct trident_channel *channel = &bank->channels[idx];
+ bank->bitmap |= 1 << idx;
+ channel->num = idx + 32;
+ return channel;
}
}
#ifdef ABUSE_BANK_A
/* channels in Bank A should be reserved for synthesizer
not for normal use (channels in Bank A can't record) */
- if (trident->bitmap[BANK_A] == ~0UL) {
+ bank_a:
+ bank = &card->banks[BANK_A];
+ if (bank->bitmap == ~0UL) {
/* no more free channels avaliable */
- printk(KERN_ERR "trident: no channels available on Bank A.\n");
- return -1;
+ printk(KERN_ERR "trident: no more channels available on Bank A.\n");
+ return NULL;
}
for (idx = 31; idx >= 0; idx--) {
- if (!(trident->bitmap[BANK_A] & (1 << idx))) {
- trident->bitmap[BANK_A] |= 1 << idx;
- return idx;
+ if (!(bank->bitmap & (1 << idx))) {
+ struct trident_channel *channel = &bank->channels[idx];
+ banks->bitmap |= 1 << idx;
+ channel->num = idx;
+ return channels;
}
}
#endif
-
- return -1;
+ return NULL;
}
-/*---------------------------------------------------------------------------
- void FreeChannelPCM( int channel )
-
- Description: Free hardware channel.
-
- Parameters : trident - pointer to target device class for 4DWave.
- channel - hardware channel number 0-63
-
- Return Value: none
-
- ---------------------------------------------------------------------------*/
-
-static void trident_free_pcm_channel(struct trident_card *trident, int channel)
+static void trident_free_pcm_channel(struct trident_card *card, int channel)
{
int bank;
@@ -543,236 +476,74 @@ static void trident_free_pcm_channel(struct trident_card *trident, int channel)
bank = channel >> 5;
channel = channel & 0x1f;
- if (trident->bitmap[bank] & (1 << (channel))) {
- trident->bitmap[bank] &= ~(1 << (channel));
+ if (card->banks[bank].bitmap & (1 << (channel))) {
+ card->banks[bank].bitmap &= ~(1 << (channel));
}
}
-/*---------------------------------------------------------------------------
- void trident_start_voice( ULONG HwChannel )
-
- Description: Start a channel, any channel 0 thru n.
- This routine automatically handles the fact that there are
- more than 32 channels available.
-
- Parameters : HwChannel - Channel number 0 thru n.
- trident - pointer to target device class for 4DWave.
-
- Return Value: None.
-
- ---------------------------------------------------------------------------*/
-void trident_start_voice(struct trident_card * trident, unsigned int channel)
-{
- unsigned int bank = channel >> 5;
- unsigned int mask = 1 << (channel & 0x1f);
-
- outl(mask, TRID_REG(trident, trident->ChRegs.lpAChStart[bank]));
-#ifdef DEBUG
- printk("trident: start voice on channel %d\n", channel);
-#endif
-}
-
-/*---------------------------------------------------------------------------
- void trident_stop_voice( ULONG HwChannel )
-
- Description: Stop a channel, any channel 0 thru n.
- This routine automatically handles the fact that there are
- more than 32 channels available.
-
- Parameters : HwChannel - Channel number 0 thru n.
- trident - pointer to target device class for 4DWave.
-
- Return Value: None.
-
- ---------------------------------------------------------------------------*/
-void trident_stop_voice(struct trident_card * trident, unsigned int channel)
+/* called with spin lock held */
+static int trident_load_channel_registers(struct trident_card *card, u32 *data, unsigned int channel)
{
- unsigned int bank = channel >> 5;
- unsigned int mask = 1 << (channel & 0x1f);
-
- outl(mask, TRID_REG(trident, trident->ChRegs.lpAChStop[bank]));
-#ifdef DEBUG
- printk("trident: stop voice on channel %d\n", channel);
-#endif
-}
-
-/*---------------------------------------------------------------------------
- int DidChannelInterrupt( )
-
- Description: Check if interrupt channel occurred.
-
- Parameters : trident - pointer to target device class for 4DWave.
-
- Return Value: TRUE if interrupt occurred, else FALSE.
-
- ---------------------------------------------------------------------------*/
-static int trident_check_channel_interrupt(struct trident_card * trident, int channel)
-{
- unsigned int ChanDwordCount = NUM_BANKS;
- unsigned int bank = channel >> 5;
- unsigned int mask = 1 << (channel & 0x1f);
-
- ReadAint(&trident->ChRegs);
-
-#ifdef DEBUG
- if (trident->ChRegs.lpChAint[bank] & mask)
- printk("trident: channel %d has interrupt\n", channel);
-#endif
- return (trident->ChRegs.lpChAint[bank] & mask) ? TRUE : FALSE;
-}
-
-/*---------------------------------------------------------------------------
- void AckChannelInterrupt( )
-
- Description: Acknowledge the interrupt bit for channel intrs.
-
- Parameters : trident - pointer to target device class for 4DWave.
-
- Return Value: None
-
- ---------------------------------------------------------------------------*/
-static void trident_ack_channel_interrupt(struct trident_card * trident, int channel)
-{
- unsigned int ChanDwordCount = NUM_BANKS;
- unsigned int bank = channel >> 5;
- unsigned int mask = 1 << (channel & 0x1f);
-
- ReadAint(&trident->ChRegs);
- trident->ChRegs.lpChAint[bank] &= mask;
- IWriteAint(&trident->ChRegs);
-}
-
-/*---------------------------------------------------------------------------
- int trident_load_hw_delta( unsigned int HwChannel, unsigned int Delta )
-
- Description: This routine writes Delta to the hardware.
-
- Parameters: Delta - data to write (2 Bytes only)
- HwChannel - Hardware channel to write to.
- trident - pointer to target device class for 4DWave.
-
- Returns: TRUE if all goes well, else FALSE.
-
- ---------------------------------------------------------------------------*/
-static int trident_load_hw_delta (struct trident_card * trident, unsigned int channel,
- unsigned short delta)
-{
- /* select a channel for output */
- outb(channel, TRID_REG(trident, T4D_LFO_GC_CIR));
+ int i;
- switch (trident->pci_id)
- {
- case PCI_DEVICE_ID_SI_7018:
- case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
- outw((u16) delta, TRID_REG(trident, CH_DX_ESO_DELTA));
- break;
- case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
- outb(delta & 0xff, TRID_REG(trident, CH_NX_DELTA_CSO + 3));
- outb((delta >> 8)& 0xff, TRID_REG(trident, CH_NX_DELTA_ESO + 3));
- break;
- default:
+ if (channel > 63)
return FALSE;
- }
- return TRUE;
-}
-/*---------------------------------------------------------------------------
- int LoadVirtualChannel( ULONG *Data, ULONG HwChannel)
-
- Description: This routine writes all required channel registers to hardware.
-
- Parameters: *Data - a pointer to the data to write (5 ULONGS always).
- HwChannel - Hardware channel to write to.
- trident - pointer to target device class for 4DWave.
-
- Returns: TRUE if all goes well, else FALSE.
-
- ---------------------------------------------------------------------------*/
-static int LoadVirtualChannel(struct trident_card * trident, unsigned int *Data, unsigned int HwChannel)
-{
- unsigned int ChanData[CHANNEL_REGS];
- unsigned int ULONGSToDo = CHANNEL_REGS;
- unsigned int i;
- unsigned int Address = CHANNEL_START;
-
- /* Copy the data first... Hack... Before mucking with Volume! */
- memcpy((unsigned char *) ChanData, (unsigned char *) Data, ULONGSToDo * 4);
-
- outb((unsigned char) HwChannel, TRID_REG(trident, T4D_LFO_GC_CIR));
+ /* select hardware channel to write */
+ outb(channel, TRID_REG(card, T4D_LFO_GC_CIR));
+ /* output the channel registers */
+ for (i = 0; i < CHANNEL_REGS; i++) {
+ outl(data[i], TRID_REG(card, CHANNEL_START + 4*i));
+ }
- for (i = 0; i < ULONGSToDo; i++, Address += 4)
- outl(ChanData[i], TRID_REG(trident, Address));
-#ifdef DEBUG
- printk("(trident) load virtual channel %d\n", HwChannel);
-#endif
return TRUE;
}
-/*---------------------------------------------------------------------------
- trident_write_voice_regs
-
- Description: This routine will write the 5 hardware channel registers
- to hardware.
-
- Paramters: trident - pointer to target device class for 4DWave.
- Channel - Real or Virtual channel number.
- Each register field.
-
- Returns: TRUE if all goes well, else FALSE.
-
- ---------------------------------------------------------------------------*/
-int trident_write_voice_regs(struct trident_card * trident,
- unsigned int Channel,
- unsigned int LBA,
- unsigned int CSO,
- unsigned int ESO,
- unsigned int DELTA,
- unsigned int ALPHA_FMS,
- unsigned int FMC_RVOL_CVOL,
- unsigned int GVSEL,
- unsigned int PAN,
- unsigned int VOL,
- unsigned int CTRL,
- unsigned int EC)
+/* called with spin lock held */
+static int trident_write_voice_regs(struct trident_state *state, unsigned int rec)
{
- unsigned int ChanData[CHANNEL_REGS + 1], FmcRvolCvol;
+ unsigned int data[CHANNEL_REGS + 1];
+ struct trident_channel *channel;
- ChanData[1] = LBA;
- ChanData[4] = (GVSEL << 31) |
- ((PAN & 0x0000007f) << 24) |
- ((VOL & 0x000000ff) << 16) |
- ((CTRL & 0x0000000f) << 12) |
- (EC & 0x00000fff);
+ if (rec)
+ channel = state->dma_adc.channel;
+ else
+ channel = state->dma_dac.channel;
- FmcRvolCvol = FMC_RVOL_CVOL & 0x0000ffff;
+ data[1] = channel->lba;
+ data[4] = channel->control;
- switch (trident->pci_id)
+ switch (state->card->pci_id)
{
case PCI_DEVICE_ID_SI_7018:
+ data[0] = 0; /* Current Sample Offset */
+ data[2] = (channel->eso << 16) | (channel->delta & 0xffff);
+ data[3] = (channel->attribute << 16) | (channel->fm_vol & 0xffff);
+ break;
case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
- ChanData[0] = (CSO << 16) | (ALPHA_FMS & 0x0000ffff);
- ChanData[2] = (ESO << 16) | (DELTA & 0x0000ffff);
- ChanData[3] = FmcRvolCvol;
+ data[0] = 0; /* Current Sample Offset */
+ data[2] = (channel->eso << 16) | (channel->delta & 0xffff);
+ data[3] = channel->fm_vol & 0xffff;
break;
case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
- ChanData[0] = (DELTA << 24) | (CSO & 0x00ffffff);
- ChanData[2] = ((DELTA << 16) & 0xff000000) | (ESO & 0x00ffffff);
- ChanData[3] = (ALPHA_FMS << 16) | FmcRvolCvol;
+ data[0] = (channel->delta << 24);
+ data[2] = ((channel->delta << 24) & 0xff000000) | (channel->eso & 0x00ffffff);
+ data[3] = channel->fm_vol & 0xffff;
break;
+ default:
+ return FALSE;
}
- LoadVirtualChannel(trident, ChanData, Channel);
-
- return TRUE;
+ return trident_load_channel_registers(state->card, data, channel->num);
}
static int compute_rate(u32 rate)
{
int delta;
- // We special case 44100 and 8000 since rounding with the equation
- // does not give us an accurate enough value. For 11025 and 22050
- // the equation gives us the best answer. All other frequencies will
- // also use the equation. JDW
+ /* We special case 44100 and 8000 since rounding with the equation
+ does not give us an accurate enough value. For 11025 and 22050
+ the equation gives us the best answer. All other frequencies will
+ also use the equation. JDW */
if (rate == 44100)
delta = 0xeb3;
else if (rate == 8000)
@@ -784,838 +555,267 @@ static int compute_rate(u32 rate)
return delta;
}
-/*---------------------------------------------------------------------------
- trident_set_dac_rate
-
- Description: This routine will set the sample rate for playback.
-
- Paramters: trident - pointer to target device class for 4DWave.
- rate - desired sample rate
- set - actually write hardware if set is true.
-
- Returns: The rate allowed by device.
-
- ---------------------------------------------------------------------------*/
-
-static unsigned int trident_set_dac_rate(struct trident_state * trident,
- unsigned int rate, int set)
-{
- u16 delta;
+/* set playback sample rate */
+static unsigned int trident_set_dac_rate(struct trident_state * state, unsigned int rate)
+{
+ struct dmabuf *dmabuf = &state->dma_dac;
if (rate > 48000)
rate = 48000;
if (rate < 4000)
rate = 4000;
- delta = compute_rate(rate);
- trident->ratedac = rate;
+ dmabuf->rate = rate;
+ dmabuf->channel->delta = compute_rate(rate);
- if (set)
- trident_load_hw_delta(trident->card, trident->dma_dac.chan,
- delta);
-#ifdef DEBUG
- printk("trident: called trident_set_dac_rate : rate = %d, "
- "set = %d, delta = 0x%04x\n", rate, set, delta);
+ trident_write_voice_regs(state, 0);
+
+#ifdef DEBUG
+ printk("trident: called trident_set_dac_rate : rate = %d\n", rate);
#endif
return rate;
}
-/*---------------------------------------------------------------------------
- trident_set_adc_rate
-
- Description: This routine will set the sample rate for capture.
-
- Paramters: trident - pointer to target device class for 4DWave.
- rate - desired sample rate
- set - actually write hardware if set is true.
-
- Returns: The rate allowed by device.
-
- ---------------------------------------------------------------------------*/
-
-static unsigned int trident_set_adc_rate(struct trident_state * trident,
- unsigned int rate, int set)
+/* set recording sample rate */
+static unsigned int trident_set_adc_rate(struct trident_state * state, unsigned int rate)
{
- u16 delta;
-
+ struct dmabuf *dmabuf = &state->dma_adc;
if (rate > 48000)
rate = 48000;
if (rate < 4000)
rate = 4000;
- delta = compute_rate(rate);
- trident->ratedac = rate;
-
-#if 0 /* It seems that 4D-Wave can not use wave tables channels for recording */
- if (set)
- trident_load_hw_delta(trident->card, trident->dma_adc.chan,
- delta);
-#endif
-#ifdef DEBUG
- printk("trident: called trident_set_adc_rate : rate = %d, "
- "set = %d, delta = 0x%04x\n", rate, set, delta);
-#endif
- return rate;
-}
-
-extern __inline__ unsigned ld2(unsigned int x)
-{
- unsigned r = 0;
-
- if (x >= 0x10000) {
- x >>= 16;
- r += 16;
- }
- if (x >= 0x100) {
- x >>= 8;
- r += 8;
- }
- if (x >= 0x10) {
- x >>= 4;
- r += 4;
- }
- if (x >= 4) {
- x >>= 2;
- r += 2;
- }
- if (x >= 2)
- r++;
- return r;
-}
-
-/* Write AC97 mixer registers */
-static void trident_ac97_set(struct trident_card *trident, u8 cmd, u16 val)
-{
- unsigned int address, mask, busy;
- unsigned short count = 0xffff;
- u32 data;
-
- data = ((u32) val) << 16;
-
- switch (trident->pci_id)
- {
- default:
- case PCI_DEVICE_ID_SI_7018:
- address = SI_AC97_WRITE;
- mask = SI_AC97_BUSY_WRITE | SI_AC97_AUDIO_BUSY;
- busy = SI_AC97_BUSY_WRITE;
- break;
- case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
- address = DX_ACR0_AC97_W;
- mask = busy = DX_AC97_BUSY_WRITE;
- break;
- case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
- address = NX_ACR1_AC97_W;
- mask = busy = NX_AC97_BUSY_WRITE;
- break;
- }
-
- do {
- if ((inw(TRID_REG(trident, address)) & busy) == 0)
- break;
- } while (count--);
-
- data |= (mask | (cmd & AC97_REG_ADDR));
-
- if (count == 0) {
- printk(KERN_ERR "trident: AC97 CODEC write timed out.\n");
- return;
- }
- outl(data, TRID_REG(trident, address));
-}
-
-/* Read AC97 codec registers */
-static u16 trident_ac97_get(struct trident_card *trident, u8 cmd)
-{
- unsigned int address, mask, busy;
- unsigned short count = 0xffff;
- u32 data;
-
- switch (trident->pci_id)
- {
- default:
- case PCI_DEVICE_ID_SI_7018:
- address = SI_AC97_READ;
- mask = SI_AC97_BUSY_READ | SI_AC97_AUDIO_BUSY;
- busy = SI_AC97_BUSY_READ;
- break;
- case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
- address = DX_ACR1_AC97_R;
- mask = busy = DX_AC97_BUSY_READ;
- break;
- case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
- address = NX_ACR2_AC97_R_PRIMARY;
- mask = NX_AC97_BUSY_READ;
- busy = 0x0c00;
- break;
- }
+ dmabuf->rate = rate;
+ dmabuf->channel->delta = compute_rate(rate);
- data = (mask | (cmd & AC97_REG_ADDR));
- outl(data, TRID_REG(trident, address));
-
- do {
- data = inl(TRID_REG(trident, address));
- if ((data & busy) == 0)
- break;
- } while (count--);
-
- if (count == 0) {
- printk(KERN_ERR "trident: AC97 CODEC read timed out.\n");
- data = 0;
- }
- return ((u16) (data >> 16));
-}
-
-/* OSS interface to the ac97s.. */
-
-#define AC97_STEREO_MASK (SOUND_MASK_VOLUME|\
- SOUND_MASK_PCM|SOUND_MASK_LINE|SOUND_MASK_CD|\
- SOUND_MASK_VIDEO|SOUND_MASK_LINE1|SOUND_MASK_IGAIN)
-
-#define AC97_SUPPORTED_MASK (AC97_STEREO_MASK | \
- SOUND_MASK_BASS|SOUND_MASK_TREBLE|SOUND_MASK_MIC|\
- SOUND_MASK_SPEAKER)
-
-#define AC97_RECORD_MASK (SOUND_MASK_MIC|\
- SOUND_MASK_CD| SOUND_MASK_VIDEO| SOUND_MASK_LINE1| SOUND_MASK_LINE|\
- SOUND_MASK_PHONEIN)
-
-#define supported_mixer(CARD,FOO) ( CARD->mix.supported_mixers & (1<<FOO) )
-
-/* this table has default mixer values for all OSS mixers.
- be sure to fill it in if you add oss mixers
- to anyone's supported mixer defines */
-
-/* possible __init */
-static struct mixer_defaults {
- int mixer;
- unsigned int value;
-} mixer_defaults[SOUND_MIXER_NRDEVICES] = {
- /* all values 0 -> 100 in bytes */
- {SOUND_MIXER_VOLUME, 0x3232},
- {SOUND_MIXER_BASS, 0x3232},
- {SOUND_MIXER_TREBLE, 0x3232},
- {SOUND_MIXER_SPEAKER, 0x3232},
- {SOUND_MIXER_MIC, 0x3232},
- {SOUND_MIXER_LINE, 0x3232},
- {SOUND_MIXER_CD, 0x3232},
- {SOUND_MIXER_VIDEO, 0x3232},
- {SOUND_MIXER_LINE1, 0x3232},
- {SOUND_MIXER_PCM, 0x3232},
- {SOUND_MIXER_IGAIN, 0x3232},
- {-1,0}
-};
-
-static struct ac97_mixer_hw {
- unsigned char offset;
- int scale;
-} ac97_hw[SOUND_MIXER_NRDEVICES]= {
- [SOUND_MIXER_VOLUME] = {AC97_MASTER_VOL_STEREO,63},
- [SOUND_MIXER_BASS] = {AC97_MASTER_TONE, 15},
- [SOUND_MIXER_TREBLE] = {AC97_MASTER_TONE, 15},
- [SOUND_MIXER_SPEAKER] = {AC97_PCBEEP_VOL, 15},
- [SOUND_MIXER_MIC] = {AC97_MIC_VOL, 31},
- [SOUND_MIXER_LINE] = {AC97_LINEIN_VOL, 31},
- [SOUND_MIXER_CD] = {AC97_CD_VOL, 31},
- [SOUND_MIXER_VIDEO] = {AC97_VIDEO_VOL, 31},
- [SOUND_MIXER_LINE1] = {AC97_AUX_VOL, 31},
- [SOUND_MIXER_PCM] = {AC97_PCMOUT_VOL, 31},
- [SOUND_MIXER_IGAIN] = {AC97_RECORD_GAIN, 31}
-};
-
-#if 0 /* *shrug* removed simply because we never used it.
- feel free to implement again if needed */
-
-/* reads the given OSS mixer from the ac97
- the caller must have insured that the ac97 knows
- about that given mixer, and should be holding a
- spinlock for the card */
-static int ac97_read_mixer(struct trident_card *card, int mixer)
-{
- u16 val;
- int ret = 0;
- struct ac97_mixer_hw *mh = &ac97_hw[mixer];
-
- val = trident_ac97_get(card , mh->offset);
-
- if (AC97_STEREO_MASK & (1<<mixer)) {
- /* nice stereo mixers .. */
- int left,right;
-
- left = (val >> 8) & 0x7f;
- right = val & 0x7f;
-
- if (mixer == SOUND_MIXER_IGAIN) {
- right = (right * 100) / mh->scale;
- left = (left * 100) / mh->scale;
- else {
- right = 100 - ((right * 100) / mh->scale);
- left = 100 - ((left * 100) / mh->scale);
- }
-
- ret = left | (right << 8);
- } else if (mixer == SOUND_MIXER_SPEAKER) {
- ret = 100 - ((((val & 0x1e)>>1) * 100) / mh->scale);
- } else if (mixer == SOUND_MIXER_MIC) {
- ret = 100 - (((val & 0x1f) * 100) / mh->scale);
- /* the low bit is optional in the tone sliders and masking
- it lets us avoid the 0xf 'bypass'.. */
- } else if (mixer == SOUND_MIXER_BASS) {
- ret = 100 - ((((val >> 8) & 0xe) * 100) / mh->scale);
- } else if (mixer == SOUND_MIXER_TREBLE) {
- ret = 100 - (((val & 0xe) * 100) / mh->scale);
- }
+ trident_write_voice_regs(state, 1);
#ifdef DEBUG
- printk("trident: read OSS mixer %2d (ac97 register 0x%02x), "
- "0x%04x -> 0x%04x\n", mixer, mh->offset, val, ret);
+ printk("trident: called trident_set_adc_rate : rate = %d\n", rate);
#endif
-
- return ret;
+ return rate;
}
-#endif
-/* write the OSS encoded volume to the given OSS encoded mixer,
- again caller's job to make sure all is well in arg land,
- call with spinlock held */
-static void ac97_write_mixer(struct trident_card *card, int mixer,
- unsigned int left, unsigned int right)
+/* prepare channel attributes for playback */
+static void trident_play_setup(struct trident_state *state)
{
- u16 val = 0;
- struct ac97_mixer_hw *mh = &ac97_hw[mixer];
+ struct dmabuf *dmabuf = &state->dma_dac;
+ struct trident_channel *channel = dmabuf->channel;
-#ifdef DEBUG
- printk("trident: wrote OSS mixer %2d (ac97 register 0x%02x), "
- "left vol:%2d, right vol:%2d:",
- mixer, mh->offset, left, right);
-#endif
+ channel->lba = virt_to_bus(dmabuf->rawbuf);
+ channel->delta = compute_rate(dmabuf->rate);
- if (AC97_STEREO_MASK & (1 << mixer)) {
- /* stereo mixers */
- if (mixer == SOUND_MIXER_IGAIN) {
- right = (right * mh->scale) / 100;
- left = (left * mh->scale) / 100;
- } else {
- right = ((100 - right) * mh->scale) / 100;
- left = ((100 - left) * mh->scale) / 100;
- }
+ channel->eso = dmabuf->dmasize >> sample_shift[dmabuf->fmt];
+ channel->eso -= 1;
- val = (left << 8) | right;
- } else if (mixer == SOUND_MIXER_SPEAKER) {
- val = (((100 - left) * mh->scale) / 100) << 1;
- } else if (mixer == SOUND_MIXER_MIC) {
- val = trident_ac97_get(card , mh->offset) & ~0x801f;
- val |= (((100 - left) * mh->scale) / 100);
- /* the low bit is optional in the tone sliders and masking
- it lets us avoid the 0xf 'bypass'.. */
- } else if (mixer == SOUND_MIXER_BASS) {
- val = trident_ac97_get(card , mh->offset) & ~0x0f00;
- val |= ((((100 - left) * mh->scale) / 100) << 8) & 0x0e00;
- } else if (mixer == SOUND_MIXER_TREBLE) {
- val = trident_ac97_get(card , mh->offset) & ~0x000f;
- val |= (((100 - left) * mh->scale) / 100) & 0x000e;
+ if (state->card->pci_id == PCI_DEVICE_ID_SI_7018) {
+ /* FIXME: channel attributes are configured by ioctls, but it is not implemented
+ so just set to ZERO for the moment */
+ channel->attribute = 0;
+ } else {
+ channel->attribute = 0;
}
-#ifdef DEBUG
- printk(" 0x%04x", val);
-#endif
- trident_ac97_set(card, mh->offset, val);
-
-#ifdef DEBUG
- val = trident_ac97_get(card, mh->offset);
- printk(" -> 0x%04x\n", val);
-#endif
-}
-
-/* the following tables allow us to go from
- OSS <-> ac97 quickly. */
-
-enum ac97_recsettings {
- AC97_REC_MIC=0,
- AC97_REC_CD,
- AC97_REC_VIDEO,
- AC97_REC_AUX,
- AC97_REC_LINE,
- AC97_REC_STEREO, /* combination of all enabled outputs.. */
- AC97_REC_MONO, /*.. or the mono equivalent */
- AC97_REC_PHONE
-};
-
-static unsigned int ac97_rm2oss[] = {
- [AC97_REC_MIC] = SOUND_MIXER_MIC,
- [AC97_REC_CD] = SOUND_MIXER_CD,
- [AC97_REC_VIDEO] = SOUND_MIXER_VIDEO,
- [AC97_REC_AUX] = SOUND_MIXER_LINE1,
- [AC97_REC_LINE] = SOUND_MIXER_LINE,
- [AC97_REC_PHONE] = SOUND_MIXER_PHONEIN
-};
-
-/* indexed by bit position */
-static unsigned int ac97_oss_rm[] = {
- [SOUND_MIXER_MIC] = AC97_REC_MIC,
- [SOUND_MIXER_CD] = AC97_REC_CD,
- [SOUND_MIXER_VIDEO] = AC97_REC_VIDEO,
- [SOUND_MIXER_LINE1] = AC97_REC_AUX,
- [SOUND_MIXER_LINE] = AC97_REC_LINE,
- [SOUND_MIXER_PHONEIN] = AC97_REC_PHONE
-};
+ channel->fm_vol = 0x0;
-/* read or write the recmask
- the ac97 can really have left and right recording
- inputs independantly set, but OSS doesn't seem to
- want us to express that to the user.
- the caller guarantees that we have a supported bit set,
- and they must be holding the card's spinlock */
-static int ac97_recmask_io(struct trident_card *card, int rw, int mask)
-{
- unsigned int val;
-
- if (rw) {
- /* read it from the card */
- val = trident_ac97_get(card, 0x1a) & 0x7;
- return ac97_rm2oss[val];
- }
-
- /* else, write the first set in the mask as the
- output */
-
- val = ffs(mask);
- val = ac97_oss_rm[val-1];
- val |= val << 8; /* set both channels */
-#ifdef DEBUG
- printk("trident: setting ac97 recmask to 0x%x\n", val);
-#endif
- trident_ac97_set(card, 0x1a, val);
-
- return 0;
-};
-
-/* AC97 codec initialisation. */
-static u16 trident_ac97_init(struct trident_card *trident)
-{
- u16 id1, id2;
- char *ac97_name = NULL;
- int i;
-
- /* initialize controller side of AC link */
- switch (trident->pci_id)
- {
- case PCI_DEVICE_ID_SI_7018:
- /* disable AC97 GPIO interrupt */
- outl(0x00, TRID_REG(trident, SI_AC97_GPIO));
- /* stop AC97 cold reset process */
- outl(0x00014000, TRID_REG(trident, SI_SERIAL_INTF_CTRL));
- break;
- case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
- /* playback on */
- outl(0x02, TRID_REG(trident, DX_ACR2_AC97_COM_STAT));
- break;
- case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
- /* enable AC97 Output Slot 3,4 (PCM Left/Right Playback) */
- outl(0x02, TRID_REG(trident, NX_ACR0_AC97_COM_STAT));
- break;
- }
-
- /* get some information about our AC97 codec */
- id1 = trident_ac97_get(trident, AC97_VENDOR_ID1);
- id2 = trident_ac97_get(trident, AC97_VENDOR_ID2);
- for (i = 0; i < sizeof (snd_ac97_codec_ids); i++) {
- if (snd_ac97_codec_ids[i].id == ((id1 << 16) | id2)) {
- ac97_name = snd_ac97_codec_ids[i].name;
- break;
- }
- }
- if (ac97_name == NULL)
- ac97_name = "Unknown";
- printk(KERN_INFO "trident: ac97 vendor id1: 0x%04x, id2: 0x%04x (%s)\n",
- id1, id2, ac97_name);
-
- /* initialize volume level */
- trident_ac97_set(trident, AC97_RESET, 0L);
- trident_ac97_set(trident, AC97_MASTER_VOL_STEREO, 0L);
- trident_ac97_set(trident, AC97_PCMOUT_VOL, 0L);
-
- /* set appropriate masks and function pointers */
- trident->mix.supported_mixers = AC97_SUPPORTED_MASK;
- trident->mix.stereo_mixers = AC97_STEREO_MASK;
- trident->mix.record_sources = AC97_RECORD_MASK;
- /* FIXME: trident->mix.read_mixer = ac97_read_mixer; */
- trident->mix.write_mixer = ac97_write_mixer;
- trident->mix.recmask_io = ac97_recmask_io;
-
- return 0;
-}
-
-/* this function only update fmt field in trident_state, the hardware channel attribute
- will be update in trident_play(rec)_setup() which will be called every time a new
- sample is played(recorded) */
-static void set_fmt(struct trident_state *s, unsigned char mask, unsigned char data)
-{
- s->fmt = (s->fmt & mask) | data;
-}
-
-/* the mode passed should be already shifted and masked */
-/* trident_play_setup: initialize channel for play back, mode specify the format of samples to
- be played.
- default values:
-*/
-
-static void trident_play_setup(struct trident_state *trident, int mode, u32 rate,
- void *buffer, int size)
-{
- unsigned int LBA;
- unsigned int Delta;
- unsigned int ESO;
- unsigned int CTRL;
- unsigned int FMC_RVOL_CVOL;
- unsigned int GVSEL;
- unsigned int PAN;
- unsigned int VOL;
- unsigned int EC;
-
- /* set Loop Begin Address */
- LBA = virt_to_bus(buffer);
- Delta = compute_rate(rate);
-
- /* set ESO */
- ESO = size;
- if (mode & TRIDENT_FMT_16BIT)
- ESO /= 2;
- if (mode & TRIDENT_FMT_STEREO)
- ESO /= 2;
- ESO = ESO - 1;
-
- /* loop mode enable */
- CTRL = 0x00000001;
- if (mode & TRIDENT_FMT_16BIT) {
+ channel->control = CHANNEL_LOOP;
+ if (dmabuf->fmt & TRIDENT_FMT_16BIT) {
/* 16-bits */
- CTRL |= 0x00000008;
+ channel->control |= CHANNEL_16BITS;
/* signed */
- CTRL |= 0x00000002;
+ channel->control |= CHANNEL_SIGNED;
}
- if (mode & TRIDENT_FMT_STEREO)
+ if (dmabuf->fmt & TRIDENT_FMT_STEREO)
/* stereo */
- CTRL |= 0x00000004;
-
- /* FIXME: some difference between 4D and 7018 in FMC_RVOL_CVOL */
- /* right vol: mute, ledt vol: mute */
- FMC_RVOL_CVOL = 0x0000ffff;
- GVSEL = 1;
- PAN = 0;
- VOL = 0;
- EC = 0;
-
- trident_write_voice_regs(trident->card,
- trident->dma_dac.chan,
- LBA,
- 0, /* cso */
- ESO,
- Delta,
- 0, /* alpha */
- FMC_RVOL_CVOL,
- GVSEL,
- PAN,
- VOL,
- CTRL,
- EC);
-
+ channel->control |= CHANNEL_STEREO;
+#ifdef DEBUG
+ printk("trident: trident_play_setup, LBA = 0x%08x, "
+ "Delat = 0x%08x, ESO = 0x%08x, Control = 0x%08x\n",
+ channel->lba, channel->delta, channel->eso, channel->control);
+#endif
+ trident_write_voice_regs(state, 0);
}
-/*
- * Native record driver
- */
-/* FIXME: Not exammed yet */
-/* again, passed mode is alrady shifted/masked */
-
-static void trident_rec_setup(struct trident_state *trident, int mode, u32 rate,
- void *buffer, int size)
+/* prepare channel attributes for recording */
+static void trident_rec_setup(struct trident_state *state)
{
- unsigned int LBA;
- unsigned int Delta;
- unsigned int ESO;
- unsigned int CTRL;
- unsigned int FMC_RVOL_CVOL;
- unsigned int GVSEL;
- unsigned int PAN;
- unsigned int VOL;
- unsigned int EC;
- unsigned char bValue;
- unsigned short wValue;
- unsigned int dwValue;
- unsigned short wRecCODECSamples;
- unsigned int dwChanFlags;
- struct trident_card *card = trident->card;
-
-#ifdef DEBUG
- printk("trident: trident_rec_setup called\n");
-#endif
+ u16 w;
+ struct trident_card *card = state->card;
+ struct dmabuf *dmabuf = &state->dma_adc;
+ struct trident_channel *channel = dmabuf->channel;
- // Enable AC-97 ADC (capture), disable capture interrupt
+ /* Enable AC-97 ADC (capture) */
switch (card->pci_id)
{
case PCI_DEVICE_ID_SI_7018:
/* for 7018, the ac97 is always in playback/record (duplex) mode */
break;
case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
- bValue = inb(TRID_REG(card, DX_ACR2_AC97_COM_STAT));
- outb(bValue | 0x48, TRID_REG(card, DX_ACR2_AC97_COM_STAT));
+ w = inb(TRID_REG(card, DX_ACR2_AC97_COM_STAT));
+ outb(w | 0x48, TRID_REG(card, DX_ACR2_AC97_COM_STAT));
break;
case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
- wValue = inw(TRID_REG(card, T4D_MISCINT));
- outw(wValue | 0x1000, TRID_REG(card, T4D_MISCINT));
+ w = inw(TRID_REG(card, T4D_MISCINT));
+ outw(w | 0x1000, TRID_REG(card, T4D_MISCINT));
break;
+ default:
+ return;
}
- // Initilize the channel and set channel Mode
- outb(0, TRID_REG(card, LEGACY_DMAR15));
-
- // Set DMA channel operation mode register
- bValue = inb(TRID_REG(card, LEGACY_DMAR11)) & 0x03;
- outb(bValue | 0x54, TRID_REG(card, LEGACY_DMAR11));
-
- // Set channel buffer Address
- LBA = virt_to_bus(buffer);
- outl(LBA, TRID_REG(card, LEGACY_DMAR0));
-
- /* set ESO */
- ESO = size;
+ channel->lba = virt_to_bus(dmabuf->rawbuf);
+ channel->delta = compute_rate(dmabuf->rate);
- dwValue = inl(TRID_REG(card, LEGACY_DMAR4)) & 0xff000000;
- dwValue |= (ESO - 1) & 0x0000ffff;
- outl(dwValue, TRID_REG(card, LEGACY_DMAR4));
+ channel->eso = dmabuf->dmasize >> sample_shift[dmabuf->fmt];
+ channel->eso -= 1;
- // Set channel sample rate , 4.12 format
- dwValue = (((unsigned int) 48000L << 12) / (unsigned long) (rate));
- outw((unsigned short) dwValue, TRID_REG(card, T4D_SBDELTA_DELTA_R));
-
- // Set channel interrupt blk length
- if (mode & TRIDENT_FMT_16BIT) {
- wRecCODECSamples = (unsigned short) ((ESO >> 1) - 1);
- dwChanFlags = 0xffffb000;
+ if (state->card->pci_id == PCI_DEVICE_ID_SI_7018) {
+ /* FIXME: channel attributes are configured by ioctls, but it is not implemented
+ so just set to ZERO for the moment */
+ channel->attribute = 0;
} else {
- wRecCODECSamples = (unsigned short) (ESO - 1);
- dwChanFlags = 0xffff1000;
+ channel->attribute = 0;
}
- dwValue = ((unsigned int) wRecCODECSamples) << 16;
- dwValue |= (unsigned int) (wRecCODECSamples) & 0x0000ffff;
- outl(dwValue, TRID_REG(card, T4D_SBBL_SBCL));
-
- // Right now, set format and start to run capturing,
- // continuous run loop enable.
- trident->bDMAStart = 0x19; // 0001 1001b
-
- if (mode & TRIDENT_FMT_16BIT)
- trident->bDMAStart |= 0xa0;
- if (mode & TRIDENT_FMT_STEREO)
- trident->bDMAStart |= 0x40;
-
- // Prepare capture intr channel
-
- Delta = ((((unsigned int) rate) << 12) / ((unsigned long) (48000L)));
-
- /* set Loop Back Address */
- LBA = virt_to_bus(buffer);
-
- /* set ESO */
- ESO = size;
- if (mode & TRIDENT_FMT_16BIT)
- ESO /= 2;
- if (mode & TRIDENT_FMT_STEREO)
- ESO /= 2;
-
- ESO = ESO - 1;
- //snd_printk("trid: ESO = %d\n", ESO);
-
- /* set ctrl mode
- CTRL default: 8-bit (unsigned) mono, loop mode enabled
- */
- CTRL = 0x00000001;
- if (mode & TRIDENT_FMT_16BIT)
- CTRL |= 0x00000008; // 16-bit data
- /* XXX DO UNSIGNED XXX */
- //if (!(mode & SND_PCM1_MODE_U))
- // CTRL |= 0x00000002; // signed data
- if (mode& TRIDENT_FMT_STEREO)
- CTRL |= 0x00000004; // stereo data
-
- FMC_RVOL_CVOL = 0x0000ffff;
- GVSEL = 1;
- PAN = 0xff;
- VOL = 0xff;
- EC = 0;
-
- trident_write_voice_regs(card,
- trident->dma_adc.chan,
- LBA,
- 0, /* cso */
- ESO,
- Delta,
- 0, /* alpha */
- FMC_RVOL_CVOL,
- GVSEL,
- PAN,
- VOL,
- CTRL,
- EC);
-
+ channel->fm_vol = 0x0;
+
+ channel->control = CHANNEL_LOOP;
+ if (dmabuf->fmt & TRIDENT_FMT_16BIT) {
+ /* 16-bits */
+ channel->control |= CHANNEL_16BITS;
+ /* signed */
+ channel->control |= CHANNEL_SIGNED;
+ }
+ if (dmabuf->fmt & TRIDENT_FMT_STEREO)
+ /* stereo */
+ channel->control |= CHANNEL_STEREO;
+#ifdef DEBUG
+ printk("trident: trident_rec_setup, LBA = 0x%08x, "
+ "Delat = 0x%08x, ESO = 0x%08x, Control = 0x%08x\n",
+ channel->lba, channel->delta, channel->eso, channel->control);
+#endif
+ trident_write_voice_regs(state, 1);
}
-/* get current playback pointer */
-__inline__ unsigned int get_dmaa(struct trident_state *trident)
+/* get current playback/recording dma buffer pointer (byte offset from LBA),
+ called with spinlock held! */
+extern __inline__ unsigned trident_get_dma_addr(struct trident_state *state, unsigned rec)
{
+ struct dmabuf *dmabuf;
u32 cso;
- u32 eso;
-#if 0
- /* FIXME: does this mean that FULL duplex is not supported ? */
- if (!(trident->enable & ADC_RUNNING))
+
+ if (rec)
+ dmabuf = &state->dma_adc;
+ else
+ dmabuf = &state->dma_dac;
+
+ if (!dmabuf->enable)
return 0;
-#endif
- outb(trident->dma_dac.chan, TRID_REG(trident->card, T4D_LFO_GC_CIR));
- switch (trident->card->pci_id)
+ outb(dmabuf->channel->num, TRID_REG(state->card, T4D_LFO_GC_CIR));
+
+ switch (state->card->pci_id)
{
case PCI_DEVICE_ID_SI_7018:
case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
/* 16 bits ESO, CSO for 7018 and DX */
- cso = inw(TRID_REG(trident->card, CH_DX_CSO_ALPHA_FMS + 2));
- eso = inw(TRID_REG(trident->card, CH_DX_ESO_DELTA + 2));
+ cso = inw(TRID_REG(state->card, CH_DX_CSO_ALPHA_FMS + 2));
break;
case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
/* 24 bits ESO, CSO for NX */
- cso = inl(TRID_REG(trident->card, CH_NX_DELTA_CSO)) & 0x00ffffff;
- eso = inl(TRID_REG(trident->card, CH_NX_DELTA_ESO)) & 0x00ffffff;
+ cso = inl(TRID_REG(state->card, CH_NX_DELTA_CSO)) & 0x00ffffff;
break;
default:
return 0;
}
#ifdef DEBUG
- printk("trident: get_dmaa: chip reported channel: %d, cso = %d, eso = %d\n",
- trident->dma_dac.chan, cso, eso);
+ printk("trident: trident_get_dma_addr: chip reported channel: %d, cso = %d\n",
+ dmabuf->channel->num, cso);
#endif
/* ESO and CSO are in units of Samples, convert to byte offset */
- if (cso > eso)
- cso = eso;
- if (trident->fmt & TRIDENT_FMT_16BIT)
- cso *= 2;
- if (trident->fmt & TRIDENT_FMT_STEREO)
- cso *= 2;
- return cso;
+ cso <<= sample_shift[dmabuf->fmt];
+
+ return (cso % dmabuf->dmasize);
}
-/* get current recording pointer */
-extern __inline__ unsigned get_dmac(struct trident_state *trident)
+/* Stop recording (lock held) */
+extern __inline__ void __stop_adc(struct trident_state *state)
{
- u32 cso;
-#if 0
- /* FIXME: does this mean that FULL duplex is not supported ? */
- if (!(trident->enable & DAC_RUNNING))
- return 0;
-#endif
- outb(trident->dma_adc.chan, TRID_REG(trident->card, T4D_LFO_GC_CIR));
+ struct dmabuf *dmabuf = &state->dma_adc;
+ unsigned int chan_num = dmabuf->channel->num;
+ struct trident_card *card = state->card;
- switch (trident->card->pci_id)
- {
- default:
- case PCI_DEVICE_ID_SI_7018:
- case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
- /* 16 bits ESO, CSO for 7018 and DX */
- cso = inw(TRID_REG(trident->card, CH_DX_CSO_ALPHA_FMS + 2));
- break;
- case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
- /* 24 bits ESO, CSO for NX */
- cso = inl(TRID_REG(trident->card, CH_NX_DELTA_CSO)) & 0x00ffffff;
- break;
- }
-
-#ifdef DEBUG
- printk("(trident) get_dmac: chip reported cso = %d\n", cso);
-#endif
- /* ESO and CSO are in units of Samples, convert to byte offset */
- if (trident->fmt & TRIDENT_FMT_16BIT)
- cso *= 2;
- if (trident->fmt & TRIDENT_FMT_STEREO)
- cso *= 2;
- return cso;
+ dmabuf->enable &= ~DMA_RUNNING;
+ trident_stop_voice(card, chan_num);
+ trident_disable_voice_irq(card, chan_num);
}
-/* Stop recording (lock held) */
-extern inline void __stop_adc(struct trident_state *s)
+static void stop_adc(struct trident_state *state)
{
- struct trident_card *trident = s->card;
-#ifdef DEBUG
- printk("(trident) stopping ADC\n");
-#endif
- s->enable &= ~ADC_RUNNING;
- trident_disable_voice_irq(trident, s->dma_adc.chan);
- outb(0x00, TRID_REG(trident, T4D_SBCTRL_SBE2R_SBDD));
- trident_disable_voice_irq(trident, s->dma_adc.chan);
- trident_stop_voice(trident, s->dma_adc.chan);
- ResetAinten(trident, s->dma_adc.chan);
-}
+ struct trident_card *card = state->card;
+ unsigned long flags;
+
+ spin_lock_irqsave(&card->lock, flags);
+ __stop_adc(state);
+ spin_unlock_irqrestore(&card->lock, flags);
+}
-extern inline void stop_adc(struct trident_state *s)
+static void start_adc(struct trident_state *state)
{
+ struct dmabuf *dmabuf = &state->dma_adc;
+ unsigned int chan_num = dmabuf->channel->num;
+ struct trident_card *card = state->card;
unsigned long flags;
- struct trident_card *trident = s->card;
- spin_lock_irqsave(&trident->lock, flags);
- __stop_adc(s);
- spin_unlock_irqrestore(&trident->lock, flags);
-}
+ spin_lock_irqsave(&card->lock, flags);
+ if ((dmabuf->mapped ||
+ dmabuf->count < (signed)(dmabuf->dmasize - 2*dmabuf->fragsize))
+ && dmabuf->ready) {
+ dmabuf->enable |= DMA_RUNNING;
+ trident_enable_voice_irq(card, chan_num);
+ trident_start_voice(card, chan_num);
+ }
+ spin_unlock_irqrestore(&card->lock, flags);
+}
/* stop playback (lock held) */
-extern inline void __stop_dac(struct trident_state *state)
+extern __inline__ void __stop_dac(struct trident_state *state)
{
- struct trident_card *trident = state->card;
- trident_stop_voice(trident, state->dma_dac.chan);
- trident_disable_voice_irq(trident, state->dma_dac.chan);
- state->enable &= ~DAC_RUNNING;
-}
+ struct dmabuf *dmabuf = &state->dma_dac;
+ unsigned int chan_num = dmabuf->channel->num;
+ struct trident_card *card = state->card;
-extern inline void stop_dac(struct trident_state *state)
+ dmabuf->enable &= ~DMA_RUNNING;
+ trident_stop_voice(card, chan_num);
+ trident_disable_voice_irq(card, chan_num);
+}
+
+static void stop_dac(struct trident_state *state)
{
- struct trident_card *trident = state->card;
+ struct trident_card *card = state->card;
unsigned long flags;
- spin_lock_irqsave(&trident->lock, flags);
+ spin_lock_irqsave(&card->lock, flags);
__stop_dac(state);
- spin_unlock_irqrestore(&trident->lock, flags);
+ spin_unlock_irqrestore(&card->lock, flags);
}
static void start_dac(struct trident_state *state)
{
+ struct dmabuf *dmabuf = &state->dma_dac;
+ unsigned int chan_num = dmabuf->channel->num;
+ struct trident_card *card = state->card;
unsigned long flags;
- struct trident_card *trident = state->card;
- spin_lock_irqsave(&state->card->lock, flags);
- if ((state->dma_dac.mapped || state->dma_dac.count > 0) && state->dma_dac.ready) {
- state->enable |= DAC_RUNNING;
- trident_enable_voice_irq(trident, state->dma_dac.chan);
- trident_start_voice(trident, state->dma_dac.chan);
+ spin_lock_irqsave(&card->lock, flags);
+ if ((dmabuf->mapped || dmabuf->count > 0) && dmabuf->ready) {
+ dmabuf->enable |= DMA_RUNNING;
+ trident_enable_voice_irq(card, chan_num);
+ trident_start_voice(card, chan_num);
}
- spin_unlock_irqrestore(&state->card->lock, flags);
-}
-
-static void start_adc(struct trident_state *s)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&s->card->lock, flags);
- if ((s->dma_adc.mapped || s->dma_adc.count < (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize))
- && s->dma_adc.ready) {
- s->enable |= ADC_RUNNING;
- trident_enable_voice_irq(s->card, s->dma_adc.chan);
- outb(s->bDMAStart, TRID_REG(s->card, T4D_SBCTRL_SBE2R_SBDD));
- trident_start_voice(s->card, s->dma_adc.chan);
-#ifdef DEBUG
- printk("(trident) starting ADC\n");
-#endif
- }
- spin_unlock_irqrestore(&s->card->lock, flags);
-}
+ spin_unlock_irqrestore(&card->lock, flags);
+}
#define DMABUF_DEFAULTORDER (15-PAGE_SHIFT)
#define DMABUF_MINORDER 1
@@ -1623,10 +823,16 @@ static void start_adc(struct trident_state *s)
/* allocate DMA buffer, playback and recording buffer should be allocated seperately */
static int alloc_dmabuf(struct trident_state *state, unsigned rec)
{
+ struct dmabuf *dmabuf;
void *rawbuf;
int order;
unsigned long map, mapend;
+ if (rec)
+ dmabuf = &state->dma_adc;
+ else
+ dmabuf = &state->dma_dac;
+
/* alloc as big a chunk as we can, FIXME: is this necessary ?? */
for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--)
if ((rawbuf = (void *)__get_free_pages(GFP_KERNEL, order)))
@@ -1634,7 +840,7 @@ static int alloc_dmabuf(struct trident_state *state, unsigned rec)
if (!rawbuf)
return -ENOMEM;
#ifdef DEBUG
- printk("trident: allocated %ld (%d) bytes at %p\n",
+ printk("trident: allocated %ld (order = %d) bytes at %p\n",
PAGE_SIZE << order, order, rawbuf);
#endif
@@ -1648,17 +854,10 @@ static int alloc_dmabuf(struct trident_state *state, unsigned rec)
return -ENOMEM;
}
- if (rec) {
- state->dma_adc.ready = state->dma_adc.mapped = 0;
- state->dma_adc.rawbuf = rawbuf;
- state->dma_adc.buforder = order;
- }
- else {
- state->dma_dac.ready = state->dma_dac.mapped = 0;
- state->dma_dac.rawbuf = rawbuf;
- state->dma_dac.buforder = order;
- }
-
+ dmabuf->ready = dmabuf->mapped = 0;
+ dmabuf->rawbuf = rawbuf;
+ dmabuf->buforder = order;
+
/* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */
mapend = MAP_NR(rawbuf + (PAGE_SIZE << order) - 1);
for (map = MAP_NR(rawbuf); map <= mapend; map++)
@@ -1668,180 +867,237 @@ static int alloc_dmabuf(struct trident_state *state, unsigned rec)
}
/* free DMA buffer */
-static void dealloc_dmabuf(struct dmabuf *db)
+static void dealloc_dmabuf(struct dmabuf *dmabuf)
{
unsigned long map, mapend;
- if (db->rawbuf) {
+ if (dmabuf->rawbuf) {
/* undo marking the pages as reserved */
- mapend = MAP_NR(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
- for (map = MAP_NR(db->rawbuf); map <= mapend; map++)
+ mapend = MAP_NR(dmabuf->rawbuf + (PAGE_SIZE << dmabuf->buforder) - 1);
+ for (map = MAP_NR(dmabuf->rawbuf); map <= mapend; map++)
clear_bit(PG_reserved, &mem_map[map].flags);
- free_pages((unsigned long)db->rawbuf, db->buforder);
+ free_pages((unsigned long)dmabuf->rawbuf, dmabuf->buforder);
}
- db->rawbuf = NULL;
- db->mapped = db->ready = 0;
+ dmabuf->rawbuf = NULL;
+ dmabuf->mapped = dmabuf->ready = 0;
}
static int prog_dmabuf(struct trident_state *state, unsigned rec)
{
- struct dmabuf *db = rec ? &state->dma_adc : &state->dma_dac;
- unsigned rate = rec ? state->rateadc : state->ratedac;
+ struct dmabuf *dmabuf;
unsigned bytepersec;
- unsigned bufs;
- unsigned char fmt;
+ unsigned bufsize;
unsigned long flags;
int ret;
+ if (rec)
+ dmabuf = &state->dma_adc;
+ else
+ dmabuf = &state->dma_dac;
+
spin_lock_irqsave(&state->card->lock, flags);
- fmt = state->fmt;
- if (rec) {
- state->enable &= ~TRIDENT_ENABLE_RE;
- fmt >>= TRIDENT_ADC_SHIFT;
- } else {
- state->enable &= ~TRIDENT_ENABLE_PE;
- fmt >>= TRIDENT_DAC_SHIFT;
- }
+ dmabuf->hwptr = dmabuf->swptr = dmabuf->total_bytes = 0;
+ dmabuf->count = dmabuf->error = dmabuf->endcleared = 0;
spin_unlock_irqrestore(&state->card->lock, flags);
- fmt &= TRIDENT_FMT_MASK;
-
- db->hwptr = db->swptr = db->total_bytes = 0;
- db->count = db->error = db->endcleared = 0;
-
/* allocate DMA buffer if not allocated yet */
- if (!db->rawbuf)
+ if (!dmabuf->rawbuf)
if ((ret = alloc_dmabuf(state, rec)))
return ret;
- bytepersec = rate << sample_shift[fmt];
- bufs = PAGE_SIZE << db->buforder;
- if (db->ossfragshift) {
- if ((1000 << db->ossfragshift) < bytepersec)
- db->fragshift = ld2(bytepersec/1000);
+ /* FIXME: figure out all this OSS fragment stuff */
+ bytepersec = dmabuf->rate << sample_shift[dmabuf->fmt];
+ bufsize = PAGE_SIZE << dmabuf->buforder;
+ if (dmabuf->ossfragshift) {
+ if ((1000 << dmabuf->ossfragshift) < bytepersec)
+ dmabuf->fragshift = ld2(bytepersec/1000);
else
- db->fragshift = db->ossfragshift;
+ dmabuf->fragshift = dmabuf->ossfragshift;
} else {
/* lets hand out reasonable big ass buffers by default */
- db->fragshift = (db->buforder + PAGE_SHIFT -2);
+ dmabuf->fragshift = (dmabuf->buforder + PAGE_SHIFT -2);
}
- db->numfrag = bufs >> db->fragshift;
- while (db->numfrag < 4 && db->fragshift > 3) {
- db->fragshift--;
- db->numfrag = bufs >> db->fragshift;
+ dmabuf->numfrag = bufsize >> dmabuf->fragshift;
+ while (dmabuf->numfrag < 4 && dmabuf->fragshift > 3) {
+ dmabuf->fragshift--;
+ dmabuf->numfrag = bufsize >> dmabuf->fragshift;
}
- db->fragsize = 1 << db->fragshift;
- if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag)
- db->numfrag = db->ossmaxfrags;
- db->fragsamples = db->fragsize >> sample_shift[fmt];
- db->dmasize = db->numfrag << db->fragshift;
+ dmabuf->fragsize = 1 << dmabuf->fragshift;
+ if (dmabuf->ossmaxfrags >= 4 && dmabuf->ossmaxfrags < dmabuf->numfrag)
+ dmabuf->numfrag = dmabuf->ossmaxfrags;
+ dmabuf->fragsamples = dmabuf->fragsize >> sample_shift[dmabuf->fmt];
+ dmabuf->dmasize = dmabuf->numfrag << dmabuf->fragshift;
- memset(db->rawbuf, (fmt & TRIDENT_FMT_16BIT) ? 0 : 0x80, db->dmasize);
+ memset(dmabuf->rawbuf, (dmabuf->fmt & TRIDENT_FMT_16BIT) ? 0 : 0x80,
+ dmabuf->dmasize);
spin_lock_irqsave(&state->card->lock, flags);
if (rec) {
- trident_rec_setup(state, fmt, state->rateadc,
- db->rawbuf, db->numfrag << db->fragshift);
+ trident_rec_setup(state);
} else {
- trident_play_setup(state, fmt, state->ratedac,
- db->rawbuf, db->numfrag << db->fragshift);
+ trident_play_setup(state);
}
spin_unlock_irqrestore(&state->card->lock, flags);
/* set the ready flag for the dma buffer */
- db->ready = 1;
+ dmabuf->ready = 1;
#ifdef DEBUG
printk("trident: prog_dmabuf, sample rate = %d, format = %d, numfrag = %d, "
"fragsize = %d dmasize = %d\n",
- rate, fmt, db->numfrag, db->fragsize, db->dmasize);
+ dmabuf->rate, dmabuf->fmt, dmabuf->numfrag,
+ dmabuf->fragsize, dmabuf->dmasize);
#endif
return 0;
}
-extern __inline__ void clear_advance(struct trident_state *s)
+/* we are doing quantum mechanics here, the buffer can only be empty, half or full filled i.e.
+ |------------|------------| or |xxxxxxxxxxxx|------------| or |xxxxxxxxxxxx|xxxxxxxxxxxx|
+ but we almost always get this
+ |xxxxxx------|------------| or |xxxxxxxxxxxx|xxxxx-------|
+ so we have to clear the tail space to "silence"
+ |xxxxxx000000|------------| or |xxxxxxxxxxxx|xxxxxx000000|
+*/
+static void trident_clear_tail(struct trident_state *state)
{
- unsigned char c = ((s->fmt >> TRIDENT_DAC_SHIFT) & TRIDENT_FMT_16BIT) ? 0 : 0x80;
- unsigned char *buf = s->dma_dac.rawbuf;
- unsigned bsize = s->dma_dac.dmasize;
- unsigned bptr = s->dma_dac.swptr;
- unsigned len = s->dma_dac.fragsize;
-
- if (bptr + len > bsize) {
- unsigned x = bsize - bptr;
- memset(buf + bptr, c, x);
- /* account for wrapping? */
- bptr = 0;
- len -= x;
+ struct dmabuf *dmabuf = &state->dma_dac;
+ unsigned swptr;
+ unsigned char silence = (dmabuf->fmt & TRIDENT_FMT_16BIT) ? 0 : 0x80;
+ unsigned int len;
+ unsigned long flags;
+
+ spin_lock_irqsave(&state->card->lock, flags);
+ swptr = dmabuf->swptr;
+ spin_unlock_irqrestore(&state->card->lock, flags);
+
+ if (swptr == 0 || swptr == dmabuf->dmasize / 2 || swptr == dmabuf->dmasize)
+ return;
+
+
+ if (swptr < dmabuf->dmasize/2)
+ len = dmabuf->dmasize/2 - swptr;
+ else
+ len = dmabuf->dmasize - swptr;
+
+ memset(dmabuf->rawbuf + swptr, silence, len);
+
+ spin_lock_irqsave(&state->card->lock, flags);
+ dmabuf->swptr += len;
+ dmabuf->count += len;
+ spin_unlock_irqrestore(&state->card->lock, flags);
+
+ /* restart the dma machine in case it is halted */
+ start_dac(state);
+}
+
+static int drain_dac(struct trident_state *state, int nonblock)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ struct dmabuf *dmabuf = &state->dma_dac;
+ unsigned long flags;
+ unsigned long tmo;
+ int count;
+
+ if (dmabuf->mapped || !dmabuf->ready)
+ return 0;
+
+ add_wait_queue(&dmabuf->wait, &wait);
+ for (;;) {
+ /* It seems that we have to set the current state to TASK_INTERRUPTIBLE
+ every time to make the process really go to sleep */
+ current->state = TASK_INTERRUPTIBLE;
+
+ spin_lock_irqsave(&state->card->lock, flags);
+ count = dmabuf->count;
+ spin_unlock_irqrestore(&state->card->lock, flags);
+
+ if (count <= 0)
+ break;
+
+ if (signal_pending(current))
+ break;
+
+ if (nonblock) {
+ remove_wait_queue(&dmabuf->wait, &wait);
+ current->state = TASK_RUNNING;
+ return -EBUSY;
+ }
+
+ /* No matter how much data left in the buffer, we have to wait untill
+ CSO == ESO/2 or CSO == ESO when address engine interrupts */
+ tmo = (dmabuf->dmasize * HZ) / dmabuf->rate;
+ tmo >>= sample_shift[dmabuf->fmt];
+ if (!schedule_timeout(tmo ? tmo : 1) && tmo){
+ printk(KERN_ERR "trident: drain_dac, dma timeout?\n");
+ break;
+ }
}
- memset(buf + bptr, c, len);
+ remove_wait_queue(&dmabuf->wait, &wait);
+ current->state = TASK_RUNNING;
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+
+ return 0;
}
/* call with spinlock held! */
-static void trident_update_ptr(struct trident_state *s)
+static void trident_update_ptr(struct trident_state *state)
{
+ struct dmabuf *dmabuf;
unsigned hwptr;
int diff;
/* update ADC pointer */
- if (s->dma_adc.ready) {
- hwptr = get_dmac(s) % s->dma_adc.dmasize;
- diff = (s->dma_adc.dmasize + hwptr - s->dma_adc.hwptr) %
- s->dma_adc.dmasize;
- s->dma_adc.hwptr = hwptr;
- s->dma_adc.total_bytes += diff;
- s->dma_adc.count += diff;
- if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
- wake_up(&s->dma_adc.wait);
- if (!s->dma_adc.mapped) {
- if (s->dma_adc.count > (signed)(s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1))) {
- s->enable &= ~TRIDENT_ENABLE_RE;
- __stop_adc(s);
- s->dma_adc.error++;
+ if (state->dma_adc.ready) {
+ dmabuf = &state->dma_adc;
+ hwptr = trident_get_dma_addr(state, 1);
+ diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize;
+
+ dmabuf->hwptr = hwptr;
+ dmabuf->total_bytes += diff;
+ dmabuf->count += diff;
+
+ if (dmabuf->count >= (signed)dmabuf->fragsize)
+ wake_up(&dmabuf->wait);
+ if (!dmabuf->mapped) {
+ if (dmabuf->count > (signed)(dmabuf->dmasize - ((3 * dmabuf->fragsize) >> 1))) {
+ __stop_adc(state);
+ dmabuf->error++;
}
}
}
/* update DAC pointer */
- if (s->dma_dac.ready) {
- hwptr = get_dmaa(s) % s->dma_dac.dmasize;
- diff = (s->dma_dac.dmasize + hwptr - s->dma_dac.hwptr) %
- s->dma_dac.dmasize;
- s->dma_dac.hwptr = hwptr;
- s->dma_dac.total_bytes += diff;
- if (s->dma_dac.mapped) {
- s->dma_dac.count += diff;
- if (s->dma_dac.count >= (signed)s->dma_dac.fragsize)
- wake_up(&s->dma_dac.wait);
- }
+ if (state->dma_dac.ready) {
+ dmabuf = &state->dma_dac;
+ hwptr = trident_get_dma_addr(state, 0);
+ diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize;
+
+ dmabuf->hwptr = hwptr;
+ dmabuf->total_bytes += diff;
+
+ if (dmabuf->mapped) {
+ dmabuf->count += diff;
+ if (dmabuf->count >= (signed)dmabuf->fragsize)
+ wake_up(&dmabuf->wait);
+ }
else {
- s->dma_dac.count -= diff;
- if (s->dma_dac.count <= 0) {
- s->enable &= ~TRIDENT_ENABLE_PE;
- /* Lock already held */
- __stop_dac(s);
- /* brute force everyone back in sync, sigh */
- s->dma_dac.count = 0;
- s->dma_dac.swptr = 0;
- s->dma_dac.hwptr = 0;
- s->dma_dac.error++;
- }
- else if (s->dma_dac.count <= (signed)s->dma_dac.fragsize &&
- !s->dma_dac.endcleared) {
- clear_advance(s);
- s->dma_dac.endcleared = 1;
+ dmabuf->count -= diff;
+ if (dmabuf->count < 0 || dmabuf->count > dmabuf->dmasize) {
+ /* buffer underrun or buffer overrun, we have no way to recover
+ it here, just stop the machine and let the process force hwptr
+ and swptr to sync */
+ __stop_dac(state);
+ dmabuf->error++;
}
-
- if (s->dma_dac.count + (signed)s->dma_dac.fragsize <= (signed)s->dma_dac.dmasize)
- wake_up(&s->dma_dac.wait);
+ /* since dma machine only interrupts at ESO and ESO/2, we sure have at
+ least half of dma buffer free, so wake up the process unconditionally */
+ wake_up(&dmabuf->wait);
}
}
}
-/*
- * Trident interrupt handlers.
- */
static void trident_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
struct trident_state *state;
@@ -1858,19 +1114,17 @@ static void trident_interrupt(int irq, void *dev_id, struct pt_regs *regs)
if (event & ADDRESS_IRQ) {
/* Update the pointers for all channels we are running. */
- /* FIXME: improve interrupt latency !!! */
- for (i = 0; i < NR_DSPS; i++) {
- state = card->channels[i];
+ /* FIXME: should read interrupt status only once */
+ for (i = 0; i < NR_HW_CH; i++) {
if (trident_check_channel_interrupt(card, 63 - i)) {
trident_ack_channel_interrupt(card, 63 - i);
- if (state != NULL)
+ if ((state = card->states[i]) != NULL) {
trident_update_ptr(state);
- else {
- /* Spurious ? */
- printk("trident: spurious channel irq %d.\n",
+ } else {
+ printk("trident: spurious channel irq %d.\n",
63 - i);
trident_stop_voice(card, i);
- trident_disable_voice_irq(card, i);
+ trident_disable_voice_irq(card, i);
}
}
}
@@ -1886,254 +1140,29 @@ static void trident_interrupt(int irq, void *dev_id, struct pt_regs *regs)
spin_unlock(&card->lock);
}
-static void set_mixer(struct trident_card *card,unsigned int mixer, unsigned int val )
-{
- unsigned int left,right;
-
- /* cleanse input a little */
- right = ((val >> 8) & 0xff) ;
- left = (val & 0xff) ;
-
- if (right > 100) right = 100;
- if (left > 100) left = 100;
-
- card->mix.mixer_state[mixer] = (right << 8) | left;
- card->mix.write_mixer(card, mixer, left, right);
-}
-
-static int mixer_ioctl(struct trident_card *card, unsigned int cmd, unsigned long arg)
-{
- unsigned long flags;
- int i, val = 0;
-
- VALIDATE_CARD(card);
- if (cmd == SOUND_MIXER_INFO) {
- mixer_info info;
- strncpy(info.id, card->pci_info->name, sizeof(info.id));
- strncpy(info.name, card->pci_info->name, sizeof(info.name));
- info.modify_counter = card->mix.modcnt;
- if (copy_to_user((void *)arg, &info, sizeof(info)))
- return -EFAULT;
- return 0;
- }
- if (cmd == SOUND_OLD_MIXER_INFO) {
- _old_mixer_info info;
- strncpy(info.id, card->pci_info->name, sizeof(info.id));
- strncpy(info.name, card->pci_info->name, sizeof(info.name));
- if (copy_to_user((void *)arg, &info, sizeof(info)))
- return -EFAULT;
- return 0;
- }
-
- if (_IOC_TYPE(cmd) != 'M' || _IOC_SIZE(cmd) != sizeof(int))
- return -EINVAL;
-
- if (cmd == OSS_GETVERSION)
- return put_user(SOUND_VERSION, (int *)arg);
-
- if (_IOC_DIR(cmd) == _IOC_READ) {
- switch (_IOC_NR(cmd)) {
- case SOUND_MIXER_RECSRC: /* give them the current record source */
- if (!card->mix.recmask_io) {
- val = 0;
- } else {
- spin_lock_irqsave(&card->lock, flags);
- val = card->mix.recmask_io(card,1,0);
- spin_unlock_irqrestore(&card->lock, flags);
- }
- break;
-
- case SOUND_MIXER_DEVMASK: /* give them the supported mixers */
- val = card->mix.supported_mixers;
- break;
-
- case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */
- val = card->mix.record_sources;
- break;
-
- case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */
- val = card->mix.stereo_mixers;
- break;
-
- case SOUND_MIXER_CAPS:
- val = SOUND_CAP_EXCL_INPUT;
- break;
-
- default: /* read a specific mixer */
- i = _IOC_NR(cmd);
-
- if (!supported_mixer(card,i))
- return -EINVAL;
-
- /* do we ever want to touch the hardware? */
- /* spin_lock_irqsave(&s->lock, flags);
- val = card->mix.read_mixer(card,i);
- spin_unlock_irqrestore(&s->lock, flags);*/
-
- val = card->mix.mixer_state[i];
- /* printk("returned 0x%x for mixer %d\n",val,i);*/
- break;
- }
- return put_user(val,(int *)arg);
- }
-
- if (_IOC_DIR(cmd) == (_IOC_WRITE|_IOC_READ)) {
- card->mix.modcnt++;
- get_user_ret(val, (int *)arg, -EFAULT);
-
- switch (_IOC_NR(cmd)) {
- case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
- if (!card->mix.recmask_io) return -EINVAL;
- if (!(val &= card->mix.record_sources)) return -EINVAL;
-
- spin_lock_irqsave(&card->lock, flags);
- card->mix.recmask_io(card, 0, val);
- spin_unlock_irqrestore(&card->lock, flags);
-
- return 0;
- default: /* write a specific mixer */
- i = _IOC_NR(cmd);
-
- if (!supported_mixer(card, i))
- return -EINVAL;
-
- spin_lock_irqsave(&card->lock, flags);
- set_mixer(card, i, val);
- spin_unlock_irqrestore(&card->lock, flags);
-
- return 0;
- }
- }
- return -EINVAL;
-}
-
-static int trident_open_mixdev(struct inode *inode, struct file *file)
-{
- int minor = MINOR(inode->i_rdev);
- struct trident_card *card = devs;
-
- while (card && card->dev_mixer != minor)
- card = card->next;
- if (!card)
- return -ENODEV;
-
- file->private_data = card;
-
- //FIXME put back in
- //MOD_INC_USE_COUNT;
- return 0;
-}
-
-static int trident_release_mixdev(struct inode *inode, struct file *file)
-{
- struct trident_card *card = (struct trident_card *)file->private_data;
-
- VALIDATE_CARD(card);
-
- //FIXME put back in
- //MOD_DEC_USE_COUNT;
- return 0;
-}
-
-static int trident_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- struct trident_card *card = (struct trident_card *)file->private_data;
-
- VALIDATE_CARD(card);
- return mixer_ioctl(card, cmd, arg);
-}
-
static loff_t trident_llseek(struct file *file, loff_t offset, int origin)
{
return -ESPIPE;
}
-static /*const*/ struct file_operations trident_mixer_fops = {
- &trident_llseek,
- NULL, /* read */
- NULL, /* write */
- NULL, /* readdir */
- NULL, /* poll */
- &trident_ioctl_mixdev,
- NULL, /* mmap */
- &trident_open_mixdev,
- NULL, /* flush */
- &trident_release_mixdev,
- NULL, /* fsync */
- NULL, /* fasync */
- NULL, /* lock */
-};
-
-/* drain the DAC buffer
- FIXME: This function will block (forever ??) when using
- XMMS Qsound plugin and direct cat sample.wav > /dev/dsp
- This behavior is when drain_dac is called by trident_release. */
-static int drain_dac(struct trident_state *s, int nonblock)
-{
- DECLARE_WAITQUEUE(wait, current);
- unsigned long flags;
- int count;
- signed long tmo;
-
- if (s->dma_dac.mapped || !s->dma_dac.ready)
- return 0;
-
- current->state = TASK_INTERRUPTIBLE;
- add_wait_queue(&s->dma_dac.wait, &wait);
- for (;;) {
- spin_lock_irqsave(&s->card->lock, flags);
- count = s->dma_dac.count;
- spin_unlock_irqrestore(&s->card->lock, flags);
-
- if (count <= 0)
- break;
-
- if (signal_pending(current))
- break;
-
- if (nonblock) {
- remove_wait_queue(&s->dma_dac.wait, &wait);
- current->state = TASK_RUNNING;
- return -EBUSY;
- }
-
- tmo = (count * HZ) / s->ratedac;
- tmo >>= sample_shift[(s->fmt >> TRIDENT_DAC_SHIFT) & TRIDENT_FMT_MASK];
-
- /* XXX this is just broken. someone is waking us up alot,
- or schedule_timeout is broken.
- or something. who cares. - zach */
- if (!schedule_timeout(tmo ? tmo : 1) && tmo)
- printk(KERN_ERR "trident: drain_dac, "
- "dma timed out? jiffies = %ld\n",
- jiffies);
- }
- remove_wait_queue(&s->dma_dac.wait, &wait);
- current->state = TASK_RUNNING;
- if (signal_pending(current))
- return -ERESTARTSYS;
-
- return 0;
-}
-
/* in this loop, dma_adc.count signifies the amount of data thats waiting
to be copied to the user's buffer. it is filled by the interrupt
handler and drained by this loop. */
static ssize_t trident_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
{
struct trident_state *state = (struct trident_state *)file->private_data;
+ struct dmabuf *dmabuf = &state->dma_dac;
ssize_t ret;
unsigned long flags;
unsigned swptr;
int cnt;
-
+
VALIDATE_STATE(state);
if (ppos != &file->f_pos)
return -ESPIPE;
- if (state->dma_adc.mapped)
+ if (dmabuf->mapped)
return -ENXIO;
- if (!state->dma_adc.ready && (ret = prog_dmabuf(state, 1)))
+ if (!dmabuf->ready && (ret = prog_dmabuf(state, 1)))
return ret;
if (!access_ok(VERIFY_WRITE, buffer, count))
return -EFAULT;
@@ -2141,12 +1170,10 @@ static ssize_t trident_read(struct file *file, char *buffer, size_t count, loff_
while (count > 0) {
spin_lock_irqsave(&state->card->lock, flags);
- /* remember, all these things are expressed in bytes to be
- sent to the user.. hence the evil / 2 down below */
- swptr = state->dma_adc.swptr;
- cnt = state->dma_adc.dmasize - swptr;
- if (state->dma_adc.count < cnt)
- cnt = state->dma_adc.count;
+ swptr = dmabuf->swptr;
+ cnt = dmabuf->dmasize - swptr;
+ if (dmabuf->count < cnt)
+ cnt = dmabuf->count;
spin_unlock_irqrestore(&state->card->lock, flags);
if (cnt > count)
@@ -2158,20 +1185,17 @@ static ssize_t trident_read(struct file *file, char *buffer, size_t count, loff_
ret = ret ? ret : -EAGAIN;
return ret;
}
- if (!interruptible_sleep_on_timeout(&state->dma_adc.wait, HZ)) {
- printk(KERN_DEBUG "(trident) read: chip lockup? "
+ if (!interruptible_sleep_on_timeout(&dmabuf->wait, HZ)) {
+ printk(KERN_ERR
+ "(trident) read: chip lockup? "
"dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
- state->dma_adc.dmasize,
- state->dma_adc.fragsize,
- state->dma_adc.count,
- state->dma_adc.hwptr,
- state->dma_adc.swptr);
+ dmabuf->dmasize, dmabuf->fragsize, dmabuf->count,
+ dmabuf->hwptr, dmabuf->swptr);
stop_adc(state);
-
spin_lock_irqsave(&state->card->lock, flags);
- state->dma_adc.count = 0;
- state->dma_adc.hwptr = 0;
- state->dma_adc.swptr = 0;
+ dmabuf->count = 0;
+ dmabuf->hwptr = 0;
+ dmabuf->swptr = 0;
spin_unlock_irqrestore(&state->card->lock, flags);
}
if (signal_pending(current)) {
@@ -2180,17 +1204,19 @@ static ssize_t trident_read(struct file *file, char *buffer, size_t count, loff_
}
continue;
}
-
- if (copy_to_user(buffer, state->dma_adc.rawbuf + swptr, cnt)) {
+
+ if (copy_to_user(buffer, dmabuf->rawbuf + swptr, cnt)) {
ret = ret ? ret : -EFAULT;
return ret;
}
- swptr = (swptr + cnt) % state->dma_adc.dmasize;
+ swptr = (swptr + cnt) % dmabuf->dmasize;
+
spin_lock_irqsave(&state->card->lock, flags);
- state->dma_adc.swptr = swptr;
- state->dma_adc.count -= cnt;
+ dmabuf->swptr = swptr;
+ dmabuf->count -= cnt;
spin_unlock_irqrestore(&state->card->lock, flags);
+
count -= cnt;
buffer += cnt;
ret += cnt;
@@ -2203,11 +1229,11 @@ static ssize_t trident_read(struct file *file, char *buffer, size_t count, loff_
static ssize_t trident_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
{
struct trident_state *state = (struct trident_state *)file->private_data;
+ struct dmabuf *dmabuf = &state->dma_dac;
ssize_t ret;
unsigned long flags;
unsigned swptr;
int cnt;
- int mode = (state->fmt >> TRIDENT_DAC_SHIFT) & TRIDENT_FMT_MASK;
#ifdef DEBUG
printk("trident: trident_write called, count = %d\n", count);
@@ -2216,9 +1242,9 @@ static ssize_t trident_write(struct file *file, const char *buffer, size_t count
VALIDATE_STATE(state);
if (ppos != &file->f_pos)
return -ESPIPE;
- if (state->dma_dac.mapped)
+ if (dmabuf->mapped)
return -ENXIO;
- if (!state->dma_dac.ready && (ret = prog_dmabuf(state, 0)))
+ if (!dmabuf->ready && (ret = prog_dmabuf(state, 0)))
return ret;
if (!access_ok(VERIFY_READ, buffer, count))
return -EFAULT;
@@ -2226,41 +1252,47 @@ static ssize_t trident_write(struct file *file, const char *buffer, size_t count
while (count > 0) {
spin_lock_irqsave(&state->card->lock, flags);
- if (state->dma_dac.count < 0) {
- state->dma_dac.count = 0;
- state->dma_dac.swptr = state->dma_dac.hwptr;
+ if (dmabuf->count < 0) {
+ /* buffer underrun, we are recovering from sleep_on_timeout,
+ resync hwptr and swptr */
+ dmabuf->count = 0;
+ dmabuf->swptr = dmabuf->hwptr;
}
- swptr = state->dma_dac.swptr;
- cnt = state->dma_dac.dmasize - swptr;
- if (state->dma_dac.count + cnt > state->dma_dac.dmasize)
- cnt = state->dma_dac.dmasize - state->dma_dac.count;
+ swptr = dmabuf->swptr;
+ cnt = dmabuf->dmasize - swptr;
+ if (dmabuf->count + cnt > dmabuf->dmasize)
+ cnt = dmabuf->dmasize - dmabuf->count;
spin_unlock_irqrestore(&state->card->lock, flags);
if (cnt > count)
cnt = count;
if (cnt <= 0) {
- /* buffer is full, wait for it to be played */
+ unsigned long tmo;
+ /* buffer is full, start the dma machine and wait for data to be played */
start_dac(state);
if (file->f_flags & O_NONBLOCK) {
if (!ret) ret = -EAGAIN;
return ret;
}
- if (!interruptible_sleep_on_timeout(&state->dma_dac.wait, HZ)) {
- printk(KERN_ERR
- "trident: write: chip lockup? "
- "dmasz %u fragsz %u count %i "
- "hwptr %u swptr %u\n",
- state->dma_dac.dmasize,
- state->dma_dac.fragsize,
- state->dma_dac.count,
- state->dma_dac.hwptr,
- state->dma_dac.swptr);
- stop_dac(state);
- spin_lock_irqsave(&state->card->lock, flags);
- state->dma_dac.count = 0;
- state->dma_dac.hwptr = 0;
- state->dma_dac.swptr = 0;
- spin_unlock_irqrestore(&state->card->lock, flags);
+ /* No matter how much data left in the buffer, we have to wait untill
+ CSO == ESO/2 or CSO == ESO when address engine interrupts */
+ tmo = (dmabuf->dmasize * HZ) / (dmabuf->rate * 2);
+ tmo >>= sample_shift[dmabuf->fmt];
+ /* There are two situations when sleep_on_timeout returns, one is when the
+ interrupt is serviced correctly and the process is waked up by ISR ON TIME.
+ Another is when timeout is expired, which means that either interrupt is NOT
+ serviced correctly (pending interrupt) or it is TOO LATE for the process to
+ be scheduled to run (scheduler latency) which results in a (potential) buffer
+ underrun. And worse, there is NOTHING we can do to prevent it. */
+ if (!interruptible_sleep_on_timeout(&dmabuf->wait, tmo)) {
+#ifdef DEBUG
+ printk(KERN_ERR "trident: schedule timeout, "
+ "dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
+ dmabuf->dmasize, dmabuf->fragsize, dmabuf->count,
+ dmabuf->hwptr, dmabuf->swptr);
+#endif
+ /* a buffer underrun, we delay the recovery untill next time the
+ while loop begin and we REALLY have data to play */
}
if (signal_pending(current)) {
if (!ret) ret = -ERESTARTSYS;
@@ -2268,18 +1300,17 @@ static ssize_t trident_write(struct file *file, const char *buffer, size_t count
}
continue;
}
- if (copy_from_user(state->dma_dac.rawbuf + swptr, buffer, cnt)) {
- if (!ret)
- ret = -EFAULT;
+ if (copy_from_user(dmabuf->rawbuf + swptr, buffer, cnt)) {
+ if (!ret) ret = -EFAULT;
return ret;
}
- swptr = (swptr + cnt) % state->dma_dac.dmasize;
+ swptr = (swptr + cnt) % dmabuf->dmasize;
spin_lock_irqsave(&state->card->lock, flags);
- state->dma_dac.swptr = swptr;
- state->dma_dac.count += cnt;
- state->dma_dac.endcleared = 0;
+ dmabuf->swptr = swptr;
+ dmabuf->count += cnt;
+ dmabuf->endcleared = 0;
spin_unlock_irqrestore(&state->card->lock, flags);
count -= cnt;
@@ -2304,7 +1335,6 @@ static unsigned int trident_poll(struct file *file, struct poll_table_struct *wa
spin_lock_irqsave(&s->card->lock, flags);
trident_update_ptr(s);
-
if (file->f_mode & FMODE_READ) {
if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
mask |= POLLIN | POLLRDNORM;
@@ -2319,56 +1349,56 @@ static unsigned int trident_poll(struct file *file, struct poll_table_struct *wa
}
}
spin_unlock_irqrestore(&s->card->lock, flags);
+
return mask;
}
-/* this needs to be fixed to deal with the dual apus/buffers */
-#if 0
static int trident_mmap(struct file *file, struct vm_area_struct *vma)
{
- struct trident_state *s = (struct trident_state *)file->private_data;
- struct dmabuf *db;
+ struct trident_state *state = (struct trident_state *)file->private_data;
+ struct dmabuf *dmabuf;
int ret;
unsigned long size;
- VALIDATE_STATE(s);
+ VALIDATE_STATE(state);
if (vma->vm_flags & VM_WRITE) {
- if ((ret = prog_dmabuf(s, 0)) != 0)
+ if ((ret = prog_dmabuf(state, 0)) != 0)
return ret;
- db = &s->dma_dac;
+ dmabuf = &state->dma_dac;
} else if (vma->vm_flags & VM_READ) {
- if ((ret = prog_dmabuf(s, 1)) != 0)
+ if ((ret = prog_dmabuf(state, 1)) != 0)
return ret;
- db = &s->dma_adc;
+ dmabuf = &state->dma_adc;
} else
return -EINVAL;
- if (vma->vm_offset != 0)
+
+ if (vma->vm_pgoff != 0)
return -EINVAL;
size = vma->vm_end - vma->vm_start;
- if (size > (PAGE_SIZE << db->buforder))
+ if (size > (PAGE_SIZE << dmabuf->buforder))
return -EINVAL;
- if (remap_page_range(vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot))
+ if (remap_page_range(vma->vm_start, virt_to_phys(dmabuf->rawbuf),
+ size, vma->vm_page_prot))
return -EAGAIN;
- db->mapped = 1;
+ dmabuf->mapped = 1;
+
return 0;
}
-#endif
static int trident_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
- struct trident_state *s = (struct trident_state *)file->private_data;
+ struct trident_state *state = (struct trident_state *)file->private_data;
unsigned long flags;
audio_buf_info abinfo;
count_info cinfo;
int val, mapped, ret;
- unsigned char fmtm, fmtd;
- VALIDATE_STATE(s);
- mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) ||
- ((file->f_mode & FMODE_READ) && s->dma_adc.mapped);
+ VALIDATE_STATE(state);
+ mapped = ((file->f_mode & FMODE_WRITE) && state->dma_dac.mapped) ||
+ ((file->f_mode & FMODE_READ) && state->dma_adc.mapped);
#ifdef DEBUG
- printk("trident: trident_ioctl, command = %2d, arg = 0x%08x\n",_IOC_NR(cmd),
- arg ? *(int *)arg : 0);
+ printk("trident: trident_ioctl, command = %2d, arg = 0x%08x\n",
+ _IOC_NR(cmd), arg ? *(int *)arg : 0);
#endif
switch (cmd)
@@ -2378,189 +1408,218 @@ static int trident_ioctl(struct inode *inode, struct file *file, unsigned int cm
case SNDCTL_DSP_RESET:
if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
+ stop_dac(state);
synchronize_irq();
- s->dma_dac.swptr = s->dma_dac.hwptr = 0;
- s->dma_dac.count = s->dma_dac.total_bytes = 0;
+ state->dma_dac.ready = 0;
+ state->dma_dac.swptr = state->dma_dac.hwptr = 0;
+ state->dma_dac.count = state->dma_dac.total_bytes = 0;
}
if (file->f_mode & FMODE_READ) {
- stop_adc(s);
+ stop_adc(state);
synchronize_irq();
- s->dma_adc.swptr = s->dma_adc.hwptr = 0;
- s->dma_adc.count = s->dma_adc.total_bytes = 0;
+ state->dma_adc.ready = 0;
+ state->dma_adc.swptr = state->dma_adc.hwptr = 0;
+ state->dma_adc.count = state->dma_adc.total_bytes = 0;
}
return 0;
case SNDCTL_DSP_SYNC:
if (file->f_mode & FMODE_WRITE)
- return drain_dac(s, file->f_flags & O_NONBLOCK);
+ return drain_dac(state, file->f_flags & O_NONBLOCK);
return 0;
- case SNDCTL_DSP_SPEED:
+ case SNDCTL_DSP_SPEED: /* set smaple rate */
get_user_ret(val, (int *)arg, -EFAULT);
if (val >= 0) {
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- s->dma_adc.ready = 0;
- trident_set_adc_rate(s, val, 1);
- }
if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- s->dma_dac.ready = 0;
- trident_set_dac_rate(s, val, 1);
+ stop_dac(state);
+ state->dma_dac.ready = 0;
+ spin_lock_irqsave(&state->card->lock, flags);
+ trident_set_dac_rate(state, val);
+ spin_unlock_irqrestore(&state->card->lock, flags);
+ }
+ if (file->f_mode & FMODE_READ) {
+ stop_adc(state);
+ state->dma_adc.ready = 0;
+ spin_lock_irqsave(&state->card->lock, flags);
+ trident_set_adc_rate(state, val);
+ spin_unlock_irqrestore(&state->card->lock, flags);
}
}
- return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac,
+ return put_user((file->f_mode & FMODE_READ) ? state->dma_adc.rate :
+ state->dma_dac.rate,
(int *)arg);
- case SNDCTL_DSP_STEREO:
+ case SNDCTL_DSP_STEREO: /* set stereo or mono channel */
get_user_ret(val, (int *)arg, -EFAULT);
- fmtd = 0;
- fmtm = ~0;
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- s->dma_adc.ready = 0;
+ if (file->f_mode & FMODE_WRITE) {
+ stop_dac(state);
+ state->dma_dac.ready = 0;
if (val)
- fmtd |= TRIDENT_FMT_STEREO << TRIDENT_ADC_SHIFT;
+ state->dma_dac.fmt |= TRIDENT_FMT_STEREO;
else
- fmtm &= ~(TRIDENT_FMT_STEREO << TRIDENT_ADC_SHIFT);
+ state->dma_dac.fmt &= ~TRIDENT_FMT_STEREO;
}
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- s->dma_dac.ready = 0;
+ if (file->f_mode & FMODE_READ) {
+ stop_adc(state);
+ state->dma_adc.ready = 0;
if (val)
- fmtd |= TRIDENT_FMT_STEREO << TRIDENT_DAC_SHIFT;
+ state->dma_adc.fmt |= TRIDENT_FMT_STEREO;
else
- fmtm &= ~(TRIDENT_FMT_STEREO << TRIDENT_DAC_SHIFT);
+ state->dma_adc.fmt &= ~TRIDENT_FMT_STEREO;
}
- set_fmt(s, fmtm, fmtd);
return 0;
case SNDCTL_DSP_GETBLKSIZE:
if (file->f_mode & FMODE_WRITE) {
- if ((val = prog_dmabuf(s, 0)))
+ if ((val = prog_dmabuf(state, 0)))
return val;
- return put_user(s->dma_dac.fragsize, (int *)arg);
+ return put_user(state->dma_dac.fragsize, (int *)arg);
+ }
+ if (file->f_mode & FMODE_READ) {
+ if ((val = prog_dmabuf(state, 1)))
+ return val;
+ return put_user(state->dma_adc.fragsize, (int *)arg);
}
- if ((val = prog_dmabuf(s, 1)))
- return val;
- return put_user(s->dma_adc.fragsize, (int *)arg);
- case SNDCTL_DSP_GETFMTS: /* Returns a mask */
- return put_user(AFMT_S8|AFMT_S16_LE, (int *)arg);
- case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
+ case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format*/
+ return put_user(AFMT_S16_LE|AFMT_U16_LE|AFMT_S8|AFMT_U8, (int *)arg);
+
+ case SNDCTL_DSP_SETFMT: /* Select sample format */
get_user_ret(val, (int *)arg, -EFAULT);
if (val != AFMT_QUERY) {
- fmtd = 0;
- fmtm = ~0;
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- s->dma_adc.ready = 0;
- /* fixed at 16bit for now */
- fmtd |= TRIDENT_FMT_16BIT << TRIDENT_ADC_SHIFT;
-#if 0
+ if (file->f_mode & FMODE_WRITE) {
+ stop_dac(state);
+ state->dma_dac.ready = 0;
if (val == AFMT_S16_LE)
- fmtd |= TRIDENT_FMT_16BIT << TRIDENT_ADC_SHIFT;
+ state->dma_dac.fmt |= TRIDENT_FMT_16BIT;
else
- fmtm &= ~(TRIDENT_FMT_16BIT << TRIDENT_ADC_SHIFT);
-#endif
+ state->dma_dac.fmt &= ~TRIDENT_FMT_16BIT;
}
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- s->dma_dac.ready = 0;
+ if (file->f_mode & FMODE_READ) {
+ stop_adc(state);
+ state->dma_adc.ready = 0;
if (val == AFMT_S16_LE)
- fmtd |= TRIDENT_FMT_16BIT << TRIDENT_DAC_SHIFT;
+ state->dma_adc.fmt |= TRIDENT_FMT_16BIT;
else
- fmtm &= ~(TRIDENT_FMT_16BIT << TRIDENT_DAC_SHIFT);
+ state->dma_adc.fmt &= ~TRIDENT_FMT_16BIT;
}
- set_fmt(s, fmtm, fmtd);
}
- return put_user((s->fmt & ((file->f_mode & FMODE_READ) ?
- (TRIDENT_FMT_16BIT << TRIDENT_ADC_SHIFT) :
- (TRIDENT_FMT_16BIT << TRIDENT_DAC_SHIFT))) ?
- AFMT_S16_LE : AFMT_S8, (int *)arg);
+ if (file->f_mode & FMODE_WRITE)
+ return put_user((state->dma_dac.fmt & TRIDENT_FMT_16BIT) ?
+ AFMT_S16_LE : AFMT_U8, (int *)arg);
+ else
+ return put_user((state->dma_adc.fmt & TRIDENT_FMT_16BIT) ?
+ AFMT_S16_LE : AFMT_U8, (int *)arg);
case SNDCTL_DSP_CHANNELS:
get_user_ret(val, (int *)arg, -EFAULT);
if (val != 0) {
- fmtd = 0;
- fmtm = ~0;
-
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- s->dma_adc.ready = 0;
+ if (file->f_mode & FMODE_WRITE) {
+ stop_dac(state);
+ state->dma_dac.ready = 0;
if (val >= 2)
- fmtd |= TRIDENT_FMT_STEREO << TRIDENT_ADC_SHIFT;
+ state->dma_dac.fmt |= TRIDENT_FMT_STEREO;
else
- fmtm &= ~(TRIDENT_FMT_STEREO << TRIDENT_ADC_SHIFT);
+ state->dma_dac.fmt &= ~TRIDENT_FMT_STEREO;
}
-
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- s->dma_dac.ready = 0;
+ if (file->f_mode & FMODE_READ) {
+ stop_adc(state);
+ state->dma_adc.ready = 0;
if (val >= 2)
- fmtd |= TRIDENT_FMT_STEREO << TRIDENT_DAC_SHIFT;
+ state->dma_adc.fmt |= TRIDENT_FMT_STEREO;
else
- fmtm &= ~(TRIDENT_FMT_STEREO << TRIDENT_DAC_SHIFT);
+ state->dma_adc.fmt &= ~TRIDENT_FMT_STEREO;
}
- set_fmt(s, fmtm, fmtd);
}
- return put_user((s->fmt & ((file->f_mode & FMODE_READ) ?
- (TRIDENT_FMT_STEREO << TRIDENT_ADC_SHIFT) :
- (TRIDENT_FMT_STEREO << TRIDENT_DAC_SHIFT))) ? 2 : 1, (int *)arg);
+ if (file->f_mode & FMODE_WRITE)
+ return put_user((state->dma_dac.fmt & TRIDENT_FMT_STEREO) ? 2 : 1,
+ (int *)arg);
+ else
+ return put_user((state->dma_adc.fmt & TRIDENT_FMT_STEREO) ? 2 : 1,
+ (int *)arg);
case SNDCTL_DSP_POST:
+ /* FIXME: the same as RESET ?? */
return 0;
case SNDCTL_DSP_SUBDIVIDE:
- if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) ||
- (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision))
+ if ((file->f_mode & FMODE_READ && state->dma_adc.subdivision) ||
+ (file->f_mode & FMODE_WRITE && state->dma_dac.subdivision))
return -EINVAL;
get_user_ret(val, (int *)arg, -EFAULT);
if (val != 1 && val != 2 && val != 4)
return -EINVAL;
if (file->f_mode & FMODE_READ)
- s->dma_adc.subdivision = val;
+ state->dma_adc.subdivision = val;
if (file->f_mode & FMODE_WRITE)
- s->dma_dac.subdivision = val;
+ state->dma_dac.subdivision = val;
return 0;
case SNDCTL_DSP_SETFRAGMENT:
get_user_ret(val, (int *)arg, -EFAULT);
if (file->f_mode & FMODE_READ) {
- s->dma_adc.ossfragshift = val & 0xffff;
- s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff;
- if (s->dma_adc.ossfragshift < 4)
- s->dma_adc.ossfragshift = 4;
- if (s->dma_adc.ossfragshift > 15)
- s->dma_adc.ossfragshift = 15;
- if (s->dma_adc.ossmaxfrags < 4)
- s->dma_adc.ossmaxfrags = 4;
+ state->dma_adc.ossfragshift = val & 0xffff;
+ state->dma_adc.ossmaxfrags = (val >> 16) & 0xffff;
+ if (state->dma_adc.ossfragshift < 4)
+ state->dma_adc.ossfragshift = 4;
+ if (state->dma_adc.ossfragshift > 15)
+ state->dma_adc.ossfragshift = 15;
+ if (state->dma_adc.ossmaxfrags < 4)
+ state->dma_adc.ossmaxfrags = 4;
}
if (file->f_mode & FMODE_WRITE) {
- s->dma_dac.ossfragshift = val & 0xffff;
- s->dma_dac.ossmaxfrags = (val >> 16) & 0xffff;
- if (s->dma_dac.ossfragshift < 4)
- s->dma_dac.ossfragshift = 4;
- if (s->dma_dac.ossfragshift > 15)
- s->dma_dac.ossfragshift = 15;
- if (s->dma_dac.ossmaxfrags < 4)
- s->dma_dac.ossmaxfrags = 4;
+ state->dma_dac.ossfragshift = val & 0xffff;
+ state->dma_dac.ossmaxfrags = (val >> 16) & 0xffff;
+ if (state->dma_dac.ossfragshift < 4)
+ state->dma_dac.ossfragshift = 4;
+ if (state->dma_dac.ossfragshift > 15)
+ state->dma_dac.ossfragshift = 15;
+ if (state->dma_dac.ossmaxfrags < 4)
+ state->dma_dac.ossmaxfrags = 4;
}
return 0;
- case SNDCTL_DSP_GETCAPS:
- return put_user(0/* DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP */,
- (int *)arg);
-
- case SNDCTL_DSP_SETDUPLEX:
- /* XXX fix */
+ case SNDCTL_DSP_GETOSPACE:
+ if (!(file->f_mode & FMODE_WRITE))
+ return -EINVAL;
+ if (!state->dma_dac.enable && (val = prog_dmabuf(state, 0)) != 0)
+ return val;
+ spin_lock_irqsave(&state->card->lock, flags);
+ trident_update_ptr(state);
+ abinfo.fragsize = state->dma_dac.fragsize;
+ abinfo.bytes = state->dma_dac.dmasize - state->dma_dac.count;
+ abinfo.fragstotal = state->dma_dac.numfrag;
+ abinfo.fragments = abinfo.bytes >> state->dma_dac.fragshift;
+ spin_unlock_irqrestore(&state->card->lock, flags);
+ return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
+
+ case SNDCTL_DSP_GETISPACE:
+ if (!(file->f_mode & FMODE_READ))
+ return -EINVAL;
+ if (!state->dma_adc.enable && (val = prog_dmabuf(state, 1)) != 0)
+ return val;
+ spin_lock_irqsave(&state->card->lock, flags);
+ trident_update_ptr(state);
+ abinfo.fragsize = state->dma_adc.fragsize;
+ abinfo.bytes = state->dma_adc.count;
+ abinfo.fragstotal = state->dma_adc.numfrag;
+ abinfo.fragments = abinfo.bytes >> state->dma_adc.fragshift;
+ spin_unlock_irqrestore(&state->card->lock, flags);
+ return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
+
+ case SNDCTL_DSP_NONBLOCK:
+ file->f_flags |= O_NONBLOCK;
return 0;
+ case SNDCTL_DSP_GETCAPS:
+ return put_user(/* DSP_CAP_DUPLEX|*/DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP,
+ (int *)arg);
+
case SNDCTL_DSP_GETTRIGGER:
val = 0;
- if (file->f_mode & FMODE_READ && s->enable & TRIDENT_ENABLE_RE)
+ if (file->f_mode & FMODE_READ && state->dma_adc.enable)
val |= PCM_ENABLE_INPUT;
- if (file->f_mode & FMODE_WRITE && s->enable & TRIDENT_ENABLE_PE)
+ if (file->f_mode & FMODE_WRITE && state->dma_dac.enable)
val |= PCM_ENABLE_OUTPUT;
return put_user(val, (int *)arg);
@@ -2568,106 +1627,86 @@ static int trident_ioctl(struct inode *inode, struct file *file, unsigned int cm
get_user_ret(val, (int *)arg, -EFAULT);
if (file->f_mode & FMODE_READ) {
if (val & PCM_ENABLE_INPUT) {
- if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
+ if (!state->dma_adc.ready && (ret = prog_dmabuf(state, 1)))
return ret;
- start_adc(s);
+ start_adc(state);
}
else
- stop_adc(s);
+ stop_adc(state);
}
if (file->f_mode & FMODE_WRITE) {
if (val & PCM_ENABLE_OUTPUT) {
- if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
+ if (!state->dma_dac.ready && (ret = prog_dmabuf(state, 0)))
return ret;
- start_dac(s);
+ start_dac(state);
}
else
- stop_dac(s);
+ stop_dac(state);
}
return 0;
- case SNDCTL_DSP_GETOSPACE:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- if (!(s->enable & TRIDENT_ENABLE_PE) && (val = prog_dmabuf(s, 0)) != 0)
- return val;
- spin_lock_irqsave(&s->card->lock, flags);
- trident_update_ptr(s);
- abinfo.fragsize = s->dma_dac.fragsize;
- abinfo.bytes = s->dma_dac.dmasize - s->dma_dac.count;
- abinfo.fragstotal = s->dma_dac.numfrag;
- abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;
- spin_unlock_irqrestore(&s->card->lock, flags);
- return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-
- case SNDCTL_DSP_GETISPACE:
- if (!(file->f_mode & FMODE_READ))
- return -EINVAL;
- if (!(s->enable & TRIDENT_ENABLE_RE) && (val = prog_dmabuf(s, 1)) != 0)
- return val;
- spin_lock_irqsave(&s->card->lock, flags);
- trident_update_ptr(s);
- abinfo.fragsize = s->dma_adc.fragsize;
- abinfo.bytes = s->dma_adc.count;
- abinfo.fragstotal = s->dma_adc.numfrag;
- abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift;
- spin_unlock_irqrestore(&s->card->lock, flags);
- return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-
- case SNDCTL_DSP_NONBLOCK:
- file->f_flags |= O_NONBLOCK;
- return 0;
-
- case SNDCTL_DSP_GETODELAY:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- spin_lock_irqsave(&s->card->lock, flags);
- trident_update_ptr(s);
- val = s->dma_dac.count;
- spin_unlock_irqrestore(&s->card->lock, flags);
- return put_user(val, (int *)arg);
-
case SNDCTL_DSP_GETIPTR:
if (!(file->f_mode & FMODE_READ))
return -EINVAL;
- spin_lock_irqsave(&s->card->lock, flags);
- trident_update_ptr(s);
- cinfo.bytes = s->dma_adc.total_bytes;
- cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift;
- cinfo.ptr = s->dma_adc.hwptr;
- if (s->dma_adc.mapped)
- s->dma_adc.count &= s->dma_adc.fragsize-1;
- spin_unlock_irqrestore(&s->card->lock, flags);
+ spin_lock_irqsave(&state->card->lock, flags);
+ trident_update_ptr(state);
+ cinfo.bytes = state->dma_adc.total_bytes;
+ cinfo.blocks = state->dma_adc.count >> state->dma_adc.fragshift;
+ cinfo.ptr = state->dma_adc.hwptr;
+ if (state->dma_adc.mapped)
+ state->dma_adc.count &= state->dma_adc.fragsize-1;
+ spin_unlock_irqrestore(&state->card->lock, flags);
return copy_to_user((void *)arg, &cinfo, sizeof(cinfo));
case SNDCTL_DSP_GETOPTR:
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
- spin_lock_irqsave(&s->card->lock, flags);
- trident_update_ptr(s);
- cinfo.bytes = s->dma_dac.total_bytes;
- cinfo.blocks = s->dma_dac.count >> s->dma_dac.fragshift;
- cinfo.ptr = s->dma_dac.hwptr;
- if (s->dma_dac.mapped)
- s->dma_dac.count &= s->dma_dac.fragsize-1;
- spin_unlock_irqrestore(&s->card->lock, flags);
+ spin_lock_irqsave(&state->card->lock, flags);
+ trident_update_ptr(state);
+ cinfo.bytes = state->dma_dac.total_bytes;
+ cinfo.blocks = state->dma_dac.count >> state->dma_dac.fragshift;
+ cinfo.ptr = state->dma_dac.hwptr;
+ if (state->dma_dac.mapped)
+ state->dma_dac.count &= state->dma_dac.fragsize-1;
+ spin_unlock_irqrestore(&state->card->lock, flags);
return copy_to_user((void *)arg, &cinfo, sizeof(cinfo));
+ case SNDCTL_DSP_SETDUPLEX:
+ /* XXX fix */
+ return 0;
+
+ case SNDCTL_DSP_GETODELAY:
+ if (!(file->f_mode & FMODE_WRITE))
+ return -EINVAL;
+ spin_lock_irqsave(&state->card->lock, flags);
+ trident_update_ptr(state);
+ val = state->dma_dac.count;
+ spin_unlock_irqrestore(&state->card->lock, flags);
+ return put_user(val, (int *)arg);
+
case SOUND_PCM_READ_RATE:
- return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, (int *)arg);
+ return put_user((file->f_mode & FMODE_READ) ? state->dma_adc.rate :
+ state->dma_dac.rate, (int *)arg);
case SOUND_PCM_READ_CHANNELS:
- return put_user((s->fmt & ((file->f_mode & FMODE_READ) ?
- (TRIDENT_FMT_STEREO << TRIDENT_ADC_SHIFT) :
- (TRIDENT_FMT_STEREO << TRIDENT_DAC_SHIFT))) ? 2 : 1, (int *)arg);
+ if (file->f_mode & FMODE_WRITE)
+ return put_user((state->dma_dac.fmt & TRIDENT_FMT_STEREO) ? 2 : 1,
+ (int *)arg);
+ else
+ return put_user((state->dma_adc.fmt & TRIDENT_FMT_STEREO) ? 2 : 1,
+ (int *)arg);
case SOUND_PCM_READ_BITS:
- return put_user((s->fmt & ((file->f_mode & FMODE_READ) ?
- (TRIDENT_FMT_16BIT << TRIDENT_ADC_SHIFT) :
- (TRIDENT_FMT_16BIT << TRIDENT_DAC_SHIFT))) ? 16 : 8, (int *)arg);
-
- case SOUND_PCM_WRITE_FILTER:
+ if (file->f_mode & FMODE_WRITE)
+ return put_user((state->dma_dac.fmt & TRIDENT_FMT_16BIT) ?
+ AFMT_S16_LE : AFMT_U8, (int *)arg);
+ else
+ return put_user((state->dma_adc.fmt & TRIDENT_FMT_16BIT) ?
+ AFMT_S16_LE : AFMT_U8, (int *)arg);
+ case SNDCTL_DSP_MAPINBUF:
+ case SNDCTL_DSP_MAPOUTBUF:
case SNDCTL_DSP_SETSYNCRO:
+ case SOUND_PCM_WRITE_FILTER:
case SOUND_PCM_READ_FILTER:
return -EINVAL;
@@ -2681,13 +1720,12 @@ static int trident_open(struct inode *inode, struct file *file)
int minor = MINOR(inode->i_rdev);
struct trident_card *card = devs;
struct trident_state *state = NULL;
- unsigned char fmtm = ~0, fmts = 0;
/* find an avaiable virtual channel (instance of /dev/dsp) */
while (card != NULL) {
- for (i = 0; i < NR_DSPS; i++) {
- if (card->channels[i] == NULL) {
- state = card->channels[i] = (struct trident_state *)
+ for (i = 0; i < NR_HW_CH; i++) {
+ if (card->states[i] == NULL) {
+ state = card->states[i] = (struct trident_state *)
kmalloc(sizeof(struct trident_state), GFP_KERNEL);
if (state == NULL)
return -ENOMEM;
@@ -2704,18 +1742,18 @@ static int trident_open(struct inode *inode, struct file *file)
found_virt:
/* found a free virtual channel, allocate hardware channels */
if (file->f_mode & FMODE_READ)
- if ((state->dma_adc.chan = trident_alloc_pcm_channel(card)) == -1) {
- kfree (card->channels[i]);
- card->channels[i] = NULL;;
+ if ((state->dma_adc.channel = trident_alloc_pcm_channel(card)) == NULL) {
+ kfree (card->states[i]);
+ card->states[i] = NULL;;
return -ENODEV;
}
if (file->f_mode & FMODE_WRITE)
- if ((state->dma_dac.chan = trident_alloc_pcm_channel(card)) == -1) {
- kfree (card->channels[i]);
- card->channels[i] = NULL;
+ if ((state->dma_dac.channel = trident_alloc_pcm_channel(card)) == NULL) {
+ kfree (card->states[i]);
+ card->states[i] = NULL;
if (file->f_mode & FMODE_READ)
/* free previously allocated hardware channel */
- trident_free_pcm_channel(card, state->dma_adc.chan);
+ trident_free_pcm_channel(card, state->dma_adc.channel->num);
return -ENODEV;
}
@@ -2732,30 +1770,27 @@ static int trident_open(struct inode *inode, struct file *file)
/* set default sample format, Refer to OSS Programmer's Guide */
if (file->f_mode & FMODE_READ) {
- /* fmtm &= ~((TRIDENT_FMT_STEREO | TRIDENT_FMT_16BIT) << TRIDENT_ADC_SHIFT);
- if ((minor & 0xf) == SND_DEV_DSP16)
- fmts |= TRIDENT_FMT_16BIT << TRIDENT_ADC_SHIFT; */
- fmtm = (TRIDENT_FMT_STEREO|TRIDENT_FMT_16BIT) << TRIDENT_ADC_SHIFT;
+ /* FIXME: Trident 4d can only record in singed 16-bits stereo, 48kHz sample */
+ state->dma_adc.fmt = TRIDENT_FMT_STEREO|TRIDENT_FMT_16BIT;
state->dma_adc.ossfragshift = 0;
state->dma_adc.ossmaxfrags = 0;
state->dma_adc.subdivision = 0;
- trident_set_adc_rate(state, 8000, 0);
+ trident_set_adc_rate(state, 48000);
}
/* according to OSS document, /dev/dsp should be default to unsigned 8-bits,
mono, with sample rate 8kHz and /dev/dspW will accept 16-bits sample */
if (file->f_mode & FMODE_WRITE) {
- fmtm &= ~((TRIDENT_FMT_STEREO | TRIDENT_FMT_16BIT) << TRIDENT_DAC_SHIFT);
+ state->dma_dac.fmt &= ~TRIDENT_FMT_MASK;
if ((minor & 0xf) == SND_DEV_DSP16)
- fmts |= TRIDENT_FMT_16BIT << TRIDENT_DAC_SHIFT;
+ state->dma_dac.fmt |= TRIDENT_FMT_16BIT;
state->dma_dac.ossfragshift = 0;
state->dma_dac.ossmaxfrags = 0;
state->dma_dac.subdivision = 0;
- trident_set_dac_rate(state, 8000, 1);
+ trident_set_dac_rate(state, 8000);
}
- set_fmt(state, fmtm, fmts);
- state->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
+ state->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
up(&state->open_sem);
//FIXME put back in
@@ -2768,8 +1803,12 @@ static int trident_release(struct inode *inode, struct file *file)
struct trident_state *state = (struct trident_state *)file->private_data;
VALIDATE_STATE(state);
- if (file->f_mode & FMODE_WRITE)
+
+
+ if (file->f_mode & FMODE_WRITE) {
+ trident_clear_tail(state);
drain_dac(state, file->f_flags & O_NONBLOCK);
+ }
/* stop DMA state machine and free DMA buffers/channels */
down(&state->open_sem);
@@ -2777,16 +1816,16 @@ static int trident_release(struct inode *inode, struct file *file)
if (file->f_mode & FMODE_WRITE) {
stop_dac(state);
dealloc_dmabuf(&state->dma_dac);
- trident_free_pcm_channel(state->card, state->dma_dac.chan);
+ trident_free_pcm_channel(state->card, state->dma_dac.channel->num);
}
if (file->f_mode & FMODE_READ) {
stop_adc(state);
dealloc_dmabuf(&state->dma_adc);
- trident_free_pcm_channel(state->card, state->dma_adc.chan);
+ trident_free_pcm_channel(state->card, state->dma_adc.channel->num);
}
- kfree(state->card->channels[state->virt]);
- state->card->channels[state->virt] = NULL;
+ kfree(state->card->states[state->virt]);
+ state->card->states[state->virt] = NULL;
state->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
/* we're covered by the open_sem */
@@ -2796,6 +1835,7 @@ static int trident_release(struct inode *inode, struct file *file)
//MOD_DEC_USE_COUNT;
return 0;
}
+
static /*const*/ struct file_operations trident_audio_fops = {
&trident_llseek,
&trident_read,
@@ -2803,7 +1843,7 @@ static /*const*/ struct file_operations trident_audio_fops = {
NULL, /* readdir */
&trident_poll,
&trident_ioctl,
- NULL, /* XXX &trident_mmap, */
+ &trident_mmap,
&trident_open,
NULL, /* flush */
&trident_release,
@@ -2812,15 +1852,238 @@ static /*const*/ struct file_operations trident_audio_fops = {
NULL, /* lock */
};
-/* install the driver, we do not allocate hardware channel nor DMA buffer now, they are defered
- untill open time */
-static int trident_install(struct pci_dev *pcidev, struct pci_audio_info *pci_info)
+/* trident specific AC97 functions */
+/* Write AC97 mixer registers */
+static void trident_ac97_set(struct ac97_codec *codec, u8 reg, u16 val)
+{
+ struct trident_card *card = (struct trident_card *)codec->private_data;
+ unsigned int address, mask, busy;
+ unsigned short count = 0xffff;
+ unsigned long flags;
+ u32 data;
+
+ data = ((u32) val) << 16;
+
+ switch (card->pci_id)
+ {
+ default:
+ case PCI_DEVICE_ID_SI_7018:
+ address = SI_AC97_WRITE;
+ mask = SI_AC97_BUSY_WRITE | SI_AC97_AUDIO_BUSY;
+ if (codec->id)
+ mask |= SI_AC97_SECONDARY;
+ busy = SI_AC97_BUSY_WRITE;
+ break;
+ case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
+ address = DX_ACR0_AC97_W;
+ mask = busy = DX_AC97_BUSY_WRITE;
+ break;
+ case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
+ address = NX_ACR1_AC97_W;
+ mask = NX_AC97_BUSY_WRITE;
+ if (codec->id)
+ mask |= NX_AC97_WRITE_SECONDARY;
+ busy = NX_AC97_BUSY_WRITE;
+ break;
+ }
+
+ spin_lock_irqsave(&card->lock, flags);
+ do {
+ if ((inw(TRID_REG(card, address)) & busy) == 0)
+ break;
+ } while (count--);
+
+
+ data |= (mask | (reg & AC97_REG_ADDR));
+
+ if (count == 0) {
+ printk(KERN_ERR "trident: AC97 CODEC write timed out.\n");
+ spin_unlock_irqrestore(&card->lock, flags);
+ return;
+ }
+
+ outl(data, TRID_REG(card, address));
+ spin_unlock_irqrestore(&card->lock, flags);
+}
+
+/* Read AC97 codec registers */
+static u16 trident_ac97_get(struct ac97_codec *codec, u8 reg)
+{
+ struct trident_card *card = (struct trident_card *)codec->private_data;
+ unsigned int address, mask, busy;
+ unsigned short count = 0xffff;
+ unsigned long flags;
+ u32 data;
+
+ switch (card->pci_id)
+ {
+ default:
+ case PCI_DEVICE_ID_SI_7018:
+ address = SI_AC97_READ;
+ mask = SI_AC97_BUSY_READ | SI_AC97_AUDIO_BUSY;
+ if (codec->id)
+ mask |= SI_AC97_SECONDARY;
+ busy = SI_AC97_BUSY_READ;
+ break;
+ case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
+ address = DX_ACR1_AC97_R;
+ mask = busy = DX_AC97_BUSY_READ;
+ break;
+ case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
+ if (codec->id)
+ address = NX_ACR3_AC97_R_SECONDARY;
+ else
+ address = NX_ACR2_AC97_R_PRIMARY;
+ mask = NX_AC97_BUSY_READ;
+ busy = 0x0c00;
+ break;
+ }
+
+ data = (mask | (reg & AC97_REG_ADDR));
+
+ spin_lock_irqsave(&card->lock, flags);
+ outl(data, TRID_REG(card, address));
+ do {
+ data = inl(TRID_REG(card, address));
+ if ((data & busy) == 0)
+ break;
+ } while (count--);
+ spin_unlock_irqrestore(&card->lock, flags);
+
+ if (count == 0) {
+ printk(KERN_ERR "trident: AC97 CODEC read timed out.\n");
+ data = 0;
+ }
+ return ((u16) (data >> 16));
+}
+
+/* OSS /dev/mixer file operation methods */
+static int trident_open_mixdev(struct inode *inode, struct file *file)
{
int i;
+ int minor = MINOR(inode->i_rdev);
+ struct trident_card *card = devs;
+
+ for (card = devs; card != NULL; card = card->next)
+ for (i = 0; i < NR_AC97; i++)
+ if (card->ac97_codec[i] != NULL &&
+ card->ac97_codec[i]->dev_mixer == minor)
+ goto match;
+
+ if (!card)
+ return -ENODEV;
+
+ match:
+ file->private_data = card->ac97_codec[i];
+
+ //FIXME put back in
+ //MOD_INC_USE_COUNT;
+ return 0;
+}
+
+static int trident_release_mixdev(struct inode *inode, struct file *file)
+{
+ //struct ac97_codec *codec = (struct ac97_codec *)file->private_data;
+
+ //FIXME put back in
+ //MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+static int trident_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct ac97_codec *codec = (struct ac97_codec *)file->private_data;
+
+ return codec->mixer_ioctl(codec, cmd, arg);
+}
+
+static /*const*/ struct file_operations trident_mixer_fops = {
+ &trident_llseek,
+ NULL, /* read */
+ NULL, /* write */
+ NULL, /* readdir */
+ NULL, /* poll */
+ &trident_ioctl_mixdev,
+ NULL, /* mmap */
+ &trident_open_mixdev,
+ NULL, /* flush */
+ &trident_release_mixdev,
+ NULL, /* fsync */
+ NULL, /* fasync */
+ NULL, /* lock */
+};
+
+/* AC97 codec initialisation. */
+static int __init trident_ac97_init(struct trident_card *card)
+{
+ int num_ac97 = 0;
+ int ready_2nd = 0;
+ struct ac97_codec *codec;
+
+ /* initialize controller side of AC link, and find out if secondary codes
+ really exist */
+ switch (card->pci_id)
+ {
+ case PCI_DEVICE_ID_SI_7018:
+ /* disable AC97 GPIO interrupt */
+ outl(0x00, TRID_REG(card, SI_AC97_GPIO));
+ /* stop AC97 cold reset process */
+ outl(PCMOUT|SECONDARY_ID, TRID_REG(card, SI_SERIAL_INTF_CTRL));
+ ready_2nd = inl(TRID_REG(card, SI_SERIAL_INTF_CTRL));
+ ready_2nd &= SI_AC97_SECONDARY_READY;
+ break;
+ case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
+ /* playback on */
+ outl(DX_AC97_PLAYBACK, TRID_REG(card, DX_ACR2_AC97_COM_STAT));
+ break;
+ case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
+ /* enable AC97 Output Slot 3,4 (PCM Left/Right Playback) */
+ outl(NX_AC97_PCM_OUTPUT, TRID_REG(card, NX_ACR0_AC97_COM_STAT));
+ ready_2nd = inl(TRID_REG(card, NX_ACR0_AC97_COM_STAT));
+ ready_2nd &= NX_AC97_SECONDARY_READY;
+ break;
+ }
+
+ for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) {
+ if ((codec = kmalloc(sizeof(struct ac97_codec), GFP_KERNEL)) == NULL)
+ return -1;
+ memset(codec, 0, sizeof(struct ac97_codec));
+
+ /* initialize some basic codec information, other fields will be filled
+ in ac97_probe_codec */
+ codec->private_data = card;
+ codec->id = num_ac97;
+ /* controller specific low level AC97 access function */
+ codec->codec_read = trident_ac97_get;
+ codec->codec_write = trident_ac97_set;
+
+ if (ac97_probe_codec(codec) == 0)
+ break;
+
+ if ((codec->dev_mixer = register_sound_mixer(&trident_mixer_fops, -1)) < 0) {
+ printk(KERN_ERR "trident: couldn't register mixer!\n");
+ kfree(codec);
+ break;
+ }
+
+ card->ac97_codec[num_ac97] = codec;
+
+ /* if there is no secondary codec at all, don't probe any more */
+ if (!ready_2nd)
+ return num_ac97+1;
+ }
+
+ return num_ac97;
+}
+
+/* install the driver, we do not allocate hardware channel nor DMA buffer now, they are defered
+ untill "ACCESS" time (in prog_dmabuf calles by open/read/write/ioctl/mmap) */
+static int __init trident_install(struct pci_dev *pcidev, struct pci_audio_info *pci_info)
+{
u16 w;
unsigned long iobase;
struct trident_card *card;
- u32 ChanDwordCount;
iobase = pcidev->resource[0].start;
if (check_region(iobase, 256)) {
@@ -2847,30 +2110,12 @@ static int trident_install(struct pci_dev *pcidev, struct pci_audio_info *pci_in
card->irq = pcidev->irq;
card->next = devs;
card->magic = TRIDENT_CARD_MAGIC;
+ card->banks[BANK_A].addresses = &bank_a_addrs;
+ card->banks[BANK_A].bitmap = 0UL;
+ card->banks[BANK_B].addresses = &bank_b_addrs;
+ card->banks[BANK_B].bitmap = 0UL;
spin_lock_init(&card->lock);
- devs = card;
-
- /* ungly stupid thing, remove ASAP */
- ChanDwordCount = card->ChanDwordCount = 2;
- card->ChRegs.lpChStart = card->ChRegs.data;
- card->ChRegs.lpChStop = card->ChRegs.lpChStart + ChanDwordCount;
- card->ChRegs.lpChAint = card->ChRegs.lpChStop + ChanDwordCount;
- card->ChRegs.lpChAinten = card->ChRegs.lpChAint + ChanDwordCount;
- card->ChRegs.lpAChStart = card->ChRegs.lpChAinten + ChanDwordCount;
- card->ChRegs.lpAChStop = card->ChRegs.lpAChStart + ChanDwordCount;
- card->ChRegs.lpAChAint = card->ChRegs.lpAChStop + ChanDwordCount;
- card->ChRegs.lpAChAinten = card->ChRegs.lpAChAint + ChanDwordCount;
- // Assign Bank A addresses.
- card->ChRegs.lpAChStart[0] = T4D_START_A;
- card->ChRegs.lpAChStop[0] = T4D_STOP_A;
- card->ChRegs.lpAChAint[0] = T4D_AINT_A;
- card->ChRegs.lpAChAinten[0] = T4D_AINTEN_A;
- /* Assign Bank B addresses */
- card->ChRegs.lpAChStart[1] = T4D_START_B;
- card->ChRegs.lpAChStop[1] = T4D_STOP_B;
- card->ChRegs.lpAChAint[1] = T4D_AINT_B;
- card->ChRegs.lpAChAinten[1] = T4D_AINTEN_B;
-
+ devs = card;
printk(KERN_INFO "trident: %s found at IO 0x%04lx, IRQ %d\n",
card->pci_info->name, card->iobase, card->irq);
@@ -2883,11 +2128,6 @@ static int trident_install(struct pci_dev *pcidev, struct pci_audio_info *pci_in
kfree(card);
return 0;
}
-
- /* initilize AC97 codec */
- trident_ac97_init(card);
- outl(0x00, TRID_REG(card, T4D_MUSICVOL_WAVEVOL));
-
/* register /dev/dsp */
if ((card->dev_audio = register_sound_dsp(&trident_audio_fops, -1)) < 0) {
printk(KERN_ERR "trident: coundn't register DSP device!\n");
@@ -2896,29 +2136,18 @@ static int trident_install(struct pci_dev *pcidev, struct pci_audio_info *pci_in
kfree(card);
return 0;
}
- /* register /dev/mixer */
- if ((card->dev_mixer = register_sound_mixer(&trident_mixer_fops, -1)) < 0) {
- printk(KERN_ERR "trident: couldn't register mixer!\n");
+ /* initilize AC97 codec and register /dev/mixer */
+ if (trident_ac97_init(card) <= 0) {
unregister_sound_dsp(card->dev_audio);
release_region(iobase, 256);
free_irq(card->irq, card);
kfree(card);
return 0;
- } else {
- /* initilize mixer channels */
- for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
- struct mixer_defaults *md = &mixer_defaults[i];
- if (md->mixer == -1)
- break;
- if (!supported_mixer(card, md->mixer))
- continue;
- set_mixer(card, md->mixer, md->value);
- }
}
+ outl(0x00, TRID_REG(card, T4D_MUSICVOL_WAVEVOL));
/* Enable Address Engine Interrupts */
- trident_enable_end_interrupts(card);
- trident_enable_middle_interrupts(card);
+ trident_enable_loop_interrupts(card);
return 1;
}
@@ -2952,23 +2181,23 @@ static int __init init_trident(void)
MODULE_AUTHOR("Alan Cox, Aaron Holtzman, Ollie Lho");
MODULE_DESCRIPTION("Trident 4DWave/SiS 7018 PCI Audio Driver");
-#ifdef DEBUG
-MODULE_PARM(debug,"i");
-#endif
-
static void __exit cleanup_trident(void)
{
while (devs != NULL) {
+ int i;
/* Kill interrupts, and SP/DIF */
- trident_disable_end_interrupts(devs);
- trident_enable_middle_interrupts(devs);
+ trident_disable_loop_interrupts(devs);
/* free hardware resources */
free_irq(devs->irq, devs);
release_region(devs->iobase, 256);
/* unregister audio devices */
- unregister_sound_mixer(devs->dev_mixer);
+ for (i = 0; i < NR_AC97; i++)
+ if (devs->ac97_codec[i] != NULL) {
+ unregister_sound_mixer(devs->ac97_codec[i]->dev_mixer);
+ kfree (devs->ac97_codec[i]);
+ }
unregister_sound_dsp(devs->dev_audio);
kfree(devs);
@@ -2978,5 +2207,3 @@ static void __exit cleanup_trident(void)
module_init(init_trident);
module_exit(cleanup_trident);
-
-
diff --git a/drivers/sound/trident.h b/drivers/sound/trident.h
index a22e60650..4504cb303 100644
--- a/drivers/sound/trident.h
+++ b/drivers/sound/trident.h
@@ -23,6 +23,7 @@
*
*/
+/* PCI vendor and device ID */
#ifndef PCI_VENDOR_ID_TRIDENT
#define PCI_VENDOR_ID_TRIDENT 0x1023
#endif
@@ -43,118 +44,101 @@
#define PCI_DEVICE_ID_SI_7018 0x7018
#endif
-/*
- * Direct registers
- */
-
#ifndef FALSE
-#define FALSE 0
-#define TRUE 1
+#define FALSE 0
+#define TRUE 1
#endif
-#define TRID_REG( trident, x ) ( (trident) -> iobase + (x) )
-
#define CHANNEL_REGS 5
#define CHANNEL_START 0xe0 // The first bytes of the contiguous register space.
-#define BANK_A 0
-#define BANK_B 1
-#define NUM_BANKS 2
-
-#define ID_4DWAVE_DX 0x2000
-#define ID_4DWAVE_NX 0x2001
-#define ID_SI_7018 0x7018
-
-// Register definitions
-
-// Global registers
-
-// T2 legacy dma control registers.
-#define LEGACY_DMAR0 0x00 // ADR0
-#define LEGACY_DMAR4 0x04 // CNT0
-#define LEGACY_DMAR11 0x0b // MOD
-#define LEGACY_DMAR15 0x0f // MMR
-
-#define T4D_START_A 0x80
-#define T4D_STOP_A 0x84
-#define T4D_DLY_A 0x88
-#define T4D_SIGN_CSO_A 0x8c
-#define T4D_CSPF_A 0x90
-#define T4D_CEBC_A 0x94
-#define T4D_AINT_A 0x98
-#define T4D_EINT_A 0x9c
-#define T4D_LFO_GC_CIR 0xa0
-#define T4D_AINTEN_A 0xa4
-#define T4D_MUSICVOL_WAVEVOL 0xa8
-#define T4D_SBDELTA_DELTA_R 0xac
-#define T4D_MISCINT 0xb0
-#define T4D_START_B 0xb4
-#define T4D_STOP_B 0xb8
-#define T4D_CSPF_B 0xbc
-#define T4D_SBBL_SBCL 0xc0
-#define T4D_SBCTRL_SBE2R_SBDD 0xc4
-#define T4D_STIMER 0xc8
-#define T4D_LFO_B_I2S_DELTA 0xcc
-#define T4D_AINT_B 0xd8
-#define T4D_AINTEN_B 0xdc
-
-// MPU-401 UART
-#define T4D_MPU401_BASE 0x20
-#define T4D_MPUR0 0x20
-#define T4D_MPUR1 0x21
-#define T4D_MPUR2 0x22
-#define T4D_MPUR3 0x23
-
-// S/PDIF Registers
-#define NX_SPCTRL_SPCSO 0x24
-#define NX_SPLBA 0x28
-#define NX_SPESO 0x2c
-#define NX_SPCSTATUS 0x64
-
-// Channel Registers
-
-#define CH_DX_CSO_ALPHA_FMS 0xe0
-#define CH_DX_ESO_DELTA 0xe8
-#define CH_DX_FMC_RVOL_CVOL 0xec
-
-#define CH_NX_DELTA_CSO 0xe0
-#define CH_NX_DELTA_ESO 0xe8
-#define CH_NX_ALPHA_FMS_FMC_RVOL_CVOL 0xec
-
-#define CH_LBA 0xe4
-#define CH_GVSEL_PAN_VOL_CTRL_EC 0xf0
-
-// AC-97 Registers
-
-#define DX_ACR0_AC97_W 0x40
-#define DX_ACR1_AC97_R 0x44
-#define DX_ACR2_AC97_COM_STAT 0x48
-
-#define NX_ACR0_AC97_COM_STAT 0x40
-#define NX_ACR1_AC97_W 0x44
-#define NX_ACR2_AC97_R_PRIMARY 0x48
-#define NX_ACR3_AC97_R_SECONDARY 0x4c
-
-#define SI_AC97_WRITE 0x40
-#define SI_AC97_READ 0x44
-#define SI_SERIAL_INTF_CTRL 0x48
-#define SI_AC97_GPIO 0x4c
+#define BANK_A 0
+#define BANK_B 1
+#define NR_BANKS 2
+
+#define TRIDENT_FMT_STEREO 0x01
+#define TRIDENT_FMT_16BIT 0x02
+#define TRIDENT_FMT_MASK 0x03
+
+#define DMA_ENABLE 0x01
+#define DMA_RUNNING 0x02
+
+/* Register Addresses */
+
+/* operational registers common to DX, NX, 7018 */
+enum trident_op_registers {
+ T4D_START_A = 0x80, T4D_STOP_A = 0x84,
+ T4D_DLY_A = 0x88, T4D_SIGN_CSO_A = 0x8c,
+ T4D_CSPF_A = 0x90, T4D_CEBC_A = 0x94,
+ T4D_AINT_A = 0x98, T4D_EINT_A = 0x9c,
+ T4D_LFO_GC_CIR = 0xa0, T4D_AINTEN_A = 0xa4,
+ T4D_MUSICVOL_WAVEVOL = 0xa8, T4D_SBDELTA_DELTA_R = 0xac,
+ T4D_MISCINT = 0xb0, T4D_START_B = 0xb4,
+ T4D_STOP_B = 0xb8, T4D_CSPF_B = 0xbc,
+ T4D_SBBL_SBCL = 0xc0, T4D_SBCTRL_SBE2R_SBDD = 0xc4,
+ T4D_STIMER = 0xc8, T4D_LFO_B_I2S_DELTA = 0xcc,
+ T4D_AINT_B = 0xd8, T4D_AINTEN_B = 0xdc
+};
-#define AC97_SIGMATEL_DAC2INVERT 0x6E
-#define AC97_SIGMATEL_BIAS1 0x70
-#define AC97_SIGMATEL_BIAS2 0x72
-#define AC97_SIGMATEL_CIC1 0x76
-#define AC97_SIGMATEL_CIC2 0x78
+/* S/PDIF Operational Registers for 4D-NX */
+enum nx_spdif_registers {
+ NX_SPCTRL_SPCSO = 0x24, NX_SPLBA = 0x28,
+ NX_SPESO = 0x2c, NX_SPCSTATUS = 0x64
+};
+
+/* OP registers to access each hardware channel */
+enum channel_registers {
+ CH_DX_CSO_ALPHA_FMS = 0xe0, CH_DX_ESO_DELTA = 0xe8,
+ CH_DX_FMC_RVOL_CVOL = 0xec,
+ CH_NX_DELTA_CSO = 0xe0, CH_NX_DELTA_ESO = 0xe8,
+ CH_NX_ALPHA_FMS_FMC_RVOL_CVOL = 0xec,
+ CH_LBA = 0xe4,
+ CH_GVSEL_PAN_VOL_CTRL_EC = 0xf0
+};
+
+/* registers to read/write/control AC97 codec */
+enum dx_ac97_registers {
+ DX_ACR0_AC97_W = 0x40, DX_ACR1_AC97_R = 0x44,
+ DX_ACR2_AC97_COM_STAT = 0x48
+};
-#define SI_AC97_BUSY_WRITE 0x8000
-#define SI_AC97_AUDIO_BUSY 0x4000
-#define DX_AC97_BUSY_WRITE 0x8000
-#define NX_AC97_BUSY_WRITE 0x0800
-#define SI_AC97_BUSY_READ 0x8000
-#define DX_AC97_BUSY_READ 0x8000
-#define NX_AC97_BUSY_READ 0x0800
+enum nx_ac97_registers {
+ NX_ACR0_AC97_COM_STAT = 0x40, NX_ACR1_AC97_W = 0x44,
+ NX_ACR2_AC97_R_PRIMARY = 0x48, NX_ACR3_AC97_R_SECONDARY = 0x4c
+};
+
+enum si_ac97_registers {
+ SI_AC97_WRITE = 0x40, SI_AC97_READ = 0x44,
+ SI_SERIAL_INTF_CTRL = 0x48, SI_AC97_GPIO = 0x4c
+};
+
+/* Bit mask for operational registers */
#define AC97_REG_ADDR 0x000000ff
+enum sis7018_ac97_bits {
+ SI_AC97_BUSY_WRITE = 0x8000, SI_AC97_BUSY_READ = 0x8000,
+ SI_AC97_AUDIO_BUSY = 0x4000, SI_AC97_MODEM_BUSY = 0x2000,
+ SI_AC97_SECONDARY = 0x0080
+};
+
+enum trident_dx_ac97_bits {
+ DX_AC97_BUSY_WRITE = 0x8000, DX_AC97_BUSY_READ = 0x8000,
+ DX_AC97_READY = 0x0010, DX_AC97_RECORD = 0x0008,
+ DX_AC97_PLAYBACK = 0x0002
+};
+
+enum trident_nx_ac97_bits {
+ /* ACR1-3 */
+ NX_AC97_BUSY_WRITE = 0x0800, NX_AC97_BUSY_READ = 0x0800,
+ NX_AC97_WRITE_SECONDARY = 0x0100,
+ /* ACR0 */
+ NX_AC97_SECONDARY_READY = 0x0040, NX_AC97_SECONDARY_RECORD = 0x0020,
+ NX_AC97_SURROUND_OUTPUT = 0x0010,
+ NX_AC97_PRIMARY_READY = 0x0008, NX_AC97_PRIMARY_RECORD = 0x0004,
+ NX_AC97_PCM_OUTPUT = 0x0002,
+ NX_AC97_WARM_RESET = 0x0001
+};
+
enum serial_intf_ctrl_bits {
WARM_REST = 0x00000001, COLD_RESET = 0x00000002,
I2S_CLOCK = 0x00000004, PCM_SEC_AC97= 0x00000008,
@@ -162,6 +146,16 @@ enum serial_intf_ctrl_bits {
I2S_OUTPUT_EN = 0x00000040, I2S_INPUT_EN = 0x00000080,
PCMIN = 0x00000100, LINE1IN = 0x00000200,
MICIN = 0x00000400, LINE2IN = 0x00000800,
+ HEAD_SET_IN = 0x00001000, GPIOIN = 0x00002000,
+ /* 7018 spec says id = 01 but the demo board routed to 10
+ SECONDARY_ID= 0x00008000, */
+ SECONDARY_ID= 0x00004000,
+ PCMOUT = 0x00010000, SURROUT = 0x00020000,
+ CENTEROUT = 0x00040000, LFEOUT = 0x00080000,
+ LINE1OUT = 0x00100000, LINE2OUT = 0x00200000,
+ GPIOOUT = 0x00400000,
+ SI_AC97_PRIMARY_READY = 0x01000000,
+ SI_AC97_SECONDARY_READY = 0x02000000,
};
enum global_control_bits {
@@ -173,6 +167,18 @@ enum global_control_bits {
EDROP_IE = 0x00008000, BANK_B_EN = 0x00010000
};
+enum channel_control_bits {
+ CHANNEL_LOOP = 0x00001000, CHANNEL_SIGNED = 0x00002000,
+ CHANNEL_STEREO = 0x00004000, CHANNEL_16BITS = 0x00008000,
+};
+
+enum channel_attribute {
+ MODEM_LINE1, MODEM_LINE2, PCM_LR, HSET,
+ I2SLR, CENTER_LFE, SURR_LR, SPDIF_LR,
+ CHANNEL_PB = 0x00000000, CHANNEL_SPC_PB = 0x40000000,
+ CHANNEL_REC = 0x80000000, CHANNEL_REC_PB = 0xc0000000
+};
+
enum miscint_bits {
PB_UNDERRUN_IRO = 0x00000001, REC_OVERRUN_IRQ = 0x00000002,
SB_IRQ = 0x00000004, MPU401_IRQ = 0x00000008,
@@ -184,31 +190,13 @@ enum miscint_bits {
ST_IRQ_EN = 0x00800000, ACGPIO_IRQ = 0x01000000
};
-#define IWriteAinten( x ) \
- {int i; \
- for( i= 0; i < ChanDwordCount; i++) \
- outl((x)->lpChAinten[i], TRID_REG(trident, (x)->lpAChAinten[i]));}
-
-#define IReadAinten( x ) \
- {int i; \
- for( i= 0; i < ChanDwordCount; i++) \
- (x)->lpChAinten[i] = inl(TRID_REG(trident, (x)->lpAChAinten[i]));}
-
-#define ReadAint( x ) \
- IReadAint( x )
-
-#define WriteAint( x ) \
- IWriteAint( x )
-
-#define IWriteAint( x ) \
- {int i; \
- for( i= 0; i < ChanDwordCount; i++) \
- outl((x)->lpChAint[i], TRID_REG(trident, (x)->lpAChAint[i]));}
+#define AC97_SIGMATEL_DAC2INVERT 0x6E
+#define AC97_SIGMATEL_BIAS1 0x70
+#define AC97_SIGMATEL_BIAS2 0x72
+#define AC97_SIGMATEL_CIC1 0x76
+#define AC97_SIGMATEL_CIC2 0x78
-#define IReadAint( x ) \
- {int i; \
- for( i= 0; i < ChanDwordCount; i++) \
- (x)->lpChAint[i] = inl(TRID_REG(trident, (x)->lpAChAint[i]));}
+#define TRID_REG( trident, x ) ( (trident) -> iobase + (x) )
#define VALIDATE_MAGIC(FOO,MAG) \
({ \
@@ -221,5 +209,31 @@ enum miscint_bits {
#define VALIDATE_STATE(a) VALIDATE_MAGIC(a,TRIDENT_STATE_MAGIC)
#define VALIDATE_CARD(a) VALIDATE_MAGIC(a,TRIDENT_CARD_MAGIC)
+
+extern __inline__ unsigned ld2(unsigned int x)
+{
+ unsigned r = 0;
+
+ if (x >= 0x10000) {
+ x >>= 16;
+ r += 16;
+ }
+ if (x >= 0x100) {
+ x >>= 8;
+ r += 8;
+ }
+ if (x >= 0x10) {
+ x >>= 4;
+ r += 4;
+ }
+ if (x >= 4) {
+ x >>= 2;
+ r += 2;
+ }
+ if (x >= 2)
+ r++;
+ return r;
+}
+
#endif /* __TRID4DWAVE_H */
diff --git a/drivers/usb/Config.in b/drivers/usb/Config.in
index aa8c6adb2..bb812ea90 100644
--- a/drivers/usb/Config.in
+++ b/drivers/usb/Config.in
@@ -9,6 +9,7 @@ if [ ! "$CONFIG_USB" = "n" ]; then
comment 'USB Controllers'
dep_tristate ' UHCI (Intel PIIX4, VIA, ...) support' CONFIG_USB_UHCI $CONFIG_USB
+ dep_tristate ' UHCI Alternate Driver (JE) support' CONFIG_USB_UHCI_ALT $CONFIG_USB
dep_tristate ' OHCI (Compaq, iMacs, OPTi, SiS, ALi, ...) support' CONFIG_USB_OHCI $CONFIG_USB
comment 'Miscellaneous USB options'
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index ee2cee37a..c43a41a31 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -45,6 +45,7 @@ obj- :=
obj-$(CONFIG_USB) += usbcore.o
obj-$(CONFIG_USB_UHCI) += usb-uhci.o
+obj-$(CONFIG_USB_UHCI_ALT) += uhci.o
obj-$(CONFIG_USB_OHCI) += usb-ohci.o
obj-$(CONFIG_USB_MOUSE) += usbmouse.o input.o
@@ -107,3 +108,4 @@ usbcore.o: $(usbcore-objs)
usb-storage.o: $(usb-storage-objs)
$(LD) -r -o $@ $(usb-storage-objs)
+
diff --git a/drivers/usb/acm.c b/drivers/usb/acm.c
index 154d5cd22..1459f1d10 100644
--- a/drivers/usb/acm.c
+++ b/drivers/usb/acm.c
@@ -1,5 +1,5 @@
/*
- * acm.c Version 0.14
+ * acm.c Version 0.15
*
* Copyright (c) 1999 Armin Fuerst <fuerst@in.tum.de>
* Copyright (c) 1999 Pavel Machek <pavel@suse.cz>
@@ -17,6 +17,7 @@
* v0.12 - added TIOCM ioctls, added break handling, made struct acm kmalloced
* v0.13 - added termios, added hangup
* v0.14 - sized down struct acm
+ * v0.15 - fixed flow control again - characters could be lost
*/
/*
@@ -137,6 +138,7 @@ struct acm {
unsigned int writesize; /* max packet size for the output bulk endpoint */
unsigned int used; /* someone has this acm's device open */
unsigned int minor; /* acm minor number */
+ unsigned char throttle; /* throttled by tty layer */
unsigned char clocal; /* termios CLOCAL */
};
@@ -210,8 +212,6 @@ static void acm_ctrl_irq(struct urb *urb)
dr->request, dr->index, dr->length, data[0], data[1]);
return;
}
-
- return;
}
static void acm_read_bulk(struct urb *urb)
@@ -219,24 +219,25 @@ static void acm_read_bulk(struct urb *urb)
struct acm *acm = urb->context;
struct tty_struct *tty = acm->tty;
unsigned char *data = urb->transfer_buffer;
- int i;
+ int i = 0;
if (!ACM_READY(acm)) return;
- if (!urb->status) {
-
- for (i = 0; i < urb->actual_length; i++)
+ if (!urb->status & !acm->throttle) {
+ for (i = 0; i < urb->actual_length && !acm->throttle; i++)
tty_insert_flip_char(tty, data[i], 0);
-
tty_flip_buffer_push(tty);
-
} else
dbg("nonzero read bulk status received: %d", urb->status);
- if (usb_submit_urb(urb))
- dbg("failed resubmitting read urb");
-
- return;
+ if (!acm->throttle) {
+ urb->actual_length = 0;
+ if (usb_submit_urb(urb))
+ dbg("failed resubmitting read urb");
+ } else {
+ memmove(data, data + i, urb->actual_length - i);
+ urb->actual_length -= i;
+ }
}
static void acm_write_bulk(struct urb *urb)
@@ -253,8 +254,6 @@ static void acm_write_bulk(struct urb *urb)
(tty->ldisc.write_wakeup)(tty);
wake_up_interruptible(&tty->write_wait);
-
- return;
}
/*
@@ -347,15 +346,16 @@ static void acm_tty_throttle(struct tty_struct *tty)
{
struct acm *acm = tty->driver_data;
if (!ACM_READY(acm)) return;
- usb_unlink_urb(&acm->readurb);
+ acm->throttle = 1;
}
static void acm_tty_unthrottle(struct tty_struct *tty)
{
struct acm *acm = tty->driver_data;
if (!ACM_READY(acm)) return;
- if (usb_submit_urb(&acm->readurb))
- dbg("usb_submit_urb(read bulk) in unthrottle() failed");
+ acm->throttle = 0;
+ if (acm->readurb.status != -EINPROGRESS)
+ acm_read_bulk(&acm->readurb);
}
static void acm_tty_break_ctl(struct tty_struct *tty, int state)
diff --git a/drivers/usb/ov511.c b/drivers/usb/ov511.c
index 6ec72d502..6dacc46b4 100644
--- a/drivers/usb/ov511.c
+++ b/drivers/usb/ov511.c
@@ -931,7 +931,7 @@ static int ov511_init_isoc(struct usb_ov511 *ov511)
err("ov511_init_isoc: usb_run_isoc(0) ret %d", err);
err = usb_submit_urb(ov511->sbuf[1].urb);
if (err)
- err("ov511_init_isoc: usb_run_isoc(1) ret %d\n", err);
+ err("ov511_init_isoc: usb_run_isoc(1) ret %d", err);
ov511->streaming = 1;
diff --git a/drivers/usb/printer.c b/drivers/usb/printer.c
index 370ed6dd6..a00a9f037 100644
--- a/drivers/usb/printer.c
+++ b/drivers/usb/printer.c
@@ -125,15 +125,15 @@ static int usblp_check_status(struct usblp *usblp)
if (status & LP_PERRORP) {
if (status & LP_POUTPA) {
- printk(KERN_INFO "usblp%d: out of paper", usblp->minor);
+ info("usblp%d: out of paper", usblp->minor);
return -ENOSPC;
}
if (~status & LP_PSELECD) {
- printk(KERN_INFO "usblp%d: off-line", usblp->minor);
+ info("usblp%d: off-line", usblp->minor);
return -EIO;
}
if (~status & LP_PERRORP) {
- printk(KERN_INFO "usblp%d: on fire", usblp->minor);
+ info("usblp%d: on fire", usblp->minor);
return -EIO;
}
}
@@ -229,18 +229,19 @@ static ssize_t usblp_write(struct file *file, const char *buffer, size_t count,
if (usblp->writeurb.status == -EINPROGRESS) {
usb_unlink_urb(&usblp->writeurb);
- printk(KERN_ERR "usblp%d: timed out\n", usblp->minor);
+ err("usblp%d: timed out", usblp->minor);
return -EIO;
}
if (!usblp->dev)
return -ENODEV;
- if (!usblp->writeurb.status)
+ if (!usblp->writeurb.status) {
writecount += usblp->writeurb.transfer_buffer_length;
- else {
+ usblp->writeurb.transfer_buffer_length = 0;
+ } else {
if (!(retval = usblp_check_status(usblp))) {
- printk(KERN_ERR "usblp%d: error %d writing to printer\n",
+ err("usblp%d: error %d writing to printer",
usblp->minor, usblp->writeurb.status);
return -EIO;
}
@@ -287,7 +288,7 @@ static ssize_t usblp_read(struct file *file, char *buffer, size_t count, loff_t
return -ENODEV;
if (usblp->readurb.status) {
- printk(KERN_ERR "usblp%d: error %d reading from printer\n",
+ err("usblp%d: error %d reading from printer",
usblp->minor, usblp->readurb.status);
usb_submit_urb(&usblp->readurb);
return -EIO;
@@ -389,7 +390,7 @@ static void *usblp_probe(struct usb_device *dev, unsigned int ifnum)
buf + USBLP_BUF_SIZE, USBLP_BUF_SIZE, usblp_bulk, usblp);
}
- printk(KERN_INFO "usblp%d: USB %sdirectional printer dev %d if %d alt %d\n",
+ info("usblp%d: USB %sdirectional printer dev %d if %d alt %d",
minor, bidir ? "Bi" : "Uni", dev->devnum, ifnum, alts);
return usblp_table[minor] = usblp;
diff --git a/drivers/usb/scanner.c b/drivers/usb/scanner.c
index ec45a6fb9..e707d23e8 100644
--- a/drivers/usb/scanner.c
+++ b/drivers/usb/scanner.c
@@ -331,7 +331,6 @@ probe_scanner(struct usb_device *dev, unsigned int ifnum)
int ep_cnt;
- char *ident;
char valid_device = 0;
char have_bulk_in, have_bulk_out, have_intr;
diff --git a/drivers/usb/uhci-debug.h b/drivers/usb/uhci-debug.h
index 73d16937a..9d715d4d8 100644
--- a/drivers/usb/uhci-debug.h
+++ b/drivers/usb/uhci-debug.h
@@ -1,195 +1,260 @@
-#ifdef DEBUG
+/*
+ * UHCI-specific debugging code. Invaluable when something
+ * goes wrong, but don't get in my face.
+ *
+ * Kernel visible pointers are surrounded in []'s and bus
+ * visible pointers are surrounded in ()'s
+ *
+ * (C) Copyright 1999 Linus Torvalds
+ * (C) Copyright 1999 Johannes Erdfelt
+ */
-static void uhci_show_qh (puhci_desc_t qh)
+#include <linux/kernel.h>
+#include <asm/io.h>
+
+#include "uhci.h"
+
+void uhci_show_td(struct uhci_td * td)
{
- if (qh->type != QH_TYPE) {
- dbg("qh has not QH_TYPE");
- return;
- }
- dbg("uhci_show_qh %p (%08lX):", qh, virt_to_bus (qh));
+ char *spid;
- if (qh->hw.qh.head & UHCI_PTR_TERM)
- dbg("Head Terminate");
- else {
- if (qh->hw.qh.head & UHCI_PTR_QH)
- dbg("Head points to QH");
- else
- dbg("Head points to TD");
+ printk("%08x ", td->link);
+ printk("e%d %s%s%s%s%s%s%s%s%s%sLength=%x ",
+ ((td->status >> 27) & 3),
+ (td->status & TD_CTRL_SPD) ? "SPD " : "",
+ (td->status & TD_CTRL_LS) ? "LS " : "",
+ (td->status & TD_CTRL_IOC) ? "IOC " : "",
+ (td->status & TD_CTRL_ACTIVE) ? "Active " : "",
+ (td->status & TD_CTRL_STALLED) ? "Stalled " : "",
+ (td->status & TD_CTRL_DBUFERR) ? "DataBufErr " : "",
+ (td->status & TD_CTRL_BABBLE) ? "Babble " : "",
+ (td->status & TD_CTRL_NAK) ? "NAK " : "",
+ (td->status & TD_CTRL_CRCTIMEO) ? "CRC/Timeo " : "",
+ (td->status & TD_CTRL_BITSTUFF) ? "BitStuff " : "",
+ td->status & 0x7ff);
- dbg("head: %08X", qh->hw.qh.head & ~UHCI_PTR_BITS);
- }
- if (qh->hw.qh.element & UHCI_PTR_TERM)
- dbg("Element Terminate");
- else {
-
- if (qh->hw.qh.element & UHCI_PTR_QH)
- dbg("Element points to QH");
- else
- dbg("Element points to TD");
- dbg("element: %08X", qh->hw.qh.element & ~UHCI_PTR_BITS);
+ switch (td->info & 0xff) {
+ case USB_PID_SETUP:
+ spid = "SETUP";
+ break;
+ case USB_PID_OUT:
+ spid = "OUT";
+ break;
+ case USB_PID_IN:
+ spid = "IN";
+ break;
+ default:
+ spid = "?";
+ break;
}
+
+ printk("MaxLen=%x DT%d EndPt=%x Dev=%x, PID=%x(%s) ",
+ td->info >> 21,
+ ((td->info >> 19) & 1),
+ (td->info >> 15) & 15,
+ (td->info >> 8) & 127,
+ (td->info & 0xff),
+ spid);
+ printk("(buf=%08x)\n", td->buffer);
}
-#endif
-static void uhci_show_td (puhci_desc_t td)
+static void uhci_show_sc(int port, unsigned short status)
{
- char *spid;
- warn("uhci_show_td %p (%08lX) ", td, virt_to_bus (td));
-
- switch (td->hw.td.info & 0xff) {
- case USB_PID_SETUP:
- spid = "SETUP";
- break;
- case USB_PID_OUT:
- spid = " OUT ";
- break;
- case USB_PID_IN:
- spid = " IN ";
- break;
- default:
- spid = " ? ";
- break;
- }
+ printk(" stat%d = %04x %s%s%s%s%s%s%s%s\n",
+ port,
+ status,
+ (status & USBPORTSC_SUSP) ? "PortSuspend " : "",
+ (status & USBPORTSC_PR) ? "PortReset " : "",
+ (status & USBPORTSC_LSDA) ? "LowSpeed " : "",
+ (status & USBPORTSC_RD) ? "ResumeDetect " : "",
+ (status & USBPORTSC_PEC) ? "EnableChange " : "",
+ (status & USBPORTSC_PE) ? "PortEnabled " : "",
+ (status & USBPORTSC_CSC) ? "ConnectChange " : "",
+ (status & USBPORTSC_CCS) ? "PortConnected " : "");
+}
- warn("MaxLen=%02x DT%d EndPt=%x Dev=%x, PID=%x(%s) (buf=%08x)",
- td->hw.td.info >> 21,
- ((td->hw.td.info >> 19) & 1),
- (td->hw.td.info >> 15) & 15,
- (td->hw.td.info >> 8) & 127,
- (td->hw.td.info & 0xff),
- spid,
- td->hw.td.buffer);
-
- warn("Len=%02x e%d %s%s%s%s%s%s%s%s%s%s",
- td->hw.td.status & 0x7ff,
- ((td->hw.td.status >> 27) & 3),
- (td->hw.td.status & TD_CTRL_SPD) ? "SPD " : "",
- (td->hw.td.status & TD_CTRL_LS) ? "LS " : "",
- (td->hw.td.status & TD_CTRL_IOC) ? "IOC " : "",
- (td->hw.td.status & TD_CTRL_ACTIVE) ? "Active " : "",
- (td->hw.td.status & TD_CTRL_STALLED) ? "Stalled " : "",
- (td->hw.td.status & TD_CTRL_DBUFERR) ? "DataBufErr " : "",
- (td->hw.td.status & TD_CTRL_BABBLE) ? "Babble " : "",
- (td->hw.td.status & TD_CTRL_NAK) ? "NAK " : "",
- (td->hw.td.status & TD_CTRL_CRCTIMEO) ? "CRC/Timeo " : "",
- (td->hw.td.status & TD_CTRL_BITSTUFF) ? "BitStuff " : ""
- );
-#if 1
- if (td->hw.td.link & UHCI_PTR_TERM)
- warn("Link Terminate");
- else {
- if (td->hw.td.link & UHCI_PTR_QH)
- warn("%s, link points to QH @ %08x",
- (td->hw.td.link & UHCI_PTR_DEPTH ? "Depth first" : " Breadth first"),
- td->hw.td.link & ~UHCI_PTR_BITS);
- else
- warn("%s, link points to TD @ %08x",
- (td->hw.td.link & UHCI_PTR_DEPTH ? "Depth first" : " Breadth first"),
- td->hw.td.link & ~UHCI_PTR_BITS);
- }
-#endif
+void uhci_show_status(struct uhci *uhci)
+{
+ unsigned int io_addr = uhci->io_addr;
+ unsigned short usbcmd, usbstat, usbint, usbfrnum;
+ unsigned int flbaseadd;
+ unsigned char sof;
+ unsigned short portsc1, portsc2;
+
+ usbcmd = inw(io_addr + 0);
+ usbstat = inw(io_addr + 2);
+ usbint = inw(io_addr + 4);
+ usbfrnum = inw(io_addr + 6);
+ flbaseadd = inl(io_addr + 8);
+ sof = inb(io_addr + 12);
+ portsc1 = inw(io_addr + 16);
+ portsc2 = inw(io_addr + 18);
+
+ printk(" usbcmd = %04x %s%s%s%s%s%s%s%s\n",
+ usbcmd,
+ (usbcmd & USBCMD_MAXP) ? "Maxp64 " : "Maxp32 ",
+ (usbcmd & USBCMD_CF) ? "CF " : "",
+ (usbcmd & USBCMD_SWDBG) ? "SWDBG " : "",
+ (usbcmd & USBCMD_FGR) ? "FGR " : "",
+ (usbcmd & USBCMD_EGSM) ? "EGSM " : "",
+ (usbcmd & USBCMD_GRESET) ? "GRESET " : "",
+ (usbcmd & USBCMD_HCRESET) ? "HCRESET " : "",
+ (usbcmd & USBCMD_RS) ? "RS " : "");
+
+ printk(" usbstat = %04x %s%s%s%s%s%s\n",
+ usbstat,
+ (usbstat & USBSTS_HCH) ? "HCHalted " : "",
+ (usbstat & USBSTS_HCPE) ? "HostControllerProcessError " : "",
+ (usbstat & USBSTS_HSE) ? "HostSystemError " : "",
+ (usbstat & USBSTS_RD) ? "ResumeDetect " : "",
+ (usbstat & USBSTS_ERROR) ? "USBError " : "",
+ (usbstat & USBSTS_USBINT) ? "USBINT " : "");
+
+ printk(" usbint = %04x\n", usbint);
+ printk(" usbfrnum = (%d)%03x\n", (usbfrnum >> 10) & 1,
+ 0xfff & (4*(unsigned int)usbfrnum));
+ printk(" flbaseadd = %08x\n", flbaseadd);
+ printk(" sof = %02x\n", sof);
+ uhci_show_sc(1, portsc1);
+ uhci_show_sc(2, portsc2);
}
-#ifdef DEBUG
-static void uhci_show_td_queue (puhci_desc_t td)
+
+#define uhci_link_to_qh(x) ((struct uhci_qh *) uhci_link_to_td(x))
+
+struct uhci_td *uhci_link_to_td(unsigned int link)
{
- dbg("uhci_show_td_queue %p (%08lX):", td, virt_to_bus (td));
- while (1) {
- uhci_show_td (td);
- if (td->hw.td.link & UHCI_PTR_TERM)
- break;
- //if(!(td->hw.td.link&UHCI_PTR_DEPTH))
- // break;
- if (td != bus_to_virt (td->hw.td.link & ~UHCI_PTR_BITS))
- td = bus_to_virt (td->hw.td.link & ~UHCI_PTR_BITS);
- else {
- dbg("td points to itself!");
- break;
- }
-// schedule();
- }
+ if (link & UHCI_PTR_TERM)
+ return NULL;
+
+ return bus_to_virt(link & ~UHCI_PTR_BITS);
}
-static void uhci_show_queue (puhci_desc_t qh)
+void uhci_show_queue(struct uhci_qh *qh)
{
- dbg("uhci_show_queue %p:", qh);
- while (1) {
- uhci_show_qh (qh);
+ struct uhci_td *td, *first;
+ int i = 0, count = 1000;
- if (qh->hw.qh.element & UHCI_PTR_QH)
- dbg("Warning: qh->element points to qh!");
- else if (!(qh->hw.qh.element & UHCI_PTR_TERM))
- uhci_show_td_queue (bus_to_virt (qh->hw.qh.element & ~UHCI_PTR_BITS));
+ if (qh->element & UHCI_PTR_QH)
+ printk(" Element points to QH (bug?)\n");
- if (qh->hw.qh.head & UHCI_PTR_TERM)
- break;
+ if (qh->element & UHCI_PTR_DEPTH)
+ printk(" Depth traverse\n");
- if (qh != bus_to_virt (qh->hw.qh.head & ~UHCI_PTR_BITS))
- qh = bus_to_virt (qh->hw.qh.head & ~UHCI_PTR_BITS);
- else {
- dbg("qh points to itself!");
+ if (qh->element & UHCI_PTR_TERM)
+ printk(" Terminate\n");
+
+ if (!(qh->element & ~UHCI_PTR_BITS)) {
+ printk(" td 0: [NULL]\n");
+ return;
+ }
+
+ first = uhci_link_to_td(qh->element);
+
+ /* Make sure it doesn't runaway */
+ for (td = first; td && count > 0;
+ td = uhci_link_to_td(td->link), --count) {
+ printk(" td %d: [%p]\n", i++, td);
+ printk(" ");
+ uhci_show_td(td);
+
+ if (td == uhci_link_to_td(td->link)) {
+ printk(KERN_ERR "td links to itself!\n");
break;
}
}
}
-static void uhci_show_sc (int port, unsigned short status)
+static int uhci_is_skeleton_td(struct uhci *uhci, struct uhci_td *td)
{
- dbg(" stat%d = %04x %s%s%s%s%s%s%s%s",
- port,
- status,
- (status & USBPORTSC_SUSP) ? "PortSuspend " : "",
- (status & USBPORTSC_PR) ? "PortReset " : "",
- (status & USBPORTSC_LSDA) ? "LowSpeed " : "",
- (status & USBPORTSC_RD) ? "ResumeDetect " : "",
- (status & USBPORTSC_PEC) ? "EnableChange " : "",
- (status & USBPORTSC_PE) ? "PortEnabled " : "",
- (status & USBPORTSC_CSC) ? "ConnectChange " : "",
- (status & USBPORTSC_CCS) ? "PortConnected " : "");
+ int j;
+
+ for (j = 0; j < UHCI_NUM_SKELTD; j++)
+ if (td == uhci->skeltd + j)
+ return 1;
+
+ return 0;
}
-void uhci_show_status (puhci_t s)
+static int uhci_is_skeleton_qh(struct uhci *uhci, struct uhci_qh *qh)
{
- unsigned int io_addr = s->io_addr;
- unsigned short usbcmd, usbstat, usbint, usbfrnum;
- unsigned int flbaseadd;
- unsigned char sof;
- unsigned short portsc1, portsc2;
+ int j;
+
+ for (j = 0; j < UHCI_NUM_SKELQH; j++)
+ if (qh == uhci->skelqh + j)
+ return 1;
- usbcmd = inw (io_addr + 0);
- usbstat = inw (io_addr + 2);
- usbint = inw (io_addr + 4);
- usbfrnum = inw (io_addr + 6);
- flbaseadd = inl (io_addr + 8);
- sof = inb (io_addr + 12);
- portsc1 = inw (io_addr + 16);
- portsc2 = inw (io_addr + 18);
-
- dbg(" usbcmd = %04x %s%s%s%s%s%s%s%s",
- usbcmd,
- (usbcmd & USBCMD_MAXP) ? "Maxp64 " : "Maxp32 ",
- (usbcmd & USBCMD_CF) ? "CF " : "",
- (usbcmd & USBCMD_SWDBG) ? "SWDBG " : "",
- (usbcmd & USBCMD_FGR) ? "FGR " : "",
- (usbcmd & USBCMD_EGSM) ? "EGSM " : "",
- (usbcmd & USBCMD_GRESET) ? "GRESET " : "",
- (usbcmd & USBCMD_HCRESET) ? "HCRESET " : "",
- (usbcmd & USBCMD_RS) ? "RS " : "");
-
- dbg(" usbstat = %04x %s%s%s%s%s%s",
- usbstat,
- (usbstat & USBSTS_HCH) ? "HCHalted " : "",
- (usbstat & USBSTS_HCPE) ? "HostControllerProcessError " : "",
- (usbstat & USBSTS_HSE) ? "HostSystemError " : "",
- (usbstat & USBSTS_RD) ? "ResumeDetect " : "",
- (usbstat & USBSTS_ERROR) ? "USBError " : "",
- (usbstat & USBSTS_USBINT) ? "USBINT " : "");
-
- dbg(" usbint = %04x", usbint);
- dbg(" usbfrnum = (%d)%03x", (usbfrnum >> 10) & 1,
- 0xfff & (4 * (unsigned int) usbfrnum));
- dbg(" flbaseadd = %08x", flbaseadd);
- dbg(" sof = %02x", sof);
- uhci_show_sc (1, portsc1);
- uhci_show_sc (2, portsc2);
+ return 0;
}
-#endif
+
+static const char *td_names[] = {"interrupt1", "interrupt2", "interrupt4",
+ "interrupt8", "interrupt16", "interrupt32",
+ "interrupt64", "interrupt128", "interrupt256" };
+static const char *qh_names[] = { "control", "bulk" };
+
+void uhci_show_queues(struct uhci *uhci)
+{
+ int i, isqh;
+ struct uhci_qh *qh;
+ struct uhci_td *td;
+
+ for (i = 0; i < UHCI_NUMFRAMES; ++i) {
+ int shown = 0;
+
+ td = uhci_link_to_td(uhci->fl->frame[i]);
+ if (td)
+ isqh = uhci->fl->frame[i] & UHCI_PTR_QH;
+ while (td && !isqh) {
+ if (uhci_is_skeleton_td(uhci, td))
+ break;
+
+ if (!shown) {
+ printk(" Frame %d\n", i);
+ shown = 1;
+ }
+
+ printk("[%p] ", td);
+
+ uhci_show_td(td);
+ td = uhci_link_to_td(td->link);
+ if (td)
+ isqh = td->link & UHCI_PTR_QH;
+ }
+ }
+ for (i = 0; i < UHCI_NUM_SKELTD; ++i) {
+ printk(" %s: [%p] (%08x)\n", td_names[i],
+ &uhci->skeltd[i],
+ uhci->skeltd[i].link);
+
+ td = uhci_link_to_td(uhci->skeltd[i].link);
+ if (td)
+ isqh = uhci->skeltd[i].link & UHCI_PTR_QH;
+ while (td && !isqh) {
+ if (uhci_is_skeleton_td(uhci, td))
+ break;
+
+ printk("[%p] ", td);
+
+ uhci_show_td(td);
+ td = uhci_link_to_td(td->link);
+ if (td)
+ isqh = td->link & UHCI_PTR_QH;
+ }
+ }
+ for (i = 0; i < UHCI_NUM_SKELQH; ++i) {
+ printk(" %s: [%p] (%08x) (%08x)\n", qh_names[i],
+ &uhci->skelqh[i],
+ uhci->skelqh[i].link, uhci->skelqh[i].element);
+
+ qh = uhci_link_to_qh(uhci->skelqh[i].link);
+ for (; qh; qh = uhci_link_to_qh(qh->link)) {
+ if (uhci_is_skeleton_qh(uhci, qh))
+ break;
+
+ printk(" [%p] (%08x) (%08x)\n",
+ qh, qh->link, qh->element);
+
+ uhci_show_queue(qh);
+ }
+ }
+}
+
diff --git a/drivers/usb/uhci.c b/drivers/usb/uhci.c
new file mode 100644
index 000000000..d18fc30cb
--- /dev/null
+++ b/drivers/usb/uhci.c
@@ -0,0 +1,2214 @@
+/*
+ * Universal Host Controller Interface driver for USB.
+ *
+ * (C) Copyright 1999 Linus Torvalds
+ * (C) Copyright 1999-2000 Johannes Erdfelt, jerdfelt@sventech.com
+ * (C) Copyright 1999 Randy Dunlap
+ * (C) Copyright 1999 Georg Acher, acher@in.tum.de
+ * (C) Copyright 1999 Deti Fliegl, deti@fliegl.de
+ * (C) Copyright 1999 Thomas Sailer, sailer@ife.ee.ethz.ch
+ * (C) Copyright 1999 Roman Weissgaerber, weissg@vienna.at
+ *
+ * Intel documents this fairly well, and as far as I know there
+ * are no royalties or anything like that, but even so there are
+ * people who decided that they want to do the same thing in a
+ * completely different way.
+ *
+ * WARNING! The USB documentation is downright evil. Most of it
+ * is just crap, written by a committee. You're better off ignoring
+ * most of it, the important stuff is:
+ * - the low-level protocol (fairly simple but lots of small details)
+ * - working around the horridness of the rest
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+
+#define DEBUG
+#include "usb.h"
+
+#include "uhci.h"
+#include "uhci-debug.h"
+
+#ifdef CONFIG_APM
+#include <linux/apm_bios.h>
+static int handle_apm_event(apm_event_t event);
+#endif
+
+static int debug = 1;
+MODULE_PARM(debug, "i");
+
+static kmem_cache_t *uhci_td_cachep;
+static kmem_cache_t *uhci_qh_cachep;
+
+static LIST_HEAD(uhci_list);
+
+static int rh_submit_urb(urb_t *urb);
+static int rh_unlink_urb(urb_t *urb);
+static int uhci_get_current_frame_number(struct usb_device *usb_dev);
+
+#define min(a,b) (((a)<(b))?(a):(b))
+
+/*
+ * Only the USB core should call uhci_alloc_dev and uhci_free_dev
+ */
+static int uhci_alloc_dev(struct usb_device *usb_dev)
+{
+ struct uhci_device *dev;
+
+ /* Allocate the UHCI device private data */
+ dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return -1;
+
+ /* Initialize "dev" */
+ memset(dev, 0, sizeof(*dev));
+
+ usb_dev->hcpriv = dev;
+ dev->usb = usb_dev;
+ atomic_set(&dev->refcnt, 1);
+
+ if (usb_dev->parent)
+ dev->uhci = usb_to_uhci(usb_dev->parent)->uhci;
+
+ return 0;
+}
+
+static int uhci_free_dev(struct usb_device *usb_dev)
+{
+ struct uhci_device *dev = usb_to_uhci(usb_dev);
+
+ if (atomic_dec_and_test(&dev->refcnt))
+ kfree(dev);
+
+ return 0;
+}
+
+static void uhci_inc_dev_use(struct uhci_device *dev)
+{
+ atomic_inc(&dev->refcnt);
+}
+
+static void uhci_dec_dev_use(struct uhci_device *dev)
+{
+ uhci_free_dev(dev->usb);
+}
+
+/*
+ * UHCI interrupt list operations..
+ */
+static void uhci_add_irq_list(struct uhci *uhci, struct uhci_td *td)
+{
+ unsigned long flags;
+
+ nested_lock(&uhci->irqlist_lock, flags);
+ list_add(&td->irq_list, &uhci->interrupt_list);
+ nested_unlock(&uhci->irqlist_lock, flags);
+}
+
+static void uhci_remove_irq_list(struct uhci *uhci, struct uhci_td *td)
+{
+ unsigned long flags;
+
+ nested_lock(&uhci->irqlist_lock, flags);
+ if (td->irq_list.next != &td->irq_list) {
+ list_del(&td->irq_list);
+ INIT_LIST_HEAD(&td->irq_list);
+ }
+ nested_unlock(&uhci->irqlist_lock, flags);
+}
+
+static void uhci_add_urb_list(struct uhci *uhci, struct urb *urb)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&uhci->urblist_lock, flags);
+ list_add(&urb->urb_list, &uhci->urb_list);
+ spin_unlock_irqrestore(&uhci->urblist_lock, flags);
+}
+
+static void uhci_remove_urb_list(struct uhci *uhci, struct urb *urb)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&uhci->urblist_lock, flags);
+ if (urb->urb_list.next != &urb->urb_list) {
+ list_del(&urb->urb_list);
+ INIT_LIST_HEAD(&urb->urb_list);
+ }
+ spin_unlock_irqrestore(&uhci->urblist_lock, flags);
+}
+
+/*
+ * We insert Isochronous transfers directly into the frame list at the
+ * beginning
+ * The layout looks as follows:
+ * frame list pointer -> iso td's (if any) ->
+ * periodic interrupt td (if frame 0) -> irq td's -> control qh -> bulk qh
+ */
+
+static void uhci_insert_td_frame_list(struct uhci *uhci, struct uhci_td *td, unsigned framenum)
+{
+ unsigned long flags;
+ struct uhci_td *nexttd;
+
+ framenum %= UHCI_NUMFRAMES;
+
+ spin_lock_irqsave(&uhci->framelist_lock, flags);
+ td->frameptr = &uhci->fl->frame[framenum];
+ td->link = uhci->fl->frame[framenum];
+ if (!(td->link & (UHCI_PTR_TERM | UHCI_PTR_QH))) {
+ nexttd = (struct uhci_td *)uhci_ptr_to_virt(td->link);
+ td->nexttd = nexttd;
+ nexttd->prevtd = td;
+ nexttd->frameptr = NULL;
+ }
+ uhci->fl->frame[framenum] = virt_to_bus(td);
+ spin_unlock_irqrestore(&uhci->framelist_lock, flags);
+}
+
+static void uhci_remove_td(struct uhci *uhci, struct uhci_td *td)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&uhci->framelist_lock, flags);
+ if (td->frameptr) {
+ *(td->frameptr) = td->link;
+ if (td->nexttd) {
+ td->nexttd->frameptr = td->frameptr;
+ td->nexttd->prevtd = NULL;
+ td->nexttd = NULL;
+ }
+ td->frameptr = NULL;
+ } else {
+ if (td->prevtd) {
+ td->prevtd->nexttd = td->nexttd;
+ td->prevtd->link = td->link;
+ }
+ if (td->nexttd)
+ td->nexttd->prevtd = td->prevtd;
+ td->prevtd = td->nexttd = NULL;
+ }
+ td->link = UHCI_PTR_TERM;
+ spin_unlock_irqrestore(&uhci->framelist_lock, flags);
+}
+
+static void uhci_insert_td(struct uhci *uhci, struct uhci_td *skeltd, struct uhci_td *td)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&uhci->framelist_lock, flags);
+
+ /* Fix the linked list pointers */
+ td->nexttd = skeltd->nexttd;
+ td->prevtd = skeltd;
+ if (skeltd->nexttd)
+ skeltd->nexttd->prevtd = td;
+ skeltd->nexttd = td;
+
+ td->link = skeltd->link;
+ skeltd->link = virt_to_bus(td);
+
+ spin_unlock_irqrestore(&uhci->framelist_lock, flags);
+}
+
+/*
+ * Inserts a td into qh list at the top.
+ */
+static void uhci_insert_tds_in_qh(struct uhci_qh *qh, struct uhci_td *begin)
+{
+ struct uhci_td *td, *prevtd;
+
+ if (!begin) /* Nothing to do */
+ return;
+
+ /* Grab the first TD and add it to the QH */
+ td = begin;
+ qh->element = virt_to_bus(td) | UHCI_PTR_DEPTH;
+
+ /* Go through the rest of the TD's, link them together */
+ prevtd = td;
+ td = td->next;
+ while (td) {
+ prevtd->link = virt_to_bus(td) | UHCI_PTR_DEPTH;
+
+ prevtd = td;
+ td = td->next;
+ }
+
+ prevtd->link = UHCI_PTR_TERM;
+}
+
+static struct uhci_td *uhci_td_alloc(struct uhci_device *dev)
+{
+ struct uhci_td *td;
+
+ td = kmem_cache_alloc(uhci_td_cachep, in_interrupt() ? SLAB_ATOMIC : SLAB_KERNEL);
+ if (!td)
+ return NULL;
+
+ td->link = UHCI_PTR_TERM;
+ td->buffer = 0;
+
+ td->frameptr = NULL;
+ td->nexttd = td->prevtd = NULL;
+ td->next = NULL;
+ td->dev = dev;
+ INIT_LIST_HEAD(&td->irq_list);
+ INIT_LIST_HEAD(&td->list);
+
+ uhci_inc_dev_use(dev);
+
+ return td;
+}
+
+static void uhci_td_free(struct uhci_td *td)
+{
+ kmem_cache_free(uhci_td_cachep, td);
+
+ if (td->dev)
+ uhci_dec_dev_use(td->dev);
+}
+
+static void uhci_schedule_delete_td(struct uhci *uhci, struct uhci_td *td)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&uhci->freelist_lock, flags);
+ list_add(&td->list, &uhci->td_free_list);
+ if (td->dev) {
+ uhci_dec_dev_use(td->dev);
+ td->dev = NULL;
+ }
+ spin_unlock_irqrestore(&uhci->freelist_lock, flags);
+}
+
+static struct uhci_qh *uhci_qh_alloc(struct uhci_device *dev)
+{
+ struct uhci_qh *qh;
+
+ qh = kmem_cache_alloc(uhci_qh_cachep, in_interrupt() ? SLAB_ATOMIC : SLAB_KERNEL);
+ if (!qh)
+ return NULL;
+
+ qh->element = UHCI_PTR_TERM;
+ qh->link = UHCI_PTR_TERM;
+
+ qh->dev = dev;
+ qh->prevqh = qh->nextqh = NULL;
+
+ INIT_LIST_HEAD(&qh->list);
+
+ uhci_inc_dev_use(dev);
+
+ return qh;
+}
+
+static void uhci_qh_free(struct uhci_qh *qh)
+{
+ kmem_cache_free(uhci_qh_cachep, qh);
+
+ if (qh->dev)
+ uhci_dec_dev_use(qh->dev);
+}
+
+static void uhci_schedule_delete_qh(struct uhci *uhci, struct uhci_qh *qh)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&uhci->freelist_lock, flags);
+ list_add(&qh->list, &uhci->qh_free_list);
+ if (qh->dev) {
+ uhci_dec_dev_use(qh->dev);
+ qh->dev = NULL;
+ }
+ spin_unlock_irqrestore(&uhci->freelist_lock, flags);
+}
+
+static void uhci_insert_qh(struct uhci *uhci, struct uhci_qh *skelqh, struct uhci_qh *qh)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&uhci->framelist_lock, flags);
+
+ /* Fix the linked list pointers */
+ qh->nextqh = skelqh->nextqh;
+ qh->prevqh = skelqh;
+ if (skelqh->nextqh)
+ skelqh->nextqh->prevqh = qh;
+ skelqh->nextqh = qh;
+
+ qh->link = skelqh->link;
+ skelqh->link = virt_to_bus(qh) | UHCI_PTR_QH;
+
+ spin_unlock_irqrestore(&uhci->framelist_lock, flags);
+}
+
+static void uhci_remove_qh(struct uhci *uhci, struct uhci_qh *qh)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&uhci->framelist_lock, flags);
+ if (qh->prevqh) {
+ qh->prevqh->nextqh = qh->nextqh;
+ qh->prevqh->link = qh->link;
+ }
+ if (qh->nextqh)
+ qh->nextqh->prevqh = qh->prevqh;
+ qh->prevqh = qh->nextqh = NULL;
+ spin_unlock_irqrestore(&uhci->framelist_lock, flags);
+}
+
+static void inline uhci_fill_td(struct uhci_td *td, __u32 status,
+ __u32 info, __u32 buffer)
+{
+ td->status = status;
+ td->info = info;
+ td->buffer = buffer;
+}
+
+static void uhci_add_td_to_urb(urb_t *urb, struct uhci_td *td)
+{
+ struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+
+ td->urb = urb;
+
+ if (urbp->end)
+ urbp->end->next = td;
+
+ urbp->end = td;
+
+ if (!urbp->begin)
+ urbp->begin = td;
+}
+
+/*
+ * Map status to standard result codes
+ *
+ * <status> is (td->status & 0xFE0000) [a.k.a. uhci_status_bits(td->status)]
+ * <dir_out> is True for output TDs and False for input TDs.
+ */
+static int uhci_map_status(int status, int dir_out)
+{
+ if (!status)
+ return 0;
+ if (status & TD_CTRL_BITSTUFF) /* Bitstuff error */
+ return -EPROTO;
+ if (status & TD_CTRL_CRCTIMEO) { /* CRC/Timeout */
+ if (dir_out)
+ return -ETIMEDOUT;
+ else
+ return -EILSEQ;
+ }
+ if (status & TD_CTRL_NAK) /* NAK */
+ return -ETIMEDOUT;
+ if (status & TD_CTRL_BABBLE) /* Babble */
+ return -EPIPE;
+ if (status & TD_CTRL_DBUFERR) /* Buffer error */
+ return -ENOSR;
+ if (status & TD_CTRL_STALLED) /* Stalled */
+ return -EPIPE;
+ if (status & TD_CTRL_ACTIVE) /* Active */
+ return 0;
+
+ return -EINVAL;
+}
+
+/*
+ * Control transfers
+ */
+static int uhci_submit_control(urb_t *urb)
+{
+ struct uhci_td *td;
+ struct uhci_qh *qh;
+ unsigned long destination, status;
+ struct uhci_device *dev = usb_to_uhci(urb->dev);
+ struct uhci *uhci = dev->uhci;
+ int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
+ int len = urb->transfer_buffer_length;
+ unsigned char *data = urb->transfer_buffer;
+ struct urb_priv *urbp;
+
+ /* The "pipe" thing contains the destination in bits 8--18 */
+ destination = (urb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP;
+
+ /* 3 errors */
+ status = (urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | (3 << 27);
+
+ urbp = kmalloc(sizeof(*urbp), in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
+ if (!urbp)
+ return -ENOMEM;
+
+ urbp->begin = urbp->end = NULL;
+
+ urb->hcpriv = urbp;
+
+ /*
+ * Build the TD for the control request
+ */
+ td = uhci_td_alloc(dev);
+ if (!td)
+ return -ENOMEM;
+
+ uhci_add_td_to_urb(urb, td);
+ uhci_fill_td(td, status, destination | (7 << 21),
+ virt_to_bus(urb->setup_packet));
+
+ /*
+ * If direction is "send", change the frame from SETUP (0x2D)
+ * to OUT (0xE1). Else change it from SETUP to IN (0x69).
+ */
+ destination ^= (USB_PID_SETUP ^ usb_packetid(urb->pipe));
+
+ if (!(urb->transfer_flags & USB_DISABLE_SPD))
+ status |= TD_CTRL_SPD;
+
+ /*
+ * Build the DATA TD's
+ */
+ td = uhci_td_alloc(dev);
+ if (!td) {
+ /* FIXME: Free the TD's */
+ return -ENOMEM;
+ }
+
+ while (len > 0) {
+ int pktsze = len;
+
+ if (pktsze > maxsze)
+ pktsze = maxsze;
+
+ /* Alternate Data0/1 (start with Data1) */
+ destination ^= 1 << TD_TOKEN_TOGGLE;
+
+ uhci_add_td_to_urb(urb, td);
+ uhci_fill_td(td, status, destination | ((pktsze - 1) << 21),
+ virt_to_bus(data));
+
+ data += pktsze;
+ len -= pktsze;
+
+ td = uhci_td_alloc(dev);
+ if (!td)
+ /* FIXME: Free all of the previously allocated td's */
+ return -ENOMEM;
+ }
+
+ /*
+ * Build the final TD for control status
+ *
+ * It's IN if the pipe is an output pipe or we're not expecting
+ * data back.
+ */
+ destination &= ~TD_PID;
+ if (usb_pipeout(urb->pipe) || !urb->transfer_buffer_length)
+ destination |= USB_PID_IN;
+ else
+ destination |= USB_PID_OUT;
+
+ destination |= 1 << TD_TOKEN_TOGGLE; /* End in Data1 */
+
+ status &= ~TD_CTRL_SPD;
+
+ uhci_add_td_to_urb(urb, td);
+ uhci_fill_td(td, status | TD_CTRL_IOC,
+ destination | (UHCI_NULL_DATA_SIZE << 21), 0);
+
+ uhci_add_irq_list(uhci, td);
+
+ qh = uhci_qh_alloc(dev);
+ if (!qh) {
+ /* FIXME: Free all of the TD's */
+ return -ENOMEM;
+ }
+ uhci_insert_tds_in_qh(qh, urbp->begin);
+
+ uhci_insert_qh(uhci, &uhci->skel_control_qh, qh);
+ urbp->qh = qh;
+
+ uhci_add_urb_list(uhci, urb);
+
+ usb_inc_dev_use(urb->dev);
+
+ return -EINPROGRESS;
+}
+
+static int uhci_unlink_control(urb_t *urb)
+{
+ struct urb_priv *urbp = urb->hcpriv;
+ struct uhci_td *td;
+ struct uhci_device *dev = usb_to_uhci(urb->dev);
+ struct uhci *uhci = dev->uhci;
+
+ if (!urbp)
+ return -EINVAL;
+
+ uhci_remove_qh(uhci, urbp->qh);
+ uhci_schedule_delete_qh(uhci, urbp->qh);
+
+ /* Go through the rest of the TD's, deleting them, then scheduling */
+ /* their deletion */
+ td = urbp->begin;
+ while (td) {
+ struct uhci_td *next = td->next;
+
+ if (td->status & TD_CTRL_IOC)
+ uhci_remove_irq_list(uhci, td);
+
+ uhci_schedule_delete_td(uhci, td);
+
+ td = next;
+ }
+
+ kfree(urbp);
+ urb->hcpriv = NULL;
+
+ uhci_remove_urb_list(uhci, urb);
+
+ return 0;
+}
+
+static int uhci_result_control(urb_t *urb)
+{
+ struct urb_priv *urbp = urb->hcpriv;
+ struct uhci_td *td;
+ unsigned int status;
+ int ret;
+
+ td = urbp->begin;
+ if (!td) /* Nothing to do */
+ return -EINVAL;
+
+ /* The first TD is the SETUP phase, check the status, but skip */
+ /* the count */
+ status = uhci_status_bits(td->status);
+ if (status & TD_CTRL_ACTIVE)
+ return -EINPROGRESS;
+
+ if (status)
+ goto td_error;
+
+ urb->actual_length = 0;
+
+ /* The rest of the TD's (but the last) are data */
+ td = td->next;
+ while (td && td->next) {
+ status = uhci_status_bits(td->status);
+ if (status & TD_CTRL_ACTIVE)
+ return -EINPROGRESS;
+
+ urb->actual_length += uhci_actual_length(td->status);
+
+ /* If SPD is set then we received a short packet */
+ /* There will be no status phase at the end */
+ if (td->status & TD_CTRL_SPD && (uhci_actual_length(td->status) < uhci_expected_length(td->info)))
+ goto td_success;
+
+ if (status)
+ goto td_error;
+
+ td = td->next;
+ }
+
+ /* Control status phase */
+ status = uhci_status_bits(td->status);
+
+ /* APC BackUPS Pro kludge */
+ /* It tries to send all of the descriptor instead of */
+ /* the amount we requested */
+ if (td->status & TD_CTRL_IOC &&
+ status & TD_CTRL_ACTIVE &&
+ status & TD_CTRL_NAK)
+ goto td_success;
+
+ if (status & TD_CTRL_ACTIVE)
+ return -EINPROGRESS;
+
+ if (status)
+ goto td_error;
+
+td_success:
+ uhci_unlink_control(urb);
+
+ return 0;
+
+td_error:
+ /* Some debugging code */
+ if (debug) {
+ dbg("uhci_result_control() failed with status %x",
+ status);
+
+ /* Print the chain for debugging purposes */
+ uhci_show_queue(urbp->qh);
+ }
+
+ if (status & TD_CTRL_STALLED) {
+ /* endpoint has stalled - mark it halted */
+ usb_endpoint_halt(urb->dev, uhci_endpoint(td->info),
+ uhci_packetout(td->info));
+ uhci_unlink_control(urb);
+
+ return -EPIPE;
+ }
+
+ ret = uhci_map_status(status, uhci_packetout(td->info));
+
+ uhci_unlink_control(urb);
+
+ return ret;
+}
+
+/*
+ * Interrupt transfers
+ */
+static int uhci_submit_interrupt(urb_t *urb)
+{
+ struct uhci_td *td;
+ unsigned long destination, status;
+ struct uhci_device *dev = usb_to_uhci(urb->dev);
+ struct uhci *uhci = dev->uhci;
+ struct urb_priv *urbp;
+
+ if (urb->transfer_buffer_length > usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)))
+ return -EINVAL;
+
+ /* The "pipe" thing contains the destination in bits 8--18 */
+ destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
+
+ status = (urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_SPD |
+ TD_CTRL_IOC;
+
+ urbp = kmalloc(sizeof(*urbp), in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
+ if (!urbp)
+ return -ENOMEM;
+
+ urbp->begin = urbp->end = NULL;
+
+ urb->hcpriv = urbp;
+
+ td = uhci_td_alloc(dev);
+ if (!td)
+ return -ENOMEM;
+
+ destination |= (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE);
+ destination |= ((urb->transfer_buffer_length - 1) << 21);
+
+ uhci_add_td_to_urb(urb, td);
+ uhci_fill_td(td, status, destination,
+ virt_to_bus(urb->transfer_buffer));
+
+ uhci_add_irq_list(uhci, td);
+
+ uhci_insert_td(uhci, &uhci->skeltd[__interval_to_skel(urb->interval)], td);
+
+ uhci_add_urb_list(uhci, urb);
+
+ usb_inc_dev_use(urb->dev);
+
+ return -EINPROGRESS;
+}
+
+static int uhci_unlink_interrupt(urb_t *urb)
+{
+ struct urb_priv *urbp = urb->hcpriv;
+ struct uhci_td *td;
+ struct uhci_device *dev = usb_to_uhci(urb->dev);
+ struct uhci *uhci = dev->uhci;
+
+ if (!urbp)
+ return -EINVAL;
+
+ td = urbp->begin;
+ uhci_remove_td(uhci, td);
+ if (td->status & TD_CTRL_IOC)
+ uhci_remove_irq_list(uhci, td);
+ uhci_schedule_delete_td(uhci, td);
+
+ kfree(urbp);
+ urb->hcpriv = NULL;
+
+ uhci_remove_urb_list(uhci, urb);
+
+ return 0;
+}
+
+static int uhci_result_interrupt(urb_t *urb)
+{
+ struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+ struct uhci_td *td;
+ int status;
+
+ if (!urbp)
+ return -EINVAL;
+
+ td = urbp->begin;
+ if (!td)
+ return -EINVAL;
+
+ status = uhci_status_bits(td->status);
+ if (status & TD_CTRL_ACTIVE)
+ return -EINPROGRESS;
+
+ if (status)
+ return uhci_map_status(status, uhci_packetout(td->info));
+
+ urb->actual_length += uhci_actual_length(td->status);
+
+ return 0;
+}
+
+static void uhci_reset_interrupt(urb_t *urb)
+{
+ struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+ struct uhci_td *td;
+
+ if (urb->interval) {
+ td = urbp->begin;
+
+ usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
+ td->status = (td->status & 0x2F000000) | TD_CTRL_ACTIVE | TD_CTRL_IOC;
+ td->info &= ~(1 << TD_TOKEN_TOGGLE);
+ td->info |= (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE);
+
+ urb->status = -EINPROGRESS;
+ } else
+ uhci_unlink_interrupt(urb);
+}
+
+/*
+ * Bulk transfers
+ */
+static int uhci_submit_bulk(urb_t *urb)
+{
+ struct uhci_td *td;
+ struct uhci_qh *qh;
+ unsigned long destination, status;
+ struct uhci_device *dev = usb_to_uhci(urb->dev);
+ struct uhci *uhci = dev->uhci;
+ int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
+ int len = urb->transfer_buffer_length;
+ unsigned char *data = urb->transfer_buffer;
+ struct urb_priv *urbp;
+
+ if (len < 0)
+ return -EINVAL;
+
+ /* The "pipe" thing contains the destination in bits 8--18 */
+ destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
+
+ /* 3 errors */
+ status = (urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | (3 << 27);
+ if (!(urb->transfer_flags & USB_DISABLE_SPD))
+ status |= TD_CTRL_SPD;
+
+ urbp = kmalloc(sizeof(*urbp), in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
+ if (!urbp)
+ return -ENOMEM;
+
+ urbp->begin = urbp->end = NULL;
+
+ urb->hcpriv = urbp;
+
+ /*
+ * Build the DATA TD's
+ */
+ while (len > 0) {
+ int pktsze = len;
+
+ if (pktsze > maxsze)
+ pktsze = maxsze;
+
+ td = uhci_td_alloc(dev);
+ if (!td) {
+ /* FIXME: Free the TD's */
+ return -ENOMEM;
+ }
+
+ uhci_add_td_to_urb(urb, td);
+ uhci_fill_td(td, status, destination | ((pktsze - 1) << 21) |
+ (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+ usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE),
+ virt_to_bus(data));
+
+ data += pktsze;
+ len -= maxsze;
+
+ if (len <= 0) {
+ td->status |= TD_CTRL_IOC;
+ uhci_add_irq_list(uhci, td);
+ }
+
+ usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+ usb_pipeout(urb->pipe));
+ }
+
+ qh = uhci_qh_alloc(dev);
+ if (!qh) {
+ /* FIXME: Free all of the TD's */
+ return -ENOMEM;
+ }
+ uhci_insert_tds_in_qh(qh, urbp->begin);
+
+ uhci_insert_qh(dev->uhci, &dev->uhci->skel_bulk_qh, qh);
+ urbp->qh = qh;
+
+ uhci_add_urb_list(uhci, urb);
+
+ usb_inc_dev_use(urb->dev);
+
+ return -EINPROGRESS;
+}
+
+/* We can use the control unlink since they're identical */
+#define uhci_unlink_bulk uhci_unlink_control
+
+static int uhci_result_bulk(urb_t *urb)
+{
+ struct urb_priv *urbp = urb->hcpriv;
+ struct uhci_td *td;
+ unsigned int status;
+
+ urb->actual_length = 0;
+
+ /* The rest of the TD's (but the last) are data */
+ for (td = urbp->begin; td; td = td->next) {
+ status = uhci_status_bits(td->status);
+ if (status & TD_CTRL_ACTIVE)
+ return -EINPROGRESS;
+
+ urb->actual_length += uhci_actual_length(td->status);
+
+ /* If SPD is set then we received a short packet */
+ if (td->status & TD_CTRL_SPD && (uhci_actual_length(td->status) < uhci_expected_length(td->info))) {
+ usb_settoggle(urb->dev, uhci_endpoint(td->info),
+ uhci_packetout(td->info),
+ uhci_toggle(td->info) ^ 1);
+
+ goto td_success;
+ }
+
+ if (status)
+ goto td_error;
+ }
+
+td_success:
+ uhci_unlink_bulk(urb);
+
+ return 0;
+
+td_error:
+ /* Some debugging code */
+ if (debug) {
+ dbg("uhci_result_bulk() failed with status %x",
+ status);
+
+ /* Print the chain for debugging purposes */
+ uhci_show_queue(urbp->qh);
+ }
+
+ if (status & TD_CTRL_STALLED) {
+ /* endpoint has stalled - mark it halted */
+ usb_endpoint_halt(urb->dev, uhci_endpoint(td->info),
+ uhci_packetout(td->info));
+ return -EPIPE;
+ }
+
+ return uhci_map_status(status, uhci_packetout(td->info));
+}
+
+/*
+ * Isochronous transfers
+ */
+static int isochronous_find_limits(urb_t *urb, unsigned int *start, unsigned int *end)
+{
+ urb_t *u, *last_urb = NULL;
+ struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
+ struct list_head *tmp, *head = &uhci->urb_list;
+ unsigned long flags;
+
+ spin_lock_irqsave(&uhci->urblist_lock, flags);
+ tmp = head->next;
+ while (tmp != head) {
+ u = list_entry(tmp, urb_t, urb_list);
+
+ /* look for pending URB's with identical pipe handle */
+ if ((urb->pipe == u->pipe) && (urb->dev == u->dev) &&
+ (u->status == -EINPROGRESS) && (u != urb)) {
+ if (!last_urb)
+ *start = u->start_frame;
+ last_urb = u;
+ }
+ tmp = tmp->next;
+ }
+ spin_unlock_irqrestore(&uhci->urblist_lock, flags);
+
+ if (last_urb) {
+ *end = (last_urb->start_frame + last_urb->number_of_packets) & 1023;
+ return 0;
+ } else
+ return -1; // no previous urb found
+
+}
+
+static int isochronous_find_start(urb_t *urb)
+{
+ int limits;
+ unsigned int start = 0, end = 0;
+
+ if (urb->number_of_packets > 900) /* 900? Why? */
+ return -EFBIG;
+
+ limits = isochronous_find_limits(urb, &start, &end);
+
+ if (urb->transfer_flags & USB_ISO_ASAP) {
+ if (limits) {
+ int curframe;
+
+ curframe = uhci_get_current_frame_number(urb->dev) % UHCI_NUMFRAMES;
+ urb->start_frame = (curframe + 10) % UHCI_NUMFRAMES;
+ } else
+ urb->start_frame = end;
+ } else {
+ urb->start_frame %= UHCI_NUMFRAMES;
+ /* FIXME: Sanity check */
+ }
+
+ return 0;
+}
+
+static int uhci_submit_isochronous(urb_t *urb)
+{
+ struct uhci_td *td;
+ struct uhci_device *dev = usb_to_uhci(urb->dev);
+ struct uhci *uhci = dev->uhci;
+ struct urb_priv *urbp;
+ int i, ret, framenum;
+ int status, destination;
+
+ status = TD_CTRL_ACTIVE | TD_CTRL_IOS;
+ destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
+
+ ret = isochronous_find_start(urb);
+ if (ret)
+ return ret;
+
+ urbp = kmalloc(sizeof(*urbp), in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
+ if (!urbp)
+ return -ENOMEM;
+
+ urbp->begin = urbp->end = NULL;
+
+ urb->hcpriv = urbp;
+
+ framenum = urb->start_frame;
+ for (i = 0; i < urb->number_of_packets; i++, framenum++) {
+ if (!urb->iso_frame_desc[i].length)
+ continue;
+
+ td = uhci_td_alloc(dev);
+ if (!td) {
+ /* FIXME: Free the TD's */
+ return -ENOMEM;
+ }
+
+ uhci_add_td_to_urb(urb, td);
+ uhci_fill_td(td, status, destination | ((urb->iso_frame_desc[i].length - 1) << 21),
+ virt_to_bus(urb->transfer_buffer + urb->iso_frame_desc[i].offset));
+
+ if (i + 1 >= urb->number_of_packets) {
+ td->status |= TD_CTRL_IOC;
+ uhci_add_irq_list(uhci, td);
+ }
+
+ uhci_insert_td_frame_list(uhci, td, framenum);
+ }
+
+ uhci_add_urb_list(uhci, urb);
+
+ usb_inc_dev_use(urb->dev);
+
+ return -EINPROGRESS;
+}
+
+static int uhci_unlink_isochronous(urb_t *urb)
+{
+ struct urb_priv *urbp = urb->hcpriv;
+ struct uhci_td *td;
+ struct uhci_device *dev = usb_to_uhci(urb->dev);
+ struct uhci *uhci = dev->uhci;
+
+ if (!urbp)
+ return -EINVAL;
+
+ /* Go through the rest of the TD's, deleting them, then scheduling */
+ /* their deletion */
+ td = urbp->begin;
+ while (td) {
+ struct uhci_td *next = td->next;
+
+ uhci_remove_td(uhci, td);
+
+ if (td->status & TD_CTRL_IOC)
+ uhci_remove_irq_list(uhci, td);
+ uhci_schedule_delete_td(uhci, td);
+
+ td = next;
+ }
+
+ kfree(urbp);
+ urb->hcpriv = NULL;
+
+ uhci_remove_urb_list(uhci, urb);
+
+ return 0;
+}
+
+static int uhci_result_isochronous(urb_t *urb)
+{
+ struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+ struct uhci_td *td;
+ int status;
+ int i, ret = 0;
+
+ td = urbp->end;
+ if (!td) /* Nothing to do */
+ return -EINVAL;
+
+ status = uhci_status_bits(td->status);
+ if (status & TD_CTRL_ACTIVE)
+ return -EINPROGRESS;
+
+ /* Assume no errors, we'll overwrite this if not */
+ urb->status = 0;
+
+ urb->actual_length = 0;
+ for (i = 0, td = urbp->begin; td; i++, td = td->next) {
+ int actlength;
+
+ actlength = uhci_actual_length(td->status);
+ urb->iso_frame_desc[i].actual_length = actlength;
+ urb->actual_length += actlength;
+
+ status = uhci_map_status(uhci_status_bits(td->status), usb_pipeout(urb->pipe));
+ urb->iso_frame_desc[i].status = status;
+ if (status != 0) {
+ urb->error_count++;
+ ret = status;
+ }
+ }
+
+ uhci_unlink_isochronous(urb);
+
+ return status;
+}
+
+static int uhci_submit_urb(urb_t *urb)
+{
+ int ret = -EINVAL;
+ struct uhci *uhci;
+
+ if (!urb)
+ return -EINVAL;
+
+ if (!urb->dev || !urb->dev->bus)
+ return -ENODEV;
+
+ uhci = (struct uhci *)urb->dev->bus->hcpriv;
+
+ if (usb_pipedevice(urb->pipe) == uhci->rh.devnum)
+ return rh_submit_urb(urb); /* Virtual root hub */
+
+ switch (usb_pipetype(urb->pipe)) {
+ case PIPE_CONTROL:
+ ret = uhci_submit_control(urb);
+ break;
+ case PIPE_INTERRUPT:
+ ret = uhci_submit_interrupt(urb);
+ break;
+ case PIPE_BULK:
+ ret = uhci_submit_bulk(urb);
+ break;
+ case PIPE_ISOCHRONOUS:
+ ret = uhci_submit_isochronous(urb);
+ break;
+ }
+
+ urb->status = ret;
+ if (ret == -EINPROGRESS) {
+ usb_inc_dev_use(urb->dev);
+
+ return 0;
+ }
+
+ return ret;
+}
+
+/*
+ * Return the result of a transfer
+ */
+static void uhci_transfer_result(urb_t *urb)
+{
+ urb_t *turb;
+ int proceed = 0, is_ring = 0;
+ int ret = -EINVAL;
+
+ switch (usb_pipetype(urb->pipe)) {
+ case PIPE_CONTROL:
+ ret = uhci_result_control(urb);
+ break;
+ case PIPE_INTERRUPT:
+ /* Interrupts are an exception */
+ urb->status = uhci_result_interrupt(urb);
+ if (urb->status != -EINPROGRESS) {
+ urb->complete(urb);
+ uhci_reset_interrupt(urb);
+ }
+ return;
+ case PIPE_BULK:
+ ret = uhci_result_bulk(urb);
+ break;
+ case PIPE_ISOCHRONOUS:
+ ret = uhci_result_isochronous(urb);
+ break;
+ }
+
+ urb->status = ret;
+ if (urb->status == -EINPROGRESS)
+ return;
+
+ if (urb->next) {
+ turb = urb->next;
+ do {
+ if (turb->status != -EINPROGRESS) {
+ proceed = 1;
+ break;
+ }
+
+ turb = turb->next;
+ } while (turb && turb != urb && turb != urb->next);
+
+ if (turb == urb || turb == urb->next)
+ is_ring = 1;
+ }
+
+ if (urb->complete && (!proceed || (urb->transfer_flags & USB_URB_EARLY_COMPLETE))) {
+ urb->complete(urb);
+ if (!proceed && is_ring)
+ uhci_submit_urb(urb);
+ }
+
+ if (proceed && urb->next) {
+ turb = urb->next;
+ do {
+ if (turb->status != -EINPROGRESS &&
+ uhci_submit_urb(turb) != 0)
+
+ turb = turb->next;
+ } while (turb && turb != urb->next);
+
+ if (urb->complete && !(urb->transfer_flags & USB_URB_EARLY_COMPLETE))
+ urb->complete(urb);
+ }
+
+ usb_dec_dev_use(urb->dev);
+}
+
+static int uhci_unlink_urb(urb_t *urb)
+{
+ struct uhci *uhci;
+ int ret = 0;
+
+ if (!urb)
+ return -EINVAL;
+
+ uhci = (struct uhci *)urb->dev->bus->hcpriv;
+
+ if (usb_pipedevice(urb->pipe) == uhci->rh.devnum)
+ return rh_unlink_urb(urb);
+
+ if (urb->status == -EINPROGRESS) {
+ switch (usb_pipetype(urb->pipe)) {
+ case PIPE_CONTROL:
+ ret = uhci_unlink_control(urb);
+ break;
+ case PIPE_INTERRUPT:
+ ret = uhci_unlink_interrupt(urb);
+ break;
+ case PIPE_BULK:
+ ret = uhci_unlink_bulk(urb);
+ break;
+ case PIPE_ISOCHRONOUS:
+ ret = uhci_unlink_isochronous(urb);
+ break;
+ }
+
+ if (urb->complete)
+ urb->complete(urb);
+
+ if (in_interrupt()) { /* wait at least 1 frame */
+ int errorcount = 10;
+
+ if (errorcount--)
+ dbg("uhci_unlink_urb called from interrupt for urb %p", urb);
+ udelay(1000);
+ } else
+ schedule_timeout(1+1*HZ/1000);
+
+ usb_dec_dev_use(urb->dev);
+ }
+
+ urb->status = -ENOENT;
+
+ return ret;
+}
+
+/*
+ * uhci_get_current_frame_number()
+ *
+ * returns the current frame number for a USB bus/controller.
+ */
+static int uhci_get_current_frame_number(struct usb_device *usb_dev)
+{
+ struct uhci_device *dev = (struct uhci_device *)usb_dev->hcpriv;
+
+ return inw(dev->uhci->io_addr + USBFRNUM);
+}
+
+struct usb_operations uhci_device_operations = {
+ uhci_alloc_dev,
+ uhci_free_dev,
+ uhci_get_current_frame_number,
+ uhci_submit_urb,
+ uhci_unlink_urb
+};
+
+/* -------------------------------------------------------------------
+ Virtual Root Hub
+ ------------------------------------------------------------------- */
+
+static __u8 root_hub_dev_des[] =
+{
+ 0x12, /* __u8 bLength; */
+ 0x01, /* __u8 bDescriptorType; Device */
+ 0x00, /* __u16 bcdUSB; v1.0 */
+ 0x01,
+ 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */
+ 0x00, /* __u8 bDeviceSubClass; */
+ 0x00, /* __u8 bDeviceProtocol; */
+ 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */
+ 0x00, /* __u16 idVendor; */
+ 0x00,
+ 0x00, /* __u16 idProduct; */
+ 0x00,
+ 0x00, /* __u16 bcdDevice; */
+ 0x00,
+ 0x00, /* __u8 iManufacturer; */
+ 0x00, /* __u8 iProduct; */
+ 0x00, /* __u8 iSerialNumber; */
+ 0x01 /* __u8 bNumConfigurations; */
+};
+
+
+/* Configuration descriptor */
+static __u8 root_hub_config_des[] =
+{
+ 0x09, /* __u8 bLength; */
+ 0x02, /* __u8 bDescriptorType; Configuration */
+ 0x19, /* __u16 wTotalLength; */
+ 0x00,
+ 0x01, /* __u8 bNumInterfaces; */
+ 0x01, /* __u8 bConfigurationValue; */
+ 0x00, /* __u8 iConfiguration; */
+ 0x40, /* __u8 bmAttributes;
+ Bit 7: Bus-powered, 6: Self-powered,
+ Bit 5 Remote-wakeup, 4..0: resvd */
+ 0x00, /* __u8 MaxPower; */
+
+ /* interface */
+ 0x09, /* __u8 if_bLength; */
+ 0x04, /* __u8 if_bDescriptorType; Interface */
+ 0x00, /* __u8 if_bInterfaceNumber; */
+ 0x00, /* __u8 if_bAlternateSetting; */
+ 0x01, /* __u8 if_bNumEndpoints; */
+ 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */
+ 0x00, /* __u8 if_bInterfaceSubClass; */
+ 0x00, /* __u8 if_bInterfaceProtocol; */
+ 0x00, /* __u8 if_iInterface; */
+
+ /* endpoint */
+ 0x07, /* __u8 ep_bLength; */
+ 0x05, /* __u8 ep_bDescriptorType; Endpoint */
+ 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */
+ 0x03, /* __u8 ep_bmAttributes; Interrupt */
+ 0x08, /* __u16 ep_wMaxPacketSize; 8 Bytes */
+ 0x00,
+ 0xff /* __u8 ep_bInterval; 255 ms */
+};
+
+static __u8 root_hub_hub_des[] =
+{
+ 0x09, /* __u8 bLength; */
+ 0x29, /* __u8 bDescriptorType; Hub-descriptor */
+ 0x02, /* __u8 bNbrPorts; */
+ 0x00, /* __u16 wHubCharacteristics; */
+ 0x00,
+ 0x01, /* __u8 bPwrOn2pwrGood; 2ms */
+ 0x00, /* __u8 bHubContrCurrent; 0 mA */
+ 0x00, /* __u8 DeviceRemovable; *** 7 Ports max *** */
+ 0xff /* __u8 PortPwrCtrlMask; *** 7 ports max *** */
+};
+
+/*-------------------------------------------------------------------------*/
+/* prepare Interrupt pipe transaction data; HUB INTERRUPT ENDPOINT */
+static int rh_send_irq(urb_t *urb)
+{
+ int i, len = 1;
+ struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
+ unsigned int io_addr = uhci->io_addr;
+ __u16 data = 0;
+
+ for (i = 0; i < uhci->rh.numports; i++) {
+ data |= ((inw(io_addr + USBPORTSC1 + i * 2) & 0xa) > 0 ? (1 << (i + 1)) : 0);
+ len = (i + 1) / 8 + 1;
+ }
+
+ *(__u16 *) urb->transfer_buffer = cpu_to_le16(data);
+ urb->actual_length = len;
+ urb->status = USB_ST_NOERROR;
+
+ if ((data > 0) && (uhci->rh.send != 0)) {
+#ifdef DEBUG /* JE */
+static int foo=5;
+if (foo--)
+#endif
+ dbg("root-hub INT complete: port1: %x port2: %x data: %x",
+ inw(io_addr + USBPORTSC1), inw(io_addr + USBPORTSC2), data);
+ urb->complete(urb);
+ }
+
+ return USB_ST_NOERROR;
+}
+
+/*-------------------------------------------------------------------------*/
+/* Virtual Root Hub INTs are polled by this timer every "interval" ms */
+static int rh_init_int_timer(urb_t *urb);
+
+static void rh_int_timer_do(unsigned long ptr)
+{
+ int len;
+ urb_t *urb = (urb_t *)ptr;
+ struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
+
+ if (uhci->rh.send) {
+ len = rh_send_irq(urb);
+ if (len > 0) {
+ urb->actual_length = len;
+ if (urb->complete)
+ urb->complete(urb);
+ }
+ }
+
+ rh_init_int_timer(urb);
+}
+
+/*-------------------------------------------------------------------------*/
+/* Root Hub INTs are polled by this timer */
+static int rh_init_int_timer(urb_t *urb)
+{
+ struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
+
+ uhci->rh.interval = urb->interval;
+ init_timer(&uhci->rh.rh_int_timer);
+ uhci->rh.rh_int_timer.function = rh_int_timer_do;
+ uhci->rh.rh_int_timer.data = (unsigned long)urb;
+ uhci->rh.rh_int_timer.expires = jiffies + (HZ * (urb->interval < 30 ? 30 : urb->interval)) / 1000;
+ add_timer(&uhci->rh.rh_int_timer);
+
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+#define OK(x) len = (x); break
+
+#define CLR_RH_PORTSTAT(x) \
+ status = inw(io_addr + USBPORTSC1 + 2 * (wIndex-1)); \
+ status = (status & 0xfff5) & ~(x); \
+ outw(status, io_addr + USBPORTSC1 + 2 * (wIndex-1))
+
+#define SET_RH_PORTSTAT(x) \
+ status = inw(io_addr + USBPORTSC1 + 2 * (wIndex-1)); \
+ status = (status & 0xfff5) | (x); \
+ outw(status, io_addr + USBPORTSC1 + 2 * (wIndex-1))
+
+
+/*-------------------------------------------------------------------------*/
+/*************************
+ ** Root Hub Control Pipe
+ *************************/
+
+static int rh_submit_urb(urb_t *urb)
+{
+ struct usb_device *usb_dev = urb->dev;
+ struct uhci *uhci = (struct uhci *)usb_dev->bus->hcpriv;
+ unsigned int pipe = urb->pipe;
+ devrequest *cmd = (devrequest *)urb->setup_packet;
+ void *data = urb->transfer_buffer;
+ int leni = urb->transfer_buffer_length;
+ int len = 0;
+ int status = 0;
+ int stat = USB_ST_NOERROR;
+ int i;
+ unsigned int io_addr = uhci->io_addr;
+ __u16 cstatus;
+ __u16 bmRType_bReq;
+ __u16 wValue;
+ __u16 wIndex;
+ __u16 wLength;
+
+ if (usb_pipetype(pipe) == PIPE_INTERRUPT) {
+ uhci->rh.urb = urb;
+ uhci->rh.send = 1;
+ uhci->rh.interval = urb->interval;
+ rh_init_int_timer(urb);
+
+ return USB_ST_NOERROR;
+ }
+
+ bmRType_bReq = cmd->requesttype | cmd->request << 8;
+ wValue = le16_to_cpu(cmd->value);
+ wIndex = le16_to_cpu(cmd->index);
+ wLength = le16_to_cpu(cmd->length);
+
+ for (i = 0; i < 8; i++)
+ uhci->rh.c_p_r[i] = 0;
+
+ switch (bmRType_bReq) {
+ /* Request Destination:
+ without flags: Device,
+ RH_INTERFACE: interface,
+ RH_ENDPOINT: endpoint,
+ RH_CLASS means HUB here,
+ RH_OTHER | RH_CLASS almost ever means HUB_PORT here
+ */
+
+ case RH_GET_STATUS:
+ *(__u16 *)data = cpu_to_le16(1);
+ OK(2);
+ case RH_GET_STATUS | RH_INTERFACE:
+ *(__u16 *)data = cpu_to_le16(0);
+ OK(2);
+ case RH_GET_STATUS | RH_ENDPOINT:
+ *(__u16 *)data = cpu_to_le16(0);
+ OK(2);
+ case RH_GET_STATUS | RH_CLASS:
+ *(__u32 *)data = cpu_to_le32(0);
+ OK(4); /* hub power */
+ case RH_GET_STATUS | RH_OTHER | RH_CLASS:
+ status = inw(io_addr + USBPORTSC1 + 2 * (wIndex - 1));
+ cstatus = ((status & USBPORTSC_CSC) >> (1 - 0)) |
+ ((status & USBPORTSC_PEC) >> (3 - 1)) |
+ (uhci->rh.c_p_r[wIndex - 1] << (0 + 4));
+ status = (status & USBPORTSC_CCS) |
+ ((status & USBPORTSC_PE) >> (2 - 1)) |
+ ((status & USBPORTSC_SUSP) >> (12 - 2)) |
+ ((status & USBPORTSC_PR) >> (9 - 4)) |
+ (1 << 8) | /* power on */
+ ((status & USBPORTSC_LSDA) << (-8 + 9));
+
+ *(__u16 *)data = cpu_to_le16(status);
+ *(__u16 *)(data + 2) = cpu_to_le16(cstatus);
+ OK(4);
+ case RH_CLEAR_FEATURE | RH_ENDPOINT:
+ switch (wValue) {
+ case RH_ENDPOINT_STALL:
+ OK(0);
+ }
+ break;
+ case RH_CLEAR_FEATURE | RH_CLASS:
+ switch (wValue) {
+ case RH_C_HUB_OVER_CURRENT:
+ OK(0); /* hub power over current */
+ }
+ break;
+ case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
+ switch (wValue) {
+ case RH_PORT_ENABLE:
+ CLR_RH_PORTSTAT(USBPORTSC_PE);
+ OK(0);
+ case RH_PORT_SUSPEND:
+ CLR_RH_PORTSTAT(USBPORTSC_SUSP);
+ OK(0);
+ case RH_PORT_POWER:
+ OK(0); /* port power */
+ case RH_C_PORT_CONNECTION:
+ SET_RH_PORTSTAT(USBPORTSC_CSC);
+ OK(0);
+ case RH_C_PORT_ENABLE:
+ SET_RH_PORTSTAT(USBPORTSC_PEC);
+ OK(0);
+ case RH_C_PORT_SUSPEND:
+ /*** WR_RH_PORTSTAT(RH_PS_PSSC); */
+ OK(0);
+ case RH_C_PORT_OVER_CURRENT:
+ OK(0); /* port power over current */
+ case RH_C_PORT_RESET:
+ uhci->rh.c_p_r[wIndex - 1] = 0;
+ OK(0);
+ }
+ break;
+ case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
+ switch (wValue) {
+ case RH_PORT_SUSPEND:
+ SET_RH_PORTSTAT(USBPORTSC_SUSP);
+ OK(0);
+ case RH_PORT_RESET:
+ SET_RH_PORTSTAT(USBPORTSC_PR);
+ wait_ms(10);
+ uhci->rh.c_p_r[wIndex - 1] = 1;
+ CLR_RH_PORTSTAT(USBPORTSC_PR);
+ udelay(10);
+ SET_RH_PORTSTAT(USBPORTSC_PE);
+ wait_ms(10);
+ SET_RH_PORTSTAT(0xa);
+ OK(0);
+ case RH_PORT_POWER:
+ OK(0); /* port power ** */
+ case RH_PORT_ENABLE:
+ SET_RH_PORTSTAT (USBPORTSC_PE);
+ OK(0);
+ }
+ break;
+ case RH_SET_ADDRESS:
+ uhci->rh.devnum = wValue;
+ OK(0);
+ case RH_GET_DESCRIPTOR:
+ switch ((wValue & 0xff00) >> 8) {
+ case 0x01: /* device descriptor */
+ len = min(leni, min(sizeof(root_hub_dev_des), wLength));
+ memcpy(data, root_hub_dev_des, len);
+ OK(len);
+ case 0x02: /* configuration descriptor */
+ len = min(leni, min(sizeof(root_hub_config_des), wLength));
+ memcpy (data, root_hub_config_des, len);
+ OK(len);
+ case 0x03: /* string descriptors */
+ stat = -EPIPE;
+ }
+ break;
+ case RH_GET_DESCRIPTOR | RH_CLASS:
+ root_hub_hub_des[2] = uhci->rh.numports;
+ len = min(leni, min(sizeof(root_hub_hub_des), wLength));
+ memcpy(data, root_hub_hub_des, len);
+ OK(len);
+ case RH_GET_CONFIGURATION:
+ *(__u8 *)data = 0x01;
+ OK(1);
+ case RH_SET_CONFIGURATION:
+ OK(0);
+ default:
+ stat = -EPIPE;
+ }
+
+ urb->actual_length = len;
+ urb->status = stat;
+ if (urb->complete)
+ urb->complete(urb);
+
+ return USB_ST_NOERROR;
+}
+/*-------------------------------------------------------------------------*/
+
+static int rh_unlink_urb(urb_t *urb)
+{
+ struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
+
+ uhci->rh.send = 0;
+ del_timer(&uhci->rh.rh_int_timer);
+
+ return 0;
+}
+/*-------------------------------------------------------------------*/
+
+/*
+ * This is just incredibly fragile. The timings must be just
+ * right, and they aren't really documented very well.
+ *
+ * Note the short delay between disabling reset and enabling
+ * the port..
+ */
+static void uhci_reset_port(unsigned int port)
+{
+ unsigned short status;
+
+ status = inw(port);
+ outw(status | USBPORTSC_PR, port); /* reset port */
+ wait_ms(10);
+ outw(status & ~USBPORTSC_PR, port);
+ udelay(50);
+
+ status = inw(port);
+ outw(status | USBPORTSC_PE, port); /* enable port */
+ wait_ms(10);
+
+ status = inw(port);
+ if (!(status & USBPORTSC_PE)) {
+ outw(status | USBPORTSC_PE, port); /* one more try at enabling port */
+ wait_ms(50);
+ }
+
+}
+
+void uhci_free_pending(struct uhci *uhci)
+{
+ struct list_head *tmp, *head;
+
+ /* Free all of the pending QH's and TD's */
+ head = &uhci->td_free_list;
+ tmp = head->next;
+ while (tmp != head) {
+ struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
+
+ tmp = tmp->next;
+
+ list_del(&td->list);
+ INIT_LIST_HEAD(&td->list);
+
+ uhci_td_free(td);
+ }
+
+ head = &uhci->qh_free_list;
+ tmp = head->next;
+ while (tmp != head) {
+ struct uhci_qh *qh = list_entry(tmp, struct uhci_qh, list);
+
+ tmp = tmp->next;
+
+ list_del(&qh->list);
+ INIT_LIST_HEAD(&qh->list);
+
+ uhci_qh_free(qh);
+ }
+}
+
+static void uhci_interrupt(int irq, void *__uhci, struct pt_regs *regs)
+{
+ struct uhci *uhci = __uhci;
+ unsigned int io_addr = uhci->io_addr;
+ unsigned short status;
+ unsigned long flags;
+ struct list_head *tmp, *head;
+ urb_t *urb;
+
+ /*
+ * Read the interrupt status, and write it back to clear the
+ * interrupt cause
+ */
+ status = inw(io_addr + USBSTS);
+ if (!status) /* shared interrupt, not mine */
+ return;
+ outw(status, io_addr + USBSTS);
+
+ if (status & ~(USBSTS_USBINT | USBSTS_ERROR)) {
+ if (status & USBSTS_RD)
+ printk(KERN_INFO "uhci: resume detected, not implemented\n");
+ if (status & USBSTS_HSE)
+ printk(KERN_ERR "uhci: host system error, PCI problems?\n");
+ if (status & USBSTS_HCPE)
+ printk(KERN_ERR "uhci: host controller process error. something bad happened\n");
+ if (status & USBSTS_HCH) {
+ printk(KERN_ERR "uhci: host controller halted. very bad\n");
+ /* FIXME: Reset the controller, fix the offending TD */
+ }
+ }
+
+ /* Free all of the pending QH's and TD's */
+ spin_lock(&uhci->freelist_lock);
+ uhci_free_pending(uhci);
+ spin_unlock(&uhci->freelist_lock);
+
+ /* Walk the list of pending TD's to see which ones completed.. */
+ nested_lock(&uhci->irqlist_lock, flags);
+ head = &uhci->interrupt_list;
+ tmp = head->next;
+ while (tmp != head) {
+ struct uhci_td *td = list_entry(tmp, struct uhci_td, irq_list);
+
+ urb = td->urb;
+
+ tmp = tmp->next;
+
+ /* Checks the status and does all of the magic necessary */
+ uhci_transfer_result(urb);
+ }
+ nested_unlock(&uhci->irqlist_lock, flags);
+}
+
+static void reset_hc(struct uhci *uhci)
+{
+ unsigned int io_addr = uhci->io_addr;
+
+ /* Global reset for 50ms */
+ outw(USBCMD_GRESET, io_addr + USBCMD);
+ wait_ms(50);
+ outw(0, io_addr + USBCMD);
+ wait_ms(10);
+}
+
+static void start_hc(struct uhci *uhci)
+{
+ unsigned int io_addr = uhci->io_addr;
+ int timeout = 1000;
+
+ /*
+ * Reset the HC - this will force us to get a
+ * new notification of any already connected
+ * ports due to the virtual disconnect that it
+ * implies.
+ */
+ outw(USBCMD_HCRESET, io_addr + USBCMD);
+ while (inw(io_addr + USBCMD) & USBCMD_HCRESET) {
+ if (!--timeout) {
+ printk(KERN_ERR "uhci: USBCMD_HCRESET timed out!\n");
+ break;
+ }
+ }
+
+ /* Turn on all interrupts */
+ outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP,
+ io_addr + USBINTR);
+
+ /* Start at frame 0 */
+ outw(0, io_addr + USBFRNUM);
+ outl(virt_to_bus(uhci->fl), io_addr + USBFLBASEADD);
+
+ /* Run and mark it configured with a 64-byte max packet */
+ outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, io_addr + USBCMD);
+}
+
+/*
+ * Allocate a frame list, and then setup the skeleton
+ *
+ * The hardware doesn't really know any difference
+ * in the queues, but the order does matter for the
+ * protocols higher up. The order is:
+ *
+ * - any isochronous events handled before any
+ * of the queues. We don't do that here, because
+ * we'll create the actual TD entries on demand.
+ * - The first queue is the "interrupt queue".
+ * - The second queue is the "control queue".
+ * - The third queue is "bulk data".
+ */
+static struct uhci *alloc_uhci(unsigned int io_addr, unsigned int io_size)
+{
+ int i, port;
+ struct uhci *uhci;
+ struct usb_bus *bus;
+
+ uhci = kmalloc(sizeof(*uhci), GFP_KERNEL);
+ if (!uhci)
+ return NULL;
+
+ memset(uhci, 0, sizeof(*uhci));
+
+ uhci->irq = -1;
+ uhci->io_addr = io_addr;
+ uhci->io_size = io_size;
+
+ INIT_LIST_HEAD(&uhci->interrupt_list);
+ INIT_LIST_HEAD(&uhci->urb_list);
+ INIT_LIST_HEAD(&uhci->td_free_list);
+ INIT_LIST_HEAD(&uhci->qh_free_list);
+
+ spin_lock_init(&uhci->urblist_lock);
+ spin_lock_init(&uhci->framelist_lock);
+ spin_lock_init(&uhci->freelist_lock);
+ nested_init(&uhci->irqlist_lock);
+
+ /* We need exactly one page (per UHCI specs), how convenient */
+ /* We assume that one page is atleast 4k (1024 frames * 4 bytes) */
+ uhci->fl = (void *)__get_free_page(GFP_KERNEL);
+ if (!uhci->fl)
+ goto au_free_uhci;
+
+ bus = usb_alloc_bus(&uhci_device_operations);
+ if (!bus)
+ goto au_free_fl;
+
+ uhci->bus = bus;
+ bus->hcpriv = uhci;
+
+ /* Initialize the root hub */
+
+ /* UHCI specs says devices must have 2 ports, but goes on to say */
+ /* they may have more but give no way to determine how many they */
+ /* have. However, according to the UHCI spec, Bit 7 is always set */
+ /* to 1. So we try to use this to our advantage */
+ for (port = 0; port < (io_size - 0x10) / 2; port++) {
+ unsigned int portstatus;
+
+ portstatus = inw(io_addr + 0x10 + (port * 2));
+ if (!(portstatus & 0x0080))
+ break;
+ }
+ if (debug)
+ info("detected %d ports", port);
+
+ /* This is experimental so anything less than 2 or greater than 8 is */
+ /* something weird and we'll ignore it */
+ if (port < 2 || port > 8) {
+ info("port count misdetected? forcing to 2 ports");
+ port = 2;
+ }
+
+ uhci->rh.numports = port;
+
+ /*
+ * 9 Interrupt queues; link int2 to int1, int4 to int2, etc
+ * then link int1 to control and control to bulk
+ */
+ for (i = 1; i < 9; i++) {
+ struct uhci_td *td = &uhci->skeltd[i];
+
+ uhci_fill_td(td, 0, (UHCI_NULL_DATA_SIZE << 21) | (0x7f << 8) | USB_PID_IN, 0);
+ td->link = virt_to_bus(&uhci->skeltd[i - 1]);
+ }
+
+
+ uhci_fill_td(&uhci->skel_int1_td, 0, (UHCI_NULL_DATA_SIZE << 21) | (0x7f << 8) | USB_PID_IN, 0);
+ uhci->skel_int1_td.link = virt_to_bus(&uhci->skel_control_qh) | UHCI_PTR_QH;
+
+ uhci->skel_control_qh.link = virt_to_bus(&uhci->skel_bulk_qh) | UHCI_PTR_QH;
+ uhci->skel_control_qh.element = UHCI_PTR_TERM;
+
+ uhci->skel_bulk_qh.link = UHCI_PTR_TERM;
+ uhci->skel_bulk_qh.element = UHCI_PTR_TERM;
+
+ /*
+ * Fill the frame list: make all entries point to
+ * the proper interrupt queue.
+ *
+ * This is probably silly, but it's a simple way to
+ * scatter the interrupt queues in a way that gives
+ * us a reasonable dynamic range for irq latencies.
+ */
+ for (i = 0; i < 1024; i++) {
+ struct uhci_td *irq = &uhci->skel_int2_td;
+
+ if (i & 1) {
+ irq++;
+ if (i & 2) {
+ irq++;
+ if (i & 4) {
+ irq++;
+ if (i & 8) {
+ irq++;
+ if (i & 16) {
+ irq++;
+ if (i & 32) {
+ irq++;
+ if (i & 64)
+ irq++;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* Only place we don't use the frame list routines */
+ uhci->fl->frame[i] = virt_to_bus(irq);
+ }
+
+ return uhci;
+
+/*
+ * error exits:
+ */
+au_free_fl:
+ free_page((unsigned long)uhci->fl);
+au_free_uhci:
+ kfree(uhci);
+
+ return NULL;
+}
+
+/*
+ * De-allocate all resources..
+ */
+static void release_uhci(struct uhci *uhci)
+{
+ if (uhci->irq >= 0) {
+ free_irq(uhci->irq, uhci);
+ uhci->irq = -1;
+ }
+
+ if (uhci->fl) {
+ free_page((unsigned long)uhci->fl);
+ uhci->fl = NULL;
+ }
+
+ usb_free_bus(uhci->bus);
+ kfree(uhci);
+}
+
+int uhci_start_root_hub(struct uhci *uhci)
+{
+ struct usb_device *usb_dev;
+
+ usb_dev = usb_alloc_dev(NULL, uhci->bus);
+ if (!usb_dev)
+ return -1;
+
+ usb_to_uhci(usb_dev)->uhci = uhci;
+
+ uhci->bus->root_hub = usb_dev;
+ usb_connect(usb_dev);
+
+ if (usb_new_device(usb_dev) != 0) {
+ usb_free_dev(usb_dev);
+
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * If we've successfully found a UHCI, now is the time to increment the
+ * module usage count, and return success..
+ */
+static int setup_uhci(int irq, unsigned int io_addr, unsigned int io_size)
+{
+ int retval;
+ struct uhci *uhci;
+
+ uhci = alloc_uhci(io_addr, io_size);
+ if (!uhci)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&uhci->uhci_list);
+ list_add(&uhci->uhci_list, &uhci_list);
+
+ request_region(uhci->io_addr, io_size, "usb-uhci");
+
+ reset_hc(uhci);
+
+ usb_register_bus(uhci->bus);
+ start_hc(uhci);
+
+ retval = -EBUSY;
+ if (request_irq(irq, uhci_interrupt, SA_SHIRQ, "usb-uhci", uhci) == 0) {
+ uhci->irq = irq;
+
+ if (!uhci_start_root_hub(uhci))
+ return 0;
+ }
+
+ /* Couldn't allocate IRQ if we got here */
+ list_del(&uhci->uhci_list);
+ INIT_LIST_HEAD(&uhci->uhci_list);
+
+ reset_hc(uhci);
+ release_region(uhci->io_addr, uhci->io_size);
+ release_uhci(uhci);
+
+ return retval;
+}
+
+static int found_uhci(struct pci_dev *dev)
+{
+ int i;
+
+ /* Search for the IO base address.. */
+ for (i = 0; i < 6; i++) {
+ unsigned int io_addr = dev->resource[i].start;
+ unsigned int io_size =
+ dev->resource[i].end - dev->resource[i].start + 1;
+
+ /* IO address? */
+ if (!(dev->resource[i].flags & 1))
+ continue;
+
+ /* Is it already in use? */
+ if (check_region(io_addr, io_size))
+ break;
+
+ /* disable legacy emulation */
+ pci_write_config_word(dev, USBLEGSUP, USBLEGSUP_DEFAULT);
+
+ pci_enable_device(dev);
+
+ if (!dev->irq) {
+ err("found UHCI device with no IRQ assigned. check BIOS settings!");
+ continue;
+ }
+
+ return setup_uhci(dev->irq, io_addr, io_size);
+ }
+
+ return -1;
+}
+
+#ifdef CONFIG_APM
+static int handle_apm_event(apm_event_t event)
+{
+ static int down = 0;
+
+ switch (event) {
+ case APM_SYS_SUSPEND:
+ case APM_USER_SUSPEND:
+ if (down) {
+ dbg("received extra suspend event");
+ break;
+ }
+ down = 1;
+ break;
+ case APM_NORMAL_RESUME:
+ case APM_CRITICAL_RESUME:
+ if (!down) {
+ dbg("received bogus resume event");
+ break;
+ }
+ down = 0;
+ break;
+ }
+ return 0;
+}
+#endif
+
+int uhci_init(void)
+{
+ int retval;
+ struct pci_dev *dev;
+ u8 type;
+
+ retval = -ENOMEM;
+
+ /* We throw all of the TD's and QH's into a kmem cache */
+ /* TD's and QH's need to be 16 byte aligned and SLAB_HWCACHE_ALIGN */
+ /* does this for us */
+ uhci_td_cachep = kmem_cache_create("uhci_td",
+ sizeof(struct uhci_td), 0,
+ SLAB_HWCACHE_ALIGN, NULL, NULL);
+
+ if (!uhci_td_cachep)
+ goto td_failed;
+
+ uhci_qh_cachep = kmem_cache_create("uhci_qh",
+ sizeof(struct uhci_qh), 0,
+ SLAB_HWCACHE_ALIGN, NULL, NULL);
+
+ if (!uhci_qh_cachep)
+ goto qh_failed;
+
+ retval = -ENODEV;
+ dev = NULL;
+ for (;;) {
+ dev = pci_find_class(PCI_CLASS_SERIAL_USB << 8, dev);
+ if (!dev)
+ break;
+
+ /* Is it the UHCI programming interface? */
+ pci_read_config_byte(dev, PCI_CLASS_PROG, &type);
+ if (type != 0)
+ continue;
+
+ /* Ok set it up */
+ retval = found_uhci(dev);
+ }
+
+ /* We only want to return an error code if ther was an error */
+ /* and we didn't find a UHCI controller */
+ if (retval && uhci_list.next == &uhci_list)
+ goto init_failed;
+
+#ifdef CONFIG_APM
+ apm_register_callback(&handle_apm_event);
+#endif
+
+ return 0;
+
+init_failed:
+ if (kmem_cache_destroy(uhci_qh_cachep))
+ printk(KERN_INFO "uhci: not all QH's were freed\n");
+
+qh_failed:
+ if (kmem_cache_destroy(uhci_td_cachep))
+ printk(KERN_INFO "uhci: not all TD's were freed\n");
+
+td_failed:
+ return retval;
+}
+
+void uhci_cleanup(void)
+{
+ struct list_head *next, *tmp, *head = &uhci_list;
+ int i;
+ unsigned long flags;
+
+ tmp = head->next;
+ while (tmp != head) {
+ struct uhci *uhci = list_entry(tmp, struct uhci, uhci_list);
+
+ next = tmp->next;
+
+ list_del(&uhci->uhci_list);
+ INIT_LIST_HEAD(&uhci->uhci_list);
+
+ if (uhci->bus->root_hub)
+ usb_disconnect(&uhci->bus->root_hub);
+
+ usb_deregister_bus(uhci->bus);
+
+ reset_hc(uhci);
+ release_region(uhci->io_addr, uhci->io_size);
+
+ /* Free any outstanding TD's and QH's */
+ spin_lock_irqsave(&uhci->freelist_lock, flags);
+ uhci_free_pending(uhci);
+ spin_unlock_irqrestore(&uhci->freelist_lock, flags);
+
+ release_uhci(uhci);
+
+ tmp = next;
+ }
+
+ if (kmem_cache_destroy(uhci_qh_cachep))
+ printk(KERN_INFO "uhci: not all QH's were freed\n");
+
+ if (kmem_cache_destroy(uhci_td_cachep))
+ printk(KERN_INFO "uhci: not all TD's were freed\n");
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+ return uhci_init();
+}
+
+void cleanup_module(void)
+{
+#ifdef CONFIG_APM
+ apm_unregister_callback(&handle_apm_event);
+#endif
+ uhci_cleanup();
+}
+#endif //MODULE
+
diff --git a/drivers/usb/uhci.h b/drivers/usb/uhci.h
new file mode 100644
index 000000000..65c597861
--- /dev/null
+++ b/drivers/usb/uhci.h
@@ -0,0 +1,425 @@
+#ifndef __LINUX_UHCI_H
+#define __LINUX_UHCI_H
+
+#include <linux/list.h>
+
+#include "usb.h"
+
+/*
+ * This nested spinlock code is courtesy of Davide Libenzi <dlibenzi@maticad.it>
+ */
+struct s_nested_lock {
+ spinlock_t lock;
+ void *uniq;
+ short int count;
+};
+
+#define nested_init(snl) \
+ spin_lock_init(&(snl)->lock); \
+ (snl)->uniq = NULL; \
+ (snl)->count = 0;
+
+#define nested_lock(snl, flags) \
+ if ((snl)->uniq == current) { \
+ (snl)->count++; \
+ flags = 0; /* No warnings */ \
+ } else { \
+ spin_lock_irqsave(&(snl)->lock, flags); \
+ (snl)->count++; \
+ (snl)->uniq = current; \
+ }
+
+#define nested_unlock(snl, flags) \
+ if (!--(snl)->count) { \
+ (snl)->uniq = NULL; \
+ spin_unlock_irqrestore(&(snl)->lock, flags); \
+ }
+
+/*
+ * Universal Host Controller Interface data structures and defines
+ */
+
+/* Command register */
+#define USBCMD 0
+#define USBCMD_RS 0x0001 /* Run/Stop */
+#define USBCMD_HCRESET 0x0002 /* Host reset */
+#define USBCMD_GRESET 0x0004 /* Global reset */
+#define USBCMD_EGSM 0x0008 /* Global Suspend Mode */
+#define USBCMD_FGR 0x0010 /* Force Global Resume */
+#define USBCMD_SWDBG 0x0020 /* SW Debug mode */
+#define USBCMD_CF 0x0040 /* Config Flag (sw only) */
+#define USBCMD_MAXP 0x0080 /* Max Packet (0 = 32, 1 = 64) */
+
+/* Status register */
+#define USBSTS 2
+#define USBSTS_USBINT 0x0001 /* Interrupt due to IOC */
+#define USBSTS_ERROR 0x0002 /* Interrupt due to error */
+#define USBSTS_RD 0x0004 /* Resume Detect */
+#define USBSTS_HSE 0x0008 /* Host System Error - basically PCI problems */
+#define USBSTS_HCPE 0x0010 /* Host Controller Process Error - the scripts were buggy */
+#define USBSTS_HCH 0x0020 /* HC Halted */
+
+/* Interrupt enable register */
+#define USBINTR 4
+#define USBINTR_TIMEOUT 0x0001 /* Timeout/CRC error enable */
+#define USBINTR_RESUME 0x0002 /* Resume interrupt enable */
+#define USBINTR_IOC 0x0004 /* Interrupt On Complete enable */
+#define USBINTR_SP 0x0008 /* Short packet interrupt enable */
+
+#define USBFRNUM 6
+#define USBFLBASEADD 8
+#define USBSOF 12
+
+/* USB port status and control registers */
+#define USBPORTSC1 16
+#define USBPORTSC2 18
+#define USBPORTSC_CCS 0x0001 /* Current Connect Status ("device present") */
+#define USBPORTSC_CSC 0x0002 /* Connect Status Change */
+#define USBPORTSC_PE 0x0004 /* Port Enable */
+#define USBPORTSC_PEC 0x0008 /* Port Enable Change */
+#define USBPORTSC_LS 0x0030 /* Line Status */
+#define USBPORTSC_RD 0x0040 /* Resume Detect */
+#define USBPORTSC_LSDA 0x0100 /* Low Speed Device Attached */
+#define USBPORTSC_PR 0x0200 /* Port Reset */
+#define USBPORTSC_SUSP 0x1000 /* Suspend */
+
+/* Legacy support register */
+#define USBLEGSUP 0xc0
+#define USBLEGSUP_DEFAULT 0x2000 /* only PIRQ enable set */
+
+#define UHCI_NULL_DATA_SIZE 0x7FF /* for UHCI controller TD */
+
+#define UHCI_PTR_BITS 0x000F
+#define UHCI_PTR_TERM 0x0001
+#define UHCI_PTR_QH 0x0002
+#define UHCI_PTR_DEPTH 0x0004
+
+#define UHCI_NUMFRAMES 1024 /* in the frame list [array] */
+#define UHCI_MAX_SOF_NUMBER 2047 /* in an SOF packet */
+#define CAN_SCHEDULE_FRAMES 1000 /* how far future frames can be scheduled */
+
+struct uhci_td;
+
+struct uhci_qh {
+ /* Hardware fields */
+ __u32 link; /* Next queue */
+ __u32 element; /* Queue element pointer */
+
+ /* Software fields */
+ struct uhci_qh *prevqh, *nextqh; /* Previous and next TD in queue */
+
+ struct uhci_device *dev; /* The owning device */
+
+ struct list_head list;
+} __attribute__((aligned(16)));
+
+struct uhci_framelist {
+ __u32 frame[UHCI_NUMFRAMES];
+} __attribute__((aligned(4096)));
+
+/*
+ * for TD <status>:
+ */
+#define TD_CTRL_SPD (1 << 29) /* Short Packet Detect */
+#define TD_CTRL_C_ERR_MASK (3 << 27) /* Error Counter bits */
+#define TD_CTRL_LS (1 << 26) /* Low Speed Device */
+#define TD_CTRL_IOS (1 << 25) /* Isochronous Select */
+#define TD_CTRL_IOC (1 << 24) /* Interrupt on Complete */
+#define TD_CTRL_ACTIVE (1 << 23) /* TD Active */
+#define TD_CTRL_STALLED (1 << 22) /* TD Stalled */
+#define TD_CTRL_DBUFERR (1 << 21) /* Data Buffer Error */
+#define TD_CTRL_BABBLE (1 << 20) /* Babble Detected */
+#define TD_CTRL_NAK (1 << 19) /* NAK Received */
+#define TD_CTRL_CRCTIMEO (1 << 18) /* CRC/Time Out Error */
+#define TD_CTRL_BITSTUFF (1 << 17) /* Bit Stuff Error */
+#define TD_CTRL_ACTLEN_MASK 0x7FF /* actual length, encoded as n - 1 */
+
+#define TD_CTRL_ANY_ERROR (TD_CTRL_STALLED | TD_CTRL_DBUFERR | \
+ TD_CTRL_BABBLE | TD_CTRL_CRCTIME | TD_CTRL_BITSTUFF)
+
+#define uhci_status_bits(ctrl_sts) (ctrl_sts & 0xFE0000)
+#define uhci_actual_length(ctrl_sts) ((ctrl_sts + 1) & TD_CTRL_ACTLEN_MASK) /* 1-based */
+
+#define uhci_ptr_to_virt(x) bus_to_virt(x & ~UHCI_PTR_BITS)
+
+/*
+ * for TD <info>: (a.k.a. Token)
+ */
+#define TD_TOKEN_TOGGLE 19
+#define TD_PID 0xFF
+
+#define uhci_maxlen(token) ((token) >> 21)
+#define uhci_expected_length(info) (((info >> 21) + 1) & TD_CTRL_ACTLEN_MASK) /* 1-based */
+#define uhci_toggle(token) (((token) >> TD_TOKEN_TOGGLE) & 1)
+#define uhci_endpoint(token) (((token) >> 15) & 0xf)
+#define uhci_devaddr(token) (((token) >> 8) & 0x7f)
+#define uhci_devep(token) (((token) >> 8) & 0x7ff)
+#define uhci_packetid(token) ((token) & 0xff)
+#define uhci_packetout(token) (uhci_packetid(token) != USB_PID_IN)
+#define uhci_packetin(token) (uhci_packetid(token) == USB_PID_IN)
+
+/*
+ * The documentation says "4 words for hardware, 4 words for software".
+ *
+ * That's silly, the hardware doesn't care. The hardware only cares that
+ * the hardware words are 16-byte aligned, and we can have any amount of
+ * sw space after the TD entry as far as I can tell.
+ *
+ * But let's just go with the documentation, at least for 32-bit machines.
+ * On 64-bit machines we probably want to take advantage of the fact that
+ * hw doesn't really care about the size of the sw-only area.
+ *
+ * Alas, not anymore, we have more than 4 words for software, woops
+ */
+struct uhci_td {
+ /* Hardware fields */
+ __u32 link;
+ __u32 status;
+ __u32 info;
+ __u32 buffer;
+
+ /* Software fields */
+ unsigned int *frameptr; /* Frame list pointer */
+ struct uhci_td *prevtd, *nexttd; /* Previous and next TD in queue */
+
+ struct uhci_device *dev;
+ struct urb *urb; /* URB this TD belongs to */
+ struct uhci_td *next; /* List of chained TD's for an URB */
+
+ struct list_head irq_list; /* Active interrupt list.. */
+ struct list_head list;
+} __attribute__((aligned(16)));
+
+/*
+ * Note the alignment requirements of the entries
+ *
+ * Each UHCI device has pre-allocated QH and TD entries.
+ * You can use more than the pre-allocated ones, but I
+ * don't see you usually needing to.
+ */
+struct uhci;
+
+struct uhci_device {
+ struct usb_device *usb;
+
+ atomic_t refcnt;
+
+ struct uhci *uhci; /* HC this device is connected to */
+};
+
+#define uhci_to_usb(uhci) ((uhci)->usb)
+#define usb_to_uhci(usb) ((struct uhci_device *)(usb)->hcpriv)
+
+/*
+ * There are various standard queues. We set up several different
+ * queues for each of the three basic queue types: interrupt,
+ * control, and bulk.
+ *
+ * - There are various different interrupt latencies: ranging from
+ * every other USB frame (2 ms apart) to every 256 USB frames (ie
+ * 256 ms apart). Make your choice according to how obnoxious you
+ * want to be on the wire, vs how critical latency is for you.
+ * - The control list is done every frame.
+ * - There are 4 bulk lists, so that up to four devices can have a
+ * bulk list of their own and when run concurrently all four lists
+ * will be be serviced.
+ *
+ * This is a bit misleading, there are various interrupt latencies, but they
+ * vary a bit, interrupt2 isn't exactly 2ms, it can vary up to 4ms since the
+ * other queues can "override" it. interrupt4 can vary up to 8ms, etc. Minor
+ * problem
+ *
+ * In the case of the root hub, these QH's are just head's of qh's. Don't
+ * be scared, it kinda makes sense. Look at this wonderful picture care of
+ * Linus:
+ *
+ * generic- -> dev1- -> generic- -> dev1- -> control- -> bulk- -> ...
+ * iso-QH iso-QH irq-QH irq-QH QH QH
+ * | | | | | |
+ * End dev1-iso-TD1 End dev1-irq-TD1 ... ...
+ * |
+ * dev1-iso-TD2
+ * |
+ * ....
+ *
+ * This may vary a bit (the UHCI docs don't explicitly say you can put iso
+ * transfers in QH's and all of their pictures don't have that either) but
+ * other than that, that is what we're doing now
+ *
+ * And now we don't put Iso transfers in QH's, so we don't waste one on it
+ * --jerdfelt
+ *
+ * To keep with Linus' nomenclature, this is called the QH skeleton. These
+ * labels (below) are only signficant to the root hub's QH's
+ */
+
+#define UHCI_NUM_SKELTD 9
+#define skel_int1_td skeltd[0]
+#define skel_int2_td skeltd[1]
+#define skel_int4_td skeltd[2]
+#define skel_int8_td skeltd[3]
+#define skel_int16_td skeltd[4]
+#define skel_int32_td skeltd[5]
+#define skel_int64_td skeltd[6]
+#define skel_int128_td skeltd[7]
+#define skel_int256_td skeltd[8]
+
+#define UHCI_NUM_SKELQH 2
+#define skel_control_qh skelqh[0]
+#define skel_bulk_qh skelqh[1]
+
+/*
+ * Search tree for determining where <interval> fits in the
+ * skelqh[] skeleton.
+ *
+ * An interrupt request should be placed into the slowest skelqh[]
+ * which meets the interval/period/frequency requirement.
+ * An interrupt request is allowed to be faster than <interval> but not slower.
+ *
+ * For a given <interval>, this function returns the appropriate/matching
+ * skelqh[] index value.
+ *
+ * NOTE: For UHCI, we don't really need int256_qh since the maximum interval
+ * is 255 ms. However, we do need an int1_qh since 1 is a valid interval
+ * and we should meet that frequency when requested to do so.
+ * This will require some change(s) to the UHCI skeleton.
+ */
+static inline int __interval_to_skel(int interval)
+{
+ if (interval < 16) {
+ if (interval < 4) {
+ if (interval < 2)
+ return 0; /* int1 for 0-1 ms */
+ return 1; /* int2 for 2-3 ms */
+ }
+ if (interval < 8)
+ return 2; /* int4 for 4-7 ms */
+ return 3; /* int8 for 8-15 ms */
+ }
+ if (interval < 64) {
+ if (interval < 32)
+ return 4; /* int16 for 16-31 ms */
+ return 5; /* int32 for 32-63 ms */
+ }
+ if (interval < 128)
+ return 6; /* int64 for 64-127 ms */
+ return 7; /* int128 for 128-255 ms (Max.) */
+}
+
+struct virt_root_hub {
+ int devnum; /* Address of Root Hub endpoint */
+ void *urb;
+ void *int_addr;
+ int send;
+ int interval;
+ int numports;
+ int c_p_r[8];
+ struct timer_list rh_int_timer;
+};
+
+/*
+ * This describes the full uhci information.
+ *
+ * Note how the "proper" USB information is just
+ * a subset of what the full implementation needs.
+ */
+struct uhci {
+ int irq;
+ unsigned int io_addr;
+ unsigned int io_size;
+
+ struct list_head uhci_list;
+
+ struct usb_bus *bus;
+
+ struct uhci_td skeltd[UHCI_NUM_SKELTD]; /* Skeleton TD's */
+ struct uhci_qh skelqh[UHCI_NUM_SKELQH]; /* Skeleton QH's */
+
+ struct uhci_framelist *fl; /* Frame list */
+
+ struct s_nested_lock irqlist_lock;
+ struct list_head interrupt_list; /* List of interrupt-active TD's for this uhci */
+
+ spinlock_t urblist_lock;
+ struct list_head urb_list;
+
+ spinlock_t framelist_lock;
+
+ spinlock_t freelist_lock;
+ struct list_head td_free_list;
+ struct list_head qh_free_list;
+
+ struct virt_root_hub rh; /* private data of the virtual root hub */
+};
+
+struct urb_priv {
+ struct uhci_qh *qh; /* QH for this URB */
+ struct uhci_td *begin;
+ struct uhci_td *end;
+};
+
+/* -------------------------------------------------------------------------
+ Virtual Root HUB
+ ------------------------------------------------------------------------- */
+/* destination of request */
+#define RH_INTERFACE 0x01
+#define RH_ENDPOINT 0x02
+#define RH_OTHER 0x03
+
+#define RH_CLASS 0x20
+#define RH_VENDOR 0x40
+
+/* Requests: bRequest << 8 | bmRequestType */
+#define RH_GET_STATUS 0x0080
+#define RH_CLEAR_FEATURE 0x0100
+#define RH_SET_FEATURE 0x0300
+#define RH_SET_ADDRESS 0x0500
+#define RH_GET_DESCRIPTOR 0x0680
+#define RH_SET_DESCRIPTOR 0x0700
+#define RH_GET_CONFIGURATION 0x0880
+#define RH_SET_CONFIGURATION 0x0900
+#define RH_GET_STATE 0x0280
+#define RH_GET_INTERFACE 0x0A80
+#define RH_SET_INTERFACE 0x0B00
+#define RH_SYNC_FRAME 0x0C80
+/* Our Vendor Specific Request */
+#define RH_SET_EP 0x2000
+
+/* Hub port features */
+#define RH_PORT_CONNECTION 0x00
+#define RH_PORT_ENABLE 0x01
+#define RH_PORT_SUSPEND 0x02
+#define RH_PORT_OVER_CURRENT 0x03
+#define RH_PORT_RESET 0x04
+#define RH_PORT_POWER 0x08
+#define RH_PORT_LOW_SPEED 0x09
+#define RH_C_PORT_CONNECTION 0x10
+#define RH_C_PORT_ENABLE 0x11
+#define RH_C_PORT_SUSPEND 0x12
+#define RH_C_PORT_OVER_CURRENT 0x13
+#define RH_C_PORT_RESET 0x14
+
+/* Hub features */
+#define RH_C_HUB_LOCAL_POWER 0x00
+#define RH_C_HUB_OVER_CURRENT 0x01
+#define RH_DEVICE_REMOTE_WAKEUP 0x00
+#define RH_ENDPOINT_STALL 0x01
+
+/* Our Vendor Specific feature */
+#define RH_REMOVE_EP 0x00
+
+#define RH_ACK 0x01
+#define RH_REQ_ERR -1
+#define RH_NACK 0x00
+
+/* needed for the debugging code */
+struct uhci_td *uhci_link_to_td(unsigned int element);
+
+/* Debugging code */
+void uhci_show_td(struct uhci_td *td);
+void uhci_show_status(struct uhci *uhci);
+void uhci_show_queue(struct uhci_qh *qh);
+void uhci_show_queues(struct uhci *uhci);
+
+#endif
+
diff --git a/drivers/usb/usb-core.c b/drivers/usb/usb-core.c
index 68927a086..9e7557e8f 100644
--- a/drivers/usb/usb-core.c
+++ b/drivers/usb/usb-core.c
@@ -132,6 +132,9 @@ int usb_init(void)
#ifdef CONFIG_USB_UHCI
uhci_init();
#endif
+#ifdef CONFIG_USB_UHCI_ALT
+ uhci_init();
+#endif
#ifdef CONFIG_USB_OHCI
ohci_hcd_init();
#endif
diff --git a/drivers/usb/usb-serial.c b/drivers/usb/usb-serial.c
index 9f37fcc9e..f30057d9c 100644
--- a/drivers/usb/usb-serial.c
+++ b/drivers/usb/usb-serial.c
@@ -996,7 +996,7 @@ static int whiteheat_writememory (struct usb_serial *serial, int address, unsign
// dbg("whiteheat_writememory %x, %d", address, length);
if (!transfer_buffer) {
- err("whiteheat_writememory: kmalloc(%d) failed.\n", length);
+ err("whiteheat_writememory: kmalloc(%d) failed.", length);
return -ENOMEM;
}
memcpy (transfer_buffer, data, length);
@@ -1078,7 +1078,7 @@ static int whiteheat_startup (struct usb_serial *serial)
response = whiteheat_writememory (serial, record->address,
(unsigned char *)record->data, record->data_size, 0xa0);
if (response < 0) {
- err("whiteheat_writememory failed for second firmware step (%d %04X %p %d)\n",
+ err("whiteheat_writememory failed for second firmware step (%d %04X %p %d)",
response, record->address, record->data, record->data_size);
break;
}
@@ -1127,7 +1127,7 @@ static void visor_serial_close(struct tty_struct *tty, struct file * filp)
dbg("visor_serial_close port %d", port);
if (!transfer_buffer) {
- err("visor_serial_close: kmalloc(%d) failed.\n", 0x12);
+ err("visor_serial_close: kmalloc(%d) failed.", 0x12);
} else {
/* send a shutdown message to the device */
usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), VISOR_CLOSE_NOTIFICATION,
@@ -1175,7 +1175,7 @@ static int visor_startup (struct usb_serial *serial)
unsigned char *transfer_buffer = kmalloc (256, GFP_KERNEL);
if (!transfer_buffer) {
- err("visor_startup: kmalloc(%d) failed.\n", 256);
+ err("visor_startup: kmalloc(%d) failed.", 256);
return -ENOMEM;
}
diff --git a/drivers/usb/usb-uhci-debug.h b/drivers/usb/usb-uhci-debug.h
new file mode 100644
index 000000000..73d16937a
--- /dev/null
+++ b/drivers/usb/usb-uhci-debug.h
@@ -0,0 +1,195 @@
+#ifdef DEBUG
+
+static void uhci_show_qh (puhci_desc_t qh)
+{
+ if (qh->type != QH_TYPE) {
+ dbg("qh has not QH_TYPE");
+ return;
+ }
+ dbg("uhci_show_qh %p (%08lX):", qh, virt_to_bus (qh));
+
+ if (qh->hw.qh.head & UHCI_PTR_TERM)
+ dbg("Head Terminate");
+ else {
+ if (qh->hw.qh.head & UHCI_PTR_QH)
+ dbg("Head points to QH");
+ else
+ dbg("Head points to TD");
+
+ dbg("head: %08X", qh->hw.qh.head & ~UHCI_PTR_BITS);
+ }
+ if (qh->hw.qh.element & UHCI_PTR_TERM)
+ dbg("Element Terminate");
+ else {
+
+ if (qh->hw.qh.element & UHCI_PTR_QH)
+ dbg("Element points to QH");
+ else
+ dbg("Element points to TD");
+ dbg("element: %08X", qh->hw.qh.element & ~UHCI_PTR_BITS);
+ }
+}
+#endif
+
+static void uhci_show_td (puhci_desc_t td)
+{
+ char *spid;
+ warn("uhci_show_td %p (%08lX) ", td, virt_to_bus (td));
+
+ switch (td->hw.td.info & 0xff) {
+ case USB_PID_SETUP:
+ spid = "SETUP";
+ break;
+ case USB_PID_OUT:
+ spid = " OUT ";
+ break;
+ case USB_PID_IN:
+ spid = " IN ";
+ break;
+ default:
+ spid = " ? ";
+ break;
+ }
+
+ warn("MaxLen=%02x DT%d EndPt=%x Dev=%x, PID=%x(%s) (buf=%08x)",
+ td->hw.td.info >> 21,
+ ((td->hw.td.info >> 19) & 1),
+ (td->hw.td.info >> 15) & 15,
+ (td->hw.td.info >> 8) & 127,
+ (td->hw.td.info & 0xff),
+ spid,
+ td->hw.td.buffer);
+
+ warn("Len=%02x e%d %s%s%s%s%s%s%s%s%s%s",
+ td->hw.td.status & 0x7ff,
+ ((td->hw.td.status >> 27) & 3),
+ (td->hw.td.status & TD_CTRL_SPD) ? "SPD " : "",
+ (td->hw.td.status & TD_CTRL_LS) ? "LS " : "",
+ (td->hw.td.status & TD_CTRL_IOC) ? "IOC " : "",
+ (td->hw.td.status & TD_CTRL_ACTIVE) ? "Active " : "",
+ (td->hw.td.status & TD_CTRL_STALLED) ? "Stalled " : "",
+ (td->hw.td.status & TD_CTRL_DBUFERR) ? "DataBufErr " : "",
+ (td->hw.td.status & TD_CTRL_BABBLE) ? "Babble " : "",
+ (td->hw.td.status & TD_CTRL_NAK) ? "NAK " : "",
+ (td->hw.td.status & TD_CTRL_CRCTIMEO) ? "CRC/Timeo " : "",
+ (td->hw.td.status & TD_CTRL_BITSTUFF) ? "BitStuff " : ""
+ );
+#if 1
+ if (td->hw.td.link & UHCI_PTR_TERM)
+ warn("Link Terminate");
+ else {
+ if (td->hw.td.link & UHCI_PTR_QH)
+ warn("%s, link points to QH @ %08x",
+ (td->hw.td.link & UHCI_PTR_DEPTH ? "Depth first" : " Breadth first"),
+ td->hw.td.link & ~UHCI_PTR_BITS);
+ else
+ warn("%s, link points to TD @ %08x",
+ (td->hw.td.link & UHCI_PTR_DEPTH ? "Depth first" : " Breadth first"),
+ td->hw.td.link & ~UHCI_PTR_BITS);
+ }
+#endif
+}
+#ifdef DEBUG
+static void uhci_show_td_queue (puhci_desc_t td)
+{
+ dbg("uhci_show_td_queue %p (%08lX):", td, virt_to_bus (td));
+ while (1) {
+ uhci_show_td (td);
+ if (td->hw.td.link & UHCI_PTR_TERM)
+ break;
+ //if(!(td->hw.td.link&UHCI_PTR_DEPTH))
+ // break;
+ if (td != bus_to_virt (td->hw.td.link & ~UHCI_PTR_BITS))
+ td = bus_to_virt (td->hw.td.link & ~UHCI_PTR_BITS);
+ else {
+ dbg("td points to itself!");
+ break;
+ }
+// schedule();
+ }
+}
+
+static void uhci_show_queue (puhci_desc_t qh)
+{
+ dbg("uhci_show_queue %p:", qh);
+ while (1) {
+ uhci_show_qh (qh);
+
+ if (qh->hw.qh.element & UHCI_PTR_QH)
+ dbg("Warning: qh->element points to qh!");
+ else if (!(qh->hw.qh.element & UHCI_PTR_TERM))
+ uhci_show_td_queue (bus_to_virt (qh->hw.qh.element & ~UHCI_PTR_BITS));
+
+ if (qh->hw.qh.head & UHCI_PTR_TERM)
+ break;
+
+ if (qh != bus_to_virt (qh->hw.qh.head & ~UHCI_PTR_BITS))
+ qh = bus_to_virt (qh->hw.qh.head & ~UHCI_PTR_BITS);
+ else {
+ dbg("qh points to itself!");
+ break;
+ }
+ }
+}
+
+static void uhci_show_sc (int port, unsigned short status)
+{
+ dbg(" stat%d = %04x %s%s%s%s%s%s%s%s",
+ port,
+ status,
+ (status & USBPORTSC_SUSP) ? "PortSuspend " : "",
+ (status & USBPORTSC_PR) ? "PortReset " : "",
+ (status & USBPORTSC_LSDA) ? "LowSpeed " : "",
+ (status & USBPORTSC_RD) ? "ResumeDetect " : "",
+ (status & USBPORTSC_PEC) ? "EnableChange " : "",
+ (status & USBPORTSC_PE) ? "PortEnabled " : "",
+ (status & USBPORTSC_CSC) ? "ConnectChange " : "",
+ (status & USBPORTSC_CCS) ? "PortConnected " : "");
+}
+
+void uhci_show_status (puhci_t s)
+{
+ unsigned int io_addr = s->io_addr;
+ unsigned short usbcmd, usbstat, usbint, usbfrnum;
+ unsigned int flbaseadd;
+ unsigned char sof;
+ unsigned short portsc1, portsc2;
+
+ usbcmd = inw (io_addr + 0);
+ usbstat = inw (io_addr + 2);
+ usbint = inw (io_addr + 4);
+ usbfrnum = inw (io_addr + 6);
+ flbaseadd = inl (io_addr + 8);
+ sof = inb (io_addr + 12);
+ portsc1 = inw (io_addr + 16);
+ portsc2 = inw (io_addr + 18);
+
+ dbg(" usbcmd = %04x %s%s%s%s%s%s%s%s",
+ usbcmd,
+ (usbcmd & USBCMD_MAXP) ? "Maxp64 " : "Maxp32 ",
+ (usbcmd & USBCMD_CF) ? "CF " : "",
+ (usbcmd & USBCMD_SWDBG) ? "SWDBG " : "",
+ (usbcmd & USBCMD_FGR) ? "FGR " : "",
+ (usbcmd & USBCMD_EGSM) ? "EGSM " : "",
+ (usbcmd & USBCMD_GRESET) ? "GRESET " : "",
+ (usbcmd & USBCMD_HCRESET) ? "HCRESET " : "",
+ (usbcmd & USBCMD_RS) ? "RS " : "");
+
+ dbg(" usbstat = %04x %s%s%s%s%s%s",
+ usbstat,
+ (usbstat & USBSTS_HCH) ? "HCHalted " : "",
+ (usbstat & USBSTS_HCPE) ? "HostControllerProcessError " : "",
+ (usbstat & USBSTS_HSE) ? "HostSystemError " : "",
+ (usbstat & USBSTS_RD) ? "ResumeDetect " : "",
+ (usbstat & USBSTS_ERROR) ? "USBError " : "",
+ (usbstat & USBSTS_USBINT) ? "USBINT " : "");
+
+ dbg(" usbint = %04x", usbint);
+ dbg(" usbfrnum = (%d)%03x", (usbfrnum >> 10) & 1,
+ 0xfff & (4 * (unsigned int) usbfrnum));
+ dbg(" flbaseadd = %08x", flbaseadd);
+ dbg(" sof = %02x", sof);
+ uhci_show_sc (1, portsc1);
+ uhci_show_sc (2, portsc2);
+}
+#endif
diff --git a/drivers/usb/usb-uhci.c b/drivers/usb/usb-uhci.c
index 3fe469699..a85dfab5a 100644
--- a/drivers/usb/usb-uhci.c
+++ b/drivers/usb/usb-uhci.c
@@ -43,7 +43,7 @@
#include "usb.h"
#include "usb-uhci.h"
-#include "uhci-debug.h"
+#include "usb-uhci-debug.h"
#ifdef CONFIG_APM
#include <linux/apm_bios.h>
diff --git a/drivers/usb/usb.c b/drivers/usb/usb.c
index 213f69036..32d6e519e 100644
--- a/drivers/usb/usb.c
+++ b/drivers/usb/usb.c
@@ -1595,17 +1595,34 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
tbuf = kmalloc(256, GFP_KERNEL);
if (!tbuf)
return -ENOMEM;
+
+ /* get langid for strings if it's not yet known */
+ if (!dev->have_langid) {
+ err = usb_get_string(dev, 0, 0, tbuf, 4);
+ if (err < 0) {
+ err("error getting string descriptor 0 (error=%d)", err);
+ goto errout;
+ } else if (tbuf[0] < 4) {
+ err("string descriptor 0 too short");
+ err = -EINVAL;
+ goto errout;
+ } else {
+ dev->have_langid = -1;
+ dev->string_langid = tbuf[2] | (tbuf[3]<< 8);
+ /* always use the first langid listed */
+ info("USB device number %d default language ID 0x%x",
+ dev->devnum, dev->string_langid);
+ }
+ }
+
/*
- * is this two step process necessary? can't we just
- * ask for a maximum length string and then take the length
- * that was returned?
+ * Just ask for a maximum length string and then take the length
+ * that was returned.
*/
- err = usb_get_string(dev, dev->string_langid, index, tbuf, 4);
- if (err < 0)
- goto errout;
- err = usb_get_string(dev, dev->string_langid, index, tbuf, tbuf[0]);
+ err = usb_get_string(dev, dev->string_langid, index, tbuf, 255);
if (err < 0)
goto errout;
+ info("actual string desc. length = %d", err);
size--; /* leave room for trailing NULL char in output buffer */
for (idx = 0, u = 2; u < err; u += 2) {
@@ -1633,7 +1650,6 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
*/
int usb_new_device(struct usb_device *dev)
{
- unsigned char *buf;
int addr, err;
int tmp;
@@ -1709,21 +1725,6 @@ int usb_new_device(struct usb_device *dev)
err("failed to set default configuration");
return -1;
}
- /* get langid for strings */
- buf = kmalloc(256, GFP_KERNEL);
- if (!buf) {
- err("out of memory\n");
- } else {
- err = usb_get_string(dev, 0, 0, buf, 4);
- if (err < 0) {
- err("error getting string descriptor 0 (error=%d)\n", err);
- } else if (buf[0] < 4) {
- err("string descriptpr 0 too short\n");
- } else
- dev->string_langid = buf[2] | (buf[3]<< 8);
- kfree(buf);
- info("USB device number %d default language ID 0x%x", dev->devnum, dev->string_langid);
- }
if (dev->descriptor.iManufacturer)
usb_show_string(dev, "Manufacturer", dev->descriptor.iManufacturer);
diff --git a/drivers/usb/usb.h b/drivers/usb/usb.h
index ec2754b1f..a7b027bf2 100644
--- a/drivers/usb/usb.h
+++ b/drivers/usb/usb.h
@@ -509,6 +509,7 @@ struct usb_device {
struct usb_device_descriptor descriptor;/* Descriptor */
struct usb_config_descriptor *config; /* All of the configs */
+ int have_langid; /* whether string_langid is valid yet */
int string_langid; /* language ID for strings */
void *hcpriv; /* Host Controller private data */
diff --git a/drivers/video/dn_accel.h b/drivers/video/dn_accel.h
new file mode 100644
index 000000000..b39be932d
--- /dev/null
+++ b/drivers/video/dn_accel.h
@@ -0,0 +1,9 @@
+#ifndef _DN_ACCEL_H_
+#define _DN_ACCEL_H_
+
+#include <linux/fb.h>
+
+void dn_bitblt(struct display *p,int x_src,int y_src, int x_dest, int y_dest,
+ int x_count, int y_count);
+
+#endif
diff --git a/drivers/video/dn_cfb4.c b/drivers/video/dn_cfb4.c
new file mode 100644
index 000000000..453eb52d6
--- /dev/null
+++ b/drivers/video/dn_cfb4.c
@@ -0,0 +1,546 @@
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/malloc.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <asm/setup.h>
+#include <asm/segment.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/amigahw.h>
+#include <asm/amigaints.h>
+#include <asm/apollohw.h>
+#include <linux/fb.h>
+#include <linux/module.h>
+#include <video/fbcon.h>
+#include <video/fbcon-mfb.h>
+#include "dn_accel.h"
+
+/* apollo video HW definitions */
+
+/*
+ * Control Registers. IOBASE + $x
+ *
+ * Note: these are the Memory/IO BASE definitions for a mono card set to the
+ * alternate address
+ *
+ * Control 3A and 3B serve identical functions except that 3A
+ * deals with control 1 and 3b deals with Color LUT reg.
+ */
+
+#define AP_IOBASE 0x3d0 /* Base address of 1 plane board. */
+#define AP_STATUS isaIO2mem(AP_IOBASE+0) /* Status register. Read */
+#define AP_WRITE_ENABLE isaIO2mem(AP_IOBASE+0) /* Write Enable Register Write */
+#define AP_DEVICE_ID isaIO2mem(AP_IOBASE+1) /* Device ID Register. Read */
+#define AP_ROP_1 isaIO2mem(AP_IOBASE+2) /* Raster Operation reg. Write Word */
+#define AP_DIAG_MEM_REQ isaIO2mem(AP_IOBASE+4) /* Diagnostic Memory Request. Write Word */
+#define AP_CONTROL_0 isaIO2mem(AP_IOBASE+8) /* Control Register 0. Read/Write */
+#define AP_CONTROL_1 isaIO2mem(AP_IOBASE+0xa) /* Control Register 1. Read/Write */
+#define AP_CONTROL_2 isaIO2mem(AP_IOBASE+0xc) /* Control Register 2. Read/Write */
+#define AP_CONTROL_3A isaIO2mem(AP_IOBASE+0xe) /* Control Register 3a. Read/Write */
+#define AP_LUT_RED isaIO2mem(AP_IOBASE+9) /* Red Lookup Table register. Write */
+#define AP_LUT_GREEN isaIO2mem(AP_IOBASE+0xb) /* Green Lookup Table register. Write */
+#define AP_LUT_BLUE isaIO2mem(AP_IOBASE+0xd) /* Blue Lookup Table register. Write */
+#define AP_AD_CHANNEL isaIO2mem(AP_IOBASE+0xf) /* A/D Result/Channel register. Read/Write */
+
+
+#define FRAME_BUFFER_START 0x0A0000
+#define FRAME_BUFFER_LEN 0x20000
+
+/* CREG 0 */
+#define VECTOR_MODE 0x40 /* 010x.xxxx */
+#define DBLT_MODE 0x80 /* 100x.xxxx */
+#define NORMAL_MODE 0xE0 /* 111x.xxxx */
+#define SHIFT_BITS 0x1F /* xxx1.1111 */
+ /* other bits are Shift value */
+
+/* CREG 1 */
+#define AD_BLT 0x80 /* 1xxx.xxxx */
+
+#define ROP_EN 0x10 /* xxx1.xxxx */
+#define DST_EQ_SRC 0x00 /* xxx0.xxxx */
+#define nRESET_SYNC 0x08 /* xxxx.1xxx */
+#define SYNC_ENAB 0x02 /* xxxx.xx1x */
+
+#define BLANK_DISP 0x00 /* xxxx.xxx0 */
+#define ENAB_DISP 0x01 /* xxxx.xxx1 */
+
+#define NORM_CREG1 (nRESET_SYNC | SYNC_ENAB | ENAB_DISP) /* no reset sync */
+
+/* CREG 2B */
+
+/*
+ * Following 3 defines are common to 1, 4 and 8 plane.
+ */
+
+#define S_DATA_1s 0x00 /* 00xx.xxxx */ /* set source to all 1's -- vector drawing */
+#define S_DATA_PIX 0x40 /* 01xx.xxxx */ /* takes source from ls-bits and replicates over 16 bits */
+#define S_DATA_PLN 0xC0 /* 11xx.xxxx */ /* normal, each data access =16-bits in
+ one plane of image mem */
+
+/* CREG 3A/CREG 3B */
+# define RESET_CREG 0x80 /* 1000.0000 */
+
+/* ROP REG - all one nibble */
+/* ********* NOTE : this is used r0,r1,r2,r3 *********** */
+#define ROP(r2,r3,r0,r1) ( (U_SHORT)((r0)|((r1)<<4)|((r2)<<8)|((r3)<<12)) )
+#define DEST_ZERO 0x0
+#define SRC_AND_DEST 0x1
+#define SRC_AND_nDEST 0x2
+#define SRC 0x3
+#define nSRC_AND_DEST 0x4
+#define DEST 0x5
+#define SRC_XOR_DEST 0x6
+#define SRC_OR_DEST 0x7
+#define SRC_NOR_DEST 0x8
+#define SRC_XNOR_DEST 0x9
+#define nDEST 0xA
+#define SRC_OR_nDEST 0xB
+#define nSRC 0xC
+#define nSRC_OR_DEST 0xD
+#define SRC_NAND_DEST 0xE
+#define DEST_ONE 0xF
+
+#define SWAP(A) ((A>>8) | ((A&0xff) <<8))
+
+
+void dn_video_setup(char *options, int *ints);
+
+/* frame buffer operations */
+
+static int dn_fb_open(struct fb_info *info,int user);
+static int dn_fb_release(struct fb_info *info,int user);
+static int dn_fb_get_fix(struct fb_fix_screeninfo *fix, int con,
+ struct fb_info *info);
+static int dn_fb_get_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info);
+static int dn_fb_set_var(struct fb_var_screeninfo *var, int isactive,
+ struct fb_info *info);
+static int dn_fb_get_cmap(struct fb_cmap *cmap,int kspc,int con,
+ struct fb_info *info);
+static int dn_fb_set_cmap(struct fb_cmap *cmap,int kspc,int con,
+ struct fb_info *info);
+static int dn_fb_pan_display(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info);
+static int dn_fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+ unsigned long arg, int con, struct fb_info *info);
+
+static int dnfbcon_switch(int con,struct fb_info *info);
+static int dnfbcon_updatevar(int con,struct fb_info *info);
+static void dnfbcon_blank(int blank,struct fb_info *info);
+
+static void dn_fb_set_disp(int con,struct fb_info *info);
+
+static struct display disp[MAX_NR_CONSOLES];
+static struct fb_info fb_info;
+static struct fb_ops dn_fb_ops = {
+ dn_fb_open,dn_fb_release, dn_fb_get_fix, dn_fb_get_var, dn_fb_set_var,
+ dn_fb_get_cmap, dn_fb_set_cmap, dn_fb_pan_display, dn_fb_ioctl
+};
+
+static int currcon=0;
+
+#define NUM_TOTAL_MODES 1
+struct fb_var_screeninfo dn_fb_predefined[] = {
+
+ { 0, },
+
+};
+
+static char dn_fb_name[]="Apollo ";
+
+/* accel stuff */
+#define USE_DN_ACCEL
+
+static struct display_switch dispsw_apollofb;
+
+static int dn_fb_open(struct fb_info *info,int user)
+{
+ /*
+ * Nothing, only a usage count for the moment
+ */
+
+ MOD_INC_USE_COUNT;
+ return(0);
+}
+
+static int dn_fb_release(struct fb_info *info,int user)
+{
+ MOD_DEC_USE_COUNT;
+ return(0);
+}
+
+static int dn_fb_get_fix(struct fb_fix_screeninfo *fix, int con,
+ struct fb_info *info) {
+
+ strcpy(fix->id,"Apollo Color4");
+ fix->smem_start=(FRAME_BUFFER_START+IO_BASE);
+ fix->smem_len=FRAME_BUFFER_LEN;
+ fix->type=FB_TYPE_PACKED_PIXELS;
+ fix->type_aux=0;
+ fix->visual=FB_VISUAL_MONO10;
+ fix->xpanstep=0;
+ fix->ypanstep=0;
+ fix->ywrapstep=0;
+ fix->line_length=128;
+
+ return 0;
+
+}
+
+static int dn_fb_get_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info) {
+
+ var->xres=1024;
+ var->yres=800;
+ var->xres_virtual=1024;
+ var->yres_virtual=1024;
+ var->xoffset=0;
+ var->yoffset=0;
+ var->bits_per_pixel=1;
+ var->grayscale=0;
+ var->nonstd=0;
+ var->activate=0;
+ var->height=-1;
+ var->width=-1;
+ var->pixclock=0;
+ var->left_margin=0;
+ var->right_margin=0;
+ var->hsync_len=0;
+ var->vsync_len=0;
+ var->sync=0;
+ var->vmode=FB_VMODE_NONINTERLACED;
+
+ return 0;
+
+}
+
+static int dn_fb_set_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info) {
+
+ printk("fb_set_var\n");
+ if(var->xres!=1024)
+ return -EINVAL;
+ if(var->yres!=800)
+ return -EINVAL;
+ if(var->xres_virtual!=1024)
+ return -EINVAL;
+ if(var->yres_virtual!=1024)
+ return -EINVAL;
+ if(var->xoffset!=0)
+ return -EINVAL;
+ if(var->yoffset!=0)
+ return -EINVAL;
+ if(var->bits_per_pixel!=1)
+ return -EINVAL;
+ if(var->grayscale!=0)
+ return -EINVAL;
+ if(var->nonstd!=0)
+ return -EINVAL;
+ if(var->activate!=0)
+ return -EINVAL;
+ if(var->pixclock!=0)
+ return -EINVAL;
+ if(var->left_margin!=0)
+ return -EINVAL;
+ if(var->right_margin!=0)
+ return -EINVAL;
+ if(var->hsync_len!=0)
+ return -EINVAL;
+ if(var->vsync_len!=0)
+ return -EINVAL;
+ if(var->sync!=0)
+ return -EINVAL;
+ if(var->vmode!=FB_VMODE_NONINTERLACED)
+ return -EINVAL;
+
+ return 0;
+
+}
+
+static int dn_fb_get_cmap(struct fb_cmap *cmap,int kspc,int con,
+ struct fb_info *info) {
+
+ printk("get cmap not supported\n");
+
+ return -EINVAL;
+}
+
+static int dn_fb_set_cmap(struct fb_cmap *cmap,int kspc,int con,
+ struct fb_info *info) {
+
+ printk("set cmap not supported\n");
+
+ return -EINVAL;
+
+}
+
+static int dn_fb_pan_display(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info) {
+
+ printk("panning not supported\n");
+
+ return -EINVAL;
+
+}
+
+static int dn_fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+ unsigned long arg, int con, struct fb_info *info) {
+
+ printk("no IOCTLs as of yet.\n");
+
+ return -EINVAL;
+
+}
+
+static void dn_fb_set_disp(int con, struct fb_info *info) {
+
+ struct fb_fix_screeninfo fix;
+ struct display *display;
+
+
+ dn_fb_get_fix(&fix,con, info);
+
+ if (con>=0)
+ display=&fb_display[con];
+ else
+ display=&disp[0];
+
+ if(con==-1)
+ con=0;
+
+ display->screen_base = (u_char *)fix.smem_start;
+printk("screenbase: %lx\n",fix.smem_start);
+ display->visual = fix.visual;
+ display->type = fix.type;
+ display->type_aux = fix.type_aux;
+ display->ypanstep = fix.ypanstep;
+ display->ywrapstep = fix.ywrapstep;
+ display->can_soft_blank = 1;
+ display->inverse = 0;
+ display->line_length = fix.line_length;
+ display->scrollmode = SCROLL_YREDRAW;
+#ifdef FBCON_HAS_MFB
+ display->dispsw = &fbcon_mfb;
+#else
+ display->dispsw=&fbcon_dummy;
+#endif
+
+}
+
+unsigned long dnfb_init(unsigned long mem_start) {
+
+ int err;
+
+printk("dn_fb_init\n");
+
+ fb_info.changevar=NULL;
+ strcpy(&fb_info.modename[0],dn_fb_name);
+ fb_info.fontname[0]=0;
+ fb_info.disp=disp;
+ fb_info.switch_con=&dnfbcon_switch;
+ fb_info.updatevar=&dnfbcon_updatevar;
+ fb_info.blank=&dnfbcon_blank;
+ fb_info.node = -1;
+ fb_info.fbops = &dn_fb_ops;
+ fb_info.flags = FBINFO_FLAG_DEFAULT;
+
+ dn_fb_get_var(&disp[0].var,0, &fb_info);
+ dn_fb_set_disp(-1, &fb_info);
+
+printk("dn_fb_init: register\n");
+ err=register_framebuffer(&fb_info);
+ if(err < 0) {
+ panic("unable to register apollo frame buffer\n");
+ }
+
+ /* now we have registered we can safely setup the hardware */
+
+ outb(RESET_CREG, AP_CONTROL_3A);
+ outb(NORMAL_MODE, AP_CONTROL_0);
+ outb((AD_BLT | DST_EQ_SRC | NORM_CREG1), AP_CONTROL_1);
+ outb(S_DATA_PLN, AP_CONTROL_2);
+ outw(SWAP(0x3), AP_ROP_1);
+
+ printk("apollo frame buffer alive and kicking !\n");
+
+
+ return mem_start;
+
+}
+
+
+static int dnfbcon_switch(int con, struct fb_info *info) {
+
+ currcon=con;
+
+ return 0;
+
+}
+
+static int dnfbcon_updatevar(int con, struct fb_info *info) {
+
+ return 0;
+
+}
+
+static void dnfbcon_blank(int blank, struct fb_info *info) {
+
+ if(blank) {
+ outb(0x0, AP_CONTROL_3A);
+ }
+ else {
+ outb(0x1, AP_CONTROL_3A);
+ }
+
+ return ;
+
+}
+
+void dn_video_setup(char *options, int *ints) {
+
+ return;
+
+}
+
+void dn_bitblt(struct display *p,int x_src,int y_src, int x_dest, int y_dest,
+ int x_count, int y_count) {
+
+ int incr,y_delta,pre_read=0,x_end,x_word_count;
+ ushort *src,dummy;
+ uint start_mask,end_mask,dest;
+ short i,j;
+
+ incr=(y_dest<=y_src) ? 1 : -1 ;
+
+ src=(ushort *)(p->screen_base+ y_src*p->next_line+(x_src >> 4));
+ dest=y_dest*(p->next_line >> 1)+(x_dest >> 4);
+
+ if(incr>0) {
+ y_delta=(p->next_line*8)-x_src-x_count;
+ x_end=x_dest+x_count-1;
+ x_word_count=(x_end>>4) - (x_dest >> 4) + 1;
+ start_mask=0xffff0000 >> (x_dest & 0xf);
+ end_mask=0x7ffff >> (x_end & 0xf);
+ outb((((x_dest & 0xf) - (x_src &0xf)) % 16)|(0x4 << 5),AP_CONTROL_0);
+ if((x_dest & 0xf) < (x_src & 0xf))
+ pre_read=1;
+ }
+ else {
+ y_delta=-((p->next_line*8)-x_src-x_count);
+ x_end=x_dest-x_count+1;
+ x_word_count=(x_dest>>4) - (x_end >> 4) + 1;
+ start_mask=0x7ffff >> (x_dest & 0xf);
+ end_mask=0xffff0000 >> (x_end & 0xf);
+ outb(((-((x_src & 0xf) - (x_dest &0xf))) % 16)|(0x4 << 5),AP_CONTROL_0);
+ if((x_dest & 0xf) > (x_src & 0xf))
+ pre_read=1;
+ }
+
+ for(i=0;i<y_count;i++) {
+
+ if(pre_read) {
+ dummy=*src;
+ src+=incr;
+ }
+
+ if(x_word_count) {
+ outb(start_mask,AP_WRITE_ENABLE);
+ *src=dest;
+ src+=incr;
+ dest+=incr;
+ outb(0,AP_WRITE_ENABLE);
+
+ for(j=1;j<(x_word_count-1);j++) {
+ *src=dest;
+ src+=incr;
+ dest+=incr;
+ }
+
+ outb(start_mask,AP_WRITE_ENABLE);
+ *src=dest;
+ dest+=incr;
+ src+=incr;
+ }
+ else {
+ outb(start_mask | end_mask, AP_WRITE_ENABLE);
+ *src=dest;
+ dest+=incr;
+ src+=incr;
+ }
+ src+=(y_delta/16);
+ dest+=(y_delta/16);
+ }
+ outb(NORMAL_MODE,AP_CONTROL_0);
+}
+
+static void bmove_apollofb(struct display *p, int sy, int sx, int dy, int dx,
+ int height, int width)
+{
+
+ int fontheight,fontwidth;
+
+ fontheight=fontheight(p);
+ fontwidth=fontwidth(p);
+
+#ifdef USE_DN_ACCEL
+ dn_bitblt(p,sx,sy*fontheight,dx,dy*fontheight,width*fontwidth,
+ height*fontheight);
+#else
+ u_char *src, *dest;
+ u_int rows;
+
+ if (sx == 0 && dx == 0 && width == p->next_line) {
+ src = p->screen_base+sy*fontheight*width;
+ dest = p->screen_base+dy*fontheight*width;
+ mymemmove(dest, src, height*fontheight*width);
+ } else if (dy <= sy) {
+ src = p->screen_base+sy*fontheight*p->next_line+sx;
+ dest = p->screen_base+dy*fontheight*p->next_line+dx;
+ for (rows = height*fontheight; rows--;) {
+ mymemmove(dest, src, width);
+ src += p->next_line;
+ dest += p->next_line;
+ }
+ } else {
+ src = p->screen_base+((sy+height)*fontheight-1)*p->next_line+sx;
+ dest = p->screen_base+((dy+height)*fontheight-1)*p->next_line+dx;
+ for (rows = height*fontheight; rows--;) {
+ mymemmove(dest, src, width);
+ src -= p->next_line;
+ dest -= p->next_line;
+ }
+ }
+#endif
+}
+
+static void clear_apollofb(struct vc_data *conp, struct display *p, int sy, int sx,
+ int height, int width)
+{
+ fbcon_mfb_clear(conp,p,sy,sx,height,width);
+}
+
+static void putc_apollofb(struct vc_data *conp, struct display *p, int c, int yy,
+ int xx)
+{
+ fbcon_mfb_putc(conp,p,c,yy,xx);
+}
+
+static void putcs_apollofb(struct vc_data *conp, struct display *p, const unsigned short *s,
+ int count, int yy, int xx)
+{
+ fbcon_mfb_putcs(conp,p,s,count,yy,xx);
+}
+
+static void rev_char_apollofb(struct display *p, int xx, int yy)
+{
+ fbcon_mfb_revc(p,xx,yy);
+}
+
+static struct display_switch dispsw_apollofb = {
+ fbcon_mfb_setup, bmove_apollofb, clear_apollofb,
+ putc_apollofb, putcs_apollofb, rev_char_apollofb
+};
diff --git a/drivers/video/dn_cfb8.c b/drivers/video/dn_cfb8.c
new file mode 100644
index 000000000..fe650f6e3
--- /dev/null
+++ b/drivers/video/dn_cfb8.c
@@ -0,0 +1,594 @@
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/malloc.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <asm/setup.h>
+#include <asm/segment.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/amigahw.h>
+#include <asm/amigaints.h>
+#include <asm/apollohw.h>
+#include <linux/fb.h>
+#include <linux/module.h>
+#include "dn_accel.h"
+#include "fbcon.h"
+#include "fbcon-mfb.h"
+
+/* apollo video HW definitions */
+
+/*
+ * Control Registers. IOBASE + $x
+ *
+ * Note: these are the Memory/IO BASE definitions for a mono card set to the
+ * alternate address
+ *
+ * Control 3A and 3B serve identical functions except that 3A
+ * deals with control 1 and 3b deals with Color LUT reg.
+ */
+
+#define AP_IOBASE 0x3d0 /* Base address of 1 plane board. */
+#define AP_STATUS isaIO2mem(AP_IOBASE+0) /* Status register. Read */
+#define AP_WRITE_ENABLE isaIO2mem(AP_IOBASE+0) /* Write Enable Register Write */
+#define AP_DEVICE_ID isaIO2mem(AP_IOBASE+1) /* Device ID Register. Read */
+#define AP_ROP_0 isaIO2mem(AP_IOBASE+2) /* Raster Operation reg. Write Word */
+#define AP_ROP_1 isaIO2mem(AP_IOBASE+4) /* Raster Operation reg. Write Word */
+#define AP_DIAG_MEM_REQ isaIO2mem(AP_IOBASE+6) /* Diagnostic Memory Request. Write Word */
+#define AP_CONTROL_0 isaIO2mem(AP_IOBASE+8) /* Control Register 0. Read/Write */
+#define AP_LUT_DATA isaIO2mem(AP_IOBASE+9) /* Control Register 0. Read/Write */
+#define AP_CONTROL_1 isaIO2mem(AP_IOBASE+0xa) /* Control Register 1. Read/Write */
+#define AP_LUT_CONTROL isaIO2mem(AP_IOBASE+0xb) /* Control Register 1. Read/Write */
+#define AP_CONTROL_2A isaIO2mem(AP_IOBASE+0xc) /* Control Register 2. Read/Write */
+#define AP_CONTROL_2B isaIO2mem(AP_IOBASE+0xd) /* Control Register 2. Read/Write */
+#define AP_CONTROL_3A isaIO2mem(AP_IOBASE+0xe) /* Control Register 3a. Read/Write */
+#define AP_CONTROL_3B isaIO2mem(AP_IOBASE+0xf) /* Control Register 3a. Read/Write */
+
+
+#define FRAME_BUFFER_START 0x0A0000
+#define FRAME_BUFFER_LEN 0x20000
+
+/* CREG 0 */
+#define VECTOR_MODE 0x40 /* 010x.xxxx */
+#define DBLT_MODE 0x80 /* 100x.xxxx */
+#define NORMAL_MODE 0xE0 /* 111x.xxxx */
+#define SHIFT_BITS 0x1F /* xxx1.1111 */
+ /* other bits are Shift value */
+
+/* CREG 1 */
+#define AD_BLT 0x80 /* 1xxx.xxxx */
+
+#define ROP_EN 0x10 /* xxx1.xxxx */
+#define DST_EQ_SRC 0x00 /* xxx0.xxxx */
+#define nRESET_SYNC 0x08 /* xxxx.1xxx */
+#define SYNC_ENAB 0x02 /* xxxx.xx1x */
+
+#define BLANK_DISP 0x00 /* xxxx.xxx0 */
+#define ENAB_DISP 0x01 /* xxxx.xxx1 */
+
+#define NORM_CREG1 (nRESET_SYNC | SYNC_ENAB | ENAB_DISP) /* no reset sync */
+
+/* CREG 2B */
+
+/*
+ * Following 3 defines are common to 1, 4 and 8 plane.
+ */
+
+#define S_DATA_1s 0x00 /* 00xx.xxxx */ /* set source to all 1's -- vector drawing */
+#define S_DATA_PIX 0x40 /* 01xx.xxxx */ /* takes source from ls-bits and replicates over 16 bits */
+#define S_DATA_PLN 0xC0 /* 11xx.xxxx */ /* normal, each data access =16-bits in
+ one plane of image mem */
+
+/* CREG 3A/CREG 3B */
+# define RESET_CREG 0x80 /* 1000.0000 */
+
+/* ROP REG - all one nibble */
+/* ********* NOTE : this is used r0,r1,r2,r3 *********** */
+#define ROP(r2,r3,r0,r1) ( (U_SHORT)((r0)|((r1)<<4)|((r2)<<8)|((r3)<<12)) )
+#define DEST_ZERO 0x0
+#define SRC_AND_DEST 0x1
+#define SRC_AND_nDEST 0x2
+#define SRC 0x3
+#define nSRC_AND_DEST 0x4
+#define DEST 0x5
+#define SRC_XOR_DEST 0x6
+#define SRC_OR_DEST 0x7
+#define SRC_NOR_DEST 0x8
+#define SRC_XNOR_DEST 0x9
+#define nDEST 0xA
+#define SRC_OR_nDEST 0xB
+#define nSRC 0xC
+#define nSRC_OR_DEST 0xD
+#define SRC_NAND_DEST 0xE
+#define DEST_ONE 0xF
+
+#define SWAP(A) ((A>>8) | ((A&0xff) <<8))
+
+
+void dn_video_setup(char *options, int *ints);
+
+/* frame buffer operations */
+
+static int dn_fb_open(struct fb_info *info);
+static int dn_fb_release(struct fb_info *info);
+static int dn_fb_get_fix(struct fb_fix_screeninfo *fix, int con,
+ struct fb_info *info);
+static int dn_fb_get_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info);
+static int dn_fb_set_var(struct fb_var_screeninfo *var, int isactive,
+ struct fb_info *info);
+static int dn_fb_get_cmap(struct fb_cmap *cmap,int kspc,int con,
+ struct fb_info *info);
+static int dn_fb_set_cmap(struct fb_cmap *cmap,int kspc,int con,
+ struct fb_info *info);
+static int dn_fb_pan_display(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info);
+static int dn_fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+ unsigned long arg, int con, struct fb_info *info);
+
+static int dnfbcon_switch(int con,struct fb_info *info);
+static int dnfbcon_updatevar(int con,struct fb_info *info);
+static void dnfbcon_blank(int blank,struct fb_info *info);
+
+static void dn_fb_set_disp(int con,struct fb_info *info);
+
+static struct display disp[MAX_NR_CONSOLES];
+static struct fb_info fb_info;
+static struct fb_ops dn_fb_ops = {
+ dn_fb_open,dn_fb_release, dn_fb_get_fix, dn_fb_get_var, dn_fb_set_var,
+ dn_fb_get_cmap, dn_fb_set_cmap, dn_fb_pan_display, dn_fb_ioctl
+};
+
+static int currcon=0;
+
+#define NUM_TOTAL_MODES 1
+struct fb_var_screeninfo dn_fb_predefined[] = {
+
+ { 0, },
+
+};
+
+static char dn_fb_name[]="Apollo ";
+
+/* accel stuff */
+#define USE_DN_ACCEL
+
+static struct display_switch dispsw_apollofb;
+
+static int dn_fb_open(struct fb_info *info)
+{
+ /*
+ * Nothing, only a usage count for the moment
+ */
+
+ MOD_INC_USE_COUNT;
+ return(0);
+}
+
+static int dn_fb_release(struct fb_info *info)
+{
+ MOD_DEC_USE_COUNT;
+ return(0);
+}
+
+static int dn_fb_get_fix(struct fb_fix_screeninfo *fix, int con,
+ struct fb_info *info) {
+
+ strcpy(fix->id,"Apollo Color8");
+ fix->smem_start=(char*)(FRAME_BUFFER_START+IO_BASE);
+ fix->smem_len=FRAME_BUFFER_LEN;
+ fix->type=FB_TYPE_PACKED_PIXELS;
+ fix->type_aux=0;
+ fix->visual=FB_VISUAL_MONO10;
+ fix->xpanstep=0;
+ fix->ypanstep=0;
+ fix->ywrapstep=0;
+ fix->line_length=128;
+
+ return 0;
+
+}
+
+static int dn_fb_get_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info) {
+
+ var->xres=1024;
+ var->yres=800;
+ var->xres_virtual=1024;
+ var->yres_virtual=1024;
+ var->xoffset=0;
+ var->yoffset=0;
+ var->bits_per_pixel=1;
+ var->grayscale=0;
+ var->nonstd=0;
+ var->activate=0;
+ var->height=-1;
+ var->width=-1;
+ var->pixclock=0;
+ var->left_margin=0;
+ var->right_margin=0;
+ var->hsync_len=0;
+ var->vsync_len=0;
+ var->sync=0;
+ var->vmode=FB_VMODE_NONINTERLACED;
+
+ return 0;
+
+}
+
+static int dn_fb_set_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info) {
+
+ printk("fb_set_var\n");
+ if(var->xres!=1024)
+ return -EINVAL;
+ if(var->yres!=800)
+ return -EINVAL;
+ if(var->xres_virtual!=1024)
+ return -EINVAL;
+ if(var->yres_virtual!=1024)
+ return -EINVAL;
+ if(var->xoffset!=0)
+ return -EINVAL;
+ if(var->yoffset!=0)
+ return -EINVAL;
+ if(var->bits_per_pixel!=1)
+ return -EINVAL;
+ if(var->grayscale!=0)
+ return -EINVAL;
+ if(var->nonstd!=0)
+ return -EINVAL;
+ if(var->activate!=0)
+ return -EINVAL;
+ if(var->pixclock!=0)
+ return -EINVAL;
+ if(var->left_margin!=0)
+ return -EINVAL;
+ if(var->right_margin!=0)
+ return -EINVAL;
+ if(var->hsync_len!=0)
+ return -EINVAL;
+ if(var->vsync_len!=0)
+ return -EINVAL;
+ if(var->sync!=0)
+ return -EINVAL;
+ if(var->vmode!=FB_VMODE_NONINTERLACED)
+ return -EINVAL;
+
+ return 0;
+
+}
+
+static int dn_fb_get_cmap(struct fb_cmap *cmap,int kspc,int con,
+ struct fb_info *info) {
+
+ printk("get cmap not supported\n");
+
+ return -EINVAL;
+}
+
+static int dn_fb_set_cmap(struct fb_cmap *cmap,int kspc,int con,
+ struct fb_info *info) {
+
+ printk("set cmap not supported\n");
+
+ return -EINVAL;
+
+}
+
+static int dn_fb_pan_display(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info) {
+
+ printk("panning not supported\n");
+
+ return -EINVAL;
+
+}
+
+static int dn_fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+ unsigned long arg, int con, struct fb_info *info) {
+
+ printk("no IOCTLs as of yet.\n");
+
+ return -EINVAL;
+
+}
+
+static void dn_fb_set_disp(int con, struct fb_info *info) {
+
+ struct fb_fix_screeninfo fix;
+
+ dn_fb_get_fix(&fix,con, info);
+ if(con==-1)
+ con=0;
+
+ disp[con].screen_base = (u_char *)fix.smem_start;
+printk("screenbase: %p\n",fix.smem_start);
+ disp[con].visual = fix.visual;
+ disp[con].type = fix.type;
+ disp[con].type_aux = fix.type_aux;
+ disp[con].ypanstep = fix.ypanstep;
+ disp[con].ywrapstep = fix.ywrapstep;
+ disp[con].can_soft_blank = 1;
+ disp[con].inverse = 0;
+ disp[con].line_length = fix.line_length;
+ disp[con].dispsw = &dispsw_apollofb;
+}
+
+unsigned long dn_fb_init(unsigned long mem_start) {
+
+ int err;
+
+printk("dn_fb_init\n");
+
+ fb_info.changevar=NULL;
+ strcpy(&fb_info.modename[0],dn_fb_name);
+ fb_info.fontname[0]=0;
+ fb_info.disp=disp;
+ fb_info.switch_con=&dnfbcon_switch;
+ fb_info.updatevar=&dnfbcon_updatevar;
+ fb_info.blank=&dnfbcon_blank;
+ fb_info.node = -1;
+ fb_info.fbops = &dn_fb_ops;
+
+printk("dn_fb_init: register\n");
+ err=register_framebuffer(&fb_info);
+ if(err < 0) {
+ panic("unable to register apollo frame buffer\n");
+ }
+
+ /* now we have registered we can safely setup the hardware */
+
+ outb(RESET_CREG, AP_CONTROL_3A);
+ outb(RESET_CREG, AP_CONTROL_3B);
+ outw(0x0, AP_WRITE_ENABLE);
+ outb(NORMAL_MODE, AP_CONTROL_0);
+ outb((AD_BLT | DST_EQ_SRC | NORM_CREG1), AP_CONTROL_1);
+ outb(0, AP_CONTROL_2A);
+ outb(S_DATA_PLN, AP_CONTROL_2B);
+ outw(SWAP(0x3), AP_ROP_1);
+
+ printk("apollo frame buffer alive and kicking !\n");
+
+ dn_fb_get_var(&disp[0].var,0, &fb_info);
+
+ dn_fb_set_disp(-1, &fb_info);
+
+ return mem_start;
+
+}
+
+
+static int dnfbcon_switch(int con, struct fb_info *info) {
+
+ currcon=con;
+
+ return 0;
+
+}
+
+static int dnfbcon_updatevar(int con, struct fb_info *info) {
+
+ return 0;
+
+}
+
+static void dnfbcon_blank(int blank, struct fb_info *info) {
+
+ if(blank) {
+ outb(0x0, AP_CONTROL_3A);
+ }
+ else {
+ outb(0x1, AP_CONTROL_3A);
+ }
+
+ return ;
+
+}
+
+void dn_video_setup(char *options, int *ints) {
+
+ return;
+
+}
+
+void dn_bitblt(struct display *p,int x_src,int y_src, int x_dest, int y_dest,
+ int x_count, int y_count) {
+
+ int incr,y_delta,pre_read=0,x_end,x_word_count;
+ ushort *src,dummy;
+ uint start_mask,end_mask,dest;
+ short i,j;
+
+ incr=(y_dest<=y_src) ? 1 : -1 ;
+
+ src=(ushort *)(p->screen_base+ y_src*p->next_line+(x_src >> 4));
+ dest=y_dest*(p->next_line >> 1)+(x_dest >> 4);
+
+ if(incr>0) {
+ y_delta=(p->next_line*8)-x_src-x_count;
+ x_end=x_dest+x_count-1;
+ x_word_count=(x_end>>4) - (x_dest >> 4) + 1;
+ start_mask=0xffff0000 >> (x_dest & 0xf);
+ end_mask=0x7ffff >> (x_end & 0xf);
+ outb((((x_dest & 0xf) - (x_src &0xf)) % 16)|(0x4 << 5),AP_CONTROL_0);
+ if((x_dest & 0xf) < (x_src & 0xf))
+ pre_read=1;
+ }
+ else {
+ y_delta=-((p->next_line*8)-x_src-x_count);
+ x_end=x_dest-x_count+1;
+ x_word_count=(x_dest>>4) - (x_end >> 4) + 1;
+ start_mask=0x7ffff >> (x_dest & 0xf);
+ end_mask=0xffff0000 >> (x_end & 0xf);
+ outb(((-((x_src & 0xf) - (x_dest &0xf))) % 16)|(0x4 << 5),AP_CONTROL_0);
+ if((x_dest & 0xf) > (x_src & 0xf))
+ pre_read=1;
+ }
+
+ for(i=0;i<y_count;i++) {
+
+ if(pre_read) {
+ dummy=*src;
+ src+=incr;
+ }
+
+ if(x_word_count) {
+ outb(start_mask,AP_WRITE_ENABLE);
+ *src=dest;
+ src+=incr;
+ dest+=incr;
+ outb(0,AP_WRITE_ENABLE);
+
+ for(j=1;j<(x_word_count-1);j++) {
+ *src=dest;
+ src+=incr;
+ dest+=incr;
+ }
+
+ outb(start_mask,AP_WRITE_ENABLE);
+ *src=dest;
+ dest+=incr;
+ src+=incr;
+ }
+ else {
+ outb(start_mask | end_mask, AP_WRITE_ENABLE);
+ *src=dest;
+ dest+=incr;
+ src+=incr;
+ }
+ src+=(y_delta/16);
+ dest+=(y_delta/16);
+ }
+ outb(NORMAL_MODE,AP_CONTROL_0);
+}
+
+static void bmove_apollofb(struct display *p, int sy, int sx, int dy, int dx,
+ int height, int width)
+{
+
+#ifdef USE_DN_ACCEL
+ dn_bitblt(p,sx,sy*p->fontheight,dx,dy*p->fontheight,width*p->fontwidth,
+ height*p->fontheight);
+#else
+ u_char *src, *dest;
+ u_int rows;
+
+ if (sx == 0 && dx == 0 && width == p->next_line) {
+ src = p->screen_base+sy*p->fontheight*width;
+ dest = p->screen_base+dy*p->fontheight*width;
+ mymemmove(dest, src, height*p->fontheight*width);
+ } else if (dy <= sy) {
+ src = p->screen_base+sy*p->fontheight*p->next_line+sx;
+ dest = p->screen_base+dy*p->fontheight*p->next_line+dx;
+ for (rows = height*p->fontheight; rows--;) {
+ mymemmove(dest, src, width);
+ src += p->next_line;
+ dest += p->next_line;
+ }
+ } else {
+ src = p->screen_base+((sy+height)*p->fontheight-1)*p->next_line+sx;
+ dest = p->screen_base+((dy+height)*p->fontheight-1)*p->next_line+dx;
+ for (rows = height*p->fontheight; rows--;) {
+ mymemmove(dest, src, width);
+ src -= p->next_line;
+ dest -= p->next_line;
+ }
+ }
+#endif
+}
+
+static void clear_apollofb(struct vc_data *conp, struct display *p, int sy, int sx,
+ int height, int width)
+{
+ u_char *dest;
+ u_int rows;
+
+ dest = p->screen_base+sy*p->fontheight*p->next_line+sx;
+
+ if (sx == 0 && width == p->next_line)
+ if (attr_reverse(p,conp))
+ mymemset(dest, height*p->fontheight*width);
+ else
+ mymemclear(dest, height*p->fontheight*width);
+ else
+ for (rows = height*p->fontheight; rows--; dest += p->next_line)
+ if (attr_reverse(p,conp))
+ mymemset(dest, width);
+ else
+ mymemclear_small(dest, width);
+}
+
+static void putc_apollofb(struct vc_data *conp, struct display *p, int c, int yy,
+ int xx)
+{
+ u_char *dest, *cdat;
+ u_int rows, bold, revs, underl;
+ u_char d;
+
+ c &= 0xff;
+
+ dest = p->screen_base+yy*p->fontheight*p->next_line+xx;
+ cdat = p->fontdata+c*p->fontheight;
+ bold = attr_bold(p,conp);
+ revs = attr_reverse(p,conp);
+ underl = attr_underline(p,conp);
+
+ for (rows = p->fontheight; rows--; dest += p->next_line) {
+ d = *cdat++;
+ if (underl && !rows)
+ d = 0xff;
+ else if (bold)
+ d |= d>>1;
+ if (revs)
+ d = ~d;
+ *dest = d;
+ }
+}
+
+static void putcs_apollofb(struct vc_data *conp, struct display *p, const char *s,
+ int count, int yy, int xx)
+{
+ u_char *dest, *dest0, *cdat;
+ u_int rows, bold, revs, underl;
+ u_char c, d;
+
+ dest0 = p->screen_base+yy*p->fontheight*p->next_line+xx;
+ bold = attr_bold(p,conp);
+ revs = attr_reverse(p,conp);
+ underl = attr_underline(p,conp);
+
+ while (count--) {
+ c = *s++;
+ dest = dest0++;
+ cdat = p->fontdata+c*p->fontheight;
+ for (rows = p->fontheight; rows--; dest += p->next_line) {
+ d = *cdat++;
+ if (underl && !rows)
+ d = 0xff;
+ else if (bold)
+ d |= d>>1;
+ if (revs)
+ d = ~d;
+ *dest = d;
+ }
+ }
+}
+
+static void rev_char_apollofb(struct display *p, int xx, int yy)
+{
+ u_char *dest;
+ u_int rows;
+
+ dest = p->screen_base+yy*p->fontheight*p->next_line+xx;
+ for (rows = p->fontheight; rows--; dest += p->next_line)
+ *dest = ~*dest;
+}
+
+static struct display_switch dispsw_apollofb = {
+ fbcon_mfb_setup, bmove_apollofb, clear_apollofb,
+ putc_apollofb, putcs_apollofb, rev_char_apollofb
+};
diff --git a/drivers/video/dnfb.c b/drivers/video/dnfb.c
index 3730695dd..30860ae2b 100644
--- a/drivers/video/dnfb.c
+++ b/drivers/video/dnfb.c
@@ -10,14 +10,15 @@
#include <asm/segment.h>
#include <asm/system.h>
#include <asm/irq.h>
+#include <asm/amigahw.h>
+#include <asm/amigaints.h>
#include <asm/apollohw.h>
#include <linux/fb.h>
#include <linux/module.h>
-
+#include "dn_accel.h"
#include <video/fbcon.h>
#include <video/fbcon-mfb.h>
-
/* apollo video HW definitions */
/*
@@ -30,16 +31,16 @@
* deals with control 1 and 3b deals with Color LUT reg.
*/
-#define AP_IOBASE 0x5d80 /* Base address of 1 plane board. */
-#define AP_STATUS 0x5d80 /* Status register. Read */
-#define AP_WRITE_ENABLE 0x5d80 /* Write Enable Register Write */
-#define AP_DEVICE_ID 0x5d81 /* Device ID Register. Read */
-#define AP_ROP_1 0x5d82 /* Raster Operation reg. Write Word */
-#define AP_DIAG_MEM_REQ 0x5d84 /* Diagnostic Memory Request. Write Word */
-#define AP_CONTROL_0 0x5d88 /* Control Register 0. Read/Write */
-#define AP_CONTROL_1 0x5d8a /* Control Register 1. Read/Write */
-#define AP_CONTROL_3A 0x5d8e /* Control Register 3a. Read/Write */
-#define AP_CONTROL_2 0x5d8c /* Control Register 2. Read/Write */
+#define AP_IOBASE 0x3b0 /* Base address of 1 plane board. */
+#define AP_STATUS isaIO2mem(AP_IOBASE+0) /* Status register. Read */
+#define AP_WRITE_ENABLE isaIO2mem(AP_IOBASE+0) /* Write Enable Register Write */
+#define AP_DEVICE_ID isaIO2mem(AP_IOBASE+1) /* Device ID Register. Read */
+#define AP_ROP_1 isaIO2mem(AP_IOBASE+2) /* Raster Operation reg. Write Word */
+#define AP_DIAG_MEM_REQ isaIO2mem(AP_IOBASE+4) /* Diagnostic Memory Request. Write Word */
+#define AP_CONTROL_0 isaIO2mem(AP_IOBASE+8) /* Control Register 0. Read/Write */
+#define AP_CONTROL_1 isaIO2mem(AP_IOBASE+0xa) /* Control Register 1. Read/Write */
+#define AP_CONTROL_3A isaIO2mem(AP_IOBASE+0xe) /* Control Register 3a. Read/Write */
+#define AP_CONTROL_2 isaIO2mem(AP_IOBASE+0xc) /* Control Register 2. Read/Write */
#define FRAME_BUFFER_START 0x0FA0000
@@ -112,44 +113,57 @@
#endif
+void dn_video_setup(char *options, int *ints);
+
/* frame buffer operations */
-static int dnfb_open(struct fb_info *info, int user);
-static int dnfb_release(struct fb_info *info, int user);
-static int dnfb_get_fix(struct fb_fix_screeninfo *fix, int con,
- struct fb_info *info);
-static int dnfb_get_var(struct fb_var_screeninfo *var, int con,
- struct fb_info *info);
-static int dnfb_set_var(struct fb_var_screeninfo *var, int con,
- struct fb_info *info);
-static int dnfb_get_cmap(struct fb_cmap *cmap,int kspc,int con,
+static int dn_fb_open(struct fb_info *info,int user);
+static int dn_fb_release(struct fb_info *info,int user);
+static int dn_fb_get_fix(struct fb_fix_screeninfo *fix, int con,
struct fb_info *info);
-static int dnfb_set_cmap(struct fb_cmap *cmap,int kspc,int con,
+static int dn_fb_get_var(struct fb_var_screeninfo *var, int con,
struct fb_info *info);
-static int dnfb_pan_display(struct fb_var_screeninfo *var, int con,
- struct fb_info *info);
-static int dnfb_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg, int con,
- struct fb_info *info);
+static int dn_fb_set_var(struct fb_var_screeninfo *var, int isactive,
+ struct fb_info *info);
+static int dn_fb_get_cmap(struct fb_cmap *cmap,int kspc,int con,
+ struct fb_info *info);
+static int dn_fb_set_cmap(struct fb_cmap *cmap,int kspc,int con,
+ struct fb_info *info);
+static int dn_fb_pan_display(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info);
+static int dn_fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+ unsigned long arg, int con, struct fb_info *info);
-static int dnfbcon_switch(int con, struct fb_info *info);
-static int dnfbcon_updatevar(int con, struct fb_info *info);
-static void dnfbcon_blank(int blank, struct fb_info *info);
+static int dnfbcon_switch(int con,struct fb_info *info);
+static int dnfbcon_updatevar(int con,struct fb_info *info);
+static void dnfbcon_blank(int blank,struct fb_info *info);
-static void dnfb_set_disp(int con, struct fb_info *info);
+static void dn_fb_set_disp(int con,struct fb_info *info);
static struct display disp[MAX_NR_CONSOLES];
static struct fb_info fb_info;
-static struct fb_ops dnfb_ops = {
- dnfb_open,dnfb_release, dnfb_get_fix, dnfb_get_var, dnfb_set_var,
- dnfb_get_cmap, dnfb_set_cmap, dnfb_pan_display, dnfb_ioctl
+static struct fb_ops dn_fb_ops = {
+ dn_fb_open,dn_fb_release, dn_fb_get_fix, dn_fb_get_var, dn_fb_set_var,
+ dn_fb_get_cmap, dn_fb_set_cmap, dn_fb_pan_display, dn_fb_ioctl
};
static int currcon=0;
-static char dnfb_name[]="Apollo";
+#define NUM_TOTAL_MODES 1
+struct fb_var_screeninfo dn_fb_predefined[] = {
+
+ { 0, },
+
+};
+
+static char dn_fb_name[]="Apollo ";
+
+/* accel stuff */
+#define USE_DN_ACCEL
-static int dnfb_open(struct fb_info *info, int user)
+static struct display_switch dispsw_apollofb;
+
+static int dn_fb_open(struct fb_info *info,int user)
{
/*
* Nothing, only a usage count for the moment
@@ -159,18 +173,17 @@ static int dnfb_open(struct fb_info *info, int user)
return(0);
}
-static int dnfb_release(struct fb_info *info, int user)
+static int dn_fb_release(struct fb_info *info,int user)
{
MOD_DEC_USE_COUNT;
return(0);
}
-static int dnfb_get_fix(struct fb_fix_screeninfo *fix, int con,
- struct fb_info *info)
-{
- memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+static int dn_fb_get_fix(struct fb_fix_screeninfo *fix, int con,
+ struct fb_info *info) {
+
strcpy(fix->id,"Apollo Mono");
- fix->smem_start=FRAME_BUFFER_START+IO_BASE;
+ fix->smem_start=(FRAME_BUFFER_START+IO_BASE);
fix->smem_len=FRAME_BUFFER_LEN;
fix->type=FB_TYPE_PACKED_PIXELS;
fix->type_aux=0;
@@ -184,10 +197,9 @@ static int dnfb_get_fix(struct fb_fix_screeninfo *fix, int con,
}
-static int dnfb_get_var(struct fb_var_screeninfo *var, int con,
- struct fb_info *info)
-{
- memset(var, 0, sizeof(struct fb_var_screeninfo));
+static int dn_fb_get_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info) {
+
var->xres=1280;
var->yres=1024;
var->xres_virtual=2048;
@@ -212,9 +224,10 @@ static int dnfb_get_var(struct fb_var_screeninfo *var, int con,
}
-static int dnfb_set_var(struct fb_var_screeninfo *var, int con,
- struct fb_info *info)
-{
+static int dn_fb_set_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info) {
+
+ printk("fb_set_var\n");
if(var->xres!=1280)
return -EINVAL;
if(var->yres!=1024)
@@ -254,119 +267,284 @@ static int dnfb_set_var(struct fb_var_screeninfo *var, int con,
}
-static int dnfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
- struct fb_info *info)
-{
+static int dn_fb_get_cmap(struct fb_cmap *cmap,int kspc,int con,
+ struct fb_info *info) {
+
printk("get cmap not supported\n");
return -EINVAL;
}
-static int dnfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
- struct fb_info *info)
-{
+static int dn_fb_set_cmap(struct fb_cmap *cmap,int kspc,int con,
+ struct fb_info *info) {
+
printk("set cmap not supported\n");
return -EINVAL;
}
-static int dnfb_pan_display(struct fb_var_screeninfo *var, int con,
- struct fb_info *info)
-{
+static int dn_fb_pan_display(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info) {
+
printk("panning not supported\n");
return -EINVAL;
}
-static int dnfb_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg, int con,
- struct fb_info *info)
-{
+static int dn_fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+ unsigned long arg, int con, struct fb_info *info) {
+
+ printk("no IOCTLs as of yet.\n");
+
return -EINVAL;
+
}
-static void dnfb_set_disp(int con, struct fb_info *info)
-{
+static void dn_fb_set_disp(int con, struct fb_info *info) {
+
struct fb_fix_screeninfo fix;
+ struct display *display;
+
+ dn_fb_get_fix(&fix,con, info);
+
+ if (con>=0)
+ display=&fb_display[con];
+ else
+ display=&disp[0];
- dnfb_get_fix(&fix, con, info);
if(con==-1)
con=0;
- disp[con].screen_base = fix.smem_start;
- disp[con].visual = fix.visual;
- disp[con].type = fix.type;
- disp[con].type_aux = fix.type_aux;
- disp[con].ypanstep = fix.ypanstep;
- disp[con].ywrapstep = fix.ywrapstep;
- disp[con].can_soft_blank = 1;
- disp[con].inverse = 0;
- disp[con].line_length = fix.line_length;
+ display->screen_base = (u_char *)fix.smem_start;
+ display->visual = fix.visual;
+ display->type = fix.type;
+ display->type_aux = fix.type_aux;
+ display->ypanstep = fix.ypanstep;
+ display->ywrapstep = fix.ywrapstep;
+ display->can_soft_blank = 1;
+ display->inverse = 0;
+ display->line_length = fix.line_length;
#ifdef FBCON_HAS_MFB
- disp[con].dispsw = &fbcon_mfb;
+ display->dispsw = &fbcon_mfb;
#else
- disp[con].dispsw = &fbcon_dummy;
+ display->dispsw=&fbcon_dummy;
#endif
+
}
-int dnfb_init(void)
-{
+unsigned long dnfb_init(unsigned long mem_start) {
+
+ int err;
+
+
fb_info.changevar=NULL;
- strcpy(&fb_info.modename[0],dnfb_name);
+ strcpy(&fb_info.modename[0],dn_fb_name);
fb_info.fontname[0]=0;
fb_info.disp=disp;
fb_info.switch_con=&dnfbcon_switch;
fb_info.updatevar=&dnfbcon_updatevar;
fb_info.blank=&dnfbcon_blank;
fb_info.node = -1;
- fb_info.fbops = &dnfb_ops;
- fb_info.flags = FBINFO_FLAG_DEFAULT;
+ fb_info.fbops = &dn_fb_ops;
- outb(RESET_CREG, AP_CONTROL_3A);
- outw(0x0, AP_WRITE_ENABLE);
- outb(NORMAL_MODE,AP_CONTROL_0);
- outb((AD_BLT | DST_EQ_SRC | NORM_CREG1), AP_CONTROL_1);
- outb(S_DATA_PLN, AP_CONTROL_2);
- outw(SWAP(0x3),AP_ROP_1);
-
- dnfb_get_var(&disp[0].var, 0, &fb_info);
- dnfb_set_disp(-1, &fb_info);
-
- if (register_framebuffer(&fb_info) < 0) {
- printk(KERN_ERR "unable to register apollo frame buffer\n");
- return -EINVAL;
+ dn_fb_get_var(&disp[0].var,0, &fb_info);
+
+ dn_fb_set_disp(-1, &fb_info);
+
+ err=register_framebuffer(&fb_info);
+ if(err < 0) {
+ panic("unable to register apollo frame buffer\n");
}
- printk("fb%d: apollo frame buffer alive and kicking !\n",
- GET_FB_IDX(fb_info.node));
- return 0;
+ /* now we have registered we can safely setup the hardware */
+
+ outb(RESET_CREG, AP_CONTROL_3A);
+ outw(0x0, AP_WRITE_ENABLE);
+ outb(NORMAL_MODE, AP_CONTROL_0);
+ outb((AD_BLT | DST_EQ_SRC | NORM_CREG1), AP_CONTROL_1);
+ outb(S_DATA_PLN, AP_CONTROL_2);
+ outw(SWAP(0x3), AP_ROP_1);
+
+ printk("apollo frame buffer alive and kicking !\n");
+
+
+ return mem_start;
+
}
-static int dnfbcon_switch(int con, struct fb_info *info)
-{
+static int dnfbcon_switch(int con, struct fb_info *info) {
+
currcon=con;
return 0;
}
-static int dnfbcon_updatevar(int con, struct fb_info *info)
-{
+static int dnfbcon_updatevar(int con, struct fb_info *info) {
+
return 0;
+
}
-static void dnfbcon_blank(int blank, struct fb_info *info)
-{
+static void dnfbcon_blank(int blank, struct fb_info *info) {
+
if(blank) {
- outb(0, AP_CONTROL_3A);
- outb((AD_BLT | DST_EQ_SRC | NORM_CREG1) & ~ENAB_DISP,
- AP_CONTROL_1);
+ outb(0x0, AP_CONTROL_3A);
+ }
+ else {
+ outb(0x1, AP_CONTROL_3A);
+ }
+
+ return ;
+
+}
+
+void dn_video_setup(char *options, int *ints) {
+
+ return;
+
+}
+
+void dn_bitblt(struct display *p,int x_src,int y_src, int x_dest, int y_dest,
+ int x_count, int y_count) {
+
+ int incr,y_delta,pre_read=0,x_end,x_word_count;
+ ushort *src,dummy;
+ uint start_mask,end_mask,dest;
+ short i,j;
+
+ incr=(y_dest<=y_src) ? 1 : -1 ;
+
+ src=(ushort *)(p->screen_base+ y_src*p->next_line+(x_src >> 4));
+ dest=y_dest*(p->next_line >> 1)+(x_dest >> 4);
+
+ if(incr>0) {
+ y_delta=(p->next_line*8)-x_src-x_count;
+ x_end=x_dest+x_count-1;
+ x_word_count=(x_end>>4) - (x_dest >> 4) + 1;
+ start_mask=0xffff0000 >> (x_dest & 0xf);
+ end_mask=0x7ffff >> (x_end & 0xf);
+ outb((((x_dest & 0xf) - (x_src &0xf)) % 16)|(0x4 << 5),AP_CONTROL_0);
+ if((x_dest & 0xf) < (x_src & 0xf))
+ pre_read=1;
}
else {
- outb(1, AP_CONTROL_3A);
- outb((AD_BLT | DST_EQ_SRC | NORM_CREG1), AP_CONTROL_1);
+ y_delta=-((p->next_line*8)-x_src-x_count);
+ x_end=x_dest-x_count+1;
+ x_word_count=(x_dest>>4) - (x_end >> 4) + 1;
+ start_mask=0x7ffff >> (x_dest & 0xf);
+ end_mask=0xffff0000 >> (x_end & 0xf);
+ outb(((-((x_src & 0xf) - (x_dest &0xf))) % 16)|(0x4 << 5),AP_CONTROL_0);
+ if((x_dest & 0xf) > (x_src & 0xf))
+ pre_read=1;
+ }
+
+ for(i=0;i<y_count;i++) {
+
+ outb(0xc | (dest >> 16), AP_CONTROL_3A);
+
+ if(pre_read) {
+ dummy=*src;
+ src+=incr;
+ }
+
+ if(x_word_count) {
+ outb(start_mask,AP_WRITE_ENABLE);
+ *src=dest;
+ src+=incr;
+ dest+=incr;
+ outb(0,AP_WRITE_ENABLE);
+
+ for(j=1;j<(x_word_count-1);j++) {
+ *src=dest;
+ src+=incr;
+ dest+=incr;
+ }
+
+ outb(start_mask,AP_WRITE_ENABLE);
+ *src=dest;
+ dest+=incr;
+ src+=incr;
+ }
+ else {
+ outb(start_mask | end_mask, AP_WRITE_ENABLE);
+ *src=dest;
+ dest+=incr;
+ src+=incr;
+ }
+ src+=(y_delta/16);
+ dest+=(y_delta/16);
+ }
+ outb(NORMAL_MODE,AP_CONTROL_0);
+}
+
+static void bmove_apollofb(struct display *p, int sy, int sx, int dy, int dx,
+ int height, int width)
+{
+
+ int fontheight,fontwidth;
+
+ fontheight=fontheight(p);
+ fontwidth=fontwidth(p);
+
+#ifdef USE_DN_ACCEL
+ dn_bitblt(p,sx,sy*fontheight,dx,dy*fontheight,width*fontwidth,
+ height*fontheight);
+#else
+ u_char *src, *dest;
+ u_int rows;
+
+ if (sx == 0 && dx == 0 && width == p->next_line) {
+ src = p->screen_base+sy*fontheight*width;
+ dest = p->screen_base+dy*fontheight*width;
+ mymemmove(dest, src, height*fontheight*width);
+ } else if (dy <= sy) {
+ src = p->screen_base+sy*fontheight*next_line+sx;
+ dest = p->screen_base+dy*fontheight*next_line+dx;
+ for (rows = height*fontheight; rows--;) {
+ mymemmove(dest, src, width);
+ src += p->next_line;
+ dest += p->next_line;
}
+ } else {
+ src = p->screen_base+((sy+height)*fontheight-1)*p->next_line+sx;
+ dest = p->screen_base+((dy+height)*fontheight-1)*p->next_line+dx;
+ for (rows = height*fontheight; rows--;) {
+ mymemmove(dest, src, width);
+ src -= p->next_line;
+ dest -= p->next_line;
+ }
+ }
+#endif
+}
+
+static void clear_apollofb(struct vc_data *conp, struct display *p, int sy, int sx,
+ int height, int width)
+{
+ fbcon_mfb_clear(conp,p,sy,sx,height,width);
}
+
+static void putc_apollofb(struct vc_data *conp, struct display *p, int c, int yy,
+ int xx)
+{
+ fbcon_mfb_putc(conp,p,c,yy,xx);
+}
+
+static void putcs_apollofb(struct vc_data *conp, struct display *p, const char *s,
+ int count, int yy, int xx)
+{
+ fbcon_mfb_putcs(conp,p,s,count,yy,xx);
+}
+
+static void rev_char_apollofb(struct display *p, int xx, int yy)
+{
+ fbcon_mfb_revc(p,xx,yy);
+}
+
+static struct display_switch dispsw_apollofb = {
+ fbcon_mfb_setup, bmove_apollofb, clear_apollofb,
+ putc_apollofb, putcs_apollofb, rev_char_apollofb
+};