aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/isdn
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/isdn')
-rw-r--r--drivers/isdn/Kconfig67
-rw-r--r--drivers/isdn/Makefile15
-rw-r--r--drivers/isdn/act2000/Kconfig13
-rw-r--r--drivers/isdn/act2000/Makefile9
-rw-r--r--drivers/isdn/act2000/act2000.h202
-rw-r--r--drivers/isdn/act2000/act2000_isa.c449
-rw-r--r--drivers/isdn/act2000/act2000_isa.h136
-rw-r--r--drivers/isdn/act2000/capi.c1177
-rw-r--r--drivers/isdn/act2000/capi.h366
-rw-r--r--drivers/isdn/act2000/module.c808
-rw-r--r--drivers/isdn/capi/Kconfig53
-rw-r--r--drivers/isdn/capi/Makefile15
-rw-r--r--drivers/isdn/capi/capi.c1554
-rw-r--r--drivers/isdn/capi/capidrv.c2315
-rw-r--r--drivers/isdn/capi/capidrv.h140
-rw-r--r--drivers/isdn/capi/capifs.c212
-rw-r--r--drivers/isdn/capi/capifs.h11
-rw-r--r--drivers/isdn/capi/capilib.c200
-rw-r--r--drivers/isdn/capi/capiutil.c859
-rw-r--r--drivers/isdn/capi/kcapi.c991
-rw-r--r--drivers/isdn/capi/kcapi.h49
-rw-r--r--drivers/isdn/capi/kcapi_proc.c336
-rw-r--r--drivers/isdn/divert/Makefile9
-rw-r--r--drivers/isdn/divert/divert_init.c83
-rw-r--r--drivers/isdn/divert/divert_procfs.c319
-rw-r--r--drivers/isdn/divert/isdn_divert.c861
-rw-r--r--drivers/isdn/divert/isdn_divert.h132
-rw-r--r--drivers/isdn/hardware/Kconfig10
-rw-r--r--drivers/isdn/hardware/Makefile6
-rw-r--r--drivers/isdn/hardware/avm/Kconfig66
-rw-r--r--drivers/isdn/hardware/avm/Makefile11
-rw-r--r--drivers/isdn/hardware/avm/avm_cs.c510
-rw-r--r--drivers/isdn/hardware/avm/avmcard.h585
-rw-r--r--drivers/isdn/hardware/avm/b1.c814
-rw-r--r--drivers/isdn/hardware/avm/b1dma.c980
-rw-r--r--drivers/isdn/hardware/avm/b1isa.c245
-rw-r--r--drivers/isdn/hardware/avm/b1pci.c417
-rw-r--r--drivers/isdn/hardware/avm/b1pcmcia.c224
-rw-r--r--drivers/isdn/hardware/avm/c4.c1310
-rw-r--r--drivers/isdn/hardware/avm/t1isa.c596
-rw-r--r--drivers/isdn/hardware/avm/t1pci.c260
-rw-r--r--drivers/isdn/hardware/eicon/Kconfig53
-rw-r--r--drivers/isdn/hardware/eicon/Makefile23
-rw-r--r--drivers/isdn/hardware/eicon/adapter.h17
-rw-r--r--drivers/isdn/hardware/eicon/capi20.h699
-rw-r--r--drivers/isdn/hardware/eicon/capidtmf.c685
-rw-r--r--drivers/isdn/hardware/eicon/capidtmf.h79
-rw-r--r--drivers/isdn/hardware/eicon/capifunc.c1219
-rw-r--r--drivers/isdn/hardware/eicon/capifunc.h40
-rw-r--r--drivers/isdn/hardware/eicon/capimain.c147
-rw-r--r--drivers/isdn/hardware/eicon/cardtype.h1098
-rw-r--r--drivers/isdn/hardware/eicon/cp_vers.h26
-rw-r--r--drivers/isdn/hardware/eicon/dadapter.c366
-rw-r--r--drivers/isdn/hardware/eicon/dadapter.h34
-rw-r--r--drivers/isdn/hardware/eicon/dbgioctl.h198
-rw-r--r--drivers/isdn/hardware/eicon/debug.c2133
-rw-r--r--drivers/isdn/hardware/eicon/debug_if.h90
-rw-r--r--drivers/isdn/hardware/eicon/debuglib.c156
-rw-r--r--drivers/isdn/hardware/eicon/debuglib.h322
-rw-r--r--drivers/isdn/hardware/eicon/dfifo.h54
-rw-r--r--drivers/isdn/hardware/eicon/di.c835
-rw-r--r--drivers/isdn/hardware/eicon/di.h118
-rw-r--r--drivers/isdn/hardware/eicon/di_dbg.h37
-rw-r--r--drivers/isdn/hardware/eicon/di_defs.h181
-rw-r--r--drivers/isdn/hardware/eicon/did_vers.h26
-rw-r--r--drivers/isdn/hardware/eicon/diddfunc.c115
-rw-r--r--drivers/isdn/hardware/eicon/diva.c660
-rw-r--r--drivers/isdn/hardware/eicon/diva.h31
-rw-r--r--drivers/isdn/hardware/eicon/diva_didd.c151
-rw-r--r--drivers/isdn/hardware/eicon/diva_dma.c94
-rw-r--r--drivers/isdn/hardware/eicon/diva_dma.h48
-rw-r--r--drivers/isdn/hardware/eicon/diva_pci.h19
-rw-r--r--drivers/isdn/hardware/eicon/divacapi.h1360
-rw-r--r--drivers/isdn/hardware/eicon/divamnt.c257
-rw-r--r--drivers/isdn/hardware/eicon/divasfunc.c238
-rw-r--r--drivers/isdn/hardware/eicon/divasi.c581
-rw-r--r--drivers/isdn/hardware/eicon/divasmain.c856
-rw-r--r--drivers/isdn/hardware/eicon/divasproc.c441
-rw-r--r--drivers/isdn/hardware/eicon/divasync.h490
-rw-r--r--drivers/isdn/hardware/eicon/dqueue.c110
-rw-r--r--drivers/isdn/hardware/eicon/dqueue.h31
-rw-r--r--drivers/isdn/hardware/eicon/dsp_defs.h304
-rw-r--r--drivers/isdn/hardware/eicon/dsp_tst.h47
-rw-r--r--drivers/isdn/hardware/eicon/dspdids.h75
-rw-r--r--drivers/isdn/hardware/eicon/dsrv4bri.h40
-rw-r--r--drivers/isdn/hardware/eicon/dsrv_bri.h37
-rw-r--r--drivers/isdn/hardware/eicon/dsrv_pri.h38
-rw-r--r--drivers/isdn/hardware/eicon/entity.h28
-rw-r--r--drivers/isdn/hardware/eicon/helpers.h51
-rw-r--r--drivers/isdn/hardware/eicon/idifunc.c267
-rw-r--r--drivers/isdn/hardware/eicon/io.c852
-rw-r--r--drivers/isdn/hardware/eicon/io.h308
-rw-r--r--drivers/isdn/hardware/eicon/istream.c226
-rw-r--r--drivers/isdn/hardware/eicon/kst_ifc.h336
-rw-r--r--drivers/isdn/hardware/eicon/main_if.h50
-rw-r--r--drivers/isdn/hardware/eicon/maintidi.c2194
-rw-r--r--drivers/isdn/hardware/eicon/maintidi.h172
-rw-r--r--drivers/isdn/hardware/eicon/man_defs.h133
-rw-r--r--drivers/isdn/hardware/eicon/mdm_msg.h346
-rw-r--r--drivers/isdn/hardware/eicon/message.c15047
-rw-r--r--drivers/isdn/hardware/eicon/mi_pc.h204
-rw-r--r--drivers/isdn/hardware/eicon/mntfunc.c370
-rw-r--r--drivers/isdn/hardware/eicon/os_4bri.c1131
-rw-r--r--drivers/isdn/hardware/eicon/os_4bri.h8
-rw-r--r--drivers/isdn/hardware/eicon/os_bri.c813
-rw-r--r--drivers/isdn/hardware/eicon/os_bri.h8
-rw-r--r--drivers/isdn/hardware/eicon/os_capi.h21
-rw-r--r--drivers/isdn/hardware/eicon/os_pri.c1051
-rw-r--r--drivers/isdn/hardware/eicon/os_pri.h8
-rw-r--r--drivers/isdn/hardware/eicon/pc.h738
-rw-r--r--drivers/isdn/hardware/eicon/pc_init.h267
-rw-r--r--drivers/isdn/hardware/eicon/pc_maint.h160
-rw-r--r--drivers/isdn/hardware/eicon/pkmaint.h44
-rw-r--r--drivers/isdn/hardware/eicon/platform.h394
-rw-r--r--drivers/isdn/hardware/eicon/pr_pc.h76
-rw-r--r--drivers/isdn/hardware/eicon/s_4bri.c510
-rw-r--r--drivers/isdn/hardware/eicon/s_bri.c191
-rw-r--r--drivers/isdn/hardware/eicon/s_pri.c205
-rw-r--r--drivers/isdn/hardware/eicon/sdp_hdr.h117
-rw-r--r--drivers/isdn/hardware/eicon/um_idi.c885
-rw-r--r--drivers/isdn/hardware/eicon/um_idi.h43
-rw-r--r--drivers/isdn/hardware/eicon/um_xdi.h68
-rw-r--r--drivers/isdn/hardware/eicon/xdi_adapter.h70
-rw-r--r--drivers/isdn/hardware/eicon/xdi_msg.h127
-rw-r--r--drivers/isdn/hardware/eicon/xdi_vers.h26
-rw-r--r--drivers/isdn/hisax/Kconfig442
-rw-r--r--drivers/isdn/hisax/Makefile64
-rw-r--r--drivers/isdn/hisax/amd7930_fn.c796
-rw-r--r--drivers/isdn/hisax/amd7930_fn.h37
-rw-r--r--drivers/isdn/hisax/arcofi.c134
-rw-r--r--drivers/isdn/hisax/arcofi.h27
-rw-r--r--drivers/isdn/hisax/asuscom.c427
-rw-r--r--drivers/isdn/hisax/avm_a1.c317
-rw-r--r--drivers/isdn/hisax/avm_a1p.c268
-rw-r--r--drivers/isdn/hisax/avm_pci.c865
-rw-r--r--drivers/isdn/hisax/avma1_cs.c527
-rw-r--r--drivers/isdn/hisax/bkm_a4t.c344
-rw-r--r--drivers/isdn/hisax/bkm_a8.c451
-rw-r--r--drivers/isdn/hisax/bkm_ax.h119
-rw-r--r--drivers/isdn/hisax/callc.c1793
-rw-r--r--drivers/isdn/hisax/config.c1958
-rw-r--r--drivers/isdn/hisax/diva.c1183
-rw-r--r--drivers/isdn/hisax/elsa.c1190
-rw-r--r--drivers/isdn/hisax/elsa_cs.c532
-rw-r--r--drivers/isdn/hisax/elsa_ser.c657
-rw-r--r--drivers/isdn/hisax/enternow.h51
-rw-r--r--drivers/isdn/hisax/enternow_pci.c399
-rw-r--r--drivers/isdn/hisax/fsm.c163
-rw-r--r--drivers/isdn/hisax/fsm.h61
-rw-r--r--drivers/isdn/hisax/gazel.c684
-rw-r--r--drivers/isdn/hisax/hfc4s8s_l1.c1714
-rw-r--r--drivers/isdn/hisax/hfc4s8s_l1.h88
-rw-r--r--drivers/isdn/hisax/hfc_2bds0.c1082
-rw-r--r--drivers/isdn/hisax/hfc_2bds0.h128
-rw-r--r--drivers/isdn/hisax/hfc_2bs0.c593
-rw-r--r--drivers/isdn/hisax/hfc_2bs0.h60
-rw-r--r--drivers/isdn/hisax/hfc_pci.c1747
-rw-r--r--drivers/isdn/hisax/hfc_pci.h236
-rw-r--r--drivers/isdn/hisax/hfc_sx.c1521
-rw-r--r--drivers/isdn/hisax/hfc_sx.h197
-rw-r--r--drivers/isdn/hisax/hfc_usb.c1828
-rw-r--r--drivers/isdn/hisax/hfc_usb.h228
-rw-r--r--drivers/isdn/hisax/hfcscard.c266
-rw-r--r--drivers/isdn/hisax/hisax.h1341
-rw-r--r--drivers/isdn/hisax/hisax_cfg.h64
-rw-r--r--drivers/isdn/hisax/hisax_debug.h81
-rw-r--r--drivers/isdn/hisax/hisax_fcpcipnp.c1028
-rw-r--r--drivers/isdn/hisax/hisax_fcpcipnp.h58
-rw-r--r--drivers/isdn/hisax/hisax_if.h66
-rw-r--r--drivers/isdn/hisax/hisax_isac.c897
-rw-r--r--drivers/isdn/hisax/hisax_isac.h45
-rw-r--r--drivers/isdn/hisax/hscx.c280
-rw-r--r--drivers/isdn/hisax/hscx.h41
-rw-r--r--drivers/isdn/hisax/hscx_irq.c292
-rw-r--r--drivers/isdn/hisax/icc.c685
-rw-r--r--drivers/isdn/hisax/icc.h72
-rw-r--r--drivers/isdn/hisax/ipac.h29
-rw-r--r--drivers/isdn/hisax/ipacx.c1004
-rw-r--r--drivers/isdn/hisax/ipacx.h162
-rw-r--r--drivers/isdn/hisax/isac.c684
-rw-r--r--drivers/isdn/hisax/isac.h70
-rw-r--r--drivers/isdn/hisax/isar.c1909
-rw-r--r--drivers/isdn/hisax/isar.h222
-rw-r--r--drivers/isdn/hisax/isdnhdlc.c628
-rw-r--r--drivers/isdn/hisax/isdnhdlc.h72
-rw-r--r--drivers/isdn/hisax/isdnl1.c932
-rw-r--r--drivers/isdn/hisax/isdnl1.h32
-rw-r--r--drivers/isdn/hisax/isdnl2.c1860
-rw-r--r--drivers/isdn/hisax/isdnl2.h26
-rw-r--r--drivers/isdn/hisax/isdnl3.c610
-rw-r--r--drivers/isdn/hisax/isdnl3.h37
-rw-r--r--drivers/isdn/hisax/isurf.c306
-rw-r--r--drivers/isdn/hisax/ix1_micro.c318
-rw-r--r--drivers/isdn/hisax/jade.c318
-rw-r--r--drivers/isdn/hisax/jade.h135
-rw-r--r--drivers/isdn/hisax/jade_irq.c236
-rw-r--r--drivers/isdn/hisax/l3_1tr6.c955
-rw-r--r--drivers/isdn/hisax/l3_1tr6.h164
-rw-r--r--drivers/isdn/hisax/l3dss1.c3238
-rw-r--r--drivers/isdn/hisax/l3dss1.h124
-rw-r--r--drivers/isdn/hisax/l3ni1.c3189
-rw-r--r--drivers/isdn/hisax/l3ni1.h136
-rw-r--r--drivers/isdn/hisax/lmgr.c50
-rw-r--r--drivers/isdn/hisax/mic.c239
-rw-r--r--drivers/isdn/hisax/netjet.c996
-rw-r--r--drivers/isdn/hisax/netjet.h72
-rw-r--r--drivers/isdn/hisax/niccy.c389
-rw-r--r--drivers/isdn/hisax/nj_s.c278
-rw-r--r--drivers/isdn/hisax/nj_u.c244
-rw-r--r--drivers/isdn/hisax/q931.c1522
-rw-r--r--drivers/isdn/hisax/s0box.c266
-rw-r--r--drivers/isdn/hisax/saphir.c300
-rw-r--r--drivers/isdn/hisax/sedlbauer.c833
-rw-r--r--drivers/isdn/hisax/sedlbauer_cs.c640
-rw-r--r--drivers/isdn/hisax/sportster.c270
-rw-r--r--drivers/isdn/hisax/st5481.h535
-rw-r--r--drivers/isdn/hisax/st5481_b.c374
-rw-r--r--drivers/isdn/hisax/st5481_d.c776
-rw-r--r--drivers/isdn/hisax/st5481_hdlc.c580
-rw-r--r--drivers/isdn/hisax/st5481_hdlc.h62
-rw-r--r--drivers/isdn/hisax/st5481_init.c224
-rw-r--r--drivers/isdn/hisax/st5481_usb.c650
-rw-r--r--drivers/isdn/hisax/tei.c466
-rw-r--r--drivers/isdn/hisax/teleint.c339
-rw-r--r--drivers/isdn/hisax/teles0.c367
-rw-r--r--drivers/isdn/hisax/teles3.c499
-rw-r--r--drivers/isdn/hisax/teles_cs.c513
-rw-r--r--drivers/isdn/hisax/telespci.c359
-rw-r--r--drivers/isdn/hisax/w6692.c1096
-rw-r--r--drivers/isdn/hisax/w6692.h184
-rw-r--r--drivers/isdn/hysdn/Kconfig18
-rw-r--r--drivers/isdn/hysdn/Makefile11
-rw-r--r--drivers/isdn/hysdn/boardergo.c453
-rw-r--r--drivers/isdn/hysdn/boardergo.h100
-rw-r--r--drivers/isdn/hysdn/hycapi.c797
-rw-r--r--drivers/isdn/hysdn/hysdn_boot.c399
-rw-r--r--drivers/isdn/hysdn/hysdn_defs.h298
-rw-r--r--drivers/isdn/hysdn/hysdn_init.c254
-rw-r--r--drivers/isdn/hysdn/hysdn_net.c348
-rw-r--r--drivers/isdn/hysdn/hysdn_pof.h78
-rw-r--r--drivers/isdn/hysdn/hysdn_procconf.c443
-rw-r--r--drivers/isdn/hysdn/hysdn_proclog.c441
-rw-r--r--drivers/isdn/hysdn/hysdn_sched.c207
-rw-r--r--drivers/isdn/hysdn/ince1pc.h134
-rw-r--r--drivers/isdn/i4l/Kconfig141
-rw-r--r--drivers/isdn/i4l/Makefile18
-rw-r--r--drivers/isdn/i4l/isdn_audio.c720
-rw-r--r--drivers/isdn/i4l/isdn_audio.h45
-rw-r--r--drivers/isdn/i4l/isdn_bsdcomp.c937
-rw-r--r--drivers/isdn/i4l/isdn_common.c2253
-rw-r--r--drivers/isdn/i4l/isdn_common.h47
-rw-r--r--drivers/isdn/i4l/isdn_concap.c108
-rw-r--r--drivers/isdn/i4l/isdn_concap.h14
-rw-r--r--drivers/isdn/i4l/isdn_net.c3222
-rw-r--r--drivers/isdn/i4l/isdn_net.h190
-rw-r--r--drivers/isdn/i4l/isdn_ppp.c3020
-rw-r--r--drivers/isdn/i4l/isdn_ppp.h43
-rw-r--r--drivers/isdn/i4l/isdn_tty.c3911
-rw-r--r--drivers/isdn/i4l/isdn_tty.h122
-rw-r--r--drivers/isdn/i4l/isdn_ttyfax.c1122
-rw-r--r--drivers/isdn/i4l/isdn_ttyfax.h18
-rw-r--r--drivers/isdn/i4l/isdn_v110.c617
-rw-r--r--drivers/isdn/i4l/isdn_v110.h29
-rw-r--r--drivers/isdn/i4l/isdn_x25iface.c328
-rw-r--r--drivers/isdn/i4l/isdn_x25iface.h39
-rw-r--r--drivers/isdn/icn/Kconfig16
-rw-r--r--drivers/isdn/icn/Makefile5
-rw-r--r--drivers/isdn/icn/icn.c1691
-rw-r--r--drivers/isdn/icn/icn.h254
-rw-r--r--drivers/isdn/isdnloop/Makefile5
-rw-r--r--drivers/isdn/isdnloop/isdnloop.c1554
-rw-r--r--drivers/isdn/isdnloop/isdnloop.h112
-rw-r--r--drivers/isdn/pcbit/Kconfig14
-rw-r--r--drivers/isdn/pcbit/Makefile9
-rw-r--r--drivers/isdn/pcbit/callbacks.c367
-rw-r--r--drivers/isdn/pcbit/callbacks.h49
-rw-r--r--drivers/isdn/pcbit/capi.c663
-rw-r--r--drivers/isdn/pcbit/capi.h88
-rw-r--r--drivers/isdn/pcbit/drv.c1088
-rw-r--r--drivers/isdn/pcbit/edss1.c325
-rw-r--r--drivers/isdn/pcbit/edss1.h99
-rw-r--r--drivers/isdn/pcbit/layer2.c732
-rw-r--r--drivers/isdn/pcbit/layer2.h288
-rw-r--r--drivers/isdn/pcbit/module.c130
-rw-r--r--drivers/isdn/pcbit/pcbit.h169
-rw-r--r--drivers/isdn/sc/Kconfig12
-rw-r--r--drivers/isdn/sc/Makefile10
-rw-r--r--drivers/isdn/sc/card.h101
-rw-r--r--drivers/isdn/sc/command.c441
-rw-r--r--drivers/isdn/sc/debug.c46
-rw-r--r--drivers/isdn/sc/debug.h19
-rw-r--r--drivers/isdn/sc/event.c69
-rw-r--r--drivers/isdn/sc/hardware.h110
-rw-r--r--drivers/isdn/sc/includes.h18
-rw-r--r--drivers/isdn/sc/init.c571
-rw-r--r--drivers/isdn/sc/interrupt.c260
-rw-r--r--drivers/isdn/sc/ioctl.c601
-rw-r--r--drivers/isdn/sc/message.c241
-rw-r--r--drivers/isdn/sc/message.h245
-rw-r--r--drivers/isdn/sc/packet.c231
-rw-r--r--drivers/isdn/sc/scioc.h105
-rw-r--r--drivers/isdn/sc/shmem.c143
-rw-r--r--drivers/isdn/sc/timer.c147
303 files changed, 150218 insertions, 0 deletions
diff --git a/drivers/isdn/Kconfig b/drivers/isdn/Kconfig
new file mode 100644
index 000000000000..c90afeea54aa
--- /dev/null
+++ b/drivers/isdn/Kconfig
@@ -0,0 +1,67 @@
1#
2# ISDN device configuration
3#
4
5menu "ISDN subsystem"
6
7config ISDN
8 tristate "ISDN support"
9 depends on NET
10 ---help---
11 ISDN ("Integrated Services Digital Networks", called RNIS in France)
12 is a special type of fully digital telephone service; it's mostly
13 used to connect to your Internet service provider (with SLIP or
14 PPP). The main advantage is that the speed is higher than ordinary
15 modem/telephone connections, and that you can have voice
16 conversations while downloading stuff. It only works if your
17 computer is equipped with an ISDN card and both you and your service
18 provider purchased an ISDN line from the phone company. For
19 details, read <http://www.alumni.caltech.edu/~dank/isdn/> on the WWW.
20
21 Select this option if you want your kernel to support ISDN.
22
23
24menu "Old ISDN4Linux"
25 depends on NET && ISDN
26
27config ISDN_I4L
28 tristate "Old ISDN4Linux (obsolete)"
29 ---help---
30 This driver allows you to use an ISDN-card for networking
31 connections and as dialin/out device. The isdn-tty's have a built
32 in AT-compatible modem emulator. Network devices support autodial,
33 channel-bundling, callback and caller-authentication without having
34 a daemon running. A reduced T.70 protocol is supported with tty's
35 suitable for German BTX. On D-Channel, the protocols EDSS1
36 (Euro-ISDN) and 1TR6 (German style) are supported. See
37 <file:Documentation/isdn/README> for more information.
38
39 ISDN support in the linux kernel is moving towards a new API,
40 called CAPI (Common ISDN Application Programming Interface).
41 Therefore the old ISDN4Linux layer is becoming obsolete. It is
42 still usable, though, if you select this option.
43
44if ISDN_I4L
45source "drivers/isdn/i4l/Kconfig"
46endif
47
48endmenu
49
50comment "CAPI subsystem"
51 depends on NET && ISDN
52
53config ISDN_CAPI
54 tristate "CAPI2.0 support"
55 depends on ISDN
56 help
57 This provides the CAPI (Common ISDN Application Programming
58 Interface, a standard making it easy for programs to access ISDN
59 hardware, see <http://www.capi.org/>. This is needed for AVM's set
60 of active ISDN controllers like B1, T1, M1.
61
62source "drivers/isdn/capi/Kconfig"
63
64source "drivers/isdn/hardware/Kconfig"
65
66endmenu
67
diff --git a/drivers/isdn/Makefile b/drivers/isdn/Makefile
new file mode 100644
index 000000000000..03d8ccd51955
--- /dev/null
+++ b/drivers/isdn/Makefile
@@ -0,0 +1,15 @@
1# Makefile for the kernel ISDN subsystem and device drivers.
2
3# Object files in subdirectories
4
5obj-$(CONFIG_ISDN_I4L) += i4l/
6obj-$(CONFIG_ISDN_CAPI) += capi/
7obj-$(CONFIG_ISDN_CAPI) += hardware/
8obj-$(CONFIG_ISDN_DIVERSION) += divert/
9obj-$(CONFIG_ISDN_DRV_HISAX) += hisax/
10obj-$(CONFIG_ISDN_DRV_ICN) += icn/
11obj-$(CONFIG_ISDN_DRV_PCBIT) += pcbit/
12obj-$(CONFIG_ISDN_DRV_SC) += sc/
13obj-$(CONFIG_ISDN_DRV_LOOP) += isdnloop/
14obj-$(CONFIG_ISDN_DRV_ACT2000) += act2000/
15obj-$(CONFIG_HYSDN) += hysdn/
diff --git a/drivers/isdn/act2000/Kconfig b/drivers/isdn/act2000/Kconfig
new file mode 100644
index 000000000000..78e6ad8d57c5
--- /dev/null
+++ b/drivers/isdn/act2000/Kconfig
@@ -0,0 +1,13 @@
1#
2# Config.in for IBM Active 2000 ISDN driver
3#
4config ISDN_DRV_ACT2000
5 tristate "IBM Active 2000 support"
6 depends on ISDN_I4L && ISA
7 help
8 Say Y here if you have an IBM Active 2000 ISDN card. In order to use
9 this card, additional firmware is necessary, which has to be loaded
10 into the card using a utility which is part of the latest
11 isdn4k-utils package. Please read the file
12 <file:Documentation/isdn/README.act2000> for more information.
13
diff --git a/drivers/isdn/act2000/Makefile b/drivers/isdn/act2000/Makefile
new file mode 100644
index 000000000000..05e582fb5c00
--- /dev/null
+++ b/drivers/isdn/act2000/Makefile
@@ -0,0 +1,9 @@
1# Makefile for the act2000 ISDN device driver
2
3# Each configuration option enables a list of files.
4
5obj-$(CONFIG_ISDN_DRV_ACT2000) += act2000.o
6
7# Multipart objects.
8
9act2000-y := module.o capi.o act2000_isa.o
diff --git a/drivers/isdn/act2000/act2000.h b/drivers/isdn/act2000/act2000.h
new file mode 100644
index 000000000000..b091d1a54125
--- /dev/null
+++ b/drivers/isdn/act2000/act2000.h
@@ -0,0 +1,202 @@
1/* $Id: act2000.h,v 1.8.6.3 2001/09/23 22:24:32 kai Exp $
2 *
3 * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000.
4 *
5 * Author Fritz Elfert
6 * Copyright by Fritz Elfert <fritz@isdn4linux.de>
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 * Thanks to Friedemann Baitinger and IBM Germany
12 *
13 */
14
15#ifndef act2000_h
16#define act2000_h
17
18#include <linux/compiler.h>
19
20#define ACT2000_IOCTL_SETPORT 1
21#define ACT2000_IOCTL_GETPORT 2
22#define ACT2000_IOCTL_SETIRQ 3
23#define ACT2000_IOCTL_GETIRQ 4
24#define ACT2000_IOCTL_SETBUS 5
25#define ACT2000_IOCTL_GETBUS 6
26#define ACT2000_IOCTL_SETPROTO 7
27#define ACT2000_IOCTL_GETPROTO 8
28#define ACT2000_IOCTL_SETMSN 9
29#define ACT2000_IOCTL_GETMSN 10
30#define ACT2000_IOCTL_LOADBOOT 11
31#define ACT2000_IOCTL_ADDCARD 12
32
33#define ACT2000_IOCTL_TEST 98
34#define ACT2000_IOCTL_DEBUGVAR 99
35
36#define ACT2000_BUS_ISA 1
37#define ACT2000_BUS_MCA 2
38#define ACT2000_BUS_PCMCIA 3
39
40/* Struct for adding new cards */
41typedef struct act2000_cdef {
42 int bus;
43 int port;
44 int irq;
45 char id[10];
46} act2000_cdef;
47
48/* Struct for downloading firmware */
49typedef struct act2000_ddef {
50 int length; /* Length of code */
51 char __user *buffer; /* Ptr. to code */
52} act2000_ddef;
53
54typedef struct act2000_fwid {
55 char isdn[4];
56 char revlen[2];
57 char revision[504];
58} act2000_fwid;
59
60#if defined(__KERNEL__) || defined(__DEBUGVAR__)
61
62#ifdef __KERNEL__
63/* Kernel includes */
64
65#include <linux/sched.h>
66#include <linux/string.h>
67#include <linux/workqueue.h>
68#include <linux/interrupt.h>
69#include <linux/skbuff.h>
70#include <linux/errno.h>
71#include <linux/fs.h>
72#include <linux/major.h>
73#include <asm/io.h>
74#include <linux/kernel.h>
75#include <linux/signal.h>
76#include <linux/slab.h>
77#include <linux/mm.h>
78#include <linux/mman.h>
79#include <linux/ioport.h>
80#include <linux/timer.h>
81#include <linux/wait.h>
82#include <linux/delay.h>
83#include <linux/ctype.h>
84#include <linux/isdnif.h>
85
86#endif /* __KERNEL__ */
87
88#define ACT2000_PORTLEN 8
89
90#define ACT2000_FLAGS_RUNNING 1 /* Cards driver activated */
91#define ACT2000_FLAGS_PVALID 2 /* Cards port is valid */
92#define ACT2000_FLAGS_IVALID 4 /* Cards irq is valid */
93#define ACT2000_FLAGS_LOADED 8 /* Firmware loaded */
94
95#define ACT2000_BCH 2 /* # of channels per card */
96
97/* D-Channel states */
98#define ACT2000_STATE_NULL 0
99#define ACT2000_STATE_ICALL 1
100#define ACT2000_STATE_OCALL 2
101#define ACT2000_STATE_IWAIT 3
102#define ACT2000_STATE_OWAIT 4
103#define ACT2000_STATE_IBWAIT 5
104#define ACT2000_STATE_OBWAIT 6
105#define ACT2000_STATE_BWAIT 7
106#define ACT2000_STATE_BHWAIT 8
107#define ACT2000_STATE_BHWAIT2 9
108#define ACT2000_STATE_DHWAIT 10
109#define ACT2000_STATE_DHWAIT2 11
110#define ACT2000_STATE_BSETUP 12
111#define ACT2000_STATE_ACTIVE 13
112
113#define ACT2000_MAX_QUEUED 8000 /* 2 * maxbuff */
114
115#define ACT2000_LOCK_TX 0
116#define ACT2000_LOCK_RX 1
117
118typedef struct act2000_chan {
119 unsigned short callref; /* Call Reference */
120 unsigned short fsm_state; /* Current D-Channel state */
121 unsigned short eazmask; /* EAZ-Mask for this Channel */
122 short queued; /* User-Data Bytes in TX queue */
123 unsigned short plci;
124 unsigned short ncci;
125 unsigned char l2prot; /* Layer 2 protocol */
126 unsigned char l3prot; /* Layer 3 protocol */
127} act2000_chan;
128
129typedef struct msn_entry {
130 char eaz;
131 char msn[16];
132 struct msn_entry * next;
133} msn_entry;
134
135typedef struct irq_data_isa {
136 __u8 *rcvptr;
137 __u16 rcvidx;
138 __u16 rcvlen;
139 struct sk_buff *rcvskb;
140 __u8 rcvignore;
141 __u8 rcvhdr[8];
142} irq_data_isa;
143
144typedef union irq_data {
145 irq_data_isa isa;
146} irq_data;
147
148/*
149 * Per card driver data
150 */
151typedef struct act2000_card {
152 unsigned short port; /* Base-port-address */
153 unsigned short irq; /* Interrupt */
154 u_char ptype; /* Protocol type (1TR6 or Euro) */
155 u_char bus; /* Cardtype (ISA, MCA, PCMCIA) */
156 struct act2000_card *next; /* Pointer to next device struct */
157 spinlock_t lock; /* protect critical operations */
158 int myid; /* Driver-Nr. assigned by linklevel */
159 unsigned long flags; /* Statusflags */
160 unsigned long ilock; /* Semaphores for IRQ-Routines */
161 struct sk_buff_head rcvq; /* Receive-Message queue */
162 struct sk_buff_head sndq; /* Send-Message queue */
163 struct sk_buff_head ackq; /* Data-Ack-Message queue */
164 u_char *ack_msg; /* Ptr to User Data in User skb */
165 __u16 need_b3ack; /* Flag: Need ACK for current skb */
166 struct sk_buff *sbuf; /* skb which is currently sent */
167 struct timer_list ptimer; /* Poll timer */
168 struct work_struct snd_tq; /* Task struct for xmit bh */
169 struct work_struct rcv_tq; /* Task struct for rcv bh */
170 struct work_struct poll_tq; /* Task struct for polled rcv bh */
171 msn_entry *msn_list;
172 unsigned short msgnum; /* Message number for sending */
173 spinlock_t mnlock; /* lock for msgnum */
174 act2000_chan bch[ACT2000_BCH]; /* B-Channel status/control */
175 char status_buf[256]; /* Buffer for status messages */
176 char *status_buf_read;
177 char *status_buf_write;
178 char *status_buf_end;
179 irq_data idat; /* Data used for IRQ handler */
180 isdn_if interface; /* Interface to upper layer */
181 char regname[35]; /* Name used for request_region */
182} act2000_card;
183
184extern __inline__ void act2000_schedule_tx(act2000_card *card)
185{
186 schedule_work(&card->snd_tq);
187}
188
189extern __inline__ void act2000_schedule_rx(act2000_card *card)
190{
191 schedule_work(&card->rcv_tq);
192}
193
194extern __inline__ void act2000_schedule_poll(act2000_card *card)
195{
196 schedule_work(&card->poll_tq);
197}
198
199extern char *act2000_find_eaz(act2000_card *, char);
200
201#endif /* defined(__KERNEL__) || defined(__DEBUGVAR__) */
202#endif /* act2000_h */
diff --git a/drivers/isdn/act2000/act2000_isa.c b/drivers/isdn/act2000/act2000_isa.c
new file mode 100644
index 000000000000..bc98d77c5ecd
--- /dev/null
+++ b/drivers/isdn/act2000/act2000_isa.c
@@ -0,0 +1,449 @@
1/* $Id: act2000_isa.c,v 1.11.6.3 2001/09/23 22:24:32 kai Exp $
2 *
3 * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000 (ISA-Version).
4 *
5 * Author Fritz Elfert
6 * Copyright by Fritz Elfert <fritz@isdn4linux.de>
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 * Thanks to Friedemann Baitinger and IBM Germany
12 *
13 */
14
15#include "act2000.h"
16#include "act2000_isa.h"
17#include "capi.h"
18
19static act2000_card *irq2card_map[16];
20
21/*
22 * Reset Controller, then try to read the Card's signature.
23 + Return:
24 * 1 = Signature found.
25 * 0 = Signature not found.
26 */
27static int
28act2000_isa_reset(unsigned short portbase)
29{
30 unsigned char reg;
31 int i;
32 int found;
33 int serial = 0;
34
35 found = 0;
36 if ((reg = inb(portbase + ISA_COR)) != 0xff) {
37 outb(reg | ISA_COR_RESET, portbase + ISA_COR);
38 mdelay(10);
39 outb(reg, portbase + ISA_COR);
40 mdelay(10);
41
42 for (i = 0; i < 16; i++) {
43 if (inb(portbase + ISA_ISR) & ISA_ISR_SERIAL)
44 serial |= 0x10000;
45 serial >>= 1;
46 }
47 if (serial == ISA_SER_ID)
48 found++;
49 }
50 return found;
51}
52
53int
54act2000_isa_detect(unsigned short portbase)
55{
56 int ret = 0;
57
58 if (request_region(portbase, ACT2000_PORTLEN, "act2000isa")) {
59 ret = act2000_isa_reset(portbase);
60 release_region(portbase, ISA_REGION);
61 }
62 return ret;
63}
64
65static irqreturn_t
66act2000_isa_interrupt(int irq, void *dev_id, struct pt_regs *regs)
67{
68 act2000_card *card = irq2card_map[irq];
69 u_char istatus;
70
71 if (!card) {
72 printk(KERN_WARNING
73 "act2000: Spurious interrupt!\n");
74 return IRQ_NONE;
75 }
76 istatus = (inb(ISA_PORT_ISR) & 0x07);
77 if (istatus & ISA_ISR_OUT) {
78 /* RX fifo has data */
79 istatus &= ISA_ISR_OUT_MASK;
80 outb(0, ISA_PORT_SIS);
81 act2000_isa_receive(card);
82 outb(ISA_SIS_INT, ISA_PORT_SIS);
83 }
84 if (istatus & ISA_ISR_ERR) {
85 /* Error Interrupt */
86 istatus &= ISA_ISR_ERR_MASK;
87 printk(KERN_WARNING "act2000: errIRQ\n");
88 }
89 if (istatus)
90 printk(KERN_DEBUG "act2000: ?IRQ %d %02x\n", irq, istatus);
91 return IRQ_HANDLED;
92}
93
94static void
95act2000_isa_select_irq(act2000_card * card)
96{
97 unsigned char reg;
98
99 reg = (inb(ISA_PORT_COR) & ~ISA_COR_IRQOFF) | ISA_COR_PERR;
100 switch (card->irq) {
101 case 3:
102 reg = ISA_COR_IRQ03;
103 break;
104 case 5:
105 reg = ISA_COR_IRQ05;
106 break;
107 case 7:
108 reg = ISA_COR_IRQ07;
109 break;
110 case 10:
111 reg = ISA_COR_IRQ10;
112 break;
113 case 11:
114 reg = ISA_COR_IRQ11;
115 break;
116 case 12:
117 reg = ISA_COR_IRQ12;
118 break;
119 case 15:
120 reg = ISA_COR_IRQ15;
121 break;
122 }
123 outb(reg, ISA_PORT_COR);
124}
125
126static void
127act2000_isa_enable_irq(act2000_card * card)
128{
129 act2000_isa_select_irq(card);
130 /* Enable READ irq */
131 outb(ISA_SIS_INT, ISA_PORT_SIS);
132}
133
134/*
135 * Install interrupt handler, enable irq on card.
136 * If irq is -1, choose next free irq, else irq is given explicitely.
137 */
138int
139act2000_isa_config_irq(act2000_card * card, short irq)
140{
141 if (card->flags & ACT2000_FLAGS_IVALID) {
142 free_irq(card->irq, NULL);
143 irq2card_map[card->irq] = NULL;
144 }
145 card->flags &= ~ACT2000_FLAGS_IVALID;
146 outb(ISA_COR_IRQOFF, ISA_PORT_COR);
147 if (!irq)
148 return 0;
149
150 if (!request_irq(irq, &act2000_isa_interrupt, 0, card->regname, NULL)) {
151 card->irq = irq;
152 irq2card_map[card->irq] = card;
153 card->flags |= ACT2000_FLAGS_IVALID;
154 printk(KERN_WARNING
155 "act2000: Could not request irq %d\n",irq);
156 return -EBUSY;
157 } else {
158 act2000_isa_select_irq(card);
159 /* Disable READ and WRITE irq */
160 outb(0, ISA_PORT_SIS);
161 outb(0, ISA_PORT_SOS);
162 }
163 return 0;
164}
165
166int
167act2000_isa_config_port(act2000_card * card, unsigned short portbase)
168{
169 if (card->flags & ACT2000_FLAGS_PVALID) {
170 release_region(card->port, ISA_REGION);
171 card->flags &= ~ACT2000_FLAGS_PVALID;
172 }
173 if (request_region(portbase, ACT2000_PORTLEN, card->regname) == NULL)
174 return -EBUSY;
175 else {
176 card->port = portbase;
177 card->flags |= ACT2000_FLAGS_PVALID;
178 return 0;
179 }
180}
181
182/*
183 * Release ressources, used by an adaptor.
184 */
185void
186act2000_isa_release(act2000_card * card)
187{
188 unsigned long flags;
189
190 spin_lock_irqsave(&card->lock, flags);
191 if (card->flags & ACT2000_FLAGS_IVALID) {
192 free_irq(card->irq, NULL);
193 irq2card_map[card->irq] = NULL;
194 }
195 card->flags &= ~ACT2000_FLAGS_IVALID;
196 if (card->flags & ACT2000_FLAGS_PVALID)
197 release_region(card->port, ISA_REGION);
198 card->flags &= ~ACT2000_FLAGS_PVALID;
199 spin_unlock_irqrestore(&card->lock, flags);
200}
201
202static int
203act2000_isa_writeb(act2000_card * card, u_char data)
204{
205 u_char timeout = 40;
206
207 while (timeout) {
208 if (inb(ISA_PORT_SOS) & ISA_SOS_READY) {
209 outb(data, ISA_PORT_SDO);
210 return 0;
211 } else {
212 timeout--;
213 udelay(10);
214 }
215 }
216 return 1;
217}
218
219static int
220act2000_isa_readb(act2000_card * card, u_char * data)
221{
222 u_char timeout = 40;
223
224 while (timeout) {
225 if (inb(ISA_PORT_SIS) & ISA_SIS_READY) {
226 *data = inb(ISA_PORT_SDI);
227 return 0;
228 } else {
229 timeout--;
230 udelay(10);
231 }
232 }
233 return 1;
234}
235
236void
237act2000_isa_receive(act2000_card *card)
238{
239 u_char c;
240
241 if (test_and_set_bit(ACT2000_LOCK_RX, (void *) &card->ilock) != 0)
242 return;
243 while (!act2000_isa_readb(card, &c)) {
244 if (card->idat.isa.rcvidx < 8) {
245 card->idat.isa.rcvhdr[card->idat.isa.rcvidx++] = c;
246 if (card->idat.isa.rcvidx == 8) {
247 int valid = actcapi_chkhdr(card, (actcapi_msghdr *)&card->idat.isa.rcvhdr);
248
249 if (valid) {
250 card->idat.isa.rcvlen = ((actcapi_msghdr *)&card->idat.isa.rcvhdr)->len;
251 card->idat.isa.rcvskb = dev_alloc_skb(card->idat.isa.rcvlen);
252 if (card->idat.isa.rcvskb == NULL) {
253 card->idat.isa.rcvignore = 1;
254 printk(KERN_WARNING
255 "act2000_isa_receive: no memory\n");
256 test_and_clear_bit(ACT2000_LOCK_RX, (void *) &card->ilock);
257 return;
258 }
259 memcpy(skb_put(card->idat.isa.rcvskb, 8), card->idat.isa.rcvhdr, 8);
260 card->idat.isa.rcvptr = skb_put(card->idat.isa.rcvskb, card->idat.isa.rcvlen - 8);
261 } else {
262 card->idat.isa.rcvidx = 0;
263 printk(KERN_WARNING
264 "act2000_isa_receive: Invalid CAPI msg\n");
265 {
266 int i; __u8 *p; __u8 *c; __u8 tmp[30];
267 for (i = 0, p = (__u8 *)&card->idat.isa.rcvhdr, c = tmp; i < 8; i++)
268 c += sprintf(c, "%02x ", *(p++));
269 printk(KERN_WARNING "act2000_isa_receive: %s\n", tmp);
270 }
271 }
272 }
273 } else {
274 if (!card->idat.isa.rcvignore)
275 *card->idat.isa.rcvptr++ = c;
276 if (++card->idat.isa.rcvidx >= card->idat.isa.rcvlen) {
277 if (!card->idat.isa.rcvignore) {
278 skb_queue_tail(&card->rcvq, card->idat.isa.rcvskb);
279 act2000_schedule_rx(card);
280 }
281 card->idat.isa.rcvidx = 0;
282 card->idat.isa.rcvlen = 8;
283 card->idat.isa.rcvignore = 0;
284 card->idat.isa.rcvskb = NULL;
285 card->idat.isa.rcvptr = card->idat.isa.rcvhdr;
286 }
287 }
288 }
289 if (!(card->flags & ACT2000_FLAGS_IVALID)) {
290 /* In polling mode, schedule myself */
291 if ((card->idat.isa.rcvidx) &&
292 (card->idat.isa.rcvignore ||
293 (card->idat.isa.rcvidx < card->idat.isa.rcvlen)))
294 act2000_schedule_poll(card);
295 }
296 test_and_clear_bit(ACT2000_LOCK_RX, (void *) &card->ilock);
297}
298
299void
300act2000_isa_send(act2000_card * card)
301{
302 unsigned long flags;
303 struct sk_buff *skb;
304 actcapi_msg *msg;
305 int l;
306
307 if (test_and_set_bit(ACT2000_LOCK_TX, (void *) &card->ilock) != 0)
308 return;
309 while (1) {
310 spin_lock_irqsave(&card->lock, flags);
311 if (!(card->sbuf)) {
312 if ((card->sbuf = skb_dequeue(&card->sndq))) {
313 card->ack_msg = card->sbuf->data;
314 msg = (actcapi_msg *)card->sbuf->data;
315 if ((msg->hdr.cmd.cmd == 0x86) &&
316 (msg->hdr.cmd.subcmd == 0) ) {
317 /* Save flags in message */
318 card->need_b3ack = msg->msg.data_b3_req.flags;
319 msg->msg.data_b3_req.flags = 0;
320 }
321 }
322 }
323 spin_unlock_irqrestore(&card->lock, flags);
324 if (!(card->sbuf)) {
325 /* No more data to send */
326 test_and_clear_bit(ACT2000_LOCK_TX, (void *) &card->ilock);
327 return;
328 }
329 skb = card->sbuf;
330 l = 0;
331 while (skb->len) {
332 if (act2000_isa_writeb(card, *(skb->data))) {
333 /* Fifo is full, but more data to send */
334 test_and_clear_bit(ACT2000_LOCK_TX, (void *) &card->ilock);
335 /* Schedule myself */
336 act2000_schedule_tx(card);
337 return;
338 }
339 skb_pull(skb, 1);
340 l++;
341 }
342 msg = (actcapi_msg *)card->ack_msg;
343 if ((msg->hdr.cmd.cmd == 0x86) &&
344 (msg->hdr.cmd.subcmd == 0) ) {
345 /*
346 * If it's user data, reset data-ptr
347 * and put skb into ackq.
348 */
349 skb->data = card->ack_msg;
350 /* Restore flags in message */
351 msg->msg.data_b3_req.flags = card->need_b3ack;
352 skb_queue_tail(&card->ackq, skb);
353 } else
354 dev_kfree_skb(skb);
355 card->sbuf = NULL;
356 }
357}
358
359/*
360 * Get firmware ID, check for 'ISDN' signature.
361 */
362static int
363act2000_isa_getid(act2000_card * card)
364{
365
366 act2000_fwid fid;
367 u_char *p = (u_char *) & fid;
368 int count = 0;
369
370 while (1) {
371 if (count > 510)
372 return -EPROTO;
373 if (act2000_isa_readb(card, p++))
374 break;
375 count++;
376 }
377 if (count <= 20) {
378 printk(KERN_WARNING "act2000: No Firmware-ID!\n");
379 return -ETIME;
380 }
381 *p = '\0';
382 fid.revlen[0] = '\0';
383 if (strcmp(fid.isdn, "ISDN")) {
384 printk(KERN_WARNING "act2000: Wrong Firmware-ID!\n");
385 return -EPROTO;
386 }
387 if ((p = strchr(fid.revision, '\n')))
388 *p = '\0';
389 printk(KERN_INFO "act2000: Firmware-ID: %s\n", fid.revision);
390 if (card->flags & ACT2000_FLAGS_IVALID) {
391 printk(KERN_DEBUG "Enabling Interrupts ...\n");
392 act2000_isa_enable_irq(card);
393 }
394 return 0;
395}
396
397/*
398 * Download microcode into card, check Firmware signature.
399 */
400int
401act2000_isa_download(act2000_card * card, act2000_ddef __user * cb)
402{
403 unsigned int length;
404 int l;
405 int c;
406 long timeout;
407 u_char *b;
408 u_char __user *p;
409 u_char *buf;
410 act2000_ddef cblock;
411
412 if (!act2000_isa_reset(card->port))
413 return -ENXIO;
414 msleep_interruptible(500);
415 if (copy_from_user(&cblock, cb, sizeof(cblock)))
416 return -EFAULT;
417 length = cblock.length;
418 p = cblock.buffer;
419 if (!access_ok(VERIFY_READ, p, length))
420 return -EFAULT;
421 buf = (u_char *) kmalloc(1024, GFP_KERNEL);
422 if (!buf)
423 return -ENOMEM;
424 timeout = 0;
425 while (length) {
426 l = (length > 1024) ? 1024 : length;
427 c = 0;
428 b = buf;
429 if (copy_from_user(buf, p, l)) {
430 kfree(buf);
431 return -EFAULT;
432 }
433 while (c < l) {
434 if (act2000_isa_writeb(card, *b++)) {
435 printk(KERN_WARNING
436 "act2000: loader timed out"
437 " len=%d c=%d\n", length, c);
438 kfree(buf);
439 return -ETIME;
440 }
441 c++;
442 }
443 length -= l;
444 p += l;
445 }
446 kfree(buf);
447 msleep_interruptible(500);
448 return (act2000_isa_getid(card));
449}
diff --git a/drivers/isdn/act2000/act2000_isa.h b/drivers/isdn/act2000/act2000_isa.h
new file mode 100644
index 000000000000..ad86c5ed9aad
--- /dev/null
+++ b/drivers/isdn/act2000/act2000_isa.h
@@ -0,0 +1,136 @@
1/* $Id: act2000_isa.h,v 1.4.6.1 2001/09/23 22:24:32 kai Exp $
2 *
3 * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000 (ISA-Version).
4 *
5 * Author Fritz Elfert
6 * Copyright by Fritz Elfert <fritz@isdn4linux.de>
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 * Thanks to Friedemann Baitinger and IBM Germany
12 *
13 */
14
15#ifndef act2000_isa_h
16#define act2000_isa_h
17
18#define ISA_POLL_LOOP 40 /* Try to read-write before give up */
19
20typedef enum {
21 INT_NO_CHANGE = 0, /* Do not change the Mask */
22 INT_ON = 1, /* Set to Enable */
23 INT_OFF = 2, /* Set to Disable */
24} ISA_INT_T;
25
26/**************************************************************************/
27/* Configuration Register COR (RW) */
28/**************************************************************************/
29/* 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 */
30/* Soft Res| IRQM | IRQ Select | N/A | WAIT |Proc err */
31/**************************************************************************/
32#define ISA_COR 0 /* Offset for ISA config register */
33#define ISA_COR_PERR 0x01 /* Processor Error Enabled */
34#define ISA_COR_WS 0x02 /* Insert Wait State if 1 */
35#define ISA_COR_IRQOFF 0x38 /* No Interrupt */
36#define ISA_COR_IRQ07 0x30 /* IRQ 7 Enable */
37#define ISA_COR_IRQ05 0x28 /* IRQ 5 Enable */
38#define ISA_COR_IRQ03 0x20 /* IRQ 3 Enable */
39#define ISA_COR_IRQ10 0x18 /* IRQ 10 Enable */
40#define ISA_COR_IRQ11 0x10 /* IRQ 11 Enable */
41#define ISA_COR_IRQ12 0x08 /* IRQ 12 Enable */
42#define ISA_COR_IRQ15 0x00 /* IRQ 15 Enable */
43#define ISA_COR_IRQPULSE 0x40 /* 0 = Level 1 = Pulse Interrupt */
44#define ISA_COR_RESET 0x80 /* Soft Reset for Transputer */
45
46/**************************************************************************/
47/* Interrupt Source Register ISR (RO) */
48/**************************************************************************/
49/* 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 */
50/* N/A | N/A | N/A |Err sig |Ser ID |IN Intr |Out Intr| Error */
51/**************************************************************************/
52#define ISA_ISR 1 /* Offset for Interrupt Register */
53#define ISA_ISR_ERR 0x01 /* Error Interrupt */
54#define ISA_ISR_OUT 0x02 /* Output Interrupt */
55#define ISA_ISR_INP 0x04 /* Input Interrupt */
56#define ISA_ISR_SERIAL 0x08 /* Read out Serial ID after Reset */
57#define ISA_ISR_ERRSIG 0x10 /* Error Signal Input */
58#define ISA_ISR_ERR_MASK 0xfe /* Mask Error Interrupt */
59#define ISA_ISR_OUT_MASK 0xfd /* Mask Output Interrupt */
60#define ISA_ISR_INP_MASK 0xfb /* Mask Input Interrupt */
61
62/* Signature delivered after Reset at ISA_ISR_SERIAL (LSB first) */
63#define ISA_SER_ID 0x0201 /* ID for ISA Card */
64
65/**************************************************************************/
66/* EEPROM Register EPR (RW) */
67/**************************************************************************/
68/* 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 */
69/* N/A | N/A | N/A |ROM Hold| ROM CS |ROM CLK | ROM IN |ROM Out */
70/**************************************************************************/
71#define ISA_EPR 2 /* Offset for this Register */
72#define ISA_EPR_OUT 0x01 /* Rome Register Out (RO) */
73#define ISA_EPR_IN 0x02 /* Rom Register In (WR) */
74#define ISA_EPR_CLK 0x04 /* Rom Clock (WR) */
75#define ISA_EPR_CS 0x08 /* Rom Cip Select (WR) */
76#define ISA_EPR_HOLD 0x10 /* Rom Hold Signal (WR) */
77
78/**************************************************************************/
79/* EEPROM enable Register EER (unused) */
80/**************************************************************************/
81#define ISA_EER 3 /* Offset for this Register */
82
83/**************************************************************************/
84/* SLC Data Input SDI (RO) */
85/**************************************************************************/
86#define ISA_SDI 4 /* Offset for this Register */
87
88/**************************************************************************/
89/* SLC Data Output SDO (WO) */
90/**************************************************************************/
91#define ISA_SDO 5 /* Offset for this Register */
92
93/**************************************************************************/
94/* IMS C011 Mode 2 Input Status Register for INMOS CPU SIS (RW) */
95/**************************************************************************/
96/* 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 */
97/* N/A | N/A | N/A | N/A | N/A | N/A |Int Ena |Data Pre */
98/**************************************************************************/
99#define ISA_SIS 6 /* Offset for this Register */
100#define ISA_SIS_READY 0x01 /* If 1 : data is available */
101#define ISA_SIS_INT 0x02 /* Enable Interrupt for READ */
102
103/**************************************************************************/
104/* IMS C011 Mode 2 Output Status Register from INMOS CPU SOS (RW) */
105/**************************************************************************/
106/* 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 */
107/* N/A | N/A | N/A | N/A | N/A | N/A |Int Ena |Out Rdy */
108/**************************************************************************/
109#define ISA_SOS 7 /* Offset for this Register */
110#define ISA_SOS_READY 0x01 /* If 1 : we can write Data */
111#define ISA_SOS_INT 0x02 /* Enable Interrupt for WRITE */
112
113#define ISA_REGION 8 /* Number of Registers */
114
115
116/* Macros for accessing ports */
117#define ISA_PORT_COR (card->port+ISA_COR)
118#define ISA_PORT_ISR (card->port+ISA_ISR)
119#define ISA_PORT_EPR (card->port+ISA_EPR)
120#define ISA_PORT_EER (card->port+ISA_EER)
121#define ISA_PORT_SDI (card->port+ISA_SDI)
122#define ISA_PORT_SDO (card->port+ISA_SDO)
123#define ISA_PORT_SIS (card->port+ISA_SIS)
124#define ISA_PORT_SOS (card->port+ISA_SOS)
125
126/* Prototypes */
127
128extern int act2000_isa_detect(unsigned short portbase);
129extern int act2000_isa_config_irq(act2000_card * card, short irq);
130extern int act2000_isa_config_port(act2000_card * card, unsigned short portbase);
131extern int act2000_isa_download(act2000_card * card, act2000_ddef __user * cb);
132extern void act2000_isa_release(act2000_card * card);
133extern void act2000_isa_receive(act2000_card *card);
134extern void act2000_isa_send(act2000_card *card);
135
136#endif /* act2000_isa_h */
diff --git a/drivers/isdn/act2000/capi.c b/drivers/isdn/act2000/capi.c
new file mode 100644
index 000000000000..40395f567231
--- /dev/null
+++ b/drivers/isdn/act2000/capi.c
@@ -0,0 +1,1177 @@
1/* $Id: capi.c,v 1.9.6.2 2001/09/23 22:24:32 kai Exp $
2 *
3 * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000.
4 * CAPI encoder/decoder
5 *
6 * Author Fritz Elfert
7 * Copyright by Fritz Elfert <fritz@isdn4linux.de>
8 *
9 * This software may be used and distributed according to the terms
10 * of the GNU General Public License, incorporated herein by reference.
11 *
12 * Thanks to Friedemann Baitinger and IBM Germany
13 *
14 */
15
16#include "act2000.h"
17#include "capi.h"
18
19static actcapi_msgdsc valid_msg[] = {
20 {{ 0x86, 0x02}, "DATA_B3_IND"}, /* DATA_B3_IND/CONF must be first because of speed!!! */
21 {{ 0x86, 0x01}, "DATA_B3_CONF"},
22 {{ 0x02, 0x01}, "CONNECT_CONF"},
23 {{ 0x02, 0x02}, "CONNECT_IND"},
24 {{ 0x09, 0x01}, "CONNECT_INFO_CONF"},
25 {{ 0x03, 0x02}, "CONNECT_ACTIVE_IND"},
26 {{ 0x04, 0x01}, "DISCONNECT_CONF"},
27 {{ 0x04, 0x02}, "DISCONNECT_IND"},
28 {{ 0x05, 0x01}, "LISTEN_CONF"},
29 {{ 0x06, 0x01}, "GET_PARAMS_CONF"},
30 {{ 0x07, 0x01}, "INFO_CONF"},
31 {{ 0x07, 0x02}, "INFO_IND"},
32 {{ 0x08, 0x01}, "DATA_CONF"},
33 {{ 0x08, 0x02}, "DATA_IND"},
34 {{ 0x40, 0x01}, "SELECT_B2_PROTOCOL_CONF"},
35 {{ 0x80, 0x01}, "SELECT_B3_PROTOCOL_CONF"},
36 {{ 0x81, 0x01}, "LISTEN_B3_CONF"},
37 {{ 0x82, 0x01}, "CONNECT_B3_CONF"},
38 {{ 0x82, 0x02}, "CONNECT_B3_IND"},
39 {{ 0x83, 0x02}, "CONNECT_B3_ACTIVE_IND"},
40 {{ 0x84, 0x01}, "DISCONNECT_B3_CONF"},
41 {{ 0x84, 0x02}, "DISCONNECT_B3_IND"},
42 {{ 0x85, 0x01}, "GET_B3_PARAMS_CONF"},
43 {{ 0x01, 0x01}, "RESET_B3_CONF"},
44 {{ 0x01, 0x02}, "RESET_B3_IND"},
45 /* {{ 0x87, 0x02, "HANDSET_IND"}, not implemented */
46 {{ 0xff, 0x01}, "MANUFACTURER_CONF"},
47 {{ 0xff, 0x02}, "MANUFACTURER_IND"},
48#ifdef DEBUG_MSG
49 /* Requests */
50 {{ 0x01, 0x00}, "RESET_B3_REQ"},
51 {{ 0x02, 0x00}, "CONNECT_REQ"},
52 {{ 0x04, 0x00}, "DISCONNECT_REQ"},
53 {{ 0x05, 0x00}, "LISTEN_REQ"},
54 {{ 0x06, 0x00}, "GET_PARAMS_REQ"},
55 {{ 0x07, 0x00}, "INFO_REQ"},
56 {{ 0x08, 0x00}, "DATA_REQ"},
57 {{ 0x09, 0x00}, "CONNECT_INFO_REQ"},
58 {{ 0x40, 0x00}, "SELECT_B2_PROTOCOL_REQ"},
59 {{ 0x80, 0x00}, "SELECT_B3_PROTOCOL_REQ"},
60 {{ 0x81, 0x00}, "LISTEN_B3_REQ"},
61 {{ 0x82, 0x00}, "CONNECT_B3_REQ"},
62 {{ 0x84, 0x00}, "DISCONNECT_B3_REQ"},
63 {{ 0x85, 0x00}, "GET_B3_PARAMS_REQ"},
64 {{ 0x86, 0x00}, "DATA_B3_REQ"},
65 {{ 0xff, 0x00}, "MANUFACTURER_REQ"},
66 /* Responses */
67 {{ 0x01, 0x03}, "RESET_B3_RESP"},
68 {{ 0x02, 0x03}, "CONNECT_RESP"},
69 {{ 0x03, 0x03}, "CONNECT_ACTIVE_RESP"},
70 {{ 0x04, 0x03}, "DISCONNECT_RESP"},
71 {{ 0x07, 0x03}, "INFO_RESP"},
72 {{ 0x08, 0x03}, "DATA_RESP"},
73 {{ 0x82, 0x03}, "CONNECT_B3_RESP"},
74 {{ 0x83, 0x03}, "CONNECT_B3_ACTIVE_RESP"},
75 {{ 0x84, 0x03}, "DISCONNECT_B3_RESP"},
76 {{ 0x86, 0x03}, "DATA_B3_RESP"},
77 {{ 0xff, 0x03}, "MANUFACTURER_RESP"},
78#endif
79 {{ 0x00, 0x00}, NULL},
80};
81#define num_valid_msg (sizeof(valid_msg)/sizeof(actcapi_msgdsc))
82#define num_valid_imsg 27 /* MANUFACTURER_IND */
83
84/*
85 * Check for a valid incoming CAPI message.
86 * Return:
87 * 0 = Invalid message
88 * 1 = Valid message, no B-Channel-data
89 * 2 = Valid message, B-Channel-data
90 */
91int
92actcapi_chkhdr(act2000_card * card, actcapi_msghdr *hdr)
93{
94 int i;
95
96 if (hdr->applicationID != 1)
97 return 0;
98 if (hdr->len < 9)
99 return 0;
100 for (i = 0; i < num_valid_imsg; i++)
101 if ((hdr->cmd.cmd == valid_msg[i].cmd.cmd) &&
102 (hdr->cmd.subcmd == valid_msg[i].cmd.subcmd)) {
103 return (i?1:2);
104 }
105 return 0;
106}
107
108#define ACTCAPI_MKHDR(l, c, s) { \
109 skb = alloc_skb(l + 8, GFP_ATOMIC); \
110 if (skb) { \
111 m = (actcapi_msg *)skb_put(skb, l + 8); \
112 m->hdr.len = l + 8; \
113 m->hdr.applicationID = 1; \
114 m->hdr.cmd.cmd = c; \
115 m->hdr.cmd.subcmd = s; \
116 m->hdr.msgnum = actcapi_nextsmsg(card); \
117 } else m = NULL;\
118}
119
120#define ACTCAPI_CHKSKB if (!skb) { \
121 printk(KERN_WARNING "actcapi: alloc_skb failed\n"); \
122 return; \
123}
124
125#define ACTCAPI_QUEUE_TX { \
126 actcapi_debug_msg(skb, 1); \
127 skb_queue_tail(&card->sndq, skb); \
128 act2000_schedule_tx(card); \
129}
130
131int
132actcapi_listen_req(act2000_card *card)
133{
134 __u16 eazmask = 0;
135 int i;
136 actcapi_msg *m;
137 struct sk_buff *skb;
138
139 for (i = 0; i < ACT2000_BCH; i++)
140 eazmask |= card->bch[i].eazmask;
141 ACTCAPI_MKHDR(9, 0x05, 0x00);
142 if (!skb) {
143 printk(KERN_WARNING "actcapi: alloc_skb failed\n");
144 return -ENOMEM;
145 }
146 m->msg.listen_req.controller = 0;
147 m->msg.listen_req.infomask = 0x3f; /* All information */
148 m->msg.listen_req.eazmask = eazmask;
149 m->msg.listen_req.simask = (eazmask)?0x86:0; /* All SI's */
150 ACTCAPI_QUEUE_TX;
151 return 0;
152}
153
154int
155actcapi_connect_req(act2000_card *card, act2000_chan *chan, char *phone,
156 char eaz, int si1, int si2)
157{
158 actcapi_msg *m;
159 struct sk_buff *skb;
160
161 ACTCAPI_MKHDR((11 + strlen(phone)), 0x02, 0x00);
162 if (!skb) {
163 printk(KERN_WARNING "actcapi: alloc_skb failed\n");
164 chan->fsm_state = ACT2000_STATE_NULL;
165 return -ENOMEM;
166 }
167 m->msg.connect_req.controller = 0;
168 m->msg.connect_req.bchan = 0x83;
169 m->msg.connect_req.infomask = 0x3f;
170 m->msg.connect_req.si1 = si1;
171 m->msg.connect_req.si2 = si2;
172 m->msg.connect_req.eaz = eaz?eaz:'0';
173 m->msg.connect_req.addr.len = strlen(phone) + 1;
174 m->msg.connect_req.addr.tnp = 0x81;
175 memcpy(m->msg.connect_req.addr.num, phone, strlen(phone));
176 chan->callref = m->hdr.msgnum;
177 ACTCAPI_QUEUE_TX;
178 return 0;
179}
180
181static void
182actcapi_connect_b3_req(act2000_card *card, act2000_chan *chan)
183{
184 actcapi_msg *m;
185 struct sk_buff *skb;
186
187 ACTCAPI_MKHDR(17, 0x82, 0x00);
188 ACTCAPI_CHKSKB;
189 m->msg.connect_b3_req.plci = chan->plci;
190 memset(&m->msg.connect_b3_req.ncpi, 0,
191 sizeof(m->msg.connect_b3_req.ncpi));
192 m->msg.connect_b3_req.ncpi.len = 13;
193 m->msg.connect_b3_req.ncpi.modulo = 8;
194 ACTCAPI_QUEUE_TX;
195}
196
197/*
198 * Set net type (1TR6) or (EDSS1)
199 */
200int
201actcapi_manufacturer_req_net(act2000_card *card)
202{
203 actcapi_msg *m;
204 struct sk_buff *skb;
205
206 ACTCAPI_MKHDR(5, 0xff, 0x00);
207 if (!skb) {
208 printk(KERN_WARNING "actcapi: alloc_skb failed\n");
209 return -ENOMEM;
210 }
211 m->msg.manufacturer_req_net.manuf_msg = 0x11;
212 m->msg.manufacturer_req_net.controller = 1;
213 m->msg.manufacturer_req_net.nettype = (card->ptype == ISDN_PTYPE_EURO)?1:0;
214 ACTCAPI_QUEUE_TX;
215 printk(KERN_INFO "act2000 %s: D-channel protocol now %s\n",
216 card->interface.id, (card->ptype == ISDN_PTYPE_EURO)?"euro":"1tr6");
217 card->interface.features &=
218 ~(ISDN_FEATURE_P_UNKNOWN | ISDN_FEATURE_P_EURO | ISDN_FEATURE_P_1TR6);
219 card->interface.features |=
220 ((card->ptype == ISDN_PTYPE_EURO)?ISDN_FEATURE_P_EURO:ISDN_FEATURE_P_1TR6);
221 return 0;
222}
223
224/*
225 * Switch V.42 on or off
226 */
227int
228actcapi_manufacturer_req_v42(act2000_card *card, ulong arg)
229{
230 actcapi_msg *m;
231 struct sk_buff *skb;
232
233 ACTCAPI_MKHDR(8, 0xff, 0x00);
234 if (!skb) {
235
236 printk(KERN_WARNING "actcapi: alloc_skb failed\n");
237 return -ENOMEM;
238 }
239 m->msg.manufacturer_req_v42.manuf_msg = 0x10;
240 m->msg.manufacturer_req_v42.controller = 0;
241 m->msg.manufacturer_req_v42.v42control = (arg?1:0);
242 ACTCAPI_QUEUE_TX;
243 return 0;
244}
245
246/*
247 * Set error-handler
248 */
249int
250actcapi_manufacturer_req_errh(act2000_card *card)
251{
252 actcapi_msg *m;
253 struct sk_buff *skb;
254
255 ACTCAPI_MKHDR(4, 0xff, 0x00);
256 if (!skb) {
257
258 printk(KERN_WARNING "actcapi: alloc_skb failed\n");
259 return -ENOMEM;
260 }
261 m->msg.manufacturer_req_err.manuf_msg = 0x03;
262 m->msg.manufacturer_req_err.controller = 0;
263 ACTCAPI_QUEUE_TX;
264 return 0;
265}
266
267/*
268 * Set MSN-Mapping.
269 */
270int
271actcapi_manufacturer_req_msn(act2000_card *card)
272{
273 msn_entry *p = card->msn_list;
274 actcapi_msg *m;
275 struct sk_buff *skb;
276 int len;
277
278 while (p) {
279 int i;
280
281 len = strlen(p->msn);
282 for (i = 0; i < 2; i++) {
283 ACTCAPI_MKHDR(6 + len, 0xff, 0x00);
284 if (!skb) {
285 printk(KERN_WARNING "actcapi: alloc_skb failed\n");
286 return -ENOMEM;
287 }
288 m->msg.manufacturer_req_msn.manuf_msg = 0x13 + i;
289 m->msg.manufacturer_req_msn.controller = 0;
290 m->msg.manufacturer_req_msn.msnmap.eaz = p->eaz;
291 m->msg.manufacturer_req_msn.msnmap.len = len;
292 memcpy(m->msg.manufacturer_req_msn.msnmap.msn, p->msn, len);
293 ACTCAPI_QUEUE_TX;
294 }
295 p = p->next;
296 }
297 return 0;
298}
299
300void
301actcapi_select_b2_protocol_req(act2000_card *card, act2000_chan *chan)
302{
303 actcapi_msg *m;
304 struct sk_buff *skb;
305
306 ACTCAPI_MKHDR(10, 0x40, 0x00);
307 ACTCAPI_CHKSKB;
308 m->msg.select_b2_protocol_req.plci = chan->plci;
309 memset(&m->msg.select_b2_protocol_req.dlpd, 0,
310 sizeof(m->msg.select_b2_protocol_req.dlpd));
311 m->msg.select_b2_protocol_req.dlpd.len = 6;
312 switch (chan->l2prot) {
313 case ISDN_PROTO_L2_TRANS:
314 m->msg.select_b2_protocol_req.protocol = 0x03;
315 m->msg.select_b2_protocol_req.dlpd.dlen = 4000;
316 break;
317 case ISDN_PROTO_L2_HDLC:
318 m->msg.select_b2_protocol_req.protocol = 0x02;
319 m->msg.select_b2_protocol_req.dlpd.dlen = 4000;
320 break;
321 case ISDN_PROTO_L2_X75I:
322 case ISDN_PROTO_L2_X75UI:
323 case ISDN_PROTO_L2_X75BUI:
324 m->msg.select_b2_protocol_req.protocol = 0x01;
325 m->msg.select_b2_protocol_req.dlpd.dlen = 4000;
326 m->msg.select_b2_protocol_req.dlpd.laa = 3;
327 m->msg.select_b2_protocol_req.dlpd.lab = 1;
328 m->msg.select_b2_protocol_req.dlpd.win = 7;
329 m->msg.select_b2_protocol_req.dlpd.modulo = 8;
330 break;
331 }
332 ACTCAPI_QUEUE_TX;
333}
334
335static void
336actcapi_select_b3_protocol_req(act2000_card *card, act2000_chan *chan)
337{
338 actcapi_msg *m;
339 struct sk_buff *skb;
340
341 ACTCAPI_MKHDR(17, 0x80, 0x00);
342 ACTCAPI_CHKSKB;
343 m->msg.select_b3_protocol_req.plci = chan->plci;
344 memset(&m->msg.select_b3_protocol_req.ncpd, 0,
345 sizeof(m->msg.select_b3_protocol_req.ncpd));
346 switch (chan->l3prot) {
347 case ISDN_PROTO_L3_TRANS:
348 m->msg.select_b3_protocol_req.protocol = 0x04;
349 m->msg.select_b3_protocol_req.ncpd.len = 13;
350 m->msg.select_b3_protocol_req.ncpd.modulo = 8;
351 break;
352 }
353 ACTCAPI_QUEUE_TX;
354}
355
356static void
357actcapi_listen_b3_req(act2000_card *card, act2000_chan *chan)
358{
359 actcapi_msg *m;
360 struct sk_buff *skb;
361
362 ACTCAPI_MKHDR(2, 0x81, 0x00);
363 ACTCAPI_CHKSKB;
364 m->msg.listen_b3_req.plci = chan->plci;
365 ACTCAPI_QUEUE_TX;
366}
367
368static void
369actcapi_disconnect_req(act2000_card *card, act2000_chan *chan)
370{
371 actcapi_msg *m;
372 struct sk_buff *skb;
373
374 ACTCAPI_MKHDR(3, 0x04, 0x00);
375 ACTCAPI_CHKSKB;
376 m->msg.disconnect_req.plci = chan->plci;
377 m->msg.disconnect_req.cause = 0;
378 ACTCAPI_QUEUE_TX;
379}
380
381void
382actcapi_disconnect_b3_req(act2000_card *card, act2000_chan *chan)
383{
384 actcapi_msg *m;
385 struct sk_buff *skb;
386
387 ACTCAPI_MKHDR(17, 0x84, 0x00);
388 ACTCAPI_CHKSKB;
389 m->msg.disconnect_b3_req.ncci = chan->ncci;
390 memset(&m->msg.disconnect_b3_req.ncpi, 0,
391 sizeof(m->msg.disconnect_b3_req.ncpi));
392 m->msg.disconnect_b3_req.ncpi.len = 13;
393 m->msg.disconnect_b3_req.ncpi.modulo = 8;
394 chan->fsm_state = ACT2000_STATE_BHWAIT;
395 ACTCAPI_QUEUE_TX;
396}
397
398void
399actcapi_connect_resp(act2000_card *card, act2000_chan *chan, __u8 cause)
400{
401 actcapi_msg *m;
402 struct sk_buff *skb;
403
404 ACTCAPI_MKHDR(3, 0x02, 0x03);
405 ACTCAPI_CHKSKB;
406 m->msg.connect_resp.plci = chan->plci;
407 m->msg.connect_resp.rejectcause = cause;
408 if (cause) {
409 chan->fsm_state = ACT2000_STATE_NULL;
410 chan->plci = 0x8000;
411 } else
412 chan->fsm_state = ACT2000_STATE_IWAIT;
413 ACTCAPI_QUEUE_TX;
414}
415
416static void
417actcapi_connect_active_resp(act2000_card *card, act2000_chan *chan)
418{
419 actcapi_msg *m;
420 struct sk_buff *skb;
421
422 ACTCAPI_MKHDR(2, 0x03, 0x03);
423 ACTCAPI_CHKSKB;
424 m->msg.connect_resp.plci = chan->plci;
425 if (chan->fsm_state == ACT2000_STATE_IWAIT)
426 chan->fsm_state = ACT2000_STATE_IBWAIT;
427 ACTCAPI_QUEUE_TX;
428}
429
430static void
431actcapi_connect_b3_resp(act2000_card *card, act2000_chan *chan, __u8 rejectcause)
432{
433 actcapi_msg *m;
434 struct sk_buff *skb;
435
436 ACTCAPI_MKHDR((rejectcause?3:17), 0x82, 0x03);
437 ACTCAPI_CHKSKB;
438 m->msg.connect_b3_resp.ncci = chan->ncci;
439 m->msg.connect_b3_resp.rejectcause = rejectcause;
440 if (!rejectcause) {
441 memset(&m->msg.connect_b3_resp.ncpi, 0,
442 sizeof(m->msg.connect_b3_resp.ncpi));
443 m->msg.connect_b3_resp.ncpi.len = 13;
444 m->msg.connect_b3_resp.ncpi.modulo = 8;
445 chan->fsm_state = ACT2000_STATE_BWAIT;
446 }
447 ACTCAPI_QUEUE_TX;
448}
449
450static void
451actcapi_connect_b3_active_resp(act2000_card *card, act2000_chan *chan)
452{
453 actcapi_msg *m;
454 struct sk_buff *skb;
455
456 ACTCAPI_MKHDR(2, 0x83, 0x03);
457 ACTCAPI_CHKSKB;
458 m->msg.connect_b3_active_resp.ncci = chan->ncci;
459 chan->fsm_state = ACT2000_STATE_ACTIVE;
460 ACTCAPI_QUEUE_TX;
461}
462
463static void
464actcapi_info_resp(act2000_card *card, act2000_chan *chan)
465{
466 actcapi_msg *m;
467 struct sk_buff *skb;
468
469 ACTCAPI_MKHDR(2, 0x07, 0x03);
470 ACTCAPI_CHKSKB;
471 m->msg.info_resp.plci = chan->plci;
472 ACTCAPI_QUEUE_TX;
473}
474
475static void
476actcapi_disconnect_b3_resp(act2000_card *card, act2000_chan *chan)
477{
478 actcapi_msg *m;
479 struct sk_buff *skb;
480
481 ACTCAPI_MKHDR(2, 0x84, 0x03);
482 ACTCAPI_CHKSKB;
483 m->msg.disconnect_b3_resp.ncci = chan->ncci;
484 chan->ncci = 0x8000;
485 chan->queued = 0;
486 ACTCAPI_QUEUE_TX;
487}
488
489static void
490actcapi_disconnect_resp(act2000_card *card, act2000_chan *chan)
491{
492 actcapi_msg *m;
493 struct sk_buff *skb;
494
495 ACTCAPI_MKHDR(2, 0x04, 0x03);
496 ACTCAPI_CHKSKB;
497 m->msg.disconnect_resp.plci = chan->plci;
498 chan->plci = 0x8000;
499 ACTCAPI_QUEUE_TX;
500}
501
502static int
503new_plci(act2000_card *card, __u16 plci)
504{
505 int i;
506 for (i = 0; i < ACT2000_BCH; i++)
507 if (card->bch[i].plci == 0x8000) {
508 card->bch[i].plci = plci;
509 return i;
510 }
511 return -1;
512}
513
514static int
515find_plci(act2000_card *card, __u16 plci)
516{
517 int i;
518 for (i = 0; i < ACT2000_BCH; i++)
519 if (card->bch[i].plci == plci)
520 return i;
521 return -1;
522}
523
524static int
525find_ncci(act2000_card *card, __u16 ncci)
526{
527 int i;
528 for (i = 0; i < ACT2000_BCH; i++)
529 if (card->bch[i].ncci == ncci)
530 return i;
531 return -1;
532}
533
534static int
535find_dialing(act2000_card *card, __u16 callref)
536{
537 int i;
538 for (i = 0; i < ACT2000_BCH; i++)
539 if ((card->bch[i].callref == callref) &&
540 (card->bch[i].fsm_state == ACT2000_STATE_OCALL))
541 return i;
542 return -1;
543}
544
545static int
546actcapi_data_b3_ind(act2000_card *card, struct sk_buff *skb) {
547 __u16 plci;
548 __u16 ncci;
549 __u16 controller;
550 __u8 blocknr;
551 int chan;
552 actcapi_msg *msg = (actcapi_msg *)skb->data;
553
554 EVAL_NCCI(msg->msg.data_b3_ind.fakencci, plci, controller, ncci);
555 chan = find_ncci(card, ncci);
556 if (chan < 0)
557 return 0;
558 if (card->bch[chan].fsm_state != ACT2000_STATE_ACTIVE)
559 return 0;
560 if (card->bch[chan].plci != plci)
561 return 0;
562 blocknr = msg->msg.data_b3_ind.blocknr;
563 skb_pull(skb, 19);
564 card->interface.rcvcallb_skb(card->myid, chan, skb);
565 if (!(skb = alloc_skb(11, GFP_ATOMIC))) {
566 printk(KERN_WARNING "actcapi: alloc_skb failed\n");
567 return 1;
568 }
569 msg = (actcapi_msg *)skb_put(skb, 11);
570 msg->hdr.len = 11;
571 msg->hdr.applicationID = 1;
572 msg->hdr.cmd.cmd = 0x86;
573 msg->hdr.cmd.subcmd = 0x03;
574 msg->hdr.msgnum = actcapi_nextsmsg(card);
575 msg->msg.data_b3_resp.ncci = ncci;
576 msg->msg.data_b3_resp.blocknr = blocknr;
577 ACTCAPI_QUEUE_TX;
578 return 1;
579}
580
581/*
582 * Walk over ackq, unlink DATA_B3_REQ from it, if
583 * ncci and blocknr are matching.
584 * Decrement queued-bytes counter.
585 */
586static int
587handle_ack(act2000_card *card, act2000_chan *chan, __u8 blocknr) {
588 unsigned long flags;
589 struct sk_buff *skb;
590 struct sk_buff *tmp;
591 struct actcapi_msg *m;
592 int ret = 0;
593
594 spin_lock_irqsave(&card->lock, flags);
595 skb = skb_peek(&card->ackq);
596 spin_unlock_irqrestore(&card->lock, flags);
597 if (!skb) {
598 printk(KERN_WARNING "act2000: handle_ack nothing found!\n");
599 return 0;
600 }
601 tmp = skb;
602 while (1) {
603 m = (actcapi_msg *)tmp->data;
604 if ((((m->msg.data_b3_req.fakencci >> 8) & 0xff) == chan->ncci) &&
605 (m->msg.data_b3_req.blocknr == blocknr)) {
606 /* found corresponding DATA_B3_REQ */
607 skb_unlink(tmp);
608 chan->queued -= m->msg.data_b3_req.datalen;
609 if (m->msg.data_b3_req.flags)
610 ret = m->msg.data_b3_req.datalen;
611 dev_kfree_skb(tmp);
612 if (chan->queued < 0)
613 chan->queued = 0;
614 return ret;
615 }
616 spin_lock_irqsave(&card->lock, flags);
617 tmp = skb_peek((struct sk_buff_head *)tmp);
618 spin_unlock_irqrestore(&card->lock, flags);
619 if ((tmp == skb) || (tmp == NULL)) {
620 /* reached end of queue */
621 printk(KERN_WARNING "act2000: handle_ack nothing found!\n");
622 return 0;
623 }
624 }
625}
626
627void
628actcapi_dispatch(act2000_card *card)
629{
630 struct sk_buff *skb;
631 actcapi_msg *msg;
632 __u16 ccmd;
633 int chan;
634 int len;
635 act2000_chan *ctmp;
636 isdn_ctrl cmd;
637 char tmp[170];
638
639 while ((skb = skb_dequeue(&card->rcvq))) {
640 actcapi_debug_msg(skb, 0);
641 msg = (actcapi_msg *)skb->data;
642 ccmd = ((msg->hdr.cmd.cmd << 8) | msg->hdr.cmd.subcmd);
643 switch (ccmd) {
644 case 0x8602:
645 /* DATA_B3_IND */
646 if (actcapi_data_b3_ind(card, skb))
647 return;
648 break;
649 case 0x8601:
650 /* DATA_B3_CONF */
651 chan = find_ncci(card, msg->msg.data_b3_conf.ncci);
652 if ((chan >= 0) && (card->bch[chan].fsm_state == ACT2000_STATE_ACTIVE)) {
653 if (msg->msg.data_b3_conf.info != 0)
654 printk(KERN_WARNING "act2000: DATA_B3_CONF: %04x\n",
655 msg->msg.data_b3_conf.info);
656 len = handle_ack(card, &card->bch[chan],
657 msg->msg.data_b3_conf.blocknr);
658 if (len) {
659 cmd.driver = card->myid;
660 cmd.command = ISDN_STAT_BSENT;
661 cmd.arg = chan;
662 cmd.parm.length = len;
663 card->interface.statcallb(&cmd);
664 }
665 }
666 break;
667 case 0x0201:
668 /* CONNECT_CONF */
669 chan = find_dialing(card, msg->hdr.msgnum);
670 if (chan >= 0) {
671 if (msg->msg.connect_conf.info) {
672 card->bch[chan].fsm_state = ACT2000_STATE_NULL;
673 cmd.driver = card->myid;
674 cmd.command = ISDN_STAT_DHUP;
675 cmd.arg = chan;
676 card->interface.statcallb(&cmd);
677 } else {
678 card->bch[chan].fsm_state = ACT2000_STATE_OWAIT;
679 card->bch[chan].plci = msg->msg.connect_conf.plci;
680 }
681 }
682 break;
683 case 0x0202:
684 /* CONNECT_IND */
685 chan = new_plci(card, msg->msg.connect_ind.plci);
686 if (chan < 0) {
687 ctmp = (act2000_chan *)tmp;
688 ctmp->plci = msg->msg.connect_ind.plci;
689 actcapi_connect_resp(card, ctmp, 0x11); /* All Card-Cannels busy */
690 } else {
691 card->bch[chan].fsm_state = ACT2000_STATE_ICALL;
692 cmd.driver = card->myid;
693 cmd.command = ISDN_STAT_ICALL;
694 cmd.arg = chan;
695 cmd.parm.setup.si1 = msg->msg.connect_ind.si1;
696 cmd.parm.setup.si2 = msg->msg.connect_ind.si2;
697 if (card->ptype == ISDN_PTYPE_EURO)
698 strcpy(cmd.parm.setup.eazmsn,
699 act2000_find_eaz(card, msg->msg.connect_ind.eaz));
700 else {
701 cmd.parm.setup.eazmsn[0] = msg->msg.connect_ind.eaz;
702 cmd.parm.setup.eazmsn[1] = 0;
703 }
704 memset(cmd.parm.setup.phone, 0, sizeof(cmd.parm.setup.phone));
705 memcpy(cmd.parm.setup.phone, msg->msg.connect_ind.addr.num,
706 msg->msg.connect_ind.addr.len - 1);
707 cmd.parm.setup.plan = msg->msg.connect_ind.addr.tnp;
708 cmd.parm.setup.screen = 0;
709 if (card->interface.statcallb(&cmd) == 2)
710 actcapi_connect_resp(card, &card->bch[chan], 0x15); /* Reject Call */
711 }
712 break;
713 case 0x0302:
714 /* CONNECT_ACTIVE_IND */
715 chan = find_plci(card, msg->msg.connect_active_ind.plci);
716 if (chan >= 0)
717 switch (card->bch[chan].fsm_state) {
718 case ACT2000_STATE_IWAIT:
719 actcapi_connect_active_resp(card, &card->bch[chan]);
720 break;
721 case ACT2000_STATE_OWAIT:
722 actcapi_connect_active_resp(card, &card->bch[chan]);
723 actcapi_select_b2_protocol_req(card, &card->bch[chan]);
724 break;
725 }
726 break;
727 case 0x8202:
728 /* CONNECT_B3_IND */
729 chan = find_plci(card, msg->msg.connect_b3_ind.plci);
730 if ((chan >= 0) && (card->bch[chan].fsm_state == ACT2000_STATE_IBWAIT)) {
731 card->bch[chan].ncci = msg->msg.connect_b3_ind.ncci;
732 actcapi_connect_b3_resp(card, &card->bch[chan], 0);
733 } else {
734 ctmp = (act2000_chan *)tmp;
735 ctmp->ncci = msg->msg.connect_b3_ind.ncci;
736 actcapi_connect_b3_resp(card, ctmp, 0x11); /* All Card-Cannels busy */
737 }
738 break;
739 case 0x8302:
740 /* CONNECT_B3_ACTIVE_IND */
741 chan = find_ncci(card, msg->msg.connect_b3_active_ind.ncci);
742 if ((chan >= 0) && (card->bch[chan].fsm_state == ACT2000_STATE_BWAIT)) {
743 actcapi_connect_b3_active_resp(card, &card->bch[chan]);
744 cmd.driver = card->myid;
745 cmd.command = ISDN_STAT_BCONN;
746 cmd.arg = chan;
747 card->interface.statcallb(&cmd);
748 }
749 break;
750 case 0x8402:
751 /* DISCONNECT_B3_IND */
752 chan = find_ncci(card, msg->msg.disconnect_b3_ind.ncci);
753 if (chan >= 0) {
754 ctmp = &card->bch[chan];
755 actcapi_disconnect_b3_resp(card, ctmp);
756 switch (ctmp->fsm_state) {
757 case ACT2000_STATE_ACTIVE:
758 ctmp->fsm_state = ACT2000_STATE_DHWAIT2;
759 cmd.driver = card->myid;
760 cmd.command = ISDN_STAT_BHUP;
761 cmd.arg = chan;
762 card->interface.statcallb(&cmd);
763 break;
764 case ACT2000_STATE_BHWAIT2:
765 actcapi_disconnect_req(card, ctmp);
766 ctmp->fsm_state = ACT2000_STATE_DHWAIT;
767 cmd.driver = card->myid;
768 cmd.command = ISDN_STAT_BHUP;
769 cmd.arg = chan;
770 card->interface.statcallb(&cmd);
771 break;
772 }
773 }
774 break;
775 case 0x0402:
776 /* DISCONNECT_IND */
777 chan = find_plci(card, msg->msg.disconnect_ind.plci);
778 if (chan >= 0) {
779 ctmp = &card->bch[chan];
780 actcapi_disconnect_resp(card, ctmp);
781 ctmp->fsm_state = ACT2000_STATE_NULL;
782 cmd.driver = card->myid;
783 cmd.command = ISDN_STAT_DHUP;
784 cmd.arg = chan;
785 card->interface.statcallb(&cmd);
786 } else {
787 ctmp = (act2000_chan *)tmp;
788 ctmp->plci = msg->msg.disconnect_ind.plci;
789 actcapi_disconnect_resp(card, ctmp);
790 }
791 break;
792 case 0x4001:
793 /* SELECT_B2_PROTOCOL_CONF */
794 chan = find_plci(card, msg->msg.select_b2_protocol_conf.plci);
795 if (chan >= 0)
796 switch (card->bch[chan].fsm_state) {
797 case ACT2000_STATE_ICALL:
798 case ACT2000_STATE_OWAIT:
799 ctmp = &card->bch[chan];
800 if (msg->msg.select_b2_protocol_conf.info == 0)
801 actcapi_select_b3_protocol_req(card, ctmp);
802 else {
803 ctmp->fsm_state = ACT2000_STATE_NULL;
804 cmd.driver = card->myid;
805 cmd.command = ISDN_STAT_DHUP;
806 cmd.arg = chan;
807 card->interface.statcallb(&cmd);
808 }
809 break;
810 }
811 break;
812 case 0x8001:
813 /* SELECT_B3_PROTOCOL_CONF */
814 chan = find_plci(card, msg->msg.select_b3_protocol_conf.plci);
815 if (chan >= 0)
816 switch (card->bch[chan].fsm_state) {
817 case ACT2000_STATE_ICALL:
818 case ACT2000_STATE_OWAIT:
819 ctmp = &card->bch[chan];
820 if (msg->msg.select_b3_protocol_conf.info == 0)
821 actcapi_listen_b3_req(card, ctmp);
822 else {
823 ctmp->fsm_state = ACT2000_STATE_NULL;
824 cmd.driver = card->myid;
825 cmd.command = ISDN_STAT_DHUP;
826 cmd.arg = chan;
827 card->interface.statcallb(&cmd);
828 }
829 }
830 break;
831 case 0x8101:
832 /* LISTEN_B3_CONF */
833 chan = find_plci(card, msg->msg.listen_b3_conf.plci);
834 if (chan >= 0)
835 switch (card->bch[chan].fsm_state) {
836 case ACT2000_STATE_ICALL:
837 ctmp = &card->bch[chan];
838 if (msg->msg.listen_b3_conf.info == 0)
839 actcapi_connect_resp(card, ctmp, 0);
840 else {
841 ctmp->fsm_state = ACT2000_STATE_NULL;
842 cmd.driver = card->myid;
843 cmd.command = ISDN_STAT_DHUP;
844 cmd.arg = chan;
845 card->interface.statcallb(&cmd);
846 }
847 break;
848 case ACT2000_STATE_OWAIT:
849 ctmp = &card->bch[chan];
850 if (msg->msg.listen_b3_conf.info == 0) {
851 actcapi_connect_b3_req(card, ctmp);
852 ctmp->fsm_state = ACT2000_STATE_OBWAIT;
853 cmd.driver = card->myid;
854 cmd.command = ISDN_STAT_DCONN;
855 cmd.arg = chan;
856 card->interface.statcallb(&cmd);
857 } else {
858 ctmp->fsm_state = ACT2000_STATE_NULL;
859 cmd.driver = card->myid;
860 cmd.command = ISDN_STAT_DHUP;
861 cmd.arg = chan;
862 card->interface.statcallb(&cmd);
863 }
864 break;
865 }
866 break;
867 case 0x8201:
868 /* CONNECT_B3_CONF */
869 chan = find_plci(card, msg->msg.connect_b3_conf.plci);
870 if ((chan >= 0) && (card->bch[chan].fsm_state == ACT2000_STATE_OBWAIT)) {
871 ctmp = &card->bch[chan];
872 if (msg->msg.connect_b3_conf.info) {
873 ctmp->fsm_state = ACT2000_STATE_NULL;
874 cmd.driver = card->myid;
875 cmd.command = ISDN_STAT_DHUP;
876 cmd.arg = chan;
877 card->interface.statcallb(&cmd);
878 } else {
879 ctmp->ncci = msg->msg.connect_b3_conf.ncci;
880 ctmp->fsm_state = ACT2000_STATE_BWAIT;
881 }
882 }
883 break;
884 case 0x8401:
885 /* DISCONNECT_B3_CONF */
886 chan = find_ncci(card, msg->msg.disconnect_b3_conf.ncci);
887 if ((chan >= 0) && (card->bch[chan].fsm_state == ACT2000_STATE_BHWAIT))
888 card->bch[chan].fsm_state = ACT2000_STATE_BHWAIT2;
889 break;
890 case 0x0702:
891 /* INFO_IND */
892 chan = find_plci(card, msg->msg.info_ind.plci);
893 if (chan >= 0)
894 /* TODO: Eval Charging info / cause */
895 actcapi_info_resp(card, &card->bch[chan]);
896 break;
897 case 0x0401:
898 /* LISTEN_CONF */
899 case 0x0501:
900 /* LISTEN_CONF */
901 case 0xff01:
902 /* MANUFACTURER_CONF */
903 break;
904 case 0xff02:
905 /* MANUFACTURER_IND */
906 if (msg->msg.manuf_msg == 3) {
907 memset(tmp, 0, sizeof(tmp));
908 strncpy(tmp,
909 &msg->msg.manufacturer_ind_err.errstring,
910 msg->hdr.len - 16);
911 if (msg->msg.manufacturer_ind_err.errcode)
912 printk(KERN_WARNING "act2000: %s\n", tmp);
913 else {
914 printk(KERN_DEBUG "act2000: %s\n", tmp);
915 if ((!strncmp(tmp, "INFO: Trace buffer con", 22)) ||
916 (!strncmp(tmp, "INFO: Compile Date/Tim", 22))) {
917 card->flags |= ACT2000_FLAGS_RUNNING;
918 cmd.command = ISDN_STAT_RUN;
919 cmd.driver = card->myid;
920 cmd.arg = 0;
921 actcapi_manufacturer_req_net(card);
922 actcapi_manufacturer_req_msn(card);
923 actcapi_listen_req(card);
924 card->interface.statcallb(&cmd);
925 }
926 }
927 }
928 break;
929 default:
930 printk(KERN_WARNING "act2000: UNHANDLED Message %04x\n", ccmd);
931 break;
932 }
933 dev_kfree_skb(skb);
934 }
935}
936
937#ifdef DEBUG_MSG
938static void
939actcapi_debug_caddr(actcapi_addr *addr)
940{
941 char tmp[30];
942
943 printk(KERN_DEBUG " Alen = %d\n", addr->len);
944 if (addr->len > 0)
945 printk(KERN_DEBUG " Atnp = 0x%02x\n", addr->tnp);
946 if (addr->len > 1) {
947 memset(tmp, 0, 30);
948 memcpy(tmp, addr->num, addr->len - 1);
949 printk(KERN_DEBUG " Anum = '%s'\n", tmp);
950 }
951}
952
953static void
954actcapi_debug_ncpi(actcapi_ncpi *ncpi)
955{
956 printk(KERN_DEBUG " ncpi.len = %d\n", ncpi->len);
957 if (ncpi->len >= 2)
958 printk(KERN_DEBUG " ncpi.lic = 0x%04x\n", ncpi->lic);
959 if (ncpi->len >= 4)
960 printk(KERN_DEBUG " ncpi.hic = 0x%04x\n", ncpi->hic);
961 if (ncpi->len >= 6)
962 printk(KERN_DEBUG " ncpi.ltc = 0x%04x\n", ncpi->ltc);
963 if (ncpi->len >= 8)
964 printk(KERN_DEBUG " ncpi.htc = 0x%04x\n", ncpi->htc);
965 if (ncpi->len >= 10)
966 printk(KERN_DEBUG " ncpi.loc = 0x%04x\n", ncpi->loc);
967 if (ncpi->len >= 12)
968 printk(KERN_DEBUG " ncpi.hoc = 0x%04x\n", ncpi->hoc);
969 if (ncpi->len >= 13)
970 printk(KERN_DEBUG " ncpi.mod = %d\n", ncpi->modulo);
971}
972
973static void
974actcapi_debug_dlpd(actcapi_dlpd *dlpd)
975{
976 printk(KERN_DEBUG " dlpd.len = %d\n", dlpd->len);
977 if (dlpd->len >= 2)
978 printk(KERN_DEBUG " dlpd.dlen = 0x%04x\n", dlpd->dlen);
979 if (dlpd->len >= 3)
980 printk(KERN_DEBUG " dlpd.laa = 0x%02x\n", dlpd->laa);
981 if (dlpd->len >= 4)
982 printk(KERN_DEBUG " dlpd.lab = 0x%02x\n", dlpd->lab);
983 if (dlpd->len >= 5)
984 printk(KERN_DEBUG " dlpd.modulo = %d\n", dlpd->modulo);
985 if (dlpd->len >= 6)
986 printk(KERN_DEBUG " dlpd.win = %d\n", dlpd->win);
987}
988
989#ifdef DEBUG_DUMP_SKB
990static void dump_skb(struct sk_buff *skb) {
991 char tmp[80];
992 char *p = skb->data;
993 char *t = tmp;
994 int i;
995
996 for (i = 0; i < skb->len; i++) {
997 t += sprintf(t, "%02x ", *p++ & 0xff);
998 if ((i & 0x0f) == 8) {
999 printk(KERN_DEBUG "dump: %s\n", tmp);
1000 t = tmp;
1001 }
1002 }
1003 if (i & 0x07)
1004 printk(KERN_DEBUG "dump: %s\n", tmp);
1005}
1006#endif
1007
1008void
1009actcapi_debug_msg(struct sk_buff *skb, int direction)
1010{
1011 actcapi_msg *msg = (actcapi_msg *)skb->data;
1012 char *descr;
1013 int i;
1014 char tmp[170];
1015
1016#ifndef DEBUG_DATA_MSG
1017 if (msg->hdr.cmd.cmd == 0x86)
1018 return;
1019#endif
1020 descr = "INVALID";
1021#ifdef DEBUG_DUMP_SKB
1022 dump_skb(skb);
1023#endif
1024 for (i = 0; i < num_valid_msg; i++)
1025 if ((msg->hdr.cmd.cmd == valid_msg[i].cmd.cmd) &&
1026 (msg->hdr.cmd.subcmd == valid_msg[i].cmd.subcmd)) {
1027 descr = valid_msg[i].description;
1028 break;
1029 }
1030 printk(KERN_DEBUG "%s %s msg\n", direction?"Outgoing":"Incoming", descr);
1031 printk(KERN_DEBUG " ApplID = %d\n", msg->hdr.applicationID);
1032 printk(KERN_DEBUG " Len = %d\n", msg->hdr.len);
1033 printk(KERN_DEBUG " MsgNum = 0x%04x\n", msg->hdr.msgnum);
1034 printk(KERN_DEBUG " Cmd = 0x%02x\n", msg->hdr.cmd.cmd);
1035 printk(KERN_DEBUG " SubCmd = 0x%02x\n", msg->hdr.cmd.subcmd);
1036 switch (i) {
1037 case 0:
1038 /* DATA B3 IND */
1039 printk(KERN_DEBUG " BLOCK = 0x%02x\n",
1040 msg->msg.data_b3_ind.blocknr);
1041 break;
1042 case 2:
1043 /* CONNECT CONF */
1044 printk(KERN_DEBUG " PLCI = 0x%04x\n",
1045 msg->msg.connect_conf.plci);
1046 printk(KERN_DEBUG " Info = 0x%04x\n",
1047 msg->msg.connect_conf.info);
1048 break;
1049 case 3:
1050 /* CONNECT IND */
1051 printk(KERN_DEBUG " PLCI = 0x%04x\n",
1052 msg->msg.connect_ind.plci);
1053 printk(KERN_DEBUG " Contr = %d\n",
1054 msg->msg.connect_ind.controller);
1055 printk(KERN_DEBUG " SI1 = %d\n",
1056 msg->msg.connect_ind.si1);
1057 printk(KERN_DEBUG " SI2 = %d\n",
1058 msg->msg.connect_ind.si2);
1059 printk(KERN_DEBUG " EAZ = '%c'\n",
1060 msg->msg.connect_ind.eaz);
1061 actcapi_debug_caddr(&msg->msg.connect_ind.addr);
1062 break;
1063 case 5:
1064 /* CONNECT ACTIVE IND */
1065 printk(KERN_DEBUG " PLCI = 0x%04x\n",
1066 msg->msg.connect_active_ind.plci);
1067 actcapi_debug_caddr(&msg->msg.connect_active_ind.addr);
1068 break;
1069 case 8:
1070 /* LISTEN CONF */
1071 printk(KERN_DEBUG " Contr = %d\n",
1072 msg->msg.listen_conf.controller);
1073 printk(KERN_DEBUG " Info = 0x%04x\n",
1074 msg->msg.listen_conf.info);
1075 break;
1076 case 11:
1077 /* INFO IND */
1078 printk(KERN_DEBUG " PLCI = 0x%04x\n",
1079 msg->msg.info_ind.plci);
1080 printk(KERN_DEBUG " Imsk = 0x%04x\n",
1081 msg->msg.info_ind.nr.mask);
1082 if (msg->hdr.len > 12) {
1083 int l = msg->hdr.len - 12;
1084 int j;
1085 char *p = tmp;
1086 for (j = 0; j < l ; j++)
1087 p += sprintf(p, "%02x ", msg->msg.info_ind.el.display[j]);
1088 printk(KERN_DEBUG " D = '%s'\n", tmp);
1089 }
1090 break;
1091 case 14:
1092 /* SELECT B2 PROTOCOL CONF */
1093 printk(KERN_DEBUG " PLCI = 0x%04x\n",
1094 msg->msg.select_b2_protocol_conf.plci);
1095 printk(KERN_DEBUG " Info = 0x%04x\n",
1096 msg->msg.select_b2_protocol_conf.info);
1097 break;
1098 case 15:
1099 /* SELECT B3 PROTOCOL CONF */
1100 printk(KERN_DEBUG " PLCI = 0x%04x\n",
1101 msg->msg.select_b3_protocol_conf.plci);
1102 printk(KERN_DEBUG " Info = 0x%04x\n",
1103 msg->msg.select_b3_protocol_conf.info);
1104 break;
1105 case 16:
1106 /* LISTEN B3 CONF */
1107 printk(KERN_DEBUG " PLCI = 0x%04x\n",
1108 msg->msg.listen_b3_conf.plci);
1109 printk(KERN_DEBUG " Info = 0x%04x\n",
1110 msg->msg.listen_b3_conf.info);
1111 break;
1112 case 18:
1113 /* CONNECT B3 IND */
1114 printk(KERN_DEBUG " NCCI = 0x%04x\n",
1115 msg->msg.connect_b3_ind.ncci);
1116 printk(KERN_DEBUG " PLCI = 0x%04x\n",
1117 msg->msg.connect_b3_ind.plci);
1118 actcapi_debug_ncpi(&msg->msg.connect_b3_ind.ncpi);
1119 break;
1120 case 19:
1121 /* CONNECT B3 ACTIVE IND */
1122 printk(KERN_DEBUG " NCCI = 0x%04x\n",
1123 msg->msg.connect_b3_active_ind.ncci);
1124 actcapi_debug_ncpi(&msg->msg.connect_b3_active_ind.ncpi);
1125 break;
1126 case 26:
1127 /* MANUFACTURER IND */
1128 printk(KERN_DEBUG " Mmsg = 0x%02x\n",
1129 msg->msg.manufacturer_ind_err.manuf_msg);
1130 switch (msg->msg.manufacturer_ind_err.manuf_msg) {
1131 case 3:
1132 printk(KERN_DEBUG " Contr = %d\n",
1133 msg->msg.manufacturer_ind_err.controller);
1134 printk(KERN_DEBUG " Code = 0x%08x\n",
1135 msg->msg.manufacturer_ind_err.errcode);
1136 memset(tmp, 0, sizeof(tmp));
1137 strncpy(tmp, &msg->msg.manufacturer_ind_err.errstring,
1138 msg->hdr.len - 16);
1139 printk(KERN_DEBUG " Emsg = '%s'\n", tmp);
1140 break;
1141 }
1142 break;
1143 case 30:
1144 /* LISTEN REQ */
1145 printk(KERN_DEBUG " Imsk = 0x%08x\n",
1146 msg->msg.listen_req.infomask);
1147 printk(KERN_DEBUG " Emsk = 0x%04x\n",
1148 msg->msg.listen_req.eazmask);
1149 printk(KERN_DEBUG " Smsk = 0x%04x\n",
1150 msg->msg.listen_req.simask);
1151 break;
1152 case 35:
1153 /* SELECT_B2_PROTOCOL_REQ */
1154 printk(KERN_DEBUG " PLCI = 0x%04x\n",
1155 msg->msg.select_b2_protocol_req.plci);
1156 printk(KERN_DEBUG " prot = 0x%02x\n",
1157 msg->msg.select_b2_protocol_req.protocol);
1158 if (msg->hdr.len >= 11)
1159 printk(KERN_DEBUG "No dlpd\n");
1160 else
1161 actcapi_debug_dlpd(&msg->msg.select_b2_protocol_req.dlpd);
1162 break;
1163 case 44:
1164 /* CONNECT RESP */
1165 printk(KERN_DEBUG " PLCI = 0x%04x\n",
1166 msg->msg.connect_resp.plci);
1167 printk(KERN_DEBUG " CAUSE = 0x%02x\n",
1168 msg->msg.connect_resp.rejectcause);
1169 break;
1170 case 45:
1171 /* CONNECT ACTIVE RESP */
1172 printk(KERN_DEBUG " PLCI = 0x%04x\n",
1173 msg->msg.connect_active_resp.plci);
1174 break;
1175 }
1176}
1177#endif
diff --git a/drivers/isdn/act2000/capi.h b/drivers/isdn/act2000/capi.h
new file mode 100644
index 000000000000..04d2bcdd37a7
--- /dev/null
+++ b/drivers/isdn/act2000/capi.h
@@ -0,0 +1,366 @@
1/* $Id: capi.h,v 1.6.6.2 2001/09/23 22:24:32 kai Exp $
2 *
3 * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000.
4 *
5 * Author Fritz Elfert
6 * Copyright by Fritz Elfert <fritz@isdn4linux.de>
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 * Thanks to Friedemann Baitinger and IBM Germany
12 *
13 */
14
15#ifndef CAPI_H
16#define CAPI_H
17
18/* Command-part of a CAPI message */
19typedef struct actcapi_msgcmd {
20 __u8 cmd;
21 __u8 subcmd;
22} actcapi_msgcmd;
23
24/* CAPI message header */
25typedef struct actcapi_msghdr {
26 __u16 len;
27 __u16 applicationID;
28 actcapi_msgcmd cmd;
29 __u16 msgnum;
30} actcapi_msghdr;
31
32/* CAPI message description (for debugging) */
33typedef struct actcapi_msgdsc {
34 actcapi_msgcmd cmd;
35 char *description;
36} actcapi_msgdsc;
37
38/* CAPI Address */
39typedef struct actcapi_addr {
40 __u8 len; /* Length of element */
41 __u8 tnp; /* Type/Numbering Plan */
42 __u8 num[20]; /* Caller ID */
43} actcapi_addr;
44
45/* CAPI INFO element mask */
46typedef union actcapi_infonr { /* info number */
47 __u16 mask; /* info-mask field */
48 struct bmask { /* bit definitions */
49 unsigned codes : 3; /* code set */
50 unsigned rsvd : 5; /* reserved */
51 unsigned svind : 1; /* single, variable length ind. */
52 unsigned wtype : 7; /* W-element type */
53 } bmask;
54} actcapi_infonr;
55
56/* CAPI INFO element */
57typedef union actcapi_infoel { /* info element */
58 __u8 len; /* length of info element */
59 __u8 display[40]; /* display contents */
60 __u8 uuinfo[40]; /* User-user info field */
61 struct cause { /* Cause information */
62 unsigned ext2 : 1; /* extension */
63 unsigned cod : 2; /* coding standard */
64 unsigned spare : 1; /* spare */
65 unsigned loc : 4; /* location */
66 unsigned ext1 : 1; /* extension */
67 unsigned cval : 7; /* Cause value */
68 } cause;
69 struct charge { /* Charging information */
70 __u8 toc; /* type of charging info */
71 __u8 unit[10]; /* charging units */
72 } charge;
73 __u8 date[20]; /* date fields */
74 __u8 stat; /* state of remote party */
75} actcapi_infoel;
76
77/* Message for EAZ<->MSN Mapping */
78typedef struct actcapi_msn {
79 __u8 eaz;
80 __u8 len; /* Length of MSN */
81 __u8 msn[15] __attribute__ ((packed));
82} actcapi_msn;
83
84typedef struct actcapi_dlpd {
85 __u8 len; /* Length of structure */
86 __u16 dlen __attribute__ ((packed)); /* Data Length */
87 __u8 laa __attribute__ ((packed)); /* Link Address A */
88 __u8 lab; /* Link Address B */
89 __u8 modulo; /* Modulo Mode */
90 __u8 win; /* Window size */
91 __u8 xid[100]; /* XID Information */
92} actcapi_dlpd;
93
94typedef struct actcapi_ncpd {
95 __u8 len; /* Length of structure */
96 __u16 lic __attribute__ ((packed));
97 __u16 hic __attribute__ ((packed));
98 __u16 ltc __attribute__ ((packed));
99 __u16 htc __attribute__ ((packed));
100 __u16 loc __attribute__ ((packed));
101 __u16 hoc __attribute__ ((packed));
102 __u8 modulo __attribute__ ((packed));
103} actcapi_ncpd;
104#define actcapi_ncpi actcapi_ncpd
105
106/*
107 * Layout of NCCI field in a B3 DATA CAPI message is different from
108 * standard at act2000:
109 *
110 * Bit 0-4 = PLCI
111 * Bit 5-7 = Controller
112 * Bit 8-15 = NCCI
113 */
114#define MAKE_NCCI(plci,contr,ncci) \
115 ((plci & 0x1f) | ((contr & 0x7) << 5) | ((ncci & 0xff) << 8))
116
117#define EVAL_NCCI(fakencci,plci,contr,ncci) { \
118 plci = fakencci & 0x1f; \
119 contr = (fakencci >> 5) & 0x7; \
120 ncci = (fakencci >> 8) & 0xff; \
121}
122
123/*
124 * Layout of PLCI field in a B3 DATA CAPI message is different from
125 * standard at act2000:
126 *
127 * Bit 0-4 = PLCI
128 * Bit 5-7 = Controller
129 * Bit 8-15 = reserved (must be 0)
130 */
131#define MAKE_PLCI(plci,contr) \
132 ((plci & 0x1f) | ((contr & 0x7) << 5))
133
134#define EVAL_PLCI(fakeplci,plci,contr) { \
135 plci = fakeplci & 0x1f; \
136 contr = (fakeplci >> 5) & 0x7; \
137}
138
139typedef struct actcapi_msg {
140 actcapi_msghdr hdr;
141 union {
142 __u16 manuf_msg;
143 struct manufacturer_req_net {
144 __u16 manuf_msg;
145 __u16 controller;
146 __u8 nettype;
147 } manufacturer_req_net;
148 struct manufacturer_req_v42 {
149 __u16 manuf_msg;
150 __u16 controller;
151 __u32 v42control;
152 } manufacturer_req_v42;
153 struct manufacturer_conf_v42 {
154 __u16 manuf_msg;
155 __u16 controller;
156 } manufacturer_conf_v42;
157 struct manufacturer_req_err {
158 __u16 manuf_msg;
159 __u16 controller;
160 } manufacturer_req_err;
161 struct manufacturer_ind_err {
162 __u16 manuf_msg;
163 __u16 controller;
164 __u32 errcode;
165 __u8 errstring; /* actually up to 160 */
166 } manufacturer_ind_err;
167 struct manufacturer_req_msn {
168 __u16 manuf_msg;
169 __u16 controller;
170 actcapi_msn msnmap;
171 } manufacturer_req_msn;
172 /* TODO: TraceInit-req/conf/ind/resp and
173 * TraceDump-req/conf/ind/resp
174 */
175 struct connect_req {
176 __u8 controller;
177 __u8 bchan;
178 __u32 infomask __attribute__ ((packed));
179 __u8 si1;
180 __u8 si2;
181 __u8 eaz;
182 actcapi_addr addr;
183 } connect_req;
184 struct connect_conf {
185 __u16 plci;
186 __u16 info;
187 } connect_conf;
188 struct connect_ind {
189 __u16 plci;
190 __u8 controller;
191 __u8 si1;
192 __u8 si2;
193 __u8 eaz;
194 actcapi_addr addr;
195 } connect_ind;
196 struct connect_resp {
197 __u16 plci;
198 __u8 rejectcause;
199 } connect_resp;
200 struct connect_active_ind {
201 __u16 plci;
202 actcapi_addr addr;
203 } connect_active_ind;
204 struct connect_active_resp {
205 __u16 plci;
206 } connect_active_resp;
207 struct connect_b3_req {
208 __u16 plci;
209 actcapi_ncpi ncpi;
210 } connect_b3_req;
211 struct connect_b3_conf {
212 __u16 plci;
213 __u16 ncci;
214 __u16 info;
215 } connect_b3_conf;
216 struct connect_b3_ind {
217 __u16 ncci;
218 __u16 plci;
219 actcapi_ncpi ncpi;
220 } connect_b3_ind;
221 struct connect_b3_resp {
222 __u16 ncci;
223 __u8 rejectcause;
224 actcapi_ncpi ncpi __attribute__ ((packed));
225 } connect_b3_resp;
226 struct disconnect_req {
227 __u16 plci;
228 __u8 cause;
229 } disconnect_req;
230 struct disconnect_conf {
231 __u16 plci;
232 __u16 info;
233 } disconnect_conf;
234 struct disconnect_ind {
235 __u16 plci;
236 __u16 info;
237 } disconnect_ind;
238 struct disconnect_resp {
239 __u16 plci;
240 } disconnect_resp;
241 struct connect_b3_active_ind {
242 __u16 ncci;
243 actcapi_ncpi ncpi;
244 } connect_b3_active_ind;
245 struct connect_b3_active_resp {
246 __u16 ncci;
247 } connect_b3_active_resp;
248 struct disconnect_b3_req {
249 __u16 ncci;
250 actcapi_ncpi ncpi;
251 } disconnect_b3_req;
252 struct disconnect_b3_conf {
253 __u16 ncci;
254 __u16 info;
255 } disconnect_b3_conf;
256 struct disconnect_b3_ind {
257 __u16 ncci;
258 __u16 info;
259 actcapi_ncpi ncpi;
260 } disconnect_b3_ind;
261 struct disconnect_b3_resp {
262 __u16 ncci;
263 } disconnect_b3_resp;
264 struct info_ind {
265 __u16 plci;
266 actcapi_infonr nr;
267 actcapi_infoel el;
268 } info_ind;
269 struct info_resp {
270 __u16 plci;
271 } info_resp;
272 struct listen_b3_req {
273 __u16 plci;
274 } listen_b3_req;
275 struct listen_b3_conf {
276 __u16 plci;
277 __u16 info;
278 } listen_b3_conf;
279 struct select_b2_protocol_req {
280 __u16 plci;
281 __u8 protocol;
282 actcapi_dlpd dlpd __attribute__ ((packed));
283 } select_b2_protocol_req;
284 struct select_b2_protocol_conf {
285 __u16 plci;
286 __u16 info;
287 } select_b2_protocol_conf;
288 struct select_b3_protocol_req {
289 __u16 plci;
290 __u8 protocol;
291 actcapi_ncpd ncpd __attribute__ ((packed));
292 } select_b3_protocol_req;
293 struct select_b3_protocol_conf {
294 __u16 plci;
295 __u16 info;
296 } select_b3_protocol_conf;
297 struct listen_req {
298 __u8 controller;
299 __u32 infomask __attribute__ ((packed));
300 __u16 eazmask __attribute__ ((packed));
301 __u16 simask __attribute__ ((packed));
302 } listen_req;
303 struct listen_conf {
304 __u8 controller;
305 __u16 info __attribute__ ((packed));
306 } listen_conf;
307 struct data_b3_req {
308 __u16 fakencci;
309 __u16 datalen;
310 __u32 unused;
311 __u8 blocknr;
312 __u16 flags __attribute__ ((packed));
313 } data_b3_req;
314 struct data_b3_ind {
315 __u16 fakencci;
316 __u16 datalen;
317 __u32 unused;
318 __u8 blocknr;
319 __u16 flags __attribute__ ((packed));
320 } data_b3_ind;
321 struct data_b3_resp {
322 __u16 ncci;
323 __u8 blocknr;
324 } data_b3_resp;
325 struct data_b3_conf {
326 __u16 ncci;
327 __u8 blocknr;
328 __u16 info __attribute__ ((packed));
329 } data_b3_conf;
330 } msg;
331} actcapi_msg;
332
333extern __inline__ unsigned short
334actcapi_nextsmsg(act2000_card *card)
335{
336 unsigned long flags;
337 unsigned short n;
338
339 spin_lock_irqsave(&card->mnlock, flags);
340 n = card->msgnum;
341 card->msgnum++;
342 card->msgnum &= 0x7fff;
343 spin_unlock_irqrestore(&card->mnlock, flags);
344 return n;
345}
346#define DEBUG_MSG
347#undef DEBUG_DATA_MSG
348#undef DEBUG_DUMP_SKB
349
350extern int actcapi_chkhdr(act2000_card *, actcapi_msghdr *);
351extern int actcapi_listen_req(act2000_card *);
352extern int actcapi_manufacturer_req_net(act2000_card *);
353extern int actcapi_manufacturer_req_v42(act2000_card *, ulong);
354extern int actcapi_manufacturer_req_errh(act2000_card *);
355extern int actcapi_manufacturer_req_msn(act2000_card *);
356extern int actcapi_connect_req(act2000_card *, act2000_chan *, char *, char, int, int);
357extern void actcapi_select_b2_protocol_req(act2000_card *, act2000_chan *);
358extern void actcapi_disconnect_b3_req(act2000_card *, act2000_chan *);
359extern void actcapi_connect_resp(act2000_card *, act2000_chan *, __u8);
360extern void actcapi_dispatch(act2000_card *);
361#ifdef DEBUG_MSG
362extern void actcapi_debug_msg(struct sk_buff *skb, int);
363#else
364#define actcapi_debug_msg(skb, len)
365#endif
366#endif
diff --git a/drivers/isdn/act2000/module.c b/drivers/isdn/act2000/module.c
new file mode 100644
index 000000000000..d89dcde4eade
--- /dev/null
+++ b/drivers/isdn/act2000/module.c
@@ -0,0 +1,808 @@
1/* $Id: module.c,v 1.14.6.4 2001/09/23 22:24:32 kai Exp $
2 *
3 * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000.
4 *
5 * Author Fritz Elfert
6 * Copyright by Fritz Elfert <fritz@isdn4linux.de>
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 * Thanks to Friedemann Baitinger and IBM Germany
12 *
13 */
14
15#include "act2000.h"
16#include "act2000_isa.h"
17#include "capi.h"
18#include <linux/module.h>
19#include <linux/init.h>
20
21static unsigned short act2000_isa_ports[] =
22{
23 0x0200, 0x0240, 0x0280, 0x02c0, 0x0300, 0x0340, 0x0380,
24 0xcfe0, 0xcfa0, 0xcf60, 0xcf20, 0xcee0, 0xcea0, 0xce60,
25};
26#define ISA_NRPORTS (sizeof(act2000_isa_ports)/sizeof(unsigned short))
27
28static act2000_card *cards = (act2000_card *) NULL;
29
30/* Parameters to be set by insmod */
31static int act_bus = 0;
32static int act_port = -1; /* -1 = Autoprobe */
33static int act_irq = -1;
34static char *act_id = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
35
36MODULE_DESCRIPTION( "ISDN4Linux: Driver for IBM Active 2000 ISDN card");
37MODULE_AUTHOR( "Fritz Elfert");
38MODULE_LICENSE( "GPL");
39MODULE_PARM_DESC(act_bus, "BusType of first card, 1=ISA, 2=MCA, 3=PCMCIA, currently only ISA");
40MODULE_PARM_DESC(membase, "Base port address of first card");
41MODULE_PARM_DESC(act_irq, "IRQ of first card");
42MODULE_PARM_DESC(act_id, "ID-String of first card");
43module_param(act_bus, int, 0);
44module_param(act_port, int, 0);
45module_param(act_irq, int, 0);
46module_param(act_id, charp, 0);
47
48static int act2000_addcard(int, int, int, char *);
49
50static act2000_chan *
51find_channel(act2000_card *card, int channel)
52{
53 if ((channel >= 0) && (channel < ACT2000_BCH))
54 return &(card->bch[channel]);
55 printk(KERN_WARNING "act2000: Invalid channel %d\n", channel);
56 return NULL;
57}
58
59/*
60 * Free MSN list
61 */
62static void
63act2000_clear_msn(act2000_card *card)
64{
65 struct msn_entry *p = card->msn_list;
66 struct msn_entry *q;
67 unsigned long flags;
68
69 spin_lock_irqsave(&card->lock, flags);
70 card->msn_list = NULL;
71 spin_unlock_irqrestore(&card->lock, flags);
72 while (p) {
73 q = p->next;
74 kfree(p);
75 p = q;
76 }
77}
78
79/*
80 * Find an MSN entry in the list.
81 * If ia5 != 0, return IA5-encoded EAZ, else
82 * return a bitmask with corresponding bit set.
83 */
84static __u16
85act2000_find_msn(act2000_card *card, char *msn, int ia5)
86{
87 struct msn_entry *p = card->msn_list;
88 __u8 eaz = '0';
89
90 while (p) {
91 if (!strcmp(p->msn, msn)) {
92 eaz = p->eaz;
93 break;
94 }
95 p = p->next;
96 }
97 if (!ia5)
98 return (1 << (eaz - '0'));
99 else
100 return eaz;
101}
102
103/*
104 * Find an EAZ entry in the list.
105 * return a string with corresponding msn.
106 */
107char *
108act2000_find_eaz(act2000_card *card, char eaz)
109{
110 struct msn_entry *p = card->msn_list;
111
112 while (p) {
113 if (p->eaz == eaz)
114 return(p->msn);
115 p = p->next;
116 }
117 return("\0");
118}
119
120/*
121 * Add or delete an MSN to the MSN list
122 *
123 * First character of msneaz is EAZ, rest is MSN.
124 * If length of eazmsn is 1, delete that entry.
125 */
126static int
127act2000_set_msn(act2000_card *card, char *eazmsn)
128{
129 struct msn_entry *p = card->msn_list;
130 struct msn_entry *q = NULL;
131 unsigned long flags;
132 int i;
133
134 if (!strlen(eazmsn))
135 return 0;
136 if (strlen(eazmsn) > 16)
137 return -EINVAL;
138 for (i = 0; i < strlen(eazmsn); i++)
139 if (!isdigit(eazmsn[i]))
140 return -EINVAL;
141 if (strlen(eazmsn) == 1) {
142 /* Delete a single MSN */
143 while (p) {
144 if (p->eaz == eazmsn[0]) {
145 spin_lock_irqsave(&card->lock, flags);
146 if (q)
147 q->next = p->next;
148 else
149 card->msn_list = p->next;
150 spin_unlock_irqrestore(&card->lock, flags);
151 kfree(p);
152 printk(KERN_DEBUG
153 "Mapping for EAZ %c deleted\n",
154 eazmsn[0]);
155 return 0;
156 }
157 q = p;
158 p = p->next;
159 }
160 return 0;
161 }
162 /* Add a single MSN */
163 while (p) {
164 /* Found in list, replace MSN */
165 if (p->eaz == eazmsn[0]) {
166 spin_lock_irqsave(&card->lock, flags);
167 strcpy(p->msn, &eazmsn[1]);
168 spin_unlock_irqrestore(&card->lock, flags);
169 printk(KERN_DEBUG
170 "Mapping for EAZ %c changed to %s\n",
171 eazmsn[0],
172 &eazmsn[1]);
173 return 0;
174 }
175 p = p->next;
176 }
177 /* Not found in list, add new entry */
178 p = kmalloc(sizeof(msn_entry), GFP_KERNEL);
179 if (!p)
180 return -ENOMEM;
181 p->eaz = eazmsn[0];
182 strcpy(p->msn, &eazmsn[1]);
183 p->next = card->msn_list;
184 spin_lock_irqsave(&card->lock, flags);
185 card->msn_list = p;
186 spin_unlock_irqrestore(&card->lock, flags);
187 printk(KERN_DEBUG
188 "Mapping %c -> %s added\n",
189 eazmsn[0],
190 &eazmsn[1]);
191 return 0;
192}
193
194static void
195act2000_transmit(struct act2000_card *card)
196{
197 switch (card->bus) {
198 case ACT2000_BUS_ISA:
199 act2000_isa_send(card);
200 break;
201 case ACT2000_BUS_PCMCIA:
202 case ACT2000_BUS_MCA:
203 default:
204 printk(KERN_WARNING
205 "act2000_transmit: Illegal bustype %d\n", card->bus);
206 }
207}
208
209static void
210act2000_receive(struct act2000_card *card)
211{
212 switch (card->bus) {
213 case ACT2000_BUS_ISA:
214 act2000_isa_receive(card);
215 break;
216 case ACT2000_BUS_PCMCIA:
217 case ACT2000_BUS_MCA:
218 default:
219 printk(KERN_WARNING
220 "act2000_receive: Illegal bustype %d\n", card->bus);
221 }
222}
223
224static void
225act2000_poll(unsigned long data)
226{
227 act2000_card * card = (act2000_card *)data;
228 unsigned long flags;
229
230 act2000_receive(card);
231 spin_lock_irqsave(&card->lock, flags);
232 mod_timer(&card->ptimer, jiffies+3);
233 spin_unlock_irqrestore(&card->lock, flags);
234}
235
236static int
237act2000_command(act2000_card * card, isdn_ctrl * c)
238{
239 ulong a;
240 act2000_chan *chan;
241 act2000_cdef cdef;
242 isdn_ctrl cmd;
243 char tmp[17];
244 int ret;
245 unsigned long flags;
246 void __user *arg;
247
248 switch (c->command) {
249 case ISDN_CMD_IOCTL:
250 memcpy(&a, c->parm.num, sizeof(ulong));
251 arg = (void __user *)a;
252 switch (c->arg) {
253 case ACT2000_IOCTL_LOADBOOT:
254 switch (card->bus) {
255 case ACT2000_BUS_ISA:
256 ret = act2000_isa_download(card,
257 arg);
258 if (!ret) {
259 card->flags |= ACT2000_FLAGS_LOADED;
260 if (!(card->flags & ACT2000_FLAGS_IVALID)) {
261 card->ptimer.expires = jiffies + 3;
262 card->ptimer.function = act2000_poll;
263 card->ptimer.data = (unsigned long)card;
264 add_timer(&card->ptimer);
265 }
266 actcapi_manufacturer_req_errh(card);
267 }
268 break;
269 default:
270 printk(KERN_WARNING
271 "act2000: Illegal BUS type %d\n",
272 card->bus);
273 ret = -EIO;
274 }
275 return ret;
276 case ACT2000_IOCTL_SETPROTO:
277 card->ptype = a?ISDN_PTYPE_EURO:ISDN_PTYPE_1TR6;
278 if (!(card->flags & ACT2000_FLAGS_RUNNING))
279 return 0;
280 actcapi_manufacturer_req_net(card);
281 return 0;
282 case ACT2000_IOCTL_SETMSN:
283 if (copy_from_user(tmp, arg,
284 sizeof(tmp)))
285 return -EFAULT;
286 if ((ret = act2000_set_msn(card, tmp)))
287 return ret;
288 if (card->flags & ACT2000_FLAGS_RUNNING)
289 return(actcapi_manufacturer_req_msn(card));
290 return 0;
291 case ACT2000_IOCTL_ADDCARD:
292 if (copy_from_user(&cdef, arg,
293 sizeof(cdef)))
294 return -EFAULT;
295 if (act2000_addcard(cdef.bus, cdef.port, cdef.irq, cdef.id))
296 return -EIO;
297 return 0;
298 case ACT2000_IOCTL_TEST:
299 if (!(card->flags & ACT2000_FLAGS_RUNNING))
300 return -ENODEV;
301 return 0;
302 default:
303 return -EINVAL;
304 }
305 break;
306 case ISDN_CMD_DIAL:
307 if (!card->flags & ACT2000_FLAGS_RUNNING)
308 return -ENODEV;
309 if (!(chan = find_channel(card, c->arg & 0x0f)))
310 break;
311 spin_lock_irqsave(&card->lock, flags);
312 if (chan->fsm_state != ACT2000_STATE_NULL) {
313 spin_unlock_irqrestore(&card->lock, flags);
314 printk(KERN_WARNING "Dial on channel with state %d\n",
315 chan->fsm_state);
316 return -EBUSY;
317 }
318 if (card->ptype == ISDN_PTYPE_EURO)
319 tmp[0] = act2000_find_msn(card, c->parm.setup.eazmsn, 1);
320 else
321 tmp[0] = c->parm.setup.eazmsn[0];
322 chan->fsm_state = ACT2000_STATE_OCALL;
323 chan->callref = 0xffff;
324 spin_unlock_irqrestore(&card->lock, flags);
325 ret = actcapi_connect_req(card, chan, c->parm.setup.phone,
326 tmp[0], c->parm.setup.si1,
327 c->parm.setup.si2);
328 if (ret) {
329 cmd.driver = card->myid;
330 cmd.command = ISDN_STAT_DHUP;
331 cmd.arg &= 0x0f;
332 card->interface.statcallb(&cmd);
333 }
334 return ret;
335 case ISDN_CMD_ACCEPTD:
336 if (!card->flags & ACT2000_FLAGS_RUNNING)
337 return -ENODEV;
338 if (!(chan = find_channel(card, c->arg & 0x0f)))
339 break;
340 if (chan->fsm_state == ACT2000_STATE_ICALL)
341 actcapi_select_b2_protocol_req(card, chan);
342 return 0;
343 case ISDN_CMD_ACCEPTB:
344 if (!card->flags & ACT2000_FLAGS_RUNNING)
345 return -ENODEV;
346 return 0;
347 case ISDN_CMD_HANGUP:
348 if (!card->flags & ACT2000_FLAGS_RUNNING)
349 return -ENODEV;
350 if (!(chan = find_channel(card, c->arg & 0x0f)))
351 break;
352 switch (chan->fsm_state) {
353 case ACT2000_STATE_ICALL:
354 case ACT2000_STATE_BSETUP:
355 actcapi_connect_resp(card, chan, 0x15);
356 break;
357 case ACT2000_STATE_ACTIVE:
358 actcapi_disconnect_b3_req(card, chan);
359 break;
360 }
361 return 0;
362 case ISDN_CMD_SETEAZ:
363 if (!card->flags & ACT2000_FLAGS_RUNNING)
364 return -ENODEV;
365 if (!(chan = find_channel(card, c->arg & 0x0f)))
366 break;
367 if (strlen(c->parm.num)) {
368 if (card->ptype == ISDN_PTYPE_EURO) {
369 chan->eazmask = act2000_find_msn(card, c->parm.num, 0);
370 }
371 if (card->ptype == ISDN_PTYPE_1TR6) {
372 int i;
373 chan->eazmask = 0;
374 for (i = 0; i < strlen(c->parm.num); i++)
375 if (isdigit(c->parm.num[i]))
376 chan->eazmask |= (1 << (c->parm.num[i] - '0'));
377 }
378 } else
379 chan->eazmask = 0x3ff;
380 actcapi_listen_req(card);
381 return 0;
382 case ISDN_CMD_CLREAZ:
383 if (!card->flags & ACT2000_FLAGS_RUNNING)
384 return -ENODEV;
385 if (!(chan = find_channel(card, c->arg & 0x0f)))
386 break;
387 chan->eazmask = 0;
388 actcapi_listen_req(card);
389 return 0;
390 case ISDN_CMD_SETL2:
391 if (!card->flags & ACT2000_FLAGS_RUNNING)
392 return -ENODEV;
393 if (!(chan = find_channel(card, c->arg & 0x0f)))
394 break;
395 chan->l2prot = (c->arg >> 8);
396 return 0;
397 case ISDN_CMD_SETL3:
398 if (!card->flags & ACT2000_FLAGS_RUNNING)
399 return -ENODEV;
400 if ((c->arg >> 8) != ISDN_PROTO_L3_TRANS) {
401 printk(KERN_WARNING "L3 protocol unknown\n");
402 return -1;
403 }
404 if (!(chan = find_channel(card, c->arg & 0x0f)))
405 break;
406 chan->l3prot = (c->arg >> 8);
407 return 0;
408 }
409
410 return -EINVAL;
411}
412
413static int
414act2000_sendbuf(act2000_card *card, int channel, int ack, struct sk_buff *skb)
415{
416 struct sk_buff *xmit_skb;
417 int len;
418 act2000_chan *chan;
419 actcapi_msg *msg;
420
421 if (!(chan = find_channel(card, channel)))
422 return -1;
423 if (chan->fsm_state != ACT2000_STATE_ACTIVE)
424 return -1;
425 len = skb->len;
426 if ((chan->queued + len) >= ACT2000_MAX_QUEUED)
427 return 0;
428 if (!len)
429 return 0;
430 if (skb_headroom(skb) < 19) {
431 printk(KERN_WARNING "act2000_sendbuf: Headroom only %d\n",
432 skb_headroom(skb));
433 xmit_skb = alloc_skb(len + 19, GFP_ATOMIC);
434 if (!xmit_skb) {
435 printk(KERN_WARNING "act2000_sendbuf: Out of memory\n");
436 return 0;
437 }
438 skb_reserve(xmit_skb, 19);
439 memcpy(skb_put(xmit_skb, len), skb->data, len);
440 } else {
441 xmit_skb = skb_clone(skb, GFP_ATOMIC);
442 if (!xmit_skb) {
443 printk(KERN_WARNING "act2000_sendbuf: Out of memory\n");
444 return 0;
445 }
446 }
447 dev_kfree_skb(skb);
448 msg = (actcapi_msg *)skb_push(xmit_skb, 19);
449 msg->hdr.len = 19 + len;
450 msg->hdr.applicationID = 1;
451 msg->hdr.cmd.cmd = 0x86;
452 msg->hdr.cmd.subcmd = 0x00;
453 msg->hdr.msgnum = actcapi_nextsmsg(card);
454 msg->msg.data_b3_req.datalen = len;
455 msg->msg.data_b3_req.blocknr = (msg->hdr.msgnum & 0xff);
456 msg->msg.data_b3_req.fakencci = MAKE_NCCI(chan->plci, 0, chan->ncci);
457 msg->msg.data_b3_req.flags = ack; /* Will be set to 0 on actual sending */
458 actcapi_debug_msg(xmit_skb, 1);
459 chan->queued += len;
460 skb_queue_tail(&card->sndq, xmit_skb);
461 act2000_schedule_tx(card);
462 return len;
463}
464
465
466/* Read the Status-replies from the Interface */
467static int
468act2000_readstatus(u_char __user * buf, int len, act2000_card * card)
469{
470 int count;
471 u_char __user *p;
472
473 for (p = buf, count = 0; count < len; p++, count++) {
474 if (card->status_buf_read == card->status_buf_write)
475 return count;
476 put_user(*card->status_buf_read++, p);
477 if (card->status_buf_read > card->status_buf_end)
478 card->status_buf_read = card->status_buf;
479 }
480 return count;
481}
482
483/*
484 * Find card with given driverId
485 */
486static inline act2000_card *
487act2000_findcard(int driverid)
488{
489 act2000_card *p = cards;
490
491 while (p) {
492 if (p->myid == driverid)
493 return p;
494 p = p->next;
495 }
496 return (act2000_card *) 0;
497}
498
499/*
500 * Wrapper functions for interface to linklevel
501 */
502static int
503if_command(isdn_ctrl * c)
504{
505 act2000_card *card = act2000_findcard(c->driver);
506
507 if (card)
508 return (act2000_command(card, c));
509 printk(KERN_ERR
510 "act2000: if_command %d called with invalid driverId %d!\n",
511 c->command, c->driver);
512 return -ENODEV;
513}
514
515static int
516if_writecmd(const u_char __user *buf, int len, int id, int channel)
517{
518 act2000_card *card = act2000_findcard(id);
519
520 if (card) {
521 if (!card->flags & ACT2000_FLAGS_RUNNING)
522 return -ENODEV;
523 return (len);
524 }
525 printk(KERN_ERR
526 "act2000: if_writecmd called with invalid driverId!\n");
527 return -ENODEV;
528}
529
530static int
531if_readstatus(u_char __user * buf, int len, int id, int channel)
532{
533 act2000_card *card = act2000_findcard(id);
534
535 if (card) {
536 if (!card->flags & ACT2000_FLAGS_RUNNING)
537 return -ENODEV;
538 return (act2000_readstatus(buf, len, card));
539 }
540 printk(KERN_ERR
541 "act2000: if_readstatus called with invalid driverId!\n");
542 return -ENODEV;
543}
544
545static int
546if_sendbuf(int id, int channel, int ack, struct sk_buff *skb)
547{
548 act2000_card *card = act2000_findcard(id);
549
550 if (card) {
551 if (!card->flags & ACT2000_FLAGS_RUNNING)
552 return -ENODEV;
553 return (act2000_sendbuf(card, channel, ack, skb));
554 }
555 printk(KERN_ERR
556 "act2000: if_sendbuf called with invalid driverId!\n");
557 return -ENODEV;
558}
559
560
561/*
562 * Allocate a new card-struct, initialize it
563 * link it into cards-list.
564 */
565static void
566act2000_alloccard(int bus, int port, int irq, char *id)
567{
568 int i;
569 act2000_card *card;
570 if (!(card = (act2000_card *) kmalloc(sizeof(act2000_card), GFP_KERNEL))) {
571 printk(KERN_WARNING
572 "act2000: (%s) Could not allocate card-struct.\n", id);
573 return;
574 }
575 memset((char *) card, 0, sizeof(act2000_card));
576 spin_lock_init(&card->lock);
577 spin_lock_init(&card->mnlock);
578 skb_queue_head_init(&card->sndq);
579 skb_queue_head_init(&card->rcvq);
580 skb_queue_head_init(&card->ackq);
581 INIT_WORK(&card->snd_tq, (void *) (void *) act2000_transmit, card);
582 INIT_WORK(&card->rcv_tq, (void *) (void *) actcapi_dispatch, card);
583 INIT_WORK(&card->poll_tq, (void *) (void *) act2000_receive, card);
584 init_timer(&card->ptimer);
585 card->interface.owner = THIS_MODULE;
586 card->interface.channels = ACT2000_BCH;
587 card->interface.maxbufsize = 4000;
588 card->interface.command = if_command;
589 card->interface.writebuf_skb = if_sendbuf;
590 card->interface.writecmd = if_writecmd;
591 card->interface.readstat = if_readstatus;
592 card->interface.features =
593 ISDN_FEATURE_L2_X75I |
594 ISDN_FEATURE_L2_HDLC |
595 ISDN_FEATURE_L3_TRANS |
596 ISDN_FEATURE_P_UNKNOWN;
597 card->interface.hl_hdrlen = 20;
598 card->ptype = ISDN_PTYPE_EURO;
599 strlcpy(card->interface.id, id, sizeof(card->interface.id));
600 for (i=0; i<ACT2000_BCH; i++) {
601 card->bch[i].plci = 0x8000;
602 card->bch[i].ncci = 0x8000;
603 card->bch[i].l2prot = ISDN_PROTO_L2_X75I;
604 card->bch[i].l3prot = ISDN_PROTO_L3_TRANS;
605 }
606 card->myid = -1;
607 card->bus = bus;
608 card->port = port;
609 card->irq = irq;
610 card->next = cards;
611 cards = card;
612}
613
614/*
615 * register card at linklevel
616 */
617static int
618act2000_registercard(act2000_card * card)
619{
620 switch (card->bus) {
621 case ACT2000_BUS_ISA:
622 break;
623 case ACT2000_BUS_MCA:
624 case ACT2000_BUS_PCMCIA:
625 default:
626 printk(KERN_WARNING
627 "act2000: Illegal BUS type %d\n",
628 card->bus);
629 return -1;
630 }
631 if (!register_isdn(&card->interface)) {
632 printk(KERN_WARNING
633 "act2000: Unable to register %s\n",
634 card->interface.id);
635 return -1;
636 }
637 card->myid = card->interface.channels;
638 sprintf(card->regname, "act2000-isdn (%s)", card->interface.id);
639 return 0;
640}
641
642static void
643unregister_card(act2000_card * card)
644{
645 isdn_ctrl cmd;
646
647 cmd.command = ISDN_STAT_UNLOAD;
648 cmd.driver = card->myid;
649 card->interface.statcallb(&cmd);
650 switch (card->bus) {
651 case ACT2000_BUS_ISA:
652 act2000_isa_release(card);
653 break;
654 case ACT2000_BUS_MCA:
655 case ACT2000_BUS_PCMCIA:
656 default:
657 printk(KERN_WARNING
658 "act2000: Invalid BUS type %d\n",
659 card->bus);
660 break;
661 }
662}
663
664static int
665act2000_addcard(int bus, int port, int irq, char *id)
666{
667 act2000_card *p;
668 act2000_card *q = NULL;
669 int initialized;
670 int added = 0;
671 int failed = 0;
672 int i;
673
674 if (!bus)
675 bus = ACT2000_BUS_ISA;
676 if (port != -1) {
677 /* Port defined, do fixed setup */
678 act2000_alloccard(bus, port, irq, id);
679 } else {
680 /* No port defined, perform autoprobing.
681 * This may result in more than one card detected.
682 */
683 switch (bus) {
684 case ACT2000_BUS_ISA:
685 for (i = 0; i < ISA_NRPORTS; i++)
686 if (act2000_isa_detect(act2000_isa_ports[i])) {
687 printk(KERN_INFO
688 "act2000: Detected ISA card at port 0x%x\n",
689 act2000_isa_ports[i]);
690 act2000_alloccard(bus, act2000_isa_ports[i], irq, id);
691 }
692 break;
693 case ACT2000_BUS_MCA:
694 case ACT2000_BUS_PCMCIA:
695 default:
696 printk(KERN_WARNING
697 "act2000: addcard: Invalid BUS type %d\n",
698 bus);
699 }
700 }
701 if (!cards)
702 return 1;
703 p = cards;
704 while (p) {
705 initialized = 0;
706 if (!p->interface.statcallb) {
707 /* Not yet registered.
708 * Try to register and activate it.
709 */
710 added++;
711 switch (p->bus) {
712 case ACT2000_BUS_ISA:
713 if (act2000_isa_detect(p->port)) {
714 if (act2000_registercard(p))
715 break;
716 if (act2000_isa_config_port(p, p->port)) {
717 printk(KERN_WARNING
718 "act2000: Could not request port 0x%04x\n",
719 p->port);
720 unregister_card(p);
721 p->interface.statcallb = NULL;
722 break;
723 }
724 if (act2000_isa_config_irq(p, p->irq)) {
725 printk(KERN_INFO
726 "act2000: No IRQ available, fallback to polling\n");
727 /* Fall back to polled operation */
728 p->irq = 0;
729 }
730 printk(KERN_INFO
731 "act2000: ISA"
732 "-type card at port "
733 "0x%04x ",
734 p->port);
735 if (p->irq)
736 printk("irq %d\n", p->irq);
737 else
738 printk("polled\n");
739 initialized = 1;
740 }
741 break;
742 case ACT2000_BUS_MCA:
743 case ACT2000_BUS_PCMCIA:
744 default:
745 printk(KERN_WARNING
746 "act2000: addcard: Invalid BUS type %d\n",
747 p->bus);
748 }
749 } else
750 /* Card already initialized */
751 initialized = 1;
752 if (initialized) {
753 /* Init OK, next card ... */
754 q = p;
755 p = p->next;
756 } else {
757 /* Init failed, remove card from list, free memory */
758 printk(KERN_WARNING
759 "act2000: Initialization of %s failed\n",
760 p->interface.id);
761 if (q) {
762 q->next = p->next;
763 kfree(p);
764 p = q->next;
765 } else {
766 cards = p->next;
767 kfree(p);
768 p = cards;
769 }
770 failed++;
771 }
772 }
773 return (added - failed);
774}
775
776#define DRIVERNAME "IBM Active 2000 ISDN driver"
777
778static int __init act2000_init(void)
779{
780 printk(KERN_INFO "%s\n", DRIVERNAME);
781 if (!cards)
782 act2000_addcard(act_bus, act_port, act_irq, act_id);
783 if (!cards)
784 printk(KERN_INFO "act2000: No cards defined yet\n");
785 return 0;
786}
787
788static void __exit act2000_exit(void)
789{
790 act2000_card *card = cards;
791 act2000_card *last;
792 while (card) {
793 unregister_card(card);
794 del_timer(&card->ptimer);
795 card = card->next;
796 }
797 card = cards;
798 while (card) {
799 last = card;
800 card = card->next;
801 act2000_clear_msn(last);
802 kfree(last);
803 }
804 printk(KERN_INFO "%s unloaded\n", DRIVERNAME);
805}
806
807module_init(act2000_init);
808module_exit(act2000_exit);
diff --git a/drivers/isdn/capi/Kconfig b/drivers/isdn/capi/Kconfig
new file mode 100644
index 000000000000..8b6c9a431ffa
--- /dev/null
+++ b/drivers/isdn/capi/Kconfig
@@ -0,0 +1,53 @@
1#
2# Config.in for the CAPI subsystem
3#
4config ISDN_DRV_AVMB1_VERBOSE_REASON
5 bool "Verbose reason code reporting (kernel size +=7K)"
6 depends on ISDN_CAPI
7 help
8 If you say Y here, the AVM B1 driver will give verbose reasons for
9 disconnecting. This will increase the size of the kernel by 7 KB. If
10 unsure, say Y.
11
12config ISDN_CAPI_MIDDLEWARE
13 bool "CAPI2.0 Middleware support (EXPERIMENTAL)"
14 depends on ISDN_CAPI && EXPERIMENTAL
15 help
16 This option will enhance the capabilities of the /dev/capi20
17 interface. It will provide a means of moving a data connection,
18 established via the usual /dev/capi20 interface to a special tty
19 device. If you want to use pppd with pppdcapiplugin to dial up to
20 your ISP, say Y here.
21
22config ISDN_CAPI_CAPI20
23 tristate "CAPI2.0 /dev/capi support"
24 depends on ISDN_CAPI
25 help
26 This option will provide the CAPI 2.0 interface to userspace
27 applications via /dev/capi20. Applications should use the
28 standardized libcapi20 to access this functionality. You should say
29 Y/M here.
30
31config ISDN_CAPI_CAPIFS_BOOL
32 bool "CAPI2.0 filesystem support"
33 depends on ISDN_CAPI_MIDDLEWARE && ISDN_CAPI_CAPI20
34
35config ISDN_CAPI_CAPIFS
36 tristate
37 depends on ISDN_CAPI_CAPIFS_BOOL
38 default ISDN_CAPI_CAPI20
39 help
40 This option provides a special file system, similar to /dev/pts with
41 device nodes for the special ttys established by using the
42 middleware extension above. If you want to use pppd with
43 pppdcapiplugin to dial up to your ISP, say Y here.
44
45config ISDN_CAPI_CAPIDRV
46 tristate "CAPI2.0 capidrv interface support"
47 depends on ISDN_CAPI && ISDN_I4L
48 help
49 This option provides the glue code to hook up CAPI driven cards to
50 the legacy isdn4linux link layer. If you have a card which is
51 supported by a CAPI driver, but still want to use old features like
52 ippp interfaces or ttyI emulation, say Y/M here.
53
diff --git a/drivers/isdn/capi/Makefile b/drivers/isdn/capi/Makefile
new file mode 100644
index 000000000000..57123e3e4978
--- /dev/null
+++ b/drivers/isdn/capi/Makefile
@@ -0,0 +1,15 @@
1# Makefile for the CAPI subsystem.
2
3# Ordering constraints: kernelcapi.o first
4
5# Each configuration option enables a list of files.
6
7obj-$(CONFIG_ISDN_CAPI) += kernelcapi.o
8obj-$(CONFIG_ISDN_CAPI_CAPI20) += capi.o
9obj-$(CONFIG_ISDN_CAPI_CAPIDRV) += capidrv.o
10obj-$(CONFIG_ISDN_CAPI_CAPIFS) += capifs.o
11
12# Multipart objects.
13
14kernelcapi-y := kcapi.o capiutil.o capilib.o
15kernelcapi-$(CONFIG_PROC_FS) += kcapi_proc.o
diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c
new file mode 100644
index 000000000000..06163538bb20
--- /dev/null
+++ b/drivers/isdn/capi/capi.c
@@ -0,0 +1,1554 @@
1/* $Id: capi.c,v 1.1.2.7 2004/04/28 09:48:59 armin Exp $
2 *
3 * CAPI 2.0 Interface for Linux
4 *
5 * Copyright 1996 by Carsten Paeth <calle@calle.de>
6 *
7 * This software may be used and distributed according to the terms
8 * of the GNU General Public License, incorporated herein by reference.
9 *
10 */
11
12#include <linux/config.h>
13#include <linux/module.h>
14#include <linux/errno.h>
15#include <linux/kernel.h>
16#include <linux/major.h>
17#include <linux/sched.h>
18#include <linux/slab.h>
19#include <linux/fcntl.h>
20#include <linux/fs.h>
21#include <linux/signal.h>
22#include <linux/mm.h>
23#include <linux/smp_lock.h>
24#include <linux/timer.h>
25#include <linux/wait.h>
26#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
27#include <linux/tty.h>
28#ifdef CONFIG_PPP
29#include <linux/netdevice.h>
30#include <linux/ppp_defs.h>
31#include <linux/if_ppp.h>
32#endif /* CONFIG_PPP */
33#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
34#include <linux/skbuff.h>
35#include <linux/proc_fs.h>
36#include <linux/poll.h>
37#include <linux/capi.h>
38#include <linux/kernelcapi.h>
39#include <linux/init.h>
40#include <linux/device.h>
41#include <linux/moduleparam.h>
42#include <linux/devfs_fs_kernel.h>
43#include <linux/isdn/capiutil.h>
44#include <linux/isdn/capicmd.h>
45#if defined(CONFIG_ISDN_CAPI_CAPIFS) || defined(CONFIG_ISDN_CAPI_CAPIFS_MODULE)
46#include "capifs.h"
47#endif
48
49static char *revision = "$Revision: 1.1.2.7 $";
50
51MODULE_DESCRIPTION("CAPI4Linux: Userspace /dev/capi20 interface");
52MODULE_AUTHOR("Carsten Paeth");
53MODULE_LICENSE("GPL");
54
55#undef _DEBUG_REFCOUNT /* alloc/free and open/close debug */
56#undef _DEBUG_TTYFUNCS /* call to tty_driver */
57#undef _DEBUG_DATAFLOW /* data flow */
58
59/* -------- driver information -------------------------------------- */
60
61static struct class_simple *capi_class;
62
63int capi_major = 68; /* allocated */
64#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
65#define CAPINC_NR_PORTS 32
66#define CAPINC_MAX_PORTS 256
67int capi_ttymajor = 191;
68int capi_ttyminors = CAPINC_NR_PORTS;
69#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
70
71module_param_named(major, capi_major, uint, 0);
72#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
73module_param_named(ttymajor, capi_ttymajor, uint, 0);
74module_param_named(ttyminors, capi_ttyminors, uint, 0);
75#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
76
77/* -------- defines ------------------------------------------------- */
78
79#define CAPINC_MAX_RECVQUEUE 10
80#define CAPINC_MAX_SENDQUEUE 10
81#define CAPI_MAX_BLKSIZE 2048
82
83/* -------- data structures ----------------------------------------- */
84
85struct capidev;
86struct capincci;
87#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
88struct capiminor;
89
90struct capiminor {
91 struct list_head list;
92 struct capincci *nccip;
93 unsigned int minor;
94
95 struct capi20_appl *ap;
96 u32 ncci;
97 u16 datahandle;
98 u16 msgid;
99
100 struct tty_struct *tty;
101 int ttyinstop;
102 int ttyoutstop;
103 struct sk_buff *ttyskb;
104 atomic_t ttyopencount;
105
106 struct sk_buff_head inqueue;
107 int inbytes;
108 struct sk_buff_head outqueue;
109 int outbytes;
110
111 /* transmit path */
112 struct datahandle_queue {
113 struct datahandle_queue *next;
114 u16 datahandle;
115 } *ackqueue;
116 int nack;
117
118};
119#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
120
121struct capincci {
122 struct capincci *next;
123 u32 ncci;
124 struct capidev *cdev;
125#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
126 struct capiminor *minorp;
127#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
128};
129
130struct capidev {
131 struct list_head list;
132 struct capi20_appl ap;
133 u16 errcode;
134 unsigned userflags;
135
136 struct sk_buff_head recvqueue;
137 wait_queue_head_t recvwait;
138
139 struct capincci *nccis;
140
141 struct semaphore ncci_list_sem;
142};
143
144/* -------- global variables ---------------------------------------- */
145
146static DEFINE_RWLOCK(capidev_list_lock);
147static LIST_HEAD(capidev_list);
148
149#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
150static DEFINE_RWLOCK(capiminor_list_lock);
151static LIST_HEAD(capiminor_list);
152#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
153
154#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
155/* -------- datahandles --------------------------------------------- */
156
157static int capincci_add_ack(struct capiminor *mp, u16 datahandle)
158{
159 struct datahandle_queue *n, **pp;
160
161 n = kmalloc(sizeof(*n), GFP_ATOMIC);
162 if (!n) {
163 printk(KERN_ERR "capi: alloc datahandle failed\n");
164 return -1;
165 }
166 n->next = NULL;
167 n->datahandle = datahandle;
168 for (pp = &mp->ackqueue; *pp; pp = &(*pp)->next) ;
169 *pp = n;
170 mp->nack++;
171 return 0;
172}
173
174static int capiminor_del_ack(struct capiminor *mp, u16 datahandle)
175{
176 struct datahandle_queue **pp, *p;
177
178 for (pp = &mp->ackqueue; *pp; pp = &(*pp)->next) {
179 if ((*pp)->datahandle == datahandle) {
180 p = *pp;
181 *pp = (*pp)->next;
182 kfree(p);
183 mp->nack--;
184 return 0;
185 }
186 }
187 return -1;
188}
189
190static void capiminor_del_all_ack(struct capiminor *mp)
191{
192 struct datahandle_queue **pp, *p;
193
194 pp = &mp->ackqueue;
195 while (*pp) {
196 p = *pp;
197 *pp = (*pp)->next;
198 kfree(p);
199 mp->nack--;
200 }
201}
202
203
204/* -------- struct capiminor ---------------------------------------- */
205
206static struct capiminor *capiminor_alloc(struct capi20_appl *ap, u32 ncci)
207{
208 struct capiminor *mp, *p;
209 unsigned int minor = 0;
210 unsigned long flags;
211
212 mp = kmalloc(sizeof(*mp), GFP_ATOMIC);
213 if (!mp) {
214 printk(KERN_ERR "capi: can't alloc capiminor\n");
215 return NULL;
216 }
217
218 memset(mp, 0, sizeof(struct capiminor));
219 mp->ap = ap;
220 mp->ncci = ncci;
221 mp->msgid = 0;
222 atomic_set(&mp->ttyopencount,0);
223
224 skb_queue_head_init(&mp->inqueue);
225 skb_queue_head_init(&mp->outqueue);
226
227 /* Allocate the least unused minor number.
228 */
229 write_lock_irqsave(&capiminor_list_lock, flags);
230 if (list_empty(&capiminor_list))
231 list_add(&mp->list, &capiminor_list);
232 else {
233 list_for_each_entry(p, &capiminor_list, list) {
234 if (p->minor > minor)
235 break;
236 minor++;
237 }
238
239 if (minor < capi_ttyminors) {
240 mp->minor = minor;
241 list_add(&mp->list, p->list.prev);
242 }
243 }
244 write_unlock_irqrestore(&capiminor_list_lock, flags);
245
246 if (!(minor < capi_ttyminors)) {
247 printk(KERN_NOTICE "capi: out of minors\n");
248 kfree(mp);
249 return NULL;
250 }
251
252 return mp;
253}
254
255static void capiminor_free(struct capiminor *mp)
256{
257 unsigned long flags;
258
259 write_lock_irqsave(&capiminor_list_lock, flags);
260 list_del(&mp->list);
261 write_unlock_irqrestore(&capiminor_list_lock, flags);
262
263 if (mp->ttyskb) kfree_skb(mp->ttyskb);
264 mp->ttyskb = NULL;
265 skb_queue_purge(&mp->inqueue);
266 skb_queue_purge(&mp->outqueue);
267 capiminor_del_all_ack(mp);
268 kfree(mp);
269}
270
271struct capiminor *capiminor_find(unsigned int minor)
272{
273 struct list_head *l;
274 struct capiminor *p = NULL;
275
276 read_lock(&capiminor_list_lock);
277 list_for_each(l, &capiminor_list) {
278 p = list_entry(l, struct capiminor, list);
279 if (p->minor == minor)
280 break;
281 }
282 read_unlock(&capiminor_list_lock);
283 if (l == &capiminor_list)
284 return NULL;
285
286 return p;
287}
288#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
289
290/* -------- struct capincci ----------------------------------------- */
291
292static struct capincci *capincci_alloc(struct capidev *cdev, u32 ncci)
293{
294 struct capincci *np, **pp;
295#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
296 struct capiminor *mp = NULL;
297#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
298
299 np = kmalloc(sizeof(*np), GFP_ATOMIC);
300 if (!np)
301 return NULL;
302 memset(np, 0, sizeof(struct capincci));
303 np->ncci = ncci;
304 np->cdev = cdev;
305#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
306 mp = NULL;
307 if (cdev->userflags & CAPIFLAG_HIGHJACKING)
308 mp = np->minorp = capiminor_alloc(&cdev->ap, ncci);
309 if (mp) {
310 mp->nccip = np;
311#ifdef _DEBUG_REFCOUNT
312 printk(KERN_DEBUG "set mp->nccip\n");
313#endif
314#if defined(CONFIG_ISDN_CAPI_CAPIFS) || defined(CONFIG_ISDN_CAPI_CAPIFS_MODULE)
315 capifs_new_ncci(mp->minor, MKDEV(capi_ttymajor, mp->minor));
316#endif
317 }
318#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
319 for (pp=&cdev->nccis; *pp; pp = &(*pp)->next)
320 ;
321 *pp = np;
322 return np;
323}
324
325static void capincci_free(struct capidev *cdev, u32 ncci)
326{
327 struct capincci *np, **pp;
328#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
329 struct capiminor *mp;
330#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
331
332 pp=&cdev->nccis;
333 while (*pp) {
334 np = *pp;
335 if (ncci == 0xffffffff || np->ncci == ncci) {
336 *pp = (*pp)->next;
337#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
338 if ((mp = np->minorp) != 0) {
339#if defined(CONFIG_ISDN_CAPI_CAPIFS) || defined(CONFIG_ISDN_CAPI_CAPIFS_MODULE)
340 capifs_free_ncci(mp->minor);
341#endif
342 if (mp->tty) {
343 mp->nccip = NULL;
344#ifdef _DEBUG_REFCOUNT
345 printk(KERN_DEBUG "reset mp->nccip\n");
346#endif
347 tty_hangup(mp->tty);
348 } else {
349 capiminor_free(mp);
350 }
351 }
352#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
353 kfree(np);
354 if (*pp == 0) return;
355 } else {
356 pp = &(*pp)->next;
357 }
358 }
359}
360
361static struct capincci *capincci_find(struct capidev *cdev, u32 ncci)
362{
363 struct capincci *p;
364
365 for (p=cdev->nccis; p ; p = p->next) {
366 if (p->ncci == ncci)
367 break;
368 }
369 return p;
370}
371
372/* -------- struct capidev ------------------------------------------ */
373
374static struct capidev *capidev_alloc(void)
375{
376 struct capidev *cdev;
377 unsigned long flags;
378
379 cdev = kmalloc(sizeof(*cdev), GFP_KERNEL);
380 if (!cdev)
381 return NULL;
382 memset(cdev, 0, sizeof(struct capidev));
383
384 init_MUTEX(&cdev->ncci_list_sem);
385 skb_queue_head_init(&cdev->recvqueue);
386 init_waitqueue_head(&cdev->recvwait);
387 write_lock_irqsave(&capidev_list_lock, flags);
388 list_add_tail(&cdev->list, &capidev_list);
389 write_unlock_irqrestore(&capidev_list_lock, flags);
390 return cdev;
391}
392
393static void capidev_free(struct capidev *cdev)
394{
395 unsigned long flags;
396
397 if (cdev->ap.applid) {
398 capi20_release(&cdev->ap);
399 cdev->ap.applid = 0;
400 }
401 skb_queue_purge(&cdev->recvqueue);
402
403 down(&cdev->ncci_list_sem);
404 capincci_free(cdev, 0xffffffff);
405 up(&cdev->ncci_list_sem);
406
407 write_lock_irqsave(&capidev_list_lock, flags);
408 list_del(&cdev->list);
409 write_unlock_irqrestore(&capidev_list_lock, flags);
410 kfree(cdev);
411}
412
413#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
414/* -------- handle data queue --------------------------------------- */
415
416static struct sk_buff *
417gen_data_b3_resp_for(struct capiminor *mp, struct sk_buff *skb)
418{
419 struct sk_buff *nskb;
420 nskb = alloc_skb(CAPI_DATA_B3_RESP_LEN, GFP_ATOMIC);
421 if (nskb) {
422 u16 datahandle = CAPIMSG_U16(skb->data,CAPIMSG_BASELEN+4+4+2);
423 unsigned char *s = skb_put(nskb, CAPI_DATA_B3_RESP_LEN);
424 capimsg_setu16(s, 0, CAPI_DATA_B3_RESP_LEN);
425 capimsg_setu16(s, 2, mp->ap->applid);
426 capimsg_setu8 (s, 4, CAPI_DATA_B3);
427 capimsg_setu8 (s, 5, CAPI_RESP);
428 capimsg_setu16(s, 6, mp->msgid++);
429 capimsg_setu32(s, 8, mp->ncci);
430 capimsg_setu16(s, 12, datahandle);
431 }
432 return nskb;
433}
434
435static int handle_recv_skb(struct capiminor *mp, struct sk_buff *skb)
436{
437 struct sk_buff *nskb;
438 int datalen;
439 u16 errcode, datahandle;
440 struct tty_ldisc *ld;
441
442 datalen = skb->len - CAPIMSG_LEN(skb->data);
443 if (mp->tty == NULL)
444 {
445#ifdef _DEBUG_DATAFLOW
446 printk(KERN_DEBUG "capi: currently no receiver\n");
447#endif
448 return -1;
449 }
450
451 ld = tty_ldisc_ref(mp->tty);
452 if (ld == NULL)
453 return -1;
454 if (ld->receive_buf == NULL) {
455#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS)
456 printk(KERN_DEBUG "capi: ldisc has no receive_buf function\n");
457#endif
458 goto bad;
459 }
460 if (mp->ttyinstop) {
461#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS)
462 printk(KERN_DEBUG "capi: recv tty throttled\n");
463#endif
464 goto bad;
465 }
466 if (ld->receive_room &&
467 ld->receive_room(mp->tty) < datalen) {
468#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS)
469 printk(KERN_DEBUG "capi: no room in tty\n");
470#endif
471 goto bad;
472 }
473 if ((nskb = gen_data_b3_resp_for(mp, skb)) == 0) {
474 printk(KERN_ERR "capi: gen_data_b3_resp failed\n");
475 goto bad;
476 }
477 datahandle = CAPIMSG_U16(skb->data,CAPIMSG_BASELEN+4);
478 errcode = capi20_put_message(mp->ap, nskb);
479 if (errcode != CAPI_NOERROR) {
480 printk(KERN_ERR "capi: send DATA_B3_RESP failed=%x\n",
481 errcode);
482 kfree_skb(nskb);
483 goto bad;
484 }
485 (void)skb_pull(skb, CAPIMSG_LEN(skb->data));
486#ifdef _DEBUG_DATAFLOW
487 printk(KERN_DEBUG "capi: DATA_B3_RESP %u len=%d => ldisc\n",
488 datahandle, skb->len);
489#endif
490 ld->receive_buf(mp->tty, skb->data, NULL, skb->len);
491 kfree_skb(skb);
492 tty_ldisc_deref(ld);
493 return 0;
494bad:
495 tty_ldisc_deref(ld);
496 return -1;
497}
498
499static void handle_minor_recv(struct capiminor *mp)
500{
501 struct sk_buff *skb;
502 while ((skb = skb_dequeue(&mp->inqueue)) != 0) {
503 unsigned int len = skb->len;
504 mp->inbytes -= len;
505 if (handle_recv_skb(mp, skb) < 0) {
506 skb_queue_head(&mp->inqueue, skb);
507 mp->inbytes += len;
508 return;
509 }
510 }
511}
512
513static int handle_minor_send(struct capiminor *mp)
514{
515 struct sk_buff *skb;
516 u16 len;
517 int count = 0;
518 u16 errcode;
519 u16 datahandle;
520
521 if (mp->tty && mp->ttyoutstop) {
522#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS)
523 printk(KERN_DEBUG "capi: send: tty stopped\n");
524#endif
525 return 0;
526 }
527
528 while ((skb = skb_dequeue(&mp->outqueue)) != 0) {
529 datahandle = mp->datahandle;
530 len = (u16)skb->len;
531 skb_push(skb, CAPI_DATA_B3_REQ_LEN);
532 memset(skb->data, 0, CAPI_DATA_B3_REQ_LEN);
533 capimsg_setu16(skb->data, 0, CAPI_DATA_B3_REQ_LEN);
534 capimsg_setu16(skb->data, 2, mp->ap->applid);
535 capimsg_setu8 (skb->data, 4, CAPI_DATA_B3);
536 capimsg_setu8 (skb->data, 5, CAPI_REQ);
537 capimsg_setu16(skb->data, 6, mp->msgid++);
538 capimsg_setu32(skb->data, 8, mp->ncci); /* NCCI */
539 capimsg_setu32(skb->data, 12, (u32) skb->data); /* Data32 */
540 capimsg_setu16(skb->data, 16, len); /* Data length */
541 capimsg_setu16(skb->data, 18, datahandle);
542 capimsg_setu16(skb->data, 20, 0); /* Flags */
543
544 if (capincci_add_ack(mp, datahandle) < 0) {
545 skb_pull(skb, CAPI_DATA_B3_REQ_LEN);
546 skb_queue_head(&mp->outqueue, skb);
547 return count;
548 }
549 errcode = capi20_put_message(mp->ap, skb);
550 if (errcode == CAPI_NOERROR) {
551 mp->datahandle++;
552 count++;
553 mp->outbytes -= len;
554#ifdef _DEBUG_DATAFLOW
555 printk(KERN_DEBUG "capi: DATA_B3_REQ %u len=%u\n",
556 datahandle, len);
557#endif
558 continue;
559 }
560 capiminor_del_ack(mp, datahandle);
561
562 if (errcode == CAPI_SENDQUEUEFULL) {
563 skb_pull(skb, CAPI_DATA_B3_REQ_LEN);
564 skb_queue_head(&mp->outqueue, skb);
565 break;
566 }
567
568 /* ups, drop packet */
569 printk(KERN_ERR "capi: put_message = %x\n", errcode);
570 mp->outbytes -= len;
571 kfree_skb(skb);
572 }
573 return count;
574}
575
576#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
577/* -------- function called by lower level -------------------------- */
578
579static void capi_recv_message(struct capi20_appl *ap, struct sk_buff *skb)
580{
581 struct capidev *cdev = ap->private;
582#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
583 struct capiminor *mp;
584 u16 datahandle;
585#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
586 struct capincci *np;
587 u32 ncci;
588
589 if (CAPIMSG_CMD(skb->data) == CAPI_CONNECT_B3_CONF) {
590 u16 info = CAPIMSG_U16(skb->data, 12); // Info field
591 if (info == 0) {
592 down(&cdev->ncci_list_sem);
593 capincci_alloc(cdev, CAPIMSG_NCCI(skb->data));
594 up(&cdev->ncci_list_sem);
595 }
596 }
597 if (CAPIMSG_CMD(skb->data) == CAPI_CONNECT_B3_IND) {
598 down(&cdev->ncci_list_sem);
599 capincci_alloc(cdev, CAPIMSG_NCCI(skb->data));
600 up(&cdev->ncci_list_sem);
601 }
602 if (CAPIMSG_COMMAND(skb->data) != CAPI_DATA_B3) {
603 skb_queue_tail(&cdev->recvqueue, skb);
604 wake_up_interruptible(&cdev->recvwait);
605 return;
606 }
607 ncci = CAPIMSG_CONTROL(skb->data);
608 for (np = cdev->nccis; np && np->ncci != ncci; np = np->next)
609 ;
610 if (!np) {
611 printk(KERN_ERR "BUG: capi_signal: ncci not found\n");
612 skb_queue_tail(&cdev->recvqueue, skb);
613 wake_up_interruptible(&cdev->recvwait);
614 return;
615 }
616#ifndef CONFIG_ISDN_CAPI_MIDDLEWARE
617 skb_queue_tail(&cdev->recvqueue, skb);
618 wake_up_interruptible(&cdev->recvwait);
619#else /* CONFIG_ISDN_CAPI_MIDDLEWARE */
620 mp = np->minorp;
621 if (!mp) {
622 skb_queue_tail(&cdev->recvqueue, skb);
623 wake_up_interruptible(&cdev->recvwait);
624 return;
625 }
626
627
628 if (CAPIMSG_SUBCOMMAND(skb->data) == CAPI_IND) {
629
630 datahandle = CAPIMSG_U16(skb->data, CAPIMSG_BASELEN+4+4+2);
631#ifdef _DEBUG_DATAFLOW
632 printk(KERN_DEBUG "capi_signal: DATA_B3_IND %u len=%d\n",
633 datahandle, skb->len-CAPIMSG_LEN(skb->data));
634#endif
635 skb_queue_tail(&mp->inqueue, skb);
636 mp->inbytes += skb->len;
637 handle_minor_recv(mp);
638
639 } else if (CAPIMSG_SUBCOMMAND(skb->data) == CAPI_CONF) {
640
641 datahandle = CAPIMSG_U16(skb->data, CAPIMSG_BASELEN+4);
642#ifdef _DEBUG_DATAFLOW
643 printk(KERN_DEBUG "capi_signal: DATA_B3_CONF %u 0x%x\n",
644 datahandle,
645 CAPIMSG_U16(skb->data, CAPIMSG_BASELEN+4+2));
646#endif
647 kfree_skb(skb);
648 (void)capiminor_del_ack(mp, datahandle);
649 if (mp->tty)
650 tty_wakeup(mp->tty);
651 (void)handle_minor_send(mp);
652
653 } else {
654 /* ups, let capi application handle it :-) */
655 skb_queue_tail(&cdev->recvqueue, skb);
656 wake_up_interruptible(&cdev->recvwait);
657 }
658#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
659}
660
661/* -------- file_operations for capidev ----------------------------- */
662
663static ssize_t
664capi_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
665{
666 struct capidev *cdev = (struct capidev *)file->private_data;
667 struct sk_buff *skb;
668 size_t copied;
669
670 if (!cdev->ap.applid)
671 return -ENODEV;
672
673 if ((skb = skb_dequeue(&cdev->recvqueue)) == 0) {
674
675 if (file->f_flags & O_NONBLOCK)
676 return -EAGAIN;
677
678 for (;;) {
679 interruptible_sleep_on(&cdev->recvwait);
680 if ((skb = skb_dequeue(&cdev->recvqueue)) != 0)
681 break;
682 if (signal_pending(current))
683 break;
684 }
685 if (skb == 0)
686 return -ERESTARTNOHAND;
687 }
688 if (skb->len > count) {
689 skb_queue_head(&cdev->recvqueue, skb);
690 return -EMSGSIZE;
691 }
692 if (copy_to_user(buf, skb->data, skb->len)) {
693 skb_queue_head(&cdev->recvqueue, skb);
694 return -EFAULT;
695 }
696 copied = skb->len;
697
698 kfree_skb(skb);
699
700 return copied;
701}
702
703static ssize_t
704capi_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
705{
706 struct capidev *cdev = (struct capidev *)file->private_data;
707 struct sk_buff *skb;
708 u16 mlen;
709
710 if (!cdev->ap.applid)
711 return -ENODEV;
712
713 skb = alloc_skb(count, GFP_USER);
714 if (!skb)
715 return -ENOMEM;
716
717 if (copy_from_user(skb_put(skb, count), buf, count)) {
718 kfree_skb(skb);
719 return -EFAULT;
720 }
721 mlen = CAPIMSG_LEN(skb->data);
722 if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_REQ) {
723 if ((size_t)(mlen + CAPIMSG_DATALEN(skb->data)) != count) {
724 kfree_skb(skb);
725 return -EINVAL;
726 }
727 } else {
728 if (mlen != count) {
729 kfree_skb(skb);
730 return -EINVAL;
731 }
732 }
733 CAPIMSG_SETAPPID(skb->data, cdev->ap.applid);
734
735 if (CAPIMSG_CMD(skb->data) == CAPI_DISCONNECT_B3_RESP) {
736 down(&cdev->ncci_list_sem);
737 capincci_free(cdev, CAPIMSG_NCCI(skb->data));
738 up(&cdev->ncci_list_sem);
739 }
740
741 cdev->errcode = capi20_put_message(&cdev->ap, skb);
742
743 if (cdev->errcode) {
744 kfree_skb(skb);
745 return -EIO;
746 }
747 return count;
748}
749
750static unsigned int
751capi_poll(struct file *file, poll_table * wait)
752{
753 struct capidev *cdev = (struct capidev *)file->private_data;
754 unsigned int mask = 0;
755
756 if (!cdev->ap.applid)
757 return POLLERR;
758
759 poll_wait(file, &(cdev->recvwait), wait);
760 mask = POLLOUT | POLLWRNORM;
761 if (!skb_queue_empty(&cdev->recvqueue))
762 mask |= POLLIN | POLLRDNORM;
763 return mask;
764}
765
766static int
767capi_ioctl(struct inode *inode, struct file *file,
768 unsigned int cmd, unsigned long arg)
769{
770 struct capidev *cdev = file->private_data;
771 struct capi20_appl *ap = &cdev->ap;
772 capi_ioctl_struct data;
773 int retval = -EINVAL;
774 void __user *argp = (void __user *)arg;
775
776 switch (cmd) {
777 case CAPI_REGISTER:
778 {
779 if (ap->applid)
780 return -EEXIST;
781
782 if (copy_from_user(&cdev->ap.rparam, argp,
783 sizeof(struct capi_register_params)))
784 return -EFAULT;
785
786 cdev->ap.private = cdev;
787 cdev->ap.recv_message = capi_recv_message;
788 cdev->errcode = capi20_register(ap);
789 if (cdev->errcode) {
790 ap->applid = 0;
791 return -EIO;
792 }
793 }
794 return (int)ap->applid;
795
796 case CAPI_GET_VERSION:
797 {
798 if (copy_from_user(&data.contr, argp,
799 sizeof(data.contr)))
800 return -EFAULT;
801 cdev->errcode = capi20_get_version(data.contr, &data.version);
802 if (cdev->errcode)
803 return -EIO;
804 if (copy_to_user(argp, &data.version,
805 sizeof(data.version)))
806 return -EFAULT;
807 }
808 return 0;
809
810 case CAPI_GET_SERIAL:
811 {
812 if (copy_from_user(&data.contr, argp,
813 sizeof(data.contr)))
814 return -EFAULT;
815 cdev->errcode = capi20_get_serial (data.contr, data.serial);
816 if (cdev->errcode)
817 return -EIO;
818 if (copy_to_user(argp, data.serial,
819 sizeof(data.serial)))
820 return -EFAULT;
821 }
822 return 0;
823 case CAPI_GET_PROFILE:
824 {
825 if (copy_from_user(&data.contr, argp,
826 sizeof(data.contr)))
827 return -EFAULT;
828
829 if (data.contr == 0) {
830 cdev->errcode = capi20_get_profile(data.contr, &data.profile);
831 if (cdev->errcode)
832 return -EIO;
833
834 retval = copy_to_user(argp,
835 &data.profile.ncontroller,
836 sizeof(data.profile.ncontroller));
837
838 } else {
839 cdev->errcode = capi20_get_profile(data.contr, &data.profile);
840 if (cdev->errcode)
841 return -EIO;
842
843 retval = copy_to_user(argp, &data.profile,
844 sizeof(data.profile));
845 }
846 if (retval)
847 return -EFAULT;
848 }
849 return 0;
850
851 case CAPI_GET_MANUFACTURER:
852 {
853 if (copy_from_user(&data.contr, argp,
854 sizeof(data.contr)))
855 return -EFAULT;
856 cdev->errcode = capi20_get_manufacturer(data.contr, data.manufacturer);
857 if (cdev->errcode)
858 return -EIO;
859
860 if (copy_to_user(argp, data.manufacturer,
861 sizeof(data.manufacturer)))
862 return -EFAULT;
863
864 }
865 return 0;
866 case CAPI_GET_ERRCODE:
867 data.errcode = cdev->errcode;
868 cdev->errcode = CAPI_NOERROR;
869 if (arg) {
870 if (copy_to_user(argp, &data.errcode,
871 sizeof(data.errcode)))
872 return -EFAULT;
873 }
874 return data.errcode;
875
876 case CAPI_INSTALLED:
877 if (capi20_isinstalled() == CAPI_NOERROR)
878 return 0;
879 return -ENXIO;
880
881 case CAPI_MANUFACTURER_CMD:
882 {
883 struct capi_manufacturer_cmd mcmd;
884 if (!capable(CAP_SYS_ADMIN))
885 return -EPERM;
886 if (copy_from_user(&mcmd, argp, sizeof(mcmd)))
887 return -EFAULT;
888 return capi20_manufacturer(mcmd.cmd, mcmd.data);
889 }
890 return 0;
891
892 case CAPI_SET_FLAGS:
893 case CAPI_CLR_FLAGS:
894 {
895 unsigned userflags;
896 if (copy_from_user(&userflags, argp,
897 sizeof(userflags)))
898 return -EFAULT;
899 if (cmd == CAPI_SET_FLAGS)
900 cdev->userflags |= userflags;
901 else
902 cdev->userflags &= ~userflags;
903 }
904 return 0;
905
906 case CAPI_GET_FLAGS:
907 if (copy_to_user(argp, &cdev->userflags,
908 sizeof(cdev->userflags)))
909 return -EFAULT;
910 return 0;
911
912 case CAPI_NCCI_OPENCOUNT:
913 {
914 struct capincci *nccip;
915#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
916 struct capiminor *mp;
917#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
918 unsigned ncci;
919 int count = 0;
920 if (copy_from_user(&ncci, argp, sizeof(ncci)))
921 return -EFAULT;
922
923 down(&cdev->ncci_list_sem);
924 if ((nccip = capincci_find(cdev, (u32) ncci)) == 0) {
925 up(&cdev->ncci_list_sem);
926 return 0;
927 }
928#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
929 if ((mp = nccip->minorp) != 0) {
930 count += atomic_read(&mp->ttyopencount);
931 }
932#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
933 up(&cdev->ncci_list_sem);
934 return count;
935 }
936 return 0;
937
938#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
939 case CAPI_NCCI_GETUNIT:
940 {
941 struct capincci *nccip;
942 struct capiminor *mp;
943 unsigned ncci;
944 int unit = 0;
945 if (copy_from_user(&ncci, argp,
946 sizeof(ncci)))
947 return -EFAULT;
948 down(&cdev->ncci_list_sem);
949 nccip = capincci_find(cdev, (u32) ncci);
950 if (!nccip || (mp = nccip->minorp) == 0) {
951 up(&cdev->ncci_list_sem);
952 return -ESRCH;
953 }
954 unit = mp->minor;
955 up(&cdev->ncci_list_sem);
956 return unit;
957 }
958 return 0;
959#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
960 }
961 return -EINVAL;
962}
963
964static int
965capi_open(struct inode *inode, struct file *file)
966{
967 if (file->private_data)
968 return -EEXIST;
969
970 if ((file->private_data = capidev_alloc()) == 0)
971 return -ENOMEM;
972
973 return nonseekable_open(inode, file);
974}
975
976static int
977capi_release(struct inode *inode, struct file *file)
978{
979 struct capidev *cdev = (struct capidev *)file->private_data;
980
981 capidev_free(cdev);
982 file->private_data = NULL;
983
984 return 0;
985}
986
987static struct file_operations capi_fops =
988{
989 .owner = THIS_MODULE,
990 .llseek = no_llseek,
991 .read = capi_read,
992 .write = capi_write,
993 .poll = capi_poll,
994 .ioctl = capi_ioctl,
995 .open = capi_open,
996 .release = capi_release,
997};
998
999#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
1000/* -------- tty_operations for capincci ----------------------------- */
1001
1002static int capinc_tty_open(struct tty_struct * tty, struct file * file)
1003{
1004 struct capiminor *mp;
1005
1006 if ((mp = capiminor_find(iminor(file->f_dentry->d_inode))) == 0)
1007 return -ENXIO;
1008 if (mp->nccip == 0)
1009 return -ENXIO;
1010
1011 tty->driver_data = (void *)mp;
1012
1013 if (atomic_read(&mp->ttyopencount) == 0)
1014 mp->tty = tty;
1015 atomic_inc(&mp->ttyopencount);
1016#ifdef _DEBUG_REFCOUNT
1017 printk(KERN_DEBUG "capinc_tty_open ocount=%d\n", atomic_read(&mp->ttyopencount));
1018#endif
1019 handle_minor_recv(mp);
1020 return 0;
1021}
1022
1023static void capinc_tty_close(struct tty_struct * tty, struct file * file)
1024{
1025 struct capiminor *mp;
1026
1027 mp = (struct capiminor *)tty->driver_data;
1028 if (mp) {
1029 if (atomic_dec_and_test(&mp->ttyopencount)) {
1030#ifdef _DEBUG_REFCOUNT
1031 printk(KERN_DEBUG "capinc_tty_close lastclose\n");
1032#endif
1033 tty->driver_data = NULL;
1034 mp->tty = NULL;
1035 }
1036#ifdef _DEBUG_REFCOUNT
1037 printk(KERN_DEBUG "capinc_tty_close ocount=%d\n", atomic_read(&mp->ttyopencount));
1038#endif
1039 if (mp->nccip == 0)
1040 capiminor_free(mp);
1041 }
1042
1043#ifdef _DEBUG_REFCOUNT
1044 printk(KERN_DEBUG "capinc_tty_close\n");
1045#endif
1046}
1047
1048static int capinc_tty_write(struct tty_struct * tty,
1049 const unsigned char *buf, int count)
1050{
1051 struct capiminor *mp = (struct capiminor *)tty->driver_data;
1052 struct sk_buff *skb;
1053
1054#ifdef _DEBUG_TTYFUNCS
1055 printk(KERN_DEBUG "capinc_tty_write(count=%d)\n", count);
1056#endif
1057
1058 if (!mp || !mp->nccip) {
1059#ifdef _DEBUG_TTYFUNCS
1060 printk(KERN_DEBUG "capinc_tty_write: mp or mp->ncci NULL\n");
1061#endif
1062 return 0;
1063 }
1064
1065 skb = mp->ttyskb;
1066 if (skb) {
1067 mp->ttyskb = NULL;
1068 skb_queue_tail(&mp->outqueue, skb);
1069 mp->outbytes += skb->len;
1070 }
1071
1072 skb = alloc_skb(CAPI_DATA_B3_REQ_LEN+count, GFP_ATOMIC);
1073 if (!skb) {
1074 printk(KERN_ERR "capinc_tty_write: alloc_skb failed\n");
1075 return -ENOMEM;
1076 }
1077
1078 skb_reserve(skb, CAPI_DATA_B3_REQ_LEN);
1079 memcpy(skb_put(skb, count), buf, count);
1080
1081 skb_queue_tail(&mp->outqueue, skb);
1082 mp->outbytes += skb->len;
1083 (void)handle_minor_send(mp);
1084 (void)handle_minor_recv(mp);
1085 return count;
1086}
1087
1088static void capinc_tty_put_char(struct tty_struct *tty, unsigned char ch)
1089{
1090 struct capiminor *mp = (struct capiminor *)tty->driver_data;
1091 struct sk_buff *skb;
1092
1093#ifdef _DEBUG_TTYFUNCS
1094 printk(KERN_DEBUG "capinc_put_char(%u)\n", ch);
1095#endif
1096
1097 if (!mp || !mp->nccip) {
1098#ifdef _DEBUG_TTYFUNCS
1099 printk(KERN_DEBUG "capinc_tty_put_char: mp or mp->ncci NULL\n");
1100#endif
1101 return;
1102 }
1103
1104 skb = mp->ttyskb;
1105 if (skb) {
1106 if (skb_tailroom(skb) > 0) {
1107 *(skb_put(skb, 1)) = ch;
1108 return;
1109 }
1110 mp->ttyskb = NULL;
1111 skb_queue_tail(&mp->outqueue, skb);
1112 mp->outbytes += skb->len;
1113 (void)handle_minor_send(mp);
1114 }
1115 skb = alloc_skb(CAPI_DATA_B3_REQ_LEN+CAPI_MAX_BLKSIZE, GFP_ATOMIC);
1116 if (skb) {
1117 skb_reserve(skb, CAPI_DATA_B3_REQ_LEN);
1118 *(skb_put(skb, 1)) = ch;
1119 mp->ttyskb = skb;
1120 } else {
1121 printk(KERN_ERR "capinc_put_char: char %u lost\n", ch);
1122 }
1123}
1124
1125static void capinc_tty_flush_chars(struct tty_struct *tty)
1126{
1127 struct capiminor *mp = (struct capiminor *)tty->driver_data;
1128 struct sk_buff *skb;
1129
1130#ifdef _DEBUG_TTYFUNCS
1131 printk(KERN_DEBUG "capinc_tty_flush_chars\n");
1132#endif
1133
1134 if (!mp || !mp->nccip) {
1135#ifdef _DEBUG_TTYFUNCS
1136 printk(KERN_DEBUG "capinc_tty_flush_chars: mp or mp->ncci NULL\n");
1137#endif
1138 return;
1139 }
1140
1141 skb = mp->ttyskb;
1142 if (skb) {
1143 mp->ttyskb = NULL;
1144 skb_queue_tail(&mp->outqueue, skb);
1145 mp->outbytes += skb->len;
1146 (void)handle_minor_send(mp);
1147 }
1148 (void)handle_minor_recv(mp);
1149}
1150
1151static int capinc_tty_write_room(struct tty_struct *tty)
1152{
1153 struct capiminor *mp = (struct capiminor *)tty->driver_data;
1154 int room;
1155 if (!mp || !mp->nccip) {
1156#ifdef _DEBUG_TTYFUNCS
1157 printk(KERN_DEBUG "capinc_tty_write_room: mp or mp->ncci NULL\n");
1158#endif
1159 return 0;
1160 }
1161 room = CAPINC_MAX_SENDQUEUE-skb_queue_len(&mp->outqueue);
1162 room *= CAPI_MAX_BLKSIZE;
1163#ifdef _DEBUG_TTYFUNCS
1164 printk(KERN_DEBUG "capinc_tty_write_room = %d\n", room);
1165#endif
1166 return room;
1167}
1168
1169int capinc_tty_chars_in_buffer(struct tty_struct *tty)
1170{
1171 struct capiminor *mp = (struct capiminor *)tty->driver_data;
1172 if (!mp || !mp->nccip) {
1173#ifdef _DEBUG_TTYFUNCS
1174 printk(KERN_DEBUG "capinc_tty_chars_in_buffer: mp or mp->ncci NULL\n");
1175#endif
1176 return 0;
1177 }
1178#ifdef _DEBUG_TTYFUNCS
1179 printk(KERN_DEBUG "capinc_tty_chars_in_buffer = %d nack=%d sq=%d rq=%d\n",
1180 mp->outbytes, mp->nack,
1181 skb_queue_len(&mp->outqueue),
1182 skb_queue_len(&mp->inqueue));
1183#endif
1184 return mp->outbytes;
1185}
1186
1187static int capinc_tty_ioctl(struct tty_struct *tty, struct file * file,
1188 unsigned int cmd, unsigned long arg)
1189{
1190 int error = 0;
1191 switch (cmd) {
1192 default:
1193 error = n_tty_ioctl (tty, file, cmd, arg);
1194 break;
1195 }
1196 return error;
1197}
1198
1199static void capinc_tty_set_termios(struct tty_struct *tty, struct termios * old)
1200{
1201#ifdef _DEBUG_TTYFUNCS
1202 printk(KERN_DEBUG "capinc_tty_set_termios\n");
1203#endif
1204}
1205
1206static void capinc_tty_throttle(struct tty_struct * tty)
1207{
1208 struct capiminor *mp = (struct capiminor *)tty->driver_data;
1209#ifdef _DEBUG_TTYFUNCS
1210 printk(KERN_DEBUG "capinc_tty_throttle\n");
1211#endif
1212 if (mp)
1213 mp->ttyinstop = 1;
1214}
1215
1216static void capinc_tty_unthrottle(struct tty_struct * tty)
1217{
1218 struct capiminor *mp = (struct capiminor *)tty->driver_data;
1219#ifdef _DEBUG_TTYFUNCS
1220 printk(KERN_DEBUG "capinc_tty_unthrottle\n");
1221#endif
1222 if (mp) {
1223 mp->ttyinstop = 0;
1224 handle_minor_recv(mp);
1225 }
1226}
1227
1228static void capinc_tty_stop(struct tty_struct *tty)
1229{
1230 struct capiminor *mp = (struct capiminor *)tty->driver_data;
1231#ifdef _DEBUG_TTYFUNCS
1232 printk(KERN_DEBUG "capinc_tty_stop\n");
1233#endif
1234 if (mp) {
1235 mp->ttyoutstop = 1;
1236 }
1237}
1238
1239static void capinc_tty_start(struct tty_struct *tty)
1240{
1241 struct capiminor *mp = (struct capiminor *)tty->driver_data;
1242#ifdef _DEBUG_TTYFUNCS
1243 printk(KERN_DEBUG "capinc_tty_start\n");
1244#endif
1245 if (mp) {
1246 mp->ttyoutstop = 0;
1247 (void)handle_minor_send(mp);
1248 }
1249}
1250
1251static void capinc_tty_hangup(struct tty_struct *tty)
1252{
1253#ifdef _DEBUG_TTYFUNCS
1254 printk(KERN_DEBUG "capinc_tty_hangup\n");
1255#endif
1256}
1257
1258static void capinc_tty_break_ctl(struct tty_struct *tty, int state)
1259{
1260#ifdef _DEBUG_TTYFUNCS
1261 printk(KERN_DEBUG "capinc_tty_break_ctl(%d)\n", state);
1262#endif
1263}
1264
1265static void capinc_tty_flush_buffer(struct tty_struct *tty)
1266{
1267#ifdef _DEBUG_TTYFUNCS
1268 printk(KERN_DEBUG "capinc_tty_flush_buffer\n");
1269#endif
1270}
1271
1272static void capinc_tty_set_ldisc(struct tty_struct *tty)
1273{
1274#ifdef _DEBUG_TTYFUNCS
1275 printk(KERN_DEBUG "capinc_tty_set_ldisc\n");
1276#endif
1277}
1278
1279static void capinc_tty_send_xchar(struct tty_struct *tty, char ch)
1280{
1281#ifdef _DEBUG_TTYFUNCS
1282 printk(KERN_DEBUG "capinc_tty_send_xchar(%d)\n", ch);
1283#endif
1284}
1285
1286static int capinc_tty_read_proc(char *page, char **start, off_t off,
1287 int count, int *eof, void *data)
1288{
1289 return 0;
1290}
1291
1292static struct tty_driver *capinc_tty_driver;
1293
1294static struct tty_operations capinc_ops = {
1295 .open = capinc_tty_open,
1296 .close = capinc_tty_close,
1297 .write = capinc_tty_write,
1298 .put_char = capinc_tty_put_char,
1299 .flush_chars = capinc_tty_flush_chars,
1300 .write_room = capinc_tty_write_room,
1301 .chars_in_buffer = capinc_tty_chars_in_buffer,
1302 .ioctl = capinc_tty_ioctl,
1303 .set_termios = capinc_tty_set_termios,
1304 .throttle = capinc_tty_throttle,
1305 .unthrottle = capinc_tty_unthrottle,
1306 .stop = capinc_tty_stop,
1307 .start = capinc_tty_start,
1308 .hangup = capinc_tty_hangup,
1309 .break_ctl = capinc_tty_break_ctl,
1310 .flush_buffer = capinc_tty_flush_buffer,
1311 .set_ldisc = capinc_tty_set_ldisc,
1312 .send_xchar = capinc_tty_send_xchar,
1313 .read_proc = capinc_tty_read_proc,
1314};
1315
1316static int capinc_tty_init(void)
1317{
1318 struct tty_driver *drv;
1319
1320 if (capi_ttyminors > CAPINC_MAX_PORTS)
1321 capi_ttyminors = CAPINC_MAX_PORTS;
1322 if (capi_ttyminors <= 0)
1323 capi_ttyminors = CAPINC_NR_PORTS;
1324
1325 drv = alloc_tty_driver(capi_ttyminors);
1326 if (!drv)
1327 return -ENOMEM;
1328
1329 drv->owner = THIS_MODULE;
1330 drv->driver_name = "capi_nc";
1331 drv->devfs_name = "capi/";
1332 drv->name = "capi";
1333 drv->major = capi_ttymajor;
1334 drv->minor_start = 0;
1335 drv->type = TTY_DRIVER_TYPE_SERIAL;
1336 drv->subtype = SERIAL_TYPE_NORMAL;
1337 drv->init_termios = tty_std_termios;
1338 drv->init_termios.c_iflag = ICRNL;
1339 drv->init_termios.c_oflag = OPOST | ONLCR;
1340 drv->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
1341 drv->init_termios.c_lflag = 0;
1342 drv->flags = TTY_DRIVER_REAL_RAW|TTY_DRIVER_RESET_TERMIOS;
1343 tty_set_operations(drv, &capinc_ops);
1344 if (tty_register_driver(drv)) {
1345 put_tty_driver(drv);
1346 printk(KERN_ERR "Couldn't register capi_nc driver\n");
1347 return -1;
1348 }
1349 capinc_tty_driver = drv;
1350 return 0;
1351}
1352
1353static void capinc_tty_exit(void)
1354{
1355 struct tty_driver *drv = capinc_tty_driver;
1356 int retval;
1357 if ((retval = tty_unregister_driver(drv)))
1358 printk(KERN_ERR "capi: failed to unregister capi_nc driver (%d)\n", retval);
1359 put_tty_driver(drv);
1360}
1361
1362#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
1363
1364/* -------- /proc functions ----------------------------------------- */
1365
1366/*
1367 * /proc/capi/capi20:
1368 * minor applid nrecvctlpkt nrecvdatapkt nsendctlpkt nsenddatapkt
1369 */
1370static int proc_capidev_read_proc(char *page, char **start, off_t off,
1371 int count, int *eof, void *data)
1372{
1373 struct capidev *cdev;
1374 struct list_head *l;
1375 int len = 0;
1376
1377 read_lock(&capidev_list_lock);
1378 list_for_each(l, &capidev_list) {
1379 cdev = list_entry(l, struct capidev, list);
1380 len += sprintf(page+len, "0 %d %lu %lu %lu %lu\n",
1381 cdev->ap.applid,
1382 cdev->ap.nrecvctlpkt,
1383 cdev->ap.nrecvdatapkt,
1384 cdev->ap.nsentctlpkt,
1385 cdev->ap.nsentdatapkt);
1386 if (len <= off) {
1387 off -= len;
1388 len = 0;
1389 } else {
1390 if (len-off > count)
1391 goto endloop;
1392 }
1393 }
1394
1395endloop:
1396 read_unlock(&capidev_list_lock);
1397 if (len < count)
1398 *eof = 1;
1399 if (len > count) len = count;
1400 if (len < 0) len = 0;
1401 return len;
1402}
1403
1404/*
1405 * /proc/capi/capi20ncci:
1406 * applid ncci
1407 */
1408static int proc_capincci_read_proc(char *page, char **start, off_t off,
1409 int count, int *eof, void *data)
1410{
1411 struct capidev *cdev;
1412 struct capincci *np;
1413 struct list_head *l;
1414 int len = 0;
1415
1416 read_lock(&capidev_list_lock);
1417 list_for_each(l, &capidev_list) {
1418 cdev = list_entry(l, struct capidev, list);
1419 for (np=cdev->nccis; np; np = np->next) {
1420 len += sprintf(page+len, "%d 0x%x\n",
1421 cdev->ap.applid,
1422 np->ncci);
1423 if (len <= off) {
1424 off -= len;
1425 len = 0;
1426 } else {
1427 if (len-off > count)
1428 goto endloop;
1429 }
1430 }
1431 }
1432endloop:
1433 read_unlock(&capidev_list_lock);
1434 *start = page+off;
1435 if (len < count)
1436 *eof = 1;
1437 if (len>count) len = count;
1438 if (len<0) len = 0;
1439 return len;
1440}
1441
1442static struct procfsentries {
1443 char *name;
1444 mode_t mode;
1445 int (*read_proc)(char *page, char **start, off_t off,
1446 int count, int *eof, void *data);
1447 struct proc_dir_entry *procent;
1448} procfsentries[] = {
1449 /* { "capi", S_IFDIR, 0 }, */
1450 { "capi/capi20", 0 , proc_capidev_read_proc },
1451 { "capi/capi20ncci", 0 , proc_capincci_read_proc },
1452};
1453
1454static void __init proc_init(void)
1455{
1456 int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]);
1457 int i;
1458
1459 for (i=0; i < nelem; i++) {
1460 struct procfsentries *p = procfsentries + i;
1461 p->procent = create_proc_entry(p->name, p->mode, NULL);
1462 if (p->procent) p->procent->read_proc = p->read_proc;
1463 }
1464}
1465
1466static void __exit proc_exit(void)
1467{
1468 int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]);
1469 int i;
1470
1471 for (i=nelem-1; i >= 0; i--) {
1472 struct procfsentries *p = procfsentries + i;
1473 if (p->procent) {
1474 remove_proc_entry(p->name, NULL);
1475 p->procent = NULL;
1476 }
1477 }
1478}
1479
1480/* -------- init function and module interface ---------------------- */
1481
1482
1483static char rev[32];
1484
1485static int __init capi_init(void)
1486{
1487 char *p;
1488 char *compileinfo;
1489
1490 if ((p = strchr(revision, ':')) != 0 && p[1]) {
1491 strlcpy(rev, p + 2, sizeof(rev));
1492 if ((p = strchr(rev, '$')) != 0 && p > rev)
1493 *(p-1) = 0;
1494 } else
1495 strcpy(rev, "1.0");
1496
1497 if (register_chrdev(capi_major, "capi20", &capi_fops)) {
1498 printk(KERN_ERR "capi20: unable to get major %d\n", capi_major);
1499 return -EIO;
1500 }
1501
1502 capi_class = class_simple_create(THIS_MODULE, "capi");
1503 if (IS_ERR(capi_class)) {
1504 unregister_chrdev(capi_major, "capi20");
1505 return PTR_ERR(capi_class);
1506 }
1507
1508 class_simple_device_add(capi_class, MKDEV(capi_major, 0), NULL, "capi");
1509 devfs_mk_cdev(MKDEV(capi_major, 0), S_IFCHR | S_IRUSR | S_IWUSR,
1510 "isdn/capi20");
1511
1512#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
1513 if (capinc_tty_init() < 0) {
1514 class_simple_device_remove(MKDEV(capi_major, 0));
1515 class_simple_destroy(capi_class);
1516 unregister_chrdev(capi_major, "capi20");
1517 return -ENOMEM;
1518 }
1519#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
1520
1521 proc_init();
1522
1523#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
1524#if defined(CONFIG_ISDN_CAPI_CAPIFS) || defined(CONFIG_ISDN_CAPI_CAPIFS_MODULE)
1525 compileinfo = " (middleware+capifs)";
1526#else
1527 compileinfo = " (no capifs)";
1528#endif
1529#else
1530 compileinfo = " (no middleware)";
1531#endif
1532 printk(KERN_NOTICE "capi20: Rev %s: started up with major %d%s\n",
1533 rev, capi_major, compileinfo);
1534
1535 return 0;
1536}
1537
1538static void __exit capi_exit(void)
1539{
1540 proc_exit();
1541
1542 class_simple_device_remove(MKDEV(capi_major, 0));
1543 class_simple_destroy(capi_class);
1544 unregister_chrdev(capi_major, "capi20");
1545 devfs_remove("isdn/capi20");
1546
1547#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
1548 capinc_tty_exit();
1549#endif
1550 printk(KERN_NOTICE "capi: Rev %s: unloaded\n", rev);
1551}
1552
1553module_init(capi_init);
1554module_exit(capi_exit);
diff --git a/drivers/isdn/capi/capidrv.c b/drivers/isdn/capi/capidrv.c
new file mode 100644
index 000000000000..d10c8b82e6aa
--- /dev/null
+++ b/drivers/isdn/capi/capidrv.c
@@ -0,0 +1,2315 @@
1/* $Id: capidrv.c,v 1.1.2.2 2004/01/12 23:17:24 keil Exp $
2 *
3 * ISDN4Linux Driver, using capi20 interface (kernelcapi)
4 *
5 * Copyright 1997 by Carsten Paeth <calle@calle.de>
6 *
7 * This software may be used and distributed according to the terms
8 * of the GNU General Public License, incorporated herein by reference.
9 *
10 */
11
12#include <linux/module.h>
13#include <linux/errno.h>
14#include <linux/kernel.h>
15#include <linux/major.h>
16#include <linux/sched.h>
17#include <linux/slab.h>
18#include <linux/fcntl.h>
19#include <linux/fs.h>
20#include <linux/signal.h>
21#include <linux/mm.h>
22#include <linux/timer.h>
23#include <linux/wait.h>
24#include <linux/skbuff.h>
25#include <linux/isdn.h>
26#include <linux/isdnif.h>
27#include <linux/proc_fs.h>
28#include <linux/capi.h>
29#include <linux/kernelcapi.h>
30#include <linux/ctype.h>
31#include <linux/init.h>
32#include <linux/moduleparam.h>
33
34#include <linux/isdn/capiutil.h>
35#include <linux/isdn/capicmd.h>
36#include "capidrv.h"
37
38static char *revision = "$Revision: 1.1.2.2 $";
39static int debugmode = 0;
40
41MODULE_DESCRIPTION("CAPI4Linux: Interface to ISDN4Linux");
42MODULE_AUTHOR("Carsten Paeth");
43MODULE_LICENSE("GPL");
44module_param(debugmode, uint, 0);
45
46/* -------- type definitions ----------------------------------------- */
47
48
49struct capidrv_contr {
50
51 struct capidrv_contr *next;
52 struct module *owner;
53 u32 contrnr;
54 char name[20];
55
56 /*
57 * for isdn4linux
58 */
59 isdn_if interface;
60 int myid;
61
62 /*
63 * LISTEN state
64 */
65 int state;
66 u32 cipmask;
67 u32 cipmask2;
68 struct timer_list listentimer;
69
70 /*
71 * ID of capi message sent
72 */
73 u16 msgid;
74
75 /*
76 * B-Channels
77 */
78 int nbchan;
79 struct capidrv_bchan {
80 struct capidrv_contr *contr;
81 u8 msn[ISDN_MSNLEN];
82 int l2;
83 int l3;
84 u8 num[ISDN_MSNLEN];
85 u8 mynum[ISDN_MSNLEN];
86 int si1;
87 int si2;
88 int incoming;
89 int disconnecting;
90 struct capidrv_plci {
91 struct capidrv_plci *next;
92 u32 plci;
93 u32 ncci; /* ncci for CONNECT_ACTIVE_IND */
94 u16 msgid; /* to identfy CONNECT_CONF */
95 int chan;
96 int state;
97 int leasedline;
98 struct capidrv_ncci {
99 struct capidrv_ncci *next;
100 struct capidrv_plci *plcip;
101 u32 ncci;
102 u16 msgid; /* to identfy CONNECT_B3_CONF */
103 int chan;
104 int state;
105 int oldstate;
106 /* */
107 u16 datahandle;
108 struct ncci_datahandle_queue {
109 struct ncci_datahandle_queue *next;
110 u16 datahandle;
111 int len;
112 } *ackqueue;
113 } *ncci_list;
114 } *plcip;
115 struct capidrv_ncci *nccip;
116 } *bchans;
117
118 struct capidrv_plci *plci_list;
119
120 /* for q931 data */
121 u8 q931_buf[4096];
122 u8 *q931_read;
123 u8 *q931_write;
124 u8 *q931_end;
125};
126
127
128struct capidrv_data {
129 struct capi20_appl ap;
130 int ncontr;
131 struct capidrv_contr *contr_list;
132};
133
134typedef struct capidrv_plci capidrv_plci;
135typedef struct capidrv_ncci capidrv_ncci;
136typedef struct capidrv_contr capidrv_contr;
137typedef struct capidrv_data capidrv_data;
138typedef struct capidrv_bchan capidrv_bchan;
139
140/* -------- data definitions ----------------------------------------- */
141
142static capidrv_data global;
143static DEFINE_SPINLOCK(global_lock);
144
145static void handle_dtrace_data(capidrv_contr *card,
146 int send, int level2, u8 *data, u16 len);
147
148/* -------- convert functions ---------------------------------------- */
149
150static inline u32 b1prot(int l2, int l3)
151{
152 switch (l2) {
153 case ISDN_PROTO_L2_X75I:
154 case ISDN_PROTO_L2_X75UI:
155 case ISDN_PROTO_L2_X75BUI:
156 return 0;
157 case ISDN_PROTO_L2_HDLC:
158 default:
159 return 0;
160 case ISDN_PROTO_L2_TRANS:
161 return 1;
162 case ISDN_PROTO_L2_V11096:
163 case ISDN_PROTO_L2_V11019:
164 case ISDN_PROTO_L2_V11038:
165 return 2;
166 case ISDN_PROTO_L2_FAX:
167 return 4;
168 case ISDN_PROTO_L2_MODEM:
169 return 8;
170 }
171}
172
173static inline u32 b2prot(int l2, int l3)
174{
175 switch (l2) {
176 case ISDN_PROTO_L2_X75I:
177 case ISDN_PROTO_L2_X75UI:
178 case ISDN_PROTO_L2_X75BUI:
179 default:
180 return 0;
181 case ISDN_PROTO_L2_HDLC:
182 case ISDN_PROTO_L2_TRANS:
183 case ISDN_PROTO_L2_V11096:
184 case ISDN_PROTO_L2_V11019:
185 case ISDN_PROTO_L2_V11038:
186 case ISDN_PROTO_L2_MODEM:
187 return 1;
188 case ISDN_PROTO_L2_FAX:
189 return 4;
190 }
191}
192
193static inline u32 b3prot(int l2, int l3)
194{
195 switch (l2) {
196 case ISDN_PROTO_L2_X75I:
197 case ISDN_PROTO_L2_X75UI:
198 case ISDN_PROTO_L2_X75BUI:
199 case ISDN_PROTO_L2_HDLC:
200 case ISDN_PROTO_L2_TRANS:
201 case ISDN_PROTO_L2_V11096:
202 case ISDN_PROTO_L2_V11019:
203 case ISDN_PROTO_L2_V11038:
204 case ISDN_PROTO_L2_MODEM:
205 default:
206 return 0;
207 case ISDN_PROTO_L2_FAX:
208 return 4;
209 }
210}
211
212static _cstruct b1config_async_v110(u16 rate)
213{
214 /* CAPI-Spec "B1 Configuration" */
215 static unsigned char buf[9];
216 buf[0] = 8; /* len */
217 /* maximum bitrate */
218 buf[1] = rate & 0xff; buf[2] = (rate >> 8) & 0xff;
219 buf[3] = 8; buf[4] = 0; /* 8 bits per character */
220 buf[5] = 0; buf[6] = 0; /* parity none */
221 buf[7] = 0; buf[8] = 0; /* 1 stop bit */
222 return buf;
223}
224
225static _cstruct b1config(int l2, int l3)
226{
227 switch (l2) {
228 case ISDN_PROTO_L2_X75I:
229 case ISDN_PROTO_L2_X75UI:
230 case ISDN_PROTO_L2_X75BUI:
231 case ISDN_PROTO_L2_HDLC:
232 case ISDN_PROTO_L2_TRANS:
233 default:
234 return NULL;
235 case ISDN_PROTO_L2_V11096:
236 return b1config_async_v110(9600);
237 case ISDN_PROTO_L2_V11019:
238 return b1config_async_v110(19200);
239 case ISDN_PROTO_L2_V11038:
240 return b1config_async_v110(38400);
241 }
242}
243
244static inline u16 si2cip(u8 si1, u8 si2)
245{
246 static const u8 cip[17][5] =
247 {
248 /* 0 1 2 3 4 */
249 {0, 0, 0, 0, 0}, /*0 */
250 {16, 16, 4, 26, 16}, /*1 */
251 {17, 17, 17, 4, 4}, /*2 */
252 {2, 2, 2, 2, 2}, /*3 */
253 {18, 18, 18, 18, 18}, /*4 */
254 {2, 2, 2, 2, 2}, /*5 */
255 {0, 0, 0, 0, 0}, /*6 */
256 {2, 2, 2, 2, 2}, /*7 */
257 {2, 2, 2, 2, 2}, /*8 */
258 {21, 21, 21, 21, 21}, /*9 */
259 {19, 19, 19, 19, 19}, /*10 */
260 {0, 0, 0, 0, 0}, /*11 */
261 {0, 0, 0, 0, 0}, /*12 */
262 {0, 0, 0, 0, 0}, /*13 */
263 {0, 0, 0, 0, 0}, /*14 */
264 {22, 22, 22, 22, 22}, /*15 */
265 {27, 27, 27, 28, 27} /*16 */
266 };
267 if (si1 > 16)
268 si1 = 0;
269 if (si2 > 4)
270 si2 = 0;
271
272 return (u16) cip[si1][si2];
273}
274
275static inline u8 cip2si1(u16 cipval)
276{
277 static const u8 si[32] =
278 {7, 1, 7, 7, 1, 1, 7, 7, /*0-7 */
279 7, 1, 0, 0, 0, 0, 0, 0, /*8-15 */
280 1, 2, 4, 10, 9, 9, 15, 7, /*16-23 */
281 7, 7, 1, 16, 16, 0, 0, 0}; /*24-31 */
282
283 if (cipval > 31)
284 cipval = 0; /* .... */
285 return si[cipval];
286}
287
288static inline u8 cip2si2(u16 cipval)
289{
290 static const u8 si[32] =
291 {0, 0, 0, 0, 2, 3, 0, 0, /*0-7 */
292 0, 3, 0, 0, 0, 0, 0, 0, /*8-15 */
293 1, 2, 0, 0, 9, 0, 0, 0, /*16-23 */
294 0, 0, 3, 2, 3, 0, 0, 0}; /*24-31 */
295
296 if (cipval > 31)
297 cipval = 0; /* .... */
298 return si[cipval];
299}
300
301
302/* -------- controller management ------------------------------------- */
303
304static inline capidrv_contr *findcontrbydriverid(int driverid)
305{
306 unsigned long flags;
307 capidrv_contr *p;
308
309 spin_lock_irqsave(&global_lock, flags);
310 for (p = global.contr_list; p; p = p->next)
311 if (p->myid == driverid)
312 break;
313 spin_unlock_irqrestore(&global_lock, flags);
314 return p;
315}
316
317static capidrv_contr *findcontrbynumber(u32 contr)
318{
319 unsigned long flags;
320 capidrv_contr *p = global.contr_list;
321
322 spin_lock_irqsave(&global_lock, flags);
323 for (p = global.contr_list; p; p = p->next)
324 if (p->contrnr == contr)
325 break;
326 spin_unlock_irqrestore(&global_lock, flags);
327 return p;
328}
329
330
331/* -------- plci management ------------------------------------------ */
332
333static capidrv_plci *new_plci(capidrv_contr * card, int chan)
334{
335 capidrv_plci *plcip;
336
337 plcip = (capidrv_plci *) kmalloc(sizeof(capidrv_plci), GFP_ATOMIC);
338
339 if (plcip == 0)
340 return NULL;
341
342 memset(plcip, 0, sizeof(capidrv_plci));
343 plcip->state = ST_PLCI_NONE;
344 plcip->plci = 0;
345 plcip->msgid = 0;
346 plcip->chan = chan;
347 plcip->next = card->plci_list;
348 card->plci_list = plcip;
349 card->bchans[chan].plcip = plcip;
350
351 return plcip;
352}
353
354static capidrv_plci *find_plci_by_plci(capidrv_contr * card, u32 plci)
355{
356 capidrv_plci *p;
357 for (p = card->plci_list; p; p = p->next)
358 if (p->plci == plci)
359 return p;
360 return NULL;
361}
362
363static capidrv_plci *find_plci_by_msgid(capidrv_contr * card, u16 msgid)
364{
365 capidrv_plci *p;
366 for (p = card->plci_list; p; p = p->next)
367 if (p->msgid == msgid)
368 return p;
369 return NULL;
370}
371
372static capidrv_plci *find_plci_by_ncci(capidrv_contr * card, u32 ncci)
373{
374 capidrv_plci *p;
375 for (p = card->plci_list; p; p = p->next)
376 if (p->plci == (ncci & 0xffff))
377 return p;
378 return NULL;
379}
380
381static void free_plci(capidrv_contr * card, capidrv_plci * plcip)
382{
383 capidrv_plci **pp;
384
385 for (pp = &card->plci_list; *pp; pp = &(*pp)->next) {
386 if (*pp == plcip) {
387 *pp = (*pp)->next;
388 card->bchans[plcip->chan].plcip = NULL;
389 card->bchans[plcip->chan].disconnecting = 0;
390 card->bchans[plcip->chan].incoming = 0;
391 kfree(plcip);
392 return;
393 }
394 }
395 printk(KERN_ERR "capidrv-%d: free_plci %p (0x%x) not found, Huh?\n",
396 card->contrnr, plcip, plcip->plci);
397}
398
399/* -------- ncci management ------------------------------------------ */
400
401static inline capidrv_ncci *new_ncci(capidrv_contr * card,
402 capidrv_plci * plcip,
403 u32 ncci)
404{
405 capidrv_ncci *nccip;
406
407 nccip = (capidrv_ncci *) kmalloc(sizeof(capidrv_ncci), GFP_ATOMIC);
408
409 if (nccip == 0)
410 return NULL;
411
412 memset(nccip, 0, sizeof(capidrv_ncci));
413 nccip->ncci = ncci;
414 nccip->state = ST_NCCI_NONE;
415 nccip->plcip = plcip;
416 nccip->chan = plcip->chan;
417 nccip->datahandle = 0;
418
419 nccip->next = plcip->ncci_list;
420 plcip->ncci_list = nccip;
421
422 card->bchans[plcip->chan].nccip = nccip;
423
424 return nccip;
425}
426
427static inline capidrv_ncci *find_ncci(capidrv_contr * card, u32 ncci)
428{
429 capidrv_plci *plcip;
430 capidrv_ncci *p;
431
432 if ((plcip = find_plci_by_ncci(card, ncci)) == 0)
433 return NULL;
434
435 for (p = plcip->ncci_list; p; p = p->next)
436 if (p->ncci == ncci)
437 return p;
438 return NULL;
439}
440
441static inline capidrv_ncci *find_ncci_by_msgid(capidrv_contr * card,
442 u32 ncci, u16 msgid)
443{
444 capidrv_plci *plcip;
445 capidrv_ncci *p;
446
447 if ((plcip = find_plci_by_ncci(card, ncci)) == 0)
448 return NULL;
449
450 for (p = plcip->ncci_list; p; p = p->next)
451 if (p->msgid == msgid)
452 return p;
453 return NULL;
454}
455
456static void free_ncci(capidrv_contr * card, struct capidrv_ncci *nccip)
457{
458 struct capidrv_ncci **pp;
459
460 for (pp = &(nccip->plcip->ncci_list); *pp; pp = &(*pp)->next) {
461 if (*pp == nccip) {
462 *pp = (*pp)->next;
463 break;
464 }
465 }
466 card->bchans[nccip->chan].nccip = NULL;
467 kfree(nccip);
468}
469
470static int capidrv_add_ack(struct capidrv_ncci *nccip,
471 u16 datahandle, int len)
472{
473 struct ncci_datahandle_queue *n, **pp;
474
475 n = (struct ncci_datahandle_queue *)
476 kmalloc(sizeof(struct ncci_datahandle_queue), GFP_ATOMIC);
477 if (!n) {
478 printk(KERN_ERR "capidrv: kmalloc ncci_datahandle failed\n");
479 return -1;
480 }
481 n->next = NULL;
482 n->datahandle = datahandle;
483 n->len = len;
484 for (pp = &nccip->ackqueue; *pp; pp = &(*pp)->next) ;
485 *pp = n;
486 return 0;
487}
488
489static int capidrv_del_ack(struct capidrv_ncci *nccip, u16 datahandle)
490{
491 struct ncci_datahandle_queue **pp, *p;
492 int len;
493
494 for (pp = &nccip->ackqueue; *pp; pp = &(*pp)->next) {
495 if ((*pp)->datahandle == datahandle) {
496 p = *pp;
497 len = p->len;
498 *pp = (*pp)->next;
499 kfree(p);
500 return len;
501 }
502 }
503 return -1;
504}
505
506/* -------- convert and send capi message ---------------------------- */
507
508static void send_message(capidrv_contr * card, _cmsg * cmsg)
509{
510 struct sk_buff *skb;
511 size_t len;
512 capi_cmsg2message(cmsg, cmsg->buf);
513 len = CAPIMSG_LEN(cmsg->buf);
514 skb = alloc_skb(len, GFP_ATOMIC);
515 memcpy(skb_put(skb, len), cmsg->buf, len);
516 if (capi20_put_message(&global.ap, skb) != CAPI_NOERROR)
517 kfree_skb(skb);
518}
519
520/* -------- state machine -------------------------------------------- */
521
522struct listenstatechange {
523 int actstate;
524 int nextstate;
525 int event;
526};
527
528static struct listenstatechange listentable[] =
529{
530 {ST_LISTEN_NONE, ST_LISTEN_WAIT_CONF, EV_LISTEN_REQ},
531 {ST_LISTEN_ACTIVE, ST_LISTEN_ACTIVE_WAIT_CONF, EV_LISTEN_REQ},
532 {ST_LISTEN_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_ERROR},
533 {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_ERROR},
534 {ST_LISTEN_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_EMPTY},
535 {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_EMPTY},
536 {ST_LISTEN_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_OK},
537 {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_OK},
538 {},
539};
540
541static void listen_change_state(capidrv_contr * card, int event)
542{
543 struct listenstatechange *p = listentable;
544 while (p->event) {
545 if (card->state == p->actstate && p->event == event) {
546 if (debugmode)
547 printk(KERN_DEBUG "capidrv-%d: listen_change_state %d -> %d\n",
548 card->contrnr, card->state, p->nextstate);
549 card->state = p->nextstate;
550 return;
551 }
552 p++;
553 }
554 printk(KERN_ERR "capidrv-%d: listen_change_state state=%d event=%d ????\n",
555 card->contrnr, card->state, event);
556
557}
558
559/* ------------------------------------------------------------------ */
560
561static void p0(capidrv_contr * card, capidrv_plci * plci)
562{
563 isdn_ctrl cmd;
564
565 card->bchans[plci->chan].contr = NULL;
566 cmd.command = ISDN_STAT_DHUP;
567 cmd.driver = card->myid;
568 cmd.arg = plci->chan;
569 card->interface.statcallb(&cmd);
570 free_plci(card, plci);
571}
572
573/* ------------------------------------------------------------------ */
574
575struct plcistatechange {
576 int actstate;
577 int nextstate;
578 int event;
579 void (*changefunc) (capidrv_contr * card, capidrv_plci * plci);
580};
581
582static struct plcistatechange plcitable[] =
583{
584 /* P-0 */
585 {ST_PLCI_NONE, ST_PLCI_OUTGOING, EV_PLCI_CONNECT_REQ, NULL},
586 {ST_PLCI_NONE, ST_PLCI_ALLOCATED, EV_PLCI_FACILITY_IND_UP, NULL},
587 {ST_PLCI_NONE, ST_PLCI_INCOMING, EV_PLCI_CONNECT_IND, NULL},
588 {ST_PLCI_NONE, ST_PLCI_RESUMEING, EV_PLCI_RESUME_REQ, NULL},
589 /* P-0.1 */
590 {ST_PLCI_OUTGOING, ST_PLCI_NONE, EV_PLCI_CONNECT_CONF_ERROR, p0},
591 {ST_PLCI_OUTGOING, ST_PLCI_ALLOCATED, EV_PLCI_CONNECT_CONF_OK, NULL},
592 /* P-1 */
593 {ST_PLCI_ALLOCATED, ST_PLCI_ACTIVE, EV_PLCI_CONNECT_ACTIVE_IND, NULL},
594 {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, NULL},
595 {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, NULL},
596 {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL},
597 /* P-ACT */
598 {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, NULL},
599 {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, NULL},
600 {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL},
601 {ST_PLCI_ACTIVE, ST_PLCI_HELD, EV_PLCI_HOLD_IND, NULL},
602 {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_SUSPEND_IND, NULL},
603 /* P-2 */
604 {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_CONNECT_REJECT, NULL},
605 {ST_PLCI_INCOMING, ST_PLCI_FACILITY_IND, EV_PLCI_FACILITY_IND_UP, NULL},
606 {ST_PLCI_INCOMING, ST_PLCI_ACCEPTING, EV_PLCI_CONNECT_RESP, NULL},
607 {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, NULL},
608 {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, NULL},
609 {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL},
610 {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_CD_IND, NULL},
611 /* P-3 */
612 {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_CONNECT_REJECT, NULL},
613 {ST_PLCI_FACILITY_IND, ST_PLCI_ACCEPTING, EV_PLCI_CONNECT_ACTIVE_IND, NULL},
614 {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, NULL},
615 {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, NULL},
616 {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL},
617 /* P-4 */
618 {ST_PLCI_ACCEPTING, ST_PLCI_ACTIVE, EV_PLCI_CONNECT_ACTIVE_IND, NULL},
619 {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, NULL},
620 {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, NULL},
621 {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL},
622 /* P-5 */
623 {ST_PLCI_DISCONNECTING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL},
624 /* P-6 */
625 {ST_PLCI_DISCONNECTED, ST_PLCI_NONE, EV_PLCI_DISCONNECT_RESP, p0},
626 /* P-0.Res */
627 {ST_PLCI_RESUMEING, ST_PLCI_NONE, EV_PLCI_RESUME_CONF_ERROR, p0},
628 {ST_PLCI_RESUMEING, ST_PLCI_RESUME, EV_PLCI_RESUME_CONF_OK, NULL},
629 /* P-RES */
630 {ST_PLCI_RESUME, ST_PLCI_ACTIVE, EV_PLCI_RESUME_IND, NULL},
631 /* P-HELD */
632 {ST_PLCI_HELD, ST_PLCI_ACTIVE, EV_PLCI_RETRIEVE_IND, NULL},
633 {},
634};
635
636static void plci_change_state(capidrv_contr * card, capidrv_plci * plci, int event)
637{
638 struct plcistatechange *p = plcitable;
639 while (p->event) {
640 if (plci->state == p->actstate && p->event == event) {
641 if (debugmode)
642 printk(KERN_DEBUG "capidrv-%d: plci_change_state:0x%x %d -> %d\n",
643 card->contrnr, plci->plci, plci->state, p->nextstate);
644 plci->state = p->nextstate;
645 if (p->changefunc)
646 p->changefunc(card, plci);
647 return;
648 }
649 p++;
650 }
651 printk(KERN_ERR "capidrv-%d: plci_change_state:0x%x state=%d event=%d ????\n",
652 card->contrnr, plci->plci, plci->state, event);
653}
654
655/* ------------------------------------------------------------------ */
656
657static _cmsg cmsg;
658
659static void n0(capidrv_contr * card, capidrv_ncci * ncci)
660{
661 isdn_ctrl cmd;
662
663 capi_fill_DISCONNECT_REQ(&cmsg,
664 global.ap.applid,
665 card->msgid++,
666 ncci->plcip->plci,
667 NULL, /* BChannelinformation */
668 NULL, /* Keypadfacility */
669 NULL, /* Useruserdata */ /* $$$$ */
670 NULL /* Facilitydataarray */
671 );
672 send_message(card, &cmsg);
673 plci_change_state(card, ncci->plcip, EV_PLCI_DISCONNECT_REQ);
674
675 cmd.command = ISDN_STAT_BHUP;
676 cmd.driver = card->myid;
677 cmd.arg = ncci->chan;
678 card->interface.statcallb(&cmd);
679 free_ncci(card, ncci);
680}
681
682/* ------------------------------------------------------------------ */
683
684struct nccistatechange {
685 int actstate;
686 int nextstate;
687 int event;
688 void (*changefunc) (capidrv_contr * card, capidrv_ncci * ncci);
689};
690
691static struct nccistatechange nccitable[] =
692{
693 /* N-0 */
694 {ST_NCCI_NONE, ST_NCCI_OUTGOING, EV_NCCI_CONNECT_B3_REQ, NULL},
695 {ST_NCCI_NONE, ST_NCCI_INCOMING, EV_NCCI_CONNECT_B3_IND, NULL},
696 /* N-0.1 */
697 {ST_NCCI_OUTGOING, ST_NCCI_ALLOCATED, EV_NCCI_CONNECT_B3_CONF_OK, NULL},
698 {ST_NCCI_OUTGOING, ST_NCCI_NONE, EV_NCCI_CONNECT_B3_CONF_ERROR, n0},
699 /* N-1 */
700 {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTING, EV_NCCI_CONNECT_B3_REJECT, NULL},
701 {ST_NCCI_INCOMING, ST_NCCI_ALLOCATED, EV_NCCI_CONNECT_B3_RESP, NULL},
702 {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, NULL},
703 {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, NULL},
704 /* N-2 */
705 {ST_NCCI_ALLOCATED, ST_NCCI_ACTIVE, EV_NCCI_CONNECT_B3_ACTIVE_IND, NULL},
706 {ST_NCCI_ALLOCATED, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, NULL},
707 {ST_NCCI_ALLOCATED, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, NULL},
708 /* N-ACT */
709 {ST_NCCI_ACTIVE, ST_NCCI_ACTIVE, EV_NCCI_RESET_B3_IND, NULL},
710 {ST_NCCI_ACTIVE, ST_NCCI_RESETING, EV_NCCI_RESET_B3_REQ, NULL},
711 {ST_NCCI_ACTIVE, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, NULL},
712 {ST_NCCI_ACTIVE, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, NULL},
713 /* N-3 */
714 {ST_NCCI_RESETING, ST_NCCI_ACTIVE, EV_NCCI_RESET_B3_IND, NULL},
715 {ST_NCCI_RESETING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, NULL},
716 {ST_NCCI_RESETING, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, NULL},
717 /* N-4 */
718 {ST_NCCI_DISCONNECTING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, NULL},
719 {ST_NCCI_DISCONNECTING, ST_NCCI_PREVIOUS, EV_NCCI_DISCONNECT_B3_CONF_ERROR,NULL},
720 /* N-5 */
721 {ST_NCCI_DISCONNECTED, ST_NCCI_NONE, EV_NCCI_DISCONNECT_B3_RESP, n0},
722 {},
723};
724
725static void ncci_change_state(capidrv_contr * card, capidrv_ncci * ncci, int event)
726{
727 struct nccistatechange *p = nccitable;
728 while (p->event) {
729 if (ncci->state == p->actstate && p->event == event) {
730 if (debugmode)
731 printk(KERN_DEBUG "capidrv-%d: ncci_change_state:0x%x %d -> %d\n",
732 card->contrnr, ncci->ncci, ncci->state, p->nextstate);
733 if (p->nextstate == ST_NCCI_PREVIOUS) {
734 ncci->state = ncci->oldstate;
735 ncci->oldstate = p->actstate;
736 } else {
737 ncci->oldstate = p->actstate;
738 ncci->state = p->nextstate;
739 }
740 if (p->changefunc)
741 p->changefunc(card, ncci);
742 return;
743 }
744 p++;
745 }
746 printk(KERN_ERR "capidrv-%d: ncci_change_state:0x%x state=%d event=%d ????\n",
747 card->contrnr, ncci->ncci, ncci->state, event);
748}
749
750/* ------------------------------------------------------------------- */
751
752static inline int new_bchan(capidrv_contr * card)
753{
754 int i;
755 for (i = 0; i < card->nbchan; i++) {
756 if (card->bchans[i].plcip == 0) {
757 card->bchans[i].disconnecting = 0;
758 return i;
759 }
760 }
761 return -1;
762}
763
764/* ------------------------------------------------------------------- */
765
766static void handle_controller(_cmsg * cmsg)
767{
768 capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f);
769
770 if (!card) {
771 printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n",
772 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
773 cmsg->adr.adrController & 0x7f);
774 return;
775 }
776 switch (CAPICMD(cmsg->Command, cmsg->Subcommand)) {
777
778 case CAPI_LISTEN_CONF: /* Controller */
779 if (debugmode)
780 printk(KERN_DEBUG "capidrv-%d: listenconf Info=0x%4x (%s) cipmask=0x%x\n",
781 card->contrnr, cmsg->Info, capi_info2str(cmsg->Info), card->cipmask);
782 if (cmsg->Info) {
783 listen_change_state(card, EV_LISTEN_CONF_ERROR);
784 } else if (card->cipmask == 0) {
785 listen_change_state(card, EV_LISTEN_CONF_EMPTY);
786 } else {
787 listen_change_state(card, EV_LISTEN_CONF_OK);
788 }
789 break;
790
791 case CAPI_MANUFACTURER_IND: /* Controller */
792 if ( cmsg->ManuID == 0x214D5641
793 && cmsg->Class == 0
794 && cmsg->Function == 1) {
795 u8 *data = cmsg->ManuData+3;
796 u16 len = cmsg->ManuData[0];
797 u16 layer;
798 int direction;
799 if (len == 255) {
800 len = (cmsg->ManuData[1] | (cmsg->ManuData[2] << 8));
801 data += 2;
802 }
803 len -= 2;
804 layer = ((*(data-1)) << 8) | *(data-2);
805 if (layer & 0x300)
806 direction = (layer & 0x200) ? 0 : 1;
807 else direction = (layer & 0x800) ? 0 : 1;
808 if (layer & 0x0C00) {
809 if ((layer & 0xff) == 0x80) {
810 handle_dtrace_data(card, direction, 1, data, len);
811 break;
812 }
813 } else if ((layer & 0xff) < 0x80) {
814 handle_dtrace_data(card, direction, 0, data, len);
815 break;
816 }
817 printk(KERN_INFO "capidrv-%d: %s from controller 0x%x layer 0x%x, ignored\n",
818 card->contrnr,
819 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
820 cmsg->adr.adrController, layer);
821 break;
822 }
823 goto ignored;
824 case CAPI_MANUFACTURER_CONF: /* Controller */
825 if (cmsg->ManuID == 0x214D5641) {
826 char *s = NULL;
827 switch (cmsg->Class) {
828 case 0: break;
829 case 1: s = "unknown class"; break;
830 case 2: s = "unknown function"; break;
831 default: s = "unkown error"; break;
832 }
833 if (s)
834 printk(KERN_INFO "capidrv-%d: %s from controller 0x%x function %d: %s\n",
835 card->contrnr,
836 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
837 cmsg->adr.adrController,
838 cmsg->Function, s);
839 break;
840 }
841 goto ignored;
842 case CAPI_FACILITY_IND: /* Controller/plci/ncci */
843 goto ignored;
844 case CAPI_FACILITY_CONF: /* Controller/plci/ncci */
845 goto ignored;
846 case CAPI_INFO_IND: /* Controller/plci */
847 goto ignored;
848 case CAPI_INFO_CONF: /* Controller/plci */
849 goto ignored;
850
851 default:
852 printk(KERN_ERR "capidrv-%d: got %s from controller 0x%x ???",
853 card->contrnr,
854 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
855 cmsg->adr.adrController);
856 }
857 return;
858
859 ignored:
860 printk(KERN_INFO "capidrv-%d: %s from controller 0x%x ignored\n",
861 card->contrnr,
862 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
863 cmsg->adr.adrController);
864}
865
866static void handle_incoming_call(capidrv_contr * card, _cmsg * cmsg)
867{
868 capidrv_plci *plcip;
869 capidrv_bchan *bchan;
870 isdn_ctrl cmd;
871 int chan;
872
873 if ((chan = new_bchan(card)) == -1) {
874 printk(KERN_ERR "capidrv-%d: incoming call on not existing bchan ?\n", card->contrnr);
875 return;
876 }
877 bchan = &card->bchans[chan];
878 if ((plcip = new_plci(card, chan)) == 0) {
879 printk(KERN_ERR "capidrv-%d: incoming call: no memory, sorry.\n", card->contrnr);
880 return;
881 }
882 bchan->incoming = 1;
883 plcip->plci = cmsg->adr.adrPLCI;
884 plci_change_state(card, plcip, EV_PLCI_CONNECT_IND);
885
886 cmd.command = ISDN_STAT_ICALL;
887 cmd.driver = card->myid;
888 cmd.arg = chan;
889 memset(&cmd.parm.setup, 0, sizeof(cmd.parm.setup));
890 strncpy(cmd.parm.setup.phone,
891 cmsg->CallingPartyNumber + 3,
892 cmsg->CallingPartyNumber[0] - 2);
893 strncpy(cmd.parm.setup.eazmsn,
894 cmsg->CalledPartyNumber + 2,
895 cmsg->CalledPartyNumber[0] - 1);
896 cmd.parm.setup.si1 = cip2si1(cmsg->CIPValue);
897 cmd.parm.setup.si2 = cip2si2(cmsg->CIPValue);
898 cmd.parm.setup.plan = cmsg->CallingPartyNumber[1];
899 cmd.parm.setup.screen = cmsg->CallingPartyNumber[2];
900
901 printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s\n",
902 card->contrnr,
903 cmd.parm.setup.phone,
904 cmd.parm.setup.si1,
905 cmd.parm.setup.si2,
906 cmd.parm.setup.eazmsn);
907
908 if (cmd.parm.setup.si1 == 1 && cmd.parm.setup.si2 != 0) {
909 printk(KERN_INFO "capidrv-%d: patching si2=%d to 0 for VBOX\n",
910 card->contrnr,
911 cmd.parm.setup.si2);
912 cmd.parm.setup.si2 = 0;
913 }
914
915 switch (card->interface.statcallb(&cmd)) {
916 case 0:
917 case 3:
918 /* No device matching this call.
919 * and isdn_common.c has send a HANGUP command
920 * which is ignored in state ST_PLCI_INCOMING,
921 * so we send RESP to ignore the call
922 */
923 capi_cmsg_answer(cmsg);
924 cmsg->Reject = 1; /* ignore */
925 send_message(card, cmsg);
926 plci_change_state(card, plcip, EV_PLCI_CONNECT_REJECT);
927 printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s ignored\n",
928 card->contrnr,
929 cmd.parm.setup.phone,
930 cmd.parm.setup.si1,
931 cmd.parm.setup.si2,
932 cmd.parm.setup.eazmsn);
933 break;
934 case 1:
935 /* At least one device matching this call (RING on ttyI)
936 * HL-driver may send ALERTING on the D-channel in this
937 * case.
938 * really means: RING on ttyI or a net interface
939 * accepted this call already.
940 *
941 * If the call was accepted, state has already changed,
942 * and CONNECT_RESP already sent.
943 */
944 if (plcip->state == ST_PLCI_INCOMING) {
945 printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s tty alerting\n",
946 card->contrnr,
947 cmd.parm.setup.phone,
948 cmd.parm.setup.si1,
949 cmd.parm.setup.si2,
950 cmd.parm.setup.eazmsn);
951 capi_fill_ALERT_REQ(cmsg,
952 global.ap.applid,
953 card->msgid++,
954 plcip->plci, /* adr */
955 NULL,/* BChannelinformation */
956 NULL,/* Keypadfacility */
957 NULL,/* Useruserdata */
958 NULL /* Facilitydataarray */
959 );
960 plcip->msgid = cmsg->Messagenumber;
961 send_message(card, cmsg);
962 } else {
963 printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s on netdev\n",
964 card->contrnr,
965 cmd.parm.setup.phone,
966 cmd.parm.setup.si1,
967 cmd.parm.setup.si2,
968 cmd.parm.setup.eazmsn);
969 }
970 break;
971
972 case 2: /* Call will be rejected. */
973 capi_cmsg_answer(cmsg);
974 cmsg->Reject = 2; /* reject call, normal call clearing */
975 send_message(card, cmsg);
976 plci_change_state(card, plcip, EV_PLCI_CONNECT_REJECT);
977 break;
978
979 default:
980 /* An error happened. (Invalid parameters for example.) */
981 capi_cmsg_answer(cmsg);
982 cmsg->Reject = 8; /* reject call,
983 destination out of order */
984 send_message(card, cmsg);
985 plci_change_state(card, plcip, EV_PLCI_CONNECT_REJECT);
986 break;
987 }
988 return;
989}
990
991static void handle_plci(_cmsg * cmsg)
992{
993 capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f);
994 capidrv_plci *plcip;
995 isdn_ctrl cmd;
996
997 if (!card) {
998 printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n",
999 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1000 cmsg->adr.adrController & 0x7f);
1001 return;
1002 }
1003 switch (CAPICMD(cmsg->Command, cmsg->Subcommand)) {
1004
1005 case CAPI_DISCONNECT_IND: /* plci */
1006 if (cmsg->Reason) {
1007 printk(KERN_INFO "capidrv-%d: %s reason 0x%x (%s) for plci 0x%x\n",
1008 card->contrnr,
1009 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1010 cmsg->Reason, capi_info2str(cmsg->Reason), cmsg->adr.adrPLCI);
1011 }
1012 if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI))) {
1013 capi_cmsg_answer(cmsg);
1014 send_message(card, cmsg);
1015 goto notfound;
1016 }
1017 card->bchans[plcip->chan].disconnecting = 1;
1018 plci_change_state(card, plcip, EV_PLCI_DISCONNECT_IND);
1019 capi_cmsg_answer(cmsg);
1020 send_message(card, cmsg);
1021 plci_change_state(card, plcip, EV_PLCI_DISCONNECT_RESP);
1022 break;
1023
1024 case CAPI_DISCONNECT_CONF: /* plci */
1025 if (cmsg->Info) {
1026 printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for plci 0x%x\n",
1027 card->contrnr,
1028 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1029 cmsg->Info, capi_info2str(cmsg->Info),
1030 cmsg->adr.adrPLCI);
1031 }
1032 if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI)))
1033 goto notfound;
1034
1035 card->bchans[plcip->chan].disconnecting = 1;
1036 break;
1037
1038 case CAPI_ALERT_CONF: /* plci */
1039 if (cmsg->Info) {
1040 printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for plci 0x%x\n",
1041 card->contrnr,
1042 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1043 cmsg->Info, capi_info2str(cmsg->Info),
1044 cmsg->adr.adrPLCI);
1045 }
1046 break;
1047
1048 case CAPI_CONNECT_IND: /* plci */
1049 handle_incoming_call(card, cmsg);
1050 break;
1051
1052 case CAPI_CONNECT_CONF: /* plci */
1053 if (cmsg->Info) {
1054 printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for plci 0x%x\n",
1055 card->contrnr,
1056 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1057 cmsg->Info, capi_info2str(cmsg->Info),
1058 cmsg->adr.adrPLCI);
1059 }
1060 if (!(plcip = find_plci_by_msgid(card, cmsg->Messagenumber)))
1061 goto notfound;
1062
1063 plcip->plci = cmsg->adr.adrPLCI;
1064 if (cmsg->Info) {
1065 plci_change_state(card, plcip, EV_PLCI_CONNECT_CONF_ERROR);
1066 } else {
1067 plci_change_state(card, plcip, EV_PLCI_CONNECT_CONF_OK);
1068 }
1069 break;
1070
1071 case CAPI_CONNECT_ACTIVE_IND: /* plci */
1072
1073 if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI)))
1074 goto notfound;
1075
1076 if (card->bchans[plcip->chan].incoming) {
1077 capi_cmsg_answer(cmsg);
1078 send_message(card, cmsg);
1079 plci_change_state(card, plcip, EV_PLCI_CONNECT_ACTIVE_IND);
1080 } else {
1081 capidrv_ncci *nccip;
1082 capi_cmsg_answer(cmsg);
1083 send_message(card, cmsg);
1084
1085 nccip = new_ncci(card, plcip, cmsg->adr.adrPLCI);
1086
1087 if (!nccip) {
1088 printk(KERN_ERR "capidrv-%d: no mem for ncci, sorry\n", card->contrnr);
1089 break; /* $$$$ */
1090 }
1091 capi_fill_CONNECT_B3_REQ(cmsg,
1092 global.ap.applid,
1093 card->msgid++,
1094 plcip->plci, /* adr */
1095 NULL /* NCPI */
1096 );
1097 nccip->msgid = cmsg->Messagenumber;
1098 send_message(card, cmsg);
1099 cmd.command = ISDN_STAT_DCONN;
1100 cmd.driver = card->myid;
1101 cmd.arg = plcip->chan;
1102 card->interface.statcallb(&cmd);
1103 plci_change_state(card, plcip, EV_PLCI_CONNECT_ACTIVE_IND);
1104 ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_REQ);
1105 }
1106 break;
1107
1108 case CAPI_INFO_IND: /* Controller/plci */
1109
1110 if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI)))
1111 goto notfound;
1112
1113 if (cmsg->InfoNumber == 0x4000) {
1114 if (cmsg->InfoElement[0] == 4) {
1115 cmd.command = ISDN_STAT_CINF;
1116 cmd.driver = card->myid;
1117 cmd.arg = plcip->chan;
1118 sprintf(cmd.parm.num, "%lu",
1119 (unsigned long)
1120 ((u32) cmsg->InfoElement[1]
1121 | ((u32) (cmsg->InfoElement[2]) << 8)
1122 | ((u32) (cmsg->InfoElement[3]) << 16)
1123 | ((u32) (cmsg->InfoElement[4]) << 24)));
1124 card->interface.statcallb(&cmd);
1125 break;
1126 }
1127 }
1128 printk(KERN_ERR "capidrv-%d: %s\n",
1129 card->contrnr, capi_cmsg2str(cmsg));
1130 break;
1131
1132 case CAPI_CONNECT_ACTIVE_CONF: /* plci */
1133 goto ignored;
1134 case CAPI_SELECT_B_PROTOCOL_CONF: /* plci */
1135 goto ignored;
1136 case CAPI_FACILITY_IND: /* Controller/plci/ncci */
1137 goto ignored;
1138 case CAPI_FACILITY_CONF: /* Controller/plci/ncci */
1139 goto ignored;
1140
1141 case CAPI_INFO_CONF: /* Controller/plci */
1142 goto ignored;
1143
1144 default:
1145 printk(KERN_ERR "capidrv-%d: got %s for plci 0x%x ???",
1146 card->contrnr,
1147 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1148 cmsg->adr.adrPLCI);
1149 }
1150 return;
1151 ignored:
1152 printk(KERN_INFO "capidrv-%d: %s for plci 0x%x ignored\n",
1153 card->contrnr,
1154 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1155 cmsg->adr.adrPLCI);
1156 return;
1157 notfound:
1158 printk(KERN_ERR "capidrv-%d: %s: plci 0x%x not found\n",
1159 card->contrnr,
1160 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1161 cmsg->adr.adrPLCI);
1162 return;
1163}
1164
1165static void handle_ncci(_cmsg * cmsg)
1166{
1167 capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f);
1168 capidrv_plci *plcip;
1169 capidrv_ncci *nccip;
1170 isdn_ctrl cmd;
1171 int len;
1172
1173 if (!card) {
1174 printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n",
1175 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1176 cmsg->adr.adrController & 0x7f);
1177 return;
1178 }
1179 switch (CAPICMD(cmsg->Command, cmsg->Subcommand)) {
1180
1181 case CAPI_CONNECT_B3_ACTIVE_IND: /* ncci */
1182 if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI)))
1183 goto notfound;
1184
1185 capi_cmsg_answer(cmsg);
1186 send_message(card, cmsg);
1187 ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_ACTIVE_IND);
1188
1189 cmd.command = ISDN_STAT_BCONN;
1190 cmd.driver = card->myid;
1191 cmd.arg = nccip->chan;
1192 card->interface.statcallb(&cmd);
1193
1194 printk(KERN_INFO "capidrv-%d: chan %d up with ncci 0x%x\n",
1195 card->contrnr, nccip->chan, nccip->ncci);
1196 break;
1197
1198 case CAPI_CONNECT_B3_ACTIVE_CONF: /* ncci */
1199 goto ignored;
1200
1201 case CAPI_CONNECT_B3_IND: /* ncci */
1202
1203 plcip = find_plci_by_ncci(card, cmsg->adr.adrNCCI);
1204 if (plcip) {
1205 nccip = new_ncci(card, plcip, cmsg->adr.adrNCCI);
1206 if (nccip) {
1207 ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_IND);
1208 capi_fill_CONNECT_B3_RESP(cmsg,
1209 global.ap.applid,
1210 card->msgid++,
1211 nccip->ncci, /* adr */
1212 0, /* Reject */
1213 NULL /* NCPI */
1214 );
1215 send_message(card, cmsg);
1216 ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_RESP);
1217 break;
1218 }
1219 printk(KERN_ERR "capidrv-%d: no mem for ncci, sorry\n", card->contrnr);
1220 } else {
1221 printk(KERN_ERR "capidrv-%d: %s: plci for ncci 0x%x not found\n",
1222 card->contrnr,
1223 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1224 cmsg->adr.adrNCCI);
1225 }
1226 capi_fill_CONNECT_B3_RESP(cmsg,
1227 global.ap.applid,
1228 card->msgid++,
1229 cmsg->adr.adrNCCI,
1230 2, /* Reject */
1231 NULL /* NCPI */
1232 );
1233 send_message(card, cmsg);
1234 break;
1235
1236 case CAPI_CONNECT_B3_CONF: /* ncci */
1237
1238 if (!(nccip = find_ncci_by_msgid(card,
1239 cmsg->adr.adrNCCI,
1240 cmsg->Messagenumber)))
1241 goto notfound;
1242
1243 nccip->ncci = cmsg->adr.adrNCCI;
1244 if (cmsg->Info) {
1245 printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for ncci 0x%x\n",
1246 card->contrnr,
1247 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1248 cmsg->Info, capi_info2str(cmsg->Info),
1249 cmsg->adr.adrNCCI);
1250 }
1251
1252 if (cmsg->Info)
1253 ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_CONF_ERROR);
1254 else
1255 ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_CONF_OK);
1256 break;
1257
1258 case CAPI_CONNECT_B3_T90_ACTIVE_IND: /* ncci */
1259 capi_cmsg_answer(cmsg);
1260 send_message(card, cmsg);
1261 break;
1262
1263 case CAPI_DATA_B3_IND: /* ncci */
1264 /* handled in handle_data() */
1265 goto ignored;
1266
1267 case CAPI_DATA_B3_CONF: /* ncci */
1268 if (cmsg->Info) {
1269 printk(KERN_WARNING "CAPI_DATA_B3_CONF: Info %x - %s\n",
1270 cmsg->Info, capi_info2str(cmsg->Info));
1271 }
1272 if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI)))
1273 goto notfound;
1274
1275 len = capidrv_del_ack(nccip, cmsg->DataHandle);
1276 if (len < 0)
1277 break;
1278 cmd.command = ISDN_STAT_BSENT;
1279 cmd.driver = card->myid;
1280 cmd.arg = nccip->chan;
1281 cmd.parm.length = len;
1282 card->interface.statcallb(&cmd);
1283 break;
1284
1285 case CAPI_DISCONNECT_B3_IND: /* ncci */
1286 if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI)))
1287 goto notfound;
1288
1289 card->bchans[nccip->chan].disconnecting = 1;
1290 ncci_change_state(card, nccip, EV_NCCI_DISCONNECT_B3_IND);
1291 capi_cmsg_answer(cmsg);
1292 send_message(card, cmsg);
1293 ncci_change_state(card, nccip, EV_NCCI_DISCONNECT_B3_RESP);
1294 break;
1295
1296 case CAPI_DISCONNECT_B3_CONF: /* ncci */
1297 if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI)))
1298 goto notfound;
1299 if (cmsg->Info) {
1300 printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for ncci 0x%x\n",
1301 card->contrnr,
1302 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1303 cmsg->Info, capi_info2str(cmsg->Info),
1304 cmsg->adr.adrNCCI);
1305 ncci_change_state(card, nccip, EV_NCCI_DISCONNECT_B3_CONF_ERROR);
1306 }
1307 break;
1308
1309 case CAPI_RESET_B3_IND: /* ncci */
1310 if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI)))
1311 goto notfound;
1312 ncci_change_state(card, nccip, EV_NCCI_RESET_B3_IND);
1313 capi_cmsg_answer(cmsg);
1314 send_message(card, cmsg);
1315 break;
1316
1317 case CAPI_RESET_B3_CONF: /* ncci */
1318 goto ignored; /* $$$$ */
1319
1320 case CAPI_FACILITY_IND: /* Controller/plci/ncci */
1321 goto ignored;
1322 case CAPI_FACILITY_CONF: /* Controller/plci/ncci */
1323 goto ignored;
1324
1325 default:
1326 printk(KERN_ERR "capidrv-%d: got %s for ncci 0x%x ???",
1327 card->contrnr,
1328 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1329 cmsg->adr.adrNCCI);
1330 }
1331 return;
1332 ignored:
1333 printk(KERN_INFO "capidrv-%d: %s for ncci 0x%x ignored\n",
1334 card->contrnr,
1335 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1336 cmsg->adr.adrNCCI);
1337 return;
1338 notfound:
1339 printk(KERN_ERR "capidrv-%d: %s: ncci 0x%x not found\n",
1340 card->contrnr,
1341 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1342 cmsg->adr.adrNCCI);
1343}
1344
1345
1346static void handle_data(_cmsg * cmsg, struct sk_buff *skb)
1347{
1348 capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f);
1349 capidrv_ncci *nccip;
1350
1351 if (!card) {
1352 printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n",
1353 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1354 cmsg->adr.adrController & 0x7f);
1355 kfree_skb(skb);
1356 return;
1357 }
1358 if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI))) {
1359 printk(KERN_ERR "capidrv-%d: %s: ncci 0x%x not found\n",
1360 card->contrnr,
1361 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1362 cmsg->adr.adrNCCI);
1363 kfree_skb(skb);
1364 return;
1365 }
1366 (void) skb_pull(skb, CAPIMSG_LEN(skb->data));
1367 card->interface.rcvcallb_skb(card->myid, nccip->chan, skb);
1368 capi_cmsg_answer(cmsg);
1369 send_message(card, cmsg);
1370}
1371
1372static _cmsg s_cmsg;
1373
1374static void capidrv_recv_message(struct capi20_appl *ap, struct sk_buff *skb)
1375{
1376 capi_message2cmsg(&s_cmsg, skb->data);
1377 if (debugmode > 3)
1378 printk(KERN_DEBUG "capidrv_signal: applid=%d %s\n",
1379 ap->applid, capi_cmsg2str(&s_cmsg));
1380
1381 if (s_cmsg.Command == CAPI_DATA_B3
1382 && s_cmsg.Subcommand == CAPI_IND) {
1383 handle_data(&s_cmsg, skb);
1384 return;
1385 }
1386 if ((s_cmsg.adr.adrController & 0xffffff00) == 0)
1387 handle_controller(&s_cmsg);
1388 else if ((s_cmsg.adr.adrPLCI & 0xffff0000) == 0)
1389 handle_plci(&s_cmsg);
1390 else
1391 handle_ncci(&s_cmsg);
1392 /*
1393 * data of skb used in s_cmsg,
1394 * free data when s_cmsg is not used again
1395 * thanks to Lars Heete <hel@admin.de>
1396 */
1397 kfree_skb(skb);
1398}
1399
1400/* ------------------------------------------------------------------- */
1401
1402#define PUTBYTE_TO_STATUS(card, byte) \
1403 do { \
1404 *(card)->q931_write++ = (byte); \
1405 if ((card)->q931_write > (card)->q931_end) \
1406 (card)->q931_write = (card)->q931_buf; \
1407 } while (0)
1408
1409static void handle_dtrace_data(capidrv_contr *card,
1410 int send, int level2, u8 *data, u16 len)
1411{
1412 u8 *p, *end;
1413 isdn_ctrl cmd;
1414
1415 if (!len) {
1416 printk(KERN_DEBUG "capidrv-%d: avmb1_q931_data: len == %d\n",
1417 card->contrnr, len);
1418 return;
1419 }
1420
1421 if (level2) {
1422 PUTBYTE_TO_STATUS(card, 'D');
1423 PUTBYTE_TO_STATUS(card, '2');
1424 PUTBYTE_TO_STATUS(card, send ? '>' : '<');
1425 PUTBYTE_TO_STATUS(card, ':');
1426 } else {
1427 PUTBYTE_TO_STATUS(card, 'D');
1428 PUTBYTE_TO_STATUS(card, '3');
1429 PUTBYTE_TO_STATUS(card, send ? '>' : '<');
1430 PUTBYTE_TO_STATUS(card, ':');
1431 }
1432
1433 for (p = data, end = data+len; p < end; p++) {
1434 u8 w;
1435 PUTBYTE_TO_STATUS(card, ' ');
1436 w = (*p >> 4) & 0xf;
1437 PUTBYTE_TO_STATUS(card, (w < 10) ? '0'+w : 'A'-10+w);
1438 w = *p & 0xf;
1439 PUTBYTE_TO_STATUS(card, (w < 10) ? '0'+w : 'A'-10+w);
1440 }
1441 PUTBYTE_TO_STATUS(card, '\n');
1442
1443 cmd.command = ISDN_STAT_STAVAIL;
1444 cmd.driver = card->myid;
1445 cmd.arg = len*3+5;
1446 card->interface.statcallb(&cmd);
1447}
1448
1449/* ------------------------------------------------------------------- */
1450
1451static _cmsg cmdcmsg;
1452
1453static int capidrv_ioctl(isdn_ctrl * c, capidrv_contr * card)
1454{
1455 switch (c->arg) {
1456 case 1:
1457 debugmode = (int)(*((unsigned int *)c->parm.num));
1458 printk(KERN_DEBUG "capidrv-%d: debugmode=%d\n",
1459 card->contrnr, debugmode);
1460 return 0;
1461 default:
1462 printk(KERN_DEBUG "capidrv-%d: capidrv_ioctl(%ld) called ??\n",
1463 card->contrnr, c->arg);
1464 return -EINVAL;
1465 }
1466 return -EINVAL;
1467}
1468
1469/*
1470 * Handle leased lines (CAPI-Bundling)
1471 */
1472
1473struct internal_bchannelinfo {
1474 unsigned short channelalloc;
1475 unsigned short operation;
1476 unsigned char cmask[31];
1477};
1478
1479static int decodeFVteln(char *teln, unsigned long *bmaskp, int *activep)
1480{
1481 unsigned long bmask = 0;
1482 int active = !0;
1483 char *s;
1484 int i;
1485
1486 if (strncmp(teln, "FV:", 3) != 0)
1487 return 1;
1488 s = teln + 3;
1489 while (*s && *s == ' ') s++;
1490 if (!*s) return -2;
1491 if (*s == 'p' || *s == 'P') {
1492 active = 0;
1493 s++;
1494 }
1495 if (*s == 'a' || *s == 'A') {
1496 active = !0;
1497 s++;
1498 }
1499 while (*s) {
1500 int digit1 = 0;
1501 int digit2 = 0;
1502 if (!isdigit(*s)) return -3;
1503 while (isdigit(*s)) { digit1 = digit1*10 + (*s - '0'); s++; }
1504 if (digit1 <= 0 && digit1 > 30) return -4;
1505 if (*s == 0 || *s == ',' || *s == ' ') {
1506 bmask |= (1 << digit1);
1507 digit1 = 0;
1508 if (*s) s++;
1509 continue;
1510 }
1511 if (*s != '-') return -5;
1512 s++;
1513 if (!isdigit(*s)) return -3;
1514 while (isdigit(*s)) { digit2 = digit2*10 + (*s - '0'); s++; }
1515 if (digit2 <= 0 && digit2 > 30) return -4;
1516 if (*s == 0 || *s == ',' || *s == ' ') {
1517 if (digit1 > digit2)
1518 for (i = digit2; i <= digit1 ; i++)
1519 bmask |= (1 << i);
1520 else
1521 for (i = digit1; i <= digit2 ; i++)
1522 bmask |= (1 << i);
1523 digit1 = digit2 = 0;
1524 if (*s) s++;
1525 continue;
1526 }
1527 return -6;
1528 }
1529 if (activep) *activep = active;
1530 if (bmaskp) *bmaskp = bmask;
1531 return 0;
1532}
1533
1534static int FVteln2capi20(char *teln, u8 AdditionalInfo[1+2+2+31])
1535{
1536 unsigned long bmask;
1537 int active;
1538 int rc, i;
1539
1540 rc = decodeFVteln(teln, &bmask, &active);
1541 if (rc) return rc;
1542 /* Length */
1543 AdditionalInfo[0] = 2+2+31;
1544 /* Channel: 3 => use channel allocation */
1545 AdditionalInfo[1] = 3; AdditionalInfo[2] = 0;
1546 /* Operation: 0 => DTE mode, 1 => DCE mode */
1547 if (active) {
1548 AdditionalInfo[3] = 0; AdditionalInfo[4] = 0;
1549 } else {
1550 AdditionalInfo[3] = 1; AdditionalInfo[4] = 0;
1551 }
1552 /* Channel mask array */
1553 AdditionalInfo[5] = 0; /* no D-Channel */
1554 for (i=1; i <= 30; i++)
1555 AdditionalInfo[5+i] = (bmask & (1 << i)) ? 0xff : 0;
1556 return 0;
1557}
1558
1559static int capidrv_command(isdn_ctrl * c, capidrv_contr * card)
1560{
1561 isdn_ctrl cmd;
1562 struct capidrv_bchan *bchan;
1563 struct capidrv_plci *plcip;
1564 u8 AdditionalInfo[1+2+2+31];
1565 int rc, isleasedline = 0;
1566
1567 if (c->command == ISDN_CMD_IOCTL)
1568 return capidrv_ioctl(c, card);
1569
1570 switch (c->command) {
1571 case ISDN_CMD_DIAL:{
1572 u8 calling[ISDN_MSNLEN + 3];
1573 u8 called[ISDN_MSNLEN + 2];
1574
1575 if (debugmode)
1576 printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_DIAL(ch=%ld,\"%s,%d,%d,%s\")\n",
1577 card->contrnr,
1578 c->arg,
1579 c->parm.setup.phone,
1580 c->parm.setup.si1,
1581 c->parm.setup.si2,
1582 c->parm.setup.eazmsn);
1583
1584 bchan = &card->bchans[c->arg % card->nbchan];
1585
1586 if (bchan->plcip) {
1587 printk(KERN_ERR "capidrv-%d: dail ch=%ld,\"%s,%d,%d,%s\" in use (plci=0x%x)\n",
1588 card->contrnr,
1589 c->arg,
1590 c->parm.setup.phone,
1591 c->parm.setup.si1,
1592 c->parm.setup.si2,
1593 c->parm.setup.eazmsn,
1594 bchan->plcip->plci);
1595 return 0;
1596 }
1597 bchan->si1 = c->parm.setup.si1;
1598 bchan->si2 = c->parm.setup.si2;
1599
1600 strncpy(bchan->num, c->parm.setup.phone, sizeof(bchan->num));
1601 strncpy(bchan->mynum, c->parm.setup.eazmsn, sizeof(bchan->mynum));
1602 rc = FVteln2capi20(bchan->num, AdditionalInfo);
1603 isleasedline = (rc == 0);
1604 if (rc < 0)
1605 printk(KERN_ERR "capidrv-%d: WARNING: invalid leased linedefinition \"%s\"\n", card->contrnr, bchan->num);
1606
1607 if (isleasedline) {
1608 calling[0] = 0;
1609 called[0] = 0;
1610 if (debugmode)
1611 printk(KERN_DEBUG "capidrv-%d: connecting leased line\n", card->contrnr);
1612 } else {
1613 calling[0] = strlen(bchan->mynum) + 2;
1614 calling[1] = 0;
1615 calling[2] = 0x80;
1616 strncpy(calling + 3, bchan->mynum, ISDN_MSNLEN);
1617 called[0] = strlen(bchan->num) + 1;
1618 called[1] = 0x80;
1619 strncpy(called + 2, bchan->num, ISDN_MSNLEN);
1620 }
1621
1622 capi_fill_CONNECT_REQ(&cmdcmsg,
1623 global.ap.applid,
1624 card->msgid++,
1625 card->contrnr, /* adr */
1626 si2cip(bchan->si1, bchan->si2), /* cipvalue */
1627 called, /* CalledPartyNumber */
1628 calling, /* CallingPartyNumber */
1629 NULL, /* CalledPartySubaddress */
1630 NULL, /* CallingPartySubaddress */
1631 b1prot(bchan->l2, bchan->l3), /* B1protocol */
1632 b2prot(bchan->l2, bchan->l3), /* B2protocol */
1633 b3prot(bchan->l2, bchan->l3), /* B3protocol */
1634 b1config(bchan->l2, bchan->l3), /* B1configuration */
1635 NULL, /* B2configuration */
1636 NULL, /* B3configuration */
1637 NULL, /* BC */
1638 NULL, /* LLC */
1639 NULL, /* HLC */
1640 /* BChannelinformation */
1641 isleasedline ? AdditionalInfo : NULL,
1642 NULL, /* Keypadfacility */
1643 NULL, /* Useruserdata */
1644 NULL /* Facilitydataarray */
1645 );
1646 if ((plcip = new_plci(card, (c->arg % card->nbchan))) == 0) {
1647 cmd.command = ISDN_STAT_DHUP;
1648 cmd.driver = card->myid;
1649 cmd.arg = (c->arg % card->nbchan);
1650 card->interface.statcallb(&cmd);
1651 return -1;
1652 }
1653 plcip->msgid = cmdcmsg.Messagenumber;
1654 plcip->leasedline = isleasedline;
1655 plci_change_state(card, plcip, EV_PLCI_CONNECT_REQ);
1656 send_message(card, &cmdcmsg);
1657 return 0;
1658 }
1659
1660 case ISDN_CMD_ACCEPTD:
1661
1662 bchan = &card->bchans[c->arg % card->nbchan];
1663 if (debugmode)
1664 printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_ACCEPTD(ch=%ld) l2=%d l3=%d\n",
1665 card->contrnr,
1666 c->arg, bchan->l2, bchan->l3);
1667
1668 capi_fill_CONNECT_RESP(&cmdcmsg,
1669 global.ap.applid,
1670 card->msgid++,
1671 bchan->plcip->plci, /* adr */
1672 0, /* Reject */
1673 b1prot(bchan->l2, bchan->l3), /* B1protocol */
1674 b2prot(bchan->l2, bchan->l3), /* B2protocol */
1675 b3prot(bchan->l2, bchan->l3), /* B3protocol */
1676 b1config(bchan->l2, bchan->l3), /* B1configuration */
1677 NULL, /* B2configuration */
1678 NULL, /* B3configuration */
1679 NULL, /* ConnectedNumber */
1680 NULL, /* ConnectedSubaddress */
1681 NULL, /* LLC */
1682 NULL, /* BChannelinformation */
1683 NULL, /* Keypadfacility */
1684 NULL, /* Useruserdata */
1685 NULL /* Facilitydataarray */
1686 );
1687 capi_cmsg2message(&cmdcmsg, cmdcmsg.buf);
1688 plci_change_state(card, bchan->plcip, EV_PLCI_CONNECT_RESP);
1689 send_message(card, &cmdcmsg);
1690 return 0;
1691
1692 case ISDN_CMD_ACCEPTB:
1693 if (debugmode)
1694 printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_ACCEPTB(ch=%ld)\n",
1695 card->contrnr,
1696 c->arg);
1697 return -ENOSYS;
1698
1699 case ISDN_CMD_HANGUP:
1700 if (debugmode)
1701 printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_HANGUP(ch=%ld)\n",
1702 card->contrnr,
1703 c->arg);
1704 bchan = &card->bchans[c->arg % card->nbchan];
1705
1706 if (bchan->disconnecting) {
1707 if (debugmode)
1708 printk(KERN_DEBUG "capidrv-%d: chan %ld already disconnecting ...\n",
1709 card->contrnr,
1710 c->arg);
1711 return 0;
1712 }
1713 if (bchan->nccip) {
1714 bchan->disconnecting = 1;
1715 capi_fill_DISCONNECT_B3_REQ(&cmdcmsg,
1716 global.ap.applid,
1717 card->msgid++,
1718 bchan->nccip->ncci,
1719 NULL /* NCPI */
1720 );
1721 ncci_change_state(card, bchan->nccip, EV_NCCI_DISCONNECT_B3_REQ);
1722 send_message(card, &cmdcmsg);
1723 return 0;
1724 } else if (bchan->plcip) {
1725 if (bchan->plcip->state == ST_PLCI_INCOMING) {
1726 /*
1727 * just ignore, we a called from
1728 * isdn_status_callback(),
1729 * which will return 0 or 2, this is handled
1730 * by the CONNECT_IND handler
1731 */
1732 bchan->disconnecting = 1;
1733 return 0;
1734 } else if (bchan->plcip->plci) {
1735 bchan->disconnecting = 1;
1736 capi_fill_DISCONNECT_REQ(&cmdcmsg,
1737 global.ap.applid,
1738 card->msgid++,
1739 bchan->plcip->plci,
1740 NULL, /* BChannelinformation */
1741 NULL, /* Keypadfacility */
1742 NULL, /* Useruserdata */
1743 NULL /* Facilitydataarray */
1744 );
1745 plci_change_state(card, bchan->plcip, EV_PLCI_DISCONNECT_REQ);
1746 send_message(card, &cmdcmsg);
1747 return 0;
1748 } else {
1749 printk(KERN_ERR "capidrv-%d: chan %ld disconnect request while waiting for CONNECT_CONF\n",
1750 card->contrnr,
1751 c->arg);
1752 return -EINVAL;
1753 }
1754 }
1755 printk(KERN_ERR "capidrv-%d: chan %ld disconnect request on free channel\n",
1756 card->contrnr,
1757 c->arg);
1758 return -EINVAL;
1759/* ready */
1760
1761 case ISDN_CMD_SETL2:
1762 if (debugmode)
1763 printk(KERN_DEBUG "capidrv-%d: set L2 on chan %ld to %ld\n",
1764 card->contrnr,
1765 (c->arg & 0xff), (c->arg >> 8));
1766 bchan = &card->bchans[(c->arg & 0xff) % card->nbchan];
1767 bchan->l2 = (c->arg >> 8);
1768 return 0;
1769
1770 case ISDN_CMD_SETL3:
1771 if (debugmode)
1772 printk(KERN_DEBUG "capidrv-%d: set L3 on chan %ld to %ld\n",
1773 card->contrnr,
1774 (c->arg & 0xff), (c->arg >> 8));
1775 bchan = &card->bchans[(c->arg & 0xff) % card->nbchan];
1776 bchan->l3 = (c->arg >> 8);
1777 return 0;
1778
1779 case ISDN_CMD_SETEAZ:
1780 if (debugmode)
1781 printk(KERN_DEBUG "capidrv-%d: set EAZ \"%s\" on chan %ld\n",
1782 card->contrnr,
1783 c->parm.num, c->arg);
1784 bchan = &card->bchans[c->arg % card->nbchan];
1785 strncpy(bchan->msn, c->parm.num, ISDN_MSNLEN);
1786 return 0;
1787
1788 case ISDN_CMD_CLREAZ:
1789 if (debugmode)
1790 printk(KERN_DEBUG "capidrv-%d: clearing EAZ on chan %ld\n",
1791 card->contrnr, c->arg);
1792 bchan = &card->bchans[c->arg % card->nbchan];
1793 bchan->msn[0] = 0;
1794 return 0;
1795
1796 default:
1797 printk(KERN_ERR "capidrv-%d: ISDN_CMD_%d, Huh?\n",
1798 card->contrnr, c->command);
1799 return -EINVAL;
1800 }
1801 return 0;
1802}
1803
1804static int if_command(isdn_ctrl * c)
1805{
1806 capidrv_contr *card = findcontrbydriverid(c->driver);
1807
1808 if (card)
1809 return capidrv_command(c, card);
1810
1811 printk(KERN_ERR
1812 "capidrv: if_command %d called with invalid driverId %d!\n",
1813 c->command, c->driver);
1814 return -ENODEV;
1815}
1816
1817static _cmsg sendcmsg;
1818
1819static int if_sendbuf(int id, int channel, int doack, struct sk_buff *skb)
1820{
1821 capidrv_contr *card = findcontrbydriverid(id);
1822 capidrv_bchan *bchan;
1823 capidrv_ncci *nccip;
1824 int len = skb->len;
1825 int msglen;
1826 u16 errcode;
1827 u16 datahandle;
1828
1829 if (!card) {
1830 printk(KERN_ERR "capidrv: if_sendbuf called with invalid driverId %d!\n",
1831 id);
1832 return 0;
1833 }
1834 if (debugmode > 4)
1835 printk(KERN_DEBUG "capidrv-%d: sendbuf len=%d skb=%p doack=%d\n",
1836 card->contrnr, len, skb, doack);
1837 bchan = &card->bchans[channel % card->nbchan];
1838 nccip = bchan->nccip;
1839 if (!nccip || nccip->state != ST_NCCI_ACTIVE) {
1840 printk(KERN_ERR "capidrv-%d: if_sendbuf: %s:%d: chan not up!\n",
1841 card->contrnr, card->name, channel);
1842 return 0;
1843 }
1844 datahandle = nccip->datahandle;
1845 capi_fill_DATA_B3_REQ(&sendcmsg, global.ap.applid, card->msgid++,
1846 nccip->ncci, /* adr */
1847 (u32) skb->data, /* Data */
1848 skb->len, /* DataLength */
1849 datahandle, /* DataHandle */
1850 0 /* Flags */
1851 );
1852
1853 if (capidrv_add_ack(nccip, datahandle, doack ? (int)skb->len : -1) < 0)
1854 return 0;
1855
1856 capi_cmsg2message(&sendcmsg, sendcmsg.buf);
1857 msglen = CAPIMSG_LEN(sendcmsg.buf);
1858 if (skb_headroom(skb) < msglen) {
1859 struct sk_buff *nskb = skb_realloc_headroom(skb, msglen);
1860 if (!nskb) {
1861 printk(KERN_ERR "capidrv-%d: if_sendbuf: no memory\n",
1862 card->contrnr);
1863 (void)capidrv_del_ack(nccip, datahandle);
1864 return 0;
1865 }
1866 printk(KERN_DEBUG "capidrv-%d: only %d bytes headroom, need %d\n",
1867 card->contrnr, skb_headroom(skb), msglen);
1868 memcpy(skb_push(nskb, msglen), sendcmsg.buf, msglen);
1869 errcode = capi20_put_message(&global.ap, nskb);
1870 if (errcode == CAPI_NOERROR) {
1871 dev_kfree_skb(skb);
1872 nccip->datahandle++;
1873 return len;
1874 }
1875 if (debugmode > 3)
1876 printk(KERN_DEBUG "capidrv-%d: sendbuf putmsg ret(%x) - %s\n",
1877 card->contrnr, errcode, capi_info2str(errcode));
1878 (void)capidrv_del_ack(nccip, datahandle);
1879 dev_kfree_skb(nskb);
1880 return errcode == CAPI_SENDQUEUEFULL ? 0 : -1;
1881 } else {
1882 memcpy(skb_push(skb, msglen), sendcmsg.buf, msglen);
1883 errcode = capi20_put_message(&global.ap, skb);
1884 if (errcode == CAPI_NOERROR) {
1885 nccip->datahandle++;
1886 return len;
1887 }
1888 if (debugmode > 3)
1889 printk(KERN_DEBUG "capidrv-%d: sendbuf putmsg ret(%x) - %s\n",
1890 card->contrnr, errcode, capi_info2str(errcode));
1891 skb_pull(skb, msglen);
1892 (void)capidrv_del_ack(nccip, datahandle);
1893 return errcode == CAPI_SENDQUEUEFULL ? 0 : -1;
1894 }
1895}
1896
1897static int if_readstat(u8 __user *buf, int len, int id, int channel)
1898{
1899 capidrv_contr *card = findcontrbydriverid(id);
1900 int count;
1901 u8 __user *p;
1902
1903 if (!card) {
1904 printk(KERN_ERR "capidrv: if_readstat called with invalid driverId %d!\n",
1905 id);
1906 return -ENODEV;
1907 }
1908
1909 for (p=buf, count=0; count < len; p++, count++) {
1910 put_user(*card->q931_read++, p);
1911 if (card->q931_read > card->q931_end)
1912 card->q931_read = card->q931_buf;
1913 }
1914 return count;
1915
1916}
1917
1918static void enable_dchannel_trace(capidrv_contr *card)
1919{
1920 u8 manufacturer[CAPI_MANUFACTURER_LEN];
1921 capi_version version;
1922 u16 contr = card->contrnr;
1923 u16 errcode;
1924 u16 avmversion[3];
1925
1926 errcode = capi20_get_manufacturer(contr, manufacturer);
1927 if (errcode != CAPI_NOERROR) {
1928 printk(KERN_ERR "%s: can't get manufacturer (0x%x)\n",
1929 card->name, errcode);
1930 return;
1931 }
1932 if (strstr(manufacturer, "AVM") == 0) {
1933 printk(KERN_ERR "%s: not from AVM, no d-channel trace possible (%s)\n",
1934 card->name, manufacturer);
1935 return;
1936 }
1937 errcode = capi20_get_version(contr, &version);
1938 if (errcode != CAPI_NOERROR) {
1939 printk(KERN_ERR "%s: can't get version (0x%x)\n",
1940 card->name, errcode);
1941 return;
1942 }
1943 avmversion[0] = (version.majormanuversion >> 4) & 0x0f;
1944 avmversion[1] = (version.majormanuversion << 4) & 0xf0;
1945 avmversion[1] |= (version.minormanuversion >> 4) & 0x0f;
1946 avmversion[2] |= version.minormanuversion & 0x0f;
1947
1948 if (avmversion[0] > 3 || (avmversion[0] == 3 && avmversion[1] > 5)) {
1949 printk(KERN_INFO "%s: D2 trace enabled\n", card->name);
1950 capi_fill_MANUFACTURER_REQ(&cmdcmsg, global.ap.applid,
1951 card->msgid++,
1952 contr,
1953 0x214D5641, /* ManuID */
1954 0, /* Class */
1955 1, /* Function */
1956 (_cstruct)"\004\200\014\000\000");
1957 } else {
1958 printk(KERN_INFO "%s: D3 trace enabled\n", card->name);
1959 capi_fill_MANUFACTURER_REQ(&cmdcmsg, global.ap.applid,
1960 card->msgid++,
1961 contr,
1962 0x214D5641, /* ManuID */
1963 0, /* Class */
1964 1, /* Function */
1965 (_cstruct)"\004\002\003\000\000");
1966 }
1967 send_message(card, &cmdcmsg);
1968}
1969
1970
1971static void send_listen(capidrv_contr *card)
1972{
1973 capi_fill_LISTEN_REQ(&cmdcmsg, global.ap.applid,
1974 card->msgid++,
1975 card->contrnr, /* controller */
1976 1 << 6, /* Infomask */
1977 card->cipmask,
1978 card->cipmask2,
1979 NULL, NULL);
1980 send_message(card, &cmdcmsg);
1981 listen_change_state(card, EV_LISTEN_REQ);
1982}
1983
1984static void listentimerfunc(unsigned long x)
1985{
1986 capidrv_contr *card = (capidrv_contr *)x;
1987 if (card->state != ST_LISTEN_NONE && card->state != ST_LISTEN_ACTIVE)
1988 printk(KERN_ERR "%s: controller dead ??\n", card->name);
1989 send_listen(card);
1990 mod_timer(&card->listentimer, jiffies + 60*HZ);
1991}
1992
1993
1994static int capidrv_addcontr(u16 contr, struct capi_profile *profp)
1995{
1996 capidrv_contr *card;
1997 unsigned long flags;
1998 isdn_ctrl cmd;
1999 char id[20];
2000 int i;
2001
2002 sprintf(id, "capidrv-%d", contr);
2003 if (!try_module_get(THIS_MODULE)) {
2004 printk(KERN_WARNING "capidrv: (%s) Could not reserve module\n", id);
2005 return -1;
2006 }
2007 if (!(card = (capidrv_contr *) kmalloc(sizeof(capidrv_contr), GFP_ATOMIC))) {
2008 printk(KERN_WARNING
2009 "capidrv: (%s) Could not allocate contr-struct.\n", id);
2010 return -1;
2011 }
2012 memset(card, 0, sizeof(capidrv_contr));
2013 card->owner = THIS_MODULE;
2014 init_timer(&card->listentimer);
2015 strcpy(card->name, id);
2016 card->contrnr = contr;
2017 card->nbchan = profp->nbchannel;
2018 card->bchans = (capidrv_bchan *) kmalloc(sizeof(capidrv_bchan) * card->nbchan, GFP_ATOMIC);
2019 if (!card->bchans) {
2020 printk(KERN_WARNING
2021 "capidrv: (%s) Could not allocate bchan-structs.\n", id);
2022 module_put(card->owner);
2023 kfree(card);
2024 return -1;
2025 }
2026 card->interface.channels = profp->nbchannel;
2027 card->interface.maxbufsize = 2048;
2028 card->interface.command = if_command;
2029 card->interface.writebuf_skb = if_sendbuf;
2030 card->interface.writecmd = NULL;
2031 card->interface.readstat = if_readstat;
2032 card->interface.features = ISDN_FEATURE_L2_HDLC |
2033 ISDN_FEATURE_L2_TRANS |
2034 ISDN_FEATURE_L3_TRANS |
2035 ISDN_FEATURE_P_UNKNOWN |
2036 ISDN_FEATURE_L2_X75I |
2037 ISDN_FEATURE_L2_X75UI |
2038 ISDN_FEATURE_L2_X75BUI;
2039 if (profp->support1 & (1<<2))
2040 card->interface.features |= ISDN_FEATURE_L2_V11096 |
2041 ISDN_FEATURE_L2_V11019 |
2042 ISDN_FEATURE_L2_V11038;
2043 if (profp->support1 & (1<<8))
2044 card->interface.features |= ISDN_FEATURE_L2_MODEM;
2045 card->interface.hl_hdrlen = 22; /* len of DATA_B3_REQ */
2046 strncpy(card->interface.id, id, sizeof(card->interface.id) - 1);
2047
2048
2049 card->q931_read = card->q931_buf;
2050 card->q931_write = card->q931_buf;
2051 card->q931_end = card->q931_buf + sizeof(card->q931_buf) - 1;
2052
2053 if (!register_isdn(&card->interface)) {
2054 printk(KERN_ERR "capidrv: Unable to register contr %s\n", id);
2055 kfree(card->bchans);
2056 module_put(card->owner);
2057 kfree(card);
2058 return -1;
2059 }
2060 card->myid = card->interface.channels;
2061 memset(card->bchans, 0, sizeof(capidrv_bchan) * card->nbchan);
2062 for (i = 0; i < card->nbchan; i++) {
2063 card->bchans[i].contr = card;
2064 }
2065
2066 spin_lock_irqsave(&global_lock, flags);
2067 card->next = global.contr_list;
2068 global.contr_list = card;
2069 global.ncontr++;
2070 spin_unlock_irqrestore(&global_lock, flags);
2071
2072 cmd.command = ISDN_STAT_RUN;
2073 cmd.driver = card->myid;
2074 card->interface.statcallb(&cmd);
2075
2076 card->cipmask = 0x1FFF03FF; /* any */
2077 card->cipmask2 = 0;
2078
2079 card->listentimer.data = (unsigned long)card;
2080 card->listentimer.function = listentimerfunc;
2081 send_listen(card);
2082 mod_timer(&card->listentimer, jiffies + 60*HZ);
2083
2084 printk(KERN_INFO "%s: now up (%d B channels)\n",
2085 card->name, card->nbchan);
2086
2087 enable_dchannel_trace(card);
2088
2089 return 0;
2090}
2091
2092static int capidrv_delcontr(u16 contr)
2093{
2094 capidrv_contr **pp, *card;
2095 unsigned long flags;
2096 isdn_ctrl cmd;
2097
2098 spin_lock_irqsave(&global_lock, flags);
2099 for (card = global.contr_list; card; card = card->next) {
2100 if (card->contrnr == contr)
2101 break;
2102 }
2103 if (!card) {
2104 spin_unlock_irqrestore(&global_lock, flags);
2105 printk(KERN_ERR "capidrv: delcontr: no contr %u\n", contr);
2106 return -1;
2107 }
2108 #warning FIXME: maybe a race condition the card should be removed here from global list /kkeil
2109 spin_unlock_irqrestore(&global_lock, flags);
2110
2111 del_timer(&card->listentimer);
2112
2113 if (debugmode)
2114 printk(KERN_DEBUG "capidrv-%d: id=%d unloading\n",
2115 card->contrnr, card->myid);
2116
2117 cmd.command = ISDN_STAT_STOP;
2118 cmd.driver = card->myid;
2119 card->interface.statcallb(&cmd);
2120
2121 while (card->nbchan) {
2122
2123 cmd.command = ISDN_STAT_DISCH;
2124 cmd.driver = card->myid;
2125 cmd.arg = card->nbchan-1;
2126 cmd.parm.num[0] = 0;
2127 if (debugmode)
2128 printk(KERN_DEBUG "capidrv-%d: id=%d disable chan=%ld\n",
2129 card->contrnr, card->myid, cmd.arg);
2130 card->interface.statcallb(&cmd);
2131
2132 if (card->bchans[card->nbchan-1].nccip)
2133 free_ncci(card, card->bchans[card->nbchan-1].nccip);
2134 if (card->bchans[card->nbchan-1].plcip)
2135 free_plci(card, card->bchans[card->nbchan-1].plcip);
2136 if (card->plci_list)
2137 printk(KERN_ERR "capidrv: bug in free_plci()\n");
2138 card->nbchan--;
2139 }
2140 kfree(card->bchans);
2141 card->bchans = NULL;
2142
2143 if (debugmode)
2144 printk(KERN_DEBUG "capidrv-%d: id=%d isdn unload\n",
2145 card->contrnr, card->myid);
2146
2147 cmd.command = ISDN_STAT_UNLOAD;
2148 cmd.driver = card->myid;
2149 card->interface.statcallb(&cmd);
2150
2151 if (debugmode)
2152 printk(KERN_DEBUG "capidrv-%d: id=%d remove contr from list\n",
2153 card->contrnr, card->myid);
2154
2155 spin_lock_irqsave(&global_lock, flags);
2156 for (pp = &global.contr_list; *pp; pp = &(*pp)->next) {
2157 if (*pp == card) {
2158 *pp = (*pp)->next;
2159 card->next = NULL;
2160 global.ncontr--;
2161 break;
2162 }
2163 }
2164 spin_unlock_irqrestore(&global_lock, flags);
2165
2166 module_put(card->owner);
2167 printk(KERN_INFO "%s: now down.\n", card->name);
2168 kfree(card);
2169 return 0;
2170}
2171
2172
2173static void lower_callback(unsigned int cmd, u32 contr, void *data)
2174{
2175
2176 switch (cmd) {
2177 case KCI_CONTRUP:
2178 printk(KERN_INFO "capidrv: controller %hu up\n", contr);
2179 (void) capidrv_addcontr(contr, (capi_profile *) data);
2180 break;
2181 case KCI_CONTRDOWN:
2182 printk(KERN_INFO "capidrv: controller %hu down\n", contr);
2183 (void) capidrv_delcontr(contr);
2184 break;
2185 }
2186}
2187
2188/*
2189 * /proc/capi/capidrv:
2190 * nrecvctlpkt nrecvdatapkt nsendctlpkt nsenddatapkt
2191 */
2192static int proc_capidrv_read_proc(char *page, char **start, off_t off,
2193 int count, int *eof, void *data)
2194{
2195 int len = 0;
2196
2197 len += sprintf(page+len, "%lu %lu %lu %lu\n",
2198 global.ap.nrecvctlpkt,
2199 global.ap.nrecvdatapkt,
2200 global.ap.nsentctlpkt,
2201 global.ap.nsentdatapkt);
2202 if (off+count >= len)
2203 *eof = 1;
2204 if (len < off)
2205 return 0;
2206 *start = page + off;
2207 return ((count < len-off) ? count : len-off);
2208}
2209
2210static struct procfsentries {
2211 char *name;
2212 mode_t mode;
2213 int (*read_proc)(char *page, char **start, off_t off,
2214 int count, int *eof, void *data);
2215 struct proc_dir_entry *procent;
2216} procfsentries[] = {
2217 /* { "capi", S_IFDIR, 0 }, */
2218 { "capi/capidrv", 0 , proc_capidrv_read_proc },
2219};
2220
2221static void __init proc_init(void)
2222{
2223 int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]);
2224 int i;
2225
2226 for (i=0; i < nelem; i++) {
2227 struct procfsentries *p = procfsentries + i;
2228 p->procent = create_proc_entry(p->name, p->mode, NULL);
2229 if (p->procent) p->procent->read_proc = p->read_proc;
2230 }
2231}
2232
2233static void __exit proc_exit(void)
2234{
2235 int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]);
2236 int i;
2237
2238 for (i=nelem-1; i >= 0; i--) {
2239 struct procfsentries *p = procfsentries + i;
2240 if (p->procent) {
2241 remove_proc_entry(p->name, NULL);
2242 p->procent = NULL;
2243 }
2244 }
2245}
2246
2247static int __init capidrv_init(void)
2248{
2249 capi_profile profile;
2250 char rev[32];
2251 char *p;
2252 u32 ncontr, contr;
2253 u16 errcode;
2254
2255 if ((p = strchr(revision, ':')) != 0 && p[1]) {
2256 strncpy(rev, p + 2, sizeof(rev));
2257 rev[sizeof(rev)-1] = 0;
2258 if ((p = strchr(rev, '$')) != 0 && p > rev)
2259 *(p-1) = 0;
2260 } else
2261 strcpy(rev, "1.0");
2262
2263 global.ap.rparam.level3cnt = -2; /* number of bchannels twice */
2264 global.ap.rparam.datablkcnt = 16;
2265 global.ap.rparam.datablklen = 2048;
2266
2267 global.ap.recv_message = capidrv_recv_message;
2268 errcode = capi20_register(&global.ap);
2269 if (errcode) {
2270 return -EIO;
2271 }
2272
2273 capi20_set_callback(&global.ap, lower_callback);
2274
2275 errcode = capi20_get_profile(0, &profile);
2276 if (errcode != CAPI_NOERROR) {
2277 capi20_release(&global.ap);
2278 return -EIO;
2279 }
2280
2281 ncontr = profile.ncontroller;
2282 for (contr = 1; contr <= ncontr; contr++) {
2283 errcode = capi20_get_profile(contr, &profile);
2284 if (errcode != CAPI_NOERROR)
2285 continue;
2286 (void) capidrv_addcontr(contr, &profile);
2287 }
2288 proc_init();
2289
2290 printk(KERN_NOTICE "capidrv: Rev %s: loaded\n", rev);
2291 return 0;
2292}
2293
2294static void __exit capidrv_exit(void)
2295{
2296 char rev[10];
2297 char *p;
2298
2299 if ((p = strchr(revision, ':')) != 0) {
2300 strcpy(rev, p + 1);
2301 p = strchr(rev, '$');
2302 *p = 0;
2303 } else {
2304 strcpy(rev, " ??? ");
2305 }
2306
2307 capi20_release(&global.ap);
2308
2309 proc_exit();
2310
2311 printk(KERN_NOTICE "capidrv: Rev%s: unloaded\n", rev);
2312}
2313
2314module_init(capidrv_init);
2315module_exit(capidrv_exit);
diff --git a/drivers/isdn/capi/capidrv.h b/drivers/isdn/capi/capidrv.h
new file mode 100644
index 000000000000..1e698e1e269f
--- /dev/null
+++ b/drivers/isdn/capi/capidrv.h
@@ -0,0 +1,140 @@
1/* $Id: capidrv.h,v 1.2.8.2 2001/09/23 22:24:33 kai Exp $
2 *
3 * ISDN4Linux Driver, using capi20 interface (kernelcapi)
4 *
5 * Copyright 1997 by Carsten Paeth <calle@calle.de>
6 *
7 * This software may be used and distributed according to the terms
8 * of the GNU General Public License, incorporated herein by reference.
9 *
10 */
11
12#ifndef __CAPIDRV_H__
13#define __CAPIDRV_H__
14
15/*
16 * LISTEN state machine
17 */
18#define ST_LISTEN_NONE 0 /* L-0 */
19#define ST_LISTEN_WAIT_CONF 1 /* L-0.1 */
20#define ST_LISTEN_ACTIVE 2 /* L-1 */
21#define ST_LISTEN_ACTIVE_WAIT_CONF 3 /* L-1.1 */
22
23
24#define EV_LISTEN_REQ 1 /* L-0 -> L-0.1
25 L-1 -> L-1.1 */
26#define EV_LISTEN_CONF_ERROR 2 /* L-0.1 -> L-0
27 L-1.1 -> L-1 */
28#define EV_LISTEN_CONF_EMPTY 3 /* L-0.1 -> L-0
29 L-1.1 -> L-0 */
30#define EV_LISTEN_CONF_OK 4 /* L-0.1 -> L-1
31 L-1.1 -> L.1 */
32
33/*
34 * per plci state machine
35 */
36#define ST_PLCI_NONE 0 /* P-0 */
37#define ST_PLCI_OUTGOING 1 /* P-0.1 */
38#define ST_PLCI_ALLOCATED 2 /* P-1 */
39#define ST_PLCI_ACTIVE 3 /* P-ACT */
40#define ST_PLCI_INCOMING 4 /* P-2 */
41#define ST_PLCI_FACILITY_IND 5 /* P-3 */
42#define ST_PLCI_ACCEPTING 6 /* P-4 */
43#define ST_PLCI_DISCONNECTING 7 /* P-5 */
44#define ST_PLCI_DISCONNECTED 8 /* P-6 */
45#define ST_PLCI_RESUMEING 9 /* P-0.Res */
46#define ST_PLCI_RESUME 10 /* P-Res */
47#define ST_PLCI_HELD 11 /* P-HELD */
48
49#define EV_PLCI_CONNECT_REQ 1 /* P-0 -> P-0.1
50 */
51#define EV_PLCI_CONNECT_CONF_ERROR 2 /* P-0.1 -> P-0
52 */
53#define EV_PLCI_CONNECT_CONF_OK 3 /* P-0.1 -> P-1
54 */
55#define EV_PLCI_FACILITY_IND_UP 4 /* P-0 -> P-1
56 */
57#define EV_PLCI_CONNECT_IND 5 /* P-0 -> P-2
58 */
59#define EV_PLCI_CONNECT_ACTIVE_IND 6 /* P-1 -> P-ACT
60 */
61#define EV_PLCI_CONNECT_REJECT 7 /* P-2 -> P-5
62 P-3 -> P-5
63 */
64#define EV_PLCI_DISCONNECT_REQ 8 /* P-1 -> P-5
65 P-2 -> P-5
66 P-3 -> P-5
67 P-4 -> P-5
68 P-ACT -> P-5
69 P-Res -> P-5 (*)
70 P-HELD -> P-5 (*)
71 */
72#define EV_PLCI_DISCONNECT_IND 9 /* P-1 -> P-6
73 P-2 -> P-6
74 P-3 -> P-6
75 P-4 -> P-6
76 P-5 -> P-6
77 P-ACT -> P-6
78 P-Res -> P-6 (*)
79 P-HELD -> P-6 (*)
80 */
81#define EV_PLCI_FACILITY_IND_DOWN 10 /* P-0.1 -> P-5
82 P-1 -> P-5
83 P-ACT -> P-5
84 P-2 -> P-5
85 P-3 -> P-5
86 P-4 -> P-5
87 */
88#define EV_PLCI_DISCONNECT_RESP 11 /* P-6 -> P-0
89 */
90#define EV_PLCI_CONNECT_RESP 12 /* P-6 -> P-0
91 */
92
93#define EV_PLCI_RESUME_REQ 13 /* P-0 -> P-0.Res
94 */
95#define EV_PLCI_RESUME_CONF_OK 14 /* P-0.Res -> P-Res
96 */
97#define EV_PLCI_RESUME_CONF_ERROR 15 /* P-0.Res -> P-0
98 */
99#define EV_PLCI_RESUME_IND 16 /* P-Res -> P-ACT
100 */
101#define EV_PLCI_HOLD_IND 17 /* P-ACT -> P-HELD
102 */
103#define EV_PLCI_RETRIEVE_IND 18 /* P-HELD -> P-ACT
104 */
105#define EV_PLCI_SUSPEND_IND 19 /* P-ACT -> P-5
106 */
107#define EV_PLCI_CD_IND 20 /* P-2 -> P-5
108 */
109
110/*
111 * per ncci state machine
112 */
113#define ST_NCCI_PREVIOUS -1
114#define ST_NCCI_NONE 0 /* N-0 */
115#define ST_NCCI_OUTGOING 1 /* N-0.1 */
116#define ST_NCCI_INCOMING 2 /* N-1 */
117#define ST_NCCI_ALLOCATED 3 /* N-2 */
118#define ST_NCCI_ACTIVE 4 /* N-ACT */
119#define ST_NCCI_RESETING 5 /* N-3 */
120#define ST_NCCI_DISCONNECTING 6 /* N-4 */
121#define ST_NCCI_DISCONNECTED 7 /* N-5 */
122
123#define EV_NCCI_CONNECT_B3_REQ 1 /* N-0 -> N-0.1 */
124#define EV_NCCI_CONNECT_B3_IND 2 /* N-0 -> N.1 */
125#define EV_NCCI_CONNECT_B3_CONF_OK 3 /* N-0.1 -> N.2 */
126#define EV_NCCI_CONNECT_B3_CONF_ERROR 4 /* N-0.1 -> N.0 */
127#define EV_NCCI_CONNECT_B3_REJECT 5 /* N-1 -> N-4 */
128#define EV_NCCI_CONNECT_B3_RESP 6 /* N-1 -> N-2 */
129#define EV_NCCI_CONNECT_B3_ACTIVE_IND 7 /* N-2 -> N-ACT */
130#define EV_NCCI_RESET_B3_REQ 8 /* N-ACT -> N-3 */
131#define EV_NCCI_RESET_B3_IND 9 /* N-3 -> N-ACT */
132#define EV_NCCI_DISCONNECT_B3_IND 10 /* N-4 -> N.5 */
133#define EV_NCCI_DISCONNECT_B3_CONF_ERROR 11 /* N-4 -> previous */
134#define EV_NCCI_DISCONNECT_B3_REQ 12 /* N-1 -> N-4
135 N-2 -> N-4
136 N-3 -> N-4
137 N-ACT -> N-4 */
138#define EV_NCCI_DISCONNECT_B3_RESP 13 /* N-5 -> N-0 */
139
140#endif /* __CAPIDRV_H__ */
diff --git a/drivers/isdn/capi/capifs.c b/drivers/isdn/capi/capifs.c
new file mode 100644
index 000000000000..f8570fd9d2ab
--- /dev/null
+++ b/drivers/isdn/capi/capifs.c
@@ -0,0 +1,212 @@
1/* $Id: capifs.c,v 1.1.2.3 2004/01/16 21:09:26 keil Exp $
2 *
3 * Copyright 2000 by Carsten Paeth <calle@calle.de>
4 *
5 * Heavily based on devpts filesystem from H. Peter Anvin
6 *
7 * This software may be used and distributed according to the terms
8 * of the GNU General Public License, incorporated herein by reference.
9 *
10 */
11
12#include <linux/fs.h>
13#include <linux/mount.h>
14#include <linux/namei.h>
15#include <linux/module.h>
16#include <linux/init.h>
17#include <linux/ctype.h>
18
19MODULE_DESCRIPTION("CAPI4Linux: /dev/capi/ filesystem");
20MODULE_AUTHOR("Carsten Paeth");
21MODULE_LICENSE("GPL");
22
23/* ------------------------------------------------------------------ */
24
25static char *revision = "$Revision: 1.1.2.3 $";
26
27/* ------------------------------------------------------------------ */
28
29#define CAPIFS_SUPER_MAGIC (('C'<<8)|'N')
30
31static struct vfsmount *capifs_mnt;
32static struct dentry *capifs_root;
33
34static struct {
35 int setuid;
36 int setgid;
37 uid_t uid;
38 gid_t gid;
39 umode_t mode;
40} config = {.mode = 0600};
41
42/* ------------------------------------------------------------------ */
43
44static int capifs_remount(struct super_block *s, int *flags, char *data)
45{
46 int setuid = 0;
47 int setgid = 0;
48 uid_t uid = 0;
49 gid_t gid = 0;
50 umode_t mode = 0600;
51 char *this_char;
52
53 this_char = NULL;
54 while ((this_char = strsep(&data, ",")) != NULL) {
55 int n;
56 char dummy;
57 if (!*this_char)
58 continue;
59 if (sscanf(this_char, "uid=%i%c", &n, &dummy) == 1) {
60 setuid = 1;
61 uid = n;
62 } else if (sscanf(this_char, "gid=%i%c", &n, &dummy) == 1) {
63 setgid = 1;
64 gid = n;
65 } else if (sscanf(this_char, "mode=%o%c", &n, &dummy) == 1)
66 mode = n & ~S_IFMT;
67 else {
68 printk("capifs: called with bogus options\n");
69 return -EINVAL;
70 }
71 }
72 config.setuid = setuid;
73 config.setgid = setgid;
74 config.uid = uid;
75 config.gid = gid;
76 config.mode = mode;
77 return 0;
78}
79
80static struct super_operations capifs_sops =
81{
82 .statfs = simple_statfs,
83 .remount_fs = capifs_remount,
84};
85
86
87static int
88capifs_fill_super(struct super_block *s, void *data, int silent)
89{
90 struct inode * inode;
91
92 s->s_blocksize = 1024;
93 s->s_blocksize_bits = 10;
94 s->s_magic = CAPIFS_SUPER_MAGIC;
95 s->s_op = &capifs_sops;
96 s->s_time_gran = 1;
97
98 inode = new_inode(s);
99 if (!inode)
100 goto fail;
101 inode->i_ino = 1;
102 inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
103 inode->i_blocks = 0;
104 inode->i_blksize = 1024;
105 inode->i_uid = inode->i_gid = 0;
106 inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR;
107 inode->i_op = &simple_dir_inode_operations;
108 inode->i_fop = &simple_dir_operations;
109 inode->i_nlink = 2;
110
111 capifs_root = s->s_root = d_alloc_root(inode);
112 if (s->s_root)
113 return 0;
114
115 printk("capifs: get root dentry failed\n");
116 iput(inode);
117fail:
118 return -ENOMEM;
119}
120
121static struct super_block *capifs_get_sb(struct file_system_type *fs_type,
122 int flags, const char *dev_name, void *data)
123{
124 return get_sb_single(fs_type, flags, data, capifs_fill_super);
125}
126
127static struct file_system_type capifs_fs_type = {
128 .owner = THIS_MODULE,
129 .name = "capifs",
130 .get_sb = capifs_get_sb,
131 .kill_sb = kill_anon_super,
132};
133
134static struct dentry *get_node(int num)
135{
136 char s[10];
137 struct dentry *root = capifs_root;
138 down(&root->d_inode->i_sem);
139 return lookup_one_len(s, root, sprintf(s, "%d", num));
140}
141
142void capifs_new_ncci(unsigned int number, dev_t device)
143{
144 struct dentry *dentry;
145 struct inode *inode = new_inode(capifs_mnt->mnt_sb);
146 if (!inode)
147 return;
148 inode->i_ino = number+2;
149 inode->i_blksize = 1024;
150 inode->i_uid = config.setuid ? config.uid : current->fsuid;
151 inode->i_gid = config.setgid ? config.gid : current->fsgid;
152 inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
153 init_special_inode(inode, S_IFCHR|config.mode, device);
154 //inode->i_op = &capifs_file_inode_operations;
155
156 dentry = get_node(number);
157 if (!IS_ERR(dentry) && !dentry->d_inode)
158 d_instantiate(dentry, inode);
159 up(&capifs_root->d_inode->i_sem);
160}
161
162void capifs_free_ncci(unsigned int number)
163{
164 struct dentry *dentry = get_node(number);
165
166 if (!IS_ERR(dentry)) {
167 struct inode *inode = dentry->d_inode;
168 if (inode) {
169 inode->i_nlink--;
170 d_delete(dentry);
171 dput(dentry);
172 }
173 dput(dentry);
174 }
175 up(&capifs_root->d_inode->i_sem);
176}
177
178static int __init capifs_init(void)
179{
180 char rev[32];
181 char *p;
182 int err;
183
184 if ((p = strchr(revision, ':')) != 0 && p[1]) {
185 strlcpy(rev, p + 2, sizeof(rev));
186 if ((p = strchr(rev, '$')) != 0 && p > rev)
187 *(p-1) = 0;
188 } else
189 strcpy(rev, "1.0");
190
191 err = register_filesystem(&capifs_fs_type);
192 if (!err) {
193 capifs_mnt = kern_mount(&capifs_fs_type);
194 if (IS_ERR(capifs_mnt))
195 err = PTR_ERR(capifs_mnt);
196 }
197 if (!err)
198 printk(KERN_NOTICE "capifs: Rev %s\n", rev);
199 return err;
200}
201
202static void __exit capifs_exit(void)
203{
204 unregister_filesystem(&capifs_fs_type);
205 mntput(capifs_mnt);
206}
207
208EXPORT_SYMBOL(capifs_new_ncci);
209EXPORT_SYMBOL(capifs_free_ncci);
210
211module_init(capifs_init);
212module_exit(capifs_exit);
diff --git a/drivers/isdn/capi/capifs.h b/drivers/isdn/capi/capifs.h
new file mode 100644
index 000000000000..d0bd4c3c430a
--- /dev/null
+++ b/drivers/isdn/capi/capifs.h
@@ -0,0 +1,11 @@
1/* $Id: capifs.h,v 1.1.2.2 2004/01/16 21:09:26 keil Exp $
2 *
3 * Copyright 2000 by Carsten Paeth <calle@calle.de>
4 *
5 * This software may be used and distributed according to the terms
6 * of the GNU General Public License, incorporated herein by reference.
7 *
8 */
9
10void capifs_new_ncci(unsigned int num, dev_t device);
11void capifs_free_ncci(unsigned int num);
diff --git a/drivers/isdn/capi/capilib.c b/drivers/isdn/capi/capilib.c
new file mode 100644
index 000000000000..68409d971e73
--- /dev/null
+++ b/drivers/isdn/capi/capilib.c
@@ -0,0 +1,200 @@
1
2#include <linux/kernel.h>
3#include <linux/module.h>
4#include <linux/isdn/capilli.h>
5
6#define DBG(format, arg...) do { \
7printk(KERN_DEBUG "%s: " format "\n" , __FUNCTION__ , ## arg); \
8} while (0)
9
10struct capilib_msgidqueue {
11 struct capilib_msgidqueue *next;
12 u16 msgid;
13};
14
15struct capilib_ncci {
16 struct list_head list;
17 u16 applid;
18 u32 ncci;
19 u32 winsize;
20 int nmsg;
21 struct capilib_msgidqueue *msgidqueue;
22 struct capilib_msgidqueue *msgidlast;
23 struct capilib_msgidqueue *msgidfree;
24 struct capilib_msgidqueue msgidpool[CAPI_MAXDATAWINDOW];
25};
26
27// ---------------------------------------------------------------------------
28// NCCI Handling
29
30static inline void mq_init(struct capilib_ncci * np)
31{
32 u_int i;
33 np->msgidqueue = NULL;
34 np->msgidlast = NULL;
35 np->nmsg = 0;
36 memset(np->msgidpool, 0, sizeof(np->msgidpool));
37 np->msgidfree = &np->msgidpool[0];
38 for (i = 1; i < np->winsize; i++) {
39 np->msgidpool[i].next = np->msgidfree;
40 np->msgidfree = &np->msgidpool[i];
41 }
42}
43
44static inline int mq_enqueue(struct capilib_ncci * np, u16 msgid)
45{
46 struct capilib_msgidqueue *mq;
47 if ((mq = np->msgidfree) == 0)
48 return 0;
49 np->msgidfree = mq->next;
50 mq->msgid = msgid;
51 mq->next = NULL;
52 if (np->msgidlast)
53 np->msgidlast->next = mq;
54 np->msgidlast = mq;
55 if (!np->msgidqueue)
56 np->msgidqueue = mq;
57 np->nmsg++;
58 return 1;
59}
60
61static inline int mq_dequeue(struct capilib_ncci * np, u16 msgid)
62{
63 struct capilib_msgidqueue **pp;
64 for (pp = &np->msgidqueue; *pp; pp = &(*pp)->next) {
65 if ((*pp)->msgid == msgid) {
66 struct capilib_msgidqueue *mq = *pp;
67 *pp = mq->next;
68 if (mq == np->msgidlast)
69 np->msgidlast = NULL;
70 mq->next = np->msgidfree;
71 np->msgidfree = mq;
72 np->nmsg--;
73 return 1;
74 }
75 }
76 return 0;
77}
78
79void capilib_new_ncci(struct list_head *head, u16 applid, u32 ncci, u32 winsize)
80{
81 struct capilib_ncci *np;
82
83 np = kmalloc(sizeof(*np), GFP_ATOMIC);
84 if (!np) {
85 printk(KERN_WARNING "capilib_new_ncci: no memory.\n");
86 return;
87 }
88 if (winsize > CAPI_MAXDATAWINDOW) {
89 printk(KERN_ERR "capi_new_ncci: winsize %d too big\n",
90 winsize);
91 winsize = CAPI_MAXDATAWINDOW;
92 }
93 np->applid = applid;
94 np->ncci = ncci;
95 np->winsize = winsize;
96 mq_init(np);
97 list_add_tail(&np->list, head);
98 DBG("kcapi: appl %d ncci 0x%x up", applid, ncci);
99}
100
101EXPORT_SYMBOL(capilib_new_ncci);
102
103void capilib_free_ncci(struct list_head *head, u16 applid, u32 ncci)
104{
105 struct list_head *l;
106 struct capilib_ncci *np;
107
108 list_for_each(l, head) {
109 np = list_entry(l, struct capilib_ncci, list);
110 if (np->applid != applid)
111 continue;
112 if (np->ncci != ncci)
113 continue;
114 printk(KERN_INFO "kcapi: appl %d ncci 0x%x down\n", applid, ncci);
115 list_del(&np->list);
116 kfree(np);
117 return;
118 }
119 printk(KERN_ERR "capilib_free_ncci: ncci 0x%x not found\n", ncci);
120}
121
122EXPORT_SYMBOL(capilib_free_ncci);
123
124void capilib_release_appl(struct list_head *head, u16 applid)
125{
126 struct list_head *l, *n;
127 struct capilib_ncci *np;
128
129 list_for_each_safe(l, n, head) {
130 np = list_entry(l, struct capilib_ncci, list);
131 if (np->applid != applid)
132 continue;
133 printk(KERN_INFO "kcapi: appl %d ncci 0x%x forced down\n", applid, np->ncci);
134 list_del(&np->list);
135 kfree(np);
136 }
137}
138
139EXPORT_SYMBOL(capilib_release_appl);
140
141void capilib_release(struct list_head *head)
142{
143 struct list_head *l, *n;
144 struct capilib_ncci *np;
145
146 list_for_each_safe(l, n, head) {
147 np = list_entry(l, struct capilib_ncci, list);
148 printk(KERN_INFO "kcapi: appl %d ncci 0x%x forced down\n", np->applid, np->ncci);
149 list_del(&np->list);
150 kfree(np);
151 }
152}
153
154EXPORT_SYMBOL(capilib_release);
155
156u16 capilib_data_b3_req(struct list_head *head, u16 applid, u32 ncci, u16 msgid)
157{
158 struct list_head *l;
159 struct capilib_ncci *np;
160
161 list_for_each(l, head) {
162 np = list_entry(l, struct capilib_ncci, list);
163 if (np->applid != applid)
164 continue;
165 if (np->ncci != ncci)
166 continue;
167
168 if (mq_enqueue(np, msgid) == 0)
169 return CAPI_SENDQUEUEFULL;
170
171 return CAPI_NOERROR;
172 }
173 printk(KERN_ERR "capilib_data_b3_req: ncci 0x%x not found\n", ncci);
174 return CAPI_NOERROR;
175}
176
177EXPORT_SYMBOL(capilib_data_b3_req);
178
179void capilib_data_b3_conf(struct list_head *head, u16 applid, u32 ncci, u16 msgid)
180{
181 struct list_head *l;
182 struct capilib_ncci *np;
183
184 list_for_each(l, head) {
185 np = list_entry(l, struct capilib_ncci, list);
186 if (np->applid != applid)
187 continue;
188 if (np->ncci != ncci)
189 continue;
190
191 if (mq_dequeue(np, msgid) == 0) {
192 printk(KERN_ERR "kcapi: msgid %hu ncci 0x%x not on queue\n",
193 msgid, ncci);
194 }
195 return;
196 }
197 printk(KERN_ERR "capilib_data_b3_conf: ncci 0x%x not found\n", ncci);
198}
199
200EXPORT_SYMBOL(capilib_data_b3_conf);
diff --git a/drivers/isdn/capi/capiutil.c b/drivers/isdn/capi/capiutil.c
new file mode 100644
index 000000000000..e7cf6bc286a6
--- /dev/null
+++ b/drivers/isdn/capi/capiutil.c
@@ -0,0 +1,859 @@
1/* $Id: capiutil.c,v 1.13.6.4 2001/09/23 22:24:33 kai Exp $
2 *
3 * CAPI 2.0 convert capi message to capi message struct
4 *
5 * From CAPI 2.0 Development Kit AVM 1995 (msg.c)
6 * Rewritten for Linux 1996 by Carsten Paeth <calle@calle.de>
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 */
12
13#include <linux/module.h>
14#include <linux/string.h>
15#include <linux/ctype.h>
16#include <linux/stddef.h>
17#include <linux/kernel.h>
18#include <linux/mm.h>
19#include <linux/init.h>
20#include <linux/config.h>
21#include <linux/isdn/capiutil.h>
22
23/* from CAPI2.0 DDK AVM Berlin GmbH */
24
25#ifndef CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON
26char *capi_info2str(u16 reason)
27{
28 return "..";
29}
30#else
31char *capi_info2str(u16 reason)
32{
33 switch (reason) {
34
35/*-- informative values (corresponding message was processed) -----*/
36 case 0x0001:
37 return "NCPI not supported by current protocol, NCPI ignored";
38 case 0x0002:
39 return "Flags not supported by current protocol, flags ignored";
40 case 0x0003:
41 return "Alert already sent by another application";
42
43/*-- error information concerning CAPI_REGISTER -----*/
44 case 0x1001:
45 return "Too many applications";
46 case 0x1002:
47 return "Logical block size too small, must be at least 128 Bytes";
48 case 0x1003:
49 return "Buffer exceeds 64 kByte";
50 case 0x1004:
51 return "Message buffer size too small, must be at least 1024 Bytes";
52 case 0x1005:
53 return "Max. number of logical connections not supported";
54 case 0x1006:
55 return "Reserved";
56 case 0x1007:
57 return "The message could not be accepted because of an internal busy condition";
58 case 0x1008:
59 return "OS resource error (no memory ?)";
60 case 0x1009:
61 return "CAPI not installed";
62 case 0x100A:
63 return "Controller does not support external equipment";
64 case 0x100B:
65 return "Controller does only support external equipment";
66
67/*-- error information concerning message exchange functions -----*/
68 case 0x1101:
69 return "Illegal application number";
70 case 0x1102:
71 return "Illegal command or subcommand or message length less than 12 bytes";
72 case 0x1103:
73 return "The message could not be accepted because of a queue full condition !! The error code does not imply that CAPI cannot receive messages directed to another controller, PLCI or NCCI";
74 case 0x1104:
75 return "Queue is empty";
76 case 0x1105:
77 return "Queue overflow, a message was lost !! This indicates a configuration error. The only recovery from this error is to perform a CAPI_RELEASE";
78 case 0x1106:
79 return "Unknown notification parameter";
80 case 0x1107:
81 return "The Message could not be accepted because of an internal busy condition";
82 case 0x1108:
83 return "OS Resource error (no memory ?)";
84 case 0x1109:
85 return "CAPI not installed";
86 case 0x110A:
87 return "Controller does not support external equipment";
88 case 0x110B:
89 return "Controller does only support external equipment";
90
91/*-- error information concerning resource / coding problems -----*/
92 case 0x2001:
93 return "Message not supported in current state";
94 case 0x2002:
95 return "Illegal Controller / PLCI / NCCI";
96 case 0x2003:
97 return "Out of PLCI";
98 case 0x2004:
99 return "Out of NCCI";
100 case 0x2005:
101 return "Out of LISTEN";
102 case 0x2006:
103 return "Out of FAX resources (protocol T.30)";
104 case 0x2007:
105 return "Illegal message parameter coding";
106
107/*-- error information concerning requested services -----*/
108 case 0x3001:
109 return "B1 protocol not supported";
110 case 0x3002:
111 return "B2 protocol not supported";
112 case 0x3003:
113 return "B3 protocol not supported";
114 case 0x3004:
115 return "B1 protocol parameter not supported";
116 case 0x3005:
117 return "B2 protocol parameter not supported";
118 case 0x3006:
119 return "B3 protocol parameter not supported";
120 case 0x3007:
121 return "B protocol combination not supported";
122 case 0x3008:
123 return "NCPI not supported";
124 case 0x3009:
125 return "CIP Value unknown";
126 case 0x300A:
127 return "Flags not supported (reserved bits)";
128 case 0x300B:
129 return "Facility not supported";
130 case 0x300C:
131 return "Data length not supported by current protocol";
132 case 0x300D:
133 return "Reset procedure not supported by current protocol";
134
135/*-- informations about the clearing of a physical connection -----*/
136 case 0x3301:
137 return "Protocol error layer 1 (broken line or B-channel removed by signalling protocol)";
138 case 0x3302:
139 return "Protocol error layer 2";
140 case 0x3303:
141 return "Protocol error layer 3";
142 case 0x3304:
143 return "Another application got that call";
144/*-- T.30 specific reasons -----*/
145 case 0x3311:
146 return "Connecting not successful (remote station is no FAX G3 machine)";
147 case 0x3312:
148 return "Connecting not successful (training error)";
149 case 0x3313:
150 return "Disconnected before transfer (remote station does not support transfer mode, e.g. resolution)";
151 case 0x3314:
152 return "Disconnected during transfer (remote abort)";
153 case 0x3315:
154 return "Disconnected during transfer (remote procedure error, e.g. unsuccessful repetition of T.30 commands)";
155 case 0x3316:
156 return "Disconnected during transfer (local tx data underrun)";
157 case 0x3317:
158 return "Disconnected during transfer (local rx data overflow)";
159 case 0x3318:
160 return "Disconnected during transfer (local abort)";
161 case 0x3319:
162 return "Illegal parameter coding (e.g. SFF coding error)";
163
164/*-- disconnect causes from the network according to ETS 300 102-1/Q.931 -----*/
165 case 0x3481: return "Unallocated (unassigned) number";
166 case 0x3482: return "No route to specified transit network";
167 case 0x3483: return "No route to destination";
168 case 0x3486: return "Channel unacceptable";
169 case 0x3487:
170 return "Call awarded and being delivered in an established channel";
171 case 0x3490: return "Normal call clearing";
172 case 0x3491: return "User busy";
173 case 0x3492: return "No user responding";
174 case 0x3493: return "No answer from user (user alerted)";
175 case 0x3495: return "Call rejected";
176 case 0x3496: return "Number changed";
177 case 0x349A: return "Non-selected user clearing";
178 case 0x349B: return "Destination out of order";
179 case 0x349C: return "Invalid number format";
180 case 0x349D: return "Facility rejected";
181 case 0x349E: return "Response to STATUS ENQUIRY";
182 case 0x349F: return "Normal, unspecified";
183 case 0x34A2: return "No circuit / channel available";
184 case 0x34A6: return "Network out of order";
185 case 0x34A9: return "Temporary failure";
186 case 0x34AA: return "Switching equipment congestion";
187 case 0x34AB: return "Access information discarded";
188 case 0x34AC: return "Requested circuit / channel not available";
189 case 0x34AF: return "Resources unavailable, unspecified";
190 case 0x34B1: return "Quality of service unavailable";
191 case 0x34B2: return "Requested facility not subscribed";
192 case 0x34B9: return "Bearer capability not authorized";
193 case 0x34BA: return "Bearer capability not presently available";
194 case 0x34BF: return "Service or option not available, unspecified";
195 case 0x34C1: return "Bearer capability not implemented";
196 case 0x34C2: return "Channel type not implemented";
197 case 0x34C5: return "Requested facility not implemented";
198 case 0x34C6: return "Only restricted digital information bearer capability is available";
199 case 0x34CF: return "Service or option not implemented, unspecified";
200 case 0x34D1: return "Invalid call reference value";
201 case 0x34D2: return "Identified channel does not exist";
202 case 0x34D3: return "A suspended call exists, but this call identity does not";
203 case 0x34D4: return "Call identity in use";
204 case 0x34D5: return "No call suspended";
205 case 0x34D6: return "Call having the requested call identity has been cleared";
206 case 0x34D8: return "Incompatible destination";
207 case 0x34DB: return "Invalid transit network selection";
208 case 0x34DF: return "Invalid message, unspecified";
209 case 0x34E0: return "Mandatory information element is missing";
210 case 0x34E1: return "Message type non-existent or not implemented";
211 case 0x34E2: return "Message not compatible with call state or message type non-existent or not implemented";
212 case 0x34E3: return "Information element non-existent or not implemented";
213 case 0x34E4: return "Invalid information element contents";
214 case 0x34E5: return "Message not compatible with call state";
215 case 0x34E6: return "Recovery on timer expiry";
216 case 0x34EF: return "Protocol error, unspecified";
217 case 0x34FF: return "Interworking, unspecified";
218
219 default: return "No additional information";
220 }
221}
222#endif
223
224typedef struct {
225 int typ;
226 size_t off;
227} _cdef;
228
229#define _CBYTE 1
230#define _CWORD 2
231#define _CDWORD 3
232#define _CSTRUCT 4
233#define _CMSTRUCT 5
234#define _CEND 6
235
236static _cdef cdef[] =
237{
238 /*00 */
239 {_CEND},
240 /*01 */
241 {_CEND},
242 /*02 */
243 {_CEND},
244 /*03 */
245 {_CDWORD, offsetof(_cmsg, adr.adrController)},
246 /*04 */
247 {_CMSTRUCT, offsetof(_cmsg, AdditionalInfo)},
248 /*05 */
249 {_CSTRUCT, offsetof(_cmsg, B1configuration)},
250 /*06 */
251 {_CWORD, offsetof(_cmsg, B1protocol)},
252 /*07 */
253 {_CSTRUCT, offsetof(_cmsg, B2configuration)},
254 /*08 */
255 {_CWORD, offsetof(_cmsg, B2protocol)},
256 /*09 */
257 {_CSTRUCT, offsetof(_cmsg, B3configuration)},
258 /*0a */
259 {_CWORD, offsetof(_cmsg, B3protocol)},
260 /*0b */
261 {_CSTRUCT, offsetof(_cmsg, BC)},
262 /*0c */
263 {_CSTRUCT, offsetof(_cmsg, BChannelinformation)},
264 /*0d */
265 {_CMSTRUCT, offsetof(_cmsg, BProtocol)},
266 /*0e */
267 {_CSTRUCT, offsetof(_cmsg, CalledPartyNumber)},
268 /*0f */
269 {_CSTRUCT, offsetof(_cmsg, CalledPartySubaddress)},
270 /*10 */
271 {_CSTRUCT, offsetof(_cmsg, CallingPartyNumber)},
272 /*11 */
273 {_CSTRUCT, offsetof(_cmsg, CallingPartySubaddress)},
274 /*12 */
275 {_CDWORD, offsetof(_cmsg, CIPmask)},
276 /*13 */
277 {_CDWORD, offsetof(_cmsg, CIPmask2)},
278 /*14 */
279 {_CWORD, offsetof(_cmsg, CIPValue)},
280 /*15 */
281 {_CDWORD, offsetof(_cmsg, Class)},
282 /*16 */
283 {_CSTRUCT, offsetof(_cmsg, ConnectedNumber)},
284 /*17 */
285 {_CSTRUCT, offsetof(_cmsg, ConnectedSubaddress)},
286 /*18 */
287 {_CDWORD, offsetof(_cmsg, Data)},
288 /*19 */
289 {_CWORD, offsetof(_cmsg, DataHandle)},
290 /*1a */
291 {_CWORD, offsetof(_cmsg, DataLength)},
292 /*1b */
293 {_CSTRUCT, offsetof(_cmsg, FacilityConfirmationParameter)},
294 /*1c */
295 {_CSTRUCT, offsetof(_cmsg, Facilitydataarray)},
296 /*1d */
297 {_CSTRUCT, offsetof(_cmsg, FacilityIndicationParameter)},
298 /*1e */
299 {_CSTRUCT, offsetof(_cmsg, FacilityRequestParameter)},
300 /*1f */
301 {_CWORD, offsetof(_cmsg, FacilitySelector)},
302 /*20 */
303 {_CWORD, offsetof(_cmsg, Flags)},
304 /*21 */
305 {_CDWORD, offsetof(_cmsg, Function)},
306 /*22 */
307 {_CSTRUCT, offsetof(_cmsg, HLC)},
308 /*23 */
309 {_CWORD, offsetof(_cmsg, Info)},
310 /*24 */
311 {_CSTRUCT, offsetof(_cmsg, InfoElement)},
312 /*25 */
313 {_CDWORD, offsetof(_cmsg, InfoMask)},
314 /*26 */
315 {_CWORD, offsetof(_cmsg, InfoNumber)},
316 /*27 */
317 {_CSTRUCT, offsetof(_cmsg, Keypadfacility)},
318 /*28 */
319 {_CSTRUCT, offsetof(_cmsg, LLC)},
320 /*29 */
321 {_CSTRUCT, offsetof(_cmsg, ManuData)},
322 /*2a */
323 {_CDWORD, offsetof(_cmsg, ManuID)},
324 /*2b */
325 {_CSTRUCT, offsetof(_cmsg, NCPI)},
326 /*2c */
327 {_CWORD, offsetof(_cmsg, Reason)},
328 /*2d */
329 {_CWORD, offsetof(_cmsg, Reason_B3)},
330 /*2e */
331 {_CWORD, offsetof(_cmsg, Reject)},
332 /*2f */
333 {_CSTRUCT, offsetof(_cmsg, Useruserdata)}
334};
335
336static unsigned char *cpars[] =
337{
338 /* ALERT_REQ */ [0x01] = "\x03\x04\x0c\x27\x2f\x1c\x01\x01",
339 /* CONNECT_REQ */ [0x02] = "\x03\x14\x0e\x10\x0f\x11\x0d\x06\x08\x0a\x05\x07\x09\x01\x0b\x28\x22\x04\x0c\x27\x2f\x1c\x01\x01",
340 /* DISCONNECT_REQ */ [0x04] = "\x03\x04\x0c\x27\x2f\x1c\x01\x01",
341 /* LISTEN_REQ */ [0x05] = "\x03\x25\x12\x13\x10\x11\x01",
342 /* INFO_REQ */ [0x08] = "\x03\x0e\x04\x0c\x27\x2f\x1c\x01\x01",
343 /* FACILITY_REQ */ [0x09] = "\x03\x1f\x1e\x01",
344 /* SELECT_B_PROTOCOL_REQ */ [0x0a] = "\x03\x0d\x06\x08\x0a\x05\x07\x09\x01\x01",
345 /* CONNECT_B3_REQ */ [0x0b] = "\x03\x2b\x01",
346 /* DISCONNECT_B3_REQ */ [0x0d] = "\x03\x2b\x01",
347 /* DATA_B3_REQ */ [0x0f] = "\x03\x18\x1a\x19\x20\x01",
348 /* RESET_B3_REQ */ [0x10] = "\x03\x2b\x01",
349 /* ALERT_CONF */ [0x13] = "\x03\x23\x01",
350 /* CONNECT_CONF */ [0x14] = "\x03\x23\x01",
351 /* DISCONNECT_CONF */ [0x16] = "\x03\x23\x01",
352 /* LISTEN_CONF */ [0x17] = "\x03\x23\x01",
353 /* MANUFACTURER_REQ */ [0x18] = "\x03\x2a\x15\x21\x29\x01",
354 /* INFO_CONF */ [0x1a] = "\x03\x23\x01",
355 /* FACILITY_CONF */ [0x1b] = "\x03\x23\x1f\x1b\x01",
356 /* SELECT_B_PROTOCOL_CONF */ [0x1c] = "\x03\x23\x01",
357 /* CONNECT_B3_CONF */ [0x1d] = "\x03\x23\x01",
358 /* DISCONNECT_B3_CONF */ [0x1f] = "\x03\x23\x01",
359 /* DATA_B3_CONF */ [0x21] = "\x03\x19\x23\x01",
360 /* RESET_B3_CONF */ [0x22] = "\x03\x23\x01",
361 /* CONNECT_IND */ [0x26] = "\x03\x14\x0e\x10\x0f\x11\x0b\x28\x22\x04\x0c\x27\x2f\x1c\x01\x01",
362 /* CONNECT_ACTIVE_IND */ [0x27] = "\x03\x16\x17\x28\x01",
363 /* DISCONNECT_IND */ [0x28] = "\x03\x2c\x01",
364 /* MANUFACTURER_CONF */ [0x2a] = "\x03\x2a\x15\x21\x29\x01",
365 /* INFO_IND */ [0x2c] = "\x03\x26\x24\x01",
366 /* FACILITY_IND */ [0x2d] = "\x03\x1f\x1d\x01",
367 /* CONNECT_B3_IND */ [0x2f] = "\x03\x2b\x01",
368 /* CONNECT_B3_ACTIVE_IND */ [0x30] = "\x03\x2b\x01",
369 /* DISCONNECT_B3_IND */ [0x31] = "\x03\x2d\x2b\x01",
370 /* DATA_B3_IND */ [0x33] = "\x03\x18\x1a\x19\x20\x01",
371 /* RESET_B3_IND */ [0x34] = "\x03\x2b\x01",
372 /* CONNECT_B3_T90_ACTIVE_IND */ [0x35] = "\x03\x2b\x01",
373 /* CONNECT_RESP */ [0x38] = "\x03\x2e\x0d\x06\x08\x0a\x05\x07\x09\x01\x16\x17\x28\x04\x0c\x27\x2f\x1c\x01\x01",
374 /* CONNECT_ACTIVE_RESP */ [0x39] = "\x03\x01",
375 /* DISCONNECT_RESP */ [0x3a] = "\x03\x01",
376 /* MANUFACTURER_IND */ [0x3c] = "\x03\x2a\x15\x21\x29\x01",
377 /* INFO_RESP */ [0x3e] = "\x03\x01",
378 /* FACILITY_RESP */ [0x3f] = "\x03\x1f\x01",
379 /* CONNECT_B3_RESP */ [0x41] = "\x03\x2e\x2b\x01",
380 /* CONNECT_B3_ACTIVE_RESP */ [0x42] = "\x03\x01",
381 /* DISCONNECT_B3_RESP */ [0x43] = "\x03\x01",
382 /* DATA_B3_RESP */ [0x45] = "\x03\x19\x01",
383 /* RESET_B3_RESP */ [0x46] = "\x03\x01",
384 /* CONNECT_B3_T90_ACTIVE_RESP */ [0x47] = "\x03\x01",
385 /* MANUFACTURER_RESP */ [0x4e] = "\x03\x2a\x15\x21\x29\x01",
386};
387
388/*-------------------------------------------------------*/
389
390#define byteTLcpy(x,y) *(u8 *)(x)=*(u8 *)(y);
391#define wordTLcpy(x,y) *(u16 *)(x)=*(u16 *)(y);
392#define dwordTLcpy(x,y) memcpy(x,y,4);
393#define structTLcpy(x,y,l) memcpy (x,y,l)
394#define structTLcpyovl(x,y,l) memmove (x,y,l)
395
396#define byteTRcpy(x,y) *(u8 *)(y)=*(u8 *)(x);
397#define wordTRcpy(x,y) *(u16 *)(y)=*(u16 *)(x);
398#define dwordTRcpy(x,y) memcpy(y,x,4);
399#define structTRcpy(x,y,l) memcpy (y,x,l)
400#define structTRcpyovl(x,y,l) memmove (y,x,l)
401
402/*-------------------------------------------------------*/
403static unsigned command_2_index(unsigned c, unsigned sc)
404{
405 if (c & 0x80)
406 c = 0x9 + (c & 0x0f);
407 else if (c <= 0x0f);
408 else if (c == 0x41)
409 c = 0x9 + 0x1;
410 else if (c == 0xff)
411 c = 0x00;
412 return (sc & 3) * (0x9 + 0x9) + c;
413}
414
415/*-------------------------------------------------------*/
416#define TYP (cdef[cmsg->par[cmsg->p]].typ)
417#define OFF (((u8 *)cmsg)+cdef[cmsg->par[cmsg->p]].off)
418
419static void jumpcstruct(_cmsg * cmsg)
420{
421 unsigned layer;
422 for (cmsg->p++, layer = 1; layer;) {
423 /* $$$$$ assert (cmsg->p); */
424 cmsg->p++;
425 switch (TYP) {
426 case _CMSTRUCT:
427 layer++;
428 break;
429 case _CEND:
430 layer--;
431 break;
432 }
433 }
434}
435/*-------------------------------------------------------*/
436static void pars_2_message(_cmsg * cmsg)
437{
438
439 for (; TYP != _CEND; cmsg->p++) {
440 switch (TYP) {
441 case _CBYTE:
442 byteTLcpy(cmsg->m + cmsg->l, OFF);
443 cmsg->l++;
444 break;
445 case _CWORD:
446 wordTLcpy(cmsg->m + cmsg->l, OFF);
447 cmsg->l += 2;
448 break;
449 case _CDWORD:
450 dwordTLcpy(cmsg->m + cmsg->l, OFF);
451 cmsg->l += 4;
452 break;
453 case _CSTRUCT:
454 if (*(u8 **) OFF == 0) {
455 *(cmsg->m + cmsg->l) = '\0';
456 cmsg->l++;
457 } else if (**(_cstruct *) OFF != 0xff) {
458 structTLcpy(cmsg->m + cmsg->l, *(_cstruct *) OFF, 1 + **(_cstruct *) OFF);
459 cmsg->l += 1 + **(_cstruct *) OFF;
460 } else {
461 _cstruct s = *(_cstruct *) OFF;
462 structTLcpy(cmsg->m + cmsg->l, s, 3 + *(u16 *) (s + 1));
463 cmsg->l += 3 + *(u16 *) (s + 1);
464 }
465 break;
466 case _CMSTRUCT:
467/*----- Metastruktur 0 -----*/
468 if (*(_cmstruct *) OFF == CAPI_DEFAULT) {
469 *(cmsg->m + cmsg->l) = '\0';
470 cmsg->l++;
471 jumpcstruct(cmsg);
472 }
473/*----- Metastruktur wird composed -----*/
474 else {
475 unsigned _l = cmsg->l;
476 unsigned _ls;
477 cmsg->l++;
478 cmsg->p++;
479 pars_2_message(cmsg);
480 _ls = cmsg->l - _l - 1;
481 if (_ls < 255)
482 (cmsg->m + _l)[0] = (u8) _ls;
483 else {
484 structTLcpyovl(cmsg->m + _l + 3, cmsg->m + _l + 1, _ls);
485 (cmsg->m + _l)[0] = 0xff;
486 wordTLcpy(cmsg->m + _l + 1, &_ls);
487 }
488 }
489 break;
490 }
491 }
492}
493
494/*-------------------------------------------------------*/
495unsigned capi_cmsg2message(_cmsg * cmsg, u8 * msg)
496{
497 cmsg->m = msg;
498 cmsg->l = 8;
499 cmsg->p = 0;
500 cmsg->par = cpars[command_2_index(cmsg->Command, cmsg->Subcommand)];
501
502 pars_2_message(cmsg);
503
504 wordTLcpy(msg + 0, &cmsg->l);
505 byteTLcpy(cmsg->m + 4, &cmsg->Command);
506 byteTLcpy(cmsg->m + 5, &cmsg->Subcommand);
507 wordTLcpy(cmsg->m + 2, &cmsg->ApplId);
508 wordTLcpy(cmsg->m + 6, &cmsg->Messagenumber);
509
510 return 0;
511}
512
513/*-------------------------------------------------------*/
514static void message_2_pars(_cmsg * cmsg)
515{
516 for (; TYP != _CEND; cmsg->p++) {
517
518 switch (TYP) {
519 case _CBYTE:
520 byteTRcpy(cmsg->m + cmsg->l, OFF);
521 cmsg->l++;
522 break;
523 case _CWORD:
524 wordTRcpy(cmsg->m + cmsg->l, OFF);
525 cmsg->l += 2;
526 break;
527 case _CDWORD:
528 dwordTRcpy(cmsg->m + cmsg->l, OFF);
529 cmsg->l += 4;
530 break;
531 case _CSTRUCT:
532 *(u8 **) OFF = cmsg->m + cmsg->l;
533
534 if (cmsg->m[cmsg->l] != 0xff)
535 cmsg->l += 1 + cmsg->m[cmsg->l];
536 else
537 cmsg->l += 3 + *(u16 *) (cmsg->m + cmsg->l + 1);
538 break;
539 case _CMSTRUCT:
540/*----- Metastruktur 0 -----*/
541 if (cmsg->m[cmsg->l] == '\0') {
542 *(_cmstruct *) OFF = CAPI_DEFAULT;
543 cmsg->l++;
544 jumpcstruct(cmsg);
545 } else {
546 unsigned _l = cmsg->l;
547 *(_cmstruct *) OFF = CAPI_COMPOSE;
548 cmsg->l = (cmsg->m + _l)[0] == 255 ? cmsg->l + 3 : cmsg->l + 1;
549 cmsg->p++;
550 message_2_pars(cmsg);
551 }
552 break;
553 }
554 }
555}
556
557/*-------------------------------------------------------*/
558unsigned capi_message2cmsg(_cmsg * cmsg, u8 * msg)
559{
560 memset(cmsg, 0, sizeof(_cmsg));
561 cmsg->m = msg;
562 cmsg->l = 8;
563 cmsg->p = 0;
564 byteTRcpy(cmsg->m + 4, &cmsg->Command);
565 byteTRcpy(cmsg->m + 5, &cmsg->Subcommand);
566 cmsg->par = cpars[command_2_index(cmsg->Command, cmsg->Subcommand)];
567
568 message_2_pars(cmsg);
569
570 wordTRcpy(msg + 0, &cmsg->l);
571 wordTRcpy(cmsg->m + 2, &cmsg->ApplId);
572 wordTRcpy(cmsg->m + 6, &cmsg->Messagenumber);
573
574 return 0;
575}
576
577/*-------------------------------------------------------*/
578unsigned capi_cmsg_header(_cmsg * cmsg, u16 _ApplId,
579 u8 _Command, u8 _Subcommand,
580 u16 _Messagenumber, u32 _Controller)
581{
582 memset(cmsg, 0, sizeof(_cmsg));
583 cmsg->ApplId = _ApplId;
584 cmsg->Command = _Command;
585 cmsg->Subcommand = _Subcommand;
586 cmsg->Messagenumber = _Messagenumber;
587 cmsg->adr.adrController = _Controller;
588 return 0;
589}
590
591/*-------------------------------------------------------*/
592
593static char *mnames[] =
594{
595 [0x01] = "ALERT_REQ",
596 [0x02] = "CONNECT_REQ",
597 [0x04] = "DISCONNECT_REQ",
598 [0x05] = "LISTEN_REQ",
599 [0x08] = "INFO_REQ",
600 [0x09] = "FACILITY_REQ",
601 [0x0a] = "SELECT_B_PROTOCOL_REQ",
602 [0x0b] = "CONNECT_B3_REQ",
603 [0x0d] = "DISCONNECT_B3_REQ",
604 [0x0f] = "DATA_B3_REQ",
605 [0x10] = "RESET_B3_REQ",
606 [0x13] = "ALERT_CONF",
607 [0x14] = "CONNECT_CONF",
608 [0x16] = "DISCONNECT_CONF",
609 [0x17] = "LISTEN_CONF",
610 [0x18] = "MANUFACTURER_REQ",
611 [0x1a] = "INFO_CONF",
612 [0x1b] = "FACILITY_CONF",
613 [0x1c] = "SELECT_B_PROTOCOL_CONF",
614 [0x1d] = "CONNECT_B3_CONF",
615 [0x1f] = "DISCONNECT_B3_CONF",
616 [0x21] = "DATA_B3_CONF",
617 [0x22] = "RESET_B3_CONF",
618 [0x26] = "CONNECT_IND",
619 [0x27] = "CONNECT_ACTIVE_IND",
620 [0x28] = "DISCONNECT_IND",
621 [0x2a] = "MANUFACTURER_CONF",
622 [0x2c] = "INFO_IND",
623 [0x2d] = "FACILITY_IND",
624 [0x2f] = "CONNECT_B3_IND",
625 [0x30] = "CONNECT_B3_ACTIVE_IND",
626 [0x31] = "DISCONNECT_B3_IND",
627 [0x33] = "DATA_B3_IND",
628 [0x34] = "RESET_B3_IND",
629 [0x35] = "CONNECT_B3_T90_ACTIVE_IND",
630 [0x38] = "CONNECT_RESP",
631 [0x39] = "CONNECT_ACTIVE_RESP",
632 [0x3a] = "DISCONNECT_RESP",
633 [0x3c] = "MANUFACTURER_IND",
634 [0x3e] = "INFO_RESP",
635 [0x3f] = "FACILITY_RESP",
636 [0x41] = "CONNECT_B3_RESP",
637 [0x42] = "CONNECT_B3_ACTIVE_RESP",
638 [0x43] = "DISCONNECT_B3_RESP",
639 [0x45] = "DATA_B3_RESP",
640 [0x46] = "RESET_B3_RESP",
641 [0x47] = "CONNECT_B3_T90_ACTIVE_RESP",
642 [0x4e] = "MANUFACTURER_RESP"
643};
644
645char *capi_cmd2str(u8 cmd, u8 subcmd)
646{
647 return mnames[command_2_index(cmd, subcmd)];
648}
649
650
651/*-------------------------------------------------------*/
652/*-------------------------------------------------------*/
653
654static char *pnames[] =
655{
656 /*00 */ NULL,
657 /*01 */ NULL,
658 /*02 */ NULL,
659 /*03 */ "Controller/PLCI/NCCI",
660 /*04 */ "AdditionalInfo",
661 /*05 */ "B1configuration",
662 /*06 */ "B1protocol",
663 /*07 */ "B2configuration",
664 /*08 */ "B2protocol",
665 /*09 */ "B3configuration",
666 /*0a */ "B3protocol",
667 /*0b */ "BC",
668 /*0c */ "BChannelinformation",
669 /*0d */ "BProtocol",
670 /*0e */ "CalledPartyNumber",
671 /*0f */ "CalledPartySubaddress",
672 /*10 */ "CallingPartyNumber",
673 /*11 */ "CallingPartySubaddress",
674 /*12 */ "CIPmask",
675 /*13 */ "CIPmask2",
676 /*14 */ "CIPValue",
677 /*15 */ "Class",
678 /*16 */ "ConnectedNumber",
679 /*17 */ "ConnectedSubaddress",
680 /*18 */ "Data32",
681 /*19 */ "DataHandle",
682 /*1a */ "DataLength",
683 /*1b */ "FacilityConfirmationParameter",
684 /*1c */ "Facilitydataarray",
685 /*1d */ "FacilityIndicationParameter",
686 /*1e */ "FacilityRequestParameter",
687 /*1f */ "FacilitySelector",
688 /*20 */ "Flags",
689 /*21 */ "Function",
690 /*22 */ "HLC",
691 /*23 */ "Info",
692 /*24 */ "InfoElement",
693 /*25 */ "InfoMask",
694 /*26 */ "InfoNumber",
695 /*27 */ "Keypadfacility",
696 /*28 */ "LLC",
697 /*29 */ "ManuData",
698 /*2a */ "ManuID",
699 /*2b */ "NCPI",
700 /*2c */ "Reason",
701 /*2d */ "Reason_B3",
702 /*2e */ "Reject",
703 /*2f */ "Useruserdata"
704};
705
706
707static char buf[8192];
708static char *p = NULL;
709
710#include <stdarg.h>
711
712/*-------------------------------------------------------*/
713static void bufprint(char *fmt,...)
714{
715 va_list f;
716 va_start(f, fmt);
717 vsprintf(p, fmt, f);
718 va_end(f);
719 p += strlen(p);
720}
721
722static void printstructlen(u8 * m, unsigned len)
723{
724 unsigned hex = 0;
725 for (; len; len--, m++)
726 if (isalnum(*m) || *m == ' ') {
727 if (hex)
728 bufprint(">");
729 bufprint("%c", *m);
730 hex = 0;
731 } else {
732 if (!hex)
733 bufprint("<%02x", *m);
734 else
735 bufprint(" %02x", *m);
736 hex = 1;
737 }
738 if (hex)
739 bufprint(">");
740}
741
742static void printstruct(u8 * m)
743{
744 unsigned len;
745 if (m[0] != 0xff) {
746 len = m[0];
747 m += 1;
748 } else {
749 len = ((u16 *) (m + 1))[0];
750 m += 3;
751 }
752 printstructlen(m, len);
753}
754
755/*-------------------------------------------------------*/
756#define NAME (pnames[cmsg->par[cmsg->p]])
757
758static void protocol_message_2_pars(_cmsg * cmsg, int level)
759{
760 for (; TYP != _CEND; cmsg->p++) {
761 int slen = 29 + 3 - level;
762 int i;
763
764 bufprint(" ");
765 for (i = 0; i < level - 1; i++)
766 bufprint(" ");
767
768 switch (TYP) {
769 case _CBYTE:
770 bufprint("%-*s = 0x%x\n", slen, NAME, *(u8 *) (cmsg->m + cmsg->l));
771 cmsg->l++;
772 break;
773 case _CWORD:
774 bufprint("%-*s = 0x%x\n", slen, NAME, *(u16 *) (cmsg->m + cmsg->l));
775 cmsg->l += 2;
776 break;
777 case _CDWORD:
778 bufprint("%-*s = 0x%lx\n", slen, NAME, *(u32 *) (cmsg->m + cmsg->l));
779 cmsg->l += 4;
780 break;
781 case _CSTRUCT:
782 bufprint("%-*s = ", slen, NAME);
783 if (cmsg->m[cmsg->l] == '\0')
784 bufprint("default");
785 else
786 printstruct(cmsg->m + cmsg->l);
787 bufprint("\n");
788 if (cmsg->m[cmsg->l] != 0xff)
789 cmsg->l += 1 + cmsg->m[cmsg->l];
790 else
791 cmsg->l += 3 + *(u16 *) (cmsg->m + cmsg->l + 1);
792
793 break;
794
795 case _CMSTRUCT:
796/*----- Metastruktur 0 -----*/
797 if (cmsg->m[cmsg->l] == '\0') {
798 bufprint("%-*s = default\n", slen, NAME);
799 cmsg->l++;
800 jumpcstruct(cmsg);
801 } else {
802 char *name = NAME;
803 unsigned _l = cmsg->l;
804 bufprint("%-*s\n", slen, name);
805 cmsg->l = (cmsg->m + _l)[0] == 255 ? cmsg->l + 3 : cmsg->l + 1;
806 cmsg->p++;
807 protocol_message_2_pars(cmsg, level + 1);
808 }
809 break;
810 }
811 }
812}
813/*-------------------------------------------------------*/
814char *capi_message2str(u8 * msg)
815{
816
817 _cmsg cmsg;
818 p = buf;
819 p[0] = 0;
820
821 cmsg.m = msg;
822 cmsg.l = 8;
823 cmsg.p = 0;
824 byteTRcpy(cmsg.m + 4, &cmsg.Command);
825 byteTRcpy(cmsg.m + 5, &cmsg.Subcommand);
826 cmsg.par = cpars[command_2_index(cmsg.Command, cmsg.Subcommand)];
827
828 bufprint("%-26s ID=%03d #0x%04x LEN=%04d\n",
829 mnames[command_2_index(cmsg.Command, cmsg.Subcommand)],
830 ((unsigned short *) msg)[1],
831 ((unsigned short *) msg)[3],
832 ((unsigned short *) msg)[0]);
833
834 protocol_message_2_pars(&cmsg, 1);
835 return buf;
836}
837
838char *capi_cmsg2str(_cmsg * cmsg)
839{
840 p = buf;
841 p[0] = 0;
842 cmsg->l = 8;
843 cmsg->p = 0;
844 bufprint("%s ID=%03d #0x%04x LEN=%04d\n",
845 mnames[command_2_index(cmsg->Command, cmsg->Subcommand)],
846 ((u16 *) cmsg->m)[1],
847 ((u16 *) cmsg->m)[3],
848 ((u16 *) cmsg->m)[0]);
849 protocol_message_2_pars(cmsg, 1);
850 return buf;
851}
852
853EXPORT_SYMBOL(capi_cmsg2message);
854EXPORT_SYMBOL(capi_message2cmsg);
855EXPORT_SYMBOL(capi_cmsg_header);
856EXPORT_SYMBOL(capi_cmd2str);
857EXPORT_SYMBOL(capi_cmsg2str);
858EXPORT_SYMBOL(capi_message2str);
859EXPORT_SYMBOL(capi_info2str);
diff --git a/drivers/isdn/capi/kcapi.c b/drivers/isdn/capi/kcapi.c
new file mode 100644
index 000000000000..feec40cf5900
--- /dev/null
+++ b/drivers/isdn/capi/kcapi.c
@@ -0,0 +1,991 @@
1/* $Id: kcapi.c,v 1.1.2.8 2004/03/26 19:57:20 armin Exp $
2 *
3 * Kernel CAPI 2.0 Module
4 *
5 * Copyright 1999 by Carsten Paeth <calle@calle.de>
6 * Copyright 2002 by Kai Germaschewski <kai@germaschewski.name>
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 */
12
13#define CONFIG_AVMB1_COMPAT
14
15#include "kcapi.h"
16#include <linux/module.h>
17#include <linux/mm.h>
18#include <linux/interrupt.h>
19#include <linux/ioport.h>
20#include <linux/proc_fs.h>
21#include <linux/seq_file.h>
22#include <linux/skbuff.h>
23#include <linux/workqueue.h>
24#include <linux/capi.h>
25#include <linux/kernelcapi.h>
26#include <linux/init.h>
27#include <linux/moduleparam.h>
28#include <linux/delay.h>
29#include <asm/uaccess.h>
30#include <linux/isdn/capicmd.h>
31#include <linux/isdn/capiutil.h>
32#ifdef CONFIG_AVMB1_COMPAT
33#include <linux/b1lli.h>
34#endif
35
36static char *revision = "$Revision: 1.1.2.8 $";
37
38/* ------------------------------------------------------------- */
39
40static int showcapimsgs = 0;
41
42MODULE_DESCRIPTION("CAPI4Linux: kernel CAPI layer");
43MODULE_AUTHOR("Carsten Paeth");
44MODULE_LICENSE("GPL");
45module_param(showcapimsgs, uint, 0);
46
47/* ------------------------------------------------------------- */
48
49struct capi_notifier {
50 struct work_struct work;
51 unsigned int cmd;
52 u32 controller;
53 u16 applid;
54 u32 ncci;
55};
56
57/* ------------------------------------------------------------- */
58
59static struct capi_version driver_version = {2, 0, 1, 1<<4};
60static char driver_serial[CAPI_SERIAL_LEN] = "0004711";
61static char capi_manufakturer[64] = "AVM Berlin";
62
63#define NCCI2CTRL(ncci) (((ncci) >> 24) & 0x7f)
64
65LIST_HEAD(capi_drivers);
66DEFINE_RWLOCK(capi_drivers_list_lock);
67
68static DEFINE_RWLOCK(application_lock);
69static DECLARE_MUTEX(controller_sem);
70
71struct capi20_appl *capi_applications[CAPI_MAXAPPL];
72struct capi_ctr *capi_cards[CAPI_MAXCONTR];
73
74static int ncards;
75
76/* -------- controller ref counting -------------------------------------- */
77
78static inline struct capi_ctr *
79capi_ctr_get(struct capi_ctr *card)
80{
81 if (!try_module_get(card->owner))
82 return NULL;
83 return card;
84}
85
86static inline void
87capi_ctr_put(struct capi_ctr *card)
88{
89 module_put(card->owner);
90}
91
92/* ------------------------------------------------------------- */
93
94static inline struct capi_ctr *get_capi_ctr_by_nr(u16 contr)
95{
96 if (contr - 1 >= CAPI_MAXCONTR)
97 return NULL;
98
99 return capi_cards[contr - 1];
100}
101
102static inline struct capi20_appl *get_capi_appl_by_nr(u16 applid)
103{
104 if (applid - 1 >= CAPI_MAXAPPL)
105 return NULL;
106
107 return capi_applications[applid - 1];
108}
109
110/* -------- util functions ------------------------------------ */
111
112static inline int capi_cmd_valid(u8 cmd)
113{
114 switch (cmd) {
115 case CAPI_ALERT:
116 case CAPI_CONNECT:
117 case CAPI_CONNECT_ACTIVE:
118 case CAPI_CONNECT_B3_ACTIVE:
119 case CAPI_CONNECT_B3:
120 case CAPI_CONNECT_B3_T90_ACTIVE:
121 case CAPI_DATA_B3:
122 case CAPI_DISCONNECT_B3:
123 case CAPI_DISCONNECT:
124 case CAPI_FACILITY:
125 case CAPI_INFO:
126 case CAPI_LISTEN:
127 case CAPI_MANUFACTURER:
128 case CAPI_RESET_B3:
129 case CAPI_SELECT_B_PROTOCOL:
130 return 1;
131 }
132 return 0;
133}
134
135static inline int capi_subcmd_valid(u8 subcmd)
136{
137 switch (subcmd) {
138 case CAPI_REQ:
139 case CAPI_CONF:
140 case CAPI_IND:
141 case CAPI_RESP:
142 return 1;
143 }
144 return 0;
145}
146
147/* ------------------------------------------------------------ */
148
149static void register_appl(struct capi_ctr *card, u16 applid, capi_register_params *rparam)
150{
151 card = capi_ctr_get(card);
152
153 if (card)
154 card->register_appl(card, applid, rparam);
155 else
156 printk(KERN_WARNING "%s: cannot get card resources\n", __FUNCTION__);
157}
158
159
160static void release_appl(struct capi_ctr *card, u16 applid)
161{
162 DBG("applid %#x", applid);
163
164 card->release_appl(card, applid);
165 capi_ctr_put(card);
166}
167
168/* -------- KCI_CONTRUP --------------------------------------- */
169
170static void notify_up(u32 contr)
171{
172 struct capi_ctr *card = get_capi_ctr_by_nr(contr);
173 struct capi20_appl *ap;
174 u16 applid;
175
176 if (showcapimsgs & 1) {
177 printk(KERN_DEBUG "kcapi: notify up contr %d\n", contr);
178 }
179 if (!card) {
180 printk(KERN_WARNING "%s: invalid contr %d\n", __FUNCTION__, contr);
181 return;
182 }
183 for (applid = 1; applid <= CAPI_MAXAPPL; applid++) {
184 ap = get_capi_appl_by_nr(applid);
185 if (!ap || ap->release_in_progress) continue;
186 register_appl(card, applid, &ap->rparam);
187 if (ap->callback && !ap->release_in_progress)
188 ap->callback(KCI_CONTRUP, contr, &card->profile);
189 }
190}
191
192/* -------- KCI_CONTRDOWN ------------------------------------- */
193
194static void notify_down(u32 contr)
195{
196 struct capi20_appl *ap;
197 u16 applid;
198
199 if (showcapimsgs & 1) {
200 printk(KERN_DEBUG "kcapi: notify down contr %d\n", contr);
201 }
202
203 for (applid = 1; applid <= CAPI_MAXAPPL; applid++) {
204 ap = get_capi_appl_by_nr(applid);
205 if (ap && ap->callback && !ap->release_in_progress)
206 ap->callback(KCI_CONTRDOWN, contr, NULL);
207 }
208}
209
210static void notify_handler(void *data)
211{
212 struct capi_notifier *np = data;
213
214 switch (np->cmd) {
215 case KCI_CONTRUP:
216 notify_up(np->controller);
217 break;
218 case KCI_CONTRDOWN:
219 notify_down(np->controller);
220 break;
221 }
222
223 kfree(np);
224}
225
226/*
227 * The notifier will result in adding/deleteing of devices. Devices can
228 * only removed in user process, not in bh.
229 */
230static int notify_push(unsigned int cmd, u32 controller, u16 applid, u32 ncci)
231{
232 struct capi_notifier *np = kmalloc(sizeof(*np), GFP_ATOMIC);
233
234 if (!np)
235 return -ENOMEM;
236
237 INIT_WORK(&np->work, notify_handler, np);
238 np->cmd = cmd;
239 np->controller = controller;
240 np->applid = applid;
241 np->ncci = ncci;
242
243 schedule_work(&np->work);
244 return 0;
245}
246
247
248/* -------- Receiver ------------------------------------------ */
249
250static void recv_handler(void *_ap)
251{
252 struct sk_buff *skb;
253 struct capi20_appl *ap = (struct capi20_appl *) _ap;
254
255 if ((!ap) || (ap->release_in_progress))
256 return;
257
258 down(&ap->recv_sem);
259 while ((skb = skb_dequeue(&ap->recv_queue))) {
260 if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_IND)
261 ap->nrecvdatapkt++;
262 else
263 ap->nrecvctlpkt++;
264
265 ap->recv_message(ap, skb);
266 }
267 up(&ap->recv_sem);
268}
269
270void capi_ctr_handle_message(struct capi_ctr * card, u16 appl, struct sk_buff *skb)
271{
272 struct capi20_appl *ap;
273 int showctl = 0;
274 u8 cmd, subcmd;
275 unsigned long flags;
276
277 if (card->cardstate != CARD_RUNNING) {
278 printk(KERN_INFO "kcapi: controller %d not active, got: %s",
279 card->cnr, capi_message2str(skb->data));
280 goto error;
281 }
282
283 cmd = CAPIMSG_COMMAND(skb->data);
284 subcmd = CAPIMSG_SUBCOMMAND(skb->data);
285 if (cmd == CAPI_DATA_B3 && subcmd == CAPI_IND) {
286 card->nrecvdatapkt++;
287 if (card->traceflag > 2) showctl |= 2;
288 } else {
289 card->nrecvctlpkt++;
290 if (card->traceflag) showctl |= 2;
291 }
292 showctl |= (card->traceflag & 1);
293 if (showctl & 2) {
294 if (showctl & 1) {
295 printk(KERN_DEBUG "kcapi: got [0x%lx] id#%d %s len=%u\n",
296 (unsigned long) card->cnr,
297 CAPIMSG_APPID(skb->data),
298 capi_cmd2str(cmd, subcmd),
299 CAPIMSG_LEN(skb->data));
300 } else {
301 printk(KERN_DEBUG "kcapi: got [0x%lx] %s\n",
302 (unsigned long) card->cnr,
303 capi_message2str(skb->data));
304 }
305
306 }
307
308 read_lock_irqsave(&application_lock, flags);
309 ap = get_capi_appl_by_nr(CAPIMSG_APPID(skb->data));
310 if ((!ap) || (ap->release_in_progress)) {
311 read_unlock_irqrestore(&application_lock, flags);
312 printk(KERN_ERR "kcapi: handle_message: applid %d state released (%s)\n",
313 CAPIMSG_APPID(skb->data), capi_message2str(skb->data));
314 goto error;
315 }
316 skb_queue_tail(&ap->recv_queue, skb);
317 schedule_work(&ap->recv_work);
318 read_unlock_irqrestore(&application_lock, flags);
319
320 return;
321
322error:
323 kfree_skb(skb);
324}
325
326EXPORT_SYMBOL(capi_ctr_handle_message);
327
328void capi_ctr_ready(struct capi_ctr * card)
329{
330 card->cardstate = CARD_RUNNING;
331
332 printk(KERN_NOTICE "kcapi: card %d \"%s\" ready.\n",
333 card->cnr, card->name);
334
335 notify_push(KCI_CONTRUP, card->cnr, 0, 0);
336}
337
338EXPORT_SYMBOL(capi_ctr_ready);
339
340void capi_ctr_reseted(struct capi_ctr * card)
341{
342 u16 appl;
343
344 DBG("");
345
346 if (card->cardstate == CARD_DETECTED)
347 return;
348
349 card->cardstate = CARD_DETECTED;
350
351 memset(card->manu, 0, sizeof(card->manu));
352 memset(&card->version, 0, sizeof(card->version));
353 memset(&card->profile, 0, sizeof(card->profile));
354 memset(card->serial, 0, sizeof(card->serial));
355
356 for (appl = 1; appl <= CAPI_MAXAPPL; appl++) {
357 struct capi20_appl *ap = get_capi_appl_by_nr(appl);
358 if (!ap || ap->release_in_progress)
359 continue;
360
361 capi_ctr_put(card);
362 }
363
364 printk(KERN_NOTICE "kcapi: card %d down.\n", card->cnr);
365
366 notify_push(KCI_CONTRDOWN, card->cnr, 0, 0);
367}
368
369EXPORT_SYMBOL(capi_ctr_reseted);
370
371void capi_ctr_suspend_output(struct capi_ctr *card)
372{
373 if (!card->blocked) {
374 printk(KERN_DEBUG "kcapi: card %d suspend\n", card->cnr);
375 card->blocked = 1;
376 }
377}
378
379EXPORT_SYMBOL(capi_ctr_suspend_output);
380
381void capi_ctr_resume_output(struct capi_ctr *card)
382{
383 if (card->blocked) {
384 printk(KERN_DEBUG "kcapi: card %d resume\n", card->cnr);
385 card->blocked = 0;
386 }
387}
388
389EXPORT_SYMBOL(capi_ctr_resume_output);
390
391/* ------------------------------------------------------------- */
392
393int
394attach_capi_ctr(struct capi_ctr *card)
395{
396 int i;
397
398 down(&controller_sem);
399
400 for (i = 0; i < CAPI_MAXCONTR; i++) {
401 if (capi_cards[i] == NULL)
402 break;
403 }
404 if (i == CAPI_MAXCONTR) {
405 up(&controller_sem);
406 printk(KERN_ERR "kcapi: out of controller slots\n");
407 return -EBUSY;
408 }
409 capi_cards[i] = card;
410
411 up(&controller_sem);
412
413 card->nrecvctlpkt = 0;
414 card->nrecvdatapkt = 0;
415 card->nsentctlpkt = 0;
416 card->nsentdatapkt = 0;
417 card->cnr = i + 1;
418 card->cardstate = CARD_DETECTED;
419 card->blocked = 0;
420 card->traceflag = showcapimsgs;
421
422 sprintf(card->procfn, "capi/controllers/%d", card->cnr);
423 card->procent = create_proc_entry(card->procfn, 0, NULL);
424 if (card->procent) {
425 card->procent->read_proc =
426 (int (*)(char *,char **,off_t,int,int *,void *))
427 card->ctr_read_proc;
428 card->procent->data = card;
429 }
430
431 ncards++;
432 printk(KERN_NOTICE "kcapi: Controller %d: %s attached\n",
433 card->cnr, card->name);
434 return 0;
435}
436
437EXPORT_SYMBOL(attach_capi_ctr);
438
439int detach_capi_ctr(struct capi_ctr *card)
440{
441 if (card->cardstate != CARD_DETECTED)
442 capi_ctr_reseted(card);
443
444 ncards--;
445
446 if (card->procent) {
447 remove_proc_entry(card->procfn, NULL);
448 card->procent = NULL;
449 }
450 capi_cards[card->cnr - 1] = NULL;
451 printk(KERN_NOTICE "kcapi: Controller %d: %s unregistered\n",
452 card->cnr, card->name);
453
454 return 0;
455}
456
457EXPORT_SYMBOL(detach_capi_ctr);
458
459void register_capi_driver(struct capi_driver *driver)
460{
461 unsigned long flags;
462
463 write_lock_irqsave(&capi_drivers_list_lock, flags);
464 list_add_tail(&driver->list, &capi_drivers);
465 write_unlock_irqrestore(&capi_drivers_list_lock, flags);
466}
467
468EXPORT_SYMBOL(register_capi_driver);
469
470void unregister_capi_driver(struct capi_driver *driver)
471{
472 unsigned long flags;
473
474 write_lock_irqsave(&capi_drivers_list_lock, flags);
475 list_del(&driver->list);
476 write_unlock_irqrestore(&capi_drivers_list_lock, flags);
477}
478
479EXPORT_SYMBOL(unregister_capi_driver);
480
481/* ------------------------------------------------------------- */
482/* -------- CAPI2.0 Interface ---------------------------------- */
483/* ------------------------------------------------------------- */
484
485u16 capi20_isinstalled(void)
486{
487 int i;
488 for (i = 0; i < CAPI_MAXCONTR; i++) {
489 if (capi_cards[i] && capi_cards[i]->cardstate == CARD_RUNNING)
490 return CAPI_NOERROR;
491 }
492 return CAPI_REGNOTINSTALLED;
493}
494
495EXPORT_SYMBOL(capi20_isinstalled);
496
497u16 capi20_register(struct capi20_appl *ap)
498{
499 int i;
500 u16 applid;
501 unsigned long flags;
502
503 DBG("");
504
505 if (ap->rparam.datablklen < 128)
506 return CAPI_LOGBLKSIZETOSMALL;
507
508 write_lock_irqsave(&application_lock, flags);
509
510 for (applid = 1; applid <= CAPI_MAXAPPL; applid++) {
511 if (capi_applications[applid - 1] == NULL)
512 break;
513 }
514 if (applid > CAPI_MAXAPPL) {
515 write_unlock_irqrestore(&application_lock, flags);
516 return CAPI_TOOMANYAPPLS;
517 }
518
519 ap->applid = applid;
520 capi_applications[applid - 1] = ap;
521
522 ap->nrecvctlpkt = 0;
523 ap->nrecvdatapkt = 0;
524 ap->nsentctlpkt = 0;
525 ap->nsentdatapkt = 0;
526 ap->callback = NULL;
527 init_MUTEX(&ap->recv_sem);
528 skb_queue_head_init(&ap->recv_queue);
529 INIT_WORK(&ap->recv_work, recv_handler, (void *)ap);
530 ap->release_in_progress = 0;
531
532 write_unlock_irqrestore(&application_lock, flags);
533
534 down(&controller_sem);
535 for (i = 0; i < CAPI_MAXCONTR; i++) {
536 if (!capi_cards[i] || capi_cards[i]->cardstate != CARD_RUNNING)
537 continue;
538 register_appl(capi_cards[i], applid, &ap->rparam);
539 }
540 up(&controller_sem);
541
542 if (showcapimsgs & 1) {
543 printk(KERN_DEBUG "kcapi: appl %d up\n", applid);
544 }
545
546 return CAPI_NOERROR;
547}
548
549EXPORT_SYMBOL(capi20_register);
550
551u16 capi20_release(struct capi20_appl *ap)
552{
553 int i;
554 unsigned long flags;
555
556 DBG("applid %#x", ap->applid);
557
558 write_lock_irqsave(&application_lock, flags);
559 ap->release_in_progress = 1;
560 capi_applications[ap->applid - 1] = NULL;
561 write_unlock_irqrestore(&application_lock, flags);
562
563 down(&controller_sem);
564 for (i = 0; i < CAPI_MAXCONTR; i++) {
565 if (!capi_cards[i] || capi_cards[i]->cardstate != CARD_RUNNING)
566 continue;
567 release_appl(capi_cards[i], ap->applid);
568 }
569 up(&controller_sem);
570
571 flush_scheduled_work();
572 skb_queue_purge(&ap->recv_queue);
573
574 if (showcapimsgs & 1) {
575 printk(KERN_DEBUG "kcapi: appl %d down\n", ap->applid);
576 }
577
578 return CAPI_NOERROR;
579}
580
581EXPORT_SYMBOL(capi20_release);
582
583u16 capi20_put_message(struct capi20_appl *ap, struct sk_buff *skb)
584{
585 struct capi_ctr *card;
586 int showctl = 0;
587 u8 cmd, subcmd;
588
589 DBG("applid %#x", ap->applid);
590
591 if (ncards == 0)
592 return CAPI_REGNOTINSTALLED;
593 if ((ap->applid == 0) || ap->release_in_progress)
594 return CAPI_ILLAPPNR;
595 if (skb->len < 12
596 || !capi_cmd_valid(CAPIMSG_COMMAND(skb->data))
597 || !capi_subcmd_valid(CAPIMSG_SUBCOMMAND(skb->data)))
598 return CAPI_ILLCMDORSUBCMDORMSGTOSMALL;
599 card = get_capi_ctr_by_nr(CAPIMSG_CONTROLLER(skb->data));
600 if (!card || card->cardstate != CARD_RUNNING) {
601 card = get_capi_ctr_by_nr(1); // XXX why?
602 if (!card || card->cardstate != CARD_RUNNING)
603 return CAPI_REGNOTINSTALLED;
604 }
605 if (card->blocked)
606 return CAPI_SENDQUEUEFULL;
607
608 cmd = CAPIMSG_COMMAND(skb->data);
609 subcmd = CAPIMSG_SUBCOMMAND(skb->data);
610
611 if (cmd == CAPI_DATA_B3 && subcmd== CAPI_REQ) {
612 card->nsentdatapkt++;
613 ap->nsentdatapkt++;
614 if (card->traceflag > 2) showctl |= 2;
615 } else {
616 card->nsentctlpkt++;
617 ap->nsentctlpkt++;
618 if (card->traceflag) showctl |= 2;
619 }
620 showctl |= (card->traceflag & 1);
621 if (showctl & 2) {
622 if (showctl & 1) {
623 printk(KERN_DEBUG "kcapi: put [%#x] id#%d %s len=%u\n",
624 CAPIMSG_CONTROLLER(skb->data),
625 CAPIMSG_APPID(skb->data),
626 capi_cmd2str(cmd, subcmd),
627 CAPIMSG_LEN(skb->data));
628 } else {
629 printk(KERN_DEBUG "kcapi: put [%#x] %s\n",
630 CAPIMSG_CONTROLLER(skb->data),
631 capi_message2str(skb->data));
632 }
633
634 }
635 return card->send_message(card, skb);
636}
637
638EXPORT_SYMBOL(capi20_put_message);
639
640u16 capi20_get_manufacturer(u32 contr, u8 *buf)
641{
642 struct capi_ctr *card;
643
644 if (contr == 0) {
645 strlcpy(buf, capi_manufakturer, CAPI_MANUFACTURER_LEN);
646 return CAPI_NOERROR;
647 }
648 card = get_capi_ctr_by_nr(contr);
649 if (!card || card->cardstate != CARD_RUNNING)
650 return CAPI_REGNOTINSTALLED;
651 strlcpy(buf, card->manu, CAPI_MANUFACTURER_LEN);
652 return CAPI_NOERROR;
653}
654
655EXPORT_SYMBOL(capi20_get_manufacturer);
656
657u16 capi20_get_version(u32 contr, struct capi_version *verp)
658{
659 struct capi_ctr *card;
660
661 if (contr == 0) {
662 *verp = driver_version;
663 return CAPI_NOERROR;
664 }
665 card = get_capi_ctr_by_nr(contr);
666 if (!card || card->cardstate != CARD_RUNNING)
667 return CAPI_REGNOTINSTALLED;
668
669 memcpy((void *) verp, &card->version, sizeof(capi_version));
670 return CAPI_NOERROR;
671}
672
673EXPORT_SYMBOL(capi20_get_version);
674
675u16 capi20_get_serial(u32 contr, u8 *serial)
676{
677 struct capi_ctr *card;
678
679 if (contr == 0) {
680 strlcpy(serial, driver_serial, CAPI_SERIAL_LEN);
681 return CAPI_NOERROR;
682 }
683 card = get_capi_ctr_by_nr(contr);
684 if (!card || card->cardstate != CARD_RUNNING)
685 return CAPI_REGNOTINSTALLED;
686
687 strlcpy((void *) serial, card->serial, CAPI_SERIAL_LEN);
688 return CAPI_NOERROR;
689}
690
691EXPORT_SYMBOL(capi20_get_serial);
692
693u16 capi20_get_profile(u32 contr, struct capi_profile *profp)
694{
695 struct capi_ctr *card;
696
697 if (contr == 0) {
698 profp->ncontroller = ncards;
699 return CAPI_NOERROR;
700 }
701 card = get_capi_ctr_by_nr(contr);
702 if (!card || card->cardstate != CARD_RUNNING)
703 return CAPI_REGNOTINSTALLED;
704
705 memcpy((void *) profp, &card->profile,
706 sizeof(struct capi_profile));
707 return CAPI_NOERROR;
708}
709
710EXPORT_SYMBOL(capi20_get_profile);
711
712#ifdef CONFIG_AVMB1_COMPAT
713static int old_capi_manufacturer(unsigned int cmd, void __user *data)
714{
715 avmb1_loadandconfigdef ldef;
716 avmb1_extcarddef cdef;
717 avmb1_resetdef rdef;
718 capicardparams cparams;
719 struct capi_ctr *card;
720 struct capi_driver *driver = NULL;
721 capiloaddata ldata;
722 struct list_head *l;
723 unsigned long flags;
724 int retval;
725
726 switch (cmd) {
727 case AVMB1_ADDCARD:
728 case AVMB1_ADDCARD_WITH_TYPE:
729 if (cmd == AVMB1_ADDCARD) {
730 if ((retval = copy_from_user(&cdef, data,
731 sizeof(avmb1_carddef))))
732 return retval;
733 cdef.cardtype = AVM_CARDTYPE_B1;
734 } else {
735 if ((retval = copy_from_user(&cdef, data,
736 sizeof(avmb1_extcarddef))))
737 return retval;
738 }
739 cparams.port = cdef.port;
740 cparams.irq = cdef.irq;
741 cparams.cardnr = cdef.cardnr;
742
743 read_lock_irqsave(&capi_drivers_list_lock, flags);
744 switch (cdef.cardtype) {
745 case AVM_CARDTYPE_B1:
746 list_for_each(l, &capi_drivers) {
747 driver = list_entry(l, struct capi_driver, list);
748 if (strcmp(driver->name, "b1isa") == 0)
749 break;
750 }
751 break;
752 case AVM_CARDTYPE_T1:
753 list_for_each(l, &capi_drivers) {
754 driver = list_entry(l, struct capi_driver, list);
755 if (strcmp(driver->name, "t1isa") == 0)
756 break;
757 }
758 break;
759 default:
760 driver = NULL;
761 break;
762 }
763 if (!driver) {
764 read_unlock_irqrestore(&capi_drivers_list_lock, flags);
765 printk(KERN_ERR "kcapi: driver not loaded.\n");
766 return -EIO;
767 }
768 if (!driver->add_card) {
769 read_unlock_irqrestore(&capi_drivers_list_lock, flags);
770 printk(KERN_ERR "kcapi: driver has no add card function.\n");
771 return -EIO;
772 }
773
774 retval = driver->add_card(driver, &cparams);
775 read_unlock_irqrestore(&capi_drivers_list_lock, flags);
776 return retval;
777
778 case AVMB1_LOAD:
779 case AVMB1_LOAD_AND_CONFIG:
780
781 if (cmd == AVMB1_LOAD) {
782 if (copy_from_user(&ldef, data,
783 sizeof(avmb1_loaddef)))
784 return -EFAULT;
785 ldef.t4config.len = 0;
786 ldef.t4config.data = NULL;
787 } else {
788 if (copy_from_user(&ldef, data,
789 sizeof(avmb1_loadandconfigdef)))
790 return -EFAULT;
791 }
792 card = get_capi_ctr_by_nr(ldef.contr);
793 card = capi_ctr_get(card);
794 if (!card)
795 return -ESRCH;
796 if (card->load_firmware == 0) {
797 printk(KERN_DEBUG "kcapi: load: no load function\n");
798 return -ESRCH;
799 }
800
801 if (ldef.t4file.len <= 0) {
802 printk(KERN_DEBUG "kcapi: load: invalid parameter: length of t4file is %d ?\n", ldef.t4file.len);
803 return -EINVAL;
804 }
805 if (ldef.t4file.data == 0) {
806 printk(KERN_DEBUG "kcapi: load: invalid parameter: dataptr is 0\n");
807 return -EINVAL;
808 }
809
810 ldata.firmware.user = 1;
811 ldata.firmware.data = ldef.t4file.data;
812 ldata.firmware.len = ldef.t4file.len;
813 ldata.configuration.user = 1;
814 ldata.configuration.data = ldef.t4config.data;
815 ldata.configuration.len = ldef.t4config.len;
816
817 if (card->cardstate != CARD_DETECTED) {
818 printk(KERN_INFO "kcapi: load: contr=%d not in detect state\n", ldef.contr);
819 return -EBUSY;
820 }
821 card->cardstate = CARD_LOADING;
822
823 retval = card->load_firmware(card, &ldata);
824
825 if (retval) {
826 card->cardstate = CARD_DETECTED;
827 capi_ctr_put(card);
828 return retval;
829 }
830
831 while (card->cardstate != CARD_RUNNING) {
832
833 msleep_interruptible(100); /* 0.1 sec */
834
835 if (signal_pending(current)) {
836 capi_ctr_put(card);
837 return -EINTR;
838 }
839 }
840 capi_ctr_put(card);
841 return 0;
842
843 case AVMB1_RESETCARD:
844 if (copy_from_user(&rdef, data, sizeof(avmb1_resetdef)))
845 return -EFAULT;
846 card = get_capi_ctr_by_nr(rdef.contr);
847 if (!card)
848 return -ESRCH;
849
850 if (card->cardstate == CARD_DETECTED)
851 return 0;
852
853 card->reset_ctr(card);
854
855 while (card->cardstate > CARD_DETECTED) {
856
857 msleep_interruptible(100); /* 0.1 sec */
858
859 if (signal_pending(current))
860 return -EINTR;
861 }
862 return 0;
863
864 }
865 return -EINVAL;
866}
867#endif
868
869int capi20_manufacturer(unsigned int cmd, void __user *data)
870{
871 struct capi_ctr *card;
872
873 switch (cmd) {
874#ifdef CONFIG_AVMB1_COMPAT
875 case AVMB1_LOAD:
876 case AVMB1_LOAD_AND_CONFIG:
877 case AVMB1_RESETCARD:
878 case AVMB1_GET_CARDINFO:
879 case AVMB1_REMOVECARD:
880 return old_capi_manufacturer(cmd, data);
881#endif
882 case KCAPI_CMD_TRACE:
883 {
884 kcapi_flagdef fdef;
885
886 if (copy_from_user(&fdef, data, sizeof(kcapi_flagdef)))
887 return -EFAULT;
888
889 card = get_capi_ctr_by_nr(fdef.contr);
890 if (!card)
891 return -ESRCH;
892
893 card->traceflag = fdef.flag;
894 printk(KERN_INFO "kcapi: contr %d set trace=%d\n",
895 card->cnr, card->traceflag);
896 return 0;
897 }
898 case KCAPI_CMD_ADDCARD:
899 {
900 struct list_head *l;
901 struct capi_driver *driver = NULL;
902 capicardparams cparams;
903 kcapi_carddef cdef;
904 int retval;
905
906 if ((retval = copy_from_user(&cdef, data, sizeof(cdef))))
907 return retval;
908
909 cparams.port = cdef.port;
910 cparams.irq = cdef.irq;
911 cparams.membase = cdef.membase;
912 cparams.cardnr = cdef.cardnr;
913 cparams.cardtype = 0;
914 cdef.driver[sizeof(cdef.driver)-1] = 0;
915
916 list_for_each(l, &capi_drivers) {
917 driver = list_entry(l, struct capi_driver, list);
918 if (strcmp(driver->name, cdef.driver) == 0)
919 break;
920 }
921 if (driver == 0) {
922 printk(KERN_ERR "kcapi: driver \"%s\" not loaded.\n",
923 cdef.driver);
924 return -ESRCH;
925 }
926
927 if (!driver->add_card) {
928 printk(KERN_ERR "kcapi: driver \"%s\" has no add card function.\n", cdef.driver);
929 return -EIO;
930 }
931
932 return driver->add_card(driver, &cparams);
933 }
934
935 default:
936 printk(KERN_ERR "kcapi: manufacturer command %d unknown.\n",
937 cmd);
938 break;
939
940 }
941 return -EINVAL;
942}
943
944EXPORT_SYMBOL(capi20_manufacturer);
945
946/* temporary hack */
947void capi20_set_callback(struct capi20_appl *ap,
948 void (*callback) (unsigned int cmd, __u32 contr, void *data))
949{
950 ap->callback = callback;
951}
952
953EXPORT_SYMBOL(capi20_set_callback);
954
955/* ------------------------------------------------------------- */
956/* -------- Init & Cleanup ------------------------------------- */
957/* ------------------------------------------------------------- */
958
959/*
960 * init / exit functions
961 */
962
963static int __init kcapi_init(void)
964{
965 char *p;
966 char rev[32];
967
968 kcapi_proc_init();
969
970 if ((p = strchr(revision, ':')) != 0 && p[1]) {
971 strlcpy(rev, p + 2, sizeof(rev));
972 if ((p = strchr(rev, '$')) != 0 && p > rev)
973 *(p-1) = 0;
974 } else
975 strcpy(rev, "1.0");
976
977 printk(KERN_NOTICE "CAPI Subsystem Rev %s\n", rev);
978
979 return 0;
980}
981
982static void __exit kcapi_exit(void)
983{
984 kcapi_proc_exit();
985
986 /* make sure all notifiers are finished */
987 flush_scheduled_work();
988}
989
990module_init(kcapi_init);
991module_exit(kcapi_exit);
diff --git a/drivers/isdn/capi/kcapi.h b/drivers/isdn/capi/kcapi.h
new file mode 100644
index 000000000000..1cb2c40f9921
--- /dev/null
+++ b/drivers/isdn/capi/kcapi.h
@@ -0,0 +1,49 @@
1/*
2 * Kernel CAPI 2.0 Module
3 *
4 * Copyright 1999 by Carsten Paeth <calle@calle.de>
5 * Copyright 2002 by Kai Germaschewski <kai@germaschewski.name>
6 *
7 * This software may be used and distributed according to the terms
8 * of the GNU General Public License, incorporated herein by reference.
9 *
10 */
11
12
13#include <linux/kernel.h>
14#include <linux/spinlock.h>
15#include <linux/list.h>
16#include <linux/isdn/capilli.h>
17
18#ifdef KCAPI_DEBUG
19#define DBG(format, arg...) do { \
20printk(KERN_DEBUG "%s: " format "\n" , __FUNCTION__ , ## arg); \
21} while (0)
22#else
23#define DBG(format, arg...) /* */
24#endif
25
26enum {
27 CARD_DETECTED = 1,
28 CARD_LOADING = 2,
29 CARD_RUNNING = 3,
30};
31
32extern struct list_head capi_drivers;
33extern rwlock_t capi_drivers_list_lock;
34
35extern struct capi20_appl *capi_applications[CAPI_MAXAPPL];
36extern struct capi_ctr *capi_cards[CAPI_MAXCONTR];
37
38#ifdef CONFIG_PROC_FS
39
40void kcapi_proc_init(void);
41void kcapi_proc_exit(void);
42
43#else
44
45static inline void kcapi_proc_init(void) { };
46static inline void kcapi_proc_exit(void) { };
47
48#endif
49
diff --git a/drivers/isdn/capi/kcapi_proc.c b/drivers/isdn/capi/kcapi_proc.c
new file mode 100644
index 000000000000..16dc5418ff41
--- /dev/null
+++ b/drivers/isdn/capi/kcapi_proc.c
@@ -0,0 +1,336 @@
1/*
2 * Kernel CAPI 2.0 Module - /proc/capi handling
3 *
4 * Copyright 1999 by Carsten Paeth <calle@calle.de>
5 * Copyright 2002 by Kai Germaschewski <kai@germaschewski.name>
6 *
7 * This software may be used and distributed according to the terms
8 * of the GNU General Public License, incorporated herein by reference.
9 *
10 */
11
12
13#include "kcapi.h"
14#include <linux/proc_fs.h>
15#include <linux/seq_file.h>
16#include <linux/init.h>
17
18static char *
19cardstate2str(unsigned short cardstate)
20{
21 switch (cardstate) {
22 case CARD_DETECTED: return "detected";
23 case CARD_LOADING: return "loading";
24 case CARD_RUNNING: return "running";
25 default: return "???";
26 }
27}
28
29// /proc/capi
30// ===========================================================================
31
32// /proc/capi/controller:
33// cnr driver cardstate name driverinfo
34// /proc/capi/contrstats:
35// cnr nrecvctlpkt nrecvdatapkt nsentctlpkt nsentdatapkt
36// ---------------------------------------------------------------------------
37
38static void *controller_start(struct seq_file *seq, loff_t *pos)
39{
40 if (*pos < CAPI_MAXCONTR)
41 return &capi_cards[*pos];
42
43 return NULL;
44}
45
46static void *controller_next(struct seq_file *seq, void *v, loff_t *pos)
47{
48 ++*pos;
49 if (*pos < CAPI_MAXCONTR)
50 return &capi_cards[*pos];
51
52 return NULL;
53}
54
55static void controller_stop(struct seq_file *seq, void *v)
56{
57}
58
59static int controller_show(struct seq_file *seq, void *v)
60{
61 struct capi_ctr *ctr = *(struct capi_ctr **) v;
62
63 if (!ctr)
64 return 0;
65
66 seq_printf(seq, "%d %-10s %-8s %-16s %s\n",
67 ctr->cnr, ctr->driver_name,
68 cardstate2str(ctr->cardstate),
69 ctr->name,
70 ctr->procinfo ? ctr->procinfo(ctr) : "");
71
72 return 0;
73}
74
75static int contrstats_show(struct seq_file *seq, void *v)
76{
77 struct capi_ctr *ctr = *(struct capi_ctr **) v;
78
79 if (!ctr)
80 return 0;
81
82 seq_printf(seq, "%d %lu %lu %lu %lu\n",
83 ctr->cnr,
84 ctr->nrecvctlpkt,
85 ctr->nrecvdatapkt,
86 ctr->nsentctlpkt,
87 ctr->nsentdatapkt);
88
89 return 0;
90}
91
92struct seq_operations seq_controller_ops = {
93 .start = controller_start,
94 .next = controller_next,
95 .stop = controller_stop,
96 .show = controller_show,
97};
98
99struct seq_operations seq_contrstats_ops = {
100 .start = controller_start,
101 .next = controller_next,
102 .stop = controller_stop,
103 .show = contrstats_show,
104};
105
106static int seq_controller_open(struct inode *inode, struct file *file)
107{
108 return seq_open(file, &seq_controller_ops);
109}
110
111static int seq_contrstats_open(struct inode *inode, struct file *file)
112{
113 return seq_open(file, &seq_contrstats_ops);
114}
115
116static struct file_operations proc_controller_ops = {
117 .open = seq_controller_open,
118 .read = seq_read,
119 .llseek = seq_lseek,
120 .release = seq_release,
121};
122
123static struct file_operations proc_contrstats_ops = {
124 .open = seq_contrstats_open,
125 .read = seq_read,
126 .llseek = seq_lseek,
127 .release = seq_release,
128};
129
130// /proc/capi/applications:
131// applid l3cnt dblkcnt dblklen #ncci recvqueuelen
132// /proc/capi/applstats:
133// applid nrecvctlpkt nrecvdatapkt nsentctlpkt nsentdatapkt
134// ---------------------------------------------------------------------------
135
136static void *
137applications_start(struct seq_file *seq, loff_t *pos)
138{
139 if (*pos < CAPI_MAXAPPL)
140 return &capi_applications[*pos];
141
142 return NULL;
143}
144
145static void *
146applications_next(struct seq_file *seq, void *v, loff_t *pos)
147{
148 ++*pos;
149 if (*pos < CAPI_MAXAPPL)
150 return &capi_applications[*pos];
151
152 return NULL;
153}
154
155static void
156applications_stop(struct seq_file *seq, void *v)
157{
158}
159
160static int
161applications_show(struct seq_file *seq, void *v)
162{
163 struct capi20_appl *ap = *(struct capi20_appl **) v;
164
165 if (!ap)
166 return 0;
167
168 seq_printf(seq, "%u %d %d %d\n",
169 ap->applid,
170 ap->rparam.level3cnt,
171 ap->rparam.datablkcnt,
172 ap->rparam.datablklen);
173
174 return 0;
175}
176
177static int
178applstats_show(struct seq_file *seq, void *v)
179{
180 struct capi20_appl *ap = *(struct capi20_appl **) v;
181
182 if (!ap)
183 return 0;
184
185 seq_printf(seq, "%u %lu %lu %lu %lu\n",
186 ap->applid,
187 ap->nrecvctlpkt,
188 ap->nrecvdatapkt,
189 ap->nsentctlpkt,
190 ap->nsentdatapkt);
191
192 return 0;
193}
194
195struct seq_operations seq_applications_ops = {
196 .start = applications_start,
197 .next = applications_next,
198 .stop = applications_stop,
199 .show = applications_show,
200};
201
202struct seq_operations seq_applstats_ops = {
203 .start = applications_start,
204 .next = applications_next,
205 .stop = applications_stop,
206 .show = applstats_show,
207};
208
209static int
210seq_applications_open(struct inode *inode, struct file *file)
211{
212 return seq_open(file, &seq_applications_ops);
213}
214
215static int
216seq_applstats_open(struct inode *inode, struct file *file)
217{
218 return seq_open(file, &seq_applstats_ops);
219}
220
221static struct file_operations proc_applications_ops = {
222 .open = seq_applications_open,
223 .read = seq_read,
224 .llseek = seq_lseek,
225 .release = seq_release,
226};
227
228static struct file_operations proc_applstats_ops = {
229 .open = seq_applstats_open,
230 .read = seq_read,
231 .llseek = seq_lseek,
232 .release = seq_release,
233};
234
235static void
236create_seq_entry(char *name, mode_t mode, struct file_operations *f)
237{
238 struct proc_dir_entry *entry;
239 entry = create_proc_entry(name, mode, NULL);
240 if (entry)
241 entry->proc_fops = f;
242}
243
244// ---------------------------------------------------------------------------
245
246
247static __inline__ struct capi_driver *capi_driver_get_idx(loff_t pos)
248{
249 struct capi_driver *drv = NULL;
250 struct list_head *l;
251 loff_t i;
252
253 i = 0;
254 list_for_each(l, &capi_drivers) {
255 drv = list_entry(l, struct capi_driver, list);
256 if (i++ == pos)
257 return drv;
258 }
259 return NULL;
260}
261
262static void *capi_driver_start(struct seq_file *seq, loff_t *pos)
263{
264 struct capi_driver *drv;
265 read_lock(&capi_drivers_list_lock);
266 drv = capi_driver_get_idx(*pos);
267 return drv;
268}
269
270static void *capi_driver_next(struct seq_file *seq, void *v, loff_t *pos)
271{
272 struct capi_driver *drv = (struct capi_driver *)v;
273 ++*pos;
274 if (drv->list.next == &capi_drivers) return NULL;
275 return list_entry(drv->list.next, struct capi_driver, list);
276}
277
278static void capi_driver_stop(struct seq_file *seq, void *v)
279{
280 read_unlock(&capi_drivers_list_lock);
281}
282
283static int capi_driver_show(struct seq_file *seq, void *v)
284{
285 struct capi_driver *drv = (struct capi_driver *)v;
286 seq_printf(seq, "%-32s %s\n", drv->name, drv->revision);
287 return 0;
288}
289
290struct seq_operations seq_capi_driver_ops = {
291 .start = capi_driver_start,
292 .next = capi_driver_next,
293 .stop = capi_driver_stop,
294 .show = capi_driver_show,
295};
296
297static int
298seq_capi_driver_open(struct inode *inode, struct file *file)
299{
300 int err;
301 err = seq_open(file, &seq_capi_driver_ops);
302 return err;
303}
304
305static struct file_operations proc_driver_ops = {
306 .open = seq_capi_driver_open,
307 .read = seq_read,
308 .llseek = seq_lseek,
309 .release = seq_release,
310};
311
312// ---------------------------------------------------------------------------
313
314void __init
315kcapi_proc_init(void)
316{
317 proc_mkdir("capi", NULL);
318 proc_mkdir("capi/controllers", NULL);
319 create_seq_entry("capi/controller", 0, &proc_controller_ops);
320 create_seq_entry("capi/contrstats", 0, &proc_contrstats_ops);
321 create_seq_entry("capi/applications", 0, &proc_applications_ops);
322 create_seq_entry("capi/applstats", 0, &proc_applstats_ops);
323 create_seq_entry("capi/driver", 0, &proc_driver_ops);
324}
325
326void __exit
327kcapi_proc_exit(void)
328{
329 remove_proc_entry("capi/driver", NULL);
330 remove_proc_entry("capi/controller", NULL);
331 remove_proc_entry("capi/contrstats", NULL);
332 remove_proc_entry("capi/applications", NULL);
333 remove_proc_entry("capi/applstats", NULL);
334 remove_proc_entry("capi/controllers", NULL);
335 remove_proc_entry("capi", NULL);
336}
diff --git a/drivers/isdn/divert/Makefile b/drivers/isdn/divert/Makefile
new file mode 100644
index 000000000000..dd4a202e0bc2
--- /dev/null
+++ b/drivers/isdn/divert/Makefile
@@ -0,0 +1,9 @@
1# Makefile for the dss1_divert ISDN module
2
3# Each configuration option enables a list of files.
4
5obj-$(CONFIG_ISDN_DIVERSION) += dss1_divert.o
6
7# Multipart objects.
8
9dss1_divert-y := isdn_divert.o divert_procfs.o divert_init.o
diff --git a/drivers/isdn/divert/divert_init.c b/drivers/isdn/divert/divert_init.c
new file mode 100644
index 000000000000..434e684f5dbb
--- /dev/null
+++ b/drivers/isdn/divert/divert_init.c
@@ -0,0 +1,83 @@
1/* $Id divert_init.c,v 1.5.6.2 2001/01/24 22:18:17 kai Exp $
2 *
3 * Module init for DSS1 diversion services for i4l.
4 *
5 * Copyright 1999 by Werner Cornelius (werner@isdn4linux.de)
6 *
7 * This software may be used and distributed according to the terms
8 * of the GNU General Public License, incorporated herein by reference.
9 *
10 */
11
12#include <linux/module.h>
13#include <linux/version.h>
14#include <linux/init.h>
15#include <linux/kernel.h>
16
17#include "isdn_divert.h"
18
19MODULE_DESCRIPTION("ISDN4Linux: Call diversion support");
20MODULE_AUTHOR("Werner Cornelius");
21MODULE_LICENSE("GPL");
22
23/****************************************/
24/* structure containing interface to hl */
25/****************************************/
26isdn_divert_if divert_if =
27 { DIVERT_IF_MAGIC, /* magic value */
28 DIVERT_CMD_REG, /* register cmd */
29 ll_callback, /* callback routine from ll */
30 NULL, /* command still not specified */
31 NULL, /* drv_to_name */
32 NULL, /* name_to_drv */
33 };
34
35/*************************/
36/* Module interface code */
37/* no cmd line parms */
38/*************************/
39static int __init divert_init(void)
40{ int i;
41
42 if (divert_dev_init())
43 { printk(KERN_WARNING "dss1_divert: cannot install device, not loaded\n");
44 return(-EIO);
45 }
46 if ((i = DIVERT_REG_NAME(&divert_if)) != DIVERT_NO_ERR)
47 { divert_dev_deinit();
48 printk(KERN_WARNING "dss1_divert: error %d registering module, not loaded\n",i);
49 return(-EIO);
50 }
51 printk(KERN_INFO "dss1_divert module successfully installed\n");
52 return(0);
53}
54
55/**********************/
56/* Module deinit code */
57/**********************/
58static void __exit divert_exit(void)
59{
60 unsigned long flags;
61 int i;
62
63 spin_lock_irqsave(&divert_lock, flags);
64 divert_if.cmd = DIVERT_CMD_REL; /* release */
65 if ((i = DIVERT_REG_NAME(&divert_if)) != DIVERT_NO_ERR)
66 { printk(KERN_WARNING "dss1_divert: error %d releasing module\n",i);
67 spin_unlock_irqrestore(&divert_lock, flags);
68 return;
69 }
70 if (divert_dev_deinit())
71 { printk(KERN_WARNING "dss1_divert: device busy, remove cancelled\n");
72 spin_unlock_irqrestore(&divert_lock, flags);
73 return;
74 }
75 spin_unlock_irqrestore(&divert_lock, flags);
76 deleterule(-1); /* delete all rules and free mem */
77 deleteprocs();
78 printk(KERN_INFO "dss1_divert module successfully removed \n");
79}
80
81module_init(divert_init);
82module_exit(divert_exit);
83
diff --git a/drivers/isdn/divert/divert_procfs.c b/drivers/isdn/divert/divert_procfs.c
new file mode 100644
index 000000000000..e1f0d87de0eb
--- /dev/null
+++ b/drivers/isdn/divert/divert_procfs.c
@@ -0,0 +1,319 @@
1/* $Id: divert_procfs.c,v 1.11.6.2 2001/09/23 22:24:36 kai Exp $
2 *
3 * Filesystem handling for the diversion supplementary services.
4 *
5 * Copyright 1998 by Werner Cornelius (werner@isdn4linux.de)
6 *
7 * This software may be used and distributed according to the terms
8 * of the GNU General Public License, incorporated herein by reference.
9 *
10 */
11
12#include <linux/config.h>
13#include <linux/module.h>
14#include <linux/version.h>
15#include <linux/poll.h>
16#include <linux/smp_lock.h>
17#ifdef CONFIG_PROC_FS
18#include <linux/proc_fs.h>
19#else
20#include <linux/fs.h>
21#endif
22#include <linux/isdnif.h>
23#include "isdn_divert.h"
24
25
26/*********************************/
27/* Variables for interface queue */
28/*********************************/
29ulong if_used = 0; /* number of interface users */
30static struct divert_info *divert_info_head = NULL; /* head of queue */
31static struct divert_info *divert_info_tail = NULL; /* pointer to last entry */
32static DEFINE_SPINLOCK(divert_info_lock);/* lock for queue */
33static wait_queue_head_t rd_queue;
34
35/*********************************/
36/* put an info buffer into queue */
37/*********************************/
38void
39put_info_buffer(char *cp)
40{
41 struct divert_info *ib;
42 unsigned long flags;
43
44 if (if_used <= 0)
45 return;
46 if (!cp)
47 return;
48 if (!*cp)
49 return;
50 if (!(ib = (struct divert_info *) kmalloc(sizeof(struct divert_info) + strlen(cp), GFP_ATOMIC)))
51 return; /* no memory */
52 strcpy(ib->info_start, cp); /* set output string */
53 ib->next = NULL;
54 spin_lock_irqsave( &divert_info_lock, flags );
55 ib->usage_cnt = if_used;
56 if (!divert_info_head)
57 divert_info_head = ib; /* new head */
58 else
59 divert_info_tail->next = ib; /* follows existing messages */
60 divert_info_tail = ib; /* new tail */
61
62 /* delete old entrys */
63 while (divert_info_head->next) {
64 if ((divert_info_head->usage_cnt <= 0) &&
65 (divert_info_head->next->usage_cnt <= 0)) {
66 ib = divert_info_head;
67 divert_info_head = divert_info_head->next;
68 kfree(ib);
69 } else
70 break;
71 } /* divert_info_head->next */
72 spin_unlock_irqrestore( &divert_info_lock, flags );
73 wake_up_interruptible(&(rd_queue));
74} /* put_info_buffer */
75
76/**********************************/
77/* deflection device read routine */
78/**********************************/
79static ssize_t
80isdn_divert_read(struct file *file, char __user *buf, size_t count, loff_t * off)
81{
82 struct divert_info *inf;
83 int len;
84
85 if (!*((struct divert_info **) file->private_data)) {
86 if (file->f_flags & O_NONBLOCK)
87 return -EAGAIN;
88 interruptible_sleep_on(&(rd_queue));
89 }
90 if (!(inf = *((struct divert_info **) file->private_data)))
91 return (0);
92
93 inf->usage_cnt--; /* new usage count */
94 file->private_data = &inf->next; /* next structure */
95 if ((len = strlen(inf->info_start)) <= count) {
96 if (copy_to_user(buf, inf->info_start, len))
97 return -EFAULT;
98 *off += len;
99 return (len);
100 }
101 return (0);
102} /* isdn_divert_read */
103
104/**********************************/
105/* deflection device write routine */
106/**********************************/
107static ssize_t
108isdn_divert_write(struct file *file, const char __user *buf, size_t count, loff_t * off)
109{
110 return (-ENODEV);
111} /* isdn_divert_write */
112
113
114/***************************************/
115/* select routines for various kernels */
116/***************************************/
117static unsigned int
118isdn_divert_poll(struct file *file, poll_table * wait)
119{
120 unsigned int mask = 0;
121
122 poll_wait(file, &(rd_queue), wait);
123 /* mask = POLLOUT | POLLWRNORM; */
124 if (*((struct divert_info **) file->private_data)) {
125 mask |= POLLIN | POLLRDNORM;
126 }
127 return mask;
128} /* isdn_divert_poll */
129
130/****************/
131/* Open routine */
132/****************/
133static int
134isdn_divert_open(struct inode *ino, struct file *filep)
135{
136 unsigned long flags;
137
138 spin_lock_irqsave( &divert_info_lock, flags );
139 if_used++;
140 if (divert_info_head)
141 filep->private_data = &(divert_info_tail->next);
142 else
143 filep->private_data = &divert_info_head;
144 spin_unlock_irqrestore( &divert_info_lock, flags );
145 /* start_divert(); */
146 return nonseekable_open(ino, filep);
147} /* isdn_divert_open */
148
149/*******************/
150/* close routine */
151/*******************/
152static int
153isdn_divert_close(struct inode *ino, struct file *filep)
154{
155 struct divert_info *inf;
156 unsigned long flags;
157
158 spin_lock_irqsave( &divert_info_lock, flags );
159 if_used--;
160 inf = *((struct divert_info **) filep->private_data);
161 while (inf) {
162 inf->usage_cnt--;
163 inf = inf->next;
164 }
165 if (if_used <= 0)
166 while (divert_info_head) {
167 inf = divert_info_head;
168 divert_info_head = divert_info_head->next;
169 kfree(inf);
170 }
171 spin_unlock_irqrestore( &divert_info_lock, flags );
172 return (0);
173} /* isdn_divert_close */
174
175/*********/
176/* IOCTL */
177/*********/
178static int
179isdn_divert_ioctl(struct inode *inode, struct file *file,
180 uint cmd, ulong arg)
181{
182 divert_ioctl dioctl;
183 int i;
184 unsigned long flags;
185 divert_rule *rulep;
186 char *cp;
187
188 if (copy_from_user(&dioctl, (void __user *) arg, sizeof(dioctl)))
189 return -EFAULT;
190
191 switch (cmd) {
192 case IIOCGETVER:
193 dioctl.drv_version = DIVERT_IIOC_VERSION; /* set version */
194 break;
195
196 case IIOCGETDRV:
197 if ((dioctl.getid.drvid = divert_if.name_to_drv(dioctl.getid.drvnam)) < 0)
198 return (-EINVAL);
199 break;
200
201 case IIOCGETNAM:
202 cp = divert_if.drv_to_name(dioctl.getid.drvid);
203 if (!cp)
204 return (-EINVAL);
205 if (!*cp)
206 return (-EINVAL);
207 strcpy(dioctl.getid.drvnam, cp);
208 break;
209
210 case IIOCGETRULE:
211 if (!(rulep = getruleptr(dioctl.getsetrule.ruleidx)))
212 return (-EINVAL);
213 dioctl.getsetrule.rule = *rulep; /* copy data */
214 break;
215
216 case IIOCMODRULE:
217 if (!(rulep = getruleptr(dioctl.getsetrule.ruleidx)))
218 return (-EINVAL);
219 spin_lock_irqsave(&divert_lock, flags);
220 *rulep = dioctl.getsetrule.rule; /* copy data */
221 spin_unlock_irqrestore(&divert_lock, flags);
222 return (0); /* no copy required */
223 break;
224
225 case IIOCINSRULE:
226 return (insertrule(dioctl.getsetrule.ruleidx, &dioctl.getsetrule.rule));
227 break;
228
229 case IIOCDELRULE:
230 return (deleterule(dioctl.getsetrule.ruleidx));
231 break;
232
233 case IIOCDODFACT:
234 return (deflect_extern_action(dioctl.fwd_ctrl.subcmd,
235 dioctl.fwd_ctrl.callid,
236 dioctl.fwd_ctrl.to_nr));
237
238 case IIOCDOCFACT:
239 case IIOCDOCFDIS:
240 case IIOCDOCFINT:
241 if (!divert_if.drv_to_name(dioctl.cf_ctrl.drvid))
242 return (-EINVAL); /* invalid driver */
243 if ((i = cf_command(dioctl.cf_ctrl.drvid,
244 (cmd == IIOCDOCFACT) ? 1 : (cmd == IIOCDOCFDIS) ? 0 : 2,
245 dioctl.cf_ctrl.cfproc,
246 dioctl.cf_ctrl.msn,
247 dioctl.cf_ctrl.service,
248 dioctl.cf_ctrl.fwd_nr,
249 &dioctl.cf_ctrl.procid)))
250 return (i);
251 break;
252
253 default:
254 return (-EINVAL);
255 } /* switch cmd */
256 return copy_to_user((void __user *)arg, &dioctl, sizeof(dioctl)) ? -EFAULT : 0;
257} /* isdn_divert_ioctl */
258
259
260#ifdef CONFIG_PROC_FS
261static struct file_operations isdn_fops =
262{
263 .owner = THIS_MODULE,
264 .llseek = no_llseek,
265 .read = isdn_divert_read,
266 .write = isdn_divert_write,
267 .poll = isdn_divert_poll,
268 .ioctl = isdn_divert_ioctl,
269 .open = isdn_divert_open,
270 .release = isdn_divert_close,
271};
272
273/****************************/
274/* isdn subdir in /proc/net */
275/****************************/
276static struct proc_dir_entry *isdn_proc_entry = NULL;
277static struct proc_dir_entry *isdn_divert_entry = NULL;
278#endif /* CONFIG_PROC_FS */
279
280/***************************************************************************/
281/* divert_dev_init must be called before the proc filesystem may be used */
282/***************************************************************************/
283int
284divert_dev_init(void)
285{
286
287 init_waitqueue_head(&rd_queue);
288
289#ifdef CONFIG_PROC_FS
290 isdn_proc_entry = create_proc_entry("isdn", S_IFDIR | S_IRUGO | S_IXUGO, proc_net);
291 if (!isdn_proc_entry)
292 return (-1);
293 isdn_divert_entry = create_proc_entry("divert", S_IFREG | S_IRUGO, isdn_proc_entry);
294 if (!isdn_divert_entry) {
295 remove_proc_entry("isdn", proc_net);
296 return (-1);
297 }
298 isdn_divert_entry->proc_fops = &isdn_fops;
299 isdn_divert_entry->owner = THIS_MODULE;
300#endif /* CONFIG_PROC_FS */
301
302 return (0);
303} /* divert_dev_init */
304
305/***************************************************************************/
306/* divert_dev_deinit must be called before leaving isdn when included as */
307/* a module. */
308/***************************************************************************/
309int
310divert_dev_deinit(void)
311{
312
313#ifdef CONFIG_PROC_FS
314 remove_proc_entry("divert", isdn_proc_entry);
315 remove_proc_entry("isdn", proc_net);
316#endif /* CONFIG_PROC_FS */
317
318 return (0);
319} /* divert_dev_deinit */
diff --git a/drivers/isdn/divert/isdn_divert.c b/drivers/isdn/divert/isdn_divert.c
new file mode 100644
index 000000000000..1eb112213f0c
--- /dev/null
+++ b/drivers/isdn/divert/isdn_divert.c
@@ -0,0 +1,861 @@
1/* $Id: isdn_divert.c,v 1.6.6.3 2001/09/23 22:24:36 kai Exp $
2 *
3 * DSS1 main diversion supplementary handling for i4l.
4 *
5 * Copyright 1999 by Werner Cornelius (werner@isdn4linux.de)
6 *
7 * This software may be used and distributed according to the terms
8 * of the GNU General Public License, incorporated herein by reference.
9 *
10 */
11
12#include <linux/version.h>
13#include <linux/proc_fs.h>
14
15#include "isdn_divert.h"
16
17/**********************************/
18/* structure keeping calling info */
19/**********************************/
20struct call_struc
21 { isdn_ctrl ics; /* delivered setup + driver parameters */
22 ulong divert_id; /* Id delivered to user */
23 unsigned char akt_state; /* actual state */
24 char deflect_dest[35]; /* deflection destination */
25 struct timer_list timer; /* timer control structure */
26 char info[90]; /* device info output */
27 struct call_struc *next; /* pointer to next entry */
28 struct call_struc *prev;
29 };
30
31
32/********************************************/
33/* structure keeping deflection table entry */
34/********************************************/
35struct deflect_struc
36 { struct deflect_struc *next,*prev;
37 divert_rule rule; /* used rule */
38 };
39
40
41/*****************************************/
42/* variables for main diversion services */
43/*****************************************/
44/* diversion/deflection processes */
45static struct call_struc *divert_head = NULL; /* head of remembered entrys */
46static ulong next_id = 1; /* next info id */
47static struct deflect_struc *table_head = NULL;
48static struct deflect_struc *table_tail = NULL;
49static unsigned char extern_wait_max = 4; /* maximum wait in s for external process */
50
51DEFINE_SPINLOCK(divert_lock);
52
53/***************************/
54/* timer callback function */
55/***************************/
56static void deflect_timer_expire(ulong arg)
57{
58 unsigned long flags;
59 struct call_struc *cs = (struct call_struc *) arg;
60
61 spin_lock_irqsave(&divert_lock, flags);
62 del_timer(&cs->timer); /* delete active timer */
63 spin_unlock_irqrestore(&divert_lock, flags);
64
65 switch(cs->akt_state)
66 { case DEFLECT_PROCEED:
67 cs->ics.command = ISDN_CMD_HANGUP; /* cancel action */
68 divert_if.ll_cmd(&cs->ics);
69 spin_lock_irqsave(&divert_lock, flags);
70 cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
71 cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
72 add_timer(&cs->timer);
73 spin_unlock_irqrestore(&divert_lock, flags);
74 break;
75
76 case DEFLECT_ALERT:
77 cs->ics.command = ISDN_CMD_REDIR; /* protocol */
78 strcpy(cs->ics.parm.setup.phone,cs->deflect_dest);
79 strcpy(cs->ics.parm.setup.eazmsn,"Testtext delayed");
80 divert_if.ll_cmd(&cs->ics);
81 spin_lock_irqsave(&divert_lock, flags);
82 cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
83 cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
84 add_timer(&cs->timer);
85 spin_unlock_irqrestore(&divert_lock, flags);
86 break;
87
88 case DEFLECT_AUTODEL:
89 default:
90 spin_lock_irqsave(&divert_lock, flags);
91 if (cs->prev)
92 cs->prev->next = cs->next; /* forward link */
93 else
94 divert_head = cs->next;
95 if (cs->next)
96 cs->next->prev = cs->prev; /* back link */
97 spin_unlock_irqrestore(&divert_lock, flags);
98 kfree(cs);
99 return;
100
101 } /* switch */
102} /* deflect_timer_func */
103
104
105/*****************************************/
106/* handle call forwarding de/activations */
107/* 0 = deact, 1 = act, 2 = interrogate */
108/*****************************************/
109int cf_command(int drvid, int mode,
110 u_char proc, char *msn,
111 u_char service, char *fwd_nr, ulong *procid)
112{ unsigned long flags;
113 int retval,msnlen;
114 int fwd_len;
115 char *p,*ielenp,tmp[60];
116 struct call_struc *cs;
117
118 if (strchr(msn,'.')) return(-EINVAL); /* subaddress not allowed in msn */
119 if ((proc & 0x7F) > 2) return(-EINVAL);
120 proc &= 3;
121 p = tmp;
122 *p++ = 0x30; /* enumeration */
123 ielenp = p++; /* remember total length position */
124 *p++ = 0xa; /* proc tag */
125 *p++ = 1; /* length */
126 *p++ = proc & 0x7F; /* procedure to de/activate/interrogate */
127 *p++ = 0xa; /* service tag */
128 *p++ = 1; /* length */
129 *p++ = service; /* service to handle */
130
131 if (mode == 1)
132 { if (!*fwd_nr) return(-EINVAL); /* destination missing */
133 if (strchr(fwd_nr,'.')) return(-EINVAL); /* subaddress not allowed */
134 fwd_len = strlen(fwd_nr);
135 *p++ = 0x30; /* number enumeration */
136 *p++ = fwd_len + 2; /* complete forward to len */
137 *p++ = 0x80; /* fwd to nr */
138 *p++ = fwd_len; /* length of number */
139 strcpy(p,fwd_nr); /* copy number */
140 p += fwd_len; /* pointer beyond fwd */
141 } /* activate */
142
143 msnlen = strlen(msn);
144 *p++ = 0x80; /* msn number */
145 if (msnlen > 1)
146 { *p++ = msnlen; /* length */
147 strcpy(p,msn);
148 p += msnlen;
149 }
150 else *p++ = 0;
151
152 *ielenp = p - ielenp - 1; /* set total IE length */
153
154 /* allocate mem for information struct */
155 if (!(cs = (struct call_struc *) kmalloc(sizeof(struct call_struc), GFP_ATOMIC)))
156 return(-ENOMEM); /* no memory */
157 init_timer(&cs->timer);
158 cs->info[0] = '\0';
159 cs->timer.function = deflect_timer_expire;
160 cs->timer.data = (ulong) cs; /* pointer to own structure */
161 cs->ics.driver = drvid;
162 cs->ics.command = ISDN_CMD_PROT_IO; /* protocol specific io */
163 cs->ics.arg = DSS1_CMD_INVOKE; /* invoke supplementary service */
164 cs->ics.parm.dss1_io.proc = (mode == 1) ? 7: (mode == 2) ? 11:8; /* operation */
165 cs->ics.parm.dss1_io.timeout = 4000; /* from ETS 300 207-1 */
166 cs->ics.parm.dss1_io.datalen = p - tmp; /* total len */
167 cs->ics.parm.dss1_io.data = tmp; /* start of buffer */
168
169 spin_lock_irqsave(&divert_lock, flags);
170 cs->ics.parm.dss1_io.ll_id = next_id++; /* id for callback */
171 spin_unlock_irqrestore(&divert_lock, flags);
172 *procid = cs->ics.parm.dss1_io.ll_id;
173
174 sprintf(cs->info,"%d 0x%lx %s%s 0 %s %02x %d%s%s\n",
175 (!mode ) ? DIVERT_DEACTIVATE : (mode == 1) ? DIVERT_ACTIVATE : DIVERT_REPORT,
176 cs->ics.parm.dss1_io.ll_id,
177 (mode != 2) ? "" : "0 ",
178 divert_if.drv_to_name(cs->ics.driver),
179 msn,
180 service & 0xFF,
181 proc,
182 (mode != 1) ? "" : " 0 ",
183 (mode != 1) ? "" : fwd_nr);
184
185 retval = divert_if.ll_cmd(&cs->ics); /* excute command */
186
187 if (!retval)
188 { cs->prev = NULL;
189 spin_lock_irqsave(&divert_lock, flags);
190 cs->next = divert_head;
191 divert_head = cs;
192 spin_unlock_irqrestore(&divert_lock, flags);
193 }
194 else
195 kfree(cs);
196 return(retval);
197} /* cf_command */
198
199
200/****************************************/
201/* handle a external deflection command */
202/****************************************/
203int deflect_extern_action(u_char cmd, ulong callid, char *to_nr)
204{ struct call_struc *cs;
205 isdn_ctrl ic;
206 unsigned long flags;
207 int i;
208
209 if ((cmd & 0x7F) > 2) return(-EINVAL); /* invalid command */
210 cs = divert_head; /* start of parameter list */
211 while (cs)
212 { if (cs->divert_id == callid) break; /* found */
213 cs = cs->next;
214 } /* search entry */
215 if (!cs) return(-EINVAL); /* invalid callid */
216
217 ic.driver = cs->ics.driver;
218 ic.arg = cs->ics.arg;
219 i = -EINVAL;
220 if (cs->akt_state == DEFLECT_AUTODEL) return(i); /* no valid call */
221 switch (cmd & 0x7F)
222 { case 0: /* hangup */
223 del_timer(&cs->timer);
224 ic.command = ISDN_CMD_HANGUP;
225 i = divert_if.ll_cmd(&ic);
226 spin_lock_irqsave(&divert_lock, flags);
227 cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
228 cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
229 add_timer(&cs->timer);
230 spin_unlock_irqrestore(&divert_lock, flags);
231 break;
232
233 case 1: /* alert */
234 if (cs->akt_state == DEFLECT_ALERT) return(0);
235 cmd &= 0x7F; /* never wait */
236 del_timer(&cs->timer);
237 ic.command = ISDN_CMD_ALERT;
238 if ((i = divert_if.ll_cmd(&ic)))
239 {
240 spin_lock_irqsave(&divert_lock, flags);
241 cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
242 cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
243 add_timer(&cs->timer);
244 spin_unlock_irqrestore(&divert_lock, flags);
245 }
246 else
247 cs->akt_state = DEFLECT_ALERT;
248 break;
249
250 case 2: /* redir */
251 del_timer(&cs->timer);
252 strcpy(cs->ics.parm.setup.phone, to_nr);
253 strcpy(cs->ics.parm.setup.eazmsn, "Testtext manual");
254 ic.command = ISDN_CMD_REDIR;
255 if ((i = divert_if.ll_cmd(&ic)))
256 {
257 spin_lock_irqsave(&divert_lock, flags);
258 cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
259 cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
260 add_timer(&cs->timer);
261 spin_unlock_irqrestore(&divert_lock, flags);
262 }
263 else
264 cs->akt_state = DEFLECT_ALERT;
265 break;
266
267 } /* switch */
268 return(i);
269} /* deflect_extern_action */
270
271/********************************/
272/* insert a new rule before idx */
273/********************************/
274int insertrule(int idx, divert_rule *newrule)
275{ struct deflect_struc *ds,*ds1=NULL;
276 unsigned long flags;
277
278 if (!(ds = (struct deflect_struc *) kmalloc(sizeof(struct deflect_struc),
279 GFP_KERNEL)))
280 return(-ENOMEM); /* no memory */
281
282 ds->rule = *newrule; /* set rule */
283
284 spin_lock_irqsave(&divert_lock, flags);
285
286 if (idx >= 0)
287 { ds1 = table_head;
288 while ((ds1) && (idx > 0))
289 { idx--;
290 ds1 = ds1->next;
291 }
292 if (!ds1) idx = -1;
293 }
294
295 if (idx < 0)
296 { ds->prev = table_tail; /* previous entry */
297 ds->next = NULL; /* end of chain */
298 if (ds->prev)
299 ds->prev->next = ds; /* last forward */
300 else
301 table_head = ds; /* is first entry */
302 table_tail = ds; /* end of queue */
303 }
304 else
305 { ds->next = ds1; /* next entry */
306 ds->prev = ds1->prev; /* prev entry */
307 ds1->prev = ds; /* backward chain old element */
308 if (!ds->prev)
309 table_head = ds; /* first element */
310 }
311
312 spin_unlock_irqrestore(&divert_lock, flags);
313 return(0);
314} /* insertrule */
315
316/***********************************/
317/* delete the rule at position idx */
318/***********************************/
319int deleterule(int idx)
320{ struct deflect_struc *ds,*ds1;
321 unsigned long flags;
322
323 if (idx < 0)
324 { spin_lock_irqsave(&divert_lock, flags);
325 ds = table_head;
326 table_head = NULL;
327 table_tail = NULL;
328 spin_unlock_irqrestore(&divert_lock, flags);
329 while (ds)
330 { ds1 = ds;
331 ds = ds->next;
332 kfree(ds1);
333 }
334 return(0);
335 }
336
337 spin_lock_irqsave(&divert_lock, flags);
338 ds = table_head;
339
340 while ((ds) && (idx > 0))
341 { idx--;
342 ds = ds->next;
343 }
344
345 if (!ds)
346 {
347 spin_unlock_irqrestore(&divert_lock, flags);
348 return(-EINVAL);
349 }
350
351 if (ds->next)
352 ds->next->prev = ds->prev; /* backward chain */
353 else
354 table_tail = ds->prev; /* end of chain */
355
356 if (ds->prev)
357 ds->prev->next = ds->next; /* forward chain */
358 else
359 table_head = ds->next; /* start of chain */
360
361 spin_unlock_irqrestore(&divert_lock, flags);
362 kfree(ds);
363 return(0);
364} /* deleterule */
365
366/*******************************************/
367/* get a pointer to a specific rule number */
368/*******************************************/
369divert_rule *getruleptr(int idx)
370{ struct deflect_struc *ds = table_head;
371
372 if (idx < 0) return(NULL);
373 while ((ds) && (idx >= 0))
374 { if (!(idx--))
375 { return(&ds->rule);
376 break;
377 }
378 ds = ds->next;
379 }
380 return(NULL);
381} /* getruleptr */
382
383/*************************************************/
384/* called from common module on an incoming call */
385/*************************************************/
386int isdn_divert_icall(isdn_ctrl *ic)
387{ int retval = 0;
388 unsigned long flags;
389 struct call_struc *cs = NULL;
390 struct deflect_struc *dv;
391 char *p,*p1;
392 u_char accept;
393
394 /* first check the internal deflection table */
395 for (dv = table_head; dv ; dv = dv->next )
396 { /* scan table */
397 if (((dv->rule.callopt == 1) && (ic->command == ISDN_STAT_ICALLW)) ||
398 ((dv->rule.callopt == 2) && (ic->command == ISDN_STAT_ICALL)))
399 continue; /* call option check */
400 if (!(dv->rule.drvid & (1L << ic->driver)))
401 continue; /* driver not matching */
402 if ((dv->rule.si1) && (dv->rule.si1 != ic->parm.setup.si1))
403 continue; /* si1 not matching */
404 if ((dv->rule.si2) && (dv->rule.si2 != ic->parm.setup.si2))
405 continue; /* si2 not matching */
406
407 p = dv->rule.my_msn;
408 p1 = ic->parm.setup.eazmsn;
409 accept = 0;
410 while (*p)
411 { /* complete compare */
412 if (*p == '-')
413 { accept = 1; /* call accepted */
414 break;
415 }
416 if (*p++ != *p1++)
417 break; /* not accepted */
418 if ((!*p) && (!*p1))
419 accept = 1;
420 } /* complete compare */
421 if (!accept) continue; /* not accepted */
422
423 if ((strcmp(dv->rule.caller,"0")) || (ic->parm.setup.phone[0]))
424 { p = dv->rule.caller;
425 p1 = ic->parm.setup.phone;
426 accept = 0;
427 while (*p)
428 { /* complete compare */
429 if (*p == '-')
430 { accept = 1; /* call accepted */
431 break;
432 }
433 if (*p++ != *p1++)
434 break; /* not accepted */
435 if ((!*p) && (!*p1))
436 accept = 1;
437 } /* complete compare */
438 if (!accept) continue; /* not accepted */
439 }
440
441 switch (dv->rule.action)
442 { case DEFLECT_IGNORE:
443 return(0);
444 break;
445
446 case DEFLECT_ALERT:
447 case DEFLECT_PROCEED:
448 case DEFLECT_REPORT:
449 case DEFLECT_REJECT:
450 if (dv->rule.action == DEFLECT_PROCEED)
451 if ((!if_used) || ((!extern_wait_max) && (!dv->rule.waittime)))
452 return(0); /* no external deflection needed */
453 if (!(cs = (struct call_struc *) kmalloc(sizeof(struct call_struc), GFP_ATOMIC)))
454 return(0); /* no memory */
455 init_timer(&cs->timer);
456 cs->info[0] = '\0';
457 cs->timer.function = deflect_timer_expire;
458 cs->timer.data = (ulong) cs; /* pointer to own structure */
459
460 cs->ics = *ic; /* copy incoming data */
461 if (!cs->ics.parm.setup.phone[0]) strcpy(cs->ics.parm.setup.phone,"0");
462 if (!cs->ics.parm.setup.eazmsn[0]) strcpy(cs->ics.parm.setup.eazmsn,"0");
463 cs->ics.parm.setup.screen = dv->rule.screen;
464 if (dv->rule.waittime)
465 cs->timer.expires = jiffies + (HZ * dv->rule.waittime);
466 else
467 if (dv->rule.action == DEFLECT_PROCEED)
468 cs->timer.expires = jiffies + (HZ * extern_wait_max);
469 else
470 cs->timer.expires = 0;
471 cs->akt_state = dv->rule.action;
472 spin_lock_irqsave(&divert_lock, flags);
473 cs->divert_id = next_id++; /* new sequence number */
474 spin_unlock_irqrestore(&divert_lock, flags);
475 cs->prev = NULL;
476 if (cs->akt_state == DEFLECT_ALERT)
477 { strcpy(cs->deflect_dest,dv->rule.to_nr);
478 if (!cs->timer.expires)
479 { strcpy(ic->parm.setup.eazmsn,"Testtext direct");
480 ic->parm.setup.screen = dv->rule.screen;
481 strcpy(ic->parm.setup.phone,dv->rule.to_nr);
482 cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
483 cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
484 retval = 5;
485 }
486 else
487 retval = 1; /* alerting */
488 }
489 else
490 { cs->deflect_dest[0] = '\0';
491 retval = 4; /* only proceed */
492 }
493 sprintf(cs->info,"%d 0x%lx %s %s %s %s 0x%x 0x%x %d %d %s\n",
494 cs->akt_state,
495 cs->divert_id,
496 divert_if.drv_to_name(cs->ics.driver),
497 (ic->command == ISDN_STAT_ICALLW) ? "1":"0",
498 cs->ics.parm.setup.phone,
499 cs->ics.parm.setup.eazmsn,
500 cs->ics.parm.setup.si1,
501 cs->ics.parm.setup.si2,
502 cs->ics.parm.setup.screen,
503 dv->rule.waittime,
504 cs->deflect_dest);
505 if ((dv->rule.action == DEFLECT_REPORT) ||
506 (dv->rule.action == DEFLECT_REJECT))
507 { put_info_buffer(cs->info);
508 kfree(cs); /* remove */
509 return((dv->rule.action == DEFLECT_REPORT) ? 0:2); /* nothing to do */
510 }
511 break;
512
513 default:
514 return(0); /* ignore call */
515 break;
516 } /* switch action */
517 break;
518 } /* scan_table */
519
520 if (cs)
521 { cs->prev = NULL;
522 spin_lock_irqsave(&divert_lock, flags);
523 cs->next = divert_head;
524 divert_head = cs;
525 if (cs->timer.expires) add_timer(&cs->timer);
526 spin_unlock_irqrestore(&divert_lock, flags);
527
528 put_info_buffer(cs->info);
529 return(retval);
530 }
531 else
532 return(0);
533} /* isdn_divert_icall */
534
535
536void deleteprocs(void)
537{ struct call_struc *cs, *cs1;
538 unsigned long flags;
539
540 spin_lock_irqsave(&divert_lock, flags);
541 cs = divert_head;
542 divert_head = NULL;
543 while (cs)
544 { del_timer(&cs->timer);
545 cs1 = cs;
546 cs = cs->next;
547 kfree(cs1);
548 }
549 spin_unlock_irqrestore(&divert_lock, flags);
550} /* deleteprocs */
551
552/****************************************************/
553/* put a address including address type into buffer */
554/****************************************************/
555int put_address(char *st, u_char *p, int len)
556{ u_char retval = 0;
557 u_char adr_typ = 0; /* network standard */
558
559 if (len < 2) return(retval);
560 if (*p == 0xA1)
561 { retval = *(++p) + 2; /* total length */
562 if (retval > len) return(0); /* too short */
563 len = retval - 2; /* remaining length */
564 if (len < 3) return(0);
565 if ((*(++p) != 0x0A) || (*(++p) != 1)) return(0);
566 adr_typ = *(++p);
567 len -= 3;
568 p++;
569 if (len < 2) return(0);
570 if (*p++ != 0x12) return(0);
571 if (*p > len) return(0); /* check number length */
572 len = *p++;
573 }
574 else
575 if (*p == 0x80)
576 { retval = *(++p) + 2; /* total length */
577 if (retval > len) return(0);
578 len = retval - 2;
579 p++;
580 }
581 else
582 return(0); /* invalid address information */
583
584 sprintf(st,"%d ",adr_typ);
585 st += strlen(st);
586 if (!len)
587 *st++ = '-';
588 else
589 while (len--)
590 *st++ = *p++;
591 *st = '\0';
592 return(retval);
593} /* put_address */
594
595/*************************************/
596/* report a succesfull interrogation */
597/*************************************/
598int interrogate_success(isdn_ctrl *ic, struct call_struc *cs)
599{ char *src = ic->parm.dss1_io.data;
600 int restlen = ic->parm.dss1_io.datalen;
601 int cnt = 1;
602 u_char n,n1;
603 char st[90], *p, *stp;
604
605 if (restlen < 2) return(-100); /* frame too short */
606 if (*src++ != 0x30) return(-101);
607 if ((n = *src++) > 0x81) return(-102); /* invalid length field */
608 restlen -= 2; /* remaining bytes */
609 if (n == 0x80)
610 { if (restlen < 2) return(-103);
611 if ((*(src+restlen-1)) || (*(src+restlen-2))) return(-104);
612 restlen -= 2;
613 }
614 else
615 if ( n == 0x81)
616 { n = *src++;
617 restlen--;
618 if (n > restlen) return(-105);
619 restlen = n;
620 }
621 else
622 if (n > restlen) return(-106);
623 else
624 restlen = n; /* standard format */
625 if (restlen < 3) return(-107); /* no procedure */
626 if ((*src++ != 2) || (*src++ != 1) || (*src++ != 0x0B)) return(-108);
627 restlen -= 3;
628 if (restlen < 2) return(-109); /* list missing */
629 if (*src == 0x31)
630 { src++;
631 if ((n = *src++) > 0x81) return(-110); /* invalid length field */
632 restlen -= 2; /* remaining bytes */
633 if (n == 0x80)
634 { if (restlen < 2) return(-111);
635 if ((*(src+restlen-1)) || (*(src+restlen-2))) return(-112);
636 restlen -= 2;
637 }
638 else
639 if ( n == 0x81)
640 { n = *src++;
641 restlen--;
642 if (n > restlen) return(-113);
643 restlen = n;
644 }
645 else
646 if (n > restlen) return(-114);
647 else
648 restlen = n; /* standard format */
649 } /* result list header */
650
651 while (restlen >= 2)
652 { stp = st;
653 sprintf(stp,"%d 0x%lx %d %s ",DIVERT_REPORT, ic->parm.dss1_io.ll_id,
654 cnt++,divert_if.drv_to_name(ic->driver));
655 stp += strlen(stp);
656 if (*src++ != 0x30) return(-115); /* invalid enum */
657 n = *src++;
658 restlen -= 2;
659 if (n > restlen) return(-116); /* enum length wrong */
660 restlen -= n;
661 p = src; /* one entry */
662 src += n;
663 if (!(n1 = put_address(stp,p,n & 0xFF))) continue;
664 stp += strlen(stp);
665 p += n1;
666 n -= n1;
667 if (n < 6) continue; /* no service and proc */
668 if ((*p++ != 0x0A) || (*p++ != 1)) continue;
669 sprintf(stp," 0x%02x ",(*p++) & 0xFF);
670 stp += strlen(stp);
671 if ((*p++ != 0x0A) || (*p++ != 1)) continue;
672 sprintf(stp,"%d ",(*p++) & 0xFF);
673 stp += strlen(stp);
674 n -= 6;
675 if (n > 2)
676 { if (*p++ != 0x30) continue;
677 if (*p > (n-2)) continue;
678 n = *p++;
679 if (!(n1 = put_address(stp,p,n & 0xFF))) continue;
680 stp += strlen(stp);
681 }
682 sprintf(stp,"\n");
683 put_info_buffer(st);
684 } /* while restlen */
685 if (restlen) return(-117);
686 return(0);
687} /* interrogate_success */
688
689/*********************************************/
690/* callback for protocol specific extensions */
691/*********************************************/
692int prot_stat_callback(isdn_ctrl *ic)
693{ struct call_struc *cs, *cs1;
694 int i;
695 unsigned long flags;
696
697 cs = divert_head; /* start of list */
698 cs1 = NULL;
699 while (cs)
700 { if (ic->driver == cs->ics.driver)
701 { switch (cs->ics.arg)
702 { case DSS1_CMD_INVOKE:
703 if ((cs->ics.parm.dss1_io.ll_id == ic->parm.dss1_io.ll_id) &&
704 (cs->ics.parm.dss1_io.hl_id == ic->parm.dss1_io.hl_id))
705 { switch (ic->arg)
706 { case DSS1_STAT_INVOKE_ERR:
707 sprintf(cs->info,"128 0x%lx 0x%x\n",
708 ic->parm.dss1_io.ll_id,
709 ic->parm.dss1_io.timeout);
710 put_info_buffer(cs->info);
711 break;
712
713 case DSS1_STAT_INVOKE_RES:
714 switch (cs->ics.parm.dss1_io.proc)
715 { case 7:
716 case 8:
717 put_info_buffer(cs->info);
718 break;
719
720 case 11:
721 i = interrogate_success(ic,cs);
722 if (i)
723 sprintf(cs->info,"%d 0x%lx %d\n",DIVERT_REPORT,
724 ic->parm.dss1_io.ll_id,i);
725 put_info_buffer(cs->info);
726 break;
727
728 default:
729 printk(KERN_WARNING "dss1_divert: unknown proc %d\n",cs->ics.parm.dss1_io.proc);
730 break;
731 }
732
733
734 break;
735
736 default:
737 printk(KERN_WARNING "dss1_divert unknown invoke answer %lx\n",ic->arg);
738 break;
739 }
740 cs1 = cs; /* remember structure */
741 cs = NULL;
742 continue; /* abort search */
743 } /* id found */
744 break;
745
746 case DSS1_CMD_INVOKE_ABORT:
747 printk(KERN_WARNING "dss1_divert unhandled invoke abort\n");
748 break;
749
750 default:
751 printk(KERN_WARNING "dss1_divert unknown cmd 0x%lx\n",cs->ics.arg);
752 break;
753 } /* switch ics.arg */
754 cs = cs->next;
755 } /* driver ok */
756 }
757
758 if (!cs1)
759 { printk(KERN_WARNING "dss1_divert unhandled process\n");
760 return(0);
761 }
762
763 if (cs1->ics.driver == -1)
764 {
765 spin_lock_irqsave(&divert_lock, flags);
766 del_timer(&cs1->timer);
767 if (cs1->prev)
768 cs1->prev->next = cs1->next; /* forward link */
769 else
770 divert_head = cs1->next;
771 if (cs1->next)
772 cs1->next->prev = cs1->prev; /* back link */
773 spin_unlock_irqrestore(&divert_lock, flags);
774 kfree(cs1);
775 }
776
777 return(0);
778} /* prot_stat_callback */
779
780
781/***************************/
782/* status callback from HL */
783/***************************/
784int isdn_divert_stat_callback(isdn_ctrl *ic)
785{ struct call_struc *cs, *cs1;
786 unsigned long flags;
787 int retval;
788
789 retval = -1;
790 cs = divert_head; /* start of list */
791 while (cs)
792 { if ((ic->driver == cs->ics.driver) && (ic->arg == cs->ics.arg))
793 { switch (ic->command)
794 { case ISDN_STAT_DHUP:
795 sprintf(cs->info,"129 0x%lx\n",cs->divert_id);
796 del_timer(&cs->timer);
797 cs->ics.driver = -1;
798 break;
799
800 case ISDN_STAT_CAUSE:
801 sprintf(cs->info,"130 0x%lx %s\n",cs->divert_id,ic->parm.num);
802 break;
803
804 case ISDN_STAT_REDIR:
805 sprintf(cs->info,"131 0x%lx\n",cs->divert_id);
806 del_timer(&cs->timer);
807 cs->ics.driver = -1;
808 break;
809
810 default:
811 sprintf(cs->info,"999 0x%lx 0x%x\n",cs->divert_id,(int)(ic->command));
812 break;
813 }
814 put_info_buffer(cs->info);
815 retval = 0;
816 }
817 cs1 = cs;
818 cs = cs->next;
819 if (cs1->ics.driver == -1)
820 {
821 spin_lock_irqsave(&divert_lock, flags);
822 if (cs1->prev)
823 cs1->prev->next = cs1->next; /* forward link */
824 else
825 divert_head = cs1->next;
826 if (cs1->next)
827 cs1->next->prev = cs1->prev; /* back link */
828 spin_unlock_irqrestore(&divert_lock, flags);
829 kfree(cs1);
830 }
831 }
832 return(retval); /* not found */
833} /* isdn_divert_stat_callback */
834
835
836/********************/
837/* callback from ll */
838/********************/
839int ll_callback(isdn_ctrl *ic)
840{
841 switch (ic->command)
842 { case ISDN_STAT_ICALL:
843 case ISDN_STAT_ICALLW:
844 return(isdn_divert_icall(ic));
845 break;
846
847 case ISDN_STAT_PROT:
848 if ((ic->arg & 0xFF) == ISDN_PTYPE_EURO)
849 { if (ic->arg != DSS1_STAT_INVOKE_BRD)
850 return(prot_stat_callback(ic));
851 else
852 return(0); /* DSS1 invoke broadcast */
853 }
854 else
855 return(-1); /* protocol not euro */
856
857 default:
858 return(isdn_divert_stat_callback(ic));
859 }
860} /* ll_callback */
861
diff --git a/drivers/isdn/divert/isdn_divert.h b/drivers/isdn/divert/isdn_divert.h
new file mode 100644
index 000000000000..19439a6176a9
--- /dev/null
+++ b/drivers/isdn/divert/isdn_divert.h
@@ -0,0 +1,132 @@
1/* $Id: isdn_divert.h,v 1.5.6.1 2001/09/23 22:24:36 kai Exp $
2 *
3 * Header for the diversion supplementary ioctl interface.
4 *
5 * Copyright 1998 by Werner Cornelius (werner@ikt.de)
6 *
7 * This software may be used and distributed according to the terms
8 * of the GNU General Public License, incorporated herein by reference.
9 *
10 */
11
12#include <linux/ioctl.h>
13#include <linux/types.h>
14
15/******************************************/
16/* IOCTL codes for interface to user prog */
17/******************************************/
18#define DIVERT_IIOC_VERSION 0x01 /* actual version */
19#define IIOCGETVER _IO('I', 1) /* get version of interface */
20#define IIOCGETDRV _IO('I', 2) /* get driver number */
21#define IIOCGETNAM _IO('I', 3) /* get driver name */
22#define IIOCGETRULE _IO('I', 4) /* read one rule */
23#define IIOCMODRULE _IO('I', 5) /* modify/replace a rule */
24#define IIOCINSRULE _IO('I', 6) /* insert/append one rule */
25#define IIOCDELRULE _IO('I', 7) /* delete a rule */
26#define IIOCDODFACT _IO('I', 8) /* hangup/reject/alert/immediately deflect a call */
27#define IIOCDOCFACT _IO('I', 9) /* activate control forwarding in PBX */
28#define IIOCDOCFDIS _IO('I',10) /* deactivate control forwarding in PBX */
29#define IIOCDOCFINT _IO('I',11) /* interrogate control forwarding in PBX */
30
31/*************************************/
32/* states reported through interface */
33/*************************************/
34#define DEFLECT_IGNORE 0 /* ignore incoming call */
35#define DEFLECT_REPORT 1 /* only report */
36#define DEFLECT_PROCEED 2 /* deflect when externally triggered */
37#define DEFLECT_ALERT 3 /* alert and deflect after delay */
38#define DEFLECT_REJECT 4 /* reject immediately */
39#define DIVERT_ACTIVATE 5 /* diversion activate */
40#define DIVERT_DEACTIVATE 6 /* diversion deactivate */
41#define DIVERT_REPORT 7 /* interrogation result */
42#define DEFLECT_AUTODEL 255 /* only for internal use */
43
44#define DEFLECT_ALL_IDS 0xFFFFFFFF /* all drivers selected */
45
46typedef struct
47 { ulong drvid; /* driver ids, bit mapped */
48 char my_msn[35]; /* desired msn, subaddr allowed */
49 char caller[35]; /* caller id, partial string with * + subaddr allowed */
50 char to_nr[35]; /* deflected to number incl. subaddress */
51 u_char si1,si2; /* service indicators, si1=bitmask, si1+2 0 = all */
52 u_char screen; /* screening: 0 = no info, 1 = info, 2 = nfo with nr */
53 u_char callopt; /* option for call handling:
54 0 = all calls
55 1 = only non waiting calls
56 2 = only waiting calls */
57 u_char action; /* desired action:
58 0 = don't report call -> ignore
59 1 = report call, do not allow/proceed for deflection
60 2 = report call, send proceed, wait max waittime secs
61 3 = report call, alert and deflect after waittime
62 4 = report call, reject immediately
63 actions 1-2 only take place if interface is opened
64 */
65 u_char waittime; /* maximum wait time for proceeding */
66 } divert_rule;
67
68typedef union
69 { int drv_version; /* return of driver version */
70 struct
71 { int drvid; /* id of driver */
72 char drvnam[30]; /* name of driver */
73 } getid;
74 struct
75 { int ruleidx; /* index of rule */
76 divert_rule rule; /* rule parms */
77 } getsetrule;
78 struct
79 { u_char subcmd; /* 0 = hangup/reject,
80 1 = alert,
81 2 = deflect */
82 ulong callid; /* id of call delivered by ascii output */
83 char to_nr[35]; /* destination when deflect,
84 else uus1 string (maxlen 31),
85 data from rule used if empty */
86 } fwd_ctrl;
87 struct
88 { int drvid; /* id of driver */
89 u_char cfproc; /* cfu = 0, cfb = 1, cfnr = 2 */
90 ulong procid; /* process id returned when no error */
91 u_char service; /* basically coded service, 0 = all */
92 char msn[25]; /* desired msn, empty = all */
93 char fwd_nr[35];/* forwarded to number + subaddress */
94 } cf_ctrl;
95 } divert_ioctl;
96
97#ifdef __KERNEL__
98
99#include <linux/isdnif.h>
100#include <linux/isdn_divertif.h>
101
102#define AUTODEL_TIME 30 /* timeout in s to delete internal entries */
103
104/**************************************************/
105/* structure keeping ascii info for device output */
106/**************************************************/
107struct divert_info
108 { struct divert_info *next;
109 ulong usage_cnt; /* number of files still to work */
110 char info_start[2]; /* info string start */
111 };
112
113
114/**************/
115/* Prototypes */
116/**************/
117extern spinlock_t divert_lock;
118
119extern ulong if_used; /* number of interface users */
120extern int divert_dev_deinit(void);
121extern int divert_dev_init(void);
122extern void put_info_buffer(char *);
123extern int ll_callback(isdn_ctrl *);
124extern isdn_divert_if divert_if;
125extern divert_rule *getruleptr(int);
126extern int insertrule(int, divert_rule *);
127extern int deleterule(int);
128extern void deleteprocs(void);
129extern int deflect_extern_action(u_char, ulong, char *);
130extern int cf_command(int, int, u_char, char *, u_char, char *, ulong *);
131
132#endif /* __KERNEL__ */
diff --git a/drivers/isdn/hardware/Kconfig b/drivers/isdn/hardware/Kconfig
new file mode 100644
index 000000000000..139f19797713
--- /dev/null
+++ b/drivers/isdn/hardware/Kconfig
@@ -0,0 +1,10 @@
1#
2# ISDN hardware drivers
3#
4comment "CAPI hardware drivers"
5 depends on NET && ISDN && ISDN_CAPI
6
7source "drivers/isdn/hardware/avm/Kconfig"
8
9source "drivers/isdn/hardware/eicon/Kconfig"
10
diff --git a/drivers/isdn/hardware/Makefile b/drivers/isdn/hardware/Makefile
new file mode 100644
index 000000000000..11c8a183948c
--- /dev/null
+++ b/drivers/isdn/hardware/Makefile
@@ -0,0 +1,6 @@
1# Makefile for the CAPI hardware drivers
2
3# Object files in subdirectories
4
5obj-$(CONFIG_CAPI_AVM) += avm/
6obj-$(CONFIG_CAPI_EICON) += eicon/
diff --git a/drivers/isdn/hardware/avm/Kconfig b/drivers/isdn/hardware/avm/Kconfig
new file mode 100644
index 000000000000..29a32a8830c0
--- /dev/null
+++ b/drivers/isdn/hardware/avm/Kconfig
@@ -0,0 +1,66 @@
1#
2# ISDN AVM drivers
3#
4
5menu "Active AVM cards"
6 depends on NET && ISDN && ISDN_CAPI!=n
7
8config CAPI_AVM
9 bool "Support AVM cards"
10 help
11 Enable support for AVM active ISDN cards.
12
13config ISDN_DRV_AVMB1_B1ISA
14 tristate "AVM B1 ISA support"
15 depends on CAPI_AVM && ISDN_CAPI && ISA
16 help
17 Enable support for the ISA version of the AVM B1 card.
18
19config ISDN_DRV_AVMB1_B1PCI
20 tristate "AVM B1 PCI support"
21 depends on CAPI_AVM && ISDN_CAPI && PCI
22 help
23 Enable support for the PCI version of the AVM B1 card.
24
25config ISDN_DRV_AVMB1_B1PCIV4
26 bool "AVM B1 PCI V4 support"
27 depends on ISDN_DRV_AVMB1_B1PCI
28 help
29 Enable support for the V4 version of AVM B1 PCI card.
30
31config ISDN_DRV_AVMB1_T1ISA
32 tristate "AVM T1/T1-B ISA support"
33 depends on CAPI_AVM && ISDN_CAPI && ISA
34 help
35 Enable support for the AVM T1 T1B card.
36 Note: This is a PRI card and handle 30 B-channels.
37
38config ISDN_DRV_AVMB1_B1PCMCIA
39 tristate "AVM B1/M1/M2 PCMCIA support"
40 depends on CAPI_AVM && ISDN_CAPI
41 help
42 Enable support for the PCMCIA version of the AVM B1 card.
43
44config ISDN_DRV_AVMB1_AVM_CS
45 tristate "AVM B1/M1/M2 PCMCIA cs module"
46 depends on ISDN_DRV_AVMB1_B1PCMCIA && PCMCIA
47 help
48 Enable the PCMCIA client driver for the AVM B1/M1/M2
49 PCMCIA cards.
50
51config ISDN_DRV_AVMB1_T1PCI
52 tristate "AVM T1/T1-B PCI support"
53 depends on CAPI_AVM && ISDN_CAPI && PCI
54 help
55 Enable support for the AVM T1 T1B card.
56 Note: This is a PRI card and handle 30 B-channels.
57
58config ISDN_DRV_AVMB1_C4
59 tristate "AVM C4/C2 support"
60 depends on CAPI_AVM && ISDN_CAPI && PCI
61 help
62 Enable support for the AVM C4/C2 PCI cards.
63 These cards handle 4/2 BRI ISDN lines (8/4 channels).
64
65endmenu
66
diff --git a/drivers/isdn/hardware/avm/Makefile b/drivers/isdn/hardware/avm/Makefile
new file mode 100644
index 000000000000..b540e8f2efb6
--- /dev/null
+++ b/drivers/isdn/hardware/avm/Makefile
@@ -0,0 +1,11 @@
1# Makefile for the AVM ISDN device drivers
2
3# Each configuration option enables a list of files.
4
5obj-$(CONFIG_ISDN_DRV_AVMB1_B1ISA) += b1isa.o b1.o
6obj-$(CONFIG_ISDN_DRV_AVMB1_B1PCI) += b1pci.o b1.o b1dma.o
7obj-$(CONFIG_ISDN_DRV_AVMB1_B1PCMCIA) += b1pcmcia.o b1.o
8obj-$(CONFIG_ISDN_DRV_AVMB1_AVM_CS) += avm_cs.o
9obj-$(CONFIG_ISDN_DRV_AVMB1_T1ISA) += t1isa.o b1.o
10obj-$(CONFIG_ISDN_DRV_AVMB1_T1PCI) += t1pci.o b1.o b1dma.o
11obj-$(CONFIG_ISDN_DRV_AVMB1_C4) += c4.o b1.o
diff --git a/drivers/isdn/hardware/avm/avm_cs.c b/drivers/isdn/hardware/avm/avm_cs.c
new file mode 100644
index 000000000000..dc00c85e3e35
--- /dev/null
+++ b/drivers/isdn/hardware/avm/avm_cs.c
@@ -0,0 +1,510 @@
1/* $Id: avm_cs.c,v 1.4.6.3 2001/09/23 22:24:33 kai Exp $
2 *
3 * A PCMCIA client driver for AVM B1/M1/M2
4 *
5 * Copyright 1999 by Carsten Paeth <calle@calle.de>
6 *
7 * This software may be used and distributed according to the terms
8 * of the GNU General Public License, incorporated herein by reference.
9 *
10 */
11
12#include <linux/module.h>
13#include <linux/kernel.h>
14#include <linux/init.h>
15#include <linux/sched.h>
16#include <linux/ptrace.h>
17#include <linux/slab.h>
18#include <linux/string.h>
19#include <linux/tty.h>
20#include <linux/serial.h>
21#include <linux/major.h>
22#include <asm/io.h>
23#include <asm/system.h>
24
25#include <pcmcia/version.h>
26#include <pcmcia/cs_types.h>
27#include <pcmcia/cs.h>
28#include <pcmcia/cistpl.h>
29#include <pcmcia/ciscode.h>
30#include <pcmcia/ds.h>
31#include <pcmcia/cisreg.h>
32
33#include <linux/skbuff.h>
34#include <linux/capi.h>
35#include <linux/b1lli.h>
36#include <linux/b1pcmcia.h>
37
38/*====================================================================*/
39
40MODULE_DESCRIPTION("CAPI4Linux: PCMCIA client driver for AVM B1/M1/M2");
41MODULE_AUTHOR("Carsten Paeth");
42MODULE_LICENSE("GPL");
43
44/*====================================================================*/
45
46/*
47 The event() function is this driver's Card Services event handler.
48 It will be called by Card Services when an appropriate card status
49 event is received. The config() and release() entry points are
50 used to configure or release a socket, in response to card insertion
51 and ejection events. They are invoked from the skeleton event
52 handler.
53*/
54
55static void avmcs_config(dev_link_t *link);
56static void avmcs_release(dev_link_t *link);
57static int avmcs_event(event_t event, int priority,
58 event_callback_args_t *args);
59
60/*
61 The attach() and detach() entry points are used to create and destroy
62 "instances" of the driver, where each instance represents everything
63 needed to manage one actual PCMCIA card.
64*/
65
66static dev_link_t *avmcs_attach(void);
67static void avmcs_detach(dev_link_t *);
68
69/*
70 The dev_info variable is the "key" that is used to match up this
71 device driver with appropriate cards, through the card configuration
72 database.
73*/
74
75static dev_info_t dev_info = "avm_cs";
76
77/*
78 A linked list of "instances" of the skeleton device. Each actual
79 PCMCIA card corresponds to one device instance, and is described
80 by one dev_link_t structure (defined in ds.h).
81
82 You may not want to use a linked list for this -- for example, the
83 memory card driver uses an array of dev_link_t pointers, where minor
84 device numbers are used to derive the corresponding array index.
85*/
86
87static dev_link_t *dev_list = NULL;
88
89/*
90 A dev_link_t structure has fields for most things that are needed
91 to keep track of a socket, but there will usually be some device
92 specific information that also needs to be kept track of. The
93 'priv' pointer in a dev_link_t structure can be used to point to
94 a device-specific private data structure, like this.
95
96 A driver needs to provide a dev_node_t structure for each device
97 on a card. In some cases, there is only one device per card (for
98 example, ethernet cards, modems). In other cases, there may be
99 many actual or logical devices (SCSI adapters, memory cards with
100 multiple partitions). The dev_node_t structures need to be kept
101 in a linked list starting at the 'dev' field of a dev_link_t
102 structure. We allocate them in the card's private data structure,
103 because they generally can't be allocated dynamically.
104*/
105
106typedef struct local_info_t {
107 dev_node_t node;
108} local_info_t;
109
110/*======================================================================
111
112 avmcs_attach() creates an "instance" of the driver, allocating
113 local data structures for one device. The device is registered
114 with Card Services.
115
116 The dev_link structure is initialized, but we don't actually
117 configure the card at this point -- we wait until we receive a
118 card insertion event.
119
120======================================================================*/
121
122static dev_link_t *avmcs_attach(void)
123{
124 client_reg_t client_reg;
125 dev_link_t *link;
126 local_info_t *local;
127 int ret;
128
129 /* Initialize the dev_link_t structure */
130 link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
131 if (!link)
132 goto err;
133 memset(link, 0, sizeof(struct dev_link_t));
134
135 /* The io structure describes IO port mapping */
136 link->io.NumPorts1 = 16;
137 link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
138 link->io.NumPorts2 = 0;
139
140 /* Interrupt setup */
141 link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
142 link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED;
143
144 link->irq.IRQInfo1 = IRQ_LEVEL_ID;
145
146 /* General socket configuration */
147 link->conf.Attributes = CONF_ENABLE_IRQ;
148 link->conf.Vcc = 50;
149 link->conf.IntType = INT_MEMORY_AND_IO;
150 link->conf.ConfigIndex = 1;
151 link->conf.Present = PRESENT_OPTION;
152
153 /* Allocate space for private device-specific data */
154 local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
155 if (!local)
156 goto err_kfree;
157 memset(local, 0, sizeof(local_info_t));
158 link->priv = local;
159
160 /* Register with Card Services */
161 link->next = dev_list;
162 dev_list = link;
163 client_reg.dev_info = &dev_info;
164 client_reg.EventMask =
165 CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
166 CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
167 CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
168 client_reg.event_handler = &avmcs_event;
169 client_reg.Version = 0x0210;
170 client_reg.event_callback_args.client_data = link;
171 ret = pcmcia_register_client(&link->handle, &client_reg);
172 if (ret != 0) {
173 cs_error(link->handle, RegisterClient, ret);
174 avmcs_detach(link);
175 goto err;
176 }
177 return link;
178
179 err_kfree:
180 kfree(link);
181 err:
182 return NULL;
183} /* avmcs_attach */
184
185/*======================================================================
186
187 This deletes a driver "instance". The device is de-registered
188 with Card Services. If it has been released, all local data
189 structures are freed. Otherwise, the structures will be freed
190 when the device is released.
191
192======================================================================*/
193
194static void avmcs_detach(dev_link_t *link)
195{
196 dev_link_t **linkp;
197
198 /* Locate device structure */
199 for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
200 if (*linkp == link) break;
201 if (*linkp == NULL)
202 return;
203
204 /*
205 If the device is currently configured and active, we won't
206 actually delete it yet. Instead, it is marked so that when
207 the release() function is called, that will trigger a proper
208 detach().
209 */
210 if (link->state & DEV_CONFIG) {
211 link->state |= DEV_STALE_LINK;
212 return;
213 }
214
215 /* Break the link with Card Services */
216 if (link->handle)
217 pcmcia_deregister_client(link->handle);
218
219 /* Unlink device structure, free pieces */
220 *linkp = link->next;
221 if (link->priv) {
222 kfree(link->priv);
223 }
224 kfree(link);
225
226} /* avmcs_detach */
227
228/*======================================================================
229
230 avmcs_config() is scheduled to run after a CARD_INSERTION event
231 is received, to configure the PCMCIA socket, and to make the
232 ethernet device available to the system.
233
234======================================================================*/
235
236static int get_tuple(client_handle_t handle, tuple_t *tuple,
237 cisparse_t *parse)
238{
239 int i = pcmcia_get_tuple_data(handle, tuple);
240 if (i != CS_SUCCESS) return i;
241 return pcmcia_parse_tuple(handle, tuple, parse);
242}
243
244static int first_tuple(client_handle_t handle, tuple_t *tuple,
245 cisparse_t *parse)
246{
247 int i = pcmcia_get_first_tuple(handle, tuple);
248 if (i != CS_SUCCESS) return i;
249 return get_tuple(handle, tuple, parse);
250}
251
252static int next_tuple(client_handle_t handle, tuple_t *tuple,
253 cisparse_t *parse)
254{
255 int i = pcmcia_get_next_tuple(handle, tuple);
256 if (i != CS_SUCCESS) return i;
257 return get_tuple(handle, tuple, parse);
258}
259
260static void avmcs_config(dev_link_t *link)
261{
262 client_handle_t handle;
263 tuple_t tuple;
264 cisparse_t parse;
265 cistpl_cftable_entry_t *cf = &parse.cftable_entry;
266 local_info_t *dev;
267 int i;
268 u_char buf[64];
269 char devname[128];
270 int cardtype;
271 int (*addcard)(unsigned int port, unsigned irq);
272
273 handle = link->handle;
274 dev = link->priv;
275
276 /*
277 This reads the card's CONFIG tuple to find its configuration
278 registers.
279 */
280 do {
281 tuple.DesiredTuple = CISTPL_CONFIG;
282 i = pcmcia_get_first_tuple(handle, &tuple);
283 if (i != CS_SUCCESS) break;
284 tuple.TupleData = buf;
285 tuple.TupleDataMax = 64;
286 tuple.TupleOffset = 0;
287 i = pcmcia_get_tuple_data(handle, &tuple);
288 if (i != CS_SUCCESS) break;
289 i = pcmcia_parse_tuple(handle, &tuple, &parse);
290 if (i != CS_SUCCESS) break;
291 link->conf.ConfigBase = parse.config.base;
292 } while (0);
293 if (i != CS_SUCCESS) {
294 cs_error(link->handle, ParseTuple, i);
295 link->state &= ~DEV_CONFIG_PENDING;
296 return;
297 }
298
299 /* Configure card */
300 link->state |= DEV_CONFIG;
301
302 do {
303
304 tuple.Attributes = 0;
305 tuple.TupleData = buf;
306 tuple.TupleDataMax = 254;
307 tuple.TupleOffset = 0;
308 tuple.DesiredTuple = CISTPL_VERS_1;
309
310 devname[0] = 0;
311 if( !first_tuple(handle, &tuple, &parse) && parse.version_1.ns > 1 ) {
312 strlcpy(devname,parse.version_1.str + parse.version_1.ofs[1],
313 sizeof(devname));
314 }
315 /*
316 * find IO port
317 */
318 tuple.TupleData = (cisdata_t *)buf;
319 tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
320 tuple.Attributes = 0;
321 tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
322 i = first_tuple(handle, &tuple, &parse);
323 while (i == CS_SUCCESS) {
324 if (cf->io.nwin > 0) {
325 link->conf.ConfigIndex = cf->index;
326 link->io.BasePort1 = cf->io.win[0].base;
327 link->io.NumPorts1 = cf->io.win[0].len;
328 link->io.NumPorts2 = 0;
329 printk(KERN_INFO "avm_cs: testing i/o %#x-%#x\n",
330 link->io.BasePort1,
331 link->io.BasePort1+link->io.NumPorts1-1);
332 i = pcmcia_request_io(link->handle, &link->io);
333 if (i == CS_SUCCESS) goto found_port;
334 }
335 i = next_tuple(handle, &tuple, &parse);
336 }
337
338found_port:
339 if (i != CS_SUCCESS) {
340 cs_error(link->handle, RequestIO, i);
341 break;
342 }
343
344 /*
345 * allocate an interrupt line
346 */
347 i = pcmcia_request_irq(link->handle, &link->irq);
348 if (i != CS_SUCCESS) {
349 cs_error(link->handle, RequestIRQ, i);
350 pcmcia_release_io(link->handle, &link->io);
351 break;
352 }
353
354 /*
355 * configure the PCMCIA socket
356 */
357 i = pcmcia_request_configuration(link->handle, &link->conf);
358 if (i != CS_SUCCESS) {
359 cs_error(link->handle, RequestConfiguration, i);
360 pcmcia_release_io(link->handle, &link->io);
361 pcmcia_release_irq(link->handle, &link->irq);
362 break;
363 }
364
365 } while (0);
366
367 /* At this point, the dev_node_t structure(s) should be
368 initialized and arranged in a linked list at link->dev. */
369
370 if (devname[0]) {
371 char *s = strrchr(devname, ' ');
372 if (!s)
373 s = devname;
374 else s++;
375 strcpy(dev->node.dev_name, s);
376 if (strcmp("M1", s) == 0) {
377 cardtype = AVM_CARDTYPE_M1;
378 } else if (strcmp("M2", s) == 0) {
379 cardtype = AVM_CARDTYPE_M2;
380 } else {
381 cardtype = AVM_CARDTYPE_B1;
382 }
383 } else {
384 strcpy(dev->node.dev_name, "b1");
385 cardtype = AVM_CARDTYPE_B1;
386 }
387
388 dev->node.major = 64;
389 dev->node.minor = 0;
390 link->dev = &dev->node;
391
392 link->state &= ~DEV_CONFIG_PENDING;
393 /* If any step failed, release any partially configured state */
394 if (i != 0) {
395 avmcs_release(link);
396 return;
397 }
398
399
400 switch (cardtype) {
401 case AVM_CARDTYPE_M1: addcard = b1pcmcia_addcard_m1; break;
402 case AVM_CARDTYPE_M2: addcard = b1pcmcia_addcard_m2; break;
403 default:
404 case AVM_CARDTYPE_B1: addcard = b1pcmcia_addcard_b1; break;
405 }
406 if ((i = (*addcard)(link->io.BasePort1, link->irq.AssignedIRQ)) < 0) {
407 printk(KERN_ERR "avm_cs: failed to add AVM-%s-Controller at i/o %#x, irq %d\n",
408 dev->node.dev_name, link->io.BasePort1, link->irq.AssignedIRQ);
409 avmcs_release(link);
410 return;
411 }
412 dev->node.minor = i;
413
414} /* avmcs_config */
415
416/*======================================================================
417
418 After a card is removed, avmcs_release() will unregister the net
419 device, and release the PCMCIA configuration. If the device is
420 still open, this will be postponed until it is closed.
421
422======================================================================*/
423
424static void avmcs_release(dev_link_t *link)
425{
426 b1pcmcia_delcard(link->io.BasePort1, link->irq.AssignedIRQ);
427
428 /* Unlink the device chain */
429 link->dev = NULL;
430
431 /* Don't bother checking to see if these succeed or not */
432 pcmcia_release_configuration(link->handle);
433 pcmcia_release_io(link->handle, &link->io);
434 pcmcia_release_irq(link->handle, &link->irq);
435 link->state &= ~DEV_CONFIG;
436
437 if (link->state & DEV_STALE_LINK)
438 avmcs_detach(link);
439
440} /* avmcs_release */
441
442/*======================================================================
443
444 The card status event handler. Mostly, this schedules other
445 stuff to run after an event is received. A CARD_REMOVAL event
446 also sets some flags to discourage the net drivers from trying
447 to talk to the card any more.
448
449 When a CARD_REMOVAL event is received, we immediately set a flag
450 to block future accesses to this device. All the functions that
451 actually access the device should check this flag to make sure
452 the card is still present.
453
454======================================================================*/
455
456static int avmcs_event(event_t event, int priority,
457 event_callback_args_t *args)
458{
459 dev_link_t *link = args->client_data;
460
461 switch (event) {
462 case CS_EVENT_CARD_REMOVAL:
463 link->state &= ~DEV_PRESENT;
464 if (link->state & DEV_CONFIG)
465 avmcs_release(link);
466 break;
467 case CS_EVENT_CARD_INSERTION:
468 link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
469 avmcs_config(link);
470 break;
471 case CS_EVENT_PM_SUSPEND:
472 link->state |= DEV_SUSPEND;
473 /* Fall through... */
474 case CS_EVENT_RESET_PHYSICAL:
475 if (link->state & DEV_CONFIG)
476 pcmcia_release_configuration(link->handle);
477 break;
478 case CS_EVENT_PM_RESUME:
479 link->state &= ~DEV_SUSPEND;
480 /* Fall through... */
481 case CS_EVENT_CARD_RESET:
482 if (link->state & DEV_CONFIG)
483 pcmcia_request_configuration(link->handle, &link->conf);
484 break;
485 }
486 return 0;
487} /* avmcs_event */
488
489static struct pcmcia_driver avmcs_driver = {
490 .owner = THIS_MODULE,
491 .drv = {
492 .name = "avm_cs",
493 },
494 .attach = avmcs_attach,
495 .detach = avmcs_detach,
496};
497
498static int __init avmcs_init(void)
499{
500 return pcmcia_register_driver(&avmcs_driver);
501}
502
503static void __exit avmcs_exit(void)
504{
505 pcmcia_unregister_driver(&avmcs_driver);
506 BUG_ON(dev_list != NULL);
507}
508
509module_init(avmcs_init);
510module_exit(avmcs_exit);
diff --git a/drivers/isdn/hardware/avm/avmcard.h b/drivers/isdn/hardware/avm/avmcard.h
new file mode 100644
index 000000000000..296d6a6f749f
--- /dev/null
+++ b/drivers/isdn/hardware/avm/avmcard.h
@@ -0,0 +1,585 @@
1/* $Id: avmcard.h,v 1.1.4.1.2.1 2001/12/21 15:00:17 kai Exp $
2 *
3 * Copyright 1999 by Carsten Paeth <calle@calle.de>
4 *
5 * This software may be used and distributed according to the terms
6 * of the GNU General Public License, incorporated herein by reference.
7 *
8 */
9
10#ifndef _AVMCARD_H_
11#define _AVMCARD_H_
12
13#include <linux/spinlock.h>
14#include <linux/list.h>
15#include <linux/interrupt.h>
16
17#define AVMB1_PORTLEN 0x1f
18#define AVM_MAXVERSION 8
19#define AVM_NCCI_PER_CHANNEL 4
20
21/*
22 * Versions
23 */
24
25#define VER_DRIVER 0
26#define VER_CARDTYPE 1
27#define VER_HWID 2
28#define VER_SERIAL 3
29#define VER_OPTION 4
30#define VER_PROTO 5
31#define VER_PROFILE 6
32#define VER_CAPI 7
33
34enum avmcardtype {
35 avm_b1isa,
36 avm_b1pci,
37 avm_b1pcmcia,
38 avm_m1,
39 avm_m2,
40 avm_t1isa,
41 avm_t1pci,
42 avm_c4,
43 avm_c2
44};
45
46typedef struct avmcard_dmabuf {
47 long size;
48 u8 *dmabuf;
49 dma_addr_t dmaaddr;
50} avmcard_dmabuf;
51
52typedef struct avmcard_dmainfo {
53 u32 recvlen;
54 avmcard_dmabuf recvbuf;
55
56 avmcard_dmabuf sendbuf;
57 struct sk_buff_head send_queue;
58
59 struct pci_dev *pcidev;
60} avmcard_dmainfo;
61
62typedef struct avmctrl_info {
63 char cardname[32];
64
65 int versionlen;
66 char versionbuf[1024];
67 char *version[AVM_MAXVERSION];
68
69 char infobuf[128]; /* for function procinfo */
70
71 struct avmcard *card;
72 struct capi_ctr capi_ctrl;
73
74 struct list_head ncci_head;
75} avmctrl_info;
76
77typedef struct avmcard {
78 char name[32];
79
80 spinlock_t lock;
81 unsigned int port;
82 unsigned irq;
83 unsigned long membase;
84 enum avmcardtype cardtype;
85 unsigned char revision;
86 unsigned char class;
87 int cardnr; /* for t1isa */
88
89 char msgbuf[128]; /* capimsg msg part */
90 char databuf[2048]; /* capimsg data part */
91
92 void __iomem *mbase;
93 volatile u32 csr;
94 avmcard_dmainfo *dma;
95
96 struct avmctrl_info *ctrlinfo;
97
98 u_int nr_controllers;
99 u_int nlogcontr;
100 struct list_head list;
101} avmcard;
102
103extern int b1_irq_table[16];
104
105/*
106 * LLI Messages to the ISDN-ControllerISDN Controller
107 */
108
109#define SEND_POLL 0x72 /*
110 * after load <- RECEIVE_POLL
111 */
112#define SEND_INIT 0x11 /*
113 * first message <- RECEIVE_INIT
114 * int32 NumApplications int32
115 * NumNCCIs int32 BoardNumber
116 */
117#define SEND_REGISTER 0x12 /*
118 * register an application int32
119 * ApplIDId int32 NumMessages
120 * int32 NumB3Connections int32
121 * NumB3Blocks int32 B3Size
122 *
123 * AnzB3Connection != 0 &&
124 * AnzB3Blocks >= 1 && B3Size >= 1
125 */
126#define SEND_RELEASE 0x14 /*
127 * deregister an application int32
128 * ApplID
129 */
130#define SEND_MESSAGE 0x15 /*
131 * send capi-message int32 length
132 * capi-data ...
133 */
134#define SEND_DATA_B3_REQ 0x13 /*
135 * send capi-data-message int32
136 * MsgLength capi-data ... int32
137 * B3Length data ....
138 */
139
140#define SEND_CONFIG 0x21 /*
141 */
142
143#define SEND_POLLACK 0x73 /* T1 Watchdog */
144
145/*
146 * LLI Messages from the ISDN-ControllerISDN Controller
147 */
148
149#define RECEIVE_POLL 0x32 /*
150 * <- after SEND_POLL
151 */
152#define RECEIVE_INIT 0x27 /*
153 * <- after SEND_INIT int32 length
154 * byte total length b1struct board
155 * driver revision b1struct card
156 * type b1struct reserved b1struct
157 * serial number b1struct driver
158 * capability b1struct d-channel
159 * protocol b1struct CAPI-2.0
160 * profile b1struct capi version
161 */
162#define RECEIVE_MESSAGE 0x21 /*
163 * <- after SEND_MESSAGE int32
164 * AppllID int32 Length capi-data
165 * ....
166 */
167#define RECEIVE_DATA_B3_IND 0x22 /*
168 * received data int32 AppllID
169 * int32 Length capi-data ...
170 * int32 B3Length data ...
171 */
172#define RECEIVE_START 0x23 /*
173 * Handshake
174 */
175#define RECEIVE_STOP 0x24 /*
176 * Handshake
177 */
178#define RECEIVE_NEW_NCCI 0x25 /*
179 * int32 AppllID int32 NCCI int32
180 * WindowSize
181 */
182#define RECEIVE_FREE_NCCI 0x26 /*
183 * int32 AppllID int32 NCCI
184 */
185#define RECEIVE_RELEASE 0x26 /*
186 * int32 AppllID int32 0xffffffff
187 */
188#define RECEIVE_TASK_READY 0x31 /*
189 * int32 tasknr
190 * int32 Length Taskname ...
191 */
192#define RECEIVE_DEBUGMSG 0x71 /*
193 * int32 Length message
194 *
195 */
196#define RECEIVE_POLLDWORD 0x75 /* t1pci in dword mode */
197
198#define WRITE_REGISTER 0x00
199#define READ_REGISTER 0x01
200
201/*
202 * port offsets
203 */
204
205#define B1_READ 0x00
206#define B1_WRITE 0x01
207#define B1_INSTAT 0x02
208#define B1_OUTSTAT 0x03
209#define B1_ANALYSE 0x04
210#define B1_REVISION 0x05
211#define B1_RESET 0x10
212
213
214#define B1_STAT0(cardtype) ((cardtype) == avm_m1 ? 0x81200000l : 0x80A00000l)
215#define B1_STAT1(cardtype) (0x80E00000l)
216
217/* ---------------------------------------------------------------- */
218
219static inline unsigned char b1outp(unsigned int base,
220 unsigned short offset,
221 unsigned char value)
222{
223 outb(value, base + offset);
224 return inb(base + B1_ANALYSE);
225}
226
227
228static inline int b1_rx_full(unsigned int base)
229{
230 return inb(base + B1_INSTAT) & 0x1;
231}
232
233static inline unsigned char b1_get_byte(unsigned int base)
234{
235 unsigned long stop = jiffies + 1 * HZ; /* maximum wait time 1 sec */
236 while (!b1_rx_full(base) && time_before(jiffies, stop));
237 if (b1_rx_full(base))
238 return inb(base + B1_READ);
239 printk(KERN_CRIT "b1lli(0x%x): rx not full after 1 second\n", base);
240 return 0;
241}
242
243static inline unsigned int b1_get_word(unsigned int base)
244{
245 unsigned int val = 0;
246 val |= b1_get_byte(base);
247 val |= (b1_get_byte(base) << 8);
248 val |= (b1_get_byte(base) << 16);
249 val |= (b1_get_byte(base) << 24);
250 return val;
251}
252
253static inline int b1_tx_empty(unsigned int base)
254{
255 return inb(base + B1_OUTSTAT) & 0x1;
256}
257
258static inline void b1_put_byte(unsigned int base, unsigned char val)
259{
260 while (!b1_tx_empty(base));
261 b1outp(base, B1_WRITE, val);
262}
263
264static inline int b1_save_put_byte(unsigned int base, unsigned char val)
265{
266 unsigned long stop = jiffies + 2 * HZ;
267 while (!b1_tx_empty(base) && time_before(jiffies,stop));
268 if (!b1_tx_empty(base)) return -1;
269 b1outp(base, B1_WRITE, val);
270 return 0;
271}
272
273static inline void b1_put_word(unsigned int base, unsigned int val)
274{
275 b1_put_byte(base, val & 0xff);
276 b1_put_byte(base, (val >> 8) & 0xff);
277 b1_put_byte(base, (val >> 16) & 0xff);
278 b1_put_byte(base, (val >> 24) & 0xff);
279}
280
281static inline unsigned int b1_get_slice(unsigned int base,
282 unsigned char *dp)
283{
284 unsigned int len, i;
285
286 len = i = b1_get_word(base);
287 while (i-- > 0) *dp++ = b1_get_byte(base);
288 return len;
289}
290
291static inline void b1_put_slice(unsigned int base,
292 unsigned char *dp, unsigned int len)
293{
294 unsigned i = len;
295 b1_put_word(base, i);
296 while (i-- > 0)
297 b1_put_byte(base, *dp++);
298}
299
300static void b1_wr_reg(unsigned int base,
301 unsigned int reg,
302 unsigned int value)
303{
304 b1_put_byte(base, WRITE_REGISTER);
305 b1_put_word(base, reg);
306 b1_put_word(base, value);
307}
308
309static inline unsigned int b1_rd_reg(unsigned int base,
310 unsigned int reg)
311{
312 b1_put_byte(base, READ_REGISTER);
313 b1_put_word(base, reg);
314 return b1_get_word(base);
315
316}
317
318static inline void b1_reset(unsigned int base)
319{
320 b1outp(base, B1_RESET, 0);
321 mdelay(55 * 2); /* 2 TIC's */
322
323 b1outp(base, B1_RESET, 1);
324 mdelay(55 * 2); /* 2 TIC's */
325
326 b1outp(base, B1_RESET, 0);
327 mdelay(55 * 2); /* 2 TIC's */
328}
329
330static inline unsigned char b1_disable_irq(unsigned int base)
331{
332 return b1outp(base, B1_INSTAT, 0x00);
333}
334
335/* ---------------------------------------------------------------- */
336
337static inline void b1_set_test_bit(unsigned int base,
338 enum avmcardtype cardtype,
339 int onoff)
340{
341 b1_wr_reg(base, B1_STAT0(cardtype), onoff ? 0x21 : 0x20);
342}
343
344static inline int b1_get_test_bit(unsigned int base,
345 enum avmcardtype cardtype)
346{
347 return (b1_rd_reg(base, B1_STAT0(cardtype)) & 0x01) != 0;
348}
349
350/* ---------------------------------------------------------------- */
351
352#define T1_FASTLINK 0x00
353#define T1_SLOWLINK 0x08
354
355#define T1_READ B1_READ
356#define T1_WRITE B1_WRITE
357#define T1_INSTAT B1_INSTAT
358#define T1_OUTSTAT B1_OUTSTAT
359#define T1_IRQENABLE 0x05
360#define T1_FIFOSTAT 0x06
361#define T1_RESETLINK 0x10
362#define T1_ANALYSE 0x11
363#define T1_IRQMASTER 0x12
364#define T1_IDENT 0x17
365#define T1_RESETBOARD 0x1f
366
367#define T1F_IREADY 0x01
368#define T1F_IHALF 0x02
369#define T1F_IFULL 0x04
370#define T1F_IEMPTY 0x08
371#define T1F_IFLAGS 0xF0
372
373#define T1F_OREADY 0x10
374#define T1F_OHALF 0x20
375#define T1F_OEMPTY 0x40
376#define T1F_OFULL 0x80
377#define T1F_OFLAGS 0xF0
378
379/* there are HEMA cards with 1k and 4k FIFO out */
380#define FIFO_OUTBSIZE 256
381#define FIFO_INPBSIZE 512
382
383#define HEMA_VERSION_ID 0
384#define HEMA_PAL_ID 0
385
386static inline void t1outp(unsigned int base,
387 unsigned short offset,
388 unsigned char value)
389{
390 outb(value, base + offset);
391}
392
393static inline unsigned char t1inp(unsigned int base,
394 unsigned short offset)
395{
396 return inb(base + offset);
397}
398
399static inline int t1_isfastlink(unsigned int base)
400{
401 return (inb(base + T1_IDENT) & ~0x82) == 1;
402}
403
404static inline unsigned char t1_fifostatus(unsigned int base)
405{
406 return inb(base + T1_FIFOSTAT);
407}
408
409static inline unsigned int t1_get_slice(unsigned int base,
410 unsigned char *dp)
411{
412 unsigned int len, i;
413#ifdef FASTLINK_DEBUG
414 unsigned wcnt = 0, bcnt = 0;
415#endif
416
417 len = i = b1_get_word(base);
418 if (t1_isfastlink(base)) {
419 int status;
420 while (i > 0) {
421 status = t1_fifostatus(base) & (T1F_IREADY|T1F_IHALF);
422 if (i >= FIFO_INPBSIZE) status |= T1F_IFULL;
423
424 switch (status) {
425 case T1F_IREADY|T1F_IHALF|T1F_IFULL:
426 insb(base+B1_READ, dp, FIFO_INPBSIZE);
427 dp += FIFO_INPBSIZE;
428 i -= FIFO_INPBSIZE;
429#ifdef FASTLINK_DEBUG
430 wcnt += FIFO_INPBSIZE;
431#endif
432 break;
433 case T1F_IREADY|T1F_IHALF:
434 insb(base+B1_READ,dp, i);
435#ifdef FASTLINK_DEBUG
436 wcnt += i;
437#endif
438 dp += i;
439 i = 0;
440 if (i == 0)
441 break;
442 /* fall through */
443 default:
444 *dp++ = b1_get_byte(base);
445 i--;
446#ifdef FASTLINK_DEBUG
447 bcnt++;
448#endif
449 break;
450 }
451 }
452#ifdef FASTLINK_DEBUG
453 if (wcnt)
454 printk(KERN_DEBUG "b1lli(0x%x): get_slice l=%d w=%d b=%d\n",
455 base, len, wcnt, bcnt);
456#endif
457 } else {
458 while (i-- > 0)
459 *dp++ = b1_get_byte(base);
460 }
461 return len;
462}
463
464static inline void t1_put_slice(unsigned int base,
465 unsigned char *dp, unsigned int len)
466{
467 unsigned i = len;
468 b1_put_word(base, i);
469 if (t1_isfastlink(base)) {
470 int status;
471 while (i > 0) {
472 status = t1_fifostatus(base) & (T1F_OREADY|T1F_OHALF);
473 if (i >= FIFO_OUTBSIZE) status |= T1F_OEMPTY;
474 switch (status) {
475 case T1F_OREADY|T1F_OHALF|T1F_OEMPTY:
476 outsb(base+B1_WRITE, dp, FIFO_OUTBSIZE);
477 dp += FIFO_OUTBSIZE;
478 i -= FIFO_OUTBSIZE;
479 break;
480 case T1F_OREADY|T1F_OHALF:
481 outsb(base+B1_WRITE, dp, i);
482 dp += i;
483 i = 0;
484 break;
485 default:
486 b1_put_byte(base, *dp++);
487 i--;
488 break;
489 }
490 }
491 } else {
492 while (i-- > 0)
493 b1_put_byte(base, *dp++);
494 }
495}
496
497static inline void t1_disable_irq(unsigned int base)
498{
499 t1outp(base, T1_IRQMASTER, 0x00);
500}
501
502static inline void t1_reset(unsigned int base)
503{
504 /* reset T1 Controller */
505 b1_reset(base);
506 /* disable irq on HEMA */
507 t1outp(base, B1_INSTAT, 0x00);
508 t1outp(base, B1_OUTSTAT, 0x00);
509 t1outp(base, T1_IRQMASTER, 0x00);
510 /* reset HEMA board configuration */
511 t1outp(base, T1_RESETBOARD, 0xf);
512}
513
514static inline void b1_setinterrupt(unsigned int base, unsigned irq,
515 enum avmcardtype cardtype)
516{
517 switch (cardtype) {
518 case avm_t1isa:
519 t1outp(base, B1_INSTAT, 0x00);
520 t1outp(base, B1_INSTAT, 0x02);
521 t1outp(base, T1_IRQMASTER, 0x08);
522 break;
523 case avm_b1isa:
524 b1outp(base, B1_INSTAT, 0x00);
525 b1outp(base, B1_RESET, b1_irq_table[irq]);
526 b1outp(base, B1_INSTAT, 0x02);
527 break;
528 default:
529 case avm_m1:
530 case avm_m2:
531 case avm_b1pci:
532 b1outp(base, B1_INSTAT, 0x00);
533 b1outp(base, B1_RESET, 0xf0);
534 b1outp(base, B1_INSTAT, 0x02);
535 break;
536 case avm_c4:
537 case avm_t1pci:
538 b1outp(base, B1_RESET, 0xf0);
539 break;
540 }
541}
542
543/* b1.c */
544avmcard *b1_alloc_card(int nr_controllers);
545void b1_free_card(avmcard *card);
546int b1_detect(unsigned int base, enum avmcardtype cardtype);
547void b1_getrevision(avmcard *card);
548int b1_load_t4file(avmcard *card, capiloaddatapart * t4file);
549int b1_load_config(avmcard *card, capiloaddatapart * config);
550int b1_loaded(avmcard *card);
551
552int b1_load_firmware(struct capi_ctr *ctrl, capiloaddata *data);
553void b1_reset_ctr(struct capi_ctr *ctrl);
554void b1_register_appl(struct capi_ctr *ctrl, u16 appl,
555 capi_register_params *rp);
556void b1_release_appl(struct capi_ctr *ctrl, u16 appl);
557u16 b1_send_message(struct capi_ctr *ctrl, struct sk_buff *skb);
558void b1_parse_version(avmctrl_info *card);
559irqreturn_t b1_interrupt(int interrupt, void *devptr, struct pt_regs *regs);
560
561int b1ctl_read_proc(char *page, char **start, off_t off,
562 int count, int *eof, struct capi_ctr *ctrl);
563
564avmcard_dmainfo *avmcard_dma_alloc(char *name, struct pci_dev *,
565 long rsize, long ssize);
566void avmcard_dma_free(avmcard_dmainfo *);
567
568/* b1dma.c */
569int b1pciv4_detect(avmcard *card);
570int t1pci_detect(avmcard *card);
571void b1dma_reset(avmcard *card);
572irqreturn_t b1dma_interrupt(int interrupt, void *devptr, struct pt_regs *regs);
573
574int b1dma_load_firmware(struct capi_ctr *ctrl, capiloaddata *data);
575void b1dma_reset_ctr(struct capi_ctr *ctrl);
576void b1dma_remove_ctr(struct capi_ctr *ctrl);
577void b1dma_register_appl(struct capi_ctr *ctrl,
578 u16 appl,
579 capi_register_params *rp);
580void b1dma_release_appl(struct capi_ctr *ctrl, u16 appl);
581u16 b1dma_send_message(struct capi_ctr *ctrl, struct sk_buff *skb);
582int b1dmactl_read_proc(char *page, char **start, off_t off,
583 int count, int *eof, struct capi_ctr *ctrl);
584
585#endif /* _AVMCARD_H_ */
diff --git a/drivers/isdn/hardware/avm/b1.c b/drivers/isdn/hardware/avm/b1.c
new file mode 100644
index 000000000000..0c7061d55027
--- /dev/null
+++ b/drivers/isdn/hardware/avm/b1.c
@@ -0,0 +1,814 @@
1/* $Id: b1.c,v 1.1.2.2 2004/01/16 21:09:27 keil Exp $
2 *
3 * Common module for AVM B1 cards.
4 *
5 * Copyright 1999 by Carsten Paeth <calle@calle.de>
6 *
7 * This software may be used and distributed according to the terms
8 * of the GNU General Public License, incorporated herein by reference.
9 *
10 */
11
12#include <linux/module.h>
13#include <linux/kernel.h>
14#include <linux/pci.h>
15#include <linux/skbuff.h>
16#include <linux/delay.h>
17#include <linux/mm.h>
18#include <linux/interrupt.h>
19#include <linux/ioport.h>
20#include <linux/capi.h>
21#include <linux/kernelcapi.h>
22#include <asm/io.h>
23#include <linux/init.h>
24#include <asm/uaccess.h>
25#include <linux/netdevice.h>
26#include <linux/isdn/capilli.h>
27#include "avmcard.h"
28#include <linux/isdn/capicmd.h>
29#include <linux/isdn/capiutil.h>
30
31static char *revision = "$Revision: 1.1.2.2 $";
32
33/* ------------------------------------------------------------- */
34
35MODULE_DESCRIPTION("CAPI4Linux: Common support for active AVM cards");
36MODULE_AUTHOR("Carsten Paeth");
37MODULE_LICENSE("GPL");
38
39/* ------------------------------------------------------------- */
40
41int b1_irq_table[16] =
42{0,
43 0,
44 0,
45 192, /* irq 3 */
46 32, /* irq 4 */
47 160, /* irq 5 */
48 96, /* irq 6 */
49 224, /* irq 7 */
50 0,
51 64, /* irq 9 */
52 80, /* irq 10 */
53 208, /* irq 11 */
54 48, /* irq 12 */
55 0,
56 0,
57 112, /* irq 15 */
58};
59
60/* ------------------------------------------------------------- */
61
62avmcard *b1_alloc_card(int nr_controllers)
63{
64 avmcard *card;
65 avmctrl_info *cinfo;
66 int i;
67
68 card = kmalloc(sizeof(*card), GFP_KERNEL);
69 if (!card)
70 return NULL;
71
72 memset(card, 0, sizeof(*card));
73
74 cinfo = kmalloc(sizeof(*cinfo) * nr_controllers, GFP_KERNEL);
75 if (!cinfo) {
76 kfree(card);
77 return NULL;
78 }
79 memset(cinfo, 0, sizeof(*cinfo) * nr_controllers);
80
81 card->ctrlinfo = cinfo;
82 for (i = 0; i < nr_controllers; i++) {
83 INIT_LIST_HEAD(&cinfo[i].ncci_head);
84 cinfo[i].card = card;
85 }
86 spin_lock_init(&card->lock);
87 card->nr_controllers = nr_controllers;
88
89 return card;
90}
91
92/* ------------------------------------------------------------- */
93
94void b1_free_card(avmcard *card)
95{
96 kfree(card->ctrlinfo);
97 kfree(card);
98}
99
100/* ------------------------------------------------------------- */
101
102int b1_detect(unsigned int base, enum avmcardtype cardtype)
103{
104 int onoff, i;
105
106 /*
107 * Statusregister 0000 00xx
108 */
109 if ((inb(base + B1_INSTAT) & 0xfc)
110 || (inb(base + B1_OUTSTAT) & 0xfc))
111 return 1;
112 /*
113 * Statusregister 0000 001x
114 */
115 b1outp(base, B1_INSTAT, 0x2); /* enable irq */
116 /* b1outp(base, B1_OUTSTAT, 0x2); */
117 if ((inb(base + B1_INSTAT) & 0xfe) != 0x2
118 /* || (inb(base + B1_OUTSTAT) & 0xfe) != 0x2 */)
119 return 2;
120 /*
121 * Statusregister 0000 000x
122 */
123 b1outp(base, B1_INSTAT, 0x0); /* disable irq */
124 b1outp(base, B1_OUTSTAT, 0x0);
125 if ((inb(base + B1_INSTAT) & 0xfe)
126 || (inb(base + B1_OUTSTAT) & 0xfe))
127 return 3;
128
129 for (onoff = !0, i= 0; i < 10 ; i++) {
130 b1_set_test_bit(base, cardtype, onoff);
131 if (b1_get_test_bit(base, cardtype) != onoff)
132 return 4;
133 onoff = !onoff;
134 }
135
136 if (cardtype == avm_m1)
137 return 0;
138
139 if ((b1_rd_reg(base, B1_STAT1(cardtype)) & 0x0f) != 0x01)
140 return 5;
141
142 return 0;
143}
144
145void b1_getrevision(avmcard *card)
146{
147 card->class = inb(card->port + B1_ANALYSE);
148 card->revision = inb(card->port + B1_REVISION);
149}
150
151#define FWBUF_SIZE 256
152int b1_load_t4file(avmcard *card, capiloaddatapart * t4file)
153{
154 unsigned char buf[FWBUF_SIZE];
155 unsigned char *dp;
156 int i, left;
157 unsigned int base = card->port;
158
159 dp = t4file->data;
160 left = t4file->len;
161 while (left > FWBUF_SIZE) {
162 if (t4file->user) {
163 if (copy_from_user(buf, dp, FWBUF_SIZE))
164 return -EFAULT;
165 } else {
166 memcpy(buf, dp, FWBUF_SIZE);
167 }
168 for (i = 0; i < FWBUF_SIZE; i++)
169 if (b1_save_put_byte(base, buf[i]) < 0) {
170 printk(KERN_ERR "%s: corrupted firmware file ?\n",
171 card->name);
172 return -EIO;
173 }
174 left -= FWBUF_SIZE;
175 dp += FWBUF_SIZE;
176 }
177 if (left) {
178 if (t4file->user) {
179 if (copy_from_user(buf, dp, left))
180 return -EFAULT;
181 } else {
182 memcpy(buf, dp, left);
183 }
184 for (i = 0; i < left; i++)
185 if (b1_save_put_byte(base, buf[i]) < 0) {
186 printk(KERN_ERR "%s: corrupted firmware file ?\n",
187 card->name);
188 return -EIO;
189 }
190 }
191 return 0;
192}
193
194int b1_load_config(avmcard *card, capiloaddatapart * config)
195{
196 unsigned char buf[FWBUF_SIZE];
197 unsigned char *dp;
198 unsigned int base = card->port;
199 int i, j, left;
200
201 dp = config->data;
202 left = config->len;
203 if (left) {
204 b1_put_byte(base, SEND_CONFIG);
205 b1_put_word(base, 1);
206 b1_put_byte(base, SEND_CONFIG);
207 b1_put_word(base, left);
208 }
209 while (left > FWBUF_SIZE) {
210 if (config->user) {
211 if (copy_from_user(buf, dp, FWBUF_SIZE))
212 return -EFAULT;
213 } else {
214 memcpy(buf, dp, FWBUF_SIZE);
215 }
216 for (i = 0; i < FWBUF_SIZE; ) {
217 b1_put_byte(base, SEND_CONFIG);
218 for (j=0; j < 4; j++) {
219 b1_put_byte(base, buf[i++]);
220 }
221 }
222 left -= FWBUF_SIZE;
223 dp += FWBUF_SIZE;
224 }
225 if (left) {
226 if (config->user) {
227 if (copy_from_user(buf, dp, left))
228 return -EFAULT;
229 } else {
230 memcpy(buf, dp, left);
231 }
232 for (i = 0; i < left; ) {
233 b1_put_byte(base, SEND_CONFIG);
234 for (j=0; j < 4; j++) {
235 if (i < left)
236 b1_put_byte(base, buf[i++]);
237 else
238 b1_put_byte(base, 0);
239 }
240 }
241 }
242 return 0;
243}
244
245int b1_loaded(avmcard *card)
246{
247 unsigned int base = card->port;
248 unsigned long stop;
249 unsigned char ans;
250 unsigned long tout = 2;
251
252 for (stop = jiffies + tout * HZ; time_before(jiffies, stop);) {
253 if (b1_tx_empty(base))
254 break;
255 }
256 if (!b1_tx_empty(base)) {
257 printk(KERN_ERR "%s: b1_loaded: tx err, corrupted t4 file ?\n",
258 card->name);
259 return 0;
260 }
261 b1_put_byte(base, SEND_POLL);
262 for (stop = jiffies + tout * HZ; time_before(jiffies, stop);) {
263 if (b1_rx_full(base)) {
264 if ((ans = b1_get_byte(base)) == RECEIVE_POLL) {
265 return 1;
266 }
267 printk(KERN_ERR "%s: b1_loaded: got 0x%x, firmware not running\n",
268 card->name, ans);
269 return 0;
270 }
271 }
272 printk(KERN_ERR "%s: b1_loaded: firmware not running\n", card->name);
273 return 0;
274}
275
276/* ------------------------------------------------------------- */
277
278int b1_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
279{
280 avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
281 avmcard *card = cinfo->card;
282 unsigned int port = card->port;
283 unsigned long flags;
284 int retval;
285
286 b1_reset(port);
287
288 if ((retval = b1_load_t4file(card, &data->firmware))) {
289 b1_reset(port);
290 printk(KERN_ERR "%s: failed to load t4file!!\n",
291 card->name);
292 return retval;
293 }
294
295 b1_disable_irq(port);
296
297 if (data->configuration.len > 0 && data->configuration.data) {
298 if ((retval = b1_load_config(card, &data->configuration))) {
299 b1_reset(port);
300 printk(KERN_ERR "%s: failed to load config!!\n",
301 card->name);
302 return retval;
303 }
304 }
305
306 if (!b1_loaded(card)) {
307 printk(KERN_ERR "%s: failed to load t4file.\n", card->name);
308 return -EIO;
309 }
310
311 spin_lock_irqsave(&card->lock, flags);
312 b1_setinterrupt(port, card->irq, card->cardtype);
313 b1_put_byte(port, SEND_INIT);
314 b1_put_word(port, CAPI_MAXAPPL);
315 b1_put_word(port, AVM_NCCI_PER_CHANNEL*2);
316 b1_put_word(port, ctrl->cnr - 1);
317 spin_unlock_irqrestore(&card->lock, flags);
318
319 return 0;
320}
321
322void b1_reset_ctr(struct capi_ctr *ctrl)
323{
324 avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
325 avmcard *card = cinfo->card;
326 unsigned int port = card->port;
327
328 b1_reset(port);
329 b1_reset(port);
330
331 memset(cinfo->version, 0, sizeof(cinfo->version));
332 capilib_release(&cinfo->ncci_head);
333 capi_ctr_reseted(ctrl);
334}
335
336void b1_register_appl(struct capi_ctr *ctrl,
337 u16 appl,
338 capi_register_params *rp)
339{
340 avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
341 avmcard *card = cinfo->card;
342 unsigned int port = card->port;
343 unsigned long flags;
344 int nconn, want = rp->level3cnt;
345
346 if (want > 0) nconn = want;
347 else nconn = ctrl->profile.nbchannel * -want;
348 if (nconn == 0) nconn = ctrl->profile.nbchannel;
349
350 spin_lock_irqsave(&card->lock, flags);
351 b1_put_byte(port, SEND_REGISTER);
352 b1_put_word(port, appl);
353 b1_put_word(port, 1024 * (nconn+1));
354 b1_put_word(port, nconn);
355 b1_put_word(port, rp->datablkcnt);
356 b1_put_word(port, rp->datablklen);
357 spin_unlock_irqrestore(&card->lock, flags);
358}
359
360void b1_release_appl(struct capi_ctr *ctrl, u16 appl)
361{
362 avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
363 avmcard *card = cinfo->card;
364 unsigned int port = card->port;
365 unsigned long flags;
366
367 capilib_release_appl(&cinfo->ncci_head, appl);
368
369 spin_lock_irqsave(&card->lock, flags);
370 b1_put_byte(port, SEND_RELEASE);
371 b1_put_word(port, appl);
372 spin_unlock_irqrestore(&card->lock, flags);
373}
374
375u16 b1_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
376{
377 avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
378 avmcard *card = cinfo->card;
379 unsigned int port = card->port;
380 unsigned long flags;
381 u16 len = CAPIMSG_LEN(skb->data);
382 u8 cmd = CAPIMSG_COMMAND(skb->data);
383 u8 subcmd = CAPIMSG_SUBCOMMAND(skb->data);
384 u16 dlen, retval;
385
386 if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) {
387 retval = capilib_data_b3_req(&cinfo->ncci_head,
388 CAPIMSG_APPID(skb->data),
389 CAPIMSG_NCCI(skb->data),
390 CAPIMSG_MSGID(skb->data));
391 if (retval != CAPI_NOERROR)
392 return retval;
393
394 dlen = CAPIMSG_DATALEN(skb->data);
395
396 spin_lock_irqsave(&card->lock, flags);
397 b1_put_byte(port, SEND_DATA_B3_REQ);
398 b1_put_slice(port, skb->data, len);
399 b1_put_slice(port, skb->data + len, dlen);
400 spin_unlock_irqrestore(&card->lock, flags);
401 } else {
402 spin_lock_irqsave(&card->lock, flags);
403 b1_put_byte(port, SEND_MESSAGE);
404 b1_put_slice(port, skb->data, len);
405 spin_unlock_irqrestore(&card->lock, flags);
406 }
407
408 dev_kfree_skb_any(skb);
409 return CAPI_NOERROR;
410}
411
412/* ------------------------------------------------------------- */
413
414void b1_parse_version(avmctrl_info *cinfo)
415{
416 struct capi_ctr *ctrl = &cinfo->capi_ctrl;
417 avmcard *card = cinfo->card;
418 capi_profile *profp;
419 u8 *dversion;
420 u8 flag;
421 int i, j;
422
423 for (j = 0; j < AVM_MAXVERSION; j++)
424 cinfo->version[j] = "\0\0" + 1;
425 for (i = 0, j = 0;
426 j < AVM_MAXVERSION && i < cinfo->versionlen;
427 j++, i += cinfo->versionbuf[i] + 1)
428 cinfo->version[j] = &cinfo->versionbuf[i + 1];
429
430 strlcpy(ctrl->serial, cinfo->version[VER_SERIAL], sizeof(ctrl->serial));
431 memcpy(&ctrl->profile, cinfo->version[VER_PROFILE],sizeof(capi_profile));
432 strlcpy(ctrl->manu, "AVM GmbH", sizeof(ctrl->manu));
433 dversion = cinfo->version[VER_DRIVER];
434 ctrl->version.majorversion = 2;
435 ctrl->version.minorversion = 0;
436 ctrl->version.majormanuversion = (((dversion[0] - '0') & 0xf) << 4);
437 ctrl->version.majormanuversion |= ((dversion[2] - '0') & 0xf);
438 ctrl->version.minormanuversion = (dversion[3] - '0') << 4;
439 ctrl->version.minormanuversion |=
440 (dversion[5] - '0') * 10 + ((dversion[6] - '0') & 0xf);
441
442 profp = &ctrl->profile;
443
444 flag = ((u8 *)(profp->manu))[1];
445 switch (flag) {
446 case 0: if (cinfo->version[VER_CARDTYPE])
447 strcpy(cinfo->cardname, cinfo->version[VER_CARDTYPE]);
448 else strcpy(cinfo->cardname, "B1");
449 break;
450 case 3: strcpy(cinfo->cardname,"PCMCIA B"); break;
451 case 4: strcpy(cinfo->cardname,"PCMCIA M1"); break;
452 case 5: strcpy(cinfo->cardname,"PCMCIA M2"); break;
453 case 6: strcpy(cinfo->cardname,"B1 V3.0"); break;
454 case 7: strcpy(cinfo->cardname,"B1 PCI"); break;
455 default: sprintf(cinfo->cardname, "AVM?%u", (unsigned int)flag); break;
456 }
457 printk(KERN_NOTICE "%s: card %d \"%s\" ready.\n",
458 card->name, ctrl->cnr, cinfo->cardname);
459
460 flag = ((u8 *)(profp->manu))[3];
461 if (flag)
462 printk(KERN_NOTICE "%s: card %d Protocol:%s%s%s%s%s%s%s\n",
463 card->name,
464 ctrl->cnr,
465 (flag & 0x01) ? " DSS1" : "",
466 (flag & 0x02) ? " CT1" : "",
467 (flag & 0x04) ? " VN3" : "",
468 (flag & 0x08) ? " NI1" : "",
469 (flag & 0x10) ? " AUSTEL" : "",
470 (flag & 0x20) ? " ESS" : "",
471 (flag & 0x40) ? " 1TR6" : ""
472 );
473
474 flag = ((u8 *)(profp->manu))[5];
475 if (flag)
476 printk(KERN_NOTICE "%s: card %d Linetype:%s%s%s%s\n",
477 card->name,
478 ctrl->cnr,
479 (flag & 0x01) ? " point to point" : "",
480 (flag & 0x02) ? " point to multipoint" : "",
481 (flag & 0x08) ? " leased line without D-channel" : "",
482 (flag & 0x04) ? " leased line with D-channel" : ""
483 );
484}
485
486/* ------------------------------------------------------------- */
487
488irqreturn_t b1_interrupt(int interrupt, void *devptr, struct pt_regs *regs)
489{
490 avmcard *card = devptr;
491 avmctrl_info *cinfo = &card->ctrlinfo[0];
492 struct capi_ctr *ctrl = &cinfo->capi_ctrl;
493 unsigned char b1cmd;
494 struct sk_buff *skb;
495
496 unsigned ApplId;
497 unsigned MsgLen;
498 unsigned DataB3Len;
499 unsigned NCCI;
500 unsigned WindowSize;
501 unsigned long flags;
502
503 spin_lock_irqsave(&card->lock, flags);
504
505 if (!b1_rx_full(card->port)) {
506 spin_unlock_irqrestore(&card->lock, flags);
507 return IRQ_NONE;
508 }
509
510 b1cmd = b1_get_byte(card->port);
511
512 switch (b1cmd) {
513
514 case RECEIVE_DATA_B3_IND:
515
516 ApplId = (unsigned) b1_get_word(card->port);
517 MsgLen = b1_get_slice(card->port, card->msgbuf);
518 DataB3Len = b1_get_slice(card->port, card->databuf);
519 spin_unlock_irqrestore(&card->lock, flags);
520
521 if (MsgLen < 30) { /* not CAPI 64Bit */
522 memset(card->msgbuf+MsgLen, 0, 30-MsgLen);
523 MsgLen = 30;
524 CAPIMSG_SETLEN(card->msgbuf, 30);
525 }
526 if (!(skb = alloc_skb(DataB3Len + MsgLen, GFP_ATOMIC))) {
527 printk(KERN_ERR "%s: incoming packet dropped\n",
528 card->name);
529 } else {
530 memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
531 memcpy(skb_put(skb, DataB3Len), card->databuf, DataB3Len);
532 capi_ctr_handle_message(ctrl, ApplId, skb);
533 }
534 break;
535
536 case RECEIVE_MESSAGE:
537
538 ApplId = (unsigned) b1_get_word(card->port);
539 MsgLen = b1_get_slice(card->port, card->msgbuf);
540 spin_unlock_irqrestore(&card->lock, flags);
541 if (!(skb = alloc_skb(MsgLen, GFP_ATOMIC))) {
542 printk(KERN_ERR "%s: incoming packet dropped\n",
543 card->name);
544 } else {
545 memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
546 if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_CONF)
547 capilib_data_b3_conf(&cinfo->ncci_head, ApplId,
548 CAPIMSG_NCCI(skb->data),
549 CAPIMSG_MSGID(skb->data));
550
551 capi_ctr_handle_message(ctrl, ApplId, skb);
552 }
553 break;
554
555 case RECEIVE_NEW_NCCI:
556
557 ApplId = b1_get_word(card->port);
558 NCCI = b1_get_word(card->port);
559 WindowSize = b1_get_word(card->port);
560 spin_unlock_irqrestore(&card->lock, flags);
561
562 capilib_new_ncci(&cinfo->ncci_head, ApplId, NCCI, WindowSize);
563
564 break;
565
566 case RECEIVE_FREE_NCCI:
567
568 ApplId = b1_get_word(card->port);
569 NCCI = b1_get_word(card->port);
570 spin_unlock_irqrestore(&card->lock, flags);
571
572 if (NCCI != 0xffffffff)
573 capilib_free_ncci(&cinfo->ncci_head, ApplId, NCCI);
574
575 break;
576
577 case RECEIVE_START:
578 /* b1_put_byte(card->port, SEND_POLLACK); */
579 spin_unlock_irqrestore(&card->lock, flags);
580 capi_ctr_resume_output(ctrl);
581 break;
582
583 case RECEIVE_STOP:
584 spin_unlock_irqrestore(&card->lock, flags);
585 capi_ctr_suspend_output(ctrl);
586 break;
587
588 case RECEIVE_INIT:
589
590 cinfo->versionlen = b1_get_slice(card->port, cinfo->versionbuf);
591 spin_unlock_irqrestore(&card->lock, flags);
592 b1_parse_version(cinfo);
593 printk(KERN_INFO "%s: %s-card (%s) now active\n",
594 card->name,
595 cinfo->version[VER_CARDTYPE],
596 cinfo->version[VER_DRIVER]);
597 capi_ctr_ready(ctrl);
598 break;
599
600 case RECEIVE_TASK_READY:
601 ApplId = (unsigned) b1_get_word(card->port);
602 MsgLen = b1_get_slice(card->port, card->msgbuf);
603 spin_unlock_irqrestore(&card->lock, flags);
604 card->msgbuf[MsgLen] = 0;
605 while ( MsgLen > 0
606 && ( card->msgbuf[MsgLen-1] == '\n'
607 || card->msgbuf[MsgLen-1] == '\r')) {
608 card->msgbuf[MsgLen-1] = 0;
609 MsgLen--;
610 }
611 printk(KERN_INFO "%s: task %d \"%s\" ready.\n",
612 card->name, ApplId, card->msgbuf);
613 break;
614
615 case RECEIVE_DEBUGMSG:
616 MsgLen = b1_get_slice(card->port, card->msgbuf);
617 spin_unlock_irqrestore(&card->lock, flags);
618 card->msgbuf[MsgLen] = 0;
619 while ( MsgLen > 0
620 && ( card->msgbuf[MsgLen-1] == '\n'
621 || card->msgbuf[MsgLen-1] == '\r')) {
622 card->msgbuf[MsgLen-1] = 0;
623 MsgLen--;
624 }
625 printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf);
626 break;
627
628 case 0xff:
629 spin_unlock_irqrestore(&card->lock, flags);
630 printk(KERN_ERR "%s: card removed ?\n", card->name);
631 return IRQ_NONE;
632 default:
633 spin_unlock_irqrestore(&card->lock, flags);
634 printk(KERN_ERR "%s: b1_interrupt: 0x%x ???\n",
635 card->name, b1cmd);
636 return IRQ_HANDLED;
637 }
638 return IRQ_HANDLED;
639}
640
641/* ------------------------------------------------------------- */
642int b1ctl_read_proc(char *page, char **start, off_t off,
643 int count, int *eof, struct capi_ctr *ctrl)
644{
645 avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
646 avmcard *card = cinfo->card;
647 u8 flag;
648 int len = 0;
649 char *s;
650
651 len += sprintf(page+len, "%-16s %s\n", "name", card->name);
652 len += sprintf(page+len, "%-16s 0x%x\n", "io", card->port);
653 len += sprintf(page+len, "%-16s %d\n", "irq", card->irq);
654 switch (card->cardtype) {
655 case avm_b1isa: s = "B1 ISA"; break;
656 case avm_b1pci: s = "B1 PCI"; break;
657 case avm_b1pcmcia: s = "B1 PCMCIA"; break;
658 case avm_m1: s = "M1"; break;
659 case avm_m2: s = "M2"; break;
660 case avm_t1isa: s = "T1 ISA (HEMA)"; break;
661 case avm_t1pci: s = "T1 PCI"; break;
662 case avm_c4: s = "C4"; break;
663 case avm_c2: s = "C2"; break;
664 default: s = "???"; break;
665 }
666 len += sprintf(page+len, "%-16s %s\n", "type", s);
667 if (card->cardtype == avm_t1isa)
668 len += sprintf(page+len, "%-16s %d\n", "cardnr", card->cardnr);
669 if ((s = cinfo->version[VER_DRIVER]) != 0)
670 len += sprintf(page+len, "%-16s %s\n", "ver_driver", s);
671 if ((s = cinfo->version[VER_CARDTYPE]) != 0)
672 len += sprintf(page+len, "%-16s %s\n", "ver_cardtype", s);
673 if ((s = cinfo->version[VER_SERIAL]) != 0)
674 len += sprintf(page+len, "%-16s %s\n", "ver_serial", s);
675
676 if (card->cardtype != avm_m1) {
677 flag = ((u8 *)(ctrl->profile.manu))[3];
678 if (flag)
679 len += sprintf(page+len, "%-16s%s%s%s%s%s%s%s\n",
680 "protocol",
681 (flag & 0x01) ? " DSS1" : "",
682 (flag & 0x02) ? " CT1" : "",
683 (flag & 0x04) ? " VN3" : "",
684 (flag & 0x08) ? " NI1" : "",
685 (flag & 0x10) ? " AUSTEL" : "",
686 (flag & 0x20) ? " ESS" : "",
687 (flag & 0x40) ? " 1TR6" : ""
688 );
689 }
690 if (card->cardtype != avm_m1) {
691 flag = ((u8 *)(ctrl->profile.manu))[5];
692 if (flag)
693 len += sprintf(page+len, "%-16s%s%s%s%s\n",
694 "linetype",
695 (flag & 0x01) ? " point to point" : "",
696 (flag & 0x02) ? " point to multipoint" : "",
697 (flag & 0x08) ? " leased line without D-channel" : "",
698 (flag & 0x04) ? " leased line with D-channel" : ""
699 );
700 }
701 len += sprintf(page+len, "%-16s %s\n", "cardname", cinfo->cardname);
702
703 if (off+count >= len)
704 *eof = 1;
705 if (len < off)
706 return 0;
707 *start = page + off;
708 return ((count < len-off) ? count : len-off);
709}
710
711/* ------------------------------------------------------------- */
712
713#ifdef CONFIG_PCI
714
715avmcard_dmainfo *
716avmcard_dma_alloc(char *name, struct pci_dev *pdev, long rsize, long ssize)
717{
718 avmcard_dmainfo *p;
719 void *buf;
720
721 p = kmalloc(sizeof(avmcard_dmainfo), GFP_KERNEL);
722 if (!p) {
723 printk(KERN_WARNING "%s: no memory.\n", name);
724 goto err;
725 }
726 memset(p, 0, sizeof(avmcard_dmainfo));
727
728 p->recvbuf.size = rsize;
729 buf = pci_alloc_consistent(pdev, rsize, &p->recvbuf.dmaaddr);
730 if (!buf) {
731 printk(KERN_WARNING "%s: allocation of receive dma buffer failed.\n", name);
732 goto err_kfree;
733 }
734 p->recvbuf.dmabuf = buf;
735
736 p->sendbuf.size = ssize;
737 buf = pci_alloc_consistent(pdev, ssize, &p->sendbuf.dmaaddr);
738 if (!buf) {
739 printk(KERN_WARNING "%s: allocation of send dma buffer failed.\n", name);
740 goto err_free_consistent;
741 }
742
743 p->sendbuf.dmabuf = buf;
744 skb_queue_head_init(&p->send_queue);
745
746 return p;
747
748 err_free_consistent:
749 pci_free_consistent(p->pcidev, p->recvbuf.size,
750 p->recvbuf.dmabuf, p->recvbuf.dmaaddr);
751 err_kfree:
752 kfree(p);
753 err:
754 return NULL;
755}
756
757void avmcard_dma_free(avmcard_dmainfo *p)
758{
759 pci_free_consistent(p->pcidev, p->recvbuf.size,
760 p->recvbuf.dmabuf, p->recvbuf.dmaaddr);
761 pci_free_consistent(p->pcidev, p->sendbuf.size,
762 p->sendbuf.dmabuf, p->sendbuf.dmaaddr);
763 skb_queue_purge(&p->send_queue);
764 kfree(p);
765}
766
767EXPORT_SYMBOL(avmcard_dma_alloc);
768EXPORT_SYMBOL(avmcard_dma_free);
769
770#endif
771
772EXPORT_SYMBOL(b1_irq_table);
773
774EXPORT_SYMBOL(b1_alloc_card);
775EXPORT_SYMBOL(b1_free_card);
776EXPORT_SYMBOL(b1_detect);
777EXPORT_SYMBOL(b1_getrevision);
778EXPORT_SYMBOL(b1_load_t4file);
779EXPORT_SYMBOL(b1_load_config);
780EXPORT_SYMBOL(b1_loaded);
781EXPORT_SYMBOL(b1_load_firmware);
782EXPORT_SYMBOL(b1_reset_ctr);
783EXPORT_SYMBOL(b1_register_appl);
784EXPORT_SYMBOL(b1_release_appl);
785EXPORT_SYMBOL(b1_send_message);
786
787EXPORT_SYMBOL(b1_parse_version);
788EXPORT_SYMBOL(b1_interrupt);
789
790EXPORT_SYMBOL(b1ctl_read_proc);
791
792static int __init b1_init(void)
793{
794 char *p;
795 char rev[32];
796
797 if ((p = strchr(revision, ':')) != 0 && p[1]) {
798 strlcpy(rev, p + 2, 32);
799 if ((p = strchr(rev, '$')) != 0 && p > rev)
800 *(p-1) = 0;
801 } else
802 strcpy(rev, "1.0");
803
804 printk(KERN_INFO "b1: revision %s\n", rev);
805
806 return 0;
807}
808
809static void __exit b1_exit(void)
810{
811}
812
813module_init(b1_init);
814module_exit(b1_exit);
diff --git a/drivers/isdn/hardware/avm/b1dma.c b/drivers/isdn/hardware/avm/b1dma.c
new file mode 100644
index 000000000000..55bed00ca865
--- /dev/null
+++ b/drivers/isdn/hardware/avm/b1dma.c
@@ -0,0 +1,980 @@
1/* $Id: b1dma.c,v 1.1.2.3 2004/02/10 01:07:12 keil Exp $
2 *
3 * Common module for AVM B1 cards that support dma with AMCC
4 *
5 * Copyright 2000 by Carsten Paeth <calle@calle.de>
6 *
7 * This software may be used and distributed according to the terms
8 * of the GNU General Public License, incorporated herein by reference.
9 *
10 */
11
12#include <linux/config.h>
13#include <linux/module.h>
14#include <linux/kernel.h>
15#include <linux/skbuff.h>
16#include <linux/delay.h>
17#include <linux/mm.h>
18#include <linux/interrupt.h>
19#include <linux/ioport.h>
20#include <linux/capi.h>
21#include <linux/kernelcapi.h>
22#include <asm/io.h>
23#include <linux/init.h>
24#include <asm/uaccess.h>
25#include <linux/netdevice.h>
26#include <linux/isdn/capilli.h>
27#include "avmcard.h"
28#include <linux/isdn/capicmd.h>
29#include <linux/isdn/capiutil.h>
30
31static char *revision = "$Revision: 1.1.2.3 $";
32
33#undef CONFIG_B1DMA_DEBUG
34
35/* ------------------------------------------------------------- */
36
37MODULE_DESCRIPTION("CAPI4Linux: DMA support for active AVM cards");
38MODULE_AUTHOR("Carsten Paeth");
39MODULE_LICENSE("GPL");
40
41static int suppress_pollack = 0;
42MODULE_PARM(suppress_pollack, "0-1i");
43
44/* ------------------------------------------------------------- */
45
46static void b1dma_dispatch_tx(avmcard *card);
47
48/* ------------------------------------------------------------- */
49
50/* S5933 */
51
52#define AMCC_RXPTR 0x24
53#define AMCC_RXLEN 0x28
54#define AMCC_TXPTR 0x2c
55#define AMCC_TXLEN 0x30
56
57#define AMCC_INTCSR 0x38
58# define EN_READ_TC_INT 0x00008000L
59# define EN_WRITE_TC_INT 0x00004000L
60# define EN_TX_TC_INT EN_READ_TC_INT
61# define EN_RX_TC_INT EN_WRITE_TC_INT
62# define AVM_FLAG 0x30000000L
63
64# define ANY_S5933_INT 0x00800000L
65# define READ_TC_INT 0x00080000L
66# define WRITE_TC_INT 0x00040000L
67# define TX_TC_INT READ_TC_INT
68# define RX_TC_INT WRITE_TC_INT
69# define MASTER_ABORT_INT 0x00100000L
70# define TARGET_ABORT_INT 0x00200000L
71# define BUS_MASTER_INT 0x00200000L
72# define ALL_INT 0x000C0000L
73
74#define AMCC_MCSR 0x3c
75# define A2P_HI_PRIORITY 0x00000100L
76# define EN_A2P_TRANSFERS 0x00000400L
77# define P2A_HI_PRIORITY 0x00001000L
78# define EN_P2A_TRANSFERS 0x00004000L
79# define RESET_A2P_FLAGS 0x04000000L
80# define RESET_P2A_FLAGS 0x02000000L
81
82/* ------------------------------------------------------------- */
83
84static inline void b1dma_writel(avmcard *card, u32 value, int off)
85{
86 writel(value, card->mbase + off);
87}
88
89static inline u32 b1dma_readl(avmcard *card, int off)
90{
91 return readl(card->mbase + off);
92}
93
94/* ------------------------------------------------------------- */
95
96static inline int b1dma_tx_empty(unsigned int port)
97{
98 return inb(port + 0x03) & 0x1;
99}
100
101static inline int b1dma_rx_full(unsigned int port)
102{
103 return inb(port + 0x02) & 0x1;
104}
105
106static int b1dma_tolink(avmcard *card, void *buf, unsigned int len)
107{
108 unsigned long stop = jiffies + 1 * HZ; /* maximum wait time 1 sec */
109 unsigned char *s = (unsigned char *)buf;
110 while (len--) {
111 while ( !b1dma_tx_empty(card->port)
112 && time_before(jiffies, stop));
113 if (!b1dma_tx_empty(card->port))
114 return -1;
115 t1outp(card->port, 0x01, *s++);
116 }
117 return 0;
118}
119
120static int b1dma_fromlink(avmcard *card, void *buf, unsigned int len)
121{
122 unsigned long stop = jiffies + 1 * HZ; /* maximum wait time 1 sec */
123 unsigned char *s = (unsigned char *)buf;
124 while (len--) {
125 while ( !b1dma_rx_full(card->port)
126 && time_before(jiffies, stop));
127 if (!b1dma_rx_full(card->port))
128 return -1;
129 *s++ = t1inp(card->port, 0x00);
130 }
131 return 0;
132}
133
134static int WriteReg(avmcard *card, u32 reg, u8 val)
135{
136 u8 cmd = 0x00;
137 if ( b1dma_tolink(card, &cmd, 1) == 0
138 && b1dma_tolink(card, &reg, 4) == 0) {
139 u32 tmp = val;
140 return b1dma_tolink(card, &tmp, 4);
141 }
142 return -1;
143}
144
145static u8 ReadReg(avmcard *card, u32 reg)
146{
147 u8 cmd = 0x01;
148 if ( b1dma_tolink(card, &cmd, 1) == 0
149 && b1dma_tolink(card, &reg, 4) == 0) {
150 u32 tmp;
151 if (b1dma_fromlink(card, &tmp, 4) == 0)
152 return (u8)tmp;
153 }
154 return 0xff;
155}
156
157/* ------------------------------------------------------------- */
158
159static inline void _put_byte(void **pp, u8 val)
160{
161 u8 *s = *pp;
162 *s++ = val;
163 *pp = s;
164}
165
166static inline void _put_word(void **pp, u32 val)
167{
168 u8 *s = *pp;
169 *s++ = val & 0xff;
170 *s++ = (val >> 8) & 0xff;
171 *s++ = (val >> 16) & 0xff;
172 *s++ = (val >> 24) & 0xff;
173 *pp = s;
174}
175
176static inline void _put_slice(void **pp, unsigned char *dp, unsigned int len)
177{
178 unsigned i = len;
179 _put_word(pp, i);
180 while (i-- > 0)
181 _put_byte(pp, *dp++);
182}
183
184static inline u8 _get_byte(void **pp)
185{
186 u8 *s = *pp;
187 u8 val;
188 val = *s++;
189 *pp = s;
190 return val;
191}
192
193static inline u32 _get_word(void **pp)
194{
195 u8 *s = *pp;
196 u32 val;
197 val = *s++;
198 val |= (*s++ << 8);
199 val |= (*s++ << 16);
200 val |= (*s++ << 24);
201 *pp = s;
202 return val;
203}
204
205static inline u32 _get_slice(void **pp, unsigned char *dp)
206{
207 unsigned int len, i;
208
209 len = i = _get_word(pp);
210 while (i-- > 0) *dp++ = _get_byte(pp);
211 return len;
212}
213
214/* ------------------------------------------------------------- */
215
216void b1dma_reset(avmcard *card)
217{
218 card->csr = 0x0;
219 b1dma_writel(card, card->csr, AMCC_INTCSR);
220 b1dma_writel(card, 0, AMCC_MCSR);
221 b1dma_writel(card, 0, AMCC_RXLEN);
222 b1dma_writel(card, 0, AMCC_TXLEN);
223
224 t1outp(card->port, 0x10, 0x00);
225 t1outp(card->port, 0x07, 0x00);
226
227 b1dma_writel(card, 0, AMCC_MCSR);
228 mdelay(10);
229 b1dma_writel(card, 0x0f000000, AMCC_MCSR); /* reset all */
230 mdelay(10);
231 b1dma_writel(card, 0, AMCC_MCSR);
232 if (card->cardtype == avm_t1pci)
233 mdelay(42);
234 else
235 mdelay(10);
236}
237
238/* ------------------------------------------------------------- */
239
240static int b1dma_detect(avmcard *card)
241{
242 b1dma_writel(card, 0, AMCC_MCSR);
243 mdelay(10);
244 b1dma_writel(card, 0x0f000000, AMCC_MCSR); /* reset all */
245 mdelay(10);
246 b1dma_writel(card, 0, AMCC_MCSR);
247 mdelay(42);
248
249 b1dma_writel(card, 0, AMCC_RXLEN);
250 b1dma_writel(card, 0, AMCC_TXLEN);
251 card->csr = 0x0;
252 b1dma_writel(card, card->csr, AMCC_INTCSR);
253
254 if (b1dma_readl(card, AMCC_MCSR) != 0x000000E6)
255 return 1;
256
257 b1dma_writel(card, 0xffffffff, AMCC_RXPTR);
258 b1dma_writel(card, 0xffffffff, AMCC_TXPTR);
259 if ( b1dma_readl(card, AMCC_RXPTR) != 0xfffffffc
260 || b1dma_readl(card, AMCC_TXPTR) != 0xfffffffc)
261 return 2;
262
263 b1dma_writel(card, 0x0, AMCC_RXPTR);
264 b1dma_writel(card, 0x0, AMCC_TXPTR);
265 if ( b1dma_readl(card, AMCC_RXPTR) != 0x0
266 || b1dma_readl(card, AMCC_TXPTR) != 0x0)
267 return 3;
268
269 t1outp(card->port, 0x10, 0x00);
270 t1outp(card->port, 0x07, 0x00);
271
272 t1outp(card->port, 0x02, 0x02);
273 t1outp(card->port, 0x03, 0x02);
274
275 if ( (t1inp(card->port, 0x02) & 0xFE) != 0x02
276 || t1inp(card->port, 0x3) != 0x03)
277 return 4;
278
279 t1outp(card->port, 0x02, 0x00);
280 t1outp(card->port, 0x03, 0x00);
281
282 if ( (t1inp(card->port, 0x02) & 0xFE) != 0x00
283 || t1inp(card->port, 0x3) != 0x01)
284 return 5;
285
286 return 0;
287}
288
289int t1pci_detect(avmcard *card)
290{
291 int ret;
292
293 if ((ret = b1dma_detect(card)) != 0)
294 return ret;
295
296 /* Transputer test */
297
298 if ( WriteReg(card, 0x80001000, 0x11) != 0
299 || WriteReg(card, 0x80101000, 0x22) != 0
300 || WriteReg(card, 0x80201000, 0x33) != 0
301 || WriteReg(card, 0x80301000, 0x44) != 0)
302 return 6;
303
304 if ( ReadReg(card, 0x80001000) != 0x11
305 || ReadReg(card, 0x80101000) != 0x22
306 || ReadReg(card, 0x80201000) != 0x33
307 || ReadReg(card, 0x80301000) != 0x44)
308 return 7;
309
310 if ( WriteReg(card, 0x80001000, 0x55) != 0
311 || WriteReg(card, 0x80101000, 0x66) != 0
312 || WriteReg(card, 0x80201000, 0x77) != 0
313 || WriteReg(card, 0x80301000, 0x88) != 0)
314 return 8;
315
316 if ( ReadReg(card, 0x80001000) != 0x55
317 || ReadReg(card, 0x80101000) != 0x66
318 || ReadReg(card, 0x80201000) != 0x77
319 || ReadReg(card, 0x80301000) != 0x88)
320 return 9;
321
322 return 0;
323}
324
325int b1pciv4_detect(avmcard *card)
326{
327 int ret, i;
328
329 if ((ret = b1dma_detect(card)) != 0)
330 return ret;
331
332 for (i=0; i < 5 ; i++) {
333 if (WriteReg(card, 0x80A00000, 0x21) != 0)
334 return 6;
335 if ((ReadReg(card, 0x80A00000) & 0x01) != 0x01)
336 return 7;
337 }
338 for (i=0; i < 5 ; i++) {
339 if (WriteReg(card, 0x80A00000, 0x20) != 0)
340 return 8;
341 if ((ReadReg(card, 0x80A00000) & 0x01) != 0x00)
342 return 9;
343 }
344
345 return 0;
346}
347
348static void b1dma_queue_tx(avmcard *card, struct sk_buff *skb)
349{
350 unsigned long flags;
351
352 spin_lock_irqsave(&card->lock, flags);
353
354 skb_queue_tail(&card->dma->send_queue, skb);
355
356 if (!(card->csr & EN_TX_TC_INT)) {
357 b1dma_dispatch_tx(card);
358 b1dma_writel(card, card->csr, AMCC_INTCSR);
359 }
360
361 spin_unlock_irqrestore(&card->lock, flags);
362}
363
364/* ------------------------------------------------------------- */
365
366static void b1dma_dispatch_tx(avmcard *card)
367{
368 avmcard_dmainfo *dma = card->dma;
369 struct sk_buff *skb;
370 u8 cmd, subcmd;
371 u16 len;
372 u32 txlen;
373 void *p;
374
375 skb = skb_dequeue(&dma->send_queue);
376
377 len = CAPIMSG_LEN(skb->data);
378
379 if (len) {
380 cmd = CAPIMSG_COMMAND(skb->data);
381 subcmd = CAPIMSG_SUBCOMMAND(skb->data);
382
383 p = dma->sendbuf.dmabuf;
384
385 if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) {
386 u16 dlen = CAPIMSG_DATALEN(skb->data);
387 _put_byte(&p, SEND_DATA_B3_REQ);
388 _put_slice(&p, skb->data, len);
389 _put_slice(&p, skb->data + len, dlen);
390 } else {
391 _put_byte(&p, SEND_MESSAGE);
392 _put_slice(&p, skb->data, len);
393 }
394 txlen = (u8 *)p - (u8 *)dma->sendbuf.dmabuf;
395#ifdef CONFIG_B1DMA_DEBUG
396 printk(KERN_DEBUG "tx: put msg len=%d\n", txlen);
397#endif
398 } else {
399 txlen = skb->len-2;
400#ifdef CONFIG_B1DMA_POLLDEBUG
401 if (skb->data[2] == SEND_POLLACK)
402 printk(KERN_INFO "%s: send ack\n", card->name);
403#endif
404#ifdef CONFIG_B1DMA_DEBUG
405 printk(KERN_DEBUG "tx: put 0x%x len=%d\n",
406 skb->data[2], txlen);
407#endif
408 memcpy(dma->sendbuf.dmabuf, skb->data+2, skb->len-2);
409 }
410 txlen = (txlen + 3) & ~3;
411
412 b1dma_writel(card, dma->sendbuf.dmaaddr, AMCC_TXPTR);
413 b1dma_writel(card, txlen, AMCC_TXLEN);
414
415 card->csr |= EN_TX_TC_INT;
416
417 dev_kfree_skb_any(skb);
418}
419
420/* ------------------------------------------------------------- */
421
422static void queue_pollack(avmcard *card)
423{
424 struct sk_buff *skb;
425 void *p;
426
427 skb = alloc_skb(3, GFP_ATOMIC);
428 if (!skb) {
429 printk(KERN_CRIT "%s: no memory, lost poll ack\n",
430 card->name);
431 return;
432 }
433 p = skb->data;
434 _put_byte(&p, 0);
435 _put_byte(&p, 0);
436 _put_byte(&p, SEND_POLLACK);
437 skb_put(skb, (u8 *)p - (u8 *)skb->data);
438
439 b1dma_queue_tx(card, skb);
440}
441
442/* ------------------------------------------------------------- */
443
444static void b1dma_handle_rx(avmcard *card)
445{
446 avmctrl_info *cinfo = &card->ctrlinfo[0];
447 avmcard_dmainfo *dma = card->dma;
448 struct capi_ctr *ctrl = &cinfo->capi_ctrl;
449 struct sk_buff *skb;
450 void *p = dma->recvbuf.dmabuf+4;
451 u32 ApplId, MsgLen, DataB3Len, NCCI, WindowSize;
452 u8 b1cmd = _get_byte(&p);
453
454#ifdef CONFIG_B1DMA_DEBUG
455 printk(KERN_DEBUG "rx: 0x%x %lu\n", b1cmd, (unsigned long)dma->recvlen);
456#endif
457
458 switch (b1cmd) {
459 case RECEIVE_DATA_B3_IND:
460
461 ApplId = (unsigned) _get_word(&p);
462 MsgLen = _get_slice(&p, card->msgbuf);
463 DataB3Len = _get_slice(&p, card->databuf);
464
465 if (MsgLen < 30) { /* not CAPI 64Bit */
466 memset(card->msgbuf+MsgLen, 0, 30-MsgLen);
467 MsgLen = 30;
468 CAPIMSG_SETLEN(card->msgbuf, 30);
469 }
470 if (!(skb = alloc_skb(DataB3Len+MsgLen, GFP_ATOMIC))) {
471 printk(KERN_ERR "%s: incoming packet dropped\n",
472 card->name);
473 } else {
474 memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
475 memcpy(skb_put(skb, DataB3Len), card->databuf, DataB3Len);
476 capi_ctr_handle_message(ctrl, ApplId, skb);
477 }
478 break;
479
480 case RECEIVE_MESSAGE:
481
482 ApplId = (unsigned) _get_word(&p);
483 MsgLen = _get_slice(&p, card->msgbuf);
484 if (!(skb = alloc_skb(MsgLen, GFP_ATOMIC))) {
485 printk(KERN_ERR "%s: incoming packet dropped\n",
486 card->name);
487 } else {
488 memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
489 if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_CONF)
490 capilib_data_b3_conf(&cinfo->ncci_head, ApplId,
491 CAPIMSG_NCCI(skb->data),
492 CAPIMSG_MSGID(skb->data));
493
494 capi_ctr_handle_message(ctrl, ApplId, skb);
495 }
496 break;
497
498 case RECEIVE_NEW_NCCI:
499
500 ApplId = _get_word(&p);
501 NCCI = _get_word(&p);
502 WindowSize = _get_word(&p);
503
504 capilib_new_ncci(&cinfo->ncci_head, ApplId, NCCI, WindowSize);
505
506 break;
507
508 case RECEIVE_FREE_NCCI:
509
510 ApplId = _get_word(&p);
511 NCCI = _get_word(&p);
512
513 if (NCCI != 0xffffffff)
514 capilib_free_ncci(&cinfo->ncci_head, ApplId, NCCI);
515
516 break;
517
518 case RECEIVE_START:
519#ifdef CONFIG_B1DMA_POLLDEBUG
520 printk(KERN_INFO "%s: receive poll\n", card->name);
521#endif
522 if (!suppress_pollack)
523 queue_pollack(card);
524 capi_ctr_resume_output(ctrl);
525 break;
526
527 case RECEIVE_STOP:
528 capi_ctr_suspend_output(ctrl);
529 break;
530
531 case RECEIVE_INIT:
532
533 cinfo->versionlen = _get_slice(&p, cinfo->versionbuf);
534 b1_parse_version(cinfo);
535 printk(KERN_INFO "%s: %s-card (%s) now active\n",
536 card->name,
537 cinfo->version[VER_CARDTYPE],
538 cinfo->version[VER_DRIVER]);
539 capi_ctr_ready(ctrl);
540 break;
541
542 case RECEIVE_TASK_READY:
543 ApplId = (unsigned) _get_word(&p);
544 MsgLen = _get_slice(&p, card->msgbuf);
545 card->msgbuf[MsgLen] = 0;
546 while ( MsgLen > 0
547 && ( card->msgbuf[MsgLen-1] == '\n'
548 || card->msgbuf[MsgLen-1] == '\r')) {
549 card->msgbuf[MsgLen-1] = 0;
550 MsgLen--;
551 }
552 printk(KERN_INFO "%s: task %d \"%s\" ready.\n",
553 card->name, ApplId, card->msgbuf);
554 break;
555
556 case RECEIVE_DEBUGMSG:
557 MsgLen = _get_slice(&p, card->msgbuf);
558 card->msgbuf[MsgLen] = 0;
559 while ( MsgLen > 0
560 && ( card->msgbuf[MsgLen-1] == '\n'
561 || card->msgbuf[MsgLen-1] == '\r')) {
562 card->msgbuf[MsgLen-1] = 0;
563 MsgLen--;
564 }
565 printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf);
566 break;
567
568 default:
569 printk(KERN_ERR "%s: b1dma_interrupt: 0x%x ???\n",
570 card->name, b1cmd);
571 return;
572 }
573}
574
575/* ------------------------------------------------------------- */
576
577static void b1dma_handle_interrupt(avmcard *card)
578{
579 u32 status;
580 u32 newcsr;
581
582 spin_lock(&card->lock);
583
584 status = b1dma_readl(card, AMCC_INTCSR);
585 if ((status & ANY_S5933_INT) == 0) {
586 spin_unlock(&card->lock);
587 return;
588 }
589
590 newcsr = card->csr | (status & ALL_INT);
591 if (status & TX_TC_INT) newcsr &= ~EN_TX_TC_INT;
592 if (status & RX_TC_INT) newcsr &= ~EN_RX_TC_INT;
593 b1dma_writel(card, newcsr, AMCC_INTCSR);
594
595 if ((status & RX_TC_INT) != 0) {
596 struct avmcard_dmainfo *dma = card->dma;
597 u32 rxlen;
598 if (card->dma->recvlen == 0) {
599 rxlen = b1dma_readl(card, AMCC_RXLEN);
600 if (rxlen == 0) {
601 dma->recvlen = *((u32 *)dma->recvbuf.dmabuf);
602 rxlen = (dma->recvlen + 3) & ~3;
603 b1dma_writel(card, dma->recvbuf.dmaaddr+4, AMCC_RXPTR);
604 b1dma_writel(card, rxlen, AMCC_RXLEN);
605#ifdef CONFIG_B1DMA_DEBUG
606 } else {
607 printk(KERN_ERR "%s: rx not complete (%d).\n",
608 card->name, rxlen);
609#endif
610 }
611 } else {
612 spin_unlock(&card->lock);
613 b1dma_handle_rx(card);
614 dma->recvlen = 0;
615 spin_lock(&card->lock);
616 b1dma_writel(card, dma->recvbuf.dmaaddr, AMCC_RXPTR);
617 b1dma_writel(card, 4, AMCC_RXLEN);
618 }
619 }
620
621 if ((status & TX_TC_INT) != 0) {
622 if (skb_queue_empty(&card->dma->send_queue))
623 card->csr &= ~EN_TX_TC_INT;
624 else
625 b1dma_dispatch_tx(card);
626 }
627 b1dma_writel(card, card->csr, AMCC_INTCSR);
628
629 spin_unlock(&card->lock);
630}
631
632irqreturn_t b1dma_interrupt(int interrupt, void *devptr, struct pt_regs *regs)
633{
634 avmcard *card = devptr;
635
636 b1dma_handle_interrupt(card);
637 return IRQ_HANDLED;
638}
639
640/* ------------------------------------------------------------- */
641
642static int b1dma_loaded(avmcard *card)
643{
644 unsigned long stop;
645 unsigned char ans;
646 unsigned long tout = 2;
647 unsigned int base = card->port;
648
649 for (stop = jiffies + tout * HZ; time_before(jiffies, stop);) {
650 if (b1_tx_empty(base))
651 break;
652 }
653 if (!b1_tx_empty(base)) {
654 printk(KERN_ERR "%s: b1dma_loaded: tx err, corrupted t4 file ?\n",
655 card->name);
656 return 0;
657 }
658 b1_put_byte(base, SEND_POLLACK);
659 for (stop = jiffies + tout * HZ; time_before(jiffies, stop);) {
660 if (b1_rx_full(base)) {
661 if ((ans = b1_get_byte(base)) == RECEIVE_POLLDWORD) {
662 return 1;
663 }
664 printk(KERN_ERR "%s: b1dma_loaded: got 0x%x, firmware not running in dword mode\n", card->name, ans);
665 return 0;
666 }
667 }
668 printk(KERN_ERR "%s: b1dma_loaded: firmware not running\n", card->name);
669 return 0;
670}
671
672/* ------------------------------------------------------------- */
673
674static void b1dma_send_init(avmcard *card)
675{
676 struct sk_buff *skb;
677 void *p;
678
679 skb = alloc_skb(15, GFP_ATOMIC);
680 if (!skb) {
681 printk(KERN_CRIT "%s: no memory, lost register appl.\n",
682 card->name);
683 return;
684 }
685 p = skb->data;
686 _put_byte(&p, 0);
687 _put_byte(&p, 0);
688 _put_byte(&p, SEND_INIT);
689 _put_word(&p, CAPI_MAXAPPL);
690 _put_word(&p, AVM_NCCI_PER_CHANNEL*30);
691 _put_word(&p, card->cardnr - 1);
692 skb_put(skb, (u8 *)p - (u8 *)skb->data);
693
694 b1dma_queue_tx(card, skb);
695}
696
697int b1dma_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
698{
699 avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
700 avmcard *card = cinfo->card;
701 int retval;
702
703 b1dma_reset(card);
704
705 if ((retval = b1_load_t4file(card, &data->firmware))) {
706 b1dma_reset(card);
707 printk(KERN_ERR "%s: failed to load t4file!!\n",
708 card->name);
709 return retval;
710 }
711
712 if (data->configuration.len > 0 && data->configuration.data) {
713 if ((retval = b1_load_config(card, &data->configuration))) {
714 b1dma_reset(card);
715 printk(KERN_ERR "%s: failed to load config!!\n",
716 card->name);
717 return retval;
718 }
719 }
720
721 if (!b1dma_loaded(card)) {
722 b1dma_reset(card);
723 printk(KERN_ERR "%s: failed to load t4file.\n", card->name);
724 return -EIO;
725 }
726
727 card->csr = AVM_FLAG;
728 b1dma_writel(card, card->csr, AMCC_INTCSR);
729 b1dma_writel(card, EN_A2P_TRANSFERS|EN_P2A_TRANSFERS|A2P_HI_PRIORITY|
730 P2A_HI_PRIORITY|RESET_A2P_FLAGS|RESET_P2A_FLAGS,
731 AMCC_MCSR);
732 t1outp(card->port, 0x07, 0x30);
733 t1outp(card->port, 0x10, 0xF0);
734
735 card->dma->recvlen = 0;
736 b1dma_writel(card, card->dma->recvbuf.dmaaddr, AMCC_RXPTR);
737 b1dma_writel(card, 4, AMCC_RXLEN);
738 card->csr |= EN_RX_TC_INT;
739 b1dma_writel(card, card->csr, AMCC_INTCSR);
740
741 b1dma_send_init(card);
742
743 return 0;
744}
745
746void b1dma_reset_ctr(struct capi_ctr *ctrl)
747{
748 avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
749 avmcard *card = cinfo->card;
750 unsigned long flags;
751
752 spin_lock_irqsave(&card->lock, flags);
753 b1dma_reset(card);
754 spin_unlock_irqrestore(&card->lock, flags);
755
756 memset(cinfo->version, 0, sizeof(cinfo->version));
757 capilib_release(&cinfo->ncci_head);
758 capi_ctr_reseted(ctrl);
759}
760
761/* ------------------------------------------------------------- */
762
763void b1dma_register_appl(struct capi_ctr *ctrl,
764 u16 appl,
765 capi_register_params *rp)
766{
767 avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
768 avmcard *card = cinfo->card;
769 struct sk_buff *skb;
770 int want = rp->level3cnt;
771 int nconn;
772 void *p;
773
774 if (want > 0) nconn = want;
775 else nconn = ctrl->profile.nbchannel * -want;
776 if (nconn == 0) nconn = ctrl->profile.nbchannel;
777
778 skb = alloc_skb(23, GFP_ATOMIC);
779 if (!skb) {
780 printk(KERN_CRIT "%s: no memory, lost register appl.\n",
781 card->name);
782 return;
783 }
784 p = skb->data;
785 _put_byte(&p, 0);
786 _put_byte(&p, 0);
787 _put_byte(&p, SEND_REGISTER);
788 _put_word(&p, appl);
789 _put_word(&p, 1024 * (nconn+1));
790 _put_word(&p, nconn);
791 _put_word(&p, rp->datablkcnt);
792 _put_word(&p, rp->datablklen);
793 skb_put(skb, (u8 *)p - (u8 *)skb->data);
794
795 b1dma_queue_tx(card, skb);
796}
797
798/* ------------------------------------------------------------- */
799
800void b1dma_release_appl(struct capi_ctr *ctrl, u16 appl)
801{
802 avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
803 avmcard *card = cinfo->card;
804 struct sk_buff *skb;
805 void *p;
806
807 capilib_release_appl(&cinfo->ncci_head, appl);
808
809 skb = alloc_skb(7, GFP_ATOMIC);
810 if (!skb) {
811 printk(KERN_CRIT "%s: no memory, lost release appl.\n",
812 card->name);
813 return;
814 }
815 p = skb->data;
816 _put_byte(&p, 0);
817 _put_byte(&p, 0);
818 _put_byte(&p, SEND_RELEASE);
819 _put_word(&p, appl);
820
821 skb_put(skb, (u8 *)p - (u8 *)skb->data);
822
823 b1dma_queue_tx(card, skb);
824}
825
826/* ------------------------------------------------------------- */
827
828u16 b1dma_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
829{
830 avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
831 avmcard *card = cinfo->card;
832 u16 retval = CAPI_NOERROR;
833
834 if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_REQ) {
835 retval = capilib_data_b3_req(&cinfo->ncci_head,
836 CAPIMSG_APPID(skb->data),
837 CAPIMSG_NCCI(skb->data),
838 CAPIMSG_MSGID(skb->data));
839 }
840 if (retval == CAPI_NOERROR)
841 b1dma_queue_tx(card, skb);
842
843 return retval;
844}
845
846/* ------------------------------------------------------------- */
847
848int b1dmactl_read_proc(char *page, char **start, off_t off,
849 int count, int *eof, struct capi_ctr *ctrl)
850{
851 avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
852 avmcard *card = cinfo->card;
853 u8 flag;
854 int len = 0;
855 char *s;
856 u32 txoff, txlen, rxoff, rxlen, csr;
857 unsigned long flags;
858
859 len += sprintf(page+len, "%-16s %s\n", "name", card->name);
860 len += sprintf(page+len, "%-16s 0x%x\n", "io", card->port);
861 len += sprintf(page+len, "%-16s %d\n", "irq", card->irq);
862 len += sprintf(page+len, "%-16s 0x%lx\n", "membase", card->membase);
863 switch (card->cardtype) {
864 case avm_b1isa: s = "B1 ISA"; break;
865 case avm_b1pci: s = "B1 PCI"; break;
866 case avm_b1pcmcia: s = "B1 PCMCIA"; break;
867 case avm_m1: s = "M1"; break;
868 case avm_m2: s = "M2"; break;
869 case avm_t1isa: s = "T1 ISA (HEMA)"; break;
870 case avm_t1pci: s = "T1 PCI"; break;
871 case avm_c4: s = "C4"; break;
872 case avm_c2: s = "C2"; break;
873 default: s = "???"; break;
874 }
875 len += sprintf(page+len, "%-16s %s\n", "type", s);
876 if ((s = cinfo->version[VER_DRIVER]) != 0)
877 len += sprintf(page+len, "%-16s %s\n", "ver_driver", s);
878 if ((s = cinfo->version[VER_CARDTYPE]) != 0)
879 len += sprintf(page+len, "%-16s %s\n", "ver_cardtype", s);
880 if ((s = cinfo->version[VER_SERIAL]) != 0)
881 len += sprintf(page+len, "%-16s %s\n", "ver_serial", s);
882
883 if (card->cardtype != avm_m1) {
884 flag = ((u8 *)(ctrl->profile.manu))[3];
885 if (flag)
886 len += sprintf(page+len, "%-16s%s%s%s%s%s%s%s\n",
887 "protocol",
888 (flag & 0x01) ? " DSS1" : "",
889 (flag & 0x02) ? " CT1" : "",
890 (flag & 0x04) ? " VN3" : "",
891 (flag & 0x08) ? " NI1" : "",
892 (flag & 0x10) ? " AUSTEL" : "",
893 (flag & 0x20) ? " ESS" : "",
894 (flag & 0x40) ? " 1TR6" : ""
895 );
896 }
897 if (card->cardtype != avm_m1) {
898 flag = ((u8 *)(ctrl->profile.manu))[5];
899 if (flag)
900 len += sprintf(page+len, "%-16s%s%s%s%s\n",
901 "linetype",
902 (flag & 0x01) ? " point to point" : "",
903 (flag & 0x02) ? " point to multipoint" : "",
904 (flag & 0x08) ? " leased line without D-channel" : "",
905 (flag & 0x04) ? " leased line with D-channel" : ""
906 );
907 }
908 len += sprintf(page+len, "%-16s %s\n", "cardname", cinfo->cardname);
909
910
911 spin_lock_irqsave(&card->lock, flags);
912
913 txoff = (dma_addr_t)b1dma_readl(card, AMCC_TXPTR)-card->dma->sendbuf.dmaaddr;
914 txlen = b1dma_readl(card, AMCC_TXLEN);
915
916 rxoff = (dma_addr_t)b1dma_readl(card, AMCC_RXPTR)-card->dma->recvbuf.dmaaddr;
917 rxlen = b1dma_readl(card, AMCC_RXLEN);
918
919 csr = b1dma_readl(card, AMCC_INTCSR);
920
921 spin_unlock_irqrestore(&card->lock, flags);
922
923 len += sprintf(page+len, "%-16s 0x%lx\n",
924 "csr (cached)", (unsigned long)card->csr);
925 len += sprintf(page+len, "%-16s 0x%lx\n",
926 "csr", (unsigned long)csr);
927 len += sprintf(page+len, "%-16s %lu\n",
928 "txoff", (unsigned long)txoff);
929 len += sprintf(page+len, "%-16s %lu\n",
930 "txlen", (unsigned long)txlen);
931 len += sprintf(page+len, "%-16s %lu\n",
932 "rxoff", (unsigned long)rxoff);
933 len += sprintf(page+len, "%-16s %lu\n",
934 "rxlen", (unsigned long)rxlen);
935
936 if (off+count >= len)
937 *eof = 1;
938 if (len < off)
939 return 0;
940 *start = page + off;
941 return ((count < len-off) ? count : len-off);
942}
943
944/* ------------------------------------------------------------- */
945
946EXPORT_SYMBOL(b1dma_reset);
947EXPORT_SYMBOL(t1pci_detect);
948EXPORT_SYMBOL(b1pciv4_detect);
949EXPORT_SYMBOL(b1dma_interrupt);
950
951EXPORT_SYMBOL(b1dma_load_firmware);
952EXPORT_SYMBOL(b1dma_reset_ctr);
953EXPORT_SYMBOL(b1dma_register_appl);
954EXPORT_SYMBOL(b1dma_release_appl);
955EXPORT_SYMBOL(b1dma_send_message);
956EXPORT_SYMBOL(b1dmactl_read_proc);
957
958int b1dma_init(void)
959{
960 char *p;
961 char rev[32];
962
963 if ((p = strchr(revision, ':')) != 0 && p[1]) {
964 strlcpy(rev, p + 2, sizeof(rev));
965 if ((p = strchr(rev, '$')) != 0 && p > rev)
966 *(p-1) = 0;
967 } else
968 strcpy(rev, "1.0");
969
970 printk(KERN_INFO "b1dma: revision %s\n", rev);
971
972 return 0;
973}
974
975void b1dma_exit(void)
976{
977}
978
979module_init(b1dma_init);
980module_exit(b1dma_exit);
diff --git a/drivers/isdn/hardware/avm/b1isa.c b/drivers/isdn/hardware/avm/b1isa.c
new file mode 100644
index 000000000000..38bd4dfecbd1
--- /dev/null
+++ b/drivers/isdn/hardware/avm/b1isa.c
@@ -0,0 +1,245 @@
1/* $Id: b1isa.c,v 1.1.2.3 2004/02/10 01:07:12 keil Exp $
2 *
3 * Module for AVM B1 ISA-card.
4 *
5 * Copyright 1999 by Carsten Paeth <calle@calle.de>
6 *
7 * This software may be used and distributed according to the terms
8 * of the GNU General Public License, incorporated herein by reference.
9 *
10 */
11
12#include <linux/module.h>
13#include <linux/kernel.h>
14#include <linux/skbuff.h>
15#include <linux/delay.h>
16#include <linux/mm.h>
17#include <linux/interrupt.h>
18#include <linux/ioport.h>
19#include <linux/capi.h>
20#include <linux/init.h>
21#include <linux/pci.h>
22#include <asm/io.h>
23#include <linux/isdn/capicmd.h>
24#include <linux/isdn/capiutil.h>
25#include <linux/isdn/capilli.h>
26#include "avmcard.h"
27
28/* ------------------------------------------------------------- */
29
30static char *revision = "$Revision: 1.1.2.3 $";
31
32/* ------------------------------------------------------------- */
33
34MODULE_DESCRIPTION("CAPI4Linux: Driver for AVM B1 ISA card");
35MODULE_AUTHOR("Carsten Paeth");
36MODULE_LICENSE("GPL");
37
38/* ------------------------------------------------------------- */
39
40static void b1isa_remove(struct pci_dev *pdev)
41{
42 avmctrl_info *cinfo = pci_get_drvdata(pdev);
43 avmcard *card;
44
45 if (!cinfo)
46 return;
47
48 card = cinfo->card;
49
50 b1_reset(card->port);
51 b1_reset(card->port);
52
53 detach_capi_ctr(&cinfo->capi_ctrl);
54 free_irq(card->irq, card);
55 release_region(card->port, AVMB1_PORTLEN);
56 b1_free_card(card);
57}
58
59/* ------------------------------------------------------------- */
60
61static char *b1isa_procinfo(struct capi_ctr *ctrl);
62
63static int b1isa_probe(struct pci_dev *pdev)
64{
65 avmctrl_info *cinfo;
66 avmcard *card;
67 int retval;
68
69 card = b1_alloc_card(1);
70 if (!card) {
71 printk(KERN_WARNING "b1isa: no memory.\n");
72 retval = -ENOMEM;
73 goto err;
74 }
75
76 cinfo = card->ctrlinfo;
77
78 card->port = pci_resource_start(pdev, 0);
79 card->irq = pdev->irq;
80 card->cardtype = avm_b1isa;
81 sprintf(card->name, "b1isa-%x", card->port);
82
83 if ( card->port != 0x150 && card->port != 0x250
84 && card->port != 0x300 && card->port != 0x340) {
85 printk(KERN_WARNING "b1isa: invalid port 0x%x.\n", card->port);
86 retval = -EINVAL;
87 goto err_free;
88 }
89 if (b1_irq_table[card->irq & 0xf] == 0) {
90 printk(KERN_WARNING "b1isa: irq %d not valid.\n", card->irq);
91 retval = -EINVAL;
92 goto err_free;
93 }
94 if (!request_region(card->port, AVMB1_PORTLEN, card->name)) {
95 printk(KERN_WARNING "b1isa: ports 0x%03x-0x%03x in use.\n",
96 card->port, card->port + AVMB1_PORTLEN);
97 retval = -EBUSY;
98 goto err_free;
99 }
100 retval = request_irq(card->irq, b1_interrupt, 0, card->name, card);
101 if (retval) {
102 printk(KERN_ERR "b1isa: unable to get IRQ %d.\n", card->irq);
103 goto err_release_region;
104 }
105 b1_reset(card->port);
106 if ((retval = b1_detect(card->port, card->cardtype)) != 0) {
107 printk(KERN_NOTICE "b1isa: NO card at 0x%x (%d)\n",
108 card->port, retval);
109 retval = -ENODEV;
110 goto err_free_irq;
111 }
112 b1_reset(card->port);
113 b1_getrevision(card);
114
115 cinfo->capi_ctrl.owner = THIS_MODULE;
116 cinfo->capi_ctrl.driver_name = "b1isa";
117 cinfo->capi_ctrl.driverdata = cinfo;
118 cinfo->capi_ctrl.register_appl = b1_register_appl;
119 cinfo->capi_ctrl.release_appl = b1_release_appl;
120 cinfo->capi_ctrl.send_message = b1_send_message;
121 cinfo->capi_ctrl.load_firmware = b1_load_firmware;
122 cinfo->capi_ctrl.reset_ctr = b1_reset_ctr;
123 cinfo->capi_ctrl.procinfo = b1isa_procinfo;
124 cinfo->capi_ctrl.ctr_read_proc = b1ctl_read_proc;
125 strcpy(cinfo->capi_ctrl.name, card->name);
126
127 retval = attach_capi_ctr(&cinfo->capi_ctrl);
128 if (retval) {
129 printk(KERN_ERR "b1isa: attach controller failed.\n");
130 goto err_free_irq;
131 }
132
133 printk(KERN_INFO "b1isa: AVM B1 ISA at i/o %#x, irq %d, revision %d\n",
134 card->port, card->irq, card->revision);
135
136 pci_set_drvdata(pdev, cinfo);
137 return 0;
138
139 err_free_irq:
140 free_irq(card->irq, card);
141 err_release_region:
142 release_region(card->port, AVMB1_PORTLEN);
143 err_free:
144 b1_free_card(card);
145 err:
146 return retval;
147}
148
149static char *b1isa_procinfo(struct capi_ctr *ctrl)
150{
151 avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
152
153 if (!cinfo)
154 return "";
155 sprintf(cinfo->infobuf, "%s %s 0x%x %d r%d",
156 cinfo->cardname[0] ? cinfo->cardname : "-",
157 cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-",
158 cinfo->card ? cinfo->card->port : 0x0,
159 cinfo->card ? cinfo->card->irq : 0,
160 cinfo->card ? cinfo->card->revision : 0
161 );
162 return cinfo->infobuf;
163}
164
165/* ------------------------------------------------------------- */
166
167#define MAX_CARDS 4
168static struct pci_dev isa_dev[MAX_CARDS];
169static int io[MAX_CARDS];
170static int irq[MAX_CARDS];
171
172MODULE_PARM(io, "1-" __MODULE_STRING(MAX_CARDS) "i");
173MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_CARDS) "i");
174MODULE_PARM_DESC(io, "I/O base address(es)");
175MODULE_PARM_DESC(irq, "IRQ number(s) (assigned)");
176
177static int b1isa_add_card(struct capi_driver *driver, capicardparams *data)
178{
179 int i;
180
181 for (i = 0; i < MAX_CARDS; i++) {
182 if (isa_dev[i].resource[0].start)
183 continue;
184
185 isa_dev[i].resource[0].start = data->port;
186 isa_dev[i].irq = data->irq;
187
188 if (b1isa_probe(&isa_dev[i]) == 0)
189 return 0;
190 }
191 return -ENODEV;
192}
193
194static struct capi_driver capi_driver_b1isa = {
195 .name = "b1isa",
196 .revision = "1.0",
197 .add_card = b1isa_add_card,
198};
199
200static int __init b1isa_init(void)
201{
202 char *p;
203 char rev[32];
204 int i;
205
206 if ((p = strchr(revision, ':')) != 0 && p[1]) {
207 strlcpy(rev, p + 2, 32);
208 if ((p = strchr(rev, '$')) != 0 && p > rev)
209 *(p-1) = 0;
210 } else
211 strcpy(rev, "1.0");
212
213 for (i = 0; i < MAX_CARDS; i++) {
214 if (!io[i])
215 break;
216
217 isa_dev[i].resource[0].start = io[i];
218 isa_dev[i].irq = irq[i];
219
220 if (b1isa_probe(&isa_dev[i]) != 0)
221 return -ENODEV;
222 }
223
224 strlcpy(capi_driver_b1isa.revision, rev, 32);
225 register_capi_driver(&capi_driver_b1isa);
226 printk(KERN_INFO "b1isa: revision %s\n", rev);
227
228 return 0;
229}
230
231static void __exit b1isa_exit(void)
232{
233 int i;
234
235 for (i = 0; i < MAX_CARDS; i++) {
236 if (!io[i])
237 break;
238
239 b1isa_remove(&isa_dev[i]);
240 }
241 unregister_capi_driver(&capi_driver_b1isa);
242}
243
244module_init(b1isa_init);
245module_exit(b1isa_exit);
diff --git a/drivers/isdn/hardware/avm/b1pci.c b/drivers/isdn/hardware/avm/b1pci.c
new file mode 100644
index 000000000000..5435a6cfb5e7
--- /dev/null
+++ b/drivers/isdn/hardware/avm/b1pci.c
@@ -0,0 +1,417 @@
1/* $Id: b1pci.c,v 1.1.2.2 2004/01/16 21:09:27 keil Exp $
2 *
3 * Module for AVM B1 PCI-card.
4 *
5 * Copyright 1999 by Carsten Paeth <calle@calle.de>
6 *
7 * This software may be used and distributed according to the terms
8 * of the GNU General Public License, incorporated herein by reference.
9 *
10 */
11
12#include <linux/config.h>
13#include <linux/module.h>
14#include <linux/kernel.h>
15#include <linux/skbuff.h>
16#include <linux/delay.h>
17#include <linux/mm.h>
18#include <linux/interrupt.h>
19#include <linux/ioport.h>
20#include <linux/pci.h>
21#include <linux/capi.h>
22#include <asm/io.h>
23#include <linux/init.h>
24#include <linux/isdn/capicmd.h>
25#include <linux/isdn/capiutil.h>
26#include <linux/isdn/capilli.h>
27#include "avmcard.h"
28
29/* ------------------------------------------------------------- */
30
31static char *revision = "$Revision: 1.1.2.2 $";
32
33/* ------------------------------------------------------------- */
34
35static struct pci_device_id b1pci_pci_tbl[] = {
36 { PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_B1, PCI_ANY_ID, PCI_ANY_ID },
37 { } /* Terminating entry */
38};
39
40MODULE_DEVICE_TABLE(pci, b1pci_pci_tbl);
41MODULE_DESCRIPTION("CAPI4Linux: Driver for AVM B1 PCI card");
42MODULE_AUTHOR("Carsten Paeth");
43MODULE_LICENSE("GPL");
44
45/* ------------------------------------------------------------- */
46
47static char *b1pci_procinfo(struct capi_ctr *ctrl)
48{
49 avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
50
51 if (!cinfo)
52 return "";
53 sprintf(cinfo->infobuf, "%s %s 0x%x %d r%d",
54 cinfo->cardname[0] ? cinfo->cardname : "-",
55 cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-",
56 cinfo->card ? cinfo->card->port : 0x0,
57 cinfo->card ? cinfo->card->irq : 0,
58 cinfo->card ? cinfo->card->revision : 0
59 );
60 return cinfo->infobuf;
61}
62
63/* ------------------------------------------------------------- */
64
65static int b1pci_probe(struct capicardparams *p, struct pci_dev *pdev)
66{
67 avmcard *card;
68 avmctrl_info *cinfo;
69 int retval;
70
71 card = b1_alloc_card(1);
72 if (!card) {
73 printk(KERN_WARNING "b1pci: no memory.\n");
74 retval = -ENOMEM;
75 goto err;
76 }
77
78 cinfo = card->ctrlinfo;
79 sprintf(card->name, "b1pci-%x", p->port);
80 card->port = p->port;
81 card->irq = p->irq;
82 card->cardtype = avm_b1pci;
83
84 if (!request_region(card->port, AVMB1_PORTLEN, card->name)) {
85 printk(KERN_WARNING "b1pci: ports 0x%03x-0x%03x in use.\n",
86 card->port, card->port + AVMB1_PORTLEN);
87 retval = -EBUSY;
88 goto err_free;
89 }
90 b1_reset(card->port);
91 retval = b1_detect(card->port, card->cardtype);
92 if (retval) {
93 printk(KERN_NOTICE "b1pci: NO card at 0x%x (%d)\n",
94 card->port, retval);
95 retval = -ENODEV;
96 goto err_release_region;
97 }
98 b1_reset(card->port);
99 b1_getrevision(card);
100
101 retval = request_irq(card->irq, b1_interrupt, SA_SHIRQ, card->name, card);
102 if (retval) {
103 printk(KERN_ERR "b1pci: unable to get IRQ %d.\n", card->irq);
104 retval = -EBUSY;
105 goto err_release_region;
106 }
107
108 cinfo->capi_ctrl.driver_name = "b1pci";
109 cinfo->capi_ctrl.driverdata = cinfo;
110 cinfo->capi_ctrl.register_appl = b1_register_appl;
111 cinfo->capi_ctrl.release_appl = b1_release_appl;
112 cinfo->capi_ctrl.send_message = b1_send_message;
113 cinfo->capi_ctrl.load_firmware = b1_load_firmware;
114 cinfo->capi_ctrl.reset_ctr = b1_reset_ctr;
115 cinfo->capi_ctrl.procinfo = b1pci_procinfo;
116 cinfo->capi_ctrl.ctr_read_proc = b1ctl_read_proc;
117 strcpy(cinfo->capi_ctrl.name, card->name);
118 cinfo->capi_ctrl.owner = THIS_MODULE;
119
120 retval = attach_capi_ctr(&cinfo->capi_ctrl);
121 if (retval) {
122 printk(KERN_ERR "b1pci: attach controller failed.\n");
123 goto err_free_irq;
124 }
125
126 if (card->revision >= 4) {
127 printk(KERN_INFO "b1pci: AVM B1 PCI V4 at i/o %#x, irq %d, revision %d (no dma)\n",
128 card->port, card->irq, card->revision);
129 } else {
130 printk(KERN_INFO "b1pci: AVM B1 PCI at i/o %#x, irq %d, revision %d\n",
131 card->port, card->irq, card->revision);
132 }
133
134 pci_set_drvdata(pdev, card);
135 return 0;
136
137 err_free_irq:
138 free_irq(card->irq, card);
139 err_release_region:
140 release_region(card->port, AVMB1_PORTLEN);
141 err_free:
142 b1_free_card(card);
143 err:
144 return retval;
145}
146
147static void b1pci_remove(struct pci_dev *pdev)
148{
149 avmcard *card = pci_get_drvdata(pdev);
150 avmctrl_info *cinfo = card->ctrlinfo;
151 unsigned int port = card->port;
152
153 b1_reset(port);
154 b1_reset(port);
155
156 detach_capi_ctr(&cinfo->capi_ctrl);
157 free_irq(card->irq, card);
158 release_region(card->port, AVMB1_PORTLEN);
159 b1_free_card(card);
160}
161
162#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
163/* ------------------------------------------------------------- */
164
165static char *b1pciv4_procinfo(struct capi_ctr *ctrl)
166{
167 avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
168
169 if (!cinfo)
170 return "";
171 sprintf(cinfo->infobuf, "%s %s 0x%x %d 0x%lx r%d",
172 cinfo->cardname[0] ? cinfo->cardname : "-",
173 cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-",
174 cinfo->card ? cinfo->card->port : 0x0,
175 cinfo->card ? cinfo->card->irq : 0,
176 cinfo->card ? cinfo->card->membase : 0,
177 cinfo->card ? cinfo->card->revision : 0
178 );
179 return cinfo->infobuf;
180}
181
182/* ------------------------------------------------------------- */
183
184static int b1pciv4_probe(struct capicardparams *p, struct pci_dev *pdev)
185{
186 avmcard *card;
187 avmctrl_info *cinfo;
188 int retval;
189
190 card = b1_alloc_card(1);
191 if (!card) {
192 printk(KERN_WARNING "b1pci: no memory.\n");
193 retval = -ENOMEM;
194 goto err;
195 }
196
197 card->dma = avmcard_dma_alloc("b1pci", pdev, 2048+128, 2048+128);
198 if (!card->dma) {
199 printk(KERN_WARNING "b1pci: dma alloc.\n");
200 retval = -ENOMEM;
201 goto err_free;
202 }
203
204 cinfo = card->ctrlinfo;
205 sprintf(card->name, "b1pciv4-%x", p->port);
206 card->port = p->port;
207 card->irq = p->irq;
208 card->membase = p->membase;
209 card->cardtype = avm_b1pci;
210
211 if (!request_region(card->port, AVMB1_PORTLEN, card->name)) {
212 printk(KERN_WARNING "b1pci: ports 0x%03x-0x%03x in use.\n",
213 card->port, card->port + AVMB1_PORTLEN);
214 retval = -EBUSY;
215 goto err_free_dma;
216 }
217
218 card->mbase = ioremap(card->membase, 64);
219 if (!card->mbase) {
220 printk(KERN_NOTICE "b1pci: can't remap memory at 0x%lx\n",
221 card->membase);
222 retval = -ENOMEM;
223 goto err_release_region;
224 }
225
226 b1dma_reset(card);
227
228 retval = b1pciv4_detect(card);
229 if (retval) {
230 printk(KERN_NOTICE "b1pci: NO card at 0x%x (%d)\n",
231 card->port, retval);
232 retval = -ENODEV;
233 goto err_unmap;
234 }
235 b1dma_reset(card);
236 b1_getrevision(card);
237
238 retval = request_irq(card->irq, b1dma_interrupt, SA_SHIRQ, card->name, card);
239 if (retval) {
240 printk(KERN_ERR "b1pci: unable to get IRQ %d.\n",
241 card->irq);
242 retval = -EBUSY;
243 goto err_unmap;
244 }
245
246 cinfo->capi_ctrl.owner = THIS_MODULE;
247 cinfo->capi_ctrl.driver_name = "b1pciv4";
248 cinfo->capi_ctrl.driverdata = cinfo;
249 cinfo->capi_ctrl.register_appl = b1dma_register_appl;
250 cinfo->capi_ctrl.release_appl = b1dma_release_appl;
251 cinfo->capi_ctrl.send_message = b1dma_send_message;
252 cinfo->capi_ctrl.load_firmware = b1dma_load_firmware;
253 cinfo->capi_ctrl.reset_ctr = b1dma_reset_ctr;
254 cinfo->capi_ctrl.procinfo = b1pciv4_procinfo;
255 cinfo->capi_ctrl.ctr_read_proc = b1dmactl_read_proc;
256 strcpy(cinfo->capi_ctrl.name, card->name);
257
258 retval = attach_capi_ctr(&cinfo->capi_ctrl);
259 if (retval) {
260 printk(KERN_ERR "b1pci: attach controller failed.\n");
261 goto err_free_irq;
262 }
263 card->cardnr = cinfo->capi_ctrl.cnr;
264
265 printk(KERN_INFO "b1pci: AVM B1 PCI V4 at i/o %#x, irq %d, mem %#lx, revision %d (dma)\n",
266 card->port, card->irq, card->membase, card->revision);
267
268 pci_set_drvdata(pdev, card);
269 return 0;
270
271 err_free_irq:
272 free_irq(card->irq, card);
273 err_unmap:
274 iounmap(card->mbase);
275 err_release_region:
276 release_region(card->port, AVMB1_PORTLEN);
277 err_free_dma:
278 avmcard_dma_free(card->dma);
279 err_free:
280 b1_free_card(card);
281 err:
282 return retval;
283
284}
285
286static void b1pciv4_remove(struct pci_dev *pdev)
287{
288 avmcard *card = pci_get_drvdata(pdev);
289 avmctrl_info *cinfo = card->ctrlinfo;
290
291 b1dma_reset(card);
292
293 detach_capi_ctr(&cinfo->capi_ctrl);
294 free_irq(card->irq, card);
295 iounmap(card->mbase);
296 release_region(card->port, AVMB1_PORTLEN);
297 avmcard_dma_free(card->dma);
298 b1_free_card(card);
299}
300
301#endif /* CONFIG_ISDN_DRV_AVMB1_B1PCIV4 */
302
303static int __devinit b1pci_pci_probe(struct pci_dev *pdev,
304 const struct pci_device_id *ent)
305{
306 struct capicardparams param;
307 int retval;
308
309 if (pci_enable_device(pdev) < 0) {
310 printk(KERN_ERR "b1pci: failed to enable AVM-B1\n");
311 return -ENODEV;
312 }
313 param.irq = pdev->irq;
314
315 if (pci_resource_start(pdev, 2)) { /* B1 PCI V4 */
316#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
317 pci_set_master(pdev);
318#endif
319 param.membase = pci_resource_start(pdev, 0);
320 param.port = pci_resource_start(pdev, 2);
321
322 printk(KERN_INFO "b1pci: PCI BIOS reports AVM-B1 V4 at i/o %#x, irq %d, mem %#x\n",
323 param.port, param.irq, param.membase);
324#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
325 retval = b1pciv4_probe(&param, pdev);
326#else
327 retval = b1pci_probe(&param, pdev);
328#endif
329 if (retval != 0) {
330 printk(KERN_ERR "b1pci: no AVM-B1 V4 at i/o %#x, irq %d, mem %#x detected\n",
331 param.port, param.irq, param.membase);
332 }
333 } else {
334 param.membase = 0;
335 param.port = pci_resource_start(pdev, 1);
336
337 printk(KERN_INFO "b1pci: PCI BIOS reports AVM-B1 at i/o %#x, irq %d\n",
338 param.port, param.irq);
339 retval = b1pci_probe(&param, pdev);
340 if (retval != 0) {
341 printk(KERN_ERR "b1pci: no AVM-B1 at i/o %#x, irq %d detected\n",
342 param.port, param.irq);
343 }
344 }
345 return retval;
346}
347
348static void __devexit b1pci_pci_remove(struct pci_dev *pdev)
349{
350#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
351 avmcard *card = pci_get_drvdata(pdev);
352
353 if (card->dma)
354 b1pciv4_remove(pdev);
355 else
356 b1pci_remove(pdev);
357#else
358 b1pci_remove(pdev);
359#endif
360}
361
362static struct pci_driver b1pci_pci_driver = {
363 .name = "b1pci",
364 .id_table = b1pci_pci_tbl,
365 .probe = b1pci_pci_probe,
366 .remove = __devexit_p(b1pci_pci_remove),
367};
368
369static struct capi_driver capi_driver_b1pci = {
370 .name = "b1pci",
371 .revision = "1.0",
372};
373#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
374static struct capi_driver capi_driver_b1pciv4 = {
375 .name = "b1pciv4",
376 .revision = "1.0",
377};
378#endif
379
380static int __init b1pci_init(void)
381{
382 char *p;
383 char rev[32];
384 int err;
385
386 if ((p = strchr(revision, ':')) != 0 && p[1]) {
387 strlcpy(rev, p + 2, 32);
388 if ((p = strchr(rev, '$')) != 0 && p > rev)
389 *(p-1) = 0;
390 } else
391 strcpy(rev, "1.0");
392
393
394 err = pci_register_driver(&b1pci_pci_driver);
395 if (!err) {
396 strlcpy(capi_driver_b1pci.revision, rev, 32);
397 register_capi_driver(&capi_driver_b1pci);
398#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
399 strlcpy(capi_driver_b1pciv4.revision, rev, 32);
400 register_capi_driver(&capi_driver_b1pciv4);
401#endif
402 printk(KERN_INFO "b1pci: revision %s\n", rev);
403 }
404 return err;
405}
406
407static void __exit b1pci_exit(void)
408{
409 unregister_capi_driver(&capi_driver_b1pci);
410#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
411 unregister_capi_driver(&capi_driver_b1pciv4);
412#endif
413 pci_unregister_driver(&b1pci_pci_driver);
414}
415
416module_init(b1pci_init);
417module_exit(b1pci_exit);
diff --git a/drivers/isdn/hardware/avm/b1pcmcia.c b/drivers/isdn/hardware/avm/b1pcmcia.c
new file mode 100644
index 000000000000..9746cc5ffff8
--- /dev/null
+++ b/drivers/isdn/hardware/avm/b1pcmcia.c
@@ -0,0 +1,224 @@
1/* $Id: b1pcmcia.c,v 1.1.2.2 2004/01/16 21:09:27 keil Exp $
2 *
3 * Module for AVM B1/M1/M2 PCMCIA-card.
4 *
5 * Copyright 1999 by Carsten Paeth <calle@calle.de>
6 *
7 * This software may be used and distributed according to the terms
8 * of the GNU General Public License, incorporated herein by reference.
9 *
10 */
11
12#include <linux/module.h>
13#include <linux/kernel.h>
14#include <linux/skbuff.h>
15#include <linux/delay.h>
16#include <linux/mm.h>
17#include <linux/interrupt.h>
18#include <linux/ioport.h>
19#include <linux/init.h>
20#include <asm/io.h>
21#include <linux/capi.h>
22#include <linux/b1pcmcia.h>
23#include <linux/isdn/capicmd.h>
24#include <linux/isdn/capiutil.h>
25#include <linux/isdn/capilli.h>
26#include "avmcard.h"
27
28/* ------------------------------------------------------------- */
29
30static char *revision = "$Revision: 1.1.2.2 $";
31
32/* ------------------------------------------------------------- */
33
34MODULE_DESCRIPTION("CAPI4Linux: Driver for AVM PCMCIA cards");
35MODULE_AUTHOR("Carsten Paeth");
36MODULE_LICENSE("GPL");
37
38/* ------------------------------------------------------------- */
39
40static void b1pcmcia_remove_ctr(struct capi_ctr *ctrl)
41{
42 avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
43 avmcard *card = cinfo->card;
44 unsigned int port = card->port;
45
46 b1_reset(port);
47 b1_reset(port);
48
49 detach_capi_ctr(ctrl);
50 free_irq(card->irq, card);
51 b1_free_card(card);
52}
53
54/* ------------------------------------------------------------- */
55
56static LIST_HEAD(cards);
57
58static char *b1pcmcia_procinfo(struct capi_ctr *ctrl);
59
60static int b1pcmcia_add_card(unsigned int port, unsigned irq,
61 enum avmcardtype cardtype)
62{
63 avmctrl_info *cinfo;
64 avmcard *card;
65 char *cardname;
66 int retval;
67
68 card = b1_alloc_card(1);
69 if (!card) {
70 printk(KERN_WARNING "b1pcmcia: no memory.\n");
71 retval = -ENOMEM;
72 goto err;
73 }
74 cinfo = card->ctrlinfo;
75
76 switch (cardtype) {
77 case avm_m1: sprintf(card->name, "m1-%x", port); break;
78 case avm_m2: sprintf(card->name, "m2-%x", port); break;
79 default: sprintf(card->name, "b1pcmcia-%x", port); break;
80 }
81 card->port = port;
82 card->irq = irq;
83 card->cardtype = cardtype;
84
85 retval = request_irq(card->irq, b1_interrupt, 0, card->name, card);
86 if (retval) {
87 printk(KERN_ERR "b1pcmcia: unable to get IRQ %d.\n",
88 card->irq);
89 retval = -EBUSY;
90 goto err_free;
91 }
92 b1_reset(card->port);
93 if ((retval = b1_detect(card->port, card->cardtype)) != 0) {
94 printk(KERN_NOTICE "b1pcmcia: NO card at 0x%x (%d)\n",
95 card->port, retval);
96 retval = -ENODEV;
97 goto err_free_irq;
98 }
99 b1_reset(card->port);
100 b1_getrevision(card);
101
102 cinfo->capi_ctrl.owner = THIS_MODULE;
103 cinfo->capi_ctrl.driver_name = "b1pcmcia";
104 cinfo->capi_ctrl.driverdata = cinfo;
105 cinfo->capi_ctrl.register_appl = b1_register_appl;
106 cinfo->capi_ctrl.release_appl = b1_release_appl;
107 cinfo->capi_ctrl.send_message = b1_send_message;
108 cinfo->capi_ctrl.load_firmware = b1_load_firmware;
109 cinfo->capi_ctrl.reset_ctr = b1_reset_ctr;
110 cinfo->capi_ctrl.procinfo = b1pcmcia_procinfo;
111 cinfo->capi_ctrl.ctr_read_proc = b1ctl_read_proc;
112 strcpy(cinfo->capi_ctrl.name, card->name);
113
114 retval = attach_capi_ctr(&cinfo->capi_ctrl);
115 if (retval) {
116 printk(KERN_ERR "b1pcmcia: attach controller failed.\n");
117 goto err_free_irq;
118 }
119 switch (cardtype) {
120 case avm_m1: cardname = "M1"; break;
121 case avm_m2: cardname = "M2"; break;
122 default : cardname = "B1 PCMCIA"; break;
123 }
124
125 printk(KERN_INFO "b1pcmcia: AVM %s at i/o %#x, irq %d, revision %d\n",
126 cardname, card->port, card->irq, card->revision);
127
128 list_add(&card->list, &cards);
129 return cinfo->capi_ctrl.cnr;
130
131 err_free_irq:
132 free_irq(card->irq, card);
133 err_free:
134 b1_free_card(card);
135 err:
136 return retval;
137}
138
139/* ------------------------------------------------------------- */
140
141static char *b1pcmcia_procinfo(struct capi_ctr *ctrl)
142{
143 avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
144
145 if (!cinfo)
146 return "";
147 sprintf(cinfo->infobuf, "%s %s 0x%x %d r%d",
148 cinfo->cardname[0] ? cinfo->cardname : "-",
149 cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-",
150 cinfo->card ? cinfo->card->port : 0x0,
151 cinfo->card ? cinfo->card->irq : 0,
152 cinfo->card ? cinfo->card->revision : 0
153 );
154 return cinfo->infobuf;
155}
156
157/* ------------------------------------------------------------- */
158
159int b1pcmcia_addcard_b1(unsigned int port, unsigned irq)
160{
161 return b1pcmcia_add_card(port, irq, avm_b1pcmcia);
162}
163
164int b1pcmcia_addcard_m1(unsigned int port, unsigned irq)
165{
166 return b1pcmcia_add_card(port, irq, avm_m1);
167}
168
169int b1pcmcia_addcard_m2(unsigned int port, unsigned irq)
170{
171 return b1pcmcia_add_card(port, irq, avm_m2);
172}
173
174int b1pcmcia_delcard(unsigned int port, unsigned irq)
175{
176 struct list_head *l;
177 avmcard *card;
178
179 list_for_each(l, &cards) {
180 card = list_entry(l, avmcard, list);
181 if (card->port == port && card->irq == irq) {
182 b1pcmcia_remove_ctr(&card->ctrlinfo[0].capi_ctrl);
183 return 0;
184 }
185 }
186 return -ESRCH;
187}
188
189EXPORT_SYMBOL(b1pcmcia_addcard_b1);
190EXPORT_SYMBOL(b1pcmcia_addcard_m1);
191EXPORT_SYMBOL(b1pcmcia_addcard_m2);
192EXPORT_SYMBOL(b1pcmcia_delcard);
193
194static struct capi_driver capi_driver_b1pcmcia = {
195 .name = "b1pcmcia",
196 .revision = "1.0",
197};
198
199static int __init b1pcmcia_init(void)
200{
201 char *p;
202 char rev[32];
203
204 if ((p = strchr(revision, ':')) != 0 && p[1]) {
205 strlcpy(rev, p + 2, 32);
206 if ((p = strchr(rev, '$')) != 0 && p > rev)
207 *(p-1) = 0;
208 } else
209 strcpy(rev, "1.0");
210
211 strlcpy(capi_driver_b1pcmcia.revision, rev, 32);
212 register_capi_driver(&capi_driver_b1pcmcia);
213 printk(KERN_INFO "b1pci: revision %s\n", rev);
214
215 return 0;
216}
217
218static void __exit b1pcmcia_exit(void)
219{
220 unregister_capi_driver(&capi_driver_b1pcmcia);
221}
222
223module_init(b1pcmcia_init);
224module_exit(b1pcmcia_exit);
diff --git a/drivers/isdn/hardware/avm/c4.c b/drivers/isdn/hardware/avm/c4.c
new file mode 100644
index 000000000000..fa6b93b1a42d
--- /dev/null
+++ b/drivers/isdn/hardware/avm/c4.c
@@ -0,0 +1,1310 @@
1/* $Id: c4.c,v 1.1.2.2 2004/01/16 21:09:27 keil Exp $
2 *
3 * Module for AVM C4 & C2 card.
4 *
5 * Copyright 1999 by Carsten Paeth <calle@calle.de>
6 *
7 * This software may be used and distributed according to the terms
8 * of the GNU General Public License, incorporated herein by reference.
9 *
10 */
11
12#include <linux/config.h>
13#include <linux/module.h>
14#include <linux/kernel.h>
15#include <linux/skbuff.h>
16#include <linux/delay.h>
17#include <linux/mm.h>
18#include <linux/interrupt.h>
19#include <linux/ioport.h>
20#include <linux/pci.h>
21#include <linux/capi.h>
22#include <linux/kernelcapi.h>
23#include <linux/init.h>
24#include <asm/io.h>
25#include <asm/uaccess.h>
26#include <linux/netdevice.h>
27#include <linux/isdn/capicmd.h>
28#include <linux/isdn/capiutil.h>
29#include <linux/isdn/capilli.h>
30#include "avmcard.h"
31
32#undef CONFIG_C4_DEBUG
33#undef CONFIG_C4_POLLDEBUG
34
35/* ------------------------------------------------------------- */
36
37static char *revision = "$Revision: 1.1.2.2 $";
38
39/* ------------------------------------------------------------- */
40
41static int suppress_pollack;
42
43static struct pci_device_id c4_pci_tbl[] = {
44 { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21285, PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_C4, 0, 0, (unsigned long)4 },
45 { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21285, PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_C2, 0, 0, (unsigned long)2 },
46 { } /* Terminating entry */
47};
48
49MODULE_DEVICE_TABLE(pci, c4_pci_tbl);
50MODULE_DESCRIPTION("CAPI4Linux: Driver for AVM C2/C4 cards");
51MODULE_AUTHOR("Carsten Paeth");
52MODULE_LICENSE("GPL");
53MODULE_PARM(suppress_pollack, "0-1i");
54
55/* ------------------------------------------------------------- */
56
57static void c4_dispatch_tx(avmcard *card);
58
59/* ------------------------------------------------------------- */
60
61#define DC21285_DRAM_A0MR 0x40000000
62#define DC21285_DRAM_A1MR 0x40004000
63#define DC21285_DRAM_A2MR 0x40008000
64#define DC21285_DRAM_A3MR 0x4000C000
65
66#define CAS_OFFSET 0x88
67
68#define DC21285_ARMCSR_BASE 0x42000000
69
70#define PCI_OUT_INT_STATUS 0x30
71#define PCI_OUT_INT_MASK 0x34
72#define MAILBOX_0 0x50
73#define MAILBOX_1 0x54
74#define MAILBOX_2 0x58
75#define MAILBOX_3 0x5C
76#define DOORBELL 0x60
77#define DOORBELL_SETUP 0x64
78
79#define CHAN_1_CONTROL 0x90
80#define CHAN_2_CONTROL 0xB0
81#define DRAM_TIMING 0x10C
82#define DRAM_ADDR_SIZE_0 0x110
83#define DRAM_ADDR_SIZE_1 0x114
84#define DRAM_ADDR_SIZE_2 0x118
85#define DRAM_ADDR_SIZE_3 0x11C
86#define SA_CONTROL 0x13C
87#define XBUS_CYCLE 0x148
88#define XBUS_STROBE 0x14C
89#define DBELL_PCI_MASK 0x150
90#define DBELL_SA_MASK 0x154
91
92#define SDRAM_SIZE 0x1000000
93
94/* ------------------------------------------------------------- */
95
96#define MBOX_PEEK_POKE MAILBOX_0
97
98#define DBELL_ADDR 0x01
99#define DBELL_DATA 0x02
100#define DBELL_RNWR 0x40
101#define DBELL_INIT 0x80
102
103/* ------------------------------------------------------------- */
104
105#define MBOX_UP_ADDR MAILBOX_0
106#define MBOX_UP_LEN MAILBOX_1
107#define MBOX_DOWN_ADDR MAILBOX_2
108#define MBOX_DOWN_LEN MAILBOX_3
109
110#define DBELL_UP_HOST 0x00000100
111#define DBELL_UP_ARM 0x00000200
112#define DBELL_DOWN_HOST 0x00000400
113#define DBELL_DOWN_ARM 0x00000800
114#define DBELL_RESET_HOST 0x40000000
115#define DBELL_RESET_ARM 0x80000000
116
117/* ------------------------------------------------------------- */
118
119#define DRAM_TIMING_DEF 0x001A01A5
120#define DRAM_AD_SZ_DEF0 0x00000045
121#define DRAM_AD_SZ_NULL 0x00000000
122
123#define SA_CTL_ALLRIGHT 0x64AA0271
124
125#define INIT_XBUS_CYCLE 0x100016DB
126#define INIT_XBUS_STROBE 0xF1F1F1F1
127
128/* ------------------------------------------------------------- */
129
130#define RESET_TIMEOUT (15*HZ) /* 15 sec */
131#define PEEK_POKE_TIMEOUT (HZ/10) /* 0.1 sec */
132
133/* ------------------------------------------------------------- */
134
135#define c4outmeml(addr, value) writel(value, addr)
136#define c4inmeml(addr) readl(addr)
137#define c4outmemw(addr, value) writew(value, addr)
138#define c4inmemw(addr) readw(addr)
139#define c4outmemb(addr, value) writeb(value, addr)
140#define c4inmemb(addr) readb(addr)
141
142/* ------------------------------------------------------------- */
143
144static inline int wait_for_doorbell(avmcard *card, unsigned long t)
145{
146 unsigned long stop;
147
148 stop = jiffies + t;
149 while (c4inmeml(card->mbase+DOORBELL) != 0xffffffff) {
150 if (!time_before(jiffies, stop))
151 return -1;
152 mb();
153 }
154 return 0;
155}
156
157static int c4_poke(avmcard *card, unsigned long off, unsigned long value)
158{
159
160 if (wait_for_doorbell(card, HZ/10) < 0)
161 return -1;
162
163 c4outmeml(card->mbase+MBOX_PEEK_POKE, off);
164 c4outmeml(card->mbase+DOORBELL, DBELL_ADDR);
165
166 if (wait_for_doorbell(card, HZ/10) < 0)
167 return -1;
168
169 c4outmeml(card->mbase+MBOX_PEEK_POKE, value);
170 c4outmeml(card->mbase+DOORBELL, DBELL_DATA | DBELL_ADDR);
171
172 return 0;
173}
174
175static int c4_peek(avmcard *card, unsigned long off, unsigned long *valuep)
176{
177 if (wait_for_doorbell(card, HZ/10) < 0)
178 return -1;
179
180 c4outmeml(card->mbase+MBOX_PEEK_POKE, off);
181 c4outmeml(card->mbase+DOORBELL, DBELL_RNWR | DBELL_ADDR);
182
183 if (wait_for_doorbell(card, HZ/10) < 0)
184 return -1;
185
186 *valuep = c4inmeml(card->mbase+MBOX_PEEK_POKE);
187
188 return 0;
189}
190
191/* ------------------------------------------------------------- */
192
193static int c4_load_t4file(avmcard *card, capiloaddatapart * t4file)
194{
195 u32 val;
196 unsigned char *dp;
197 u_int left;
198 u32 loadoff = 0;
199
200 dp = t4file->data;
201 left = t4file->len;
202 while (left >= sizeof(u32)) {
203 if (t4file->user) {
204 if (copy_from_user(&val, dp, sizeof(val)))
205 return -EFAULT;
206 } else {
207 memcpy(&val, dp, sizeof(val));
208 }
209 if (c4_poke(card, loadoff, val)) {
210 printk(KERN_ERR "%s: corrupted firmware file ?\n",
211 card->name);
212 return -EIO;
213 }
214 left -= sizeof(u32);
215 dp += sizeof(u32);
216 loadoff += sizeof(u32);
217 }
218 if (left) {
219 val = 0;
220 if (t4file->user) {
221 if (copy_from_user(&val, dp, left))
222 return -EFAULT;
223 } else {
224 memcpy(&val, dp, left);
225 }
226 if (c4_poke(card, loadoff, val)) {
227 printk(KERN_ERR "%s: corrupted firmware file ?\n",
228 card->name);
229 return -EIO;
230 }
231 }
232 return 0;
233}
234
235/* ------------------------------------------------------------- */
236
237static inline void _put_byte(void **pp, u8 val)
238{
239 u8 *s = *pp;
240 *s++ = val;
241 *pp = s;
242}
243
244static inline void _put_word(void **pp, u32 val)
245{
246 u8 *s = *pp;
247 *s++ = val & 0xff;
248 *s++ = (val >> 8) & 0xff;
249 *s++ = (val >> 16) & 0xff;
250 *s++ = (val >> 24) & 0xff;
251 *pp = s;
252}
253
254static inline void _put_slice(void **pp, unsigned char *dp, unsigned int len)
255{
256 unsigned i = len;
257 _put_word(pp, i);
258 while (i-- > 0)
259 _put_byte(pp, *dp++);
260}
261
262static inline u8 _get_byte(void **pp)
263{
264 u8 *s = *pp;
265 u8 val;
266 val = *s++;
267 *pp = s;
268 return val;
269}
270
271static inline u32 _get_word(void **pp)
272{
273 u8 *s = *pp;
274 u32 val;
275 val = *s++;
276 val |= (*s++ << 8);
277 val |= (*s++ << 16);
278 val |= (*s++ << 24);
279 *pp = s;
280 return val;
281}
282
283static inline u32 _get_slice(void **pp, unsigned char *dp)
284{
285 unsigned int len, i;
286
287 len = i = _get_word(pp);
288 while (i-- > 0) *dp++ = _get_byte(pp);
289 return len;
290}
291
292/* ------------------------------------------------------------- */
293
294static void c4_reset(avmcard *card)
295{
296 unsigned long stop;
297
298 c4outmeml(card->mbase+DOORBELL, DBELL_RESET_ARM);
299
300 stop = jiffies + HZ*10;
301 while (c4inmeml(card->mbase+DOORBELL) != 0xffffffff) {
302 if (!time_before(jiffies, stop))
303 return;
304 c4outmeml(card->mbase+DOORBELL, DBELL_ADDR);
305 mb();
306 }
307
308 c4_poke(card, DC21285_ARMCSR_BASE + CHAN_1_CONTROL, 0);
309 c4_poke(card, DC21285_ARMCSR_BASE + CHAN_2_CONTROL, 0);
310}
311
312/* ------------------------------------------------------------- */
313
314static int c4_detect(avmcard *card)
315{
316 unsigned long stop, dummy;
317
318 c4outmeml(card->mbase+PCI_OUT_INT_MASK, 0x0c);
319 if (c4inmeml(card->mbase+PCI_OUT_INT_MASK) != 0x0c)
320 return 1;
321
322 c4outmeml(card->mbase+DOORBELL, DBELL_RESET_ARM);
323
324 stop = jiffies + HZ*10;
325 while (c4inmeml(card->mbase+DOORBELL) != 0xffffffff) {
326 if (!time_before(jiffies, stop))
327 return 2;
328 c4outmeml(card->mbase+DOORBELL, DBELL_ADDR);
329 mb();
330 }
331
332 c4_poke(card, DC21285_ARMCSR_BASE + CHAN_1_CONTROL, 0);
333 c4_poke(card, DC21285_ARMCSR_BASE + CHAN_2_CONTROL, 0);
334
335 c4outmeml(card->mbase+MAILBOX_0, 0x55aa55aa);
336 if (c4inmeml(card->mbase+MAILBOX_0) != 0x55aa55aa) return 3;
337
338 c4outmeml(card->mbase+MAILBOX_0, 0xaa55aa55);
339 if (c4inmeml(card->mbase+MAILBOX_0) != 0xaa55aa55) return 4;
340
341 if (c4_poke(card, DC21285_ARMCSR_BASE+DBELL_SA_MASK, 0)) return 5;
342 if (c4_poke(card, DC21285_ARMCSR_BASE+DBELL_PCI_MASK, 0)) return 6;
343 if (c4_poke(card, DC21285_ARMCSR_BASE+SA_CONTROL, SA_CTL_ALLRIGHT))
344 return 7;
345 if (c4_poke(card, DC21285_ARMCSR_BASE+XBUS_CYCLE, INIT_XBUS_CYCLE))
346 return 8;
347 if (c4_poke(card, DC21285_ARMCSR_BASE+XBUS_STROBE, INIT_XBUS_STROBE))
348 return 8;
349 if (c4_poke(card, DC21285_ARMCSR_BASE+DRAM_TIMING, 0)) return 9;
350
351 mdelay(1);
352
353 if (c4_peek(card, DC21285_DRAM_A0MR, &dummy)) return 10;
354 if (c4_peek(card, DC21285_DRAM_A1MR, &dummy)) return 11;
355 if (c4_peek(card, DC21285_DRAM_A2MR, &dummy)) return 12;
356 if (c4_peek(card, DC21285_DRAM_A3MR, &dummy)) return 13;
357
358 if (c4_poke(card, DC21285_DRAM_A0MR+CAS_OFFSET, 0)) return 14;
359 if (c4_poke(card, DC21285_DRAM_A1MR+CAS_OFFSET, 0)) return 15;
360 if (c4_poke(card, DC21285_DRAM_A2MR+CAS_OFFSET, 0)) return 16;
361 if (c4_poke(card, DC21285_DRAM_A3MR+CAS_OFFSET, 0)) return 17;
362
363 mdelay(1);
364
365 if (c4_poke(card, DC21285_ARMCSR_BASE+DRAM_TIMING, DRAM_TIMING_DEF))
366 return 18;
367
368 if (c4_poke(card, DC21285_ARMCSR_BASE+DRAM_ADDR_SIZE_0,DRAM_AD_SZ_DEF0))
369 return 19;
370 if (c4_poke(card, DC21285_ARMCSR_BASE+DRAM_ADDR_SIZE_1,DRAM_AD_SZ_NULL))
371 return 20;
372 if (c4_poke(card, DC21285_ARMCSR_BASE+DRAM_ADDR_SIZE_2,DRAM_AD_SZ_NULL))
373 return 21;
374 if (c4_poke(card, DC21285_ARMCSR_BASE+DRAM_ADDR_SIZE_3,DRAM_AD_SZ_NULL))
375 return 22;
376
377 /* Transputer test */
378
379 if ( c4_poke(card, 0x000000, 0x11111111)
380 || c4_poke(card, 0x400000, 0x22222222)
381 || c4_poke(card, 0x800000, 0x33333333)
382 || c4_poke(card, 0xC00000, 0x44444444))
383 return 23;
384
385 if ( c4_peek(card, 0x000000, &dummy) || dummy != 0x11111111
386 || c4_peek(card, 0x400000, &dummy) || dummy != 0x22222222
387 || c4_peek(card, 0x800000, &dummy) || dummy != 0x33333333
388 || c4_peek(card, 0xC00000, &dummy) || dummy != 0x44444444)
389 return 24;
390
391 if ( c4_poke(card, 0x000000, 0x55555555)
392 || c4_poke(card, 0x400000, 0x66666666)
393 || c4_poke(card, 0x800000, 0x77777777)
394 || c4_poke(card, 0xC00000, 0x88888888))
395 return 25;
396
397 if ( c4_peek(card, 0x000000, &dummy) || dummy != 0x55555555
398 || c4_peek(card, 0x400000, &dummy) || dummy != 0x66666666
399 || c4_peek(card, 0x800000, &dummy) || dummy != 0x77777777
400 || c4_peek(card, 0xC00000, &dummy) || dummy != 0x88888888)
401 return 26;
402
403 return 0;
404}
405
406/* ------------------------------------------------------------- */
407
408static void c4_dispatch_tx(avmcard *card)
409{
410 avmcard_dmainfo *dma = card->dma;
411 struct sk_buff *skb;
412 u8 cmd, subcmd;
413 u16 len;
414 u32 txlen;
415 void *p;
416
417
418 if (card->csr & DBELL_DOWN_ARM) { /* tx busy */
419 return;
420 }
421
422 skb = skb_dequeue(&dma->send_queue);
423 if (!skb) {
424#ifdef CONFIG_C4_DEBUG
425 printk(KERN_DEBUG "%s: tx underrun\n", card->name);
426#endif
427 return;
428 }
429
430 len = CAPIMSG_LEN(skb->data);
431
432 if (len) {
433 cmd = CAPIMSG_COMMAND(skb->data);
434 subcmd = CAPIMSG_SUBCOMMAND(skb->data);
435
436 p = dma->sendbuf.dmabuf;
437
438 if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) {
439 u16 dlen = CAPIMSG_DATALEN(skb->data);
440 _put_byte(&p, SEND_DATA_B3_REQ);
441 _put_slice(&p, skb->data, len);
442 _put_slice(&p, skb->data + len, dlen);
443 } else {
444 _put_byte(&p, SEND_MESSAGE);
445 _put_slice(&p, skb->data, len);
446 }
447 txlen = (u8 *)p - (u8 *)dma->sendbuf.dmabuf;
448#ifdef CONFIG_C4_DEBUG
449 printk(KERN_DEBUG "%s: tx put msg len=%d\n", card->name, txlen);
450#endif
451 } else {
452 txlen = skb->len-2;
453#ifdef CONFIG_C4_POLLDEBUG
454 if (skb->data[2] == SEND_POLLACK)
455 printk(KERN_INFO "%s: ack to c4\n", card->name);
456#endif
457#ifdef CONFIG_C4_DEBUG
458 printk(KERN_DEBUG "%s: tx put 0x%x len=%d\n",
459 card->name, skb->data[2], txlen);
460#endif
461 memcpy(dma->sendbuf.dmabuf, skb->data+2, skb->len-2);
462 }
463 txlen = (txlen + 3) & ~3;
464
465 c4outmeml(card->mbase+MBOX_DOWN_ADDR, dma->sendbuf.dmaaddr);
466 c4outmeml(card->mbase+MBOX_DOWN_LEN, txlen);
467
468 card->csr |= DBELL_DOWN_ARM;
469
470 c4outmeml(card->mbase+DOORBELL, DBELL_DOWN_ARM);
471
472 dev_kfree_skb_any(skb);
473}
474
475/* ------------------------------------------------------------- */
476
477static void queue_pollack(avmcard *card)
478{
479 struct sk_buff *skb;
480 void *p;
481
482 skb = alloc_skb(3, GFP_ATOMIC);
483 if (!skb) {
484 printk(KERN_CRIT "%s: no memory, lost poll ack\n",
485 card->name);
486 return;
487 }
488 p = skb->data;
489 _put_byte(&p, 0);
490 _put_byte(&p, 0);
491 _put_byte(&p, SEND_POLLACK);
492 skb_put(skb, (u8 *)p - (u8 *)skb->data);
493
494 skb_queue_tail(&card->dma->send_queue, skb);
495 c4_dispatch_tx(card);
496}
497
498/* ------------------------------------------------------------- */
499
500static void c4_handle_rx(avmcard *card)
501{
502 avmcard_dmainfo *dma = card->dma;
503 struct capi_ctr *ctrl;
504 avmctrl_info *cinfo;
505 struct sk_buff *skb;
506 void *p = dma->recvbuf.dmabuf;
507 u32 ApplId, MsgLen, DataB3Len, NCCI, WindowSize;
508 u8 b1cmd = _get_byte(&p);
509 u32 cidx;
510
511
512#ifdef CONFIG_C4_DEBUG
513 printk(KERN_DEBUG "%s: rx 0x%x len=%lu\n", card->name,
514 b1cmd, (unsigned long)dma->recvlen);
515#endif
516
517 switch (b1cmd) {
518 case RECEIVE_DATA_B3_IND:
519
520 ApplId = (unsigned) _get_word(&p);
521 MsgLen = _get_slice(&p, card->msgbuf);
522 DataB3Len = _get_slice(&p, card->databuf);
523 cidx = CAPIMSG_CONTROLLER(card->msgbuf)-card->cardnr;
524 if (cidx >= card->nlogcontr) cidx = 0;
525 ctrl = &card->ctrlinfo[cidx].capi_ctrl;
526
527 if (MsgLen < 30) { /* not CAPI 64Bit */
528 memset(card->msgbuf+MsgLen, 0, 30-MsgLen);
529 MsgLen = 30;
530 CAPIMSG_SETLEN(card->msgbuf, 30);
531 }
532 if (!(skb = alloc_skb(DataB3Len+MsgLen, GFP_ATOMIC))) {
533 printk(KERN_ERR "%s: incoming packet dropped\n",
534 card->name);
535 } else {
536 memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
537 memcpy(skb_put(skb, DataB3Len), card->databuf, DataB3Len);
538 capi_ctr_handle_message(ctrl, ApplId, skb);
539 }
540 break;
541
542 case RECEIVE_MESSAGE:
543
544 ApplId = (unsigned) _get_word(&p);
545 MsgLen = _get_slice(&p, card->msgbuf);
546 cidx = CAPIMSG_CONTROLLER(card->msgbuf)-card->cardnr;
547 if (cidx >= card->nlogcontr) cidx = 0;
548 cinfo = &card->ctrlinfo[cidx];
549 ctrl = &card->ctrlinfo[cidx].capi_ctrl;
550
551 if (!(skb = alloc_skb(MsgLen, GFP_ATOMIC))) {
552 printk(KERN_ERR "%s: incoming packet dropped\n",
553 card->name);
554 } else {
555 memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
556 if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_CONF)
557 capilib_data_b3_conf(&cinfo->ncci_head, ApplId,
558 CAPIMSG_NCCI(skb->data),
559 CAPIMSG_MSGID(skb->data));
560
561 capi_ctr_handle_message(ctrl, ApplId, skb);
562 }
563 break;
564
565 case RECEIVE_NEW_NCCI:
566
567 ApplId = _get_word(&p);
568 NCCI = _get_word(&p);
569 WindowSize = _get_word(&p);
570 cidx = (NCCI&0x7f) - card->cardnr;
571 if (cidx >= card->nlogcontr) cidx = 0;
572
573 capilib_new_ncci(&card->ctrlinfo[cidx].ncci_head, ApplId, NCCI, WindowSize);
574
575 break;
576
577 case RECEIVE_FREE_NCCI:
578
579 ApplId = _get_word(&p);
580 NCCI = _get_word(&p);
581
582 if (NCCI != 0xffffffff) {
583 cidx = (NCCI&0x7f) - card->cardnr;
584 if (cidx >= card->nlogcontr) cidx = 0;
585 capilib_free_ncci(&card->ctrlinfo[cidx].ncci_head, ApplId, NCCI);
586 }
587 break;
588
589 case RECEIVE_START:
590#ifdef CONFIG_C4_POLLDEBUG
591 printk(KERN_INFO "%s: poll from c4\n", card->name);
592#endif
593 if (!suppress_pollack)
594 queue_pollack(card);
595 for (cidx=0; cidx < card->nr_controllers; cidx++) {
596 ctrl = &card->ctrlinfo[cidx].capi_ctrl;
597 capi_ctr_resume_output(ctrl);
598 }
599 break;
600
601 case RECEIVE_STOP:
602 for (cidx=0; cidx < card->nr_controllers; cidx++) {
603 ctrl = &card->ctrlinfo[cidx].capi_ctrl;
604 capi_ctr_suspend_output(ctrl);
605 }
606 break;
607
608 case RECEIVE_INIT:
609
610 cidx = card->nlogcontr;
611 if (cidx >= card->nr_controllers) {
612 printk(KERN_ERR "%s: card with %d controllers ??\n",
613 card->name, cidx+1);
614 break;
615 }
616 card->nlogcontr++;
617 cinfo = &card->ctrlinfo[cidx];
618 ctrl = &cinfo->capi_ctrl;
619 cinfo->versionlen = _get_slice(&p, cinfo->versionbuf);
620 b1_parse_version(cinfo);
621 printk(KERN_INFO "%s: %s-card (%s) now active\n",
622 card->name,
623 cinfo->version[VER_CARDTYPE],
624 cinfo->version[VER_DRIVER]);
625 capi_ctr_ready(&cinfo->capi_ctrl);
626 break;
627
628 case RECEIVE_TASK_READY:
629 ApplId = (unsigned) _get_word(&p);
630 MsgLen = _get_slice(&p, card->msgbuf);
631 card->msgbuf[MsgLen] = 0;
632 while ( MsgLen > 0
633 && ( card->msgbuf[MsgLen-1] == '\n'
634 || card->msgbuf[MsgLen-1] == '\r')) {
635 card->msgbuf[MsgLen-1] = 0;
636 MsgLen--;
637 }
638 printk(KERN_INFO "%s: task %d \"%s\" ready.\n",
639 card->name, ApplId, card->msgbuf);
640 break;
641
642 case RECEIVE_DEBUGMSG:
643 MsgLen = _get_slice(&p, card->msgbuf);
644 card->msgbuf[MsgLen] = 0;
645 while ( MsgLen > 0
646 && ( card->msgbuf[MsgLen-1] == '\n'
647 || card->msgbuf[MsgLen-1] == '\r')) {
648 card->msgbuf[MsgLen-1] = 0;
649 MsgLen--;
650 }
651 printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf);
652 break;
653
654 default:
655 printk(KERN_ERR "%s: c4_interrupt: 0x%x ???\n",
656 card->name, b1cmd);
657 return;
658 }
659}
660
661/* ------------------------------------------------------------- */
662
663static irqreturn_t c4_handle_interrupt(avmcard *card)
664{
665 unsigned long flags;
666 u32 status;
667
668 spin_lock_irqsave(&card->lock, flags);
669 status = c4inmeml(card->mbase+DOORBELL);
670
671 if (status & DBELL_RESET_HOST) {
672 u_int i;
673 c4outmeml(card->mbase+PCI_OUT_INT_MASK, 0x0c);
674 spin_unlock_irqrestore(&card->lock, flags);
675 if (card->nlogcontr == 0)
676 return IRQ_HANDLED;
677 printk(KERN_ERR "%s: unexpected reset\n", card->name);
678 for (i=0; i < card->nr_controllers; i++) {
679 avmctrl_info *cinfo = &card->ctrlinfo[i];
680 memset(cinfo->version, 0, sizeof(cinfo->version));
681 capilib_release(&cinfo->ncci_head);
682 capi_ctr_reseted(&cinfo->capi_ctrl);
683 }
684 card->nlogcontr = 0;
685 return IRQ_HANDLED;
686 }
687
688 status &= (DBELL_UP_HOST | DBELL_DOWN_HOST);
689 if (!status) {
690 spin_unlock_irqrestore(&card->lock, flags);
691 return IRQ_HANDLED;
692 }
693 c4outmeml(card->mbase+DOORBELL, status);
694
695 if ((status & DBELL_UP_HOST) != 0) {
696 card->dma->recvlen = c4inmeml(card->mbase+MBOX_UP_LEN);
697 c4outmeml(card->mbase+MBOX_UP_LEN, 0);
698 c4_handle_rx(card);
699 card->dma->recvlen = 0;
700 c4outmeml(card->mbase+MBOX_UP_LEN, card->dma->recvbuf.size);
701 c4outmeml(card->mbase+DOORBELL, DBELL_UP_ARM);
702 }
703
704 if ((status & DBELL_DOWN_HOST) != 0) {
705 card->csr &= ~DBELL_DOWN_ARM;
706 c4_dispatch_tx(card);
707 } else if (card->csr & DBELL_DOWN_HOST) {
708 if (c4inmeml(card->mbase+MBOX_DOWN_LEN) == 0) {
709 card->csr &= ~DBELL_DOWN_ARM;
710 c4_dispatch_tx(card);
711 }
712 }
713 spin_unlock_irqrestore(&card->lock, flags);
714 return IRQ_HANDLED;
715}
716
717static irqreturn_t c4_interrupt(int interrupt, void *devptr, struct pt_regs *regs)
718{
719 avmcard *card = devptr;
720
721 return c4_handle_interrupt(card);
722}
723
724/* ------------------------------------------------------------- */
725
726static void c4_send_init(avmcard *card)
727{
728 struct sk_buff *skb;
729 void *p;
730
731 skb = alloc_skb(15, GFP_ATOMIC);
732 if (!skb) {
733 printk(KERN_CRIT "%s: no memory, lost register appl.\n",
734 card->name);
735 return;
736 }
737 p = skb->data;
738 _put_byte(&p, 0);
739 _put_byte(&p, 0);
740 _put_byte(&p, SEND_INIT);
741 _put_word(&p, CAPI_MAXAPPL);
742 _put_word(&p, AVM_NCCI_PER_CHANNEL*30);
743 _put_word(&p, card->cardnr - 1);
744 skb_put(skb, (u8 *)p - (u8 *)skb->data);
745
746 skb_queue_tail(&card->dma->send_queue, skb);
747 c4_dispatch_tx(card);
748}
749
750static int queue_sendconfigword(avmcard *card, u32 val)
751{
752 struct sk_buff *skb;
753 void *p;
754
755 skb = alloc_skb(3+4, GFP_ATOMIC);
756 if (!skb) {
757 printk(KERN_CRIT "%s: no memory, send config\n",
758 card->name);
759 return -ENOMEM;
760 }
761 p = skb->data;
762 _put_byte(&p, 0);
763 _put_byte(&p, 0);
764 _put_byte(&p, SEND_CONFIG);
765 _put_word(&p, val);
766 skb_put(skb, (u8 *)p - (u8 *)skb->data);
767
768 skb_queue_tail(&card->dma->send_queue, skb);
769 c4_dispatch_tx(card);
770 return 0;
771}
772
773static int queue_sendconfig(avmcard *card, char cval[4])
774{
775 struct sk_buff *skb;
776 unsigned long flags;
777 void *p;
778
779 skb = alloc_skb(3+4, GFP_ATOMIC);
780 if (!skb) {
781 printk(KERN_CRIT "%s: no memory, send config\n",
782 card->name);
783 return -ENOMEM;
784 }
785 p = skb->data;
786 _put_byte(&p, 0);
787 _put_byte(&p, 0);
788 _put_byte(&p, SEND_CONFIG);
789 _put_byte(&p, cval[0]);
790 _put_byte(&p, cval[1]);
791 _put_byte(&p, cval[2]);
792 _put_byte(&p, cval[3]);
793 skb_put(skb, (u8 *)p - (u8 *)skb->data);
794
795 skb_queue_tail(&card->dma->send_queue, skb);
796
797 spin_lock_irqsave(&card->lock, flags);
798 c4_dispatch_tx(card);
799 spin_unlock_irqrestore(&card->lock, flags);
800 return 0;
801}
802
803static int c4_send_config(avmcard *card, capiloaddatapart * config)
804{
805 u8 val[4];
806 unsigned char *dp;
807 u_int left;
808 int retval;
809
810 if ((retval = queue_sendconfigword(card, 1)) != 0)
811 return retval;
812 if ((retval = queue_sendconfigword(card, config->len)) != 0)
813 return retval;
814
815 dp = config->data;
816 left = config->len;
817 while (left >= sizeof(u32)) {
818 if (config->user) {
819 if (copy_from_user(val, dp, sizeof(val)))
820 return -EFAULT;
821 } else {
822 memcpy(val, dp, sizeof(val));
823 }
824 if ((retval = queue_sendconfig(card, val)) != 0)
825 return retval;
826 left -= sizeof(val);
827 dp += sizeof(val);
828 }
829 if (left) {
830 memset(val, 0, sizeof(val));
831 if (config->user) {
832 if (copy_from_user(&val, dp, left))
833 return -EFAULT;
834 } else {
835 memcpy(&val, dp, left);
836 }
837 if ((retval = queue_sendconfig(card, val)) != 0)
838 return retval;
839 }
840
841 return 0;
842}
843
844static int c4_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
845{
846 avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
847 avmcard *card = cinfo->card;
848 int retval;
849
850 if ((retval = c4_load_t4file(card, &data->firmware))) {
851 printk(KERN_ERR "%s: failed to load t4file!!\n",
852 card->name);
853 c4_reset(card);
854 return retval;
855 }
856
857 card->csr = 0;
858 c4outmeml(card->mbase+MBOX_UP_LEN, 0);
859 c4outmeml(card->mbase+MBOX_DOWN_LEN, 0);
860 c4outmeml(card->mbase+DOORBELL, DBELL_INIT);
861 mdelay(1);
862 c4outmeml(card->mbase+DOORBELL,
863 DBELL_UP_HOST | DBELL_DOWN_HOST | DBELL_RESET_HOST);
864
865 c4outmeml(card->mbase+PCI_OUT_INT_MASK, 0x08);
866
867 card->dma->recvlen = 0;
868 c4outmeml(card->mbase+MBOX_UP_ADDR, card->dma->recvbuf.dmaaddr);
869 c4outmeml(card->mbase+MBOX_UP_LEN, card->dma->recvbuf.size);
870 c4outmeml(card->mbase+DOORBELL, DBELL_UP_ARM);
871
872 if (data->configuration.len > 0 && data->configuration.data) {
873 retval = c4_send_config(card, &data->configuration);
874 if (retval) {
875 printk(KERN_ERR "%s: failed to set config!!\n",
876 card->name);
877 c4_reset(card);
878 return retval;
879 }
880 }
881
882 c4_send_init(card);
883
884 return 0;
885}
886
887
888void c4_reset_ctr(struct capi_ctr *ctrl)
889{
890 avmcard *card = ((avmctrl_info *)(ctrl->driverdata))->card;
891 avmctrl_info *cinfo;
892 u_int i;
893 unsigned long flags;
894
895 spin_lock_irqsave(&card->lock, flags);
896
897 c4_reset(card);
898
899 spin_unlock_irqrestore(&card->lock, flags);
900
901 for (i=0; i < card->nr_controllers; i++) {
902 cinfo = &card->ctrlinfo[i];
903 memset(cinfo->version, 0, sizeof(cinfo->version));
904 capi_ctr_reseted(&cinfo->capi_ctrl);
905 }
906 card->nlogcontr = 0;
907}
908
909static void c4_remove(struct pci_dev *pdev)
910{
911 avmcard *card = pci_get_drvdata(pdev);
912 avmctrl_info *cinfo;
913 u_int i;
914
915 if (!card)
916 return;
917
918 c4_reset(card);
919
920 for (i=0; i < card->nr_controllers; i++) {
921 cinfo = &card->ctrlinfo[i];
922 detach_capi_ctr(&cinfo->capi_ctrl);
923 }
924
925 free_irq(card->irq, card);
926 iounmap(card->mbase);
927 release_region(card->port, AVMB1_PORTLEN);
928 avmcard_dma_free(card->dma);
929 pci_set_drvdata(pdev, NULL);
930 b1_free_card(card);
931}
932
933/* ------------------------------------------------------------- */
934
935
936void c4_register_appl(struct capi_ctr *ctrl,
937 u16 appl,
938 capi_register_params *rp)
939{
940 avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
941 avmcard *card = cinfo->card;
942 struct sk_buff *skb;
943 int want = rp->level3cnt;
944 unsigned long flags;
945 int nconn;
946 void *p;
947
948 if (ctrl->cnr == card->cardnr) {
949
950 if (want > 0) nconn = want;
951 else nconn = ctrl->profile.nbchannel * 4 * -want;
952 if (nconn == 0) nconn = ctrl->profile.nbchannel * 4;
953
954 skb = alloc_skb(23, GFP_ATOMIC);
955 if (!skb) {
956 printk(KERN_CRIT "%s: no memory, lost register appl.\n",
957 card->name);
958 return;
959 }
960 p = skb->data;
961 _put_byte(&p, 0);
962 _put_byte(&p, 0);
963 _put_byte(&p, SEND_REGISTER);
964 _put_word(&p, appl);
965 _put_word(&p, 1024 * (nconn+1));
966 _put_word(&p, nconn);
967 _put_word(&p, rp->datablkcnt);
968 _put_word(&p, rp->datablklen);
969 skb_put(skb, (u8 *)p - (u8 *)skb->data);
970
971 skb_queue_tail(&card->dma->send_queue, skb);
972
973 spin_lock_irqsave(&card->lock, flags);
974 c4_dispatch_tx(card);
975 spin_unlock_irqrestore(&card->lock, flags);
976 }
977}
978
979/* ------------------------------------------------------------- */
980
981void c4_release_appl(struct capi_ctr *ctrl, u16 appl)
982{
983 avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
984 avmcard *card = cinfo->card;
985 unsigned long flags;
986 struct sk_buff *skb;
987 void *p;
988
989 capilib_release_appl(&cinfo->ncci_head, appl);
990
991 if (ctrl->cnr == card->cardnr) {
992 skb = alloc_skb(7, GFP_ATOMIC);
993 if (!skb) {
994 printk(KERN_CRIT "%s: no memory, lost release appl.\n",
995 card->name);
996 return;
997 }
998 p = skb->data;
999 _put_byte(&p, 0);
1000 _put_byte(&p, 0);
1001 _put_byte(&p, SEND_RELEASE);
1002 _put_word(&p, appl);
1003
1004 skb_put(skb, (u8 *)p - (u8 *)skb->data);
1005 skb_queue_tail(&card->dma->send_queue, skb);
1006 spin_lock_irqsave(&card->lock, flags);
1007 c4_dispatch_tx(card);
1008 spin_unlock_irqrestore(&card->lock, flags);
1009 }
1010}
1011
1012/* ------------------------------------------------------------- */
1013
1014
1015static u16 c4_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
1016{
1017 avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
1018 avmcard *card = cinfo->card;
1019 u16 retval = CAPI_NOERROR;
1020 unsigned long flags;
1021
1022 if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_REQ) {
1023 retval = capilib_data_b3_req(&cinfo->ncci_head,
1024 CAPIMSG_APPID(skb->data),
1025 CAPIMSG_NCCI(skb->data),
1026 CAPIMSG_MSGID(skb->data));
1027 }
1028 if (retval == CAPI_NOERROR) {
1029 skb_queue_tail(&card->dma->send_queue, skb);
1030 spin_lock_irqsave(&card->lock, flags);
1031 c4_dispatch_tx(card);
1032 spin_unlock_irqrestore(&card->lock, flags);
1033 }
1034 return retval;
1035}
1036
1037/* ------------------------------------------------------------- */
1038
1039static char *c4_procinfo(struct capi_ctr *ctrl)
1040{
1041 avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
1042
1043 if (!cinfo)
1044 return "";
1045 sprintf(cinfo->infobuf, "%s %s 0x%x %d 0x%lx",
1046 cinfo->cardname[0] ? cinfo->cardname : "-",
1047 cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-",
1048 cinfo->card ? cinfo->card->port : 0x0,
1049 cinfo->card ? cinfo->card->irq : 0,
1050 cinfo->card ? cinfo->card->membase : 0
1051 );
1052 return cinfo->infobuf;
1053}
1054
1055static int c4_read_proc(char *page, char **start, off_t off,
1056 int count, int *eof, struct capi_ctr *ctrl)
1057{
1058 avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
1059 avmcard *card = cinfo->card;
1060 u8 flag;
1061 int len = 0;
1062 char *s;
1063
1064 len += sprintf(page+len, "%-16s %s\n", "name", card->name);
1065 len += sprintf(page+len, "%-16s 0x%x\n", "io", card->port);
1066 len += sprintf(page+len, "%-16s %d\n", "irq", card->irq);
1067 len += sprintf(page+len, "%-16s 0x%lx\n", "membase", card->membase);
1068 switch (card->cardtype) {
1069 case avm_b1isa: s = "B1 ISA"; break;
1070 case avm_b1pci: s = "B1 PCI"; break;
1071 case avm_b1pcmcia: s = "B1 PCMCIA"; break;
1072 case avm_m1: s = "M1"; break;
1073 case avm_m2: s = "M2"; break;
1074 case avm_t1isa: s = "T1 ISA (HEMA)"; break;
1075 case avm_t1pci: s = "T1 PCI"; break;
1076 case avm_c4: s = "C4"; break;
1077 case avm_c2: s = "C2"; break;
1078 default: s = "???"; break;
1079 }
1080 len += sprintf(page+len, "%-16s %s\n", "type", s);
1081 if ((s = cinfo->version[VER_DRIVER]) != 0)
1082 len += sprintf(page+len, "%-16s %s\n", "ver_driver", s);
1083 if ((s = cinfo->version[VER_CARDTYPE]) != 0)
1084 len += sprintf(page+len, "%-16s %s\n", "ver_cardtype", s);
1085 if ((s = cinfo->version[VER_SERIAL]) != 0)
1086 len += sprintf(page+len, "%-16s %s\n", "ver_serial", s);
1087
1088 if (card->cardtype != avm_m1) {
1089 flag = ((u8 *)(ctrl->profile.manu))[3];
1090 if (flag)
1091 len += sprintf(page+len, "%-16s%s%s%s%s%s%s%s\n",
1092 "protocol",
1093 (flag & 0x01) ? " DSS1" : "",
1094 (flag & 0x02) ? " CT1" : "",
1095 (flag & 0x04) ? " VN3" : "",
1096 (flag & 0x08) ? " NI1" : "",
1097 (flag & 0x10) ? " AUSTEL" : "",
1098 (flag & 0x20) ? " ESS" : "",
1099 (flag & 0x40) ? " 1TR6" : ""
1100 );
1101 }
1102 if (card->cardtype != avm_m1) {
1103 flag = ((u8 *)(ctrl->profile.manu))[5];
1104 if (flag)
1105 len += sprintf(page+len, "%-16s%s%s%s%s\n",
1106 "linetype",
1107 (flag & 0x01) ? " point to point" : "",
1108 (flag & 0x02) ? " point to multipoint" : "",
1109 (flag & 0x08) ? " leased line without D-channel" : "",
1110 (flag & 0x04) ? " leased line with D-channel" : ""
1111 );
1112 }
1113 len += sprintf(page+len, "%-16s %s\n", "cardname", cinfo->cardname);
1114
1115 if (off+count >= len)
1116 *eof = 1;
1117 if (len < off)
1118 return 0;
1119 *start = page + off;
1120 return ((count < len-off) ? count : len-off);
1121}
1122
1123/* ------------------------------------------------------------- */
1124
1125static int c4_add_card(struct capicardparams *p, struct pci_dev *dev,
1126 int nr_controllers)
1127{
1128 avmcard *card;
1129 avmctrl_info *cinfo;
1130 int retval;
1131 int i;
1132
1133 card = b1_alloc_card(nr_controllers);
1134 if (!card) {
1135 printk(KERN_WARNING "c4: no memory.\n");
1136 retval = -ENOMEM;
1137 goto err;
1138 }
1139 card->dma = avmcard_dma_alloc("c4", dev, 2048+128, 2048+128);
1140 if (!card->dma) {
1141 printk(KERN_WARNING "c4: no memory.\n");
1142 retval = -ENOMEM;
1143 goto err_free;
1144 }
1145
1146 sprintf(card->name, "c%d-%x", nr_controllers, p->port);
1147 card->port = p->port;
1148 card->irq = p->irq;
1149 card->membase = p->membase;
1150 card->cardtype = (nr_controllers == 4) ? avm_c4 : avm_c2;
1151
1152 if (!request_region(card->port, AVMB1_PORTLEN, card->name)) {
1153 printk(KERN_WARNING "c4: ports 0x%03x-0x%03x in use.\n",
1154 card->port, card->port + AVMB1_PORTLEN);
1155 retval = -EBUSY;
1156 goto err_free_dma;
1157 }
1158
1159 card->mbase = ioremap(card->membase, 128);
1160 if (card->mbase == 0) {
1161 printk(KERN_NOTICE "c4: can't remap memory at 0x%lx\n",
1162 card->membase);
1163 retval = -EIO;
1164 goto err_release_region;
1165 }
1166
1167 retval = c4_detect(card);
1168 if (retval != 0) {
1169 printk(KERN_NOTICE "c4: NO card at 0x%x error(%d)\n",
1170 card->port, retval);
1171 retval = -EIO;
1172 goto err_unmap;
1173 }
1174 c4_reset(card);
1175
1176 retval = request_irq(card->irq, c4_interrupt, SA_SHIRQ, card->name, card);
1177 if (retval) {
1178 printk(KERN_ERR "c4: unable to get IRQ %d.\n",card->irq);
1179 retval = -EBUSY;
1180 goto err_unmap;
1181 }
1182
1183 for (i=0; i < nr_controllers ; i++) {
1184 cinfo = &card->ctrlinfo[i];
1185 cinfo->capi_ctrl.owner = THIS_MODULE;
1186 cinfo->capi_ctrl.driver_name = "c4";
1187 cinfo->capi_ctrl.driverdata = cinfo;
1188 cinfo->capi_ctrl.register_appl = c4_register_appl;
1189 cinfo->capi_ctrl.release_appl = c4_release_appl;
1190 cinfo->capi_ctrl.send_message = c4_send_message;
1191 cinfo->capi_ctrl.load_firmware = c4_load_firmware;
1192 cinfo->capi_ctrl.reset_ctr = c4_reset_ctr;
1193 cinfo->capi_ctrl.procinfo = c4_procinfo;
1194 cinfo->capi_ctrl.ctr_read_proc = c4_read_proc;
1195 strcpy(cinfo->capi_ctrl.name, card->name);
1196
1197 retval = attach_capi_ctr(&cinfo->capi_ctrl);
1198 if (retval) {
1199 printk(KERN_ERR "c4: attach controller failed (%d).\n", i);
1200 for (i--; i >= 0; i--) {
1201 cinfo = &card->ctrlinfo[i];
1202 detach_capi_ctr(&cinfo->capi_ctrl);
1203 }
1204 goto err_free_irq;
1205 }
1206 if (i == 0)
1207 card->cardnr = cinfo->capi_ctrl.cnr;
1208 }
1209
1210 printk(KERN_INFO "c4: AVM C%d at i/o %#x, irq %d, mem %#lx\n",
1211 nr_controllers, card->port, card->irq,
1212 card->membase);
1213 pci_set_drvdata(dev, card);
1214 return 0;
1215
1216 err_free_irq:
1217 free_irq(card->irq, card);
1218 err_unmap:
1219 iounmap(card->mbase);
1220 err_release_region:
1221 release_region(card->port, AVMB1_PORTLEN);
1222 err_free_dma:
1223 avmcard_dma_free(card->dma);
1224 err_free:
1225 b1_free_card(card);
1226 err:
1227 return retval;
1228}
1229
1230/* ------------------------------------------------------------- */
1231
1232static int __devinit c4_probe(struct pci_dev *dev,
1233 const struct pci_device_id *ent)
1234{
1235 int nr = ent->driver_data;
1236 int retval = 0;
1237 struct capicardparams param;
1238
1239 if (pci_enable_device(dev) < 0) {
1240 printk(KERN_ERR "c4: failed to enable AVM-C%d\n", nr);
1241 return -ENODEV;
1242 }
1243 pci_set_master(dev);
1244
1245 param.port = pci_resource_start(dev, 1);
1246 param.irq = dev->irq;
1247 param.membase = pci_resource_start(dev, 0);
1248
1249 printk(KERN_INFO "c4: PCI BIOS reports AVM-C%d at i/o %#x, irq %d, mem %#x\n",
1250 nr, param.port, param.irq, param.membase);
1251
1252 retval = c4_add_card(&param, dev, nr);
1253 if (retval != 0) {
1254 printk(KERN_ERR "c4: no AVM-C%d at i/o %#x, irq %d detected, mem %#x\n",
1255 nr, param.port, param.irq, param.membase);
1256 return -ENODEV;
1257 }
1258 return 0;
1259}
1260
1261static struct pci_driver c4_pci_driver = {
1262 .name = "c4",
1263 .id_table = c4_pci_tbl,
1264 .probe = c4_probe,
1265 .remove = c4_remove,
1266};
1267
1268static struct capi_driver capi_driver_c2 = {
1269 .name = "c2",
1270 .revision = "1.0",
1271};
1272
1273static struct capi_driver capi_driver_c4 = {
1274 .name = "c4",
1275 .revision = "1.0",
1276};
1277
1278static int __init c4_init(void)
1279{
1280 char *p;
1281 char rev[32];
1282 int err;
1283
1284 if ((p = strchr(revision, ':')) != 0 && p[1]) {
1285 strlcpy(rev, p + 2, 32);
1286 if ((p = strchr(rev, '$')) != 0 && p > rev)
1287 *(p-1) = 0;
1288 } else
1289 strcpy(rev, "1.0");
1290
1291 err = pci_register_driver(&c4_pci_driver);
1292 if (!err) {
1293 strlcpy(capi_driver_c2.revision, rev, 32);
1294 register_capi_driver(&capi_driver_c2);
1295 strlcpy(capi_driver_c4.revision, rev, 32);
1296 register_capi_driver(&capi_driver_c4);
1297 printk(KERN_INFO "c4: revision %s\n", rev);
1298 }
1299 return err;
1300}
1301
1302static void __exit c4_exit(void)
1303{
1304 unregister_capi_driver(&capi_driver_c2);
1305 unregister_capi_driver(&capi_driver_c4);
1306 pci_unregister_driver(&c4_pci_driver);
1307}
1308
1309module_init(c4_init);
1310module_exit(c4_exit);
diff --git a/drivers/isdn/hardware/avm/t1isa.c b/drivers/isdn/hardware/avm/t1isa.c
new file mode 100644
index 000000000000..cb9d9cee2a64
--- /dev/null
+++ b/drivers/isdn/hardware/avm/t1isa.c
@@ -0,0 +1,596 @@
1/* $Id: t1isa.c,v 1.1.2.3 2004/02/10 01:07:12 keil Exp $
2 *
3 * Module for AVM T1 HEMA-card.
4 *
5 * Copyright 1999 by Carsten Paeth <calle@calle.de>
6 *
7 * This software may be used and distributed according to the terms
8 * of the GNU General Public License, incorporated herein by reference.
9 *
10 */
11
12#include <linux/module.h>
13#include <linux/kernel.h>
14#include <linux/skbuff.h>
15#include <linux/delay.h>
16#include <linux/mm.h>
17#include <linux/interrupt.h>
18#include <linux/ioport.h>
19#include <linux/capi.h>
20#include <linux/netdevice.h>
21#include <linux/kernelcapi.h>
22#include <linux/init.h>
23#include <linux/pci.h>
24#include <asm/io.h>
25#include <linux/isdn/capicmd.h>
26#include <linux/isdn/capiutil.h>
27#include <linux/isdn/capilli.h>
28#include "avmcard.h"
29
30/* ------------------------------------------------------------- */
31
32static char *revision = "$Revision: 1.1.2.3 $";
33
34/* ------------------------------------------------------------- */
35
36MODULE_DESCRIPTION("CAPI4Linux: Driver for AVM T1 HEMA ISA card");
37MODULE_AUTHOR("Carsten Paeth");
38MODULE_LICENSE("GPL");
39
40/* ------------------------------------------------------------- */
41
42static int hema_irq_table[16] =
43{0,
44 0,
45 0,
46 0x80, /* irq 3 */
47 0,
48 0x90, /* irq 5 */
49 0,
50 0xA0, /* irq 7 */
51 0,
52 0xB0, /* irq 9 */
53 0xC0, /* irq 10 */
54 0xD0, /* irq 11 */
55 0xE0, /* irq 12 */
56 0,
57 0,
58 0xF0, /* irq 15 */
59};
60
61static int t1_detectandinit(unsigned int base, unsigned irq, int cardnr)
62{
63 unsigned char cregs[8];
64 unsigned char reverse_cardnr;
65 unsigned char dummy;
66 int i;
67
68 reverse_cardnr = ((cardnr & 0x01) << 3) | ((cardnr & 0x02) << 1)
69 | ((cardnr & 0x04) >> 1) | ((cardnr & 0x08) >> 3);
70 cregs[0] = (HEMA_VERSION_ID << 4) | (reverse_cardnr & 0xf);
71 cregs[1] = 0x00; /* fast & slow link connected to CON1 */
72 cregs[2] = 0x05; /* fast link 20MBit, slow link 20 MBit */
73 cregs[3] = 0;
74 cregs[4] = 0x11; /* zero wait state */
75 cregs[5] = hema_irq_table[irq & 0xf];
76 cregs[6] = 0;
77 cregs[7] = 0;
78
79 /*
80 * no one else should use the ISA bus in this moment,
81 * but no function there to prevent this :-(
82 * save_flags(flags); cli();
83 */
84
85 /* board reset */
86 t1outp(base, T1_RESETBOARD, 0xf);
87 mdelay(100);
88 dummy = t1inp(base, T1_FASTLINK+T1_OUTSTAT); /* first read */
89
90 /* write config */
91 dummy = (base >> 4) & 0xff;
92 for (i=1;i<=0xf;i++) t1outp(base, i, dummy);
93 t1outp(base, HEMA_PAL_ID & 0xf, dummy);
94 t1outp(base, HEMA_PAL_ID >> 4, cregs[0]);
95 for(i=1;i<7;i++) t1outp(base, 0, cregs[i]);
96 t1outp(base, ((base >> 4)) & 0x3, cregs[7]);
97 /* restore_flags(flags); */
98
99 mdelay(100);
100 t1outp(base, T1_FASTLINK+T1_RESETLINK, 0);
101 t1outp(base, T1_SLOWLINK+T1_RESETLINK, 0);
102 mdelay(10);
103 t1outp(base, T1_FASTLINK+T1_RESETLINK, 1);
104 t1outp(base, T1_SLOWLINK+T1_RESETLINK, 1);
105 mdelay(100);
106 t1outp(base, T1_FASTLINK+T1_RESETLINK, 0);
107 t1outp(base, T1_SLOWLINK+T1_RESETLINK, 0);
108 mdelay(10);
109 t1outp(base, T1_FASTLINK+T1_ANALYSE, 0);
110 mdelay(5);
111 t1outp(base, T1_SLOWLINK+T1_ANALYSE, 0);
112
113 if (t1inp(base, T1_FASTLINK+T1_OUTSTAT) != 0x1) /* tx empty */
114 return 1;
115 if (t1inp(base, T1_FASTLINK+T1_INSTAT) != 0x0) /* rx empty */
116 return 2;
117 if (t1inp(base, T1_FASTLINK+T1_IRQENABLE) != 0x0)
118 return 3;
119 if ((t1inp(base, T1_FASTLINK+T1_FIFOSTAT) & 0xf0) != 0x70)
120 return 4;
121 if ((t1inp(base, T1_FASTLINK+T1_IRQMASTER) & 0x0e) != 0)
122 return 5;
123 if ((t1inp(base, T1_FASTLINK+T1_IDENT) & 0x7d) != 1)
124 return 6;
125 if (t1inp(base, T1_SLOWLINK+T1_OUTSTAT) != 0x1) /* tx empty */
126 return 7;
127 if ((t1inp(base, T1_SLOWLINK+T1_IRQMASTER) & 0x0e) != 0)
128 return 8;
129 if ((t1inp(base, T1_SLOWLINK+T1_IDENT) & 0x7d) != 0)
130 return 9;
131 return 0;
132}
133
134static irqreturn_t t1isa_interrupt(int interrupt, void *devptr, struct pt_regs *regs)
135{
136 avmcard *card = devptr;
137 avmctrl_info *cinfo = &card->ctrlinfo[0];
138 struct capi_ctr *ctrl = &cinfo->capi_ctrl;
139 unsigned char b1cmd;
140 struct sk_buff *skb;
141
142 unsigned ApplId;
143 unsigned MsgLen;
144 unsigned DataB3Len;
145 unsigned NCCI;
146 unsigned WindowSize;
147 unsigned long flags;
148
149 spin_lock_irqsave(&card->lock, flags);
150
151 while (b1_rx_full(card->port)) {
152
153 b1cmd = b1_get_byte(card->port);
154
155 switch (b1cmd) {
156
157 case RECEIVE_DATA_B3_IND:
158
159 ApplId = (unsigned) b1_get_word(card->port);
160 MsgLen = t1_get_slice(card->port, card->msgbuf);
161 DataB3Len = t1_get_slice(card->port, card->databuf);
162 spin_unlock_irqrestore(&card->lock, flags);
163
164 if (MsgLen < 30) { /* not CAPI 64Bit */
165 memset(card->msgbuf+MsgLen, 0, 30-MsgLen);
166 MsgLen = 30;
167 CAPIMSG_SETLEN(card->msgbuf, 30);
168 }
169 if (!(skb = alloc_skb(DataB3Len+MsgLen, GFP_ATOMIC))) {
170 printk(KERN_ERR "%s: incoming packet dropped\n",
171 card->name);
172 } else {
173 memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
174 memcpy(skb_put(skb, DataB3Len), card->databuf, DataB3Len);
175 capi_ctr_handle_message(ctrl, ApplId, skb);
176 }
177 break;
178
179 case RECEIVE_MESSAGE:
180
181 ApplId = (unsigned) b1_get_word(card->port);
182 MsgLen = t1_get_slice(card->port, card->msgbuf);
183 spin_unlock_irqrestore(&card->lock, flags);
184 if (!(skb = alloc_skb(MsgLen, GFP_ATOMIC))) {
185 printk(KERN_ERR "%s: incoming packet dropped\n",
186 card->name);
187 } else {
188 memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
189 if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3)
190 capilib_data_b3_conf(&cinfo->ncci_head, ApplId,
191 CAPIMSG_NCCI(skb->data),
192 CAPIMSG_MSGID(skb->data));
193
194 capi_ctr_handle_message(ctrl, ApplId, skb);
195 }
196 break;
197
198 case RECEIVE_NEW_NCCI:
199
200 ApplId = b1_get_word(card->port);
201 NCCI = b1_get_word(card->port);
202 WindowSize = b1_get_word(card->port);
203 spin_unlock_irqrestore(&card->lock, flags);
204
205 capilib_new_ncci(&cinfo->ncci_head, ApplId, NCCI, WindowSize);
206
207 break;
208
209 case RECEIVE_FREE_NCCI:
210
211 ApplId = b1_get_word(card->port);
212 NCCI = b1_get_word(card->port);
213 spin_unlock_irqrestore(&card->lock, flags);
214
215 if (NCCI != 0xffffffff)
216 capilib_free_ncci(&cinfo->ncci_head, ApplId, NCCI);
217
218 break;
219
220 case RECEIVE_START:
221 b1_put_byte(card->port, SEND_POLLACK);
222 spin_unlock_irqrestore(&card->lock, flags);
223 capi_ctr_resume_output(ctrl);
224 break;
225
226 case RECEIVE_STOP:
227 spin_unlock_irqrestore(&card->lock, flags);
228 capi_ctr_suspend_output(ctrl);
229 break;
230
231 case RECEIVE_INIT:
232
233 cinfo->versionlen = t1_get_slice(card->port, cinfo->versionbuf);
234 spin_unlock_irqrestore(&card->lock, flags);
235 b1_parse_version(cinfo);
236 printk(KERN_INFO "%s: %s-card (%s) now active\n",
237 card->name,
238 cinfo->version[VER_CARDTYPE],
239 cinfo->version[VER_DRIVER]);
240 capi_ctr_ready(ctrl);
241 break;
242
243 case RECEIVE_TASK_READY:
244 ApplId = (unsigned) b1_get_word(card->port);
245 MsgLen = t1_get_slice(card->port, card->msgbuf);
246 spin_unlock_irqrestore(&card->lock, flags);
247 card->msgbuf[MsgLen] = 0;
248 while ( MsgLen > 0
249 && ( card->msgbuf[MsgLen-1] == '\n'
250 || card->msgbuf[MsgLen-1] == '\r')) {
251 card->msgbuf[MsgLen-1] = 0;
252 MsgLen--;
253 }
254 printk(KERN_INFO "%s: task %d \"%s\" ready.\n",
255 card->name, ApplId, card->msgbuf);
256 break;
257
258 case RECEIVE_DEBUGMSG:
259 MsgLen = t1_get_slice(card->port, card->msgbuf);
260 spin_unlock_irqrestore(&card->lock, flags);
261 card->msgbuf[MsgLen] = 0;
262 while ( MsgLen > 0
263 && ( card->msgbuf[MsgLen-1] == '\n'
264 || card->msgbuf[MsgLen-1] == '\r')) {
265 card->msgbuf[MsgLen-1] = 0;
266 MsgLen--;
267 }
268 printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf);
269 break;
270
271
272 case 0xff:
273 spin_unlock_irqrestore(&card->lock, flags);
274 printk(KERN_ERR "%s: card reseted ?\n", card->name);
275 return IRQ_HANDLED;
276 default:
277 spin_unlock_irqrestore(&card->lock, flags);
278 printk(KERN_ERR "%s: b1_interrupt: 0x%x ???\n",
279 card->name, b1cmd);
280 return IRQ_NONE;
281 }
282 }
283 return IRQ_HANDLED;
284}
285
286/* ------------------------------------------------------------- */
287
288static int t1isa_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
289{
290 avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
291 avmcard *card = cinfo->card;
292 unsigned int port = card->port;
293 unsigned long flags;
294 int retval;
295
296 t1_disable_irq(port);
297 b1_reset(port);
298
299 if ((retval = b1_load_t4file(card, &data->firmware))) {
300 b1_reset(port);
301 printk(KERN_ERR "%s: failed to load t4file!!\n",
302 card->name);
303 return retval;
304 }
305
306 if (data->configuration.len > 0 && data->configuration.data) {
307 if ((retval = b1_load_config(card, &data->configuration))) {
308 b1_reset(port);
309 printk(KERN_ERR "%s: failed to load config!!\n",
310 card->name);
311 return retval;
312 }
313 }
314
315 if (!b1_loaded(card)) {
316 printk(KERN_ERR "%s: failed to load t4file.\n", card->name);
317 return -EIO;
318 }
319
320 spin_lock_irqsave(&card->lock, flags);
321 b1_setinterrupt(port, card->irq, card->cardtype);
322 b1_put_byte(port, SEND_INIT);
323 b1_put_word(port, CAPI_MAXAPPL);
324 b1_put_word(port, AVM_NCCI_PER_CHANNEL*30);
325 b1_put_word(port, ctrl->cnr - 1);
326 spin_unlock_irqrestore(&card->lock, flags);
327
328 return 0;
329}
330
331void t1isa_reset_ctr(struct capi_ctr *ctrl)
332{
333 avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
334 avmcard *card = cinfo->card;
335 unsigned int port = card->port;
336
337 t1_disable_irq(port);
338 b1_reset(port);
339 b1_reset(port);
340
341 memset(cinfo->version, 0, sizeof(cinfo->version));
342 capilib_release(&cinfo->ncci_head);
343 capi_ctr_reseted(ctrl);
344}
345
346static void t1isa_remove(struct pci_dev *pdev)
347{
348 avmctrl_info *cinfo = pci_get_drvdata(pdev);
349 avmcard *card;
350
351 if (!cinfo)
352 return;
353
354 card = cinfo->card;
355
356 t1_disable_irq(card->port);
357 b1_reset(card->port);
358 b1_reset(card->port);
359 t1_reset(card->port);
360
361 detach_capi_ctr(&cinfo->capi_ctrl);
362 free_irq(card->irq, card);
363 release_region(card->port, AVMB1_PORTLEN);
364 b1_free_card(card);
365}
366
367/* ------------------------------------------------------------- */
368
369static u16 t1isa_send_message(struct capi_ctr *ctrl, struct sk_buff *skb);
370static char *t1isa_procinfo(struct capi_ctr *ctrl);
371
372static int t1isa_probe(struct pci_dev *pdev, int cardnr)
373{
374 avmctrl_info *cinfo;
375 avmcard *card;
376 int retval;
377
378 card = b1_alloc_card(1);
379 if (!card) {
380 printk(KERN_WARNING "t1isa: no memory.\n");
381 retval = -ENOMEM;
382 goto err;
383 }
384
385 cinfo = card->ctrlinfo;
386 card->port = pci_resource_start(pdev, 0);
387 card->irq = pdev->irq;
388 card->cardtype = avm_t1isa;
389 card->cardnr = cardnr;
390 sprintf(card->name, "t1isa-%x", card->port);
391
392 if (!(((card->port & 0x7) == 0) && ((card->port & 0x30) != 0x30))) {
393 printk(KERN_WARNING "t1isa: invalid port 0x%x.\n", card->port);
394 retval = -EINVAL;
395 goto err_free;
396 }
397 if (hema_irq_table[card->irq & 0xf] == 0) {
398 printk(KERN_WARNING "t1isa: irq %d not valid.\n", card->irq);
399 retval = -EINVAL;
400 goto err_free;
401 }
402 if (!request_region(card->port, AVMB1_PORTLEN, card->name)) {
403 printk(KERN_INFO "t1isa: ports 0x%03x-0x%03x in use.\n",
404 card->port, card->port + AVMB1_PORTLEN);
405 retval = -EBUSY;
406 goto err_free;
407 }
408 retval = request_irq(card->irq, t1isa_interrupt, 0, card->name, card);
409 if (retval) {
410 printk(KERN_INFO "t1isa: unable to get IRQ %d.\n", card->irq);
411 retval = -EBUSY;
412 goto err_release_region;
413 }
414
415 if ((retval = t1_detectandinit(card->port, card->irq, card->cardnr)) != 0) {
416 printk(KERN_INFO "t1isa: NO card at 0x%x (%d)\n",
417 card->port, retval);
418 retval = -ENODEV;
419 goto err_free_irq;
420 }
421 t1_disable_irq(card->port);
422 b1_reset(card->port);
423
424 cinfo->capi_ctrl.owner = THIS_MODULE;
425 cinfo->capi_ctrl.driver_name = "t1isa";
426 cinfo->capi_ctrl.driverdata = cinfo;
427 cinfo->capi_ctrl.register_appl = b1_register_appl;
428 cinfo->capi_ctrl.release_appl = b1_release_appl;
429 cinfo->capi_ctrl.send_message = t1isa_send_message;
430 cinfo->capi_ctrl.load_firmware = t1isa_load_firmware;
431 cinfo->capi_ctrl.reset_ctr = t1isa_reset_ctr;
432 cinfo->capi_ctrl.procinfo = t1isa_procinfo;
433 cinfo->capi_ctrl.ctr_read_proc = b1ctl_read_proc;
434 strcpy(cinfo->capi_ctrl.name, card->name);
435
436 retval = attach_capi_ctr(&cinfo->capi_ctrl);
437 if (retval) {
438 printk(KERN_INFO "t1isa: attach controller failed.\n");
439 goto err_free_irq;
440 }
441
442 printk(KERN_INFO "t1isa: AVM T1 ISA at i/o %#x, irq %d, card %d\n",
443 card->port, card->irq, card->cardnr);
444
445 pci_set_drvdata(pdev, cinfo);
446 return 0;
447
448 err_free_irq:
449 free_irq(card->irq, card);
450 err_release_region:
451 release_region(card->port, AVMB1_PORTLEN);
452 err_free:
453 b1_free_card(card);
454 err:
455 return retval;
456}
457
458static u16 t1isa_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
459{
460 avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
461 avmcard *card = cinfo->card;
462 unsigned int port = card->port;
463 unsigned long flags;
464 u16 len = CAPIMSG_LEN(skb->data);
465 u8 cmd = CAPIMSG_COMMAND(skb->data);
466 u8 subcmd = CAPIMSG_SUBCOMMAND(skb->data);
467 u16 dlen, retval;
468
469 if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) {
470 retval = capilib_data_b3_req(&cinfo->ncci_head,
471 CAPIMSG_APPID(skb->data),
472 CAPIMSG_NCCI(skb->data),
473 CAPIMSG_MSGID(skb->data));
474 if (retval != CAPI_NOERROR)
475 return retval;
476
477 dlen = CAPIMSG_DATALEN(skb->data);
478
479 spin_lock_irqsave(&card->lock, flags);
480 b1_put_byte(port, SEND_DATA_B3_REQ);
481 t1_put_slice(port, skb->data, len);
482 t1_put_slice(port, skb->data + len, dlen);
483 spin_unlock_irqrestore(&card->lock, flags);
484 } else {
485
486 spin_lock_irqsave(&card->lock, flags);
487 b1_put_byte(port, SEND_MESSAGE);
488 t1_put_slice(port, skb->data, len);
489 spin_unlock_irqrestore(&card->lock, flags);
490 }
491
492 dev_kfree_skb_any(skb);
493 return CAPI_NOERROR;
494}
495/* ------------------------------------------------------------- */
496
497static char *t1isa_procinfo(struct capi_ctr *ctrl)
498{
499 avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
500
501 if (!cinfo)
502 return "";
503 sprintf(cinfo->infobuf, "%s %s 0x%x %d %d",
504 cinfo->cardname[0] ? cinfo->cardname : "-",
505 cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-",
506 cinfo->card ? cinfo->card->port : 0x0,
507 cinfo->card ? cinfo->card->irq : 0,
508 cinfo->card ? cinfo->card->cardnr : 0
509 );
510 return cinfo->infobuf;
511}
512
513
514/* ------------------------------------------------------------- */
515
516#define MAX_CARDS 4
517static struct pci_dev isa_dev[MAX_CARDS];
518static int io[MAX_CARDS];
519static int irq[MAX_CARDS];
520static int cardnr[MAX_CARDS];
521
522MODULE_PARM(io, "1-" __MODULE_STRING(MAX_CARDS) "i");
523MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_CARDS) "i");
524MODULE_PARM(cardnr, "1-" __MODULE_STRING(MAX_CARDS) "i");
525MODULE_PARM_DESC(io, "I/O base address(es)");
526MODULE_PARM_DESC(irq, "IRQ number(s) (assigned)");
527MODULE_PARM_DESC(cardnr, "Card number(s) (as jumpered)");
528
529static int t1isa_add_card(struct capi_driver *driver, capicardparams *data)
530{
531 int i;
532
533 for (i = 0; i < MAX_CARDS; i++) {
534 if (isa_dev[i].resource[0].start)
535 continue;
536
537 isa_dev[i].resource[0].start = data->port;
538 isa_dev[i].irq = data->irq;
539
540 if (t1isa_probe(&isa_dev[i], data->cardnr) == 0)
541 return 0;
542 }
543 return -ENODEV;
544}
545
546static struct capi_driver capi_driver_t1isa = {
547 .name = "t1isa",
548 .revision = "1.0",
549 .add_card = t1isa_add_card,
550};
551
552static int __init t1isa_init(void)
553{
554 char rev[32];
555 char *p;
556 int i;
557
558 if ((p = strchr(revision, ':')) != 0 && p[1]) {
559 strlcpy(rev, p + 2, 32);
560 if ((p = strchr(rev, '$')) != 0 && p > rev)
561 *(p-1) = 0;
562 } else
563 strcpy(rev, "1.0");
564
565 for (i = 0; i < MAX_CARDS; i++) {
566 if (!io[i])
567 break;
568
569 isa_dev[i].resource[0].start = io[i];
570 isa_dev[i].irq = irq[i];
571
572 if (t1isa_probe(&isa_dev[i], cardnr[i]) != 0)
573 return -ENODEV;
574 }
575
576 strlcpy(capi_driver_t1isa.revision, rev, 32);
577 register_capi_driver(&capi_driver_t1isa);
578 printk(KERN_INFO "t1isa: revision %s\n", rev);
579
580 return 0;
581}
582
583static void __exit t1isa_exit(void)
584{
585 int i;
586
587 for (i = 0; i < MAX_CARDS; i++) {
588 if (!io[i])
589 break;
590
591 t1isa_remove(&isa_dev[i]);
592 }
593}
594
595module_init(t1isa_init);
596module_exit(t1isa_exit);
diff --git a/drivers/isdn/hardware/avm/t1pci.c b/drivers/isdn/hardware/avm/t1pci.c
new file mode 100644
index 000000000000..2ceec8e8419f
--- /dev/null
+++ b/drivers/isdn/hardware/avm/t1pci.c
@@ -0,0 +1,260 @@
1/* $Id: t1pci.c,v 1.1.2.2 2004/01/16 21:09:27 keil Exp $
2 *
3 * Module for AVM T1 PCI-card.
4 *
5 * Copyright 1999 by Carsten Paeth <calle@calle.de>
6 *
7 * This software may be used and distributed according to the terms
8 * of the GNU General Public License, incorporated herein by reference.
9 *
10 */
11
12#include <linux/config.h>
13#include <linux/module.h>
14#include <linux/kernel.h>
15#include <linux/skbuff.h>
16#include <linux/delay.h>
17#include <linux/mm.h>
18#include <linux/interrupt.h>
19#include <linux/ioport.h>
20#include <linux/pci.h>
21#include <linux/capi.h>
22#include <linux/init.h>
23#include <asm/io.h>
24#include <linux/isdn/capicmd.h>
25#include <linux/isdn/capiutil.h>
26#include <linux/isdn/capilli.h>
27#include "avmcard.h"
28
29#undef CONFIG_T1PCI_DEBUG
30#undef CONFIG_T1PCI_POLLDEBUG
31
32/* ------------------------------------------------------------- */
33static char *revision = "$Revision: 1.1.2.2 $";
34/* ------------------------------------------------------------- */
35
36static struct pci_device_id t1pci_pci_tbl[] = {
37 { PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_T1, PCI_ANY_ID, PCI_ANY_ID },
38 { } /* Terminating entry */
39};
40
41MODULE_DEVICE_TABLE(pci, t1pci_pci_tbl);
42MODULE_DESCRIPTION("CAPI4Linux: Driver for AVM T1 PCI card");
43MODULE_AUTHOR("Carsten Paeth");
44MODULE_LICENSE("GPL");
45
46/* ------------------------------------------------------------- */
47
48static char *t1pci_procinfo(struct capi_ctr *ctrl);
49
50static int t1pci_add_card(struct capicardparams *p, struct pci_dev *pdev)
51{
52 avmcard *card;
53 avmctrl_info *cinfo;
54 int retval;
55
56 card = b1_alloc_card(1);
57 if (!card) {
58 printk(KERN_WARNING "t1pci: no memory.\n");
59 retval = -ENOMEM;
60 goto err;
61 }
62
63 card->dma = avmcard_dma_alloc("t1pci", pdev, 2048+128, 2048+128);
64 if (!card->dma) {
65 printk(KERN_WARNING "t1pci: no memory.\n");
66 retval = -ENOMEM;
67 goto err_free;
68 }
69
70 cinfo = card->ctrlinfo;
71 sprintf(card->name, "t1pci-%x", p->port);
72 card->port = p->port;
73 card->irq = p->irq;
74 card->membase = p->membase;
75 card->cardtype = avm_t1pci;
76
77 if (!request_region(card->port, AVMB1_PORTLEN, card->name)) {
78 printk(KERN_WARNING "t1pci: ports 0x%03x-0x%03x in use.\n",
79 card->port, card->port + AVMB1_PORTLEN);
80 retval = -EBUSY;
81 goto err_free_dma;
82 }
83
84 card->mbase = ioremap(card->membase, 64);
85 if (!card->mbase) {
86 printk(KERN_NOTICE "t1pci: can't remap memory at 0x%lx\n",
87 card->membase);
88 retval = -EIO;
89 goto err_release_region;
90 }
91
92 b1dma_reset(card);
93
94 retval = t1pci_detect(card);
95 if (retval != 0) {
96 if (retval < 6)
97 printk(KERN_NOTICE "t1pci: NO card at 0x%x (%d)\n",
98 card->port, retval);
99 else
100 printk(KERN_NOTICE "t1pci: card at 0x%x, but cable not connected or T1 has no power (%d)\n",
101 card->port, retval);
102 retval = -EIO;
103 goto err_unmap;
104 }
105 b1dma_reset(card);
106
107 retval = request_irq(card->irq, b1dma_interrupt, SA_SHIRQ, card->name, card);
108 if (retval) {
109 printk(KERN_ERR "t1pci: unable to get IRQ %d.\n", card->irq);
110 retval = -EBUSY;
111 goto err_unmap;
112 }
113
114 cinfo->capi_ctrl.owner = THIS_MODULE;
115 cinfo->capi_ctrl.driver_name = "t1pci";
116 cinfo->capi_ctrl.driverdata = cinfo;
117 cinfo->capi_ctrl.register_appl = b1dma_register_appl;
118 cinfo->capi_ctrl.release_appl = b1dma_release_appl;
119 cinfo->capi_ctrl.send_message = b1dma_send_message;
120 cinfo->capi_ctrl.load_firmware = b1dma_load_firmware;
121 cinfo->capi_ctrl.reset_ctr = b1dma_reset_ctr;
122 cinfo->capi_ctrl.procinfo = t1pci_procinfo;
123 cinfo->capi_ctrl.ctr_read_proc = b1dmactl_read_proc;
124 strcpy(cinfo->capi_ctrl.name, card->name);
125
126 retval = attach_capi_ctr(&cinfo->capi_ctrl);
127 if (retval) {
128 printk(KERN_ERR "t1pci: attach controller failed.\n");
129 retval = -EBUSY;
130 goto err_free_irq;
131 }
132 card->cardnr = cinfo->capi_ctrl.cnr;
133
134 printk(KERN_INFO "t1pci: AVM T1 PCI at i/o %#x, irq %d, mem %#lx\n",
135 card->port, card->irq, card->membase);
136
137 pci_set_drvdata(pdev, card);
138 return 0;
139
140 err_free_irq:
141 free_irq(card->irq, card);
142 err_unmap:
143 iounmap(card->mbase);
144 err_release_region:
145 release_region(card->port, AVMB1_PORTLEN);
146 err_free_dma:
147 avmcard_dma_free(card->dma);
148 err_free:
149 b1_free_card(card);
150 err:
151 return retval;
152}
153
154/* ------------------------------------------------------------- */
155
156static void t1pci_remove(struct pci_dev *pdev)
157{
158 avmcard *card = pci_get_drvdata(pdev);
159 avmctrl_info *cinfo = card->ctrlinfo;
160
161 b1dma_reset(card);
162
163 detach_capi_ctr(&cinfo->capi_ctrl);
164 free_irq(card->irq, card);
165 iounmap(card->mbase);
166 release_region(card->port, AVMB1_PORTLEN);
167 avmcard_dma_free(card->dma);
168 b1_free_card(card);
169}
170
171/* ------------------------------------------------------------- */
172
173static char *t1pci_procinfo(struct capi_ctr *ctrl)
174{
175 avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
176
177 if (!cinfo)
178 return "";
179 sprintf(cinfo->infobuf, "%s %s 0x%x %d 0x%lx",
180 cinfo->cardname[0] ? cinfo->cardname : "-",
181 cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-",
182 cinfo->card ? cinfo->card->port : 0x0,
183 cinfo->card ? cinfo->card->irq : 0,
184 cinfo->card ? cinfo->card->membase : 0
185 );
186 return cinfo->infobuf;
187}
188
189/* ------------------------------------------------------------- */
190
191static int __devinit t1pci_probe(struct pci_dev *dev,
192 const struct pci_device_id *ent)
193{
194 struct capicardparams param;
195 int retval;
196
197 if (pci_enable_device(dev) < 0) {
198 printk(KERN_ERR "t1pci: failed to enable AVM-T1-PCI\n");
199 return -ENODEV;
200 }
201 pci_set_master(dev);
202
203 param.port = pci_resource_start(dev, 1);
204 param.irq = dev->irq;
205 param.membase = pci_resource_start(dev, 0);
206
207 printk(KERN_INFO "t1pci: PCI BIOS reports AVM-T1-PCI at i/o %#x, irq %d, mem %#x\n",
208 param.port, param.irq, param.membase);
209
210 retval = t1pci_add_card(&param, dev);
211 if (retval != 0) {
212 printk(KERN_ERR "t1pci: no AVM-T1-PCI at i/o %#x, irq %d detected, mem %#x\n",
213 param.port, param.irq, param.membase);
214 return -ENODEV;
215 }
216 return 0;
217}
218
219static struct pci_driver t1pci_pci_driver = {
220 .name = "t1pci",
221 .id_table = t1pci_pci_tbl,
222 .probe = t1pci_probe,
223 .remove = t1pci_remove,
224};
225
226static struct capi_driver capi_driver_t1pci = {
227 .name = "t1pci",
228 .revision = "1.0",
229};
230
231static int __init t1pci_init(void)
232{
233 char *p;
234 char rev[32];
235 int err;
236
237 if ((p = strchr(revision, ':')) != 0 && p[1]) {
238 strlcpy(rev, p + 2, 32);
239 if ((p = strchr(rev, '$')) != 0 && p > rev)
240 *(p-1) = 0;
241 } else
242 strcpy(rev, "1.0");
243
244 err = pci_register_driver(&t1pci_pci_driver);
245 if (!err) {
246 strlcpy(capi_driver_t1pci.revision, rev, 32);
247 register_capi_driver(&capi_driver_t1pci);
248 printk(KERN_INFO "t1pci: revision %s\n", rev);
249 }
250 return err;
251}
252
253static void __exit t1pci_exit(void)
254{
255 unregister_capi_driver(&capi_driver_t1pci);
256 pci_unregister_driver(&t1pci_pci_driver);
257}
258
259module_init(t1pci_init);
260module_exit(t1pci_exit);
diff --git a/drivers/isdn/hardware/eicon/Kconfig b/drivers/isdn/hardware/eicon/Kconfig
new file mode 100644
index 000000000000..51e66bc64208
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/Kconfig
@@ -0,0 +1,53 @@
1#
2# ISDN DIVAS Eicon driver
3#
4
5menu "Active Eicon DIVA Server cards"
6 depends on NET && ISDN && ISDN_CAPI!=n
7
8config CAPI_EICON
9 bool "Support Eicon cards"
10 help
11 Enable support for Eicon Networks active ISDN cards.
12
13config ISDN_DIVAS
14 tristate "Support Eicon DIVA Server cards"
15 depends on CAPI_EICON && PROC_FS && PCI
16 help
17 Say Y here if you have an Eicon Networks DIVA Server PCI ISDN card.
18 In order to use this card, additional firmware is necessary, which
19 has to be downloaded into the card using the divactrl utility.
20
21config ISDN_DIVAS_BRIPCI
22 bool "DIVA Server BRI/PCI support"
23 depends on ISDN_DIVAS
24 help
25 Enable support for DIVA Server BRI-PCI.
26
27config ISDN_DIVAS_PRIPCI
28 bool "DIVA Server PRI/PCI support"
29 depends on ISDN_DIVAS
30 help
31 Enable support for DIVA Server PRI-PCI.
32
33config ISDN_DIVAS_DIVACAPI
34 tristate "DIVA CAPI2.0 interface support"
35 depends on ISDN_DIVAS && ISDN_CAPI
36 help
37 You need this to provide the CAPI interface
38 for DIVA Server cards.
39
40config ISDN_DIVAS_USERIDI
41 tristate "DIVA User-IDI interface support"
42 depends on ISDN_DIVAS
43 help
44 Enable support for user-mode IDI interface.
45
46config ISDN_DIVAS_MAINT
47 tristate "DIVA Maint driver support"
48 depends on ISDN_DIVAS && m
49 help
50 Enable Divas Maintainance driver.
51
52endmenu
53
diff --git a/drivers/isdn/hardware/eicon/Makefile b/drivers/isdn/hardware/eicon/Makefile
new file mode 100644
index 000000000000..4fa7fdb7df0d
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/Makefile
@@ -0,0 +1,23 @@
1# Makefile for the Eicon DIVA ISDN drivers.
2
3# Each configuration option enables a list of files.
4
5obj-$(CONFIG_ISDN_DIVAS) += divadidd.o divas.o
6obj-$(CONFIG_ISDN_DIVAS_MAINT) += diva_mnt.o
7obj-$(CONFIG_ISDN_DIVAS_USERIDI) += diva_idi.o
8obj-$(CONFIG_ISDN_DIVAS_DIVACAPI) += divacapi.o
9
10# Multipart objects.
11
12divas-y := divasmain.o divasfunc.o di.o io.o istream.o \
13 diva.o divasproc.o diva_dma.o
14divas-$(CONFIG_ISDN_DIVAS_BRIPCI) += os_bri.o s_bri.o os_4bri.o s_4bri.o
15divas-$(CONFIG_ISDN_DIVAS_PRIPCI) += os_pri.o s_pri.o
16
17divacapi-y := capimain.o capifunc.o message.o capidtmf.o
18
19divadidd-y := diva_didd.o diddfunc.o dadapter.o
20
21diva_mnt-y := divamnt.o mntfunc.o debug.o maintidi.o
22
23diva_idi-y := divasi.o idifunc.o um_idi.o dqueue.o
diff --git a/drivers/isdn/hardware/eicon/adapter.h b/drivers/isdn/hardware/eicon/adapter.h
new file mode 100644
index 000000000000..71a7c2f084a7
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/adapter.h
@@ -0,0 +1,17 @@
1/* $Id: adapter.h,v 1.4 2004/03/21 17:26:01 armin Exp $ */
2
3#ifndef __DIVA_USER_MODE_IDI_ADAPTER_H__
4#define __DIVA_USER_MODE_IDI_ADAPTER_H__
5
6#define DIVA_UM_IDI_ADAPTER_REMOVED 0x00000001
7
8typedef struct _diva_um_idi_adapter {
9 struct list_head link;
10 DESCRIPTOR d;
11 int adapter_nr;
12 struct list_head entity_q; /* entities linked to this adapter */
13 dword status;
14} diva_um_idi_adapter_t;
15
16
17#endif
diff --git a/drivers/isdn/hardware/eicon/capi20.h b/drivers/isdn/hardware/eicon/capi20.h
new file mode 100644
index 000000000000..7ebcccda74d8
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/capi20.h
@@ -0,0 +1,699 @@
1
2/*
3 *
4 Copyright (c) Eicon Networks, 2002.
5 *
6 This source file is supplied for the use with
7 Eicon Networks range of DIVA Server Adapters.
8 *
9 Eicon File Revision : 2.1
10 *
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2, or (at your option)
14 any later version.
15 *
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
18 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 See the GNU General Public License for more details.
20 *
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26#ifndef _INC_CAPI20
27#define _INC_CAPI20
28 /* operations on message queues */
29 /* the common device type for CAPI20 drivers */
30#define FILE_DEVICE_CAPI20 0x8001
31 /* DEVICE_CONTROL codes for user and kernel mode applications */
32#define CAPI20_CTL_REGISTER 0x0801
33#define CAPI20_CTL_RELEASE 0x0802
34#define CAPI20_CTL_GET_MANUFACTURER 0x0805
35#define CAPI20_CTL_GET_VERSION 0x0806
36#define CAPI20_CTL_GET_SERIAL 0x0807
37#define CAPI20_CTL_GET_PROFILE 0x0808
38 /* INTERNAL_DEVICE_CONTROL codes for kernel mode applicatios only */
39#define CAPI20_CTL_PUT_MESSAGE 0x0803
40#define CAPI20_CTL_GET_MESSAGE 0x0804
41 /* the wrapped codes as required by the system */
42#define CAPI_CTL_CODE(f,m) CTL_CODE(FILE_DEVICE_CAPI20,f,m,FILE_ANY_ACCESS)
43#define IOCTL_CAPI_REGISTER CAPI_CTL_CODE(CAPI20_CTL_REGISTER,METHOD_BUFFERED)
44#define IOCTL_CAPI_RELEASE CAPI_CTL_CODE(CAPI20_CTL_RELEASE,METHOD_BUFFERED)
45#define IOCTL_CAPI_GET_MANUFACTURER CAPI_CTL_CODE(CAPI20_CTL_GET_MANUFACTURER,METHOD_BUFFERED)
46#define IOCTL_CAPI_GET_VERSION CAPI_CTL_CODE(CAPI20_CTL_GET_VERSION,METHOD_BUFFERED)
47#define IOCTL_CAPI_GET_SERIAL CAPI_CTL_CODE(CAPI20_CTL_GET_SERIAL,METHOD_BUFFERED)
48#define IOCTL_CAPI_GET_PROFILE CAPI_CTL_CODE(CAPI20_CTL_GET_PROFILE,METHOD_BUFFERED)
49#define IOCTL_CAPI_PUT_MESSAGE CAPI_CTL_CODE(CAPI20_CTL_PUT_MESSAGE,METHOD_BUFFERED)
50#define IOCTL_CAPI_GET_MESSAGE CAPI_CTL_CODE(CAPI20_CTL_GET_MESSAGE,METHOD_BUFFERED)
51struct divas_capi_register_params {
52 word MessageBufferSize;
53 word maxLogicalConnection;
54 word maxBDataBlocks;
55 word maxBDataLen;
56};
57struct divas_capi_version {
58 word CapiMajor;
59 word CapiMinor;
60 word ManuMajor;
61 word ManuMinor;
62};
63typedef struct api_profile_s {
64 word Number;
65 word Channels;
66 dword Global_Options;
67 dword B1_Protocols;
68 dword B2_Protocols;
69 dword B3_Protocols;
70} API_PROFILE;
71 /* ISDN Common API message types */
72#define _ALERT_R 0x8001
73#define _CONNECT_R 0x8002
74#define _CONNECT_I 0x8202
75#define _CONNECT_ACTIVE_I 0x8203
76#define _DISCONNECT_R 0x8004
77#define _DISCONNECT_I 0x8204
78#define _LISTEN_R 0x8005
79#define _INFO_R 0x8008
80#define _INFO_I 0x8208
81#define _SELECT_B_REQ 0x8041
82#define _FACILITY_R 0x8080
83#define _FACILITY_I 0x8280
84#define _CONNECT_B3_R 0x8082
85#define _CONNECT_B3_I 0x8282
86#define _CONNECT_B3_ACTIVE_I 0x8283
87#define _DISCONNECT_B3_R 0x8084
88#define _DISCONNECT_B3_I 0x8284
89#define _DATA_B3_R 0x8086
90#define _DATA_B3_I 0x8286
91#define _RESET_B3_R 0x8087
92#define _RESET_B3_I 0x8287
93#define _CONNECT_B3_T90_ACTIVE_I 0x8288
94#define _MANUFACTURER_R 0x80ff
95#define _MANUFACTURER_I 0x82ff
96 /* OR this to convert a REQUEST to a CONFIRM */
97#define CONFIRM 0x0100
98 /* OR this to convert a INDICATION to a RESPONSE */
99#define RESPONSE 0x0100
100/*------------------------------------------------------------------*/
101/* diehl isdn private MANUFACTURER codes */
102/*------------------------------------------------------------------*/
103#define _DI_MANU_ID 0x44444944
104#define _DI_ASSIGN_PLCI 0x0001
105#define _DI_ADV_CODEC 0x0002
106#define _DI_DSP_CTRL 0x0003
107#define _DI_SIG_CTRL 0x0004
108#define _DI_RXT_CTRL 0x0005
109#define _DI_IDI_CTRL 0x0006
110#define _DI_CFG_CTRL 0x0007
111#define _DI_REMOVE_CODEC 0x0008
112#define _DI_OPTIONS_REQUEST 0x0009
113#define _DI_SSEXT_CTRL 0x000a
114#define _DI_NEGOTIATE_B3 0x000b
115/*------------------------------------------------------------------*/
116/* parameter structures */
117/*------------------------------------------------------------------*/
118 /* ALERT-REQUEST */
119typedef struct {
120 byte structs[1]; /* Additional Info */
121} _ALT_REQP;
122 /* ALERT-CONFIRM */
123typedef struct {
124 word Info;
125} _ALT_CONP;
126 /* CONNECT-REQUEST */
127typedef struct {
128 word CIP_Value;
129 byte structs[1]; /* Called party number,
130 Called party subaddress,
131 Calling party number,
132 Calling party subaddress,
133 B_protocol,
134 BC,
135 LLC,
136 HLC,
137 Additional Info */
138} _CON_REQP;
139 /* CONNECT-CONFIRM */
140typedef struct {
141 word Info;
142} _CON_CONP;
143 /* CONNECT-INDICATION */
144typedef struct {
145 word CIP_Value;
146 byte structs[1]; /* Called party number,
147 Called party subaddress,
148 Calling party number,
149 Calling party subaddress,
150 BC,
151 LLC,
152 HLC,
153 Additional Info */
154} _CON_INDP;
155 /* CONNECT-RESPONSE */
156typedef struct {
157 word Accept;
158 byte structs[1]; /* B_protocol,
159 Connected party number,
160 Connected party subaddress,
161 LLC */
162} _CON_RESP;
163 /* CONNECT-ACTIVE-INDICATION */
164typedef struct {
165 byte structs[1]; /* Connected party number,
166 Connected party subaddress,
167 LLC */
168} _CON_A_INDP;
169 /* CONNECT-ACTIVE-RESPONSE */
170typedef struct {
171 byte structs[1]; /* empty */
172} _CON_A_RESP;
173 /* DISCONNECT-REQUEST */
174typedef struct {
175 byte structs[1]; /* Additional Info */
176} _DIS_REQP;
177 /* DISCONNECT-CONFIRM */
178typedef struct {
179 word Info;
180} _DIS_CONP;
181 /* DISCONNECT-INDICATION */
182typedef struct {
183 word Info;
184} _DIS_INDP;
185 /* DISCONNECT-RESPONSE */
186typedef struct {
187 byte structs[1]; /* empty */
188} _DIS_RESP;
189 /* LISTEN-REQUEST */
190typedef struct {
191 dword Info_Mask;
192 dword CIP_Mask;
193 byte structs[1]; /* Calling party number,
194 Calling party subaddress */
195} _LIS_REQP;
196 /* LISTEN-CONFIRM */
197typedef struct {
198 word Info;
199} _LIS_CONP;
200 /* INFO-REQUEST */
201typedef struct {
202 byte structs[1]; /* Called party number,
203 Additional Info */
204} _INF_REQP;
205 /* INFO-CONFIRM */
206typedef struct {
207 word Info;
208} _INF_CONP;
209 /* INFO-INDICATION */
210typedef struct {
211 word Number;
212 byte structs[1]; /* Info element */
213} _INF_INDP;
214 /* INFO-RESPONSE */
215typedef struct {
216 byte structs[1]; /* empty */
217} _INF_RESP;
218 /* SELECT-B-REQUEST */
219typedef struct {
220 byte structs[1]; /* B-protocol */
221} _SEL_B_REQP;
222 /* SELECT-B-CONFIRM */
223typedef struct {
224 word Info;
225} _SEL_B_CONP;
226 /* FACILITY-REQUEST */
227typedef struct {
228 word Selector;
229 byte structs[1]; /* Facility parameters */
230} _FAC_REQP;
231 /* FACILITY-CONFIRM STRUCT FOR SUPPLEMENT. SERVICES */
232typedef struct {
233 byte struct_length;
234 word function;
235 byte length;
236 word SupplementaryServiceInfo;
237 dword SupportedServices;
238} _FAC_CON_STRUCTS;
239 /* FACILITY-CONFIRM */
240typedef struct {
241 word Info;
242 word Selector;
243 byte structs[1]; /* Facility parameters */
244} _FAC_CONP;
245 /* FACILITY-INDICATION */
246typedef struct {
247 word Selector;
248 byte structs[1]; /* Facility parameters */
249} _FAC_INDP;
250 /* FACILITY-RESPONSE */
251typedef struct {
252 word Selector;
253 byte structs[1]; /* Facility parameters */
254} _FAC_RESP;
255 /* CONNECT-B3-REQUEST */
256typedef struct {
257 byte structs[1]; /* NCPI */
258} _CON_B3_REQP;
259 /* CONNECT-B3-CONFIRM */
260typedef struct {
261 word Info;
262} _CON_B3_CONP;
263 /* CONNECT-B3-INDICATION */
264typedef struct {
265 byte structs[1]; /* NCPI */
266} _CON_B3_INDP;
267 /* CONNECT-B3-RESPONSE */
268typedef struct {
269 word Accept;
270 byte structs[1]; /* NCPI */
271} _CON_B3_RESP;
272 /* CONNECT-B3-ACTIVE-INDICATION */
273typedef struct {
274 byte structs[1]; /* NCPI */
275} _CON_B3_A_INDP;
276 /* CONNECT-B3-ACTIVE-RESPONSE */
277typedef struct {
278 byte structs[1]; /* empty */
279} _CON_B3_A_RESP;
280 /* DISCONNECT-B3-REQUEST */
281typedef struct {
282 byte structs[1]; /* NCPI */
283} _DIS_B3_REQP;
284 /* DISCONNECT-B3-CONFIRM */
285typedef struct {
286 word Info;
287} _DIS_B3_CONP;
288 /* DISCONNECT-B3-INDICATION */
289typedef struct {
290 word Info;
291 byte structs[1]; /* NCPI */
292} _DIS_B3_INDP;
293 /* DISCONNECT-B3-RESPONSE */
294typedef struct {
295 byte structs[1]; /* empty */
296} _DIS_B3_RESP;
297 /* DATA-B3-REQUEST */
298typedef struct {
299 dword Data;
300 word Data_Length;
301 word Number;
302 word Flags;
303} _DAT_B3_REQP;
304 /* DATA-B3-REQUEST 64 BIT Systems */
305typedef struct {
306 dword Data;
307 word Data_Length;
308 word Number;
309 word Flags;
310 void *pData;
311} _DAT_B3_REQ64P;
312 /* DATA-B3-CONFIRM */
313typedef struct {
314 word Number;
315 word Info;
316} _DAT_B3_CONP;
317 /* DATA-B3-INDICATION */
318typedef struct {
319 dword Data;
320 word Data_Length;
321 word Number;
322 word Flags;
323} _DAT_B3_INDP;
324 /* DATA-B3-INDICATION 64 BIT Systems */
325typedef struct {
326 dword Data;
327 word Data_Length;
328 word Number;
329 word Flags;
330 void *pData;
331} _DAT_B3_IND64P;
332 /* DATA-B3-RESPONSE */
333typedef struct {
334 word Number;
335} _DAT_B3_RESP;
336 /* RESET-B3-REQUEST */
337typedef struct {
338 byte structs[1]; /* NCPI */
339} _RES_B3_REQP;
340 /* RESET-B3-CONFIRM */
341typedef struct {
342 word Info;
343} _RES_B3_CONP;
344 /* RESET-B3-INDICATION */
345typedef struct {
346 byte structs[1]; /* NCPI */
347} _RES_B3_INDP;
348 /* RESET-B3-RESPONSE */
349typedef struct {
350 byte structs[1]; /* empty */
351} _RES_B3_RESP;
352 /* CONNECT-B3-T90-ACTIVE-INDICATION */
353typedef struct {
354 byte structs[1]; /* NCPI */
355} _CON_B3_T90_A_INDP;
356 /* CONNECT-B3-T90-ACTIVE-RESPONSE */
357typedef struct {
358 word Reject;
359 byte structs[1]; /* NCPI */
360} _CON_B3_T90_A_RESP;
361/*------------------------------------------------------------------*/
362/* message structure */
363/*------------------------------------------------------------------*/
364typedef struct _API_MSG CAPI_MSG;
365typedef struct _MSG_HEADER CAPI_MSG_HEADER;
366struct _API_MSG {
367 struct _MSG_HEADER {
368 word length;
369 word appl_id;
370 word command;
371 word number;
372 byte controller;
373 byte plci;
374 word ncci;
375 } header;
376 union {
377 _ALT_REQP alert_req;
378 _ALT_CONP alert_con;
379 _CON_REQP connect_req;
380 _CON_CONP connect_con;
381 _CON_INDP connect_ind;
382 _CON_RESP connect_res;
383 _CON_A_INDP connect_a_ind;
384 _CON_A_RESP connect_a_res;
385 _DIS_REQP disconnect_req;
386 _DIS_CONP disconnect_con;
387 _DIS_INDP disconnect_ind;
388 _DIS_RESP disconnect_res;
389 _LIS_REQP listen_req;
390 _LIS_CONP listen_con;
391 _INF_REQP info_req;
392 _INF_CONP info_con;
393 _INF_INDP info_ind;
394 _INF_RESP info_res;
395 _SEL_B_REQP select_b_req;
396 _SEL_B_CONP select_b_con;
397 _FAC_REQP facility_req;
398 _FAC_CONP facility_con;
399 _FAC_INDP facility_ind;
400 _FAC_RESP facility_res;
401 _CON_B3_REQP connect_b3_req;
402 _CON_B3_CONP connect_b3_con;
403 _CON_B3_INDP connect_b3_ind;
404 _CON_B3_RESP connect_b3_res;
405 _CON_B3_A_INDP connect_b3_a_ind;
406 _CON_B3_A_RESP connect_b3_a_res;
407 _DIS_B3_REQP disconnect_b3_req;
408 _DIS_B3_CONP disconnect_b3_con;
409 _DIS_B3_INDP disconnect_b3_ind;
410 _DIS_B3_RESP disconnect_b3_res;
411 _DAT_B3_REQP data_b3_req;
412 _DAT_B3_REQ64P data_b3_req64;
413 _DAT_B3_CONP data_b3_con;
414 _DAT_B3_INDP data_b3_ind;
415 _DAT_B3_IND64P data_b3_ind64;
416 _DAT_B3_RESP data_b3_res;
417 _RES_B3_REQP reset_b3_req;
418 _RES_B3_CONP reset_b3_con;
419 _RES_B3_INDP reset_b3_ind;
420 _RES_B3_RESP reset_b3_res;
421 _CON_B3_T90_A_INDP connect_b3_t90_a_ind;
422 _CON_B3_T90_A_RESP connect_b3_t90_a_res;
423 byte b[200];
424 } info;
425};
426/*------------------------------------------------------------------*/
427/* non-fatal errors */
428/*------------------------------------------------------------------*/
429#define _NCPI_IGNORED 0x0001
430#define _FLAGS_IGNORED 0x0002
431#define _ALERT_IGNORED 0x0003
432/*------------------------------------------------------------------*/
433/* API function error codes */
434/*------------------------------------------------------------------*/
435#define GOOD 0x0000
436#define _TOO_MANY_APPLICATIONS 0x1001
437#define _BLOCK_TOO_SMALL 0x1002
438#define _BUFFER_TOO_BIG 0x1003
439#define _MSG_BUFFER_TOO_SMALL 0x1004
440#define _TOO_MANY_CONNECTIONS 0x1005
441#define _REG_CAPI_BUSY 0x1007
442#define _REG_RESOURCE_ERROR 0x1008
443#define _REG_CAPI_NOT_INSTALLED 0x1009
444#define _WRONG_APPL_ID 0x1101
445#define _BAD_MSG 0x1102
446#define _QUEUE_FULL 0x1103
447#define _GET_NO_MSG 0x1104
448#define _MSG_LOST 0x1105
449#define _WRONG_NOTIFY 0x1106
450#define _CAPI_BUSY 0x1107
451#define _RESOURCE_ERROR 0x1108
452#define _CAPI_NOT_INSTALLED 0x1109
453#define _NO_EXTERNAL_EQUIPMENT 0x110a
454#define _ONLY_EXTERNAL_EQUIPMENT 0x110b
455/*------------------------------------------------------------------*/
456/* addressing/coding error codes */
457/*------------------------------------------------------------------*/
458#define _WRONG_STATE 0x2001
459#define _WRONG_IDENTIFIER 0x2002
460#define _OUT_OF_PLCI 0x2003
461#define _OUT_OF_NCCI 0x2004
462#define _OUT_OF_LISTEN 0x2005
463#define _OUT_OF_FAX 0x2006
464#define _WRONG_MESSAGE_FORMAT 0x2007
465#define _OUT_OF_INTERCONNECT_RESOURCES 0x2008
466/*------------------------------------------------------------------*/
467/* configuration error codes */
468/*------------------------------------------------------------------*/
469#define _B1_NOT_SUPPORTED 0x3001
470#define _B2_NOT_SUPPORTED 0x3002
471#define _B3_NOT_SUPPORTED 0x3003
472#define _B1_PARM_NOT_SUPPORTED 0x3004
473#define _B2_PARM_NOT_SUPPORTED 0x3005
474#define _B3_PARM_NOT_SUPPORTED 0x3006
475#define _B_STACK_NOT_SUPPORTED 0x3007
476#define _NCPI_NOT_SUPPORTED 0x3008
477#define _CIP_NOT_SUPPORTED 0x3009
478#define _FLAGS_NOT_SUPPORTED 0x300a
479#define _FACILITY_NOT_SUPPORTED 0x300b
480#define _DATA_LEN_NOT_SUPPORTED 0x300c
481#define _RESET_NOT_SUPPORTED 0x300d
482#define _SUPPLEMENTARY_SERVICE_NOT_SUPPORTED 0x300e
483#define _REQUEST_NOT_ALLOWED_IN_THIS_STATE 0x3010
484#define _FACILITY_SPECIFIC_FUNCTION_NOT_SUPP 0x3011
485/*------------------------------------------------------------------*/
486/* reason codes */
487/*------------------------------------------------------------------*/
488#define _L1_ERROR 0x3301
489#define _L2_ERROR 0x3302
490#define _L3_ERROR 0x3303
491#define _OTHER_APPL_CONNECTED 0x3304
492#define _CAPI_GUARD_ERROR 0x3305
493#define _L3_CAUSE 0x3400
494/*------------------------------------------------------------------*/
495/* b3 reason codes */
496/*------------------------------------------------------------------*/
497#define _B_CHANNEL_LOST 0x3301
498#define _B2_ERROR 0x3302
499#define _B3_ERROR 0x3303
500/*------------------------------------------------------------------*/
501/* fax error codes */
502/*------------------------------------------------------------------*/
503#define _FAX_NO_CONNECTION 0x3311
504#define _FAX_TRAINING_ERROR 0x3312
505#define _FAX_REMOTE_REJECT 0x3313
506#define _FAX_REMOTE_ABORT 0x3314
507#define _FAX_PROTOCOL_ERROR 0x3315
508#define _FAX_TX_UNDERRUN 0x3316
509#define _FAX_RX_OVERFLOW 0x3317
510#define _FAX_LOCAL_ABORT 0x3318
511#define _FAX_PARAMETER_ERROR 0x3319
512/*------------------------------------------------------------------*/
513/* line interconnect error codes */
514/*------------------------------------------------------------------*/
515#define _LI_USER_INITIATED 0x0000
516#define _LI_LINE_NO_LONGER_AVAILABLE 0x3805
517#define _LI_INTERCONNECT_NOT_ESTABLISHED 0x3806
518#define _LI_LINES_NOT_COMPATIBLE 0x3807
519#define _LI2_USER_INITIATED 0x0000
520#define _LI2_PLCI_HAS_NO_BCHANNEL 0x3800
521#define _LI2_LINES_NOT_COMPATIBLE 0x3801
522#define _LI2_NOT_IN_SAME_INTERCONNECTION 0x3802
523/*------------------------------------------------------------------*/
524/* global options */
525/*------------------------------------------------------------------*/
526#define GL_INTERNAL_CONTROLLER_SUPPORTED 0x00000001L
527#define GL_EXTERNAL_EQUIPMENT_SUPPORTED 0x00000002L
528#define GL_HANDSET_SUPPORTED 0x00000004L
529#define GL_DTMF_SUPPORTED 0x00000008L
530#define GL_SUPPLEMENTARY_SERVICES_SUPPORTED 0x00000010L
531#define GL_CHANNEL_ALLOCATION_SUPPORTED 0x00000020L
532#define GL_BCHANNEL_OPERATION_SUPPORTED 0x00000040L
533#define GL_LINE_INTERCONNECT_SUPPORTED 0x00000080L
534#define GL_ECHO_CANCELLER_SUPPORTED 0x00000100L
535/*------------------------------------------------------------------*/
536/* protocol selection */
537/*------------------------------------------------------------------*/
538#define B1_HDLC 0
539#define B1_TRANSPARENT 1
540#define B1_V110_ASYNC 2
541#define B1_V110_SYNC 3
542#define B1_T30 4
543#define B1_HDLC_INVERTED 5
544#define B1_TRANSPARENT_R 6
545#define B1_MODEM_ALL_NEGOTIATE 7
546#define B1_MODEM_ASYNC 8
547#define B1_MODEM_SYNC_HDLC 9
548#define B2_X75 0
549#define B2_TRANSPARENT 1
550#define B2_SDLC 2
551#define B2_LAPD 3
552#define B2_T30 4
553#define B2_PPP 5
554#define B2_TRANSPARENT_NO_CRC 6
555#define B2_MODEM_EC_COMPRESSION 7
556#define B2_X75_V42BIS 8
557#define B2_V120_ASYNC 9
558#define B2_V120_ASYNC_V42BIS 10
559#define B2_V120_BIT_TRANSPARENT 11
560#define B2_LAPD_FREE_SAPI_SEL 12
561#define B3_TRANSPARENT 0
562#define B3_T90NL 1
563#define B3_ISO8208 2
564#define B3_X25_DCE 3
565#define B3_T30 4
566#define B3_T30_WITH_EXTENSIONS 5
567#define B3_RESERVED 6
568#define B3_MODEM 7
569/*------------------------------------------------------------------*/
570/* facility definitions */
571/*------------------------------------------------------------------*/
572#define SELECTOR_HANDSET 0
573#define SELECTOR_DTMF 1
574#define SELECTOR_V42BIS 2
575#define SELECTOR_SU_SERV 3
576#define SELECTOR_POWER_MANAGEMENT 4
577#define SELECTOR_LINE_INTERCONNECT 5
578#define SELECTOR_ECHO_CANCELLER 6
579/*------------------------------------------------------------------*/
580/* supplementary services definitions */
581/*------------------------------------------------------------------*/
582#define S_GET_SUPPORTED_SERVICES 0x0000
583#define S_LISTEN 0x0001
584#define S_HOLD 0x0002
585#define S_RETRIEVE 0x0003
586#define S_SUSPEND 0x0004
587#define S_RESUME 0x0005
588#define S_ECT 0x0006
589#define S_3PTY_BEGIN 0x0007
590#define S_3PTY_END 0x0008
591#define S_CALL_DEFLECTION 0x000d
592#define S_CALL_FORWARDING_START 0x0009
593#define S_CALL_FORWARDING_STOP 0x000a
594#define S_INTERROGATE_DIVERSION 0x000b /* or interrogate parameters */
595#define S_INTERROGATE_NUMBERS 0x000c
596#define S_CCBS_REQUEST 0x000f
597#define S_CCBS_DEACTIVATE 0x0010
598#define S_CCBS_INTERROGATE 0x0011
599#define S_CCBS_CALL 0x0012
600#define S_MWI_ACTIVATE 0x0013
601#define S_MWI_DEACTIVATE 0x0014
602#define S_CONF_BEGIN 0x0017
603#define S_CONF_ADD 0x0018
604#define S_CONF_SPLIT 0x0019
605#define S_CONF_DROP 0x001a
606#define S_CONF_ISOLATE 0x001b
607#define S_CONF_REATTACH 0x001c
608#define S_CCBS_ERASECALLLINKAGEID 0x800d
609#define S_CCBS_STOP_ALERTING 0x8012
610#define S_CCBS_INFO_RETAIN 0x8013
611#define S_MWI_INDICATE 0x8014
612#define S_CONF_PARTYDISC 0x8016
613#define S_CONF_NOTIFICATION 0x8017
614/* Service Masks */
615#define MASK_HOLD_RETRIEVE 0x00000001
616#define MASK_TERMINAL_PORTABILITY 0x00000002
617#define MASK_ECT 0x00000004
618#define MASK_3PTY 0x00000008
619#define MASK_CALL_FORWARDING 0x00000010
620#define MASK_CALL_DEFLECTION 0x00000020
621#define MASK_MWI 0x00000100
622#define MASK_CCNR 0x00000200
623#define MASK_CONF 0x00000400
624/*------------------------------------------------------------------*/
625/* dtmf definitions */
626/*------------------------------------------------------------------*/
627#define DTMF_LISTEN_START 1
628#define DTMF_LISTEN_STOP 2
629#define DTMF_DIGITS_SEND 3
630#define DTMF_SUCCESS 0
631#define DTMF_INCORRECT_DIGIT 1
632#define DTMF_UNKNOWN_REQUEST 2
633/*------------------------------------------------------------------*/
634/* line interconnect definitions */
635/*------------------------------------------------------------------*/
636#define LI_GET_SUPPORTED_SERVICES 0
637#define LI_REQ_CONNECT 1
638#define LI_REQ_DISCONNECT 2
639#define LI_IND_CONNECT_ACTIVE 1
640#define LI_IND_DISCONNECT 2
641#define LI_FLAG_CONFERENCE_A_B ((dword) 0x00000001L)
642#define LI_FLAG_CONFERENCE_B_A ((dword) 0x00000002L)
643#define LI_FLAG_MONITOR_A ((dword) 0x00000004L)
644#define LI_FLAG_MONITOR_B ((dword) 0x00000008L)
645#define LI_FLAG_ANNOUNCEMENT_A ((dword) 0x00000010L)
646#define LI_FLAG_ANNOUNCEMENT_B ((dword) 0x00000020L)
647#define LI_FLAG_MIX_A ((dword) 0x00000040L)
648#define LI_FLAG_MIX_B ((dword) 0x00000080L)
649#define LI_CONFERENCING_SUPPORTED ((dword) 0x00000001L)
650#define LI_MONITORING_SUPPORTED ((dword) 0x00000002L)
651#define LI_ANNOUNCEMENTS_SUPPORTED ((dword) 0x00000004L)
652#define LI_MIXING_SUPPORTED ((dword) 0x00000008L)
653#define LI_CROSS_CONTROLLER_SUPPORTED ((dword) 0x00000010L)
654#define LI2_GET_SUPPORTED_SERVICES 0
655#define LI2_REQ_CONNECT 1
656#define LI2_REQ_DISCONNECT 2
657#define LI2_IND_CONNECT_ACTIVE 1
658#define LI2_IND_DISCONNECT 2
659#define LI2_FLAG_INTERCONNECT_A_B ((dword) 0x00000001L)
660#define LI2_FLAG_INTERCONNECT_B_A ((dword) 0x00000002L)
661#define LI2_FLAG_MONITOR_B ((dword) 0x00000004L)
662#define LI2_FLAG_MIX_B ((dword) 0x00000008L)
663#define LI2_FLAG_MONITOR_X ((dword) 0x00000010L)
664#define LI2_FLAG_MIX_X ((dword) 0x00000020L)
665#define LI2_FLAG_LOOP_B ((dword) 0x00000040L)
666#define LI2_FLAG_LOOP_PC ((dword) 0x00000080L)
667#define LI2_FLAG_LOOP_X ((dword) 0x00000100L)
668#define LI2_CROSS_CONTROLLER_SUPPORTED ((dword) 0x00000001L)
669#define LI2_ASYMMETRIC_SUPPORTED ((dword) 0x00000002L)
670#define LI2_MONITORING_SUPPORTED ((dword) 0x00000004L)
671#define LI2_MIXING_SUPPORTED ((dword) 0x00000008L)
672#define LI2_REMOTE_MONITORING_SUPPORTED ((dword) 0x00000010L)
673#define LI2_REMOTE_MIXING_SUPPORTED ((dword) 0x00000020L)
674#define LI2_B_LOOPING_SUPPORTED ((dword) 0x00000040L)
675#define LI2_PC_LOOPING_SUPPORTED ((dword) 0x00000080L)
676#define LI2_X_LOOPING_SUPPORTED ((dword) 0x00000100L)
677/*------------------------------------------------------------------*/
678/* echo canceller definitions */
679/*------------------------------------------------------------------*/
680#define EC_GET_SUPPORTED_SERVICES 0
681#define EC_ENABLE_OPERATION 1
682#define EC_DISABLE_OPERATION 2
683#define EC_ENABLE_NON_LINEAR_PROCESSING 0x0001
684#define EC_DO_NOT_REQUIRE_REVERSALS 0x0002
685#define EC_DETECT_DISABLE_TONE 0x0004
686#define EC_ENABLE_ADAPTIVE_PREDELAY 0x0008
687#define EC_NON_LINEAR_PROCESSING_SUPPORTED 0x0001
688#define EC_BYPASS_ON_ANY_2100HZ_SUPPORTED 0x0002
689#define EC_BYPASS_ON_REV_2100HZ_SUPPORTED 0x0004
690#define EC_ADAPTIVE_PREDELAY_SUPPORTED 0x0008
691#define EC_BYPASS_INDICATION 1
692#define EC_BYPASS_DUE_TO_CONTINUOUS_2100HZ 1
693#define EC_BYPASS_DUE_TO_REVERSED_2100HZ 2
694#define EC_BYPASS_RELEASED 3
695/*------------------------------------------------------------------*/
696/* function prototypes */
697/*------------------------------------------------------------------*/
698/*------------------------------------------------------------------*/
699#endif /* _INC_CAPI20 */
diff --git a/drivers/isdn/hardware/eicon/capidtmf.c b/drivers/isdn/hardware/eicon/capidtmf.c
new file mode 100644
index 000000000000..f130724144f3
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/capidtmf.c
@@ -0,0 +1,685 @@
1
2/*
3 *
4 Copyright (c) Eicon Networks, 2002.
5 *
6 This source file is supplied for the use with
7 Eicon Networks range of DIVA Server Adapters.
8 *
9 Eicon File Revision : 2.1
10 *
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2, or (at your option)
14 any later version.
15 *
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
18 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 See the GNU General Public License for more details.
20 *
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27#include "platform.h"
28
29
30
31
32
33
34
35
36
37#include "capidtmf.h"
38
39/* #define TRACE_ */
40
41#define FILE_ "CAPIDTMF.C"
42
43/*---------------------------------------------------------------------------*/
44
45
46#define trace(a)
47
48
49
50/*---------------------------------------------------------------------------*/
51
52static short capidtmf_expand_table_alaw[0x0100] =
53{
54 -5504, 5504, -344, 344, -22016, 22016, -1376, 1376,
55 -2752, 2752, -88, 88, -11008, 11008, -688, 688,
56 -7552, 7552, -472, 472, -30208, 30208, -1888, 1888,
57 -3776, 3776, -216, 216, -15104, 15104, -944, 944,
58 -4480, 4480, -280, 280, -17920, 17920, -1120, 1120,
59 -2240, 2240, -24, 24, -8960, 8960, -560, 560,
60 -6528, 6528, -408, 408, -26112, 26112, -1632, 1632,
61 -3264, 3264, -152, 152, -13056, 13056, -816, 816,
62 -6016, 6016, -376, 376, -24064, 24064, -1504, 1504,
63 -3008, 3008, -120, 120, -12032, 12032, -752, 752,
64 -8064, 8064, -504, 504, -32256, 32256, -2016, 2016,
65 -4032, 4032, -248, 248, -16128, 16128, -1008, 1008,
66 -4992, 4992, -312, 312, -19968, 19968, -1248, 1248,
67 -2496, 2496, -56, 56, -9984, 9984, -624, 624,
68 -7040, 7040, -440, 440, -28160, 28160, -1760, 1760,
69 -3520, 3520, -184, 184, -14080, 14080, -880, 880,
70 -5248, 5248, -328, 328, -20992, 20992, -1312, 1312,
71 -2624, 2624, -72, 72, -10496, 10496, -656, 656,
72 -7296, 7296, -456, 456, -29184, 29184, -1824, 1824,
73 -3648, 3648, -200, 200, -14592, 14592, -912, 912,
74 -4224, 4224, -264, 264, -16896, 16896, -1056, 1056,
75 -2112, 2112, -8, 8, -8448, 8448, -528, 528,
76 -6272, 6272, -392, 392, -25088, 25088, -1568, 1568,
77 -3136, 3136, -136, 136, -12544, 12544, -784, 784,
78 -5760, 5760, -360, 360, -23040, 23040, -1440, 1440,
79 -2880, 2880, -104, 104, -11520, 11520, -720, 720,
80 -7808, 7808, -488, 488, -31232, 31232, -1952, 1952,
81 -3904, 3904, -232, 232, -15616, 15616, -976, 976,
82 -4736, 4736, -296, 296, -18944, 18944, -1184, 1184,
83 -2368, 2368, -40, 40, -9472, 9472, -592, 592,
84 -6784, 6784, -424, 424, -27136, 27136, -1696, 1696,
85 -3392, 3392, -168, 168, -13568, 13568, -848, 848
86};
87
88static short capidtmf_expand_table_ulaw[0x0100] =
89{
90 -32124, 32124, -1884, 1884, -7932, 7932, -372, 372,
91 -15996, 15996, -876, 876, -3900, 3900, -120, 120,
92 -23932, 23932, -1372, 1372, -5884, 5884, -244, 244,
93 -11900, 11900, -620, 620, -2876, 2876, -56, 56,
94 -28028, 28028, -1628, 1628, -6908, 6908, -308, 308,
95 -13948, 13948, -748, 748, -3388, 3388, -88, 88,
96 -19836, 19836, -1116, 1116, -4860, 4860, -180, 180,
97 -9852, 9852, -492, 492, -2364, 2364, -24, 24,
98 -30076, 30076, -1756, 1756, -7420, 7420, -340, 340,
99 -14972, 14972, -812, 812, -3644, 3644, -104, 104,
100 -21884, 21884, -1244, 1244, -5372, 5372, -212, 212,
101 -10876, 10876, -556, 556, -2620, 2620, -40, 40,
102 -25980, 25980, -1500, 1500, -6396, 6396, -276, 276,
103 -12924, 12924, -684, 684, -3132, 3132, -72, 72,
104 -17788, 17788, -988, 988, -4348, 4348, -148, 148,
105 -8828, 8828, -428, 428, -2108, 2108, -8, 8,
106 -31100, 31100, -1820, 1820, -7676, 7676, -356, 356,
107 -15484, 15484, -844, 844, -3772, 3772, -112, 112,
108 -22908, 22908, -1308, 1308, -5628, 5628, -228, 228,
109 -11388, 11388, -588, 588, -2748, 2748, -48, 48,
110 -27004, 27004, -1564, 1564, -6652, 6652, -292, 292,
111 -13436, 13436, -716, 716, -3260, 3260, -80, 80,
112 -18812, 18812, -1052, 1052, -4604, 4604, -164, 164,
113 -9340, 9340, -460, 460, -2236, 2236, -16, 16,
114 -29052, 29052, -1692, 1692, -7164, 7164, -324, 324,
115 -14460, 14460, -780, 780, -3516, 3516, -96, 96,
116 -20860, 20860, -1180, 1180, -5116, 5116, -196, 196,
117 -10364, 10364, -524, 524, -2492, 2492, -32, 32,
118 -24956, 24956, -1436, 1436, -6140, 6140, -260, 260,
119 -12412, 12412, -652, 652, -3004, 3004, -64, 64,
120 -16764, 16764, -924, 924, -4092, 4092, -132, 132,
121 -8316, 8316, -396, 396, -1980, 1980, 0, 0
122};
123
124
125/*---------------------------------------------------------------------------*/
126
127static short capidtmf_recv_window_function[CAPIDTMF_RECV_ACCUMULATE_CYCLES] =
128{
129 -500L, -999L, -1499L, -1998L, -2496L, -2994L, -3491L, -3988L,
130 -4483L, -4978L, -5471L, -5963L, -6454L, -6943L, -7431L, -7917L,
131 -8401L, -8883L, -9363L, -9840L, -10316L, -10789L, -11259L, -11727L,
132 -12193L, -12655L, -13115L, -13571L, -14024L, -14474L, -14921L, -15364L,
133 -15804L, -16240L, -16672L, -17100L, -17524L, -17944L, -18360L, -18772L,
134 -19180L, -19583L, -19981L, -20375L, -20764L, -21148L, -21527L, -21901L,
135 -22270L, -22634L, -22993L, -23346L, -23694L, -24037L, -24374L, -24705L,
136 -25030L, -25350L, -25664L, -25971L, -26273L, -26568L, -26858L, -27141L,
137 -27418L, -27688L, -27952L, -28210L, -28461L, -28705L, -28943L, -29174L,
138 -29398L, -29615L, -29826L, -30029L, -30226L, -30415L, -30598L, -30773L,
139 -30941L, -31102L, -31256L, -31402L, -31541L, -31673L, -31797L, -31914L,
140 -32024L, -32126L, -32221L, -32308L, -32388L, -32460L, -32524L, -32581L,
141 -32631L, -32673L, -32707L, -32734L, -32753L, -32764L, -32768L, -32764L,
142 -32753L, -32734L, -32707L, -32673L, -32631L, -32581L, -32524L, -32460L,
143 -32388L, -32308L, -32221L, -32126L, -32024L, -31914L, -31797L, -31673L,
144 -31541L, -31402L, -31256L, -31102L, -30941L, -30773L, -30598L, -30415L,
145 -30226L, -30029L, -29826L, -29615L, -29398L, -29174L, -28943L, -28705L,
146 -28461L, -28210L, -27952L, -27688L, -27418L, -27141L, -26858L, -26568L,
147 -26273L, -25971L, -25664L, -25350L, -25030L, -24705L, -24374L, -24037L,
148 -23694L, -23346L, -22993L, -22634L, -22270L, -21901L, -21527L, -21148L,
149 -20764L, -20375L, -19981L, -19583L, -19180L, -18772L, -18360L, -17944L,
150 -17524L, -17100L, -16672L, -16240L, -15804L, -15364L, -14921L, -14474L,
151 -14024L, -13571L, -13115L, -12655L, -12193L, -11727L, -11259L, -10789L,
152 -10316L, -9840L, -9363L, -8883L, -8401L, -7917L, -7431L, -6943L,
153 -6454L, -5963L, -5471L, -4978L, -4483L, -3988L, -3491L, -2994L,
154 -2496L, -1998L, -1499L, -999L, -500L,
155};
156
157static byte capidtmf_leading_zeroes_table[0x100] =
158{
159 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
160 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
161 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
162 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
163 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
164 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
165 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
166 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
167 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
168 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
169 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
170 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
171 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
172 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
173 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
174 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
175};
176
177#define capidtmf_byte_leading_zeroes(b) (capidtmf_leading_zeroes_table[(BYTE)(b)])
178#define capidtmf_word_leading_zeroes(w) (((w) & 0xff00) ? capidtmf_leading_zeroes_table[(w) >> 8] : 8 + capidtmf_leading_zeroes_table[(w)])
179#define capidtmf_dword_leading_zeroes(d) (((d) & 0xffff0000L) ? (((d) & 0xff000000L) ? capidtmf_leading_zeroes_table[(d) >> 24] : 8 + capidtmf_leading_zeroes_table[(d) >> 16]) : (((d) & 0xff00) ? 16 + capidtmf_leading_zeroes_table[(d) >> 8] : 24 + capidtmf_leading_zeroes_table[(d)]))
180
181
182/*---------------------------------------------------------------------------*/
183
184
185static void capidtmf_goertzel_loop (long *buffer, long *coeffs, short *sample, long count)
186{
187 int i, j;
188 long c, d, q0, q1, q2;
189
190 for (i = 0; i < CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT - 1; i++)
191 {
192 q1 = buffer[i];
193 q2 = buffer[i + CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT];
194 d = coeffs[i] >> 1;
195 c = d << 1;
196 if (c >= 0)
197 {
198 for (j = 0; j < count; j++)
199 {
200 q0 = sample[j] - q2 + (c * (q1 >> 16)) + (((dword)(((dword) d) * ((dword)(q1 & 0xffff)))) >> 15);
201 q2 = q1;
202 q1 = q0;
203 }
204 }
205 else
206 {
207 c = -c;
208 d = -d;
209 for (j = 0; j < count; j++)
210 {
211 q0 = sample[j] - q2 - ((c * (q1 >> 16)) + (((dword)(((dword) d) * ((dword)(q1 & 0xffff)))) >> 15));
212 q2 = q1;
213 q1 = q0;
214 }
215 }
216 buffer[i] = q1;
217 buffer[i + CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT] = q2;
218 }
219 q1 = buffer[i];
220 q2 = buffer[i + CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT];
221 c = (coeffs[i] >> 1) << 1;
222 if (c >= 0)
223 {
224 for (j = 0; j < count; j++)
225 {
226 q0 = sample[j] - q2 + (c * (q1 >> 16)) + (((dword)(((dword)(c >> 1)) * ((dword)(q1 & 0xffff)))) >> 15);
227 q2 = q1;
228 q1 = q0;
229 c -= CAPIDTMF_RECV_FUNDAMENTAL_DECREMENT;
230 }
231 }
232 else
233 {
234 c = -c;
235 for (j = 0; j < count; j++)
236 {
237 q0 = sample[j] - q2 - ((c * (q1 >> 16)) + (((dword)(((dword)(c >> 1)) * ((dword)(q1 & 0xffff)))) >> 15));
238 q2 = q1;
239 q1 = q0;
240 c += CAPIDTMF_RECV_FUNDAMENTAL_DECREMENT;
241 }
242 }
243 coeffs[i] = c;
244 buffer[i] = q1;
245 buffer[i + CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT] = q2;
246}
247
248
249static void capidtmf_goertzel_result (long *buffer, long *coeffs)
250{
251 int i;
252 long d, e, q1, q2, lo, mid, hi;
253 dword k;
254
255 for (i = 0; i < CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT; i++)
256 {
257 q1 = buffer[i];
258 q2 = buffer[i + CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT];
259 d = coeffs[i] >> 1;
260 if (d >= 0)
261 d = ((d << 1) * (-q1 >> 16)) + (((dword)(((dword) d) * ((dword)(-q1 & 0xffff)))) >> 15);
262 else
263 d = ((-d << 1) * (-q1 >> 16)) + (((dword)(((dword) -d) * ((dword)(-q1 & 0xffff)))) >> 15);
264 e = (q2 >= 0) ? q2 : -q2;
265 if (d >= 0)
266 {
267 k = ((dword)(d & 0xffff)) * ((dword)(e & 0xffff));
268 lo = k & 0xffff;
269 mid = k >> 16;
270 k = ((dword)(d >> 16)) * ((dword)(e & 0xffff));
271 mid += k & 0xffff;
272 hi = k >> 16;
273 k = ((dword)(d & 0xffff)) * ((dword)(e >> 16));
274 mid += k & 0xffff;
275 hi += k >> 16;
276 hi += ((dword)(d >> 16)) * ((dword)(e >> 16));
277 }
278 else
279 {
280 d = -d;
281 k = ((dword)(d & 0xffff)) * ((dword)(e & 0xffff));
282 lo = -((long)(k & 0xffff));
283 mid = -((long)(k >> 16));
284 k = ((dword)(d >> 16)) * ((dword)(e & 0xffff));
285 mid -= k & 0xffff;
286 hi = -((long)(k >> 16));
287 k = ((dword)(d & 0xffff)) * ((dword)(e >> 16));
288 mid -= k & 0xffff;
289 hi -= k >> 16;
290 hi -= ((dword)(d >> 16)) * ((dword)(e >> 16));
291 }
292 if (q2 < 0)
293 {
294 lo = -lo;
295 mid = -mid;
296 hi = -hi;
297 }
298 d = (q1 >= 0) ? q1 : -q1;
299 k = ((dword)(d & 0xffff)) * ((dword)(d & 0xffff));
300 lo += k & 0xffff;
301 mid += k >> 16;
302 k = ((dword)(d >> 16)) * ((dword)(d & 0xffff));
303 mid += (k & 0xffff) << 1;
304 hi += (k >> 16) << 1;
305 hi += ((dword)(d >> 16)) * ((dword)(d >> 16));
306 d = (q2 >= 0) ? q2 : -q2;
307 k = ((dword)(d & 0xffff)) * ((dword)(d & 0xffff));
308 lo += k & 0xffff;
309 mid += k >> 16;
310 k = ((dword)(d >> 16)) * ((dword)(d & 0xffff));
311 mid += (k & 0xffff) << 1;
312 hi += (k >> 16) << 1;
313 hi += ((dword)(d >> 16)) * ((dword)(d >> 16));
314 mid += lo >> 16;
315 hi += mid >> 16;
316 buffer[i] = (lo & 0xffff) | (mid << 16);
317 buffer[i + CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT] = hi;
318 }
319}
320
321
322/*---------------------------------------------------------------------------*/
323
324#define CAPIDTMF_RECV_GUARD_SNR_INDEX_697 0
325#define CAPIDTMF_RECV_GUARD_SNR_INDEX_770 1
326#define CAPIDTMF_RECV_GUARD_SNR_INDEX_852 2
327#define CAPIDTMF_RECV_GUARD_SNR_INDEX_941 3
328#define CAPIDTMF_RECV_GUARD_SNR_INDEX_1209 4
329#define CAPIDTMF_RECV_GUARD_SNR_INDEX_1336 5
330#define CAPIDTMF_RECV_GUARD_SNR_INDEX_1477 6
331#define CAPIDTMF_RECV_GUARD_SNR_INDEX_1633 7
332#define CAPIDTMF_RECV_GUARD_SNR_INDEX_635 8
333#define CAPIDTMF_RECV_GUARD_SNR_INDEX_1010 9
334#define CAPIDTMF_RECV_GUARD_SNR_INDEX_1140 10
335#define CAPIDTMF_RECV_GUARD_SNR_INDEX_1272 11
336#define CAPIDTMF_RECV_GUARD_SNR_INDEX_1405 12
337#define CAPIDTMF_RECV_GUARD_SNR_INDEX_1555 13
338#define CAPIDTMF_RECV_GUARD_SNR_INDEX_1715 14
339#define CAPIDTMF_RECV_GUARD_SNR_INDEX_1875 15
340
341#define CAPIDTMF_RECV_GUARD_SNR_DONTCARE 0xc000
342#define CAPIDTMF_RECV_NO_DIGIT 0xff
343#define CAPIDTMF_RECV_TIME_GRANULARITY (CAPIDTMF_RECV_ACCUMULATE_CYCLES + 1)
344
345#define CAPIDTMF_RECV_INDICATION_DIGIT 0x0001
346
347static long capidtmf_recv_goertzel_coef_table[CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT] =
348{
349 0xda97L * 2, /* 697 Hz (Low group 697 Hz) */
350 0xd299L * 2, /* 770 Hz (Low group 770 Hz) */
351 0xc8cbL * 2, /* 852 Hz (Low group 852 Hz) */
352 0xbd36L * 2, /* 941 Hz (Low group 941 Hz) */
353 0x9501L * 2, /* 1209 Hz (High group 1209 Hz) */
354 0x7f89L * 2, /* 1336 Hz (High group 1336 Hz) */
355 0x6639L * 2, /* 1477 Hz (High group 1477 Hz) */
356 0x48c6L * 2, /* 1633 Hz (High group 1633 Hz) */
357 0xe14cL * 2, /* 630 Hz (Lower guard of low group 631 Hz) */
358 0xb2e0L * 2, /* 1015 Hz (Upper guard of low group 1039 Hz) */
359 0xa1a0L * 2, /* 1130 Hz (Lower guard of high group 1140 Hz) */
360 0x8a87L * 2, /* 1272 Hz (Guard between 1209 Hz and 1336 Hz: 1271 Hz) */
361 0x7353L * 2, /* 1405 Hz (2nd harmonics of 697 Hz and guard between 1336 Hz and 1477 Hz: 1405 Hz) */
362 0x583bL * 2, /* 1552 Hz (2nd harmonics of 770 Hz and guard between 1477 Hz and 1633 Hz: 1553 Hz) */
363 0x37d8L * 2, /* 1720 Hz (2nd harmonics of 852 Hz and upper guard of high group: 1715 Hz) */
364 0x0000L * 2 /* 100-630 Hz (fundamentals) */
365};
366
367
368static word capidtmf_recv_guard_snr_low_table[CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT] =
369{
370 14, /* Low group peak versus 697 Hz */
371 14, /* Low group peak versus 770 Hz */
372 16, /* Low group peak versus 852 Hz */
373 16, /* Low group peak versus 941 Hz */
374 CAPIDTMF_RECV_GUARD_SNR_DONTCARE, /* Low group peak versus 1209 Hz */
375 CAPIDTMF_RECV_GUARD_SNR_DONTCARE, /* Low group peak versus 1336 Hz */
376 CAPIDTMF_RECV_GUARD_SNR_DONTCARE, /* Low group peak versus 1477 Hz */
377 CAPIDTMF_RECV_GUARD_SNR_DONTCARE, /* Low group peak versus 1633 Hz */
378 14, /* Low group peak versus 635 Hz */
379 16, /* Low group peak versus 1010 Hz */
380 CAPIDTMF_RECV_GUARD_SNR_DONTCARE, /* Low group peak versus 1140 Hz */
381 CAPIDTMF_RECV_GUARD_SNR_DONTCARE, /* Low group peak versus 1272 Hz */
382 DSPDTMF_RX_HARMONICS_SEL_DEFAULT - 8, /* Low group peak versus 1405 Hz */
383 DSPDTMF_RX_HARMONICS_SEL_DEFAULT - 4, /* Low group peak versus 1555 Hz */
384 DSPDTMF_RX_HARMONICS_SEL_DEFAULT - 4, /* Low group peak versus 1715 Hz */
385 12 /* Low group peak versus 100-630 Hz */
386};
387
388
389static word capidtmf_recv_guard_snr_high_table[CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT] =
390{
391 CAPIDTMF_RECV_GUARD_SNR_DONTCARE, /* High group peak versus 697 Hz */
392 CAPIDTMF_RECV_GUARD_SNR_DONTCARE, /* High group peak versus 770 Hz */
393 CAPIDTMF_RECV_GUARD_SNR_DONTCARE, /* High group peak versus 852 Hz */
394 CAPIDTMF_RECV_GUARD_SNR_DONTCARE, /* High group peak versus 941 Hz */
395 20, /* High group peak versus 1209 Hz */
396 20, /* High group peak versus 1336 Hz */
397 20, /* High group peak versus 1477 Hz */
398 20, /* High group peak versus 1633 Hz */
399 CAPIDTMF_RECV_GUARD_SNR_DONTCARE, /* High group peak versus 635 Hz */
400 CAPIDTMF_RECV_GUARD_SNR_DONTCARE, /* High group peak versus 1010 Hz */
401 16, /* High group peak versus 1140 Hz */
402 4, /* High group peak versus 1272 Hz */
403 6, /* High group peak versus 1405 Hz */
404 8, /* High group peak versus 1555 Hz */
405 16, /* High group peak versus 1715 Hz */
406 12 /* High group peak versus 100-630 Hz */
407};
408
409
410/*---------------------------------------------------------------------------*/
411
412static void capidtmf_recv_init (t_capidtmf_state *p_state)
413{
414 p_state->recv.min_gap_duration = 1;
415 p_state->recv.min_digit_duration = 1;
416
417 p_state->recv.cycle_counter = 0;
418 p_state->recv.current_digit_on_time = 0;
419 p_state->recv.current_digit_off_time = 0;
420 p_state->recv.current_digit_value = CAPIDTMF_RECV_NO_DIGIT;
421
422 p_state->recv.digit_write_pos = 0;
423 p_state->recv.digit_read_pos = 0;
424 p_state->recv.indication_state = 0;
425 p_state->recv.indication_state_ack = 0;
426 p_state->recv.state = CAPIDTMF_RECV_STATE_IDLE;
427}
428
429
430void capidtmf_recv_enable (t_capidtmf_state *p_state, word min_digit_duration, word min_gap_duration)
431{
432 p_state->recv.indication_state_ack &= CAPIDTMF_RECV_INDICATION_DIGIT;
433 p_state->recv.min_digit_duration = (word)(((((dword) min_digit_duration) * 8) +
434 ((dword)(CAPIDTMF_RECV_TIME_GRANULARITY / 2))) / ((dword) CAPIDTMF_RECV_TIME_GRANULARITY));
435 if (p_state->recv.min_digit_duration <= 1)
436 p_state->recv.min_digit_duration = 1;
437 else
438 (p_state->recv.min_digit_duration)--;
439 p_state->recv.min_gap_duration =
440 (word)((((dword) min_gap_duration) * 8) / ((dword) CAPIDTMF_RECV_TIME_GRANULARITY));
441 if (p_state->recv.min_gap_duration <= 1)
442 p_state->recv.min_gap_duration = 1;
443 else
444 (p_state->recv.min_gap_duration)--;
445 p_state->recv.state |= CAPIDTMF_RECV_STATE_DTMF_ACTIVE;
446}
447
448
449void capidtmf_recv_disable (t_capidtmf_state *p_state)
450{
451 p_state->recv.state &= ~CAPIDTMF_RECV_STATE_DTMF_ACTIVE;
452 if (p_state->recv.state == CAPIDTMF_RECV_STATE_IDLE)
453 capidtmf_recv_init (p_state);
454 else
455 {
456 p_state->recv.cycle_counter = 0;
457 p_state->recv.current_digit_on_time = 0;
458 p_state->recv.current_digit_off_time = 0;
459 p_state->recv.current_digit_value = CAPIDTMF_RECV_NO_DIGIT;
460 }
461}
462
463
464word capidtmf_recv_indication (t_capidtmf_state *p_state, byte *buffer)
465{
466 word i, j, k, flags;
467
468 flags = p_state->recv.indication_state ^ p_state->recv.indication_state_ack;
469 p_state->recv.indication_state_ack ^= flags & CAPIDTMF_RECV_INDICATION_DIGIT;
470 if (p_state->recv.digit_write_pos != p_state->recv.digit_read_pos)
471 {
472 i = 0;
473 k = p_state->recv.digit_write_pos;
474 j = p_state->recv.digit_read_pos;
475 do
476 {
477 buffer[i++] = p_state->recv.digit_buffer[j];
478 j = (j == CAPIDTMF_RECV_DIGIT_BUFFER_SIZE - 1) ? 0 : j + 1;
479 } while (j != k);
480 p_state->recv.digit_read_pos = k;
481 return (i);
482 }
483 p_state->recv.indication_state_ack ^= flags;
484 return (0);
485}
486
487
488#define CAPIDTMF_RECV_WINDOWED_SAMPLES 32
489
490void capidtmf_recv_block (t_capidtmf_state *p_state, byte *buffer, word length)
491{
492 byte result_digit;
493 word sample_number, cycle_counter, n, i;
494 word low_peak, high_peak;
495 dword lo, hi;
496 byte *p;
497 short *q;
498 byte goertzel_result_buffer[CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT];
499 short windowed_sample_buffer[CAPIDTMF_RECV_WINDOWED_SAMPLES];
500
501
502 if (p_state->recv.state & CAPIDTMF_RECV_STATE_DTMF_ACTIVE)
503 {
504 cycle_counter = p_state->recv.cycle_counter;
505 sample_number = 0;
506 while (sample_number < length)
507 {
508 if (cycle_counter < CAPIDTMF_RECV_ACCUMULATE_CYCLES)
509 {
510 if (cycle_counter == 0)
511 {
512 for (i = 0; i < CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT; i++)
513 {
514 p_state->recv.goertzel_buffer[0][i] = 0;
515 p_state->recv.goertzel_buffer[1][i] = 0;
516 }
517 }
518 n = CAPIDTMF_RECV_ACCUMULATE_CYCLES - cycle_counter;
519 if (n > length - sample_number)
520 n = length - sample_number;
521 if (n > CAPIDTMF_RECV_WINDOWED_SAMPLES)
522 n = CAPIDTMF_RECV_WINDOWED_SAMPLES;
523 p = buffer + sample_number;
524 q = capidtmf_recv_window_function + cycle_counter;
525 if (p_state->ulaw)
526 {
527 for (i = 0; i < n; i++)
528 {
529 windowed_sample_buffer[i] =
530 (short)((capidtmf_expand_table_ulaw[p[i]] * ((long)(q[i]))) >> 15);
531 }
532 }
533 else
534 {
535 for (i = 0; i < n; i++)
536 {
537 windowed_sample_buffer[i] =
538 (short)((capidtmf_expand_table_alaw[p[i]] * ((long)(q[i]))) >> 15);
539 }
540 }
541 capidtmf_recv_goertzel_coef_table[CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT - 1] = CAPIDTMF_RECV_FUNDAMENTAL_OFFSET;
542 capidtmf_goertzel_loop (p_state->recv.goertzel_buffer[0],
543 capidtmf_recv_goertzel_coef_table, windowed_sample_buffer, n);
544 cycle_counter += n;
545 sample_number += n;
546 }
547 else
548 {
549 capidtmf_goertzel_result (p_state->recv.goertzel_buffer[0],
550 capidtmf_recv_goertzel_coef_table);
551 for (i = 0; i < CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT; i++)
552 {
553 lo = (dword)(p_state->recv.goertzel_buffer[0][i]);
554 hi = (dword)(p_state->recv.goertzel_buffer[1][i]);
555 if (hi != 0)
556 {
557 n = capidtmf_dword_leading_zeroes (hi);
558 hi = (hi << n) | (lo >> (32 - n));
559 }
560 else
561 {
562 n = capidtmf_dword_leading_zeroes (lo);
563 hi = lo << n;
564 n += 32;
565 }
566 n = 195 - 3 * n;
567 if (hi >= 0xcb300000L)
568 n += 2;
569 else if (hi >= 0xa1450000L)
570 n++;
571 goertzel_result_buffer[i] = (byte) n;
572 }
573 low_peak = DSPDTMF_RX_SENSITIVITY_LOW_DEFAULT;
574 result_digit = CAPIDTMF_RECV_NO_DIGIT;
575 for (i = 0; i < CAPIDTMF_LOW_GROUP_FREQUENCIES; i++)
576 {
577 if (goertzel_result_buffer[i] > low_peak)
578 {
579 low_peak = goertzel_result_buffer[i];
580 result_digit = (byte) i;
581 }
582 }
583 high_peak = DSPDTMF_RX_SENSITIVITY_HIGH_DEFAULT;
584 n = CAPIDTMF_RECV_NO_DIGIT;
585 for (i = CAPIDTMF_LOW_GROUP_FREQUENCIES; i < CAPIDTMF_RECV_BASE_FREQUENCY_COUNT; i++)
586 {
587 if (goertzel_result_buffer[i] > high_peak)
588 {
589 high_peak = goertzel_result_buffer[i];
590 n = (i - CAPIDTMF_LOW_GROUP_FREQUENCIES) << 2;
591 }
592 }
593 result_digit |= (byte) n;
594 if (low_peak + DSPDTMF_RX_HIGH_EXCEEDING_LOW_DEFAULT < high_peak)
595 result_digit = CAPIDTMF_RECV_NO_DIGIT;
596 if (high_peak + DSPDTMF_RX_LOW_EXCEEDING_HIGH_DEFAULT < low_peak)
597 result_digit = CAPIDTMF_RECV_NO_DIGIT;
598 n = 0;
599 for (i = 0; i < CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT; i++)
600 {
601 if ((((short)(low_peak - goertzel_result_buffer[i] - capidtmf_recv_guard_snr_low_table[i])) < 0)
602 || (((short)(high_peak - goertzel_result_buffer[i] - capidtmf_recv_guard_snr_high_table[i])) < 0))
603 {
604 n++;
605 }
606 }
607 if (n != 2)
608 result_digit = CAPIDTMF_RECV_NO_DIGIT;
609
610 if (result_digit == CAPIDTMF_RECV_NO_DIGIT)
611 {
612 if (p_state->recv.current_digit_on_time != 0)
613 {
614 if (++(p_state->recv.current_digit_off_time) >= p_state->recv.min_gap_duration)
615 {
616 p_state->recv.current_digit_on_time = 0;
617 p_state->recv.current_digit_off_time = 0;
618 }
619 }
620 else
621 {
622 if (p_state->recv.current_digit_off_time != 0)
623 (p_state->recv.current_digit_off_time)--;
624 }
625 }
626 else
627 {
628 if ((p_state->recv.current_digit_on_time == 0)
629 && (p_state->recv.current_digit_off_time != 0))
630 {
631 (p_state->recv.current_digit_off_time)--;
632 }
633 else
634 {
635 n = p_state->recv.current_digit_off_time;
636 if ((p_state->recv.current_digit_on_time != 0)
637 && (result_digit != p_state->recv.current_digit_value))
638 {
639 p_state->recv.current_digit_on_time = 0;
640 n = 0;
641 }
642 p_state->recv.current_digit_value = result_digit;
643 p_state->recv.current_digit_off_time = 0;
644 if (p_state->recv.current_digit_on_time != 0xffff)
645 {
646 p_state->recv.current_digit_on_time += n + 1;
647 if (p_state->recv.current_digit_on_time >= p_state->recv.min_digit_duration)
648 {
649 p_state->recv.current_digit_on_time = 0xffff;
650 i = (p_state->recv.digit_write_pos == CAPIDTMF_RECV_DIGIT_BUFFER_SIZE - 1) ?
651 0 : p_state->recv.digit_write_pos + 1;
652 if (i == p_state->recv.digit_read_pos)
653 {
654 trace (dprintf ("%s,%d: Receive digit overrun",
655 (char *)(FILE_), __LINE__));
656 }
657 else
658 {
659 p_state->recv.digit_buffer[p_state->recv.digit_write_pos] = result_digit;
660 p_state->recv.digit_write_pos = i;
661 p_state->recv.indication_state =
662 (p_state->recv.indication_state & ~CAPIDTMF_RECV_INDICATION_DIGIT) |
663 (~p_state->recv.indication_state_ack & CAPIDTMF_RECV_INDICATION_DIGIT);
664 }
665 }
666 }
667 }
668 }
669 cycle_counter = 0;
670 sample_number++;
671 }
672 }
673 p_state->recv.cycle_counter = cycle_counter;
674 }
675}
676
677
678void capidtmf_init (t_capidtmf_state *p_state, byte ulaw)
679{
680 p_state->ulaw = ulaw;
681 capidtmf_recv_init (p_state);
682}
683
684
685/*---------------------------------------------------------------------------*/
diff --git a/drivers/isdn/hardware/eicon/capidtmf.h b/drivers/isdn/hardware/eicon/capidtmf.h
new file mode 100644
index 000000000000..242048fb2dd7
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/capidtmf.h
@@ -0,0 +1,79 @@
1
2/*
3 *
4 Copyright (c) Eicon Networks, 2002.
5 *
6 This source file is supplied for the use with
7 Eicon Networks range of DIVA Server Adapters.
8 *
9 Eicon File Revision : 2.1
10 *
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2, or (at your option)
14 any later version.
15 *
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
18 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 See the GNU General Public License for more details.
20 *
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26#ifndef CAPIDTMF_H_
27#define CAPIDTMF_H_
28/*---------------------------------------------------------------------------*/
29/*---------------------------------------------------------------------------*/
30#define CAPIDTMF_TONE_GROUP_COUNT 2
31#define CAPIDTMF_LOW_GROUP_FREQUENCIES 4
32#define CAPIDTMF_HIGH_GROUP_FREQUENCIES 4
33#define DSPDTMF_RX_SENSITIVITY_LOW_DEFAULT 50 /* -52 dBm */
34#define DSPDTMF_RX_SENSITIVITY_HIGH_DEFAULT 50 /* -52 dBm */
35#define DSPDTMF_RX_HIGH_EXCEEDING_LOW_DEFAULT 10 /* dB */
36#define DSPDTMF_RX_LOW_EXCEEDING_HIGH_DEFAULT 10 /* dB */
37#define DSPDTMF_RX_HARMONICS_SEL_DEFAULT 12 /* dB */
38#define CAPIDTMF_RECV_BASE_FREQUENCY_COUNT (CAPIDTMF_LOW_GROUP_FREQUENCIES + CAPIDTMF_HIGH_GROUP_FREQUENCIES)
39#define CAPIDTMF_RECV_GUARD_FREQUENCY_COUNT 8
40#define CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT (CAPIDTMF_RECV_BASE_FREQUENCY_COUNT + CAPIDTMF_RECV_GUARD_FREQUENCY_COUNT)
41#define CAPIDTMF_RECV_POSITIVE_COEFF_COUNT 16
42#define CAPIDTMF_RECV_NEGATIVE_COEFF_COUNT (CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT - CAPIDTMF_RECV_POSITIVE_COEFF_COUNT)
43#define CAPIDTMF_RECV_ACCUMULATE_CYCLES 205
44#define CAPIDTMF_RECV_FUNDAMENTAL_OFFSET (0xff35L * 2)
45#define CAPIDTMF_RECV_FUNDAMENTAL_DECREMENT (0x0028L * 2)
46#define CAPIDTMF_RECV_DIGIT_BUFFER_SIZE 32
47#define CAPIDTMF_RECV_STATE_IDLE 0x00
48#define CAPIDTMF_RECV_STATE_DTMF_ACTIVE 0x01
49typedef struct tag_capidtmf_recv_state
50{
51 byte digit_buffer[CAPIDTMF_RECV_DIGIT_BUFFER_SIZE];
52 word digit_write_pos;
53 word digit_read_pos;
54 word indication_state;
55 word indication_state_ack;
56 long goertzel_buffer[2][CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT];
57 word min_gap_duration;
58 word min_digit_duration;
59 word cycle_counter;
60 word current_digit_on_time;
61 word current_digit_off_time;
62 byte current_digit_value;
63 byte state;
64} t_capidtmf_recv_state;
65typedef struct tag_capidtmf_state
66{
67 byte ulaw;
68 t_capidtmf_recv_state recv;
69} t_capidtmf_state;
70word capidtmf_recv_indication (t_capidtmf_state *p_state, byte *buffer);
71void capidtmf_recv_block (t_capidtmf_state *p_state, byte *buffer, word length);
72void capidtmf_init (t_capidtmf_state *p_state, byte ulaw);
73void capidtmf_recv_enable (t_capidtmf_state *p_state, word min_digit_duration, word min_gap_duration);
74void capidtmf_recv_disable (t_capidtmf_state *p_state);
75#define capidtmf_indication(p_state,buffer) (((p_state)->recv.indication_state != (p_state)->recv.indication_state_ack) ? capidtmf_recv_indication (p_state, buffer) : 0)
76#define capidtmf_recv_process_block(p_state,buffer,length) { if ((p_state)->recv.state != CAPIDTMF_RECV_STATE_IDLE) capidtmf_recv_block (p_state, buffer, length); }
77/*---------------------------------------------------------------------------*/
78/*---------------------------------------------------------------------------*/
79#endif
diff --git a/drivers/isdn/hardware/eicon/capifunc.c b/drivers/isdn/hardware/eicon/capifunc.c
new file mode 100644
index 000000000000..0afd7633556d
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/capifunc.c
@@ -0,0 +1,1219 @@
1/* $Id: capifunc.c,v 1.61.4.7 2005/02/11 19:40:25 armin Exp $
2 *
3 * ISDN interface module for Eicon active cards DIVA.
4 * CAPI Interface common functions
5 *
6 * Copyright 2000-2003 by Armin Schindler (mac@melware.de)
7 * Copyright 2000-2003 Cytronics & Melware (info@melware.de)
8 *
9 * This software may be used and distributed according to the terms
10 * of the GNU General Public License, incorporated herein by reference.
11 *
12 */
13
14#include "platform.h"
15#include "os_capi.h"
16#include "di_defs.h"
17#include "capi20.h"
18#include "divacapi.h"
19#include "divasync.h"
20#include "capifunc.h"
21
22#define DBG_MINIMUM (DL_LOG + DL_FTL + DL_ERR)
23#define DBG_DEFAULT (DBG_MINIMUM + DL_XLOG + DL_REG)
24
25DIVA_CAPI_ADAPTER *adapter = (DIVA_CAPI_ADAPTER *) NULL;
26APPL *application = (APPL *) NULL;
27byte max_appl = MAX_APPL;
28byte max_adapter = 0;
29static CAPI_MSG *mapped_msg = (CAPI_MSG *) NULL;
30
31byte UnMapController(byte);
32char DRIVERRELEASE_CAPI[32];
33
34extern void AutomaticLaw(DIVA_CAPI_ADAPTER *);
35extern void callback(ENTITY *);
36extern word api_remove_start(void);
37extern word CapiRelease(word);
38extern word CapiRegister(word);
39extern word api_put(APPL *, CAPI_MSG *);
40
41static diva_os_spin_lock_t api_lock;
42
43static LIST_HEAD(cards);
44
45static dword notify_handle;
46static void DIRequest(ENTITY * e);
47static DESCRIPTOR MAdapter;
48static DESCRIPTOR DAdapter;
49static byte ControllerMap[MAX_DESCRIPTORS + 1];
50
51
52static void diva_register_appl(struct capi_ctr *, __u16,
53 capi_register_params *);
54static void diva_release_appl(struct capi_ctr *, __u16);
55static char *diva_procinfo(struct capi_ctr *);
56static u16 diva_send_message(struct capi_ctr *,
57 diva_os_message_buffer_s *);
58extern void diva_os_set_controller_struct(struct capi_ctr *);
59
60extern void DIVA_DIDD_Read(DESCRIPTOR *, int);
61
62/*
63 * debug
64 */
65static void no_printf(unsigned char *, ...);
66#include "debuglib.c"
67static void xlog(char *x, ...)
68{
69#ifndef DIVA_NO_DEBUGLIB
70 va_list ap;
71 if (myDriverDebugHandle.dbgMask & DL_XLOG) {
72 va_start(ap, x);
73 if (myDriverDebugHandle.dbg_irq) {
74 myDriverDebugHandle.dbg_irq(myDriverDebugHandle.id,
75 DLI_XLOG, x, ap);
76 } else if (myDriverDebugHandle.dbg_old) {
77 myDriverDebugHandle.dbg_old(myDriverDebugHandle.id,
78 x, ap);
79 }
80 va_end(ap);
81 }
82#endif
83}
84
85/*
86 * info for proc
87 */
88static char *diva_procinfo(struct capi_ctr *ctrl)
89{
90 return (ctrl->serial);
91}
92
93/*
94 * stop debugging
95 */
96static void stop_dbg(void)
97{
98 DbgDeregister();
99 memset(&MAdapter, 0, sizeof(MAdapter));
100 dprintf = no_printf;
101}
102
103/*
104 * dummy debug function
105 */
106static void no_printf(unsigned char *x, ...)
107{
108}
109
110/*
111 * Controller mapping
112 */
113byte MapController(byte Controller)
114{
115 byte i;
116 byte MappedController = 0;
117 byte ctrl = Controller & 0x7f; /* mask external controller bit off */
118
119 for (i = 1; i < max_adapter + 1; i++) {
120 if (ctrl == ControllerMap[i]) {
121 MappedController = (byte) i;
122 break;
123 }
124 }
125 if (i > max_adapter) {
126 ControllerMap[0] = ctrl;
127 MappedController = 0;
128 }
129 return (MappedController | (Controller & 0x80)); /* put back external controller bit */
130}
131
132/*
133 * Controller unmapping
134 */
135byte UnMapController(byte MappedController)
136{
137 byte Controller;
138 byte ctrl = MappedController & 0x7f; /* mask external controller bit off */
139
140 if (ctrl <= max_adapter) {
141 Controller = ControllerMap[ctrl];
142 } else {
143 Controller = 0;
144 }
145
146 return (Controller | (MappedController & 0x80)); /* put back external controller bit */
147}
148
149/*
150 * find a new free id
151 */
152static int find_free_id(void)
153{
154 int num = 0;
155 DIVA_CAPI_ADAPTER *a;
156
157 while (num < MAX_DESCRIPTORS) {
158 a = &adapter[num];
159 if (!a->Id)
160 break;
161 num++;
162 }
163 return(num + 1);
164}
165
166/*
167 * find a card structure by controller number
168 */
169static diva_card *find_card_by_ctrl(word controller)
170{
171 struct list_head *tmp;
172 diva_card *card;
173
174 list_for_each(tmp, &cards) {
175 card = list_entry(tmp, diva_card, list);
176 if (ControllerMap[card->Id] == controller) {
177 if (card->remove_in_progress)
178 card = NULL;
179 return(card);
180 }
181 }
182 return (diva_card *) 0;
183}
184
185/*
186 * Buffer RX/TX
187 */
188void *TransmitBufferSet(APPL * appl, dword ref)
189{
190 appl->xbuffer_used[ref] = TRUE;
191 DBG_PRV1(("%d:xbuf_used(%d)", appl->Id, ref + 1))
192 return (void *) ref;
193}
194
195void *TransmitBufferGet(APPL * appl, void *p)
196{
197 if (appl->xbuffer_internal[(dword) p])
198 return appl->xbuffer_internal[(dword) p];
199
200 return appl->xbuffer_ptr[(dword) p];
201}
202
203void TransmitBufferFree(APPL * appl, void *p)
204{
205 appl->xbuffer_used[(dword) p] = FALSE;
206 DBG_PRV1(("%d:xbuf_free(%d)", appl->Id, ((dword) p) + 1))
207}
208
209void *ReceiveBufferGet(APPL * appl, int Num)
210{
211 return &appl->ReceiveBuffer[Num * appl->MaxDataLength];
212}
213
214/*
215 * api_remove_start/complete for cleanup
216 */
217void api_remove_complete(void)
218{
219 DBG_PRV1(("api_remove_complete"))
220}
221
222/*
223 * main function called by message.c
224 */
225void sendf(APPL * appl, word command, dword Id, word Number, byte * format, ...)
226{
227 word i, j;
228 word length = 12, dlength = 0;
229 byte *write;
230 CAPI_MSG msg;
231 byte *string = NULL;
232 va_list ap;
233 diva_os_message_buffer_s *dmb;
234 diva_card *card = NULL;
235 dword tmp;
236
237 if (!appl)
238 return;
239
240 DBG_PRV1(("sendf(a=%d,cmd=%x,format=%s)",
241 appl->Id, command, (byte *) format))
242
243 PUT_WORD(&msg.header.appl_id, appl->Id);
244 PUT_WORD(&msg.header.command, command);
245 if ((byte) (command >> 8) == 0x82)
246 Number = appl->Number++;
247 PUT_WORD(&msg.header.number, Number);
248
249 PUT_DWORD(&msg.header.controller, Id);
250 write = (byte *) & msg;
251 write += 12;
252
253 va_start(ap, format);
254 for (i = 0; format[i]; i++) {
255 switch (format[i]) {
256 case 'b':
257 tmp = va_arg(ap, dword);
258 *(byte *) write = (byte) (tmp & 0xff);
259 write += 1;
260 length += 1;
261 break;
262 case 'w':
263 tmp = va_arg(ap, dword);
264 PUT_WORD(write, (tmp & 0xffff));
265 write += 2;
266 length += 2;
267 break;
268 case 'd':
269 tmp = va_arg(ap, dword);
270 PUT_DWORD(write, tmp);
271 write += 4;
272 length += 4;
273 break;
274 case 's':
275 case 'S':
276 string = va_arg(ap, byte *);
277 length += string[0] + 1;
278 for (j = 0; j <= string[0]; j++)
279 *write++ = string[j];
280 break;
281 }
282 }
283 va_end(ap);
284
285 PUT_WORD(&msg.header.length, length);
286 msg.header.controller = UnMapController(msg.header.controller);
287
288 if (command == _DATA_B3_I)
289 dlength = GET_WORD(
290 ((byte *) & msg.info.data_b3_ind.Data_Length));
291
292 if (!(dmb = diva_os_alloc_message_buffer(length + dlength,
293 (void **) &write))) {
294 DBG_ERR(("sendf: alloc_message_buffer failed, incoming msg dropped."))
295 return;
296 }
297
298 /* copy msg header to sk_buff */
299 memcpy(write, (byte *) & msg, length);
300
301 /* if DATA_B3_IND, copy data too */
302 if (command == _DATA_B3_I) {
303 dword data = GET_DWORD(&msg.info.data_b3_ind.Data);
304 memcpy(write + length, (void *) data, dlength);
305 }
306
307#ifndef DIVA_NO_DEBUGLIB
308 if (myDriverDebugHandle.dbgMask & DL_XLOG) {
309 switch (command) {
310 default:
311 xlog("\x00\x02", &msg, 0x81, length);
312 break;
313 case _DATA_B3_R | CONFIRM:
314 if (myDriverDebugHandle.dbgMask & DL_BLK)
315 xlog("\x00\x02", &msg, 0x81, length);
316 break;
317 case _DATA_B3_I:
318 if (myDriverDebugHandle.dbgMask & DL_BLK) {
319 xlog("\x00\x02", &msg, 0x81, length);
320 for (i = 0; i < dlength; i += 256) {
321 DBG_BLK((((char *) GET_DWORD(&msg.info.data_b3_ind.Data)) + i,
322 ((dlength - i) < 256) ? (dlength - i) : 256))
323 if (!(myDriverDebugHandle.dbgMask & DL_PRV0))
324 break; /* not more if not explicitely requested */
325 }
326 }
327 break;
328 }
329 }
330#endif
331
332 /* find the card structure for this controller */
333 if (!(card = find_card_by_ctrl(write[8] & 0x7f))) {
334 DBG_ERR(("sendf - controller %d not found, incoming msg dropped",
335 write[8] & 0x7f))
336 diva_os_free_message_buffer(dmb);
337 return;
338 }
339 /* send capi msg to capi layer */
340 capi_ctr_handle_message(&card->capi_ctrl, appl->Id, dmb);
341}
342
343/*
344 * cleanup adapter
345 */
346static void clean_adapter(int id, struct list_head *free_mem_q)
347{
348 DIVA_CAPI_ADAPTER *a;
349 int i, k;
350
351 a = &adapter[id];
352 k = li_total_channels - a->li_channels;
353 if (k == 0) {
354 if (li_config_table) {
355 list_add((struct list_head *)li_config_table, free_mem_q);
356 li_config_table = NULL;
357 }
358 } else {
359 if (a->li_base < k) {
360 memmove(&li_config_table[a->li_base],
361 &li_config_table[a->li_base + a->li_channels],
362 (k - a->li_base) * sizeof(LI_CONFIG));
363 for (i = 0; i < k; i++) {
364 memmove(&li_config_table[i].flag_table[a->li_base],
365 &li_config_table[i].flag_table[a->li_base + a->li_channels],
366 k - a->li_base);
367 memmove(&li_config_table[i].
368 coef_table[a->li_base],
369 &li_config_table[i].coef_table[a->li_base + a->li_channels],
370 k - a->li_base);
371 }
372 }
373 }
374 li_total_channels = k;
375 for (i = id; i < max_adapter; i++) {
376 if (adapter[i].request)
377 adapter[i].li_base -= a->li_channels;
378 }
379 if (a->plci)
380 list_add((struct list_head *)a->plci, free_mem_q);
381
382 memset(a, 0x00, sizeof(DIVA_CAPI_ADAPTER));
383 while ((max_adapter != 0) && !adapter[max_adapter - 1].request)
384 max_adapter--;
385}
386
387/*
388 * remove a card, but ensures consistent state of LI tables
389 * in the time adapter is removed
390 */
391static void divacapi_remove_card(DESCRIPTOR * d)
392{
393 diva_card *card = NULL;
394 diva_os_spin_lock_magic_t old_irql;
395 LIST_HEAD(free_mem_q);
396 struct list_head *link;
397 struct list_head *tmp;
398
399 /*
400 * Set "remove in progress flag".
401 * Ensures that there is no call from sendf to CAPI in
402 * the time CAPI controller is about to be removed.
403 */
404 diva_os_enter_spin_lock(&api_lock, &old_irql, "remove card");
405 list_for_each(tmp, &cards) {
406 card = list_entry(tmp, diva_card, list);
407 if (card->d.request == d->request) {
408 card->remove_in_progress = 1;
409 list_del(tmp);
410 break;
411 }
412 }
413 diva_os_leave_spin_lock(&api_lock, &old_irql, "remove card");
414
415 if (card) {
416 /*
417 * Detach CAPI. Sendf cannot call to CAPI any more.
418 * After detach no call to send_message() is done too.
419 */
420 detach_capi_ctr(&card->capi_ctrl);
421
422 /*
423 * Now get API lock (to ensure stable state of LI tables)
424 * and update the adapter map/LI table.
425 */
426 diva_os_enter_spin_lock(&api_lock, &old_irql, "remove card");
427
428 clean_adapter(card->Id - 1, &free_mem_q);
429 DBG_TRC(("DelAdapterMap (%d) -> (%d)",
430 ControllerMap[card->Id], card->Id))
431 ControllerMap[card->Id] = 0;
432 DBG_TRC(("adapter remove, max_adapter=%d",
433 max_adapter));
434 diva_os_leave_spin_lock(&api_lock, &old_irql, "remove card");
435
436 /* After releasing the lock, we can free the memory */
437 diva_os_free (0, card);
438 }
439
440 /* free queued memory areas */
441 list_for_each_safe(link, tmp, &free_mem_q) {
442 list_del(link);
443 diva_os_free(0, link);
444 }
445}
446
447/*
448 * remove cards
449 */
450static void divacapi_remove_cards(void)
451{
452 DESCRIPTOR d;
453 struct list_head *tmp;
454 diva_card *card;
455 diva_os_spin_lock_magic_t old_irql;
456
457rescan:
458 diva_os_enter_spin_lock(&api_lock, &old_irql, "remove cards");
459 list_for_each(tmp, &cards) {
460 card = list_entry(tmp, diva_card, list);
461 diva_os_leave_spin_lock(&api_lock, &old_irql, "remove cards");
462 d.request = card->d.request;
463 divacapi_remove_card(&d);
464 goto rescan;
465 }
466 diva_os_leave_spin_lock(&api_lock, &old_irql, "remove cards");
467}
468
469/*
470 * sync_callback
471 */
472static void sync_callback(ENTITY * e)
473{
474 diva_os_spin_lock_magic_t old_irql;
475
476 DBG_TRC(("cb:Id=%x,Rc=%x,Ind=%x", e->Id, e->Rc, e->Ind))
477
478 diva_os_enter_spin_lock(&api_lock, &old_irql, "sync_callback");
479 callback(e);
480 diva_os_leave_spin_lock(&api_lock, &old_irql, "sync_callback");
481}
482
483/*
484 * add a new card
485 */
486static int diva_add_card(DESCRIPTOR * d)
487{
488 int k = 0, i = 0;
489 diva_os_spin_lock_magic_t old_irql;
490 diva_card *card = NULL;
491 struct capi_ctr *ctrl = NULL;
492 DIVA_CAPI_ADAPTER *a = NULL;
493 IDI_SYNC_REQ sync_req;
494 char serial[16];
495 void* mem_to_free;
496 LI_CONFIG *new_li_config_table;
497 int j;
498
499 if (!(card = (diva_card *) diva_os_malloc(0, sizeof(diva_card)))) {
500 DBG_ERR(("diva_add_card: failed to allocate card struct."))
501 return (0);
502 }
503 memset((char *) card, 0x00, sizeof(diva_card));
504 memcpy(&card->d, d, sizeof(DESCRIPTOR));
505 sync_req.GetName.Req = 0;
506 sync_req.GetName.Rc = IDI_SYNC_REQ_GET_NAME;
507 card->d.request((ENTITY *) & sync_req);
508 strlcpy(card->name, sync_req.GetName.name, sizeof(card->name));
509 ctrl = &card->capi_ctrl;
510 strcpy(ctrl->name, card->name);
511 ctrl->register_appl = diva_register_appl;
512 ctrl->release_appl = diva_release_appl;
513 ctrl->send_message = diva_send_message;
514 ctrl->procinfo = diva_procinfo;
515 ctrl->driverdata = card;
516 diva_os_set_controller_struct(ctrl);
517
518 if (attach_capi_ctr(ctrl)) {
519 DBG_ERR(("diva_add_card: failed to attach controller."))
520 diva_os_free(0, card);
521 return (0);
522 }
523
524 diva_os_enter_spin_lock(&api_lock, &old_irql, "find id");
525 card->Id = find_free_id();
526 diva_os_leave_spin_lock(&api_lock, &old_irql, "find id");
527
528 strlcpy(ctrl->manu, M_COMPANY, sizeof(ctrl->manu));
529 ctrl->version.majorversion = 2;
530 ctrl->version.minorversion = 0;
531 ctrl->version.majormanuversion = DRRELMAJOR;
532 ctrl->version.minormanuversion = DRRELMINOR;
533 sync_req.GetSerial.Req = 0;
534 sync_req.GetSerial.Rc = IDI_SYNC_REQ_GET_SERIAL;
535 sync_req.GetSerial.serial = 0;
536 card->d.request((ENTITY *) & sync_req);
537 if ((i = ((sync_req.GetSerial.serial & 0xff000000) >> 24))) {
538 sprintf(serial, "%ld-%d",
539 sync_req.GetSerial.serial & 0x00ffffff, i + 1);
540 } else {
541 sprintf(serial, "%ld", sync_req.GetSerial.serial);
542 }
543 serial[CAPI_SERIAL_LEN - 1] = 0;
544 strlcpy(ctrl->serial, serial, sizeof(ctrl->serial));
545
546 a = &adapter[card->Id - 1];
547 card->adapter = a;
548 a->os_card = card;
549 ControllerMap[card->Id] = (byte) (ctrl->cnr);
550
551 DBG_TRC(("AddAdapterMap (%d) -> (%d)", ctrl->cnr, card->Id))
552
553 sync_req.xdi_capi_prms.Req = 0;
554 sync_req.xdi_capi_prms.Rc = IDI_SYNC_REQ_XDI_GET_CAPI_PARAMS;
555 sync_req.xdi_capi_prms.info.structure_length =
556 sizeof(diva_xdi_get_capi_parameters_t);
557 card->d.request((ENTITY *) & sync_req);
558 a->flag_dynamic_l1_down =
559 sync_req.xdi_capi_prms.info.flag_dynamic_l1_down;
560 a->group_optimization_enabled =
561 sync_req.xdi_capi_prms.info.group_optimization_enabled;
562 a->request = DIRequest; /* card->d.request; */
563 a->max_plci = card->d.channels + 30;
564 a->max_listen = (card->d.channels > 2) ? 8 : 2;
565 if (!
566 (a->plci =
567 (PLCI *) diva_os_malloc(0, sizeof(PLCI) * a->max_plci))) {
568 DBG_ERR(("diva_add_card: failed alloc plci struct."))
569 memset(a, 0, sizeof(DIVA_CAPI_ADAPTER));
570 return (0);
571 }
572 memset(a->plci, 0, sizeof(PLCI) * a->max_plci);
573
574 for (k = 0; k < a->max_plci; k++) {
575 a->Id = (byte) card->Id;
576 a->plci[k].Sig.callback = sync_callback;
577 a->plci[k].Sig.XNum = 1;
578 a->plci[k].Sig.X = a->plci[k].XData;
579 a->plci[k].Sig.user[0] = (word) (card->Id - 1);
580 a->plci[k].Sig.user[1] = (word) k;
581 a->plci[k].NL.callback = sync_callback;
582 a->plci[k].NL.XNum = 1;
583 a->plci[k].NL.X = a->plci[k].XData;
584 a->plci[k].NL.user[0] = (word) ((card->Id - 1) | 0x8000);
585 a->plci[k].NL.user[1] = (word) k;
586 a->plci[k].adapter = a;
587 }
588
589 a->profile.Number = card->Id;
590 a->profile.Channels = card->d.channels;
591 if (card->d.features & DI_FAX3) {
592 a->profile.Global_Options = 0x71;
593 if (card->d.features & DI_CODEC)
594 a->profile.Global_Options |= 0x6;
595#if IMPLEMENT_DTMF
596 a->profile.Global_Options |= 0x8;
597#endif /* IMPLEMENT_DTMF */
598 a->profile.Global_Options |= 0x80; /* Line Interconnect */
599#if IMPLEMENT_ECHO_CANCELLER
600 a->profile.Global_Options |= 0x100;
601#endif /* IMPLEMENT_ECHO_CANCELLER */
602 a->profile.B1_Protocols = 0xdf;
603 a->profile.B2_Protocols = 0x1fdb;
604 a->profile.B3_Protocols = 0xb7;
605 a->manufacturer_features = MANUFACTURER_FEATURE_HARDDTMF;
606 } else {
607 a->profile.Global_Options = 0x71;
608 if (card->d.features & DI_CODEC)
609 a->profile.Global_Options |= 0x2;
610 a->profile.B1_Protocols = 0x43;
611 a->profile.B2_Protocols = 0x1f0f;
612 a->profile.B3_Protocols = 0x07;
613 a->manufacturer_features = 0;
614 }
615
616 a->li_pri = (a->profile.Channels > 2);
617 a->li_channels = a->li_pri ? MIXER_CHANNELS_PRI : MIXER_CHANNELS_BRI;
618 a->li_base = 0;
619 for (i = 0; &adapter[i] != a; i++) {
620 if (adapter[i].request)
621 a->li_base = adapter[i].li_base + adapter[i].li_channels;
622 }
623 k = li_total_channels + a->li_channels;
624 new_li_config_table =
625 (LI_CONFIG *) diva_os_malloc(0, ((k * sizeof(LI_CONFIG) + 3) & ~3) + (2 * k) * ((k + 3) & ~3));
626 if (new_li_config_table == NULL) {
627 DBG_ERR(("diva_add_card: failed alloc li_config table."))
628 memset(a, 0, sizeof(DIVA_CAPI_ADAPTER));
629 return (0);
630 }
631
632 /* Prevent access to line interconnect table in process update */
633 diva_os_enter_spin_lock(&api_lock, &old_irql, "add card");
634
635 j = 0;
636 for (i = 0; i < k; i++) {
637 if ((i >= a->li_base) && (i < a->li_base + a->li_channels))
638 memset(&new_li_config_table[i], 0, sizeof(LI_CONFIG));
639 else
640 memcpy(&new_li_config_table[i], &li_config_table[j], sizeof(LI_CONFIG));
641 new_li_config_table[i].flag_table =
642 ((byte *) new_li_config_table) + (((k * sizeof(LI_CONFIG) + 3) & ~3) + (2 * i) * ((k + 3) & ~3));
643 new_li_config_table[i].coef_table =
644 ((byte *) new_li_config_table) + (((k * sizeof(LI_CONFIG) + 3) & ~3) + (2 * i + 1) * ((k + 3) & ~3));
645 if ((i >= a->li_base) && (i < a->li_base + a->li_channels)) {
646 new_li_config_table[i].adapter = a;
647 memset(&new_li_config_table[i].flag_table[0], 0, k);
648 memset(&new_li_config_table[i].coef_table[0], 0, k);
649 } else {
650 if (a->li_base != 0) {
651 memcpy(&new_li_config_table[i].flag_table[0],
652 &li_config_table[j].flag_table[0],
653 a->li_base);
654 memcpy(&new_li_config_table[i].coef_table[0],
655 &li_config_table[j].coef_table[0],
656 a->li_base);
657 }
658 memset(&new_li_config_table[i].flag_table[a->li_base], 0, a->li_channels);
659 memset(&new_li_config_table[i].coef_table[a->li_base], 0, a->li_channels);
660 if (a->li_base + a->li_channels < k) {
661 memcpy(&new_li_config_table[i].flag_table[a->li_base +
662 a->li_channels],
663 &li_config_table[j].flag_table[a->li_base],
664 k - (a->li_base + a->li_channels));
665 memcpy(&new_li_config_table[i].coef_table[a->li_base +
666 a->li_channels],
667 &li_config_table[j].coef_table[a->li_base],
668 k - (a->li_base + a->li_channels));
669 }
670 j++;
671 }
672 }
673 li_total_channels = k;
674
675 mem_to_free = li_config_table;
676
677 li_config_table = new_li_config_table;
678 for (i = card->Id; i < max_adapter; i++) {
679 if (adapter[i].request)
680 adapter[i].li_base += a->li_channels;
681 }
682
683 if (a == &adapter[max_adapter])
684 max_adapter++;
685
686 list_add(&(card->list), &cards);
687 AutomaticLaw(a);
688
689 diva_os_leave_spin_lock(&api_lock, &old_irql, "add card");
690
691 if (mem_to_free) {
692 diva_os_free (0, mem_to_free);
693 }
694
695 i = 0;
696 while (i++ < 30) {
697 if (a->automatic_law > 3)
698 break;
699 diva_os_sleep(10);
700 }
701
702 /* profile information */
703 PUT_WORD(&ctrl->profile.nbchannel, card->d.channels);
704 ctrl->profile.goptions = a->profile.Global_Options;
705 ctrl->profile.support1 = a->profile.B1_Protocols;
706 ctrl->profile.support2 = a->profile.B2_Protocols;
707 ctrl->profile.support3 = a->profile.B3_Protocols;
708 /* manufacturer profile information */
709 ctrl->profile.manu[0] = a->man_profile.private_options;
710 ctrl->profile.manu[1] = a->man_profile.rtp_primary_payloads;
711 ctrl->profile.manu[2] = a->man_profile.rtp_additional_payloads;
712 ctrl->profile.manu[3] = 0;
713 ctrl->profile.manu[4] = 0;
714
715 capi_ctr_ready(ctrl);
716
717 DBG_TRC(("adapter added, max_adapter=%d", max_adapter));
718 return (1);
719}
720
721/*
722 * register appl
723 */
724static void diva_register_appl(struct capi_ctr *ctrl, __u16 appl,
725 capi_register_params * rp)
726{
727 APPL *this;
728 word bnum, xnum;
729 int i = 0;
730 unsigned char *p;
731 void *DataNCCI, *DataFlags, *ReceiveBuffer, *xbuffer_used;
732 void **xbuffer_ptr, **xbuffer_internal;
733 diva_os_spin_lock_magic_t old_irql;
734 unsigned int mem_len;
735 int nconn = rp->level3cnt;
736
737
738 if (diva_os_in_irq()) {
739 DBG_ERR(("CAPI_REGISTER - in irq context !"))
740 return;
741 }
742
743 DBG_TRC(("application register Id=%d", appl))
744
745 if (appl > MAX_APPL) {
746 DBG_ERR(("CAPI_REGISTER - appl.Id exceeds MAX_APPL"))
747 return;
748 }
749
750 if (nconn <= 0)
751 nconn = ctrl->profile.nbchannel * -nconn;
752
753 if (nconn == 0)
754 nconn = ctrl->profile.nbchannel;
755
756 DBG_LOG(("CAPI_REGISTER - Id = %d", appl))
757 DBG_LOG((" MaxLogicalConnections = %d(%d)", nconn, rp->level3cnt))
758 DBG_LOG((" MaxBDataBuffers = %d", rp->datablkcnt))
759 DBG_LOG((" MaxBDataLength = %d", rp->datablklen))
760
761 if (nconn < 1 ||
762 nconn > 255 ||
763 rp->datablklen < 80 ||
764 rp->datablklen > 2150 || rp->datablkcnt > 255) {
765 DBG_ERR(("CAPI_REGISTER - invalid parameters"))
766 return;
767 }
768
769 if (application[appl - 1].Id == appl) {
770 DBG_LOG(("CAPI_REGISTER - appl already registered"))
771 return; /* appl already registered */
772 }
773
774 /* alloc memory */
775
776 bnum = nconn * rp->datablkcnt;
777 xnum = nconn * MAX_DATA_B3;
778
779 mem_len = bnum * sizeof(word); /* DataNCCI */
780 mem_len += bnum * sizeof(word); /* DataFlags */
781 mem_len += bnum * rp->datablklen; /* ReceiveBuffer */
782 mem_len += xnum; /* xbuffer_used */
783 mem_len += xnum * sizeof(void *); /* xbuffer_ptr */
784 mem_len += xnum * sizeof(void *); /* xbuffer_internal */
785 mem_len += xnum * rp->datablklen; /* xbuffer_ptr[xnum] */
786
787 DBG_LOG((" Allocated Memory = %d", mem_len))
788 if (!(p = diva_os_malloc(0, mem_len))) {
789 DBG_ERR(("CAPI_REGISTER - memory allocation failed"))
790 return;
791 }
792 memset(p, 0, mem_len);
793
794 DataNCCI = (void *)p;
795 p += bnum * sizeof(word);
796 DataFlags = (void *)p;
797 p += bnum * sizeof(word);
798 ReceiveBuffer = (void *)p;
799 p += bnum * rp->datablklen;
800 xbuffer_used = (void *)p;
801 p += xnum;
802 xbuffer_ptr = (void **)p;
803 p += xnum * sizeof(void *);
804 xbuffer_internal = (void **)p;
805 p += xnum * sizeof(void *);
806 for (i = 0; i < xnum; i++) {
807 xbuffer_ptr[i] = (void *)p;
808 p += rp->datablklen;
809 }
810
811 /* initialize application data */
812 diva_os_enter_spin_lock(&api_lock, &old_irql, "register_appl");
813
814 this = &application[appl - 1];
815 memset(this, 0, sizeof(APPL));
816
817 this->Id = appl;
818
819 for (i = 0; i < max_adapter; i++) {
820 adapter[i].CIP_Mask[appl - 1] = 0;
821 }
822
823 this->queue_size = 1000;
824
825 this->MaxNCCI = (byte) nconn;
826 this->MaxNCCIData = (byte) rp->datablkcnt;
827 this->MaxBuffer = bnum;
828 this->MaxDataLength = rp->datablklen;
829
830 this->DataNCCI = DataNCCI;
831 this->DataFlags = DataFlags;
832 this->ReceiveBuffer = ReceiveBuffer;
833 this->xbuffer_used = xbuffer_used;
834 this->xbuffer_ptr = xbuffer_ptr;
835 this->xbuffer_internal = xbuffer_internal;
836 for (i = 0; i < xnum; i++) {
837 this->xbuffer_ptr[i] = xbuffer_ptr[i];
838 }
839
840 CapiRegister(this->Id);
841 diva_os_leave_spin_lock(&api_lock, &old_irql, "register_appl");
842
843}
844
845/*
846 * release appl
847 */
848static void diva_release_appl(struct capi_ctr *ctrl, __u16 appl)
849{
850 diva_os_spin_lock_magic_t old_irql;
851 APPL *this = &application[appl - 1];
852 void *mem_to_free = NULL;
853
854 DBG_TRC(("application %d(%d) cleanup", this->Id, appl))
855
856 if (diva_os_in_irq()) {
857 DBG_ERR(("CAPI_RELEASE - in irq context !"))
858 return;
859 }
860
861 diva_os_enter_spin_lock(&api_lock, &old_irql, "release_appl");
862 if (this->Id) {
863 CapiRelease(this->Id);
864 mem_to_free = this->DataNCCI;
865 this->DataNCCI = NULL;
866 this->Id = 0;
867 }
868 diva_os_leave_spin_lock(&api_lock, &old_irql, "release_appl");
869
870 if (mem_to_free)
871 diva_os_free(0, mem_to_free);
872
873}
874
875/*
876 * send message
877 */
878static u16 diva_send_message(struct capi_ctr *ctrl,
879 diva_os_message_buffer_s * dmb)
880{
881 int i = 0;
882 word ret = 0;
883 diva_os_spin_lock_magic_t old_irql;
884 CAPI_MSG *msg = (CAPI_MSG *) DIVA_MESSAGE_BUFFER_DATA(dmb);
885 APPL *this = &application[GET_WORD(&msg->header.appl_id) - 1];
886 diva_card *card = ctrl->driverdata;
887 __u32 length = DIVA_MESSAGE_BUFFER_LEN(dmb);
888 word clength = GET_WORD(&msg->header.length);
889 word command = GET_WORD(&msg->header.command);
890 u16 retval = CAPI_NOERROR;
891
892 if (diva_os_in_irq()) {
893 DBG_ERR(("CAPI_SEND_MSG - in irq context !"))
894 return CAPI_REGOSRESOURCEERR;
895 }
896 DBG_PRV1(("Write - appl = %d, cmd = 0x%x", this->Id, command))
897
898 if (card->remove_in_progress) {
899 DBG_ERR(("CAPI_SEND_MSG - remove in progress!"))
900 return CAPI_REGOSRESOURCEERR;
901 }
902
903 diva_os_enter_spin_lock(&api_lock, &old_irql, "send message");
904
905 if (!this->Id) {
906 diva_os_leave_spin_lock(&api_lock, &old_irql, "send message");
907 return CAPI_ILLAPPNR;
908 }
909
910 /* patch controller number */
911 msg->header.controller = ControllerMap[card->Id]
912 | (msg->header.controller & 0x80); /* preserve external controller bit */
913
914 switch (command) {
915 default:
916 xlog("\x00\x02", msg, 0x80, clength);
917 break;
918
919 case _DATA_B3_I | RESPONSE:
920#ifndef DIVA_NO_DEBUGLIB
921 if (myDriverDebugHandle.dbgMask & DL_BLK)
922 xlog("\x00\x02", msg, 0x80, clength);
923#endif
924 break;
925
926 case _DATA_B3_R:
927#ifndef DIVA_NO_DEBUGLIB
928 if (myDriverDebugHandle.dbgMask & DL_BLK)
929 xlog("\x00\x02", msg, 0x80, clength);
930#endif
931
932 if (clength == 24)
933 clength = 22; /* workaround for PPcom bug */
934 /* header is always 22 */
935 if (GET_WORD(&msg->info.data_b3_req.Data_Length) >
936 this->MaxDataLength
937 || GET_WORD(&msg->info.data_b3_req.Data_Length) >
938 (length - clength)) {
939 DBG_ERR(("Write - invalid message size"))
940 retval = CAPI_ILLCMDORSUBCMDORMSGTOSMALL;
941 goto write_end;
942 }
943
944 for (i = 0; i < (MAX_DATA_B3 * this->MaxNCCI)
945 && this->xbuffer_used[i]; i++);
946 if (i == (MAX_DATA_B3 * this->MaxNCCI)) {
947 DBG_ERR(("Write - too many data pending"))
948 retval = CAPI_SENDQUEUEFULL;
949 goto write_end;
950 }
951 msg->info.data_b3_req.Data = i;
952
953 this->xbuffer_internal[i] = NULL;
954 memcpy(this->xbuffer_ptr[i], &((__u8 *) msg)[clength],
955 GET_WORD(&msg->info.data_b3_req.Data_Length));
956
957#ifndef DIVA_NO_DEBUGLIB
958 if ((myDriverDebugHandle.dbgMask & DL_BLK)
959 && (myDriverDebugHandle.dbgMask & DL_XLOG)) {
960 int j;
961 for (j = 0; j <
962 GET_WORD(&msg->info.data_b3_req.Data_Length);
963 j += 256) {
964 DBG_BLK((((char *) this->xbuffer_ptr[i]) + j,
965 ((GET_WORD(&msg->info.data_b3_req.Data_Length) - j) <
966 256) ? (GET_WORD(&msg->info.data_b3_req.Data_Length) - j) : 256))
967 if (!(myDriverDebugHandle.dbgMask & DL_PRV0))
968 break; /* not more if not explicitely requested */
969 }
970 }
971#endif
972 break;
973 }
974
975 memcpy(mapped_msg, msg, (__u32) clength);
976 mapped_msg->header.controller = MapController(mapped_msg->header.controller);
977 mapped_msg->header.length = clength;
978 mapped_msg->header.command = command;
979 mapped_msg->header.number = GET_WORD(&msg->header.number);
980
981 ret = api_put(this, mapped_msg);
982 switch (ret) {
983 case 0:
984 break;
985 case _BAD_MSG:
986 DBG_ERR(("Write - bad message"))
987 retval = CAPI_ILLCMDORSUBCMDORMSGTOSMALL;
988 break;
989 case _QUEUE_FULL:
990 DBG_ERR(("Write - queue full"))
991 retval = CAPI_SENDQUEUEFULL;
992 break;
993 default:
994 DBG_ERR(("Write - api_put returned unknown error"))
995 retval = CAPI_UNKNOWNNOTPAR;
996 break;
997 }
998
999 write_end:
1000 diva_os_leave_spin_lock(&api_lock, &old_irql, "send message");
1001 if (retval == CAPI_NOERROR)
1002 diva_os_free_message_buffer(dmb);
1003 return retval;
1004}
1005
1006
1007/*
1008 * cards request function
1009 */
1010static void DIRequest(ENTITY * e)
1011{
1012 DIVA_CAPI_ADAPTER *a = &(adapter[(byte) e->user[0]]);
1013 diva_card *os_card = (diva_card *) a->os_card;
1014
1015 if (e->Req && (a->FlowControlIdTable[e->ReqCh] == e->Id)) {
1016 a->FlowControlSkipTable[e->ReqCh] = 1;
1017 }
1018
1019 (*(os_card->d.request)) (e);
1020}
1021
1022/*
1023 * callback function from didd
1024 */
1025static void didd_callback(void *context, DESCRIPTOR * adapter, int removal)
1026{
1027 if (adapter->type == IDI_DADAPTER) {
1028 DBG_ERR(("Notification about IDI_DADAPTER change ! Oops."));
1029 return;
1030 } else if (adapter->type == IDI_DIMAINT) {
1031 if (removal) {
1032 stop_dbg();
1033 } else {
1034 memcpy(&MAdapter, adapter, sizeof(MAdapter));
1035 dprintf = (DIVA_DI_PRINTF) MAdapter.request;
1036 DbgRegister("CAPI20", DRIVERRELEASE_CAPI, DBG_DEFAULT);
1037 }
1038 } else if ((adapter->type > 0) && (adapter->type < 16)) { /* IDI Adapter */
1039 if (removal) {
1040 divacapi_remove_card(adapter);
1041 } else {
1042 diva_add_card(adapter);
1043 }
1044 }
1045 return;
1046}
1047
1048/*
1049 * connect to didd
1050 */
1051static int divacapi_connect_didd(void)
1052{
1053 int x = 0;
1054 int dadapter = 0;
1055 IDI_SYNC_REQ req;
1056 DESCRIPTOR DIDD_Table[MAX_DESCRIPTORS];
1057
1058 DIVA_DIDD_Read(DIDD_Table, sizeof(DIDD_Table));
1059
1060 for (x = 0; x < MAX_DESCRIPTORS; x++) {
1061 if (DIDD_Table[x].type == IDI_DIMAINT) { /* MAINT found */
1062 memcpy(&MAdapter, &DIDD_Table[x], sizeof(DAdapter));
1063 dprintf = (DIVA_DI_PRINTF) MAdapter.request;
1064 DbgRegister("CAPI20", DRIVERRELEASE_CAPI, DBG_DEFAULT);
1065 break;
1066 }
1067 }
1068 for (x = 0; x < MAX_DESCRIPTORS; x++) {
1069 if (DIDD_Table[x].type == IDI_DADAPTER) { /* DADAPTER found */
1070 dadapter = 1;
1071 memcpy(&DAdapter, &DIDD_Table[x], sizeof(DAdapter));
1072 req.didd_notify.e.Req = 0;
1073 req.didd_notify.e.Rc =
1074 IDI_SYNC_REQ_DIDD_REGISTER_ADAPTER_NOTIFY;
1075 req.didd_notify.info.callback = (void *)didd_callback;
1076 req.didd_notify.info.context = NULL;
1077 DAdapter.request((ENTITY *) & req);
1078 if (req.didd_notify.e.Rc != 0xff) {
1079 stop_dbg();
1080 return (0);
1081 }
1082 notify_handle = req.didd_notify.info.handle;
1083 }
1084 else if ((DIDD_Table[x].type > 0) && (DIDD_Table[x].type < 16)) { /* IDI Adapter found */
1085 diva_add_card(&DIDD_Table[x]);
1086 }
1087 }
1088
1089 if (!dadapter) {
1090 stop_dbg();
1091 }
1092
1093 return (dadapter);
1094}
1095
1096/*
1097 * diconnect from didd
1098 */
1099static void divacapi_disconnect_didd(void)
1100{
1101 IDI_SYNC_REQ req;
1102
1103 stop_dbg();
1104
1105 req.didd_notify.e.Req = 0;
1106 req.didd_notify.e.Rc = IDI_SYNC_REQ_DIDD_REMOVE_ADAPTER_NOTIFY;
1107 req.didd_notify.info.handle = notify_handle;
1108 DAdapter.request((ENTITY *) & req);
1109}
1110
1111/*
1112 * we do not provide date/time here,
1113 * the application should do this.
1114 */
1115int fax_head_line_time(char *buffer)
1116{
1117 return (0);
1118}
1119
1120/*
1121 * init (alloc) main structures
1122 */
1123static int DIVA_INIT_FUNCTION init_main_structs(void)
1124{
1125 if (!(mapped_msg = (CAPI_MSG *) diva_os_malloc(0, MAX_MSG_SIZE))) {
1126 DBG_ERR(("init: failed alloc mapped_msg."))
1127 return 0;
1128 }
1129
1130 if (!(adapter = diva_os_malloc(0, sizeof(DIVA_CAPI_ADAPTER) * MAX_DESCRIPTORS))) {
1131 DBG_ERR(("init: failed alloc adapter struct."))
1132 diva_os_free(0, mapped_msg);
1133 return 0;
1134 }
1135 memset(adapter, 0, sizeof(DIVA_CAPI_ADAPTER) * MAX_DESCRIPTORS);
1136
1137 if (!(application = diva_os_malloc(0, sizeof(APPL) * MAX_APPL))) {
1138 DBG_ERR(("init: failed alloc application struct."))
1139 diva_os_free(0, mapped_msg);
1140 diva_os_free(0, adapter);
1141 return 0;
1142 }
1143 memset(application, 0, sizeof(APPL) * MAX_APPL);
1144
1145 return (1);
1146}
1147
1148/*
1149 * remove (free) main structures
1150 */
1151static void remove_main_structs(void)
1152{
1153 if (application)
1154 diva_os_free(0, application);
1155 if (adapter)
1156 diva_os_free(0, adapter);
1157 if (mapped_msg)
1158 diva_os_free(0, mapped_msg);
1159}
1160
1161/*
1162 * api_remove_start
1163 */
1164static void do_api_remove_start(void)
1165{
1166 diva_os_spin_lock_magic_t old_irql;
1167 int ret = 1, count = 100;
1168
1169 do {
1170 diva_os_enter_spin_lock(&api_lock, &old_irql, "api remove start");
1171 ret = api_remove_start();
1172 diva_os_leave_spin_lock(&api_lock, &old_irql, "api remove start");
1173
1174 diva_os_sleep(10);
1175 } while (ret && count--);
1176
1177 if (ret)
1178 DBG_ERR(("could not remove signaling ID's"))
1179}
1180
1181/*
1182 * init
1183 */
1184int DIVA_INIT_FUNCTION init_capifunc(void)
1185{
1186 diva_os_initialize_spin_lock(&api_lock, "capifunc");
1187 memset(ControllerMap, 0, MAX_DESCRIPTORS + 1);
1188 max_adapter = 0;
1189
1190
1191 if (!init_main_structs()) {
1192 DBG_ERR(("init: failed to init main structs."))
1193 diva_os_destroy_spin_lock(&api_lock, "capifunc");
1194 return (0);
1195 }
1196
1197 if (!divacapi_connect_didd()) {
1198 DBG_ERR(("init: failed to connect to DIDD."))
1199 do_api_remove_start();
1200 divacapi_remove_cards();
1201 remove_main_structs();
1202 diva_os_destroy_spin_lock(&api_lock, "capifunc");
1203 return (0);
1204 }
1205
1206 return (1);
1207}
1208
1209/*
1210 * finit
1211 */
1212void DIVA_EXIT_FUNCTION finit_capifunc(void)
1213{
1214 do_api_remove_start();
1215 divacapi_disconnect_didd();
1216 divacapi_remove_cards();
1217 remove_main_structs();
1218 diva_os_destroy_spin_lock(&api_lock, "capifunc");
1219}
diff --git a/drivers/isdn/hardware/eicon/capifunc.h b/drivers/isdn/hardware/eicon/capifunc.h
new file mode 100644
index 000000000000..bd256f29738c
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/capifunc.h
@@ -0,0 +1,40 @@
1/* $Id: capifunc.h,v 1.11.4.1 2004/08/28 20:03:53 armin Exp $
2 *
3 * ISDN interface module for Eicon active cards DIVA.
4 * CAPI Interface common functions
5 *
6 * Copyright 2000-2003 by Armin Schindler (mac@melware.de)
7 * Copyright 2000-2003 Cytronics & Melware (info@melware.de)
8 *
9 * This software may be used and distributed according to the terms
10 * of the GNU General Public License, incorporated herein by reference.
11 */
12
13#ifndef __CAPIFUNC_H__
14#define __CAPIFUNC_H__
15
16#define DRRELMAJOR 2
17#define DRRELMINOR 0
18#define DRRELEXTRA ""
19
20#define M_COMPANY "Eicon Networks"
21
22extern char DRIVERRELEASE_CAPI[];
23
24typedef struct _diva_card {
25 struct list_head list;
26 int remove_in_progress;
27 int Id;
28 struct capi_ctr capi_ctrl;
29 DIVA_CAPI_ADAPTER *adapter;
30 DESCRIPTOR d;
31 char name[32];
32} diva_card;
33
34/*
35 * prototypes
36 */
37int init_capifunc(void);
38void finit_capifunc(void);
39
40#endif /* __CAPIFUNC_H__ */
diff --git a/drivers/isdn/hardware/eicon/capimain.c b/drivers/isdn/hardware/eicon/capimain.c
new file mode 100644
index 000000000000..8fe4f3f09353
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/capimain.c
@@ -0,0 +1,147 @@
1/* $Id: capimain.c,v 1.24 2003/09/09 06:51:05 schindler Exp $
2 *
3 * ISDN interface module for Eicon active cards DIVA.
4 * CAPI Interface
5 *
6 * Copyright 2000-2003 by Armin Schindler (mac@melware.de)
7 * Copyright 2000-2003 Cytronics & Melware (info@melware.de)
8 *
9 * This software may be used and distributed according to the terms
10 * of the GNU General Public License, incorporated herein by reference.
11 */
12
13#include <linux/config.h>
14#include <linux/module.h>
15#include <linux/init.h>
16#include <asm/uaccess.h>
17#include <linux/smp_lock.h>
18#include <linux/skbuff.h>
19
20#include "os_capi.h"
21
22#include "platform.h"
23#include "di_defs.h"
24#include "capi20.h"
25#include "divacapi.h"
26#include "cp_vers.h"
27#include "capifunc.h"
28
29static char *main_revision = "$Revision: 1.24 $";
30static char *DRIVERNAME =
31 "Eicon DIVA - CAPI Interface driver (http://www.melware.net)";
32static char *DRIVERLNAME = "divacapi";
33
34MODULE_DESCRIPTION("CAPI driver for Eicon DIVA cards");
35MODULE_AUTHOR("Cytronics & Melware, Eicon Networks");
36MODULE_SUPPORTED_DEVICE("CAPI and DIVA card drivers");
37MODULE_LICENSE("GPL");
38
39/*
40 * get revision number from revision string
41 */
42static char *getrev(const char *revision)
43{
44 char *rev;
45 char *p;
46 if ((p = strchr(revision, ':'))) {
47 rev = p + 2;
48 p = strchr(rev, '$');
49 *--p = 0;
50 } else
51 rev = "1.0";
52 return rev;
53
54}
55
56/*
57 * alloc a message buffer
58 */
59diva_os_message_buffer_s *diva_os_alloc_message_buffer(unsigned long size,
60 void **data_buf)
61{
62 diva_os_message_buffer_s *dmb = alloc_skb(size, GFP_ATOMIC);
63 if (dmb) {
64 *data_buf = skb_put(dmb, size);
65 }
66 return (dmb);
67}
68
69/*
70 * free a message buffer
71 */
72void diva_os_free_message_buffer(diva_os_message_buffer_s * dmb)
73{
74 kfree_skb(dmb);
75}
76
77/*
78 * proc function for controller info
79 */
80static int diva_ctl_read_proc(char *page, char **start, off_t off,
81 int count, int *eof, struct capi_ctr *ctrl)
82{
83 diva_card *card = (diva_card *) ctrl->driverdata;
84 int len = 0;
85
86 len += sprintf(page + len, "%s\n", ctrl->name);
87 len += sprintf(page + len, "Serial No. : %s\n", ctrl->serial);
88 len += sprintf(page + len, "Id : %d\n", card->Id);
89 len += sprintf(page + len, "Channels : %d\n", card->d.channels);
90
91 if (off + count >= len)
92 *eof = 1;
93 if (len < off)
94 return 0;
95 *start = page + off;
96 return ((count < len - off) ? count : len - off);
97}
98
99/*
100 * set additional os settings in capi_ctr struct
101 */
102void diva_os_set_controller_struct(struct capi_ctr *ctrl)
103{
104 ctrl->driver_name = DRIVERLNAME;
105 ctrl->load_firmware = NULL;
106 ctrl->reset_ctr = NULL;
107 ctrl->ctr_read_proc = diva_ctl_read_proc;
108 ctrl->owner = THIS_MODULE;
109}
110
111/*
112 * module init
113 */
114static int DIVA_INIT_FUNCTION divacapi_init(void)
115{
116 char tmprev[32];
117 int ret = 0;
118
119 sprintf(DRIVERRELEASE_CAPI, "%d.%d%s", DRRELMAJOR, DRRELMINOR,
120 DRRELEXTRA);
121
122 printk(KERN_INFO "%s\n", DRIVERNAME);
123 printk(KERN_INFO "%s: Rel:%s Rev:", DRIVERLNAME, DRIVERRELEASE_CAPI);
124 strcpy(tmprev, main_revision);
125 printk("%s Build: %s(%s)\n", getrev(tmprev),
126 diva_capi_common_code_build, DIVA_BUILD);
127
128 if (!(init_capifunc())) {
129 printk(KERN_ERR "%s: failed init capi_driver.\n",
130 DRIVERLNAME);
131 ret = -EIO;
132 }
133
134 return ret;
135}
136
137/*
138 * module exit
139 */
140static void DIVA_EXIT_FUNCTION divacapi_exit(void)
141{
142 finit_capifunc();
143 printk(KERN_INFO "%s: module unloaded.\n", DRIVERLNAME);
144}
145
146module_init(divacapi_init);
147module_exit(divacapi_exit);
diff --git a/drivers/isdn/hardware/eicon/cardtype.h b/drivers/isdn/hardware/eicon/cardtype.h
new file mode 100644
index 000000000000..18a5c42fffdb
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/cardtype.h
@@ -0,0 +1,1098 @@
1
2/*
3 *
4 Copyright (c) Eicon Networks, 2002.
5 *
6 This source file is supplied for the use with
7 Eicon Networks range of DIVA Server Adapters.
8 *
9 Eicon File Revision : 2.1
10 *
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2, or (at your option)
14 any later version.
15 *
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
18 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 See the GNU General Public License for more details.
20 *
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26#ifndef _CARDTYPE_H_
27#define _CARDTYPE_H_
28#ifndef CARDTYPE_H_WANT_DATA
29#define CARDTYPE_H_WANT_DATA 0
30#endif
31#ifndef CARDTYPE_H_WANT_IDI_DATA
32#define CARDTYPE_H_WANT_IDI_DATA 0
33#endif
34#ifndef CARDTYPE_H_WANT_RESOURCE_DATA
35#define CARDTYPE_H_WANT_RESOURCE_DATA 1
36#endif
37#ifndef CARDTYPE_H_WANT_FILE_DATA
38#define CARDTYPE_H_WANT_FILE_DATA 1
39#endif
40/*
41 * D-channel protocol identifiers
42 *
43 * Attention: Unfortunately the identifiers defined here differ from
44 * the identifiers used in Protocol/1/Common/prot/q931.h .
45 * The only reason for this is that q931.h has not a global
46 * scope and we did not know about the definitions there.
47 * But the definitions here cannot be changed easily because
48 * they are used in setup scripts and programs.
49 * Thus the definitions here have to be mapped if they are
50 * used in the protocol code context !
51 *
52 * Now the identifiers are defined in the q931lib/constant.h file.
53 * Unfortunately this file has also not a global scope.
54 * But beginning with PROTTYPE_US any new identifier will get the same
55 * value as the corresponding PROT_* definition in q931lib/constant.h !
56 */
57#define PROTTYPE_MINVAL 0
58#define PROTTYPE_ETSI 0
59#define PROTTYPE_1TR6 1
60#define PROTTYPE_BELG 2
61#define PROTTYPE_FRANC 3
62#define PROTTYPE_ATEL 4
63#define PROTTYPE_NI 5 /* DMS 100, Nortel, National ISDN */
64#define PROTTYPE_5ESS 6 /* 5ESS , AT&T, 5ESS Custom */
65#define PROTTYPE_JAPAN 7
66#define PROTTYPE_SWED 8
67#define PROTTYPE_US 9 /* US autodetect */
68#define PROTTYPE_ITALY 10
69#define PROTTYPE_TWAN 11
70#define PROTTYPE_AUSTRAL 12
71#define PROTTYPE_4ESDN 13
72#define PROTTYPE_4ESDS 14
73#define PROTTYPE_4ELDS 15
74#define PROTTYPE_4EMGC 16
75#define PROTTYPE_4EMGI 17
76#define PROTTYPE_HONGKONG 18
77#define PROTTYPE_RBSCAS 19
78#define PROTTYPE_CORNETN 20
79#define PROTTYPE_QSIG 21
80#define PROTTYPE_NI_EWSD 22 /* EWSD, Siemens, National ISDN */
81#define PROTTYPE_5ESS_NI 23 /* 5ESS, Lucent, National ISDN */
82#define PROTTYPE_T1CORNETN 24
83#define PROTTYPE_CORNETNQ 25
84#define PROTTYPE_T1CORNETNQ 26
85#define PROTTYPE_T1QSIG 27
86#define PROTTYPE_E1UNCH 28
87#define PROTTYPE_T1UNCH 29
88#define PROTTYPE_E1CHAN 30
89#define PROTTYPE_T1CHAN 31
90#define PROTTYPE_R2CAS 32
91#define PROTTYPE_MAXVAL 32
92/*
93 * Card type identifiers
94 */
95#define CARD_UNKNOWN 0
96#define CARD_NONE 0
97 /* DIVA cards */
98#define CARDTYPE_DIVA_MCA 0
99#define CARDTYPE_DIVA_ISA 1
100#define CARDTYPE_DIVA_PCM 2
101#define CARDTYPE_DIVAPRO_ISA 3
102#define CARDTYPE_DIVAPRO_PCM 4
103#define CARDTYPE_DIVAPICO_ISA 5
104#define CARDTYPE_DIVAPICO_PCM 6
105 /* DIVA 2.0 cards */
106#define CARDTYPE_DIVAPRO20_PCI 7
107#define CARDTYPE_DIVA20_PCI 8
108 /* S cards */
109#define CARDTYPE_QUADRO_ISA 9
110#define CARDTYPE_S_ISA 10
111#define CARDTYPE_S_MCA 11
112#define CARDTYPE_SX_ISA 12
113#define CARDTYPE_SX_MCA 13
114#define CARDTYPE_SXN_ISA 14
115#define CARDTYPE_SXN_MCA 15
116#define CARDTYPE_SCOM_ISA 16
117#define CARDTYPE_SCOM_MCA 17
118#define CARDTYPE_PR_ISA 18
119#define CARDTYPE_PR_MCA 19
120 /* Diva Server cards (formerly called Maestra, later Amadeo) */
121#define CARDTYPE_MAESTRA_ISA 20
122#define CARDTYPE_MAESTRA_PCI 21
123 /* Diva Server cards to be developed (Quadro, Primary rate) */
124#define CARDTYPE_DIVASRV_Q_8M_PCI 22
125#define CARDTYPE_DIVASRV_P_30M_PCI 23
126#define CARDTYPE_DIVASRV_P_2M_PCI 24
127#define CARDTYPE_DIVASRV_P_9M_PCI 25
128 /* DIVA 2.0 cards */
129#define CARDTYPE_DIVA20_ISA 26
130#define CARDTYPE_DIVA20U_ISA 27
131#define CARDTYPE_DIVA20U_PCI 28
132#define CARDTYPE_DIVAPRO20_ISA 29
133#define CARDTYPE_DIVAPRO20U_ISA 30
134#define CARDTYPE_DIVAPRO20U_PCI 31
135 /* DIVA combi cards (piccola ISDN + rockwell V.34 modem) */
136#define CARDTYPE_DIVAMOBILE_PCM 32
137#define CARDTYPE_TDKGLOBALPRO_PCM 33
138 /* DIVA Pro PC OEM card for 'New Media Corporation' */
139#define CARDTYPE_NMC_DIVAPRO_PCM 34
140 /* DIVA Pro 2.0 OEM cards for 'British Telecom' */
141#define CARDTYPE_BT_EXLANE_PCI 35
142#define CARDTYPE_BT_EXLANE_ISA 36
143 /* DIVA low cost cards, 1st name DIVA 3.0, 2nd DIVA 2.01, 3rd ??? */
144#define CARDTYPE_DIVALOW_ISA 37
145#define CARDTYPE_DIVALOWU_ISA 38
146#define CARDTYPE_DIVALOW_PCI 39
147#define CARDTYPE_DIVALOWU_PCI 40
148 /* DIVA combi cards (piccola ISDN + rockwell V.90 modem) */
149#define CARDTYPE_DIVAMOBILE_V90_PCM 41
150#define CARDTYPE_TDKGLOBPRO_V90_PCM 42
151#define CARDTYPE_DIVASRV_P_23M_PCI 43
152#define CARDTYPE_DIVALOW_USB 44
153 /* DIVA Audio (CT) family */
154#define CARDTYPE_DIVA_CT_ST 45
155#define CARDTYPE_DIVA_CT_U 46
156#define CARDTYPE_DIVA_CTLITE_ST 47
157#define CARDTYPE_DIVA_CTLITE_U 48
158 /* DIVA ISDN plus V.90 series */
159#define CARDTYPE_DIVAISDN_V90_PCM 49
160#define CARDTYPE_DIVAISDN_V90_PCI 50
161#define CARDTYPE_DIVAISDN_TA 51
162 /* DIVA Server Voice cards */
163#define CARDTYPE_DIVASRV_VOICE_Q_8M_PCI 52
164 /* DIVA Server V2 cards */
165#define CARDTYPE_DIVASRV_Q_8M_V2_PCI 53
166#define CARDTYPE_DIVASRV_P_30M_V2_PCI 54
167 /* DIVA Server Voice V2 cards */
168#define CARDTYPE_DIVASRV_VOICE_Q_8M_V2_PCI 55
169#define CARDTYPE_DIVASRV_VOICE_P_30M_V2_PCI 56
170 /* Diva LAN */
171#define CARDTYPE_DIVAISDN_LAN 57
172#define CARDTYPE_DIVA_202_PCI_ST 58
173#define CARDTYPE_DIVA_202_PCI_U 59
174#define CARDTYPE_DIVASRV_B_2M_V2_PCI 60
175#define CARDTYPE_DIVASRV_B_2F_PCI 61
176#define CARDTYPE_DIVALOW_USBV2 62
177#define CARDTYPE_DIVASRV_VOICE_B_2M_V2_PCI 63
178#define CARDTYPE_DIVA_PRO_30_PCI_ST 64
179#define CARDTYPE_DIVA_CT_ST_V20 65
180/* Diva Mobile V.90 PC Card and Diva ISDN PC Card */
181#define CARDTYPE_DIVAMOBILE_V2_PCM 66
182#define CARDTYPE_DIVA_V2_PCM 67
183/* Re-badged Diva Pro PC Card */
184#define CARDTYPE_DIVA_PC_CARD 68
185 /* next free card type identifier */
186#define CARDTYPE_MAX 69
187/*
188 * The card families
189 */
190#define FAMILY_DIVA 1
191#define FAMILY_S 2
192#define FAMILY_MAESTRA 3
193#define FAMILY_MAX 4
194/*
195 * The basic card types
196 */
197#define CARD_DIVA 1 /* DSP based, old DSP */
198#define CARD_PRO 2 /* DSP based, new DSP */
199#define CARD_PICO 3 /* HSCX based */
200#define CARD_S 4 /* IDI on board based */
201#define CARD_SX 5 /* IDI on board based */
202#define CARD_SXN 6 /* IDI on board based */
203#define CARD_SCOM 7 /* IDI on board based */
204#define CARD_QUAD 8 /* IDI on board based */
205#define CARD_PR 9 /* IDI on board based */
206#define CARD_MAE 10 /* IDI on board based */
207#define CARD_MAEQ 11 /* IDI on board based */
208#define CARD_MAEP 12 /* IDI on board based */
209#define CARD_DIVALOW 13 /* IPAC based */
210#define CARD_CT 14 /* SCOUT based */
211#define CARD_DIVATA 15 /* DIVA TA */
212#define CARD_DIVALAN 16 /* DIVA LAN */
213#define CARD_MAE2 17 /* IDI on board based */
214#define CARD_MAX 18
215/*
216 * The internal card types of the S family
217 */
218#define CARD_I_NONE 0
219#define CARD_I_S 0
220#define CARD_I_SX 1
221#define CARD_I_SCOM 2
222#define CARD_I_QUAD 3
223#define CARD_I_PR 4
224/*
225 * The bus types we support
226 */
227#define BUS_ISA 1
228#define BUS_PCM 2
229#define BUS_PCI 3
230#define BUS_MCA 4
231#define BUS_USB 5
232#define BUS_COM 6
233#define BUS_LAN 7
234/*
235 * The chips we use for B-channel traffic
236 */
237#define CHIP_NONE 0
238#define CHIP_DSP 1
239#define CHIP_HSCX 2
240#define CHIP_IPAC 3
241#define CHIP_SCOUT 4
242#define CHIP_EXTERN 5
243#define CHIP_IPACX 6
244/*
245 * The structures where the card properties are aggregated by id
246 */
247typedef struct CARD_PROPERTIES
248{ char *Name; /* official marketing name */
249 unsigned short PnPId; /* plug and play ID (for non PCMIA cards) */
250 unsigned short Version; /* major and minor version no of the card */
251 unsigned char DescType; /* card type to set in the IDI descriptor */
252 unsigned char Family; /* basic family of the card */
253 unsigned short Features; /* features bits to set in the IDI desc. */
254 unsigned char Card; /* basic card type */
255 unsigned char IType; /* internal type of S cards (read from ram) */
256 unsigned char Bus; /* bus type this card is designed for */
257 unsigned char Chip; /* chipset used on card */
258 unsigned char Adapters; /* number of adapters on card */
259 unsigned char Channels; /* # of channels per adapter */
260 unsigned short E_info; /* # of ram entity info structs per adapter */
261 unsigned short SizeIo; /* size of IO window per adapter */
262 unsigned short SizeMem; /* size of memory window per adapter */
263} CARD_PROPERTIES;
264typedef struct CARD_RESOURCE
265{ unsigned char Int [10];
266 unsigned short IoFirst;
267 unsigned short IoStep;
268 unsigned short IoCnt;
269 unsigned long MemFirst;
270 unsigned long MemStep;
271 unsigned short MemCnt;
272} CARD_RESOURCE;
273/* test if the card of type 't' is a plug & play card */
274#define IS_PNP(t) \
275( \
276 ( \
277 CardProperties[t].Bus != BUS_ISA \
278 && \
279 CardProperties[t].Bus != BUS_MCA \
280 ) \
281 || \
282 ( \
283 CardProperties[t].Family != FAMILY_S \
284 && \
285 CardProperties[t].Card != CARD_DIVA \
286 ) \
287)
288/* extract IDI Descriptor info for card type 't' (p == DescType/Features) */
289#define IDI_PROP(t,p) (CardProperties[t].p)
290#if CARDTYPE_H_WANT_DATA
291#if CARDTYPE_H_WANT_IDI_DATA
292/* include "di_defs.h" for IDI adapter type and feature flag definitions */
293#include "di_defs.h"
294#else /*!CARDTYPE_H_WANT_IDI_DATA*/
295/* define IDI adapter types and feature flags here to prevent inclusion */
296#ifndef IDI_ADAPTER_S
297#define IDI_ADAPTER_S 1
298#define IDI_ADAPTER_PR 2
299#define IDI_ADAPTER_DIVA 3
300#define IDI_ADAPTER_MAESTRA 4
301#endif
302#ifndef DI_VOICE
303#define DI_VOICE 0x0 /* obsolete define */
304#define DI_FAX3 0x1
305#define DI_MODEM 0x2
306#define DI_POST 0x4
307#define DI_V110 0x8
308#define DI_V120 0x10
309#define DI_POTS 0x20
310#define DI_CODEC 0x40
311#define DI_MANAGE 0x80
312#define DI_V_42 0x0100
313#define DI_EXTD_FAX 0x0200 /* Extended FAX (ECM, 2D, T.6, Polling) */
314#define DI_AT_PARSER 0x0400 /* Build-in AT Parser in the L2 */
315#define DI_VOICE_OVER_IP 0x0800 /* Voice over IP support */
316#endif
317#endif /*CARDTYPE_H_WANT_IDI_DATA*/
318#define DI_V1x0 (DI_V110 | DI_V120)
319#define DI_NULL 0x0000
320#if defined(SOFT_DSP_SUPPORT)
321#define SOFT_DSP_ADD_FEATURES (DI_MODEM | DI_FAX3 | DI_AT_PARSER)
322#else
323#define SOFT_DSP_ADD_FEATURES 0
324#endif
325#if defined(SOFT_V110_SUPPORT)
326#define DI_SOFT_V110 DI_V110
327#else
328#define DI_SOFT_V110 0
329#endif
330/*--- CardProperties [Index=CARDTYPE_....] ---------------------------------*/
331CARD_PROPERTIES CardProperties [ ] =
332{
333{ /* 0 */
334 "Diva MCA", 0x6336, 0x0100,
335 IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V1x0 | DI_FAX3,
336 CARD_DIVA, CARD_I_NONE, BUS_MCA, CHIP_DSP,
337 1, 2, 0, 8, 0
338},
339{ /* 1 */
340 "Diva ISA", 0x0000, 0x0100,
341 IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V1x0 | DI_FAX3,
342 CARD_DIVA, CARD_I_NONE, BUS_ISA, CHIP_DSP,
343 1, 2, 0, 8, 0
344},
345{ /* 2 */
346 "Diva/PCM", 0x0000, 0x0100,
347 IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V1x0 | DI_FAX3,
348 CARD_DIVA, CARD_I_NONE, BUS_PCM, CHIP_DSP,
349 1, 2, 0, 8, 0
350},
351{ /* 3 */
352 "Diva PRO ISA", 0x0031, 0x0100,
353 IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V1x0 | DI_FAX3 | DI_MODEM | DI_CODEC,
354 CARD_PRO, CARD_I_NONE, BUS_ISA, CHIP_DSP,
355 1, 2, 0, 8, 0
356},
357{ /* 4 */
358 "Diva PRO PC-Card", 0x0000, 0x0100,
359 IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V1x0 | DI_FAX3 | DI_MODEM,
360 CARD_PRO, CARD_I_NONE, BUS_PCM, CHIP_DSP,
361 1, 2, 0, 8, 0
362},
363{ /* 5 */
364 "Diva PICCOLA ISA", 0x0051, 0x0100,
365 IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V120 | SOFT_DSP_ADD_FEATURES,
366 CARD_PICO, CARD_I_NONE, BUS_ISA, CHIP_HSCX,
367 1, 2, 0, 8, 0
368},
369{ /* 6 */
370 "Diva PICCOLA PCM", 0x0000, 0x0100,
371 IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V120 | SOFT_DSP_ADD_FEATURES,
372 CARD_PICO, CARD_I_NONE, BUS_PCM, CHIP_HSCX,
373 1, 2, 0, 8, 0
374},
375{ /* 7 */
376 "Diva PRO 2.0 S/T PCI", 0xe001, 0x0200,
377 IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V1x0 | DI_FAX3 | DI_MODEM | DI_POTS,
378 CARD_PRO, CARD_I_NONE, BUS_PCI, CHIP_DSP,
379 1, 2, 0, 8, 0
380},
381{ /* 8 */
382 "Diva 2.0 S/T PCI", 0xe002, 0x0200,
383 IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V120 | DI_POTS | SOFT_DSP_ADD_FEATURES,
384 CARD_PICO, CARD_I_NONE, BUS_PCI, CHIP_HSCX,
385 1, 2, 0, 8, 0
386},
387{ /* 9 */
388 "QUADRO ISA", 0x0000, 0x0100,
389 IDI_ADAPTER_S, FAMILY_S, DI_NULL,
390 CARD_QUAD, CARD_I_QUAD, BUS_ISA, CHIP_NONE,
391 4, 2, 16, 0, 0x800
392},
393{ /* 10 */
394 "S ISA", 0x0000, 0x0100,
395 IDI_ADAPTER_S, FAMILY_S, DI_CODEC,
396 CARD_S, CARD_I_S, BUS_ISA, CHIP_NONE,
397 1, 1, 16, 0, 0x800
398},
399{ /* 11 */
400 "S MCA", 0x6a93, 0x0100,
401 IDI_ADAPTER_S, FAMILY_S, DI_CODEC,
402 CARD_S, CARD_I_S, BUS_MCA, CHIP_NONE,
403 1, 1, 16, 16, 0x400
404},
405{ /* 12 */
406 "SX ISA", 0x0000, 0x0100,
407 IDI_ADAPTER_S, FAMILY_S, DI_NULL,
408 CARD_SX, CARD_I_SX, BUS_ISA, CHIP_NONE,
409 1, 2, 16, 0, 0x800
410},
411{ /* 13 */
412 "SX MCA", 0x6a93, 0x0100,
413 IDI_ADAPTER_S, FAMILY_S, DI_NULL,
414 CARD_SX, CARD_I_SX, BUS_MCA, CHIP_NONE,
415 1, 2, 16, 16, 0x400
416},
417{ /* 14 */
418 "SXN ISA", 0x0000, 0x0100,
419 IDI_ADAPTER_S, FAMILY_S, DI_NULL,
420 CARD_SXN, CARD_I_SCOM, BUS_ISA, CHIP_NONE,
421 1, 2, 16, 0, 0x800
422},
423{ /* 15 */
424 "SXN MCA", 0x6a93, 0x0100,
425 IDI_ADAPTER_S, FAMILY_S, DI_NULL,
426 CARD_SXN, CARD_I_SCOM, BUS_MCA, CHIP_NONE,
427 1, 2, 16, 16, 0x400
428},
429{ /* 16 */
430 "SCOM ISA", 0x0000, 0x0100,
431 IDI_ADAPTER_S, FAMILY_S, DI_CODEC,
432 CARD_SCOM, CARD_I_SCOM, BUS_ISA, CHIP_NONE,
433 1, 2, 16, 0, 0x800
434},
435{ /* 17 */
436 "SCOM MCA", 0x6a93, 0x0100,
437 IDI_ADAPTER_S, FAMILY_S, DI_CODEC,
438 CARD_SCOM, CARD_I_SCOM, BUS_MCA, CHIP_NONE,
439 1, 2, 16, 16, 0x400
440},
441{ /* 18 */
442 "S2M ISA", 0x0000, 0x0100,
443 IDI_ADAPTER_PR, FAMILY_S, DI_NULL,
444 CARD_PR, CARD_I_PR, BUS_ISA, CHIP_NONE,
445 1, 30, 256, 0, 0x4000
446},
447{ /* 19 */
448 "S2M MCA", 0x6abb, 0x0100,
449 IDI_ADAPTER_PR, FAMILY_S, DI_NULL,
450 CARD_PR, CARD_I_PR, BUS_MCA, CHIP_NONE,
451 1, 30, 256, 16, 0x4000
452},
453{ /* 20 */
454 "Diva Server BRI-2M ISA", 0x0041, 0x0100,
455 IDI_ADAPTER_MAESTRA,FAMILY_MAESTRA, DI_V1x0 | DI_FAX3 | DI_MODEM,
456 CARD_MAE, CARD_I_NONE, BUS_ISA, CHIP_DSP,
457 1, 2, 16, 8, 0
458},
459{ /* 21 */
460 "Diva Server BRI-2M PCI", 0xE010, 0x0100,
461 IDI_ADAPTER_MAESTRA,FAMILY_MAESTRA, DI_V1x0 | DI_FAX3 | DI_MODEM,
462 CARD_MAE, CARD_I_NONE, BUS_PCI, CHIP_DSP,
463 1, 2, 16, 8, 0
464},
465{ /* 22 */
466 "Diva Server 4BRI-8M PCI", 0xE012, 0x0100,
467 IDI_ADAPTER_MAESTRA,FAMILY_MAESTRA, DI_V1x0 | DI_FAX3 | DI_MODEM,
468 CARD_MAEQ, CARD_I_NONE, BUS_PCI, CHIP_DSP,
469 4, 2, 16, 8, 0
470},
471{ /* 23 */
472 "Diva Server PRI-30M PCI", 0xE014, 0x0100,
473 IDI_ADAPTER_MAESTRA,FAMILY_MAESTRA, DI_V1x0 | DI_FAX3 | DI_MODEM,
474 CARD_MAEP, CARD_I_NONE, BUS_PCI, CHIP_DSP,
475 1, 30, 256, 8, 0
476},
477{ /* 24 */
478 "Diva Server PRI-2M PCI", 0xe014, 0x0100,
479 IDI_ADAPTER_MAESTRA,FAMILY_MAESTRA, DI_V1x0 | DI_FAX3 | DI_MODEM,
480 CARD_MAEP, CARD_I_NONE, BUS_PCI, CHIP_DSP,
481 1, 30, 256, 8, 0
482},
483{ /* 25 */
484 "Diva Server PRI-9M PCI", 0x0000, 0x0100,
485 IDI_ADAPTER_MAESTRA,FAMILY_MAESTRA, DI_V1x0 | DI_FAX3 | DI_MODEM,
486 CARD_MAEP, CARD_I_NONE, BUS_PCI, CHIP_DSP,
487 1, 30, 256, 8, 0
488},
489{ /* 26 */
490 "Diva 2.0 S/T ISA", 0x0071, 0x0200,
491 IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V120 | DI_POTS | SOFT_DSP_ADD_FEATURES,
492 CARD_PICO, CARD_I_NONE, BUS_ISA, CHIP_HSCX,
493 1, 2, 0, 8, 0
494},
495{ /* 27 */
496 "Diva 2.0 U ISA", 0x0091, 0x0200,
497 IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V120 | DI_POTS | SOFT_DSP_ADD_FEATURES,
498 CARD_PICO, CARD_I_NONE, BUS_ISA, CHIP_HSCX,
499 1, 2, 0, 8, 0
500},
501{ /* 28 */
502 "Diva 2.0 U PCI", 0xe004, 0x0200,
503 IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V120 | DI_POTS | SOFT_DSP_ADD_FEATURES,
504 CARD_PICO, CARD_I_NONE, BUS_PCI, CHIP_HSCX,
505 1, 2, 0, 8, 0
506},
507{ /* 29 */
508 "Diva PRO 2.0 S/T ISA", 0x0061, 0x0200,
509 IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V1x0 | DI_FAX3 | DI_MODEM | DI_POTS,
510 CARD_PRO, CARD_I_NONE, BUS_ISA, CHIP_DSP,
511 1, 2, 0, 8, 0
512},
513{ /* 30 */
514 "Diva PRO 2.0 U ISA", 0x0081, 0x0200,
515 IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V1x0 | DI_FAX3 | DI_MODEM | DI_POTS,
516 CARD_PRO, CARD_I_NONE, BUS_ISA, CHIP_DSP,
517 1, 2, 0, 8, 0
518},
519{ /* 31 */
520 "Diva PRO 2.0 U PCI", 0xe003, 0x0200,
521 IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V1x0 | DI_FAX3 | DI_MODEM | DI_POTS,
522 CARD_PRO, CARD_I_NONE, BUS_PCI, CHIP_DSP,
523 1, 2, 0, 8, 0
524},
525{ /* 32 */
526 "Diva MOBILE", 0x0000, 0x0100,
527 IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V120 | SOFT_DSP_ADD_FEATURES,
528 CARD_PICO, CARD_I_NONE, BUS_PCM, CHIP_HSCX,
529 1, 2, 0, 8, 0
530},
531{ /* 33 */
532 "TDK DFI3600", 0x0000, 0x0100,
533 IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V120 | SOFT_DSP_ADD_FEATURES,
534 CARD_PICO, CARD_I_NONE, BUS_PCM, CHIP_HSCX,
535 1, 2, 0, 8, 0
536},
537{ /* 34 (OEM version of 4 - "Diva PRO PC-Card") */
538 "New Media ISDN", 0x0000, 0x0100,
539 IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V1x0 | DI_FAX3 | DI_MODEM,
540 CARD_PRO, CARD_I_NONE, BUS_PCM, CHIP_DSP,
541 1, 2, 0, 8, 0
542},
543{ /* 35 (OEM version of 7 - "Diva PRO 2.0 S/T PCI") */
544 "BT ExLane PCI", 0xe101, 0x0200,
545 IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V1x0 | DI_FAX3 | DI_MODEM | DI_POTS,
546 CARD_PRO, CARD_I_NONE, BUS_PCI, CHIP_DSP,
547 1, 2, 0, 8, 0
548},
549{ /* 36 (OEM version of 29 - "Diva PRO 2.0 S/T ISA") */
550 "BT ExLane ISA", 0x1061, 0x0200,
551 IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V1x0 | DI_FAX3 | DI_MODEM | DI_POTS,
552 CARD_PRO, CARD_I_NONE, BUS_ISA, CHIP_DSP,
553 1, 2, 0, 8, 0
554},
555{ /* 37 */
556 "Diva 2.01 S/T ISA", 0x00A1, 0x0300,
557 IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V120 | SOFT_DSP_ADD_FEATURES,
558 CARD_DIVALOW, CARD_I_NONE, BUS_ISA, CHIP_IPAC,
559 1, 2, 0, 8, 0
560},
561{ /* 38 */
562 "Diva 2.01 U ISA", 0x00B1, 0x0300,
563 IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V120 | SOFT_DSP_ADD_FEATURES,
564 CARD_DIVALOW, CARD_I_NONE, BUS_ISA, CHIP_IPAC,
565 1, 2, 0, 8, 0
566},
567{ /* 39 */
568 "Diva 2.01 S/T PCI", 0xe005, 0x0300,
569 IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V120 | SOFT_DSP_ADD_FEATURES,
570 CARD_DIVALOW, CARD_I_NONE, BUS_PCI, CHIP_IPAC,
571 1, 2, 0, 8, 0
572},
573{ /* 40 no ID yet */
574 "Diva 2.01 U PCI", 0x0000, 0x0300,
575 IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V120 | SOFT_DSP_ADD_FEATURES,
576 CARD_DIVALOW, CARD_I_NONE, BUS_PCI, CHIP_IPAC,
577 1, 2, 0, 8, 0
578},
579{ /* 41 */
580 "Diva MOBILE V.90", 0x0000, 0x0100,
581 IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V120 | SOFT_DSP_ADD_FEATURES,
582 CARD_PICO, CARD_I_NONE, BUS_PCM, CHIP_HSCX,
583 1, 2, 0, 8, 0
584},
585{ /* 42 */
586 "TDK DFI3600 V.90", 0x0000, 0x0100,
587 IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V120 | SOFT_DSP_ADD_FEATURES,
588 CARD_PICO, CARD_I_NONE, BUS_PCM, CHIP_HSCX,
589 1, 2, 0, 8, 0
590},
591{ /* 43 */
592 "Diva Server PRI-23M PCI", 0xe014, 0x0100,
593 IDI_ADAPTER_MAESTRA,FAMILY_MAESTRA, DI_V1x0 | DI_FAX3 | DI_MODEM,
594 CARD_MAEP, CARD_I_NONE, BUS_PCI, CHIP_DSP,
595 1, 30, 256, 8, 0
596},
597{ /* 44 */
598 "Diva 2.01 S/T USB", 0x1000, 0x0300,
599 IDI_ADAPTER_DIVA ,FAMILY_DIVA, DI_V120 | SOFT_DSP_ADD_FEATURES,
600 CARD_DIVALOW, CARD_I_NONE, BUS_USB, CHIP_IPAC,
601 1, 2, 0, 8, 0
602},
603{ /* 45 */
604 "Diva CT S/T PCI", 0xe006, 0x0300,
605 IDI_ADAPTER_DIVA ,FAMILY_DIVA, DI_V1x0 | DI_FAX3 | DI_MODEM | DI_CODEC,
606 CARD_CT, CARD_I_NONE, BUS_PCI, CHIP_DSP,
607 1, 2, 0, 0, 0
608},
609{ /* 46 */
610 "Diva CT U PCI", 0xe007, 0x0300,
611 IDI_ADAPTER_DIVA ,FAMILY_DIVA, DI_V1x0 | DI_FAX3 | DI_MODEM | DI_CODEC,
612 CARD_CT, CARD_I_NONE, BUS_PCI, CHIP_DSP,
613 1, 2, 0, 0, 0
614},
615{ /* 47 */
616 "Diva CT Lite S/T PCI", 0xe008, 0x0300,
617 IDI_ADAPTER_DIVA ,FAMILY_DIVA, DI_V1x0 | DI_FAX3 | DI_MODEM | DI_CODEC,
618 CARD_CT, CARD_I_NONE, BUS_PCI, CHIP_DSP,
619 1, 2, 0, 0, 0
620},
621{ /* 48 */
622 "Diva CT Lite U PCI", 0xe009, 0x0300,
623 IDI_ADAPTER_DIVA ,FAMILY_DIVA, DI_V1x0 | DI_FAX3 | DI_MODEM | DI_CODEC,
624 CARD_CT, CARD_I_NONE, BUS_PCI, CHIP_DSP,
625 1, 2, 0, 0, 0
626},
627{ /* 49 */
628 "Diva ISDN+V.90 PC Card", 0x8D8C, 0x0100,
629 IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V1x0 | DI_FAX3 | DI_MODEM | DI_CODEC,
630 CARD_DIVALOW, CARD_I_NONE, BUS_PCM, CHIP_IPAC,
631 1, 2, 0, 8, 0
632},
633{ /* 50 */
634 "Diva ISDN+V.90 PCI", 0xe00A, 0x0100,
635 IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V120 | SOFT_DSP_ADD_FEATURES,
636 CARD_DIVALOW, CARD_I_NONE, BUS_PCI, CHIP_IPAC,
637 1, 2, 0, 8, 0
638},
639{ /* 51 (DivaTA) no ID */
640 "Diva TA", 0x0000, 0x0300,
641 IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V110 | DI_FAX3 | SOFT_DSP_ADD_FEATURES,
642 CARD_DIVATA, CARD_I_NONE, BUS_COM, CHIP_EXTERN,
643 1, 1, 0, 8, 0
644},
645{ /* 52 (Diva Server 4BRI-8M PCI adapter enabled for Voice) */
646 "Diva Server Voice 4BRI-8M PCI", 0xE016, 0x0100,
647 IDI_ADAPTER_MAESTRA,FAMILY_MAESTRA, DI_V1x0 | DI_FAX3 | DI_MODEM | DI_VOICE_OVER_IP,
648 CARD_MAEQ, CARD_I_NONE, BUS_PCI, CHIP_DSP,
649 4, 2, 16, 8, 0
650},
651{ /* 53 (Diva Server 4BRI 2.0 adapter) */
652 "Diva Server 4BRI-8M 2.0 PCI", 0xE013, 0x0200,
653 IDI_ADAPTER_MAESTRA,FAMILY_MAESTRA, DI_V1x0 | DI_FAX3 | DI_MODEM,
654 CARD_MAEQ, CARD_I_NONE, BUS_PCI, CHIP_DSP,
655 4, 2, 16, 8, 0
656},
657{ /* 54 (Diva Server PRI 2.0 adapter) */
658 "Diva Server PRI 2.0 PCI", 0xE015, 0x0200,
659 IDI_ADAPTER_MAESTRA,FAMILY_MAESTRA, DI_V1x0 | DI_FAX3 | DI_MODEM,
660 CARD_MAEP, CARD_I_NONE, BUS_PCI, CHIP_DSP,
661 1, 30, 256, 8, 0
662},
663{ /* 55 (Diva Server 4BRI-8M 2.0 PCI adapter enabled for Voice) */
664 "Diva Server Voice 4BRI-8M 2.0 PCI", 0xE017, 0x0200,
665 IDI_ADAPTER_MAESTRA,FAMILY_MAESTRA, DI_V1x0 | DI_FAX3 | DI_MODEM | DI_VOICE_OVER_IP,
666 CARD_MAEQ, CARD_I_NONE, BUS_PCI, CHIP_DSP,
667 4, 2, 16, 8, 0
668},
669{ /* 56 (Diva Server PRI 2.0 PCI adapter enabled for Voice) */
670 "Diva Server Voice PRI 2.0 PCI", 0xE019, 0x0200,
671 IDI_ADAPTER_MAESTRA,FAMILY_MAESTRA, DI_V1x0 | DI_FAX3 | DI_MODEM | DI_VOICE_OVER_IP,
672 CARD_MAEP, CARD_I_NONE, BUS_PCI, CHIP_DSP,
673 1, 30, 256, 8, 0
674},
675{
676 /* 57 (DivaLan ) no ID */
677 "Diva LAN", 0x0000, 0x0300,
678 IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V110 | DI_FAX3 | SOFT_DSP_ADD_FEATURES,
679 CARD_DIVALAN, CARD_I_NONE, BUS_LAN, CHIP_EXTERN,
680 1, 1, 0, 8, 0
681},
682{ /* 58 */
683 "Diva 2.02 PCI S/T", 0xE00B, 0x0300,
684 IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V120 | SOFT_DSP_ADD_FEATURES | DI_SOFT_V110,
685 CARD_DIVALOW, CARD_I_NONE, BUS_PCI, CHIP_IPACX,
686 1, 2, 0, 8, 0
687},
688{ /* 59 */
689 "Diva 2.02 PCI U", 0xE00C, 0x0300,
690 IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V120 | SOFT_DSP_ADD_FEATURES,
691 CARD_DIVALOW, CARD_I_NONE, BUS_PCI, CHIP_IPACX,
692 1, 2, 0, 8, 0
693},
694{ /* 60 */
695 "Diva Server BRI-2M 2.0 PCI", 0xE018, 0x0200,
696 IDI_ADAPTER_MAESTRA,FAMILY_MAESTRA, DI_V1x0 | DI_FAX3 | DI_MODEM,
697 CARD_MAE2, CARD_I_NONE, BUS_PCI, CHIP_DSP,
698 1, 2, 16, 8, 0
699},
700{ /* 61 (the previous name was Diva Server BRI-2F 2.0 PCI) */
701 "Diva Server 2FX", 0xE01A, 0x0200,
702 IDI_ADAPTER_MAESTRA,FAMILY_MAESTRA, DI_V1x0 | DI_FAX3 | DI_MODEM | DI_SOFT_V110,
703 CARD_MAE2, CARD_I_NONE, BUS_PCI, CHIP_IPACX,
704 1, 2, 16, 8, 0
705},
706{ /* 62 */
707 " Diva ISDN USB 2.0", 0x1003, 0x0300,
708 IDI_ADAPTER_DIVA ,FAMILY_DIVA, DI_V120 | SOFT_DSP_ADD_FEATURES,
709 CARD_DIVALOW, CARD_I_NONE, BUS_USB, CHIP_IPACX,
710 1, 2, 0, 8, 0
711},
712{ /* 63 (Diva Server BRI-2M 2.0 PCI adapter enabled for Voice) */
713 "Diva Server Voice BRI-2M 2.0 PCI", 0xE01B, 0x0200,
714 IDI_ADAPTER_MAESTRA,FAMILY_MAESTRA, DI_V1x0 | DI_FAX3 | DI_MODEM | DI_VOICE_OVER_IP,
715 CARD_MAE2, CARD_I_NONE, BUS_PCI, CHIP_DSP,
716 1, 2, 16, 8, 0
717},
718{ /* 64 */
719 "Diva Pro 3.0 PCI", 0xe00d, 0x0300,
720 IDI_ADAPTER_DIVA ,FAMILY_DIVA, DI_V1x0 | DI_FAX3 | DI_MODEM,
721 CARD_PRO, CARD_I_NONE, BUS_PCI, CHIP_DSP,
722 1, 2, 0, 0, 0
723},
724{ /* 65 */
725 "Diva ISDN + CT 2.0", 0xE00E, 0x0300,
726 IDI_ADAPTER_DIVA ,FAMILY_DIVA, DI_V1x0 | DI_FAX3 | DI_MODEM | DI_CODEC,
727 CARD_CT, CARD_I_NONE, BUS_PCI, CHIP_DSP,
728 1, 2, 0, 0, 0
729},
730{ /* 66 */
731 "Diva Mobile V.90 PC Card", 0x8331, 0x0100,
732 IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V120 | SOFT_DSP_ADD_FEATURES,
733 CARD_PICO, CARD_I_NONE, BUS_PCM, CHIP_IPACX,
734 1, 2, 0, 8, 0
735},
736{ /* 67 */
737 "Diva ISDN PC Card", 0x8311, 0x0100,
738 IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V120 | SOFT_DSP_ADD_FEATURES,
739 CARD_PICO, CARD_I_NONE, BUS_PCM, CHIP_IPACX,
740 1, 2, 0, 8, 0
741},
742{ /* 68 */
743 "Diva ISDN PC Card", 0x0000, 0x0100,
744 IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V120 | SOFT_DSP_ADD_FEATURES,
745 CARD_PRO, CARD_I_NONE, BUS_PCM, CHIP_DSP,
746 1, 2, 0, 8, 0
747},
748} ;
749#if CARDTYPE_H_WANT_RESOURCE_DATA
750/*--- CardResource [Index=CARDTYPE_....] ---------------------------(GEI)-*/
751CARD_RESOURCE CardResource [ ] = {
752/* Interrupts IO-Address Mem-Address */
753/* 0*/ { 3,4,9,0,0,0,0,0,0,0, 0x200,0x20,16, 0x0,0x0,0 }, // DIVA MCA
754/* 1*/ { 3,4,9,10,11,12,0,0,0,0, 0x200,0x20,16, 0x0,0x0,0 }, // DIVA ISA
755/* 2*/ { 3,4,5,7,9,10,11,12,14,15, 0x0,0x8,8192, 0x0,0x0,0 }, // DIVA PCMCIA
756/* 3*/ { 3,5,7,9,10,11,12,14,15,0, 0x200,0x20,16, 0x0,0x0,0 }, // DIVA PRO ISA
757/* 4*/ { 3,4,5,7,9,10,11,12,14,15, 0x0,0x8,8192, 0x0,0x0,0 }, // DIVA PRO PCMCIA
758/* 5*/ { 3,5,7,9,10,11,12,14,15,0, 0x200,0x20,16, 0x0,0x0,0 }, // DIVA PICCOLA ISA
759/* 6*/ { 0,0,0,0,0,0,0,0,0,0, 0x0,0x0,0, 0x0,0x0,0 }, // DIVA PICCOLA PCMCIA
760/* 7*/ { 3,4,5,7,9,10,11,12,14,15, 0x0,0x8,8192, 0x0,0x0,0 }, // DIVA PRO 2.0 PCI
761/* 8*/ { 3,4,5,7,9,10,11,12,14,15, 0x0,0x8,8192, 0x0,0x0,0 }, // DIVA 2.0 PCI
762/* 9*/ { 3,4,5,7,9,10,11,12,0,0, 0x0,0x0,0, 0x80000,0x2000,64 }, // QUADRO ISA
763/*10*/ { 3,4,9,10,11,12,0,0,0,0, 0x0,0x0,0, 0xc0000,0x2000,16 }, // S ISA
764/*11*/ { 3,4,9,0,0,0,0,0,0,0, 0xc00,0x10,16, 0xc0000,0x2000,16 }, // S MCA
765/*12*/ { 3,4,9,10,11,12,0,0,0,0, 0x0,0x0,0, 0xc0000,0x2000,16 }, // SX ISA
766/*13*/ { 3,4,9,0,0,0,0,0,0,0, 0xc00,0x10,16, 0xc0000,0x2000,16 }, // SX MCA
767/*14*/ { 3,4,5,7,9,10,11,12,0,0, 0x0,0x0,0, 0x80000,0x0800,256 }, // SXN ISA
768/*15*/ { 3,4,9,0,0,0,0,0,0,0, 0xc00,0x10,16, 0xc0000,0x2000,16 }, // SXN MCA
769/*16*/ { 3,4,5,7,9,10,11,12,0,0, 0x0,0x0,0, 0x80000,0x0800,256 }, // SCOM ISA
770/*17*/ { 3,4,9,0,0,0,0,0,0,0, 0xc00,0x10,16, 0xc0000,0x2000,16 }, // SCOM MCA
771/*18*/ { 3,4,5,7,9,10,11,12,0,0, 0x0,0x0,0, 0xc0000,0x4000,16 }, // S2M ISA
772/*19*/ { 3,4,9,0,0,0,0,0,0,0, 0xc00,0x10,16, 0xc0000,0x4000,16 }, // S2M MCA
773/*20*/ { 3,5,7,9,10,11,12,14,15,0, 0x200,0x20,16, 0x0,0x0,0 }, // MAESTRA ISA
774/*21*/ { 3,4,5,7,9,10,11,12,14,15, 0x0,0x8,8192, 0x0,0x0,0 }, // MAESTRA PCI
775/*22*/ { 3,5,7,9,10,11,12,14,15,0, 0x200,0x20,16, 0x0,0x0,0 }, // MAESTRA QUADRO ISA
776/*23*/ { 3,4,5,7,9,10,11,12,14,15, 0x0,0x20,2048, 0x0,0x0,0 }, // MAESTRA QUADRO PCI
777/*24*/ { 3,5,7,9,10,11,12,14,15,0, 0x200,0x20,16, 0x0,0x0,0 }, // MAESTRA PRIMARY ISA
778/*25*/ { 3,4,5,7,9,10,11,12,14,15, 0x0,0x8,8192, 0x0,0x0,0 }, // MAESTRA PRIMARY PCI
779/*26*/ { 3,5,7,9,10,11,12,14,15,0, 0x200,0x20,16, 0x0,0x0,0 }, // DIVA 2.0 ISA
780/*27*/ { 3,5,7,9,10,11,12,14,15,0, 0x200,0x20,16, 0x0,0x0,0 }, // DIVA 2.0 /U ISA
781/*28*/ { 3,4,5,7,9,10,11,12,14,15, 0x0,0x8,8192, 0x0,0x0,0 }, // DIVA 2.0 /U PCI
782/*29*/ { 3,5,7,9,10,11,12,14,15,0, 0x200,0x20,16, 0x0,0x0,0 }, // DIVA PRO 2.0 ISA
783/*30*/ { 3,5,7,9,10,11,12,14,15,0, 0x200,0x20,16, 0x0,0x0,0 }, // DIVA PRO 2.0 /U ISA
784/*31*/ { 3,4,5,7,9,10,11,12,14,15, 0x0,0x8,8192, 0x0,0x0,0 }, // DIVA PRO 2.0 /U PCI
785/*32*/ { 0,0,0,0,0,0,0,0,0,0, 0x0,0x0,0, 0x0,0x0,0 }, // DIVA MOBILE
786/*33*/ { 0,0,0,0,0,0,0,0,0,0, 0x0,0x0,0, 0x0,0x0,0 }, // TDK DFI3600 (same as DIVA MOBILE [32])
787/*34*/ { 3,4,5,7,9,10,11,12,14,15, 0x0,0x8,8192, 0x0,0x0,0 }, // New Media ISDN (same as DIVA PRO PCMCIA [4])
788/*35*/ { 3,4,5,7,9,10,11,12,14,15, 0x0,0x8,8192, 0x0,0x0,0 }, // BT ExLane PCI (same as DIVA PRO 2.0 PCI [7])
789/*36*/ { 3,5,7,9,10,11,12,14,15,0, 0x200,0x20,16, 0x0,0x0,0 }, // BT ExLane ISA (same as DIVA PRO 2.0 ISA [29])
790/*37*/ { 3,5,7,9,10,11,12,14,15,0, 0x200,0x20,16, 0x0,0x0,0 }, // DIVA 2.01 S/T ISA
791/*38*/ { 3,5,7,9,10,11,12,14,15,0, 0x200,0x20,16, 0x0,0x0,0 }, // DIVA 2.01 U ISA
792/*39*/ { 3,4,5,7,9,10,11,12,14,15, 0x0,0x8,8192, 0x0,0x0,0 }, // DIVA 2.01 S/T PCI
793/*40*/ { 3,4,5,7,9,10,11,12,14,15, 0x0,0x8,8192, 0x0,0x0,0 }, // DIVA 2.01 U PCI
794/*41*/ { 0,0,0,0,0,0,0,0,0,0, 0x0,0x0,0, 0x0,0x0,0 }, // DIVA MOBILE V.90
795/*42*/ { 0,0,0,0,0,0,0,0,0,0, 0x0,0x0,0, 0x0,0x0,0 }, // TDK DFI3600 V.90 (same as DIVA MOBILE V.90 [39])
796/*43*/ { 3,4,5,7,9,10,11,12,14,15, 0x0,0x20,2048, 0x0,0x0,0 }, // DIVA Server PRI-23M PCI
797/*44*/ { 0,0,0,0,0,0,0,0,0,0, 0x0,0x0,0, 0x0,0x0,0 }, // DIVA 2.01 S/T USB
798/*45*/ { 0,0,0,0,0,0,0,0,0,0, 0x0,0x0,0, 0x0,0x0,0 }, // DIVA CT S/T PCI
799/*46*/ { 0,0,0,0,0,0,0,0,0,0, 0x0,0x0,0, 0x0,0x0,0 }, // DIVA CT U PCI
800/*47*/ { 0,0,0,0,0,0,0,0,0,0, 0x0,0x0,0, 0x0,0x0,0 }, // DIVA CT Lite S/T PCI
801/*48*/ { 0,0,0,0,0,0,0,0,0,0, 0x0,0x0,0, 0x0,0x0,0 }, // DIVA CT Lite U PCI
802/*49*/ { 0,0,0,0,0,0,0,0,0,0, 0x0,0x0,0, 0x0,0x0,0 }, // DIVA ISDN+V.90 PC Card
803/*50*/ { 3,4,5,7,9,10,11,12,14,15, 0x0,0x8,8192, 0x0,0x0,0 }, // DIVA ISDN+V.90 PCI
804/*51*/ { 0,0,0,0,0,0,0,0,0,0, 0x0,0x0,0, 0x0,0x0,0 }, // DIVA TA
805/*52*/ { 3,4,5,7,9,10,11,12,14,15, 0x0,0x20,2048, 0x0,0x0,0 }, // MAESTRA VOICE QUADRO PCI
806/*53*/ { 3,4,5,7,9,10,11,12,14,15, 0x0,0x20,2048, 0x0,0x0,0 }, // MAESTRA VOICE QUADRO PCI
807/*54*/ { 3,4,5,7,9,10,11,12,14,15, 0x0,0x8,8192, 0x0,0x0,0 }, // MAESTRA VOICE PRIMARY PCI
808/*55*/ { 3,4,5,7,9,10,11,12,14,15, 0x0,0x20,2048, 0x0,0x0,0 }, // MAESTRA VOICE QUADRO PCI
809/*56*/ { 3,4,5,7,9,10,11,12,14,15, 0x0,0x8,8192, 0x0,0x0,0 }, // MAESTRA VOICE PRIMARY PCI
810/*57*/ { 0,0,0,0,0,0,0,0,0,0, 0x0,0x0,0, 0x0,0x0,0 }, // DIVA LAN
811/*58*/ { 3,4,5,7,9,10,11,12,14,15, 0x0,0x8,8192, 0x0,0x0,0 }, // DIVA 2.02 S/T PCI
812/*59*/ { 3,4,5,7,9,10,11,12,14,15, 0x0,0x8,8192, 0x0,0x0,0 }, // DIVA 2.02 U PCI
813/*60*/ { 0,0,0,0,0,0,0,0,0,0, 0x0,0x0,0, 0x0,0x0,0 }, // Diva Server BRI-2M 2.0 PCI
814/*61*/ { 0,0,0,0,0,0,0,0,0,0, 0x0,0x0,0, 0x0,0x0,0 }, // Diva Server BRI-2F PCI
815/*62*/ { 0,0,0,0,0,0,0,0,0,0, 0x0,0x0,0, 0x0,0x0,0 }, // DIVA 2.01 S/T USB
816/*63*/ { 0,0,0,0,0,0,0,0,0,0, 0x0,0x0,0, 0x0,0x0,0 }, // Diva Server Voice BRI-2M 2.0 PCI
817/*64*/ { 3,4,5,7,9,10,11,12,14,15, 0x0,0x8,8192, 0x0,0x0,0 }, // DIVA 3.0 PCI
818/*65*/ { 0,0,0,0,0,0,0,0,0,0, 0x0,0x0,0, 0x0,0x0,0 }, // DIVA CT S/T PCI V2.0
819/*66*/ { 0,0,0,0,0,0,0,0,0,0, 0x0,0x0,0, 0x0,0x0,0 }, // DIVA Mobile V.90 PC Card
820/*67*/ { 0,0,0,0,0,0,0,0,0,0, 0x0,0x0,0, 0x0,0x0,0 }, // DIVA ISDN PC Card
821/*68*/ { 3,4,5,7,9,10,11,12,14,15, 0x0,0x8,8192, 0x0,0x0,0 }, // DIVA ISDN PC Card
822};
823#endif /*CARDTYPE_H_WANT_RESOURCE_DATA*/
824#else /*!CARDTYPE_H_WANT_DATA*/
825extern CARD_PROPERTIES CardProperties [] ;
826extern CARD_RESOURCE CardResource [] ;
827#endif /*CARDTYPE_H_WANT_DATA*/
828/*
829 * all existing download files
830 */
831#define CARD_DSP_CNT 5
832#define CARD_PROT_CNT 9
833#define CARD_FT_UNKNOWN 0
834#define CARD_FT_B 1
835#define CARD_FT_D 2
836#define CARD_FT_S 3
837#define CARD_FT_M 4
838#define CARD_FT_NEW_DSP_COMBIFILE 5 /* File format of new DSP code (the DSP code powered by Telindus) */
839#define CARD_FILE_NONE 0
840#define CARD_B_S 1
841#define CARD_B_P 2
842#define CARD_D_K1 3
843#define CARD_D_K2 4
844#define CARD_D_H 5
845#define CARD_D_V 6
846#define CARD_D_M 7
847#define CARD_D_F 8
848#define CARD_P_S_E 9
849#define CARD_P_S_1 10
850#define CARD_P_S_B 11
851#define CARD_P_S_F 12
852#define CARD_P_S_A 13
853#define CARD_P_S_N 14
854#define CARD_P_S_5 15
855#define CARD_P_S_J 16
856#define CARD_P_SX_E 17
857#define CARD_P_SX_1 18
858#define CARD_P_SX_B 19
859#define CARD_P_SX_F 20
860#define CARD_P_SX_A 21
861#define CARD_P_SX_N 22
862#define CARD_P_SX_5 23
863#define CARD_P_SX_J 24
864#define CARD_P_SY_E 25
865#define CARD_P_SY_1 26
866#define CARD_P_SY_B 27
867#define CARD_P_SY_F 28
868#define CARD_P_SY_A 29
869#define CARD_P_SY_N 30
870#define CARD_P_SY_5 31
871#define CARD_P_SY_J 32
872#define CARD_P_SQ_E 33
873#define CARD_P_SQ_1 34
874#define CARD_P_SQ_B 35
875#define CARD_P_SQ_F 36
876#define CARD_P_SQ_A 37
877#define CARD_P_SQ_N 38
878#define CARD_P_SQ_5 39
879#define CARD_P_SQ_J 40
880#define CARD_P_P_E 41
881#define CARD_P_P_1 42
882#define CARD_P_P_B 43
883#define CARD_P_P_F 44
884#define CARD_P_P_A 45
885#define CARD_P_P_N 46
886#define CARD_P_P_5 47
887#define CARD_P_P_J 48
888#define CARD_P_M_E 49
889#define CARD_P_M_1 50
890#define CARD_P_M_B 51
891#define CARD_P_M_F 52
892#define CARD_P_M_A 53
893#define CARD_P_M_N 54
894#define CARD_P_M_5 55
895#define CARD_P_M_J 56
896#define CARD_P_S_S 57
897#define CARD_P_SX_S 58
898#define CARD_P_SY_S 59
899#define CARD_P_SQ_S 60
900#define CARD_P_P_S 61
901#define CARD_P_M_S 62
902#define CARD_D_NEW_DSP_COMBIFILE 63
903typedef struct CARD_FILES_DATA
904{
905 char * Name;
906 unsigned char Type;
907}
908CARD_FILES_DATA;
909typedef struct CARD_FILES
910{
911 unsigned char Boot;
912 unsigned char Dsp [CARD_DSP_CNT];
913 unsigned char DspTelindus;
914 unsigned char Prot [CARD_PROT_CNT];
915}
916CARD_FILES;
917#if CARDTYPE_H_WANT_DATA
918#if CARDTYPE_H_WANT_FILE_DATA
919CARD_FILES_DATA CardFData [] = {
920// Filename Filetype
921 0, CARD_FT_UNKNOWN,
922 "didnload.bin", CARD_FT_B,
923 "diprload.bin", CARD_FT_B,
924 "didiva.bin", CARD_FT_D,
925 "didivapp.bin", CARD_FT_D,
926 "dihscx.bin", CARD_FT_D,
927 "div110.bin", CARD_FT_D,
928 "dimodem.bin", CARD_FT_D,
929 "difax.bin", CARD_FT_D,
930 "di_etsi.bin", CARD_FT_S,
931 "di_1tr6.bin", CARD_FT_S,
932 "di_belg.bin", CARD_FT_S,
933 "di_franc.bin", CARD_FT_S,
934 "di_atel.bin", CARD_FT_S,
935 "di_ni.bin", CARD_FT_S,
936 "di_5ess.bin", CARD_FT_S,
937 "di_japan.bin", CARD_FT_S,
938 "di_etsi.sx", CARD_FT_S,
939 "di_1tr6.sx", CARD_FT_S,
940 "di_belg.sx", CARD_FT_S,
941 "di_franc.sx", CARD_FT_S,
942 "di_atel.sx", CARD_FT_S,
943 "di_ni.sx", CARD_FT_S,
944 "di_5ess.sx", CARD_FT_S,
945 "di_japan.sx", CARD_FT_S,
946 "di_etsi.sy", CARD_FT_S,
947 "di_1tr6.sy", CARD_FT_S,
948 "di_belg.sy", CARD_FT_S,
949 "di_franc.sy", CARD_FT_S,
950 "di_atel.sy", CARD_FT_S,
951 "di_ni.sy", CARD_FT_S,
952 "di_5ess.sy", CARD_FT_S,
953 "di_japan.sy", CARD_FT_S,
954 "di_etsi.sq", CARD_FT_S,
955 "di_1tr6.sq", CARD_FT_S,
956 "di_belg.sq", CARD_FT_S,
957 "di_franc.sq", CARD_FT_S,
958 "di_atel.sq", CARD_FT_S,
959 "di_ni.sq", CARD_FT_S,
960 "di_5ess.sq", CARD_FT_S,
961 "di_japan.sq", CARD_FT_S,
962 "di_etsi.p", CARD_FT_S,
963 "di_1tr6.p", CARD_FT_S,
964 "di_belg.p", CARD_FT_S,
965 "di_franc.p", CARD_FT_S,
966 "di_atel.p", CARD_FT_S,
967 "di_ni.p", CARD_FT_S,
968 "di_5ess.p", CARD_FT_S,
969 "di_japan.p", CARD_FT_S,
970 "di_etsi.sm", CARD_FT_M,
971 "di_1tr6.sm", CARD_FT_M,
972 "di_belg.sm", CARD_FT_M,
973 "di_franc.sm", CARD_FT_M,
974 "di_atel.sm", CARD_FT_M,
975 "di_ni.sm", CARD_FT_M,
976 "di_5ess.sm", CARD_FT_M,
977 "di_japan.sm", CARD_FT_M,
978 "di_swed.bin", CARD_FT_S,
979 "di_swed.sx", CARD_FT_S,
980 "di_swed.sy", CARD_FT_S,
981 "di_swed.sq", CARD_FT_S,
982 "di_swed.p", CARD_FT_S,
983 "di_swed.sm", CARD_FT_M,
984 "didspdld.bin", CARD_FT_NEW_DSP_COMBIFILE
985};
986CARD_FILES CardFiles [] =
987{
988 { /* CARD_UNKNOWN */
989 CARD_FILE_NONE,
990 CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
991 CARD_FILE_NONE,
992 CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
993 CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
994 CARD_FILE_NONE
995 },
996 { /* CARD_DIVA */
997 CARD_FILE_NONE,
998 CARD_D_K1, CARD_D_H, CARD_D_V, CARD_FILE_NONE, CARD_D_F,
999 CARD_D_NEW_DSP_COMBIFILE,
1000 CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
1001 CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
1002 CARD_FILE_NONE
1003 },
1004 { /* CARD_PRO */
1005 CARD_FILE_NONE,
1006 CARD_D_K2, CARD_D_H, CARD_D_V, CARD_D_M, CARD_D_F,
1007 CARD_D_NEW_DSP_COMBIFILE,
1008 CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
1009 CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
1010 CARD_FILE_NONE
1011 },
1012 { /* CARD_PICO */
1013 CARD_FILE_NONE,
1014 CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
1015 CARD_FILE_NONE,
1016 CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
1017 CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
1018 CARD_FILE_NONE
1019 },
1020 { /* CARD_S */
1021 CARD_B_S,
1022 CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
1023 CARD_FILE_NONE,
1024 CARD_P_S_E, CARD_P_S_1, CARD_P_S_B, CARD_P_S_F,
1025 CARD_P_S_A, CARD_P_S_N, CARD_P_S_5, CARD_P_S_J,
1026 CARD_P_S_S
1027 },
1028 { /* CARD_SX */
1029 CARD_B_S,
1030 CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
1031 CARD_FILE_NONE,
1032 CARD_P_SX_E, CARD_P_SX_1, CARD_P_SX_B, CARD_P_SX_F,
1033 CARD_P_SX_A, CARD_P_SX_N, CARD_P_SX_5, CARD_P_SX_J,
1034 CARD_P_SX_S
1035 },
1036 { /* CARD_SXN */
1037 CARD_B_S,
1038 CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
1039 CARD_FILE_NONE,
1040 CARD_P_SY_E, CARD_P_SY_1, CARD_P_SY_B, CARD_P_SY_F,
1041 CARD_P_SY_A, CARD_P_SY_N, CARD_P_SY_5, CARD_P_SY_J,
1042 CARD_P_SY_S
1043 },
1044 { /* CARD_SCOM */
1045 CARD_B_S,
1046 CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
1047 CARD_FILE_NONE,
1048 CARD_P_SY_E, CARD_P_SY_1, CARD_P_SY_B, CARD_P_SY_F,
1049 CARD_P_SY_A, CARD_P_SY_N, CARD_P_SY_5, CARD_P_SY_J,
1050 CARD_P_SY_S
1051 },
1052 { /* CARD_QUAD */
1053 CARD_B_S,
1054 CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
1055 CARD_FILE_NONE,
1056 CARD_P_SQ_E, CARD_P_SQ_1, CARD_P_SQ_B, CARD_P_SQ_F,
1057 CARD_P_SQ_A, CARD_P_SQ_N, CARD_P_SQ_5, CARD_P_SQ_J,
1058 CARD_P_SQ_S
1059 },
1060 { /* CARD_PR */
1061 CARD_B_P,
1062 CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
1063 CARD_FILE_NONE,
1064 CARD_P_P_E, CARD_P_P_1, CARD_P_P_B, CARD_P_P_F,
1065 CARD_P_P_A, CARD_P_P_N, CARD_P_P_5, CARD_P_P_J,
1066 CARD_P_P_S
1067 },
1068 { /* CARD_MAE */
1069 CARD_FILE_NONE,
1070 CARD_D_K2, CARD_D_H, CARD_D_V, CARD_D_M, CARD_D_F,
1071 CARD_D_NEW_DSP_COMBIFILE,
1072 CARD_P_M_E, CARD_P_M_1, CARD_P_M_B, CARD_P_M_F,
1073 CARD_P_M_A, CARD_P_M_N, CARD_P_M_5, CARD_P_M_J,
1074 CARD_P_M_S
1075 },
1076 { /* CARD_MAEQ */ /* currently not supported */
1077 CARD_FILE_NONE,
1078 CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
1079 CARD_FILE_NONE,
1080 CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
1081 CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
1082 CARD_FILE_NONE
1083 },
1084 { /* CARD_MAEP */ /* currently not supported */
1085 CARD_FILE_NONE,
1086 CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
1087 CARD_FILE_NONE,
1088 CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
1089 CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
1090 CARD_FILE_NONE
1091 }
1092};
1093#endif /*CARDTYPE_H_WANT_FILE_DATA*/
1094#else /*!CARDTYPE_H_WANT_DATA*/
1095extern CARD_FILES_DATA CardFData [] ;
1096extern CARD_FILES CardFiles [] ;
1097#endif /*CARDTYPE_H_WANT_DATA*/
1098#endif /* _CARDTYPE_H_ */
diff --git a/drivers/isdn/hardware/eicon/cp_vers.h b/drivers/isdn/hardware/eicon/cp_vers.h
new file mode 100644
index 000000000000..cb5ada31111c
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/cp_vers.h
@@ -0,0 +1,26 @@
1
2/*
3 *
4 Copyright (c) Eicon Networks, 2002.
5 *
6 This source file is supplied for the use with
7 Eicon Networks range of DIVA Server Adapters.
8 *
9 Eicon File Revision : 2.1
10 *
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2, or (at your option)
14 any later version.
15 *
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
18 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 See the GNU General Public License for more details.
20 *
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26static char diva_capi_common_code_build[] = "102-28";
diff --git a/drivers/isdn/hardware/eicon/dadapter.c b/drivers/isdn/hardware/eicon/dadapter.c
new file mode 100644
index 000000000000..6e548a222ef1
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/dadapter.c
@@ -0,0 +1,366 @@
1
2/*
3 *
4 Copyright (c) Eicon Networks, 2002.
5 *
6 This source file is supplied for the use with
7 Eicon Networks range of DIVA Server Adapters.
8 *
9 Eicon File Revision : 2.1
10 *
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2, or (at your option)
14 any later version.
15 *
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
18 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 See the GNU General Public License for more details.
20 *
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26#include "platform.h"
27#include "pc.h"
28#include "debuglib.h"
29#include "di_defs.h"
30#include "divasync.h"
31#include "dadapter.h"
32/* --------------------------------------------------------------------------
33 Adapter array change notification framework
34 -------------------------------------------------------------------------- */
35typedef struct _didd_adapter_change_notification {
36 didd_adapter_change_callback_t callback;
37 void IDI_CALL_ENTITY_T * context;
38} didd_adapter_change_notification_t, \
39 * IDI_CALL_ENTITY_T pdidd_adapter_change_notification_t;
40#define DIVA_DIDD_MAX_NOTIFICATIONS 256
41static didd_adapter_change_notification_t\
42 NotificationTable[DIVA_DIDD_MAX_NOTIFICATIONS];
43/* --------------------------------------------------------------------------
44 Array to held adapter information
45 -------------------------------------------------------------------------- */
46static DESCRIPTOR HandleTable[NEW_MAX_DESCRIPTORS];
47dword Adapters = 0; /* Number of adapters */
48/* --------------------------------------------------------------------------
49 Shadow IDI_DIMAINT
50 and 'shadow' debug stuff
51 -------------------------------------------------------------------------- */
52static void no_printf (unsigned char * format, ...)
53{
54#ifdef EBUG
55 va_list ap;
56 va_start (ap, format);
57 debug((format, ap));
58 va_end (ap);
59#endif
60}
61
62/* -------------------------------------------------------------------------
63 Portable debug Library
64 ------------------------------------------------------------------------- */
65#include "debuglib.c"
66
67static DESCRIPTOR MAdapter = {IDI_DIMAINT, /* Adapter Type */
68 0x00, /* Channels */
69 0x0000, /* Features */
70 (IDI_CALL)no_printf};
71/* --------------------------------------------------------------------------
72 DAdapter. Only IDI clients with buffer, that is huge enough to
73 get all descriptors will receive information about DAdapter
74 { byte type, byte channels, word features, IDI_CALL request }
75 -------------------------------------------------------------------------- */
76static void IDI_CALL_LINK_T diva_dadapter_request (ENTITY IDI_CALL_ENTITY_T *);
77static DESCRIPTOR DAdapter = {IDI_DADAPTER, /* Adapter Type */
78 0x00, /* Channels */
79 0x0000, /* Features */
80 diva_dadapter_request };
81/* --------------------------------------------------------------------------
82 LOCALS
83 -------------------------------------------------------------------------- */
84static dword diva_register_adapter_callback (\
85 didd_adapter_change_callback_t callback,
86 void IDI_CALL_ENTITY_T* context);
87static void diva_remove_adapter_callback (dword handle);
88static void diva_notify_adapter_change (DESCRIPTOR* d, int removal);
89static diva_os_spin_lock_t didd_spin;
90/* --------------------------------------------------------------------------
91 Should be called as first step, after driver init
92 -------------------------------------------------------------------------- */
93void diva_didd_load_time_init (void) {
94 memset (&HandleTable[0], 0x00, sizeof(HandleTable));
95 memset (&NotificationTable[0], 0x00, sizeof(NotificationTable));
96 diva_os_initialize_spin_lock (&didd_spin, "didd");
97}
98/* --------------------------------------------------------------------------
99 Should be called as last step, if driver does unload
100 -------------------------------------------------------------------------- */
101void diva_didd_load_time_finit (void) {
102 diva_os_destroy_spin_lock (&didd_spin, "didd");
103}
104/* --------------------------------------------------------------------------
105 Called in order to register new adapter in adapter array
106 return adapter handle (> 0) on success
107 return -1 adapter array overflow
108 -------------------------------------------------------------------------- */
109static int diva_didd_add_descriptor (DESCRIPTOR* d) {
110 diva_os_spin_lock_magic_t irql;
111 int i;
112 if (d->type == IDI_DIMAINT) {
113 if (d->request) {
114 MAdapter.request = d->request;
115 dprintf = (DIVA_DI_PRINTF)d->request;
116 diva_notify_adapter_change (&MAdapter, 0); /* Inserted */
117 DBG_TRC (("DIMAINT registered, dprintf=%08x", d->request))
118 } else {
119 DBG_TRC (("DIMAINT removed"))
120 diva_notify_adapter_change (&MAdapter, 1); /* About to remove */
121 MAdapter.request = (IDI_CALL)no_printf;
122 dprintf = no_printf;
123 }
124 return (NEW_MAX_DESCRIPTORS);
125 }
126 for (i = 0; i < NEW_MAX_DESCRIPTORS; i++) {
127 diva_os_enter_spin_lock (&didd_spin, &irql, "didd_add");
128 if (HandleTable[i].type == 0) {
129 memcpy (&HandleTable[i], d, sizeof(*d));
130 Adapters++;
131 diva_os_leave_spin_lock (&didd_spin, &irql, "didd_add");
132 diva_notify_adapter_change (d, 0); /* we have new adapter */
133 DBG_TRC (("Add adapter[%d], request=%08x", (i+1), d->request))
134 return (i+1);
135 }
136 diva_os_leave_spin_lock (&didd_spin, &irql, "didd_add");
137 }
138 DBG_ERR (("Can't add adapter, out of resources"))
139 return (-1);
140}
141/* --------------------------------------------------------------------------
142 Called in order to remove one registered adapter from array
143 return adapter handle (> 0) on success
144 return 0 on success
145 -------------------------------------------------------------------------- */
146static int diva_didd_remove_descriptor (IDI_CALL request) {
147 diva_os_spin_lock_magic_t irql;
148 int i;
149 if (request == MAdapter.request) {
150 DBG_TRC(("DIMAINT removed"))
151 dprintf = no_printf;
152 diva_notify_adapter_change (&MAdapter, 1); /* About to remove */
153 MAdapter.request = (IDI_CALL)no_printf;
154 return (0);
155 }
156 for (i = 0; (Adapters && (i < NEW_MAX_DESCRIPTORS)); i++) {
157 if (HandleTable[i].request == request) {
158 diva_notify_adapter_change (&HandleTable[i], 1); /* About to remove */
159 diva_os_enter_spin_lock (&didd_spin, &irql, "didd_rm");
160 memset (&HandleTable[i], 0x00, sizeof(HandleTable[0]));
161 Adapters--;
162 diva_os_leave_spin_lock (&didd_spin, &irql, "didd_rm");
163 DBG_TRC (("Remove adapter[%d], request=%08x", (i+1), request))
164 return (0);
165 }
166 }
167 DBG_ERR (("Invalid request=%08x, can't remove adapter", request))
168 return (-1);
169}
170/* --------------------------------------------------------------------------
171 Read adapter array
172 return 1 if not enough space to save all available adapters
173 -------------------------------------------------------------------------- */
174static int diva_didd_read_adapter_array (DESCRIPTOR* buffer, int length) {
175 diva_os_spin_lock_magic_t irql;
176 int src, dst;
177 memset (buffer, 0x00, length);
178 length /= sizeof(DESCRIPTOR);
179 DBG_TRC (("DIDD_Read, space = %d, Adapters = %d", length, Adapters+2))
180
181 diva_os_enter_spin_lock (&didd_spin, &irql, "didd_read");
182 for (src = 0, dst = 0;
183 (Adapters && (src < NEW_MAX_DESCRIPTORS) && (dst < length));
184 src++) {
185 if (HandleTable[src].type) {
186 memcpy (&buffer[dst], &HandleTable[src], sizeof(DESCRIPTOR));
187 dst++;
188 }
189 }
190 diva_os_leave_spin_lock (&didd_spin, &irql, "didd_read");
191 if (dst < length) {
192 memcpy (&buffer[dst], &MAdapter, sizeof(DESCRIPTOR));
193 dst++;
194 } else {
195 DBG_ERR (("Can't write DIMAINT. Array too small"))
196 }
197 if (dst < length) {
198 memcpy (&buffer[dst], &DAdapter, sizeof(DESCRIPTOR));
199 dst++;
200 } else {
201 DBG_ERR (("Can't write DADAPTER. Array too small"))
202 }
203 DBG_TRC (("Read %d adapters", dst))
204 return (dst == length);
205}
206/* --------------------------------------------------------------------------
207 DAdapter request function.
208 This function does process only synchronous requests, and is used
209 for reception/registration of new interfaces
210 -------------------------------------------------------------------------- */
211static void IDI_CALL_LINK_T diva_dadapter_request (\
212 ENTITY IDI_CALL_ENTITY_T *e) {
213 IDI_SYNC_REQ *syncReq = (IDI_SYNC_REQ *)e ;
214 if (e->Req) { /* We do not process it, also return error */
215 e->Rc = OUT_OF_RESOURCES;
216 DBG_ERR (("Can't process async request, Req=%02x", e->Req))
217 return;
218 }
219 /*
220 So, we process sync request
221 */
222 switch (e->Rc) {
223 case IDI_SYNC_REQ_DIDD_REGISTER_ADAPTER_NOTIFY: {
224 diva_didd_adapter_notify_t* pinfo = &syncReq->didd_notify.info;
225 pinfo->handle = diva_register_adapter_callback (\
226 (didd_adapter_change_callback_t)pinfo->callback,
227 (void IDI_CALL_ENTITY_T *)pinfo->context);
228 e->Rc = 0xff;
229 } break;
230 case IDI_SYNC_REQ_DIDD_REMOVE_ADAPTER_NOTIFY: {
231 diva_didd_adapter_notify_t* pinfo = &syncReq->didd_notify.info;
232 diva_remove_adapter_callback (pinfo->handle);
233 e->Rc = 0xff;
234 } break;
235 case IDI_SYNC_REQ_DIDD_ADD_ADAPTER: {
236 diva_didd_add_adapter_t* pinfo = &syncReq->didd_add_adapter.info;
237 if (diva_didd_add_descriptor ((DESCRIPTOR*)pinfo->descriptor) < 0) {
238 e->Rc = OUT_OF_RESOURCES;
239 } else {
240 e->Rc = 0xff;
241 }
242 } break;
243 case IDI_SYNC_REQ_DIDD_REMOVE_ADAPTER: {
244 diva_didd_remove_adapter_t* pinfo = &syncReq->didd_remove_adapter.info;
245 if (diva_didd_remove_descriptor ((IDI_CALL)pinfo->p_request) < 0) {
246 e->Rc = OUT_OF_RESOURCES;
247 } else {
248 e->Rc = 0xff;
249 }
250 } break;
251 case IDI_SYNC_REQ_DIDD_READ_ADAPTER_ARRAY: {
252 diva_didd_read_adapter_array_t* pinfo =\
253 &syncReq->didd_read_adapter_array.info;
254 if (diva_didd_read_adapter_array ((DESCRIPTOR*)pinfo->buffer,
255 (int)pinfo->length)) {
256 e->Rc = OUT_OF_RESOURCES;
257 } else {
258 e->Rc = 0xff;
259 }
260 } break;
261 default:
262 DBG_ERR (("Can't process sync request, Req=%02x", e->Rc))
263 e->Rc = OUT_OF_RESOURCES;
264 }
265}
266/* --------------------------------------------------------------------------
267 IDI client does register his notification function
268 -------------------------------------------------------------------------- */
269static dword diva_register_adapter_callback (\
270 didd_adapter_change_callback_t callback,
271 void IDI_CALL_ENTITY_T* context) {
272 diva_os_spin_lock_magic_t irql;
273 dword i;
274
275 for (i = 0; i < DIVA_DIDD_MAX_NOTIFICATIONS; i++) {
276 diva_os_enter_spin_lock (&didd_spin, &irql, "didd_nfy_add");
277 if (!NotificationTable[i].callback) {
278 NotificationTable[i].callback = callback;
279 NotificationTable[i].context = context;
280 diva_os_leave_spin_lock (&didd_spin, &irql, "didd_nfy_add");
281 DBG_TRC(("Register adapter notification[%d]=%08x", i+1, callback))
282 return (i+1);
283 }
284 diva_os_leave_spin_lock (&didd_spin, &irql, "didd_nfy_add");
285 }
286 DBG_ERR (("Can't register adapter notification, overflow"))
287 return (0);
288}
289/* --------------------------------------------------------------------------
290 IDI client does register his notification function
291 -------------------------------------------------------------------------- */
292static void diva_remove_adapter_callback (dword handle) {
293 diva_os_spin_lock_magic_t irql;
294 if (handle && ((--handle) < DIVA_DIDD_MAX_NOTIFICATIONS)) {
295 diva_os_enter_spin_lock (&didd_spin, &irql, "didd_nfy_rm");
296 NotificationTable[handle].callback = NULL;
297 NotificationTable[handle].context = NULL;
298 diva_os_leave_spin_lock (&didd_spin, &irql, "didd_nfy_rm");
299 DBG_TRC(("Remove adapter notification[%d]", (int)(handle+1)))
300 return;
301 }
302 DBG_ERR(("Can't remove adapter notification, handle=%d", handle))
303}
304/* --------------------------------------------------------------------------
305 Notify all client about adapter array change
306 Does suppose following behavior in the client side:
307 Step 1: Redister Notification
308 Step 2: Read Adapter Array
309 -------------------------------------------------------------------------- */
310static void diva_notify_adapter_change (DESCRIPTOR* d, int removal) {
311 int i, do_notify;
312 didd_adapter_change_notification_t nfy;
313 diva_os_spin_lock_magic_t irql;
314 for (i = 0; i < DIVA_DIDD_MAX_NOTIFICATIONS; i++) {
315 do_notify = 0;
316 diva_os_enter_spin_lock (&didd_spin, &irql, "didd_nfy");
317 if (NotificationTable[i].callback) {
318 memcpy (&nfy, &NotificationTable[i], sizeof(nfy));
319 do_notify = 1;
320 }
321 diva_os_leave_spin_lock (&didd_spin, &irql, "didd_nfy");
322 if (do_notify) {
323 (*(nfy.callback))(nfy.context, d, removal);
324 }
325 }
326}
327/* --------------------------------------------------------------------------
328 For all systems, that are linked by Kernel Mode Linker this is ONLY one
329 function thet should be exported by this device driver
330 IDI clients should look for IDI_DADAPTER, and use request function
331 of this adapter (sync request) in order to receive appropriate services:
332 - add new adapter
333 - remove existing adapter
334 - add adapter array notification
335 - remove adapter array notification
336 (read adapter is redundant in this case)
337 INPUT:
338 buffer - pointer to buffer that will receive adapter array
339 length - length (in bytes) of space in buffer
340 OUTPUT:
341 Adapter array will be written to memory described by 'buffer'
342 If the last adapter seen in the returned adapter array is
343 IDI_DADAPTER or if last adapter in array does have type '0', then
344 it was enougth space in buffer to accommodate all available
345 adapter descriptors
346 *NOTE 1 (debug interface):
347 The IDI adapter of type 'IDI_DIMAINT' does register as 'request'
348 famous 'dprintf' function (of type DI_PRINTF, please look
349 include/debuglib.c and include/debuglib.h) for details.
350 So dprintf is not exported from module debug module directly,
351 instead of this IDI_DIMAINT is registered.
352 Module load order will receive in this case:
353 1. DIDD (this file)
354 2. DIMAINT does load and register 'IDI_DIMAINT', at this step
355 DIDD should be able to get 'dprintf', save it, and
356 register with DIDD by means of 'dprintf' function.
357 3. any other driver is loaded and is able to access adapter array
358 and debug interface
359 This approach does allow to load/unload debug interface on demand,
360 and save memory, it it is necessary.
361 -------------------------------------------------------------------------- */
362void IDI_CALL_LINK_T DIVA_DIDD_Read (void IDI_CALL_ENTITY_T * buffer,
363 int length) {
364 diva_didd_read_adapter_array (buffer, length);
365}
366
diff --git a/drivers/isdn/hardware/eicon/dadapter.h b/drivers/isdn/hardware/eicon/dadapter.h
new file mode 100644
index 000000000000..3575ac912e6c
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/dadapter.h
@@ -0,0 +1,34 @@
1
2/*
3 *
4 Copyright (c) Eicon Networks, 2002.
5 *
6 This source file is supplied for the use with
7 Eicon Networks range of DIVA Server Adapters.
8 *
9 Eicon File Revision : 2.1
10 *
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2, or (at your option)
14 any later version.
15 *
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
18 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 See the GNU General Public License for more details.
20 *
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26#ifndef __DIVA_DIDD_DADAPTER_INC__
27#define __DIVA_DIDD_DADAPTER_INC__
28
29void diva_didd_load_time_init (void);
30void diva_didd_load_time_finit (void);
31
32#define NEW_MAX_DESCRIPTORS 64
33
34#endif
diff --git a/drivers/isdn/hardware/eicon/dbgioctl.h b/drivers/isdn/hardware/eicon/dbgioctl.h
new file mode 100644
index 000000000000..0fb6f5e88b60
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/dbgioctl.h
@@ -0,0 +1,198 @@
1
2/*
3 *
4 Copyright (c) Eicon Technology Corporation, 2000.
5 *
6 This source file is supplied for the use with Eicon
7 Technology Corporation's range of DIVA Server Adapters.
8 *
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2, or (at your option)
12 any later version.
13 *
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
16 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 See the GNU General Public License for more details.
18 *
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 *
23 */
24/*------------------------------------------------------------------*/
25/* file: dbgioctl.h */
26/*------------------------------------------------------------------*/
27
28#if !defined(__DBGIOCTL_H__)
29
30#define __DBGIOCTL_H__
31
32#ifdef NOT_YET_NEEDED
33/*
34 * The requested operation is passed in arg0 of DbgIoctlArgs,
35 * additional arguments (if any) in arg1, arg2 and arg3.
36 */
37
38typedef struct
39{ ULONG arg0 ;
40 ULONG arg1 ;
41 ULONG arg2 ;
42 ULONG arg3 ;
43} DbgIoctlArgs ;
44
45#define DBG_COPY_LOGS 0 /* copy debugs to user until buffer full */
46 /* arg1: size threshold */
47 /* arg2: timeout in milliseconds */
48
49#define DBG_FLUSH_LOGS 1 /* flush pending debugs to user buffer */
50 /* arg1: internal driver id */
51
52#define DBG_LIST_DRVS 2 /* return the list of registered drivers */
53
54#define DBG_GET_MASK 3 /* get current debug mask of driver */
55 /* arg1: internal driver id */
56
57#define DBG_SET_MASK 4 /* set/change debug mask of driver */
58 /* arg1: internal driver id */
59 /* arg2: new debug mask */
60
61#define DBG_GET_BUFSIZE 5 /* get current buffer size of driver */
62 /* arg1: internal driver id */
63 /* arg2: new debug mask */
64
65#define DBG_SET_BUFSIZE 6 /* set new buffer size of driver */
66 /* arg1: new buffer size */
67
68/*
69 * common internal debug message structure
70 */
71
72typedef struct
73{ unsigned short id ; /* virtual driver id */
74 unsigned short type ; /* special message type */
75 unsigned long seq ; /* sequence number of message */
76 unsigned long size ; /* size of message in bytes */
77 unsigned long next ; /* offset to next buffered message */
78 LARGE_INTEGER NTtime ; /* 100 ns since 1.1.1601 */
79 unsigned char data[4] ;/* message data */
80} OldDbgMessage ;
81
82typedef struct
83{ LARGE_INTEGER NTtime ; /* 100 ns since 1.1.1601 */
84 unsigned short size ; /* size of message in bytes */
85 unsigned short ffff ; /* always 0xffff to indicate new msg */
86 unsigned short id ; /* virtual driver id */
87 unsigned short type ; /* special message type */
88 unsigned long seq ; /* sequence number of message */
89 unsigned char data[4] ;/* message data */
90} DbgMessage ;
91
92#endif
93
94#define DRV_ID_UNKNOWN 0x0C /* for messages via prtComp() */
95
96#define MSG_PROC_FLAG 0x80
97#define MSG_PROC_NO_GET(x) (((x) & MSG_PROC_FLAG) ? (((x) >> 4) & 7) : -1)
98#define MSG_PROC_NO_SET(x) (MSG_PROC_FLAG | (((x) & 7) << 4))
99
100#define MSG_TYPE_DRV_ID 0x0001
101#define MSG_TYPE_FLAGS 0x0002
102#define MSG_TYPE_STRING 0x0003
103#define MSG_TYPE_BINARY 0x0004
104
105#define MSG_HEAD_SIZE ((unsigned long)&(((DbgMessage *)0)->data[0]))
106#define MSG_ALIGN(len) (((unsigned long)(len) + MSG_HEAD_SIZE + 3) & ~3)
107#define MSG_SIZE(pMsg) MSG_ALIGN((pMsg)->size)
108#define MSG_NEXT(pMsg) ((DbgMessage *)( ((char *)(pMsg)) + MSG_SIZE(pMsg) ))
109
110#define OLD_MSG_HEAD_SIZE ((unsigned long)&(((OldDbgMessage *)0)->data[0]))
111#define OLD_MSG_ALIGN(len) (((unsigned long)(len)+OLD_MSG_HEAD_SIZE+3) & ~3)
112
113/*
114 * manifest constants
115 */
116
117#define MSG_FRAME_MAX_SIZE 2150 /* maximum size of B1 frame */
118#define MSG_TEXT_MAX_SIZE 1024 /* maximum size of msg text */
119#define MSG_MAX_SIZE MSG_ALIGN(MSG_FRAME_MAX_SIZE)
120#define DBG_MIN_BUFFER_SIZE 0x00008000 /* minimal total buffer size 32 KB */
121#define DBG_DEF_BUFFER_SIZE 0x00020000 /* default total buffer size 128 KB */
122#define DBG_MAX_BUFFER_SIZE 0x00400000 /* maximal total buffer size 4 MB */
123
124#define DBGDRV_NAME "Diehl_DIMAINT"
125#define UNIDBG_DRIVER L"\\Device\\Diehl_DIMAINT" /* UNICODE name for kernel */
126#define DEBUG_DRIVER "\\\\.\\" DBGDRV_NAME /* traditional string for apps */
127#define DBGVXD_NAME "DIMAINT"
128#define DEBUG_VXD "\\\\.\\" DBGVXD_NAME /* traditional string for apps */
129
130/*
131 * Special IDI interface debug construction
132 */
133
134#define DBG_IDI_SIG_REQ (unsigned long)0xF479C402
135#define DBG_IDI_SIG_IND (unsigned long)0xF479C403
136#define DBG_IDI_NL_REQ (unsigned long)0xF479C404
137#define DBG_IDI_NL_IND (unsigned long)0xF479C405
138
139typedef struct
140{ unsigned long magic_type ;
141 unsigned short data_len ;
142 unsigned char layer_ID ;
143 unsigned char entity_ID ;
144 unsigned char request ;
145 unsigned char ret_code ;
146 unsigned char indication ;
147 unsigned char complete ;
148 unsigned char data[4] ;
149} DbgIdiAct, *DbgIdiAction ;
150
151/*
152 * We want to use the same IOCTL codes in Win95 and WinNT.
153 * The official constructor for IOCTL codes is the CTL_CODE macro
154 * from <winoctl.h> (<devioctl.h> in WinNT DDK environment).
155 * The problem here is that we don't know how to get <winioctl.h>
156 * working in a Win95 DDK environment!
157 */
158
159# ifdef CTL_CODE /*{*/
160
161/* Assert that we have the same idea of the CTL_CODE macro. */
162
163#define CTL_CODE( DeviceType, Function, Method, Access ) ( \
164 ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \
165)
166
167# else /* !CTL_CODE */ /*}{*/
168
169/* Use the definitions stolen from <winioctl.h>. */
170
171#define CTL_CODE( DeviceType, Function, Method, Access ) ( \
172 ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \
173)
174
175#define METHOD_BUFFERED 0
176#define METHOD_IN_DIRECT 1
177#define METHOD_OUT_DIRECT 2
178#define METHOD_NEITHER 3
179
180#define FILE_ANY_ACCESS 0
181#define FILE_READ_ACCESS ( 0x0001 ) // file & pipe
182#define FILE_WRITE_ACCESS ( 0x0002 ) // file & pipe
183
184# endif /* CTL_CODE */ /*}*/
185
186/*
187 * Now we can define WinNT/Win95 DeviceIoControl codes.
188 *
189 * These codes are defined in di_defs.h too, a possible mismatch will be
190 * detected when the dbgtool is compiled.
191 */
192
193#define IOCTL_DRIVER_LNK \
194 CTL_CODE(0x8001U,0x701,METHOD_OUT_DIRECT,FILE_ANY_ACCESS)
195#define IOCTL_DRIVER_DBG \
196 CTL_CODE(0x8001U,0x702,METHOD_OUT_DIRECT,FILE_ANY_ACCESS)
197
198#endif /* __DBGIOCTL_H__ */
diff --git a/drivers/isdn/hardware/eicon/debug.c b/drivers/isdn/hardware/eicon/debug.c
new file mode 100644
index 000000000000..6851c6270ce8
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/debug.c
@@ -0,0 +1,2133 @@
1#include "platform.h"
2#include "pc.h"
3#include "di_defs.h"
4#include "debug_if.h"
5#include "divasync.h"
6#include "kst_ifc.h"
7#include "maintidi.h"
8#include "man_defs.h"
9
10/*
11 LOCALS
12 */
13#define DBG_MAGIC (0x47114711L)
14
15static void DI_register (void *arg);
16static void DI_deregister (pDbgHandle hDbg);
17static void DI_format (int do_lock, word id, int type, char *format, va_list argument_list);
18static void DI_format_locked (word id, int type, char *format, va_list argument_list);
19static void DI_format_old (word id, char *format, va_list ap) { }
20static void DiProcessEventLog (unsigned short id, unsigned long msgID, va_list ap) { }
21static void single_p (byte * P, word * PLength, byte Id);
22static void diva_maint_xdi_cb (ENTITY* e);
23static word SuperTraceCreateReadReq (byte* P, const char* path);
24static int diva_mnt_cmp_nmbr (const char* nmbr);
25static void diva_free_dma_descriptor (IDI_CALL request, int nr);
26static int diva_get_dma_descriptor (IDI_CALL request, dword *dma_magic);
27void diva_mnt_internal_dprintf (dword drv_id, dword type, char* p, ...);
28
29static dword MaxDumpSize = 256 ;
30static dword MaxXlogSize = 2 + 128 ;
31static char TraceFilter[DIVA_MAX_SELECTIVE_FILTER_LENGTH+1];
32static int TraceFilterIdent = -1;
33static int TraceFilterChannel = -1;
34
35typedef struct _diva_maint_client {
36 dword sec;
37 dword usec;
38 pDbgHandle hDbg;
39 char drvName[128];
40 dword dbgMask;
41 dword last_dbgMask;
42 IDI_CALL request;
43 _DbgHandle_ Dbg;
44 int logical;
45 int channels;
46 diva_strace_library_interface_t* pIdiLib;
47 BUFFERS XData;
48 char xbuffer[2048+512];
49 byte* pmem;
50 int request_pending;
51 int dma_handle;
52} diva_maint_client_t;
53static diva_maint_client_t clients[MAX_DESCRIPTORS];
54
55static void diva_change_management_debug_mask (diva_maint_client_t* pC, dword old_mask);
56
57static void diva_maint_error (void* user_context,
58 diva_strace_library_interface_t* hLib,
59 int Adapter,
60 int error,
61 const char* file,
62 int line);
63static void diva_maint_state_change_notify (void* user_context,
64 diva_strace_library_interface_t* hLib,
65 int Adapter,
66 diva_trace_line_state_t* channel,
67 int notify_subject);
68static void diva_maint_trace_notify (void* user_context,
69 diva_strace_library_interface_t* hLib,
70 int Adapter,
71 void* xlog_buffer,
72 int length);
73
74
75
76typedef struct MSG_QUEUE {
77 dword Size; /* total size of queue (constant) */
78 byte *Base; /* lowest address (constant) */
79 byte *High; /* Base + Size (constant) */
80 byte *Head; /* first message in queue (if any) */
81 byte *Tail; /* first free position */
82 byte *Wrap; /* current wraparound position */
83 dword Count; /* current no of bytes in queue */
84} MSG_QUEUE;
85
86typedef struct MSG_HEAD {
87 volatile dword Size; /* size of data following MSG_HEAD */
88#define MSG_INCOMPLETE 0x8000 /* ored to Size until queueCompleteMsg */
89} MSG_HEAD;
90
91#define queueCompleteMsg(p) do{ ((MSG_HEAD *)p - 1)->Size &= ~MSG_INCOMPLETE; }while(0)
92#define queueCount(q) ((q)->Count)
93#define MSG_NEED(size) \
94 ( (sizeof(MSG_HEAD) + size + sizeof(dword) - 1) & ~(sizeof(dword) - 1) )
95
96static void queueInit (MSG_QUEUE *Q, byte *Buffer, dword sizeBuffer) {
97 Q->Size = sizeBuffer;
98 Q->Base = Q->Head = Q->Tail = Buffer;
99 Q->High = Buffer + sizeBuffer;
100 Q->Wrap = NULL;
101 Q->Count= 0;
102}
103
104static byte *queueAllocMsg (MSG_QUEUE *Q, word size) {
105 /* Allocate 'size' bytes at tail of queue which will be filled later
106 * directly with callers own message header info and/or message.
107 * An 'alloced' message is marked incomplete by oring the 'Size' field
108 * with MSG_INCOMPLETE.
109 * This must be reset via queueCompleteMsg() after the message is filled.
110 * As long as a message is marked incomplete queuePeekMsg() will return
111 * a 'queue empty' condition when it reaches such a message. */
112
113 MSG_HEAD *Msg;
114 word need = MSG_NEED(size);
115
116 if (Q->Tail == Q->Head) {
117 if (Q->Wrap || need > Q->Size) {
118 return NULL; /* full */
119 }
120 goto alloc; /* empty */
121 }
122
123 if (Q->Tail > Q->Head) {
124 if (Q->Tail + need <= Q->High) goto alloc; /* append */
125 if (Q->Base + need > Q->Head) {
126 return NULL; /* too much */
127 }
128 /* wraparound the queue (but not the message) */
129 Q->Wrap = Q->Tail;
130 Q->Tail = Q->Base;
131 goto alloc;
132 }
133
134 if (Q->Tail + need > Q->Head) {
135 return NULL; /* too much */
136 }
137
138alloc:
139 Msg = (MSG_HEAD *)Q->Tail;
140
141 Msg->Size = size | MSG_INCOMPLETE;
142
143 Q->Tail += need;
144 Q->Count += size;
145
146
147
148 return ((byte*)(Msg + 1));
149}
150
151static void queueFreeMsg (MSG_QUEUE *Q) {
152/* Free the message at head of queue */
153
154 word size = ((MSG_HEAD *)Q->Head)->Size & ~MSG_INCOMPLETE;
155
156 Q->Head += MSG_NEED(size);
157 Q->Count -= size;
158
159 if (Q->Wrap) {
160 if (Q->Head >= Q->Wrap) {
161 Q->Head = Q->Base;
162 Q->Wrap = NULL;
163 }
164 } else if (Q->Head >= Q->Tail) {
165 Q->Head = Q->Tail = Q->Base;
166 }
167}
168
169static byte *queuePeekMsg (MSG_QUEUE *Q, word *size) {
170 /* Show the first valid message in queue BUT DON'T free the message.
171 * After looking on the message contents it can be freed queueFreeMsg()
172 * or simply remain in message queue. */
173
174 MSG_HEAD *Msg = (MSG_HEAD *)Q->Head;
175
176 if (((byte *)Msg == Q->Tail && !Q->Wrap) ||
177 (Msg->Size & MSG_INCOMPLETE)) {
178 return NULL;
179 } else {
180 *size = Msg->Size;
181 return ((byte *)(Msg + 1));
182 }
183}
184
185/*
186 Message queue header
187 */
188static MSG_QUEUE* dbg_queue;
189static byte* dbg_base;
190static int external_dbg_queue;
191static diva_os_spin_lock_t dbg_q_lock;
192static diva_os_spin_lock_t dbg_adapter_lock;
193static int dbg_q_busy;
194static volatile dword dbg_sequence;
195static dword start_sec;
196static dword start_usec;
197
198/*
199 INTERFACE:
200 Initialize run time queue structures.
201 base: base of the message queue
202 length: length of the message queue
203 do_init: perfor queue reset
204
205 return: zero on success, -1 on error
206 */
207int diva_maint_init (byte* base, unsigned long length, int do_init) {
208 if (dbg_queue || (!base) || (length < (4096*4))) {
209 return (-1);
210 }
211
212 TraceFilter[0] = 0;
213 TraceFilterIdent = -1;
214 TraceFilterChannel = -1;
215
216 dbg_base = base;
217
218 diva_os_get_time (&start_sec, &start_usec);
219
220 *(dword*)base = (dword)DBG_MAGIC; /* Store Magic */
221 base += sizeof(dword);
222 length -= sizeof(dword);
223
224 *(dword*)base = 2048; /* Extension Field Length */
225 base += sizeof(dword);
226 length -= sizeof(dword);
227
228 strcpy (base, "KERNEL MODE BUFFER\n");
229 base += 2048;
230 length -= 2048;
231
232 *(dword*)base = 0; /* Terminate extension */
233 base += sizeof(dword);
234 length -= sizeof(dword);
235
236 *(void**)base = (void*)(base+sizeof(void*)); /* Store Base */
237 base += sizeof(void*);
238 length -= sizeof(void*);
239
240 dbg_queue = (MSG_QUEUE*)base;
241 queueInit (dbg_queue, base + sizeof(MSG_QUEUE), length - sizeof(MSG_QUEUE) - 512);
242 external_dbg_queue = 0;
243
244 if (!do_init) {
245 external_dbg_queue = 1; /* memory was located on the external device */
246 }
247
248
249 if (diva_os_initialize_spin_lock (&dbg_q_lock, "dbg_init")) {
250 dbg_queue = NULL;
251 dbg_base = NULL;
252 external_dbg_queue = 0;
253 return (-1);
254 }
255
256 if (diva_os_initialize_spin_lock (&dbg_adapter_lock, "dbg_init")) {
257 diva_os_destroy_spin_lock(&dbg_q_lock, "dbg_init");
258 dbg_queue = NULL;
259 dbg_base = NULL;
260 external_dbg_queue = 0;
261 return (-1);
262 }
263
264 return (0);
265}
266
267/*
268 INTERFACE:
269 Finit at unload time
270 return address of internal queue or zero if queue
271 was external
272 */
273void* diva_maint_finit (void) {
274 void* ret = (void*)dbg_base;
275 int i;
276
277 dbg_queue = NULL;
278 dbg_base = NULL;
279
280 if (ret) {
281 diva_os_destroy_spin_lock(&dbg_q_lock, "dbg_finit");
282 diva_os_destroy_spin_lock(&dbg_adapter_lock, "dbg_finit");
283 }
284
285 if (external_dbg_queue) {
286 ret = NULL;
287 }
288 external_dbg_queue = 0;
289
290 for (i = 1; i < (sizeof(clients)/sizeof(clients[0])); i++) {
291 if (clients[i].pmem) {
292 diva_os_free (0, clients[i].pmem);
293 }
294 }
295
296 return (ret);
297}
298
299/*
300 INTERFACE:
301 Return amount of messages in debug queue
302 */
303dword diva_dbg_q_length (void) {
304 return (dbg_queue ? queueCount(dbg_queue) : 0);
305}
306
307/*
308 INTERFACE:
309 Lock message queue and return the pointer to the first
310 entry.
311 */
312diva_dbg_entry_head_t* diva_maint_get_message (word* size,
313 diva_os_spin_lock_magic_t* old_irql) {
314 diva_dbg_entry_head_t* pmsg = NULL;
315
316 diva_os_enter_spin_lock (&dbg_q_lock, old_irql, "read");
317 if (dbg_q_busy) {
318 diva_os_leave_spin_lock (&dbg_q_lock, old_irql, "read_busy");
319 return NULL;
320 }
321 dbg_q_busy = 1;
322
323 if (!(pmsg = (diva_dbg_entry_head_t*)queuePeekMsg (dbg_queue, size))) {
324 dbg_q_busy = 0;
325 diva_os_leave_spin_lock (&dbg_q_lock, old_irql, "read_empty");
326 }
327
328 return (pmsg);
329}
330
331/*
332 INTERFACE:
333 acknowledge last message and unlock queue
334 */
335void diva_maint_ack_message (int do_release,
336 diva_os_spin_lock_magic_t* old_irql) {
337 if (!dbg_q_busy) {
338 return;
339 }
340 if (do_release) {
341 queueFreeMsg (dbg_queue);
342 }
343 dbg_q_busy = 0;
344 diva_os_leave_spin_lock (&dbg_q_lock, old_irql, "read_ack");
345}
346
347
348/*
349 INTERFACE:
350 PRT COMP function used to register
351 with MAINT adapter or log in compatibility
352 mode in case older driver version is connected too
353 */
354void diva_maint_prtComp (char *format, ...) {
355 void *hDbg;
356 va_list ap;
357
358 if (!format)
359 return;
360
361 va_start(ap, format);
362
363 /*
364 register to new log driver functions
365 */
366 if ((format[0] == 0) && ((unsigned char)format[1] == 255)) {
367 hDbg = va_arg(ap, void *); /* ptr to DbgHandle */
368 DI_register (hDbg);
369 }
370
371 va_end (ap);
372}
373
374static void DI_register (void *arg) {
375 diva_os_spin_lock_magic_t old_irql;
376 dword sec, usec;
377 pDbgHandle hDbg ;
378 int id, free_id = -1, best_id = 0;
379
380 diva_os_get_time (&sec, &usec);
381
382 hDbg = (pDbgHandle)arg ;
383 /*
384 Check for bad args, specially for the old obsolete debug handle
385 */
386 if ((hDbg == NULL) ||
387 ((hDbg->id == 0) && (((_OldDbgHandle_ *)hDbg)->id == -1)) ||
388 (hDbg->Registered != 0)) {
389 return ;
390 }
391
392 diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "register");
393
394 for (id = 1; id < (sizeof(clients)/sizeof(clients[0])); id++) {
395 if (clients[id].hDbg == hDbg) {
396 /*
397 driver already registered
398 */
399 diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "register");
400 return;
401 }
402 if (clients[id].hDbg) { /* slot is busy */
403 continue;
404 }
405 free_id = id;
406 if (!strcmp (clients[id].drvName, hDbg->drvName)) {
407 /*
408 This driver was already registered with this name
409 and slot is still free - reuse it
410 */
411 best_id = 1;
412 break;
413 }
414 if (!clients[id].hDbg) { /* slot is busy */
415 break;
416 }
417 }
418
419 if (free_id != -1) {
420 diva_dbg_entry_head_t* pmsg = NULL;
421 int len;
422 char tmp[256];
423 word size;
424
425 /*
426 Register new driver with id == free_id
427 */
428 clients[free_id].hDbg = hDbg;
429 clients[free_id].sec = sec;
430 clients[free_id].usec = usec;
431 strcpy (clients[free_id].drvName, hDbg->drvName);
432
433 clients[free_id].dbgMask = hDbg->dbgMask;
434 if (best_id) {
435 hDbg->dbgMask |= clients[free_id].last_dbgMask;
436 } else {
437 clients[free_id].last_dbgMask = 0;
438 }
439
440 hDbg->Registered = DBG_HANDLE_REG_NEW ;
441 hDbg->id = (byte)free_id;
442 hDbg->dbg_end = DI_deregister;
443 hDbg->dbg_prt = DI_format_locked;
444 hDbg->dbg_ev = DiProcessEventLog;
445 hDbg->dbg_irq = DI_format_locked;
446 if (hDbg->Version > 0) {
447 hDbg->dbg_old = DI_format_old;
448 }
449 hDbg->next = (pDbgHandle)DBG_MAGIC;
450
451 /*
452 Log driver register, MAINT driver ID is '0'
453 */
454 len = sprintf (tmp, "DIMAINT - drv # %d = '%s' registered",
455 free_id, hDbg->drvName);
456
457 while (!(pmsg = (diva_dbg_entry_head_t*)queueAllocMsg (dbg_queue,
458 (word)(len+1+sizeof(*pmsg))))) {
459 if ((pmsg = (diva_dbg_entry_head_t*)queuePeekMsg (dbg_queue, &size))) {
460 queueFreeMsg (dbg_queue);
461 } else {
462 break;
463 }
464 }
465
466 if (pmsg) {
467 pmsg->sequence = dbg_sequence++;
468 pmsg->time_sec = sec;
469 pmsg->time_usec = usec;
470 pmsg->facility = MSG_TYPE_STRING;
471 pmsg->dli = DLI_REG;
472 pmsg->drv_id = 0; /* id 0 - DIMAINT */
473 pmsg->di_cpu = 0;
474 pmsg->data_length = len+1;
475
476 memcpy (&pmsg[1], tmp, len+1);
477 queueCompleteMsg (pmsg);
478 diva_maint_wakeup_read();
479 }
480 }
481
482 diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "register");
483}
484
485static void DI_deregister (pDbgHandle hDbg) {
486 diva_os_spin_lock_magic_t old_irql, old_irql1;
487 dword sec, usec;
488 int i;
489 word size;
490 byte* pmem = NULL;
491
492 diva_os_get_time (&sec, &usec);
493
494 diva_os_enter_spin_lock (&dbg_adapter_lock, &old_irql1, "read");
495 diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "read");
496
497 for (i = 1; i < (sizeof(clients)/sizeof(clients[0])); i++) {
498 if (clients[i].hDbg == hDbg) {
499 diva_dbg_entry_head_t* pmsg;
500 char tmp[256];
501 int len;
502
503 clients[i].hDbg = NULL;
504
505 hDbg->id = -1;
506 hDbg->dbgMask = 0;
507 hDbg->dbg_end = NULL;
508 hDbg->dbg_prt = NULL;
509 hDbg->dbg_irq = NULL;
510 if (hDbg->Version > 0)
511 hDbg->dbg_old = NULL;
512 hDbg->Registered = 0;
513 hDbg->next = NULL;
514
515 if (clients[i].pIdiLib) {
516 (*(clients[i].pIdiLib->DivaSTraceLibraryFinit))(clients[i].pIdiLib->hLib);
517 clients[i].pIdiLib = NULL;
518
519 pmem = clients[i].pmem;
520 clients[i].pmem = NULL;
521 }
522
523 /*
524 Log driver register, MAINT driver ID is '0'
525 */
526 len = sprintf (tmp, "DIMAINT - drv # %d = '%s' de-registered",
527 i, hDbg->drvName);
528
529 while (!(pmsg = (diva_dbg_entry_head_t*)queueAllocMsg (dbg_queue,
530 (word)(len+1+sizeof(*pmsg))))) {
531 if ((pmsg = (diva_dbg_entry_head_t*)queuePeekMsg (dbg_queue, &size))) {
532 queueFreeMsg (dbg_queue);
533 } else {
534 break;
535 }
536 }
537
538 if (pmsg) {
539 pmsg->sequence = dbg_sequence++;
540 pmsg->time_sec = sec;
541 pmsg->time_usec = usec;
542 pmsg->facility = MSG_TYPE_STRING;
543 pmsg->dli = DLI_REG;
544 pmsg->drv_id = 0; /* id 0 - DIMAINT */
545 pmsg->di_cpu = 0;
546 pmsg->data_length = len+1;
547
548 memcpy (&pmsg[1], tmp, len+1);
549 queueCompleteMsg (pmsg);
550 diva_maint_wakeup_read();
551 }
552
553 break;
554 }
555 }
556
557 diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "read_ack");
558 diva_os_leave_spin_lock (&dbg_adapter_lock, &old_irql1, "read_ack");
559
560 if (pmem) {
561 diva_os_free (0, pmem);
562 }
563}
564
565static void DI_format_locked (unsigned short id,
566 int type,
567 char *format,
568 va_list argument_list) {
569 DI_format (1, id, type, format, argument_list);
570}
571
572static void DI_format (int do_lock,
573 unsigned short id,
574 int type,
575 char *format,
576 va_list ap) {
577 diva_os_spin_lock_magic_t old_irql;
578 dword sec, usec;
579 diva_dbg_entry_head_t* pmsg = NULL;
580 dword length;
581 word size;
582 static char fmtBuf[MSG_FRAME_MAX_SIZE+sizeof(*pmsg)+1];
583 char *data;
584 unsigned short code;
585
586 if (diva_os_in_irq()) {
587 dbg_sequence++;
588 return;
589 }
590
591 if ((!format) ||
592 ((TraceFilter[0] != 0) && ((TraceFilterIdent < 0) || (TraceFilterChannel < 0)))) {
593 return;
594 }
595
596
597
598 diva_os_get_time (&sec, &usec);
599
600 if (do_lock) {
601 diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "format");
602 }
603
604 switch (type) {
605 case DLI_MXLOG :
606 case DLI_BLK :
607 case DLI_SEND:
608 case DLI_RECV:
609 if (!(length = va_arg(ap, unsigned long))) {
610 break;
611 }
612 if (length > MaxDumpSize) {
613 length = MaxDumpSize;
614 }
615 while (!(pmsg = (diva_dbg_entry_head_t*)queueAllocMsg (dbg_queue,
616 (word)length+sizeof(*pmsg)))) {
617 if ((pmsg = (diva_dbg_entry_head_t*)queuePeekMsg (dbg_queue, &size))) {
618 queueFreeMsg (dbg_queue);
619 } else {
620 break;
621 }
622 }
623 if (pmsg) {
624 memcpy (&pmsg[1], format, length);
625 pmsg->sequence = dbg_sequence++;
626 pmsg->time_sec = sec;
627 pmsg->time_usec = usec;
628 pmsg->facility = MSG_TYPE_BINARY ;
629 pmsg->dli = type; /* DLI_XXX */
630 pmsg->drv_id = id; /* driver MAINT id */
631 pmsg->di_cpu = 0;
632 pmsg->data_length = length;
633 queueCompleteMsg (pmsg);
634 }
635 break;
636
637 case DLI_XLOG: {
638 byte* p;
639 data = va_arg(ap, char*);
640 code = (unsigned short)va_arg(ap, unsigned int);
641 length = (unsigned long) va_arg(ap, unsigned int);
642
643 if (length > MaxXlogSize)
644 length = MaxXlogSize;
645
646 while (!(pmsg = (diva_dbg_entry_head_t*)queueAllocMsg (dbg_queue,
647 (word)length+sizeof(*pmsg)+2))) {
648 if ((pmsg = (diva_dbg_entry_head_t*)queuePeekMsg (dbg_queue, &size))) {
649 queueFreeMsg (dbg_queue);
650 } else {
651 break;
652 }
653 }
654 if (pmsg) {
655 p = (byte*)&pmsg[1];
656 p[0] = (char)(code) ;
657 p[1] = (char)(code >> 8) ;
658 if (data && length) {
659 memcpy (&p[2], &data[0], length) ;
660 }
661 length += 2 ;
662
663 pmsg->sequence = dbg_sequence++;
664 pmsg->time_sec = sec;
665 pmsg->time_usec = usec;
666 pmsg->facility = MSG_TYPE_BINARY ;
667 pmsg->dli = type; /* DLI_XXX */
668 pmsg->drv_id = id; /* driver MAINT id */
669 pmsg->di_cpu = 0;
670 pmsg->data_length = length;
671 queueCompleteMsg (pmsg);
672 }
673 } break;
674
675 case DLI_LOG :
676 case DLI_FTL :
677 case DLI_ERR :
678 case DLI_TRC :
679 case DLI_REG :
680 case DLI_MEM :
681 case DLI_SPL :
682 case DLI_IRP :
683 case DLI_TIM :
684 case DLI_TAPI:
685 case DLI_NDIS:
686 case DLI_CONN:
687 case DLI_STAT:
688 case DLI_PRV0:
689 case DLI_PRV1:
690 case DLI_PRV2:
691 case DLI_PRV3:
692 if ((length = (unsigned long)vsprintf (&fmtBuf[0], format, ap)) > 0) {
693 length += (sizeof(*pmsg)+1);
694
695 while (!(pmsg = (diva_dbg_entry_head_t*)queueAllocMsg (dbg_queue,
696 (word)length))) {
697 if ((pmsg = (diva_dbg_entry_head_t*)queuePeekMsg (dbg_queue, &size))) {
698 queueFreeMsg (dbg_queue);
699 } else {
700 break;
701 }
702 }
703
704 pmsg->sequence = dbg_sequence++;
705 pmsg->time_sec = sec;
706 pmsg->time_usec = usec;
707 pmsg->facility = MSG_TYPE_STRING;
708 pmsg->dli = type; /* DLI_XXX */
709 pmsg->drv_id = id; /* driver MAINT id */
710 pmsg->di_cpu = 0;
711 pmsg->data_length = length - sizeof(*pmsg);
712
713 memcpy (&pmsg[1], fmtBuf, pmsg->data_length);
714 queueCompleteMsg (pmsg);
715 }
716 break;
717
718 } /* switch type */
719
720
721 if (queueCount(dbg_queue)) {
722 diva_maint_wakeup_read();
723 }
724
725 if (do_lock) {
726 diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "format");
727 }
728}
729
730/*
731 Write driver ID and driver revision to callers buffer
732 */
733int diva_get_driver_info (dword id, byte* data, int data_length) {
734 diva_os_spin_lock_magic_t old_irql;
735 byte* p = data;
736 int to_copy;
737
738 if (!data || !id || (data_length < 17) ||
739 (id >= (sizeof(clients)/sizeof(clients[0])))) {
740 return (-1);
741 }
742
743 diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "driver info");
744
745 if (clients[id].hDbg) {
746 *p++ = 1;
747 *p++ = (byte)clients[id].sec; /* save seconds */
748 *p++ = (byte)(clients[id].sec >> 8);
749 *p++ = (byte)(clients[id].sec >> 16);
750 *p++ = (byte)(clients[id].sec >> 24);
751
752 *p++ = (byte)(clients[id].usec/1000); /* save mseconds */
753 *p++ = (byte)((clients[id].usec/1000) >> 8);
754 *p++ = (byte)((clients[id].usec/1000) >> 16);
755 *p++ = (byte)((clients[id].usec/1000) >> 24);
756
757 data_length -= 9;
758
759 if ((to_copy = MIN(strlen(clients[id].drvName), data_length-1))) {
760 memcpy (p, clients[id].drvName, to_copy);
761 p += to_copy;
762 data_length -= to_copy;
763 if ((data_length >= 4) && clients[id].hDbg->drvTag[0]) {
764 *p++ = '(';
765 data_length -= 1;
766 if ((to_copy = MIN(strlen(clients[id].hDbg->drvTag), data_length-2))) {
767 memcpy (p, clients[id].hDbg->drvTag, to_copy);
768 p += to_copy;
769 data_length -= to_copy;
770 if (data_length >= 2) {
771 *p++ = ')';
772 data_length--;
773 }
774 }
775 }
776 }
777 }
778 *p++ = 0;
779
780 diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "driver info");
781
782 return (p - data);
783}
784
785int diva_get_driver_dbg_mask (dword id, byte* data) {
786 diva_os_spin_lock_magic_t old_irql;
787 int ret = -1;
788
789 if (!data || !id || (id >= (sizeof(clients)/sizeof(clients[0])))) {
790 return (-1);
791 }
792 diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "driver info");
793
794 if (clients[id].hDbg) {
795 ret = 4;
796 *data++= (byte)(clients[id].hDbg->dbgMask);
797 *data++= (byte)(clients[id].hDbg->dbgMask >> 8);
798 *data++= (byte)(clients[id].hDbg->dbgMask >> 16);
799 *data++= (byte)(clients[id].hDbg->dbgMask >> 24);
800 }
801
802 diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "driver info");
803
804 return (ret);
805}
806
807int diva_set_driver_dbg_mask (dword id, dword mask) {
808 diva_os_spin_lock_magic_t old_irql, old_irql1;
809 int ret = -1;
810
811
812 if (!id || (id >= (sizeof(clients)/sizeof(clients[0])))) {
813 return (-1);
814 }
815
816 diva_os_enter_spin_lock (&dbg_adapter_lock, &old_irql1, "dbg mask");
817 diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "dbg mask");
818
819 if (clients[id].hDbg) {
820 dword old_mask = clients[id].hDbg->dbgMask;
821 mask &= 0x7fffffff;
822 clients[id].hDbg->dbgMask = mask;
823 clients[id].last_dbgMask = (clients[id].hDbg->dbgMask | clients[id].dbgMask);
824 ret = 4;
825 diva_change_management_debug_mask (&clients[id], old_mask);
826 }
827
828
829 diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "dbg mask");
830
831 if (clients[id].request_pending) {
832 clients[id].request_pending = 0;
833 (*(clients[id].request))((ENTITY*)(*(clients[id].pIdiLib->DivaSTraceGetHandle))(clients[id].pIdiLib->hLib));
834 }
835
836 diva_os_leave_spin_lock (&dbg_adapter_lock, &old_irql1, "dbg mask");
837
838 return (ret);
839}
840
841static int diva_get_idi_adapter_info (IDI_CALL request, dword* serial, dword* logical) {
842 IDI_SYNC_REQ sync_req;
843
844 sync_req.xdi_logical_adapter_number.Req = 0;
845 sync_req.xdi_logical_adapter_number.Rc = IDI_SYNC_REQ_XDI_GET_LOGICAL_ADAPTER_NUMBER;
846 (*request)((ENTITY *)&sync_req);
847 *logical = sync_req.xdi_logical_adapter_number.info.logical_adapter_number;
848
849 sync_req.GetSerial.Req = 0;
850 sync_req.GetSerial.Rc = IDI_SYNC_REQ_GET_SERIAL;
851 sync_req.GetSerial.serial = 0;
852 (*request)((ENTITY *)&sync_req);
853 *serial = sync_req.GetSerial.serial;
854
855 return (0);
856}
857
858/*
859 Register XDI adapter as MAINT compatible driver
860 */
861void diva_mnt_add_xdi_adapter (const DESCRIPTOR* d) {
862 diva_os_spin_lock_magic_t old_irql, old_irql1;
863 dword sec, usec, logical, serial, org_mask;
864 int id, best_id = 0, free_id = -1;
865 char tmp[256];
866 diva_dbg_entry_head_t* pmsg = NULL;
867 int len;
868 word size;
869 byte* pmem;
870
871 diva_os_get_time (&sec, &usec);
872 diva_get_idi_adapter_info (d->request, &serial, &logical);
873 if (serial & 0xff000000) {
874 sprintf (tmp, "ADAPTER:%d SN:%u-%d",
875 (int)logical,
876 serial & 0x00ffffff,
877 (byte)(((serial & 0xff000000) >> 24) + 1));
878 } else {
879 sprintf (tmp, "ADAPTER:%d SN:%u", (int)logical, serial);
880 }
881
882 if (!(pmem = diva_os_malloc (0, DivaSTraceGetMemotyRequirement (d->channels)))) {
883 return;
884 }
885 memset (pmem, 0x00, DivaSTraceGetMemotyRequirement (d->channels));
886
887 diva_os_enter_spin_lock (&dbg_adapter_lock, &old_irql1, "register");
888 diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "register");
889
890 for (id = 1; id < (sizeof(clients)/sizeof(clients[0])); id++) {
891 if (clients[id].hDbg && (clients[id].request == d->request)) {
892 diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "register");
893 diva_os_leave_spin_lock (&dbg_adapter_lock, &old_irql1, "register");
894 diva_os_free(0, pmem);
895 return;
896 }
897 if (clients[id].hDbg) { /* slot is busy */
898 continue;
899 }
900 if (free_id < 0) {
901 free_id = id;
902 }
903 if (!strcmp (clients[id].drvName, tmp)) {
904 /*
905 This driver was already registered with this name
906 and slot is still free - reuse it
907 */
908 free_id = id;
909 best_id = 1;
910 break;
911 }
912 }
913
914 if (free_id < 0) {
915 diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "register");
916 diva_os_leave_spin_lock (&dbg_adapter_lock, &old_irql1, "register");
917 diva_os_free (0, pmem);
918 return;
919 }
920
921 id = free_id;
922 clients[id].request = d->request;
923 clients[id].request_pending = 0;
924 clients[id].hDbg = &clients[id].Dbg;
925 clients[id].sec = sec;
926 clients[id].usec = usec;
927 strcpy (clients[id].drvName, tmp);
928 strcpy (clients[id].Dbg.drvName, tmp);
929 clients[id].Dbg.drvTag[0] = 0;
930 clients[id].logical = (int)logical;
931 clients[id].channels = (int)d->channels;
932 clients[id].dma_handle = -1;
933
934 clients[id].Dbg.dbgMask = 0;
935 clients[id].dbgMask = clients[id].Dbg.dbgMask;
936 if (id) {
937 clients[id].Dbg.dbgMask |= clients[free_id].last_dbgMask;
938 } else {
939 clients[id].last_dbgMask = 0;
940 }
941 clients[id].Dbg.Registered = DBG_HANDLE_REG_NEW;
942 clients[id].Dbg.id = (byte)id;
943 clients[id].Dbg.dbg_end = DI_deregister;
944 clients[id].Dbg.dbg_prt = DI_format_locked;
945 clients[id].Dbg.dbg_ev = DiProcessEventLog;
946 clients[id].Dbg.dbg_irq = DI_format_locked;
947 clients[id].Dbg.next = (pDbgHandle)DBG_MAGIC;
948
949 {
950 diva_trace_library_user_interface_t diva_maint_user_ifc = { &clients[id],
951 diva_maint_state_change_notify,
952 diva_maint_trace_notify,
953 diva_maint_error };
954
955 /*
956 Attach to adapter management interface
957 */
958 if ((clients[id].pIdiLib =
959 DivaSTraceLibraryCreateInstance ((int)logical, &diva_maint_user_ifc, pmem))) {
960 if (((*(clients[id].pIdiLib->DivaSTraceLibraryStart))(clients[id].pIdiLib->hLib))) {
961 diva_mnt_internal_dprintf (0, DLI_ERR, "Adapter(%d) Start failed", (int)logical);
962 (*(clients[id].pIdiLib->DivaSTraceLibraryFinit))(clients[id].pIdiLib->hLib);
963 clients[id].pIdiLib = NULL;
964 }
965 } else {
966 diva_mnt_internal_dprintf (0, DLI_ERR, "A(%d) management init failed", (int)logical);
967 }
968 }
969
970 if (!clients[id].pIdiLib) {
971 clients[id].request = NULL;
972 clients[id].request_pending = 0;
973 clients[id].hDbg = NULL;
974 diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "register");
975 diva_os_leave_spin_lock (&dbg_adapter_lock, &old_irql1, "register");
976 diva_os_free (0, pmem);
977 return;
978 }
979
980 /*
981 Log driver register, MAINT driver ID is '0'
982 */
983 len = sprintf (tmp, "DIMAINT - drv # %d = '%s' registered",
984 id, clients[id].Dbg.drvName);
985
986 while (!(pmsg = (diva_dbg_entry_head_t*)queueAllocMsg (dbg_queue,
987 (word)(len+1+sizeof(*pmsg))))) {
988 if ((pmsg = (diva_dbg_entry_head_t*)queuePeekMsg (dbg_queue, &size))) {
989 queueFreeMsg (dbg_queue);
990 } else {
991 break;
992 }
993 }
994
995 if (pmsg) {
996 pmsg->sequence = dbg_sequence++;
997 pmsg->time_sec = sec;
998 pmsg->time_usec = usec;
999 pmsg->facility = MSG_TYPE_STRING;
1000 pmsg->dli = DLI_REG;
1001 pmsg->drv_id = 0; /* id 0 - DIMAINT */
1002 pmsg->di_cpu = 0;
1003 pmsg->data_length = len+1;
1004
1005 memcpy (&pmsg[1], tmp, len+1);
1006 queueCompleteMsg (pmsg);
1007 diva_maint_wakeup_read();
1008 }
1009
1010 org_mask = clients[id].Dbg.dbgMask;
1011 clients[id].Dbg.dbgMask = 0;
1012
1013 diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "register");
1014
1015 if (clients[id].request_pending) {
1016 clients[id].request_pending = 0;
1017 (*(clients[id].request))((ENTITY*)(*(clients[id].pIdiLib->DivaSTraceGetHandle))(clients[id].pIdiLib->hLib));
1018 }
1019
1020 diva_os_leave_spin_lock (&dbg_adapter_lock, &old_irql1, "register");
1021
1022 diva_set_driver_dbg_mask (id, org_mask);
1023}
1024
1025/*
1026 De-Register XDI adapter
1027 */
1028void diva_mnt_remove_xdi_adapter (const DESCRIPTOR* d) {
1029 diva_os_spin_lock_magic_t old_irql, old_irql1;
1030 dword sec, usec;
1031 int i;
1032 word size;
1033 byte* pmem = NULL;
1034
1035 diva_os_get_time (&sec, &usec);
1036
1037 diva_os_enter_spin_lock (&dbg_adapter_lock, &old_irql1, "read");
1038 diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "read");
1039
1040 for (i = 1; i < (sizeof(clients)/sizeof(clients[0])); i++) {
1041 if (clients[i].hDbg && (clients[i].request == d->request)) {
1042 diva_dbg_entry_head_t* pmsg;
1043 char tmp[256];
1044 int len;
1045
1046 if (clients[i].pIdiLib) {
1047 (*(clients[i].pIdiLib->DivaSTraceLibraryFinit))(clients[i].pIdiLib->hLib);
1048 clients[i].pIdiLib = NULL;
1049
1050 pmem = clients[i].pmem;
1051 clients[i].pmem = NULL;
1052 }
1053
1054 clients[i].hDbg = NULL;
1055 clients[i].request_pending = 0;
1056 if (clients[i].dma_handle >= 0) {
1057 /*
1058 Free DMA handle
1059 */
1060 diva_free_dma_descriptor (clients[i].request, clients[i].dma_handle);
1061 clients[i].dma_handle = -1;
1062 }
1063 clients[i].request = NULL;
1064
1065 /*
1066 Log driver register, MAINT driver ID is '0'
1067 */
1068 len = sprintf (tmp, "DIMAINT - drv # %d = '%s' de-registered",
1069 i, clients[i].Dbg.drvName);
1070
1071 memset (&clients[i].Dbg, 0x00, sizeof(clients[i].Dbg));
1072
1073 while (!(pmsg = (diva_dbg_entry_head_t*)queueAllocMsg (dbg_queue,
1074 (word)(len+1+sizeof(*pmsg))))) {
1075 if ((pmsg = (diva_dbg_entry_head_t*)queuePeekMsg (dbg_queue, &size))) {
1076 queueFreeMsg (dbg_queue);
1077 } else {
1078 break;
1079 }
1080 }
1081
1082 if (pmsg) {
1083 pmsg->sequence = dbg_sequence++;
1084 pmsg->time_sec = sec;
1085 pmsg->time_usec = usec;
1086 pmsg->facility = MSG_TYPE_STRING;
1087 pmsg->dli = DLI_REG;
1088 pmsg->drv_id = 0; /* id 0 - DIMAINT */
1089 pmsg->di_cpu = 0;
1090 pmsg->data_length = len+1;
1091
1092 memcpy (&pmsg[1], tmp, len+1);
1093 queueCompleteMsg (pmsg);
1094 diva_maint_wakeup_read();
1095 }
1096
1097 break;
1098 }
1099 }
1100
1101 diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "read_ack");
1102 diva_os_leave_spin_lock (&dbg_adapter_lock, &old_irql1, "read_ack");
1103
1104 if (pmem) {
1105 diva_os_free (0, pmem);
1106 }
1107}
1108
1109/* ----------------------------------------------------------------
1110 Low level interface for management interface client
1111 ---------------------------------------------------------------- */
1112/*
1113 Return handle to client structure
1114 */
1115void* SuperTraceOpenAdapter (int AdapterNumber) {
1116 int i;
1117
1118 for (i = 1; i < (sizeof(clients)/sizeof(clients[0])); i++) {
1119 if (clients[i].hDbg && clients[i].request && (clients[i].logical == AdapterNumber)) {
1120 return (&clients[i]);
1121 }
1122 }
1123
1124 return NULL;
1125}
1126
1127int SuperTraceCloseAdapter (void* AdapterHandle) {
1128 return (0);
1129}
1130
1131int SuperTraceReadRequest (void* AdapterHandle, const char* name, byte* data) {
1132 diva_maint_client_t* pC = (diva_maint_client_t*)AdapterHandle;
1133
1134 if (pC && pC->pIdiLib && pC->request) {
1135 ENTITY* e = (ENTITY*)(*(pC->pIdiLib->DivaSTraceGetHandle))(pC->pIdiLib->hLib);
1136 byte* xdata = (byte*)&pC->xbuffer[0];
1137 char tmp = 0;
1138 word length;
1139
1140 if (!strcmp(name, "\\")) { /* Read ROOT */
1141 name = &tmp;
1142 }
1143 length = SuperTraceCreateReadReq (xdata, name);
1144 single_p (xdata, &length, 0); /* End Of Message */
1145
1146 e->Req = MAN_READ;
1147 e->ReqCh = 0;
1148 e->X->PLength = length;
1149 e->X->P = (byte*)xdata;
1150
1151 pC->request_pending = 1;
1152
1153 return (0);
1154 }
1155
1156 return (-1);
1157}
1158
1159int SuperTraceGetNumberOfChannels (void* AdapterHandle) {
1160 if (AdapterHandle) {
1161 diva_maint_client_t* pC = (diva_maint_client_t*)AdapterHandle;
1162
1163 return (pC->channels);
1164 }
1165
1166 return (0);
1167}
1168
1169int SuperTraceASSIGN (void* AdapterHandle, byte* data) {
1170 diva_maint_client_t* pC = (diva_maint_client_t*)AdapterHandle;
1171
1172 if (pC && pC->pIdiLib && pC->request) {
1173 ENTITY* e = (ENTITY*)(*(pC->pIdiLib->DivaSTraceGetHandle))(pC->pIdiLib->hLib);
1174 IDI_SYNC_REQ* preq;
1175 char buffer[((sizeof(preq->xdi_extended_features)+4) > sizeof(ENTITY)) ? (sizeof(preq->xdi_extended_features)+4) : sizeof(ENTITY)];
1176 char features[4];
1177 word assign_data_length = 1;
1178
1179 features[0] = 0;
1180 pC->xbuffer[0] = 0;
1181 preq = (IDI_SYNC_REQ*)&buffer[0];
1182 preq->xdi_extended_features.Req = 0;
1183 preq->xdi_extended_features.Rc = IDI_SYNC_REQ_XDI_GET_EXTENDED_FEATURES;
1184 preq->xdi_extended_features.info.buffer_length_in_bytes = sizeof(features);
1185 preq->xdi_extended_features.info.features = &features[0];
1186
1187 (*(pC->request))((ENTITY*)preq);
1188
1189 if ((features[0] & DIVA_XDI_EXTENDED_FEATURES_VALID) &&
1190 (features[0] & DIVA_XDI_EXTENDED_FEATURE_MANAGEMENT_DMA)) {
1191 dword rx_dma_magic;
1192 if ((pC->dma_handle = diva_get_dma_descriptor (pC->request, &rx_dma_magic)) >= 0) {
1193 pC->xbuffer[0] = LLI;
1194 pC->xbuffer[1] = 8;
1195 pC->xbuffer[2] = 0x40;
1196 pC->xbuffer[3] = (byte)pC->dma_handle;
1197 pC->xbuffer[4] = (byte)rx_dma_magic;
1198 pC->xbuffer[5] = (byte)(rx_dma_magic >> 8);
1199 pC->xbuffer[6] = (byte)(rx_dma_magic >> 16);
1200 pC->xbuffer[7] = (byte)(rx_dma_magic >> 24);
1201 pC->xbuffer[8] = (byte)DIVA_MAX_MANAGEMENT_TRANSFER_SIZE;
1202 pC->xbuffer[9] = (byte)(DIVA_MAX_MANAGEMENT_TRANSFER_SIZE >> 8);
1203 pC->xbuffer[10] = 0;
1204
1205 assign_data_length = 11;
1206 }
1207 } else {
1208 pC->dma_handle = -1;
1209 }
1210
1211 e->Id = MAN_ID;
1212 e->callback = diva_maint_xdi_cb;
1213 e->XNum = 1;
1214 e->X = &pC->XData;
1215 e->Req = ASSIGN;
1216 e->ReqCh = 0;
1217 e->X->PLength = assign_data_length;
1218 e->X->P = (byte*)&pC->xbuffer[0];
1219
1220 pC->request_pending = 1;
1221
1222 return (0);
1223 }
1224
1225 return (-1);
1226}
1227
1228int SuperTraceREMOVE (void* AdapterHandle) {
1229 diva_maint_client_t* pC = (diva_maint_client_t*)AdapterHandle;
1230
1231 if (pC && pC->pIdiLib && pC->request) {
1232 ENTITY* e = (ENTITY*)(*(pC->pIdiLib->DivaSTraceGetHandle))(pC->pIdiLib->hLib);
1233
1234 e->XNum = 1;
1235 e->X = &pC->XData;
1236 e->Req = REMOVE;
1237 e->ReqCh = 0;
1238 e->X->PLength = 1;
1239 e->X->P = (byte*)&pC->xbuffer[0];
1240 pC->xbuffer[0] = 0;
1241
1242 pC->request_pending = 1;
1243
1244 return (0);
1245 }
1246
1247 return (-1);
1248}
1249
1250int SuperTraceTraceOnRequest(void* hAdapter, const char* name, byte* data) {
1251 diva_maint_client_t* pC = (diva_maint_client_t*)hAdapter;
1252
1253 if (pC && pC->pIdiLib && pC->request) {
1254 ENTITY* e = (ENTITY*)(*(pC->pIdiLib->DivaSTraceGetHandle))(pC->pIdiLib->hLib);
1255 byte* xdata = (byte*)&pC->xbuffer[0];
1256 char tmp = 0;
1257 word length;
1258
1259 if (!strcmp(name, "\\")) { /* Read ROOT */
1260 name = &tmp;
1261 }
1262 length = SuperTraceCreateReadReq (xdata, name);
1263 single_p (xdata, &length, 0); /* End Of Message */
1264 e->Req = MAN_EVENT_ON;
1265 e->ReqCh = 0;
1266 e->X->PLength = length;
1267 e->X->P = (byte*)xdata;
1268
1269 pC->request_pending = 1;
1270
1271 return (0);
1272 }
1273
1274 return (-1);
1275}
1276
1277int SuperTraceWriteVar (void* AdapterHandle,
1278 byte* data,
1279 const char* name,
1280 void* var,
1281 byte type,
1282 byte var_length) {
1283 diva_maint_client_t* pC = (diva_maint_client_t*)AdapterHandle;
1284
1285 if (pC && pC->pIdiLib && pC->request) {
1286 ENTITY* e = (ENTITY*)(*(pC->pIdiLib->DivaSTraceGetHandle))(pC->pIdiLib->hLib);
1287 diva_man_var_header_t* pVar = (diva_man_var_header_t*)&pC->xbuffer[0];
1288 word length = SuperTraceCreateReadReq ((byte*)pVar, name);
1289
1290 memcpy (&pC->xbuffer[length], var, var_length);
1291 length += var_length;
1292 pVar->length += var_length;
1293 pVar->value_length = var_length;
1294 pVar->type = type;
1295 single_p ((byte*)pVar, &length, 0); /* End Of Message */
1296
1297 e->Req = MAN_WRITE;
1298 e->ReqCh = 0;
1299 e->X->PLength = length;
1300 e->X->P = (byte*)pVar;
1301
1302 pC->request_pending = 1;
1303
1304 return (0);
1305 }
1306
1307 return (-1);
1308}
1309
1310int SuperTraceExecuteRequest (void* AdapterHandle,
1311 const char* name,
1312 byte* data) {
1313 diva_maint_client_t* pC = (diva_maint_client_t*)AdapterHandle;
1314
1315 if (pC && pC->pIdiLib && pC->request) {
1316 ENTITY* e = (ENTITY*)(*(pC->pIdiLib->DivaSTraceGetHandle))(pC->pIdiLib->hLib);
1317 byte* xdata = (byte*)&pC->xbuffer[0];
1318 word length;
1319
1320 length = SuperTraceCreateReadReq (xdata, name);
1321 single_p (xdata, &length, 0); /* End Of Message */
1322
1323 e->Req = MAN_EXECUTE;
1324 e->ReqCh = 0;
1325 e->X->PLength = length;
1326 e->X->P = (byte*)xdata;
1327
1328 pC->request_pending = 1;
1329
1330 return (0);
1331 }
1332
1333 return (-1);
1334}
1335
1336static word SuperTraceCreateReadReq (byte* P, const char* path) {
1337 byte var_length;
1338 byte* plen;
1339
1340 var_length = (byte)strlen (path);
1341
1342 *P++ = ESC;
1343 plen = P++;
1344 *P++ = 0x80; /* MAN_IE */
1345 *P++ = 0x00; /* Type */
1346 *P++ = 0x00; /* Attribute */
1347 *P++ = 0x00; /* Status */
1348 *P++ = 0x00; /* Variable Length */
1349 *P++ = var_length;
1350 memcpy (P, path, var_length);
1351 P += var_length;
1352 *plen = var_length + 0x06;
1353
1354 return ((word)(var_length + 0x08));
1355}
1356
1357static void single_p (byte * P, word * PLength, byte Id) {
1358 P[(*PLength)++] = Id;
1359}
1360
1361static void diva_maint_xdi_cb (ENTITY* e) {
1362 diva_strace_context_t* pLib = DIVAS_CONTAINING_RECORD(e,diva_strace_context_t,e);
1363 diva_maint_client_t* pC;
1364 diva_os_spin_lock_magic_t old_irql, old_irql1;
1365
1366
1367 diva_os_enter_spin_lock (&dbg_adapter_lock, &old_irql1, "xdi_cb");
1368 diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "xdi_cb");
1369
1370 pC = (diva_maint_client_t*)pLib->hAdapter;
1371
1372 if ((e->complete == 255) || (pC->dma_handle < 0)) {
1373 if ((*(pLib->instance.DivaSTraceMessageInput))(&pLib->instance)) {
1374 diva_mnt_internal_dprintf (0, DLI_ERR, "Trace internal library error");
1375 }
1376 } else {
1377 /*
1378 Process combined management interface indication
1379 */
1380 if ((*(pLib->instance.DivaSTraceMessageInput))(&pLib->instance)) {
1381 diva_mnt_internal_dprintf (0, DLI_ERR, "Trace internal library error (DMA mode)");
1382 }
1383 }
1384
1385 diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "xdi_cb");
1386
1387
1388 if (pC->request_pending) {
1389 pC->request_pending = 0;
1390 (*(pC->request))(e);
1391 }
1392
1393 diva_os_leave_spin_lock (&dbg_adapter_lock, &old_irql1, "xdi_cb");
1394}
1395
1396
1397static void diva_maint_error (void* user_context,
1398 diva_strace_library_interface_t* hLib,
1399 int Adapter,
1400 int error,
1401 const char* file,
1402 int line) {
1403 diva_mnt_internal_dprintf (0, DLI_ERR,
1404 "Trace library error(%d) A(%d) %s %d", error, Adapter, file, line);
1405}
1406
1407static void print_ie (diva_trace_ie_t* ie, char* buffer, int length) {
1408 int i;
1409
1410 buffer[0] = 0;
1411
1412 if (length > 32) {
1413 for (i = 0; ((i < ie->length) && (length > 3)); i++) {
1414 sprintf (buffer, "%02x", ie->data[i]);
1415 buffer += 2;
1416 length -= 2;
1417 if (i < (ie->length-1)) {
1418 strcpy (buffer, " ");
1419 buffer++;
1420 length--;
1421 }
1422 }
1423 }
1424}
1425
1426static void diva_maint_state_change_notify (void* user_context,
1427 diva_strace_library_interface_t* hLib,
1428 int Adapter,
1429 diva_trace_line_state_t* channel,
1430 int notify_subject) {
1431 diva_maint_client_t* pC = (diva_maint_client_t*)user_context;
1432 diva_trace_fax_state_t* fax = &channel->fax;
1433 diva_trace_modem_state_t* modem = &channel->modem;
1434 char tmp[256];
1435
1436 if (!pC->hDbg) {
1437 return;
1438 }
1439
1440 switch (notify_subject) {
1441 case DIVA_SUPER_TRACE_NOTIFY_LINE_CHANGE: {
1442 int view = (TraceFilter[0] == 0);
1443 /*
1444 Process selective Trace
1445 */
1446 if (channel->Line[0] == 'I' && channel->Line[1] == 'd' &&
1447 channel->Line[2] == 'l' && channel->Line[3] == 'e') {
1448 if ((TraceFilterIdent == pC->hDbg->id) && (TraceFilterChannel == (int)channel->ChannelNumber)) {
1449 (*(hLib->DivaSTraceSetBChannel))(hLib, (int)channel->ChannelNumber, 0);
1450 (*(hLib->DivaSTraceSetAudioTap))(hLib, (int)channel->ChannelNumber, 0);
1451 diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG, "Selective Trace OFF for Ch=%d",
1452 (int)channel->ChannelNumber);
1453 TraceFilterIdent = -1;
1454 TraceFilterChannel = -1;
1455 view = 1;
1456 }
1457 } else if (TraceFilter[0] && (TraceFilterIdent < 0) && !(diva_mnt_cmp_nmbr (&channel->RemoteAddress[0]) &&
1458 diva_mnt_cmp_nmbr (&channel->LocalAddress[0]))) {
1459
1460 if ((pC->hDbg->dbgMask & DIVA_MGT_DBG_IFC_BCHANNEL) != 0) { /* Activate B-channel trace */
1461 (*(hLib->DivaSTraceSetBChannel))(hLib, (int)channel->ChannelNumber, 1);
1462 }
1463 if ((pC->hDbg->dbgMask & DIVA_MGT_DBG_IFC_AUDIO) != 0) { /* Activate AudioTap Trace */
1464 (*(hLib->DivaSTraceSetAudioTap))(hLib, (int)channel->ChannelNumber, 1);
1465 }
1466
1467 TraceFilterIdent = pC->hDbg->id;
1468 TraceFilterChannel = (int)channel->ChannelNumber;
1469
1470 if (TraceFilterIdent >= 0) {
1471 diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG, "Selective Trace ON for Ch=%d",
1472 (int)channel->ChannelNumber);
1473 view = 1;
1474 }
1475 }
1476 if (view && (pC->hDbg->dbgMask & DIVA_MGT_DBG_LINE_EVENTS)) {
1477 diva_mnt_internal_dprintf (pC->hDbg->id, DLI_STAT, "L Ch = %d",
1478 (int)channel->ChannelNumber);
1479 diva_mnt_internal_dprintf (pC->hDbg->id, DLI_STAT, "L Status = <%s>", &channel->Line[0]);
1480 diva_mnt_internal_dprintf (pC->hDbg->id, DLI_STAT, "L Layer1 = <%s>", &channel->Framing[0]);
1481 diva_mnt_internal_dprintf (pC->hDbg->id, DLI_STAT, "L Layer2 = <%s>", &channel->Layer2[0]);
1482 diva_mnt_internal_dprintf (pC->hDbg->id, DLI_STAT, "L Layer3 = <%s>", &channel->Layer3[0]);
1483 diva_mnt_internal_dprintf (pC->hDbg->id, DLI_STAT, "L RAddr = <%s>",
1484 &channel->RemoteAddress[0]);
1485 diva_mnt_internal_dprintf (pC->hDbg->id, DLI_STAT, "L RSAddr = <%s>",
1486 &channel->RemoteSubAddress[0]);
1487 diva_mnt_internal_dprintf (pC->hDbg->id, DLI_STAT, "L LAddr = <%s>",
1488 &channel->LocalAddress[0]);
1489 diva_mnt_internal_dprintf (pC->hDbg->id, DLI_STAT, "L LSAddr = <%s>",
1490 &channel->LocalSubAddress[0]);
1491 print_ie(&channel->call_BC, tmp, sizeof(tmp));
1492 diva_mnt_internal_dprintf (pC->hDbg->id, DLI_STAT, "L BC = <%s>", tmp);
1493 print_ie(&channel->call_HLC, tmp, sizeof(tmp));
1494 diva_mnt_internal_dprintf (pC->hDbg->id, DLI_STAT, "L HLC = <%s>", tmp);
1495 print_ie(&channel->call_LLC, tmp, sizeof(tmp));
1496 diva_mnt_internal_dprintf (pC->hDbg->id, DLI_STAT, "L LLC = <%s>", tmp);
1497 diva_mnt_internal_dprintf (pC->hDbg->id, DLI_STAT, "L CR = 0x%x", channel->CallReference);
1498 diva_mnt_internal_dprintf (pC->hDbg->id, DLI_STAT, "L Disc = 0x%x",
1499 channel->LastDisconnecCause);
1500 diva_mnt_internal_dprintf (pC->hDbg->id, DLI_STAT, "L Owner = <%s>", &channel->UserID[0]);
1501 }
1502
1503 } break;
1504
1505 case DIVA_SUPER_TRACE_NOTIFY_MODEM_CHANGE:
1506 if (pC->hDbg->dbgMask & DIVA_MGT_DBG_MDM_PROGRESS) {
1507 {
1508 int ch = TraceFilterChannel;
1509 int id = TraceFilterIdent;
1510
1511 if ((id >= 0) && (ch >= 0) && (id < sizeof(clients)/sizeof(clients[0])) &&
1512 (clients[id].Dbg.id == (byte)id) && (clients[id].pIdiLib == hLib)) {
1513 if (ch != (int)modem->ChannelNumber) {
1514 break;
1515 }
1516 } else if (TraceFilter[0] != 0) {
1517 break;
1518 }
1519 }
1520
1521
1522 diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM Ch = %lu",
1523 (int)modem->ChannelNumber);
1524 diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM Event = %lu", modem->Event);
1525 diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM Norm = %lu", modem->Norm);
1526 diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM Opts. = 0x%08x", modem->Options);
1527 diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM Tx = %lu Bps", modem->TxSpeed);
1528 diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM Rx = %lu Bps", modem->RxSpeed);
1529 diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM RT = %lu mSec",
1530 modem->RoundtripMsec);
1531 diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM Sr = %lu", modem->SymbolRate);
1532 diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM Rxl = %d dBm", modem->RxLeveldBm);
1533 diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM El = %d dBm", modem->EchoLeveldBm);
1534 diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM SNR = %lu dB", modem->SNRdb);
1535 diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM MAE = %lu", modem->MAE);
1536 diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM LRet = %lu",
1537 modem->LocalRetrains);
1538 diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM RRet = %lu",
1539 modem->RemoteRetrains);
1540 diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM LRes = %lu", modem->LocalResyncs);
1541 diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM RRes = %lu",
1542 modem->RemoteResyncs);
1543 if (modem->Event == 3) {
1544 diva_mnt_internal_dprintf(pC->hDbg->id,DLI_STAT,"MDM Disc = %lu", modem->DiscReason);
1545 }
1546 }
1547 if ((modem->Event == 3) && (pC->hDbg->dbgMask & DIVA_MGT_DBG_MDM_STATISTICS)) {
1548 (*(pC->pIdiLib->DivaSTraceGetModemStatistics))(pC->pIdiLib);
1549 }
1550 break;
1551
1552 case DIVA_SUPER_TRACE_NOTIFY_FAX_CHANGE:
1553 if (pC->hDbg->dbgMask & DIVA_MGT_DBG_FAX_PROGRESS) {
1554 {
1555 int ch = TraceFilterChannel;
1556 int id = TraceFilterIdent;
1557
1558 if ((id >= 0) && (ch >= 0) && (id < sizeof(clients)/sizeof(clients[0])) &&
1559 (clients[id].Dbg.id == (byte)id) && (clients[id].pIdiLib == hLib)) {
1560 if (ch != (int)fax->ChannelNumber) {
1561 break;
1562 }
1563 } else if (TraceFilter[0] != 0) {
1564 break;
1565 }
1566 }
1567
1568 diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX Ch = %lu",(int)fax->ChannelNumber);
1569 diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX Event = %lu", fax->Event);
1570 diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX Pages = %lu", fax->Page_Counter);
1571 diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX Feat. = 0x%08x", fax->Features);
1572 diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX ID = <%s>", &fax->Station_ID[0]);
1573 diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX Saddr = <%s>", &fax->Subaddress[0]);
1574 diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX Pwd = <%s>", &fax->Password[0]);
1575 diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX Speed = %lu", fax->Speed);
1576 diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX Res. = 0x%08x", fax->Resolution);
1577 diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX Width = %lu", fax->Paper_Width);
1578 diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX Length= %lu", fax->Paper_Length);
1579 diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX SLT = %lu", fax->Scanline_Time);
1580 if (fax->Event == 3) {
1581 diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX Disc = %lu", fax->Disc_Reason);
1582 }
1583 }
1584 if ((fax->Event == 3) && (pC->hDbg->dbgMask & DIVA_MGT_DBG_FAX_STATISTICS)) {
1585 (*(pC->pIdiLib->DivaSTraceGetFaxStatistics))(pC->pIdiLib);
1586 }
1587 break;
1588
1589 case DIVA_SUPER_TRACE_INTERFACE_CHANGE:
1590 if (pC->hDbg->dbgMask & DIVA_MGT_DBG_IFC_EVENTS) {
1591 diva_mnt_internal_dprintf (pC->hDbg->id, DLI_STAT,
1592 "Layer 1 -> [%s]", channel->pInterface->Layer1);
1593 diva_mnt_internal_dprintf (pC->hDbg->id, DLI_STAT,
1594 "Layer 2 -> [%s]", channel->pInterface->Layer2);
1595 }
1596 break;
1597
1598 case DIVA_SUPER_TRACE_NOTIFY_STAT_CHANGE:
1599 if (pC->hDbg->dbgMask & DIVA_MGT_DBG_IFC_STATISTICS) {
1600 /*
1601 Incoming Statistics
1602 */
1603 if (channel->pInterfaceStat->inc.Calls) {
1604 diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
1605 "Inc Calls =%lu", channel->pInterfaceStat->inc.Calls);
1606 }
1607 if (channel->pInterfaceStat->inc.Connected) {
1608 diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
1609 "Inc Connected =%lu", channel->pInterfaceStat->inc.Connected);
1610 }
1611 if (channel->pInterfaceStat->inc.User_Busy) {
1612 diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
1613 "Inc Busy =%lu", channel->pInterfaceStat->inc.User_Busy);
1614 }
1615 if (channel->pInterfaceStat->inc.Call_Rejected) {
1616 diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
1617 "Inc Rejected =%lu", channel->pInterfaceStat->inc.Call_Rejected);
1618 }
1619 if (channel->pInterfaceStat->inc.Wrong_Number) {
1620 diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
1621 "Inc Wrong Nr =%lu", channel->pInterfaceStat->inc.Wrong_Number);
1622 }
1623 if (channel->pInterfaceStat->inc.Incompatible_Dst) {
1624 diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
1625 "Inc Incomp. Dest =%lu", channel->pInterfaceStat->inc.Incompatible_Dst);
1626 }
1627 if (channel->pInterfaceStat->inc.Out_of_Order) {
1628 diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
1629 "Inc Out of Order =%lu", channel->pInterfaceStat->inc.Out_of_Order);
1630 }
1631 if (channel->pInterfaceStat->inc.Ignored) {
1632 diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
1633 "Inc Ignored =%lu", channel->pInterfaceStat->inc.Ignored);
1634 }
1635
1636 /*
1637 Outgoing Statistics
1638 */
1639 if (channel->pInterfaceStat->outg.Calls) {
1640 diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
1641 "Outg Calls =%lu", channel->pInterfaceStat->outg.Calls);
1642 }
1643 if (channel->pInterfaceStat->outg.Connected) {
1644 diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
1645 "Outg Connected =%lu", channel->pInterfaceStat->outg.Connected);
1646 }
1647 if (channel->pInterfaceStat->outg.User_Busy) {
1648 diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
1649 "Outg Busy =%lu", channel->pInterfaceStat->outg.User_Busy);
1650 }
1651 if (channel->pInterfaceStat->outg.No_Answer) {
1652 diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
1653 "Outg No Answer =%lu", channel->pInterfaceStat->outg.No_Answer);
1654 }
1655 if (channel->pInterfaceStat->outg.Wrong_Number) {
1656 diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
1657 "Outg Wrong Nr =%lu", channel->pInterfaceStat->outg.Wrong_Number);
1658 }
1659 if (channel->pInterfaceStat->outg.Call_Rejected) {
1660 diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
1661 "Outg Rejected =%lu", channel->pInterfaceStat->outg.Call_Rejected);
1662 }
1663 if (channel->pInterfaceStat->outg.Other_Failures) {
1664 diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
1665 "Outg Other Failures =%lu", channel->pInterfaceStat->outg.Other_Failures);
1666 }
1667 }
1668 break;
1669
1670 case DIVA_SUPER_TRACE_NOTIFY_MDM_STAT_CHANGE:
1671 if (channel->pInterfaceStat->mdm.Disc_Normal) {
1672 diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
1673 "MDM Disc Normal = %lu", channel->pInterfaceStat->mdm.Disc_Normal);
1674 }
1675 if (channel->pInterfaceStat->mdm.Disc_Unspecified) {
1676 diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
1677 "MDM Disc Unsp. = %lu", channel->pInterfaceStat->mdm.Disc_Unspecified);
1678 }
1679 if (channel->pInterfaceStat->mdm.Disc_Busy_Tone) {
1680 diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
1681 "MDM Disc Busy Tone = %lu", channel->pInterfaceStat->mdm.Disc_Busy_Tone);
1682 }
1683 if (channel->pInterfaceStat->mdm.Disc_Congestion) {
1684 diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
1685 "MDM Disc Congestion = %lu", channel->pInterfaceStat->mdm.Disc_Congestion);
1686 }
1687 if (channel->pInterfaceStat->mdm.Disc_Carr_Wait) {
1688 diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
1689 "MDM Disc Carrier Wait = %lu", channel->pInterfaceStat->mdm.Disc_Carr_Wait);
1690 }
1691 if (channel->pInterfaceStat->mdm.Disc_Trn_Timeout) {
1692 diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
1693 "MDM Disc Trn. T.o. = %lu", channel->pInterfaceStat->mdm.Disc_Trn_Timeout);
1694 }
1695 if (channel->pInterfaceStat->mdm.Disc_Incompat) {
1696 diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
1697 "MDM Disc Incompatible = %lu", channel->pInterfaceStat->mdm.Disc_Incompat);
1698 }
1699 if (channel->pInterfaceStat->mdm.Disc_Frame_Rej) {
1700 diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
1701 "MDM Disc Frame Reject = %lu", channel->pInterfaceStat->mdm.Disc_Frame_Rej);
1702 }
1703 if (channel->pInterfaceStat->mdm.Disc_V42bis) {
1704 diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
1705 "MDM Disc V.42bis = %lu", channel->pInterfaceStat->mdm.Disc_V42bis);
1706 }
1707 break;
1708
1709 case DIVA_SUPER_TRACE_NOTIFY_FAX_STAT_CHANGE:
1710 if (channel->pInterfaceStat->fax.Disc_Normal) {
1711 diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
1712 "FAX Disc Normal = %lu", channel->pInterfaceStat->fax.Disc_Normal);
1713 }
1714 if (channel->pInterfaceStat->fax.Disc_Not_Ident) {
1715 diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
1716 "FAX Disc Not Ident. = %lu", channel->pInterfaceStat->fax.Disc_Not_Ident);
1717 }
1718 if (channel->pInterfaceStat->fax.Disc_No_Response) {
1719 diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
1720 "FAX Disc No Response = %lu", channel->pInterfaceStat->fax.Disc_No_Response);
1721 }
1722 if (channel->pInterfaceStat->fax.Disc_Retries) {
1723 diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
1724 "FAX Disc Max Retries = %lu", channel->pInterfaceStat->fax.Disc_Retries);
1725 }
1726 if (channel->pInterfaceStat->fax.Disc_Unexp_Msg) {
1727 diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
1728 "FAX Unexp. Msg. = %lu", channel->pInterfaceStat->fax.Disc_Unexp_Msg);
1729 }
1730 if (channel->pInterfaceStat->fax.Disc_No_Polling) {
1731 diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
1732 "FAX Disc No Polling = %lu", channel->pInterfaceStat->fax.Disc_No_Polling);
1733 }
1734 if (channel->pInterfaceStat->fax.Disc_Training) {
1735 diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
1736 "FAX Disc Training = %lu", channel->pInterfaceStat->fax.Disc_Training);
1737 }
1738 if (channel->pInterfaceStat->fax.Disc_Unexpected) {
1739 diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
1740 "FAX Disc Unexpected = %lu", channel->pInterfaceStat->fax.Disc_Unexpected);
1741 }
1742 if (channel->pInterfaceStat->fax.Disc_Application) {
1743 diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
1744 "FAX Disc Application = %lu", channel->pInterfaceStat->fax.Disc_Application);
1745 }
1746 if (channel->pInterfaceStat->fax.Disc_Incompat) {
1747 diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
1748 "FAX Disc Incompatible = %lu", channel->pInterfaceStat->fax.Disc_Incompat);
1749 }
1750 if (channel->pInterfaceStat->fax.Disc_No_Command) {
1751 diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
1752 "FAX Disc No Command = %lu", channel->pInterfaceStat->fax.Disc_No_Command);
1753 }
1754 if (channel->pInterfaceStat->fax.Disc_Long_Msg) {
1755 diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
1756 "FAX Disc Long Msg. = %lu", channel->pInterfaceStat->fax.Disc_Long_Msg);
1757 }
1758 if (channel->pInterfaceStat->fax.Disc_Supervisor) {
1759 diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
1760 "FAX Disc Supervisor = %lu", channel->pInterfaceStat->fax.Disc_Supervisor);
1761 }
1762 if (channel->pInterfaceStat->fax.Disc_SUB_SEP_PWD) {
1763 diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
1764 "FAX Disc SUP SEP PWD = %lu", channel->pInterfaceStat->fax.Disc_SUB_SEP_PWD);
1765 }
1766 if (channel->pInterfaceStat->fax.Disc_Invalid_Msg) {
1767 diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
1768 "FAX Disc Invalid Msg. = %lu", channel->pInterfaceStat->fax.Disc_Invalid_Msg);
1769 }
1770 if (channel->pInterfaceStat->fax.Disc_Page_Coding) {
1771 diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
1772 "FAX Disc Page Coding = %lu", channel->pInterfaceStat->fax.Disc_Page_Coding);
1773 }
1774 if (channel->pInterfaceStat->fax.Disc_App_Timeout) {
1775 diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
1776 "FAX Disc Appl. T.o. = %lu", channel->pInterfaceStat->fax.Disc_App_Timeout);
1777 }
1778 if (channel->pInterfaceStat->fax.Disc_Unspecified) {
1779 diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
1780 "FAX Disc Unspec. = %lu", channel->pInterfaceStat->fax.Disc_Unspecified);
1781 }
1782 break;
1783 }
1784}
1785
1786/*
1787 Receive trace information from the Management Interface and store it in the
1788 internal trace buffer with MSG_TYPE_MLOG as is, without any filtering.
1789 Event Filtering and formatting is done in Management Interface self.
1790 */
1791static void diva_maint_trace_notify (void* user_context,
1792 diva_strace_library_interface_t* hLib,
1793 int Adapter,
1794 void* xlog_buffer,
1795 int length) {
1796 diva_maint_client_t* pC = (diva_maint_client_t*)user_context;
1797 diva_dbg_entry_head_t* pmsg;
1798 word size;
1799 dword sec, usec;
1800 int ch = TraceFilterChannel;
1801 int id = TraceFilterIdent;
1802
1803 /*
1804 Selective trace
1805 */
1806 if ((id >= 0) && (ch >= 0) && (id < sizeof(clients)/sizeof(clients[0])) &&
1807 (clients[id].Dbg.id == (byte)id) && (clients[id].pIdiLib == hLib)) {
1808 const char* p = NULL;
1809 int ch_value = -1;
1810 MI_XLOG_HDR *TrcData = (MI_XLOG_HDR *)xlog_buffer;
1811
1812 if (Adapter != clients[id].logical) {
1813 return; /* Ignore all trace messages from other adapters */
1814 }
1815
1816 if (TrcData->code == 24) {
1817 p = (char*)&TrcData->code;
1818 p += 2;
1819 }
1820
1821 /*
1822 All L1 messages start as [dsp,ch], so we can filter this information
1823 and filter out all messages that use different channel
1824 */
1825 if (p && p[0] == '[') {
1826 if (p[2] == ',') {
1827 p += 3;
1828 ch_value = *p - '0';
1829 } else if (p[3] == ',') {
1830 p += 4;
1831 ch_value = *p - '0';
1832 }
1833 if (ch_value >= 0) {
1834 if (p[2] == ']') {
1835 ch_value = ch_value * 10 + p[1] - '0';
1836 }
1837 if (ch_value != ch) {
1838 return; /* Ignore other channels */
1839 }
1840 }
1841 }
1842
1843 } else if (TraceFilter[0] != 0) {
1844 return; /* Ignore trace if trace filter is activated, but idle */
1845 }
1846
1847 diva_os_get_time (&sec, &usec);
1848
1849 while (!(pmsg = (diva_dbg_entry_head_t*)queueAllocMsg (dbg_queue,
1850 (word)length+sizeof(*pmsg)))) {
1851 if ((pmsg = (diva_dbg_entry_head_t*)queuePeekMsg (dbg_queue, &size))) {
1852 queueFreeMsg (dbg_queue);
1853 } else {
1854 break;
1855 }
1856 }
1857 if (pmsg) {
1858 memcpy (&pmsg[1], xlog_buffer, length);
1859 pmsg->sequence = dbg_sequence++;
1860 pmsg->time_sec = sec;
1861 pmsg->time_usec = usec;
1862 pmsg->facility = MSG_TYPE_MLOG;
1863 pmsg->dli = pC->logical;
1864 pmsg->drv_id = pC->hDbg->id;
1865 pmsg->di_cpu = 0;
1866 pmsg->data_length = length;
1867 queueCompleteMsg (pmsg);
1868 if (queueCount(dbg_queue)) {
1869 diva_maint_wakeup_read();
1870 }
1871 }
1872}
1873
1874
1875/*
1876 Convert MAINT trace mask to management interface trace mask/work/facility and
1877 issue command to management interface
1878 */
1879static void diva_change_management_debug_mask (diva_maint_client_t* pC, dword old_mask) {
1880 if (pC->request && pC->hDbg && pC->pIdiLib) {
1881 dword changed = pC->hDbg->dbgMask ^ old_mask;
1882
1883 if (changed & DIVA_MGT_DBG_TRACE) {
1884 (*(pC->pIdiLib->DivaSTraceSetInfo))(pC->pIdiLib,
1885 (pC->hDbg->dbgMask & DIVA_MGT_DBG_TRACE) != 0);
1886 }
1887 if (changed & DIVA_MGT_DBG_DCHAN) {
1888 (*(pC->pIdiLib->DivaSTraceSetDChannel))(pC->pIdiLib,
1889 (pC->hDbg->dbgMask & DIVA_MGT_DBG_DCHAN) != 0);
1890 }
1891 if (!TraceFilter[0]) {
1892 if (changed & DIVA_MGT_DBG_IFC_BCHANNEL) {
1893 int i, state = ((pC->hDbg->dbgMask & DIVA_MGT_DBG_IFC_BCHANNEL) != 0);
1894
1895 for (i = 0; i < pC->channels; i++) {
1896 (*(pC->pIdiLib->DivaSTraceSetBChannel))(pC->pIdiLib, i+1, state);
1897 }
1898 }
1899 if (changed & DIVA_MGT_DBG_IFC_AUDIO) {
1900 int i, state = ((pC->hDbg->dbgMask & DIVA_MGT_DBG_IFC_AUDIO) != 0);
1901
1902 for (i = 0; i < pC->channels; i++) {
1903 (*(pC->pIdiLib->DivaSTraceSetAudioTap))(pC->pIdiLib, i+1, state);
1904 }
1905 }
1906 }
1907 }
1908}
1909
1910
1911void diva_mnt_internal_dprintf (dword drv_id, dword type, char* fmt, ...) {
1912 va_list ap;
1913
1914 va_start(ap, fmt);
1915 DI_format (0, (word)drv_id, (int)type, fmt, ap);
1916 va_end(ap);
1917}
1918
1919/*
1920 Shutdown all adapters before driver removal
1921 */
1922int diva_mnt_shutdown_xdi_adapters (void) {
1923 diva_os_spin_lock_magic_t old_irql, old_irql1;
1924 int i, fret = 0;
1925 byte * pmem;
1926
1927
1928 for (i = 1; i < (sizeof(clients)/sizeof(clients[0])); i++) {
1929 pmem = NULL;
1930
1931 diva_os_enter_spin_lock (&dbg_adapter_lock, &old_irql1, "unload");
1932 diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "unload");
1933
1934 if (clients[i].hDbg && clients[i].pIdiLib && clients[i].request) {
1935 if ((*(clients[i].pIdiLib->DivaSTraceLibraryStop))(clients[i].pIdiLib) == 1) {
1936 /*
1937 Adapter removal complete
1938 */
1939 if (clients[i].pIdiLib) {
1940 (*(clients[i].pIdiLib->DivaSTraceLibraryFinit))(clients[i].pIdiLib->hLib);
1941 clients[i].pIdiLib = NULL;
1942
1943 pmem = clients[i].pmem;
1944 clients[i].pmem = NULL;
1945 }
1946 clients[i].hDbg = NULL;
1947 clients[i].request_pending = 0;
1948
1949 if (clients[i].dma_handle >= 0) {
1950 /*
1951 Free DMA handle
1952 */
1953 diva_free_dma_descriptor (clients[i].request, clients[i].dma_handle);
1954 clients[i].dma_handle = -1;
1955 }
1956 clients[i].request = NULL;
1957 } else {
1958 fret = -1;
1959 }
1960 }
1961
1962 diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "unload");
1963 if (clients[i].hDbg && clients[i].pIdiLib && clients[i].request && clients[i].request_pending) {
1964 clients[i].request_pending = 0;
1965 (*(clients[i].request))((ENTITY*)(*(clients[i].pIdiLib->DivaSTraceGetHandle))(clients[i].pIdiLib->hLib));
1966 if (clients[i].dma_handle >= 0) {
1967 diva_free_dma_descriptor (clients[i].request, clients[i].dma_handle);
1968 clients[i].dma_handle = -1;
1969 }
1970 }
1971 diva_os_leave_spin_lock (&dbg_adapter_lock, &old_irql1, "unload");
1972
1973 if (pmem) {
1974 diva_os_free (0, pmem);
1975 }
1976 }
1977
1978 return (fret);
1979}
1980
1981/*
1982 Set/Read the trace filter used for selective tracing.
1983 Affects B- and Audio Tap trace mask at run time
1984 */
1985int diva_set_trace_filter (int filter_length, const char* filter) {
1986 diva_os_spin_lock_magic_t old_irql, old_irql1;
1987 int i, ch, on, client_b_on, client_atap_on;
1988
1989 diva_os_enter_spin_lock (&dbg_adapter_lock, &old_irql1, "dbg mask");
1990 diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "write_filter");
1991
1992 if (filter_length <= DIVA_MAX_SELECTIVE_FILTER_LENGTH) {
1993 memcpy (&TraceFilter[0], filter, filter_length);
1994 if (TraceFilter[filter_length]) {
1995 TraceFilter[filter_length] = 0;
1996 }
1997 if (TraceFilter[0] == '*') {
1998 TraceFilter[0] = 0;
1999 }
2000 } else {
2001 filter_length = -1;
2002 }
2003
2004 TraceFilterIdent = -1;
2005 TraceFilterChannel = -1;
2006
2007 on = (TraceFilter[0] == 0);
2008
2009 for (i = 1; i < (sizeof(clients)/sizeof(clients[0])); i++) {
2010 if (clients[i].hDbg && clients[i].pIdiLib && clients[i].request) {
2011 client_b_on = on && ((clients[i].hDbg->dbgMask & DIVA_MGT_DBG_IFC_BCHANNEL) != 0);
2012 client_atap_on = on && ((clients[i].hDbg->dbgMask & DIVA_MGT_DBG_IFC_AUDIO) != 0);
2013 for (ch = 0; ch < clients[i].channels; ch++) {
2014 (*(clients[i].pIdiLib->DivaSTraceSetBChannel))(clients[i].pIdiLib->hLib, ch+1, client_b_on);
2015 (*(clients[i].pIdiLib->DivaSTraceSetAudioTap))(clients[i].pIdiLib->hLib, ch+1, client_atap_on);
2016 }
2017 }
2018 }
2019
2020 for (i = 1; i < (sizeof(clients)/sizeof(clients[0])); i++) {
2021 if (clients[i].hDbg && clients[i].pIdiLib && clients[i].request && clients[i].request_pending) {
2022 diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "write_filter");
2023 clients[i].request_pending = 0;
2024 (*(clients[i].request))((ENTITY*)(*(clients[i].pIdiLib->DivaSTraceGetHandle))(clients[i].pIdiLib->hLib));
2025 diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "write_filter");
2026 }
2027 }
2028
2029 diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "write_filter");
2030 diva_os_leave_spin_lock (&dbg_adapter_lock, &old_irql1, "dbg mask");
2031
2032 return (filter_length);
2033}
2034
2035int diva_get_trace_filter (int max_length, char* filter) {
2036 diva_os_spin_lock_magic_t old_irql;
2037 int len;
2038
2039 diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "read_filter");
2040 len = strlen (&TraceFilter[0]) + 1;
2041 if (max_length >= len) {
2042 memcpy (filter, &TraceFilter[0], len);
2043 }
2044 diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "read_filter");
2045
2046 return (len);
2047}
2048
2049static int diva_dbg_cmp_key (const char* ref, const char* key) {
2050 while (*key && (*ref++ == *key++));
2051 return (!*key && !*ref);
2052}
2053
2054/*
2055 In case trace filter starts with "C" character then
2056 all following characters are interpreted as command.
2057 Followings commands are available:
2058 - single, trace single call at time, independent from CPN/CiPN
2059 */
2060static int diva_mnt_cmp_nmbr (const char* nmbr) {
2061 const char* ref = &TraceFilter[0];
2062 int ref_len = strlen(&TraceFilter[0]), nmbr_len = strlen(nmbr);
2063
2064 if (ref[0] == 'C') {
2065 if (diva_dbg_cmp_key (&ref[1], "single")) {
2066 return (0);
2067 }
2068 return (-1);
2069 }
2070
2071 if (!ref_len || (ref_len > nmbr_len)) {
2072 return (-1);
2073 }
2074
2075 nmbr = nmbr + nmbr_len - 1;
2076 ref = ref + ref_len - 1;
2077
2078 while (ref_len--) {
2079 if (*nmbr-- != *ref--) {
2080 return (-1);
2081 }
2082 }
2083
2084 return (0);
2085}
2086
2087static int diva_get_dma_descriptor (IDI_CALL request, dword *dma_magic) {
2088 ENTITY e;
2089 IDI_SYNC_REQ* pReq = (IDI_SYNC_REQ*)&e;
2090
2091 if (!request) {
2092 return (-1);
2093 }
2094
2095 pReq->xdi_dma_descriptor_operation.Req = 0;
2096 pReq->xdi_dma_descriptor_operation.Rc = IDI_SYNC_REQ_DMA_DESCRIPTOR_OPERATION;
2097
2098 pReq->xdi_dma_descriptor_operation.info.operation = IDI_SYNC_REQ_DMA_DESCRIPTOR_ALLOC;
2099 pReq->xdi_dma_descriptor_operation.info.descriptor_number = -1;
2100 pReq->xdi_dma_descriptor_operation.info.descriptor_address = NULL;
2101 pReq->xdi_dma_descriptor_operation.info.descriptor_magic = 0;
2102
2103 (*request)((ENTITY*)pReq);
2104
2105 if (!pReq->xdi_dma_descriptor_operation.info.operation &&
2106 (pReq->xdi_dma_descriptor_operation.info.descriptor_number >= 0) &&
2107 pReq->xdi_dma_descriptor_operation.info.descriptor_magic) {
2108 *dma_magic = pReq->xdi_dma_descriptor_operation.info.descriptor_magic;
2109 return (pReq->xdi_dma_descriptor_operation.info.descriptor_number);
2110 } else {
2111 return (-1);
2112 }
2113}
2114
2115static void diva_free_dma_descriptor (IDI_CALL request, int nr) {
2116 ENTITY e;
2117 IDI_SYNC_REQ* pReq = (IDI_SYNC_REQ*)&e;
2118
2119 if (!request || (nr < 0)) {
2120 return;
2121 }
2122
2123 pReq->xdi_dma_descriptor_operation.Req = 0;
2124 pReq->xdi_dma_descriptor_operation.Rc = IDI_SYNC_REQ_DMA_DESCRIPTOR_OPERATION;
2125
2126 pReq->xdi_dma_descriptor_operation.info.operation = IDI_SYNC_REQ_DMA_DESCRIPTOR_FREE;
2127 pReq->xdi_dma_descriptor_operation.info.descriptor_number = nr;
2128 pReq->xdi_dma_descriptor_operation.info.descriptor_address = NULL;
2129 pReq->xdi_dma_descriptor_operation.info.descriptor_magic = 0;
2130
2131 (*request)((ENTITY*)pReq);
2132}
2133
diff --git a/drivers/isdn/hardware/eicon/debug_if.h b/drivers/isdn/hardware/eicon/debug_if.h
new file mode 100644
index 000000000000..4db739d5803c
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/debug_if.h
@@ -0,0 +1,90 @@
1/*
2 *
3 Copyright (c) Eicon Technology Corporation, 2000.
4 *
5 This source file is supplied for the use with Eicon
6 Technology Corporation's range of DIVA Server Adapters.
7 *
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2, or (at your option)
11 any later version.
12 *
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
15 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16 See the GNU General Public License for more details.
17 *
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 *
22 */
23#ifndef __DIVA_DEBUG_IF_H__
24#define __DIVA_DEBUG_IF_H__
25#define MSG_TYPE_DRV_ID 0x0001
26#define MSG_TYPE_FLAGS 0x0002
27#define MSG_TYPE_STRING 0x0003
28#define MSG_TYPE_BINARY 0x0004
29#define MSG_TYPE_MLOG 0x0005
30
31#define MSG_FRAME_MAX_SIZE 2150
32
33typedef struct _diva_dbg_entry_head {
34 dword sequence;
35 dword time_sec;
36 dword time_usec;
37 dword facility;
38 dword dli;
39 dword drv_id;
40 dword di_cpu;
41 dword data_length;
42} diva_dbg_entry_head_t;
43
44int diva_maint_init (byte* base, unsigned long length, int do_init);
45void* diva_maint_finit (void);
46dword diva_dbg_q_length (void);
47diva_dbg_entry_head_t* diva_maint_get_message (word* size,
48 diva_os_spin_lock_magic_t* old_irql);
49void diva_maint_ack_message (int do_release,
50 diva_os_spin_lock_magic_t* old_irql);
51void diva_maint_prtComp (char *format, ...);
52void diva_maint_wakeup_read (void);
53int diva_get_driver_info (dword id, byte* data, int data_length);
54int diva_get_driver_dbg_mask (dword id, byte* data);
55int diva_set_driver_dbg_mask (dword id, dword mask);
56void diva_mnt_remove_xdi_adapter (const DESCRIPTOR* d);
57void diva_mnt_add_xdi_adapter (const DESCRIPTOR* d);
58int diva_mnt_shutdown_xdi_adapters (void);
59
60#define DIVA_MAX_SELECTIVE_FILTER_LENGTH 127
61int diva_set_trace_filter (int filter_length, const char* filter);
62int diva_get_trace_filter (int max_length, char* filter);
63
64
65#define DITRACE_CMD_GET_DRIVER_INFO 1
66#define DITRACE_READ_DRIVER_DBG_MASK 2
67#define DITRACE_WRITE_DRIVER_DBG_MASK 3
68#define DITRACE_READ_TRACE_ENTRY 4
69#define DITRACE_READ_TRACE_ENTRYS 5
70#define DITRACE_WRITE_SELECTIVE_TRACE_FILTER 6
71#define DITRACE_READ_SELECTIVE_TRACE_FILTER 7
72
73/*
74 Trace lavels for debug via management interface
75 */
76#define DIVA_MGT_DBG_TRACE 0x00000001 /* All trace messages from the card */
77#define DIVA_MGT_DBG_DCHAN 0x00000002 /* All D-channel relater trace messages */
78#define DIVA_MGT_DBG_MDM_PROGRESS 0x00000004 /* Modem progress events */
79#define DIVA_MGT_DBG_FAX_PROGRESS 0x00000008 /* Fax progress events */
80#define DIVA_MGT_DBG_IFC_STATISTICS 0x00000010 /* Interface call statistics */
81#define DIVA_MGT_DBG_MDM_STATISTICS 0x00000020 /* Global modem statistics */
82#define DIVA_MGT_DBG_FAX_STATISTICS 0x00000040 /* Global call statistics */
83#define DIVA_MGT_DBG_LINE_EVENTS 0x00000080 /* Line state events */
84#define DIVA_MGT_DBG_IFC_EVENTS 0x00000100 /* Interface/L1/L2 state events */
85#define DIVA_MGT_DBG_IFC_BCHANNEL 0x00000200 /* B-Channel trace for all channels */
86#define DIVA_MGT_DBG_IFC_AUDIO 0x00000400 /* Audio Tap trace for all channels */
87
88# endif /* DEBUG_IF___H */
89
90
diff --git a/drivers/isdn/hardware/eicon/debuglib.c b/drivers/isdn/hardware/eicon/debuglib.c
new file mode 100644
index 000000000000..a19b7ffe9ace
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/debuglib.c
@@ -0,0 +1,156 @@
1
2/*
3 *
4 Copyright (c) Eicon Networks, 2002.
5 *
6 This source file is supplied for the use with
7 Eicon Networks range of DIVA Server Adapters.
8 *
9 Eicon File Revision : 2.1
10 *
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2, or (at your option)
14 any later version.
15 *
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
18 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 See the GNU General Public License for more details.
20 *
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27#include "debuglib.h"
28
29#ifdef DIVA_NO_DEBUGLIB
30static DIVA_DI_PRINTF dprintf;
31#else /* DIVA_NO_DEBUGLIB */
32
33_DbgHandle_ myDriverDebugHandle = { 0 /*!Registered*/, DBG_HANDLE_VERSION };
34DIVA_DI_PRINTF dprintf = no_printf;
35/*****************************************************************************/
36#define DBG_FUNC(name) \
37void \
38myDbgPrint_##name (char *format, ...) \
39{ va_list ap ; \
40 if ( myDriverDebugHandle.dbg_prt ) \
41 { va_start (ap, format) ; \
42 (myDriverDebugHandle.dbg_prt) \
43 (myDriverDebugHandle.id, DLI_##name, format, ap) ; \
44 va_end (ap) ; \
45} }
46DBG_FUNC(LOG)
47DBG_FUNC(FTL)
48DBG_FUNC(ERR)
49DBG_FUNC(TRC)
50DBG_FUNC(MXLOG)
51DBG_FUNC(FTL_MXLOG)
52void
53myDbgPrint_EVL (long msgID, ...)
54{ va_list ap ;
55 if ( myDriverDebugHandle.dbg_ev )
56 { va_start (ap, msgID) ;
57 (myDriverDebugHandle.dbg_ev)
58 (myDriverDebugHandle.id, (unsigned long)msgID, ap) ;
59 va_end (ap) ;
60} }
61DBG_FUNC(REG)
62DBG_FUNC(MEM)
63DBG_FUNC(SPL)
64DBG_FUNC(IRP)
65DBG_FUNC(TIM)
66DBG_FUNC(BLK)
67DBG_FUNC(TAPI)
68DBG_FUNC(NDIS)
69DBG_FUNC(CONN)
70DBG_FUNC(STAT)
71DBG_FUNC(SEND)
72DBG_FUNC(RECV)
73DBG_FUNC(PRV0)
74DBG_FUNC(PRV1)
75DBG_FUNC(PRV2)
76DBG_FUNC(PRV3)
77/*****************************************************************************/
78int
79DbgRegister (char *drvName, char *drvTag, unsigned long dbgMask)
80{
81 int len;
82/*
83 * deregister (if already registered) and zero out myDriverDebugHandle
84 */
85 DbgDeregister () ;
86/*
87 * initialize the debug handle
88 */
89 myDriverDebugHandle.Version = DBG_HANDLE_VERSION ;
90 myDriverDebugHandle.id = -1 ;
91 myDriverDebugHandle.dbgMask = dbgMask | (DL_EVL | DL_FTL | DL_LOG) ;
92 len = strlen (drvName) ;
93 memcpy (myDriverDebugHandle.drvName, drvName,
94 (len < sizeof(myDriverDebugHandle.drvName)) ?
95 len : sizeof(myDriverDebugHandle.drvName) - 1) ;
96 len = strlen (drvTag) ;
97 memcpy (myDriverDebugHandle.drvTag, drvTag,
98 (len < sizeof(myDriverDebugHandle.drvTag)) ?
99 len : sizeof(myDriverDebugHandle.drvTag) - 1) ;
100/*
101 * Try to register debugging via old (and only) interface
102 */
103 dprintf("\000\377", &myDriverDebugHandle) ;
104 if ( myDriverDebugHandle.dbg_prt )
105 {
106 return (1) ;
107 }
108/*
109 * Check if we registered whith an old maint driver (see debuglib.h)
110 */
111 if ( myDriverDebugHandle.dbg_end != NULL
112 /* location of 'dbg_prt' in _OldDbgHandle_ struct */
113 && (myDriverDebugHandle.regTime.LowPart ||
114 myDriverDebugHandle.regTime.HighPart ) )
115 /* same location as in _OldDbgHandle_ struct */
116 {
117 dprintf("%s: Cannot log to old maint driver !", drvName) ;
118 myDriverDebugHandle.dbg_end =
119 ((_OldDbgHandle_ *)&myDriverDebugHandle)->dbg_end ;
120 DbgDeregister () ;
121 }
122 return (0) ;
123}
124/*****************************************************************************/
125void
126DbgSetLevel (unsigned long dbgMask)
127{
128 myDriverDebugHandle.dbgMask = dbgMask | (DL_EVL | DL_FTL | DL_LOG) ;
129}
130/*****************************************************************************/
131void
132DbgDeregister (void)
133{
134 if ( myDriverDebugHandle.dbg_end )
135 {
136 (myDriverDebugHandle.dbg_end)(&myDriverDebugHandle) ;
137 }
138 memset (&myDriverDebugHandle, 0, sizeof(myDriverDebugHandle)) ;
139}
140void xdi_dbg_xlog (char* x, ...) {
141 va_list ap;
142 va_start (ap, x);
143 if (myDriverDebugHandle.dbg_end &&
144 (myDriverDebugHandle.dbg_irq || myDriverDebugHandle.dbg_old) &&
145 (myDriverDebugHandle.dbgMask & DL_STAT)) {
146 if (myDriverDebugHandle.dbg_irq) {
147 (*(myDriverDebugHandle.dbg_irq))(myDriverDebugHandle.id,
148 (x[0] != 0) ? DLI_TRC : DLI_XLOG, x, ap);
149 } else {
150 (*(myDriverDebugHandle.dbg_old))(myDriverDebugHandle.id, x, ap);
151 }
152 }
153 va_end(ap);
154}
155/*****************************************************************************/
156#endif /* DIVA_NO_DEBUGLIB */
diff --git a/drivers/isdn/hardware/eicon/debuglib.h b/drivers/isdn/hardware/eicon/debuglib.h
new file mode 100644
index 000000000000..11b3b9edd1d6
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/debuglib.h
@@ -0,0 +1,322 @@
1
2/*
3 *
4 Copyright (c) Eicon Networks, 2002.
5 *
6 This source file is supplied for the use with
7 Eicon Networks range of DIVA Server Adapters.
8 *
9 Eicon File Revision : 2.1
10 *
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2, or (at your option)
14 any later version.
15 *
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
18 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 See the GNU General Public License for more details.
20 *
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26#if !defined(__DEBUGLIB_H__)
27#define __DEBUGLIB_H__
28#include <stdarg.h>
29/*
30 * define global debug priorities
31 */
32#define DL_LOG 0x00000001 /* always worth mentioning */
33#define DL_FTL 0x00000002 /* always sampled error */
34#define DL_ERR 0x00000004 /* any kind of error */
35#define DL_TRC 0x00000008 /* verbose information */
36#define DL_XLOG 0x00000010 /* old xlog info */
37#define DL_MXLOG 0x00000020 /* maestra xlog info */
38#define DL_FTL_MXLOG 0x00000021 /* fatal maestra xlog info */
39#define DL_EVL 0x00000080 /* special NT eventlog msg */
40#define DL_COMPAT (DL_MXLOG | DL_XLOG)
41#define DL_PRIOR_MASK (DL_EVL | DL_COMPAT | DL_TRC | DL_ERR | DL_FTL | DL_LOG)
42#define DLI_LOG 0x0100
43#define DLI_FTL 0x0200
44#define DLI_ERR 0x0300
45#define DLI_TRC 0x0400
46#define DLI_XLOG 0x0500
47#define DLI_MXLOG 0x0600
48#define DLI_FTL_MXLOG 0x0600
49#define DLI_EVL 0x0800
50/*
51 * define OS (operating system interface) debuglevel
52 */
53#define DL_REG 0x00000100 /* init/query registry */
54#define DL_MEM 0x00000200 /* memory management */
55#define DL_SPL 0x00000400 /* event/spinlock handling */
56#define DL_IRP 0x00000800 /* I/O request handling */
57#define DL_TIM 0x00001000 /* timer/watchdog handling */
58#define DL_BLK 0x00002000 /* raw data block contents */
59#define DL_OS_MASK (DL_BLK | DL_TIM | DL_IRP | DL_SPL | DL_MEM | DL_REG)
60#define DLI_REG 0x0900
61#define DLI_MEM 0x0A00
62#define DLI_SPL 0x0B00
63#define DLI_IRP 0x0C00
64#define DLI_TIM 0x0D00
65#define DLI_BLK 0x0E00
66/*
67 * define ISDN (connection interface) debuglevel
68 */
69#define DL_TAPI 0x00010000 /* debug TAPI interface */
70#define DL_NDIS 0x00020000 /* debug NDIS interface */
71#define DL_CONN 0x00040000 /* connection handling */
72#define DL_STAT 0x00080000 /* trace state machines */
73#define DL_SEND 0x00100000 /* trace raw xmitted data */
74#define DL_RECV 0x00200000 /* trace raw received data */
75#define DL_DATA (DL_SEND | DL_RECV)
76#define DL_ISDN_MASK (DL_DATA | DL_STAT | DL_CONN | DL_NDIS | DL_TAPI)
77#define DLI_TAPI 0x1100
78#define DLI_NDIS 0x1200
79#define DLI_CONN 0x1300
80#define DLI_STAT 0x1400
81#define DLI_SEND 0x1500
82#define DLI_RECV 0x1600
83/*
84 * define some private (unspecified) debuglevel
85 */
86#define DL_PRV0 0x01000000
87#define DL_PRV1 0x02000000
88#define DL_PRV2 0x04000000
89#define DL_PRV3 0x08000000
90#define DL_PRIV_MASK (DL_PRV0 | DL_PRV1 | DL_PRV2 | DL_PRV3)
91#define DLI_PRV0 0x1900
92#define DLI_PRV1 0x1A00
93#define DLI_PRV2 0x1B00
94#define DLI_PRV3 0x1C00
95#define DT_INDEX(x) ((x) & 0x000F)
96#define DL_INDEX(x) ((((x) >> 8) & 0x00FF) - 1)
97#define DLI_NAME(x) ((x) & 0xFF00)
98/*
99 * Debug mask for kernel mode tracing, if set the output is also sent to
100 * the system debug function. Requires that the project is compiled
101 * with _KERNEL_DBG_PRINT_
102 */
103#define DL_TO_KERNEL 0x40000000
104
105#ifdef DIVA_NO_DEBUGLIB
106#define myDbgPrint_LOG(x...) do { } while(0);
107#define myDbgPrint_FTL(x...) do { } while(0);
108#define myDbgPrint_ERR(x...) do { } while(0);
109#define myDbgPrint_TRC(x...) do { } while(0);
110#define myDbgPrint_MXLOG(x...) do { } while(0);
111#define myDbgPrint_EVL(x...) do { } while(0);
112#define myDbgPrint_REG(x...) do { } while(0);
113#define myDbgPrint_MEM(x...) do { } while(0);
114#define myDbgPrint_SPL(x...) do { } while(0);
115#define myDbgPrint_IRP(x...) do { } while(0);
116#define myDbgPrint_TIM(x...) do { } while(0);
117#define myDbgPrint_BLK(x...) do { } while(0);
118#define myDbgPrint_TAPI(x...) do { } while(0);
119#define myDbgPrint_NDIS(x...) do { } while(0);
120#define myDbgPrint_CONN(x...) do { } while(0);
121#define myDbgPrint_STAT(x...) do { } while(0);
122#define myDbgPrint_SEND(x...) do { } while(0);
123#define myDbgPrint_RECV(x...) do { } while(0);
124#define myDbgPrint_PRV0(x...) do { } while(0);
125#define myDbgPrint_PRV1(x...) do { } while(0);
126#define myDbgPrint_PRV2(x...) do { } while(0);
127#define myDbgPrint_PRV3(x...) do { } while(0);
128#define DBG_TEST(func,args) do { } while(0);
129#define DBG_EVL_ID(args) do { } while(0);
130
131#else /* DIVA_NO_DEBUGLIB */
132/*
133 * define low level macros for formatted & raw debugging
134 */
135#define DBG_DECL(func) extern void myDbgPrint_##func (char *, ...) ;
136DBG_DECL(LOG)
137DBG_DECL(FTL)
138DBG_DECL(ERR)
139DBG_DECL(TRC)
140DBG_DECL(MXLOG)
141DBG_DECL(FTL_MXLOG)
142extern void myDbgPrint_EVL (long, ...) ;
143DBG_DECL(REG)
144DBG_DECL(MEM)
145DBG_DECL(SPL)
146DBG_DECL(IRP)
147DBG_DECL(TIM)
148DBG_DECL(BLK)
149DBG_DECL(TAPI)
150DBG_DECL(NDIS)
151DBG_DECL(CONN)
152DBG_DECL(STAT)
153DBG_DECL(SEND)
154DBG_DECL(RECV)
155DBG_DECL(PRV0)
156DBG_DECL(PRV1)
157DBG_DECL(PRV2)
158DBG_DECL(PRV3)
159#ifdef _KERNEL_DBG_PRINT_
160/*
161 * tracing to maint and kernel if selected in the trace mask.
162 */
163#define DBG_TEST(func,args) \
164{ if ( (myDriverDebugHandle.dbgMask) & (unsigned long)DL_##func ) \
165 { \
166 if ( (myDriverDebugHandle.dbgMask) & DL_TO_KERNEL ) \
167 {DbgPrint args; DbgPrint ("\r\n");} \
168 myDbgPrint_##func args ; \
169} }
170#else
171/*
172 * Standard tracing to maint driver.
173 */
174#define DBG_TEST(func,args) \
175{ if ( (myDriverDebugHandle.dbgMask) & (unsigned long)DL_##func ) \
176 { myDbgPrint_##func args ; \
177} }
178#endif
179/*
180 * For event level debug use a separate define, the paramete are
181 * different and cause compiler errors on some systems.
182 */
183#define DBG_EVL_ID(args) \
184{ if ( (myDriverDebugHandle.dbgMask) & (unsigned long)DL_EVL ) \
185 { myDbgPrint_EVL args ; \
186} }
187
188#endif /* DIVA_NO_DEBUGLIB */
189
190#define DBG_LOG(args) DBG_TEST(LOG, args)
191#define DBG_FTL(args) DBG_TEST(FTL, args)
192#define DBG_ERR(args) DBG_TEST(ERR, args)
193#define DBG_TRC(args) DBG_TEST(TRC, args)
194#define DBG_MXLOG(args) DBG_TEST(MXLOG, args)
195#define DBG_FTL_MXLOG(args) DBG_TEST(FTL_MXLOG, args)
196#define DBG_EVL(args) DBG_EVL_ID(args)
197#define DBG_REG(args) DBG_TEST(REG, args)
198#define DBG_MEM(args) DBG_TEST(MEM, args)
199#define DBG_SPL(args) DBG_TEST(SPL, args)
200#define DBG_IRP(args) DBG_TEST(IRP, args)
201#define DBG_TIM(args) DBG_TEST(TIM, args)
202#define DBG_BLK(args) DBG_TEST(BLK, args)
203#define DBG_TAPI(args) DBG_TEST(TAPI, args)
204#define DBG_NDIS(args) DBG_TEST(NDIS, args)
205#define DBG_CONN(args) DBG_TEST(CONN, args)
206#define DBG_STAT(args) DBG_TEST(STAT, args)
207#define DBG_SEND(args) DBG_TEST(SEND, args)
208#define DBG_RECV(args) DBG_TEST(RECV, args)
209#define DBG_PRV0(args) DBG_TEST(PRV0, args)
210#define DBG_PRV1(args) DBG_TEST(PRV1, args)
211#define DBG_PRV2(args) DBG_TEST(PRV2, args)
212#define DBG_PRV3(args) DBG_TEST(PRV3, args)
213/*
214 * prototypes for debug register/deregister functions in "debuglib.c"
215 */
216#ifdef DIVA_NO_DEBUGLIB
217#define DbgRegister(name,tag, mask) do { } while(0)
218#define DbgDeregister() do { } while(0)
219#define DbgSetLevel(mask) do { } while(0)
220#else
221extern DIVA_DI_PRINTF dprintf;
222extern int DbgRegister (char *drvName, char *drvTag, unsigned long dbgMask) ;
223extern void DbgDeregister (void) ;
224extern void DbgSetLevel (unsigned long dbgMask) ;
225#endif
226/*
227 * driver internal structure for debug handling;
228 * in client drivers this structure is maintained in "debuglib.c",
229 * in the debug driver "debug.c" maintains a chain of such structs.
230 */
231typedef struct _DbgHandle_ *pDbgHandle ;
232typedef void ( * DbgEnd) (pDbgHandle) ;
233typedef void ( * DbgLog) (unsigned short, int, char *, va_list) ;
234typedef void ( * DbgOld) (unsigned short, char *, va_list) ;
235typedef void ( * DbgEv) (unsigned short, unsigned long, va_list) ;
236typedef void ( * DbgIrq) (unsigned short, int, char *, va_list) ;
237typedef struct _DbgHandle_
238{ char Registered ; /* driver successfull registered */
239#define DBG_HANDLE_REG_NEW 0x01 /* this (new) structure */
240#define DBG_HANDLE_REG_OLD 0x7f /* old structure (see below) */
241 char Version; /* version of this structure */
242#define DBG_HANDLE_VERSION 1 /* contains dbg_old function now */
243#define DBG_HANDLE_VER_EXT 2 /* pReserved points to extended info*/
244 short id ; /* internal id of registered driver */
245 struct _DbgHandle_ *next ; /* ptr to next registered driver */
246 struct /*LARGE_INTEGER*/ {
247 unsigned long LowPart;
248 long HighPart;
249 } regTime ; /* timestamp for registration */
250 void *pIrp ; /* ptr to pending i/o request */
251 unsigned long dbgMask ; /* current debug mask */
252 char drvName[16] ; /* ASCII name of registered driver */
253 char drvTag[64] ; /* revision string */
254 DbgEnd dbg_end ; /* function for debug closing */
255 DbgLog dbg_prt ; /* function for debug appending */
256 DbgOld dbg_old ; /* function for old debug appending */
257 DbgEv dbg_ev ; /* function for Windows NT Eventlog */
258 DbgIrq dbg_irq ; /* function for irql checked debug */
259 void *pReserved3 ;
260} _DbgHandle_ ;
261extern _DbgHandle_ myDriverDebugHandle ;
262typedef struct _OldDbgHandle_
263{ struct _OldDbgHandle_ *next ;
264 void *pIrp ;
265 long regTime[2] ;
266 unsigned long dbgMask ;
267 short id ;
268 char drvName[78] ;
269 DbgEnd dbg_end ;
270 DbgLog dbg_prt ;
271} _OldDbgHandle_ ;
272/* the differences in DbgHandles
273 old: tmp: new:
274 0 long next char Registered char Registered
275 char filler char Version
276 short id short id
277 4 long pIrp long regTime.lo long next
278 8 long regTime.lo long regTime.hi long regTime.lo
279 12 long regTime.hi long next long regTime.hi
280 16 long dbgMask long pIrp long pIrp
281 20 short id long dbgMask long dbgMask
282 22 char drvName[78] ..
283 24 .. char drvName[16] char drvName[16]
284 40 .. char drvTag[64] char drvTag[64]
285 100 void *dbg_end .. ..
286 104 void *dbg_prt void *dbg_end void *dbg_end
287 108 .. void *dbg_prt void *dbg_prt
288 112 .. .. void *dbg_old
289 116 .. .. void *dbg_ev
290 120 .. .. void *dbg_irq
291 124 .. .. void *pReserved3
292 ( new->id == 0 && *((short *)&new->dbgMask) == -1 ) identifies "old",
293 new->Registered and new->Version overlay old->next,
294 new->next overlays old->pIrp, new->regTime matches old->regTime and
295 thus these fields can be maintained in new struct whithout trouble;
296 id, dbgMask, drvName, dbg_end and dbg_prt need special handling !
297*/
298#define DBG_EXT_TYPE_CARD_TRACE 0x00000001
299typedef struct
300{
301 unsigned long ExtendedType;
302 union
303 {
304 /* DBG_EXT_TYPE_CARD_TRACE */
305 struct
306 {
307 void ( * MaskChangedNotify) (void *pContext);
308 unsigned long ModuleTxtMask;
309 unsigned long DebugLevel;
310 unsigned long B_ChannelMask;
311 unsigned long LogBufferSize;
312 } CardTrace;
313 }Data;
314} _DbgExtendedInfo_;
315#ifndef DIVA_NO_DEBUGLIB
316/* -------------------------------------------------------------
317 Function used for xlog-style debug
318 ------------------------------------------------------------- */
319#define XDI_USE_XLOG 1
320void xdi_dbg_xlog (char* x, ...);
321#endif /* DIVA_NO_DEBUGLIB */
322#endif /* __DEBUGLIB_H__ */
diff --git a/drivers/isdn/hardware/eicon/dfifo.h b/drivers/isdn/hardware/eicon/dfifo.h
new file mode 100644
index 000000000000..9a109c71e935
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/dfifo.h
@@ -0,0 +1,54 @@
1
2/*
3 *
4 Copyright (c) Eicon Networks, 2002.
5 *
6 This source file is supplied for the use with
7 Eicon Networks range of DIVA Server Adapters.
8 *
9 Eicon File Revision : 2.1
10 *
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2, or (at your option)
14 any later version.
15 *
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
18 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 See the GNU General Public License for more details.
20 *
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26#ifndef __DIVA_IDI_DFIFO_INC__
27#define __DIVA_IDI_DFIFO_INC__
28#define DIVA_DFIFO_CACHE_SZ 64 /* Used to isolate pipe from
29 rest of the world
30 should be divisible by 4
31 */
32#define DIVA_DFIFO_RAW_SZ (2512*8)
33#define DIVA_DFIFO_DATA_SZ 68
34#define DIVA_DFIFO_HDR_SZ 4
35#define DIVA_DFIFO_SEGMENT_SZ (DIVA_DFIFO_DATA_SZ+DIVA_DFIFO_HDR_SZ)
36#define DIVA_DFIFO_SEGMENTS ((DIVA_DFIFO_RAW_SZ)/(DIVA_DFIFO_SEGMENT_SZ)+1)
37#define DIVA_DFIFO_MEM_SZ (\
38 (DIVA_DFIFO_SEGMENT_SZ)*(DIVA_DFIFO_SEGMENTS)+\
39 (DIVA_DFIFO_CACHE_SZ)*2\
40 )
41#define DIVA_DFIFO_STEP DIVA_DFIFO_SEGMENT_SZ
42/* -------------------------------------------------------------------------
43 Block header layout is:
44 byte[0] -> flags
45 byte[1] -> length of data in block
46 byte[2] -> reserved
47 byte[4] -> reserved
48 ------------------------------------------------------------------------- */
49#define DIVA_DFIFO_WRAP 0x80 /* This is the last block in fifo */
50#define DIVA_DFIFO_READY 0x40 /* This block is ready for processing */
51#define DIVA_DFIFO_LAST 0x20 /* This block is last in message */
52#define DIVA_DFIFO_AUTO 0x10 /* Don't look for 'ready', don't ack */
53int diva_dfifo_create (void* start, int length);
54#endif
diff --git a/drivers/isdn/hardware/eicon/di.c b/drivers/isdn/hardware/eicon/di.c
new file mode 100644
index 000000000000..0617d7cabf06
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/di.c
@@ -0,0 +1,835 @@
1
2/*
3 *
4 Copyright (c) Eicon Networks, 2002.
5 *
6 This source file is supplied for the use with
7 Eicon Networks range of DIVA Server Adapters.
8 *
9 Eicon File Revision : 2.1
10 *
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2, or (at your option)
14 any later version.
15 *
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
18 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 See the GNU General Public License for more details.
20 *
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26#include "platform.h"
27#include "pc.h"
28#include "pr_pc.h"
29#include "di_defs.h"
30#include "di.h"
31#if !defined USE_EXTENDED_DEBUGS
32 #include "dimaint.h"
33#else
34 #define dprintf
35#endif
36#include "io.h"
37#include "dfifo.h"
38#define PR_RAM ((struct pr_ram *)0)
39#define RAM ((struct dual *)0)
40/*------------------------------------------------------------------*/
41/* local function prototypes */
42/*------------------------------------------------------------------*/
43void pr_out(ADAPTER * a);
44byte pr_dpc(ADAPTER * a);
45static byte pr_ready(ADAPTER * a);
46static byte isdn_rc(ADAPTER *, byte, byte, byte, word, dword, dword);
47static byte isdn_ind(ADAPTER *, byte, byte, byte, PBUFFER *, byte, word);
48/* -----------------------------------------------------------------
49 Functions used for the extended XDI Debug
50 macros
51 global convergence counter (used by all adapters)
52 Look by the implementation part of the functions
53 about the parameters.
54 If you change the dubugging parameters, then you should update
55 the aididbg.doc in the IDI doc's.
56 ----------------------------------------------------------------- */
57#if defined(XDI_USE_XLOG)
58#define XDI_A_NR(_x_) ((byte)(((ISDN_ADAPTER *)(_x_->io))->ANum))
59static void xdi_xlog (byte *msg, word code, int length);
60static byte xdi_xlog_sec = 0;
61#else
62#define XDI_A_NR(_x_) ((byte)0)
63#endif
64static void xdi_xlog_rc_event (byte Adapter,
65 byte Id, byte Ch, byte Rc, byte cb, byte type);
66static void xdi_xlog_request (byte Adapter, byte Id,
67 byte Ch, byte Req, byte type);
68static void xdi_xlog_ind (byte Adapter,
69 byte Id,
70 byte Ch,
71 byte Ind,
72 byte rnr_valid,
73 byte rnr,
74 byte type);
75/*------------------------------------------------------------------*/
76/* output function */
77/*------------------------------------------------------------------*/
78void pr_out(ADAPTER * a)
79{
80 byte e_no;
81 ENTITY * this = NULL;
82 BUFFERS *X;
83 word length;
84 word i;
85 word clength;
86 REQ * ReqOut;
87 byte more;
88 byte ReadyCount;
89 byte ReqCount;
90 byte Id;
91 dtrc(dprintf("pr_out"));
92 /* while a request is pending ... */
93 e_no = look_req(a);
94 if(!e_no)
95 {
96 dtrc(dprintf("no_req"));
97 return;
98 }
99 ReadyCount = pr_ready(a);
100 if(!ReadyCount)
101 {
102 dtrc(dprintf("not_ready"));
103 return;
104 }
105 ReqCount = 0;
106 while(e_no && ReadyCount) {
107 next_req(a);
108 this = entity_ptr(a, e_no);
109#ifdef USE_EXTENDED_DEBUGS
110 if ( !this )
111 {
112 DBG_FTL(("XDI: [%02x] !A%d ==> NULL entity ptr - try to ignore",
113 xdi_xlog_sec++, (int)((ISDN_ADAPTER *)a->io)->ANum))
114 e_no = look_req(a) ;
115 ReadyCount-- ;
116 continue ;
117 }
118 {
119 DBG_TRC((">A%d Id=0x%x Req=0x%x", ((ISDN_ADAPTER *)a->io)->ANum, this->Id, this->Req))
120 }
121#else
122 dbug(dprintf("out:Req=%x,Id=%x,Ch=%x",this->Req,this->Id,this->ReqCh));
123#endif
124 /* get address of next available request buffer */
125 ReqOut = (REQ *)&PR_RAM->B[a->ram_inw(a, &PR_RAM->NextReq)];
126#if defined(DIVA_ISTREAM)
127 if (!(a->tx_stream[this->Id] &&
128 this->Req == N_DATA)) {
129#endif
130 /* now copy the data from the current data buffer into the */
131 /* adapters request buffer */
132 length = 0;
133 i = this->XCurrent;
134 X = PTR_X(a,this);
135 while(i<this->XNum && length<270) {
136 clength = MIN((word)(270-length),X[i].PLength-this->XOffset);
137 a->ram_out_buffer(a,
138 &ReqOut->XBuffer.P[length],
139 PTR_P(a,this,&X[i].P[this->XOffset]),
140 clength);
141 length +=clength;
142 this->XOffset +=clength;
143 if(this->XOffset==X[i].PLength) {
144 this->XCurrent = (byte)++i;
145 this->XOffset = 0;
146 }
147 }
148#if defined(DIVA_ISTREAM)
149 } else { /* Use CMA extension in order to transfer data to the card */
150 i = this->XCurrent;
151 X = PTR_X(a,this);
152 while (i < this->XNum) {
153 diva_istream_write (a,
154 this->Id,
155 PTR_P(a,this,&X[i].P[0]),
156 X[i].PLength,
157 ((i+1) == this->XNum),
158 0, 0);
159 this->XCurrent = (byte)++i;
160 }
161 length = 0;
162 }
163#endif
164 a->ram_outw(a, &ReqOut->XBuffer.length, length);
165 a->ram_out(a, &ReqOut->ReqId, this->Id);
166 a->ram_out(a, &ReqOut->ReqCh, this->ReqCh);
167 /* if it's a specific request (no ASSIGN) ... */
168 if(this->Id &0x1f) {
169 /* if buffers are left in the list of data buffers do */
170 /* do chaining (LL_MDATA, N_MDATA) */
171 this->More++;
172 if(i<this->XNum && this->MInd) {
173 xdi_xlog_request (XDI_A_NR(a), this->Id, this->ReqCh, this->MInd,
174 a->IdTypeTable[this->No]);
175 a->ram_out(a, &ReqOut->Req, this->MInd);
176 more = TRUE;
177 }
178 else {
179 xdi_xlog_request (XDI_A_NR(a), this->Id, this->ReqCh, this->Req,
180 a->IdTypeTable[this->No]);
181 this->More |=XMOREF;
182 a->ram_out(a, &ReqOut->Req, this->Req);
183 more = FALSE;
184 if (a->FlowControlIdTable[this->ReqCh] == this->Id)
185 a->FlowControlSkipTable[this->ReqCh] = TRUE;
186 /*
187 Note that remove request was sent to the card
188 */
189 if (this->Req == REMOVE) {
190 a->misc_flags_table[e_no] |= DIVA_MISC_FLAGS_REMOVE_PENDING;
191 }
192 }
193 /* if we did chaining, this entity is put back into the */
194 /* request queue */
195 if(more) {
196 req_queue(a,this->No);
197 }
198 }
199 /* else it's a ASSIGN */
200 else {
201 /* save the request code used for buffer chaining */
202 this->MInd = 0;
203 if (this->Id==BLLC_ID) this->MInd = LL_MDATA;
204 if (this->Id==NL_ID ||
205 this->Id==TASK_ID ||
206 this->Id==MAN_ID
207 ) this->MInd = N_MDATA;
208 /* send the ASSIGN */
209 a->IdTypeTable[this->No] = this->Id;
210 xdi_xlog_request (XDI_A_NR(a),this->Id,this->ReqCh,this->Req, this->Id);
211 this->More |=XMOREF;
212 a->ram_out(a, &ReqOut->Req, this->Req);
213 /* save the reference of the ASSIGN */
214 assign_queue(a, this->No, a->ram_inw(a, &ReqOut->Reference));
215 }
216 a->ram_outw(a, &PR_RAM->NextReq, a->ram_inw(a, &ReqOut->next));
217 ReadyCount--;
218 ReqCount++;
219 e_no = look_req(a);
220 }
221 /* send the filled request buffers to the ISDN adapter */
222 a->ram_out(a, &PR_RAM->ReqInput,
223 (byte)(a->ram_in(a, &PR_RAM->ReqInput) + ReqCount));
224 /* if it is a 'unreturncoded' UREMOVE request, remove the */
225 /* Id from our table after sending the request */
226 if(this && (this->Req==UREMOVE) && this->Id) {
227 Id = this->Id;
228 e_no = a->IdTable[Id];
229 free_entity(a, e_no);
230 for (i = 0; i < 256; i++)
231 {
232 if (a->FlowControlIdTable[i] == Id)
233 a->FlowControlIdTable[i] = 0;
234 }
235 a->IdTable[Id] = 0;
236 this->Id = 0;
237 }
238}
239static byte pr_ready(ADAPTER * a)
240{
241 byte ReadyCount;
242 ReadyCount = (byte)(a->ram_in(a, &PR_RAM->ReqOutput) -
243 a->ram_in(a, &PR_RAM->ReqInput));
244 if(!ReadyCount) {
245 if(!a->ReadyInt) {
246 a->ram_inc(a, &PR_RAM->ReadyInt);
247 a->ReadyInt++;
248 }
249 }
250 return ReadyCount;
251}
252/*------------------------------------------------------------------*/
253/* isdn interrupt handler */
254/*------------------------------------------------------------------*/
255byte pr_dpc(ADAPTER * a)
256{
257 byte Count;
258 RC * RcIn;
259 IND * IndIn;
260 byte c;
261 byte RNRId;
262 byte Rc;
263 byte Ind;
264 /* if return codes are available ... */
265 if((Count = a->ram_in(a, &PR_RAM->RcOutput)) != 0) {
266 dtrc(dprintf("#Rc=%x",Count));
267 /* get the buffer address of the first return code */
268 RcIn = (RC *)&PR_RAM->B[a->ram_inw(a, &PR_RAM->NextRc)];
269 /* for all return codes do ... */
270 while(Count--) {
271 if((Rc=a->ram_in(a, &RcIn->Rc)) != 0) {
272 dword tmp[2];
273 /*
274 Get extended information, associated with return code
275 */
276 a->ram_in_buffer(a,
277 &RcIn->Reserved2[0],
278 (byte*)&tmp[0],
279 8);
280 /* call return code handler, if it is not our return code */
281 /* the handler returns 2 */
282 /* for all return codes we process, we clear the Rc field */
283 isdn_rc(a,
284 Rc,
285 a->ram_in(a, &RcIn->RcId),
286 a->ram_in(a, &RcIn->RcCh),
287 a->ram_inw(a, &RcIn->Reference),
288 tmp[0], /* type of extended informtion */
289 tmp[1]); /* extended information */
290 a->ram_out(a, &RcIn->Rc, 0);
291 }
292 /* get buffer address of next return code */
293 RcIn = (RC *)&PR_RAM->B[a->ram_inw(a, &RcIn->next)];
294 }
295 /* clear all return codes (no chaining!) */
296 a->ram_out(a, &PR_RAM->RcOutput ,0);
297 /* call output function */
298 pr_out(a);
299 }
300 /* clear RNR flag */
301 RNRId = 0;
302 /* if indications are available ... */
303 if((Count = a->ram_in(a, &PR_RAM->IndOutput)) != 0) {
304 dtrc(dprintf("#Ind=%x",Count));
305 /* get the buffer address of the first indication */
306 IndIn = (IND *)&PR_RAM->B[a->ram_inw(a, &PR_RAM->NextInd)];
307 /* for all indications do ... */
308 while(Count--) {
309 /* if the application marks an indication as RNR, all */
310 /* indications from the same Id delivered in this interrupt */
311 /* are marked RNR */
312 if(RNRId && RNRId==a->ram_in(a, &IndIn->IndId)) {
313 a->ram_out(a, &IndIn->Ind, 0);
314 a->ram_out(a, &IndIn->RNR, TRUE);
315 }
316 else {
317 Ind = a->ram_in(a, &IndIn->Ind);
318 if(Ind) {
319 RNRId = 0;
320 /* call indication handler, a return value of 2 means chain */
321 /* a return value of 1 means RNR */
322 /* for all indications we process, we clear the Ind field */
323 c = isdn_ind(a,
324 Ind,
325 a->ram_in(a, &IndIn->IndId),
326 a->ram_in(a, &IndIn->IndCh),
327 &IndIn->RBuffer,
328 a->ram_in(a, &IndIn->MInd),
329 a->ram_inw(a, &IndIn->MLength));
330 if(c==1) {
331 dtrc(dprintf("RNR"));
332 a->ram_out(a, &IndIn->Ind, 0);
333 RNRId = a->ram_in(a, &IndIn->IndId);
334 a->ram_out(a, &IndIn->RNR, TRUE);
335 }
336 }
337 }
338 /* get buffer address of next indication */
339 IndIn = (IND *)&PR_RAM->B[a->ram_inw(a, &IndIn->next)];
340 }
341 a->ram_out(a, &PR_RAM->IndOutput, 0);
342 }
343 return FALSE;
344}
345byte scom_test_int(ADAPTER * a)
346{
347 return a->ram_in(a,(void *)0x3fe);
348}
349void scom_clear_int(ADAPTER * a)
350{
351 a->ram_out(a,(void *)0x3fe,0);
352}
353/*------------------------------------------------------------------*/
354/* return code handler */
355/*------------------------------------------------------------------*/
356byte isdn_rc(ADAPTER * a,
357 byte Rc,
358 byte Id,
359 byte Ch,
360 word Ref,
361 dword extended_info_type,
362 dword extended_info)
363{
364 ENTITY * this;
365 byte e_no;
366 word i;
367 int cancel_rc;
368#ifdef USE_EXTENDED_DEBUGS
369 {
370 DBG_TRC(("<A%d Id=0x%x Rc=0x%x", ((ISDN_ADAPTER *)a->io)->ANum, Id, Rc))
371 }
372#else
373 dbug(dprintf("isdn_rc(Rc=%x,Id=%x,Ch=%x)",Rc,Id,Ch));
374#endif
375 /* check for ready interrupt */
376 if(Rc==READY_INT) {
377 xdi_xlog_rc_event (XDI_A_NR(a), Id, Ch, Rc, 0, 0);
378 if(a->ReadyInt) {
379 a->ReadyInt--;
380 return 0;
381 }
382 return 2;
383 }
384 /* if we know this Id ... */
385 e_no = a->IdTable[Id];
386 if(e_no) {
387 this = entity_ptr(a,e_no);
388 xdi_xlog_rc_event (XDI_A_NR(a), Id, Ch, Rc, 0, a->IdTypeTable[this->No]);
389 this->RcCh = Ch;
390 /* if it is a return code to a REMOVE request, remove the */
391 /* Id from our table */
392 if ((a->misc_flags_table[e_no] & DIVA_MISC_FLAGS_REMOVE_PENDING) &&
393 (Rc==OK)) {
394 if (a->IdTypeTable[e_no] == NL_ID) {
395 if (a->RcExtensionSupported &&
396 (extended_info_type != DIVA_RC_TYPE_REMOVE_COMPLETE)) {
397 dtrc(dprintf("XDI: N-REMOVE, A(%02x) Id:%02x, ignore RC=OK",
398 XDI_A_NR(a),Id));
399 return (0);
400 }
401 if (extended_info_type == DIVA_RC_TYPE_REMOVE_COMPLETE)
402 a->RcExtensionSupported = TRUE;
403 }
404 a->misc_flags_table[e_no] &= ~DIVA_MISC_FLAGS_REMOVE_PENDING;
405 a->misc_flags_table[e_no] &= ~DIVA_MISC_FLAGS_NO_RC_CANCELLING;
406 free_entity(a, e_no);
407 for (i = 0; i < 256; i++)
408 {
409 if (a->FlowControlIdTable[i] == Id)
410 a->FlowControlIdTable[i] = 0;
411 }
412 a->IdTable[Id] = 0;
413 this->Id = 0;
414 /* ---------------------------------------------------------------
415 If we send N_DISC or N_DISK_ACK after we have received OK_FC
416 then the card will respond with OK_FC and later with RC==OK.
417 If we send N_REMOVE in this state we will receive only RC==OK
418 This will create the state in that the XDI is waiting for the
419 additional RC and does not delivery the RC to the client. This
420 code corrects the counter of outstanding RC's in this case.
421 --------------------------------------------------------------- */
422 if ((this->More & XMOREC) > 1) {
423 this->More &= ~XMOREC;
424 this->More |= 1;
425 dtrc(dprintf("XDI: correct MORE on REMOVE A(%02x) Id:%02x",
426 XDI_A_NR(a),Id));
427 }
428 }
429 if (Rc==OK_FC) {
430 a->FlowControlIdTable[Ch] = Id;
431 a->FlowControlSkipTable[Ch] = FALSE;
432 this->Rc = Rc;
433 this->More &= ~(XBUSY | XMOREC);
434 this->complete=0xff;
435 xdi_xlog_rc_event (XDI_A_NR(a), Id, Ch, Rc, 1, a->IdTypeTable[this->No]);
436 CALLBACK(a, this);
437 return 0;
438 }
439 /*
440 New protocol code sends return codes that comes from release
441 of flow control condition marked with DIVA_RC_TYPE_OK_FC extended
442 information element type.
443 If like return code arrives then application is able to process
444 all return codes self and XDI should not cances return codes.
445 This return code does not decrement XMOREC partial return code
446 counter due to fact that it was no request for this return code,
447 also XMOREC was not incremented.
448 */
449 if (extended_info_type == DIVA_RC_TYPE_OK_FC) {
450 a->misc_flags_table[e_no] |= DIVA_MISC_FLAGS_NO_RC_CANCELLING;
451 this->Rc = Rc;
452 this->complete=0xff;
453 xdi_xlog_rc_event (XDI_A_NR(a), Id, Ch, Rc, 1, a->IdTypeTable[this->No]);
454 DBG_TRC(("XDI OK_FC A(%02x) Id:%02x Ch:%02x Rc:%02x",
455 XDI_A_NR(a), Id, Ch, Rc))
456 CALLBACK(a, this);
457 return 0;
458 }
459 cancel_rc = !(a->misc_flags_table[e_no] & DIVA_MISC_FLAGS_NO_RC_CANCELLING);
460 if (cancel_rc && (a->FlowControlIdTable[Ch] == Id))
461 {
462 a->FlowControlIdTable[Ch] = 0;
463 if ((Rc != OK) || !a->FlowControlSkipTable[Ch])
464 {
465 this->Rc = Rc;
466 if (Ch == this->ReqCh)
467 {
468 this->More &=~(XBUSY | XMOREC);
469 this->complete=0xff;
470 }
471 xdi_xlog_rc_event (XDI_A_NR(a), Id, Ch, Rc, 1, a->IdTypeTable[this->No]);
472 CALLBACK(a, this);
473 }
474 return 0;
475 }
476 if (this->More &XMOREC)
477 this->More--;
478 /* call the application callback function */
479 if (((!cancel_rc) || (this->More & XMOREF)) && !(this->More & XMOREC)) {
480 this->Rc = Rc;
481 this->More &=~XBUSY;
482 this->complete=0xff;
483 xdi_xlog_rc_event (XDI_A_NR(a), Id, Ch, Rc, 1, a->IdTypeTable[this->No]);
484 CALLBACK(a, this);
485 }
486 return 0;
487 }
488 /* if it's an ASSIGN return code check if it's a return */
489 /* code to an ASSIGN request from us */
490 if((Rc &0xf0)==ASSIGN_RC) {
491 e_no = get_assign(a, Ref);
492 if(e_no) {
493 this = entity_ptr(a,e_no);
494 this->Id = Id;
495 xdi_xlog_rc_event (XDI_A_NR(a), Id, Ch, Rc, 2, a->IdTypeTable[this->No]);
496 /* call the application callback function */
497 this->Rc = Rc;
498 this->More &=~XBUSY;
499 this->complete=0xff;
500#if defined(DIVA_ISTREAM) /* { */
501 if ((Rc == ASSIGN_OK) && a->ram_offset &&
502 (a->IdTypeTable[this->No] == NL_ID) &&
503 ((extended_info_type == DIVA_RC_TYPE_RX_DMA) ||
504 (extended_info_type == DIVA_RC_TYPE_CMA_PTR)) &&
505 extended_info) {
506 dword offset = (*(a->ram_offset)) (a);
507 dword tmp[2];
508 extended_info -= offset;
509#ifdef PLATFORM_GT_32BIT
510 a->ram_in_dw(a, (void*)ULongToPtr(extended_info), (dword*)&tmp[0], 2);
511#else
512 a->ram_in_dw(a, (void*)extended_info, (dword*)&tmp[0], 2);
513#endif
514 a->tx_stream[Id] = tmp[0];
515 a->rx_stream[Id] = tmp[1];
516 if (extended_info_type == DIVA_RC_TYPE_RX_DMA) {
517 DBG_TRC(("Id=0x%x RxDMA=%08x:%08x",
518 Id, a->tx_stream[Id], a->rx_stream[Id]))
519 a->misc_flags_table[this->No] |= DIVA_MISC_FLAGS_RX_DMA;
520 } else {
521 DBG_TRC(("Id=0x%x CMA=%08x:%08x",
522 Id, a->tx_stream[Id], a->rx_stream[Id]))
523 a->misc_flags_table[this->No] &= ~DIVA_MISC_FLAGS_RX_DMA;
524 a->rx_pos[Id] = 0;
525 a->rx_stream[Id] -= offset;
526 }
527 a->tx_pos[Id] = 0;
528 a->tx_stream[Id] -= offset;
529 } else {
530 a->tx_stream[Id] = 0;
531 a->rx_stream[Id] = 0;
532 a->misc_flags_table[this->No] &= ~DIVA_MISC_FLAGS_RX_DMA;
533 }
534#endif /* } */
535 CALLBACK(a, this);
536 if(Rc==ASSIGN_OK) {
537 a->IdTable[Id] = e_no;
538 }
539 else
540 {
541 free_entity(a, e_no);
542 for (i = 0; i < 256; i++)
543 {
544 if (a->FlowControlIdTable[i] == Id)
545 a->FlowControlIdTable[i] = 0;
546 }
547 a->IdTable[Id] = 0;
548 this->Id = 0;
549 }
550 return 1;
551 }
552 }
553 return 2;
554}
555/*------------------------------------------------------------------*/
556/* indication handler */
557/*------------------------------------------------------------------*/
558byte isdn_ind(ADAPTER * a,
559 byte Ind,
560 byte Id,
561 byte Ch,
562 PBUFFER * RBuffer,
563 byte MInd,
564 word MLength)
565{
566 ENTITY * this;
567 word clength;
568 word offset;
569 BUFFERS *R;
570 byte* cma = NULL;
571#ifdef USE_EXTENDED_DEBUGS
572 {
573 DBG_TRC(("<A%d Id=0x%x Ind=0x%x", ((ISDN_ADAPTER *)a->io)->ANum, Id, Ind))
574 }
575#else
576 dbug(dprintf("isdn_ind(Ind=%x,Id=%x,Ch=%x)",Ind,Id,Ch));
577#endif
578 if(a->IdTable[Id]) {
579 this = entity_ptr(a,a->IdTable[Id]);
580 this->IndCh = Ch;
581 xdi_xlog_ind (XDI_A_NR(a), Id, Ch, Ind,
582 0/* rnr_valid */, 0 /* rnr */, a->IdTypeTable[this->No]);
583 /* if the Receive More flag is not yet set, this is the */
584 /* first buffer of the packet */
585 if(this->RCurrent==0xff) {
586 /* check for receive buffer chaining */
587 if(Ind==this->MInd) {
588 this->complete = 0;
589 this->Ind = MInd;
590 }
591 else {
592 this->complete = 1;
593 this->Ind = Ind;
594 }
595 /* call the application callback function for the receive */
596 /* look ahead */
597 this->RLength = MLength;
598#if defined(DIVA_ISTREAM)
599 if ((a->rx_stream[this->Id] ||
600 (a->misc_flags_table[this->No] & DIVA_MISC_FLAGS_RX_DMA)) &&
601 ((Ind == N_DATA) ||
602 (a->protocol_capabilities & PROTCAP_CMA_ALLPR))) {
603 PISDN_ADAPTER IoAdapter = (PISDN_ADAPTER)a->io ;
604 if (a->misc_flags_table[this->No] & DIVA_MISC_FLAGS_RX_DMA) {
605#if defined(DIVA_IDI_RX_DMA)
606 dword d;
607 diva_get_dma_map_entry (\
608 (struct _diva_dma_map_entry*)IoAdapter->dma_map,
609 (int)a->rx_stream[this->Id], (void**)&cma, &d);
610#else
611 cma = &a->stream_buffer[0];
612 cma[0] = cma[1] = cma[2] = cma[3] = 0;
613#endif
614 this->RLength = MLength = (word)*(dword*)cma;
615 cma += 4;
616 } else {
617 int final = 0;
618 cma = &a->stream_buffer[0];
619 this->RLength = MLength = (word)diva_istream_read (a,
620 Id,
621 cma,
622 sizeof(a->stream_buffer),
623 &final, NULL, NULL);
624 }
625 IoAdapter->RBuffer.length = MIN(MLength, 270);
626 if (IoAdapter->RBuffer.length != MLength) {
627 this->complete = 0;
628 } else {
629 this->complete = 1;
630 }
631 memcpy (IoAdapter->RBuffer.P, cma, IoAdapter->RBuffer.length) ;
632 this->RBuffer = (DBUFFER *)&IoAdapter->RBuffer ;
633 }
634#endif
635 if (!cma) {
636 a->ram_look_ahead(a, RBuffer, this);
637 }
638 this->RNum = 0;
639 CALLBACK(a, this);
640 /* map entity ptr, selector could be re-mapped by call to */
641 /* IDI from within callback */
642 this = entity_ptr(a,a->IdTable[Id]);
643 xdi_xlog_ind (XDI_A_NR(a), Id, Ch, Ind,
644 1/* rnr_valid */, this->RNR/* rnr */, a->IdTypeTable[this->No]);
645 /* check for RNR */
646 if(this->RNR==1) {
647 this->RNR = 0;
648 return 1;
649 }
650 /* if no buffers are provided by the application, the */
651 /* application want to copy the data itself including */
652 /* N_MDATA/LL_MDATA chaining */
653 if(!this->RNR && !this->RNum) {
654 xdi_xlog_ind (XDI_A_NR(a), Id, Ch, Ind,
655 2/* rnr_valid */, 0/* rnr */, a->IdTypeTable[this->No]);
656 return 0;
657 }
658 /* if there is no RNR, set the More flag */
659 this->RCurrent = 0;
660 this->ROffset = 0;
661 }
662 if(this->RNR==2) {
663 if(Ind!=this->MInd) {
664 this->RCurrent = 0xff;
665 this->RNR = 0;
666 }
667 return 0;
668 }
669 /* if we have received buffers from the application, copy */
670 /* the data into these buffers */
671 offset = 0;
672 R = PTR_R(a,this);
673 do {
674 if(this->ROffset==R[this->RCurrent].PLength) {
675 this->ROffset = 0;
676 this->RCurrent++;
677 }
678 if (cma) {
679 clength = MIN(MLength, R[this->RCurrent].PLength-this->ROffset);
680 } else {
681 clength = MIN(a->ram_inw(a, &RBuffer->length)-offset,
682 R[this->RCurrent].PLength-this->ROffset);
683 }
684 if(R[this->RCurrent].P) {
685 if (cma) {
686 memcpy (PTR_P(a,this,&R[this->RCurrent].P[this->ROffset]),
687 &cma[offset],
688 clength);
689 } else {
690 a->ram_in_buffer(a,
691 &RBuffer->P[offset],
692 PTR_P(a,this,&R[this->RCurrent].P[this->ROffset]),
693 clength);
694 }
695 }
696 offset +=clength;
697 this->ROffset +=clength;
698 if (cma) {
699 if (offset >= MLength) {
700 break;
701 }
702 continue;
703 }
704 } while(offset<(a->ram_inw(a, &RBuffer->length)));
705 /* if it's the last buffer of the packet, call the */
706 /* application callback function for the receive complete */
707 /* call */
708 if(Ind!=this->MInd) {
709 R[this->RCurrent].PLength = this->ROffset;
710 if(this->ROffset) this->RCurrent++;
711 this->RNum = this->RCurrent;
712 this->RCurrent = 0xff;
713 this->Ind = Ind;
714 this->complete = 2;
715 xdi_xlog_ind (XDI_A_NR(a), Id, Ch, Ind,
716 3/* rnr_valid */, 0/* rnr */, a->IdTypeTable[this->No]);
717 CALLBACK(a, this);
718 }
719 return 0;
720 }
721 return 2;
722}
723#if defined(XDI_USE_XLOG)
724/* -----------------------------------------------------------
725 This function works in the same way as xlog on the
726 active board
727 ----------------------------------------------------------- */
728static void xdi_xlog (byte *msg, word code, int length) {
729 xdi_dbg_xlog ("\x00\x02", msg, code, length);
730}
731#endif
732/* -----------------------------------------------------------
733 This function writes the information about the Return Code
734 processing in the trace buffer. Trace ID is 221.
735 INPUT:
736 Adapter - system unicue adapter number (0 ... 255)
737 Id - Id of the entity that had sent this return code
738 Ch - Channel of the entity that had sent this return code
739 Rc - return code value
740 cb: (0...2)
741 switch (cb) {
742 case 0: printf ("DELIVERY"); break;
743 case 1: printf ("CALLBACK"); break;
744 case 2: printf ("ASSIGN"); break;
745 }
746 DELIVERY - have entered isdn_rc with this RC
747 CALLBACK - about to make callback to the application
748 for this RC
749 ASSIGN - about to make callback for RC that is result
750 of ASSIGN request. It is no DELIVERY message
751 before of this message
752 type - the Id that was sent by the ASSIGN of this entity.
753 This should be global Id like NL_ID, DSIG_ID, MAN_ID.
754 An unknown Id will cause "?-" in the front of the request.
755 In this case the log.c is to be extended.
756 ----------------------------------------------------------- */
757static void xdi_xlog_rc_event (byte Adapter,
758 byte Id, byte Ch, byte Rc, byte cb, byte type) {
759#if defined(XDI_USE_XLOG)
760 word LogInfo[4];
761 PUT_WORD(&LogInfo[0], ((word)Adapter | (word)(xdi_xlog_sec++ << 8)));
762 PUT_WORD(&LogInfo[1], ((word)Id | (word)(Ch << 8)));
763 PUT_WORD(&LogInfo[2], ((word)Rc | (word)(type << 8)));
764 PUT_WORD(&LogInfo[3], cb);
765 xdi_xlog ((byte*)&LogInfo[0], 221, sizeof(LogInfo));
766#endif
767}
768/* ------------------------------------------------------------------------
769 This function writes the information about the request processing
770 in the trace buffer. Trace ID is 220.
771 INPUT:
772 Adapter - system unicue adapter number (0 ... 255)
773 Id - Id of the entity that had sent this request
774 Ch - Channel of the entity that had sent this request
775 Req - Code of the request
776 type - the Id that was sent by the ASSIGN of this entity.
777 This should be global Id like NL_ID, DSIG_ID, MAN_ID.
778 An unknown Id will cause "?-" in the front of the request.
779 In this case the log.c is to be extended.
780 ------------------------------------------------------------------------ */
781static void xdi_xlog_request (byte Adapter, byte Id,
782 byte Ch, byte Req, byte type) {
783#if defined(XDI_USE_XLOG)
784 word LogInfo[3];
785 PUT_WORD(&LogInfo[0], ((word)Adapter | (word)(xdi_xlog_sec++ << 8)));
786 PUT_WORD(&LogInfo[1], ((word)Id | (word)(Ch << 8)));
787 PUT_WORD(&LogInfo[2], ((word)Req | (word)(type << 8)));
788 xdi_xlog ((byte*)&LogInfo[0], 220, sizeof(LogInfo));
789#endif
790}
791/* ------------------------------------------------------------------------
792 This function writes the information about the indication processing
793 in the trace buffer. Trace ID is 222.
794 INPUT:
795 Adapter - system unicue adapter number (0 ... 255)
796 Id - Id of the entity that had sent this indication
797 Ch - Channel of the entity that had sent this indication
798 Ind - Code of the indication
799 rnr_valid: (0 .. 3) supported
800 switch (rnr_valid) {
801 case 0: printf ("DELIVERY"); break;
802 case 1: printf ("RNR=%d", rnr);
803 case 2: printf ("RNum=0");
804 case 3: printf ("COMPLETE");
805 }
806 DELIVERY - indication entered isdn_rc function
807 RNR=... - application had returned RNR=... after the
808 look ahead callback
809 RNum=0 - aplication had not returned any buffer to copy
810 this indication and will copy it self
811 COMPLETE - XDI had copied the data to the buffers provided
812 bu the application and is about to issue the
813 final callback
814 rnr: Look case 1 of the rnr_valid
815 type: the Id that was sent by the ASSIGN of this entity. This should
816 be global Id like NL_ID, DSIG_ID, MAN_ID. An unknown Id will
817 cause "?-" in the front of the request. In this case the
818 log.c is to be extended.
819 ------------------------------------------------------------------------ */
820static void xdi_xlog_ind (byte Adapter,
821 byte Id,
822 byte Ch,
823 byte Ind,
824 byte rnr_valid,
825 byte rnr,
826 byte type) {
827#if defined(XDI_USE_XLOG)
828 word LogInfo[4];
829 PUT_WORD(&LogInfo[0], ((word)Adapter | (word)(xdi_xlog_sec++ << 8)));
830 PUT_WORD(&LogInfo[1], ((word)Id | (word)(Ch << 8)));
831 PUT_WORD(&LogInfo[2], ((word)Ind | (word)(type << 8)));
832 PUT_WORD(&LogInfo[3], ((word)rnr | (word)(rnr_valid << 8)));
833 xdi_xlog ((byte*)&LogInfo[0], 222, sizeof(LogInfo));
834#endif
835}
diff --git a/drivers/isdn/hardware/eicon/di.h b/drivers/isdn/hardware/eicon/di.h
new file mode 100644
index 000000000000..dcf37b10f5dc
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/di.h
@@ -0,0 +1,118 @@
1
2/*
3 *
4 Copyright (c) Eicon Networks, 2002.
5 *
6 This source file is supplied for the use with
7 Eicon Networks range of DIVA Server Adapters.
8 *
9 Eicon File Revision : 2.1
10 *
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2, or (at your option)
14 any later version.
15 *
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
18 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 See the GNU General Public License for more details.
20 *
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26/*
27 * some macros for detailed trace management
28 */
29#include "di_dbg.h"
30/*****************************************************************************/
31#define XMOREC 0x1f
32#define XMOREF 0x20
33#define XBUSY 0x40
34#define RMORE 0x80
35#define DIVA_MISC_FLAGS_REMOVE_PENDING 0x01
36#define DIVA_MISC_FLAGS_NO_RC_CANCELLING 0x02
37#define DIVA_MISC_FLAGS_RX_DMA 0x04
38 /* structure for all information we have to keep on a per */
39 /* adapater basis */
40typedef struct adapter_s ADAPTER;
41struct adapter_s {
42 void * io;
43 byte IdTable[256];
44 byte IdTypeTable[256];
45 byte FlowControlIdTable[256];
46 byte FlowControlSkipTable[256];
47 byte ReadyInt;
48 byte RcExtensionSupported;
49 byte misc_flags_table[256];
50 dword protocol_capabilities;
51 byte ( * ram_in)(ADAPTER * a, void * adr);
52 word ( * ram_inw)(ADAPTER * a, void * adr);
53 void (* ram_in_buffer)(ADAPTER * a, void * adr, void * P, word length);
54 void (* ram_look_ahead)(ADAPTER * a, PBUFFER * RBuffer, ENTITY * e);
55 void ( * ram_out)(ADAPTER * a, void * adr, byte data);
56 void ( * ram_outw)(ADAPTER * a, void * adr, word data);
57 void (* ram_out_buffer)(ADAPTER * a, void * adr, void * P, word length);
58 void ( * ram_inc)(ADAPTER * a, void * adr);
59#if defined(DIVA_ISTREAM)
60 dword rx_stream[256];
61 dword tx_stream[256];
62 word tx_pos[256];
63 word rx_pos[256];
64 byte stream_buffer[2512];
65 dword ( * ram_offset)(ADAPTER * a);
66 void ( * ram_out_dw) (ADAPTER *a,
67 void *addr,
68 const dword* data,
69 int dwords);
70 void ( * ram_in_dw) (ADAPTER *a,
71 void *addr,
72 dword* data,
73 int dwords);
74 void ( * istream_wakeup)(ADAPTER* a);
75#else
76 byte stream_buffer[4];
77#endif
78};
79/*------------------------------------------------------------------*/
80/* public functions of IDI common code */
81/*------------------------------------------------------------------*/
82void pr_out(ADAPTER * a);
83byte pr_dpc(ADAPTER * a);
84byte scom_test_int(ADAPTER * a);
85void scom_clear_int(ADAPTER * a);
86/*------------------------------------------------------------------*/
87/* OS specific functions used by IDI common code */
88/*------------------------------------------------------------------*/
89void free_entity(ADAPTER * a, byte e_no);
90void assign_queue(ADAPTER * a, byte e_no, word ref);
91byte get_assign(ADAPTER * a, word ref);
92void req_queue(ADAPTER * a, byte e_no);
93byte look_req(ADAPTER * a);
94void next_req(ADAPTER * a);
95ENTITY * entity_ptr(ADAPTER * a, byte e_no);
96#if defined(DIVA_ISTREAM)
97struct _diva_xdi_stream_interface;
98void diva_xdi_provide_istream_info (ADAPTER* a,
99 struct _diva_xdi_stream_interface* pI);
100void pr_stream (ADAPTER * a);
101int diva_istream_write (void* context,
102 int Id,
103 void* data,
104 int length,
105 int final,
106 byte usr1,
107 byte usr2);
108int diva_istream_read (void* context,
109 int Id,
110 void* data,
111 int max_length,
112 int* final,
113 byte* usr1,
114 byte* usr2);
115#if defined(DIVA_IDI_RX_DMA)
116#include "diva_dma.h"
117#endif
118#endif
diff --git a/drivers/isdn/hardware/eicon/di_dbg.h b/drivers/isdn/hardware/eicon/di_dbg.h
new file mode 100644
index 000000000000..d576ff31d44c
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/di_dbg.h
@@ -0,0 +1,37 @@
1
2/*
3 *
4 Copyright (c) Eicon Networks, 2002.
5 *
6 This source file is supplied for the use with
7 Eicon Networks range of DIVA Server Adapters.
8 *
9 Eicon File Revision : 2.1
10 *
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2, or (at your option)
14 any later version.
15 *
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
18 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 See the GNU General Public License for more details.
20 *
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26#ifndef __DIVA_DI_DBG_INC__
27#define __DIVA_DI_DBG_INC__
28#if !defined (dtrc)
29#define dtrc(a)
30#endif
31#if !defined (dbug)
32#define dbug(a)
33#endif
34#if !defined USE_EXTENDED_DEBUGS
35extern void (*dprintf)(char*, ...);
36#endif
37#endif
diff --git a/drivers/isdn/hardware/eicon/di_defs.h b/drivers/isdn/hardware/eicon/di_defs.h
new file mode 100644
index 000000000000..4c2f61267df1
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/di_defs.h
@@ -0,0 +1,181 @@
1
2/*
3 *
4 Copyright (c) Eicon Networks, 2002.
5 *
6 This source file is supplied for the use with
7 Eicon Networks range of DIVA Server Adapters.
8 *
9 Eicon File Revision : 2.1
10 *
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2, or (at your option)
14 any later version.
15 *
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
18 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 See the GNU General Public License for more details.
20 *
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26#ifndef _DI_DEFS_
27#define _DI_DEFS_
28 /* typedefs for our data structures */
29typedef struct get_name_s GET_NAME;
30/* The entity_s structure is used to pass all
31 parameters between application and IDI */
32typedef struct entity_s ENTITY;
33typedef struct buffers_s BUFFERS;
34typedef struct postcall_s POSTCALL;
35typedef struct get_para_s GET_PARA;
36#define BOARD_NAME_LENGTH 9
37#define IDI_CALL_LINK_T
38#define IDI_CALL_ENTITY_T
39/* typedef void ( * IDI_CALL)(ENTITY *); */
40/* --------------------------------------------------------
41 IDI_CALL
42 -------------------------------------------------------- */
43typedef void (IDI_CALL_LINK_T * IDI_CALL)(ENTITY IDI_CALL_ENTITY_T *);
44typedef struct {
45 word length; /* length of data/parameter field */
46 byte P[270]; /* data/parameter field */
47} DBUFFER;
48struct get_name_s {
49 word command; /* command = 0x0100 */
50 byte name[BOARD_NAME_LENGTH];
51};
52struct postcall_s {
53 word command; /* command = 0x0300 */
54 word dummy; /* not used */
55 void ( * callback)(void *); /* call back */
56 void *context; /* context pointer */
57};
58#define REQ_PARA 0x0600 /* request command line parameters */
59#define REQ_PARA_LEN 1 /* number of data bytes */
60#define L1_STARTUP_DOWN_POS 0 /* '-y' command line parameter in......*/
61#define L1_STARTUP_DOWN_MSK 0x01 /* first byte position (index 0) with value 0x01 */
62struct get_para_s {
63 word command; /* command = 0x0600 */
64 byte len; /* max length of para field in bytes */
65 byte para[REQ_PARA_LEN]; /* parameter field */
66};
67struct buffers_s {
68 word PLength;
69 byte * P;
70};
71struct entity_s {
72 byte Req; /* pending request */
73 byte Rc; /* return code received */
74 byte Ind; /* indication received */
75 byte ReqCh; /* channel of current Req */
76 byte RcCh; /* channel of current Rc */
77 byte IndCh; /* channel of current Ind */
78 byte Id; /* ID used by this entity */
79 byte GlobalId; /* reserved field */
80 byte XNum; /* number of X-buffers */
81 byte RNum; /* number of R-buffers */
82 BUFFERS * X; /* pointer to X-buffer list */
83 BUFFERS * R; /* pointer to R-buffer list */
84 word RLength; /* length of current R-data */
85 DBUFFER * RBuffer; /* buffer of current R-data */
86 byte RNR; /* receive not ready flag */
87 byte complete; /* receive complete status */
88 IDI_CALL callback;
89 word user[2];
90 /* fields used by the driver internally */
91 byte No; /* entity number */
92 byte reserved2; /* reserved field */
93 byte More; /* R/X More flags */
94 byte MInd; /* MDATA coding for this ID */
95 byte XCurrent; /* current transmit buffer */
96 byte RCurrent; /* current receive buffer */
97 word XOffset; /* offset in x-buffer */
98 word ROffset; /* offset in r-buffer */
99};
100typedef struct {
101 byte type;
102 byte channels;
103 word features;
104 IDI_CALL request;
105} DESCRIPTOR;
106 /* descriptor type field coding */
107#define IDI_ADAPTER_S 1
108#define IDI_ADAPTER_PR 2
109#define IDI_ADAPTER_DIVA 3
110#define IDI_ADAPTER_MAESTRA 4
111#define IDI_VADAPTER 0x40
112#define IDI_DRIVER 0x80
113#define IDI_DADAPTER 0xfd
114#define IDI_DIDDPNP 0xfe
115#define IDI_DIMAINT 0xff
116 /* Hardware IDs ISA PNP */
117#define HW_ID_DIVA_PRO 3 /* same as IDI_ADAPTER_DIVA */
118#define HW_ID_MAESTRA 4 /* same as IDI_ADAPTER_MAESTRA */
119#define HW_ID_PICCOLA 5
120#define HW_ID_DIVA_PRO20 6
121#define HW_ID_DIVA20 7
122#define HW_ID_DIVA_PRO20_U 8
123#define HW_ID_DIVA20_U 9
124#define HW_ID_DIVA30 10
125#define HW_ID_DIVA30_U 11
126 /* Hardware IDs PCI */
127#define HW_ID_EICON_PCI 0x1133
128#define HW_ID_SIEMENS_PCI 0x8001 /* unused SubVendor ID for Siemens Cornet-N cards */
129#define HW_ID_PROTTYPE_CORNETN 0x0014 /* SubDevice ID for Siemens Cornet-N cards */
130#define HW_ID_FUJITSU_SIEMENS_PCI 0x110A /* SubVendor ID for Fujitsu Siemens */
131#define HW_ID_GS03_PCI 0x0021 /* SubDevice ID for Fujitsu Siemens ISDN S0 card */
132#define HW_ID_DIVA_PRO20_PCI 0xe001
133#define HW_ID_DIVA20_PCI 0xe002
134#define HW_ID_DIVA_PRO20_PCI_U 0xe003
135#define HW_ID_DIVA20_PCI_U 0xe004
136#define HW_ID_DIVA201_PCI 0xe005
137#define HW_ID_DIVA_CT_ST 0xe006
138#define HW_ID_DIVA_CT_U 0xe007
139#define HW_ID_DIVA_CTL_ST 0xe008
140#define HW_ID_DIVA_CTL_U 0xe009
141#define HW_ID_DIVA_ISDN_V90_PCI 0xe00a
142#define HW_ID_DIVA202_PCI_ST 0xe00b
143#define HW_ID_DIVA202_PCI_U 0xe00c
144#define HW_ID_DIVA_PRO30_PCI 0xe00d
145#define HW_ID_MAESTRA_PCI 0xe010
146#define HW_ID_MAESTRAQ_PCI 0xe012
147#define HW_ID_DSRV_Q8M_V2_PCI 0xe013
148#define HW_ID_MAESTRAP_PCI 0xe014
149#define HW_ID_DSRV_P30M_V2_PCI 0xe015
150#define HW_ID_DSRV_VOICE_Q8M_PCI 0xe016
151#define HW_ID_DSRV_VOICE_Q8M_V2_PCI 0xe017
152#define HW_ID_DSRV_B2M_V2_PCI 0xe018
153#define HW_ID_DSRV_VOICE_P30M_V2_PCI 0xe019
154#define HW_ID_DSRV_B2F_PCI 0xe01a
155#define HW_ID_DSRV_VOICE_B2M_V2_PCI 0xe01b
156 /* Hardware IDs USB */
157#define EICON_USB_VENDOR_ID 0x071D
158#define HW_ID_DIVA_USB_REV1 0x1000
159#define HW_ID_DIVA_USB_REV2 0x1003
160#define HW_ID_TELEDAT_SURF_USB_REV2 0x1004
161#define HW_ID_TELEDAT_SURF_USB_REV1 0x2000
162/* --------------------------------------------------------------------------
163 Adapter array change notification framework
164 -------------------------------------------------------------------------- */
165typedef void (IDI_CALL_LINK_T* didd_adapter_change_callback_t)( void IDI_CALL_ENTITY_T * context, DESCRIPTOR* adapter, int removal);
166/* -------------------------------------------------------------------------- */
167#define DI_VOICE 0x0 /* obsolete define */
168#define DI_FAX3 0x1
169#define DI_MODEM 0x2
170#define DI_POST 0x4
171#define DI_V110 0x8
172#define DI_V120 0x10
173#define DI_POTS 0x20
174#define DI_CODEC 0x40
175#define DI_MANAGE 0x80
176#define DI_V_42 0x0100
177#define DI_EXTD_FAX 0x0200 /* Extended FAX (ECM, 2D, T.6, Polling) */
178#define DI_AT_PARSER 0x0400 /* Build-in AT Parser in the L2 */
179#define DI_VOICE_OVER_IP 0x0800 /* Voice over IP support */
180typedef void (IDI_CALL_LINK_T* _IDI_CALL)(void*, ENTITY*);
181#endif
diff --git a/drivers/isdn/hardware/eicon/did_vers.h b/drivers/isdn/hardware/eicon/did_vers.h
new file mode 100644
index 000000000000..538c590fdf42
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/did_vers.h
@@ -0,0 +1,26 @@
1
2/*
3 *
4 Copyright (c) Eicon Networks, 2002.
5 *
6 This source file is supplied for the use with
7 Eicon Networks range of DIVA Server Adapters.
8 *
9 Eicon File Revision : 2.1
10 *
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2, or (at your option)
14 any later version.
15 *
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
18 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 See the GNU General Public License for more details.
20 *
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26static char diva_didd_common_code_build[] = "102-51";
diff --git a/drivers/isdn/hardware/eicon/diddfunc.c b/drivers/isdn/hardware/eicon/diddfunc.c
new file mode 100644
index 000000000000..3029234178d8
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/diddfunc.c
@@ -0,0 +1,115 @@
1/* $Id: diddfunc.c,v 1.14.6.2 2004/08/28 20:03:53 armin Exp $
2 *
3 * DIDD Interface module for Eicon active cards.
4 *
5 * Functions are in dadapter.c
6 *
7 * Copyright 2002-2003 by Armin Schindler (mac@melware.de)
8 * Copyright 2002-2003 Cytronics & Melware (info@melware.de)
9 *
10 * This software may be used and distributed according to the terms
11 * of the GNU General Public License, incorporated herein by reference.
12 */
13
14#include "platform.h"
15#include "di_defs.h"
16#include "dadapter.h"
17#include "divasync.h"
18
19#define DBG_MINIMUM (DL_LOG + DL_FTL + DL_ERR)
20#define DBG_DEFAULT (DBG_MINIMUM + DL_XLOG + DL_REG)
21
22
23extern void DIVA_DIDD_Read(void *, int);
24extern char *DRIVERRELEASE_DIDD;
25static dword notify_handle;
26static DESCRIPTOR _DAdapter;
27
28/*
29 * didd callback function
30 */
31static void *didd_callback(void *context, DESCRIPTOR * adapter,
32 int removal)
33{
34 if (adapter->type == IDI_DADAPTER) {
35 DBG_ERR(("Notification about IDI_DADAPTER change ! Oops."))
36 return (NULL);
37 } else if (adapter->type == IDI_DIMAINT) {
38 if (removal) {
39 DbgDeregister();
40 } else {
41 DbgRegister("DIDD", DRIVERRELEASE_DIDD, DBG_DEFAULT);
42 }
43 }
44 return (NULL);
45}
46
47/*
48 * connect to didd
49 */
50static int DIVA_INIT_FUNCTION connect_didd(void)
51{
52 int x = 0;
53 int dadapter = 0;
54 IDI_SYNC_REQ req;
55 DESCRIPTOR DIDD_Table[MAX_DESCRIPTORS];
56
57 DIVA_DIDD_Read(DIDD_Table, sizeof(DIDD_Table));
58
59 for (x = 0; x < MAX_DESCRIPTORS; x++) {
60 if (DIDD_Table[x].type == IDI_DADAPTER) { /* DADAPTER found */
61 dadapter = 1;
62 memcpy(&_DAdapter, &DIDD_Table[x], sizeof(_DAdapter));
63 req.didd_notify.e.Req = 0;
64 req.didd_notify.e.Rc =
65 IDI_SYNC_REQ_DIDD_REGISTER_ADAPTER_NOTIFY;
66 req.didd_notify.info.callback = (void *)didd_callback;
67 req.didd_notify.info.context = NULL;
68 _DAdapter.request((ENTITY *) & req);
69 if (req.didd_notify.e.Rc != 0xff)
70 return (0);
71 notify_handle = req.didd_notify.info.handle;
72 } else if (DIDD_Table[x].type == IDI_DIMAINT) { /* MAINT found */
73 DbgRegister("DIDD", DRIVERRELEASE_DIDD, DBG_DEFAULT);
74 }
75 }
76 return (dadapter);
77}
78
79/*
80 * disconnect from didd
81 */
82static void DIVA_EXIT_FUNCTION disconnect_didd(void)
83{
84 IDI_SYNC_REQ req;
85
86 req.didd_notify.e.Req = 0;
87 req.didd_notify.e.Rc = IDI_SYNC_REQ_DIDD_REMOVE_ADAPTER_NOTIFY;
88 req.didd_notify.info.handle = notify_handle;
89 _DAdapter.request((ENTITY *) & req);
90}
91
92/*
93 * init
94 */
95int DIVA_INIT_FUNCTION diddfunc_init(void)
96{
97 diva_didd_load_time_init();
98
99 if (!connect_didd()) {
100 DBG_ERR(("init: failed to connect to DIDD."))
101 diva_didd_load_time_finit();
102 return (0);
103 }
104 return (1);
105}
106
107/*
108 * finit
109 */
110void DIVA_EXIT_FUNCTION diddfunc_finit(void)
111{
112 DbgDeregister();
113 disconnect_didd();
114 diva_didd_load_time_finit();
115}
diff --git a/drivers/isdn/hardware/eicon/diva.c b/drivers/isdn/hardware/eicon/diva.c
new file mode 100644
index 000000000000..8ab8027f33c0
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/diva.c
@@ -0,0 +1,660 @@
1/* $Id: diva.c,v 1.21.4.1 2004/05/08 14:33:43 armin Exp $ */
2
3#define CARDTYPE_H_WANT_DATA 1
4#define CARDTYPE_H_WANT_IDI_DATA 0
5#define CARDTYPE_H_WANT_RESOURCE_DATA 0
6#define CARDTYPE_H_WANT_FILE_DATA 0
7
8#include "platform.h"
9#include "debuglib.h"
10#include "cardtype.h"
11#include "pc.h"
12#include "di_defs.h"
13#include "di.h"
14#include "io.h"
15#include "pc_maint.h"
16#include "xdi_msg.h"
17#include "xdi_adapter.h"
18#include "diva_pci.h"
19#include "diva.h"
20
21#ifdef CONFIG_ISDN_DIVAS_PRIPCI
22#include "os_pri.h"
23#endif
24#ifdef CONFIG_ISDN_DIVAS_BRIPCI
25#include "os_bri.h"
26#include "os_4bri.h"
27#endif
28
29PISDN_ADAPTER IoAdapters[MAX_ADAPTER];
30extern IDI_CALL Requests[MAX_ADAPTER];
31extern int create_adapter_proc(diva_os_xdi_adapter_t * a);
32extern void remove_adapter_proc(diva_os_xdi_adapter_t * a);
33
34#define DivaIdiReqFunc(N) \
35static void DivaIdiRequest##N(ENTITY *e) \
36{ if ( IoAdapters[N] ) (* IoAdapters[N]->DIRequest)(IoAdapters[N], e) ; }
37
38/*
39** Create own 32 Adapters
40*/
41DivaIdiReqFunc(0)
42DivaIdiReqFunc(1)
43DivaIdiReqFunc(2)
44DivaIdiReqFunc(3)
45DivaIdiReqFunc(4)
46DivaIdiReqFunc(5)
47DivaIdiReqFunc(6)
48DivaIdiReqFunc(7)
49DivaIdiReqFunc(8)
50DivaIdiReqFunc(9)
51DivaIdiReqFunc(10)
52DivaIdiReqFunc(11)
53DivaIdiReqFunc(12)
54DivaIdiReqFunc(13)
55DivaIdiReqFunc(14)
56DivaIdiReqFunc(15)
57DivaIdiReqFunc(16)
58DivaIdiReqFunc(17)
59DivaIdiReqFunc(18)
60DivaIdiReqFunc(19)
61DivaIdiReqFunc(20)
62DivaIdiReqFunc(21)
63DivaIdiReqFunc(22)
64DivaIdiReqFunc(23)
65DivaIdiReqFunc(24)
66DivaIdiReqFunc(25)
67DivaIdiReqFunc(26)
68DivaIdiReqFunc(27)
69DivaIdiReqFunc(28)
70DivaIdiReqFunc(29)
71DivaIdiReqFunc(30)
72DivaIdiReqFunc(31)
73
74struct pt_regs;
75
76/*
77** LOCALS
78*/
79static LIST_HEAD(adapter_queue);
80
81typedef struct _diva_get_xlog {
82 word command;
83 byte req;
84 byte rc;
85 byte data[sizeof(struct mi_pc_maint)];
86} diva_get_xlog_t;
87
88typedef struct _diva_supported_cards_info {
89 int CardOrdinal;
90 diva_init_card_proc_t init_card;
91} diva_supported_cards_info_t;
92
93static diva_supported_cards_info_t divas_supported_cards[] = {
94#ifdef CONFIG_ISDN_DIVAS_PRIPCI
95 /*
96 PRI Cards
97 */
98 {CARDTYPE_DIVASRV_P_30M_PCI, diva_pri_init_card},
99 /*
100 PRI Rev.2 Cards
101 */
102 {CARDTYPE_DIVASRV_P_30M_V2_PCI, diva_pri_init_card},
103 /*
104 PRI Rev.2 VoIP Cards
105 */
106 {CARDTYPE_DIVASRV_VOICE_P_30M_V2_PCI, diva_pri_init_card},
107#endif
108#ifdef CONFIG_ISDN_DIVAS_BRIPCI
109 /*
110 4BRI Rev 1 Cards
111 */
112 {CARDTYPE_DIVASRV_Q_8M_PCI, diva_4bri_init_card},
113 {CARDTYPE_DIVASRV_VOICE_Q_8M_PCI, diva_4bri_init_card},
114 /*
115 4BRI Rev 2 Cards
116 */
117 {CARDTYPE_DIVASRV_Q_8M_V2_PCI, diva_4bri_init_card},
118 {CARDTYPE_DIVASRV_VOICE_Q_8M_V2_PCI, diva_4bri_init_card},
119 /*
120 4BRI Based BRI Rev 2 Cards
121 */
122 {CARDTYPE_DIVASRV_B_2M_V2_PCI, diva_4bri_init_card},
123 {CARDTYPE_DIVASRV_B_2F_PCI, diva_4bri_init_card},
124 {CARDTYPE_DIVASRV_VOICE_B_2M_V2_PCI, diva_4bri_init_card},
125 /*
126 BRI
127 */
128 {CARDTYPE_MAESTRA_PCI, diva_bri_init_card},
129#endif
130
131 /*
132 EOL
133 */
134 {-1}
135};
136
137static void diva_init_request_array(void);
138static void *divas_create_pci_card(int handle, void *pci_dev_handle);
139
140static diva_os_spin_lock_t adapter_lock;
141
142static int diva_find_free_adapters(int base, int nr)
143{
144 int i;
145
146 for (i = 0; i < nr; i++) {
147 if (IoAdapters[base + i]) {
148 return (-1);
149 }
150 }
151
152 return (0);
153}
154
155static diva_os_xdi_adapter_t *diva_q_get_next(struct list_head * what)
156{
157 diva_os_xdi_adapter_t *a = NULL;
158
159 if (what && (what->next != &adapter_queue))
160 a = list_entry(what->next, diva_os_xdi_adapter_t, link);
161
162 return(a);
163}
164
165/* --------------------------------------------------------------------------
166 Add card to the card list
167 -------------------------------------------------------------------------- */
168void *diva_driver_add_card(void *pdev, unsigned long CardOrdinal)
169{
170 diva_os_spin_lock_magic_t old_irql;
171 diva_os_xdi_adapter_t *pdiva, *pa;
172 int i, j, max, nr;
173
174 for (i = 0; divas_supported_cards[i].CardOrdinal != -1; i++) {
175 if (divas_supported_cards[i].CardOrdinal == CardOrdinal) {
176 if (!(pdiva = divas_create_pci_card(i, pdev))) {
177 return NULL;
178 }
179 switch (CardOrdinal) {
180 case CARDTYPE_DIVASRV_Q_8M_PCI:
181 case CARDTYPE_DIVASRV_VOICE_Q_8M_PCI:
182 case CARDTYPE_DIVASRV_Q_8M_V2_PCI:
183 case CARDTYPE_DIVASRV_VOICE_Q_8M_V2_PCI:
184 max = MAX_ADAPTER - 4;
185 nr = 4;
186 break;
187
188 default:
189 max = MAX_ADAPTER;
190 nr = 1;
191 }
192
193 diva_os_enter_spin_lock(&adapter_lock, &old_irql, "add card");
194
195 for (i = 0; i < max; i++) {
196 if (!diva_find_free_adapters(i, nr)) {
197 pdiva->controller = i + 1;
198 pdiva->xdi_adapter.ANum = pdiva->controller;
199 IoAdapters[i] = &pdiva->xdi_adapter;
200 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "add card");
201 create_adapter_proc(pdiva); /* add adapter to proc file system */
202
203 DBG_LOG(("add %s:%d",
204 CardProperties
205 [CardOrdinal].Name,
206 pdiva->controller))
207
208 diva_os_enter_spin_lock(&adapter_lock, &old_irql, "add card");
209 pa = pdiva;
210 for (j = 1; j < nr; j++) { /* slave adapters, if any */
211 pa = diva_q_get_next(&pa->link);
212 if (pa && !pa->interface.cleanup_adapter_proc) {
213 pa->controller = i + 1 + j;
214 pa->xdi_adapter.ANum = pa->controller;
215 IoAdapters[i + j] = &pa->xdi_adapter;
216 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "add card");
217 DBG_LOG(("add slave adapter (%d)",
218 pa->controller))
219 create_adapter_proc(pa); /* add adapter to proc file system */
220 diva_os_enter_spin_lock(&adapter_lock, &old_irql, "add card");
221 } else {
222 DBG_ERR(("slave adapter problem"))
223 break;
224 }
225 }
226
227 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "add card");
228 return (pdiva);
229 }
230 }
231
232 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "add card");
233
234 /*
235 Not able to add adapter - remove it and return error
236 */
237 DBG_ERR(("can not alloc request array"))
238 diva_driver_remove_card(pdiva);
239
240 return NULL;
241 }
242 }
243
244 return NULL;
245}
246
247/* --------------------------------------------------------------------------
248 Called on driver load, MAIN, main, DriverEntry
249 -------------------------------------------------------------------------- */
250int divasa_xdi_driver_entry(void)
251{
252 diva_os_initialize_spin_lock(&adapter_lock, "adapter");
253 memset(&IoAdapters[0], 0x00, sizeof(IoAdapters));
254 diva_init_request_array();
255
256 return (0);
257}
258
259/* --------------------------------------------------------------------------
260 Remove adapter from list
261 -------------------------------------------------------------------------- */
262static diva_os_xdi_adapter_t *get_and_remove_from_queue(void)
263{
264 diva_os_spin_lock_magic_t old_irql;
265 diva_os_xdi_adapter_t *a = NULL;
266
267 diva_os_enter_spin_lock(&adapter_lock, &old_irql, "driver_unload");
268
269 if (!list_empty(&adapter_queue)) {
270 a = list_entry(adapter_queue.next, diva_os_xdi_adapter_t, link);
271 list_del(adapter_queue.next);
272 }
273
274 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "driver_unload");
275 return (a);
276}
277
278/* --------------------------------------------------------------------------
279 Remove card from the card list
280 -------------------------------------------------------------------------- */
281void diva_driver_remove_card(void *pdiva)
282{
283 diva_os_spin_lock_magic_t old_irql;
284 diva_os_xdi_adapter_t *a[4];
285 diva_os_xdi_adapter_t *pa;
286 int i;
287
288 pa = a[0] = (diva_os_xdi_adapter_t *) pdiva;
289 a[1] = a[2] = a[3] = NULL;
290
291 diva_os_enter_spin_lock(&adapter_lock, &old_irql, "remode adapter");
292
293 for (i = 1; i < 4; i++) {
294 if ((pa = diva_q_get_next(&pa->link))
295 && !pa->interface.cleanup_adapter_proc) {
296 a[i] = pa;
297 } else {
298 break;
299 }
300 }
301
302 for (i = 0; ((i < 4) && a[i]); i++) {
303 list_del(&a[i]->link);
304 }
305
306 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "driver_unload");
307
308 (*(a[0]->interface.cleanup_adapter_proc)) (a[0]);
309
310 for (i = 0; i < 4; i++) {
311 if (a[i]) {
312 if (a[i]->controller) {
313 DBG_LOG(("remove adapter (%d)",
314 a[i]->controller)) IoAdapters[a[i]->controller - 1] = NULL;
315 remove_adapter_proc(a[i]);
316 }
317 diva_os_free(0, a[i]);
318 }
319 }
320}
321
322/* --------------------------------------------------------------------------
323 Create diva PCI adapter and init internal adapter structures
324 -------------------------------------------------------------------------- */
325static void *divas_create_pci_card(int handle, void *pci_dev_handle)
326{
327 diva_supported_cards_info_t *pI = &divas_supported_cards[handle];
328 diva_os_spin_lock_magic_t old_irql;
329 diva_os_xdi_adapter_t *a;
330
331 DBG_LOG(("found %d-%s", pI->CardOrdinal, CardProperties[pI->CardOrdinal].Name))
332
333 if (!(a = (diva_os_xdi_adapter_t *) diva_os_malloc(0, sizeof(*a)))) {
334 DBG_ERR(("A: can't alloc adapter"));
335 return NULL;
336 }
337
338 memset(a, 0x00, sizeof(*a));
339
340 a->CardIndex = handle;
341 a->CardOrdinal = pI->CardOrdinal;
342 a->Bus = DIVAS_XDI_ADAPTER_BUS_PCI;
343 a->xdi_adapter.cardType = a->CardOrdinal;
344 a->resources.pci.bus = diva_os_get_pci_bus(pci_dev_handle);
345 a->resources.pci.func = diva_os_get_pci_func(pci_dev_handle);
346 a->resources.pci.hdev = pci_dev_handle;
347
348 /*
349 Add master adapter first, so slave adapters will receive higher
350 numbers as master adapter
351 */
352 diva_os_enter_spin_lock(&adapter_lock, &old_irql, "found_pci_card");
353 list_add_tail(&a->link, &adapter_queue);
354 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "found_pci_card");
355
356 if ((*(pI->init_card)) (a)) {
357 diva_os_enter_spin_lock(&adapter_lock, &old_irql, "found_pci_card");
358 list_del(&a->link);
359 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "found_pci_card");
360 diva_os_free(0, a);
361 DBG_ERR(("A: can't get adapter resources"));
362 return NULL;
363 }
364
365 return (a);
366}
367
368/* --------------------------------------------------------------------------
369 Called on driver unload FINIT, finit, Unload
370 -------------------------------------------------------------------------- */
371void divasa_xdi_driver_unload(void)
372{
373 diva_os_xdi_adapter_t *a;
374
375 while ((a = get_and_remove_from_queue())) {
376 if (a->interface.cleanup_adapter_proc) {
377 (*(a->interface.cleanup_adapter_proc)) (a);
378 }
379 if (a->controller) {
380 IoAdapters[a->controller - 1] = NULL;
381 remove_adapter_proc(a);
382 }
383 diva_os_free(0, a);
384 }
385 diva_os_destroy_spin_lock(&adapter_lock, "adapter");
386}
387
388/*
389** Receive and process command from user mode utility
390*/
391void *diva_xdi_open_adapter(void *os_handle, const void __user *src,
392 int length,
393 divas_xdi_copy_from_user_fn_t cp_fn)
394{
395 diva_xdi_um_cfg_cmd_t msg;
396 diva_os_xdi_adapter_t *a = NULL;
397 diva_os_spin_lock_magic_t old_irql;
398 struct list_head *tmp;
399
400 if (length < sizeof(diva_xdi_um_cfg_cmd_t)) {
401 DBG_ERR(("A: A(?) open, msg too small (%d < %d)",
402 length, sizeof(diva_xdi_um_cfg_cmd_t)))
403 return NULL;
404 }
405 if ((*cp_fn) (os_handle, &msg, src, sizeof(msg)) <= 0) {
406 DBG_ERR(("A: A(?) open, write error"))
407 return NULL;
408 }
409 diva_os_enter_spin_lock(&adapter_lock, &old_irql, "open_adapter");
410 list_for_each(tmp, &adapter_queue) {
411 a = list_entry(tmp, diva_os_xdi_adapter_t, link);
412 if (a->controller == (int)msg.adapter)
413 break;
414 a = NULL;
415 }
416 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "open_adapter");
417
418 if (!a) {
419 DBG_ERR(("A: A(%d) open, adapter not found", msg.adapter))
420 }
421
422 return (a);
423}
424
425/*
426** Easy cleanup mailbox status
427*/
428void diva_xdi_close_adapter(void *adapter, void *os_handle)
429{
430 diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) adapter;
431
432 a->xdi_mbox.status &= ~DIVA_XDI_MBOX_BUSY;
433 if (a->xdi_mbox.data) {
434 diva_os_free(0, a->xdi_mbox.data);
435 a->xdi_mbox.data = NULL;
436 }
437}
438
439int
440diva_xdi_write(void *adapter, void *os_handle, const void __user *src,
441 int length, divas_xdi_copy_from_user_fn_t cp_fn)
442{
443 diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) adapter;
444 void *data;
445
446 if (a->xdi_mbox.status & DIVA_XDI_MBOX_BUSY) {
447 DBG_ERR(("A: A(%d) write, mbox busy", a->controller))
448 return (-1);
449 }
450
451 if (length < sizeof(diva_xdi_um_cfg_cmd_t)) {
452 DBG_ERR(("A: A(%d) write, message too small (%d < %d)",
453 a->controller, length,
454 sizeof(diva_xdi_um_cfg_cmd_t)))
455 return (-3);
456 }
457
458 if (!(data = diva_os_malloc(0, length))) {
459 DBG_ERR(("A: A(%d) write, ENOMEM", a->controller))
460 return (-2);
461 }
462
463 length = (*cp_fn) (os_handle, data, src, length);
464 if (length > 0) {
465 if ((*(a->interface.cmd_proc))
466 (a, (diva_xdi_um_cfg_cmd_t *) data, length)) {
467 length = -3;
468 }
469 } else {
470 DBG_ERR(("A: A(%d) write error (%d)", a->controller,
471 length))
472 }
473
474 diva_os_free(0, data);
475
476 return (length);
477}
478
479/*
480** Write answers to user mode utility, if any
481*/
482int
483diva_xdi_read(void *adapter, void *os_handle, void __user *dst,
484 int max_length, divas_xdi_copy_to_user_fn_t cp_fn)
485{
486 diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) adapter;
487 int ret;
488
489 if (!(a->xdi_mbox.status & DIVA_XDI_MBOX_BUSY)) {
490 DBG_ERR(("A: A(%d) rx mbox empty", a->controller))
491 return (-1);
492 }
493 if (!a->xdi_mbox.data) {
494 a->xdi_mbox.status &= ~DIVA_XDI_MBOX_BUSY;
495 DBG_ERR(("A: A(%d) rx ENOMEM", a->controller))
496 return (-2);
497 }
498
499 if (max_length < a->xdi_mbox.data_length) {
500 DBG_ERR(("A: A(%d) rx buffer too short(%d < %d)",
501 a->controller, max_length,
502 a->xdi_mbox.data_length))
503 return (-3);
504 }
505
506 ret = (*cp_fn) (os_handle, dst, a->xdi_mbox.data,
507 a->xdi_mbox.data_length);
508 if (ret > 0) {
509 diva_os_free(0, a->xdi_mbox.data);
510 a->xdi_mbox.data = NULL;
511 a->xdi_mbox.status &= ~DIVA_XDI_MBOX_BUSY;
512 }
513
514 return (ret);
515}
516
517
518irqreturn_t diva_os_irq_wrapper(int irq, void *context, struct pt_regs *regs)
519{
520 diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) context;
521 diva_xdi_clear_interrupts_proc_t clear_int_proc;
522
523 if (!a || !a->xdi_adapter.diva_isr_handler) {
524 return IRQ_NONE;
525 }
526
527 if ((clear_int_proc = a->clear_interrupts_proc)) {
528 (*clear_int_proc) (a);
529 a->clear_interrupts_proc = NULL;
530 return IRQ_HANDLED;
531 }
532
533 (*(a->xdi_adapter.diva_isr_handler)) (&a->xdi_adapter);
534 return IRQ_HANDLED;
535}
536
537static void diva_init_request_array(void)
538{
539 Requests[0] = DivaIdiRequest0;
540 Requests[1] = DivaIdiRequest1;
541 Requests[2] = DivaIdiRequest2;
542 Requests[3] = DivaIdiRequest3;
543 Requests[4] = DivaIdiRequest4;
544 Requests[5] = DivaIdiRequest5;
545 Requests[6] = DivaIdiRequest6;
546 Requests[7] = DivaIdiRequest7;
547 Requests[8] = DivaIdiRequest8;
548 Requests[9] = DivaIdiRequest9;
549 Requests[10] = DivaIdiRequest10;
550 Requests[11] = DivaIdiRequest11;
551 Requests[12] = DivaIdiRequest12;
552 Requests[13] = DivaIdiRequest13;
553 Requests[14] = DivaIdiRequest14;
554 Requests[15] = DivaIdiRequest15;
555 Requests[16] = DivaIdiRequest16;
556 Requests[17] = DivaIdiRequest17;
557 Requests[18] = DivaIdiRequest18;
558 Requests[19] = DivaIdiRequest19;
559 Requests[20] = DivaIdiRequest20;
560 Requests[21] = DivaIdiRequest21;
561 Requests[22] = DivaIdiRequest22;
562 Requests[23] = DivaIdiRequest23;
563 Requests[24] = DivaIdiRequest24;
564 Requests[25] = DivaIdiRequest25;
565 Requests[26] = DivaIdiRequest26;
566 Requests[27] = DivaIdiRequest27;
567 Requests[28] = DivaIdiRequest28;
568 Requests[29] = DivaIdiRequest29;
569 Requests[30] = DivaIdiRequest30;
570 Requests[31] = DivaIdiRequest31;
571}
572
573void diva_xdi_display_adapter_features(int card)
574{
575 dword features;
576 if (!card || ((card - 1) >= MAX_ADAPTER) || !IoAdapters[card - 1]) {
577 return;
578 }
579 card--;
580 features = IoAdapters[card]->Properties.Features;
581
582 DBG_LOG(("FEATURES FOR ADAPTER: %d", card + 1))
583 DBG_LOG((" DI_FAX3 : %s",
584 (features & DI_FAX3) ? "Y" : "N"))
585 DBG_LOG((" DI_MODEM : %s",
586 (features & DI_MODEM) ? "Y" : "N"))
587 DBG_LOG((" DI_POST : %s",
588 (features & DI_POST) ? "Y" : "N"))
589 DBG_LOG((" DI_V110 : %s",
590 (features & DI_V110) ? "Y" : "N"))
591 DBG_LOG((" DI_V120 : %s",
592 (features & DI_V120) ? "Y" : "N"))
593 DBG_LOG((" DI_POTS : %s",
594 (features & DI_POTS) ? "Y" : "N"))
595 DBG_LOG((" DI_CODEC : %s",
596 (features & DI_CODEC) ? "Y" : "N"))
597 DBG_LOG((" DI_MANAGE : %s",
598 (features & DI_MANAGE) ? "Y" : "N"))
599 DBG_LOG((" DI_V_42 : %s",
600 (features & DI_V_42) ? "Y" : "N"))
601 DBG_LOG((" DI_EXTD_FAX : %s",
602 (features & DI_EXTD_FAX) ? "Y" : "N"))
603 DBG_LOG((" DI_AT_PARSER : %s",
604 (features & DI_AT_PARSER) ? "Y" : "N"))
605 DBG_LOG((" DI_VOICE_OVER_IP : %s",
606 (features & DI_VOICE_OVER_IP) ? "Y" : "N"))
607}
608
609void diva_add_slave_adapter(diva_os_xdi_adapter_t * a)
610{
611 diva_os_spin_lock_magic_t old_irql;
612
613 diva_os_enter_spin_lock(&adapter_lock, &old_irql, "add_slave");
614 list_add_tail(&a->link, &adapter_queue);
615 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "add_slave");
616}
617
618int diva_card_read_xlog(diva_os_xdi_adapter_t * a)
619{
620 diva_get_xlog_t *req;
621 byte *data;
622
623 if (!a->xdi_adapter.Initialized || !a->xdi_adapter.DIRequest) {
624 return (-1);
625 }
626 if (!(data = diva_os_malloc(0, sizeof(struct mi_pc_maint)))) {
627 return (-1);
628 }
629 memset(data, 0x00, sizeof(struct mi_pc_maint));
630
631 if (!(req = diva_os_malloc(0, sizeof(*req)))) {
632 diva_os_free(0, data);
633 return (-1);
634 }
635 req->command = 0x0400;
636 req->req = LOG;
637 req->rc = 0x00;
638
639 (*(a->xdi_adapter.DIRequest)) (&a->xdi_adapter, (ENTITY *) req);
640
641 if (!req->rc || req->req) {
642 diva_os_free(0, data);
643 diva_os_free(0, req);
644 return (-1);
645 }
646
647 memcpy(data, &req->req, sizeof(struct mi_pc_maint));
648
649 diva_os_free(0, req);
650
651 a->xdi_mbox.data_length = sizeof(struct mi_pc_maint);
652 a->xdi_mbox.data = data;
653 a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
654
655 return (0);
656}
657
658void xdiFreeFile(void *handle)
659{
660}
diff --git a/drivers/isdn/hardware/eicon/diva.h b/drivers/isdn/hardware/eicon/diva.h
new file mode 100644
index 000000000000..e979085d1b89
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/diva.h
@@ -0,0 +1,31 @@
1/* $Id: diva.h,v 1.1.2.2 2001/02/08 12:25:43 armin Exp $ */
2
3#ifndef __DIVA_XDI_OS_PART_H__
4#define __DIVA_XDI_OS_PART_H__
5
6
7int divasa_xdi_driver_entry(void);
8void divasa_xdi_driver_unload(void);
9void *diva_driver_add_card(void *pdev, unsigned long CardOrdinal);
10void diva_driver_remove_card(void *pdiva);
11
12typedef int (*divas_xdi_copy_to_user_fn_t) (void *os_handle, void __user *dst,
13 const void *src, int length);
14
15typedef int (*divas_xdi_copy_from_user_fn_t) (void *os_handle, void *dst,
16 const void __user *src, int length);
17
18int diva_xdi_read(void *adapter, void *os_handle, void __user *dst,
19 int max_length, divas_xdi_copy_to_user_fn_t cp_fn);
20
21int diva_xdi_write(void *adapter, void *os_handle, const void __user *src,
22 int length, divas_xdi_copy_from_user_fn_t cp_fn);
23
24void *diva_xdi_open_adapter(void *os_handle, const void __user *src,
25 int length,
26 divas_xdi_copy_from_user_fn_t cp_fn);
27
28void diva_xdi_close_adapter(void *adapter, void *os_handle);
29
30
31#endif
diff --git a/drivers/isdn/hardware/eicon/diva_didd.c b/drivers/isdn/hardware/eicon/diva_didd.c
new file mode 100644
index 000000000000..7fdf8ae5be52
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/diva_didd.c
@@ -0,0 +1,151 @@
1/* $Id: diva_didd.c,v 1.13.6.4 2005/02/11 19:40:25 armin Exp $
2 *
3 * DIDD Interface module for Eicon active cards.
4 *
5 * Functions are in dadapter.c
6 *
7 * Copyright 2002-2003 by Armin Schindler (mac@melware.de)
8 * Copyright 2002-2003 Cytronics & Melware (info@melware.de)
9 *
10 * This software may be used and distributed according to the terms
11 * of the GNU General Public License, incorporated herein by reference.
12 */
13
14#include <linux/config.h>
15#include <linux/module.h>
16#include <linux/init.h>
17#include <linux/kernel.h>
18#include <linux/proc_fs.h>
19
20#include "platform.h"
21#include "di_defs.h"
22#include "dadapter.h"
23#include "divasync.h"
24#include "did_vers.h"
25
26static char *main_revision = "$Revision: 1.13.6.4 $";
27
28static char *DRIVERNAME =
29 "Eicon DIVA - DIDD table (http://www.melware.net)";
30static char *DRIVERLNAME = "divadidd";
31char *DRIVERRELEASE_DIDD = "2.0";
32
33static char *main_proc_dir = "eicon";
34
35MODULE_DESCRIPTION("DIDD table driver for diva drivers");
36MODULE_AUTHOR("Cytronics & Melware, Eicon Networks");
37MODULE_SUPPORTED_DEVICE("Eicon diva drivers");
38MODULE_LICENSE("GPL");
39
40#define DBG_MINIMUM (DL_LOG + DL_FTL + DL_ERR)
41#define DBG_DEFAULT (DBG_MINIMUM + DL_XLOG + DL_REG)
42
43extern int diddfunc_init(void);
44extern void diddfunc_finit(void);
45
46extern void DIVA_DIDD_Read(void *, int);
47
48static struct proc_dir_entry *proc_didd;
49struct proc_dir_entry *proc_net_eicon = NULL;
50
51EXPORT_SYMBOL(DIVA_DIDD_Read);
52EXPORT_SYMBOL(proc_net_eicon);
53
54static char *getrev(const char *revision)
55{
56 char *rev;
57 char *p;
58 if ((p = strchr(revision, ':'))) {
59 rev = p + 2;
60 p = strchr(rev, '$');
61 *--p = 0;
62 } else
63 rev = "1.0";
64 return rev;
65}
66
67static int
68proc_read(char *page, char **start, off_t off, int count, int *eof,
69 void *data)
70{
71 int len = 0;
72 char tmprev[32];
73
74 strcpy(tmprev, main_revision);
75 len += sprintf(page + len, "%s\n", DRIVERNAME);
76 len += sprintf(page + len, "name : %s\n", DRIVERLNAME);
77 len += sprintf(page + len, "release : %s\n", DRIVERRELEASE_DIDD);
78 len += sprintf(page + len, "build : %s(%s)\n",
79 diva_didd_common_code_build, DIVA_BUILD);
80 len += sprintf(page + len, "revision : %s\n", getrev(tmprev));
81
82 if (off + count >= len)
83 *eof = 1;
84 if (len < off)
85 return 0;
86 *start = page + off;
87 return ((count < len - off) ? count : len - off);
88}
89
90static int DIVA_INIT_FUNCTION create_proc(void)
91{
92 proc_net_eicon = create_proc_entry(main_proc_dir, S_IFDIR, proc_net);
93
94 if (proc_net_eicon) {
95 if ((proc_didd =
96 create_proc_entry(DRIVERLNAME, S_IFREG | S_IRUGO,
97 proc_net_eicon))) {
98 proc_didd->read_proc = proc_read;
99 }
100 return (1);
101 }
102 return (0);
103}
104
105static void DIVA_EXIT_FUNCTION remove_proc(void)
106{
107 remove_proc_entry(DRIVERLNAME, proc_net_eicon);
108 remove_proc_entry(main_proc_dir, proc_net);
109}
110
111static int DIVA_INIT_FUNCTION divadidd_init(void)
112{
113 char tmprev[32];
114 int ret = 0;
115
116 printk(KERN_INFO "%s\n", DRIVERNAME);
117 printk(KERN_INFO "%s: Rel:%s Rev:", DRIVERLNAME, DRIVERRELEASE_DIDD);
118 strcpy(tmprev, main_revision);
119 printk("%s Build:%s(%s)\n", getrev(tmprev),
120 diva_didd_common_code_build, DIVA_BUILD);
121
122 if (!create_proc()) {
123 printk(KERN_ERR "%s: could not create proc entry\n",
124 DRIVERLNAME);
125 ret = -EIO;
126 goto out;
127 }
128
129 if (!diddfunc_init()) {
130 printk(KERN_ERR "%s: failed to connect to DIDD.\n",
131 DRIVERLNAME);
132#ifdef MODULE
133 remove_proc();
134#endif
135 ret = -EIO;
136 goto out;
137 }
138
139 out:
140 return (ret);
141}
142
143static void DIVA_EXIT_FUNCTION divadidd_exit(void)
144{
145 diddfunc_finit();
146 remove_proc();
147 printk(KERN_INFO "%s: module unloaded.\n", DRIVERLNAME);
148}
149
150module_init(divadidd_init);
151module_exit(divadidd_exit);
diff --git a/drivers/isdn/hardware/eicon/diva_dma.c b/drivers/isdn/hardware/eicon/diva_dma.c
new file mode 100644
index 000000000000..f53a7407605f
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/diva_dma.c
@@ -0,0 +1,94 @@
1
2/*
3 *
4 Copyright (c) Eicon Networks, 2002.
5 *
6 This source file is supplied for the use with
7 Eicon Networks range of DIVA Server Adapters.
8 *
9 Eicon File Revision : 2.1
10 *
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2, or (at your option)
14 any later version.
15 *
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
18 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 See the GNU General Public License for more details.
20 *
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26#include "platform.h"
27#include "diva_dma.h"
28/*
29 Every entry has length of PAGE_SIZE
30 and represents one single physical page
31 */
32struct _diva_dma_map_entry {
33 int busy;
34 dword phys_bus_addr; /* 32bit address as seen by the card */
35 void* local_ram_addr; /* local address as seen by the host */
36 void* addr_handle; /* handle uset to free allocated memory */
37};
38/*
39 Create local mapping structure and init it to default state
40 */
41struct _diva_dma_map_entry* diva_alloc_dma_map (void* os_context, int nentries) {
42 diva_dma_map_entry_t* pmap = diva_os_malloc(0, sizeof(*pmap)*(nentries+1));
43 if (pmap)
44 memset (pmap, 0, sizeof(*pmap)*(nentries+1));
45 return pmap;
46}
47/*
48 Free local map (context should be freed before) if any
49 */
50void diva_free_dma_mapping (struct _diva_dma_map_entry* pmap) {
51 if (pmap) {
52 diva_os_free (0, pmap);
53 }
54}
55/*
56 Set information saved on the map entry
57 */
58void diva_init_dma_map_entry (struct _diva_dma_map_entry* pmap,
59 int nr, void* virt, dword phys,
60 void* addr_handle) {
61 pmap[nr].phys_bus_addr = phys;
62 pmap[nr].local_ram_addr = virt;
63 pmap[nr].addr_handle = addr_handle;
64}
65/*
66 Allocate one single entry in the map
67 */
68int diva_alloc_dma_map_entry (struct _diva_dma_map_entry* pmap) {
69 int i;
70 for (i = 0; (pmap && pmap[i].local_ram_addr); i++) {
71 if (!pmap[i].busy) {
72 pmap[i].busy = 1;
73 return (i);
74 }
75 }
76 return (-1);
77}
78/*
79 Free one single entry in the map
80 */
81void diva_free_dma_map_entry (struct _diva_dma_map_entry* pmap, int nr) {
82 pmap[nr].busy = 0;
83}
84/*
85 Get information saved on the map entry
86 */
87void diva_get_dma_map_entry (struct _diva_dma_map_entry* pmap, int nr,
88 void** pvirt, dword* pphys) {
89 *pphys = pmap[nr].phys_bus_addr;
90 *pvirt = pmap[nr].local_ram_addr;
91}
92void* diva_get_entry_handle (struct _diva_dma_map_entry* pmap, int nr) {
93 return (pmap[nr].addr_handle);
94}
diff --git a/drivers/isdn/hardware/eicon/diva_dma.h b/drivers/isdn/hardware/eicon/diva_dma.h
new file mode 100644
index 000000000000..dff80724cdbd
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/diva_dma.h
@@ -0,0 +1,48 @@
1
2/*
3 *
4 Copyright (c) Eicon Networks, 2002.
5 *
6 This source file is supplied for the use with
7 Eicon Networks range of DIVA Server Adapters.
8 *
9 Eicon File Revision : 2.1
10 *
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2, or (at your option)
14 any later version.
15 *
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
18 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 See the GNU General Public License for more details.
20 *
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26#ifndef __DIVA_DMA_MAPPING_IFC_H__
27#define __DIVA_DMA_MAPPING_IFC_H__
28typedef struct _diva_dma_map_entry diva_dma_map_entry_t;
29struct _diva_dma_map_entry* diva_alloc_dma_map (void* os_context, int nentries);
30void diva_init_dma_map_entry (struct _diva_dma_map_entry* pmap,
31 int nr, void* virt, dword phys,
32 void* addr_handle);
33int diva_alloc_dma_map_entry (struct _diva_dma_map_entry* pmap);
34void diva_free_dma_map_entry (struct _diva_dma_map_entry* pmap, int entry);
35void diva_get_dma_map_entry (struct _diva_dma_map_entry* pmap, int nr,
36 void** pvirt, dword* pphys);
37void diva_free_dma_mapping (struct _diva_dma_map_entry* pmap);
38/*
39 Functionality to be implemented by OS wrapper
40 and running in process context
41 */
42void diva_init_dma_map (void* hdev,
43 struct _diva_dma_map_entry** ppmap,
44 int nentries);
45void diva_free_dma_map (void* hdev,
46 struct _diva_dma_map_entry* pmap);
47void* diva_get_entry_handle (struct _diva_dma_map_entry* pmap, int nr);
48#endif
diff --git a/drivers/isdn/hardware/eicon/diva_pci.h b/drivers/isdn/hardware/eicon/diva_pci.h
new file mode 100644
index 000000000000..cc0d5102723a
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/diva_pci.h
@@ -0,0 +1,19 @@
1/* $Id: diva_pci.h,v 1.6 2003/01/04 15:29:45 schindler Exp $ */
2
3#ifndef __DIVA_PCI_INTERFACE_H__
4#define __DIVA_PCI_INTERFACE_H__
5
6void __iomem *divasa_remap_pci_bar(diva_os_xdi_adapter_t *a,
7 int id,
8 unsigned long bar,
9 unsigned long area_length);
10void divasa_unmap_pci_bar(void __iomem *bar);
11unsigned long divasa_get_pci_irq(unsigned char bus,
12 unsigned char func, void *pci_dev_handle);
13unsigned long divasa_get_pci_bar(unsigned char bus,
14 unsigned char func,
15 int bar, void *pci_dev_handle);
16byte diva_os_get_pci_bus(void *pci_dev_handle);
17byte diva_os_get_pci_func(void *pci_dev_handle);
18
19#endif
diff --git a/drivers/isdn/hardware/eicon/divacapi.h b/drivers/isdn/hardware/eicon/divacapi.h
new file mode 100644
index 000000000000..9f5b68037a26
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/divacapi.h
@@ -0,0 +1,1360 @@
1
2/*
3 *
4 Copyright (c) Eicon Networks, 2002.
5 *
6 This source file is supplied for the use with
7 Eicon Networks range of DIVA Server Adapters.
8 *
9 Eicon File Revision : 2.1
10 *
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2, or (at your option)
14 any later version.
15 *
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
18 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 See the GNU General Public License for more details.
20 *
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*#define DEBUG */
28
29
30
31
32
33
34
35
36
37
38
39#define IMPLEMENT_DTMF 1
40#define IMPLEMENT_LINE_INTERCONNECT2 1
41#define IMPLEMENT_ECHO_CANCELLER 1
42#define IMPLEMENT_RTP 1
43#define IMPLEMENT_T38 1
44#define IMPLEMENT_FAX_SUB_SEP_PWD 1
45#define IMPLEMENT_V18 1
46#define IMPLEMENT_DTMF_TONE 1
47#define IMPLEMENT_PIAFS 1
48#define IMPLEMENT_FAX_PAPER_FORMATS 1
49#define IMPLEMENT_VOWN 1
50#define IMPLEMENT_CAPIDTMF 1
51#define IMPLEMENT_FAX_NONSTANDARD 1
52#define VSWITCH_SUPPORT 1
53
54
55#define IMPLEMENT_LINE_INTERCONNECT 0
56#define IMPLEMENT_MARKED_OK_AFTER_FC 1
57
58#include "capidtmf.h"
59
60/*------------------------------------------------------------------*/
61/* Common API internal definitions */
62/*------------------------------------------------------------------*/
63
64#define MAX_APPL 240
65#define MAX_NCCI 127
66
67#define MSG_IN_QUEUE_SIZE ((4096 + 3) & 0xfffc) /* must be multiple of 4 */
68
69
70#define MSG_IN_OVERHEAD sizeof(APPL *)
71
72#define MAX_NL_CHANNEL 255
73#define MAX_DATA_B3 8
74#define MAX_DATA_ACK MAX_DATA_B3
75#define MAX_MULTI_IE 6
76#define MAX_MSG_SIZE 256
77#define MAX_MSG_PARMS 10
78#define MAX_CPN_MASK_SIZE 16
79#define MAX_MSN_CONFIG 10
80#define EXT_CONTROLLER 0x80
81#define CODEC 0x01
82#define CODEC_PERMANENT 0x02
83#define ADV_VOICE 0x03
84#define MAX_CIP_TYPES 5 /* kind of CIP types for group optimization */
85#define C_IND_MASK_DWORDS ((MAX_APPL+32) >> 5)
86
87
88#define FAX_CONNECT_INFO_BUFFER_SIZE 256
89#define NCPI_BUFFER_SIZE 256
90
91#define MAX_CHANNELS_PER_PLCI 8
92#define MAX_INTERNAL_COMMAND_LEVELS 4
93#define INTERNAL_REQ_BUFFER_SIZE 272
94
95#define INTERNAL_IND_BUFFER_SIZE 768
96
97#define DTMF_PARAMETER_BUFFER_SIZE 12
98#define ADV_VOICE_COEF_BUFFER_SIZE 50
99
100#define LI_PLCI_B_QUEUE_ENTRIES 256
101
102
103
104typedef struct _APPL APPL;
105typedef struct _PLCI PLCI;
106typedef struct _NCCI NCCI;
107typedef struct _DIVA_CAPI_ADAPTER DIVA_CAPI_ADAPTER;
108typedef struct _DATA_B3_DESC DATA_B3_DESC;
109typedef struct _DATA_ACK_DESC DATA_ACK_DESC;
110typedef struct manufacturer_profile_s MANUFACTURER_PROFILE;
111typedef struct fax_ncpi_s FAX_NCPI;
112typedef struct api_parse_s API_PARSE;
113typedef struct api_save_s API_SAVE;
114typedef struct msn_config_s MSN_CONFIG;
115typedef struct msn_config_max_s MSN_CONFIG_MAX;
116typedef struct msn_ld_s MSN_LD;
117
118struct manufacturer_profile_s {
119 dword private_options;
120 dword rtp_primary_payloads;
121 dword rtp_additional_payloads;
122};
123
124struct fax_ncpi_s {
125 word options;
126 word format;
127};
128
129struct msn_config_s {
130 byte msn[MAX_CPN_MASK_SIZE];
131};
132
133struct msn_config_max_s {
134 MSN_CONFIG msn_conf[MAX_MSN_CONFIG];
135};
136
137struct msn_ld_s {
138 dword low;
139 dword high;
140};
141
142struct api_parse_s {
143 word length;
144 byte * info;
145};
146
147struct api_save_s {
148 API_PARSE parms[MAX_MSG_PARMS+1];
149 byte info[MAX_MSG_SIZE];
150};
151
152struct _DATA_B3_DESC {
153 word Handle;
154 word Number;
155 word Flags;
156 word Length;
157 void * P;
158};
159
160struct _DATA_ACK_DESC {
161 word Handle;
162 word Number;
163};
164
165typedef void (* t_std_internal_command)(dword Id, PLCI *plci, byte Rc);
166
167/************************************************************************/
168/* Don't forget to adapt dos.asm after changing the _APPL structure!!!! */
169struct _APPL {
170 word Id;
171 word NullCREnable;
172 word CDEnable;
173 dword S_Handle;
174
175
176
177
178
179
180 LIST_ENTRY s_function;
181 dword s_context;
182 word s_count;
183 APPL * s_next;
184 byte * xbuffer_used;
185 void ** xbuffer_internal;
186 void ** xbuffer_ptr;
187
188
189
190
191
192
193 byte * queue;
194 word queue_size;
195 word queue_free;
196 word queue_read;
197 word queue_write;
198 word queue_signal;
199 byte msg_lost;
200 byte appl_flags;
201 word Number;
202
203 word MaxBuffer;
204 byte MaxNCCI;
205 byte MaxNCCIData;
206 word MaxDataLength;
207 word NCCIDataFlowCtrlTimer;
208 byte * ReceiveBuffer;
209 word * DataNCCI;
210 word * DataFlags;
211};
212
213
214struct _PLCI {
215 ENTITY Sig;
216 ENTITY NL;
217 word RNum;
218 word RFlags;
219 BUFFERS RData[2];
220 BUFFERS XData[1];
221 BUFFERS NData[2];
222
223 DIVA_CAPI_ADAPTER *adapter;
224 APPL *appl;
225 PLCI *relatedPTYPLCI;
226 byte Id;
227 byte State;
228 byte sig_req;
229 byte nl_req;
230 byte SuppState;
231 byte channels;
232 byte tel;
233 byte B1_resource;
234 byte B2_prot;
235 byte B3_prot;
236
237 word command;
238 word m_command;
239 word internal_command;
240 word number;
241 word req_in_start;
242 word req_in;
243 word req_out;
244 word msg_in_write_pos;
245 word msg_in_read_pos;
246 word msg_in_wrap_pos;
247
248 void * data_sent_ptr;
249 byte data_sent;
250 byte send_disc;
251 byte sig_global_req;
252 byte sig_remove_id;
253 byte nl_global_req;
254 byte nl_remove_id;
255 byte b_channel;
256 byte adv_nl;
257 byte manufacturer;
258 byte call_dir;
259 byte hook_state;
260 byte spoofed_msg;
261 byte ptyState;
262 byte cr_enquiry;
263 word hangup_flow_ctrl_timer;
264
265 word ncci_ring_list;
266 byte inc_dis_ncci_table[MAX_CHANNELS_PER_PLCI];
267 t_std_internal_command internal_command_queue[MAX_INTERNAL_COMMAND_LEVELS];
268 dword c_ind_mask_table[C_IND_MASK_DWORDS];
269 dword group_optimization_mask_table[C_IND_MASK_DWORDS];
270 byte RBuffer[200];
271 dword msg_in_queue[MSG_IN_QUEUE_SIZE/sizeof(dword)];
272 API_SAVE saved_msg;
273 API_SAVE B_protocol;
274 byte fax_connect_info_length;
275 byte fax_connect_info_buffer[FAX_CONNECT_INFO_BUFFER_SIZE];
276 byte fax_edata_ack_length;
277 word nsf_control_bits;
278 byte ncpi_state;
279 byte ncpi_buffer[NCPI_BUFFER_SIZE];
280
281 byte internal_req_buffer[INTERNAL_REQ_BUFFER_SIZE];
282 byte internal_ind_buffer[INTERNAL_IND_BUFFER_SIZE + 3];
283 dword requested_options_conn;
284 dword requested_options;
285 word B1_facilities;
286 API_SAVE *adjust_b_parms_msg;
287 word adjust_b_facilities;
288 word adjust_b_command;
289 word adjust_b_ncci;
290 word adjust_b_mode;
291 word adjust_b_state;
292 byte adjust_b_restore;
293
294 byte dtmf_rec_active;
295 word dtmf_rec_pulse_ms;
296 word dtmf_rec_pause_ms;
297 byte dtmf_send_requests;
298 word dtmf_send_pulse_ms;
299 word dtmf_send_pause_ms;
300 word dtmf_cmd;
301 word dtmf_msg_number_queue[8];
302 byte dtmf_parameter_length;
303 byte dtmf_parameter_buffer[DTMF_PARAMETER_BUFFER_SIZE];
304
305
306 t_capidtmf_state capidtmf_state;
307
308
309 byte li_bchannel_id; /* BRI: 1..2, PRI: 1..32 */
310 byte li_channel_bits;
311 byte li_notify_update;
312 word li_cmd;
313 word li_write_command;
314 word li_write_channel;
315 word li_plci_b_write_pos;
316 word li_plci_b_read_pos;
317 word li_plci_b_req_pos;
318 dword li_plci_b_queue[LI_PLCI_B_QUEUE_ENTRIES];
319
320
321 word ec_cmd;
322 word ec_idi_options;
323 word ec_tail_length;
324
325
326 byte tone_last_indication_code;
327
328 byte vswitchstate;
329 byte vsprot;
330 byte vsprotdialect;
331 byte notifiedcall; /* Flag if it is a spoofed call */
332
333 int rx_dma_descriptor;
334 dword rx_dma_magic;
335};
336
337
338struct _NCCI {
339 byte data_out;
340 byte data_pending;
341 byte data_ack_out;
342 byte data_ack_pending;
343 DATA_B3_DESC DBuffer[MAX_DATA_B3];
344 DATA_ACK_DESC DataAck[MAX_DATA_ACK];
345};
346
347
348struct _DIVA_CAPI_ADAPTER {
349 IDI_CALL request;
350 byte Id;
351 byte max_plci;
352 byte max_listen;
353 byte listen_active;
354 PLCI *plci;
355 byte ch_ncci[MAX_NL_CHANNEL+1];
356 byte ncci_ch[MAX_NCCI+1];
357 byte ncci_plci[MAX_NCCI+1];
358 byte ncci_state[MAX_NCCI+1];
359 byte ncci_next[MAX_NCCI+1];
360 NCCI ncci[MAX_NCCI+1];
361
362 byte ch_flow_control[MAX_NL_CHANNEL+1]; /* Used by XON protocol */
363 byte ch_flow_control_pending;
364 byte ch_flow_plci[MAX_NL_CHANNEL+1];
365 int last_flow_control_ch;
366
367 dword Info_Mask[MAX_APPL];
368 dword CIP_Mask[MAX_APPL];
369
370 dword Notification_Mask[MAX_APPL];
371 PLCI *codec_listen[MAX_APPL];
372 dword requested_options_table[MAX_APPL];
373 API_PROFILE profile;
374 MANUFACTURER_PROFILE man_profile;
375 dword manufacturer_features;
376
377 byte AdvCodecFLAG;
378 PLCI *AdvCodecPLCI;
379 PLCI *AdvSignalPLCI;
380 APPL *AdvSignalAppl;
381 byte TelOAD[23];
382 byte TelOSA[23];
383 byte scom_appl_disable;
384 PLCI *automatic_lawPLCI;
385 byte automatic_law;
386 byte u_law;
387
388 byte adv_voice_coef_length;
389 byte adv_voice_coef_buffer[ADV_VOICE_COEF_BUFFER_SIZE];
390
391 byte li_pri;
392 byte li_channels;
393 word li_base;
394
395 byte adapter_disabled;
396 byte group_optimization_enabled; /* use application groups if enabled */
397 dword sdram_bar;
398 byte flag_dynamic_l1_down; /* for hunt groups:down layer 1 if no appl present*/
399 byte FlowControlIdTable[256];
400 byte FlowControlSkipTable[256];
401 void* os_card; /* pointer to associated OS dependent adapter structure */
402};
403
404
405/*------------------------------------------------------------------*/
406/* Application flags */
407/*------------------------------------------------------------------*/
408
409#define APPL_FLAG_OLD_LI_SPEC 0x01
410#define APPL_FLAG_PRIV_EC_SPEC 0x02
411
412
413/*------------------------------------------------------------------*/
414/* API parameter definitions */
415/*------------------------------------------------------------------*/
416
417#define X75_TTX 1 /* x.75 for ttx */
418#define TRF 2 /* transparent with hdlc framing */
419#define TRF_IN 3 /* transparent with hdlc fr. inc. */
420#define SDLC 4 /* sdlc, sna layer-2 */
421#define X75_BTX 5 /* x.75 for btx */
422#define LAPD 6 /* lapd (Q.921) */
423#define X25_L2 7 /* x.25 layer-2 */
424#define V120_L2 8 /* V.120 layer-2 protocol */
425#define V42_IN 9 /* V.42 layer-2 protocol, incomming */
426#define V42 10 /* V.42 layer-2 protocol */
427#define MDM_ATP 11 /* AT Parser built in the L2 */
428#define X75_V42BIS 12 /* ISO7776 (X.75 SLP) modified to support V.42 bis compression */
429#define RTPL2_IN 13 /* RTP layer-2 protocol, incomming */
430#define RTPL2 14 /* RTP layer-2 protocol */
431#define V120_V42BIS 15 /* V.120 layer-2 protocol supporting V.42 bis compression */
432
433#define T70NL 1
434#define X25PLP 2
435#define T70NLX 3
436#define TRANSPARENT_NL 4
437#define ISO8208 5
438#define T30 6
439
440
441/*------------------------------------------------------------------*/
442/* FAX interface to IDI */
443/*------------------------------------------------------------------*/
444
445#define CAPI_MAX_HEAD_LINE_SPACE 89
446#define CAPI_MAX_DATE_TIME_LENGTH 18
447
448#define T30_MAX_STATION_ID_LENGTH 20
449#define T30_MAX_SUBADDRESS_LENGTH 20
450#define T30_MAX_PASSWORD_LENGTH 20
451
452typedef struct t30_info_s T30_INFO;
453struct t30_info_s {
454 byte code;
455 byte rate_div_2400;
456 byte resolution;
457 byte data_format;
458 byte pages_low;
459 byte pages_high;
460 byte operating_mode;
461 byte control_bits_low;
462 byte control_bits_high;
463 byte feature_bits_low;
464 byte feature_bits_high;
465 byte recording_properties;
466 byte universal_6;
467 byte universal_7;
468 byte station_id_len;
469 byte head_line_len;
470 byte station_id[T30_MAX_STATION_ID_LENGTH];
471/* byte head_line[]; */
472/* byte sub_sep_length; */
473/* byte sub_sep_field[]; */
474/* byte pwd_length; */
475/* byte pwd_field[]; */
476/* byte nsf_info_length; */
477/* byte nsf_info_field[]; */
478};
479
480
481#define T30_RESOLUTION_R8_0385 0x00
482#define T30_RESOLUTION_R8_0770_OR_200 0x01
483#define T30_RESOLUTION_R8_1540 0x02
484#define T30_RESOLUTION_R16_1540_OR_400 0x04
485#define T30_RESOLUTION_R4_0385_OR_100 0x08
486#define T30_RESOLUTION_300_300 0x10
487#define T30_RESOLUTION_INCH_BASED 0x40
488#define T30_RESOLUTION_METRIC_BASED 0x80
489
490#define T30_RECORDING_WIDTH_ISO_A4 0
491#define T30_RECORDING_WIDTH_ISO_B4 1
492#define T30_RECORDING_WIDTH_ISO_A3 2
493#define T30_RECORDING_WIDTH_COUNT 3
494
495#define T30_RECORDING_LENGTH_ISO_A4 0
496#define T30_RECORDING_LENGTH_ISO_B4 1
497#define T30_RECORDING_LENGTH_UNLIMITED 2
498#define T30_RECORDING_LENGTH_COUNT 3
499
500#define T30_MIN_SCANLINE_TIME_00_00_00 0
501#define T30_MIN_SCANLINE_TIME_05_05_05 1
502#define T30_MIN_SCANLINE_TIME_10_05_05 2
503#define T30_MIN_SCANLINE_TIME_10_10_10 3
504#define T30_MIN_SCANLINE_TIME_20_10_10 4
505#define T30_MIN_SCANLINE_TIME_20_20_20 5
506#define T30_MIN_SCANLINE_TIME_40_20_20 6
507#define T30_MIN_SCANLINE_TIME_40_40_40 7
508#define T30_MIN_SCANLINE_TIME_RES_8 8
509#define T30_MIN_SCANLINE_TIME_RES_9 9
510#define T30_MIN_SCANLINE_TIME_RES_10 10
511#define T30_MIN_SCANLINE_TIME_10_10_05 11
512#define T30_MIN_SCANLINE_TIME_20_10_05 12
513#define T30_MIN_SCANLINE_TIME_20_20_10 13
514#define T30_MIN_SCANLINE_TIME_40_20_10 14
515#define T30_MIN_SCANLINE_TIME_40_40_20 15
516#define T30_MIN_SCANLINE_TIME_COUNT 16
517
518#define T30_DATA_FORMAT_SFF 0
519#define T30_DATA_FORMAT_ASCII 1
520#define T30_DATA_FORMAT_NATIVE 2
521#define T30_DATA_FORMAT_COUNT 3
522
523
524#define T30_OPERATING_MODE_STANDARD 0
525#define T30_OPERATING_MODE_CLASS2 1
526#define T30_OPERATING_MODE_CLASS1 2
527#define T30_OPERATING_MODE_CAPI 3
528#define T30_OPERATING_MODE_CAPI_NEG 4
529#define T30_OPERATING_MODE_COUNT 5
530
531 /* EDATA transmit messages */
532#define EDATA_T30_DIS 0x01
533#define EDATA_T30_FTT 0x02
534#define EDATA_T30_MCF 0x03
535#define EDATA_T30_PARAMETERS 0x04
536
537 /* EDATA receive messages */
538#define EDATA_T30_DCS 0x81
539#define EDATA_T30_TRAIN_OK 0x82
540#define EDATA_T30_EOP 0x83
541#define EDATA_T30_MPS 0x84
542#define EDATA_T30_EOM 0x85
543#define EDATA_T30_DTC 0x86
544#define EDATA_T30_PAGE_END 0x87 /* Indicates end of page data. Reserved, but not implemented ! */
545#define EDATA_T30_EOP_CAPI 0x88
546
547
548#define T30_SUCCESS 0
549#define T30_ERR_NO_DIS_RECEIVED 1
550#define T30_ERR_TIMEOUT_NO_RESPONSE 2
551#define T30_ERR_RETRY_NO_RESPONSE 3
552#define T30_ERR_TOO_MANY_REPEATS 4
553#define T30_ERR_UNEXPECTED_MESSAGE 5
554#define T30_ERR_UNEXPECTED_DCN 6
555#define T30_ERR_DTC_UNSUPPORTED 7
556#define T30_ERR_ALL_RATES_FAILED 8
557#define T30_ERR_TOO_MANY_TRAINS 9
558#define T30_ERR_RECEIVE_CORRUPTED 10
559#define T30_ERR_UNEXPECTED_DISC 11
560#define T30_ERR_APPLICATION_DISC 12
561#define T30_ERR_INCOMPATIBLE_DIS 13
562#define T30_ERR_INCOMPATIBLE_DCS 14
563#define T30_ERR_TIMEOUT_NO_COMMAND 15
564#define T30_ERR_RETRY_NO_COMMAND 16
565#define T30_ERR_TIMEOUT_COMMAND_TOO_LONG 17
566#define T30_ERR_TIMEOUT_RESPONSE_TOO_LONG 18
567#define T30_ERR_NOT_IDENTIFIED 19
568#define T30_ERR_SUPERVISORY_TIMEOUT 20
569#define T30_ERR_TOO_LONG_SCAN_LINE 21
570/* #define T30_ERR_RETRY_NO_PAGE_AFTER_MPS 22 */
571#define T30_ERR_RETRY_NO_PAGE_RECEIVED 23
572#define T30_ERR_RETRY_NO_DCS_AFTER_FTT 24
573#define T30_ERR_RETRY_NO_DCS_AFTER_EOM 25
574#define T30_ERR_RETRY_NO_DCS_AFTER_MPS 26
575#define T30_ERR_RETRY_NO_DCN_AFTER_MCF 27
576#define T30_ERR_RETRY_NO_DCN_AFTER_RTN 28
577#define T30_ERR_RETRY_NO_CFR 29
578#define T30_ERR_RETRY_NO_MCF_AFTER_EOP 30
579#define T30_ERR_RETRY_NO_MCF_AFTER_EOM 31
580#define T30_ERR_RETRY_NO_MCF_AFTER_MPS 32
581#define T30_ERR_SUB_SEP_UNSUPPORTED 33
582#define T30_ERR_PWD_UNSUPPORTED 34
583#define T30_ERR_SUB_SEP_PWD_UNSUPPORTED 35
584#define T30_ERR_INVALID_COMMAND_FRAME 36
585#define T30_ERR_UNSUPPORTED_PAGE_CODING 37
586#define T30_ERR_INVALID_PAGE_CODING 38
587#define T30_ERR_INCOMPATIBLE_PAGE_CONFIG 39
588#define T30_ERR_TIMEOUT_FROM_APPLICATION 40
589#define T30_ERR_V34FAX_NO_REACTION_ON_MARK 41
590#define T30_ERR_V34FAX_TRAINING_TIMEOUT 42
591#define T30_ERR_V34FAX_UNEXPECTED_V21 43
592#define T30_ERR_V34FAX_PRIMARY_CTS_ON 44
593#define T30_ERR_V34FAX_TURNAROUND_POLLING 45
594#define T30_ERR_V34FAX_V8_INCOMPATIBILITY 46
595
596
597#define T30_CONTROL_BIT_DISABLE_FINE 0x0001
598#define T30_CONTROL_BIT_ENABLE_ECM 0x0002
599#define T30_CONTROL_BIT_ECM_64_BYTES 0x0004
600#define T30_CONTROL_BIT_ENABLE_2D_CODING 0x0008
601#define T30_CONTROL_BIT_ENABLE_T6_CODING 0x0010
602#define T30_CONTROL_BIT_ENABLE_UNCOMPR 0x0020
603#define T30_CONTROL_BIT_ACCEPT_POLLING 0x0040
604#define T30_CONTROL_BIT_REQUEST_POLLING 0x0080
605#define T30_CONTROL_BIT_MORE_DOCUMENTS 0x0100
606#define T30_CONTROL_BIT_ACCEPT_SUBADDRESS 0x0200
607#define T30_CONTROL_BIT_ACCEPT_SEL_POLLING 0x0400
608#define T30_CONTROL_BIT_ACCEPT_PASSWORD 0x0800
609#define T30_CONTROL_BIT_ENABLE_V34FAX 0x1000
610#define T30_CONTROL_BIT_EARLY_CONNECT 0x2000
611
612#define T30_CONTROL_BIT_ALL_FEATURES (T30_CONTROL_BIT_ENABLE_ECM | T30_CONTROL_BIT_ENABLE_2D_CODING | T30_CONTROL_BIT_ENABLE_T6_CODING | T30_CONTROL_BIT_ENABLE_UNCOMPR | T30_CONTROL_BIT_ENABLE_V34FAX)
613
614#define T30_FEATURE_BIT_FINE 0x0001
615#define T30_FEATURE_BIT_ECM 0x0002
616#define T30_FEATURE_BIT_ECM_64_BYTES 0x0004
617#define T30_FEATURE_BIT_2D_CODING 0x0008
618#define T30_FEATURE_BIT_T6_CODING 0x0010
619#define T30_FEATURE_BIT_UNCOMPR_ENABLED 0x0020
620#define T30_FEATURE_BIT_POLLING 0x0040
621#define T30_FEATURE_BIT_MORE_DOCUMENTS 0x0100
622#define T30_FEATURE_BIT_V34FAX 0x1000
623
624
625#define T30_NSF_CONTROL_BIT_ENABLE_NSF 0x0001
626#define T30_NSF_CONTROL_BIT_RAW_INFO 0x0002
627#define T30_NSF_CONTROL_BIT_NEGOTIATE_IND 0x0004
628#define T30_NSF_CONTROL_BIT_NEGOTIATE_RESP 0x0008
629
630#define T30_NSF_ELEMENT_NSF_FIF 0x00
631#define T30_NSF_ELEMENT_NSC_FIF 0x01
632#define T30_NSF_ELEMENT_NSS_FIF 0x02
633#define T30_NSF_ELEMENT_COMPANY_NAME 0x03
634
635
636/*------------------------------------------------------------------*/
637/* Analog modem definitions */
638/*------------------------------------------------------------------*/
639
640typedef struct async_s ASYNC_FORMAT;
641struct async_s {
642 unsigned pe: 1;
643 unsigned parity:2;
644 unsigned spare: 2;
645 unsigned stp: 1;
646 unsigned ch_len:2; /* 3th octett in CAI */
647};
648
649
650/*------------------------------------------------------------------*/
651/* PLCI/NCCI states */
652/*------------------------------------------------------------------*/
653
654#define IDLE 0
655#define OUTG_CON_PENDING 1
656#define INC_CON_PENDING 2
657#define INC_CON_ALERT 3
658#define INC_CON_ACCEPT 4
659#define INC_ACT_PENDING 5
660#define LISTENING 6
661#define CONNECTED 7
662#define OUTG_DIS_PENDING 8
663#define INC_DIS_PENDING 9
664#define LOCAL_CONNECT 10
665#define INC_RES_PENDING 11
666#define OUTG_RES_PENDING 12
667#define SUSPENDING 13
668#define ADVANCED_VOICE_SIG 14
669#define ADVANCED_VOICE_NOSIG 15
670#define RESUMING 16
671#define INC_CON_CONNECTED_ALERT 17
672#define OUTG_REJ_PENDING 18
673
674
675/*------------------------------------------------------------------*/
676/* auxilliary states for supplementary services */
677/*------------------------------------------------------------------*/
678
679#define IDLE 0
680#define HOLD_REQUEST 1
681#define HOLD_INDICATE 2
682#define CALL_HELD 3
683#define RETRIEVE_REQUEST 4
684#define RETRIEVE_INDICATION 5
685
686/*------------------------------------------------------------------*/
687/* Capi IE + Msg types */
688/*------------------------------------------------------------------*/
689#define ESC_CAUSE 0x800|CAU /* Escape cause element */
690#define ESC_MSGTYPE 0x800|MSGTYPEIE /* Escape message type */
691#define ESC_CHI 0x800|CHI /* Escape channel id */
692#define ESC_LAW 0x800|BC /* Escape law info */
693#define ESC_CR 0x800|CRIE /* Escape CallReference */
694#define ESC_PROFILE 0x800|PROFILEIE /* Escape profile */
695#define ESC_SSEXT 0x800|SSEXTIE /* Escape Supplem. Serv.*/
696#define ESC_VSWITCH 0x800|VSWITCHIE /* Escape VSwitch */
697#define CST 0x14 /* Call State i.e. */
698#define PI 0x1E /* Progress Indicator */
699#define NI 0x27 /* Notification Ind */
700#define CONN_NR 0x4C /* Connected Number */
701#define CONG_RNR 0xBF /* Congestion RNR */
702#define CONG_RR 0xB0 /* Congestion RR */
703#define RESERVED 0xFF /* Res. for future use */
704#define ON_BOARD_CODEC 0x02 /* external controller */
705#define HANDSET 0x04 /* Codec+Handset(Pro11) */
706#define HOOK_SUPPORT 0x01 /* activate Hook signal */
707#define SCR 0x7a /* unscreened number */
708
709#define HOOK_OFF_REQ 0x9001 /* internal conn req */
710#define HOOK_ON_REQ 0x9002 /* internal disc req */
711#define SUSPEND_REQ 0x9003 /* internal susp req */
712#define RESUME_REQ 0x9004 /* internal resume req */
713#define USELAW_REQ 0x9005 /* internal law req */
714#define LISTEN_SIG_ASSIGN_PEND 0x9006
715#define PERM_LIST_REQ 0x900a /* permanent conn DCE */
716#define C_HOLD_REQ 0x9011
717#define C_RETRIEVE_REQ 0x9012
718#define C_NCR_FAC_REQ 0x9013
719#define PERM_COD_ASSIGN 0x9014
720#define PERM_COD_CALL 0x9015
721#define PERM_COD_HOOK 0x9016
722#define PERM_COD_CONN_PEND 0x9017 /* wait for connect_con */
723#define PTY_REQ_PEND 0x9018
724#define CD_REQ_PEND 0x9019
725#define CF_START_PEND 0x901a
726#define CF_STOP_PEND 0x901b
727#define ECT_REQ_PEND 0x901c
728#define GETSERV_REQ_PEND 0x901d
729#define BLOCK_PLCI 0x901e
730#define INTERR_NUMBERS_REQ_PEND 0x901f
731#define INTERR_DIVERSION_REQ_PEND 0x9020
732#define MWI_ACTIVATE_REQ_PEND 0x9021
733#define MWI_DEACTIVATE_REQ_PEND 0x9022
734#define SSEXT_REQ_COMMAND 0x9023
735#define SSEXT_NC_REQ_COMMAND 0x9024
736#define START_L1_SIG_ASSIGN_PEND 0x9025
737#define REM_L1_SIG_ASSIGN_PEND 0x9026
738#define CONF_BEGIN_REQ_PEND 0x9027
739#define CONF_ADD_REQ_PEND 0x9028
740#define CONF_SPLIT_REQ_PEND 0x9029
741#define CONF_DROP_REQ_PEND 0x902a
742#define CONF_ISOLATE_REQ_PEND 0x902b
743#define CONF_REATTACH_REQ_PEND 0x902c
744#define VSWITCH_REQ_PEND 0x902d
745#define GET_MWI_STATE 0x902e
746#define CCBS_REQUEST_REQ_PEND 0x902f
747#define CCBS_DEACTIVATE_REQ_PEND 0x9030
748#define CCBS_INTERROGATE_REQ_PEND 0x9031
749
750#define NO_INTERNAL_COMMAND 0
751#define DTMF_COMMAND_1 1
752#define DTMF_COMMAND_2 2
753#define DTMF_COMMAND_3 3
754#define MIXER_COMMAND_1 4
755#define MIXER_COMMAND_2 5
756#define MIXER_COMMAND_3 6
757#define ADV_VOICE_COMMAND_CONNECT_1 7
758#define ADV_VOICE_COMMAND_CONNECT_2 8
759#define ADV_VOICE_COMMAND_CONNECT_3 9
760#define ADV_VOICE_COMMAND_DISCONNECT_1 10
761#define ADV_VOICE_COMMAND_DISCONNECT_2 11
762#define ADV_VOICE_COMMAND_DISCONNECT_3 12
763#define ADJUST_B_RESTORE_1 13
764#define ADJUST_B_RESTORE_2 14
765#define RESET_B3_COMMAND_1 15
766#define SELECT_B_COMMAND_1 16
767#define FAX_CONNECT_INFO_COMMAND_1 17
768#define FAX_CONNECT_INFO_COMMAND_2 18
769#define FAX_ADJUST_B23_COMMAND_1 19
770#define FAX_ADJUST_B23_COMMAND_2 20
771#define EC_COMMAND_1 21
772#define EC_COMMAND_2 22
773#define EC_COMMAND_3 23
774#define RTP_CONNECT_B3_REQ_COMMAND_1 24
775#define RTP_CONNECT_B3_REQ_COMMAND_2 25
776#define RTP_CONNECT_B3_REQ_COMMAND_3 26
777#define RTP_CONNECT_B3_RES_COMMAND_1 27
778#define RTP_CONNECT_B3_RES_COMMAND_2 28
779#define RTP_CONNECT_B3_RES_COMMAND_3 29
780#define HOLD_SAVE_COMMAND_1 30
781#define RETRIEVE_RESTORE_COMMAND_1 31
782#define FAX_DISCONNECT_COMMAND_1 32
783#define FAX_DISCONNECT_COMMAND_2 33
784#define FAX_DISCONNECT_COMMAND_3 34
785#define FAX_EDATA_ACK_COMMAND_1 35
786#define FAX_EDATA_ACK_COMMAND_2 36
787#define FAX_CONNECT_ACK_COMMAND_1 37
788#define FAX_CONNECT_ACK_COMMAND_2 38
789#define STD_INTERNAL_COMMAND_COUNT 39
790
791#define UID 0x2d /* User Id for Mgmt */
792
793#define CALL_DIR_OUT 0x01 /* call direction of initial call */
794#define CALL_DIR_IN 0x02
795#define CALL_DIR_ORIGINATE 0x04 /* DTE/DCE direction according to */
796#define CALL_DIR_ANSWER 0x08 /* state of B-Channel Operation */
797#define CALL_DIR_FORCE_OUTG_NL 0x10 /* for RESET_B3 reconnect, after DISC_B3... */
798
799#define AWAITING_MANUF_CON 0x80 /* command spoofing flags */
800#define SPOOFING_REQUIRED 0xff
801#define AWAITING_SELECT_B 0xef
802
803/*------------------------------------------------------------------*/
804/* B_CTRL / DSP_CTRL */
805/*------------------------------------------------------------------*/
806
807#define DSP_CTRL_OLD_SET_MIXER_COEFFICIENTS 0x01
808#define DSP_CTRL_SET_BCHANNEL_PASSIVATION_BRI 0x02
809#define DSP_CTRL_SET_DTMF_PARAMETERS 0x03
810
811#define MANUFACTURER_FEATURE_SLAVE_CODEC 0x00000001L
812#define MANUFACTURER_FEATURE_FAX_MORE_DOCUMENTS 0x00000002L
813#define MANUFACTURER_FEATURE_HARDDTMF 0x00000004L
814#define MANUFACTURER_FEATURE_SOFTDTMF_SEND 0x00000008L
815#define MANUFACTURER_FEATURE_DTMF_PARAMETERS 0x00000010L
816#define MANUFACTURER_FEATURE_SOFTDTMF_RECEIVE 0x00000020L
817#define MANUFACTURER_FEATURE_FAX_SUB_SEP_PWD 0x00000040L
818#define MANUFACTURER_FEATURE_V18 0x00000080L
819#define MANUFACTURER_FEATURE_MIXER_CH_CH 0x00000100L
820#define MANUFACTURER_FEATURE_MIXER_CH_PC 0x00000200L
821#define MANUFACTURER_FEATURE_MIXER_PC_CH 0x00000400L
822#define MANUFACTURER_FEATURE_MIXER_PC_PC 0x00000800L
823#define MANUFACTURER_FEATURE_ECHO_CANCELLER 0x00001000L
824#define MANUFACTURER_FEATURE_RTP 0x00002000L
825#define MANUFACTURER_FEATURE_T38 0x00004000L
826#define MANUFACTURER_FEATURE_TRANSP_DELIVERY_CONF 0x00008000L
827#define MANUFACTURER_FEATURE_XONOFF_FLOW_CONTROL 0x00010000L
828#define MANUFACTURER_FEATURE_OOB_CHANNEL 0x00020000L
829#define MANUFACTURER_FEATURE_IN_BAND_CHANNEL 0x00040000L
830#define MANUFACTURER_FEATURE_IN_BAND_FEATURE 0x00080000L
831#define MANUFACTURER_FEATURE_PIAFS 0x00100000L
832#define MANUFACTURER_FEATURE_DTMF_TONE 0x00200000L
833#define MANUFACTURER_FEATURE_FAX_PAPER_FORMATS 0x00400000L
834#define MANUFACTURER_FEATURE_OK_FC_LABEL 0x00800000L
835#define MANUFACTURER_FEATURE_VOWN 0x01000000L
836#define MANUFACTURER_FEATURE_XCONNECT 0x02000000L
837#define MANUFACTURER_FEATURE_DMACONNECT 0x04000000L
838#define MANUFACTURER_FEATURE_AUDIO_TAP 0x08000000L
839#define MANUFACTURER_FEATURE_FAX_NONSTANDARD 0x10000000L
840
841/*------------------------------------------------------------------*/
842/* DTMF interface to IDI */
843/*------------------------------------------------------------------*/
844
845
846#define DTMF_DIGIT_TONE_LOW_GROUP_697_HZ 0x00
847#define DTMF_DIGIT_TONE_LOW_GROUP_770_HZ 0x01
848#define DTMF_DIGIT_TONE_LOW_GROUP_852_HZ 0x02
849#define DTMF_DIGIT_TONE_LOW_GROUP_941_HZ 0x03
850#define DTMF_DIGIT_TONE_LOW_GROUP_MASK 0x03
851#define DTMF_DIGIT_TONE_HIGH_GROUP_1209_HZ 0x00
852#define DTMF_DIGIT_TONE_HIGH_GROUP_1336_HZ 0x04
853#define DTMF_DIGIT_TONE_HIGH_GROUP_1477_HZ 0x08
854#define DTMF_DIGIT_TONE_HIGH_GROUP_1633_HZ 0x0c
855#define DTMF_DIGIT_TONE_HIGH_GROUP_MASK 0x0c
856#define DTMF_DIGIT_TONE_CODE_0 0x07
857#define DTMF_DIGIT_TONE_CODE_1 0x00
858#define DTMF_DIGIT_TONE_CODE_2 0x04
859#define DTMF_DIGIT_TONE_CODE_3 0x08
860#define DTMF_DIGIT_TONE_CODE_4 0x01
861#define DTMF_DIGIT_TONE_CODE_5 0x05
862#define DTMF_DIGIT_TONE_CODE_6 0x09
863#define DTMF_DIGIT_TONE_CODE_7 0x02
864#define DTMF_DIGIT_TONE_CODE_8 0x06
865#define DTMF_DIGIT_TONE_CODE_9 0x0a
866#define DTMF_DIGIT_TONE_CODE_STAR 0x03
867#define DTMF_DIGIT_TONE_CODE_HASHMARK 0x0b
868#define DTMF_DIGIT_TONE_CODE_A 0x0c
869#define DTMF_DIGIT_TONE_CODE_B 0x0d
870#define DTMF_DIGIT_TONE_CODE_C 0x0e
871#define DTMF_DIGIT_TONE_CODE_D 0x0f
872
873#define DTMF_UDATA_REQUEST_SEND_DIGITS 16
874#define DTMF_UDATA_REQUEST_ENABLE_RECEIVER 17
875#define DTMF_UDATA_REQUEST_DISABLE_RECEIVER 18
876#define DTMF_UDATA_INDICATION_DIGITS_SENT 16
877#define DTMF_UDATA_INDICATION_DIGITS_RECEIVED 17
878#define DTMF_UDATA_INDICATION_MODEM_CALLING_TONE 18
879#define DTMF_UDATA_INDICATION_FAX_CALLING_TONE 19
880#define DTMF_UDATA_INDICATION_ANSWER_TONE 20
881
882#define UDATA_REQUEST_MIXER_TAP_DATA 27
883#define UDATA_INDICATION_MIXER_TAP_DATA 27
884
885#define DTMF_LISTEN_ACTIVE_FLAG 0x01
886#define DTMF_SEND_DIGIT_FLAG 0x01
887
888
889/*------------------------------------------------------------------*/
890/* Mixer interface to IDI */
891/*------------------------------------------------------------------*/
892
893
894#define LI2_FLAG_PCCONNECT_A_B 0x40000000
895#define LI2_FLAG_PCCONNECT_B_A 0x80000000
896
897#define MIXER_BCHANNELS_BRI 2
898#define MIXER_IC_CHANNELS_BRI MIXER_BCHANNELS_BRI
899#define MIXER_IC_CHANNEL_BASE MIXER_BCHANNELS_BRI
900#define MIXER_CHANNELS_BRI (MIXER_BCHANNELS_BRI + MIXER_IC_CHANNELS_BRI)
901#define MIXER_CHANNELS_PRI 32
902
903typedef struct li_config_s LI_CONFIG;
904
905struct xconnect_card_address_s {
906 dword low;
907 dword high;
908};
909
910struct xconnect_transfer_address_s {
911 struct xconnect_card_address_s card_address;
912 dword offset;
913};
914
915struct li_config_s {
916 DIVA_CAPI_ADAPTER *adapter;
917 PLCI *plci;
918 struct xconnect_transfer_address_s send_b;
919 struct xconnect_transfer_address_s send_pc;
920 byte *flag_table; /* dword aligned and sized */
921 byte *coef_table; /* dword aligned and sized */
922 byte channel;
923 byte curchnl;
924 byte chflags;
925};
926
927extern LI_CONFIG *li_config_table;
928extern word li_total_channels;
929
930#define LI_CHANNEL_INVOLVED 0x01
931#define LI_CHANNEL_ACTIVE 0x02
932#define LI_CHANNEL_TX_DATA 0x04
933#define LI_CHANNEL_RX_DATA 0x08
934#define LI_CHANNEL_CONFERENCE 0x10
935#define LI_CHANNEL_ADDRESSES_SET 0x80
936
937#define LI_CHFLAG_MONITOR 0x01
938#define LI_CHFLAG_MIX 0x02
939#define LI_CHFLAG_LOOP 0x04
940
941#define LI_FLAG_INTERCONNECT 0x01
942#define LI_FLAG_MONITOR 0x02
943#define LI_FLAG_MIX 0x04
944#define LI_FLAG_PCCONNECT 0x08
945#define LI_FLAG_CONFERENCE 0x10
946#define LI_FLAG_ANNOUNCEMENT 0x20
947
948#define LI_COEF_CH_CH 0x01
949#define LI_COEF_CH_PC 0x02
950#define LI_COEF_PC_CH 0x04
951#define LI_COEF_PC_PC 0x08
952#define LI_COEF_CH_CH_SET 0x10
953#define LI_COEF_CH_PC_SET 0x20
954#define LI_COEF_PC_CH_SET 0x40
955#define LI_COEF_PC_PC_SET 0x80
956
957#define LI_REQ_SILENT_UPDATE 0xffff
958
959#define LI_PLCI_B_LAST_FLAG ((dword) 0x80000000L)
960#define LI_PLCI_B_DISC_FLAG ((dword) 0x40000000L)
961#define LI_PLCI_B_SKIP_FLAG ((dword) 0x20000000L)
962#define LI_PLCI_B_FLAG_MASK ((dword) 0xe0000000L)
963
964#define UDATA_REQUEST_SET_MIXER_COEFS_BRI 24
965#define UDATA_REQUEST_SET_MIXER_COEFS_PRI_SYNC 25
966#define UDATA_REQUEST_SET_MIXER_COEFS_PRI_ASYN 26
967#define UDATA_INDICATION_MIXER_COEFS_SET 24
968
969#define MIXER_FEATURE_ENABLE_TX_DATA 0x0001
970#define MIXER_FEATURE_ENABLE_RX_DATA 0x0002
971
972#define MIXER_COEF_LINE_CHANNEL_MASK 0x1f
973#define MIXER_COEF_LINE_FROM_PC_FLAG 0x20
974#define MIXER_COEF_LINE_TO_PC_FLAG 0x40
975#define MIXER_COEF_LINE_ROW_FLAG 0x80
976
977#define UDATA_REQUEST_XCONNECT_FROM 28
978#define UDATA_INDICATION_XCONNECT_FROM 28
979#define UDATA_REQUEST_XCONNECT_TO 29
980#define UDATA_INDICATION_XCONNECT_TO 29
981
982#define XCONNECT_CHANNEL_PORT_B 0x0000
983#define XCONNECT_CHANNEL_PORT_PC 0x8000
984#define XCONNECT_CHANNEL_PORT_MASK 0x8000
985#define XCONNECT_CHANNEL_NUMBER_MASK 0x7fff
986#define XCONNECT_CHANNEL_PORT_COUNT 2
987
988#define XCONNECT_SUCCESS 0x0000
989#define XCONNECT_ERROR 0x0001
990
991
992/*------------------------------------------------------------------*/
993/* Echo canceller interface to IDI */
994/*------------------------------------------------------------------*/
995
996
997#define PRIVATE_ECHO_CANCELLER 0
998
999#define PRIV_SELECTOR_ECHO_CANCELLER 255
1000
1001#define EC_ENABLE_OPERATION 1
1002#define EC_DISABLE_OPERATION 2
1003#define EC_FREEZE_COEFFICIENTS 3
1004#define EC_RESUME_COEFFICIENT_UPDATE 4
1005#define EC_RESET_COEFFICIENTS 5
1006
1007#define EC_DISABLE_NON_LINEAR_PROCESSING 0x0001
1008#define EC_DO_NOT_REQUIRE_REVERSALS 0x0002
1009#define EC_DETECT_DISABLE_TONE 0x0004
1010
1011#define EC_SUCCESS 0
1012#define EC_UNSUPPORTED_OPERATION 1
1013
1014#define EC_BYPASS_DUE_TO_CONTINUOUS_2100HZ 1
1015#define EC_BYPASS_DUE_TO_REVERSED_2100HZ 2
1016#define EC_BYPASS_RELEASED 3
1017
1018#define DSP_CTRL_SET_LEC_PARAMETERS 0x05
1019
1020#define LEC_ENABLE_ECHO_CANCELLER 0x0001
1021#define LEC_ENABLE_2100HZ_DETECTOR 0x0002
1022#define LEC_REQUIRE_2100HZ_REVERSALS 0x0004
1023#define LEC_MANUAL_DISABLE 0x0008
1024#define LEC_ENABLE_NONLINEAR_PROCESSING 0x0010
1025#define LEC_FREEZE_COEFFICIENTS 0x0020
1026#define LEC_RESET_COEFFICIENTS 0x8000
1027
1028#define LEC_MAX_SUPPORTED_TAIL_LENGTH 32
1029
1030#define LEC_UDATA_INDICATION_DISABLE_DETECT 9
1031
1032#define LEC_DISABLE_TYPE_CONTIGNUOUS_2100HZ 0x00
1033#define LEC_DISABLE_TYPE_REVERSED_2100HZ 0x01
1034#define LEC_DISABLE_RELEASED 0x02
1035
1036
1037/*------------------------------------------------------------------*/
1038/* RTP interface to IDI */
1039/*------------------------------------------------------------------*/
1040
1041
1042#define B1_RTP 31
1043#define B2_RTP 31
1044#define B3_RTP 31
1045
1046#define PRIVATE_RTP 1
1047
1048#define RTP_PRIM_PAYLOAD_PCMU_8000 0
1049#define RTP_PRIM_PAYLOAD_1016_8000 1
1050#define RTP_PRIM_PAYLOAD_G726_32_8000 2
1051#define RTP_PRIM_PAYLOAD_GSM_8000 3
1052#define RTP_PRIM_PAYLOAD_G723_8000 4
1053#define RTP_PRIM_PAYLOAD_DVI4_8000 5
1054#define RTP_PRIM_PAYLOAD_DVI4_16000 6
1055#define RTP_PRIM_PAYLOAD_LPC_8000 7
1056#define RTP_PRIM_PAYLOAD_PCMA_8000 8
1057#define RTP_PRIM_PAYLOAD_G722_16000 9
1058#define RTP_PRIM_PAYLOAD_QCELP_8000 12
1059#define RTP_PRIM_PAYLOAD_G728_8000 14
1060#define RTP_PRIM_PAYLOAD_G729_8000 18
1061#define RTP_PRIM_PAYLOAD_GSM_HR_8000 30
1062#define RTP_PRIM_PAYLOAD_GSM_EFR_8000 31
1063
1064#define RTP_ADD_PAYLOAD_BASE 32
1065#define RTP_ADD_PAYLOAD_RED 32
1066#define RTP_ADD_PAYLOAD_CN_8000 33
1067#define RTP_ADD_PAYLOAD_DTMF 34
1068
1069#define RTP_SUCCESS 0
1070#define RTP_ERR_SSRC_OR_PAYLOAD_CHANGE 1
1071
1072#define UDATA_REQUEST_RTP_RECONFIGURE 64
1073#define UDATA_INDICATION_RTP_CHANGE 65
1074#define BUDATA_REQUEST_QUERY_RTCP_REPORT 1
1075#define BUDATA_INDICATION_RTCP_REPORT 1
1076
1077#define RTP_CONNECT_OPTION_DISC_ON_SSRC_CHANGE 0x00000001L
1078#define RTP_CONNECT_OPTION_DISC_ON_PT_CHANGE 0x00000002L
1079#define RTP_CONNECT_OPTION_DISC_ON_UNKNOWN_PT 0x00000004L
1080#define RTP_CONNECT_OPTION_NO_SILENCE_TRANSMIT 0x00010000L
1081
1082#define RTP_PAYLOAD_OPTION_VOICE_ACTIVITY_DETECT 0x0001
1083#define RTP_PAYLOAD_OPTION_DISABLE_POST_FILTER 0x0002
1084#define RTP_PAYLOAD_OPTION_G723_LOW_CODING_RATE 0x0100
1085
1086#define RTP_PACKET_FILTER_IGNORE_UNKNOWN_SSRC 0x00000001L
1087
1088#define RTP_CHANGE_FLAG_SSRC_CHANGE 0x00000001L
1089#define RTP_CHANGE_FLAG_PAYLOAD_TYPE_CHANGE 0x00000002L
1090#define RTP_CHANGE_FLAG_UNKNOWN_PAYLOAD_TYPE 0x00000004L
1091
1092
1093/*------------------------------------------------------------------*/
1094/* T.38 interface to IDI */
1095/*------------------------------------------------------------------*/
1096
1097
1098#define B1_T38 30
1099#define B2_T38 30
1100#define B3_T38 30
1101
1102#define PRIVATE_T38 2
1103
1104
1105/*------------------------------------------------------------------*/
1106/* PIAFS interface to IDI */
1107/*------------------------------------------------------------------*/
1108
1109
1110#define B1_PIAFS 29
1111#define B2_PIAFS 29
1112
1113#define PRIVATE_PIAFS 29
1114
1115/*
1116 B2 configuration for PIAFS:
1117+---------------------+------+-----------------------------------------+
1118| PIAFS Protocol | byte | Bit 1 - Protocol Speed |
1119| Speed configuration | | 0 - 32K |
1120| | | 1 - 64K (default) |
1121| | | Bit 2 - Variable Protocol Speed |
1122| | | 0 - Speed is fix |
1123| | | 1 - Speed is variable (default) |
1124+---------------------+------+-----------------------------------------+
1125| Direction | word | Enable compression/decompression for |
1126| | | 0: All direction |
1127| | | 1: disable outgoing data |
1128| | | 2: disable incomming data |
1129| | | 3: disable both direction (default) |
1130+---------------------+------+-----------------------------------------+
1131| Number of code | word | Parameter P1 of V.42bis in accordance |
1132| words | | with V.42bis |
1133+---------------------+------+-----------------------------------------+
1134| Maximum String | word | Parameter P2 of V.42bis in accordance |
1135| Length | | with V.42bis |
1136+---------------------+------+-----------------------------------------+
1137| control (UDATA) | byte | enable PIAFS control communication |
1138| abilities | | |
1139+---------------------+------+-----------------------------------------+
1140*/
1141#define PIAFS_UDATA_ABILITIES 0x80
1142
1143/*------------------------------------------------------------------*/
1144/* FAX SUB/SEP/PWD extension */
1145/*------------------------------------------------------------------*/
1146
1147
1148#define PRIVATE_FAX_SUB_SEP_PWD 3
1149
1150
1151
1152/*------------------------------------------------------------------*/
1153/* V.18 extension */
1154/*------------------------------------------------------------------*/
1155
1156
1157#define PRIVATE_V18 4
1158
1159
1160
1161/*------------------------------------------------------------------*/
1162/* DTMF TONE extension */
1163/*------------------------------------------------------------------*/
1164
1165
1166#define DTMF_GET_SUPPORTED_DETECT_CODES 0xf8
1167#define DTMF_GET_SUPPORTED_SEND_CODES 0xf9
1168#define DTMF_LISTEN_TONE_START 0xfa
1169#define DTMF_LISTEN_TONE_STOP 0xfb
1170#define DTMF_SEND_TONE 0xfc
1171#define DTMF_LISTEN_MF_START 0xfd
1172#define DTMF_LISTEN_MF_STOP 0xfe
1173#define DTMF_SEND_MF 0xff
1174
1175#define DTMF_MF_DIGIT_TONE_CODE_1 0x10
1176#define DTMF_MF_DIGIT_TONE_CODE_2 0x11
1177#define DTMF_MF_DIGIT_TONE_CODE_3 0x12
1178#define DTMF_MF_DIGIT_TONE_CODE_4 0x13
1179#define DTMF_MF_DIGIT_TONE_CODE_5 0x14
1180#define DTMF_MF_DIGIT_TONE_CODE_6 0x15
1181#define DTMF_MF_DIGIT_TONE_CODE_7 0x16
1182#define DTMF_MF_DIGIT_TONE_CODE_8 0x17
1183#define DTMF_MF_DIGIT_TONE_CODE_9 0x18
1184#define DTMF_MF_DIGIT_TONE_CODE_0 0x19
1185#define DTMF_MF_DIGIT_TONE_CODE_K1 0x1a
1186#define DTMF_MF_DIGIT_TONE_CODE_K2 0x1b
1187#define DTMF_MF_DIGIT_TONE_CODE_KP 0x1c
1188#define DTMF_MF_DIGIT_TONE_CODE_S1 0x1d
1189#define DTMF_MF_DIGIT_TONE_CODE_ST 0x1e
1190
1191#define DTMF_DIGIT_CODE_COUNT 16
1192#define DTMF_MF_DIGIT_CODE_BASE DSP_DTMF_DIGIT_CODE_COUNT
1193#define DTMF_MF_DIGIT_CODE_COUNT 15
1194#define DTMF_TOTAL_DIGIT_CODE_COUNT (DSP_MF_DIGIT_CODE_BASE + DSP_MF_DIGIT_CODE_COUNT)
1195
1196#define DTMF_TONE_DIGIT_BASE 0x80
1197
1198#define DTMF_SIGNAL_NO_TONE (DTMF_TONE_DIGIT_BASE + 0)
1199#define DTMF_SIGNAL_UNIDENTIFIED_TONE (DTMF_TONE_DIGIT_BASE + 1)
1200
1201#define DTMF_SIGNAL_DIAL_TONE (DTMF_TONE_DIGIT_BASE + 2)
1202#define DTMF_SIGNAL_PABX_INTERNAL_DIAL_TONE (DTMF_TONE_DIGIT_BASE + 3)
1203#define DTMF_SIGNAL_SPECIAL_DIAL_TONE (DTMF_TONE_DIGIT_BASE + 4) /* stutter dial tone */
1204#define DTMF_SIGNAL_SECOND_DIAL_TONE (DTMF_TONE_DIGIT_BASE + 5)
1205#define DTMF_SIGNAL_RINGING_TONE (DTMF_TONE_DIGIT_BASE + 6)
1206#define DTMF_SIGNAL_SPECIAL_RINGING_TONE (DTMF_TONE_DIGIT_BASE + 7)
1207#define DTMF_SIGNAL_BUSY_TONE (DTMF_TONE_DIGIT_BASE + 8)
1208#define DTMF_SIGNAL_CONGESTION_TONE (DTMF_TONE_DIGIT_BASE + 9) /* reorder tone */
1209#define DTMF_SIGNAL_SPECIAL_INFORMATION_TONE (DTMF_TONE_DIGIT_BASE + 10)
1210#define DTMF_SIGNAL_COMFORT_TONE (DTMF_TONE_DIGIT_BASE + 11)
1211#define DTMF_SIGNAL_HOLD_TONE (DTMF_TONE_DIGIT_BASE + 12)
1212#define DTMF_SIGNAL_RECORD_TONE (DTMF_TONE_DIGIT_BASE + 13)
1213#define DTMF_SIGNAL_CALLER_WAITING_TONE (DTMF_TONE_DIGIT_BASE + 14)
1214#define DTMF_SIGNAL_CALL_WAITING_TONE (DTMF_TONE_DIGIT_BASE + 15)
1215#define DTMF_SIGNAL_PAY_TONE (DTMF_TONE_DIGIT_BASE + 16)
1216#define DTMF_SIGNAL_POSITIVE_INDICATION_TONE (DTMF_TONE_DIGIT_BASE + 17)
1217#define DTMF_SIGNAL_NEGATIVE_INDICATION_TONE (DTMF_TONE_DIGIT_BASE + 18)
1218#define DTMF_SIGNAL_WARNING_TONE (DTMF_TONE_DIGIT_BASE + 19)
1219#define DTMF_SIGNAL_INTRUSION_TONE (DTMF_TONE_DIGIT_BASE + 20)
1220#define DTMF_SIGNAL_CALLING_CARD_SERVICE_TONE (DTMF_TONE_DIGIT_BASE + 21)
1221#define DTMF_SIGNAL_PAYPHONE_RECOGNITION_TONE (DTMF_TONE_DIGIT_BASE + 22)
1222#define DTMF_SIGNAL_CPE_ALERTING_SIGNAL (DTMF_TONE_DIGIT_BASE + 23)
1223#define DTMF_SIGNAL_OFF_HOOK_WARNING_TONE (DTMF_TONE_DIGIT_BASE + 24)
1224
1225#define DTMF_SIGNAL_INTERCEPT_TONE (DTMF_TONE_DIGIT_BASE + 63)
1226
1227#define DTMF_SIGNAL_MODEM_CALLING_TONE (DTMF_TONE_DIGIT_BASE + 64)
1228#define DTMF_SIGNAL_FAX_CALLING_TONE (DTMF_TONE_DIGIT_BASE + 65)
1229#define DTMF_SIGNAL_ANSWER_TONE (DTMF_TONE_DIGIT_BASE + 66)
1230#define DTMF_SIGNAL_REVERSED_ANSWER_TONE (DTMF_TONE_DIGIT_BASE + 67)
1231#define DTMF_SIGNAL_ANSAM_TONE (DTMF_TONE_DIGIT_BASE + 68)
1232#define DTMF_SIGNAL_REVERSED_ANSAM_TONE (DTMF_TONE_DIGIT_BASE + 69)
1233#define DTMF_SIGNAL_BELL103_ANSWER_TONE (DTMF_TONE_DIGIT_BASE + 70)
1234#define DTMF_SIGNAL_FAX_FLAGS (DTMF_TONE_DIGIT_BASE + 71)
1235#define DTMF_SIGNAL_G2_FAX_GROUP_ID (DTMF_TONE_DIGIT_BASE + 72)
1236#define DTMF_SIGNAL_HUMAN_SPEECH (DTMF_TONE_DIGIT_BASE + 73)
1237#define DTMF_SIGNAL_ANSWERING_MACHINE_390 (DTMF_TONE_DIGIT_BASE + 74)
1238
1239#define DTMF_MF_LISTEN_ACTIVE_FLAG 0x02
1240#define DTMF_SEND_MF_FLAG 0x02
1241#define DTMF_TONE_LISTEN_ACTIVE_FLAG 0x04
1242#define DTMF_SEND_TONE_FLAG 0x04
1243
1244#define PRIVATE_DTMF_TONE 5
1245
1246
1247/*------------------------------------------------------------------*/
1248/* FAX paper format extension */
1249/*------------------------------------------------------------------*/
1250
1251
1252#define PRIVATE_FAX_PAPER_FORMATS 6
1253
1254
1255
1256/*------------------------------------------------------------------*/
1257/* V.OWN extension */
1258/*------------------------------------------------------------------*/
1259
1260
1261#define PRIVATE_VOWN 7
1262
1263
1264
1265/*------------------------------------------------------------------*/
1266/* FAX non-standard facilities extension */
1267/*------------------------------------------------------------------*/
1268
1269
1270#define PRIVATE_FAX_NONSTANDARD 8
1271
1272
1273
1274/*------------------------------------------------------------------*/
1275/* Advanced voice */
1276/*------------------------------------------------------------------*/
1277
1278#define ADV_VOICE_WRITE_ACTIVATION 0
1279#define ADV_VOICE_WRITE_DEACTIVATION 1
1280#define ADV_VOICE_WRITE_UPDATE 2
1281
1282#define ADV_VOICE_OLD_COEF_COUNT 6
1283#define ADV_VOICE_NEW_COEF_BASE (ADV_VOICE_OLD_COEF_COUNT * sizeof(word))
1284
1285/*------------------------------------------------------------------*/
1286/* B1 resource switching */
1287/*------------------------------------------------------------------*/
1288
1289#define B1_FACILITY_LOCAL 0x01
1290#define B1_FACILITY_MIXER 0x02
1291#define B1_FACILITY_DTMFX 0x04
1292#define B1_FACILITY_DTMFR 0x08
1293#define B1_FACILITY_VOICE 0x10
1294#define B1_FACILITY_EC 0x20
1295
1296#define ADJUST_B_MODE_SAVE 0x0001
1297#define ADJUST_B_MODE_REMOVE_L23 0x0002
1298#define ADJUST_B_MODE_SWITCH_L1 0x0004
1299#define ADJUST_B_MODE_NO_RESOURCE 0x0008
1300#define ADJUST_B_MODE_ASSIGN_L23 0x0010
1301#define ADJUST_B_MODE_USER_CONNECT 0x0020
1302#define ADJUST_B_MODE_CONNECT 0x0040
1303#define ADJUST_B_MODE_RESTORE 0x0080
1304
1305#define ADJUST_B_START 0
1306#define ADJUST_B_SAVE_MIXER_1 1
1307#define ADJUST_B_SAVE_DTMF_1 2
1308#define ADJUST_B_REMOVE_L23_1 3
1309#define ADJUST_B_REMOVE_L23_2 4
1310#define ADJUST_B_SAVE_EC_1 5
1311#define ADJUST_B_SAVE_DTMF_PARAMETER_1 6
1312#define ADJUST_B_SAVE_VOICE_1 7
1313#define ADJUST_B_SWITCH_L1_1 8
1314#define ADJUST_B_SWITCH_L1_2 9
1315#define ADJUST_B_RESTORE_VOICE_1 10
1316#define ADJUST_B_RESTORE_VOICE_2 11
1317#define ADJUST_B_RESTORE_DTMF_PARAMETER_1 12
1318#define ADJUST_B_RESTORE_DTMF_PARAMETER_2 13
1319#define ADJUST_B_RESTORE_EC_1 14
1320#define ADJUST_B_RESTORE_EC_2 15
1321#define ADJUST_B_ASSIGN_L23_1 16
1322#define ADJUST_B_ASSIGN_L23_2 17
1323#define ADJUST_B_CONNECT_1 18
1324#define ADJUST_B_CONNECT_2 19
1325#define ADJUST_B_CONNECT_3 20
1326#define ADJUST_B_CONNECT_4 21
1327#define ADJUST_B_RESTORE_DTMF_1 22
1328#define ADJUST_B_RESTORE_DTMF_2 23
1329#define ADJUST_B_RESTORE_MIXER_1 24
1330#define ADJUST_B_RESTORE_MIXER_2 25
1331#define ADJUST_B_RESTORE_MIXER_3 26
1332#define ADJUST_B_RESTORE_MIXER_4 27
1333#define ADJUST_B_RESTORE_MIXER_5 28
1334#define ADJUST_B_RESTORE_MIXER_6 29
1335#define ADJUST_B_RESTORE_MIXER_7 30
1336#define ADJUST_B_END 31
1337
1338/*------------------------------------------------------------------*/
1339/* XON Protocol def's */
1340/*------------------------------------------------------------------*/
1341#define N_CH_XOFF 0x01
1342#define N_XON_SENT 0x02
1343#define N_XON_REQ 0x04
1344#define N_XON_CONNECT_IND 0x08
1345#define N_RX_FLOW_CONTROL_MASK 0x3f
1346#define N_OK_FC_PENDING 0x80
1347#define N_TX_FLOW_CONTROL_MASK 0xc0
1348
1349/*------------------------------------------------------------------*/
1350/* NCPI state */
1351/*------------------------------------------------------------------*/
1352#define NCPI_VALID_CONNECT_B3_IND 0x01
1353#define NCPI_VALID_CONNECT_B3_ACT 0x02
1354#define NCPI_VALID_DISC_B3_IND 0x04
1355#define NCPI_CONNECT_B3_ACT_SENT 0x08
1356#define NCPI_NEGOTIATE_B3_SENT 0x10
1357#define NCPI_MDM_CTS_ON_RECEIVED 0x40
1358#define NCPI_MDM_DCD_ON_RECEIVED 0x80
1359
1360/*------------------------------------------------------------------*/
diff --git a/drivers/isdn/hardware/eicon/divamnt.c b/drivers/isdn/hardware/eicon/divamnt.c
new file mode 100644
index 000000000000..6146f7633be5
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/divamnt.c
@@ -0,0 +1,257 @@
1/* $Id: divamnt.c,v 1.32.6.10 2005/02/11 19:40:25 armin Exp $
2 *
3 * Driver for Eicon DIVA Server ISDN cards.
4 * Maint module
5 *
6 * Copyright 2000-2003 by Armin Schindler (mac@melware.de)
7 * Copyright 2000-2003 Cytronics & Melware (info@melware.de)
8 *
9 * This software may be used and distributed according to the terms
10 * of the GNU General Public License, incorporated herein by reference.
11 */
12
13#include <linux/config.h>
14#include <linux/module.h>
15#include <linux/init.h>
16#include <linux/kernel.h>
17#include <linux/sched.h>
18#include <linux/smp_lock.h>
19#include <linux/poll.h>
20#include <linux/devfs_fs_kernel.h>
21#include <asm/uaccess.h>
22
23#include "platform.h"
24#include "di_defs.h"
25#include "divasync.h"
26#include "debug_if.h"
27
28static char *main_revision = "$Revision: 1.32.6.10 $";
29
30static int major;
31
32MODULE_DESCRIPTION("Maint driver for Eicon DIVA Server cards");
33MODULE_AUTHOR("Cytronics & Melware, Eicon Networks");
34MODULE_SUPPORTED_DEVICE("DIVA card driver");
35MODULE_LICENSE("GPL");
36
37static int buffer_length = 128;
38module_param(buffer_length, int, 0);
39static unsigned long diva_dbg_mem = 0;
40module_param(diva_dbg_mem, ulong, 0);
41
42static char *DRIVERNAME =
43 "Eicon DIVA - MAINT module (http://www.melware.net)";
44static char *DRIVERLNAME = "diva_mnt";
45static char *DEVNAME = "DivasMAINT";
46char *DRIVERRELEASE_MNT = "2.0";
47
48static wait_queue_head_t msgwaitq;
49static unsigned long opened;
50static struct timeval start_time;
51
52extern int mntfunc_init(int *, void **, unsigned long);
53extern void mntfunc_finit(void);
54extern int maint_read_write(void __user *buf, int count);
55
56/*
57 * helper functions
58 */
59static char *getrev(const char *revision)
60{
61 char *rev;
62 char *p;
63
64 if ((p = strchr(revision, ':'))) {
65 rev = p + 2;
66 p = strchr(rev, '$');
67 *--p = 0;
68 } else
69 rev = "1.0";
70
71 return rev;
72}
73
74/*
75 * kernel/user space copy functions
76 */
77int diva_os_copy_to_user(void *os_handle, void __user *dst, const void *src,
78 int length)
79{
80 return (copy_to_user(dst, src, length));
81}
82int diva_os_copy_from_user(void *os_handle, void *dst, const void __user *src,
83 int length)
84{
85 return (copy_from_user(dst, src, length));
86}
87
88/*
89 * get time
90 */
91void diva_os_get_time(dword * sec, dword * usec)
92{
93 struct timeval tv;
94
95 do_gettimeofday(&tv);
96
97 if (tv.tv_sec > start_time.tv_sec) {
98 if (start_time.tv_usec > tv.tv_usec) {
99 tv.tv_sec--;
100 tv.tv_usec += 1000000;
101 }
102 *sec = (dword) (tv.tv_sec - start_time.tv_sec);
103 *usec = (dword) (tv.tv_usec - start_time.tv_usec);
104 } else if (tv.tv_sec == start_time.tv_sec) {
105 *sec = 0;
106 if (start_time.tv_usec < tv.tv_usec) {
107 *usec = (dword) (tv.tv_usec - start_time.tv_usec);
108 } else {
109 *usec = 0;
110 }
111 } else {
112 *sec = (dword) tv.tv_sec;
113 *usec = (dword) tv.tv_usec;
114 }
115}
116
117/*
118 * device node operations
119 */
120static unsigned int maint_poll(struct file *file, poll_table * wait)
121{
122 unsigned int mask = 0;
123
124 poll_wait(file, &msgwaitq, wait);
125 mask = POLLOUT | POLLWRNORM;
126 if (file->private_data || diva_dbg_q_length()) {
127 mask |= POLLIN | POLLRDNORM;
128 }
129 return (mask);
130}
131
132static int maint_open(struct inode *ino, struct file *filep)
133{
134 /* only one open is allowed, so we test
135 it atomically */
136 if (test_and_set_bit(0, &opened))
137 return (-EBUSY);
138
139 filep->private_data = NULL;
140
141 return nonseekable_open(ino, filep);
142}
143
144static int maint_close(struct inode *ino, struct file *filep)
145{
146 if (filep->private_data) {
147 diva_os_free(0, filep->private_data);
148 filep->private_data = NULL;
149 }
150
151 /* clear 'used' flag */
152 clear_bit(0, &opened);
153
154 return (0);
155}
156
157static ssize_t divas_maint_write(struct file *file, const char __user *buf,
158 size_t count, loff_t * ppos)
159{
160 return (maint_read_write((char __user *) buf, (int) count));
161}
162
163static ssize_t divas_maint_read(struct file *file, char __user *buf,
164 size_t count, loff_t * ppos)
165{
166 return (maint_read_write(buf, (int) count));
167}
168
169static struct file_operations divas_maint_fops = {
170 .owner = THIS_MODULE,
171 .llseek = no_llseek,
172 .read = divas_maint_read,
173 .write = divas_maint_write,
174 .poll = maint_poll,
175 .open = maint_open,
176 .release = maint_close
177};
178
179static void divas_maint_unregister_chrdev(void)
180{
181 devfs_remove(DEVNAME);
182 unregister_chrdev(major, DEVNAME);
183}
184
185static int DIVA_INIT_FUNCTION divas_maint_register_chrdev(void)
186{
187 if ((major = register_chrdev(0, DEVNAME, &divas_maint_fops)) < 0)
188 {
189 printk(KERN_ERR "%s: failed to create /dev entry.\n",
190 DRIVERLNAME);
191 return (0);
192 }
193 devfs_mk_cdev(MKDEV(major, 0), S_IFCHR|S_IRUSR|S_IWUSR, DEVNAME);
194
195 return (1);
196}
197
198/*
199 * wake up reader
200 */
201void diva_maint_wakeup_read(void)
202{
203 wake_up_interruptible(&msgwaitq);
204}
205
206/*
207 * Driver Load
208 */
209static int DIVA_INIT_FUNCTION maint_init(void)
210{
211 char tmprev[50];
212 int ret = 0;
213 void *buffer = NULL;
214
215 do_gettimeofday(&start_time);
216 init_waitqueue_head(&msgwaitq);
217
218 printk(KERN_INFO "%s\n", DRIVERNAME);
219 printk(KERN_INFO "%s: Rel:%s Rev:", DRIVERLNAME, DRIVERRELEASE_MNT);
220 strcpy(tmprev, main_revision);
221 printk("%s Build: %s \n", getrev(tmprev), DIVA_BUILD);
222
223 if (!divas_maint_register_chrdev()) {
224 ret = -EIO;
225 goto out;
226 }
227
228 if (!(mntfunc_init(&buffer_length, &buffer, diva_dbg_mem))) {
229 printk(KERN_ERR "%s: failed to connect to DIDD.\n",
230 DRIVERLNAME);
231 divas_maint_unregister_chrdev();
232 ret = -EIO;
233 goto out;
234 }
235
236 printk(KERN_INFO "%s: trace buffer = %p - %d kBytes, %s (Major: %d)\n",
237 DRIVERLNAME, buffer, (buffer_length / 1024),
238 (diva_dbg_mem == 0) ? "internal" : "external", major);
239
240 out:
241 return (ret);
242}
243
244/*
245** Driver Unload
246*/
247static void DIVA_EXIT_FUNCTION maint_exit(void)
248{
249 divas_maint_unregister_chrdev();
250 mntfunc_finit();
251
252 printk(KERN_INFO "%s: module unloaded.\n", DRIVERLNAME);
253}
254
255module_init(maint_init);
256module_exit(maint_exit);
257
diff --git a/drivers/isdn/hardware/eicon/divasfunc.c b/drivers/isdn/hardware/eicon/divasfunc.c
new file mode 100644
index 000000000000..df61e510a28b
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/divasfunc.c
@@ -0,0 +1,238 @@
1/* $Id: divasfunc.c,v 1.23.4.2 2004/08/28 20:03:53 armin Exp $
2 *
3 * Low level driver for Eicon DIVA Server ISDN cards.
4 *
5 * Copyright 2000-2003 by Armin Schindler (mac@melware.de)
6 * Copyright 2000-2003 Cytronics & Melware (info@melware.de)
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 */
11
12#include "platform.h"
13#include "di_defs.h"
14#include "pc.h"
15#include "di.h"
16#include "io.h"
17#include "divasync.h"
18#include "diva.h"
19#include "xdi_vers.h"
20
21#define DBG_MINIMUM (DL_LOG + DL_FTL + DL_ERR)
22#define DBG_DEFAULT (DBG_MINIMUM + DL_XLOG + DL_REG)
23
24static int debugmask;
25
26extern void DIVA_DIDD_Read(void *, int);
27
28extern PISDN_ADAPTER IoAdapters[MAX_ADAPTER];
29
30extern char *DRIVERRELEASE_DIVAS;
31
32static dword notify_handle;
33static DESCRIPTOR DAdapter;
34static DESCRIPTOR MAdapter;
35
36/* --------------------------------------------------------------------------
37 MAINT driver connector section
38 -------------------------------------------------------------------------- */
39static void no_printf(unsigned char *x, ...)
40{
41 /* dummy debug function */
42}
43
44#include "debuglib.c"
45
46/*
47 * get the adapters serial number
48 */
49void diva_get_vserial_number(PISDN_ADAPTER IoAdapter, char *buf)
50{
51 int contr = 0;
52
53 if ((contr = ((IoAdapter->serialNo & 0xff000000) >> 24))) {
54 sprintf(buf, "%d-%d",
55 IoAdapter->serialNo & 0x00ffffff, contr + 1);
56 } else {
57 sprintf(buf, "%d", IoAdapter->serialNo);
58 }
59}
60
61/*
62 * register a new adapter
63 */
64void diva_xdi_didd_register_adapter(int card)
65{
66 DESCRIPTOR d;
67 IDI_SYNC_REQ req;
68
69 if (card && ((card - 1) < MAX_ADAPTER) &&
70 IoAdapters[card - 1] && Requests[card - 1]) {
71 d.type = IoAdapters[card - 1]->Properties.DescType;
72 d.request = Requests[card - 1];
73 d.channels = IoAdapters[card - 1]->Properties.Channels;
74 d.features = IoAdapters[card - 1]->Properties.Features;
75 DBG_TRC(("DIDD register A(%d) channels=%d", card,
76 d.channels))
77 /* workaround for different Name in structure */
78 strlcpy(IoAdapters[card - 1]->Name,
79 IoAdapters[card - 1]->Properties.Name,
80 sizeof(IoAdapters[card - 1]->Name));
81 req.didd_remove_adapter.e.Req = 0;
82 req.didd_add_adapter.e.Rc = IDI_SYNC_REQ_DIDD_ADD_ADAPTER;
83 req.didd_add_adapter.info.descriptor = (void *) &d;
84 DAdapter.request((ENTITY *) & req);
85 if (req.didd_add_adapter.e.Rc != 0xff) {
86 DBG_ERR(("DIDD register A(%d) failed !", card))
87 }
88 IoAdapters[card - 1]->os_trap_nfy_Fnc = NULL;
89 }
90}
91
92/*
93 * remove an adapter
94 */
95void diva_xdi_didd_remove_adapter(int card)
96{
97 IDI_SYNC_REQ req;
98 ADAPTER *a = &IoAdapters[card - 1]->a;
99
100 IoAdapters[card - 1]->os_trap_nfy_Fnc = NULL;
101 DBG_TRC(("DIDD de-register A(%d)", card))
102 req.didd_remove_adapter.e.Req = 0;
103 req.didd_remove_adapter.e.Rc = IDI_SYNC_REQ_DIDD_REMOVE_ADAPTER;
104 req.didd_remove_adapter.info.p_request =
105 (IDI_CALL) Requests[card - 1];
106 DAdapter.request((ENTITY *) & req);
107 memset(&(a->IdTable), 0x00, 256);
108}
109
110/*
111 * start debug
112 */
113static void start_dbg(void)
114{
115 DbgRegister("DIVAS", DRIVERRELEASE_DIVAS, (debugmask) ? debugmask : DBG_DEFAULT);
116 DBG_LOG(("DIVA ISDNXDI BUILD (%s[%s]-%s-%s)",
117 DIVA_BUILD, diva_xdi_common_code_build, __DATE__,
118 __TIME__))
119}
120
121/*
122 * stop debug
123 */
124static void stop_dbg(void)
125{
126 DbgDeregister();
127 memset(&MAdapter, 0, sizeof(MAdapter));
128 dprintf = no_printf;
129}
130
131/*
132 * didd callback function
133 */
134static void *didd_callback(void *context, DESCRIPTOR * adapter,
135 int removal)
136{
137 if (adapter->type == IDI_DADAPTER) {
138 DBG_ERR(("Notification about IDI_DADAPTER change ! Oops."));
139 return (NULL);
140 }
141
142 if (adapter->type == IDI_DIMAINT) {
143 if (removal) {
144 stop_dbg();
145 } else {
146 memcpy(&MAdapter, adapter, sizeof(MAdapter));
147 dprintf = (DIVA_DI_PRINTF) MAdapter.request;
148 start_dbg();
149 }
150 }
151 return (NULL);
152}
153
154/*
155 * connect to didd
156 */
157static int DIVA_INIT_FUNCTION connect_didd(void)
158{
159 int x = 0;
160 int dadapter = 0;
161 IDI_SYNC_REQ req;
162 DESCRIPTOR DIDD_Table[MAX_DESCRIPTORS];
163
164 DIVA_DIDD_Read(DIDD_Table, sizeof(DIDD_Table));
165
166 for (x = 0; x < MAX_DESCRIPTORS; x++) {
167 if (DIDD_Table[x].type == IDI_DADAPTER) { /* DADAPTER found */
168 dadapter = 1;
169 memcpy(&DAdapter, &DIDD_Table[x], sizeof(DAdapter));
170 req.didd_notify.e.Req = 0;
171 req.didd_notify.e.Rc =
172 IDI_SYNC_REQ_DIDD_REGISTER_ADAPTER_NOTIFY;
173 req.didd_notify.info.callback = (void *)didd_callback;
174 req.didd_notify.info.context = NULL;
175 DAdapter.request((ENTITY *) & req);
176 if (req.didd_notify.e.Rc != 0xff) {
177 stop_dbg();
178 return (0);
179 }
180 notify_handle = req.didd_notify.info.handle;
181 } else if (DIDD_Table[x].type == IDI_DIMAINT) { /* MAINT found */
182 memcpy(&MAdapter, &DIDD_Table[x], sizeof(DAdapter));
183 dprintf = (DIVA_DI_PRINTF) MAdapter.request;
184 start_dbg();
185 }
186 }
187
188 if (!dadapter) {
189 stop_dbg();
190 }
191
192 return (dadapter);
193}
194
195/*
196 * disconnect from didd
197 */
198static void DIVA_EXIT_FUNCTION disconnect_didd(void)
199{
200 IDI_SYNC_REQ req;
201
202 stop_dbg();
203
204 req.didd_notify.e.Req = 0;
205 req.didd_notify.e.Rc = IDI_SYNC_REQ_DIDD_REMOVE_ADAPTER_NOTIFY;
206 req.didd_notify.info.handle = notify_handle;
207 DAdapter.request((ENTITY *) & req);
208}
209
210/*
211 * init
212 */
213int DIVA_INIT_FUNCTION divasfunc_init(int dbgmask)
214{
215 char *version;
216
217 debugmask = dbgmask;
218
219 if (!connect_didd()) {
220 DBG_ERR(("divasfunc: failed to connect to DIDD."))
221 return (0);
222 }
223
224 version = diva_xdi_common_code_build;
225
226 divasa_xdi_driver_entry();
227
228 return (1);
229}
230
231/*
232 * exit
233 */
234void DIVA_EXIT_FUNCTION divasfunc_exit(void)
235{
236 divasa_xdi_driver_unload();
237 disconnect_didd();
238}
diff --git a/drivers/isdn/hardware/eicon/divasi.c b/drivers/isdn/hardware/eicon/divasi.c
new file mode 100644
index 000000000000..df715b47e2b4
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/divasi.c
@@ -0,0 +1,581 @@
1/* $Id: divasi.c,v 1.25.6.2 2005/01/31 12:22:20 armin Exp $
2 *
3 * Driver for Eicon DIVA Server ISDN cards.
4 * User Mode IDI Interface
5 *
6 * Copyright 2000-2003 by Armin Schindler (mac@melware.de)
7 * Copyright 2000-2003 Cytronics & Melware (info@melware.de)
8 *
9 * This software may be used and distributed according to the terms
10 * of the GNU General Public License, incorporated herein by reference.
11 */
12
13#include <linux/config.h>
14#include <linux/module.h>
15#include <linux/init.h>
16#include <linux/kernel.h>
17#include <linux/sched.h>
18#include <linux/smp_lock.h>
19#include <linux/poll.h>
20#include <linux/proc_fs.h>
21#include <linux/skbuff.h>
22#include <linux/devfs_fs_kernel.h>
23#include <asm/uaccess.h>
24
25#include "platform.h"
26#include "di_defs.h"
27#include "divasync.h"
28#include "um_xdi.h"
29#include "um_idi.h"
30
31static char *main_revision = "$Revision: 1.25.6.2 $";
32
33static int major;
34
35MODULE_DESCRIPTION("User IDI Interface for Eicon ISDN cards");
36MODULE_AUTHOR("Cytronics & Melware, Eicon Networks");
37MODULE_SUPPORTED_DEVICE("DIVA card driver");
38MODULE_LICENSE("GPL");
39
40typedef struct _diva_um_idi_os_context {
41 wait_queue_head_t read_wait;
42 wait_queue_head_t close_wait;
43 struct timer_list diva_timer_id;
44 int aborted;
45 int adapter_nr;
46} diva_um_idi_os_context_t;
47
48static char *DRIVERNAME = "Eicon DIVA - User IDI (http://www.melware.net)";
49static char *DRIVERLNAME = "diva_idi";
50static char *DEVNAME = "DivasIDI";
51char *DRIVERRELEASE_IDI = "2.0";
52
53extern int idifunc_init(void);
54extern void idifunc_finit(void);
55
56/*
57 * helper functions
58 */
59static char *getrev(const char *revision)
60{
61 char *rev;
62 char *p;
63 if ((p = strchr(revision, ':'))) {
64 rev = p + 2;
65 p = strchr(rev, '$');
66 *--p = 0;
67 } else
68 rev = "1.0";
69 return rev;
70}
71
72/*
73 * LOCALS
74 */
75static ssize_t um_idi_read(struct file *file, char __user *buf, size_t count,
76 loff_t * offset);
77static ssize_t um_idi_write(struct file *file, const char __user *buf,
78 size_t count, loff_t * offset);
79static unsigned int um_idi_poll(struct file *file, poll_table * wait);
80static int um_idi_open(struct inode *inode, struct file *file);
81static int um_idi_release(struct inode *inode, struct file *file);
82static int remove_entity(void *entity);
83static void diva_um_timer_function(unsigned long data);
84
85/*
86 * proc entry
87 */
88extern struct proc_dir_entry *proc_net_eicon;
89static struct proc_dir_entry *um_idi_proc_entry = NULL;
90
91static int
92um_idi_proc_read(char *page, char **start, off_t off, int count, int *eof,
93 void *data)
94{
95 int len = 0;
96 char tmprev[32];
97
98 len += sprintf(page + len, "%s\n", DRIVERNAME);
99 len += sprintf(page + len, "name : %s\n", DRIVERLNAME);
100 len += sprintf(page + len, "release : %s\n", DRIVERRELEASE_IDI);
101 strcpy(tmprev, main_revision);
102 len += sprintf(page + len, "revision : %s\n", getrev(tmprev));
103 len += sprintf(page + len, "build : %s\n", DIVA_BUILD);
104 len += sprintf(page + len, "major : %d\n", major);
105
106 if (off + count >= len)
107 *eof = 1;
108 if (len < off)
109 return 0;
110 *start = page + off;
111 return ((count < len - off) ? count : len - off);
112}
113
114static int DIVA_INIT_FUNCTION create_um_idi_proc(void)
115{
116 um_idi_proc_entry = create_proc_entry(DRIVERLNAME,
117 S_IFREG | S_IRUGO | S_IWUSR,
118 proc_net_eicon);
119 if (!um_idi_proc_entry)
120 return (0);
121
122 um_idi_proc_entry->read_proc = um_idi_proc_read;
123 um_idi_proc_entry->owner = THIS_MODULE;
124
125 return (1);
126}
127
128static void remove_um_idi_proc(void)
129{
130 if (um_idi_proc_entry) {
131 remove_proc_entry(DRIVERLNAME, proc_net_eicon);
132 um_idi_proc_entry = NULL;
133 }
134}
135
136static struct file_operations divas_idi_fops = {
137 .owner = THIS_MODULE,
138 .llseek = no_llseek,
139 .read = um_idi_read,
140 .write = um_idi_write,
141 .poll = um_idi_poll,
142 .open = um_idi_open,
143 .release = um_idi_release
144};
145
146static void divas_idi_unregister_chrdev(void)
147{
148 devfs_remove(DEVNAME);
149 unregister_chrdev(major, DEVNAME);
150}
151
152static int DIVA_INIT_FUNCTION divas_idi_register_chrdev(void)
153{
154 if ((major = register_chrdev(0, DEVNAME, &divas_idi_fops)) < 0)
155 {
156 printk(KERN_ERR "%s: failed to create /dev entry.\n",
157 DRIVERLNAME);
158 return (0);
159 }
160 devfs_mk_cdev(MKDEV(major, 0), S_IFCHR|S_IRUSR|S_IWUSR, DEVNAME);
161
162 return (1);
163}
164
165/*
166** Driver Load
167*/
168static int DIVA_INIT_FUNCTION divasi_init(void)
169{
170 char tmprev[50];
171 int ret = 0;
172
173 printk(KERN_INFO "%s\n", DRIVERNAME);
174 printk(KERN_INFO "%s: Rel:%s Rev:", DRIVERLNAME, DRIVERRELEASE_IDI);
175 strcpy(tmprev, main_revision);
176 printk("%s Build: %s\n", getrev(tmprev), DIVA_BUILD);
177
178 if (!divas_idi_register_chrdev()) {
179 ret = -EIO;
180 goto out;
181 }
182
183 if (!create_um_idi_proc()) {
184 divas_idi_unregister_chrdev();
185 printk(KERN_ERR "%s: failed to create proc entry.\n",
186 DRIVERLNAME);
187 ret = -EIO;
188 goto out;
189 }
190
191 if (!(idifunc_init())) {
192 remove_um_idi_proc();
193 divas_idi_unregister_chrdev();
194 printk(KERN_ERR "%s: failed to connect to DIDD.\n",
195 DRIVERLNAME);
196 ret = -EIO;
197 goto out;
198 }
199 printk(KERN_INFO "%s: started with major %d\n", DRIVERLNAME, major);
200
201 out:
202 return (ret);
203}
204
205
206/*
207** Driver Unload
208*/
209static void DIVA_EXIT_FUNCTION divasi_exit(void)
210{
211 idifunc_finit();
212 remove_um_idi_proc();
213 divas_idi_unregister_chrdev();
214
215 printk(KERN_INFO "%s: module unloaded.\n", DRIVERLNAME);
216}
217
218module_init(divasi_init);
219module_exit(divasi_exit);
220
221
222/*
223 * FILE OPERATIONS
224 */
225
226static int
227divas_um_idi_copy_to_user(void *os_handle, void *dst, const void *src,
228 int length)
229{
230 memcpy(dst, src, length);
231 return (length);
232}
233
234static ssize_t
235um_idi_read(struct file *file, char __user *buf, size_t count, loff_t * offset)
236{
237 diva_um_idi_os_context_t *p_os;
238 int ret = -EINVAL;
239 void *data;
240
241 if (!file->private_data) {
242 return (-ENODEV);
243 }
244
245 if (!
246 (p_os =
247 (diva_um_idi_os_context_t *) diva_um_id_get_os_context(file->
248 private_data)))
249 {
250 return (-ENODEV);
251 }
252 if (p_os->aborted) {
253 return (-ENODEV);
254 }
255
256 if (!(data = diva_os_malloc(0, count))) {
257 return (-ENOMEM);
258 }
259
260 ret = diva_um_idi_read(file->private_data,
261 file, data, count,
262 divas_um_idi_copy_to_user);
263 switch (ret) {
264 case 0: /* no message available */
265 ret = (-EAGAIN);
266 break;
267 case (-1): /* adapter was removed */
268 ret = (-ENODEV);
269 break;
270 case (-2): /* message_length > length of user buffer */
271 ret = (-EFAULT);
272 break;
273 }
274
275 if (ret > 0) {
276 if (copy_to_user(buf, data, ret)) {
277 ret = (-EFAULT);
278 }
279 }
280
281 diva_os_free(0, data);
282 DBG_TRC(("read: ret %d", ret));
283 return (ret);
284}
285
286
287static int
288divas_um_idi_copy_from_user(void *os_handle, void *dst, const void *src,
289 int length)
290{
291 memcpy(dst, src, length);
292 return (length);
293}
294
295static int um_idi_open_adapter(struct file *file, int adapter_nr)
296{
297 diva_um_idi_os_context_t *p_os;
298 void *e =
299 divas_um_idi_create_entity((dword) adapter_nr, (void *) file);
300
301 if (!(file->private_data = e)) {
302 return (0);
303 }
304 p_os = (diva_um_idi_os_context_t *) diva_um_id_get_os_context(e);
305 init_waitqueue_head(&p_os->read_wait);
306 init_waitqueue_head(&p_os->close_wait);
307 init_timer(&p_os->diva_timer_id);
308 p_os->diva_timer_id.function = (void *) diva_um_timer_function;
309 p_os->diva_timer_id.data = (unsigned long) p_os;
310 p_os->aborted = 0;
311 p_os->adapter_nr = adapter_nr;
312 return (1);
313}
314
315static ssize_t
316um_idi_write(struct file *file, const char __user *buf, size_t count,
317 loff_t * offset)
318{
319 diva_um_idi_os_context_t *p_os;
320 int ret = -EINVAL;
321 void *data;
322 int adapter_nr = 0;
323
324 if (!file->private_data) {
325 /* the first write() selects the adapter_nr */
326 if (count == sizeof(int)) {
327 if (copy_from_user
328 ((void *) &adapter_nr, buf,
329 count)) return (-EFAULT);
330 if (!(um_idi_open_adapter(file, adapter_nr)))
331 return (-ENODEV);
332 return (count);
333 } else
334 return (-ENODEV);
335 }
336
337 if (!(p_os =
338 (diva_um_idi_os_context_t *) diva_um_id_get_os_context(file->
339 private_data)))
340 {
341 return (-ENODEV);
342 }
343 if (p_os->aborted) {
344 return (-ENODEV);
345 }
346
347 if (!(data = diva_os_malloc(0, count))) {
348 return (-ENOMEM);
349 }
350
351 if (copy_from_user(data, buf, count)) {
352 ret = -EFAULT;
353 } else {
354 ret = diva_um_idi_write(file->private_data,
355 file, data, count,
356 divas_um_idi_copy_from_user);
357 switch (ret) {
358 case 0: /* no space available */
359 ret = (-EAGAIN);
360 break;
361 case (-1): /* adapter was removed */
362 ret = (-ENODEV);
363 break;
364 case (-2): /* length of user buffer > max message_length */
365 ret = (-EFAULT);
366 break;
367 }
368 }
369 diva_os_free(0, data);
370 DBG_TRC(("write: ret %d", ret));
371 return (ret);
372}
373
374static unsigned int um_idi_poll(struct file *file, poll_table * wait)
375{
376 diva_um_idi_os_context_t *p_os;
377
378 if (!file->private_data) {
379 return (POLLERR);
380 }
381
382 if ((!(p_os =
383 (diva_um_idi_os_context_t *)
384 diva_um_id_get_os_context(file->private_data)))
385 || p_os->aborted) {
386 return (POLLERR);
387 }
388
389 poll_wait(file, &p_os->read_wait, wait);
390
391 if (p_os->aborted) {
392 return (POLLERR);
393 }
394
395 switch (diva_user_mode_idi_ind_ready(file->private_data, file)) {
396 case (-1):
397 return (POLLERR);
398
399 case 0:
400 return (0);
401 }
402
403 return (POLLIN | POLLRDNORM);
404}
405
406static int um_idi_open(struct inode *inode, struct file *file)
407{
408 return (0);
409}
410
411
412static int um_idi_release(struct inode *inode, struct file *file)
413{
414 diva_um_idi_os_context_t *p_os;
415 unsigned int adapter_nr;
416 int ret = 0;
417
418 if (!(file->private_data)) {
419 ret = -ENODEV;
420 goto out;
421 }
422
423 if (!(p_os =
424 (diva_um_idi_os_context_t *) diva_um_id_get_os_context(file->private_data))) {
425 ret = -ENODEV;
426 goto out;
427 }
428
429 adapter_nr = p_os->adapter_nr;
430
431 if ((ret = remove_entity(file->private_data))) {
432 goto out;
433 }
434
435 if (divas_um_idi_delete_entity
436 ((int) adapter_nr, file->private_data)) {
437 ret = -ENODEV;
438 goto out;
439 }
440
441 out:
442 return (ret);
443}
444
445int diva_os_get_context_size(void)
446{
447 return (sizeof(diva_um_idi_os_context_t));
448}
449
450void diva_os_wakeup_read(void *os_context)
451{
452 diva_um_idi_os_context_t *p_os =
453 (diva_um_idi_os_context_t *) os_context;
454 wake_up_interruptible(&p_os->read_wait);
455}
456
457void diva_os_wakeup_close(void *os_context)
458{
459 diva_um_idi_os_context_t *p_os =
460 (diva_um_idi_os_context_t *) os_context;
461 wake_up_interruptible(&p_os->close_wait);
462}
463
464static
465void diva_um_timer_function(unsigned long data)
466{
467 diva_um_idi_os_context_t *p_os = (diva_um_idi_os_context_t *) data;
468
469 p_os->aborted = 1;
470 wake_up_interruptible(&p_os->read_wait);
471 wake_up_interruptible(&p_os->close_wait);
472 DBG_ERR(("entity removal watchdog"))
473}
474
475/*
476** If application exits without entity removal this function will remove
477** entity and block until removal is complete
478*/
479static int remove_entity(void *entity)
480{
481 struct task_struct *curtask = current;
482 diva_um_idi_os_context_t *p_os;
483
484 diva_um_idi_stop_wdog(entity);
485
486 if (!entity) {
487 DBG_FTL(("Zero entity on remove"))
488 return (0);
489 }
490
491 if (!(p_os =
492 (diva_um_idi_os_context_t *)
493 diva_um_id_get_os_context(entity))) {
494 DBG_FTL(("Zero entity os context on remove"))
495 return (0);
496 }
497
498 if (!divas_um_idi_entity_assigned(entity) || p_os->aborted) {
499 /*
500 Entity is not assigned, also can be removed
501 */
502 return (0);
503 }
504
505 DBG_TRC(("E(%08x) check remove", entity))
506
507 /*
508 If adapter not answers on remove request inside of
509 10 Sec, then adapter is dead
510 */
511 diva_um_idi_start_wdog(entity);
512
513 {
514 DECLARE_WAITQUEUE(wait, curtask);
515
516 add_wait_queue(&p_os->close_wait, &wait);
517 for (;;) {
518 set_current_state(TASK_INTERRUPTIBLE);
519 if (!divas_um_idi_entity_start_remove(entity)
520 || p_os->aborted) {
521 break;
522 }
523 schedule();
524 }
525 set_current_state(TASK_RUNNING);
526 remove_wait_queue(&p_os->close_wait, &wait);
527 }
528
529 DBG_TRC(("E(%08x) start remove", entity))
530 {
531 DECLARE_WAITQUEUE(wait, curtask);
532
533 add_wait_queue(&p_os->close_wait, &wait);
534 for (;;) {
535 set_current_state(TASK_INTERRUPTIBLE);
536 if (!divas_um_idi_entity_assigned(entity)
537 || p_os->aborted) {
538 break;
539 }
540 schedule();
541 }
542 set_current_state(TASK_RUNNING);
543 remove_wait_queue(&p_os->close_wait, &wait);
544 }
545
546 DBG_TRC(("E(%08x) remove complete, aborted:%d", entity,
547 p_os->aborted))
548
549 diva_um_idi_stop_wdog(entity);
550
551 p_os->aborted = 0;
552
553 return (0);
554}
555
556/*
557 * timer watchdog
558 */
559void diva_um_idi_start_wdog(void *entity)
560{
561 diva_um_idi_os_context_t *p_os;
562
563 if (entity &&
564 ((p_os =
565 (diva_um_idi_os_context_t *)
566 diva_um_id_get_os_context(entity)))) {
567 mod_timer(&p_os->diva_timer_id, jiffies + 10 * HZ);
568 }
569}
570
571void diva_um_idi_stop_wdog(void *entity)
572{
573 diva_um_idi_os_context_t *p_os;
574
575 if (entity &&
576 ((p_os =
577 (diva_um_idi_os_context_t *)
578 diva_um_id_get_os_context(entity)))) {
579 del_timer(&p_os->diva_timer_id);
580 }
581}
diff --git a/drivers/isdn/hardware/eicon/divasmain.c b/drivers/isdn/hardware/eicon/divasmain.c
new file mode 100644
index 000000000000..c9b26e86d183
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/divasmain.c
@@ -0,0 +1,856 @@
1/* $Id: divasmain.c,v 1.55.4.6 2005/02/09 19:28:20 armin Exp $
2 *
3 * Low level driver for Eicon DIVA Server ISDN cards.
4 *
5 * Copyright 2000-2003 by Armin Schindler (mac@melware.de)
6 * Copyright 2000-2003 Cytronics & Melware (info@melware.de)
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 */
11
12#include <linux/config.h>
13#include <linux/module.h>
14#include <linux/init.h>
15#include <linux/kernel.h>
16#include <linux/sched.h>
17#include <linux/devfs_fs_kernel.h>
18#include <asm/uaccess.h>
19#include <asm/io.h>
20#include <linux/ioport.h>
21#include <linux/workqueue.h>
22#include <linux/pci.h>
23#include <linux/smp_lock.h>
24#include <linux/interrupt.h>
25#include <linux/list.h>
26#include <linux/poll.h>
27#include <linux/kmod.h>
28
29#include "platform.h"
30#undef ID_MASK
31#undef N_DATA
32#include "pc.h"
33#include "di_defs.h"
34#include "divasync.h"
35#include "diva.h"
36#include "di.h"
37#include "io.h"
38#include "xdi_msg.h"
39#include "xdi_adapter.h"
40#include "xdi_vers.h"
41#include "diva_dma.h"
42#include "diva_pci.h"
43
44static char *main_revision = "$Revision: 1.55.4.6 $";
45
46static int major;
47
48static int dbgmask;
49
50MODULE_DESCRIPTION("Kernel driver for Eicon DIVA Server cards");
51MODULE_AUTHOR("Cytronics & Melware, Eicon Networks");
52MODULE_LICENSE("GPL");
53
54module_param(dbgmask, int, 0);
55MODULE_PARM_DESC(dbgmask, "initial debug mask");
56
57static char *DRIVERNAME =
58 "Eicon DIVA Server driver (http://www.melware.net)";
59static char *DRIVERLNAME = "divas";
60static char *DEVNAME = "Divas";
61char *DRIVERRELEASE_DIVAS = "2.0";
62
63extern irqreturn_t diva_os_irq_wrapper(int irq, void *context,
64 struct pt_regs *regs);
65extern int create_divas_proc(void);
66extern void remove_divas_proc(void);
67extern void diva_get_vserial_number(PISDN_ADAPTER IoAdapter, char *buf);
68extern int divasfunc_init(int dbgmask);
69extern void divasfunc_exit(void);
70
71typedef struct _diva_os_thread_dpc {
72 struct tasklet_struct divas_task;
73 diva_os_soft_isr_t *psoft_isr;
74} diva_os_thread_dpc_t;
75
76/* --------------------------------------------------------------------------
77 PCI driver interface section
78 -------------------------------------------------------------------------- */
79/*
80 vendor, device Vendor and device ID to match (or PCI_ANY_ID)
81 subvendor, Subsystem vendor and device ID to match (or PCI_ANY_ID)
82 subdevice
83 class, Device class to match. The class_mask tells which bits
84 class_mask of the class are honored during the comparison.
85 driver_data Data private to the driver.
86 */
87
88#if !defined(PCI_DEVICE_ID_EICON_MAESTRAP_2)
89#define PCI_DEVICE_ID_EICON_MAESTRAP_2 0xE015
90#endif
91
92#if !defined(PCI_DEVICE_ID_EICON_4BRI_VOIP)
93#define PCI_DEVICE_ID_EICON_4BRI_VOIP 0xE016
94#endif
95
96#if !defined(PCI_DEVICE_ID_EICON_4BRI_2_VOIP)
97#define PCI_DEVICE_ID_EICON_4BRI_2_VOIP 0xE017
98#endif
99
100#if !defined(PCI_DEVICE_ID_EICON_BRI2M_2)
101#define PCI_DEVICE_ID_EICON_BRI2M_2 0xE018
102#endif
103
104#if !defined(PCI_DEVICE_ID_EICON_MAESTRAP_2_VOIP)
105#define PCI_DEVICE_ID_EICON_MAESTRAP_2_VOIP 0xE019
106#endif
107
108#if !defined(PCI_DEVICE_ID_EICON_2F)
109#define PCI_DEVICE_ID_EICON_2F 0xE01A
110#endif
111
112#if !defined(PCI_DEVICE_ID_EICON_BRI2M_2_VOIP)
113#define PCI_DEVICE_ID_EICON_BRI2M_2_VOIP 0xE01B
114#endif
115
116/*
117 This table should be sorted by PCI device ID
118 */
119static struct pci_device_id divas_pci_tbl[] = {
120/* Diva Server BRI-2M PCI 0xE010 */
121 {PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_MAESTRA,
122 PCI_ANY_ID, PCI_ANY_ID, 0, 0, CARDTYPE_MAESTRA_PCI},
123/* Diva Server 4BRI-8M PCI 0xE012 */
124 {PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_MAESTRAQ,
125 PCI_ANY_ID, PCI_ANY_ID, 0, 0, CARDTYPE_DIVASRV_Q_8M_PCI},
126/* Diva Server 4BRI-8M 2.0 PCI 0xE013 */
127 {PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_MAESTRAQ_U,
128 PCI_ANY_ID, PCI_ANY_ID, 0, 0, CARDTYPE_DIVASRV_Q_8M_V2_PCI},
129/* Diva Server PRI-30M PCI 0xE014 */
130 {PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_MAESTRAP,
131 PCI_ANY_ID, PCI_ANY_ID, 0, 0, CARDTYPE_DIVASRV_P_30M_PCI},
132/* Diva Server PRI 2.0 adapter 0xE015 */
133 {PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_MAESTRAP_2,
134 PCI_ANY_ID, PCI_ANY_ID, 0, 0, CARDTYPE_DIVASRV_P_30M_V2_PCI},
135/* Diva Server Voice 4BRI-8M PCI 0xE016 */
136 {PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_4BRI_VOIP,
137 PCI_ANY_ID, PCI_ANY_ID, 0, 0, CARDTYPE_DIVASRV_VOICE_Q_8M_PCI},
138/* Diva Server Voice 4BRI-8M 2.0 PCI 0xE017 */
139 {PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_4BRI_2_VOIP,
140 PCI_ANY_ID, PCI_ANY_ID, 0, 0, CARDTYPE_DIVASRV_VOICE_Q_8M_V2_PCI},
141/* Diva Server BRI-2M 2.0 PCI 0xE018 */
142 {PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_BRI2M_2,
143 PCI_ANY_ID, PCI_ANY_ID, 0, 0, CARDTYPE_DIVASRV_B_2M_V2_PCI},
144/* Diva Server Voice PRI 2.0 PCI 0xE019 */
145 {PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_MAESTRAP_2_VOIP,
146 PCI_ANY_ID, PCI_ANY_ID, 0, 0,
147 CARDTYPE_DIVASRV_VOICE_P_30M_V2_PCI},
148/* Diva Server 2FX 0xE01A */
149 {PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_2F,
150 PCI_ANY_ID, PCI_ANY_ID, 0, 0, CARDTYPE_DIVASRV_B_2F_PCI},
151/* Diva Server Voice BRI-2M 2.0 PCI 0xE01B */
152 {PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_BRI2M_2_VOIP,
153 PCI_ANY_ID, PCI_ANY_ID, 0, 0, CARDTYPE_DIVASRV_VOICE_B_2M_V2_PCI},
154 {0,} /* 0 terminated list. */
155};
156MODULE_DEVICE_TABLE(pci, divas_pci_tbl);
157
158static int divas_init_one(struct pci_dev *pdev,
159 const struct pci_device_id *ent);
160static void __devexit divas_remove_one(struct pci_dev *pdev);
161
162static struct pci_driver diva_pci_driver = {
163 .name = "divas",
164 .probe = divas_init_one,
165 .remove = __devexit_p(divas_remove_one),
166 .id_table = divas_pci_tbl,
167};
168
169/*********************************************************
170 ** little helper functions
171 *********************************************************/
172static char *getrev(const char *revision)
173{
174 char *rev;
175 char *p;
176 if ((p = strchr(revision, ':'))) {
177 rev = p + 2;
178 p = strchr(rev, '$');
179 *--p = 0;
180 } else
181 rev = "1.0";
182 return rev;
183}
184
185void diva_log_info(unsigned char *format, ...)
186{
187 va_list args;
188 unsigned char line[160];
189
190 va_start(args, format);
191 vsprintf(line, format, args);
192 va_end(args);
193
194 printk(KERN_INFO "%s: %s\n", DRIVERLNAME, line);
195}
196
197void divas_get_version(char *p)
198{
199 char tmprev[32];
200
201 strcpy(tmprev, main_revision);
202 sprintf(p, "%s: %s(%s) %s(%s) major=%d\n", DRIVERLNAME, DRIVERRELEASE_DIVAS,
203 getrev(tmprev), diva_xdi_common_code_build, DIVA_BUILD, major);
204}
205
206/* --------------------------------------------------------------------------
207 PCI Bus services
208 -------------------------------------------------------------------------- */
209byte diva_os_get_pci_bus(void *pci_dev_handle)
210{
211 struct pci_dev *pdev = (struct pci_dev *) pci_dev_handle;
212 return ((byte) pdev->bus->number);
213}
214
215byte diva_os_get_pci_func(void *pci_dev_handle)
216{
217 struct pci_dev *pdev = (struct pci_dev *) pci_dev_handle;
218 return ((byte) pdev->devfn);
219}
220
221unsigned long divasa_get_pci_irq(unsigned char bus, unsigned char func,
222 void *pci_dev_handle)
223{
224 unsigned char irq = 0;
225 struct pci_dev *dev = (struct pci_dev *) pci_dev_handle;
226
227 irq = dev->irq;
228
229 return ((unsigned long) irq);
230}
231
232unsigned long divasa_get_pci_bar(unsigned char bus, unsigned char func,
233 int bar, void *pci_dev_handle)
234{
235 unsigned long ret = 0;
236 struct pci_dev *dev = (struct pci_dev *) pci_dev_handle;
237
238 if (bar < 6) {
239 ret = dev->resource[bar].start;
240 }
241
242 DBG_TRC(("GOT BAR[%d]=%08x", bar, ret));
243
244 {
245 unsigned long type = (ret & 0x00000001);
246 if (type & PCI_BASE_ADDRESS_SPACE_IO) {
247 DBG_TRC((" I/O"));
248 ret &= PCI_BASE_ADDRESS_IO_MASK;
249 } else {
250 DBG_TRC((" memory"));
251 ret &= PCI_BASE_ADDRESS_MEM_MASK;
252 }
253 DBG_TRC((" final=%08x", ret));
254 }
255
256 return (ret);
257}
258
259void PCIwrite(byte bus, byte func, int offset, void *data, int length,
260 void *pci_dev_handle)
261{
262 struct pci_dev *dev = (struct pci_dev *) pci_dev_handle;
263
264 switch (length) {
265 case 1: /* byte */
266 pci_write_config_byte(dev, offset,
267 *(unsigned char *) data);
268 break;
269 case 2: /* word */
270 pci_write_config_word(dev, offset,
271 *(unsigned short *) data);
272 break;
273 case 4: /* dword */
274 pci_write_config_dword(dev, offset,
275 *(unsigned int *) data);
276 break;
277
278 default: /* buffer */
279 if (!(length % 4) && !(length & 0x03)) { /* Copy as dword */
280 dword *p = (dword *) data;
281 length /= 4;
282
283 while (length--) {
284 pci_write_config_dword(dev, offset,
285 *(unsigned int *)
286 p++);
287 }
288 } else { /* copy as byte stream */
289 byte *p = (byte *) data;
290
291 while (length--) {
292 pci_write_config_byte(dev, offset,
293 *(unsigned char *)
294 p++);
295 }
296 }
297 }
298}
299
300void PCIread(byte bus, byte func, int offset, void *data, int length,
301 void *pci_dev_handle)
302{
303 struct pci_dev *dev = (struct pci_dev *) pci_dev_handle;
304
305 switch (length) {
306 case 1: /* byte */
307 pci_read_config_byte(dev, offset, (unsigned char *) data);
308 break;
309 case 2: /* word */
310 pci_read_config_word(dev, offset, (unsigned short *) data);
311 break;
312 case 4: /* dword */
313 pci_read_config_dword(dev, offset, (unsigned int *) data);
314 break;
315
316 default: /* buffer */
317 if (!(length % 4) && !(length & 0x03)) { /* Copy as dword */
318 dword *p = (dword *) data;
319 length /= 4;
320
321 while (length--) {
322 pci_read_config_dword(dev, offset,
323 (unsigned int *)
324 p++);
325 }
326 } else { /* copy as byte stream */
327 byte *p = (byte *) data;
328
329 while (length--) {
330 pci_read_config_byte(dev, offset,
331 (unsigned char *)
332 p++);
333 }
334 }
335 }
336}
337
338/*
339 Init map with DMA pages. It is not problem if some allocations fail -
340 the channels that will not get one DMA page will use standard PIO
341 interface
342 */
343static void *diva_pci_alloc_consistent(struct pci_dev *hwdev,
344 size_t size,
345 dma_addr_t * dma_handle,
346 void **addr_handle)
347{
348 void *addr = pci_alloc_consistent(hwdev, size, dma_handle);
349
350 *addr_handle = addr;
351
352 return (addr);
353}
354
355void diva_init_dma_map(void *hdev,
356 struct _diva_dma_map_entry **ppmap, int nentries)
357{
358 struct pci_dev *pdev = (struct pci_dev *) hdev;
359 struct _diva_dma_map_entry *pmap =
360 diva_alloc_dma_map(hdev, nentries);
361
362 if (pmap) {
363 int i;
364 dma_addr_t dma_handle;
365 void *cpu_addr;
366 void *addr_handle;
367
368 for (i = 0; i < nentries; i++) {
369 if (!(cpu_addr = diva_pci_alloc_consistent(pdev,
370 PAGE_SIZE,
371 &dma_handle,
372 &addr_handle)))
373 {
374 break;
375 }
376 diva_init_dma_map_entry(pmap, i, cpu_addr,
377 (dword) dma_handle,
378 addr_handle);
379 DBG_TRC(("dma map alloc [%d]=(%08lx:%08x:%08lx)",
380 i, (unsigned long) cpu_addr,
381 (dword) dma_handle,
382 (unsigned long) addr_handle))}
383 }
384
385 *ppmap = pmap;
386}
387
388/*
389 Free all contained in the map entries and memory used by the map
390 Should be always called after adapter removal from DIDD array
391 */
392void diva_free_dma_map(void *hdev, struct _diva_dma_map_entry *pmap)
393{
394 struct pci_dev *pdev = (struct pci_dev *) hdev;
395 int i;
396 dword phys_addr;
397 void *cpu_addr;
398 dma_addr_t dma_handle;
399 void *addr_handle;
400
401 for (i = 0; (pmap != 0); i++) {
402 diva_get_dma_map_entry(pmap, i, &cpu_addr, &phys_addr);
403 if (!cpu_addr) {
404 break;
405 }
406 addr_handle = diva_get_entry_handle(pmap, i);
407 dma_handle = (dma_addr_t) phys_addr;
408 pci_free_consistent(pdev, PAGE_SIZE, addr_handle,
409 dma_handle);
410 DBG_TRC(("dma map free [%d]=(%08lx:%08x:%08lx)", i,
411 (unsigned long) cpu_addr, (dword) dma_handle,
412 (unsigned long) addr_handle))
413 }
414
415 diva_free_dma_mapping(pmap);
416}
417
418
419/*********************************************************
420 ** I/O port utilities
421 *********************************************************/
422
423int
424diva_os_register_io_port(void *adapter, int on, unsigned long port,
425 unsigned long length, const char *name, int id)
426{
427 if (on) {
428 if (!request_region(port, length, name)) {
429 DBG_ERR(("A: I/O: can't register port=%08x", port))
430 return (-1);
431 }
432 } else {
433 release_region(port, length);
434 }
435 return (0);
436}
437
438void __iomem *divasa_remap_pci_bar(diva_os_xdi_adapter_t *a, int id, unsigned long bar, unsigned long area_length)
439{
440 void __iomem *ret = ioremap(bar, area_length);
441 DBG_TRC(("remap(%08x)->%p", bar, ret));
442 return (ret);
443}
444
445void divasa_unmap_pci_bar(void __iomem *bar)
446{
447 if (bar) {
448 iounmap(bar);
449 }
450}
451
452/*********************************************************
453 ** I/O port access
454 *********************************************************/
455byte __inline__ inpp(void __iomem *addr)
456{
457 return (inb((unsigned long) addr));
458}
459
460word __inline__ inppw(void __iomem *addr)
461{
462 return (inw((unsigned long) addr));
463}
464
465void __inline__ inppw_buffer(void __iomem *addr, void *P, int length)
466{
467 insw((unsigned long) addr, (word *) P, length >> 1);
468}
469
470void __inline__ outppw_buffer(void __iomem *addr, void *P, int length)
471{
472 outsw((unsigned long) addr, (word *) P, length >> 1);
473}
474
475void __inline__ outppw(void __iomem *addr, word w)
476{
477 outw(w, (unsigned long) addr);
478}
479
480void __inline__ outpp(void __iomem *addr, word p)
481{
482 outb(p, (unsigned long) addr);
483}
484
485/* --------------------------------------------------------------------------
486 IRQ request / remove
487 -------------------------------------------------------------------------- */
488int diva_os_register_irq(void *context, byte irq, const char *name)
489{
490 int result = request_irq(irq, diva_os_irq_wrapper,
491 SA_INTERRUPT | SA_SHIRQ, name, context);
492 return (result);
493}
494
495void diva_os_remove_irq(void *context, byte irq)
496{
497 free_irq(irq, context);
498}
499
500/* --------------------------------------------------------------------------
501 DPC framework implementation
502 -------------------------------------------------------------------------- */
503static void diva_os_dpc_proc(unsigned long context)
504{
505 diva_os_thread_dpc_t *psoft_isr = (diva_os_thread_dpc_t *) context;
506 diva_os_soft_isr_t *pisr = psoft_isr->psoft_isr;
507
508 (*(pisr->callback)) (pisr, pisr->callback_context);
509}
510
511int diva_os_initialize_soft_isr(diva_os_soft_isr_t * psoft_isr,
512 diva_os_soft_isr_callback_t callback,
513 void *callback_context)
514{
515 diva_os_thread_dpc_t *pdpc;
516
517 pdpc = (diva_os_thread_dpc_t *) diva_os_malloc(0, sizeof(*pdpc));
518 if (!(psoft_isr->object = pdpc)) {
519 return (-1);
520 }
521 memset(pdpc, 0x00, sizeof(*pdpc));
522 psoft_isr->callback = callback;
523 psoft_isr->callback_context = callback_context;
524 pdpc->psoft_isr = psoft_isr;
525 tasklet_init(&pdpc->divas_task, diva_os_dpc_proc, (unsigned long)pdpc);
526
527 return (0);
528}
529
530int diva_os_schedule_soft_isr(diva_os_soft_isr_t * psoft_isr)
531{
532 if (psoft_isr && psoft_isr->object) {
533 diva_os_thread_dpc_t *pdpc =
534 (diva_os_thread_dpc_t *) psoft_isr->object;
535
536 tasklet_schedule(&pdpc->divas_task);
537 }
538
539 return (1);
540}
541
542int diva_os_cancel_soft_isr(diva_os_soft_isr_t * psoft_isr)
543{
544 return (0);
545}
546
547void diva_os_remove_soft_isr(diva_os_soft_isr_t * psoft_isr)
548{
549 if (psoft_isr && psoft_isr->object) {
550 diva_os_thread_dpc_t *pdpc =
551 (diva_os_thread_dpc_t *) psoft_isr->object;
552 void *mem;
553
554 tasklet_kill(&pdpc->divas_task);
555 flush_scheduled_work();
556 mem = psoft_isr->object;
557 psoft_isr->object = NULL;
558 diva_os_free(0, mem);
559 }
560}
561
562/*
563 * kernel/user space copy functions
564 */
565static int
566xdi_copy_to_user(void *os_handle, void __user *dst, const void *src, int length)
567{
568 if (copy_to_user(dst, src, length)) {
569 return (-EFAULT);
570 }
571 return (length);
572}
573
574static int
575xdi_copy_from_user(void *os_handle, void *dst, const void __user *src, int length)
576{
577 if (copy_from_user(dst, src, length)) {
578 return (-EFAULT);
579 }
580 return (length);
581}
582
583/*
584 * device node operations
585 */
586static int divas_open(struct inode *inode, struct file *file)
587{
588 return (0);
589}
590
591static int divas_release(struct inode *inode, struct file *file)
592{
593 if (file->private_data) {
594 diva_xdi_close_adapter(file->private_data, file);
595 }
596 return (0);
597}
598
599static ssize_t divas_write(struct file *file, const char __user *buf,
600 size_t count, loff_t * ppos)
601{
602 int ret = -EINVAL;
603
604 if (!file->private_data) {
605 file->private_data = diva_xdi_open_adapter(file, buf,
606 count,
607 xdi_copy_from_user);
608 }
609 if (!file->private_data) {
610 return (-ENODEV);
611 }
612
613 ret = diva_xdi_write(file->private_data, file,
614 buf, count, xdi_copy_from_user);
615 switch (ret) {
616 case -1: /* Message should be removed from rx mailbox first */
617 ret = -EBUSY;
618 break;
619 case -2: /* invalid adapter was specified in this call */
620 ret = -ENOMEM;
621 break;
622 case -3:
623 ret = -ENXIO;
624 break;
625 }
626 DBG_TRC(("write: ret %d", ret));
627 return (ret);
628}
629
630static ssize_t divas_read(struct file *file, char __user *buf,
631 size_t count, loff_t * ppos)
632{
633 int ret = -EINVAL;
634
635 if (!file->private_data) {
636 file->private_data = diva_xdi_open_adapter(file, buf,
637 count,
638 xdi_copy_from_user);
639 }
640 if (!file->private_data) {
641 return (-ENODEV);
642 }
643
644 ret = diva_xdi_read(file->private_data, file,
645 buf, count, xdi_copy_to_user);
646 switch (ret) {
647 case -1: /* RX mailbox is empty */
648 ret = -EAGAIN;
649 break;
650 case -2: /* no memory, mailbox was cleared, last command is failed */
651 ret = -ENOMEM;
652 break;
653 case -3: /* can't copy to user, retry */
654 ret = -EFAULT;
655 break;
656 }
657 DBG_TRC(("read: ret %d", ret));
658 return (ret);
659}
660
661static unsigned int divas_poll(struct file *file, poll_table * wait)
662{
663 if (!file->private_data) {
664 return (POLLERR);
665 }
666 return (POLLIN | POLLRDNORM);
667}
668
669static struct file_operations divas_fops = {
670 .owner = THIS_MODULE,
671 .llseek = no_llseek,
672 .read = divas_read,
673 .write = divas_write,
674 .poll = divas_poll,
675 .open = divas_open,
676 .release = divas_release
677};
678
679static void divas_unregister_chrdev(void)
680{
681 devfs_remove(DEVNAME);
682 unregister_chrdev(major, DEVNAME);
683}
684
685static int DIVA_INIT_FUNCTION divas_register_chrdev(void)
686{
687 if ((major = register_chrdev(0, DEVNAME, &divas_fops)) < 0)
688 {
689 printk(KERN_ERR "%s: failed to create /dev entry.\n",
690 DRIVERLNAME);
691 return (0);
692 }
693 devfs_mk_cdev(MKDEV(major, 0), S_IFCHR|S_IRUSR|S_IWUSR, DEVNAME);
694
695 return (1);
696}
697
698/* --------------------------------------------------------------------------
699 PCI driver section
700 -------------------------------------------------------------------------- */
701static int __devinit divas_init_one(struct pci_dev *pdev,
702 const struct pci_device_id *ent)
703{
704 void *pdiva = NULL;
705 u8 pci_latency;
706 u8 new_latency = 32;
707
708 DBG_TRC(("%s bus: %08x fn: %08x insertion.\n",
709 CardProperties[ent->driver_data].Name,
710 pdev->bus->number, pdev->devfn))
711 printk(KERN_INFO "%s: %s bus: %08x fn: %08x insertion.\n",
712 DRIVERLNAME, CardProperties[ent->driver_data].Name,
713 pdev->bus->number, pdev->devfn);
714
715 if (pci_enable_device(pdev)) {
716 DBG_TRC(("%s: %s bus: %08x fn: %08x device init failed.\n",
717 DRIVERLNAME,
718 CardProperties[ent->driver_data].Name,
719 pdev->bus->number,
720 pdev->devfn))
721 printk(KERN_ERR
722 "%s: %s bus: %08x fn: %08x device init failed.\n",
723 DRIVERLNAME,
724 CardProperties[ent->driver_data].
725 Name, pdev->bus->number,
726 pdev->devfn);
727 return (-EIO);
728 }
729
730 pci_set_master(pdev);
731
732 pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency);
733 if (!pci_latency) {
734 DBG_TRC(("%s: bus: %08x fn: %08x fix latency.\n",
735 DRIVERLNAME, pdev->bus->number, pdev->devfn))
736 printk(KERN_INFO
737 "%s: bus: %08x fn: %08x fix latency.\n",
738 DRIVERLNAME, pdev->bus->number, pdev->devfn);
739 pci_write_config_byte(pdev, PCI_LATENCY_TIMER, new_latency);
740 }
741
742 if (!(pdiva = diva_driver_add_card(pdev, ent->driver_data))) {
743 DBG_TRC(("%s: %s bus: %08x fn: %08x card init failed.\n",
744 DRIVERLNAME,
745 CardProperties[ent->driver_data].Name,
746 pdev->bus->number,
747 pdev->devfn))
748 printk(KERN_ERR
749 "%s: %s bus: %08x fn: %08x card init failed.\n",
750 DRIVERLNAME,
751 CardProperties[ent->driver_data].
752 Name, pdev->bus->number,
753 pdev->devfn);
754 return (-EIO);
755 }
756
757 pci_set_drvdata(pdev, pdiva);
758
759 return (0);
760}
761
762static void __devexit divas_remove_one(struct pci_dev *pdev)
763{
764 void *pdiva = pci_get_drvdata(pdev);
765
766 DBG_TRC(("bus: %08x fn: %08x removal.\n",
767 pdev->bus->number, pdev->devfn))
768 printk(KERN_INFO "%s: bus: %08x fn: %08x removal.\n",
769 DRIVERLNAME, pdev->bus->number, pdev->devfn);
770
771 if (pdiva) {
772 diva_driver_remove_card(pdiva);
773 }
774
775}
776
777/* --------------------------------------------------------------------------
778 Driver Load / Startup
779 -------------------------------------------------------------------------- */
780static int DIVA_INIT_FUNCTION divas_init(void)
781{
782 char tmprev[50];
783 int ret = 0;
784
785 printk(KERN_INFO "%s\n", DRIVERNAME);
786 printk(KERN_INFO "%s: Rel:%s Rev:", DRIVERLNAME, DRIVERRELEASE_DIVAS);
787 strcpy(tmprev, main_revision);
788 printk("%s Build: %s(%s)\n", getrev(tmprev),
789 diva_xdi_common_code_build, DIVA_BUILD);
790 printk(KERN_INFO "%s: support for: ", DRIVERLNAME);
791#ifdef CONFIG_ISDN_DIVAS_BRIPCI
792 printk("BRI/PCI ");
793#endif
794#ifdef CONFIG_ISDN_DIVAS_PRIPCI
795 printk("PRI/PCI ");
796#endif
797 printk("adapters\n");
798
799 if (!divasfunc_init(dbgmask)) {
800 printk(KERN_ERR "%s: failed to connect to DIDD.\n",
801 DRIVERLNAME);
802 ret = -EIO;
803 goto out;
804 }
805
806 if (!divas_register_chrdev()) {
807#ifdef MODULE
808 divasfunc_exit();
809#endif
810 ret = -EIO;
811 goto out;
812 }
813
814 if (!create_divas_proc()) {
815#ifdef MODULE
816 remove_divas_proc();
817 divas_unregister_chrdev();
818 divasfunc_exit();
819#endif
820 printk(KERN_ERR "%s: failed to create proc entry.\n",
821 DRIVERLNAME);
822 ret = -EIO;
823 goto out;
824 }
825
826 if ((ret = pci_register_driver(&diva_pci_driver))) {
827#ifdef MODULE
828 remove_divas_proc();
829 divas_unregister_chrdev();
830 divasfunc_exit();
831#endif
832 printk(KERN_ERR "%s: failed to init pci driver.\n",
833 DRIVERLNAME);
834 goto out;
835 }
836 printk(KERN_INFO "%s: started with major %d\n", DRIVERLNAME, major);
837
838 out:
839 return (ret);
840}
841
842/* --------------------------------------------------------------------------
843 Driver Unload
844 -------------------------------------------------------------------------- */
845static void DIVA_EXIT_FUNCTION divas_exit(void)
846{
847 pci_unregister_driver(&diva_pci_driver);
848 remove_divas_proc();
849 divas_unregister_chrdev();
850 divasfunc_exit();
851
852 printk(KERN_INFO "%s: module unloaded.\n", DRIVERLNAME);
853}
854
855module_init(divas_init);
856module_exit(divas_exit);
diff --git a/drivers/isdn/hardware/eicon/divasproc.c b/drivers/isdn/hardware/eicon/divasproc.c
new file mode 100644
index 000000000000..b6435589d459
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/divasproc.c
@@ -0,0 +1,441 @@
1/* $Id: divasproc.c,v 1.19.4.3 2005/01/31 12:22:20 armin Exp $
2 *
3 * Low level driver for Eicon DIVA Server ISDN cards.
4 * /proc functions
5 *
6 * Copyright 2000-2003 by Armin Schindler (mac@melware.de)
7 * Copyright 2000-2003 Cytronics & Melware (info@melware.de)
8 *
9 * This software may be used and distributed according to the terms
10 * of the GNU General Public License, incorporated herein by reference.
11 */
12
13#include <linux/config.h>
14#include <linux/module.h>
15#include <linux/kernel.h>
16#include <linux/poll.h>
17#include <linux/proc_fs.h>
18#include <linux/list.h>
19#include <asm/uaccess.h>
20
21#include "platform.h"
22#include "debuglib.h"
23#undef ID_MASK
24#undef N_DATA
25#include "pc.h"
26#include "di_defs.h"
27#include "divasync.h"
28#include "di.h"
29#include "io.h"
30#include "xdi_msg.h"
31#include "xdi_adapter.h"
32#include "diva.h"
33#include "diva_pci.h"
34
35
36extern PISDN_ADAPTER IoAdapters[MAX_ADAPTER];
37extern void divas_get_version(char *);
38extern void diva_get_vserial_number(PISDN_ADAPTER IoAdapter, char *buf);
39
40/*********************************************************
41 ** Functions for /proc interface / File operations
42 *********************************************************/
43
44static char *divas_proc_name = "divas";
45static char *adapter_dir_name = "adapter";
46static char *info_proc_name = "info";
47static char *grp_opt_proc_name = "group_optimization";
48static char *d_l1_down_proc_name = "dynamic_l1_down";
49
50/*
51** "divas" entry
52*/
53
54extern struct proc_dir_entry *proc_net_eicon;
55static struct proc_dir_entry *divas_proc_entry = NULL;
56
57static ssize_t
58divas_read(struct file *file, char __user *buf, size_t count, loff_t * off)
59{
60 int len = 0;
61 int cadapter;
62 char tmpbuf[80];
63 char tmpser[16];
64
65 if (*off)
66 return 0;
67
68 divas_get_version(tmpbuf);
69 if (copy_to_user(buf + len, &tmpbuf, strlen(tmpbuf)))
70 return -EFAULT;
71 len += strlen(tmpbuf);
72
73 for (cadapter = 0; cadapter < MAX_ADAPTER; cadapter++) {
74 if (IoAdapters[cadapter]) {
75 diva_get_vserial_number(IoAdapters[cadapter],
76 tmpser);
77 sprintf(tmpbuf,
78 "%2d: %-30s Serial:%-10s IRQ:%2d\n",
79 cadapter + 1,
80 IoAdapters[cadapter]->Properties.Name,
81 tmpser,
82 IoAdapters[cadapter]->irq_info.irq_nr);
83 if ((strlen(tmpbuf) + len) > count)
84 break;
85 if (copy_to_user
86 (buf + len, &tmpbuf,
87 strlen(tmpbuf))) return -EFAULT;
88 len += strlen(tmpbuf);
89 }
90 }
91
92 *off += len;
93 return (len);
94}
95
96static ssize_t
97divas_write(struct file *file, const char __user *buf, size_t count, loff_t * off)
98{
99 return (-ENODEV);
100}
101
102static unsigned int divas_poll(struct file *file, poll_table * wait)
103{
104 return (POLLERR);
105}
106
107static int divas_open(struct inode *inode, struct file *file)
108{
109 return nonseekable_open(inode, file);
110}
111
112static int divas_close(struct inode *inode, struct file *file)
113{
114 return (0);
115}
116
117static struct file_operations divas_fops = {
118 .owner = THIS_MODULE,
119 .llseek = no_llseek,
120 .read = divas_read,
121 .write = divas_write,
122 .poll = divas_poll,
123 .open = divas_open,
124 .release = divas_close
125};
126
127int create_divas_proc(void)
128{
129 divas_proc_entry = create_proc_entry(divas_proc_name,
130 S_IFREG | S_IRUGO,
131 proc_net_eicon);
132 if (!divas_proc_entry)
133 return (0);
134
135 divas_proc_entry->proc_fops = &divas_fops;
136 divas_proc_entry->owner = THIS_MODULE;
137
138 return (1);
139}
140
141void remove_divas_proc(void)
142{
143 if (divas_proc_entry) {
144 remove_proc_entry(divas_proc_name, proc_net_eicon);
145 divas_proc_entry = NULL;
146 }
147}
148
149/*
150** write group_optimization
151*/
152static int
153write_grp_opt(struct file *file, const char __user *buffer, unsigned long count,
154 void *data)
155{
156 diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) data;
157 PISDN_ADAPTER IoAdapter = IoAdapters[a->controller - 1];
158
159 if ((count == 1) || (count == 2)) {
160 char c;
161 if (get_user(c, buffer))
162 return -EFAULT;
163 switch (c) {
164 case '0':
165 IoAdapter->capi_cfg.cfg_1 &=
166 ~DIVA_XDI_CAPI_CFG_1_GROUP_POPTIMIZATION_ON;
167 break;
168 case '1':
169 IoAdapter->capi_cfg.cfg_1 |=
170 DIVA_XDI_CAPI_CFG_1_GROUP_POPTIMIZATION_ON;
171 break;
172 default:
173 return (-EINVAL);
174 }
175 return (count);
176 }
177 return (-EINVAL);
178}
179
180/*
181** write dynamic_l1_down
182*/
183static int
184write_d_l1_down(struct file *file, const char __user *buffer, unsigned long count,
185 void *data)
186{
187 diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) data;
188 PISDN_ADAPTER IoAdapter = IoAdapters[a->controller - 1];
189
190 if ((count == 1) || (count == 2)) {
191 char c;
192 if (get_user(c, buffer))
193 return -EFAULT;
194 switch (c) {
195 case '0':
196 IoAdapter->capi_cfg.cfg_1 &=
197 ~DIVA_XDI_CAPI_CFG_1_DYNAMIC_L1_ON;
198 break;
199 case '1':
200 IoAdapter->capi_cfg.cfg_1 |=
201 DIVA_XDI_CAPI_CFG_1_DYNAMIC_L1_ON;
202 break;
203 default:
204 return (-EINVAL);
205 }
206 return (count);
207 }
208 return (-EINVAL);
209}
210
211
212/*
213** read dynamic_l1_down
214*/
215static int
216read_d_l1_down(char *page, char **start, off_t off, int count, int *eof,
217 void *data)
218{
219 int len = 0;
220 diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) data;
221 PISDN_ADAPTER IoAdapter = IoAdapters[a->controller - 1];
222
223 len += sprintf(page + len, "%s\n",
224 (IoAdapter->capi_cfg.
225 cfg_1 & DIVA_XDI_CAPI_CFG_1_DYNAMIC_L1_ON) ? "1" :
226 "0");
227
228 if (off + count >= len)
229 *eof = 1;
230 if (len < off)
231 return 0;
232 *start = page + off;
233 return ((count < len - off) ? count : len - off);
234}
235
236/*
237** read group_optimization
238*/
239static int
240read_grp_opt(char *page, char **start, off_t off, int count, int *eof,
241 void *data)
242{
243 int len = 0;
244 diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) data;
245 PISDN_ADAPTER IoAdapter = IoAdapters[a->controller - 1];
246
247 len += sprintf(page + len, "%s\n",
248 (IoAdapter->capi_cfg.
249 cfg_1 & DIVA_XDI_CAPI_CFG_1_GROUP_POPTIMIZATION_ON)
250 ? "1" : "0");
251
252 if (off + count >= len)
253 *eof = 1;
254 if (len < off)
255 return 0;
256 *start = page + off;
257 return ((count < len - off) ? count : len - off);
258}
259
260/*
261** info write
262*/
263static int
264info_write(struct file *file, const char __user *buffer, unsigned long count,
265 void *data)
266{
267 diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) data;
268 PISDN_ADAPTER IoAdapter = IoAdapters[a->controller - 1];
269 char c[4];
270
271 if (count <= 4)
272 return -EINVAL;
273
274 if (copy_from_user(c, buffer, 4))
275 return -EFAULT;
276
277 /* this is for test purposes only */
278 if (!memcmp(c, "trap", 4)) {
279 (*(IoAdapter->os_trap_nfy_Fnc)) (IoAdapter, IoAdapter->ANum);
280 return (count);
281 }
282 return (-EINVAL);
283}
284
285/*
286** info read
287*/
288static int
289info_read(char *page, char **start, off_t off, int count, int *eof,
290 void *data)
291{
292 int i = 0;
293 int len = 0;
294 char *p;
295 char tmpser[16];
296 diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) data;
297 PISDN_ADAPTER IoAdapter = IoAdapters[a->controller - 1];
298
299 len +=
300 sprintf(page + len, "Name : %s\n",
301 IoAdapter->Properties.Name);
302 len += sprintf(page + len, "DSP state : %08x\n", a->dsp_mask);
303 len += sprintf(page + len, "Channels : %02d\n",
304 IoAdapter->Properties.Channels);
305 len += sprintf(page + len, "E. max/used : %03d/%03d\n",
306 IoAdapter->e_max, IoAdapter->e_count);
307 diva_get_vserial_number(IoAdapter, tmpser);
308 len += sprintf(page + len, "Serial : %s\n", tmpser);
309 len +=
310 sprintf(page + len, "IRQ : %d\n",
311 IoAdapter->irq_info.irq_nr);
312 len += sprintf(page + len, "CardIndex : %d\n", a->CardIndex);
313 len += sprintf(page + len, "CardOrdinal : %d\n", a->CardOrdinal);
314 len += sprintf(page + len, "Controller : %d\n", a->controller);
315 len += sprintf(page + len, "Bus-Type : %s\n",
316 (a->Bus ==
317 DIVAS_XDI_ADAPTER_BUS_ISA) ? "ISA" : "PCI");
318 len += sprintf(page + len, "Port-Name : %s\n", a->port_name);
319 if (a->Bus == DIVAS_XDI_ADAPTER_BUS_PCI) {
320 len +=
321 sprintf(page + len, "PCI-bus : %d\n",
322 a->resources.pci.bus);
323 len +=
324 sprintf(page + len, "PCI-func : %d\n",
325 a->resources.pci.func);
326 for (i = 0; i < 8; i++) {
327 if (a->resources.pci.bar[i]) {
328 len +=
329 sprintf(page + len,
330 "Mem / I/O %d : 0x%x / mapped : 0x%lx",
331 i, a->resources.pci.bar[i],
332 (unsigned long) a->resources.
333 pci.addr[i]);
334 if (a->resources.pci.length[i]) {
335 len +=
336 sprintf(page + len,
337 " / length : %d",
338 a->resources.pci.
339 length[i]);
340 }
341 len += sprintf(page + len, "\n");
342 }
343 }
344 }
345 if ((!a->xdi_adapter.port) &&
346 ((!a->xdi_adapter.ram) ||
347 (!a->xdi_adapter.reset)
348 || (!a->xdi_adapter.cfg))) {
349 if (!IoAdapter->irq_info.irq_nr) {
350 p = "slave";
351 } else {
352 p = "out of service";
353 }
354 } else if (a->xdi_adapter.trapped) {
355 p = "trapped";
356 } else if (a->xdi_adapter.Initialized) {
357 p = "active";
358 } else {
359 p = "ready";
360 }
361 len += sprintf(page + len, "State : %s\n", p);
362
363 if (off + count >= len)
364 *eof = 1;
365 if (len < off)
366 return 0;
367 *start = page + off;
368 return ((count < len - off) ? count : len - off);
369}
370
371/*
372** adapter proc init/de-init
373*/
374
375/* --------------------------------------------------------------------------
376 Create adapter directory and files in proc file system
377 -------------------------------------------------------------------------- */
378int create_adapter_proc(diva_os_xdi_adapter_t * a)
379{
380 struct proc_dir_entry *de, *pe;
381 char tmp[16];
382
383 sprintf(tmp, "%s%d", adapter_dir_name, a->controller);
384 if (!(de = create_proc_entry(tmp, S_IFDIR, proc_net_eicon)))
385 return (0);
386 a->proc_adapter_dir = (void *) de;
387
388 if (!(pe =
389 create_proc_entry(info_proc_name, S_IFREG | S_IRUGO | S_IWUSR, de)))
390 return (0);
391 a->proc_info = (void *) pe;
392 pe->write_proc = info_write;
393 pe->read_proc = info_read;
394 pe->data = a;
395
396 if ((pe = create_proc_entry(grp_opt_proc_name,
397 S_IFREG | S_IRUGO | S_IWUSR, de))) {
398 a->proc_grp_opt = (void *) pe;
399 pe->write_proc = write_grp_opt;
400 pe->read_proc = read_grp_opt;
401 pe->data = a;
402 }
403 if ((pe = create_proc_entry(d_l1_down_proc_name,
404 S_IFREG | S_IRUGO | S_IWUSR, de))) {
405 a->proc_d_l1_down = (void *) pe;
406 pe->write_proc = write_d_l1_down;
407 pe->read_proc = read_d_l1_down;
408 pe->data = a;
409 }
410
411 DBG_TRC(("proc entry %s created", tmp));
412
413 return (1);
414}
415
416/* --------------------------------------------------------------------------
417 Remove adapter directory and files in proc file system
418 -------------------------------------------------------------------------- */
419void remove_adapter_proc(diva_os_xdi_adapter_t * a)
420{
421 char tmp[16];
422
423 if (a->proc_adapter_dir) {
424 if (a->proc_d_l1_down) {
425 remove_proc_entry(d_l1_down_proc_name,
426 (struct proc_dir_entry *) a->proc_adapter_dir);
427 }
428 if (a->proc_grp_opt) {
429 remove_proc_entry(grp_opt_proc_name,
430 (struct proc_dir_entry *) a->proc_adapter_dir);
431 }
432 if (a->proc_info) {
433 remove_proc_entry(info_proc_name,
434 (struct proc_dir_entry *) a->proc_adapter_dir);
435 }
436 sprintf(tmp, "%s%d", adapter_dir_name, a->controller);
437 remove_proc_entry(tmp, proc_net_eicon);
438 DBG_TRC(("proc entry %s%d removed", adapter_dir_name,
439 a->controller));
440 }
441}
diff --git a/drivers/isdn/hardware/eicon/divasync.h b/drivers/isdn/hardware/eicon/divasync.h
new file mode 100644
index 000000000000..0a5be7f969f2
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/divasync.h
@@ -0,0 +1,490 @@
1
2/*
3 *
4 Copyright (c) Eicon Networks, 2002.
5 *
6 This source file is supplied for the use with
7 Eicon Networks range of DIVA Server Adapters.
8 *
9 Eicon File Revision : 2.1
10 *
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2, or (at your option)
14 any later version.
15 *
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
18 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 See the GNU General Public License for more details.
20 *
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26#ifndef __DIVA_SYNC__H
27#define __DIVA_SYNC__H
28#define IDI_SYNC_REQ_REMOVE 0x00
29#define IDI_SYNC_REQ_GET_NAME 0x01
30#define IDI_SYNC_REQ_GET_SERIAL 0x02
31#define IDI_SYNC_REQ_SET_POSTCALL 0x03
32#define IDI_SYNC_REQ_GET_XLOG 0x04
33#define IDI_SYNC_REQ_GET_FEATURES 0x05
34#define IDI_SYNC_REQ_USB_REGISTER 0x06
35#define IDI_SYNC_REQ_USB_RELEASE 0x07
36#define IDI_SYNC_REQ_USB_ADD_DEVICE 0x08
37#define IDI_SYNC_REQ_USB_START_DEVICE 0x09
38#define IDI_SYNC_REQ_USB_STOP_DEVICE 0x0A
39#define IDI_SYNC_REQ_USB_REMOVE_DEVICE 0x0B
40#define IDI_SYNC_REQ_GET_CARDTYPE 0x0C
41#define IDI_SYNC_REQ_GET_DBG_XLOG 0x0D
42#define DIVA_USB
43#define DIVA_USB_REQ 0xAC
44#define DIVA_USB_TEST 0xAB
45#define DIVA_USB_ADD_ADAPTER 0xAC
46#define DIVA_USB_REMOVE_ADAPTER 0xAD
47#define IDI_SYNC_REQ_SERIAL_HOOK 0x80
48#define IDI_SYNC_REQ_XCHANGE_STATUS 0x81
49#define IDI_SYNC_REQ_USB_HOOK 0x82
50#define IDI_SYNC_REQ_PORTDRV_HOOK 0x83
51#define IDI_SYNC_REQ_SLI 0x84 /* SLI request from 3signal modem drivers */
52#define IDI_SYNC_REQ_RECONFIGURE 0x85
53#define IDI_SYNC_REQ_RESET 0x86
54#define IDI_SYNC_REQ_GET_85X_DEVICE_DATA 0x87
55#define IDI_SYNC_REQ_LOCK_85X 0x88
56#define IDI_SYNC_REQ_DIVA_85X_USB_DATA_EXCHANGE 0x99
57#define IDI_SYNC_REQ_DIPORT_EXCHANGE_REQ 0x98
58#define IDI_SYNC_REQ_GET_85X_EXT_PORT_TYPE 0xA0
59/******************************************************************************/
60#define IDI_SYNC_REQ_XDI_GET_EXTENDED_FEATURES 0x92
61/*
62 To receive XDI features:
63 1. set 'buffer_length_in_bytes' to length of you buffer
64 2. set 'features' to pointer to your buffer
65 3. issue synchronous request to XDI
66 4. Check that feature 'DIVA_XDI_EXTENDED_FEATURES_VALID' is present
67 after call. This feature does indicate that your request
68 was processed and XDI does support this synchronous request
69 5. if on return bit 31 (0x80000000) in 'buffer_length_in_bytes' is
70 set then provided buffer was too small, and bits 30-0 does
71 contain necessary length of buffer.
72 in this case only features that do find place in the buffer
73 are indicated to caller
74*/
75typedef struct _diva_xdi_get_extended_xdi_features {
76 dword buffer_length_in_bytes;
77 byte *features;
78} diva_xdi_get_extended_xdi_features_t;
79/*
80 features[0]
81 */
82#define DIVA_XDI_EXTENDED_FEATURES_VALID 0x01
83#define DIVA_XDI_EXTENDED_FEATURE_CMA 0x02
84#define DIVA_XDI_EXTENDED_FEATURE_SDRAM_BAR 0x04
85#define DIVA_XDI_EXTENDED_FEATURE_CAPI_PRMS 0x08
86#define DIVA_XDI_EXTENDED_FEATURE_NO_CANCEL_RC 0x10
87#define DIVA_XDI_EXTENDED_FEATURE_RX_DMA 0x20
88#define DIVA_XDI_EXTENDED_FEATURE_MANAGEMENT_DMA 0x40
89#define DIVA_XDI_EXTENDED_FEATURE_WIDE_ID 0x80
90#define DIVA_XDI_EXTENDED_FEATURES_MAX_SZ 1
91/******************************************************************************/
92#define IDI_SYNC_REQ_XDI_GET_ADAPTER_SDRAM_BAR 0x93
93typedef struct _diva_xdi_get_adapter_sdram_bar {
94 dword bar;
95} diva_xdi_get_adapter_sdram_bar_t;
96/******************************************************************************/
97#define IDI_SYNC_REQ_XDI_GET_CAPI_PARAMS 0x94
98/*
99 CAPI Parameters will be written in the caller's buffer
100 */
101typedef struct _diva_xdi_get_capi_parameters {
102 dword structure_length;
103 byte flag_dynamic_l1_down;
104 byte group_optimization_enabled;
105} diva_xdi_get_capi_parameters_t;
106/******************************************************************************/
107#define IDI_SYNC_REQ_XDI_GET_LOGICAL_ADAPTER_NUMBER 0x95
108/*
109 Get logical adapter number, as assigned by XDI
110 'controller' is starting with zero 'sub' controller number
111 in case of one adapter that supports multiple interfaces
112 'controller' is zero for Master adapter (and adapter that supports
113 only one interface)
114 */
115typedef struct _diva_xdi_get_logical_adapter_number {
116 dword logical_adapter_number;
117 dword controller;
118 dword total_controllers;
119} diva_xdi_get_logical_adapter_number_s_t;
120/******************************************************************************/
121#define IDI_SYNC_REQ_UP1DM_OPERATION 0x96
122/******************************************************************************/
123#define IDI_SYNC_REQ_DMA_DESCRIPTOR_OPERATION 0x97
124#define IDI_SYNC_REQ_DMA_DESCRIPTOR_ALLOC 0x01
125#define IDI_SYNC_REQ_DMA_DESCRIPTOR_FREE 0x02
126typedef struct _diva_xdi_dma_descriptor_operation {
127 int operation;
128 int descriptor_number;
129 void* descriptor_address;
130 dword descriptor_magic;
131} diva_xdi_dma_descriptor_operation_t;
132/******************************************************************************/
133#define IDI_SYNC_REQ_DIDD_REGISTER_ADAPTER_NOTIFY 0x01
134#define IDI_SYNC_REQ_DIDD_REMOVE_ADAPTER_NOTIFY 0x02
135#define IDI_SYNC_REQ_DIDD_ADD_ADAPTER 0x03
136#define IDI_SYNC_REQ_DIDD_REMOVE_ADAPTER 0x04
137#define IDI_SYNC_REQ_DIDD_READ_ADAPTER_ARRAY 0x05
138#define IDI_SYNC_REQ_DIDD_GET_CFG_LIB_IFC 0x10
139typedef struct _diva_didd_adapter_notify {
140 dword handle; /* Notification handle */
141 void * callback;
142 void * context;
143} diva_didd_adapter_notify_t;
144typedef struct _diva_didd_add_adapter {
145 void * descriptor;
146} diva_didd_add_adapter_t;
147typedef struct _diva_didd_remove_adapter {
148 IDI_CALL p_request;
149} diva_didd_remove_adapter_t;
150typedef struct _diva_didd_read_adapter_array {
151 void * buffer;
152 dword length;
153} diva_didd_read_adapter_array_t;
154typedef struct _diva_didd_get_cfg_lib_ifc {
155 void* ifc;
156} diva_didd_get_cfg_lib_ifc_t;
157/******************************************************************************/
158#define IDI_SYNC_REQ_XDI_GET_STREAM 0x91
159#define DIVA_XDI_SYNCHRONOUS_SERVICE 0x01
160#define DIVA_XDI_DMA_SERVICE 0x02
161#define DIVA_XDI_AUTO_SERVICE 0x03
162#define DIVA_ISTREAM_COMPLETE_NOTIFY 0
163#define DIVA_ISTREAM_COMPLETE_READ 1
164#define DIVA_ISTREAM_COMPLETE_WRITE 2
165typedef struct _diva_xdi_stream_interface {
166 unsigned char Id; /* filled by XDI client */
167 unsigned char provided_service; /* filled by XDI */
168 unsigned char requested_service; /* filled by XDI Client */
169 void* xdi_context; /* filled by XDI */
170 void* client_context; /* filled by XDI client */
171 int (*write)(void* context,
172 int Id,
173 void* data,
174 int length,
175 int final,
176 byte usr1,
177 byte usr2);
178 int (*read)(void* context,
179 int Id,
180 void* data,
181 int max_length,
182 int* final,
183 byte* usr1,
184 byte* usr2);
185 int (*complete)(void* client_context,
186 int Id,
187 int what,
188 void* data,
189 int length,
190 int* final);
191} diva_xdi_stream_interface_t;
192/******************************************************************************/
193/*
194 * IDI_SYNC_REQ_SERIAL_HOOK - special interface for the DIVA Mobile card
195 */
196typedef struct
197{ unsigned char LineState; /* Modem line state (STATUS_R) */
198#define SERIAL_GSM_CELL 0x01 /* GSM or CELL cable attached */
199 unsigned char CardState; /* PCMCIA card state (0 = down) */
200 unsigned char IsdnState; /* ISDN layer 1 state (0 = down)*/
201 unsigned char HookState; /* current logical hook state */
202#define SERIAL_ON_HOOK 0x02 /* set in DIVA CTRL_R register */
203} SERIAL_STATE;
204typedef int ( * SERIAL_INT_CB) (void *Context) ;
205typedef int ( * SERIAL_DPC_CB) (void *Context) ;
206typedef unsigned char ( * SERIAL_I_SYNC) (void *Context) ;
207typedef struct
208{ /* 'Req' and 'Rc' must be at the same place as in the ENTITY struct */
209 unsigned char Req; /* request (must be always 0) */
210 unsigned char Rc; /* return code (is the request) */
211 unsigned char Function; /* private function code */
212#define SERIAL_HOOK_ATTACH 0x81
213#define SERIAL_HOOK_STATUS 0x82
214#define SERIAL_HOOK_I_SYNC 0x83
215#define SERIAL_HOOK_NOECHO 0x84
216#define SERIAL_HOOK_RING 0x85
217#define SERIAL_HOOK_DETACH 0x8f
218 unsigned char Flags; /* function refinements */
219 /* parameters passed by the the ATTACH request */
220 SERIAL_INT_CB InterruptHandler; /* called on each interrupt */
221 SERIAL_DPC_CB DeferredHandler; /* called on hook state changes */
222 void *HandlerContext; /* context for both handlers */
223 /* return values for both the ATTACH and the STATUS request */
224 unsigned long IoBase; /* IO port assigned to UART */
225 SERIAL_STATE State;
226 /* parameters and return values for the I_SYNC function */
227 SERIAL_I_SYNC SyncFunction; /* to be called synchronized */
228 void *SyncContext; /* context for this function */
229 unsigned char SyncResult; /* return value of function */
230} SERIAL_HOOK;
231/*
232 * IDI_SYNC_REQ_XCHANGE_STATUS - exchange the status between IDI and WMP
233 * IDI_SYNC_REQ_RECONFIGURE - reconfiguration of IDI from WMP
234 */
235typedef struct
236{ /* 'Req' and 'Rc' must be at the same place as in the ENTITY struct */
237 unsigned char Req; /* request (must be always 0) */
238 unsigned char Rc; /* return code (is the request) */
239#define DRIVER_STATUS_BOOT 0xA1
240#define DRIVER_STATUS_INIT_DEV 0xA2
241#define DRIVER_STATUS_RUNNING 0xA3
242#define DRIVER_STATUS_SHUTDOWN 0xAF
243#define DRIVER_STATUS_TRAPPED 0xAE
244 unsigned char wmpStatus; /* exported by WMP */
245 unsigned char idiStatus; /* exported by IDI */
246 unsigned long wizProto ; /* from WMP registry to IDI */
247 /* the cardtype value is defined by cardtype.h */
248 unsigned long cardType ; /* from IDI registry to WMP */
249 unsigned long nt2 ; /* from IDI registry to WMP */
250 unsigned long permanent ; /* from IDI registry to WMP */
251 unsigned long stableL2 ; /* from IDI registry to WMP */
252 unsigned long tei ; /* from IDI registry to WMP */
253#define CRC4_MASK 0x00000003
254#define L1_TRISTATE_MASK 0x00000004
255#define WATCHDOG_MASK 0x00000008
256#define NO_ORDER_CHECK_MASK 0x00000010
257#define LOW_CHANNEL_MASK 0x00000020
258#define NO_HSCX30_MASK 0x00000040
259#define MODE_MASK 0x00000080
260#define SET_BOARD 0x00001000
261#define SET_CRC4 0x00030000
262#define SET_L1_TRISTATE 0x00040000
263#define SET_WATCHDOG 0x00080000
264#define SET_NO_ORDER_CHECK 0x00100000
265#define SET_LOW_CHANNEL 0x00200000
266#define SET_NO_HSCX30 0x00400000
267#define SET_MODE 0x00800000
268#define SET_PROTO 0x02000000
269#define SET_CARDTYPE 0x04000000
270#define SET_NT2 0x08000000
271#define SET_PERMANENT 0x10000000
272#define SET_STABLEL2 0x20000000
273#define SET_TEI 0x40000000
274#define SET_NUMBERLEN 0x80000000
275 unsigned long Flag ; /* |31-Type-16|15-Mask-0| */
276 unsigned long NumberLen ; /* reconfiguration: union is empty */
277 union {
278 struct { /* possible reconfiguration, but ... ; SET_BOARD */
279 unsigned long SerialNumber ;
280 char *pCardname ; /* di_defs.h: BOARD_NAME_LENGTH */
281 } board ;
282 struct { /* reset: need resources */
283 void * pRawResources ;
284 void * pXlatResources ;
285 } res ;
286 struct { /* reconfiguration: wizProto == PROTTYPE_RBSCAS */
287#define GLARE_RESOLVE_MASK 0x00000001
288#define DID_MASK 0x00000002
289#define BEARER_CAP_MASK 0x0000000c
290#define SET_GLARE_RESOLVE 0x00010000
291#define SET_DID 0x00020000
292#define SET_BEARER_CAP 0x000c0000
293 unsigned long Flag ; /* |31-Type-16|15-VALUE-0| */
294 unsigned short DigitTimeout ;
295 unsigned short AnswerDelay ;
296 } rbs ;
297 struct { /* reconfiguration: wizProto == PROTTYPE_QSIG */
298#define CALL_REF_LENGTH1_MASK 0x00000001
299#define BRI_CHANNEL_ID_MASK 0x00000002
300#define SET_CALL_REF_LENGTH 0x00010000
301#define SET_BRI_CHANNEL_ID 0x00020000
302 unsigned long Flag ; /* |31-Type-16|15-VALUE-0| */
303 } qsig ;
304 struct { /* reconfiguration: NumberLen != 0 */
305#define SET_SPID1 0x00010000
306#define SET_NUMBER1 0x00020000
307#define SET_SUBADDRESS1 0x00040000
308#define SET_SPID2 0x00100000
309#define SET_NUMBER2 0x00200000
310#define SET_SUBADDRESS2 0x00400000
311#define MASK_SET 0xffff0000
312 unsigned long Flag ; /* |31-Type-16|15-Channel-0| */
313 unsigned char *pBuffer ; /* number value */
314 } isdnNo ;
315 }
316parms
317;
318} isdnProps ;
319/*
320 * IDI_SYNC_REQ_PORTDRV_HOOK - signal plug/unplug (Award Cardware only)
321 */
322typedef void ( * PORTDRV_HOOK_CB) (void *Context, int Plug) ;
323typedef struct
324{ /* 'Req' and 'Rc' must be at the same place as in the ENTITY struct */
325 unsigned char Req; /* request (must be always 0) */
326 unsigned char Rc; /* return code (is the request) */
327 unsigned char Function; /* private function code */
328 unsigned char Flags; /* function refinements */
329 PORTDRV_HOOK_CB Callback; /* to be called on plug/unplug */
330 void *Context; /* context for callback */
331 unsigned long Info; /* more info if needed */
332} PORTDRV_HOOK ;
333/* Codes for the 'Rc' element in structure below. */
334#define SLI_INSTALL (0xA1)
335#define SLI_UNINSTALL (0xA2)
336typedef int ( * SLIENTRYPOINT)(void* p3SignalAPI, void* pContext);
337typedef struct
338{ /* 'Req' and 'Rc' must be at the same place as in the ENTITY struct */
339 unsigned char Req; /* request (must be always 0) */
340 unsigned char Rc; /* return code (is the request) */
341 unsigned char Function; /* private function code */
342 unsigned char Flags; /* function refinements */
343 SLIENTRYPOINT Callback; /* to be called on plug/unplug */
344 void *Context; /* context for callback */
345 unsigned long Info; /* more info if needed */
346} SLIENTRYPOINT_REQ ;
347/******************************************************************************/
348/*
349 * Definitions for DIVA USB
350 */
351typedef int ( * USB_SEND_REQ) (unsigned char PipeIndex, unsigned char Type,void *Data, int sizeData);
352typedef int ( * USB_START_DEV) (void *Adapter, void *Ipac) ;
353/* called from WDM */
354typedef void ( * USB_RECV_NOTIFY) (void *Ipac, void *msg) ;
355typedef void ( * USB_XMIT_NOTIFY) (void *Ipac, unsigned char PipeIndex) ;
356/******************************************************************************/
357/*
358 * Parameter description for synchronous requests.
359 *
360 * Sorry, must repeat some parts of di_defs.h here because
361 * they are not defined for all operating environments
362 */
363typedef union
364{ ENTITY Entity;
365 struct
366 { /* 'Req' and 'Rc' are at the same place as in the ENTITY struct */
367 unsigned char Req; /* request (must be always 0) */
368 unsigned char Rc; /* return code (is the request) */
369 } Request;
370 struct
371 { unsigned char Req; /* request (must be always 0) */
372 unsigned char Rc; /* return code (0x01) */
373 unsigned char name[BOARD_NAME_LENGTH];
374 } GetName;
375 struct
376 { unsigned char Req; /* request (must be always 0) */
377 unsigned char Rc; /* return code (0x02) */
378 unsigned long serial; /* serial number */
379 } GetSerial;
380 struct
381 { unsigned char Req; /* request (must be always 0) */
382 unsigned char Rc; /* return code (0x02) */
383 unsigned long lineIdx;/* line, 0 if card has only one */
384 } GetLineIdx;
385 struct
386 { unsigned char Req; /* request (must be always 0) */
387 unsigned char Rc; /* return code (0x02) */
388 unsigned long cardtype;/* card type */
389 } GetCardType;
390 struct
391 { unsigned short command;/* command = 0x0300 */
392 unsigned short dummy; /* not used */
393 IDI_CALL callback;/* routine to call back */
394 ENTITY *contxt; /* ptr to entity to use */
395 } PostCall;
396 struct
397 { unsigned char Req; /* request (must be always 0) */
398 unsigned char Rc; /* return code (0x04) */
399 unsigned char pcm[1]; /* buffer (a pc_maint struct) */
400 } GetXlog;
401 struct
402 { unsigned char Req; /* request (must be always 0) */
403 unsigned char Rc; /* return code (0x05) */
404 unsigned short features;/* feature defines see below */
405 } GetFeatures;
406 SERIAL_HOOK SerialHook;
407/* Added for DIVA USB */
408 struct
409 { unsigned char Req;
410 unsigned char Rc;
411 USB_SEND_REQ UsbSendRequest; /* function in Diva Usb WDM driver in usb_os.c, */
412 /* called from usb_drv.c to send a message to our device */
413 /* eg UsbSendRequest (USB_PIPE_SIGNAL, USB_IPAC_START, 0, 0) ; */
414 USB_RECV_NOTIFY usb_recv; /* called from usb_os.c to pass a received message and ptr to IPAC */
415 /* on to usb_drv.c by a call to usb_recv(). */
416 USB_XMIT_NOTIFY usb_xmit; /* called from usb_os.c in DivaUSB.sys WDM to indicate a completed transmit */
417 /* to usb_drv.c by a call to usb_xmit(). */
418 USB_START_DEV UsbStartDevice; /* Start the USB Device, in usb_os.c */
419 IDI_CALL callback; /* routine to call back */
420 ENTITY *contxt; /* ptr to entity to use */
421 void ** ipac_ptr; /* pointer to struct IPAC in VxD */
422 } Usb_Msg_old;
423/* message used by WDM and VXD to pass pointers of function and IPAC* */
424 struct
425 { unsigned char Req;
426 unsigned char Rc;
427 USB_SEND_REQ pUsbSendRequest;/* function in Diva Usb WDM driver in usb_os.c, */
428 /* called from usb_drv.c to send a message to our device */
429 /* eg UsbSendRequest (USB_PIPE_SIGNAL, USB_IPAC_START, 0, 0) ; */
430 USB_RECV_NOTIFY p_usb_recv; /* called from usb_os.c to pass a received message and ptr to IPAC */
431 /* on to usb_drv.c by a call to usb_recv(). */
432 USB_XMIT_NOTIFY p_usb_xmit; /* called from usb_os.c in DivaUSB.sys WDM to indicate a completed transmit */
433 /* to usb_drv.c by a call to usb_xmit().*/
434 void *ipac_ptr; /* &Diva.ipac pointer to struct IPAC in VxD */
435 } Usb_Msg;
436 PORTDRV_HOOK PortdrvHook;
437 SLIENTRYPOINT_REQ sliEntryPointReq;
438 struct {
439 unsigned char Req;
440 unsigned char Rc;
441 diva_xdi_stream_interface_t info;
442 } xdi_stream_info;
443 struct {
444 unsigned char Req;
445 unsigned char Rc;
446 diva_xdi_get_extended_xdi_features_t info;
447 } xdi_extended_features;
448 struct {
449 unsigned char Req;
450 unsigned char Rc;
451 diva_xdi_get_adapter_sdram_bar_t info;
452 } xdi_sdram_bar;
453 struct {
454 unsigned char Req;
455 unsigned char Rc;
456 diva_xdi_get_capi_parameters_t info;
457 } xdi_capi_prms;
458 struct {
459 ENTITY e;
460 diva_didd_adapter_notify_t info;
461 } didd_notify;
462 struct {
463 ENTITY e;
464 diva_didd_add_adapter_t info;
465 } didd_add_adapter;
466 struct {
467 ENTITY e;
468 diva_didd_remove_adapter_t info;
469 } didd_remove_adapter;
470 struct {
471 ENTITY e;
472 diva_didd_read_adapter_array_t info;
473 } didd_read_adapter_array;
474 struct {
475 ENTITY e;
476 diva_didd_get_cfg_lib_ifc_t info;
477 } didd_get_cfg_lib_ifc;
478 struct {
479 unsigned char Req;
480 unsigned char Rc;
481 diva_xdi_get_logical_adapter_number_s_t info;
482 } xdi_logical_adapter_number;
483 struct {
484 unsigned char Req;
485 unsigned char Rc;
486 diva_xdi_dma_descriptor_operation_t info;
487 } xdi_dma_descriptor_operation;
488} IDI_SYNC_REQ;
489/******************************************************************************/
490#endif /* __DIVA_SYNC__H */
diff --git a/drivers/isdn/hardware/eicon/dqueue.c b/drivers/isdn/hardware/eicon/dqueue.c
new file mode 100644
index 000000000000..982258225174
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/dqueue.c
@@ -0,0 +1,110 @@
1/* $Id: dqueue.c,v 1.5 2003/04/12 21:40:49 schindler Exp $
2 *
3 * Driver for Eicon DIVA Server ISDN cards.
4 * User Mode IDI Interface
5 *
6 * Copyright 2000-2003 by Armin Schindler (mac@melware.de)
7 * Copyright 2000-2003 Cytronics & Melware (info@melware.de)
8 *
9 * This software may be used and distributed according to the terms
10 * of the GNU General Public License, incorporated herein by reference.
11 */
12
13#include "platform.h"
14#include "dqueue.h"
15
16int
17diva_data_q_init(diva_um_idi_data_queue_t * q,
18 int max_length, int max_segments)
19{
20 int i;
21
22 q->max_length = max_length;
23 q->segments = max_segments;
24
25 for (i = 0; i < q->segments; i++) {
26 q->data[i] = NULL;
27 q->length[i] = 0;
28 }
29 q->read = q->write = q->count = q->segment_pending = 0;
30
31 for (i = 0; i < q->segments; i++) {
32 if (!(q->data[i] = diva_os_malloc(0, q->max_length))) {
33 diva_data_q_finit(q);
34 return (-1);
35 }
36 }
37
38 return (0);
39}
40
41int diva_data_q_finit(diva_um_idi_data_queue_t * q)
42{
43 int i;
44
45 for (i = 0; i < q->segments; i++) {
46 if (q->data[i]) {
47 diva_os_free(0, q->data[i]);
48 }
49 q->data[i] = NULL;
50 q->length[i] = 0;
51 }
52 q->read = q->write = q->count = q->segment_pending = 0;
53
54 return (0);
55}
56
57int diva_data_q_get_max_length(const diva_um_idi_data_queue_t * q)
58{
59 return (q->max_length);
60}
61
62void *diva_data_q_get_segment4write(diva_um_idi_data_queue_t * q)
63{
64 if ((!q->segment_pending) && (q->count < q->segments)) {
65 q->segment_pending = 1;
66 return (q->data[q->write]);
67 }
68
69 return NULL;
70}
71
72void
73diva_data_q_ack_segment4write(diva_um_idi_data_queue_t * q, int length)
74{
75 if (q->segment_pending) {
76 q->length[q->write] = length;
77 q->count++;
78 q->write++;
79 if (q->write >= q->segments) {
80 q->write = 0;
81 }
82 q->segment_pending = 0;
83 }
84}
85
86const void *diva_data_q_get_segment4read(const diva_um_idi_data_queue_t *
87 q)
88{
89 if (q->count) {
90 return (q->data[q->read]);
91 }
92 return NULL;
93}
94
95int diva_data_q_get_segment_length(const diva_um_idi_data_queue_t * q)
96{
97 return (q->length[q->read]);
98}
99
100void diva_data_q_ack_segment4read(diva_um_idi_data_queue_t * q)
101{
102 if (q->count) {
103 q->length[q->read] = 0;
104 q->count--;
105 q->read++;
106 if (q->read >= q->segments) {
107 q->read = 0;
108 }
109 }
110}
diff --git a/drivers/isdn/hardware/eicon/dqueue.h b/drivers/isdn/hardware/eicon/dqueue.h
new file mode 100644
index 000000000000..72d21c967227
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/dqueue.h
@@ -0,0 +1,31 @@
1/* $Id: dqueue.h,v 1.1.2.2 2001/02/08 12:25:43 armin Exp $ */
2
3#ifndef _DIVA_USER_MODE_IDI_DATA_QUEUE_H__
4#define _DIVA_USER_MODE_IDI_DATA_QUEUE_H__
5
6#define DIVA_UM_IDI_MAX_MSGS 64
7
8typedef struct _diva_um_idi_data_queue {
9 int segments;
10 int max_length;
11 int read;
12 int write;
13 int count;
14 int segment_pending;
15 void *data[DIVA_UM_IDI_MAX_MSGS];
16 int length[DIVA_UM_IDI_MAX_MSGS];
17} diva_um_idi_data_queue_t;
18
19int diva_data_q_init(diva_um_idi_data_queue_t * q,
20 int max_length, int max_segments);
21int diva_data_q_finit(diva_um_idi_data_queue_t * q);
22int diva_data_q_get_max_length(const diva_um_idi_data_queue_t * q);
23void *diva_data_q_get_segment4write(diva_um_idi_data_queue_t * q);
24void diva_data_q_ack_segment4write(diva_um_idi_data_queue_t * q,
25 int length);
26const void *diva_data_q_get_segment4read(const diva_um_idi_data_queue_t *
27 q);
28int diva_data_q_get_segment_length(const diva_um_idi_data_queue_t * q);
29void diva_data_q_ack_segment4read(diva_um_idi_data_queue_t * q);
30
31#endif
diff --git a/drivers/isdn/hardware/eicon/dsp_defs.h b/drivers/isdn/hardware/eicon/dsp_defs.h
new file mode 100644
index 000000000000..b44950e06f32
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/dsp_defs.h
@@ -0,0 +1,304 @@
1
2/*
3 *
4 Copyright (c) Eicon Networks, 2002.
5 *
6 This source file is supplied for the use with
7 Eicon Networks range of DIVA Server Adapters.
8 *
9 Eicon File Revision : 2.1
10 *
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2, or (at your option)
14 any later version.
15 *
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
18 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 See the GNU General Public License for more details.
20 *
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26#ifndef DSP_DEFS_H_
27#define DSP_DEFS_H_
28#include "dspdids.h"
29/*---------------------------------------------------------------------------*/
30#define dsp_download_reserve_space(fp,length)
31/*****************************************************************************/
32/*
33 * OS file access abstraction layer
34 *
35 * I/O functions returns -1 on error, 0 on EOF
36 */
37#define OS_SEEK_SET 0
38#define OS_SEEK_CUR 1
39#define OS_SEEK_END 2
40struct _OsFileHandle_;
41typedef long ( * OsFileIo) (struct _OsFileHandle_ *handle,
42 void *buffer,
43 long size) ;
44typedef long ( * OsFileSeek)(struct _OsFileHandle_ *handle,
45 long position,
46 int mode) ;
47typedef long ( * OsCardLoad)(struct _OsFileHandle_ *handle,
48 long length,
49 void * *addr) ;
50typedef struct _OsFileHandle_
51{ void *sysFileDesc ;
52 unsigned long sysFileSize ;
53 OsFileIo sysFileRead ;
54 OsFileSeek sysFileSeek ;
55 void *sysLoadDesc ;
56 OsCardLoad sysCardLoad ;
57} OsFileHandle ;
58extern OsFileHandle *OsOpenFile (char *path_name) ;
59extern void OsCloseFile (OsFileHandle *fp) ;
60/*****************************************************************************/
61#define DSP_TELINDUS_FILE "dspdload.bin"
62/* special DSP file for BRI cards for Qsig and CornetN because of missing memory */
63#define DSP_QSIG_TELINDUS_FILE "dspdqsig.bin"
64#define DSP_MDM_TELINDUS_FILE "dspdvmdm.bin"
65#define DSP_FAX_TELINDUS_FILE "dspdvfax.bin"
66#define DSP_DIRECTORY_ENTRIES 64
67#define DSP_MEMORY_TYPE_EXTERNAL_DM 0
68#define DSP_MEMORY_TYPE_EXTERNAL_PM 1
69#define DSP_MEMORY_TYPE_INTERNAL_DM 2
70#define DSP_MEMORY_TYPE_INTERNAL_PM 3
71#define DSP_DOWNLOAD_FLAG_BOOTABLE 0x0001
72#define DSP_DOWNLOAD_FLAG_2181 0x0002
73#define DSP_DOWNLOAD_FLAG_TIMECRITICAL 0x0004
74#define DSP_DOWNLOAD_FLAG_COMPAND 0x0008
75#define DSP_MEMORY_BLOCK_COUNT 16
76#define DSP_SEGMENT_PM_FLAG 0x0001
77#define DSP_SEGMENT_SHARED_FLAG 0x0002
78#define DSP_SEGMENT_EXTERNAL_DM DSP_MEMORY_TYPE_EXTERNAL_DM
79#define DSP_SEGMENT_EXTERNAL_PM DSP_MEMORY_TYPE_EXTERNAL_PM
80#define DSP_SEGMENT_INTERNAL_DM DSP_MEMORY_TYPE_INTERNAL_DM
81#define DSP_SEGMENT_INTERNAL_PM DSP_MEMORY_TYPE_INTERNAL_PM
82#define DSP_SEGMENT_FIRST_RELOCATABLE 4
83#define DSP_DATA_BLOCK_PM_FLAG 0x0001
84#define DSP_DATA_BLOCK_DWORD_FLAG 0x0002
85#define DSP_DATA_BLOCK_RESOLVE_FLAG 0x0004
86#define DSP_RELOC_NONE 0x00
87#define DSP_RELOC_SEGMENT_MASK 0x3f
88#define DSP_RELOC_TYPE_MASK 0xc0
89#define DSP_RELOC_TYPE_0 0x00 /* relocation of address in DM word / high part of PM word */
90#define DSP_RELOC_TYPE_1 0x40 /* relocation of address in low part of PM data word */
91#define DSP_RELOC_TYPE_2 0x80 /* relocation of address in standard command */
92#define DSP_RELOC_TYPE_3 0xc0 /* relocation of address in call/jump on flag in */
93#define DSP_COMBIFILE_FORMAT_IDENTIFICATION_SIZE 48
94#define DSP_COMBIFILE_FORMAT_VERSION_BCD 0x0100
95#define DSP_FILE_FORMAT_IDENTIFICATION_SIZE 48
96#define DSP_FILE_FORMAT_VERSION_BCD 0x0100
97typedef struct tag_dsp_combifile_header
98{
99 char format_identification[DSP_COMBIFILE_FORMAT_IDENTIFICATION_SIZE];
100 word format_version_bcd;
101 word header_size;
102 word combifile_description_size;
103 word directory_entries;
104 word directory_size;
105 word download_count;
106 word usage_mask_size;
107} t_dsp_combifile_header;
108typedef struct tag_dsp_combifile_directory_entry
109{
110 word card_type_number;
111 word file_set_number;
112} t_dsp_combifile_directory_entry;
113typedef struct tag_dsp_file_header
114{
115 char format_identification[DSP_FILE_FORMAT_IDENTIFICATION_SIZE];
116 word format_version_bcd;
117 word download_id;
118 word download_flags;
119 word required_processing_power;
120 word interface_channel_count;
121 word header_size;
122 word download_description_size;
123 word memory_block_table_size;
124 word memory_block_count;
125 word segment_table_size;
126 word segment_count;
127 word symbol_table_size;
128 word symbol_count;
129 word total_data_size_dm;
130 word data_block_count_dm;
131 word total_data_size_pm;
132 word data_block_count_pm;
133} t_dsp_file_header;
134typedef struct tag_dsp_memory_block_desc
135{
136 word alias_memory_block;
137 word memory_type;
138 word address;
139 word size; /* DSP words */
140} t_dsp_memory_block_desc;
141typedef struct tag_dsp_segment_desc
142{
143 word memory_block;
144 word attributes;
145 word base;
146 word size;
147 word alignment; /* ==0 -> no other legal start address than base */
148} t_dsp_segment_desc;
149typedef struct tag_dsp_symbol_desc
150{
151 word symbol_id;
152 word segment;
153 word offset;
154 word size; /* DSP words */
155} t_dsp_symbol_desc;
156typedef struct tag_dsp_data_block_header
157{
158 word attributes;
159 word segment;
160 word offset;
161 word size; /* DSP words */
162} t_dsp_data_block_header;
163typedef struct tag_dsp_download_desc
164{
165 word download_id;
166 word download_flags;
167 word required_processing_power;
168 word interface_channel_count;
169 word excess_header_size;
170 word memory_block_count;
171 word segment_count;
172 word symbol_count;
173 word data_block_count_dm;
174 word data_block_count_pm;
175 byte * p_excess_header_data;
176 char * p_download_description;
177 t_dsp_memory_block_desc *p_memory_block_table;
178 t_dsp_segment_desc *p_segment_table;
179 t_dsp_symbol_desc *p_symbol_table;
180 word * p_data_blocks_dm;
181 word * p_data_blocks_pm;
182} t_dsp_desc;
183typedef struct tag_dsp_portable_download_desc /* be sure to keep native alignment for MAESTRA's */
184{
185 word download_id;
186 word download_flags;
187 word required_processing_power;
188 word interface_channel_count;
189 word excess_header_size;
190 word memory_block_count;
191 word segment_count;
192 word symbol_count;
193 word data_block_count_dm;
194 word data_block_count_pm;
195 dword p_excess_header_data;
196 dword p_download_description;
197 dword p_memory_block_table;
198 dword p_segment_table;
199 dword p_symbol_table;
200 dword p_data_blocks_dm;
201 dword p_data_blocks_pm;
202} t_dsp_portable_desc;
203#define DSP_DOWNLOAD_INDEX_KERNEL 0
204#define DSP30TX_DOWNLOAD_INDEX_KERNEL 1
205#define DSP30RX_DOWNLOAD_INDEX_KERNEL 2
206#define DSP_MAX_DOWNLOAD_COUNT 64
207#define DSP_DOWNLOAD_MAX_SEGMENTS 16
208#define DSP_UDATA_REQUEST_RECONFIGURE 0
209/*
210parameters:
211 <word> reconfigure delay (in 8kHz samples)
212 <word> reconfigure code
213 <byte> reconfigure hdlc preamble flags
214*/
215#define DSP_RECONFIGURE_TX_FLAG 0x8000
216#define DSP_RECONFIGURE_SHORT_TRAIN_FLAG 0x4000
217#define DSP_RECONFIGURE_ECHO_PROTECT_FLAG 0x2000
218#define DSP_RECONFIGURE_HDLC_FLAG 0x1000
219#define DSP_RECONFIGURE_SYNC_FLAG 0x0800
220#define DSP_RECONFIGURE_PROTOCOL_MASK 0x00ff
221#define DSP_RECONFIGURE_IDLE 0
222#define DSP_RECONFIGURE_V25 1
223#define DSP_RECONFIGURE_V21_CH2 2
224#define DSP_RECONFIGURE_V27_2400 3
225#define DSP_RECONFIGURE_V27_4800 4
226#define DSP_RECONFIGURE_V29_7200 5
227#define DSP_RECONFIGURE_V29_9600 6
228#define DSP_RECONFIGURE_V33_12000 7
229#define DSP_RECONFIGURE_V33_14400 8
230#define DSP_RECONFIGURE_V17_7200 9
231#define DSP_RECONFIGURE_V17_9600 10
232#define DSP_RECONFIGURE_V17_12000 11
233#define DSP_RECONFIGURE_V17_14400 12
234/*
235data indications if transparent framer
236 <byte> data 0
237 <byte> data 1
238 ...
239data indications if HDLC framer
240 <byte> data 0
241 <byte> data 1
242 ...
243 <byte> CRC 0
244 <byte> CRC 1
245 <byte> preamble flags
246*/
247#define DSP_UDATA_INDICATION_SYNC 0
248/*
249returns:
250 <word> time of sync (sampled from counter at 8kHz)
251*/
252#define DSP_UDATA_INDICATION_DCD_OFF 1
253/*
254returns:
255 <word> time of DCD off (sampled from counter at 8kHz)
256*/
257#define DSP_UDATA_INDICATION_DCD_ON 2
258/*
259returns:
260 <word> time of DCD on (sampled from counter at 8kHz)
261 <byte> connected norm
262 <word> connected options
263 <dword> connected speed (bit/s)
264*/
265#define DSP_UDATA_INDICATION_CTS_OFF 3
266/*
267returns:
268 <word> time of CTS off (sampled from counter at 8kHz)
269*/
270#define DSP_UDATA_INDICATION_CTS_ON 4
271/*
272returns:
273 <word> time of CTS on (sampled from counter at 8kHz)
274 <byte> connected norm
275 <word> connected options
276 <dword> connected speed (bit/s)
277*/
278#define DSP_CONNECTED_NORM_UNSPECIFIED 0
279#define DSP_CONNECTED_NORM_V21 1
280#define DSP_CONNECTED_NORM_V23 2
281#define DSP_CONNECTED_NORM_V22 3
282#define DSP_CONNECTED_NORM_V22_BIS 4
283#define DSP_CONNECTED_NORM_V32_BIS 5
284#define DSP_CONNECTED_NORM_V34 6
285#define DSP_CONNECTED_NORM_V8 7
286#define DSP_CONNECTED_NORM_BELL_212A 8
287#define DSP_CONNECTED_NORM_BELL_103 9
288#define DSP_CONNECTED_NORM_V29_LEASED_LINE 10
289#define DSP_CONNECTED_NORM_V33_LEASED_LINE 11
290#define DSP_CONNECTED_NORM_TFAST 12
291#define DSP_CONNECTED_NORM_V21_CH2 13
292#define DSP_CONNECTED_NORM_V27_TER 14
293#define DSP_CONNECTED_NORM_V29 15
294#define DSP_CONNECTED_NORM_V33 16
295#define DSP_CONNECTED_NORM_V17 17
296#define DSP_CONNECTED_OPTION_TRELLIS 0x0001
297/*---------------------------------------------------------------------------*/
298extern char *dsp_read_file (OsFileHandle *fp,
299 word card_type_number,
300 word *p_dsp_download_count,
301 t_dsp_desc *p_dsp_download_table,
302 t_dsp_portable_desc *p_dsp_portable_download_table) ;
303/*---------------------------------------------------------------------------*/
304#endif /* DSP_DEFS_H_ */
diff --git a/drivers/isdn/hardware/eicon/dsp_tst.h b/drivers/isdn/hardware/eicon/dsp_tst.h
new file mode 100644
index 000000000000..a6021e5b1ae7
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/dsp_tst.h
@@ -0,0 +1,47 @@
1/* $Id: dsp_tst.h,v 1.1.2.2 2001/02/08 12:25:43 armin Exp $ */
2
3#ifndef __DIVA_PRI_HOST_TEST_DSPS_H__
4#define __DIVA_PRI_HOST_TEST_DSPS_H__
5
6/*
7 DSP registers on maestra pri
8 */
9#define DSP1_PORT (0x00)
10#define DSP2_PORT (0x8)
11#define DSP3_PORT (0x800)
12#define DSP4_PORT (0x808)
13#define DSP5_PORT (0x810)
14#define DSP6_PORT (0x818)
15#define DSP7_PORT (0x820)
16#define DSP8_PORT (0x828)
17#define DSP9_PORT (0x830)
18#define DSP10_PORT (0x840)
19#define DSP11_PORT (0x848)
20#define DSP12_PORT (0x850)
21#define DSP13_PORT (0x858)
22#define DSP14_PORT (0x860)
23#define DSP15_PORT (0x868)
24#define DSP16_PORT (0x870)
25#define DSP17_PORT (0x1000)
26#define DSP18_PORT (0x1008)
27#define DSP19_PORT (0x1010)
28#define DSP20_PORT (0x1018)
29#define DSP21_PORT (0x1020)
30#define DSP22_PORT (0x1028)
31#define DSP23_PORT (0x1030)
32#define DSP24_PORT (0x1040)
33#define DSP25_PORT (0x1048)
34#define DSP26_PORT (0x1050)
35#define DSP27_PORT (0x1058)
36#define DSP28_PORT (0x1060)
37#define DSP29_PORT (0x1068)
38#define DSP30_PORT (0x1070)
39#define DSP_ADR_OFFS 0x80
40
41/*------------------------------------------------------------------
42 Dsp related definitions
43 ------------------------------------------------------------------ */
44#define DSP_SIGNATURE_PROBE_WORD 0x5a5a
45#define dsp_make_address_ex(pm,address) ((word)((pm) ? (address) : (address) + 0x4000))
46
47#endif
diff --git a/drivers/isdn/hardware/eicon/dspdids.h b/drivers/isdn/hardware/eicon/dspdids.h
new file mode 100644
index 000000000000..ebe131a53b9c
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/dspdids.h
@@ -0,0 +1,75 @@
1
2/*
3 *
4 Copyright (c) Eicon Networks, 2002.
5 *
6 This source file is supplied for the use with
7 Eicon Networks range of DIVA Server Adapters.
8 *
9 Eicon File Revision : 2.1
10 *
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2, or (at your option)
14 any later version.
15 *
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
18 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 See the GNU General Public License for more details.
20 *
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26#ifndef DSPDIDS_H_
27#define DSPDIDS_H_
28/*---------------------------------------------------------------------------*/
29#define DSP_DID_INVALID 0
30#define DSP_DID_DIVA 1
31#define DSP_DID_DIVA_PRO 2
32#define DSP_DID_DIVA_PRO_20 3
33#define DSP_DID_DIVA_PRO_PCCARD 4
34#define DSP_DID_DIVA_SERVER_BRI_1M 5
35#define DSP_DID_DIVA_SERVER_BRI_2M 6
36#define DSP_DID_DIVA_SERVER_PRI_2M_TX 7
37#define DSP_DID_DIVA_SERVER_PRI_2M_RX 8
38#define DSP_DID_DIVA_SERVER_PRI_30M 9
39#define DSP_DID_TASK_HSCX 100
40#define DSP_DID_TASK_HSCX_PRI_2M_TX 101
41#define DSP_DID_TASK_HSCX_PRI_2M_RX 102
42#define DSP_DID_TASK_V110KRNL 200
43#define DSP_DID_OVERLAY_V1100 201
44#define DSP_DID_OVERLAY_V1101 202
45#define DSP_DID_OVERLAY_V1102 203
46#define DSP_DID_OVERLAY_V1103 204
47#define DSP_DID_OVERLAY_V1104 205
48#define DSP_DID_OVERLAY_V1105 206
49#define DSP_DID_OVERLAY_V1106 207
50#define DSP_DID_OVERLAY_V1107 208
51#define DSP_DID_OVERLAY_V1108 209
52#define DSP_DID_OVERLAY_V1109 210
53#define DSP_DID_TASK_V110_PRI_2M_TX 220
54#define DSP_DID_TASK_V110_PRI_2M_RX 221
55#define DSP_DID_TASK_MODEM 300
56#define DSP_DID_TASK_FAX05 400
57#define DSP_DID_TASK_VOICE 500
58#define DSP_DID_TASK_TIKRNL81 600
59#define DSP_DID_OVERLAY_DIAL 601
60#define DSP_DID_OVERLAY_V22 602
61#define DSP_DID_OVERLAY_V32 603
62#define DSP_DID_OVERLAY_FSK 604
63#define DSP_DID_OVERLAY_FAX 605
64#define DSP_DID_OVERLAY_VXX 606
65#define DSP_DID_OVERLAY_V8 607
66#define DSP_DID_OVERLAY_INFO 608
67#define DSP_DID_OVERLAY_V34 609
68#define DSP_DID_OVERLAY_DFX 610
69#define DSP_DID_PARTIAL_OVERLAY_DIAL 611
70#define DSP_DID_PARTIAL_OVERLAY_FSK 612
71#define DSP_DID_PARTIAL_OVERLAY_FAX 613
72#define DSP_DID_TASK_TIKRNL05 700
73/*---------------------------------------------------------------------------*/
74#endif
75/*---------------------------------------------------------------------------*/
diff --git a/drivers/isdn/hardware/eicon/dsrv4bri.h b/drivers/isdn/hardware/eicon/dsrv4bri.h
new file mode 100644
index 000000000000..732d22dfe4a5
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/dsrv4bri.h
@@ -0,0 +1,40 @@
1
2/*
3 *
4 Copyright (c) Eicon Networks, 2002.
5 *
6 This source file is supplied for the use with
7 Eicon Networks range of DIVA Server Adapters.
8 *
9 Eicon File Revision : 2.1
10 *
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2, or (at your option)
14 any later version.
15 *
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
18 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 See the GNU General Public License for more details.
20 *
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26#ifndef __DIVA_XDI_DSRV_4_BRI_INC__
27#define __DIVA_XDI_DSRV_4_BRI_INC__
28/*
29 * Some special registers in the PLX 9054
30 */
31#define PLX9054_P2LDBELL 0x60
32#define PLX9054_L2PDBELL 0x64
33#define PLX9054_INTCSR 0x69
34#define PLX9054_INT_ENABLE 0x09
35#define PLX9054_SOFT_RESET 0x4000
36#define PLX9054_RELOAD_EEPROM 0x2000
37#define DIVA_4BRI_REVISION(__x__) (((__x__)->cardType == CARDTYPE_DIVASRV_Q_8M_V2_PCI) || ((__x__)->cardType == CARDTYPE_DIVASRV_VOICE_Q_8M_V2_PCI) || ((__x__)->cardType == CARDTYPE_DIVASRV_B_2M_V2_PCI) || ((__x__)->cardType == CARDTYPE_DIVASRV_B_2F_PCI) || ((__x__)->cardType == CARDTYPE_DIVASRV_VOICE_B_2M_V2_PCI))
38void diva_os_set_qBri_functions (PISDN_ADAPTER IoAdapter);
39void diva_os_set_qBri2_functions (PISDN_ADAPTER IoAdapter);
40#endif
diff --git a/drivers/isdn/hardware/eicon/dsrv_bri.h b/drivers/isdn/hardware/eicon/dsrv_bri.h
new file mode 100644
index 000000000000..f38ebbe53332
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/dsrv_bri.h
@@ -0,0 +1,37 @@
1
2/*
3 *
4 Copyright (c) Eicon Networks, 2002.
5 *
6 This source file is supplied for the use with
7 Eicon Networks range of DIVA Server Adapters.
8 *
9 Eicon File Revision : 2.1
10 *
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2, or (at your option)
14 any later version.
15 *
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
18 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 See the GNU General Public License for more details.
20 *
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26#ifndef __DIVA_XDI_DSRV_BRI_INC__
27#define __DIVA_XDI_DSRV_BRI_INC__
28/*
29 Functions exported from os dependent part of
30 BRI card configuration and used in
31 OS independed part
32 */
33/*
34 Prepare OS dependent part of BRI functions
35 */
36void diva_os_prepare_maestra_functions (PISDN_ADAPTER IoAdapter);
37#endif
diff --git a/drivers/isdn/hardware/eicon/dsrv_pri.h b/drivers/isdn/hardware/eicon/dsrv_pri.h
new file mode 100644
index 000000000000..861182666c89
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/dsrv_pri.h
@@ -0,0 +1,38 @@
1
2/*
3 *
4 Copyright (c) Eicon Networks, 2002.
5 *
6 This source file is supplied for the use with
7 Eicon Networks range of DIVA Server Adapters.
8 *
9 Eicon File Revision : 2.1
10 *
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2, or (at your option)
14 any later version.
15 *
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
18 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 See the GNU General Public License for more details.
20 *
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26#ifndef __DIVA_XDI_DSRV_PRI_INC__
27#define __DIVA_XDI_DSRV_PRI_INC__
28/*
29 Functions exported from os dependent part of
30 PRI card configuration and used in
31 OS independed part
32 */
33/*
34 Prepare OS dependent part of PRI/PRI Rev.2 functions
35 */
36void diva_os_prepare_pri_functions (PISDN_ADAPTER IoAdapter);
37void diva_os_prepare_pri2_functions (PISDN_ADAPTER IoAdapter);
38#endif
diff --git a/drivers/isdn/hardware/eicon/entity.h b/drivers/isdn/hardware/eicon/entity.h
new file mode 100644
index 000000000000..16252cf164bb
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/entity.h
@@ -0,0 +1,28 @@
1/* $Id: entity.h,v 1.4 2004/03/21 17:26:01 armin Exp $ */
2
3#ifndef __DIVAS_USER_MODE_IDI_ENTITY__
4#define __DIVAS_USER_MODE_IDI_ENTITY__
5
6#define DIVA_UM_IDI_RC_PENDING 0x00000001
7#define DIVA_UM_IDI_REMOVE_PENDING 0x00000002
8#define DIVA_UM_IDI_TX_FLOW_CONTROL 0x00000004
9#define DIVA_UM_IDI_REMOVED 0x00000008
10#define DIVA_UM_IDI_ASSIGN_PENDING 0x00000010
11
12typedef struct _divas_um_idi_entity {
13 struct list_head link;
14 diva_um_idi_adapter_t* adapter; /* Back to adapter */
15 ENTITY e;
16 void* os_ref;
17 dword status;
18 void* os_context;
19 int rc_count;
20 diva_um_idi_data_queue_t data; /* definad by user 1 ... MAX */
21 diva_um_idi_data_queue_t rc; /* two entries */
22 BUFFERS XData;
23 BUFFERS RData;
24 byte buffer[2048+512];
25} divas_um_idi_entity_t;
26
27
28#endif
diff --git a/drivers/isdn/hardware/eicon/helpers.h b/drivers/isdn/hardware/eicon/helpers.h
new file mode 100644
index 000000000000..b2123119e430
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/helpers.h
@@ -0,0 +1,51 @@
1
2/*
3 *
4 Copyright (c) Eicon Networks, 2002.
5 *
6 This source file is supplied for the use with
7 Eicon Networks range of DIVA Server Adapters.
8 *
9 Eicon File Revision : 2.1
10 *
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2, or (at your option)
14 any later version.
15 *
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
18 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 See the GNU General Public License for more details.
20 *
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26#ifndef __DIVA_XDI_CARD_CONFIG_HELPERS_INC__
27#define __DIVA_XDI_CARD_CONFIG_HELPERS_INC__
28dword diva_get_protocol_file_features (byte* File,
29 int offset,
30 char *IdStringBuffer,
31 dword IdBufferSize);
32void diva_configure_protocol (PISDN_ADAPTER IoAdapter);
33/*
34 Low level file access system abstraction
35 */
36/* -------------------------------------------------------------------------
37 Access to single file
38 Return pointer to the image of the requested file,
39 write image length to 'FileLength'
40 ------------------------------------------------------------------------- */
41void *xdiLoadFile (char *FileName, dword *FileLength, unsigned long MaxLoadSize) ;
42/* -------------------------------------------------------------------------
43 Dependent on the protocol settings does read return pointer
44 to the image of appropriate protocol file
45 ------------------------------------------------------------------------- */
46void *xdiLoadArchive (PISDN_ADAPTER IoAdapter, dword *FileLength, unsigned long MaxLoadSize) ;
47/* --------------------------------------------------------------------------
48 Free all system resources accessed by xdiLoadFile and xdiLoadArchive
49 -------------------------------------------------------------------------- */
50void xdiFreeFile (void* handle);
51#endif
diff --git a/drivers/isdn/hardware/eicon/idifunc.c b/drivers/isdn/hardware/eicon/idifunc.c
new file mode 100644
index 000000000000..4cbc68cf4dba
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/idifunc.c
@@ -0,0 +1,267 @@
1/* $Id: idifunc.c,v 1.14.4.4 2004/08/28 20:03:53 armin Exp $
2 *
3 * Driver for Eicon DIVA Server ISDN cards.
4 * User Mode IDI Interface
5 *
6 * Copyright 2000-2003 by Armin Schindler (mac@melware.de)
7 * Copyright 2000-2003 Cytronics & Melware (info@melware.de)
8 *
9 * This software may be used and distributed according to the terms
10 * of the GNU General Public License, incorporated herein by reference.
11 */
12
13#include "platform.h"
14#include "di_defs.h"
15#include "divasync.h"
16#include "um_xdi.h"
17#include "um_idi.h"
18
19#define DBG_MINIMUM (DL_LOG + DL_FTL + DL_ERR)
20#define DBG_DEFAULT (DBG_MINIMUM + DL_XLOG + DL_REG)
21
22extern char *DRIVERRELEASE_IDI;
23
24extern void DIVA_DIDD_Read(void *, int);
25extern int diva_user_mode_idi_create_adapter(const DESCRIPTOR *, int);
26extern void diva_user_mode_idi_remove_adapter(int);
27
28static dword notify_handle;
29static DESCRIPTOR DAdapter;
30static DESCRIPTOR MAdapter;
31
32static void no_printf(unsigned char *x, ...)
33{
34 /* dummy debug function */
35}
36
37#include "debuglib.c"
38
39/*
40 * stop debug
41 */
42static void stop_dbg(void)
43{
44 DbgDeregister();
45 memset(&MAdapter, 0, sizeof(MAdapter));
46 dprintf = no_printf;
47}
48
49typedef struct _udiva_card {
50 struct list_head list;
51 int Id;
52 DESCRIPTOR d;
53} udiva_card;
54
55static LIST_HEAD(cards);
56static diva_os_spin_lock_t ll_lock;
57
58/*
59 * find card in list
60 */
61static udiva_card *find_card_in_list(DESCRIPTOR * d)
62{
63 udiva_card *card;
64 struct list_head *tmp;
65 diva_os_spin_lock_magic_t old_irql;
66
67 diva_os_enter_spin_lock(&ll_lock, &old_irql, "find card");
68 list_for_each(tmp, &cards) {
69 card = list_entry(tmp, udiva_card, list);
70 if (card->d.request == d->request) {
71 diva_os_leave_spin_lock(&ll_lock, &old_irql,
72 "find card");
73 return (card);
74 }
75 }
76 diva_os_leave_spin_lock(&ll_lock, &old_irql, "find card");
77 return ((udiva_card *) NULL);
78}
79
80/*
81 * new card
82 */
83static void um_new_card(DESCRIPTOR * d)
84{
85 int adapter_nr = 0;
86 udiva_card *card = NULL;
87 IDI_SYNC_REQ sync_req;
88 diva_os_spin_lock_magic_t old_irql;
89
90 if (!(card = diva_os_malloc(0, sizeof(udiva_card)))) {
91 DBG_ERR(("cannot get buffer for card"));
92 return;
93 }
94 memcpy(&card->d, d, sizeof(DESCRIPTOR));
95 sync_req.xdi_logical_adapter_number.Req = 0;
96 sync_req.xdi_logical_adapter_number.Rc =
97 IDI_SYNC_REQ_XDI_GET_LOGICAL_ADAPTER_NUMBER;
98 card->d.request((ENTITY *) & sync_req);
99 adapter_nr =
100 sync_req.xdi_logical_adapter_number.info.logical_adapter_number;
101 card->Id = adapter_nr;
102 if (!(diva_user_mode_idi_create_adapter(d, adapter_nr))) {
103 diva_os_enter_spin_lock(&ll_lock, &old_irql, "add card");
104 list_add_tail(&card->list, &cards);
105 diva_os_leave_spin_lock(&ll_lock, &old_irql, "add card");
106 } else {
107 DBG_ERR(("could not create user mode idi card %d",
108 adapter_nr));
109 }
110}
111
112/*
113 * remove card
114 */
115static void um_remove_card(DESCRIPTOR * d)
116{
117 diva_os_spin_lock_magic_t old_irql;
118 udiva_card *card = NULL;
119
120 if (!(card = find_card_in_list(d))) {
121 DBG_ERR(("cannot find card to remove"));
122 return;
123 }
124 diva_user_mode_idi_remove_adapter(card->Id);
125 diva_os_enter_spin_lock(&ll_lock, &old_irql, "remove card");
126 list_del(&card->list);
127 diva_os_leave_spin_lock(&ll_lock, &old_irql, "remove card");
128 DBG_LOG(("idi proc entry removed for card %d", card->Id));
129 diva_os_free(0, card);
130}
131
132/*
133 * remove all adapter
134 */
135static void DIVA_EXIT_FUNCTION remove_all_idi_proc(void)
136{
137 udiva_card *card;
138 diva_os_spin_lock_magic_t old_irql;
139
140rescan:
141 diva_os_enter_spin_lock(&ll_lock, &old_irql, "remove all");
142 if (!list_empty(&cards)) {
143 card = list_entry(cards.next, udiva_card, list);
144 list_del(&card->list);
145 diva_os_leave_spin_lock(&ll_lock, &old_irql, "remove all");
146 diva_user_mode_idi_remove_adapter(card->Id);
147 diva_os_free(0, card);
148 goto rescan;
149 }
150 diva_os_leave_spin_lock(&ll_lock, &old_irql, "remove all");
151}
152
153/*
154 * DIDD notify callback
155 */
156static void *didd_callback(void *context, DESCRIPTOR * adapter,
157 int removal)
158{
159 if (adapter->type == IDI_DADAPTER) {
160 DBG_ERR(("Notification about IDI_DADAPTER change ! Oops."));
161 return (NULL);
162 } else if (adapter->type == IDI_DIMAINT) {
163 if (removal) {
164 stop_dbg();
165 } else {
166 memcpy(&MAdapter, adapter, sizeof(MAdapter));
167 dprintf = (DIVA_DI_PRINTF) MAdapter.request;
168 DbgRegister("User IDI", DRIVERRELEASE_IDI, DBG_DEFAULT);
169 }
170 } else if ((adapter->type > 0) && (adapter->type < 16)) { /* IDI Adapter */
171 if (removal) {
172 um_remove_card(adapter);
173 } else {
174 um_new_card(adapter);
175 }
176 }
177 return (NULL);
178}
179
180/*
181 * connect DIDD
182 */
183static int DIVA_INIT_FUNCTION connect_didd(void)
184{
185 int x = 0;
186 int dadapter = 0;
187 IDI_SYNC_REQ req;
188 DESCRIPTOR DIDD_Table[MAX_DESCRIPTORS];
189
190 DIVA_DIDD_Read(DIDD_Table, sizeof(DIDD_Table));
191
192 for (x = 0; x < MAX_DESCRIPTORS; x++) {
193 if (DIDD_Table[x].type == IDI_DADAPTER) { /* DADAPTER found */
194 dadapter = 1;
195 memcpy(&DAdapter, &DIDD_Table[x], sizeof(DAdapter));
196 req.didd_notify.e.Req = 0;
197 req.didd_notify.e.Rc =
198 IDI_SYNC_REQ_DIDD_REGISTER_ADAPTER_NOTIFY;
199 req.didd_notify.info.callback = (void *)didd_callback;
200 req.didd_notify.info.context = NULL;
201 DAdapter.request((ENTITY *) & req);
202 if (req.didd_notify.e.Rc != 0xff) {
203 stop_dbg();
204 return (0);
205 }
206 notify_handle = req.didd_notify.info.handle;
207 } else if (DIDD_Table[x].type == IDI_DIMAINT) { /* MAINT found */
208 memcpy(&MAdapter, &DIDD_Table[x], sizeof(DAdapter));
209 dprintf = (DIVA_DI_PRINTF) MAdapter.request;
210 DbgRegister("User IDI", DRIVERRELEASE_IDI, DBG_DEFAULT);
211 } else if ((DIDD_Table[x].type > 0)
212 && (DIDD_Table[x].type < 16)) { /* IDI Adapter found */
213 um_new_card(&DIDD_Table[x]);
214 }
215 }
216
217 if (!dadapter) {
218 stop_dbg();
219 }
220
221 return (dadapter);
222}
223
224/*
225 * Disconnect from DIDD
226 */
227static void DIVA_EXIT_FUNCTION disconnect_didd(void)
228{
229 IDI_SYNC_REQ req;
230
231 stop_dbg();
232
233 req.didd_notify.e.Req = 0;
234 req.didd_notify.e.Rc = IDI_SYNC_REQ_DIDD_REMOVE_ADAPTER_NOTIFY;
235 req.didd_notify.info.handle = notify_handle;
236 DAdapter.request((ENTITY *) & req);
237}
238
239/*
240 * init
241 */
242int DIVA_INIT_FUNCTION idifunc_init(void)
243{
244 diva_os_initialize_spin_lock(&ll_lock, "idifunc");
245
246 if (diva_user_mode_idi_init()) {
247 DBG_ERR(("init: init failed."));
248 return (0);
249 }
250
251 if (!connect_didd()) {
252 diva_user_mode_idi_finit();
253 DBG_ERR(("init: failed to connect to DIDD."));
254 return (0);
255 }
256 return (1);
257}
258
259/*
260 * finit
261 */
262void DIVA_EXIT_FUNCTION idifunc_finit(void)
263{
264 diva_user_mode_idi_finit();
265 disconnect_didd();
266 remove_all_idi_proc();
267}
diff --git a/drivers/isdn/hardware/eicon/io.c b/drivers/isdn/hardware/eicon/io.c
new file mode 100644
index 000000000000..4a27e230b0a5
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/io.c
@@ -0,0 +1,852 @@
1
2/*
3 *
4 Copyright (c) Eicon Networks, 2002.
5 *
6 This source file is supplied for the use with
7 Eicon Networks range of DIVA Server Adapters.
8 *
9 Eicon File Revision : 2.1
10 *
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2, or (at your option)
14 any later version.
15 *
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
18 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 See the GNU General Public License for more details.
20 *
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26#include "platform.h"
27#include "di_defs.h"
28#include "pc.h"
29#include "pr_pc.h"
30#include "divasync.h"
31#define MIPS_SCOM
32#include "pkmaint.h" /* pc_main.h, packed in os-dependent fashion */
33#include "di.h"
34#include "mi_pc.h"
35#include "io.h"
36extern ADAPTER * adapter[MAX_ADAPTER];
37extern PISDN_ADAPTER IoAdapters[MAX_ADAPTER];
38void request (PISDN_ADAPTER, ENTITY *);
39static void pcm_req (PISDN_ADAPTER, ENTITY *);
40/* --------------------------------------------------------------------------
41 local functions
42 -------------------------------------------------------------------------- */
43#define ReqFunc(N) \
44static void Request##N(ENTITY *e) \
45{ if ( IoAdapters[N] ) (* IoAdapters[N]->DIRequest)(IoAdapters[N], e) ; }
46ReqFunc(0)
47ReqFunc(1)
48ReqFunc(2)
49ReqFunc(3)
50ReqFunc(4)
51ReqFunc(5)
52ReqFunc(6)
53ReqFunc(7)
54ReqFunc(8)
55ReqFunc(9)
56ReqFunc(10)
57ReqFunc(11)
58ReqFunc(12)
59ReqFunc(13)
60ReqFunc(14)
61ReqFunc(15)
62IDI_CALL Requests[MAX_ADAPTER] =
63{ &Request0, &Request1, &Request2, &Request3,
64 &Request4, &Request5, &Request6, &Request7,
65 &Request8, &Request9, &Request10, &Request11,
66 &Request12, &Request13, &Request14, &Request15
67};
68/*****************************************************************************/
69/*
70 This array should indicate all new services, that this version of XDI
71 is able to provide to his clients
72 */
73static byte extended_xdi_features[DIVA_XDI_EXTENDED_FEATURES_MAX_SZ+1] = {
74 (DIVA_XDI_EXTENDED_FEATURES_VALID |
75 DIVA_XDI_EXTENDED_FEATURE_SDRAM_BAR |
76 DIVA_XDI_EXTENDED_FEATURE_CAPI_PRMS |
77#if defined(DIVA_IDI_RX_DMA)
78 DIVA_XDI_EXTENDED_FEATURE_CMA |
79 DIVA_XDI_EXTENDED_FEATURE_RX_DMA |
80 DIVA_XDI_EXTENDED_FEATURE_MANAGEMENT_DMA |
81#endif
82 DIVA_XDI_EXTENDED_FEATURE_NO_CANCEL_RC),
83 0
84};
85/*****************************************************************************/
86void
87dump_xlog_buffer (PISDN_ADAPTER IoAdapter, Xdesc *xlogDesc)
88{
89 dword logLen ;
90 word *Xlog = xlogDesc->buf ;
91 word logCnt = xlogDesc->cnt ;
92 word logOut = xlogDesc->out / sizeof(*Xlog) ;
93 DBG_FTL(("%s: ************* XLOG recovery (%d) *************",
94 &IoAdapter->Name[0], (int)logCnt))
95 DBG_FTL(("Microcode: %s", &IoAdapter->ProtocolIdString[0]))
96 for ( ; logCnt > 0 ; --logCnt )
97 {
98 if ( !GET_WORD(&Xlog[logOut]) )
99 {
100 if ( --logCnt == 0 )
101 break ;
102 logOut = 0 ;
103 }
104 if ( GET_WORD(&Xlog[logOut]) <= (logOut * sizeof(*Xlog)) )
105 {
106 if ( logCnt > 2 )
107 {
108 DBG_FTL(("Possibly corrupted XLOG: %d entries left",
109 (int)logCnt))
110 }
111 break ;
112 }
113 logLen = (dword)(GET_WORD(&Xlog[logOut]) - (logOut * sizeof(*Xlog))) ;
114 DBG_FTL_MXLOG(( (char *)&Xlog[logOut + 1], (dword)(logLen - 2) ))
115 logOut = (GET_WORD(&Xlog[logOut]) + 1) / sizeof(*Xlog) ;
116 }
117 DBG_FTL(("%s: ***************** end of XLOG *****************",
118 &IoAdapter->Name[0]))
119}
120/*****************************************************************************/
121#if defined(XDI_USE_XLOG)
122static char *(ExceptionCauseTable[]) =
123{
124 "Interrupt",
125 "TLB mod /IBOUND",
126 "TLB load /DBOUND",
127 "TLB store",
128 "Address error load",
129 "Address error store",
130 "Instruction load bus error",
131 "Data load/store bus error",
132 "Syscall",
133 "Breakpoint",
134 "Reverd instruction",
135 "Coprocessor unusable",
136 "Overflow",
137 "TRAP",
138 "VCEI",
139 "Floating Point Exception",
140 "CP2",
141 "Reserved 17",
142 "Reserved 18",
143 "Reserved 19",
144 "Reserved 20",
145 "Reserved 21",
146 "Reserved 22",
147 "WATCH",
148 "Reserved 24",
149 "Reserved 25",
150 "Reserved 26",
151 "Reserved 27",
152 "Reserved 28",
153 "Reserved 29",
154 "Reserved 30",
155 "VCED"
156} ;
157#endif
158void
159dump_trap_frame (PISDN_ADAPTER IoAdapter, byte __iomem *exceptionFrame)
160{
161 MP_XCPTC __iomem *xcept = (MP_XCPTC __iomem *)exceptionFrame ;
162 dword __iomem *regs;
163 regs = &xcept->regs[0] ;
164 DBG_FTL(("%s: ***************** CPU TRAPPED *****************",
165 &IoAdapter->Name[0]))
166 DBG_FTL(("Microcode: %s", &IoAdapter->ProtocolIdString[0]))
167 DBG_FTL(("Cause: %s",
168 ExceptionCauseTable[(READ_DWORD(&xcept->cr) & 0x0000007c) >> 2]))
169 DBG_FTL(("sr 0x%08x cr 0x%08x epc 0x%08x vaddr 0x%08x",
170 READ_DWORD(&xcept->sr), READ_DWORD(&xcept->cr),
171 READ_DWORD(&xcept->epc), READ_DWORD(&xcept->vaddr)))
172 DBG_FTL(("zero 0x%08x at 0x%08x v0 0x%08x v1 0x%08x",
173 READ_DWORD(&regs[ 0]), READ_DWORD(&regs[ 1]),
174 READ_DWORD(&regs[ 2]), READ_DWORD(&regs[ 3])))
175 DBG_FTL(("a0 0x%08x a1 0x%08x a2 0x%08x a3 0x%08x",
176 READ_DWORD(&regs[ 4]), READ_DWORD(&regs[ 5]),
177 READ_DWORD(&regs[ 6]), READ_DWORD(&regs[ 7])))
178 DBG_FTL(("t0 0x%08x t1 0x%08x t2 0x%08x t3 0x%08x",
179 READ_DWORD(&regs[ 8]), READ_DWORD(&regs[ 9]),
180 READ_DWORD(&regs[10]), READ_DWORD(&regs[11])))
181 DBG_FTL(("t4 0x%08x t5 0x%08x t6 0x%08x t7 0x%08x",
182 READ_DWORD(&regs[12]), READ_DWORD(&regs[13]),
183 READ_DWORD(&regs[14]), READ_DWORD(&regs[15])))
184 DBG_FTL(("s0 0x%08x s1 0x%08x s2 0x%08x s3 0x%08x",
185 READ_DWORD(&regs[16]), READ_DWORD(&regs[17]),
186 READ_DWORD(&regs[18]), READ_DWORD(&regs[19])))
187 DBG_FTL(("s4 0x%08x s5 0x%08x s6 0x%08x s7 0x%08x",
188 READ_DWORD(&regs[20]), READ_DWORD(&regs[21]),
189 READ_DWORD(&regs[22]), READ_DWORD(&regs[23])))
190 DBG_FTL(("t8 0x%08x t9 0x%08x k0 0x%08x k1 0x%08x",
191 READ_DWORD(&regs[24]), READ_DWORD(&regs[25]),
192 READ_DWORD(&regs[26]), READ_DWORD(&regs[27])))
193 DBG_FTL(("gp 0x%08x sp 0x%08x s8 0x%08x ra 0x%08x",
194 READ_DWORD(&regs[28]), READ_DWORD(&regs[29]),
195 READ_DWORD(&regs[30]), READ_DWORD(&regs[31])))
196 DBG_FTL(("md 0x%08x|%08x resvd 0x%08x class 0x%08x",
197 READ_DWORD(&xcept->mdhi), READ_DWORD(&xcept->mdlo),
198 READ_DWORD(&xcept->reseverd), READ_DWORD(&xcept->xclass)))
199}
200/* --------------------------------------------------------------------------
201 Real XDI Request function
202 -------------------------------------------------------------------------- */
203void request(PISDN_ADAPTER IoAdapter, ENTITY * e)
204{
205 byte i;
206 diva_os_spin_lock_magic_t irql;
207/*
208 * if the Req field in the entity structure is 0,
209 * we treat this request as a special function call
210 */
211 if ( !e->Req )
212 {
213 IDI_SYNC_REQ *syncReq = (IDI_SYNC_REQ *)e ;
214 switch (e->Rc)
215 {
216#if defined(DIVA_IDI_RX_DMA)
217 case IDI_SYNC_REQ_DMA_DESCRIPTOR_OPERATION: {
218 diva_xdi_dma_descriptor_operation_t* pI = \
219 &syncReq->xdi_dma_descriptor_operation.info;
220 if (!IoAdapter->dma_map) {
221 pI->operation = -1;
222 pI->descriptor_number = -1;
223 return;
224 }
225 diva_os_enter_spin_lock (&IoAdapter->data_spin_lock, &irql, "dma_op");
226 if (pI->operation == IDI_SYNC_REQ_DMA_DESCRIPTOR_ALLOC) {
227 pI->descriptor_number = diva_alloc_dma_map_entry (\
228 (struct _diva_dma_map_entry*)IoAdapter->dma_map);
229 if (pI->descriptor_number >= 0) {
230 dword dma_magic;
231 void* local_addr;
232 diva_get_dma_map_entry (\
233 (struct _diva_dma_map_entry*)IoAdapter->dma_map,
234 pI->descriptor_number,
235 &local_addr, &dma_magic);
236 pI->descriptor_address = local_addr;
237 pI->descriptor_magic = dma_magic;
238 pI->operation = 0;
239 } else {
240 pI->operation = -1;
241 }
242 } else if ((pI->operation == IDI_SYNC_REQ_DMA_DESCRIPTOR_FREE) &&
243 (pI->descriptor_number >= 0)) {
244 diva_free_dma_map_entry((struct _diva_dma_map_entry*)IoAdapter->dma_map,
245 pI->descriptor_number);
246 pI->descriptor_number = -1;
247 pI->operation = 0;
248 } else {
249 pI->descriptor_number = -1;
250 pI->operation = -1;
251 }
252 diva_os_leave_spin_lock (&IoAdapter->data_spin_lock, &irql, "dma_op");
253 } return;
254#endif
255 case IDI_SYNC_REQ_XDI_GET_LOGICAL_ADAPTER_NUMBER: {
256 diva_xdi_get_logical_adapter_number_s_t *pI = \
257 &syncReq->xdi_logical_adapter_number.info;
258 pI->logical_adapter_number = IoAdapter->ANum;
259 pI->controller = IoAdapter->ControllerNumber;
260 pI->total_controllers = IoAdapter->Properties.Adapters;
261 } return;
262 case IDI_SYNC_REQ_XDI_GET_CAPI_PARAMS: {
263 diva_xdi_get_capi_parameters_t prms, *pI = &syncReq->xdi_capi_prms.info;
264 memset (&prms, 0x00, sizeof(prms));
265 prms.structure_length = MIN(sizeof(prms), pI->structure_length);
266 memset (pI, 0x00, pI->structure_length);
267 prms.flag_dynamic_l1_down = (IoAdapter->capi_cfg.cfg_1 & \
268 DIVA_XDI_CAPI_CFG_1_DYNAMIC_L1_ON) ? 1 : 0;
269 prms.group_optimization_enabled = (IoAdapter->capi_cfg.cfg_1 & \
270 DIVA_XDI_CAPI_CFG_1_GROUP_POPTIMIZATION_ON) ? 1 : 0;
271 memcpy (pI, &prms, prms.structure_length);
272 } return;
273 case IDI_SYNC_REQ_XDI_GET_ADAPTER_SDRAM_BAR:
274 syncReq->xdi_sdram_bar.info.bar = IoAdapter->sdram_bar;
275 return;
276 case IDI_SYNC_REQ_XDI_GET_EXTENDED_FEATURES: {
277 dword i;
278 diva_xdi_get_extended_xdi_features_t* pI =\
279 &syncReq->xdi_extended_features.info;
280 pI->buffer_length_in_bytes &= ~0x80000000;
281 if (pI->buffer_length_in_bytes && pI->features) {
282 memset (pI->features, 0x00, pI->buffer_length_in_bytes);
283 }
284 for (i = 0; ((pI->features) && (i < pI->buffer_length_in_bytes) &&
285 (i < DIVA_XDI_EXTENDED_FEATURES_MAX_SZ)); i++) {
286 pI->features[i] = extended_xdi_features[i];
287 }
288 if ((pI->buffer_length_in_bytes < DIVA_XDI_EXTENDED_FEATURES_MAX_SZ) ||
289 (!pI->features)) {
290 pI->buffer_length_in_bytes =\
291 (0x80000000 | DIVA_XDI_EXTENDED_FEATURES_MAX_SZ);
292 }
293 } return;
294 case IDI_SYNC_REQ_XDI_GET_STREAM:
295 if (IoAdapter) {
296 diva_xdi_provide_istream_info (&IoAdapter->a,
297 &syncReq->xdi_stream_info.info);
298 } else {
299 syncReq->xdi_stream_info.info.provided_service = 0;
300 }
301 return;
302 case IDI_SYNC_REQ_GET_NAME:
303 if ( IoAdapter )
304 {
305 strcpy (&syncReq->GetName.name[0], IoAdapter->Name) ;
306 DBG_TRC(("xdi: Adapter %d / Name '%s'",
307 IoAdapter->ANum, IoAdapter->Name))
308 return ;
309 }
310 syncReq->GetName.name[0] = '\0' ;
311 break ;
312 case IDI_SYNC_REQ_GET_SERIAL:
313 if ( IoAdapter )
314 {
315 syncReq->GetSerial.serial = IoAdapter->serialNo ;
316 DBG_TRC(("xdi: Adapter %d / SerialNo %ld",
317 IoAdapter->ANum, IoAdapter->serialNo))
318 return ;
319 }
320 syncReq->GetSerial.serial = 0 ;
321 break ;
322 case IDI_SYNC_REQ_GET_CARDTYPE:
323 if ( IoAdapter )
324 {
325 syncReq->GetCardType.cardtype = IoAdapter->cardType ;
326 DBG_TRC(("xdi: Adapter %d / CardType %ld",
327 IoAdapter->ANum, IoAdapter->cardType))
328 return ;
329 }
330 syncReq->GetCardType.cardtype = 0 ;
331 break ;
332 case IDI_SYNC_REQ_GET_XLOG:
333 if ( IoAdapter )
334 {
335 pcm_req (IoAdapter, e) ;
336 return ;
337 }
338 e->Ind = 0 ;
339 break ;
340 case IDI_SYNC_REQ_GET_DBG_XLOG:
341 if ( IoAdapter )
342 {
343 pcm_req (IoAdapter, e) ;
344 return ;
345 }
346 e->Ind = 0 ;
347 break ;
348 case IDI_SYNC_REQ_GET_FEATURES:
349 if ( IoAdapter )
350 {
351 syncReq->GetFeatures.features =
352 (unsigned short)IoAdapter->features ;
353 return ;
354 }
355 syncReq->GetFeatures.features = 0 ;
356 break ;
357 case IDI_SYNC_REQ_PORTDRV_HOOK:
358 if ( IoAdapter )
359 {
360 DBG_TRC(("Xdi:IDI_SYNC_REQ_PORTDRV_HOOK - ignored"))
361 return ;
362 }
363 break;
364 }
365 if ( IoAdapter )
366 {
367 return ;
368 }
369 }
370 DBG_TRC(("xdi: Id 0x%x / Req 0x%x / Rc 0x%x", e->Id, e->Req, e->Rc))
371 if ( !IoAdapter )
372 {
373 DBG_FTL(("xdi: uninitialized Adapter used - ignore request"))
374 return ;
375 }
376 diva_os_enter_spin_lock (&IoAdapter->data_spin_lock, &irql, "data_req");
377/*
378 * assign an entity
379 */
380 if ( !(e->Id &0x1f) )
381 {
382 if ( IoAdapter->e_count >= IoAdapter->e_max )
383 {
384 DBG_FTL(("xdi: all Ids in use (max=%d) --> Req ignored",
385 IoAdapter->e_max))
386 diva_os_leave_spin_lock (&IoAdapter->data_spin_lock, &irql, "data_req");
387 return ;
388 }
389/*
390 * find a new free id
391 */
392 for ( i = 1 ; IoAdapter->e_tbl[i].e ; ++i ) ;
393 IoAdapter->e_tbl[i].e = e ;
394 IoAdapter->e_count++ ;
395 e->No = (byte)i ;
396 e->More = 0 ;
397 e->RCurrent = 0xff ;
398 }
399 else
400 {
401 i = e->No ;
402 }
403/*
404 * if the entity is still busy, ignore the request call
405 */
406 if ( e->More & XBUSY )
407 {
408 DBG_FTL(("xdi: Id 0x%x busy --> Req 0x%x ignored", e->Id, e->Req))
409 if ( !IoAdapter->trapped && IoAdapter->trapFnc )
410 {
411 IoAdapter->trapFnc (IoAdapter) ;
412 /*
413 Firs trap, also notify user if supported
414 */
415 if (IoAdapter->trapped && IoAdapter->os_trap_nfy_Fnc) {
416 (*(IoAdapter->os_trap_nfy_Fnc))(IoAdapter, IoAdapter->ANum);
417 }
418 }
419 diva_os_leave_spin_lock (&IoAdapter->data_spin_lock, &irql, "data_req");
420 return ;
421 }
422/*
423 * initialize transmit status variables
424 */
425 e->More |= XBUSY ;
426 e->More &= ~XMOREF ;
427 e->XCurrent = 0 ;
428 e->XOffset = 0 ;
429/*
430 * queue this entity in the adapter request queue
431 */
432 IoAdapter->e_tbl[i].next = 0 ;
433 if ( IoAdapter->head )
434 {
435 IoAdapter->e_tbl[IoAdapter->tail].next = i ;
436 IoAdapter->tail = i ;
437 }
438 else
439 {
440 IoAdapter->head = i ;
441 IoAdapter->tail = i ;
442 }
443/*
444 * queue the DPC to process the request
445 */
446 diva_os_schedule_soft_isr (&IoAdapter->req_soft_isr);
447 diva_os_leave_spin_lock (&IoAdapter->data_spin_lock, &irql, "data_req");
448}
449/* ---------------------------------------------------------------------
450 Main DPC routine
451 --------------------------------------------------------------------- */
452void DIDpcRoutine (struct _diva_os_soft_isr* psoft_isr, void* Context) {
453 PISDN_ADAPTER IoAdapter = (PISDN_ADAPTER)Context ;
454 ADAPTER* a = &IoAdapter->a ;
455 diva_os_atomic_t* pin_dpc = &IoAdapter->in_dpc;
456 if (diva_os_atomic_increment (pin_dpc) == 1) {
457 do {
458 if ( IoAdapter->tst_irq (a) )
459 {
460 if ( !IoAdapter->Unavailable )
461 IoAdapter->dpc (a) ;
462 IoAdapter->clr_irq (a) ;
463 }
464 IoAdapter->out (a) ;
465 } while (diva_os_atomic_decrement (pin_dpc) > 0);
466 /* ----------------------------------------------------------------
467 Look for XLOG request (cards with indirect addressing)
468 ---------------------------------------------------------------- */
469 if (IoAdapter->pcm_pending) {
470 struct pc_maint *pcm;
471 diva_os_spin_lock_magic_t OldIrql ;
472 diva_os_enter_spin_lock (&IoAdapter->data_spin_lock,
473 &OldIrql,
474 "data_dpc");
475 pcm = (struct pc_maint *)IoAdapter->pcm_data;
476 switch (IoAdapter->pcm_pending) {
477 case 1: /* ask card for XLOG */
478 a->ram_out (a, &IoAdapter->pcm->rc, 0) ;
479 a->ram_out (a, &IoAdapter->pcm->req, pcm->req) ;
480 IoAdapter->pcm_pending = 2;
481 break;
482 case 2: /* Try to get XLOG from the card */
483 if ((int)(a->ram_in (a, &IoAdapter->pcm->rc))) {
484 a->ram_in_buffer (a, IoAdapter->pcm, pcm, sizeof(*pcm)) ;
485 IoAdapter->pcm_pending = 3;
486 }
487 break;
488 case 3: /* let XDI recovery XLOG */
489 break;
490 }
491 diva_os_leave_spin_lock (&IoAdapter->data_spin_lock,
492 &OldIrql,
493 "data_dpc");
494 }
495 /* ---------------------------------------------------------------- */
496 }
497}
498/* --------------------------------------------------------------------------
499 XLOG interface
500 -------------------------------------------------------------------------- */
501static void
502pcm_req (PISDN_ADAPTER IoAdapter, ENTITY *e)
503{
504 diva_os_spin_lock_magic_t OldIrql ;
505 int i, rc ;
506 ADAPTER *a = &IoAdapter->a ;
507 struct pc_maint *pcm = (struct pc_maint *)&e->Ind ;
508/*
509 * special handling of I/O based card interface
510 * the memory access isn't an atomic operation !
511 */
512 if ( IoAdapter->Properties.Card == CARD_MAE )
513 {
514 diva_os_enter_spin_lock (&IoAdapter->data_spin_lock,
515 &OldIrql,
516 "data_pcm_1");
517 IoAdapter->pcm_data = (void *)pcm;
518 IoAdapter->pcm_pending = 1;
519 diva_os_schedule_soft_isr (&IoAdapter->req_soft_isr);
520 diva_os_leave_spin_lock (&IoAdapter->data_spin_lock,
521 &OldIrql,
522 "data_pcm_1");
523 for ( rc = 0, i = (IoAdapter->trapped ? 3000 : 250) ; !rc && (i > 0) ; --i )
524 {
525 diva_os_sleep (1) ;
526 if (IoAdapter->pcm_pending == 3) {
527 diva_os_enter_spin_lock (&IoAdapter->data_spin_lock,
528 &OldIrql,
529 "data_pcm_3");
530 IoAdapter->pcm_pending = 0;
531 IoAdapter->pcm_data = NULL ;
532 diva_os_leave_spin_lock (&IoAdapter->data_spin_lock,
533 &OldIrql,
534 "data_pcm_3");
535 return ;
536 }
537 diva_os_enter_spin_lock (&IoAdapter->data_spin_lock,
538 &OldIrql,
539 "data_pcm_2");
540 diva_os_schedule_soft_isr (&IoAdapter->req_soft_isr);
541 diva_os_leave_spin_lock (&IoAdapter->data_spin_lock,
542 &OldIrql,
543 "data_pcm_2");
544 }
545 diva_os_enter_spin_lock (&IoAdapter->data_spin_lock,
546 &OldIrql,
547 "data_pcm_4");
548 IoAdapter->pcm_pending = 0;
549 IoAdapter->pcm_data = NULL ;
550 diva_os_leave_spin_lock (&IoAdapter->data_spin_lock,
551 &OldIrql,
552 "data_pcm_4");
553 goto Trapped ;
554 }
555/*
556 * memory based shared ram is accessible from different
557 * processors without disturbing concurrent processes.
558 */
559 a->ram_out (a, &IoAdapter->pcm->rc, 0) ;
560 a->ram_out (a, &IoAdapter->pcm->req, pcm->req) ;
561 for ( i = (IoAdapter->trapped ? 3000 : 250) ; --i > 0 ; )
562 {
563 diva_os_sleep (1) ;
564 rc = (int)(a->ram_in (a, &IoAdapter->pcm->rc)) ;
565 if ( rc )
566 {
567 a->ram_in_buffer (a, IoAdapter->pcm, pcm, sizeof(*pcm)) ;
568 return ;
569 }
570 }
571Trapped:
572 if ( IoAdapter->trapFnc )
573 {
574 int trapped = IoAdapter->trapped;
575 IoAdapter->trapFnc (IoAdapter) ;
576 /*
577 Firs trap, also notify user if supported
578 */
579 if (!trapped && IoAdapter->trapped && IoAdapter->os_trap_nfy_Fnc) {
580 (*(IoAdapter->os_trap_nfy_Fnc))(IoAdapter, IoAdapter->ANum);
581 }
582 }
583}
584/*------------------------------------------------------------------*/
585/* ram access functions for memory mapped cards */
586/*------------------------------------------------------------------*/
587byte mem_in (ADAPTER *a, void *addr)
588{
589 byte val;
590 volatile byte __iomem *Base = DIVA_OS_MEM_ATTACH_RAM((PISDN_ADAPTER)a->io);
591 val = READ_BYTE(Base + (unsigned long)addr);
592 DIVA_OS_MEM_DETACH_RAM((PISDN_ADAPTER)a->io, Base);
593 return (val);
594}
595word mem_inw (ADAPTER *a, void *addr)
596{
597 word val;
598 volatile byte __iomem *Base = DIVA_OS_MEM_ATTACH_RAM((PISDN_ADAPTER)a->io);
599 val = READ_WORD((Base + (unsigned long)addr));
600 DIVA_OS_MEM_DETACH_RAM((PISDN_ADAPTER)a->io, Base);
601 return (val);
602}
603void mem_in_dw (ADAPTER *a, void *addr, dword* data, int dwords)
604{
605 volatile byte __iomem * Base = DIVA_OS_MEM_ATTACH_RAM((PISDN_ADAPTER)a->io);
606 while (dwords--) {
607 *data++ = READ_DWORD((Base + (unsigned long)addr));
608 addr+=4;
609 }
610 DIVA_OS_MEM_DETACH_RAM((PISDN_ADAPTER)a->io, Base);
611}
612void mem_in_buffer (ADAPTER *a, void *addr, void *buffer, word length)
613{
614 volatile byte __iomem *Base = DIVA_OS_MEM_ATTACH_RAM((PISDN_ADAPTER)a->io);
615 memcpy_fromio(buffer, (Base + (unsigned long)addr), length);
616 DIVA_OS_MEM_DETACH_RAM((PISDN_ADAPTER)a->io, Base);
617}
618void mem_look_ahead (ADAPTER *a, PBUFFER *RBuffer, ENTITY *e)
619{
620 PISDN_ADAPTER IoAdapter = (PISDN_ADAPTER)a->io ;
621 IoAdapter->RBuffer.length = mem_inw (a, &RBuffer->length) ;
622 mem_in_buffer (a, RBuffer->P, IoAdapter->RBuffer.P,
623 IoAdapter->RBuffer.length) ;
624 e->RBuffer = (DBUFFER *)&IoAdapter->RBuffer ;
625}
626void mem_out (ADAPTER *a, void *addr, byte data)
627{
628 volatile byte __iomem *Base = DIVA_OS_MEM_ATTACH_RAM((PISDN_ADAPTER)a->io);
629 WRITE_BYTE(Base + (unsigned long)addr, data);
630 DIVA_OS_MEM_DETACH_RAM((PISDN_ADAPTER)a->io, Base);
631}
632void mem_outw (ADAPTER *a, void *addr, word data)
633{
634 volatile byte __iomem * Base = DIVA_OS_MEM_ATTACH_RAM((PISDN_ADAPTER)a->io);
635 WRITE_WORD((Base + (unsigned long)addr), data);
636 DIVA_OS_MEM_DETACH_RAM((PISDN_ADAPTER)a->io, Base);
637}
638void mem_out_dw (ADAPTER *a, void *addr, const dword* data, int dwords)
639{
640 volatile byte __iomem * Base = DIVA_OS_MEM_ATTACH_RAM((PISDN_ADAPTER)a->io);
641 while (dwords--) {
642 WRITE_DWORD((Base + (unsigned long)addr), *data);
643 addr+=4;
644 data++;
645 }
646 DIVA_OS_MEM_DETACH_RAM((PISDN_ADAPTER)a->io, Base);
647}
648void mem_out_buffer (ADAPTER *a, void *addr, void *buffer, word length)
649{
650 volatile byte __iomem * Base = DIVA_OS_MEM_ATTACH_RAM((PISDN_ADAPTER)a->io);
651 memcpy_toio((Base + (unsigned long)addr), buffer, length) ;
652 DIVA_OS_MEM_DETACH_RAM((PISDN_ADAPTER)a->io, Base);
653}
654void mem_inc (ADAPTER *a, void *addr)
655{
656 volatile byte __iomem *Base = DIVA_OS_MEM_ATTACH_RAM((PISDN_ADAPTER)a->io);
657 byte x = READ_BYTE(Base + (unsigned long)addr);
658 WRITE_BYTE(Base + (unsigned long)addr, x + 1);
659 DIVA_OS_MEM_DETACH_RAM((PISDN_ADAPTER)a->io, Base);
660}
661/*------------------------------------------------------------------*/
662/* ram access functions for io-mapped cards */
663/*------------------------------------------------------------------*/
664byte io_in(ADAPTER * a, void * adr)
665{
666 byte val;
667 byte __iomem *Port = DIVA_OS_MEM_ATTACH_PORT((PISDN_ADAPTER)a->io);
668 outppw(Port + 4, (word)(unsigned long)adr);
669 val = inpp(Port);
670 DIVA_OS_MEM_DETACH_PORT((PISDN_ADAPTER)a->io, Port);
671 return(val);
672}
673word io_inw(ADAPTER * a, void * adr)
674{
675 word val;
676 byte __iomem *Port = DIVA_OS_MEM_ATTACH_PORT((PISDN_ADAPTER)a->io);
677 outppw(Port + 4, (word)(unsigned long)adr);
678 val = inppw(Port);
679 DIVA_OS_MEM_DETACH_PORT((PISDN_ADAPTER)a->io, Port);
680 return(val);
681}
682void io_in_buffer(ADAPTER * a, void * adr, void * buffer, word len)
683{
684 byte __iomem *Port = DIVA_OS_MEM_ATTACH_PORT((PISDN_ADAPTER)a->io);
685 byte* P = (byte*)buffer;
686 if ((long)adr & 1) {
687 outppw(Port+4, (word)(unsigned long)adr);
688 *P = inpp(Port);
689 P++;
690 adr = ((byte *) adr) + 1;
691 len--;
692 if (!len) {
693 DIVA_OS_MEM_DETACH_PORT((PISDN_ADAPTER)a->io, Port);
694 return;
695 }
696 }
697 outppw(Port+4, (word)(unsigned long)adr);
698 inppw_buffer (Port, P, len+1);
699 DIVA_OS_MEM_DETACH_PORT((PISDN_ADAPTER)a->io, Port);
700}
701void io_look_ahead(ADAPTER * a, PBUFFER * RBuffer, ENTITY * e)
702{
703 byte __iomem *Port = DIVA_OS_MEM_ATTACH_PORT((PISDN_ADAPTER)a->io);
704 outppw(Port+4, (word)(unsigned long)RBuffer);
705 ((PISDN_ADAPTER)a->io)->RBuffer.length = inppw(Port);
706 inppw_buffer (Port, ((PISDN_ADAPTER)a->io)->RBuffer.P, ((PISDN_ADAPTER)a->io)->RBuffer.length + 1);
707 e->RBuffer = (DBUFFER *) &(((PISDN_ADAPTER)a->io)->RBuffer);
708 DIVA_OS_MEM_DETACH_PORT((PISDN_ADAPTER)a->io, Port);
709}
710void io_out(ADAPTER * a, void * adr, byte data)
711{
712 byte __iomem *Port = DIVA_OS_MEM_ATTACH_PORT((PISDN_ADAPTER)a->io);
713 outppw(Port+4, (word)(unsigned long)adr);
714 outpp(Port, data);
715 DIVA_OS_MEM_DETACH_PORT((PISDN_ADAPTER)a->io, Port);
716}
717void io_outw(ADAPTER * a, void * adr, word data)
718{
719 byte __iomem *Port = DIVA_OS_MEM_ATTACH_PORT((PISDN_ADAPTER)a->io);
720 outppw(Port+4, (word)(unsigned long)adr);
721 outppw(Port, data);
722 DIVA_OS_MEM_DETACH_PORT((PISDN_ADAPTER)a->io, Port);
723}
724void io_out_buffer(ADAPTER * a, void * adr, void * buffer, word len)
725{
726 byte __iomem *Port = DIVA_OS_MEM_ATTACH_PORT((PISDN_ADAPTER)a->io);
727 byte* P = (byte*)buffer;
728 if ((long)adr & 1) {
729 outppw(Port+4, (word)(unsigned long)adr);
730 outpp(Port, *P);
731 P++;
732 adr = ((byte *) adr) + 1;
733 len--;
734 if (!len) {
735 DIVA_OS_MEM_DETACH_PORT((PISDN_ADAPTER)a->io, Port);
736 return;
737 }
738 }
739 outppw(Port+4, (word)(unsigned long)adr);
740 outppw_buffer (Port, P, len+1);
741 DIVA_OS_MEM_DETACH_PORT((PISDN_ADAPTER)a->io, Port);
742}
743void io_inc(ADAPTER * a, void * adr)
744{
745 byte x;
746 byte __iomem *Port = DIVA_OS_MEM_ATTACH_PORT((PISDN_ADAPTER)a->io);
747 outppw(Port+4, (word)(unsigned long)adr);
748 x = inpp(Port);
749 outppw(Port+4, (word)(unsigned long)adr);
750 outpp(Port, x+1);
751 DIVA_OS_MEM_DETACH_PORT((PISDN_ADAPTER)a->io, Port);
752}
753/*------------------------------------------------------------------*/
754/* OS specific functions related to queuing of entities */
755/*------------------------------------------------------------------*/
756void free_entity(ADAPTER * a, byte e_no)
757{
758 PISDN_ADAPTER IoAdapter;
759 diva_os_spin_lock_magic_t irql;
760 IoAdapter = (PISDN_ADAPTER) a->io;
761 diva_os_enter_spin_lock (&IoAdapter->data_spin_lock, &irql, "data_free");
762 IoAdapter->e_tbl[e_no].e = NULL;
763 IoAdapter->e_count--;
764 diva_os_leave_spin_lock (&IoAdapter->data_spin_lock, &irql, "data_free");
765}
766void assign_queue(ADAPTER * a, byte e_no, word ref)
767{
768 PISDN_ADAPTER IoAdapter;
769 diva_os_spin_lock_magic_t irql;
770 IoAdapter = (PISDN_ADAPTER) a->io;
771 diva_os_enter_spin_lock (&IoAdapter->data_spin_lock, &irql, "data_assign");
772 IoAdapter->e_tbl[e_no].assign_ref = ref;
773 IoAdapter->e_tbl[e_no].next = (byte)IoAdapter->assign;
774 IoAdapter->assign = e_no;
775 diva_os_leave_spin_lock (&IoAdapter->data_spin_lock, &irql, "data_assign");
776}
777byte get_assign(ADAPTER * a, word ref)
778{
779 PISDN_ADAPTER IoAdapter;
780 diva_os_spin_lock_magic_t irql;
781 byte e_no;
782 IoAdapter = (PISDN_ADAPTER) a->io;
783 diva_os_enter_spin_lock (&IoAdapter->data_spin_lock,
784 &irql,
785 "data_assign_get");
786 for(e_no = (byte)IoAdapter->assign;
787 e_no && IoAdapter->e_tbl[e_no].assign_ref!=ref;
788 e_no = IoAdapter->e_tbl[e_no].next);
789 diva_os_leave_spin_lock (&IoAdapter->data_spin_lock,
790 &irql,
791 "data_assign_get");
792 return e_no;
793}
794void req_queue(ADAPTER * a, byte e_no)
795{
796 PISDN_ADAPTER IoAdapter;
797 diva_os_spin_lock_magic_t irql;
798 IoAdapter = (PISDN_ADAPTER) a->io;
799 diva_os_enter_spin_lock (&IoAdapter->data_spin_lock, &irql, "data_req_q");
800 IoAdapter->e_tbl[e_no].next = 0;
801 if(IoAdapter->head) {
802 IoAdapter->e_tbl[IoAdapter->tail].next = e_no;
803 IoAdapter->tail = e_no;
804 }
805 else {
806 IoAdapter->head = e_no;
807 IoAdapter->tail = e_no;
808 }
809 diva_os_leave_spin_lock (&IoAdapter->data_spin_lock, &irql, "data_req_q");
810}
811byte look_req(ADAPTER * a)
812{
813 PISDN_ADAPTER IoAdapter;
814 IoAdapter = (PISDN_ADAPTER) a->io;
815 return ((byte)IoAdapter->head) ;
816}
817void next_req(ADAPTER * a)
818{
819 PISDN_ADAPTER IoAdapter;
820 diva_os_spin_lock_magic_t irql;
821 IoAdapter = (PISDN_ADAPTER) a->io;
822 diva_os_enter_spin_lock (&IoAdapter->data_spin_lock, &irql, "data_req_next");
823 IoAdapter->head = IoAdapter->e_tbl[IoAdapter->head].next;
824 if(!IoAdapter->head) IoAdapter->tail = 0;
825 diva_os_leave_spin_lock (&IoAdapter->data_spin_lock, &irql, "data_req_next");
826}
827/*------------------------------------------------------------------*/
828/* memory map functions */
829/*------------------------------------------------------------------*/
830ENTITY * entity_ptr(ADAPTER * a, byte e_no)
831{
832 PISDN_ADAPTER IoAdapter;
833 IoAdapter = (PISDN_ADAPTER) a->io;
834 return (IoAdapter->e_tbl[e_no].e);
835}
836void * PTR_X(ADAPTER * a, ENTITY * e)
837{
838 return ((void *) e->X);
839}
840void * PTR_R(ADAPTER * a, ENTITY * e)
841{
842 return ((void *) e->R);
843}
844void * PTR_P(ADAPTER * a, ENTITY * e, void * P)
845{
846 return P;
847}
848void CALLBACK(ADAPTER * a, ENTITY * e)
849{
850 if ( e && e->callback )
851 e->callback (e) ;
852}
diff --git a/drivers/isdn/hardware/eicon/io.h b/drivers/isdn/hardware/eicon/io.h
new file mode 100644
index 000000000000..0c6c650d76bb
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/io.h
@@ -0,0 +1,308 @@
1
2/*
3 *
4 Copyright (c) Eicon Networks, 2002.
5 *
6 This source file is supplied for the use with
7 Eicon Networks range of DIVA Server Adapters.
8 *
9 Eicon File Revision : 2.1
10 *
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2, or (at your option)
14 any later version.
15 *
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
18 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 See the GNU General Public License for more details.
20 *
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26#ifndef __DIVA_XDI_COMMON_IO_H_INC__ /* { */
27#define __DIVA_XDI_COMMON_IO_H_INC__
28/*
29 maximum = 16 adapters
30 */
31#define DI_MAX_LINKS MAX_ADAPTER
32#define ISDN_MAX_NUM_LEN 60
33/* --------------------------------------------------------------------------
34 structure for quadro card management (obsolete for
35 systems that do provide per card load event)
36 -------------------------------------------------------------------------- */
37typedef struct {
38 dword Num ;
39 DEVICE_NAME DeviceName[4] ;
40 PISDN_ADAPTER QuadroAdapter[4] ;
41} ADAPTER_LIST_ENTRY, *PADAPTER_LIST_ENTRY ;
42/* --------------------------------------------------------------------------
43 Special OS memory support structures
44 -------------------------------------------------------------------------- */
45#define MAX_MAPPED_ENTRIES 8
46typedef struct {
47 void * Address;
48 dword Length;
49} ADAPTER_MEMORY ;
50/* --------------------------------------------------------------------------
51 Configuration of XDI clients carried by XDI
52 -------------------------------------------------------------------------- */
53#define DIVA_XDI_CAPI_CFG_1_DYNAMIC_L1_ON 0x01
54#define DIVA_XDI_CAPI_CFG_1_GROUP_POPTIMIZATION_ON 0x02
55typedef struct _diva_xdi_capi_cfg {
56 byte cfg_1;
57} diva_xdi_capi_cfg_t;
58/* --------------------------------------------------------------------------
59 Main data structure kept per adapter
60 -------------------------------------------------------------------------- */
61struct _ISDN_ADAPTER {
62 void (* DIRequest)(PISDN_ADAPTER, ENTITY *) ;
63 int State ; /* from NT4 1.srv, a good idea, but a poor achievment */
64 int Initialized ;
65 int RegisteredWithDidd ;
66 int Unavailable ; /* callback function possible? */
67 int ResourcesClaimed ;
68 int PnpBiosConfigUsed ;
69 dword Logging ;
70 dword features ;
71 char ProtocolIdString[80] ;
72 /*
73 remember mapped memory areas
74 */
75 ADAPTER_MEMORY MappedMemory[MAX_MAPPED_ENTRIES] ;
76 CARD_PROPERTIES Properties ;
77 dword cardType ;
78 dword protocol_id ; /* configured protocol identifier */
79 char protocol_name[8] ; /* readable name of protocol */
80 dword BusType ;
81 dword BusNumber ;
82 dword slotNumber ;
83 dword slotId ;
84 dword ControllerNumber ; /* for QUADRO cards only */
85 PISDN_ADAPTER MultiMaster ; /* for 4-BRI card only - use MultiMaster or QuadroList */
86 PADAPTER_LIST_ENTRY QuadroList ; /* for QUADRO card only */
87 PDEVICE_OBJECT DeviceObject ;
88 dword DeviceId ;
89 diva_os_adapter_irq_info_t irq_info;
90 dword volatile IrqCount ;
91 int trapped ;
92 dword DspCodeBaseAddr ;
93 dword MaxDspCodeSize ;
94 dword downloadAddr ;
95 dword DspCodeBaseAddrTable[4] ; /* add. for MultiMaster */
96 dword MaxDspCodeSizeTable[4] ; /* add. for MultiMaster */
97 dword downloadAddrTable[4] ; /* add. for MultiMaster */
98 dword MemoryBase ;
99 dword MemorySize ;
100 byte __iomem *Address ;
101 byte __iomem *Config ;
102 byte __iomem *Control ;
103 byte __iomem *reset ;
104 byte __iomem *port ;
105 byte __iomem *ram ;
106 byte __iomem *cfg ;
107 byte __iomem *prom ;
108 byte __iomem *ctlReg ;
109 struct pc_maint *pcm ;
110 diva_os_dependent_devica_name_t os_name;
111 byte Name[32] ;
112 dword serialNo ;
113 dword ANum ;
114 dword ArchiveType ; /* ARCHIVE_TYPE_NONE ..._SINGLE ..._USGEN ..._MULTI */
115 char *ProtocolSuffix ; /* internal protocolfile table */
116 char Archive[32] ;
117 char Protocol[32] ;
118 char AddDownload[32] ; /* Dsp- or other additional download files */
119 char Oad1[ISDN_MAX_NUM_LEN] ;
120 char Osa1[ISDN_MAX_NUM_LEN] ;
121 char Oad2[ISDN_MAX_NUM_LEN] ;
122 char Osa2[ISDN_MAX_NUM_LEN] ;
123 char Spid1[ISDN_MAX_NUM_LEN] ;
124 char Spid2[ISDN_MAX_NUM_LEN] ;
125 byte nosig ;
126 byte BriLayer2LinkCount ; /* amount of TEI's that adapter will support in P2MP mode */
127 dword Channels ;
128 dword tei ;
129 dword nt2 ;
130 dword TerminalCount ;
131 dword WatchDog ;
132 dword Permanent ;
133 dword BChMask ; /* B channel mask for unchannelized modes */
134 dword StableL2 ;
135 dword DidLen ;
136 dword NoOrderCheck ;
137 dword ForceLaw; /* VoiceCoding - default:0, a-law: 1, my-law: 2 */
138 dword SigFlags ;
139 dword LowChannel ;
140 dword NoHscx30 ;
141 dword ProtVersion ;
142 dword crc4 ;
143 dword L1TristateOrQsig ; /* enable Layer 1 Tristate (bit 2)Or Qsig params (bit 0,1)*/
144 dword InitialDspInfo ;
145 dword ModemGuardTone ;
146 dword ModemMinSpeed ;
147 dword ModemMaxSpeed ;
148 dword ModemOptions ;
149 dword ModemOptions2 ;
150 dword ModemNegotiationMode ;
151 dword ModemModulationsMask ;
152 dword ModemTransmitLevel ;
153 dword FaxOptions ;
154 dword FaxMaxSpeed ;
155 dword Part68LevelLimiter ;
156 dword UsEktsNumCallApp ;
157 byte UsEktsFeatAddConf ;
158 byte UsEktsFeatRemoveConf ;
159 byte UsEktsFeatCallTransfer ;
160 byte UsEktsFeatMsgWaiting ;
161 byte QsigDialect;
162 byte ForceVoiceMailAlert;
163 byte DisableAutoSpid;
164 byte ModemCarrierWaitTimeSec;
165 byte ModemCarrierLossWaitTimeTenthSec;
166 byte PiafsLinkTurnaroundInFrames;
167 byte DiscAfterProgress;
168 byte AniDniLimiter[3];
169 byte TxAttenuation; /* PRI/E1 only: attenuate TX signal */
170 word QsigFeatures;
171 dword GenerateRingtone ;
172 dword SupplementaryServicesFeatures;
173 dword R2Dialect;
174 dword R2CasOptions;
175 dword FaxV34Options;
176 dword DisabledDspMask;
177 dword AdapterTestMask;
178 dword DspImageLength;
179 word AlertToIn20mSecTicks;
180 word ModemEyeSetup;
181 byte R2CtryLength;
182 byte CCBSRelTimer;
183 byte *PcCfgBufferFile;/* flexible parameter via file */
184 byte *PcCfgBuffer ; /* flexible parameter via multistring */
185 diva_os_dump_file_t dump_file; /* dump memory to file at lowest irq level */
186 diva_os_board_trace_t board_trace ; /* traces from the board */
187 diva_os_spin_lock_t isr_spin_lock;
188 diva_os_spin_lock_t data_spin_lock;
189 diva_os_soft_isr_t req_soft_isr;
190 diva_os_soft_isr_t isr_soft_isr;
191 diva_os_atomic_t in_dpc;
192 PBUFFER RBuffer; /* Copy of receive lookahead buffer */
193 word e_max;
194 word e_count;
195 E_INFO *e_tbl;
196 word assign; /* list of pending ASSIGNs */
197 word head; /* head of request queue */
198 word tail; /* tail of request queue */
199 ADAPTER a ; /* not a separate structure */
200 void (* out)(ADAPTER * a) ;
201 byte (* dpc)(ADAPTER * a) ;
202 byte (* tst_irq)(ADAPTER * a) ;
203 void (* clr_irq)(ADAPTER * a) ;
204 int (* load)(PISDN_ADAPTER) ;
205 int (* mapmem)(PISDN_ADAPTER) ;
206 int (* chkIrq)(PISDN_ADAPTER) ;
207 void (* disIrq)(PISDN_ADAPTER) ;
208 void (* start)(PISDN_ADAPTER) ;
209 void (* stop)(PISDN_ADAPTER) ;
210 void (* rstFnc)(PISDN_ADAPTER) ;
211 void (* trapFnc)(PISDN_ADAPTER) ;
212 dword (* DetectDsps)(PISDN_ADAPTER) ;
213 void (* os_trap_nfy_Fnc)(PISDN_ADAPTER, dword) ;
214 diva_os_isr_callback_t diva_isr_handler;
215 dword sdram_bar; /* must be 32 bit */
216 dword fpga_features;
217 volatile int pcm_pending;
218 volatile void * pcm_data;
219 diva_xdi_capi_cfg_t capi_cfg;
220 dword tasks;
221 void *dma_map;
222 int (*DivaAdapterTestProc)(PISDN_ADAPTER);
223 void *AdapterTestMemoryStart;
224 dword AdapterTestMemoryLength;
225 const byte* cfg_lib_memory_init;
226 dword cfg_lib_memory_init_length;
227};
228/* ---------------------------------------------------------------------
229 Entity table
230 --------------------------------------------------------------------- */
231struct e_info_s {
232 ENTITY * e;
233 byte next; /* chaining index */
234 word assign_ref; /* assign reference */
235};
236/* ---------------------------------------------------------------------
237 S-cards shared ram structure for loading
238 --------------------------------------------------------------------- */
239struct s_load {
240 byte ctrl;
241 byte card;
242 byte msize;
243 byte fill0;
244 word ebit;
245 word elocl;
246 word eloch;
247 byte reserved[20];
248 word signature;
249 byte fill[224];
250 byte b[256];
251};
252#define PR_RAM ((struct pr_ram *)0)
253#define RAM ((struct dual *)0)
254/* ---------------------------------------------------------------------
255 platform specific conversions
256 --------------------------------------------------------------------- */
257extern void * PTR_P(ADAPTER * a, ENTITY * e, void * P);
258extern void * PTR_X(ADAPTER * a, ENTITY * e);
259extern void * PTR_R(ADAPTER * a, ENTITY * e);
260extern void CALLBACK(ADAPTER * a, ENTITY * e);
261extern void set_ram(void * * adr_ptr);
262/* ---------------------------------------------------------------------
263 ram access functions for io mapped cards
264 --------------------------------------------------------------------- */
265byte io_in(ADAPTER * a, void * adr);
266word io_inw(ADAPTER * a, void * adr);
267void io_in_buffer(ADAPTER * a, void * adr, void * P, word length);
268void io_look_ahead(ADAPTER * a, PBUFFER * RBuffer, ENTITY * e);
269void io_out(ADAPTER * a, void * adr, byte data);
270void io_outw(ADAPTER * a, void * adr, word data);
271void io_out_buffer(ADAPTER * a, void * adr, void * P, word length);
272void io_inc(ADAPTER * a, void * adr);
273void bri_in_buffer (PISDN_ADAPTER IoAdapter, dword Pos,
274 void *Buf, dword Len);
275int bri_out_buffer (PISDN_ADAPTER IoAdapter, dword Pos,
276 void *Buf, dword Len, int Verify);
277/* ---------------------------------------------------------------------
278 ram access functions for memory mapped cards
279 --------------------------------------------------------------------- */
280byte mem_in(ADAPTER * a, void * adr);
281word mem_inw(ADAPTER * a, void * adr);
282void mem_in_buffer(ADAPTER * a, void * adr, void * P, word length);
283void mem_look_ahead(ADAPTER * a, PBUFFER * RBuffer, ENTITY * e);
284void mem_out(ADAPTER * a, void * adr, byte data);
285void mem_outw(ADAPTER * a, void * adr, word data);
286void mem_out_buffer(ADAPTER * a, void * adr, void * P, word length);
287void mem_inc(ADAPTER * a, void * adr);
288void mem_in_dw (ADAPTER *a, void *addr, dword* data, int dwords);
289void mem_out_dw (ADAPTER *a, void *addr, const dword* data, int dwords);
290/* ---------------------------------------------------------------------
291 functions exported by io.c
292 --------------------------------------------------------------------- */
293extern IDI_CALL Requests[MAX_ADAPTER] ;
294extern void DIDpcRoutine (struct _diva_os_soft_isr* psoft_isr,
295 void* context);
296extern void request (PISDN_ADAPTER, ENTITY *) ;
297/* ---------------------------------------------------------------------
298 trapFn helpers, used to recover debug trace from dead card
299 --------------------------------------------------------------------- */
300typedef struct {
301 word *buf ;
302 word cnt ;
303 word out ;
304} Xdesc ;
305extern void dump_trap_frame (PISDN_ADAPTER IoAdapter, byte __iomem *exception) ;
306extern void dump_xlog_buffer (PISDN_ADAPTER IoAdapter, Xdesc *xlogDesc) ;
307/* --------------------------------------------------------------------- */
308#endif /* } __DIVA_XDI_COMMON_IO_H_INC__ */
diff --git a/drivers/isdn/hardware/eicon/istream.c b/drivers/isdn/hardware/eicon/istream.c
new file mode 100644
index 000000000000..23139668d9b1
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/istream.c
@@ -0,0 +1,226 @@
1
2/*
3 *
4 Copyright (c) Eicon Networks, 2002.
5 *
6 This source file is supplied for the use with
7 Eicon Networks range of DIVA Server Adapters.
8 *
9 Eicon File Revision : 2.1
10 *
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2, or (at your option)
14 any later version.
15 *
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
18 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 See the GNU General Public License for more details.
20 *
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26#include "platform.h"
27#if defined(DIVA_ISTREAM) /* { */
28#include "pc.h"
29#include "pr_pc.h"
30#include "di_defs.h"
31#include "divasync.h"
32#include "di.h"
33#if !defined USE_EXTENDED_DEBUGS
34 #include "dimaint.h"
35#else
36 #define dprintf
37#endif
38#include "dfifo.h"
39int diva_istream_write (void* context,
40 int Id,
41 void* data,
42 int length,
43 int final,
44 byte usr1,
45 byte usr2);
46int diva_istream_read (void* context,
47 int Id,
48 void* data,
49 int max_length,
50 int* final,
51 byte* usr1,
52 byte* usr2);
53/* -------------------------------------------------------------------
54 Does provide iStream interface to the client
55 ------------------------------------------------------------------- */
56void diva_xdi_provide_istream_info (ADAPTER* a,
57 diva_xdi_stream_interface_t* pi) {
58 pi->provided_service = 0;
59}
60/* ------------------------------------------------------------------
61 Does write the data from caller's buffer to the card's
62 stream interface.
63 If synchronous service was requested, then function
64 does return amount of data written to stream.
65 'final' does indicate that pice of data to be written is
66 final part of frame (necessary only by structured datatransfer)
67 return 0 if zero lengh packet was written
68 return -1 if stream is full
69 ------------------------------------------------------------------ */
70int diva_istream_write (void* context,
71 int Id,
72 void* data,
73 int length,
74 int final,
75 byte usr1,
76 byte usr2) {
77 ADAPTER* a = (ADAPTER*)context;
78 int written = 0, to_write = -1;
79 char tmp[4];
80 byte* data_ptr = (byte*)data;
81 for (;;) {
82 a->ram_in_dw (a,
83#ifdef PLATFORM_GT_32BIT
84 ULongToPtr(a->tx_stream[Id] + a->tx_pos[Id]),
85#else
86 (void*)(a->tx_stream[Id] + a->tx_pos[Id]),
87#endif
88 (dword*)&tmp[0],
89 1);
90 if (tmp[0] & DIVA_DFIFO_READY) { /* No free blocks more */
91 if (to_write < 0)
92 return (-1); /* was not able to write */
93 break; /* only part of message was written */
94 }
95 to_write = MIN(length, DIVA_DFIFO_DATA_SZ);
96 if (to_write) {
97 a->ram_out_buffer (a,
98#ifdef PLATFORM_GT_32BIT
99 ULongToPtr(a->tx_stream[Id] + a->tx_pos[Id]+4),
100#else
101 (void*)(a->tx_stream[Id] + a->tx_pos[Id] + 4),
102#endif
103 data_ptr,
104 (word)to_write);
105 length -= to_write;
106 written += to_write;
107 data_ptr += to_write;
108 }
109 tmp[1] = (char)to_write;
110 tmp[0] = (tmp[0] & DIVA_DFIFO_WRAP) |
111 DIVA_DFIFO_READY |
112 ((!length && final) ? DIVA_DFIFO_LAST : 0);
113 if (tmp[0] & DIVA_DFIFO_LAST) {
114 tmp[2] = usr1;
115 tmp[3] = usr2;
116 }
117 a->ram_out_dw (a,
118#ifdef PLATFORM_GT_32BIT
119 ULongToPtr(a->tx_stream[Id] + a->tx_pos[Id]),
120#else
121 (void*)(a->tx_stream[Id] + a->tx_pos[Id]),
122#endif
123 (dword*)&tmp[0],
124 1);
125 if (tmp[0] & DIVA_DFIFO_WRAP) {
126 a->tx_pos[Id] = 0;
127 } else {
128 a->tx_pos[Id] += DIVA_DFIFO_STEP;
129 }
130 if (!length) {
131 break;
132 }
133 }
134 return (written);
135}
136/* -------------------------------------------------------------------
137 In case of SYNCRONOUS service:
138 Does write data from stream in caller's buffer.
139 Does return amount of data written to buffer
140 Final flag is set on return if last part of structured frame
141 was received
142 return 0 if zero packet was received
143 return -1 if stream is empty
144 return -2 if read buffer does not profide sufficient space
145 to accommodate entire segment
146 max_length should be at least 68 bytes
147 ------------------------------------------------------------------- */
148int diva_istream_read (void* context,
149 int Id,
150 void* data,
151 int max_length,
152 int* final,
153 byte* usr1,
154 byte* usr2) {
155 ADAPTER* a = (ADAPTER*)context;
156 int read = 0, to_read = -1;
157 char tmp[4];
158 byte* data_ptr = (byte*)data;
159 *final = 0;
160 for (;;) {
161 a->ram_in_dw (a,
162#ifdef PLATFORM_GT_32BIT
163 ULongToPtr(a->rx_stream[Id] + a->rx_pos[Id]),
164#else
165 (void*)(a->rx_stream[Id] + a->rx_pos[Id]),
166#endif
167 (dword*)&tmp[0],
168 1);
169 if (tmp[1] > max_length) {
170 if (to_read < 0)
171 return (-2); /* was not able to read */
172 break;
173 }
174 if (!(tmp[0] & DIVA_DFIFO_READY)) {
175 if (to_read < 0)
176 return (-1); /* was not able to read */
177 break;
178 }
179 to_read = MIN(max_length, tmp[1]);
180 if (to_read) {
181 a->ram_in_buffer(a,
182#ifdef PLATFORM_GT_32BIT
183 ULongToPtr(a->rx_stream[Id] + a->rx_pos[Id] + 4),
184#else
185 (void*)(a->rx_stream[Id] + a->rx_pos[Id] + 4),
186#endif
187 data_ptr,
188 (word)to_read);
189 max_length -= to_read;
190 read += to_read;
191 data_ptr += to_read;
192 }
193 if (tmp[0] & DIVA_DFIFO_LAST) {
194 *final = 1;
195 }
196 tmp[0] &= DIVA_DFIFO_WRAP;
197 a->ram_out_dw(a,
198#ifdef PLATFORM_GT_32BIT
199 ULongToPtr(a->rx_stream[Id] + a->rx_pos[Id]),
200#else
201 (void*)(a->rx_stream[Id] + a->rx_pos[Id]),
202#endif
203 (dword*)&tmp[0],
204 1);
205 if (tmp[0] & DIVA_DFIFO_WRAP) {
206 a->rx_pos[Id] = 0;
207 } else {
208 a->rx_pos[Id] += DIVA_DFIFO_STEP;
209 }
210 if (*final) {
211 if (usr1)
212 *usr1 = tmp[2];
213 if (usr2)
214 *usr2 = tmp[3];
215 break;
216 }
217 }
218 return (read);
219}
220/* ---------------------------------------------------------------------
221 Does check if one of streams had caused interrupt and does
222 wake up corresponding application
223 --------------------------------------------------------------------- */
224void pr_stream (ADAPTER * a) {
225}
226#endif /* } */
diff --git a/drivers/isdn/hardware/eicon/kst_ifc.h b/drivers/isdn/hardware/eicon/kst_ifc.h
new file mode 100644
index 000000000000..203189a010c2
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/kst_ifc.h
@@ -0,0 +1,336 @@
1/*
2 *
3 Copyright (c) Eicon Networks, 2000.
4 *
5 This source file is supplied for the use with
6 Eicon Networks range of DIVA Server Adapters.
7 *
8 Eicon File Revision : 1.9
9 *
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2, or (at your option)
13 any later version.
14 *
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
17 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18 See the GNU General Public License for more details.
19 *
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 */
25#ifndef __DIVA_EICON_TRACE_API__
26#define __DIVA_EICON_TRACE_API__
27
28#define DIVA_TRACE_LINE_TYPE_LEN 64
29#define DIVA_TRACE_IE_LEN 64
30#define DIVA_TRACE_FAX_PRMS_LEN 128
31
32typedef struct _diva_trace_ie {
33 byte length;
34 byte data[DIVA_TRACE_IE_LEN];
35} diva_trace_ie_t;
36
37/*
38 Structure used to represent "State\\BX\\Modem" directory
39 to user.
40 */
41typedef struct _diva_trace_modem_state {
42 dword ChannelNumber;
43
44 dword Event;
45
46 dword Norm;
47
48 dword Options; /* Options received from Application */
49
50 dword TxSpeed;
51 dword RxSpeed;
52
53 dword RoundtripMsec;
54
55 dword SymbolRate;
56
57 int RxLeveldBm;
58 int EchoLeveldBm;
59
60 dword SNRdb;
61 dword MAE;
62
63 dword LocalRetrains;
64 dword RemoteRetrains;
65 dword LocalResyncs;
66 dword RemoteResyncs;
67
68 dword DiscReason;
69
70} diva_trace_modem_state_t;
71
72/*
73 Representation of "State\\BX\\FAX" directory
74 */
75typedef struct _diva_trace_fax_state {
76 dword ChannelNumber;
77 dword Event;
78 dword Page_Counter;
79 dword Features;
80 char Station_ID[DIVA_TRACE_FAX_PRMS_LEN];
81 char Subaddress[DIVA_TRACE_FAX_PRMS_LEN];
82 char Password[DIVA_TRACE_FAX_PRMS_LEN];
83 dword Speed;
84 dword Resolution;
85 dword Paper_Width;
86 dword Paper_Length;
87 dword Scanline_Time;
88 dword Disc_Reason;
89 dword dummy;
90} diva_trace_fax_state_t;
91
92/*
93 Structure used to represent Interface State in the abstract
94 and interface/D-channel protocol independent form.
95 */
96typedef struct _diva_trace_interface_state {
97 char Layer1[DIVA_TRACE_LINE_TYPE_LEN];
98 char Layer2[DIVA_TRACE_LINE_TYPE_LEN];
99} diva_trace_interface_state_t;
100
101typedef struct _diva_incoming_call_statistics {
102 dword Calls;
103 dword Connected;
104 dword User_Busy;
105 dword Call_Rejected;
106 dword Wrong_Number;
107 dword Incompatible_Dst;
108 dword Out_of_Order;
109 dword Ignored;
110} diva_incoming_call_statistics_t;
111
112typedef struct _diva_outgoing_call_statistics {
113 dword Calls;
114 dword Connected;
115 dword User_Busy;
116 dword No_Answer;
117 dword Wrong_Number;
118 dword Call_Rejected;
119 dword Other_Failures;
120} diva_outgoing_call_statistics_t;
121
122typedef struct _diva_modem_call_statistics {
123 dword Disc_Normal;
124 dword Disc_Unspecified;
125 dword Disc_Busy_Tone;
126 dword Disc_Congestion;
127 dword Disc_Carr_Wait;
128 dword Disc_Trn_Timeout;
129 dword Disc_Incompat;
130 dword Disc_Frame_Rej;
131 dword Disc_V42bis;
132} diva_modem_call_statistics_t;
133
134typedef struct _diva_fax_call_statistics {
135 dword Disc_Normal;
136 dword Disc_Not_Ident;
137 dword Disc_No_Response;
138 dword Disc_Retries;
139 dword Disc_Unexp_Msg;
140 dword Disc_No_Polling;
141 dword Disc_Training;
142 dword Disc_Unexpected;
143 dword Disc_Application;
144 dword Disc_Incompat;
145 dword Disc_No_Command;
146 dword Disc_Long_Msg;
147 dword Disc_Supervisor;
148 dword Disc_SUB_SEP_PWD;
149 dword Disc_Invalid_Msg;
150 dword Disc_Page_Coding;
151 dword Disc_App_Timeout;
152 dword Disc_Unspecified;
153} diva_fax_call_statistics_t;
154
155typedef struct _diva_prot_statistics {
156 dword X_Frames;
157 dword X_Bytes;
158 dword X_Errors;
159 dword R_Frames;
160 dword R_Bytes;
161 dword R_Errors;
162} diva_prot_statistics_t;
163
164typedef struct _diva_ifc_statistics {
165 diva_incoming_call_statistics_t inc;
166 diva_outgoing_call_statistics_t outg;
167 diva_modem_call_statistics_t mdm;
168 diva_fax_call_statistics_t fax;
169 diva_prot_statistics_t b1;
170 diva_prot_statistics_t b2;
171 diva_prot_statistics_t d1;
172 diva_prot_statistics_t d2;
173} diva_ifc_statistics_t;
174
175/*
176 Structure used to represent "State\\BX" directory
177 to user.
178 */
179typedef struct _diva_trace_line_state {
180 dword ChannelNumber;
181
182 char Line[DIVA_TRACE_LINE_TYPE_LEN];
183
184 char Framing[DIVA_TRACE_LINE_TYPE_LEN];
185
186 char Layer2[DIVA_TRACE_LINE_TYPE_LEN];
187 char Layer3[DIVA_TRACE_LINE_TYPE_LEN];
188
189 char RemoteAddress[DIVA_TRACE_LINE_TYPE_LEN];
190 char RemoteSubAddress[DIVA_TRACE_LINE_TYPE_LEN];
191
192 char LocalAddress[DIVA_TRACE_LINE_TYPE_LEN];
193 char LocalSubAddress[DIVA_TRACE_LINE_TYPE_LEN];
194
195 diva_trace_ie_t call_BC;
196 diva_trace_ie_t call_HLC;
197 diva_trace_ie_t call_LLC;
198
199 dword Charges;
200
201 dword CallReference;
202
203 dword LastDisconnecCause;
204
205 char UserID[DIVA_TRACE_LINE_TYPE_LEN];
206
207 diva_trace_modem_state_t modem;
208 diva_trace_fax_state_t fax;
209
210 diva_trace_interface_state_t* pInterface;
211
212 diva_ifc_statistics_t* pInterfaceStat;
213
214} diva_trace_line_state_t;
215
216#define DIVA_SUPER_TRACE_NOTIFY_LINE_CHANGE ('l')
217#define DIVA_SUPER_TRACE_NOTIFY_MODEM_CHANGE ('m')
218#define DIVA_SUPER_TRACE_NOTIFY_FAX_CHANGE ('f')
219#define DIVA_SUPER_TRACE_INTERFACE_CHANGE ('i')
220#define DIVA_SUPER_TRACE_NOTIFY_STAT_CHANGE ('s')
221#define DIVA_SUPER_TRACE_NOTIFY_MDM_STAT_CHANGE ('M')
222#define DIVA_SUPER_TRACE_NOTIFY_FAX_STAT_CHANGE ('F')
223
224struct _diva_strace_library_interface;
225typedef void (*diva_trace_channel_state_change_proc_t)(void* user_context,
226 struct _diva_strace_library_interface* hLib,
227 int Adapter,
228 diva_trace_line_state_t* channel, int notify_subject);
229typedef void (*diva_trace_channel_trace_proc_t)(void* user_context,
230 struct _diva_strace_library_interface* hLib,
231 int Adapter, void* xlog_buffer, int length);
232typedef void (*diva_trace_error_proc_t)(void* user_context,
233 struct _diva_strace_library_interface* hLib,
234 int Adapter,
235 int error, const char* file, int line);
236
237/*
238 This structure creates interface from user to library
239 */
240typedef struct _diva_trace_library_user_interface {
241 void* user_context;
242 diva_trace_channel_state_change_proc_t notify_proc;
243 diva_trace_channel_trace_proc_t trace_proc;
244 diva_trace_error_proc_t error_notify_proc;
245} diva_trace_library_user_interface_t;
246
247/*
248 Interface from Library to User
249 */
250typedef int (*DivaSTraceLibraryStart_proc_t)(void* hLib);
251typedef int (*DivaSTraceLibraryFinit_proc_t)(void* hLib);
252typedef int (*DivaSTraceMessageInput_proc_t)(void* hLib);
253typedef void* (*DivaSTraceGetHandle_proc_t)(void* hLib);
254
255/*
256 Turn Audio Tap trace on/off
257 Channel should be in the range 1 ... Number of Channels
258 */
259typedef int (*DivaSTraceSetAudioTap_proc_t)(void* hLib, int Channel, int on);
260
261/*
262 Turn B-channel trace on/off
263 Channel should be in the range 1 ... Number of Channels
264 */
265typedef int (*DivaSTraceSetBChannel_proc_t)(void* hLib, int Channel, int on);
266
267/*
268 Turn D-channel (Layer1/Layer2/Layer3) trace on/off
269 Layer1 - All D-channel frames received/sent over the interface
270 inclusive Layer 2 headers, Layer 2 frames and TEI management frames
271 Layer2 - Events from LAPD protocol instance with SAPI of signalling protocol
272 Layer3 - All D-channel frames addressed to assigned to the card TEI and
273 SAPI of signalling protocol, and signalling protocol events.
274 */
275typedef int (*DivaSTraceSetDChannel_proc_t)(void* hLib, int on);
276
277/*
278 Get overall card statistics
279 */
280typedef int (*DivaSTraceGetOutgoingCallStatistics_proc_t)(void* hLib);
281typedef int (*DivaSTraceGetIncomingCallStatistics_proc_t)(void* hLib);
282typedef int (*DivaSTraceGetModemStatistics_proc_t)(void* hLib);
283typedef int (*DivaSTraceGetFaxStatistics_proc_t)(void* hLib);
284typedef int (*DivaSTraceGetBLayer1Statistics_proc_t)(void* hLib);
285typedef int (*DivaSTraceGetBLayer2Statistics_proc_t)(void* hLib);
286typedef int (*DivaSTraceGetDLayer1Statistics_proc_t)(void* hLib);
287typedef int (*DivaSTraceGetDLayer2Statistics_proc_t)(void* hLib);
288
289/*
290 Call control
291 */
292typedef int (*DivaSTraceClearCall_proc_t)(void* hLib, int Channel);
293
294typedef struct _diva_strace_library_interface {
295 void* hLib;
296 DivaSTraceLibraryStart_proc_t DivaSTraceLibraryStart;
297 DivaSTraceLibraryStart_proc_t DivaSTraceLibraryStop;
298 DivaSTraceLibraryFinit_proc_t DivaSTraceLibraryFinit;
299 DivaSTraceMessageInput_proc_t DivaSTraceMessageInput;
300 DivaSTraceGetHandle_proc_t DivaSTraceGetHandle;
301 DivaSTraceSetAudioTap_proc_t DivaSTraceSetAudioTap;
302 DivaSTraceSetBChannel_proc_t DivaSTraceSetBChannel;
303 DivaSTraceSetDChannel_proc_t DivaSTraceSetDChannel;
304 DivaSTraceSetDChannel_proc_t DivaSTraceSetInfo;
305 DivaSTraceGetOutgoingCallStatistics_proc_t \
306 DivaSTraceGetOutgoingCallStatistics;
307 DivaSTraceGetIncomingCallStatistics_proc_t \
308 DivaSTraceGetIncomingCallStatistics;
309 DivaSTraceGetModemStatistics_proc_t \
310 DivaSTraceGetModemStatistics;
311 DivaSTraceGetFaxStatistics_proc_t \
312 DivaSTraceGetFaxStatistics;
313 DivaSTraceGetBLayer1Statistics_proc_t \
314 DivaSTraceGetBLayer1Statistics;
315 DivaSTraceGetBLayer2Statistics_proc_t \
316 DivaSTraceGetBLayer2Statistics;
317 DivaSTraceGetDLayer1Statistics_proc_t \
318 DivaSTraceGetDLayer1Statistics;
319 DivaSTraceGetDLayer2Statistics_proc_t \
320 DivaSTraceGetDLayer2Statistics;
321 DivaSTraceClearCall_proc_t DivaSTraceClearCall;
322} diva_strace_library_interface_t;
323
324/*
325 Create and return Library interface
326 */
327diva_strace_library_interface_t* DivaSTraceLibraryCreateInstance (int Adapter,
328 const diva_trace_library_user_interface_t* user_proc,
329 byte* pmem);
330dword DivaSTraceGetMemotyRequirement (int channels);
331
332#define DIVA_MAX_ADAPTERS 64
333#define DIVA_MAX_LINES 32
334
335#endif
336
diff --git a/drivers/isdn/hardware/eicon/main_if.h b/drivers/isdn/hardware/eicon/main_if.h
new file mode 100644
index 000000000000..0ea339afd424
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/main_if.h
@@ -0,0 +1,50 @@
1/*
2 *
3 Copyright (c) Eicon Technology Corporation, 2000.
4 *
5 This source file is supplied for the use with Eicon
6 Technology Corporation's range of DIVA Server Adapters.
7 *
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2, or (at your option)
11 any later version.
12 *
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
15 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16 See the GNU General Public License for more details.
17 *
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 *
22 */
23/*------------------------------------------------------------------*/
24/* file: main_if.h */
25/*------------------------------------------------------------------*/
26# ifndef MAIN_IF___H
27# define MAIN_IF___H
28
29# include "debug_if.h"
30
31void DI_lock (void) ;
32void DI_unlock (void) ;
33
34#ifdef NOT_YET_NEEDED
35void DI_nttime (LARGE_INTEGER *NTtime) ;
36void DI_ntlcltime(LARGE_INTEGER *NTtime, LARGE_INTEGER *lclNTtime) ;
37void DI_nttimefields(LARGE_INTEGER *NTtime, TIME_FIELDS *TimeFields);
38unsigned long DI_wintime(LARGE_INTEGER *NTtime) ;
39
40unsigned short DiInsertProcessorNumber (int type) ;
41void DiProcessEventLog (unsigned short id, unsigned long msgID, va_list ap);
42
43void StartIoctlTimer (void (*Handler)(void), unsigned long msec) ;
44void StopIoctlTimer (void) ;
45void UnpendIoctl (DbgRequest *pDbgReq) ;
46#endif
47
48void add_to_q(int, char* , unsigned int);
49# endif /* MAIN_IF___H */
50
diff --git a/drivers/isdn/hardware/eicon/maintidi.c b/drivers/isdn/hardware/eicon/maintidi.c
new file mode 100644
index 000000000000..23960cb6eaab
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/maintidi.c
@@ -0,0 +1,2194 @@
1/*
2 *
3 Copyright (c) Eicon Networks, 2000.
4 *
5 This source file is supplied for the use with
6 Eicon Networks range of DIVA Server Adapters.
7 *
8 Eicon File Revision : 1.9
9 *
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2, or (at your option)
13 any later version.
14 *
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
17 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18 See the GNU General Public License for more details.
19 *
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 */
25#include "platform.h"
26#include "kst_ifc.h"
27#include "di_defs.h"
28#include "maintidi.h"
29#include "pc.h"
30#include "man_defs.h"
31
32
33extern void diva_mnt_internal_dprintf (dword drv_id, dword type, char* p, ...);
34
35#define MODEM_PARSE_ENTRIES 16 /* amount of variables of interest */
36#define FAX_PARSE_ENTRIES 12 /* amount of variables of interest */
37#define LINE_PARSE_ENTRIES 15 /* amount of variables of interest */
38#define STAT_PARSE_ENTRIES 70 /* amount of variables of interest */
39
40/*
41 LOCAL FUNCTIONS
42 */
43static int DivaSTraceLibraryStart (void* hLib);
44static int DivaSTraceLibraryStop (void* hLib);
45static int SuperTraceLibraryFinit (void* hLib);
46static void* SuperTraceGetHandle (void* hLib);
47static int SuperTraceMessageInput (void* hLib);
48static int SuperTraceSetAudioTap (void* hLib, int Channel, int on);
49static int SuperTraceSetBChannel (void* hLib, int Channel, int on);
50static int SuperTraceSetDChannel (void* hLib, int on);
51static int SuperTraceSetInfo (void* hLib, int on);
52static int SuperTraceClearCall (void* hLib, int Channel);
53static int SuperTraceGetOutgoingCallStatistics (void* hLib);
54static int SuperTraceGetIncomingCallStatistics (void* hLib);
55static int SuperTraceGetModemStatistics (void* hLib);
56static int SuperTraceGetFaxStatistics (void* hLib);
57static int SuperTraceGetBLayer1Statistics (void* hLib);
58static int SuperTraceGetBLayer2Statistics (void* hLib);
59static int SuperTraceGetDLayer1Statistics (void* hLib);
60static int SuperTraceGetDLayer2Statistics (void* hLib);
61
62/*
63 LOCAL FUNCTIONS
64 */
65static int ScheduleNextTraceRequest (diva_strace_context_t* pLib);
66static int process_idi_event (diva_strace_context_t* pLib,
67 diva_man_var_header_t* pVar);
68static int process_idi_info (diva_strace_context_t* pLib,
69 diva_man_var_header_t* pVar);
70static int diva_modem_event (diva_strace_context_t* pLib, int Channel);
71static int diva_fax_event (diva_strace_context_t* pLib, int Channel);
72static int diva_line_event (diva_strace_context_t* pLib, int Channel);
73static int diva_modem_info (diva_strace_context_t* pLib,
74 int Channel,
75 diva_man_var_header_t* pVar);
76static int diva_fax_info (diva_strace_context_t* pLib,
77 int Channel,
78 diva_man_var_header_t* pVar);
79static int diva_line_info (diva_strace_context_t* pLib,
80 int Channel,
81 diva_man_var_header_t* pVar);
82static int diva_ifc_statistics (diva_strace_context_t* pLib,
83 diva_man_var_header_t* pVar);
84static diva_man_var_header_t* get_next_var (diva_man_var_header_t* pVar);
85static diva_man_var_header_t* find_var (diva_man_var_header_t* pVar,
86 const char* name);
87static int diva_strace_read_int (diva_man_var_header_t* pVar, int* var);
88static int diva_strace_read_uint (diva_man_var_header_t* pVar, dword* var);
89static int diva_strace_read_asz (diva_man_var_header_t* pVar, char* var);
90static int diva_strace_read_asc (diva_man_var_header_t* pVar, char* var);
91static int diva_strace_read_ie (diva_man_var_header_t* pVar,
92 diva_trace_ie_t* var);
93static void diva_create_parse_table (diva_strace_context_t* pLib);
94static void diva_trace_error (diva_strace_context_t* pLib,
95 int error, const char* file, int line);
96static void diva_trace_notify_user (diva_strace_context_t* pLib,
97 int Channel,
98 int notify_subject);
99static int diva_trace_read_variable (diva_man_var_header_t* pVar,
100 void* variable);
101
102/*
103 Initialize the library and return context
104 of the created trace object that will represent
105 the IDI adapter.
106 Return 0 on error.
107 */
108diva_strace_library_interface_t* DivaSTraceLibraryCreateInstance (int Adapter,
109 const diva_trace_library_user_interface_t* user_proc,
110 byte* pmem) {
111 diva_strace_context_t* pLib = (diva_strace_context_t*)pmem;
112 int i;
113
114 if (!pLib) {
115 return NULL;
116 }
117
118 pmem += sizeof(*pLib);
119 memset(pLib, 0x00, sizeof(*pLib));
120
121 pLib->Adapter = Adapter;
122
123 /*
124 Set up Library Interface
125 */
126 pLib->instance.hLib = pLib;
127 pLib->instance.DivaSTraceLibraryStart = DivaSTraceLibraryStart;
128 pLib->instance.DivaSTraceLibraryStop = DivaSTraceLibraryStop;
129 pLib->instance.DivaSTraceLibraryFinit = SuperTraceLibraryFinit;
130 pLib->instance.DivaSTraceMessageInput = SuperTraceMessageInput;
131 pLib->instance.DivaSTraceGetHandle = SuperTraceGetHandle;
132 pLib->instance.DivaSTraceSetAudioTap = SuperTraceSetAudioTap;
133 pLib->instance.DivaSTraceSetBChannel = SuperTraceSetBChannel;
134 pLib->instance.DivaSTraceSetDChannel = SuperTraceSetDChannel;
135 pLib->instance.DivaSTraceSetInfo = SuperTraceSetInfo;
136 pLib->instance.DivaSTraceGetOutgoingCallStatistics = \
137 SuperTraceGetOutgoingCallStatistics;
138 pLib->instance.DivaSTraceGetIncomingCallStatistics = \
139 SuperTraceGetIncomingCallStatistics;
140 pLib->instance.DivaSTraceGetModemStatistics = \
141 SuperTraceGetModemStatistics;
142 pLib->instance.DivaSTraceGetFaxStatistics = \
143 SuperTraceGetFaxStatistics;
144 pLib->instance.DivaSTraceGetBLayer1Statistics = \
145 SuperTraceGetBLayer1Statistics;
146 pLib->instance.DivaSTraceGetBLayer2Statistics = \
147 SuperTraceGetBLayer2Statistics;
148 pLib->instance.DivaSTraceGetDLayer1Statistics = \
149 SuperTraceGetDLayer1Statistics;
150 pLib->instance.DivaSTraceGetDLayer2Statistics = \
151 SuperTraceGetDLayer2Statistics;
152 pLib->instance.DivaSTraceClearCall = SuperTraceClearCall;
153
154
155 if (user_proc) {
156 pLib->user_proc_table.user_context = user_proc->user_context;
157 pLib->user_proc_table.notify_proc = user_proc->notify_proc;
158 pLib->user_proc_table.trace_proc = user_proc->trace_proc;
159 pLib->user_proc_table.error_notify_proc = user_proc->error_notify_proc;
160 }
161
162 if (!(pLib->hAdapter = SuperTraceOpenAdapter (Adapter))) {
163 diva_mnt_internal_dprintf (0, DLI_ERR, "Can not open XDI adapter");
164 return NULL;
165 }
166 pLib->Channels = SuperTraceGetNumberOfChannels (pLib->hAdapter);
167
168 /*
169 Calculate amount of parte table entites necessary to translate
170 information from all events of onterest
171 */
172 pLib->parse_entries = (MODEM_PARSE_ENTRIES + FAX_PARSE_ENTRIES + \
173 STAT_PARSE_ENTRIES + \
174 LINE_PARSE_ENTRIES + 1) * pLib->Channels;
175 pLib->parse_table = (diva_strace_path2action_t*)pmem;
176
177 for (i = 0; i < 30; i++) {
178 pLib->lines[i].pInterface = &pLib->Interface;
179 pLib->lines[i].pInterfaceStat = &pLib->InterfaceStat;
180 }
181
182 pLib->e.R = &pLib->RData;
183
184 pLib->req_busy = 1;
185 pLib->rc_ok = ASSIGN_OK;
186
187 diva_create_parse_table (pLib);
188
189 return ((diva_strace_library_interface_t*)pLib);
190}
191
192static int DivaSTraceLibraryStart (void* hLib) {
193 diva_strace_context_t* pLib = (diva_strace_context_t*)hLib;
194
195 return (SuperTraceASSIGN (pLib->hAdapter, pLib->buffer));
196}
197
198/*
199 Return (-1) on error
200 Return (0) if was initiated or pending
201 Return (1) if removal is complete
202 */
203static int DivaSTraceLibraryStop (void* hLib) {
204 diva_strace_context_t* pLib = (diva_strace_context_t*)hLib;
205
206 if (!pLib->e.Id) { /* Was never started/assigned */
207 return (1);
208 }
209
210 switch (pLib->removal_state) {
211 case 0:
212 pLib->removal_state = 1;
213 ScheduleNextTraceRequest(pLib);
214 break;
215
216 case 3:
217 return (1);
218 }
219
220 return (0);
221}
222
223static int SuperTraceLibraryFinit (void* hLib) {
224 diva_strace_context_t* pLib = (diva_strace_context_t*)hLib;
225 if (pLib) {
226 if (pLib->hAdapter) {
227 SuperTraceCloseAdapter (pLib->hAdapter);
228 }
229 return (0);
230 }
231 return (-1);
232}
233
234static void* SuperTraceGetHandle (void* hLib) {
235 diva_strace_context_t* pLib = (diva_strace_context_t*)hLib;
236
237 return (&pLib->e);
238}
239
240/*
241 After library handle object is gone in signaled state
242 this function should be called and will pick up incoming
243 IDI messages (return codes and indications).
244 */
245static int SuperTraceMessageInput (void* hLib) {
246 diva_strace_context_t* pLib = (diva_strace_context_t*)hLib;
247 int ret = 0;
248 byte Rc, Ind;
249
250 if (pLib->e.complete == 255) {
251 /*
252 Process return code
253 */
254 pLib->req_busy = 0;
255 Rc = pLib->e.Rc;
256 pLib->e.Rc = 0;
257
258 if (pLib->removal_state == 2) {
259 pLib->removal_state = 3;
260 return (0);
261 }
262
263 if (Rc != pLib->rc_ok) {
264 int ignore = 0;
265 /*
266 Auto-detect amount of events/channels and features
267 */
268 if (pLib->general_b_ch_event == 1) {
269 pLib->general_b_ch_event = 2;
270 ignore = 1;
271 } else if (pLib->general_fax_event == 1) {
272 pLib->general_fax_event = 2;
273 ignore = 1;
274 } else if (pLib->general_mdm_event == 1) {
275 pLib->general_mdm_event = 2;
276 ignore = 1;
277 } else if ((pLib->ChannelsTraceActive < pLib->Channels) && pLib->ChannelsTraceActive) {
278 pLib->ChannelsTraceActive = pLib->Channels;
279 ignore = 1;
280 } else if (pLib->ModemTraceActive < pLib->Channels) {
281 pLib->ModemTraceActive = pLib->Channels;
282 ignore = 1;
283 } else if (pLib->FaxTraceActive < pLib->Channels) {
284 pLib->FaxTraceActive = pLib->Channels;
285 ignore = 1;
286 } else if (pLib->audio_trace_init == 2) {
287 ignore = 1;
288 pLib->audio_trace_init = 1;
289 } else if (pLib->eye_pattern_pending) {
290 pLib->eye_pattern_pending = 0;
291 ignore = 1;
292 } else if (pLib->audio_tap_pending) {
293 pLib->audio_tap_pending = 0;
294 ignore = 1;
295 }
296
297 if (!ignore) {
298 return (-1); /* request failed */
299 }
300 } else {
301 if (pLib->general_b_ch_event == 1) {
302 pLib->ChannelsTraceActive = pLib->Channels;
303 pLib->general_b_ch_event = 2;
304 } else if (pLib->general_fax_event == 1) {
305 pLib->general_fax_event = 2;
306 pLib->FaxTraceActive = pLib->Channels;
307 } else if (pLib->general_mdm_event == 1) {
308 pLib->general_mdm_event = 2;
309 pLib->ModemTraceActive = pLib->Channels;
310 }
311 }
312 if (pLib->audio_trace_init == 2) {
313 pLib->audio_trace_init = 1;
314 }
315 pLib->rc_ok = 0xff; /* default OK after assign was done */
316 if ((ret = ScheduleNextTraceRequest(pLib))) {
317 return (-1);
318 }
319 } else {
320 /*
321 Process indication
322 Always 'RNR' indication if return code is pending
323 */
324 Ind = pLib->e.Ind;
325 pLib->e.Ind = 0;
326 if (pLib->removal_state) {
327 pLib->e.RNum = 0;
328 pLib->e.RNR = 2;
329 } else if (pLib->req_busy) {
330 pLib->e.RNum = 0;
331 pLib->e.RNR = 1;
332 } else {
333 if (pLib->e.complete != 0x02) {
334 /*
335 Look-ahead call, set up buffers
336 */
337 pLib->e.RNum = 1;
338 pLib->e.R->P = (byte*)&pLib->buffer[0];
339 pLib->e.R->PLength = (word)(sizeof(pLib->buffer) - 1);
340
341 } else {
342 /*
343 Indication reception complete, process it now
344 */
345 byte* p = (byte*)&pLib->buffer[0];
346 pLib->buffer[pLib->e.R->PLength] = 0; /* terminate I.E. with zero */
347
348 switch (Ind) {
349 case MAN_COMBI_IND: {
350 int total_length = pLib->e.R->PLength;
351 word this_ind_length;
352
353 while (total_length > 3 && *p) {
354 Ind = *p++;
355 this_ind_length = (word)p[0] | ((word)p[1] << 8);
356 p += 2;
357
358 switch (Ind) {
359 case MAN_INFO_IND:
360 if (process_idi_info (pLib, (diva_man_var_header_t*)p)) {
361 return (-1);
362 }
363 break;
364 case MAN_EVENT_IND:
365 if (process_idi_event (pLib, (diva_man_var_header_t*)p)) {
366 return (-1);
367 }
368 break;
369 case MAN_TRACE_IND:
370 if (pLib->trace_on == 1) {
371 /*
372 Ignore first trace event that is result of
373 EVENT_ON operation
374 */
375 pLib->trace_on++;
376 } else {
377 /*
378 Delivery XLOG buffer to application
379 */
380 if (pLib->user_proc_table.trace_proc) {
381 (*(pLib->user_proc_table.trace_proc))(pLib->user_proc_table.user_context,
382 &pLib->instance, pLib->Adapter,
383 p, this_ind_length);
384 }
385 }
386 break;
387 default:
388 diva_mnt_internal_dprintf (0, DLI_ERR, "Unknon IDI Ind (DMA mode): %02x", Ind);
389 }
390 p += (this_ind_length+1);
391 total_length -= (4 + this_ind_length);
392 }
393 } break;
394 case MAN_INFO_IND:
395 if (process_idi_info (pLib, (diva_man_var_header_t*)p)) {
396 return (-1);
397 }
398 break;
399 case MAN_EVENT_IND:
400 if (process_idi_event (pLib, (diva_man_var_header_t*)p)) {
401 return (-1);
402 }
403 break;
404 case MAN_TRACE_IND:
405 if (pLib->trace_on == 1) {
406 /*
407 Ignore first trace event that is result of
408 EVENT_ON operation
409 */
410 pLib->trace_on++;
411 } else {
412 /*
413 Delivery XLOG buffer to application
414 */
415 if (pLib->user_proc_table.trace_proc) {
416 (*(pLib->user_proc_table.trace_proc))(pLib->user_proc_table.user_context,
417 &pLib->instance, pLib->Adapter,
418 p, pLib->e.R->PLength);
419 }
420 }
421 break;
422 default:
423 diva_mnt_internal_dprintf (0, DLI_ERR, "Unknon IDI Ind: %02x", Ind);
424 }
425 }
426 }
427 }
428
429 if ((ret = ScheduleNextTraceRequest(pLib))) {
430 return (-1);
431 }
432
433 return (ret);
434}
435
436/*
437 Internal state machine responsible for scheduling of requests
438 */
439static int ScheduleNextTraceRequest (diva_strace_context_t* pLib) {
440 char name[64];
441 int ret = 0;
442 int i;
443
444 if (pLib->req_busy) {
445 return (0);
446 }
447
448 if (pLib->removal_state == 1) {
449 if (SuperTraceREMOVE (pLib->hAdapter)) {
450 pLib->removal_state = 3;
451 } else {
452 pLib->req_busy = 1;
453 pLib->removal_state = 2;
454 }
455 return (0);
456 }
457
458 if (pLib->removal_state) {
459 return (0);
460 }
461
462 if (!pLib->general_b_ch_event) {
463 if ((ret = SuperTraceTraceOnRequest(pLib->hAdapter, "State\\B Event", pLib->buffer))) {
464 return (-1);
465 }
466 pLib->general_b_ch_event = 1;
467 pLib->req_busy = 1;
468 return (0);
469 }
470
471 if (!pLib->general_fax_event) {
472 if ((ret = SuperTraceTraceOnRequest(pLib->hAdapter, "State\\FAX Event", pLib->buffer))) {
473 return (-1);
474 }
475 pLib->general_fax_event = 1;
476 pLib->req_busy = 1;
477 return (0);
478 }
479
480 if (!pLib->general_mdm_event) {
481 if ((ret = SuperTraceTraceOnRequest(pLib->hAdapter, "State\\Modem Event", pLib->buffer))) {
482 return (-1);
483 }
484 pLib->general_mdm_event = 1;
485 pLib->req_busy = 1;
486 return (0);
487 }
488
489 if (pLib->ChannelsTraceActive < pLib->Channels) {
490 pLib->ChannelsTraceActive++;
491 sprintf (name, "State\\B%d\\Line", pLib->ChannelsTraceActive);
492 if ((ret = SuperTraceTraceOnRequest(pLib->hAdapter, name, pLib->buffer))) {
493 pLib->ChannelsTraceActive--;
494 return (-1);
495 }
496 pLib->req_busy = 1;
497 return (0);
498 }
499
500 if (pLib->ModemTraceActive < pLib->Channels) {
501 pLib->ModemTraceActive++;
502 sprintf (name, "State\\B%d\\Modem\\Event", pLib->ModemTraceActive);
503 if ((ret = SuperTraceTraceOnRequest(pLib->hAdapter, name, pLib->buffer))) {
504 pLib->ModemTraceActive--;
505 return (-1);
506 }
507 pLib->req_busy = 1;
508 return (0);
509 }
510
511 if (pLib->FaxTraceActive < pLib->Channels) {
512 pLib->FaxTraceActive++;
513 sprintf (name, "State\\B%d\\FAX\\Event", pLib->FaxTraceActive);
514 if ((ret = SuperTraceTraceOnRequest(pLib->hAdapter, name, pLib->buffer))) {
515 pLib->FaxTraceActive--;
516 return (-1);
517 }
518 pLib->req_busy = 1;
519 return (0);
520 }
521
522 if (!pLib->trace_mask_init) {
523 word tmp = 0x0000;
524 if (SuperTraceWriteVar (pLib->hAdapter,
525 pLib->buffer,
526 "Trace\\Event Enable",
527 &tmp,
528 0x87, /* MI_BITFLD */
529 sizeof(tmp))) {
530 return (-1);
531 }
532 pLib->trace_mask_init = 1;
533 pLib->req_busy = 1;
534 return (0);
535 }
536
537 if (!pLib->audio_trace_init) {
538 dword tmp = 0x00000000;
539 if (SuperTraceWriteVar (pLib->hAdapter,
540 pLib->buffer,
541 "Trace\\AudioCh# Enable",
542 &tmp,
543 0x87, /* MI_BITFLD */
544 sizeof(tmp))) {
545 return (-1);
546 }
547 pLib->audio_trace_init = 2;
548 pLib->req_busy = 1;
549 return (0);
550 }
551
552 if (!pLib->bchannel_init) {
553 dword tmp = 0x00000000;
554 if (SuperTraceWriteVar (pLib->hAdapter,
555 pLib->buffer,
556 "Trace\\B-Ch# Enable",
557 &tmp,
558 0x87, /* MI_BITFLD */
559 sizeof(tmp))) {
560 return (-1);
561 }
562 pLib->bchannel_init = 1;
563 pLib->req_busy = 1;
564 return (0);
565 }
566
567 if (!pLib->trace_length_init) {
568 word tmp = 30;
569 if (SuperTraceWriteVar (pLib->hAdapter,
570 pLib->buffer,
571 "Trace\\Max Log Length",
572 &tmp,
573 0x82, /* MI_UINT */
574 sizeof(tmp))) {
575 return (-1);
576 }
577 pLib->trace_length_init = 1;
578 pLib->req_busy = 1;
579 return (0);
580 }
581
582 if (!pLib->trace_on) {
583 if (SuperTraceTraceOnRequest (pLib->hAdapter,
584 "Trace\\Log Buffer",
585 pLib->buffer)) {
586 return (-1);
587 }
588 pLib->trace_on = 1;
589 pLib->req_busy = 1;
590 return (0);
591 }
592
593 if (pLib->trace_event_mask != pLib->current_trace_event_mask) {
594 if (SuperTraceWriteVar (pLib->hAdapter,
595 pLib->buffer,
596 "Trace\\Event Enable",
597 &pLib->trace_event_mask,
598 0x87, /* MI_BITFLD */
599 sizeof(pLib->trace_event_mask))) {
600 return (-1);
601 }
602 pLib->current_trace_event_mask = pLib->trace_event_mask;
603 pLib->req_busy = 1;
604 return (0);
605 }
606
607 if ((pLib->audio_tap_pending >= 0) && (pLib->audio_tap_mask != pLib->current_audio_tap_mask)) {
608 if (SuperTraceWriteVar (pLib->hAdapter,
609 pLib->buffer,
610 "Trace\\AudioCh# Enable",
611 &pLib->audio_tap_mask,
612 0x87, /* MI_BITFLD */
613 sizeof(pLib->audio_tap_mask))) {
614 return (-1);
615 }
616 pLib->current_audio_tap_mask = pLib->audio_tap_mask;
617 pLib->audio_tap_pending = 1;
618 pLib->req_busy = 1;
619 return (0);
620 }
621
622 if ((pLib->eye_pattern_pending >= 0) && (pLib->audio_tap_mask != pLib->current_eye_pattern_mask)) {
623 if (SuperTraceWriteVar (pLib->hAdapter,
624 pLib->buffer,
625 "Trace\\EyeCh# Enable",
626 &pLib->audio_tap_mask,
627 0x87, /* MI_BITFLD */
628 sizeof(pLib->audio_tap_mask))) {
629 return (-1);
630 }
631 pLib->current_eye_pattern_mask = pLib->audio_tap_mask;
632 pLib->eye_pattern_pending = 1;
633 pLib->req_busy = 1;
634 return (0);
635 }
636
637 if (pLib->bchannel_trace_mask != pLib->current_bchannel_trace_mask) {
638 if (SuperTraceWriteVar (pLib->hAdapter,
639 pLib->buffer,
640 "Trace\\B-Ch# Enable",
641 &pLib->bchannel_trace_mask,
642 0x87, /* MI_BITFLD */
643 sizeof(pLib->bchannel_trace_mask))) {
644 return (-1);
645 }
646 pLib->current_bchannel_trace_mask = pLib->bchannel_trace_mask;
647 pLib->req_busy = 1;
648 return (0);
649 }
650
651 if (!pLib->trace_events_down) {
652 if (SuperTraceTraceOnRequest (pLib->hAdapter,
653 "Events Down",
654 pLib->buffer)) {
655 return (-1);
656 }
657 pLib->trace_events_down = 1;
658 pLib->req_busy = 1;
659 return (0);
660 }
661
662 if (!pLib->l1_trace) {
663 if (SuperTraceTraceOnRequest (pLib->hAdapter,
664 "State\\Layer1",
665 pLib->buffer)) {
666 return (-1);
667 }
668 pLib->l1_trace = 1;
669 pLib->req_busy = 1;
670 return (0);
671 }
672
673 if (!pLib->l2_trace) {
674 if (SuperTraceTraceOnRequest (pLib->hAdapter,
675 "State\\Layer2 No1",
676 pLib->buffer)) {
677 return (-1);
678 }
679 pLib->l2_trace = 1;
680 pLib->req_busy = 1;
681 return (0);
682 }
683
684 for (i = 0; i < 30; i++) {
685 if (pLib->pending_line_status & (1L << i)) {
686 sprintf (name, "State\\B%d", i+1);
687 if (SuperTraceReadRequest (pLib->hAdapter, name, pLib->buffer)) {
688 return (-1);
689 }
690 pLib->pending_line_status &= ~(1L << i);
691 pLib->req_busy = 1;
692 return (0);
693 }
694 if (pLib->pending_modem_status & (1L << i)) {
695 sprintf (name, "State\\B%d\\Modem", i+1);
696 if (SuperTraceReadRequest (pLib->hAdapter, name, pLib->buffer)) {
697 return (-1);
698 }
699 pLib->pending_modem_status &= ~(1L << i);
700 pLib->req_busy = 1;
701 return (0);
702 }
703 if (pLib->pending_fax_status & (1L << i)) {
704 sprintf (name, "State\\B%d\\FAX", i+1);
705 if (SuperTraceReadRequest (pLib->hAdapter, name, pLib->buffer)) {
706 return (-1);
707 }
708 pLib->pending_fax_status &= ~(1L << i);
709 pLib->req_busy = 1;
710 return (0);
711 }
712 if (pLib->clear_call_command & (1L << i)) {
713 sprintf (name, "State\\B%d\\Clear Call", i+1);
714 if (SuperTraceExecuteRequest (pLib->hAdapter, name, pLib->buffer)) {
715 return (-1);
716 }
717 pLib->clear_call_command &= ~(1L << i);
718 pLib->req_busy = 1;
719 return (0);
720 }
721 }
722
723 if (pLib->outgoing_ifc_stats) {
724 if (SuperTraceReadRequest (pLib->hAdapter,
725 "Statistics\\Outgoing Calls",
726 pLib->buffer)) {
727 return (-1);
728 }
729 pLib->outgoing_ifc_stats = 0;
730 pLib->req_busy = 1;
731 return (0);
732 }
733
734 if (pLib->incoming_ifc_stats) {
735 if (SuperTraceReadRequest (pLib->hAdapter,
736 "Statistics\\Incoming Calls",
737 pLib->buffer)) {
738 return (-1);
739 }
740 pLib->incoming_ifc_stats = 0;
741 pLib->req_busy = 1;
742 return (0);
743 }
744
745 if (pLib->modem_ifc_stats) {
746 if (SuperTraceReadRequest (pLib->hAdapter,
747 "Statistics\\Modem",
748 pLib->buffer)) {
749 return (-1);
750 }
751 pLib->modem_ifc_stats = 0;
752 pLib->req_busy = 1;
753 return (0);
754 }
755
756 if (pLib->fax_ifc_stats) {
757 if (SuperTraceReadRequest (pLib->hAdapter,
758 "Statistics\\FAX",
759 pLib->buffer)) {
760 return (-1);
761 }
762 pLib->fax_ifc_stats = 0;
763 pLib->req_busy = 1;
764 return (0);
765 }
766
767 if (pLib->b1_ifc_stats) {
768 if (SuperTraceReadRequest (pLib->hAdapter,
769 "Statistics\\B-Layer1",
770 pLib->buffer)) {
771 return (-1);
772 }
773 pLib->b1_ifc_stats = 0;
774 pLib->req_busy = 1;
775 return (0);
776 }
777
778 if (pLib->b2_ifc_stats) {
779 if (SuperTraceReadRequest (pLib->hAdapter,
780 "Statistics\\B-Layer2",
781 pLib->buffer)) {
782 return (-1);
783 }
784 pLib->b2_ifc_stats = 0;
785 pLib->req_busy = 1;
786 return (0);
787 }
788
789 if (pLib->d1_ifc_stats) {
790 if (SuperTraceReadRequest (pLib->hAdapter,
791 "Statistics\\D-Layer1",
792 pLib->buffer)) {
793 return (-1);
794 }
795 pLib->d1_ifc_stats = 0;
796 pLib->req_busy = 1;
797 return (0);
798 }
799
800 if (pLib->d2_ifc_stats) {
801 if (SuperTraceReadRequest (pLib->hAdapter,
802 "Statistics\\D-Layer2",
803 pLib->buffer)) {
804 return (-1);
805 }
806 pLib->d2_ifc_stats = 0;
807 pLib->req_busy = 1;
808 return (0);
809 }
810
811 if (!pLib->IncomingCallsCallsActive) {
812 pLib->IncomingCallsCallsActive = 1;
813 sprintf (name, "%s", "Statistics\\Incoming Calls\\Calls");
814 if ((ret = SuperTraceTraceOnRequest(pLib->hAdapter, name, pLib->buffer))) {
815 pLib->IncomingCallsCallsActive = 0;
816 return (-1);
817 }
818 pLib->req_busy = 1;
819 return (0);
820 }
821 if (!pLib->IncomingCallsConnectedActive) {
822 pLib->IncomingCallsConnectedActive = 1;
823 sprintf (name, "%s", "Statistics\\Incoming Calls\\Connected");
824 if ((ret = SuperTraceTraceOnRequest(pLib->hAdapter, name, pLib->buffer))) {
825 pLib->IncomingCallsConnectedActive = 0;
826 return (-1);
827 }
828 pLib->req_busy = 1;
829 return (0);
830 }
831 if (!pLib->OutgoingCallsCallsActive) {
832 pLib->OutgoingCallsCallsActive = 1;
833 sprintf (name, "%s", "Statistics\\Outgoing Calls\\Calls");
834 if ((ret = SuperTraceTraceOnRequest(pLib->hAdapter, name, pLib->buffer))) {
835 pLib->OutgoingCallsCallsActive = 0;
836 return (-1);
837 }
838 pLib->req_busy = 1;
839 return (0);
840 }
841 if (!pLib->OutgoingCallsConnectedActive) {
842 pLib->OutgoingCallsConnectedActive = 1;
843 sprintf (name, "%s", "Statistics\\Outgoing Calls\\Connected");
844 if ((ret = SuperTraceTraceOnRequest(pLib->hAdapter, name, pLib->buffer))) {
845 pLib->OutgoingCallsConnectedActive = 0;
846 return (-1);
847 }
848 pLib->req_busy = 1;
849 return (0);
850 }
851
852 return (0);
853}
854
855static int process_idi_event (diva_strace_context_t* pLib,
856 diva_man_var_header_t* pVar) {
857 const char* path = (char*)&pVar->path_length+1;
858 char name[64];
859 int i;
860
861 if (!strncmp("State\\B Event", path, pVar->path_length)) {
862 dword ch_id;
863 if (!diva_trace_read_variable (pVar, &ch_id)) {
864 if (!pLib->line_init_event && !pLib->pending_line_status) {
865 for (i = 1; i <= pLib->Channels; i++) {
866 diva_line_event(pLib, i);
867 }
868 return (0);
869 } else if (ch_id && ch_id <= pLib->Channels) {
870 return (diva_line_event(pLib, (int)ch_id));
871 }
872 return (0);
873 }
874 return (-1);
875 }
876
877 if (!strncmp("State\\FAX Event", path, pVar->path_length)) {
878 dword ch_id;
879 if (!diva_trace_read_variable (pVar, &ch_id)) {
880 if (!pLib->pending_fax_status && !pLib->fax_init_event) {
881 for (i = 1; i <= pLib->Channels; i++) {
882 diva_fax_event(pLib, i);
883 }
884 return (0);
885 } else if (ch_id && ch_id <= pLib->Channels) {
886 return (diva_fax_event(pLib, (int)ch_id));
887 }
888 return (0);
889 }
890 return (-1);
891 }
892
893 if (!strncmp("State\\Modem Event", path, pVar->path_length)) {
894 dword ch_id;
895 if (!diva_trace_read_variable (pVar, &ch_id)) {
896 if (!pLib->pending_modem_status && !pLib->modem_init_event) {
897 for (i = 1; i <= pLib->Channels; i++) {
898 diva_modem_event(pLib, i);
899 }
900 return (0);
901 } else if (ch_id && ch_id <= pLib->Channels) {
902 return (diva_modem_event(pLib, (int)ch_id));
903 }
904 return (0);
905 }
906 return (-1);
907 }
908
909 /*
910 First look for Line Event
911 */
912 for (i = 1; i <= pLib->Channels; i++) {
913 sprintf (name, "State\\B%d\\Line", i);
914 if (find_var (pVar, name)) {
915 return (diva_line_event(pLib, i));
916 }
917 }
918
919 /*
920 Look for Moden Progress Event
921 */
922 for (i = 1; i <= pLib->Channels; i++) {
923 sprintf (name, "State\\B%d\\Modem\\Event", i);
924 if (find_var (pVar, name)) {
925 return (diva_modem_event (pLib, i));
926 }
927 }
928
929 /*
930 Look for Fax Event
931 */
932 for (i = 1; i <= pLib->Channels; i++) {
933 sprintf (name, "State\\B%d\\FAX\\Event", i);
934 if (find_var (pVar, name)) {
935 return (diva_fax_event (pLib, i));
936 }
937 }
938
939 /*
940 Notification about loss of events
941 */
942 if (!strncmp("Events Down", path, pVar->path_length)) {
943 if (pLib->trace_events_down == 1) {
944 pLib->trace_events_down = 2;
945 } else {
946 diva_trace_error (pLib, 1, "Events Down", 0);
947 }
948 return (0);
949 }
950
951 if (!strncmp("State\\Layer1", path, pVar->path_length)) {
952 diva_strace_read_asz (pVar, &pLib->lines[0].pInterface->Layer1[0]);
953 if (pLib->l1_trace == 1) {
954 pLib->l1_trace = 2;
955 } else {
956 diva_trace_notify_user (pLib, 0, DIVA_SUPER_TRACE_INTERFACE_CHANGE);
957 }
958 return (0);
959 }
960 if (!strncmp("State\\Layer2 No1", path, pVar->path_length)) {
961 char* tmp = &pLib->lines[0].pInterface->Layer2[0];
962 dword l2_state;
963 diva_strace_read_uint (pVar, &l2_state);
964
965 switch (l2_state) {
966 case 0:
967 strcpy (tmp, "Idle");
968 break;
969 case 1:
970 strcpy (tmp, "Layer2 UP");
971 break;
972 case 2:
973 strcpy (tmp, "Layer2 Disconnecting");
974 break;
975 case 3:
976 strcpy (tmp, "Layer2 Connecting");
977 break;
978 case 4:
979 strcpy (tmp, "SPID Initializing");
980 break;
981 case 5:
982 strcpy (tmp, "SPID Initialised");
983 break;
984 case 6:
985 strcpy (tmp, "Layer2 Connecting");
986 break;
987
988 case 7:
989 strcpy (tmp, "Auto SPID Stopped");
990 break;
991
992 case 8:
993 strcpy (tmp, "Auto SPID Idle");
994 break;
995
996 case 9:
997 strcpy (tmp, "Auto SPID Requested");
998 break;
999
1000 case 10:
1001 strcpy (tmp, "Auto SPID Delivery");
1002 break;
1003
1004 case 11:
1005 strcpy (tmp, "Auto SPID Complete");
1006 break;
1007
1008 default:
1009 sprintf (tmp, "U:%d", (int)l2_state);
1010 }
1011 if (pLib->l2_trace == 1) {
1012 pLib->l2_trace = 2;
1013 } else {
1014 diva_trace_notify_user (pLib, 0, DIVA_SUPER_TRACE_INTERFACE_CHANGE);
1015 }
1016 return (0);
1017 }
1018
1019 if (!strncmp("Statistics\\Incoming Calls\\Calls", path, pVar->path_length) ||
1020 !strncmp("Statistics\\Incoming Calls\\Connected", path, pVar->path_length)) {
1021 return (SuperTraceGetIncomingCallStatistics (pLib));
1022 }
1023
1024 if (!strncmp("Statistics\\Outgoing Calls\\Calls", path, pVar->path_length) ||
1025 !strncmp("Statistics\\Outgoing Calls\\Connected", path, pVar->path_length)) {
1026 return (SuperTraceGetOutgoingCallStatistics (pLib));
1027 }
1028
1029 return (-1);
1030}
1031
1032static int diva_line_event (diva_strace_context_t* pLib, int Channel) {
1033 pLib->pending_line_status |= (1L << (Channel-1));
1034 return (0);
1035}
1036
1037static int diva_modem_event (diva_strace_context_t* pLib, int Channel) {
1038 pLib->pending_modem_status |= (1L << (Channel-1));
1039 return (0);
1040}
1041
1042static int diva_fax_event (diva_strace_context_t* pLib, int Channel) {
1043 pLib->pending_fax_status |= (1L << (Channel-1));
1044 return (0);
1045}
1046
1047/*
1048 Process INFO indications that arrive from the card
1049 Uses path of first I.E. to detect the source of the
1050 infication
1051 */
1052static int process_idi_info (diva_strace_context_t* pLib,
1053 diva_man_var_header_t* pVar) {
1054 const char* path = (char*)&pVar->path_length+1;
1055 char name[64];
1056 int i, len;
1057
1058 /*
1059 First look for Modem Status Info
1060 */
1061 for (i = pLib->Channels; i > 0; i--) {
1062 len = sprintf (name, "State\\B%d\\Modem", i);
1063 if (!strncmp(name, path, len)) {
1064 return (diva_modem_info (pLib, i, pVar));
1065 }
1066 }
1067
1068 /*
1069 Look for Fax Status Info
1070 */
1071 for (i = pLib->Channels; i > 0; i--) {
1072 len = sprintf (name, "State\\B%d\\FAX", i);
1073 if (!strncmp(name, path, len)) {
1074 return (diva_fax_info (pLib, i, pVar));
1075 }
1076 }
1077
1078 /*
1079 Look for Line Status Info
1080 */
1081 for (i = pLib->Channels; i > 0; i--) {
1082 len = sprintf (name, "State\\B%d", i);
1083 if (!strncmp(name, path, len)) {
1084 return (diva_line_info (pLib, i, pVar));
1085 }
1086 }
1087
1088 if (!diva_ifc_statistics (pLib, pVar)) {
1089 return (0);
1090 }
1091
1092 return (-1);
1093}
1094
1095/*
1096 MODEM INSTANCE STATE UPDATE
1097
1098 Update Modem Status Information and issue notification to user,
1099 that will inform about change in the state of modem instance, that is
1100 associuated with this channel
1101 */
1102static int diva_modem_info (diva_strace_context_t* pLib,
1103 int Channel,
1104 diva_man_var_header_t* pVar) {
1105 diva_man_var_header_t* cur;
1106 int i, nr = Channel - 1;
1107
1108 for (i = pLib->modem_parse_entry_first[nr];
1109 i <= pLib->modem_parse_entry_last[nr]; i++) {
1110 if ((cur = find_var (pVar, pLib->parse_table[i].path))) {
1111 if (diva_trace_read_variable (cur, pLib->parse_table[i].variable)) {
1112 diva_trace_error (pLib, -3 , __FILE__, __LINE__);
1113 return (-1);
1114 }
1115 } else {
1116 diva_trace_error (pLib, -2 , __FILE__, __LINE__);
1117 return (-1);
1118 }
1119 }
1120
1121 /*
1122 We do not use first event to notify user - this is the event that is
1123 generated as result of EVENT ON operation and is used only to initialize
1124 internal variables of application
1125 */
1126 if (pLib->modem_init_event & (1L << nr)) {
1127 diva_trace_notify_user (pLib, nr, DIVA_SUPER_TRACE_NOTIFY_MODEM_CHANGE);
1128 } else {
1129 pLib->modem_init_event |= (1L << nr);
1130 }
1131
1132 return (0);
1133}
1134
1135static int diva_fax_info (diva_strace_context_t* pLib,
1136 int Channel,
1137 diva_man_var_header_t* pVar) {
1138 diva_man_var_header_t* cur;
1139 int i, nr = Channel - 1;
1140
1141 for (i = pLib->fax_parse_entry_first[nr];
1142 i <= pLib->fax_parse_entry_last[nr]; i++) {
1143 if ((cur = find_var (pVar, pLib->parse_table[i].path))) {
1144 if (diva_trace_read_variable (cur, pLib->parse_table[i].variable)) {
1145 diva_trace_error (pLib, -3 , __FILE__, __LINE__);
1146 return (-1);
1147 }
1148 } else {
1149 diva_trace_error (pLib, -2 , __FILE__, __LINE__);
1150 return (-1);
1151 }
1152 }
1153
1154 /*
1155 We do not use first event to notify user - this is the event that is
1156 generated as result of EVENT ON operation and is used only to initialize
1157 internal variables of application
1158 */
1159 if (pLib->fax_init_event & (1L << nr)) {
1160 diva_trace_notify_user (pLib, nr, DIVA_SUPER_TRACE_NOTIFY_FAX_CHANGE);
1161 } else {
1162 pLib->fax_init_event |= (1L << nr);
1163 }
1164
1165 return (0);
1166}
1167
1168/*
1169 LINE STATE UPDATE
1170 Update Line Status Information and issue notification to user,
1171 that will inform about change in the line state.
1172 */
1173static int diva_line_info (diva_strace_context_t* pLib,
1174 int Channel,
1175 diva_man_var_header_t* pVar) {
1176 diva_man_var_header_t* cur;
1177 int i, nr = Channel - 1;
1178
1179 for (i = pLib->line_parse_entry_first[nr];
1180 i <= pLib->line_parse_entry_last[nr]; i++) {
1181 if ((cur = find_var (pVar, pLib->parse_table[i].path))) {
1182 if (diva_trace_read_variable (cur, pLib->parse_table[i].variable)) {
1183 diva_trace_error (pLib, -3 , __FILE__, __LINE__);
1184 return (-1);
1185 }
1186 } else {
1187 diva_trace_error (pLib, -2 , __FILE__, __LINE__);
1188 return (-1);
1189 }
1190 }
1191
1192 /*
1193 We do not use first event to notify user - this is the event that is
1194 generated as result of EVENT ON operation and is used only to initialize
1195 internal variables of application
1196
1197 Exception is is if the line is "online". In this case we have to notify
1198 user about this confition.
1199 */
1200 if (pLib->line_init_event & (1L << nr)) {
1201 diva_trace_notify_user (pLib, nr, DIVA_SUPER_TRACE_NOTIFY_LINE_CHANGE);
1202 } else {
1203 pLib->line_init_event |= (1L << nr);
1204 if (strcmp (&pLib->lines[nr].Line[0], "Idle")) {
1205 diva_trace_notify_user (pLib, nr, DIVA_SUPER_TRACE_NOTIFY_LINE_CHANGE);
1206 }
1207 }
1208
1209 return (0);
1210}
1211
1212/*
1213 Move position to next vatianle in the chain
1214 */
1215static diva_man_var_header_t* get_next_var (diva_man_var_header_t* pVar) {
1216 byte* msg = (byte*)pVar;
1217 byte* start;
1218 int msg_length;
1219
1220 if (*msg != ESC) return NULL;
1221
1222 start = msg + 2;
1223 msg_length = *(msg+1);
1224 msg = (start+msg_length);
1225
1226 if (*msg != ESC) return NULL;
1227
1228 return ((diva_man_var_header_t*)msg);
1229}
1230
1231/*
1232 Move position to variable with given name
1233 */
1234static diva_man_var_header_t* find_var (diva_man_var_header_t* pVar,
1235 const char* name) {
1236 const char* path;
1237
1238 do {
1239 path = (char*)&pVar->path_length+1;
1240
1241 if (!strncmp (name, path, pVar->path_length)) {
1242 break;
1243 }
1244 } while ((pVar = get_next_var (pVar)));
1245
1246 return (pVar);
1247}
1248
1249static void diva_create_line_parse_table (diva_strace_context_t* pLib,
1250 int Channel) {
1251 diva_trace_line_state_t* pLine = &pLib->lines[Channel];
1252 int nr = Channel+1;
1253
1254 if ((pLib->cur_parse_entry + LINE_PARSE_ENTRIES) >= pLib->parse_entries) {
1255 diva_trace_error (pLib, -1, __FILE__, __LINE__);
1256 return;
1257 }
1258
1259 pLine->ChannelNumber = nr;
1260
1261 pLib->line_parse_entry_first[Channel] = pLib->cur_parse_entry;
1262
1263 sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
1264 "State\\B%d\\Framing", nr);
1265 pLib->parse_table[pLib->cur_parse_entry++].variable = &pLine->Framing[0];
1266
1267 sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
1268 "State\\B%d\\Line", nr);
1269 pLib->parse_table[pLib->cur_parse_entry++].variable = &pLine->Line[0];
1270
1271 sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
1272 "State\\B%d\\Layer2", nr);
1273 pLib->parse_table[pLib->cur_parse_entry++].variable = &pLine->Layer2[0];
1274
1275 sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
1276 "State\\B%d\\Layer3", nr);
1277 pLib->parse_table[pLib->cur_parse_entry++].variable = &pLine->Layer3[0];
1278
1279 sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
1280 "State\\B%d\\Remote Address", nr);
1281 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1282 &pLine->RemoteAddress[0];
1283
1284 sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
1285 "State\\B%d\\Remote SubAddr", nr);
1286 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1287 &pLine->RemoteSubAddress[0];
1288
1289 sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
1290 "State\\B%d\\Local Address", nr);
1291 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1292 &pLine->LocalAddress[0];
1293
1294 sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
1295 "State\\B%d\\Local SubAddr", nr);
1296 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1297 &pLine->LocalSubAddress[0];
1298
1299 sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
1300 "State\\B%d\\BC", nr);
1301 pLib->parse_table[pLib->cur_parse_entry++].variable = &pLine->call_BC;
1302
1303 sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
1304 "State\\B%d\\HLC", nr);
1305 pLib->parse_table[pLib->cur_parse_entry++].variable = &pLine->call_HLC;
1306
1307 sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
1308 "State\\B%d\\LLC", nr);
1309 pLib->parse_table[pLib->cur_parse_entry++].variable = &pLine->call_LLC;
1310
1311 sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
1312 "State\\B%d\\Charges", nr);
1313 pLib->parse_table[pLib->cur_parse_entry++].variable = &pLine->Charges;
1314
1315 sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
1316 "State\\B%d\\Call Reference", nr);
1317 pLib->parse_table[pLib->cur_parse_entry++].variable = &pLine->CallReference;
1318
1319 sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
1320 "State\\B%d\\Last Disc Cause", nr);
1321 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1322 &pLine->LastDisconnecCause;
1323
1324 sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
1325 "State\\B%d\\User ID", nr);
1326 pLib->parse_table[pLib->cur_parse_entry++].variable = &pLine->UserID[0];
1327
1328 pLib->line_parse_entry_last[Channel] = pLib->cur_parse_entry - 1;
1329}
1330
1331static void diva_create_fax_parse_table (diva_strace_context_t* pLib,
1332 int Channel) {
1333 diva_trace_fax_state_t* pFax = &pLib->lines[Channel].fax;
1334 int nr = Channel+1;
1335
1336 if ((pLib->cur_parse_entry + FAX_PARSE_ENTRIES) >= pLib->parse_entries) {
1337 diva_trace_error (pLib, -1, __FILE__, __LINE__);
1338 return;
1339 }
1340 pFax->ChannelNumber = nr;
1341
1342 pLib->fax_parse_entry_first[Channel] = pLib->cur_parse_entry;
1343
1344 sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
1345 "State\\B%d\\FAX\\Event", nr);
1346 pLib->parse_table[pLib->cur_parse_entry++].variable = &pFax->Event;
1347
1348 sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
1349 "State\\B%d\\FAX\\Page Counter", nr);
1350 pLib->parse_table[pLib->cur_parse_entry++].variable = &pFax->Page_Counter;
1351
1352 sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
1353 "State\\B%d\\FAX\\Features", nr);
1354 pLib->parse_table[pLib->cur_parse_entry++].variable = &pFax->Features;
1355
1356 sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
1357 "State\\B%d\\FAX\\Station ID", nr);
1358 pLib->parse_table[pLib->cur_parse_entry++].variable = &pFax->Station_ID[0];
1359
1360 sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
1361 "State\\B%d\\FAX\\Subaddress", nr);
1362 pLib->parse_table[pLib->cur_parse_entry++].variable = &pFax->Subaddress[0];
1363
1364 sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
1365 "State\\B%d\\FAX\\Password", nr);
1366 pLib->parse_table[pLib->cur_parse_entry++].variable = &pFax->Password[0];
1367
1368 sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
1369 "State\\B%d\\FAX\\Speed", nr);
1370 pLib->parse_table[pLib->cur_parse_entry++].variable = &pFax->Speed;
1371
1372 sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
1373 "State\\B%d\\FAX\\Resolution", nr);
1374 pLib->parse_table[pLib->cur_parse_entry++].variable = &pFax->Resolution;
1375
1376 sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
1377 "State\\B%d\\FAX\\Paper Width", nr);
1378 pLib->parse_table[pLib->cur_parse_entry++].variable = &pFax->Paper_Width;
1379
1380 sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
1381 "State\\B%d\\FAX\\Paper Length", nr);
1382 pLib->parse_table[pLib->cur_parse_entry++].variable = &pFax->Paper_Length;
1383
1384 sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
1385 "State\\B%d\\FAX\\Scanline Time", nr);
1386 pLib->parse_table[pLib->cur_parse_entry++].variable = &pFax->Scanline_Time;
1387
1388 sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
1389 "State\\B%d\\FAX\\Disc Reason", nr);
1390 pLib->parse_table[pLib->cur_parse_entry++].variable = &pFax->Disc_Reason;
1391
1392 pLib->fax_parse_entry_last[Channel] = pLib->cur_parse_entry - 1;
1393}
1394
1395static void diva_create_modem_parse_table (diva_strace_context_t* pLib,
1396 int Channel) {
1397 diva_trace_modem_state_t* pModem = &pLib->lines[Channel].modem;
1398 int nr = Channel+1;
1399
1400 if ((pLib->cur_parse_entry + MODEM_PARSE_ENTRIES) >= pLib->parse_entries) {
1401 diva_trace_error (pLib, -1, __FILE__, __LINE__);
1402 return;
1403 }
1404 pModem->ChannelNumber = nr;
1405
1406 pLib->modem_parse_entry_first[Channel] = pLib->cur_parse_entry;
1407
1408 sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
1409 "State\\B%d\\Modem\\Event", nr);
1410 pLib->parse_table[pLib->cur_parse_entry++].variable = &pModem->Event;
1411
1412 sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
1413 "State\\B%d\\Modem\\Norm", nr);
1414 pLib->parse_table[pLib->cur_parse_entry++].variable = &pModem->Norm;
1415
1416 sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
1417 "State\\B%d\\Modem\\Options", nr);
1418 pLib->parse_table[pLib->cur_parse_entry++].variable = &pModem->Options;
1419
1420 sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
1421 "State\\B%d\\Modem\\TX Speed", nr);
1422 pLib->parse_table[pLib->cur_parse_entry++].variable = &pModem->TxSpeed;
1423
1424 sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
1425 "State\\B%d\\Modem\\RX Speed", nr);
1426 pLib->parse_table[pLib->cur_parse_entry++].variable = &pModem->RxSpeed;
1427
1428 sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
1429 "State\\B%d\\Modem\\Roundtrip ms", nr);
1430 pLib->parse_table[pLib->cur_parse_entry++].variable = &pModem->RoundtripMsec;
1431
1432 sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
1433 "State\\B%d\\Modem\\Symbol Rate", nr);
1434 pLib->parse_table[pLib->cur_parse_entry++].variable = &pModem->SymbolRate;
1435
1436 sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
1437 "State\\B%d\\Modem\\RX Level dBm", nr);
1438 pLib->parse_table[pLib->cur_parse_entry++].variable = &pModem->RxLeveldBm;
1439
1440 sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
1441 "State\\B%d\\Modem\\Echo Level dBm", nr);
1442 pLib->parse_table[pLib->cur_parse_entry++].variable = &pModem->EchoLeveldBm;
1443
1444 sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
1445 "State\\B%d\\Modem\\SNR dB", nr);
1446 pLib->parse_table[pLib->cur_parse_entry++].variable = &pModem->SNRdb;
1447
1448 sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
1449 "State\\B%d\\Modem\\MAE", nr);
1450 pLib->parse_table[pLib->cur_parse_entry++].variable = &pModem->MAE;
1451
1452 sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
1453 "State\\B%d\\Modem\\Local Retrains", nr);
1454 pLib->parse_table[pLib->cur_parse_entry++].variable = &pModem->LocalRetrains;
1455
1456 sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
1457 "State\\B%d\\Modem\\Remote Retrains", nr);
1458 pLib->parse_table[pLib->cur_parse_entry++].variable = &pModem->RemoteRetrains;
1459
1460 sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
1461 "State\\B%d\\Modem\\Local Resyncs", nr);
1462 pLib->parse_table[pLib->cur_parse_entry++].variable = &pModem->LocalResyncs;
1463
1464 sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
1465 "State\\B%d\\Modem\\Remote Resyncs", nr);
1466 pLib->parse_table[pLib->cur_parse_entry++].variable = &pModem->RemoteResyncs;
1467
1468 sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
1469 "State\\B%d\\Modem\\Disc Reason", nr);
1470 pLib->parse_table[pLib->cur_parse_entry++].variable = &pModem->DiscReason;
1471
1472 pLib->modem_parse_entry_last[Channel] = pLib->cur_parse_entry - 1;
1473}
1474
1475static void diva_create_parse_table (diva_strace_context_t* pLib) {
1476 int i;
1477
1478 for (i = 0; i < pLib->Channels; i++) {
1479 diva_create_line_parse_table (pLib, i);
1480 diva_create_modem_parse_table (pLib, i);
1481 diva_create_fax_parse_table (pLib, i);
1482 }
1483
1484 pLib->statistic_parse_first = pLib->cur_parse_entry;
1485
1486 /*
1487 Outgoing Calls
1488 */
1489 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1490 "Statistics\\Outgoing Calls\\Calls");
1491 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1492 &pLib->InterfaceStat.outg.Calls;
1493
1494 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1495 "Statistics\\Outgoing Calls\\Connected");
1496 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1497 &pLib->InterfaceStat.outg.Connected;
1498
1499 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1500 "Statistics\\Outgoing Calls\\User Busy");
1501 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1502 &pLib->InterfaceStat.outg.User_Busy;
1503
1504 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1505 "Statistics\\Outgoing Calls\\No Answer");
1506 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1507 &pLib->InterfaceStat.outg.No_Answer;
1508
1509 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1510 "Statistics\\Outgoing Calls\\Wrong Number");
1511 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1512 &pLib->InterfaceStat.outg.Wrong_Number;
1513
1514 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1515 "Statistics\\Outgoing Calls\\Call Rejected");
1516 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1517 &pLib->InterfaceStat.outg.Call_Rejected;
1518
1519 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1520 "Statistics\\Outgoing Calls\\Other Failures");
1521 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1522 &pLib->InterfaceStat.outg.Other_Failures;
1523
1524 /*
1525 Incoming Calls
1526 */
1527 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1528 "Statistics\\Incoming Calls\\Calls");
1529 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1530 &pLib->InterfaceStat.inc.Calls;
1531
1532 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1533 "Statistics\\Incoming Calls\\Connected");
1534 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1535 &pLib->InterfaceStat.inc.Connected;
1536
1537 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1538 "Statistics\\Incoming Calls\\User Busy");
1539 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1540 &pLib->InterfaceStat.inc.User_Busy;
1541
1542 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1543 "Statistics\\Incoming Calls\\Call Rejected");
1544 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1545 &pLib->InterfaceStat.inc.Call_Rejected;
1546
1547 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1548 "Statistics\\Incoming Calls\\Wrong Number");
1549 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1550 &pLib->InterfaceStat.inc.Wrong_Number;
1551
1552 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1553 "Statistics\\Incoming Calls\\Incompatible Dst");
1554 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1555 &pLib->InterfaceStat.inc.Incompatible_Dst;
1556
1557 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1558 "Statistics\\Incoming Calls\\Out of Order");
1559 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1560 &pLib->InterfaceStat.inc.Out_of_Order;
1561
1562 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1563 "Statistics\\Incoming Calls\\Ignored");
1564 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1565 &pLib->InterfaceStat.inc.Ignored;
1566
1567 /*
1568 Modem Statistics
1569 */
1570 pLib->mdm_statistic_parse_first = pLib->cur_parse_entry;
1571
1572 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1573 "Statistics\\Modem\\Disc Normal");
1574 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1575 &pLib->InterfaceStat.mdm.Disc_Normal;
1576
1577 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1578 "Statistics\\Modem\\Disc Unspecified");
1579 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1580 &pLib->InterfaceStat.mdm.Disc_Unspecified;
1581
1582 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1583 "Statistics\\Modem\\Disc Busy Tone");
1584 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1585 &pLib->InterfaceStat.mdm.Disc_Busy_Tone;
1586
1587 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1588 "Statistics\\Modem\\Disc Congestion");
1589 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1590 &pLib->InterfaceStat.mdm.Disc_Congestion;
1591
1592 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1593 "Statistics\\Modem\\Disc Carr. Wait");
1594 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1595 &pLib->InterfaceStat.mdm.Disc_Carr_Wait;
1596
1597 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1598 "Statistics\\Modem\\Disc Trn Timeout");
1599 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1600 &pLib->InterfaceStat.mdm.Disc_Trn_Timeout;
1601
1602 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1603 "Statistics\\Modem\\Disc Incompat.");
1604 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1605 &pLib->InterfaceStat.mdm.Disc_Incompat;
1606
1607 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1608 "Statistics\\Modem\\Disc Frame Rej.");
1609 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1610 &pLib->InterfaceStat.mdm.Disc_Frame_Rej;
1611
1612 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1613 "Statistics\\Modem\\Disc V42bis");
1614 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1615 &pLib->InterfaceStat.mdm.Disc_V42bis;
1616
1617 pLib->mdm_statistic_parse_last = pLib->cur_parse_entry - 1;
1618
1619 /*
1620 Fax Statistics
1621 */
1622 pLib->fax_statistic_parse_first = pLib->cur_parse_entry;
1623
1624 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1625 "Statistics\\FAX\\Disc Normal");
1626 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1627 &pLib->InterfaceStat.fax.Disc_Normal;
1628
1629 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1630 "Statistics\\FAX\\Disc Not Ident.");
1631 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1632 &pLib->InterfaceStat.fax.Disc_Not_Ident;
1633
1634 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1635 "Statistics\\FAX\\Disc No Response");
1636 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1637 &pLib->InterfaceStat.fax.Disc_No_Response;
1638
1639 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1640 "Statistics\\FAX\\Disc Retries");
1641 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1642 &pLib->InterfaceStat.fax.Disc_Retries;
1643
1644 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1645 "Statistics\\FAX\\Disc Unexp. Msg.");
1646 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1647 &pLib->InterfaceStat.fax.Disc_Unexp_Msg;
1648
1649 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1650 "Statistics\\FAX\\Disc No Polling.");
1651 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1652 &pLib->InterfaceStat.fax.Disc_No_Polling;
1653
1654 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1655 "Statistics\\FAX\\Disc Training");
1656 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1657 &pLib->InterfaceStat.fax.Disc_Training;
1658
1659 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1660 "Statistics\\FAX\\Disc Unexpected");
1661 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1662 &pLib->InterfaceStat.fax.Disc_Unexpected;
1663
1664 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1665 "Statistics\\FAX\\Disc Application");
1666 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1667 &pLib->InterfaceStat.fax.Disc_Application;
1668
1669 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1670 "Statistics\\FAX\\Disc Incompat.");
1671 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1672 &pLib->InterfaceStat.fax.Disc_Incompat;
1673
1674 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1675 "Statistics\\FAX\\Disc No Command");
1676 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1677 &pLib->InterfaceStat.fax.Disc_No_Command;
1678
1679 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1680 "Statistics\\FAX\\Disc Long Msg");
1681 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1682 &pLib->InterfaceStat.fax.Disc_Long_Msg;
1683
1684 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1685 "Statistics\\FAX\\Disc Supervisor");
1686 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1687 &pLib->InterfaceStat.fax.Disc_Supervisor;
1688
1689 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1690 "Statistics\\FAX\\Disc SUB SEP PWD");
1691 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1692 &pLib->InterfaceStat.fax.Disc_SUB_SEP_PWD;
1693
1694 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1695 "Statistics\\FAX\\Disc Invalid Msg");
1696 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1697 &pLib->InterfaceStat.fax.Disc_Invalid_Msg;
1698
1699 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1700 "Statistics\\FAX\\Disc Page Coding");
1701 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1702 &pLib->InterfaceStat.fax.Disc_Page_Coding;
1703
1704 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1705 "Statistics\\FAX\\Disc App Timeout");
1706 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1707 &pLib->InterfaceStat.fax.Disc_App_Timeout;
1708
1709 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1710 "Statistics\\FAX\\Disc Unspecified");
1711 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1712 &pLib->InterfaceStat.fax.Disc_Unspecified;
1713
1714 pLib->fax_statistic_parse_last = pLib->cur_parse_entry - 1;
1715
1716 /*
1717 B-Layer1"
1718 */
1719 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1720 "Statistics\\B-Layer1\\X-Frames");
1721 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1722 &pLib->InterfaceStat.b1.X_Frames;
1723
1724 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1725 "Statistics\\B-Layer1\\X-Bytes");
1726 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1727 &pLib->InterfaceStat.b1.X_Bytes;
1728
1729 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1730 "Statistics\\B-Layer1\\X-Errors");
1731 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1732 &pLib->InterfaceStat.b1.X_Errors;
1733
1734 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1735 "Statistics\\B-Layer1\\R-Frames");
1736 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1737 &pLib->InterfaceStat.b1.R_Frames;
1738
1739 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1740 "Statistics\\B-Layer1\\R-Bytes");
1741 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1742 &pLib->InterfaceStat.b1.R_Bytes;
1743
1744 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1745 "Statistics\\B-Layer1\\R-Errors");
1746 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1747 &pLib->InterfaceStat.b1.R_Errors;
1748
1749 /*
1750 B-Layer2
1751 */
1752 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1753 "Statistics\\B-Layer2\\X-Frames");
1754 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1755 &pLib->InterfaceStat.b2.X_Frames;
1756
1757 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1758 "Statistics\\B-Layer2\\X-Bytes");
1759 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1760 &pLib->InterfaceStat.b2.X_Bytes;
1761
1762 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1763 "Statistics\\B-Layer2\\X-Errors");
1764 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1765 &pLib->InterfaceStat.b2.X_Errors;
1766
1767 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1768 "Statistics\\B-Layer2\\R-Frames");
1769 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1770 &pLib->InterfaceStat.b2.R_Frames;
1771
1772 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1773 "Statistics\\B-Layer2\\R-Bytes");
1774 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1775 &pLib->InterfaceStat.b2.R_Bytes;
1776
1777 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1778 "Statistics\\B-Layer2\\R-Errors");
1779 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1780 &pLib->InterfaceStat.b2.R_Errors;
1781
1782 /*
1783 D-Layer1
1784 */
1785 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1786 "Statistics\\D-Layer1\\X-Frames");
1787 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1788 &pLib->InterfaceStat.d1.X_Frames;
1789
1790 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1791 "Statistics\\D-Layer1\\X-Bytes");
1792 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1793 &pLib->InterfaceStat.d1.X_Bytes;
1794
1795 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1796 "Statistics\\D-Layer1\\X-Errors");
1797 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1798 &pLib->InterfaceStat.d1.X_Errors;
1799
1800 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1801 "Statistics\\D-Layer1\\R-Frames");
1802 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1803 &pLib->InterfaceStat.d1.R_Frames;
1804
1805 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1806 "Statistics\\D-Layer1\\R-Bytes");
1807 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1808 &pLib->InterfaceStat.d1.R_Bytes;
1809
1810 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1811 "Statistics\\D-Layer1\\R-Errors");
1812 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1813 &pLib->InterfaceStat.d1.R_Errors;
1814
1815 /*
1816 D-Layer2
1817 */
1818 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1819 "Statistics\\D-Layer2\\X-Frames");
1820 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1821 &pLib->InterfaceStat.d2.X_Frames;
1822
1823 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1824 "Statistics\\D-Layer2\\X-Bytes");
1825 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1826 &pLib->InterfaceStat.d2.X_Bytes;
1827
1828 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1829 "Statistics\\D-Layer2\\X-Errors");
1830 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1831 &pLib->InterfaceStat.d2.X_Errors;
1832
1833 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1834 "Statistics\\D-Layer2\\R-Frames");
1835 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1836 &pLib->InterfaceStat.d2.R_Frames;
1837
1838 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1839 "Statistics\\D-Layer2\\R-Bytes");
1840 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1841 &pLib->InterfaceStat.d2.R_Bytes;
1842
1843 strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
1844 "Statistics\\D-Layer2\\R-Errors");
1845 pLib->parse_table[pLib->cur_parse_entry++].variable = \
1846 &pLib->InterfaceStat.d2.R_Errors;
1847
1848
1849 pLib->statistic_parse_last = pLib->cur_parse_entry - 1;
1850}
1851
1852static void diva_trace_error (diva_strace_context_t* pLib,
1853 int error, const char* file, int line) {
1854 if (pLib->user_proc_table.error_notify_proc) {
1855 (*(pLib->user_proc_table.error_notify_proc))(\
1856 pLib->user_proc_table.user_context,
1857 &pLib->instance, pLib->Adapter,
1858 error, file, line);
1859 }
1860}
1861
1862/*
1863 Delivery notification to user
1864 */
1865static void diva_trace_notify_user (diva_strace_context_t* pLib,
1866 int Channel,
1867 int notify_subject) {
1868 if (pLib->user_proc_table.notify_proc) {
1869 (*(pLib->user_proc_table.notify_proc))(pLib->user_proc_table.user_context,
1870 &pLib->instance,
1871 pLib->Adapter,
1872 &pLib->lines[Channel],
1873 notify_subject);
1874 }
1875}
1876
1877/*
1878 Read variable value to they destination based on the variable type
1879 */
1880static int diva_trace_read_variable (diva_man_var_header_t* pVar,
1881 void* variable) {
1882 switch (pVar->type) {
1883 case 0x03: /* MI_ASCIIZ - syting */
1884 return (diva_strace_read_asz (pVar, (char*)variable));
1885 case 0x04: /* MI_ASCII - string */
1886 return (diva_strace_read_asc (pVar, (char*)variable));
1887 case 0x05: /* MI_NUMBER - counted sequence of bytes */
1888 return (diva_strace_read_ie (pVar, (diva_trace_ie_t*)variable));
1889 case 0x81: /* MI_INT - signed integer */
1890 return (diva_strace_read_int (pVar, (int*)variable));
1891 case 0x82: /* MI_UINT - unsigned integer */
1892 return (diva_strace_read_uint (pVar, (dword*)variable));
1893 case 0x83: /* MI_HINT - unsigned integer, hex representetion */
1894 return (diva_strace_read_uint (pVar, (dword*)variable));
1895 case 0x87: /* MI_BITFLD - unsigned integer, bit representation */
1896 return (diva_strace_read_uint (pVar, (dword*)variable));
1897 }
1898
1899 /*
1900 This type of variable is not handled, indicate error
1901 Or one problem in management interface, or in application recodeing
1902 table, or this application should handle it.
1903 */
1904 return (-1);
1905}
1906
1907/*
1908 Read signed integer to destination
1909 */
1910static int diva_strace_read_int (diva_man_var_header_t* pVar, int* var) {
1911 byte* ptr = (char*)&pVar->path_length;
1912 int value;
1913
1914 ptr += (pVar->path_length + 1);
1915
1916 switch (pVar->value_length) {
1917 case 1:
1918 value = *(char*)ptr;
1919 break;
1920
1921 case 2:
1922 value = (short)GET_WORD(ptr);
1923 break;
1924
1925 case 4:
1926 value = (int)GET_DWORD(ptr);
1927 break;
1928
1929 default:
1930 return (-1);
1931 }
1932
1933 *var = value;
1934
1935 return (0);
1936}
1937
1938static int diva_strace_read_uint (diva_man_var_header_t* pVar, dword* var) {
1939 byte* ptr = (char*)&pVar->path_length;
1940 dword value;
1941
1942 ptr += (pVar->path_length + 1);
1943
1944 switch (pVar->value_length) {
1945 case 1:
1946 value = (byte)(*ptr);
1947 break;
1948
1949 case 2:
1950 value = (word)GET_WORD(ptr);
1951 break;
1952
1953 case 3:
1954 value = (dword)GET_DWORD(ptr);
1955 value &= 0x00ffffff;
1956 break;
1957
1958 case 4:
1959 value = (dword)GET_DWORD(ptr);
1960 break;
1961
1962 default:
1963 return (-1);
1964 }
1965
1966 *var = value;
1967
1968 return (0);
1969}
1970
1971/*
1972 Read zero terminated ASCII string
1973 */
1974static int diva_strace_read_asz (diva_man_var_header_t* pVar, char* var) {
1975 char* ptr = (char*)&pVar->path_length;
1976 int length;
1977
1978 ptr += (pVar->path_length + 1);
1979
1980 if (!(length = pVar->value_length)) {
1981 length = strlen (ptr);
1982 }
1983 memcpy (var, ptr, length);
1984 var[length] = 0;
1985
1986 return (0);
1987}
1988
1989/*
1990 Read counted (with leading length byte) ASCII string
1991 */
1992static int diva_strace_read_asc (diva_man_var_header_t* pVar, char* var) {
1993 char* ptr = (char*)&pVar->path_length;
1994
1995 ptr += (pVar->path_length + 1);
1996 memcpy (var, ptr+1, *ptr);
1997 var[(int)*ptr] = 0;
1998
1999 return (0);
2000}
2001
2002/*
2003 Read one information element - i.e. one string of byte values with
2004 one length byte in front
2005 */
2006static int diva_strace_read_ie (diva_man_var_header_t* pVar,
2007 diva_trace_ie_t* var) {
2008 char* ptr = (char*)&pVar->path_length;
2009
2010 ptr += (pVar->path_length + 1);
2011
2012 var->length = *ptr;
2013 memcpy (&var->data[0], ptr+1, *ptr);
2014
2015 return (0);
2016}
2017
2018static int SuperTraceSetAudioTap (void* hLib, int Channel, int on) {
2019 diva_strace_context_t* pLib = (diva_strace_context_t*)hLib;
2020
2021 if ((Channel < 1) || (Channel > pLib->Channels)) {
2022 return (-1);
2023 }
2024 Channel--;
2025
2026 if (on) {
2027 pLib->audio_tap_mask |= (1L << Channel);
2028 } else {
2029 pLib->audio_tap_mask &= ~(1L << Channel);
2030 }
2031
2032 /*
2033 EYE patterns have TM_M_DATA set as additional
2034 condition
2035 */
2036 if (pLib->audio_tap_mask) {
2037 pLib->trace_event_mask |= TM_M_DATA;
2038 } else {
2039 pLib->trace_event_mask &= ~TM_M_DATA;
2040 }
2041
2042 return (ScheduleNextTraceRequest (pLib));
2043}
2044
2045static int SuperTraceSetBChannel (void* hLib, int Channel, int on) {
2046 diva_strace_context_t* pLib = (diva_strace_context_t*)hLib;
2047
2048 if ((Channel < 1) || (Channel > pLib->Channels)) {
2049 return (-1);
2050 }
2051 Channel--;
2052
2053 if (on) {
2054 pLib->bchannel_trace_mask |= (1L << Channel);
2055 } else {
2056 pLib->bchannel_trace_mask &= ~(1L << Channel);
2057 }
2058
2059 return (ScheduleNextTraceRequest (pLib));
2060}
2061
2062static int SuperTraceSetDChannel (void* hLib, int on) {
2063 diva_strace_context_t* pLib = (diva_strace_context_t*)hLib;
2064
2065 if (on) {
2066 pLib->trace_event_mask |= (TM_D_CHAN | TM_C_COMM | TM_DL_ERR | TM_LAYER1);
2067 } else {
2068 pLib->trace_event_mask &= ~(TM_D_CHAN | TM_C_COMM | TM_DL_ERR | TM_LAYER1);
2069 }
2070
2071 return (ScheduleNextTraceRequest (pLib));
2072}
2073
2074static int SuperTraceSetInfo (void* hLib, int on) {
2075 diva_strace_context_t* pLib = (diva_strace_context_t*)hLib;
2076
2077 if (on) {
2078 pLib->trace_event_mask |= TM_STRING;
2079 } else {
2080 pLib->trace_event_mask &= ~TM_STRING;
2081 }
2082
2083 return (ScheduleNextTraceRequest (pLib));
2084}
2085
2086static int SuperTraceClearCall (void* hLib, int Channel) {
2087 diva_strace_context_t* pLib = (diva_strace_context_t*)hLib;
2088
2089 if ((Channel < 1) || (Channel > pLib->Channels)) {
2090 return (-1);
2091 }
2092 Channel--;
2093
2094 pLib->clear_call_command |= (1L << Channel);
2095
2096 return (ScheduleNextTraceRequest (pLib));
2097}
2098
2099/*
2100 Parse and update cumulative statistice
2101 */
2102static int diva_ifc_statistics (diva_strace_context_t* pLib,
2103 diva_man_var_header_t* pVar) {
2104 diva_man_var_header_t* cur;
2105 int i, one_updated = 0, mdm_updated = 0, fax_updated = 0;
2106
2107 for (i = pLib->statistic_parse_first; i <= pLib->statistic_parse_last; i++) {
2108 if ((cur = find_var (pVar, pLib->parse_table[i].path))) {
2109 if (diva_trace_read_variable (cur, pLib->parse_table[i].variable)) {
2110 diva_trace_error (pLib, -3 , __FILE__, __LINE__);
2111 return (-1);
2112 }
2113 one_updated = 1;
2114 if ((i >= pLib->mdm_statistic_parse_first) && (i <= pLib->mdm_statistic_parse_last)) {
2115 mdm_updated = 1;
2116 }
2117 if ((i >= pLib->fax_statistic_parse_first) && (i <= pLib->fax_statistic_parse_last)) {
2118 fax_updated = 1;
2119 }
2120 }
2121 }
2122
2123 /*
2124 We do not use first event to notify user - this is the event that is
2125 generated as result of EVENT ON operation and is used only to initialize
2126 internal variables of application
2127 */
2128 if (mdm_updated) {
2129 diva_trace_notify_user (pLib, 0, DIVA_SUPER_TRACE_NOTIFY_MDM_STAT_CHANGE);
2130 } else if (fax_updated) {
2131 diva_trace_notify_user (pLib, 0, DIVA_SUPER_TRACE_NOTIFY_FAX_STAT_CHANGE);
2132 } else if (one_updated) {
2133 diva_trace_notify_user (pLib, 0, DIVA_SUPER_TRACE_NOTIFY_STAT_CHANGE);
2134 }
2135
2136 return (one_updated ? 0 : -1);
2137}
2138
2139static int SuperTraceGetOutgoingCallStatistics (void* hLib) {
2140 diva_strace_context_t* pLib = (diva_strace_context_t*)hLib;
2141 pLib->outgoing_ifc_stats = 1;
2142 return (ScheduleNextTraceRequest (pLib));
2143}
2144
2145static int SuperTraceGetIncomingCallStatistics (void* hLib) {
2146 diva_strace_context_t* pLib = (diva_strace_context_t*)hLib;
2147 pLib->incoming_ifc_stats = 1;
2148 return (ScheduleNextTraceRequest (pLib));
2149}
2150
2151static int SuperTraceGetModemStatistics (void* hLib) {
2152 diva_strace_context_t* pLib = (diva_strace_context_t*)hLib;
2153 pLib->modem_ifc_stats = 1;
2154 return (ScheduleNextTraceRequest (pLib));
2155}
2156
2157static int SuperTraceGetFaxStatistics (void* hLib) {
2158 diva_strace_context_t* pLib = (diva_strace_context_t*)hLib;
2159 pLib->fax_ifc_stats = 1;
2160 return (ScheduleNextTraceRequest (pLib));
2161}
2162
2163static int SuperTraceGetBLayer1Statistics (void* hLib) {
2164 diva_strace_context_t* pLib = (diva_strace_context_t*)hLib;
2165 pLib->b1_ifc_stats = 1;
2166 return (ScheduleNextTraceRequest (pLib));
2167}
2168
2169static int SuperTraceGetBLayer2Statistics (void* hLib) {
2170 diva_strace_context_t* pLib = (diva_strace_context_t*)hLib;
2171 pLib->b2_ifc_stats = 1;
2172 return (ScheduleNextTraceRequest (pLib));
2173}
2174
2175static int SuperTraceGetDLayer1Statistics (void* hLib) {
2176 diva_strace_context_t* pLib = (diva_strace_context_t*)hLib;
2177 pLib->d1_ifc_stats = 1;
2178 return (ScheduleNextTraceRequest (pLib));
2179}
2180
2181static int SuperTraceGetDLayer2Statistics (void* hLib) {
2182 diva_strace_context_t* pLib = (diva_strace_context_t*)hLib;
2183 pLib->d2_ifc_stats = 1;
2184 return (ScheduleNextTraceRequest (pLib));
2185}
2186
2187dword DivaSTraceGetMemotyRequirement (int channels) {
2188 dword parse_entries = (MODEM_PARSE_ENTRIES + FAX_PARSE_ENTRIES + \
2189 STAT_PARSE_ENTRIES + \
2190 LINE_PARSE_ENTRIES + 1) * channels;
2191 return (sizeof(diva_strace_context_t) + \
2192 (parse_entries * sizeof(diva_strace_path2action_t)));
2193}
2194
diff --git a/drivers/isdn/hardware/eicon/maintidi.h b/drivers/isdn/hardware/eicon/maintidi.h
new file mode 100644
index 000000000000..4f06294966b8
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/maintidi.h
@@ -0,0 +1,172 @@
1/*
2 *
3 Copyright (c) Eicon Networks, 2000.
4 *
5 This source file is supplied for the use with
6 Eicon Networks range of DIVA Server Adapters.
7 *
8 Eicon File Revision : 1.9
9 *
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2, or (at your option)
13 any later version.
14 *
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
17 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18 See the GNU General Public License for more details.
19 *
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 */
25#ifndef __DIVA_EICON_TRACE_IDI_IFC_H__
26#define __DIVA_EICON_TRACE_IDI_IFC_H__
27
28void* SuperTraceOpenAdapter (int AdapterNumber);
29int SuperTraceCloseAdapter (void* AdapterHandle);
30int SuperTraceWrite (void* AdapterHandle,
31 const void* data, int length);
32int SuperTraceReadRequest (void* AdapterHandle,const char* name,byte* data);
33int SuperTraceGetNumberOfChannels (void* AdapterHandle);
34int SuperTraceASSIGN (void* AdapterHandle, byte* data);
35int SuperTraceREMOVE (void* AdapterHandle);
36int SuperTraceTraceOnRequest(void* hAdapter, const char* name, byte* data);
37int SuperTraceWriteVar (void* AdapterHandle,
38 byte* data,
39 const char* name,
40 void* var,
41 byte type,
42 byte var_length);
43int SuperTraceExecuteRequest (void* AdapterHandle,
44 const char* name,
45 byte* data);
46
47typedef struct _diva_strace_path2action {
48 char path[64]; /* Full path to variable */
49 void* variable; /* Variable that will receive value */
50} diva_strace_path2action_t;
51
52#define DIVA_MAX_MANAGEMENT_TRANSFER_SIZE 4096
53
54typedef struct _diva_strace_context {
55 diva_strace_library_interface_t instance;
56
57 int Adapter;
58 void* hAdapter;
59
60 int Channels;
61 int req_busy;
62
63 ENTITY e;
64 IDI_CALL request;
65 BUFFERS XData;
66 BUFFERS RData;
67 byte buffer[DIVA_MAX_MANAGEMENT_TRANSFER_SIZE + 1];
68 int removal_state;
69 int general_b_ch_event;
70 int general_fax_event;
71 int general_mdm_event;
72
73 byte rc_ok;
74
75 /*
76 Initialization request state machine
77 */
78 int ChannelsTraceActive;
79 int ModemTraceActive;
80 int FaxTraceActive;
81 int IncomingCallsCallsActive;
82 int IncomingCallsConnectedActive;
83 int OutgoingCallsCallsActive;
84 int OutgoingCallsConnectedActive;
85
86 int trace_mask_init;
87 int audio_trace_init;
88 int bchannel_init;
89 int trace_length_init;
90 int trace_on;
91 int trace_events_down;
92 int l1_trace;
93 int l2_trace;
94
95 /*
96 Trace\Event Enable
97 */
98 word trace_event_mask;
99 word current_trace_event_mask;
100
101 dword audio_tap_mask;
102 dword current_audio_tap_mask;
103 dword current_eye_pattern_mask;
104 int audio_tap_pending;
105 int eye_pattern_pending;
106
107 dword bchannel_trace_mask;
108 dword current_bchannel_trace_mask;
109
110
111 diva_trace_line_state_t lines[30];
112
113 int parse_entries;
114 int cur_parse_entry;
115 diva_strace_path2action_t* parse_table;
116
117 diva_trace_library_user_interface_t user_proc_table;
118
119 int line_parse_entry_first[30];
120 int line_parse_entry_last[30];
121
122 int modem_parse_entry_first[30];
123 int modem_parse_entry_last[30];
124
125 int fax_parse_entry_first[30];
126 int fax_parse_entry_last[30];
127
128 int statistic_parse_first;
129 int statistic_parse_last;
130
131 int mdm_statistic_parse_first;
132 int mdm_statistic_parse_last;
133
134 int fax_statistic_parse_first;
135 int fax_statistic_parse_last;
136
137 dword line_init_event;
138 dword modem_init_event;
139 dword fax_init_event;
140
141 dword pending_line_status;
142 dword pending_modem_status;
143 dword pending_fax_status;
144
145 dword clear_call_command;
146
147 int outgoing_ifc_stats;
148 int incoming_ifc_stats;
149 int modem_ifc_stats;
150 int fax_ifc_stats;
151 int b1_ifc_stats;
152 int b2_ifc_stats;
153 int d1_ifc_stats;
154 int d2_ifc_stats;
155
156 diva_trace_interface_state_t Interface;
157 diva_ifc_statistics_t InterfaceStat;
158} diva_strace_context_t;
159
160typedef struct _diva_man_var_header {
161 byte escape;
162 byte length;
163 byte management_id;
164 byte type;
165 byte attribute;
166 byte status;
167 byte value_length;
168 byte path_length;
169} diva_man_var_header_t;
170
171#endif
172
diff --git a/drivers/isdn/hardware/eicon/man_defs.h b/drivers/isdn/hardware/eicon/man_defs.h
new file mode 100644
index 000000000000..cb4ef4cae6c1
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/man_defs.h
@@ -0,0 +1,133 @@
1/*
2 *
3 Copyright (c) Eicon Networks, 2002.
4 *
5 This source file is supplied for the use with
6 Eicon Networks range of DIVA Server Adapters.
7 *
8 Eicon File Revision : 1.9
9 *
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2, or (at your option)
13 any later version.
14 *
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
17 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18 See the GNU General Public License for more details.
19 *
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 */
25/* Definitions for use with the Management Information Element */
26
27/*------------------------------------------------------------------*/
28/* Management information element */
29/* ---------------------------------------------------------- */
30/* Byte Coding Comment */
31/* ---------------------------------------------------------- */
32/* 0 | 0 1 1 1 1 1 1 1 | ESC */
33/* 1 | 0 x x x x x x x | Length of information element (m-1) */
34/* 2 | 1 0 0 0 0 0 0 0 | Management Information Id */
35/* 3 | x x x x x x x x | Type */
36/* 4 | x x x x x x x x | Attribute */
37/* 5 | x x x x x x x x | Status */
38/* 6 | x x x x x x x x | Variable Value Length (m-n) */
39/* 7 | x x x x x x x x | Path / Variable Name String Length (n-8)*/
40/* 8..n | x x x x x x x x | Path/Node Name String separated by '\' */
41/* n..m | x x x x x x x x | Variable content */
42/*------------------------------------------------------------------*/
43
44/*------------------------------------------------------------------*/
45/* Type Field */
46/* */
47/* MAN_READ: not used */
48/* MAN_WRITE: not used */
49/* MAN_EVENT_ON: not used */
50/* MAN_EVENT_OFF: not used */
51/* MAN_INFO_IND: type of variable */
52/* MAN_EVENT_IND: type of variable */
53/* MAN_TRACE_IND not used */
54/*------------------------------------------------------------------*/
55#define MI_DIR 0x01 /* Directory string (zero terminated) */
56#define MI_EXECUTE 0x02 /* Executable function (has no value) */
57#define MI_ASCIIZ 0x03 /* Zero terminated string */
58#define MI_ASCII 0x04 /* String, first byte is length */
59#define MI_NUMBER 0x05 /* Number string, first byte is length*/
60#define MI_TRACE 0x06 /* Trace information, format see below*/
61
62#define MI_FIXED_LENGTH 0x80 /* get length from MAN_INFO max_len */
63#define MI_INT 0x81 /* number to display as signed int */
64#define MI_UINT 0x82 /* number to display as unsigned int */
65#define MI_HINT 0x83 /* number to display in hex format */
66#define MI_HSTR 0x84 /* number to display as a hex string */
67#define MI_BOOLEAN 0x85 /* number to display as boolean */
68#define MI_IP_ADDRESS 0x86 /* number to display as IP address */
69#define MI_BITFLD 0x87 /* number to display as bit field */
70#define MI_SPID_STATE 0x88 /* state# of SPID initialisation */
71
72/*------------------------------------------------------------------*/
73/* Attribute Field */
74/* */
75/* MAN_READ: not used */
76/* MAN_WRITE: not used */
77/* MAN_EVENT_ON: not used */
78/* MAN_EVENT_OFF: not used */
79/* MAN_INFO_IND: set according to capabilities of that variable */
80/* MAN_EVENT_IND: not used */
81/* MAN_TRACE_IND not used */
82/*------------------------------------------------------------------*/
83#define MI_WRITE 0x01 /* Variable is writeable */
84#define MI_EVENT 0x02 /* Variable can indicate changes */
85
86/*------------------------------------------------------------------*/
87/* Status Field */
88/* */
89/* MAN_READ: not used */
90/* MAN_WRITE: not used */
91/* MAN_EVENT_ON: not used */
92/* MAN_EVENT_OFF: not used */
93/* MAN_INFO_IND: set according to the actual status */
94/* MAN_EVENT_IND: set according to the actual statu */
95/* MAN_TRACE_IND not used */
96/*------------------------------------------------------------------*/
97#define MI_LOCKED 0x01 /* write protected by another instance*/
98#define MI_EVENT_ON 0x02 /* Event logging switched on */
99#define MI_PROTECTED 0x04 /* write protected by this instance */
100
101/*------------------------------------------------------------------*/
102/* Data Format used for MAN_TRACE_IND (no MI-element used) */
103/*------------------------------------------------------------------*/
104typedef struct mi_xlog_hdr_s MI_XLOG_HDR;
105struct mi_xlog_hdr_s
106{
107 unsigned long time; /* Timestamp in msec units */
108 unsigned short size; /* Size of data that follows */
109 unsigned short code; /* code of trace event */
110}; /* unspecified data follows this header */
111
112/*------------------------------------------------------------------*/
113/* Trace mask definitions for trace events except B channel and */
114/* debug trace events */
115/*------------------------------------------------------------------*/
116#define TM_D_CHAN 0x0001 /* D-Channel (D-.) Code 3,4 */
117#define TM_L_LAYER 0x0002 /* Low Layer (LL) Code 6,7 */
118#define TM_N_LAYER 0x0004 /* Network Layer (N) Code 14,15 */
119#define TM_DL_ERR 0x0008 /* Data Link Error (MDL) Code 9 */
120#define TM_LAYER1 0x0010 /* Layer 1 Code 20 */
121#define TM_C_COMM 0x0020 /* Call Comment (SIG) Code 5,21,22 */
122#define TM_M_DATA 0x0040 /* Modulation Data (EYE) Code 23 */
123#define TM_STRING 0x0080 /* Sting data Code 24 */
124#define TM_N_USED2 0x0100 /* not used */
125#define TM_N_USED3 0x0200 /* not used */
126#define TM_N_USED4 0x0400 /* not used */
127#define TM_N_USED5 0x0800 /* not used */
128#define TM_N_USED6 0x1000 /* not used */
129#define TM_N_USED7 0x2000 /* not used */
130#define TM_N_USED8 0x4000 /* not used */
131#define TM_REST 0x8000 /* Codes 10,11,12,13,16,18,19,128,129 */
132
133/*------ End of file -----------------------------------------------*/
diff --git a/drivers/isdn/hardware/eicon/mdm_msg.h b/drivers/isdn/hardware/eicon/mdm_msg.h
new file mode 100644
index 000000000000..7a737e10bce0
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/mdm_msg.h
@@ -0,0 +1,346 @@
1
2/*
3 *
4 Copyright (c) Eicon Networks, 2002.
5 *
6 This source file is supplied for the use with
7 Eicon Networks range of DIVA Server Adapters.
8 *
9 Eicon File Revision : 2.1
10 *
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2, or (at your option)
14 any later version.
15 *
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
18 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 See the GNU General Public License for more details.
20 *
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26#ifndef __EICON_MDM_MSG_H__
27#define __EICON_MDM_MSG_H__
28#define DSP_UDATA_INDICATION_DCD_OFF 0x01
29#define DSP_UDATA_INDICATION_DCD_ON 0x02
30#define DSP_UDATA_INDICATION_CTS_OFF 0x03
31#define DSP_UDATA_INDICATION_CTS_ON 0x04
32/* =====================================================================
33DCD_OFF Message:
34 <word> time of DCD off (sampled from counter at 8kHz)
35DCD_ON Message:
36 <word> time of DCD on (sampled from counter at 8kHz)
37 <byte> connected norm
38 <word> connected options
39 <dword> connected speed (bit/s, max of tx and rx speed)
40 <word> roundtrip delay (ms)
41 <dword> connected speed tx (bit/s)
42 <dword> connected speed rx (bit/s)
43 Size of this message == 19 bytes, but we will receive only 11
44 ===================================================================== */
45#define DSP_CONNECTED_NORM_UNSPECIFIED 0
46#define DSP_CONNECTED_NORM_V21 1
47#define DSP_CONNECTED_NORM_V23 2
48#define DSP_CONNECTED_NORM_V22 3
49#define DSP_CONNECTED_NORM_V22_BIS 4
50#define DSP_CONNECTED_NORM_V32_BIS 5
51#define DSP_CONNECTED_NORM_V34 6
52#define DSP_CONNECTED_NORM_V8 7
53#define DSP_CONNECTED_NORM_BELL_212A 8
54#define DSP_CONNECTED_NORM_BELL_103 9
55#define DSP_CONNECTED_NORM_V29_LEASED_LINE 10
56#define DSP_CONNECTED_NORM_V33_LEASED_LINE 11
57#define DSP_CONNECTED_NORM_V90 12
58#define DSP_CONNECTED_NORM_V21_CH2 13
59#define DSP_CONNECTED_NORM_V27_TER 14
60#define DSP_CONNECTED_NORM_V29 15
61#define DSP_CONNECTED_NORM_V33 16
62#define DSP_CONNECTED_NORM_V17 17
63#define DSP_CONNECTED_NORM_V32 18
64#define DSP_CONNECTED_NORM_K56_FLEX 19
65#define DSP_CONNECTED_NORM_X2 20
66#define DSP_CONNECTED_NORM_V18 21
67#define DSP_CONNECTED_NORM_V18_LOW_HIGH 22
68#define DSP_CONNECTED_NORM_V18_HIGH_LOW 23
69#define DSP_CONNECTED_NORM_V21_LOW_HIGH 24
70#define DSP_CONNECTED_NORM_V21_HIGH_LOW 25
71#define DSP_CONNECTED_NORM_BELL103_LOW_HIGH 26
72#define DSP_CONNECTED_NORM_BELL103_HIGH_LOW 27
73#define DSP_CONNECTED_NORM_V23_75_1200 28
74#define DSP_CONNECTED_NORM_V23_1200_75 29
75#define DSP_CONNECTED_NORM_EDT_110 30
76#define DSP_CONNECTED_NORM_BAUDOT_45 31
77#define DSP_CONNECTED_NORM_BAUDOT_47 32
78#define DSP_CONNECTED_NORM_BAUDOT_50 33
79#define DSP_CONNECTED_NORM_DTMF 34
80#define DSP_CONNECTED_NORM_V18_RESERVED_13 35
81#define DSP_CONNECTED_NORM_V18_RESERVED_14 36
82#define DSP_CONNECTED_NORM_V18_RESERVED_15 37
83#define DSP_CONNECTED_NORM_VOWN 38
84#define DSP_CONNECTED_NORM_V23_OFF_HOOK 39
85#define DSP_CONNECTED_NORM_V23_ON_HOOK 40
86#define DSP_CONNECTED_NORM_VOWN_RESERVED_3 41
87#define DSP_CONNECTED_NORM_VOWN_RESERVED_4 42
88#define DSP_CONNECTED_NORM_VOWN_RESERVED_5 43
89#define DSP_CONNECTED_NORM_VOWN_RESERVED_6 44
90#define DSP_CONNECTED_NORM_VOWN_RESERVED_7 45
91#define DSP_CONNECTED_NORM_VOWN_RESERVED_8 46
92#define DSP_CONNECTED_NORM_VOWN_RESERVED_9 47
93#define DSP_CONNECTED_NORM_VOWN_RESERVED_10 48
94#define DSP_CONNECTED_NORM_VOWN_RESERVED_11 49
95#define DSP_CONNECTED_NORM_VOWN_RESERVED_12 50
96#define DSP_CONNECTED_NORM_VOWN_RESERVED_13 51
97#define DSP_CONNECTED_NORM_VOWN_RESERVED_14 52
98#define DSP_CONNECTED_NORM_VOWN_RESERVED_15 53
99#define DSP_CONNECTED_NORM_VOWN_RESERVED_16 54
100#define DSP_CONNECTED_NORM_VOWN_RESERVED_17 55
101#define DSP_CONNECTED_NORM_VOWN_RESERVED_18 56
102#define DSP_CONNECTED_NORM_VOWN_RESERVED_19 57
103#define DSP_CONNECTED_NORM_VOWN_RESERVED_20 58
104#define DSP_CONNECTED_NORM_VOWN_RESERVED_21 59
105#define DSP_CONNECTED_NORM_VOWN_RESERVED_22 60
106#define DSP_CONNECTED_NORM_VOWN_RESERVED_23 61
107#define DSP_CONNECTED_NORM_VOWN_RESERVED_24 62
108#define DSP_CONNECTED_NORM_VOWN_RESERVED_25 63
109#define DSP_CONNECTED_NORM_VOWN_RESERVED_26 64
110#define DSP_CONNECTED_NORM_VOWN_RESERVED_27 65
111#define DSP_CONNECTED_NORM_VOWN_RESERVED_28 66
112#define DSP_CONNECTED_NORM_VOWN_RESERVED_29 67
113#define DSP_CONNECTED_NORM_VOWN_RESERVED_30 68
114#define DSP_CONNECTED_NORM_VOWN_RESERVED_31 69
115#define DSP_CONNECTED_OPTION_TRELLIS 0x0001
116#define DSP_CONNECTED_OPTION_V42_TRANS 0x0002
117#define DSP_CONNECTED_OPTION_V42_LAPM 0x0004
118#define DSP_CONNECTED_OPTION_SHORT_TRAIN 0x0008
119#define DSP_CONNECTED_OPTION_TALKER_ECHO_PROTECT 0x0010
120#define DSP_CONNECTED_OPTION_V42BIS 0x0020
121#define DSP_CONNECTED_OPTION_MNP2 0x0040
122#define DSP_CONNECTED_OPTION_MNP3 0x0080
123#define DSP_CONNECTED_OPTION_MNP4 0x00c0
124#define DSP_CONNECTED_OPTION_MNP5 0x0100
125#define DSP_CONNECTED_OPTION_MNP10 0x0200
126#define DSP_CONNECTED_OPTION_MASK_V42 0x0024
127#define DSP_CONNECTED_OPTION_MASK_MNP 0x03c0
128#define DSP_CONNECTED_OPTION_MASK_ERROR_CORRECT 0x03e4
129#define DSP_CONNECTED_OPTION_MASK_COMPRESSION 0x0320
130#define DSP_UDATA_INDICATION_DISCONNECT 5
131/*
132returns:
133 <byte> cause
134*/
135/* ==========================================================
136 DLC: B2 modem configuration
137 ========================================================== */
138/*
139Fields in assign DLC information element for modem protocol V.42/MNP:
140 <byte> length of information element
141 <word> information field length
142 <byte> address A (not used, default 3)
143 <byte> address B (not used, default 1)
144 <byte> modulo mode (not used, default 7)
145 <byte> window size (not used, default 7)
146 <word> XID length (not used, default 0)
147 ... XID information (not used, default empty)
148 <byte> modem protocol negotiation options
149 <byte> modem protocol options
150 <byte> modem protocol break configuration
151 <byte> modem protocol application options
152*/
153#define DLC_MODEMPROT_DISABLE_V42_V42BIS 0x01
154#define DLC_MODEMPROT_DISABLE_MNP_MNP5 0x02
155#define DLC_MODEMPROT_REQUIRE_PROTOCOL 0x04
156#define DLC_MODEMPROT_DISABLE_V42_DETECT 0x08
157#define DLC_MODEMPROT_DISABLE_COMPRESSION 0x10
158#define DLC_MODEMPROT_REQUIRE_PROTOCOL_V34UP 0x20
159#define DLC_MODEMPROT_NO_PROTOCOL_IF_1200 0x01
160#define DLC_MODEMPROT_BUFFER_IN_V42_DETECT 0x02
161#define DLC_MODEMPROT_DISABLE_V42_SREJ 0x04
162#define DLC_MODEMPROT_DISABLE_MNP3 0x08
163#define DLC_MODEMPROT_DISABLE_MNP4 0x10
164#define DLC_MODEMPROT_DISABLE_MNP10 0x20
165#define DLC_MODEMPROT_NO_PROTOCOL_IF_V22BIS 0x40
166#define DLC_MODEMPROT_NO_PROTOCOL_IF_V32BIS 0x80
167#define DLC_MODEMPROT_BREAK_DISABLED 0x00
168#define DLC_MODEMPROT_BREAK_NORMAL 0x01
169#define DLC_MODEMPROT_BREAK_EXPEDITED 0x02
170#define DLC_MODEMPROT_BREAK_DESTRUCTIVE 0x03
171#define DLC_MODEMPROT_BREAK_CONFIG_MASK 0x03
172#define DLC_MODEMPROT_APPL_EARLY_CONNECT 0x01
173#define DLC_MODEMPROT_APPL_PASS_INDICATIONS 0x02
174/* ==========================================================
175 CAI parameters used for the modem L1 configuration
176 ========================================================== */
177/*
178Fields in assign CAI information element:
179 <byte> length of information element
180 <byte> info field and B-channel hardware
181 <byte> rate adaptation bit rate
182 <byte> async framing parameters
183 <byte> reserved
184 <word> packet length
185 <byte> modem line taking options
186 <byte> modem modulation negotiation parameters
187 <byte> modem modulation options
188 <byte> modem disabled modulations mask low
189 <byte> modem disabled modulations mask high
190 <byte> modem enabled modulations mask
191 <word> modem min TX speed
192 <word> modem max TX speed
193 <word> modem min RX speed
194 <word> modem max RX speed
195 <byte> modem disabled symbol rates mask
196 <byte> modem info options mask
197 <byte> modem transmit level adjust
198 <byte> modem speaker parameters
199 <word> modem private debug config
200 <struct> modem reserved
201 <struct> v18 config parameters
202 <struct> v18 probing sequence
203 <struct> v18 probing message
204*/
205#define DSP_CAI_HARDWARE_HDLC_64K 0x05
206#define DSP_CAI_HARDWARE_HDLC_56K 0x08
207#define DSP_CAI_HARDWARE_TRANSP 0x09
208#define DSP_CAI_HARDWARE_V110_SYNC 0x0c
209#define DSP_CAI_HARDWARE_V110_ASYNC 0x0d
210#define DSP_CAI_HARDWARE_HDLC_128K 0x0f
211#define DSP_CAI_HARDWARE_FAX 0x10
212#define DSP_CAI_HARDWARE_MODEM_ASYNC 0x11
213#define DSP_CAI_HARDWARE_MODEM_SYNC 0x12
214#define DSP_CAI_HARDWARE_V110_HDLCA 0x13
215#define DSP_CAI_HARDWARE_ADVANCED_VOICE 0x14
216#define DSP_CAI_HARDWARE_TRANSP_DTMF 0x16
217#define DSP_CAI_HARDWARE_DTMF_VOICE_ISDN 0x17
218#define DSP_CAI_HARDWARE_DTMF_VOICE_LOCAL 0x18
219#define DSP_CAI_HARDWARE_MASK 0x3f
220#define DSP_CAI_ENABLE_INFO_INDICATIONS 0x80
221#define DSP_CAI_RATE_ADAPTATION_300 0x00
222#define DSP_CAI_RATE_ADAPTATION_600 0x01
223#define DSP_CAI_RATE_ADAPTATION_1200 0x02
224#define DSP_CAI_RATE_ADAPTATION_2400 0x03
225#define DSP_CAI_RATE_ADAPTATION_4800 0x04
226#define DSP_CAI_RATE_ADAPTATION_9600 0x05
227#define DSP_CAI_RATE_ADAPTATION_19200 0x06
228#define DSP_CAI_RATE_ADAPTATION_38400 0x07
229#define DSP_CAI_RATE_ADAPTATION_48000 0x08
230#define DSP_CAI_RATE_ADAPTATION_56000 0x09
231#define DSP_CAI_RATE_ADAPTATION_7200 0x0a
232#define DSP_CAI_RATE_ADAPTATION_14400 0x0b
233#define DSP_CAI_RATE_ADAPTATION_28800 0x0c
234#define DSP_CAI_RATE_ADAPTATION_12000 0x0d
235#define DSP_CAI_RATE_ADAPTATION_1200_75 0x0e
236#define DSP_CAI_RATE_ADAPTATION_75_1200 0x0f
237#define DSP_CAI_RATE_ADAPTATION_MASK 0x0f
238#define DSP_CAI_ASYNC_PARITY_ENABLE 0x01
239#define DSP_CAI_ASYNC_PARITY_SPACE 0x00
240#define DSP_CAI_ASYNC_PARITY_ODD 0x02
241#define DSP_CAI_ASYNC_PARITY_EVEN 0x04
242#define DSP_CAI_ASYNC_PARITY_MARK 0x06
243#define DSP_CAI_ASYNC_PARITY_MASK 0x06
244#define DSP_CAI_ASYNC_ONE_STOP_BIT 0x00
245#define DSP_CAI_ASYNC_TWO_STOP_BITS 0x20
246#define DSP_CAI_ASYNC_CHAR_LENGTH_8 0x00
247#define DSP_CAI_ASYNC_CHAR_LENGTH_7 0x40
248#define DSP_CAI_ASYNC_CHAR_LENGTH_6 0x80
249#define DSP_CAI_ASYNC_CHAR_LENGTH_5 0xc0
250#define DSP_CAI_ASYNC_CHAR_LENGTH_MASK 0xc0
251#define DSP_CAI_MODEM_LEASED_LINE_MODE 0x01
252#define DSP_CAI_MODEM_4_WIRE_OPERATION 0x02
253#define DSP_CAI_MODEM_DISABLE_BUSY_DETECT 0x04
254#define DSP_CAI_MODEM_DISABLE_CALLING_TONE 0x08
255#define DSP_CAI_MODEM_DISABLE_ANSWER_TONE 0x10
256#define DSP_CAI_MODEM_ENABLE_DIAL_TONE_DET 0x20
257#define DSP_CAI_MODEM_USE_POTS_INTERFACE 0x40
258#define DSP_CAI_MODEM_FORCE_RAY_TAYLOR_FAX 0x80
259#define DSP_CAI_MODEM_NEGOTIATE_HIGHEST 0x00
260#define DSP_CAI_MODEM_NEGOTIATE_DISABLED 0x01
261#define DSP_CAI_MODEM_NEGOTIATE_IN_CLASS 0x02
262#define DSP_CAI_MODEM_NEGOTIATE_V100 0x03
263#define DSP_CAI_MODEM_NEGOTIATE_V8 0x04
264#define DSP_CAI_MODEM_NEGOTIATE_V8BIS 0x05
265#define DSP_CAI_MODEM_NEGOTIATE_MASK 0x07
266#define DSP_CAI_MODEM_GUARD_TONE_NONE 0x00
267#define DSP_CAI_MODEM_GUARD_TONE_550HZ 0x40
268#define DSP_CAI_MODEM_GUARD_TONE_1800HZ 0x80
269#define DSP_CAI_MODEM_GUARD_TONE_MASK 0xc0
270#define DSP_CAI_MODEM_DISABLE_RETRAIN 0x01
271#define DSP_CAI_MODEM_DISABLE_STEPUPDOWN 0x02
272#define DSP_CAI_MODEM_DISABLE_SPLIT_SPEED 0x04
273#define DSP_CAI_MODEM_DISABLE_TRELLIS 0x08
274#define DSP_CAI_MODEM_ALLOW_RDL_TEST_LOOP 0x10
275#define DSP_CAI_MODEM_DISABLE_FLUSH_TIMER 0x40
276#define DSP_CAI_MODEM_REVERSE_DIRECTION 0x80
277#define DSP_CAI_MODEM_DISABLE_V21 0x01
278#define DSP_CAI_MODEM_DISABLE_V23 0x02
279#define DSP_CAI_MODEM_DISABLE_V22 0x04
280#define DSP_CAI_MODEM_DISABLE_V22BIS 0x08
281#define DSP_CAI_MODEM_DISABLE_V32 0x10
282#define DSP_CAI_MODEM_DISABLE_V32BIS 0x20
283#define DSP_CAI_MODEM_DISABLE_V34 0x40
284#define DSP_CAI_MODEM_DISABLE_V90 0x80
285#define DSP_CAI_MODEM_DISABLE_BELL103 0x01
286#define DSP_CAI_MODEM_DISABLE_BELL212A 0x02
287#define DSP_CAI_MODEM_DISABLE_VFC 0x04
288#define DSP_CAI_MODEM_DISABLE_K56FLEX 0x08
289#define DSP_CAI_MODEM_DISABLE_X2 0x10
290#define DSP_CAI_MODEM_ENABLE_V29FDX 0x01
291#define DSP_CAI_MODEM_ENABLE_V33 0x02
292#define DSP_CAI_MODEM_DISABLE_2400_SYMBOLS 0x01
293#define DSP_CAI_MODEM_DISABLE_2743_SYMBOLS 0x02
294#define DSP_CAI_MODEM_DISABLE_2800_SYMBOLS 0x04
295#define DSP_CAI_MODEM_DISABLE_3000_SYMBOLS 0x08
296#define DSP_CAI_MODEM_DISABLE_3200_SYMBOLS 0x10
297#define DSP_CAI_MODEM_DISABLE_3429_SYMBOLS 0x20
298#define DSP_CAI_MODEM_DISABLE_TX_REDUCTION 0x01
299#define DSP_CAI_MODEM_DISABLE_PRECODING 0x02
300#define DSP_CAI_MODEM_DISABLE_PREEMPHASIS 0x04
301#define DSP_CAI_MODEM_DISABLE_SHAPING 0x08
302#define DSP_CAI_MODEM_DISABLE_NONLINEAR_EN 0x10
303#define DSP_CAI_MODEM_SPEAKER_OFF 0x00
304#define DSP_CAI_MODEM_SPEAKER_DURING_TRAIN 0x01
305#define DSP_CAI_MODEM_SPEAKER_TIL_CONNECT 0x02
306#define DSP_CAI_MODEM_SPEAKER_ALWAYS_ON 0x03
307#define DSP_CAI_MODEM_SPEAKER_CONTROL_MASK 0x03
308#define DSP_CAI_MODEM_SPEAKER_VOLUME_MIN 0x00
309#define DSP_CAI_MODEM_SPEAKER_VOLUME_LOW 0x04
310#define DSP_CAI_MODEM_SPEAKER_VOLUME_HIGH 0x08
311#define DSP_CAI_MODEM_SPEAKER_VOLUME_MAX 0x0c
312#define DSP_CAI_MODEM_SPEAKER_VOLUME_MASK 0x0c
313/* ==========================================================
314 DCD/CTS State
315 ========================================================== */
316#define MDM_WANT_CONNECT_B3_ACTIVE_I 0x01
317#define MDM_NCPI_VALID 0x02
318#define MDM_NCPI_CTS_ON_RECEIVED 0x04
319#define MDM_NCPI_DCD_ON_RECEIVED 0x08
320/* ==========================================================
321 CAPI NCPI Constants
322 ========================================================== */
323#define MDM_NCPI_ECM_V42 0x0001
324#define MDM_NCPI_ECM_MNP 0x0002
325#define MDM_NCPI_TRANSPARENT 0x0004
326#define MDM_NCPI_COMPRESSED 0x0010
327/* ==========================================================
328 CAPI B2 Config Constants
329 ========================================================== */
330#define MDM_B2_DISABLE_V42bis 0x0001
331#define MDM_B2_DISABLE_MNP 0x0002
332#define MDM_B2_DISABLE_TRANS 0x0004
333#define MDM_B2_DISABLE_V42 0x0008
334#define MDM_B2_DISABLE_COMP 0x0010
335/* ==========================================================
336 CAPI B1 Config Constants
337 ========================================================== */
338#define MDM_CAPI_DISABLE_RETRAIN 0x0001
339#define MDM_CAPI_DISABLE_RING_TONE 0x0002
340#define MDM_CAPI_GUARD_1800 0x0004
341#define MDM_CAPI_GUARD_550 0x0008
342#define MDM_CAPI_NEG_V8 0x0003
343#define MDM_CAPI_NEG_V100 0x0002
344#define MDM_CAPI_NEG_MOD_CLASS 0x0001
345#define MDM_CAPI_NEG_DISABLED 0x0000
346#endif
diff --git a/drivers/isdn/hardware/eicon/message.c b/drivers/isdn/hardware/eicon/message.c
new file mode 100644
index 000000000000..f9b00f19afd2
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/message.c
@@ -0,0 +1,15047 @@
1
2/*
3 *
4 Copyright (c) Eicon Networks, 2002.
5 *
6 This source file is supplied for the use with
7 Eicon Networks range of DIVA Server Adapters.
8 *
9 Eicon File Revision : 2.1
10 *
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2, or (at your option)
14 any later version.
15 *
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
18 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 See the GNU General Public License for more details.
20 *
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27
28
29
30
31#include "platform.h"
32#include "di_defs.h"
33#include "pc.h"
34#include "capi20.h"
35#include "divacapi.h"
36#include "mdm_msg.h"
37#include "divasync.h"
38
39
40
41#define FILE_ "MESSAGE.C"
42#define dprintf
43
44
45
46
47
48
49
50
51
52/*------------------------------------------------------------------*/
53/* This is options supported for all adapters that are server by */
54/* XDI driver. Allo it is not necessary to ask it from every adapter*/
55/* and it is not necessary to save it separate for every adapter */
56/* Macrose defined here have only local meaning */
57/*------------------------------------------------------------------*/
58static dword diva_xdi_extended_features = 0;
59
60#define DIVA_CAPI_USE_CMA 0x00000001
61#define DIVA_CAPI_XDI_PROVIDES_SDRAM_BAR 0x00000002
62#define DIVA_CAPI_XDI_PROVIDES_NO_CANCEL 0x00000004
63#define DIVA_CAPI_XDI_PROVIDES_RX_DMA 0x00000008
64
65/*
66 CAPI can request to process all return codes self only if:
67 protocol code supports this && xdi supports this
68 */
69#define DIVA_CAPI_SUPPORTS_NO_CANCEL(__a__) (((__a__)->manufacturer_features&MANUFACTURER_FEATURE_XONOFF_FLOW_CONTROL)&& ((__a__)->manufacturer_features & MANUFACTURER_FEATURE_OK_FC_LABEL) && (diva_xdi_extended_features & DIVA_CAPI_XDI_PROVIDES_NO_CANCEL))
70
71/*------------------------------------------------------------------*/
72/* local function prototypes */
73/*------------------------------------------------------------------*/
74
75static void group_optimization(DIVA_CAPI_ADAPTER * a, PLCI * plci);
76static void set_group_ind_mask (PLCI *plci);
77static void clear_group_ind_mask_bit (PLCI *plci, word b);
78static byte test_group_ind_mask_bit (PLCI *plci, word b);
79void AutomaticLaw(DIVA_CAPI_ADAPTER *);
80word CapiRelease(word);
81word CapiRegister(word);
82word api_put(APPL *, CAPI_MSG *);
83static word api_parse(byte *, word, byte *, API_PARSE *);
84static void api_save_msg(API_PARSE *in, byte *format, API_SAVE *out);
85static void api_load_msg(API_SAVE *in, API_PARSE *out);
86
87word api_remove_start(void);
88void api_remove_complete(void);
89
90static void plci_remove(PLCI *);
91static void diva_get_extended_adapter_features (DIVA_CAPI_ADAPTER * a);
92static void diva_ask_for_xdi_sdram_bar (DIVA_CAPI_ADAPTER *, IDI_SYNC_REQ *);
93
94void callback(ENTITY *);
95
96static void control_rc(PLCI *, byte, byte, byte, byte, byte);
97static void data_rc(PLCI *, byte);
98static void data_ack(PLCI *, byte);
99static void sig_ind(PLCI *);
100static void SendInfo(PLCI *, dword, byte * *, byte);
101static void SendSetupInfo(APPL *, PLCI *, dword, byte * *, byte);
102static void SendSSExtInd(APPL *, PLCI * plci, dword Id, byte * * parms);
103
104static void VSwitchReqInd(PLCI *plci, dword Id, byte **parms);
105
106static void nl_ind(PLCI *);
107
108static byte connect_req(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
109static byte connect_res(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
110static byte connect_a_res(dword,word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
111static byte disconnect_req(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
112static byte disconnect_res(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
113static byte listen_req(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
114static byte info_req(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
115static byte info_res(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
116static byte alert_req(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
117static byte facility_req(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
118static byte facility_res(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
119static byte connect_b3_req(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
120static byte connect_b3_res(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
121static byte connect_b3_a_res(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
122static byte disconnect_b3_req(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
123static byte disconnect_b3_res(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
124static byte data_b3_req(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
125static byte data_b3_res(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
126static byte reset_b3_req(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
127static byte reset_b3_res(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
128static byte connect_b3_t90_a_res(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
129static byte select_b_req(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
130static byte manufacturer_req(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
131static byte manufacturer_res(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
132
133static word get_plci(DIVA_CAPI_ADAPTER *);
134static void add_p(PLCI *, byte, byte *);
135static void add_s(PLCI * plci, byte code, API_PARSE * p);
136static void add_ss(PLCI * plci, byte code, API_PARSE * p);
137static void add_ie(PLCI * plci, byte code, byte * p, word p_length);
138static void add_d(PLCI *, word, byte *);
139static void add_ai(PLCI *, API_PARSE *);
140static word add_b1(PLCI *, API_PARSE *, word, word);
141static word add_b23(PLCI *, API_PARSE *);
142static word add_modem_b23 (PLCI * plci, API_PARSE* bp_parms);
143static void sig_req(PLCI *, byte, byte);
144static void nl_req_ncci(PLCI *, byte, byte);
145static void send_req(PLCI *);
146static void send_data(PLCI *);
147static word plci_remove_check(PLCI *);
148static void listen_check(DIVA_CAPI_ADAPTER *);
149static byte AddInfo(byte **, byte **, byte *, byte *);
150static byte getChannel(API_PARSE *);
151static void IndParse(PLCI *, word *, byte **, byte);
152static byte ie_compare(byte *, byte *);
153static word find_cip(DIVA_CAPI_ADAPTER *, byte *, byte *);
154static word CPN_filter_ok(byte *cpn,DIVA_CAPI_ADAPTER *,word);
155
156/*
157 XON protocol helpers
158 */
159static void channel_flow_control_remove (PLCI * plci);
160static void channel_x_off (PLCI * plci, byte ch, byte flag);
161static void channel_x_on (PLCI * plci, byte ch);
162static void channel_request_xon (PLCI * plci, byte ch);
163static void channel_xmit_xon (PLCI * plci);
164static int channel_can_xon (PLCI * plci, byte ch);
165static void channel_xmit_extended_xon (PLCI * plci);
166
167static byte SendMultiIE(PLCI * plci, dword Id, byte * * parms, byte ie_type, dword info_mask, byte setupParse);
168static word AdvCodecSupport(DIVA_CAPI_ADAPTER *, PLCI *, APPL *, byte);
169static void CodecIdCheck(DIVA_CAPI_ADAPTER *, PLCI *);
170static void SetVoiceChannel(PLCI *, byte *, DIVA_CAPI_ADAPTER * );
171static void VoiceChannelOff(PLCI *plci);
172static void adv_voice_write_coefs (PLCI *plci, word write_command);
173static void adv_voice_clear_config (PLCI *plci);
174
175static word get_b1_facilities (PLCI * plci, byte b1_resource);
176static byte add_b1_facilities (PLCI * plci, byte b1_resource, word b1_facilities);
177static void adjust_b1_facilities (PLCI *plci, byte new_b1_resource, word new_b1_facilities);
178static word adjust_b_process (dword Id, PLCI *plci, byte Rc);
179static void adjust_b1_resource (dword Id, PLCI *plci, API_SAVE *bp_msg, word b1_facilities, word internal_command);
180static void adjust_b_restore (dword Id, PLCI *plci, byte Rc);
181static void reset_b3_command (dword Id, PLCI *plci, byte Rc);
182static void select_b_command (dword Id, PLCI *plci, byte Rc);
183static void fax_connect_ack_command (dword Id, PLCI *plci, byte Rc);
184static void fax_edata_ack_command (dword Id, PLCI *plci, byte Rc);
185static void fax_connect_info_command (dword Id, PLCI *plci, byte Rc);
186static void fax_adjust_b23_command (dword Id, PLCI *plci, byte Rc);
187static void fax_disconnect_command (dword Id, PLCI *plci, byte Rc);
188static void hold_save_command (dword Id, PLCI *plci, byte Rc);
189static void retrieve_restore_command (dword Id, PLCI *plci, byte Rc);
190static void init_b1_config (PLCI *plci);
191static void clear_b1_config (PLCI *plci);
192
193static void dtmf_command (dword Id, PLCI *plci, byte Rc);
194static byte dtmf_request (dword Id, word Number, DIVA_CAPI_ADAPTER *a, PLCI *plci, APPL *appl, API_PARSE *msg);
195static void dtmf_confirmation (dword Id, PLCI *plci);
196static void dtmf_indication (dword Id, PLCI *plci, byte *msg, word length);
197static void dtmf_parameter_write (PLCI *plci);
198
199
200static void mixer_set_bchannel_id_esc (PLCI *plci, byte bchannel_id);
201static void mixer_set_bchannel_id (PLCI *plci, byte *chi);
202static void mixer_clear_config (PLCI *plci);
203static void mixer_notify_update (PLCI *plci, byte others);
204static void mixer_command (dword Id, PLCI *plci, byte Rc);
205static byte mixer_request (dword Id, word Number, DIVA_CAPI_ADAPTER *a, PLCI *plci, APPL *appl, API_PARSE *msg);
206static void mixer_indication_coefs_set (dword Id, PLCI *plci);
207static void mixer_indication_xconnect_from (dword Id, PLCI *plci, byte *msg, word length);
208static void mixer_indication_xconnect_to (dword Id, PLCI *plci, byte *msg, word length);
209static void mixer_remove (PLCI *plci);
210
211
212static void ec_command (dword Id, PLCI *plci, byte Rc);
213static byte ec_request (dword Id, word Number, DIVA_CAPI_ADAPTER *a, PLCI *plci, APPL *appl, API_PARSE *msg);
214static void ec_indication (dword Id, PLCI *plci, byte *msg, word length);
215
216
217static void rtp_connect_b3_req_command (dword Id, PLCI *plci, byte Rc);
218static void rtp_connect_b3_res_command (dword Id, PLCI *plci, byte Rc);
219
220
221static int diva_get_dma_descriptor (PLCI *plci, dword *dma_magic);
222static void diva_free_dma_descriptor (PLCI *plci, int nr);
223
224/*------------------------------------------------------------------*/
225/* external function prototypes */
226/*------------------------------------------------------------------*/
227
228extern byte MapController (byte);
229extern byte UnMapController (byte);
230#define MapId(Id) (((Id) & 0xffffff00L) | MapController ((byte)(Id)))
231#define UnMapId(Id) (((Id) & 0xffffff00L) | UnMapController ((byte)(Id)))
232
233void sendf(APPL *, word, dword, word, byte *, ...);
234void * TransmitBufferSet(APPL * appl, dword ref);
235void * TransmitBufferGet(APPL * appl, void * p);
236void TransmitBufferFree(APPL * appl, void * p);
237void * ReceiveBufferGet(APPL * appl, int Num);
238
239int fax_head_line_time (char *buffer);
240
241
242/*------------------------------------------------------------------*/
243/* Global data definitions */
244/*------------------------------------------------------------------*/
245extern byte max_adapter;
246extern byte max_appl;
247extern DIVA_CAPI_ADAPTER * adapter;
248extern APPL * application;
249
250
251
252
253
254
255
256static byte remove_started = FALSE;
257static PLCI dummy_plci;
258
259
260static struct _ftable {
261 word command;
262 byte * format;
263 byte (* function)(dword, word, DIVA_CAPI_ADAPTER *, PLCI *, APPL *, API_PARSE *);
264} ftable[] = {
265 {_DATA_B3_R, "dwww", data_b3_req},
266 {_DATA_B3_I|RESPONSE, "w", data_b3_res},
267 {_INFO_R, "ss", info_req},
268 {_INFO_I|RESPONSE, "", info_res},
269 {_CONNECT_R, "wsssssssss", connect_req},
270 {_CONNECT_I|RESPONSE, "wsssss", connect_res},
271 {_CONNECT_ACTIVE_I|RESPONSE, "", connect_a_res},
272 {_DISCONNECT_R, "s", disconnect_req},
273 {_DISCONNECT_I|RESPONSE, "", disconnect_res},
274 {_LISTEN_R, "dddss", listen_req},
275 {_ALERT_R, "s", alert_req},
276 {_FACILITY_R, "ws", facility_req},
277 {_FACILITY_I|RESPONSE, "ws", facility_res},
278 {_CONNECT_B3_R, "s", connect_b3_req},
279 {_CONNECT_B3_I|RESPONSE, "ws", connect_b3_res},
280 {_CONNECT_B3_ACTIVE_I|RESPONSE, "", connect_b3_a_res},
281 {_DISCONNECT_B3_R, "s", disconnect_b3_req},
282 {_DISCONNECT_B3_I|RESPONSE, "", disconnect_b3_res},
283 {_RESET_B3_R, "s", reset_b3_req},
284 {_RESET_B3_I|RESPONSE, "", reset_b3_res},
285 {_CONNECT_B3_T90_ACTIVE_I|RESPONSE, "ws", connect_b3_t90_a_res},
286 {_CONNECT_B3_T90_ACTIVE_I|RESPONSE, "", connect_b3_t90_a_res},
287 {_SELECT_B_REQ, "s", select_b_req},
288 {_MANUFACTURER_R, "dws", manufacturer_req},
289 {_MANUFACTURER_I|RESPONSE, "dws", manufacturer_res},
290 {_MANUFACTURER_I|RESPONSE, "", manufacturer_res}
291};
292
293static byte * cip_bc[29][2] = {
294 { "", "" }, /* 0 */
295 { "\x03\x80\x90\xa3", "\x03\x80\x90\xa2" }, /* 1 */
296 { "\x02\x88\x90", "\x02\x88\x90" }, /* 2 */
297 { "\x02\x89\x90", "\x02\x89\x90" }, /* 3 */
298 { "\x03\x90\x90\xa3", "\x03\x90\x90\xa2" }, /* 4 */
299 { "\x03\x91\x90\xa5", "\x03\x91\x90\xa5" }, /* 5 */
300 { "\x02\x98\x90", "\x02\x98\x90" }, /* 6 */
301 { "\x04\x88\xc0\xc6\xe6", "\x04\x88\xc0\xc6\xe6" }, /* 7 */
302 { "\x04\x88\x90\x21\x8f", "\x04\x88\x90\x21\x8f" }, /* 8 */
303 { "\x03\x91\x90\xa5", "\x03\x91\x90\xa5" }, /* 9 */
304 { "", "" }, /* 10 */
305 { "", "" }, /* 11 */
306 { "", "" }, /* 12 */
307 { "", "" }, /* 13 */
308 { "", "" }, /* 14 */
309 { "", "" }, /* 15 */
310
311 { "\x03\x80\x90\xa3", "\x03\x80\x90\xa2" }, /* 16 */
312 { "\x03\x90\x90\xa3", "\x03\x90\x90\xa2" }, /* 17 */
313 { "\x02\x88\x90", "\x02\x88\x90" }, /* 18 */
314 { "\x02\x88\x90", "\x02\x88\x90" }, /* 19 */
315 { "\x02\x88\x90", "\x02\x88\x90" }, /* 20 */
316 { "\x02\x88\x90", "\x02\x88\x90" }, /* 21 */
317 { "\x02\x88\x90", "\x02\x88\x90" }, /* 22 */
318 { "\x02\x88\x90", "\x02\x88\x90" }, /* 23 */
319 { "\x02\x88\x90", "\x02\x88\x90" }, /* 24 */
320 { "\x02\x88\x90", "\x02\x88\x90" }, /* 25 */
321 { "\x03\x91\x90\xa5", "\x03\x91\x90\xa5" }, /* 26 */
322 { "\x03\x91\x90\xa5", "\x03\x91\x90\xa5" }, /* 27 */
323 { "\x02\x88\x90", "\x02\x88\x90" } /* 28 */
324};
325
326static byte * cip_hlc[29] = {
327 "", /* 0 */
328 "", /* 1 */
329 "", /* 2 */
330 "", /* 3 */
331 "", /* 4 */
332 "", /* 5 */
333 "", /* 6 */
334 "", /* 7 */
335 "", /* 8 */
336 "", /* 9 */
337 "", /* 10 */
338 "", /* 11 */
339 "", /* 12 */
340 "", /* 13 */
341 "", /* 14 */
342 "", /* 15 */
343
344 "\x02\x91\x81", /* 16 */
345 "\x02\x91\x84", /* 17 */
346 "\x02\x91\xa1", /* 18 */
347 "\x02\x91\xa4", /* 19 */
348 "\x02\x91\xa8", /* 20 */
349 "\x02\x91\xb1", /* 21 */
350 "\x02\x91\xb2", /* 22 */
351 "\x02\x91\xb5", /* 23 */
352 "\x02\x91\xb8", /* 24 */
353 "\x02\x91\xc1", /* 25 */
354 "\x02\x91\x81", /* 26 */
355 "\x03\x91\xe0\x01", /* 27 */
356 "\x03\x91\xe0\x02" /* 28 */
357};
358
359/*------------------------------------------------------------------*/
360
361#define V120_HEADER_LENGTH 1
362#define V120_HEADER_EXTEND_BIT 0x80
363#define V120_HEADER_BREAK_BIT 0x40
364#define V120_HEADER_C1_BIT 0x04
365#define V120_HEADER_C2_BIT 0x08
366#define V120_HEADER_FLUSH_COND (V120_HEADER_BREAK_BIT | V120_HEADER_C1_BIT | V120_HEADER_C2_BIT)
367
368static byte v120_default_header[] =
369{
370
371 0x83 /* Ext, BR , res, res, C2 , C1 , B , F */
372
373};
374
375static byte v120_break_header[] =
376{
377
378 0xc3 | V120_HEADER_BREAK_BIT /* Ext, BR , res, res, C2 , C1 , B , F */
379
380};
381
382
383/*------------------------------------------------------------------*/
384/* API_PUT function */
385/*------------------------------------------------------------------*/
386
387word api_put(APPL * appl, CAPI_MSG * msg)
388{
389 word i, j, k, l, n;
390 word ret;
391 byte c;
392 byte controller;
393 DIVA_CAPI_ADAPTER * a;
394 PLCI * plci;
395 NCCI * ncci_ptr;
396 word ncci;
397 CAPI_MSG *m;
398 API_PARSE msg_parms[MAX_MSG_PARMS+1];
399
400 if (msg->header.length < sizeof (msg->header) ||
401 msg->header.length > MAX_MSG_SIZE) {
402 dbug(1,dprintf("bad len"));
403 return _BAD_MSG;
404 }
405
406 controller = (byte)((msg->header.controller &0x7f)-1);
407
408 /* controller starts with 0 up to (max_adapter - 1) */
409 if ( controller >= max_adapter )
410 {
411 dbug(1,dprintf("invalid ctrl"));
412 return _BAD_MSG;
413 }
414
415 a = &adapter[controller];
416 plci = NULL;
417 if ((msg->header.plci != 0) && (msg->header.plci <= a->max_plci) && !a->adapter_disabled)
418 {
419 dbug(1,dprintf("plci=%x",msg->header.plci));
420 plci = &a->plci[msg->header.plci-1];
421 ncci = GET_WORD(&msg->header.ncci);
422 if (plci->Id
423 && (plci->appl
424 || (plci->State == INC_CON_PENDING)
425 || (plci->State == INC_CON_ALERT)
426 || (msg->header.command == (_DISCONNECT_I|RESPONSE)))
427 && ((ncci == 0)
428 || (msg->header.command == (_DISCONNECT_B3_I|RESPONSE))
429 || ((ncci < MAX_NCCI+1) && (a->ncci_plci[ncci] == plci->Id))))
430 {
431 i = plci->msg_in_read_pos;
432 j = plci->msg_in_write_pos;
433 if (j >= i)
434 {
435 if (j + msg->header.length + MSG_IN_OVERHEAD <= MSG_IN_QUEUE_SIZE)
436 i += MSG_IN_QUEUE_SIZE - j;
437 else
438 j = 0;
439 }
440 else
441 {
442
443 n = (((CAPI_MSG *)(plci->msg_in_queue))->header.length + MSG_IN_OVERHEAD + 3) & 0xfffc;
444
445 if (i > MSG_IN_QUEUE_SIZE - n)
446 i = MSG_IN_QUEUE_SIZE - n + 1;
447 i -= j;
448 }
449
450 if (i <= ((msg->header.length + MSG_IN_OVERHEAD + 3) & 0xfffc))
451
452 {
453 dbug(0,dprintf("Q-FULL1(msg) - len=%d write=%d read=%d wrap=%d free=%d",
454 msg->header.length, plci->msg_in_write_pos,
455 plci->msg_in_read_pos, plci->msg_in_wrap_pos, i));
456
457 return _QUEUE_FULL;
458 }
459 c = FALSE;
460 if ((((byte *) msg) < ((byte *)(plci->msg_in_queue)))
461 || (((byte *) msg) >= ((byte *)(plci->msg_in_queue)) + sizeof(plci->msg_in_queue)))
462 {
463 if (plci->msg_in_write_pos != plci->msg_in_read_pos)
464 c = TRUE;
465 }
466 if (msg->header.command == _DATA_B3_R)
467 {
468 if (msg->header.length < 20)
469 {
470 dbug(1,dprintf("DATA_B3 REQ wrong length %d", msg->header.length));
471 return _BAD_MSG;
472 }
473 ncci_ptr = &(a->ncci[ncci]);
474 n = ncci_ptr->data_pending;
475 l = ncci_ptr->data_ack_pending;
476 k = plci->msg_in_read_pos;
477 while (k != plci->msg_in_write_pos)
478 {
479 if (k == plci->msg_in_wrap_pos)
480 k = 0;
481 if ((((CAPI_MSG *)(&((byte *)(plci->msg_in_queue))[k]))->header.command == _DATA_B3_R)
482 && (((CAPI_MSG *)(&((byte *)(plci->msg_in_queue))[k]))->header.ncci == ncci))
483 {
484 n++;
485 if (((CAPI_MSG *)(&((byte *)(plci->msg_in_queue))[k]))->info.data_b3_req.Flags & 0x0004)
486 l++;
487 }
488
489 k += (((CAPI_MSG *)(&((byte *)(plci->msg_in_queue))[k]))->header.length +
490 MSG_IN_OVERHEAD + 3) & 0xfffc;
491
492 }
493 if ((n >= MAX_DATA_B3) || (l >= MAX_DATA_ACK))
494 {
495 dbug(0,dprintf("Q-FULL2(data) - pending=%d/%d ack_pending=%d/%d",
496 ncci_ptr->data_pending, n, ncci_ptr->data_ack_pending, l));
497
498 return _QUEUE_FULL;
499 }
500 if (plci->req_in || plci->internal_command)
501 {
502 if ((((byte *) msg) >= ((byte *)(plci->msg_in_queue)))
503 && (((byte *) msg) < ((byte *)(plci->msg_in_queue)) + sizeof(plci->msg_in_queue)))
504 {
505 dbug(0,dprintf("Q-FULL3(requeue)"));
506
507 return _QUEUE_FULL;
508 }
509 c = TRUE;
510 }
511 }
512 else
513 {
514 if (plci->req_in || plci->internal_command)
515 c = TRUE;
516 else
517 {
518 plci->command = msg->header.command;
519 plci->number = msg->header.number;
520 }
521 }
522 if (c)
523 {
524 dbug(1,dprintf("enqueue msg(0x%04x,0x%x,0x%x) - len=%d write=%d read=%d wrap=%d free=%d",
525 msg->header.command, plci->req_in, plci->internal_command,
526 msg->header.length, plci->msg_in_write_pos,
527 plci->msg_in_read_pos, plci->msg_in_wrap_pos, i));
528 if (j == 0)
529 plci->msg_in_wrap_pos = plci->msg_in_write_pos;
530 m = (CAPI_MSG *)(&((byte *)(plci->msg_in_queue))[j]);
531 for (i = 0; i < msg->header.length; i++)
532 ((byte *)(plci->msg_in_queue))[j++] = ((byte *) msg)[i];
533 if (m->header.command == _DATA_B3_R)
534 {
535
536 m->info.data_b3_req.Data = (dword)(TransmitBufferSet (appl, m->info.data_b3_req.Data));
537
538 }
539
540 j = (j + 3) & 0xfffc;
541
542 *((APPL * *)(&((byte *)(plci->msg_in_queue))[j])) = appl;
543 plci->msg_in_write_pos = j + MSG_IN_OVERHEAD;
544 return 0;
545 }
546 }
547 else
548 {
549 plci = NULL;
550 }
551 }
552 dbug(1,dprintf("com=%x",msg->header.command));
553
554 for(j=0;j<MAX_MSG_PARMS+1;j++) msg_parms[j].length = 0;
555 for(i=0, ret = _BAD_MSG;
556 i<(sizeof(ftable)/sizeof(struct _ftable));
557 i++) {
558
559 if(ftable[i].command==msg->header.command) {
560 /* break loop if the message is correct, otherwise continue scan */
561 /* (for example: CONNECT_B3_T90_ACT_RES has two specifications) */
562 if(!api_parse(msg->info.b,(word)(msg->header.length-12),ftable[i].format,msg_parms)) {
563 ret = 0;
564 break;
565 }
566 for(j=0;j<MAX_MSG_PARMS+1;j++) msg_parms[j].length = 0;
567 }
568 }
569 if(ret) {
570 dbug(1,dprintf("BAD_MSG"));
571 if(plci) plci->command = 0;
572 return ret;
573 }
574
575
576 c = ftable[i].function(GET_DWORD(&msg->header.controller),
577 msg->header.number,
578 a,
579 plci,
580 appl,
581 msg_parms);
582
583 channel_xmit_extended_xon (plci);
584
585 if(c==1) send_req(plci);
586 if(c==2 && plci) plci->req_in = plci->req_in_start = plci->req_out = 0;
587 if(plci && !plci->req_in) plci->command = 0;
588 return 0;
589}
590
591
592/*------------------------------------------------------------------*/
593/* api_parse function, check the format of api messages */
594/*------------------------------------------------------------------*/
595
596word api_parse(byte * msg, word length, byte * format, API_PARSE * parms)
597{
598 word i;
599 word p;
600
601 for(i=0,p=0; format[i]; i++) {
602 if(parms)
603 {
604 parms[i].info = &msg[p];
605 }
606 switch(format[i]) {
607 case 'b':
608 p +=1;
609 break;
610 case 'w':
611 p +=2;
612 break;
613 case 'd':
614 p +=4;
615 break;
616 case 's':
617 if(msg[p]==0xff) {
618 parms[i].info +=2;
619 parms[i].length = msg[p+1] + (msg[p+2]<<8);
620 p +=(parms[i].length +3);
621 }
622 else {
623 parms[i].length = msg[p];
624 p +=(parms[i].length +1);
625 }
626 break;
627 }
628
629 if(p>length) return TRUE;
630 }
631 if(parms) parms[i].info = NULL;
632 return FALSE;
633}
634
635void api_save_msg(API_PARSE *in, byte *format, API_SAVE *out)
636{
637 word i, j, n = 0;
638 byte *p;
639
640 p = out->info;
641 for (i = 0; format[i] != '\0'; i++)
642 {
643 out->parms[i].info = p;
644 out->parms[i].length = in[i].length;
645 switch (format[i])
646 {
647 case 'b':
648 n = 1;
649 break;
650 case 'w':
651 n = 2;
652 break;
653 case 'd':
654 n = 4;
655 break;
656 case 's':
657 n = in[i].length + 1;
658 break;
659 }
660 for (j = 0; j < n; j++)
661 *(p++) = in[i].info[j];
662 }
663 out->parms[i].info = NULL;
664 out->parms[i].length = 0;
665}
666
667void api_load_msg(API_SAVE *in, API_PARSE *out)
668{
669 word i;
670
671 i = 0;
672 do
673 {
674 out[i].info = in->parms[i].info;
675 out[i].length = in->parms[i].length;
676 } while (in->parms[i++].info);
677}
678
679
680/*------------------------------------------------------------------*/
681/* CAPI remove function */
682/*------------------------------------------------------------------*/
683
684word api_remove_start(void)
685{
686 word i;
687 word j;
688
689 if(!remove_started) {
690 remove_started = TRUE;
691 for(i=0;i<max_adapter;i++) {
692 if(adapter[i].request) {
693 for(j=0;j<adapter[i].max_plci;j++) {
694 if(adapter[i].plci[j].Sig.Id) plci_remove(&adapter[i].plci[j]);
695 }
696 }
697 }
698 return 1;
699 }
700 else {
701 for(i=0;i<max_adapter;i++) {
702 if(adapter[i].request) {
703 for(j=0;j<adapter[i].max_plci;j++) {
704 if(adapter[i].plci[j].Sig.Id) return 1;
705 }
706 }
707 }
708 }
709 api_remove_complete();
710 return 0;
711}
712
713
714/*------------------------------------------------------------------*/
715/* internal command queue */
716/*------------------------------------------------------------------*/
717
718static void init_internal_command_queue (PLCI *plci)
719{
720 word i;
721
722 dbug (1, dprintf ("%s,%d: init_internal_command_queue",
723 (char *)(FILE_), __LINE__));
724
725 plci->internal_command = 0;
726 for (i = 0; i < MAX_INTERNAL_COMMAND_LEVELS; i++)
727 plci->internal_command_queue[i] = NULL;
728}
729
730
731static void start_internal_command (dword Id, PLCI *plci, t_std_internal_command command_function)
732{
733 word i;
734
735 dbug (1, dprintf ("[%06lx] %s,%d: start_internal_command",
736 UnMapId (Id), (char *)(FILE_), __LINE__));
737
738 if (plci->internal_command == 0)
739 {
740 plci->internal_command_queue[0] = command_function;
741 (* command_function)(Id, plci, OK);
742 }
743 else
744 {
745 i = 1;
746 while (plci->internal_command_queue[i] != 0)
747 i++;
748 plci->internal_command_queue[i] = command_function;
749 }
750}
751
752
753static void next_internal_command (dword Id, PLCI *plci)
754{
755 word i;
756
757 dbug (1, dprintf ("[%06lx] %s,%d: next_internal_command",
758 UnMapId (Id), (char *)(FILE_), __LINE__));
759
760 plci->internal_command = 0;
761 plci->internal_command_queue[0] = NULL;
762 while (plci->internal_command_queue[1] != 0)
763 {
764 for (i = 0; i < MAX_INTERNAL_COMMAND_LEVELS - 1; i++)
765 plci->internal_command_queue[i] = plci->internal_command_queue[i+1];
766 plci->internal_command_queue[MAX_INTERNAL_COMMAND_LEVELS - 1] = NULL;
767 (*(plci->internal_command_queue[0]))(Id, plci, OK);
768 if (plci->internal_command != 0)
769 return;
770 plci->internal_command_queue[0] = NULL;
771 }
772}
773
774
775/*------------------------------------------------------------------*/
776/* NCCI allocate/remove function */
777/*------------------------------------------------------------------*/
778
779static dword ncci_mapping_bug = 0;
780
781static word get_ncci (PLCI *plci, byte ch, word force_ncci)
782{
783 DIVA_CAPI_ADAPTER *a;
784 word ncci, i, j, k;
785
786 a = plci->adapter;
787 if (!ch || a->ch_ncci[ch])
788 {
789 ncci_mapping_bug++;
790 dbug(1,dprintf("NCCI mapping exists %ld %02x %02x %02x-%02x",
791 ncci_mapping_bug, ch, force_ncci, a->ncci_ch[a->ch_ncci[ch]], a->ch_ncci[ch]));
792 ncci = ch;
793 }
794 else
795 {
796 if (force_ncci)
797 ncci = force_ncci;
798 else
799 {
800 if ((ch < MAX_NCCI+1) && !a->ncci_ch[ch])
801 ncci = ch;
802 else
803 {
804 ncci = 1;
805 while ((ncci < MAX_NCCI+1) && a->ncci_ch[ncci])
806 ncci++;
807 if (ncci == MAX_NCCI+1)
808 {
809 ncci_mapping_bug++;
810 i = 1;
811 do
812 {
813 j = 1;
814 while ((j < MAX_NCCI+1) && (a->ncci_ch[j] != i))
815 j++;
816 k = j;
817 if (j < MAX_NCCI+1)
818 {
819 do
820 {
821 j++;
822 } while ((j < MAX_NCCI+1) && (a->ncci_ch[j] != i));
823 }
824 } while ((i < MAX_NL_CHANNEL+1) && (j < MAX_NCCI+1));
825 if (i < MAX_NL_CHANNEL+1)
826 {
827 dbug(1,dprintf("NCCI mapping overflow %ld %02x %02x %02x-%02x-%02x",
828 ncci_mapping_bug, ch, force_ncci, i, k, j));
829 }
830 else
831 {
832 dbug(1,dprintf("NCCI mapping overflow %ld %02x %02x",
833 ncci_mapping_bug, ch, force_ncci));
834 }
835 ncci = ch;
836 }
837 }
838 a->ncci_plci[ncci] = plci->Id;
839 a->ncci_state[ncci] = IDLE;
840 if (!plci->ncci_ring_list)
841 plci->ncci_ring_list = ncci;
842 else
843 a->ncci_next[ncci] = a->ncci_next[plci->ncci_ring_list];
844 a->ncci_next[plci->ncci_ring_list] = (byte) ncci;
845 }
846 a->ncci_ch[ncci] = ch;
847 a->ch_ncci[ch] = (byte) ncci;
848 dbug(1,dprintf("NCCI mapping established %ld %02x %02x %02x-%02x",
849 ncci_mapping_bug, ch, force_ncci, ch, ncci));
850 }
851 return (ncci);
852}
853
854
855static void ncci_free_receive_buffers (PLCI *plci, word ncci)
856{
857 DIVA_CAPI_ADAPTER *a;
858 APPL *appl;
859 word i, ncci_code;
860 dword Id;
861
862 a = plci->adapter;
863 Id = (((dword) ncci) << 16) | (((word)(plci->Id)) << 8) | a->Id;
864 if (ncci)
865 {
866 if (a->ncci_plci[ncci] == plci->Id)
867 {
868 if (!plci->appl)
869 {
870 ncci_mapping_bug++;
871 dbug(1,dprintf("NCCI mapping appl expected %ld %08lx",
872 ncci_mapping_bug, Id));
873 }
874 else
875 {
876 appl = plci->appl;
877 ncci_code = ncci | (((word) a->Id) << 8);
878 for (i = 0; i < appl->MaxBuffer; i++)
879 {
880 if ((appl->DataNCCI[i] == ncci_code)
881 && (((byte)(appl->DataFlags[i] >> 8)) == plci->Id))
882 {
883 appl->DataNCCI[i] = 0;
884 }
885 }
886 }
887 }
888 }
889 else
890 {
891 for (ncci = 1; ncci < MAX_NCCI+1; ncci++)
892 {
893 if (a->ncci_plci[ncci] == plci->Id)
894 {
895 if (!plci->appl)
896 {
897 ncci_mapping_bug++;
898 dbug(1,dprintf("NCCI mapping no appl %ld %08lx",
899 ncci_mapping_bug, Id));
900 }
901 else
902 {
903 appl = plci->appl;
904 ncci_code = ncci | (((word) a->Id) << 8);
905 for (i = 0; i < appl->MaxBuffer; i++)
906 {
907 if ((appl->DataNCCI[i] == ncci_code)
908 && (((byte)(appl->DataFlags[i] >> 8)) == plci->Id))
909 {
910 appl->DataNCCI[i] = 0;
911 }
912 }
913 }
914 }
915 }
916 }
917}
918
919
920static void cleanup_ncci_data (PLCI *plci, word ncci)
921{
922 NCCI *ncci_ptr;
923
924 if (ncci && (plci->adapter->ncci_plci[ncci] == plci->Id))
925 {
926 ncci_ptr = &(plci->adapter->ncci[ncci]);
927 if (plci->appl)
928 {
929 while (ncci_ptr->data_pending != 0)
930 {
931 if (!plci->data_sent || (ncci_ptr->DBuffer[ncci_ptr->data_out].P != plci->data_sent_ptr))
932 TransmitBufferFree (plci->appl, ncci_ptr->DBuffer[ncci_ptr->data_out].P);
933 (ncci_ptr->data_out)++;
934 if (ncci_ptr->data_out == MAX_DATA_B3)
935 ncci_ptr->data_out = 0;
936 (ncci_ptr->data_pending)--;
937 }
938 }
939 ncci_ptr->data_out = 0;
940 ncci_ptr->data_pending = 0;
941 ncci_ptr->data_ack_out = 0;
942 ncci_ptr->data_ack_pending = 0;
943 }
944}
945
946
947static void ncci_remove (PLCI *plci, word ncci, byte preserve_ncci)
948{
949 DIVA_CAPI_ADAPTER *a;
950 dword Id;
951 word i;
952
953 a = plci->adapter;
954 Id = (((dword) ncci) << 16) | (((word)(plci->Id)) << 8) | a->Id;
955 if (!preserve_ncci)
956 ncci_free_receive_buffers (plci, ncci);
957 if (ncci)
958 {
959 if (a->ncci_plci[ncci] != plci->Id)
960 {
961 ncci_mapping_bug++;
962 dbug(1,dprintf("NCCI mapping doesn't exist %ld %08lx %02x",
963 ncci_mapping_bug, Id, preserve_ncci));
964 }
965 else
966 {
967 cleanup_ncci_data (plci, ncci);
968 dbug(1,dprintf("NCCI mapping released %ld %08lx %02x %02x-%02x",
969 ncci_mapping_bug, Id, preserve_ncci, a->ncci_ch[ncci], ncci));
970 a->ch_ncci[a->ncci_ch[ncci]] = 0;
971 if (!preserve_ncci)
972 {
973 a->ncci_ch[ncci] = 0;
974 a->ncci_plci[ncci] = 0;
975 a->ncci_state[ncci] = IDLE;
976 i = plci->ncci_ring_list;
977 while ((i != 0) && (a->ncci_next[i] != plci->ncci_ring_list) && (a->ncci_next[i] != ncci))
978 i = a->ncci_next[i];
979 if ((i != 0) && (a->ncci_next[i] == ncci))
980 {
981 if (i == ncci)
982 plci->ncci_ring_list = 0;
983 else if (plci->ncci_ring_list == ncci)
984 plci->ncci_ring_list = i;
985 a->ncci_next[i] = a->ncci_next[ncci];
986 }
987 a->ncci_next[ncci] = 0;
988 }
989 }
990 }
991 else
992 {
993 for (ncci = 1; ncci < MAX_NCCI+1; ncci++)
994 {
995 if (a->ncci_plci[ncci] == plci->Id)
996 {
997 cleanup_ncci_data (plci, ncci);
998 dbug(1,dprintf("NCCI mapping released %ld %08lx %02x %02x-%02x",
999 ncci_mapping_bug, Id, preserve_ncci, a->ncci_ch[ncci], ncci));
1000 a->ch_ncci[a->ncci_ch[ncci]] = 0;
1001 if (!preserve_ncci)
1002 {
1003 a->ncci_ch[ncci] = 0;
1004 a->ncci_plci[ncci] = 0;
1005 a->ncci_state[ncci] = IDLE;
1006 a->ncci_next[ncci] = 0;
1007 }
1008 }
1009 }
1010 if (!preserve_ncci)
1011 plci->ncci_ring_list = 0;
1012 }
1013}
1014
1015
1016/*------------------------------------------------------------------*/
1017/* PLCI remove function */
1018/*------------------------------------------------------------------*/
1019
1020static void plci_free_msg_in_queue (PLCI *plci)
1021{
1022 word i;
1023
1024 if (plci->appl)
1025 {
1026 i = plci->msg_in_read_pos;
1027 while (i != plci->msg_in_write_pos)
1028 {
1029 if (i == plci->msg_in_wrap_pos)
1030 i = 0;
1031 if (((CAPI_MSG *)(&((byte *)(plci->msg_in_queue))[i]))->header.command == _DATA_B3_R)
1032 {
1033
1034 TransmitBufferFree (plci->appl,
1035 (byte *)(((CAPI_MSG *)(&((byte *)(plci->msg_in_queue))[i]))->info.data_b3_req.Data));
1036
1037 }
1038
1039 i += (((CAPI_MSG *)(&((byte *)(plci->msg_in_queue))[i]))->header.length +
1040 MSG_IN_OVERHEAD + 3) & 0xfffc;
1041
1042 }
1043 }
1044 plci->msg_in_write_pos = MSG_IN_QUEUE_SIZE;
1045 plci->msg_in_read_pos = MSG_IN_QUEUE_SIZE;
1046 plci->msg_in_wrap_pos = MSG_IN_QUEUE_SIZE;
1047}
1048
1049
1050static void plci_remove(PLCI * plci)
1051{
1052
1053 if(!plci) {
1054 dbug(1,dprintf("plci_remove(no plci)"));
1055 return;
1056 }
1057 init_internal_command_queue (plci);
1058 dbug(1,dprintf("plci_remove(%x,tel=%x)",plci->Id,plci->tel));
1059 if(plci_remove_check(plci))
1060 {
1061 return;
1062 }
1063 if (plci->Sig.Id == 0xff)
1064 {
1065 dbug(1,dprintf("D-channel X.25 plci->NL.Id:%0x", plci->NL.Id));
1066 if (plci->NL.Id && !plci->nl_remove_id)
1067 {
1068 nl_req_ncci(plci,REMOVE,0);
1069 send_req(plci);
1070 }
1071 }
1072 else
1073 {
1074 if (!plci->sig_remove_id
1075 && (plci->Sig.Id
1076 || (plci->req_in!=plci->req_out)
1077 || (plci->nl_req || plci->sig_req)))
1078 {
1079 sig_req(plci,HANGUP,0);
1080 send_req(plci);
1081 }
1082 }
1083 ncci_remove (plci, 0, FALSE);
1084 plci_free_msg_in_queue (plci);
1085
1086 plci->channels = 0;
1087 plci->appl = NULL;
1088 if ((plci->State == INC_CON_PENDING) || (plci->State == INC_CON_ALERT))
1089 plci->State = OUTG_DIS_PENDING;
1090}
1091
1092/*------------------------------------------------------------------*/
1093/* Application Group function helpers */
1094/*------------------------------------------------------------------*/
1095
1096static void set_group_ind_mask (PLCI *plci)
1097{
1098 word i;
1099
1100 for (i = 0; i < C_IND_MASK_DWORDS; i++)
1101 plci->group_optimization_mask_table[i] = 0xffffffffL;
1102}
1103
1104static void clear_group_ind_mask_bit (PLCI *plci, word b)
1105{
1106 plci->group_optimization_mask_table[b >> 5] &= ~(1L << (b & 0x1f));
1107}
1108
1109static byte test_group_ind_mask_bit (PLCI *plci, word b)
1110{
1111 return ((plci->group_optimization_mask_table[b >> 5] & (1L << (b & 0x1f))) != 0);
1112}
1113
1114/*------------------------------------------------------------------*/
1115/* c_ind_mask operations for arbitrary MAX_APPL */
1116/*------------------------------------------------------------------*/
1117
1118static void clear_c_ind_mask (PLCI *plci)
1119{
1120 word i;
1121
1122 for (i = 0; i < C_IND_MASK_DWORDS; i++)
1123 plci->c_ind_mask_table[i] = 0;
1124}
1125
1126static byte c_ind_mask_empty (PLCI *plci)
1127{
1128 word i;
1129
1130 i = 0;
1131 while ((i < C_IND_MASK_DWORDS) && (plci->c_ind_mask_table[i] == 0))
1132 i++;
1133 return (i == C_IND_MASK_DWORDS);
1134}
1135
1136static void set_c_ind_mask_bit (PLCI *plci, word b)
1137{
1138 plci->c_ind_mask_table[b >> 5] |= (1L << (b & 0x1f));
1139}
1140
1141static void clear_c_ind_mask_bit (PLCI *plci, word b)
1142{
1143 plci->c_ind_mask_table[b >> 5] &= ~(1L << (b & 0x1f));
1144}
1145
1146static byte test_c_ind_mask_bit (PLCI *plci, word b)
1147{
1148 return ((plci->c_ind_mask_table[b >> 5] & (1L << (b & 0x1f))) != 0);
1149}
1150
1151static void dump_c_ind_mask (PLCI *plci)
1152{
1153static char hex_digit_table[0x10] =
1154 {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
1155 word i, j, k;
1156 dword d;
1157 char *p;
1158 char buf[40];
1159
1160 for (i = 0; i < C_IND_MASK_DWORDS; i += 4)
1161 {
1162 p = buf + 36;
1163 *p = '\0';
1164 for (j = 0; j < 4; j++)
1165 {
1166 if (i+j < C_IND_MASK_DWORDS)
1167 {
1168 d = plci->c_ind_mask_table[i+j];
1169 for (k = 0; k < 8; k++)
1170 {
1171 *(--p) = hex_digit_table[d & 0xf];
1172 d >>= 4;
1173 }
1174 }
1175 else if (i != 0)
1176 {
1177 for (k = 0; k < 8; k++)
1178 *(--p) = ' ';
1179 }
1180 *(--p) = ' ';
1181 }
1182 dbug(1,dprintf ("c_ind_mask =%s", (char *) p));
1183 }
1184}
1185
1186
1187
1188
1189
1190#define dump_plcis(a)
1191
1192
1193
1194/*------------------------------------------------------------------*/
1195/* translation function for each message */
1196/*------------------------------------------------------------------*/
1197
1198byte connect_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * parms)
1199{
1200 word ch;
1201 word i;
1202 word Info;
1203 word CIP;
1204 byte LinkLayer;
1205 API_PARSE * ai;
1206 API_PARSE * bp;
1207 API_PARSE ai_parms[5];
1208 word channel = 0;
1209 dword ch_mask;
1210 byte m;
1211 static byte esc_chi[35] = {0x02,0x18,0x01};
1212 static byte lli[2] = {0x01,0x00};
1213 byte noCh = 0;
1214 word dir = 0;
1215 byte *p_chi = "";
1216
1217 for(i=0;i<5;i++) ai_parms[i].length = 0;
1218
1219 dbug(1,dprintf("connect_req(%d)",parms->length));
1220 Info = _WRONG_IDENTIFIER;
1221 if(a)
1222 {
1223 if(a->adapter_disabled)
1224 {
1225 dbug(1,dprintf("adapter disabled"));
1226 Id = ((word)1<<8)|a->Id;
1227 sendf(appl,_CONNECT_R|CONFIRM,Id,Number,"w",0);
1228 sendf(appl, _DISCONNECT_I, Id, 0, "w", _L1_ERROR);
1229 return FALSE;
1230 }
1231 Info = _OUT_OF_PLCI;
1232 if((i=get_plci(a)))
1233 {
1234 Info = 0;
1235 plci = &a->plci[i-1];
1236 plci->appl = appl;
1237 plci->call_dir = CALL_DIR_OUT | CALL_DIR_ORIGINATE;
1238 /* check 'external controller' bit for codec support */
1239 if(Id & EXT_CONTROLLER)
1240 {
1241 if(AdvCodecSupport(a, plci, appl, 0) )
1242 {
1243 plci->Id = 0;
1244 sendf(appl, _CONNECT_R|CONFIRM, Id, Number, "w", _WRONG_IDENTIFIER);
1245 return 2;
1246 }
1247 }
1248 ai = &parms[9];
1249 bp = &parms[5];
1250 ch = 0;
1251 if(bp->length)LinkLayer = bp->info[3];
1252 else LinkLayer = 0;
1253 if(ai->length)
1254 {
1255 ch=0xffff;
1256 if(!api_parse(&ai->info[1],(word)ai->length,"ssss",ai_parms))
1257 {
1258 ch = 0;
1259 if(ai_parms[0].length)
1260 {
1261 ch = GET_WORD(ai_parms[0].info+1);
1262 if(ch>4) ch=0; /* safety -> ignore ChannelID */
1263 if(ch==4) /* explizit CHI in message */
1264 {
1265 /* check length of B-CH struct */
1266 if((ai_parms[0].info)[3]>=1)
1267 {
1268 if((ai_parms[0].info)[4]==CHI)
1269 {
1270 p_chi = &((ai_parms[0].info)[5]);
1271 }
1272 else
1273 {
1274 p_chi = &((ai_parms[0].info)[3]);
1275 }
1276 if(p_chi[0]>35) /* check length of channel ID */
1277 {
1278 Info = _WRONG_MESSAGE_FORMAT;
1279 }
1280 }
1281 else Info = _WRONG_MESSAGE_FORMAT;
1282 }
1283
1284 if(ch==3 && ai_parms[0].length>=7 && ai_parms[0].length<=36)
1285 {
1286 dir = GET_WORD(ai_parms[0].info+3);
1287 ch_mask = 0;
1288 m = 0x3f;
1289 for(i=0; i+5<=ai_parms[0].length; i++)
1290 {
1291 if(ai_parms[0].info[i+5]!=0)
1292 {
1293 if((ai_parms[0].info[i+5] | m) != 0xff)
1294 Info = _WRONG_MESSAGE_FORMAT;
1295 else
1296 {
1297 if (ch_mask == 0)
1298 channel = i;
1299 ch_mask |= 1L << i;
1300 }
1301 }
1302 m = 0;
1303 }
1304 if (ch_mask == 0)
1305 Info = _WRONG_MESSAGE_FORMAT;
1306 if (!Info)
1307 {
1308 if ((ai_parms[0].length == 36) || (ch_mask != ((dword)(1L << channel))))
1309 {
1310 esc_chi[0] = (byte)(ai_parms[0].length - 2);
1311 for(i=0; i+5<=ai_parms[0].length; i++)
1312 esc_chi[i+3] = ai_parms[0].info[i+5];
1313 }
1314 else
1315 esc_chi[0] = 2;
1316 esc_chi[2] = (byte)channel;
1317 plci->b_channel = (byte)channel; /* not correct for ETSI ch 17..31 */
1318 add_p(plci,LLI,lli);
1319 add_p(plci,ESC,esc_chi);
1320 plci->State = LOCAL_CONNECT;
1321 if(!dir) plci->call_dir |= CALL_DIR_FORCE_OUTG_NL; /* dir 0=DTE, 1=DCE */
1322 }
1323 }
1324 }
1325 }
1326 else Info = _WRONG_MESSAGE_FORMAT;
1327 }
1328
1329 dbug(1,dprintf("ch=%x,dir=%x,p_ch=%d",ch,dir,channel));
1330 plci->command = _CONNECT_R;
1331 plci->number = Number;
1332 /* x.31 or D-ch free SAPI in LinkLayer? */
1333 if(ch==1 && LinkLayer!=3 && LinkLayer!=12) noCh = TRUE;
1334 if((ch==0 || ch==2 || noCh || ch==3 || ch==4) && !Info)
1335 {
1336 /* B-channel used for B3 connections (ch==0), or no B channel */
1337 /* is used (ch==2) or perm. connection (3) is used do a CALL */
1338 if(noCh) Info = add_b1(plci,&parms[5],2,0); /* no resource */
1339 else Info = add_b1(plci,&parms[5],ch,0);
1340 add_s(plci,OAD,&parms[2]);
1341 add_s(plci,OSA,&parms[4]);
1342 add_s(plci,BC,&parms[6]);
1343 add_s(plci,LLC,&parms[7]);
1344 add_s(plci,HLC,&parms[8]);
1345 CIP = GET_WORD(parms[0].info);
1346 if (a->Info_Mask[appl->Id-1] & 0x200)
1347 {
1348 /* early B3 connect (CIP mask bit 9) no release after a disc */
1349 add_p(plci,LLI,"\x01\x01");
1350 }
1351 if(GET_WORD(parms[0].info)<29) {
1352 add_p(plci,BC,cip_bc[GET_WORD(parms[0].info)][a->u_law]);
1353 add_p(plci,HLC,cip_hlc[GET_WORD(parms[0].info)]);
1354 }
1355 add_p(plci,UID,"\x06\x43\x61\x70\x69\x32\x30");
1356 sig_req(plci,ASSIGN,DSIG_ID);
1357 }
1358 else if(ch==1) {
1359
1360 /* D-Channel used for B3 connections */
1361 plci->Sig.Id = 0xff;
1362 Info = 0;
1363 }
1364
1365 if(!Info && ch!=2 && !noCh ) {
1366 Info = add_b23(plci,&parms[5]);
1367 if(!Info) {
1368 if(!(plci->tel && !plci->adv_nl))nl_req_ncci(plci,ASSIGN,0);
1369 }
1370 }
1371
1372 if(!Info)
1373 {
1374 if(ch==0 || ch==2 || ch==3 || noCh || ch==4)
1375 {
1376 if(plci->spoofed_msg==SPOOFING_REQUIRED)
1377 {
1378 api_save_msg(parms, "wsssssssss", &plci->saved_msg);
1379 plci->spoofed_msg = CALL_REQ;
1380 plci->internal_command = BLOCK_PLCI;
1381 plci->command = 0;
1382 dbug(1,dprintf("Spoof"));
1383 send_req(plci);
1384 return FALSE;
1385 }
1386 if(ch==4)add_p(plci,CHI,p_chi);
1387 add_s(plci,CPN,&parms[1]);
1388 add_s(plci,DSA,&parms[3]);
1389 if(noCh) add_p(plci,ESC,"\x02\x18\xfd"); /* D-channel, no B-L3 */
1390 add_ai(plci,&parms[9]);
1391 if(!dir)sig_req(plci,CALL_REQ,0);
1392 else
1393 {
1394 plci->command = PERM_LIST_REQ;
1395 plci->appl = appl;
1396 sig_req(plci,LISTEN_REQ,0);
1397 send_req(plci);
1398 return FALSE;
1399 }
1400 }
1401 send_req(plci);
1402 return FALSE;
1403 }
1404 plci->Id = 0;
1405 }
1406 }
1407 sendf(appl,
1408 _CONNECT_R|CONFIRM,
1409 Id,
1410 Number,
1411 "w",Info);
1412 return 2;
1413}
1414
1415byte connect_res(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * parms)
1416{
1417 word i, Info;
1418 word Reject;
1419 static byte cau_t[] = {0,0,0x90,0x91,0xac,0x9d,0x86,0xd8,0x9b};
1420 static byte esc_t[] = {0x03,0x08,0x00,0x00};
1421 API_PARSE * ai;
1422 API_PARSE ai_parms[5];
1423 word ch=0;
1424
1425 if(!plci) {
1426 dbug(1,dprintf("connect_res(no plci)"));
1427 return 0; /* no plci, no send */
1428 }
1429
1430 dbug(1,dprintf("connect_res(State=0x%x)",plci->State));
1431 for(i=0;i<5;i++) ai_parms[i].length = 0;
1432 ai = &parms[5];
1433 dbug(1,dprintf("ai->length=%d",ai->length));
1434
1435 if(ai->length)
1436 {
1437 if(!api_parse(&ai->info[1],(word)ai->length,"ssss",ai_parms))
1438 {
1439 dbug(1,dprintf("ai_parms[0].length=%d/0x%x",ai_parms[0].length,GET_WORD(ai_parms[0].info+1)));
1440 ch = 0;
1441 if(ai_parms[0].length)
1442 {
1443 ch = GET_WORD(ai_parms[0].info+1);
1444 dbug(1,dprintf("BCH-I=0x%x",ch));
1445 }
1446 }
1447 }
1448
1449 if(plci->State==INC_CON_CONNECTED_ALERT)
1450 {
1451 dbug(1,dprintf("Connected Alert Call_Res"));
1452 if (a->Info_Mask[appl->Id-1] & 0x200)
1453 {
1454 /* early B3 connect (CIP mask bit 9) no release after a disc */
1455 add_p(plci,LLI,"\x01\x01");
1456 }
1457 add_s(plci, CONN_NR, &parms[2]);
1458 add_s(plci, LLC, &parms[4]);
1459 add_ai(plci, &parms[5]);
1460 plci->State = INC_CON_ACCEPT;
1461 sig_req(plci, CALL_RES,0);
1462 return 1;
1463 }
1464 else if(plci->State==INC_CON_PENDING || plci->State==INC_CON_ALERT) {
1465 clear_c_ind_mask_bit (plci, (word)(appl->Id-1));
1466 dump_c_ind_mask (plci);
1467 Reject = GET_WORD(parms[0].info);
1468 dbug(1,dprintf("Reject=0x%x",Reject));
1469 if(Reject)
1470 {
1471 if(c_ind_mask_empty (plci))
1472 {
1473 if((Reject&0xff00)==0x3400)
1474 {
1475 esc_t[2] = ((byte)(Reject&0x00ff)) | 0x80;
1476 add_p(plci,ESC,esc_t);
1477 add_ai(plci, &parms[5]);
1478 sig_req(plci,REJECT,0);
1479 }
1480 else if(Reject==1 || Reject>9)
1481 {
1482 add_ai(plci, &parms[5]);
1483 sig_req(plci,HANGUP,0);
1484 }
1485 else
1486 {
1487 esc_t[2] = cau_t[(Reject&0x000f)];
1488 add_p(plci,ESC,esc_t);
1489 add_ai(plci, &parms[5]);
1490 sig_req(plci,REJECT,0);
1491 }
1492 plci->appl = appl;
1493 }
1494 else
1495 {
1496 sendf(appl, _DISCONNECT_I, Id, 0, "w", _OTHER_APPL_CONNECTED);
1497 }
1498 }
1499 else {
1500 plci->appl = appl;
1501 if(Id & EXT_CONTROLLER){
1502 if(AdvCodecSupport(a, plci, appl, 0)){
1503 dbug(1,dprintf("connect_res(error from AdvCodecSupport)"));
1504 sig_req(plci,HANGUP,0);
1505 return 1;
1506 }
1507 if(plci->tel == ADV_VOICE && a->AdvCodecPLCI)
1508 {
1509 Info = add_b23(plci, &parms[1]);
1510 if (Info)
1511 {
1512 dbug(1,dprintf("connect_res(error from add_b23)"));
1513 sig_req(plci,HANGUP,0);
1514 return 1;
1515 }
1516 if(plci->adv_nl)
1517 {
1518 nl_req_ncci(plci, ASSIGN, 0);
1519 }
1520 }
1521 }
1522 else
1523 {
1524 plci->tel = 0;
1525 if(ch!=2)
1526 {
1527 Info = add_b23(plci, &parms[1]);
1528 if (Info)
1529 {
1530 dbug(1,dprintf("connect_res(error from add_b23 2)"));
1531 sig_req(plci,HANGUP,0);
1532 return 1;
1533 }
1534 }
1535 nl_req_ncci(plci, ASSIGN, 0);
1536 }
1537
1538 if(plci->spoofed_msg==SPOOFING_REQUIRED)
1539 {
1540 api_save_msg(parms, "wsssss", &plci->saved_msg);
1541 plci->spoofed_msg = CALL_RES;
1542 plci->internal_command = BLOCK_PLCI;
1543 plci->command = 0;
1544 dbug(1,dprintf("Spoof"));
1545 }
1546 else
1547 {
1548 add_b1 (plci, &parms[1], ch, plci->B1_facilities);
1549 if (a->Info_Mask[appl->Id-1] & 0x200)
1550 {
1551 /* early B3 connect (CIP mask bit 9) no release after a disc */
1552 add_p(plci,LLI,"\x01\x01");
1553 }
1554 add_s(plci, CONN_NR, &parms[2]);
1555 add_s(plci, LLC, &parms[4]);
1556 add_ai(plci, &parms[5]);
1557 plci->State = INC_CON_ACCEPT;
1558 sig_req(plci, CALL_RES,0);
1559 }
1560
1561 for(i=0; i<max_appl; i++) {
1562 if(test_c_ind_mask_bit (plci, i)) {
1563 sendf(&application[i], _DISCONNECT_I, Id, 0, "w", _OTHER_APPL_CONNECTED);
1564 }
1565 }
1566 }
1567 }
1568 return 1;
1569}
1570
1571byte connect_a_res(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * msg)
1572{
1573 dbug(1,dprintf("connect_a_res"));
1574 return FALSE;
1575}
1576
1577byte disconnect_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * msg)
1578{
1579 word Info;
1580 word i;
1581
1582 dbug(1,dprintf("disconnect_req"));
1583
1584 Info = _WRONG_IDENTIFIER;
1585
1586 if(plci)
1587 {
1588 if(plci->State==INC_CON_PENDING || plci->State==INC_CON_ALERT)
1589 {
1590 clear_c_ind_mask_bit (plci, (word)(appl->Id-1));
1591 plci->appl = appl;
1592 for(i=0; i<max_appl; i++)
1593 {
1594 if(test_c_ind_mask_bit (plci, i))
1595 sendf(&application[i], _DISCONNECT_I, Id, 0, "w", 0);
1596 }
1597 plci->State = OUTG_DIS_PENDING;
1598 }
1599 if(plci->Sig.Id && plci->appl)
1600 {
1601 Info = 0;
1602 if(plci->Sig.Id!=0xff)
1603 {
1604 if(plci->State!=INC_DIS_PENDING)
1605 {
1606 add_ai(plci, &msg[0]);
1607 sig_req(plci,HANGUP,0);
1608 plci->State = OUTG_DIS_PENDING;
1609 return 1;
1610 }
1611 }
1612 else
1613 {
1614 if (plci->NL.Id && !plci->nl_remove_id)
1615 {
1616 mixer_remove (plci);
1617 nl_req_ncci(plci,REMOVE,0);
1618 sendf(appl,_DISCONNECT_R|CONFIRM,Id,Number,"w",0);
1619 sendf(appl, _DISCONNECT_I, Id, 0, "w", 0);
1620 plci->State = INC_DIS_PENDING;
1621 }
1622 return 1;
1623 }
1624 }
1625 }
1626
1627 if(!appl) return FALSE;
1628 sendf(appl, _DISCONNECT_R|CONFIRM, Id, Number, "w",Info);
1629 return FALSE;
1630}
1631
1632byte disconnect_res(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * msg)
1633{
1634 dbug(1,dprintf("disconnect_res"));
1635 if(plci)
1636 {
1637 /* clear ind mask bit, just in case of collsion of */
1638 /* DISCONNECT_IND and CONNECT_RES */
1639 clear_c_ind_mask_bit (plci, (word)(appl->Id-1));
1640 ncci_free_receive_buffers (plci, 0);
1641 if(plci_remove_check(plci))
1642 {
1643 return 0;
1644 }
1645 if(plci->State==INC_DIS_PENDING
1646 || plci->State==SUSPENDING) {
1647 if(c_ind_mask_empty (plci)) {
1648 if(plci->State!=SUSPENDING)plci->State = IDLE;
1649 dbug(1,dprintf("chs=%d",plci->channels));
1650 if(!plci->channels) {
1651 plci_remove(plci);
1652 }
1653 }
1654 }
1655 }
1656 return 0;
1657}
1658
1659byte listen_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * parms)
1660{
1661 word Info;
1662 byte i;
1663
1664 dbug(1,dprintf("listen_req(Appl=0x%x)",appl->Id));
1665
1666 Info = _WRONG_IDENTIFIER;
1667 if(a) {
1668 Info = 0;
1669 a->Info_Mask[appl->Id-1] = GET_DWORD(parms[0].info);
1670 a->CIP_Mask[appl->Id-1] = GET_DWORD(parms[1].info);
1671 dbug(1,dprintf("CIP_MASK=0x%lx",GET_DWORD(parms[1].info)));
1672 if (a->Info_Mask[appl->Id-1] & 0x200){ /* early B3 connect provides */
1673 a->Info_Mask[appl->Id-1] |= 0x10; /* call progression infos */
1674 }
1675
1676 /* check if external controller listen and switch listen on or off*/
1677 if(Id&EXT_CONTROLLER && GET_DWORD(parms[1].info)){
1678 if(a->profile.Global_Options & ON_BOARD_CODEC) {
1679 dummy_plci.State = IDLE;
1680 a->codec_listen[appl->Id-1] = &dummy_plci;
1681 a->TelOAD[0] = (byte)(parms[3].length);
1682 for(i=1;parms[3].length>=i && i<22;i++) {
1683 a->TelOAD[i] = parms[3].info[i];
1684 }
1685 a->TelOAD[i] = 0;
1686 a->TelOSA[0] = (byte)(parms[4].length);
1687 for(i=1;parms[4].length>=i && i<22;i++) {
1688 a->TelOSA[i] = parms[4].info[i];
1689 }
1690 a->TelOSA[i] = 0;
1691 }
1692 else Info = 0x2002; /* wrong controller, codec not supported */
1693 }
1694 else{ /* clear listen */
1695 a->codec_listen[appl->Id-1] = (PLCI *)0;
1696 }
1697 }
1698 sendf(appl,
1699 _LISTEN_R|CONFIRM,
1700 Id,
1701 Number,
1702 "w",Info);
1703
1704 if (a) listen_check(a);
1705 return FALSE;
1706}
1707
1708byte info_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * msg)
1709{
1710 word i;
1711 API_PARSE * ai;
1712 PLCI * rc_plci = NULL;
1713 API_PARSE ai_parms[5];
1714 word Info = 0;
1715
1716 dbug(1,dprintf("info_req"));
1717 for(i=0;i<5;i++) ai_parms[i].length = 0;
1718
1719 ai = &msg[1];
1720
1721 if(ai->length)
1722 {
1723 if(api_parse(&ai->info[1],(word)ai->length,"ssss",ai_parms))
1724 {
1725 dbug(1,dprintf("AddInfo wrong"));
1726 Info = _WRONG_MESSAGE_FORMAT;
1727 }
1728 }
1729 if(!a) Info = _WRONG_STATE;
1730
1731 if(!Info && plci)
1732 { /* no fac, with CPN, or KEY */
1733 rc_plci = plci;
1734 if(!ai_parms[3].length && plci->State && (msg[0].length || ai_parms[1].length) )
1735 {
1736 /* overlap sending option */
1737 dbug(1,dprintf("OvlSnd"));
1738 add_s(plci,CPN,&msg[0]);
1739 add_s(plci,KEY,&ai_parms[1]);
1740 sig_req(plci,INFO_REQ,0);
1741 send_req(plci);
1742 return FALSE;
1743 }
1744
1745 if(plci->State && ai_parms[2].length)
1746 {
1747 /* User_Info option */
1748 dbug(1,dprintf("UUI"));
1749 add_s(plci,UUI,&ai_parms[2]);
1750 sig_req(plci,USER_DATA,0);
1751 }
1752 else if(plci->State && ai_parms[3].length)
1753 {
1754 /* Facility option */
1755 dbug(1,dprintf("FAC"));
1756 add_s(plci,CPN,&msg[0]);
1757 add_ai(plci, &msg[1]);
1758 sig_req(plci,FACILITY_REQ,0);
1759 }
1760 else
1761 {
1762 Info = _WRONG_STATE;
1763 }
1764 }
1765 else if((ai_parms[1].length || ai_parms[2].length || ai_parms[3].length) && !Info)
1766 {
1767 /* NCR_Facility option -> send UUI and Keypad too */
1768 dbug(1,dprintf("NCR_FAC"));
1769 if((i=get_plci(a)))
1770 {
1771 rc_plci = &a->plci[i-1];
1772 appl->NullCREnable = TRUE;
1773 rc_plci->internal_command = C_NCR_FAC_REQ;
1774 rc_plci->appl = appl;
1775 add_p(rc_plci,CAI,"\x01\x80");
1776 add_p(rc_plci,UID,"\x06\x43\x61\x70\x69\x32\x30");
1777 sig_req(rc_plci,ASSIGN,DSIG_ID);
1778 send_req(rc_plci);
1779 }
1780 else
1781 {
1782 Info = _OUT_OF_PLCI;
1783 }
1784
1785 if(!Info)
1786 {
1787 add_s(rc_plci,CPN,&msg[0]);
1788 add_ai(rc_plci, &msg[1]);
1789 sig_req(rc_plci,NCR_FACILITY,0);
1790 send_req(rc_plci);
1791 return FALSE;
1792 /* for application controlled supplementary services */
1793 }
1794 }
1795
1796 if (!rc_plci)
1797 {
1798 Info = _WRONG_MESSAGE_FORMAT;
1799 }
1800
1801 if(!Info)
1802 {
1803 send_req(rc_plci);
1804 }
1805 else
1806 { /* appl is not assigned to a PLCI or error condition */
1807 dbug(1,dprintf("localInfoCon"));
1808 sendf(appl,
1809 _INFO_R|CONFIRM,
1810 Id,
1811 Number,
1812 "w",Info);
1813 }
1814 return FALSE;
1815}
1816
1817byte info_res(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * msg)
1818{
1819 dbug(1,dprintf("info_res"));
1820 return FALSE;
1821}
1822
1823byte alert_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * msg)
1824{
1825 word Info;
1826 byte ret;
1827
1828 dbug(1,dprintf("alert_req"));
1829
1830 Info = _WRONG_IDENTIFIER;
1831 ret = FALSE;
1832 if(plci) {
1833 Info = _ALERT_IGNORED;
1834 if(plci->State!=INC_CON_ALERT) {
1835 Info = _WRONG_STATE;
1836 if(plci->State==INC_CON_PENDING) {
1837 Info = 0;
1838 plci->State=INC_CON_ALERT;
1839 add_ai(plci, &msg[0]);
1840 sig_req(plci,CALL_ALERT,0);
1841 ret = 1;
1842 }
1843 }
1844 }
1845 sendf(appl,
1846 _ALERT_R|CONFIRM,
1847 Id,
1848 Number,
1849 "w",Info);
1850 return ret;
1851}
1852
1853byte facility_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * msg)
1854{
1855 word Info = 0;
1856 word i = 0;
1857
1858 word selector;
1859 word SSreq;
1860 long relatedPLCIvalue;
1861 DIVA_CAPI_ADAPTER * relatedadapter;
1862 byte * SSparms = "";
1863 byte RCparms[] = "\x05\x00\x00\x02\x00\x00";
1864 byte SSstruct[] = "\x09\x00\x00\x06\x00\x00\x00\x00\x00\x00";
1865 API_PARSE * parms;
1866 API_PARSE ss_parms[11];
1867 PLCI *rplci;
1868 byte cai[15];
1869 dword d;
1870 API_PARSE dummy;
1871
1872 dbug(1,dprintf("facility_req"));
1873 for(i=0;i<9;i++) ss_parms[i].length = 0;
1874
1875 parms = &msg[1];
1876
1877 if(!a)
1878 {
1879 dbug(1,dprintf("wrong Ctrl"));
1880 Info = _WRONG_IDENTIFIER;
1881 }
1882
1883 selector = GET_WORD(msg[0].info);
1884
1885 if(!Info)
1886 {
1887 switch(selector)
1888 {
1889 case SELECTOR_HANDSET:
1890 Info = AdvCodecSupport(a, plci, appl, HOOK_SUPPORT);
1891 break;
1892
1893 case SELECTOR_SU_SERV:
1894 if(!msg[1].length)
1895 {
1896 Info = _WRONG_MESSAGE_FORMAT;
1897 break;
1898 }
1899 SSreq = GET_WORD(&(msg[1].info[1]));
1900 PUT_WORD(&RCparms[1],SSreq);
1901 SSparms = RCparms;
1902 switch(SSreq)
1903 {
1904 case S_GET_SUPPORTED_SERVICES:
1905 if((i=get_plci(a)))
1906 {
1907 rplci = &a->plci[i-1];
1908 rplci->appl = appl;
1909 add_p(rplci,CAI,"\x01\x80");
1910 add_p(rplci,UID,"\x06\x43\x61\x70\x69\x32\x30");
1911 sig_req(rplci,ASSIGN,DSIG_ID);
1912 send_req(rplci);
1913 }
1914 else
1915 {
1916 PUT_DWORD(&SSstruct[6], MASK_TERMINAL_PORTABILITY);
1917 SSparms = (byte *)SSstruct;
1918 break;
1919 }
1920 rplci->internal_command = GETSERV_REQ_PEND;
1921 rplci->number = Number;
1922 rplci->appl = appl;
1923 sig_req(rplci,S_SUPPORTED,0);
1924 send_req(rplci);
1925 return FALSE;
1926 break;
1927
1928 case S_LISTEN:
1929 if(parms->length==7)
1930 {
1931 if(api_parse(&parms->info[1],(word)parms->length,"wbd",ss_parms))
1932 {
1933 dbug(1,dprintf("format wrong"));
1934 Info = _WRONG_MESSAGE_FORMAT;
1935 break;
1936 }
1937 }
1938 else
1939 {
1940 Info = _WRONG_MESSAGE_FORMAT;
1941 break;
1942 }
1943 a->Notification_Mask[appl->Id-1] = GET_DWORD(ss_parms[2].info);
1944 if(a->Notification_Mask[appl->Id-1] & SMASK_MWI) /* MWI active? */
1945 {
1946 if((i=get_plci(a)))
1947 {
1948 rplci = &a->plci[i-1];
1949 rplci->appl = appl;
1950 add_p(rplci,CAI,"\x01\x80");
1951 add_p(rplci,UID,"\x06\x43\x61\x70\x69\x32\x30");
1952 sig_req(rplci,ASSIGN,DSIG_ID);
1953 send_req(rplci);
1954 }
1955 else
1956 {
1957 break;
1958 }
1959 rplci->internal_command = GET_MWI_STATE;
1960 rplci->number = Number;
1961 sig_req(rplci,MWI_POLL,0);
1962 send_req(rplci);
1963 }
1964 break;
1965
1966 case S_HOLD:
1967 api_parse(&parms->info[1],(word)parms->length,"ws",ss_parms);
1968 if(plci && plci->State && plci->SuppState==IDLE)
1969 {
1970 plci->SuppState = HOLD_REQUEST;
1971 plci->command = C_HOLD_REQ;
1972 add_s(plci,CAI,&ss_parms[1]);
1973 sig_req(plci,CALL_HOLD,0);
1974 send_req(plci);
1975 return FALSE;
1976 }
1977 else Info = 0x3010; /* wrong state */
1978 break;
1979 case S_RETRIEVE:
1980 if(plci && plci->State && plci->SuppState==CALL_HELD)
1981 {
1982 if(Id & EXT_CONTROLLER)
1983 {
1984 if(AdvCodecSupport(a, plci, appl, 0))
1985 {
1986 Info = 0x3010; /* wrong state */
1987 break;
1988 }
1989 }
1990 else plci->tel = 0;
1991
1992 plci->SuppState = RETRIEVE_REQUEST;
1993 plci->command = C_RETRIEVE_REQ;
1994 if(plci->spoofed_msg==SPOOFING_REQUIRED)
1995 {
1996 plci->spoofed_msg = CALL_RETRIEVE;
1997 plci->internal_command = BLOCK_PLCI;
1998 plci->command = 0;
1999 dbug(1,dprintf("Spoof"));
2000 return FALSE;
2001 }
2002 else
2003 {
2004 sig_req(plci,CALL_RETRIEVE,0);
2005 send_req(plci);
2006 return FALSE;
2007 }
2008 }
2009 else Info = 0x3010; /* wrong state */
2010 break;
2011 case S_SUSPEND:
2012 if(parms->length)
2013 {
2014 if(api_parse(&parms->info[1],(word)parms->length,"wbs",ss_parms))
2015 {
2016 dbug(1,dprintf("format wrong"));
2017 Info = _WRONG_MESSAGE_FORMAT;
2018 break;
2019 }
2020 }
2021 if(plci && plci->State)
2022 {
2023 add_s(plci,CAI,&ss_parms[2]);
2024 plci->command = SUSPEND_REQ;
2025 sig_req(plci,SUSPEND,0);
2026 plci->State = SUSPENDING;
2027 send_req(plci);
2028 }
2029 else Info = 0x3010; /* wrong state */
2030 break;
2031
2032 case S_RESUME:
2033 if(!(i=get_plci(a)) )
2034 {
2035 Info = _OUT_OF_PLCI;
2036 break;
2037 }
2038 rplci = &a->plci[i-1];
2039 rplci->appl = appl;
2040 rplci->number = Number;
2041 rplci->tel = 0;
2042 rplci->call_dir = CALL_DIR_OUT | CALL_DIR_ORIGINATE;
2043 /* check 'external controller' bit for codec support */
2044 if(Id & EXT_CONTROLLER)
2045 {
2046 if(AdvCodecSupport(a, rplci, appl, 0) )
2047 {
2048 rplci->Id = 0;
2049 Info = 0x300A;
2050 break;
2051 }
2052 }
2053 if(parms->length)
2054 {
2055 if(api_parse(&parms->info[1],(word)parms->length,"wbs",ss_parms))
2056 {
2057 dbug(1,dprintf("format wrong"));
2058 rplci->Id = 0;
2059 Info = _WRONG_MESSAGE_FORMAT;
2060 break;
2061 }
2062 }
2063 dummy.length = 0;
2064 dummy.info = "\x00";
2065 add_b1(rplci, &dummy, 0, 0);
2066 if (a->Info_Mask[appl->Id-1] & 0x200)
2067 {
2068 /* early B3 connect (CIP mask bit 9) no release after a disc */
2069 add_p(rplci,LLI,"\x01\x01");
2070 }
2071 add_p(rplci,UID,"\x06\x43\x61\x70\x69\x32\x30");
2072 sig_req(rplci,ASSIGN,DSIG_ID);
2073 send_req(rplci);
2074 add_s(rplci,CAI,&ss_parms[2]);
2075 rplci->command = RESUME_REQ;
2076 sig_req(rplci,RESUME,0);
2077 rplci->State = RESUMING;
2078 send_req(rplci);
2079 break;
2080
2081 case S_CONF_BEGIN: /* Request */
2082 case S_CONF_DROP:
2083 case S_CONF_ISOLATE:
2084 case S_CONF_REATTACH:
2085 if(api_parse(&parms->info[1],(word)parms->length,"wbd",ss_parms))
2086 {
2087 dbug(1,dprintf("format wrong"));
2088 Info = _WRONG_MESSAGE_FORMAT;
2089 break;
2090 }
2091 if(plci && plci->State && ((plci->SuppState==IDLE)||(plci->SuppState==CALL_HELD)))
2092 {
2093 d = GET_DWORD(ss_parms[2].info);
2094 if(d>=0x80)
2095 {
2096 dbug(1,dprintf("format wrong"));
2097 Info = _WRONG_MESSAGE_FORMAT;
2098 break;
2099 }
2100 plci->ptyState = (byte)SSreq;
2101 plci->command = 0;
2102 cai[0] = 2;
2103 switch(SSreq)
2104 {
2105 case S_CONF_BEGIN:
2106 cai[1] = CONF_BEGIN;
2107 plci->internal_command = CONF_BEGIN_REQ_PEND;
2108 break;
2109 case S_CONF_DROP:
2110 cai[1] = CONF_DROP;
2111 plci->internal_command = CONF_DROP_REQ_PEND;
2112 break;
2113 case S_CONF_ISOLATE:
2114 cai[1] = CONF_ISOLATE;
2115 plci->internal_command = CONF_ISOLATE_REQ_PEND;
2116 break;
2117 case S_CONF_REATTACH:
2118 cai[1] = CONF_REATTACH;
2119 plci->internal_command = CONF_REATTACH_REQ_PEND;
2120 break;
2121 }
2122 cai[2] = (byte)d; /* Conference Size resp. PartyId */
2123 add_p(plci,CAI,cai);
2124 sig_req(plci,S_SERVICE,0);
2125 send_req(plci);
2126 return FALSE;
2127 }
2128 else Info = 0x3010; /* wrong state */
2129 break;
2130
2131 case S_ECT:
2132 case S_3PTY_BEGIN:
2133 case S_3PTY_END:
2134 case S_CONF_ADD:
2135 if(parms->length==7)
2136 {
2137 if(api_parse(&parms->info[1],(word)parms->length,"wbd",ss_parms))
2138 {
2139 dbug(1,dprintf("format wrong"));
2140 Info = _WRONG_MESSAGE_FORMAT;
2141 break;
2142 }
2143 }
2144 else if(parms->length==8) /* workaround for the T-View-S */
2145 {
2146 if(api_parse(&parms->info[1],(word)parms->length,"wbdb",ss_parms))
2147 {
2148 dbug(1,dprintf("format wrong"));
2149 Info = _WRONG_MESSAGE_FORMAT;
2150 break;
2151 }
2152 }
2153 else
2154 {
2155 Info = _WRONG_MESSAGE_FORMAT;
2156 break;
2157 }
2158 if(!msg[1].length)
2159 {
2160 Info = _WRONG_MESSAGE_FORMAT;
2161 break;
2162 }
2163 if (!plci)
2164 {
2165 Info = _WRONG_IDENTIFIER;
2166 break;
2167 }
2168 relatedPLCIvalue = GET_DWORD(ss_parms[2].info);
2169 relatedPLCIvalue &= 0x0000FFFF;
2170 dbug(1,dprintf("PTY/ECT/addCONF,relPLCI=%lx",relatedPLCIvalue));
2171 /* controller starts with 0 up to (max_adapter - 1) */
2172 if (((relatedPLCIvalue & 0x7f) == 0)
2173 || (MapController ((byte)(relatedPLCIvalue & 0x7f)) == 0)
2174 || (MapController ((byte)(relatedPLCIvalue & 0x7f)) > max_adapter))
2175 {
2176 if(SSreq==S_3PTY_END)
2177 {
2178 dbug(1, dprintf("wrong Controller use 2nd PLCI=PLCI"));
2179 rplci = plci;
2180 }
2181 else
2182 {
2183 Info = 0x3010; /* wrong state */
2184 break;
2185 }
2186 }
2187 else
2188 {
2189 relatedadapter = &adapter[MapController ((byte)(relatedPLCIvalue & 0x7f))-1];
2190 relatedPLCIvalue >>=8;
2191 /* find PLCI PTR*/
2192 for(i=0,rplci=NULL;i<relatedadapter->max_plci;i++)
2193 {
2194 if(relatedadapter->plci[i].Id == (byte)relatedPLCIvalue)
2195 {
2196 rplci = &relatedadapter->plci[i];
2197 }
2198 }
2199 if(!rplci || !relatedPLCIvalue)
2200 {
2201 if(SSreq==S_3PTY_END)
2202 {
2203 dbug(1, dprintf("use 2nd PLCI=PLCI"));
2204 rplci = plci;
2205 }
2206 else
2207 {
2208 Info = 0x3010; /* wrong state */
2209 break;
2210 }
2211 }
2212 }
2213/*
2214 dbug(1,dprintf("rplci:%x",rplci));
2215 dbug(1,dprintf("plci:%x",plci));
2216 dbug(1,dprintf("rplci->ptyState:%x",rplci->ptyState));
2217 dbug(1,dprintf("plci->ptyState:%x",plci->ptyState));
2218 dbug(1,dprintf("SSreq:%x",SSreq));
2219 dbug(1,dprintf("rplci->internal_command:%x",rplci->internal_command));
2220 dbug(1,dprintf("rplci->appl:%x",rplci->appl));
2221 dbug(1,dprintf("rplci->Id:%x",rplci->Id));
2222*/
2223 /* send PTY/ECT req, cannot check all states because of US stuff */
2224 if( !rplci->internal_command && rplci->appl )
2225 {
2226 plci->command = 0;
2227 rplci->relatedPTYPLCI = plci;
2228 plci->relatedPTYPLCI = rplci;
2229 rplci->ptyState = (byte)SSreq;
2230 if(SSreq==S_ECT)
2231 {
2232 rplci->internal_command = ECT_REQ_PEND;
2233 cai[1] = ECT_EXECUTE;
2234
2235 rplci->vswitchstate=0;
2236 rplci->vsprot=0;
2237 rplci->vsprotdialect=0;
2238 plci->vswitchstate=0;
2239 plci->vsprot=0;
2240 plci->vsprotdialect=0;
2241
2242 }
2243 else if(SSreq==S_CONF_ADD)
2244 {
2245 rplci->internal_command = CONF_ADD_REQ_PEND;
2246 cai[1] = CONF_ADD;
2247 }
2248 else
2249 {
2250 rplci->internal_command = PTY_REQ_PEND;
2251 cai[1] = (byte)(SSreq-3);
2252 }
2253 rplci->number = Number;
2254 if(plci!=rplci) /* explicit invocation */
2255 {
2256 cai[0] = 2;
2257 cai[2] = plci->Sig.Id;
2258 dbug(1,dprintf("explicit invocation"));
2259 }
2260 else
2261 {
2262 dbug(1,dprintf("implicit invocation"));
2263 cai[0] = 1;
2264 }
2265 add_p(rplci,CAI,cai);
2266 sig_req(rplci,S_SERVICE,0);
2267 send_req(rplci);
2268 return FALSE;
2269 }
2270 else
2271 {
2272 dbug(0,dprintf("Wrong line"));
2273 Info = 0x3010; /* wrong state */
2274 break;
2275 }
2276 break;
2277
2278 case S_CALL_DEFLECTION:
2279 if(api_parse(&parms->info[1],(word)parms->length,"wbwss",ss_parms))
2280 {
2281 dbug(1,dprintf("format wrong"));
2282 Info = _WRONG_MESSAGE_FORMAT;
2283 break;
2284 }
2285 if (!plci)
2286 {
2287 Info = _WRONG_IDENTIFIER;
2288 break;
2289 }
2290 /* reuse unused screening indicator */
2291 ss_parms[3].info[3] = (byte)GET_WORD(&(ss_parms[2].info[0]));
2292 plci->command = 0;
2293 plci->internal_command = CD_REQ_PEND;
2294 appl->CDEnable = TRUE;
2295 cai[0] = 1;
2296 cai[1] = CALL_DEFLECTION;
2297 add_p(plci,CAI,cai);
2298 add_p(plci,CPN,ss_parms[3].info);
2299 sig_req(plci,S_SERVICE,0);
2300 send_req(plci);
2301 return FALSE;
2302 break;
2303
2304 case S_CALL_FORWARDING_START:
2305 if(api_parse(&parms->info[1],(word)parms->length,"wbdwwsss",ss_parms))
2306 {
2307 dbug(1,dprintf("format wrong"));
2308 Info = _WRONG_MESSAGE_FORMAT;
2309 break;
2310 }
2311
2312 if((i=get_plci(a)))
2313 {
2314 rplci = &a->plci[i-1];
2315 rplci->appl = appl;
2316 add_p(rplci,CAI,"\x01\x80");
2317 add_p(rplci,UID,"\x06\x43\x61\x70\x69\x32\x30");
2318 sig_req(rplci,ASSIGN,DSIG_ID);
2319 send_req(rplci);
2320 }
2321 else
2322 {
2323 Info = _OUT_OF_PLCI;
2324 break;
2325 }
2326
2327 /* reuse unused screening indicator */
2328 rplci->internal_command = CF_START_PEND;
2329 rplci->appl = appl;
2330 rplci->number = Number;
2331 appl->S_Handle = GET_DWORD(&(ss_parms[2].info[0]));
2332 cai[0] = 2;
2333 cai[1] = 0x70|(byte)GET_WORD(&(ss_parms[3].info[0])); /* Function */
2334 cai[2] = (byte)GET_WORD(&(ss_parms[4].info[0])); /* Basic Service */
2335 add_p(rplci,CAI,cai);
2336 add_p(rplci,OAD,ss_parms[5].info);
2337 add_p(rplci,CPN,ss_parms[6].info);
2338 sig_req(rplci,S_SERVICE,0);
2339 send_req(rplci);
2340 return FALSE;
2341 break;
2342
2343 case S_INTERROGATE_DIVERSION:
2344 case S_INTERROGATE_NUMBERS:
2345 case S_CALL_FORWARDING_STOP:
2346 case S_CCBS_REQUEST:
2347 case S_CCBS_DEACTIVATE:
2348 case S_CCBS_INTERROGATE:
2349 switch(SSreq)
2350 {
2351 case S_INTERROGATE_NUMBERS:
2352 if(api_parse(&parms->info[1],(word)parms->length,"wbd",ss_parms))
2353 {
2354 dbug(0,dprintf("format wrong"));
2355 Info = _WRONG_MESSAGE_FORMAT;
2356 }
2357 break;
2358 case S_CCBS_REQUEST:
2359 case S_CCBS_DEACTIVATE:
2360 if(api_parse(&parms->info[1],(word)parms->length,"wbdw",ss_parms))
2361 {
2362 dbug(0,dprintf("format wrong"));
2363 Info = _WRONG_MESSAGE_FORMAT;
2364 }
2365 break;
2366 case S_CCBS_INTERROGATE:
2367 if(api_parse(&parms->info[1],(word)parms->length,"wbdws",ss_parms))
2368 {
2369 dbug(0,dprintf("format wrong"));
2370 Info = _WRONG_MESSAGE_FORMAT;
2371 }
2372 break;
2373 default:
2374 if(api_parse(&parms->info[1],(word)parms->length,"wbdwws",ss_parms))
2375 {
2376 dbug(0,dprintf("format wrong"));
2377 Info = _WRONG_MESSAGE_FORMAT;
2378 break;
2379 }
2380 break;
2381 }
2382
2383 if(Info) break;
2384 if((i=get_plci(a)))
2385 {
2386 rplci = &a->plci[i-1];
2387 switch(SSreq)
2388 {
2389 case S_INTERROGATE_DIVERSION: /* use cai with S_SERVICE below */
2390 cai[1] = 0x60|(byte)GET_WORD(&(ss_parms[3].info[0])); /* Function */
2391 rplci->internal_command = INTERR_DIVERSION_REQ_PEND; /* move to rplci if assigned */
2392 break;
2393 case S_INTERROGATE_NUMBERS: /* use cai with S_SERVICE below */
2394 cai[1] = DIVERSION_INTERROGATE_NUM; /* Function */
2395 rplci->internal_command = INTERR_NUMBERS_REQ_PEND; /* move to rplci if assigned */
2396 break;
2397 case S_CALL_FORWARDING_STOP:
2398 rplci->internal_command = CF_STOP_PEND;
2399 cai[1] = 0x80|(byte)GET_WORD(&(ss_parms[3].info[0])); /* Function */
2400 break;
2401 case S_CCBS_REQUEST:
2402 cai[1] = CCBS_REQUEST;
2403 rplci->internal_command = CCBS_REQUEST_REQ_PEND;
2404 break;
2405 case S_CCBS_DEACTIVATE:
2406 cai[1] = CCBS_DEACTIVATE;
2407 rplci->internal_command = CCBS_DEACTIVATE_REQ_PEND;
2408 break;
2409 case S_CCBS_INTERROGATE:
2410 cai[1] = CCBS_INTERROGATE;
2411 rplci->internal_command = CCBS_INTERROGATE_REQ_PEND;
2412 break;
2413 default:
2414 cai[1] = 0;
2415 break;
2416 }
2417 rplci->appl = appl;
2418 rplci->number = Number;
2419 add_p(rplci,CAI,"\x01\x80");
2420 add_p(rplci,UID,"\x06\x43\x61\x70\x69\x32\x30");
2421 sig_req(rplci,ASSIGN,DSIG_ID);
2422 send_req(rplci);
2423 }
2424 else
2425 {
2426 Info = _OUT_OF_PLCI;
2427 break;
2428 }
2429
2430 appl->S_Handle = GET_DWORD(&(ss_parms[2].info[0]));
2431 switch(SSreq)
2432 {
2433 case S_INTERROGATE_NUMBERS:
2434 cai[0] = 1;
2435 add_p(rplci,CAI,cai);
2436 break;
2437 case S_CCBS_REQUEST:
2438 case S_CCBS_DEACTIVATE:
2439 cai[0] = 3;
2440 PUT_WORD(&cai[2],GET_WORD(&(ss_parms[3].info[0])));
2441 add_p(rplci,CAI,cai);
2442 break;
2443 case S_CCBS_INTERROGATE:
2444 cai[0] = 3;
2445 PUT_WORD(&cai[2],GET_WORD(&(ss_parms[3].info[0])));
2446 add_p(rplci,CAI,cai);
2447 add_p(rplci,OAD,ss_parms[4].info);
2448 break;
2449 default:
2450 cai[0] = 2;
2451 cai[2] = (byte)GET_WORD(&(ss_parms[4].info[0])); /* Basic Service */
2452 add_p(rplci,CAI,cai);
2453 add_p(rplci,OAD,ss_parms[5].info);
2454 break;
2455 }
2456
2457 sig_req(rplci,S_SERVICE,0);
2458 send_req(rplci);
2459 return FALSE;
2460 break;
2461
2462 case S_MWI_ACTIVATE:
2463 if(api_parse(&parms->info[1],(word)parms->length,"wbwdwwwssss",ss_parms))
2464 {
2465 dbug(1,dprintf("format wrong"));
2466 Info = _WRONG_MESSAGE_FORMAT;
2467 break;
2468 }
2469 if(!plci)
2470 {
2471 if((i=get_plci(a)))
2472 {
2473 rplci = &a->plci[i-1];
2474 rplci->appl = appl;
2475 rplci->cr_enquiry=TRUE;
2476 add_p(rplci,CAI,"\x01\x80");
2477 add_p(rplci,UID,"\x06\x43\x61\x70\x69\x32\x30");
2478 sig_req(rplci,ASSIGN,DSIG_ID);
2479 send_req(rplci);
2480 }
2481 else
2482 {
2483 Info = _OUT_OF_PLCI;
2484 break;
2485 }
2486 }
2487 else
2488 {
2489 rplci = plci;
2490 rplci->cr_enquiry=FALSE;
2491 }
2492
2493 rplci->command = 0;
2494 rplci->internal_command = MWI_ACTIVATE_REQ_PEND;
2495 rplci->appl = appl;
2496 rplci->number = Number;
2497
2498 cai[0] = 13;
2499 cai[1] = ACTIVATION_MWI; /* Function */
2500 PUT_WORD(&cai[2],GET_WORD(&(ss_parms[2].info[0]))); /* Basic Service */
2501 PUT_DWORD(&cai[4],GET_DWORD(&(ss_parms[3].info[0]))); /* Number of Messages */
2502 PUT_WORD(&cai[8],GET_WORD(&(ss_parms[4].info[0]))); /* Message Status */
2503 PUT_WORD(&cai[10],GET_WORD(&(ss_parms[5].info[0]))); /* Message Reference */
2504 PUT_WORD(&cai[12],GET_WORD(&(ss_parms[6].info[0]))); /* Invocation Mode */
2505 add_p(rplci,CAI,cai);
2506 add_p(rplci,CPN,ss_parms[7].info); /* Receiving User Number */
2507 add_p(rplci,OAD,ss_parms[8].info); /* Controlling User Number */
2508 add_p(rplci,OSA,ss_parms[9].info); /* Controlling User Provided Number */
2509 add_p(rplci,UID,ss_parms[10].info); /* Time */
2510 sig_req(rplci,S_SERVICE,0);
2511 send_req(rplci);
2512 return FALSE;
2513
2514 case S_MWI_DEACTIVATE:
2515 if(api_parse(&parms->info[1],(word)parms->length,"wbwwss",ss_parms))
2516 {
2517 dbug(1,dprintf("format wrong"));
2518 Info = _WRONG_MESSAGE_FORMAT;
2519 break;
2520 }
2521 if(!plci)
2522 {
2523 if((i=get_plci(a)))
2524 {
2525 rplci = &a->plci[i-1];
2526 rplci->appl = appl;
2527 rplci->cr_enquiry=TRUE;
2528 add_p(rplci,CAI,"\x01\x80");
2529 add_p(rplci,UID,"\x06\x43\x61\x70\x69\x32\x30");
2530 sig_req(rplci,ASSIGN,DSIG_ID);
2531 send_req(rplci);
2532 }
2533 else
2534 {
2535 Info = _OUT_OF_PLCI;
2536 break;
2537 }
2538 }
2539 else
2540 {
2541 rplci = plci;
2542 rplci->cr_enquiry=FALSE;
2543 }
2544
2545 rplci->command = 0;
2546 rplci->internal_command = MWI_DEACTIVATE_REQ_PEND;
2547 rplci->appl = appl;
2548 rplci->number = Number;
2549
2550 cai[0] = 5;
2551 cai[1] = DEACTIVATION_MWI; /* Function */
2552 PUT_WORD(&cai[2],GET_WORD(&(ss_parms[2].info[0]))); /* Basic Service */
2553 PUT_WORD(&cai[4],GET_WORD(&(ss_parms[3].info[0]))); /* Invocation Mode */
2554 add_p(rplci,CAI,cai);
2555 add_p(rplci,CPN,ss_parms[4].info); /* Receiving User Number */
2556 add_p(rplci,OAD,ss_parms[5].info); /* Controlling User Number */
2557 sig_req(rplci,S_SERVICE,0);
2558 send_req(rplci);
2559 return FALSE;
2560
2561 default:
2562 Info = 0x300E; /* not supported */
2563 break;
2564 }
2565 break; /* case SELECTOR_SU_SERV: end */
2566
2567
2568 case SELECTOR_DTMF:
2569 return (dtmf_request (Id, Number, a, plci, appl, msg));
2570
2571
2572
2573 case SELECTOR_LINE_INTERCONNECT:
2574 return (mixer_request (Id, Number, a, plci, appl, msg));
2575
2576
2577
2578 case PRIV_SELECTOR_ECHO_CANCELLER:
2579 appl->appl_flags |= APPL_FLAG_PRIV_EC_SPEC;
2580 return (ec_request (Id, Number, a, plci, appl, msg));
2581
2582 case SELECTOR_ECHO_CANCELLER:
2583 appl->appl_flags &= ~APPL_FLAG_PRIV_EC_SPEC;
2584 return (ec_request (Id, Number, a, plci, appl, msg));
2585
2586
2587 case SELECTOR_V42BIS:
2588 default:
2589 Info = _FACILITY_NOT_SUPPORTED;
2590 break;
2591 } /* end of switch(selector) */
2592 }
2593
2594 dbug(1,dprintf("SendFacRc"));
2595 sendf(appl,
2596 _FACILITY_R|CONFIRM,
2597 Id,
2598 Number,
2599 "wws",Info,selector,SSparms);
2600 return FALSE;
2601}
2602
2603byte facility_res(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * msg)
2604{
2605 dbug(1,dprintf("facility_res"));
2606 return FALSE;
2607}
2608
2609byte connect_b3_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * parms)
2610{
2611 word Info = 0;
2612 byte req;
2613 byte len;
2614 word w;
2615 word fax_control_bits, fax_feature_bits, fax_info_change;
2616 API_PARSE * ncpi;
2617 byte pvc[2];
2618
2619 API_PARSE fax_parms[9];
2620 word i;
2621
2622
2623 dbug(1,dprintf("connect_b3_req"));
2624 if(plci)
2625 {
2626 if ((plci->State == IDLE) || (plci->State == OUTG_DIS_PENDING)
2627 || (plci->State == INC_DIS_PENDING) || (plci->SuppState != IDLE))
2628 {
2629 Info = _WRONG_STATE;
2630 }
2631 else
2632 {
2633 /* local reply if assign unsuccessfull
2634 or B3 protocol allows only one layer 3 connection
2635 and already connected
2636 or B2 protocol not any LAPD
2637 and connect_b3_req contradicts originate/answer direction */
2638 if (!plci->NL.Id
2639 || (((plci->B3_prot != B3_T90NL) && (plci->B3_prot != B3_ISO8208) && (plci->B3_prot != B3_X25_DCE))
2640 && ((plci->channels != 0)
2641 || (((plci->B2_prot != B2_SDLC) && (plci->B2_prot != B2_LAPD) && (plci->B2_prot != B2_LAPD_FREE_SAPI_SEL))
2642 && ((plci->call_dir & CALL_DIR_ANSWER) && !(plci->call_dir & CALL_DIR_FORCE_OUTG_NL))))))
2643 {
2644 dbug(1,dprintf("B3 already connected=%d or no NL.Id=0x%x, dir=%d sstate=0x%x",
2645 plci->channels,plci->NL.Id,plci->call_dir,plci->SuppState));
2646 Info = _WRONG_STATE;
2647 sendf(appl,
2648 _CONNECT_B3_R|CONFIRM,
2649 Id,
2650 Number,
2651 "w",Info);
2652 return FALSE;
2653 }
2654 plci->requested_options_conn = 0;
2655
2656 req = N_CONNECT;
2657 ncpi = &parms[0];
2658 if(plci->B3_prot==2 || plci->B3_prot==3)
2659 {
2660 if(ncpi->length>2)
2661 {
2662 /* check for PVC */
2663 if(ncpi->info[2] || ncpi->info[3])
2664 {
2665 pvc[0] = ncpi->info[3];
2666 pvc[1] = ncpi->info[2];
2667 add_d(plci,2,pvc);
2668 req = N_RESET;
2669 }
2670 else
2671 {
2672 if(ncpi->info[1] &1) req = N_CONNECT | N_D_BIT;
2673 add_d(plci,(word)(ncpi->length-3),&ncpi->info[4]);
2674 }
2675 }
2676 }
2677 else if(plci->B3_prot==5)
2678 {
2679 if (plci->NL.Id && !plci->nl_remove_id)
2680 {
2681 fax_control_bits = GET_WORD(&((T30_INFO *)plci->fax_connect_info_buffer)->control_bits_low);
2682 fax_feature_bits = GET_WORD(&((T30_INFO *)plci->fax_connect_info_buffer)->feature_bits_low);
2683 if (!(fax_control_bits & T30_CONTROL_BIT_MORE_DOCUMENTS)
2684 || (fax_feature_bits & T30_FEATURE_BIT_MORE_DOCUMENTS))
2685 {
2686 len = (byte)(&(((T30_INFO *) 0)->universal_6));
2687 fax_info_change = FALSE;
2688 if (ncpi->length >= 4)
2689 {
2690 w = GET_WORD(&ncpi->info[3]);
2691 if ((w & 0x0001) != ((word)(((T30_INFO *)(plci->fax_connect_info_buffer))->resolution & 0x0001)))
2692 {
2693 ((T30_INFO *)(plci->fax_connect_info_buffer))->resolution =
2694 (byte)((((T30_INFO *)(plci->fax_connect_info_buffer))->resolution & ~T30_RESOLUTION_R8_0770_OR_200) |
2695 ((w & 0x0001) ? T30_RESOLUTION_R8_0770_OR_200 : 0));
2696 fax_info_change = TRUE;
2697 }
2698 fax_control_bits &= ~(T30_CONTROL_BIT_REQUEST_POLLING | T30_CONTROL_BIT_MORE_DOCUMENTS);
2699 if (w & 0x0002) /* Fax-polling request */
2700 fax_control_bits |= T30_CONTROL_BIT_REQUEST_POLLING;
2701 if ((w & 0x0004) /* Request to send / poll another document */
2702 && (a->manufacturer_features & MANUFACTURER_FEATURE_FAX_MORE_DOCUMENTS))
2703 {
2704 fax_control_bits |= T30_CONTROL_BIT_MORE_DOCUMENTS;
2705 }
2706 if (ncpi->length >= 6)
2707 {
2708 w = GET_WORD(&ncpi->info[5]);
2709 if (((byte) w) != ((T30_INFO *)(plci->fax_connect_info_buffer))->data_format)
2710 {
2711 ((T30_INFO *)(plci->fax_connect_info_buffer))->data_format = (byte) w;
2712 fax_info_change = TRUE;
2713 }
2714
2715 if ((a->man_profile.private_options & (1L << PRIVATE_FAX_SUB_SEP_PWD))
2716 && (GET_WORD(&ncpi->info[5]) & 0x8000)) /* Private SEP/SUB/PWD enable */
2717 {
2718 plci->requested_options_conn |= (1L << PRIVATE_FAX_SUB_SEP_PWD);
2719 }
2720 if ((a->man_profile.private_options & (1L << PRIVATE_FAX_NONSTANDARD))
2721 && (GET_WORD(&ncpi->info[5]) & 0x4000)) /* Private non-standard facilities enable */
2722 {
2723 plci->requested_options_conn |= (1L << PRIVATE_FAX_NONSTANDARD);
2724 }
2725 fax_control_bits &= ~(T30_CONTROL_BIT_ACCEPT_SUBADDRESS | T30_CONTROL_BIT_ACCEPT_SEL_POLLING |
2726 T30_CONTROL_BIT_ACCEPT_PASSWORD);
2727 if ((plci->requested_options_conn | plci->requested_options | a->requested_options_table[appl->Id-1])
2728 & ((1L << PRIVATE_FAX_SUB_SEP_PWD) | (1L << PRIVATE_FAX_NONSTANDARD)))
2729 {
2730 if (api_parse (&ncpi->info[1], ncpi->length, "wwwwsss", fax_parms))
2731 Info = _WRONG_MESSAGE_FORMAT;
2732 else
2733 {
2734 if ((plci->requested_options_conn | plci->requested_options | a->requested_options_table[appl->Id-1])
2735 & (1L << PRIVATE_FAX_SUB_SEP_PWD))
2736 {
2737 fax_control_bits |= T30_CONTROL_BIT_ACCEPT_SUBADDRESS | T30_CONTROL_BIT_ACCEPT_PASSWORD;
2738 if (fax_control_bits & T30_CONTROL_BIT_ACCEPT_POLLING)
2739 fax_control_bits |= T30_CONTROL_BIT_ACCEPT_SEL_POLLING;
2740 }
2741 w = fax_parms[4].length;
2742 if (w > 20)
2743 w = 20;
2744 ((T30_INFO *)(plci->fax_connect_info_buffer))->station_id_len = (byte) w;
2745 for (i = 0; i < w; i++)
2746 ((T30_INFO *)(plci->fax_connect_info_buffer))->station_id[i] = fax_parms[4].info[1+i];
2747 ((T30_INFO *)(plci->fax_connect_info_buffer))->head_line_len = 0;
2748 len = (byte)(((T30_INFO *) 0)->station_id + 20);
2749 w = fax_parms[5].length;
2750 if (w > 20)
2751 w = 20;
2752 plci->fax_connect_info_buffer[len++] = (byte) w;
2753 for (i = 0; i < w; i++)
2754 plci->fax_connect_info_buffer[len++] = fax_parms[5].info[1+i];
2755 w = fax_parms[6].length;
2756 if (w > 20)
2757 w = 20;
2758 plci->fax_connect_info_buffer[len++] = (byte) w;
2759 for (i = 0; i < w; i++)
2760 plci->fax_connect_info_buffer[len++] = fax_parms[6].info[1+i];
2761 if ((plci->requested_options_conn | plci->requested_options | a->requested_options_table[appl->Id-1])
2762 & (1L << PRIVATE_FAX_NONSTANDARD))
2763 {
2764 if (api_parse (&ncpi->info[1], ncpi->length, "wwwwssss", fax_parms))
2765 {
2766 dbug(1,dprintf("non-standard facilities info missing or wrong format"));
2767 plci->fax_connect_info_buffer[len++] = 0;
2768 }
2769 else
2770 {
2771 if ((fax_parms[7].length >= 3) && (fax_parms[7].info[1] >= 2))
2772 plci->nsf_control_bits = GET_WORD(&fax_parms[7].info[2]);
2773 plci->fax_connect_info_buffer[len++] = (byte)(fax_parms[7].length);
2774 for (i = 0; i < fax_parms[7].length; i++)
2775 plci->fax_connect_info_buffer[len++] = fax_parms[7].info[1+i];
2776 }
2777 }
2778 }
2779 }
2780 else
2781 {
2782 len = (byte)(&(((T30_INFO *) 0)->universal_6));
2783 }
2784 fax_info_change = TRUE;
2785
2786 }
2787 if (fax_control_bits != GET_WORD(&((T30_INFO *)plci->fax_connect_info_buffer)->control_bits_low))
2788 {
2789 PUT_WORD (&((T30_INFO *)plci->fax_connect_info_buffer)->control_bits_low, fax_control_bits);
2790 fax_info_change = TRUE;
2791 }
2792 }
2793 if (Info == GOOD)
2794 {
2795 plci->fax_connect_info_length = len;
2796 if (fax_info_change)
2797 {
2798 if (fax_feature_bits & T30_FEATURE_BIT_MORE_DOCUMENTS)
2799 {
2800 start_internal_command (Id, plci, fax_connect_info_command);
2801 return FALSE;
2802 }
2803 else
2804 {
2805 start_internal_command (Id, plci, fax_adjust_b23_command);
2806 return FALSE;
2807 }
2808 }
2809 }
2810 }
2811 else Info = _WRONG_STATE;
2812 }
2813 else Info = _WRONG_STATE;
2814 }
2815
2816 else if (plci->B3_prot == B3_RTP)
2817 {
2818 plci->internal_req_buffer[0] = ncpi->length + 1;
2819 plci->internal_req_buffer[1] = UDATA_REQUEST_RTP_RECONFIGURE;
2820 for (w = 0; w < ncpi->length; w++)
2821 plci->internal_req_buffer[2+w] = ncpi->info[1+w];
2822 start_internal_command (Id, plci, rtp_connect_b3_req_command);
2823 return FALSE;
2824 }
2825
2826 if(!Info)
2827 {
2828 nl_req_ncci(plci,req,0);
2829 return 1;
2830 }
2831 }
2832 }
2833 else Info = _WRONG_IDENTIFIER;
2834
2835 sendf(appl,
2836 _CONNECT_B3_R|CONFIRM,
2837 Id,
2838 Number,
2839 "w",Info);
2840 return FALSE;
2841}
2842
2843byte connect_b3_res(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * parms)
2844{
2845 word ncci;
2846 API_PARSE * ncpi;
2847 byte req;
2848
2849 word w;
2850
2851
2852 API_PARSE fax_parms[9];
2853 word i;
2854 byte len;
2855
2856
2857 dbug(1,dprintf("connect_b3_res"));
2858
2859 ncci = (word)(Id>>16);
2860 if(plci && ncci) {
2861 if(a->ncci_state[ncci]==INC_CON_PENDING) {
2862 if (GET_WORD (&parms[0].info[0]) != 0)
2863 {
2864 a->ncci_state[ncci] = OUTG_REJ_PENDING;
2865 channel_request_xon (plci, a->ncci_ch[ncci]);
2866 channel_xmit_xon (plci);
2867 cleanup_ncci_data (plci, ncci);
2868 nl_req_ncci(plci,N_DISC,(byte)ncci);
2869 return 1;
2870 }
2871 a->ncci_state[ncci] = INC_ACT_PENDING;
2872
2873 req = N_CONNECT_ACK;
2874 ncpi = &parms[1];
2875 if ((plci->B3_prot == 4) || (plci->B3_prot == 5) || (plci->B3_prot == 7))
2876 {
2877
2878 if ((plci->requested_options_conn | plci->requested_options | a->requested_options_table[plci->appl->Id-1])
2879 & (1L << PRIVATE_FAX_NONSTANDARD))
2880 {
2881 if (((plci->B3_prot == 4) || (plci->B3_prot == 5))
2882 && (plci->nsf_control_bits & T30_NSF_CONTROL_BIT_ENABLE_NSF)
2883 && (plci->nsf_control_bits & T30_NSF_CONTROL_BIT_NEGOTIATE_RESP))
2884 {
2885 len = ((byte)(((T30_INFO *) 0)->station_id + 20));
2886 if (plci->fax_connect_info_length < len)
2887 {
2888 ((T30_INFO *)(plci->fax_connect_info_buffer))->station_id_len = 0;
2889 ((T30_INFO *)(plci->fax_connect_info_buffer))->head_line_len = 0;
2890 }
2891 if (api_parse (&ncpi->info[1], ncpi->length, "wwwwssss", fax_parms))
2892 {
2893 dbug(1,dprintf("non-standard facilities info missing or wrong format"));
2894 }
2895 else
2896 {
2897 if (plci->fax_connect_info_length <= len)
2898 plci->fax_connect_info_buffer[len] = 0;
2899 len += 1 + plci->fax_connect_info_buffer[len];
2900 if (plci->fax_connect_info_length <= len)
2901 plci->fax_connect_info_buffer[len] = 0;
2902 len += 1 + plci->fax_connect_info_buffer[len];
2903 if ((fax_parms[7].length >= 3) && (fax_parms[7].info[1] >= 2))
2904 plci->nsf_control_bits = GET_WORD(&fax_parms[7].info[2]);
2905 plci->fax_connect_info_buffer[len++] = (byte)(fax_parms[7].length);
2906 for (i = 0; i < fax_parms[7].length; i++)
2907 plci->fax_connect_info_buffer[len++] = fax_parms[7].info[1+i];
2908 }
2909 plci->fax_connect_info_length = len;
2910 ((T30_INFO *)(plci->fax_connect_info_buffer))->code = 0;
2911 start_internal_command (Id, plci, fax_connect_ack_command);
2912 return FALSE;
2913 }
2914 }
2915
2916 nl_req_ncci(plci,req,(byte)ncci);
2917 if ((plci->ncpi_state & NCPI_VALID_CONNECT_B3_ACT)
2918 && !(plci->ncpi_state & NCPI_CONNECT_B3_ACT_SENT))
2919 {
2920 if (plci->B3_prot == 4)
2921 sendf(appl,_CONNECT_B3_ACTIVE_I,Id,0,"s","");
2922 else
2923 sendf(appl,_CONNECT_B3_ACTIVE_I,Id,0,"S",plci->ncpi_buffer);
2924 plci->ncpi_state |= NCPI_CONNECT_B3_ACT_SENT;
2925 }
2926 }
2927
2928 else if (plci->B3_prot == B3_RTP)
2929 {
2930 plci->internal_req_buffer[0] = ncpi->length + 1;
2931 plci->internal_req_buffer[1] = UDATA_REQUEST_RTP_RECONFIGURE;
2932 for (w = 0; w < ncpi->length; w++)
2933 plci->internal_req_buffer[2+w] = ncpi->info[1+w];
2934 start_internal_command (Id, plci, rtp_connect_b3_res_command);
2935 return FALSE;
2936 }
2937
2938 else
2939 {
2940 if(ncpi->length>2) {
2941 if(ncpi->info[1] &1) req = N_CONNECT_ACK | N_D_BIT;
2942 add_d(plci,(word)(ncpi->length-3),&ncpi->info[4]);
2943 }
2944 nl_req_ncci(plci,req,(byte)ncci);
2945 sendf(appl,_CONNECT_B3_ACTIVE_I,Id,0,"s","");
2946 if (plci->adjust_b_restore)
2947 {
2948 plci->adjust_b_restore = FALSE;
2949 start_internal_command (Id, plci, adjust_b_restore);
2950 }
2951 }
2952 return 1;
2953 }
2954 }
2955 return FALSE;
2956}
2957
2958byte connect_b3_a_res(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * parms)
2959{
2960 word ncci;
2961
2962 ncci = (word)(Id>>16);
2963 dbug(1,dprintf("connect_b3_a_res(ncci=0x%x)",ncci));
2964
2965 if (plci && ncci && (plci->State != IDLE) && (plci->State != INC_DIS_PENDING)
2966 && (plci->State != OUTG_DIS_PENDING))
2967 {
2968 if(a->ncci_state[ncci]==INC_ACT_PENDING) {
2969 a->ncci_state[ncci] = CONNECTED;
2970 if(plci->State!=INC_CON_CONNECTED_ALERT) plci->State = CONNECTED;
2971 channel_request_xon (plci, a->ncci_ch[ncci]);
2972 channel_xmit_xon (plci);
2973 }
2974 }
2975 return FALSE;
2976}
2977
2978byte disconnect_b3_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * parms)
2979{
2980 word Info;
2981 word ncci;
2982 API_PARSE * ncpi;
2983
2984 dbug(1,dprintf("disconnect_b3_req"));
2985
2986 Info = _WRONG_IDENTIFIER;
2987 ncci = (word)(Id>>16);
2988 if (plci && ncci)
2989 {
2990 Info = _WRONG_STATE;
2991 if ((a->ncci_state[ncci] == CONNECTED)
2992 || (a->ncci_state[ncci] == OUTG_CON_PENDING)
2993 || (a->ncci_state[ncci] == INC_CON_PENDING)
2994 || (a->ncci_state[ncci] == INC_ACT_PENDING))
2995 {
2996 a->ncci_state[ncci] = OUTG_DIS_PENDING;
2997 channel_request_xon (plci, a->ncci_ch[ncci]);
2998 channel_xmit_xon (plci);
2999
3000 if (a->ncci[ncci].data_pending
3001 && ((plci->B3_prot == B3_TRANSPARENT)
3002 || (plci->B3_prot == B3_T30)
3003 || (plci->B3_prot == B3_T30_WITH_EXTENSIONS)))
3004 {
3005 plci->send_disc = (byte)ncci;
3006 plci->command = 0;
3007 return FALSE;
3008 }
3009 else
3010 {
3011 cleanup_ncci_data (plci, ncci);
3012
3013 if(plci->B3_prot==2 || plci->B3_prot==3)
3014 {
3015 ncpi = &parms[0];
3016 if(ncpi->length>3)
3017 {
3018 add_d(plci, (word)(ncpi->length - 3) ,(byte *)&(ncpi->info[4]));
3019 }
3020 }
3021 nl_req_ncci(plci,N_DISC,(byte)ncci);
3022 }
3023 return 1;
3024 }
3025 }
3026 sendf(appl,
3027 _DISCONNECT_B3_R|CONFIRM,
3028 Id,
3029 Number,
3030 "w",Info);
3031 return FALSE;
3032}
3033
3034byte disconnect_b3_res(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * parms)
3035{
3036 word ncci;
3037 word i;
3038
3039 ncci = (word)(Id>>16);
3040 dbug(1,dprintf("disconnect_b3_res(ncci=0x%x",ncci));
3041 if(plci && ncci) {
3042 plci->requested_options_conn = 0;
3043 plci->fax_connect_info_length = 0;
3044 plci->ncpi_state = 0x00;
3045 if (((plci->B3_prot != B3_T90NL) && (plci->B3_prot != B3_ISO8208) && (plci->B3_prot != B3_X25_DCE))
3046 && ((plci->B2_prot != B2_LAPD) && (plci->B2_prot != B2_LAPD_FREE_SAPI_SEL)))
3047 {
3048 plci->call_dir |= CALL_DIR_FORCE_OUTG_NL;
3049 }
3050 for(i=0; i<MAX_CHANNELS_PER_PLCI && plci->inc_dis_ncci_table[i]!=(byte)ncci; i++);
3051 if(i<MAX_CHANNELS_PER_PLCI) {
3052 if(plci->channels)plci->channels--;
3053 for(; i<MAX_CHANNELS_PER_PLCI-1; i++) plci->inc_dis_ncci_table[i] = plci->inc_dis_ncci_table[i+1];
3054 plci->inc_dis_ncci_table[MAX_CHANNELS_PER_PLCI-1] = 0;
3055
3056 ncci_free_receive_buffers (plci, ncci);
3057
3058 if((plci->State==IDLE || plci->State==SUSPENDING) && !plci->channels){
3059 if(plci->State == SUSPENDING){
3060 sendf(plci->appl,
3061 _FACILITY_I,
3062 Id & 0xffffL,
3063 0,
3064 "ws", (word)3, "\x03\x04\x00\x00");
3065 sendf(plci->appl, _DISCONNECT_I, Id & 0xffffL, 0, "w", 0);
3066 }
3067 plci_remove(plci);
3068 plci->State=IDLE;
3069 }
3070 }
3071 else
3072 {
3073 if ((a->manufacturer_features & MANUFACTURER_FEATURE_FAX_PAPER_FORMATS)
3074 && ((plci->B3_prot == 4) || (plci->B3_prot == 5))
3075 && (a->ncci_state[ncci] == INC_DIS_PENDING))
3076 {
3077 ncci_free_receive_buffers (plci, ncci);
3078
3079 nl_req_ncci(plci,N_EDATA,(byte)ncci);
3080
3081 plci->adapter->ncci_state[ncci] = IDLE;
3082 start_internal_command (Id, plci, fax_disconnect_command);
3083 return 1;
3084 }
3085 }
3086 }
3087 return FALSE;
3088}
3089
3090byte data_b3_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * parms)
3091{
3092 NCCI *ncci_ptr;
3093 DATA_B3_DESC *data;
3094 word Info;
3095 word ncci;
3096 word i;
3097
3098 dbug(1,dprintf("data_b3_req"));
3099
3100 Info = _WRONG_IDENTIFIER;
3101 ncci = (word)(Id>>16);
3102 dbug(1,dprintf("ncci=0x%x, plci=0x%x",ncci,plci));
3103
3104 if (plci && ncci)
3105 {
3106 Info = _WRONG_STATE;
3107 if ((a->ncci_state[ncci] == CONNECTED)
3108 || (a->ncci_state[ncci] == INC_ACT_PENDING))
3109 {
3110 /* queue data */
3111 ncci_ptr = &(a->ncci[ncci]);
3112 i = ncci_ptr->data_out + ncci_ptr->data_pending;
3113 if (i >= MAX_DATA_B3)
3114 i -= MAX_DATA_B3;
3115 data = &(ncci_ptr->DBuffer[i]);
3116 data->Number = Number;
3117 if ((((byte *)(parms[0].info)) >= ((byte *)(plci->msg_in_queue)))
3118 && (((byte *)(parms[0].info)) < ((byte *)(plci->msg_in_queue)) + sizeof(plci->msg_in_queue)))
3119 {
3120
3121 data->P = (byte *)(*((dword *)(parms[0].info)));
3122
3123 }
3124 else
3125 data->P = TransmitBufferSet(appl,*(dword *)parms[0].info);
3126 data->Length = GET_WORD(parms[1].info);
3127 data->Handle = GET_WORD(parms[2].info);
3128 data->Flags = GET_WORD(parms[3].info);
3129 (ncci_ptr->data_pending)++;
3130
3131 /* check for delivery confirmation */
3132 if (data->Flags & 0x0004)
3133 {
3134 i = ncci_ptr->data_ack_out + ncci_ptr->data_ack_pending;
3135 if (i >= MAX_DATA_ACK)
3136 i -= MAX_DATA_ACK;
3137 ncci_ptr->DataAck[i].Number = data->Number;
3138 ncci_ptr->DataAck[i].Handle = data->Handle;
3139 (ncci_ptr->data_ack_pending)++;
3140 }
3141
3142 send_data(plci);
3143 return FALSE;
3144 }
3145 }
3146 if (appl)
3147 {
3148 if (plci)
3149 {
3150 if ((((byte *)(parms[0].info)) >= ((byte *)(plci->msg_in_queue)))
3151 && (((byte *)(parms[0].info)) < ((byte *)(plci->msg_in_queue)) + sizeof(plci->msg_in_queue)))
3152 {
3153
3154 TransmitBufferFree (appl, (byte *)(*((dword *)(parms[0].info))));
3155
3156 }
3157 }
3158 sendf(appl,
3159 _DATA_B3_R|CONFIRM,
3160 Id,
3161 Number,
3162 "ww",GET_WORD(parms[2].info),Info);
3163 }
3164 return FALSE;
3165}
3166
3167byte data_b3_res(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * parms)
3168{
3169 word n;
3170 word ncci;
3171 word NCCIcode;
3172
3173 dbug(1,dprintf("data_b3_res"));
3174
3175 ncci = (word)(Id>>16);
3176 if(plci && ncci) {
3177 n = GET_WORD(parms[0].info);
3178 dbug(1,dprintf("free(%d)",n));
3179 NCCIcode = ncci | (((word) a->Id) << 8);
3180 if(n<appl->MaxBuffer &&
3181 appl->DataNCCI[n]==NCCIcode &&
3182 (byte)(appl->DataFlags[n]>>8)==plci->Id) {
3183 dbug(1,dprintf("found"));
3184 appl->DataNCCI[n] = 0;
3185
3186 if (channel_can_xon (plci, a->ncci_ch[ncci])) {
3187 channel_request_xon (plci, a->ncci_ch[ncci]);
3188 }
3189 channel_xmit_xon (plci);
3190
3191 if(appl->DataFlags[n] &4) {
3192 nl_req_ncci(plci,N_DATA_ACK,(byte)ncci);
3193 return 1;
3194 }
3195 }
3196 }
3197 return FALSE;
3198}
3199
3200byte reset_b3_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * parms)
3201{
3202 word Info;
3203 word ncci;
3204
3205 dbug(1,dprintf("reset_b3_req"));
3206
3207 Info = _WRONG_IDENTIFIER;
3208 ncci = (word)(Id>>16);
3209 if(plci && ncci)
3210 {
3211 Info = _WRONG_STATE;
3212 switch (plci->B3_prot)
3213 {
3214 case B3_ISO8208:
3215 case B3_X25_DCE:
3216 if(a->ncci_state[ncci]==CONNECTED)
3217 {
3218 nl_req_ncci(plci,N_RESET,(byte)ncci);
3219 send_req(plci);
3220 Info = GOOD;
3221 }
3222 break;
3223 case B3_TRANSPARENT:
3224 if(a->ncci_state[ncci]==CONNECTED)
3225 {
3226 start_internal_command (Id, plci, reset_b3_command);
3227 Info = GOOD;
3228 }
3229 break;
3230 }
3231 }
3232 /* reset_b3 must result in a reset_b3_con & reset_b3_Ind */
3233 sendf(appl,
3234 _RESET_B3_R|CONFIRM,
3235 Id,
3236 Number,
3237 "w",Info);
3238 return FALSE;
3239}
3240
3241byte reset_b3_res(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * parms)
3242{
3243 word ncci;
3244
3245 dbug(1,dprintf("reset_b3_res"));
3246
3247 ncci = (word)(Id>>16);
3248 if(plci && ncci) {
3249 switch (plci->B3_prot)
3250 {
3251 case B3_ISO8208:
3252 case B3_X25_DCE:
3253 if(a->ncci_state[ncci]==INC_RES_PENDING)
3254 {
3255 a->ncci_state[ncci] = CONNECTED;
3256 nl_req_ncci(plci,N_RESET_ACK,(byte)ncci);
3257 return TRUE;
3258 }
3259 break;
3260 }
3261 }
3262 return FALSE;
3263}
3264
3265byte connect_b3_t90_a_res(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * parms)
3266{
3267 word ncci;
3268 API_PARSE * ncpi;
3269 byte req;
3270
3271 dbug(1,dprintf("connect_b3_t90_a_res"));
3272
3273 ncci = (word)(Id>>16);
3274 if(plci && ncci) {
3275 if(a->ncci_state[ncci]==INC_ACT_PENDING) {
3276 a->ncci_state[ncci] = CONNECTED;
3277 }
3278 else if(a->ncci_state[ncci]==INC_CON_PENDING) {
3279 a->ncci_state[ncci] = CONNECTED;
3280
3281 req = N_CONNECT_ACK;
3282
3283 /* parms[0]==0 for CAPI original message definition! */
3284 if(parms[0].info) {
3285 ncpi = &parms[1];
3286 if(ncpi->length>2) {
3287 if(ncpi->info[1] &1) req = N_CONNECT_ACK | N_D_BIT;
3288 add_d(plci,(word)(ncpi->length-3),&ncpi->info[4]);
3289 }
3290 }
3291 nl_req_ncci(plci,req,(byte)ncci);
3292 return 1;
3293 }
3294 }
3295 return FALSE;
3296}
3297
3298
3299byte select_b_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * msg)
3300{
3301 word Info=0;
3302 word i;
3303 byte tel;
3304 API_PARSE bp_parms[7];
3305
3306 if(!plci || !msg)
3307 {
3308 Info = _WRONG_IDENTIFIER;
3309 }
3310 else
3311 {
3312 dbug(1,dprintf("select_b_req[%d],PLCI=0x%x,Tel=0x%x,NL=0x%x,appl=0x%x,sstate=0x%x",
3313 msg->length,plci->Id,plci->tel,plci->NL.Id,plci->appl,plci->SuppState));
3314 dbug(1,dprintf("PlciState=0x%x",plci->State));
3315 for(i=0;i<7;i++) bp_parms[i].length = 0;
3316
3317 /* check if no channel is open, no B3 connected only */
3318 if((plci->State == IDLE) || (plci->State == OUTG_DIS_PENDING) || (plci->State == INC_DIS_PENDING)
3319 || (plci->SuppState != IDLE) || plci->channels || plci->nl_remove_id)
3320 {
3321 Info = _WRONG_STATE;
3322 }
3323 /* check message format and fill bp_parms pointer */
3324 else if(msg->length && api_parse(&msg->info[1], (word)msg->length, "wwwsss", bp_parms))
3325 {
3326 Info = _WRONG_MESSAGE_FORMAT;
3327 }
3328 else
3329 {
3330 if((plci->State==INC_CON_PENDING) || (plci->State==INC_CON_ALERT)) /* send alert tone inband to the network, */
3331 { /* e.g. Qsig or RBS or Cornet-N or xess PRI */
3332 if(Id & EXT_CONTROLLER)
3333 {
3334 sendf(appl, _SELECT_B_REQ|CONFIRM, Id, Number, "w", 0x2002); /* wrong controller */
3335 return 0;
3336 }
3337 plci->State=INC_CON_CONNECTED_ALERT;
3338 plci->appl = appl;
3339 clear_c_ind_mask_bit (plci, (word)(appl->Id-1));
3340 dump_c_ind_mask (plci);
3341 for(i=0; i<max_appl; i++) /* disconnect the other appls */
3342 { /* its quasi a connect */
3343 if(test_c_ind_mask_bit (plci, i))
3344 sendf(&application[i], _DISCONNECT_I, Id, 0, "w", _OTHER_APPL_CONNECTED);
3345 }
3346 }
3347
3348 api_save_msg(msg, "s", &plci->saved_msg);
3349 tel = plci->tel;
3350 if(Id & EXT_CONTROLLER)
3351 {
3352 if(tel) /* external controller in use by this PLCI */
3353 {
3354 if(a->AdvSignalAppl && a->AdvSignalAppl!=appl)
3355 {
3356 dbug(1,dprintf("Ext_Ctrl in use 1"));
3357 Info = _WRONG_STATE;
3358 }
3359 }
3360 else /* external controller NOT in use by this PLCI ? */
3361 {
3362 if(a->AdvSignalPLCI)
3363 {
3364 dbug(1,dprintf("Ext_Ctrl in use 2"));
3365 Info = _WRONG_STATE;
3366 }
3367 else /* activate the codec */
3368 {
3369 dbug(1,dprintf("Ext_Ctrl start"));
3370 if(AdvCodecSupport(a, plci, appl, 0) )
3371 {
3372 dbug(1,dprintf("Error in codec procedures"));
3373 Info = _WRONG_STATE;
3374 }
3375 else if(plci->spoofed_msg==SPOOFING_REQUIRED) /* wait until codec is active */
3376 {
3377 plci->spoofed_msg = AWAITING_SELECT_B;
3378 plci->internal_command = BLOCK_PLCI; /* lock other commands */
3379 plci->command = 0;
3380 dbug(1,dprintf("continue if codec loaded"));
3381 return FALSE;
3382 }
3383 }
3384 }
3385 }
3386 else /* external controller bit is OFF */
3387 {
3388 if(tel) /* external controller in use, need to switch off */
3389 {
3390 if(a->AdvSignalAppl==appl)
3391 {
3392 CodecIdCheck(a, plci);
3393 plci->tel = 0;
3394 plci->adv_nl = 0;
3395 dbug(1,dprintf("Ext_Ctrl disable"));
3396 }
3397 else
3398 {
3399 dbug(1,dprintf("Ext_Ctrl not requested"));
3400 }
3401 }
3402 }
3403 if (!Info)
3404 {
3405 if (plci->call_dir & CALL_DIR_OUT)
3406 plci->call_dir = CALL_DIR_OUT | CALL_DIR_ORIGINATE;
3407 else if (plci->call_dir & CALL_DIR_IN)
3408 plci->call_dir = CALL_DIR_IN | CALL_DIR_ANSWER;
3409 start_internal_command (Id, plci, select_b_command);
3410 return FALSE;
3411 }
3412 }
3413 }
3414 sendf(appl, _SELECT_B_REQ|CONFIRM, Id, Number, "w", Info);
3415 return FALSE;
3416}
3417
3418byte manufacturer_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * parms)
3419{
3420 word command;
3421 word i;
3422 word ncci;
3423 API_PARSE * m;
3424 API_PARSE m_parms[5];
3425 word codec;
3426 byte req;
3427 byte ch;
3428 byte dir;
3429 static byte chi[2] = {0x01,0x00};
3430 static byte lli[2] = {0x01,0x00};
3431 static byte codec_cai[2] = {0x01,0x01};
3432 static byte null_msg = {0};
3433 static API_PARSE null_parms = { 0, &null_msg };
3434 PLCI * v_plci;
3435 word Info=0;
3436
3437 dbug(1,dprintf("manufacturer_req"));
3438 for(i=0;i<5;i++) m_parms[i].length = 0;
3439
3440 if(GET_DWORD(parms[0].info)!=_DI_MANU_ID) {
3441 Info = _WRONG_MESSAGE_FORMAT;
3442 }
3443 command = GET_WORD(parms[1].info);
3444 m = &parms[2];
3445 if (!Info)
3446 {
3447 switch(command) {
3448 case _DI_ASSIGN_PLCI:
3449 if(api_parse(&m->info[1],(word)m->length,"wbbs",m_parms)) {
3450 Info = _WRONG_MESSAGE_FORMAT;
3451 break;
3452 }
3453 codec = GET_WORD(m_parms[0].info);
3454 ch = m_parms[1].info[0];
3455 dir = m_parms[2].info[0];
3456 if((i=get_plci(a))) {
3457 plci = &a->plci[i-1];
3458 plci->appl = appl;
3459 plci->command = _MANUFACTURER_R;
3460 plci->m_command = command;
3461 plci->number = Number;
3462 plci->State = LOCAL_CONNECT;
3463 Id = ( ((word)plci->Id<<8)|plci->adapter->Id|0x80);
3464 dbug(1,dprintf("ManCMD,plci=0x%x",Id));
3465
3466 if((ch==1 || ch==2) && (dir<=2)) {
3467 chi[1] = (byte)(0x80|ch);
3468 lli[1] = 0;
3469 plci->call_dir = CALL_DIR_OUT | CALL_DIR_ORIGINATE;
3470 switch(codec)
3471 {
3472 case 0:
3473 Info = add_b1(plci,&m_parms[3],0,0);
3474 break;
3475 case 1:
3476 add_p(plci,CAI,codec_cai);
3477 break;
3478 /* manual 'swich on' to the codec support without signalling */
3479 /* first 'assign plci' with this function, then use */
3480 case 2:
3481 if(AdvCodecSupport(a, plci, appl, 0) ) {
3482 Info = _RESOURCE_ERROR;
3483 }
3484 else {
3485 Info = add_b1(plci,&null_parms,0,B1_FACILITY_LOCAL);
3486 lli[1] = 0x10; /* local call codec stream */
3487 }
3488 break;
3489 }
3490
3491 plci->State = LOCAL_CONNECT;
3492 plci->manufacturer = TRUE;
3493 plci->command = _MANUFACTURER_R;
3494 plci->m_command = command;
3495 plci->number = Number;
3496
3497 if(!Info)
3498 {
3499 add_p(plci,LLI,lli);
3500 add_p(plci,CHI,chi);
3501 add_p(plci,UID,"\x06\x43\x61\x70\x69\x32\x30");
3502 sig_req(plci,ASSIGN,DSIG_ID);
3503
3504 if(!codec)
3505 {
3506 Info = add_b23(plci,&m_parms[3]);
3507 if(!Info)
3508 {
3509 nl_req_ncci(plci,ASSIGN,0);
3510 send_req(plci);
3511 }
3512 }
3513 if(!Info)
3514 {
3515 dbug(1,dprintf("dir=0x%x,spoof=0x%x",dir,plci->spoofed_msg));
3516 if (plci->spoofed_msg==SPOOFING_REQUIRED)
3517 {
3518 api_save_msg (m_parms, "wbbs", &plci->saved_msg);
3519 plci->spoofed_msg = AWAITING_MANUF_CON;
3520 plci->internal_command = BLOCK_PLCI; /* reject other req meanwhile */
3521 plci->command = 0;
3522 send_req(plci);
3523 return FALSE;
3524 }
3525 if(dir==1) {
3526 sig_req(plci,CALL_REQ,0);
3527 }
3528 else if(!dir){
3529 sig_req(plci,LISTEN_REQ,0);
3530 }
3531 send_req(plci);
3532 }
3533 else
3534 {
3535 sendf(appl,
3536 _MANUFACTURER_R|CONFIRM,
3537 Id,
3538 Number,
3539 "dww",_DI_MANU_ID,command,Info);
3540 return 2;
3541 }
3542 }
3543 }
3544 }
3545 else Info = _OUT_OF_PLCI;
3546 break;
3547
3548 case _DI_IDI_CTRL:
3549 if(!plci)
3550 {
3551 Info = _WRONG_IDENTIFIER;
3552 break;
3553 }
3554 if(api_parse(&m->info[1],(word)m->length,"bs",m_parms)) {
3555 Info = _WRONG_MESSAGE_FORMAT;
3556 break;
3557 }
3558 req = m_parms[0].info[0];
3559 plci->command = _MANUFACTURER_R;
3560 plci->m_command = command;
3561 plci->number = Number;
3562 if(req==CALL_REQ)
3563 {
3564 plci->b_channel = getChannel(&m_parms[1]);
3565 mixer_set_bchannel_id_esc (plci, plci->b_channel);
3566 if(plci->spoofed_msg==SPOOFING_REQUIRED)
3567 {
3568 plci->spoofed_msg = CALL_REQ | AWAITING_MANUF_CON;
3569 plci->internal_command = BLOCK_PLCI; /* reject other req meanwhile */
3570 plci->command = 0;
3571 break;
3572 }
3573 }
3574 else if(req==LAW_REQ)
3575 {
3576 plci->cr_enquiry = TRUE;
3577 }
3578 add_ss(plci,FTY,&m_parms[1]);
3579 sig_req(plci,req,0);
3580 send_req(plci);
3581 if(req==HANGUP)
3582 {
3583 if (plci->NL.Id && !plci->nl_remove_id)
3584 {
3585 if (plci->channels)
3586 {
3587 for (ncci = 1; ncci < MAX_NCCI+1; ncci++)
3588 {
3589 if ((a->ncci_plci[ncci] == plci->Id) && (a->ncci_state[ncci] == CONNECTED))
3590 {
3591 a->ncci_state[ncci] = OUTG_DIS_PENDING;
3592 cleanup_ncci_data (plci, ncci);
3593 nl_req_ncci(plci,N_DISC,(byte)ncci);
3594 }
3595 }
3596 }
3597 mixer_remove (plci);
3598 nl_req_ncci(plci,REMOVE,0);
3599 send_req(plci);
3600 }
3601 }
3602 break;
3603
3604 case _DI_SIG_CTRL:
3605 /* signalling control for loop activation B-channel */
3606 if(!plci)
3607 {
3608 Info = _WRONG_IDENTIFIER;
3609 break;
3610 }
3611 if(m->length){
3612 plci->command = _MANUFACTURER_R;
3613 plci->number = Number;
3614 add_ss(plci,FTY,m);
3615 sig_req(plci,SIG_CTRL,0);
3616 send_req(plci);
3617 }
3618 else Info = _WRONG_MESSAGE_FORMAT;
3619 break;
3620
3621 case _DI_RXT_CTRL:
3622 /* activation control for receiver/transmitter B-channel */
3623 if(!plci)
3624 {
3625 Info = _WRONG_IDENTIFIER;
3626 break;
3627 }
3628 if(m->length){
3629 plci->command = _MANUFACTURER_R;
3630 plci->number = Number;
3631 add_ss(plci,FTY,m);
3632 sig_req(plci,DSP_CTRL,0);
3633 send_req(plci);
3634 }
3635 else Info = _WRONG_MESSAGE_FORMAT;
3636 break;
3637
3638 case _DI_ADV_CODEC:
3639 case _DI_DSP_CTRL:
3640 /* TEL_CTRL commands to support non standard adjustments: */
3641 /* Ring on/off, Handset micro volume, external micro vol. */
3642 /* handset+external speaker volume, receiver+transm. gain,*/
3643 /* handsfree on (hookinfo off), set mixer command */
3644
3645 if(command == _DI_ADV_CODEC)
3646 {
3647 if(!a->AdvCodecPLCI) {
3648 Info = _WRONG_STATE;
3649 break;
3650 }
3651 v_plci = a->AdvCodecPLCI;
3652 }
3653 else
3654 {
3655 if (plci
3656 && (m->length >= 3)
3657 && (m->info[1] == 0x1c)
3658 && (m->info[2] >= 1))
3659 {
3660 if (m->info[3] == DSP_CTRL_OLD_SET_MIXER_COEFFICIENTS)
3661 {
3662 if ((plci->tel != ADV_VOICE) || (plci != a->AdvSignalPLCI))
3663 {
3664 Info = _WRONG_STATE;
3665 break;
3666 }
3667 a->adv_voice_coef_length = m->info[2] - 1;
3668 if (a->adv_voice_coef_length > m->length - 3)
3669 a->adv_voice_coef_length = (byte)(m->length - 3);
3670 if (a->adv_voice_coef_length > ADV_VOICE_COEF_BUFFER_SIZE)
3671 a->adv_voice_coef_length = ADV_VOICE_COEF_BUFFER_SIZE;
3672 for (i = 0; i < a->adv_voice_coef_length; i++)
3673 a->adv_voice_coef_buffer[i] = m->info[4 + i];
3674 if (plci->B1_facilities & B1_FACILITY_VOICE)
3675 adv_voice_write_coefs (plci, ADV_VOICE_WRITE_UPDATE);
3676 break;
3677 }
3678 else if (m->info[3] == DSP_CTRL_SET_DTMF_PARAMETERS)
3679 {
3680 if (!(a->manufacturer_features & MANUFACTURER_FEATURE_DTMF_PARAMETERS))
3681 {
3682 Info = _FACILITY_NOT_SUPPORTED;
3683 break;
3684 }
3685
3686 plci->dtmf_parameter_length = m->info[2] - 1;
3687 if (plci->dtmf_parameter_length > m->length - 3)
3688 plci->dtmf_parameter_length = (byte)(m->length - 3);
3689 if (plci->dtmf_parameter_length > DTMF_PARAMETER_BUFFER_SIZE)
3690 plci->dtmf_parameter_length = DTMF_PARAMETER_BUFFER_SIZE;
3691 for (i = 0; i < plci->dtmf_parameter_length; i++)
3692 plci->dtmf_parameter_buffer[i] = m->info[4+i];
3693 if (plci->B1_facilities & B1_FACILITY_DTMFR)
3694 dtmf_parameter_write (plci);
3695 break;
3696
3697 }
3698 }
3699 v_plci = plci;
3700 }
3701
3702 if(!v_plci)
3703 {
3704 Info = _WRONG_IDENTIFIER;
3705 break;
3706 }
3707 if(m->length){
3708 add_ss(v_plci,FTY,m);
3709 sig_req(v_plci,TEL_CTRL,0);
3710 send_req(v_plci);
3711 }
3712 else Info = _WRONG_MESSAGE_FORMAT;
3713
3714 break;
3715
3716 case _DI_OPTIONS_REQUEST:
3717 if(api_parse(&m->info[1],(word)m->length,"d",m_parms)) {
3718 Info = _WRONG_MESSAGE_FORMAT;
3719 break;
3720 }
3721 if (GET_DWORD (m_parms[0].info) & ~a->man_profile.private_options)
3722 {
3723 Info = _FACILITY_NOT_SUPPORTED;
3724 break;
3725 }
3726 a->requested_options_table[appl->Id-1] = GET_DWORD (m_parms[0].info);
3727 break;
3728
3729
3730
3731 default:
3732 Info = _WRONG_MESSAGE_FORMAT;
3733 break;
3734 }
3735 }
3736
3737 sendf(appl,
3738 _MANUFACTURER_R|CONFIRM,
3739 Id,
3740 Number,
3741 "dww",_DI_MANU_ID,command,Info);
3742 return FALSE;
3743}
3744
3745
3746byte manufacturer_res(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * msg)
3747{
3748 word indication;
3749
3750 API_PARSE m_parms[3];
3751 API_PARSE *ncpi;
3752 API_PARSE fax_parms[9];
3753 word i;
3754 byte len;
3755
3756
3757 dbug(1,dprintf("manufacturer_res"));
3758
3759 if ((msg[0].length == 0)
3760 || (msg[1].length == 0)
3761 || (GET_DWORD(msg[0].info)!=_DI_MANU_ID))
3762 {
3763 return FALSE;
3764 }
3765 indication = GET_WORD(msg[1].info);
3766 switch (indication)
3767 {
3768
3769 case _DI_NEGOTIATE_B3:
3770 if(!plci)
3771 break;
3772 if (((plci->B3_prot != 4) && (plci->B3_prot != 5))
3773 || !(plci->ncpi_state & NCPI_NEGOTIATE_B3_SENT))
3774 {
3775 dbug(1,dprintf("wrong state for NEGOTIATE_B3 parameters"));
3776 break;
3777 }
3778 if (api_parse (&msg[2].info[1], msg[2].length, "ws", m_parms))
3779 {
3780 dbug(1,dprintf("wrong format in NEGOTIATE_B3 parameters"));
3781 break;
3782 }
3783 ncpi = &m_parms[1];
3784 len = ((byte)(((T30_INFO *) 0)->station_id + 20));
3785 if (plci->fax_connect_info_length < len)
3786 {
3787 ((T30_INFO *)(plci->fax_connect_info_buffer))->station_id_len = 0;
3788 ((T30_INFO *)(plci->fax_connect_info_buffer))->head_line_len = 0;
3789 }
3790 if (api_parse (&ncpi->info[1], ncpi->length, "wwwwssss", fax_parms))
3791 {
3792 dbug(1,dprintf("non-standard facilities info missing or wrong format"));
3793 }
3794 else
3795 {
3796 if (plci->fax_connect_info_length <= len)
3797 plci->fax_connect_info_buffer[len] = 0;
3798 len += 1 + plci->fax_connect_info_buffer[len];
3799 if (plci->fax_connect_info_length <= len)
3800 plci->fax_connect_info_buffer[len] = 0;
3801 len += 1 + plci->fax_connect_info_buffer[len];
3802 if ((fax_parms[7].length >= 3) && (fax_parms[7].info[1] >= 2))
3803 plci->nsf_control_bits = GET_WORD(&fax_parms[7].info[2]);
3804 plci->fax_connect_info_buffer[len++] = (byte)(fax_parms[7].length);
3805 for (i = 0; i < fax_parms[7].length; i++)
3806 plci->fax_connect_info_buffer[len++] = fax_parms[7].info[1+i];
3807 }
3808 plci->fax_connect_info_length = len;
3809 plci->fax_edata_ack_length = plci->fax_connect_info_length;
3810 start_internal_command (Id, plci, fax_edata_ack_command);
3811 break;
3812
3813 }
3814 return FALSE;
3815}
3816
3817/*------------------------------------------------------------------*/
3818/* IDI callback function */
3819/*------------------------------------------------------------------*/
3820
3821void callback(ENTITY * e)
3822{
3823 DIVA_CAPI_ADAPTER * a;
3824 APPL * appl;
3825 PLCI * plci;
3826 CAPI_MSG *m;
3827 word i, j;
3828 byte rc;
3829 byte ch;
3830 byte req;
3831 byte global_req;
3832 int no_cancel_rc;
3833
3834 dbug(1,dprintf("%x:CB(%x:Req=%x,Rc=%x,Ind=%x)",
3835 (e->user[0]+1)&0x7fff,e->Id,e->Req,e->Rc,e->Ind));
3836
3837 a = &(adapter[(byte)e->user[0]]);
3838 plci = &(a->plci[e->user[1]]);
3839 no_cancel_rc = DIVA_CAPI_SUPPORTS_NO_CANCEL(a);
3840
3841 /*
3842 If new protocol code and new XDI is used then CAPI should work
3843 fully in accordance with IDI cpec an look on callback field instead
3844 of Rc field for return codes.
3845 */
3846 if (((e->complete == 0xff) && no_cancel_rc) ||
3847 (e->Rc && !no_cancel_rc)) {
3848 rc = e->Rc;
3849 ch = e->RcCh;
3850 req = e->Req;
3851 e->Rc = 0;
3852
3853 if (e->user[0] & 0x8000)
3854 {
3855 /*
3856 If REMOVE request was sent then we have to wait until
3857 return code with Id set to zero arrives.
3858 All other return codes should be ignored.
3859 */
3860 if (req == REMOVE)
3861 {
3862 if (e->Id)
3863 {
3864 dbug(1,dprintf("cancel RC in REMOVE state"));
3865 return;
3866 }
3867 channel_flow_control_remove (plci);
3868 for (i = 0; i < 256; i++)
3869 {
3870 if (a->FlowControlIdTable[i] == plci->nl_remove_id)
3871 a->FlowControlIdTable[i] = 0;
3872 }
3873 plci->nl_remove_id = 0;
3874 if (plci->rx_dma_descriptor > 0) {
3875 diva_free_dma_descriptor (plci, plci->rx_dma_descriptor - 1);
3876 plci->rx_dma_descriptor = 0;
3877 }
3878 }
3879 if (rc == OK_FC)
3880 {
3881 a->FlowControlIdTable[ch] = e->Id;
3882 a->FlowControlSkipTable[ch] = 0;
3883
3884 a->ch_flow_control[ch] |= N_OK_FC_PENDING;
3885 a->ch_flow_plci[ch] = plci->Id;
3886 plci->nl_req = 0;
3887 }
3888 else
3889 {
3890 /*
3891 Cancel return codes self, if feature was requested
3892 */
3893 if (no_cancel_rc && (a->FlowControlIdTable[ch] == e->Id) && e->Id) {
3894 a->FlowControlIdTable[ch] = 0;
3895 if ((rc == OK) && a->FlowControlSkipTable[ch]) {
3896 dbug(3,dprintf ("XDI CAPI: RC cancelled Id:0x02, Ch:%02x", e->Id, ch));
3897 return;
3898 }
3899 }
3900
3901 if (a->ch_flow_control[ch] & N_OK_FC_PENDING)
3902 {
3903 a->ch_flow_control[ch] &= ~N_OK_FC_PENDING;
3904 if (ch == e->ReqCh)
3905 plci->nl_req = 0;
3906 }
3907 else
3908 plci->nl_req = 0;
3909 }
3910 if (plci->nl_req)
3911 control_rc (plci, 0, rc, ch, 0, TRUE);
3912 else
3913 {
3914 if (req == N_XON)
3915 {
3916 channel_x_on (plci, ch);
3917 if (plci->internal_command)
3918 control_rc (plci, req, rc, ch, 0, TRUE);
3919 }
3920 else
3921 {
3922 if (plci->nl_global_req)
3923 {
3924 global_req = plci->nl_global_req;
3925 plci->nl_global_req = 0;
3926 if (rc != ASSIGN_OK) {
3927 e->Id = 0;
3928 if (plci->rx_dma_descriptor > 0) {
3929 diva_free_dma_descriptor (plci, plci->rx_dma_descriptor - 1);
3930 plci->rx_dma_descriptor = 0;
3931 }
3932 }
3933 channel_xmit_xon (plci);
3934 control_rc (plci, 0, rc, ch, global_req, TRUE);
3935 }
3936 else if (plci->data_sent)
3937 {
3938 channel_xmit_xon (plci);
3939 plci->data_sent = FALSE;
3940 plci->NL.XNum = 1;
3941 data_rc (plci, ch);
3942 if (plci->internal_command)
3943 control_rc (plci, req, rc, ch, 0, TRUE);
3944 }
3945 else
3946 {
3947 channel_xmit_xon (plci);
3948 control_rc (plci, req, rc, ch, 0, TRUE);
3949 }
3950 }
3951 }
3952 }
3953 else
3954 {
3955 /*
3956 If REMOVE request was sent then we have to wait until
3957 return code with Id set to zero arrives.
3958 All other return codes should be ignored.
3959 */
3960 if (req == REMOVE)
3961 {
3962 if (e->Id)
3963 {
3964 dbug(1,dprintf("cancel RC in REMOVE state"));
3965 return;
3966 }
3967 plci->sig_remove_id = 0;
3968 }
3969 plci->sig_req = 0;
3970 if (plci->sig_global_req)
3971 {
3972 global_req = plci->sig_global_req;
3973 plci->sig_global_req = 0;
3974 if (rc != ASSIGN_OK)
3975 e->Id = 0;
3976 channel_xmit_xon (plci);
3977 control_rc (plci, 0, rc, ch, global_req, FALSE);
3978 }
3979 else
3980 {
3981 channel_xmit_xon (plci);
3982 control_rc (plci, req, rc, ch, 0, FALSE);
3983 }
3984 }
3985 /*
3986 Again: in accordance with IDI spec Rc and Ind can't be delivered in the
3987 same callback. Also if new XDI and protocol code used then jump
3988 direct to finish.
3989 */
3990 if (no_cancel_rc) {
3991 channel_xmit_xon(plci);
3992 goto capi_callback_suffix;
3993 }
3994 }
3995
3996 channel_xmit_xon(plci);
3997
3998 if (e->Ind) {
3999 if (e->user[0] &0x8000) {
4000 byte Ind = e->Ind & 0x0f;
4001 byte Ch = e->IndCh;
4002 if (((Ind==N_DISC) || (Ind==N_DISC_ACK)) &&
4003 (a->ch_flow_plci[Ch] == plci->Id)) {
4004 if (a->ch_flow_control[Ch] & N_RX_FLOW_CONTROL_MASK) {
4005 dbug(3,dprintf ("XDI CAPI: I: pending N-XON Ch:%02x", Ch));
4006 }
4007 a->ch_flow_control[Ch] &= ~N_RX_FLOW_CONTROL_MASK;
4008 }
4009 nl_ind(plci);
4010 if ((e->RNR != 1) &&
4011 (a->ch_flow_plci[Ch] == plci->Id) &&
4012 (a->ch_flow_control[Ch] & N_RX_FLOW_CONTROL_MASK)) {
4013 a->ch_flow_control[Ch] &= ~N_RX_FLOW_CONTROL_MASK;
4014 dbug(3,dprintf ("XDI CAPI: I: remove faked N-XON Ch:%02x", Ch));
4015 }
4016 } else {
4017 sig_ind(plci);
4018 }
4019 e->Ind = 0;
4020 }
4021
4022capi_callback_suffix:
4023
4024 while (!plci->req_in
4025 && !plci->internal_command
4026 && (plci->msg_in_write_pos != plci->msg_in_read_pos))
4027 {
4028 j = (plci->msg_in_read_pos == plci->msg_in_wrap_pos) ? 0 : plci->msg_in_read_pos;
4029
4030 i = (((CAPI_MSG *)(&((byte *)(plci->msg_in_queue))[j]))->header.length + 3) & 0xfffc;
4031
4032 m = (CAPI_MSG *)(&((byte *)(plci->msg_in_queue))[j]);
4033 appl = *((APPL * *)(&((byte *)(plci->msg_in_queue))[j+i]));
4034 dbug(1,dprintf("dequeue msg(0x%04x) - write=%d read=%d wrap=%d",
4035 m->header.command, plci->msg_in_write_pos, plci->msg_in_read_pos, plci->msg_in_wrap_pos));
4036 if (plci->msg_in_read_pos == plci->msg_in_wrap_pos)
4037 {
4038 plci->msg_in_wrap_pos = MSG_IN_QUEUE_SIZE;
4039 plci->msg_in_read_pos = i + MSG_IN_OVERHEAD;
4040 }
4041 else
4042 {
4043 plci->msg_in_read_pos = j + i + MSG_IN_OVERHEAD;
4044 }
4045 if (plci->msg_in_read_pos == plci->msg_in_write_pos)
4046 {
4047 plci->msg_in_write_pos = MSG_IN_QUEUE_SIZE;
4048 plci->msg_in_read_pos = MSG_IN_QUEUE_SIZE;
4049 }
4050 else if (plci->msg_in_read_pos == plci->msg_in_wrap_pos)
4051 {
4052 plci->msg_in_read_pos = MSG_IN_QUEUE_SIZE;
4053 plci->msg_in_wrap_pos = MSG_IN_QUEUE_SIZE;
4054 }
4055 i = api_put (appl, m);
4056 if (i != 0)
4057 {
4058 if (m->header.command == _DATA_B3_R)
4059
4060 TransmitBufferFree (appl, (byte *)(m->info.data_b3_req.Data));
4061
4062 dbug(1,dprintf("Error 0x%04x from msg(0x%04x)", i, m->header.command));
4063 break;
4064 }
4065
4066 if (plci->li_notify_update)
4067 {
4068 plci->li_notify_update = FALSE;
4069 mixer_notify_update (plci, FALSE);
4070 }
4071
4072 }
4073 send_data(plci);
4074 send_req(plci);
4075}
4076
4077
4078void control_rc(PLCI * plci, byte req, byte rc, byte ch, byte global_req, byte nl_rc)
4079{
4080 dword Id;
4081 dword rId;
4082 word Number;
4083 word Info=0;
4084 word i;
4085 word ncci;
4086 DIVA_CAPI_ADAPTER * a;
4087 APPL * appl;
4088 PLCI * rplci;
4089 byte SSparms[] = "\x05\x00\x00\x02\x00\x00";
4090 byte SSstruct[] = "\x09\x00\x00\x06\x00\x00\x00\x00\x00\x00";
4091
4092 if (!plci) {
4093 dbug(0,dprintf("A: control_rc, no plci %02x:%02x:%02x:%02x:%02x", req, rc, ch, global_req, nl_rc));
4094 return;
4095 }
4096 dbug(1,dprintf("req0_in/out=%d/%d",plci->req_in,plci->req_out));
4097 if(plci->req_in!=plci->req_out)
4098 {
4099 if (nl_rc || (global_req != ASSIGN) || (rc == ASSIGN_OK))
4100 {
4101 dbug(1,dprintf("req_1return"));
4102 return;
4103 }
4104 /* cancel outstanding request on the PLCI after SIG ASSIGN failure */
4105 }
4106 plci->req_in = plci->req_in_start = plci->req_out = 0;
4107 dbug(1,dprintf("control_rc"));
4108
4109 appl = plci->appl;
4110 a = plci->adapter;
4111 ncci = a->ch_ncci[ch];
4112 if(appl)
4113 {
4114 Id = (((dword)(ncci ? ncci : ch)) << 16) | ((word)plci->Id << 8) | a->Id;
4115 if(plci->tel && plci->SuppState!=CALL_HELD) Id|=EXT_CONTROLLER;
4116 Number = plci->number;
4117 dbug(1,dprintf("Contr_RC-Id=%08lx,plci=%x,tel=%x, entity=0x%x, command=0x%x, int_command=0x%x",Id,plci->Id,plci->tel,plci->Sig.Id,plci->command,plci->internal_command));
4118 dbug(1,dprintf("channels=0x%x",plci->channels));
4119 if (plci_remove_check(plci))
4120 return;
4121 if(req==REMOVE && rc==ASSIGN_OK)
4122 {
4123 sig_req(plci,HANGUP,0);
4124 sig_req(plci,REMOVE,0);
4125 send_req(plci);
4126 }
4127 if(plci->command)
4128 {
4129 switch(plci->command)
4130 {
4131 case C_HOLD_REQ:
4132 dbug(1,dprintf("HoldRC=0x%x",rc));
4133 SSparms[1] = (byte)S_HOLD;
4134 if(rc!=OK)
4135 {
4136 plci->SuppState = IDLE;
4137 Info = 0x2001;
4138 }
4139 sendf(appl,_FACILITY_R|CONFIRM,Id,Number,"wws",Info,3,SSparms);
4140 break;
4141
4142 case C_RETRIEVE_REQ:
4143 dbug(1,dprintf("RetrieveRC=0x%x",rc));
4144 SSparms[1] = (byte)S_RETRIEVE;
4145 if(rc!=OK)
4146 {
4147 plci->SuppState = CALL_HELD;
4148 Info = 0x2001;
4149 }
4150 sendf(appl,_FACILITY_R|CONFIRM,Id,Number,"wws",Info,3,SSparms);
4151 break;
4152
4153 case _INFO_R:
4154 dbug(1,dprintf("InfoRC=0x%x",rc));
4155 if(rc!=OK) Info=_WRONG_STATE;
4156 sendf(appl,_INFO_R|CONFIRM,Id,Number,"w",Info);
4157 break;
4158
4159 case _CONNECT_R:
4160 dbug(1,dprintf("Connect_R=0x%x/0x%x/0x%x/0x%x",req,rc,global_req,nl_rc));
4161 if (plci->State == INC_DIS_PENDING)
4162 break;
4163 if(plci->Sig.Id!=0xff)
4164 {
4165 if (((global_req == ASSIGN) && (rc != ASSIGN_OK))
4166 || (!nl_rc && (req == CALL_REQ) && (rc != OK)))
4167 {
4168 dbug(1,dprintf("No more IDs/Call_Req failed"));
4169 sendf(appl,_CONNECT_R|CONFIRM,Id&0xffL,Number,"w",_OUT_OF_PLCI);
4170 plci_remove(plci);
4171 plci->State = IDLE;
4172 break;
4173 }
4174 if(plci->State!=LOCAL_CONNECT)plci->State = OUTG_CON_PENDING;
4175 sendf(appl,_CONNECT_R|CONFIRM,Id,Number,"w",0);
4176 }
4177 else /* D-ch activation */
4178 {
4179 if (rc != ASSIGN_OK)
4180 {
4181 dbug(1,dprintf("No more IDs/X.25 Call_Req failed"));
4182 sendf(appl,_CONNECT_R|CONFIRM,Id&0xffL,Number,"w",_OUT_OF_PLCI);
4183 plci_remove(plci);
4184 plci->State = IDLE;
4185 break;
4186 }
4187 sendf(appl,_CONNECT_R|CONFIRM,Id,Number,"w",0);
4188 sendf(plci->appl,_CONNECT_ACTIVE_I,Id,0,"sss","","","");
4189 plci->State = INC_ACT_PENDING;
4190 }
4191 break;
4192
4193 case _CONNECT_I|RESPONSE:
4194 if (plci->State != INC_DIS_PENDING)
4195 plci->State = INC_CON_ACCEPT;
4196 break;
4197
4198 case _DISCONNECT_R:
4199 if (plci->State == INC_DIS_PENDING)
4200 break;
4201 if(plci->Sig.Id!=0xff)
4202 {
4203 plci->State = OUTG_DIS_PENDING;
4204 sendf(appl,_DISCONNECT_R|CONFIRM,Id,Number,"w",0);
4205 }
4206 break;
4207
4208 case SUSPEND_REQ:
4209 break;
4210
4211 case RESUME_REQ:
4212 break;
4213
4214 case _CONNECT_B3_R:
4215 if(rc!=OK)
4216 {
4217 sendf(appl,_CONNECT_B3_R|CONFIRM,Id,Number,"w",_WRONG_IDENTIFIER);
4218 break;
4219 }
4220 ncci = get_ncci (plci, ch, 0);
4221 Id = (Id & 0xffff) | (((dword) ncci) << 16);
4222 plci->channels++;
4223 if(req==N_RESET)
4224 {
4225 a->ncci_state[ncci] = INC_ACT_PENDING;
4226 sendf(appl,_CONNECT_B3_R|CONFIRM,Id,Number,"w",0);
4227 sendf(appl,_CONNECT_B3_ACTIVE_I,Id,0,"s","");
4228 }
4229 else
4230 {
4231 a->ncci_state[ncci] = OUTG_CON_PENDING;
4232 sendf(appl,_CONNECT_B3_R|CONFIRM,Id,Number,"w",0);
4233 }
4234 break;
4235
4236 case _CONNECT_B3_I|RESPONSE:
4237 break;
4238
4239 case _RESET_B3_R:
4240/* sendf(appl,_RESET_B3_R|CONFIRM,Id,Number,"w",0);*/
4241 break;
4242
4243 case _DISCONNECT_B3_R:
4244 sendf(appl,_DISCONNECT_B3_R|CONFIRM,Id,Number,"w",0);
4245 break;
4246
4247 case _MANUFACTURER_R:
4248 break;
4249
4250 case PERM_LIST_REQ:
4251 if(rc!=OK)
4252 {
4253 Info = _WRONG_IDENTIFIER;
4254 sendf(plci->appl,_CONNECT_R|CONFIRM,Id,Number,"w",Info);
4255 plci_remove(plci);
4256 }
4257 else
4258 sendf(plci->appl,_CONNECT_R|CONFIRM,Id,Number,"w",Info);
4259 break;
4260
4261 default:
4262 break;
4263 }
4264 plci->command = 0;
4265 }
4266 else if (plci->internal_command)
4267 {
4268 switch(plci->internal_command)
4269 {
4270 case BLOCK_PLCI:
4271 return;
4272
4273 case GET_MWI_STATE:
4274 if(rc==OK) /* command supported, wait for indication */
4275 {
4276 return;
4277 }
4278 plci_remove(plci);
4279 break;
4280
4281 /* Get Supported Services */
4282 case GETSERV_REQ_PEND:
4283 if(rc==OK) /* command supported, wait for indication */
4284 {
4285 break;
4286 }
4287 PUT_DWORD(&SSstruct[6], MASK_TERMINAL_PORTABILITY);
4288 sendf(appl, _FACILITY_R|CONFIRM, Id, Number, "wws",0,3,SSstruct);
4289 plci_remove(plci);
4290 break;
4291
4292 case INTERR_DIVERSION_REQ_PEND: /* Interrogate Parameters */
4293 case INTERR_NUMBERS_REQ_PEND:
4294 case CF_START_PEND: /* Call Forwarding Start pending */
4295 case CF_STOP_PEND: /* Call Forwarding Stop pending */
4296 case CCBS_REQUEST_REQ_PEND:
4297 case CCBS_DEACTIVATE_REQ_PEND:
4298 case CCBS_INTERROGATE_REQ_PEND:
4299 switch(plci->internal_command)
4300 {
4301 case INTERR_DIVERSION_REQ_PEND:
4302 SSparms[1] = S_INTERROGATE_DIVERSION;
4303 break;
4304 case INTERR_NUMBERS_REQ_PEND:
4305 SSparms[1] = S_INTERROGATE_NUMBERS;
4306 break;
4307 case CF_START_PEND:
4308 SSparms[1] = S_CALL_FORWARDING_START;
4309 break;
4310 case CF_STOP_PEND:
4311 SSparms[1] = S_CALL_FORWARDING_STOP;
4312 break;
4313 case CCBS_REQUEST_REQ_PEND:
4314 SSparms[1] = S_CCBS_REQUEST;
4315 break;
4316 case CCBS_DEACTIVATE_REQ_PEND:
4317 SSparms[1] = S_CCBS_DEACTIVATE;
4318 break;
4319 case CCBS_INTERROGATE_REQ_PEND:
4320 SSparms[1] = S_CCBS_INTERROGATE;
4321 break;
4322 }
4323 if(global_req==ASSIGN)
4324 {
4325 dbug(1,dprintf("AssignDiversion_RC=0x%x/0x%x",req,rc));
4326 return;
4327 }
4328 if(!plci->appl) break;
4329 if(rc==ISDN_GUARD_REJ)
4330 {
4331 Info = _CAPI_GUARD_ERROR;
4332 }
4333 else if(rc!=OK)
4334 {
4335 Info = _SUPPLEMENTARY_SERVICE_NOT_SUPPORTED;
4336 }
4337 sendf(plci->appl,_FACILITY_R|CONFIRM,Id&0x7,
4338 plci->number,"wws",Info,(word)3,SSparms);
4339 if(Info) plci_remove(plci);
4340 break;
4341
4342 /* 3pty conference pending */
4343 case PTY_REQ_PEND:
4344 if(!plci->relatedPTYPLCI) break;
4345 rplci = plci->relatedPTYPLCI;
4346 SSparms[1] = plci->ptyState;
4347 rId = ((word)rplci->Id<<8)|rplci->adapter->Id;
4348 if(rplci->tel) rId|=EXT_CONTROLLER;
4349 if(rc!=OK)
4350 {
4351 Info = 0x300E; /* not supported */
4352 plci->relatedPTYPLCI = NULL;
4353 plci->ptyState = 0;
4354 }
4355 sendf(rplci->appl,
4356 _FACILITY_R|CONFIRM,
4357 rId,
4358 plci->number,
4359 "wws",Info,(word)3,SSparms);
4360 break;
4361
4362 /* Explicit Call Transfer pending */
4363 case ECT_REQ_PEND:
4364 dbug(1,dprintf("ECT_RC=0x%x/0x%x",req,rc));
4365 if(!plci->relatedPTYPLCI) break;
4366 rplci = plci->relatedPTYPLCI;
4367 SSparms[1] = S_ECT;
4368 rId = ((word)rplci->Id<<8)|rplci->adapter->Id;
4369 if(rplci->tel) rId|=EXT_CONTROLLER;
4370 if(rc!=OK)
4371 {
4372 Info = 0x300E; /* not supported */
4373 plci->relatedPTYPLCI = NULL;
4374 plci->ptyState = 0;
4375 }
4376 sendf(rplci->appl,
4377 _FACILITY_R|CONFIRM,
4378 rId,
4379 plci->number,
4380 "wws",Info,(word)3,SSparms);
4381 break;
4382
4383 case _MANUFACTURER_R:
4384 dbug(1,dprintf("_Manufacturer_R=0x%x/0x%x",req,rc));
4385 if ((global_req == ASSIGN) && (rc != ASSIGN_OK))
4386 {
4387 dbug(1,dprintf("No more IDs"));
4388 sendf(appl,_MANUFACTURER_R|CONFIRM,Id,Number,"dww",_DI_MANU_ID,_MANUFACTURER_R,_OUT_OF_PLCI);
4389 plci_remove(plci); /* after codec init, internal codec commands pending */
4390 }
4391 break;
4392
4393 case _CONNECT_R:
4394 dbug(1,dprintf("_Connect_R=0x%x/0x%x",req,rc));
4395 if ((global_req == ASSIGN) && (rc != ASSIGN_OK))
4396 {
4397 dbug(1,dprintf("No more IDs"));
4398 sendf(appl,_CONNECT_R|CONFIRM,Id&0xffL,Number,"w",_OUT_OF_PLCI);
4399 plci_remove(plci); /* after codec init, internal codec commands pending */
4400 }
4401 break;
4402
4403 case PERM_COD_HOOK: /* finished with Hook_Ind */
4404 return;
4405
4406 case PERM_COD_CALL:
4407 dbug(1,dprintf("***Codec Connect_Pending A, Rc = 0x%x",rc));
4408 plci->internal_command = PERM_COD_CONN_PEND;
4409 return;
4410
4411 case PERM_COD_ASSIGN:
4412 dbug(1,dprintf("***Codec Assign A, Rc = 0x%x",rc));
4413 if(rc!=ASSIGN_OK) break;
4414 sig_req(plci,CALL_REQ,0);
4415 send_req(plci);
4416 plci->internal_command = PERM_COD_CALL;
4417 return;
4418
4419 /* Null Call Reference Request pending */
4420 case C_NCR_FAC_REQ:
4421 dbug(1,dprintf("NCR_FAC=0x%x/0x%x",req,rc));
4422 if(global_req==ASSIGN)
4423 {
4424 if(rc==ASSIGN_OK)
4425 {
4426 return;
4427 }
4428 else
4429 {
4430 sendf(appl,_INFO_R|CONFIRM,Id&0xf,Number,"w",_WRONG_STATE);
4431 appl->NullCREnable = FALSE;
4432 plci_remove(plci);
4433 }
4434 }
4435 else if(req==NCR_FACILITY)
4436 {
4437 if(rc==OK)
4438 {
4439 sendf(appl,_INFO_R|CONFIRM,Id&0xf,Number,"w",0);
4440 }
4441 else
4442 {
4443 sendf(appl,_INFO_R|CONFIRM,Id&0xf,Number,"w",_WRONG_STATE);
4444 appl->NullCREnable = FALSE;
4445 }
4446 plci_remove(plci);
4447 }
4448 break;
4449
4450 case HOOK_ON_REQ:
4451 if(plci->channels)
4452 {
4453 if(a->ncci_state[ncci]==CONNECTED)
4454 {
4455 a->ncci_state[ncci] = OUTG_DIS_PENDING;
4456 cleanup_ncci_data (plci, ncci);
4457 nl_req_ncci(plci,N_DISC,(byte)ncci);
4458 }
4459 break;
4460 }
4461 break;
4462
4463 case HOOK_OFF_REQ:
4464 if (plci->State == INC_DIS_PENDING)
4465 break;
4466 sig_req(plci,CALL_REQ,0);
4467 send_req(plci);
4468 plci->State=OUTG_CON_PENDING;
4469 break;
4470
4471
4472 case MWI_ACTIVATE_REQ_PEND:
4473 case MWI_DEACTIVATE_REQ_PEND:
4474 if(global_req == ASSIGN && rc==ASSIGN_OK)
4475 {
4476 dbug(1,dprintf("MWI_REQ assigned"));
4477 return;
4478 }
4479 else if(rc!=OK)
4480 {
4481 if(rc==WRONG_IE)
4482 {
4483 Info = 0x2007; /* Illegal message parameter coding */
4484 dbug(1,dprintf("MWI_REQ invalid parameter"));
4485 }
4486 else
4487 {
4488 Info = 0x300B; /* not supported */
4489 dbug(1,dprintf("MWI_REQ not supported"));
4490 }
4491 /* 0x3010: Request not allowed in this state */
4492 PUT_WORD(&SSparms[4],0x300E); /* SS not supported */
4493
4494 }
4495 if(plci->internal_command==MWI_ACTIVATE_REQ_PEND)
4496 {
4497 PUT_WORD(&SSparms[1],S_MWI_ACTIVATE);
4498 }
4499 else PUT_WORD(&SSparms[1],S_MWI_DEACTIVATE);
4500
4501 if(plci->cr_enquiry)
4502 {
4503 sendf(plci->appl,
4504 _FACILITY_R|CONFIRM,
4505 Id&0xf,
4506 plci->number,
4507 "wws",Info,(word)3,SSparms);
4508 if(rc!=OK) plci_remove(plci);
4509 }
4510 else
4511 {
4512 sendf(plci->appl,
4513 _FACILITY_R|CONFIRM,
4514 Id,
4515 plci->number,
4516 "wws",Info,(word)3,SSparms);
4517 }
4518 break;
4519
4520 case CONF_BEGIN_REQ_PEND:
4521 case CONF_ADD_REQ_PEND:
4522 case CONF_SPLIT_REQ_PEND:
4523 case CONF_DROP_REQ_PEND:
4524 case CONF_ISOLATE_REQ_PEND:
4525 case CONF_REATTACH_REQ_PEND:
4526 dbug(1,dprintf("CONF_RC=0x%x/0x%x",req,rc));
4527 if((plci->internal_command==CONF_ADD_REQ_PEND)&&(!plci->relatedPTYPLCI)) break;
4528 rplci = plci;
4529 rId = Id;
4530 switch(plci->internal_command)
4531 {
4532 case CONF_BEGIN_REQ_PEND:
4533 SSparms[1] = S_CONF_BEGIN;
4534 break;
4535 case CONF_ADD_REQ_PEND:
4536 SSparms[1] = S_CONF_ADD;
4537 rplci = plci->relatedPTYPLCI;
4538 rId = ((word)rplci->Id<<8)|rplci->adapter->Id;
4539 break;
4540 case CONF_SPLIT_REQ_PEND:
4541 SSparms[1] = S_CONF_SPLIT;
4542 break;
4543 case CONF_DROP_REQ_PEND:
4544 SSparms[1] = S_CONF_DROP;
4545 break;
4546 case CONF_ISOLATE_REQ_PEND:
4547 SSparms[1] = S_CONF_ISOLATE;
4548 break;
4549 case CONF_REATTACH_REQ_PEND:
4550 SSparms[1] = S_CONF_REATTACH;
4551 break;
4552 }
4553
4554 if(rc!=OK)
4555 {
4556 Info = 0x300E; /* not supported */
4557 plci->relatedPTYPLCI = NULL;
4558 plci->ptyState = 0;
4559 }
4560 sendf(rplci->appl,
4561 _FACILITY_R|CONFIRM,
4562 rId,
4563 plci->number,
4564 "wws",Info,(word)3,SSparms);
4565 break;
4566
4567 case VSWITCH_REQ_PEND:
4568 if(rc!=OK)
4569 {
4570 if(plci->relatedPTYPLCI)
4571 {
4572 plci->relatedPTYPLCI->vswitchstate=0;
4573 plci->relatedPTYPLCI->vsprot=0;
4574 plci->relatedPTYPLCI->vsprotdialect=0;
4575 }
4576 plci->vswitchstate=0;
4577 plci->vsprot=0;
4578 plci->vsprotdialect=0;
4579 }
4580 else
4581 {
4582 if(plci->relatedPTYPLCI &&
4583 plci->vswitchstate==1 &&
4584 plci->relatedPTYPLCI->vswitchstate==3) /* join complete */
4585 plci->vswitchstate=3;
4586 }
4587 break;
4588
4589 /* Call Deflection Request pending (SSCT) */
4590 case CD_REQ_PEND:
4591 SSparms[1] = S_CALL_DEFLECTION;
4592 if(rc!=OK)
4593 {
4594 Info = 0x300E; /* not supported */
4595 plci->appl->CDEnable = 0;
4596 }
4597 sendf(plci->appl,_FACILITY_R|CONFIRM,Id,
4598 plci->number,"wws",Info,(word)3,SSparms);
4599 break;
4600
4601 case RTP_CONNECT_B3_REQ_COMMAND_2:
4602 if (rc == OK)
4603 {
4604 ncci = get_ncci (plci, ch, 0);
4605 Id = (Id & 0xffff) | (((dword) ncci) << 16);
4606 plci->channels++;
4607 a->ncci_state[ncci] = OUTG_CON_PENDING;
4608 }
4609
4610 default:
4611 if (plci->internal_command_queue[0])
4612 {
4613 (*(plci->internal_command_queue[0]))(Id, plci, rc);
4614 if (plci->internal_command)
4615 return;
4616 }
4617 break;
4618 }
4619 next_internal_command (Id, plci);
4620 }
4621 }
4622 else /* appl==0 */
4623 {
4624 Id = ((word)plci->Id<<8)|plci->adapter->Id;
4625 if(plci->tel) Id|=EXT_CONTROLLER;
4626
4627 switch(plci->internal_command)
4628 {
4629 case BLOCK_PLCI:
4630 return;
4631
4632 case START_L1_SIG_ASSIGN_PEND:
4633 case REM_L1_SIG_ASSIGN_PEND:
4634 if(global_req == ASSIGN)
4635 {
4636 break;
4637 }
4638 else
4639 {
4640 dbug(1,dprintf("***L1 Req rem PLCI"));
4641 plci->internal_command = 0;
4642 sig_req(plci,REMOVE,0);
4643 send_req(plci);
4644 }
4645 break;
4646
4647 /* Call Deflection Request pending, just no appl ptr assigned */
4648 case CD_REQ_PEND:
4649 SSparms[1] = S_CALL_DEFLECTION;
4650 if(rc!=OK)
4651 {
4652 Info = 0x300E; /* not supported */
4653 }
4654 for(i=0; i<max_appl; i++)
4655 {
4656 if(application[i].CDEnable)
4657 {
4658 if(!application[i].Id) application[i].CDEnable = 0;
4659 else
4660 {
4661 sendf(&application[i],_FACILITY_R|CONFIRM,Id,
4662 plci->number,"wws",Info,(word)3,SSparms);
4663 if(Info) application[i].CDEnable = 0;
4664 }
4665 }
4666 }
4667 plci->internal_command = 0;
4668 break;
4669
4670 case PERM_COD_HOOK: /* finished with Hook_Ind */
4671 return;
4672
4673 case PERM_COD_CALL:
4674 plci->internal_command = PERM_COD_CONN_PEND;
4675 dbug(1,dprintf("***Codec Connect_Pending, Rc = 0x%x",rc));
4676 return;
4677
4678 case PERM_COD_ASSIGN:
4679 dbug(1,dprintf("***Codec Assign, Rc = 0x%x",rc));
4680 plci->internal_command = 0;
4681 if(rc!=ASSIGN_OK) break;
4682 plci->internal_command = PERM_COD_CALL;
4683 sig_req(plci,CALL_REQ,0);
4684 send_req(plci);
4685 return;
4686
4687 case LISTEN_SIG_ASSIGN_PEND:
4688 if(rc == ASSIGN_OK)
4689 {
4690 plci->internal_command = 0;
4691 dbug(1,dprintf("ListenCheck, new SIG_ID = 0x%x",plci->Sig.Id));
4692 add_p(plci,ESC,"\x02\x18\x00"); /* support call waiting */
4693 sig_req(plci,INDICATE_REQ,0);
4694 send_req(plci);
4695 }
4696 else
4697 {
4698 dbug(1,dprintf("ListenCheck failed (assignRc=0x%x)",rc));
4699 a->listen_active--;
4700 plci_remove(plci);
4701 plci->State = IDLE;
4702 }
4703 break;
4704
4705 case USELAW_REQ:
4706 if(global_req == ASSIGN)
4707 {
4708 if (rc==ASSIGN_OK)
4709 {
4710 sig_req(plci,LAW_REQ,0);
4711 send_req(plci);
4712 dbug(1,dprintf("Auto-Law assigned"));
4713 }
4714 else
4715 {
4716 dbug(1,dprintf("Auto-Law assign failed"));
4717 a->automatic_law = 3;
4718 plci->internal_command = 0;
4719 a->automatic_lawPLCI = NULL;
4720 }
4721 break;
4722 }
4723 else if(req == LAW_REQ && rc==OK)
4724 {
4725 dbug(1,dprintf("Auto-Law initiated"));
4726 a->automatic_law = 2;
4727 plci->internal_command = 0;
4728 }
4729 else
4730 {
4731 dbug(1,dprintf("Auto-Law not supported"));
4732 a->automatic_law = 3;
4733 plci->internal_command = 0;
4734 sig_req(plci,REMOVE,0);
4735 send_req(plci);
4736 a->automatic_lawPLCI = NULL;
4737 }
4738 break;
4739 }
4740 plci_remove_check(plci);
4741 }
4742}
4743
4744void data_rc(PLCI * plci, byte ch)
4745{
4746 dword Id;
4747 DIVA_CAPI_ADAPTER * a;
4748 NCCI *ncci_ptr;
4749 DATA_B3_DESC *data;
4750 word ncci;
4751
4752 if (plci->appl)
4753 {
4754 TransmitBufferFree (plci->appl, plci->data_sent_ptr);
4755 a = plci->adapter;
4756 ncci = a->ch_ncci[ch];
4757 if (ncci && (a->ncci_plci[ncci] == plci->Id))
4758 {
4759 ncci_ptr = &(a->ncci[ncci]);
4760 dbug(1,dprintf("data_out=%d, data_pending=%d",ncci_ptr->data_out,ncci_ptr->data_pending));
4761 if (ncci_ptr->data_pending)
4762 {
4763 data = &(ncci_ptr->DBuffer[ncci_ptr->data_out]);
4764 if (!(data->Flags &4) && a->ncci_state[ncci])
4765 {
4766 Id = (((dword)ncci)<<16)|((word)plci->Id<<8)|a->Id;
4767 if(plci->tel) Id|=EXT_CONTROLLER;
4768 sendf(plci->appl,_DATA_B3_R|CONFIRM,Id,data->Number,
4769 "ww",data->Handle,0);
4770 }
4771 (ncci_ptr->data_out)++;
4772 if (ncci_ptr->data_out == MAX_DATA_B3)
4773 ncci_ptr->data_out = 0;
4774 (ncci_ptr->data_pending)--;
4775 }
4776 }
4777 }
4778}
4779
4780void data_ack(PLCI * plci, byte ch)
4781{
4782 dword Id;
4783 DIVA_CAPI_ADAPTER * a;
4784 NCCI *ncci_ptr;
4785 word ncci;
4786
4787 a = plci->adapter;
4788 ncci = a->ch_ncci[ch];
4789 ncci_ptr = &(a->ncci[ncci]);
4790 if (ncci_ptr->data_ack_pending)
4791 {
4792 if (a->ncci_state[ncci] && (a->ncci_plci[ncci] == plci->Id))
4793 {
4794 Id = (((dword)ncci)<<16)|((word)plci->Id<<8)|a->Id;
4795 if(plci->tel) Id|=EXT_CONTROLLER;
4796 sendf(plci->appl,_DATA_B3_R|CONFIRM,Id,ncci_ptr->DataAck[ncci_ptr->data_ack_out].Number,
4797 "ww",ncci_ptr->DataAck[ncci_ptr->data_ack_out].Handle,0);
4798 }
4799 (ncci_ptr->data_ack_out)++;
4800 if (ncci_ptr->data_ack_out == MAX_DATA_ACK)
4801 ncci_ptr->data_ack_out = 0;
4802 (ncci_ptr->data_ack_pending)--;
4803 }
4804}
4805
4806void sig_ind(PLCI * plci)
4807{
4808 dword x_Id;
4809 dword Id;
4810 dword rId;
4811 word Number = 0;
4812 word i;
4813 word cip;
4814 dword cip_mask;
4815 byte *ie;
4816 DIVA_CAPI_ADAPTER * a;
4817 API_PARSE saved_parms[MAX_MSG_PARMS+1];
4818#define MAXPARMSIDS 31
4819 byte * parms[MAXPARMSIDS];
4820 byte * add_i[4];
4821 byte * multi_fac_parms[MAX_MULTI_IE];
4822 byte * multi_pi_parms [MAX_MULTI_IE];
4823 byte * multi_ssext_parms [MAX_MULTI_IE];
4824 byte * multi_CiPN_parms [MAX_MULTI_IE];
4825
4826 byte * multi_vswitch_parms [MAX_MULTI_IE];
4827
4828 byte ai_len;
4829 byte *esc_chi = "";
4830 byte *esc_law = "";
4831 byte *pty_cai = "";
4832 byte *esc_cr = "";
4833 byte *esc_profile = "";
4834
4835 byte facility[256];
4836 PLCI * tplci = NULL;
4837 byte chi[] = "\x02\x18\x01";
4838 byte voice_cai[] = "\x06\x14\x00\x00\x00\x00\x08";
4839 byte resume_cau[] = "\x05\x05\x00\x02\x00\x00";
4840 /* ESC_MSGTYPE must be the last but one message, a new IE has to be */
4841 /* included before the ESC_MSGTYPE and MAXPARMSIDS has to be incremented */
4842 /* SMSG is situated at the end because its 0 (for compatibility reasons */
4843 /* (see Info_Mask Bit 4, first IE. then the message type) */
4844 word parms_id[] =
4845 {MAXPARMSIDS, CPN, 0xff, DSA, OSA, BC, LLC, HLC, ESC_CAUSE, DSP, DT, CHA,
4846 UUI, CONG_RR, CONG_RNR, ESC_CHI, KEY, CHI, CAU, ESC_LAW,
4847 RDN, RDX, CONN_NR, RIN, NI, CAI, ESC_CR,
4848 CST, ESC_PROFILE, 0xff, ESC_MSGTYPE, SMSG};
4849 /* 14 FTY repl by ESC_CHI */
4850 /* 18 PI repl by ESC_LAW */
4851 /* removed OAD changed to 0xff for future use, OAD is multiIE now */
4852 word multi_fac_id[] = {1, FTY};
4853 word multi_pi_id[] = {1, PI};
4854 word multi_CiPN_id[] = {1, OAD};
4855 word multi_ssext_id[] = {1, ESC_SSEXT};
4856
4857 word multi_vswitch_id[] = {1, ESC_VSWITCH};
4858
4859 byte * cau;
4860 word ncci;
4861 byte SS_Ind[] = "\x05\x02\x00\x02\x00\x00"; /* Hold_Ind struct*/
4862 byte CF_Ind[] = "\x09\x02\x00\x06\x00\x00\x00\x00\x00\x00";
4863 byte Interr_Err_Ind[] = "\x0a\x02\x00\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
4864 byte CONF_Ind[] = "\x09\x16\x00\x06\x00\x00\0x00\0x00\0x00\0x00";
4865 byte force_mt_info = FALSE;
4866 byte dir;
4867 dword d;
4868 word w;
4869
4870 a = plci->adapter;
4871 Id = ((word)plci->Id<<8)|a->Id;
4872 PUT_WORD(&SS_Ind[4],0x0000);
4873
4874 if (plci->sig_remove_id)
4875 {
4876 plci->Sig.RNR = 2; /* discard */
4877 dbug(1,dprintf("SIG discard while remove pending"));
4878 return;
4879 }
4880 if(plci->tel && plci->SuppState!=CALL_HELD) Id|=EXT_CONTROLLER;
4881 dbug(1,dprintf("SigInd-Id=%08lx,plci=%x,tel=%x,state=0x%x,channels=%d,Discflowcl=%d",
4882 Id,plci->Id,plci->tel,plci->State,plci->channels,plci->hangup_flow_ctrl_timer));
4883 if(plci->Sig.Ind==CALL_HOLD_ACK && plci->channels)
4884 {
4885 plci->Sig.RNR = 1;
4886 return;
4887 }
4888 if(plci->Sig.Ind==HANGUP && plci->channels)
4889 {
4890 plci->Sig.RNR = 1;
4891 plci->hangup_flow_ctrl_timer++;
4892 /* recover the network layer after timeout */
4893 if(plci->hangup_flow_ctrl_timer==100)
4894 {
4895 dbug(1,dprintf("Exceptional disc"));
4896 plci->Sig.RNR = 0;
4897 plci->hangup_flow_ctrl_timer = 0;
4898 for (ncci = 1; ncci < MAX_NCCI+1; ncci++)
4899 {
4900 if (a->ncci_plci[ncci] == plci->Id)
4901 {
4902 cleanup_ncci_data (plci, ncci);
4903 if(plci->channels)plci->channels--;
4904 if (plci->appl)
4905 sendf(plci->appl,_DISCONNECT_B3_I, (((dword) ncci) << 16) | Id,0,"ws",0,"");
4906 }
4907 }
4908 if (plci->appl)
4909 sendf(plci->appl, _DISCONNECT_I, Id, 0, "w", 0);
4910 plci_remove(plci);
4911 plci->State=IDLE;
4912 }
4913 return;
4914 }
4915
4916 /* do first parse the info with no OAD in, because OAD will be converted */
4917 /* first the multiple facility IE, then mult. progress ind. */
4918 /* then the parameters for the info_ind + conn_ind */
4919 IndParse(plci,multi_fac_id,multi_fac_parms,MAX_MULTI_IE);
4920 IndParse(plci,multi_pi_id,multi_pi_parms,MAX_MULTI_IE);
4921 IndParse(plci,multi_ssext_id,multi_ssext_parms,MAX_MULTI_IE);
4922
4923 IndParse(plci,multi_vswitch_id,multi_vswitch_parms,MAX_MULTI_IE);
4924
4925 IndParse(plci,parms_id,parms,0);
4926 IndParse(plci,multi_CiPN_id,multi_CiPN_parms,MAX_MULTI_IE);
4927 esc_chi = parms[14];
4928 esc_law = parms[18];
4929 pty_cai = parms[24];
4930 esc_cr = parms[25];
4931 esc_profile = parms[27];
4932 if(esc_cr[0] && plci)
4933 {
4934 if(plci->cr_enquiry && plci->appl)
4935 {
4936 plci->cr_enquiry = FALSE;
4937 /* d = MANU_ID */
4938 /* w = m_command */
4939 /* b = total length */
4940 /* b = indication type */
4941 /* b = length of all IEs */
4942 /* b = IE1 */
4943 /* S = IE1 length + cont. */
4944 /* b = IE2 */
4945 /* S = IE2 lenght + cont. */
4946 sendf(plci->appl,
4947 _MANUFACTURER_I,
4948 Id,
4949 0,
4950 "dwbbbbSbS",_DI_MANU_ID,plci->m_command,
4951 2+1+1+esc_cr[0]+1+1+esc_law[0],plci->Sig.Ind,1+1+esc_cr[0]+1+1+esc_law[0],ESC,esc_cr,ESC,esc_law);
4952 }
4953 }
4954 /* create the additional info structure */
4955 add_i[1] = parms[15]; /* KEY of additional info */
4956 add_i[2] = parms[11]; /* UUI of additional info */
4957 ai_len = AddInfo(add_i,multi_fac_parms, esc_chi, facility);
4958
4959 /* the ESC_LAW indicates if u-Law or a-Law is actually used by the card */
4960 /* indication returns by the card if requested by the function */
4961 /* AutomaticLaw() after driver init */
4962 if (a->automatic_law<4)
4963 {
4964 if(esc_law[0]){
4965 if(esc_law[2]){
4966 dbug(0,dprintf("u-Law selected"));
4967 a->u_law = 1;
4968 }
4969 else {
4970 dbug(0,dprintf("a-Law selected"));
4971 a->u_law = 0;
4972 }
4973 a->automatic_law = 4;
4974 if(plci==a->automatic_lawPLCI) {
4975 plci->internal_command = 0;
4976 sig_req(plci,REMOVE,0);
4977 send_req(plci);
4978 a->automatic_lawPLCI = NULL;
4979 }
4980 }
4981 if (esc_profile[0])
4982 {
4983 dbug (1, dprintf ("[%06x] CardProfile: %lx %lx %lx %lx %lx",
4984 UnMapController (a->Id), GET_DWORD (&esc_profile[6]),
4985 GET_DWORD (&esc_profile[10]), GET_DWORD (&esc_profile[14]),
4986 GET_DWORD (&esc_profile[18]), GET_DWORD (&esc_profile[46])));
4987
4988 a->profile.Global_Options &= 0x000000ffL;
4989 a->profile.B1_Protocols &= 0x000003ffL;
4990 a->profile.B2_Protocols &= 0x00001fdfL;
4991 a->profile.B3_Protocols &= 0x000000b7L;
4992
4993 a->profile.Global_Options &= GET_DWORD (&esc_profile[6]) |
4994 GL_BCHANNEL_OPERATION_SUPPORTED;
4995 a->profile.B1_Protocols &= GET_DWORD (&esc_profile[10]);
4996 a->profile.B2_Protocols &= GET_DWORD (&esc_profile[14]);
4997 a->profile.B3_Protocols &= GET_DWORD (&esc_profile[18]);
4998 a->manufacturer_features = GET_DWORD (&esc_profile[46]);
4999 a->man_profile.private_options = 0;
5000
5001 if (a->manufacturer_features & MANUFACTURER_FEATURE_ECHO_CANCELLER)
5002 {
5003 a->man_profile.private_options |= 1L << PRIVATE_ECHO_CANCELLER;
5004 a->profile.Global_Options |= GL_ECHO_CANCELLER_SUPPORTED;
5005 }
5006
5007
5008 if (a->manufacturer_features & MANUFACTURER_FEATURE_RTP)
5009 a->man_profile.private_options |= 1L << PRIVATE_RTP;
5010 a->man_profile.rtp_primary_payloads = GET_DWORD (&esc_profile[50]);
5011 a->man_profile.rtp_additional_payloads = GET_DWORD (&esc_profile[54]);
5012
5013
5014 if (a->manufacturer_features & MANUFACTURER_FEATURE_T38)
5015 a->man_profile.private_options |= 1L << PRIVATE_T38;
5016
5017
5018 if (a->manufacturer_features & MANUFACTURER_FEATURE_FAX_SUB_SEP_PWD)
5019 a->man_profile.private_options |= 1L << PRIVATE_FAX_SUB_SEP_PWD;
5020
5021
5022 if (a->manufacturer_features & MANUFACTURER_FEATURE_V18)
5023 a->man_profile.private_options |= 1L << PRIVATE_V18;
5024
5025
5026 if (a->manufacturer_features & MANUFACTURER_FEATURE_DTMF_TONE)
5027 a->man_profile.private_options |= 1L << PRIVATE_DTMF_TONE;
5028
5029
5030 if (a->manufacturer_features & MANUFACTURER_FEATURE_PIAFS)
5031 a->man_profile.private_options |= 1L << PRIVATE_PIAFS;
5032
5033
5034 if (a->manufacturer_features & MANUFACTURER_FEATURE_FAX_PAPER_FORMATS)
5035 a->man_profile.private_options |= 1L << PRIVATE_FAX_PAPER_FORMATS;
5036
5037
5038 if (a->manufacturer_features & MANUFACTURER_FEATURE_VOWN)
5039 a->man_profile.private_options |= 1L << PRIVATE_VOWN;
5040
5041
5042 if (a->manufacturer_features & MANUFACTURER_FEATURE_FAX_NONSTANDARD)
5043 a->man_profile.private_options |= 1L << PRIVATE_FAX_NONSTANDARD;
5044
5045 }
5046 else
5047 {
5048 a->profile.Global_Options &= 0x0000007fL;
5049 a->profile.B1_Protocols &= 0x000003dfL;
5050 a->profile.B2_Protocols &= 0x00001adfL;
5051 a->profile.B3_Protocols &= 0x000000b7L;
5052 a->manufacturer_features &= MANUFACTURER_FEATURE_HARDDTMF;
5053 }
5054 if (a->manufacturer_features & (MANUFACTURER_FEATURE_HARDDTMF |
5055 MANUFACTURER_FEATURE_SOFTDTMF_SEND | MANUFACTURER_FEATURE_SOFTDTMF_RECEIVE))
5056 {
5057 a->profile.Global_Options |= GL_DTMF_SUPPORTED;
5058 }
5059 a->manufacturer_features &= ~MANUFACTURER_FEATURE_OOB_CHANNEL;
5060 dbug (1, dprintf ("[%06x] Profile: %lx %lx %lx %lx %lx",
5061 UnMapController (a->Id), a->profile.Global_Options,
5062 a->profile.B1_Protocols, a->profile.B2_Protocols,
5063 a->profile.B3_Protocols, a->manufacturer_features));
5064 }
5065 /* codec plci for the handset/hook state support is just an internal id */
5066 if(plci!=a->AdvCodecPLCI)
5067 {
5068 force_mt_info = SendMultiIE(plci,Id,multi_fac_parms, FTY, 0x20, 0);
5069 force_mt_info |= SendMultiIE(plci,Id,multi_pi_parms, PI, 0x210, 0);
5070 SendSSExtInd(NULL,plci,Id,multi_ssext_parms);
5071 SendInfo(plci,Id, parms, force_mt_info);
5072
5073 VSwitchReqInd(plci,Id,multi_vswitch_parms);
5074
5075 }
5076
5077 /* switch the codec to the b-channel */
5078 if(esc_chi[0] && plci && !plci->SuppState){
5079 plci->b_channel = esc_chi[esc_chi[0]]&0x1f;
5080 mixer_set_bchannel_id_esc (plci, plci->b_channel);
5081 dbug(1,dprintf("storeChannel=0x%x",plci->b_channel));
5082 if(plci->tel==ADV_VOICE && plci->appl) {
5083 SetVoiceChannel(a->AdvCodecPLCI, esc_chi, a);
5084 }
5085 }
5086
5087 if(plci->appl) Number = plci->appl->Number++;
5088
5089 switch(plci->Sig.Ind) {
5090 /* Response to Get_Supported_Services request */
5091 case S_SUPPORTED:
5092 dbug(1,dprintf("S_Supported"));
5093 if(!plci->appl) break;
5094 if(pty_cai[0]==4)
5095 {
5096 PUT_DWORD(&CF_Ind[6],GET_DWORD(&pty_cai[1]) );
5097 }
5098 else
5099 {
5100 PUT_DWORD(&CF_Ind[6],MASK_TERMINAL_PORTABILITY | MASK_HOLD_RETRIEVE);
5101 }
5102 PUT_WORD (&CF_Ind[1], 0);
5103 PUT_WORD (&CF_Ind[4], 0);
5104 sendf(plci->appl,_FACILITY_R|CONFIRM,Id&0x7,plci->number, "wws",0,3,CF_Ind);
5105 plci_remove(plci);
5106 break;
5107
5108 /* Supplementary Service rejected */
5109 case S_SERVICE_REJ:
5110 dbug(1,dprintf("S_Reject=0x%x",pty_cai[5]));
5111 if(!pty_cai[0]) break;
5112 switch (pty_cai[5])
5113 {
5114 case ECT_EXECUTE:
5115 case THREE_PTY_END:
5116 case THREE_PTY_BEGIN:
5117 if(!plci->relatedPTYPLCI) break;
5118 tplci = plci->relatedPTYPLCI;
5119 rId = ( (word)tplci->Id<<8)|tplci->adapter->Id;
5120 if(tplci->tel) rId|=EXT_CONTROLLER;
5121 if(pty_cai[5]==ECT_EXECUTE)
5122 {
5123 PUT_WORD(&SS_Ind[1],S_ECT);
5124
5125 plci->vswitchstate=0;
5126 plci->relatedPTYPLCI->vswitchstate=0;
5127
5128 }
5129 else
5130 {
5131 PUT_WORD(&SS_Ind[1],pty_cai[5]+3);
5132 }
5133 if(pty_cai[2]!=0xff)
5134 {
5135 PUT_WORD(&SS_Ind[4],0x3600|(word)pty_cai[2]);
5136 }
5137 else
5138 {
5139 PUT_WORD(&SS_Ind[4],0x300E);
5140 }
5141 plci->relatedPTYPLCI = NULL;
5142 plci->ptyState = 0;
5143 sendf(tplci->appl,_FACILITY_I,rId,0,"ws",3, SS_Ind);
5144 break;
5145
5146 case CALL_DEFLECTION:
5147 if(pty_cai[2]!=0xff)
5148 {
5149 PUT_WORD(&SS_Ind[4],0x3600|(word)pty_cai[2]);
5150 }
5151 else
5152 {
5153 PUT_WORD(&SS_Ind[4],0x300E);
5154 }
5155 PUT_WORD(&SS_Ind[1],pty_cai[5]);
5156 for(i=0; i<max_appl; i++)
5157 {
5158 if(application[i].CDEnable)
5159 {
5160 if(application[i].Id) sendf(&application[i],_FACILITY_I,Id,0,"ws",3, SS_Ind);
5161 application[i].CDEnable = FALSE;
5162 }
5163 }
5164 break;
5165
5166 case DEACTIVATION_DIVERSION:
5167 case ACTIVATION_DIVERSION:
5168 case DIVERSION_INTERROGATE_CFU:
5169 case DIVERSION_INTERROGATE_CFB:
5170 case DIVERSION_INTERROGATE_CFNR:
5171 case DIVERSION_INTERROGATE_NUM:
5172 case CCBS_REQUEST:
5173 case CCBS_DEACTIVATE:
5174 case CCBS_INTERROGATE:
5175 if(!plci->appl) break;
5176 if(pty_cai[2]!=0xff)
5177 {
5178 PUT_WORD(&Interr_Err_Ind[4],0x3600|(word)pty_cai[2]);
5179 }
5180 else
5181 {
5182 PUT_WORD(&Interr_Err_Ind[4],0x300E);
5183 }
5184 switch (pty_cai[5])
5185 {
5186 case DEACTIVATION_DIVERSION:
5187 dbug(1,dprintf("Deact_Div"));
5188 Interr_Err_Ind[0]=0x9;
5189 Interr_Err_Ind[3]=0x6;
5190 PUT_WORD(&Interr_Err_Ind[1],S_CALL_FORWARDING_STOP);
5191 break;
5192 case ACTIVATION_DIVERSION:
5193 dbug(1,dprintf("Act_Div"));
5194 Interr_Err_Ind[0]=0x9;
5195 Interr_Err_Ind[3]=0x6;
5196 PUT_WORD(&Interr_Err_Ind[1],S_CALL_FORWARDING_START);
5197 break;
5198 case DIVERSION_INTERROGATE_CFU:
5199 case DIVERSION_INTERROGATE_CFB:
5200 case DIVERSION_INTERROGATE_CFNR:
5201 dbug(1,dprintf("Interr_Div"));
5202 Interr_Err_Ind[0]=0xa;
5203 Interr_Err_Ind[3]=0x7;
5204 PUT_WORD(&Interr_Err_Ind[1],S_INTERROGATE_DIVERSION);
5205 break;
5206 case DIVERSION_INTERROGATE_NUM:
5207 dbug(1,dprintf("Interr_Num"));
5208 Interr_Err_Ind[0]=0xa;
5209 Interr_Err_Ind[3]=0x7;
5210 PUT_WORD(&Interr_Err_Ind[1],S_INTERROGATE_NUMBERS);
5211 break;
5212 case CCBS_REQUEST:
5213 dbug(1,dprintf("CCBS Request"));
5214 Interr_Err_Ind[0]=0xd;
5215 Interr_Err_Ind[3]=0xa;
5216 PUT_WORD(&Interr_Err_Ind[1],S_CCBS_REQUEST);
5217 break;
5218 case CCBS_DEACTIVATE:
5219 dbug(1,dprintf("CCBS Deactivate"));
5220 Interr_Err_Ind[0]=0x9;
5221 Interr_Err_Ind[3]=0x6;
5222 PUT_WORD(&Interr_Err_Ind[1],S_CCBS_DEACTIVATE);
5223 break;
5224 case CCBS_INTERROGATE:
5225 dbug(1,dprintf("CCBS Interrogate"));
5226 Interr_Err_Ind[0]=0xb;
5227 Interr_Err_Ind[3]=0x8;
5228 PUT_WORD(&Interr_Err_Ind[1],S_CCBS_INTERROGATE);
5229 break;
5230 }
5231 PUT_DWORD(&Interr_Err_Ind[6],plci->appl->S_Handle);
5232 sendf(plci->appl,_FACILITY_I,Id&0x7,0,"ws",3, Interr_Err_Ind);
5233 plci_remove(plci);
5234 break;
5235 case ACTIVATION_MWI:
5236 case DEACTIVATION_MWI:
5237 if(pty_cai[5]==ACTIVATION_MWI)
5238 {
5239 PUT_WORD(&SS_Ind[1],S_MWI_ACTIVATE);
5240 }
5241 else PUT_WORD(&SS_Ind[1],S_MWI_DEACTIVATE);
5242
5243 if(pty_cai[2]!=0xff)
5244 {
5245 PUT_WORD(&SS_Ind[4],0x3600|(word)pty_cai[2]);
5246 }
5247 else
5248 {
5249 PUT_WORD(&SS_Ind[4],0x300E);
5250 }
5251
5252 if(plci->cr_enquiry)
5253 {
5254 sendf(plci->appl,_FACILITY_I,Id&0xf,0,"ws",3, SS_Ind);
5255 plci_remove(plci);
5256 }
5257 else
5258 {
5259 sendf(plci->appl,_FACILITY_I,Id,0,"ws",3, SS_Ind);
5260 }
5261 break;
5262 case CONF_ADD: /* ERROR */
5263 case CONF_BEGIN:
5264 case CONF_DROP:
5265 case CONF_ISOLATE:
5266 case CONF_REATTACH:
5267 CONF_Ind[0]=9;
5268 CONF_Ind[3]=6;
5269 switch(pty_cai[5])
5270 {
5271 case CONF_BEGIN:
5272 PUT_WORD(&CONF_Ind[1],S_CONF_BEGIN);
5273 plci->ptyState = 0;
5274 break;
5275 case CONF_DROP:
5276 CONF_Ind[0]=5;
5277 CONF_Ind[3]=2;
5278 PUT_WORD(&CONF_Ind[1],S_CONF_DROP);
5279 plci->ptyState = CONNECTED;
5280 break;
5281 case CONF_ISOLATE:
5282 CONF_Ind[0]=5;
5283 CONF_Ind[3]=2;
5284 PUT_WORD(&CONF_Ind[1],S_CONF_ISOLATE);
5285 plci->ptyState = CONNECTED;
5286 break;
5287 case CONF_REATTACH:
5288 CONF_Ind[0]=5;
5289 CONF_Ind[3]=2;
5290 PUT_WORD(&CONF_Ind[1],S_CONF_REATTACH);
5291 plci->ptyState = CONNECTED;
5292 break;
5293 case CONF_ADD:
5294 PUT_WORD(&CONF_Ind[1],S_CONF_ADD);
5295 plci->relatedPTYPLCI = NULL;
5296 tplci=plci->relatedPTYPLCI;
5297 if(tplci) tplci->ptyState = CONNECTED;
5298 plci->ptyState = CONNECTED;
5299 break;
5300 }
5301
5302 if(pty_cai[2]!=0xff)
5303 {
5304 PUT_WORD(&CONF_Ind[4],0x3600|(word)pty_cai[2]);
5305 }
5306 else
5307 {
5308 PUT_WORD(&CONF_Ind[4],0x3303); /* Time-out: network did not respond
5309 within the required time */
5310 }
5311
5312 PUT_DWORD(&CONF_Ind[6],0x0);
5313 sendf(plci->appl,_FACILITY_I,Id,0,"ws",3, CONF_Ind);
5314 break;
5315 }
5316 break;
5317
5318 /* Supplementary Service indicates success */
5319 case S_SERVICE:
5320 dbug(1,dprintf("Service_Ind"));
5321 PUT_WORD (&CF_Ind[4], 0);
5322 switch (pty_cai[5])
5323 {
5324 case THREE_PTY_END:
5325 case THREE_PTY_BEGIN:
5326 case ECT_EXECUTE:
5327 if(!plci->relatedPTYPLCI) break;
5328 tplci = plci->relatedPTYPLCI;
5329 rId = ( (word)tplci->Id<<8)|tplci->adapter->Id;
5330 if(tplci->tel) rId|=EXT_CONTROLLER;
5331 if(pty_cai[5]==ECT_EXECUTE)
5332 {
5333 PUT_WORD(&SS_Ind[1],S_ECT);
5334
5335 if(plci->vswitchstate!=3)
5336 {
5337
5338 plci->ptyState = IDLE;
5339 plci->relatedPTYPLCI = NULL;
5340 plci->ptyState = 0;
5341
5342 }
5343
5344 dbug(1,dprintf("ECT OK"));
5345 sendf(tplci->appl,_FACILITY_I,rId,0,"ws",3, SS_Ind);
5346
5347
5348
5349 }
5350 else
5351 {
5352 switch (plci->ptyState)
5353 {
5354 case S_3PTY_BEGIN:
5355 plci->ptyState = CONNECTED;
5356 dbug(1,dprintf("3PTY ON"));
5357 break;
5358
5359 case S_3PTY_END:
5360 plci->ptyState = IDLE;
5361 plci->relatedPTYPLCI = NULL;
5362 plci->ptyState = 0;
5363 dbug(1,dprintf("3PTY OFF"));
5364 break;
5365 }
5366 PUT_WORD(&SS_Ind[1],pty_cai[5]+3);
5367 sendf(tplci->appl,_FACILITY_I,rId,0,"ws",3, SS_Ind);
5368 }
5369 break;
5370
5371 case CALL_DEFLECTION:
5372 PUT_WORD(&SS_Ind[1],pty_cai[5]);
5373 for(i=0; i<max_appl; i++)
5374 {
5375 if(application[i].CDEnable)
5376 {
5377 if(application[i].Id) sendf(&application[i],_FACILITY_I,Id,0,"ws",3, SS_Ind);
5378 application[i].CDEnable = FALSE;
5379 }
5380 }
5381 break;
5382
5383 case DEACTIVATION_DIVERSION:
5384 case ACTIVATION_DIVERSION:
5385 if(!plci->appl) break;
5386 PUT_WORD(&CF_Ind[1],pty_cai[5]+2);
5387 PUT_DWORD(&CF_Ind[6],plci->appl->S_Handle);
5388 sendf(plci->appl,_FACILITY_I,Id&0x7,0,"ws",3, CF_Ind);
5389 plci_remove(plci);
5390 break;
5391
5392 case DIVERSION_INTERROGATE_CFU:
5393 case DIVERSION_INTERROGATE_CFB:
5394 case DIVERSION_INTERROGATE_CFNR:
5395 case DIVERSION_INTERROGATE_NUM:
5396 case CCBS_REQUEST:
5397 case CCBS_DEACTIVATE:
5398 case CCBS_INTERROGATE:
5399 if(!plci->appl) break;
5400 switch (pty_cai[5])
5401 {
5402 case DIVERSION_INTERROGATE_CFU:
5403 case DIVERSION_INTERROGATE_CFB:
5404 case DIVERSION_INTERROGATE_CFNR:
5405 dbug(1,dprintf("Interr_Div"));
5406 PUT_WORD(&pty_cai[1],S_INTERROGATE_DIVERSION);
5407 pty_cai[3]=pty_cai[0]-3; /* Supplementary Service-specific parameter len */
5408 break;
5409 case DIVERSION_INTERROGATE_NUM:
5410 dbug(1,dprintf("Interr_Num"));
5411 PUT_WORD(&pty_cai[1],S_INTERROGATE_NUMBERS);
5412 pty_cai[3]=pty_cai[0]-3; /* Supplementary Service-specific parameter len */
5413 break;
5414 case CCBS_REQUEST:
5415 dbug(1,dprintf("CCBS Request"));
5416 PUT_WORD(&pty_cai[1],S_CCBS_REQUEST);
5417 pty_cai[3]=pty_cai[0]-3; /* Supplementary Service-specific parameter len */
5418 break;
5419 case CCBS_DEACTIVATE:
5420 dbug(1,dprintf("CCBS Deactivate"));
5421 PUT_WORD(&pty_cai[1],S_CCBS_DEACTIVATE);
5422 pty_cai[3]=pty_cai[0]-3; /* Supplementary Service-specific parameter len */
5423 break;
5424 case CCBS_INTERROGATE:
5425 dbug(1,dprintf("CCBS Interrogate"));
5426 PUT_WORD(&pty_cai[1],S_CCBS_INTERROGATE);
5427 pty_cai[3]=pty_cai[0]-3; /* Supplementary Service-specific parameter len */
5428 break;
5429 }
5430 PUT_WORD(&pty_cai[4],0); /* Supplementary Service Reason */
5431 PUT_DWORD(&pty_cai[6],plci->appl->S_Handle);
5432 sendf(plci->appl,_FACILITY_I,Id&0x7,0,"wS",3, pty_cai);
5433 plci_remove(plci);
5434 break;
5435
5436 case ACTIVATION_MWI:
5437 case DEACTIVATION_MWI:
5438 if(pty_cai[5]==ACTIVATION_MWI)
5439 {
5440 PUT_WORD(&SS_Ind[1],S_MWI_ACTIVATE);
5441 }
5442 else PUT_WORD(&SS_Ind[1],S_MWI_DEACTIVATE);
5443 if(plci->cr_enquiry)
5444 {
5445 sendf(plci->appl,_FACILITY_I,Id&0xf,0,"ws",3, SS_Ind);
5446 plci_remove(plci);
5447 }
5448 else
5449 {
5450 sendf(plci->appl,_FACILITY_I,Id,0,"ws",3, SS_Ind);
5451 }
5452 break;
5453 case MWI_INDICATION:
5454 if(pty_cai[0]>=0x12)
5455 {
5456 PUT_WORD(&pty_cai[3],S_MWI_INDICATE);
5457 pty_cai[2]=pty_cai[0]-2; /* len Parameter */
5458 pty_cai[5]=pty_cai[0]-5; /* Supplementary Service-specific parameter len */
5459 if(plci->appl && (a->Notification_Mask[plci->appl->Id-1]&SMASK_MWI))
5460 {
5461 if(plci->internal_command==GET_MWI_STATE) /* result on Message Waiting Listen */
5462 {
5463 sendf(plci->appl,_FACILITY_I,Id&0xf,0,"wS",3, &pty_cai[2]);
5464 plci_remove(plci);
5465 return;
5466 }
5467 else sendf(plci->appl,_FACILITY_I,Id,0,"wS",3, &pty_cai[2]);
5468 pty_cai[0]=0;
5469 }
5470 else
5471 {
5472 for(i=0; i<max_appl; i++)
5473 {
5474 if(a->Notification_Mask[i]&SMASK_MWI)
5475 {
5476 sendf(&application[i],_FACILITY_I,Id&0x7,0,"wS",3, &pty_cai[2]);
5477 pty_cai[0]=0;
5478 }
5479 }
5480 }
5481
5482 if(!pty_cai[0])
5483 { /* acknowledge */
5484 facility[2]= 0; /* returncode */
5485 }
5486 else facility[2]= 0xff;
5487 }
5488 else
5489 {
5490 /* reject */
5491 facility[2]= 0xff; /* returncode */
5492 }
5493 facility[0]= 2;
5494 facility[1]= MWI_RESPONSE; /* Function */
5495 add_p(plci,CAI,facility);
5496 add_p(plci,ESC,multi_ssext_parms[0]); /* remembered parameter -> only one possible */
5497 sig_req(plci,S_SERVICE,0);
5498 send_req(plci);
5499 plci->command = 0;
5500 next_internal_command (Id, plci);
5501 break;
5502 case CONF_ADD: /* OK */
5503 case CONF_BEGIN:
5504 case CONF_DROP:
5505 case CONF_ISOLATE:
5506 case CONF_REATTACH:
5507 case CONF_PARTYDISC:
5508 CONF_Ind[0]=9;
5509 CONF_Ind[3]=6;
5510 switch(pty_cai[5])
5511 {
5512 case CONF_BEGIN:
5513 PUT_WORD(&CONF_Ind[1],S_CONF_BEGIN);
5514 if(pty_cai[0]==6)
5515 {
5516 d=pty_cai[6];
5517 PUT_DWORD(&CONF_Ind[6],d); /* PartyID */
5518 }
5519 else
5520 {
5521 PUT_DWORD(&CONF_Ind[6],0x0);
5522 }
5523 break;
5524 case CONF_ISOLATE:
5525 PUT_WORD(&CONF_Ind[1],S_CONF_ISOLATE);
5526 CONF_Ind[0]=5;
5527 CONF_Ind[3]=2;
5528 break;
5529 case CONF_REATTACH:
5530 PUT_WORD(&CONF_Ind[1],S_CONF_REATTACH);
5531 CONF_Ind[0]=5;
5532 CONF_Ind[3]=2;
5533 break;
5534 case CONF_DROP:
5535 PUT_WORD(&CONF_Ind[1],S_CONF_DROP);
5536 CONF_Ind[0]=5;
5537 CONF_Ind[3]=2;
5538 break;
5539 case CONF_ADD:
5540 PUT_WORD(&CONF_Ind[1],S_CONF_ADD);
5541 d=pty_cai[6];
5542 PUT_DWORD(&CONF_Ind[6],d); /* PartyID */
5543 tplci=plci->relatedPTYPLCI;
5544 if(tplci) tplci->ptyState = CONNECTED;
5545 break;
5546 case CONF_PARTYDISC:
5547 CONF_Ind[0]=7;
5548 CONF_Ind[3]=4;
5549 PUT_WORD(&CONF_Ind[1],S_CONF_PARTYDISC);
5550 d=pty_cai[6];
5551 PUT_DWORD(&CONF_Ind[4],d); /* PartyID */
5552 break;
5553 }
5554 plci->ptyState = CONNECTED;
5555 sendf(plci->appl,_FACILITY_I,Id,0,"ws",3, CONF_Ind);
5556 break;
5557 case CCBS_INFO_RETAIN:
5558 case CCBS_ERASECALLLINKAGEID:
5559 case CCBS_STOP_ALERTING:
5560 CONF_Ind[0]=5;
5561 CONF_Ind[3]=2;
5562 switch(pty_cai[5])
5563 {
5564 case CCBS_INFO_RETAIN:
5565 PUT_WORD(&CONF_Ind[1],S_CCBS_INFO_RETAIN);
5566 break;
5567 case CCBS_STOP_ALERTING:
5568 PUT_WORD(&CONF_Ind[1],S_CCBS_STOP_ALERTING);
5569 break;
5570 case CCBS_ERASECALLLINKAGEID:
5571 PUT_WORD(&CONF_Ind[1],S_CCBS_ERASECALLLINKAGEID);
5572 CONF_Ind[0]=7;
5573 CONF_Ind[3]=4;
5574 CONF_Ind[6]=0;
5575 CONF_Ind[7]=0;
5576 break;
5577 }
5578 w=pty_cai[6];
5579 PUT_WORD(&CONF_Ind[4],w); /* PartyID */
5580
5581 if(plci->appl && (a->Notification_Mask[plci->appl->Id-1]&SMASK_CCBS))
5582 {
5583 sendf(plci->appl,_FACILITY_I,Id,0,"ws",3, CONF_Ind);
5584 }
5585 else
5586 {
5587 for(i=0; i<max_appl; i++)
5588 if(a->Notification_Mask[i]&SMASK_CCBS)
5589 sendf(&application[i],_FACILITY_I,Id&0x7,0,"ws",3, CONF_Ind);
5590 }
5591 break;
5592 }
5593 break;
5594 case CALL_HOLD_REJ:
5595 cau = parms[7];
5596 if(cau)
5597 {
5598 i = _L3_CAUSE | cau[2];
5599 if(cau[2]==0) i = 0x3603;
5600 }
5601 else
5602 {
5603 i = 0x3603;
5604 }
5605 PUT_WORD(&SS_Ind[1],S_HOLD);
5606 PUT_WORD(&SS_Ind[4],i);
5607 if(plci->SuppState == HOLD_REQUEST)
5608 {
5609 plci->SuppState = IDLE;
5610 sendf(plci->appl,_FACILITY_I,Id,0,"ws",3, SS_Ind);
5611 }
5612 break;
5613
5614 case CALL_HOLD_ACK:
5615 if(plci->SuppState == HOLD_REQUEST)
5616 {
5617 plci->SuppState = CALL_HELD;
5618 CodecIdCheck(a, plci);
5619 start_internal_command (Id, plci, hold_save_command);
5620 }
5621 break;
5622
5623 case CALL_RETRIEVE_REJ:
5624 cau = parms[7];
5625 if(cau)
5626 {
5627 i = _L3_CAUSE | cau[2];
5628 if(cau[2]==0) i = 0x3603;
5629 }
5630 else
5631 {
5632 i = 0x3603;
5633 }
5634 PUT_WORD(&SS_Ind[1],S_RETRIEVE);
5635 PUT_WORD(&SS_Ind[4],i);
5636 if(plci->SuppState == RETRIEVE_REQUEST)
5637 {
5638 plci->SuppState = CALL_HELD;
5639 CodecIdCheck(a, plci);
5640 sendf(plci->appl,_FACILITY_I,Id,0,"ws",3, SS_Ind);
5641 }
5642 break;
5643
5644 case CALL_RETRIEVE_ACK:
5645 PUT_WORD(&SS_Ind[1],S_RETRIEVE);
5646 if(plci->SuppState == RETRIEVE_REQUEST)
5647 {
5648 plci->SuppState = IDLE;
5649 plci->call_dir |= CALL_DIR_FORCE_OUTG_NL;
5650 plci->b_channel = esc_chi[esc_chi[0]]&0x1f;
5651 if(plci->tel)
5652 {
5653 mixer_set_bchannel_id_esc (plci, plci->b_channel);
5654 dbug(1,dprintf("RetrChannel=0x%x",plci->b_channel));
5655 SetVoiceChannel(a->AdvCodecPLCI, esc_chi, a);
5656 if(plci->B2_prot==B2_TRANSPARENT && plci->B3_prot==B3_TRANSPARENT)
5657 {
5658 dbug(1,dprintf("Get B-ch"));
5659 start_internal_command (Id, plci, retrieve_restore_command);
5660 }
5661 else
5662 sendf(plci->appl,_FACILITY_I,Id,0,"ws",3, SS_Ind);
5663 }
5664 else
5665 start_internal_command (Id, plci, retrieve_restore_command);
5666 }
5667 break;
5668
5669 case INDICATE_IND:
5670 if(plci->State != LISTENING) {
5671 sig_req(plci,HANGUP,0);
5672 send_req(plci);
5673 break;
5674 }
5675 cip = find_cip(a,parms[4],parms[6]);
5676 cip_mask = 1L<<cip;
5677 dbug(1,dprintf("cip=%d,cip_mask=%lx",cip,cip_mask));
5678 clear_c_ind_mask (plci);
5679 if (!remove_started && !a->adapter_disabled)
5680 {
5681 set_c_ind_mask_bit (plci, MAX_APPL);
5682 group_optimization(a, plci);
5683 for(i=0; i<max_appl; i++) {
5684 if(application[i].Id
5685 && (a->CIP_Mask[i]&1 || a->CIP_Mask[i]&cip_mask)
5686 && CPN_filter_ok(parms[0],a,i)
5687 && test_group_ind_mask_bit (plci, i) ) {
5688 dbug(1,dprintf("storedcip_mask[%d]=0x%lx",i,a->CIP_Mask[i] ));
5689 set_c_ind_mask_bit (plci, i);
5690 dump_c_ind_mask (plci);
5691 plci->State = INC_CON_PENDING;
5692 plci->call_dir = (plci->call_dir & ~(CALL_DIR_OUT | CALL_DIR_ORIGINATE)) |
5693 CALL_DIR_IN | CALL_DIR_ANSWER;
5694 if(esc_chi[0]) {
5695 plci->b_channel = esc_chi[esc_chi[0]]&0x1f;
5696 mixer_set_bchannel_id_esc (plci, plci->b_channel);
5697 }
5698 /* if a listen on the ext controller is done, check if hook states */
5699 /* are supported or if just a on board codec must be activated */
5700 if(a->codec_listen[i] && !a->AdvSignalPLCI) {
5701 if(a->profile.Global_Options & HANDSET)
5702 plci->tel = ADV_VOICE;
5703 else if(a->profile.Global_Options & ON_BOARD_CODEC)
5704 plci->tel = CODEC;
5705 if(plci->tel) Id|=EXT_CONTROLLER;
5706 a->codec_listen[i] = plci;
5707 }
5708
5709 sendf(&application[i],_CONNECT_I,Id,0,
5710 "wSSSSSSSbSSSSS", cip, /* CIP */
5711 parms[0], /* CalledPartyNumber */
5712 multi_CiPN_parms[0], /* CallingPartyNumber */
5713 parms[2], /* CalledPartySubad */
5714 parms[3], /* CallingPartySubad */
5715 parms[4], /* BearerCapability */
5716 parms[5], /* LowLC */
5717 parms[6], /* HighLC */
5718 ai_len, /* nested struct add_i */
5719 add_i[0], /* B channel info */
5720 add_i[1], /* keypad facility */
5721 add_i[2], /* user user data */
5722 add_i[3], /* nested facility */
5723 multi_CiPN_parms[1] /* second CiPN(SCR) */
5724 );
5725 SendSSExtInd(&application[i],
5726 plci,
5727 Id,
5728 multi_ssext_parms);
5729 SendSetupInfo(&application[i],
5730 plci,
5731 Id,
5732 parms,
5733 SendMultiIE(plci,Id,multi_pi_parms, PI, 0x210, TRUE));
5734 }
5735 }
5736 clear_c_ind_mask_bit (plci, MAX_APPL);
5737 dump_c_ind_mask (plci);
5738 }
5739 if(c_ind_mask_empty (plci)) {
5740 sig_req(plci,HANGUP,0);
5741 send_req(plci);
5742 plci->State = IDLE;
5743 }
5744 plci->notifiedcall = 0;
5745 a->listen_active--;
5746 listen_check(a);
5747 break;
5748
5749 case CALL_PEND_NOTIFY:
5750 plci->notifiedcall = 1;
5751 listen_check(a);
5752 break;
5753
5754 case CALL_IND:
5755 case CALL_CON:
5756 if(plci->State==ADVANCED_VOICE_SIG || plci->State==ADVANCED_VOICE_NOSIG)
5757 {
5758 if(plci->internal_command==PERM_COD_CONN_PEND)
5759 {
5760 if(plci->State==ADVANCED_VOICE_NOSIG)
5761 {
5762 dbug(1,dprintf("***Codec OK"));
5763 if(a->AdvSignalPLCI)
5764 {
5765 tplci = a->AdvSignalPLCI;
5766 if(tplci->spoofed_msg)
5767 {
5768 dbug(1,dprintf("***Spoofed Msg(0x%x)",tplci->spoofed_msg));
5769 tplci->command = 0;
5770 tplci->internal_command = 0;
5771 x_Id = ((word)tplci->Id<<8)|tplci->adapter->Id | 0x80;
5772 switch (tplci->spoofed_msg)
5773 {
5774 case CALL_RES:
5775 tplci->command = _CONNECT_I|RESPONSE;
5776 api_load_msg (&tplci->saved_msg, saved_parms);
5777 add_b1(tplci,&saved_parms[1],0,tplci->B1_facilities);
5778 if (tplci->adapter->Info_Mask[tplci->appl->Id-1] & 0x200)
5779 {
5780 /* early B3 connect (CIP mask bit 9) no release after a disc */
5781 add_p(tplci,LLI,"\x01\x01");
5782 }
5783 add_s(tplci, CONN_NR, &saved_parms[2]);
5784 add_s(tplci, LLC, &saved_parms[4]);
5785 add_ai(tplci, &saved_parms[5]);
5786 tplci->State = INC_CON_ACCEPT;
5787 sig_req(tplci, CALL_RES,0);
5788 send_req(tplci);
5789 break;
5790
5791 case AWAITING_SELECT_B:
5792 dbug(1,dprintf("Select_B continue"));
5793 start_internal_command (x_Id, tplci, select_b_command);
5794 break;
5795
5796 case AWAITING_MANUF_CON: /* Get_Plci per Manufacturer_Req to ext controller */
5797 if(!tplci->Sig.Id)
5798 {
5799 dbug(1,dprintf("No SigID!"));
5800 sendf(tplci->appl, _MANUFACTURER_R|CONFIRM,x_Id,tplci->number, "dww",_DI_MANU_ID,_MANUFACTURER_R,_OUT_OF_PLCI);
5801 plci_remove(tplci);
5802 break;
5803 }
5804 tplci->command = _MANUFACTURER_R;
5805 api_load_msg (&tplci->saved_msg, saved_parms);
5806 dir = saved_parms[2].info[0];
5807 if(dir==1) {
5808 sig_req(tplci,CALL_REQ,0);
5809 }
5810 else if(!dir){
5811 sig_req(tplci,LISTEN_REQ,0);
5812 }
5813 send_req(tplci);
5814 sendf(tplci->appl, _MANUFACTURER_R|CONFIRM,x_Id,tplci->number, "dww",_DI_MANU_ID,_MANUFACTURER_R,0);
5815 break;
5816
5817 case (CALL_REQ|AWAITING_MANUF_CON):
5818 sig_req(tplci,CALL_REQ,0);
5819 send_req(tplci);
5820 break;
5821
5822 case CALL_REQ:
5823 if(!tplci->Sig.Id)
5824 {
5825 dbug(1,dprintf("No SigID!"));
5826 sendf(tplci->appl,_CONNECT_R|CONFIRM,tplci->adapter->Id,0,"w",_OUT_OF_PLCI);
5827 plci_remove(tplci);
5828 break;
5829 }
5830 tplci->command = _CONNECT_R;
5831 api_load_msg (&tplci->saved_msg, saved_parms);
5832 add_s(tplci,CPN,&saved_parms[1]);
5833 add_s(tplci,DSA,&saved_parms[3]);
5834 add_ai(tplci,&saved_parms[9]);
5835 sig_req(tplci,CALL_REQ,0);
5836 send_req(tplci);
5837 break;
5838
5839 case CALL_RETRIEVE:
5840 tplci->command = C_RETRIEVE_REQ;
5841 sig_req(tplci,CALL_RETRIEVE,0);
5842 send_req(tplci);
5843 break;
5844 }
5845 tplci->spoofed_msg = 0;
5846 if (tplci->internal_command == 0)
5847 next_internal_command (x_Id, tplci);
5848 }
5849 }
5850 next_internal_command (Id, plci);
5851 break;
5852 }
5853 dbug(1,dprintf("***Codec Hook Init Req"));
5854 plci->internal_command = PERM_COD_HOOK;
5855 add_p(plci,FTY,"\x01\x09"); /* Get Hook State*/
5856 sig_req(plci,TEL_CTRL,0);
5857 send_req(plci);
5858 }
5859 }
5860 else if(plci->command != _MANUFACTURER_R /* old style permanent connect */
5861 && plci->State!=INC_ACT_PENDING)
5862 {
5863 mixer_set_bchannel_id_esc (plci, plci->b_channel);
5864 if(plci->tel == ADV_VOICE && plci->SuppState == IDLE) /* with permanent codec switch on immediately */
5865 {
5866 chi[2] = plci->b_channel;
5867 SetVoiceChannel(a->AdvCodecPLCI, chi, a);
5868 }
5869 sendf(plci->appl,_CONNECT_ACTIVE_I,Id,0,"Sss",parms[21],"","");
5870 plci->State = INC_ACT_PENDING;
5871 }
5872 break;
5873
5874 case TEL_CTRL:
5875 Number = 0;
5876 ie = multi_fac_parms[0]; /* inspect the facility hook indications */
5877 if(plci->State==ADVANCED_VOICE_SIG && ie[0]){
5878 switch (ie[1]&0x91) {
5879 case 0x80: /* hook off */
5880 case 0x81:
5881 if(plci->internal_command==PERM_COD_HOOK)
5882 {
5883 dbug(1,dprintf("init:hook_off"));
5884 plci->hook_state = ie[1];
5885 next_internal_command (Id, plci);
5886 break;
5887 }
5888 else /* ignore doubled hook indications */
5889 {
5890 if( ((plci->hook_state)&0xf0)==0x80)
5891 {
5892 dbug(1,dprintf("ignore hook"));
5893 break;
5894 }
5895 plci->hook_state = ie[1]&0x91;
5896 }
5897 /* check for incoming call pending */
5898 /* and signal '+'.Appl must decide */
5899 /* with connect_res if call must */
5900 /* accepted or not */
5901 for(i=0, tplci=NULL;i<max_appl;i++){
5902 if(a->codec_listen[i]
5903 && (a->codec_listen[i]->State==INC_CON_PENDING
5904 ||a->codec_listen[i]->State==INC_CON_ALERT) ){
5905 tplci = a->codec_listen[i];
5906 tplci->appl = &application[i];
5907 }
5908 }
5909 /* no incoming call, do outgoing call */
5910 /* and signal '+' if outg. setup */
5911 if(!a->AdvSignalPLCI && !tplci){
5912 if((i=get_plci(a))) {
5913 a->AdvSignalPLCI = &a->plci[i-1];
5914 tplci = a->AdvSignalPLCI;
5915 tplci->tel = ADV_VOICE;
5916 PUT_WORD(&voice_cai[5],a->AdvSignalAppl->MaxDataLength);
5917 if (a->Info_Mask[a->AdvSignalAppl->Id-1] & 0x200){
5918 /* early B3 connect (CIP mask bit 9) no release after a disc */
5919 add_p(tplci,LLI,"\x01\x01");
5920 }
5921 add_p(tplci, CAI, voice_cai);
5922 add_p(tplci, OAD, a->TelOAD);
5923 add_p(tplci, OSA, a->TelOSA);
5924 add_p(tplci,SHIFT|6,NULL);
5925 add_p(tplci,SIN,"\x02\x01\x00");
5926 add_p(tplci,UID,"\x06\x43\x61\x70\x69\x32\x30");
5927 sig_req(tplci,ASSIGN,DSIG_ID);
5928 a->AdvSignalPLCI->internal_command = HOOK_OFF_REQ;
5929 a->AdvSignalPLCI->command = 0;
5930 tplci->appl = a->AdvSignalAppl;
5931 tplci->call_dir = CALL_DIR_OUT | CALL_DIR_ORIGINATE;
5932 send_req(tplci);
5933 }
5934
5935 }
5936
5937 if(!tplci) break;
5938 Id = ((word)tplci->Id<<8)|a->Id;
5939 Id|=EXT_CONTROLLER;
5940 sendf(tplci->appl,
5941 _FACILITY_I,
5942 Id,
5943 0,
5944 "ws", (word)0, "\x01+");
5945 break;
5946
5947 case 0x90: /* hook on */
5948 case 0x91:
5949 if(plci->internal_command==PERM_COD_HOOK)
5950 {
5951 dbug(1,dprintf("init:hook_on"));
5952 plci->hook_state = ie[1]&0x91;
5953 next_internal_command (Id, plci);
5954 break;
5955 }
5956 else /* ignore doubled hook indications */
5957 {
5958 if( ((plci->hook_state)&0xf0)==0x90) break;
5959 plci->hook_state = ie[1]&0x91;
5960 }
5961 /* hangup the adv. voice call and signal '-' to the appl */
5962 if(a->AdvSignalPLCI) {
5963 Id = ((word)a->AdvSignalPLCI->Id<<8)|a->Id;
5964 if(plci->tel) Id|=EXT_CONTROLLER;
5965 sendf(a->AdvSignalAppl,
5966 _FACILITY_I,
5967 Id,
5968 0,
5969 "ws", (word)0, "\x01-");
5970 a->AdvSignalPLCI->internal_command = HOOK_ON_REQ;
5971 a->AdvSignalPLCI->command = 0;
5972 sig_req(a->AdvSignalPLCI,HANGUP,0);
5973 send_req(a->AdvSignalPLCI);
5974 }
5975 break;
5976 }
5977 }
5978 break;
5979
5980 case RESUME:
5981 clear_c_ind_mask_bit (plci, (word)(plci->appl->Id-1));
5982 PUT_WORD(&resume_cau[4],GOOD);
5983 sendf(plci->appl,_FACILITY_I,Id,0,"ws", (word)3, resume_cau);
5984 break;
5985
5986 case SUSPEND:
5987 clear_c_ind_mask (plci);
5988
5989 if (plci->NL.Id && !plci->nl_remove_id) {
5990 mixer_remove (plci);
5991 nl_req_ncci(plci,REMOVE,0);
5992 }
5993 if (!plci->sig_remove_id) {
5994 plci->internal_command = 0;
5995 sig_req(plci,REMOVE,0);
5996 }
5997 send_req(plci);
5998 if(!plci->channels) {
5999 sendf(plci->appl,_FACILITY_I,Id,0,"ws", (word)3, "\x05\x04\x00\x02\x00\x00");
6000 sendf(plci->appl, _DISCONNECT_I, Id, 0, "w", 0);
6001 }
6002 break;
6003
6004 case SUSPEND_REJ:
6005 break;
6006
6007 case HANGUP:
6008 plci->hangup_flow_ctrl_timer=0;
6009 if(plci->manufacturer && plci->State==LOCAL_CONNECT) break;
6010 cau = parms[7];
6011 if(cau) {
6012 i = _L3_CAUSE | cau[2];
6013 if(cau[2]==0) i = 0;
6014 else if(cau[2]==8) i = _L1_ERROR;
6015 else if(cau[2]==9 || cau[2]==10) i = _L2_ERROR;
6016 else if(cau[2]==5) i = _CAPI_GUARD_ERROR;
6017 }
6018 else {
6019 i = _L3_ERROR;
6020 }
6021
6022 if(plci->State==INC_CON_PENDING || plci->State==INC_CON_ALERT)
6023 {
6024 for(i=0; i<max_appl; i++)
6025 {
6026 if(test_c_ind_mask_bit (plci, i))
6027 sendf(&application[i], _DISCONNECT_I, Id, 0, "w", 0);
6028 }
6029 }
6030 else
6031 {
6032 clear_c_ind_mask (plci);
6033 }
6034 if(!plci->appl)
6035 {
6036 if (plci->State == LISTENING)
6037 {
6038 plci->notifiedcall=0;
6039 a->listen_active--;
6040 }
6041 plci->State = INC_DIS_PENDING;
6042 if(c_ind_mask_empty (plci))
6043 {
6044 plci->State = IDLE;
6045 if (plci->NL.Id && !plci->nl_remove_id)
6046 {
6047 mixer_remove (plci);
6048 nl_req_ncci(plci,REMOVE,0);
6049 }
6050 if (!plci->sig_remove_id)
6051 {
6052 plci->internal_command = 0;
6053 sig_req(plci,REMOVE,0);
6054 }
6055 send_req(plci);
6056 }
6057 }
6058 else
6059 {
6060 /* collision of DISCONNECT or CONNECT_RES with HANGUP can */
6061 /* result in a second HANGUP! Don't generate another */
6062 /* DISCONNECT */
6063 if(plci->State!=IDLE && plci->State!=INC_DIS_PENDING)
6064 {
6065 if(plci->State==RESUMING)
6066 {
6067 PUT_WORD(&resume_cau[4],i);
6068 sendf(plci->appl,_FACILITY_I,Id,0,"ws", (word)3, resume_cau);
6069 }
6070 plci->State = INC_DIS_PENDING;
6071 sendf(plci->appl,_DISCONNECT_I,Id,0,"w",i);
6072 }
6073 }
6074 break;
6075
6076 case SSEXT_IND:
6077 SendSSExtInd(NULL,plci,Id,multi_ssext_parms);
6078 break;
6079
6080 case VSWITCH_REQ:
6081 VSwitchReqInd(plci,Id,multi_vswitch_parms);
6082 break;
6083 case VSWITCH_IND:
6084 if(plci->relatedPTYPLCI &&
6085 plci->vswitchstate==3 &&
6086 plci->relatedPTYPLCI->vswitchstate==3 &&
6087 parms[MAXPARMSIDS-1][0])
6088 {
6089 add_p(plci->relatedPTYPLCI,SMSG,parms[MAXPARMSIDS-1]);
6090 sig_req(plci->relatedPTYPLCI,VSWITCH_REQ,0);
6091 send_req(plci->relatedPTYPLCI);
6092 }
6093 else VSwitchReqInd(plci,Id,multi_vswitch_parms);
6094 break;
6095
6096 }
6097}
6098
6099
6100static void SendSetupInfo(APPL * appl, PLCI * plci, dword Id, byte * * parms, byte Info_Sent_Flag)
6101{
6102 word i;
6103 byte * ie;
6104 word Info_Number;
6105 byte * Info_Element;
6106 word Info_Mask = 0;
6107
6108 dbug(1,dprintf("SetupInfo"));
6109
6110 for(i=0; i<MAXPARMSIDS; i++) {
6111 ie = parms[i];
6112 Info_Number = 0;
6113 Info_Element = ie;
6114 if(ie[0]) {
6115 switch(i) {
6116 case 0:
6117 dbug(1,dprintf("CPN "));
6118 Info_Number = 0x0070;
6119 Info_Mask = 0x80;
6120 Info_Sent_Flag = TRUE;
6121 break;
6122 case 8: /* display */
6123 dbug(1,dprintf("display(%d)",i));
6124 Info_Number = 0x0028;
6125 Info_Mask = 0x04;
6126 Info_Sent_Flag = TRUE;
6127 break;
6128 case 16: /* Channel Id */
6129 dbug(1,dprintf("CHI"));
6130 Info_Number = 0x0018;
6131 Info_Mask = 0x100;
6132 Info_Sent_Flag = TRUE;
6133 mixer_set_bchannel_id (plci, Info_Element);
6134 break;
6135 case 19: /* Redirected Number */
6136 dbug(1,dprintf("RDN"));
6137 Info_Number = 0x0074;
6138 Info_Mask = 0x400;
6139 Info_Sent_Flag = TRUE;
6140 break;
6141 case 20: /* Redirected Number extended */
6142 dbug(1,dprintf("RDX"));
6143 Info_Number = 0x0073;
6144 Info_Mask = 0x400;
6145 Info_Sent_Flag = TRUE;
6146 break;
6147 case 22: /* Redirecing Number */
6148 dbug(1,dprintf("RIN"));
6149 Info_Number = 0x0076;
6150 Info_Mask = 0x400;
6151 Info_Sent_Flag = TRUE;
6152 break;
6153 default:
6154 Info_Number = 0;
6155 break;
6156 }
6157 }
6158
6159 if(i==MAXPARMSIDS-2){ /* to indicate the message type "Setup" */
6160 Info_Number = 0x8000 |5;
6161 Info_Mask = 0x10;
6162 Info_Element = "";
6163 }
6164
6165 if(Info_Sent_Flag && Info_Number){
6166 if(plci->adapter->Info_Mask[appl->Id-1] & Info_Mask) {
6167 sendf(appl,_INFO_I,Id,0,"wS",Info_Number,Info_Element);
6168 }
6169 }
6170 }
6171}
6172
6173
6174void SendInfo(PLCI * plci, dword Id, byte * * parms, byte iesent)
6175{
6176 word i;
6177 word j;
6178 word k;
6179 byte * ie;
6180 word Info_Number;
6181 byte * Info_Element;
6182 word Info_Mask = 0;
6183 static byte charges[5] = {4,0,0,0,0};
6184 static byte cause[] = {0x02,0x80,0x00};
6185 APPL *appl;
6186
6187 dbug(1,dprintf("InfoParse "));
6188
6189 if(
6190 !plci->appl
6191 && !plci->State
6192 && plci->Sig.Ind!=NCR_FACILITY
6193 )
6194 {
6195 dbug(1,dprintf("NoParse "));
6196 return;
6197 }
6198 cause[2] = 0;
6199 for(i=0; i<MAXPARMSIDS; i++) {
6200 ie = parms[i];
6201 Info_Number = 0;
6202 Info_Element = ie;
6203 if(ie[0]) {
6204 switch(i) {
6205 case 0:
6206 dbug(1,dprintf("CPN "));
6207 Info_Number = 0x0070;
6208 Info_Mask = 0x80;
6209 break;
6210 case 7: /* ESC_CAU */
6211 dbug(1,dprintf("cau(0x%x)",ie[2]));
6212 Info_Number = 0x0008;
6213 Info_Mask = 0x00;
6214 cause[2] = ie[2];
6215 Info_Element = NULL;
6216 break;
6217 case 8: /* display */
6218 dbug(1,dprintf("display(%d)",i));
6219 Info_Number = 0x0028;
6220 Info_Mask = 0x04;
6221 break;
6222 case 9: /* Date display */
6223 dbug(1,dprintf("date(%d)",i));
6224 Info_Number = 0x0029;
6225 Info_Mask = 0x02;
6226 break;
6227 case 10: /* charges */
6228 for(j=0;j<4;j++) charges[1+j] = 0;
6229 for(j=0; j<ie[0] && !(ie[1+j]&0x80); j++);
6230 for(k=1,j++; j<ie[0] && k<=4; j++,k++) charges[k] = ie[1+j];
6231 Info_Number = 0x4000;
6232 Info_Mask = 0x40;
6233 Info_Element = charges;
6234 break;
6235 case 11: /* user user info */
6236 dbug(1,dprintf("uui"));
6237 Info_Number = 0x007E;
6238 Info_Mask = 0x08;
6239 break;
6240 case 12: /* congestion receiver ready */
6241 dbug(1,dprintf("clRDY"));
6242 Info_Number = 0x00B0;
6243 Info_Mask = 0x08;
6244 Info_Element = "";
6245 break;
6246 case 13: /* congestion receiver not ready */
6247 dbug(1,dprintf("clNRDY"));
6248 Info_Number = 0x00BF;
6249 Info_Mask = 0x08;
6250 Info_Element = "";
6251 break;
6252 case 15: /* Keypad Facility */
6253 dbug(1,dprintf("KEY"));
6254 Info_Number = 0x002C;
6255 Info_Mask = 0x20;
6256 break;
6257 case 16: /* Channel Id */
6258 dbug(1,dprintf("CHI"));
6259 Info_Number = 0x0018;
6260 Info_Mask = 0x100;
6261 mixer_set_bchannel_id (plci, Info_Element);
6262 break;
6263 case 17: /* if no 1tr6 cause, send full cause, else esc_cause */
6264 dbug(1,dprintf("q9cau(0x%x)",ie[2]));
6265 if(!cause[2] || cause[2]<0x80) break; /* eg. layer 1 error */
6266 Info_Number = 0x0008;
6267 Info_Mask = 0x01;
6268 if(cause[2] != ie[2]) Info_Element = cause;
6269 break;
6270 case 19: /* Redirected Number */
6271 dbug(1,dprintf("RDN"));
6272 Info_Number = 0x0074;
6273 Info_Mask = 0x400;
6274 break;
6275 case 22: /* Redirecing Number */
6276 dbug(1,dprintf("RIN"));
6277 Info_Number = 0x0076;
6278 Info_Mask = 0x400;
6279 break;
6280 case 23: /* Notification Indicator */
6281 dbug(1,dprintf("NI"));
6282 Info_Number = (word)NI;
6283 Info_Mask = 0x210;
6284 break;
6285 case 26: /* Call State */
6286 dbug(1,dprintf("CST"));
6287 Info_Number = (word)CST;
6288 Info_Mask = 0x01; /* do with cause i.e. for now */
6289 break;
6290 case MAXPARMSIDS-2: /* Escape Message Type, must be the last indication */
6291 dbug(1,dprintf("ESC/MT[0x%x]",ie[3]));
6292 Info_Number = 0x8000 |ie[3];
6293 if(iesent) Info_Mask = 0xffff;
6294 else Info_Mask = 0x10;
6295 Info_Element = "";
6296 break;
6297 default:
6298 Info_Number = 0;
6299 Info_Mask = 0;
6300 Info_Element = "";
6301 break;
6302 }
6303 }
6304
6305 if(plci->Sig.Ind==NCR_FACILITY) /* check controller broadcast */
6306 {
6307 for(j=0; j<max_appl; j++)
6308 {
6309 appl = &application[j];
6310 if(Info_Number
6311 && appl->Id
6312 && plci->adapter->Info_Mask[appl->Id-1] &Info_Mask)
6313 {
6314 dbug(1,dprintf("NCR_Ind"));
6315 iesent=TRUE;
6316 sendf(&application[j],_INFO_I,Id&0x0f,0,"wS",Info_Number,Info_Element);
6317 }
6318 }
6319 }
6320 else if(!plci->appl)
6321 { /* overlap receiving broadcast */
6322 if(Info_Number==CPN
6323 || Info_Number==KEY
6324 || Info_Number==NI
6325 || Info_Number==DSP
6326 || Info_Number==UUI )
6327 {
6328 for(j=0; j<max_appl; j++)
6329 {
6330 if(test_c_ind_mask_bit (plci, j))
6331 {
6332 dbug(1,dprintf("Ovl_Ind"));
6333 iesent=TRUE;
6334 sendf(&application[j],_INFO_I,Id,0,"wS",Info_Number,Info_Element);
6335 }
6336 }
6337 }
6338 } /* all other signalling states */
6339 else if(Info_Number
6340 && plci->adapter->Info_Mask[plci->appl->Id-1] &Info_Mask)
6341 {
6342 dbug(1,dprintf("Std_Ind"));
6343 iesent=TRUE;
6344 sendf(plci->appl,_INFO_I,Id,0,"wS",Info_Number,Info_Element);
6345 }
6346 }
6347}
6348
6349
6350byte SendMultiIE(PLCI * plci, dword Id, byte * * parms, byte ie_type, dword info_mask, byte setupParse)
6351{
6352 word i;
6353 word j;
6354 byte * ie;
6355 word Info_Number;
6356 byte * Info_Element;
6357 APPL *appl;
6358 word Info_Mask = 0;
6359 byte iesent=0;
6360
6361 if(
6362 !plci->appl
6363 && !plci->State
6364 && plci->Sig.Ind!=NCR_FACILITY
6365 && !setupParse
6366 )
6367 {
6368 dbug(1,dprintf("NoM-IEParse "));
6369 return 0;
6370 }
6371 dbug(1,dprintf("M-IEParse "));
6372
6373 for(i=0; i<MAX_MULTI_IE; i++)
6374 {
6375 ie = parms[i];
6376 Info_Number = 0;
6377 Info_Element = ie;
6378 if(ie[0])
6379 {
6380 dbug(1,dprintf("[Ind0x%x]:IE=0x%x",plci->Sig.Ind,ie_type));
6381 Info_Number = (word)ie_type;
6382 Info_Mask = (word)info_mask;
6383 }
6384
6385 if(plci->Sig.Ind==NCR_FACILITY) /* check controller broadcast */
6386 {
6387 for(j=0; j<max_appl; j++)
6388 {
6389 appl = &application[j];
6390 if(Info_Number
6391 && appl->Id
6392 && plci->adapter->Info_Mask[appl->Id-1] &Info_Mask)
6393 {
6394 iesent = TRUE;
6395 dbug(1,dprintf("Mlt_NCR_Ind"));
6396 sendf(&application[j],_INFO_I,Id&0x0f,0,"wS",Info_Number,Info_Element);
6397 }
6398 }
6399 }
6400 else if(!plci->appl && Info_Number)
6401 { /* overlap receiving broadcast */
6402 for(j=0; j<max_appl; j++)
6403 {
6404 if(test_c_ind_mask_bit (plci, j))
6405 {
6406 iesent = TRUE;
6407 dbug(1,dprintf("Mlt_Ovl_Ind"));
6408 sendf(&application[j],_INFO_I,Id,0,"wS",Info_Number,Info_Element);
6409 }
6410 }
6411 } /* all other signalling states */
6412 else if(Info_Number
6413 && plci->adapter->Info_Mask[plci->appl->Id-1] &Info_Mask)
6414 {
6415 iesent = TRUE;
6416 dbug(1,dprintf("Mlt_Std_Ind"));
6417 sendf(plci->appl,_INFO_I,Id,0,"wS",Info_Number,Info_Element);
6418 }
6419 }
6420 return iesent;
6421}
6422
6423static void SendSSExtInd(APPL * appl, PLCI * plci, dword Id, byte * * parms)
6424{
6425 word i;
6426 /* Format of multi_ssext_parms[i][]:
6427 0 byte length
6428 1 byte SSEXTIE
6429 2 byte SSEXT_REQ/SSEXT_IND
6430 3 byte length
6431 4 word SSExtCommand
6432 6... Params
6433 */
6434 if(
6435 plci
6436 && plci->State
6437 && plci->Sig.Ind!=NCR_FACILITY
6438 )
6439 for(i=0;i<MAX_MULTI_IE;i++)
6440 {
6441 if(parms[i][0]<6) continue;
6442 if(parms[i][2]==SSEXT_REQ) continue;
6443
6444 if(appl)
6445 {
6446 parms[i][0]=0; /* kill it */
6447 sendf(appl,_MANUFACTURER_I,
6448 Id,
6449 0,
6450 "dwS",
6451 _DI_MANU_ID,
6452 _DI_SSEXT_CTRL,
6453 &parms[i][3]);
6454 }
6455 else if(plci->appl)
6456 {
6457 parms[i][0]=0; /* kill it */
6458 sendf(plci->appl,_MANUFACTURER_I,
6459 Id,
6460 0,
6461 "dwS",
6462 _DI_MANU_ID,
6463 _DI_SSEXT_CTRL,
6464 &parms[i][3]);
6465 }
6466 }
6467};
6468
6469void nl_ind(PLCI * plci)
6470{
6471 byte ch;
6472 word ncci;
6473 dword Id;
6474 DIVA_CAPI_ADAPTER * a;
6475 word NCCIcode;
6476 APPL * APPLptr;
6477 word count;
6478 word Num;
6479 word i, ncpi_state;
6480 byte len, ncci_state;
6481 word msg;
6482 word info = 0;
6483 word fax_feature_bits;
6484 byte fax_send_edata_ack;
6485 static byte v120_header_buffer[2 + 3];
6486 static word fax_info[] = {
6487 0, /* T30_SUCCESS */
6488 _FAX_NO_CONNECTION, /* T30_ERR_NO_DIS_RECEIVED */
6489 _FAX_PROTOCOL_ERROR, /* T30_ERR_TIMEOUT_NO_RESPONSE */
6490 _FAX_PROTOCOL_ERROR, /* T30_ERR_RETRY_NO_RESPONSE */
6491 _FAX_PROTOCOL_ERROR, /* T30_ERR_TOO_MANY_REPEATS */
6492 _FAX_PROTOCOL_ERROR, /* T30_ERR_UNEXPECTED_MESSAGE */
6493 _FAX_REMOTE_ABORT, /* T30_ERR_UNEXPECTED_DCN */
6494 _FAX_LOCAL_ABORT, /* T30_ERR_DTC_UNSUPPORTED */
6495 _FAX_TRAINING_ERROR, /* T30_ERR_ALL_RATES_FAILED */
6496 _FAX_TRAINING_ERROR, /* T30_ERR_TOO_MANY_TRAINS */
6497 _FAX_PARAMETER_ERROR, /* T30_ERR_RECEIVE_CORRUPTED */
6498 _FAX_REMOTE_ABORT, /* T30_ERR_UNEXPECTED_DISC */
6499 _FAX_LOCAL_ABORT, /* T30_ERR_APPLICATION_DISC */
6500 _FAX_REMOTE_REJECT, /* T30_ERR_INCOMPATIBLE_DIS */
6501 _FAX_LOCAL_ABORT, /* T30_ERR_INCOMPATIBLE_DCS */
6502 _FAX_PROTOCOL_ERROR, /* T30_ERR_TIMEOUT_NO_COMMAND */
6503 _FAX_PROTOCOL_ERROR, /* T30_ERR_RETRY_NO_COMMAND */
6504 _FAX_PROTOCOL_ERROR, /* T30_ERR_TIMEOUT_COMMAND_TOO_LONG */
6505 _FAX_PROTOCOL_ERROR, /* T30_ERR_TIMEOUT_RESPONSE_TOO_LONG */
6506 _FAX_NO_CONNECTION, /* T30_ERR_NOT_IDENTIFIED */
6507 _FAX_PROTOCOL_ERROR, /* T30_ERR_SUPERVISORY_TIMEOUT */
6508 _FAX_PARAMETER_ERROR, /* T30_ERR_TOO_LONG_SCAN_LINE */
6509 _FAX_PROTOCOL_ERROR, /* T30_ERR_RETRY_NO_PAGE_AFTER_MPS */
6510 _FAX_PROTOCOL_ERROR, /* T30_ERR_RETRY_NO_PAGE_AFTER_CFR */
6511 _FAX_PROTOCOL_ERROR, /* T30_ERR_RETRY_NO_DCS_AFTER_FTT */
6512 _FAX_PROTOCOL_ERROR, /* T30_ERR_RETRY_NO_DCS_AFTER_EOM */
6513 _FAX_PROTOCOL_ERROR, /* T30_ERR_RETRY_NO_DCS_AFTER_MPS */
6514 _FAX_PROTOCOL_ERROR, /* T30_ERR_RETRY_NO_DCN_AFTER_MCF */
6515 _FAX_PROTOCOL_ERROR, /* T30_ERR_RETRY_NO_DCN_AFTER_RTN */
6516 _FAX_PROTOCOL_ERROR, /* T30_ERR_RETRY_NO_CFR */
6517 _FAX_PROTOCOL_ERROR, /* T30_ERR_RETRY_NO_MCF_AFTER_EOP */
6518 _FAX_PROTOCOL_ERROR, /* T30_ERR_RETRY_NO_MCF_AFTER_EOM */
6519 _FAX_PROTOCOL_ERROR, /* T30_ERR_RETRY_NO_MCF_AFTER_MPS */
6520 0x331d, /* T30_ERR_SUB_SEP_UNSUPPORTED */
6521 0x331e, /* T30_ERR_PWD_UNSUPPORTED */
6522 0x331f, /* T30_ERR_SUB_SEP_PWD_UNSUPPORTED */
6523 _FAX_PROTOCOL_ERROR, /* T30_ERR_INVALID_COMMAND_FRAME */
6524 _FAX_PARAMETER_ERROR, /* T30_ERR_UNSUPPORTED_PAGE_CODING */
6525 _FAX_PARAMETER_ERROR, /* T30_ERR_INVALID_PAGE_CODING */
6526 _FAX_REMOTE_REJECT, /* T30_ERR_INCOMPATIBLE_PAGE_CONFIG */
6527 _FAX_LOCAL_ABORT, /* T30_ERR_TIMEOUT_FROM_APPLICATION */
6528 _FAX_PROTOCOL_ERROR, /* T30_ERR_V34FAX_NO_REACTION_ON_MARK */
6529 _FAX_PROTOCOL_ERROR, /* T30_ERR_V34FAX_TRAINING_TIMEOUT */
6530 _FAX_PROTOCOL_ERROR, /* T30_ERR_V34FAX_UNEXPECTED_V21 */
6531 _FAX_PROTOCOL_ERROR, /* T30_ERR_V34FAX_PRIMARY_CTS_ON */
6532 _FAX_LOCAL_ABORT, /* T30_ERR_V34FAX_TURNAROUND_POLLING */
6533 _FAX_LOCAL_ABORT /* T30_ERR_V34FAX_V8_INCOMPATIBILITY */
6534 };
6535
6536 byte dtmf_code_buffer[CAPIDTMF_RECV_DIGIT_BUFFER_SIZE + 1];
6537
6538
6539 static word rtp_info[] = {
6540 GOOD, /* RTP_SUCCESS */
6541 0x3600 /* RTP_ERR_SSRC_OR_PAYLOAD_CHANGE */
6542 };
6543
6544 static dword udata_forwarding_table[0x100 / sizeof(dword)] =
6545 {
6546 0x0020301e, 0x00000000, 0x00000000, 0x00000000,
6547 0x00000000, 0x00000000, 0x00000000, 0x00000000
6548 };
6549
6550 ch = plci->NL.IndCh;
6551 a = plci->adapter;
6552 ncci = a->ch_ncci[ch];
6553 Id = (((dword)(ncci ? ncci : ch)) << 16) | (((word) plci->Id) << 8) | a->Id;
6554 if(plci->tel) Id|=EXT_CONTROLLER;
6555 APPLptr = plci->appl;
6556 dbug(1,dprintf("NL_IND-Id(NL:0x%x)=0x%08lx,plci=%x,tel=%x,state=0x%x,ch=0x%x,chs=%d,Ind=%x",
6557 plci->NL.Id,Id,plci->Id,plci->tel,plci->State,ch,plci->channels,plci->NL.Ind &0x0f));
6558
6559 /* in the case if no connect_active_Ind was sent to the appl we wait for */
6560
6561 if (plci->nl_remove_id)
6562 {
6563 plci->NL.RNR = 2; /* discard */
6564 dbug(1,dprintf("NL discard while remove pending"));
6565 return;
6566 }
6567 if((plci->NL.Ind &0x0f)==N_CONNECT)
6568 {
6569 if(plci->State==INC_DIS_PENDING
6570 || plci->State==OUTG_DIS_PENDING
6571 || plci->State==IDLE)
6572 {
6573 plci->NL.RNR = 2; /* discard */
6574 dbug(1,dprintf("discard n_connect"));
6575 return;
6576 }
6577 if(plci->State < INC_ACT_PENDING)
6578 {
6579 plci->NL.RNR = 1; /* flow control */
6580 channel_x_off (plci, ch, N_XON_CONNECT_IND);
6581 return;
6582 }
6583 }
6584
6585 if(!APPLptr) /* no application or invalid data */
6586 { /* while reloading the DSP */
6587 dbug(1,dprintf("discard1"));
6588 plci->NL.RNR = 2;
6589 return;
6590 }
6591
6592 if (((plci->NL.Ind &0x0f) == N_UDATA)
6593 && (((plci->B2_prot != B2_SDLC) && ((plci->B1_resource == 17) || (plci->B1_resource == 18)))
6594 || (plci->B2_prot == 7)
6595 || (plci->B3_prot == 7)) )
6596 {
6597 plci->ncpi_buffer[0] = 0;
6598
6599 ncpi_state = plci->ncpi_state;
6600 if (plci->NL.complete == 1)
6601 {
6602 byte * data = &plci->NL.RBuffer->P[0];
6603
6604 if ((plci->NL.RBuffer->length >= 12)
6605 &&( (*data == DSP_UDATA_INDICATION_DCD_ON)
6606 ||(*data == DSP_UDATA_INDICATION_CTS_ON)) )
6607 {
6608 word conn_opt, ncpi_opt = 0x00;
6609/* HexDump ("MDM N_UDATA:", plci->NL.RBuffer->length, data); */
6610
6611 if (*data == DSP_UDATA_INDICATION_DCD_ON)
6612 plci->ncpi_state |= NCPI_MDM_DCD_ON_RECEIVED;
6613 if (*data == DSP_UDATA_INDICATION_CTS_ON)
6614 plci->ncpi_state |= NCPI_MDM_CTS_ON_RECEIVED;
6615
6616 data++; /* indication code */
6617 data += 2; /* timestamp */
6618 if ((*data == DSP_CONNECTED_NORM_V18) || (*data == DSP_CONNECTED_NORM_VOWN))
6619 ncpi_state &= ~(NCPI_MDM_DCD_ON_RECEIVED | NCPI_MDM_CTS_ON_RECEIVED);
6620 data++; /* connected norm */
6621 conn_opt = GET_WORD(data);
6622 data += 2; /* connected options */
6623
6624 PUT_WORD (&(plci->ncpi_buffer[1]), (word)(GET_DWORD(data) & 0x0000FFFF));
6625
6626 if (conn_opt & DSP_CONNECTED_OPTION_MASK_V42)
6627 {
6628 ncpi_opt |= MDM_NCPI_ECM_V42;
6629 }
6630 else if (conn_opt & DSP_CONNECTED_OPTION_MASK_MNP)
6631 {
6632 ncpi_opt |= MDM_NCPI_ECM_MNP;
6633 }
6634 else
6635 {
6636 ncpi_opt |= MDM_NCPI_TRANSPARENT;
6637 }
6638 if (conn_opt & DSP_CONNECTED_OPTION_MASK_COMPRESSION)
6639 {
6640 ncpi_opt |= MDM_NCPI_COMPRESSED;
6641 }
6642 PUT_WORD (&(plci->ncpi_buffer[3]), ncpi_opt);
6643 plci->ncpi_buffer[0] = 4;
6644
6645 plci->ncpi_state |= NCPI_VALID_CONNECT_B3_IND | NCPI_VALID_CONNECT_B3_ACT | NCPI_VALID_DISC_B3_IND;
6646 }
6647 }
6648 if (plci->B3_prot == 7)
6649 {
6650 if (((a->ncci_state[ncci] == INC_ACT_PENDING) || (a->ncci_state[ncci] == OUTG_CON_PENDING))
6651 && (plci->ncpi_state & NCPI_VALID_CONNECT_B3_ACT)
6652 && !(plci->ncpi_state & NCPI_CONNECT_B3_ACT_SENT))
6653 {
6654 a->ncci_state[ncci] = INC_ACT_PENDING;
6655 sendf(plci->appl,_CONNECT_B3_ACTIVE_I,Id,0,"S",plci->ncpi_buffer);
6656 plci->ncpi_state |= NCPI_CONNECT_B3_ACT_SENT;
6657 }
6658 }
6659
6660 if (!((plci->requested_options_conn | plci->requested_options | plci->adapter->requested_options_table[plci->appl->Id-1])
6661 & ((1L << PRIVATE_V18) | (1L << PRIVATE_VOWN)))
6662 || !(ncpi_state & NCPI_MDM_DCD_ON_RECEIVED)
6663 || !(ncpi_state & NCPI_MDM_CTS_ON_RECEIVED))
6664
6665 {
6666 plci->NL.RNR = 2;
6667 return;
6668 }
6669 }
6670
6671 if(plci->NL.complete == 2)
6672 {
6673 if (((plci->NL.Ind &0x0f) == N_UDATA)
6674 && !(udata_forwarding_table[plci->RData[0].P[0] >> 5] & (1L << (plci->RData[0].P[0] & 0x1f))))
6675 {
6676 switch(plci->RData[0].P[0])
6677 {
6678
6679 case DTMF_UDATA_INDICATION_FAX_CALLING_TONE:
6680 if (plci->dtmf_rec_active & DTMF_LISTEN_ACTIVE_FLAG)
6681 sendf(plci->appl, _FACILITY_I, Id & 0xffffL, 0,"ws", SELECTOR_DTMF, "\x01X");
6682 break;
6683 case DTMF_UDATA_INDICATION_ANSWER_TONE:
6684 if (plci->dtmf_rec_active & DTMF_LISTEN_ACTIVE_FLAG)
6685 sendf(plci->appl, _FACILITY_I, Id & 0xffffL, 0,"ws", SELECTOR_DTMF, "\x01Y");
6686 break;
6687 case DTMF_UDATA_INDICATION_DIGITS_RECEIVED:
6688 dtmf_indication (Id, plci, plci->RData[0].P, plci->RData[0].PLength);
6689 break;
6690 case DTMF_UDATA_INDICATION_DIGITS_SENT:
6691 dtmf_confirmation (Id, plci);
6692 break;
6693
6694
6695 case UDATA_INDICATION_MIXER_TAP_DATA:
6696 capidtmf_recv_process_block (&(plci->capidtmf_state), plci->RData[0].P + 1, (word)(plci->RData[0].PLength - 1));
6697 i = capidtmf_indication (&(plci->capidtmf_state), dtmf_code_buffer + 1);
6698 if (i != 0)
6699 {
6700 dtmf_code_buffer[0] = DTMF_UDATA_INDICATION_DIGITS_RECEIVED;
6701 dtmf_indication (Id, plci, dtmf_code_buffer, (word)(i + 1));
6702 }
6703 break;
6704
6705
6706 case UDATA_INDICATION_MIXER_COEFS_SET:
6707 mixer_indication_coefs_set (Id, plci);
6708 break;
6709 case UDATA_INDICATION_XCONNECT_FROM:
6710 mixer_indication_xconnect_from (Id, plci, plci->RData[0].P, plci->RData[0].PLength);
6711 break;
6712 case UDATA_INDICATION_XCONNECT_TO:
6713 mixer_indication_xconnect_to (Id, plci, plci->RData[0].P, plci->RData[0].PLength);
6714 break;
6715
6716
6717 case LEC_UDATA_INDICATION_DISABLE_DETECT:
6718 ec_indication (Id, plci, plci->RData[0].P, plci->RData[0].PLength);
6719 break;
6720
6721
6722
6723 default:
6724 break;
6725 }
6726 }
6727 else
6728 {
6729 if ((plci->RData[0].PLength != 0)
6730 && ((plci->B2_prot == B2_V120_ASYNC)
6731 || (plci->B2_prot == B2_V120_ASYNC_V42BIS)
6732 || (plci->B2_prot == B2_V120_BIT_TRANSPARENT)))
6733 {
6734
6735 sendf(plci->appl,_DATA_B3_I,Id,0,
6736 "dwww",
6737 plci->RData[1].P,
6738 (plci->NL.RNum < 2) ? 0 : plci->RData[1].PLength,
6739 plci->RNum,
6740 plci->RFlags);
6741
6742 }
6743 else
6744 {
6745
6746 sendf(plci->appl,_DATA_B3_I,Id,0,
6747 "dwww",
6748 plci->RData[0].P,
6749 plci->RData[0].PLength,
6750 plci->RNum,
6751 plci->RFlags);
6752
6753 }
6754 }
6755 return;
6756 }
6757
6758 fax_feature_bits = 0;
6759 if((plci->NL.Ind &0x0f)==N_CONNECT ||
6760 (plci->NL.Ind &0x0f)==N_CONNECT_ACK ||
6761 (plci->NL.Ind &0x0f)==N_DISC ||
6762 (plci->NL.Ind &0x0f)==N_EDATA ||
6763 (plci->NL.Ind &0x0f)==N_DISC_ACK)
6764 {
6765 info = 0;
6766 plci->ncpi_buffer[0] = 0;
6767 switch (plci->B3_prot) {
6768 case 0: /*XPARENT*/
6769 case 1: /*T.90 NL*/
6770 break; /* no network control protocol info - jfr */
6771 case 2: /*ISO8202*/
6772 case 3: /*X25 DCE*/
6773 for(i=0; i<plci->NL.RLength; i++) plci->ncpi_buffer[4+i] = plci->NL.RBuffer->P[i];
6774 plci->ncpi_buffer[0] = (byte)(i+3);
6775 plci->ncpi_buffer[1] = (byte)(plci->NL.Ind &N_D_BIT? 1:0);
6776 plci->ncpi_buffer[2] = 0;
6777 plci->ncpi_buffer[3] = 0;
6778 break;
6779 case 4: /*T.30 - FAX*/
6780 case 5: /*T.30 - FAX*/
6781 if(plci->NL.RLength>=sizeof(T30_INFO))
6782 {
6783 dbug(1,dprintf("FaxStatus %04x", ((T30_INFO *)plci->NL.RBuffer->P)->code));
6784 len = 9;
6785 PUT_WORD(&(plci->ncpi_buffer[1]),((T30_INFO *)plci->NL.RBuffer->P)->rate_div_2400 * 2400);
6786 fax_feature_bits = GET_WORD(&((T30_INFO *)plci->NL.RBuffer->P)->feature_bits_low);
6787 i = (((T30_INFO *)plci->NL.RBuffer->P)->resolution & T30_RESOLUTION_R8_0770_OR_200) ? 0x0001 : 0x0000;
6788 if (plci->B3_prot == 5)
6789 {
6790 if (!(fax_feature_bits & T30_FEATURE_BIT_ECM))
6791 i |= 0x8000; /* This is not an ECM connection */
6792 if (fax_feature_bits & T30_FEATURE_BIT_T6_CODING)
6793 i |= 0x4000; /* This is a connection with MMR compression */
6794 if (fax_feature_bits & T30_FEATURE_BIT_2D_CODING)
6795 i |= 0x2000; /* This is a connection with MR compression */
6796 if (fax_feature_bits & T30_FEATURE_BIT_MORE_DOCUMENTS)
6797 i |= 0x0004; /* More documents */
6798 if (fax_feature_bits & T30_FEATURE_BIT_POLLING)
6799 i |= 0x0002; /* Fax-polling indication */
6800 }
6801 dbug(1,dprintf("FAX Options %04x %04x",fax_feature_bits,i));
6802 PUT_WORD(&(plci->ncpi_buffer[3]),i);
6803 PUT_WORD(&(plci->ncpi_buffer[5]),((T30_INFO *)plci->NL.RBuffer->P)->data_format);
6804 plci->ncpi_buffer[7] = ((T30_INFO *)plci->NL.RBuffer->P)->pages_low;
6805 plci->ncpi_buffer[8] = ((T30_INFO *)plci->NL.RBuffer->P)->pages_high;
6806 plci->ncpi_buffer[len] = 0;
6807 if(((T30_INFO *)plci->NL.RBuffer->P)->station_id_len)
6808 {
6809 plci->ncpi_buffer[len] = 20;
6810 for (i = 0; i < 20; i++)
6811 plci->ncpi_buffer[++len] = ((T30_INFO *)plci->NL.RBuffer->P)->station_id[i];
6812 }
6813 if (((plci->NL.Ind & 0x0f) == N_DISC) || ((plci->NL.Ind & 0x0f) == N_DISC_ACK))
6814 {
6815 if (((T30_INFO *)plci->NL.RBuffer->P)->code < sizeof(fax_info) / sizeof(fax_info[0]))
6816 info = fax_info[((T30_INFO *)plci->NL.RBuffer->P)->code];
6817 else
6818 info = _FAX_PROTOCOL_ERROR;
6819 }
6820
6821 if ((plci->requested_options_conn | plci->requested_options | a->requested_options_table[plci->appl->Id-1])
6822 & ((1L << PRIVATE_FAX_SUB_SEP_PWD) | (1L << PRIVATE_FAX_NONSTANDARD)))
6823 {
6824 i = ((word)(((T30_INFO *) 0)->station_id + 20)) + ((T30_INFO *)plci->NL.RBuffer->P)->head_line_len;
6825 while (i < plci->NL.RBuffer->length)
6826 plci->ncpi_buffer[++len] = plci->NL.RBuffer->P[i++];
6827 }
6828
6829 plci->ncpi_buffer[0] = len;
6830 fax_feature_bits = GET_WORD(&((T30_INFO *)plci->NL.RBuffer->P)->feature_bits_low);
6831 PUT_WORD(&((T30_INFO *)plci->fax_connect_info_buffer)->feature_bits_low, fax_feature_bits);
6832
6833 plci->ncpi_state |= NCPI_VALID_CONNECT_B3_IND;
6834 if (((plci->NL.Ind &0x0f) == N_CONNECT_ACK)
6835 || (((plci->NL.Ind &0x0f) == N_CONNECT)
6836 && (fax_feature_bits & T30_FEATURE_BIT_POLLING))
6837 || (((plci->NL.Ind &0x0f) == N_EDATA)
6838 && ((((T30_INFO *)plci->NL.RBuffer->P)->code == EDATA_T30_TRAIN_OK)
6839 || (((T30_INFO *)plci->NL.RBuffer->P)->code == EDATA_T30_DIS)
6840 || (((T30_INFO *)plci->NL.RBuffer->P)->code == EDATA_T30_DTC))))
6841 {
6842 plci->ncpi_state |= NCPI_VALID_CONNECT_B3_ACT;
6843 }
6844 if (((plci->NL.Ind &0x0f) == N_DISC)
6845 || ((plci->NL.Ind &0x0f) == N_DISC_ACK)
6846 || (((plci->NL.Ind &0x0f) == N_EDATA)
6847 && (((T30_INFO *)plci->NL.RBuffer->P)->code == EDATA_T30_EOP_CAPI)))
6848 {
6849 plci->ncpi_state |= NCPI_VALID_CONNECT_B3_ACT | NCPI_VALID_DISC_B3_IND;
6850 }
6851 }
6852 break;
6853
6854 case B3_RTP:
6855 if (((plci->NL.Ind & 0x0f) == N_DISC) || ((plci->NL.Ind & 0x0f) == N_DISC_ACK))
6856 {
6857 if (plci->NL.RLength != 0)
6858 {
6859 info = rtp_info[plci->NL.RBuffer->P[0]];
6860 plci->ncpi_buffer[0] = plci->NL.RLength - 1;
6861 for (i = 1; i < plci->NL.RLength; i++)
6862 plci->ncpi_buffer[i] = plci->NL.RBuffer->P[i];
6863 }
6864 }
6865 break;
6866
6867 }
6868 plci->NL.RNR = 2;
6869 }
6870 switch(plci->NL.Ind &0x0f) {
6871 case N_EDATA:
6872 if ((plci->B3_prot == 4) || (plci->B3_prot == 5))
6873 {
6874 dbug(1,dprintf("EDATA ncci=0x%x state=%d code=%02x", ncci, a->ncci_state[ncci],
6875 ((T30_INFO *)plci->NL.RBuffer->P)->code));
6876 fax_send_edata_ack = (((T30_INFO *)(plci->fax_connect_info_buffer))->operating_mode == T30_OPERATING_MODE_CAPI_NEG);
6877
6878 if ((plci->nsf_control_bits & T30_NSF_CONTROL_BIT_ENABLE_NSF)
6879 && (plci->nsf_control_bits & (T30_NSF_CONTROL_BIT_NEGOTIATE_IND | T30_NSF_CONTROL_BIT_NEGOTIATE_RESP))
6880 && (((T30_INFO *)plci->NL.RBuffer->P)->code == EDATA_T30_DIS)
6881 && (a->ncci_state[ncci] == OUTG_CON_PENDING)
6882 && (plci->ncpi_state & NCPI_VALID_CONNECT_B3_ACT)
6883 && !(plci->ncpi_state & NCPI_NEGOTIATE_B3_SENT))
6884 {
6885 ((T30_INFO *)(plci->fax_connect_info_buffer))->code = ((T30_INFO *)plci->NL.RBuffer->P)->code;
6886 sendf(plci->appl,_MANUFACTURER_I,Id,0,"dwbS",_DI_MANU_ID,_DI_NEGOTIATE_B3,
6887 (byte)(plci->ncpi_buffer[0] + 1), plci->ncpi_buffer);
6888 plci->ncpi_state |= NCPI_NEGOTIATE_B3_SENT;
6889 if (plci->nsf_control_bits & T30_NSF_CONTROL_BIT_NEGOTIATE_RESP)
6890 fax_send_edata_ack = FALSE;
6891 }
6892
6893 if (a->manufacturer_features & MANUFACTURER_FEATURE_FAX_PAPER_FORMATS)
6894 {
6895 switch (((T30_INFO *)plci->NL.RBuffer->P)->code)
6896 {
6897 case EDATA_T30_DIS:
6898 if ((a->ncci_state[ncci] == OUTG_CON_PENDING)
6899 && !(GET_WORD(&((T30_INFO *)plci->fax_connect_info_buffer)->control_bits_low) & T30_CONTROL_BIT_REQUEST_POLLING)
6900 && (plci->ncpi_state & NCPI_VALID_CONNECT_B3_ACT)
6901 && !(plci->ncpi_state & NCPI_CONNECT_B3_ACT_SENT))
6902 {
6903 a->ncci_state[ncci] = INC_ACT_PENDING;
6904 if (plci->B3_prot == 4)
6905 sendf(plci->appl,_CONNECT_B3_ACTIVE_I,Id,0,"s","");
6906 else
6907 sendf(plci->appl,_CONNECT_B3_ACTIVE_I,Id,0,"S",plci->ncpi_buffer);
6908 plci->ncpi_state |= NCPI_CONNECT_B3_ACT_SENT;
6909 }
6910 break;
6911
6912 case EDATA_T30_TRAIN_OK:
6913 if ((a->ncci_state[ncci] == INC_ACT_PENDING)
6914 && (plci->ncpi_state & NCPI_VALID_CONNECT_B3_ACT)
6915 && !(plci->ncpi_state & NCPI_CONNECT_B3_ACT_SENT))
6916 {
6917 if (plci->B3_prot == 4)
6918 sendf(plci->appl,_CONNECT_B3_ACTIVE_I,Id,0,"s","");
6919 else
6920 sendf(plci->appl,_CONNECT_B3_ACTIVE_I,Id,0,"S",plci->ncpi_buffer);
6921 plci->ncpi_state |= NCPI_CONNECT_B3_ACT_SENT;
6922 }
6923 break;
6924
6925 case EDATA_T30_EOP_CAPI:
6926 if (a->ncci_state[ncci] == CONNECTED)
6927 {
6928 sendf(plci->appl,_DISCONNECT_B3_I,Id,0,"wS",GOOD,plci->ncpi_buffer);
6929 a->ncci_state[ncci] = INC_DIS_PENDING;
6930 plci->ncpi_state = 0;
6931 fax_send_edata_ack = FALSE;
6932 }
6933 break;
6934 }
6935 }
6936 else
6937 {
6938 switch (((T30_INFO *)plci->NL.RBuffer->P)->code)
6939 {
6940 case EDATA_T30_TRAIN_OK:
6941 if ((a->ncci_state[ncci] == INC_ACT_PENDING)
6942 && (plci->ncpi_state & NCPI_VALID_CONNECT_B3_ACT)
6943 && !(plci->ncpi_state & NCPI_CONNECT_B3_ACT_SENT))
6944 {
6945 if (plci->B3_prot == 4)
6946 sendf(plci->appl,_CONNECT_B3_ACTIVE_I,Id,0,"s","");
6947 else
6948 sendf(plci->appl,_CONNECT_B3_ACTIVE_I,Id,0,"S",plci->ncpi_buffer);
6949 plci->ncpi_state |= NCPI_CONNECT_B3_ACT_SENT;
6950 }
6951 break;
6952 }
6953 }
6954 if (fax_send_edata_ack)
6955 {
6956 ((T30_INFO *)(plci->fax_connect_info_buffer))->code = ((T30_INFO *)plci->NL.RBuffer->P)->code;
6957 plci->fax_edata_ack_length = 1;
6958 start_internal_command (Id, plci, fax_edata_ack_command);
6959 }
6960 }
6961 else
6962 {
6963 dbug(1,dprintf("EDATA ncci=0x%x state=%d", ncci, a->ncci_state[ncci]));
6964 }
6965 break;
6966 case N_CONNECT:
6967 if (!a->ch_ncci[ch])
6968 {
6969 ncci = get_ncci (plci, ch, 0);
6970 Id = (Id & 0xffff) | (((dword) ncci) << 16);
6971 }
6972 dbug(1,dprintf("N_CONNECT: ch=%d state=%d plci=%lx plci_Id=%lx plci_State=%d",
6973 ch, a->ncci_state[ncci], a->ncci_plci[ncci], plci->Id, plci->State));
6974
6975 msg = _CONNECT_B3_I;
6976 if (a->ncci_state[ncci] == IDLE)
6977 plci->channels++;
6978 else if (plci->B3_prot == 1)
6979 msg = _CONNECT_B3_T90_ACTIVE_I;
6980
6981 a->ncci_state[ncci] = INC_CON_PENDING;
6982 if(plci->B3_prot == 4)
6983 sendf(plci->appl,msg,Id,0,"s","");
6984 else
6985 sendf(plci->appl,msg,Id,0,"S",plci->ncpi_buffer);
6986 break;
6987 case N_CONNECT_ACK:
6988 dbug(1,dprintf("N_connect_Ack"));
6989 if (plci->internal_command_queue[0]
6990 && ((plci->adjust_b_state == ADJUST_B_CONNECT_2)
6991 || (plci->adjust_b_state == ADJUST_B_CONNECT_3)
6992 || (plci->adjust_b_state == ADJUST_B_CONNECT_4)))
6993 {
6994 (*(plci->internal_command_queue[0]))(Id, plci, 0);
6995 if (!plci->internal_command)
6996 next_internal_command (Id, plci);
6997 break;
6998 }
6999 msg = _CONNECT_B3_ACTIVE_I;
7000 if (plci->B3_prot == 1)
7001 {
7002 if (a->ncci_state[ncci] != OUTG_CON_PENDING)
7003 msg = _CONNECT_B3_T90_ACTIVE_I;
7004 a->ncci_state[ncci] = INC_ACT_PENDING;
7005 sendf(plci->appl,msg,Id,0,"S",plci->ncpi_buffer);
7006 }
7007 else if ((plci->B3_prot == 4) || (plci->B3_prot == 5) || (plci->B3_prot == 7))
7008 {
7009 if ((a->ncci_state[ncci] == OUTG_CON_PENDING)
7010 && (plci->ncpi_state & NCPI_VALID_CONNECT_B3_ACT)
7011 && !(plci->ncpi_state & NCPI_CONNECT_B3_ACT_SENT))
7012 {
7013 a->ncci_state[ncci] = INC_ACT_PENDING;
7014 if (plci->B3_prot == 4)
7015 sendf(plci->appl,msg,Id,0,"s","");
7016 else
7017 sendf(plci->appl,msg,Id,0,"S",plci->ncpi_buffer);
7018 plci->ncpi_state |= NCPI_CONNECT_B3_ACT_SENT;
7019 }
7020 }
7021 else
7022 {
7023 a->ncci_state[ncci] = INC_ACT_PENDING;
7024 sendf(plci->appl,msg,Id,0,"S",plci->ncpi_buffer);
7025 }
7026 if (plci->adjust_b_restore)
7027 {
7028 plci->adjust_b_restore = FALSE;
7029 start_internal_command (Id, plci, adjust_b_restore);
7030 }
7031 break;
7032 case N_DISC:
7033 case N_DISC_ACK:
7034 if (plci->internal_command_queue[0]
7035 && ((plci->internal_command == FAX_DISCONNECT_COMMAND_1)
7036 || (plci->internal_command == FAX_DISCONNECT_COMMAND_2)
7037 || (plci->internal_command == FAX_DISCONNECT_COMMAND_3)))
7038 {
7039 (*(plci->internal_command_queue[0]))(Id, plci, 0);
7040 if (!plci->internal_command)
7041 next_internal_command (Id, plci);
7042 }
7043 ncci_state = a->ncci_state[ncci];
7044 ncci_remove (plci, ncci, FALSE);
7045
7046 /* with N_DISC or N_DISC_ACK the IDI frees the respective */
7047 /* channel, so we cannot store the state in ncci_state! The */
7048 /* information which channel we received a N_DISC is thus */
7049 /* stored in the inc_dis_ncci_table buffer. */
7050 for(i=0; plci->inc_dis_ncci_table[i]; i++);
7051 plci->inc_dis_ncci_table[i] = (byte) ncci;
7052
7053 /* need a connect_b3_ind before a disconnect_b3_ind with FAX */
7054 if (!plci->channels
7055 && (plci->B1_resource == 16)
7056 && (plci->State <= CONNECTED))
7057 {
7058 len = 9;
7059 i = ((T30_INFO *)plci->fax_connect_info_buffer)->rate_div_2400 * 2400;
7060 PUT_WORD (&plci->ncpi_buffer[1], i);
7061 PUT_WORD (&plci->ncpi_buffer[3], 0);
7062 i = ((T30_INFO *)plci->fax_connect_info_buffer)->data_format;
7063 PUT_WORD (&plci->ncpi_buffer[5], i);
7064 PUT_WORD (&plci->ncpi_buffer[7], 0);
7065 plci->ncpi_buffer[len] = 0;
7066 plci->ncpi_buffer[0] = len;
7067 if(plci->B3_prot == 4)
7068 sendf(plci->appl,_CONNECT_B3_I,Id,0,"s","");
7069 else
7070 {
7071
7072 if ((plci->requested_options_conn | plci->requested_options | a->requested_options_table[plci->appl->Id-1])
7073 & ((1L << PRIVATE_FAX_SUB_SEP_PWD) | (1L << PRIVATE_FAX_NONSTANDARD)))
7074 {
7075 plci->ncpi_buffer[++len] = 0;
7076 plci->ncpi_buffer[++len] = 0;
7077 plci->ncpi_buffer[++len] = 0;
7078 plci->ncpi_buffer[0] = len;
7079 }
7080
7081 sendf(plci->appl,_CONNECT_B3_I,Id,0,"S",plci->ncpi_buffer);
7082 }
7083 sendf(plci->appl,_DISCONNECT_B3_I,Id,0,"wS",info,plci->ncpi_buffer);
7084 plci->ncpi_state = 0;
7085 sig_req(plci,HANGUP,0);
7086 send_req(plci);
7087 plci->State = OUTG_DIS_PENDING;
7088 /* disc here */
7089 }
7090 else if ((a->manufacturer_features & MANUFACTURER_FEATURE_FAX_PAPER_FORMATS)
7091 && ((plci->B3_prot == 4) || (plci->B3_prot == 5))
7092 && ((ncci_state == INC_DIS_PENDING) || (ncci_state == IDLE)))
7093 {
7094 if (ncci_state == IDLE)
7095 {
7096 if (plci->channels)
7097 plci->channels--;
7098 if((plci->State==IDLE || plci->State==SUSPENDING) && !plci->channels){
7099 if(plci->State == SUSPENDING){
7100 sendf(plci->appl,
7101 _FACILITY_I,
7102 Id & 0xffffL,
7103 0,
7104 "ws", (word)3, "\x03\x04\x00\x00");
7105 sendf(plci->appl, _DISCONNECT_I, Id & 0xffffL, 0, "w", 0);
7106 }
7107 plci_remove(plci);
7108 plci->State=IDLE;
7109 }
7110 }
7111 }
7112 else if (plci->channels)
7113 {
7114 sendf(plci->appl,_DISCONNECT_B3_I,Id,0,"wS",info,plci->ncpi_buffer);
7115 plci->ncpi_state = 0;
7116 if ((ncci_state == OUTG_REJ_PENDING)
7117 && ((plci->B3_prot != B3_T90NL) && (plci->B3_prot != B3_ISO8208) && (plci->B3_prot != B3_X25_DCE)))
7118 {
7119 sig_req(plci,HANGUP,0);
7120 send_req(plci);
7121 plci->State = OUTG_DIS_PENDING;
7122 }
7123 }
7124 break;
7125 case N_RESET:
7126 a->ncci_state[ncci] = INC_RES_PENDING;
7127 sendf(plci->appl,_RESET_B3_I,Id,0,"S",plci->ncpi_buffer);
7128 break;
7129 case N_RESET_ACK:
7130 a->ncci_state[ncci] = CONNECTED;
7131 sendf(plci->appl,_RESET_B3_I,Id,0,"S",plci->ncpi_buffer);
7132 break;
7133
7134 case N_UDATA:
7135 if (!(udata_forwarding_table[plci->NL.RBuffer->P[0] >> 5] & (1L << (plci->NL.RBuffer->P[0] & 0x1f))))
7136 {
7137 plci->RData[0].P = plci->internal_ind_buffer + (-((int)(plci->internal_ind_buffer)) & 3);
7138 plci->RData[0].PLength = INTERNAL_IND_BUFFER_SIZE;
7139 plci->NL.R = plci->RData;
7140 plci->NL.RNum = 1;
7141 return;
7142 }
7143 case N_BDATA:
7144 case N_DATA:
7145 if (((a->ncci_state[ncci] != CONNECTED) && (plci->B2_prot == 1)) /* transparent */
7146 || (a->ncci_state[ncci] == IDLE)
7147 || (a->ncci_state[ncci] == INC_DIS_PENDING))
7148 {
7149 plci->NL.RNR = 2;
7150 break;
7151 }
7152 if ((a->ncci_state[ncci] != CONNECTED)
7153 && (a->ncci_state[ncci] != OUTG_DIS_PENDING)
7154 && (a->ncci_state[ncci] != OUTG_REJ_PENDING))
7155 {
7156 dbug(1,dprintf("flow control"));
7157 plci->NL.RNR = 1; /* flow control */
7158 channel_x_off (plci, ch, 0);
7159 break;
7160 }
7161
7162 NCCIcode = ncci | (((word)a->Id) << 8);
7163
7164 /* count all buffers within the Application pool */
7165 /* belonging to the same NCCI. If this is below the */
7166 /* number of buffers available per NCCI we accept */
7167 /* this packet, otherwise we reject it */
7168 count = 0;
7169 Num = 0xffff;
7170 for(i=0; i<APPLptr->MaxBuffer; i++) {
7171 if(NCCIcode==APPLptr->DataNCCI[i]) count++;
7172 if(!APPLptr->DataNCCI[i] && Num==0xffff) Num = i;
7173 }
7174
7175 if(count>=APPLptr->MaxNCCIData || Num==0xffff)
7176 {
7177 dbug(3,dprintf("Flow-Control"));
7178 plci->NL.RNR = 1;
7179 if( ++(APPLptr->NCCIDataFlowCtrlTimer)>=
7180 (word)((a->manufacturer_features & MANUFACTURER_FEATURE_OOB_CHANNEL) ? 40 : 2000))
7181 {
7182 plci->NL.RNR = 2;
7183 dbug(3,dprintf("DiscardData"));
7184 } else {
7185 channel_x_off (plci, ch, 0);
7186 }
7187 break;
7188 }
7189 else
7190 {
7191 APPLptr->NCCIDataFlowCtrlTimer = 0;
7192 }
7193
7194 plci->RData[0].P = ReceiveBufferGet(APPLptr,Num);
7195 if(!plci->RData[0].P) {
7196 plci->NL.RNR = 1;
7197 channel_x_off (plci, ch, 0);
7198 break;
7199 }
7200
7201 APPLptr->DataNCCI[Num] = NCCIcode;
7202 APPLptr->DataFlags[Num] = (plci->Id<<8) | (plci->NL.Ind>>4);
7203 dbug(3,dprintf("Buffer(%d), Max = %d",Num,APPLptr->MaxBuffer));
7204
7205 plci->RNum = Num;
7206 plci->RFlags = plci->NL.Ind>>4;
7207 plci->RData[0].PLength = APPLptr->MaxDataLength;
7208 plci->NL.R = plci->RData;
7209 if ((plci->NL.RLength != 0)
7210 && ((plci->B2_prot == B2_V120_ASYNC)
7211 || (plci->B2_prot == B2_V120_ASYNC_V42BIS)
7212 || (plci->B2_prot == B2_V120_BIT_TRANSPARENT)))
7213 {
7214 plci->RData[1].P = plci->RData[0].P;
7215 plci->RData[1].PLength = plci->RData[0].PLength;
7216 plci->RData[0].P = v120_header_buffer + (-((int) v120_header_buffer) & 3);
7217 if ((plci->NL.RBuffer->P[0] & V120_HEADER_EXTEND_BIT) || (plci->NL.RLength == 1))
7218 plci->RData[0].PLength = 1;
7219 else
7220 plci->RData[0].PLength = 2;
7221 if (plci->NL.RBuffer->P[0] & V120_HEADER_BREAK_BIT)
7222 plci->RFlags |= 0x0010;
7223 if (plci->NL.RBuffer->P[0] & (V120_HEADER_C1_BIT | V120_HEADER_C2_BIT))
7224 plci->RFlags |= 0x8000;
7225 plci->NL.RNum = 2;
7226 }
7227 else
7228 {
7229 if((plci->NL.Ind &0x0f)==N_UDATA)
7230 plci->RFlags |= 0x0010;
7231
7232 else if ((plci->B3_prot == B3_RTP) && ((plci->NL.Ind & 0x0f) == N_BDATA))
7233 plci->RFlags |= 0x0001;
7234
7235 plci->NL.RNum = 1;
7236 }
7237 break;
7238 case N_DATA_ACK:
7239 data_ack (plci, ch);
7240 break;
7241 default:
7242 plci->NL.RNR = 2;
7243 break;
7244 }
7245}
7246
7247/*------------------------------------------------------------------*/
7248/* find a free PLCI */
7249/*------------------------------------------------------------------*/
7250
7251word get_plci(DIVA_CAPI_ADAPTER * a)
7252{
7253 word i,j;
7254 PLCI * plci;
7255
7256 dump_plcis (a);
7257 for(i=0;i<a->max_plci && a->plci[i].Id;i++);
7258 if(i==a->max_plci) {
7259 dbug(1,dprintf("get_plci: out of PLCIs"));
7260 return 0;
7261 }
7262 plci = &a->plci[i];
7263 plci->Id = (byte)(i+1);
7264
7265 plci->Sig.Id = 0;
7266 plci->NL.Id = 0;
7267 plci->sig_req = 0;
7268 plci->nl_req = 0;
7269
7270 plci->appl = NULL;
7271 plci->relatedPTYPLCI = NULL;
7272 plci->State = IDLE;
7273 plci->SuppState = IDLE;
7274 plci->channels = 0;
7275 plci->tel = 0;
7276 plci->B1_resource = 0;
7277 plci->B2_prot = 0;
7278 plci->B3_prot = 0;
7279
7280 plci->command = 0;
7281 plci->m_command = 0;
7282 init_internal_command_queue (plci);
7283 plci->number = 0;
7284 plci->req_in_start = 0;
7285 plci->req_in = 0;
7286 plci->req_out = 0;
7287 plci->msg_in_write_pos = MSG_IN_QUEUE_SIZE;
7288 plci->msg_in_read_pos = MSG_IN_QUEUE_SIZE;
7289 plci->msg_in_wrap_pos = MSG_IN_QUEUE_SIZE;
7290
7291 plci->data_sent = FALSE;
7292 plci->send_disc = 0;
7293 plci->sig_global_req = 0;
7294 plci->sig_remove_id = 0;
7295 plci->nl_global_req = 0;
7296 plci->nl_remove_id = 0;
7297 plci->adv_nl = 0;
7298 plci->manufacturer = FALSE;
7299 plci->call_dir = CALL_DIR_OUT | CALL_DIR_ORIGINATE;
7300 plci->spoofed_msg = 0;
7301 plci->ptyState = 0;
7302 plci->cr_enquiry = FALSE;
7303 plci->hangup_flow_ctrl_timer = 0;
7304
7305 plci->ncci_ring_list = 0;
7306 for(j=0;j<MAX_CHANNELS_PER_PLCI;j++) plci->inc_dis_ncci_table[j] = 0;
7307 clear_c_ind_mask (plci);
7308 set_group_ind_mask (plci);
7309 plci->fax_connect_info_length = 0;
7310 plci->nsf_control_bits = 0;
7311 plci->ncpi_state = 0x00;
7312 plci->ncpi_buffer[0] = 0;
7313
7314 plci->requested_options_conn = 0;
7315 plci->requested_options = 0;
7316 plci->notifiedcall = 0;
7317 plci->vswitchstate = 0;
7318 plci->vsprot = 0;
7319 plci->vsprotdialect = 0;
7320 init_b1_config (plci);
7321 dbug(1,dprintf("get_plci(%x)",plci->Id));
7322 return i+1;
7323}
7324
7325/*------------------------------------------------------------------*/
7326/* put a parameter in the parameter buffer */
7327/*------------------------------------------------------------------*/
7328
7329static void add_p(PLCI * plci, byte code, byte * p)
7330{
7331 word p_length;
7332
7333 p_length = 0;
7334 if(p) p_length = p[0];
7335 add_ie(plci, code, p, p_length);
7336}
7337
7338/*------------------------------------------------------------------*/
7339/* put a structure in the parameter buffer */
7340/*------------------------------------------------------------------*/
7341static void add_s(PLCI * plci, byte code, API_PARSE * p)
7342{
7343 if(p) add_ie(plci, code, p->info, (word)p->length);
7344}
7345
7346/*------------------------------------------------------------------*/
7347/* put multiple structures in the parameter buffer */
7348/*------------------------------------------------------------------*/
7349static void add_ss(PLCI * plci, byte code, API_PARSE * p)
7350{
7351 byte i;
7352
7353 if(p){
7354 dbug(1,dprintf("add_ss(%x,len=%d)",code,p->length));
7355 for(i=2;i<(byte)p->length;i+=p->info[i]+2){
7356 dbug(1,dprintf("add_ss_ie(%x,len=%d)",p->info[i-1],p->info[i]));
7357 add_ie(plci, p->info[i-1], (byte *)&(p->info[i]), (word)p->info[i]);
7358 }
7359 }
7360}
7361
7362/*------------------------------------------------------------------*/
7363/* return the channel number sent by the application in a esc_chi */
7364/*------------------------------------------------------------------*/
7365static byte getChannel(API_PARSE * p)
7366{
7367 byte i;
7368
7369 if(p){
7370 for(i=2;i<(byte)p->length;i+=p->info[i]+2){
7371 if(p->info[i]==2){
7372 if(p->info[i-1]==ESC && p->info[i+1]==CHI) return (p->info[i+2]);
7373 }
7374 }
7375 }
7376 return 0;
7377}
7378
7379
7380/*------------------------------------------------------------------*/
7381/* put an information element in the parameter buffer */
7382/*------------------------------------------------------------------*/
7383
7384static void add_ie(PLCI * plci, byte code, byte * p, word p_length)
7385{
7386 word i;
7387
7388 if(!(code &0x80) && !p_length) return;
7389
7390 if(plci->req_in==plci->req_in_start) {
7391 plci->req_in +=2;
7392 }
7393 else {
7394 plci->req_in--;
7395 }
7396 plci->RBuffer[plci->req_in++] = code;
7397
7398 if(p) {
7399 plci->RBuffer[plci->req_in++] = (byte)p_length;
7400 for(i=0;i<p_length;i++) plci->RBuffer[plci->req_in++] = p[1+i];
7401 }
7402
7403 plci->RBuffer[plci->req_in++] = 0;
7404}
7405
7406/*------------------------------------------------------------------*/
7407/* put a unstructured data into the buffer */
7408/*------------------------------------------------------------------*/
7409
7410void add_d(PLCI * plci, word length, byte * p)
7411{
7412 word i;
7413
7414 if(plci->req_in==plci->req_in_start) {
7415 plci->req_in +=2;
7416 }
7417 else {
7418 plci->req_in--;
7419 }
7420 for(i=0;i<length;i++) plci->RBuffer[plci->req_in++] = p[i];
7421}
7422
7423/*------------------------------------------------------------------*/
7424/* put parameters from the Additional Info parameter in the */
7425/* parameter buffer */
7426/*------------------------------------------------------------------*/
7427
7428void add_ai(PLCI * plci, API_PARSE * ai)
7429{
7430 word i;
7431 API_PARSE ai_parms[5];
7432
7433 for(i=0;i<5;i++) ai_parms[i].length = 0;
7434
7435 if(!ai->length)
7436 return;
7437 if(api_parse(&ai->info[1], (word)ai->length, "ssss", ai_parms))
7438 return;
7439
7440 add_s (plci,KEY,&ai_parms[1]);
7441 add_s (plci,UUI,&ai_parms[2]);
7442 add_ss(plci,FTY,&ai_parms[3]);
7443}
7444
7445/*------------------------------------------------------------------*/
7446/* put parameter for b1 protocol in the parameter buffer */
7447/*------------------------------------------------------------------*/
7448
7449word add_b1(PLCI * plci, API_PARSE * bp, word b_channel_info, word b1_facilities)
7450{
7451 API_PARSE bp_parms[8];
7452 API_PARSE mdm_cfg[9];
7453 API_PARSE global_config[2];
7454 byte cai[256];
7455 byte resource[] = {5,9,13,12,16,39,9,17,17,18};
7456 byte voice_cai[] = "\x06\x14\x00\x00\x00\x00\x08";
7457 word i;
7458
7459 API_PARSE mdm_cfg_v18[4];
7460 word j, n, w;
7461 dword d;
7462
7463
7464 for(i=0;i<8;i++) bp_parms[i].length = 0;
7465 for(i=0;i<2;i++) global_config[i].length = 0;
7466
7467 dbug(1,dprintf("add_b1"));
7468 api_save_msg(bp, "s", &plci->B_protocol);
7469
7470 if(b_channel_info==2){
7471 plci->B1_resource = 0;
7472 adjust_b1_facilities (plci, plci->B1_resource, b1_facilities);
7473 add_p(plci, CAI, "\x01\x00");
7474 dbug(1,dprintf("Cai=1,0 (no resource)"));
7475 return 0;
7476 }
7477
7478 if(plci->tel == CODEC_PERMANENT) return 0;
7479 else if(plci->tel == CODEC){
7480 plci->B1_resource = 1;
7481 adjust_b1_facilities (plci, plci->B1_resource, b1_facilities);
7482 add_p(plci, CAI, "\x01\x01");
7483 dbug(1,dprintf("Cai=1,1 (Codec)"));
7484 return 0;
7485 }
7486 else if(plci->tel == ADV_VOICE){
7487 plci->B1_resource = add_b1_facilities (plci, 9, (word)(b1_facilities | B1_FACILITY_VOICE));
7488 adjust_b1_facilities (plci, plci->B1_resource, (word)(b1_facilities | B1_FACILITY_VOICE));
7489 voice_cai[1] = plci->B1_resource;
7490 PUT_WORD (&voice_cai[5], plci->appl->MaxDataLength);
7491 add_p(plci, CAI, voice_cai);
7492 dbug(1,dprintf("Cai=1,0x%x (AdvVoice)",voice_cai[1]));
7493 return 0;
7494 }
7495 plci->call_dir &= ~(CALL_DIR_ORIGINATE | CALL_DIR_ANSWER);
7496 if (plci->call_dir & CALL_DIR_OUT)
7497 plci->call_dir |= CALL_DIR_ORIGINATE;
7498 else if (plci->call_dir & CALL_DIR_IN)
7499 plci->call_dir |= CALL_DIR_ANSWER;
7500
7501 if(!bp->length){
7502 plci->B1_resource = 0x5;
7503 adjust_b1_facilities (plci, plci->B1_resource, b1_facilities);
7504 add_p(plci, CAI, "\x01\x05");
7505 return 0;
7506 }
7507
7508 dbug(1,dprintf("b_prot_len=%d",(word)bp->length));
7509 if(bp->length>256) return _WRONG_MESSAGE_FORMAT;
7510 if(api_parse(&bp->info[1], (word)bp->length, "wwwsssb", bp_parms))
7511 {
7512 bp_parms[6].length = 0;
7513 if(api_parse(&bp->info[1], (word)bp->length, "wwwsss", bp_parms))
7514 {
7515 dbug(1,dprintf("b-form.!"));
7516 return _WRONG_MESSAGE_FORMAT;
7517 }
7518 }
7519 else if (api_parse(&bp->info[1], (word)bp->length, "wwwssss", bp_parms))
7520 {
7521 dbug(1,dprintf("b-form.!"));
7522 return _WRONG_MESSAGE_FORMAT;
7523 }
7524
7525 if(bp_parms[6].length)
7526 {
7527 if(api_parse(&bp_parms[6].info[1], (word)bp_parms[6].length, "w", global_config))
7528 {
7529 return _WRONG_MESSAGE_FORMAT;
7530 }
7531 switch(GET_WORD(global_config[0].info))
7532 {
7533 case 1:
7534 plci->call_dir = (plci->call_dir & ~CALL_DIR_ANSWER) | CALL_DIR_ORIGINATE;
7535 break;
7536 case 2:
7537 plci->call_dir = (plci->call_dir & ~CALL_DIR_ORIGINATE) | CALL_DIR_ANSWER;
7538 break;
7539 }
7540 }
7541 dbug(1,dprintf("call_dir=%04x", plci->call_dir));
7542
7543
7544 if ((GET_WORD(bp_parms[0].info) == B1_RTP)
7545 && (plci->adapter->man_profile.private_options & (1L << PRIVATE_RTP)))
7546 {
7547 plci->B1_resource = add_b1_facilities (plci, 31, (word)(b1_facilities & ~B1_FACILITY_VOICE));
7548 adjust_b1_facilities (plci, plci->B1_resource, (word)(b1_facilities & ~B1_FACILITY_VOICE));
7549 cai[1] = plci->B1_resource;
7550 cai[2] = 0;
7551 cai[3] = 0;
7552 cai[4] = 0;
7553 PUT_WORD(&cai[5],plci->appl->MaxDataLength);
7554 for (i = 0; i < bp_parms[3].length; i++)
7555 cai[7+i] = bp_parms[3].info[1+i];
7556 cai[0] = 6 + bp_parms[3].length;
7557 add_p(plci, CAI, cai);
7558 return 0;
7559 }
7560
7561
7562 if ((GET_WORD(bp_parms[0].info) == B1_PIAFS)
7563 && (plci->adapter->man_profile.private_options & (1L << PRIVATE_PIAFS)))
7564 {
7565 plci->B1_resource = add_b1_facilities (plci, 35/* PIAFS HARDWARE FACILITY */, (word)(b1_facilities & ~B1_FACILITY_VOICE));
7566 adjust_b1_facilities (plci, plci->B1_resource, (word)(b1_facilities & ~B1_FACILITY_VOICE));
7567 cai[1] = plci->B1_resource;
7568 cai[2] = 0;
7569 cai[3] = 0;
7570 cai[4] = 0;
7571 PUT_WORD(&cai[5],plci->appl->MaxDataLength);
7572 cai[0] = 6;
7573 add_p(plci, CAI, cai);
7574 return 0;
7575 }
7576
7577
7578 if ((GET_WORD(bp_parms[0].info) >= 32)
7579 || (!((1L << GET_WORD(bp_parms[0].info)) & plci->adapter->profile.B1_Protocols)
7580 && ((GET_WORD(bp_parms[0].info) != 3)
7581 || !((1L << B1_HDLC) & plci->adapter->profile.B1_Protocols)
7582 || ((bp_parms[3].length != 0) && (GET_WORD(&bp_parms[3].info[1]) != 0) && (GET_WORD(&bp_parms[3].info[1]) != 56000)))))
7583 {
7584 return _B1_NOT_SUPPORTED;
7585 }
7586 plci->B1_resource = add_b1_facilities (plci, resource[GET_WORD(bp_parms[0].info)],
7587 (word)(b1_facilities & ~B1_FACILITY_VOICE));
7588 adjust_b1_facilities (plci, plci->B1_resource, (word)(b1_facilities & ~B1_FACILITY_VOICE));
7589 cai[0] = 6;
7590 cai[1] = plci->B1_resource;
7591 for (i=2;i<sizeof(cai);i++) cai[i] = 0;
7592
7593 if ((GET_WORD(bp_parms[0].info) == B1_MODEM_ALL_NEGOTIATE)
7594 || (GET_WORD(bp_parms[0].info) == B1_MODEM_ASYNC)
7595 || (GET_WORD(bp_parms[0].info) == B1_MODEM_SYNC_HDLC))
7596 { /* B1 - modem */
7597 for (i=0;i<7;i++) mdm_cfg[i].length = 0;
7598
7599 if (bp_parms[3].length)
7600 {
7601 if(api_parse(&bp_parms[3].info[1],(word)bp_parms[3].length,"wwwwww", mdm_cfg))
7602 {
7603 return (_WRONG_MESSAGE_FORMAT);
7604 }
7605
7606 cai[2] = 0; /* Bit rate for adaptation */
7607
7608 dbug(1,dprintf("MDM Max Bit Rate:<%d>", GET_WORD(mdm_cfg[0].info)));
7609
7610 PUT_WORD (&cai[13], 0); /* Min Tx speed */
7611 PUT_WORD (&cai[15], GET_WORD(mdm_cfg[0].info)); /* Max Tx speed */
7612 PUT_WORD (&cai[17], 0); /* Min Rx speed */
7613 PUT_WORD (&cai[19], GET_WORD(mdm_cfg[0].info)); /* Max Rx speed */
7614
7615 cai[3] = 0; /* Async framing parameters */
7616 switch (GET_WORD (mdm_cfg[2].info))
7617 { /* Parity */
7618 case 1: /* odd parity */
7619 cai[3] |= (DSP_CAI_ASYNC_PARITY_ENABLE | DSP_CAI_ASYNC_PARITY_ODD);
7620 dbug(1,dprintf("MDM: odd parity"));
7621 break;
7622
7623 case 2: /* even parity */
7624 cai[3] |= (DSP_CAI_ASYNC_PARITY_ENABLE | DSP_CAI_ASYNC_PARITY_EVEN);
7625 dbug(1,dprintf("MDM: even parity"));
7626 break;
7627
7628 default:
7629 dbug(1,dprintf("MDM: no parity"));
7630 break;
7631 }
7632
7633 switch (GET_WORD (mdm_cfg[3].info))
7634 { /* stop bits */
7635 case 1: /* 2 stop bits */
7636 cai[3] |= DSP_CAI_ASYNC_TWO_STOP_BITS;
7637 dbug(1,dprintf("MDM: 2 stop bits"));
7638 break;
7639
7640 default:
7641 dbug(1,dprintf("MDM: 1 stop bit"));
7642 break;
7643 }
7644
7645 switch (GET_WORD (mdm_cfg[1].info))
7646 { /* char length */
7647 case 5:
7648 cai[3] |= DSP_CAI_ASYNC_CHAR_LENGTH_5;
7649 dbug(1,dprintf("MDM: 5 bits"));
7650 break;
7651
7652 case 6:
7653 cai[3] |= DSP_CAI_ASYNC_CHAR_LENGTH_6;
7654 dbug(1,dprintf("MDM: 6 bits"));
7655 break;
7656
7657 case 7:
7658 cai[3] |= DSP_CAI_ASYNC_CHAR_LENGTH_7;
7659 dbug(1,dprintf("MDM: 7 bits"));
7660 break;
7661
7662 default:
7663 dbug(1,dprintf("MDM: 8 bits"));
7664 break;
7665 }
7666
7667 cai[7] = 0; /* Line taking options */
7668 cai[8] = 0; /* Modulation negotiation options */
7669 cai[9] = 0; /* Modulation options */
7670
7671 if (((plci->call_dir & CALL_DIR_ORIGINATE) != 0) ^ ((plci->call_dir & CALL_DIR_OUT) != 0))
7672 {
7673 cai[9] |= DSP_CAI_MODEM_REVERSE_DIRECTION;
7674 dbug(1, dprintf("MDM: Reverse direction"));
7675 }
7676
7677 if (GET_WORD (mdm_cfg[4].info) & MDM_CAPI_DISABLE_RETRAIN)
7678 {
7679 cai[9] |= DSP_CAI_MODEM_DISABLE_RETRAIN;
7680 dbug(1, dprintf("MDM: Disable retrain"));
7681 }
7682
7683 if (GET_WORD (mdm_cfg[4].info) & MDM_CAPI_DISABLE_RING_TONE)
7684 {
7685 cai[7] |= DSP_CAI_MODEM_DISABLE_CALLING_TONE | DSP_CAI_MODEM_DISABLE_ANSWER_TONE;
7686 dbug(1, dprintf("MDM: Disable ring tone"));
7687 }
7688
7689 if (GET_WORD (mdm_cfg[4].info) & MDM_CAPI_GUARD_1800)
7690 {
7691 cai[8] |= DSP_CAI_MODEM_GUARD_TONE_1800HZ;
7692 dbug(1, dprintf("MDM: 1800 guard tone"));
7693 }
7694 else if (GET_WORD (mdm_cfg[4].info) & MDM_CAPI_GUARD_550 )
7695 {
7696 cai[8] |= DSP_CAI_MODEM_GUARD_TONE_550HZ;
7697 dbug(1, dprintf("MDM: 550 guard tone"));
7698 }
7699
7700 if ((GET_WORD (mdm_cfg[5].info) & 0x00ff) == MDM_CAPI_NEG_V100)
7701 {
7702 cai[8] |= DSP_CAI_MODEM_NEGOTIATE_V100;
7703 dbug(1, dprintf("MDM: V100"));
7704 }
7705 else if ((GET_WORD (mdm_cfg[5].info) & 0x00ff) == MDM_CAPI_NEG_MOD_CLASS)
7706 {
7707 cai[8] |= DSP_CAI_MODEM_NEGOTIATE_IN_CLASS;
7708 dbug(1, dprintf("MDM: IN CLASS"));
7709 }
7710 else if ((GET_WORD (mdm_cfg[5].info) & 0x00ff) == MDM_CAPI_NEG_DISABLED)
7711 {
7712 cai[8] |= DSP_CAI_MODEM_NEGOTIATE_DISABLED;
7713 dbug(1, dprintf("MDM: DISABLED"));
7714 }
7715 cai[0] = 20;
7716
7717 if ((plci->adapter->man_profile.private_options & (1L << PRIVATE_V18))
7718 && (GET_WORD(mdm_cfg[5].info) & 0x8000)) /* Private V.18 enable */
7719 {
7720 plci->requested_options |= 1L << PRIVATE_V18;
7721 }
7722 if (GET_WORD(mdm_cfg[5].info) & 0x4000) /* Private VOWN enable */
7723 plci->requested_options |= 1L << PRIVATE_VOWN;
7724
7725 if ((plci->requested_options_conn | plci->requested_options | plci->adapter->requested_options_table[plci->appl->Id-1])
7726 & ((1L << PRIVATE_V18) | (1L << PRIVATE_VOWN)))
7727 {
7728 if (!api_parse(&bp_parms[3].info[1],(word)bp_parms[3].length,"wwwwwws", mdm_cfg))
7729 {
7730 i = 27;
7731 if (mdm_cfg[6].length >= 4)
7732 {
7733 d = GET_DWORD(&mdm_cfg[6].info[1]);
7734 cai[7] |= (byte) d; /* line taking options */
7735 cai[9] |= (byte)(d >> 8); /* modulation options */
7736 cai[++i] = (byte)(d >> 16); /* vown modulation options */
7737 cai[++i] = (byte)(d >> 24);
7738 if (mdm_cfg[6].length >= 8)
7739 {
7740 d = GET_DWORD(&mdm_cfg[6].info[5]);
7741 cai[10] |= (byte) d; /* disabled modulations mask */
7742 cai[11] |= (byte)(d >> 8);
7743 if (mdm_cfg[6].length >= 12)
7744 {
7745 d = GET_DWORD(&mdm_cfg[6].info[9]);
7746 cai[12] = (byte) d; /* enabled modulations mask */
7747 cai[++i] = (byte)(d >> 8); /* vown enabled modulations */
7748 cai[++i] = (byte)(d >> 16);
7749 cai[++i] = (byte)(d >> 24);
7750 cai[++i] = 0;
7751 if (mdm_cfg[6].length >= 14)
7752 {
7753 w = GET_WORD(&mdm_cfg[6].info[13]);
7754 if (w != 0)
7755 PUT_WORD(&cai[13], w); /* min tx speed */
7756 if (mdm_cfg[6].length >= 16)
7757 {
7758 w = GET_WORD(&mdm_cfg[6].info[15]);
7759 if (w != 0)
7760 PUT_WORD(&cai[15], w); /* max tx speed */
7761 if (mdm_cfg[6].length >= 18)
7762 {
7763 w = GET_WORD(&mdm_cfg[6].info[17]);
7764 if (w != 0)
7765 PUT_WORD(&cai[17], w); /* min rx speed */
7766 if (mdm_cfg[6].length >= 20)
7767 {
7768 w = GET_WORD(&mdm_cfg[6].info[19]);
7769 if (w != 0)
7770 PUT_WORD(&cai[19], w); /* max rx speed */
7771 if (mdm_cfg[6].length >= 22)
7772 {
7773 w = GET_WORD(&mdm_cfg[6].info[21]);
7774 cai[23] = (byte)(-((short) w)); /* transmit level */
7775 if (mdm_cfg[6].length >= 24)
7776 {
7777 w = GET_WORD(&mdm_cfg[6].info[23]);
7778 cai[22] |= (byte) w; /* info options mask */
7779 cai[21] |= (byte)(w >> 8); /* disabled symbol rates */
7780 }
7781 }
7782 }
7783 }
7784 }
7785 }
7786 }
7787 }
7788 }
7789 cai[27] = i - 27;
7790 i++;
7791 if (!api_parse(&bp_parms[3].info[1],(word)bp_parms[3].length,"wwwwwwss", mdm_cfg))
7792 {
7793 if (!api_parse(&mdm_cfg[7].info[1],(word)mdm_cfg[7].length,"sss", mdm_cfg_v18))
7794 {
7795 for (n = 0; n < 3; n++)
7796 {
7797 cai[i] = (byte)(mdm_cfg_v18[n].length);
7798 for (j = 1; j < ((word)(cai[i] + 1)); j++)
7799 cai[i+j] = mdm_cfg_v18[n].info[j];
7800 i += cai[i] + 1;
7801 }
7802 }
7803 }
7804 cai[0] = (byte)(i - 1);
7805 }
7806 }
7807
7808 }
7809 }
7810 if(GET_WORD(bp_parms[0].info)==2 || /* V.110 async */
7811 GET_WORD(bp_parms[0].info)==3 ) /* V.110 sync */
7812 {
7813 if(bp_parms[3].length){
7814 dbug(1,dprintf("V.110,%d",GET_WORD(&bp_parms[3].info[1])));
7815 switch(GET_WORD(&bp_parms[3].info[1])){ /* Rate */
7816 case 0:
7817 case 56000:
7818 if(GET_WORD(bp_parms[0].info)==3){ /* V.110 sync 56k */
7819 dbug(1,dprintf("56k sync HSCX"));
7820 cai[1] = 8;
7821 cai[2] = 0;
7822 cai[3] = 0;
7823 }
7824 else if(GET_WORD(bp_parms[0].info)==2){
7825 dbug(1,dprintf("56k async DSP"));
7826 cai[2] = 9;
7827 }
7828 break;
7829 case 50: cai[2] = 1; break;
7830 case 75: cai[2] = 1; break;
7831 case 110: cai[2] = 1; break;
7832 case 150: cai[2] = 1; break;
7833 case 200: cai[2] = 1; break;
7834 case 300: cai[2] = 1; break;
7835 case 600: cai[2] = 1; break;
7836 case 1200: cai[2] = 2; break;
7837 case 2400: cai[2] = 3; break;
7838 case 4800: cai[2] = 4; break;
7839 case 7200: cai[2] = 10; break;
7840 case 9600: cai[2] = 5; break;
7841 case 12000: cai[2] = 13; break;
7842 case 24000: cai[2] = 0; break;
7843 case 14400: cai[2] = 11; break;
7844 case 19200: cai[2] = 6; break;
7845 case 28800: cai[2] = 12; break;
7846 case 38400: cai[2] = 7; break;
7847 case 48000: cai[2] = 8; break;
7848 case 76: cai[2] = 15; break; /* 75/1200 */
7849 case 1201: cai[2] = 14; break; /* 1200/75 */
7850 case 56001: cai[2] = 9; break; /* V.110 56000 */
7851
7852 default:
7853 return _B1_PARM_NOT_SUPPORTED;
7854 }
7855 cai[3] = 0;
7856 if (cai[1] == 13) /* v.110 async */
7857 {
7858 if (bp_parms[3].length >= 8)
7859 {
7860 switch (GET_WORD (&bp_parms[3].info[3]))
7861 { /* char length */
7862 case 5:
7863 cai[3] |= DSP_CAI_ASYNC_CHAR_LENGTH_5;
7864 break;
7865 case 6:
7866 cai[3] |= DSP_CAI_ASYNC_CHAR_LENGTH_6;
7867 break;
7868 case 7:
7869 cai[3] |= DSP_CAI_ASYNC_CHAR_LENGTH_7;
7870 break;
7871 }
7872 switch (GET_WORD (&bp_parms[3].info[5]))
7873 { /* Parity */
7874 case 1: /* odd parity */
7875 cai[3] |= (DSP_CAI_ASYNC_PARITY_ENABLE | DSP_CAI_ASYNC_PARITY_ODD);
7876 break;
7877 case 2: /* even parity */
7878 cai[3] |= (DSP_CAI_ASYNC_PARITY_ENABLE | DSP_CAI_ASYNC_PARITY_EVEN);
7879 break;
7880 }
7881 switch (GET_WORD (&bp_parms[3].info[7]))
7882 { /* stop bits */
7883 case 1: /* 2 stop bits */
7884 cai[3] |= DSP_CAI_ASYNC_TWO_STOP_BITS;
7885 break;
7886 }
7887 }
7888 }
7889 }
7890 else if(cai[1]==8 || GET_WORD(bp_parms[0].info)==3 ){
7891 dbug(1,dprintf("V.110 default 56k sync"));
7892 cai[1] = 8;
7893 cai[2] = 0;
7894 cai[3] = 0;
7895 }
7896 else {
7897 dbug(1,dprintf("V.110 default 9600 async"));
7898 cai[2] = 5;
7899 }
7900 }
7901 PUT_WORD(&cai[5],plci->appl->MaxDataLength);
7902 dbug(1,dprintf("CAI[%d]=%x,%x,%x,%x,%x,%x", cai[0], cai[1], cai[2], cai[3], cai[4], cai[5], cai[6]));
7903/* HexDump ("CAI", sizeof(cai), &cai[0]); */
7904
7905 add_p(plci, CAI, cai);
7906 return 0;
7907}
7908
7909/*------------------------------------------------------------------*/
7910/* put parameter for b2 and B3 protocol in the parameter buffer */
7911/*------------------------------------------------------------------*/
7912
7913word add_b23(PLCI * plci, API_PARSE * bp)
7914{
7915 word i, fax_control_bits;
7916 byte pos, len;
7917 byte SAPI = 0x40; /* default SAPI 16 for x.31 */
7918 API_PARSE bp_parms[8];
7919 API_PARSE * b1_config;
7920 API_PARSE * b2_config;
7921 API_PARSE b2_config_parms[8];
7922 API_PARSE * b3_config;
7923 API_PARSE b3_config_parms[6];
7924 API_PARSE global_config[2];
7925
7926 static byte llc[3] = {2,0,0};
7927 static byte dlc[20] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
7928 static byte nlc[256];
7929 static byte lli[12] = {1,1};
7930
7931 const byte llc2_out[] = {1,2,4,6,2,0,0,0, X75_V42BIS,V120_L2,V120_V42BIS,V120_L2,6};
7932 const byte llc2_in[] = {1,3,4,6,3,0,0,0, X75_V42BIS,V120_L2,V120_V42BIS,V120_L2,6};
7933
7934 const byte llc3[] = {4,3,2,2,6,6,0};
7935 const byte header[] = {0,2,3,3,0,0,0};
7936
7937 for(i=0;i<8;i++) bp_parms[i].length = 0;
7938 for(i=0;i<6;i++) b2_config_parms[i].length = 0;
7939 for(i=0;i<5;i++) b3_config_parms[i].length = 0;
7940
7941 lli[0] = 1;
7942 lli[1] = 1;
7943 if (plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_XONOFF_FLOW_CONTROL)
7944 lli[1] |= 2;
7945 if (plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_OOB_CHANNEL)
7946 lli[1] |= 4;
7947
7948 if ((lli[1] & 0x02) && (diva_xdi_extended_features & DIVA_CAPI_USE_CMA)) {
7949 lli[1] |= 0x10;
7950 if (plci->rx_dma_descriptor <= 0) {
7951 plci->rx_dma_descriptor=diva_get_dma_descriptor(plci,&plci->rx_dma_magic);
7952 if (plci->rx_dma_descriptor >= 0)
7953 plci->rx_dma_descriptor++;
7954 }
7955 if (plci->rx_dma_descriptor > 0) {
7956 lli[0] = 6;
7957 lli[1] |= 0x40;
7958 lli[2] = (byte)(plci->rx_dma_descriptor - 1);
7959 lli[3] = (byte)plci->rx_dma_magic;
7960 lli[4] = (byte)(plci->rx_dma_magic >> 8);
7961 lli[5] = (byte)(plci->rx_dma_magic >> 16);
7962 lli[6] = (byte)(plci->rx_dma_magic >> 24);
7963 }
7964 }
7965
7966 if (DIVA_CAPI_SUPPORTS_NO_CANCEL(plci->adapter)) {
7967 lli[1] |= 0x20;
7968 }
7969
7970 dbug(1,dprintf("add_b23"));
7971 api_save_msg(bp, "s", &plci->B_protocol);
7972
7973 if(!bp->length && plci->tel)
7974 {
7975 plci->adv_nl = TRUE;
7976 dbug(1,dprintf("Default adv.Nl"));
7977 add_p(plci,LLI,lli);
7978 plci->B2_prot = 1 /*XPARENT*/;
7979 plci->B3_prot = 0 /*XPARENT*/;
7980 llc[1] = 2;
7981 llc[2] = 4;
7982 add_p(plci, LLC, llc);
7983 dlc[0] = 2;
7984 PUT_WORD(&dlc[1],plci->appl->MaxDataLength);
7985 add_p(plci, DLC, dlc);
7986 return 0;
7987 }
7988
7989 if(!bp->length) /*default*/
7990 {
7991 dbug(1,dprintf("ret default"));
7992 add_p(plci,LLI,lli);
7993 plci->B2_prot = 0 /*X.75 */;
7994 plci->B3_prot = 0 /*XPARENT*/;
7995 llc[1] = 1;
7996 llc[2] = 4;
7997 add_p(plci, LLC, llc);
7998 dlc[0] = 2;
7999 PUT_WORD(&dlc[1],plci->appl->MaxDataLength);
8000 add_p(plci, DLC, dlc);
8001 return 0;
8002 }
8003 dbug(1,dprintf("b_prot_len=%d",(word)bp->length));
8004 if((word)bp->length > 256) return _WRONG_MESSAGE_FORMAT;
8005
8006 if(api_parse(&bp->info[1], (word)bp->length, "wwwsssb", bp_parms))
8007 {
8008 bp_parms[6].length = 0;
8009 if(api_parse(&bp->info[1], (word)bp->length, "wwwsss", bp_parms))
8010 {
8011 dbug(1,dprintf("b-form.!"));
8012 return _WRONG_MESSAGE_FORMAT;
8013 }
8014 }
8015 else if (api_parse(&bp->info[1], (word)bp->length, "wwwssss", bp_parms))
8016 {
8017 dbug(1,dprintf("b-form.!"));
8018 return _WRONG_MESSAGE_FORMAT;
8019 }
8020
8021 if(plci->tel==ADV_VOICE) /* transparent B on advanced voice */
8022 {
8023 if(GET_WORD(bp_parms[1].info)!=1
8024 || GET_WORD(bp_parms[2].info)!=0) return _B2_NOT_SUPPORTED;
8025 plci->adv_nl = TRUE;
8026 }
8027 else if(plci->tel) return _B2_NOT_SUPPORTED;
8028
8029
8030 if ((GET_WORD(bp_parms[1].info) == B2_RTP)
8031 && (GET_WORD(bp_parms[2].info) == B3_RTP)
8032 && (plci->adapter->man_profile.private_options & (1L << PRIVATE_RTP)))
8033 {
8034 add_p(plci,LLI,lli);
8035 plci->B2_prot = (byte) GET_WORD(bp_parms[1].info);
8036 plci->B3_prot = (byte) GET_WORD(bp_parms[2].info);
8037 llc[1] = (plci->call_dir & (CALL_DIR_ORIGINATE | CALL_DIR_FORCE_OUTG_NL)) ? 14 : 13;
8038 llc[2] = 4;
8039 add_p(plci, LLC, llc);
8040 dlc[0] = 2;
8041 PUT_WORD(&dlc[1],plci->appl->MaxDataLength);
8042 dlc[3] = 3; /* Addr A */
8043 dlc[4] = 1; /* Addr B */
8044 dlc[5] = 7; /* modulo mode */
8045 dlc[6] = 7; /* window size */
8046 dlc[7] = 0; /* XID len Lo */
8047 dlc[8] = 0; /* XID len Hi */
8048 for (i = 0; i < bp_parms[4].length; i++)
8049 dlc[9+i] = bp_parms[4].info[1+i];
8050 dlc[0] = (byte)(8 + bp_parms[4].length);
8051 add_p(plci, DLC, dlc);
8052 for (i = 0; i < bp_parms[5].length; i++)
8053 nlc[1+i] = bp_parms[5].info[1+i];
8054 nlc[0] = (byte)(bp_parms[5].length);
8055 add_p(plci, NLC, nlc);
8056 return 0;
8057 }
8058
8059
8060
8061 if ((GET_WORD(bp_parms[1].info) >= 32)
8062 || (!((1L << GET_WORD(bp_parms[1].info)) & plci->adapter->profile.B2_Protocols)
8063 && ((GET_WORD(bp_parms[1].info) != B2_PIAFS)
8064 || !(plci->adapter->man_profile.private_options & (1L << PRIVATE_PIAFS)))))
8065
8066 {
8067 return _B2_NOT_SUPPORTED;
8068 }
8069 if ((GET_WORD(bp_parms[2].info) >= 32)
8070 || !((1L << GET_WORD(bp_parms[2].info)) & plci->adapter->profile.B3_Protocols))
8071 {
8072 return _B3_NOT_SUPPORTED;
8073 }
8074 if ((GET_WORD(bp_parms[1].info) != B2_SDLC)
8075 && ((GET_WORD(bp_parms[0].info) == B1_MODEM_ALL_NEGOTIATE)
8076 || (GET_WORD(bp_parms[0].info) == B1_MODEM_ASYNC)
8077 || (GET_WORD(bp_parms[0].info) == B1_MODEM_SYNC_HDLC)))
8078 {
8079 return (add_modem_b23 (plci, bp_parms));
8080 }
8081
8082 add_p(plci,LLI,lli);
8083
8084 plci->B2_prot = (byte) GET_WORD(bp_parms[1].info);
8085 plci->B3_prot = (byte) GET_WORD(bp_parms[2].info);
8086 if(plci->B2_prot==12) SAPI = 0; /* default SAPI D-channel */
8087
8088 if(bp_parms[6].length)
8089 {
8090 if(api_parse(&bp_parms[6].info[1], (word)bp_parms[6].length, "w", global_config))
8091 {
8092 return _WRONG_MESSAGE_FORMAT;
8093 }
8094 switch(GET_WORD(global_config[0].info))
8095 {
8096 case 1:
8097 plci->call_dir = (plci->call_dir & ~CALL_DIR_ANSWER) | CALL_DIR_ORIGINATE;
8098 break;
8099 case 2:
8100 plci->call_dir = (plci->call_dir & ~CALL_DIR_ORIGINATE) | CALL_DIR_ANSWER;
8101 break;
8102 }
8103 }
8104 dbug(1,dprintf("call_dir=%04x", plci->call_dir));
8105
8106
8107 if (plci->B2_prot == B2_PIAFS)
8108 llc[1] = PIAFS_CRC;
8109 else
8110/* IMPLEMENT_PIAFS */
8111 {
8112 llc[1] = (plci->call_dir & (CALL_DIR_ORIGINATE | CALL_DIR_FORCE_OUTG_NL)) ?
8113 llc2_out[GET_WORD(bp_parms[1].info)] : llc2_in[GET_WORD(bp_parms[1].info)];
8114 }
8115 llc[2] = llc3[GET_WORD(bp_parms[2].info)];
8116
8117 add_p(plci, LLC, llc);
8118
8119 dlc[0] = 2;
8120 PUT_WORD(&dlc[1], plci->appl->MaxDataLength +
8121 header[GET_WORD(bp_parms[2].info)]);
8122
8123 b1_config = &bp_parms[3];
8124 nlc[0] = 0;
8125 if(plci->B3_prot == 4
8126 || plci->B3_prot == 5)
8127 {
8128 for (i=0;i<sizeof(T30_INFO);i++) nlc[i] = 0;
8129 nlc[0] = sizeof(T30_INFO);
8130 if (plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_FAX_PAPER_FORMATS)
8131 ((T30_INFO *)&nlc[1])->operating_mode = T30_OPERATING_MODE_CAPI;
8132 ((T30_INFO *)&nlc[1])->rate_div_2400 = 0xff;
8133 if(b1_config->length>=2)
8134 {
8135 ((T30_INFO *)&nlc[1])->rate_div_2400 = (byte)(GET_WORD(&b1_config->info[1])/2400);
8136 }
8137 }
8138 b2_config = &bp_parms[4];
8139
8140
8141 if (llc[1] == PIAFS_CRC)
8142 {
8143 if (plci->B3_prot != B3_TRANSPARENT)
8144 {
8145 return _B_STACK_NOT_SUPPORTED;
8146 }
8147 if(b2_config->length && api_parse(&b2_config->info[1], (word)b2_config->length, "bwww", b2_config_parms)) {
8148 return _WRONG_MESSAGE_FORMAT;
8149 }
8150 PUT_WORD(&dlc[1],plci->appl->MaxDataLength);
8151 dlc[3] = 0; /* Addr A */
8152 dlc[4] = 0; /* Addr B */
8153 dlc[5] = 0; /* modulo mode */
8154 dlc[6] = 0; /* window size */
8155 if (b2_config->length >= 7){
8156 dlc[ 7] = 7;
8157 dlc[ 8] = 0;
8158 dlc[ 9] = b2_config_parms[0].info[0]; /* PIAFS protocol Speed configuration */
8159 dlc[10] = b2_config_parms[1].info[0]; /* V.42bis P0 */
8160 dlc[11] = b2_config_parms[1].info[1]; /* V.42bis P0 */
8161 dlc[12] = b2_config_parms[2].info[0]; /* V.42bis P1 */
8162 dlc[13] = b2_config_parms[2].info[1]; /* V.42bis P1 */
8163 dlc[14] = b2_config_parms[3].info[0]; /* V.42bis P2 */
8164 dlc[15] = b2_config_parms[3].info[1]; /* V.42bis P2 */
8165 dlc[ 0] = 15;
8166 if(b2_config->length >= 8) { /* PIAFS control abilities */
8167 dlc[ 7] = 10;
8168 dlc[16] = 2; /* Length of PIAFS extention */
8169 dlc[17] = PIAFS_UDATA_ABILITIES; /* control (UDATA) ability */
8170 dlc[18] = b2_config_parms[4].info[0]; /* value */
8171 dlc[ 0] = 18;
8172 }
8173 }
8174 else /* default values, 64K, variable, no compression */
8175 {
8176 dlc[ 7] = 7;
8177 dlc[ 8] = 0;
8178 dlc[ 9] = 0x03; /* PIAFS protocol Speed configuration */
8179 dlc[10] = 0x03; /* V.42bis P0 */
8180 dlc[11] = 0; /* V.42bis P0 */
8181 dlc[12] = 0; /* V.42bis P1 */
8182 dlc[13] = 0; /* V.42bis P1 */
8183 dlc[14] = 0; /* V.42bis P2 */
8184 dlc[15] = 0; /* V.42bis P2 */
8185 dlc[ 0] = 15;
8186 }
8187 add_p(plci, DLC, dlc);
8188 }
8189 else
8190
8191 if ((llc[1] == V120_L2) || (llc[1] == V120_V42BIS))
8192 {
8193 if (plci->B3_prot != B3_TRANSPARENT)
8194 return _B_STACK_NOT_SUPPORTED;
8195
8196 dlc[0] = 6;
8197 PUT_WORD (&dlc[1], GET_WORD (&dlc[1]) + 2);
8198 dlc[3] = 0x08;
8199 dlc[4] = 0x01;
8200 dlc[5] = 127;
8201 dlc[6] = 7;
8202 if (b2_config->length != 0)
8203 {
8204 if((llc[1]==V120_V42BIS) && api_parse(&b2_config->info[1], (word)b2_config->length, "bbbbwww", b2_config_parms)) {
8205 return _WRONG_MESSAGE_FORMAT;
8206 }
8207 dlc[3] = (byte)((b2_config->info[2] << 3) | ((b2_config->info[1] >> 5) & 0x04));
8208 dlc[4] = (byte)((b2_config->info[1] << 1) | 0x01);
8209 if (b2_config->info[3] != 128)
8210 {
8211 dbug(1,dprintf("1D-dlc= %x %x %x %x %x", dlc[0], dlc[1], dlc[2], dlc[3], dlc[4]));
8212 return _B2_PARM_NOT_SUPPORTED;
8213 }
8214 dlc[5] = (byte)(b2_config->info[3] - 1);
8215 dlc[6] = b2_config->info[4];
8216 if(llc[1]==V120_V42BIS){
8217 if (b2_config->length >= 10){
8218 dlc[ 7] = 6;
8219 dlc[ 8] = 0;
8220 dlc[ 9] = b2_config_parms[4].info[0];
8221 dlc[10] = b2_config_parms[4].info[1];
8222 dlc[11] = b2_config_parms[5].info[0];
8223 dlc[12] = b2_config_parms[5].info[1];
8224 dlc[13] = b2_config_parms[6].info[0];
8225 dlc[14] = b2_config_parms[6].info[1];
8226 dlc[ 0] = 14;
8227 dbug(1,dprintf("b2_config_parms[4].info[0] [1]: %x %x", b2_config_parms[4].info[0], b2_config_parms[4].info[1]));
8228 dbug(1,dprintf("b2_config_parms[5].info[0] [1]: %x %x", b2_config_parms[5].info[0], b2_config_parms[5].info[1]));
8229 dbug(1,dprintf("b2_config_parms[6].info[0] [1]: %x %x", b2_config_parms[6].info[0], b2_config_parms[6].info[1]));
8230 }
8231 else {
8232 dlc[ 6] = 14;
8233 }
8234 }
8235 }
8236 }
8237 else
8238 {
8239 if(b2_config->length)
8240 {
8241 dbug(1,dprintf("B2-Config"));
8242 if(llc[1]==X75_V42BIS){
8243 if(api_parse(&b2_config->info[1], (word)b2_config->length, "bbbbwww", b2_config_parms))
8244 {
8245 return _WRONG_MESSAGE_FORMAT;
8246 }
8247 }
8248 else {
8249 if(api_parse(&b2_config->info[1], (word)b2_config->length, "bbbbs", b2_config_parms))
8250 {
8251 return _WRONG_MESSAGE_FORMAT;
8252 }
8253 }
8254 /* if B2 Protocol is LAPD, b2_config structure is different */
8255 if(llc[1]==6)
8256 {
8257 dlc[0] = 4;
8258 if(b2_config->length>=1) dlc[2] = b2_config->info[1]; /* TEI */
8259 else dlc[2] = 0x01;
8260 if( (b2_config->length>=2) && (plci->B2_prot==12) )
8261 {
8262 SAPI = b2_config->info[2]; /* SAPI */
8263 }
8264 dlc[1] = SAPI;
8265 if( (b2_config->length>=3) && (b2_config->info[3]==128) )
8266 {
8267 dlc[3] = 127; /* Mode */
8268 }
8269 else
8270 {
8271 dlc[3] = 7; /* Mode */
8272 }
8273
8274 if(b2_config->length>=4) dlc[4] = b2_config->info[4]; /* Window */
8275 else dlc[4] = 1;
8276 dbug(1,dprintf("D-dlc[%d]=%x,%x,%x,%x", dlc[0], dlc[1], dlc[2], dlc[3], dlc[4]));
8277 if(b2_config->length>5) return _B2_PARM_NOT_SUPPORTED;
8278 }
8279 else
8280 {
8281 dlc[0] = (byte)(b2_config_parms[4].length+6);
8282 dlc[3] = b2_config->info[1];
8283 dlc[4] = b2_config->info[2];
8284 if(b2_config->info[3]!=8 && b2_config->info[3]!=128){
8285 dbug(1,dprintf("1D-dlc= %x %x %x %x %x", dlc[0], dlc[1], dlc[2], dlc[3], dlc[4]));
8286 return _B2_PARM_NOT_SUPPORTED;
8287 }
8288
8289 dlc[5] = (byte)(b2_config->info[3]-1);
8290 dlc[6] = b2_config->info[4];
8291 if(dlc[6]>dlc[5]){
8292 dbug(1,dprintf("2D-dlc= %x %x %x %x %x %x %x", dlc[0], dlc[1], dlc[2], dlc[3], dlc[4], dlc[5], dlc[6]));
8293 return _B2_PARM_NOT_SUPPORTED;
8294 }
8295
8296 if(llc[1]==X75_V42BIS) {
8297 if (b2_config->length >= 10){
8298 dlc[ 7] = 6;
8299 dlc[ 8] = 0;
8300 dlc[ 9] = b2_config_parms[4].info[0];
8301 dlc[10] = b2_config_parms[4].info[1];
8302 dlc[11] = b2_config_parms[5].info[0];
8303 dlc[12] = b2_config_parms[5].info[1];
8304 dlc[13] = b2_config_parms[6].info[0];
8305 dlc[14] = b2_config_parms[6].info[1];
8306 dlc[ 0] = 14;
8307 dbug(1,dprintf("b2_config_parms[4].info[0] [1]: %x %x", b2_config_parms[4].info[0], b2_config_parms[4].info[1]));
8308 dbug(1,dprintf("b2_config_parms[5].info[0] [1]: %x %x", b2_config_parms[5].info[0], b2_config_parms[5].info[1]));
8309 dbug(1,dprintf("b2_config_parms[6].info[0] [1]: %x %x", b2_config_parms[6].info[0], b2_config_parms[6].info[1]));
8310 }
8311 else {
8312 dlc[ 6] = 14;
8313 }
8314
8315 }
8316 else {
8317 PUT_WORD(&dlc[7], (word)b2_config_parms[4].length);
8318 for(i=0; i<b2_config_parms[4].length; i++)
8319 dlc[11+i] = b2_config_parms[4].info[1+i];
8320 }
8321 }
8322 }
8323 }
8324 add_p(plci, DLC, dlc);
8325
8326 b3_config = &bp_parms[5];
8327 if(b3_config->length)
8328 {
8329 if(plci->B3_prot == 4
8330 || plci->B3_prot == 5)
8331 {
8332 if(api_parse(&b3_config->info[1], (word)b3_config->length, "wwss", b3_config_parms))
8333 {
8334 return _WRONG_MESSAGE_FORMAT;
8335 }
8336 i = GET_WORD((byte *)(b3_config_parms[0].info));
8337 ((T30_INFO *)&nlc[1])->resolution = (byte)(((i & 0x0001) ||
8338 ((plci->B3_prot == 4) && (((byte)(GET_WORD((byte *)b3_config_parms[1].info))) != 5))) ? T30_RESOLUTION_R8_0770_OR_200 : 0);
8339 ((T30_INFO *)&nlc[1])->data_format = (byte)(GET_WORD((byte *)b3_config_parms[1].info));
8340 fax_control_bits = T30_CONTROL_BIT_ALL_FEATURES;
8341 if ((((T30_INFO *)&nlc[1])->rate_div_2400 != 0) && (((T30_INFO *)&nlc[1])->rate_div_2400 <= 6))
8342 fax_control_bits &= ~T30_CONTROL_BIT_ENABLE_V34FAX;
8343 if (plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_FAX_PAPER_FORMATS)
8344 {
8345
8346 if ((plci->requested_options_conn | plci->requested_options | plci->adapter->requested_options_table[plci->appl->Id-1])
8347 & (1L << PRIVATE_FAX_PAPER_FORMATS))
8348 {
8349 ((T30_INFO *)&nlc[1])->resolution |= T30_RESOLUTION_R8_1540 |
8350 T30_RESOLUTION_R16_1540_OR_400 | T30_RESOLUTION_300_300 |
8351 T30_RESOLUTION_INCH_BASED | T30_RESOLUTION_METRIC_BASED;
8352 }
8353
8354 ((T30_INFO *)&nlc[1])->recording_properties =
8355 T30_RECORDING_WIDTH_ISO_A3 |
8356 (T30_RECORDING_LENGTH_UNLIMITED << 2) |
8357 (T30_MIN_SCANLINE_TIME_00_00_00 << 4);
8358 }
8359 if(plci->B3_prot == 5)
8360 {
8361 if (i & 0x0002) /* Accept incoming fax-polling requests */
8362 fax_control_bits |= T30_CONTROL_BIT_ACCEPT_POLLING;
8363 if (i & 0x2000) /* Do not use MR compression */
8364 fax_control_bits &= ~T30_CONTROL_BIT_ENABLE_2D_CODING;
8365 if (i & 0x4000) /* Do not use MMR compression */
8366 fax_control_bits &= ~T30_CONTROL_BIT_ENABLE_T6_CODING;
8367 if (i & 0x8000) /* Do not use ECM */
8368 fax_control_bits &= ~T30_CONTROL_BIT_ENABLE_ECM;
8369 if (plci->fax_connect_info_length != 0)
8370 {
8371 ((T30_INFO *)&nlc[1])->resolution = ((T30_INFO *)plci->fax_connect_info_buffer)->resolution;
8372 ((T30_INFO *)&nlc[1])->data_format = ((T30_INFO *)plci->fax_connect_info_buffer)->data_format;
8373 ((T30_INFO *)&nlc[1])->recording_properties = ((T30_INFO *)plci->fax_connect_info_buffer)->recording_properties;
8374 fax_control_bits |= GET_WORD(&((T30_INFO *)plci->fax_connect_info_buffer)->control_bits_low) &
8375 (T30_CONTROL_BIT_REQUEST_POLLING | T30_CONTROL_BIT_MORE_DOCUMENTS);
8376 }
8377 }
8378 /* copy station id to NLC */
8379 for(i=0; i<20; i++)
8380 {
8381 if(i<b3_config_parms[2].length)
8382 {
8383 ((T30_INFO *)&nlc[1])->station_id[i] = ((byte *)b3_config_parms[2].info)[1+i];
8384 }
8385 else
8386 {
8387 ((T30_INFO *)&nlc[1])->station_id[i] = ' ';
8388 }
8389 }
8390 ((T30_INFO *)&nlc[1])->station_id_len = 20;
8391 /* copy head line to NLC */
8392 if(b3_config_parms[3].length)
8393 {
8394
8395 pos = (byte)(fax_head_line_time (&(((T30_INFO *)&nlc[1])->station_id[20])));
8396 if (pos != 0)
8397 {
8398 if (CAPI_MAX_DATE_TIME_LENGTH + 2 + b3_config_parms[3].length > CAPI_MAX_HEAD_LINE_SPACE)
8399 pos = 0;
8400 else
8401 {
8402 ((T30_INFO *)&nlc[1])->station_id[20 + pos++] = ' ';
8403 ((T30_INFO *)&nlc[1])->station_id[20 + pos++] = ' ';
8404 len = (byte)b3_config_parms[2].length;
8405 if (len > 20)
8406 len = 20;
8407 if (CAPI_MAX_DATE_TIME_LENGTH + 2 + len + 2 + b3_config_parms[3].length <= CAPI_MAX_HEAD_LINE_SPACE)
8408 {
8409 for (i = 0; i < len; i++)
8410 ((T30_INFO *)&nlc[1])->station_id[20 + pos++] = ((byte *)b3_config_parms[2].info)[1+i];
8411 ((T30_INFO *)&nlc[1])->station_id[20 + pos++] = ' ';
8412 ((T30_INFO *)&nlc[1])->station_id[20 + pos++] = ' ';
8413 }
8414 }
8415 }
8416
8417 len = (byte)b3_config_parms[3].length;
8418 if (len > CAPI_MAX_HEAD_LINE_SPACE - pos)
8419 len = (byte)(CAPI_MAX_HEAD_LINE_SPACE - pos);
8420 ((T30_INFO *)&nlc[1])->head_line_len = (byte)(pos + len);
8421 nlc[0] += (byte)(pos + len);
8422 for (i = 0; i < len; i++)
8423 ((T30_INFO *)&nlc[1])->station_id[20 + pos++] = ((byte *)b3_config_parms[3].info)[1+i];
8424 }
8425 else
8426 ((T30_INFO *)&nlc[1])->head_line_len = 0;
8427
8428 plci->nsf_control_bits = 0;
8429 if(plci->B3_prot == 5)
8430 {
8431 if ((plci->adapter->man_profile.private_options & (1L << PRIVATE_FAX_SUB_SEP_PWD))
8432 && (GET_WORD((byte *)b3_config_parms[1].info) & 0x8000)) /* Private SUB/SEP/PWD enable */
8433 {
8434 plci->requested_options |= 1L << PRIVATE_FAX_SUB_SEP_PWD;
8435 }
8436 if ((plci->adapter->man_profile.private_options & (1L << PRIVATE_FAX_NONSTANDARD))
8437 && (GET_WORD((byte *)b3_config_parms[1].info) & 0x4000)) /* Private non-standard facilities enable */
8438 {
8439 plci->requested_options |= 1L << PRIVATE_FAX_NONSTANDARD;
8440 }
8441 if ((plci->requested_options_conn | plci->requested_options | plci->adapter->requested_options_table[plci->appl->Id-1])
8442 & ((1L << PRIVATE_FAX_SUB_SEP_PWD) | (1L << PRIVATE_FAX_NONSTANDARD)))
8443 {
8444 if ((plci->requested_options_conn | plci->requested_options | plci->adapter->requested_options_table[plci->appl->Id-1])
8445 & (1L << PRIVATE_FAX_SUB_SEP_PWD))
8446 {
8447 fax_control_bits |= T30_CONTROL_BIT_ACCEPT_SUBADDRESS | T30_CONTROL_BIT_ACCEPT_PASSWORD;
8448 if (fax_control_bits & T30_CONTROL_BIT_ACCEPT_POLLING)
8449 fax_control_bits |= T30_CONTROL_BIT_ACCEPT_SEL_POLLING;
8450 }
8451 len = nlc[0];
8452 pos = ((byte)(((T30_INFO *) 0)->station_id + 20));
8453 if (pos < plci->fax_connect_info_length)
8454 {
8455 for (i = 1 + plci->fax_connect_info_buffer[pos]; i != 0; i--)
8456 nlc[++len] = plci->fax_connect_info_buffer[pos++];
8457 }
8458 else
8459 nlc[++len] = 0;
8460 if (pos < plci->fax_connect_info_length)
8461 {
8462 for (i = 1 + plci->fax_connect_info_buffer[pos]; i != 0; i--)
8463 nlc[++len] = plci->fax_connect_info_buffer[pos++];
8464 }
8465 else
8466 nlc[++len] = 0;
8467 if ((plci->requested_options_conn | plci->requested_options | plci->adapter->requested_options_table[plci->appl->Id-1])
8468 & (1L << PRIVATE_FAX_NONSTANDARD))
8469 {
8470 if ((pos < plci->fax_connect_info_length) && (plci->fax_connect_info_buffer[pos] != 0))
8471 {
8472 if ((plci->fax_connect_info_buffer[pos] >= 3) && (plci->fax_connect_info_buffer[pos+1] >= 2))
8473 plci->nsf_control_bits = GET_WORD(&plci->fax_connect_info_buffer[pos+2]);
8474 for (i = 1 + plci->fax_connect_info_buffer[pos]; i != 0; i--)
8475 nlc[++len] = plci->fax_connect_info_buffer[pos++];
8476 }
8477 else
8478 {
8479 if(api_parse(&b3_config->info[1], (word)b3_config->length, "wwsss", b3_config_parms))
8480 {
8481 dbug(1,dprintf("non-standard facilities info missing or wrong format"));
8482 nlc[++len] = 0;
8483 }
8484 else
8485 {
8486 if ((b3_config_parms[4].length >= 3) && (b3_config_parms[4].info[1] >= 2))
8487 plci->nsf_control_bits = GET_WORD(&b3_config_parms[4].info[2]);
8488 nlc[++len] = (byte)(b3_config_parms[4].length);
8489 for (i = 0; i < b3_config_parms[4].length; i++)
8490 nlc[++len] = b3_config_parms[4].info[1+i];
8491 }
8492 }
8493 }
8494 nlc[0] = len;
8495 if ((plci->nsf_control_bits & T30_NSF_CONTROL_BIT_ENABLE_NSF)
8496 && (plci->nsf_control_bits & T30_NSF_CONTROL_BIT_NEGOTIATE_RESP))
8497 {
8498 ((T30_INFO *)&nlc[1])->operating_mode = T30_OPERATING_MODE_CAPI_NEG;
8499 }
8500 }
8501 }
8502
8503 PUT_WORD(&(((T30_INFO *)&nlc[1])->control_bits_low), fax_control_bits);
8504 len = ((byte)(((T30_INFO *) 0)->station_id + 20));
8505 for (i = 0; i < len; i++)
8506 plci->fax_connect_info_buffer[i] = nlc[1+i];
8507 ((T30_INFO *) plci->fax_connect_info_buffer)->head_line_len = 0;
8508 i += ((T30_INFO *)&nlc[1])->head_line_len;
8509 while (i < nlc[0])
8510 plci->fax_connect_info_buffer[len++] = nlc[++i];
8511 plci->fax_connect_info_length = len;
8512 }
8513 else
8514 {
8515 nlc[0] = 14;
8516 if(b3_config->length!=16)
8517 return _B3_PARM_NOT_SUPPORTED;
8518 for(i=0; i<12; i++) nlc[1+i] = b3_config->info[1+i];
8519 if(GET_WORD(&b3_config->info[13])!=8 && GET_WORD(&b3_config->info[13])!=128)
8520 return _B3_PARM_NOT_SUPPORTED;
8521 nlc[13] = b3_config->info[13];
8522 if(GET_WORD(&b3_config->info[15])>=nlc[13])
8523 return _B3_PARM_NOT_SUPPORTED;
8524 nlc[14] = b3_config->info[15];
8525 }
8526 }
8527 else
8528 {
8529 if (plci->B3_prot == 4
8530 || plci->B3_prot == 5 /*T.30 - FAX*/ ) return _B3_PARM_NOT_SUPPORTED;
8531 }
8532 add_p(plci, NLC, nlc);
8533 return 0;
8534}
8535
8536/*----------------------------------------------------------------*/
8537/* make the same as add_b23, but only for the modem related */
8538/* L2 and L3 B-Chan protocol. */
8539/* */
8540/* Enabled L2 and L3 Configurations: */
8541/* If L1 == Modem all negotiation */
8542/* only L2 == Modem with full negotiation is allowed */
8543/* If L1 == Modem async or sync */
8544/* only L2 == Transparent is allowed */
8545/* L3 == Modem or L3 == Transparent are allowed */
8546/* B2 Configuration for modem: */
8547/* word : enable/disable compression, bitoptions */
8548/* B3 Configuration for modem: */
8549/* empty */
8550/*----------------------------------------------------------------*/
8551static word add_modem_b23 (PLCI * plci, API_PARSE* bp_parms)
8552{
8553 static byte lli[12] = {1,1};
8554 static byte llc[3] = {2,0,0};
8555 static byte dlc[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
8556 API_PARSE mdm_config[2];
8557 word i;
8558 word b2_config = 0;
8559
8560 for(i=0;i<2;i++) mdm_config[i].length = 0;
8561 for(i=0;i<sizeof(dlc);i++) dlc[i] = 0;
8562
8563 if (((GET_WORD(bp_parms[0].info) == B1_MODEM_ALL_NEGOTIATE)
8564 && (GET_WORD(bp_parms[1].info) != B2_MODEM_EC_COMPRESSION))
8565 || ((GET_WORD(bp_parms[0].info) != B1_MODEM_ALL_NEGOTIATE)
8566 && (GET_WORD(bp_parms[1].info) != B2_TRANSPARENT)))
8567 {
8568 return (_B_STACK_NOT_SUPPORTED);
8569 }
8570 if ((GET_WORD(bp_parms[2].info) != B3_MODEM)
8571 && (GET_WORD(bp_parms[2].info) != B3_TRANSPARENT))
8572 {
8573 return (_B_STACK_NOT_SUPPORTED);
8574 }
8575
8576 plci->B2_prot = (byte) GET_WORD(bp_parms[1].info);
8577 plci->B3_prot = (byte) GET_WORD(bp_parms[2].info);
8578
8579 if ((GET_WORD(bp_parms[1].info) == B2_MODEM_EC_COMPRESSION) && bp_parms[4].length)
8580 {
8581 if (api_parse (&bp_parms[4].info[1],
8582 (word)bp_parms[4].length, "w",
8583 mdm_config))
8584 {
8585 return (_WRONG_MESSAGE_FORMAT);
8586 }
8587 b2_config = GET_WORD(mdm_config[0].info);
8588 }
8589
8590 /* OK, L2 is modem */
8591
8592 lli[0] = 1;
8593 lli[1] = 1;
8594 if (plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_XONOFF_FLOW_CONTROL)
8595 lli[1] |= 2;
8596 if (plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_OOB_CHANNEL)
8597 lli[1] |= 4;
8598
8599 if ((lli[1] & 0x02) && (diva_xdi_extended_features & DIVA_CAPI_USE_CMA)) {
8600 lli[1] |= 0x10;
8601 if (plci->rx_dma_descriptor <= 0) {
8602 plci->rx_dma_descriptor=diva_get_dma_descriptor(plci,&plci->rx_dma_magic);
8603 if (plci->rx_dma_descriptor >= 0)
8604 plci->rx_dma_descriptor++;
8605 }
8606 if (plci->rx_dma_descriptor > 0) {
8607 lli[1] |= 0x40;
8608 lli[0] = 6;
8609 lli[2] = (byte)(plci->rx_dma_descriptor - 1);
8610 lli[3] = (byte)plci->rx_dma_magic;
8611 lli[4] = (byte)(plci->rx_dma_magic >> 8);
8612 lli[5] = (byte)(plci->rx_dma_magic >> 16);
8613 lli[6] = (byte)(plci->rx_dma_magic >> 24);
8614 }
8615 }
8616
8617 if (DIVA_CAPI_SUPPORTS_NO_CANCEL(plci->adapter)) {
8618 lli[1] |= 0x20;
8619 }
8620
8621 llc[1] = (plci->call_dir & (CALL_DIR_ORIGINATE | CALL_DIR_FORCE_OUTG_NL)) ?
8622 /*V42*/ 10 : /*V42_IN*/ 9;
8623 llc[2] = 4; /* pass L3 always transparent */
8624 add_p(plci, LLI, lli);
8625 add_p(plci, LLC, llc);
8626 i = 1;
8627 PUT_WORD (&dlc[i], plci->appl->MaxDataLength);
8628 i += 2;
8629 if (GET_WORD(bp_parms[1].info) == B2_MODEM_EC_COMPRESSION)
8630 {
8631 if (bp_parms[4].length)
8632 {
8633 dbug(1, dprintf("MDM b2_config=%02x", b2_config));
8634 dlc[i++] = 3; /* Addr A */
8635 dlc[i++] = 1; /* Addr B */
8636 dlc[i++] = 7; /* modulo mode */
8637 dlc[i++] = 7; /* window size */
8638 dlc[i++] = 0; /* XID len Lo */
8639 dlc[i++] = 0; /* XID len Hi */
8640
8641 if (b2_config & MDM_B2_DISABLE_V42bis)
8642 {
8643 dlc[i] |= DLC_MODEMPROT_DISABLE_V42_V42BIS;
8644 }
8645 if (b2_config & MDM_B2_DISABLE_MNP)
8646 {
8647 dlc[i] |= DLC_MODEMPROT_DISABLE_MNP_MNP5;
8648 }
8649 if (b2_config & MDM_B2_DISABLE_TRANS)
8650 {
8651 dlc[i] |= DLC_MODEMPROT_REQUIRE_PROTOCOL;
8652 }
8653 if (b2_config & MDM_B2_DISABLE_V42)
8654 {
8655 dlc[i] |= DLC_MODEMPROT_DISABLE_V42_DETECT;
8656 }
8657 if (b2_config & MDM_B2_DISABLE_COMP)
8658 {
8659 dlc[i] |= DLC_MODEMPROT_DISABLE_COMPRESSION;
8660 }
8661 i++;
8662 }
8663 }
8664 else
8665 {
8666 dlc[i++] = 3; /* Addr A */
8667 dlc[i++] = 1; /* Addr B */
8668 dlc[i++] = 7; /* modulo mode */
8669 dlc[i++] = 7; /* window size */
8670 dlc[i++] = 0; /* XID len Lo */
8671 dlc[i++] = 0; /* XID len Hi */
8672 dlc[i++] = DLC_MODEMPROT_DISABLE_V42_V42BIS |
8673 DLC_MODEMPROT_DISABLE_MNP_MNP5 |
8674 DLC_MODEMPROT_DISABLE_V42_DETECT |
8675 DLC_MODEMPROT_DISABLE_COMPRESSION;
8676 }
8677 dlc[0] = (byte)(i - 1);
8678/* HexDump ("DLC", sizeof(dlc), &dlc[0]); */
8679 add_p(plci, DLC, dlc);
8680 return (0);
8681}
8682
8683
8684/*------------------------------------------------------------------*/
8685/* send a request for the signaling entity */
8686/*------------------------------------------------------------------*/
8687
8688void sig_req(PLCI * plci, byte req, byte Id)
8689{
8690 if(!plci) return;
8691 if(plci->adapter->adapter_disabled) return;
8692 dbug(1,dprintf("sig_req(%x)",req));
8693 if (req == REMOVE)
8694 plci->sig_remove_id = plci->Sig.Id;
8695 if(plci->req_in==plci->req_in_start) {
8696 plci->req_in +=2;
8697 plci->RBuffer[plci->req_in++] = 0;
8698 }
8699 PUT_WORD(&plci->RBuffer[plci->req_in_start], plci->req_in-plci->req_in_start-2);
8700 plci->RBuffer[plci->req_in++] = Id; /* sig/nl flag */
8701 plci->RBuffer[plci->req_in++] = req; /* request */
8702 plci->RBuffer[plci->req_in++] = 0; /* channel */
8703 plci->req_in_start = plci->req_in;
8704}
8705
8706/*------------------------------------------------------------------*/
8707/* send a request for the network layer entity */
8708/*------------------------------------------------------------------*/
8709
8710void nl_req_ncci(PLCI * plci, byte req, byte ncci)
8711{
8712 if(!plci) return;
8713 if(plci->adapter->adapter_disabled) return;
8714 dbug(1,dprintf("nl_req %02x %02x %02x", plci->Id, req, ncci));
8715 if (req == REMOVE)
8716 {
8717 plci->nl_remove_id = plci->NL.Id;
8718 ncci_remove (plci, 0, (byte)(ncci != 0));
8719 ncci = 0;
8720 }
8721 if(plci->req_in==plci->req_in_start) {
8722 plci->req_in +=2;
8723 plci->RBuffer[plci->req_in++] = 0;
8724 }
8725 PUT_WORD(&plci->RBuffer[plci->req_in_start], plci->req_in-plci->req_in_start-2);
8726 plci->RBuffer[plci->req_in++] = 1; /* sig/nl flag */
8727 plci->RBuffer[plci->req_in++] = req; /* request */
8728 plci->RBuffer[plci->req_in++] = plci->adapter->ncci_ch[ncci]; /* channel */
8729 plci->req_in_start = plci->req_in;
8730}
8731
8732void send_req(PLCI * plci)
8733{
8734 ENTITY * e;
8735 word l;
8736/* word i; */
8737
8738 if(!plci) return;
8739 if(plci->adapter->adapter_disabled) return;
8740 channel_xmit_xon (plci);
8741
8742 /* if nothing to do, return */
8743 if(plci->req_in==plci->req_out) return;
8744 dbug(1,dprintf("send_req(in=%d,out=%d)",plci->req_in,plci->req_out));
8745
8746 if(plci->nl_req || plci->sig_req) return;
8747
8748 l = GET_WORD(&plci->RBuffer[plci->req_out]);
8749 plci->req_out += 2;
8750 plci->XData[0].P = &plci->RBuffer[plci->req_out];
8751 plci->req_out += l;
8752 if(plci->RBuffer[plci->req_out]==1)
8753 {
8754 e = &plci->NL;
8755 plci->req_out++;
8756 e->Req = plci->nl_req = plci->RBuffer[plci->req_out++];
8757 e->ReqCh = plci->RBuffer[plci->req_out++];
8758 if(!(e->Id & 0x1f))
8759 {
8760 e->Id = NL_ID;
8761 plci->RBuffer[plci->req_out-4] = CAI;
8762 plci->RBuffer[plci->req_out-3] = 1;
8763 plci->RBuffer[plci->req_out-2] = (plci->Sig.Id==0xff) ? 0 : plci->Sig.Id;
8764 plci->RBuffer[plci->req_out-1] = 0;
8765 l+=3;
8766 plci->nl_global_req = plci->nl_req;
8767 }
8768 dbug(1,dprintf("%x:NLREQ(%x:%x:%x)",plci->adapter->Id,e->Id,e->Req,e->ReqCh));
8769 }
8770 else
8771 {
8772 e = &plci->Sig;
8773 if(plci->RBuffer[plci->req_out])
8774 e->Id = plci->RBuffer[plci->req_out];
8775 plci->req_out++;
8776 e->Req = plci->sig_req = plci->RBuffer[plci->req_out++];
8777 e->ReqCh = plci->RBuffer[plci->req_out++];
8778 if(!(e->Id & 0x1f))
8779 plci->sig_global_req = plci->sig_req;
8780 dbug(1,dprintf("%x:SIGREQ(%x:%x:%x)",plci->adapter->Id,e->Id,e->Req,e->ReqCh));
8781 }
8782 plci->XData[0].PLength = l;
8783 e->X = plci->XData;
8784 plci->adapter->request(e);
8785 dbug(1,dprintf("send_ok"));
8786}
8787
8788void send_data(PLCI * plci)
8789{
8790 DIVA_CAPI_ADAPTER * a;
8791 DATA_B3_DESC * data;
8792 NCCI *ncci_ptr;
8793 word ncci;
8794
8795 if (!plci->nl_req && plci->ncci_ring_list)
8796 {
8797 a = plci->adapter;
8798 ncci = plci->ncci_ring_list;
8799 do
8800 {
8801 ncci = a->ncci_next[ncci];
8802 ncci_ptr = &(a->ncci[ncci]);
8803 if (!(a->ncci_ch[ncci]
8804 && (a->ch_flow_control[a->ncci_ch[ncci]] & N_OK_FC_PENDING)))
8805 {
8806 if (ncci_ptr->data_pending)
8807 {
8808 if ((a->ncci_state[ncci] == CONNECTED)
8809 || (a->ncci_state[ncci] == INC_ACT_PENDING)
8810 || (plci->send_disc == ncci))
8811 {
8812 data = &(ncci_ptr->DBuffer[ncci_ptr->data_out]);
8813 if ((plci->B2_prot == B2_V120_ASYNC)
8814 || (plci->B2_prot == B2_V120_ASYNC_V42BIS)
8815 || (plci->B2_prot == B2_V120_BIT_TRANSPARENT))
8816 {
8817 plci->NData[1].P = TransmitBufferGet (plci->appl, data->P);
8818 plci->NData[1].PLength = data->Length;
8819 if (data->Flags & 0x10)
8820 plci->NData[0].P = v120_break_header;
8821 else
8822 plci->NData[0].P = v120_default_header;
8823 plci->NData[0].PLength = 1 ;
8824 plci->NL.XNum = 2;
8825 plci->NL.Req = plci->nl_req = (byte)((data->Flags&0x07)<<4 |N_DATA);
8826 }
8827 else
8828 {
8829 plci->NData[0].P = TransmitBufferGet (plci->appl, data->P);
8830 plci->NData[0].PLength = data->Length;
8831 if (data->Flags & 0x10)
8832 plci->NL.Req = plci->nl_req = (byte)N_UDATA;
8833
8834 else if ((plci->B3_prot == B3_RTP) && (data->Flags & 0x01))
8835 plci->NL.Req = plci->nl_req = (byte)N_BDATA;
8836
8837 else
8838 plci->NL.Req = plci->nl_req = (byte)((data->Flags&0x07)<<4 |N_DATA);
8839 }
8840 plci->NL.X = plci->NData;
8841 plci->NL.ReqCh = a->ncci_ch[ncci];
8842 dbug(1,dprintf("%x:DREQ(%x:%x)",a->Id,plci->NL.Id,plci->NL.Req));
8843 plci->data_sent = TRUE;
8844 plci->data_sent_ptr = data->P;
8845 a->request(&plci->NL);
8846 }
8847 else {
8848 cleanup_ncci_data (plci, ncci);
8849 }
8850 }
8851 else if (plci->send_disc == ncci)
8852 {
8853 /* dprintf("N_DISC"); */
8854 plci->NData[0].PLength = 0;
8855 plci->NL.ReqCh = a->ncci_ch[ncci];
8856 plci->NL.Req = plci->nl_req = N_DISC;
8857 a->request(&plci->NL);
8858 plci->command = _DISCONNECT_B3_R;
8859 plci->send_disc = 0;
8860 }
8861 }
8862 } while (!plci->nl_req && (ncci != plci->ncci_ring_list));
8863 plci->ncci_ring_list = ncci;
8864 }
8865}
8866
8867void listen_check(DIVA_CAPI_ADAPTER * a)
8868{
8869 word i,j;
8870 PLCI * plci;
8871 byte activnotifiedcalls = 0;
8872
8873 dbug(1,dprintf("listen_check(%d,%d)",a->listen_active,a->max_listen));
8874 if (!remove_started && !a->adapter_disabled)
8875 {
8876 for(i=0;i<a->max_plci;i++)
8877 {
8878 plci = &(a->plci[i]);
8879 if(plci->notifiedcall) activnotifiedcalls++;
8880 }
8881 dbug(1,dprintf("listen_check(%d)",activnotifiedcalls));
8882
8883 for(i=a->listen_active; i < ((word)(a->max_listen+activnotifiedcalls)); i++) {
8884 if((j=get_plci(a))) {
8885 a->listen_active++;
8886 plci = &a->plci[j-1];
8887 plci->State = LISTENING;
8888
8889 add_p(plci,OAD,"\x01\xfd");
8890
8891 add_p(plci,KEY,"\x04\x43\x41\x32\x30");
8892
8893 add_p(plci,CAI,"\x01\xc0");
8894 add_p(plci,UID,"\x06\x43\x61\x70\x69\x32\x30");
8895 add_p(plci,LLI,"\x01\xc4"); /* support Dummy CR FAC + MWI + SpoofNotify */
8896 add_p(plci,SHIFT|6,NULL);
8897 add_p(plci,SIN,"\x02\x00\x00");
8898 plci->internal_command = LISTEN_SIG_ASSIGN_PEND; /* do indicate_req if OK */
8899 sig_req(plci,ASSIGN,DSIG_ID);
8900 send_req(plci);
8901 }
8902 }
8903 }
8904}
8905
8906/*------------------------------------------------------------------*/
8907/* functions for all parameters sent in INDs */
8908/*------------------------------------------------------------------*/
8909
8910void IndParse(PLCI * plci, word * parms_id, byte ** parms, byte multiIEsize)
8911{
8912 word ploc; /* points to current location within packet */
8913 byte w;
8914 byte wlen;
8915 byte codeset,lock;
8916 byte * in;
8917 word i;
8918 word code;
8919 word mIEindex = 0;
8920 ploc = 0;
8921 codeset = 0;
8922 lock = 0;
8923
8924 in = plci->Sig.RBuffer->P;
8925 for(i=0; i<parms_id[0]; i++) /* multiIE parms_id contains just the 1st */
8926 { /* element but parms array is larger */
8927 parms[i] = (byte *)"";
8928 }
8929 for(i=0; i<multiIEsize; i++)
8930 {
8931 parms[i] = (byte *)"";
8932 }
8933
8934 while(ploc<plci->Sig.RBuffer->length-1) {
8935
8936 /* read information element id and length */
8937 w = in[ploc];
8938
8939 if(w & 0x80) {
8940/* w &=0xf0; removed, cannot detect congestion levels */
8941/* upper 4 bit masked with w==SHIFT now */
8942 wlen = 0;
8943 }
8944 else {
8945 wlen = (byte)(in[ploc+1]+1);
8946 }
8947 /* check if length valid (not exceeding end of packet) */
8948 if((ploc+wlen) > 270) return ;
8949 if(lock & 0x80) lock &=0x7f;
8950 else codeset = lock;
8951
8952 if((w&0xf0)==SHIFT) {
8953 codeset = in[ploc];
8954 if(!(codeset & 0x08)) lock = (byte)(codeset & 7);
8955 codeset &=7;
8956 lock |=0x80;
8957 }
8958 else {
8959 if(w==ESC && wlen>=3) code = in[ploc+2] |0x800;
8960 else code = w;
8961 code |= (codeset<<8);
8962
8963 for(i=1; i<parms_id[0]+1 && parms_id[i]!=code; i++);
8964
8965 if(i<parms_id[0]+1) {
8966 if(!multiIEsize) { /* with multiIEs use next field index, */
8967 mIEindex = i-1; /* with normal IEs use same index like parms_id */
8968 }
8969
8970 parms[mIEindex] = &in[ploc+1];
8971 dbug(1,dprintf("mIE[%d]=0x%x",*parms[mIEindex],in[ploc]));
8972 if(parms_id[i]==OAD
8973 || parms_id[i]==CONN_NR
8974 || parms_id[i]==CAD) {
8975 if(in[ploc+2] &0x80) {
8976 in[ploc+0] = (byte)(in[ploc+1]+1);
8977 in[ploc+1] = (byte)(in[ploc+2] &0x7f);
8978 in[ploc+2] = 0x80;
8979 parms[mIEindex] = &in[ploc];
8980 }
8981 }
8982 mIEindex++; /* effects multiIEs only */
8983 }
8984 }
8985
8986 ploc +=(wlen+1);
8987 }
8988 return ;
8989}
8990
8991/*------------------------------------------------------------------*/
8992/* try to match a cip from received BC and HLC */
8993/*------------------------------------------------------------------*/
8994
8995byte ie_compare(byte * ie1, byte * ie2)
8996{
8997 word i;
8998 if(!ie1 || ! ie2) return FALSE;
8999 if(!ie1[0]) return FALSE;
9000 for(i=0;i<(word)(ie1[0]+1);i++) if(ie1[i]!=ie2[i]) return FALSE;
9001 return TRUE;
9002}
9003
9004word find_cip(DIVA_CAPI_ADAPTER * a, byte * bc, byte * hlc)
9005{
9006 word i;
9007 word j;
9008
9009 for(i=9;i && !ie_compare(bc,cip_bc[i][a->u_law]);i--);
9010
9011 for(j=16;j<29 &&
9012 (!ie_compare(bc,cip_bc[j][a->u_law]) || !ie_compare(hlc,cip_hlc[j])); j++);
9013 if(j==29) return i;
9014 return j;
9015}
9016
9017
9018static byte AddInfo(byte **add_i,
9019 byte **fty_i,
9020 byte *esc_chi,
9021 byte *facility)
9022{
9023 byte i;
9024 byte j;
9025 byte k;
9026 byte flen;
9027 byte len=0;
9028 /* facility is a nested structure */
9029 /* FTY can be more than once */
9030
9031 if(esc_chi[0] && !(esc_chi[esc_chi[0]])&0x7f )
9032 {
9033 add_i[0] = (byte *)"\x02\x02\x00"; /* use neither b nor d channel */
9034 }
9035
9036 else
9037 {
9038 add_i[0] = (byte *)"";
9039 }
9040 if(!fty_i[0][0])
9041 {
9042 add_i[3] = (byte *)"";
9043 }
9044 else
9045 { /* facility array found */
9046 for(i=0,j=1;i<MAX_MULTI_IE && fty_i[i][0];i++)
9047 {
9048 dbug(1,dprintf("AddIFac[%d]",fty_i[i][0]));
9049 len += fty_i[i][0];
9050 len += 2;
9051 flen=fty_i[i][0];
9052 facility[j++]=0x1c; /* copy fac IE */
9053 for(k=0;k<=flen;k++,j++)
9054 {
9055 facility[j]=fty_i[i][k];
9056/* dbug(1,dprintf("%x ",facility[j])); */
9057 }
9058 }
9059 facility[0] = len;
9060 add_i[3] = facility;
9061 }
9062/* dbug(1,dprintf("FacArrLen=%d ",len)); */
9063 len = add_i[0][0]+add_i[1][0]+add_i[2][0]+add_i[3][0];
9064 len += 4; /* calculate length of all */
9065 return(len);
9066}
9067
9068/*------------------------------------------------------------------*/
9069/* voice and codec features */
9070/*------------------------------------------------------------------*/
9071
9072void SetVoiceChannel(PLCI *plci, byte *chi, DIVA_CAPI_ADAPTER * a)
9073{
9074 byte voice_chi[] = "\x02\x18\x01";
9075 byte channel;
9076
9077 channel = chi[chi[0]]&0x3;
9078 dbug(1,dprintf("ExtDevON(Ch=0x%x)",channel));
9079 voice_chi[2] = (channel) ? channel : 1;
9080 add_p(plci,FTY,"\x02\x01\x07"); /* B On, default on 1 */
9081 add_p(plci,ESC,voice_chi); /* Channel */
9082 sig_req(plci,TEL_CTRL,0);
9083 send_req(plci);
9084 if(a->AdvSignalPLCI)
9085 {
9086 adv_voice_write_coefs (a->AdvSignalPLCI, ADV_VOICE_WRITE_ACTIVATION);
9087 }
9088}
9089
9090void VoiceChannelOff(PLCI *plci)
9091{
9092 dbug(1,dprintf("ExtDevOFF"));
9093 add_p(plci,FTY,"\x02\x01\x08"); /* B Off */
9094 sig_req(plci,TEL_CTRL,0);
9095 send_req(plci);
9096 if(plci->adapter->AdvSignalPLCI)
9097 {
9098 adv_voice_clear_config (plci->adapter->AdvSignalPLCI);
9099 }
9100}
9101
9102
9103word AdvCodecSupport(DIVA_CAPI_ADAPTER *a, PLCI *plci, APPL *appl, byte hook_listen)
9104{
9105 word j;
9106 PLCI *splci;
9107
9108 /* check if hardware supports handset with hook states (adv.codec) */
9109 /* or if just a on board codec is supported */
9110 /* the advanced codec plci is just for internal use */
9111
9112 /* diva Pro with on-board codec: */
9113 if(a->profile.Global_Options & HANDSET)
9114 {
9115 /* new call, but hook states are already signalled */
9116 if(a->AdvCodecFLAG)
9117 {
9118 if(a->AdvSignalAppl!=appl || a->AdvSignalPLCI)
9119 {
9120 dbug(1,dprintf("AdvSigPlci=0x%x",a->AdvSignalPLCI));
9121 return 0x2001; /* codec in use by another application */
9122 }
9123 if(plci!=0)
9124 {
9125 a->AdvSignalPLCI = plci;
9126 plci->tel=ADV_VOICE;
9127 }
9128 return 0; /* adv codec still used */
9129 }
9130 if((j=get_plci(a)))
9131 {
9132 splci = &a->plci[j-1];
9133 splci->tel = CODEC_PERMANENT;
9134 /* hook_listen indicates if a facility_req with handset/hook support */
9135 /* was sent. Otherwise if just a call on an external device was made */
9136 /* the codec will be used but the hook info will be discarded (just */
9137 /* the external controller is in use */
9138 if(hook_listen) splci->State = ADVANCED_VOICE_SIG;
9139 else
9140 {
9141 splci->State = ADVANCED_VOICE_NOSIG;
9142 if(plci)
9143 {
9144 plci->spoofed_msg = SPOOFING_REQUIRED;
9145 }
9146 /* indicate D-ch connect if */
9147 } /* codec is connected OK */
9148 if(plci!=0)
9149 {
9150 a->AdvSignalPLCI = plci;
9151 plci->tel=ADV_VOICE;
9152 }
9153 a->AdvSignalAppl = appl;
9154 a->AdvCodecFLAG = TRUE;
9155 a->AdvCodecPLCI = splci;
9156 add_p(splci,CAI,"\x01\x15");
9157 add_p(splci,LLI,"\x01\x00");
9158 add_p(splci,ESC,"\x02\x18\x00");
9159 add_p(splci,UID,"\x06\x43\x61\x70\x69\x32\x30");
9160 splci->internal_command = PERM_COD_ASSIGN;
9161 dbug(1,dprintf("Codec Assign"));
9162 sig_req(splci,ASSIGN,DSIG_ID);
9163 send_req(splci);
9164 }
9165 else
9166 {
9167 return 0x2001; /* wrong state, no more plcis */
9168 }
9169 }
9170 else if(a->profile.Global_Options & ON_BOARD_CODEC)
9171 {
9172 if(hook_listen) return 0x300B; /* Facility not supported */
9173 /* no hook with SCOM */
9174 if(plci!=0) plci->tel = CODEC;
9175 dbug(1,dprintf("S/SCOM codec"));
9176 /* first time we use the scom-s codec we must shut down the internal */
9177 /* handset application of the card. This can be done by an assign with */
9178 /* a cai with the 0x80 bit set. Assign return code is 'out of resource'*/
9179 if(!a->scom_appl_disable){
9180 if((j=get_plci(a))) {
9181 splci = &a->plci[j-1];
9182 add_p(splci,CAI,"\x01\x80");
9183 add_p(splci,UID,"\x06\x43\x61\x70\x69\x32\x30");
9184 sig_req(splci,ASSIGN,0xC0); /* 0xc0 is the TEL_ID */
9185 send_req(splci);
9186 a->scom_appl_disable = TRUE;
9187 }
9188 else{
9189 return 0x2001; /* wrong state, no more plcis */
9190 }
9191 }
9192 }
9193 else return 0x300B; /* Facility not supported */
9194
9195 return 0;
9196}
9197
9198
9199void CodecIdCheck(DIVA_CAPI_ADAPTER *a, PLCI *plci)
9200{
9201
9202 dbug(1,dprintf("CodecIdCheck"));
9203
9204 if(a->AdvSignalPLCI == plci)
9205 {
9206 dbug(1,dprintf("PLCI owns codec"));
9207 VoiceChannelOff(a->AdvCodecPLCI);
9208 if(a->AdvCodecPLCI->State == ADVANCED_VOICE_NOSIG)
9209 {
9210 dbug(1,dprintf("remove temp codec PLCI"));
9211 plci_remove(a->AdvCodecPLCI);
9212 a->AdvCodecFLAG = 0;
9213 a->AdvCodecPLCI = NULL;
9214 a->AdvSignalAppl = NULL;
9215 }
9216 a->AdvSignalPLCI = NULL;
9217 }
9218}
9219
9220/* -------------------------------------------------------------------
9221 Ask for physical address of card on PCI bus
9222 ------------------------------------------------------------------- */
9223static void diva_ask_for_xdi_sdram_bar (DIVA_CAPI_ADAPTER * a,
9224 IDI_SYNC_REQ * preq) {
9225 a->sdram_bar = 0;
9226 if (diva_xdi_extended_features & DIVA_CAPI_XDI_PROVIDES_SDRAM_BAR) {
9227 ENTITY * e = (ENTITY *)preq;
9228
9229 e->user[0] = a->Id - 1;
9230 preq->xdi_sdram_bar.info.bar = 0;
9231 preq->xdi_sdram_bar.Req = 0;
9232 preq->xdi_sdram_bar.Rc = IDI_SYNC_REQ_XDI_GET_ADAPTER_SDRAM_BAR;
9233
9234 (*(a->request))(e);
9235
9236 a->sdram_bar = preq->xdi_sdram_bar.info.bar;
9237 dbug(3,dprintf("A(%d) SDRAM BAR = %08x", a->Id, a->sdram_bar));
9238 }
9239}
9240
9241/* -------------------------------------------------------------------
9242 Ask XDI about extended features
9243 ------------------------------------------------------------------- */
9244static void diva_get_extended_adapter_features (DIVA_CAPI_ADAPTER * a) {
9245 IDI_SYNC_REQ * preq;
9246 char buffer[ ((sizeof(preq->xdi_extended_features)+4) > sizeof(ENTITY)) ? (sizeof(preq->xdi_extended_features)+4) : sizeof(ENTITY)];
9247
9248 char features[4];
9249 preq = (IDI_SYNC_REQ *)&buffer[0];
9250
9251 if (!diva_xdi_extended_features) {
9252 ENTITY * e = (ENTITY *)preq;
9253 diva_xdi_extended_features |= 0x80000000;
9254
9255 e->user[0] = a->Id - 1;
9256 preq->xdi_extended_features.Req = 0;
9257 preq->xdi_extended_features.Rc = IDI_SYNC_REQ_XDI_GET_EXTENDED_FEATURES;
9258 preq->xdi_extended_features.info.buffer_length_in_bytes = sizeof(features);
9259 preq->xdi_extended_features.info.features = &features[0];
9260
9261 (*(a->request))(e);
9262
9263 if (features[0] & DIVA_XDI_EXTENDED_FEATURES_VALID) {
9264 /*
9265 Check features located in the byte '0'
9266 */
9267 if (features[0] & DIVA_XDI_EXTENDED_FEATURE_CMA) {
9268 diva_xdi_extended_features |= DIVA_CAPI_USE_CMA;
9269 }
9270 if (features[0] & DIVA_XDI_EXTENDED_FEATURE_RX_DMA) {
9271 diva_xdi_extended_features |= DIVA_CAPI_XDI_PROVIDES_RX_DMA;
9272 dbug(1,dprintf("XDI provides RxDMA"));
9273 }
9274 if (features[0] & DIVA_XDI_EXTENDED_FEATURE_SDRAM_BAR) {
9275 diva_xdi_extended_features |= DIVA_CAPI_XDI_PROVIDES_SDRAM_BAR;
9276 }
9277 if (features[0] & DIVA_XDI_EXTENDED_FEATURE_NO_CANCEL_RC) {
9278 diva_xdi_extended_features |= DIVA_CAPI_XDI_PROVIDES_NO_CANCEL;
9279 dbug(3,dprintf("XDI provides NO_CANCEL_RC feature"));
9280 }
9281
9282 }
9283 }
9284
9285 diva_ask_for_xdi_sdram_bar (a, preq);
9286}
9287
9288/*------------------------------------------------------------------*/
9289/* automatic law */
9290/*------------------------------------------------------------------*/
9291/* called from OS specific part after init time to get the Law */
9292/* a-law (Euro) and u-law (us,japan) use different BCs in the Setup message */
9293void AutomaticLaw(DIVA_CAPI_ADAPTER *a)
9294{
9295 word j;
9296 PLCI *splci;
9297
9298 if(a->automatic_law) {
9299 return;
9300 }
9301 if((j=get_plci(a))) {
9302 diva_get_extended_adapter_features (a);
9303 splci = &a->plci[j-1];
9304 a->automatic_lawPLCI = splci;
9305 a->automatic_law = 1;
9306 add_p(splci,CAI,"\x01\x80");
9307 add_p(splci,UID,"\x06\x43\x61\x70\x69\x32\x30");
9308 splci->internal_command = USELAW_REQ;
9309 splci->command = 0;
9310 splci->number = 0;
9311 sig_req(splci,ASSIGN,DSIG_ID);
9312 send_req(splci);
9313 }
9314}
9315
9316/* called from OS specific part if an application sends an Capi20Release */
9317word CapiRelease(word Id)
9318{
9319 word i, j, appls_found;
9320 PLCI *plci;
9321 APPL *this;
9322 DIVA_CAPI_ADAPTER *a;
9323
9324 if (!Id)
9325 {
9326 dbug(0,dprintf("A: CapiRelease(Id==0)"));
9327 return (_WRONG_APPL_ID);
9328 }
9329
9330 this = &application[Id-1]; /* get application pointer */
9331
9332 for(i=0,appls_found=0; i<max_appl; i++)
9333 {
9334 if(application[i].Id) /* an application has been found */
9335 {
9336 appls_found++;
9337 }
9338 }
9339
9340 for(i=0; i<max_adapter; i++) /* scan all adapters... */
9341 {
9342 a = &adapter[i];
9343 if (a->request)
9344 {
9345 a->Info_Mask[Id-1] = 0;
9346 a->CIP_Mask[Id-1] = 0;
9347 a->Notification_Mask[Id-1] = 0;
9348 a->codec_listen[Id-1] = NULL;
9349 a->requested_options_table[Id-1] = 0;
9350 for(j=0; j<a->max_plci; j++) /* and all PLCIs connected */
9351 { /* with this application */
9352 plci = &a->plci[j];
9353 if(plci->Id) /* if plci owns no application */
9354 { /* it may be not jet connected */
9355 if(plci->State==INC_CON_PENDING
9356 || plci->State==INC_CON_ALERT)
9357 {
9358 if(test_c_ind_mask_bit (plci, (word)(Id-1)))
9359 {
9360 clear_c_ind_mask_bit (plci, (word)(Id-1));
9361 if(c_ind_mask_empty (plci))
9362 {
9363 sig_req(plci,HANGUP,0);
9364 send_req(plci);
9365 plci->State = OUTG_DIS_PENDING;
9366 }
9367 }
9368 }
9369 if(test_c_ind_mask_bit (plci, (word)(Id-1)))
9370 {
9371 clear_c_ind_mask_bit (plci, (word)(Id-1));
9372 if(c_ind_mask_empty (plci))
9373 {
9374 if(!plci->appl)
9375 {
9376 plci_remove(plci);
9377 plci->State = IDLE;
9378 }
9379 }
9380 }
9381 if(plci->appl==this)
9382 {
9383 plci->appl = NULL;
9384 plci_remove(plci);
9385 plci->State = IDLE;
9386 }
9387 }
9388 }
9389 listen_check(a);
9390
9391 if(a->flag_dynamic_l1_down)
9392 {
9393 if(appls_found==1) /* last application does a capi release */
9394 {
9395 if((j=get_plci(a)))
9396 {
9397 plci = &a->plci[j-1];
9398 plci->command = 0;
9399 add_p(plci,OAD,"\x01\xfd");
9400 add_p(plci,CAI,"\x01\x80");
9401 add_p(plci,UID,"\x06\x43\x61\x70\x69\x32\x30");
9402 add_p(plci,SHIFT|6,NULL);
9403 add_p(plci,SIN,"\x02\x00\x00");
9404 plci->internal_command = REM_L1_SIG_ASSIGN_PEND;
9405 sig_req(plci,ASSIGN,DSIG_ID);
9406 add_p(plci,FTY,"\x02\xff\x06"); /* l1 down */
9407 sig_req(plci,SIG_CTRL,0);
9408 send_req(plci);
9409 }
9410 }
9411 }
9412 if(a->AdvSignalAppl==this)
9413 {
9414 this->NullCREnable = FALSE;
9415 if (a->AdvCodecPLCI)
9416 {
9417 plci_remove(a->AdvCodecPLCI);
9418 a->AdvCodecPLCI->tel = 0;
9419 a->AdvCodecPLCI->adv_nl = 0;
9420 }
9421 a->AdvSignalAppl = NULL;
9422 a->AdvSignalPLCI = NULL;
9423 a->AdvCodecFLAG = 0;
9424 a->AdvCodecPLCI = NULL;
9425 }
9426 }
9427 }
9428
9429 this->Id = 0;
9430
9431 return GOOD;
9432}
9433
9434static word plci_remove_check(PLCI *plci)
9435{
9436 if(!plci) return TRUE;
9437 if(!plci->NL.Id && c_ind_mask_empty (plci))
9438 {
9439 if(plci->Sig.Id == 0xff)
9440 plci->Sig.Id = 0;
9441 if(!plci->Sig.Id)
9442 {
9443 dbug(1,dprintf("plci_remove_complete(%x)",plci->Id));
9444 dbug(1,dprintf("tel=0x%x,Sig=0x%x",plci->tel,plci->Sig.Id));
9445 if (plci->Id)
9446 {
9447 CodecIdCheck(plci->adapter, plci);
9448 clear_b1_config (plci);
9449 ncci_remove (plci, 0, FALSE);
9450 plci_free_msg_in_queue (plci);
9451 channel_flow_control_remove (plci);
9452 plci->Id = 0;
9453 plci->State = IDLE;
9454 plci->channels = 0;
9455 plci->appl = NULL;
9456 plci->notifiedcall = 0;
9457 }
9458 listen_check(plci->adapter);
9459 return TRUE;
9460 }
9461 }
9462 return FALSE;
9463}
9464
9465
9466/*------------------------------------------------------------------*/
9467
9468static byte plci_nl_busy (PLCI *plci)
9469{
9470 /* only applicable for non-multiplexed protocols */
9471 return (plci->nl_req
9472 || (plci->ncci_ring_list
9473 && plci->adapter->ncci_ch[plci->ncci_ring_list]
9474 && (plci->adapter->ch_flow_control[plci->adapter->ncci_ch[plci->ncci_ring_list]] & N_OK_FC_PENDING)));
9475}
9476
9477
9478/*------------------------------------------------------------------*/
9479/* DTMF facilities */
9480/*------------------------------------------------------------------*/
9481
9482
9483static struct
9484{
9485 byte send_mask;
9486 byte listen_mask;
9487 byte character;
9488 byte code;
9489} dtmf_digit_map[] =
9490{
9491 { 0x01, 0x01, 0x23, DTMF_DIGIT_TONE_CODE_HASHMARK },
9492 { 0x01, 0x01, 0x2a, DTMF_DIGIT_TONE_CODE_STAR },
9493 { 0x01, 0x01, 0x30, DTMF_DIGIT_TONE_CODE_0 },
9494 { 0x01, 0x01, 0x31, DTMF_DIGIT_TONE_CODE_1 },
9495 { 0x01, 0x01, 0x32, DTMF_DIGIT_TONE_CODE_2 },
9496 { 0x01, 0x01, 0x33, DTMF_DIGIT_TONE_CODE_3 },
9497 { 0x01, 0x01, 0x34, DTMF_DIGIT_TONE_CODE_4 },
9498 { 0x01, 0x01, 0x35, DTMF_DIGIT_TONE_CODE_5 },
9499 { 0x01, 0x01, 0x36, DTMF_DIGIT_TONE_CODE_6 },
9500 { 0x01, 0x01, 0x37, DTMF_DIGIT_TONE_CODE_7 },
9501 { 0x01, 0x01, 0x38, DTMF_DIGIT_TONE_CODE_8 },
9502 { 0x01, 0x01, 0x39, DTMF_DIGIT_TONE_CODE_9 },
9503 { 0x01, 0x01, 0x41, DTMF_DIGIT_TONE_CODE_A },
9504 { 0x01, 0x01, 0x42, DTMF_DIGIT_TONE_CODE_B },
9505 { 0x01, 0x01, 0x43, DTMF_DIGIT_TONE_CODE_C },
9506 { 0x01, 0x01, 0x44, DTMF_DIGIT_TONE_CODE_D },
9507 { 0x01, 0x00, 0x61, DTMF_DIGIT_TONE_CODE_A },
9508 { 0x01, 0x00, 0x62, DTMF_DIGIT_TONE_CODE_B },
9509 { 0x01, 0x00, 0x63, DTMF_DIGIT_TONE_CODE_C },
9510 { 0x01, 0x00, 0x64, DTMF_DIGIT_TONE_CODE_D },
9511
9512 { 0x04, 0x04, 0x80, DTMF_SIGNAL_NO_TONE },
9513 { 0x00, 0x04, 0x81, DTMF_SIGNAL_UNIDENTIFIED_TONE },
9514 { 0x04, 0x04, 0x82, DTMF_SIGNAL_DIAL_TONE },
9515 { 0x04, 0x04, 0x83, DTMF_SIGNAL_PABX_INTERNAL_DIAL_TONE },
9516 { 0x04, 0x04, 0x84, DTMF_SIGNAL_SPECIAL_DIAL_TONE },
9517 { 0x04, 0x04, 0x85, DTMF_SIGNAL_SECOND_DIAL_TONE },
9518 { 0x04, 0x04, 0x86, DTMF_SIGNAL_RINGING_TONE },
9519 { 0x04, 0x04, 0x87, DTMF_SIGNAL_SPECIAL_RINGING_TONE },
9520 { 0x04, 0x04, 0x88, DTMF_SIGNAL_BUSY_TONE },
9521 { 0x04, 0x04, 0x89, DTMF_SIGNAL_CONGESTION_TONE },
9522 { 0x04, 0x04, 0x8a, DTMF_SIGNAL_SPECIAL_INFORMATION_TONE },
9523 { 0x04, 0x04, 0x8b, DTMF_SIGNAL_COMFORT_TONE },
9524 { 0x04, 0x04, 0x8c, DTMF_SIGNAL_HOLD_TONE },
9525 { 0x04, 0x04, 0x8d, DTMF_SIGNAL_RECORD_TONE },
9526 { 0x04, 0x04, 0x8e, DTMF_SIGNAL_CALLER_WAITING_TONE },
9527 { 0x04, 0x04, 0x8f, DTMF_SIGNAL_CALL_WAITING_TONE },
9528 { 0x04, 0x04, 0x90, DTMF_SIGNAL_PAY_TONE },
9529 { 0x04, 0x04, 0x91, DTMF_SIGNAL_POSITIVE_INDICATION_TONE },
9530 { 0x04, 0x04, 0x92, DTMF_SIGNAL_NEGATIVE_INDICATION_TONE },
9531 { 0x04, 0x04, 0x93, DTMF_SIGNAL_WARNING_TONE },
9532 { 0x04, 0x04, 0x94, DTMF_SIGNAL_INTRUSION_TONE },
9533 { 0x04, 0x04, 0x95, DTMF_SIGNAL_CALLING_CARD_SERVICE_TONE },
9534 { 0x04, 0x04, 0x96, DTMF_SIGNAL_PAYPHONE_RECOGNITION_TONE },
9535 { 0x04, 0x04, 0x97, DTMF_SIGNAL_CPE_ALERTING_SIGNAL },
9536 { 0x04, 0x04, 0x98, DTMF_SIGNAL_OFF_HOOK_WARNING_TONE },
9537 { 0x04, 0x04, 0xbf, DTMF_SIGNAL_INTERCEPT_TONE },
9538 { 0x04, 0x04, 0xc0, DTMF_SIGNAL_MODEM_CALLING_TONE },
9539 { 0x04, 0x04, 0xc1, DTMF_SIGNAL_FAX_CALLING_TONE },
9540 { 0x04, 0x04, 0xc2, DTMF_SIGNAL_ANSWER_TONE },
9541 { 0x04, 0x04, 0xc3, DTMF_SIGNAL_REVERSED_ANSWER_TONE },
9542 { 0x04, 0x04, 0xc4, DTMF_SIGNAL_ANSAM_TONE },
9543 { 0x04, 0x04, 0xc5, DTMF_SIGNAL_REVERSED_ANSAM_TONE },
9544 { 0x04, 0x04, 0xc6, DTMF_SIGNAL_BELL103_ANSWER_TONE },
9545 { 0x04, 0x04, 0xc7, DTMF_SIGNAL_FAX_FLAGS },
9546 { 0x04, 0x04, 0xc8, DTMF_SIGNAL_G2_FAX_GROUP_ID },
9547 { 0x00, 0x04, 0xc9, DTMF_SIGNAL_HUMAN_SPEECH },
9548 { 0x04, 0x04, 0xca, DTMF_SIGNAL_ANSWERING_MACHINE_390 },
9549 { 0x02, 0x02, 0xf1, DTMF_MF_DIGIT_TONE_CODE_1 },
9550 { 0x02, 0x02, 0xf2, DTMF_MF_DIGIT_TONE_CODE_2 },
9551 { 0x02, 0x02, 0xf3, DTMF_MF_DIGIT_TONE_CODE_3 },
9552 { 0x02, 0x02, 0xf4, DTMF_MF_DIGIT_TONE_CODE_4 },
9553 { 0x02, 0x02, 0xf5, DTMF_MF_DIGIT_TONE_CODE_5 },
9554 { 0x02, 0x02, 0xf6, DTMF_MF_DIGIT_TONE_CODE_6 },
9555 { 0x02, 0x02, 0xf7, DTMF_MF_DIGIT_TONE_CODE_7 },
9556 { 0x02, 0x02, 0xf8, DTMF_MF_DIGIT_TONE_CODE_8 },
9557 { 0x02, 0x02, 0xf9, DTMF_MF_DIGIT_TONE_CODE_9 },
9558 { 0x02, 0x02, 0xfa, DTMF_MF_DIGIT_TONE_CODE_0 },
9559 { 0x02, 0x02, 0xfb, DTMF_MF_DIGIT_TONE_CODE_K1 },
9560 { 0x02, 0x02, 0xfc, DTMF_MF_DIGIT_TONE_CODE_K2 },
9561 { 0x02, 0x02, 0xfd, DTMF_MF_DIGIT_TONE_CODE_KP },
9562 { 0x02, 0x02, 0xfe, DTMF_MF_DIGIT_TONE_CODE_S1 },
9563 { 0x02, 0x02, 0xff, DTMF_MF_DIGIT_TONE_CODE_ST },
9564
9565};
9566
9567#define DTMF_DIGIT_MAP_ENTRIES (sizeof(dtmf_digit_map) / sizeof(dtmf_digit_map[0]))
9568
9569
9570static void dtmf_enable_receiver (PLCI *plci, byte enable_mask)
9571{
9572 word min_digit_duration, min_gap_duration;
9573
9574 dbug (1, dprintf ("[%06lx] %s,%d: dtmf_enable_receiver %02x",
9575 (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
9576 (char *)(FILE_), __LINE__, enable_mask));
9577
9578 if (enable_mask != 0)
9579 {
9580 min_digit_duration = (plci->dtmf_rec_pulse_ms == 0) ? 40 : plci->dtmf_rec_pulse_ms;
9581 min_gap_duration = (plci->dtmf_rec_pause_ms == 0) ? 40 : plci->dtmf_rec_pause_ms;
9582 plci->internal_req_buffer[0] = DTMF_UDATA_REQUEST_ENABLE_RECEIVER;
9583 PUT_WORD (&plci->internal_req_buffer[1], min_digit_duration);
9584 PUT_WORD (&plci->internal_req_buffer[3], min_gap_duration);
9585 plci->NData[0].PLength = 5;
9586
9587 PUT_WORD (&plci->internal_req_buffer[5], INTERNAL_IND_BUFFER_SIZE);
9588 plci->NData[0].PLength += 2;
9589 capidtmf_recv_enable (&(plci->capidtmf_state), min_digit_duration, min_gap_duration);
9590
9591 }
9592 else
9593 {
9594 plci->internal_req_buffer[0] = DTMF_UDATA_REQUEST_DISABLE_RECEIVER;
9595 plci->NData[0].PLength = 1;
9596
9597 capidtmf_recv_disable (&(plci->capidtmf_state));
9598
9599 }
9600 plci->NData[0].P = plci->internal_req_buffer;
9601 plci->NL.X = plci->NData;
9602 plci->NL.ReqCh = 0;
9603 plci->NL.Req = plci->nl_req = (byte) N_UDATA;
9604 plci->adapter->request (&plci->NL);
9605}
9606
9607
9608static void dtmf_send_digits (PLCI *plci, byte *digit_buffer, word digit_count)
9609{
9610 word w, i;
9611
9612 dbug (1, dprintf ("[%06lx] %s,%d: dtmf_send_digits %d",
9613 (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
9614 (char *)(FILE_), __LINE__, digit_count));
9615
9616 plci->internal_req_buffer[0] = DTMF_UDATA_REQUEST_SEND_DIGITS;
9617 w = (plci->dtmf_send_pulse_ms == 0) ? 40 : plci->dtmf_send_pulse_ms;
9618 PUT_WORD (&plci->internal_req_buffer[1], w);
9619 w = (plci->dtmf_send_pause_ms == 0) ? 40 : plci->dtmf_send_pause_ms;
9620 PUT_WORD (&plci->internal_req_buffer[3], w);
9621 for (i = 0; i < digit_count; i++)
9622 {
9623 w = 0;
9624 while ((w < DTMF_DIGIT_MAP_ENTRIES)
9625 && (digit_buffer[i] != dtmf_digit_map[w].character))
9626 {
9627 w++;
9628 }
9629 plci->internal_req_buffer[5+i] = (w < DTMF_DIGIT_MAP_ENTRIES) ?
9630 dtmf_digit_map[w].code : DTMF_DIGIT_TONE_CODE_STAR;
9631 }
9632 plci->NData[0].PLength = 5 + digit_count;
9633 plci->NData[0].P = plci->internal_req_buffer;
9634 plci->NL.X = plci->NData;
9635 plci->NL.ReqCh = 0;
9636 plci->NL.Req = plci->nl_req = (byte) N_UDATA;
9637 plci->adapter->request (&plci->NL);
9638}
9639
9640
9641static void dtmf_rec_clear_config (PLCI *plci)
9642{
9643
9644 dbug (1, dprintf ("[%06lx] %s,%d: dtmf_rec_clear_config",
9645 (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
9646 (char *)(FILE_), __LINE__));
9647
9648 plci->dtmf_rec_active = 0;
9649 plci->dtmf_rec_pulse_ms = 0;
9650 plci->dtmf_rec_pause_ms = 0;
9651
9652 capidtmf_init (&(plci->capidtmf_state), plci->adapter->u_law);
9653
9654}
9655
9656
9657static void dtmf_send_clear_config (PLCI *plci)
9658{
9659
9660 dbug (1, dprintf ("[%06lx] %s,%d: dtmf_send_clear_config",
9661 (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
9662 (char *)(FILE_), __LINE__));
9663
9664 plci->dtmf_send_requests = 0;
9665 plci->dtmf_send_pulse_ms = 0;
9666 plci->dtmf_send_pause_ms = 0;
9667}
9668
9669
9670static void dtmf_prepare_switch (dword Id, PLCI *plci)
9671{
9672
9673 dbug (1, dprintf ("[%06lx] %s,%d: dtmf_prepare_switch",
9674 UnMapId (Id), (char *)(FILE_), __LINE__));
9675
9676 while (plci->dtmf_send_requests != 0)
9677 dtmf_confirmation (Id, plci);
9678}
9679
9680
9681static word dtmf_save_config (dword Id, PLCI *plci, byte Rc)
9682{
9683
9684 dbug (1, dprintf ("[%06lx] %s,%d: dtmf_save_config %02x %d",
9685 UnMapId (Id), (char *)(FILE_), __LINE__, Rc, plci->adjust_b_state));
9686
9687 return (GOOD);
9688}
9689
9690
9691static word dtmf_restore_config (dword Id, PLCI *plci, byte Rc)
9692{
9693 word Info;
9694
9695 dbug (1, dprintf ("[%06lx] %s,%d: dtmf_restore_config %02x %d",
9696 UnMapId (Id), (char *)(FILE_), __LINE__, Rc, plci->adjust_b_state));
9697
9698 Info = GOOD;
9699 if (plci->B1_facilities & B1_FACILITY_DTMFR)
9700 {
9701 switch (plci->adjust_b_state)
9702 {
9703 case ADJUST_B_RESTORE_DTMF_1:
9704 plci->internal_command = plci->adjust_b_command;
9705 if (plci_nl_busy (plci))
9706 {
9707 plci->adjust_b_state = ADJUST_B_RESTORE_DTMF_1;
9708 break;
9709 }
9710 dtmf_enable_receiver (plci, plci->dtmf_rec_active);
9711 plci->adjust_b_state = ADJUST_B_RESTORE_DTMF_2;
9712 break;
9713 case ADJUST_B_RESTORE_DTMF_2:
9714 if ((Rc != OK) && (Rc != OK_FC))
9715 {
9716 dbug (1, dprintf ("[%06lx] %s,%d: Reenable DTMF receiver failed %02x",
9717 UnMapId (Id), (char *)(FILE_), __LINE__, Rc));
9718 Info = _WRONG_STATE;
9719 break;
9720 }
9721 break;
9722 }
9723 }
9724 return (Info);
9725}
9726
9727
9728static void dtmf_command (dword Id, PLCI *plci, byte Rc)
9729{
9730 word internal_command, Info;
9731 byte mask;
9732 byte result[4];
9733
9734 dbug (1, dprintf ("[%06lx] %s,%d: dtmf_command %02x %04x %04x %d %d %d %d",
9735 UnMapId (Id), (char *)(FILE_), __LINE__, Rc, plci->internal_command,
9736 plci->dtmf_cmd, plci->dtmf_rec_pulse_ms, plci->dtmf_rec_pause_ms,
9737 plci->dtmf_send_pulse_ms, plci->dtmf_send_pause_ms));
9738
9739 Info = GOOD;
9740 result[0] = 2;
9741 PUT_WORD (&result[1], DTMF_SUCCESS);
9742 internal_command = plci->internal_command;
9743 plci->internal_command = 0;
9744 mask = 0x01;
9745 switch (plci->dtmf_cmd)
9746 {
9747
9748 case DTMF_LISTEN_TONE_START:
9749 mask <<= 1;
9750 case DTMF_LISTEN_MF_START:
9751 mask <<= 1;
9752
9753 case DTMF_LISTEN_START:
9754 switch (internal_command)
9755 {
9756 default:
9757 adjust_b1_resource (Id, plci, NULL, (word)(plci->B1_facilities |
9758 B1_FACILITY_DTMFR), DTMF_COMMAND_1);
9759 case DTMF_COMMAND_1:
9760 if (adjust_b_process (Id, plci, Rc) != GOOD)
9761 {
9762 dbug (1, dprintf ("[%06lx] %s,%d: Load DTMF failed",
9763 UnMapId (Id), (char *)(FILE_), __LINE__));
9764 Info = _FACILITY_NOT_SUPPORTED;
9765 break;
9766 }
9767 if (plci->internal_command)
9768 return;
9769 case DTMF_COMMAND_2:
9770 if (plci_nl_busy (plci))
9771 {
9772 plci->internal_command = DTMF_COMMAND_2;
9773 return;
9774 }
9775 plci->internal_command = DTMF_COMMAND_3;
9776 dtmf_enable_receiver (plci, (byte)(plci->dtmf_rec_active | mask));
9777 return;
9778 case DTMF_COMMAND_3:
9779 if ((Rc != OK) && (Rc != OK_FC))
9780 {
9781 dbug (1, dprintf ("[%06lx] %s,%d: Enable DTMF receiver failed %02x",
9782 UnMapId (Id), (char *)(FILE_), __LINE__, Rc));
9783 Info = _FACILITY_NOT_SUPPORTED;
9784 break;
9785 }
9786
9787 plci->tone_last_indication_code = DTMF_SIGNAL_NO_TONE;
9788
9789 plci->dtmf_rec_active |= mask;
9790 break;
9791 }
9792 break;
9793
9794
9795 case DTMF_LISTEN_TONE_STOP:
9796 mask <<= 1;
9797 case DTMF_LISTEN_MF_STOP:
9798 mask <<= 1;
9799
9800 case DTMF_LISTEN_STOP:
9801 switch (internal_command)
9802 {
9803 default:
9804 plci->dtmf_rec_active &= ~mask;
9805 if (plci->dtmf_rec_active)
9806 break;
9807/*
9808 case DTMF_COMMAND_1:
9809 if (plci->dtmf_rec_active)
9810 {
9811 if (plci_nl_busy (plci))
9812 {
9813 plci->internal_command = DTMF_COMMAND_1;
9814 return;
9815 }
9816 plci->dtmf_rec_active &= ~mask;
9817 plci->internal_command = DTMF_COMMAND_2;
9818 dtmf_enable_receiver (plci, FALSE);
9819 return;
9820 }
9821 Rc = OK;
9822 case DTMF_COMMAND_2:
9823 if ((Rc != OK) && (Rc != OK_FC))
9824 {
9825 dbug (1, dprintf ("[%06lx] %s,%d: Disable DTMF receiver failed %02x",
9826 UnMapId (Id), (char far *)(FILE_), __LINE__, Rc));
9827 Info = _FACILITY_NOT_SUPPORTED;
9828 break;
9829 }
9830*/
9831 adjust_b1_resource (Id, plci, NULL, (word)(plci->B1_facilities &
9832 ~(B1_FACILITY_DTMFX | B1_FACILITY_DTMFR)), DTMF_COMMAND_3);
9833 case DTMF_COMMAND_3:
9834 if (adjust_b_process (Id, plci, Rc) != GOOD)
9835 {
9836 dbug (1, dprintf ("[%06lx] %s,%d: Unload DTMF failed",
9837 UnMapId (Id), (char *)(FILE_), __LINE__));
9838 Info = _FACILITY_NOT_SUPPORTED;
9839 break;
9840 }
9841 if (plci->internal_command)
9842 return;
9843 break;
9844 }
9845 break;
9846
9847
9848 case DTMF_SEND_TONE:
9849 mask <<= 1;
9850 case DTMF_SEND_MF:
9851 mask <<= 1;
9852
9853 case DTMF_DIGITS_SEND:
9854 switch (internal_command)
9855 {
9856 default:
9857 adjust_b1_resource (Id, plci, NULL, (word)(plci->B1_facilities |
9858 ((plci->dtmf_parameter_length != 0) ? B1_FACILITY_DTMFX | B1_FACILITY_DTMFR : B1_FACILITY_DTMFX)),
9859 DTMF_COMMAND_1);
9860 case DTMF_COMMAND_1:
9861 if (adjust_b_process (Id, plci, Rc) != GOOD)
9862 {
9863 dbug (1, dprintf ("[%06lx] %s,%d: Load DTMF failed",
9864 UnMapId (Id), (char *)(FILE_), __LINE__));
9865 Info = _FACILITY_NOT_SUPPORTED;
9866 break;
9867 }
9868 if (plci->internal_command)
9869 return;
9870 case DTMF_COMMAND_2:
9871 if (plci_nl_busy (plci))
9872 {
9873 plci->internal_command = DTMF_COMMAND_2;
9874 return;
9875 }
9876 plci->dtmf_msg_number_queue[(plci->dtmf_send_requests)++] = plci->number;
9877 plci->internal_command = DTMF_COMMAND_3;
9878 dtmf_send_digits (plci, &plci->saved_msg.parms[3].info[1], plci->saved_msg.parms[3].length);
9879 return;
9880 case DTMF_COMMAND_3:
9881 if ((Rc != OK) && (Rc != OK_FC))
9882 {
9883 dbug (1, dprintf ("[%06lx] %s,%d: Send DTMF digits failed %02x",
9884 UnMapId (Id), (char *)(FILE_), __LINE__, Rc));
9885 if (plci->dtmf_send_requests != 0)
9886 (plci->dtmf_send_requests)--;
9887 Info = _FACILITY_NOT_SUPPORTED;
9888 break;
9889 }
9890 return;
9891 }
9892 break;
9893 }
9894 sendf (plci->appl, _FACILITY_R | CONFIRM, Id & 0xffffL, plci->number,
9895 "wws", Info, SELECTOR_DTMF, result);
9896}
9897
9898
9899static byte dtmf_request (dword Id, word Number, DIVA_CAPI_ADAPTER *a, PLCI *plci, APPL *appl, API_PARSE *msg)
9900{
9901 word Info;
9902 word i, j;
9903 byte mask;
9904 API_PARSE dtmf_parms[5];
9905 byte result[40];
9906
9907 dbug (1, dprintf ("[%06lx] %s,%d: dtmf_request",
9908 UnMapId (Id), (char *)(FILE_), __LINE__));
9909
9910 Info = GOOD;
9911 result[0] = 2;
9912 PUT_WORD (&result[1], DTMF_SUCCESS);
9913 if (!(a->profile.Global_Options & GL_DTMF_SUPPORTED))
9914 {
9915 dbug (1, dprintf ("[%06lx] %s,%d: Facility not supported",
9916 UnMapId (Id), (char *)(FILE_), __LINE__));
9917 Info = _FACILITY_NOT_SUPPORTED;
9918 }
9919 else if (api_parse (&msg[1].info[1], msg[1].length, "w", dtmf_parms))
9920 {
9921 dbug (1, dprintf ("[%06lx] %s,%d: Wrong message format",
9922 UnMapId (Id), (char *)(FILE_), __LINE__));
9923 Info = _WRONG_MESSAGE_FORMAT;
9924 }
9925
9926 else if ((GET_WORD (dtmf_parms[0].info) == DTMF_GET_SUPPORTED_DETECT_CODES)
9927 || (GET_WORD (dtmf_parms[0].info) == DTMF_GET_SUPPORTED_SEND_CODES))
9928 {
9929 if (!((a->requested_options_table[appl->Id-1])
9930 & (1L << PRIVATE_DTMF_TONE)))
9931 {
9932 dbug (1, dprintf ("[%06lx] %s,%d: DTMF unknown request %04x",
9933 UnMapId (Id), (char *)(FILE_), __LINE__, GET_WORD (dtmf_parms[0].info)));
9934 PUT_WORD (&result[1], DTMF_UNKNOWN_REQUEST);
9935 }
9936 else
9937 {
9938 for (i = 0; i < 32; i++)
9939 result[4 + i] = 0;
9940 if (GET_WORD (dtmf_parms[0].info) == DTMF_GET_SUPPORTED_DETECT_CODES)
9941 {
9942 for (i = 0; i < DTMF_DIGIT_MAP_ENTRIES; i++)
9943 {
9944 if (dtmf_digit_map[i].listen_mask != 0)
9945 result[4 + (dtmf_digit_map[i].character >> 3)] |= (1 << (dtmf_digit_map[i].character & 0x7));
9946 }
9947 }
9948 else
9949 {
9950 for (i = 0; i < DTMF_DIGIT_MAP_ENTRIES; i++)
9951 {
9952 if (dtmf_digit_map[i].send_mask != 0)
9953 result[4 + (dtmf_digit_map[i].character >> 3)] |= (1 << (dtmf_digit_map[i].character & 0x7));
9954 }
9955 }
9956 result[0] = 3 + 32;
9957 result[3] = 32;
9958 }
9959 }
9960
9961 else if (plci == NULL)
9962 {
9963 dbug (1, dprintf ("[%06lx] %s,%d: Wrong PLCI",
9964 UnMapId (Id), (char *)(FILE_), __LINE__));
9965 Info = _WRONG_IDENTIFIER;
9966 }
9967 else
9968 {
9969 if (!plci->State
9970 || !plci->NL.Id || plci->nl_remove_id)
9971 {
9972 dbug (1, dprintf ("[%06lx] %s,%d: Wrong state",
9973 UnMapId (Id), (char *)(FILE_), __LINE__));
9974 Info = _WRONG_STATE;
9975 }
9976 else
9977 {
9978 plci->command = 0;
9979 plci->dtmf_cmd = GET_WORD (dtmf_parms[0].info);
9980 mask = 0x01;
9981 switch (plci->dtmf_cmd)
9982 {
9983
9984 case DTMF_LISTEN_TONE_START:
9985 case DTMF_LISTEN_TONE_STOP:
9986 mask <<= 1;
9987 case DTMF_LISTEN_MF_START:
9988 case DTMF_LISTEN_MF_STOP:
9989 mask <<= 1;
9990 if (!((plci->requested_options_conn | plci->requested_options | plci->adapter->requested_options_table[appl->Id-1])
9991 & (1L << PRIVATE_DTMF_TONE)))
9992 {
9993 dbug (1, dprintf ("[%06lx] %s,%d: DTMF unknown request %04x",
9994 UnMapId (Id), (char *)(FILE_), __LINE__, GET_WORD (dtmf_parms[0].info)));
9995 PUT_WORD (&result[1], DTMF_UNKNOWN_REQUEST);
9996 break;
9997 }
9998
9999 case DTMF_LISTEN_START:
10000 case DTMF_LISTEN_STOP:
10001 if (!(a->manufacturer_features & MANUFACTURER_FEATURE_HARDDTMF)
10002 && !(a->manufacturer_features & MANUFACTURER_FEATURE_SOFTDTMF_RECEIVE))
10003 {
10004 dbug (1, dprintf ("[%06lx] %s,%d: Facility not supported",
10005 UnMapId (Id), (char *)(FILE_), __LINE__));
10006 Info = _FACILITY_NOT_SUPPORTED;
10007 break;
10008 }
10009 if (mask & DTMF_LISTEN_ACTIVE_FLAG)
10010 {
10011 if (api_parse (&msg[1].info[1], msg[1].length, "wwws", dtmf_parms))
10012 {
10013 plci->dtmf_rec_pulse_ms = 0;
10014 plci->dtmf_rec_pause_ms = 0;
10015 }
10016 else
10017 {
10018 plci->dtmf_rec_pulse_ms = GET_WORD (dtmf_parms[1].info);
10019 plci->dtmf_rec_pause_ms = GET_WORD (dtmf_parms[2].info);
10020 }
10021 }
10022 start_internal_command (Id, plci, dtmf_command);
10023 return (FALSE);
10024
10025
10026 case DTMF_SEND_TONE:
10027 mask <<= 1;
10028 case DTMF_SEND_MF:
10029 mask <<= 1;
10030 if (!((plci->requested_options_conn | plci->requested_options | plci->adapter->requested_options_table[appl->Id-1])
10031 & (1L << PRIVATE_DTMF_TONE)))
10032 {
10033 dbug (1, dprintf ("[%06lx] %s,%d: DTMF unknown request %04x",
10034 UnMapId (Id), (char *)(FILE_), __LINE__, GET_WORD (dtmf_parms[0].info)));
10035 PUT_WORD (&result[1], DTMF_UNKNOWN_REQUEST);
10036 break;
10037 }
10038
10039 case DTMF_DIGITS_SEND:
10040 if (api_parse (&msg[1].info[1], msg[1].length, "wwws", dtmf_parms))
10041 {
10042 dbug (1, dprintf ("[%06lx] %s,%d: Wrong message format",
10043 UnMapId (Id), (char *)(FILE_), __LINE__));
10044 Info = _WRONG_MESSAGE_FORMAT;
10045 break;
10046 }
10047 if (mask & DTMF_LISTEN_ACTIVE_FLAG)
10048 {
10049 plci->dtmf_send_pulse_ms = GET_WORD (dtmf_parms[1].info);
10050 plci->dtmf_send_pause_ms = GET_WORD (dtmf_parms[2].info);
10051 }
10052 i = 0;
10053 j = 0;
10054 while ((i < dtmf_parms[3].length) && (j < DTMF_DIGIT_MAP_ENTRIES))
10055 {
10056 j = 0;
10057 while ((j < DTMF_DIGIT_MAP_ENTRIES)
10058 && ((dtmf_parms[3].info[i+1] != dtmf_digit_map[j].character)
10059 || ((dtmf_digit_map[j].send_mask & mask) == 0)))
10060 {
10061 j++;
10062 }
10063 i++;
10064 }
10065 if (j == DTMF_DIGIT_MAP_ENTRIES)
10066 {
10067 dbug (1, dprintf ("[%06lx] %s,%d: Incorrect DTMF digit %02x",
10068 UnMapId (Id), (char *)(FILE_), __LINE__, dtmf_parms[3].info[i]));
10069 PUT_WORD (&result[1], DTMF_INCORRECT_DIGIT);
10070 break;
10071 }
10072 if (plci->dtmf_send_requests >=
10073 sizeof(plci->dtmf_msg_number_queue) / sizeof(plci->dtmf_msg_number_queue[0]))
10074 {
10075 dbug (1, dprintf ("[%06lx] %s,%d: DTMF request overrun",
10076 UnMapId (Id), (char *)(FILE_), __LINE__));
10077 Info = _WRONG_STATE;
10078 break;
10079 }
10080 api_save_msg (dtmf_parms, "wwws", &plci->saved_msg);
10081 start_internal_command (Id, plci, dtmf_command);
10082 return (FALSE);
10083
10084 default:
10085 dbug (1, dprintf ("[%06lx] %s,%d: DTMF unknown request %04x",
10086 UnMapId (Id), (char *)(FILE_), __LINE__, plci->dtmf_cmd));
10087 PUT_WORD (&result[1], DTMF_UNKNOWN_REQUEST);
10088 }
10089 }
10090 }
10091 sendf (appl, _FACILITY_R | CONFIRM, Id & 0xffffL, Number,
10092 "wws", Info, SELECTOR_DTMF, result);
10093 return (FALSE);
10094}
10095
10096
10097static void dtmf_confirmation (dword Id, PLCI *plci)
10098{
10099 word Info;
10100 word i;
10101 byte result[4];
10102
10103 dbug (1, dprintf ("[%06lx] %s,%d: dtmf_confirmation",
10104 UnMapId (Id), (char *)(FILE_), __LINE__));
10105
10106 Info = GOOD;
10107 result[0] = 2;
10108 PUT_WORD (&result[1], DTMF_SUCCESS);
10109 if (plci->dtmf_send_requests != 0)
10110 {
10111 sendf (plci->appl, _FACILITY_R | CONFIRM, Id & 0xffffL, plci->dtmf_msg_number_queue[0],
10112 "wws", GOOD, SELECTOR_DTMF, result);
10113 (plci->dtmf_send_requests)--;
10114 for (i = 0; i < plci->dtmf_send_requests; i++)
10115 plci->dtmf_msg_number_queue[i] = plci->dtmf_msg_number_queue[i+1];
10116 }
10117}
10118
10119
10120static void dtmf_indication (dword Id, PLCI *plci, byte *msg, word length)
10121{
10122 word i, j, n;
10123
10124 dbug (1, dprintf ("[%06lx] %s,%d: dtmf_indication",
10125 UnMapId (Id), (char *)(FILE_), __LINE__));
10126
10127 n = 0;
10128 for (i = 1; i < length; i++)
10129 {
10130 j = 0;
10131 while ((j < DTMF_DIGIT_MAP_ENTRIES)
10132 && ((msg[i] != dtmf_digit_map[j].code)
10133 || ((dtmf_digit_map[j].listen_mask & plci->dtmf_rec_active) == 0)))
10134 {
10135 j++;
10136 }
10137 if (j < DTMF_DIGIT_MAP_ENTRIES)
10138 {
10139
10140 if ((dtmf_digit_map[j].listen_mask & DTMF_TONE_LISTEN_ACTIVE_FLAG)
10141 && (plci->tone_last_indication_code == DTMF_SIGNAL_NO_TONE)
10142 && (dtmf_digit_map[j].character != DTMF_SIGNAL_UNIDENTIFIED_TONE))
10143 {
10144 if (n + 1 == i)
10145 {
10146 for (i = length; i > n + 1; i--)
10147 msg[i] = msg[i - 1];
10148 length++;
10149 i++;
10150 }
10151 msg[++n] = DTMF_SIGNAL_UNIDENTIFIED_TONE;
10152 }
10153 plci->tone_last_indication_code = dtmf_digit_map[j].character;
10154
10155 msg[++n] = dtmf_digit_map[j].character;
10156 }
10157 }
10158 if (n != 0)
10159 {
10160 msg[0] = (byte) n;
10161 sendf (plci->appl, _FACILITY_I, Id & 0xffffL, 0, "wS", SELECTOR_DTMF, msg);
10162 }
10163}
10164
10165
10166/*------------------------------------------------------------------*/
10167/* DTMF parameters */
10168/*------------------------------------------------------------------*/
10169
10170static void dtmf_parameter_write (PLCI *plci)
10171{
10172 word i;
10173 byte parameter_buffer[DTMF_PARAMETER_BUFFER_SIZE + 2];
10174
10175 dbug (1, dprintf ("[%06lx] %s,%d: dtmf_parameter_write",
10176 (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
10177 (char *)(FILE_), __LINE__));
10178
10179 parameter_buffer[0] = plci->dtmf_parameter_length + 1;
10180 parameter_buffer[1] = DSP_CTRL_SET_DTMF_PARAMETERS;
10181 for (i = 0; i < plci->dtmf_parameter_length; i++)
10182 parameter_buffer[2+i] = plci->dtmf_parameter_buffer[i];
10183 add_p (plci, FTY, parameter_buffer);
10184 sig_req (plci, TEL_CTRL, 0);
10185 send_req (plci);
10186}
10187
10188
10189static void dtmf_parameter_clear_config (PLCI *plci)
10190{
10191
10192 dbug (1, dprintf ("[%06lx] %s,%d: dtmf_parameter_clear_config",
10193 (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
10194 (char *)(FILE_), __LINE__));
10195
10196 plci->dtmf_parameter_length = 0;
10197}
10198
10199
10200static void dtmf_parameter_prepare_switch (dword Id, PLCI *plci)
10201{
10202
10203 dbug (1, dprintf ("[%06lx] %s,%d: dtmf_parameter_prepare_switch",
10204 UnMapId (Id), (char *)(FILE_), __LINE__));
10205
10206}
10207
10208
10209static word dtmf_parameter_save_config (dword Id, PLCI *plci, byte Rc)
10210{
10211
10212 dbug (1, dprintf ("[%06lx] %s,%d: dtmf_parameter_save_config %02x %d",
10213 UnMapId (Id), (char *)(FILE_), __LINE__, Rc, plci->adjust_b_state));
10214
10215 return (GOOD);
10216}
10217
10218
10219static word dtmf_parameter_restore_config (dword Id, PLCI *plci, byte Rc)
10220{
10221 word Info;
10222
10223 dbug (1, dprintf ("[%06lx] %s,%d: dtmf_parameter_restore_config %02x %d",
10224 UnMapId (Id), (char *)(FILE_), __LINE__, Rc, plci->adjust_b_state));
10225
10226 Info = GOOD;
10227 if ((plci->B1_facilities & B1_FACILITY_DTMFR)
10228 && (plci->dtmf_parameter_length != 0))
10229 {
10230 switch (plci->adjust_b_state)
10231 {
10232 case ADJUST_B_RESTORE_DTMF_PARAMETER_1:
10233 plci->internal_command = plci->adjust_b_command;
10234 if (plci->sig_req)
10235 {
10236 plci->adjust_b_state = ADJUST_B_RESTORE_DTMF_PARAMETER_1;
10237 break;
10238 }
10239 dtmf_parameter_write (plci);
10240 plci->adjust_b_state = ADJUST_B_RESTORE_DTMF_PARAMETER_2;
10241 break;
10242 case ADJUST_B_RESTORE_DTMF_PARAMETER_2:
10243 if ((Rc != OK) && (Rc != OK_FC))
10244 {
10245 dbug (1, dprintf ("[%06lx] %s,%d: Restore DTMF parameters failed %02x",
10246 UnMapId (Id), (char *)(FILE_), __LINE__, Rc));
10247 Info = _WRONG_STATE;
10248 break;
10249 }
10250 break;
10251 }
10252 }
10253 return (Info);
10254}
10255
10256
10257/*------------------------------------------------------------------*/
10258/* Line interconnect facilities */
10259/*------------------------------------------------------------------*/
10260
10261
10262LI_CONFIG *li_config_table;
10263word li_total_channels;
10264
10265
10266/*------------------------------------------------------------------*/
10267/* translate a CHI information element to a channel number */
10268/* returns 0xff - any channel */
10269/* 0xfe - chi wrong coding */
10270/* 0xfd - D-channel */
10271/* 0x00 - no channel */
10272/* else channel number / PRI: timeslot */
10273/* if channels is provided we accept more than one channel. */
10274/*------------------------------------------------------------------*/
10275
10276static byte chi_to_channel (byte *chi, dword *pchannelmap)
10277{
10278 int p;
10279 int i;
10280 dword map;
10281 byte excl;
10282 byte ofs;
10283 byte ch;
10284
10285 if (pchannelmap) *pchannelmap = 0;
10286 if(!chi[0]) return 0xff;
10287 excl = 0;
10288
10289 if(chi[1] & 0x20) {
10290 if(chi[0]==1 && chi[1]==0xac) return 0xfd; /* exclusive d-channel */
10291 for(i=1; i<chi[0] && !(chi[i] &0x80); i++);
10292 if(i==chi[0] || !(chi[i] &0x80)) return 0xfe;
10293 if((chi[1] |0xc8)!=0xe9) return 0xfe;
10294 if(chi[1] &0x08) excl = 0x40;
10295
10296 /* int. id present */
10297 if(chi[1] &0x40) {
10298 p=i+1;
10299 for(i=p; i<chi[0] && !(chi[i] &0x80); i++);
10300 if(i==chi[0] || !(chi[i] &0x80)) return 0xfe;
10301 }
10302
10303 /* coding standard, Number/Map, Channel Type */
10304 p=i+1;
10305 for(i=p; i<chi[0] && !(chi[i] &0x80); i++);
10306 if(i==chi[0] || !(chi[i] &0x80)) return 0xfe;
10307 if((chi[p]|0xd0)!=0xd3) return 0xfe;
10308
10309 /* Number/Map */
10310 if(chi[p] &0x10) {
10311
10312 /* map */
10313 if((chi[0]-p)==4) ofs = 0;
10314 else if((chi[0]-p)==3) ofs = 1;
10315 else return 0xfe;
10316 ch = 0;
10317 map = 0;
10318 for(i=0; i<4 && p<chi[0]; i++) {
10319 p++;
10320 ch += 8;
10321 map <<= 8;
10322 if(chi[p]) {
10323 for (ch=0; !(chi[p] & (1 << ch)); ch++);
10324 map |= chi[p];
10325 }
10326 }
10327 ch += ofs;
10328 map <<= ofs;
10329 }
10330 else {
10331
10332 /* number */
10333 p=i+1;
10334 ch = chi[p] &0x3f;
10335 if(pchannelmap) {
10336 if((byte)(chi[0]-p)>30) return 0xfe;
10337 map = 0;
10338 for(i=p; i<=chi[0]; i++) {
10339 if ((chi[i] &0x7f) > 31) return 0xfe;
10340 map |= (1L << (chi[i] &0x7f));
10341 }
10342 }
10343 else {
10344 if(p!=chi[0]) return 0xfe;
10345 if (ch > 31) return 0xfe;
10346 map = (1L << ch);
10347 }
10348 if(chi[p] &0x40) return 0xfe;
10349 }
10350 if (pchannelmap) *pchannelmap = map;
10351 else if (map != ((dword)(1L << ch))) return 0xfe;
10352 return (byte)(excl | ch);
10353 }
10354 else { /* not PRI */
10355 for(i=1; i<chi[0] && !(chi[i] &0x80); i++);
10356 if(i!=chi[0] || !(chi[i] &0x80)) return 0xfe;
10357 if(chi[1] &0x08) excl = 0x40;
10358
10359 switch(chi[1] |0x98) {
10360 case 0x98: return 0;
10361 case 0x99:
10362 if (pchannelmap) *pchannelmap = 2;
10363 return excl |1;
10364 case 0x9a:
10365 if (pchannelmap) *pchannelmap = 4;
10366 return excl |2;
10367 case 0x9b: return 0xff;
10368 case 0x9c: return 0xfd; /* d-ch */
10369 default: return 0xfe;
10370 }
10371 }
10372}
10373
10374
10375static void mixer_set_bchannel_id_esc (PLCI *plci, byte bchannel_id)
10376{
10377 DIVA_CAPI_ADAPTER *a;
10378 PLCI *splci;
10379 byte old_id;
10380
10381 a = plci->adapter;
10382 old_id = plci->li_bchannel_id;
10383 if (a->li_pri)
10384 {
10385 if ((old_id != 0) && (li_config_table[a->li_base + (old_id - 1)].plci == plci))
10386 li_config_table[a->li_base + (old_id - 1)].plci = NULL;
10387 plci->li_bchannel_id = (bchannel_id & 0x1f) + 1;
10388 if (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == NULL)
10389 li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci = plci;
10390 }
10391 else
10392 {
10393 if (((bchannel_id & 0x03) == 1) || ((bchannel_id & 0x03) == 2))
10394 {
10395 if ((old_id != 0) && (li_config_table[a->li_base + (old_id - 1)].plci == plci))
10396 li_config_table[a->li_base + (old_id - 1)].plci = NULL;
10397 plci->li_bchannel_id = bchannel_id & 0x03;
10398 if ((a->AdvSignalPLCI != NULL) && (a->AdvSignalPLCI != plci) && (a->AdvSignalPLCI->tel == ADV_VOICE))
10399 {
10400 splci = a->AdvSignalPLCI;
10401 if (li_config_table[a->li_base + (2 - plci->li_bchannel_id)].plci == NULL)
10402 {
10403 if ((splci->li_bchannel_id != 0)
10404 && (li_config_table[a->li_base + (splci->li_bchannel_id - 1)].plci == splci))
10405 {
10406 li_config_table[a->li_base + (splci->li_bchannel_id - 1)].plci = NULL;
10407 }
10408 splci->li_bchannel_id = 3 - plci->li_bchannel_id;
10409 li_config_table[a->li_base + (2 - plci->li_bchannel_id)].plci = splci;
10410 dbug (1, dprintf ("[%06lx] %s,%d: adv_voice_set_bchannel_id_esc %d",
10411 (dword)((splci->Id << 8) | UnMapController (splci->adapter->Id)),
10412 (char *)(FILE_), __LINE__, splci->li_bchannel_id));
10413 }
10414 }
10415 if (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == NULL)
10416 li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci = plci;
10417 }
10418 }
10419 if ((old_id == 0) && (plci->li_bchannel_id != 0)
10420 && (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == plci))
10421 {
10422 mixer_clear_config (plci);
10423 }
10424 dbug (1, dprintf ("[%06lx] %s,%d: mixer_set_bchannel_id_esc %d %d",
10425 (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
10426 (char *)(FILE_), __LINE__, bchannel_id, plci->li_bchannel_id));
10427}
10428
10429
10430static void mixer_set_bchannel_id (PLCI *plci, byte *chi)
10431{
10432 DIVA_CAPI_ADAPTER *a;
10433 PLCI *splci;
10434 byte ch, old_id;
10435
10436 a = plci->adapter;
10437 old_id = plci->li_bchannel_id;
10438 ch = chi_to_channel (chi, NULL);
10439 if (!(ch & 0x80))
10440 {
10441 if (a->li_pri)
10442 {
10443 if ((old_id != 0) && (li_config_table[a->li_base + (old_id - 1)].plci == plci))
10444 li_config_table[a->li_base + (old_id - 1)].plci = NULL;
10445 plci->li_bchannel_id = (ch & 0x1f) + 1;
10446 if (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == NULL)
10447 li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci = plci;
10448 }
10449 else
10450 {
10451 if (((ch & 0x1f) == 1) || ((ch & 0x1f) == 2))
10452 {
10453 if ((old_id != 0) && (li_config_table[a->li_base + (old_id - 1)].plci == plci))
10454 li_config_table[a->li_base + (old_id - 1)].plci = NULL;
10455 plci->li_bchannel_id = ch & 0x1f;
10456 if ((a->AdvSignalPLCI != NULL) && (a->AdvSignalPLCI != plci) && (a->AdvSignalPLCI->tel == ADV_VOICE))
10457 {
10458 splci = a->AdvSignalPLCI;
10459 if (li_config_table[a->li_base + (2 - plci->li_bchannel_id)].plci == NULL)
10460 {
10461 if ((splci->li_bchannel_id != 0)
10462 && (li_config_table[a->li_base + (splci->li_bchannel_id - 1)].plci == splci))
10463 {
10464 li_config_table[a->li_base + (splci->li_bchannel_id - 1)].plci = NULL;
10465 }
10466 splci->li_bchannel_id = 3 - plci->li_bchannel_id;
10467 li_config_table[a->li_base + (2 - plci->li_bchannel_id)].plci = splci;
10468 dbug (1, dprintf ("[%06lx] %s,%d: adv_voice_set_bchannel_id %d",
10469 (dword)((splci->Id << 8) | UnMapController (splci->adapter->Id)),
10470 (char *)(FILE_), __LINE__, splci->li_bchannel_id));
10471 }
10472 }
10473 if (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == NULL)
10474 li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci = plci;
10475 }
10476 }
10477 }
10478 if ((old_id == 0) && (plci->li_bchannel_id != 0)
10479 && (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == plci))
10480 {
10481 mixer_clear_config (plci);
10482 }
10483 dbug (1, dprintf ("[%06lx] %s,%d: mixer_set_bchannel_id %02x %d",
10484 (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
10485 (char *)(FILE_), __LINE__, ch, plci->li_bchannel_id));
10486}
10487
10488
10489#define MIXER_MAX_DUMP_CHANNELS 34
10490
10491static void mixer_calculate_coefs (DIVA_CAPI_ADAPTER *a)
10492{
10493static char hex_digit_table[0x10] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
10494 word n, i, j;
10495 char *p;
10496 char hex_line[2 * MIXER_MAX_DUMP_CHANNELS + MIXER_MAX_DUMP_CHANNELS / 8 + 4];
10497
10498 dbug (1, dprintf ("[%06lx] %s,%d: mixer_calculate_coefs",
10499 (dword)(UnMapController (a->Id)), (char *)(FILE_), __LINE__));
10500
10501 for (i = 0; i < li_total_channels; i++)
10502 {
10503 li_config_table[i].channel &= LI_CHANNEL_ADDRESSES_SET;
10504 if (li_config_table[i].chflags != 0)
10505 li_config_table[i].channel |= LI_CHANNEL_INVOLVED;
10506 else
10507 {
10508 for (j = 0; j < li_total_channels; j++)
10509 {
10510 if (((li_config_table[i].flag_table[j]) != 0)
10511 || ((li_config_table[j].flag_table[i]) != 0))
10512 {
10513 li_config_table[i].channel |= LI_CHANNEL_INVOLVED;
10514 }
10515 if (((li_config_table[i].flag_table[j] & LI_FLAG_CONFERENCE) != 0)
10516 || ((li_config_table[j].flag_table[i] & LI_FLAG_CONFERENCE) != 0))
10517 {
10518 li_config_table[i].channel |= LI_CHANNEL_CONFERENCE;
10519 }
10520 }
10521 }
10522 }
10523 for (i = 0; i < li_total_channels; i++)
10524 {
10525 for (j = 0; j < li_total_channels; j++)
10526 {
10527 li_config_table[i].coef_table[j] &= ~(LI_COEF_CH_CH | LI_COEF_CH_PC | LI_COEF_PC_CH | LI_COEF_PC_PC);
10528 if (li_config_table[i].flag_table[j] & LI_FLAG_CONFERENCE)
10529 li_config_table[i].coef_table[j] |= LI_COEF_CH_CH;
10530 }
10531 }
10532 for (n = 0; n < li_total_channels; n++)
10533 {
10534 if (li_config_table[n].channel & LI_CHANNEL_CONFERENCE)
10535 {
10536 for (i = 0; i < li_total_channels; i++)
10537 {
10538 if (li_config_table[i].channel & LI_CHANNEL_CONFERENCE)
10539 {
10540 for (j = 0; j < li_total_channels; j++)
10541 {
10542 li_config_table[i].coef_table[j] |=
10543 li_config_table[i].coef_table[n] & li_config_table[n].coef_table[j];
10544 }
10545 }
10546 }
10547 }
10548 }
10549 for (i = 0; i < li_total_channels; i++)
10550 {
10551 if (li_config_table[i].channel & LI_CHANNEL_INVOLVED)
10552 {
10553 li_config_table[i].coef_table[i] &= ~LI_COEF_CH_CH;
10554 for (j = 0; j < li_total_channels; j++)
10555 {
10556 if (li_config_table[i].coef_table[j] & LI_COEF_CH_CH)
10557 li_config_table[i].flag_table[j] |= LI_FLAG_CONFERENCE;
10558 }
10559 if (li_config_table[i].flag_table[i] & LI_FLAG_CONFERENCE)
10560 li_config_table[i].coef_table[i] |= LI_COEF_CH_CH;
10561 }
10562 }
10563 for (i = 0; i < li_total_channels; i++)
10564 {
10565 if (li_config_table[i].channel & LI_CHANNEL_INVOLVED)
10566 {
10567 for (j = 0; j < li_total_channels; j++)
10568 {
10569 if (li_config_table[i].flag_table[j] & LI_FLAG_INTERCONNECT)
10570 li_config_table[i].coef_table[j] |= LI_COEF_CH_CH;
10571 if (li_config_table[i].flag_table[j] & LI_FLAG_MONITOR)
10572 li_config_table[i].coef_table[j] |= LI_COEF_CH_PC;
10573 if (li_config_table[i].flag_table[j] & LI_FLAG_MIX)
10574 li_config_table[i].coef_table[j] |= LI_COEF_PC_CH;
10575 if (li_config_table[i].flag_table[j] & LI_FLAG_PCCONNECT)
10576 li_config_table[i].coef_table[j] |= LI_COEF_PC_PC;
10577 }
10578 if (li_config_table[i].chflags & LI_CHFLAG_MONITOR)
10579 {
10580 for (j = 0; j < li_total_channels; j++)
10581 {
10582 if (li_config_table[i].flag_table[j] & LI_FLAG_INTERCONNECT)
10583 {
10584 li_config_table[i].coef_table[j] |= LI_COEF_CH_PC;
10585 if (li_config_table[j].chflags & LI_CHFLAG_MIX)
10586 li_config_table[i].coef_table[j] |= LI_COEF_PC_CH | LI_COEF_PC_PC;
10587 }
10588 }
10589 }
10590 if (li_config_table[i].chflags & LI_CHFLAG_MIX)
10591 {
10592 for (j = 0; j < li_total_channels; j++)
10593 {
10594 if (li_config_table[j].flag_table[i] & LI_FLAG_INTERCONNECT)
10595 li_config_table[j].coef_table[i] |= LI_COEF_PC_CH;
10596 }
10597 }
10598 if (li_config_table[i].chflags & LI_CHFLAG_LOOP)
10599 {
10600 for (j = 0; j < li_total_channels; j++)
10601 {
10602 if (li_config_table[i].flag_table[j] & LI_FLAG_INTERCONNECT)
10603 {
10604 for (n = 0; n < li_total_channels; n++)
10605 {
10606 if (li_config_table[n].flag_table[i] & LI_FLAG_INTERCONNECT)
10607 {
10608 li_config_table[n].coef_table[j] |= LI_COEF_CH_CH;
10609 if (li_config_table[j].chflags & LI_CHFLAG_MIX)
10610 {
10611 li_config_table[n].coef_table[j] |= LI_COEF_PC_CH;
10612 if (li_config_table[n].chflags & LI_CHFLAG_MONITOR)
10613 li_config_table[n].coef_table[j] |= LI_COEF_CH_PC | LI_COEF_PC_PC;
10614 }
10615 else if (li_config_table[n].chflags & LI_CHFLAG_MONITOR)
10616 li_config_table[n].coef_table[j] |= LI_COEF_CH_PC;
10617 }
10618 }
10619 }
10620 }
10621 }
10622 }
10623 }
10624 for (i = 0; i < li_total_channels; i++)
10625 {
10626 if (li_config_table[i].channel & LI_CHANNEL_INVOLVED)
10627 {
10628 if (li_config_table[i].chflags & (LI_CHFLAG_MONITOR | LI_CHFLAG_MIX | LI_CHFLAG_LOOP))
10629 li_config_table[i].channel |= LI_CHANNEL_ACTIVE;
10630 if (li_config_table[i].chflags & LI_CHFLAG_MONITOR)
10631 li_config_table[i].channel |= LI_CHANNEL_RX_DATA;
10632 if (li_config_table[i].chflags & LI_CHFLAG_MIX)
10633 li_config_table[i].channel |= LI_CHANNEL_TX_DATA;
10634 for (j = 0; j < li_total_channels; j++)
10635 {
10636 if ((li_config_table[i].flag_table[j] &
10637 (LI_FLAG_INTERCONNECT | LI_FLAG_PCCONNECT | LI_FLAG_CONFERENCE | LI_FLAG_MONITOR))
10638 || (li_config_table[j].flag_table[i] &
10639 (LI_FLAG_INTERCONNECT | LI_FLAG_PCCONNECT | LI_FLAG_CONFERENCE | LI_FLAG_ANNOUNCEMENT | LI_FLAG_MIX)))
10640 {
10641 li_config_table[i].channel |= LI_CHANNEL_ACTIVE;
10642 }
10643 if (li_config_table[i].flag_table[j] & (LI_FLAG_PCCONNECT | LI_FLAG_MONITOR))
10644 li_config_table[i].channel |= LI_CHANNEL_RX_DATA;
10645 if (li_config_table[j].flag_table[i] & (LI_FLAG_PCCONNECT | LI_FLAG_ANNOUNCEMENT | LI_FLAG_MIX))
10646 li_config_table[i].channel |= LI_CHANNEL_TX_DATA;
10647 }
10648 if (!(li_config_table[i].channel & LI_CHANNEL_ACTIVE))
10649 {
10650 li_config_table[i].coef_table[i] |= LI_COEF_PC_CH | LI_COEF_CH_PC;
10651 li_config_table[i].channel |= LI_CHANNEL_TX_DATA | LI_CHANNEL_RX_DATA;
10652 }
10653 }
10654 }
10655 for (i = 0; i < li_total_channels; i++)
10656 {
10657 if (li_config_table[i].channel & LI_CHANNEL_INVOLVED)
10658 {
10659 j = 0;
10660 while ((j < li_total_channels) && !(li_config_table[i].flag_table[j] & LI_FLAG_ANNOUNCEMENT))
10661 j++;
10662 if (j < li_total_channels)
10663 {
10664 for (j = 0; j < li_total_channels; j++)
10665 {
10666 li_config_table[i].coef_table[j] &= ~(LI_COEF_CH_CH | LI_COEF_PC_CH);
10667 if (li_config_table[i].flag_table[j] & LI_FLAG_ANNOUNCEMENT)
10668 li_config_table[i].coef_table[j] |= LI_COEF_PC_CH;
10669 }
10670 }
10671 }
10672 }
10673 n = li_total_channels;
10674 if (n > MIXER_MAX_DUMP_CHANNELS)
10675 n = MIXER_MAX_DUMP_CHANNELS;
10676 p = hex_line;
10677 for (j = 0; j < n; j++)
10678 {
10679 if ((j & 0x7) == 0)
10680 *(p++) = ' ';
10681 *(p++) = hex_digit_table[li_config_table[j].curchnl >> 4];
10682 *(p++) = hex_digit_table[li_config_table[j].curchnl & 0xf];
10683 }
10684 *p = '\0';
10685 dbug (1, dprintf ("[%06lx] CURRENT %s",
10686 (dword)(UnMapController (a->Id)), (char *) hex_line));
10687 p = hex_line;
10688 for (j = 0; j < n; j++)
10689 {
10690 if ((j & 0x7) == 0)
10691 *(p++) = ' ';
10692 *(p++) = hex_digit_table[li_config_table[j].channel >> 4];
10693 *(p++) = hex_digit_table[li_config_table[j].channel & 0xf];
10694 }
10695 *p = '\0';
10696 dbug (1, dprintf ("[%06lx] CHANNEL %s",
10697 (dword)(UnMapController (a->Id)), (char *) hex_line));
10698 p = hex_line;
10699 for (j = 0; j < n; j++)
10700 {
10701 if ((j & 0x7) == 0)
10702 *(p++) = ' ';
10703 *(p++) = hex_digit_table[li_config_table[j].chflags >> 4];
10704 *(p++) = hex_digit_table[li_config_table[j].chflags & 0xf];
10705 }
10706 *p = '\0';
10707 dbug (1, dprintf ("[%06lx] CHFLAG %s",
10708 (dword)(UnMapController (a->Id)), (char *) hex_line));
10709 for (i = 0; i < n; i++)
10710 {
10711 p = hex_line;
10712 for (j = 0; j < n; j++)
10713 {
10714 if ((j & 0x7) == 0)
10715 *(p++) = ' ';
10716 *(p++) = hex_digit_table[li_config_table[i].flag_table[j] >> 4];
10717 *(p++) = hex_digit_table[li_config_table[i].flag_table[j] & 0xf];
10718 }
10719 *p = '\0';
10720 dbug (1, dprintf ("[%06lx] FLAG[%02x]%s",
10721 (dword)(UnMapController (a->Id)), i, (char *) hex_line));
10722 }
10723 for (i = 0; i < n; i++)
10724 {
10725 p = hex_line;
10726 for (j = 0; j < n; j++)
10727 {
10728 if ((j & 0x7) == 0)
10729 *(p++) = ' ';
10730 *(p++) = hex_digit_table[li_config_table[i].coef_table[j] >> 4];
10731 *(p++) = hex_digit_table[li_config_table[i].coef_table[j] & 0xf];
10732 }
10733 *p = '\0';
10734 dbug (1, dprintf ("[%06lx] COEF[%02x]%s",
10735 (dword)(UnMapController (a->Id)), i, (char *) hex_line));
10736 }
10737}
10738
10739
10740static struct
10741{
10742 byte mask;
10743 byte line_flags;
10744} mixer_write_prog_pri[] =
10745{
10746 { LI_COEF_CH_CH, 0 },
10747 { LI_COEF_CH_PC, MIXER_COEF_LINE_TO_PC_FLAG },
10748 { LI_COEF_PC_CH, MIXER_COEF_LINE_FROM_PC_FLAG },
10749 { LI_COEF_PC_PC, MIXER_COEF_LINE_TO_PC_FLAG | MIXER_COEF_LINE_FROM_PC_FLAG }
10750};
10751
10752static struct
10753{
10754 byte from_ch;
10755 byte to_ch;
10756 byte mask;
10757 byte xconnect_override;
10758} mixer_write_prog_bri[] =
10759{
10760 { 0, 0, LI_COEF_CH_CH, 0x01 }, /* B to B */
10761 { 1, 0, LI_COEF_CH_CH, 0x01 }, /* Alt B to B */
10762 { 0, 0, LI_COEF_PC_CH, 0x80 }, /* PC to B */
10763 { 1, 0, LI_COEF_PC_CH, 0x01 }, /* Alt PC to B */
10764 { 2, 0, LI_COEF_CH_CH, 0x00 }, /* IC to B */
10765 { 3, 0, LI_COEF_CH_CH, 0x00 }, /* Alt IC to B */
10766 { 0, 0, LI_COEF_CH_PC, 0x80 }, /* B to PC */
10767 { 1, 0, LI_COEF_CH_PC, 0x01 }, /* Alt B to PC */
10768 { 0, 0, LI_COEF_PC_PC, 0x01 }, /* PC to PC */
10769 { 1, 0, LI_COEF_PC_PC, 0x01 }, /* Alt PC to PC */
10770 { 2, 0, LI_COEF_CH_PC, 0x00 }, /* IC to PC */
10771 { 3, 0, LI_COEF_CH_PC, 0x00 }, /* Alt IC to PC */
10772 { 0, 2, LI_COEF_CH_CH, 0x00 }, /* B to IC */
10773 { 1, 2, LI_COEF_CH_CH, 0x00 }, /* Alt B to IC */
10774 { 0, 2, LI_COEF_PC_CH, 0x00 }, /* PC to IC */
10775 { 1, 2, LI_COEF_PC_CH, 0x00 }, /* Alt PC to IC */
10776 { 2, 2, LI_COEF_CH_CH, 0x00 }, /* IC to IC */
10777 { 3, 2, LI_COEF_CH_CH, 0x00 }, /* Alt IC to IC */
10778 { 1, 1, LI_COEF_CH_CH, 0x01 }, /* Alt B to Alt B */
10779 { 0, 1, LI_COEF_CH_CH, 0x01 }, /* B to Alt B */
10780 { 1, 1, LI_COEF_PC_CH, 0x80 }, /* Alt PC to Alt B */
10781 { 0, 1, LI_COEF_PC_CH, 0x01 }, /* PC to Alt B */
10782 { 3, 1, LI_COEF_CH_CH, 0x00 }, /* Alt IC to Alt B */
10783 { 2, 1, LI_COEF_CH_CH, 0x00 }, /* IC to Alt B */
10784 { 1, 1, LI_COEF_CH_PC, 0x80 }, /* Alt B to Alt PC */
10785 { 0, 1, LI_COEF_CH_PC, 0x01 }, /* B to Alt PC */
10786 { 1, 1, LI_COEF_PC_PC, 0x01 }, /* Alt PC to Alt PC */
10787 { 0, 1, LI_COEF_PC_PC, 0x01 }, /* PC to Alt PC */
10788 { 3, 1, LI_COEF_CH_PC, 0x00 }, /* Alt IC to Alt PC */
10789 { 2, 1, LI_COEF_CH_PC, 0x00 }, /* IC to Alt PC */
10790 { 1, 3, LI_COEF_CH_CH, 0x00 }, /* Alt B to Alt IC */
10791 { 0, 3, LI_COEF_CH_CH, 0x00 }, /* B to Alt IC */
10792 { 1, 3, LI_COEF_PC_CH, 0x00 }, /* Alt PC to Alt IC */
10793 { 0, 3, LI_COEF_PC_CH, 0x00 }, /* PC to Alt IC */
10794 { 3, 3, LI_COEF_CH_CH, 0x00 }, /* Alt IC to Alt IC */
10795 { 2, 3, LI_COEF_CH_CH, 0x00 } /* IC to Alt IC */
10796};
10797
10798static byte mixer_swapped_index_bri[] =
10799{
10800 18, /* B to B */
10801 19, /* Alt B to B */
10802 20, /* PC to B */
10803 21, /* Alt PC to B */
10804 22, /* IC to B */
10805 23, /* Alt IC to B */
10806 24, /* B to PC */
10807 25, /* Alt B to PC */
10808 26, /* PC to PC */
10809 27, /* Alt PC to PC */
10810 28, /* IC to PC */
10811 29, /* Alt IC to PC */
10812 30, /* B to IC */
10813 31, /* Alt B to IC */
10814 32, /* PC to IC */
10815 33, /* Alt PC to IC */
10816 34, /* IC to IC */
10817 35, /* Alt IC to IC */
10818 0, /* Alt B to Alt B */
10819 1, /* B to Alt B */
10820 2, /* Alt PC to Alt B */
10821 3, /* PC to Alt B */
10822 4, /* Alt IC to Alt B */
10823 5, /* IC to Alt B */
10824 6, /* Alt B to Alt PC */
10825 7, /* B to Alt PC */
10826 8, /* Alt PC to Alt PC */
10827 9, /* PC to Alt PC */
10828 10, /* Alt IC to Alt PC */
10829 11, /* IC to Alt PC */
10830 12, /* Alt B to Alt IC */
10831 13, /* B to Alt IC */
10832 14, /* Alt PC to Alt IC */
10833 15, /* PC to Alt IC */
10834 16, /* Alt IC to Alt IC */
10835 17 /* IC to Alt IC */
10836};
10837
10838static struct
10839{
10840 byte mask;
10841 byte from_pc;
10842 byte to_pc;
10843} xconnect_write_prog[] =
10844{
10845 { LI_COEF_CH_CH, FALSE, FALSE },
10846 { LI_COEF_CH_PC, FALSE, TRUE },
10847 { LI_COEF_PC_CH, TRUE, FALSE },
10848 { LI_COEF_PC_PC, TRUE, TRUE }
10849};
10850
10851
10852static void xconnect_query_addresses (PLCI *plci)
10853{
10854 DIVA_CAPI_ADAPTER *a;
10855 word w, ch;
10856 byte *p;
10857
10858 dbug (1, dprintf ("[%06lx] %s,%d: xconnect_query_addresses",
10859 (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
10860 (char *)(FILE_), __LINE__));
10861
10862 a = plci->adapter;
10863 if (a->li_pri && ((plci->li_bchannel_id == 0)
10864 || (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci != plci)))
10865 {
10866 dbug (1, dprintf ("[%06x] %s,%d: Channel id wiped out",
10867 (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
10868 (char *)(FILE_), __LINE__));
10869 return;
10870 }
10871 p = plci->internal_req_buffer;
10872 ch = (a->li_pri) ? plci->li_bchannel_id - 1 : 0;
10873 *(p++) = UDATA_REQUEST_XCONNECT_FROM;
10874 w = ch;
10875 *(p++) = (byte) w;
10876 *(p++) = (byte)(w >> 8);
10877 w = ch | XCONNECT_CHANNEL_PORT_PC;
10878 *(p++) = (byte) w;
10879 *(p++) = (byte)(w >> 8);
10880 plci->NData[0].P = plci->internal_req_buffer;
10881 plci->NData[0].PLength = p - plci->internal_req_buffer;
10882 plci->NL.X = plci->NData;
10883 plci->NL.ReqCh = 0;
10884 plci->NL.Req = plci->nl_req = (byte) N_UDATA;
10885 plci->adapter->request (&plci->NL);
10886}
10887
10888
10889static void xconnect_write_coefs (PLCI *plci, word internal_command)
10890{
10891
10892 dbug (1, dprintf ("[%06lx] %s,%d: xconnect_write_coefs %04x",
10893 (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
10894 (char *)(FILE_), __LINE__, internal_command));
10895
10896 plci->li_write_command = internal_command;
10897 plci->li_write_channel = 0;
10898}
10899
10900
10901static byte xconnect_write_coefs_process (dword Id, PLCI *plci, byte Rc)
10902{
10903 DIVA_CAPI_ADAPTER *a;
10904 word w, n, i, j, r, s, to_ch;
10905 dword d;
10906 byte *p;
10907 struct xconnect_transfer_address_s *transfer_address;
10908 byte ch_map[MIXER_CHANNELS_BRI];
10909
10910 dbug (1, dprintf ("[%06x] %s,%d: xconnect_write_coefs_process %02x %d",
10911 UnMapId (Id), (char *)(FILE_), __LINE__, Rc, plci->li_write_channel));
10912
10913 a = plci->adapter;
10914 if ((plci->li_bchannel_id == 0)
10915 || (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci != plci))
10916 {
10917 dbug (1, dprintf ("[%06x] %s,%d: Channel id wiped out",
10918 UnMapId (Id), (char *)(FILE_), __LINE__));
10919 return (TRUE);
10920 }
10921 i = a->li_base + (plci->li_bchannel_id - 1);
10922 j = plci->li_write_channel;
10923 p = plci->internal_req_buffer;
10924 if (j != 0)
10925 {
10926 if ((Rc != OK) && (Rc != OK_FC))
10927 {
10928 dbug (1, dprintf ("[%06lx] %s,%d: LI write coefs failed %02x",
10929 UnMapId (Id), (char *)(FILE_), __LINE__, Rc));
10930 return (FALSE);
10931 }
10932 }
10933 if (li_config_table[i].adapter->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT)
10934 {
10935 r = 0;
10936 s = 0;
10937 if (j < li_total_channels)
10938 {
10939 if (li_config_table[i].channel & LI_CHANNEL_ADDRESSES_SET)
10940 {
10941 s = ((li_config_table[i].send_b.card_address.low | li_config_table[i].send_b.card_address.high) ?
10942 (LI_COEF_CH_CH | LI_COEF_CH_PC | LI_COEF_PC_CH | LI_COEF_PC_PC) : (LI_COEF_CH_PC | LI_COEF_PC_PC)) &
10943 ((li_config_table[i].send_pc.card_address.low | li_config_table[i].send_pc.card_address.high) ?
10944 (LI_COEF_CH_CH | LI_COEF_CH_PC | LI_COEF_PC_CH | LI_COEF_PC_PC) : (LI_COEF_CH_CH | LI_COEF_PC_CH));
10945 }
10946 r = ((li_config_table[i].coef_table[j] & 0xf) ^ (li_config_table[i].coef_table[j] >> 4));
10947 while ((j < li_total_channels)
10948 && ((r == 0)
10949 || (!(li_config_table[j].channel & LI_CHANNEL_ADDRESSES_SET))
10950 || (!li_config_table[j].adapter->li_pri
10951 && (j >= li_config_table[j].adapter->li_base + MIXER_BCHANNELS_BRI))
10952 || (((li_config_table[j].send_b.card_address.low != li_config_table[i].send_b.card_address.low)
10953 || (li_config_table[j].send_b.card_address.high != li_config_table[i].send_b.card_address.high))
10954 && (!(a->manufacturer_features & MANUFACTURER_FEATURE_DMACONNECT)
10955 || !(li_config_table[j].adapter->manufacturer_features & MANUFACTURER_FEATURE_DMACONNECT)))
10956 || ((li_config_table[j].adapter->li_base != a->li_base)
10957 && !(r & s &
10958 ((li_config_table[j].send_b.card_address.low | li_config_table[j].send_b.card_address.high) ?
10959 (LI_COEF_CH_CH | LI_COEF_CH_PC | LI_COEF_PC_CH | LI_COEF_PC_PC) : (LI_COEF_PC_CH | LI_COEF_PC_PC)) &
10960 ((li_config_table[j].send_pc.card_address.low | li_config_table[j].send_pc.card_address.high) ?
10961 (LI_COEF_CH_CH | LI_COEF_CH_PC | LI_COEF_PC_CH | LI_COEF_PC_PC) : (LI_COEF_CH_CH | LI_COEF_CH_PC))))))
10962 {
10963 j++;
10964 if (j < li_total_channels)
10965 r = ((li_config_table[i].coef_table[j] & 0xf) ^ (li_config_table[i].coef_table[j] >> 4));
10966 }
10967 }
10968 if (j < li_total_channels)
10969 {
10970 plci->internal_command = plci->li_write_command;
10971 if (plci_nl_busy (plci))
10972 return (TRUE);
10973 to_ch = (a->li_pri) ? plci->li_bchannel_id - 1 : 0;
10974 *(p++) = UDATA_REQUEST_XCONNECT_TO;
10975 do
10976 {
10977 if (li_config_table[j].adapter->li_base != a->li_base)
10978 {
10979 r &= s &
10980 ((li_config_table[j].send_b.card_address.low | li_config_table[j].send_b.card_address.high) ?
10981 (LI_COEF_CH_CH | LI_COEF_CH_PC | LI_COEF_PC_CH | LI_COEF_PC_PC) : (LI_COEF_PC_CH | LI_COEF_PC_PC)) &
10982 ((li_config_table[j].send_pc.card_address.low | li_config_table[j].send_pc.card_address.high) ?
10983 (LI_COEF_CH_CH | LI_COEF_CH_PC | LI_COEF_PC_CH | LI_COEF_PC_PC) : (LI_COEF_CH_CH | LI_COEF_CH_PC));
10984 }
10985 n = 0;
10986 do
10987 {
10988 if (r & xconnect_write_prog[n].mask)
10989 {
10990 if (xconnect_write_prog[n].from_pc)
10991 transfer_address = &(li_config_table[j].send_pc);
10992 else
10993 transfer_address = &(li_config_table[j].send_b);
10994 d = transfer_address->card_address.low;
10995 *(p++) = (byte) d;
10996 *(p++) = (byte)(d >> 8);
10997 *(p++) = (byte)(d >> 16);
10998 *(p++) = (byte)(d >> 24);
10999 d = transfer_address->card_address.high;
11000 *(p++) = (byte) d;
11001 *(p++) = (byte)(d >> 8);
11002 *(p++) = (byte)(d >> 16);
11003 *(p++) = (byte)(d >> 24);
11004 d = transfer_address->offset;
11005 *(p++) = (byte) d;
11006 *(p++) = (byte)(d >> 8);
11007 *(p++) = (byte)(d >> 16);
11008 *(p++) = (byte)(d >> 24);
11009 w = xconnect_write_prog[n].to_pc ? to_ch | XCONNECT_CHANNEL_PORT_PC : to_ch;
11010 *(p++) = (byte) w;
11011 *(p++) = (byte)(w >> 8);
11012 w = ((li_config_table[i].coef_table[j] & xconnect_write_prog[n].mask) == 0) ? 0x01 :
11013 (li_config_table[i].adapter->u_law ?
11014 (li_config_table[j].adapter->u_law ? 0x80 : 0x86) :
11015 (li_config_table[j].adapter->u_law ? 0x7a : 0x80));
11016 *(p++) = (byte) w;
11017 *(p++) = (byte) 0;
11018 li_config_table[i].coef_table[j] ^= xconnect_write_prog[n].mask << 4;
11019 }
11020 n++;
11021 } while ((n < sizeof(xconnect_write_prog) / sizeof(xconnect_write_prog[0]))
11022 && ((p - plci->internal_req_buffer) + 16 < INTERNAL_REQ_BUFFER_SIZE));
11023 if (n == sizeof(xconnect_write_prog) / sizeof(xconnect_write_prog[0]))
11024 {
11025 do
11026 {
11027 j++;
11028 if (j < li_total_channels)
11029 r = ((li_config_table[i].coef_table[j] & 0xf) ^ (li_config_table[i].coef_table[j] >> 4));
11030 } while ((j < li_total_channels)
11031 && ((r == 0)
11032 || (!(li_config_table[j].channel & LI_CHANNEL_ADDRESSES_SET))
11033 || (!li_config_table[j].adapter->li_pri
11034 && (j >= li_config_table[j].adapter->li_base + MIXER_BCHANNELS_BRI))
11035 || (((li_config_table[j].send_b.card_address.low != li_config_table[i].send_b.card_address.low)
11036 || (li_config_table[j].send_b.card_address.high != li_config_table[i].send_b.card_address.high))
11037 && (!(a->manufacturer_features & MANUFACTURER_FEATURE_DMACONNECT)
11038 || !(li_config_table[j].adapter->manufacturer_features & MANUFACTURER_FEATURE_DMACONNECT)))
11039 || ((li_config_table[j].adapter->li_base != a->li_base)
11040 && !(r & s &
11041 ((li_config_table[j].send_b.card_address.low | li_config_table[j].send_b.card_address.high) ?
11042 (LI_COEF_CH_CH | LI_COEF_CH_PC | LI_COEF_PC_CH | LI_COEF_PC_PC) : (LI_COEF_PC_CH | LI_COEF_PC_PC)) &
11043 ((li_config_table[j].send_pc.card_address.low | li_config_table[j].send_pc.card_address.high) ?
11044 (LI_COEF_CH_CH | LI_COEF_CH_PC | LI_COEF_PC_CH | LI_COEF_PC_PC) : (LI_COEF_CH_CH | LI_COEF_CH_PC))))));
11045 }
11046 } while ((j < li_total_channels)
11047 && ((p - plci->internal_req_buffer) + 16 < INTERNAL_REQ_BUFFER_SIZE));
11048 }
11049 else if (j == li_total_channels)
11050 {
11051 plci->internal_command = plci->li_write_command;
11052 if (plci_nl_busy (plci))
11053 return (TRUE);
11054 if (a->li_pri)
11055 {
11056 *(p++) = UDATA_REQUEST_SET_MIXER_COEFS_PRI_SYNC;
11057 w = 0;
11058 if (li_config_table[i].channel & LI_CHANNEL_TX_DATA)
11059 w |= MIXER_FEATURE_ENABLE_TX_DATA;
11060 if (li_config_table[i].channel & LI_CHANNEL_RX_DATA)
11061 w |= MIXER_FEATURE_ENABLE_RX_DATA;
11062 *(p++) = (byte) w;
11063 *(p++) = (byte)(w >> 8);
11064 }
11065 else
11066 {
11067 *(p++) = UDATA_REQUEST_SET_MIXER_COEFS_BRI;
11068 w = 0;
11069 if ((plci->tel == ADV_VOICE) && (plci == a->AdvSignalPLCI)
11070 && (ADV_VOICE_NEW_COEF_BASE + sizeof(word) <= a->adv_voice_coef_length))
11071 {
11072 w = GET_WORD (a->adv_voice_coef_buffer + ADV_VOICE_NEW_COEF_BASE);
11073 }
11074 if (li_config_table[i].channel & LI_CHANNEL_TX_DATA)
11075 w |= MIXER_FEATURE_ENABLE_TX_DATA;
11076 if (li_config_table[i].channel & LI_CHANNEL_RX_DATA)
11077 w |= MIXER_FEATURE_ENABLE_RX_DATA;
11078 *(p++) = (byte) w;
11079 *(p++) = (byte)(w >> 8);
11080 for (j = 0; j < sizeof(ch_map); j += 2)
11081 {
11082 if (plci->li_bchannel_id == 2)
11083 {
11084 ch_map[j] = (byte)(j+1);
11085 ch_map[j+1] = (byte) j;
11086 }
11087 else
11088 {
11089 ch_map[j] = (byte) j;
11090 ch_map[j+1] = (byte)(j+1);
11091 }
11092 }
11093 for (n = 0; n < sizeof(mixer_write_prog_bri) / sizeof(mixer_write_prog_bri[0]); n++)
11094 {
11095 i = a->li_base + ch_map[mixer_write_prog_bri[n].to_ch];
11096 j = a->li_base + ch_map[mixer_write_prog_bri[n].from_ch];
11097 if (li_config_table[i].channel & li_config_table[j].channel & LI_CHANNEL_INVOLVED)
11098 {
11099 *p = (mixer_write_prog_bri[n].xconnect_override != 0) ?
11100 mixer_write_prog_bri[n].xconnect_override :
11101 ((li_config_table[i].coef_table[j] & mixer_write_prog_bri[n].mask) ? 0x80 : 0x01);
11102 if ((i >= a->li_base + MIXER_BCHANNELS_BRI) || (j >= a->li_base + MIXER_BCHANNELS_BRI))
11103 {
11104 w = ((li_config_table[i].coef_table[j] & 0xf) ^ (li_config_table[i].coef_table[j] >> 4));
11105 li_config_table[i].coef_table[j] ^= (w & mixer_write_prog_bri[n].mask) << 4;
11106 }
11107 }
11108 else
11109 {
11110 *p = 0x00;
11111 if ((a->AdvSignalPLCI != NULL) && (a->AdvSignalPLCI->tel == ADV_VOICE))
11112 {
11113 w = (plci == a->AdvSignalPLCI) ? n : mixer_swapped_index_bri[n];
11114 if (ADV_VOICE_NEW_COEF_BASE + sizeof(word) + w < a->adv_voice_coef_length)
11115 *p = a->adv_voice_coef_buffer[ADV_VOICE_NEW_COEF_BASE + sizeof(word) + w];
11116 }
11117 }
11118 p++;
11119 }
11120 }
11121 j = li_total_channels + 1;
11122 }
11123 }
11124 else
11125 {
11126 if (j <= li_total_channels)
11127 {
11128 plci->internal_command = plci->li_write_command;
11129 if (plci_nl_busy (plci))
11130 return (TRUE);
11131 if (j < a->li_base)
11132 j = a->li_base;
11133 if (a->li_pri)
11134 {
11135 *(p++) = UDATA_REQUEST_SET_MIXER_COEFS_PRI_SYNC;
11136 w = 0;
11137 if (li_config_table[i].channel & LI_CHANNEL_TX_DATA)
11138 w |= MIXER_FEATURE_ENABLE_TX_DATA;
11139 if (li_config_table[i].channel & LI_CHANNEL_RX_DATA)
11140 w |= MIXER_FEATURE_ENABLE_RX_DATA;
11141 *(p++) = (byte) w;
11142 *(p++) = (byte)(w >> 8);
11143 for (n = 0; n < sizeof(mixer_write_prog_pri) / sizeof(mixer_write_prog_pri[0]); n++)
11144 {
11145 *(p++) = (byte)((plci->li_bchannel_id - 1) | mixer_write_prog_pri[n].line_flags);
11146 for (j = a->li_base; j < a->li_base + MIXER_CHANNELS_PRI; j++)
11147 {
11148 w = ((li_config_table[i].coef_table[j] & 0xf) ^ (li_config_table[i].coef_table[j] >> 4));
11149 if (w & mixer_write_prog_pri[n].mask)
11150 {
11151 *(p++) = (li_config_table[i].coef_table[j] & mixer_write_prog_pri[n].mask) ? 0x80 : 0x01;
11152 li_config_table[i].coef_table[j] ^= mixer_write_prog_pri[n].mask << 4;
11153 }
11154 else
11155 *(p++) = 0x00;
11156 }
11157 *(p++) = (byte)((plci->li_bchannel_id - 1) | MIXER_COEF_LINE_ROW_FLAG | mixer_write_prog_pri[n].line_flags);
11158 for (j = a->li_base; j < a->li_base + MIXER_CHANNELS_PRI; j++)
11159 {
11160 w = ((li_config_table[j].coef_table[i] & 0xf) ^ (li_config_table[j].coef_table[i] >> 4));
11161 if (w & mixer_write_prog_pri[n].mask)
11162 {
11163 *(p++) = (li_config_table[j].coef_table[i] & mixer_write_prog_pri[n].mask) ? 0x80 : 0x01;
11164 li_config_table[j].coef_table[i] ^= mixer_write_prog_pri[n].mask << 4;
11165 }
11166 else
11167 *(p++) = 0x00;
11168 }
11169 }
11170 }
11171 else
11172 {
11173 *(p++) = UDATA_REQUEST_SET_MIXER_COEFS_BRI;
11174 w = 0;
11175 if ((plci->tel == ADV_VOICE) && (plci == a->AdvSignalPLCI)
11176 && (ADV_VOICE_NEW_COEF_BASE + sizeof(word) <= a->adv_voice_coef_length))
11177 {
11178 w = GET_WORD (a->adv_voice_coef_buffer + ADV_VOICE_NEW_COEF_BASE);
11179 }
11180 if (li_config_table[i].channel & LI_CHANNEL_TX_DATA)
11181 w |= MIXER_FEATURE_ENABLE_TX_DATA;
11182 if (li_config_table[i].channel & LI_CHANNEL_RX_DATA)
11183 w |= MIXER_FEATURE_ENABLE_RX_DATA;
11184 *(p++) = (byte) w;
11185 *(p++) = (byte)(w >> 8);
11186 for (j = 0; j < sizeof(ch_map); j += 2)
11187 {
11188 if (plci->li_bchannel_id == 2)
11189 {
11190 ch_map[j] = (byte)(j+1);
11191 ch_map[j+1] = (byte) j;
11192 }
11193 else
11194 {
11195 ch_map[j] = (byte) j;
11196 ch_map[j+1] = (byte)(j+1);
11197 }
11198 }
11199 for (n = 0; n < sizeof(mixer_write_prog_bri) / sizeof(mixer_write_prog_bri[0]); n++)
11200 {
11201 i = a->li_base + ch_map[mixer_write_prog_bri[n].to_ch];
11202 j = a->li_base + ch_map[mixer_write_prog_bri[n].from_ch];
11203 if (li_config_table[i].channel & li_config_table[j].channel & LI_CHANNEL_INVOLVED)
11204 {
11205 *p = ((li_config_table[i].coef_table[j] & mixer_write_prog_bri[n].mask) ? 0x80 : 0x01);
11206 w = ((li_config_table[i].coef_table[j] & 0xf) ^ (li_config_table[i].coef_table[j] >> 4));
11207 li_config_table[i].coef_table[j] ^= (w & mixer_write_prog_bri[n].mask) << 4;
11208 }
11209 else
11210 {
11211 *p = 0x00;
11212 if ((a->AdvSignalPLCI != NULL) && (a->AdvSignalPLCI->tel == ADV_VOICE))
11213 {
11214 w = (plci == a->AdvSignalPLCI) ? n : mixer_swapped_index_bri[n];
11215 if (ADV_VOICE_NEW_COEF_BASE + sizeof(word) + w < a->adv_voice_coef_length)
11216 *p = a->adv_voice_coef_buffer[ADV_VOICE_NEW_COEF_BASE + sizeof(word) + w];
11217 }
11218 }
11219 p++;
11220 }
11221 }
11222 j = li_total_channels + 1;
11223 }
11224 }
11225 plci->li_write_channel = j;
11226 if (p != plci->internal_req_buffer)
11227 {
11228 plci->NData[0].P = plci->internal_req_buffer;
11229 plci->NData[0].PLength = p - plci->internal_req_buffer;
11230 plci->NL.X = plci->NData;
11231 plci->NL.ReqCh = 0;
11232 plci->NL.Req = plci->nl_req = (byte) N_UDATA;
11233 plci->adapter->request (&plci->NL);
11234 }
11235 return (TRUE);
11236}
11237
11238
11239static void mixer_notify_update (PLCI *plci, byte others)
11240{
11241 DIVA_CAPI_ADAPTER *a;
11242 word i, w;
11243 PLCI *notify_plci;
11244 byte msg[sizeof(CAPI_MSG_HEADER) + 6];
11245
11246 dbug (1, dprintf ("[%06lx] %s,%d: mixer_notify_update %d",
11247 (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
11248 (char *)(FILE_), __LINE__, others));
11249
11250 a = plci->adapter;
11251 if (a->profile.Global_Options & GL_LINE_INTERCONNECT_SUPPORTED)
11252 {
11253 if (others)
11254 plci->li_notify_update = TRUE;
11255 i = 0;
11256 do
11257 {
11258 notify_plci = NULL;
11259 if (others)
11260 {
11261 while ((i < li_total_channels) && (li_config_table[i].plci == NULL))
11262 i++;
11263 if (i < li_total_channels)
11264 notify_plci = li_config_table[i++].plci;
11265 }
11266 else
11267 {
11268 if ((plci->li_bchannel_id != 0)
11269 && (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == plci))
11270 {
11271 notify_plci = plci;
11272 }
11273 }
11274 if ((notify_plci != NULL)
11275 && !notify_plci->li_notify_update
11276 && (notify_plci->appl != NULL)
11277 && (notify_plci->State)
11278 && notify_plci->NL.Id && !notify_plci->nl_remove_id)
11279 {
11280 notify_plci->li_notify_update = TRUE;
11281 ((CAPI_MSG *) msg)->header.length = 18;
11282 ((CAPI_MSG *) msg)->header.appl_id = notify_plci->appl->Id;
11283 ((CAPI_MSG *) msg)->header.command = _FACILITY_R;
11284 ((CAPI_MSG *) msg)->header.number = 0;
11285 ((CAPI_MSG *) msg)->header.controller = notify_plci->adapter->Id;
11286 ((CAPI_MSG *) msg)->header.plci = notify_plci->Id;
11287 ((CAPI_MSG *) msg)->header.ncci = 0;
11288 ((CAPI_MSG *) msg)->info.facility_req.Selector = SELECTOR_LINE_INTERCONNECT;
11289 ((CAPI_MSG *) msg)->info.facility_req.structs[0] = 3;
11290 PUT_WORD (&(((CAPI_MSG *) msg)->info.facility_req.structs[1]), LI_REQ_SILENT_UPDATE);
11291 ((CAPI_MSG *) msg)->info.facility_req.structs[3] = 0;
11292 w = api_put (notify_plci->appl, (CAPI_MSG *) msg);
11293 if (w != _QUEUE_FULL)
11294 {
11295 if (w != 0)
11296 {
11297 dbug (1, dprintf ("[%06lx] %s,%d: Interconnect notify failed %06x %d",
11298 (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
11299 (char *)(FILE_), __LINE__,
11300 (dword)((notify_plci->Id << 8) | UnMapController (notify_plci->adapter->Id)), w));
11301 }
11302 notify_plci->li_notify_update = FALSE;
11303 }
11304 }
11305 } while (others && (notify_plci != NULL));
11306 if (others)
11307 plci->li_notify_update = FALSE;
11308 }
11309}
11310
11311
11312static void mixer_clear_config (PLCI *plci)
11313{
11314 DIVA_CAPI_ADAPTER *a;
11315 word i, j;
11316
11317 dbug (1, dprintf ("[%06lx] %s,%d: mixer_clear_config",
11318 (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
11319 (char *)(FILE_), __LINE__));
11320
11321 plci->li_notify_update = FALSE;
11322 plci->li_plci_b_write_pos = 0;
11323 plci->li_plci_b_read_pos = 0;
11324 plci->li_plci_b_req_pos = 0;
11325 a = plci->adapter;
11326 if ((plci->li_bchannel_id != 0)
11327 && (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == plci))
11328 {
11329 i = a->li_base + (plci->li_bchannel_id - 1);
11330 li_config_table[i].curchnl = 0;
11331 li_config_table[i].channel = 0;
11332 li_config_table[i].chflags = 0;
11333 for (j = 0; j < li_total_channels; j++)
11334 {
11335 li_config_table[j].flag_table[i] = 0;
11336 li_config_table[i].flag_table[j] = 0;
11337 li_config_table[i].coef_table[j] = 0;
11338 li_config_table[j].coef_table[i] = 0;
11339 }
11340 if (!a->li_pri)
11341 {
11342 li_config_table[i].coef_table[i] |= LI_COEF_CH_PC_SET | LI_COEF_PC_CH_SET;
11343 if ((plci->tel == ADV_VOICE) && (plci == a->AdvSignalPLCI))
11344 {
11345 i = a->li_base + MIXER_IC_CHANNEL_BASE + (plci->li_bchannel_id - 1);
11346 li_config_table[i].curchnl = 0;
11347 li_config_table[i].channel = 0;
11348 li_config_table[i].chflags = 0;
11349 for (j = 0; j < li_total_channels; j++)
11350 {
11351 li_config_table[i].flag_table[j] = 0;
11352 li_config_table[j].flag_table[i] = 0;
11353 li_config_table[i].coef_table[j] = 0;
11354 li_config_table[j].coef_table[i] = 0;
11355 }
11356 if (a->manufacturer_features & MANUFACTURER_FEATURE_SLAVE_CODEC)
11357 {
11358 i = a->li_base + MIXER_IC_CHANNEL_BASE + (2 - plci->li_bchannel_id);
11359 li_config_table[i].curchnl = 0;
11360 li_config_table[i].channel = 0;
11361 li_config_table[i].chflags = 0;
11362 for (j = 0; j < li_total_channels; j++)
11363 {
11364 li_config_table[i].flag_table[j] = 0;
11365 li_config_table[j].flag_table[i] = 0;
11366 li_config_table[i].coef_table[j] = 0;
11367 li_config_table[j].coef_table[i] = 0;
11368 }
11369 }
11370 }
11371 }
11372 }
11373}
11374
11375
11376static void mixer_prepare_switch (dword Id, PLCI *plci)
11377{
11378
11379 dbug (1, dprintf ("[%06lx] %s,%d: mixer_prepare_switch",
11380 UnMapId (Id), (char *)(FILE_), __LINE__));
11381
11382 do
11383 {
11384 mixer_indication_coefs_set (Id, plci);
11385 } while (plci->li_plci_b_read_pos != plci->li_plci_b_req_pos);
11386}
11387
11388
11389static word mixer_save_config (dword Id, PLCI *plci, byte Rc)
11390{
11391 DIVA_CAPI_ADAPTER *a;
11392 word i, j;
11393
11394 dbug (1, dprintf ("[%06lx] %s,%d: mixer_save_config %02x %d",
11395 UnMapId (Id), (char *)(FILE_), __LINE__, Rc, plci->adjust_b_state));
11396
11397 a = plci->adapter;
11398 if ((plci->li_bchannel_id != 0)
11399 && (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == plci))
11400 {
11401 i = a->li_base + (plci->li_bchannel_id - 1);
11402 for (j = 0; j < li_total_channels; j++)
11403 {
11404 li_config_table[i].coef_table[j] &= 0xf;
11405 li_config_table[j].coef_table[i] &= 0xf;
11406 }
11407 if (!a->li_pri)
11408 li_config_table[i].coef_table[i] |= LI_COEF_CH_PC_SET | LI_COEF_PC_CH_SET;
11409 }
11410 return (GOOD);
11411}
11412
11413
11414static word mixer_restore_config (dword Id, PLCI *plci, byte Rc)
11415{
11416 DIVA_CAPI_ADAPTER *a;
11417 word Info;
11418
11419 dbug (1, dprintf ("[%06lx] %s,%d: mixer_restore_config %02x %d",
11420 UnMapId (Id), (char *)(FILE_), __LINE__, Rc, plci->adjust_b_state));
11421
11422 Info = GOOD;
11423 a = plci->adapter;
11424 if ((plci->B1_facilities & B1_FACILITY_MIXER)
11425 && (plci->li_bchannel_id != 0)
11426 && (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == plci))
11427 {
11428 switch (plci->adjust_b_state)
11429 {
11430 case ADJUST_B_RESTORE_MIXER_1:
11431 if (a->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT)
11432 {
11433 plci->internal_command = plci->adjust_b_command;
11434 if (plci_nl_busy (plci))
11435 {
11436 plci->adjust_b_state = ADJUST_B_RESTORE_MIXER_1;
11437 break;
11438 }
11439 xconnect_query_addresses (plci);
11440 plci->adjust_b_state = ADJUST_B_RESTORE_MIXER_2;
11441 break;
11442 }
11443 plci->adjust_b_state = ADJUST_B_RESTORE_MIXER_5;
11444 Rc = OK;
11445 case ADJUST_B_RESTORE_MIXER_2:
11446 case ADJUST_B_RESTORE_MIXER_3:
11447 case ADJUST_B_RESTORE_MIXER_4:
11448 if ((Rc != OK) && (Rc != OK_FC) && (Rc != 0))
11449 {
11450 dbug (1, dprintf ("[%06lx] %s,%d: Adjust B query addresses failed %02x",
11451 UnMapId (Id), (char *)(FILE_), __LINE__, Rc));
11452 Info = _WRONG_STATE;
11453 break;
11454 }
11455 if (Rc == OK)
11456 {
11457 if (plci->adjust_b_state == ADJUST_B_RESTORE_MIXER_2)
11458 plci->adjust_b_state = ADJUST_B_RESTORE_MIXER_3;
11459 else if (plci->adjust_b_state == ADJUST_B_RESTORE_MIXER_4)
11460 plci->adjust_b_state = ADJUST_B_RESTORE_MIXER_5;
11461 }
11462 else if (Rc == 0)
11463 {
11464 if (plci->adjust_b_state == ADJUST_B_RESTORE_MIXER_2)
11465 plci->adjust_b_state = ADJUST_B_RESTORE_MIXER_4;
11466 else if (plci->adjust_b_state == ADJUST_B_RESTORE_MIXER_3)
11467 plci->adjust_b_state = ADJUST_B_RESTORE_MIXER_5;
11468 }
11469 if (plci->adjust_b_state != ADJUST_B_RESTORE_MIXER_5)
11470 {
11471 plci->internal_command = plci->adjust_b_command;
11472 break;
11473 }
11474 case ADJUST_B_RESTORE_MIXER_5:
11475 xconnect_write_coefs (plci, plci->adjust_b_command);
11476 plci->adjust_b_state = ADJUST_B_RESTORE_MIXER_6;
11477 Rc = OK;
11478 case ADJUST_B_RESTORE_MIXER_6:
11479 if (!xconnect_write_coefs_process (Id, plci, Rc))
11480 {
11481 dbug (1, dprintf ("[%06lx] %s,%d: Write mixer coefs failed",
11482 UnMapId (Id), (char *)(FILE_), __LINE__));
11483 Info = _FACILITY_NOT_SUPPORTED;
11484 break;
11485 }
11486 if (plci->internal_command)
11487 break;
11488 plci->adjust_b_state = ADJUST_B_RESTORE_MIXER_7;
11489 case ADJUST_B_RESTORE_MIXER_7:
11490 break;
11491 }
11492 }
11493 return (Info);
11494}
11495
11496
11497static void mixer_command (dword Id, PLCI *plci, byte Rc)
11498{
11499 DIVA_CAPI_ADAPTER *a;
11500 word i, internal_command, Info;
11501
11502 dbug (1, dprintf ("[%06lx] %s,%d: mixer_command %02x %04x %04x",
11503 UnMapId (Id), (char *)(FILE_), __LINE__, Rc, plci->internal_command,
11504 plci->li_cmd));
11505
11506 Info = GOOD;
11507 a = plci->adapter;
11508 internal_command = plci->internal_command;
11509 plci->internal_command = 0;
11510 switch (plci->li_cmd)
11511 {
11512 case LI_REQ_CONNECT:
11513 case LI_REQ_DISCONNECT:
11514 case LI_REQ_SILENT_UPDATE:
11515 switch (internal_command)
11516 {
11517 default:
11518 if (plci->li_channel_bits & LI_CHANNEL_INVOLVED)
11519 {
11520 adjust_b1_resource (Id, plci, NULL, (word)(plci->B1_facilities |
11521 B1_FACILITY_MIXER), MIXER_COMMAND_1);
11522 }
11523 case MIXER_COMMAND_1:
11524 if (plci->li_channel_bits & LI_CHANNEL_INVOLVED)
11525 {
11526 if (adjust_b_process (Id, plci, Rc) != GOOD)
11527 {
11528 dbug (1, dprintf ("[%06lx] %s,%d: Load mixer failed",
11529 UnMapId (Id), (char *)(FILE_), __LINE__));
11530 Info = _FACILITY_NOT_SUPPORTED;
11531 break;
11532 }
11533 if (plci->internal_command)
11534 return;
11535 }
11536 plci->li_plci_b_req_pos = plci->li_plci_b_write_pos;
11537 if ((plci->li_channel_bits & LI_CHANNEL_INVOLVED)
11538 || ((get_b1_facilities (plci, plci->B1_resource) & B1_FACILITY_MIXER)
11539 && (add_b1_facilities (plci, plci->B1_resource, (word)(plci->B1_facilities &
11540 ~B1_FACILITY_MIXER)) == plci->B1_resource)))
11541 {
11542 xconnect_write_coefs (plci, MIXER_COMMAND_2);
11543 }
11544 else
11545 {
11546 do
11547 {
11548 mixer_indication_coefs_set (Id, plci);
11549 } while (plci->li_plci_b_read_pos != plci->li_plci_b_req_pos);
11550 }
11551 case MIXER_COMMAND_2:
11552 if ((plci->li_channel_bits & LI_CHANNEL_INVOLVED)
11553 || ((get_b1_facilities (plci, plci->B1_resource) & B1_FACILITY_MIXER)
11554 && (add_b1_facilities (plci, plci->B1_resource, (word)(plci->B1_facilities &
11555 ~B1_FACILITY_MIXER)) == plci->B1_resource)))
11556 {
11557 if (!xconnect_write_coefs_process (Id, plci, Rc))
11558 {
11559 dbug (1, dprintf ("[%06lx] %s,%d: Write mixer coefs failed",
11560 UnMapId (Id), (char *)(FILE_), __LINE__));
11561 if (plci->li_plci_b_write_pos != plci->li_plci_b_req_pos)
11562 {
11563 do
11564 {
11565 plci->li_plci_b_write_pos = (plci->li_plci_b_write_pos == 0) ?
11566 LI_PLCI_B_QUEUE_ENTRIES-1 : plci->li_plci_b_write_pos - 1;
11567 i = (plci->li_plci_b_write_pos == 0) ?
11568 LI_PLCI_B_QUEUE_ENTRIES-1 : plci->li_plci_b_write_pos - 1;
11569 } while ((plci->li_plci_b_write_pos != plci->li_plci_b_req_pos)
11570 && !(plci->li_plci_b_queue[i] & LI_PLCI_B_LAST_FLAG));
11571 }
11572 Info = _FACILITY_NOT_SUPPORTED;
11573 break;
11574 }
11575 if (plci->internal_command)
11576 return;
11577 }
11578 if (!(plci->li_channel_bits & LI_CHANNEL_INVOLVED))
11579 {
11580 adjust_b1_resource (Id, plci, NULL, (word)(plci->B1_facilities &
11581 ~B1_FACILITY_MIXER), MIXER_COMMAND_3);
11582 }
11583 case MIXER_COMMAND_3:
11584 if (!(plci->li_channel_bits & LI_CHANNEL_INVOLVED))
11585 {
11586 if (adjust_b_process (Id, plci, Rc) != GOOD)
11587 {
11588 dbug (1, dprintf ("[%06lx] %s,%d: Unload mixer failed",
11589 UnMapId (Id), (char *)(FILE_), __LINE__));
11590 Info = _FACILITY_NOT_SUPPORTED;
11591 break;
11592 }
11593 if (plci->internal_command)
11594 return;
11595 }
11596 break;
11597 }
11598 break;
11599 }
11600 if ((plci->li_bchannel_id == 0)
11601 || (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci != plci))
11602 {
11603 dbug (1, dprintf ("[%06x] %s,%d: Channel id wiped out %d",
11604 UnMapId (Id), (char *)(FILE_), __LINE__, (int)(plci->li_bchannel_id)));
11605 }
11606 else
11607 {
11608 i = a->li_base + (plci->li_bchannel_id - 1);
11609 li_config_table[i].curchnl = plci->li_channel_bits;
11610 if (!a->li_pri && (plci->tel == ADV_VOICE) && (plci == a->AdvSignalPLCI))
11611 {
11612 i = a->li_base + MIXER_IC_CHANNEL_BASE + (plci->li_bchannel_id - 1);
11613 li_config_table[i].curchnl = plci->li_channel_bits;
11614 if (a->manufacturer_features & MANUFACTURER_FEATURE_SLAVE_CODEC)
11615 {
11616 i = a->li_base + MIXER_IC_CHANNEL_BASE + (2 - plci->li_bchannel_id);
11617 li_config_table[i].curchnl = plci->li_channel_bits;
11618 }
11619 }
11620 }
11621}
11622
11623
11624static void li_update_connect (dword Id, DIVA_CAPI_ADAPTER *a, PLCI *plci,
11625 dword plci_b_id, byte connect, dword li_flags)
11626{
11627 word i, ch_a, ch_a_v, ch_a_s, ch_b, ch_b_v, ch_b_s;
11628 PLCI *plci_b;
11629 DIVA_CAPI_ADAPTER *a_b;
11630
11631 a_b = &(adapter[MapController ((byte)(plci_b_id & 0x7f)) - 1]);
11632 plci_b = &(a_b->plci[((plci_b_id >> 8) & 0xff) - 1]);
11633 ch_a = a->li_base + (plci->li_bchannel_id - 1);
11634 if (!a->li_pri && (plci->tel == ADV_VOICE)
11635 && (plci == a->AdvSignalPLCI) && (Id & EXT_CONTROLLER))
11636 {
11637 ch_a_v = ch_a + MIXER_IC_CHANNEL_BASE;
11638 ch_a_s = (a->manufacturer_features & MANUFACTURER_FEATURE_SLAVE_CODEC) ?
11639 a->li_base + MIXER_IC_CHANNEL_BASE + (2 - plci->li_bchannel_id) : ch_a_v;
11640 }
11641 else
11642 {
11643 ch_a_v = ch_a;
11644 ch_a_s = ch_a;
11645 }
11646 ch_b = a_b->li_base + (plci_b->li_bchannel_id - 1);
11647 if (!a_b->li_pri && (plci_b->tel == ADV_VOICE)
11648 && (plci_b == a_b->AdvSignalPLCI) && (plci_b_id & EXT_CONTROLLER))
11649 {
11650 ch_b_v = ch_b + MIXER_IC_CHANNEL_BASE;
11651 ch_b_s = (a_b->manufacturer_features & MANUFACTURER_FEATURE_SLAVE_CODEC) ?
11652 a_b->li_base + MIXER_IC_CHANNEL_BASE + (2 - plci_b->li_bchannel_id) : ch_b_v;
11653 }
11654 else
11655 {
11656 ch_b_v = ch_b;
11657 ch_b_s = ch_b;
11658 }
11659 if (connect)
11660 {
11661 li_config_table[ch_a].flag_table[ch_a_v] &= ~LI_FLAG_MONITOR;
11662 li_config_table[ch_a].flag_table[ch_a_s] &= ~LI_FLAG_MONITOR;
11663 li_config_table[ch_a_v].flag_table[ch_a] &= ~(LI_FLAG_ANNOUNCEMENT | LI_FLAG_MIX);
11664 li_config_table[ch_a_s].flag_table[ch_a] &= ~(LI_FLAG_ANNOUNCEMENT | LI_FLAG_MIX);
11665 }
11666 li_config_table[ch_a].flag_table[ch_b_v] &= ~LI_FLAG_MONITOR;
11667 li_config_table[ch_a].flag_table[ch_b_s] &= ~LI_FLAG_MONITOR;
11668 li_config_table[ch_b_v].flag_table[ch_a] &= ~(LI_FLAG_ANNOUNCEMENT | LI_FLAG_MIX);
11669 li_config_table[ch_b_s].flag_table[ch_a] &= ~(LI_FLAG_ANNOUNCEMENT | LI_FLAG_MIX);
11670 if (ch_a_v == ch_b_v)
11671 {
11672 li_config_table[ch_a_v].flag_table[ch_b_v] &= ~LI_FLAG_CONFERENCE;
11673 li_config_table[ch_a_s].flag_table[ch_b_s] &= ~LI_FLAG_CONFERENCE;
11674 }
11675 else
11676 {
11677 if (li_config_table[ch_a_v].flag_table[ch_b_v] & LI_FLAG_CONFERENCE)
11678 {
11679 for (i = 0; i < li_total_channels; i++)
11680 {
11681 if (i != ch_a_v)
11682 li_config_table[ch_a_v].flag_table[i] &= ~LI_FLAG_CONFERENCE;
11683 }
11684 }
11685 if (li_config_table[ch_a_s].flag_table[ch_b_v] & LI_FLAG_CONFERENCE)
11686 {
11687 for (i = 0; i < li_total_channels; i++)
11688 {
11689 if (i != ch_a_s)
11690 li_config_table[ch_a_s].flag_table[i] &= ~LI_FLAG_CONFERENCE;
11691 }
11692 }
11693 if (li_config_table[ch_b_v].flag_table[ch_a_v] & LI_FLAG_CONFERENCE)
11694 {
11695 for (i = 0; i < li_total_channels; i++)
11696 {
11697 if (i != ch_a_v)
11698 li_config_table[i].flag_table[ch_a_v] &= ~LI_FLAG_CONFERENCE;
11699 }
11700 }
11701 if (li_config_table[ch_b_v].flag_table[ch_a_s] & LI_FLAG_CONFERENCE)
11702 {
11703 for (i = 0; i < li_total_channels; i++)
11704 {
11705 if (i != ch_a_s)
11706 li_config_table[i].flag_table[ch_a_s] &= ~LI_FLAG_CONFERENCE;
11707 }
11708 }
11709 }
11710 if (li_flags & LI_FLAG_CONFERENCE_A_B)
11711 {
11712 li_config_table[ch_b_v].flag_table[ch_a_v] |= LI_FLAG_CONFERENCE;
11713 li_config_table[ch_b_s].flag_table[ch_a_v] |= LI_FLAG_CONFERENCE;
11714 li_config_table[ch_b_v].flag_table[ch_a_s] |= LI_FLAG_CONFERENCE;
11715 li_config_table[ch_b_s].flag_table[ch_a_s] |= LI_FLAG_CONFERENCE;
11716 }
11717 if (li_flags & LI_FLAG_CONFERENCE_B_A)
11718 {
11719 li_config_table[ch_a_v].flag_table[ch_b_v] |= LI_FLAG_CONFERENCE;
11720 li_config_table[ch_a_v].flag_table[ch_b_s] |= LI_FLAG_CONFERENCE;
11721 li_config_table[ch_a_s].flag_table[ch_b_v] |= LI_FLAG_CONFERENCE;
11722 li_config_table[ch_a_s].flag_table[ch_b_s] |= LI_FLAG_CONFERENCE;
11723 }
11724 if (li_flags & LI_FLAG_MONITOR_A)
11725 {
11726 li_config_table[ch_a].flag_table[ch_a_v] |= LI_FLAG_MONITOR;
11727 li_config_table[ch_a].flag_table[ch_a_s] |= LI_FLAG_MONITOR;
11728 }
11729 if (li_flags & LI_FLAG_MONITOR_B)
11730 {
11731 li_config_table[ch_a].flag_table[ch_b_v] |= LI_FLAG_MONITOR;
11732 li_config_table[ch_a].flag_table[ch_b_s] |= LI_FLAG_MONITOR;
11733 }
11734 if (li_flags & LI_FLAG_ANNOUNCEMENT_A)
11735 {
11736 li_config_table[ch_a_v].flag_table[ch_a] |= LI_FLAG_ANNOUNCEMENT;
11737 li_config_table[ch_a_s].flag_table[ch_a] |= LI_FLAG_ANNOUNCEMENT;
11738 }
11739 if (li_flags & LI_FLAG_ANNOUNCEMENT_B)
11740 {
11741 li_config_table[ch_b_v].flag_table[ch_a] |= LI_FLAG_ANNOUNCEMENT;
11742 li_config_table[ch_b_s].flag_table[ch_a] |= LI_FLAG_ANNOUNCEMENT;
11743 }
11744 if (li_flags & LI_FLAG_MIX_A)
11745 {
11746 li_config_table[ch_a_v].flag_table[ch_a] |= LI_FLAG_MIX;
11747 li_config_table[ch_a_s].flag_table[ch_a] |= LI_FLAG_MIX;
11748 }
11749 if (li_flags & LI_FLAG_MIX_B)
11750 {
11751 li_config_table[ch_b_v].flag_table[ch_a] |= LI_FLAG_MIX;
11752 li_config_table[ch_b_s].flag_table[ch_a] |= LI_FLAG_MIX;
11753 }
11754 if (ch_a_v != ch_a_s)
11755 {
11756 li_config_table[ch_a_v].flag_table[ch_a_s] |= LI_FLAG_CONFERENCE;
11757 li_config_table[ch_a_s].flag_table[ch_a_v] |= LI_FLAG_CONFERENCE;
11758 }
11759 if (ch_b_v != ch_b_s)
11760 {
11761 li_config_table[ch_b_v].flag_table[ch_b_s] |= LI_FLAG_CONFERENCE;
11762 li_config_table[ch_b_s].flag_table[ch_b_v] |= LI_FLAG_CONFERENCE;
11763 }
11764}
11765
11766
11767static void li2_update_connect (dword Id, DIVA_CAPI_ADAPTER *a, PLCI *plci,
11768 dword plci_b_id, byte connect, dword li_flags)
11769{
11770 word ch_a, ch_a_v, ch_a_s, ch_b, ch_b_v, ch_b_s;
11771 PLCI *plci_b;
11772 DIVA_CAPI_ADAPTER *a_b;
11773
11774 a_b = &(adapter[MapController ((byte)(plci_b_id & 0x7f)) - 1]);
11775 plci_b = &(a_b->plci[((plci_b_id >> 8) & 0xff) - 1]);
11776 ch_a = a->li_base + (plci->li_bchannel_id - 1);
11777 if (!a->li_pri && (plci->tel == ADV_VOICE)
11778 && (plci == a->AdvSignalPLCI) && (Id & EXT_CONTROLLER))
11779 {
11780 ch_a_v = ch_a + MIXER_IC_CHANNEL_BASE;
11781 ch_a_s = (a->manufacturer_features & MANUFACTURER_FEATURE_SLAVE_CODEC) ?
11782 a->li_base + MIXER_IC_CHANNEL_BASE + (2 - plci->li_bchannel_id) : ch_a_v;
11783 }
11784 else
11785 {
11786 ch_a_v = ch_a;
11787 ch_a_s = ch_a;
11788 }
11789 ch_b = a_b->li_base + (plci_b->li_bchannel_id - 1);
11790 if (!a_b->li_pri && (plci_b->tel == ADV_VOICE)
11791 && (plci_b == a_b->AdvSignalPLCI) && (plci_b_id & EXT_CONTROLLER))
11792 {
11793 ch_b_v = ch_b + MIXER_IC_CHANNEL_BASE;
11794 ch_b_s = (a_b->manufacturer_features & MANUFACTURER_FEATURE_SLAVE_CODEC) ?
11795 a_b->li_base + MIXER_IC_CHANNEL_BASE + (2 - plci_b->li_bchannel_id) : ch_b_v;
11796 }
11797 else
11798 {
11799 ch_b_v = ch_b;
11800 ch_b_s = ch_b;
11801 }
11802 if (connect)
11803 {
11804 li_config_table[ch_b].flag_table[ch_b_v] &= ~LI_FLAG_MONITOR;
11805 li_config_table[ch_b].flag_table[ch_b_s] &= ~LI_FLAG_MONITOR;
11806 li_config_table[ch_b_v].flag_table[ch_b] &= ~LI_FLAG_MIX;
11807 li_config_table[ch_b_s].flag_table[ch_b] &= ~LI_FLAG_MIX;
11808 li_config_table[ch_b].flag_table[ch_b] &= ~LI_FLAG_PCCONNECT;
11809 li_config_table[ch_b].chflags &= ~(LI_CHFLAG_MONITOR | LI_CHFLAG_MIX | LI_CHFLAG_LOOP);
11810 }
11811 li_config_table[ch_b_v].flag_table[ch_a_v] &= ~(LI_FLAG_INTERCONNECT | LI_FLAG_CONFERENCE);
11812 li_config_table[ch_b_s].flag_table[ch_a_v] &= ~(LI_FLAG_INTERCONNECT | LI_FLAG_CONFERENCE);
11813 li_config_table[ch_b_v].flag_table[ch_a_s] &= ~(LI_FLAG_INTERCONNECT | LI_FLAG_CONFERENCE);
11814 li_config_table[ch_b_s].flag_table[ch_a_s] &= ~(LI_FLAG_INTERCONNECT | LI_FLAG_CONFERENCE);
11815 li_config_table[ch_a_v].flag_table[ch_b_v] &= ~(LI_FLAG_INTERCONNECT | LI_FLAG_CONFERENCE);
11816 li_config_table[ch_a_v].flag_table[ch_b_s] &= ~(LI_FLAG_INTERCONNECT | LI_FLAG_CONFERENCE);
11817 li_config_table[ch_a_s].flag_table[ch_b_v] &= ~(LI_FLAG_INTERCONNECT | LI_FLAG_CONFERENCE);
11818 li_config_table[ch_a_s].flag_table[ch_b_s] &= ~(LI_FLAG_INTERCONNECT | LI_FLAG_CONFERENCE);
11819 if (li_flags & LI2_FLAG_INTERCONNECT_A_B)
11820 {
11821 li_config_table[ch_b_v].flag_table[ch_a_v] |= LI_FLAG_INTERCONNECT;
11822 li_config_table[ch_b_s].flag_table[ch_a_v] |= LI_FLAG_INTERCONNECT;
11823 li_config_table[ch_b_v].flag_table[ch_a_s] |= LI_FLAG_INTERCONNECT;
11824 li_config_table[ch_b_s].flag_table[ch_a_s] |= LI_FLAG_INTERCONNECT;
11825 }
11826 if (li_flags & LI2_FLAG_INTERCONNECT_B_A)
11827 {
11828 li_config_table[ch_a_v].flag_table[ch_b_v] |= LI_FLAG_INTERCONNECT;
11829 li_config_table[ch_a_v].flag_table[ch_b_s] |= LI_FLAG_INTERCONNECT;
11830 li_config_table[ch_a_s].flag_table[ch_b_v] |= LI_FLAG_INTERCONNECT;
11831 li_config_table[ch_a_s].flag_table[ch_b_s] |= LI_FLAG_INTERCONNECT;
11832 }
11833 if (li_flags & LI2_FLAG_MONITOR_B)
11834 {
11835 li_config_table[ch_b].flag_table[ch_b_v] |= LI_FLAG_MONITOR;
11836 li_config_table[ch_b].flag_table[ch_b_s] |= LI_FLAG_MONITOR;
11837 }
11838 if (li_flags & LI2_FLAG_MIX_B)
11839 {
11840 li_config_table[ch_b_v].flag_table[ch_b] |= LI_FLAG_MIX;
11841 li_config_table[ch_b_s].flag_table[ch_b] |= LI_FLAG_MIX;
11842 }
11843 if (li_flags & LI2_FLAG_MONITOR_X)
11844 li_config_table[ch_b].chflags |= LI_CHFLAG_MONITOR;
11845 if (li_flags & LI2_FLAG_MIX_X)
11846 li_config_table[ch_b].chflags |= LI_CHFLAG_MIX;
11847 if (li_flags & LI2_FLAG_LOOP_B)
11848 {
11849 li_config_table[ch_b_v].flag_table[ch_b_v] |= LI_FLAG_INTERCONNECT;
11850 li_config_table[ch_b_s].flag_table[ch_b_v] |= LI_FLAG_INTERCONNECT;
11851 li_config_table[ch_b_v].flag_table[ch_b_s] |= LI_FLAG_INTERCONNECT;
11852 li_config_table[ch_b_s].flag_table[ch_b_s] |= LI_FLAG_INTERCONNECT;
11853 }
11854 if (li_flags & LI2_FLAG_LOOP_PC)
11855 li_config_table[ch_b].flag_table[ch_b] |= LI_FLAG_PCCONNECT;
11856 if (li_flags & LI2_FLAG_LOOP_X)
11857 li_config_table[ch_b].chflags |= LI_CHFLAG_LOOP;
11858 if (li_flags & LI2_FLAG_PCCONNECT_A_B)
11859 li_config_table[ch_b_s].flag_table[ch_a_s] |= LI_FLAG_PCCONNECT;
11860 if (li_flags & LI2_FLAG_PCCONNECT_B_A)
11861 li_config_table[ch_a_s].flag_table[ch_b_s] |= LI_FLAG_PCCONNECT;
11862 if (ch_a_v != ch_a_s)
11863 {
11864 li_config_table[ch_a_v].flag_table[ch_a_s] |= LI_FLAG_CONFERENCE;
11865 li_config_table[ch_a_s].flag_table[ch_a_v] |= LI_FLAG_CONFERENCE;
11866 }
11867 if (ch_b_v != ch_b_s)
11868 {
11869 li_config_table[ch_b_v].flag_table[ch_b_s] |= LI_FLAG_CONFERENCE;
11870 li_config_table[ch_b_s].flag_table[ch_b_v] |= LI_FLAG_CONFERENCE;
11871 }
11872}
11873
11874
11875static word li_check_main_plci (dword Id, PLCI *plci)
11876{
11877 if (plci == NULL)
11878 {
11879 dbug (1, dprintf ("[%06lx] %s,%d: Wrong PLCI",
11880 UnMapId (Id), (char *)(FILE_), __LINE__));
11881 return (_WRONG_IDENTIFIER);
11882 }
11883 if (!plci->State
11884 || !plci->NL.Id || plci->nl_remove_id
11885 || (plci->li_bchannel_id == 0))
11886 {
11887 dbug (1, dprintf ("[%06lx] %s,%d: Wrong state",
11888 UnMapId (Id), (char *)(FILE_), __LINE__));
11889 return (_WRONG_STATE);
11890 }
11891 li_config_table[plci->adapter->li_base + (plci->li_bchannel_id - 1)].plci = plci;
11892 return (GOOD);
11893}
11894
11895
11896static PLCI *li_check_plci_b (dword Id, PLCI *plci,
11897 dword plci_b_id, word plci_b_write_pos, byte *p_result)
11898{
11899 byte ctlr_b;
11900 PLCI *plci_b;
11901
11902 if (((plci->li_plci_b_read_pos > plci_b_write_pos) ? plci->li_plci_b_read_pos :
11903 LI_PLCI_B_QUEUE_ENTRIES + plci->li_plci_b_read_pos) - plci_b_write_pos - 1 < 2)
11904 {
11905 dbug (1, dprintf ("[%06lx] %s,%d: LI request overrun",
11906 UnMapId (Id), (char *)(FILE_), __LINE__));
11907 PUT_WORD (p_result, _REQUEST_NOT_ALLOWED_IN_THIS_STATE);
11908 return (NULL);
11909 }
11910 ctlr_b = 0;
11911 if ((plci_b_id & 0x7f) != 0)
11912 {
11913 ctlr_b = MapController ((byte)(plci_b_id & 0x7f));
11914 if ((ctlr_b > max_adapter) || ((ctlr_b != 0) && (adapter[ctlr_b - 1].request == NULL)))
11915 ctlr_b = 0;
11916 }
11917 if ((ctlr_b == 0)
11918 || (((plci_b_id >> 8) & 0xff) == 0)
11919 || (((plci_b_id >> 8) & 0xff) > adapter[ctlr_b - 1].max_plci))
11920 {
11921 dbug (1, dprintf ("[%06lx] %s,%d: LI invalid second PLCI %08lx",
11922 UnMapId (Id), (char *)(FILE_), __LINE__, plci_b_id));
11923 PUT_WORD (p_result, _WRONG_IDENTIFIER);
11924 return (NULL);
11925 }
11926 plci_b = &(adapter[ctlr_b - 1].plci[((plci_b_id >> 8) & 0xff) - 1]);
11927 if (!plci_b->State
11928 || !plci_b->NL.Id || plci_b->nl_remove_id
11929 || (plci_b->li_bchannel_id == 0))
11930 {
11931 dbug (1, dprintf ("[%06lx] %s,%d: LI peer in wrong state %08lx",
11932 UnMapId (Id), (char *)(FILE_), __LINE__, plci_b_id));
11933 PUT_WORD (p_result, _REQUEST_NOT_ALLOWED_IN_THIS_STATE);
11934 return (NULL);
11935 }
11936 li_config_table[plci_b->adapter->li_base + (plci_b->li_bchannel_id - 1)].plci = plci_b;
11937 if (((byte)(plci_b_id & ~EXT_CONTROLLER)) !=
11938 ((byte)(UnMapController (plci->adapter->Id) & ~EXT_CONTROLLER))
11939 && (!(plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT)
11940 || !(plci_b->adapter->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT)))
11941 {
11942 dbug (1, dprintf ("[%06lx] %s,%d: LI not on same ctrl %08lx",
11943 UnMapId (Id), (char *)(FILE_), __LINE__, plci_b_id));
11944 PUT_WORD (p_result, _WRONG_IDENTIFIER);
11945 return (NULL);
11946 }
11947 if (!(get_b1_facilities (plci_b, add_b1_facilities (plci_b, plci_b->B1_resource,
11948 (word)(plci_b->B1_facilities | B1_FACILITY_MIXER))) & B1_FACILITY_MIXER))
11949 {
11950 dbug (1, dprintf ("[%06lx] %s,%d: Interconnect peer cannot mix %d",
11951 UnMapId (Id), (char *)(FILE_), __LINE__, plci_b->B1_resource));
11952 PUT_WORD (p_result, _REQUEST_NOT_ALLOWED_IN_THIS_STATE);
11953 return (NULL);
11954 }
11955 return (plci_b);
11956}
11957
11958
11959static PLCI *li2_check_plci_b (dword Id, PLCI *plci,
11960 dword plci_b_id, word plci_b_write_pos, byte *p_result)
11961{
11962 byte ctlr_b;
11963 PLCI *plci_b;
11964
11965 if (((plci->li_plci_b_read_pos > plci_b_write_pos) ? plci->li_plci_b_read_pos :
11966 LI_PLCI_B_QUEUE_ENTRIES + plci->li_plci_b_read_pos) - plci_b_write_pos - 1 < 2)
11967 {
11968 dbug (1, dprintf ("[%06lx] %s,%d: LI request overrun",
11969 UnMapId (Id), (char *)(FILE_), __LINE__));
11970 PUT_WORD (p_result, _WRONG_STATE);
11971 return (NULL);
11972 }
11973 ctlr_b = 0;
11974 if ((plci_b_id & 0x7f) != 0)
11975 {
11976 ctlr_b = MapController ((byte)(plci_b_id & 0x7f));
11977 if ((ctlr_b > max_adapter) || ((ctlr_b != 0) && (adapter[ctlr_b - 1].request == NULL)))
11978 ctlr_b = 0;
11979 }
11980 if ((ctlr_b == 0)
11981 || (((plci_b_id >> 8) & 0xff) == 0)
11982 || (((plci_b_id >> 8) & 0xff) > adapter[ctlr_b - 1].max_plci))
11983 {
11984 dbug (1, dprintf ("[%06lx] %s,%d: LI invalid second PLCI %08lx",
11985 UnMapId (Id), (char *)(FILE_), __LINE__, plci_b_id));
11986 PUT_WORD (p_result, _WRONG_IDENTIFIER);
11987 return (NULL);
11988 }
11989 plci_b = &(adapter[ctlr_b - 1].plci[((plci_b_id >> 8) & 0xff) - 1]);
11990 if (!plci_b->State
11991 || !plci_b->NL.Id || plci_b->nl_remove_id
11992 || (plci_b->li_bchannel_id == 0)
11993 || (li_config_table[plci_b->adapter->li_base + (plci_b->li_bchannel_id - 1)].plci != plci_b))
11994 {
11995 dbug (1, dprintf ("[%06lx] %s,%d: LI peer in wrong state %08lx",
11996 UnMapId (Id), (char *)(FILE_), __LINE__, plci_b_id));
11997 PUT_WORD (p_result, _WRONG_STATE);
11998 return (NULL);
11999 }
12000 if (((byte)(plci_b_id & ~EXT_CONTROLLER)) !=
12001 ((byte)(UnMapController (plci->adapter->Id) & ~EXT_CONTROLLER))
12002 && (!(plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT)
12003 || !(plci_b->adapter->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT)))
12004 {
12005 dbug (1, dprintf ("[%06lx] %s,%d: LI not on same ctrl %08lx",
12006 UnMapId (Id), (char *)(FILE_), __LINE__, plci_b_id));
12007 PUT_WORD (p_result, _WRONG_IDENTIFIER);
12008 return (NULL);
12009 }
12010 if (!(get_b1_facilities (plci_b, add_b1_facilities (plci_b, plci_b->B1_resource,
12011 (word)(plci_b->B1_facilities | B1_FACILITY_MIXER))) & B1_FACILITY_MIXER))
12012 {
12013 dbug (1, dprintf ("[%06lx] %s,%d: Interconnect peer cannot mix %d",
12014 UnMapId (Id), (char *)(FILE_), __LINE__, plci_b->B1_resource));
12015 PUT_WORD (p_result, _WRONG_STATE);
12016 return (NULL);
12017 }
12018 return (plci_b);
12019}
12020
12021
12022static byte mixer_request (dword Id, word Number, DIVA_CAPI_ADAPTER *a, PLCI *plci, APPL *appl, API_PARSE *msg)
12023{
12024 word Info;
12025 word i;
12026 dword d, li_flags, plci_b_id;
12027 PLCI *plci_b;
12028 API_PARSE li_parms[3];
12029 API_PARSE li_req_parms[3];
12030 API_PARSE li_participant_struct[2];
12031 API_PARSE li_participant_parms[3];
12032 word participant_parms_pos;
12033 byte result_buffer[32];
12034 byte *result;
12035 word result_pos;
12036 word plci_b_write_pos;
12037
12038 dbug (1, dprintf ("[%06lx] %s,%d: mixer_request",
12039 UnMapId (Id), (char *)(FILE_), __LINE__));
12040
12041 Info = GOOD;
12042 result = result_buffer;
12043 result_buffer[0] = 0;
12044 if (!(a->profile.Global_Options & GL_LINE_INTERCONNECT_SUPPORTED))
12045 {
12046 dbug (1, dprintf ("[%06lx] %s,%d: Facility not supported",
12047 UnMapId (Id), (char *)(FILE_), __LINE__));
12048 Info = _FACILITY_NOT_SUPPORTED;
12049 }
12050 else if (api_parse (&msg[1].info[1], msg[1].length, "ws", li_parms))
12051 {
12052 dbug (1, dprintf ("[%06lx] %s,%d: Wrong message format",
12053 UnMapId (Id), (char *)(FILE_), __LINE__));
12054 Info = _WRONG_MESSAGE_FORMAT;
12055 }
12056 else
12057 {
12058 result_buffer[0] = 3;
12059 PUT_WORD (&result_buffer[1], GET_WORD (li_parms[0].info));
12060 result_buffer[3] = 0;
12061 switch (GET_WORD (li_parms[0].info))
12062 {
12063 case LI_GET_SUPPORTED_SERVICES:
12064 if (appl->appl_flags & APPL_FLAG_OLD_LI_SPEC)
12065 {
12066 result_buffer[0] = 17;
12067 result_buffer[3] = 14;
12068 PUT_WORD (&result_buffer[4], GOOD);
12069 d = 0;
12070 if (a->manufacturer_features & MANUFACTURER_FEATURE_MIXER_CH_CH)
12071 d |= LI_CONFERENCING_SUPPORTED;
12072 if (a->manufacturer_features & MANUFACTURER_FEATURE_MIXER_CH_PC)
12073 d |= LI_MONITORING_SUPPORTED;
12074 if (a->manufacturer_features & MANUFACTURER_FEATURE_MIXER_PC_CH)
12075 d |= LI_ANNOUNCEMENTS_SUPPORTED | LI_MIXING_SUPPORTED;
12076 if (a->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT)
12077 d |= LI_CROSS_CONTROLLER_SUPPORTED;
12078 PUT_DWORD (&result_buffer[6], d);
12079 if (a->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT)
12080 {
12081 d = 0;
12082 for (i = 0; i < li_total_channels; i++)
12083 {
12084 if ((li_config_table[i].adapter->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT)
12085 && (li_config_table[i].adapter->li_pri
12086 || (i < li_config_table[i].adapter->li_base + MIXER_BCHANNELS_BRI)))
12087 {
12088 d++;
12089 }
12090 }
12091 }
12092 else
12093 {
12094 d = a->li_pri ? a->li_channels : MIXER_BCHANNELS_BRI;
12095 }
12096 PUT_DWORD (&result_buffer[10], d / 2);
12097 PUT_DWORD (&result_buffer[14], d);
12098 }
12099 else
12100 {
12101 result_buffer[0] = 25;
12102 result_buffer[3] = 22;
12103 PUT_WORD (&result_buffer[4], GOOD);
12104 d = LI2_ASYMMETRIC_SUPPORTED | LI2_B_LOOPING_SUPPORTED | LI2_X_LOOPING_SUPPORTED;
12105 if (a->manufacturer_features & MANUFACTURER_FEATURE_MIXER_CH_PC)
12106 d |= LI2_MONITORING_SUPPORTED | LI2_REMOTE_MONITORING_SUPPORTED;
12107 if (a->manufacturer_features & MANUFACTURER_FEATURE_MIXER_PC_CH)
12108 d |= LI2_MIXING_SUPPORTED | LI2_REMOTE_MIXING_SUPPORTED;
12109 if (a->manufacturer_features & MANUFACTURER_FEATURE_MIXER_PC_PC)
12110 d |= LI2_PC_LOOPING_SUPPORTED;
12111 if (a->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT)
12112 d |= LI2_CROSS_CONTROLLER_SUPPORTED;
12113 PUT_DWORD (&result_buffer[6], d);
12114 d = a->li_pri ? a->li_channels : MIXER_BCHANNELS_BRI;
12115 PUT_DWORD (&result_buffer[10], d / 2);
12116 PUT_DWORD (&result_buffer[14], d - 1);
12117 if (a->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT)
12118 {
12119 d = 0;
12120 for (i = 0; i < li_total_channels; i++)
12121 {
12122 if ((li_config_table[i].adapter->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT)
12123 && (li_config_table[i].adapter->li_pri
12124 || (i < li_config_table[i].adapter->li_base + MIXER_BCHANNELS_BRI)))
12125 {
12126 d++;
12127 }
12128 }
12129 }
12130 PUT_DWORD (&result_buffer[18], d / 2);
12131 PUT_DWORD (&result_buffer[22], d - 1);
12132 }
12133 break;
12134
12135 case LI_REQ_CONNECT:
12136 if (li_parms[1].length == 8)
12137 {
12138 appl->appl_flags |= APPL_FLAG_OLD_LI_SPEC;
12139 if (api_parse (&li_parms[1].info[1], li_parms[1].length, "dd", li_req_parms))
12140 {
12141 dbug (1, dprintf ("[%06lx] %s,%d: Wrong message format",
12142 UnMapId (Id), (char *)(FILE_), __LINE__));
12143 Info = _WRONG_MESSAGE_FORMAT;
12144 break;
12145 }
12146 plci_b_id = GET_DWORD (li_req_parms[0].info) & 0xffff;
12147 li_flags = GET_DWORD (li_req_parms[1].info);
12148 Info = li_check_main_plci (Id, plci);
12149 result_buffer[0] = 9;
12150 result_buffer[3] = 6;
12151 PUT_DWORD (&result_buffer[4], plci_b_id);
12152 PUT_WORD (&result_buffer[8], GOOD);
12153 if (Info != GOOD)
12154 break;
12155 result = plci->saved_msg.info;
12156 for (i = 0; i <= result_buffer[0]; i++)
12157 result[i] = result_buffer[i];
12158 plci_b_write_pos = plci->li_plci_b_write_pos;
12159 plci_b = li_check_plci_b (Id, plci, plci_b_id, plci_b_write_pos, &result[8]);
12160 if (plci_b == NULL)
12161 break;
12162 li_update_connect (Id, a, plci, plci_b_id, TRUE, li_flags);
12163 plci->li_plci_b_queue[plci_b_write_pos] = plci_b_id | LI_PLCI_B_LAST_FLAG;
12164 plci_b_write_pos = (plci_b_write_pos == LI_PLCI_B_QUEUE_ENTRIES-1) ? 0 : plci_b_write_pos + 1;
12165 plci->li_plci_b_write_pos = plci_b_write_pos;
12166 }
12167 else
12168 {
12169 appl->appl_flags &= ~APPL_FLAG_OLD_LI_SPEC;
12170 if (api_parse (&li_parms[1].info[1], li_parms[1].length, "ds", li_req_parms))
12171 {
12172 dbug (1, dprintf ("[%06lx] %s,%d: Wrong message format",
12173 UnMapId (Id), (char *)(FILE_), __LINE__));
12174 Info = _WRONG_MESSAGE_FORMAT;
12175 break;
12176 }
12177 li_flags = GET_DWORD (li_req_parms[0].info) & ~(LI2_FLAG_INTERCONNECT_A_B | LI2_FLAG_INTERCONNECT_B_A);
12178 Info = li_check_main_plci (Id, plci);
12179 result_buffer[0] = 7;
12180 result_buffer[3] = 4;
12181 PUT_WORD (&result_buffer[4], Info);
12182 result_buffer[6] = 0;
12183 if (Info != GOOD)
12184 break;
12185 result = plci->saved_msg.info;
12186 for (i = 0; i <= result_buffer[0]; i++)
12187 result[i] = result_buffer[i];
12188 plci_b_write_pos = plci->li_plci_b_write_pos;
12189 participant_parms_pos = 0;
12190 result_pos = 7;
12191 li2_update_connect (Id, a, plci, UnMapId (Id), TRUE, li_flags);
12192 while (participant_parms_pos < li_req_parms[1].length)
12193 {
12194 result[result_pos] = 6;
12195 result_pos += 7;
12196 PUT_DWORD (&result[result_pos - 6], 0);
12197 PUT_WORD (&result[result_pos - 2], GOOD);
12198 if (api_parse (&li_req_parms[1].info[1 + participant_parms_pos],
12199 (word)(li_parms[1].length - participant_parms_pos), "s", li_participant_struct))
12200 {
12201 dbug (1, dprintf ("[%06lx] %s,%d: Wrong message format",
12202 UnMapId (Id), (char *)(FILE_), __LINE__));
12203 PUT_WORD (&result[result_pos - 2], _WRONG_MESSAGE_FORMAT);
12204 break;
12205 }
12206 if (api_parse (&li_participant_struct[0].info[1],
12207 li_participant_struct[0].length, "dd", li_participant_parms))
12208 {
12209 dbug (1, dprintf ("[%06lx] %s,%d: Wrong message format",
12210 UnMapId (Id), (char *)(FILE_), __LINE__));
12211 PUT_WORD (&result[result_pos - 2], _WRONG_MESSAGE_FORMAT);
12212 break;
12213 }
12214 plci_b_id = GET_DWORD (li_participant_parms[0].info) & 0xffff;
12215 li_flags = GET_DWORD (li_participant_parms[1].info);
12216 PUT_DWORD (&result[result_pos - 6], plci_b_id);
12217 if (sizeof(result) - result_pos < 7)
12218 {
12219 dbug (1, dprintf ("[%06lx] %s,%d: LI result overrun",
12220 UnMapId (Id), (char *)(FILE_), __LINE__));
12221 PUT_WORD (&result[result_pos - 2], _WRONG_STATE);
12222 break;
12223 }
12224 plci_b = li2_check_plci_b (Id, plci, plci_b_id, plci_b_write_pos, &result[result_pos - 2]);
12225 if (plci_b != NULL)
12226 {
12227 li2_update_connect (Id, a, plci, plci_b_id, TRUE, li_flags);
12228 plci->li_plci_b_queue[plci_b_write_pos] = plci_b_id |
12229 ((li_flags & (LI2_FLAG_INTERCONNECT_A_B | LI2_FLAG_INTERCONNECT_B_A |
12230 LI2_FLAG_PCCONNECT_A_B | LI2_FLAG_PCCONNECT_B_A)) ? 0 : LI_PLCI_B_DISC_FLAG);
12231 plci_b_write_pos = (plci_b_write_pos == LI_PLCI_B_QUEUE_ENTRIES-1) ? 0 : plci_b_write_pos + 1;
12232 }
12233 participant_parms_pos = (word)((&li_participant_struct[0].info[1 + li_participant_struct[0].length]) -
12234 (&li_req_parms[1].info[1]));
12235 }
12236 result[0] = (byte)(result_pos - 1);
12237 result[3] = (byte)(result_pos - 4);
12238 result[6] = (byte)(result_pos - 7);
12239 i = (plci_b_write_pos == 0) ? LI_PLCI_B_QUEUE_ENTRIES-1 : plci_b_write_pos - 1;
12240 if ((plci_b_write_pos == plci->li_plci_b_read_pos)
12241 || (plci->li_plci_b_queue[i] & LI_PLCI_B_LAST_FLAG))
12242 {
12243 plci->li_plci_b_queue[plci_b_write_pos] = LI_PLCI_B_SKIP_FLAG | LI_PLCI_B_LAST_FLAG;
12244 plci_b_write_pos = (plci_b_write_pos == LI_PLCI_B_QUEUE_ENTRIES-1) ? 0 : plci_b_write_pos + 1;
12245 }
12246 else
12247 plci->li_plci_b_queue[i] |= LI_PLCI_B_LAST_FLAG;
12248 plci->li_plci_b_write_pos = plci_b_write_pos;
12249 }
12250 mixer_calculate_coefs (a);
12251 plci->li_channel_bits = li_config_table[a->li_base + (plci->li_bchannel_id - 1)].channel;
12252 mixer_notify_update (plci, TRUE);
12253 sendf (appl, _FACILITY_R | CONFIRM, Id & 0xffffL, Number,
12254 "wwS", Info, SELECTOR_LINE_INTERCONNECT, result);
12255 plci->command = 0;
12256 plci->li_cmd = GET_WORD (li_parms[0].info);
12257 start_internal_command (Id, plci, mixer_command);
12258 return (FALSE);
12259
12260 case LI_REQ_DISCONNECT:
12261 if (li_parms[1].length == 4)
12262 {
12263 appl->appl_flags |= APPL_FLAG_OLD_LI_SPEC;
12264 if (api_parse (&li_parms[1].info[1], li_parms[1].length, "d", li_req_parms))
12265 {
12266 dbug (1, dprintf ("[%06lx] %s,%d: Wrong message format",
12267 UnMapId (Id), (char *)(FILE_), __LINE__));
12268 Info = _WRONG_MESSAGE_FORMAT;
12269 break;
12270 }
12271 plci_b_id = GET_DWORD (li_req_parms[0].info) & 0xffff;
12272 Info = li_check_main_plci (Id, plci);
12273 result_buffer[0] = 9;
12274 result_buffer[3] = 6;
12275 PUT_DWORD (&result_buffer[4], GET_DWORD (li_req_parms[0].info));
12276 PUT_WORD (&result_buffer[8], GOOD);
12277 if (Info != GOOD)
12278 break;
12279 result = plci->saved_msg.info;
12280 for (i = 0; i <= result_buffer[0]; i++)
12281 result[i] = result_buffer[i];
12282 plci_b_write_pos = plci->li_plci_b_write_pos;
12283 plci_b = li_check_plci_b (Id, plci, plci_b_id, plci_b_write_pos, &result[8]);
12284 if (plci_b == NULL)
12285 break;
12286 li_update_connect (Id, a, plci, plci_b_id, FALSE, 0);
12287 plci->li_plci_b_queue[plci_b_write_pos] = plci_b_id | LI_PLCI_B_DISC_FLAG | LI_PLCI_B_LAST_FLAG;
12288 plci_b_write_pos = (plci_b_write_pos == LI_PLCI_B_QUEUE_ENTRIES-1) ? 0 : plci_b_write_pos + 1;
12289 plci->li_plci_b_write_pos = plci_b_write_pos;
12290 }
12291 else
12292 {
12293 appl->appl_flags &= ~APPL_FLAG_OLD_LI_SPEC;
12294 if (api_parse (&li_parms[1].info[1], li_parms[1].length, "s", li_req_parms))
12295 {
12296 dbug (1, dprintf ("[%06lx] %s,%d: Wrong message format",
12297 UnMapId (Id), (char *)(FILE_), __LINE__));
12298 Info = _WRONG_MESSAGE_FORMAT;
12299 break;
12300 }
12301 Info = li_check_main_plci (Id, plci);
12302 result_buffer[0] = 7;
12303 result_buffer[3] = 4;
12304 PUT_WORD (&result_buffer[4], Info);
12305 result_buffer[6] = 0;
12306 if (Info != GOOD)
12307 break;
12308 result = plci->saved_msg.info;
12309 for (i = 0; i <= result_buffer[0]; i++)
12310 result[i] = result_buffer[i];
12311 plci_b_write_pos = plci->li_plci_b_write_pos;
12312 participant_parms_pos = 0;
12313 result_pos = 7;
12314 while (participant_parms_pos < li_req_parms[0].length)
12315 {
12316 result[result_pos] = 6;
12317 result_pos += 7;
12318 PUT_DWORD (&result[result_pos - 6], 0);
12319 PUT_WORD (&result[result_pos - 2], GOOD);
12320 if (api_parse (&li_req_parms[0].info[1 + participant_parms_pos],
12321 (word)(li_parms[1].length - participant_parms_pos), "s", li_participant_struct))
12322 {
12323 dbug (1, dprintf ("[%06lx] %s,%d: Wrong message format",
12324 UnMapId (Id), (char *)(FILE_), __LINE__));
12325 PUT_WORD (&result[result_pos - 2], _WRONG_MESSAGE_FORMAT);
12326 break;
12327 }
12328 if (api_parse (&li_participant_struct[0].info[1],
12329 li_participant_struct[0].length, "d", li_participant_parms))
12330 {
12331 dbug (1, dprintf ("[%06lx] %s,%d: Wrong message format",
12332 UnMapId (Id), (char *)(FILE_), __LINE__));
12333 PUT_WORD (&result[result_pos - 2], _WRONG_MESSAGE_FORMAT);
12334 break;
12335 }
12336 plci_b_id = GET_DWORD (li_participant_parms[0].info) & 0xffff;
12337 PUT_DWORD (&result[result_pos - 6], plci_b_id);
12338 if (sizeof(result) - result_pos < 7)
12339 {
12340 dbug (1, dprintf ("[%06lx] %s,%d: LI result overrun",
12341 UnMapId (Id), (char *)(FILE_), __LINE__));
12342 PUT_WORD (&result[result_pos - 2], _WRONG_STATE);
12343 break;
12344 }
12345 plci_b = li2_check_plci_b (Id, plci, plci_b_id, plci_b_write_pos, &result[result_pos - 2]);
12346 if (plci_b != NULL)
12347 {
12348 li2_update_connect (Id, a, plci, plci_b_id, FALSE, 0);
12349 plci->li_plci_b_queue[plci_b_write_pos] = plci_b_id | LI_PLCI_B_DISC_FLAG;
12350 plci_b_write_pos = (plci_b_write_pos == LI_PLCI_B_QUEUE_ENTRIES-1) ? 0 : plci_b_write_pos + 1;
12351 }
12352 participant_parms_pos = (word)((&li_participant_struct[0].info[1 + li_participant_struct[0].length]) -
12353 (&li_req_parms[0].info[1]));
12354 }
12355 result[0] = (byte)(result_pos - 1);
12356 result[3] = (byte)(result_pos - 4);
12357 result[6] = (byte)(result_pos - 7);
12358 i = (plci_b_write_pos == 0) ? LI_PLCI_B_QUEUE_ENTRIES-1 : plci_b_write_pos - 1;
12359 if ((plci_b_write_pos == plci->li_plci_b_read_pos)
12360 || (plci->li_plci_b_queue[i] & LI_PLCI_B_LAST_FLAG))
12361 {
12362 plci->li_plci_b_queue[plci_b_write_pos] = LI_PLCI_B_SKIP_FLAG | LI_PLCI_B_LAST_FLAG;
12363 plci_b_write_pos = (plci_b_write_pos == LI_PLCI_B_QUEUE_ENTRIES-1) ? 0 : plci_b_write_pos + 1;
12364 }
12365 else
12366 plci->li_plci_b_queue[i] |= LI_PLCI_B_LAST_FLAG;
12367 plci->li_plci_b_write_pos = plci_b_write_pos;
12368 }
12369 mixer_calculate_coefs (a);
12370 plci->li_channel_bits = li_config_table[a->li_base + (plci->li_bchannel_id - 1)].channel;
12371 mixer_notify_update (plci, TRUE);
12372 sendf (appl, _FACILITY_R | CONFIRM, Id & 0xffffL, Number,
12373 "wwS", Info, SELECTOR_LINE_INTERCONNECT, result);
12374 plci->command = 0;
12375 plci->li_cmd = GET_WORD (li_parms[0].info);
12376 start_internal_command (Id, plci, mixer_command);
12377 return (FALSE);
12378
12379 case LI_REQ_SILENT_UPDATE:
12380 if (!plci || !plci->State
12381 || !plci->NL.Id || plci->nl_remove_id
12382 || (plci->li_bchannel_id == 0)
12383 || (li_config_table[plci->adapter->li_base + (plci->li_bchannel_id - 1)].plci != plci))
12384 {
12385 dbug (1, dprintf ("[%06lx] %s,%d: Wrong state",
12386 UnMapId (Id), (char *)(FILE_), __LINE__));
12387 return (FALSE);
12388 }
12389 plci_b_write_pos = plci->li_plci_b_write_pos;
12390 if (((plci->li_plci_b_read_pos > plci_b_write_pos) ? plci->li_plci_b_read_pos :
12391 LI_PLCI_B_QUEUE_ENTRIES + plci->li_plci_b_read_pos) - plci_b_write_pos - 1 < 2)
12392 {
12393 dbug (1, dprintf ("[%06lx] %s,%d: LI request overrun",
12394 UnMapId (Id), (char *)(FILE_), __LINE__));
12395 return (FALSE);
12396 }
12397 i = (plci_b_write_pos == 0) ? LI_PLCI_B_QUEUE_ENTRIES-1 : plci_b_write_pos - 1;
12398 if ((plci_b_write_pos == plci->li_plci_b_read_pos)
12399 || (plci->li_plci_b_queue[i] & LI_PLCI_B_LAST_FLAG))
12400 {
12401 plci->li_plci_b_queue[plci_b_write_pos] = LI_PLCI_B_SKIP_FLAG | LI_PLCI_B_LAST_FLAG;
12402 plci_b_write_pos = (plci_b_write_pos == LI_PLCI_B_QUEUE_ENTRIES-1) ? 0 : plci_b_write_pos + 1;
12403 }
12404 else
12405 plci->li_plci_b_queue[i] |= LI_PLCI_B_LAST_FLAG;
12406 plci->li_plci_b_write_pos = plci_b_write_pos;
12407 plci->li_channel_bits = li_config_table[a->li_base + (plci->li_bchannel_id - 1)].channel;
12408 plci->command = 0;
12409 plci->li_cmd = GET_WORD (li_parms[0].info);
12410 start_internal_command (Id, plci, mixer_command);
12411 return (FALSE);
12412
12413 default:
12414 dbug (1, dprintf ("[%06lx] %s,%d: LI unknown request %04x",
12415 UnMapId (Id), (char *)(FILE_), __LINE__, GET_WORD (li_parms[0].info)));
12416 Info = _FACILITY_NOT_SUPPORTED;
12417 }
12418 }
12419 sendf (appl, _FACILITY_R | CONFIRM, Id & 0xffffL, Number,
12420 "wwS", Info, SELECTOR_LINE_INTERCONNECT, result);
12421 return (FALSE);
12422}
12423
12424
12425static void mixer_indication_coefs_set (dword Id, PLCI *plci)
12426{
12427 dword d;
12428 DIVA_CAPI_ADAPTER *a;
12429 byte result[12];
12430
12431 dbug (1, dprintf ("[%06lx] %s,%d: mixer_indication_coefs_set",
12432 UnMapId (Id), (char *)(FILE_), __LINE__));
12433
12434 a = plci->adapter;
12435 if (plci->li_plci_b_read_pos != plci->li_plci_b_req_pos)
12436 {
12437 do
12438 {
12439 d = plci->li_plci_b_queue[plci->li_plci_b_read_pos];
12440 if (!(d & LI_PLCI_B_SKIP_FLAG))
12441 {
12442 if (plci->appl->appl_flags & APPL_FLAG_OLD_LI_SPEC)
12443 {
12444 if (d & LI_PLCI_B_DISC_FLAG)
12445 {
12446 result[0] = 5;
12447 PUT_WORD (&result[1], LI_IND_DISCONNECT);
12448 result[3] = 2;
12449 PUT_WORD (&result[4], _LI_USER_INITIATED);
12450 }
12451 else
12452 {
12453 result[0] = 7;
12454 PUT_WORD (&result[1], LI_IND_CONNECT_ACTIVE);
12455 result[3] = 4;
12456 PUT_DWORD (&result[4], d & ~LI_PLCI_B_FLAG_MASK);
12457 }
12458 }
12459 else
12460 {
12461 if (d & LI_PLCI_B_DISC_FLAG)
12462 {
12463 result[0] = 9;
12464 PUT_WORD (&result[1], LI_IND_DISCONNECT);
12465 result[3] = 6;
12466 PUT_DWORD (&result[4], d & ~LI_PLCI_B_FLAG_MASK);
12467 PUT_WORD (&result[8], _LI_USER_INITIATED);
12468 }
12469 else
12470 {
12471 result[0] = 7;
12472 PUT_WORD (&result[1], LI_IND_CONNECT_ACTIVE);
12473 result[3] = 4;
12474 PUT_DWORD (&result[4], d & ~LI_PLCI_B_FLAG_MASK);
12475 }
12476 }
12477 sendf (plci->appl, _FACILITY_I, Id & 0xffffL, 0,
12478 "ws", SELECTOR_LINE_INTERCONNECT, result);
12479 }
12480 plci->li_plci_b_read_pos = (plci->li_plci_b_read_pos == LI_PLCI_B_QUEUE_ENTRIES-1) ?
12481 0 : plci->li_plci_b_read_pos + 1;
12482 } while (!(d & LI_PLCI_B_LAST_FLAG) && (plci->li_plci_b_read_pos != plci->li_plci_b_req_pos));
12483 }
12484}
12485
12486
12487static void mixer_indication_xconnect_from (dword Id, PLCI *plci, byte *msg, word length)
12488{
12489 word i, j, ch;
12490 struct xconnect_transfer_address_s s, *p;
12491 DIVA_CAPI_ADAPTER *a;
12492
12493 dbug (1, dprintf ("[%06lx] %s,%d: mixer_indication_xconnect_from %d",
12494 UnMapId (Id), (char *)(FILE_), __LINE__, (int) length));
12495
12496 a = plci->adapter;
12497 i = 1;
12498 for (i = 1; i < length; i += 16)
12499 {
12500 s.card_address.low = msg[i] | (msg[i+1] << 8) | (((dword)(msg[i+2])) << 16) | (((dword)(msg[i+3])) << 24);
12501 s.card_address.high = msg[i+4] | (msg[i+5] << 8) | (((dword)(msg[i+6])) << 16) | (((dword)(msg[i+7])) << 24);
12502 s.offset = msg[i+8] | (msg[i+9] << 8) | (((dword)(msg[i+10])) << 16) | (((dword)(msg[i+11])) << 24);
12503 ch = msg[i+12] | (msg[i+13] << 8);
12504 j = ch & XCONNECT_CHANNEL_NUMBER_MASK;
12505 if (!a->li_pri && (plci->li_bchannel_id == 2))
12506 j = 1 - j;
12507 j += a->li_base;
12508 if (ch & XCONNECT_CHANNEL_PORT_PC)
12509 p = &(li_config_table[j].send_pc);
12510 else
12511 p = &(li_config_table[j].send_b);
12512 p->card_address.low = s.card_address.low;
12513 p->card_address.high = s.card_address.high;
12514 p->offset = s.offset;
12515 li_config_table[j].channel |= LI_CHANNEL_ADDRESSES_SET;
12516 }
12517 if (plci->internal_command_queue[0]
12518 && ((plci->adjust_b_state == ADJUST_B_RESTORE_MIXER_2)
12519 || (plci->adjust_b_state == ADJUST_B_RESTORE_MIXER_3)
12520 || (plci->adjust_b_state == ADJUST_B_RESTORE_MIXER_4)))
12521 {
12522 (*(plci->internal_command_queue[0]))(Id, plci, 0);
12523 if (!plci->internal_command)
12524 next_internal_command (Id, plci);
12525 }
12526 mixer_notify_update (plci, TRUE);
12527}
12528
12529
12530static void mixer_indication_xconnect_to (dword Id, PLCI *plci, byte *msg, word length)
12531{
12532
12533 dbug (1, dprintf ("[%06lx] %s,%d: mixer_indication_xconnect_to %d",
12534 UnMapId (Id), (char *)(FILE_), __LINE__, (int) length));
12535
12536}
12537
12538
12539static byte mixer_notify_source_removed (PLCI *plci, dword plci_b_id)
12540{
12541 word plci_b_write_pos;
12542
12543 plci_b_write_pos = plci->li_plci_b_write_pos;
12544 if (((plci->li_plci_b_read_pos > plci_b_write_pos) ? plci->li_plci_b_read_pos :
12545 LI_PLCI_B_QUEUE_ENTRIES + plci->li_plci_b_read_pos) - plci_b_write_pos - 1 < 1)
12546 {
12547 dbug (1, dprintf ("[%06lx] %s,%d: LI request overrun",
12548 (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
12549 (char *)(FILE_), __LINE__));
12550 return (FALSE);
12551 }
12552 plci->li_plci_b_queue[plci_b_write_pos] = plci_b_id | LI_PLCI_B_DISC_FLAG;
12553 plci_b_write_pos = (plci_b_write_pos == LI_PLCI_B_QUEUE_ENTRIES-1) ? 0 : plci_b_write_pos + 1;
12554 plci->li_plci_b_write_pos = plci_b_write_pos;
12555 return (TRUE);
12556}
12557
12558
12559static void mixer_remove (PLCI *plci)
12560{
12561 DIVA_CAPI_ADAPTER *a;
12562 PLCI *notify_plci;
12563 dword plci_b_id;
12564 word i, j;
12565
12566 dbug (1, dprintf ("[%06lx] %s,%d: mixer_remove",
12567 (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
12568 (char *)(FILE_), __LINE__));
12569
12570 a = plci->adapter;
12571 plci_b_id = (plci->Id << 8) | UnMapController (plci->adapter->Id);
12572 if (a->profile.Global_Options & GL_LINE_INTERCONNECT_SUPPORTED)
12573 {
12574 if ((plci->li_bchannel_id != 0)
12575 && (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == plci))
12576 {
12577 i = a->li_base + (plci->li_bchannel_id - 1);
12578 if ((li_config_table[i].curchnl | li_config_table[i].channel) & LI_CHANNEL_INVOLVED)
12579 {
12580 for (j = 0; j < li_total_channels; j++)
12581 {
12582 if ((li_config_table[i].flag_table[j] & LI_FLAG_INTERCONNECT)
12583 || (li_config_table[j].flag_table[i] & LI_FLAG_INTERCONNECT))
12584 {
12585 notify_plci = li_config_table[j].plci;
12586 if ((notify_plci != NULL)
12587 && (notify_plci != plci)
12588 && (notify_plci->appl != NULL)
12589 && !(notify_plci->appl->appl_flags & APPL_FLAG_OLD_LI_SPEC)
12590 && (notify_plci->State)
12591 && notify_plci->NL.Id && !notify_plci->nl_remove_id)
12592 {
12593 mixer_notify_source_removed (notify_plci, plci_b_id);
12594 }
12595 }
12596 }
12597 mixer_clear_config (plci);
12598 mixer_calculate_coefs (a);
12599 mixer_notify_update (plci, TRUE);
12600 }
12601 li_config_table[i].plci = NULL;
12602 plci->li_bchannel_id = 0;
12603 }
12604 }
12605}
12606
12607
12608/*------------------------------------------------------------------*/
12609/* Echo canceller facilities */
12610/*------------------------------------------------------------------*/
12611
12612
12613static void ec_write_parameters (PLCI *plci)
12614{
12615 word w;
12616 byte parameter_buffer[6];
12617
12618 dbug (1, dprintf ("[%06lx] %s,%d: ec_write_parameters",
12619 (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
12620 (char *)(FILE_), __LINE__));
12621
12622 parameter_buffer[0] = 5;
12623 parameter_buffer[1] = DSP_CTRL_SET_LEC_PARAMETERS;
12624 PUT_WORD (&parameter_buffer[2], plci->ec_idi_options);
12625 plci->ec_idi_options &= ~LEC_RESET_COEFFICIENTS;
12626 w = (plci->ec_tail_length == 0) ? 128 : plci->ec_tail_length;
12627 PUT_WORD (&parameter_buffer[4], w);
12628 add_p (plci, FTY, parameter_buffer);
12629 sig_req (plci, TEL_CTRL, 0);
12630 send_req (plci);
12631}
12632
12633
12634static void ec_clear_config (PLCI *plci)
12635{
12636
12637 dbug (1, dprintf ("[%06lx] %s,%d: ec_clear_config",
12638 (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
12639 (char *)(FILE_), __LINE__));
12640
12641 plci->ec_idi_options = LEC_ENABLE_ECHO_CANCELLER |
12642 LEC_MANUAL_DISABLE | LEC_ENABLE_NONLINEAR_PROCESSING;
12643 plci->ec_tail_length = 0;
12644}
12645
12646
12647static void ec_prepare_switch (dword Id, PLCI *plci)
12648{
12649
12650 dbug (1, dprintf ("[%06lx] %s,%d: ec_prepare_switch",
12651 UnMapId (Id), (char *)(FILE_), __LINE__));
12652
12653}
12654
12655
12656static word ec_save_config (dword Id, PLCI *plci, byte Rc)
12657{
12658
12659 dbug (1, dprintf ("[%06lx] %s,%d: ec_save_config %02x %d",
12660 UnMapId (Id), (char *)(FILE_), __LINE__, Rc, plci->adjust_b_state));
12661
12662 return (GOOD);
12663}
12664
12665
12666static word ec_restore_config (dword Id, PLCI *plci, byte Rc)
12667{
12668 word Info;
12669
12670 dbug (1, dprintf ("[%06lx] %s,%d: ec_restore_config %02x %d",
12671 UnMapId (Id), (char *)(FILE_), __LINE__, Rc, plci->adjust_b_state));
12672
12673 Info = GOOD;
12674 if (plci->B1_facilities & B1_FACILITY_EC)
12675 {
12676 switch (plci->adjust_b_state)
12677 {
12678 case ADJUST_B_RESTORE_EC_1:
12679 plci->internal_command = plci->adjust_b_command;
12680 if (plci->sig_req)
12681 {
12682 plci->adjust_b_state = ADJUST_B_RESTORE_EC_1;
12683 break;
12684 }
12685 ec_write_parameters (plci);
12686 plci->adjust_b_state = ADJUST_B_RESTORE_EC_2;
12687 break;
12688 case ADJUST_B_RESTORE_EC_2:
12689 if ((Rc != OK) && (Rc != OK_FC))
12690 {
12691 dbug (1, dprintf ("[%06lx] %s,%d: Restore EC failed %02x",
12692 UnMapId (Id), (char *)(FILE_), __LINE__, Rc));
12693 Info = _WRONG_STATE;
12694 break;
12695 }
12696 break;
12697 }
12698 }
12699 return (Info);
12700}
12701
12702
12703static void ec_command (dword Id, PLCI *plci, byte Rc)
12704{
12705 word internal_command, Info;
12706 byte result[8];
12707
12708 dbug (1, dprintf ("[%06lx] %s,%d: ec_command %02x %04x %04x %04x %d",
12709 UnMapId (Id), (char *)(FILE_), __LINE__, Rc, plci->internal_command,
12710 plci->ec_cmd, plci->ec_idi_options, plci->ec_tail_length));
12711
12712 Info = GOOD;
12713 if (plci->appl->appl_flags & APPL_FLAG_PRIV_EC_SPEC)
12714 {
12715 result[0] = 2;
12716 PUT_WORD (&result[1], EC_SUCCESS);
12717 }
12718 else
12719 {
12720 result[0] = 5;
12721 PUT_WORD (&result[1], plci->ec_cmd);
12722 result[3] = 2;
12723 PUT_WORD (&result[4], GOOD);
12724 }
12725 internal_command = plci->internal_command;
12726 plci->internal_command = 0;
12727 switch (plci->ec_cmd)
12728 {
12729 case EC_ENABLE_OPERATION:
12730 case EC_FREEZE_COEFFICIENTS:
12731 case EC_RESUME_COEFFICIENT_UPDATE:
12732 case EC_RESET_COEFFICIENTS:
12733 switch (internal_command)
12734 {
12735 default:
12736 adjust_b1_resource (Id, plci, NULL, (word)(plci->B1_facilities |
12737 B1_FACILITY_EC), EC_COMMAND_1);
12738 case EC_COMMAND_1:
12739 if (adjust_b_process (Id, plci, Rc) != GOOD)
12740 {
12741 dbug (1, dprintf ("[%06lx] %s,%d: Load EC failed",
12742 UnMapId (Id), (char *)(FILE_), __LINE__));
12743 Info = _FACILITY_NOT_SUPPORTED;
12744 break;
12745 }
12746 if (plci->internal_command)
12747 return;
12748 case EC_COMMAND_2:
12749 if (plci->sig_req)
12750 {
12751 plci->internal_command = EC_COMMAND_2;
12752 return;
12753 }
12754 plci->internal_command = EC_COMMAND_3;
12755 ec_write_parameters (plci);
12756 return;
12757 case EC_COMMAND_3:
12758 if ((Rc != OK) && (Rc != OK_FC))
12759 {
12760 dbug (1, dprintf ("[%06lx] %s,%d: Enable EC failed %02x",
12761 UnMapId (Id), (char *)(FILE_), __LINE__, Rc));
12762 Info = _FACILITY_NOT_SUPPORTED;
12763 break;
12764 }
12765 break;
12766 }
12767 break;
12768
12769 case EC_DISABLE_OPERATION:
12770 switch (internal_command)
12771 {
12772 default:
12773 case EC_COMMAND_1:
12774 if (plci->B1_facilities & B1_FACILITY_EC)
12775 {
12776 if (plci->sig_req)
12777 {
12778 plci->internal_command = EC_COMMAND_1;
12779 return;
12780 }
12781 plci->internal_command = EC_COMMAND_2;
12782 ec_write_parameters (plci);
12783 return;
12784 }
12785 Rc = OK;
12786 case EC_COMMAND_2:
12787 if ((Rc != OK) && (Rc != OK_FC))
12788 {
12789 dbug (1, dprintf ("[%06lx] %s,%d: Disable EC failed %02x",
12790 UnMapId (Id), (char *)(FILE_), __LINE__, Rc));
12791 Info = _FACILITY_NOT_SUPPORTED;
12792 break;
12793 }
12794 adjust_b1_resource (Id, plci, NULL, (word)(plci->B1_facilities &
12795 ~B1_FACILITY_EC), EC_COMMAND_3);
12796 case EC_COMMAND_3:
12797 if (adjust_b_process (Id, plci, Rc) != GOOD)
12798 {
12799 dbug (1, dprintf ("[%06lx] %s,%d: Unload EC failed",
12800 UnMapId (Id), (char *)(FILE_), __LINE__));
12801 Info = _FACILITY_NOT_SUPPORTED;
12802 break;
12803 }
12804 if (plci->internal_command)
12805 return;
12806 break;
12807 }
12808 break;
12809 }
12810 sendf (plci->appl, _FACILITY_R | CONFIRM, Id & 0xffffL, plci->number,
12811 "wws", Info, (plci->appl->appl_flags & APPL_FLAG_PRIV_EC_SPEC) ?
12812 PRIV_SELECTOR_ECHO_CANCELLER : SELECTOR_ECHO_CANCELLER, result);
12813}
12814
12815
12816static byte ec_request (dword Id, word Number, DIVA_CAPI_ADAPTER *a, PLCI *plci, APPL *appl, API_PARSE *msg)
12817{
12818 word Info;
12819 word opt;
12820 API_PARSE ec_parms[3];
12821 byte result[16];
12822
12823 dbug (1, dprintf ("[%06lx] %s,%d: ec_request",
12824 UnMapId (Id), (char *)(FILE_), __LINE__));
12825
12826 Info = GOOD;
12827 result[0] = 0;
12828 if (!(a->man_profile.private_options & (1L << PRIVATE_ECHO_CANCELLER)))
12829 {
12830 dbug (1, dprintf ("[%06lx] %s,%d: Facility not supported",
12831 UnMapId (Id), (char *)(FILE_), __LINE__));
12832 Info = _FACILITY_NOT_SUPPORTED;
12833 }
12834 else
12835 {
12836 if (appl->appl_flags & APPL_FLAG_PRIV_EC_SPEC)
12837 {
12838 if (api_parse (&msg[1].info[1], msg[1].length, "w", ec_parms))
12839 {
12840 dbug (1, dprintf ("[%06lx] %s,%d: Wrong message format",
12841 UnMapId (Id), (char *)(FILE_), __LINE__));
12842 Info = _WRONG_MESSAGE_FORMAT;
12843 }
12844 else
12845 {
12846 if (plci == NULL)
12847 {
12848 dbug (1, dprintf ("[%06lx] %s,%d: Wrong PLCI",
12849 UnMapId (Id), (char *)(FILE_), __LINE__));
12850 Info = _WRONG_IDENTIFIER;
12851 }
12852 else if (!plci->State || !plci->NL.Id || plci->nl_remove_id)
12853 {
12854 dbug (1, dprintf ("[%06lx] %s,%d: Wrong state",
12855 UnMapId (Id), (char *)(FILE_), __LINE__));
12856 Info = _WRONG_STATE;
12857 }
12858 else
12859 {
12860 plci->command = 0;
12861 plci->ec_cmd = GET_WORD (ec_parms[0].info);
12862 plci->ec_idi_options &= ~(LEC_MANUAL_DISABLE | LEC_RESET_COEFFICIENTS);
12863 result[0] = 2;
12864 PUT_WORD (&result[1], EC_SUCCESS);
12865 if (msg[1].length >= 4)
12866 {
12867 opt = GET_WORD (&ec_parms[0].info[2]);
12868 plci->ec_idi_options &= ~(LEC_ENABLE_NONLINEAR_PROCESSING |
12869 LEC_ENABLE_2100HZ_DETECTOR | LEC_REQUIRE_2100HZ_REVERSALS);
12870 if (!(opt & EC_DISABLE_NON_LINEAR_PROCESSING))
12871 plci->ec_idi_options |= LEC_ENABLE_NONLINEAR_PROCESSING;
12872 if (opt & EC_DETECT_DISABLE_TONE)
12873 plci->ec_idi_options |= LEC_ENABLE_2100HZ_DETECTOR;
12874 if (!(opt & EC_DO_NOT_REQUIRE_REVERSALS))
12875 plci->ec_idi_options |= LEC_REQUIRE_2100HZ_REVERSALS;
12876 if (msg[1].length >= 6)
12877 {
12878 plci->ec_tail_length = GET_WORD (&ec_parms[0].info[4]);
12879 }
12880 }
12881 switch (plci->ec_cmd)
12882 {
12883 case EC_ENABLE_OPERATION:
12884 plci->ec_idi_options &= ~LEC_FREEZE_COEFFICIENTS;
12885 start_internal_command (Id, plci, ec_command);
12886 return (FALSE);
12887
12888 case EC_DISABLE_OPERATION:
12889 plci->ec_idi_options = LEC_ENABLE_ECHO_CANCELLER |
12890 LEC_MANUAL_DISABLE | LEC_ENABLE_NONLINEAR_PROCESSING |
12891 LEC_RESET_COEFFICIENTS;
12892 start_internal_command (Id, plci, ec_command);
12893 return (FALSE);
12894
12895 case EC_FREEZE_COEFFICIENTS:
12896 plci->ec_idi_options |= LEC_FREEZE_COEFFICIENTS;
12897 start_internal_command (Id, plci, ec_command);
12898 return (FALSE);
12899
12900 case EC_RESUME_COEFFICIENT_UPDATE:
12901 plci->ec_idi_options &= ~LEC_FREEZE_COEFFICIENTS;
12902 start_internal_command (Id, plci, ec_command);
12903 return (FALSE);
12904
12905 case EC_RESET_COEFFICIENTS:
12906 plci->ec_idi_options |= LEC_RESET_COEFFICIENTS;
12907 start_internal_command (Id, plci, ec_command);
12908 return (FALSE);
12909
12910 default:
12911 dbug (1, dprintf ("[%06lx] %s,%d: EC unknown request %04x",
12912 UnMapId (Id), (char *)(FILE_), __LINE__, plci->ec_cmd));
12913 PUT_WORD (&result[1], EC_UNSUPPORTED_OPERATION);
12914 }
12915 }
12916 }
12917 }
12918 else
12919 {
12920 if (api_parse (&msg[1].info[1], msg[1].length, "ws", ec_parms))
12921 {
12922 dbug (1, dprintf ("[%06lx] %s,%d: Wrong message format",
12923 UnMapId (Id), (char *)(FILE_), __LINE__));
12924 Info = _WRONG_MESSAGE_FORMAT;
12925 }
12926 else
12927 {
12928 if (GET_WORD (ec_parms[0].info) == EC_GET_SUPPORTED_SERVICES)
12929 {
12930 result[0] = 11;
12931 PUT_WORD (&result[1], EC_GET_SUPPORTED_SERVICES);
12932 result[3] = 8;
12933 PUT_WORD (&result[4], GOOD);
12934 PUT_WORD (&result[6], 0x0007);
12935 PUT_WORD (&result[8], LEC_MAX_SUPPORTED_TAIL_LENGTH);
12936 PUT_WORD (&result[10], 0);
12937 }
12938 else if (plci == NULL)
12939 {
12940 dbug (1, dprintf ("[%06lx] %s,%d: Wrong PLCI",
12941 UnMapId (Id), (char *)(FILE_), __LINE__));
12942 Info = _WRONG_IDENTIFIER;
12943 }
12944 else if (!plci->State || !plci->NL.Id || plci->nl_remove_id)
12945 {
12946 dbug (1, dprintf ("[%06lx] %s,%d: Wrong state",
12947 UnMapId (Id), (char *)(FILE_), __LINE__));
12948 Info = _WRONG_STATE;
12949 }
12950 else
12951 {
12952 plci->command = 0;
12953 plci->ec_cmd = GET_WORD (ec_parms[0].info);
12954 plci->ec_idi_options &= ~(LEC_MANUAL_DISABLE | LEC_RESET_COEFFICIENTS);
12955 result[0] = 5;
12956 PUT_WORD (&result[1], plci->ec_cmd);
12957 result[3] = 2;
12958 PUT_WORD (&result[4], GOOD);
12959 plci->ec_idi_options &= ~(LEC_ENABLE_NONLINEAR_PROCESSING |
12960 LEC_ENABLE_2100HZ_DETECTOR | LEC_REQUIRE_2100HZ_REVERSALS);
12961 plci->ec_tail_length = 0;
12962 if (ec_parms[1].length >= 2)
12963 {
12964 opt = GET_WORD (&ec_parms[1].info[1]);
12965 if (opt & EC_ENABLE_NON_LINEAR_PROCESSING)
12966 plci->ec_idi_options |= LEC_ENABLE_NONLINEAR_PROCESSING;
12967 if (opt & EC_DETECT_DISABLE_TONE)
12968 plci->ec_idi_options |= LEC_ENABLE_2100HZ_DETECTOR;
12969 if (!(opt & EC_DO_NOT_REQUIRE_REVERSALS))
12970 plci->ec_idi_options |= LEC_REQUIRE_2100HZ_REVERSALS;
12971 if (ec_parms[1].length >= 4)
12972 {
12973 plci->ec_tail_length = GET_WORD (&ec_parms[1].info[3]);
12974 }
12975 }
12976 switch (plci->ec_cmd)
12977 {
12978 case EC_ENABLE_OPERATION:
12979 plci->ec_idi_options &= ~LEC_FREEZE_COEFFICIENTS;
12980 start_internal_command (Id, plci, ec_command);
12981 return (FALSE);
12982
12983 case EC_DISABLE_OPERATION:
12984 plci->ec_idi_options = LEC_ENABLE_ECHO_CANCELLER |
12985 LEC_MANUAL_DISABLE | LEC_ENABLE_NONLINEAR_PROCESSING |
12986 LEC_RESET_COEFFICIENTS;
12987 start_internal_command (Id, plci, ec_command);
12988 return (FALSE);
12989
12990 default:
12991 dbug (1, dprintf ("[%06lx] %s,%d: EC unknown request %04x",
12992 UnMapId (Id), (char *)(FILE_), __LINE__, plci->ec_cmd));
12993 PUT_WORD (&result[4], _FACILITY_SPECIFIC_FUNCTION_NOT_SUPP);
12994 }
12995 }
12996 }
12997 }
12998 }
12999 sendf (appl, _FACILITY_R | CONFIRM, Id & 0xffffL, Number,
13000 "wws", Info, (appl->appl_flags & APPL_FLAG_PRIV_EC_SPEC) ?
13001 PRIV_SELECTOR_ECHO_CANCELLER : SELECTOR_ECHO_CANCELLER, result);
13002 return (FALSE);
13003}
13004
13005
13006static void ec_indication (dword Id, PLCI *plci, byte *msg, word length)
13007{
13008 byte result[8];
13009
13010 dbug (1, dprintf ("[%06lx] %s,%d: ec_indication",
13011 UnMapId (Id), (char *)(FILE_), __LINE__));
13012
13013 if (!(plci->ec_idi_options & LEC_MANUAL_DISABLE))
13014 {
13015 if (plci->appl->appl_flags & APPL_FLAG_PRIV_EC_SPEC)
13016 {
13017 result[0] = 2;
13018 PUT_WORD (&result[1], 0);
13019 switch (msg[1])
13020 {
13021 case LEC_DISABLE_TYPE_CONTIGNUOUS_2100HZ:
13022 PUT_WORD (&result[1], EC_BYPASS_DUE_TO_CONTINUOUS_2100HZ);
13023 break;
13024 case LEC_DISABLE_TYPE_REVERSED_2100HZ:
13025 PUT_WORD (&result[1], EC_BYPASS_DUE_TO_REVERSED_2100HZ);
13026 break;
13027 case LEC_DISABLE_RELEASED:
13028 PUT_WORD (&result[1], EC_BYPASS_RELEASED);
13029 break;
13030 }
13031 }
13032 else
13033 {
13034 result[0] = 5;
13035 PUT_WORD (&result[1], EC_BYPASS_INDICATION);
13036 result[3] = 2;
13037 PUT_WORD (&result[4], 0);
13038 switch (msg[1])
13039 {
13040 case LEC_DISABLE_TYPE_CONTIGNUOUS_2100HZ:
13041 PUT_WORD (&result[4], EC_BYPASS_DUE_TO_CONTINUOUS_2100HZ);
13042 break;
13043 case LEC_DISABLE_TYPE_REVERSED_2100HZ:
13044 PUT_WORD (&result[4], EC_BYPASS_DUE_TO_REVERSED_2100HZ);
13045 break;
13046 case LEC_DISABLE_RELEASED:
13047 PUT_WORD (&result[4], EC_BYPASS_RELEASED);
13048 break;
13049 }
13050 }
13051 sendf (plci->appl, _FACILITY_I, Id & 0xffffL, 0, "ws", (plci->appl->appl_flags & APPL_FLAG_PRIV_EC_SPEC) ?
13052 PRIV_SELECTOR_ECHO_CANCELLER : SELECTOR_ECHO_CANCELLER, result);
13053 }
13054}
13055
13056
13057
13058/*------------------------------------------------------------------*/
13059/* Advanced voice */
13060/*------------------------------------------------------------------*/
13061
13062static void adv_voice_write_coefs (PLCI *plci, word write_command)
13063{
13064 DIVA_CAPI_ADAPTER *a;
13065 word i;
13066 byte *p;
13067
13068 word w, n, j, k;
13069 byte ch_map[MIXER_CHANNELS_BRI];
13070
13071 byte coef_buffer[ADV_VOICE_COEF_BUFFER_SIZE + 2];
13072
13073 dbug (1, dprintf ("[%06lx] %s,%d: adv_voice_write_coefs %d",
13074 (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
13075 (char *)(FILE_), __LINE__, write_command));
13076
13077 a = plci->adapter;
13078 p = coef_buffer + 1;
13079 *(p++) = DSP_CTRL_OLD_SET_MIXER_COEFFICIENTS;
13080 i = 0;
13081 while (i + sizeof(word) <= a->adv_voice_coef_length)
13082 {
13083 PUT_WORD (p, GET_WORD (a->adv_voice_coef_buffer + i));
13084 p += 2;
13085 i += 2;
13086 }
13087 while (i < ADV_VOICE_OLD_COEF_COUNT * sizeof(word))
13088 {
13089 PUT_WORD (p, 0x8000);
13090 p += 2;
13091 i += 2;
13092 }
13093
13094 if (!a->li_pri && (plci->li_bchannel_id == 0))
13095 {
13096 if ((li_config_table[a->li_base].plci == NULL) && (li_config_table[a->li_base + 1].plci != NULL))
13097 {
13098 plci->li_bchannel_id = 1;
13099 li_config_table[a->li_base].plci = plci;
13100 dbug (1, dprintf ("[%06lx] %s,%d: adv_voice_set_bchannel_id %d",
13101 (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
13102 (char *)(FILE_), __LINE__, plci->li_bchannel_id));
13103 }
13104 else if ((li_config_table[a->li_base].plci != NULL) && (li_config_table[a->li_base + 1].plci == NULL))
13105 {
13106 plci->li_bchannel_id = 2;
13107 li_config_table[a->li_base + 1].plci = plci;
13108 dbug (1, dprintf ("[%06lx] %s,%d: adv_voice_set_bchannel_id %d",
13109 (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
13110 (char *)(FILE_), __LINE__, plci->li_bchannel_id));
13111 }
13112 }
13113 if (!a->li_pri && (plci->li_bchannel_id != 0)
13114 && (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == plci))
13115 {
13116 i = a->li_base + (plci->li_bchannel_id - 1);
13117 switch (write_command)
13118 {
13119 case ADV_VOICE_WRITE_ACTIVATION:
13120 j = a->li_base + MIXER_IC_CHANNEL_BASE + (plci->li_bchannel_id - 1);
13121 k = a->li_base + MIXER_IC_CHANNEL_BASE + (2 - plci->li_bchannel_id);
13122 if (!(plci->B1_facilities & B1_FACILITY_MIXER))
13123 {
13124 li_config_table[j].flag_table[i] |= LI_FLAG_CONFERENCE | LI_FLAG_MIX;
13125 li_config_table[i].flag_table[j] |= LI_FLAG_CONFERENCE | LI_FLAG_MONITOR;
13126 }
13127 if (a->manufacturer_features & MANUFACTURER_FEATURE_SLAVE_CODEC)
13128 {
13129 li_config_table[k].flag_table[i] |= LI_FLAG_CONFERENCE | LI_FLAG_MIX;
13130 li_config_table[i].flag_table[k] |= LI_FLAG_CONFERENCE | LI_FLAG_MONITOR;
13131 li_config_table[k].flag_table[j] |= LI_FLAG_CONFERENCE;
13132 li_config_table[j].flag_table[k] |= LI_FLAG_CONFERENCE;
13133 }
13134 mixer_calculate_coefs (a);
13135 li_config_table[i].curchnl = li_config_table[i].channel;
13136 li_config_table[j].curchnl = li_config_table[j].channel;
13137 if (a->manufacturer_features & MANUFACTURER_FEATURE_SLAVE_CODEC)
13138 li_config_table[k].curchnl = li_config_table[k].channel;
13139 break;
13140
13141 case ADV_VOICE_WRITE_DEACTIVATION:
13142 for (j = 0; j < li_total_channels; j++)
13143 {
13144 li_config_table[i].flag_table[j] = 0;
13145 li_config_table[j].flag_table[i] = 0;
13146 }
13147 k = a->li_base + MIXER_IC_CHANNEL_BASE + (plci->li_bchannel_id - 1);
13148 for (j = 0; j < li_total_channels; j++)
13149 {
13150 li_config_table[k].flag_table[j] = 0;
13151 li_config_table[j].flag_table[k] = 0;
13152 }
13153 if (a->manufacturer_features & MANUFACTURER_FEATURE_SLAVE_CODEC)
13154 {
13155 k = a->li_base + MIXER_IC_CHANNEL_BASE + (2 - plci->li_bchannel_id);
13156 for (j = 0; j < li_total_channels; j++)
13157 {
13158 li_config_table[k].flag_table[j] = 0;
13159 li_config_table[j].flag_table[k] = 0;
13160 }
13161 }
13162 mixer_calculate_coefs (a);
13163 break;
13164 }
13165 if (plci->B1_facilities & B1_FACILITY_MIXER)
13166 {
13167 w = 0;
13168 if (ADV_VOICE_NEW_COEF_BASE + sizeof(word) <= a->adv_voice_coef_length)
13169 w = GET_WORD (a->adv_voice_coef_buffer + ADV_VOICE_NEW_COEF_BASE);
13170 if (li_config_table[i].channel & LI_CHANNEL_TX_DATA)
13171 w |= MIXER_FEATURE_ENABLE_TX_DATA;
13172 if (li_config_table[i].channel & LI_CHANNEL_RX_DATA)
13173 w |= MIXER_FEATURE_ENABLE_RX_DATA;
13174 *(p++) = (byte) w;
13175 *(p++) = (byte)(w >> 8);
13176 for (j = 0; j < sizeof(ch_map); j += 2)
13177 {
13178 ch_map[j] = (byte)(j + (plci->li_bchannel_id - 1));
13179 ch_map[j+1] = (byte)(j + (2 - plci->li_bchannel_id));
13180 }
13181 for (n = 0; n < sizeof(mixer_write_prog_bri) / sizeof(mixer_write_prog_bri[0]); n++)
13182 {
13183 i = a->li_base + ch_map[mixer_write_prog_bri[n].to_ch];
13184 j = a->li_base + ch_map[mixer_write_prog_bri[n].from_ch];
13185 if (li_config_table[i].channel & li_config_table[j].channel & LI_CHANNEL_INVOLVED)
13186 {
13187 *(p++) = ((li_config_table[i].coef_table[j] & mixer_write_prog_bri[n].mask) ? 0x80 : 0x01);
13188 w = ((li_config_table[i].coef_table[j] & 0xf) ^ (li_config_table[i].coef_table[j] >> 4));
13189 li_config_table[i].coef_table[j] ^= (w & mixer_write_prog_bri[n].mask) << 4;
13190 }
13191 else
13192 {
13193 *(p++) = (ADV_VOICE_NEW_COEF_BASE + sizeof(word) + n < a->adv_voice_coef_length) ?
13194 a->adv_voice_coef_buffer[ADV_VOICE_NEW_COEF_BASE + sizeof(word) + n] : 0x00;
13195 }
13196 }
13197 }
13198 else
13199 {
13200 for (i = ADV_VOICE_NEW_COEF_BASE; i < a->adv_voice_coef_length; i++)
13201 *(p++) = a->adv_voice_coef_buffer[i];
13202 }
13203 }
13204 else
13205
13206 {
13207 for (i = ADV_VOICE_NEW_COEF_BASE; i < a->adv_voice_coef_length; i++)
13208 *(p++) = a->adv_voice_coef_buffer[i];
13209 }
13210 coef_buffer[0] = (p - coef_buffer) - 1;
13211 add_p (plci, FTY, coef_buffer);
13212 sig_req (plci, TEL_CTRL, 0);
13213 send_req (plci);
13214}
13215
13216
13217static void adv_voice_clear_config (PLCI *plci)
13218{
13219 DIVA_CAPI_ADAPTER *a;
13220
13221 word i, j;
13222
13223
13224 dbug (1, dprintf ("[%06lx] %s,%d: adv_voice_clear_config",
13225 (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
13226 (char *)(FILE_), __LINE__));
13227
13228 a = plci->adapter;
13229 if ((plci->tel == ADV_VOICE) && (plci == a->AdvSignalPLCI))
13230 {
13231 a->adv_voice_coef_length = 0;
13232
13233 if (!a->li_pri && (plci->li_bchannel_id != 0)
13234 && (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == plci))
13235 {
13236 i = a->li_base + (plci->li_bchannel_id - 1);
13237 li_config_table[i].curchnl = 0;
13238 li_config_table[i].channel = 0;
13239 li_config_table[i].chflags = 0;
13240 for (j = 0; j < li_total_channels; j++)
13241 {
13242 li_config_table[i].flag_table[j] = 0;
13243 li_config_table[j].flag_table[i] = 0;
13244 li_config_table[i].coef_table[j] = 0;
13245 li_config_table[j].coef_table[i] = 0;
13246 }
13247 li_config_table[i].coef_table[i] |= LI_COEF_CH_PC_SET | LI_COEF_PC_CH_SET;
13248 i = a->li_base + MIXER_IC_CHANNEL_BASE + (plci->li_bchannel_id - 1);
13249 li_config_table[i].curchnl = 0;
13250 li_config_table[i].channel = 0;
13251 li_config_table[i].chflags = 0;
13252 for (j = 0; j < li_total_channels; j++)
13253 {
13254 li_config_table[i].flag_table[j] = 0;
13255 li_config_table[j].flag_table[i] = 0;
13256 li_config_table[i].coef_table[j] = 0;
13257 li_config_table[j].coef_table[i] = 0;
13258 }
13259 if (a->manufacturer_features & MANUFACTURER_FEATURE_SLAVE_CODEC)
13260 {
13261 i = a->li_base + MIXER_IC_CHANNEL_BASE + (2 - plci->li_bchannel_id);
13262 li_config_table[i].curchnl = 0;
13263 li_config_table[i].channel = 0;
13264 li_config_table[i].chflags = 0;
13265 for (j = 0; j < li_total_channels; j++)
13266 {
13267 li_config_table[i].flag_table[j] = 0;
13268 li_config_table[j].flag_table[i] = 0;
13269 li_config_table[i].coef_table[j] = 0;
13270 li_config_table[j].coef_table[i] = 0;
13271 }
13272 }
13273 }
13274
13275 }
13276}
13277
13278
13279static void adv_voice_prepare_switch (dword Id, PLCI *plci)
13280{
13281
13282 dbug (1, dprintf ("[%06lx] %s,%d: adv_voice_prepare_switch",
13283 UnMapId (Id), (char *)(FILE_), __LINE__));
13284
13285}
13286
13287
13288static word adv_voice_save_config (dword Id, PLCI *plci, byte Rc)
13289{
13290
13291 dbug (1, dprintf ("[%06lx] %s,%d: adv_voice_save_config %02x %d",
13292 UnMapId (Id), (char *)(FILE_), __LINE__, Rc, plci->adjust_b_state));
13293
13294 return (GOOD);
13295}
13296
13297
13298static word adv_voice_restore_config (dword Id, PLCI *plci, byte Rc)
13299{
13300 DIVA_CAPI_ADAPTER *a;
13301 word Info;
13302
13303 dbug (1, dprintf ("[%06lx] %s,%d: adv_voice_restore_config %02x %d",
13304 UnMapId (Id), (char *)(FILE_), __LINE__, Rc, plci->adjust_b_state));
13305
13306 Info = GOOD;
13307 a = plci->adapter;
13308 if ((plci->B1_facilities & B1_FACILITY_VOICE)
13309 && (plci->tel == ADV_VOICE) && (plci == a->AdvSignalPLCI))
13310 {
13311 switch (plci->adjust_b_state)
13312 {
13313 case ADJUST_B_RESTORE_VOICE_1:
13314 plci->internal_command = plci->adjust_b_command;
13315 if (plci->sig_req)
13316 {
13317 plci->adjust_b_state = ADJUST_B_RESTORE_VOICE_1;
13318 break;
13319 }
13320 adv_voice_write_coefs (plci, ADV_VOICE_WRITE_UPDATE);
13321 plci->adjust_b_state = ADJUST_B_RESTORE_VOICE_2;
13322 break;
13323 case ADJUST_B_RESTORE_VOICE_2:
13324 if ((Rc != OK) && (Rc != OK_FC))
13325 {
13326 dbug (1, dprintf ("[%06lx] %s,%d: Restore voice config failed %02x",
13327 UnMapId (Id), (char *)(FILE_), __LINE__, Rc));
13328 Info = _WRONG_STATE;
13329 break;
13330 }
13331 break;
13332 }
13333 }
13334 return (Info);
13335}
13336
13337
13338
13339
13340/*------------------------------------------------------------------*/
13341/* B1 resource switching */
13342/*------------------------------------------------------------------*/
13343
13344static byte b1_facilities_table[] =
13345{
13346 0x00, /* 0 No bchannel resources */
13347 0x00, /* 1 Codec (automatic law) */
13348 0x00, /* 2 Codec (A-law) */
13349 0x00, /* 3 Codec (y-law) */
13350 0x00, /* 4 HDLC for X.21 */
13351 0x00, /* 5 HDLC */
13352 0x00, /* 6 External Device 0 */
13353 0x00, /* 7 External Device 1 */
13354 0x00, /* 8 HDLC 56k */
13355 0x00, /* 9 Transparent */
13356 0x00, /* 10 Loopback to network */
13357 0x00, /* 11 Test pattern to net */
13358 0x00, /* 12 Rate adaptation sync */
13359 0x00, /* 13 Rate adaptation async */
13360 0x00, /* 14 R-Interface */
13361 0x00, /* 15 HDLC 128k leased line */
13362 0x00, /* 16 FAX */
13363 0x00, /* 17 Modem async */
13364 0x00, /* 18 Modem sync HDLC */
13365 0x00, /* 19 V.110 async HDLC */
13366 0x12, /* 20 Adv voice (Trans,mixer) */
13367 0x00, /* 21 Codec connected to IC */
13368 0x0c, /* 22 Trans,DTMF */
13369 0x1e, /* 23 Trans,DTMF+mixer */
13370 0x1f, /* 24 Trans,DTMF+mixer+local */
13371 0x13, /* 25 Trans,mixer+local */
13372 0x12, /* 26 HDLC,mixer */
13373 0x12, /* 27 HDLC 56k,mixer */
13374 0x2c, /* 28 Trans,LEC+DTMF */
13375 0x3e, /* 29 Trans,LEC+DTMF+mixer */
13376 0x3f, /* 30 Trans,LEC+DTMF+mixer+local */
13377 0x2c, /* 31 RTP,LEC+DTMF */
13378 0x3e, /* 32 RTP,LEC+DTMF+mixer */
13379 0x3f, /* 33 RTP,LEC+DTMF+mixer+local */
13380 0x00, /* 34 Signaling task */
13381 0x00, /* 35 PIAFS */
13382 0x0c, /* 36 Trans,DTMF+TONE */
13383 0x1e, /* 37 Trans,DTMF+TONE+mixer */
13384 0x1f /* 38 Trans,DTMF+TONE+mixer+local*/
13385};
13386
13387
13388static word get_b1_facilities (PLCI * plci, byte b1_resource)
13389{
13390 word b1_facilities;
13391
13392 b1_facilities = b1_facilities_table[b1_resource];
13393 if ((b1_resource == 9) || (b1_resource == 20) || (b1_resource == 25))
13394 {
13395
13396 if (!(((plci->requested_options_conn | plci->requested_options) & (1L << PRIVATE_DTMF_TONE))
13397 || (plci->appl && (plci->adapter->requested_options_table[plci->appl->Id-1] & (1L << PRIVATE_DTMF_TONE)))))
13398
13399 {
13400 if (plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_SOFTDTMF_SEND)
13401 b1_facilities |= B1_FACILITY_DTMFX;
13402 if (plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_SOFTDTMF_RECEIVE)
13403 b1_facilities |= B1_FACILITY_DTMFR;
13404 }
13405 }
13406 if ((b1_resource == 17) || (b1_resource == 18))
13407 {
13408 if (plci->adapter->manufacturer_features & (MANUFACTURER_FEATURE_V18 | MANUFACTURER_FEATURE_VOWN))
13409 b1_facilities |= B1_FACILITY_DTMFX | B1_FACILITY_DTMFR;
13410 }
13411/*
13412 dbug (1, dprintf ("[%06lx] %s,%d: get_b1_facilities %d %04x",
13413 (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
13414 (char far *)(FILE_), __LINE__, b1_resource, b1_facilites));
13415*/
13416 return (b1_facilities);
13417}
13418
13419
13420static byte add_b1_facilities (PLCI * plci, byte b1_resource, word b1_facilities)
13421{
13422 byte b;
13423
13424 switch (b1_resource)
13425 {
13426 case 5:
13427 case 26:
13428 if (b1_facilities & (B1_FACILITY_MIXER | B1_FACILITY_VOICE))
13429 b = 26;
13430 else
13431 b = 5;
13432 break;
13433
13434 case 8:
13435 case 27:
13436 if (b1_facilities & (B1_FACILITY_MIXER | B1_FACILITY_VOICE))
13437 b = 27;
13438 else
13439 b = 8;
13440 break;
13441
13442 case 9:
13443 case 20:
13444 case 22:
13445 case 23:
13446 case 24:
13447 case 25:
13448 case 28:
13449 case 29:
13450 case 30:
13451 case 36:
13452 case 37:
13453 case 38:
13454 if (b1_facilities & B1_FACILITY_EC)
13455 {
13456 if (b1_facilities & B1_FACILITY_LOCAL)
13457 b = 30;
13458 else if (b1_facilities & (B1_FACILITY_MIXER | B1_FACILITY_VOICE))
13459 b = 29;
13460 else
13461 b = 28;
13462 }
13463
13464 else if ((b1_facilities & (B1_FACILITY_DTMFX | B1_FACILITY_DTMFR | B1_FACILITY_MIXER))
13465 && (((plci->requested_options_conn | plci->requested_options) & (1L << PRIVATE_DTMF_TONE))
13466 || (plci->appl && (plci->adapter->requested_options_table[plci->appl->Id-1] & (1L << PRIVATE_DTMF_TONE)))))
13467 {
13468 if (b1_facilities & B1_FACILITY_LOCAL)
13469 b = 38;
13470 else if (b1_facilities & (B1_FACILITY_MIXER | B1_FACILITY_VOICE))
13471 b = 37;
13472 else
13473 b = 36;
13474 }
13475
13476 else if (((plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_HARDDTMF)
13477 && !(plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_SOFTDTMF_RECEIVE))
13478 || ((b1_facilities & B1_FACILITY_DTMFR)
13479 && ((b1_facilities & B1_FACILITY_MIXER)
13480 || !(plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_SOFTDTMF_RECEIVE)))
13481 || ((b1_facilities & B1_FACILITY_DTMFX)
13482 && ((b1_facilities & B1_FACILITY_MIXER)
13483 || !(plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_SOFTDTMF_SEND))))
13484 {
13485 if (b1_facilities & B1_FACILITY_LOCAL)
13486 b = 24;
13487 else if (b1_facilities & (B1_FACILITY_MIXER | B1_FACILITY_VOICE))
13488 b = 23;
13489 else
13490 b = 22;
13491 }
13492 else
13493 {
13494 if (b1_facilities & B1_FACILITY_LOCAL)
13495 b = 25;
13496 else if (b1_facilities & (B1_FACILITY_MIXER | B1_FACILITY_VOICE))
13497 b = 20;
13498 else
13499 b = 9;
13500 }
13501 break;
13502
13503 case 31:
13504 case 32:
13505 case 33:
13506 if (b1_facilities & B1_FACILITY_LOCAL)
13507 b = 33;
13508 else if (b1_facilities & (B1_FACILITY_MIXER | B1_FACILITY_VOICE))
13509 b = 32;
13510 else
13511 b = 31;
13512 break;
13513
13514 default:
13515 b = b1_resource;
13516 }
13517 dbug (1, dprintf ("[%06lx] %s,%d: add_b1_facilities %d %04x %d %04x",
13518 (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
13519 (char *)(FILE_), __LINE__,
13520 b1_resource, b1_facilities, b, get_b1_facilities (plci, b)));
13521 return (b);
13522}
13523
13524
13525static void adjust_b1_facilities (PLCI *plci, byte new_b1_resource, word new_b1_facilities)
13526{
13527 word removed_facilities;
13528
13529 dbug (1, dprintf ("[%06lx] %s,%d: adjust_b1_facilities %d %04x %04x",
13530 (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
13531 (char *)(FILE_), __LINE__, new_b1_resource, new_b1_facilities,
13532 new_b1_facilities & get_b1_facilities (plci, new_b1_resource)));
13533
13534 new_b1_facilities &= get_b1_facilities (plci, new_b1_resource);
13535 removed_facilities = plci->B1_facilities & ~new_b1_facilities;
13536
13537 if (removed_facilities & B1_FACILITY_EC)
13538 ec_clear_config (plci);
13539
13540
13541 if (removed_facilities & B1_FACILITY_DTMFR)
13542 {
13543 dtmf_rec_clear_config (plci);
13544 dtmf_parameter_clear_config (plci);
13545 }
13546 if (removed_facilities & B1_FACILITY_DTMFX)
13547 dtmf_send_clear_config (plci);
13548
13549
13550 if (removed_facilities & B1_FACILITY_MIXER)
13551 mixer_clear_config (plci);
13552
13553 if (removed_facilities & B1_FACILITY_VOICE)
13554 adv_voice_clear_config (plci);
13555 plci->B1_facilities = new_b1_facilities;
13556}
13557
13558
13559static void adjust_b_clear (PLCI *plci)
13560{
13561
13562 dbug (1, dprintf ("[%06lx] %s,%d: adjust_b_clear",
13563 (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
13564 (char *)(FILE_), __LINE__));
13565
13566 plci->adjust_b_restore = FALSE;
13567}
13568
13569
13570static word adjust_b_process (dword Id, PLCI *plci, byte Rc)
13571{
13572 word Info;
13573 byte b1_resource;
13574 NCCI * ncci_ptr;
13575 API_PARSE bp[2];
13576
13577 dbug (1, dprintf ("[%06lx] %s,%d: adjust_b_process %02x %d",
13578 UnMapId (Id), (char *)(FILE_), __LINE__, Rc, plci->adjust_b_state));
13579
13580 Info = GOOD;
13581 switch (plci->adjust_b_state)
13582 {
13583 case ADJUST_B_START:
13584 if ((plci->adjust_b_parms_msg == NULL)
13585 && (plci->adjust_b_mode & ADJUST_B_MODE_SWITCH_L1)
13586 && ((plci->adjust_b_mode & ~(ADJUST_B_MODE_SAVE | ADJUST_B_MODE_SWITCH_L1 |
13587 ADJUST_B_MODE_NO_RESOURCE | ADJUST_B_MODE_RESTORE)) == 0))
13588 {
13589 b1_resource = (plci->adjust_b_mode == ADJUST_B_MODE_NO_RESOURCE) ?
13590 0 : add_b1_facilities (plci, plci->B1_resource, plci->adjust_b_facilities);
13591 if (b1_resource == plci->B1_resource)
13592 {
13593 adjust_b1_facilities (plci, b1_resource, plci->adjust_b_facilities);
13594 break;
13595 }
13596 if (plci->adjust_b_facilities & ~get_b1_facilities (plci, b1_resource))
13597 {
13598 dbug (1, dprintf ("[%06lx] %s,%d: Adjust B nonsupported facilities %d %d %04x",
13599 UnMapId (Id), (char *)(FILE_), __LINE__,
13600 plci->B1_resource, b1_resource, plci->adjust_b_facilities));
13601 Info = _WRONG_STATE;
13602 break;
13603 }
13604 }
13605 if (plci->adjust_b_mode & ADJUST_B_MODE_SAVE)
13606 {
13607
13608 mixer_prepare_switch (Id, plci);
13609
13610
13611 dtmf_prepare_switch (Id, plci);
13612 dtmf_parameter_prepare_switch (Id, plci);
13613
13614
13615 ec_prepare_switch (Id, plci);
13616
13617 adv_voice_prepare_switch (Id, plci);
13618 }
13619 plci->adjust_b_state = ADJUST_B_SAVE_MIXER_1;
13620 Rc = OK;
13621 case ADJUST_B_SAVE_MIXER_1:
13622 if (plci->adjust_b_mode & ADJUST_B_MODE_SAVE)
13623 {
13624
13625 Info = mixer_save_config (Id, plci, Rc);
13626 if ((Info != GOOD) || plci->internal_command)
13627 break;
13628
13629 }
13630 plci->adjust_b_state = ADJUST_B_SAVE_DTMF_1;
13631 Rc = OK;
13632 case ADJUST_B_SAVE_DTMF_1:
13633 if (plci->adjust_b_mode & ADJUST_B_MODE_SAVE)
13634 {
13635
13636 Info = dtmf_save_config (Id, plci, Rc);
13637 if ((Info != GOOD) || plci->internal_command)
13638 break;
13639
13640 }
13641 plci->adjust_b_state = ADJUST_B_REMOVE_L23_1;
13642 case ADJUST_B_REMOVE_L23_1:
13643 if ((plci->adjust_b_mode & ADJUST_B_MODE_REMOVE_L23)
13644 && plci->NL.Id && !plci->nl_remove_id)
13645 {
13646 plci->internal_command = plci->adjust_b_command;
13647 if (plci->adjust_b_ncci != 0)
13648 {
13649 ncci_ptr = &(plci->adapter->ncci[plci->adjust_b_ncci]);
13650 while (ncci_ptr->data_pending)
13651 {
13652 plci->data_sent_ptr = ncci_ptr->DBuffer[ncci_ptr->data_out].P;
13653 data_rc (plci, plci->adapter->ncci_ch[plci->adjust_b_ncci]);
13654 }
13655 while (ncci_ptr->data_ack_pending)
13656 data_ack (plci, plci->adapter->ncci_ch[plci->adjust_b_ncci]);
13657 }
13658 nl_req_ncci (plci, REMOVE,
13659 (byte)((plci->adjust_b_mode & ADJUST_B_MODE_CONNECT) ? plci->adjust_b_ncci : 0));
13660 send_req (plci);
13661 plci->adjust_b_state = ADJUST_B_REMOVE_L23_2;
13662 break;
13663 }
13664 plci->adjust_b_state = ADJUST_B_REMOVE_L23_2;
13665 Rc = OK;
13666 case ADJUST_B_REMOVE_L23_2:
13667 if ((Rc != OK) && (Rc != OK_FC))
13668 {
13669 dbug (1, dprintf ("[%06lx] %s,%d: Adjust B remove failed %02x",
13670 UnMapId (Id), (char *)(FILE_), __LINE__, Rc));
13671 Info = _WRONG_STATE;
13672 break;
13673 }
13674 if (plci->adjust_b_mode & ADJUST_B_MODE_REMOVE_L23)
13675 {
13676 if (plci_nl_busy (plci))
13677 {
13678 plci->internal_command = plci->adjust_b_command;
13679 break;
13680 }
13681 }
13682 plci->adjust_b_state = ADJUST_B_SAVE_EC_1;
13683 Rc = OK;
13684 case ADJUST_B_SAVE_EC_1:
13685 if (plci->adjust_b_mode & ADJUST_B_MODE_SAVE)
13686 {
13687
13688 Info = ec_save_config (Id, plci, Rc);
13689 if ((Info != GOOD) || plci->internal_command)
13690 break;
13691
13692 }
13693 plci->adjust_b_state = ADJUST_B_SAVE_DTMF_PARAMETER_1;
13694 Rc = OK;
13695 case ADJUST_B_SAVE_DTMF_PARAMETER_1:
13696 if (plci->adjust_b_mode & ADJUST_B_MODE_SAVE)
13697 {
13698
13699 Info = dtmf_parameter_save_config (Id, plci, Rc);
13700 if ((Info != GOOD) || plci->internal_command)
13701 break;
13702
13703 }
13704 plci->adjust_b_state = ADJUST_B_SAVE_VOICE_1;
13705 Rc = OK;
13706 case ADJUST_B_SAVE_VOICE_1:
13707 if (plci->adjust_b_mode & ADJUST_B_MODE_SAVE)
13708 {
13709 Info = adv_voice_save_config (Id, plci, Rc);
13710 if ((Info != GOOD) || plci->internal_command)
13711 break;
13712 }
13713 plci->adjust_b_state = ADJUST_B_SWITCH_L1_1;
13714 case ADJUST_B_SWITCH_L1_1:
13715 if (plci->adjust_b_mode & ADJUST_B_MODE_SWITCH_L1)
13716 {
13717 if (plci->sig_req)
13718 {
13719 plci->internal_command = plci->adjust_b_command;
13720 break;
13721 }
13722 if (plci->adjust_b_parms_msg != NULL)
13723 api_load_msg (plci->adjust_b_parms_msg, bp);
13724 else
13725 api_load_msg (&plci->B_protocol, bp);
13726 Info = add_b1 (plci, bp,
13727 (word)((plci->adjust_b_mode & ADJUST_B_MODE_NO_RESOURCE) ? 2 : 0),
13728 plci->adjust_b_facilities);
13729 if (Info != GOOD)
13730 {
13731 dbug (1, dprintf ("[%06lx] %s,%d: Adjust B invalid L1 parameters %d %04x",
13732 UnMapId (Id), (char *)(FILE_), __LINE__,
13733 plci->B1_resource, plci->adjust_b_facilities));
13734 break;
13735 }
13736 plci->internal_command = plci->adjust_b_command;
13737 sig_req (plci, RESOURCES, 0);
13738 send_req (plci);
13739 plci->adjust_b_state = ADJUST_B_SWITCH_L1_2;
13740 break;
13741 }
13742 plci->adjust_b_state = ADJUST_B_SWITCH_L1_2;
13743 Rc = OK;
13744 case ADJUST_B_SWITCH_L1_2:
13745 if ((Rc != OK) && (Rc != OK_FC))
13746 {
13747 dbug (1, dprintf ("[%06lx] %s,%d: Adjust B switch failed %02x %d %04x",
13748 UnMapId (Id), (char *)(FILE_), __LINE__,
13749 Rc, plci->B1_resource, plci->adjust_b_facilities));
13750 Info = _WRONG_STATE;
13751 break;
13752 }
13753 plci->adjust_b_state = ADJUST_B_RESTORE_VOICE_1;
13754 Rc = OK;
13755 case ADJUST_B_RESTORE_VOICE_1:
13756 case ADJUST_B_RESTORE_VOICE_2:
13757 if (plci->adjust_b_mode & ADJUST_B_MODE_RESTORE)
13758 {
13759 Info = adv_voice_restore_config (Id, plci, Rc);
13760 if ((Info != GOOD) || plci->internal_command)
13761 break;
13762 }
13763 plci->adjust_b_state = ADJUST_B_RESTORE_DTMF_PARAMETER_1;
13764 Rc = OK;
13765 case ADJUST_B_RESTORE_DTMF_PARAMETER_1:
13766 case ADJUST_B_RESTORE_DTMF_PARAMETER_2:
13767 if (plci->adjust_b_mode & ADJUST_B_MODE_RESTORE)
13768 {
13769
13770 Info = dtmf_parameter_restore_config (Id, plci, Rc);
13771 if ((Info != GOOD) || plci->internal_command)
13772 break;
13773
13774 }
13775 plci->adjust_b_state = ADJUST_B_RESTORE_EC_1;
13776 Rc = OK;
13777 case ADJUST_B_RESTORE_EC_1:
13778 case ADJUST_B_RESTORE_EC_2:
13779 if (plci->adjust_b_mode & ADJUST_B_MODE_RESTORE)
13780 {
13781
13782 Info = ec_restore_config (Id, plci, Rc);
13783 if ((Info != GOOD) || plci->internal_command)
13784 break;
13785
13786 }
13787 plci->adjust_b_state = ADJUST_B_ASSIGN_L23_1;
13788 case ADJUST_B_ASSIGN_L23_1:
13789 if (plci->adjust_b_mode & ADJUST_B_MODE_ASSIGN_L23)
13790 {
13791 if (plci_nl_busy (plci))
13792 {
13793 plci->internal_command = plci->adjust_b_command;
13794 break;
13795 }
13796 if (plci->adjust_b_mode & ADJUST_B_MODE_CONNECT)
13797 plci->call_dir |= CALL_DIR_FORCE_OUTG_NL;
13798 if (plci->adjust_b_parms_msg != NULL)
13799 api_load_msg (plci->adjust_b_parms_msg, bp);
13800 else
13801 api_load_msg (&plci->B_protocol, bp);
13802 Info = add_b23 (plci, bp);
13803 if (Info != GOOD)
13804 {
13805 dbug (1, dprintf ("[%06lx] %s,%d: Adjust B invalid L23 parameters %04x",
13806 UnMapId (Id), (char *)(FILE_), __LINE__, Info));
13807 break;
13808 }
13809 plci->internal_command = plci->adjust_b_command;
13810 nl_req_ncci (plci, ASSIGN, 0);
13811 send_req (plci);
13812 plci->adjust_b_state = ADJUST_B_ASSIGN_L23_2;
13813 break;
13814 }
13815 plci->adjust_b_state = ADJUST_B_ASSIGN_L23_2;
13816 Rc = ASSIGN_OK;
13817 case ADJUST_B_ASSIGN_L23_2:
13818 if ((Rc != OK) && (Rc != OK_FC) && (Rc != ASSIGN_OK))
13819 {
13820 dbug (1, dprintf ("[%06lx] %s,%d: Adjust B assign failed %02x",
13821 UnMapId (Id), (char *)(FILE_), __LINE__, Rc));
13822 Info = _WRONG_STATE;
13823 break;
13824 }
13825 if (plci->adjust_b_mode & ADJUST_B_MODE_ASSIGN_L23)
13826 {
13827 if (Rc != ASSIGN_OK)
13828 {
13829 plci->internal_command = plci->adjust_b_command;
13830 break;
13831 }
13832 }
13833 if (plci->adjust_b_mode & ADJUST_B_MODE_USER_CONNECT)
13834 {
13835 plci->adjust_b_restore = TRUE;
13836 break;
13837 }
13838 plci->adjust_b_state = ADJUST_B_CONNECT_1;
13839 case ADJUST_B_CONNECT_1:
13840 if (plci->adjust_b_mode & ADJUST_B_MODE_CONNECT)
13841 {
13842 plci->internal_command = plci->adjust_b_command;
13843 if (plci_nl_busy (plci))
13844 break;
13845 nl_req_ncci (plci, N_CONNECT, 0);
13846 send_req (plci);
13847 plci->adjust_b_state = ADJUST_B_CONNECT_2;
13848 break;
13849 }
13850 plci->adjust_b_state = ADJUST_B_RESTORE_DTMF_1;
13851 Rc = OK;
13852 case ADJUST_B_CONNECT_2:
13853 case ADJUST_B_CONNECT_3:
13854 case ADJUST_B_CONNECT_4:
13855 if ((Rc != OK) && (Rc != OK_FC) && (Rc != 0))
13856 {
13857 dbug (1, dprintf ("[%06lx] %s,%d: Adjust B connect failed %02x",
13858 UnMapId (Id), (char *)(FILE_), __LINE__, Rc));
13859 Info = _WRONG_STATE;
13860 break;
13861 }
13862 if (Rc == OK)
13863 {
13864 if (plci->adjust_b_mode & ADJUST_B_MODE_CONNECT)
13865 {
13866 get_ncci (plci, (byte)(Id >> 16), plci->adjust_b_ncci);
13867 Id = (Id & 0xffff) | (((dword)(plci->adjust_b_ncci)) << 16);
13868 }
13869 if (plci->adjust_b_state == ADJUST_B_CONNECT_2)
13870 plci->adjust_b_state = ADJUST_B_CONNECT_3;
13871 else if (plci->adjust_b_state == ADJUST_B_CONNECT_4)
13872 plci->adjust_b_state = ADJUST_B_RESTORE_DTMF_1;
13873 }
13874 else if (Rc == 0)
13875 {
13876 if (plci->adjust_b_state == ADJUST_B_CONNECT_2)
13877 plci->adjust_b_state = ADJUST_B_CONNECT_4;
13878 else if (plci->adjust_b_state == ADJUST_B_CONNECT_3)
13879 plci->adjust_b_state = ADJUST_B_RESTORE_DTMF_1;
13880 }
13881 if (plci->adjust_b_state != ADJUST_B_RESTORE_DTMF_1)
13882 {
13883 plci->internal_command = plci->adjust_b_command;
13884 break;
13885 }
13886 Rc = OK;
13887 case ADJUST_B_RESTORE_DTMF_1:
13888 case ADJUST_B_RESTORE_DTMF_2:
13889 if (plci->adjust_b_mode & ADJUST_B_MODE_RESTORE)
13890 {
13891
13892 Info = dtmf_restore_config (Id, plci, Rc);
13893 if ((Info != GOOD) || plci->internal_command)
13894 break;
13895
13896 }
13897 plci->adjust_b_state = ADJUST_B_RESTORE_MIXER_1;
13898 Rc = OK;
13899 case ADJUST_B_RESTORE_MIXER_1:
13900 case ADJUST_B_RESTORE_MIXER_2:
13901 case ADJUST_B_RESTORE_MIXER_3:
13902 case ADJUST_B_RESTORE_MIXER_4:
13903 case ADJUST_B_RESTORE_MIXER_5:
13904 case ADJUST_B_RESTORE_MIXER_6:
13905 case ADJUST_B_RESTORE_MIXER_7:
13906 if (plci->adjust_b_mode & ADJUST_B_MODE_RESTORE)
13907 {
13908
13909 Info = mixer_restore_config (Id, plci, Rc);
13910 if ((Info != GOOD) || plci->internal_command)
13911 break;
13912
13913 }
13914 plci->adjust_b_state = ADJUST_B_END;
13915 case ADJUST_B_END:
13916 break;
13917 }
13918 return (Info);
13919}
13920
13921
13922static void adjust_b1_resource (dword Id, PLCI *plci, API_SAVE *bp_msg, word b1_facilities, word internal_command)
13923{
13924
13925 dbug (1, dprintf ("[%06lx] %s,%d: adjust_b1_resource %d %04x",
13926 UnMapId (Id), (char *)(FILE_), __LINE__,
13927 plci->B1_resource, b1_facilities));
13928
13929 plci->adjust_b_parms_msg = bp_msg;
13930 plci->adjust_b_facilities = b1_facilities;
13931 plci->adjust_b_command = internal_command;
13932 plci->adjust_b_ncci = (word)(Id >> 16);
13933 if ((bp_msg == NULL) && (plci->B1_resource == 0))
13934 plci->adjust_b_mode = ADJUST_B_MODE_SAVE | ADJUST_B_MODE_NO_RESOURCE | ADJUST_B_MODE_SWITCH_L1;
13935 else
13936 plci->adjust_b_mode = ADJUST_B_MODE_SAVE | ADJUST_B_MODE_SWITCH_L1 | ADJUST_B_MODE_RESTORE;
13937 plci->adjust_b_state = ADJUST_B_START;
13938 dbug (1, dprintf ("[%06lx] %s,%d: Adjust B1 resource %d %04x...",
13939 UnMapId (Id), (char *)(FILE_), __LINE__,
13940 plci->B1_resource, b1_facilities));
13941}
13942
13943
13944static void adjust_b_restore (dword Id, PLCI *plci, byte Rc)
13945{
13946 word internal_command;
13947
13948 dbug (1, dprintf ("[%06lx] %s,%d: adjust_b_restore %02x %04x",
13949 UnMapId (Id), (char *)(FILE_), __LINE__, Rc, plci->internal_command));
13950
13951 internal_command = plci->internal_command;
13952 plci->internal_command = 0;
13953 switch (internal_command)
13954 {
13955 default:
13956 plci->command = 0;
13957 if (plci->req_in != 0)
13958 {
13959 plci->internal_command = ADJUST_B_RESTORE_1;
13960 break;
13961 }
13962 Rc = OK;
13963 case ADJUST_B_RESTORE_1:
13964 if ((Rc != OK) && (Rc != OK_FC))
13965 {
13966 dbug (1, dprintf ("[%06lx] %s,%d: Adjust B enqueued failed %02x",
13967 UnMapId (Id), (char *)(FILE_), __LINE__, Rc));
13968 }
13969 plci->adjust_b_parms_msg = NULL;
13970 plci->adjust_b_facilities = plci->B1_facilities;
13971 plci->adjust_b_command = ADJUST_B_RESTORE_2;
13972 plci->adjust_b_ncci = (word)(Id >> 16);
13973 plci->adjust_b_mode = ADJUST_B_MODE_RESTORE;
13974 plci->adjust_b_state = ADJUST_B_START;
13975 dbug (1, dprintf ("[%06lx] %s,%d: Adjust B restore...",
13976 UnMapId (Id), (char *)(FILE_), __LINE__));
13977 case ADJUST_B_RESTORE_2:
13978 if (adjust_b_process (Id, plci, Rc) != GOOD)
13979 {
13980 dbug (1, dprintf ("[%06lx] %s,%d: Adjust B restore failed",
13981 UnMapId (Id), (char *)(FILE_), __LINE__));
13982 }
13983 if (plci->internal_command)
13984 break;
13985 break;
13986 }
13987}
13988
13989
13990static void reset_b3_command (dword Id, PLCI *plci, byte Rc)
13991{
13992 word Info;
13993 word internal_command;
13994
13995 dbug (1, dprintf ("[%06lx] %s,%d: reset_b3_command %02x %04x",
13996 UnMapId (Id), (char *)(FILE_), __LINE__, Rc, plci->internal_command));
13997
13998 Info = GOOD;
13999 internal_command = plci->internal_command;
14000 plci->internal_command = 0;
14001 switch (internal_command)
14002 {
14003 default:
14004 plci->command = 0;
14005 plci->adjust_b_parms_msg = NULL;
14006 plci->adjust_b_facilities = plci->B1_facilities;
14007 plci->adjust_b_command = RESET_B3_COMMAND_1;
14008 plci->adjust_b_ncci = (word)(Id >> 16);
14009 plci->adjust_b_mode = ADJUST_B_MODE_REMOVE_L23 | ADJUST_B_MODE_ASSIGN_L23 | ADJUST_B_MODE_CONNECT;
14010 plci->adjust_b_state = ADJUST_B_START;
14011 dbug (1, dprintf ("[%06lx] %s,%d: Reset B3...",
14012 UnMapId (Id), (char *)(FILE_), __LINE__));
14013 case RESET_B3_COMMAND_1:
14014 Info = adjust_b_process (Id, plci, Rc);
14015 if (Info != GOOD)
14016 {
14017 dbug (1, dprintf ("[%06lx] %s,%d: Reset failed",
14018 UnMapId (Id), (char *)(FILE_), __LINE__));
14019 break;
14020 }
14021 if (plci->internal_command)
14022 return;
14023 break;
14024 }
14025/* sendf (plci->appl, _RESET_B3_R | CONFIRM, Id, plci->number, "w", Info);*/
14026 sendf(plci->appl,_RESET_B3_I,Id,0,"s","");
14027}
14028
14029
14030static void select_b_command (dword Id, PLCI *plci, byte Rc)
14031{
14032 word Info;
14033 word internal_command;
14034 byte esc_chi[3];
14035
14036 dbug (1, dprintf ("[%06lx] %s,%d: select_b_command %02x %04x",
14037 UnMapId (Id), (char *)(FILE_), __LINE__, Rc, plci->internal_command));
14038
14039 Info = GOOD;
14040 internal_command = plci->internal_command;
14041 plci->internal_command = 0;
14042 switch (internal_command)
14043 {
14044 default:
14045 plci->command = 0;
14046 plci->adjust_b_parms_msg = &plci->saved_msg;
14047 if ((plci->tel == ADV_VOICE) && (plci == plci->adapter->AdvSignalPLCI))
14048 plci->adjust_b_facilities = plci->B1_facilities | B1_FACILITY_VOICE;
14049 else
14050 plci->adjust_b_facilities = plci->B1_facilities & ~B1_FACILITY_VOICE;
14051 plci->adjust_b_command = SELECT_B_COMMAND_1;
14052 plci->adjust_b_ncci = (word)(Id >> 16);
14053 if (plci->saved_msg.parms[0].length == 0)
14054 {
14055 plci->adjust_b_mode = ADJUST_B_MODE_SAVE | ADJUST_B_MODE_REMOVE_L23 | ADJUST_B_MODE_SWITCH_L1 |
14056 ADJUST_B_MODE_NO_RESOURCE;
14057 }
14058 else
14059 {
14060 plci->adjust_b_mode = ADJUST_B_MODE_SAVE | ADJUST_B_MODE_REMOVE_L23 | ADJUST_B_MODE_SWITCH_L1 |
14061 ADJUST_B_MODE_ASSIGN_L23 | ADJUST_B_MODE_USER_CONNECT | ADJUST_B_MODE_RESTORE;
14062 }
14063 plci->adjust_b_state = ADJUST_B_START;
14064 dbug (1, dprintf ("[%06lx] %s,%d: Select B protocol...",
14065 UnMapId (Id), (char *)(FILE_), __LINE__));
14066 case SELECT_B_COMMAND_1:
14067 Info = adjust_b_process (Id, plci, Rc);
14068 if (Info != GOOD)
14069 {
14070 dbug (1, dprintf ("[%06lx] %s,%d: Select B protocol failed",
14071 UnMapId (Id), (char *)(FILE_), __LINE__));
14072 break;
14073 }
14074 if (plci->internal_command)
14075 return;
14076 if (plci->tel == ADV_VOICE)
14077 {
14078 esc_chi[0] = 0x02;
14079 esc_chi[1] = 0x18;
14080 esc_chi[2] = plci->b_channel;
14081 SetVoiceChannel (plci->adapter->AdvCodecPLCI, esc_chi, plci->adapter);
14082 }
14083 break;
14084 }
14085 sendf (plci->appl, _SELECT_B_REQ | CONFIRM, Id, plci->number, "w", Info);
14086}
14087
14088
14089static void fax_connect_ack_command (dword Id, PLCI *plci, byte Rc)
14090{
14091 word Info;
14092 word internal_command;
14093
14094 dbug (1, dprintf ("[%06lx] %s,%d: fax_connect_ack_command %02x %04x",
14095 UnMapId (Id), (char *)(FILE_), __LINE__, Rc, plci->internal_command));
14096
14097 Info = GOOD;
14098 internal_command = plci->internal_command;
14099 plci->internal_command = 0;
14100 switch (internal_command)
14101 {
14102 default:
14103 plci->command = 0;
14104 case FAX_CONNECT_ACK_COMMAND_1:
14105 if (plci_nl_busy (plci))
14106 {
14107 plci->internal_command = FAX_CONNECT_ACK_COMMAND_1;
14108 return;
14109 }
14110 plci->internal_command = FAX_CONNECT_ACK_COMMAND_2;
14111 plci->NData[0].P = plci->fax_connect_info_buffer;
14112 plci->NData[0].PLength = plci->fax_connect_info_length;
14113 plci->NL.X = plci->NData;
14114 plci->NL.ReqCh = 0;
14115 plci->NL.Req = plci->nl_req = (byte) N_CONNECT_ACK;
14116 plci->adapter->request (&plci->NL);
14117 return;
14118 case FAX_CONNECT_ACK_COMMAND_2:
14119 if ((Rc != OK) && (Rc != OK_FC))
14120 {
14121 dbug (1, dprintf ("[%06lx] %s,%d: FAX issue CONNECT ACK failed %02x",
14122 UnMapId (Id), (char *)(FILE_), __LINE__, Rc));
14123 break;
14124 }
14125 }
14126 if ((plci->ncpi_state & NCPI_VALID_CONNECT_B3_ACT)
14127 && !(plci->ncpi_state & NCPI_CONNECT_B3_ACT_SENT))
14128 {
14129 if (plci->B3_prot == 4)
14130 sendf(plci->appl,_CONNECT_B3_ACTIVE_I,Id,0,"s","");
14131 else
14132 sendf(plci->appl,_CONNECT_B3_ACTIVE_I,Id,0,"S",plci->ncpi_buffer);
14133 plci->ncpi_state |= NCPI_CONNECT_B3_ACT_SENT;
14134 }
14135}
14136
14137
14138static void fax_edata_ack_command (dword Id, PLCI *plci, byte Rc)
14139{
14140 word Info;
14141 word internal_command;
14142
14143 dbug (1, dprintf ("[%06lx] %s,%d: fax_edata_ack_command %02x %04x",
14144 UnMapId (Id), (char *)(FILE_), __LINE__, Rc, plci->internal_command));
14145
14146 Info = GOOD;
14147 internal_command = plci->internal_command;
14148 plci->internal_command = 0;
14149 switch (internal_command)
14150 {
14151 default:
14152 plci->command = 0;
14153 case FAX_EDATA_ACK_COMMAND_1:
14154 if (plci_nl_busy (plci))
14155 {
14156 plci->internal_command = FAX_EDATA_ACK_COMMAND_1;
14157 return;
14158 }
14159 plci->internal_command = FAX_EDATA_ACK_COMMAND_2;
14160 plci->NData[0].P = plci->fax_connect_info_buffer;
14161 plci->NData[0].PLength = plci->fax_edata_ack_length;
14162 plci->NL.X = plci->NData;
14163 plci->NL.ReqCh = 0;
14164 plci->NL.Req = plci->nl_req = (byte) N_EDATA;
14165 plci->adapter->request (&plci->NL);
14166 return;
14167 case FAX_EDATA_ACK_COMMAND_2:
14168 if ((Rc != OK) && (Rc != OK_FC))
14169 {
14170 dbug (1, dprintf ("[%06lx] %s,%d: FAX issue EDATA ACK failed %02x",
14171 UnMapId (Id), (char *)(FILE_), __LINE__, Rc));
14172 break;
14173 }
14174 }
14175}
14176
14177
14178static void fax_connect_info_command (dword Id, PLCI *plci, byte Rc)
14179{
14180 word Info;
14181 word internal_command;
14182
14183 dbug (1, dprintf ("[%06lx] %s,%d: fax_connect_info_command %02x %04x",
14184 UnMapId (Id), (char *)(FILE_), __LINE__, Rc, plci->internal_command));
14185
14186 Info = GOOD;
14187 internal_command = plci->internal_command;
14188 plci->internal_command = 0;
14189 switch (internal_command)
14190 {
14191 default:
14192 plci->command = 0;
14193 case FAX_CONNECT_INFO_COMMAND_1:
14194 if (plci_nl_busy (plci))
14195 {
14196 plci->internal_command = FAX_CONNECT_INFO_COMMAND_1;
14197 return;
14198 }
14199 plci->internal_command = FAX_CONNECT_INFO_COMMAND_2;
14200 plci->NData[0].P = plci->fax_connect_info_buffer;
14201 plci->NData[0].PLength = plci->fax_connect_info_length;
14202 plci->NL.X = plci->NData;
14203 plci->NL.ReqCh = 0;
14204 plci->NL.Req = plci->nl_req = (byte) N_EDATA;
14205 plci->adapter->request (&plci->NL);
14206 return;
14207 case FAX_CONNECT_INFO_COMMAND_2:
14208 if ((Rc != OK) && (Rc != OK_FC))
14209 {
14210 dbug (1, dprintf ("[%06lx] %s,%d: FAX setting connect info failed %02x",
14211 UnMapId (Id), (char *)(FILE_), __LINE__, Rc));
14212 Info = _WRONG_STATE;
14213 break;
14214 }
14215 if (plci_nl_busy (plci))
14216 {
14217 plci->internal_command = FAX_CONNECT_INFO_COMMAND_2;
14218 return;
14219 }
14220 plci->command = _CONNECT_B3_R;
14221 nl_req_ncci (plci, N_CONNECT, 0);
14222 send_req (plci);
14223 return;
14224 }
14225 sendf (plci->appl, _CONNECT_B3_R | CONFIRM, Id, plci->number, "w", Info);
14226}
14227
14228
14229static void fax_adjust_b23_command (dword Id, PLCI *plci, byte Rc)
14230{
14231 word Info;
14232 word internal_command;
14233
14234 dbug (1, dprintf ("[%06lx] %s,%d: fax_adjust_b23_command %02x %04x",
14235 UnMapId (Id), (char *)(FILE_), __LINE__, Rc, plci->internal_command));
14236
14237 Info = GOOD;
14238 internal_command = plci->internal_command;
14239 plci->internal_command = 0;
14240 switch (internal_command)
14241 {
14242 default:
14243 plci->command = 0;
14244 plci->adjust_b_parms_msg = NULL;
14245 plci->adjust_b_facilities = plci->B1_facilities;
14246 plci->adjust_b_command = FAX_ADJUST_B23_COMMAND_1;
14247 plci->adjust_b_ncci = (word)(Id >> 16);
14248 plci->adjust_b_mode = ADJUST_B_MODE_REMOVE_L23 | ADJUST_B_MODE_ASSIGN_L23;
14249 plci->adjust_b_state = ADJUST_B_START;
14250 dbug (1, dprintf ("[%06lx] %s,%d: FAX adjust B23...",
14251 UnMapId (Id), (char *)(FILE_), __LINE__));
14252 case FAX_ADJUST_B23_COMMAND_1:
14253 Info = adjust_b_process (Id, plci, Rc);
14254 if (Info != GOOD)
14255 {
14256 dbug (1, dprintf ("[%06lx] %s,%d: FAX adjust failed",
14257 UnMapId (Id), (char *)(FILE_), __LINE__));
14258 break;
14259 }
14260 if (plci->internal_command)
14261 return;
14262 case FAX_ADJUST_B23_COMMAND_2:
14263 if (plci_nl_busy (plci))
14264 {
14265 plci->internal_command = FAX_ADJUST_B23_COMMAND_2;
14266 return;
14267 }
14268 plci->command = _CONNECT_B3_R;
14269 nl_req_ncci (plci, N_CONNECT, 0);
14270 send_req (plci);
14271 return;
14272 }
14273 sendf (plci->appl, _CONNECT_B3_R | CONFIRM, Id, plci->number, "w", Info);
14274}
14275
14276
14277static void fax_disconnect_command (dword Id, PLCI *plci, byte Rc)
14278{
14279 word internal_command;
14280
14281 dbug (1, dprintf ("[%06lx] %s,%d: fax_disconnect_command %02x %04x",
14282 UnMapId (Id), (char *)(FILE_), __LINE__, Rc, plci->internal_command));
14283
14284 internal_command = plci->internal_command;
14285 plci->internal_command = 0;
14286 switch (internal_command)
14287 {
14288 default:
14289 plci->command = 0;
14290 plci->internal_command = FAX_DISCONNECT_COMMAND_1;
14291 return;
14292 case FAX_DISCONNECT_COMMAND_1:
14293 case FAX_DISCONNECT_COMMAND_2:
14294 case FAX_DISCONNECT_COMMAND_3:
14295 if ((Rc != OK) && (Rc != OK_FC) && (Rc != 0))
14296 {
14297 dbug (1, dprintf ("[%06lx] %s,%d: FAX disconnect EDATA failed %02x",
14298 UnMapId (Id), (char *)(FILE_), __LINE__, Rc));
14299 break;
14300 }
14301 if (Rc == OK)
14302 {
14303 if ((internal_command == FAX_DISCONNECT_COMMAND_1)
14304 || (internal_command == FAX_DISCONNECT_COMMAND_2))
14305 {
14306 plci->internal_command = FAX_DISCONNECT_COMMAND_2;
14307 }
14308 }
14309 else if (Rc == 0)
14310 {
14311 if (internal_command == FAX_DISCONNECT_COMMAND_1)
14312 plci->internal_command = FAX_DISCONNECT_COMMAND_3;
14313 }
14314 return;
14315 }
14316}
14317
14318
14319
14320static void rtp_connect_b3_req_command (dword Id, PLCI *plci, byte Rc)
14321{
14322 word Info;
14323 word internal_command;
14324
14325 dbug (1, dprintf ("[%06lx] %s,%d: rtp_connect_b3_req_command %02x %04x",
14326 UnMapId (Id), (char *)(FILE_), __LINE__, Rc, plci->internal_command));
14327
14328 Info = GOOD;
14329 internal_command = plci->internal_command;
14330 plci->internal_command = 0;
14331 switch (internal_command)
14332 {
14333 default:
14334 plci->command = 0;
14335 case RTP_CONNECT_B3_REQ_COMMAND_1:
14336 if (plci_nl_busy (plci))
14337 {
14338 plci->internal_command = RTP_CONNECT_B3_REQ_COMMAND_1;
14339 return;
14340 }
14341 plci->internal_command = RTP_CONNECT_B3_REQ_COMMAND_2;
14342 nl_req_ncci (plci, N_CONNECT, 0);
14343 send_req (plci);
14344 return;
14345 case RTP_CONNECT_B3_REQ_COMMAND_2:
14346 if ((Rc != OK) && (Rc != OK_FC))
14347 {
14348 dbug (1, dprintf ("[%06lx] %s,%d: RTP setting connect info failed %02x",
14349 UnMapId (Id), (char *)(FILE_), __LINE__, Rc));
14350 Info = _WRONG_STATE;
14351 break;
14352 }
14353 if (plci_nl_busy (plci))
14354 {
14355 plci->internal_command = RTP_CONNECT_B3_REQ_COMMAND_2;
14356 return;
14357 }
14358 plci->internal_command = RTP_CONNECT_B3_REQ_COMMAND_3;
14359 plci->NData[0].PLength = plci->internal_req_buffer[0];
14360 plci->NData[0].P = plci->internal_req_buffer + 1;
14361 plci->NL.X = plci->NData;
14362 plci->NL.ReqCh = 0;
14363 plci->NL.Req = plci->nl_req = (byte) N_UDATA;
14364 plci->adapter->request (&plci->NL);
14365 break;
14366 case RTP_CONNECT_B3_REQ_COMMAND_3:
14367 return;
14368 }
14369 sendf (plci->appl, _CONNECT_B3_R | CONFIRM, Id, plci->number, "w", Info);
14370}
14371
14372
14373static void rtp_connect_b3_res_command (dword Id, PLCI *plci, byte Rc)
14374{
14375 word Info;
14376 word internal_command;
14377
14378 dbug (1, dprintf ("[%06lx] %s,%d: rtp_connect_b3_res_command %02x %04x",
14379 UnMapId (Id), (char *)(FILE_), __LINE__, Rc, plci->internal_command));
14380
14381 Info = GOOD;
14382 internal_command = plci->internal_command;
14383 plci->internal_command = 0;
14384 switch (internal_command)
14385 {
14386 default:
14387 plci->command = 0;
14388 case RTP_CONNECT_B3_RES_COMMAND_1:
14389 if (plci_nl_busy (plci))
14390 {
14391 plci->internal_command = RTP_CONNECT_B3_RES_COMMAND_1;
14392 return;
14393 }
14394 plci->internal_command = RTP_CONNECT_B3_RES_COMMAND_2;
14395 nl_req_ncci (plci, N_CONNECT_ACK, (byte)(Id >> 16));
14396 send_req (plci);
14397 return;
14398 case RTP_CONNECT_B3_RES_COMMAND_2:
14399 if ((Rc != OK) && (Rc != OK_FC))
14400 {
14401 dbug (1, dprintf ("[%06lx] %s,%d: RTP setting connect resp info failed %02x",
14402 UnMapId (Id), (char *)(FILE_), __LINE__, Rc));
14403 Info = _WRONG_STATE;
14404 break;
14405 }
14406 if (plci_nl_busy (plci))
14407 {
14408 plci->internal_command = RTP_CONNECT_B3_RES_COMMAND_2;
14409 return;
14410 }
14411 sendf (plci->appl, _CONNECT_B3_ACTIVE_I, Id, 0, "s", "");
14412 plci->internal_command = RTP_CONNECT_B3_RES_COMMAND_3;
14413 plci->NData[0].PLength = plci->internal_req_buffer[0];
14414 plci->NData[0].P = plci->internal_req_buffer + 1;
14415 plci->NL.X = plci->NData;
14416 plci->NL.ReqCh = 0;
14417 plci->NL.Req = plci->nl_req = (byte) N_UDATA;
14418 plci->adapter->request (&plci->NL);
14419 return;
14420 case RTP_CONNECT_B3_RES_COMMAND_3:
14421 return;
14422 }
14423}
14424
14425
14426
14427static void hold_save_command (dword Id, PLCI *plci, byte Rc)
14428{
14429 byte SS_Ind[] = "\x05\x02\x00\x02\x00\x00"; /* Hold_Ind struct*/
14430 word Info;
14431 word internal_command;
14432
14433 dbug (1, dprintf ("[%06lx] %s,%d: hold_save_command %02x %04x",
14434 UnMapId (Id), (char *)(FILE_), __LINE__, Rc, plci->internal_command));
14435
14436 Info = GOOD;
14437 internal_command = plci->internal_command;
14438 plci->internal_command = 0;
14439 switch (internal_command)
14440 {
14441 default:
14442 if (!plci->NL.Id)
14443 break;
14444 plci->command = 0;
14445 plci->adjust_b_parms_msg = NULL;
14446 plci->adjust_b_facilities = plci->B1_facilities;
14447 plci->adjust_b_command = HOLD_SAVE_COMMAND_1;
14448 plci->adjust_b_ncci = (word)(Id >> 16);
14449 plci->adjust_b_mode = ADJUST_B_MODE_SAVE | ADJUST_B_MODE_REMOVE_L23;
14450 plci->adjust_b_state = ADJUST_B_START;
14451 dbug (1, dprintf ("[%06lx] %s,%d: HOLD save...",
14452 UnMapId (Id), (char *)(FILE_), __LINE__));
14453 case HOLD_SAVE_COMMAND_1:
14454 Info = adjust_b_process (Id, plci, Rc);
14455 if (Info != GOOD)
14456 {
14457 dbug (1, dprintf ("[%06lx] %s,%d: HOLD save failed",
14458 UnMapId (Id), (char *)(FILE_), __LINE__));
14459 break;
14460 }
14461 if (plci->internal_command)
14462 return;
14463 }
14464 sendf (plci->appl, _FACILITY_I, Id & 0xffffL, 0, "ws", 3, SS_Ind);
14465}
14466
14467
14468static void retrieve_restore_command (dword Id, PLCI *plci, byte Rc)
14469{
14470 byte SS_Ind[] = "\x05\x03\x00\x02\x00\x00"; /* Retrieve_Ind struct*/
14471 word Info;
14472 word internal_command;
14473
14474 dbug (1, dprintf ("[%06lx] %s,%d: retrieve_restore_command %02x %04x",
14475 UnMapId (Id), (char *)(FILE_), __LINE__, Rc, plci->internal_command));
14476
14477 Info = GOOD;
14478 internal_command = plci->internal_command;
14479 plci->internal_command = 0;
14480 switch (internal_command)
14481 {
14482 default:
14483 plci->command = 0;
14484 plci->adjust_b_parms_msg = NULL;
14485 plci->adjust_b_facilities = plci->B1_facilities;
14486 plci->adjust_b_command = RETRIEVE_RESTORE_COMMAND_1;
14487 plci->adjust_b_ncci = (word)(Id >> 16);
14488 plci->adjust_b_mode = ADJUST_B_MODE_ASSIGN_L23 | ADJUST_B_MODE_USER_CONNECT | ADJUST_B_MODE_RESTORE;
14489 plci->adjust_b_state = ADJUST_B_START;
14490 dbug (1, dprintf ("[%06lx] %s,%d: RETRIEVE restore...",
14491 UnMapId (Id), (char *)(FILE_), __LINE__));
14492 case RETRIEVE_RESTORE_COMMAND_1:
14493 Info = adjust_b_process (Id, plci, Rc);
14494 if (Info != GOOD)
14495 {
14496 dbug (1, dprintf ("[%06lx] %s,%d: RETRIEVE restore failed",
14497 UnMapId (Id), (char *)(FILE_), __LINE__));
14498 break;
14499 }
14500 if (plci->internal_command)
14501 return;
14502 }
14503 sendf (plci->appl, _FACILITY_I, Id & 0xffffL, 0, "ws", 3, SS_Ind);
14504}
14505
14506
14507static void init_b1_config (PLCI *plci)
14508{
14509
14510 dbug (1, dprintf ("[%06lx] %s,%d: init_b1_config",
14511 (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
14512 (char *)(FILE_), __LINE__));
14513
14514 plci->B1_resource = 0;
14515 plci->B1_facilities = 0;
14516
14517 plci->li_bchannel_id = 0;
14518 mixer_clear_config (plci);
14519
14520
14521 ec_clear_config (plci);
14522
14523
14524 dtmf_rec_clear_config (plci);
14525 dtmf_send_clear_config (plci);
14526 dtmf_parameter_clear_config (plci);
14527
14528 adv_voice_clear_config (plci);
14529 adjust_b_clear (plci);
14530}
14531
14532
14533static void clear_b1_config (PLCI *plci)
14534{
14535
14536 dbug (1, dprintf ("[%06lx] %s,%d: clear_b1_config",
14537 (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
14538 (char *)(FILE_), __LINE__));
14539
14540 adv_voice_clear_config (plci);
14541 adjust_b_clear (plci);
14542
14543 ec_clear_config (plci);
14544
14545
14546 dtmf_rec_clear_config (plci);
14547 dtmf_send_clear_config (plci);
14548 dtmf_parameter_clear_config (plci);
14549
14550
14551 if ((plci->li_bchannel_id != 0)
14552 && (li_config_table[plci->adapter->li_base + (plci->li_bchannel_id - 1)].plci == plci))
14553 {
14554 mixer_clear_config (plci);
14555 li_config_table[plci->adapter->li_base + (plci->li_bchannel_id - 1)].plci = NULL;
14556 plci->li_bchannel_id = 0;
14557 }
14558
14559 plci->B1_resource = 0;
14560 plci->B1_facilities = 0;
14561}
14562
14563
14564/* -----------------------------------------------------------------
14565 XON protocol local helpers
14566 ----------------------------------------------------------------- */
14567static void channel_flow_control_remove (PLCI * plci) {
14568 DIVA_CAPI_ADAPTER * a = plci->adapter;
14569 word i;
14570 for(i=1;i<MAX_NL_CHANNEL+1;i++) {
14571 if (a->ch_flow_plci[i] == plci->Id) {
14572 a->ch_flow_plci[i] = 0;
14573 a->ch_flow_control[i] = 0;
14574 }
14575 }
14576}
14577
14578static void channel_x_on (PLCI * plci, byte ch) {
14579 DIVA_CAPI_ADAPTER * a = plci->adapter;
14580 if (a->ch_flow_control[ch] & N_XON_SENT) {
14581 a->ch_flow_control[ch] &= ~N_XON_SENT;
14582 }
14583}
14584
14585static void channel_x_off (PLCI * plci, byte ch, byte flag) {
14586 DIVA_CAPI_ADAPTER * a = plci->adapter;
14587 if ((a->ch_flow_control[ch] & N_RX_FLOW_CONTROL_MASK) == 0) {
14588 a->ch_flow_control[ch] |= (N_CH_XOFF | flag);
14589 a->ch_flow_plci[ch] = plci->Id;
14590 a->ch_flow_control_pending++;
14591 }
14592}
14593
14594static void channel_request_xon (PLCI * plci, byte ch) {
14595 DIVA_CAPI_ADAPTER * a = plci->adapter;
14596
14597 if (a->ch_flow_control[ch] & N_CH_XOFF) {
14598 a->ch_flow_control[ch] |= N_XON_REQ;
14599 a->ch_flow_control[ch] &= ~N_CH_XOFF;
14600 a->ch_flow_control[ch] &= ~N_XON_CONNECT_IND;
14601 }
14602}
14603
14604static void channel_xmit_extended_xon (PLCI * plci) {
14605 DIVA_CAPI_ADAPTER * a;
14606 int max_ch = sizeof(a->ch_flow_control)/sizeof(a->ch_flow_control[0]);
14607 int i, one_requested = 0;
14608
14609 if ((!plci) || (!plci->Id) || ((a = plci->adapter) == 0)) {
14610 return;
14611 }
14612
14613 for (i = 0; i < max_ch; i++) {
14614 if ((a->ch_flow_control[i] & N_CH_XOFF) &&
14615 (a->ch_flow_control[i] & N_XON_CONNECT_IND) &&
14616 (plci->Id == a->ch_flow_plci[i])) {
14617 channel_request_xon (plci, (byte)i);
14618 one_requested = 1;
14619 }
14620 }
14621
14622 if (one_requested) {
14623 channel_xmit_xon (plci);
14624 }
14625}
14626
14627/*
14628 Try to xmit next X_ON
14629 */
14630static int find_channel_with_pending_x_on (DIVA_CAPI_ADAPTER * a, PLCI * plci) {
14631 int max_ch = sizeof(a->ch_flow_control)/sizeof(a->ch_flow_control[0]);
14632 int i;
14633
14634 if (!(plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_XONOFF_FLOW_CONTROL)) {
14635 return (0);
14636 }
14637
14638 if (a->last_flow_control_ch >= max_ch) {
14639 a->last_flow_control_ch = 1;
14640 }
14641 for (i=a->last_flow_control_ch; i < max_ch; i++) {
14642 if ((a->ch_flow_control[i] & N_XON_REQ) &&
14643 (plci->Id == a->ch_flow_plci[i])) {
14644 a->last_flow_control_ch = i+1;
14645 return (i);
14646 }
14647 }
14648
14649 for (i = 1; i < a->last_flow_control_ch; i++) {
14650 if ((a->ch_flow_control[i] & N_XON_REQ) &&
14651 (plci->Id == a->ch_flow_plci[i])) {
14652 a->last_flow_control_ch = i+1;
14653 return (i);
14654 }
14655 }
14656
14657 return (0);
14658}
14659
14660static void channel_xmit_xon (PLCI * plci) {
14661 DIVA_CAPI_ADAPTER * a = plci->adapter;
14662 byte ch;
14663
14664 if (plci->nl_req || !plci->NL.Id || plci->nl_remove_id) {
14665 return;
14666 }
14667 if ((ch = (byte)find_channel_with_pending_x_on (a, plci)) == 0) {
14668 return;
14669 }
14670 a->ch_flow_control[ch] &= ~N_XON_REQ;
14671 a->ch_flow_control[ch] |= N_XON_SENT;
14672
14673 plci->NL.Req = plci->nl_req = (byte)N_XON;
14674 plci->NL.ReqCh = ch;
14675 plci->NL.X = plci->NData;
14676 plci->NL.XNum = 1;
14677 plci->NData[0].P = &plci->RBuffer[0];
14678 plci->NData[0].PLength = 0;
14679
14680 plci->adapter->request(&plci->NL);
14681}
14682
14683static int channel_can_xon (PLCI * plci, byte ch) {
14684 APPL * APPLptr;
14685 DIVA_CAPI_ADAPTER * a;
14686 word NCCIcode;
14687 dword count;
14688 word Num;
14689 word i;
14690
14691 APPLptr = plci->appl;
14692 a = plci->adapter;
14693
14694 if (!APPLptr)
14695 return (0);
14696
14697 NCCIcode = a->ch_ncci[ch] | (((word) a->Id) << 8);
14698
14699 /* count all buffers within the Application pool */
14700 /* belonging to the same NCCI. XON if a first is */
14701 /* used. */
14702 count = 0;
14703 Num = 0xffff;
14704 for(i=0; i<APPLptr->MaxBuffer; i++) {
14705 if(NCCIcode==APPLptr->DataNCCI[i]) count++;
14706 if(!APPLptr->DataNCCI[i] && Num==0xffff) Num = i;
14707 }
14708 if ((count > 2) || (Num == 0xffff)) {
14709 return (0);
14710 }
14711 return (1);
14712}
14713
14714
14715/*------------------------------------------------------------------*/
14716
14717static word CPN_filter_ok(byte *cpn,DIVA_CAPI_ADAPTER * a,word offset)
14718{
14719 return 1;
14720}
14721
14722
14723
14724/**********************************************************************************/
14725/* function groups the listening applications according to the CIP mask and the */
14726/* Info_Mask. Each group gets just one Connect_Ind. Some application manufacturer */
14727/* are not multi-instance capable, so they start e.g. 30 applications what causes */
14728/* big problems on application level (one call, 30 Connect_Ind, ect). The */
14729/* function must be enabled by setting "a->group_optimization_enabled" from the */
14730/* OS specific part (per adapter). */
14731/**********************************************************************************/
14732static void group_optimization(DIVA_CAPI_ADAPTER * a, PLCI * plci)
14733{
14734 word i,j,k,busy,group_found;
14735 dword info_mask_group[MAX_CIP_TYPES];
14736 dword cip_mask_group[MAX_CIP_TYPES];
14737 word appl_number_group_type[MAX_APPL];
14738 PLCI *auxplci;
14739
14740 set_group_ind_mask (plci); /* all APPLs within this inc. call are allowed to dial in */
14741
14742 if(!a->group_optimization_enabled)
14743 {
14744 dbug(1,dprintf("No group optimization"));
14745 return;
14746 }
14747
14748 dbug(1,dprintf("Group optimization = 0x%x...", a->group_optimization_enabled));
14749
14750 for(i=0;i<MAX_CIP_TYPES;i++)
14751 {
14752 info_mask_group[i] = 0;
14753 cip_mask_group [i] = 0;
14754 }
14755 for(i=0;i<MAX_APPL;i++)
14756 {
14757 appl_number_group_type[i] = 0;
14758 }
14759 for(i=0; i<max_appl; i++) /* check if any multi instance capable application is present */
14760 { /* group_optimization set to 1 means not to optimize multi-instance capable applications (default) */
14761 if(application[i].Id && (application[i].MaxNCCI) > 1 && (a->CIP_Mask[i]) && (a->group_optimization_enabled ==1) )
14762 {
14763 dbug(1,dprintf("Multi-Instance capable, no optimization required"));
14764 return; /* allow good application unfiltered access */
14765 }
14766 }
14767 for(i=0; i<max_appl; i++) /* Build CIP Groups */
14768 {
14769 if(application[i].Id && a->CIP_Mask[i] )
14770 {
14771 for(k=0,busy=FALSE; k<a->max_plci; k++)
14772 {
14773 if(a->plci[k].Id)
14774 {
14775 auxplci = &a->plci[k];
14776 if(auxplci->appl == &application[i]) /* application has a busy PLCI */
14777 {
14778 busy = TRUE;
14779 dbug(1,dprintf("Appl 0x%x is busy",i+1));
14780 }
14781 else if(test_c_ind_mask_bit (auxplci, i)) /* application has an incoming call pending */
14782 {
14783 busy = TRUE;
14784 dbug(1,dprintf("Appl 0x%x has inc. call pending",i+1));
14785 }
14786 }
14787 }
14788
14789 for(j=0,group_found=0; j<=(MAX_CIP_TYPES) && !busy &&!group_found; j++) /* build groups with free applications only */
14790 {
14791 if(j==MAX_CIP_TYPES) /* all groups are in use but group still not found */
14792 { /* the MAX_CIP_TYPES group enables all calls because of field overflow */
14793 appl_number_group_type[i] = MAX_CIP_TYPES;
14794 group_found=TRUE;
14795 dbug(1,dprintf("Field overflow appl 0x%x",i+1));
14796 }
14797 else if( (info_mask_group[j]==a->CIP_Mask[i]) && (cip_mask_group[j]==a->Info_Mask[i]) )
14798 { /* is group already present ? */
14799 appl_number_group_type[i] = j|0x80; /* store the group number for each application */
14800 group_found=TRUE;
14801 dbug(1,dprintf("Group 0x%x found with appl 0x%x, CIP=0x%lx",appl_number_group_type[i],i+1,info_mask_group[j]));
14802 }
14803 else if(!info_mask_group[j])
14804 { /* establish a new group */
14805 appl_number_group_type[i] = j|0x80; /* store the group number for each application */
14806 info_mask_group[j] = a->CIP_Mask[i]; /* store the new CIP mask for the new group */
14807 cip_mask_group[j] = a->Info_Mask[i]; /* store the new Info_Mask for this new group */
14808 group_found=TRUE;
14809 dbug(1,dprintf("New Group 0x%x established with appl 0x%x, CIP=0x%lx",appl_number_group_type[i],i+1,info_mask_group[j]));
14810 }
14811 }
14812 }
14813 }
14814
14815 for(i=0; i<max_appl; i++) /* Build group_optimization_mask_table */
14816 {
14817 if(appl_number_group_type[i]) /* application is free, has listens and is member of a group */
14818 {
14819 if(appl_number_group_type[i] == MAX_CIP_TYPES)
14820 {
14821 dbug(1,dprintf("OverflowGroup 0x%x, valid appl = 0x%x, call enabled",appl_number_group_type[i],i+1));
14822 }
14823 else
14824 {
14825 dbug(1,dprintf("Group 0x%x, valid appl = 0x%x",appl_number_group_type[i],i+1));
14826 for(j=i+1; j<max_appl; j++) /* search other group members and mark them as busy */
14827 {
14828 if(appl_number_group_type[i] == appl_number_group_type[j])
14829 {
14830 dbug(1,dprintf("Appl 0x%x is member of group 0x%x, no call",j+1,appl_number_group_type[j]));
14831 clear_group_ind_mask_bit (plci, j); /* disable call on other group members */
14832 appl_number_group_type[j] = 0; /* remove disabled group member from group list */
14833 }
14834 }
14835 }
14836 }
14837 else /* application should not get a call */
14838 {
14839 clear_group_ind_mask_bit (plci, i);
14840 }
14841 }
14842
14843}
14844
14845
14846
14847/* OS notifies the driver about a application Capi_Register */
14848word CapiRegister(word id)
14849{
14850 word i,j,appls_found;
14851
14852 PLCI *plci;
14853 DIVA_CAPI_ADAPTER *a;
14854
14855 for(i=0,appls_found=0; i<max_appl; i++)
14856 {
14857 if( application[i].Id && (application[i].Id!=id) )
14858 {
14859 appls_found++; /* an application has been found */
14860 }
14861 }
14862
14863 if(appls_found) return TRUE;
14864 for(i=0; i<max_adapter; i++) /* scan all adapters... */
14865 {
14866 a = &adapter[i];
14867 if(a->request)
14868 {
14869 if(a->flag_dynamic_l1_down) /* remove adapter from L1 tristate (Huntgroup) */
14870 {
14871 if(!appls_found) /* first application does a capi register */
14872 {
14873 if((j=get_plci(a))) /* activate L1 of all adapters */
14874 {
14875 plci = &a->plci[j-1];
14876 plci->command = 0;
14877 add_p(plci,OAD,"\x01\xfd");
14878 add_p(plci,CAI,"\x01\x80");
14879 add_p(plci,UID,"\x06\x43\x61\x70\x69\x32\x30");
14880 add_p(plci,SHIFT|6,NULL);
14881 add_p(plci,SIN,"\x02\x00\x00");
14882 plci->internal_command = START_L1_SIG_ASSIGN_PEND;
14883 sig_req(plci,ASSIGN,DSIG_ID);
14884 add_p(plci,FTY,"\x02\xff\x07"); /* l1 start */
14885 sig_req(plci,SIG_CTRL,0);
14886 send_req(plci);
14887 }
14888 }
14889 }
14890 }
14891 }
14892 return FALSE;
14893}
14894
14895/*------------------------------------------------------------------*/
14896
14897/* Functions for virtual Switching e.g. Transfer by join, Conference */
14898
14899static void VSwitchReqInd(PLCI *plci, dword Id, byte **parms)
14900{
14901 word i;
14902 /* Format of vswitch_t:
14903 0 byte length
14904 1 byte VSWITCHIE
14905 2 byte VSWITCH_REQ/VSWITCH_IND
14906 3 byte reserved
14907 4 word VSwitchcommand
14908 6 word returnerror
14909 8... Params
14910 */
14911 if(!plci ||
14912 !plci->appl ||
14913 !plci->State ||
14914 plci->Sig.Ind==NCR_FACILITY
14915 )
14916 return;
14917
14918 for(i=0;i<MAX_MULTI_IE;i++)
14919 {
14920 if(!parms[i][0]) continue;
14921 if(parms[i][0]<7)
14922 {
14923 parms[i][0]=0; /* kill it */
14924 continue;
14925 }
14926 dbug(1,dprintf("VSwitchReqInd(%d)",parms[i][4]));
14927 switch(parms[i][4])
14928 {
14929 case VSJOIN:
14930 if(!plci->relatedPTYPLCI ||
14931 (plci->ptyState!=S_ECT && plci->relatedPTYPLCI->ptyState!=S_ECT))
14932 { /* Error */
14933 break;
14934 }
14935 /* remember all necessary informations */
14936 if(parms[i][0]!=11 || parms[i][8]!=3) /* Length Test */
14937 {
14938 break;
14939 }
14940 if(parms[i][2]==VSWITCH_IND && parms[i][9]==1)
14941 { /* first indication after ECT-Request on Consultation Call */
14942 plci->vswitchstate=parms[i][9];
14943 parms[i][9]=2; /* State */
14944 /* now ask first Call to join */
14945 }
14946 else if(parms[i][2]==VSWITCH_REQ && parms[i][9]==3)
14947 { /* Answer of VSWITCH_REQ from first Call */
14948 plci->vswitchstate=parms[i][9];
14949 /* tell consultation call to join
14950 and the protocol capabilities of the first call */
14951 }
14952 else
14953 { /* Error */
14954 break;
14955 }
14956 plci->vsprot=parms[i][10]; /* protocol */
14957 plci->vsprotdialect=parms[i][11]; /* protocoldialect */
14958 /* send join request to related PLCI */
14959 parms[i][1]=VSWITCHIE;
14960 parms[i][2]=VSWITCH_REQ;
14961
14962 plci->relatedPTYPLCI->command = 0;
14963 plci->relatedPTYPLCI->internal_command = VSWITCH_REQ_PEND;
14964 add_p(plci->relatedPTYPLCI,ESC,&parms[i][0]);
14965 sig_req(plci->relatedPTYPLCI,VSWITCH_REQ,0);
14966 send_req(plci->relatedPTYPLCI);
14967 break;
14968 case VSTRANSPORT:
14969 default:
14970 if(plci->relatedPTYPLCI &&
14971 plci->vswitchstate==3 &&
14972 plci->relatedPTYPLCI->vswitchstate==3)
14973 {
14974 add_p(plci->relatedPTYPLCI,ESC,&parms[i][0]);
14975 sig_req(plci->relatedPTYPLCI,VSWITCH_REQ,0);
14976 send_req(plci->relatedPTYPLCI);
14977 }
14978 break;
14979 }
14980 parms[i][0]=0; /* kill it */
14981 }
14982}
14983
14984
14985/*------------------------------------------------------------------*/
14986
14987static int diva_get_dma_descriptor (PLCI *plci, dword *dma_magic) {
14988 ENTITY e;
14989 IDI_SYNC_REQ* pReq = (IDI_SYNC_REQ*)&e;
14990
14991 if (!(diva_xdi_extended_features & DIVA_CAPI_XDI_PROVIDES_RX_DMA)) {
14992 return (-1);
14993 }
14994
14995 pReq->xdi_dma_descriptor_operation.Req = 0;
14996 pReq->xdi_dma_descriptor_operation.Rc = IDI_SYNC_REQ_DMA_DESCRIPTOR_OPERATION;
14997
14998 pReq->xdi_dma_descriptor_operation.info.operation = IDI_SYNC_REQ_DMA_DESCRIPTOR_ALLOC;
14999 pReq->xdi_dma_descriptor_operation.info.descriptor_number = -1;
15000 pReq->xdi_dma_descriptor_operation.info.descriptor_address = NULL;
15001 pReq->xdi_dma_descriptor_operation.info.descriptor_magic = 0;
15002
15003 e.user[0] = plci->adapter->Id - 1;
15004 plci->adapter->request((ENTITY*)pReq);
15005
15006 if (!pReq->xdi_dma_descriptor_operation.info.operation &&
15007 (pReq->xdi_dma_descriptor_operation.info.descriptor_number >= 0) &&
15008 pReq->xdi_dma_descriptor_operation.info.descriptor_magic) {
15009 *dma_magic = pReq->xdi_dma_descriptor_operation.info.descriptor_magic;
15010 dbug(3,dprintf("dma_alloc, a:%d (%d-%08x)",
15011 plci->adapter->Id,
15012 pReq->xdi_dma_descriptor_operation.info.descriptor_number,
15013 *dma_magic));
15014 return (pReq->xdi_dma_descriptor_operation.info.descriptor_number);
15015 } else {
15016 dbug(1,dprintf("dma_alloc failed"));
15017 return (-1);
15018 }
15019}
15020
15021static void diva_free_dma_descriptor (PLCI *plci, int nr) {
15022 ENTITY e;
15023 IDI_SYNC_REQ* pReq = (IDI_SYNC_REQ*)&e;
15024
15025 if (nr < 0) {
15026 return;
15027 }
15028
15029 pReq->xdi_dma_descriptor_operation.Req = 0;
15030 pReq->xdi_dma_descriptor_operation.Rc = IDI_SYNC_REQ_DMA_DESCRIPTOR_OPERATION;
15031
15032 pReq->xdi_dma_descriptor_operation.info.operation = IDI_SYNC_REQ_DMA_DESCRIPTOR_FREE;
15033 pReq->xdi_dma_descriptor_operation.info.descriptor_number = nr;
15034 pReq->xdi_dma_descriptor_operation.info.descriptor_address = NULL;
15035 pReq->xdi_dma_descriptor_operation.info.descriptor_magic = 0;
15036
15037 e.user[0] = plci->adapter->Id - 1;
15038 plci->adapter->request((ENTITY*)pReq);
15039
15040 if (!pReq->xdi_dma_descriptor_operation.info.operation) {
15041 dbug(1,dprintf("dma_free(%d)", nr));
15042 } else {
15043 dbug(1,dprintf("dma_free failed (%d)", nr));
15044 }
15045}
15046
15047/*------------------------------------------------------------------*/
diff --git a/drivers/isdn/hardware/eicon/mi_pc.h b/drivers/isdn/hardware/eicon/mi_pc.h
new file mode 100644
index 000000000000..a861dac1f784
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/mi_pc.h
@@ -0,0 +1,204 @@
1
2/*
3 *
4 Copyright (c) Eicon Networks, 2002.
5 *
6 This source file is supplied for the use with
7 Eicon Networks range of DIVA Server Adapters.
8 *
9 Eicon File Revision : 2.1
10 *
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2, or (at your option)
14 any later version.
15 *
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
18 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 See the GNU General Public License for more details.
20 *
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26/*----------------------------------------------------------------------------
27// MAESTRA ISA PnP */
28#define BRI_MEMORY_BASE 0x1f700000
29#define BRI_MEMORY_SIZE 0x00100000 /* 1MB on the BRI */
30#define BRI_SHARED_RAM_SIZE 0x00010000 /* 64k shared RAM */
31#define BRI_RAY_TAYLOR_DSP_CODE_SIZE 0x00020000 /* max 128k DSP-Code (Ray Taylor's code) */
32#define BRI_ORG_MAX_DSP_CODE_SIZE 0x00050000 /* max 320k DSP-Code (Telindus) */
33#define BRI_V90D_MAX_DSP_CODE_SIZE 0x00060000 /* max 384k DSP-Code if V.90D included */
34#define BRI_CACHED_ADDR(x) (((x) & 0x1fffffffL) | 0x80000000L)
35#define BRI_UNCACHED_ADDR(x) (((x) & 0x1fffffffL) | 0xa0000000L)
36#define ADDR 4
37#define ADDRH 6
38#define DATA 0
39#define RESET 7
40#define DEFAULT_ADDRESS 0x240
41#define DEFAULT_IRQ 3
42#define M_PCI_ADDR 0x04 /* MAESTRA BRI PCI */
43#define M_PCI_ADDRH 0x0c /* MAESTRA BRI PCI */
44#define M_PCI_DATA 0x00 /* MAESTRA BRI PCI */
45#define M_PCI_RESET 0x10 /* MAESTRA BRI PCI */
46/*----------------------------------------------------------------------------
47// MAESTRA PRI PCI */
48#define MP_IRQ_RESET 0xc18 /* offset of isr in the CONFIG memory bar */
49#define MP_IRQ_RESET_VAL 0xfe /* value to clear an interrupt */
50#define MP_MEMORY_SIZE 0x00400000 /* 4MB on standard PRI */
51#define MP2_MEMORY_SIZE 0x00800000 /* 8MB on PRI Rev. 2 */
52#define MP_SHARED_RAM_OFFSET 0x00001000 /* offset of shared RAM base in the DRAM memory bar */
53#define MP_SHARED_RAM_SIZE 0x00010000 /* 64k shared RAM */
54#define MP_PROTOCOL_OFFSET (MP_SHARED_RAM_OFFSET + MP_SHARED_RAM_SIZE)
55#define MP_RAY_TAYLOR_DSP_CODE_SIZE 0x00040000 /* max 256k DSP-Code (Ray Taylor's code) */
56#define MP_ORG_MAX_DSP_CODE_SIZE 0x00060000 /* max 384k DSP-Code (Telindus) */
57#define MP_V90D_MAX_DSP_CODE_SIZE 0x00070000 /* max 448k DSP-Code if V.90D included) */
58#define MP_VOIP_MAX_DSP_CODE_SIZE 0x00090000 /* max 576k DSP-Code if voice over IP included */
59#define MP_CACHED_ADDR(x) (((x) & 0x1fffffffL) | 0x80000000L)
60#define MP_UNCACHED_ADDR(x) (((x) & 0x1fffffffL) | 0xa0000000L)
61#define MP_RESET 0x20 /* offset of RESET register in the DEVICES memory bar */
62/* RESET register bits */
63#define _MP_S2M_RESET 0x10 /* active lo */
64#define _MP_LED2 0x08 /* 1 = on */
65#define _MP_LED1 0x04 /* 1 = on */
66#define _MP_DSP_RESET 0x02 /* active lo */
67#define _MP_RISC_RESET 0x81 /* active hi, bit 7 for compatibility with old boards */
68/* CPU exception context structure in MP shared ram after trap */
69typedef struct mp_xcptcontext_s MP_XCPTC;
70struct mp_xcptcontext_s {
71 dword sr;
72 dword cr;
73 dword epc;
74 dword vaddr;
75 dword regs[32];
76 dword mdlo;
77 dword mdhi;
78 dword reseverd;
79 dword xclass;
80};
81/* boot interface structure for PRI */
82struct mp_load {
83 dword volatile cmd;
84 dword volatile addr;
85 dword volatile len;
86 dword volatile err;
87 dword volatile live;
88 dword volatile res1[0x1b];
89 dword volatile TrapId; /* has value 0x999999XX on a CPU trap */
90 dword volatile res2[0x03];
91 MP_XCPTC volatile xcpt; /* contains register dump */
92 dword volatile rest[((0x1020>>2)-6) - 0x1b - 1 - 0x03 - (sizeof(MP_XCPTC)>>2)];
93 dword volatile signature;
94 dword data[60000]; /* real interface description */
95};
96/*----------------------------------------------------------------------------*/
97/* SERVER 4BRI (Quattro PCI) */
98#define MQ_BOARD_REG_OFFSET 0x800000 /* PC relative On board registers offset */
99#define MQ_BREG_RISC 0x1200 /* RISC Reset ect */
100#define MQ_RISC_COLD_RESET_MASK 0x0001 /* RISC Cold reset */
101#define MQ_RISC_WARM_RESET_MASK 0x0002 /* RISC Warm reset */
102#define MQ_BREG_IRQ_TEST 0x0608 /* Interrupt request, no CPU interaction */
103#define MQ_IRQ_REQ_ON 0x1
104#define MQ_IRQ_REQ_OFF 0x0
105#define MQ_BOARD_DSP_OFFSET 0xa00000 /* PC relative On board DSP regs offset */
106#define MQ_DSP1_ADDR_OFFSET 0x0008 /* Addr register offset DSP 1 subboard 1 */
107#define MQ_DSP2_ADDR_OFFSET 0x0208 /* Addr register offset DSP 2 subboard 1 */
108#define MQ_DSP1_DATA_OFFSET 0x0000 /* Data register offset DSP 1 subboard 1 */
109#define MQ_DSP2_DATA_OFFSET 0x0200 /* Data register offset DSP 2 subboard 1 */
110#define MQ_DSP_JUNK_OFFSET 0x0400 /* DSP Data/Addr regs subboard offset */
111#define MQ_ISAC_DSP_RESET 0x0028 /* ISAC and DSP reset address offset */
112#define MQ_BOARD_ISAC_DSP_RESET 0x800028 /* ISAC and DSP reset address offset */
113#define MQ_INSTANCE_COUNT 4 /* 4BRI consists of four instances */
114#define MQ_MEMORY_SIZE 0x00400000 /* 4MB on standard 4BRI */
115#define MQ_CTRL_SIZE 0x00002000 /* 8K memory mapped registers */
116#define MQ_SHARED_RAM_SIZE 0x00010000 /* 64k shared RAM */
117#define MQ_ORG_MAX_DSP_CODE_SIZE 0x00050000 /* max 320k DSP-Code (Telindus) */
118#define MQ_V90D_MAX_DSP_CODE_SIZE 0x00060000 /* max 384K DSP-Code if V.90D included */
119#define MQ_VOIP_MAX_DSP_CODE_SIZE 0x00028000 /* max 4*160k = 640K DSP-Code if voice over IP included */
120#define MQ_CACHED_ADDR(x) (((x) & 0x1fffffffL) | 0x80000000L)
121#define MQ_UNCACHED_ADDR(x) (((x) & 0x1fffffffL) | 0xa0000000L)
122/*--------------------------------------------------------------------------------------------*/
123/* Additional definitions reflecting the different address map of the SERVER 4BRI V2 */
124#define MQ2_BREG_RISC 0x0200 /* RISC Reset ect */
125#define MQ2_BREG_IRQ_TEST 0x0400 /* Interrupt request, no CPU interaction */
126#define MQ2_BOARD_DSP_OFFSET 0x800000 /* PC relative On board DSP regs offset */
127#define MQ2_DSP1_DATA_OFFSET 0x1800 /* Data register offset DSP 1 subboard 1 */
128#define MQ2_DSP1_ADDR_OFFSET 0x1808 /* Addr register offset DSP 1 subboard 1 */
129#define MQ2_DSP2_DATA_OFFSET 0x1810 /* Data register offset DSP 2 subboard 1 */
130#define MQ2_DSP2_ADDR_OFFSET 0x1818 /* Addr register offset DSP 2 subboard 1 */
131#define MQ2_DSP_JUNK_OFFSET 0x1000 /* DSP Data/Addr regs subboard offset */
132#define MQ2_ISAC_DSP_RESET 0x0000 /* ISAC and DSP reset address offset */
133#define MQ2_BOARD_ISAC_DSP_RESET 0x800000 /* ISAC and DSP reset address offset */
134#define MQ2_IPACX_CONFIG 0x0300 /* IPACX Configuration TE(0)/NT(1) */
135#define MQ2_BOARD_IPACX_CONFIG 0x800300 /* "" */
136#define MQ2_MEMORY_SIZE 0x01000000 /* 16MB code/data memory */
137#define MQ2_CTRL_SIZE 0x00008000 /* 32K memory mapped registers */
138/*----------------------------------------------------------------------------*/
139/* SERVER BRI 2M/2F as derived from 4BRI V2 */
140#define BRI2_MEMORY_SIZE 0x00800000 /* 8MB code/data memory */
141#define BRI2_PROTOCOL_MEMORY_SIZE (MQ2_MEMORY_SIZE >> 2) /* same as one 4BRI Rev.2 task */
142#define BRI2_CTRL_SIZE 0x00008000 /* 32K memory mapped registers */
143#define M_INSTANCE_COUNT 1 /* BRI consists of one instance */
144/*
145 * Some useful constants for proper initialization of the GT6401x
146 */
147#define ID_REG 0x0000 /*Pci reg-contain the Dev&Ven ID of the card*/
148#define RAS0_BASEREG 0x0010 /*Ras0 register - contain the base addr Ras0*/
149#define RAS2_BASEREG 0x0014
150#define CS_BASEREG 0x0018
151#define BOOT_BASEREG 0x001c
152#define GTREGS_BASEREG 0x0024 /*GTRegsBase reg-contain the base addr where*/
153 /*the GT64010 internal regs where mapped */
154/*
155 * GT64010 internal registers
156 */
157 /* DRAM device coding */
158#define LOW_RAS0_DREG 0x0400 /*Ras0 low decode address*/
159#define HI_RAS0_DREG 0x0404 /*Ras0 high decode address*/
160#define LOW_RAS1_DREG 0x0408 /*Ras1 low decode address*/
161#define HI_RAS1_DREG 0x040c /*Ras1 high decode address*/
162#define LOW_RAS2_DREG 0x0410 /*Ras2 low decode address*/
163#define HI_RAS2_DREG 0x0414 /*Ras2 high decode address*/
164#define LOW_RAS3_DREG 0x0418 /*Ras3 low decode address*/
165#define HI_RAS3_DREG 0x041c /*Ras3 high decode address*/
166 /* I/O CS device coding */
167#define LOW_CS0_DREG 0x0420 /* CS0* low decode register */
168#define HI_CS0_DREG 0x0424 /* CS0* high decode register */
169#define LOW_CS1_DREG 0x0428 /* CS1* low decode register */
170#define HI_CS1_DREG 0x042c /* CS1* high decode register */
171#define LOW_CS2_DREG 0x0430 /* CS2* low decode register */
172#define HI_CS2_DREG 0x0434 /* CS2* high decode register */
173#define LOW_CS3_DREG 0x0438 /* CS3* low decode register */
174#define HI_CS3_DREG 0x043c /* CS3* high decode register */
175 /* Boot PROM device coding */
176#define LOW_BOOTCS_DREG 0x0440 /* Boot CS low decode register */
177#define HI_BOOTCS_DREG 0x0444 /* Boot CS High decode register */
178 /* DRAM group coding (for CPU) */
179#define LO_RAS10_GREG 0x0008 /*Ras1..0 group low decode address*/
180#define HI_RAS10_GREG 0x0010 /*Ras1..0 group high decode address*/
181#define LO_RAS32_GREG 0x0018 /*Ras3..2 group low decode address */
182#define HI_RAS32_GREG 0x0020 /*Ras3..2 group high decode address */
183 /* I/O CS group coding for (CPU) */
184#define LO_CS20_GREG 0x0028 /* CS2..0 group low decode register */
185#define HI_CS20_GREG 0x0030 /* CS2..0 group high decode register */
186#define LO_CS3B_GREG 0x0038 /* CS3 & PROM group low decode register */
187#define HI_CS3B_GREG 0x0040 /* CS3 & PROM group high decode register */
188 /* Galileo specific PCI config. */
189#define PCI_TIMEOUT_RET 0x0c04 /* Time Out and retry register */
190#define RAS10_BANKSIZE 0x0c08 /* RAS 1..0 group PCI bank size */
191#define RAS32_BANKSIZE 0x0c0c /* RAS 3..2 group PCI bank size */
192#define CS20_BANKSIZE 0x0c10 /* CS 2..0 group PCI bank size */
193#define CS3B_BANKSIZE 0x0c14 /* CS 3 & Boot group PCI bank size */
194#define DRAM_SIZE 0x0001 /*Dram size in mega bytes*/
195#define PROM_SIZE 0x08000 /*Prom size in bytes*/
196/*--------------------------------------------------------------------------*/
197#define OFFS_DIVA_INIT_TASK_COUNT 0x68
198#define OFFS_DSP_CODE_BASE_ADDR 0x6c
199#define OFFS_XLOG_BUF_ADDR 0x70
200#define OFFS_XLOG_COUNT_ADDR 0x74
201#define OFFS_XLOG_OUT_ADDR 0x78
202#define OFFS_PROTOCOL_END_ADDR 0x7c
203#define OFFS_PROTOCOL_ID_STRING 0x80
204/*--------------------------------------------------------------------------*/
diff --git a/drivers/isdn/hardware/eicon/mntfunc.c b/drivers/isdn/hardware/eicon/mntfunc.c
new file mode 100644
index 000000000000..a564b7560031
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/mntfunc.c
@@ -0,0 +1,370 @@
1/* $Id: mntfunc.c,v 1.19.6.4 2005/01/31 12:22:20 armin Exp $
2 *
3 * Driver for Eicon DIVA Server ISDN cards.
4 * Maint module
5 *
6 * Copyright 2000-2003 by Armin Schindler (mac@melware.de)
7 * Copyright 2000-2003 Cytronics & Melware (info@melware.de)
8 *
9 * This software may be used and distributed according to the terms
10 * of the GNU General Public License, incorporated herein by reference.
11 */
12
13
14#include "platform.h"
15#include "di_defs.h"
16#include "divasync.h"
17#include "debug_if.h"
18
19extern char *DRIVERRELEASE_MNT;
20
21#define DBG_MINIMUM (DL_LOG + DL_FTL + DL_ERR)
22#define DBG_DEFAULT (DBG_MINIMUM + DL_XLOG + DL_REG)
23
24extern void DIVA_DIDD_Read(void *, int);
25
26static dword notify_handle;
27static DESCRIPTOR DAdapter;
28static DESCRIPTOR MAdapter;
29static DESCRIPTOR MaintDescriptor =
30 { IDI_DIMAINT, 0, 0, (IDI_CALL) diva_maint_prtComp };
31
32extern int diva_os_copy_to_user(void *os_handle, void __user *dst,
33 const void *src, int length);
34extern int diva_os_copy_from_user(void *os_handle, void *dst,
35 const void __user *src, int length);
36
37static void no_printf(unsigned char *x, ...)
38{
39 /* dummy debug function */
40}
41
42#include "debuglib.c"
43
44/*
45 * DIDD callback function
46 */
47static void *didd_callback(void *context, DESCRIPTOR * adapter,
48 int removal)
49{
50 if (adapter->type == IDI_DADAPTER) {
51 DBG_ERR(("cb: Change in DAdapter ? Oops ?."));
52 } else if (adapter->type == IDI_DIMAINT) {
53 if (removal) {
54 DbgDeregister();
55 memset(&MAdapter, 0, sizeof(MAdapter));
56 dprintf = no_printf;
57 } else {
58 memcpy(&MAdapter, adapter, sizeof(MAdapter));
59 dprintf = (DIVA_DI_PRINTF) MAdapter.request;
60 DbgRegister("MAINT", DRIVERRELEASE_MNT, DBG_DEFAULT);
61 }
62 } else if ((adapter->type > 0) && (adapter->type < 16)) {
63 if (removal) {
64 diva_mnt_remove_xdi_adapter(adapter);
65 } else {
66 diva_mnt_add_xdi_adapter(adapter);
67 }
68 }
69 return (NULL);
70}
71
72/*
73 * connect to didd
74 */
75static int DIVA_INIT_FUNCTION connect_didd(void)
76{
77 int x = 0;
78 int dadapter = 0;
79 IDI_SYNC_REQ req;
80 DESCRIPTOR DIDD_Table[MAX_DESCRIPTORS];
81
82 DIVA_DIDD_Read(DIDD_Table, sizeof(DIDD_Table));
83
84 for (x = 0; x < MAX_DESCRIPTORS; x++) {
85 if (DIDD_Table[x].type == IDI_DADAPTER) { /* DADAPTER found */
86 dadapter = 1;
87 memcpy(&DAdapter, &DIDD_Table[x], sizeof(DAdapter));
88 req.didd_notify.e.Req = 0;
89 req.didd_notify.e.Rc =
90 IDI_SYNC_REQ_DIDD_REGISTER_ADAPTER_NOTIFY;
91 req.didd_notify.info.callback = (void *)didd_callback;
92 req.didd_notify.info.context = NULL;
93 DAdapter.request((ENTITY *) & req);
94 if (req.didd_notify.e.Rc != 0xff)
95 return (0);
96 notify_handle = req.didd_notify.info.handle;
97 /* Register MAINT (me) */
98 req.didd_add_adapter.e.Req = 0;
99 req.didd_add_adapter.e.Rc =
100 IDI_SYNC_REQ_DIDD_ADD_ADAPTER;
101 req.didd_add_adapter.info.descriptor =
102 (void *) &MaintDescriptor;
103 DAdapter.request((ENTITY *) & req);
104 if (req.didd_add_adapter.e.Rc != 0xff)
105 return (0);
106 } else if ((DIDD_Table[x].type > 0)
107 && (DIDD_Table[x].type < 16)) {
108 diva_mnt_add_xdi_adapter(&DIDD_Table[x]);
109 }
110 }
111 return (dadapter);
112}
113
114/*
115 * disconnect from didd
116 */
117static void DIVA_EXIT_FUNCTION disconnect_didd(void)
118{
119 IDI_SYNC_REQ req;
120
121 req.didd_notify.e.Req = 0;
122 req.didd_notify.e.Rc = IDI_SYNC_REQ_DIDD_REMOVE_ADAPTER_NOTIFY;
123 req.didd_notify.info.handle = notify_handle;
124 DAdapter.request((ENTITY *) & req);
125
126 req.didd_remove_adapter.e.Req = 0;
127 req.didd_remove_adapter.e.Rc = IDI_SYNC_REQ_DIDD_REMOVE_ADAPTER;
128 req.didd_remove_adapter.info.p_request =
129 (IDI_CALL) MaintDescriptor.request;
130 DAdapter.request((ENTITY *) & req);
131}
132
133/*
134 * read/write maint
135 */
136int maint_read_write(void __user *buf, int count)
137{
138 byte data[128];
139 dword cmd, id, mask;
140 int ret = 0;
141
142 if (count < (3 * sizeof(dword)))
143 return (-EFAULT);
144
145 if (diva_os_copy_from_user(NULL, (void *) &data[0],
146 buf, 3 * sizeof(dword))) {
147 return (-EFAULT);
148 }
149
150 cmd = *(dword *) & data[0]; /* command */
151 id = *(dword *) & data[4]; /* driver id */
152 mask = *(dword *) & data[8]; /* mask or size */
153
154 switch (cmd) {
155 case DITRACE_CMD_GET_DRIVER_INFO:
156 if ((ret = diva_get_driver_info(id, data, sizeof(data))) > 0) {
157 if ((count < ret) || diva_os_copy_to_user
158 (NULL, buf, (void *) &data[0], ret))
159 ret = -EFAULT;
160 } else {
161 ret = -EINVAL;
162 }
163 break;
164
165 case DITRACE_READ_DRIVER_DBG_MASK:
166 if ((ret = diva_get_driver_dbg_mask(id, (byte *) data)) > 0) {
167 if ((count < ret) || diva_os_copy_to_user
168 (NULL, buf, (void *) &data[0], ret))
169 ret = -EFAULT;
170 } else {
171 ret = -ENODEV;
172 }
173 break;
174
175 case DITRACE_WRITE_DRIVER_DBG_MASK:
176 if ((ret = diva_set_driver_dbg_mask(id, mask)) <= 0) {
177 ret = -ENODEV;
178 }
179 break;
180
181 /*
182 Filter commands will ignore the ID due to fact that filtering affects
183 the B- channel and Audio Tap trace levels only. Also MAINT driver will
184 select the right trace ID by itself
185 */
186 case DITRACE_WRITE_SELECTIVE_TRACE_FILTER:
187 if (!mask) {
188 ret = diva_set_trace_filter (1, "*");
189 } else if (mask < sizeof(data)) {
190 if (diva_os_copy_from_user(NULL, data, (char __user *)buf+12, mask)) {
191 ret = -EFAULT;
192 } else {
193 ret = diva_set_trace_filter ((int)mask, data);
194 }
195 } else {
196 ret = -EINVAL;
197 }
198 break;
199
200 case DITRACE_READ_SELECTIVE_TRACE_FILTER:
201 if ((ret = diva_get_trace_filter (sizeof(data), data)) > 0) {
202 if (diva_os_copy_to_user (NULL, buf, data, ret))
203 ret = -EFAULT;
204 } else {
205 ret = -ENODEV;
206 }
207 break;
208
209 case DITRACE_READ_TRACE_ENTRY:{
210 diva_os_spin_lock_magic_t old_irql;
211 word size;
212 diva_dbg_entry_head_t *pmsg;
213 byte *pbuf;
214
215 if (!(pbuf = diva_os_malloc(0, mask))) {
216 return (-ENOMEM);
217 }
218
219 for(;;) {
220 if (!(pmsg =
221 diva_maint_get_message(&size, &old_irql))) {
222 break;
223 }
224 if (size > mask) {
225 diva_maint_ack_message(0, &old_irql);
226 ret = -EINVAL;
227 break;
228 }
229 ret = size;
230 memcpy(pbuf, pmsg, size);
231 diva_maint_ack_message(1, &old_irql);
232 if ((count < size) ||
233 diva_os_copy_to_user (NULL, buf, (void *) pbuf, size))
234 ret = -EFAULT;
235 break;
236 }
237 diva_os_free(0, pbuf);
238 }
239 break;
240
241 case DITRACE_READ_TRACE_ENTRYS:{
242 diva_os_spin_lock_magic_t old_irql;
243 word size;
244 diva_dbg_entry_head_t *pmsg;
245 byte *pbuf = NULL;
246 int written = 0;
247
248 if (mask < 4096) {
249 ret = -EINVAL;
250 break;
251 }
252 if (!(pbuf = diva_os_malloc(0, mask))) {
253 return (-ENOMEM);
254 }
255
256 for (;;) {
257 if (!(pmsg =
258 diva_maint_get_message(&size, &old_irql))) {
259 break;
260 }
261 if ((size + 8) > mask) {
262 diva_maint_ack_message(0, &old_irql);
263 break;
264 }
265 /*
266 Write entry length
267 */
268 pbuf[written++] = (byte) size;
269 pbuf[written++] = (byte) (size >> 8);
270 pbuf[written++] = 0;
271 pbuf[written++] = 0;
272 /*
273 Write message
274 */
275 memcpy(&pbuf[written], pmsg, size);
276 diva_maint_ack_message(1, &old_irql);
277 written += size;
278 mask -= (size + 4);
279 }
280 pbuf[written++] = 0;
281 pbuf[written++] = 0;
282 pbuf[written++] = 0;
283 pbuf[written++] = 0;
284
285 if ((count < written) || diva_os_copy_to_user(NULL, buf, (void *) pbuf, written)) {
286 ret = -EFAULT;
287 } else {
288 ret = written;
289 }
290 diva_os_free(0, pbuf);
291 }
292 break;
293
294 default:
295 ret = -EINVAL;
296 }
297 return (ret);
298}
299
300/*
301 * init
302 */
303int DIVA_INIT_FUNCTION mntfunc_init(int *buffer_length, void **buffer,
304 unsigned long diva_dbg_mem)
305{
306 if (*buffer_length < 64) {
307 *buffer_length = 64;
308 }
309 if (*buffer_length > 512) {
310 *buffer_length = 512;
311 }
312 *buffer_length *= 1024;
313
314 if (diva_dbg_mem) {
315 *buffer = (void *) diva_dbg_mem;
316 } else {
317 while ((*buffer_length >= (64 * 1024))
318 &&
319 (!(*buffer = diva_os_malloc (0, *buffer_length)))) {
320 *buffer_length -= 1024;
321 }
322
323 if (!*buffer) {
324 DBG_ERR(("init: Can not alloc trace buffer"));
325 return (0);
326 }
327 }
328
329 if (diva_maint_init(*buffer, *buffer_length, (diva_dbg_mem == 0))) {
330 if (!diva_dbg_mem) {
331 diva_os_free (0, *buffer);
332 }
333 DBG_ERR(("init: maint init failed"));
334 return (0);
335 }
336
337 if (!connect_didd()) {
338 DBG_ERR(("init: failed to connect to DIDD."));
339 diva_maint_finit();
340 if (!diva_dbg_mem) {
341 diva_os_free (0, *buffer);
342 }
343 return (0);
344 }
345 return (1);
346}
347
348/*
349 * exit
350 */
351void DIVA_EXIT_FUNCTION mntfunc_finit(void)
352{
353 void *buffer;
354 int i = 100;
355
356 DbgDeregister();
357
358 while (diva_mnt_shutdown_xdi_adapters() && i--) {
359 diva_os_sleep(10);
360 }
361
362 disconnect_didd();
363
364 if ((buffer = diva_maint_finit())) {
365 diva_os_free (0, buffer);
366 }
367
368 memset(&MAdapter, 0, sizeof(MAdapter));
369 dprintf = no_printf;
370}
diff --git a/drivers/isdn/hardware/eicon/os_4bri.c b/drivers/isdn/hardware/eicon/os_4bri.c
new file mode 100644
index 000000000000..cccfabc1117d
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/os_4bri.c
@@ -0,0 +1,1131 @@
1/* $Id: os_4bri.c,v 1.28.4.4 2005/02/11 19:40:25 armin Exp $ */
2
3#include "platform.h"
4#include "debuglib.h"
5#include "cardtype.h"
6#include "pc.h"
7#include "pr_pc.h"
8#include "di_defs.h"
9#include "dsp_defs.h"
10#include "di.h"
11#include "io.h"
12
13#include "xdi_msg.h"
14#include "xdi_adapter.h"
15#include "os_4bri.h"
16#include "diva_pci.h"
17#include "mi_pc.h"
18#include "dsrv4bri.h"
19
20static void *diva_xdiLoadFileFile = NULL;
21static dword diva_xdiLoadFileLength = 0;
22
23/*
24** IMPORTS
25*/
26extern void prepare_qBri_functions(PISDN_ADAPTER IoAdapter);
27extern void prepare_qBri2_functions(PISDN_ADAPTER IoAdapter);
28extern void diva_xdi_display_adapter_features(int card);
29extern void diva_add_slave_adapter(diva_os_xdi_adapter_t * a);
30
31extern int qBri_FPGA_download(PISDN_ADAPTER IoAdapter);
32extern void start_qBri_hardware(PISDN_ADAPTER IoAdapter);
33
34extern int diva_card_read_xlog(diva_os_xdi_adapter_t * a);
35
36/*
37** LOCALS
38*/
39static unsigned long _4bri_bar_length[4] = {
40 0x100,
41 0x100, /* I/O */
42 MQ_MEMORY_SIZE,
43 0x2000
44};
45static unsigned long _4bri_v2_bar_length[4] = {
46 0x100,
47 0x100, /* I/O */
48 MQ2_MEMORY_SIZE,
49 0x10000
50};
51static unsigned long _4bri_v2_bri_bar_length[4] = {
52 0x100,
53 0x100, /* I/O */
54 BRI2_MEMORY_SIZE,
55 0x10000
56};
57
58
59static int diva_4bri_cleanup_adapter(diva_os_xdi_adapter_t * a);
60static int _4bri_get_serial_number(diva_os_xdi_adapter_t * a);
61static int diva_4bri_cmd_card_proc(struct _diva_os_xdi_adapter *a,
62 diva_xdi_um_cfg_cmd_t * cmd,
63 int length);
64static int diva_4bri_cleanup_slave_adapters(diva_os_xdi_adapter_t * a);
65static int diva_4bri_write_fpga_image(diva_os_xdi_adapter_t * a,
66 byte * data, dword length);
67static int diva_4bri_reset_adapter(PISDN_ADAPTER IoAdapter);
68static int diva_4bri_write_sdram_block(PISDN_ADAPTER IoAdapter,
69 dword address,
70 const byte * data,
71 dword length, dword limit);
72static int diva_4bri_start_adapter(PISDN_ADAPTER IoAdapter,
73 dword start_address, dword features);
74static int check_qBri_interrupt(PISDN_ADAPTER IoAdapter);
75static int diva_4bri_stop_adapter(diva_os_xdi_adapter_t * a);
76
77static int _4bri_is_rev_2_card(int card_ordinal)
78{
79 switch (card_ordinal) {
80 case CARDTYPE_DIVASRV_Q_8M_V2_PCI:
81 case CARDTYPE_DIVASRV_VOICE_Q_8M_V2_PCI:
82 case CARDTYPE_DIVASRV_B_2M_V2_PCI:
83 case CARDTYPE_DIVASRV_B_2F_PCI:
84 case CARDTYPE_DIVASRV_VOICE_B_2M_V2_PCI:
85 return (1);
86 }
87 return (0);
88}
89
90static int _4bri_is_rev_2_bri_card(int card_ordinal)
91{
92 switch (card_ordinal) {
93 case CARDTYPE_DIVASRV_B_2M_V2_PCI:
94 case CARDTYPE_DIVASRV_B_2F_PCI:
95 case CARDTYPE_DIVASRV_VOICE_B_2M_V2_PCI:
96 return (1);
97 }
98 return (0);
99}
100
101static void diva_4bri_set_addresses(diva_os_xdi_adapter_t *a)
102{
103 dword offset = a->resources.pci.qoffset;
104 dword c_offset = offset * a->xdi_adapter.ControllerNumber;
105
106 a->resources.pci.mem_type_id[MEM_TYPE_RAM] = 2;
107 a->resources.pci.mem_type_id[MEM_TYPE_ADDRESS] = 2;
108 a->resources.pci.mem_type_id[MEM_TYPE_CONTROL] = 2;
109 a->resources.pci.mem_type_id[MEM_TYPE_RESET] = 0;
110 a->resources.pci.mem_type_id[MEM_TYPE_CTLREG] = 3;
111 a->resources.pci.mem_type_id[MEM_TYPE_PROM] = 0;
112
113 /*
114 Set up hardware related pointers
115 */
116 a->xdi_adapter.Address = a->resources.pci.addr[2]; /* BAR2 SDRAM */
117 a->xdi_adapter.Address += c_offset;
118
119 a->xdi_adapter.Control = a->resources.pci.addr[2]; /* BAR2 SDRAM */
120
121 a->xdi_adapter.ram = a->resources.pci.addr[2]; /* BAR2 SDRAM */
122 a->xdi_adapter.ram += c_offset + (offset - MQ_SHARED_RAM_SIZE);
123
124 a->xdi_adapter.reset = a->resources.pci.addr[0]; /* BAR0 CONFIG */
125 /*
126 ctlReg contains the register address for the MIPS CPU reset control
127 */
128 a->xdi_adapter.ctlReg = a->resources.pci.addr[3]; /* BAR3 CNTRL */
129 /*
130 prom contains the register address for FPGA and EEPROM programming
131 */
132 a->xdi_adapter.prom = &a->xdi_adapter.reset[0x6E];
133}
134
135/*
136** BAR0 - MEM - 0x100 - CONFIG MEM
137** BAR1 - I/O - 0x100 - UNUSED
138** BAR2 - MEM - MQ_MEMORY_SIZE (MQ2_MEMORY_SIZE on Rev.2) - SDRAM
139** BAR3 - MEM - 0x2000 (0x10000 on Rev.2) - CNTRL
140**
141** Called by master adapter, that will initialize and add slave adapters
142*/
143int diva_4bri_init_card(diva_os_xdi_adapter_t * a)
144{
145 int bar, i;
146 byte __iomem *p;
147 PADAPTER_LIST_ENTRY quadro_list;
148 diva_os_xdi_adapter_t *diva_current;
149 diva_os_xdi_adapter_t *adapter_list[4];
150 PISDN_ADAPTER Slave;
151 unsigned long bar_length[sizeof(_4bri_bar_length) /
152 sizeof(_4bri_bar_length[0])];
153 int v2 = _4bri_is_rev_2_card(a->CardOrdinal);
154 int tasks = _4bri_is_rev_2_bri_card(a->CardOrdinal) ? 1 : MQ_INSTANCE_COUNT;
155 int factor = (tasks == 1) ? 1 : 2;
156
157 if (v2) {
158 if (_4bri_is_rev_2_bri_card(a->CardOrdinal)) {
159 memcpy(bar_length, _4bri_v2_bri_bar_length,
160 sizeof(bar_length));
161 } else {
162 memcpy(bar_length, _4bri_v2_bar_length,
163 sizeof(bar_length));
164 }
165 } else {
166 memcpy(bar_length, _4bri_bar_length, sizeof(bar_length));
167 }
168 DBG_TRC(("SDRAM_LENGTH=%08x, tasks=%d, factor=%d",
169 bar_length[2], tasks, factor))
170
171 /*
172 Get Serial Number
173 The serial number of 4BRI is accessible in accordance with PCI spec
174 via command register located in configuration space, also we do not
175 have to map any BAR before we can access it
176 */
177 if (!_4bri_get_serial_number(a)) {
178 DBG_ERR(("A: 4BRI can't get Serial Number"))
179 diva_4bri_cleanup_adapter(a);
180 return (-1);
181 }
182
183 /*
184 Set properties
185 */
186 a->xdi_adapter.Properties = CardProperties[a->CardOrdinal];
187 DBG_LOG(("Load %s, SN:%ld, bus:%02x, func:%02x",
188 a->xdi_adapter.Properties.Name,
189 a->xdi_adapter.serialNo,
190 a->resources.pci.bus, a->resources.pci.func))
191
192 /*
193 First initialization step: get and check hardware resoures.
194 Do not map resources and do not access card at this step
195 */
196 for (bar = 0; bar < 4; bar++) {
197 a->resources.pci.bar[bar] =
198 divasa_get_pci_bar(a->resources.pci.bus,
199 a->resources.pci.func, bar,
200 a->resources.pci.hdev);
201 if (!a->resources.pci.bar[bar]
202 || (a->resources.pci.bar[bar] == 0xFFFFFFF0)) {
203 DBG_ERR(
204 ("A: invalid bar[%d]=%08x", bar,
205 a->resources.pci.bar[bar]))
206 return (-1);
207 }
208 }
209 a->resources.pci.irq =
210 (byte) divasa_get_pci_irq(a->resources.pci.bus,
211 a->resources.pci.func,
212 a->resources.pci.hdev);
213 if (!a->resources.pci.irq) {
214 DBG_ERR(("A: invalid irq"));
215 return (-1);
216 }
217
218 a->xdi_adapter.sdram_bar = a->resources.pci.bar[2];
219
220 /*
221 Map all MEMORY BAR's
222 */
223 for (bar = 0; bar < 4; bar++) {
224 if (bar != 1) { /* ignore I/O */
225 a->resources.pci.addr[bar] =
226 divasa_remap_pci_bar(a, bar, a->resources.pci.bar[bar],
227 bar_length[bar]);
228 if (!a->resources.pci.addr[bar]) {
229 DBG_ERR(("A: 4BRI: can't map bar[%d]", bar))
230 diva_4bri_cleanup_adapter(a);
231 return (-1);
232 }
233 }
234 }
235
236 /*
237 Register I/O port
238 */
239 sprintf(&a->port_name[0], "DIVA 4BRI %ld", (long) a->xdi_adapter.serialNo);
240
241 if (diva_os_register_io_port(a, 1, a->resources.pci.bar[1],
242 bar_length[1], &a->port_name[0], 1)) {
243 DBG_ERR(("A: 4BRI: can't register bar[1]"))
244 diva_4bri_cleanup_adapter(a);
245 return (-1);
246 }
247
248 a->resources.pci.addr[1] =
249 (void *) (unsigned long) a->resources.pci.bar[1];
250
251 /*
252 Set cleanup pointer for base adapter only, so slave adapter
253 will be unable to get cleanup
254 */
255 a->interface.cleanup_adapter_proc = diva_4bri_cleanup_adapter;
256
257 /*
258 Create slave adapters
259 */
260 if (tasks > 1) {
261 if (!(a->slave_adapters[0] =
262 (diva_os_xdi_adapter_t *) diva_os_malloc(0, sizeof(*a))))
263 {
264 diva_4bri_cleanup_adapter(a);
265 return (-1);
266 }
267 if (!(a->slave_adapters[1] =
268 (diva_os_xdi_adapter_t *) diva_os_malloc(0, sizeof(*a))))
269 {
270 diva_os_free(0, a->slave_adapters[0]);
271 a->slave_adapters[0] = NULL;
272 diva_4bri_cleanup_adapter(a);
273 return (-1);
274 }
275 if (!(a->slave_adapters[2] =
276 (diva_os_xdi_adapter_t *) diva_os_malloc(0, sizeof(*a))))
277 {
278 diva_os_free(0, a->slave_adapters[0]);
279 diva_os_free(0, a->slave_adapters[1]);
280 a->slave_adapters[0] = NULL;
281 a->slave_adapters[1] = NULL;
282 diva_4bri_cleanup_adapter(a);
283 return (-1);
284 }
285 memset(a->slave_adapters[0], 0x00, sizeof(*a));
286 memset(a->slave_adapters[1], 0x00, sizeof(*a));
287 memset(a->slave_adapters[2], 0x00, sizeof(*a));
288 }
289
290 adapter_list[0] = a;
291 adapter_list[1] = a->slave_adapters[0];
292 adapter_list[2] = a->slave_adapters[1];
293 adapter_list[3] = a->slave_adapters[2];
294
295 /*
296 Allocate slave list
297 */
298 quadro_list =
299 (PADAPTER_LIST_ENTRY) diva_os_malloc(0, sizeof(*quadro_list));
300 if (!(a->slave_list = quadro_list)) {
301 for (i = 0; i < (tasks - 1); i++) {
302 diva_os_free(0, a->slave_adapters[i]);
303 a->slave_adapters[i] = NULL;
304 }
305 diva_4bri_cleanup_adapter(a);
306 return (-1);
307 }
308 memset(quadro_list, 0x00, sizeof(*quadro_list));
309
310 /*
311 Set interfaces
312 */
313 a->xdi_adapter.QuadroList = quadro_list;
314 for (i = 0; i < tasks; i++) {
315 adapter_list[i]->xdi_adapter.ControllerNumber = i;
316 adapter_list[i]->xdi_adapter.tasks = tasks;
317 quadro_list->QuadroAdapter[i] =
318 &adapter_list[i]->xdi_adapter;
319 }
320
321 for (i = 0; i < tasks; i++) {
322 diva_current = adapter_list[i];
323
324 diva_current->dsp_mask = 0x00000003;
325
326 diva_current->xdi_adapter.a.io =
327 &diva_current->xdi_adapter;
328 diva_current->xdi_adapter.DIRequest = request;
329 diva_current->interface.cmd_proc = diva_4bri_cmd_card_proc;
330 diva_current->xdi_adapter.Properties =
331 CardProperties[a->CardOrdinal];
332 diva_current->CardOrdinal = a->CardOrdinal;
333
334 diva_current->xdi_adapter.Channels =
335 CardProperties[a->CardOrdinal].Channels;
336 diva_current->xdi_adapter.e_max =
337 CardProperties[a->CardOrdinal].E_info;
338 diva_current->xdi_adapter.e_tbl =
339 diva_os_malloc(0,
340 diva_current->xdi_adapter.e_max *
341 sizeof(E_INFO));
342
343 if (!diva_current->xdi_adapter.e_tbl) {
344 diva_4bri_cleanup_slave_adapters(a);
345 diva_4bri_cleanup_adapter(a);
346 for (i = 1; i < (tasks - 1); i++) {
347 diva_os_free(0, adapter_list[i]);
348 }
349 return (-1);
350 }
351 memset(diva_current->xdi_adapter.e_tbl, 0x00,
352 diva_current->xdi_adapter.e_max * sizeof(E_INFO));
353
354 if (diva_os_initialize_spin_lock(&diva_current->xdi_adapter.isr_spin_lock, "isr")) {
355 diva_4bri_cleanup_slave_adapters(a);
356 diva_4bri_cleanup_adapter(a);
357 for (i = 1; i < (tasks - 1); i++) {
358 diva_os_free(0, adapter_list[i]);
359 }
360 return (-1);
361 }
362 if (diva_os_initialize_spin_lock(&diva_current->xdi_adapter.data_spin_lock, "data")) {
363 diva_4bri_cleanup_slave_adapters(a);
364 diva_4bri_cleanup_adapter(a);
365 for (i = 1; i < (tasks - 1); i++) {
366 diva_os_free(0, adapter_list[i]);
367 }
368 return (-1);
369 }
370
371 strcpy(diva_current->xdi_adapter.req_soft_isr. dpc_thread_name, "kdivas4brid");
372
373 if (diva_os_initialize_soft_isr (&diva_current->xdi_adapter.req_soft_isr, DIDpcRoutine,
374 &diva_current->xdi_adapter)) {
375 diva_4bri_cleanup_slave_adapters(a);
376 diva_4bri_cleanup_adapter(a);
377 for (i = 1; i < (tasks - 1); i++) {
378 diva_os_free(0, adapter_list[i]);
379 }
380 return (-1);
381 }
382
383 /*
384 Do not initialize second DPC - only one thread will be created
385 */
386 diva_current->xdi_adapter.isr_soft_isr.object =
387 diva_current->xdi_adapter.req_soft_isr.object;
388 }
389
390 if (v2) {
391 prepare_qBri2_functions(&a->xdi_adapter);
392 } else {
393 prepare_qBri_functions(&a->xdi_adapter);
394 }
395
396 for (i = 0; i < tasks; i++) {
397 diva_current = adapter_list[i];
398 if (i)
399 memcpy(&diva_current->resources, &a->resources, sizeof(divas_card_resources_t));
400 diva_current->resources.pci.qoffset = (a->xdi_adapter.MemorySize >> factor);
401 }
402
403 /*
404 Set up hardware related pointers
405 */
406 a->xdi_adapter.cfg = (void *) (unsigned long) a->resources.pci.bar[0]; /* BAR0 CONFIG */
407 a->xdi_adapter.port = (void *) (unsigned long) a->resources.pci.bar[1]; /* BAR1 */
408 a->xdi_adapter.ctlReg = (void *) (unsigned long) a->resources.pci.bar[3]; /* BAR3 CNTRL */
409
410 for (i = 0; i < tasks; i++) {
411 diva_current = adapter_list[i];
412 diva_4bri_set_addresses(diva_current);
413 Slave = a->xdi_adapter.QuadroList->QuadroAdapter[i];
414 Slave->MultiMaster = &a->xdi_adapter;
415 Slave->sdram_bar = a->xdi_adapter.sdram_bar;
416 if (i) {
417 Slave->serialNo = ((dword) (Slave->ControllerNumber << 24)) |
418 a->xdi_adapter.serialNo;
419 Slave->cardType = a->xdi_adapter.cardType;
420 }
421 }
422
423 /*
424 reset contains the base address for the PLX 9054 register set
425 */
426 p = DIVA_OS_MEM_ATTACH_RESET(&a->xdi_adapter);
427 WRITE_BYTE(&p[PLX9054_INTCSR], 0x00); /* disable PCI interrupts */
428 DIVA_OS_MEM_DETACH_RESET(&a->xdi_adapter, p);
429
430 /*
431 Set IRQ handler
432 */
433 a->xdi_adapter.irq_info.irq_nr = a->resources.pci.irq;
434 sprintf(a->xdi_adapter.irq_info.irq_name, "DIVA 4BRI %ld",
435 (long) a->xdi_adapter.serialNo);
436
437 if (diva_os_register_irq(a, a->xdi_adapter.irq_info.irq_nr,
438 a->xdi_adapter.irq_info.irq_name)) {
439 diva_4bri_cleanup_slave_adapters(a);
440 diva_4bri_cleanup_adapter(a);
441 for (i = 1; i < (tasks - 1); i++) {
442 diva_os_free(0, adapter_list[i]);
443 }
444 return (-1);
445 }
446
447 a->xdi_adapter.irq_info.registered = 1;
448
449 /*
450 Add three slave adapters
451 */
452 if (tasks > 1) {
453 diva_add_slave_adapter(adapter_list[1]);
454 diva_add_slave_adapter(adapter_list[2]);
455 diva_add_slave_adapter(adapter_list[3]);
456 }
457
458 diva_log_info("%s IRQ:%d SerNo:%d", a->xdi_adapter.Properties.Name,
459 a->resources.pci.irq, a->xdi_adapter.serialNo);
460
461 return (0);
462}
463
464/*
465** Cleanup function will be called for master adapter only
466** this is garanteed by design: cleanup callback is set
467** by master adapter only
468*/
469static int diva_4bri_cleanup_adapter(diva_os_xdi_adapter_t * a)
470{
471 int bar;
472
473 /*
474 Stop adapter if running
475 */
476 if (a->xdi_adapter.Initialized) {
477 diva_4bri_stop_adapter(a);
478 }
479
480 /*
481 Remove IRQ handler
482 */
483 if (a->xdi_adapter.irq_info.registered) {
484 diva_os_remove_irq(a, a->xdi_adapter.irq_info.irq_nr);
485 }
486 a->xdi_adapter.irq_info.registered = 0;
487
488 /*
489 Free DPC's and spin locks on all adapters
490 */
491 diva_4bri_cleanup_slave_adapters(a);
492
493 /*
494 Unmap all BARS
495 */
496 for (bar = 0; bar < 4; bar++) {
497 if (bar != 1) {
498 if (a->resources.pci.bar[bar]
499 && a->resources.pci.addr[bar]) {
500 divasa_unmap_pci_bar(a->resources.pci.addr[bar]);
501 a->resources.pci.bar[bar] = 0;
502 a->resources.pci.addr[bar] = NULL;
503 }
504 }
505 }
506
507 /*
508 Unregister I/O
509 */
510 if (a->resources.pci.bar[1] && a->resources.pci.addr[1]) {
511 diva_os_register_io_port(a, 0, a->resources.pci.bar[1],
512 _4bri_is_rev_2_card(a->
513 CardOrdinal) ?
514 _4bri_v2_bar_length[1] :
515 _4bri_bar_length[1],
516 &a->port_name[0], 1);
517 a->resources.pci.bar[1] = 0;
518 a->resources.pci.addr[1] = NULL;
519 }
520
521 if (a->slave_list) {
522 diva_os_free(0, a->slave_list);
523 a->slave_list = NULL;
524 }
525
526 return (0);
527}
528
529static int _4bri_get_serial_number(diva_os_xdi_adapter_t * a)
530{
531 dword data[64];
532 dword serNo;
533 word addr, status, i, j;
534 byte Bus, Slot;
535 void *hdev;
536
537 Bus = a->resources.pci.bus;
538 Slot = a->resources.pci.func;
539 hdev = a->resources.pci.hdev;
540
541 for (i = 0; i < 64; ++i) {
542 addr = i * 4;
543 for (j = 0; j < 5; ++j) {
544 PCIwrite(Bus, Slot, 0x4E, &addr, sizeof(addr),
545 hdev);
546 diva_os_wait(1);
547 PCIread(Bus, Slot, 0x4E, &status, sizeof(status),
548 hdev);
549 if (status & 0x8000)
550 break;
551 }
552 if (j >= 5) {
553 DBG_ERR(("EEPROM[%d] read failed (0x%x)", i * 4, addr))
554 return (0);
555 }
556 PCIread(Bus, Slot, 0x50, &data[i], sizeof(data[i]), hdev);
557 }
558 DBG_BLK(((char *) &data[0], sizeof(data)))
559
560 serNo = data[32];
561 if (serNo == 0 || serNo == 0xffffffff)
562 serNo = data[63];
563
564 if (!serNo) {
565 DBG_LOG(("W: Serial Number == 0, create one serial number"));
566 serNo = a->resources.pci.bar[1] & 0xffff0000;
567 serNo |= a->resources.pci.bus << 8;
568 serNo |= a->resources.pci.func;
569 }
570
571 a->xdi_adapter.serialNo = serNo;
572
573 DBG_REG(("Serial No. : %ld", a->xdi_adapter.serialNo))
574
575 return (serNo);
576}
577
578/*
579** Release resources of slave adapters
580*/
581static int diva_4bri_cleanup_slave_adapters(diva_os_xdi_adapter_t * a)
582{
583 diva_os_xdi_adapter_t *adapter_list[4];
584 diva_os_xdi_adapter_t *diva_current;
585 int i;
586
587 adapter_list[0] = a;
588 adapter_list[1] = a->slave_adapters[0];
589 adapter_list[2] = a->slave_adapters[1];
590 adapter_list[3] = a->slave_adapters[2];
591
592 for (i = 0; i < a->xdi_adapter.tasks; i++) {
593 diva_current = adapter_list[i];
594 if (diva_current) {
595 diva_os_destroy_spin_lock(&diva_current->
596 xdi_adapter.
597 isr_spin_lock, "unload");
598 diva_os_destroy_spin_lock(&diva_current->
599 xdi_adapter.
600 data_spin_lock,
601 "unload");
602
603 diva_os_cancel_soft_isr(&diva_current->xdi_adapter.
604 req_soft_isr);
605 diva_os_cancel_soft_isr(&diva_current->xdi_adapter.
606 isr_soft_isr);
607
608 diva_os_remove_soft_isr(&diva_current->xdi_adapter.
609 req_soft_isr);
610 diva_current->xdi_adapter.isr_soft_isr.object = NULL;
611
612 if (diva_current->xdi_adapter.e_tbl) {
613 diva_os_free(0,
614 diva_current->xdi_adapter.
615 e_tbl);
616 }
617 diva_current->xdi_adapter.e_tbl = NULL;
618 diva_current->xdi_adapter.e_max = 0;
619 diva_current->xdi_adapter.e_count = 0;
620 }
621 }
622
623 return (0);
624}
625
626static int
627diva_4bri_cmd_card_proc(struct _diva_os_xdi_adapter *a,
628 diva_xdi_um_cfg_cmd_t * cmd, int length)
629{
630 int ret = -1;
631
632 if (cmd->adapter != a->controller) {
633 DBG_ERR(("A: 4bri_cmd, invalid controller=%d != %d",
634 cmd->adapter, a->controller))
635 return (-1);
636 }
637
638 switch (cmd->command) {
639 case DIVA_XDI_UM_CMD_GET_CARD_ORDINAL:
640 a->xdi_mbox.data_length = sizeof(dword);
641 a->xdi_mbox.data =
642 diva_os_malloc(0, a->xdi_mbox.data_length);
643 if (a->xdi_mbox.data) {
644 *(dword *) a->xdi_mbox.data =
645 (dword) a->CardOrdinal;
646 a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
647 ret = 0;
648 }
649 break;
650
651 case DIVA_XDI_UM_CMD_GET_SERIAL_NR:
652 a->xdi_mbox.data_length = sizeof(dword);
653 a->xdi_mbox.data =
654 diva_os_malloc(0, a->xdi_mbox.data_length);
655 if (a->xdi_mbox.data) {
656 *(dword *) a->xdi_mbox.data =
657 (dword) a->xdi_adapter.serialNo;
658 a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
659 ret = 0;
660 }
661 break;
662
663 case DIVA_XDI_UM_CMD_GET_PCI_HW_CONFIG:
664 if (!a->xdi_adapter.ControllerNumber) {
665 /*
666 Only master adapter can access hardware config
667 */
668 a->xdi_mbox.data_length = sizeof(dword) * 9;
669 a->xdi_mbox.data =
670 diva_os_malloc(0, a->xdi_mbox.data_length);
671 if (a->xdi_mbox.data) {
672 int i;
673 dword *data = (dword *) a->xdi_mbox.data;
674
675 for (i = 0; i < 8; i++) {
676 *data++ = a->resources.pci.bar[i];
677 }
678 *data++ = (dword) a->resources.pci.irq;
679 a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
680 ret = 0;
681 }
682 }
683 break;
684
685 case DIVA_XDI_UM_CMD_GET_CARD_STATE:
686 if (!a->xdi_adapter.ControllerNumber) {
687 a->xdi_mbox.data_length = sizeof(dword);
688 a->xdi_mbox.data =
689 diva_os_malloc(0, a->xdi_mbox.data_length);
690 if (a->xdi_mbox.data) {
691 dword *data = (dword *) a->xdi_mbox.data;
692 if (!a->xdi_adapter.ram
693 || !a->xdi_adapter.reset
694 || !a->xdi_adapter.cfg) {
695 *data = 3;
696 } else if (a->xdi_adapter.trapped) {
697 *data = 2;
698 } else if (a->xdi_adapter.Initialized) {
699 *data = 1;
700 } else {
701 *data = 0;
702 }
703 a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
704 ret = 0;
705 }
706 }
707 break;
708
709 case DIVA_XDI_UM_CMD_WRITE_FPGA:
710 if (!a->xdi_adapter.ControllerNumber) {
711 ret =
712 diva_4bri_write_fpga_image(a,
713 (byte *) & cmd[1],
714 cmd->command_data.
715 write_fpga.
716 image_length);
717 }
718 break;
719
720 case DIVA_XDI_UM_CMD_RESET_ADAPTER:
721 if (!a->xdi_adapter.ControllerNumber) {
722 ret = diva_4bri_reset_adapter(&a->xdi_adapter);
723 }
724 break;
725
726 case DIVA_XDI_UM_CMD_WRITE_SDRAM_BLOCK:
727 if (!a->xdi_adapter.ControllerNumber) {
728 ret = diva_4bri_write_sdram_block(&a->xdi_adapter,
729 cmd->
730 command_data.
731 write_sdram.
732 offset,
733 (byte *) &
734 cmd[1],
735 cmd->
736 command_data.
737 write_sdram.
738 length,
739 a->xdi_adapter.
740 MemorySize);
741 }
742 break;
743
744 case DIVA_XDI_UM_CMD_START_ADAPTER:
745 if (!a->xdi_adapter.ControllerNumber) {
746 ret = diva_4bri_start_adapter(&a->xdi_adapter,
747 cmd->command_data.
748 start.offset,
749 cmd->command_data.
750 start.features);
751 }
752 break;
753
754 case DIVA_XDI_UM_CMD_SET_PROTOCOL_FEATURES:
755 if (!a->xdi_adapter.ControllerNumber) {
756 a->xdi_adapter.features =
757 cmd->command_data.features.features;
758 a->xdi_adapter.a.protocol_capabilities =
759 a->xdi_adapter.features;
760 DBG_TRC(("Set raw protocol features (%08x)",
761 a->xdi_adapter.features))
762 ret = 0;
763 }
764 break;
765
766 case DIVA_XDI_UM_CMD_STOP_ADAPTER:
767 if (!a->xdi_adapter.ControllerNumber) {
768 ret = diva_4bri_stop_adapter(a);
769 }
770 break;
771
772 case DIVA_XDI_UM_CMD_READ_XLOG_ENTRY:
773 ret = diva_card_read_xlog(a);
774 break;
775
776 case DIVA_XDI_UM_CMD_READ_SDRAM:
777 if (!a->xdi_adapter.ControllerNumber
778 && a->xdi_adapter.Address) {
779 if (
780 (a->xdi_mbox.data_length =
781 cmd->command_data.read_sdram.length)) {
782 if (
783 (a->xdi_mbox.data_length +
784 cmd->command_data.read_sdram.offset) <
785 a->xdi_adapter.MemorySize) {
786 a->xdi_mbox.data =
787 diva_os_malloc(0,
788 a->xdi_mbox.
789 data_length);
790 if (a->xdi_mbox.data) {
791 byte __iomem *p = DIVA_OS_MEM_ATTACH_ADDRESS(&a->xdi_adapter);
792 byte __iomem *src = p;
793 byte *dst = a->xdi_mbox.data;
794 dword len = a->xdi_mbox.data_length;
795
796 src += cmd->command_data.read_sdram.offset;
797
798 while (len--) {
799 *dst++ = READ_BYTE(src++);
800 }
801 DIVA_OS_MEM_DETACH_ADDRESS(&a->xdi_adapter, p);
802 a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
803 ret = 0;
804 }
805 }
806 }
807 }
808 break;
809
810 default:
811 DBG_ERR(("A: A(%d) invalid cmd=%d", a->controller,
812 cmd->command))
813 }
814
815 return (ret);
816}
817
818void *xdiLoadFile(char *FileName, unsigned long *FileLength,
819 unsigned long lim)
820{
821 void *ret = diva_xdiLoadFileFile;
822
823 if (FileLength) {
824 *FileLength = diva_xdiLoadFileLength;
825 }
826 diva_xdiLoadFileFile = NULL;
827 diva_xdiLoadFileLength = 0;
828
829 return (ret);
830}
831
832void diva_os_set_qBri_functions(PISDN_ADAPTER IoAdapter)
833{
834}
835
836void diva_os_set_qBri2_functions(PISDN_ADAPTER IoAdapter)
837{
838}
839
840static int
841diva_4bri_write_fpga_image(diva_os_xdi_adapter_t * a, byte * data,
842 dword length)
843{
844 int ret;
845
846 diva_xdiLoadFileFile = data;
847 diva_xdiLoadFileLength = length;
848
849 ret = qBri_FPGA_download(&a->xdi_adapter);
850
851 diva_xdiLoadFileFile = NULL;
852 diva_xdiLoadFileLength = 0;
853
854 return (ret ? 0 : -1);
855}
856
857static int diva_4bri_reset_adapter(PISDN_ADAPTER IoAdapter)
858{
859 PISDN_ADAPTER Slave;
860 int i;
861
862 if (!IoAdapter->Address || !IoAdapter->reset) {
863 return (-1);
864 }
865 if (IoAdapter->Initialized) {
866 DBG_ERR(("A: A(%d) can't reset 4BRI adapter - please stop first",
867 IoAdapter->ANum))
868 return (-1);
869 }
870
871 /*
872 Forget all entities on all adapters
873 */
874 for (i = 0; ((i < IoAdapter->tasks) && IoAdapter->QuadroList); i++) {
875 Slave = IoAdapter->QuadroList->QuadroAdapter[i];
876 Slave->e_count = 0;
877 if (Slave->e_tbl) {
878 memset(Slave->e_tbl, 0x00,
879 Slave->e_max * sizeof(E_INFO));
880 }
881 Slave->head = 0;
882 Slave->tail = 0;
883 Slave->assign = 0;
884 Slave->trapped = 0;
885
886 memset(&Slave->a.IdTable[0], 0x00,
887 sizeof(Slave->a.IdTable));
888 memset(&Slave->a.IdTypeTable[0], 0x00,
889 sizeof(Slave->a.IdTypeTable));
890 memset(&Slave->a.FlowControlIdTable[0], 0x00,
891 sizeof(Slave->a.FlowControlIdTable));
892 memset(&Slave->a.FlowControlSkipTable[0], 0x00,
893 sizeof(Slave->a.FlowControlSkipTable));
894 memset(&Slave->a.misc_flags_table[0], 0x00,
895 sizeof(Slave->a.misc_flags_table));
896 memset(&Slave->a.rx_stream[0], 0x00,
897 sizeof(Slave->a.rx_stream));
898 memset(&Slave->a.tx_stream[0], 0x00,
899 sizeof(Slave->a.tx_stream));
900 memset(&Slave->a.tx_pos[0], 0x00, sizeof(Slave->a.tx_pos));
901 memset(&Slave->a.rx_pos[0], 0x00, sizeof(Slave->a.rx_pos));
902 }
903
904 return (0);
905}
906
907
908static int
909diva_4bri_write_sdram_block(PISDN_ADAPTER IoAdapter,
910 dword address,
911 const byte * data, dword length, dword limit)
912{
913 byte __iomem *p = DIVA_OS_MEM_ATTACH_ADDRESS(IoAdapter);
914 byte __iomem *mem = p;
915
916 if (((address + length) >= limit) || !mem) {
917 DIVA_OS_MEM_DETACH_ADDRESS(IoAdapter, p);
918 DBG_ERR(("A: A(%d) write 4BRI address=0x%08lx",
919 IoAdapter->ANum, address + length))
920 return (-1);
921 }
922 mem += address;
923
924 while (length--) {
925 WRITE_BYTE(mem++, *data++);
926 }
927
928 DIVA_OS_MEM_DETACH_ADDRESS(IoAdapter, p);
929 return (0);
930}
931
932static int
933diva_4bri_start_adapter(PISDN_ADAPTER IoAdapter,
934 dword start_address, dword features)
935{
936 volatile word __iomem *signature;
937 int started = 0;
938 int i;
939 byte __iomem *p;
940
941 /*
942 start adapter
943 */
944 start_qBri_hardware(IoAdapter);
945
946 p = DIVA_OS_MEM_ATTACH_RAM(IoAdapter);
947 /*
948 wait for signature in shared memory (max. 3 seconds)
949 */
950 signature = (volatile word __iomem *) (&p[0x1E]);
951
952 for (i = 0; i < 300; ++i) {
953 diva_os_wait(10);
954 if (READ_WORD(&signature[0]) == 0x4447) {
955 DBG_TRC(("Protocol startup time %d.%02d seconds",
956 (i / 100), (i % 100)))
957 started = 1;
958 break;
959 }
960 }
961
962 for (i = 1; i < IoAdapter->tasks; i++) {
963 IoAdapter->QuadroList->QuadroAdapter[i]->features =
964 IoAdapter->features;
965 IoAdapter->QuadroList->QuadroAdapter[i]->a.
966 protocol_capabilities = IoAdapter->features;
967 }
968
969 if (!started) {
970 DBG_FTL(("%s: Adapter selftest failed, signature=%04x",
971 IoAdapter->Properties.Name,
972 READ_WORD(&signature[0])))
973 DIVA_OS_MEM_DETACH_RAM(IoAdapter, p);
974 (*(IoAdapter->trapFnc)) (IoAdapter);
975 IoAdapter->stop(IoAdapter);
976 return (-1);
977 }
978 DIVA_OS_MEM_DETACH_RAM(IoAdapter, p);
979
980 for (i = 0; i < IoAdapter->tasks; i++) {
981 IoAdapter->QuadroList->QuadroAdapter[i]->Initialized = 1;
982 IoAdapter->QuadroList->QuadroAdapter[i]->IrqCount = 0;
983 }
984
985 if (check_qBri_interrupt(IoAdapter)) {
986 DBG_ERR(("A: A(%d) interrupt test failed",
987 IoAdapter->ANum))
988 for (i = 0; i < IoAdapter->tasks; i++) {
989 IoAdapter->QuadroList->QuadroAdapter[i]->Initialized = 0;
990 }
991 IoAdapter->stop(IoAdapter);
992 return (-1);
993 }
994
995 IoAdapter->Properties.Features = (word) features;
996 diva_xdi_display_adapter_features(IoAdapter->ANum);
997
998 for (i = 0; i < IoAdapter->tasks; i++) {
999 DBG_LOG(("A(%d) %s adapter successfull started",
1000 IoAdapter->QuadroList->QuadroAdapter[i]->ANum,
1001 (IoAdapter->tasks == 1) ? "BRI 2.0" : "4BRI"))
1002 diva_xdi_didd_register_adapter(IoAdapter->QuadroList->QuadroAdapter[i]->ANum);
1003 IoAdapter->QuadroList->QuadroAdapter[i]->Properties.Features = (word) features;
1004 }
1005
1006 return (0);
1007}
1008
1009static int check_qBri_interrupt(PISDN_ADAPTER IoAdapter)
1010{
1011#ifdef SUPPORT_INTERRUPT_TEST_ON_4BRI
1012 int i;
1013 ADAPTER *a = &IoAdapter->a;
1014 byte __iomem *p;
1015
1016 IoAdapter->IrqCount = 0;
1017
1018 if (IoAdapter->ControllerNumber > 0)
1019 return (-1);
1020
1021 p = DIVA_OS_MEM_ATTACH_RESET(IoAdapter);
1022 WRITE_BYTE(&p[PLX9054_INTCSR], PLX9054_INT_ENABLE);
1023 DIVA_OS_MEM_DETACH_RESET(IoAdapter, p);
1024 /*
1025 interrupt test
1026 */
1027 a->ReadyInt = 1;
1028 a->ram_out(a, &PR_RAM->ReadyInt, 1);
1029
1030 for (i = 100; !IoAdapter->IrqCount && (i-- > 0); diva_os_wait(10));
1031
1032 return ((IoAdapter->IrqCount > 0) ? 0 : -1);
1033#else
1034 dword volatile __iomem *qBriIrq;
1035 byte __iomem *p;
1036 /*
1037 Reset on-board interrupt register
1038 */
1039 IoAdapter->IrqCount = 0;
1040 p = DIVA_OS_MEM_ATTACH_CTLREG(IoAdapter);
1041 qBriIrq = (dword volatile __iomem *) (&p[_4bri_is_rev_2_card
1042 (IoAdapter->
1043 cardType) ? (MQ2_BREG_IRQ_TEST)
1044 : (MQ_BREG_IRQ_TEST)]);
1045
1046 WRITE_DWORD(qBriIrq, MQ_IRQ_REQ_OFF);
1047 DIVA_OS_MEM_DETACH_CTLREG(IoAdapter, p);
1048
1049 p = DIVA_OS_MEM_ATTACH_RESET(IoAdapter);
1050 WRITE_BYTE(&p[PLX9054_INTCSR], PLX9054_INT_ENABLE);
1051 DIVA_OS_MEM_DETACH_RESET(IoAdapter, p);
1052
1053 diva_os_wait(100);
1054
1055 return (0);
1056#endif /* SUPPORT_INTERRUPT_TEST_ON_4BRI */
1057}
1058
1059static void diva_4bri_clear_interrupts(diva_os_xdi_adapter_t * a)
1060{
1061 PISDN_ADAPTER IoAdapter = &a->xdi_adapter;
1062
1063 /*
1064 clear any pending interrupt
1065 */
1066 IoAdapter->disIrq(IoAdapter);
1067
1068 IoAdapter->tst_irq(&IoAdapter->a);
1069 IoAdapter->clr_irq(&IoAdapter->a);
1070 IoAdapter->tst_irq(&IoAdapter->a);
1071
1072 /*
1073 kill pending dpcs
1074 */
1075 diva_os_cancel_soft_isr(&IoAdapter->req_soft_isr);
1076 diva_os_cancel_soft_isr(&IoAdapter->isr_soft_isr);
1077}
1078
1079static int diva_4bri_stop_adapter(diva_os_xdi_adapter_t * a)
1080{
1081 PISDN_ADAPTER IoAdapter = &a->xdi_adapter;
1082 int i;
1083
1084 if (!IoAdapter->ram) {
1085 return (-1);
1086 }
1087
1088 if (!IoAdapter->Initialized) {
1089 DBG_ERR(("A: A(%d) can't stop PRI adapter - not running",
1090 IoAdapter->ANum))
1091 return (-1); /* nothing to stop */
1092 }
1093
1094 for (i = 0; i < IoAdapter->tasks; i++) {
1095 IoAdapter->QuadroList->QuadroAdapter[i]->Initialized = 0;
1096 }
1097
1098 /*
1099 Disconnect Adapters from DIDD
1100 */
1101 for (i = 0; i < IoAdapter->tasks; i++) {
1102 diva_xdi_didd_remove_adapter(IoAdapter->QuadroList->QuadroAdapter[i]->ANum);
1103 }
1104
1105 i = 100;
1106
1107 /*
1108 Stop interrupts
1109 */
1110 a->clear_interrupts_proc = diva_4bri_clear_interrupts;
1111 IoAdapter->a.ReadyInt = 1;
1112 IoAdapter->a.ram_inc(&IoAdapter->a, &PR_RAM->ReadyInt);
1113 do {
1114 diva_os_sleep(10);
1115 } while (i-- && a->clear_interrupts_proc);
1116
1117 if (a->clear_interrupts_proc) {
1118 diva_4bri_clear_interrupts(a);
1119 a->clear_interrupts_proc = NULL;
1120 DBG_ERR(("A: A(%d) no final interrupt from 4BRI adapter",
1121 IoAdapter->ANum))
1122 }
1123 IoAdapter->a.ReadyInt = 0;
1124
1125 /*
1126 Stop and reset adapter
1127 */
1128 IoAdapter->stop(IoAdapter);
1129
1130 return (0);
1131}
diff --git a/drivers/isdn/hardware/eicon/os_4bri.h b/drivers/isdn/hardware/eicon/os_4bri.h
new file mode 100644
index 000000000000..665f0af27ce7
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/os_4bri.h
@@ -0,0 +1,8 @@
1/* $Id: os_4bri.h,v 1.1.2.2 2001/02/08 12:25:44 armin Exp $ */
2
3#ifndef __DIVA_OS_4_BRI_H__
4#define __DIVA_OS_4_BRI_H__
5
6int diva_4bri_init_card(diva_os_xdi_adapter_t * a);
7
8#endif
diff --git a/drivers/isdn/hardware/eicon/os_bri.c b/drivers/isdn/hardware/eicon/os_bri.c
new file mode 100644
index 000000000000..4cc44a5dd1db
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/os_bri.c
@@ -0,0 +1,813 @@
1/* $Id: os_bri.c,v 1.21 2004/03/21 17:26:01 armin Exp $ */
2
3#include "platform.h"
4#include "debuglib.h"
5#include "cardtype.h"
6#include "pc.h"
7#include "pr_pc.h"
8#include "di_defs.h"
9#include "dsp_defs.h"
10#include "di.h"
11#include "io.h"
12
13#include "xdi_msg.h"
14#include "xdi_adapter.h"
15#include "os_bri.h"
16#include "diva_pci.h"
17#include "mi_pc.h"
18#include "pc_maint.h"
19
20/*
21** IMPORTS
22*/
23extern void prepare_maestra_functions(PISDN_ADAPTER IoAdapter);
24extern void diva_xdi_display_adapter_features(int card);
25extern int diva_card_read_xlog(diva_os_xdi_adapter_t * a);
26
27/*
28** LOCALS
29*/
30static int bri_bar_length[3] = {
31 0x80,
32 0x80,
33 0x20
34};
35static int diva_bri_cleanup_adapter(diva_os_xdi_adapter_t * a);
36static dword diva_bri_get_serial_number(diva_os_xdi_adapter_t * a);
37static int diva_bri_cmd_card_proc(struct _diva_os_xdi_adapter *a,
38 diva_xdi_um_cfg_cmd_t * cmd, int length);
39static int diva_bri_reregister_io(diva_os_xdi_adapter_t * a);
40static int diva_bri_reset_adapter(PISDN_ADAPTER IoAdapter);
41static int diva_bri_write_sdram_block(PISDN_ADAPTER IoAdapter,
42 dword address,
43 const byte * data, dword length);
44static int diva_bri_start_adapter(PISDN_ADAPTER IoAdapter,
45 dword start_address, dword features);
46static int diva_bri_stop_adapter(diva_os_xdi_adapter_t * a);
47
48static void diva_bri_set_addresses(diva_os_xdi_adapter_t * a)
49{
50 a->resources.pci.mem_type_id[MEM_TYPE_RAM] = 0;
51 a->resources.pci.mem_type_id[MEM_TYPE_CFG] = 1;
52 a->resources.pci.mem_type_id[MEM_TYPE_ADDRESS] = 2;
53 a->resources.pci.mem_type_id[MEM_TYPE_RESET] = 1;
54 a->resources.pci.mem_type_id[MEM_TYPE_PORT] = 2;
55 a->resources.pci.mem_type_id[MEM_TYPE_CTLREG] = 2;
56
57 a->xdi_adapter.ram = a->resources.pci.addr[0];
58 a->xdi_adapter.cfg = a->resources.pci.addr[1];
59 a->xdi_adapter.Address = a->resources.pci.addr[2];
60
61 a->xdi_adapter.reset = a->xdi_adapter.cfg;
62 a->xdi_adapter.port = a->xdi_adapter.Address;
63
64 a->xdi_adapter.ctlReg = a->xdi_adapter.port + M_PCI_RESET;
65
66 a->xdi_adapter.reset += 0x4C; /* PLX 9050 !! */
67}
68
69/*
70** BAR0 - MEM Addr - 0x80 - NOT USED
71** BAR1 - I/O Addr - 0x80
72** BAR2 - I/O Addr - 0x20
73*/
74int diva_bri_init_card(diva_os_xdi_adapter_t * a)
75{
76 int bar;
77 dword bar2 = 0, bar2_length = 0xffffffff;
78 word cmd = 0, cmd_org;
79 byte Bus, Slot;
80 void *hdev;
81 byte __iomem *p;
82
83 /*
84 Set properties
85 */
86 a->xdi_adapter.Properties = CardProperties[a->CardOrdinal];
87 DBG_LOG(("Load %s", a->xdi_adapter.Properties.Name))
88
89 /*
90 Get resources
91 */
92 for (bar = 0; bar < 3; bar++) {
93 a->resources.pci.bar[bar] =
94 divasa_get_pci_bar(a->resources.pci.bus,
95 a->resources.pci.func, bar,
96 a->resources.pci.hdev);
97 if (!a->resources.pci.bar[bar]) {
98 DBG_ERR(("A: can't get BAR[%d]", bar))
99 return (-1);
100 }
101 }
102
103 a->resources.pci.irq =
104 (byte) divasa_get_pci_irq(a->resources.pci.bus,
105 a->resources.pci.func,
106 a->resources.pci.hdev);
107 if (!a->resources.pci.irq) {
108 DBG_ERR(("A: invalid irq"));
109 return (-1);
110 }
111
112 /*
113 Get length of I/O bar 2 - it is different by older
114 EEPROM version
115 */
116 Bus = a->resources.pci.bus;
117 Slot = a->resources.pci.func;
118 hdev = a->resources.pci.hdev;
119
120 /*
121 Get plain original values of the BAR2 CDM registers
122 */
123 PCIread(Bus, Slot, 0x18, &bar2, sizeof(bar2), hdev);
124 PCIread(Bus, Slot, 0x04, &cmd_org, sizeof(cmd_org), hdev);
125 /*
126 Disable device and get BAR2 length
127 */
128 PCIwrite(Bus, Slot, 0x04, &cmd, sizeof(cmd), hdev);
129 PCIwrite(Bus, Slot, 0x18, &bar2_length, sizeof(bar2_length), hdev);
130 PCIread(Bus, Slot, 0x18, &bar2_length, sizeof(bar2_length), hdev);
131 /*
132 Restore BAR2 and CMD registers
133 */
134 PCIwrite(Bus, Slot, 0x18, &bar2, sizeof(bar2), hdev);
135 PCIwrite(Bus, Slot, 0x04, &cmd_org, sizeof(cmd_org), hdev);
136
137 /*
138 Calculate BAR2 length
139 */
140 bar2_length = (~(bar2_length & ~7)) + 1;
141 DBG_LOG(("BAR[2] length=%lx", bar2_length))
142
143 /*
144 Map and register resources
145 */
146 if (!(a->resources.pci.addr[0] =
147 divasa_remap_pci_bar(a, 0, a->resources.pci.bar[0],
148 bri_bar_length[0]))) {
149 DBG_ERR(("A: BRI, can't map BAR[0]"))
150 diva_bri_cleanup_adapter(a);
151 return (-1);
152 }
153
154 sprintf(&a->port_name[0], "BRI %02x:%02x",
155 a->resources.pci.bus, a->resources.pci.func);
156
157 if (diva_os_register_io_port(a, 1, a->resources.pci.bar[1],
158 bri_bar_length[1], &a->port_name[0], 1)) {
159 DBG_ERR(("A: BRI, can't register BAR[1]"))
160 diva_bri_cleanup_adapter(a);
161 return (-1);
162 }
163 a->resources.pci.addr[1] = (void *) (unsigned long) a->resources.pci.bar[1];
164 a->resources.pci.length[1] = bri_bar_length[1];
165
166 if (diva_os_register_io_port(a, 1, a->resources.pci.bar[2],
167 bar2_length, &a->port_name[0], 2)) {
168 DBG_ERR(("A: BRI, can't register BAR[2]"))
169 diva_bri_cleanup_adapter(a);
170 return (-1);
171 }
172 a->resources.pci.addr[2] = (void *) (unsigned long) a->resources.pci.bar[2];
173 a->resources.pci.length[2] = bar2_length;
174
175 /*
176 Set all memory areas
177 */
178 diva_bri_set_addresses(a);
179
180 /*
181 Get Serial Number
182 */
183 a->xdi_adapter.serialNo = diva_bri_get_serial_number(a);
184
185 /*
186 Register I/O ports with correct name now
187 */
188 if (diva_bri_reregister_io(a)) {
189 diva_bri_cleanup_adapter(a);
190 return (-1);
191 }
192
193 /*
194 Initialize OS dependent objects
195 */
196 if (diva_os_initialize_spin_lock
197 (&a->xdi_adapter.isr_spin_lock, "isr")) {
198 diva_bri_cleanup_adapter(a);
199 return (-1);
200 }
201 if (diva_os_initialize_spin_lock
202 (&a->xdi_adapter.data_spin_lock, "data")) {
203 diva_bri_cleanup_adapter(a);
204 return (-1);
205 }
206
207 strcpy(a->xdi_adapter.req_soft_isr.dpc_thread_name, "kdivasbrid");
208
209 if (diva_os_initialize_soft_isr(&a->xdi_adapter.req_soft_isr,
210 DIDpcRoutine, &a->xdi_adapter)) {
211 diva_bri_cleanup_adapter(a);
212 return (-1);
213 }
214 /*
215 Do not initialize second DPC - only one thread will be created
216 */
217 a->xdi_adapter.isr_soft_isr.object = a->xdi_adapter.req_soft_isr.object;
218
219 /*
220 Create entity table
221 */
222 a->xdi_adapter.Channels = CardProperties[a->CardOrdinal].Channels;
223 a->xdi_adapter.e_max = CardProperties[a->CardOrdinal].E_info;
224 a->xdi_adapter.e_tbl = diva_os_malloc(0, a->xdi_adapter.e_max * sizeof(E_INFO));
225 if (!a->xdi_adapter.e_tbl) {
226 diva_bri_cleanup_adapter(a);
227 return (-1);
228 }
229 memset(a->xdi_adapter.e_tbl, 0x00, a->xdi_adapter.e_max * sizeof(E_INFO));
230
231 /*
232 Set up interface
233 */
234 a->xdi_adapter.a.io = &a->xdi_adapter;
235 a->xdi_adapter.DIRequest = request;
236 a->interface.cleanup_adapter_proc = diva_bri_cleanup_adapter;
237 a->interface.cmd_proc = diva_bri_cmd_card_proc;
238
239 p = DIVA_OS_MEM_ATTACH_RESET(&a->xdi_adapter);
240 outpp(p, 0x41);
241 DIVA_OS_MEM_DETACH_RESET(&a->xdi_adapter, p);
242
243 prepare_maestra_functions(&a->xdi_adapter);
244
245 a->dsp_mask = 0x00000003;
246
247 /*
248 Set IRQ handler
249 */
250 a->xdi_adapter.irq_info.irq_nr = a->resources.pci.irq;
251 sprintf(a->xdi_adapter.irq_info.irq_name, "DIVA BRI %ld",
252 (long) a->xdi_adapter.serialNo);
253 if (diva_os_register_irq(a, a->xdi_adapter.irq_info.irq_nr,
254 a->xdi_adapter.irq_info.irq_name)) {
255 diva_bri_cleanup_adapter(a);
256 return (-1);
257 }
258 a->xdi_adapter.irq_info.registered = 1;
259
260 diva_log_info("%s IRQ:%d SerNo:%d", a->xdi_adapter.Properties.Name,
261 a->resources.pci.irq, a->xdi_adapter.serialNo);
262
263 return (0);
264}
265
266
267static int diva_bri_cleanup_adapter(diva_os_xdi_adapter_t * a)
268{
269 int i;
270
271 if (a->xdi_adapter.Initialized) {
272 diva_bri_stop_adapter(a);
273 }
274
275 /*
276 Remove ISR Handler
277 */
278 if (a->xdi_adapter.irq_info.registered) {
279 diva_os_remove_irq(a, a->xdi_adapter.irq_info.irq_nr);
280 }
281 a->xdi_adapter.irq_info.registered = 0;
282
283 if (a->resources.pci.addr[0] && a->resources.pci.bar[0]) {
284 divasa_unmap_pci_bar(a->resources.pci.addr[0]);
285 a->resources.pci.addr[0] = NULL;
286 a->resources.pci.bar[0] = 0;
287 }
288
289 for (i = 1; i < 3; i++) {
290 if (a->resources.pci.addr[i] && a->resources.pci.bar[i]) {
291 diva_os_register_io_port(a, 0,
292 a->resources.pci.bar[i],
293 a->resources.pci.
294 length[i],
295 &a->port_name[0], i);
296 a->resources.pci.addr[i] = NULL;
297 a->resources.pci.bar[i] = 0;
298 }
299 }
300
301 /*
302 Free OS objects
303 */
304 diva_os_cancel_soft_isr(&a->xdi_adapter.req_soft_isr);
305 diva_os_cancel_soft_isr(&a->xdi_adapter.isr_soft_isr);
306
307 diva_os_remove_soft_isr(&a->xdi_adapter.req_soft_isr);
308 a->xdi_adapter.isr_soft_isr.object = NULL;
309
310 diva_os_destroy_spin_lock(&a->xdi_adapter.isr_spin_lock, "rm");
311 diva_os_destroy_spin_lock(&a->xdi_adapter.data_spin_lock, "rm");
312
313 /*
314 Free memory
315 */
316 if (a->xdi_adapter.e_tbl) {
317 diva_os_free(0, a->xdi_adapter.e_tbl);
318 a->xdi_adapter.e_tbl = NULL;
319 }
320
321 return (0);
322}
323
324void diva_os_prepare_maestra_functions(PISDN_ADAPTER IoAdapter)
325{
326}
327
328/*
329** Get serial number
330*/
331static dword diva_bri_get_serial_number(diva_os_xdi_adapter_t * a)
332{
333 dword serNo = 0;
334 byte __iomem *confIO;
335 word serHi, serLo;
336 word __iomem *confMem;
337
338 confIO = DIVA_OS_MEM_ATTACH_CFG(&a->xdi_adapter);
339 serHi = (word) (inppw(&confIO[0x22]) & 0x0FFF);
340 serLo = (word) (inppw(&confIO[0x26]) & 0x0FFF);
341 serNo = ((dword) serHi << 16) | (dword) serLo;
342 DIVA_OS_MEM_DETACH_CFG(&a->xdi_adapter, confIO);
343
344 if ((serNo == 0) || (serNo == 0xFFFFFFFF)) {
345 DBG_FTL(("W: BRI use BAR[0] to get card serial number"))
346
347 confMem = (word __iomem *)DIVA_OS_MEM_ATTACH_RAM(&a->xdi_adapter);
348 serHi = (word) (READ_WORD(&confMem[0x11]) & 0x0FFF);
349 serLo = (word) (READ_WORD(&confMem[0x13]) & 0x0FFF);
350 serNo = (((dword) serHi) << 16) | ((dword) serLo);
351 DIVA_OS_MEM_DETACH_RAM(&a->xdi_adapter, confMem);
352 }
353
354 DBG_LOG(("Serial Number=%ld", serNo))
355
356 return (serNo);
357}
358
359/*
360** Unregister I/O and register it with new name,
361** based on Serial Number
362*/
363static int diva_bri_reregister_io(diva_os_xdi_adapter_t * a)
364{
365 int i;
366
367 for (i = 1; i < 3; i++) {
368 diva_os_register_io_port(a, 0, a->resources.pci.bar[i],
369 a->resources.pci.length[i],
370 &a->port_name[0], i);
371 a->resources.pci.addr[i] = NULL;
372 }
373
374 sprintf(a->port_name, "DIVA BRI %ld",
375 (long) a->xdi_adapter.serialNo);
376
377 for (i = 1; i < 3; i++) {
378 if (diva_os_register_io_port(a, 1, a->resources.pci.bar[i],
379 a->resources.pci.length[i],
380 &a->port_name[0], i)) {
381 DBG_ERR(("A: failed to reregister BAR[%d]", i))
382 return (-1);
383 }
384 a->resources.pci.addr[i] =
385 (void *) (unsigned long) a->resources.pci.bar[i];
386 }
387
388 return (0);
389}
390
391/*
392** Process command from user mode
393*/
394static int
395diva_bri_cmd_card_proc(struct _diva_os_xdi_adapter *a,
396 diva_xdi_um_cfg_cmd_t * cmd, int length)
397{
398 int ret = -1;
399
400 if (cmd->adapter != a->controller) {
401 DBG_ERR(("A: pri_cmd, invalid controller=%d != %d",
402 cmd->adapter, a->controller))
403 return (-1);
404 }
405
406 switch (cmd->command) {
407 case DIVA_XDI_UM_CMD_GET_CARD_ORDINAL:
408 a->xdi_mbox.data_length = sizeof(dword);
409 a->xdi_mbox.data =
410 diva_os_malloc(0, a->xdi_mbox.data_length);
411 if (a->xdi_mbox.data) {
412 *(dword *) a->xdi_mbox.data =
413 (dword) a->CardOrdinal;
414 a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
415 ret = 0;
416 }
417 break;
418
419 case DIVA_XDI_UM_CMD_GET_SERIAL_NR:
420 a->xdi_mbox.data_length = sizeof(dword);
421 a->xdi_mbox.data =
422 diva_os_malloc(0, a->xdi_mbox.data_length);
423 if (a->xdi_mbox.data) {
424 *(dword *) a->xdi_mbox.data =
425 (dword) a->xdi_adapter.serialNo;
426 a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
427 ret = 0;
428 }
429 break;
430
431 case DIVA_XDI_UM_CMD_GET_PCI_HW_CONFIG:
432 a->xdi_mbox.data_length = sizeof(dword) * 9;
433 a->xdi_mbox.data =
434 diva_os_malloc(0, a->xdi_mbox.data_length);
435 if (a->xdi_mbox.data) {
436 int i;
437 dword *data = (dword *) a->xdi_mbox.data;
438
439 for (i = 0; i < 8; i++) {
440 *data++ = a->resources.pci.bar[i];
441 }
442 *data++ = (dword) a->resources.pci.irq;
443 a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
444 ret = 0;
445 }
446 break;
447
448 case DIVA_XDI_UM_CMD_GET_CARD_STATE:
449 a->xdi_mbox.data_length = sizeof(dword);
450 a->xdi_mbox.data =
451 diva_os_malloc(0, a->xdi_mbox.data_length);
452 if (a->xdi_mbox.data) {
453 dword *data = (dword *) a->xdi_mbox.data;
454 if (!a->xdi_adapter.port) {
455 *data = 3;
456 } else if (a->xdi_adapter.trapped) {
457 *data = 2;
458 } else if (a->xdi_adapter.Initialized) {
459 *data = 1;
460 } else {
461 *data = 0;
462 }
463 a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
464 ret = 0;
465 }
466 break;
467
468 case DIVA_XDI_UM_CMD_RESET_ADAPTER:
469 ret = diva_bri_reset_adapter(&a->xdi_adapter);
470 break;
471
472 case DIVA_XDI_UM_CMD_WRITE_SDRAM_BLOCK:
473 ret = diva_bri_write_sdram_block(&a->xdi_adapter,
474 cmd->command_data.
475 write_sdram.offset,
476 (byte *) & cmd[1],
477 cmd->command_data.
478 write_sdram.length);
479 break;
480
481 case DIVA_XDI_UM_CMD_START_ADAPTER:
482 ret = diva_bri_start_adapter(&a->xdi_adapter,
483 cmd->command_data.start.
484 offset,
485 cmd->command_data.start.
486 features);
487 break;
488
489 case DIVA_XDI_UM_CMD_SET_PROTOCOL_FEATURES:
490 a->xdi_adapter.features =
491 cmd->command_data.features.features;
492 a->xdi_adapter.a.protocol_capabilities =
493 a->xdi_adapter.features;
494 DBG_TRC(
495 ("Set raw protocol features (%08x)",
496 a->xdi_adapter.features)) ret = 0;
497 break;
498
499 case DIVA_XDI_UM_CMD_STOP_ADAPTER:
500 ret = diva_bri_stop_adapter(a);
501 break;
502
503 case DIVA_XDI_UM_CMD_READ_XLOG_ENTRY:
504 ret = diva_card_read_xlog(a);
505 break;
506
507 default:
508 DBG_ERR(
509 ("A: A(%d) invalid cmd=%d", a->controller,
510 cmd->command))}
511
512 return (ret);
513}
514
515static int diva_bri_reset_adapter(PISDN_ADAPTER IoAdapter)
516{
517 byte __iomem *addrHi, *addrLo, *ioaddr;
518 dword i;
519 byte __iomem *Port;
520
521 if (!IoAdapter->port) {
522 return (-1);
523 }
524 if (IoAdapter->Initialized) {
525 DBG_ERR(("A: A(%d) can't reset BRI adapter - please stop first",
526 IoAdapter->ANum)) return (-1);
527 }
528 (*(IoAdapter->rstFnc)) (IoAdapter);
529 diva_os_wait(100);
530 Port = DIVA_OS_MEM_ATTACH_PORT(IoAdapter);
531 addrHi = Port +
532 ((IoAdapter->Properties.Bus == BUS_PCI) ? M_PCI_ADDRH : ADDRH);
533 addrLo = Port + ADDR;
534 ioaddr = Port + DATA;
535 /*
536 recover
537 */
538 outpp(addrHi, (byte) 0);
539 outppw(addrLo, (word) 0);
540 outppw(ioaddr, (word) 0);
541 /*
542 clear shared memory
543 */
544 outpp(addrHi,
545 (byte) (
546 (IoAdapter->MemoryBase + IoAdapter->MemorySize -
547 BRI_SHARED_RAM_SIZE) >> 16));
548 outppw(addrLo, 0);
549 for (i = 0; i < 0x8000; outppw(ioaddr, 0), ++i);
550 diva_os_wait(100);
551
552 /*
553 clear signature
554 */
555 outpp(addrHi,
556 (byte) (
557 (IoAdapter->MemoryBase + IoAdapter->MemorySize -
558 BRI_SHARED_RAM_SIZE) >> 16));
559 outppw(addrLo, 0x1e);
560 outpp(ioaddr, 0);
561 outpp(ioaddr, 0);
562
563 outpp(addrHi, (byte) 0);
564 outppw(addrLo, (word) 0);
565 outppw(ioaddr, (word) 0);
566
567 DIVA_OS_MEM_DETACH_PORT(IoAdapter, Port);
568
569 /*
570 Forget all outstanding entities
571 */
572 IoAdapter->e_count = 0;
573 if (IoAdapter->e_tbl) {
574 memset(IoAdapter->e_tbl, 0x00,
575 IoAdapter->e_max * sizeof(E_INFO));
576 }
577 IoAdapter->head = 0;
578 IoAdapter->tail = 0;
579 IoAdapter->assign = 0;
580 IoAdapter->trapped = 0;
581
582 memset(&IoAdapter->a.IdTable[0], 0x00,
583 sizeof(IoAdapter->a.IdTable));
584 memset(&IoAdapter->a.IdTypeTable[0], 0x00,
585 sizeof(IoAdapter->a.IdTypeTable));
586 memset(&IoAdapter->a.FlowControlIdTable[0], 0x00,
587 sizeof(IoAdapter->a.FlowControlIdTable));
588 memset(&IoAdapter->a.FlowControlSkipTable[0], 0x00,
589 sizeof(IoAdapter->a.FlowControlSkipTable));
590 memset(&IoAdapter->a.misc_flags_table[0], 0x00,
591 sizeof(IoAdapter->a.misc_flags_table));
592 memset(&IoAdapter->a.rx_stream[0], 0x00,
593 sizeof(IoAdapter->a.rx_stream));
594 memset(&IoAdapter->a.tx_stream[0], 0x00,
595 sizeof(IoAdapter->a.tx_stream));
596 memset(&IoAdapter->a.tx_pos[0], 0x00, sizeof(IoAdapter->a.tx_pos));
597 memset(&IoAdapter->a.rx_pos[0], 0x00, sizeof(IoAdapter->a.rx_pos));
598
599 return (0);
600}
601
602static int
603diva_bri_write_sdram_block(PISDN_ADAPTER IoAdapter,
604 dword address, const byte * data, dword length)
605{
606 byte __iomem *addrHi, *addrLo, *ioaddr;
607 byte __iomem *Port;
608
609 if (!IoAdapter->port) {
610 return (-1);
611 }
612
613 Port = DIVA_OS_MEM_ATTACH_PORT(IoAdapter);
614 addrHi = Port +
615 ((IoAdapter->Properties.Bus == BUS_PCI) ? M_PCI_ADDRH : ADDRH);
616 addrLo = Port + ADDR;
617 ioaddr = Port + DATA;
618
619 while (length--) {
620 outpp(addrHi, (word) (address >> 16));
621 outppw(addrLo, (word) (address & 0x0000ffff));
622 outpp(ioaddr, *data++);
623 address++;
624 }
625
626 DIVA_OS_MEM_DETACH_PORT(IoAdapter, Port);
627 return (0);
628}
629
630static int
631diva_bri_start_adapter(PISDN_ADAPTER IoAdapter,
632 dword start_address, dword features)
633{
634 byte __iomem *Port;
635 dword i, test;
636 byte __iomem *addrHi, *addrLo, *ioaddr;
637 int started = 0;
638 ADAPTER *a = &IoAdapter->a;
639
640 if (IoAdapter->Initialized) {
641 DBG_ERR(
642 ("A: A(%d) bri_start_adapter, adapter already running",
643 IoAdapter->ANum)) return (-1);
644 }
645 if (!IoAdapter->port) {
646 DBG_ERR(("A: A(%d) bri_start_adapter, adapter not mapped",
647 IoAdapter->ANum)) return (-1);
648 }
649
650 sprintf(IoAdapter->Name, "A(%d)", (int) IoAdapter->ANum);
651 DBG_LOG(("A(%d) start BRI", IoAdapter->ANum))
652
653 Port = DIVA_OS_MEM_ATTACH_PORT(IoAdapter);
654 addrHi = Port +
655 ((IoAdapter->Properties.Bus == BUS_PCI) ? M_PCI_ADDRH : ADDRH);
656 addrLo = Port + ADDR;
657 ioaddr = Port + DATA;
658
659 outpp(addrHi,
660 (byte) (
661 (IoAdapter->MemoryBase + IoAdapter->MemorySize -
662 BRI_SHARED_RAM_SIZE) >> 16));
663 outppw(addrLo, 0x1e);
664 outppw(ioaddr, 0x00);
665 DIVA_OS_MEM_DETACH_PORT(IoAdapter, Port);
666
667 /*
668 start the protocol code
669 */
670 Port = DIVA_OS_MEM_ATTACH_CTLREG(IoAdapter);
671 outpp(Port, 0x08);
672 DIVA_OS_MEM_DETACH_CTLREG(IoAdapter, Port);
673
674 Port = DIVA_OS_MEM_ATTACH_PORT(IoAdapter);
675 addrHi = Port +
676 ((IoAdapter->Properties.Bus == BUS_PCI) ? M_PCI_ADDRH : ADDRH);
677 addrLo = Port + ADDR;
678 ioaddr = Port + DATA;
679 /*
680 wait for signature (max. 3 seconds)
681 */
682 for (i = 0; i < 300; ++i) {
683 diva_os_wait(10);
684 outpp(addrHi,
685 (byte) (
686 (IoAdapter->MemoryBase +
687 IoAdapter->MemorySize -
688 BRI_SHARED_RAM_SIZE) >> 16));
689 outppw(addrLo, 0x1e);
690 test = (dword) inppw(ioaddr);
691 if (test == 0x4447) {
692 DBG_LOG(
693 ("Protocol startup time %d.%02d seconds",
694 (i / 100), (i % 100)))
695 started = 1;
696 break;
697 }
698 }
699 DIVA_OS_MEM_DETACH_PORT(IoAdapter, Port);
700
701 if (!started) {
702 DBG_FTL(("A: A(%d) %s: Adapter selftest failed 0x%04X",
703 IoAdapter->ANum, IoAdapter->Properties.Name,
704 test))
705 (*(IoAdapter->trapFnc)) (IoAdapter);
706 return (-1);
707 }
708
709 IoAdapter->Initialized = 1;
710
711 /*
712 Check Interrupt
713 */
714 IoAdapter->IrqCount = 0;
715 a->ReadyInt = 1;
716
717 if (IoAdapter->reset) {
718 Port = DIVA_OS_MEM_ATTACH_RESET(IoAdapter);
719 outpp(Port, 0x41);
720 DIVA_OS_MEM_DETACH_RESET(IoAdapter, Port);
721 }
722
723 a->ram_out(a, &PR_RAM->ReadyInt, 1);
724 for (i = 0; ((!IoAdapter->IrqCount) && (i < 100)); i++) {
725 diva_os_wait(10);
726 }
727 if (!IoAdapter->IrqCount) {
728 DBG_ERR(
729 ("A: A(%d) interrupt test failed",
730 IoAdapter->ANum))
731 IoAdapter->Initialized = 0;
732 IoAdapter->stop(IoAdapter);
733 return (-1);
734 }
735
736 IoAdapter->Properties.Features = (word) features;
737 diva_xdi_display_adapter_features(IoAdapter->ANum);
738 DBG_LOG(("A(%d) BRI adapter successfull started", IoAdapter->ANum))
739 /*
740 Register with DIDD
741 */
742 diva_xdi_didd_register_adapter(IoAdapter->ANum);
743
744 return (0);
745}
746
747static void diva_bri_clear_interrupts(diva_os_xdi_adapter_t * a)
748{
749 PISDN_ADAPTER IoAdapter = &a->xdi_adapter;
750
751 /*
752 clear any pending interrupt
753 */
754 IoAdapter->disIrq(IoAdapter);
755
756 IoAdapter->tst_irq(&IoAdapter->a);
757 IoAdapter->clr_irq(&IoAdapter->a);
758 IoAdapter->tst_irq(&IoAdapter->a);
759
760 /*
761 kill pending dpcs
762 */
763 diva_os_cancel_soft_isr(&IoAdapter->req_soft_isr);
764 diva_os_cancel_soft_isr(&IoAdapter->isr_soft_isr);
765}
766
767/*
768** Stop card
769*/
770static int diva_bri_stop_adapter(diva_os_xdi_adapter_t * a)
771{
772 PISDN_ADAPTER IoAdapter = &a->xdi_adapter;
773 int i = 100;
774
775 if (!IoAdapter->port) {
776 return (-1);
777 }
778 if (!IoAdapter->Initialized) {
779 DBG_ERR(("A: A(%d) can't stop BRI adapter - not running",
780 IoAdapter->ANum))
781 return (-1); /* nothing to stop */
782 }
783 IoAdapter->Initialized = 0;
784
785 /*
786 Disconnect Adapter from DIDD
787 */
788 diva_xdi_didd_remove_adapter(IoAdapter->ANum);
789
790 /*
791 Stop interrupts
792 */
793 a->clear_interrupts_proc = diva_bri_clear_interrupts;
794 IoAdapter->a.ReadyInt = 1;
795 IoAdapter->a.ram_inc(&IoAdapter->a, &PR_RAM->ReadyInt);
796 do {
797 diva_os_sleep(10);
798 } while (i-- && a->clear_interrupts_proc);
799 if (a->clear_interrupts_proc) {
800 diva_bri_clear_interrupts(a);
801 a->clear_interrupts_proc = NULL;
802 DBG_ERR(("A: A(%d) no final interrupt from BRI adapter",
803 IoAdapter->ANum))
804 }
805 IoAdapter->a.ReadyInt = 0;
806
807 /*
808 Stop and reset adapter
809 */
810 IoAdapter->stop(IoAdapter);
811
812 return (0);
813}
diff --git a/drivers/isdn/hardware/eicon/os_bri.h b/drivers/isdn/hardware/eicon/os_bri.h
new file mode 100644
index 000000000000..a54f0ce58e13
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/os_bri.h
@@ -0,0 +1,8 @@
1/* $Id: os_bri.h,v 1.1.2.2 2001/02/08 12:25:44 armin Exp $ */
2
3#ifndef __DIVA_OS_BRI_REV_1_H__
4#define __DIVA_OS_BRI_REV_1_H__
5
6int diva_bri_init_card(diva_os_xdi_adapter_t * a);
7
8#endif
diff --git a/drivers/isdn/hardware/eicon/os_capi.h b/drivers/isdn/hardware/eicon/os_capi.h
new file mode 100644
index 000000000000..726f915a09e5
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/os_capi.h
@@ -0,0 +1,21 @@
1/* $Id: os_capi.h,v 1.7 2003/04/12 21:40:49 schindler Exp $
2 *
3 * ISDN interface module for Eicon active cards DIVA.
4 * CAPI Interface OS include files
5 *
6 * Copyright 2000-2003 by Armin Schindler (mac@melware.de)
7 * Copyright 2000-2003 Cytronics & Melware (info@melware.de)
8 *
9 * This software may be used and distributed according to the terms
10 * of the GNU General Public License, incorporated herein by reference.
11 */
12
13#ifndef __OS_CAPI_H__
14#define __OS_CAPI_H__
15
16#include <linux/capi.h>
17#include <linux/kernelcapi.h>
18#include <linux/isdn/capiutil.h>
19#include <linux/isdn/capilli.h>
20
21#endif /* __OS_CAPI_H__ */
diff --git a/drivers/isdn/hardware/eicon/os_pri.c b/drivers/isdn/hardware/eicon/os_pri.c
new file mode 100644
index 000000000000..8ac207f75e54
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/os_pri.c
@@ -0,0 +1,1051 @@
1/* $Id: os_pri.c,v 1.32 2004/03/21 17:26:01 armin Exp $ */
2
3#include "platform.h"
4#include "debuglib.h"
5#include "cardtype.h"
6#include "pc.h"
7#include "pr_pc.h"
8#include "di_defs.h"
9#include "dsp_defs.h"
10#include "di.h"
11#include "io.h"
12
13#include "xdi_msg.h"
14#include "xdi_adapter.h"
15#include "os_pri.h"
16#include "diva_pci.h"
17#include "mi_pc.h"
18#include "pc_maint.h"
19#include "dsp_tst.h"
20#include "diva_dma.h"
21
22/* --------------------------------------------------------------------------
23 OS Dependent part of XDI driver for DIVA PRI Adapter
24
25 DSP detection/validation by Anthony Booth (Eicon Networks, www.eicon.com)
26-------------------------------------------------------------------------- */
27
28#define DIVA_PRI_NO_PCI_BIOS_WORKAROUND 1
29
30extern int diva_card_read_xlog(diva_os_xdi_adapter_t * a);
31
32/*
33** IMPORTS
34*/
35extern void prepare_pri_functions(PISDN_ADAPTER IoAdapter);
36extern void prepare_pri2_functions(PISDN_ADAPTER IoAdapter);
37extern void diva_xdi_display_adapter_features(int card);
38
39static int diva_pri_cleanup_adapter(diva_os_xdi_adapter_t * a);
40static int diva_pri_cmd_card_proc(struct _diva_os_xdi_adapter *a,
41 diva_xdi_um_cfg_cmd_t * cmd, int length);
42static int pri_get_serial_number(diva_os_xdi_adapter_t * a);
43static int diva_pri_stop_adapter(diva_os_xdi_adapter_t * a);
44static dword diva_pri_detect_dsps(diva_os_xdi_adapter_t * a);
45
46/*
47** Check card revision
48*/
49static int pri_is_rev_2_card(int card_ordinal)
50{
51 switch (card_ordinal) {
52 case CARDTYPE_DIVASRV_P_30M_V2_PCI:
53 case CARDTYPE_DIVASRV_VOICE_P_30M_V2_PCI:
54 return (1);
55 }
56 return (0);
57}
58
59static void diva_pri_set_addresses(diva_os_xdi_adapter_t * a)
60{
61 a->resources.pci.mem_type_id[MEM_TYPE_ADDRESS] = 0;
62 a->resources.pci.mem_type_id[MEM_TYPE_CONTROL] = 2;
63 a->resources.pci.mem_type_id[MEM_TYPE_CONFIG] = 4;
64 a->resources.pci.mem_type_id[MEM_TYPE_RAM] = 0;
65 a->resources.pci.mem_type_id[MEM_TYPE_RESET] = 2;
66 a->resources.pci.mem_type_id[MEM_TYPE_CFG] = 4;
67 a->resources.pci.mem_type_id[MEM_TYPE_PROM] = 3;
68
69 a->xdi_adapter.Address = a->resources.pci.addr[0];
70 a->xdi_adapter.Control = a->resources.pci.addr[2];
71 a->xdi_adapter.Config = a->resources.pci.addr[4];
72
73 a->xdi_adapter.ram = a->resources.pci.addr[0];
74 a->xdi_adapter.ram += MP_SHARED_RAM_OFFSET;
75
76 a->xdi_adapter.reset = a->resources.pci.addr[2];
77 a->xdi_adapter.reset += MP_RESET;
78
79 a->xdi_adapter.cfg = a->resources.pci.addr[4];
80 a->xdi_adapter.cfg += MP_IRQ_RESET;
81
82 a->xdi_adapter.sdram_bar = a->resources.pci.bar[0];
83
84 a->xdi_adapter.prom = a->resources.pci.addr[3];
85}
86
87/*
88** BAR0 - SDRAM, MP_MEMORY_SIZE, MP2_MEMORY_SIZE by Rev.2
89** BAR1 - DEVICES, 0x1000
90** BAR2 - CONTROL (REG), 0x2000
91** BAR3 - FLASH (REG), 0x8000
92** BAR4 - CONFIG (CFG), 0x1000
93*/
94int diva_pri_init_card(diva_os_xdi_adapter_t * a)
95{
96 int bar = 0;
97 int pri_rev_2;
98 unsigned long bar_length[5] = {
99 MP_MEMORY_SIZE,
100 0x1000,
101 0x2000,
102 0x8000,
103 0x1000
104 };
105
106 pri_rev_2 = pri_is_rev_2_card(a->CardOrdinal);
107
108 if (pri_rev_2) {
109 bar_length[0] = MP2_MEMORY_SIZE;
110 }
111 /*
112 Set properties
113 */
114 a->xdi_adapter.Properties = CardProperties[a->CardOrdinal];
115 DBG_LOG(("Load %s", a->xdi_adapter.Properties.Name))
116
117 /*
118 First initialization step: get and check hardware resoures.
119 Do not map resources and do not acecess card at this step
120 */
121 for (bar = 0; bar < 5; bar++) {
122 a->resources.pci.bar[bar] =
123 divasa_get_pci_bar(a->resources.pci.bus,
124 a->resources.pci.func, bar,
125 a->resources.pci.hdev);
126 if (!a->resources.pci.bar[bar]
127 || (a->resources.pci.bar[bar] == 0xFFFFFFF0)) {
128 DBG_ERR(("A: invalid bar[%d]=%08x", bar,
129 a->resources.pci.bar[bar]))
130 return (-1);
131 }
132 }
133 a->resources.pci.irq =
134 (byte) divasa_get_pci_irq(a->resources.pci.bus,
135 a->resources.pci.func,
136 a->resources.pci.hdev);
137 if (!a->resources.pci.irq) {
138 DBG_ERR(("A: invalid irq"));
139 return (-1);
140 }
141
142 /*
143 Map all BAR's
144 */
145 for (bar = 0; bar < 5; bar++) {
146 a->resources.pci.addr[bar] =
147 divasa_remap_pci_bar(a, bar, a->resources.pci.bar[bar],
148 bar_length[bar]);
149 if (!a->resources.pci.addr[bar]) {
150 DBG_ERR(("A: A(%d), can't map bar[%d]",
151 a->controller, bar))
152 diva_pri_cleanup_adapter(a);
153 return (-1);
154 }
155 }
156
157 /*
158 Set all memory areas
159 */
160 diva_pri_set_addresses(a);
161
162 /*
163 Get Serial Number of this adapter
164 */
165 if (pri_get_serial_number(a)) {
166 dword serNo;
167 serNo = a->resources.pci.bar[1] & 0xffff0000;
168 serNo |= ((dword) a->resources.pci.bus) << 8;
169 serNo += (a->resources.pci.func + a->controller + 1);
170 a->xdi_adapter.serialNo = serNo & ~0xFF000000;
171 DBG_ERR(("A: A(%d) can't get Serial Number, generated serNo=%ld",
172 a->controller, a->xdi_adapter.serialNo))
173 }
174
175
176 /*
177 Initialize os objects
178 */
179 if (diva_os_initialize_spin_lock(&a->xdi_adapter.isr_spin_lock, "isr")) {
180 diva_pri_cleanup_adapter(a);
181 return (-1);
182 }
183 if (diva_os_initialize_spin_lock
184 (&a->xdi_adapter.data_spin_lock, "data")) {
185 diva_pri_cleanup_adapter(a);
186 return (-1);
187 }
188
189 strcpy(a->xdi_adapter.req_soft_isr.dpc_thread_name, "kdivasprid");
190
191 if (diva_os_initialize_soft_isr(&a->xdi_adapter.req_soft_isr,
192 DIDpcRoutine, &a->xdi_adapter)) {
193 diva_pri_cleanup_adapter(a);
194 return (-1);
195 }
196
197 /*
198 Do not initialize second DPC - only one thread will be created
199 */
200 a->xdi_adapter.isr_soft_isr.object =
201 a->xdi_adapter.req_soft_isr.object;
202
203 /*
204 Next step of card initialization:
205 set up all interface pointers
206 */
207 a->xdi_adapter.Channels = CardProperties[a->CardOrdinal].Channels;
208 a->xdi_adapter.e_max = CardProperties[a->CardOrdinal].E_info;
209
210 a->xdi_adapter.e_tbl =
211 diva_os_malloc(0, a->xdi_adapter.e_max * sizeof(E_INFO));
212 if (!a->xdi_adapter.e_tbl) {
213 diva_pri_cleanup_adapter(a);
214 return (-1);
215 }
216 memset(a->xdi_adapter.e_tbl, 0x00, a->xdi_adapter.e_max * sizeof(E_INFO));
217
218 a->xdi_adapter.a.io = &a->xdi_adapter;
219 a->xdi_adapter.DIRequest = request;
220 a->interface.cleanup_adapter_proc = diva_pri_cleanup_adapter;
221 a->interface.cmd_proc = diva_pri_cmd_card_proc;
222
223 if (pri_rev_2) {
224 prepare_pri2_functions(&a->xdi_adapter);
225 } else {
226 prepare_pri_functions(&a->xdi_adapter);
227 }
228
229 a->dsp_mask = diva_pri_detect_dsps(a);
230
231 /*
232 Allocate DMA map
233 */
234 if (pri_rev_2) {
235 diva_init_dma_map(a->resources.pci.hdev,
236 (struct _diva_dma_map_entry **) &a->xdi_adapter.dma_map, 32);
237 }
238
239 /*
240 Set IRQ handler
241 */
242 a->xdi_adapter.irq_info.irq_nr = a->resources.pci.irq;
243 sprintf(a->xdi_adapter.irq_info.irq_name,
244 "DIVA PRI %ld", (long) a->xdi_adapter.serialNo);
245
246 if (diva_os_register_irq(a, a->xdi_adapter.irq_info.irq_nr,
247 a->xdi_adapter.irq_info.irq_name)) {
248 diva_pri_cleanup_adapter(a);
249 return (-1);
250 }
251 a->xdi_adapter.irq_info.registered = 1;
252
253 diva_log_info("%s IRQ:%d SerNo:%d", a->xdi_adapter.Properties.Name,
254 a->resources.pci.irq, a->xdi_adapter.serialNo);
255
256 return (0);
257}
258
259static int diva_pri_cleanup_adapter(diva_os_xdi_adapter_t * a)
260{
261 int bar = 0;
262
263 /*
264 Stop Adapter if adapter is running
265 */
266 if (a->xdi_adapter.Initialized) {
267 diva_pri_stop_adapter(a);
268 }
269
270 /*
271 Remove ISR Handler
272 */
273 if (a->xdi_adapter.irq_info.registered) {
274 diva_os_remove_irq(a, a->xdi_adapter.irq_info.irq_nr);
275 }
276 a->xdi_adapter.irq_info.registered = 0;
277
278 /*
279 Step 1: unmap all BAR's, if any was mapped
280 */
281 for (bar = 0; bar < 5; bar++) {
282 if (a->resources.pci.bar[bar]
283 && a->resources.pci.addr[bar]) {
284 divasa_unmap_pci_bar(a->resources.pci.addr[bar]);
285 a->resources.pci.bar[bar] = 0;
286 a->resources.pci.addr[bar] = NULL;
287 }
288 }
289
290 /*
291 Free OS objects
292 */
293 diva_os_cancel_soft_isr(&a->xdi_adapter.isr_soft_isr);
294 diva_os_cancel_soft_isr(&a->xdi_adapter.req_soft_isr);
295
296 diva_os_remove_soft_isr(&a->xdi_adapter.req_soft_isr);
297 a->xdi_adapter.isr_soft_isr.object = NULL;
298
299 diva_os_destroy_spin_lock(&a->xdi_adapter.isr_spin_lock, "rm");
300 diva_os_destroy_spin_lock(&a->xdi_adapter.data_spin_lock, "rm");
301
302 /*
303 Free memory accupied by XDI adapter
304 */
305 if (a->xdi_adapter.e_tbl) {
306 diva_os_free(0, a->xdi_adapter.e_tbl);
307 a->xdi_adapter.e_tbl = NULL;
308 }
309 a->xdi_adapter.Channels = 0;
310 a->xdi_adapter.e_max = 0;
311
312
313 /*
314 Free adapter DMA map
315 */
316 diva_free_dma_map(a->resources.pci.hdev,
317 (struct _diva_dma_map_entry *) a->xdi_adapter.
318 dma_map);
319 a->xdi_adapter.dma_map = NULL;
320
321
322 /*
323 Detach this adapter from debug driver
324 */
325
326 return (0);
327}
328
329/*
330** Activate On Board Boot Loader
331*/
332static int diva_pri_reset_adapter(PISDN_ADAPTER IoAdapter)
333{
334 dword i;
335 struct mp_load __iomem *boot;
336
337 if (!IoAdapter->Address || !IoAdapter->reset) {
338 return (-1);
339 }
340 if (IoAdapter->Initialized) {
341 DBG_ERR(("A: A(%d) can't reset PRI adapter - please stop first",
342 IoAdapter->ANum))
343 return (-1);
344 }
345
346 boot = (struct mp_load __iomem *) DIVA_OS_MEM_ATTACH_ADDRESS(IoAdapter);
347 WRITE_DWORD(&boot->err, 0);
348 DIVA_OS_MEM_DETACH_ADDRESS(IoAdapter, boot);
349
350 IoAdapter->rstFnc(IoAdapter);
351
352 diva_os_wait(10);
353
354 boot = (struct mp_load __iomem *) DIVA_OS_MEM_ATTACH_ADDRESS(IoAdapter);
355 i = READ_DWORD(&boot->live);
356
357 diva_os_wait(10);
358 if (i == READ_DWORD(&boot->live)) {
359 DIVA_OS_MEM_DETACH_ADDRESS(IoAdapter, boot);
360 DBG_ERR(("A: A(%d) CPU on PRI %ld is not alive!",
361 IoAdapter->ANum, IoAdapter->serialNo))
362 return (-1);
363 }
364 if (READ_DWORD(&boot->err)) {
365 DBG_ERR(("A: A(%d) PRI %ld Board Selftest failed, error=%08lx",
366 IoAdapter->ANum, IoAdapter->serialNo,
367 READ_DWORD(&boot->err)))
368 DIVA_OS_MEM_DETACH_ADDRESS(IoAdapter, boot);
369 return (-1);
370 }
371 DIVA_OS_MEM_DETACH_ADDRESS(IoAdapter, boot);
372
373 /*
374 Forget all outstanding entities
375 */
376 IoAdapter->e_count = 0;
377 if (IoAdapter->e_tbl) {
378 memset(IoAdapter->e_tbl, 0x00,
379 IoAdapter->e_max * sizeof(E_INFO));
380 }
381 IoAdapter->head = 0;
382 IoAdapter->tail = 0;
383 IoAdapter->assign = 0;
384 IoAdapter->trapped = 0;
385
386 memset(&IoAdapter->a.IdTable[0], 0x00,
387 sizeof(IoAdapter->a.IdTable));
388 memset(&IoAdapter->a.IdTypeTable[0], 0x00,
389 sizeof(IoAdapter->a.IdTypeTable));
390 memset(&IoAdapter->a.FlowControlIdTable[0], 0x00,
391 sizeof(IoAdapter->a.FlowControlIdTable));
392 memset(&IoAdapter->a.FlowControlSkipTable[0], 0x00,
393 sizeof(IoAdapter->a.FlowControlSkipTable));
394 memset(&IoAdapter->a.misc_flags_table[0], 0x00,
395 sizeof(IoAdapter->a.misc_flags_table));
396 memset(&IoAdapter->a.rx_stream[0], 0x00,
397 sizeof(IoAdapter->a.rx_stream));
398 memset(&IoAdapter->a.tx_stream[0], 0x00,
399 sizeof(IoAdapter->a.tx_stream));
400 memset(&IoAdapter->a.tx_pos[0], 0x00, sizeof(IoAdapter->a.tx_pos));
401 memset(&IoAdapter->a.rx_pos[0], 0x00, sizeof(IoAdapter->a.rx_pos));
402
403 return (0);
404}
405
406static int
407diva_pri_write_sdram_block(PISDN_ADAPTER IoAdapter,
408 dword address,
409 const byte * data, dword length, dword limit)
410{
411 byte __iomem *p = DIVA_OS_MEM_ATTACH_ADDRESS(IoAdapter);
412 byte __iomem *mem = p;
413
414 if (((address + length) >= limit) || !mem) {
415 DIVA_OS_MEM_DETACH_ADDRESS(IoAdapter, p);
416 DBG_ERR(("A: A(%d) write PRI address=0x%08lx",
417 IoAdapter->ANum, address + length))
418 return (-1);
419 }
420 mem += address;
421
422 /* memcpy_toio(), maybe? */
423 while (length--) {
424 WRITE_BYTE(mem++, *data++);
425 }
426
427 DIVA_OS_MEM_DETACH_ADDRESS(IoAdapter, p);
428 return (0);
429}
430
431static int
432diva_pri_start_adapter(PISDN_ADAPTER IoAdapter,
433 dword start_address, dword features)
434{
435 dword i;
436 int started = 0;
437 byte __iomem *p;
438 struct mp_load __iomem *boot = (struct mp_load __iomem *) DIVA_OS_MEM_ATTACH_ADDRESS(IoAdapter);
439 ADAPTER *a = &IoAdapter->a;
440
441 if (IoAdapter->Initialized) {
442 DIVA_OS_MEM_DETACH_ADDRESS(IoAdapter, boot);
443 DBG_ERR(("A: A(%d) pri_start_adapter, adapter already running",
444 IoAdapter->ANum))
445 return (-1);
446 }
447 if (!boot) {
448 DIVA_OS_MEM_DETACH_ADDRESS(IoAdapter, boot);
449 DBG_ERR(("A: PRI %ld can't start, adapter not mapped",
450 IoAdapter->serialNo))
451 return (-1);
452 }
453
454 sprintf(IoAdapter->Name, "A(%d)", (int) IoAdapter->ANum);
455 DBG_LOG(("A(%d) start PRI at 0x%08lx", IoAdapter->ANum,
456 start_address))
457
458 WRITE_DWORD(&boot->addr, start_address);
459 WRITE_DWORD(&boot->cmd, 3);
460
461 for (i = 0; i < 300; ++i) {
462 diva_os_wait(10);
463 if ((READ_DWORD(&boot->signature) >> 16) == 0x4447) {
464 DBG_LOG(("A(%d) Protocol startup time %d.%02d seconds",
465 IoAdapter->ANum, (i / 100), (i % 100)))
466 started = 1;
467 break;
468 }
469 }
470
471 if (!started) {
472 byte __iomem *p = (byte __iomem *)boot;
473 dword TrapId;
474 dword debug;
475 TrapId = READ_DWORD(&p[0x80]);
476 debug = READ_DWORD(&p[0x1c]);
477 DBG_ERR(("A(%d) Adapter start failed 0x%08lx, TrapId=%08lx, debug=%08lx",
478 IoAdapter->ANum, READ_DWORD(&boot->signature),
479 TrapId, debug))
480 DIVA_OS_MEM_DETACH_ADDRESS(IoAdapter, boot);
481 if (IoAdapter->trapFnc) {
482 (*(IoAdapter->trapFnc)) (IoAdapter);
483 }
484 IoAdapter->stop(IoAdapter);
485 return (-1);
486 }
487 DIVA_OS_MEM_DETACH_ADDRESS(IoAdapter, boot);
488
489 IoAdapter->Initialized = TRUE;
490
491 /*
492 Check Interrupt
493 */
494 IoAdapter->IrqCount = 0;
495 p = DIVA_OS_MEM_ATTACH_CFG(IoAdapter);
496 WRITE_DWORD(p, (dword) ~ 0x03E00000);
497 DIVA_OS_MEM_DETACH_CFG(IoAdapter, p);
498 a->ReadyInt = 1;
499 a->ram_out(a, &PR_RAM->ReadyInt, 1);
500
501 for (i = 100; !IoAdapter->IrqCount && (i-- > 0); diva_os_wait(10));
502
503 if (!IoAdapter->IrqCount) {
504 DBG_ERR(("A: A(%d) interrupt test failed",
505 IoAdapter->ANum))
506 IoAdapter->Initialized = FALSE;
507 IoAdapter->stop(IoAdapter);
508 return (-1);
509 }
510
511 IoAdapter->Properties.Features = (word) features;
512
513 diva_xdi_display_adapter_features(IoAdapter->ANum);
514
515 DBG_LOG(("A(%d) PRI adapter successfull started", IoAdapter->ANum))
516 /*
517 Register with DIDD
518 */
519 diva_xdi_didd_register_adapter(IoAdapter->ANum);
520
521 return (0);
522}
523
524static void diva_pri_clear_interrupts(diva_os_xdi_adapter_t * a)
525{
526 PISDN_ADAPTER IoAdapter = &a->xdi_adapter;
527
528 /*
529 clear any pending interrupt
530 */
531 IoAdapter->disIrq(IoAdapter);
532
533 IoAdapter->tst_irq(&IoAdapter->a);
534 IoAdapter->clr_irq(&IoAdapter->a);
535 IoAdapter->tst_irq(&IoAdapter->a);
536
537 /*
538 kill pending dpcs
539 */
540 diva_os_cancel_soft_isr(&IoAdapter->req_soft_isr);
541 diva_os_cancel_soft_isr(&IoAdapter->isr_soft_isr);
542}
543
544/*
545** Stop Adapter, but do not unmap/unregister - adapter
546** will be restarted later
547*/
548static int diva_pri_stop_adapter(diva_os_xdi_adapter_t * a)
549{
550 PISDN_ADAPTER IoAdapter = &a->xdi_adapter;
551 int i = 100;
552
553 if (!IoAdapter->ram) {
554 return (-1);
555 }
556 if (!IoAdapter->Initialized) {
557 DBG_ERR(("A: A(%d) can't stop PRI adapter - not running",
558 IoAdapter->ANum))
559 return (-1); /* nothing to stop */
560 }
561 IoAdapter->Initialized = 0;
562
563 /*
564 Disconnect Adapter from DIDD
565 */
566 diva_xdi_didd_remove_adapter(IoAdapter->ANum);
567
568 /*
569 Stop interrupts
570 */
571 a->clear_interrupts_proc = diva_pri_clear_interrupts;
572 IoAdapter->a.ReadyInt = 1;
573 IoAdapter->a.ram_inc(&IoAdapter->a, &PR_RAM->ReadyInt);
574 do {
575 diva_os_sleep(10);
576 } while (i-- && a->clear_interrupts_proc);
577
578 if (a->clear_interrupts_proc) {
579 diva_pri_clear_interrupts(a);
580 a->clear_interrupts_proc = NULL;
581 DBG_ERR(("A: A(%d) no final interrupt from PRI adapter",
582 IoAdapter->ANum))
583 }
584 IoAdapter->a.ReadyInt = 0;
585
586 /*
587 Stop and reset adapter
588 */
589 IoAdapter->stop(IoAdapter);
590
591 return (0);
592}
593
594/*
595** Process commands form configuration/download framework and from
596** user mode
597**
598** return 0 on success
599*/
600static int
601diva_pri_cmd_card_proc(struct _diva_os_xdi_adapter *a,
602 diva_xdi_um_cfg_cmd_t * cmd, int length)
603{
604 int ret = -1;
605
606 if (cmd->adapter != a->controller) {
607 DBG_ERR(("A: pri_cmd, invalid controller=%d != %d",
608 cmd->adapter, a->controller))
609 return (-1);
610 }
611
612 switch (cmd->command) {
613 case DIVA_XDI_UM_CMD_GET_CARD_ORDINAL:
614 a->xdi_mbox.data_length = sizeof(dword);
615 a->xdi_mbox.data =
616 diva_os_malloc(0, a->xdi_mbox.data_length);
617 if (a->xdi_mbox.data) {
618 *(dword *) a->xdi_mbox.data =
619 (dword) a->CardOrdinal;
620 a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
621 ret = 0;
622 }
623 break;
624
625 case DIVA_XDI_UM_CMD_GET_SERIAL_NR:
626 a->xdi_mbox.data_length = sizeof(dword);
627 a->xdi_mbox.data =
628 diva_os_malloc(0, a->xdi_mbox.data_length);
629 if (a->xdi_mbox.data) {
630 *(dword *) a->xdi_mbox.data =
631 (dword) a->xdi_adapter.serialNo;
632 a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
633 ret = 0;
634 }
635 break;
636
637 case DIVA_XDI_UM_CMD_GET_PCI_HW_CONFIG:
638 a->xdi_mbox.data_length = sizeof(dword) * 9;
639 a->xdi_mbox.data =
640 diva_os_malloc(0, a->xdi_mbox.data_length);
641 if (a->xdi_mbox.data) {
642 int i;
643 dword *data = (dword *) a->xdi_mbox.data;
644
645 for (i = 0; i < 8; i++) {
646 *data++ = a->resources.pci.bar[i];
647 }
648 *data++ = (dword) a->resources.pci.irq;
649 a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
650 ret = 0;
651 }
652 break;
653
654 case DIVA_XDI_UM_CMD_RESET_ADAPTER:
655 ret = diva_pri_reset_adapter(&a->xdi_adapter);
656 break;
657
658 case DIVA_XDI_UM_CMD_WRITE_SDRAM_BLOCK:
659 ret = diva_pri_write_sdram_block(&a->xdi_adapter,
660 cmd->command_data.
661 write_sdram.offset,
662 (byte *) & cmd[1],
663 cmd->command_data.
664 write_sdram.length,
665 pri_is_rev_2_card(a->
666 CardOrdinal)
667 ? MP2_MEMORY_SIZE :
668 MP_MEMORY_SIZE);
669 break;
670
671 case DIVA_XDI_UM_CMD_STOP_ADAPTER:
672 ret = diva_pri_stop_adapter(a);
673 break;
674
675 case DIVA_XDI_UM_CMD_START_ADAPTER:
676 ret = diva_pri_start_adapter(&a->xdi_adapter,
677 cmd->command_data.start.
678 offset,
679 cmd->command_data.start.
680 features);
681 break;
682
683 case DIVA_XDI_UM_CMD_SET_PROTOCOL_FEATURES:
684 a->xdi_adapter.features =
685 cmd->command_data.features.features;
686 a->xdi_adapter.a.protocol_capabilities =
687 a->xdi_adapter.features;
688 DBG_TRC(("Set raw protocol features (%08x)",
689 a->xdi_adapter.features))
690 ret = 0;
691 break;
692
693 case DIVA_XDI_UM_CMD_GET_CARD_STATE:
694 a->xdi_mbox.data_length = sizeof(dword);
695 a->xdi_mbox.data =
696 diva_os_malloc(0, a->xdi_mbox.data_length);
697 if (a->xdi_mbox.data) {
698 dword *data = (dword *) a->xdi_mbox.data;
699 if (!a->xdi_adapter.ram ||
700 !a->xdi_adapter.reset ||
701 !a->xdi_adapter.cfg) {
702 *data = 3;
703 } else if (a->xdi_adapter.trapped) {
704 *data = 2;
705 } else if (a->xdi_adapter.Initialized) {
706 *data = 1;
707 } else {
708 *data = 0;
709 }
710 a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
711 ret = 0;
712 }
713 break;
714
715 case DIVA_XDI_UM_CMD_READ_XLOG_ENTRY:
716 ret = diva_card_read_xlog(a);
717 break;
718
719 case DIVA_XDI_UM_CMD_READ_SDRAM:
720 if (a->xdi_adapter.Address) {
721 if (
722 (a->xdi_mbox.data_length =
723 cmd->command_data.read_sdram.length)) {
724 if (
725 (a->xdi_mbox.data_length +
726 cmd->command_data.read_sdram.offset) <
727 a->xdi_adapter.MemorySize) {
728 a->xdi_mbox.data =
729 diva_os_malloc(0,
730 a->xdi_mbox.
731 data_length);
732 if (a->xdi_mbox.data) {
733 byte __iomem *p = DIVA_OS_MEM_ATTACH_ADDRESS(&a->xdi_adapter);
734 byte __iomem *src = p;
735 byte *dst = a->xdi_mbox.data;
736 dword len = a->xdi_mbox.data_length;
737
738 src += cmd->command_data.read_sdram.offset;
739
740 while (len--) {
741 *dst++ = READ_BYTE(src++);
742 }
743 a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
744 DIVA_OS_MEM_DETACH_ADDRESS(&a->xdi_adapter, p);
745 ret = 0;
746 }
747 }
748 }
749 }
750 break;
751
752 default:
753 DBG_ERR(("A: A(%d) invalid cmd=%d", a->controller,
754 cmd->command))
755 }
756
757 return (ret);
758}
759
760/*
761** Get Serial Number
762*/
763static int pri_get_serial_number(diva_os_xdi_adapter_t * a)
764{
765 byte data[64];
766 int i;
767 dword len = sizeof(data);
768 volatile byte __iomem *config;
769 volatile byte __iomem *flash;
770 byte c;
771
772/*
773 * First set some GT6401x config registers before accessing the BOOT-ROM
774 */
775 config = DIVA_OS_MEM_ATTACH_CONFIG(&a->xdi_adapter);
776 c = READ_BYTE(&config[0xc3c]);
777 if (!(c & 0x08)) {
778 WRITE_BYTE(&config[0xc3c], c); /* Base Address enable register */
779 }
780 WRITE_BYTE(&config[LOW_BOOTCS_DREG], 0x00);
781 WRITE_BYTE(&config[HI_BOOTCS_DREG], 0xFF);
782 DIVA_OS_MEM_DETACH_CONFIG(&a->xdi_adapter, config);
783/*
784 * Read only the last 64 bytes of manufacturing data
785 */
786 memset(data, '\0', len);
787 flash = DIVA_OS_MEM_ATTACH_PROM(&a->xdi_adapter);
788 for (i = 0; i < len; i++) {
789 data[i] = READ_BYTE(&flash[0x8000 - len + i]);
790 }
791 DIVA_OS_MEM_DETACH_PROM(&a->xdi_adapter, flash);
792
793 config = DIVA_OS_MEM_ATTACH_CONFIG(&a->xdi_adapter);
794 WRITE_BYTE(&config[LOW_BOOTCS_DREG], 0xFC); /* Disable FLASH EPROM access */
795 WRITE_BYTE(&config[HI_BOOTCS_DREG], 0xFF);
796 DIVA_OS_MEM_DETACH_CONFIG(&a->xdi_adapter, config);
797
798 if (memcmp(&data[48], "DIVAserverPR", 12)) {
799#if !defined(DIVA_PRI_NO_PCI_BIOS_WORKAROUND) /* { */
800 word cmd = 0, cmd_org;
801 void *addr;
802 dword addr1, addr3, addr4;
803 byte Bus, Slot;
804 void *hdev;
805 addr4 = a->resources.pci.bar[4];
806 addr3 = a->resources.pci.bar[3]; /* flash */
807 addr1 = a->resources.pci.bar[1]; /* unused */
808
809 DBG_ERR(("A: apply Compaq BIOS workaround"))
810 DBG_LOG(("%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
811 data[0], data[1], data[2], data[3],
812 data[4], data[5], data[6], data[7]))
813
814 Bus = a->resources.pci.bus;
815 Slot = a->resources.pci.func;
816 hdev = a->resources.pci.hdev;
817 PCIread(Bus, Slot, 0x04, &cmd_org, sizeof(cmd_org), hdev);
818 PCIwrite(Bus, Slot, 0x04, &cmd, sizeof(cmd), hdev);
819
820 PCIwrite(Bus, Slot, 0x14, &addr4, sizeof(addr4), hdev);
821 PCIwrite(Bus, Slot, 0x20, &addr1, sizeof(addr1), hdev);
822
823 PCIwrite(Bus, Slot, 0x04, &cmd_org, sizeof(cmd_org), hdev);
824
825 addr = a->resources.pci.addr[1];
826 a->resources.pci.addr[1] = a->resources.pci.addr[4];
827 a->resources.pci.addr[4] = addr;
828
829 addr1 = a->resources.pci.bar[1];
830 a->resources.pci.bar[1] = a->resources.pci.bar[4];
831 a->resources.pci.bar[4] = addr1;
832
833 /*
834 Try to read Flash again
835 */
836 len = sizeof(data);
837
838 config = DIVA_OS_MEM_ATTACH_CONFIG(&a->xdi_adapter);
839 if (!(config[0xc3c] & 0x08)) {
840 config[0xc3c] |= 0x08; /* Base Address enable register */
841 }
842 config[LOW_BOOTCS_DREG] = 0x00;
843 config[HI_BOOTCS_DREG] = 0xFF;
844 DIVA_OS_MEM_DETACH_CONFIG(&a->xdi_adapter, config);
845
846 memset(data, '\0', len);
847 flash = DIVA_OS_MEM_ATTACH_PROM(&a->xdi_adapter);
848 for (i = 0; i < len; i++) {
849 data[i] = flash[0x8000 - len + i];
850 }
851 DIVA_OS_MEM_ATTACH_PROM(&a->xdi_adapter, flash);
852 config = DIVA_OS_MEM_ATTACH_CONFIG(&a->xdi_adapter);
853 config[LOW_BOOTCS_DREG] = 0xFC;
854 config[HI_BOOTCS_DREG] = 0xFF;
855 DIVA_OS_MEM_DETACH_CONFIG(&a->xdi_adapter, config);
856
857 if (memcmp(&data[48], "DIVAserverPR", 12)) {
858 DBG_ERR(("A: failed to read serial number"))
859 DBG_LOG(("%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
860 data[0], data[1], data[2], data[3],
861 data[4], data[5], data[6], data[7]))
862 return (-1);
863 }
864#else /* } { */
865 DBG_ERR(("A: failed to read DIVA signature word"))
866 DBG_LOG(("%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
867 data[0], data[1], data[2], data[3],
868 data[4], data[5], data[6], data[7]))
869 DBG_LOG(("%02x:%02x:%02x:%02x", data[47], data[46],
870 data[45], data[44]))
871#endif /* } */
872 }
873
874 a->xdi_adapter.serialNo =
875 (data[47] << 24) | (data[46] << 16) | (data[45] << 8) |
876 data[44];
877 if (!a->xdi_adapter.serialNo
878 || (a->xdi_adapter.serialNo == 0xffffffff)) {
879 a->xdi_adapter.serialNo = 0;
880 DBG_ERR(("A: failed to read serial number"))
881 return (-1);
882 }
883
884 DBG_LOG(("Serial No. : %ld", a->xdi_adapter.serialNo))
885 DBG_TRC(("Board Revision : %d.%02d", (int) data[41],
886 (int) data[40]))
887 DBG_TRC(("PLD revision : %d.%02d", (int) data[33],
888 (int) data[32]))
889 DBG_TRC(("Boot loader version : %d.%02d", (int) data[37],
890 (int) data[36]))
891
892 DBG_TRC(("Manufacturing Date : %d/%02d/%02d (yyyy/mm/dd)",
893 (int) ((data[28] > 90) ? 1900 : 2000) +
894 (int) data[28], (int) data[29], (int) data[30]))
895
896 return (0);
897}
898
899void diva_os_prepare_pri2_functions(PISDN_ADAPTER IoAdapter)
900{
901}
902
903void diva_os_prepare_pri_functions(PISDN_ADAPTER IoAdapter)
904{
905}
906
907/*
908** Checks presence of DSP on board
909*/
910static int
911dsp_check_presence(volatile byte __iomem * addr, volatile byte __iomem * data, int dsp)
912{
913 word pattern;
914
915 WRITE_WORD(addr, 0x4000);
916 WRITE_WORD(data, DSP_SIGNATURE_PROBE_WORD);
917
918 WRITE_WORD(addr, 0x4000);
919 pattern = READ_WORD(data);
920
921 if (pattern != DSP_SIGNATURE_PROBE_WORD) {
922 DBG_TRC(("W: DSP[%d] %04x(is) != %04x(should)",
923 dsp, pattern, DSP_SIGNATURE_PROBE_WORD))
924 return (-1);
925 }
926
927 WRITE_WORD(addr, 0x4000);
928 WRITE_WORD(data, ~DSP_SIGNATURE_PROBE_WORD);
929
930 WRITE_WORD(addr, 0x4000);
931 pattern = READ_WORD(data);
932
933 if (pattern != (word) ~ DSP_SIGNATURE_PROBE_WORD) {
934 DBG_ERR(("A: DSP[%d] %04x(is) != %04x(should)",
935 dsp, pattern, (word) ~ DSP_SIGNATURE_PROBE_WORD))
936 return (-2);
937 }
938
939 DBG_TRC(("DSP[%d] present", dsp))
940
941 return (0);
942}
943
944
945/*
946** Check if DSP's are present and operating
947** Information about detected DSP's is returned as bit mask
948** Bit 0 - DSP1
949** ...
950** ...
951** ...
952** Bit 29 - DSP30
953*/
954static dword diva_pri_detect_dsps(diva_os_xdi_adapter_t * a)
955{
956 byte __iomem *base;
957 byte __iomem *p;
958 dword ret = 0;
959 dword row_offset[7] = {
960 0x00000000,
961 0x00000800, /* 1 - ROW 1 */
962 0x00000840, /* 2 - ROW 2 */
963 0x00001000, /* 3 - ROW 3 */
964 0x00001040, /* 4 - ROW 4 */
965 0x00000000 /* 5 - ROW 0 */
966 };
967
968 byte __iomem *dsp_addr_port;
969 byte __iomem *dsp_data_port;
970 byte row_state;
971 int dsp_row = 0, dsp_index, dsp_num;
972
973 if (!a->xdi_adapter.Control || !a->xdi_adapter.reset) {
974 return (0);
975 }
976
977 p = DIVA_OS_MEM_ATTACH_RESET(&a->xdi_adapter);
978 WRITE_BYTE(p, _MP_RISC_RESET | _MP_DSP_RESET);
979 DIVA_OS_MEM_DETACH_RESET(&a->xdi_adapter, p);
980 diva_os_wait(5);
981
982 base = DIVA_OS_MEM_ATTACH_CONTROL(&a->xdi_adapter);
983
984 for (dsp_num = 0; dsp_num < 30; dsp_num++) {
985 dsp_row = dsp_num / 7 + 1;
986 dsp_index = dsp_num % 7;
987
988 dsp_data_port = base;
989 dsp_addr_port = base;
990
991 dsp_data_port += row_offset[dsp_row];
992 dsp_addr_port += row_offset[dsp_row];
993
994 dsp_data_port += (dsp_index * 8);
995 dsp_addr_port += (dsp_index * 8) + 0x80;
996
997 if (!dsp_check_presence
998 (dsp_addr_port, dsp_data_port, dsp_num + 1)) {
999 ret |= (1 << dsp_num);
1000 }
1001 }
1002 DIVA_OS_MEM_DETACH_CONTROL(&a->xdi_adapter, base);
1003
1004 p = DIVA_OS_MEM_ATTACH_RESET(&a->xdi_adapter);
1005 WRITE_BYTE(p, _MP_RISC_RESET | _MP_LED1 | _MP_LED2);
1006 DIVA_OS_MEM_DETACH_RESET(&a->xdi_adapter, p);
1007 diva_os_wait(5);
1008
1009 /*
1010 Verify modules
1011 */
1012 for (dsp_row = 0; dsp_row < 4; dsp_row++) {
1013 row_state = ((ret >> (dsp_row * 7)) & 0x7F);
1014 if (row_state && (row_state != 0x7F)) {
1015 for (dsp_index = 0; dsp_index < 7; dsp_index++) {
1016 if (!(row_state & (1 << dsp_index))) {
1017 DBG_ERR(("A: MODULE[%d]-DSP[%d] failed",
1018 dsp_row + 1,
1019 dsp_index + 1))
1020 }
1021 }
1022 }
1023 }
1024
1025 if (!(ret & 0x10000000)) {
1026 DBG_ERR(("A: ON BOARD-DSP[1] failed"))
1027 }
1028 if (!(ret & 0x20000000)) {
1029 DBG_ERR(("A: ON BOARD-DSP[2] failed"))
1030 }
1031
1032 /*
1033 Print module population now
1034 */
1035 DBG_LOG(("+-----------------------+"))
1036 DBG_LOG(("| DSP MODULE POPULATION |"))
1037 DBG_LOG(("+-----------------------+"))
1038 DBG_LOG(("| 1 | 2 | 3 | 4 |"))
1039 DBG_LOG(("+-----------------------+"))
1040 DBG_LOG(("| %s | %s | %s | %s |",
1041 ((ret >> (0 * 7)) & 0x7F) ? "Y" : "N",
1042 ((ret >> (1 * 7)) & 0x7F) ? "Y" : "N",
1043 ((ret >> (2 * 7)) & 0x7F) ? "Y" : "N",
1044 ((ret >> (3 * 7)) & 0x7F) ? "Y" : "N"))
1045 DBG_LOG(("+-----------------------+"))
1046
1047 DBG_LOG(("DSP's(present-absent):%08x-%08x", ret,
1048 ~ret & 0x3fffffff))
1049
1050 return (ret);
1051}
diff --git a/drivers/isdn/hardware/eicon/os_pri.h b/drivers/isdn/hardware/eicon/os_pri.h
new file mode 100644
index 000000000000..a7c42f94d78a
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/os_pri.h
@@ -0,0 +1,8 @@
1/* $Id: os_pri.h,v 1.1.2.2 2001/02/08 12:25:44 armin Exp $ */
2
3#ifndef __DIVA_OS_PRI_REV_1_H__
4#define __DIVA_OS_PRI_REV_1_H__
5
6int diva_pri_init_card(diva_os_xdi_adapter_t * a);
7
8#endif
diff --git a/drivers/isdn/hardware/eicon/pc.h b/drivers/isdn/hardware/eicon/pc.h
new file mode 100644
index 000000000000..1c6945768a35
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/pc.h
@@ -0,0 +1,738 @@
1
2/*
3 *
4 Copyright (c) Eicon Networks, 2002.
5 *
6 This source file is supplied for the use with
7 Eicon Networks range of DIVA Server Adapters.
8 *
9 Eicon File Revision : 2.1
10 *
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2, or (at your option)
14 any later version.
15 *
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
18 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 See the GNU General Public License for more details.
20 *
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26#ifndef PC_H_INCLUDED /* { */
27#define PC_H_INCLUDED
28/*------------------------------------------------------------------*/
29/* buffer definition */
30/*------------------------------------------------------------------*/
31typedef struct {
32 word length; /* length of data/parameter field */
33 byte P[270]; /* data/parameter field */
34} PBUFFER;
35/*------------------------------------------------------------------*/
36/* dual port ram structure */
37/*------------------------------------------------------------------*/
38struct dual
39{
40 byte Req; /* request register */
41 byte ReqId; /* request task/entity identification */
42 byte Rc; /* return code register */
43 byte RcId; /* return code task/entity identification */
44 byte Ind; /* Indication register */
45 byte IndId; /* Indication task/entity identification */
46 byte IMask; /* Interrupt Mask Flag */
47 byte RNR; /* Receiver Not Ready (set by PC) */
48 byte XLock; /* XBuffer locked Flag */
49 byte Int; /* ISDN-S interrupt */
50 byte ReqCh; /* Channel field for layer-3 Requests */
51 byte RcCh; /* Channel field for layer-3 Returncodes */
52 byte IndCh; /* Channel field for layer-3 Indications */
53 byte MInd; /* more data indication field */
54 word MLength; /* more data total packet length */
55 byte ReadyInt; /* request field for ready interrupt */
56 byte SWReg; /* Software register for special purposes */
57 byte Reserved[11]; /* reserved space */
58 byte InterfaceType; /* interface type 1=16K interface */
59 word Signature; /* ISDN-S adapter Signature (GD) */
60 PBUFFER XBuffer; /* Transmit Buffer */
61 PBUFFER RBuffer; /* Receive Buffer */
62};
63/*------------------------------------------------------------------*/
64/* SWReg Values (0 means no command) */
65/*------------------------------------------------------------------*/
66#define SWREG_DIE_WITH_LEDON 0x01
67#define SWREG_HALT_CPU 0x02 /* Push CPU into a while(1) loop */
68/*------------------------------------------------------------------*/
69/* Id Fields Coding */
70/*------------------------------------------------------------------*/
71#define ID_MASK 0xe0 /* Mask for the ID field */
72#define GL_ERR_ID 0x1f /* ID for error reporting on global requests*/
73#define DSIG_ID 0x00 /* ID for D-channel signaling */
74#define NL_ID 0x20 /* ID for network-layer access (B or D) */
75#define BLLC_ID 0x60 /* ID for B-channel link level access */
76#define TASK_ID 0x80 /* ID for dynamic user tasks */
77#define TIMER_ID 0xa0 /* ID for timer task */
78#define TEL_ID 0xc0 /* ID for telephone support */
79#define MAN_ID 0xe0 /* ID for management */
80/*------------------------------------------------------------------*/
81/* ASSIGN and REMOVE requests are the same for all entities */
82/*------------------------------------------------------------------*/
83#define ASSIGN 0x01
84#define UREMOVE 0xfe /* without return code */
85#define REMOVE 0xff
86/*------------------------------------------------------------------*/
87/* Timer Interrupt Task Interface */
88/*------------------------------------------------------------------*/
89#define ASSIGN_TIM 0x01
90#define REMOVE_TIM 0xff
91/*------------------------------------------------------------------*/
92/* dynamic user task interface */
93/*------------------------------------------------------------------*/
94#define ASSIGN_TSK 0x01
95#define REMOVE_TSK 0xff
96#define LOAD 0xf0
97#define RELOCATE 0xf1
98#define START 0xf2
99#define LOAD2 0xf3
100#define RELOCATE2 0xf4
101/*------------------------------------------------------------------*/
102/* dynamic user task messages */
103/*------------------------------------------------------------------*/
104#define TSK_B2 0x0000
105#define TSK_WAKEUP 0x2000
106#define TSK_TIMER 0x4000
107#define TSK_TSK 0x6000
108#define TSK_PC 0xe000
109/*------------------------------------------------------------------*/
110/* LL management primitives */
111/*------------------------------------------------------------------*/
112#define ASSIGN_LL 1 /* assign logical link */
113#define REMOVE_LL 0xff /* remove logical link */
114/*------------------------------------------------------------------*/
115/* LL service primitives */
116/*------------------------------------------------------------------*/
117#define LL_UDATA 1 /* link unit data request/indication */
118#define LL_ESTABLISH 2 /* link establish request/indication */
119#define LL_RELEASE 3 /* link release request/indication */
120#define LL_DATA 4 /* data request/indication */
121#define LL_LOCAL 5 /* switch to local operation (COM only) */
122#define LL_DATA_PEND 5 /* data pending indication (SDLC SHM only) */
123#define LL_REMOTE 6 /* switch to remote operation (COM only) */
124#define LL_TEST 8 /* link test request */
125#define LL_MDATA 9 /* more data request/indication */
126#define LL_BUDATA 10 /* broadcast unit data request/indication */
127#define LL_XID 12 /* XID command request/indication */
128#define LL_XID_R 13 /* XID response request/indication */
129/*------------------------------------------------------------------*/
130/* NL service primitives */
131/*------------------------------------------------------------------*/
132#define N_MDATA 1 /* more data to come REQ/IND */
133#define N_CONNECT 2 /* OSI N-CONNECT REQ/IND */
134#define N_CONNECT_ACK 3 /* OSI N-CONNECT CON/RES */
135#define N_DISC 4 /* OSI N-DISC REQ/IND */
136#define N_DISC_ACK 5 /* OSI N-DISC CON/RES */
137#define N_RESET 6 /* OSI N-RESET REQ/IND */
138#define N_RESET_ACK 7 /* OSI N-RESET CON/RES */
139#define N_DATA 8 /* OSI N-DATA REQ/IND */
140#define N_EDATA 9 /* OSI N-EXPEDITED DATA REQ/IND */
141#define N_UDATA 10 /* OSI D-UNIT-DATA REQ/IND */
142#define N_BDATA 11 /* BROADCAST-DATA REQ/IND */
143#define N_DATA_ACK 12 /* data ack ind for D-bit procedure */
144#define N_EDATA_ACK 13 /* data ack ind for INTERRUPT */
145#define N_XON 15 /* clear RNR state */
146#define N_COMBI_IND N_XON /* combined indication */
147#define N_Q_BIT 0x10 /* Q-bit for req/ind */
148#define N_M_BIT 0x20 /* M-bit for req/ind */
149#define N_D_BIT 0x40 /* D-bit for req/ind */
150/*------------------------------------------------------------------*/
151/* Signaling management primitives */
152/*------------------------------------------------------------------*/
153#define ASSIGN_SIG 1 /* assign signaling task */
154#define UREMOVE_SIG 0xfe /* remove signaling task without return code*/
155#define REMOVE_SIG 0xff /* remove signaling task */
156/*------------------------------------------------------------------*/
157/* Signaling service primitives */
158/*------------------------------------------------------------------*/
159#define CALL_REQ 1 /* call request */
160#define CALL_CON 1 /* call confirmation */
161#define CALL_IND 2 /* incoming call connected */
162#define LISTEN_REQ 2 /* listen request */
163#define HANGUP 3 /* hangup request/indication */
164#define SUSPEND 4 /* call suspend request/confirm */
165#define RESUME 5 /* call resume request/confirm */
166#define SUSPEND_REJ 6 /* suspend rejected indication */
167#define USER_DATA 8 /* user data for user to user signaling */
168#define CONGESTION 9 /* network congestion indication */
169#define INDICATE_REQ 10 /* request to indicate an incoming call */
170#define INDICATE_IND 10 /* indicates that there is an incoming call */
171#define CALL_RES 11 /* accept an incoming call */
172#define CALL_ALERT 12 /* send ALERT for incoming call */
173#define INFO_REQ 13 /* INFO request */
174#define INFO_IND 13 /* INFO indication */
175#define REJECT 14 /* reject an incoming call */
176#define RESOURCES 15 /* reserve B-Channel hardware resources */
177#define HW_CTRL 16 /* B-Channel hardware IOCTL req/ind */
178#define TEL_CTRL 16 /* Telephone control request/indication */
179#define STATUS_REQ 17 /* Request D-State (returned in INFO_IND) */
180#define FAC_REG_REQ 18 /* 1TR6 connection independent fac reg */
181#define FAC_REG_ACK 19 /* 1TR6 fac registration acknowledge */
182#define FAC_REG_REJ 20 /* 1TR6 fac registration reject */
183#define CALL_COMPLETE 21/* send a CALL_PROC for incoming call */
184#define SW_CTRL 22 /* extended software features */
185#define REGISTER_REQ 23 /* Q.931 connection independent reg req */
186#define REGISTER_IND 24 /* Q.931 connection independent reg ind */
187#define FACILITY_REQ 25 /* Q.931 connection independent fac req */
188#define FACILITY_IND 26 /* Q.931 connection independent fac ind */
189#define NCR_INFO_REQ 27 /* INFO_REQ with NULL CR */
190#define GCR_MIM_REQ 28 /* MANAGEMENT_INFO_REQ with global CR */
191#define SIG_CTRL 29 /* Control for Signalling Hardware */
192#define DSP_CTRL 30 /* Control for DSPs */
193#define LAW_REQ 31 /* Law config request for (returns info_i) */
194#define SPID_CTRL 32 /* Request/indication SPID related */
195#define NCR_FACILITY 33 /* Request/indication with NULL/DUMMY CR */
196#define CALL_HOLD 34 /* Request/indication to hold a CALL */
197#define CALL_RETRIEVE 35 /* Request/indication to retrieve a CALL */
198#define CALL_HOLD_ACK 36 /* OK of hold a CALL */
199#define CALL_RETRIEVE_ACK 37 /* OK of retrieve a CALL */
200#define CALL_HOLD_REJ 38 /* Reject of hold a CALL */
201#define CALL_RETRIEVE_REJ 39 /* Reject of retrieve a call */
202#define GCR_RESTART 40 /* Send/Receive Restart message */
203#define S_SERVICE 41 /* Send/Receive Supplementary Service */
204#define S_SERVICE_REJ 42 /* Reject Supplementary Service indication */
205#define S_SUPPORTED 43 /* Req/Ind to get Supported Services */
206#define STATUS_ENQ 44 /* Req to send the D-ch request if !state0 */
207#define CALL_GUARD 45 /* Req/Ind to use the FLAGS_CALL_OUTCHECK */
208#define CALL_GUARD_HP 46 /* Call Guard function to reject a call */
209#define CALL_GUARD_IF 47 /* Call Guard function, inform the appl */
210#define SSEXT_REQ 48 /* Supplem.Serv./QSIG specific request */
211#define SSEXT_IND 49 /* Supplem.Serv./QSIG specific indication */
212/* reserved commands for the US protocols */
213#define INT_3PTY_NIND 50 /* US specific indication */
214#define INT_CF_NIND 51 /* US specific indication */
215#define INT_3PTY_DROP 52 /* US specific indication */
216#define INT_MOVE_CONF 53 /* US specific indication */
217#define INT_MOVE_RC 54 /* US specific indication */
218#define INT_MOVE_FLIPPED_CONF 55 /* US specific indication */
219#define INT_X5NI_OK 56 /* internal transfer OK indication */
220#define INT_XDMS_START 57 /* internal transfer OK indication */
221#define INT_XDMS_STOP 58 /* internal transfer finish indication */
222#define INT_XDMS_STOP2 59 /* internal transfer send FA */
223#define INT_CUSTCONF_REJ 60 /* internal conference reject */
224#define INT_CUSTXFER 61 /* internal transfer request */
225#define INT_CUSTX_NIND 62 /* internal transfer ack */
226#define INT_CUSTXREJ_NIND 63 /* internal transfer rej */
227#define INT_X5NI_CF_XFER 64 /* internal transfer OK indication */
228#define VSWITCH_REQ 65 /* communication between protocol and */
229#define VSWITCH_IND 66 /* capifunctions for D-CH-switching */
230#define MWI_POLL 67 /* Message Waiting Status Request fkt */
231#define CALL_PEND_NOTIFY 68 /* notify capi to set new listen */
232#define DO_NOTHING 69 /* dont do somethin if you get this */
233#define INT_CT_REJ 70 /* ECT rejected internal command */
234#define CALL_HOLD_COMPLETE 71 /* In NT Mode indicate hold complete */
235#define CALL_RETRIEVE_COMPLETE 72 /* In NT Mode indicate retrieve complete */
236/*------------------------------------------------------------------*/
237/* management service primitives */
238/*------------------------------------------------------------------*/
239#define MAN_READ 2
240#define MAN_WRITE 3
241#define MAN_EXECUTE 4
242#define MAN_EVENT_ON 5
243#define MAN_EVENT_OFF 6
244#define MAN_LOCK 7
245#define MAN_UNLOCK 8
246#define MAN_INFO_IND 2
247#define MAN_EVENT_IND 3
248#define MAN_TRACE_IND 4
249#define MAN_COMBI_IND 9
250#define MAN_ESC 0x80
251/*------------------------------------------------------------------*/
252/* return code coding */
253/*------------------------------------------------------------------*/
254#define UNKNOWN_COMMAND 0x01 /* unknown command */
255#define WRONG_COMMAND 0x02 /* wrong command */
256#define WRONG_ID 0x03 /* unknown task/entity id */
257#define WRONG_CH 0x04 /* wrong task/entity id */
258#define UNKNOWN_IE 0x05 /* unknown information el. */
259#define WRONG_IE 0x06 /* wrong information el. */
260#define OUT_OF_RESOURCES 0x07 /* ISDN-S card out of res. */
261#define ISDN_GUARD_REJ 0x09 /* ISDN-Guard SuppServ rej */
262#define N_FLOW_CONTROL 0x10 /* Flow-Control, retry */
263#define ASSIGN_RC 0xe0 /* ASSIGN acknowledgement */
264#define ASSIGN_OK 0xef /* ASSIGN OK */
265#define OK_FC 0xfc /* Flow-Control RC */
266#define READY_INT 0xfd /* Ready interrupt */
267#define TIMER_INT 0xfe /* timer interrupt */
268#define OK 0xff /* command accepted */
269/*------------------------------------------------------------------*/
270/* information elements */
271/*------------------------------------------------------------------*/
272#define SHIFT 0x90 /* codeset shift */
273#define MORE 0xa0 /* more data */
274#define SDNCMPL 0xa1 /* sending complete */
275#define CL 0xb0 /* congestion level */
276 /* codeset 0 */
277#define SMSG 0x00 /* segmented message */
278#define BC 0x04 /* Bearer Capability */
279#define CAU 0x08 /* cause */
280#define CAD 0x0c /* Connected address */
281#define CAI 0x10 /* call identity */
282#define CHI 0x18 /* channel identification */
283#define LLI 0x19 /* logical link id */
284#define CHA 0x1a /* charge advice */
285#define FTY 0x1c /* Facility */
286#define DT 0x29 /* ETSI date/time */
287#define KEY 0x2c /* keypad information element */
288#define UID 0x2d /* User id information element */
289#define DSP 0x28 /* display */
290#define SIG 0x34 /* signalling hardware control */
291#define OAD 0x6c /* origination address */
292#define OSA 0x6d /* origination sub-address */
293#define CPN 0x70 /* called party number */
294#define DSA 0x71 /* destination sub-address */
295#define RDX 0x73 /* redirecting number extended */
296#define RDN 0x74 /* redirecting number */
297#define RIN 0x76 /* redirection number */
298#define IUP 0x76 /* VN6 rerouter->PCS (codeset 6) */
299#define IPU 0x77 /* VN6 PCS->rerouter (codeset 6) */
300#define RI 0x79 /* restart indicator */
301#define MIE 0x7a /* management info element */
302#define LLC 0x7c /* low layer compatibility */
303#define HLC 0x7d /* high layer compatibility */
304#define UUI 0x7e /* user user information */
305#define ESC 0x7f /* escape extension */
306#define DLC 0x20 /* data link layer configuration */
307#define NLC 0x21 /* network layer configuration */
308#define REDIRECT_IE 0x22 /* redirection request/indication data */
309#define REDIRECT_NET_IE 0x23 /* redirection network override data */
310 /* codeset 6 */
311#define SIN 0x01 /* service indicator */
312#define CIF 0x02 /* charging information */
313#define DATE 0x03 /* date */
314#define CPS 0x07 /* called party status */
315/*------------------------------------------------------------------*/
316/* ESC information elements */
317/*------------------------------------------------------------------*/
318#define MSGTYPEIE 0x7a /* Messagetype info element */
319#define CRIE 0x7b /* INFO info element */
320#define CODESET6IE 0xec /* Tunnel for Codeset 6 IEs */
321#define VSWITCHIE 0xed /* VSwitch info element */
322#define SSEXTIE 0xee /* Supplem. Service info element */
323#define PROFILEIE 0xef /* Profile info element */
324/*------------------------------------------------------------------*/
325/* TEL_CTRL contents */
326/*------------------------------------------------------------------*/
327#define RING_ON 0x01
328#define RING_OFF 0x02
329#define HANDS_FREE_ON 0x03
330#define HANDS_FREE_OFF 0x04
331#define ON_HOOK 0x80
332#define OFF_HOOK 0x90
333/* operation values used by ETSI supplementary services */
334#define THREE_PTY_BEGIN 0x04
335#define THREE_PTY_END 0x05
336#define ECT_EXECUTE 0x06
337#define ACTIVATION_DIVERSION 0x07
338#define DEACTIVATION_DIVERSION 0x08
339#define CALL_DEFLECTION 0x0D
340#define INTERROGATION_DIVERSION 0x0B
341#define INTERROGATION_SERV_USR_NR 0x11
342#define ACTIVATION_MWI 0x20
343#define DEACTIVATION_MWI 0x21
344#define MWI_INDICATION 0x22
345#define MWI_RESPONSE 0x23
346#define CONF_BEGIN 0x28
347#define CONF_ADD 0x29
348#define CONF_SPLIT 0x2a
349#define CONF_DROP 0x2b
350#define CONF_ISOLATE 0x2c
351#define CONF_REATTACH 0x2d
352#define CONF_PARTYDISC 0x2e
353#define CCBS_INFO_RETAIN 0x2f
354#define CCBS_ERASECALLLINKAGEID 0x30
355#define CCBS_STOP_ALERTING 0x31
356#define CCBS_REQUEST 0x32
357#define CCBS_DEACTIVATE 0x33
358#define CCBS_INTERROGATE 0x34
359#define CCBS_STATUS 0x35
360#define CCBS_ERASE 0x36
361#define CCBS_B_FREE 0x37
362#define CCNR_INFO_RETAIN 0x38
363#define CCBS_REMOTE_USER_FREE 0x39
364#define CCNR_REQUEST 0x3a
365#define CCNR_INTERROGATE 0x3b
366#define GET_SUPPORTED_SERVICES 0xff
367#define DIVERSION_PROCEDURE_CFU 0x70
368#define DIVERSION_PROCEDURE_CFB 0x71
369#define DIVERSION_PROCEDURE_CFNR 0x72
370#define DIVERSION_DEACTIVATION_CFU 0x80
371#define DIVERSION_DEACTIVATION_CFB 0x81
372#define DIVERSION_DEACTIVATION_CFNR 0x82
373#define DIVERSION_INTERROGATE_NUM 0x11
374#define DIVERSION_INTERROGATE_CFU 0x60
375#define DIVERSION_INTERROGATE_CFB 0x61
376#define DIVERSION_INTERROGATE_CFNR 0x62
377/* Service Masks */
378#define SMASK_HOLD_RETRIEVE 0x00000001
379#define SMASK_TERMINAL_PORTABILITY 0x00000002
380#define SMASK_ECT 0x00000004
381#define SMASK_3PTY 0x00000008
382#define SMASK_CALL_FORWARDING 0x00000010
383#define SMASK_CALL_DEFLECTION 0x00000020
384#define SMASK_MCID 0x00000040
385#define SMASK_CCBS 0x00000080
386#define SMASK_MWI 0x00000100
387#define SMASK_CCNR 0x00000200
388#define SMASK_CONF 0x00000400
389/* ----------------------------------------------
390 Types of transfers used to transfer the
391 information in the 'struct RC->Reserved2[8]'
392 The information is transferred as 2 dwords
393 (2 4Byte unsigned values)
394 First of them is the transfer type.
395 2^32-1 possible messages are possible in this way.
396 The context of the second one had no meaning
397 ---------------------------------------------- */
398#define DIVA_RC_TYPE_NONE 0x00000000
399#define DIVA_RC_TYPE_REMOVE_COMPLETE 0x00000008
400#define DIVA_RC_TYPE_STREAM_PTR 0x00000009
401#define DIVA_RC_TYPE_CMA_PTR 0x0000000a
402#define DIVA_RC_TYPE_OK_FC 0x0000000b
403#define DIVA_RC_TYPE_RX_DMA 0x0000000c
404/* ------------------------------------------------------
405 IO Control codes for IN BAND SIGNALING
406 ------------------------------------------------------ */
407#define CTRL_L1_SET_SIG_ID 5
408#define CTRL_L1_SET_DAD 6
409#define CTRL_L1_RESOURCES 7
410/* ------------------------------------------------------ */
411/* ------------------------------------------------------
412 Layer 2 types
413 ------------------------------------------------------ */
414#define X75T 1 /* x.75 for ttx */
415#define TRF 2 /* transparent with hdlc framing */
416#define TRF_IN 3 /* transparent with hdlc fr. inc. */
417#define SDLC 4 /* sdlc, sna layer-2 */
418#define X75 5 /* x.75 for btx */
419#define LAPD 6 /* lapd (Q.921) */
420#define X25_L2 7 /* x.25 layer-2 */
421#define V120_L2 8 /* V.120 layer-2 protocol */
422#define V42_IN 9 /* V.42 layer-2 protocol, incomming */
423#define V42 10 /* V.42 layer-2 protocol */
424#define MDM_ATP 11 /* AT Parser built in the L2 */
425#define X75_V42BIS 12 /* x.75 with V.42bis */
426#define RTPL2_IN 13 /* RTP layer-2 protocol, incomming */
427#define RTPL2 14 /* RTP layer-2 protocol */
428#define V120_V42BIS 15 /* V.120 asynchronous mode supporting V.42bis compression */
429#define LISTENER 27 /* Layer 2 to listen line */
430#define MTP2 28 /* MTP2 Layer 2 */
431#define PIAFS_CRC 29 /* PIAFS Layer 2 with CRC calculation at L2 */
432/* ------------------------------------------------------
433 PIAFS DLC DEFINITIONS
434 ------------------------------------------------------ */
435#define PIAFS_64K 0x01
436#define PIAFS_VARIABLE_SPEED 0x02
437#define PIAFS_CHINESE_SPEED 0x04
438#define PIAFS_UDATA_ABILITY_ID 0x80
439#define PIAFS_UDATA_ABILITY_DCDON 0x01
440#define PIAFS_UDATA_ABILITY_DDI 0x80
441/*
442DLC of PIAFS :
443Byte | 8 7 6 5 4 3 2 1
444-----+--------------------------------------------------------
445 0 | 0 0 1 0 0 0 0 0 Data Link Configuration
446 1 | X X X X X X X X Length of IE (at least 15 Bytes)
447 2 | 0 0 0 0 0 0 0 0 max. information field, LOW byte (not used, fix 73 Bytes)
448 3 | 0 0 0 0 0 0 0 0 max. information field, HIGH byte (not used, fix 73 Bytes)
449 4 | 0 0 0 0 0 0 0 0 address A (not used)
450 5 | 0 0 0 0 0 0 0 0 address B (not used)
451 6 | 0 0 0 0 0 0 0 0 Mode (not used, fix 128)
452 7 | 0 0 0 0 0 0 0 0 Window Size (not used, fix 127)
453 8 | X X X X X X X X XID Length, Low Byte (at least 7 Bytes)
454 9 | X X X X X X X X XID Length, High Byte
455 10 | 0 0 0 0 0 C V S PIAFS Protocol Speed configuration -> Note(1)
456 | S = 0 -> Protocol Speed is 32K
457 | S = 1 -> Protocol Speed is 64K
458 | V = 0 -> Protocol Speed is fixed
459 | V = 1 -> Protocol Speed is variable
460 | C = 0 -> speed setting according to standard
461 | C = 1 -> speed setting for chinese implementation
462 11 | 0 0 0 0 0 0 R T P0 - V42bis Compression enable/disable, Low Byte
463 | T = 0 -> Transmit Direction enable
464 | T = 1 -> Transmit Direction disable
465 | R = 0 -> Receive Direction enable
466 | R = 1 -> Receive Direction disable
467 13 | 0 0 0 0 0 0 0 0 P0 - V42bis Compression enable/disable, High Byte
468 14 | X X X X X X X X P1 - V42bis Dictionary Size, Low Byte
469 15 | X X X X X X X X P1 - V42bis Dictionary Size, High Byte
470 16 | X X X X X X X X P2 - V42bis String Length, Low Byte
471 17 | X X X X X X X X P2 - V42bis String Length, High Byte
472 18 | X X X X X X X X PIAFS extension length
473 19 | 1 0 0 0 0 0 0 0 PIAFS extension Id (0x80) - UDATA abilities
474 20 | U 0 0 0 0 0 0 D UDATA abilities -> Note (2)
475 | up to now the following Bits are defined:
476 | D - signal DCD ON
477 | U - use extensive UDATA control communication
478 | for DDI test application
479+ Note (1): ----------+------+-----------------------------------------+
480| PIAFS Protocol | Bit | |
481| Speed configuration | S | Bit 1 - Protocol Speed |
482| | | 0 - 32K |
483| | | 1 - 64K (default) |
484| | V | Bit 2 - Variable Protocol Speed |
485| | | 0 - Speed is fix |
486| | | 1 - Speed is variable (default) |
487| | | OVERWRITES 32k Bit 1 |
488| | C | Bit 3 0 - Speed Settings according to |
489| | | PIAFS specification |
490| | | 1 - Speed setting for chinese |
491| | | PIAFS implementation |
492| | | Explanation for chinese speed settings: |
493| | | if Bit 3 is set the following |
494| | | rules apply: |
495| | | Bit1=0 Bit2=0: 32k fix |
496| | | Bit1=1 Bit2=0: 64k fix |
497| | | Bit1=0 Bit2=1: PIAFS is trying |
498| | | to negotiate 32k is that is |
499| | | not possible it tries to |
500| | | negotiate 64k |
501| | | Bit1=1 Bit2=1: PIAFS is trying |
502| | | to negotiate 64k is that is |
503| | | not possible it tries to |
504| | | negotiate 32k |
505+ Note (2): ----------+------+-----------------------------------------+
506| PIAFS | Bit | this byte defines the usage of UDATA |
507| Implementation | | control communication |
508| UDATA usage | D | Bit 1 - DCD-ON signalling |
509| | | 0 - no DCD-ON is signalled |
510| | | (default) |
511| | | 1 - DCD-ON will be signalled |
512| | U | Bit 8 - DDI test application UDATA |
513| | | control communication |
514| | | 0 - no UDATA control |
515| | | communication (default) |
516| | | sets as well the DCD-ON |
517| | | signalling |
518| | | 1 - UDATA control communication |
519| | | ATTENTION: Do not use these |
520| | | setting if you |
521| | | are not really |
522| | | that you need it |
523| | | and you know |
524| | | exactly what you |
525| | | are doing. |
526| | | You can easily |
527| | | disable any |
528| | | data transfer. |
529+---------------------+------+-----------------------------------------+
530*/
531/* ------------------------------------------------------
532 LISTENER DLC DEFINITIONS
533 ------------------------------------------------------ */
534#define LISTENER_FEATURE_MASK_CUMMULATIVE 0x0001
535/* ------------------------------------------------------
536 LISTENER META-FRAME CODE/PRIMITIVE DEFINITIONS
537 ------------------------------------------------------ */
538#define META_CODE_LL_UDATA_RX 0x01
539#define META_CODE_LL_UDATA_TX 0x02
540#define META_CODE_LL_DATA_RX 0x03
541#define META_CODE_LL_DATA_TX 0x04
542#define META_CODE_LL_MDATA_RX 0x05
543#define META_CODE_LL_MDATA_TX 0x06
544#define META_CODE_EMPTY 0x10
545#define META_CODE_LOST_FRAMES 0x11
546#define META_FLAG_TRUNCATED 0x0001
547/*------------------------------------------------------------------*/
548/* CAPI-like profile to indicate features on LAW_REQ */
549/*------------------------------------------------------------------*/
550#define GL_INTERNAL_CONTROLLER_SUPPORTED 0x00000001L
551#define GL_EXTERNAL_EQUIPMENT_SUPPORTED 0x00000002L
552#define GL_HANDSET_SUPPORTED 0x00000004L
553#define GL_DTMF_SUPPORTED 0x00000008L
554#define GL_SUPPLEMENTARY_SERVICES_SUPPORTED 0x00000010L
555#define GL_CHANNEL_ALLOCATION_SUPPORTED 0x00000020L
556#define GL_BCHANNEL_OPERATION_SUPPORTED 0x00000040L
557#define GL_LINE_INTERCONNECT_SUPPORTED 0x00000080L
558#define B1_HDLC_SUPPORTED 0x00000001L
559#define B1_TRANSPARENT_SUPPORTED 0x00000002L
560#define B1_V110_ASYNC_SUPPORTED 0x00000004L
561#define B1_V110_SYNC_SUPPORTED 0x00000008L
562#define B1_T30_SUPPORTED 0x00000010L
563#define B1_HDLC_INVERTED_SUPPORTED 0x00000020L
564#define B1_TRANSPARENT_R_SUPPORTED 0x00000040L
565#define B1_MODEM_ALL_NEGOTIATE_SUPPORTED 0x00000080L
566#define B1_MODEM_ASYNC_SUPPORTED 0x00000100L
567#define B1_MODEM_SYNC_HDLC_SUPPORTED 0x00000200L
568#define B2_X75_SUPPORTED 0x00000001L
569#define B2_TRANSPARENT_SUPPORTED 0x00000002L
570#define B2_SDLC_SUPPORTED 0x00000004L
571#define B2_LAPD_SUPPORTED 0x00000008L
572#define B2_T30_SUPPORTED 0x00000010L
573#define B2_PPP_SUPPORTED 0x00000020L
574#define B2_TRANSPARENT_NO_CRC_SUPPORTED 0x00000040L
575#define B2_MODEM_EC_COMPRESSION_SUPPORTED 0x00000080L
576#define B2_X75_V42BIS_SUPPORTED 0x00000100L
577#define B2_V120_ASYNC_SUPPORTED 0x00000200L
578#define B2_V120_ASYNC_V42BIS_SUPPORTED 0x00000400L
579#define B2_V120_BIT_TRANSPARENT_SUPPORTED 0x00000800L
580#define B2_LAPD_FREE_SAPI_SEL_SUPPORTED 0x00001000L
581#define B3_TRANSPARENT_SUPPORTED 0x00000001L
582#define B3_T90NL_SUPPORTED 0x00000002L
583#define B3_ISO8208_SUPPORTED 0x00000004L
584#define B3_X25_DCE_SUPPORTED 0x00000008L
585#define B3_T30_SUPPORTED 0x00000010L
586#define B3_T30_WITH_EXTENSIONS_SUPPORTED 0x00000020L
587#define B3_RESERVED_SUPPORTED 0x00000040L
588#define B3_MODEM_SUPPORTED 0x00000080L
589#define MANUFACTURER_FEATURE_SLAVE_CODEC 0x00000001L
590#define MANUFACTURER_FEATURE_FAX_MORE_DOCUMENTS 0x00000002L
591#define MANUFACTURER_FEATURE_HARDDTMF 0x00000004L
592#define MANUFACTURER_FEATURE_SOFTDTMF_SEND 0x00000008L
593#define MANUFACTURER_FEATURE_DTMF_PARAMETERS 0x00000010L
594#define MANUFACTURER_FEATURE_SOFTDTMF_RECEIVE 0x00000020L
595#define MANUFACTURER_FEATURE_FAX_SUB_SEP_PWD 0x00000040L
596#define MANUFACTURER_FEATURE_V18 0x00000080L
597#define MANUFACTURER_FEATURE_MIXER_CH_CH 0x00000100L
598#define MANUFACTURER_FEATURE_MIXER_CH_PC 0x00000200L
599#define MANUFACTURER_FEATURE_MIXER_PC_CH 0x00000400L
600#define MANUFACTURER_FEATURE_MIXER_PC_PC 0x00000800L
601#define MANUFACTURER_FEATURE_ECHO_CANCELLER 0x00001000L
602#define MANUFACTURER_FEATURE_RTP 0x00002000L
603#define MANUFACTURER_FEATURE_T38 0x00004000L
604#define MANUFACTURER_FEATURE_TRANSP_DELIVERY_CONF 0x00008000L
605#define MANUFACTURER_FEATURE_XONOFF_FLOW_CONTROL 0x00010000L
606#define MANUFACTURER_FEATURE_OOB_CHANNEL 0x00020000L
607#define MANUFACTURER_FEATURE_IN_BAND_CHANNEL 0x00040000L
608#define MANUFACTURER_FEATURE_IN_BAND_FEATURE 0x00080000L
609#define MANUFACTURER_FEATURE_PIAFS 0x00100000L
610#define MANUFACTURER_FEATURE_DTMF_TONE 0x00200000L
611#define MANUFACTURER_FEATURE_FAX_PAPER_FORMATS 0x00400000L
612#define MANUFACTURER_FEATURE_OK_FC_LABEL 0x00800000L
613#define MANUFACTURER_FEATURE_VOWN 0x01000000L
614#define MANUFACTURER_FEATURE_XCONNECT 0x02000000L
615#define MANUFACTURER_FEATURE_DMACONNECT 0x04000000L
616#define MANUFACTURER_FEATURE_AUDIO_TAP 0x08000000L
617#define MANUFACTURER_FEATURE_FAX_NONSTANDARD 0x10000000L
618#define MANUFACTURER_FEATURE_SS7 0x20000000L
619#define MANUFACTURER_FEATURE_MADAPTER 0x40000000L
620#define MANUFACTURER_FEATURE_MEASURE 0x80000000L
621#define MANUFACTURER_FEATURE2_LISTENING 0x00000001L
622#define MANUFACTURER_FEATURE2_SS_DIFFCONTPOSSIBLE 0x00000002L
623#define MANUFACTURER_FEATURE2_GENERIC_TONE 0x00000004L
624#define MANUFACTURER_FEATURE2_COLOR_FAX 0x00000008L
625#define MANUFACTURER_FEATURE2_SS_ECT_DIFFCONTPOSSIBLE 0x00000010L
626#define RTP_PRIM_PAYLOAD_PCMU_8000 0
627#define RTP_PRIM_PAYLOAD_1016_8000 1
628#define RTP_PRIM_PAYLOAD_G726_32_8000 2
629#define RTP_PRIM_PAYLOAD_GSM_8000 3
630#define RTP_PRIM_PAYLOAD_G723_8000 4
631#define RTP_PRIM_PAYLOAD_DVI4_8000 5
632#define RTP_PRIM_PAYLOAD_DVI4_16000 6
633#define RTP_PRIM_PAYLOAD_LPC_8000 7
634#define RTP_PRIM_PAYLOAD_PCMA_8000 8
635#define RTP_PRIM_PAYLOAD_G722_16000 9
636#define RTP_PRIM_PAYLOAD_QCELP_8000 12
637#define RTP_PRIM_PAYLOAD_G728_8000 14
638#define RTP_PRIM_PAYLOAD_G729_8000 18
639#define RTP_PRIM_PAYLOAD_GSM_HR_8000 30
640#define RTP_PRIM_PAYLOAD_GSM_EFR_8000 31
641#define RTP_ADD_PAYLOAD_BASE 32
642#define RTP_ADD_PAYLOAD_RED 32
643#define RTP_ADD_PAYLOAD_CN_8000 33
644#define RTP_ADD_PAYLOAD_DTMF 34
645#define RTP_PRIM_PAYLOAD_PCMU_8000_SUPPORTED (1L << RTP_PRIM_PAYLOAD_PCMU_8000)
646#define RTP_PRIM_PAYLOAD_1016_8000_SUPPORTED (1L << RTP_PRIM_PAYLOAD_1016_8000)
647#define RTP_PRIM_PAYLOAD_G726_32_8000_SUPPORTED (1L << RTP_PRIM_PAYLOAD_G726_32_8000)
648#define RTP_PRIM_PAYLOAD_GSM_8000_SUPPORTED (1L << RTP_PRIM_PAYLOAD_GSM_8000)
649#define RTP_PRIM_PAYLOAD_G723_8000_SUPPORTED (1L << RTP_PRIM_PAYLOAD_G723_8000)
650#define RTP_PRIM_PAYLOAD_DVI4_8000_SUPPORTED (1L << RTP_PRIM_PAYLOAD_DVI4_8000)
651#define RTP_PRIM_PAYLOAD_DVI4_16000_SUPPORTED (1L << RTP_PRIM_PAYLOAD_DVI4_16000)
652#define RTP_PRIM_PAYLOAD_LPC_8000_SUPPORTED (1L << RTP_PRIM_PAYLOAD_LPC_8000)
653#define RTP_PRIM_PAYLOAD_PCMA_8000_SUPPORTED (1L << RTP_PRIM_PAYLOAD_PCMA_8000)
654#define RTP_PRIM_PAYLOAD_G722_16000_SUPPORTED (1L << RTP_PRIM_PAYLOAD_G722_16000)
655#define RTP_PRIM_PAYLOAD_QCELP_8000_SUPPORTED (1L << RTP_PRIM_PAYLOAD_QCELP_8000)
656#define RTP_PRIM_PAYLOAD_G728_8000_SUPPORTED (1L << RTP_PRIM_PAYLOAD_G728_8000)
657#define RTP_PRIM_PAYLOAD_G729_8000_SUPPORTED (1L << RTP_PRIM_PAYLOAD_G729_8000)
658#define RTP_PRIM_PAYLOAD_GSM_HR_8000_SUPPORTED (1L << RTP_PRIM_PAYLOAD_GSM_HR_8000)
659#define RTP_PRIM_PAYLOAD_GSM_EFR_8000_SUPPORTED (1L << RTP_PRIM_PAYLOAD_GSM_EFR_8000)
660#define RTP_ADD_PAYLOAD_RED_SUPPORTED (1L << (RTP_ADD_PAYLOAD_RED - RTP_ADD_PAYLOAD_BASE))
661#define RTP_ADD_PAYLOAD_CN_8000_SUPPORTED (1L << (RTP_ADD_PAYLOAD_CN_8000 - RTP_ADD_PAYLOAD_BASE))
662#define RTP_ADD_PAYLOAD_DTMF_SUPPORTED (1L << (RTP_ADD_PAYLOAD_DTMF - RTP_ADD_PAYLOAD_BASE))
663/* virtual switching definitions */
664#define VSJOIN 1
665#define VSTRANSPORT 2
666#define VSGETPARAMS 3
667#define VSCAD 1
668#define VSRXCPNAME 2
669#define VSCALLSTAT 3
670#define VSINVOKEID 4
671#define VSCLMRKS 5
672#define VSTBCTIDENT 6
673#define VSETSILINKID 7
674#define VSSAMECONTROLLER 8
675/* Errorcodes for VSETSILINKID begin */
676#define VSETSILINKIDRRWC 1
677#define VSETSILINKIDREJECT 2
678#define VSETSILINKIDTIMEOUT 3
679#define VSETSILINKIDFAILCOUNT 4
680#define VSETSILINKIDERROR 5
681/* Errorcodes for VSETSILINKID end */
682/* -----------------------------------------------------------**
683** The PROTOCOL_FEATURE_STRING in feature.h (included **
684** in prstart.sx and astart.sx) defines capabilities and **
685** features of the actual protocol code. It's used as a bit **
686** mask. **
687** The following Bits are defined: **
688** -----------------------------------------------------------*/
689#define PROTCAP_TELINDUS 0x0001 /* Telindus Variant of protocol code */
690#define PROTCAP_MAN_IF 0x0002 /* Management interface implemented */
691#define PROTCAP_V_42 0x0004 /* V42 implemented */
692#define PROTCAP_V90D 0x0008 /* V.90D (implies up to 384k DSP code) */
693#define PROTCAP_EXTD_FAX 0x0010 /* Extended FAX (ECM, 2D, T6, Polling) */
694#define PROTCAP_EXTD_RXFC 0x0020 /* RxFC (Extd Flow Control), OOB Chnl */
695#define PROTCAP_VOIP 0x0040 /* VoIP (implies up to 512k DSP code) */
696#define PROTCAP_CMA_ALLPR 0x0080 /* CMA support for all NL primitives */
697#define PROTCAP_FREE8 0x0100 /* not used */
698#define PROTCAP_FREE9 0x0200 /* not used */
699#define PROTCAP_FREE10 0x0400 /* not used */
700#define PROTCAP_FREE11 0x0800 /* not used */
701#define PROTCAP_FREE12 0x1000 /* not used */
702#define PROTCAP_FREE13 0x2000 /* not used */
703#define PROTCAP_FREE14 0x4000 /* not used */
704#define PROTCAP_EXTENSION 0x8000 /* used for future extentions */
705/* -----------------------------------------------------------* */
706/* Onhook data transmission ETS30065901 */
707/* Message Type */
708/*#define RESERVED4 0x4*/
709#define CALL_SETUP 0x80
710#define MESSAGE_WAITING_INDICATOR 0x82
711/*#define RESERVED84 0x84*/
712/*#define RESERVED85 0x85*/
713#define ADVICE_OF_CHARGE 0x86
714/*1111 0001
715to
7161111 1111
717F1H - Reserved for network operator use
718to
719FFH*/
720/* Parameter Types */
721#define DATE_AND_TIME 1
722#define CLI_PARAMETER_TYPE 2
723#define CALLED_DIRECTORY_NUMBER_PARAMETER_TYPE 3
724#define REASON_FOR_ABSENCE_OF_CLI_PARAMETER_TYPE 4
725#define NAME_PARAMETER_TYPE 7
726#define REASON_FOR_ABSENCE_OF_CALLING_PARTY_NAME_PARAMETER_TYPE 8
727#define VISUAL_INDICATOR_PARAMETER_TYPE 0xb
728#define COMPLEMENTARY_CLI_PARAMETER_TYPE 0x10
729#define CALL_TYPE_PARAMETER_TYPE 0x11
730#define FIRST_CALLED_LINE_DIRECTORY_NUMBER_PARAMETER_TYPE 0x12
731#define NETWORK_MESSAGE_SYSTEM_STATUS_PARAMETER_TYPE 0x13
732#define FORWARDED_CALL_TYPE_PARAMETER_TYPE 0x15
733#define TYPE_OF_CALLING_USER_PARAMETER_TYPE 0x16
734#define REDIRECTING_NUMBER_PARAMETER_TYPE 0x1a
735#define EXTENSION_FOR_NETWORK_OPERATOR_USE_PARAMETER_TYPE 0xe0
736/* -----------------------------------------------------------* */
737#else
738#endif /* PC_H_INCLUDED } */
diff --git a/drivers/isdn/hardware/eicon/pc_init.h b/drivers/isdn/hardware/eicon/pc_init.h
new file mode 100644
index 000000000000..a616fc9d32e9
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/pc_init.h
@@ -0,0 +1,267 @@
1
2/*
3 *
4 Copyright (c) Eicon Networks, 2002.
5 *
6 This source file is supplied for the use with
7 Eicon Networks range of DIVA Server Adapters.
8 *
9 Eicon File Revision : 2.1
10 *
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2, or (at your option)
14 any later version.
15 *
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
18 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 See the GNU General Public License for more details.
20 *
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26#ifndef PC_INIT_H_
27#define PC_INIT_H_
28/*------------------------------------------------------------------*/
29/*
30 Initialisation parameters for the card
31 0x0008 <byte> TEI
32 0x0009 <byte> NT2 flag
33 0x000a <byte> Default DID length
34 0x000b <byte> Disable watchdog flag
35 0x000c <byte> Permanent connection flag
36 0x000d <byte> Bit 3-8: L1 Hunt Group/Tristate
37 0x000d <byte> Bit 1: QSig small CR length if set to 1
38 0x000d <byte> Bit 2: QSig small CHI length if set to 1
39 0x000e <byte> Bit 1-3: Stable L2, 0=OnDemand,1=NoDisc,2=permanent
40 0x000e <byte> Bit 4: NT mode
41 0x000e <byte> Bit 5: QSig Channel ID format
42 0x000e <byte> Bit 6: QSig Call Forwarding Allowed Flag
43 0x000e <byte> Bit 7: Disable AutoSPID Flag
44 0x000f <byte> No order check flag
45 0x0010 <byte> Force companding type:0=default,1=a-law,2=u-law
46 0x0012 <byte> Low channel flag
47 0x0013 <byte> Protocol version
48 0x0014 <byte> CRC4 option:0=default,1=double_frm,2=multi_frm,3=auto
49 0x0015 <byte> Bit 0: NoHscx30, Bit 1: Loopback flag, Bit 2: ForceHscx30
50 0x0016 <byte> DSP info
51 0x0017-0x0019 Serial number
52 0x001a <byte> Card type
53 0x0020 <string> OAD 0
54 0x0040 <string> OSA 0
55 0x0060 <string> SPID 0 (if not T.1)
56 0x0060 <struct> if T.1: Robbed Bit Configuration
57 0x0060 length (8)
58 0x0061 RBS Answer Delay
59 0x0062 RBS Config Bit 3, 4:
60 0 0 -> Wink Start
61 1 0 -> Loop Start
62 0 1 -> Ground Start
63 1 1 -> reserved
64 Bit 5, 6:
65 0 0 -> Pulse Dial -> Rotary
66 1 0 -> DTMF
67 0 1 -> MF
68 1 1 -> reserved
69 0x0063 RBS RX Digit Timeout
70 0x0064 RBS Bearer Capability
71 0x0065-0x0069 RBS Debug Mask
72 0x0080 <string> OAD 1
73 0x00a0 <string> OSA 1
74 0x00c0 <string> SPID 1
75 0x00e0 <w-element list> Additional configuration
76*/
77#define PCINIT_END_OF_LIST 0x00
78#define PCINIT_MODEM_GUARD_TONE 0x01
79#define PCINIT_MODEM_MIN_SPEED 0x02
80#define PCINIT_MODEM_MAX_SPEED 0x03
81#define PCINIT_MODEM_PROTOCOL_OPTIONS 0x04
82#define PCINIT_FAX_OPTIONS 0x05
83#define PCINIT_FAX_MAX_SPEED 0x06
84#define PCINIT_MODEM_OPTIONS 0x07
85#define PCINIT_MODEM_NEGOTIATION_MODE 0x08
86#define PCINIT_MODEM_MODULATIONS_MASK 0x09
87#define PCINIT_MODEM_TRANSMIT_LEVEL 0x0a
88#define PCINIT_FAX_DISABLED_RESOLUTIONS 0x0b
89#define PCINIT_FAX_MAX_RECORDING_WIDTH 0x0c
90#define PCINIT_FAX_MAX_RECORDING_LENGTH 0x0d
91#define PCINIT_FAX_MIN_SCANLINE_TIME 0x0e
92#define PCINIT_US_EKTS_CACH_HANDLES 0x0f
93#define PCINIT_US_EKTS_BEGIN_CONF 0x10
94#define PCINIT_US_EKTS_DROP_CONF 0x11
95#define PCINIT_US_EKTS_CALL_TRANSFER 0x12
96#define PCINIT_RINGERTONE_OPTION 0x13
97#define PCINIT_CARD_ADDRESS 0x14
98#define PCINIT_FPGA_FEATURES 0x15
99#define PCINIT_US_EKTS_MWI 0x16
100#define PCINIT_MODEM_SPEAKER_CONTROL 0x17
101#define PCINIT_MODEM_SPEAKER_VOLUME 0x18
102#define PCINIT_MODEM_CARRIER_WAIT_TIME 0x19
103#define PCINIT_MODEM_CARRIER_LOSS_TIME 0x1a
104#define PCINIT_UNCHAN_B_MASK 0x1b
105#define PCINIT_PART68_LIMITER 0x1c
106#define PCINIT_XDI_FEATURES 0x1d
107#define PCINIT_QSIG_DIALECT 0x1e
108#define PCINIT_DISABLE_AUTOSPID_FLAG 0x1f
109#define PCINIT_FORCE_VOICE_MAIL_ALERT 0x20
110#define PCINIT_PIAFS_TURNAROUND_FRAMES 0x21
111#define PCINIT_L2_COUNT 0x22
112#define PCINIT_QSIG_FEATURES 0x23
113#define PCINIT_NO_SIGNALLING 0x24
114#define PCINIT_CARD_SN 0x25
115#define PCINIT_CARD_PORT 0x26
116#define PCINIT_ALERTTO 0x27
117#define PCINIT_MODEM_EYE_SETUP 0x28
118#define PCINIT_FAX_V34_OPTIONS 0x29
119/*------------------------------------------------------------------*/
120#define PCINIT_MODEM_GUARD_TONE_NONE 0x00
121#define PCINIT_MODEM_GUARD_TONE_550HZ 0x01
122#define PCINIT_MODEM_GUARD_TONE_1800HZ 0x02
123#define PCINIT_MODEM_GUARD_TONE_CHOICES 0x03
124#define PCINIT_MODEMPROT_DISABLE_V42_V42BIS 0x0001
125#define PCINIT_MODEMPROT_DISABLE_MNP_MNP5 0x0002
126#define PCINIT_MODEMPROT_REQUIRE_PROTOCOL 0x0004
127#define PCINIT_MODEMPROT_DISABLE_V42_DETECT 0x0008
128#define PCINIT_MODEMPROT_DISABLE_COMPRESSION 0x0010
129#define PCINIT_MODEMPROT_REQUIRE_PROTOCOL_V34UP 0x0020
130#define PCINIT_MODEMPROT_NO_PROTOCOL_IF_1200 0x0100
131#define PCINIT_MODEMPROT_BUFFER_IN_V42_DETECT 0x0200
132#define PCINIT_MODEMPROT_DISABLE_V42_SREJ 0x0400
133#define PCINIT_MODEMPROT_DISABLE_MNP3 0x0800
134#define PCINIT_MODEMPROT_DISABLE_MNP4 0x1000
135#define PCINIT_MODEMPROT_DISABLE_MNP10 0x2000
136#define PCINIT_MODEMPROT_NO_PROTOCOL_IF_V22BIS 0x4000
137#define PCINIT_MODEMPROT_NO_PROTOCOL_IF_V32BIS 0x8000
138#define PCINIT_MODEMCONFIG_LEASED_LINE_MODE 0x00000001L
139#define PCINIT_MODEMCONFIG_4_WIRE_OPERATION 0x00000002L
140#define PCINIT_MODEMCONFIG_DISABLE_BUSY_DETECT 0x00000004L
141#define PCINIT_MODEMCONFIG_DISABLE_CALLING_TONE 0x00000008L
142#define PCINIT_MODEMCONFIG_DISABLE_ANSWER_TONE 0x00000010L
143#define PCINIT_MODEMCONFIG_ENABLE_DIAL_TONE_DET 0x00000020L
144#define PCINIT_MODEMCONFIG_USE_POTS_INTERFACE 0x00000040L
145#define PCINIT_MODEMCONFIG_FORCE_RAY_TAYLOR_FAX 0x00000080L
146#define PCINIT_MODEMCONFIG_DISABLE_RETRAIN 0x00000100L
147#define PCINIT_MODEMCONFIG_DISABLE_STEPDOWN 0x00000200L
148#define PCINIT_MODEMCONFIG_DISABLE_SPLIT_SPEED 0x00000400L
149#define PCINIT_MODEMCONFIG_DISABLE_TRELLIS 0x00000800L
150#define PCINIT_MODEMCONFIG_ALLOW_RDL_TEST_LOOP 0x00001000L
151#define PCINIT_MODEMCONFIG_DISABLE_STEPUP 0x00002000L
152#define PCINIT_MODEMCONFIG_DISABLE_FLUSH_TIMER 0x00004000L
153#define PCINIT_MODEMCONFIG_REVERSE_DIRECTION 0x00008000L
154#define PCINIT_MODEMCONFIG_DISABLE_TX_REDUCTION 0x00010000L
155#define PCINIT_MODEMCONFIG_DISABLE_PRECODING 0x00020000L
156#define PCINIT_MODEMCONFIG_DISABLE_PREEMPHASIS 0x00040000L
157#define PCINIT_MODEMCONFIG_DISABLE_SHAPING 0x00080000L
158#define PCINIT_MODEMCONFIG_DISABLE_NONLINEAR_EN 0x00100000L
159#define PCINIT_MODEMCONFIG_DISABLE_MANUALREDUCT 0x00200000L
160#define PCINIT_MODEMCONFIG_DISABLE_16_POINT_TRN 0x00400000L
161#define PCINIT_MODEMCONFIG_DISABLE_2400_SYMBOLS 0x01000000L
162#define PCINIT_MODEMCONFIG_DISABLE_2743_SYMBOLS 0x02000000L
163#define PCINIT_MODEMCONFIG_DISABLE_2800_SYMBOLS 0x04000000L
164#define PCINIT_MODEMCONFIG_DISABLE_3000_SYMBOLS 0x08000000L
165#define PCINIT_MODEMCONFIG_DISABLE_3200_SYMBOLS 0x10000000L
166#define PCINIT_MODEMCONFIG_DISABLE_3429_SYMBOLS 0x20000000L
167#define PCINIT_MODEM_NEGOTIATE_HIGHEST 0x00
168#define PCINIT_MODEM_NEGOTIATE_DISABLED 0x01
169#define PCINIT_MODEM_NEGOTIATE_IN_CLASS 0x02
170#define PCINIT_MODEM_NEGOTIATE_V100 0x03
171#define PCINIT_MODEM_NEGOTIATE_V8 0x04
172#define PCINIT_MODEM_NEGOTIATE_V8BIS 0x05
173#define PCINIT_MODEM_NEGOTIATE_CHOICES 0x06
174#define PCINIT_MODEMMODULATION_DISABLE_V21 0x00000001L
175#define PCINIT_MODEMMODULATION_DISABLE_V23 0x00000002L
176#define PCINIT_MODEMMODULATION_DISABLE_V22 0x00000004L
177#define PCINIT_MODEMMODULATION_DISABLE_V22BIS 0x00000008L
178#define PCINIT_MODEMMODULATION_DISABLE_V32 0x00000010L
179#define PCINIT_MODEMMODULATION_DISABLE_V32BIS 0x00000020L
180#define PCINIT_MODEMMODULATION_DISABLE_V34 0x00000040L
181#define PCINIT_MODEMMODULATION_DISABLE_V90 0x00000080L
182#define PCINIT_MODEMMODULATION_DISABLE_BELL103 0x00000100L
183#define PCINIT_MODEMMODULATION_DISABLE_BELL212A 0x00000200L
184#define PCINIT_MODEMMODULATION_DISABLE_VFC 0x00000400L
185#define PCINIT_MODEMMODULATION_DISABLE_K56FLEX 0x00000800L
186#define PCINIT_MODEMMODULATION_DISABLE_X2 0x00001000L
187#define PCINIT_MODEMMODULATION_ENABLE_V29FDX 0x00010000L
188#define PCINIT_MODEMMODULATION_ENABLE_V33 0x00020000L
189#define PCINIT_MODEMMODULATION_ENABLE_V90A 0x00040000L
190#define PCINIT_MODEM_TRANSMIT_LEVEL_CHOICES 0x10
191#define PCINIT_MODEM_SPEAKER_OFF 0x00
192#define PCINIT_MODEM_SPEAKER_DURING_TRAIN 0x01
193#define PCINIT_MODEM_SPEAKER_TIL_CONNECT 0x02
194#define PCINIT_MODEM_SPEAKER_ALWAYS_ON 0x03
195#define PCINIT_MODEM_SPEAKER_CHOICES 0x04
196#define PCINIT_MODEM_SPEAKER_VOLUME_MIN 0x00
197#define PCINIT_MODEM_SPEAKER_VOLUME_LOW 0x01
198#define PCINIT_MODEM_SPEAKER_VOLUME_HIGH 0x02
199#define PCINIT_MODEM_SPEAKER_VOLUME_MAX 0x03
200#define PCINIT_MODEM_SPEAKER_VOLUME_CHOICES 0x04
201/*------------------------------------------------------------------*/
202#define PCINIT_FAXCONFIG_DISABLE_FINE 0x0001
203#define PCINIT_FAXCONFIG_DISABLE_ECM 0x0002
204#define PCINIT_FAXCONFIG_ECM_64_BYTES 0x0004
205#define PCINIT_FAXCONFIG_DISABLE_2D_CODING 0x0008
206#define PCINIT_FAXCONFIG_DISABLE_T6_CODING 0x0010
207#define PCINIT_FAXCONFIG_DISABLE_UNCOMPR 0x0020
208#define PCINIT_FAXCONFIG_REFUSE_POLLING 0x0040
209#define PCINIT_FAXCONFIG_HIDE_TOTAL_PAGES 0x0080
210#define PCINIT_FAXCONFIG_HIDE_ALL_HEADLINE 0x0100
211#define PCINIT_FAXCONFIG_HIDE_PAGE_INFO 0x0180
212#define PCINIT_FAXCONFIG_HEADLINE_OPTIONS_MASK 0x0180
213#define PCINIT_FAXCONFIG_DISABLE_FEATURE_FALLBACK 0x0200
214#define PCINIT_FAXCONFIG_V34FAX_CONTROL_RATE_1200 0x0800
215#define PCINIT_FAXCONFIG_DISABLE_V34FAX 0x1000
216#define PCINIT_FAXCONFIG_DISABLE_R8_0770_OR_200 0x01
217#define PCINIT_FAXCONFIG_DISABLE_R8_1540 0x02
218#define PCINIT_FAXCONFIG_DISABLE_R16_1540_OR_400 0x04
219#define PCINIT_FAXCONFIG_DISABLE_R4_0385_OR_100 0x08
220#define PCINIT_FAXCONFIG_DISABLE_300_300 0x10
221#define PCINIT_FAXCONFIG_DISABLE_INCH_BASED 0x40
222#define PCINIT_FAXCONFIG_DISABLE_METRIC_BASED 0x80
223#define PCINIT_FAXCONFIG_REC_WIDTH_ISO_A3 0
224#define PCINIT_FAXCONFIG_REC_WIDTH_ISO_B4 1
225#define PCINIT_FAXCONFIG_REC_WIDTH_ISO_A4 2
226#define PCINIT_FAXCONFIG_REC_WIDTH_COUNT 3
227#define PCINIT_FAXCONFIG_REC_LENGTH_UNLIMITED 0
228#define PCINIT_FAXCONFIG_REC_LENGTH_ISO_B4 1
229#define PCINIT_FAXCONFIG_REC_LENGTH_ISO_A4 2
230#define PCINIT_FAXCONFIG_REC_LENGTH_COUNT 3
231#define PCINIT_FAXCONFIG_SCANLINE_TIME_00_00_00 0
232#define PCINIT_FAXCONFIG_SCANLINE_TIME_05_05_05 1
233#define PCINIT_FAXCONFIG_SCANLINE_TIME_10_05_05 2
234#define PCINIT_FAXCONFIG_SCANLINE_TIME_10_10_10 3
235#define PCINIT_FAXCONFIG_SCANLINE_TIME_20_10_10 4
236#define PCINIT_FAXCONFIG_SCANLINE_TIME_20_20_20 5
237#define PCINIT_FAXCONFIG_SCANLINE_TIME_40_20_20 6
238#define PCINIT_FAXCONFIG_SCANLINE_TIME_40_40_40 7
239#define PCINIT_FAXCONFIG_SCANLINE_TIME_RES_8 8
240#define PCINIT_FAXCONFIG_SCANLINE_TIME_RES_9 9
241#define PCINIT_FAXCONFIG_SCANLINE_TIME_RES_10 10
242#define PCINIT_FAXCONFIG_SCANLINE_TIME_10_10_05 11
243#define PCINIT_FAXCONFIG_SCANLINE_TIME_20_10_05 12
244#define PCINIT_FAXCONFIG_SCANLINE_TIME_20_20_10 13
245#define PCINIT_FAXCONFIG_SCANLINE_TIME_40_20_10 14
246#define PCINIT_FAXCONFIG_SCANLINE_TIME_40_40_20 15
247#define PCINIT_FAXCONFIG_SCANLINE_TIME_COUNT 16
248#define PCINIT_FAXCONFIG_DISABLE_TX_REDUCTION 0x00010000L
249#define PCINIT_FAXCONFIG_DISABLE_PRECODING 0x00020000L
250#define PCINIT_FAXCONFIG_DISABLE_PREEMPHASIS 0x00040000L
251#define PCINIT_FAXCONFIG_DISABLE_SHAPING 0x00080000L
252#define PCINIT_FAXCONFIG_DISABLE_NONLINEAR_EN 0x00100000L
253#define PCINIT_FAXCONFIG_DISABLE_MANUALREDUCT 0x00200000L
254#define PCINIT_FAXCONFIG_DISABLE_16_POINT_TRN 0x00400000L
255#define PCINIT_FAXCONFIG_DISABLE_2400_SYMBOLS 0x01000000L
256#define PCINIT_FAXCONFIG_DISABLE_2743_SYMBOLS 0x02000000L
257#define PCINIT_FAXCONFIG_DISABLE_2800_SYMBOLS 0x04000000L
258#define PCINIT_FAXCONFIG_DISABLE_3000_SYMBOLS 0x08000000L
259#define PCINIT_FAXCONFIG_DISABLE_3200_SYMBOLS 0x10000000L
260#define PCINIT_FAXCONFIG_DISABLE_3429_SYMBOLS 0x20000000L
261/*--------------------------------------------------------------------------*/
262#define PCINIT_XDI_CMA_FOR_ALL_NL_PRIMITIVES 0x01
263/*--------------------------------------------------------------------------*/
264#define PCINIT_FPGA_PLX_ACCESS_SUPPORTED 0x01
265/*--------------------------------------------------------------------------*/
266#endif
267/*--------------------------------------------------------------------------*/
diff --git a/drivers/isdn/hardware/eicon/pc_maint.h b/drivers/isdn/hardware/eicon/pc_maint.h
new file mode 100644
index 000000000000..352ab8dafb22
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/pc_maint.h
@@ -0,0 +1,160 @@
1
2/*
3 *
4 Copyright (c) Eicon Networks, 2002.
5 *
6 This source file is supplied for the use with
7 Eicon Networks range of DIVA Server Adapters.
8 *
9 Eicon File Revision : 2.1
10 *
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2, or (at your option)
14 any later version.
15 *
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
18 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 See the GNU General Public License for more details.
20 *
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26#ifdef PLATFORM_GT_32BIT
27/* #define POINTER_32BIT byte * __ptr32 */
28#define POINTER_32BIT dword
29#else
30#define POINTER_32BIT byte *
31#endif
32#if !defined(MIPS_SCOM)
33#define BUFFER_SZ 48
34#define MAINT_OFFS 0x380
35#else
36#define BUFFER_SZ 128
37#if defined(PRI)
38#define MAINT_OFFS 0xef00
39#else
40#define MAINT_OFFS 0xff00
41#endif
42#endif
43#define MIPS_BUFFER_SZ 128
44#if defined(PRI)
45#define MIPS_MAINT_OFFS 0xef00
46#else
47#define MIPS_MAINT_OFFS 0xff00
48#endif
49#define LOG 1
50#define MEMR 2
51#define MEMW 3
52#define IOR 4
53#define IOW 5
54#define B1TEST 6
55#define B2TEST 7
56#define BTESTOFF 8
57#define DSIG_STATS 9
58#define B_CH_STATS 10
59#define D_CH_STATS 11
60#define BL1_STATS 12
61#define BL1_STATS_C 13
62#define GET_VERSION 14
63#define OS_STATS 15
64#define XLOG_SET_MASK 16
65#define XLOG_GET_MASK 17
66#define DSP_READ 20
67#define DSP_WRITE 21
68#define OK 0xff
69#define MORE_EVENTS 0xfe
70#define NO_EVENT 1
71struct DSigStruc
72{
73 byte Id;
74 byte u;
75 byte listen;
76 byte active;
77 byte sin[3];
78 byte bc[6];
79 byte llc[6];
80 byte hlc[6];
81 byte oad[20];
82};
83struct BL1Struc {
84 dword cx_b1;
85 dword cx_b2;
86 dword cr_b1;
87 dword cr_b2;
88 dword px_b1;
89 dword px_b2;
90 dword pr_b1;
91 dword pr_b2;
92 word er_b1;
93 word er_b2;
94};
95struct L2Struc {
96 dword XTotal;
97 dword RTotal;
98 word XError;
99 word RError;
100};
101struct OSStruc {
102 dword free_n;
103};
104typedef union
105{
106 struct DSigStruc DSigStats;
107 struct BL1Struc BL1Stats;
108 struct L2Struc L2Stats;
109 struct OSStruc OSStats;
110 byte b[BUFFER_SZ];
111 word w[BUFFER_SZ>>1];
112 word l[BUFFER_SZ>>2]; /* word is wrong, do not use! Use 'd' instead. */
113 dword d[BUFFER_SZ>>2];
114} BUFFER;
115typedef union
116{
117 struct DSigStruc DSigStats;
118 struct BL1Struc BL1Stats;
119 struct L2Struc L2Stats;
120 struct OSStruc OSStats;
121 byte b[MIPS_BUFFER_SZ];
122 word w[MIPS_BUFFER_SZ>>1];
123 word l[BUFFER_SZ>>2]; /* word is wrong, do not use! Use 'd' instead. */
124 dword d[MIPS_BUFFER_SZ>>2];
125} MIPS_BUFFER;
126#if !defined(MIPS_SCOM)
127struct pc_maint
128{
129 byte req;
130 byte rc;
131 POINTER_32BIT mem;
132 short length;
133 word port;
134 byte fill[6];
135 BUFFER data;
136};
137#else
138struct pc_maint
139{
140 byte req;
141 byte rc;
142 byte reserved[2]; /* R3000 alignment ... */
143 POINTER_32BIT mem;
144 short length;
145 word port;
146 byte fill[4]; /* data at offset 16 */
147 BUFFER data;
148};
149#endif
150struct mi_pc_maint
151{
152 byte req;
153 byte rc;
154 byte reserved[2]; /* R3000 alignment ... */
155 POINTER_32BIT mem;
156 short length;
157 word port;
158 byte fill[4]; /* data at offset 16 */
159 MIPS_BUFFER data;
160};
diff --git a/drivers/isdn/hardware/eicon/pkmaint.h b/drivers/isdn/hardware/eicon/pkmaint.h
new file mode 100644
index 000000000000..722f85fe42f6
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/pkmaint.h
@@ -0,0 +1,44 @@
1
2/*
3 *
4 Copyright (c) Eicon Networks, 2002.
5 *
6 This source file is supplied for the use with
7 Eicon Networks range of DIVA Server Adapters.
8 *
9 Eicon File Revision : 2.1
10 *
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2, or (at your option)
14 any later version.
15 *
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
18 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 See the GNU General Public License for more details.
20 *
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26#ifndef __DIVA_XDI_OS_DEPENDENT_PACK_MAIN_ON_BYTE_INC__
27#define __DIVA_XDI_OS_DEPENDENT_PACK_MAIN_ON_BYTE_INC__
28
29
30/*
31 Only one purpose of this compiler dependent file to pack
32 structures, described in pc_maint.h so that no padding
33 will be included.
34
35 With microsoft compile it is done by "pshpack1.h" and
36 after is restored by "poppack.h"
37 */
38
39
40#include "pc_maint.h"
41
42
43#endif
44
diff --git a/drivers/isdn/hardware/eicon/platform.h b/drivers/isdn/hardware/eicon/platform.h
new file mode 100644
index 000000000000..12b8ff29e976
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/platform.h
@@ -0,0 +1,394 @@
1/* $Id: platform.h,v 1.37.4.6 2005/01/31 12:22:20 armin Exp $
2 *
3 * platform.h
4 *
5 *
6 * Copyright 2000-2003 by Armin Schindler (mac@melware.de)
7 * Copyright 2000 Eicon Networks
8 *
9 * This software may be used and distributed according to the terms
10 * of the GNU General Public License, incorporated herein by reference.
11 */
12
13
14#ifndef __PLATFORM_H__
15#define __PLATFORM_H__
16
17#if !defined(DIVA_BUILD)
18#define DIVA_BUILD "local"
19#endif
20
21#include <linux/config.h>
22#include <linux/module.h>
23#include <linux/init.h>
24#include <linux/kernel.h>
25#include <linux/sched.h>
26#include <linux/skbuff.h>
27#include <linux/vmalloc.h>
28#include <linux/proc_fs.h>
29#include <linux/interrupt.h>
30#include <linux/smp_lock.h>
31#include <linux/delay.h>
32#include <linux/list.h>
33#include <asm/types.h>
34#include <asm/io.h>
35
36#include "cardtype.h"
37
38/* activate debuglib for modules only */
39#ifndef MODULE
40#define DIVA_NO_DEBUGLIB
41#endif
42
43#define DIVA_INIT_FUNCTION __init
44#define DIVA_EXIT_FUNCTION __exit
45
46#define DIVA_USER_MODE_CARD_CONFIG 1
47#define USE_EXTENDED_DEBUGS 1
48
49#define MAX_ADAPTER 32
50
51#define DIVA_ISTREAM 1
52
53#define MEMORY_SPACE_TYPE 0
54#define PORT_SPACE_TYPE 1
55
56
57#include <linux/string.h>
58
59#ifndef byte
60#define byte u8
61#endif
62
63#ifndef word
64#define word u16
65#endif
66
67#ifndef dword
68#define dword u32
69#endif
70
71#ifndef qword
72#define qword u64
73#endif
74
75#ifndef TRUE
76#define TRUE 1
77#endif
78
79#ifndef FALSE
80#define FALSE 0
81#endif
82
83#ifndef NULL
84#define NULL ((void *) 0)
85#endif
86
87#ifndef MIN
88#define MIN(a,b) ((a)>(b) ? (b) : (a))
89#endif
90
91#ifndef MAX
92#define MAX(a,b) ((a)>(b) ? (a) : (b))
93#endif
94
95#ifndef far
96#define far
97#endif
98
99#ifndef _pascal
100#define _pascal
101#endif
102
103#ifndef _loadds
104#define _loadds
105#endif
106
107#ifndef _cdecl
108#define _cdecl
109#endif
110
111#define MEM_TYPE_RAM 0
112#define MEM_TYPE_PORT 1
113#define MEM_TYPE_PROM 2
114#define MEM_TYPE_CTLREG 3
115#define MEM_TYPE_RESET 4
116#define MEM_TYPE_CFG 5
117#define MEM_TYPE_ADDRESS 6
118#define MEM_TYPE_CONFIG 7
119#define MEM_TYPE_CONTROL 8
120
121#define MAX_MEM_TYPE 10
122
123#define DIVA_OS_MEM_ATTACH_RAM(a) ((a)->ram)
124#define DIVA_OS_MEM_ATTACH_PORT(a) ((a)->port)
125#define DIVA_OS_MEM_ATTACH_PROM(a) ((a)->prom)
126#define DIVA_OS_MEM_ATTACH_CTLREG(a) ((a)->ctlReg)
127#define DIVA_OS_MEM_ATTACH_RESET(a) ((a)->reset)
128#define DIVA_OS_MEM_ATTACH_CFG(a) ((a)->cfg)
129#define DIVA_OS_MEM_ATTACH_ADDRESS(a) ((a)->Address)
130#define DIVA_OS_MEM_ATTACH_CONFIG(a) ((a)->Config)
131#define DIVA_OS_MEM_ATTACH_CONTROL(a) ((a)->Control)
132
133#define DIVA_OS_MEM_DETACH_RAM(a, x) do { } while(0)
134#define DIVA_OS_MEM_DETACH_PORT(a, x) do { } while(0)
135#define DIVA_OS_MEM_DETACH_PROM(a, x) do { } while(0)
136#define DIVA_OS_MEM_DETACH_CTLREG(a, x) do { } while(0)
137#define DIVA_OS_MEM_DETACH_RESET(a, x) do { } while(0)
138#define DIVA_OS_MEM_DETACH_CFG(a, x) do { } while(0)
139#define DIVA_OS_MEM_DETACH_ADDRESS(a, x) do { } while(0)
140#define DIVA_OS_MEM_DETACH_CONFIG(a, x) do { } while(0)
141#define DIVA_OS_MEM_DETACH_CONTROL(a, x) do { } while(0)
142
143#if !defined(DIM)
144#define DIM(array) (sizeof (array)/sizeof ((array)[0]))
145#endif
146
147#define DIVA_INVALID_FILE_HANDLE ((dword)(-1))
148
149#define DIVAS_CONTAINING_RECORD(address, type, field) \
150 ((type *)((char*)(address) - (char*)(&((type *)0)->field)))
151
152extern int sprintf(char *, const char*, ...);
153
154typedef void* LIST_ENTRY;
155
156typedef char DEVICE_NAME[64];
157typedef struct _ISDN_ADAPTER ISDN_ADAPTER;
158typedef struct _ISDN_ADAPTER* PISDN_ADAPTER;
159
160typedef void (* DIVA_DI_PRINTF) (unsigned char *, ...);
161#include "debuglib.h"
162
163#define dtrc(p) DBG_PRV0(p)
164#define dbug(a,p) DBG_PRV1(p)
165
166
167typedef struct e_info_s E_INFO ;
168
169typedef char diva_os_dependent_devica_name_t[64];
170typedef void* PDEVICE_OBJECT;
171
172struct _diva_os_soft_isr;
173struct _diva_os_timer;
174struct _ISDN_ADAPTER;
175
176void diva_log_info(unsigned char *, ...);
177
178/*
179** XDI DIDD Interface
180*/
181void diva_xdi_didd_register_adapter (int card);
182void diva_xdi_didd_remove_adapter (int card);
183
184/*
185** memory allocation
186*/
187static __inline__ void* diva_os_malloc (unsigned long flags, unsigned long size)
188{
189 void *ret = NULL;
190
191 if (size) {
192 ret = (void *) vmalloc((unsigned int) size);
193 }
194 return (ret);
195}
196static __inline__ void diva_os_free (unsigned long flags, void* ptr)
197{
198 vfree(ptr);
199}
200
201/*
202** use skbuffs for message buffer
203*/
204typedef struct sk_buff diva_os_message_buffer_s;
205diva_os_message_buffer_s *diva_os_alloc_message_buffer(unsigned long size, void **data_buf);
206void diva_os_free_message_buffer(diva_os_message_buffer_s *dmb);
207#define DIVA_MESSAGE_BUFFER_LEN(x) x->len
208#define DIVA_MESSAGE_BUFFER_DATA(x) x->data
209
210/*
211** mSeconds waiting
212*/
213static __inline__ void diva_os_sleep(dword mSec)
214{
215 msleep(mSec);
216}
217static __inline__ void diva_os_wait(dword mSec)
218{
219 mdelay(mSec);
220}
221
222/*
223** PCI Configuration space access
224*/
225void PCIwrite (byte bus, byte func, int offset, void* data, int length, void* pci_dev_handle);
226void PCIread (byte bus, byte func, int offset, void* data, int length, void* pci_dev_handle);
227
228/*
229** I/O Port utilities
230*/
231int diva_os_register_io_port (void *adapter, int register, unsigned long port,
232 unsigned long length, const char* name, int id);
233/*
234** I/O port access abstraction
235*/
236byte inpp (void __iomem *);
237word inppw (void __iomem *);
238void inppw_buffer (void __iomem *, void*, int);
239void outppw (void __iomem *, word);
240void outppw_buffer (void __iomem * , void*, int);
241void outpp (void __iomem *, word);
242
243/*
244** IRQ
245*/
246typedef struct _diva_os_adapter_irq_info {
247 byte irq_nr;
248 int registered;
249 char irq_name[24];
250} diva_os_adapter_irq_info_t;
251int diva_os_register_irq (void* context, byte irq, const char* name);
252void diva_os_remove_irq (void* context, byte irq);
253
254#define diva_os_in_irq() in_irq()
255
256/*
257** Spin Lock framework
258*/
259typedef long diva_os_spin_lock_magic_t;
260typedef spinlock_t diva_os_spin_lock_t;
261static __inline__ int diva_os_initialize_spin_lock (spinlock_t *lock, void * unused) { \
262 spin_lock_init (lock); return(0); }
263static __inline__ void diva_os_enter_spin_lock (diva_os_spin_lock_t* a, \
264 diva_os_spin_lock_magic_t* old_irql, \
265 void* dbg) { spin_lock_bh(a); }
266static __inline__ void diva_os_leave_spin_lock (diva_os_spin_lock_t* a, \
267 diva_os_spin_lock_magic_t* old_irql, \
268 void* dbg) { spin_unlock_bh(a); }
269
270#define diva_os_destroy_spin_lock(a,b) do { } while(0)
271
272/*
273** Deffered processing framework
274*/
275typedef int (*diva_os_isr_callback_t)(struct _ISDN_ADAPTER*);
276typedef void (*diva_os_soft_isr_callback_t)(struct _diva_os_soft_isr* psoft_isr, void* context);
277
278typedef struct _diva_os_soft_isr {
279 void* object;
280 diva_os_soft_isr_callback_t callback;
281 void* callback_context;
282 char dpc_thread_name[24];
283} diva_os_soft_isr_t;
284
285int diva_os_initialize_soft_isr (diva_os_soft_isr_t* psoft_isr, diva_os_soft_isr_callback_t callback, void* callback_context);
286int diva_os_schedule_soft_isr (diva_os_soft_isr_t* psoft_isr);
287int diva_os_cancel_soft_isr (diva_os_soft_isr_t* psoft_isr);
288void diva_os_remove_soft_isr (diva_os_soft_isr_t* psoft_isr);
289
290/*
291 Get time service
292 */
293void diva_os_get_time (dword* sec, dword* usec);
294
295/*
296** atomic operation, fake because we use threads
297*/
298typedef int diva_os_atomic_t;
299static diva_os_atomic_t __inline__
300diva_os_atomic_increment(diva_os_atomic_t* pv)
301{
302 *pv += 1;
303 return (*pv);
304}
305static diva_os_atomic_t __inline__
306diva_os_atomic_decrement(diva_os_atomic_t* pv)
307{
308 *pv -= 1;
309 return (*pv);
310}
311
312/*
313** CAPI SECTION
314*/
315#define NO_CORNETN
316#define IMPLEMENT_DTMF 1
317#define IMPLEMENT_ECHO_CANCELLER 1
318#define IMPLEMENT_RTP 1
319#define IMPLEMENT_T38 1
320#define IMPLEMENT_FAX_SUB_SEP_PWD 1
321#define IMPLEMENT_V18 1
322#define IMPLEMENT_DTMF_TONE 1
323#define IMPLEMENT_PIAFS 1
324#define IMPLEMENT_FAX_PAPER_FORMATS 1
325#define IMPLEMENT_VOWN 1
326#define IMPLEMENT_CAPIDTMF 1
327#define IMPLEMENT_FAX_NONSTANDARD 1
328#define VSWITCH_SUPPORT 1
329
330#define IMPLEMENT_MARKED_OK_AFTER_FC 1
331
332#define DIVA_IDI_RX_DMA 1
333
334/*
335** endian macros
336**
337** If only... In some cases we did use them for endianness conversion;
338** unfortunately, other uses were real iomem accesses.
339*/
340#define READ_BYTE(addr) readb(addr)
341#define READ_WORD(addr) readw(addr)
342#define READ_DWORD(addr) readl(addr)
343
344#define WRITE_BYTE(addr,v) writeb(v,addr)
345#define WRITE_WORD(addr,v) writew(v,addr)
346#define WRITE_DWORD(addr,v) writel(v,addr)
347
348static inline __u16 GET_WORD(void *addr)
349{
350 return le16_to_cpu(*(__le16 *)addr);
351}
352static inline __u32 GET_DWORD(void *addr)
353{
354 return le32_to_cpu(*(__le32 *)addr);
355}
356static inline void PUT_WORD(void *addr, __u16 v)
357{
358 *(__le16 *)addr = cpu_to_le16(v);
359}
360static inline void PUT_DWORD(void *addr, __u32 v)
361{
362 *(__le32 *)addr = cpu_to_le32(v);
363}
364
365/*
366** 32/64 bit macors
367*/
368#ifdef BITS_PER_LONG
369 #if BITS_PER_LONG > 32
370 #define PLATFORM_GT_32BIT
371 #define ULongToPtr(x) (void *)(unsigned long)(x)
372 #endif
373#endif
374
375/*
376** undef os definitions of macros we use
377*/
378#undef ID_MASK
379#undef N_DATA
380#undef ADDR
381
382/*
383** dump file
384*/
385#define diva_os_dump_file_t char
386#define diva_os_board_trace_t char
387#define diva_os_dump_file(__x__) do { } while(0)
388
389/*
390** size of internal arrays
391*/
392#define MAX_DESCRIPTORS 64
393
394#endif /* __PLATFORM_H__ */
diff --git a/drivers/isdn/hardware/eicon/pr_pc.h b/drivers/isdn/hardware/eicon/pr_pc.h
new file mode 100644
index 000000000000..bf49a5af567f
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/pr_pc.h
@@ -0,0 +1,76 @@
1
2/*
3 *
4 Copyright (c) Eicon Networks, 2002.
5 *
6 This source file is supplied for the use with
7 Eicon Networks range of DIVA Server Adapters.
8 *
9 Eicon File Revision : 2.1
10 *
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2, or (at your option)
14 any later version.
15 *
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
18 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 See the GNU General Public License for more details.
20 *
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26struct pr_ram {
27 word NextReq; /* pointer to next Req Buffer */
28 word NextRc; /* pointer to next Rc Buffer */
29 word NextInd; /* pointer to next Ind Buffer */
30 byte ReqInput; /* number of Req Buffers sent */
31 byte ReqOutput; /* number of Req Buffers returned */
32 byte ReqReserved; /* number of Req Buffers reserved */
33 byte Int; /* ISDN-P interrupt */
34 byte XLock; /* Lock field for arbitration */
35 byte RcOutput; /* number of Rc buffers received */
36 byte IndOutput; /* number of Ind buffers received */
37 byte IMask; /* Interrupt Mask Flag */
38 byte Reserved1[2]; /* reserved field, do not use */
39 byte ReadyInt; /* request field for ready interrupt */
40 byte Reserved2[12]; /* reserved field, do not use */
41 byte InterfaceType; /* interface type 1=16K interface */
42 word Signature; /* ISDN-P initialized indication */
43 byte B[1]; /* buffer space for Req,Ind and Rc */
44};
45typedef struct {
46 word next;
47 byte Req;
48 byte ReqId;
49 byte ReqCh;
50 byte Reserved1;
51 word Reference;
52 byte Reserved[8];
53 PBUFFER XBuffer;
54} REQ;
55typedef struct {
56 word next;
57 byte Rc;
58 byte RcId;
59 byte RcCh;
60 byte Reserved1;
61 word Reference;
62 byte Reserved2[8];
63} RC;
64typedef struct {
65 word next;
66 byte Ind;
67 byte IndId;
68 byte IndCh;
69 byte MInd;
70 word MLength;
71 word Reference;
72 byte RNR;
73 byte Reserved;
74 dword Ack;
75 PBUFFER RBuffer;
76} IND;
diff --git a/drivers/isdn/hardware/eicon/s_4bri.c b/drivers/isdn/hardware/eicon/s_4bri.c
new file mode 100644
index 000000000000..25c5d7feb838
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/s_4bri.c
@@ -0,0 +1,510 @@
1
2/*
3 *
4 Copyright (c) Eicon Networks, 2002.
5 *
6 This source file is supplied for the use with
7 Eicon Networks range of DIVA Server Adapters.
8 *
9 Eicon File Revision : 2.1
10 *
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2, or (at your option)
14 any later version.
15 *
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
18 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 See the GNU General Public License for more details.
20 *
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26#include "platform.h"
27#include "di_defs.h"
28#include "pc.h"
29#include "pr_pc.h"
30#include "di.h"
31#include "mi_pc.h"
32#include "pc_maint.h"
33#include "divasync.h"
34#include "pc_init.h"
35#include "io.h"
36#include "helpers.h"
37#include "dsrv4bri.h"
38#include "dsp_defs.h"
39#include "sdp_hdr.h"
40
41/*****************************************************************************/
42#define MAX_XLOG_SIZE (64 * 1024)
43
44/* --------------------------------------------------------------------------
45 Recovery XLOG from QBRI Card
46 -------------------------------------------------------------------------- */
47static void qBri_cpu_trapped (PISDN_ADAPTER IoAdapter) {
48 byte __iomem *base ;
49 word *Xlog ;
50 dword regs[4], TrapID, offset, size ;
51 Xdesc xlogDesc ;
52 int factor = (IoAdapter->tasks == 1) ? 1 : 2;
53
54/*
55 * check for trapped MIPS 46xx CPU, dump exception frame
56 */
57
58 base = DIVA_OS_MEM_ATTACH_CONTROL(IoAdapter);
59 offset = IoAdapter->ControllerNumber * (IoAdapter->MemorySize >> factor) ;
60
61 TrapID = READ_DWORD(&base[0x80]) ;
62
63 if ( (TrapID == 0x99999999) || (TrapID == 0x99999901) )
64 {
65 dump_trap_frame (IoAdapter, &base[0x90]) ;
66 IoAdapter->trapped = 1 ;
67 }
68
69 regs[0] = READ_DWORD((base + offset) + 0x70);
70 regs[1] = READ_DWORD((base + offset) + 0x74);
71 regs[2] = READ_DWORD((base + offset) + 0x78);
72 regs[3] = READ_DWORD((base + offset) + 0x7c);
73 regs[0] &= IoAdapter->MemorySize - 1 ;
74
75 if ( (regs[0] >= offset)
76 && (regs[0] < offset + (IoAdapter->MemorySize >> factor) - 1) )
77 {
78 if ( !(Xlog = (word *)diva_os_malloc (0, MAX_XLOG_SIZE)) ) {
79 DIVA_OS_MEM_DETACH_CONTROL(IoAdapter, base);
80 return ;
81 }
82
83 size = offset + (IoAdapter->MemorySize >> factor) - regs[0] ;
84 if ( size > MAX_XLOG_SIZE )
85 size = MAX_XLOG_SIZE ;
86 memcpy_fromio (Xlog, &base[regs[0]], size) ;
87 xlogDesc.buf = Xlog ;
88 xlogDesc.cnt = READ_WORD(&base[regs[1] & (IoAdapter->MemorySize - 1)]) ;
89 xlogDesc.out = READ_WORD(&base[regs[2] & (IoAdapter->MemorySize - 1)]) ;
90 dump_xlog_buffer (IoAdapter, &xlogDesc) ;
91 diva_os_free (0, Xlog) ;
92 IoAdapter->trapped = 2 ;
93 }
94 DIVA_OS_MEM_DETACH_CONTROL(IoAdapter, base);
95}
96
97/* --------------------------------------------------------------------------
98 Reset QBRI Hardware
99 -------------------------------------------------------------------------- */
100static void reset_qBri_hardware (PISDN_ADAPTER IoAdapter) {
101 word volatile __iomem *qBriReset ;
102 byte volatile __iomem *qBriCntrl ;
103 byte volatile __iomem *p ;
104
105 qBriReset = (word volatile __iomem *)DIVA_OS_MEM_ATTACH_PROM(IoAdapter);
106 WRITE_WORD(qBriReset, READ_WORD(qBriReset) | PLX9054_SOFT_RESET) ;
107 diva_os_wait (1) ;
108 WRITE_WORD(qBriReset, READ_WORD(qBriReset) & ~PLX9054_SOFT_RESET) ;
109 diva_os_wait (1);
110 WRITE_WORD(qBriReset, READ_WORD(qBriReset) | PLX9054_RELOAD_EEPROM) ;
111 diva_os_wait (1) ;
112 WRITE_WORD(qBriReset, READ_WORD(qBriReset) & ~PLX9054_RELOAD_EEPROM) ;
113 diva_os_wait (1);
114 DIVA_OS_MEM_DETACH_PROM(IoAdapter, qBriReset);
115
116 qBriCntrl = DIVA_OS_MEM_ATTACH_CTLREG(IoAdapter);
117 p = &qBriCntrl[DIVA_4BRI_REVISION(IoAdapter) ? (MQ2_BREG_RISC) : (MQ_BREG_RISC)];
118 WRITE_DWORD(p, 0) ;
119 DIVA_OS_MEM_DETACH_CTLREG(IoAdapter, qBriCntrl);
120
121 DBG_TRC(("resetted board @ reset addr 0x%08lx", qBriReset))
122 DBG_TRC(("resetted board @ cntrl addr 0x%08lx", p))
123}
124
125/* --------------------------------------------------------------------------
126 Start Card CPU
127 -------------------------------------------------------------------------- */
128void start_qBri_hardware (PISDN_ADAPTER IoAdapter) {
129 byte volatile __iomem *qBriReset ;
130 byte volatile __iomem *p ;
131
132 p = DIVA_OS_MEM_ATTACH_CTLREG(IoAdapter);
133 qBriReset = &p[(DIVA_4BRI_REVISION(IoAdapter)) ? (MQ2_BREG_RISC) : (MQ_BREG_RISC)];
134 WRITE_DWORD(qBriReset, MQ_RISC_COLD_RESET_MASK) ;
135 diva_os_wait (2) ;
136 WRITE_DWORD(qBriReset, MQ_RISC_WARM_RESET_MASK | MQ_RISC_COLD_RESET_MASK) ;
137 diva_os_wait (10) ;
138 DIVA_OS_MEM_DETACH_CTLREG(IoAdapter, p);
139
140 DBG_TRC(("started processor @ addr 0x%08lx", qBriReset))
141}
142
143/* --------------------------------------------------------------------------
144 Stop Card CPU
145 -------------------------------------------------------------------------- */
146static void stop_qBri_hardware (PISDN_ADAPTER IoAdapter) {
147 byte volatile __iomem *p ;
148 dword volatile __iomem *qBriReset ;
149 dword volatile __iomem *qBriIrq ;
150 dword volatile __iomem *qBriIsacDspReset ;
151 int rev2 = DIVA_4BRI_REVISION(IoAdapter);
152 int reset_offset = rev2 ? (MQ2_BREG_RISC) : (MQ_BREG_RISC);
153 int irq_offset = rev2 ? (MQ2_BREG_IRQ_TEST) : (MQ_BREG_IRQ_TEST);
154 int hw_offset = rev2 ? (MQ2_ISAC_DSP_RESET) : (MQ_ISAC_DSP_RESET);
155
156 if ( IoAdapter->ControllerNumber > 0 )
157 return ;
158 p = DIVA_OS_MEM_ATTACH_CTLREG(IoAdapter);
159 qBriReset = (dword volatile __iomem *)&p[reset_offset];
160 qBriIsacDspReset = (dword volatile __iomem *)&p[hw_offset];
161/*
162 * clear interrupt line (reset Local Interrupt Test Register)
163 */
164 WRITE_DWORD(qBriReset, 0) ;
165 WRITE_DWORD(qBriIsacDspReset, 0) ;
166 DIVA_OS_MEM_DETACH_CTLREG(IoAdapter, p);
167
168 p = DIVA_OS_MEM_ATTACH_RESET(IoAdapter);
169 WRITE_BYTE(&p[PLX9054_INTCSR], 0x00); /* disable PCI interrupts */
170 DIVA_OS_MEM_DETACH_RESET(IoAdapter, p);
171
172 p = DIVA_OS_MEM_ATTACH_CTLREG(IoAdapter);
173 qBriIrq = (dword volatile __iomem *)&p[irq_offset];
174 WRITE_DWORD(qBriIrq, MQ_IRQ_REQ_OFF) ;
175 DIVA_OS_MEM_DETACH_CTLREG(IoAdapter, p);
176
177 DBG_TRC(("stopped processor @ addr 0x%08lx", qBriReset))
178
179}
180
181/* --------------------------------------------------------------------------
182 FPGA download
183 -------------------------------------------------------------------------- */
184#define FPGA_NAME_OFFSET 0x10
185
186static byte * qBri_check_FPGAsrc (PISDN_ADAPTER IoAdapter, char *FileName,
187 dword *Length, dword *code) {
188 byte *File ;
189 char *fpgaFile, *fpgaType, *fpgaDate, *fpgaTime ;
190 dword fpgaFlen, fpgaTlen, fpgaDlen, cnt, year, i ;
191
192 if (!(File = (byte *)xdiLoadFile (FileName, Length, 0))) {
193 return (NULL) ;
194 }
195/*
196 * scan file until FF and put id string into buffer
197 */
198 for ( i = 0 ; File[i] != 0xff ; )
199 {
200 if ( ++i >= *Length )
201 {
202 DBG_FTL(("FPGA download: start of data header not found"))
203 xdiFreeFile (File) ;
204 return (NULL) ;
205 }
206 }
207 *code = i++ ;
208
209 if ( (File[i] & 0xF0) != 0x20 )
210 {
211 DBG_FTL(("FPGA download: data header corrupted"))
212 xdiFreeFile (File) ;
213 return (NULL) ;
214 }
215 fpgaFlen = (dword) File[FPGA_NAME_OFFSET - 1] ;
216 if ( fpgaFlen == 0 )
217 fpgaFlen = 12 ;
218 fpgaFile = (char *)&File[FPGA_NAME_OFFSET] ;
219 fpgaTlen = (dword) fpgaFile[fpgaFlen + 2] ;
220 if ( fpgaTlen == 0 )
221 fpgaTlen = 10 ;
222 fpgaType = (char *)&fpgaFile[fpgaFlen + 3] ;
223 fpgaDlen = (dword) fpgaType[fpgaTlen + 2] ;
224 if ( fpgaDlen == 0 )
225 fpgaDlen = 11 ;
226 fpgaDate = (char *)&fpgaType[fpgaTlen + 3] ;
227 fpgaTime = (char *)&fpgaDate[fpgaDlen + 3] ;
228 cnt = (dword)(((File[ i ] & 0x0F) << 20) + (File[i + 1] << 12)
229 + (File[i + 2] << 4) + (File[i + 3] >> 4)) ;
230
231 if ( (dword)(i + (cnt / 8)) > *Length )
232 {
233 DBG_FTL(("FPGA download: '%s' file too small (%ld < %ld)",
234 FileName, *Length, code + ((cnt + 7) / 8) ))
235 xdiFreeFile (File) ;
236 return (NULL) ;
237 }
238 i = 0 ;
239 do
240 {
241 while ( (fpgaDate[i] != '\0')
242 && ((fpgaDate[i] < '0') || (fpgaDate[i] > '9')) )
243 {
244 i++;
245 }
246 year = 0 ;
247 while ( (fpgaDate[i] >= '0') && (fpgaDate[i] <= '9') )
248 year = year * 10 + (fpgaDate[i++] - '0') ;
249 } while ( (year < 2000) && (fpgaDate[i] != '\0') );
250
251 switch (IoAdapter->cardType) {
252 case CARDTYPE_DIVASRV_B_2F_PCI:
253 break;
254
255 default:
256 if ( year >= 2001 ) {
257 IoAdapter->fpga_features |= PCINIT_FPGA_PLX_ACCESS_SUPPORTED ;
258 }
259 }
260
261 DBG_LOG(("FPGA[%s] file %s (%s %s) len %d",
262 fpgaType, fpgaFile, fpgaDate, fpgaTime, cnt))
263 return (File) ;
264}
265
266/******************************************************************************/
267
268#define FPGA_PROG 0x0001 /* PROG enable low */
269#define FPGA_BUSY 0x0002 /* BUSY high, DONE low */
270#define FPGA_CS 0x000C /* Enable I/O pins */
271#define FPGA_CCLK 0x0100
272#define FPGA_DOUT 0x0400
273#define FPGA_DIN FPGA_DOUT /* bidirectional I/O */
274
275int qBri_FPGA_download (PISDN_ADAPTER IoAdapter) {
276 int bit ;
277 byte *File ;
278 dword code, FileLength ;
279 word volatile __iomem *addr = (word volatile __iomem *)DIVA_OS_MEM_ATTACH_PROM(IoAdapter);
280 word val, baseval = FPGA_CS | FPGA_PROG ;
281
282
283
284 if (DIVA_4BRI_REVISION(IoAdapter))
285 {
286 char* name;
287
288 switch (IoAdapter->cardType) {
289 case CARDTYPE_DIVASRV_B_2F_PCI:
290 name = "dsbri2f.bit";
291 break;
292
293 case CARDTYPE_DIVASRV_B_2M_V2_PCI:
294 case CARDTYPE_DIVASRV_VOICE_B_2M_V2_PCI:
295 name = "dsbri2m.bit";
296 break;
297
298 default:
299 name = "ds4bri2.bit";
300 }
301
302 File = qBri_check_FPGAsrc (IoAdapter, name,
303 &FileLength, &code);
304 }
305 else
306 {
307 File = qBri_check_FPGAsrc (IoAdapter, "ds4bri.bit",
308 &FileLength, &code) ;
309 }
310 if ( !File ) {
311 DIVA_OS_MEM_DETACH_PROM(IoAdapter, addr);
312 return (0) ;
313 }
314/*
315 * prepare download, pulse PROGRAM pin down.
316 */
317 WRITE_WORD(addr, baseval & ~FPGA_PROG) ; /* PROGRAM low pulse */
318 WRITE_WORD(addr, baseval) ; /* release */
319 diva_os_wait (50) ; /* wait until FPGA finished internal memory clear */
320/*
321 * check done pin, must be low
322 */
323 if ( READ_WORD(addr) & FPGA_BUSY )
324 {
325 DBG_FTL(("FPGA download: acknowledge for FPGA memory clear missing"))
326 xdiFreeFile (File) ;
327 DIVA_OS_MEM_DETACH_PROM(IoAdapter, addr);
328 return (0) ;
329 }
330/*
331 * put data onto the FPGA
332 */
333 while ( code < FileLength )
334 {
335 val = ((word)File[code++]) << 3 ;
336
337 for ( bit = 8 ; bit-- > 0 ; val <<= 1 ) /* put byte onto FPGA */
338 {
339 baseval &= ~FPGA_DOUT ; /* clr data bit */
340 baseval |= (val & FPGA_DOUT) ; /* copy data bit */
341 WRITE_WORD(addr, baseval) ;
342 WRITE_WORD(addr, baseval | FPGA_CCLK) ; /* set CCLK hi */
343 WRITE_WORD(addr, baseval | FPGA_CCLK) ; /* set CCLK hi */
344 WRITE_WORD(addr, baseval) ; /* set CCLK lo */
345 }
346 }
347 xdiFreeFile (File) ;
348 diva_os_wait (100) ;
349 val = READ_WORD(addr) ;
350
351 DIVA_OS_MEM_DETACH_PROM(IoAdapter, addr);
352
353 if ( !(val & FPGA_BUSY) )
354 {
355 DBG_FTL(("FPGA download: chip remains in busy state (0x%04x)", val))
356 return (0) ;
357 }
358
359 return (1) ;
360}
361
362static int load_qBri_hardware (PISDN_ADAPTER IoAdapter) {
363 return (0);
364}
365
366/* --------------------------------------------------------------------------
367 Card ISR
368 -------------------------------------------------------------------------- */
369static int qBri_ISR (struct _ISDN_ADAPTER* IoAdapter) {
370 dword volatile __iomem *qBriIrq ;
371
372 PADAPTER_LIST_ENTRY QuadroList = IoAdapter->QuadroList ;
373
374 word i ;
375 int serviced = 0 ;
376 byte __iomem *p;
377
378 p = DIVA_OS_MEM_ATTACH_RESET(IoAdapter);
379
380 if ( !(READ_BYTE(&p[PLX9054_INTCSR]) & 0x80) ) {
381 DIVA_OS_MEM_DETACH_RESET(IoAdapter, p);
382 return (0) ;
383 }
384 DIVA_OS_MEM_DETACH_RESET(IoAdapter, p);
385
386/*
387 * clear interrupt line (reset Local Interrupt Test Register)
388 */
389 p = DIVA_OS_MEM_ATTACH_CTLREG(IoAdapter);
390 qBriIrq = (dword volatile __iomem *)(&p[DIVA_4BRI_REVISION(IoAdapter) ? (MQ2_BREG_IRQ_TEST) : (MQ_BREG_IRQ_TEST)]);
391 WRITE_DWORD(qBriIrq, MQ_IRQ_REQ_OFF) ;
392 DIVA_OS_MEM_DETACH_CTLREG(IoAdapter, p);
393
394 for ( i = 0 ; i < IoAdapter->tasks; ++i )
395 {
396 IoAdapter = QuadroList->QuadroAdapter[i] ;
397
398 if ( IoAdapter && IoAdapter->Initialized
399 && IoAdapter->tst_irq (&IoAdapter->a) )
400 {
401 IoAdapter->IrqCount++ ;
402 serviced = 1 ;
403 diva_os_schedule_soft_isr (&IoAdapter->isr_soft_isr);
404 }
405 }
406
407 return (serviced) ;
408}
409
410/* --------------------------------------------------------------------------
411 Does disable the interrupt on the card
412 -------------------------------------------------------------------------- */
413static void disable_qBri_interrupt (PISDN_ADAPTER IoAdapter) {
414 dword volatile __iomem *qBriIrq ;
415 byte __iomem *p;
416
417 if ( IoAdapter->ControllerNumber > 0 )
418 return ;
419/*
420 * clear interrupt line (reset Local Interrupt Test Register)
421 */
422 p = DIVA_OS_MEM_ATTACH_RESET(IoAdapter);
423 WRITE_BYTE(&p[PLX9054_INTCSR], 0x00); /* disable PCI interrupts */
424 DIVA_OS_MEM_DETACH_RESET(IoAdapter, p);
425
426 p = DIVA_OS_MEM_ATTACH_CTLREG(IoAdapter);
427 qBriIrq = (dword volatile __iomem *)(&p[DIVA_4BRI_REVISION(IoAdapter) ? (MQ2_BREG_IRQ_TEST) : (MQ_BREG_IRQ_TEST)]);
428 WRITE_DWORD(qBriIrq, MQ_IRQ_REQ_OFF) ;
429 DIVA_OS_MEM_DETACH_CTLREG(IoAdapter, p);
430}
431
432/* --------------------------------------------------------------------------
433 Install Adapter Entry Points
434 -------------------------------------------------------------------------- */
435static void set_common_qBri_functions (PISDN_ADAPTER IoAdapter) {
436 ADAPTER *a;
437
438 a = &IoAdapter->a ;
439
440 a->ram_in = mem_in ;
441 a->ram_inw = mem_inw ;
442 a->ram_in_buffer = mem_in_buffer ;
443 a->ram_look_ahead = mem_look_ahead ;
444 a->ram_out = mem_out ;
445 a->ram_outw = mem_outw ;
446 a->ram_out_buffer = mem_out_buffer ;
447 a->ram_inc = mem_inc ;
448
449 IoAdapter->out = pr_out ;
450 IoAdapter->dpc = pr_dpc ;
451 IoAdapter->tst_irq = scom_test_int ;
452 IoAdapter->clr_irq = scom_clear_int ;
453 IoAdapter->pcm = (struct pc_maint *)MIPS_MAINT_OFFS ;
454
455 IoAdapter->load = load_qBri_hardware ;
456
457 IoAdapter->disIrq = disable_qBri_interrupt ;
458 IoAdapter->rstFnc = reset_qBri_hardware ;
459 IoAdapter->stop = stop_qBri_hardware ;
460 IoAdapter->trapFnc = qBri_cpu_trapped ;
461
462 IoAdapter->diva_isr_handler = qBri_ISR;
463
464 IoAdapter->a.io = (void*)IoAdapter ;
465}
466
467static void set_qBri_functions (PISDN_ADAPTER IoAdapter) {
468 if (!IoAdapter->tasks) {
469 IoAdapter->tasks = MQ_INSTANCE_COUNT;
470 }
471 IoAdapter->MemorySize = MQ_MEMORY_SIZE ;
472 set_common_qBri_functions (IoAdapter) ;
473 diva_os_set_qBri_functions (IoAdapter) ;
474}
475
476static void set_qBri2_functions (PISDN_ADAPTER IoAdapter) {
477 if (!IoAdapter->tasks) {
478 IoAdapter->tasks = MQ_INSTANCE_COUNT;
479 }
480 IoAdapter->MemorySize = (IoAdapter->tasks == 1) ? BRI2_MEMORY_SIZE : MQ2_MEMORY_SIZE;
481 set_common_qBri_functions (IoAdapter) ;
482 diva_os_set_qBri2_functions (IoAdapter) ;
483}
484
485/******************************************************************************/
486
487void prepare_qBri_functions (PISDN_ADAPTER IoAdapter) {
488
489 set_qBri_functions (IoAdapter->QuadroList->QuadroAdapter[0]) ;
490 set_qBri_functions (IoAdapter->QuadroList->QuadroAdapter[1]) ;
491 set_qBri_functions (IoAdapter->QuadroList->QuadroAdapter[2]) ;
492 set_qBri_functions (IoAdapter->QuadroList->QuadroAdapter[3]) ;
493
494}
495
496void prepare_qBri2_functions (PISDN_ADAPTER IoAdapter) {
497 if (!IoAdapter->tasks) {
498 IoAdapter->tasks = MQ_INSTANCE_COUNT;
499 }
500
501 set_qBri2_functions (IoAdapter->QuadroList->QuadroAdapter[0]) ;
502 if (IoAdapter->tasks > 1) {
503 set_qBri2_functions (IoAdapter->QuadroList->QuadroAdapter[1]) ;
504 set_qBri2_functions (IoAdapter->QuadroList->QuadroAdapter[2]) ;
505 set_qBri2_functions (IoAdapter->QuadroList->QuadroAdapter[3]) ;
506 }
507
508}
509
510/* -------------------------------------------------------------------------- */
diff --git a/drivers/isdn/hardware/eicon/s_bri.c b/drivers/isdn/hardware/eicon/s_bri.c
new file mode 100644
index 000000000000..5c87552e8c08
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/s_bri.c
@@ -0,0 +1,191 @@
1
2/*
3 *
4 Copyright (c) Eicon Networks, 2002.
5 *
6 This source file is supplied for the use with
7 Eicon Networks range of DIVA Server Adapters.
8 *
9 Eicon File Revision : 2.1
10 *
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2, or (at your option)
14 any later version.
15 *
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
18 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 See the GNU General Public License for more details.
20 *
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26#include "platform.h"
27#include "di_defs.h"
28#include "pc.h"
29#include "pr_pc.h"
30#include "di.h"
31#include "mi_pc.h"
32#include "pc_maint.h"
33#include "divasync.h"
34#include "io.h"
35#include "helpers.h"
36#include "dsrv_bri.h"
37#include "dsp_defs.h"
38/*****************************************************************************/
39#define MAX_XLOG_SIZE (64 * 1024)
40/* --------------------------------------------------------------------------
41 Investigate card state, recovery trace buffer
42 -------------------------------------------------------------------------- */
43static void bri_cpu_trapped (PISDN_ADAPTER IoAdapter) {
44 byte __iomem *addrHi, *addrLo, *ioaddr ;
45 word *Xlog ;
46 dword regs[4], i, size ;
47 Xdesc xlogDesc ;
48 byte __iomem *Port;
49/*
50 * first read pointers and trap frame
51 */
52 if ( !(Xlog = (word *)diva_os_malloc (0, MAX_XLOG_SIZE)) )
53 return ;
54 Port = DIVA_OS_MEM_ATTACH_PORT(IoAdapter);
55 addrHi = Port + ((IoAdapter->Properties.Bus == BUS_PCI) ? M_PCI_ADDRH : ADDRH) ;
56 addrLo = Port + ADDR ;
57 ioaddr = Port + DATA ;
58 outpp (addrHi, 0) ;
59 outppw (addrLo, 0) ;
60 for ( i = 0 ; i < 0x100 ; Xlog[i++] = inppw(ioaddr) ) ;
61/*
62 * check for trapped MIPS 3xxx CPU, dump only exception frame
63 */
64 if ( GET_DWORD(&Xlog[0x80 / sizeof(Xlog[0])]) == 0x99999999 )
65 {
66 dump_trap_frame (IoAdapter, &((byte *)Xlog)[0x90]) ;
67 IoAdapter->trapped = 1 ;
68 }
69 regs[0] = GET_DWORD(&((byte *)Xlog)[0x70]);
70 regs[1] = GET_DWORD(&((byte *)Xlog)[0x74]);
71 regs[2] = GET_DWORD(&((byte *)Xlog)[0x78]);
72 regs[3] = GET_DWORD(&((byte *)Xlog)[0x7c]);
73 outpp (addrHi, (regs[1] >> 16) & 0x7F) ;
74 outppw (addrLo, regs[1] & 0xFFFF) ;
75 xlogDesc.cnt = inppw(ioaddr) ;
76 outpp (addrHi, (regs[2] >> 16) & 0x7F) ;
77 outppw (addrLo, regs[2] & 0xFFFF) ;
78 xlogDesc.out = inppw(ioaddr) ;
79 xlogDesc.buf = Xlog ;
80 regs[0] &= IoAdapter->MemorySize - 1 ;
81 if ( (regs[0] < IoAdapter->MemorySize - 1) )
82 {
83 size = IoAdapter->MemorySize - regs[0] ;
84 if ( size > MAX_XLOG_SIZE )
85 size = MAX_XLOG_SIZE ;
86 for ( i = 0 ; i < (size / sizeof(*Xlog)) ; regs[0] += 2 )
87 {
88 outpp (addrHi, (regs[0] >> 16) & 0x7F) ;
89 outppw (addrLo, regs[0] & 0xFFFF) ;
90 Xlog[i++] = inppw(ioaddr) ;
91 }
92 dump_xlog_buffer (IoAdapter, &xlogDesc) ;
93 diva_os_free (0, Xlog) ;
94 IoAdapter->trapped = 2 ;
95 }
96 outpp (addrHi, (byte)((BRI_UNCACHED_ADDR (IoAdapter->MemoryBase + IoAdapter->MemorySize -
97 BRI_SHARED_RAM_SIZE)) >> 16)) ;
98 outppw (addrLo, 0x00) ;
99 DIVA_OS_MEM_DETACH_PORT(IoAdapter, Port);
100}
101/* ---------------------------------------------------------------------
102 Reset hardware
103 --------------------------------------------------------------------- */
104static void reset_bri_hardware (PISDN_ADAPTER IoAdapter) {
105 byte __iomem *p = DIVA_OS_MEM_ATTACH_CTLREG(IoAdapter);
106 outpp (p, 0x00) ;
107 DIVA_OS_MEM_DETACH_CTLREG(IoAdapter, p);
108}
109/* ---------------------------------------------------------------------
110 Halt system
111 --------------------------------------------------------------------- */
112static void stop_bri_hardware (PISDN_ADAPTER IoAdapter) {
113 byte __iomem *p = DIVA_OS_MEM_ATTACH_RESET(IoAdapter);
114 if (p) {
115 outpp (p, 0x00) ; /* disable interrupts ! */
116 }
117 DIVA_OS_MEM_DETACH_RESET(IoAdapter, p);
118 p = DIVA_OS_MEM_ATTACH_CTLREG(IoAdapter);
119 outpp (p, 0x00) ; /* clear int, halt cpu */
120 DIVA_OS_MEM_DETACH_CTLREG(IoAdapter, p);
121}
122static int load_bri_hardware (PISDN_ADAPTER IoAdapter) {
123 return (0);
124}
125/******************************************************************************/
126static int bri_ISR (struct _ISDN_ADAPTER* IoAdapter) {
127 byte __iomem *p;
128
129 p = DIVA_OS_MEM_ATTACH_CTLREG(IoAdapter);
130 if ( !(inpp (p) & 0x01) ) {
131 DIVA_OS_MEM_DETACH_CTLREG(IoAdapter, p);
132 return (0) ;
133 }
134 /*
135 clear interrupt line
136 */
137 outpp (p, 0x08) ;
138 DIVA_OS_MEM_DETACH_CTLREG(IoAdapter, p);
139 IoAdapter->IrqCount++ ;
140 if ( IoAdapter->Initialized ) {
141 diva_os_schedule_soft_isr (&IoAdapter->isr_soft_isr);
142 }
143 return (1) ;
144}
145/* --------------------------------------------------------------------------
146 Disable IRQ in the card hardware
147 -------------------------------------------------------------------------- */
148static void disable_bri_interrupt (PISDN_ADAPTER IoAdapter) {
149 byte __iomem *p;
150 p = DIVA_OS_MEM_ATTACH_RESET(IoAdapter);
151 if ( p )
152 {
153 outpp (p, 0x00) ; /* disable interrupts ! */
154 }
155 DIVA_OS_MEM_DETACH_RESET(IoAdapter, p);
156 p = DIVA_OS_MEM_ATTACH_CTLREG(IoAdapter);
157 outpp (p, 0x00) ; /* clear int, halt cpu */
158 DIVA_OS_MEM_DETACH_CTLREG(IoAdapter, p);
159}
160/* -------------------------------------------------------------------------
161 Fill card entry points
162 ------------------------------------------------------------------------- */
163void prepare_maestra_functions (PISDN_ADAPTER IoAdapter) {
164 ADAPTER *a = &IoAdapter->a ;
165 a->ram_in = io_in ;
166 a->ram_inw = io_inw ;
167 a->ram_in_buffer = io_in_buffer ;
168 a->ram_look_ahead = io_look_ahead ;
169 a->ram_out = io_out ;
170 a->ram_outw = io_outw ;
171 a->ram_out_buffer = io_out_buffer ;
172 a->ram_inc = io_inc ;
173 IoAdapter->MemoryBase = BRI_MEMORY_BASE ;
174 IoAdapter->MemorySize = BRI_MEMORY_SIZE ;
175 IoAdapter->out = pr_out ;
176 IoAdapter->dpc = pr_dpc ;
177 IoAdapter->tst_irq = scom_test_int ;
178 IoAdapter->clr_irq = scom_clear_int ;
179 IoAdapter->pcm = (struct pc_maint *)MIPS_MAINT_OFFS ;
180 IoAdapter->load = load_bri_hardware ;
181 IoAdapter->disIrq = disable_bri_interrupt ;
182 IoAdapter->rstFnc = reset_bri_hardware ;
183 IoAdapter->stop = stop_bri_hardware ;
184 IoAdapter->trapFnc = bri_cpu_trapped ;
185 IoAdapter->diva_isr_handler = bri_ISR;
186 /*
187 Prepare OS dependent functions
188 */
189 diva_os_prepare_maestra_functions (IoAdapter);
190}
191/* -------------------------------------------------------------------------- */
diff --git a/drivers/isdn/hardware/eicon/s_pri.c b/drivers/isdn/hardware/eicon/s_pri.c
new file mode 100644
index 000000000000..18f287888570
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/s_pri.c
@@ -0,0 +1,205 @@
1
2/*
3 *
4 Copyright (c) Eicon Networks, 2002.
5 *
6 This source file is supplied for the use with
7 Eicon Networks range of DIVA Server Adapters.
8 *
9 Eicon File Revision : 2.1
10 *
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2, or (at your option)
14 any later version.
15 *
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
18 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 See the GNU General Public License for more details.
20 *
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26#include "platform.h"
27#include "di_defs.h"
28#include "pc.h"
29#include "pr_pc.h"
30#include "di.h"
31#include "mi_pc.h"
32#include "pc_maint.h"
33#include "divasync.h"
34#include "io.h"
35#include "helpers.h"
36#include "dsrv_pri.h"
37#include "dsp_defs.h"
38/*****************************************************************************/
39#define MAX_XLOG_SIZE (64 * 1024)
40/* -------------------------------------------------------------------------
41 Does return offset between ADAPTER->ram and real begin of memory
42 ------------------------------------------------------------------------- */
43static dword pri_ram_offset (ADAPTER* a) {
44 return ((dword)MP_SHARED_RAM_OFFSET);
45}
46/* -------------------------------------------------------------------------
47 Recovery XLOG buffer from the card
48 ------------------------------------------------------------------------- */
49static void pri_cpu_trapped (PISDN_ADAPTER IoAdapter) {
50 byte __iomem *base ;
51 word *Xlog ;
52 dword regs[4], TrapID, size ;
53 Xdesc xlogDesc ;
54/*
55 * check for trapped MIPS 46xx CPU, dump exception frame
56 */
57 base = DIVA_OS_MEM_ATTACH_ADDRESS(IoAdapter);
58 TrapID = READ_DWORD(&base[0x80]) ;
59 if ( (TrapID == 0x99999999) || (TrapID == 0x99999901) )
60 {
61 dump_trap_frame (IoAdapter, &base[0x90]) ;
62 IoAdapter->trapped = 1 ;
63 }
64 regs[0] = READ_DWORD(&base[MP_PROTOCOL_OFFSET + 0x70]);
65 regs[1] = READ_DWORD(&base[MP_PROTOCOL_OFFSET + 0x74]);
66 regs[2] = READ_DWORD(&base[MP_PROTOCOL_OFFSET + 0x78]);
67 regs[3] = READ_DWORD(&base[MP_PROTOCOL_OFFSET + 0x7c]);
68 regs[0] &= IoAdapter->MemorySize - 1 ;
69 if ( (regs[0] < IoAdapter->MemorySize - 1) )
70 {
71 if ( !(Xlog = (word *)diva_os_malloc (0, MAX_XLOG_SIZE)) ) {
72 DIVA_OS_MEM_DETACH_ADDRESS(IoAdapter, base);
73 return ;
74 }
75 size = IoAdapter->MemorySize - regs[0] ;
76 if ( size > MAX_XLOG_SIZE )
77 size = MAX_XLOG_SIZE ;
78 memcpy_fromio(Xlog, &base[regs[0]], size) ;
79 xlogDesc.buf = Xlog ;
80 xlogDesc.cnt = READ_WORD(&base[regs[1] & (IoAdapter->MemorySize - 1)]) ;
81 xlogDesc.out = READ_WORD(&base[regs[2] & (IoAdapter->MemorySize - 1)]) ;
82 dump_xlog_buffer (IoAdapter, &xlogDesc) ;
83 diva_os_free (0, Xlog) ;
84 IoAdapter->trapped = 2 ;
85 }
86 DIVA_OS_MEM_DETACH_ADDRESS(IoAdapter, base);
87}
88/* -------------------------------------------------------------------------
89 Hardware reset of PRI card
90 ------------------------------------------------------------------------- */
91static void reset_pri_hardware (PISDN_ADAPTER IoAdapter) {
92 byte __iomem *p = DIVA_OS_MEM_ATTACH_RESET(IoAdapter);
93 WRITE_BYTE(p, _MP_RISC_RESET | _MP_LED1 | _MP_LED2);
94 diva_os_wait (50) ;
95 WRITE_BYTE(p, 0x00);
96 diva_os_wait (50) ;
97 DIVA_OS_MEM_DETACH_RESET(IoAdapter, p);
98}
99/* -------------------------------------------------------------------------
100 Stop Card Hardware
101 ------------------------------------------------------------------------- */
102static void stop_pri_hardware (PISDN_ADAPTER IoAdapter) {
103 dword i;
104 byte __iomem *p;
105 dword volatile __iomem *cfgReg = (void __iomem *)DIVA_OS_MEM_ATTACH_CFG(IoAdapter);
106 WRITE_DWORD(&cfgReg[3], 0);
107 WRITE_DWORD(&cfgReg[1], 0);
108 DIVA_OS_MEM_DETACH_CFG(IoAdapter, cfgReg);
109 IoAdapter->a.ram_out (&IoAdapter->a, &RAM->SWReg, SWREG_HALT_CPU) ;
110 i = 0 ;
111 while ( (i < 100) && (IoAdapter->a.ram_in (&IoAdapter->a, &RAM->SWReg) != 0) )
112 {
113 diva_os_wait (1) ;
114 i++ ;
115 }
116 DBG_TRC(("%s: PRI stopped (%d)", IoAdapter->Name, i))
117 cfgReg = (void __iomem *)DIVA_OS_MEM_ATTACH_CFG(IoAdapter);
118 WRITE_DWORD(&cfgReg[0],((dword)(~0x03E00000)));
119 DIVA_OS_MEM_DETACH_CFG(IoAdapter, cfgReg);
120 diva_os_wait (1) ;
121 p = DIVA_OS_MEM_ATTACH_RESET(IoAdapter);
122 WRITE_BYTE(p, _MP_RISC_RESET | _MP_LED1 | _MP_LED2);
123 DIVA_OS_MEM_DETACH_RESET(IoAdapter, p);
124}
125static int load_pri_hardware (PISDN_ADAPTER IoAdapter) {
126 return (0);
127}
128/* --------------------------------------------------------------------------
129 PRI Adapter interrupt Service Routine
130 -------------------------------------------------------------------------- */
131static int pri_ISR (struct _ISDN_ADAPTER* IoAdapter) {
132 byte __iomem *cfg = DIVA_OS_MEM_ATTACH_CFG(IoAdapter);
133 if ( !(READ_DWORD(cfg) & 0x80000000) ) {
134 DIVA_OS_MEM_DETACH_CFG(IoAdapter, cfg);
135 return (0) ;
136 }
137 /*
138 clear interrupt line
139 */
140 WRITE_DWORD(cfg, (dword)~0x03E00000) ;
141 DIVA_OS_MEM_DETACH_CFG(IoAdapter, cfg);
142 IoAdapter->IrqCount++ ;
143 if ( IoAdapter->Initialized )
144 {
145 diva_os_schedule_soft_isr (&IoAdapter->isr_soft_isr);
146 }
147 return (1) ;
148}
149/* -------------------------------------------------------------------------
150 Disable interrupt in the card hardware
151 ------------------------------------------------------------------------- */
152static void disable_pri_interrupt (PISDN_ADAPTER IoAdapter) {
153 dword volatile __iomem *cfgReg = (dword volatile __iomem *)DIVA_OS_MEM_ATTACH_CFG(IoAdapter) ;
154 WRITE_DWORD(&cfgReg[3], 0);
155 WRITE_DWORD(&cfgReg[1], 0);
156 WRITE_DWORD(&cfgReg[0], (dword)(~0x03E00000)) ;
157 DIVA_OS_MEM_DETACH_CFG(IoAdapter, cfgReg);
158}
159/* -------------------------------------------------------------------------
160 Install entry points for PRI Adapter
161 ------------------------------------------------------------------------- */
162static void prepare_common_pri_functions (PISDN_ADAPTER IoAdapter) {
163 ADAPTER *a = &IoAdapter->a ;
164 a->ram_in = mem_in ;
165 a->ram_inw = mem_inw ;
166 a->ram_in_buffer = mem_in_buffer ;
167 a->ram_look_ahead = mem_look_ahead ;
168 a->ram_out = mem_out ;
169 a->ram_outw = mem_outw ;
170 a->ram_out_buffer = mem_out_buffer ;
171 a->ram_inc = mem_inc ;
172 a->ram_offset = pri_ram_offset ;
173 a->ram_out_dw = mem_out_dw;
174 a->ram_in_dw = mem_in_dw;
175 a->istream_wakeup = pr_stream;
176 IoAdapter->out = pr_out ;
177 IoAdapter->dpc = pr_dpc ;
178 IoAdapter->tst_irq = scom_test_int ;
179 IoAdapter->clr_irq = scom_clear_int ;
180 IoAdapter->pcm = (struct pc_maint *)(MIPS_MAINT_OFFS
181 - MP_SHARED_RAM_OFFSET) ;
182 IoAdapter->load = load_pri_hardware ;
183 IoAdapter->disIrq = disable_pri_interrupt ;
184 IoAdapter->rstFnc = reset_pri_hardware ;
185 IoAdapter->stop = stop_pri_hardware ;
186 IoAdapter->trapFnc = pri_cpu_trapped ;
187 IoAdapter->diva_isr_handler = pri_ISR;
188}
189/* -------------------------------------------------------------------------
190 Install entry points for PRI Adapter
191 ------------------------------------------------------------------------- */
192void prepare_pri_functions (PISDN_ADAPTER IoAdapter) {
193 IoAdapter->MemorySize = MP_MEMORY_SIZE ;
194 prepare_common_pri_functions (IoAdapter) ;
195 diva_os_prepare_pri_functions (IoAdapter);
196}
197/* -------------------------------------------------------------------------
198 Install entry points for PRI Rev.2 Adapter
199 ------------------------------------------------------------------------- */
200void prepare_pri2_functions (PISDN_ADAPTER IoAdapter) {
201 IoAdapter->MemorySize = MP2_MEMORY_SIZE ;
202 prepare_common_pri_functions (IoAdapter) ;
203 diva_os_prepare_pri2_functions (IoAdapter);
204}
205/* ------------------------------------------------------------------------- */
diff --git a/drivers/isdn/hardware/eicon/sdp_hdr.h b/drivers/isdn/hardware/eicon/sdp_hdr.h
new file mode 100644
index 000000000000..8f61c696b9aa
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/sdp_hdr.h
@@ -0,0 +1,117 @@
1
2/*
3 *
4 Copyright (c) Eicon Networks, 2002.
5 *
6 This source file is supplied for the use with
7 Eicon Networks range of DIVA Server Adapters.
8 *
9 Eicon File Revision : 2.1
10 *
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2, or (at your option)
14 any later version.
15 *
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
18 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 See the GNU General Public License for more details.
20 *
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26#ifndef __DIVA_SOFT_DSP_TASK_ENTRY_H__
27#define __DIVA_SOFT_DSP_TASK_ENTRY_H__
28/*
29 The soft DSP image is described by binary header contained on begin of this
30 image:
31OFFSET FROM IMAGE START | VARIABLE
32------------------------------------------------------------------------
33 DIVA_MIPS_TASK_IMAGE_LINK_OFFS | link to the next image
34 ----------------------------------------------------------------------
35 DIVA_MIPS_TASK_IMAGE_GP_OFFS | image gp register value, void*
36 ----------------------------------------------------------------------
37 DIVA_MIPS_TASK_IMAGE_ENTRY_OFFS | diva_mips_sdp_task_entry_t*
38 ----------------------------------------------------------------------
39 DIVA_MIPS_TASK_IMAGE_LOAD_ADDR_OFFS | image image start address (void*)
40 ----------------------------------------------------------------------
41 DIVA_MIPS_TASK_IMAGE_END_ADDR_OFFS | image image end address (void*)
42 ----------------------------------------------------------------------
43 DIVA_MIPS_TASK_IMAGE_ID_STRING_OFFS | image id string char[...];
44 ----------------------------------------------------------------------
45 */
46#define DIVA_MIPS_TASK_IMAGE_LINK_OFFS 0x6C
47#define DIVA_MIPS_TASK_IMAGE_GP_OFFS 0x70
48#define DIVA_MIPS_TASK_IMAGE_ENTRY_OFFS 0x74
49#define DIVA_MIPS_TASK_IMAGE_LOAD_ADDR_OFFS 0x78
50#define DIVA_MIPS_TASK_IMAGE_END_ADDR_OFFS 0x7c
51#define DIVA_MIPS_TASK_IMAGE_ID_STRING_OFFS 0x80
52/*
53 This function is called in order to set GP register of this task
54 This function should be always called before any function of the
55 task is called
56 */
57typedef void (*diva_task_set_prog_gp_proc_t)(void* new_gp);
58/*
59 This function is called to clear .bss at task initialization step
60 */
61typedef void (*diva_task_sys_reset_proc_t)(void);
62/*
63 This function is called in order to provide GP of master call to
64 task, that will be used by calls from the task to the master
65 */
66typedef void (*diva_task_set_main_gp_proc_t)(void* main_gp);
67/*
68 This function is called to provide address of 'dprintf' function
69 to the task
70 */
71typedef word (*diva_prt_proc_t)(char *, ...);
72typedef void (*diva_task_set_prt_proc_t)(diva_prt_proc_t fn);
73/*
74 This function is called to set task PID
75 */
76typedef void (*diva_task_set_pid_proc_t)(dword id);
77/*
78 This function is called for run-time task init
79 */
80typedef int (*diva_task_run_time_init_proc_t)(void*, dword);
81/*
82 This function is called from system scheduler or from timer
83 */
84typedef void (*diva_task_callback_proc_t)(void);
85/*
86 This callback is used by task to get current time im mS
87 */
88typedef dword (*diva_task_get_tick_count_proc_t)(void);
89typedef void (*diva_task_set_get_time_proc_t)(\
90 diva_task_get_tick_count_proc_t fn);
91typedef struct _diva_mips_sdp_task_entry {
92 diva_task_set_prog_gp_proc_t set_gp_proc;
93 diva_task_sys_reset_proc_t sys_reset_proc;
94 diva_task_set_main_gp_proc_t set_main_gp_proc;
95 diva_task_set_prt_proc_t set_dprintf_proc;
96 diva_task_set_pid_proc_t set_pid_proc;
97 diva_task_run_time_init_proc_t run_time_init_proc;
98 diva_task_callback_proc_t task_callback_proc;
99 diva_task_callback_proc_t timer_callback_proc;
100 diva_task_set_get_time_proc_t set_get_time_proc;
101 void* last_entry_proc;
102} diva_mips_sdp_task_entry_t;
103/*
104 'last_entry_proc' should be set to zero and is used for future extensuios
105 */
106typedef struct _diva_mips_sw_task {
107 diva_mips_sdp_task_entry_t sdp_entry;
108 void* sdp_gp_reg;
109 void* own_gp_reg;
110} diva_mips_sw_task_t;
111#if !defined(DIVA_BRI2F_SDP_1_NAME)
112#define DIVA_BRI2F_SDP_1_NAME "sdp0.2q0"
113#endif
114#if !defined(DIVA_BRI2F_SDP_2_NAME)
115#define DIVA_BRI2F_SDP_2_NAME "sdp1.2q0"
116#endif
117#endif
diff --git a/drivers/isdn/hardware/eicon/um_idi.c b/drivers/isdn/hardware/eicon/um_idi.c
new file mode 100644
index 000000000000..6563db998d06
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/um_idi.c
@@ -0,0 +1,885 @@
1/* $Id: um_idi.c,v 1.14 2004/03/21 17:54:37 armin Exp $ */
2
3#include "platform.h"
4#include "di_defs.h"
5#include "pc.h"
6#include "dqueue.h"
7#include "adapter.h"
8#include "entity.h"
9#include "um_xdi.h"
10#include "um_idi.h"
11#include "debuglib.h"
12#include "divasync.h"
13
14#define DIVAS_MAX_XDI_ADAPTERS 64
15
16/* --------------------------------------------------------------------------
17 IMPORTS
18 -------------------------------------------------------------------------- */
19extern void diva_os_wakeup_read(void *os_context);
20extern void diva_os_wakeup_close(void *os_context);
21/* --------------------------------------------------------------------------
22 LOCALS
23 -------------------------------------------------------------------------- */
24static LIST_HEAD(adapter_q);
25static diva_os_spin_lock_t adapter_lock;
26
27static diva_um_idi_adapter_t *diva_um_idi_find_adapter(dword nr);
28static void cleanup_adapter(diva_um_idi_adapter_t * a);
29static void cleanup_entity(divas_um_idi_entity_t * e);
30static int diva_user_mode_idi_adapter_features(diva_um_idi_adapter_t * a,
31 diva_um_idi_adapter_features_t
32 * features);
33static int process_idi_request(divas_um_idi_entity_t * e,
34 const diva_um_idi_req_hdr_t * req);
35static int process_idi_rc(divas_um_idi_entity_t * e, byte rc);
36static int process_idi_ind(divas_um_idi_entity_t * e, byte ind);
37static int write_return_code(divas_um_idi_entity_t * e, byte rc);
38
39/* --------------------------------------------------------------------------
40 MAIN
41 -------------------------------------------------------------------------- */
42int diva_user_mode_idi_init(void)
43{
44 diva_os_initialize_spin_lock(&adapter_lock, "adapter");
45 return (0);
46}
47
48/* --------------------------------------------------------------------------
49 Copy adapter features to user supplied buffer
50 -------------------------------------------------------------------------- */
51static int
52diva_user_mode_idi_adapter_features(diva_um_idi_adapter_t * a,
53 diva_um_idi_adapter_features_t *
54 features)
55{
56 IDI_SYNC_REQ sync_req;
57
58 if ((a) && (a->d.request)) {
59 features->type = a->d.type;
60 features->features = a->d.features;
61 features->channels = a->d.channels;
62 memset(features->name, 0, sizeof(features->name));
63
64 sync_req.GetName.Req = 0;
65 sync_req.GetName.Rc = IDI_SYNC_REQ_GET_NAME;
66 (*(a->d.request)) ((ENTITY *) & sync_req);
67 strlcpy(features->name, sync_req.GetName.name,
68 sizeof(features->name));
69
70 sync_req.GetSerial.Req = 0;
71 sync_req.GetSerial.Rc = IDI_SYNC_REQ_GET_SERIAL;
72 sync_req.GetSerial.serial = 0;
73 (*(a->d.request)) ((ENTITY *) & sync_req);
74 features->serial_number = sync_req.GetSerial.serial;
75 }
76
77 return ((a) ? 0 : -1);
78}
79
80/* --------------------------------------------------------------------------
81 REMOVE ADAPTER
82 -------------------------------------------------------------------------- */
83void diva_user_mode_idi_remove_adapter(int adapter_nr)
84{
85 struct list_head *tmp;
86 diva_um_idi_adapter_t *a;
87
88 list_for_each(tmp, &adapter_q) {
89 a = list_entry(tmp, diva_um_idi_adapter_t, link);
90 if (a->adapter_nr == adapter_nr) {
91 list_del(tmp);
92 cleanup_adapter(a);
93 DBG_LOG(("DIDD: del adapter(%d)", a->adapter_nr));
94 diva_os_free(0, a);
95 break;
96 }
97 }
98}
99
100/* --------------------------------------------------------------------------
101 CALLED ON DRIVER EXIT (UNLOAD)
102 -------------------------------------------------------------------------- */
103void diva_user_mode_idi_finit(void)
104{
105 struct list_head *tmp, *safe;
106 diva_um_idi_adapter_t *a;
107
108 list_for_each_safe(tmp, safe, &adapter_q) {
109 a = list_entry(tmp, diva_um_idi_adapter_t, link);
110 list_del(tmp);
111 cleanup_adapter(a);
112 DBG_LOG(("DIDD: del adapter(%d)", a->adapter_nr));
113 diva_os_free(0, a);
114 }
115 diva_os_destroy_spin_lock(&adapter_lock, "adapter");
116}
117
118/* -------------------------------------------------------------------------
119 CREATE AND INIT IDI ADAPTER
120 ------------------------------------------------------------------------- */
121int diva_user_mode_idi_create_adapter(const DESCRIPTOR * d, int adapter_nr)
122{
123 diva_os_spin_lock_magic_t old_irql;
124 diva_um_idi_adapter_t *a =
125 (diva_um_idi_adapter_t *) diva_os_malloc(0,
126 sizeof
127 (diva_um_idi_adapter_t));
128
129 if (!a) {
130 return (-1);
131 }
132 memset(a, 0x00, sizeof(*a));
133 INIT_LIST_HEAD(&a->entity_q);
134
135 a->d = *d;
136 a->adapter_nr = adapter_nr;
137
138 DBG_LOG(("DIDD_ADD A(%d), type:%02x, features:%04x, channels:%d",
139 adapter_nr, a->d.type, a->d.features, a->d.channels));
140
141 diva_os_enter_spin_lock(&adapter_lock, &old_irql, "create_adapter");
142 list_add_tail(&a->link, &adapter_q);
143 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "create_adapter");
144 return (0);
145}
146
147/* ------------------------------------------------------------------------
148 Find adapter by Adapter number
149 ------------------------------------------------------------------------ */
150static diva_um_idi_adapter_t *diva_um_idi_find_adapter(dword nr)
151{
152 diva_um_idi_adapter_t *a = NULL;
153 struct list_head *tmp;
154
155 list_for_each(tmp, &adapter_q) {
156 a = list_entry(tmp, diva_um_idi_adapter_t, link);
157 DBG_TRC(("find_adapter: (%d)-(%d)", nr, a->adapter_nr));
158 if (a->adapter_nr == (int)nr)
159 break;
160 a = NULL;
161 }
162 return(a);
163}
164
165/* ------------------------------------------------------------------------
166 Cleanup this adapter and cleanup/delete all entities assigned
167 to this adapter
168 ------------------------------------------------------------------------ */
169static void cleanup_adapter(diva_um_idi_adapter_t * a)
170{
171 struct list_head *tmp, *safe;
172 divas_um_idi_entity_t *e;
173
174 list_for_each_safe(tmp, safe, &a->entity_q) {
175 e = list_entry(tmp, divas_um_idi_entity_t, link);
176 list_del(tmp);
177 cleanup_entity(e);
178 if (e->os_context) {
179 diva_os_wakeup_read(e->os_context);
180 diva_os_wakeup_close(e->os_context);
181 }
182 }
183 memset(&a->d, 0x00, sizeof(DESCRIPTOR));
184}
185
186/* ------------------------------------------------------------------------
187 Cleanup, but NOT delete this entity
188 ------------------------------------------------------------------------ */
189static void cleanup_entity(divas_um_idi_entity_t * e)
190{
191 e->os_ref = NULL;
192 e->status = 0;
193 e->adapter = NULL;
194 e->e.Id = 0;
195 e->rc_count = 0;
196
197 e->status |= DIVA_UM_IDI_REMOVED;
198 e->status |= DIVA_UM_IDI_REMOVE_PENDING;
199
200 diva_data_q_finit(&e->data);
201 diva_data_q_finit(&e->rc);
202}
203
204
205/* ------------------------------------------------------------------------
206 Create ENTITY, link it to the adapter and remove pointer to entity
207 ------------------------------------------------------------------------ */
208void *divas_um_idi_create_entity(dword adapter_nr, void *file)
209{
210 divas_um_idi_entity_t *e;
211 diva_um_idi_adapter_t *a;
212 diva_os_spin_lock_magic_t old_irql;
213
214 if ((e = (divas_um_idi_entity_t *) diva_os_malloc(0, sizeof(*e)))) {
215 memset(e, 0x00, sizeof(*e));
216 if (!
217 (e->os_context =
218 diva_os_malloc(0, diva_os_get_context_size()))) {
219 DBG_LOG(("E(%08x) no memory for os context", e));
220 diva_os_free(0, e);
221 return NULL;
222 }
223 memset(e->os_context, 0x00, diva_os_get_context_size());
224
225 if ((diva_data_q_init(&e->data, 2048 + 512, 16))) {
226 diva_os_free(0, e->os_context);
227 diva_os_free(0, e);
228 return NULL;
229 }
230 if ((diva_data_q_init(&e->rc, sizeof(diva_um_idi_ind_hdr_t), 2))) {
231 diva_data_q_finit(&e->data);
232 diva_os_free(0, e->os_context);
233 diva_os_free(0, e);
234 return NULL;
235 }
236
237 diva_os_enter_spin_lock(&adapter_lock, &old_irql, "create_entity");
238 /*
239 Look for Adapter requested
240 */
241 if (!(a = diva_um_idi_find_adapter(adapter_nr))) {
242 /*
243 No adapter was found, or this adapter was removed
244 */
245 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "create_entity");
246
247 DBG_LOG(("A: no adapter(%ld)", adapter_nr));
248
249 cleanup_entity(e);
250 diva_os_free(0, e->os_context);
251 diva_os_free(0, e);
252
253 return NULL;
254 }
255
256 e->os_ref = file; /* link to os handle */
257 e->adapter = a; /* link to adapter */
258
259 list_add_tail(&e->link, &a->entity_q); /* link from adapter */
260
261 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "create_entity");
262
263 DBG_LOG(("A(%ld), create E(%08x)", adapter_nr, e));
264 }
265
266 return (e);
267}
268
269/* ------------------------------------------------------------------------
270 Unlink entity and free memory
271 ------------------------------------------------------------------------ */
272int divas_um_idi_delete_entity(int adapter_nr, void *entity)
273{
274 divas_um_idi_entity_t *e;
275 diva_um_idi_adapter_t *a;
276 diva_os_spin_lock_magic_t old_irql;
277
278 if (!(e = (divas_um_idi_entity_t *) entity))
279 return (-1);
280
281 diva_os_enter_spin_lock(&adapter_lock, &old_irql, "delete_entity");
282 if ((a = e->adapter)) {
283 list_del(&e->link);
284 }
285 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "delete_entity");
286
287 diva_um_idi_stop_wdog(entity);
288 cleanup_entity(e);
289 diva_os_free(0, e->os_context);
290 memset(e, 0x00, sizeof(*e));
291 diva_os_free(0, e);
292
293 DBG_LOG(("A(%d) remove E:%08x", adapter_nr, e));
294
295 return (0);
296}
297
298/* --------------------------------------------------------------------------
299 Called by application to read data from IDI
300 -------------------------------------------------------------------------- */
301int diva_um_idi_read(void *entity,
302 void *os_handle,
303 void *dst,
304 int max_length, divas_um_idi_copy_to_user_fn_t cp_fn)
305{
306 divas_um_idi_entity_t *e;
307 diva_um_idi_adapter_t *a;
308 const void *data;
309 int length, ret = 0;
310 diva_um_idi_data_queue_t *q;
311 diva_os_spin_lock_magic_t old_irql;
312
313 diva_os_enter_spin_lock(&adapter_lock, &old_irql, "read");
314
315 e = (divas_um_idi_entity_t *) entity;
316 if (!e || (!(a = e->adapter)) ||
317 (e->status & DIVA_UM_IDI_REMOVE_PENDING) ||
318 (e->status & DIVA_UM_IDI_REMOVED) ||
319 (a->status & DIVA_UM_IDI_ADAPTER_REMOVED)) {
320 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "read");
321 DBG_ERR(("E(%08x) read failed - adapter removed", e))
322 return (-1);
323 }
324
325 DBG_TRC(("A(%d) E(%08x) read(%d)", a->adapter_nr, e, max_length));
326
327 /*
328 Try to read return code first
329 */
330 data = diva_data_q_get_segment4read(&e->rc);
331 q = &e->rc;
332
333 /*
334 No return codes available, read indications now
335 */
336 if (!data) {
337 if (!(e->status & DIVA_UM_IDI_RC_PENDING)) {
338 DBG_TRC(("A(%d) E(%08x) read data", a->adapter_nr, e));
339 data = diva_data_q_get_segment4read(&e->data);
340 q = &e->data;
341 }
342 } else {
343 e->status &= ~DIVA_UM_IDI_RC_PENDING;
344 DBG_TRC(("A(%d) E(%08x) read rc", a->adapter_nr, e));
345 }
346
347 if (data) {
348 if ((length = diva_data_q_get_segment_length(q)) >
349 max_length) {
350 /*
351 Not enough space to read message
352 */
353 DBG_ERR(("A: A(%d) E(%08x) read small buffer",
354 a->adapter_nr, e, ret));
355 diva_os_leave_spin_lock(&adapter_lock, &old_irql,
356 "read");
357 return (-2);
358 }
359 /*
360 Copy it to user, this function does access ONLY locked an verified
361 memory, also we can access it witch spin lock held
362 */
363
364 if ((ret = (*cp_fn) (os_handle, dst, data, length)) >= 0) {
365 /*
366 Acknowledge only if read was successfull
367 */
368 diva_data_q_ack_segment4read(q);
369 }
370 }
371
372
373 DBG_TRC(("A(%d) E(%08x) read=%d", a->adapter_nr, e, ret));
374
375 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "read");
376
377 return (ret);
378}
379
380
381int diva_um_idi_write(void *entity,
382 void *os_handle,
383 const void *src,
384 int length, divas_um_idi_copy_from_user_fn_t cp_fn)
385{
386 divas_um_idi_entity_t *e;
387 diva_um_idi_adapter_t *a;
388 diva_um_idi_req_hdr_t *req;
389 void *data;
390 int ret = 0;
391 diva_os_spin_lock_magic_t old_irql;
392
393 diva_os_enter_spin_lock(&adapter_lock, &old_irql, "write");
394
395 e = (divas_um_idi_entity_t *) entity;
396 if (!e || (!(a = e->adapter)) ||
397 (e->status & DIVA_UM_IDI_REMOVE_PENDING) ||
398 (e->status & DIVA_UM_IDI_REMOVED) ||
399 (a->status & DIVA_UM_IDI_ADAPTER_REMOVED)) {
400 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "write");
401 DBG_ERR(("E(%08x) write failed - adapter removed", e))
402 return (-1);
403 }
404
405 DBG_TRC(("A(%d) E(%08x) write(%d)", a->adapter_nr, e, length));
406
407 if ((length < sizeof(*req)) || (length > sizeof(e->buffer))) {
408 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "write");
409 return (-2);
410 }
411
412 if (e->status & DIVA_UM_IDI_RC_PENDING) {
413 DBG_ERR(("A: A(%d) E(%08x) rc pending", a->adapter_nr, e));
414 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "write");
415 return (-1); /* should wait for RC code first */
416 }
417
418 /*
419 Copy function does access only locked verified memory,
420 also it can be called with spin lock held
421 */
422 if ((ret = (*cp_fn) (os_handle, e->buffer, src, length)) < 0) {
423 DBG_TRC(("A: A(%d) E(%08x) write error=%d", a->adapter_nr,
424 e, ret));
425 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "write");
426 return (ret);
427 }
428
429 req = (diva_um_idi_req_hdr_t *) & e->buffer[0];
430
431 switch (req->type) {
432 case DIVA_UM_IDI_GET_FEATURES:{
433 DBG_LOG(("A(%d) get_features", a->adapter_nr));
434 if (!(data =
435 diva_data_q_get_segment4write(&e->data))) {
436 DBG_ERR(("A(%d) get_features, no free buffer",
437 a->adapter_nr));
438 diva_os_leave_spin_lock(&adapter_lock,
439 &old_irql,
440 "write");
441 return (0);
442 }
443 diva_user_mode_idi_adapter_features(a, &(((diva_um_idi_ind_hdr_t
444 *) data)->hdr.features));
445 ((diva_um_idi_ind_hdr_t *) data)->type =
446 DIVA_UM_IDI_IND_FEATURES;
447 ((diva_um_idi_ind_hdr_t *) data)->data_length = 0;
448 diva_data_q_ack_segment4write(&e->data,
449 sizeof(diva_um_idi_ind_hdr_t));
450
451 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "write");
452
453 diva_os_wakeup_read(e->os_context);
454 }
455 break;
456
457 case DIVA_UM_IDI_REQ:
458 case DIVA_UM_IDI_REQ_MAN:
459 case DIVA_UM_IDI_REQ_SIG:
460 case DIVA_UM_IDI_REQ_NET:
461 DBG_TRC(("A(%d) REQ(%02d)-(%02d)-(%08x)", a->adapter_nr,
462 req->Req, req->ReqCh,
463 req->type & DIVA_UM_IDI_REQ_TYPE_MASK));
464 switch (process_idi_request(e, req)) {
465 case -1:
466 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "write");
467 return (-1);
468 case -2:
469 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "write");
470 diva_os_wakeup_read(e->os_context);
471 break;
472 default:
473 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "write");
474 break;
475 }
476 break;
477
478 default:
479 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "write");
480 return (-1);
481 }
482
483 DBG_TRC(("A(%d) E(%08x) write=%d", a->adapter_nr, e, ret));
484
485 return (ret);
486}
487
488/* --------------------------------------------------------------------------
489 CALLBACK FROM XDI
490 -------------------------------------------------------------------------- */
491static void diva_um_idi_xdi_callback(ENTITY * entity)
492{
493 divas_um_idi_entity_t *e = DIVAS_CONTAINING_RECORD(entity,
494 divas_um_idi_entity_t,
495 e);
496 diva_os_spin_lock_magic_t old_irql;
497 int call_wakeup = 0;
498
499 diva_os_enter_spin_lock(&adapter_lock, &old_irql, "xdi_callback");
500
501 if (e->e.complete == 255) {
502 if (!(e->status & DIVA_UM_IDI_REMOVE_PENDING)) {
503 diva_um_idi_stop_wdog(e);
504 }
505 if ((call_wakeup = process_idi_rc(e, e->e.Rc))) {
506 if (e->rc_count) {
507 e->rc_count--;
508 }
509 }
510 e->e.Rc = 0;
511 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "xdi_callback");
512
513 if (call_wakeup) {
514 diva_os_wakeup_read(e->os_context);
515 diva_os_wakeup_close(e->os_context);
516 }
517 } else {
518 if (e->status & DIVA_UM_IDI_REMOVE_PENDING) {
519 e->e.RNum = 0;
520 e->e.RNR = 2;
521 } else {
522 call_wakeup = process_idi_ind(e, e->e.Ind);
523 }
524 e->e.Ind = 0;
525 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "xdi_callback");
526 if (call_wakeup) {
527 diva_os_wakeup_read(e->os_context);
528 }
529 }
530}
531
532static int process_idi_request(divas_um_idi_entity_t * e,
533 const diva_um_idi_req_hdr_t * req)
534{
535 int assign = 0;
536 byte Req = (byte) req->Req;
537 dword type = req->type & DIVA_UM_IDI_REQ_TYPE_MASK;
538
539 if (!e->e.Id || !e->e.callback) { /* not assigned */
540 if (Req != ASSIGN) {
541 DBG_ERR(("A: A(%d) E(%08x) not assigned",
542 e->adapter->adapter_nr, e));
543 return (-1); /* NOT ASSIGNED */
544 } else {
545 switch (type) {
546 case DIVA_UM_IDI_REQ_TYPE_MAN:
547 e->e.Id = MAN_ID;
548 DBG_TRC(("A(%d) E(%08x) assign MAN",
549 e->adapter->adapter_nr, e));
550 break;
551
552 case DIVA_UM_IDI_REQ_TYPE_SIG:
553 e->e.Id = DSIG_ID;
554 DBG_TRC(("A(%d) E(%08x) assign SIG",
555 e->adapter->adapter_nr, e));
556 break;
557
558 case DIVA_UM_IDI_REQ_TYPE_NET:
559 e->e.Id = NL_ID;
560 DBG_TRC(("A(%d) E(%08x) assign NET",
561 e->adapter->adapter_nr, e));
562 break;
563
564 default:
565 DBG_ERR(("A: A(%d) E(%08x) unknown type=%08x",
566 e->adapter->adapter_nr, e,
567 type));
568 return (-1);
569 }
570 }
571 e->e.XNum = 1;
572 e->e.RNum = 1;
573 e->e.callback = diva_um_idi_xdi_callback;
574 e->e.X = &e->XData;
575 e->e.R = &e->RData;
576 assign = 1;
577 }
578 e->status |= DIVA_UM_IDI_RC_PENDING;
579 e->e.Req = Req;
580 e->e.ReqCh = (byte) req->ReqCh;
581 e->e.X->PLength = (word) req->data_length;
582 e->e.X->P = (byte *) & req[1]; /* Our buffer is safe */
583
584 DBG_TRC(("A(%d) E(%08x) request(%02x-%02x-%02x (%d))",
585 e->adapter->adapter_nr, e, e->e.Id, e->e.Req,
586 e->e.ReqCh, e->e.X->PLength));
587
588 e->rc_count++;
589
590 if (e->adapter && e->adapter->d.request) {
591 diva_um_idi_start_wdog(e);
592 (*(e->adapter->d.request)) (&e->e);
593 }
594
595 if (assign) {
596 if (e->e.Rc == OUT_OF_RESOURCES) {
597 /*
598 XDI has no entities more, call was not forwarded to the card,
599 no callback will be scheduled
600 */
601 DBG_ERR(("A: A(%d) E(%08x) XDI out of entities",
602 e->adapter->adapter_nr, e));
603
604 e->e.Id = 0;
605 e->e.ReqCh = 0;
606 e->e.RcCh = 0;
607 e->e.Ind = 0;
608 e->e.IndCh = 0;
609 e->e.XNum = 0;
610 e->e.RNum = 0;
611 e->e.callback = NULL;
612 e->e.X = NULL;
613 e->e.R = NULL;
614 write_return_code(e, ASSIGN_RC | OUT_OF_RESOURCES);
615 return (-2);
616 } else {
617 e->status |= DIVA_UM_IDI_ASSIGN_PENDING;
618 }
619 }
620
621 return (0);
622}
623
624static int process_idi_rc(divas_um_idi_entity_t * e, byte rc)
625{
626 DBG_TRC(("A(%d) E(%08x) rc(%02x-%02x-%02x)",
627 e->adapter->adapter_nr, e, e->e.Id, rc, e->e.RcCh));
628
629 if (e->status & DIVA_UM_IDI_ASSIGN_PENDING) {
630 e->status &= ~DIVA_UM_IDI_ASSIGN_PENDING;
631 if (rc != ASSIGN_OK) {
632 DBG_ERR(("A: A(%d) E(%08x) ASSIGN failed",
633 e->adapter->adapter_nr, e));
634 e->e.callback = NULL;
635 e->e.Id = 0;
636 e->e.Req = 0;
637 e->e.ReqCh = 0;
638 e->e.Rc = 0;
639 e->e.RcCh = 0;
640 e->e.Ind = 0;
641 e->e.IndCh = 0;
642 e->e.X = NULL;
643 e->e.R = NULL;
644 e->e.XNum = 0;
645 e->e.RNum = 0;
646 }
647 }
648 if ((e->e.Req == REMOVE) && e->e.Id && (rc == 0xff)) {
649 DBG_ERR(("A: A(%d) E(%08x) discard OK in REMOVE",
650 e->adapter->adapter_nr, e));
651 return (0); /* let us do it in the driver */
652 }
653 if ((e->e.Req == REMOVE) && (!e->e.Id)) { /* REMOVE COMPLETE */
654 e->e.callback = NULL;
655 e->e.Id = 0;
656 e->e.Req = 0;
657 e->e.ReqCh = 0;
658 e->e.Rc = 0;
659 e->e.RcCh = 0;
660 e->e.Ind = 0;
661 e->e.IndCh = 0;
662 e->e.X = NULL;
663 e->e.R = NULL;
664 e->e.XNum = 0;
665 e->e.RNum = 0;
666 e->rc_count = 0;
667 }
668 if ((e->e.Req == REMOVE) && (rc != 0xff)) { /* REMOVE FAILED */
669 DBG_ERR(("A: A(%d) E(%08x) REMOVE FAILED",
670 e->adapter->adapter_nr, e));
671 }
672 write_return_code(e, rc);
673
674 return (1);
675}
676
677static int process_idi_ind(divas_um_idi_entity_t * e, byte ind)
678{
679 int do_wakeup = 0;
680
681 if (e->e.complete != 0x02) {
682 diva_um_idi_ind_hdr_t *pind =
683 (diva_um_idi_ind_hdr_t *)
684 diva_data_q_get_segment4write(&e->data);
685 if (pind) {
686 e->e.RNum = 1;
687 e->e.R->P = (byte *) & pind[1];
688 e->e.R->PLength =
689 (word) (diva_data_q_get_max_length(&e->data) -
690 sizeof(*pind));
691 DBG_TRC(("A(%d) E(%08x) ind_1(%02x-%02x-%02x)-[%d-%d]",
692 e->adapter->adapter_nr, e, e->e.Id, ind,
693 e->e.IndCh, e->e.RLength,
694 e->e.R->PLength));
695
696 } else {
697 DBG_TRC(("A(%d) E(%08x) ind(%02x-%02x-%02x)-RNR",
698 e->adapter->adapter_nr, e, e->e.Id, ind,
699 e->e.IndCh));
700 e->e.RNum = 0;
701 e->e.RNR = 1;
702 do_wakeup = 1;
703 }
704 } else {
705 diva_um_idi_ind_hdr_t *pind =
706 (diva_um_idi_ind_hdr_t *) (e->e.R->P);
707
708 DBG_TRC(("A(%d) E(%08x) ind(%02x-%02x-%02x)-[%d]",
709 e->adapter->adapter_nr, e, e->e.Id, ind,
710 e->e.IndCh, e->e.R->PLength));
711
712 pind--;
713 pind->type = DIVA_UM_IDI_IND;
714 pind->hdr.ind.Ind = ind;
715 pind->hdr.ind.IndCh = e->e.IndCh;
716 pind->data_length = e->e.R->PLength;
717 diva_data_q_ack_segment4write(&e->data,
718 (int) (sizeof(*pind) +
719 e->e.R->PLength));
720 do_wakeup = 1;
721 }
722
723 if ((e->status & DIVA_UM_IDI_RC_PENDING) && !e->rc.count) {
724 do_wakeup = 0;
725 }
726
727 return (do_wakeup);
728}
729
730/* --------------------------------------------------------------------------
731 Write return code to the return code queue of entity
732 -------------------------------------------------------------------------- */
733static int write_return_code(divas_um_idi_entity_t * e, byte rc)
734{
735 diva_um_idi_ind_hdr_t *prc;
736
737 if (!(prc =
738 (diva_um_idi_ind_hdr_t *) diva_data_q_get_segment4write(&e->rc)))
739 {
740 DBG_ERR(("A: A(%d) E(%08x) rc(%02x) lost",
741 e->adapter->adapter_nr, e, rc));
742 e->status &= ~DIVA_UM_IDI_RC_PENDING;
743 return (-1);
744 }
745
746 prc->type = DIVA_UM_IDI_IND_RC;
747 prc->hdr.rc.Rc = rc;
748 prc->hdr.rc.RcCh = e->e.RcCh;
749 prc->data_length = 0;
750 diva_data_q_ack_segment4write(&e->rc, sizeof(*prc));
751
752 return (0);
753}
754
755/* --------------------------------------------------------------------------
756 Return amount of entries that can be bead from this entity or
757 -1 if adapter was removed
758 -------------------------------------------------------------------------- */
759int diva_user_mode_idi_ind_ready(void *entity, void *os_handle)
760{
761 divas_um_idi_entity_t *e;
762 diva_um_idi_adapter_t *a;
763 diva_os_spin_lock_magic_t old_irql;
764 int ret;
765
766 if (!entity)
767 return (-1);
768 diva_os_enter_spin_lock(&adapter_lock, &old_irql, "ind_ready");
769 e = (divas_um_idi_entity_t *) entity;
770 a = e->adapter;
771
772 if ((!a) || (a->status & DIVA_UM_IDI_ADAPTER_REMOVED)) {
773 /*
774 Adapter was unloaded
775 */
776 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "ind_ready");
777 return (-1); /* adapter was removed */
778 }
779 if (e->status & DIVA_UM_IDI_REMOVED) {
780 /*
781 entity was removed as result of adapter removal
782 user should assign this entity again
783 */
784 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "ind_ready");
785 return (-1);
786 }
787
788 ret = e->rc.count + e->data.count;
789
790 if ((e->status & DIVA_UM_IDI_RC_PENDING) && !e->rc.count) {
791 ret = 0;
792 }
793
794 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "ind_ready");
795
796 return (ret);
797}
798
799void *diva_um_id_get_os_context(void *entity)
800{
801 return (((divas_um_idi_entity_t *) entity)->os_context);
802}
803
804int divas_um_idi_entity_assigned(void *entity)
805{
806 divas_um_idi_entity_t *e;
807 diva_um_idi_adapter_t *a;
808 int ret;
809 diva_os_spin_lock_magic_t old_irql;
810
811 diva_os_enter_spin_lock(&adapter_lock, &old_irql, "assigned?");
812
813
814 e = (divas_um_idi_entity_t *) entity;
815 if (!e || (!(a = e->adapter)) ||
816 (e->status & DIVA_UM_IDI_REMOVED) ||
817 (a->status & DIVA_UM_IDI_ADAPTER_REMOVED)) {
818 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "assigned?");
819 return (0);
820 }
821
822 e->status |= DIVA_UM_IDI_REMOVE_PENDING;
823
824 ret = (e->e.Id || e->rc_count
825 || (e->status & DIVA_UM_IDI_ASSIGN_PENDING));
826
827 DBG_TRC(("Id:%02x, rc_count:%d, status:%08x", e->e.Id, e->rc_count,
828 e->status))
829
830 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "assigned?");
831
832 return (ret);
833}
834
835int divas_um_idi_entity_start_remove(void *entity)
836{
837 divas_um_idi_entity_t *e;
838 diva_um_idi_adapter_t *a;
839 diva_os_spin_lock_magic_t old_irql;
840
841 diva_os_enter_spin_lock(&adapter_lock, &old_irql, "start_remove");
842
843 e = (divas_um_idi_entity_t *) entity;
844 if (!e || (!(a = e->adapter)) ||
845 (e->status & DIVA_UM_IDI_REMOVED) ||
846 (a->status & DIVA_UM_IDI_ADAPTER_REMOVED)) {
847 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "start_remove");
848 return (0);
849 }
850
851 if (e->rc_count) {
852 /*
853 Entity BUSY
854 */
855 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "start_remove");
856 return (1);
857 }
858
859 if (!e->e.Id) {
860 /*
861 Remove request was already pending, and arrived now
862 */
863 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "start_remove");
864 return (0); /* REMOVE was pending */
865 }
866
867 /*
868 Now send remove request
869 */
870 e->e.Req = REMOVE;
871 e->e.ReqCh = 0;
872
873 e->rc_count++;
874
875 DBG_TRC(("A(%d) E(%08x) request(%02x-%02x-%02x (%d))",
876 e->adapter->adapter_nr, e, e->e.Id, e->e.Req,
877 e->e.ReqCh, e->e.X->PLength));
878
879 if (a->d.request)
880 (*(a->d.request)) (&e->e);
881
882 diva_os_leave_spin_lock(&adapter_lock, &old_irql, "start_remove");
883
884 return (0);
885}
diff --git a/drivers/isdn/hardware/eicon/um_idi.h b/drivers/isdn/hardware/eicon/um_idi.h
new file mode 100644
index 000000000000..141072f8881e
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/um_idi.h
@@ -0,0 +1,43 @@
1/* $Id: um_idi.h,v 1.6 2004/03/21 17:26:01 armin Exp $ */
2
3#ifndef __DIVA_USER_MODE_IDI_CORE_H__
4#define __DIVA_USER_MODE_IDI_CORE_H__
5
6
7/*
8 interface between UM IDI core and OS dependent part
9 */
10int diva_user_mode_idi_init(void);
11void diva_user_mode_idi_finit(void);
12void *divas_um_idi_create_entity(dword adapter_nr, void *file);
13int divas_um_idi_delete_entity(int adapter_nr, void *entity);
14
15typedef int (*divas_um_idi_copy_to_user_fn_t) (void *os_handle,
16 void *dst,
17 const void *src,
18 int length);
19typedef int (*divas_um_idi_copy_from_user_fn_t) (void *os_handle,
20 void *dst,
21 const void *src,
22 int length);
23
24int diva_um_idi_read(void *entity,
25 void *os_handle,
26 void *dst,
27 int max_length, divas_um_idi_copy_to_user_fn_t cp_fn);
28
29int diva_um_idi_write(void *entity,
30 void *os_handle,
31 const void *src,
32 int length, divas_um_idi_copy_from_user_fn_t cp_fn);
33
34int diva_user_mode_idi_ind_ready(void *entity, void *os_handle);
35void *diva_um_id_get_os_context(void *entity);
36int diva_os_get_context_size(void);
37int divas_um_idi_entity_assigned(void *entity);
38int divas_um_idi_entity_start_remove(void *entity);
39
40void diva_um_idi_start_wdog(void *entity);
41void diva_um_idi_stop_wdog(void *entity);
42
43#endif
diff --git a/drivers/isdn/hardware/eicon/um_xdi.h b/drivers/isdn/hardware/eicon/um_xdi.h
new file mode 100644
index 000000000000..b48fc042a5bc
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/um_xdi.h
@@ -0,0 +1,68 @@
1/* $Id: um_xdi.h,v 1.1.2.2 2002/10/02 14:38:38 armin Exp $ */
2
3#ifndef __DIVA_USER_MODE_XDI_H__
4#define __DIVA_USER_MODE_XDI_H__
5
6/*
7 Contains declaratiom of structures shared between application
8 and user mode idi driver
9*/
10
11typedef struct _diva_um_idi_adapter_features {
12 dword type;
13 dword features;
14 dword channels;
15 dword serial_number;
16 char name[128];
17} diva_um_idi_adapter_features_t;
18
19#define DIVA_UM_IDI_REQ_MASK 0x0000FFFF
20#define DIVA_UM_IDI_REQ_TYPE_MASK (~(DIVA_UM_IDI_REQ_MASK))
21#define DIVA_UM_IDI_GET_FEATURES 1 /* trigger features indication */
22#define DIVA_UM_IDI_REQ 2
23#define DIVA_UM_IDI_REQ_TYPE_MAN 0x10000000
24#define DIVA_UM_IDI_REQ_TYPE_SIG 0x20000000
25#define DIVA_UM_IDI_REQ_TYPE_NET 0x30000000
26#define DIVA_UM_IDI_REQ_MAN (DIVA_UM_IDI_REQ | DIVA_UM_IDI_REQ_TYPE_MAN)
27#define DIVA_UM_IDI_REQ_SIG (DIVA_UM_IDI_REQ | DIVA_UM_IDI_REQ_TYPE_SIG)
28#define DIVA_UM_IDI_REQ_NET (DIVA_UM_IDI_REQ | DIVA_UM_IDI_REQ_TYPE_NET)
29/*
30 data_length bytes will follow this structure
31*/
32typedef struct _diva_um_idi_req_hdr {
33 dword type;
34 dword Req;
35 dword ReqCh;
36 dword data_length;
37} diva_um_idi_req_hdr_t;
38
39typedef struct _diva_um_idi_ind_parameters {
40 dword Ind;
41 dword IndCh;
42} diva_um_idi_ind_parameters_t;
43
44typedef struct _diva_um_idi_rc_parameters {
45 dword Rc;
46 dword RcCh;
47} diva_um_idi_rc_parameters_t;
48
49typedef union _diva_um_idi_ind {
50 diva_um_idi_adapter_features_t features;
51 diva_um_idi_ind_parameters_t ind;
52 diva_um_idi_rc_parameters_t rc;
53} diva_um_idi_ind_t;
54
55#define DIVA_UM_IDI_IND_FEATURES 1 /* features indication */
56#define DIVA_UM_IDI_IND 2
57#define DIVA_UM_IDI_IND_RC 3
58/*
59 data_length bytes of data follow
60 this structure
61*/
62typedef struct _diva_um_idi_ind_hdr {
63 dword type;
64 diva_um_idi_ind_t hdr;
65 dword data_length;
66} diva_um_idi_ind_hdr_t;
67
68#endif
diff --git a/drivers/isdn/hardware/eicon/xdi_adapter.h b/drivers/isdn/hardware/eicon/xdi_adapter.h
new file mode 100644
index 000000000000..a3bd163afb8f
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/xdi_adapter.h
@@ -0,0 +1,70 @@
1/* $Id: xdi_adapter.h,v 1.7 2004/03/21 17:26:01 armin Exp $ */
2
3#ifndef __DIVA_OS_XDI_ADAPTER_H__
4#define __DIVA_OS_XDI_ADAPTER_H__
5
6#define DIVAS_XDI_ADAPTER_BUS_PCI 0
7#define DIVAS_XDI_ADAPTER_BUS_ISA 1
8
9typedef struct _divas_pci_card_resources {
10 byte bus;
11 byte func;
12 void *hdev;
13
14 dword bar[8]; /* contains context of appropriate BAR Register */
15 void __iomem *addr[8]; /* same bar, but mapped into memory */
16 dword length[8]; /* bar length */
17 int mem_type_id[MAX_MEM_TYPE];
18 unsigned int qoffset;
19 byte irq;
20} divas_pci_card_resources_t;
21
22typedef union _divas_card_resources {
23 divas_pci_card_resources_t pci;
24} divas_card_resources_t;
25
26struct _diva_os_xdi_adapter;
27typedef int (*diva_init_card_proc_t) (struct _diva_os_xdi_adapter * a);
28typedef int (*diva_cmd_card_proc_t) (struct _diva_os_xdi_adapter * a,
29 diva_xdi_um_cfg_cmd_t * data,
30 int length);
31typedef void (*diva_xdi_clear_interrupts_proc_t) (struct
32 _diva_os_xdi_adapter *);
33
34#define DIVA_XDI_MBOX_BUSY 1
35#define DIVA_XDI_MBOX_WAIT_XLOG 2
36
37typedef struct _xdi_mbox_t {
38 dword status;
39 diva_xdi_um_cfg_cmd_data_t cmd_data;
40 dword data_length;
41 void *data;
42} xdi_mbox_t;
43
44typedef struct _diva_os_idi_adapter_interface {
45 diva_init_card_proc_t cleanup_adapter_proc;
46 diva_cmd_card_proc_t cmd_proc;
47} diva_os_idi_adapter_interface_t;
48
49typedef struct _diva_os_xdi_adapter {
50 struct list_head link;
51 int CardIndex;
52 int CardOrdinal;
53 int controller; /* number of this controller */
54 int Bus; /* PCI, ISA, ... */
55 divas_card_resources_t resources;
56 char port_name[24];
57 ISDN_ADAPTER xdi_adapter;
58 xdi_mbox_t xdi_mbox;
59 diva_os_idi_adapter_interface_t interface;
60 struct _diva_os_xdi_adapter *slave_adapters[3];
61 void *slave_list;
62 void *proc_adapter_dir; /* adapterX proc entry */
63 void *proc_info; /* info proc entry */
64 void *proc_grp_opt; /* group_optimization */
65 void *proc_d_l1_down; /* dynamic_l1_down */
66 volatile diva_xdi_clear_interrupts_proc_t clear_interrupts_proc;
67 dword dsp_mask;
68} diva_os_xdi_adapter_t;
69
70#endif
diff --git a/drivers/isdn/hardware/eicon/xdi_msg.h b/drivers/isdn/hardware/eicon/xdi_msg.h
new file mode 100644
index 000000000000..3ade28f66698
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/xdi_msg.h
@@ -0,0 +1,127 @@
1/* $Id: xdi_msg.h,v 1.1.2.2 2001/02/16 08:40:36 armin Exp $ */
2
3#ifndef __DIVA_XDI_UM_CFG_MESSSGE_H__
4#define __DIVA_XDI_UM_CFG_MESSAGE_H__
5
6/*
7 Definition of messages used to communicate between
8 XDI device driver and user mode configuration utility
9*/
10
11/*
12 As acknowledge one DWORD - card ordinal will be read from the card
13*/
14#define DIVA_XDI_UM_CMD_GET_CARD_ORDINAL 0
15
16/*
17 no acknowledge will be generated, memory block will be written in the
18 memory at given offset
19*/
20#define DIVA_XDI_UM_CMD_WRITE_SDRAM_BLOCK 1
21
22/*
23 no acknowledge will be genatated, FPGA will be programmed
24*/
25#define DIVA_XDI_UM_CMD_WRITE_FPGA 2
26
27/*
28 As acknowledge block of SDRAM will be read in the user buffer
29*/
30#define DIVA_XDI_UM_CMD_READ_SDRAM 3
31
32/*
33 As acknowledge dword with serial number will be read in the user buffer
34*/
35#define DIVA_XDI_UM_CMD_GET_SERIAL_NR 4
36
37/*
38 As acknowledge struct consisting from 9 dwords with PCI info.
39 dword[0...7] = 8 PCI BARS
40 dword[9] = IRQ
41*/
42#define DIVA_XDI_UM_CMD_GET_PCI_HW_CONFIG 5
43
44/*
45 Reset of the board + activation of primary
46 boot loader
47*/
48#define DIVA_XDI_UM_CMD_RESET_ADAPTER 6
49
50/*
51 Called after code download to start adapter
52 at specified address
53 Start does set new set of features due to fact that we not know
54 if protocol features have changed
55*/
56#define DIVA_XDI_UM_CMD_START_ADAPTER 7
57
58/*
59 Stop adapter, called if user
60 wishes to stop adapter without unload
61 of the driver, to reload adapter with
62 different protocol
63*/
64#define DIVA_XDI_UM_CMD_STOP_ADAPTER 8
65
66/*
67 Get state of current adapter
68 Acknowledge is one dword with following values:
69 0 - adapter ready for download
70 1 - adapter running
71 2 - adapter dead
72 3 - out of service, driver should be restarted or hardware problem
73*/
74#define DIVA_XDI_UM_CMD_GET_CARD_STATE 9
75
76/*
77 Reads XLOG entry from the card
78*/
79#define DIVA_XDI_UM_CMD_READ_XLOG_ENTRY 10
80
81/*
82 Set untranslated protocol code features
83 */
84#define DIVA_XDI_UM_CMD_SET_PROTOCOL_FEATURES 11
85
86typedef struct _diva_xdi_um_cfg_cmd_data_set_features {
87 dword features;
88} diva_xdi_um_cfg_cmd_data_set_features_t;
89
90typedef struct _diva_xdi_um_cfg_cmd_data_start {
91 dword offset;
92 dword features;
93} diva_xdi_um_cfg_cmd_data_start_t;
94
95typedef struct _diva_xdi_um_cfg_cmd_data_write_sdram {
96 dword ram_number;
97 dword offset;
98 dword length;
99} diva_xdi_um_cfg_cmd_data_write_sdram_t;
100
101typedef struct _diva_xdi_um_cfg_cmd_data_write_fpga {
102 dword fpga_number;
103 dword image_length;
104} diva_xdi_um_cfg_cmd_data_write_fpga_t;
105
106typedef struct _diva_xdi_um_cfg_cmd_data_read_sdram {
107 dword ram_number;
108 dword offset;
109 dword length;
110} diva_xdi_um_cfg_cmd_data_read_sdram_t;
111
112typedef union _diva_xdi_um_cfg_cmd_data {
113 diva_xdi_um_cfg_cmd_data_write_sdram_t write_sdram;
114 diva_xdi_um_cfg_cmd_data_write_fpga_t write_fpga;
115 diva_xdi_um_cfg_cmd_data_read_sdram_t read_sdram;
116 diva_xdi_um_cfg_cmd_data_start_t start;
117 diva_xdi_um_cfg_cmd_data_set_features_t features;
118} diva_xdi_um_cfg_cmd_data_t;
119
120typedef struct _diva_xdi_um_cfg_cmd {
121 dword adapter; /* Adapter number 1...N */
122 dword command;
123 diva_xdi_um_cfg_cmd_data_t command_data;
124 dword data_length; /* Plain binary data will follow */
125} diva_xdi_um_cfg_cmd_t;
126
127#endif
diff --git a/drivers/isdn/hardware/eicon/xdi_vers.h b/drivers/isdn/hardware/eicon/xdi_vers.h
new file mode 100644
index 000000000000..cf3494185b9d
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/xdi_vers.h
@@ -0,0 +1,26 @@
1
2/*
3 *
4 Copyright (c) Eicon Networks, 2002.
5 *
6 This source file is supplied for the use with
7 Eicon Networks range of DIVA Server Adapters.
8 *
9 Eicon File Revision : 2.1
10 *
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2, or (at your option)
14 any later version.
15 *
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
18 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 See the GNU General Public License for more details.
20 *
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26static char diva_xdi_common_code_build[] = "102-52";
diff --git a/drivers/isdn/hisax/Kconfig b/drivers/isdn/hisax/Kconfig
new file mode 100644
index 000000000000..6c7b8bffc6fd
--- /dev/null
+++ b/drivers/isdn/hisax/Kconfig
@@ -0,0 +1,442 @@
1
2menu "Passive cards"
3 depends on ISDN_I4L
4
5config ISDN_DRV_HISAX
6 tristate "HiSax SiemensChipSet driver support"
7 select CRC_CCITT
8 ---help---
9 This is a driver supporting the Siemens chipset on various
10 ISDN-cards (like AVM A1, Elsa ISDN cards, Teles S0-16.0, Teles
11 S0-16.3, Teles S0-8, Teles/Creatix PnP, ITK micro ix1 and many
12 compatibles).
13
14 HiSax is just the name of this driver, not the name of any hardware.
15
16 If you have a card with such a chipset, you should say Y here and
17 also to the configuration option of the driver for your particular
18 card, below.
19
20if ISDN_DRV_HISAX!=n
21
22comment "D-channel protocol features"
23
24config HISAX_EURO
25 bool "HiSax Support for EURO/DSS1"
26 help
27 Say Y or N according to the D-channel protocol which your local
28 telephone service company provides.
29
30 The call control protocol E-DSS1 is used in most European countries.
31 If unsure, say Y.
32
33config DE_AOC
34 bool "Support for german chargeinfo"
35 depends on HISAX_EURO
36 help
37 If you want that the HiSax hardware driver sends messages to the
38 upper level of the isdn code on each AOCD (Advice Of Charge, During
39 the call -- transmission of the fee information during a call) and
40 on each AOCE (Advice Of Charge, at the End of the call --
41 transmission of fee information at the end of the call), say Y here.
42 This works only in Germany.
43
44config HISAX_NO_SENDCOMPLETE
45 bool "Disable sending complete"
46 depends on HISAX_EURO
47 help
48 If you have trouble with some ugly exchanges or you live in
49 Australia select this option.
50
51config HISAX_NO_LLC
52 bool "Disable sending low layer compatibility"
53 depends on HISAX_EURO
54 help
55 If you have trouble with some ugly exchanges try to select this
56 option.
57
58config HISAX_NO_KEYPAD
59 bool "Disable keypad protocol option"
60 depends on HISAX_EURO
61 help
62 If you like to send special dial strings including * or # without
63 using the keypad protocol, select this option.
64
65config HISAX_1TR6
66 bool "HiSax Support for german 1TR6"
67 help
68 Say Y or N according to the D-channel protocol which your local
69 telephone service company provides.
70
71 1TR6 is an old call control protocol which was used in Germany
72 before E-DSS1 was established. Nowadays, all new lines in Germany
73 use E-DSS1.
74
75config HISAX_NI1
76 bool "HiSax Support for US NI1"
77 help
78 Enable this if you like to use ISDN in US on a NI1 basic rate
79 interface.
80
81config HISAX_MAX_CARDS
82 int "Maximum number of cards supported by HiSax"
83 default "8"
84 help
85 This option allows you to specify the maximum number of cards which
86 the HiSax driver will be able to handle.
87
88comment "HiSax supported cards"
89
90config HISAX_16_0
91 bool "Teles 16.0/8.0"
92 depends on ISA
93 help
94 This enables HiSax support for the Teles ISDN-cards S0-16.0, S0-8
95 and many compatibles.
96
97 See <file:Documentation/isdn/README.HiSax> on how to configure it
98 using the different cards, a different D-channel protocol, or
99 non-standard IRQ/port/shmem settings.
100
101config HISAX_16_3
102 bool "Teles 16.3 or PNP or PCMCIA"
103 help
104 This enables HiSax support for the Teles ISDN-cards S0-16.3 the
105 Teles/Creatix PnP and the Teles PCMCIA.
106
107 See <file:Documentation/isdn/README.HiSax> on how to configure it
108 using the different cards, a different D-channel protocol, or
109 non-standard IRQ/port settings.
110
111config HISAX_TELESPCI
112 bool "Teles PCI"
113 depends on PCI && (BROKEN || !(SPARC64 || PPC))
114 help
115 This enables HiSax support for the Teles PCI.
116 See <file:Documentation/isdn/README.HiSax> on how to configure it.
117
118config HISAX_S0BOX
119 bool "Teles S0Box"
120 help
121 This enables HiSax support for the Teles/Creatix parallel port
122 S0BOX. See <file:Documentation/isdn/README.HiSax> on how to
123 configure it.
124
125config HISAX_AVM_A1
126 bool "AVM A1 (Fritz)"
127 depends on ISA
128 help
129 This enables HiSax support for the AVM A1 (aka "Fritz").
130
131 See <file:Documentation/isdn/README.HiSax> on how to configure it
132 using the different cards, a different D-channel protocol, or
133 non-standard IRQ/port settings.
134
135config HISAX_FRITZPCI
136 bool "AVM PnP/PCI (Fritz!PnP/PCI)"
137 help
138 This enables HiSax support for the AVM "Fritz!PnP" and "Fritz!PCI".
139 See <file:Documentation/isdn/README.HiSax> on how to configure it.
140
141config HISAX_AVM_A1_PCMCIA
142 bool "AVM A1 PCMCIA (Fritz)"
143 help
144 This enables HiSax support for the AVM A1 "Fritz!PCMCIA").
145 See <file:Documentation/isdn/README.HiSax> on how to configure it.
146
147config HISAX_ELSA
148 bool "Elsa cards"
149 help
150 This enables HiSax support for the Elsa Mircolink ISA cards, for the
151 Elsa Quickstep series cards and Elsa PCMCIA.
152
153 See <file:Documentation/isdn/README.HiSax> on how to configure it
154 using the different cards, a different D-channel protocol, or
155 non-standard IRQ/port settings.
156
157config HISAX_IX1MICROR2
158 bool "ITK ix1-micro Revision 2"
159 depends on ISA
160 help
161 This enables HiSax support for the ITK ix1-micro Revision 2 card.
162
163 See <file:Documentation/isdn/README.HiSax> on how to configure it
164 using the different cards, a different D-channel protocol, or
165 non-standard IRQ/port settings.
166
167config HISAX_DIEHLDIVA
168 bool "Eicon.Diehl Diva cards"
169 help
170 This enables HiSax support for the Eicon.Diehl Diva none PRO
171 versions passive ISDN cards.
172
173 See <file:Documentation/isdn/README.HiSax> on how to configure it
174 using the different cards, a different D-channel protocol, or
175 non-standard IRQ/port settings.
176
177config HISAX_ASUSCOM
178 bool "ASUSCOM ISA cards"
179 depends on ISA
180 help
181 This enables HiSax support for the AsusCom and their OEM versions
182 passive ISDN ISA cards.
183
184 See <file:Documentation/isdn/README.HiSax> on how to configure it
185 using the different cards, a different D-channel protocol, or
186 non-standard IRQ/port settings.
187
188config HISAX_TELEINT
189 bool "TELEINT cards"
190 depends on ISA
191 help
192 This enables HiSax support for the TELEINT SA1 semiactiv ISDN card.
193
194 See <file:Documentation/isdn/README.HiSax> on how to configure it
195 using the different cards, a different D-channel protocol, or
196 non-standard IRQ/port settings.
197
198config HISAX_HFCS
199 bool "HFC-S based cards"
200 depends on ISA
201 help
202 This enables HiSax support for the HFC-S 2BDS0 based cards, like
203 teles 16.3c.
204
205 See <file:Documentation/isdn/README.HiSax> on how to configure it
206 using the different cards, a different D-channel protocol, or
207 non-standard IRQ/port settings.
208
209config HISAX_SEDLBAUER
210 bool "Sedlbauer cards"
211 help
212 This enables HiSax support for the Sedlbauer passive ISDN cards.
213
214 See <file:Documentation/isdn/README.HiSax> on how to configure it
215 using the different cards, a different D-channel protocol, or
216 non-standard IRQ/port settings.
217
218config HISAX_SPORTSTER
219 bool "USR Sportster internal TA"
220 depends on ISA
221 help
222 This enables HiSax support for the USR Sportster internal TA card.
223
224 See <file:Documentation/isdn/README.HiSax> on how to configure it
225 using a different D-channel protocol, or non-standard IRQ/port
226 settings.
227
228config HISAX_MIC
229 bool "MIC card"
230 depends on ISA
231 help
232 This enables HiSax support for the ITH MIC card.
233
234 See <file:Documentation/isdn/README.HiSax> on how to configure it
235 using a different D-channel protocol, or non-standard IRQ/port
236 settings.
237
238config HISAX_NETJET
239 bool "NETjet card"
240 depends on PCI && (BROKEN || !(SPARC64 || PPC))
241 help
242 This enables HiSax support for the NetJet from Traverse
243 Technologies.
244
245 See <file:Documentation/isdn/README.HiSax> on how to configure it
246 using a different D-channel protocol, or non-standard IRQ/port
247 settings.
248
249config HISAX_NETJET_U
250 bool "NETspider U card"
251 depends on PCI && (BROKEN || !(SPARC64 || PPC))
252 help
253 This enables HiSax support for the Netspider U interface ISDN card
254 from Traverse Technologies.
255 See <file:Documentation/isdn/README.HiSax> on how to configure it
256 using a different D-channel protocol, or non-standard IRQ/port
257 settings.
258
259config HISAX_NICCY
260 bool "Niccy PnP/PCI card"
261 help
262 This enables HiSax support for the Dr. Neuhaus Niccy PnP or PCI.
263
264 See <file:Documentation/isdn/README.HiSax> on how to configure it
265 using a different D-channel protocol, or non-standard IRQ/port
266 settings.
267
268config HISAX_ISURF
269 bool "Siemens I-Surf card"
270 depends on ISA
271 help
272 This enables HiSax support for the Siemens I-Talk/I-Surf card with
273 ISAR chip.
274 See <file:Documentation/isdn/README.HiSax> on how to configure it
275 using a different D-channel protocol, or non-standard IRQ/port
276 settings.
277
278config HISAX_HSTSAPHIR
279 bool "HST Saphir card"
280 depends on ISA
281 help
282 This enables HiSax support for the HST Saphir card.
283
284 See <file:Documentation/isdn/README.HiSax> on how to configure it
285 using a different D-channel protocol, or non-standard IRQ/port
286 settings.
287
288config HISAX_BKM_A4T
289 bool "Telekom A4T card"
290 depends on PCI
291 help
292 This enables HiSax support for the Telekom A4T card.
293
294 See <file:Documentation/isdn/README.HiSax> on how to configure it
295 using a different D-channel protocol, or non-standard IRQ/port
296 settings.
297
298config HISAX_SCT_QUADRO
299 bool "Scitel Quadro card"
300 depends on PCI
301 help
302 This enables HiSax support for the Scitel Quadro card.
303
304 See <file:Documentation/isdn/README.HiSax> on how to configure it
305 using a different D-channel protocol, or non-standard IRQ/port
306 settings.
307
308config HISAX_GAZEL
309 bool "Gazel cards"
310 help
311 This enables HiSax support for the Gazel cards.
312
313 See <file:Documentation/isdn/README.HiSax> on how to configure it
314 using a different D-channel protocol, or non-standard IRQ/port
315 settings.
316
317config HISAX_HFC_PCI
318 bool "HFC PCI-Bus cards"
319 depends on PCI && (BROKEN || !(SPARC64 || PPC))
320 help
321 This enables HiSax support for the HFC-S PCI 2BDS0 based cards.
322
323 For more informations see under
324 <file:Documentation/isdn/README.hfc-pci>.
325
326config HISAX_W6692
327 bool "Winbond W6692 based cards"
328 depends on PCI
329 help
330 This enables HiSax support for Winbond W6692 based PCI ISDN cards.
331
332 See <file:Documentation/isdn/README.HiSax> on how to configure it
333 using a different D-channel protocol, or non-standard IRQ/port
334 settings.
335
336config HISAX_HFC_SX
337 bool "HFC-S+, HFC-SP, HFC-PCMCIA cards"
338 help
339 This enables HiSax support for the HFC-S+, HFC-SP and HFC-PCMCIA
340 cards. This code is not finished yet.
341
342# bool ' TESTEMULATOR (EXPERIMENTAL)' CONFIG_HISAX_TESTEMU
343
344config HISAX_ENTERNOW_PCI
345 bool "Formula-n enter:now PCI card"
346 depends on PCI && (BROKEN || !(SPARC64 || PPC))
347 help
348 This enables HiSax support for the Formula-n enter:now PCI
349 ISDN card.
350
351config HISAX_AMD7930
352 bool "Am7930 (EXPERIMENTAL)"
353 depends on EXPERIMENTAL && (SPARC32 || SPARC64)
354 help
355 This enables HiSax support for the AMD7930 chips on some SPARCs.
356 This code is not finished yet.
357
358endif
359
360if ISDN_DRV_HISAX
361
362config HISAX_DEBUG
363 bool "HiSax debugging"
364 help
365 This enables debugging code in the new-style HiSax drivers, i.e.
366 the ST5481 USB driver currently.
367 If in doubt, say yes.
368
369comment "HiSax PCMCIA card service modules"
370
371config HISAX_SEDLBAUER_CS
372 tristate "Sedlbauer PCMCIA cards"
373 depends on PCMCIA && HISAX_SEDLBAUER
374 help
375 This enables the PCMCIA client driver for the Sedlbauer Speed Star
376 and Speed Star II cards.
377
378config HISAX_ELSA_CS
379 tristate "ELSA PCMCIA MicroLink cards"
380 depends on PCMCIA && HISAX_ELSA
381 help
382 This enables the PCMCIA client driver for the Elsa PCMCIA MicroLink
383 card.
384
385config HISAX_AVM_A1_CS
386 tristate "AVM A1 PCMCIA cards"
387 depends on PCMCIA && ISDN_DRV_HISAX
388 help
389 This enables the PCMCIA client driver for the AVM A1 / Fritz!Card
390 PCMCIA cards.
391
392config HISAX_TELES_CS
393 tristate "TELES PCMCIA cards"
394 depends on PCMCIA && HISAX_16_3
395 help
396 This enables the PCMCIA client driver for the Teles PCMCIA cards.
397
398comment "HiSax sub driver modules"
399
400config HISAX_ST5481
401 tristate "ST5481 USB ISDN modem (EXPERIMENTAL)"
402 depends on USB && EXPERIMENTAL
403 select CRC_CCITT
404 help
405 This enables the driver for ST5481 based USB ISDN adapters,
406 e.g. the BeWan Gazel 128 USB
407
408config HISAX_HFCUSB
409 tristate "HFC USB based ISDN modems (EXPERIMENTAL)"
410 depends on USB && EXPERIMENTAL
411 help
412 This enables the driver for HFC USB based ISDN modems.
413
414config HISAX_HFC4S8S
415 tristate "HFC-4S/8S based ISDN cards (EXPERIMENTAL)"
416 depends on EXPERIMENTAL
417 help
418 This enables the driver for HFC-4S/8S based ISDN cards.
419
420config HISAX_FRITZ_PCIPNP
421 tristate "AVM Fritz!Card PCI/PCIv2/PnP support (EXPERIMENTAL)"
422 depends on PCI && EXPERIMENTAL
423 help
424 This enables the driver for the AVM Fritz!Card PCI,
425 Fritz!Card PCI v2 and Fritz!Card PnP.
426 (the latter also needs you to select "ISA Plug and Play support"
427 from the menu "Plug and Play configuration")
428
429config HISAX_HDLC
430 bool
431 depends on HISAX_ST5481
432 default y
433
434config HISAX_AVM_A1_PCMCIA
435 bool
436 depends on HISAX_AVM_A1_CS
437 default y
438
439endif
440
441endmenu
442
diff --git a/drivers/isdn/hisax/Makefile b/drivers/isdn/hisax/Makefile
new file mode 100644
index 000000000000..8d6bb56754b8
--- /dev/null
+++ b/drivers/isdn/hisax/Makefile
@@ -0,0 +1,64 @@
1# Makefile for the hisax ISDN device driver
2
3# The target object and module list name.
4
5# Define maximum number of cards
6
7EXTRA_CFLAGS += -DHISAX_MAX_CARDS=$(CONFIG_HISAX_MAX_CARDS)
8
9obj-$(CONFIG_ISDN_DRV_HISAX) += hisax.o
10obj-$(CONFIG_HISAX_SEDLBAUER_CS) += sedlbauer_cs.o
11obj-$(CONFIG_HISAX_ELSA_CS) += elsa_cs.o
12obj-$(CONFIG_HISAX_AVM_A1_CS) += avma1_cs.o
13obj-$(CONFIG_HISAX_TELES_CS) += teles_cs.o
14obj-$(CONFIG_HISAX_ST5481) += hisax_st5481.o
15obj-$(CONFIG_HISAX_HFCUSB) += hfc_usb.o
16obj-$(CONFIG_HISAX_HFC4S8S) += hfc4s8s_l1.o
17obj-$(CONFIG_HISAX_FRITZ_PCIPNP) += hisax_isac.o hisax_fcpcipnp.o
18
19ifdef CONFIG_HISAX_HDLC
20obj-$(CONFIG_ISDN_DRV_HISAX) += isdnhdlc.o
21endif
22
23# Multipart objects.
24
25hisax_st5481-y := st5481_init.o st5481_usb.o st5481_d.o \
26 st5481_b.o st5481_hdlc.o
27
28hisax-y := config.o isdnl1.o tei.o isdnl2.o isdnl3.o \
29 lmgr.o q931.o callc.o fsm.o
30hisax-$(CONFIG_HISAX_EURO) += l3dss1.o
31hisax-$(CONFIG_HISAX_NI1) += l3ni1.o
32hisax-$(CONFIG_HISAX_1TR6) += l3_1tr6.o
33
34hisax-$(CONFIG_HISAX_16_0) += teles0.o isac.o arcofi.o hscx.o
35hisax-$(CONFIG_HISAX_16_3) += teles3.o isac.o arcofi.o hscx.o
36hisax-$(CONFIG_HISAX_TELESPCI) += telespci.o isac.o arcofi.o hscx.o
37hisax-$(CONFIG_HISAX_S0BOX) += s0box.o isac.o arcofi.o hscx.o
38hisax-$(CONFIG_HISAX_AVM_A1) += avm_a1.o isac.o arcofi.o hscx.o
39hisax-$(CONFIG_HISAX_AVM_A1_PCMCIA) += avm_a1p.o isac.o arcofi.o hscx.o
40hisax-$(CONFIG_HISAX_FRITZPCI) += avm_pci.o isac.o arcofi.o
41hisax-$(CONFIG_HISAX_ELSA) += elsa.o isac.o arcofi.o hscx.o
42hisax-$(CONFIG_HISAX_IX1MICROR2) += ix1_micro.o isac.o arcofi.o hscx.o
43hisax-$(CONFIG_HISAX_DIEHLDIVA) += diva.o isac.o arcofi.o hscx.o ipacx.o
44hisax-$(CONFIG_HISAX_ASUSCOM) += asuscom.o isac.o arcofi.o hscx.o
45hisax-$(CONFIG_HISAX_TELEINT) += teleint.o isac.o arcofi.o hfc_2bs0.o
46hisax-$(CONFIG_HISAX_SEDLBAUER) += sedlbauer.o isac.o arcofi.o hscx.o \
47 isar.o
48hisax-$(CONFIG_HISAX_SPORTSTER) += sportster.o isac.o arcofi.o hscx.o
49hisax-$(CONFIG_HISAX_MIC) += mic.o isac.o arcofi.o hscx.o
50hisax-$(CONFIG_HISAX_NETJET) += nj_s.o netjet.o isac.o arcofi.o
51hisax-$(CONFIG_HISAX_NETJET_U) += nj_u.o netjet.o icc.o
52hisax-$(CONFIG_HISAX_HFCS) += hfcscard.o hfc_2bds0.o
53hisax-$(CONFIG_HISAX_HFC_PCI) += hfc_pci.o
54hisax-$(CONFIG_HISAX_HFC_SX) += hfc_sx.o
55hisax-$(CONFIG_HISAX_NICCY) += niccy.o isac.o arcofi.o hscx.o
56hisax-$(CONFIG_HISAX_ISURF) += isurf.o isac.o arcofi.o isar.o
57hisax-$(CONFIG_HISAX_HSTSAPHIR) += saphir.o isac.o arcofi.o hscx.o
58hisax-$(CONFIG_HISAX_BKM_A4T) += bkm_a4t.o isac.o arcofi.o jade.o
59hisax-$(CONFIG_HISAX_SCT_QUADRO) += bkm_a8.o isac.o arcofi.o hscx.o
60hisax-$(CONFIG_HISAX_GAZEL) += gazel.o isac.o arcofi.o hscx.o
61hisax-$(CONFIG_HISAX_W6692) += w6692.o
62hisax-$(CONFIG_HISAX_ENTERNOW_PCI) += enternow_pci.o amd7930_fn.o
63#hisax-$(CONFIG_HISAX_TESTEMU) += testemu.o
64
diff --git a/drivers/isdn/hisax/amd7930_fn.c b/drivers/isdn/hisax/amd7930_fn.c
new file mode 100644
index 000000000000..c4f861a5db25
--- /dev/null
+++ b/drivers/isdn/hisax/amd7930_fn.c
@@ -0,0 +1,796 @@
1/* gerdes_amd7930.c,v 0.99 2001/10/02
2 *
3 * gerdes_amd7930.c Amd 79C30A and 79C32A specific routines
4 * (based on HiSax driver by Karsten Keil)
5 *
6 * Author Christoph Ersfeld <info@formula-n.de>
7 * Formula-n Europe AG (www.formula-n.com)
8 * previously Gerdes AG
9 *
10 *
11 * This file is (c) under GNU PUBLIC LICENSE
12 *
13 *
14 * Notes:
15 * Version 0.99 is the first release of this driver and there are
16 * certainly a few bugs.
17 *
18 * Please don't report any malfunction to me without sending
19 * (compressed) debug-logs.
20 * It would be nearly impossible to retrace it.
21 *
22 * Log D-channel-processing as follows:
23 *
24 * 1. Load hisax with card-specific parameters, this example ist for
25 * Formula-n enter:now ISDN PCI and compatible
26 * (f.e. Gerdes Power ISDN PCI)
27 *
28 * modprobe hisax type=41 protocol=2 id=gerdes
29 *
30 * if you chose an other value for id, you need to modify the
31 * code below, too.
32 *
33 * 2. set debug-level
34 *
35 * hisaxctrl gerdes 1 0x3ff
36 * hisaxctrl gerdes 11 0x4f
37 * cat /dev/isdnctrl >> ~/log &
38 *
39 * Please take also a look into /var/log/messages if there is
40 * anything importand concerning HISAX.
41 *
42 *
43 * Credits:
44 * Programming the driver for Formula-n enter:now ISDN PCI and
45 * necessary this driver for the used Amd 7930 D-channel-controller
46 * was spnsored by Formula-n Europe AG.
47 * Thanks to Karsten Keil and Petr Novak, who gave me support in
48 * Hisax-specific questions.
49 * I want so say special thanks to Carl-Friedrich Braun, who had to
50 * answer a lot of questions about generally ISDN and about handling
51 * of the Amd-Chip.
52 *
53 */
54
55
56#include "hisax.h"
57#include "isdnl1.h"
58#include "isac.h"
59#include "amd7930_fn.h"
60#include <linux/interrupt.h>
61#include <linux/init.h>
62
63static void Amd7930_new_ph(struct IsdnCardState *cs);
64
65static WORD initAMD[] = {
66 0x0100,
67
68 0x00A5, 3, 0x01, 0x40, 0x58, // LPR, LMR1, LMR2
69 0x0086, 1, 0x0B, // DMR1 (D-Buffer TH-Interrupts on)
70 0x0087, 1, 0xFF, // DMR2
71 0x0092, 1, 0x03, // EFCR (extended mode d-channel-fifo on)
72 0x0090, 4, 0xFE, 0xFF, 0x02, 0x0F, // FRAR4, SRAR4, DMR3, DMR4 (address recognition )
73 0x0084, 2, 0x80, 0x00, // DRLR
74 0x00C0, 1, 0x47, // PPCR1
75 0x00C8, 1, 0x01, // PPCR2
76
77 0x0102,
78 0x0107,
79 0x01A1, 1,
80 0x0121, 1,
81 0x0189, 2,
82
83 0x0045, 4, 0x61, 0x72, 0x00, 0x00, // MCR1, MCR2, MCR3, MCR4
84 0x0063, 2, 0x08, 0x08, // GX
85 0x0064, 2, 0x08, 0x08, // GR
86 0x0065, 2, 0x99, 0x00, // GER
87 0x0066, 2, 0x7C, 0x8B, // STG
88 0x0067, 2, 0x00, 0x00, // FTGR1, FTGR2
89 0x0068, 2, 0x20, 0x20, // ATGR1, ATGR2
90 0x0069, 1, 0x4F, // MMR1
91 0x006A, 1, 0x00, // MMR2
92 0x006C, 1, 0x40, // MMR3
93 0x0021, 1, 0x02, // INIT
94 0x00A3, 1, 0x40, // LMR1
95
96 0xFFFF
97};
98
99
100void /* macro wWordAMD */
101WriteWordAmd7930(struct IsdnCardState *cs, BYTE reg, WORD val)
102{
103 wByteAMD(cs, 0x00, reg);
104 wByteAMD(cs, 0x01, LOBYTE(val));
105 wByteAMD(cs, 0x01, HIBYTE(val));
106}
107
108WORD /* macro rWordAMD */
109ReadWordAmd7930(struct IsdnCardState *cs, BYTE reg)
110{
111 WORD res;
112 /* direct access register */
113 if(reg < 8) {
114 res = rByteAMD(cs, reg);
115 res += 256*rByteAMD(cs, reg);
116 }
117 /* indirect access register */
118 else {
119 wByteAMD(cs, 0x00, reg);
120 res = rByteAMD(cs, 0x01);
121 res += 256*rByteAMD(cs, 0x01);
122 }
123 return (res);
124}
125
126
127static void
128Amd7930_ph_command(struct IsdnCardState *cs, u_char command, char *s)
129{
130 if (cs->debug & L1_DEB_ISAC)
131 debugl1(cs, "AMD7930: %s: ph_command 0x%02X", s, command);
132
133 cs->dc.amd7930.lmr1 = command;
134 wByteAMD(cs, 0xA3, command);
135}
136
137
138
139static BYTE i430States[] = {
140// to reset F3 F4 F5 F6 F7 F8 AR from
141 0x01, 0x02, 0x00, 0x00, 0x00, 0x07, 0x05, 0x00, // init
142 0x01, 0x02, 0x00, 0x00, 0x00, 0x07, 0x05, 0x00, // reset
143 0x01, 0x02, 0x00, 0x00, 0x00, 0x09, 0x05, 0x04, // F3
144 0x01, 0x02, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, // F4
145 0x01, 0x02, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, // F5
146 0x01, 0x03, 0x00, 0x00, 0x00, 0x06, 0x05, 0x00, // F6
147 0x11, 0x13, 0x00, 0x00, 0x1B, 0x00, 0x15, 0x00, // F7
148 0x01, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, // F8
149 0x01, 0x03, 0x00, 0x00, 0x00, 0x09, 0x00, 0x0A}; // AR
150
151
152/* Row init - reset F3 F4 F5 F6 F7 F8 AR */
153static BYTE stateHelper[] = { 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
154
155
156
157
158static void
159Amd7930_get_state(struct IsdnCardState *cs) {
160 BYTE lsr = rByteAMD(cs, 0xA1);
161 cs->dc.amd7930.ph_state = (lsr & 0x7) + 2;
162 Amd7930_new_ph(cs);
163}
164
165
166
167static void
168Amd7930_new_ph(struct IsdnCardState *cs)
169{
170 u_char index = stateHelper[cs->dc.amd7930.old_state]*8 + stateHelper[cs->dc.amd7930.ph_state]-1;
171 u_char message = i430States[index];
172
173 if (cs->debug & L1_DEB_ISAC)
174 debugl1(cs, "AMD7930: new_ph %d, old_ph %d, message %d, index %d",
175 cs->dc.amd7930.ph_state, cs->dc.amd7930.old_state, message & 0x0f, index);
176
177 cs->dc.amd7930.old_state = cs->dc.amd7930.ph_state;
178
179 /* abort transmit if nessesary */
180 if ((message & 0xf0) && (cs->tx_skb)) {
181 wByteAMD(cs, 0x21, 0xC2);
182 wByteAMD(cs, 0x21, 0x02);
183 }
184
185 switch (message & 0x0f) {
186
187 case (1):
188 l1_msg(cs, HW_RESET | INDICATION, NULL);
189 Amd7930_get_state(cs);
190 break;
191 case (2): /* init, Card starts in F3 */
192 l1_msg(cs, HW_DEACTIVATE | CONFIRM, NULL);
193 break;
194 case (3):
195 l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL);
196 break;
197 case (4):
198 l1_msg(cs, HW_POWERUP | CONFIRM, NULL);
199 Amd7930_ph_command(cs, 0x50, "HW_ENABLE REQUEST");
200 break;
201 case (5):
202 l1_msg(cs, HW_RSYNC | INDICATION, NULL);
203 break;
204 case (6):
205 l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
206 break;
207 case (7): /* init, Card starts in F7 */
208 l1_msg(cs, HW_RSYNC | INDICATION, NULL);
209 l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
210 break;
211 case (8):
212 l1_msg(cs, HW_POWERUP | CONFIRM, NULL);
213 /* fall through */
214 case (9):
215 Amd7930_ph_command(cs, 0x40, "HW_ENABLE REQ cleared if set");
216 l1_msg(cs, HW_RSYNC | INDICATION, NULL);
217 l1_msg(cs, HW_INFO2 | INDICATION, NULL);
218 l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
219 break;
220 case (10):
221 Amd7930_ph_command(cs, 0x40, "T3 expired, HW_ENABLE REQ cleared");
222 cs->dc.amd7930.old_state = 3;
223 break;
224 case (11):
225 l1_msg(cs, HW_INFO2 | INDICATION, NULL);
226 break;
227 default:
228 break;
229 }
230}
231
232
233
234static void
235Amd7930_bh(struct IsdnCardState *cs)
236{
237
238 struct PStack *stptr;
239
240 if (!cs)
241 return;
242 if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) {
243 if (cs->debug)
244 debugl1(cs, "Amd7930: bh, D-Channel Busy cleared");
245 stptr = cs->stlist;
246 while (stptr != NULL) {
247 stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL);
248 stptr = stptr->next;
249 }
250 }
251 if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) {
252 if (cs->debug & L1_DEB_ISAC)
253 debugl1(cs, "AMD7930: bh, D_L1STATECHANGE");
254 Amd7930_new_ph(cs);
255 }
256
257 if (test_and_clear_bit(D_RCVBUFREADY, &cs->event)) {
258 if (cs->debug & L1_DEB_ISAC)
259 debugl1(cs, "AMD7930: bh, D_RCVBUFREADY");
260 DChannel_proc_rcv(cs);
261 }
262
263 if (test_and_clear_bit(D_XMTBUFREADY, &cs->event)) {
264 if (cs->debug & L1_DEB_ISAC)
265 debugl1(cs, "AMD7930: bh, D_XMTBUFREADY");
266 DChannel_proc_xmt(cs);
267 }
268}
269
270static void
271Amd7930_empty_Dfifo(struct IsdnCardState *cs, int flag)
272{
273
274 BYTE stat, der;
275 BYTE *ptr;
276 struct sk_buff *skb;
277
278
279 if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
280 debugl1(cs, "Amd7930: empty_Dfifo");
281
282
283 ptr = cs->rcvbuf + cs->rcvidx;
284
285 /* AMD interrupts off */
286 AmdIrqOff(cs);
287
288 /* read D-Channel-Fifo*/
289 stat = rByteAMD(cs, 0x07); // DSR2
290
291 /* while Data in Fifo ... */
292 while ( (stat & 2) && ((ptr-cs->rcvbuf) < MAX_DFRAME_LEN_L1) ) {
293 *ptr = rByteAMD(cs, 0x04); // DCRB
294 ptr++;
295 stat = rByteAMD(cs, 0x07); // DSR2
296 cs->rcvidx = ptr - cs->rcvbuf;
297
298 /* Paket ready? */
299 if (stat & 1) {
300
301 der = rWordAMD(cs, 0x03);
302
303 /* no errors, packet ok */
304 if(!der && !flag) {
305 rWordAMD(cs, 0x89); // clear DRCR
306
307 if ((cs->rcvidx) > 0) {
308 if (!(skb = alloc_skb(cs->rcvidx, GFP_ATOMIC)))
309 printk(KERN_WARNING "HiSax: Amd7930: empty_Dfifo, D receive out of memory!\n");
310 else {
311 /* Debugging */
312 if (cs->debug & L1_DEB_ISAC_FIFO) {
313 char *t = cs->dlog;
314
315 t += sprintf(t, "Amd7930: empty_Dfifo cnt: %d |", cs->rcvidx);
316 QuickHex(t, cs->rcvbuf, cs->rcvidx);
317 debugl1(cs, cs->dlog);
318 }
319 /* moves received data in sk-buffer */
320 memcpy(skb_put(skb, cs->rcvidx), cs->rcvbuf, cs->rcvidx);
321 skb_queue_tail(&cs->rq, skb);
322 }
323 }
324
325 }
326 /* throw damaged packets away, reset receive-buffer, indicate RX */
327 ptr = cs->rcvbuf;
328 cs->rcvidx = 0;
329 schedule_event(cs, D_RCVBUFREADY);
330 }
331 }
332 /* Packet to long, overflow */
333 if(cs->rcvidx >= MAX_DFRAME_LEN_L1) {
334 if (cs->debug & L1_DEB_WARN)
335 debugl1(cs, "AMD7930: empty_Dfifo L2-Framelength overrun");
336 cs->rcvidx = 0;
337 return;
338 }
339 /* AMD interrupts on */
340 AmdIrqOn(cs);
341}
342
343
344static void
345Amd7930_fill_Dfifo(struct IsdnCardState *cs)
346{
347
348 WORD dtcrr, dtcrw, len, count;
349 BYTE txstat, dmr3;
350 BYTE *ptr, *deb_ptr;
351
352 if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
353 debugl1(cs, "Amd7930: fill_Dfifo");
354
355 if ((!cs->tx_skb) || (cs->tx_skb->len <= 0))
356 return;
357
358 dtcrw = 0;
359 if(!cs->dc.amd7930.tx_xmtlen)
360 /* new Frame */
361 len = dtcrw = cs->tx_skb->len;
362 /* continue frame */
363 else len = cs->dc.amd7930.tx_xmtlen;
364
365
366 /* AMD interrupts off */
367 AmdIrqOff(cs);
368
369 deb_ptr = ptr = cs->tx_skb->data;
370
371 /* while free place in tx-fifo available and data in sk-buffer */
372 txstat = 0x10;
373 while((txstat & 0x10) && (cs->tx_cnt < len)) {
374 wByteAMD(cs, 0x04, *ptr);
375 ptr++;
376 cs->tx_cnt++;
377 txstat= rByteAMD(cs, 0x07);
378 }
379 count = ptr - cs->tx_skb->data;
380 skb_pull(cs->tx_skb, count);
381
382
383 dtcrr = rWordAMD(cs, 0x85); // DTCR
384 dmr3 = rByteAMD(cs, 0x8E);
385
386 if (cs->debug & L1_DEB_ISAC) {
387 debugl1(cs, "Amd7930: fill_Dfifo, DMR3: 0x%02X, DTCR read: 0x%04X write: 0x%02X 0x%02X", dmr3, dtcrr, LOBYTE(dtcrw), HIBYTE(dtcrw));
388 }
389
390 /* writeing of dtcrw starts transmit */
391 if(!cs->dc.amd7930.tx_xmtlen) {
392 wWordAMD(cs, 0x85, dtcrw);
393 cs->dc.amd7930.tx_xmtlen = dtcrw;
394 }
395
396 if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
397 debugl1(cs, "Amd7930: fill_Dfifo dbusytimer running");
398 del_timer(&cs->dbusytimer);
399 }
400 init_timer(&cs->dbusytimer);
401 cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ) / 1000);
402 add_timer(&cs->dbusytimer);
403
404 if (cs->debug & L1_DEB_ISAC_FIFO) {
405 char *t = cs->dlog;
406
407 t += sprintf(t, "Amd7930: fill_Dfifo cnt: %d |", count);
408 QuickHex(t, deb_ptr, count);
409 debugl1(cs, cs->dlog);
410 }
411 /* AMD interrupts on */
412 AmdIrqOn(cs);
413}
414
415
416void Amd7930_interrupt(struct IsdnCardState *cs, BYTE irflags)
417{
418 BYTE dsr1, dsr2, lsr;
419 WORD der;
420
421 while (irflags)
422 {
423
424 dsr1 = rByteAMD(cs, 0x02);
425 der = rWordAMD(cs, 0x03);
426 dsr2 = rByteAMD(cs, 0x07);
427 lsr = rByteAMD(cs, 0xA1);
428
429 if (cs->debug & L1_DEB_ISAC)
430 debugl1(cs, "Amd7930: interrupt: flags: 0x%02X, DSR1: 0x%02X, DSR2: 0x%02X, LSR: 0x%02X, DER=0x%04X", irflags, dsr1, dsr2, lsr, der);
431
432 /* D error -> read DER and DSR2 bit 2 */
433 if (der || (dsr2 & 4)) {
434
435 if (cs->debug & L1_DEB_WARN)
436 debugl1(cs, "Amd7930: interrupt: D error DER=0x%04X", der);
437
438 /* RX, TX abort if collision detected */
439 if (der & 2) {
440 wByteAMD(cs, 0x21, 0xC2);
441 wByteAMD(cs, 0x21, 0x02);
442 if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
443 del_timer(&cs->dbusytimer);
444 if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
445 schedule_event(cs, D_CLEARBUSY);
446 /* restart frame */
447 if (cs->tx_skb) {
448 skb_push(cs->tx_skb, cs->tx_cnt);
449 cs->tx_cnt = 0;
450 cs->dc.amd7930.tx_xmtlen = 0;
451 Amd7930_fill_Dfifo(cs);
452 } else {
453 printk(KERN_WARNING "HiSax: Amd7930 D-Collision, no skb\n");
454 debugl1(cs, "Amd7930: interrupt: D-Collision, no skb");
455 }
456 }
457 /* remove damaged data from fifo */
458 Amd7930_empty_Dfifo(cs, 1);
459
460 if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
461 del_timer(&cs->dbusytimer);
462 if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
463 schedule_event(cs, D_CLEARBUSY);
464 /* restart TX-Frame */
465 if (cs->tx_skb) {
466 skb_push(cs->tx_skb, cs->tx_cnt);
467 cs->tx_cnt = 0;
468 cs->dc.amd7930.tx_xmtlen = 0;
469 Amd7930_fill_Dfifo(cs);
470 }
471 }
472
473 /* D TX FIFO empty -> fill */
474 if (irflags & 1) {
475 if (cs->debug & L1_DEB_ISAC)
476 debugl1(cs, "Amd7930: interrupt: clear Timer and fill D-TX-FIFO if data");
477
478 /* AMD interrupts off */
479 AmdIrqOff(cs);
480
481 if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
482 del_timer(&cs->dbusytimer);
483 if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
484 schedule_event(cs, D_CLEARBUSY);
485 if (cs->tx_skb) {
486 if (cs->tx_skb->len)
487 Amd7930_fill_Dfifo(cs);
488 }
489 /* AMD interrupts on */
490 AmdIrqOn(cs);
491 }
492
493
494 /* D RX FIFO full or tiny packet in Fifo -> empty */
495 if ((irflags & 2) || (dsr1 & 2)) {
496 if (cs->debug & L1_DEB_ISAC)
497 debugl1(cs, "Amd7930: interrupt: empty D-FIFO");
498 Amd7930_empty_Dfifo(cs, 0);
499 }
500
501
502 /* D-Frame transmit complete */
503 if (dsr1 & 64) {
504 if (cs->debug & L1_DEB_ISAC) {
505 debugl1(cs, "Amd7930: interrupt: transmit packet ready");
506 }
507 /* AMD interrupts off */
508 AmdIrqOff(cs);
509
510 if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
511 del_timer(&cs->dbusytimer);
512 if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
513 schedule_event(cs, D_CLEARBUSY);
514
515 if (cs->tx_skb) {
516 if (cs->debug & L1_DEB_ISAC)
517 debugl1(cs, "Amd7930: interrupt: TX-Packet ready, freeing skb");
518 dev_kfree_skb_irq(cs->tx_skb);
519 cs->tx_cnt = 0;
520 cs->dc.amd7930.tx_xmtlen=0;
521 cs->tx_skb = NULL;
522 }
523 if ((cs->tx_skb = skb_dequeue(&cs->sq))) {
524 if (cs->debug & L1_DEB_ISAC)
525 debugl1(cs, "Amd7930: interrupt: TX-Packet ready, next packet dequeued");
526 cs->tx_cnt = 0;
527 cs->dc.amd7930.tx_xmtlen=0;
528 Amd7930_fill_Dfifo(cs);
529 }
530 else
531 schedule_event(cs, D_XMTBUFREADY);
532 /* AMD interrupts on */
533 AmdIrqOn(cs);
534 }
535
536 /* LIU status interrupt -> read LSR, check statechanges */
537 if (lsr & 0x38) {
538 /* AMD interrupts off */
539 AmdIrqOff(cs);
540
541 if (cs->debug & L1_DEB_ISAC)
542 debugl1(cs, "Amd: interrupt: LSR=0x%02X, LIU is in state %d", lsr, ((lsr & 0x7) +2));
543
544 cs->dc.amd7930.ph_state = (lsr & 0x7) + 2;
545
546 schedule_event(cs, D_L1STATECHANGE);
547 /* AMD interrupts on */
548 AmdIrqOn(cs);
549 }
550
551 /* reads Interrupt-Register again. If there is a new interrupt-flag: restart handler */
552 irflags = rByteAMD(cs, 0x00);
553 }
554
555}
556
557static void
558Amd7930_l1hw(struct PStack *st, int pr, void *arg)
559{
560 struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
561 struct sk_buff *skb = arg;
562 u_long flags;
563
564 if (cs->debug & L1_DEB_ISAC)
565 debugl1(cs, "Amd7930: l1hw called, pr: 0x%04X", pr);
566
567 switch (pr) {
568 case (PH_DATA | REQUEST):
569 if (cs->debug & DEB_DLOG_HEX)
570 LogFrame(cs, skb->data, skb->len);
571 if (cs->debug & DEB_DLOG_VERBOSE)
572 dlogframe(cs, skb, 0);
573 spin_lock_irqsave(&cs->lock, flags);
574 if (cs->tx_skb) {
575 skb_queue_tail(&cs->sq, skb);
576#ifdef L2FRAME_DEBUG /* psa */
577 if (cs->debug & L1_DEB_LAPD)
578 Logl2Frame(cs, skb, "Amd7930: l1hw: PH_DATA Queued", 0);
579#endif
580 } else {
581 cs->tx_skb = skb;
582 cs->tx_cnt = 0;
583 cs->dc.amd7930.tx_xmtlen=0;
584#ifdef L2FRAME_DEBUG /* psa */
585 if (cs->debug & L1_DEB_LAPD)
586 Logl2Frame(cs, skb, "Amd7930: l1hw: PH_DATA", 0);
587#endif
588 Amd7930_fill_Dfifo(cs);
589 }
590 spin_unlock_irqrestore(&cs->lock, flags);
591 break;
592 case (PH_PULL | INDICATION):
593 spin_lock_irqsave(&cs->lock, flags);
594 if (cs->tx_skb) {
595 if (cs->debug & L1_DEB_WARN)
596 debugl1(cs, "Amd7930: l1hw: l2l1 tx_skb exist this shouldn't happen");
597 skb_queue_tail(&cs->sq, skb);
598 break;
599 }
600 if (cs->debug & DEB_DLOG_HEX)
601 LogFrame(cs, skb->data, skb->len);
602 if (cs->debug & DEB_DLOG_VERBOSE)
603 dlogframe(cs, skb, 0);
604 cs->tx_skb = skb;
605 cs->tx_cnt = 0;
606 cs->dc.amd7930.tx_xmtlen=0;
607#ifdef L2FRAME_DEBUG /* psa */
608 if (cs->debug & L1_DEB_LAPD)
609 Logl2Frame(cs, skb, "Amd7930: l1hw: PH_DATA_PULLED", 0);
610#endif
611 Amd7930_fill_Dfifo(cs);
612 spin_unlock_irqrestore(&cs->lock, flags);
613 break;
614 case (PH_PULL | REQUEST):
615#ifdef L2FRAME_DEBUG /* psa */
616 if (cs->debug & L1_DEB_LAPD)
617 debugl1(cs, "Amd7930: l1hw: -> PH_REQUEST_PULL, skb: %s", (cs->tx_skb)? "yes":"no");
618#endif
619 if (!cs->tx_skb) {
620 test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
621 st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
622 } else
623 test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
624 break;
625 case (HW_RESET | REQUEST):
626 spin_lock_irqsave(&cs->lock, flags);
627 if ((cs->dc.amd7930.ph_state == 8)) {
628 /* b-channels off, PH-AR cleared
629 * change to F3 */
630 Amd7930_ph_command(cs, 0x20, "HW_RESET REQEST"); //LMR1 bit 5
631 spin_unlock_irqrestore(&cs->lock, flags);
632 } else {
633 Amd7930_ph_command(cs, 0x40, "HW_RESET REQUEST");
634 cs->dc.amd7930.ph_state = 2;
635 spin_unlock_irqrestore(&cs->lock, flags);
636 Amd7930_new_ph(cs);
637 }
638 break;
639 case (HW_ENABLE | REQUEST):
640 cs->dc.amd7930.ph_state = 9;
641 Amd7930_new_ph(cs);
642 break;
643 case (HW_INFO3 | REQUEST):
644 // automatic
645 break;
646 case (HW_TESTLOOP | REQUEST):
647 /* not implemented yet */
648 break;
649 case (HW_DEACTIVATE | RESPONSE):
650 skb_queue_purge(&cs->rq);
651 skb_queue_purge(&cs->sq);
652 if (cs->tx_skb) {
653 dev_kfree_skb(cs->tx_skb);
654 cs->tx_skb = NULL;
655 }
656 if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
657 del_timer(&cs->dbusytimer);
658 if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
659 schedule_event(cs, D_CLEARBUSY);
660 break;
661 default:
662 if (cs->debug & L1_DEB_WARN)
663 debugl1(cs, "Amd7930: l1hw: unknown %04x", pr);
664 break;
665 }
666}
667
668void
669setstack_Amd7930(struct PStack *st, struct IsdnCardState *cs)
670{
671
672 if (cs->debug & L1_DEB_ISAC)
673 debugl1(cs, "Amd7930: setstack called");
674
675 st->l1.l1hw = Amd7930_l1hw;
676}
677
678
679void
680DC_Close_Amd7930(struct IsdnCardState *cs) {
681 if (cs->debug & L1_DEB_ISAC)
682 debugl1(cs, "Amd7930: DC_Close called");
683}
684
685
686static void
687dbusy_timer_handler(struct IsdnCardState *cs)
688{
689 u_long flags;
690 struct PStack *stptr;
691 WORD dtcr, der;
692 BYTE dsr1, dsr2;
693
694
695 if (cs->debug & L1_DEB_ISAC)
696 debugl1(cs, "Amd7930: dbusy_timer expired!");
697
698 if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
699 spin_lock_irqsave(&cs->lock, flags);
700 /* D Transmit Byte Count Register:
701 * Counts down packet's number of Bytes, 0 if packet ready */
702 dtcr = rWordAMD(cs, 0x85);
703 dsr1 = rByteAMD(cs, 0x02);
704 dsr2 = rByteAMD(cs, 0x07);
705 der = rWordAMD(cs, 0x03);
706
707 if (cs->debug & L1_DEB_ISAC)
708 debugl1(cs, "Amd7930: dbusy_timer_handler: DSR1=0x%02X, DSR2=0x%02X, DER=0x%04X, cs->tx_skb->len=%u, tx_stat=%u, dtcr=%u, cs->tx_cnt=%u", dsr1, dsr2, der, cs->tx_skb->len, cs->dc.amd7930.tx_xmtlen, dtcr, cs->tx_cnt);
709
710 if ((cs->dc.amd7930.tx_xmtlen - dtcr) < cs->tx_cnt) { /* D-Channel Busy */
711 test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags);
712 stptr = cs->stlist;
713 spin_unlock_irqrestore(&cs->lock, flags);
714 while (stptr != NULL) {
715 stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL);
716 stptr = stptr->next;
717 }
718
719 } else {
720 /* discard frame; reset transceiver */
721 test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags);
722 if (cs->tx_skb) {
723 dev_kfree_skb_any(cs->tx_skb);
724 cs->tx_cnt = 0;
725 cs->tx_skb = NULL;
726 cs->dc.amd7930.tx_xmtlen = 0;
727 } else {
728 printk(KERN_WARNING "HiSax: Amd7930: D-Channel Busy no skb\n");
729 debugl1(cs, "Amd7930: D-Channel Busy no skb");
730
731 }
732 /* Transmitter reset, abort transmit */
733 wByteAMD(cs, 0x21, 0x82);
734 wByteAMD(cs, 0x21, 0x02);
735 spin_unlock_irqrestore(&cs->lock, flags);
736 cs->irq_func(cs->irq, cs, NULL);
737
738 if (cs->debug & L1_DEB_ISAC)
739 debugl1(cs, "Amd7930: dbusy_timer_handler: Transmitter reset");
740 }
741 }
742}
743
744
745
746void __devinit
747Amd7930_init(struct IsdnCardState *cs)
748{
749 WORD *ptr;
750 BYTE cmd, cnt;
751
752 if (cs->debug & L1_DEB_ISAC)
753 debugl1(cs, "Amd7930: initamd called");
754
755 cs->dc.amd7930.tx_xmtlen = 0;
756 cs->dc.amd7930.old_state = 0;
757 cs->dc.amd7930.lmr1 = 0x40;
758 cs->dc.amd7930.ph_command = Amd7930_ph_command;
759 cs->setstack_d = setstack_Amd7930;
760 cs->DC_Close = DC_Close_Amd7930;
761
762 /* AMD Initialisation */
763 for (ptr = initAMD; *ptr != 0xFFFF; ) {
764 cmd = LOBYTE(*ptr);
765
766 /* read */
767 if (*ptr++ >= 0x100) {
768 if (cmd < 8)
769 /* setzt Register zurück */
770 rByteAMD(cs, cmd);
771 else {
772 wByteAMD(cs, 0x00, cmd);
773 for (cnt = *ptr++; cnt > 0; cnt--)
774 rByteAMD(cs, 0x01);
775 }
776 }
777 /* write */
778 else if (cmd < 8)
779 wByteAMD(cs, cmd, LOBYTE(*ptr++));
780
781 else {
782 wByteAMD(cs, 0x00, cmd);
783 for (cnt = *ptr++; cnt > 0; cnt--)
784 wByteAMD(cs, 0x01, LOBYTE(*ptr++));
785 }
786 }
787}
788
789void __devinit
790setup_Amd7930(struct IsdnCardState *cs)
791{
792 INIT_WORK(&cs->tqueue, (void *)(void *) Amd7930_bh, cs);
793 cs->dbusytimer.function = (void *) dbusy_timer_handler;
794 cs->dbusytimer.data = (long) cs;
795 init_timer(&cs->dbusytimer);
796}
diff --git a/drivers/isdn/hisax/amd7930_fn.h b/drivers/isdn/hisax/amd7930_fn.h
new file mode 100644
index 000000000000..e039c3a0f2a2
--- /dev/null
+++ b/drivers/isdn/hisax/amd7930_fn.h
@@ -0,0 +1,37 @@
1/* 2001/10/02
2 *
3 * gerdes_amd7930.h Header-file included by
4 * gerdes_amd7930.c
5 *
6 * Author Christoph Ersfeld <info@formula-n.de>
7 * Formula-n Europe AG (www.formula-n.com)
8 * previously Gerdes AG
9 *
10 *
11 * This file is (c) under GNU PUBLIC LICENSE
12 */
13
14
15
16
17#define BYTE unsigned char
18#define WORD unsigned int
19#define rByteAMD(cs, reg) cs->readisac(cs, reg)
20#define wByteAMD(cs, reg, val) cs->writeisac(cs, reg, val)
21#define rWordAMD(cs, reg) ReadWordAmd7930(cs, reg)
22#define wWordAMD(cs, reg, val) WriteWordAmd7930(cs, reg, val)
23#define HIBYTE(w) ((unsigned char)((w & 0xff00) / 256))
24#define LOBYTE(w) ((unsigned char)(w & 0x00ff))
25
26#define AmdIrqOff(cs) cs->dc.amd7930.setIrqMask(cs, 0)
27#define AmdIrqOn(cs) cs->dc.amd7930.setIrqMask(cs, 1)
28
29#define AMD_CR 0x00
30#define AMD_DR 0x01
31
32
33#define DBUSY_TIMER_VALUE 80
34
35extern void Amd7930_interrupt(struct IsdnCardState *, unsigned char);
36extern void Amd7930_init(struct IsdnCardState *);
37extern void setup_Amd7930(struct IsdnCardState *);
diff --git a/drivers/isdn/hisax/arcofi.c b/drivers/isdn/hisax/arcofi.c
new file mode 100644
index 000000000000..d30ce5b978c2
--- /dev/null
+++ b/drivers/isdn/hisax/arcofi.c
@@ -0,0 +1,134 @@
1/* $Id: arcofi.c,v 1.14.2.3 2004/01/13 14:31:24 keil Exp $
2 *
3 * Ansteuerung ARCOFI 2165
4 *
5 * Author Karsten Keil
6 * Copyright by Karsten Keil <keil@isdn4linux.de>
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 */
12
13#include "hisax.h"
14#include "isdnl1.h"
15#include "isac.h"
16#include "arcofi.h"
17
18#define ARCOFI_TIMER_VALUE 20
19
20static void
21add_arcofi_timer(struct IsdnCardState *cs) {
22 if (test_and_set_bit(FLG_ARCOFI_TIMER, &cs->HW_Flags)) {
23 del_timer(&cs->dc.isac.arcofitimer);
24 }
25 init_timer(&cs->dc.isac.arcofitimer);
26 cs->dc.isac.arcofitimer.expires = jiffies + ((ARCOFI_TIMER_VALUE * HZ)/1000);
27 add_timer(&cs->dc.isac.arcofitimer);
28}
29
30static void
31send_arcofi(struct IsdnCardState *cs) {
32 u_char val;
33
34 add_arcofi_timer(cs);
35 cs->dc.isac.mon_txp = 0;
36 cs->dc.isac.mon_txc = cs->dc.isac.arcofi_list->len;
37 memcpy(cs->dc.isac.mon_tx, cs->dc.isac.arcofi_list->msg, cs->dc.isac.mon_txc);
38 switch(cs->dc.isac.arcofi_bc) {
39 case 0: break;
40 case 1: cs->dc.isac.mon_tx[1] |= 0x40;
41 break;
42 default: break;
43 }
44 cs->dc.isac.mocr &= 0x0f;
45 cs->dc.isac.mocr |= 0xa0;
46 cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
47 val = cs->readisac(cs, ISAC_MOSR);
48 cs->writeisac(cs, ISAC_MOX1, cs->dc.isac.mon_tx[cs->dc.isac.mon_txp++]);
49 cs->dc.isac.mocr |= 0x10;
50 cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
51}
52
53int
54arcofi_fsm(struct IsdnCardState *cs, int event, void *data) {
55 if (cs->debug & L1_DEB_MONITOR) {
56 debugl1(cs, "arcofi state %d event %d", cs->dc.isac.arcofi_state, event);
57 }
58 if (event == ARCOFI_TIMEOUT) {
59 cs->dc.isac.arcofi_state = ARCOFI_NOP;
60 test_and_set_bit(FLG_ARCOFI_ERROR, &cs->HW_Flags);
61 wake_up(&cs->dc.isac.arcofi_wait);
62 return(1);
63 }
64 switch (cs->dc.isac.arcofi_state) {
65 case ARCOFI_NOP:
66 if (event == ARCOFI_START) {
67 cs->dc.isac.arcofi_list = data;
68 cs->dc.isac.arcofi_state = ARCOFI_TRANSMIT;
69 send_arcofi(cs);
70 }
71 break;
72 case ARCOFI_TRANSMIT:
73 if (event == ARCOFI_TX_END) {
74 if (cs->dc.isac.arcofi_list->receive) {
75 add_arcofi_timer(cs);
76 cs->dc.isac.arcofi_state = ARCOFI_RECEIVE;
77 } else {
78 if (cs->dc.isac.arcofi_list->next) {
79 cs->dc.isac.arcofi_list =
80 cs->dc.isac.arcofi_list->next;
81 send_arcofi(cs);
82 } else {
83 if (test_and_clear_bit(FLG_ARCOFI_TIMER, &cs->HW_Flags)) {
84 del_timer(&cs->dc.isac.arcofitimer);
85 }
86 cs->dc.isac.arcofi_state = ARCOFI_NOP;
87 wake_up(&cs->dc.isac.arcofi_wait);
88 }
89 }
90 }
91 break;
92 case ARCOFI_RECEIVE:
93 if (event == ARCOFI_RX_END) {
94 if (cs->dc.isac.arcofi_list->next) {
95 cs->dc.isac.arcofi_list =
96 cs->dc.isac.arcofi_list->next;
97 cs->dc.isac.arcofi_state = ARCOFI_TRANSMIT;
98 send_arcofi(cs);
99 } else {
100 if (test_and_clear_bit(FLG_ARCOFI_TIMER, &cs->HW_Flags)) {
101 del_timer(&cs->dc.isac.arcofitimer);
102 }
103 cs->dc.isac.arcofi_state = ARCOFI_NOP;
104 wake_up(&cs->dc.isac.arcofi_wait);
105 }
106 }
107 break;
108 default:
109 debugl1(cs, "Arcofi unknown state %x", cs->dc.isac.arcofi_state);
110 return(2);
111 }
112 return(0);
113}
114
115static void
116arcofi_timer(struct IsdnCardState *cs) {
117 arcofi_fsm(cs, ARCOFI_TIMEOUT, NULL);
118}
119
120void
121clear_arcofi(struct IsdnCardState *cs) {
122 if (test_and_clear_bit(FLG_ARCOFI_TIMER, &cs->HW_Flags)) {
123 del_timer(&cs->dc.isac.arcofitimer);
124 }
125}
126
127void
128init_arcofi(struct IsdnCardState *cs) {
129 cs->dc.isac.arcofitimer.function = (void *) arcofi_timer;
130 cs->dc.isac.arcofitimer.data = (long) cs;
131 init_timer(&cs->dc.isac.arcofitimer);
132 init_waitqueue_head(&cs->dc.isac.arcofi_wait);
133 test_and_set_bit(HW_ARCOFI, &cs->HW_Flags);
134}
diff --git a/drivers/isdn/hisax/arcofi.h b/drivers/isdn/hisax/arcofi.h
new file mode 100644
index 000000000000..00c44d3ce972
--- /dev/null
+++ b/drivers/isdn/hisax/arcofi.h
@@ -0,0 +1,27 @@
1/* $Id: arcofi.h,v 1.6.6.2 2001/09/23 22:24:46 kai Exp $
2 *
3 * Ansteuerung ARCOFI 2165
4 *
5 * Author Karsten Keil
6 * Copyright by Karsten Keil <keil@isdn4linux.de>
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 */
12
13#define ARCOFI_USE 1
14
15/* states */
16#define ARCOFI_NOP 0
17#define ARCOFI_TRANSMIT 1
18#define ARCOFI_RECEIVE 2
19/* events */
20#define ARCOFI_START 1
21#define ARCOFI_TX_END 2
22#define ARCOFI_RX_END 3
23#define ARCOFI_TIMEOUT 4
24
25extern int arcofi_fsm(struct IsdnCardState *cs, int event, void *data);
26extern void init_arcofi(struct IsdnCardState *cs);
27extern void clear_arcofi(struct IsdnCardState *cs);
diff --git a/drivers/isdn/hisax/asuscom.c b/drivers/isdn/hisax/asuscom.c
new file mode 100644
index 000000000000..7546e2e4a94e
--- /dev/null
+++ b/drivers/isdn/hisax/asuscom.c
@@ -0,0 +1,427 @@
1/* $Id: asuscom.c,v 1.14.2.4 2004/01/13 23:48:39 keil Exp $
2 *
3 * low level stuff for ASUSCOM NETWORK INC. ISDNLink cards
4 *
5 * Author Karsten Keil
6 * Copyright by Karsten Keil <keil@isdn4linux.de>
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 * Thanks to ASUSCOM NETWORK INC. Taiwan and Dynalink NL for information
12 *
13 */
14
15#include <linux/init.h>
16#include <linux/isapnp.h>
17#include "hisax.h"
18#include "isac.h"
19#include "ipac.h"
20#include "hscx.h"
21#include "isdnl1.h"
22
23extern const char *CardType[];
24
25const char *Asuscom_revision = "$Revision: 1.14.2.4 $";
26
27#define byteout(addr,val) outb(val,addr)
28#define bytein(addr) inb(addr)
29
30#define ASUS_ISAC 0
31#define ASUS_HSCX 1
32#define ASUS_ADR 2
33#define ASUS_CTRL_U7 3
34#define ASUS_CTRL_POTS 5
35
36#define ASUS_IPAC_ALE 0
37#define ASUS_IPAC_DATA 1
38
39#define ASUS_ISACHSCX 1
40#define ASUS_IPAC 2
41
42/* CARD_ADR (Write) */
43#define ASUS_RESET 0x80 /* Bit 7 Reset-Leitung */
44
45static inline u_char
46readreg(unsigned int ale, unsigned int adr, u_char off)
47{
48 register u_char ret;
49
50 byteout(ale, off);
51 ret = bytein(adr);
52 return (ret);
53}
54
55static inline void
56readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
57{
58 byteout(ale, off);
59 insb(adr, data, size);
60}
61
62
63static inline void
64writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
65{
66 byteout(ale, off);
67 byteout(adr, data);
68}
69
70static inline void
71writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
72{
73 byteout(ale, off);
74 outsb(adr, data, size);
75}
76
77/* Interface functions */
78
79static u_char
80ReadISAC(struct IsdnCardState *cs, u_char offset)
81{
82 return (readreg(cs->hw.asus.adr, cs->hw.asus.isac, offset));
83}
84
85static void
86WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
87{
88 writereg(cs->hw.asus.adr, cs->hw.asus.isac, offset, value);
89}
90
91static void
92ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
93{
94 readfifo(cs->hw.asus.adr, cs->hw.asus.isac, 0, data, size);
95}
96
97static void
98WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
99{
100 writefifo(cs->hw.asus.adr, cs->hw.asus.isac, 0, data, size);
101}
102
103static u_char
104ReadISAC_IPAC(struct IsdnCardState *cs, u_char offset)
105{
106 return (readreg(cs->hw.asus.adr, cs->hw.asus.isac, offset|0x80));
107}
108
109static void
110WriteISAC_IPAC(struct IsdnCardState *cs, u_char offset, u_char value)
111{
112 writereg(cs->hw.asus.adr, cs->hw.asus.isac, offset|0x80, value);
113}
114
115static void
116ReadISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size)
117{
118 readfifo(cs->hw.asus.adr, cs->hw.asus.isac, 0x80, data, size);
119}
120
121static void
122WriteISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size)
123{
124 writefifo(cs->hw.asus.adr, cs->hw.asus.isac, 0x80, data, size);
125}
126
127static u_char
128ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
129{
130 return (readreg(cs->hw.asus.adr,
131 cs->hw.asus.hscx, offset + (hscx ? 0x40 : 0)));
132}
133
134static void
135WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
136{
137 writereg(cs->hw.asus.adr,
138 cs->hw.asus.hscx, offset + (hscx ? 0x40 : 0), value);
139}
140
141/*
142 * fast interrupt HSCX stuff goes here
143 */
144
145#define READHSCX(cs, nr, reg) readreg(cs->hw.asus.adr, \
146 cs->hw.asus.hscx, reg + (nr ? 0x40 : 0))
147#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.asus.adr, \
148 cs->hw.asus.hscx, reg + (nr ? 0x40 : 0), data)
149
150#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.asus.adr, \
151 cs->hw.asus.hscx, (nr ? 0x40 : 0), ptr, cnt)
152
153#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.asus.adr, \
154 cs->hw.asus.hscx, (nr ? 0x40 : 0), ptr, cnt)
155
156#include "hscx_irq.c"
157
158static irqreturn_t
159asuscom_interrupt(int intno, void *dev_id, struct pt_regs *regs)
160{
161 struct IsdnCardState *cs = dev_id;
162 u_char val;
163 u_long flags;
164
165 spin_lock_irqsave(&cs->lock, flags);
166 val = readreg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_ISTA + 0x40);
167 Start_HSCX:
168 if (val)
169 hscx_int_main(cs, val);
170 val = readreg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_ISTA);
171 Start_ISAC:
172 if (val)
173 isac_interrupt(cs, val);
174 val = readreg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_ISTA + 0x40);
175 if (val) {
176 if (cs->debug & L1_DEB_HSCX)
177 debugl1(cs, "HSCX IntStat after IntRoutine");
178 goto Start_HSCX;
179 }
180 val = readreg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_ISTA);
181 if (val) {
182 if (cs->debug & L1_DEB_ISAC)
183 debugl1(cs, "ISAC IntStat after IntRoutine");
184 goto Start_ISAC;
185 }
186 writereg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_MASK, 0xFF);
187 writereg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_MASK + 0x40, 0xFF);
188 writereg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_MASK, 0xFF);
189 writereg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_MASK, 0x0);
190 writereg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_MASK, 0x0);
191 writereg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_MASK + 0x40, 0x0);
192 spin_unlock_irqrestore(&cs->lock, flags);
193 return IRQ_HANDLED;
194}
195
196static irqreturn_t
197asuscom_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs)
198{
199 struct IsdnCardState *cs = dev_id;
200 u_char ista, val, icnt = 5;
201 u_long flags;
202
203 spin_lock_irqsave(&cs->lock, flags);
204 ista = readreg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_ISTA);
205Start_IPAC:
206 if (cs->debug & L1_DEB_IPAC)
207 debugl1(cs, "IPAC ISTA %02X", ista);
208 if (ista & 0x0f) {
209 val = readreg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_ISTA + 0x40);
210 if (ista & 0x01)
211 val |= 0x01;
212 if (ista & 0x04)
213 val |= 0x02;
214 if (ista & 0x08)
215 val |= 0x04;
216 if (val)
217 hscx_int_main(cs, val);
218 }
219 if (ista & 0x20) {
220 val = 0xfe & readreg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_ISTA | 0x80);
221 if (val) {
222 isac_interrupt(cs, val);
223 }
224 }
225 if (ista & 0x10) {
226 val = 0x01;
227 isac_interrupt(cs, val);
228 }
229 ista = readreg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_ISTA);
230 if ((ista & 0x3f) && icnt) {
231 icnt--;
232 goto Start_IPAC;
233 }
234 if (!icnt)
235 printk(KERN_WARNING "ASUS IRQ LOOP\n");
236 writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_MASK, 0xFF);
237 writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_MASK, 0xC0);
238 spin_unlock_irqrestore(&cs->lock, flags);
239 return IRQ_HANDLED;
240}
241
242void
243release_io_asuscom(struct IsdnCardState *cs)
244{
245 int bytecnt = 8;
246
247 if (cs->hw.asus.cfg_reg)
248 release_region(cs->hw.asus.cfg_reg, bytecnt);
249}
250
251static void
252reset_asuscom(struct IsdnCardState *cs)
253{
254 if (cs->subtyp == ASUS_IPAC)
255 writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_POTA2, 0x20);
256 else
257 byteout(cs->hw.asus.adr, ASUS_RESET); /* Reset On */
258 mdelay(10);
259 if (cs->subtyp == ASUS_IPAC)
260 writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_POTA2, 0x0);
261 else
262 byteout(cs->hw.asus.adr, 0); /* Reset Off */
263 mdelay(10);
264 if (cs->subtyp == ASUS_IPAC) {
265 writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_CONF, 0x0);
266 writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_ACFG, 0xff);
267 writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_AOE, 0x0);
268 writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_MASK, 0xc0);
269 writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_PCFG, 0x12);
270 }
271}
272
273static int
274Asus_card_msg(struct IsdnCardState *cs, int mt, void *arg)
275{
276 u_long flags;
277
278 switch (mt) {
279 case CARD_RESET:
280 spin_lock_irqsave(&cs->lock, flags);
281 reset_asuscom(cs);
282 spin_unlock_irqrestore(&cs->lock, flags);
283 return(0);
284 case CARD_RELEASE:
285 release_io_asuscom(cs);
286 return(0);
287 case CARD_INIT:
288 spin_lock_irqsave(&cs->lock, flags);
289 cs->debug |= L1_DEB_IPAC;
290 inithscxisac(cs, 3);
291 spin_unlock_irqrestore(&cs->lock, flags);
292 return(0);
293 case CARD_TEST:
294 return(0);
295 }
296 return(0);
297}
298
299#ifdef __ISAPNP__
300static struct isapnp_device_id asus_ids[] __initdata = {
301 { ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1688),
302 ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1688),
303 (unsigned long) "Asus1688 PnP" },
304 { ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1690),
305 ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1690),
306 (unsigned long) "Asus1690 PnP" },
307 { ISAPNP_VENDOR('S', 'I', 'E'), ISAPNP_FUNCTION(0x0020),
308 ISAPNP_VENDOR('S', 'I', 'E'), ISAPNP_FUNCTION(0x0020),
309 (unsigned long) "Isurf2 PnP" },
310 { ISAPNP_VENDOR('E', 'L', 'F'), ISAPNP_FUNCTION(0x0000),
311 ISAPNP_VENDOR('E', 'L', 'F'), ISAPNP_FUNCTION(0x0000),
312 (unsigned long) "Iscas TE320" },
313 { 0, }
314};
315
316static struct isapnp_device_id *ipid __initdata = &asus_ids[0];
317static struct pnp_card *pnp_c __devinitdata = NULL;
318#endif
319
320int __init
321setup_asuscom(struct IsdnCard *card)
322{
323 int bytecnt;
324 struct IsdnCardState *cs = card->cs;
325 u_char val;
326 char tmp[64];
327
328 strcpy(tmp, Asuscom_revision);
329 printk(KERN_INFO "HiSax: Asuscom ISDNLink driver Rev. %s\n", HiSax_getrev(tmp));
330 if (cs->typ != ISDN_CTYPE_ASUSCOM)
331 return (0);
332#ifdef __ISAPNP__
333 if (!card->para[1] && isapnp_present()) {
334 struct pnp_dev *pnp_d;
335 while(ipid->card_vendor) {
336 if ((pnp_c = pnp_find_card(ipid->card_vendor,
337 ipid->card_device, pnp_c))) {
338 pnp_d = NULL;
339 if ((pnp_d = pnp_find_dev(pnp_c,
340 ipid->vendor, ipid->function, pnp_d))) {
341 int err;
342
343 printk(KERN_INFO "HiSax: %s detected\n",
344 (char *)ipid->driver_data);
345 pnp_disable_dev(pnp_d);
346 err = pnp_activate_dev(pnp_d);
347 if (err<0) {
348 printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
349 __FUNCTION__, err);
350 return(0);
351 }
352 card->para[1] = pnp_port_start(pnp_d, 0);
353 card->para[0] = pnp_irq(pnp_d, 0);
354 if (!card->para[0] || !card->para[1]) {
355 printk(KERN_ERR "AsusPnP:some resources are missing %ld/%lx\n",
356 card->para[0], card->para[1]);
357 pnp_disable_dev(pnp_d);
358 return(0);
359 }
360 break;
361 } else {
362 printk(KERN_ERR "AsusPnP: PnP error card found, no device\n");
363 }
364 }
365 ipid++;
366 pnp_c = NULL;
367 }
368 if (!ipid->card_vendor) {
369 printk(KERN_INFO "AsusPnP: no ISAPnP card found\n");
370 return(0);
371 }
372 }
373#endif
374 bytecnt = 8;
375 cs->hw.asus.cfg_reg = card->para[1];
376 cs->irq = card->para[0];
377 if (!request_region(cs->hw.asus.cfg_reg, bytecnt, "asuscom isdn")) {
378 printk(KERN_WARNING
379 "HiSax: %s config port %x-%x already in use\n",
380 CardType[card->typ],
381 cs->hw.asus.cfg_reg,
382 cs->hw.asus.cfg_reg + bytecnt);
383 return (0);
384 }
385 printk(KERN_INFO "ISDNLink: defined at 0x%x IRQ %d\n",
386 cs->hw.asus.cfg_reg, cs->irq);
387 setup_isac(cs);
388 cs->BC_Read_Reg = &ReadHSCX;
389 cs->BC_Write_Reg = &WriteHSCX;
390 cs->BC_Send_Data = &hscx_fill_fifo;
391 cs->cardmsg = &Asus_card_msg;
392 val = readreg(cs->hw.asus.cfg_reg + ASUS_IPAC_ALE,
393 cs->hw.asus.cfg_reg + ASUS_IPAC_DATA, IPAC_ID);
394 if ((val == 1) || (val == 2)) {
395 cs->subtyp = ASUS_IPAC;
396 cs->hw.asus.adr = cs->hw.asus.cfg_reg + ASUS_IPAC_ALE;
397 cs->hw.asus.isac = cs->hw.asus.cfg_reg + ASUS_IPAC_DATA;
398 cs->hw.asus.hscx = cs->hw.asus.cfg_reg + ASUS_IPAC_DATA;
399 test_and_set_bit(HW_IPAC, &cs->HW_Flags);
400 cs->readisac = &ReadISAC_IPAC;
401 cs->writeisac = &WriteISAC_IPAC;
402 cs->readisacfifo = &ReadISACfifo_IPAC;
403 cs->writeisacfifo = &WriteISACfifo_IPAC;
404 cs->irq_func = &asuscom_interrupt_ipac;
405 printk(KERN_INFO "Asus: IPAC version %x\n", val);
406 } else {
407 cs->subtyp = ASUS_ISACHSCX;
408 cs->hw.asus.adr = cs->hw.asus.cfg_reg + ASUS_ADR;
409 cs->hw.asus.isac = cs->hw.asus.cfg_reg + ASUS_ISAC;
410 cs->hw.asus.hscx = cs->hw.asus.cfg_reg + ASUS_HSCX;
411 cs->hw.asus.u7 = cs->hw.asus.cfg_reg + ASUS_CTRL_U7;
412 cs->hw.asus.pots = cs->hw.asus.cfg_reg + ASUS_CTRL_POTS;
413 cs->readisac = &ReadISAC;
414 cs->writeisac = &WriteISAC;
415 cs->readisacfifo = &ReadISACfifo;
416 cs->writeisacfifo = &WriteISACfifo;
417 cs->irq_func = &asuscom_interrupt;
418 ISACVersion(cs, "ISDNLink:");
419 if (HscxVersion(cs, "ISDNLink:")) {
420 printk(KERN_WARNING
421 "ISDNLink: wrong HSCX versions check IO address\n");
422 release_io_asuscom(cs);
423 return (0);
424 }
425 }
426 return (1);
427}
diff --git a/drivers/isdn/hisax/avm_a1.c b/drivers/isdn/hisax/avm_a1.c
new file mode 100644
index 000000000000..8f028d42fd2f
--- /dev/null
+++ b/drivers/isdn/hisax/avm_a1.c
@@ -0,0 +1,317 @@
1/* $Id: avm_a1.c,v 2.15.2.4 2004/01/13 21:46:03 keil Exp $
2 *
3 * low level stuff for AVM A1 (Fritz) isdn cards
4 *
5 * Author Karsten Keil
6 * Copyright by Karsten Keil <keil@isdn4linux.de>
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 */
12
13#include <linux/init.h>
14#include "hisax.h"
15#include "isac.h"
16#include "hscx.h"
17#include "isdnl1.h"
18
19extern const char *CardType[];
20static const char *avm_revision = "$Revision: 2.15.2.4 $";
21
22#define AVM_A1_STAT_ISAC 0x01
23#define AVM_A1_STAT_HSCX 0x02
24#define AVM_A1_STAT_TIMER 0x04
25
26#define byteout(addr,val) outb(val,addr)
27#define bytein(addr) inb(addr)
28
29static inline u_char
30readreg(unsigned int adr, u_char off)
31{
32 return (bytein(adr + off));
33}
34
35static inline void
36writereg(unsigned int adr, u_char off, u_char data)
37{
38 byteout(adr + off, data);
39}
40
41
42static inline void
43read_fifo(unsigned int adr, u_char * data, int size)
44{
45 insb(adr, data, size);
46}
47
48static void
49write_fifo(unsigned int adr, u_char * data, int size)
50{
51 outsb(adr, data, size);
52}
53
54/* Interface functions */
55
56static u_char
57ReadISAC(struct IsdnCardState *cs, u_char offset)
58{
59 return (readreg(cs->hw.avm.isac, offset));
60}
61
62static void
63WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
64{
65 writereg(cs->hw.avm.isac, offset, value);
66}
67
68static void
69ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
70{
71 read_fifo(cs->hw.avm.isacfifo, data, size);
72}
73
74static void
75WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
76{
77 write_fifo(cs->hw.avm.isacfifo, data, size);
78}
79
80static u_char
81ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
82{
83 return (readreg(cs->hw.avm.hscx[hscx], offset));
84}
85
86static void
87WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
88{
89 writereg(cs->hw.avm.hscx[hscx], offset, value);
90}
91
92/*
93 * fast interrupt HSCX stuff goes here
94 */
95
96#define READHSCX(cs, nr, reg) readreg(cs->hw.avm.hscx[nr], reg)
97#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.avm.hscx[nr], reg, data)
98#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo(cs->hw.avm.hscxfifo[nr], ptr, cnt)
99#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo(cs->hw.avm.hscxfifo[nr], ptr, cnt)
100
101#include "hscx_irq.c"
102
103static irqreturn_t
104avm_a1_interrupt(int intno, void *dev_id, struct pt_regs *regs)
105{
106 struct IsdnCardState *cs = dev_id;
107 u_char val, sval;
108 u_long flags;
109
110 spin_lock_irqsave(&cs->lock, flags);
111 while (((sval = bytein(cs->hw.avm.cfg_reg)) & 0xf) != 0x7) {
112 if (!(sval & AVM_A1_STAT_TIMER)) {
113 byteout(cs->hw.avm.cfg_reg, 0x1E);
114 sval = bytein(cs->hw.avm.cfg_reg);
115 } else if (cs->debug & L1_DEB_INTSTAT)
116 debugl1(cs, "avm IntStatus %x", sval);
117 if (!(sval & AVM_A1_STAT_HSCX)) {
118 val = readreg(cs->hw.avm.hscx[1], HSCX_ISTA);
119 if (val)
120 hscx_int_main(cs, val);
121 }
122 if (!(sval & AVM_A1_STAT_ISAC)) {
123 val = readreg(cs->hw.avm.isac, ISAC_ISTA);
124 if (val)
125 isac_interrupt(cs, val);
126 }
127 }
128 writereg(cs->hw.avm.hscx[0], HSCX_MASK, 0xFF);
129 writereg(cs->hw.avm.hscx[1], HSCX_MASK, 0xFF);
130 writereg(cs->hw.avm.isac, ISAC_MASK, 0xFF);
131 writereg(cs->hw.avm.isac, ISAC_MASK, 0x0);
132 writereg(cs->hw.avm.hscx[0], HSCX_MASK, 0x0);
133 writereg(cs->hw.avm.hscx[1], HSCX_MASK, 0x0);
134 spin_unlock_irqrestore(&cs->lock, flags);
135 return IRQ_HANDLED;
136}
137
138inline static void
139release_ioregs(struct IsdnCardState *cs, int mask)
140{
141 release_region(cs->hw.avm.cfg_reg, 8);
142 if (mask & 1)
143 release_region(cs->hw.avm.isac + 32, 32);
144 if (mask & 2)
145 release_region(cs->hw.avm.isacfifo, 1);
146 if (mask & 4)
147 release_region(cs->hw.avm.hscx[0] + 32, 32);
148 if (mask & 8)
149 release_region(cs->hw.avm.hscxfifo[0], 1);
150 if (mask & 0x10)
151 release_region(cs->hw.avm.hscx[1] + 32, 32);
152 if (mask & 0x20)
153 release_region(cs->hw.avm.hscxfifo[1], 1);
154}
155
156static int
157AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
158{
159 u_long flags;
160
161 switch (mt) {
162 case CARD_RESET:
163 return(0);
164 case CARD_RELEASE:
165 release_ioregs(cs, 0x3f);
166 return(0);
167 case CARD_INIT:
168 spin_lock_irqsave(&cs->lock, flags);
169 inithscxisac(cs, 1);
170 byteout(cs->hw.avm.cfg_reg, 0x16);
171 byteout(cs->hw.avm.cfg_reg, 0x1E);
172 inithscxisac(cs, 2);
173 spin_unlock_irqrestore(&cs->lock, flags);
174 return(0);
175 case CARD_TEST:
176 return(0);
177 }
178 return(0);
179}
180
181int __init
182setup_avm_a1(struct IsdnCard *card)
183{
184 u_char val;
185 struct IsdnCardState *cs = card->cs;
186 char tmp[64];
187
188 strcpy(tmp, avm_revision);
189 printk(KERN_INFO "HiSax: AVM driver Rev. %s\n", HiSax_getrev(tmp));
190 if (cs->typ != ISDN_CTYPE_A1)
191 return (0);
192
193 cs->hw.avm.cfg_reg = card->para[1] + 0x1800;
194 cs->hw.avm.isac = card->para[1] + 0x1400 - 0x20;
195 cs->hw.avm.hscx[0] = card->para[1] + 0x400 - 0x20;
196 cs->hw.avm.hscx[1] = card->para[1] + 0xc00 - 0x20;
197 cs->hw.avm.isacfifo = card->para[1] + 0x1000;
198 cs->hw.avm.hscxfifo[0] = card->para[1];
199 cs->hw.avm.hscxfifo[1] = card->para[1] + 0x800;
200 cs->irq = card->para[0];
201 if (!request_region(cs->hw.avm.cfg_reg, 8, "avm cfg")) {
202 printk(KERN_WARNING
203 "HiSax: %s config port %x-%x already in use\n",
204 CardType[card->typ],
205 cs->hw.avm.cfg_reg,
206 cs->hw.avm.cfg_reg + 8);
207 return (0);
208 }
209 if (!request_region(cs->hw.avm.isac + 32, 32, "HiSax isac")) {
210 printk(KERN_WARNING
211 "HiSax: %s isac ports %x-%x already in use\n",
212 CardType[cs->typ],
213 cs->hw.avm.isac + 32,
214 cs->hw.avm.isac + 64);
215 release_ioregs(cs, 0);
216 return (0);
217 }
218 if (!request_region(cs->hw.avm.isacfifo, 1, "HiSax isac fifo")) {
219 printk(KERN_WARNING
220 "HiSax: %s isac fifo port %x already in use\n",
221 CardType[cs->typ],
222 cs->hw.avm.isacfifo);
223 release_ioregs(cs, 1);
224 return (0);
225 }
226 if (!request_region(cs->hw.avm.hscx[0] + 32, 32, "HiSax hscx A")) {
227 printk(KERN_WARNING
228 "HiSax: %s hscx A ports %x-%x already in use\n",
229 CardType[cs->typ],
230 cs->hw.avm.hscx[0] + 32,
231 cs->hw.avm.hscx[0] + 64);
232 release_ioregs(cs, 3);
233 return (0);
234 }
235 if (!request_region(cs->hw.avm.hscxfifo[0], 1, "HiSax hscx A fifo")) {
236 printk(KERN_WARNING
237 "HiSax: %s hscx A fifo port %x already in use\n",
238 CardType[cs->typ],
239 cs->hw.avm.hscxfifo[0]);
240 release_ioregs(cs, 7);
241 return (0);
242 }
243 if (!request_region(cs->hw.avm.hscx[1] + 32, 32, "HiSax hscx B")) {
244 printk(KERN_WARNING
245 "HiSax: %s hscx B ports %x-%x already in use\n",
246 CardType[cs->typ],
247 cs->hw.avm.hscx[1] + 32,
248 cs->hw.avm.hscx[1] + 64);
249 release_ioregs(cs, 0xf);
250 return (0);
251 }
252 if (!request_region(cs->hw.avm.hscxfifo[1], 1, "HiSax hscx B fifo")) {
253 printk(KERN_WARNING
254 "HiSax: %s hscx B fifo port %x already in use\n",
255 CardType[cs->typ],
256 cs->hw.avm.hscxfifo[1]);
257 release_ioregs(cs, 0x1f);
258 return (0);
259 }
260 byteout(cs->hw.avm.cfg_reg, 0x0);
261 HZDELAY(HZ / 5 + 1);
262 byteout(cs->hw.avm.cfg_reg, 0x1);
263 HZDELAY(HZ / 5 + 1);
264 byteout(cs->hw.avm.cfg_reg, 0x0);
265 HZDELAY(HZ / 5 + 1);
266 val = cs->irq;
267 if (val == 9)
268 val = 2;
269 byteout(cs->hw.avm.cfg_reg + 1, val);
270 HZDELAY(HZ / 5 + 1);
271 byteout(cs->hw.avm.cfg_reg, 0x0);
272 HZDELAY(HZ / 5 + 1);
273
274 val = bytein(cs->hw.avm.cfg_reg);
275 printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
276 cs->hw.avm.cfg_reg, val);
277 val = bytein(cs->hw.avm.cfg_reg + 3);
278 printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
279 cs->hw.avm.cfg_reg + 3, val);
280 val = bytein(cs->hw.avm.cfg_reg + 2);
281 printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
282 cs->hw.avm.cfg_reg + 2, val);
283 val = bytein(cs->hw.avm.cfg_reg);
284 printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
285 cs->hw.avm.cfg_reg, val);
286
287 printk(KERN_INFO
288 "HiSax: %s config irq:%d cfg:0x%X\n",
289 CardType[cs->typ], cs->irq,
290 cs->hw.avm.cfg_reg);
291 printk(KERN_INFO
292 "HiSax: isac:0x%X/0x%X\n",
293 cs->hw.avm.isac + 32, cs->hw.avm.isacfifo);
294 printk(KERN_INFO
295 "HiSax: hscx A:0x%X/0x%X hscx B:0x%X/0x%X\n",
296 cs->hw.avm.hscx[0] + 32, cs->hw.avm.hscxfifo[0],
297 cs->hw.avm.hscx[1] + 32, cs->hw.avm.hscxfifo[1]);
298
299 cs->readisac = &ReadISAC;
300 cs->writeisac = &WriteISAC;
301 cs->readisacfifo = &ReadISACfifo;
302 cs->writeisacfifo = &WriteISACfifo;
303 cs->BC_Read_Reg = &ReadHSCX;
304 cs->BC_Write_Reg = &WriteHSCX;
305 cs->BC_Send_Data = &hscx_fill_fifo;
306 setup_isac(cs);
307 cs->cardmsg = &AVM_card_msg;
308 cs->irq_func = &avm_a1_interrupt;
309 ISACVersion(cs, "AVM A1:");
310 if (HscxVersion(cs, "AVM A1:")) {
311 printk(KERN_WARNING
312 "AVM A1: wrong HSCX versions check IO address\n");
313 release_ioregs(cs, 0x3f);
314 return (0);
315 }
316 return (1);
317}
diff --git a/drivers/isdn/hisax/avm_a1p.c b/drivers/isdn/hisax/avm_a1p.c
new file mode 100644
index 000000000000..d643bb32ad09
--- /dev/null
+++ b/drivers/isdn/hisax/avm_a1p.c
@@ -0,0 +1,268 @@
1/* $Id: avm_a1p.c,v 2.9.2.5 2004/01/24 20:47:19 keil Exp $
2 *
3 * low level stuff for the following AVM cards:
4 * A1 PCMCIA
5 * FRITZ!Card PCMCIA
6 * FRITZ!Card PCMCIA 2.0
7 *
8 * Author Carsten Paeth
9 * Copyright by Carsten Paeth <calle@calle.de>
10 *
11 * This software may be used and distributed according to the terms
12 * of the GNU General Public License, incorporated herein by reference.
13 *
14 */
15
16#include <linux/init.h>
17#include "hisax.h"
18#include "isac.h"
19#include "hscx.h"
20#include "isdnl1.h"
21
22/* register offsets */
23#define ADDRREG_OFFSET 0x02
24#define DATAREG_OFFSET 0x03
25#define ASL0_OFFSET 0x04
26#define ASL1_OFFSET 0x05
27#define MODREG_OFFSET 0x06
28#define VERREG_OFFSET 0x07
29
30/* address offsets */
31#define ISAC_FIFO_OFFSET 0x00
32#define ISAC_REG_OFFSET 0x20
33#define HSCX_CH_DIFF 0x40
34#define HSCX_FIFO_OFFSET 0x80
35#define HSCX_REG_OFFSET 0xa0
36
37/* read bits ASL0 */
38#define ASL0_R_TIMER 0x10 /* active low */
39#define ASL0_R_ISAC 0x20 /* active low */
40#define ASL0_R_HSCX 0x40 /* active low */
41#define ASL0_R_TESTBIT 0x80
42#define ASL0_R_IRQPENDING (ASL0_R_ISAC|ASL0_R_HSCX|ASL0_R_TIMER)
43
44/* write bits ASL0 */
45#define ASL0_W_RESET 0x01
46#define ASL0_W_TDISABLE 0x02
47#define ASL0_W_TRESET 0x04
48#define ASL0_W_IRQENABLE 0x08
49#define ASL0_W_TESTBIT 0x80
50
51/* write bits ASL1 */
52#define ASL1_W_LED0 0x10
53#define ASL1_W_LED1 0x20
54#define ASL1_W_ENABLE_S0 0xC0
55
56#define byteout(addr,val) outb(val,addr)
57#define bytein(addr) inb(addr)
58
59static const char *avm_revision = "$Revision: 2.9.2.5 $";
60
61static inline u_char
62ReadISAC(struct IsdnCardState *cs, u_char offset)
63{
64 u_char ret;
65
66 offset -= 0x20;
67 byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET,ISAC_REG_OFFSET+offset);
68 ret = bytein(cs->hw.avm.cfg_reg+DATAREG_OFFSET);
69 return ret;
70}
71
72static inline void
73WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
74{
75 offset -= 0x20;
76 byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET,ISAC_REG_OFFSET+offset);
77 byteout(cs->hw.avm.cfg_reg+DATAREG_OFFSET, value);
78}
79
80static inline void
81ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
82{
83 byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET,ISAC_FIFO_OFFSET);
84 insb(cs->hw.avm.cfg_reg+DATAREG_OFFSET, data, size);
85}
86
87static inline void
88WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
89{
90 byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET,ISAC_FIFO_OFFSET);
91 outsb(cs->hw.avm.cfg_reg+DATAREG_OFFSET, data, size);
92}
93
94static inline u_char
95ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
96{
97 u_char ret;
98
99 offset -= 0x20;
100 byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET,
101 HSCX_REG_OFFSET+hscx*HSCX_CH_DIFF+offset);
102 ret = bytein(cs->hw.avm.cfg_reg+DATAREG_OFFSET);
103 return ret;
104}
105
106static inline void
107WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
108{
109 offset -= 0x20;
110 byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET,
111 HSCX_REG_OFFSET+hscx*HSCX_CH_DIFF+offset);
112 byteout(cs->hw.avm.cfg_reg+DATAREG_OFFSET, value);
113}
114
115static inline void
116ReadHSCXfifo(struct IsdnCardState *cs, int hscx, u_char * data, int size)
117{
118 byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET,
119 HSCX_FIFO_OFFSET+hscx*HSCX_CH_DIFF);
120 insb(cs->hw.avm.cfg_reg+DATAREG_OFFSET, data, size);
121}
122
123static inline void
124WriteHSCXfifo(struct IsdnCardState *cs, int hscx, u_char * data, int size)
125{
126 byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET,
127 HSCX_FIFO_OFFSET+hscx*HSCX_CH_DIFF);
128 outsb(cs->hw.avm.cfg_reg+DATAREG_OFFSET, data, size);
129}
130
131/*
132 * fast interrupt HSCX stuff goes here
133 */
134
135#define READHSCX(cs, nr, reg) ReadHSCX(cs, nr, reg)
136#define WRITEHSCX(cs, nr, reg, data) WriteHSCX(cs, nr, reg, data)
137#define READHSCXFIFO(cs, nr, ptr, cnt) ReadHSCXfifo(cs, nr, ptr, cnt)
138#define WRITEHSCXFIFO(cs, nr, ptr, cnt) WriteHSCXfifo(cs, nr, ptr, cnt)
139
140#include "hscx_irq.c"
141
142static irqreturn_t
143avm_a1p_interrupt(int intno, void *dev_id, struct pt_regs *regs)
144{
145 struct IsdnCardState *cs = dev_id;
146 u_char val, sval;
147 u_long flags;
148
149 spin_lock_irqsave(&cs->lock, flags);
150 while ((sval = (~bytein(cs->hw.avm.cfg_reg+ASL0_OFFSET) & ASL0_R_IRQPENDING))) {
151 if (cs->debug & L1_DEB_INTSTAT)
152 debugl1(cs, "avm IntStatus %x", sval);
153 if (sval & ASL0_R_HSCX) {
154 val = ReadHSCX(cs, 1, HSCX_ISTA);
155 if (val)
156 hscx_int_main(cs, val);
157 }
158 if (sval & ASL0_R_ISAC) {
159 val = ReadISAC(cs, ISAC_ISTA);
160 if (val)
161 isac_interrupt(cs, val);
162 }
163 }
164 WriteHSCX(cs, 0, HSCX_MASK, 0xff);
165 WriteHSCX(cs, 1, HSCX_MASK, 0xff);
166 WriteISAC(cs, ISAC_MASK, 0xff);
167 WriteISAC(cs, ISAC_MASK, 0x00);
168 WriteHSCX(cs, 0, HSCX_MASK, 0x00);
169 WriteHSCX(cs, 1, HSCX_MASK, 0x00);
170 spin_unlock_irqrestore(&cs->lock, flags);
171 return IRQ_HANDLED;
172}
173
174static int
175AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
176{
177 u_long flags;
178
179 switch (mt) {
180 case CARD_RESET:
181 spin_lock_irqsave(&cs->lock, flags);
182 byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET,0x00);
183 HZDELAY(HZ / 5 + 1);
184 byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET,ASL0_W_RESET);
185 HZDELAY(HZ / 5 + 1);
186 byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET,0x00);
187 spin_unlock_irqrestore(&cs->lock, flags);
188 return 0;
189
190 case CARD_RELEASE:
191 /* free_irq is done in HiSax_closecard(). */
192 /* free_irq(cs->irq, cs); */
193 return 0;
194
195 case CARD_INIT:
196 spin_lock_irqsave(&cs->lock, flags);
197 byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET,ASL0_W_TDISABLE|ASL0_W_TRESET|ASL0_W_IRQENABLE);
198 clear_pending_isac_ints(cs);
199 clear_pending_hscx_ints(cs);
200 inithscxisac(cs, 1);
201 inithscxisac(cs, 2);
202 spin_unlock_irqrestore(&cs->lock, flags);
203 return 0;
204
205 case CARD_TEST:
206 /* we really don't need it for the PCMCIA Version */
207 return 0;
208
209 default:
210 /* all card drivers ignore others, so we do the same */
211 return 0;
212 }
213 return 0;
214}
215
216int
217setup_avm_a1_pcmcia(struct IsdnCard *card)
218{
219 u_char model, vers;
220 struct IsdnCardState *cs = card->cs;
221 char tmp[64];
222
223
224 strcpy(tmp, avm_revision);
225 printk(KERN_INFO "HiSax: AVM A1 PCMCIA driver Rev. %s\n",
226 HiSax_getrev(tmp));
227 if (cs->typ != ISDN_CTYPE_A1_PCMCIA)
228 return (0);
229
230 cs->hw.avm.cfg_reg = card->para[1];
231 cs->irq = card->para[0];
232
233
234 byteout(cs->hw.avm.cfg_reg+ASL1_OFFSET, ASL1_W_ENABLE_S0);
235 byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET,0x00);
236 HZDELAY(HZ / 5 + 1);
237 byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET,ASL0_W_RESET);
238 HZDELAY(HZ / 5 + 1);
239 byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET,0x00);
240
241 byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET, ASL0_W_TDISABLE|ASL0_W_TRESET);
242
243 model = bytein(cs->hw.avm.cfg_reg+MODREG_OFFSET);
244 vers = bytein(cs->hw.avm.cfg_reg+VERREG_OFFSET);
245
246 printk(KERN_INFO "AVM A1 PCMCIA: io 0x%x irq %d model %d version %d\n",
247 cs->hw.avm.cfg_reg, cs->irq, model, vers);
248
249 setup_isac(cs);
250 cs->readisac = &ReadISAC;
251 cs->writeisac = &WriteISAC;
252 cs->readisacfifo = &ReadISACfifo;
253 cs->writeisacfifo = &WriteISACfifo;
254 cs->BC_Read_Reg = &ReadHSCX;
255 cs->BC_Write_Reg = &WriteHSCX;
256 cs->BC_Send_Data = &hscx_fill_fifo;
257 cs->cardmsg = &AVM_card_msg;
258 cs->irq_flags = SA_SHIRQ;
259 cs->irq_func = &avm_a1p_interrupt;
260
261 ISACVersion(cs, "AVM A1 PCMCIA:");
262 if (HscxVersion(cs, "AVM A1 PCMCIA:")) {
263 printk(KERN_WARNING
264 "AVM A1 PCMCIA: wrong HSCX versions check IO address\n");
265 return (0);
266 }
267 return (1);
268}
diff --git a/drivers/isdn/hisax/avm_pci.c b/drivers/isdn/hisax/avm_pci.c
new file mode 100644
index 000000000000..6fcb2cf7b0b6
--- /dev/null
+++ b/drivers/isdn/hisax/avm_pci.c
@@ -0,0 +1,865 @@
1/* $Id: avm_pci.c,v 1.29.2.4 2004/02/11 13:21:32 keil Exp $
2 *
3 * low level stuff for AVM Fritz!PCI and ISA PnP isdn cards
4 *
5 * Author Karsten Keil
6 * Copyright by Karsten Keil <keil@isdn4linux.de>
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 * Thanks to AVM, Berlin for information
12 *
13 */
14
15#include <linux/config.h>
16#include <linux/init.h>
17#include "hisax.h"
18#include "isac.h"
19#include "isdnl1.h"
20#include <linux/pci.h>
21#include <linux/isapnp.h>
22#include <linux/interrupt.h>
23
24extern const char *CardType[];
25static const char *avm_pci_rev = "$Revision: 1.29.2.4 $";
26
27#define AVM_FRITZ_PCI 1
28#define AVM_FRITZ_PNP 2
29
30#define HDLC_FIFO 0x0
31#define HDLC_STATUS 0x4
32
33#define AVM_HDLC_1 0x00
34#define AVM_HDLC_2 0x01
35#define AVM_ISAC_FIFO 0x02
36#define AVM_ISAC_REG_LOW 0x04
37#define AVM_ISAC_REG_HIGH 0x06
38
39#define AVM_STATUS0_IRQ_ISAC 0x01
40#define AVM_STATUS0_IRQ_HDLC 0x02
41#define AVM_STATUS0_IRQ_TIMER 0x04
42#define AVM_STATUS0_IRQ_MASK 0x07
43
44#define AVM_STATUS0_RESET 0x01
45#define AVM_STATUS0_DIS_TIMER 0x02
46#define AVM_STATUS0_RES_TIMER 0x04
47#define AVM_STATUS0_ENA_IRQ 0x08
48#define AVM_STATUS0_TESTBIT 0x10
49
50#define AVM_STATUS1_INT_SEL 0x0f
51#define AVM_STATUS1_ENA_IOM 0x80
52
53#define HDLC_MODE_ITF_FLG 0x01
54#define HDLC_MODE_TRANS 0x02
55#define HDLC_MODE_CCR_7 0x04
56#define HDLC_MODE_CCR_16 0x08
57#define HDLC_MODE_TESTLOOP 0x80
58
59#define HDLC_INT_XPR 0x80
60#define HDLC_INT_XDU 0x40
61#define HDLC_INT_RPR 0x20
62#define HDLC_INT_MASK 0xE0
63
64#define HDLC_STAT_RME 0x01
65#define HDLC_STAT_RDO 0x10
66#define HDLC_STAT_CRCVFRRAB 0x0E
67#define HDLC_STAT_CRCVFR 0x06
68#define HDLC_STAT_RML_MASK 0x3f00
69
70#define HDLC_CMD_XRS 0x80
71#define HDLC_CMD_XME 0x01
72#define HDLC_CMD_RRS 0x20
73#define HDLC_CMD_XML_MASK 0x3f00
74
75
76/* Interface functions */
77
78static u_char
79ReadISAC(struct IsdnCardState *cs, u_char offset)
80{
81 register u_char idx = (offset > 0x2f) ? AVM_ISAC_REG_HIGH : AVM_ISAC_REG_LOW;
82 register u_char val;
83
84 outb(idx, cs->hw.avm.cfg_reg + 4);
85 val = inb(cs->hw.avm.isac + (offset & 0xf));
86 return (val);
87}
88
89static void
90WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
91{
92 register u_char idx = (offset > 0x2f) ? AVM_ISAC_REG_HIGH : AVM_ISAC_REG_LOW;
93
94 outb(idx, cs->hw.avm.cfg_reg + 4);
95 outb(value, cs->hw.avm.isac + (offset & 0xf));
96}
97
98static void
99ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
100{
101 outb(AVM_ISAC_FIFO, cs->hw.avm.cfg_reg + 4);
102 insb(cs->hw.avm.isac, data, size);
103}
104
105static void
106WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
107{
108 outb(AVM_ISAC_FIFO, cs->hw.avm.cfg_reg + 4);
109 outsb(cs->hw.avm.isac, data, size);
110}
111
112static inline u_int
113ReadHDLCPCI(struct IsdnCardState *cs, int chan, u_char offset)
114{
115 register u_int idx = chan ? AVM_HDLC_2 : AVM_HDLC_1;
116 register u_int val;
117
118 outl(idx, cs->hw.avm.cfg_reg + 4);
119 val = inl(cs->hw.avm.isac + offset);
120 return (val);
121}
122
123static inline void
124WriteHDLCPCI(struct IsdnCardState *cs, int chan, u_char offset, u_int value)
125{
126 register u_int idx = chan ? AVM_HDLC_2 : AVM_HDLC_1;
127
128 outl(idx, cs->hw.avm.cfg_reg + 4);
129 outl(value, cs->hw.avm.isac + offset);
130}
131
132static inline u_char
133ReadHDLCPnP(struct IsdnCardState *cs, int chan, u_char offset)
134{
135 register u_char idx = chan ? AVM_HDLC_2 : AVM_HDLC_1;
136 register u_char val;
137
138 outb(idx, cs->hw.avm.cfg_reg + 4);
139 val = inb(cs->hw.avm.isac + offset);
140 return (val);
141}
142
143static inline void
144WriteHDLCPnP(struct IsdnCardState *cs, int chan, u_char offset, u_char value)
145{
146 register u_char idx = chan ? AVM_HDLC_2 : AVM_HDLC_1;
147
148 outb(idx, cs->hw.avm.cfg_reg + 4);
149 outb(value, cs->hw.avm.isac + offset);
150}
151
152static u_char
153ReadHDLC_s(struct IsdnCardState *cs, int chan, u_char offset)
154{
155 return(0xff & ReadHDLCPCI(cs, chan, offset));
156}
157
158static void
159WriteHDLC_s(struct IsdnCardState *cs, int chan, u_char offset, u_char value)
160{
161 WriteHDLCPCI(cs, chan, offset, value);
162}
163
164static inline
165struct BCState *Sel_BCS(struct IsdnCardState *cs, int channel)
166{
167 if (cs->bcs[0].mode && (cs->bcs[0].channel == channel))
168 return(&cs->bcs[0]);
169 else if (cs->bcs[1].mode && (cs->bcs[1].channel == channel))
170 return(&cs->bcs[1]);
171 else
172 return(NULL);
173}
174
175void
176write_ctrl(struct BCState *bcs, int which) {
177
178 if (bcs->cs->debug & L1_DEB_HSCX)
179 debugl1(bcs->cs, "hdlc %c wr%x ctrl %x",
180 'A' + bcs->channel, which, bcs->hw.hdlc.ctrl.ctrl);
181 if (bcs->cs->subtyp == AVM_FRITZ_PCI) {
182 WriteHDLCPCI(bcs->cs, bcs->channel, HDLC_STATUS, bcs->hw.hdlc.ctrl.ctrl);
183 } else {
184 if (which & 4)
185 WriteHDLCPnP(bcs->cs, bcs->channel, HDLC_STATUS + 2,
186 bcs->hw.hdlc.ctrl.sr.mode);
187 if (which & 2)
188 WriteHDLCPnP(bcs->cs, bcs->channel, HDLC_STATUS + 1,
189 bcs->hw.hdlc.ctrl.sr.xml);
190 if (which & 1)
191 WriteHDLCPnP(bcs->cs, bcs->channel, HDLC_STATUS,
192 bcs->hw.hdlc.ctrl.sr.cmd);
193 }
194}
195
196void
197modehdlc(struct BCState *bcs, int mode, int bc)
198{
199 struct IsdnCardState *cs = bcs->cs;
200 int hdlc = bcs->channel;
201
202 if (cs->debug & L1_DEB_HSCX)
203 debugl1(cs, "hdlc %c mode %d --> %d ichan %d --> %d",
204 'A' + hdlc, bcs->mode, mode, hdlc, bc);
205 bcs->hw.hdlc.ctrl.ctrl = 0;
206 switch (mode) {
207 case (-1): /* used for init */
208 bcs->mode = 1;
209 bcs->channel = bc;
210 bc = 0;
211 case (L1_MODE_NULL):
212 if (bcs->mode == L1_MODE_NULL)
213 return;
214 bcs->hw.hdlc.ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS;
215 bcs->hw.hdlc.ctrl.sr.mode = HDLC_MODE_TRANS;
216 write_ctrl(bcs, 5);
217 bcs->mode = L1_MODE_NULL;
218 bcs->channel = bc;
219 break;
220 case (L1_MODE_TRANS):
221 bcs->mode = mode;
222 bcs->channel = bc;
223 bcs->hw.hdlc.ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS;
224 bcs->hw.hdlc.ctrl.sr.mode = HDLC_MODE_TRANS;
225 write_ctrl(bcs, 5);
226 bcs->hw.hdlc.ctrl.sr.cmd = HDLC_CMD_XRS;
227 write_ctrl(bcs, 1);
228 bcs->hw.hdlc.ctrl.sr.cmd = 0;
229 schedule_event(bcs, B_XMTBUFREADY);
230 break;
231 case (L1_MODE_HDLC):
232 bcs->mode = mode;
233 bcs->channel = bc;
234 bcs->hw.hdlc.ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS;
235 bcs->hw.hdlc.ctrl.sr.mode = HDLC_MODE_ITF_FLG;
236 write_ctrl(bcs, 5);
237 bcs->hw.hdlc.ctrl.sr.cmd = HDLC_CMD_XRS;
238 write_ctrl(bcs, 1);
239 bcs->hw.hdlc.ctrl.sr.cmd = 0;
240 schedule_event(bcs, B_XMTBUFREADY);
241 break;
242 }
243}
244
245static inline void
246hdlc_empty_fifo(struct BCState *bcs, int count)
247{
248 register u_int *ptr;
249 u_char *p;
250 u_char idx = bcs->channel ? AVM_HDLC_2 : AVM_HDLC_1;
251 int cnt=0;
252 struct IsdnCardState *cs = bcs->cs;
253
254 if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
255 debugl1(cs, "hdlc_empty_fifo %d", count);
256 if (bcs->hw.hdlc.rcvidx + count > HSCX_BUFMAX) {
257 if (cs->debug & L1_DEB_WARN)
258 debugl1(cs, "hdlc_empty_fifo: incoming packet too large");
259 return;
260 }
261 p = bcs->hw.hdlc.rcvbuf + bcs->hw.hdlc.rcvidx;
262 ptr = (u_int *)p;
263 bcs->hw.hdlc.rcvidx += count;
264 if (cs->subtyp == AVM_FRITZ_PCI) {
265 outl(idx, cs->hw.avm.cfg_reg + 4);
266 while (cnt < count) {
267#ifdef __powerpc__
268#ifdef CONFIG_APUS
269 *ptr++ = in_le32((unsigned *)(cs->hw.avm.isac +_IO_BASE));
270#else
271 *ptr++ = in_be32((unsigned *)(cs->hw.avm.isac +_IO_BASE));
272#endif /* CONFIG_APUS */
273#else
274 *ptr++ = inl(cs->hw.avm.isac);
275#endif /* __powerpc__ */
276 cnt += 4;
277 }
278 } else {
279 outb(idx, cs->hw.avm.cfg_reg + 4);
280 while (cnt < count) {
281 *p++ = inb(cs->hw.avm.isac);
282 cnt++;
283 }
284 }
285 if (cs->debug & L1_DEB_HSCX_FIFO) {
286 char *t = bcs->blog;
287
288 if (cs->subtyp == AVM_FRITZ_PNP)
289 p = (u_char *) ptr;
290 t += sprintf(t, "hdlc_empty_fifo %c cnt %d",
291 bcs->channel ? 'B' : 'A', count);
292 QuickHex(t, p, count);
293 debugl1(cs, bcs->blog);
294 }
295}
296
297static inline void
298hdlc_fill_fifo(struct BCState *bcs)
299{
300 struct IsdnCardState *cs = bcs->cs;
301 int count, cnt =0;
302 int fifo_size = 32;
303 u_char *p;
304 u_int *ptr;
305
306 if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
307 debugl1(cs, "hdlc_fill_fifo");
308 if (!bcs->tx_skb)
309 return;
310 if (bcs->tx_skb->len <= 0)
311 return;
312
313 bcs->hw.hdlc.ctrl.sr.cmd &= ~HDLC_CMD_XME;
314 if (bcs->tx_skb->len > fifo_size) {
315 count = fifo_size;
316 } else {
317 count = bcs->tx_skb->len;
318 if (bcs->mode != L1_MODE_TRANS)
319 bcs->hw.hdlc.ctrl.sr.cmd |= HDLC_CMD_XME;
320 }
321 if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
322 debugl1(cs, "hdlc_fill_fifo %d/%ld", count, bcs->tx_skb->len);
323 p = bcs->tx_skb->data;
324 ptr = (u_int *)p;
325 skb_pull(bcs->tx_skb, count);
326 bcs->tx_cnt -= count;
327 bcs->hw.hdlc.count += count;
328 bcs->hw.hdlc.ctrl.sr.xml = ((count == fifo_size) ? 0 : count);
329 write_ctrl(bcs, 3); /* sets the correct index too */
330 if (cs->subtyp == AVM_FRITZ_PCI) {
331 while (cnt<count) {
332#ifdef __powerpc__
333#ifdef CONFIG_APUS
334 out_le32((unsigned *)(cs->hw.avm.isac +_IO_BASE), *ptr++);
335#else
336 out_be32((unsigned *)(cs->hw.avm.isac +_IO_BASE), *ptr++);
337#endif /* CONFIG_APUS */
338#else
339 outl(*ptr++, cs->hw.avm.isac);
340#endif /* __powerpc__ */
341 cnt += 4;
342 }
343 } else {
344 while (cnt<count) {
345 outb(*p++, cs->hw.avm.isac);
346 cnt++;
347 }
348 }
349 if (cs->debug & L1_DEB_HSCX_FIFO) {
350 char *t = bcs->blog;
351
352 if (cs->subtyp == AVM_FRITZ_PNP)
353 p = (u_char *) ptr;
354 t += sprintf(t, "hdlc_fill_fifo %c cnt %d",
355 bcs->channel ? 'B' : 'A', count);
356 QuickHex(t, p, count);
357 debugl1(cs, bcs->blog);
358 }
359}
360
361static inline void
362HDLC_irq(struct BCState *bcs, u_int stat) {
363 int len;
364 struct sk_buff *skb;
365
366 if (bcs->cs->debug & L1_DEB_HSCX)
367 debugl1(bcs->cs, "ch%d stat %#x", bcs->channel, stat);
368 if (stat & HDLC_INT_RPR) {
369 if (stat & HDLC_STAT_RDO) {
370 if (bcs->cs->debug & L1_DEB_HSCX)
371 debugl1(bcs->cs, "RDO");
372 else
373 debugl1(bcs->cs, "ch%d stat %#x", bcs->channel, stat);
374 bcs->hw.hdlc.ctrl.sr.xml = 0;
375 bcs->hw.hdlc.ctrl.sr.cmd |= HDLC_CMD_RRS;
376 write_ctrl(bcs, 1);
377 bcs->hw.hdlc.ctrl.sr.cmd &= ~HDLC_CMD_RRS;
378 write_ctrl(bcs, 1);
379 bcs->hw.hdlc.rcvidx = 0;
380 } else {
381 if (!(len = (stat & HDLC_STAT_RML_MASK)>>8))
382 len = 32;
383 hdlc_empty_fifo(bcs, len);
384 if ((stat & HDLC_STAT_RME) || (bcs->mode == L1_MODE_TRANS)) {
385 if (((stat & HDLC_STAT_CRCVFRRAB)==HDLC_STAT_CRCVFR) ||
386 (bcs->mode == L1_MODE_TRANS)) {
387 if (!(skb = dev_alloc_skb(bcs->hw.hdlc.rcvidx)))
388 printk(KERN_WARNING "HDLC: receive out of memory\n");
389 else {
390 memcpy(skb_put(skb, bcs->hw.hdlc.rcvidx),
391 bcs->hw.hdlc.rcvbuf, bcs->hw.hdlc.rcvidx);
392 skb_queue_tail(&bcs->rqueue, skb);
393 }
394 bcs->hw.hdlc.rcvidx = 0;
395 schedule_event(bcs, B_RCVBUFREADY);
396 } else {
397 if (bcs->cs->debug & L1_DEB_HSCX)
398 debugl1(bcs->cs, "invalid frame");
399 else
400 debugl1(bcs->cs, "ch%d invalid frame %#x", bcs->channel, stat);
401 bcs->hw.hdlc.rcvidx = 0;
402 }
403 }
404 }
405 }
406 if (stat & HDLC_INT_XDU) {
407 /* Here we lost an TX interrupt, so
408 * restart transmitting the whole frame.
409 */
410 if (bcs->tx_skb) {
411 skb_push(bcs->tx_skb, bcs->hw.hdlc.count);
412 bcs->tx_cnt += bcs->hw.hdlc.count;
413 bcs->hw.hdlc.count = 0;
414 if (bcs->cs->debug & L1_DEB_WARN)
415 debugl1(bcs->cs, "ch%d XDU", bcs->channel);
416 } else if (bcs->cs->debug & L1_DEB_WARN)
417 debugl1(bcs->cs, "ch%d XDU without skb", bcs->channel);
418 bcs->hw.hdlc.ctrl.sr.xml = 0;
419 bcs->hw.hdlc.ctrl.sr.cmd |= HDLC_CMD_XRS;
420 write_ctrl(bcs, 1);
421 bcs->hw.hdlc.ctrl.sr.cmd &= ~HDLC_CMD_XRS;
422 write_ctrl(bcs, 1);
423 hdlc_fill_fifo(bcs);
424 } else if (stat & HDLC_INT_XPR) {
425 if (bcs->tx_skb) {
426 if (bcs->tx_skb->len) {
427 hdlc_fill_fifo(bcs);
428 return;
429 } else {
430 if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) &&
431 (PACKET_NOACK != bcs->tx_skb->pkt_type)) {
432 u_long flags;
433 spin_lock_irqsave(&bcs->aclock, flags);
434 bcs->ackcnt += bcs->hw.hdlc.count;
435 spin_unlock_irqrestore(&bcs->aclock, flags);
436 schedule_event(bcs, B_ACKPENDING);
437 }
438 dev_kfree_skb_irq(bcs->tx_skb);
439 bcs->hw.hdlc.count = 0;
440 bcs->tx_skb = NULL;
441 }
442 }
443 if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
444 bcs->hw.hdlc.count = 0;
445 test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
446 hdlc_fill_fifo(bcs);
447 } else {
448 test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
449 schedule_event(bcs, B_XMTBUFREADY);
450 }
451 }
452}
453
454inline void
455HDLC_irq_main(struct IsdnCardState *cs)
456{
457 u_int stat;
458 struct BCState *bcs;
459
460 if (cs->subtyp == AVM_FRITZ_PCI) {
461 stat = ReadHDLCPCI(cs, 0, HDLC_STATUS);
462 } else {
463 stat = ReadHDLCPnP(cs, 0, HDLC_STATUS);
464 if (stat & HDLC_INT_RPR)
465 stat |= (ReadHDLCPnP(cs, 0, HDLC_STATUS+1))<<8;
466 }
467 if (stat & HDLC_INT_MASK) {
468 if (!(bcs = Sel_BCS(cs, 0))) {
469 if (cs->debug)
470 debugl1(cs, "hdlc spurious channel 0 IRQ");
471 } else
472 HDLC_irq(bcs, stat);
473 }
474 if (cs->subtyp == AVM_FRITZ_PCI) {
475 stat = ReadHDLCPCI(cs, 1, HDLC_STATUS);
476 } else {
477 stat = ReadHDLCPnP(cs, 1, HDLC_STATUS);
478 if (stat & HDLC_INT_RPR)
479 stat |= (ReadHDLCPnP(cs, 1, HDLC_STATUS+1))<<8;
480 }
481 if (stat & HDLC_INT_MASK) {
482 if (!(bcs = Sel_BCS(cs, 1))) {
483 if (cs->debug)
484 debugl1(cs, "hdlc spurious channel 1 IRQ");
485 } else
486 HDLC_irq(bcs, stat);
487 }
488}
489
490void
491hdlc_l2l1(struct PStack *st, int pr, void *arg)
492{
493 struct BCState *bcs = st->l1.bcs;
494 struct sk_buff *skb = arg;
495 u_long flags;
496
497 switch (pr) {
498 case (PH_DATA | REQUEST):
499 spin_lock_irqsave(&bcs->cs->lock, flags);
500 if (bcs->tx_skb) {
501 skb_queue_tail(&bcs->squeue, skb);
502 } else {
503 bcs->tx_skb = skb;
504 test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
505 bcs->hw.hdlc.count = 0;
506 bcs->cs->BC_Send_Data(bcs);
507 }
508 spin_unlock_irqrestore(&bcs->cs->lock, flags);
509 break;
510 case (PH_PULL | INDICATION):
511 spin_lock_irqsave(&bcs->cs->lock, flags);
512 if (bcs->tx_skb) {
513 printk(KERN_WARNING "hdlc_l2l1: this shouldn't happen\n");
514 } else {
515 test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
516 bcs->tx_skb = skb;
517 bcs->hw.hdlc.count = 0;
518 bcs->cs->BC_Send_Data(bcs);
519 }
520 spin_unlock_irqrestore(&bcs->cs->lock, flags);
521 break;
522 case (PH_PULL | REQUEST):
523 if (!bcs->tx_skb) {
524 test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
525 st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
526 } else
527 test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
528 break;
529 case (PH_ACTIVATE | REQUEST):
530 spin_lock_irqsave(&bcs->cs->lock, flags);
531 test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag);
532 modehdlc(bcs, st->l1.mode, st->l1.bc);
533 spin_unlock_irqrestore(&bcs->cs->lock, flags);
534 l1_msg_b(st, pr, arg);
535 break;
536 case (PH_DEACTIVATE | REQUEST):
537 l1_msg_b(st, pr, arg);
538 break;
539 case (PH_DEACTIVATE | CONFIRM):
540 spin_lock_irqsave(&bcs->cs->lock, flags);
541 test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag);
542 test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
543 modehdlc(bcs, 0, st->l1.bc);
544 spin_unlock_irqrestore(&bcs->cs->lock, flags);
545 st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
546 break;
547 }
548}
549
550void
551close_hdlcstate(struct BCState *bcs)
552{
553 modehdlc(bcs, 0, 0);
554 if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) {
555 if (bcs->hw.hdlc.rcvbuf) {
556 kfree(bcs->hw.hdlc.rcvbuf);
557 bcs->hw.hdlc.rcvbuf = NULL;
558 }
559 if (bcs->blog) {
560 kfree(bcs->blog);
561 bcs->blog = NULL;
562 }
563 skb_queue_purge(&bcs->rqueue);
564 skb_queue_purge(&bcs->squeue);
565 if (bcs->tx_skb) {
566 dev_kfree_skb_any(bcs->tx_skb);
567 bcs->tx_skb = NULL;
568 test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
569 }
570 }
571}
572
573int
574open_hdlcstate(struct IsdnCardState *cs, struct BCState *bcs)
575{
576 if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
577 if (!(bcs->hw.hdlc.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) {
578 printk(KERN_WARNING
579 "HiSax: No memory for hdlc.rcvbuf\n");
580 return (1);
581 }
582 if (!(bcs->blog = kmalloc(MAX_BLOG_SPACE, GFP_ATOMIC))) {
583 printk(KERN_WARNING
584 "HiSax: No memory for bcs->blog\n");
585 test_and_clear_bit(BC_FLG_INIT, &bcs->Flag);
586 kfree(bcs->hw.hdlc.rcvbuf);
587 bcs->hw.hdlc.rcvbuf = NULL;
588 return (2);
589 }
590 skb_queue_head_init(&bcs->rqueue);
591 skb_queue_head_init(&bcs->squeue);
592 }
593 bcs->tx_skb = NULL;
594 test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
595 bcs->event = 0;
596 bcs->hw.hdlc.rcvidx = 0;
597 bcs->tx_cnt = 0;
598 return (0);
599}
600
601int
602setstack_hdlc(struct PStack *st, struct BCState *bcs)
603{
604 bcs->channel = st->l1.bc;
605 if (open_hdlcstate(st->l1.hardware, bcs))
606 return (-1);
607 st->l1.bcs = bcs;
608 st->l2.l2l1 = hdlc_l2l1;
609 setstack_manager(st);
610 bcs->st = st;
611 setstack_l1_B(st);
612 return (0);
613}
614
615void __init
616clear_pending_hdlc_ints(struct IsdnCardState *cs)
617{
618 u_int val;
619
620 if (cs->subtyp == AVM_FRITZ_PCI) {
621 val = ReadHDLCPCI(cs, 0, HDLC_STATUS);
622 debugl1(cs, "HDLC 1 STA %x", val);
623 val = ReadHDLCPCI(cs, 1, HDLC_STATUS);
624 debugl1(cs, "HDLC 2 STA %x", val);
625 } else {
626 val = ReadHDLCPnP(cs, 0, HDLC_STATUS);
627 debugl1(cs, "HDLC 1 STA %x", val);
628 val = ReadHDLCPnP(cs, 0, HDLC_STATUS + 1);
629 debugl1(cs, "HDLC 1 RML %x", val);
630 val = ReadHDLCPnP(cs, 0, HDLC_STATUS + 2);
631 debugl1(cs, "HDLC 1 MODE %x", val);
632 val = ReadHDLCPnP(cs, 0, HDLC_STATUS + 3);
633 debugl1(cs, "HDLC 1 VIN %x", val);
634 val = ReadHDLCPnP(cs, 1, HDLC_STATUS);
635 debugl1(cs, "HDLC 2 STA %x", val);
636 val = ReadHDLCPnP(cs, 1, HDLC_STATUS + 1);
637 debugl1(cs, "HDLC 2 RML %x", val);
638 val = ReadHDLCPnP(cs, 1, HDLC_STATUS + 2);
639 debugl1(cs, "HDLC 2 MODE %x", val);
640 val = ReadHDLCPnP(cs, 1, HDLC_STATUS + 3);
641 debugl1(cs, "HDLC 2 VIN %x", val);
642 }
643}
644
645void __init
646inithdlc(struct IsdnCardState *cs)
647{
648 cs->bcs[0].BC_SetStack = setstack_hdlc;
649 cs->bcs[1].BC_SetStack = setstack_hdlc;
650 cs->bcs[0].BC_Close = close_hdlcstate;
651 cs->bcs[1].BC_Close = close_hdlcstate;
652 modehdlc(cs->bcs, -1, 0);
653 modehdlc(cs->bcs + 1, -1, 1);
654}
655
656static irqreturn_t
657avm_pcipnp_interrupt(int intno, void *dev_id, struct pt_regs *regs)
658{
659 struct IsdnCardState *cs = dev_id;
660 u_long flags;
661 u_char val;
662 u_char sval;
663
664 spin_lock_irqsave(&cs->lock, flags);
665 sval = inb(cs->hw.avm.cfg_reg + 2);
666 if ((sval & AVM_STATUS0_IRQ_MASK) == AVM_STATUS0_IRQ_MASK) {
667 /* possible a shared IRQ reqest */
668 spin_unlock_irqrestore(&cs->lock, flags);
669 return IRQ_NONE;
670 }
671 if (!(sval & AVM_STATUS0_IRQ_ISAC)) {
672 val = ReadISAC(cs, ISAC_ISTA);
673 isac_interrupt(cs, val);
674 }
675 if (!(sval & AVM_STATUS0_IRQ_HDLC)) {
676 HDLC_irq_main(cs);
677 }
678 WriteISAC(cs, ISAC_MASK, 0xFF);
679 WriteISAC(cs, ISAC_MASK, 0x0);
680 spin_unlock_irqrestore(&cs->lock, flags);
681 return IRQ_HANDLED;
682}
683
684static void
685reset_avmpcipnp(struct IsdnCardState *cs)
686{
687 printk(KERN_INFO "AVM PCI/PnP: reset\n");
688 outb(AVM_STATUS0_RESET | AVM_STATUS0_DIS_TIMER, cs->hw.avm.cfg_reg + 2);
689 mdelay(10);
690 outb(AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER | AVM_STATUS0_ENA_IRQ, cs->hw.avm.cfg_reg + 2);
691 outb(AVM_STATUS1_ENA_IOM | cs->irq, cs->hw.avm.cfg_reg + 3);
692 mdelay(10);
693 printk(KERN_INFO "AVM PCI/PnP: S1 %x\n", inb(cs->hw.avm.cfg_reg + 3));
694}
695
696static int
697AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
698{
699 u_long flags;
700
701 switch (mt) {
702 case CARD_RESET:
703 spin_lock_irqsave(&cs->lock, flags);
704 reset_avmpcipnp(cs);
705 spin_unlock_irqrestore(&cs->lock, flags);
706 return(0);
707 case CARD_RELEASE:
708 outb(0, cs->hw.avm.cfg_reg + 2);
709 release_region(cs->hw.avm.cfg_reg, 32);
710 return(0);
711 case CARD_INIT:
712 spin_lock_irqsave(&cs->lock, flags);
713 reset_avmpcipnp(cs);
714 clear_pending_isac_ints(cs);
715 initisac(cs);
716 inithdlc(cs);
717 outb(AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER,
718 cs->hw.avm.cfg_reg + 2);
719 WriteISAC(cs, ISAC_MASK, 0);
720 outb(AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER |
721 AVM_STATUS0_ENA_IRQ, cs->hw.avm.cfg_reg + 2);
722 /* RESET Receiver and Transmitter */
723 WriteISAC(cs, ISAC_CMDR, 0x41);
724 spin_unlock_irqrestore(&cs->lock, flags);
725 return(0);
726 case CARD_TEST:
727 return(0);
728 }
729 return(0);
730}
731
732#ifdef CONFIG_PCI
733static struct pci_dev *dev_avm __initdata = NULL;
734#endif
735#ifdef __ISAPNP__
736static struct pnp_card *pnp_avm_c __initdata = NULL;
737#endif
738
739int __init
740setup_avm_pcipnp(struct IsdnCard *card)
741{
742 u_int val, ver;
743 struct IsdnCardState *cs = card->cs;
744 char tmp[64];
745
746 strcpy(tmp, avm_pci_rev);
747 printk(KERN_INFO "HiSax: AVM PCI driver Rev. %s\n", HiSax_getrev(tmp));
748 if (cs->typ != ISDN_CTYPE_FRITZPCI)
749 return (0);
750 if (card->para[1]) {
751 /* old manual method */
752 cs->hw.avm.cfg_reg = card->para[1];
753 cs->irq = card->para[0];
754 cs->subtyp = AVM_FRITZ_PNP;
755 goto ready;
756 }
757#ifdef __ISAPNP__
758 if (isapnp_present()) {
759 struct pnp_dev *pnp_avm_d = NULL;
760 if ((pnp_avm_c = pnp_find_card(
761 ISAPNP_VENDOR('A', 'V', 'M'),
762 ISAPNP_FUNCTION(0x0900), pnp_avm_c))) {
763 if ((pnp_avm_d = pnp_find_dev(pnp_avm_c,
764 ISAPNP_VENDOR('A', 'V', 'M'),
765 ISAPNP_FUNCTION(0x0900), pnp_avm_d))) {
766 int err;
767
768 pnp_disable_dev(pnp_avm_d);
769 err = pnp_activate_dev(pnp_avm_d);
770 if (err<0) {
771 printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
772 __FUNCTION__, err);
773 return(0);
774 }
775 cs->hw.avm.cfg_reg =
776 pnp_port_start(pnp_avm_d, 0);
777 cs->irq = pnp_irq(pnp_avm_d, 0);
778 if (!cs->irq) {
779 printk(KERN_ERR "FritzPnP:No IRQ\n");
780 return(0);
781 }
782 if (!cs->hw.avm.cfg_reg) {
783 printk(KERN_ERR "FritzPnP:No IO address\n");
784 return(0);
785 }
786 cs->subtyp = AVM_FRITZ_PNP;
787 goto ready;
788 }
789 }
790 } else {
791 printk(KERN_INFO "FritzPnP: no ISA PnP present\n");
792 }
793#endif
794#ifdef CONFIG_PCI
795 if ((dev_avm = pci_find_device(PCI_VENDOR_ID_AVM,
796 PCI_DEVICE_ID_AVM_A1, dev_avm))) {
797 if (pci_enable_device(dev_avm))
798 return(0);
799 cs->irq = dev_avm->irq;
800 if (!cs->irq) {
801 printk(KERN_ERR "FritzPCI: No IRQ for PCI card found\n");
802 return(0);
803 }
804 cs->hw.avm.cfg_reg = pci_resource_start(dev_avm, 1);
805 if (!cs->hw.avm.cfg_reg) {
806 printk(KERN_ERR "FritzPCI: No IO-Adr for PCI card found\n");
807 return(0);
808 }
809 cs->subtyp = AVM_FRITZ_PCI;
810 } else {
811 printk(KERN_WARNING "FritzPCI: No PCI card found\n");
812 return(0);
813 }
814 cs->irq_flags |= SA_SHIRQ;
815#else
816 printk(KERN_WARNING "FritzPCI: NO_PCI_BIOS\n");
817 return (0);
818#endif /* CONFIG_PCI */
819ready:
820 cs->hw.avm.isac = cs->hw.avm.cfg_reg + 0x10;
821 if (!request_region(cs->hw.avm.cfg_reg, 32,
822 (cs->subtyp == AVM_FRITZ_PCI) ? "avm PCI" : "avm PnP")) {
823 printk(KERN_WARNING
824 "HiSax: %s config port %x-%x already in use\n",
825 CardType[card->typ],
826 cs->hw.avm.cfg_reg,
827 cs->hw.avm.cfg_reg + 31);
828 return (0);
829 }
830 switch (cs->subtyp) {
831 case AVM_FRITZ_PCI:
832 val = inl(cs->hw.avm.cfg_reg);
833 printk(KERN_INFO "AVM PCI: stat %#x\n", val);
834 printk(KERN_INFO "AVM PCI: Class %X Rev %d\n",
835 val & 0xff, (val>>8) & 0xff);
836 cs->BC_Read_Reg = &ReadHDLC_s;
837 cs->BC_Write_Reg = &WriteHDLC_s;
838 break;
839 case AVM_FRITZ_PNP:
840 val = inb(cs->hw.avm.cfg_reg);
841 ver = inb(cs->hw.avm.cfg_reg + 1);
842 printk(KERN_INFO "AVM PnP: Class %X Rev %d\n", val, ver);
843 cs->BC_Read_Reg = &ReadHDLCPnP;
844 cs->BC_Write_Reg = &WriteHDLCPnP;
845 break;
846 default:
847 printk(KERN_WARNING "AVM unknown subtype %d\n", cs->subtyp);
848 return(0);
849 }
850 printk(KERN_INFO "HiSax: %s config irq:%d base:0x%X\n",
851 (cs->subtyp == AVM_FRITZ_PCI) ? "AVM Fritz!PCI" : "AVM Fritz!PnP",
852 cs->irq, cs->hw.avm.cfg_reg);
853
854 setup_isac(cs);
855 cs->readisac = &ReadISAC;
856 cs->writeisac = &WriteISAC;
857 cs->readisacfifo = &ReadISACfifo;
858 cs->writeisacfifo = &WriteISACfifo;
859 cs->BC_Send_Data = &hdlc_fill_fifo;
860 cs->cardmsg = &AVM_card_msg;
861 cs->irq_func = &avm_pcipnp_interrupt;
862 cs->writeisac(cs, ISAC_MASK, 0xFF);
863 ISACVersion(cs, (cs->subtyp == AVM_FRITZ_PCI) ? "AVM PCI:" : "AVM PnP:");
864 return (1);
865}
diff --git a/drivers/isdn/hisax/avma1_cs.c b/drivers/isdn/hisax/avma1_cs.c
new file mode 100644
index 000000000000..663a0bf703b7
--- /dev/null
+++ b/drivers/isdn/hisax/avma1_cs.c
@@ -0,0 +1,527 @@
1/*
2 * PCMCIA client driver for AVM A1 / Fritz!PCMCIA
3 *
4 * Author Carsten Paeth
5 * Copyright 1998-2001 by Carsten Paeth <calle@calle.in-berlin.de>
6 *
7 * This software may be used and distributed according to the terms
8 * of the GNU General Public License, incorporated herein by reference.
9 *
10 */
11
12#include <linux/module.h>
13
14
15#include <linux/kernel.h>
16#include <linux/init.h>
17#include <linux/sched.h>
18#include <linux/ptrace.h>
19#include <linux/slab.h>
20#include <linux/string.h>
21#include <asm/io.h>
22#include <asm/system.h>
23
24#include <pcmcia/version.h>
25#include <pcmcia/cs_types.h>
26#include <pcmcia/cs.h>
27#include <pcmcia/cistpl.h>
28#include <pcmcia/ds.h>
29#include "hisax_cfg.h"
30
31MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for AVM A1/Fritz!PCMCIA cards");
32MODULE_AUTHOR("Carsten Paeth");
33MODULE_LICENSE("GPL");
34
35/*
36 All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If
37 you do not define PCMCIA_DEBUG at all, all the debug code will be
38 left out. If you compile with PCMCIA_DEBUG=0, the debug code will
39 be present but disabled -- but it can then be enabled for specific
40 modules at load time with a 'pc_debug=#' option to insmod.
41*/
42#ifdef PCMCIA_DEBUG
43static int pc_debug = PCMCIA_DEBUG;
44module_param(pc_debug, int, 0);
45#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args);
46static char *version =
47"avma1_cs.c 1.00 1998/01/23 10:00:00 (Carsten Paeth)";
48#else
49#define DEBUG(n, args...)
50#endif
51
52/*====================================================================*/
53
54/* Parameters that can be set with 'insmod' */
55
56static int isdnprot = 2;
57
58module_param(isdnprot, int, 0);
59
60/*====================================================================*/
61
62/*
63 The event() function is this driver's Card Services event handler.
64 It will be called by Card Services when an appropriate card status
65 event is received. The config() and release() entry points are
66 used to configure or release a socket, in response to card insertion
67 and ejection events. They are invoked from the skeleton event
68 handler.
69*/
70
71static void avma1cs_config(dev_link_t *link);
72static void avma1cs_release(dev_link_t *link);
73static int avma1cs_event(event_t event, int priority,
74 event_callback_args_t *args);
75
76/*
77 The attach() and detach() entry points are used to create and destroy
78 "instances" of the driver, where each instance represents everything
79 needed to manage one actual PCMCIA card.
80*/
81
82static dev_link_t *avma1cs_attach(void);
83static void avma1cs_detach(dev_link_t *);
84
85/*
86 The dev_info variable is the "key" that is used to match up this
87 device driver with appropriate cards, through the card configuration
88 database.
89*/
90
91static dev_info_t dev_info = "avma1_cs";
92
93/*
94 A linked list of "instances" of the skeleton device. Each actual
95 PCMCIA card corresponds to one device instance, and is described
96 by one dev_link_t structure (defined in ds.h).
97
98 You may not want to use a linked list for this -- for example, the
99 memory card driver uses an array of dev_link_t pointers, where minor
100 device numbers are used to derive the corresponding array index.
101*/
102
103static dev_link_t *dev_list = NULL;
104
105/*
106 A dev_link_t structure has fields for most things that are needed
107 to keep track of a socket, but there will usually be some device
108 specific information that also needs to be kept track of. The
109 'priv' pointer in a dev_link_t structure can be used to point to
110 a device-specific private data structure, like this.
111
112 A driver needs to provide a dev_node_t structure for each device
113 on a card. In some cases, there is only one device per card (for
114 example, ethernet cards, modems). In other cases, there may be
115 many actual or logical devices (SCSI adapters, memory cards with
116 multiple partitions). The dev_node_t structures need to be kept
117 in a linked list starting at the 'dev' field of a dev_link_t
118 structure. We allocate them in the card's private data structure,
119 because they generally can't be allocated dynamically.
120*/
121
122typedef struct local_info_t {
123 dev_node_t node;
124} local_info_t;
125
126/*======================================================================
127
128 avma1cs_attach() creates an "instance" of the driver, allocating
129 local data structures for one device. The device is registered
130 with Card Services.
131
132 The dev_link structure is initialized, but we don't actually
133 configure the card at this point -- we wait until we receive a
134 card insertion event.
135
136======================================================================*/
137
138static dev_link_t *avma1cs_attach(void)
139{
140 client_reg_t client_reg;
141 dev_link_t *link;
142 local_info_t *local;
143 int ret;
144
145 DEBUG(0, "avma1cs_attach()\n");
146
147 /* Initialize the dev_link_t structure */
148 link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
149 if (!link)
150 return NULL;
151 memset(link, 0, sizeof(struct dev_link_t));
152
153 /* Allocate space for private device-specific data */
154 local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
155 if (!local) {
156 kfree(link);
157 return NULL;
158 }
159 memset(local, 0, sizeof(local_info_t));
160 link->priv = local;
161
162 /* The io structure describes IO port mapping */
163 link->io.NumPorts1 = 16;
164 link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
165 link->io.NumPorts2 = 16;
166 link->io.Attributes2 = IO_DATA_PATH_WIDTH_16;
167 link->io.IOAddrLines = 5;
168
169 /* Interrupt setup */
170 link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
171 link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED;
172
173 link->irq.IRQInfo1 = IRQ_LEVEL_ID;
174
175 /* General socket configuration */
176 link->conf.Attributes = CONF_ENABLE_IRQ;
177 link->conf.Vcc = 50;
178 link->conf.IntType = INT_MEMORY_AND_IO;
179 link->conf.ConfigIndex = 1;
180 link->conf.Present = PRESENT_OPTION;
181
182 /* Register with Card Services */
183 link->next = dev_list;
184 dev_list = link;
185 client_reg.dev_info = &dev_info;
186 client_reg.EventMask =
187 CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
188 CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
189 CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
190 client_reg.event_handler = &avma1cs_event;
191 client_reg.Version = 0x0210;
192 client_reg.event_callback_args.client_data = link;
193 ret = pcmcia_register_client(&link->handle, &client_reg);
194 if (ret != 0) {
195 cs_error(link->handle, RegisterClient, ret);
196 avma1cs_detach(link);
197 return NULL;
198 }
199
200 return link;
201} /* avma1cs_attach */
202
203/*======================================================================
204
205 This deletes a driver "instance". The device is de-registered
206 with Card Services. If it has been released, all local data
207 structures are freed. Otherwise, the structures will be freed
208 when the device is released.
209
210======================================================================*/
211
212static void avma1cs_detach(dev_link_t *link)
213{
214 dev_link_t **linkp;
215
216 DEBUG(0, "avma1cs_detach(0x%p)\n", link);
217
218 /* Locate device structure */
219 for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
220 if (*linkp == link) break;
221 if (*linkp == NULL)
222 return;
223
224 /*
225 If the device is currently configured and active, we won't
226 actually delete it yet. Instead, it is marked so that when
227 the release() function is called, that will trigger a proper
228 detach().
229 */
230 if (link->state & DEV_CONFIG) {
231#ifdef PCMCIA_DEBUG
232 printk(KERN_DEBUG "avma1_cs: detach postponed, '%s' "
233 "still locked\n", link->dev->dev_name);
234#endif
235 link->state |= DEV_STALE_LINK;
236 return;
237 }
238
239 /* Break the link with Card Services */
240 if (link->handle)
241 pcmcia_deregister_client(link->handle);
242
243 /* Unlink device structure, free pieces */
244 *linkp = link->next;
245 if (link->priv) {
246 kfree(link->priv);
247 }
248 kfree(link);
249
250} /* avma1cs_detach */
251
252/*======================================================================
253
254 avma1cs_config() is scheduled to run after a CARD_INSERTION event
255 is received, to configure the PCMCIA socket, and to make the
256 ethernet device available to the system.
257
258======================================================================*/
259
260static int get_tuple(client_handle_t handle, tuple_t *tuple,
261 cisparse_t *parse)
262{
263 int i = pcmcia_get_tuple_data(handle, tuple);
264 if (i != CS_SUCCESS) return i;
265 return pcmcia_parse_tuple(handle, tuple, parse);
266}
267
268static int first_tuple(client_handle_t handle, tuple_t *tuple,
269 cisparse_t *parse)
270{
271 int i = pcmcia_get_first_tuple(handle, tuple);
272 if (i != CS_SUCCESS) return i;
273 return get_tuple(handle, tuple, parse);
274}
275
276static int next_tuple(client_handle_t handle, tuple_t *tuple,
277 cisparse_t *parse)
278{
279 int i = pcmcia_get_next_tuple(handle, tuple);
280 if (i != CS_SUCCESS) return i;
281 return get_tuple(handle, tuple, parse);
282}
283
284static void avma1cs_config(dev_link_t *link)
285{
286 client_handle_t handle;
287 tuple_t tuple;
288 cisparse_t parse;
289 cistpl_cftable_entry_t *cf = &parse.cftable_entry;
290 local_info_t *dev;
291 int i;
292 u_char buf[64];
293 char devname[128];
294 IsdnCard_t icard;
295 int busy = 0;
296
297 handle = link->handle;
298 dev = link->priv;
299
300 DEBUG(0, "avma1cs_config(0x%p)\n", link);
301
302 /*
303 This reads the card's CONFIG tuple to find its configuration
304 registers.
305 */
306 do {
307 tuple.DesiredTuple = CISTPL_CONFIG;
308 i = pcmcia_get_first_tuple(handle, &tuple);
309 if (i != CS_SUCCESS) break;
310 tuple.TupleData = buf;
311 tuple.TupleDataMax = 64;
312 tuple.TupleOffset = 0;
313 i = pcmcia_get_tuple_data(handle, &tuple);
314 if (i != CS_SUCCESS) break;
315 i = pcmcia_parse_tuple(handle, &tuple, &parse);
316 if (i != CS_SUCCESS) break;
317 link->conf.ConfigBase = parse.config.base;
318 } while (0);
319 if (i != CS_SUCCESS) {
320 cs_error(link->handle, ParseTuple, i);
321 link->state &= ~DEV_CONFIG_PENDING;
322 return;
323 }
324
325 /* Configure card */
326 link->state |= DEV_CONFIG;
327
328 do {
329
330 tuple.Attributes = 0;
331 tuple.TupleData = buf;
332 tuple.TupleDataMax = 254;
333 tuple.TupleOffset = 0;
334 tuple.DesiredTuple = CISTPL_VERS_1;
335
336 devname[0] = 0;
337 if( !first_tuple(handle, &tuple, &parse) && parse.version_1.ns > 1 ) {
338 strlcpy(devname,parse.version_1.str + parse.version_1.ofs[1],
339 sizeof(devname));
340 }
341 /*
342 * find IO port
343 */
344 tuple.TupleData = (cisdata_t *)buf;
345 tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
346 tuple.Attributes = 0;
347 tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
348 i = first_tuple(handle, &tuple, &parse);
349 while (i == CS_SUCCESS) {
350 if (cf->io.nwin > 0) {
351 link->conf.ConfigIndex = cf->index;
352 link->io.BasePort1 = cf->io.win[0].base;
353 link->io.NumPorts1 = cf->io.win[0].len;
354 link->io.NumPorts2 = 0;
355 printk(KERN_INFO "avma1_cs: testing i/o %#x-%#x\n",
356 link->io.BasePort1,
357 link->io.BasePort1+link->io.NumPorts1 - 1);
358 i = pcmcia_request_io(link->handle, &link->io);
359 if (i == CS_SUCCESS) goto found_port;
360 }
361 i = next_tuple(handle, &tuple, &parse);
362 }
363
364found_port:
365 if (i != CS_SUCCESS) {
366 cs_error(link->handle, RequestIO, i);
367 break;
368 }
369
370 /*
371 * allocate an interrupt line
372 */
373 i = pcmcia_request_irq(link->handle, &link->irq);
374 if (i != CS_SUCCESS) {
375 cs_error(link->handle, RequestIRQ, i);
376 pcmcia_release_io(link->handle, &link->io);
377 break;
378 }
379
380 /*
381 * configure the PCMCIA socket
382 */
383 i = pcmcia_request_configuration(link->handle, &link->conf);
384 if (i != CS_SUCCESS) {
385 cs_error(link->handle, RequestConfiguration, i);
386 pcmcia_release_io(link->handle, &link->io);
387 pcmcia_release_irq(link->handle, &link->irq);
388 break;
389 }
390
391 } while (0);
392
393 /* At this point, the dev_node_t structure(s) should be
394 initialized and arranged in a linked list at link->dev. */
395
396 strcpy(dev->node.dev_name, "A1");
397 dev->node.major = 45;
398 dev->node.minor = 0;
399 link->dev = &dev->node;
400
401 link->state &= ~DEV_CONFIG_PENDING;
402 /* If any step failed, release any partially configured state */
403 if (i != 0) {
404 avma1cs_release(link);
405 return;
406 }
407
408 printk(KERN_NOTICE "avma1_cs: checking at i/o %#x, irq %d\n",
409 link->io.BasePort1, link->irq.AssignedIRQ);
410
411 icard.para[0] = link->irq.AssignedIRQ;
412 icard.para[1] = link->io.BasePort1;
413 icard.protocol = isdnprot;
414 icard.typ = ISDN_CTYPE_A1_PCMCIA;
415
416 i = hisax_init_pcmcia(link, &busy, &icard);
417 if (i < 0) {
418 printk(KERN_ERR "avma1_cs: failed to initialize AVM A1 PCMCIA %d at i/o %#x\n", i, link->io.BasePort1);
419 avma1cs_release(link);
420 return;
421 }
422 dev->node.minor = i;
423
424} /* avma1cs_config */
425
426/*======================================================================
427
428 After a card is removed, avma1cs_release() will unregister the net
429 device, and release the PCMCIA configuration. If the device is
430 still open, this will be postponed until it is closed.
431
432======================================================================*/
433
434static void avma1cs_release(dev_link_t *link)
435{
436 local_info_t *local = link->priv;
437
438 DEBUG(0, "avma1cs_release(0x%p)\n", link);
439
440 /* no unregister function with hisax */
441 HiSax_closecard(local->node.minor);
442
443 /* Unlink the device chain */
444 link->dev = NULL;
445
446 /* Don't bother checking to see if these succeed or not */
447 pcmcia_release_configuration(link->handle);
448 pcmcia_release_io(link->handle, &link->io);
449 pcmcia_release_irq(link->handle, &link->irq);
450 link->state &= ~DEV_CONFIG;
451
452 if (link->state & DEV_STALE_LINK)
453 avma1cs_detach(link);
454} /* avma1cs_release */
455
456/*======================================================================
457
458 The card status event handler. Mostly, this schedules other
459 stuff to run after an event is received. A CARD_REMOVAL event
460 also sets some flags to discourage the net drivers from trying
461 to talk to the card any more.
462
463 When a CARD_REMOVAL event is received, we immediately set a flag
464 to block future accesses to this device. All the functions that
465 actually access the device should check this flag to make sure
466 the card is still present.
467
468======================================================================*/
469
470static int avma1cs_event(event_t event, int priority,
471 event_callback_args_t *args)
472{
473 dev_link_t *link = args->client_data;
474
475 DEBUG(1, "avma1cs_event(0x%06x)\n", event);
476
477 switch (event) {
478 case CS_EVENT_CARD_REMOVAL:
479 if (link->state & DEV_CONFIG)
480 avma1cs_release(link);
481 break;
482 case CS_EVENT_CARD_INSERTION:
483 link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
484 avma1cs_config(link);
485 break;
486 case CS_EVENT_PM_SUSPEND:
487 link->state |= DEV_SUSPEND;
488 /* Fall through... */
489 case CS_EVENT_RESET_PHYSICAL:
490 if (link->state & DEV_CONFIG)
491 pcmcia_release_configuration(link->handle);
492 break;
493 case CS_EVENT_PM_RESUME:
494 link->state &= ~DEV_SUSPEND;
495 /* Fall through... */
496 case CS_EVENT_CARD_RESET:
497 if (link->state & DEV_CONFIG)
498 pcmcia_request_configuration(link->handle, &link->conf);
499 break;
500 }
501 return 0;
502} /* avma1cs_event */
503
504static struct pcmcia_driver avma1cs_driver = {
505 .owner = THIS_MODULE,
506 .drv = {
507 .name = "avma1_cs",
508 },
509 .attach = avma1cs_attach,
510 .detach = avma1cs_detach,
511};
512
513/*====================================================================*/
514
515static int __init init_avma1_cs(void)
516{
517 return(pcmcia_register_driver(&avma1cs_driver));
518}
519
520static void __exit exit_avma1_cs(void)
521{
522 pcmcia_unregister_driver(&avma1cs_driver);
523 BUG_ON(dev_list != NULL);
524}
525
526module_init(init_avma1_cs);
527module_exit(exit_avma1_cs);
diff --git a/drivers/isdn/hisax/bkm_a4t.c b/drivers/isdn/hisax/bkm_a4t.c
new file mode 100644
index 000000000000..f410f628a3e2
--- /dev/null
+++ b/drivers/isdn/hisax/bkm_a4t.c
@@ -0,0 +1,344 @@
1/* $Id: bkm_a4t.c,v 1.22.2.4 2004/01/14 16:04:48 keil Exp $
2 *
3 * low level stuff for T-Berkom A4T
4 *
5 * Author Roland Klabunde
6 * Copyright by Roland Klabunde <R.Klabunde@Berkom.de>
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 */
12
13
14#include <linux/config.h>
15#include <linux/init.h>
16#include "hisax.h"
17#include "isac.h"
18#include "hscx.h"
19#include "jade.h"
20#include "isdnl1.h"
21#include <linux/pci.h>
22#include "bkm_ax.h"
23
24extern const char *CardType[];
25
26const char *bkm_a4t_revision = "$Revision: 1.22.2.4 $";
27
28
29static inline u_char
30readreg(unsigned int ale, unsigned long adr, u_char off)
31{
32 register u_int ret;
33 unsigned int *po = (unsigned int *) adr; /* Postoffice */
34
35 *po = (GCS_2 | PO_WRITE | off);
36 __WAITI20__(po);
37 *po = (ale | PO_READ);
38 __WAITI20__(po);
39 ret = *po;
40 return ((unsigned char) ret);
41}
42
43
44static inline void
45readfifo(unsigned int ale, unsigned long adr, u_char off, u_char * data, int size)
46{
47 int i;
48 for (i = 0; i < size; i++)
49 *data++ = readreg(ale, adr, off);
50}
51
52
53static inline void
54writereg(unsigned int ale, unsigned long adr, u_char off, u_char data)
55{
56 unsigned int *po = (unsigned int *) adr; /* Postoffice */
57 *po = (GCS_2 | PO_WRITE | off);
58 __WAITI20__(po);
59 *po = (ale | PO_WRITE | data);
60 __WAITI20__(po);
61}
62
63
64static inline void
65writefifo(unsigned int ale, unsigned long adr, u_char off, u_char * data, int size)
66{
67 int i;
68
69 for (i = 0; i < size; i++)
70 writereg(ale, adr, off, *data++);
71}
72
73
74/* Interface functions */
75
76static u_char
77ReadISAC(struct IsdnCardState *cs, u_char offset)
78{
79 return (readreg(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, offset));
80}
81
82static void
83WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
84{
85 writereg(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, offset, value);
86}
87
88static void
89ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
90{
91 readfifo(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, 0, data, size);
92}
93
94static void
95WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
96{
97 writefifo(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, 0, data, size);
98}
99
100static u_char
101ReadJADE(struct IsdnCardState *cs, int jade, u_char offset)
102{
103 return (readreg(cs->hw.ax.jade_ale, cs->hw.ax.jade_adr, offset + (jade == -1 ? 0 : (jade ? 0xC0 : 0x80))));
104}
105
106static void
107WriteJADE(struct IsdnCardState *cs, int jade, u_char offset, u_char value)
108{
109 writereg(cs->hw.ax.jade_ale, cs->hw.ax.jade_adr, offset + (jade == -1 ? 0 : (jade ? 0xC0 : 0x80)), value);
110}
111
112/*
113 * fast interrupt JADE stuff goes here
114 */
115
116#define READJADE(cs, nr, reg) readreg(cs->hw.ax.jade_ale,\
117 cs->hw.ax.jade_adr, reg + (nr == -1 ? 0 : (nr ? 0xC0 : 0x80)))
118#define WRITEJADE(cs, nr, reg, data) writereg(cs->hw.ax.jade_ale,\
119 cs->hw.ax.jade_adr, reg + (nr == -1 ? 0 : (nr ? 0xC0 : 0x80)), data)
120
121#define READJADEFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.ax.jade_ale,\
122 cs->hw.ax.jade_adr, (nr == -1 ? 0 : (nr ? 0xC0 : 0x80)), ptr, cnt)
123#define WRITEJADEFIFO(cs, nr, ptr, cnt) writefifo( cs->hw.ax.jade_ale,\
124 cs->hw.ax.jade_adr, (nr == -1 ? 0 : (nr ? 0xC0 : 0x80)), ptr, cnt)
125
126#include "jade_irq.c"
127
128static irqreturn_t
129bkm_interrupt(int intno, void *dev_id, struct pt_regs *regs)
130{
131 struct IsdnCardState *cs = dev_id;
132 u_char val = 0;
133 u_long flags;
134 I20_REGISTER_FILE *pI20_Regs;
135
136 spin_lock_irqsave(&cs->lock, flags);
137 pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base);
138
139 /* ISDN interrupt pending? */
140 if (pI20_Regs->i20IntStatus & intISDN) {
141 /* Reset the ISDN interrupt */
142 pI20_Regs->i20IntStatus = intISDN;
143 /* Disable ISDN interrupt */
144 pI20_Regs->i20IntCtrl &= ~intISDN;
145 /* Channel A first */
146 val = readreg(cs->hw.ax.jade_ale, cs->hw.ax.jade_adr, jade_HDLC_ISR + 0x80);
147 if (val) {
148 jade_int_main(cs, val, 0);
149 }
150 /* Channel B */
151 val = readreg(cs->hw.ax.jade_ale, cs->hw.ax.jade_adr, jade_HDLC_ISR + 0xC0);
152 if (val) {
153 jade_int_main(cs, val, 1);
154 }
155 /* D-Channel */
156 val = readreg(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, ISAC_ISTA);
157 if (val) {
158 isac_interrupt(cs, val);
159 }
160 /* Reenable ISDN interrupt */
161 pI20_Regs->i20IntCtrl |= intISDN;
162 spin_unlock_irqrestore(&cs->lock, flags);
163 return IRQ_HANDLED;
164 } else {
165 spin_unlock_irqrestore(&cs->lock, flags);
166 return IRQ_NONE;
167 }
168}
169
170void
171release_io_bkm(struct IsdnCardState *cs)
172{
173 if (cs->hw.ax.base) {
174 iounmap((void *) cs->hw.ax.base);
175 cs->hw.ax.base = 0;
176 }
177}
178
179static void
180enable_bkm_int(struct IsdnCardState *cs, unsigned bEnable)
181{
182 if (cs->typ == ISDN_CTYPE_BKM_A4T) {
183 I20_REGISTER_FILE *pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base);
184 if (bEnable)
185 pI20_Regs->i20IntCtrl |= (intISDN | intPCI);
186 else
187 /* CAUTION: This disables the video capture driver too */
188 pI20_Regs->i20IntCtrl &= ~(intISDN | intPCI);
189 }
190}
191
192static void
193reset_bkm(struct IsdnCardState *cs)
194{
195 if (cs->typ == ISDN_CTYPE_BKM_A4T) {
196 I20_REGISTER_FILE *pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base);
197 /* Issue the I20 soft reset */
198 pI20_Regs->i20SysControl = 0xFF; /* all in */
199 mdelay(10);
200 /* Remove the soft reset */
201 pI20_Regs->i20SysControl = sysRESET | 0xFF;
202 mdelay(10);
203 /* Set our configuration */
204 pI20_Regs->i20SysControl = sysRESET | sysCFG;
205 /* Issue ISDN reset */
206 pI20_Regs->i20GuestControl = guestWAIT_CFG |
207 g_A4T_JADE_RES |
208 g_A4T_ISAR_RES |
209 g_A4T_ISAC_RES |
210 g_A4T_JADE_BOOTR |
211 g_A4T_ISAR_BOOTR;
212 mdelay(10);
213
214 /* Remove RESET state from ISDN */
215 pI20_Regs->i20GuestControl &= ~(g_A4T_ISAC_RES |
216 g_A4T_JADE_RES |
217 g_A4T_ISAR_RES);
218 mdelay(10);
219 }
220}
221
222static int
223BKM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
224{
225 u_long flags;
226
227 switch (mt) {
228 case CARD_RESET:
229 /* Disable ints */
230 spin_lock_irqsave(&cs->lock, flags);
231 enable_bkm_int(cs, 0);
232 reset_bkm(cs);
233 spin_unlock_irqrestore(&cs->lock, flags);
234 return (0);
235 case CARD_RELEASE:
236 /* Sanity */
237 spin_lock_irqsave(&cs->lock, flags);
238 enable_bkm_int(cs, 0);
239 reset_bkm(cs);
240 spin_unlock_irqrestore(&cs->lock, flags);
241 release_io_bkm(cs);
242 return (0);
243 case CARD_INIT:
244 spin_lock_irqsave(&cs->lock, flags);
245 clear_pending_isac_ints(cs);
246 clear_pending_jade_ints(cs);
247 initisac(cs);
248 initjade(cs);
249 /* Enable ints */
250 enable_bkm_int(cs, 1);
251 spin_unlock_irqrestore(&cs->lock, flags);
252 return (0);
253 case CARD_TEST:
254 return (0);
255 }
256 return (0);
257}
258
259static struct pci_dev *dev_a4t __initdata = NULL;
260
261int __init
262setup_bkm_a4t(struct IsdnCard *card)
263{
264 struct IsdnCardState *cs = card->cs;
265 char tmp[64];
266 u_int pci_memaddr = 0, found = 0;
267 I20_REGISTER_FILE *pI20_Regs;
268#ifdef CONFIG_PCI
269#endif
270
271 strcpy(tmp, bkm_a4t_revision);
272 printk(KERN_INFO "HiSax: T-Berkom driver Rev. %s\n", HiSax_getrev(tmp));
273 if (cs->typ == ISDN_CTYPE_BKM_A4T) {
274 cs->subtyp = BKM_A4T;
275 } else
276 return (0);
277
278#ifdef CONFIG_PCI
279 while ((dev_a4t = pci_find_device(PCI_VENDOR_ID_ZORAN,
280 PCI_DEVICE_ID_ZORAN_36120, dev_a4t))) {
281 u16 sub_sys;
282 u16 sub_vendor;
283
284 sub_vendor = dev_a4t->subsystem_vendor;
285 sub_sys = dev_a4t->subsystem_device;
286 if ((sub_sys == PCI_DEVICE_ID_BERKOM_A4T) && (sub_vendor == PCI_VENDOR_ID_BERKOM)) {
287 if (pci_enable_device(dev_a4t))
288 return(0);
289 found = 1;
290 pci_memaddr = pci_resource_start(dev_a4t, 0);
291 cs->irq = dev_a4t->irq;
292 break;
293 }
294 }
295 if (!found) {
296 printk(KERN_WARNING "HiSax: %s: Card not found\n", CardType[card->typ]);
297 return (0);
298 }
299 if (!cs->irq) { /* IRQ range check ?? */
300 printk(KERN_WARNING "HiSax: %s: No IRQ\n", CardType[card->typ]);
301 return (0);
302 }
303 if (!pci_memaddr) {
304 printk(KERN_WARNING "HiSax: %s: No Memory base address\n", CardType[card->typ]);
305 return (0);
306 }
307 cs->hw.ax.base = (long) ioremap(pci_memaddr, 4096);
308 /* Check suspecious address */
309 pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base);
310 if ((pI20_Regs->i20IntStatus & 0x8EFFFFFF) != 0) {
311 printk(KERN_WARNING "HiSax: %s address %lx-%lx suspecious\n",
312 CardType[card->typ], cs->hw.ax.base, cs->hw.ax.base + 4096);
313 iounmap((void *) cs->hw.ax.base);
314 cs->hw.ax.base = 0;
315 return (0);
316 }
317 cs->hw.ax.isac_adr = cs->hw.ax.base + PO_OFFSET;
318 cs->hw.ax.jade_adr = cs->hw.ax.base + PO_OFFSET;
319 cs->hw.ax.isac_ale = GCS_1;
320 cs->hw.ax.jade_ale = GCS_3;
321#else
322 printk(KERN_WARNING "HiSax: %s: NO_PCI_BIOS\n", CardType[card->typ]);
323 printk(KERN_WARNING "HiSax: %s: unable to configure\n", CardType[card->typ]);
324 return (0);
325#endif /* CONFIG_PCI */
326 printk(KERN_INFO "HiSax: %s: Card configured at 0x%lX IRQ %d\n",
327 CardType[card->typ], cs->hw.ax.base, cs->irq);
328
329 setup_isac(cs);
330 cs->readisac = &ReadISAC;
331 cs->writeisac = &WriteISAC;
332 cs->readisacfifo = &ReadISACfifo;
333 cs->writeisacfifo = &WriteISACfifo;
334 cs->BC_Read_Reg = &ReadJADE;
335 cs->BC_Write_Reg = &WriteJADE;
336 cs->BC_Send_Data = &jade_fill_fifo;
337 cs->cardmsg = &BKM_card_msg;
338 cs->irq_func = &bkm_interrupt;
339 cs->irq_flags |= SA_SHIRQ;
340 ISACVersion(cs, "Telekom A4T:");
341 /* Jade version */
342 JadeVersion(cs, "Telekom A4T:");
343 return (1);
344}
diff --git a/drivers/isdn/hisax/bkm_a8.c b/drivers/isdn/hisax/bkm_a8.c
new file mode 100644
index 000000000000..94bb83ce7fd8
--- /dev/null
+++ b/drivers/isdn/hisax/bkm_a8.c
@@ -0,0 +1,451 @@
1/* $Id: bkm_a8.c,v 1.22.2.4 2004/01/15 14:02:34 keil Exp $
2 *
3 * low level stuff for Scitel Quadro (4*S0, passive)
4 *
5 * Author Roland Klabunde
6 * Copyright by Roland Klabunde <R.Klabunde@Berkom.de>
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 */
12
13
14#include <linux/config.h>
15#include <linux/init.h>
16#include "hisax.h"
17#include "isac.h"
18#include "ipac.h"
19#include "hscx.h"
20#include "isdnl1.h"
21#include <linux/pci.h>
22#include "bkm_ax.h"
23
24#ifdef CONFIG_PCI
25
26#define ATTEMPT_PCI_REMAPPING /* Required for PLX rev 1 */
27
28extern const char *CardType[];
29
30const char sct_quadro_revision[] = "$Revision: 1.22.2.4 $";
31
32static const char *sct_quadro_subtypes[] =
33{
34 "",
35 "#1",
36 "#2",
37 "#3",
38 "#4"
39};
40
41
42#define wordout(addr,val) outw(val,addr)
43#define wordin(addr) inw(addr)
44
45static inline u_char
46readreg(unsigned int ale, unsigned int adr, u_char off)
47{
48 register u_char ret;
49 wordout(ale, off);
50 ret = wordin(adr) & 0xFF;
51 return (ret);
52}
53
54static inline void
55readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
56{
57 int i;
58 wordout(ale, off);
59 for (i = 0; i < size; i++)
60 data[i] = wordin(adr) & 0xFF;
61}
62
63
64static inline void
65writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
66{
67 wordout(ale, off);
68 wordout(adr, data);
69}
70
71static inline void
72writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
73{
74 int i;
75 wordout(ale, off);
76 for (i = 0; i < size; i++)
77 wordout(adr, data[i]);
78}
79
80/* Interface functions */
81
82static u_char
83ReadISAC(struct IsdnCardState *cs, u_char offset)
84{
85 return (readreg(cs->hw.ax.base, cs->hw.ax.data_adr, offset | 0x80));
86}
87
88static void
89WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
90{
91 writereg(cs->hw.ax.base, cs->hw.ax.data_adr, offset | 0x80, value);
92}
93
94static void
95ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
96{
97 readfifo(cs->hw.ax.base, cs->hw.ax.data_adr, 0x80, data, size);
98}
99
100static void
101WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
102{
103 writefifo(cs->hw.ax.base, cs->hw.ax.data_adr, 0x80, data, size);
104}
105
106
107static u_char
108ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
109{
110 return (readreg(cs->hw.ax.base, cs->hw.ax.data_adr, offset + (hscx ? 0x40 : 0)));
111}
112
113static void
114WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
115{
116 writereg(cs->hw.ax.base, cs->hw.ax.data_adr, offset + (hscx ? 0x40 : 0), value);
117}
118
119/* Set the specific ipac to active */
120static void
121set_ipac_active(struct IsdnCardState *cs, u_int active)
122{
123 /* set irq mask */
124 writereg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_MASK,
125 active ? 0xc0 : 0xff);
126}
127
128/*
129 * fast interrupt HSCX stuff goes here
130 */
131
132#define READHSCX(cs, nr, reg) readreg(cs->hw.ax.base, \
133 cs->hw.ax.data_adr, reg + (nr ? 0x40 : 0))
134#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.ax.base, \
135 cs->hw.ax.data_adr, reg + (nr ? 0x40 : 0), data)
136#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.ax.base, \
137 cs->hw.ax.data_adr, (nr ? 0x40 : 0), ptr, cnt)
138#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.ax.base, \
139 cs->hw.ax.data_adr, (nr ? 0x40 : 0), ptr, cnt)
140
141#include "hscx_irq.c"
142
143static irqreturn_t
144bkm_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs)
145{
146 struct IsdnCardState *cs = dev_id;
147 u_char ista, val, icnt = 5;
148 u_long flags;
149
150 spin_lock_irqsave(&cs->lock, flags);
151 ista = readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ISTA);
152 if (!(ista & 0x3f)) { /* not this IPAC */
153 spin_unlock_irqrestore(&cs->lock, flags);
154 return IRQ_NONE;
155 }
156 Start_IPAC:
157 if (cs->debug & L1_DEB_IPAC)
158 debugl1(cs, "IPAC ISTA %02X", ista);
159 if (ista & 0x0f) {
160 val = readreg(cs->hw.ax.base, cs->hw.ax.data_adr, HSCX_ISTA + 0x40);
161 if (ista & 0x01)
162 val |= 0x01;
163 if (ista & 0x04)
164 val |= 0x02;
165 if (ista & 0x08)
166 val |= 0x04;
167 if (val) {
168 hscx_int_main(cs, val);
169 }
170 }
171 if (ista & 0x20) {
172 val = 0xfe & readreg(cs->hw.ax.base, cs->hw.ax.data_adr, ISAC_ISTA | 0x80);
173 if (val) {
174 isac_interrupt(cs, val);
175 }
176 }
177 if (ista & 0x10) {
178 val = 0x01;
179 isac_interrupt(cs, val);
180 }
181 ista = readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ISTA);
182 if ((ista & 0x3f) && icnt) {
183 icnt--;
184 goto Start_IPAC;
185 }
186 if (!icnt)
187 printk(KERN_WARNING "HiSax: %s (%s) IRQ LOOP\n",
188 CardType[cs->typ],
189 sct_quadro_subtypes[cs->subtyp]);
190 writereg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_MASK, 0xFF);
191 writereg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_MASK, 0xC0);
192 spin_unlock_irqrestore(&cs->lock, flags);
193 return IRQ_HANDLED;
194}
195
196void
197release_io_sct_quadro(struct IsdnCardState *cs)
198{
199 release_region(cs->hw.ax.base & 0xffffffc0, 128);
200 if (cs->subtyp == SCT_1)
201 release_region(cs->hw.ax.plx_adr, 64);
202}
203
204static void
205enable_bkm_int(struct IsdnCardState *cs, unsigned bEnable)
206{
207 if (cs->typ == ISDN_CTYPE_SCT_QUADRO) {
208 if (bEnable)
209 wordout(cs->hw.ax.plx_adr + 0x4C, (wordin(cs->hw.ax.plx_adr + 0x4C) | 0x41));
210 else
211 wordout(cs->hw.ax.plx_adr + 0x4C, (wordin(cs->hw.ax.plx_adr + 0x4C) & ~0x41));
212 }
213}
214
215static void
216reset_bkm(struct IsdnCardState *cs)
217{
218 if (cs->subtyp == SCT_1) {
219 wordout(cs->hw.ax.plx_adr + 0x50, (wordin(cs->hw.ax.plx_adr + 0x50) & ~4));
220 mdelay(10);
221 /* Remove the soft reset */
222 wordout(cs->hw.ax.plx_adr + 0x50, (wordin(cs->hw.ax.plx_adr + 0x50) | 4));
223 mdelay(10);
224 }
225}
226
227static int
228BKM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
229{
230 u_long flags;
231
232 switch (mt) {
233 case CARD_RESET:
234 spin_lock_irqsave(&cs->lock, flags);
235 /* Disable ints */
236 set_ipac_active(cs, 0);
237 enable_bkm_int(cs, 0);
238 reset_bkm(cs);
239 spin_unlock_irqrestore(&cs->lock, flags);
240 return (0);
241 case CARD_RELEASE:
242 /* Sanity */
243 spin_lock_irqsave(&cs->lock, flags);
244 set_ipac_active(cs, 0);
245 enable_bkm_int(cs, 0);
246 spin_unlock_irqrestore(&cs->lock, flags);
247 release_io_sct_quadro(cs);
248 return (0);
249 case CARD_INIT:
250 spin_lock_irqsave(&cs->lock, flags);
251 cs->debug |= L1_DEB_IPAC;
252 set_ipac_active(cs, 1);
253 inithscxisac(cs, 3);
254 /* Enable ints */
255 enable_bkm_int(cs, 1);
256 spin_unlock_irqrestore(&cs->lock, flags);
257 return (0);
258 case CARD_TEST:
259 return (0);
260 }
261 return (0);
262}
263
264int __init
265sct_alloc_io(u_int adr, u_int len)
266{
267 if (!request_region(adr, len, "scitel")) {
268 printk(KERN_WARNING
269 "HiSax: Scitel port %#x-%#x already in use\n",
270 adr, adr + len);
271 return (1);
272 }
273 return(0);
274}
275
276static struct pci_dev *dev_a8 __initdata = NULL;
277static u16 sub_vendor_id __initdata = 0;
278static u16 sub_sys_id __initdata = 0;
279static u_char pci_bus __initdata = 0;
280static u_char pci_device_fn __initdata = 0;
281static u_char pci_irq __initdata = 0;
282
283#endif /* CONFIG_PCI */
284
285int __init
286setup_sct_quadro(struct IsdnCard *card)
287{
288#ifdef CONFIG_PCI
289 struct IsdnCardState *cs = card->cs;
290 char tmp[64];
291 u_char pci_rev_id;
292 u_int found = 0;
293 u_int pci_ioaddr1, pci_ioaddr2, pci_ioaddr3, pci_ioaddr4, pci_ioaddr5;
294
295 strcpy(tmp, sct_quadro_revision);
296 printk(KERN_INFO "HiSax: T-Berkom driver Rev. %s\n", HiSax_getrev(tmp));
297 if (cs->typ == ISDN_CTYPE_SCT_QUADRO) {
298 cs->subtyp = SCT_1; /* Preset */
299 } else
300 return (0);
301
302 /* Identify subtype by para[0] */
303 if (card->para[0] >= SCT_1 && card->para[0] <= SCT_4)
304 cs->subtyp = card->para[0];
305 else {
306 printk(KERN_WARNING "HiSax: %s: Invalid subcontroller in configuration, default to 1\n",
307 CardType[card->typ]);
308 return (0);
309 }
310 if ((cs->subtyp != SCT_1) && ((sub_sys_id != PCI_DEVICE_ID_BERKOM_SCITEL_QUADRO) ||
311 (sub_vendor_id != PCI_VENDOR_ID_BERKOM)))
312 return (0);
313 if (cs->subtyp == SCT_1) {
314 while ((dev_a8 = pci_find_device(PCI_VENDOR_ID_PLX,
315 PCI_DEVICE_ID_PLX_9050, dev_a8))) {
316
317 sub_vendor_id = dev_a8->subsystem_vendor;
318 sub_sys_id = dev_a8->subsystem_device;
319 if ((sub_sys_id == PCI_DEVICE_ID_BERKOM_SCITEL_QUADRO) &&
320 (sub_vendor_id == PCI_VENDOR_ID_BERKOM)) {
321 if (pci_enable_device(dev_a8))
322 return(0);
323 pci_ioaddr1 = pci_resource_start(dev_a8, 1);
324 pci_irq = dev_a8->irq;
325 pci_bus = dev_a8->bus->number;
326 pci_device_fn = dev_a8->devfn;
327 found = 1;
328 break;
329 }
330 }
331 if (!found) {
332 printk(KERN_WARNING "HiSax: %s (%s): Card not found\n",
333 CardType[card->typ],
334 sct_quadro_subtypes[cs->subtyp]);
335 return (0);
336 }
337#ifdef ATTEMPT_PCI_REMAPPING
338/* HACK: PLX revision 1 bug: PLX address bit 7 must not be set */
339 pci_read_config_byte(dev_a8, PCI_REVISION_ID, &pci_rev_id);
340 if ((pci_ioaddr1 & 0x80) && (pci_rev_id == 1)) {
341 printk(KERN_WARNING "HiSax: %s (%s): PLX rev 1, remapping required!\n",
342 CardType[card->typ],
343 sct_quadro_subtypes[cs->subtyp]);
344 /* Restart PCI negotiation */
345 pci_write_config_dword(dev_a8, PCI_BASE_ADDRESS_1, (u_int) - 1);
346 /* Move up by 0x80 byte */
347 pci_ioaddr1 += 0x80;
348 pci_ioaddr1 &= PCI_BASE_ADDRESS_IO_MASK;
349 pci_write_config_dword(dev_a8, PCI_BASE_ADDRESS_1, pci_ioaddr1);
350 dev_a8->resource[ 1].start = pci_ioaddr1;
351 }
352#endif /* End HACK */
353 }
354 if (!pci_irq) { /* IRQ range check ?? */
355 printk(KERN_WARNING "HiSax: %s (%s): No IRQ\n",
356 CardType[card->typ],
357 sct_quadro_subtypes[cs->subtyp]);
358 return (0);
359 }
360 pci_read_config_dword(dev_a8, PCI_BASE_ADDRESS_1, &pci_ioaddr1);
361 pci_read_config_dword(dev_a8, PCI_BASE_ADDRESS_2, &pci_ioaddr2);
362 pci_read_config_dword(dev_a8, PCI_BASE_ADDRESS_3, &pci_ioaddr3);
363 pci_read_config_dword(dev_a8, PCI_BASE_ADDRESS_4, &pci_ioaddr4);
364 pci_read_config_dword(dev_a8, PCI_BASE_ADDRESS_5, &pci_ioaddr5);
365 if (!pci_ioaddr1 || !pci_ioaddr2 || !pci_ioaddr3 || !pci_ioaddr4 || !pci_ioaddr5) {
366 printk(KERN_WARNING "HiSax: %s (%s): No IO base address(es)\n",
367 CardType[card->typ],
368 sct_quadro_subtypes[cs->subtyp]);
369 return (0);
370 }
371 pci_ioaddr1 &= PCI_BASE_ADDRESS_IO_MASK;
372 pci_ioaddr2 &= PCI_BASE_ADDRESS_IO_MASK;
373 pci_ioaddr3 &= PCI_BASE_ADDRESS_IO_MASK;
374 pci_ioaddr4 &= PCI_BASE_ADDRESS_IO_MASK;
375 pci_ioaddr5 &= PCI_BASE_ADDRESS_IO_MASK;
376 /* Take over */
377 cs->irq = pci_irq;
378 cs->irq_flags |= SA_SHIRQ;
379 /* pci_ioaddr1 is unique to all subdevices */
380 /* pci_ioaddr2 is for the fourth subdevice only */
381 /* pci_ioaddr3 is for the third subdevice only */
382 /* pci_ioaddr4 is for the second subdevice only */
383 /* pci_ioaddr5 is for the first subdevice only */
384 cs->hw.ax.plx_adr = pci_ioaddr1;
385 /* Enter all ipac_base addresses */
386 switch(cs->subtyp) {
387 case 1:
388 cs->hw.ax.base = pci_ioaddr5 + 0x00;
389 if (sct_alloc_io(pci_ioaddr1, 128))
390 return(0);
391 if (sct_alloc_io(pci_ioaddr5, 64))
392 return(0);
393 /* disable all IPAC */
394 writereg(pci_ioaddr5, pci_ioaddr5 + 4,
395 IPAC_MASK, 0xFF);
396 writereg(pci_ioaddr4 + 0x08, pci_ioaddr4 + 0x0c,
397 IPAC_MASK, 0xFF);
398 writereg(pci_ioaddr3 + 0x10, pci_ioaddr3 + 0x14,
399 IPAC_MASK, 0xFF);
400 writereg(pci_ioaddr2 + 0x20, pci_ioaddr2 + 0x24,
401 IPAC_MASK, 0xFF);
402 break;
403 case 2:
404 cs->hw.ax.base = pci_ioaddr4 + 0x08;
405 if (sct_alloc_io(pci_ioaddr4, 64))
406 return(0);
407 break;
408 case 3:
409 cs->hw.ax.base = pci_ioaddr3 + 0x10;
410 if (sct_alloc_io(pci_ioaddr3, 64))
411 return(0);
412 break;
413 case 4:
414 cs->hw.ax.base = pci_ioaddr2 + 0x20;
415 if (sct_alloc_io(pci_ioaddr2, 64))
416 return(0);
417 break;
418 }
419 /* For isac and hscx data path */
420 cs->hw.ax.data_adr = cs->hw.ax.base + 4;
421
422 printk(KERN_INFO "HiSax: %s (%s) configured at 0x%.4lX, 0x%.4lX, 0x%.4lX and IRQ %d\n",
423 CardType[card->typ],
424 sct_quadro_subtypes[cs->subtyp],
425 cs->hw.ax.plx_adr,
426 cs->hw.ax.base,
427 cs->hw.ax.data_adr,
428 cs->irq);
429
430 test_and_set_bit(HW_IPAC, &cs->HW_Flags);
431
432 cs->readisac = &ReadISAC;
433 cs->writeisac = &WriteISAC;
434 cs->readisacfifo = &ReadISACfifo;
435 cs->writeisacfifo = &WriteISACfifo;
436
437 cs->BC_Read_Reg = &ReadHSCX;
438 cs->BC_Write_Reg = &WriteHSCX;
439 cs->BC_Send_Data = &hscx_fill_fifo;
440 cs->cardmsg = &BKM_card_msg;
441 cs->irq_func = &bkm_interrupt_ipac;
442
443 printk(KERN_INFO "HiSax: %s (%s): IPAC Version %d\n",
444 CardType[card->typ],
445 sct_quadro_subtypes[cs->subtyp],
446 readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ID));
447 return (1);
448#else
449 printk(KERN_ERR "HiSax: bkm_a8 only supported on PCI Systems\n");
450#endif /* CONFIG_PCI */
451}
diff --git a/drivers/isdn/hisax/bkm_ax.h b/drivers/isdn/hisax/bkm_ax.h
new file mode 100644
index 000000000000..029e0a277661
--- /dev/null
+++ b/drivers/isdn/hisax/bkm_ax.h
@@ -0,0 +1,119 @@
1/* $Id: bkm_ax.h,v 1.5.6.3 2001/09/23 22:24:46 kai Exp $
2 *
3 * low level decls for T-Berkom cards A4T and Scitel Quadro (4*S0, passive)
4 *
5 * Author Roland Klabunde
6 * Copyright by Roland Klabunde <R.Klabunde@Berkom.de>
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 */
12
13#ifndef __BKM_AX_H__
14#define __BKM_AX_H__
15
16/* Supported boards (subtypes) */
17#define SCT_1 1
18#define SCT_2 2
19#define SCT_3 3
20#define SCT_4 4
21#define BKM_A4T 5
22
23#define PLX_ADDR_PLX 0x14 /* Addr PLX configuration */
24#define PLX_ADDR_ISAC 0x18 /* Addr ISAC */
25#define PLX_ADDR_HSCX 0x1C /* Addr HSCX */
26#define PLX_ADDR_ALE 0x20 /* Addr ALE */
27#define PLX_ADDR_ALEPLUS 0x24 /* Next Addr behind ALE */
28
29#define PLX_SUBVEN 0x2C /* Offset SubVendor */
30#define PLX_SUBSYS 0x2E /* Offset SubSystem */
31
32
33/* Application specific registers I20 (Siemens SZB6120H) */
34typedef struct {
35 /* Video front end horizontal configuration register */
36 volatile u_int i20VFEHorzCfg; /* Offset 00 */
37 /* Video front end vertical configuration register */
38 volatile u_int i20VFEVertCfg; /* Offset 04 */
39 /* Video front end scaler and pixel format register */
40 volatile u_int i20VFEScaler; /* Offset 08 */
41 /* Video display top register */
42 volatile u_int i20VDispTop; /* Offset 0C */
43 /* Video display bottom register */
44 volatile u_int i20VDispBottom; /* Offset 10 */
45 /* Video stride, status and frame grab register */
46 volatile u_int i20VidFrameGrab;/* Offset 14 */
47 /* Video display configuration register */
48 volatile u_int i20VDispCfg; /* Offset 18 */
49 /* Video masking map top */
50 volatile u_int i20VMaskTop; /* Offset 1C */
51 /* Video masking map bottom */
52 volatile u_int i20VMaskBottom; /* Offset 20 */
53 /* Overlay control register */
54 volatile u_int i20OvlyControl; /* Offset 24 */
55 /* System, PCI and general purpose pins control register */
56 volatile u_int i20SysControl; /* Offset 28 */
57#define sysRESET 0x01000000 /* bit 24:Softreset (Low) */
58 /* GPIO 4...0: Output fixed for our cfg! */
59#define sysCFG 0x000000E0 /* GPIO 7,6,5: Input */
60 /* General purpose pins and guest bus control register */
61 volatile u_int i20GuestControl;/* Offset 2C */
62#define guestWAIT_CFG 0x00005555 /* 4 PCI waits for all */
63#define guestISDN_INT_E 0x01000000 /* ISDN Int en (low) */
64#define guestVID_INT_E 0x02000000 /* Video interrupt en (low) */
65#define guestADI1_INT_R 0x04000000 /* ADI #1 int req (low) */
66#define guestADI2_INT_R 0x08000000 /* ADI #2 int req (low) */
67#define guestISDN_RES 0x10000000 /* ISDN reset bit (high) */
68#define guestADI1_INT_S 0x20000000 /* ADI #1 int pending (low) */
69#define guestADI2_INT_S 0x40000000 /* ADI #2 int pending (low) */
70#define guestISDN_INT_S 0x80000000 /* ISAC int pending (low) */
71
72#define g_A4T_JADE_RES 0x01000000 /* JADE Reset (High) */
73#define g_A4T_ISAR_RES 0x02000000 /* ISAR Reset (High) */
74#define g_A4T_ISAC_RES 0x04000000 /* ISAC Reset (High) */
75#define g_A4T_JADE_BOOTR 0x08000000 /* JADE enable boot SRAM (Low) NOT USED */
76#define g_A4T_ISAR_BOOTR 0x10000000 /* ISAR enable boot SRAM (Low) NOT USED */
77#define g_A4T_JADE_INT_S 0x20000000 /* JADE interrupt pnd (Low) */
78#define g_A4T_ISAR_INT_S 0x40000000 /* ISAR interrupt pnd (Low) */
79#define g_A4T_ISAC_INT_S 0x80000000 /* ISAC interrupt pnd (Low) */
80
81 volatile u_int i20CodeSource; /* Offset 30 */
82 volatile u_int i20CodeXferCtrl;/* Offset 34 */
83 volatile u_int i20CodeMemPtr; /* Offset 38 */
84
85 volatile u_int i20IntStatus; /* Offset 3C */
86 volatile u_int i20IntCtrl; /* Offset 40 */
87#define intISDN 0x40000000 /* GIRQ1En (ISAC/ADI) (High) */
88#define intVID 0x20000000 /* GIRQ0En (VSYNC) (High) */
89#define intCOD 0x10000000 /* CodRepIrqEn (High) */
90#define intPCI 0x01000000 /* PCI IntA enable (High) */
91
92 volatile u_int i20I2CCtrl; /* Offset 44 */
93} I20_REGISTER_FILE, *PI20_REGISTER_FILE;
94
95/*
96 * Postoffice structure for A4T
97 *
98 */
99#define PO_OFFSET 0x00000200 /* Postoffice offset from base */
100
101#define GCS_0 0x00000000 /* Guest bus chip selects */
102#define GCS_1 0x00100000
103#define GCS_2 0x00200000
104#define GCS_3 0x00300000
105
106#define PO_READ 0x00000000 /* R/W from/to guest bus */
107#define PO_WRITE 0x00800000
108
109#define PO_PEND 0x02000000
110
111#define POSTOFFICE(postoffice) *(volatile unsigned int*)(postoffice)
112
113/* Wait unlimited (don't worry) */
114#define __WAITI20__(postoffice) \
115do { \
116 while ((POSTOFFICE(postoffice) & PO_PEND)) ; \
117} while (0)
118
119#endif /* __BKM_AX_H__ */
diff --git a/drivers/isdn/hisax/callc.c b/drivers/isdn/hisax/callc.c
new file mode 100644
index 000000000000..04065ab2610f
--- /dev/null
+++ b/drivers/isdn/hisax/callc.c
@@ -0,0 +1,1793 @@
1/* $Id: callc.c,v 2.59.2.4 2004/02/11 13:21:32 keil Exp $
2 *
3 * Author Karsten Keil
4 * Copyright by Karsten Keil <keil@isdn4linux.de>
5 *
6 * This software may be used and distributed according to the terms
7 * of the GNU General Public License, incorporated herein by reference.
8 *
9 * For changes and modifications please read
10 * Documentation/isdn/HiSax.cert
11 *
12 * based on the teles driver from Jan den Ouden
13 *
14 * Thanks to Jan den Ouden
15 * Fritz Elfert
16 *
17 */
18
19#include <linux/module.h>
20#include <linux/init.h>
21#include "hisax.h"
22#include <linux/isdn/capicmd.h>
23
24const char *lli_revision = "$Revision: 2.59.2.4 $";
25
26extern struct IsdnCard cards[];
27extern int nrcards;
28
29static int init_b_st(struct Channel *chanp, int incoming);
30static void release_b_st(struct Channel *chanp);
31
32static struct Fsm callcfsm;
33static int chancount;
34
35/* experimental REJECT after ALERTING for CALLBACK to beat the 4s delay */
36#define ALERT_REJECT 0
37
38/* Value to delay the sending of the first B-channel paket after CONNECT
39 * here is no value given by ITU, but experience shows that 300 ms will
40 * work on many networks, if you or your other side is behind local exchanges
41 * a greater value may be recommented. If the delay is to short the first paket
42 * will be lost and autodetect on many comercial routers goes wrong !
43 * You can adjust this value on runtime with
44 * hisaxctrl <id> 2 <value>
45 * value is in milliseconds
46 */
47#define DEFAULT_B_DELAY 300
48
49/* Flags for remembering action done in lli */
50
51#define FLG_START_B 0
52
53/*
54 * Find card with given driverId
55 */
56static inline struct IsdnCardState *
57hisax_findcard(int driverid)
58{
59 int i;
60
61 for (i = 0; i < nrcards; i++)
62 if (cards[i].cs)
63 if (cards[i].cs->myid == driverid)
64 return (cards[i].cs);
65 return (struct IsdnCardState *) 0;
66}
67
68static void
69link_debug(struct Channel *chanp, int direction, char *fmt, ...)
70{
71 va_list args;
72 char tmp[16];
73
74 va_start(args, fmt);
75 sprintf(tmp, "Ch%d %s ", chanp->chan,
76 direction ? "LL->HL" : "HL->LL");
77 VHiSax_putstatus(chanp->cs, tmp, fmt, args);
78 va_end(args);
79}
80
81enum {
82 ST_NULL, /* 0 inactive */
83 ST_OUT_DIAL, /* 1 outgoing, SETUP send; awaiting confirm */
84 ST_IN_WAIT_LL, /* 2 incoming call received; wait for LL confirm */
85 ST_IN_ALERT_SENT, /* 3 incoming call received; ALERT send */
86 ST_IN_WAIT_CONN_ACK, /* 4 incoming CONNECT send; awaiting CONN_ACK */
87 ST_WAIT_BCONN, /* 5 CONNECT/CONN_ACK received, awaiting b-channel prot. estbl. */
88 ST_ACTIVE, /* 6 active, b channel prot. established */
89 ST_WAIT_BRELEASE, /* 7 call clear. (initiator), awaiting b channel prot. rel. */
90 ST_WAIT_BREL_DISC, /* 8 call clear. (receiver), DISCONNECT req. received */
91 ST_WAIT_DCOMMAND, /* 9 call clear. (receiver), awaiting DCHANNEL message */
92 ST_WAIT_DRELEASE, /* 10 DISCONNECT sent, awaiting RELEASE */
93 ST_WAIT_D_REL_CNF, /* 11 RELEASE sent, awaiting RELEASE confirm */
94 ST_IN_PROCEED_SEND, /* 12 incoming call, proceeding send */
95};
96
97
98#define STATE_COUNT (ST_IN_PROCEED_SEND + 1)
99
100static char *strState[] =
101{
102 "ST_NULL",
103 "ST_OUT_DIAL",
104 "ST_IN_WAIT_LL",
105 "ST_IN_ALERT_SENT",
106 "ST_IN_WAIT_CONN_ACK",
107 "ST_WAIT_BCONN",
108 "ST_ACTIVE",
109 "ST_WAIT_BRELEASE",
110 "ST_WAIT_BREL_DISC",
111 "ST_WAIT_DCOMMAND",
112 "ST_WAIT_DRELEASE",
113 "ST_WAIT_D_REL_CNF",
114 "ST_IN_PROCEED_SEND",
115};
116
117enum {
118 EV_DIAL, /* 0 */
119 EV_SETUP_CNF, /* 1 */
120 EV_ACCEPTB, /* 2 */
121 EV_DISCONNECT_IND, /* 3 */
122 EV_RELEASE, /* 4 */
123 EV_LEASED, /* 5 */
124 EV_LEASED_REL, /* 6 */
125 EV_SETUP_IND, /* 7 */
126 EV_ACCEPTD, /* 8 */
127 EV_SETUP_CMPL_IND, /* 9 */
128 EV_BC_EST, /* 10 */
129 EV_WRITEBUF, /* 11 */
130 EV_HANGUP, /* 12 */
131 EV_BC_REL, /* 13 */
132 EV_CINF, /* 14 */
133 EV_SUSPEND, /* 15 */
134 EV_RESUME, /* 16 */
135 EV_NOSETUP_RSP, /* 17 */
136 EV_SETUP_ERR, /* 18 */
137 EV_CONNECT_ERR, /* 19 */
138 EV_PROCEED, /* 20 */
139 EV_ALERT, /* 21 */
140 EV_REDIR, /* 22 */
141};
142
143#define EVENT_COUNT (EV_REDIR + 1)
144
145static char *strEvent[] =
146{
147 "EV_DIAL",
148 "EV_SETUP_CNF",
149 "EV_ACCEPTB",
150 "EV_DISCONNECT_IND",
151 "EV_RELEASE",
152 "EV_LEASED",
153 "EV_LEASED_REL",
154 "EV_SETUP_IND",
155 "EV_ACCEPTD",
156 "EV_SETUP_CMPL_IND",
157 "EV_BC_EST",
158 "EV_WRITEBUF",
159 "EV_HANGUP",
160 "EV_BC_REL",
161 "EV_CINF",
162 "EV_SUSPEND",
163 "EV_RESUME",
164 "EV_NOSETUP_RSP",
165 "EV_SETUP_ERR",
166 "EV_CONNECT_ERR",
167 "EV_PROCEED",
168 "EV_ALERT",
169 "EV_REDIR",
170};
171
172
173static inline void
174HL_LL(struct Channel *chanp, int command)
175{
176 isdn_ctrl ic;
177
178 ic.driver = chanp->cs->myid;
179 ic.command = command;
180 ic.arg = chanp->chan;
181 chanp->cs->iif.statcallb(&ic);
182}
183
184static inline void
185lli_deliver_cause(struct Channel *chanp)
186{
187 isdn_ctrl ic;
188
189 if (!chanp->proc)
190 return;
191 if (chanp->proc->para.cause == NO_CAUSE)
192 return;
193 ic.driver = chanp->cs->myid;
194 ic.command = ISDN_STAT_CAUSE;
195 ic.arg = chanp->chan;
196 if (chanp->cs->protocol == ISDN_PTYPE_EURO)
197 sprintf(ic.parm.num, "E%02X%02X", chanp->proc->para.loc & 0x7f,
198 chanp->proc->para.cause & 0x7f);
199 else
200 sprintf(ic.parm.num, "%02X%02X", chanp->proc->para.loc & 0x7f,
201 chanp->proc->para.cause & 0x7f);
202 chanp->cs->iif.statcallb(&ic);
203}
204
205static inline void
206lli_close(struct FsmInst *fi)
207{
208 struct Channel *chanp = fi->userdata;
209
210 FsmChangeState(fi, ST_NULL);
211 chanp->Flags = 0;
212 chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan);
213}
214
215static void
216lli_leased_in(struct FsmInst *fi, int event, void *arg)
217{
218 struct Channel *chanp = fi->userdata;
219 isdn_ctrl ic;
220 int ret;
221
222 if (!chanp->leased)
223 return;
224 chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) (long)chanp->chan);
225 FsmChangeState(fi, ST_IN_WAIT_LL);
226 if (chanp->debug & 1)
227 link_debug(chanp, 0, "STAT_ICALL_LEASED");
228 ic.driver = chanp->cs->myid;
229 ic.command = ((chanp->chan < 2) ? ISDN_STAT_ICALL : ISDN_STAT_ICALLW);
230 ic.arg = chanp->chan;
231 ic.parm.setup.si1 = 7;
232 ic.parm.setup.si2 = 0;
233 ic.parm.setup.plan = 0;
234 ic.parm.setup.screen = 0;
235 sprintf(ic.parm.setup.eazmsn,"%d", chanp->chan + 1);
236 sprintf(ic.parm.setup.phone,"LEASED%d", chanp->cs->myid);
237 ret = chanp->cs->iif.statcallb(&ic);
238 if (chanp->debug & 1)
239 link_debug(chanp, 1, "statcallb ret=%d", ret);
240 if (!ret) {
241 chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan);
242 FsmChangeState(fi, ST_NULL);
243 }
244}
245
246
247/*
248 * Dial out
249 */
250static void
251lli_init_bchan_out(struct FsmInst *fi, int event, void *arg)
252{
253 struct Channel *chanp = fi->userdata;
254
255 FsmChangeState(fi, ST_WAIT_BCONN);
256 if (chanp->debug & 1)
257 link_debug(chanp, 0, "STAT_DCONN");
258 HL_LL(chanp, ISDN_STAT_DCONN);
259 init_b_st(chanp, 0);
260 chanp->b_st->lli.l4l3(chanp->b_st, DL_ESTABLISH | REQUEST, NULL);
261}
262
263static void
264lli_prep_dialout(struct FsmInst *fi, int event, void *arg)
265{
266 struct Channel *chanp = fi->userdata;
267
268 FsmDelTimer(&chanp->drel_timer, 60);
269 FsmDelTimer(&chanp->dial_timer, 73);
270 chanp->l2_active_protocol = chanp->l2_protocol;
271 chanp->incoming = 0;
272 chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) (long)chanp->chan);
273 if (chanp->leased) {
274 lli_init_bchan_out(fi, event, arg);
275 } else {
276 FsmChangeState(fi, ST_OUT_DIAL);
277 chanp->d_st->lli.l4l3(chanp->d_st, CC_SETUP | REQUEST, chanp);
278 }
279}
280
281static void
282lli_resume(struct FsmInst *fi, int event, void *arg)
283{
284 struct Channel *chanp = fi->userdata;
285
286 FsmDelTimer(&chanp->drel_timer, 60);
287 FsmDelTimer(&chanp->dial_timer, 73);
288 chanp->l2_active_protocol = chanp->l2_protocol;
289 chanp->incoming = 0;
290 chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) (long)chanp->chan);
291 if (chanp->leased) {
292 lli_init_bchan_out(fi, event, arg);
293 } else {
294 FsmChangeState(fi, ST_OUT_DIAL);
295 chanp->d_st->lli.l4l3(chanp->d_st, CC_RESUME | REQUEST, chanp);
296 }
297}
298
299static void
300lli_go_active(struct FsmInst *fi, int event, void *arg)
301{
302 struct Channel *chanp = fi->userdata;
303 isdn_ctrl ic;
304
305
306 FsmChangeState(fi, ST_ACTIVE);
307 chanp->data_open = !0;
308 if (chanp->bcs->conmsg)
309 strcpy(ic.parm.num, chanp->bcs->conmsg);
310 else
311 ic.parm.num[0] = 0;
312 if (chanp->debug & 1)
313 link_debug(chanp, 0, "STAT_BCONN %s", ic.parm.num);
314 ic.driver = chanp->cs->myid;
315 ic.command = ISDN_STAT_BCONN;
316 ic.arg = chanp->chan;
317 chanp->cs->iif.statcallb(&ic);
318 chanp->cs->cardmsg(chanp->cs, MDL_INFO_CONN, (void *) (long)chanp->chan);
319}
320
321
322/*
323 * RESUME
324 */
325
326/* incoming call */
327
328static void
329lli_deliver_call(struct FsmInst *fi, int event, void *arg)
330{
331 struct Channel *chanp = fi->userdata;
332 isdn_ctrl ic;
333 int ret;
334
335 chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) (long)chanp->chan);
336 /*
337 * Report incoming calls only once to linklevel, use CallFlags
338 * which is set to 3 with each broadcast message in isdnl1.c
339 * and resetted if a interface answered the STAT_ICALL.
340 */
341 if (1) { /* for only one TEI */
342 FsmChangeState(fi, ST_IN_WAIT_LL);
343 if (chanp->debug & 1)
344 link_debug(chanp, 0, (chanp->chan < 2) ? "STAT_ICALL" : "STAT_ICALLW");
345 ic.driver = chanp->cs->myid;
346 ic.command = ((chanp->chan < 2) ? ISDN_STAT_ICALL : ISDN_STAT_ICALLW);
347
348 ic.arg = chanp->chan;
349 /*
350 * No need to return "unknown" for calls without OAD,
351 * cause that's handled in linklevel now (replaced by '0')
352 */
353 memcpy(&ic.parm.setup, &chanp->proc->para.setup, sizeof(setup_parm));
354 ret = chanp->cs->iif.statcallb(&ic);
355 if (chanp->debug & 1)
356 link_debug(chanp, 1, "statcallb ret=%d", ret);
357
358 switch (ret) {
359 case 1: /* OK, someone likes this call */
360 FsmDelTimer(&chanp->drel_timer, 61);
361 FsmChangeState(fi, ST_IN_ALERT_SENT);
362 chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc);
363 break;
364 case 5: /* direct redirect */
365 case 4: /* Proceeding desired */
366 FsmDelTimer(&chanp->drel_timer, 61);
367 FsmChangeState(fi, ST_IN_PROCEED_SEND);
368 chanp->d_st->lli.l4l3(chanp->d_st, CC_PROCEED_SEND | REQUEST, chanp->proc);
369 if (ret == 5) {
370 memcpy(&chanp->setup, &ic.parm.setup, sizeof(setup_parm));
371 chanp->d_st->lli.l4l3(chanp->d_st, CC_REDIR | REQUEST, chanp->proc);
372 }
373 break;
374 case 2: /* Rejecting Call */
375 break;
376 case 3: /* incomplete number */
377 FsmDelTimer(&chanp->drel_timer, 61);
378 chanp->d_st->lli.l4l3(chanp->d_st, CC_MORE_INFO | REQUEST, chanp->proc);
379 break;
380 case 0: /* OK, nobody likes this call */
381 default: /* statcallb problems */
382 chanp->d_st->lli.l4l3(chanp->d_st, CC_IGNORE | REQUEST, chanp->proc);
383 chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan);
384 FsmChangeState(fi, ST_NULL);
385 break;
386 }
387 } else {
388 chanp->d_st->lli.l4l3(chanp->d_st, CC_IGNORE | REQUEST, chanp->proc);
389 chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan);
390 }
391}
392
393static void
394lli_send_dconnect(struct FsmInst *fi, int event, void *arg)
395{
396 struct Channel *chanp = fi->userdata;
397
398 FsmChangeState(fi, ST_IN_WAIT_CONN_ACK);
399 chanp->d_st->lli.l4l3(chanp->d_st, CC_SETUP | RESPONSE, chanp->proc);
400}
401
402static void
403lli_send_alert(struct FsmInst *fi, int event, void *arg)
404{
405 struct Channel *chanp = fi->userdata;
406
407 FsmChangeState(fi, ST_IN_ALERT_SENT);
408 chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc);
409}
410
411static void
412lli_send_redir(struct FsmInst *fi, int event, void *arg)
413{
414 struct Channel *chanp = fi->userdata;
415
416 chanp->d_st->lli.l4l3(chanp->d_st, CC_REDIR | REQUEST, chanp->proc);
417}
418
419static void
420lli_init_bchan_in(struct FsmInst *fi, int event, void *arg)
421{
422 struct Channel *chanp = fi->userdata;
423
424 FsmChangeState(fi, ST_WAIT_BCONN);
425 if (chanp->debug & 1)
426 link_debug(chanp, 0, "STAT_DCONN");
427 HL_LL(chanp, ISDN_STAT_DCONN);
428 chanp->l2_active_protocol = chanp->l2_protocol;
429 chanp->incoming = !0;
430 init_b_st(chanp, !0);
431 chanp->b_st->lli.l4l3(chanp->b_st, DL_ESTABLISH | REQUEST, NULL);
432}
433
434static void
435lli_setup_rsp(struct FsmInst *fi, int event, void *arg)
436{
437 struct Channel *chanp = fi->userdata;
438
439 if (chanp->leased) {
440 lli_init_bchan_in(fi, event, arg);
441 } else {
442 FsmChangeState(fi, ST_IN_WAIT_CONN_ACK);
443#ifdef WANT_ALERT
444 chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc);
445#endif
446 chanp->d_st->lli.l4l3(chanp->d_st, CC_SETUP | RESPONSE, chanp->proc);
447 }
448}
449
450/* Call suspend */
451
452static void
453lli_suspend(struct FsmInst *fi, int event, void *arg)
454{
455 struct Channel *chanp = fi->userdata;
456
457 chanp->d_st->lli.l4l3(chanp->d_st, CC_SUSPEND | REQUEST, chanp->proc);
458}
459
460/* Call clearing */
461
462static void
463lli_leased_hup(struct FsmInst *fi, struct Channel *chanp)
464{
465 isdn_ctrl ic;
466
467 ic.driver = chanp->cs->myid;
468 ic.command = ISDN_STAT_CAUSE;
469 ic.arg = chanp->chan;
470 sprintf(ic.parm.num, "L0010");
471 chanp->cs->iif.statcallb(&ic);
472 if (chanp->debug & 1)
473 link_debug(chanp, 0, "STAT_DHUP");
474 HL_LL(chanp, ISDN_STAT_DHUP);
475 lli_close(fi);
476}
477
478static void
479lli_disconnect_req(struct FsmInst *fi, int event, void *arg)
480{
481 struct Channel *chanp = fi->userdata;
482
483 if (chanp->leased) {
484 lli_leased_hup(fi, chanp);
485 } else {
486 FsmChangeState(fi, ST_WAIT_DRELEASE);
487 if (chanp->proc)
488 chanp->proc->para.cause = 0x10; /* Normal Call Clearing */
489 chanp->d_st->lli.l4l3(chanp->d_st, CC_DISCONNECT | REQUEST,
490 chanp->proc);
491 }
492}
493
494static void
495lli_disconnect_reject(struct FsmInst *fi, int event, void *arg)
496{
497 struct Channel *chanp = fi->userdata;
498
499 if (chanp->leased) {
500 lli_leased_hup(fi, chanp);
501 } else {
502 FsmChangeState(fi, ST_WAIT_DRELEASE);
503 if (chanp->proc)
504 chanp->proc->para.cause = 0x15; /* Call Rejected */
505 chanp->d_st->lli.l4l3(chanp->d_st, CC_DISCONNECT | REQUEST,
506 chanp->proc);
507 }
508}
509
510static void
511lli_dhup_close(struct FsmInst *fi, int event, void *arg)
512{
513 struct Channel *chanp = fi->userdata;
514
515 if (chanp->leased) {
516 lli_leased_hup(fi, chanp);
517 } else {
518 if (chanp->debug & 1)
519 link_debug(chanp, 0, "STAT_DHUP");
520 lli_deliver_cause(chanp);
521 HL_LL(chanp, ISDN_STAT_DHUP);
522 lli_close(fi);
523 }
524}
525
526static void
527lli_reject_req(struct FsmInst *fi, int event, void *arg)
528{
529 struct Channel *chanp = fi->userdata;
530
531 if (chanp->leased) {
532 lli_leased_hup(fi, chanp);
533 return;
534 }
535#ifndef ALERT_REJECT
536 if (chanp->proc)
537 chanp->proc->para.cause = 0x15; /* Call Rejected */
538 chanp->d_st->lli.l4l3(chanp->d_st, CC_REJECT | REQUEST, chanp->proc);
539 lli_dhup_close(fi, event, arg);
540#else
541 FsmRestartTimer(&chanp->drel_timer, 40, EV_HANGUP, NULL, 63);
542 FsmChangeState(fi, ST_IN_ALERT_SENT);
543 chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc);
544#endif
545}
546
547static void
548lli_disconn_bchan(struct FsmInst *fi, int event, void *arg)
549{
550 struct Channel *chanp = fi->userdata;
551
552 chanp->data_open = 0;
553 FsmChangeState(fi, ST_WAIT_BRELEASE);
554 chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL);
555}
556
557static void
558lli_start_disc(struct FsmInst *fi, int event, void *arg)
559{
560 struct Channel *chanp = fi->userdata;
561
562 if (chanp->leased) {
563 lli_leased_hup(fi, chanp);
564 } else {
565 lli_disconnect_req(fi, event, arg);
566 }
567}
568
569static void
570lli_rel_b_disc(struct FsmInst *fi, int event, void *arg)
571{
572 struct Channel *chanp = fi->userdata;
573
574 release_b_st(chanp);
575 lli_start_disc(fi, event, arg);
576}
577
578static void
579lli_bhup_disc(struct FsmInst *fi, int event, void *arg)
580{
581 struct Channel *chanp = fi->userdata;
582
583 if (chanp->debug & 1)
584 link_debug(chanp, 0, "STAT_BHUP");
585 HL_LL(chanp, ISDN_STAT_BHUP);
586 lli_rel_b_disc(fi, event, arg);
587}
588
589static void
590lli_bhup_rel_b(struct FsmInst *fi, int event, void *arg)
591{
592 struct Channel *chanp = fi->userdata;
593
594 FsmChangeState(fi, ST_WAIT_DCOMMAND);
595 chanp->data_open = 0;
596 if (chanp->debug & 1)
597 link_debug(chanp, 0, "STAT_BHUP");
598 HL_LL(chanp, ISDN_STAT_BHUP);
599 release_b_st(chanp);
600}
601
602static void
603lli_release_bchan(struct FsmInst *fi, int event, void *arg)
604{
605 struct Channel *chanp = fi->userdata;
606
607 chanp->data_open = 0;
608 FsmChangeState(fi, ST_WAIT_BREL_DISC);
609 chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL);
610}
611
612
613static void
614lli_rel_b_dhup(struct FsmInst *fi, int event, void *arg)
615{
616 struct Channel *chanp = fi->userdata;
617
618 release_b_st(chanp);
619 lli_dhup_close(fi, event, arg);
620}
621
622static void
623lli_bhup_dhup(struct FsmInst *fi, int event, void *arg)
624{
625 struct Channel *chanp = fi->userdata;
626
627 if (chanp->debug & 1)
628 link_debug(chanp, 0, "STAT_BHUP");
629 HL_LL(chanp, ISDN_STAT_BHUP);
630 lli_rel_b_dhup(fi, event, arg);
631}
632
633static void
634lli_abort(struct FsmInst *fi, int event, void *arg)
635{
636 struct Channel *chanp = fi->userdata;
637
638 chanp->data_open = 0;
639 chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL);
640 lli_bhup_dhup(fi, event, arg);
641}
642
643static void
644lli_release_req(struct FsmInst *fi, int event, void *arg)
645{
646 struct Channel *chanp = fi->userdata;
647
648 if (chanp->leased) {
649 lli_leased_hup(fi, chanp);
650 } else {
651 FsmChangeState(fi, ST_WAIT_D_REL_CNF);
652 chanp->d_st->lli.l4l3(chanp->d_st, CC_RELEASE | REQUEST,
653 chanp->proc);
654 }
655}
656
657static void
658lli_rel_b_release_req(struct FsmInst *fi, int event, void *arg)
659{
660 struct Channel *chanp = fi->userdata;
661
662 release_b_st(chanp);
663 lli_release_req(fi, event, arg);
664}
665
666static void
667lli_bhup_release_req(struct FsmInst *fi, int event, void *arg)
668{
669 struct Channel *chanp = fi->userdata;
670
671 if (chanp->debug & 1)
672 link_debug(chanp, 0, "STAT_BHUP");
673 HL_LL(chanp, ISDN_STAT_BHUP);
674 lli_rel_b_release_req(fi, event, arg);
675}
676
677
678/* processing charge info */
679static void
680lli_charge_info(struct FsmInst *fi, int event, void *arg)
681{
682 struct Channel *chanp = fi->userdata;
683 isdn_ctrl ic;
684
685 ic.driver = chanp->cs->myid;
686 ic.command = ISDN_STAT_CINF;
687 ic.arg = chanp->chan;
688 sprintf(ic.parm.num, "%d", chanp->proc->para.chargeinfo);
689 chanp->cs->iif.statcallb(&ic);
690}
691
692/* error procedures */
693
694static void
695lli_dchan_not_ready(struct FsmInst *fi, int event, void *arg)
696{
697 struct Channel *chanp = fi->userdata;
698
699 if (chanp->debug & 1)
700 link_debug(chanp, 0, "STAT_DHUP");
701 HL_LL(chanp, ISDN_STAT_DHUP);
702}
703
704static void
705lli_no_setup_rsp(struct FsmInst *fi, int event, void *arg)
706{
707 struct Channel *chanp = fi->userdata;
708
709 if (chanp->debug & 1)
710 link_debug(chanp, 0, "STAT_DHUP");
711 HL_LL(chanp, ISDN_STAT_DHUP);
712 lli_close(fi);
713}
714
715static void
716lli_error(struct FsmInst *fi, int event, void *arg)
717{
718 FsmChangeState(fi, ST_WAIT_DRELEASE);
719}
720
721static void
722lli_failure_l(struct FsmInst *fi, int event, void *arg)
723{
724 struct Channel *chanp = fi->userdata;
725 isdn_ctrl ic;
726
727 FsmChangeState(fi, ST_NULL);
728 ic.driver = chanp->cs->myid;
729 ic.command = ISDN_STAT_CAUSE;
730 ic.arg = chanp->chan;
731 sprintf(ic.parm.num, "L%02X%02X", 0, 0x2f);
732 chanp->cs->iif.statcallb(&ic);
733 HL_LL(chanp, ISDN_STAT_DHUP);
734 chanp->Flags = 0;
735 chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan);
736}
737
738static void
739lli_rel_b_fail(struct FsmInst *fi, int event, void *arg)
740{
741 struct Channel *chanp = fi->userdata;
742
743 release_b_st(chanp);
744 lli_failure_l(fi, event, arg);
745}
746
747static void
748lli_bhup_fail(struct FsmInst *fi, int event, void *arg)
749{
750 struct Channel *chanp = fi->userdata;
751
752 if (chanp->debug & 1)
753 link_debug(chanp, 0, "STAT_BHUP");
754 HL_LL(chanp, ISDN_STAT_BHUP);
755 lli_rel_b_fail(fi, event, arg);
756}
757
758static void
759lli_failure_a(struct FsmInst *fi, int event, void *arg)
760{
761 struct Channel *chanp = fi->userdata;
762
763 chanp->data_open = 0;
764 chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL);
765 lli_bhup_fail(fi, event, arg);
766}
767
768/* *INDENT-OFF* */
769static struct FsmNode fnlist[] __initdata =
770{
771 {ST_NULL, EV_DIAL, lli_prep_dialout},
772 {ST_NULL, EV_RESUME, lli_resume},
773 {ST_NULL, EV_SETUP_IND, lli_deliver_call},
774 {ST_NULL, EV_LEASED, lli_leased_in},
775 {ST_OUT_DIAL, EV_SETUP_CNF, lli_init_bchan_out},
776 {ST_OUT_DIAL, EV_HANGUP, lli_disconnect_req},
777 {ST_OUT_DIAL, EV_DISCONNECT_IND, lli_release_req},
778 {ST_OUT_DIAL, EV_RELEASE, lli_dhup_close},
779 {ST_OUT_DIAL, EV_NOSETUP_RSP, lli_no_setup_rsp},
780 {ST_OUT_DIAL, EV_SETUP_ERR, lli_error},
781 {ST_IN_WAIT_LL, EV_LEASED_REL, lli_failure_l},
782 {ST_IN_WAIT_LL, EV_ACCEPTD, lli_setup_rsp},
783 {ST_IN_WAIT_LL, EV_HANGUP, lli_reject_req},
784 {ST_IN_WAIT_LL, EV_DISCONNECT_IND, lli_release_req},
785 {ST_IN_WAIT_LL, EV_RELEASE, lli_dhup_close},
786 {ST_IN_WAIT_LL, EV_SETUP_IND, lli_deliver_call},
787 {ST_IN_WAIT_LL, EV_SETUP_ERR, lli_error},
788 {ST_IN_ALERT_SENT, EV_SETUP_CMPL_IND, lli_init_bchan_in},
789 {ST_IN_ALERT_SENT, EV_ACCEPTD, lli_send_dconnect},
790 {ST_IN_ALERT_SENT, EV_HANGUP, lli_disconnect_reject},
791 {ST_IN_ALERT_SENT, EV_DISCONNECT_IND, lli_release_req},
792 {ST_IN_ALERT_SENT, EV_RELEASE, lli_dhup_close},
793 {ST_IN_ALERT_SENT, EV_REDIR, lli_send_redir},
794 {ST_IN_PROCEED_SEND, EV_REDIR, lli_send_redir},
795 {ST_IN_PROCEED_SEND, EV_ALERT, lli_send_alert},
796 {ST_IN_PROCEED_SEND, EV_ACCEPTD, lli_send_dconnect},
797 {ST_IN_PROCEED_SEND, EV_HANGUP, lli_disconnect_reject},
798 {ST_IN_PROCEED_SEND, EV_DISCONNECT_IND, lli_dhup_close},
799 {ST_IN_ALERT_SENT, EV_RELEASE, lli_dhup_close},
800 {ST_IN_WAIT_CONN_ACK, EV_SETUP_CMPL_IND, lli_init_bchan_in},
801 {ST_IN_WAIT_CONN_ACK, EV_HANGUP, lli_disconnect_req},
802 {ST_IN_WAIT_CONN_ACK, EV_DISCONNECT_IND, lli_release_req},
803 {ST_IN_WAIT_CONN_ACK, EV_RELEASE, lli_dhup_close},
804 {ST_IN_WAIT_CONN_ACK, EV_CONNECT_ERR, lli_error},
805 {ST_WAIT_BCONN, EV_BC_EST, lli_go_active},
806 {ST_WAIT_BCONN, EV_BC_REL, lli_rel_b_disc},
807 {ST_WAIT_BCONN, EV_HANGUP, lli_rel_b_disc},
808 {ST_WAIT_BCONN, EV_DISCONNECT_IND, lli_rel_b_release_req},
809 {ST_WAIT_BCONN, EV_RELEASE, lli_rel_b_dhup},
810 {ST_WAIT_BCONN, EV_LEASED_REL, lli_rel_b_fail},
811 {ST_WAIT_BCONN, EV_CINF, lli_charge_info},
812 {ST_ACTIVE, EV_CINF, lli_charge_info},
813 {ST_ACTIVE, EV_BC_REL, lli_bhup_rel_b},
814 {ST_ACTIVE, EV_SUSPEND, lli_suspend},
815 {ST_ACTIVE, EV_HANGUP, lli_disconn_bchan},
816 {ST_ACTIVE, EV_DISCONNECT_IND, lli_release_bchan},
817 {ST_ACTIVE, EV_RELEASE, lli_abort},
818 {ST_ACTIVE, EV_LEASED_REL, lli_failure_a},
819 {ST_WAIT_BRELEASE, EV_BC_REL, lli_bhup_disc},
820 {ST_WAIT_BRELEASE, EV_DISCONNECT_IND, lli_bhup_release_req},
821 {ST_WAIT_BRELEASE, EV_RELEASE, lli_bhup_dhup},
822 {ST_WAIT_BRELEASE, EV_LEASED_REL, lli_bhup_fail},
823 {ST_WAIT_BREL_DISC, EV_BC_REL, lli_bhup_release_req},
824 {ST_WAIT_BREL_DISC, EV_RELEASE, lli_bhup_dhup},
825 {ST_WAIT_DCOMMAND, EV_HANGUP, lli_start_disc},
826 {ST_WAIT_DCOMMAND, EV_DISCONNECT_IND, lli_release_req},
827 {ST_WAIT_DCOMMAND, EV_RELEASE, lli_dhup_close},
828 {ST_WAIT_DCOMMAND, EV_LEASED_REL, lli_failure_l},
829 {ST_WAIT_DRELEASE, EV_RELEASE, lli_dhup_close},
830 {ST_WAIT_DRELEASE, EV_DIAL, lli_dchan_not_ready},
831 /* ETS 300-104 16.1 */
832 {ST_WAIT_D_REL_CNF, EV_RELEASE, lli_dhup_close},
833 {ST_WAIT_D_REL_CNF, EV_DIAL, lli_dchan_not_ready},
834};
835/* *INDENT-ON* */
836
837#define FNCOUNT (sizeof(fnlist)/sizeof(struct FsmNode))
838
839int __init
840CallcNew(void)
841{
842 callcfsm.state_count = STATE_COUNT;
843 callcfsm.event_count = EVENT_COUNT;
844 callcfsm.strEvent = strEvent;
845 callcfsm.strState = strState;
846 return FsmNew(&callcfsm, fnlist, FNCOUNT);
847}
848
849void
850CallcFree(void)
851{
852 FsmFree(&callcfsm);
853}
854
855static void
856release_b_st(struct Channel *chanp)
857{
858 struct PStack *st = chanp->b_st;
859
860 if(test_and_clear_bit(FLG_START_B, &chanp->Flags)) {
861 chanp->bcs->BC_Close(chanp->bcs);
862 switch (chanp->l2_active_protocol) {
863 case (ISDN_PROTO_L2_X75I):
864 releasestack_isdnl2(st);
865 break;
866 case (ISDN_PROTO_L2_HDLC):
867 case (ISDN_PROTO_L2_HDLC_56K):
868 case (ISDN_PROTO_L2_TRANS):
869 case (ISDN_PROTO_L2_MODEM):
870 case (ISDN_PROTO_L2_FAX):
871 releasestack_transl2(st);
872 break;
873 }
874 }
875}
876
877struct Channel
878*selectfreechannel(struct PStack *st, int bch)
879{
880 struct IsdnCardState *cs = st->l1.hardware;
881 struct Channel *chanp = st->lli.userdata;
882 int i;
883
884 if (test_bit(FLG_TWO_DCHAN, &cs->HW_Flags))
885 i=1;
886 else
887 i=0;
888
889 if (!bch) {
890 i = 2; /* virtual channel */
891 chanp += 2;
892 }
893
894 while (i < ((bch) ? cs->chanlimit : (2 + MAX_WAITING_CALLS))) {
895 if (chanp->fi.state == ST_NULL)
896 return (chanp);
897 chanp++;
898 i++;
899 }
900
901 if (bch) /* number of channels is limited */ {
902 i = 2; /* virtual channel */
903 chanp = st->lli.userdata;
904 chanp += i;
905 while (i < (2 + MAX_WAITING_CALLS)) {
906 if (chanp->fi.state == ST_NULL)
907 return (chanp);
908 chanp++;
909 i++;
910 }
911 }
912 return (NULL);
913}
914
915static void stat_redir_result(struct IsdnCardState *cs, int chan, ulong result)
916{ isdn_ctrl ic;
917
918 ic.driver = cs->myid;
919 ic.command = ISDN_STAT_REDIR;
920 ic.arg = chan;
921 ic.parm.num[0] = result;
922 cs->iif.statcallb(&ic);
923} /* stat_redir_result */
924
925static void
926dchan_l3l4(struct PStack *st, int pr, void *arg)
927{
928 struct l3_process *pc = arg;
929 struct IsdnCardState *cs = st->l1.hardware;
930 struct Channel *chanp;
931
932 if(!pc)
933 return;
934
935 if (pr == (CC_SETUP | INDICATION)) {
936 if (!(chanp = selectfreechannel(pc->st, pc->para.bchannel))) {
937 pc->para.cause = 0x11; /* User busy */
938 pc->st->lli.l4l3(pc->st, CC_REJECT | REQUEST, pc);
939 } else {
940 chanp->proc = pc;
941 pc->chan = chanp;
942 FsmEvent(&chanp->fi, EV_SETUP_IND, NULL);
943 }
944 return;
945 }
946 if (!(chanp = pc->chan))
947 return;
948
949 switch (pr) {
950 case (CC_MORE_INFO | INDICATION):
951 FsmEvent(&chanp->fi, EV_SETUP_IND, NULL);
952 break;
953 case (CC_DISCONNECT | INDICATION):
954 FsmEvent(&chanp->fi, EV_DISCONNECT_IND, NULL);
955 break;
956 case (CC_RELEASE | CONFIRM):
957 FsmEvent(&chanp->fi, EV_RELEASE, NULL);
958 break;
959 case (CC_SUSPEND | CONFIRM):
960 FsmEvent(&chanp->fi, EV_RELEASE, NULL);
961 break;
962 case (CC_RESUME | CONFIRM):
963 FsmEvent(&chanp->fi, EV_SETUP_CNF, NULL);
964 break;
965 case (CC_RESUME_ERR):
966 FsmEvent(&chanp->fi, EV_RELEASE, NULL);
967 break;
968 case (CC_RELEASE | INDICATION):
969 FsmEvent(&chanp->fi, EV_RELEASE, NULL);
970 break;
971 case (CC_SETUP_COMPL | INDICATION):
972 FsmEvent(&chanp->fi, EV_SETUP_CMPL_IND, NULL);
973 break;
974 case (CC_SETUP | CONFIRM):
975 FsmEvent(&chanp->fi, EV_SETUP_CNF, NULL);
976 break;
977 case (CC_CHARGE | INDICATION):
978 FsmEvent(&chanp->fi, EV_CINF, NULL);
979 break;
980 case (CC_NOSETUP_RSP):
981 FsmEvent(&chanp->fi, EV_NOSETUP_RSP, NULL);
982 break;
983 case (CC_SETUP_ERR):
984 FsmEvent(&chanp->fi, EV_SETUP_ERR, NULL);
985 break;
986 case (CC_CONNECT_ERR):
987 FsmEvent(&chanp->fi, EV_CONNECT_ERR, NULL);
988 break;
989 case (CC_RELEASE_ERR):
990 FsmEvent(&chanp->fi, EV_RELEASE, NULL);
991 break;
992 case (CC_PROCEED_SEND | INDICATION):
993 case (CC_PROCEEDING | INDICATION):
994 case (CC_ALERTING | INDICATION):
995 case (CC_PROGRESS | INDICATION):
996 case (CC_NOTIFY | INDICATION):
997 break;
998 case (CC_REDIR | INDICATION):
999 stat_redir_result(cs, chanp->chan, pc->redir_result);
1000 break;
1001 default:
1002 if (chanp->debug & 0x800) {
1003 HiSax_putstatus(chanp->cs, "Ch",
1004 "%d L3->L4 unknown primitiv %#x",
1005 chanp->chan, pr);
1006 }
1007 }
1008}
1009
1010static void
1011dummy_pstack(struct PStack *st, int pr, void *arg) {
1012 printk(KERN_WARNING"call to dummy_pstack pr=%04x arg %lx\n", pr, (long)arg);
1013}
1014
1015static int
1016init_PStack(struct PStack **stp) {
1017 *stp = kmalloc(sizeof(struct PStack), GFP_ATOMIC);
1018 if (!*stp)
1019 return -ENOMEM;
1020 (*stp)->next = NULL;
1021 (*stp)->l1.l1l2 = dummy_pstack;
1022 (*stp)->l1.l1hw = dummy_pstack;
1023 (*stp)->l1.l1tei = dummy_pstack;
1024 (*stp)->l2.l2tei = dummy_pstack;
1025 (*stp)->l2.l2l1 = dummy_pstack;
1026 (*stp)->l2.l2l3 = dummy_pstack;
1027 (*stp)->l3.l3l2 = dummy_pstack;
1028 (*stp)->l3.l3ml3 = dummy_pstack;
1029 (*stp)->l3.l3l4 = dummy_pstack;
1030 (*stp)->lli.l4l3 = dummy_pstack;
1031 (*stp)->ma.layer = dummy_pstack;
1032 return 0;
1033}
1034
1035static int
1036init_d_st(struct Channel *chanp)
1037{
1038 struct PStack *st;
1039 struct IsdnCardState *cs = chanp->cs;
1040 char tmp[16];
1041 int err;
1042
1043 err = init_PStack(&chanp->d_st);
1044 if (err)
1045 return err;
1046 st = chanp->d_st;
1047 st->next = NULL;
1048 HiSax_addlist(cs, st);
1049 setstack_HiSax(st, cs);
1050 st->l2.sap = 0;
1051 st->l2.tei = -1;
1052 st->l2.flag = 0;
1053 test_and_set_bit(FLG_MOD128, &st->l2.flag);
1054 test_and_set_bit(FLG_LAPD, &st->l2.flag);
1055 test_and_set_bit(FLG_ORIG, &st->l2.flag);
1056 st->l2.maxlen = MAX_DFRAME_LEN;
1057 st->l2.window = 1;
1058 st->l2.T200 = 1000; /* 1000 milliseconds */
1059 st->l2.N200 = 3; /* try 3 times */
1060 st->l2.T203 = 10000; /* 10000 milliseconds */
1061 if (test_bit(FLG_TWO_DCHAN, &cs->HW_Flags))
1062 sprintf(tmp, "DCh%d Q.921 ", chanp->chan);
1063 else
1064 sprintf(tmp, "DCh Q.921 ");
1065 setstack_isdnl2(st, tmp);
1066 setstack_l3dc(st, chanp);
1067 st->lli.userdata = chanp;
1068 st->l3.l3l4 = dchan_l3l4;
1069
1070 return 0;
1071}
1072
1073static void
1074callc_debug(struct FsmInst *fi, char *fmt, ...)
1075{
1076 va_list args;
1077 struct Channel *chanp = fi->userdata;
1078 char tmp[16];
1079
1080 va_start(args, fmt);
1081 sprintf(tmp, "Ch%d callc ", chanp->chan);
1082 VHiSax_putstatus(chanp->cs, tmp, fmt, args);
1083 va_end(args);
1084}
1085
1086static int
1087init_chan(int chan, struct IsdnCardState *csta)
1088{
1089 struct Channel *chanp = csta->channel + chan;
1090 int err;
1091
1092 chanp->cs = csta;
1093 chanp->bcs = csta->bcs + chan;
1094 chanp->chan = chan;
1095 chanp->incoming = 0;
1096 chanp->debug = 0;
1097 chanp->Flags = 0;
1098 chanp->leased = 0;
1099 err = init_PStack(&chanp->b_st);
1100 if (err)
1101 return err;
1102 chanp->b_st->l1.delay = DEFAULT_B_DELAY;
1103 chanp->fi.fsm = &callcfsm;
1104 chanp->fi.state = ST_NULL;
1105 chanp->fi.debug = 0;
1106 chanp->fi.userdata = chanp;
1107 chanp->fi.printdebug = callc_debug;
1108 FsmInitTimer(&chanp->fi, &chanp->dial_timer);
1109 FsmInitTimer(&chanp->fi, &chanp->drel_timer);
1110 if (!chan || (test_bit(FLG_TWO_DCHAN, &csta->HW_Flags) && chan < 2)) {
1111 err = init_d_st(chanp);
1112 if (err)
1113 return err;
1114 } else {
1115 chanp->d_st = csta->channel->d_st;
1116 }
1117 chanp->data_open = 0;
1118 return 0;
1119}
1120
1121int
1122CallcNewChan(struct IsdnCardState *csta) {
1123 int i, err;
1124
1125 chancount += 2;
1126 err = init_chan(0, csta);
1127 if (err)
1128 return err;
1129 err = init_chan(1, csta);
1130 if (err)
1131 return err;
1132 printk(KERN_INFO "HiSax: 2 channels added\n");
1133
1134 for (i = 0; i < MAX_WAITING_CALLS; i++) {
1135 err = init_chan(i+2,csta);
1136 if (err)
1137 return err;
1138 }
1139 printk(KERN_INFO "HiSax: MAX_WAITING_CALLS added\n");
1140 if (test_bit(FLG_PTP, &csta->channel->d_st->l2.flag)) {
1141 printk(KERN_INFO "LAYER2 WATCHING ESTABLISH\n");
1142 csta->channel->d_st->lli.l4l3(csta->channel->d_st,
1143 DL_ESTABLISH | REQUEST, NULL);
1144 }
1145 return (0);
1146}
1147
1148static void
1149release_d_st(struct Channel *chanp)
1150{
1151 struct PStack *st = chanp->d_st;
1152
1153 if (!st)
1154 return;
1155 releasestack_isdnl2(st);
1156 releasestack_isdnl3(st);
1157 HiSax_rmlist(st->l1.hardware, st);
1158 kfree(st);
1159 chanp->d_st = NULL;
1160}
1161
1162void
1163CallcFreeChan(struct IsdnCardState *csta)
1164{
1165 int i;
1166
1167 for (i = 0; i < 2; i++) {
1168 FsmDelTimer(&csta->channel[i].drel_timer, 74);
1169 FsmDelTimer(&csta->channel[i].dial_timer, 75);
1170 if (i || test_bit(FLG_TWO_DCHAN, &csta->HW_Flags))
1171 release_d_st(csta->channel + i);
1172 if (csta->channel[i].b_st) {
1173 release_b_st(csta->channel + i);
1174 kfree(csta->channel[i].b_st);
1175 csta->channel[i].b_st = NULL;
1176 } else
1177 printk(KERN_WARNING "CallcFreeChan b_st ch%d allready freed\n", i);
1178 if (i || test_bit(FLG_TWO_DCHAN, &csta->HW_Flags)) {
1179 release_d_st(csta->channel + i);
1180 } else
1181 csta->channel[i].d_st = NULL;
1182 }
1183}
1184
1185static void
1186lldata_handler(struct PStack *st, int pr, void *arg)
1187{
1188 struct Channel *chanp = (struct Channel *) st->lli.userdata;
1189 struct sk_buff *skb = arg;
1190
1191 switch (pr) {
1192 case (DL_DATA | INDICATION):
1193 if (chanp->data_open) {
1194 if (chanp->debug & 0x800)
1195 link_debug(chanp, 0, "lldata: %d", skb->len);
1196 chanp->cs->iif.rcvcallb_skb(chanp->cs->myid, chanp->chan, skb);
1197 } else {
1198 link_debug(chanp, 0, "lldata: channel not open");
1199 dev_kfree_skb(skb);
1200 }
1201 break;
1202 case (DL_ESTABLISH | INDICATION):
1203 case (DL_ESTABLISH | CONFIRM):
1204 FsmEvent(&chanp->fi, EV_BC_EST, NULL);
1205 break;
1206 case (DL_RELEASE | INDICATION):
1207 case (DL_RELEASE | CONFIRM):
1208 FsmEvent(&chanp->fi, EV_BC_REL, NULL);
1209 break;
1210 default:
1211 printk(KERN_WARNING "lldata_handler unknown primitive %#x\n",
1212 pr);
1213 break;
1214 }
1215}
1216
1217static void
1218lltrans_handler(struct PStack *st, int pr, void *arg)
1219{
1220 struct Channel *chanp = (struct Channel *) st->lli.userdata;
1221 struct sk_buff *skb = arg;
1222
1223 switch (pr) {
1224 case (PH_DATA | INDICATION):
1225 if (chanp->data_open) {
1226 if (chanp->debug & 0x800)
1227 link_debug(chanp, 0, "lltrans: %d", skb->len);
1228 chanp->cs->iif.rcvcallb_skb(chanp->cs->myid, chanp->chan, skb);
1229 } else {
1230 link_debug(chanp, 0, "lltrans: channel not open");
1231 dev_kfree_skb(skb);
1232 }
1233 break;
1234 case (PH_ACTIVATE | INDICATION):
1235 case (PH_ACTIVATE | CONFIRM):
1236 FsmEvent(&chanp->fi, EV_BC_EST, NULL);
1237 break;
1238 case (PH_DEACTIVATE | INDICATION):
1239 case (PH_DEACTIVATE | CONFIRM):
1240 FsmEvent(&chanp->fi, EV_BC_REL, NULL);
1241 break;
1242 default:
1243 printk(KERN_WARNING "lltrans_handler unknown primitive %#x\n",
1244 pr);
1245 break;
1246 }
1247}
1248
1249void
1250lli_writewakeup(struct PStack *st, int len)
1251{
1252 struct Channel *chanp = st->lli.userdata;
1253 isdn_ctrl ic;
1254
1255 if (chanp->debug & 0x800)
1256 link_debug(chanp, 0, "llwakeup: %d", len);
1257 ic.driver = chanp->cs->myid;
1258 ic.command = ISDN_STAT_BSENT;
1259 ic.arg = chanp->chan;
1260 ic.parm.length = len;
1261 chanp->cs->iif.statcallb(&ic);
1262}
1263
1264static int
1265init_b_st(struct Channel *chanp, int incoming)
1266{
1267 struct PStack *st = chanp->b_st;
1268 struct IsdnCardState *cs = chanp->cs;
1269 char tmp[16];
1270
1271 st->l1.hardware = cs;
1272 if (chanp->leased)
1273 st->l1.bc = chanp->chan & 1;
1274 else
1275 st->l1.bc = chanp->proc->para.bchannel - 1;
1276 switch (chanp->l2_active_protocol) {
1277 case (ISDN_PROTO_L2_X75I):
1278 case (ISDN_PROTO_L2_HDLC):
1279 st->l1.mode = L1_MODE_HDLC;
1280 break;
1281 case (ISDN_PROTO_L2_HDLC_56K):
1282 st->l1.mode = L1_MODE_HDLC_56K;
1283 break;
1284 case (ISDN_PROTO_L2_TRANS):
1285 st->l1.mode = L1_MODE_TRANS;
1286 break;
1287 case (ISDN_PROTO_L2_MODEM):
1288 st->l1.mode = L1_MODE_V32;
1289 break;
1290 case (ISDN_PROTO_L2_FAX):
1291 st->l1.mode = L1_MODE_FAX;
1292 break;
1293 }
1294 chanp->bcs->conmsg = NULL;
1295 if (chanp->bcs->BC_SetStack(st, chanp->bcs))
1296 return (-1);
1297 st->l2.flag = 0;
1298 test_and_set_bit(FLG_LAPB, &st->l2.flag);
1299 st->l2.maxlen = MAX_DATA_SIZE;
1300 if (!incoming)
1301 test_and_set_bit(FLG_ORIG, &st->l2.flag);
1302 st->l2.T200 = 1000; /* 1000 milliseconds */
1303 st->l2.window = 7;
1304 st->l2.N200 = 4; /* try 4 times */
1305 st->l2.T203 = 5000; /* 5000 milliseconds */
1306 st->l3.debug = 0;
1307 switch (chanp->l2_active_protocol) {
1308 case (ISDN_PROTO_L2_X75I):
1309 sprintf(tmp, "Ch%d X.75", chanp->chan);
1310 setstack_isdnl2(st, tmp);
1311 setstack_l3bc(st, chanp);
1312 st->l2.l2l3 = lldata_handler;
1313 st->lli.userdata = chanp;
1314 test_and_clear_bit(FLG_LLI_L1WAKEUP, &st->lli.flag);
1315 test_and_set_bit(FLG_LLI_L2WAKEUP, &st->lli.flag);
1316 st->l2.l2m.debug = chanp->debug & 16;
1317 st->l2.debug = chanp->debug & 64;
1318 break;
1319 case (ISDN_PROTO_L2_HDLC):
1320 case (ISDN_PROTO_L2_HDLC_56K):
1321 case (ISDN_PROTO_L2_TRANS):
1322 case (ISDN_PROTO_L2_MODEM):
1323 case (ISDN_PROTO_L2_FAX):
1324 st->l1.l1l2 = lltrans_handler;
1325 st->lli.userdata = chanp;
1326 test_and_set_bit(FLG_LLI_L1WAKEUP, &st->lli.flag);
1327 test_and_clear_bit(FLG_LLI_L2WAKEUP, &st->lli.flag);
1328 setstack_transl2(st);
1329 setstack_l3bc(st, chanp);
1330 break;
1331 }
1332 test_and_set_bit(FLG_START_B, &chanp->Flags);
1333 return (0);
1334}
1335
1336static void
1337leased_l4l3(struct PStack *st, int pr, void *arg)
1338{
1339 struct Channel *chanp = (struct Channel *) st->lli.userdata;
1340 struct sk_buff *skb = arg;
1341
1342 switch (pr) {
1343 case (DL_DATA | REQUEST):
1344 link_debug(chanp, 0, "leased line d-channel DATA");
1345 dev_kfree_skb(skb);
1346 break;
1347 case (DL_ESTABLISH | REQUEST):
1348 st->l2.l2l1(st, PH_ACTIVATE | REQUEST, NULL);
1349 break;
1350 case (DL_RELEASE | REQUEST):
1351 break;
1352 default:
1353 printk(KERN_WARNING "transd_l4l3 unknown primitive %#x\n",
1354 pr);
1355 break;
1356 }
1357}
1358
1359static void
1360leased_l1l2(struct PStack *st, int pr, void *arg)
1361{
1362 struct Channel *chanp = (struct Channel *) st->lli.userdata;
1363 struct sk_buff *skb = arg;
1364 int i,event = EV_LEASED_REL;
1365
1366 switch (pr) {
1367 case (PH_DATA | INDICATION):
1368 link_debug(chanp, 0, "leased line d-channel DATA");
1369 dev_kfree_skb(skb);
1370 break;
1371 case (PH_ACTIVATE | INDICATION):
1372 case (PH_ACTIVATE | CONFIRM):
1373 event = EV_LEASED;
1374 case (PH_DEACTIVATE | INDICATION):
1375 case (PH_DEACTIVATE | CONFIRM):
1376 if (test_bit(FLG_TWO_DCHAN, &chanp->cs->HW_Flags))
1377 i = 1;
1378 else
1379 i = 0;
1380 while (i < 2) {
1381 FsmEvent(&chanp->fi, event, NULL);
1382 chanp++;
1383 i++;
1384 }
1385 break;
1386 default:
1387 printk(KERN_WARNING
1388 "transd_l1l2 unknown primitive %#x\n", pr);
1389 break;
1390 }
1391}
1392
1393static void
1394distr_debug(struct IsdnCardState *csta, int debugflags)
1395{
1396 int i;
1397 struct Channel *chanp = csta->channel;
1398
1399 for (i = 0; i < (2 + MAX_WAITING_CALLS) ; i++) {
1400 chanp[i].debug = debugflags;
1401 chanp[i].fi.debug = debugflags & 2;
1402 chanp[i].d_st->l2.l2m.debug = debugflags & 8;
1403 chanp[i].b_st->l2.l2m.debug = debugflags & 0x10;
1404 chanp[i].d_st->l2.debug = debugflags & 0x20;
1405 chanp[i].b_st->l2.debug = debugflags & 0x40;
1406 chanp[i].d_st->l3.l3m.debug = debugflags & 0x80;
1407 chanp[i].b_st->l3.l3m.debug = debugflags & 0x100;
1408 chanp[i].b_st->ma.tei_m.debug = debugflags & 0x200;
1409 chanp[i].b_st->ma.debug = debugflags & 0x200;
1410 chanp[i].d_st->l1.l1m.debug = debugflags & 0x1000;
1411 chanp[i].b_st->l1.l1m.debug = debugflags & 0x2000;
1412 }
1413 if (debugflags & 4)
1414 csta->debug |= DEB_DLOG_HEX;
1415 else
1416 csta->debug &= ~DEB_DLOG_HEX;
1417}
1418
1419static char tmpbuf[256];
1420
1421static void
1422capi_debug(struct Channel *chanp, capi_msg *cm)
1423{
1424 char *t = tmpbuf;
1425
1426 t += QuickHex(t, (u_char *)cm, (cm->Length>50)? 50: cm->Length);
1427 t--;
1428 *t= 0;
1429 HiSax_putstatus(chanp->cs, "Ch", "%d CAPIMSG %s", chanp->chan, tmpbuf);
1430}
1431
1432void
1433lli_got_fac_req(struct Channel *chanp, capi_msg *cm) {
1434 if ((cm->para[0] != 3) || (cm->para[1] != 0))
1435 return;
1436 if (cm->para[2]<3)
1437 return;
1438 if (cm->para[4] != 0)
1439 return;
1440 switch(cm->para[3]) {
1441 case 4: /* Suspend */
1442 strncpy(chanp->setup.phone, &cm->para[5], cm->para[5] +1);
1443 FsmEvent(&chanp->fi, EV_SUSPEND, cm);
1444 break;
1445 case 5: /* Resume */
1446 strncpy(chanp->setup.phone, &cm->para[5], cm->para[5] +1);
1447 if (chanp->fi.state == ST_NULL) {
1448 FsmEvent(&chanp->fi, EV_RESUME, cm);
1449 } else {
1450 FsmDelTimer(&chanp->dial_timer, 72);
1451 FsmAddTimer(&chanp->dial_timer, 80, EV_RESUME, cm, 73);
1452 }
1453 break;
1454 }
1455}
1456
1457void
1458lli_got_manufacturer(struct Channel *chanp, struct IsdnCardState *cs, capi_msg *cm) {
1459 if ((cs->typ == ISDN_CTYPE_ELSA) || (cs->typ == ISDN_CTYPE_ELSA_PNP) ||
1460 (cs->typ == ISDN_CTYPE_ELSA_PCI)) {
1461 if (cs->hw.elsa.MFlag) {
1462 cs->cardmsg(cs, CARD_AUX_IND, cm->para);
1463 }
1464 }
1465}
1466
1467
1468/***************************************************************/
1469/* Limit the available number of channels for the current card */
1470/***************************************************************/
1471static int
1472set_channel_limit(struct IsdnCardState *cs, int chanmax)
1473{
1474 isdn_ctrl ic;
1475 int i, ii;
1476
1477 if ((chanmax < 0) || (chanmax > 2))
1478 return(-EINVAL);
1479 cs->chanlimit = 0;
1480 for (ii = 0; ii < 2; ii++) {
1481 ic.driver = cs->myid;
1482 ic.command = ISDN_STAT_DISCH;
1483 ic.arg = ii;
1484 if (ii >= chanmax)
1485 ic.parm.num[0] = 0; /* disabled */
1486 else
1487 ic.parm.num[0] = 1; /* enabled */
1488 i = cs->iif.statcallb(&ic);
1489 if (i) return(-EINVAL);
1490 if (ii < chanmax)
1491 cs->chanlimit++;
1492 }
1493 return(0);
1494} /* set_channel_limit */
1495
1496int
1497HiSax_command(isdn_ctrl * ic)
1498{
1499 struct IsdnCardState *csta = hisax_findcard(ic->driver);
1500 struct PStack *st;
1501 struct Channel *chanp;
1502 int i;
1503 u_int num;
1504
1505 if (!csta) {
1506 printk(KERN_ERR
1507 "HiSax: if_command %d called with invalid driverId %d!\n",
1508 ic->command, ic->driver);
1509 return -ENODEV;
1510 }
1511 switch (ic->command) {
1512 case (ISDN_CMD_SETEAZ):
1513 chanp = csta->channel + ic->arg;
1514 break;
1515 case (ISDN_CMD_SETL2):
1516 chanp = csta->channel + (ic->arg & 0xff);
1517 if (chanp->debug & 1)
1518 link_debug(chanp, 1, "SETL2 card %d %ld",
1519 csta->cardnr + 1, ic->arg >> 8);
1520 chanp->l2_protocol = ic->arg >> 8;
1521 break;
1522 case (ISDN_CMD_SETL3):
1523 chanp = csta->channel + (ic->arg & 0xff);
1524 if (chanp->debug & 1)
1525 link_debug(chanp, 1, "SETL3 card %d %ld",
1526 csta->cardnr + 1, ic->arg >> 8);
1527 chanp->l3_protocol = ic->arg >> 8;
1528 break;
1529 case (ISDN_CMD_DIAL):
1530 chanp = csta->channel + (ic->arg & 0xff);
1531 if (chanp->debug & 1)
1532 link_debug(chanp, 1, "DIAL %s -> %s (%d,%d)",
1533 ic->parm.setup.eazmsn, ic->parm.setup.phone,
1534 ic->parm.setup.si1, ic->parm.setup.si2);
1535 memcpy(&chanp->setup, &ic->parm.setup, sizeof(setup_parm));
1536 if (!strcmp(chanp->setup.eazmsn, "0"))
1537 chanp->setup.eazmsn[0] = '\0';
1538 /* this solution is dirty and may be change, if
1539 * we make a callreference based callmanager */
1540 if (chanp->fi.state == ST_NULL) {
1541 FsmEvent(&chanp->fi, EV_DIAL, NULL);
1542 } else {
1543 FsmDelTimer(&chanp->dial_timer, 70);
1544 FsmAddTimer(&chanp->dial_timer, 50, EV_DIAL, NULL, 71);
1545 }
1546 break;
1547 case (ISDN_CMD_ACCEPTB):
1548 chanp = csta->channel + ic->arg;
1549 if (chanp->debug & 1)
1550 link_debug(chanp, 1, "ACCEPTB");
1551 FsmEvent(&chanp->fi, EV_ACCEPTB, NULL);
1552 break;
1553 case (ISDN_CMD_ACCEPTD):
1554 chanp = csta->channel + ic->arg;
1555 memcpy(&chanp->setup, &ic->parm.setup, sizeof(setup_parm));
1556 if (chanp->debug & 1)
1557 link_debug(chanp, 1, "ACCEPTD");
1558 FsmEvent(&chanp->fi, EV_ACCEPTD, NULL);
1559 break;
1560 case (ISDN_CMD_HANGUP):
1561 chanp = csta->channel + ic->arg;
1562 if (chanp->debug & 1)
1563 link_debug(chanp, 1, "HANGUP");
1564 FsmEvent(&chanp->fi, EV_HANGUP, NULL);
1565 break;
1566 case (CAPI_PUT_MESSAGE):
1567 chanp = csta->channel + ic->arg;
1568 if (chanp->debug & 1)
1569 capi_debug(chanp, &ic->parm.cmsg);
1570 if (ic->parm.cmsg.Length < 8)
1571 break;
1572 switch(ic->parm.cmsg.Command) {
1573 case CAPI_FACILITY:
1574 if (ic->parm.cmsg.Subcommand == CAPI_REQ)
1575 lli_got_fac_req(chanp, &ic->parm.cmsg);
1576 break;
1577 case CAPI_MANUFACTURER:
1578 if (ic->parm.cmsg.Subcommand == CAPI_REQ)
1579 lli_got_manufacturer(chanp, csta, &ic->parm.cmsg);
1580 break;
1581 default:
1582 break;
1583 }
1584 break;
1585 case (ISDN_CMD_IOCTL):
1586 switch (ic->arg) {
1587 case (0):
1588 num = *(unsigned int *) ic->parm.num;
1589 HiSax_reportcard(csta->cardnr, num);
1590 break;
1591 case (1):
1592 num = *(unsigned int *) ic->parm.num;
1593 distr_debug(csta, num);
1594 printk(KERN_DEBUG "HiSax: debugging flags card %d set to %x\n",
1595 csta->cardnr + 1, num);
1596 HiSax_putstatus(csta, "debugging flags ",
1597 "card %d set to %x", csta->cardnr + 1, num);
1598 break;
1599 case (2):
1600 num = *(unsigned int *) ic->parm.num;
1601 csta->channel[0].b_st->l1.delay = num;
1602 csta->channel[1].b_st->l1.delay = num;
1603 HiSax_putstatus(csta, "delay ", "card %d set to %d ms",
1604 csta->cardnr + 1, num);
1605 printk(KERN_DEBUG "HiSax: delay card %d set to %d ms\n",
1606 csta->cardnr + 1, num);
1607 break;
1608 case (5): /* set card in leased mode */
1609 num = *(unsigned int *) ic->parm.num;
1610 if ((num <1) || (num > 2)) {
1611 HiSax_putstatus(csta, "Set LEASED ",
1612 "wrong channel %d", num);
1613 printk(KERN_WARNING "HiSax: Set LEASED wrong channel %d\n",
1614 num);
1615 } else {
1616 num--;
1617 chanp = csta->channel +num;
1618 chanp->leased = 1;
1619 HiSax_putstatus(csta, "Card",
1620 "%d channel %d set leased mode\n",
1621 csta->cardnr + 1, num + 1);
1622 chanp->d_st->l1.l1l2 = leased_l1l2;
1623 chanp->d_st->lli.l4l3 = leased_l4l3;
1624 chanp->d_st->lli.l4l3(chanp->d_st,
1625 DL_ESTABLISH | REQUEST, NULL);
1626 }
1627 break;
1628 case (6): /* set B-channel test loop */
1629 num = *(unsigned int *) ic->parm.num;
1630 if (csta->stlist)
1631 csta->stlist->l2.l2l1(csta->stlist,
1632 PH_TESTLOOP | REQUEST, (void *) (long)num);
1633 break;
1634 case (7): /* set card in PTP mode */
1635 num = *(unsigned int *) ic->parm.num;
1636 if (test_bit(FLG_TWO_DCHAN, &csta->HW_Flags)) {
1637 printk(KERN_ERR "HiSax PTP mode only with one TEI possible\n");
1638 } else if (num) {
1639 test_and_set_bit(FLG_PTP, &csta->channel[0].d_st->l2.flag);
1640 test_and_set_bit(FLG_FIXED_TEI, &csta->channel[0].d_st->l2.flag);
1641 csta->channel[0].d_st->l2.tei = 0;
1642 HiSax_putstatus(csta, "set card ", "in PTP mode");
1643 printk(KERN_DEBUG "HiSax: set card in PTP mode\n");
1644 printk(KERN_INFO "LAYER2 WATCHING ESTABLISH\n");
1645 csta->channel[0].d_st->lli.l4l3(csta->channel[0].d_st,
1646 DL_ESTABLISH | REQUEST, NULL);
1647 } else {
1648 test_and_clear_bit(FLG_PTP, &csta->channel[0].d_st->l2.flag);
1649 test_and_clear_bit(FLG_FIXED_TEI, &csta->channel[0].d_st->l2.flag);
1650 HiSax_putstatus(csta, "set card ", "in PTMP mode");
1651 printk(KERN_DEBUG "HiSax: set card in PTMP mode\n");
1652 }
1653 break;
1654 case (8): /* set card in FIXED TEI mode */
1655 num = *(unsigned int *) ic->parm.num;
1656 chanp = csta->channel + (num & 1);
1657 num = num >>1;
1658 if (num == 127) {
1659 test_and_clear_bit(FLG_FIXED_TEI, &chanp->d_st->l2.flag);
1660 chanp->d_st->l2.tei = -1;
1661 HiSax_putstatus(csta, "set card ", "in VAR TEI mode");
1662 printk(KERN_DEBUG "HiSax: set card in VAR TEI mode\n");
1663 } else {
1664 test_and_set_bit(FLG_FIXED_TEI, &chanp->d_st->l2.flag);
1665 chanp->d_st->l2.tei = num;
1666 HiSax_putstatus(csta, "set card ", "in FIXED TEI (%d) mode", num);
1667 printk(KERN_DEBUG "HiSax: set card in FIXED TEI (%d) mode\n",
1668 num);
1669 }
1670 chanp->d_st->lli.l4l3(chanp->d_st,
1671 DL_ESTABLISH | REQUEST, NULL);
1672 break;
1673 case (11):
1674 num = csta->debug & DEB_DLOG_HEX;
1675 csta->debug = *(unsigned int *) ic->parm.num;
1676 csta->debug |= num;
1677 HiSax_putstatus(cards[0].cs, "l1 debugging ",
1678 "flags card %d set to %x",
1679 csta->cardnr + 1, csta->debug);
1680 printk(KERN_DEBUG "HiSax: l1 debugging flags card %d set to %x\n",
1681 csta->cardnr + 1, csta->debug);
1682 break;
1683 case (13):
1684 csta->channel[0].d_st->l3.debug = *(unsigned int *) ic->parm.num;
1685 csta->channel[1].d_st->l3.debug = *(unsigned int *) ic->parm.num;
1686 HiSax_putstatus(cards[0].cs, "l3 debugging ",
1687 "flags card %d set to %x\n", csta->cardnr + 1,
1688 *(unsigned int *) ic->parm.num);
1689 printk(KERN_DEBUG "HiSax: l3 debugging flags card %d set to %x\n",
1690 csta->cardnr + 1, *(unsigned int *) ic->parm.num);
1691 break;
1692 case (10):
1693 i = *(unsigned int *) ic->parm.num;
1694 return(set_channel_limit(csta, i));
1695 default:
1696 if (csta->auxcmd)
1697 return(csta->auxcmd(csta, ic));
1698 printk(KERN_DEBUG "HiSax: invalid ioclt %d\n",
1699 (int) ic->arg);
1700 return (-EINVAL);
1701 }
1702 break;
1703
1704 case (ISDN_CMD_PROCEED):
1705 chanp = csta->channel + ic->arg;
1706 if (chanp->debug & 1)
1707 link_debug(chanp, 1, "PROCEED");
1708 FsmEvent(&chanp->fi, EV_PROCEED, NULL);
1709 break;
1710
1711 case (ISDN_CMD_ALERT):
1712 chanp = csta->channel + ic->arg;
1713 if (chanp->debug & 1)
1714 link_debug(chanp, 1, "ALERT");
1715 FsmEvent(&chanp->fi, EV_ALERT, NULL);
1716 break;
1717
1718 case (ISDN_CMD_REDIR):
1719 chanp = csta->channel + ic->arg;
1720 if (chanp->debug & 1)
1721 link_debug(chanp, 1, "REDIR");
1722 memcpy(&chanp->setup, &ic->parm.setup, sizeof(setup_parm));
1723 FsmEvent(&chanp->fi, EV_REDIR, NULL);
1724 break;
1725
1726 /* protocol specific io commands */
1727 case (ISDN_CMD_PROT_IO):
1728 for (st = csta->stlist; st; st = st->next)
1729 if (st->protocol == (ic->arg & 0xFF))
1730 return(st->lli.l4l3_proto(st, ic));
1731 return(-EINVAL);
1732 break;
1733 default:
1734 if (csta->auxcmd)
1735 return(csta->auxcmd(csta, ic));
1736 return(-EINVAL);
1737 }
1738 return (0);
1739}
1740
1741int
1742HiSax_writebuf_skb(int id, int chan, int ack, struct sk_buff *skb)
1743{
1744 struct IsdnCardState *csta = hisax_findcard(id);
1745 struct Channel *chanp;
1746 struct PStack *st;
1747 int len = skb->len;
1748 struct sk_buff *nskb;
1749
1750 if (!csta) {
1751 printk(KERN_ERR
1752 "HiSax: if_sendbuf called with invalid driverId!\n");
1753 return -ENODEV;
1754 }
1755 chanp = csta->channel + chan;
1756 st = chanp->b_st;
1757 if (!chanp->data_open) {
1758 link_debug(chanp, 1, "writebuf: channel not open");
1759 return -EIO;
1760 }
1761 if (len > MAX_DATA_SIZE) {
1762 link_debug(chanp, 1, "writebuf: packet too large (%d bytes)", len);
1763 printk(KERN_WARNING "HiSax_writebuf: packet too large (%d bytes) !\n",
1764 len);
1765 return -EINVAL;
1766 }
1767 if (len) {
1768 if ((len + chanp->bcs->tx_cnt) > MAX_DATA_MEM) {
1769 /* Must return 0 here, since this is not an error
1770 * but a temporary lack of resources.
1771 */
1772 if (chanp->debug & 0x800)
1773 link_debug(chanp, 1, "writebuf: no buffers for %d bytes", len);
1774 return 0;
1775 } else if (chanp->debug & 0x800)
1776 link_debug(chanp, 1, "writebuf %d/%d/%d", len, chanp->bcs->tx_cnt,MAX_DATA_MEM);
1777 nskb = skb_clone(skb, GFP_ATOMIC);
1778 if (nskb) {
1779 nskb->truesize = nskb->len;
1780 if (!ack)
1781 nskb->pkt_type = PACKET_NOACK;
1782 if (chanp->l2_active_protocol == ISDN_PROTO_L2_X75I)
1783 st->l3.l3l2(st, DL_DATA | REQUEST, nskb);
1784 else {
1785 chanp->bcs->tx_cnt += len;
1786 st->l2.l2l1(st, PH_DATA | REQUEST, nskb);
1787 }
1788 dev_kfree_skb(skb);
1789 } else
1790 len = 0;
1791 }
1792 return (len);
1793}
diff --git a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c
new file mode 100644
index 000000000000..1663ee69d41d
--- /dev/null
+++ b/drivers/isdn/hisax/config.c
@@ -0,0 +1,1958 @@
1/* $Id: config.c,v 2.84.2.5 2004/02/11 13:21:33 keil Exp $
2 *
3 * Author Karsten Keil
4 * Copyright by Karsten Keil <keil@isdn4linux.de>
5 * by Kai Germaschewski <kai.germaschewski@gmx.de>
6 *
7 * This software may be used and distributed according to the terms
8 * of the GNU General Public License, incorporated herein by reference.
9 *
10 * For changes and modifications please read
11 * Documentation/isdn/HiSax.cert
12 *
13 * based on the teles driver from Jan den Ouden
14 *
15 */
16
17#include <linux/types.h>
18#include <linux/stddef.h>
19#include <linux/timer.h>
20#include <linux/config.h>
21#include <linux/init.h>
22#include "hisax.h"
23#include <linux/module.h>
24#include <linux/kernel_stat.h>
25#include <linux/workqueue.h>
26#include <linux/interrupt.h>
27#define HISAX_STATUS_BUFSIZE 4096
28#define INCLUDE_INLINE_FUNCS
29
30/*
31 * This structure array contains one entry per card. An entry looks
32 * like this:
33 *
34 * { type, protocol, p0, p1, p2, NULL }
35 *
36 * type
37 * 1 Teles 16.0 p0=irq p1=membase p2=iobase
38 * 2 Teles 8.0 p0=irq p1=membase
39 * 3 Teles 16.3 p0=irq p1=iobase
40 * 4 Creatix PNP p0=irq p1=IO0 (ISAC) p2=IO1 (HSCX)
41 * 5 AVM A1 (Fritz) p0=irq p1=iobase
42 * 6 ELSA PC [p0=iobase] or nothing (autodetect)
43 * 7 ELSA Quickstep p0=irq p1=iobase
44 * 8 Teles PCMCIA p0=irq p1=iobase
45 * 9 ITK ix1-micro p0=irq p1=iobase
46 * 10 ELSA PCMCIA p0=irq p1=iobase
47 * 11 Eicon.Diehl Diva p0=irq p1=iobase
48 * 12 Asuscom ISDNLink p0=irq p1=iobase
49 * 13 Teleint p0=irq p1=iobase
50 * 14 Teles 16.3c p0=irq p1=iobase
51 * 15 Sedlbauer speed p0=irq p1=iobase
52 * 15 Sedlbauer PC/104 p0=irq p1=iobase
53 * 15 Sedlbauer speed pci no parameter
54 * 16 USR Sportster internal p0=irq p1=iobase
55 * 17 MIC card p0=irq p1=iobase
56 * 18 ELSA Quickstep 1000PCI no parameter
57 * 19 Compaq ISDN S0 ISA card p0=irq p1=IO0 (HSCX) p2=IO1 (ISAC) p3=IO2
58 * 20 Travers Technologies NETjet-S PCI card
59 * 21 TELES PCI no parameter
60 * 22 Sedlbauer Speed Star p0=irq p1=iobase
61 * 23 reserved
62 * 24 Dr Neuhaus Niccy PnP/PCI card p0=irq p1=IO0 p2=IO1 (PnP only)
63 * 25 Teles S0Box p0=irq p1=iobase (from isapnp setup)
64 * 26 AVM A1 PCMCIA (Fritz) p0=irq p1=iobase
65 * 27 AVM PnP/PCI p0=irq p1=iobase (PCI no parameter)
66 * 28 Sedlbauer Speed Fax+ p0=irq p1=iobase (from isapnp setup)
67 * 29 Siemens I-Surf p0=irq p1=iobase p2=memory (from isapnp setup)
68 * 30 ACER P10 p0=irq p1=iobase (from isapnp setup)
69 * 31 HST Saphir p0=irq p1=iobase
70 * 32 Telekom A4T none
71 * 33 Scitel Quadro p0=subcontroller (4*S0, subctrl 1...4)
72 * 34 Gazel ISDN cards
73 * 35 HFC 2BDS0 PCI none
74 * 36 Winbond 6692 PCI none
75 * 37 HFC 2BDS0 S+/SP p0=irq p1=iobase
76 * 38 Travers Technologies NETspider-U PCI card
77 * 39 HFC 2BDS0-SP PCMCIA p0=irq p1=iobase
78 * 40 hotplug interface
79 * 41 Formula-n enter:now ISDN PCI a/b none
80 *
81 * protocol can be either ISDN_PTYPE_EURO or ISDN_PTYPE_1TR6 or ISDN_PTYPE_NI1
82 *
83 *
84 */
85
86const char *CardType[] = {
87 "No Card", "Teles 16.0", "Teles 8.0", "Teles 16.3",
88 "Creatix/Teles PnP", "AVM A1", "Elsa ML", "Elsa Quickstep",
89 "Teles PCMCIA", "ITK ix1-micro Rev.2", "Elsa PCMCIA",
90 "Eicon.Diehl Diva", "ISDNLink", "TeleInt", "Teles 16.3c",
91 "Sedlbauer Speed Card", "USR Sportster", "ith mic Linux",
92 "Elsa PCI", "Compaq ISA", "NETjet-S", "Teles PCI",
93 "Sedlbauer Speed Star (PCMCIA)", "AMD 7930", "NICCY", "S0Box",
94 "AVM A1 (PCMCIA)", "AVM Fritz PnP/PCI", "Sedlbauer Speed Fax +",
95 "Siemens I-Surf", "Acer P10", "HST Saphir", "Telekom A4T",
96 "Scitel Quadro", "Gazel", "HFC 2BDS0 PCI", "Winbond 6692",
97 "HFC 2BDS0 SX", "NETspider-U", "HFC-2BDS0-SP PCMCIA",
98 "Hotplug", "Formula-n enter:now PCI a/b",
99};
100
101#ifdef CONFIG_HISAX_ELSA
102#define DEFAULT_CARD ISDN_CTYPE_ELSA
103#define DEFAULT_CFG {0,0,0,0}
104#endif
105
106#ifdef CONFIG_HISAX_AVM_A1
107#undef DEFAULT_CARD
108#undef DEFAULT_CFG
109#define DEFAULT_CARD ISDN_CTYPE_A1
110#define DEFAULT_CFG {10,0x340,0,0}
111#endif
112
113#ifdef CONFIG_HISAX_AVM_A1_PCMCIA
114#undef DEFAULT_CARD
115#undef DEFAULT_CFG
116#define DEFAULT_CARD ISDN_CTYPE_A1_PCMCIA
117#define DEFAULT_CFG {11,0x170,0,0}
118#endif
119
120#ifdef CONFIG_HISAX_FRITZPCI
121#undef DEFAULT_CARD
122#undef DEFAULT_CFG
123#define DEFAULT_CARD ISDN_CTYPE_FRITZPCI
124#define DEFAULT_CFG {0,0,0,0}
125#endif
126
127#ifdef CONFIG_HISAX_16_3
128#undef DEFAULT_CARD
129#undef DEFAULT_CFG
130#define DEFAULT_CARD ISDN_CTYPE_16_3
131#define DEFAULT_CFG {15,0x180,0,0}
132#endif
133
134#ifdef CONFIG_HISAX_S0BOX
135#undef DEFAULT_CARD
136#undef DEFAULT_CFG
137#define DEFAULT_CARD ISDN_CTYPE_S0BOX
138#define DEFAULT_CFG {7,0x378,0,0}
139#endif
140
141#ifdef CONFIG_HISAX_16_0
142#undef DEFAULT_CARD
143#undef DEFAULT_CFG
144#define DEFAULT_CARD ISDN_CTYPE_16_0
145#define DEFAULT_CFG {15,0xd0000,0xd80,0}
146#endif
147
148#ifdef CONFIG_HISAX_TELESPCI
149#undef DEFAULT_CARD
150#undef DEFAULT_CFG
151#define DEFAULT_CARD ISDN_CTYPE_TELESPCI
152#define DEFAULT_CFG {0,0,0,0}
153#endif
154
155#ifdef CONFIG_HISAX_IX1MICROR2
156#undef DEFAULT_CARD
157#undef DEFAULT_CFG
158#define DEFAULT_CARD ISDN_CTYPE_IX1MICROR2
159#define DEFAULT_CFG {5,0x390,0,0}
160#endif
161
162#ifdef CONFIG_HISAX_DIEHLDIVA
163#undef DEFAULT_CARD
164#undef DEFAULT_CFG
165#define DEFAULT_CARD ISDN_CTYPE_DIEHLDIVA
166#define DEFAULT_CFG {0,0x0,0,0}
167#endif
168
169#ifdef CONFIG_HISAX_ASUSCOM
170#undef DEFAULT_CARD
171#undef DEFAULT_CFG
172#define DEFAULT_CARD ISDN_CTYPE_ASUSCOM
173#define DEFAULT_CFG {5,0x200,0,0}
174#endif
175
176#ifdef CONFIG_HISAX_TELEINT
177#undef DEFAULT_CARD
178#undef DEFAULT_CFG
179#define DEFAULT_CARD ISDN_CTYPE_TELEINT
180#define DEFAULT_CFG {5,0x300,0,0}
181#endif
182
183#ifdef CONFIG_HISAX_SEDLBAUER
184#undef DEFAULT_CARD
185#undef DEFAULT_CFG
186#define DEFAULT_CARD ISDN_CTYPE_SEDLBAUER
187#define DEFAULT_CFG {11,0x270,0,0}
188#endif
189
190#ifdef CONFIG_HISAX_SPORTSTER
191#undef DEFAULT_CARD
192#undef DEFAULT_CFG
193#define DEFAULT_CARD ISDN_CTYPE_SPORTSTER
194#define DEFAULT_CFG {7,0x268,0,0}
195#endif
196
197#ifdef CONFIG_HISAX_MIC
198#undef DEFAULT_CARD
199#undef DEFAULT_CFG
200#define DEFAULT_CARD ISDN_CTYPE_MIC
201#define DEFAULT_CFG {12,0x3e0,0,0}
202#endif
203
204#ifdef CONFIG_HISAX_NETJET
205#undef DEFAULT_CARD
206#undef DEFAULT_CFG
207#define DEFAULT_CARD ISDN_CTYPE_NETJET_S
208#define DEFAULT_CFG {0,0,0,0}
209#endif
210
211#ifdef CONFIG_HISAX_HFCS
212#undef DEFAULT_CARD
213#undef DEFAULT_CFG
214#define DEFAULT_CARD ISDN_CTYPE_TELES3C
215#define DEFAULT_CFG {5,0x500,0,0}
216#endif
217
218#ifdef CONFIG_HISAX_HFC_PCI
219#undef DEFAULT_CARD
220#undef DEFAULT_CFG
221#define DEFAULT_CARD ISDN_CTYPE_HFC_PCI
222#define DEFAULT_CFG {0,0,0,0}
223#endif
224
225#ifdef CONFIG_HISAX_HFC_SX
226#undef DEFAULT_CARD
227#undef DEFAULT_CFG
228#define DEFAULT_CARD ISDN_CTYPE_HFC_SX
229#define DEFAULT_CFG {5,0x2E0,0,0}
230#endif
231
232
233#ifdef CONFIG_HISAX_AMD7930
234#undef DEFAULT_CARD
235#undef DEFAULT_CFG
236#define DEFAULT_CARD ISDN_CTYPE_AMD7930
237#define DEFAULT_CFG {12,0x3e0,0,0}
238#endif
239
240#ifdef CONFIG_HISAX_NICCY
241#undef DEFAULT_CARD
242#undef DEFAULT_CFG
243#define DEFAULT_CARD ISDN_CTYPE_NICCY
244#define DEFAULT_CFG {0,0x0,0,0}
245#endif
246
247#ifdef CONFIG_HISAX_ISURF
248#undef DEFAULT_CARD
249#undef DEFAULT_CFG
250#define DEFAULT_CARD ISDN_CTYPE_ISURF
251#define DEFAULT_CFG {5,0x100,0xc8000,0}
252#endif
253
254#ifdef CONFIG_HISAX_HSTSAPHIR
255#undef DEFAULT_CARD
256#undef DEFAULT_CFG
257#define DEFAULT_CARD ISDN_CTYPE_HSTSAPHIR
258#define DEFAULT_CFG {5,0x250,0,0}
259#endif
260
261#ifdef CONFIG_HISAX_BKM_A4T
262#undef DEFAULT_CARD
263#undef DEFAULT_CFG
264#define DEFAULT_CARD ISDN_CTYPE_BKM_A4T
265#define DEFAULT_CFG {0,0x0,0,0}
266#endif
267
268#ifdef CONFIG_HISAX_SCT_QUADRO
269#undef DEFAULT_CARD
270#undef DEFAULT_CFG
271#define DEFAULT_CARD ISDN_CTYPE_SCT_QUADRO
272#define DEFAULT_CFG {1,0x0,0,0}
273#endif
274
275#ifdef CONFIG_HISAX_GAZEL
276#undef DEFAULT_CARD
277#undef DEFAULT_CFG
278#define DEFAULT_CARD ISDN_CTYPE_GAZEL
279#define DEFAULT_CFG {15,0x180,0,0}
280#endif
281
282#ifdef CONFIG_HISAX_W6692
283#undef DEFAULT_CARD
284#undef DEFAULT_CFG
285#define DEFAULT_CARD ISDN_CTYPE_W6692
286#define DEFAULT_CFG {0,0,0,0}
287#endif
288
289#ifdef CONFIG_HISAX_NETJET_U
290#undef DEFAULT_CARD
291#undef DEFAULT_CFG
292#define DEFAULT_CARD ISDN_CTYPE_NETJET_U
293#define DEFAULT_CFG {0,0,0,0}
294#endif
295
296#ifdef CONFIG_HISAX_1TR6
297#define DEFAULT_PROTO ISDN_PTYPE_1TR6
298#define DEFAULT_PROTO_NAME "1TR6"
299#endif
300#ifdef CONFIG_HISAX_NI1
301#undef DEFAULT_PROTO
302#define DEFAULT_PROTO ISDN_PTYPE_NI1
303#undef DEFAULT_PROTO_NAME
304#define DEFAULT_PROTO_NAME "NI1"
305#endif
306#ifdef CONFIG_HISAX_EURO
307#undef DEFAULT_PROTO
308#define DEFAULT_PROTO ISDN_PTYPE_EURO
309#undef DEFAULT_PROTO_NAME
310#define DEFAULT_PROTO_NAME "EURO"
311#endif
312#ifndef DEFAULT_PROTO
313#define DEFAULT_PROTO ISDN_PTYPE_UNKNOWN
314#define DEFAULT_PROTO_NAME "UNKNOWN"
315#endif
316#ifndef DEFAULT_CARD
317#define DEFAULT_CARD 0
318#define DEFAULT_CFG {0,0,0,0}
319#endif
320
321#define FIRST_CARD { \
322 DEFAULT_CARD, \
323 DEFAULT_PROTO, \
324 DEFAULT_CFG, \
325 NULL, \
326}
327
328struct IsdnCard cards[HISAX_MAX_CARDS] = {
329 FIRST_CARD,
330};
331
332#define HISAX_IDSIZE (HISAX_MAX_CARDS*8)
333static char HiSaxID[HISAX_IDSIZE] = { 0, };
334
335char *HiSax_id = HiSaxID;
336#ifdef MODULE
337/* Variables for insmod */
338static int type[HISAX_MAX_CARDS] = { 0, };
339static int protocol[HISAX_MAX_CARDS] = { 0, };
340static int io[HISAX_MAX_CARDS] = { 0, };
341#undef IO0_IO1
342#ifdef CONFIG_HISAX_16_3
343#define IO0_IO1
344#endif
345#ifdef CONFIG_HISAX_NICCY
346#undef IO0_IO1
347#define IO0_IO1
348#endif
349#ifdef IO0_IO1
350static int io0[HISAX_MAX_CARDS] __devinitdata = { 0, };
351static int io1[HISAX_MAX_CARDS] __devinitdata = { 0, };
352#endif
353static int irq[HISAX_MAX_CARDS] __devinitdata = { 0, };
354static int mem[HISAX_MAX_CARDS] __devinitdata = { 0, };
355static char *id = HiSaxID;
356
357MODULE_DESCRIPTION("ISDN4Linux: Driver for passive ISDN cards");
358MODULE_AUTHOR("Karsten Keil");
359MODULE_LICENSE("GPL");
360module_param_array(type, int, NULL, 0);
361module_param_array(protocol, int, NULL, 0);
362module_param_array(io, int, NULL, 0);
363module_param_array(irq, int, NULL, 0);
364module_param_array(mem, int, NULL, 0);
365module_param(id, charp, 0);
366#ifdef IO0_IO1
367module_param_array(io0, int, NULL, 0);
368module_param_array(io1, int, NULL, 0);
369#endif
370#endif /* MODULE */
371
372int nrcards;
373
374extern char *l1_revision;
375extern char *l2_revision;
376extern char *l3_revision;
377extern char *lli_revision;
378extern char *tei_revision;
379
380char *HiSax_getrev(const char *revision)
381{
382 char *rev;
383 char *p;
384
385 if ((p = strchr(revision, ':'))) {
386 rev = p + 2;
387 p = strchr(rev, '$');
388 *--p = 0;
389 } else
390 rev = "???";
391 return rev;
392}
393
394void __init HiSaxVersion(void)
395{
396 char tmp[64];
397
398 printk(KERN_INFO "HiSax: Linux Driver for passive ISDN cards\n");
399#ifdef MODULE
400 printk(KERN_INFO "HiSax: Version 3.5 (module)\n");
401#else
402 printk(KERN_INFO "HiSax: Version 3.5 (kernel)\n");
403#endif
404 strcpy(tmp, l1_revision);
405 printk(KERN_INFO "HiSax: Layer1 Revision %s\n", HiSax_getrev(tmp));
406 strcpy(tmp, l2_revision);
407 printk(KERN_INFO "HiSax: Layer2 Revision %s\n", HiSax_getrev(tmp));
408 strcpy(tmp, tei_revision);
409 printk(KERN_INFO "HiSax: TeiMgr Revision %s\n", HiSax_getrev(tmp));
410 strcpy(tmp, l3_revision);
411 printk(KERN_INFO "HiSax: Layer3 Revision %s\n", HiSax_getrev(tmp));
412 strcpy(tmp, lli_revision);
413 printk(KERN_INFO "HiSax: LinkLayer Revision %s\n",
414 HiSax_getrev(tmp));
415}
416
417#ifndef MODULE
418#define MAX_ARG (HISAX_MAX_CARDS*5)
419static int __init HiSax_setup(char *line)
420{
421 int i, j, argc;
422 int ints[MAX_ARG + 1];
423 char *str;
424
425 str = get_options(line, MAX_ARG, ints);
426 argc = ints[0];
427 printk(KERN_DEBUG "HiSax_setup: argc(%d) str(%s)\n", argc, str);
428 i = 0;
429 j = 1;
430 while (argc && (i < HISAX_MAX_CARDS)) {
431 cards[i].protocol = DEFAULT_PROTO;
432 if (argc) {
433 cards[i].typ = ints[j];
434 j++;
435 argc--;
436 }
437 if (argc) {
438 cards[i].protocol = ints[j];
439 j++;
440 argc--;
441 }
442 if (argc) {
443 cards[i].para[0] = ints[j];
444 j++;
445 argc--;
446 }
447 if (argc) {
448 cards[i].para[1] = ints[j];
449 j++;
450 argc--;
451 }
452 if (argc) {
453 cards[i].para[2] = ints[j];
454 j++;
455 argc--;
456 }
457 i++;
458 }
459 if (str && *str) {
460 if (strlen(str) < HISAX_IDSIZE)
461 strcpy(HiSaxID, str);
462 else
463 printk(KERN_WARNING "HiSax: ID too long!");
464 } else
465 strcpy(HiSaxID, "HiSax");
466
467 HiSax_id = HiSaxID;
468 return 1;
469}
470
471__setup("hisax=", HiSax_setup);
472#endif /* MODULES */
473
474#if CARD_TELES0
475extern int setup_teles0(struct IsdnCard *card);
476#endif
477
478#if CARD_TELES3
479extern int setup_teles3(struct IsdnCard *card);
480#endif
481
482#if CARD_S0BOX
483extern int setup_s0box(struct IsdnCard *card);
484#endif
485
486#if CARD_TELESPCI
487extern int setup_telespci(struct IsdnCard *card);
488#endif
489
490#if CARD_AVM_A1
491extern int setup_avm_a1(struct IsdnCard *card);
492#endif
493
494#if CARD_AVM_A1_PCMCIA
495extern int setup_avm_a1_pcmcia(struct IsdnCard *card);
496#endif
497
498#if CARD_FRITZPCI
499extern int setup_avm_pcipnp(struct IsdnCard *card);
500#endif
501
502#if CARD_ELSA
503extern int setup_elsa(struct IsdnCard *card);
504#endif
505
506#if CARD_IX1MICROR2
507extern int setup_ix1micro(struct IsdnCard *card);
508#endif
509
510#if CARD_DIEHLDIVA
511extern int setup_diva(struct IsdnCard *card);
512#endif
513
514#if CARD_ASUSCOM
515extern int setup_asuscom(struct IsdnCard *card);
516#endif
517
518#if CARD_TELEINT
519extern int setup_TeleInt(struct IsdnCard *card);
520#endif
521
522#if CARD_SEDLBAUER
523extern int setup_sedlbauer(struct IsdnCard *card);
524#endif
525
526#if CARD_SPORTSTER
527extern int setup_sportster(struct IsdnCard *card);
528#endif
529
530#if CARD_MIC
531extern int setup_mic(struct IsdnCard *card);
532#endif
533
534#if CARD_NETJET_S
535extern int setup_netjet_s(struct IsdnCard *card);
536#endif
537
538#if CARD_HFCS
539extern int setup_hfcs(struct IsdnCard *card);
540#endif
541
542#if CARD_HFC_PCI
543extern int setup_hfcpci(struct IsdnCard *card);
544#endif
545
546#if CARD_HFC_SX
547extern int setup_hfcsx(struct IsdnCard *card);
548#endif
549
550#if CARD_AMD7930
551extern int setup_amd7930(struct IsdnCard *card);
552#endif
553
554#if CARD_NICCY
555extern int setup_niccy(struct IsdnCard *card);
556#endif
557
558#if CARD_ISURF
559extern int setup_isurf(struct IsdnCard *card);
560#endif
561
562#if CARD_HSTSAPHIR
563extern int setup_saphir(struct IsdnCard *card);
564#endif
565
566#if CARD_TESTEMU
567extern int setup_testemu(struct IsdnCard *card);
568#endif
569
570#if CARD_BKM_A4T
571extern int setup_bkm_a4t(struct IsdnCard *card);
572#endif
573
574#if CARD_SCT_QUADRO
575extern int setup_sct_quadro(struct IsdnCard *card);
576#endif
577
578#if CARD_GAZEL
579extern int setup_gazel(struct IsdnCard *card);
580#endif
581
582#if CARD_W6692
583extern int setup_w6692(struct IsdnCard *card);
584#endif
585
586#if CARD_NETJET_U
587extern int setup_netjet_u(struct IsdnCard *card);
588#endif
589
590#if CARD_FN_ENTERNOW_PCI
591extern int setup_enternow_pci(struct IsdnCard *card);
592#endif
593
594/*
595 * Find card with given driverId
596 */
597static inline struct IsdnCardState *hisax_findcard(int driverid)
598{
599 int i;
600
601 for (i = 0; i < nrcards; i++)
602 if (cards[i].cs)
603 if (cards[i].cs->myid == driverid)
604 return cards[i].cs;
605 return NULL;
606}
607
608/*
609 * Find card with given card number
610 */
611struct IsdnCardState *hisax_get_card(int cardnr)
612{
613 if ((cardnr <= nrcards) && (cardnr > 0))
614 if (cards[cardnr - 1].cs)
615 return cards[cardnr - 1].cs;
616 return NULL;
617}
618
619int HiSax_readstatus(u_char __user *buf, int len, int id, int channel)
620{
621 int count, cnt;
622 u_char __user *p = buf;
623 struct IsdnCardState *cs = hisax_findcard(id);
624
625 if (cs) {
626 if (len > HISAX_STATUS_BUFSIZE) {
627 printk(KERN_WARNING
628 "HiSax: status overflow readstat %d/%d\n",
629 len, HISAX_STATUS_BUFSIZE);
630 }
631 count = cs->status_end - cs->status_read + 1;
632 if (count >= len)
633 count = len;
634 copy_to_user(p, cs->status_read, count);
635 cs->status_read += count;
636 if (cs->status_read > cs->status_end)
637 cs->status_read = cs->status_buf;
638 p += count;
639 count = len - count;
640 while (count) {
641 if (count > HISAX_STATUS_BUFSIZE)
642 cnt = HISAX_STATUS_BUFSIZE;
643 else
644 cnt = count;
645 copy_to_user(p, cs->status_read, cnt);
646 p += cnt;
647 cs->status_read += cnt % HISAX_STATUS_BUFSIZE;
648 count -= cnt;
649 }
650 return len;
651 } else {
652 printk(KERN_ERR
653 "HiSax: if_readstatus called with invalid driverId!\n");
654 return -ENODEV;
655 }
656}
657
658int jiftime(char *s, long mark)
659{
660 s += 8;
661
662 *s-- = '\0';
663 *s-- = mark % 10 + '0';
664 mark /= 10;
665 *s-- = mark % 10 + '0';
666 mark /= 10;
667 *s-- = '.';
668 *s-- = mark % 10 + '0';
669 mark /= 10;
670 *s-- = mark % 6 + '0';
671 mark /= 6;
672 *s-- = ':';
673 *s-- = mark % 10 + '0';
674 mark /= 10;
675 *s-- = mark % 10 + '0';
676 return 8;
677}
678
679static u_char tmpbuf[HISAX_STATUS_BUFSIZE];
680
681void VHiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt,
682 va_list args)
683{
684 /* if head == NULL the fmt contains the full info */
685
686 u_long flags;
687 int count, i;
688 u_char *p;
689 isdn_ctrl ic;
690 int len;
691
692 if (!cs) {
693 printk(KERN_WARNING "HiSax: No CardStatus for message");
694 return;
695 }
696 spin_lock_irqsave(&cs->statlock, flags);
697 p = tmpbuf;
698 if (head) {
699 p += jiftime(p, jiffies);
700 p += sprintf(p, " %s", head);
701 p += vsprintf(p, fmt, args);
702 *p++ = '\n';
703 *p = 0;
704 len = p - tmpbuf;
705 p = tmpbuf;
706 } else {
707 p = fmt;
708 len = strlen(fmt);
709 }
710 if (len > HISAX_STATUS_BUFSIZE) {
711 spin_unlock_irqrestore(&cs->statlock, flags);
712 printk(KERN_WARNING "HiSax: status overflow %d/%d\n",
713 len, HISAX_STATUS_BUFSIZE);
714 return;
715 }
716 count = len;
717 i = cs->status_end - cs->status_write + 1;
718 if (i >= len)
719 i = len;
720 len -= i;
721 memcpy(cs->status_write, p, i);
722 cs->status_write += i;
723 if (cs->status_write > cs->status_end)
724 cs->status_write = cs->status_buf;
725 p += i;
726 if (len) {
727 memcpy(cs->status_write, p, len);
728 cs->status_write += len;
729 }
730#ifdef KERNELSTACK_DEBUG
731 i = (ulong) & len - current->kernel_stack_page;
732 sprintf(tmpbuf, "kstack %s %lx use %ld\n", current->comm,
733 current->kernel_stack_page, i);
734 len = strlen(tmpbuf);
735 for (p = tmpbuf, i = len; i > 0; i--, p++) {
736 *cs->status_write++ = *p;
737 if (cs->status_write > cs->status_end)
738 cs->status_write = cs->status_buf;
739 count++;
740 }
741#endif
742 spin_unlock_irqrestore(&cs->statlock, flags);
743 if (count) {
744 ic.command = ISDN_STAT_STAVAIL;
745 ic.driver = cs->myid;
746 ic.arg = count;
747 cs->iif.statcallb(&ic);
748 }
749}
750
751void HiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, ...)
752{
753 va_list args;
754
755 va_start(args, fmt);
756 VHiSax_putstatus(cs, head, fmt, args);
757 va_end(args);
758}
759
760int ll_run(struct IsdnCardState *cs, int addfeatures)
761{
762 isdn_ctrl ic;
763
764 ic.driver = cs->myid;
765 ic.command = ISDN_STAT_RUN;
766 cs->iif.features |= addfeatures;
767 cs->iif.statcallb(&ic);
768 return 0;
769}
770
771void ll_stop(struct IsdnCardState *cs)
772{
773 isdn_ctrl ic;
774
775 ic.command = ISDN_STAT_STOP;
776 ic.driver = cs->myid;
777 cs->iif.statcallb(&ic);
778 // CallcFreeChan(cs);
779}
780
781static void ll_unload(struct IsdnCardState *cs)
782{
783 isdn_ctrl ic;
784
785 ic.command = ISDN_STAT_UNLOAD;
786 ic.driver = cs->myid;
787 cs->iif.statcallb(&ic);
788 if (cs->status_buf)
789 kfree(cs->status_buf);
790 cs->status_read = NULL;
791 cs->status_write = NULL;
792 cs->status_end = NULL;
793 kfree(cs->dlog);
794 cs->dlog = NULL;
795}
796
797static void closecard(int cardnr)
798{
799 struct IsdnCardState *csta = cards[cardnr].cs;
800
801 if (csta->bcs->BC_Close != NULL) {
802 csta->bcs->BC_Close(csta->bcs + 1);
803 csta->bcs->BC_Close(csta->bcs);
804 }
805
806 skb_queue_purge(&csta->rq);
807 skb_queue_purge(&csta->sq);
808 if (csta->rcvbuf) {
809 kfree(csta->rcvbuf);
810 csta->rcvbuf = NULL;
811 }
812 if (csta->tx_skb) {
813 dev_kfree_skb(csta->tx_skb);
814 csta->tx_skb = NULL;
815 }
816 if (csta->DC_Close != NULL) {
817 csta->DC_Close(csta);
818 }
819 if (csta->cardmsg)
820 csta->cardmsg(csta, CARD_RELEASE, NULL);
821 if (csta->dbusytimer.function != NULL) // FIXME?
822 del_timer(&csta->dbusytimer);
823 ll_unload(csta);
824}
825
826static int init_card(struct IsdnCardState *cs)
827{
828 int irq_cnt, cnt = 3, ret;
829
830 if (!cs->irq) {
831 ret = cs->cardmsg(cs, CARD_INIT, NULL);
832 return(ret);
833 }
834 irq_cnt = kstat_irqs(cs->irq);
835 printk(KERN_INFO "%s: IRQ %d count %d\n", CardType[cs->typ],
836 cs->irq, irq_cnt);
837 if (request_irq(cs->irq, cs->irq_func, cs->irq_flags, "HiSax", cs)) {
838 printk(KERN_WARNING "HiSax: couldn't get interrupt %d\n",
839 cs->irq);
840 return 1;
841 }
842 while (cnt) {
843 cs->cardmsg(cs, CARD_INIT, NULL);
844 /* Timeout 10ms */
845 msleep(10);
846 printk(KERN_INFO "%s: IRQ %d count %d\n",
847 CardType[cs->typ], cs->irq, kstat_irqs(cs->irq));
848 if (kstat_irqs(cs->irq) == irq_cnt) {
849 printk(KERN_WARNING
850 "%s: IRQ(%d) getting no interrupts during init %d\n",
851 CardType[cs->typ], cs->irq, 4 - cnt);
852 if (cnt == 1) {
853 free_irq(cs->irq, cs);
854 return 2;
855 } else {
856 cs->cardmsg(cs, CARD_RESET, NULL);
857 cnt--;
858 }
859 } else {
860 cs->cardmsg(cs, CARD_TEST, NULL);
861 return 0;
862 }
863 }
864 return 3;
865}
866
867static int checkcard(int cardnr, char *id, int *busy_flag, struct module *lockowner)
868{
869 int ret = 0;
870 struct IsdnCard *card = cards + cardnr;
871 struct IsdnCardState *cs;
872
873 cs = kmalloc(sizeof(struct IsdnCardState), GFP_ATOMIC);
874 if (!cs) {
875 printk(KERN_WARNING
876 "HiSax: No memory for IsdnCardState(card %d)\n",
877 cardnr + 1);
878 goto out;
879 }
880 memset(cs, 0, sizeof(struct IsdnCardState));
881 card->cs = cs;
882 spin_lock_init(&cs->statlock);
883 spin_lock_init(&cs->lock);
884 cs->chanlimit = 2; /* maximum B-channel number */
885 cs->logecho = 0; /* No echo logging */
886 cs->cardnr = cardnr;
887 cs->debug = L1_DEB_WARN;
888 cs->HW_Flags = 0;
889 cs->busy_flag = busy_flag;
890 cs->irq_flags = I4L_IRQ_FLAG;
891#if TEI_PER_CARD
892 if (card->protocol == ISDN_PTYPE_NI1)
893 test_and_set_bit(FLG_TWO_DCHAN, &cs->HW_Flags);
894#else
895 test_and_set_bit(FLG_TWO_DCHAN, &cs->HW_Flags);
896#endif
897 cs->protocol = card->protocol;
898
899 if (card->typ <= 0 || card->typ > ISDN_CTYPE_COUNT) {
900 printk(KERN_WARNING
901 "HiSax: Card Type %d out of range\n", card->typ);
902 goto outf_cs;
903 }
904 if (!(cs->dlog = kmalloc(MAX_DLOG_SPACE, GFP_ATOMIC))) {
905 printk(KERN_WARNING
906 "HiSax: No memory for dlog(card %d)\n", cardnr + 1);
907 goto outf_cs;
908 }
909 if (!(cs->status_buf = kmalloc(HISAX_STATUS_BUFSIZE, GFP_ATOMIC))) {
910 printk(KERN_WARNING
911 "HiSax: No memory for status_buf(card %d)\n",
912 cardnr + 1);
913 goto outf_dlog;
914 }
915 cs->stlist = NULL;
916 cs->status_read = cs->status_buf;
917 cs->status_write = cs->status_buf;
918 cs->status_end = cs->status_buf + HISAX_STATUS_BUFSIZE - 1;
919 cs->typ = card->typ;
920#ifdef MODULE
921 cs->iif.owner = lockowner;
922#endif
923 strcpy(cs->iif.id, id);
924 cs->iif.channels = 2;
925 cs->iif.maxbufsize = MAX_DATA_SIZE;
926 cs->iif.hl_hdrlen = MAX_HEADER_LEN;
927 cs->iif.features =
928 ISDN_FEATURE_L2_X75I |
929 ISDN_FEATURE_L2_HDLC |
930 ISDN_FEATURE_L2_HDLC_56K |
931 ISDN_FEATURE_L2_TRANS |
932 ISDN_FEATURE_L3_TRANS |
933#ifdef CONFIG_HISAX_1TR6
934 ISDN_FEATURE_P_1TR6 |
935#endif
936#ifdef CONFIG_HISAX_EURO
937 ISDN_FEATURE_P_EURO |
938#endif
939#ifdef CONFIG_HISAX_NI1
940 ISDN_FEATURE_P_NI1 |
941#endif
942 0;
943
944 cs->iif.command = HiSax_command;
945 cs->iif.writecmd = NULL;
946 cs->iif.writebuf_skb = HiSax_writebuf_skb;
947 cs->iif.readstat = HiSax_readstatus;
948 register_isdn(&cs->iif);
949 cs->myid = cs->iif.channels;
950 printk(KERN_INFO
951 "HiSax: Card %d Protocol %s Id=%s (%d)\n", cardnr + 1,
952 (card->protocol == ISDN_PTYPE_1TR6) ? "1TR6" :
953 (card->protocol == ISDN_PTYPE_EURO) ? "EDSS1" :
954 (card->protocol == ISDN_PTYPE_LEASED) ? "LEASED" :
955 (card->protocol == ISDN_PTYPE_NI1) ? "NI1" :
956 "NONE", cs->iif.id, cs->myid);
957 switch (card->typ) {
958#if CARD_TELES0
959 case ISDN_CTYPE_16_0:
960 case ISDN_CTYPE_8_0:
961 ret = setup_teles0(card);
962 break;
963#endif
964#if CARD_TELES3
965 case ISDN_CTYPE_16_3:
966 case ISDN_CTYPE_PNP:
967 case ISDN_CTYPE_TELESPCMCIA:
968 case ISDN_CTYPE_COMPAQ_ISA:
969 ret = setup_teles3(card);
970 break;
971#endif
972#if CARD_S0BOX
973 case ISDN_CTYPE_S0BOX:
974 ret = setup_s0box(card);
975 break;
976#endif
977#if CARD_TELESPCI
978 case ISDN_CTYPE_TELESPCI:
979 ret = setup_telespci(card);
980 break;
981#endif
982#if CARD_AVM_A1
983 case ISDN_CTYPE_A1:
984 ret = setup_avm_a1(card);
985 break;
986#endif
987#if CARD_AVM_A1_PCMCIA
988 case ISDN_CTYPE_A1_PCMCIA:
989 ret = setup_avm_a1_pcmcia(card);
990 break;
991#endif
992#if CARD_FRITZPCI
993 case ISDN_CTYPE_FRITZPCI:
994 ret = setup_avm_pcipnp(card);
995 break;
996#endif
997#if CARD_ELSA
998 case ISDN_CTYPE_ELSA:
999 case ISDN_CTYPE_ELSA_PNP:
1000 case ISDN_CTYPE_ELSA_PCMCIA:
1001 case ISDN_CTYPE_ELSA_PCI:
1002 ret = setup_elsa(card);
1003 break;
1004#endif
1005#if CARD_IX1MICROR2
1006 case ISDN_CTYPE_IX1MICROR2:
1007 ret = setup_ix1micro(card);
1008 break;
1009#endif
1010#if CARD_DIEHLDIVA
1011 case ISDN_CTYPE_DIEHLDIVA:
1012 ret = setup_diva(card);
1013 break;
1014#endif
1015#if CARD_ASUSCOM
1016 case ISDN_CTYPE_ASUSCOM:
1017 ret = setup_asuscom(card);
1018 break;
1019#endif
1020#if CARD_TELEINT
1021 case ISDN_CTYPE_TELEINT:
1022 ret = setup_TeleInt(card);
1023 break;
1024#endif
1025#if CARD_SEDLBAUER
1026 case ISDN_CTYPE_SEDLBAUER:
1027 case ISDN_CTYPE_SEDLBAUER_PCMCIA:
1028 case ISDN_CTYPE_SEDLBAUER_FAX:
1029 ret = setup_sedlbauer(card);
1030 break;
1031#endif
1032#if CARD_SPORTSTER
1033 case ISDN_CTYPE_SPORTSTER:
1034 ret = setup_sportster(card);
1035 break;
1036#endif
1037#if CARD_MIC
1038 case ISDN_CTYPE_MIC:
1039 ret = setup_mic(card);
1040 break;
1041#endif
1042#if CARD_NETJET_S
1043 case ISDN_CTYPE_NETJET_S:
1044 ret = setup_netjet_s(card);
1045 break;
1046#endif
1047#if CARD_HFCS
1048 case ISDN_CTYPE_TELES3C:
1049 case ISDN_CTYPE_ACERP10:
1050 ret = setup_hfcs(card);
1051 break;
1052#endif
1053#if CARD_HFC_PCI
1054 case ISDN_CTYPE_HFC_PCI:
1055 ret = setup_hfcpci(card);
1056 break;
1057#endif
1058#if CARD_HFC_SX
1059 case ISDN_CTYPE_HFC_SX:
1060 ret = setup_hfcsx(card);
1061 break;
1062#endif
1063#if CARD_NICCY
1064 case ISDN_CTYPE_NICCY:
1065 ret = setup_niccy(card);
1066 break;
1067#endif
1068#if CARD_AMD7930
1069 case ISDN_CTYPE_AMD7930:
1070 ret = setup_amd7930(card);
1071 break;
1072#endif
1073#if CARD_ISURF
1074 case ISDN_CTYPE_ISURF:
1075 ret = setup_isurf(card);
1076 break;
1077#endif
1078#if CARD_HSTSAPHIR
1079 case ISDN_CTYPE_HSTSAPHIR:
1080 ret = setup_saphir(card);
1081 break;
1082#endif
1083#if CARD_TESTEMU
1084 case ISDN_CTYPE_TESTEMU:
1085 ret = setup_testemu(card);
1086 break;
1087#endif
1088#if CARD_BKM_A4T
1089 case ISDN_CTYPE_BKM_A4T:
1090 ret = setup_bkm_a4t(card);
1091 break;
1092#endif
1093#if CARD_SCT_QUADRO
1094 case ISDN_CTYPE_SCT_QUADRO:
1095 ret = setup_sct_quadro(card);
1096 break;
1097#endif
1098#if CARD_GAZEL
1099 case ISDN_CTYPE_GAZEL:
1100 ret = setup_gazel(card);
1101 break;
1102#endif
1103#if CARD_W6692
1104 case ISDN_CTYPE_W6692:
1105 ret = setup_w6692(card);
1106 break;
1107#endif
1108#if CARD_NETJET_U
1109 case ISDN_CTYPE_NETJET_U:
1110 ret = setup_netjet_u(card);
1111 break;
1112#endif
1113#if CARD_FN_ENTERNOW_PCI
1114 case ISDN_CTYPE_ENTERNOW:
1115 ret = setup_enternow_pci(card);
1116 break;
1117#endif
1118 case ISDN_CTYPE_DYNAMIC:
1119 ret = 2;
1120 break;
1121 default:
1122 printk(KERN_WARNING
1123 "HiSax: Support for %s Card not selected\n",
1124 CardType[card->typ]);
1125 ll_unload(cs);
1126 goto outf_cs;
1127 }
1128 if (!ret) {
1129 ll_unload(cs);
1130 goto outf_cs;
1131 }
1132 if (!(cs->rcvbuf = kmalloc(MAX_DFRAME_LEN_L1, GFP_ATOMIC))) {
1133 printk(KERN_WARNING "HiSax: No memory for isac rcvbuf\n");
1134 ll_unload(cs);
1135 goto outf_cs;
1136 }
1137 cs->rcvidx = 0;
1138 cs->tx_skb = NULL;
1139 cs->tx_cnt = 0;
1140 cs->event = 0;
1141 cs->tqueue.data = cs;
1142
1143 skb_queue_head_init(&cs->rq);
1144 skb_queue_head_init(&cs->sq);
1145
1146 init_bcstate(cs, 0);
1147 init_bcstate(cs, 1);
1148
1149 /* init_card only handles interrupts which are not */
1150 /* used here for the loadable driver */
1151 switch (card->typ) {
1152 case ISDN_CTYPE_DYNAMIC:
1153 ret = 0;
1154 break;
1155 default:
1156 ret = init_card(cs);
1157 break;
1158 }
1159 if (ret) {
1160 closecard(cardnr);
1161 ret = 0;
1162 goto outf_cs;
1163 }
1164 init_tei(cs, cs->protocol);
1165 ret = CallcNewChan(cs);
1166 if (ret) {
1167 closecard(cardnr);
1168 ret = 0;
1169 goto outf_cs;
1170 }
1171 /* ISAR needs firmware download first */
1172 if (!test_bit(HW_ISAR, &cs->HW_Flags))
1173 ll_run(cs, 0);
1174
1175 ret = 1;
1176 goto out;
1177
1178 outf_dlog:
1179 kfree(cs->dlog);
1180 outf_cs:
1181 kfree(cs);
1182 card->cs = NULL;
1183 out:
1184 return ret;
1185}
1186
1187void HiSax_shiftcards(int idx)
1188{
1189 int i;
1190
1191 for (i = idx; i < (HISAX_MAX_CARDS - 1); i++)
1192 memcpy(&cards[i], &cards[i + 1], sizeof(cards[i]));
1193}
1194
1195int HiSax_inithardware(int *busy_flag)
1196{
1197 int foundcards = 0;
1198 int i = 0;
1199 int t = ',';
1200 int flg = 0;
1201 char *id;
1202 char *next_id = HiSax_id;
1203 char ids[20];
1204
1205 if (strchr(HiSax_id, ','))
1206 t = ',';
1207 else if (strchr(HiSax_id, '%'))
1208 t = '%';
1209
1210 while (i < nrcards) {
1211 if (cards[i].typ < 1)
1212 break;
1213 id = next_id;
1214 if ((next_id = strchr(id, t))) {
1215 *next_id++ = 0;
1216 strcpy(ids, id);
1217 flg = i + 1;
1218 } else {
1219 next_id = id;
1220 if (flg >= i)
1221 strcpy(ids, id);
1222 else
1223 sprintf(ids, "%s%d", id, i);
1224 }
1225 if (checkcard(i, ids, busy_flag, THIS_MODULE)) {
1226 foundcards++;
1227 i++;
1228 } else {
1229 /* make sure we don't oops the module */
1230 if (cards[i].typ > 0 && cards[i].typ <= ISDN_CTYPE_COUNT) {
1231 printk(KERN_WARNING
1232 "HiSax: Card %s not installed !\n",
1233 CardType[cards[i].typ]);
1234 }
1235 HiSax_shiftcards(i);
1236 nrcards--;
1237 }
1238 }
1239 return foundcards;
1240}
1241
1242void HiSax_closecard(int cardnr)
1243{
1244 int i, last = nrcards - 1;
1245
1246 if (cardnr > last || cardnr < 0)
1247 return;
1248 if (cards[cardnr].cs) {
1249 ll_stop(cards[cardnr].cs);
1250 release_tei(cards[cardnr].cs);
1251 CallcFreeChan(cards[cardnr].cs);
1252
1253 closecard(cardnr);
1254 if (cards[cardnr].cs->irq)
1255 free_irq(cards[cardnr].cs->irq, cards[cardnr].cs);
1256 kfree((void *) cards[cardnr].cs);
1257 cards[cardnr].cs = NULL;
1258 }
1259 i = cardnr;
1260 while (i <= last) {
1261 cards[i] = cards[i + 1];
1262 i++;
1263 }
1264 nrcards--;
1265}
1266
1267void HiSax_reportcard(int cardnr, int sel)
1268{
1269 struct IsdnCardState *cs = cards[cardnr].cs;
1270
1271 printk(KERN_DEBUG "HiSax: reportcard No %d\n", cardnr + 1);
1272 printk(KERN_DEBUG "HiSax: Type %s\n", CardType[cs->typ]);
1273 printk(KERN_DEBUG "HiSax: debuglevel %x\n", cs->debug);
1274 printk(KERN_DEBUG "HiSax: HiSax_reportcard address 0x%lX\n",
1275 (ulong) & HiSax_reportcard);
1276 printk(KERN_DEBUG "HiSax: cs 0x%lX\n", (ulong) cs);
1277 printk(KERN_DEBUG "HiSax: HW_Flags %lx bc0 flg %lx bc1 flg %lx\n",
1278 cs->HW_Flags, cs->bcs[0].Flag, cs->bcs[1].Flag);
1279 printk(KERN_DEBUG "HiSax: bcs 0 mode %d ch%d\n",
1280 cs->bcs[0].mode, cs->bcs[0].channel);
1281 printk(KERN_DEBUG "HiSax: bcs 1 mode %d ch%d\n",
1282 cs->bcs[1].mode, cs->bcs[1].channel);
1283#ifdef ERROR_STATISTIC
1284 printk(KERN_DEBUG "HiSax: dc errors(rx,crc,tx) %d,%d,%d\n",
1285 cs->err_rx, cs->err_crc, cs->err_tx);
1286 printk(KERN_DEBUG
1287 "HiSax: bc0 errors(inv,rdo,crc,tx) %d,%d,%d,%d\n",
1288 cs->bcs[0].err_inv, cs->bcs[0].err_rdo, cs->bcs[0].err_crc,
1289 cs->bcs[0].err_tx);
1290 printk(KERN_DEBUG
1291 "HiSax: bc1 errors(inv,rdo,crc,tx) %d,%d,%d,%d\n",
1292 cs->bcs[1].err_inv, cs->bcs[1].err_rdo, cs->bcs[1].err_crc,
1293 cs->bcs[1].err_tx);
1294 if (sel == 99) {
1295 cs->err_rx = 0;
1296 cs->err_crc = 0;
1297 cs->err_tx = 0;
1298 cs->bcs[0].err_inv = 0;
1299 cs->bcs[0].err_rdo = 0;
1300 cs->bcs[0].err_crc = 0;
1301 cs->bcs[0].err_tx = 0;
1302 cs->bcs[1].err_inv = 0;
1303 cs->bcs[1].err_rdo = 0;
1304 cs->bcs[1].err_crc = 0;
1305 cs->bcs[1].err_tx = 0;
1306 }
1307#endif
1308}
1309
1310static int __init HiSax_init(void)
1311{
1312 int i, retval;
1313#ifdef MODULE
1314 int j;
1315 int nzproto = 0;
1316#endif
1317
1318 HiSaxVersion();
1319 retval = CallcNew();
1320 if (retval)
1321 goto out;
1322 retval = Isdnl3New();
1323 if (retval)
1324 goto out_callc;
1325 retval = Isdnl2New();
1326 if (retval)
1327 goto out_isdnl3;
1328 retval = TeiNew();
1329 if (retval)
1330 goto out_isdnl2;
1331 retval = Isdnl1New();
1332 if (retval)
1333 goto out_tei;
1334
1335#ifdef MODULE
1336 if (!type[0]) {
1337 /* We 'll register drivers later, but init basic functions */
1338 for (i = 0; i < HISAX_MAX_CARDS; i++)
1339 cards[i].typ = 0;
1340 return 0;
1341 }
1342#ifdef CONFIG_HISAX_ELSA
1343 if (type[0] == ISDN_CTYPE_ELSA_PCMCIA) {
1344 /* we have exported and return in this case */
1345 return 0;
1346 }
1347#endif
1348#ifdef CONFIG_HISAX_SEDLBAUER
1349 if (type[0] == ISDN_CTYPE_SEDLBAUER_PCMCIA) {
1350 /* we have to export and return in this case */
1351 return 0;
1352 }
1353#endif
1354#ifdef CONFIG_HISAX_AVM_A1_PCMCIA
1355 if (type[0] == ISDN_CTYPE_A1_PCMCIA) {
1356 /* we have to export and return in this case */
1357 return 0;
1358 }
1359#endif
1360#ifdef CONFIG_HISAX_HFC_SX
1361 if (type[0] == ISDN_CTYPE_HFC_SP_PCMCIA) {
1362 /* we have to export and return in this case */
1363 return 0;
1364 }
1365#endif
1366#endif
1367 nrcards = 0;
1368#ifdef MODULE
1369 if (id) /* If id= string used */
1370 HiSax_id = id;
1371 for (i = j = 0; j < HISAX_MAX_CARDS; i++) {
1372 cards[j].typ = type[i];
1373 if (protocol[i]) {
1374 cards[j].protocol = protocol[i];
1375 nzproto++;
1376 } else {
1377 cards[j].protocol = DEFAULT_PROTO;
1378 }
1379 switch (type[i]) {
1380 case ISDN_CTYPE_16_0:
1381 cards[j].para[0] = irq[i];
1382 cards[j].para[1] = mem[i];
1383 cards[j].para[2] = io[i];
1384 break;
1385
1386 case ISDN_CTYPE_8_0:
1387 cards[j].para[0] = irq[i];
1388 cards[j].para[1] = mem[i];
1389 break;
1390
1391#ifdef IO0_IO1
1392 case ISDN_CTYPE_PNP:
1393 case ISDN_CTYPE_NICCY:
1394 cards[j].para[0] = irq[i];
1395 cards[j].para[1] = io0[i];
1396 cards[j].para[2] = io1[i];
1397 break;
1398 case ISDN_CTYPE_COMPAQ_ISA:
1399 cards[j].para[0] = irq[i];
1400 cards[j].para[1] = io0[i];
1401 cards[j].para[2] = io1[i];
1402 cards[j].para[3] = io[i];
1403 break;
1404#endif
1405 case ISDN_CTYPE_ELSA:
1406 case ISDN_CTYPE_HFC_PCI:
1407 cards[j].para[0] = io[i];
1408 break;
1409 case ISDN_CTYPE_16_3:
1410 case ISDN_CTYPE_TELESPCMCIA:
1411 case ISDN_CTYPE_A1:
1412 case ISDN_CTYPE_A1_PCMCIA:
1413 case ISDN_CTYPE_ELSA_PNP:
1414 case ISDN_CTYPE_ELSA_PCMCIA:
1415 case ISDN_CTYPE_IX1MICROR2:
1416 case ISDN_CTYPE_DIEHLDIVA:
1417 case ISDN_CTYPE_ASUSCOM:
1418 case ISDN_CTYPE_TELEINT:
1419 case ISDN_CTYPE_SEDLBAUER:
1420 case ISDN_CTYPE_SEDLBAUER_PCMCIA:
1421 case ISDN_CTYPE_SEDLBAUER_FAX:
1422 case ISDN_CTYPE_SPORTSTER:
1423 case ISDN_CTYPE_MIC:
1424 case ISDN_CTYPE_TELES3C:
1425 case ISDN_CTYPE_ACERP10:
1426 case ISDN_CTYPE_S0BOX:
1427 case ISDN_CTYPE_FRITZPCI:
1428 case ISDN_CTYPE_HSTSAPHIR:
1429 case ISDN_CTYPE_GAZEL:
1430 case ISDN_CTYPE_HFC_SX:
1431 case ISDN_CTYPE_HFC_SP_PCMCIA:
1432 cards[j].para[0] = irq[i];
1433 cards[j].para[1] = io[i];
1434 break;
1435 case ISDN_CTYPE_ISURF:
1436 cards[j].para[0] = irq[i];
1437 cards[j].para[1] = io[i];
1438 cards[j].para[2] = mem[i];
1439 break;
1440 case ISDN_CTYPE_ELSA_PCI:
1441 case ISDN_CTYPE_NETJET_S:
1442 case ISDN_CTYPE_AMD7930:
1443 case ISDN_CTYPE_TELESPCI:
1444 case ISDN_CTYPE_W6692:
1445 case ISDN_CTYPE_NETJET_U:
1446 break;
1447 case ISDN_CTYPE_BKM_A4T:
1448 break;
1449 case ISDN_CTYPE_SCT_QUADRO:
1450 if (irq[i]) {
1451 cards[j].para[0] = irq[i];
1452 } else {
1453 /* QUADRO is a 4 BRI card */
1454 cards[j++].para[0] = 1;
1455 /* we need to check if further cards can be added */
1456 if (j < HISAX_MAX_CARDS) {
1457 cards[j].typ = ISDN_CTYPE_SCT_QUADRO;
1458 cards[j].protocol = protocol[i];
1459 cards[j++].para[0] = 2;
1460 }
1461 if (j < HISAX_MAX_CARDS) {
1462 cards[j].typ = ISDN_CTYPE_SCT_QUADRO;
1463 cards[j].protocol = protocol[i];
1464 cards[j++].para[0] = 3;
1465 }
1466 if (j < HISAX_MAX_CARDS) {
1467 cards[j].typ = ISDN_CTYPE_SCT_QUADRO;
1468 cards[j].protocol = protocol[i];
1469 cards[j].para[0] = 4;
1470 }
1471 }
1472 break;
1473 }
1474 j++;
1475 }
1476 if (!nzproto) {
1477 printk(KERN_WARNING
1478 "HiSax: Warning - no protocol specified\n");
1479 printk(KERN_WARNING "HiSax: using protocol %s\n",
1480 DEFAULT_PROTO_NAME);
1481 }
1482#endif
1483 if (!HiSax_id)
1484 HiSax_id = HiSaxID;
1485 if (!HiSaxID[0])
1486 strcpy(HiSaxID, "HiSax");
1487 for (i = 0; i < HISAX_MAX_CARDS; i++)
1488 if (cards[i].typ > 0)
1489 nrcards++;
1490 printk(KERN_DEBUG "HiSax: Total %d card%s defined\n",
1491 nrcards, (nrcards > 1) ? "s" : "");
1492
1493 /* Install only, if at least one card found */
1494 if (!HiSax_inithardware(NULL))
1495 return -ENODEV;
1496 return 0;
1497
1498 out_tei:
1499 TeiFree();
1500 out_isdnl2:
1501 Isdnl2Free();
1502 out_isdnl3:
1503 Isdnl3Free();
1504 out_callc:
1505 CallcFree();
1506 out:
1507 return retval;
1508}
1509
1510static void __exit HiSax_exit(void)
1511{
1512 int cardnr = nrcards - 1;
1513
1514 while (cardnr >= 0)
1515 HiSax_closecard(cardnr--);
1516 Isdnl1Free();
1517 TeiFree();
1518 Isdnl2Free();
1519 Isdnl3Free();
1520 CallcFree();
1521 printk(KERN_INFO "HiSax module removed\n");
1522}
1523
1524int hisax_init_pcmcia(void *pcm_iob, int *busy_flag, struct IsdnCard *card)
1525{
1526 u_char ids[16];
1527 int ret = -1;
1528
1529 cards[nrcards] = *card;
1530 if (nrcards)
1531 sprintf(ids, "HiSax%d", nrcards);
1532 else
1533 sprintf(ids, "HiSax");
1534 if (!checkcard(nrcards, ids, busy_flag, THIS_MODULE))
1535 goto error;
1536
1537 ret = nrcards;
1538 nrcards++;
1539error:
1540 return ret;
1541}
1542
1543EXPORT_SYMBOL(hisax_init_pcmcia);
1544EXPORT_SYMBOL(HiSax_closecard);
1545
1546#include "hisax_if.h"
1547
1548EXPORT_SYMBOL(hisax_register);
1549EXPORT_SYMBOL(hisax_unregister);
1550
1551static void hisax_d_l1l2(struct hisax_if *ifc, int pr, void *arg);
1552static void hisax_b_l1l2(struct hisax_if *ifc, int pr, void *arg);
1553static void hisax_d_l2l1(struct PStack *st, int pr, void *arg);
1554static void hisax_b_l2l1(struct PStack *st, int pr, void *arg);
1555static int hisax_cardmsg(struct IsdnCardState *cs, int mt, void *arg);
1556static int hisax_bc_setstack(struct PStack *st, struct BCState *bcs);
1557static void hisax_bc_close(struct BCState *bcs);
1558static void hisax_bh(struct IsdnCardState *cs);
1559static void EChannel_proc_rcv(struct hisax_d_if *d_if);
1560
1561int hisax_register(struct hisax_d_if *hisax_d_if, struct hisax_b_if *b_if[],
1562 char *name, int protocol)
1563{
1564 int i, retval;
1565 char id[20];
1566 struct IsdnCardState *cs;
1567
1568 for (i = 0; i < HISAX_MAX_CARDS; i++) {
1569 if (!cards[i].typ)
1570 break;
1571 }
1572
1573 if (i >= HISAX_MAX_CARDS)
1574 return -EBUSY;
1575
1576 cards[i].typ = ISDN_CTYPE_DYNAMIC;
1577 cards[i].protocol = protocol;
1578 sprintf(id, "%s%d", name, i);
1579 nrcards++;
1580 retval = checkcard(i, id, NULL, hisax_d_if->owner);
1581 if (retval == 0) { // yuck
1582 cards[i].typ = 0;
1583 nrcards--;
1584 return retval;
1585 }
1586 cs = cards[i].cs;
1587 hisax_d_if->cs = cs;
1588 cs->hw.hisax_d_if = hisax_d_if;
1589 cs->cardmsg = hisax_cardmsg;
1590 INIT_WORK(&cs->tqueue, (void *)(void *)hisax_bh, cs);
1591 cs->channel[0].d_st->l2.l2l1 = hisax_d_l2l1;
1592 for (i = 0; i < 2; i++) {
1593 cs->bcs[i].BC_SetStack = hisax_bc_setstack;
1594 cs->bcs[i].BC_Close = hisax_bc_close;
1595
1596 b_if[i]->ifc.l1l2 = hisax_b_l1l2;
1597
1598 hisax_d_if->b_if[i] = b_if[i];
1599 }
1600 hisax_d_if->ifc.l1l2 = hisax_d_l1l2;
1601 skb_queue_head_init(&hisax_d_if->erq);
1602 clear_bit(0, &hisax_d_if->ph_state);
1603
1604 return 0;
1605}
1606
1607void hisax_unregister(struct hisax_d_if *hisax_d_if)
1608{
1609 cards[hisax_d_if->cs->cardnr].typ = 0;
1610 HiSax_closecard(hisax_d_if->cs->cardnr);
1611 skb_queue_purge(&hisax_d_if->erq);
1612}
1613
1614#include "isdnl1.h"
1615
1616static void hisax_sched_event(struct IsdnCardState *cs, int event)
1617{
1618 test_and_set_bit(event, &cs->event);
1619 schedule_work(&cs->tqueue);
1620}
1621
1622static void hisax_bh(struct IsdnCardState *cs)
1623{
1624 struct PStack *st;
1625 int pr;
1626
1627 if (test_and_clear_bit(D_RCVBUFREADY, &cs->event))
1628 DChannel_proc_rcv(cs);
1629 if (test_and_clear_bit(E_RCVBUFREADY, &cs->event))
1630 EChannel_proc_rcv(cs->hw.hisax_d_if);
1631 if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) {
1632 if (test_bit(0, &cs->hw.hisax_d_if->ph_state))
1633 pr = PH_ACTIVATE | INDICATION;
1634 else
1635 pr = PH_DEACTIVATE | INDICATION;
1636 for (st = cs->stlist; st; st = st->next)
1637 st->l1.l1l2(st, pr, NULL);
1638
1639 }
1640}
1641
1642static void hisax_b_sched_event(struct BCState *bcs, int event)
1643{
1644 test_and_set_bit(event, &bcs->event);
1645 schedule_work(&bcs->tqueue);
1646}
1647
1648static inline void D_L2L1(struct hisax_d_if *d_if, int pr, void *arg)
1649{
1650 struct hisax_if *ifc = (struct hisax_if *) d_if;
1651 ifc->l2l1(ifc, pr, arg);
1652}
1653
1654static inline void B_L2L1(struct hisax_b_if *b_if, int pr, void *arg)
1655{
1656 struct hisax_if *ifc = (struct hisax_if *) b_if;
1657 ifc->l2l1(ifc, pr, arg);
1658}
1659
1660static void hisax_d_l1l2(struct hisax_if *ifc, int pr, void *arg)
1661{
1662 struct hisax_d_if *d_if = (struct hisax_d_if *) ifc;
1663 struct IsdnCardState *cs = d_if->cs;
1664 struct PStack *st;
1665 struct sk_buff *skb;
1666
1667 switch (pr) {
1668 case PH_ACTIVATE | INDICATION:
1669 set_bit(0, &d_if->ph_state);
1670 hisax_sched_event(cs, D_L1STATECHANGE);
1671 break;
1672 case PH_DEACTIVATE | INDICATION:
1673 clear_bit(0, &d_if->ph_state);
1674 hisax_sched_event(cs, D_L1STATECHANGE);
1675 break;
1676 case PH_DATA | INDICATION:
1677 skb_queue_tail(&cs->rq, arg);
1678 hisax_sched_event(cs, D_RCVBUFREADY);
1679 break;
1680 case PH_DATA | CONFIRM:
1681 skb = skb_dequeue(&cs->sq);
1682 if (skb) {
1683 D_L2L1(d_if, PH_DATA | REQUEST, skb);
1684 break;
1685 }
1686 clear_bit(FLG_L1_DBUSY, &cs->HW_Flags);
1687 for (st = cs->stlist; st; st = st->next) {
1688 if (test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags)) {
1689 st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
1690 break;
1691 }
1692 }
1693 break;
1694 case PH_DATA_E | INDICATION:
1695 skb_queue_tail(&d_if->erq, arg);
1696 hisax_sched_event(cs, E_RCVBUFREADY);
1697 break;
1698 default:
1699 printk("pr %#x\n", pr);
1700 break;
1701 }
1702}
1703
1704static void hisax_b_l1l2(struct hisax_if *ifc, int pr, void *arg)
1705{
1706 struct hisax_b_if *b_if = (struct hisax_b_if *) ifc;
1707 struct BCState *bcs = b_if->bcs;
1708 struct PStack *st = bcs->st;
1709 struct sk_buff *skb;
1710
1711 // FIXME use isdnl1?
1712 switch (pr) {
1713 case PH_ACTIVATE | INDICATION:
1714 st->l1.l1l2(st, pr, NULL);
1715 break;
1716 case PH_DEACTIVATE | INDICATION:
1717 st->l1.l1l2(st, pr, NULL);
1718 clear_bit(BC_FLG_BUSY, &bcs->Flag);
1719 skb_queue_purge(&bcs->squeue);
1720 bcs->hw.b_if = NULL;
1721 break;
1722 case PH_DATA | INDICATION:
1723 skb_queue_tail(&bcs->rqueue, arg);
1724 hisax_b_sched_event(bcs, B_RCVBUFREADY);
1725 break;
1726 case PH_DATA | CONFIRM:
1727 bcs->tx_cnt -= (int) arg;
1728 if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag)) {
1729 u_long flags;
1730 spin_lock_irqsave(&bcs->aclock, flags);
1731 bcs->ackcnt += (int) arg;
1732 spin_unlock_irqrestore(&bcs->aclock, flags);
1733 schedule_event(bcs, B_ACKPENDING);
1734 }
1735 skb = skb_dequeue(&bcs->squeue);
1736 if (skb) {
1737 B_L2L1(b_if, PH_DATA | REQUEST, skb);
1738 break;
1739 }
1740 clear_bit(BC_FLG_BUSY, &bcs->Flag);
1741 if (test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags)) {
1742 st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
1743 }
1744 break;
1745 default:
1746 printk("hisax_b_l1l2 pr %#x\n", pr);
1747 break;
1748 }
1749}
1750
1751static void hisax_d_l2l1(struct PStack *st, int pr, void *arg)
1752{
1753 struct IsdnCardState *cs = st->l1.hardware;
1754 struct hisax_d_if *hisax_d_if = cs->hw.hisax_d_if;
1755 struct sk_buff *skb = arg;
1756
1757 switch (pr) {
1758 case PH_DATA | REQUEST:
1759 case PH_PULL | INDICATION:
1760 if (cs->debug & DEB_DLOG_HEX)
1761 LogFrame(cs, skb->data, skb->len);
1762 if (cs->debug & DEB_DLOG_VERBOSE)
1763 dlogframe(cs, skb, 0);
1764 Logl2Frame(cs, skb, "PH_DATA_REQ", 0);
1765 // FIXME lock?
1766 if (!test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags))
1767 D_L2L1(hisax_d_if, PH_DATA | REQUEST, skb);
1768 else
1769 skb_queue_tail(&cs->sq, skb);
1770 break;
1771 case PH_PULL | REQUEST:
1772 if (!test_bit(FLG_L1_DBUSY, &cs->HW_Flags))
1773 st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
1774 else
1775 set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
1776 break;
1777 default:
1778 D_L2L1(hisax_d_if, pr, arg);
1779 break;
1780 }
1781}
1782
1783static int hisax_cardmsg(struct IsdnCardState *cs, int mt, void *arg)
1784{
1785 return 0;
1786}
1787
1788static void hisax_b_l2l1(struct PStack *st, int pr, void *arg)
1789{
1790 struct BCState *bcs = st->l1.bcs;
1791 struct hisax_b_if *b_if = bcs->hw.b_if;
1792
1793 switch (pr) {
1794 case PH_ACTIVATE | REQUEST:
1795 B_L2L1(b_if, pr, (void *) st->l1.mode);
1796 break;
1797 case PH_DATA | REQUEST:
1798 case PH_PULL | INDICATION:
1799 // FIXME lock?
1800 if (!test_and_set_bit(BC_FLG_BUSY, &bcs->Flag)) {
1801 B_L2L1(b_if, PH_DATA | REQUEST, arg);
1802 } else {
1803 skb_queue_tail(&bcs->squeue, arg);
1804 }
1805 break;
1806 case PH_PULL | REQUEST:
1807 if (!test_bit(BC_FLG_BUSY, &bcs->Flag))
1808 st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
1809 else
1810 set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
1811 break;
1812 case PH_DEACTIVATE | REQUEST:
1813 test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
1814 skb_queue_purge(&bcs->squeue);
1815 default:
1816 B_L2L1(b_if, pr, arg);
1817 break;
1818 }
1819}
1820
1821static int hisax_bc_setstack(struct PStack *st, struct BCState *bcs)
1822{
1823 struct IsdnCardState *cs = st->l1.hardware;
1824 struct hisax_d_if *hisax_d_if = cs->hw.hisax_d_if;
1825
1826 bcs->channel = st->l1.bc;
1827
1828 bcs->hw.b_if = hisax_d_if->b_if[st->l1.bc];
1829 hisax_d_if->b_if[st->l1.bc]->bcs = bcs;
1830
1831 st->l1.bcs = bcs;
1832 st->l2.l2l1 = hisax_b_l2l1;
1833 setstack_manager(st);
1834 bcs->st = st;
1835 setstack_l1_B(st);
1836 skb_queue_head_init(&bcs->rqueue);
1837 skb_queue_head_init(&bcs->squeue);
1838 return 0;
1839}
1840
1841static void hisax_bc_close(struct BCState *bcs)
1842{
1843 struct hisax_b_if *b_if = bcs->hw.b_if;
1844
1845 if (b_if)
1846 B_L2L1(b_if, PH_DEACTIVATE | REQUEST, NULL);
1847}
1848
1849static void EChannel_proc_rcv(struct hisax_d_if *d_if)
1850{
1851 struct IsdnCardState *cs = d_if->cs;
1852 u_char *ptr;
1853 struct sk_buff *skb;
1854
1855 while ((skb = skb_dequeue(&d_if->erq)) != NULL) {
1856 if (cs->debug & DEB_DLOG_HEX) {
1857 ptr = cs->dlog;
1858 if ((skb->len) < MAX_DLOG_SPACE / 3 - 10) {
1859 *ptr++ = 'E';
1860 *ptr++ = 'C';
1861 *ptr++ = 'H';
1862 *ptr++ = 'O';
1863 *ptr++ = ':';
1864 ptr += QuickHex(ptr, skb->data, skb->len);
1865 ptr--;
1866 *ptr++ = '\n';
1867 *ptr = 0;
1868 HiSax_putstatus(cs, NULL, cs->dlog);
1869 } else
1870 HiSax_putstatus(cs, "LogEcho: ",
1871 "warning Frame too big (%d)",
1872 skb->len);
1873 }
1874 dev_kfree_skb_any(skb);
1875 }
1876}
1877
1878#ifdef CONFIG_PCI
1879#include <linux/pci.h>
1880
1881static struct pci_device_id hisax_pci_tbl[] __initdata = {
1882#ifdef CONFIG_HISAX_FRITZPCI
1883 {PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_A1, PCI_ANY_ID, PCI_ANY_ID},
1884#endif
1885#ifdef CONFIG_HISAX_DIEHLDIVA
1886 {PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_DIVA20, PCI_ANY_ID, PCI_ANY_ID},
1887 {PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_DIVA20_U, PCI_ANY_ID, PCI_ANY_ID},
1888 {PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_DIVA201, PCI_ANY_ID, PCI_ANY_ID},
1889//#########################################################################################
1890 {PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_DIVA202, PCI_ANY_ID, PCI_ANY_ID},
1891//#########################################################################################
1892#endif
1893#ifdef CONFIG_HISAX_ELSA
1894 {PCI_VENDOR_ID_ELSA, PCI_DEVICE_ID_ELSA_MICROLINK, PCI_ANY_ID, PCI_ANY_ID},
1895 {PCI_VENDOR_ID_ELSA, PCI_DEVICE_ID_ELSA_QS3000, PCI_ANY_ID, PCI_ANY_ID},
1896#endif
1897#ifdef CONFIG_HISAX_GAZEL
1898 {PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_R685, PCI_ANY_ID, PCI_ANY_ID},
1899 {PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_R753, PCI_ANY_ID, PCI_ANY_ID},
1900 {PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_DJINN_ITOO, PCI_ANY_ID, PCI_ANY_ID},
1901#endif
1902#ifdef CONFIG_HISAX_QUADRO
1903 {PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_ANY_ID, PCI_ANY_ID},
1904#endif
1905#ifdef CONFIG_HISAX_NICCY
1906 {PCI_VENDOR_ID_SATSAGEM, PCI_DEVICE_ID_SATSAGEM_NICCY, PCI_ANY_ID,PCI_ANY_ID},
1907#endif
1908#ifdef CONFIG_HISAX_SEDLBAUER
1909 {PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_100, PCI_ANY_ID,PCI_ANY_ID},
1910#endif
1911#if defined(CONFIG_HISAX_NETJET) || defined(CONFIG_HISAX_NETJET_U)
1912 {PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_300, PCI_ANY_ID,PCI_ANY_ID},
1913#endif
1914#if defined(CONFIG_HISAX_TELESPCI) || defined(CONFIG_HISAX_SCT_QUADRO)
1915 {PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36120, PCI_ANY_ID,PCI_ANY_ID},
1916#endif
1917#ifdef CONFIG_HISAX_W6692
1918 {PCI_VENDOR_ID_DYNALINK, PCI_DEVICE_ID_DYNALINK_IS64PH, PCI_ANY_ID,PCI_ANY_ID},
1919 {PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND2_6692, PCI_ANY_ID,PCI_ANY_ID},
1920#endif
1921#ifdef CONFIG_HISAX_HFC_PCI
1922 {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_2BD0, PCI_ANY_ID, PCI_ANY_ID},
1923 {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B000, PCI_ANY_ID, PCI_ANY_ID},
1924 {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B006, PCI_ANY_ID, PCI_ANY_ID},
1925 {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B007, PCI_ANY_ID, PCI_ANY_ID},
1926 {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B008, PCI_ANY_ID, PCI_ANY_ID},
1927 {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B009, PCI_ANY_ID, PCI_ANY_ID},
1928 {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B00A, PCI_ANY_ID, PCI_ANY_ID},
1929 {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B00B, PCI_ANY_ID, PCI_ANY_ID},
1930 {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B00C, PCI_ANY_ID, PCI_ANY_ID},
1931 {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B100, PCI_ANY_ID, PCI_ANY_ID},
1932 {PCI_VENDOR_ID_ABOCOM, PCI_DEVICE_ID_ABOCOM_2BD1, PCI_ANY_ID, PCI_ANY_ID},
1933 {PCI_VENDOR_ID_ASUSTEK, PCI_DEVICE_ID_ASUSTEK_0675, PCI_ANY_ID, PCI_ANY_ID},
1934 {PCI_VENDOR_ID_BERKOM, PCI_DEVICE_ID_BERKOM_T_CONCEPT, PCI_ANY_ID, PCI_ANY_ID},
1935 {PCI_VENDOR_ID_BERKOM, PCI_DEVICE_ID_BERKOM_A1T, PCI_ANY_ID, PCI_ANY_ID},
1936 {PCI_VENDOR_ID_ANIGMA, PCI_DEVICE_ID_ANIGMA_MC145575, PCI_ANY_ID, PCI_ANY_ID},
1937 {PCI_VENDOR_ID_ZOLTRIX, PCI_DEVICE_ID_ZOLTRIX_2BD0, PCI_ANY_ID, PCI_ANY_ID},
1938 {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_E, PCI_ANY_ID, PCI_ANY_ID},
1939 {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_E, PCI_ANY_ID, PCI_ANY_ID},
1940 {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_A, PCI_ANY_ID, PCI_ANY_ID},
1941 {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_A, PCI_ANY_ID, PCI_ANY_ID},
1942#endif
1943 { } /* Terminating entry */
1944};
1945
1946MODULE_DEVICE_TABLE(pci, hisax_pci_tbl);
1947#endif /* CONFIG_PCI */
1948
1949module_init(HiSax_init);
1950module_exit(HiSax_exit);
1951
1952EXPORT_SYMBOL(FsmNew);
1953EXPORT_SYMBOL(FsmFree);
1954EXPORT_SYMBOL(FsmEvent);
1955EXPORT_SYMBOL(FsmChangeState);
1956EXPORT_SYMBOL(FsmInitTimer);
1957EXPORT_SYMBOL(FsmDelTimer);
1958EXPORT_SYMBOL(FsmRestartTimer);
diff --git a/drivers/isdn/hisax/diva.c b/drivers/isdn/hisax/diva.c
new file mode 100644
index 000000000000..394d481e093f
--- /dev/null
+++ b/drivers/isdn/hisax/diva.c
@@ -0,0 +1,1183 @@
1/* $Id: diva.c,v 1.33.2.6 2004/02/11 13:21:33 keil Exp $
2 *
3 * low level stuff for Eicon.Diehl Diva Family ISDN cards
4 *
5 * Author Karsten Keil
6 * Copyright by Karsten Keil <keil@isdn4linux.de>
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 * For changes and modifications please read
12 * Documentation/isdn/HiSax.cert
13 *
14 * Thanks to Eicon Technology for documents and information
15 *
16 */
17
18#include <linux/init.h>
19#include <linux/config.h>
20#include "hisax.h"
21#include "isac.h"
22#include "hscx.h"
23#include "ipac.h"
24#include "ipacx.h"
25#include "isdnl1.h"
26#include <linux/pci.h>
27#include <linux/isapnp.h>
28
29extern const char *CardType[];
30
31const char *Diva_revision = "$Revision: 1.33.2.6 $";
32
33#define byteout(addr,val) outb(val,addr)
34#define bytein(addr) inb(addr)
35
36#define DIVA_HSCX_DATA 0
37#define DIVA_HSCX_ADR 4
38#define DIVA_ISA_ISAC_DATA 2
39#define DIVA_ISA_ISAC_ADR 6
40#define DIVA_ISA_CTRL 7
41#define DIVA_IPAC_ADR 0
42#define DIVA_IPAC_DATA 1
43
44#define DIVA_PCI_ISAC_DATA 8
45#define DIVA_PCI_ISAC_ADR 0xc
46#define DIVA_PCI_CTRL 0x10
47
48/* SUB Types */
49#define DIVA_ISA 1
50#define DIVA_PCI 2
51#define DIVA_IPAC_ISA 3
52#define DIVA_IPAC_PCI 4
53#define DIVA_IPACX_PCI 5
54
55/* CTRL (Read) */
56#define DIVA_IRQ_STAT 0x01
57#define DIVA_EEPROM_SDA 0x02
58
59/* CTRL (Write) */
60#define DIVA_IRQ_REQ 0x01
61#define DIVA_RESET 0x08
62#define DIVA_EEPROM_CLK 0x40
63#define DIVA_PCI_LED_A 0x10
64#define DIVA_PCI_LED_B 0x20
65#define DIVA_ISA_LED_A 0x20
66#define DIVA_ISA_LED_B 0x40
67#define DIVA_IRQ_CLR 0x80
68
69/* Siemens PITA */
70#define PITA_MISC_REG 0x1c
71#ifdef __BIG_ENDIAN
72#define PITA_PARA_SOFTRESET 0x00000001
73#define PITA_SER_SOFTRESET 0x00000002
74#define PITA_PARA_MPX_MODE 0x00000004
75#define PITA_INT0_ENABLE 0x00000200
76#else
77#define PITA_PARA_SOFTRESET 0x01000000
78#define PITA_SER_SOFTRESET 0x02000000
79#define PITA_PARA_MPX_MODE 0x04000000
80#define PITA_INT0_ENABLE 0x00020000
81#endif
82#define PITA_INT0_STATUS 0x02
83
84static inline u_char
85readreg(unsigned int ale, unsigned int adr, u_char off)
86{
87 register u_char ret;
88
89 byteout(ale, off);
90 ret = bytein(adr);
91 return (ret);
92}
93
94static inline void
95readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
96{
97 byteout(ale, off);
98 insb(adr, data, size);
99}
100
101
102static inline void
103writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
104{
105 byteout(ale, off);
106 byteout(adr, data);
107}
108
109static inline void
110writefifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size)
111{
112 byteout(ale, off);
113 outsb(adr, data, size);
114}
115
116static inline u_char
117memreadreg(unsigned long adr, u_char off)
118{
119 return(*((unsigned char *)
120 (((unsigned int *)adr) + off)));
121}
122
123static inline void
124memwritereg(unsigned long adr, u_char off, u_char data)
125{
126 register u_char *p;
127
128 p = (unsigned char *)(((unsigned int *)adr) + off);
129 *p = data;
130}
131
132/* Interface functions */
133
134static u_char
135ReadISAC(struct IsdnCardState *cs, u_char offset)
136{
137 return(readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, offset));
138}
139
140static void
141WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
142{
143 writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, offset, value);
144}
145
146static void
147ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
148{
149 readfifo(cs->hw.diva.isac_adr, cs->hw.diva.isac, 0, data, size);
150}
151
152static void
153WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
154{
155 writefifo(cs->hw.diva.isac_adr, cs->hw.diva.isac, 0, data, size);
156}
157
158static u_char
159ReadISAC_IPAC(struct IsdnCardState *cs, u_char offset)
160{
161 return (readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, offset+0x80));
162}
163
164static void
165WriteISAC_IPAC(struct IsdnCardState *cs, u_char offset, u_char value)
166{
167 writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, offset|0x80, value);
168}
169
170static void
171ReadISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size)
172{
173 readfifo(cs->hw.diva.isac_adr, cs->hw.diva.isac, 0x80, data, size);
174}
175
176static void
177WriteISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size)
178{
179 writefifo(cs->hw.diva.isac_adr, cs->hw.diva.isac, 0x80, data, size);
180}
181
182static u_char
183ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
184{
185 return(readreg(cs->hw.diva.hscx_adr,
186 cs->hw.diva.hscx, offset + (hscx ? 0x40 : 0)));
187}
188
189static void
190WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
191{
192 writereg(cs->hw.diva.hscx_adr,
193 cs->hw.diva.hscx, offset + (hscx ? 0x40 : 0), value);
194}
195
196static u_char
197MemReadISAC_IPAC(struct IsdnCardState *cs, u_char offset)
198{
199 return (memreadreg(cs->hw.diva.cfg_reg, offset+0x80));
200}
201
202static void
203MemWriteISAC_IPAC(struct IsdnCardState *cs, u_char offset, u_char value)
204{
205 memwritereg(cs->hw.diva.cfg_reg, offset|0x80, value);
206}
207
208static void
209MemReadISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size)
210{
211 while(size--)
212 *data++ = memreadreg(cs->hw.diva.cfg_reg, 0x80);
213}
214
215static void
216MemWriteISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size)
217{
218 while(size--)
219 memwritereg(cs->hw.diva.cfg_reg, 0x80, *data++);
220}
221
222static u_char
223MemReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
224{
225 return(memreadreg(cs->hw.diva.cfg_reg, offset + (hscx ? 0x40 : 0)));
226}
227
228static void
229MemWriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
230{
231 memwritereg(cs->hw.diva.cfg_reg, offset + (hscx ? 0x40 : 0), value);
232}
233
234/* IO-Functions for IPACX type cards */
235static u_char
236MemReadISAC_IPACX(struct IsdnCardState *cs, u_char offset)
237{
238 return (memreadreg(cs->hw.diva.cfg_reg, offset));
239}
240
241static void
242MemWriteISAC_IPACX(struct IsdnCardState *cs, u_char offset, u_char value)
243{
244 memwritereg(cs->hw.diva.cfg_reg, offset, value);
245}
246
247static void
248MemReadISACfifo_IPACX(struct IsdnCardState *cs, u_char * data, int size)
249{
250 while(size--)
251 *data++ = memreadreg(cs->hw.diva.cfg_reg, 0);
252}
253
254static void
255MemWriteISACfifo_IPACX(struct IsdnCardState *cs, u_char * data, int size)
256{
257 while(size--)
258 memwritereg(cs->hw.diva.cfg_reg, 0, *data++);
259}
260
261static u_char
262MemReadHSCX_IPACX(struct IsdnCardState *cs, int hscx, u_char offset)
263{
264 return(memreadreg(cs->hw.diva.cfg_reg, offset +
265 (hscx ? IPACX_OFF_B2 : IPACX_OFF_B1)));
266}
267
268static void
269MemWriteHSCX_IPACX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
270{
271 memwritereg(cs->hw.diva.cfg_reg, offset +
272 (hscx ? IPACX_OFF_B2 : IPACX_OFF_B1), value);
273}
274
275/*
276 * fast interrupt HSCX stuff goes here
277 */
278
279#define READHSCX(cs, nr, reg) readreg(cs->hw.diva.hscx_adr, \
280 cs->hw.diva.hscx, reg + (nr ? 0x40 : 0))
281#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.diva.hscx_adr, \
282 cs->hw.diva.hscx, reg + (nr ? 0x40 : 0), data)
283
284#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.diva.hscx_adr, \
285 cs->hw.diva.hscx, (nr ? 0x40 : 0), ptr, cnt)
286
287#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.diva.hscx_adr, \
288 cs->hw.diva.hscx, (nr ? 0x40 : 0), ptr, cnt)
289
290#include "hscx_irq.c"
291
292static irqreturn_t
293diva_interrupt(int intno, void *dev_id, struct pt_regs *regs)
294{
295 struct IsdnCardState *cs = dev_id;
296 u_char val, sval;
297 u_long flags;
298 int cnt=5;
299
300 spin_lock_irqsave(&cs->lock, flags);
301 while (((sval = bytein(cs->hw.diva.ctrl)) & DIVA_IRQ_REQ) && cnt) {
302 val = readreg(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, HSCX_ISTA + 0x40);
303 if (val)
304 hscx_int_main(cs, val);
305 val = readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, ISAC_ISTA);
306 if (val)
307 isac_interrupt(cs, val);
308 cnt--;
309 }
310 if (!cnt)
311 printk(KERN_WARNING "Diva: IRQ LOOP\n");
312 writereg(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, HSCX_MASK, 0xFF);
313 writereg(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, HSCX_MASK + 0x40, 0xFF);
314 writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, ISAC_MASK, 0xFF);
315 writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, ISAC_MASK, 0x0);
316 writereg(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, HSCX_MASK, 0x0);
317 writereg(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, HSCX_MASK + 0x40, 0x0);
318 spin_unlock_irqrestore(&cs->lock, flags);
319 return IRQ_HANDLED;
320}
321
322static irqreturn_t
323diva_irq_ipac_isa(int intno, void *dev_id, struct pt_regs *regs)
324{
325 struct IsdnCardState *cs = dev_id;
326 u_char ista,val;
327 u_long flags;
328 int icnt=5;
329
330 spin_lock_irqsave(&cs->lock, flags);
331 ista = readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_ISTA);
332Start_IPACISA:
333 if (cs->debug & L1_DEB_IPAC)
334 debugl1(cs, "IPAC ISTA %02X", ista);
335 if (ista & 0x0f) {
336 val = readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, HSCX_ISTA + 0x40);
337 if (ista & 0x01)
338 val |= 0x01;
339 if (ista & 0x04)
340 val |= 0x02;
341 if (ista & 0x08)
342 val |= 0x04;
343 if (val)
344 hscx_int_main(cs, val);
345 }
346 if (ista & 0x20) {
347 val = 0xfe & readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, ISAC_ISTA + 0x80);
348 if (val) {
349 isac_interrupt(cs, val);
350 }
351 }
352 if (ista & 0x10) {
353 val = 0x01;
354 isac_interrupt(cs, val);
355 }
356 ista = readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_ISTA);
357 if ((ista & 0x3f) && icnt) {
358 icnt--;
359 goto Start_IPACISA;
360 }
361 if (!icnt)
362 printk(KERN_WARNING "DIVA IPAC IRQ LOOP\n");
363 writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_MASK, 0xFF);
364 writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_MASK, 0xC0);
365 spin_unlock_irqrestore(&cs->lock, flags);
366 return IRQ_HANDLED;
367}
368
369static inline void
370MemwaitforCEC(struct IsdnCardState *cs, int hscx)
371{
372 int to = 50;
373
374 while ((MemReadHSCX(cs, hscx, HSCX_STAR) & 0x04) && to) {
375 udelay(1);
376 to--;
377 }
378 if (!to)
379 printk(KERN_WARNING "HiSax: waitforCEC timeout\n");
380}
381
382
383static inline void
384MemwaitforXFW(struct IsdnCardState *cs, int hscx)
385{
386 int to = 50;
387
388 while ((!(MemReadHSCX(cs, hscx, HSCX_STAR) & 0x44) == 0x40) && to) {
389 udelay(1);
390 to--;
391 }
392 if (!to)
393 printk(KERN_WARNING "HiSax: waitforXFW timeout\n");
394}
395
396static inline void
397MemWriteHSCXCMDR(struct IsdnCardState *cs, int hscx, u_char data)
398{
399 MemwaitforCEC(cs, hscx);
400 MemWriteHSCX(cs, hscx, HSCX_CMDR, data);
401}
402
403static void
404Memhscx_empty_fifo(struct BCState *bcs, int count)
405{
406 u_char *ptr;
407 struct IsdnCardState *cs = bcs->cs;
408 int cnt;
409
410 if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
411 debugl1(cs, "hscx_empty_fifo");
412
413 if (bcs->hw.hscx.rcvidx + count > HSCX_BUFMAX) {
414 if (cs->debug & L1_DEB_WARN)
415 debugl1(cs, "hscx_empty_fifo: incoming packet too large");
416 MemWriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x80);
417 bcs->hw.hscx.rcvidx = 0;
418 return;
419 }
420 ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx;
421 cnt = count;
422 while (cnt--)
423 *ptr++ = memreadreg(cs->hw.diva.cfg_reg, bcs->hw.hscx.hscx ? 0x40 : 0);
424 MemWriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x80);
425 ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx;
426 bcs->hw.hscx.rcvidx += count;
427 if (cs->debug & L1_DEB_HSCX_FIFO) {
428 char *t = bcs->blog;
429
430 t += sprintf(t, "hscx_empty_fifo %c cnt %d",
431 bcs->hw.hscx.hscx ? 'B' : 'A', count);
432 QuickHex(t, ptr, count);
433 debugl1(cs, bcs->blog);
434 }
435}
436
437static void
438Memhscx_fill_fifo(struct BCState *bcs)
439{
440 struct IsdnCardState *cs = bcs->cs;
441 int more, count, cnt;
442 int fifo_size = test_bit(HW_IPAC, &cs->HW_Flags)? 64: 32;
443 u_char *ptr,*p;
444
445 if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
446 debugl1(cs, "hscx_fill_fifo");
447
448 if (!bcs->tx_skb)
449 return;
450 if (bcs->tx_skb->len <= 0)
451 return;
452
453 more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0;
454 if (bcs->tx_skb->len > fifo_size) {
455 more = !0;
456 count = fifo_size;
457 } else
458 count = bcs->tx_skb->len;
459 cnt = count;
460 MemwaitforXFW(cs, bcs->hw.hscx.hscx);
461 p = ptr = bcs->tx_skb->data;
462 skb_pull(bcs->tx_skb, count);
463 bcs->tx_cnt -= count;
464 bcs->hw.hscx.count += count;
465 while(cnt--)
466 memwritereg(cs->hw.diva.cfg_reg, bcs->hw.hscx.hscx ? 0x40 : 0,
467 *p++);
468 MemWriteHSCXCMDR(cs, bcs->hw.hscx.hscx, more ? 0x8 : 0xa);
469 if (cs->debug & L1_DEB_HSCX_FIFO) {
470 char *t = bcs->blog;
471
472 t += sprintf(t, "hscx_fill_fifo %c cnt %d",
473 bcs->hw.hscx.hscx ? 'B' : 'A', count);
474 QuickHex(t, ptr, count);
475 debugl1(cs, bcs->blog);
476 }
477}
478
479static inline void
480Memhscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx)
481{
482 u_char r;
483 struct BCState *bcs = cs->bcs + hscx;
484 struct sk_buff *skb;
485 int fifo_size = test_bit(HW_IPAC, &cs->HW_Flags)? 64: 32;
486 int count;
487
488 if (!test_bit(BC_FLG_INIT, &bcs->Flag))
489 return;
490
491 if (val & 0x80) { /* RME */
492 r = MemReadHSCX(cs, hscx, HSCX_RSTA);
493 if ((r & 0xf0) != 0xa0) {
494 if (!(r & 0x80))
495 if (cs->debug & L1_DEB_WARN)
496 debugl1(cs, "HSCX invalid frame");
497 if ((r & 0x40) && bcs->mode)
498 if (cs->debug & L1_DEB_WARN)
499 debugl1(cs, "HSCX RDO mode=%d",
500 bcs->mode);
501 if (!(r & 0x20))
502 if (cs->debug & L1_DEB_WARN)
503 debugl1(cs, "HSCX CRC error");
504 MemWriteHSCXCMDR(cs, hscx, 0x80);
505 } else {
506 count = MemReadHSCX(cs, hscx, HSCX_RBCL) & (
507 test_bit(HW_IPAC, &cs->HW_Flags)? 0x3f: 0x1f);
508 if (count == 0)
509 count = fifo_size;
510 Memhscx_empty_fifo(bcs, count);
511 if ((count = bcs->hw.hscx.rcvidx - 1) > 0) {
512 if (cs->debug & L1_DEB_HSCX_FIFO)
513 debugl1(cs, "HX Frame %d", count);
514 if (!(skb = dev_alloc_skb(count)))
515 printk(KERN_WARNING "HSCX: receive out of memory\n");
516 else {
517 memcpy(skb_put(skb, count), bcs->hw.hscx.rcvbuf, count);
518 skb_queue_tail(&bcs->rqueue, skb);
519 }
520 }
521 }
522 bcs->hw.hscx.rcvidx = 0;
523 schedule_event(bcs, B_RCVBUFREADY);
524 }
525 if (val & 0x40) { /* RPF */
526 Memhscx_empty_fifo(bcs, fifo_size);
527 if (bcs->mode == L1_MODE_TRANS) {
528 /* receive audio data */
529 if (!(skb = dev_alloc_skb(fifo_size)))
530 printk(KERN_WARNING "HiSax: receive out of memory\n");
531 else {
532 memcpy(skb_put(skb, fifo_size), bcs->hw.hscx.rcvbuf, fifo_size);
533 skb_queue_tail(&bcs->rqueue, skb);
534 }
535 bcs->hw.hscx.rcvidx = 0;
536 schedule_event(bcs, B_RCVBUFREADY);
537 }
538 }
539 if (val & 0x10) { /* XPR */
540 if (bcs->tx_skb) {
541 if (bcs->tx_skb->len) {
542 Memhscx_fill_fifo(bcs);
543 return;
544 } else {
545 if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) &&
546 (PACKET_NOACK != bcs->tx_skb->pkt_type)) {
547 u_long flags;
548 spin_lock_irqsave(&bcs->aclock, flags);
549 bcs->ackcnt += bcs->hw.hscx.count;
550 spin_unlock_irqrestore(&bcs->aclock, flags);
551 schedule_event(bcs, B_ACKPENDING);
552 }
553 dev_kfree_skb_irq(bcs->tx_skb);
554 bcs->hw.hscx.count = 0;
555 bcs->tx_skb = NULL;
556 }
557 }
558 if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
559 bcs->hw.hscx.count = 0;
560 test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
561 Memhscx_fill_fifo(bcs);
562 } else {
563 test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
564 schedule_event(bcs, B_XMTBUFREADY);
565 }
566 }
567}
568
569static inline void
570Memhscx_int_main(struct IsdnCardState *cs, u_char val)
571{
572
573 u_char exval;
574 struct BCState *bcs;
575
576 if (val & 0x01) { // EXB
577 bcs = cs->bcs + 1;
578 exval = MemReadHSCX(cs, 1, HSCX_EXIR);
579 if (exval & 0x40) {
580 if (bcs->mode == 1)
581 Memhscx_fill_fifo(bcs);
582 else {
583 /* Here we lost an TX interrupt, so
584 * restart transmitting the whole frame.
585 */
586 if (bcs->tx_skb) {
587 skb_push(bcs->tx_skb, bcs->hw.hscx.count);
588 bcs->tx_cnt += bcs->hw.hscx.count;
589 bcs->hw.hscx.count = 0;
590 }
591 MemWriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x01);
592 if (cs->debug & L1_DEB_WARN)
593 debugl1(cs, "HSCX B EXIR %x Lost TX", exval);
594 }
595 } else if (cs->debug & L1_DEB_HSCX)
596 debugl1(cs, "HSCX B EXIR %x", exval);
597 }
598 if (val & 0xf8) {
599 if (cs->debug & L1_DEB_HSCX)
600 debugl1(cs, "HSCX B interrupt %x", val);
601 Memhscx_interrupt(cs, val, 1);
602 }
603 if (val & 0x02) { // EXA
604 bcs = cs->bcs;
605 exval = MemReadHSCX(cs, 0, HSCX_EXIR);
606 if (exval & 0x40) {
607 if (bcs->mode == L1_MODE_TRANS)
608 Memhscx_fill_fifo(bcs);
609 else {
610 /* Here we lost an TX interrupt, so
611 * restart transmitting the whole frame.
612 */
613 if (bcs->tx_skb) {
614 skb_push(bcs->tx_skb, bcs->hw.hscx.count);
615 bcs->tx_cnt += bcs->hw.hscx.count;
616 bcs->hw.hscx.count = 0;
617 }
618 MemWriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x01);
619 if (cs->debug & L1_DEB_WARN)
620 debugl1(cs, "HSCX A EXIR %x Lost TX", exval);
621 }
622 } else if (cs->debug & L1_DEB_HSCX)
623 debugl1(cs, "HSCX A EXIR %x", exval);
624 }
625 if (val & 0x04) { // ICA
626 exval = MemReadHSCX(cs, 0, HSCX_ISTA);
627 if (cs->debug & L1_DEB_HSCX)
628 debugl1(cs, "HSCX A interrupt %x", exval);
629 Memhscx_interrupt(cs, exval, 0);
630 }
631}
632
633static irqreturn_t
634diva_irq_ipac_pci(int intno, void *dev_id, struct pt_regs *regs)
635{
636 struct IsdnCardState *cs = dev_id;
637 u_char ista,val;
638 int icnt=5;
639 u_char *cfg;
640 u_long flags;
641
642 spin_lock_irqsave(&cs->lock, flags);
643 cfg = (u_char *) cs->hw.diva.pci_cfg;
644 val = *cfg;
645 if (!(val & PITA_INT0_STATUS)) {
646 spin_unlock_irqrestore(&cs->lock, flags);
647 return IRQ_NONE; /* other shared IRQ */
648 }
649 *cfg = PITA_INT0_STATUS; /* Reset pending INT0 */
650 ista = memreadreg(cs->hw.diva.cfg_reg, IPAC_ISTA);
651Start_IPACPCI:
652 if (cs->debug & L1_DEB_IPAC)
653 debugl1(cs, "IPAC ISTA %02X", ista);
654 if (ista & 0x0f) {
655 val = memreadreg(cs->hw.diva.cfg_reg, HSCX_ISTA + 0x40);
656 if (ista & 0x01)
657 val |= 0x01;
658 if (ista & 0x04)
659 val |= 0x02;
660 if (ista & 0x08)
661 val |= 0x04;
662 if (val)
663 Memhscx_int_main(cs, val);
664 }
665 if (ista & 0x20) {
666 val = 0xfe & memreadreg(cs->hw.diva.cfg_reg, ISAC_ISTA + 0x80);
667 if (val) {
668 isac_interrupt(cs, val);
669 }
670 }
671 if (ista & 0x10) {
672 val = 0x01;
673 isac_interrupt(cs, val);
674 }
675 ista = memreadreg(cs->hw.diva.cfg_reg, IPAC_ISTA);
676 if ((ista & 0x3f) && icnt) {
677 icnt--;
678 goto Start_IPACPCI;
679 }
680 if (!icnt)
681 printk(KERN_WARNING "DIVA IPAC PCI IRQ LOOP\n");
682 memwritereg(cs->hw.diva.cfg_reg, IPAC_MASK, 0xFF);
683 memwritereg(cs->hw.diva.cfg_reg, IPAC_MASK, 0xC0);
684 spin_unlock_irqrestore(&cs->lock, flags);
685 return IRQ_HANDLED;
686}
687
688static irqreturn_t
689diva_irq_ipacx_pci(int intno, void *dev_id, struct pt_regs *regs)
690{
691 struct IsdnCardState *cs = dev_id;
692 u_char val;
693 u_char *cfg;
694 u_long flags;
695
696 spin_lock_irqsave(&cs->lock, flags);
697 cfg = (u_char *) cs->hw.diva.pci_cfg;
698 val = *cfg;
699 if (!(val &PITA_INT0_STATUS)) {
700 spin_unlock_irqrestore(&cs->lock, flags);
701 return IRQ_NONE; // other shared IRQ
702 }
703 interrupt_ipacx(cs); // handler for chip
704 *cfg = PITA_INT0_STATUS; // Reset PLX interrupt
705 spin_unlock_irqrestore(&cs->lock, flags);
706 return IRQ_HANDLED;
707}
708
709void
710release_io_diva(struct IsdnCardState *cs)
711{
712 int bytecnt;
713
714 if ((cs->subtyp == DIVA_IPAC_PCI) ||
715 (cs->subtyp == DIVA_IPACX_PCI) ) {
716 u_int *cfg = (unsigned int *)cs->hw.diva.pci_cfg;
717
718 *cfg = 0; /* disable INT0/1 */
719 *cfg = 2; /* reset pending INT0 */
720 iounmap((void *)cs->hw.diva.cfg_reg);
721 iounmap((void *)cs->hw.diva.pci_cfg);
722 return;
723 } else if (cs->subtyp != DIVA_IPAC_ISA) {
724 del_timer(&cs->hw.diva.tl);
725 if (cs->hw.diva.cfg_reg)
726 byteout(cs->hw.diva.ctrl, 0); /* LED off, Reset */
727 }
728 if ((cs->subtyp == DIVA_ISA) || (cs->subtyp == DIVA_IPAC_ISA))
729 bytecnt = 8;
730 else
731 bytecnt = 32;
732 if (cs->hw.diva.cfg_reg) {
733 release_region(cs->hw.diva.cfg_reg, bytecnt);
734 }
735}
736
737static void
738reset_diva(struct IsdnCardState *cs)
739{
740 if (cs->subtyp == DIVA_IPAC_ISA) {
741 writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_POTA2, 0x20);
742 mdelay(10);
743 writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_POTA2, 0x00);
744 mdelay(10);
745 writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_MASK, 0xc0);
746 } else if (cs->subtyp == DIVA_IPAC_PCI) {
747 unsigned int *ireg = (unsigned int *)(cs->hw.diva.pci_cfg +
748 PITA_MISC_REG);
749 *ireg = PITA_PARA_SOFTRESET | PITA_PARA_MPX_MODE;
750 mdelay(10);
751 *ireg = PITA_PARA_MPX_MODE;
752 mdelay(10);
753 memwritereg(cs->hw.diva.cfg_reg, IPAC_MASK, 0xc0);
754 } else if (cs->subtyp == DIVA_IPACX_PCI) {
755 unsigned int *ireg = (unsigned int *)(cs->hw.diva.pci_cfg +
756 PITA_MISC_REG);
757 *ireg = PITA_PARA_SOFTRESET | PITA_PARA_MPX_MODE;
758 mdelay(10);
759 *ireg = PITA_PARA_MPX_MODE | PITA_SER_SOFTRESET;
760 mdelay(10);
761 MemWriteISAC_IPACX(cs, IPACX_MASK, 0xff); // Interrupts off
762 } else { /* DIVA 2.0 */
763 cs->hw.diva.ctrl_reg = 0; /* Reset On */
764 byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg);
765 mdelay(10);
766 cs->hw.diva.ctrl_reg |= DIVA_RESET; /* Reset Off */
767 byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg);
768 mdelay(10);
769 if (cs->subtyp == DIVA_ISA)
770 cs->hw.diva.ctrl_reg |= DIVA_ISA_LED_A;
771 else {
772 /* Workaround PCI9060 */
773 byteout(cs->hw.diva.pci_cfg + 0x69, 9);
774 cs->hw.diva.ctrl_reg |= DIVA_PCI_LED_A;
775 }
776 byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg);
777 }
778}
779
780#define DIVA_ASSIGN 1
781
782static void
783diva_led_handler(struct IsdnCardState *cs)
784{
785 int blink = 0;
786
787 if ((cs->subtyp == DIVA_IPAC_ISA) ||
788 (cs->subtyp == DIVA_IPAC_PCI) ||
789 (cs->subtyp == DIVA_IPACX_PCI) )
790 return;
791 del_timer(&cs->hw.diva.tl);
792 if (cs->hw.diva.status & DIVA_ASSIGN)
793 cs->hw.diva.ctrl_reg |= (DIVA_ISA == cs->subtyp) ?
794 DIVA_ISA_LED_A : DIVA_PCI_LED_A;
795 else {
796 cs->hw.diva.ctrl_reg ^= (DIVA_ISA == cs->subtyp) ?
797 DIVA_ISA_LED_A : DIVA_PCI_LED_A;
798 blink = 250;
799 }
800 if (cs->hw.diva.status & 0xf000)
801 cs->hw.diva.ctrl_reg |= (DIVA_ISA == cs->subtyp) ?
802 DIVA_ISA_LED_B : DIVA_PCI_LED_B;
803 else if (cs->hw.diva.status & 0x0f00) {
804 cs->hw.diva.ctrl_reg ^= (DIVA_ISA == cs->subtyp) ?
805 DIVA_ISA_LED_B : DIVA_PCI_LED_B;
806 blink = 500;
807 } else
808 cs->hw.diva.ctrl_reg &= ~((DIVA_ISA == cs->subtyp) ?
809 DIVA_ISA_LED_B : DIVA_PCI_LED_B);
810
811 byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg);
812 if (blink) {
813 init_timer(&cs->hw.diva.tl);
814 cs->hw.diva.tl.expires = jiffies + ((blink * HZ) / 1000);
815 add_timer(&cs->hw.diva.tl);
816 }
817}
818
819static int
820Diva_card_msg(struct IsdnCardState *cs, int mt, void *arg)
821{
822 u_int *ireg;
823 u_long flags;
824
825 switch (mt) {
826 case CARD_RESET:
827 spin_lock_irqsave(&cs->lock, flags);
828 reset_diva(cs);
829 spin_unlock_irqrestore(&cs->lock, flags);
830 return(0);
831 case CARD_RELEASE:
832 release_io_diva(cs);
833 return(0);
834 case CARD_INIT:
835 spin_lock_irqsave(&cs->lock, flags);
836 reset_diva(cs);
837 if (cs->subtyp == DIVA_IPACX_PCI) {
838 ireg = (unsigned int *)cs->hw.diva.pci_cfg;
839 *ireg = PITA_INT0_ENABLE;
840 init_ipacx(cs, 3); // init chip and enable interrupts
841 spin_unlock_irqrestore(&cs->lock, flags);
842 return (0);
843 }
844 if (cs->subtyp == DIVA_IPAC_PCI) {
845 ireg = (unsigned int *)cs->hw.diva.pci_cfg;
846 *ireg = PITA_INT0_ENABLE;
847 }
848 inithscxisac(cs, 3);
849 spin_unlock_irqrestore(&cs->lock, flags);
850 return(0);
851 case CARD_TEST:
852 return(0);
853 case (MDL_REMOVE | REQUEST):
854 cs->hw.diva.status = 0;
855 break;
856 case (MDL_ASSIGN | REQUEST):
857 cs->hw.diva.status |= DIVA_ASSIGN;
858 break;
859 case MDL_INFO_SETUP:
860 if ((long)arg)
861 cs->hw.diva.status |= 0x0200;
862 else
863 cs->hw.diva.status |= 0x0100;
864 break;
865 case MDL_INFO_CONN:
866 if ((long)arg)
867 cs->hw.diva.status |= 0x2000;
868 else
869 cs->hw.diva.status |= 0x1000;
870 break;
871 case MDL_INFO_REL:
872 if ((long)arg) {
873 cs->hw.diva.status &= ~0x2000;
874 cs->hw.diva.status &= ~0x0200;
875 } else {
876 cs->hw.diva.status &= ~0x1000;
877 cs->hw.diva.status &= ~0x0100;
878 }
879 break;
880 }
881 if ((cs->subtyp != DIVA_IPAC_ISA) &&
882 (cs->subtyp != DIVA_IPAC_PCI) &&
883 (cs->subtyp != DIVA_IPACX_PCI)) {
884 spin_lock_irqsave(&cs->lock, flags);
885 diva_led_handler(cs);
886 spin_unlock_irqrestore(&cs->lock, flags);
887 }
888 return(0);
889}
890
891static struct pci_dev *dev_diva __initdata = NULL;
892static struct pci_dev *dev_diva_u __initdata = NULL;
893static struct pci_dev *dev_diva201 __initdata = NULL;
894static struct pci_dev *dev_diva202 __initdata = NULL;
895
896#ifdef __ISAPNP__
897static struct isapnp_device_id diva_ids[] __initdata = {
898 { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
899 ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
900 (unsigned long) "Diva picola" },
901 { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
902 ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x51),
903 (unsigned long) "Diva picola" },
904 { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71),
905 ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71),
906 (unsigned long) "Diva 2.0" },
907 { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71),
908 ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x71),
909 (unsigned long) "Diva 2.0" },
910 { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1),
911 ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1),
912 (unsigned long) "Diva 2.01" },
913 { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1),
914 ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0xA1),
915 (unsigned long) "Diva 2.01" },
916 { 0, }
917};
918
919static struct isapnp_device_id *ipid __initdata = &diva_ids[0];
920static struct pnp_card *pnp_c __devinitdata = NULL;
921#endif
922
923
924int __init
925setup_diva(struct IsdnCard *card)
926{
927 int bytecnt = 8;
928 u_char val;
929 struct IsdnCardState *cs = card->cs;
930 char tmp[64];
931
932 strcpy(tmp, Diva_revision);
933 printk(KERN_INFO "HiSax: Eicon.Diehl Diva driver Rev. %s\n", HiSax_getrev(tmp));
934 if (cs->typ != ISDN_CTYPE_DIEHLDIVA)
935 return(0);
936 cs->hw.diva.status = 0;
937 if (card->para[1]) {
938 cs->hw.diva.ctrl_reg = 0;
939 cs->hw.diva.cfg_reg = card->para[1];
940 val = readreg(cs->hw.diva.cfg_reg + DIVA_IPAC_ADR,
941 cs->hw.diva.cfg_reg + DIVA_IPAC_DATA, IPAC_ID);
942 printk(KERN_INFO "Diva: IPAC version %x\n", val);
943 if ((val == 1) || (val==2)) {
944 cs->subtyp = DIVA_IPAC_ISA;
945 cs->hw.diva.ctrl = 0;
946 cs->hw.diva.isac = card->para[1] + DIVA_IPAC_DATA;
947 cs->hw.diva.hscx = card->para[1] + DIVA_IPAC_DATA;
948 cs->hw.diva.isac_adr = card->para[1] + DIVA_IPAC_ADR;
949 cs->hw.diva.hscx_adr = card->para[1] + DIVA_IPAC_ADR;
950 test_and_set_bit(HW_IPAC, &cs->HW_Flags);
951 } else {
952 cs->subtyp = DIVA_ISA;
953 cs->hw.diva.ctrl = card->para[1] + DIVA_ISA_CTRL;
954 cs->hw.diva.isac = card->para[1] + DIVA_ISA_ISAC_DATA;
955 cs->hw.diva.hscx = card->para[1] + DIVA_HSCX_DATA;
956 cs->hw.diva.isac_adr = card->para[1] + DIVA_ISA_ISAC_ADR;
957 cs->hw.diva.hscx_adr = card->para[1] + DIVA_HSCX_ADR;
958 }
959 cs->irq = card->para[0];
960 } else {
961#ifdef __ISAPNP__
962 if (isapnp_present()) {
963 struct pnp_dev *pnp_d;
964 while(ipid->card_vendor) {
965 if ((pnp_c = pnp_find_card(ipid->card_vendor,
966 ipid->card_device, pnp_c))) {
967 pnp_d = NULL;
968 if ((pnp_d = pnp_find_dev(pnp_c,
969 ipid->vendor, ipid->function, pnp_d))) {
970 int err;
971
972 printk(KERN_INFO "HiSax: %s detected\n",
973 (char *)ipid->driver_data);
974 pnp_disable_dev(pnp_d);
975 err = pnp_activate_dev(pnp_d);
976 if (err<0) {
977 printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
978 __FUNCTION__, err);
979 return(0);
980 }
981 card->para[1] = pnp_port_start(pnp_d, 0);
982 card->para[0] = pnp_irq(pnp_d, 0);
983 if (!card->para[0] || !card->para[1]) {
984 printk(KERN_ERR "Diva PnP:some resources are missing %ld/%lx\n",
985 card->para[0], card->para[1]);
986 pnp_disable_dev(pnp_d);
987 return(0);
988 }
989 cs->hw.diva.cfg_reg = card->para[1];
990 cs->irq = card->para[0];
991 if (ipid->function == ISAPNP_FUNCTION(0xA1)) {
992 cs->subtyp = DIVA_IPAC_ISA;
993 cs->hw.diva.ctrl = 0;
994 cs->hw.diva.isac =
995 card->para[1] + DIVA_IPAC_DATA;
996 cs->hw.diva.hscx =
997 card->para[1] + DIVA_IPAC_DATA;
998 cs->hw.diva.isac_adr =
999 card->para[1] + DIVA_IPAC_ADR;
1000 cs->hw.diva.hscx_adr =
1001 card->para[1] + DIVA_IPAC_ADR;
1002 test_and_set_bit(HW_IPAC, &cs->HW_Flags);
1003 } else {
1004 cs->subtyp = DIVA_ISA;
1005 cs->hw.diva.ctrl =
1006 card->para[1] + DIVA_ISA_CTRL;
1007 cs->hw.diva.isac =
1008 card->para[1] + DIVA_ISA_ISAC_DATA;
1009 cs->hw.diva.hscx =
1010 card->para[1] + DIVA_HSCX_DATA;
1011 cs->hw.diva.isac_adr =
1012 card->para[1] + DIVA_ISA_ISAC_ADR;
1013 cs->hw.diva.hscx_adr =
1014 card->para[1] + DIVA_HSCX_ADR;
1015 }
1016 goto ready;
1017 } else {
1018 printk(KERN_ERR "Diva PnP: PnP error card found, no device\n");
1019 return(0);
1020 }
1021 }
1022 ipid++;
1023 pnp_c=NULL;
1024 }
1025 if (!ipid->card_vendor) {
1026 printk(KERN_INFO "Diva PnP: no ISAPnP card found\n");
1027 }
1028 }
1029#endif
1030#ifdef CONFIG_PCI
1031 cs->subtyp = 0;
1032 if ((dev_diva = pci_find_device(PCI_VENDOR_ID_EICON,
1033 PCI_DEVICE_ID_EICON_DIVA20, dev_diva))) {
1034 if (pci_enable_device(dev_diva))
1035 return(0);
1036 cs->subtyp = DIVA_PCI;
1037 cs->irq = dev_diva->irq;
1038 cs->hw.diva.cfg_reg = pci_resource_start(dev_diva, 2);
1039 } else if ((dev_diva_u = pci_find_device(PCI_VENDOR_ID_EICON,
1040 PCI_DEVICE_ID_EICON_DIVA20_U, dev_diva_u))) {
1041 if (pci_enable_device(dev_diva_u))
1042 return(0);
1043 cs->subtyp = DIVA_PCI;
1044 cs->irq = dev_diva_u->irq;
1045 cs->hw.diva.cfg_reg = pci_resource_start(dev_diva_u, 2);
1046 } else if ((dev_diva201 = pci_find_device(PCI_VENDOR_ID_EICON,
1047 PCI_DEVICE_ID_EICON_DIVA201, dev_diva201))) {
1048 if (pci_enable_device(dev_diva201))
1049 return(0);
1050 cs->subtyp = DIVA_IPAC_PCI;
1051 cs->irq = dev_diva201->irq;
1052 cs->hw.diva.pci_cfg =
1053 (ulong) ioremap(pci_resource_start(dev_diva201, 0), 4096);
1054 cs->hw.diva.cfg_reg =
1055 (ulong) ioremap(pci_resource_start(dev_diva201, 1), 4096);
1056 } else if ((dev_diva202 = pci_find_device(PCI_VENDOR_ID_EICON,
1057 PCI_DEVICE_ID_EICON_DIVA202, dev_diva202))) {
1058 if (pci_enable_device(dev_diva202))
1059 return(0);
1060 cs->subtyp = DIVA_IPACX_PCI;
1061 cs->irq = dev_diva202->irq;
1062 cs->hw.diva.pci_cfg =
1063 (ulong) ioremap(pci_resource_start(dev_diva202, 0), 4096);
1064 cs->hw.diva.cfg_reg =
1065 (ulong) ioremap(pci_resource_start(dev_diva202, 1), 4096);
1066 } else {
1067 printk(KERN_WARNING "Diva: No PCI card found\n");
1068 return(0);
1069 }
1070
1071 if (!cs->irq) {
1072 printk(KERN_WARNING "Diva: No IRQ for PCI card found\n");
1073 return(0);
1074 }
1075
1076 if (!cs->hw.diva.cfg_reg) {
1077 printk(KERN_WARNING "Diva: No IO-Adr for PCI card found\n");
1078 return(0);
1079 }
1080 cs->irq_flags |= SA_SHIRQ;
1081#else
1082 printk(KERN_WARNING "Diva: cfgreg 0 and NO_PCI_BIOS\n");
1083 printk(KERN_WARNING "Diva: unable to config DIVA PCI\n");
1084 return (0);
1085#endif /* CONFIG_PCI */
1086 if ((cs->subtyp == DIVA_IPAC_PCI) ||
1087 (cs->subtyp == DIVA_IPACX_PCI) ) {
1088 cs->hw.diva.ctrl = 0;
1089 cs->hw.diva.isac = 0;
1090 cs->hw.diva.hscx = 0;
1091 cs->hw.diva.isac_adr = 0;
1092 cs->hw.diva.hscx_adr = 0;
1093 test_and_set_bit(HW_IPAC, &cs->HW_Flags);
1094 bytecnt = 0;
1095 } else {
1096 cs->hw.diva.ctrl = cs->hw.diva.cfg_reg + DIVA_PCI_CTRL;
1097 cs->hw.diva.isac = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_DATA;
1098 cs->hw.diva.hscx = cs->hw.diva.cfg_reg + DIVA_HSCX_DATA;
1099 cs->hw.diva.isac_adr = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_ADR;
1100 cs->hw.diva.hscx_adr = cs->hw.diva.cfg_reg + DIVA_HSCX_ADR;
1101 bytecnt = 32;
1102 }
1103 }
1104ready:
1105 printk(KERN_INFO
1106 "Diva: %s card configured at %#lx IRQ %d\n",
1107 (cs->subtyp == DIVA_PCI) ? "PCI" :
1108 (cs->subtyp == DIVA_ISA) ? "ISA" :
1109 (cs->subtyp == DIVA_IPAC_ISA) ? "IPAC ISA" :
1110 (cs->subtyp == DIVA_IPAC_PCI) ? "IPAC PCI" : "IPACX PCI",
1111 cs->hw.diva.cfg_reg, cs->irq);
1112 if ((cs->subtyp == DIVA_IPAC_PCI) ||
1113 (cs->subtyp == DIVA_IPACX_PCI) ||
1114 (cs->subtyp == DIVA_PCI) )
1115 printk(KERN_INFO "Diva: %s space at %#lx\n",
1116 (cs->subtyp == DIVA_PCI) ? "PCI" :
1117 (cs->subtyp == DIVA_IPAC_PCI) ? "IPAC PCI" : "IPACX PCI",
1118 cs->hw.diva.pci_cfg);
1119 if ((cs->subtyp != DIVA_IPAC_PCI) &&
1120 (cs->subtyp != DIVA_IPACX_PCI) ) {
1121 if (!request_region(cs->hw.diva.cfg_reg, bytecnt, "diva isdn")) {
1122 printk(KERN_WARNING
1123 "HiSax: %s config port %lx-%lx already in use\n",
1124 CardType[card->typ],
1125 cs->hw.diva.cfg_reg,
1126 cs->hw.diva.cfg_reg + bytecnt);
1127 return (0);
1128 }
1129 }
1130 cs->BC_Read_Reg = &ReadHSCX;
1131 cs->BC_Write_Reg = &WriteHSCX;
1132 cs->BC_Send_Data = &hscx_fill_fifo;
1133 cs->cardmsg = &Diva_card_msg;
1134 setup_isac(cs);
1135 if (cs->subtyp == DIVA_IPAC_ISA) {
1136 cs->readisac = &ReadISAC_IPAC;
1137 cs->writeisac = &WriteISAC_IPAC;
1138 cs->readisacfifo = &ReadISACfifo_IPAC;
1139 cs->writeisacfifo = &WriteISACfifo_IPAC;
1140 cs->irq_func = &diva_irq_ipac_isa;
1141 val = readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_ID);
1142 printk(KERN_INFO "Diva: IPAC version %x\n", val);
1143 } else if (cs->subtyp == DIVA_IPAC_PCI) {
1144 cs->readisac = &MemReadISAC_IPAC;
1145 cs->writeisac = &MemWriteISAC_IPAC;
1146 cs->readisacfifo = &MemReadISACfifo_IPAC;
1147 cs->writeisacfifo = &MemWriteISACfifo_IPAC;
1148 cs->BC_Read_Reg = &MemReadHSCX;
1149 cs->BC_Write_Reg = &MemWriteHSCX;
1150 cs->BC_Send_Data = &Memhscx_fill_fifo;
1151 cs->irq_func = &diva_irq_ipac_pci;
1152 val = memreadreg(cs->hw.diva.cfg_reg, IPAC_ID);
1153 printk(KERN_INFO "Diva: IPAC version %x\n", val);
1154 } else if (cs->subtyp == DIVA_IPACX_PCI) {
1155 cs->readisac = &MemReadISAC_IPACX;
1156 cs->writeisac = &MemWriteISAC_IPACX;
1157 cs->readisacfifo = &MemReadISACfifo_IPACX;
1158 cs->writeisacfifo = &MemWriteISACfifo_IPACX;
1159 cs->BC_Read_Reg = &MemReadHSCX_IPACX;
1160 cs->BC_Write_Reg = &MemWriteHSCX_IPACX;
1161 cs->BC_Send_Data = NULL; // function located in ipacx module
1162 cs->irq_func = &diva_irq_ipacx_pci;
1163 printk(KERN_INFO "Diva: IPACX Design Id: %x\n",
1164 MemReadISAC_IPACX(cs, IPACX_ID) &0x3F);
1165 } else { /* DIVA 2.0 */
1166 cs->hw.diva.tl.function = (void *) diva_led_handler;
1167 cs->hw.diva.tl.data = (long) cs;
1168 init_timer(&cs->hw.diva.tl);
1169 cs->readisac = &ReadISAC;
1170 cs->writeisac = &WriteISAC;
1171 cs->readisacfifo = &ReadISACfifo;
1172 cs->writeisacfifo = &WriteISACfifo;
1173 cs->irq_func = &diva_interrupt;
1174 ISACVersion(cs, "Diva:");
1175 if (HscxVersion(cs, "Diva:")) {
1176 printk(KERN_WARNING
1177 "Diva: wrong HSCX versions check IO address\n");
1178 release_io_diva(cs);
1179 return (0);
1180 }
1181 }
1182 return (1);
1183}
diff --git a/drivers/isdn/hisax/elsa.c b/drivers/isdn/hisax/elsa.c
new file mode 100644
index 000000000000..4d7a0250d7e2
--- /dev/null
+++ b/drivers/isdn/hisax/elsa.c
@@ -0,0 +1,1190 @@
1/* $Id: elsa.c,v 2.32.2.4 2004/01/24 20:47:21 keil Exp $
2 *
3 * low level stuff for Elsa isdn cards
4 *
5 * Author Karsten Keil
6 * Copyright by Karsten Keil <keil@isdn4linux.de>
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 * For changes and modifications please read
12 * Documentation/isdn/HiSax.cert
13 *
14 * Thanks to Elsa GmbH for documents and information
15 *
16 * Klaus Lichtenwalder (Klaus.Lichtenwalder@WebForum.DE)
17 * for ELSA PCMCIA support
18 *
19 */
20
21#include <linux/init.h>
22#include <linux/config.h>
23#include "hisax.h"
24#include "arcofi.h"
25#include "isac.h"
26#include "ipac.h"
27#include "hscx.h"
28#include "isdnl1.h"
29#include <linux/pci.h>
30#include <linux/isapnp.h>
31#include <linux/serial.h>
32#include <linux/serial_reg.h>
33
34extern const char *CardType[];
35
36const char *Elsa_revision = "$Revision: 2.32.2.4 $";
37const char *Elsa_Types[] =
38{"None", "PC", "PCC-8", "PCC-16", "PCF", "PCF-Pro",
39 "PCMCIA", "QS 1000", "QS 3000", "Microlink PCI", "QS 3000 PCI",
40 "PCMCIA-IPAC" };
41
42const char *ITACVer[] =
43{"?0?", "?1?", "?2?", "?3?", "?4?", "V2.2",
44 "B1", "A1"};
45
46#define byteout(addr,val) outb(val,addr)
47#define bytein(addr) inb(addr)
48
49#define ELSA_ISAC 0
50#define ELSA_ISAC_PCM 1
51#define ELSA_ITAC 1
52#define ELSA_HSCX 2
53#define ELSA_ALE 3
54#define ELSA_ALE_PCM 4
55#define ELSA_CONTROL 4
56#define ELSA_CONFIG 5
57#define ELSA_START_TIMER 6
58#define ELSA_TRIG_IRQ 7
59
60#define ELSA_PC 1
61#define ELSA_PCC8 2
62#define ELSA_PCC16 3
63#define ELSA_PCF 4
64#define ELSA_PCFPRO 5
65#define ELSA_PCMCIA 6
66#define ELSA_QS1000 7
67#define ELSA_QS3000 8
68#define ELSA_QS1000PCI 9
69#define ELSA_QS3000PCI 10
70#define ELSA_PCMCIA_IPAC 11
71
72/* PCI stuff */
73#define ELSA_PCI_IRQ_MASK 0x04
74
75/* ITAC Registeradressen (only Microlink PC) */
76#define ITAC_SYS 0x34
77#define ITAC_ISEN 0x48
78#define ITAC_RFIE 0x4A
79#define ITAC_XFIE 0x4C
80#define ITAC_SCIE 0x4E
81#define ITAC_STIE 0x46
82
83/*** ***
84 *** Makros als Befehle fuer die Kartenregister ***
85 *** (mehrere Befehle werden durch Bit-Oderung kombiniert) ***
86 *** ***/
87
88/* Config-Register (Read) */
89#define ELSA_TIMER_RUN 0x02 /* Bit 1 des Config-Reg */
90#define ELSA_TIMER_RUN_PCC8 0x01 /* Bit 0 des Config-Reg bei PCC */
91#define ELSA_IRQ_IDX 0x38 /* Bit 3,4,5 des Config-Reg */
92#define ELSA_IRQ_IDX_PCC8 0x30 /* Bit 4,5 des Config-Reg */
93#define ELSA_IRQ_IDX_PC 0x0c /* Bit 2,3 des Config-Reg */
94
95/* Control-Register (Write) */
96#define ELSA_LINE_LED 0x02 /* Bit 1 Gelbe LED */
97#define ELSA_STAT_LED 0x08 /* Bit 3 Gruene LED */
98#define ELSA_ISDN_RESET 0x20 /* Bit 5 Reset-Leitung */
99#define ELSA_ENA_TIMER_INT 0x80 /* Bit 7 Freigabe Timer Interrupt */
100
101/* ALE-Register (Read) */
102#define ELSA_HW_RELEASE 0x07 /* Bit 0-2 Hardwarerkennung */
103#define ELSA_S0_POWER_BAD 0x08 /* Bit 3 S0-Bus Spannung fehlt */
104
105/* Status Flags */
106#define ELSA_TIMER_AKTIV 1
107#define ELSA_BAD_PWR 2
108#define ELSA_ASSIGN 4
109
110#define RS_ISR_PASS_LIMIT 256
111#define _INLINE_ inline
112#define FLG_MODEM_ACTIVE 1
113/* IPAC AUX */
114#define ELSA_IPAC_LINE_LED 0x40 /* Bit 6 Gelbe LED */
115#define ELSA_IPAC_STAT_LED 0x80 /* Bit 7 Gruene LED */
116
117#if ARCOFI_USE
118static struct arcofi_msg ARCOFI_XOP_F =
119 {NULL,0,2,{0xa1,0x3f,0,0,0,0,0,0,0,0}}; /* Normal OP */
120static struct arcofi_msg ARCOFI_XOP_1 =
121 {&ARCOFI_XOP_F,0,2,{0xa1,0x31,0,0,0,0,0,0,0,0}}; /* PWR UP */
122static struct arcofi_msg ARCOFI_SOP_F =
123 {&ARCOFI_XOP_1,0,10,{0xa1,0x1f,0x00,0x50,0x10,0x00,0x00,0x80,0x02,0x12}};
124static struct arcofi_msg ARCOFI_COP_9 =
125 {&ARCOFI_SOP_F,0,10,{0xa1,0x29,0x80,0xcb,0xe9,0x88,0x00,0xc8,0xd8,0x80}}; /* RX */
126static struct arcofi_msg ARCOFI_COP_8 =
127 {&ARCOFI_COP_9,0,10,{0xa1,0x28,0x49,0x31,0x8,0x13,0x6e,0x88,0x2a,0x61}}; /* TX */
128static struct arcofi_msg ARCOFI_COP_7 =
129 {&ARCOFI_COP_8,0,4,{0xa1,0x27,0x80,0x80,0,0,0,0,0,0}}; /* GZ */
130static struct arcofi_msg ARCOFI_COP_6 =
131 {&ARCOFI_COP_7,0,6,{0xa1,0x26,0,0,0x82,0x7c,0,0,0,0}}; /* GRL GRH */
132static struct arcofi_msg ARCOFI_COP_5 =
133 {&ARCOFI_COP_6,0,4,{0xa1,0x25,0xbb,0x4a,0,0,0,0,0,0}}; /* GTX */
134static struct arcofi_msg ARCOFI_VERSION =
135 {NULL,1,2,{0xa0,0,0,0,0,0,0,0,0,0}};
136static struct arcofi_msg ARCOFI_XOP_0 =
137 {NULL,0,2,{0xa1,0x30,0,0,0,0,0,0,0,0}}; /* PWR Down */
138
139static void set_arcofi(struct IsdnCardState *cs, int bc);
140
141#include "elsa_ser.c"
142#endif /* ARCOFI_USE */
143
144static inline u_char
145readreg(unsigned int ale, unsigned int adr, u_char off)
146{
147 register u_char ret;
148
149 byteout(ale, off);
150 ret = bytein(adr);
151 return (ret);
152}
153
154static inline void
155readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
156{
157 byteout(ale, off);
158 insb(adr, data, size);
159}
160
161
162static inline void
163writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
164{
165 byteout(ale, off);
166 byteout(adr, data);
167}
168
169static inline void
170writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
171{
172 byteout(ale, off);
173 outsb(adr, data, size);
174}
175
176/* Interface functions */
177
178static u_char
179ReadISAC(struct IsdnCardState *cs, u_char offset)
180{
181 return (readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, offset));
182}
183
184static void
185WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
186{
187 writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, offset, value);
188}
189
190static void
191ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
192{
193 readfifo(cs->hw.elsa.ale, cs->hw.elsa.isac, 0, data, size);
194}
195
196static void
197WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
198{
199 writefifo(cs->hw.elsa.ale, cs->hw.elsa.isac, 0, data, size);
200}
201
202static u_char
203ReadISAC_IPAC(struct IsdnCardState *cs, u_char offset)
204{
205 return (readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, offset+0x80));
206}
207
208static void
209WriteISAC_IPAC(struct IsdnCardState *cs, u_char offset, u_char value)
210{
211 writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, offset|0x80, value);
212}
213
214static void
215ReadISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size)
216{
217 readfifo(cs->hw.elsa.ale, cs->hw.elsa.isac, 0x80, data, size);
218}
219
220static void
221WriteISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size)
222{
223 writefifo(cs->hw.elsa.ale, cs->hw.elsa.isac, 0x80, data, size);
224}
225
226static u_char
227ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
228{
229 return (readreg(cs->hw.elsa.ale,
230 cs->hw.elsa.hscx, offset + (hscx ? 0x40 : 0)));
231}
232
233static void
234WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
235{
236 writereg(cs->hw.elsa.ale,
237 cs->hw.elsa.hscx, offset + (hscx ? 0x40 : 0), value);
238}
239
240static inline u_char
241readitac(struct IsdnCardState *cs, u_char off)
242{
243 register u_char ret;
244
245 byteout(cs->hw.elsa.ale, off);
246 ret = bytein(cs->hw.elsa.itac);
247 return (ret);
248}
249
250static inline void
251writeitac(struct IsdnCardState *cs, u_char off, u_char data)
252{
253 byteout(cs->hw.elsa.ale, off);
254 byteout(cs->hw.elsa.itac, data);
255}
256
257static inline int
258TimerRun(struct IsdnCardState *cs)
259{
260 register u_char v;
261
262 v = bytein(cs->hw.elsa.cfg);
263 if ((cs->subtyp == ELSA_QS1000) || (cs->subtyp == ELSA_QS3000))
264 return (0 == (v & ELSA_TIMER_RUN));
265 else if (cs->subtyp == ELSA_PCC8)
266 return (v & ELSA_TIMER_RUN_PCC8);
267 return (v & ELSA_TIMER_RUN);
268}
269/*
270 * fast interrupt HSCX stuff goes here
271 */
272
273#define READHSCX(cs, nr, reg) readreg(cs->hw.elsa.ale, \
274 cs->hw.elsa.hscx, reg + (nr ? 0x40 : 0))
275#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.elsa.ale, \
276 cs->hw.elsa.hscx, reg + (nr ? 0x40 : 0), data)
277
278#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.elsa.ale, \
279 cs->hw.elsa.hscx, (nr ? 0x40 : 0), ptr, cnt)
280
281#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.elsa.ale, \
282 cs->hw.elsa.hscx, (nr ? 0x40 : 0), ptr, cnt)
283
284#include "hscx_irq.c"
285
286static irqreturn_t
287elsa_interrupt(int intno, void *dev_id, struct pt_regs *regs)
288{
289 struct IsdnCardState *cs = dev_id;
290 u_long flags;
291 u_char val;
292 int icnt=5;
293
294 if ((cs->typ == ISDN_CTYPE_ELSA_PCMCIA) && (*cs->busy_flag == 1)) {
295 /* The card tends to generate interrupts while being removed
296 causing us to just crash the kernel. bad. */
297 printk(KERN_WARNING "Elsa: card not available!\n");
298 return IRQ_NONE;
299 }
300 spin_lock_irqsave(&cs->lock, flags);
301#if ARCOFI_USE
302 if (cs->hw.elsa.MFlag) {
303 val = serial_inp(cs, UART_IIR);
304 if (!(val & UART_IIR_NO_INT)) {
305 debugl1(cs,"IIR %02x", val);
306 rs_interrupt_elsa(intno, cs);
307 }
308 }
309#endif
310 val = readreg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_ISTA + 0x40);
311 Start_HSCX:
312 if (val) {
313 hscx_int_main(cs, val);
314 }
315 val = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, ISAC_ISTA);
316 Start_ISAC:
317 if (val) {
318 isac_interrupt(cs, val);
319 }
320 val = readreg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_ISTA + 0x40);
321 if (val && icnt) {
322 if (cs->debug & L1_DEB_HSCX)
323 debugl1(cs, "HSCX IntStat after IntRoutine");
324 icnt--;
325 goto Start_HSCX;
326 }
327 val = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, ISAC_ISTA);
328 if (val && icnt) {
329 if (cs->debug & L1_DEB_ISAC)
330 debugl1(cs, "ISAC IntStat after IntRoutine");
331 icnt--;
332 goto Start_ISAC;
333 }
334 if (!icnt)
335 printk(KERN_WARNING"ELSA IRQ LOOP\n");
336 writereg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_MASK, 0xFF);
337 writereg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_MASK + 0x40, 0xFF);
338 writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, ISAC_MASK, 0xFF);
339 if (cs->hw.elsa.status & ELSA_TIMER_AKTIV) {
340 if (!TimerRun(cs)) {
341 /* Timer Restart */
342 byteout(cs->hw.elsa.timer, 0);
343 cs->hw.elsa.counter++;
344 }
345 }
346#if ARCOFI_USE
347 if (cs->hw.elsa.MFlag) {
348 val = serial_inp(cs, UART_MCR);
349 val ^= 0x8;
350 serial_outp(cs, UART_MCR, val);
351 val = serial_inp(cs, UART_MCR);
352 val ^= 0x8;
353 serial_outp(cs, UART_MCR, val);
354 }
355#endif
356 if (cs->hw.elsa.trig)
357 byteout(cs->hw.elsa.trig, 0x00);
358 writereg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_MASK, 0x0);
359 writereg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_MASK + 0x40, 0x0);
360 writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, ISAC_MASK, 0x0);
361 spin_unlock_irqrestore(&cs->lock, flags);
362 return IRQ_HANDLED;
363}
364
365static irqreturn_t
366elsa_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs)
367{
368 struct IsdnCardState *cs = dev_id;
369 u_long flags;
370 u_char ista,val;
371 int icnt=5;
372
373 spin_lock_irqsave(&cs->lock, flags);
374 if (cs->subtyp == ELSA_QS1000PCI || cs->subtyp == ELSA_QS3000PCI) {
375 val = bytein(cs->hw.elsa.cfg + 0x4c); /* PCI IRQ */
376 if (!(val & ELSA_PCI_IRQ_MASK)) {
377 spin_unlock_irqrestore(&cs->lock, flags);
378 return IRQ_NONE;
379 }
380 }
381#if ARCOFI_USE
382 if (cs->hw.elsa.MFlag) {
383 val = serial_inp(cs, UART_IIR);
384 if (!(val & UART_IIR_NO_INT)) {
385 debugl1(cs,"IIR %02x", val);
386 rs_interrupt_elsa(intno, cs);
387 }
388 }
389#endif
390 ista = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ISTA);
391Start_IPAC:
392 if (cs->debug & L1_DEB_IPAC)
393 debugl1(cs, "IPAC ISTA %02X", ista);
394 if (ista & 0x0f) {
395 val = readreg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_ISTA + 0x40);
396 if (ista & 0x01)
397 val |= 0x01;
398 if (ista & 0x04)
399 val |= 0x02;
400 if (ista & 0x08)
401 val |= 0x04;
402 if (val)
403 hscx_int_main(cs, val);
404 }
405 if (ista & 0x20) {
406 val = 0xfe & readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, ISAC_ISTA + 0x80);
407 if (val) {
408 isac_interrupt(cs, val);
409 }
410 }
411 if (ista & 0x10) {
412 val = 0x01;
413 isac_interrupt(cs, val);
414 }
415 ista = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ISTA);
416 if ((ista & 0x3f) && icnt) {
417 icnt--;
418 goto Start_IPAC;
419 }
420 if (!icnt)
421 printk(KERN_WARNING "ELSA IRQ LOOP\n");
422 writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_MASK, 0xFF);
423 writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_MASK, 0xC0);
424 spin_unlock_irqrestore(&cs->lock, flags);
425 return IRQ_HANDLED;
426}
427
428void
429release_io_elsa(struct IsdnCardState *cs)
430{
431 int bytecnt = 8;
432
433 del_timer(&cs->hw.elsa.tl);
434#if ARCOFI_USE
435 clear_arcofi(cs);
436#endif
437 if (cs->hw.elsa.ctrl)
438 byteout(cs->hw.elsa.ctrl, 0); /* LEDs Out */
439 if (cs->subtyp == ELSA_QS1000PCI) {
440 byteout(cs->hw.elsa.cfg + 0x4c, 0x01); /* disable IRQ */
441 writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ATX, 0xff);
442 bytecnt = 2;
443 release_region(cs->hw.elsa.cfg, 0x80);
444 }
445 if (cs->subtyp == ELSA_QS3000PCI) {
446 byteout(cs->hw.elsa.cfg + 0x4c, 0x03); /* disable ELSA PCI IRQ */
447 writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ATX, 0xff);
448 release_region(cs->hw.elsa.cfg, 0x80);
449 }
450 if (cs->subtyp == ELSA_PCMCIA_IPAC) {
451 writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ATX, 0xff);
452 }
453 if ((cs->subtyp == ELSA_PCFPRO) ||
454 (cs->subtyp == ELSA_QS3000) ||
455 (cs->subtyp == ELSA_PCF) ||
456 (cs->subtyp == ELSA_QS3000PCI)) {
457 bytecnt = 16;
458#if ARCOFI_USE
459 release_modem(cs);
460#endif
461 }
462 if (cs->hw.elsa.base)
463 release_region(cs->hw.elsa.base, bytecnt);
464}
465
466static void
467reset_elsa(struct IsdnCardState *cs)
468{
469 if (cs->hw.elsa.timer) {
470 /* Wait 1 Timer */
471 byteout(cs->hw.elsa.timer, 0);
472 while (TimerRun(cs));
473 cs->hw.elsa.ctrl_reg |= 0x50;
474 cs->hw.elsa.ctrl_reg &= ~ELSA_ISDN_RESET; /* Reset On */
475 byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg);
476 /* Wait 1 Timer */
477 byteout(cs->hw.elsa.timer, 0);
478 while (TimerRun(cs));
479 cs->hw.elsa.ctrl_reg |= ELSA_ISDN_RESET; /* Reset Off */
480 byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg);
481 /* Wait 1 Timer */
482 byteout(cs->hw.elsa.timer, 0);
483 while (TimerRun(cs));
484 if (cs->hw.elsa.trig)
485 byteout(cs->hw.elsa.trig, 0xff);
486 }
487 if ((cs->subtyp == ELSA_QS1000PCI) || (cs->subtyp == ELSA_QS3000PCI) || (cs->subtyp == ELSA_PCMCIA_IPAC)) {
488 writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_POTA2, 0x20);
489 mdelay(10);
490 writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_POTA2, 0x00);
491 writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_MASK, 0xc0);
492 mdelay(10);
493 if (cs->subtyp != ELSA_PCMCIA_IPAC) {
494 writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ACFG, 0x0);
495 writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_AOE, 0x3c);
496 } else {
497 writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_PCFG, 0x10);
498 writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ACFG, 0x4);
499 writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_AOE, 0xf8);
500 }
501 writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ATX, 0xff);
502 if (cs->subtyp == ELSA_QS1000PCI)
503 byteout(cs->hw.elsa.cfg + 0x4c, 0x41); /* enable ELSA PCI IRQ */
504 else if (cs->subtyp == ELSA_QS3000PCI)
505 byteout(cs->hw.elsa.cfg + 0x4c, 0x43); /* enable ELSA PCI IRQ */
506 }
507}
508
509#if ARCOFI_USE
510
511static void
512set_arcofi(struct IsdnCardState *cs, int bc) {
513 cs->dc.isac.arcofi_bc = bc;
514 arcofi_fsm(cs, ARCOFI_START, &ARCOFI_COP_5);
515 interruptible_sleep_on(&cs->dc.isac.arcofi_wait);
516}
517
518static int
519check_arcofi(struct IsdnCardState *cs)
520{
521 int arcofi_present = 0;
522 char tmp[40];
523 char *t;
524 u_char *p;
525
526 if (!cs->dc.isac.mon_tx)
527 if (!(cs->dc.isac.mon_tx=kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) {
528 if (cs->debug & L1_DEB_WARN)
529 debugl1(cs, "ISAC MON TX out of buffers!");
530 return(0);
531 }
532 cs->dc.isac.arcofi_bc = 0;
533 arcofi_fsm(cs, ARCOFI_START, &ARCOFI_VERSION);
534 interruptible_sleep_on(&cs->dc.isac.arcofi_wait);
535 if (!test_and_clear_bit(FLG_ARCOFI_ERROR, &cs->HW_Flags)) {
536 debugl1(cs, "Arcofi response received %d bytes", cs->dc.isac.mon_rxp);
537 p = cs->dc.isac.mon_rx;
538 t = tmp;
539 t += sprintf(tmp, "Arcofi data");
540 QuickHex(t, p, cs->dc.isac.mon_rxp);
541 debugl1(cs, tmp);
542 if ((cs->dc.isac.mon_rxp == 2) && (cs->dc.isac.mon_rx[0] == 0xa0)) {
543 switch(cs->dc.isac.mon_rx[1]) {
544 case 0x80:
545 debugl1(cs, "Arcofi 2160 detected");
546 arcofi_present = 1;
547 break;
548 case 0x82:
549 debugl1(cs, "Arcofi 2165 detected");
550 arcofi_present = 2;
551 break;
552 case 0x84:
553 debugl1(cs, "Arcofi 2163 detected");
554 arcofi_present = 3;
555 break;
556 default:
557 debugl1(cs, "unknown Arcofi response");
558 break;
559 }
560 } else
561 debugl1(cs, "undefined Monitor response");
562 cs->dc.isac.mon_rxp = 0;
563 } else if (cs->dc.isac.mon_tx) {
564 debugl1(cs, "Arcofi not detected");
565 }
566 if (arcofi_present) {
567 if (cs->subtyp==ELSA_QS1000) {
568 cs->subtyp = ELSA_QS3000;
569 printk(KERN_INFO
570 "Elsa: %s detected modem at 0x%lx\n",
571 Elsa_Types[cs->subtyp],
572 cs->hw.elsa.base+8);
573 release_region(cs->hw.elsa.base, 8);
574 if (!request_region(cs->hw.elsa.base, 16, "elsa isdn modem")) {
575 printk(KERN_WARNING
576 "HiSax: %s config port %lx-%lx already in use\n",
577 Elsa_Types[cs->subtyp],
578 cs->hw.elsa.base + 8,
579 cs->hw.elsa.base + 16);
580 }
581 } else if (cs->subtyp==ELSA_PCC16) {
582 cs->subtyp = ELSA_PCF;
583 printk(KERN_INFO
584 "Elsa: %s detected modem at 0x%lx\n",
585 Elsa_Types[cs->subtyp],
586 cs->hw.elsa.base+8);
587 release_region(cs->hw.elsa.base, 8);
588 if (!request_region(cs->hw.elsa.base, 16, "elsa isdn modem")) {
589 printk(KERN_WARNING
590 "HiSax: %s config port %lx-%lx already in use\n",
591 Elsa_Types[cs->subtyp],
592 cs->hw.elsa.base + 8,
593 cs->hw.elsa.base + 16);
594 }
595 } else
596 printk(KERN_INFO
597 "Elsa: %s detected modem at 0x%lx\n",
598 Elsa_Types[cs->subtyp],
599 cs->hw.elsa.base+8);
600 arcofi_fsm(cs, ARCOFI_START, &ARCOFI_XOP_0);
601 interruptible_sleep_on(&cs->dc.isac.arcofi_wait);
602 return(1);
603 }
604 return(0);
605}
606#endif /* ARCOFI_USE */
607
608static void
609elsa_led_handler(struct IsdnCardState *cs)
610{
611 int blink = 0;
612
613 if (cs->subtyp == ELSA_PCMCIA || cs->subtyp == ELSA_PCMCIA_IPAC)
614 return;
615 del_timer(&cs->hw.elsa.tl);
616 if (cs->hw.elsa.status & ELSA_ASSIGN)
617 cs->hw.elsa.ctrl_reg |= ELSA_STAT_LED;
618 else if (cs->hw.elsa.status & ELSA_BAD_PWR)
619 cs->hw.elsa.ctrl_reg &= ~ELSA_STAT_LED;
620 else {
621 cs->hw.elsa.ctrl_reg ^= ELSA_STAT_LED;
622 blink = 250;
623 }
624 if (cs->hw.elsa.status & 0xf000)
625 cs->hw.elsa.ctrl_reg |= ELSA_LINE_LED;
626 else if (cs->hw.elsa.status & 0x0f00) {
627 cs->hw.elsa.ctrl_reg ^= ELSA_LINE_LED;
628 blink = 500;
629 } else
630 cs->hw.elsa.ctrl_reg &= ~ELSA_LINE_LED;
631
632 if ((cs->subtyp == ELSA_QS1000PCI) ||
633 (cs->subtyp == ELSA_QS3000PCI)) {
634 u_char led = 0xff;
635 if (cs->hw.elsa.ctrl_reg & ELSA_LINE_LED)
636 led ^= ELSA_IPAC_LINE_LED;
637 if (cs->hw.elsa.ctrl_reg & ELSA_STAT_LED)
638 led ^= ELSA_IPAC_STAT_LED;
639 writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ATX, led);
640 } else
641 byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg);
642 if (blink) {
643 init_timer(&cs->hw.elsa.tl);
644 cs->hw.elsa.tl.expires = jiffies + ((blink * HZ) / 1000);
645 add_timer(&cs->hw.elsa.tl);
646 }
647}
648
649static int
650Elsa_card_msg(struct IsdnCardState *cs, int mt, void *arg)
651{
652 int ret = 0;
653 u_long flags;
654
655 switch (mt) {
656 case CARD_RESET:
657 spin_lock_irqsave(&cs->lock, flags);
658 reset_elsa(cs);
659 spin_unlock_irqrestore(&cs->lock, flags);
660 return(0);
661 case CARD_RELEASE:
662 release_io_elsa(cs);
663 return(0);
664 case CARD_INIT:
665 spin_lock_irqsave(&cs->lock, flags);
666 cs->debug |= L1_DEB_IPAC;
667 reset_elsa(cs);
668 inithscxisac(cs, 1);
669 if ((cs->subtyp == ELSA_QS1000) ||
670 (cs->subtyp == ELSA_QS3000))
671 {
672 byteout(cs->hw.elsa.timer, 0);
673 }
674 if (cs->hw.elsa.trig)
675 byteout(cs->hw.elsa.trig, 0xff);
676 inithscxisac(cs, 2);
677 spin_unlock_irqrestore(&cs->lock, flags);
678 return(0);
679 case CARD_TEST:
680 if ((cs->subtyp == ELSA_PCMCIA) ||
681 (cs->subtyp == ELSA_PCMCIA_IPAC) ||
682 (cs->subtyp == ELSA_QS1000PCI)) {
683 return(0);
684 } else if (cs->subtyp == ELSA_QS3000PCI) {
685 ret = 0;
686 } else {
687 spin_lock_irqsave(&cs->lock, flags);
688 cs->hw.elsa.counter = 0;
689 cs->hw.elsa.ctrl_reg |= ELSA_ENA_TIMER_INT;
690 cs->hw.elsa.status |= ELSA_TIMER_AKTIV;
691 byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg);
692 byteout(cs->hw.elsa.timer, 0);
693 spin_unlock_irqrestore(&cs->lock, flags);
694 msleep(110);
695 spin_lock_irqsave(&cs->lock, flags);
696 cs->hw.elsa.ctrl_reg &= ~ELSA_ENA_TIMER_INT;
697 byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg);
698 cs->hw.elsa.status &= ~ELSA_TIMER_AKTIV;
699 spin_unlock_irqrestore(&cs->lock, flags);
700 printk(KERN_INFO "Elsa: %d timer tics in 110 msek\n",
701 cs->hw.elsa.counter);
702 if ((cs->hw.elsa.counter > 10) &&
703 (cs->hw.elsa.counter < 16)) {
704 printk(KERN_INFO "Elsa: timer and irq OK\n");
705 ret = 0;
706 } else {
707 printk(KERN_WARNING
708 "Elsa: timer tic problem (%d/12) maybe an IRQ(%d) conflict\n",
709 cs->hw.elsa.counter, cs->irq);
710 ret = 1;
711 }
712 }
713#if ARCOFI_USE
714 if (check_arcofi(cs)) {
715 init_modem(cs);
716 }
717#endif
718 elsa_led_handler(cs);
719 return(ret);
720 case (MDL_REMOVE | REQUEST):
721 cs->hw.elsa.status &= 0;
722 break;
723 case (MDL_ASSIGN | REQUEST):
724 cs->hw.elsa.status |= ELSA_ASSIGN;
725 break;
726 case MDL_INFO_SETUP:
727 if ((long) arg)
728 cs->hw.elsa.status |= 0x0200;
729 else
730 cs->hw.elsa.status |= 0x0100;
731 break;
732 case MDL_INFO_CONN:
733 if ((long) arg)
734 cs->hw.elsa.status |= 0x2000;
735 else
736 cs->hw.elsa.status |= 0x1000;
737 break;
738 case MDL_INFO_REL:
739 if ((long) arg) {
740 cs->hw.elsa.status &= ~0x2000;
741 cs->hw.elsa.status &= ~0x0200;
742 } else {
743 cs->hw.elsa.status &= ~0x1000;
744 cs->hw.elsa.status &= ~0x0100;
745 }
746 break;
747#if ARCOFI_USE
748 case CARD_AUX_IND:
749 if (cs->hw.elsa.MFlag) {
750 int len;
751 u_char *msg;
752
753 if (!arg)
754 return(0);
755 msg = arg;
756 len = *msg;
757 msg++;
758 modem_write_cmd(cs, msg, len);
759 }
760 break;
761#endif
762 }
763 if (cs->typ == ISDN_CTYPE_ELSA) {
764 int pwr = bytein(cs->hw.elsa.ale);
765 if (pwr & 0x08)
766 cs->hw.elsa.status |= ELSA_BAD_PWR;
767 else
768 cs->hw.elsa.status &= ~ELSA_BAD_PWR;
769 }
770 elsa_led_handler(cs);
771 return(ret);
772}
773
774static unsigned char
775probe_elsa_adr(unsigned int adr, int typ)
776{
777 int i, in1, in2, p16_1 = 0, p16_2 = 0, p8_1 = 0, p8_2 = 0, pc_1 = 0,
778 pc_2 = 0, pfp_1 = 0, pfp_2 = 0;
779
780 /* In case of the elsa pcmcia card, this region is in use,
781 reserved for us by the card manager. So we do not check it
782 here, it would fail. */
783 if (typ != ISDN_CTYPE_ELSA_PCMCIA) {
784 if (request_region(adr, 8, "elsa card")) {
785 release_region(adr, 8);
786 } else {
787 printk(KERN_WARNING
788 "Elsa: Probing Port 0x%x: already in use\n", adr);
789 return (0);
790 }
791 }
792 for (i = 0; i < 16; i++) {
793 in1 = inb(adr + ELSA_CONFIG); /* 'toggelt' bei */
794 in2 = inb(adr + ELSA_CONFIG); /* jedem Zugriff */
795 p16_1 += 0x04 & in1;
796 p16_2 += 0x04 & in2;
797 p8_1 += 0x02 & in1;
798 p8_2 += 0x02 & in2;
799 pc_1 += 0x01 & in1;
800 pc_2 += 0x01 & in2;
801 pfp_1 += 0x40 & in1;
802 pfp_2 += 0x40 & in2;
803 }
804 printk(KERN_INFO "Elsa: Probing IO 0x%x", adr);
805 if (65 == ++p16_1 * ++p16_2) {
806 printk(" PCC-16/PCF found\n");
807 return (ELSA_PCC16);
808 } else if (1025 == ++pfp_1 * ++pfp_2) {
809 printk(" PCF-Pro found\n");
810 return (ELSA_PCFPRO);
811 } else if (33 == ++p8_1 * ++p8_2) {
812 printk(" PCC8 found\n");
813 return (ELSA_PCC8);
814 } else if (17 == ++pc_1 * ++pc_2) {
815 printk(" PC found\n");
816 return (ELSA_PC);
817 } else {
818 printk(" failed\n");
819 return (0);
820 }
821}
822
823static unsigned int
824probe_elsa(struct IsdnCardState *cs)
825{
826 int i;
827 unsigned int CARD_portlist[] =
828 {0x160, 0x170, 0x260, 0x360, 0};
829
830 for (i = 0; CARD_portlist[i]; i++) {
831 if ((cs->subtyp = probe_elsa_adr(CARD_portlist[i], cs->typ)))
832 break;
833 }
834 return (CARD_portlist[i]);
835}
836
837static struct pci_dev *dev_qs1000 __devinitdata = NULL;
838static struct pci_dev *dev_qs3000 __devinitdata = NULL;
839
840#ifdef __ISAPNP__
841static struct isapnp_device_id elsa_ids[] __devinitdata = {
842 { ISAPNP_VENDOR('E', 'L', 'S'), ISAPNP_FUNCTION(0x0133),
843 ISAPNP_VENDOR('E', 'L', 'S'), ISAPNP_FUNCTION(0x0133),
844 (unsigned long) "Elsa QS1000" },
845 { ISAPNP_VENDOR('E', 'L', 'S'), ISAPNP_FUNCTION(0x0134),
846 ISAPNP_VENDOR('E', 'L', 'S'), ISAPNP_FUNCTION(0x0134),
847 (unsigned long) "Elsa QS3000" },
848 { 0, }
849};
850
851static struct isapnp_device_id *ipid __devinitdata = &elsa_ids[0];
852static struct pnp_card *pnp_c __devinitdata = NULL;
853#endif
854
855int __devinit
856setup_elsa(struct IsdnCard *card)
857{
858 int bytecnt;
859 u_char val;
860 struct IsdnCardState *cs = card->cs;
861 char tmp[64];
862
863 strcpy(tmp, Elsa_revision);
864 printk(KERN_INFO "HiSax: Elsa driver Rev. %s\n", HiSax_getrev(tmp));
865 cs->hw.elsa.ctrl_reg = 0;
866 cs->hw.elsa.status = 0;
867 cs->hw.elsa.MFlag = 0;
868 cs->subtyp = 0;
869 if (cs->typ == ISDN_CTYPE_ELSA) {
870 cs->hw.elsa.base = card->para[0];
871 printk(KERN_INFO "Elsa: Microlink IO probing\n");
872 if (cs->hw.elsa.base) {
873 if (!(cs->subtyp = probe_elsa_adr(cs->hw.elsa.base,
874 cs->typ))) {
875 printk(KERN_WARNING
876 "Elsa: no Elsa Microlink at %#lx\n",
877 cs->hw.elsa.base);
878 return (0);
879 }
880 } else
881 cs->hw.elsa.base = probe_elsa(cs);
882 if (cs->hw.elsa.base) {
883 cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG;
884 cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL;
885 cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE;
886 cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC;
887 cs->hw.elsa.itac = cs->hw.elsa.base + ELSA_ITAC;
888 cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
889 cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ;
890 cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER;
891 val = bytein(cs->hw.elsa.cfg);
892 if (cs->subtyp == ELSA_PC) {
893 const u_char CARD_IrqTab[8] =
894 {7, 3, 5, 9, 0, 0, 0, 0};
895 cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PC) >> 2];
896 } else if (cs->subtyp == ELSA_PCC8) {
897 const u_char CARD_IrqTab[8] =
898 {7, 3, 5, 9, 0, 0, 0, 0};
899 cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PCC8) >> 4];
900 } else {
901 const u_char CARD_IrqTab[8] =
902 {15, 10, 15, 3, 11, 5, 11, 9};
903 cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX) >> 3];
904 }
905 val = bytein(cs->hw.elsa.ale) & ELSA_HW_RELEASE;
906 if (val < 3)
907 val |= 8;
908 val += 'A' - 3;
909 if (val == 'B' || val == 'C')
910 val ^= 1;
911 if ((cs->subtyp == ELSA_PCFPRO) && (val = 'G'))
912 val = 'C';
913 printk(KERN_INFO
914 "Elsa: %s found at %#lx Rev.:%c IRQ %d\n",
915 Elsa_Types[cs->subtyp],
916 cs->hw.elsa.base,
917 val, cs->irq);
918 val = bytein(cs->hw.elsa.ale) & ELSA_S0_POWER_BAD;
919 if (val) {
920 printk(KERN_WARNING
921 "Elsa: Microlink S0 bus power bad\n");
922 cs->hw.elsa.status |= ELSA_BAD_PWR;
923 }
924 } else {
925 printk(KERN_WARNING
926 "No Elsa Microlink found\n");
927 return (0);
928 }
929 } else if (cs->typ == ISDN_CTYPE_ELSA_PNP) {
930#ifdef __ISAPNP__
931 if (!card->para[1] && isapnp_present()) {
932 struct pnp_dev *pnp_d;
933 while(ipid->card_vendor) {
934 if ((pnp_c = pnp_find_card(ipid->card_vendor,
935 ipid->card_device, pnp_c))) {
936 pnp_d = NULL;
937 if ((pnp_d = pnp_find_dev(pnp_c,
938 ipid->vendor, ipid->function, pnp_d))) {
939 int err;
940
941 printk(KERN_INFO "HiSax: %s detected\n",
942 (char *)ipid->driver_data);
943 pnp_disable_dev(pnp_d);
944 err = pnp_activate_dev(pnp_d);
945 if (err<0) {
946 printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
947 __FUNCTION__, err);
948 return(0);
949 }
950 card->para[1] = pnp_port_start(pnp_d, 0);
951 card->para[0] = pnp_irq(pnp_d, 0);
952
953 if (!card->para[0] || !card->para[1]) {
954 printk(KERN_ERR "Elsa PnP:some resources are missing %ld/%lx\n",
955 card->para[0], card->para[1]);
956 pnp_disable_dev(pnp_d);
957 return(0);
958 }
959 if (ipid->function == ISAPNP_FUNCTION(0x133))
960 cs->subtyp = ELSA_QS1000;
961 else
962 cs->subtyp = ELSA_QS3000;
963 break;
964 } else {
965 printk(KERN_ERR "Elsa PnP: PnP error card found, no device\n");
966 return(0);
967 }
968 }
969 ipid++;
970 pnp_c=NULL;
971 }
972 if (!ipid->card_vendor) {
973 printk(KERN_INFO "Elsa PnP: no ISAPnP card found\n");
974 return(0);
975 }
976 }
977#endif
978 if (card->para[1] && card->para[0]) {
979 cs->hw.elsa.base = card->para[1];
980 cs->irq = card->para[0];
981 if (!cs->subtyp)
982 cs->subtyp = ELSA_QS1000;
983 } else {
984 printk(KERN_ERR "Elsa PnP: no parameter\n");
985 }
986 cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG;
987 cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE;
988 cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC;
989 cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
990 cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ;
991 cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER;
992 cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL;
993 printk(KERN_INFO
994 "Elsa: %s defined at %#lx IRQ %d\n",
995 Elsa_Types[cs->subtyp],
996 cs->hw.elsa.base,
997 cs->irq);
998 } else if (cs->typ == ISDN_CTYPE_ELSA_PCMCIA) {
999 cs->hw.elsa.base = card->para[1];
1000 cs->irq = card->para[0];
1001 val = readreg(cs->hw.elsa.base + 0, cs->hw.elsa.base + 2, IPAC_ID);
1002 if ((val == 1) || (val == 2)) { /* IPAC version 1.1/1.2 */
1003 cs->subtyp = ELSA_PCMCIA_IPAC;
1004 cs->hw.elsa.ale = cs->hw.elsa.base + 0;
1005 cs->hw.elsa.isac = cs->hw.elsa.base + 2;
1006 cs->hw.elsa.hscx = cs->hw.elsa.base + 2;
1007 test_and_set_bit(HW_IPAC, &cs->HW_Flags);
1008 } else {
1009 cs->subtyp = ELSA_PCMCIA;
1010 cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE_PCM;
1011 cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC_PCM;
1012 cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
1013 }
1014 cs->hw.elsa.timer = 0;
1015 cs->hw.elsa.trig = 0;
1016 cs->hw.elsa.ctrl = 0;
1017 cs->irq_flags |= SA_SHIRQ;
1018 printk(KERN_INFO
1019 "Elsa: %s defined at %#lx IRQ %d\n",
1020 Elsa_Types[cs->subtyp],
1021 cs->hw.elsa.base,
1022 cs->irq);
1023 } else if (cs->typ == ISDN_CTYPE_ELSA_PCI) {
1024#ifdef CONFIG_PCI
1025 cs->subtyp = 0;
1026 if ((dev_qs1000 = pci_find_device(PCI_VENDOR_ID_ELSA,
1027 PCI_DEVICE_ID_ELSA_MICROLINK, dev_qs1000))) {
1028 if (pci_enable_device(dev_qs1000))
1029 return(0);
1030 cs->subtyp = ELSA_QS1000PCI;
1031 cs->irq = dev_qs1000->irq;
1032 cs->hw.elsa.cfg = pci_resource_start(dev_qs1000, 1);
1033 cs->hw.elsa.base = pci_resource_start(dev_qs1000, 3);
1034 } else if ((dev_qs3000 = pci_find_device(PCI_VENDOR_ID_ELSA,
1035 PCI_DEVICE_ID_ELSA_QS3000, dev_qs3000))) {
1036 if (pci_enable_device(dev_qs3000))
1037 return(0);
1038 cs->subtyp = ELSA_QS3000PCI;
1039 cs->irq = dev_qs3000->irq;
1040 cs->hw.elsa.cfg = pci_resource_start(dev_qs3000, 1);
1041 cs->hw.elsa.base = pci_resource_start(dev_qs3000, 3);
1042 } else {
1043 printk(KERN_WARNING "Elsa: No PCI card found\n");
1044 return(0);
1045 }
1046 if (!cs->irq) {
1047 printk(KERN_WARNING "Elsa: No IRQ for PCI card found\n");
1048 return(0);
1049 }
1050
1051 if (!(cs->hw.elsa.base && cs->hw.elsa.cfg)) {
1052 printk(KERN_WARNING "Elsa: No IO-Adr for PCI card found\n");
1053 return(0);
1054 }
1055 if ((cs->hw.elsa.cfg & 0xff) || (cs->hw.elsa.base & 0xf)) {
1056 printk(KERN_WARNING "Elsa: You may have a wrong PCI bios\n");
1057 printk(KERN_WARNING "Elsa: If your system hangs now, read\n");
1058 printk(KERN_WARNING "Elsa: Documentation/isdn/README.HiSax\n");
1059 }
1060 cs->hw.elsa.ale = cs->hw.elsa.base;
1061 cs->hw.elsa.isac = cs->hw.elsa.base +1;
1062 cs->hw.elsa.hscx = cs->hw.elsa.base +1;
1063 test_and_set_bit(HW_IPAC, &cs->HW_Flags);
1064 cs->hw.elsa.timer = 0;
1065 cs->hw.elsa.trig = 0;
1066 cs->irq_flags |= SA_SHIRQ;
1067 printk(KERN_INFO
1068 "Elsa: %s defined at %#lx/0x%x IRQ %d\n",
1069 Elsa_Types[cs->subtyp],
1070 cs->hw.elsa.base,
1071 cs->hw.elsa.cfg,
1072 cs->irq);
1073#else
1074 printk(KERN_WARNING "Elsa: Elsa PCI and NO_PCI_BIOS\n");
1075 printk(KERN_WARNING "Elsa: unable to config Elsa PCI\n");
1076 return (0);
1077#endif /* CONFIG_PCI */
1078 } else
1079 return (0);
1080
1081 switch (cs->subtyp) {
1082 case ELSA_PC:
1083 case ELSA_PCC8:
1084 case ELSA_PCC16:
1085 case ELSA_QS1000:
1086 case ELSA_PCMCIA:
1087 case ELSA_PCMCIA_IPAC:
1088 bytecnt = 8;
1089 break;
1090 case ELSA_PCFPRO:
1091 case ELSA_PCF:
1092 case ELSA_QS3000:
1093 case ELSA_QS3000PCI:
1094 bytecnt = 16;
1095 break;
1096 case ELSA_QS1000PCI:
1097 bytecnt = 2;
1098 break;
1099 default:
1100 printk(KERN_WARNING
1101 "Unknown ELSA subtype %d\n", cs->subtyp);
1102 return (0);
1103 }
1104 /* In case of the elsa pcmcia card, this region is in use,
1105 reserved for us by the card manager. So we do not check it
1106 here, it would fail. */
1107 if (cs->typ != ISDN_CTYPE_ELSA_PCMCIA && !request_region(cs->hw.elsa.base, bytecnt, "elsa isdn")) {
1108 printk(KERN_WARNING
1109 "HiSax: %s config port %#lx-%#lx already in use\n",
1110 CardType[card->typ],
1111 cs->hw.elsa.base,
1112 cs->hw.elsa.base + bytecnt);
1113 return (0);
1114 }
1115 if ((cs->subtyp == ELSA_QS1000PCI) || (cs->subtyp == ELSA_QS3000PCI)) {
1116 if (!request_region(cs->hw.elsa.cfg, 0x80, "elsa isdn pci")) {
1117 printk(KERN_WARNING
1118 "HiSax: %s pci port %x-%x already in use\n",
1119 CardType[card->typ],
1120 cs->hw.elsa.cfg,
1121 cs->hw.elsa.cfg + 0x80);
1122 release_region(cs->hw.elsa.base, bytecnt);
1123 return (0);
1124 }
1125 }
1126#if ARCOFI_USE
1127 init_arcofi(cs);
1128#endif
1129 setup_isac(cs);
1130 cs->hw.elsa.tl.function = (void *) elsa_led_handler;
1131 cs->hw.elsa.tl.data = (long) cs;
1132 init_timer(&cs->hw.elsa.tl);
1133 /* Teste Timer */
1134 if (cs->hw.elsa.timer) {
1135 byteout(cs->hw.elsa.trig, 0xff);
1136 byteout(cs->hw.elsa.timer, 0);
1137 if (!TimerRun(cs)) {
1138 byteout(cs->hw.elsa.timer, 0); /* 2. Versuch */
1139 if (!TimerRun(cs)) {
1140 printk(KERN_WARNING
1141 "Elsa: timer do not start\n");
1142 release_io_elsa(cs);
1143 return (0);
1144 }
1145 }
1146 HZDELAY((HZ/100) + 1); /* wait >=10 ms */
1147 if (TimerRun(cs)) {
1148 printk(KERN_WARNING "Elsa: timer do not run down\n");
1149 release_io_elsa(cs);
1150 return (0);
1151 }
1152 printk(KERN_INFO "Elsa: timer OK; resetting card\n");
1153 }
1154 cs->BC_Read_Reg = &ReadHSCX;
1155 cs->BC_Write_Reg = &WriteHSCX;
1156 cs->BC_Send_Data = &hscx_fill_fifo;
1157 cs->cardmsg = &Elsa_card_msg;
1158 if ((cs->subtyp == ELSA_QS1000PCI) || (cs->subtyp == ELSA_QS3000PCI) || (cs->subtyp == ELSA_PCMCIA_IPAC)) {
1159 cs->readisac = &ReadISAC_IPAC;
1160 cs->writeisac = &WriteISAC_IPAC;
1161 cs->readisacfifo = &ReadISACfifo_IPAC;
1162 cs->writeisacfifo = &WriteISACfifo_IPAC;
1163 cs->irq_func = &elsa_interrupt_ipac;
1164 val = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ID);
1165 printk(KERN_INFO "Elsa: IPAC version %x\n", val);
1166 } else {
1167 cs->readisac = &ReadISAC;
1168 cs->writeisac = &WriteISAC;
1169 cs->readisacfifo = &ReadISACfifo;
1170 cs->writeisacfifo = &WriteISACfifo;
1171 cs->irq_func = &elsa_interrupt;
1172 ISACVersion(cs, "Elsa:");
1173 if (HscxVersion(cs, "Elsa:")) {
1174 printk(KERN_WARNING
1175 "Elsa: wrong HSCX versions check IO address\n");
1176 release_io_elsa(cs);
1177 return (0);
1178 }
1179 }
1180 if (cs->subtyp == ELSA_PC) {
1181 val = readitac(cs, ITAC_SYS);
1182 printk(KERN_INFO "Elsa: ITAC version %s\n", ITACVer[val & 7]);
1183 writeitac(cs, ITAC_ISEN, 0);
1184 writeitac(cs, ITAC_RFIE, 0);
1185 writeitac(cs, ITAC_XFIE, 0);
1186 writeitac(cs, ITAC_SCIE, 0);
1187 writeitac(cs, ITAC_STIE, 0);
1188 }
1189 return (1);
1190}
diff --git a/drivers/isdn/hisax/elsa_cs.c b/drivers/isdn/hisax/elsa_cs.c
new file mode 100644
index 000000000000..bfc013225f46
--- /dev/null
+++ b/drivers/isdn/hisax/elsa_cs.c
@@ -0,0 +1,532 @@
1/*======================================================================
2
3 An elsa_cs PCMCIA client driver
4
5 This driver is for the Elsa PCM ISDN Cards, i.e. the MicroLink
6
7
8 The contents of this file are subject to the Mozilla Public
9 License Version 1.1 (the "License"); you may not use this file
10 except in compliance with the License. You may obtain a copy of
11 the License at http://www.mozilla.org/MPL/
12
13 Software distributed under the License is distributed on an "AS
14 IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
15 implied. See the License for the specific language governing
16 rights and limitations under the License.
17
18 The initial developer of the original code is David A. Hinds
19 <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
20 are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
21
22 Modifications from dummy_cs.c are Copyright (C) 1999-2001 Klaus
23 Lichtenwalder <Lichtenwalder@ACM.org>. All Rights Reserved.
24
25 Alternatively, the contents of this file may be used under the
26 terms of the GNU General Public License version 2 (the "GPL"), in
27 which case the provisions of the GPL are applicable instead of the
28 above. If you wish to allow the use of your version of this file
29 only under the terms of the GPL and not to allow others to use
30 your version of this file under the MPL, indicate your decision
31 by deleting the provisions above and replace them with the notice
32 and other provisions required by the GPL. If you do not delete
33 the provisions above, a recipient may use your version of this
34 file under either the MPL or the GPL.
35
36======================================================================*/
37
38#include <linux/module.h>
39#include <linux/kernel.h>
40#include <linux/init.h>
41#include <linux/sched.h>
42#include <linux/ptrace.h>
43#include <linux/slab.h>
44#include <linux/string.h>
45#include <linux/timer.h>
46#include <linux/ioport.h>
47#include <asm/io.h>
48#include <asm/system.h>
49
50#include <pcmcia/version.h>
51#include <pcmcia/cs_types.h>
52#include <pcmcia/cs.h>
53#include <pcmcia/cistpl.h>
54#include <pcmcia/cisreg.h>
55#include <pcmcia/ds.h>
56#include "hisax_cfg.h"
57
58MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for Elsa PCM cards");
59MODULE_AUTHOR("Klaus Lichtenwalder");
60MODULE_LICENSE("Dual MPL/GPL");
61
62/*
63 All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If
64 you do not define PCMCIA_DEBUG at all, all the debug code will be
65 left out. If you compile with PCMCIA_DEBUG=0, the debug code will
66 be present but disabled -- but it can then be enabled for specific
67 modules at load time with a 'pc_debug=#' option to insmod.
68*/
69
70#ifdef PCMCIA_DEBUG
71static int pc_debug = PCMCIA_DEBUG;
72module_param(pc_debug, int, 0);
73#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args);
74static char *version =
75"elsa_cs.c $Revision: 1.2.2.4 $ $Date: 2004/01/25 15:07:06 $ (K.Lichtenwalder)";
76#else
77#define DEBUG(n, args...)
78#endif
79
80/*====================================================================*/
81
82/* Parameters that can be set with 'insmod' */
83
84static int protocol = 2; /* EURO-ISDN Default */
85module_param(protocol, int, 0);
86
87/*====================================================================*/
88
89/*
90 The event() function is this driver's Card Services event handler.
91 It will be called by Card Services when an appropriate card status
92 event is received. The config() and release() entry points are
93 used to configure or release a socket, in response to card insertion
94 and ejection events. They are invoked from the elsa_cs event
95 handler.
96*/
97
98static void elsa_cs_config(dev_link_t *link);
99static void elsa_cs_release(dev_link_t *link);
100static int elsa_cs_event(event_t event, int priority,
101 event_callback_args_t *args);
102
103/*
104 The attach() and detach() entry points are used to create and destroy
105 "instances" of the driver, where each instance represents everything
106 needed to manage one actual PCMCIA card.
107*/
108
109static dev_link_t *elsa_cs_attach(void);
110static void elsa_cs_detach(dev_link_t *);
111
112/*
113 The dev_info variable is the "key" that is used to match up this
114 device driver with appropriate cards, through the card configuration
115 database.
116*/
117
118static dev_info_t dev_info = "elsa_cs";
119
120/*
121 A linked list of "instances" of the elsa_cs device. Each actual
122 PCMCIA card corresponds to one device instance, and is described
123 by one dev_link_t structure (defined in ds.h).
124
125 You may not want to use a linked list for this -- for example, the
126 memory card driver uses an array of dev_link_t pointers, where minor
127 device numbers are used to derive the corresponding array index.
128*/
129
130static dev_link_t *dev_list = NULL;
131
132/*
133 A dev_link_t structure has fields for most things that are needed
134 to keep track of a socket, but there will usually be some device
135 specific information that also needs to be kept track of. The
136 'priv' pointer in a dev_link_t structure can be used to point to
137 a device-specific private data structure, like this.
138
139 To simplify the data structure handling, we actually include the
140 dev_link_t structure in the device's private data structure.
141
142 A driver needs to provide a dev_node_t structure for each device
143 on a card. In some cases, there is only one device per card (for
144 example, ethernet cards, modems). In other cases, there may be
145 many actual or logical devices (SCSI adapters, memory cards with
146 multiple partitions). The dev_node_t structures need to be kept
147 in a linked list starting at the 'dev' field of a dev_link_t
148 structure. We allocate them in the card's private data structure,
149 because they generally shouldn't be allocated dynamically.
150 In this case, we also provide a flag to indicate if a device is
151 "stopped" due to a power management event, or card ejection. The
152 device IO routines can use a flag like this to throttle IO to a
153 card that is not ready to accept it.
154*/
155
156typedef struct local_info_t {
157 dev_link_t link;
158 dev_node_t node;
159 int busy;
160 int cardnr;
161} local_info_t;
162
163/*======================================================================
164
165 elsa_cs_attach() creates an "instance" of the driver, allocatingx
166 local data structures for one device. The device is registered
167 with Card Services.
168
169 The dev_link structure is initialized, but we don't actually
170 configure the card at this point -- we wait until we receive a
171 card insertion event.
172
173======================================================================*/
174
175static dev_link_t *elsa_cs_attach(void)
176{
177 client_reg_t client_reg;
178 dev_link_t *link;
179 local_info_t *local;
180 int ret;
181
182 DEBUG(0, "elsa_cs_attach()\n");
183
184 /* Allocate space for private device-specific data */
185 local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
186 if (!local) return NULL;
187 memset(local, 0, sizeof(local_info_t));
188 local->cardnr = -1;
189 link = &local->link; link->priv = local;
190
191 /* Interrupt setup */
192 link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED;
193 link->irq.IRQInfo1 = IRQ_LEVEL_ID|IRQ_SHARE_ID;
194 link->irq.Handler = NULL;
195
196 /*
197 General socket configuration defaults can go here. In this
198 client, we assume very little, and rely on the CIS for almost
199 everything. In most clients, many details (i.e., number, sizes,
200 and attributes of IO windows) are fixed by the nature of the
201 device, and can be hard-wired here.
202 */
203 link->io.NumPorts1 = 8;
204 link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
205 link->io.IOAddrLines = 3;
206
207 link->conf.Attributes = CONF_ENABLE_IRQ;
208 link->conf.Vcc = 50;
209 link->conf.IntType = INT_MEMORY_AND_IO;
210
211 /* Register with Card Services */
212 link->next = dev_list;
213 dev_list = link;
214 client_reg.dev_info = &dev_info;
215 client_reg.EventMask =
216 CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
217 CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
218 CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
219 client_reg.event_handler = &elsa_cs_event;
220 client_reg.Version = 0x0210;
221 client_reg.event_callback_args.client_data = link;
222 ret = pcmcia_register_client(&link->handle, &client_reg);
223 if (ret != CS_SUCCESS) {
224 cs_error(link->handle, RegisterClient, ret);
225 elsa_cs_detach(link);
226 return NULL;
227 }
228
229 return link;
230} /* elsa_cs_attach */
231
232/*======================================================================
233
234 This deletes a driver "instance". The device is de-registered
235 with Card Services. If it has been released, all local data
236 structures are freed. Otherwise, the structures will be freed
237 when the device is released.
238
239======================================================================*/
240
241static void elsa_cs_detach(dev_link_t *link)
242{
243 dev_link_t **linkp;
244 local_info_t *info = link->priv;
245 int ret;
246
247 DEBUG(0, "elsa_cs_detach(0x%p)\n", link);
248
249 /* Locate device structure */
250 for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
251 if (*linkp == link) break;
252 if (*linkp == NULL)
253 return;
254
255 if (link->state & DEV_CONFIG)
256 elsa_cs_release(link);
257
258 /* Break the link with Card Services */
259 if (link->handle) {
260 ret = pcmcia_deregister_client(link->handle);
261 if (ret != CS_SUCCESS)
262 cs_error(link->handle, DeregisterClient, ret);
263 }
264
265 /* Unlink device structure and free it */
266 *linkp = link->next;
267 kfree(info);
268
269} /* elsa_cs_detach */
270
271/*======================================================================
272
273 elsa_cs_config() is scheduled to run after a CARD_INSERTION event
274 is received, to configure the PCMCIA socket, and to make the
275 device available to the system.
276
277======================================================================*/
278static int get_tuple(client_handle_t handle, tuple_t *tuple,
279 cisparse_t *parse)
280{
281 int i = pcmcia_get_tuple_data(handle, tuple);
282 if (i != CS_SUCCESS) return i;
283 return pcmcia_parse_tuple(handle, tuple, parse);
284}
285
286static int first_tuple(client_handle_t handle, tuple_t *tuple,
287 cisparse_t *parse)
288{
289 int i = pcmcia_get_first_tuple(handle, tuple);
290 if (i != CS_SUCCESS) return i;
291 return get_tuple(handle, tuple, parse);
292}
293
294static int next_tuple(client_handle_t handle, tuple_t *tuple,
295 cisparse_t *parse)
296{
297 int i = pcmcia_get_next_tuple(handle, tuple);
298 if (i != CS_SUCCESS) return i;
299 return get_tuple(handle, tuple, parse);
300}
301
302static void elsa_cs_config(dev_link_t *link)
303{
304 client_handle_t handle;
305 tuple_t tuple;
306 cisparse_t parse;
307 local_info_t *dev;
308 int i, j, last_fn;
309 u_short buf[128];
310 cistpl_cftable_entry_t *cf = &parse.cftable_entry;
311 IsdnCard_t icard;
312
313 DEBUG(0, "elsa_config(0x%p)\n", link);
314 handle = link->handle;
315 dev = link->priv;
316
317 /*
318 This reads the card's CONFIG tuple to find its configuration
319 registers.
320 */
321 tuple.DesiredTuple = CISTPL_CONFIG;
322 tuple.TupleData = (cisdata_t *)buf;
323 tuple.TupleDataMax = 255;
324 tuple.TupleOffset = 0;
325 tuple.Attributes = 0;
326 i = first_tuple(handle, &tuple, &parse);
327 if (i != CS_SUCCESS) {
328 last_fn = ParseTuple;
329 goto cs_failed;
330 }
331 link->conf.ConfigBase = parse.config.base;
332 link->conf.Present = parse.config.rmask[0];
333
334 /* Configure card */
335 link->state |= DEV_CONFIG;
336
337 tuple.TupleData = (cisdata_t *)buf;
338 tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
339 tuple.Attributes = 0;
340 tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
341 i = first_tuple(handle, &tuple, &parse);
342 while (i == CS_SUCCESS) {
343 if ( (cf->io.nwin > 0) && cf->io.win[0].base) {
344 printk(KERN_INFO "(elsa_cs: looks like the 96 model)\n");
345 link->conf.ConfigIndex = cf->index;
346 link->io.BasePort1 = cf->io.win[0].base;
347 i = pcmcia_request_io(link->handle, &link->io);
348 if (i == CS_SUCCESS) break;
349 } else {
350 printk(KERN_INFO "(elsa_cs: looks like the 97 model)\n");
351 link->conf.ConfigIndex = cf->index;
352 for (i = 0, j = 0x2f0; j > 0x100; j -= 0x10) {
353 link->io.BasePort1 = j;
354 i = pcmcia_request_io(link->handle, &link->io);
355 if (i == CS_SUCCESS) break;
356 }
357 break;
358 }
359 i = next_tuple(handle, &tuple, &parse);
360 }
361
362 if (i != CS_SUCCESS) {
363 last_fn = RequestIO;
364 goto cs_failed;
365 }
366
367 i = pcmcia_request_irq(link->handle, &link->irq);
368 if (i != CS_SUCCESS) {
369 link->irq.AssignedIRQ = 0;
370 last_fn = RequestIRQ;
371 goto cs_failed;
372 }
373
374 i = pcmcia_request_configuration(link->handle, &link->conf);
375 if (i != CS_SUCCESS) {
376 last_fn = RequestConfiguration;
377 goto cs_failed;
378 }
379
380 /* At this point, the dev_node_t structure(s) should be
381 initialized and arranged in a linked list at link->dev. *//* */
382 sprintf(dev->node.dev_name, "elsa");
383 dev->node.major = dev->node.minor = 0x0;
384
385 link->dev = &dev->node;
386
387 /* Finally, report what we've done */
388 printk(KERN_INFO "%s: index 0x%02x: Vcc %d.%d",
389 dev->node.dev_name, link->conf.ConfigIndex,
390 link->conf.Vcc/10, link->conf.Vcc%10);
391 if (link->conf.Vpp1)
392 printk(", Vpp %d.%d", link->conf.Vpp1/10, link->conf.Vpp1%10);
393 if (link->conf.Attributes & CONF_ENABLE_IRQ)
394 printk(", irq %d", link->irq.AssignedIRQ);
395 if (link->io.NumPorts1)
396 printk(", io 0x%04x-0x%04x", link->io.BasePort1,
397 link->io.BasePort1+link->io.NumPorts1-1);
398 if (link->io.NumPorts2)
399 printk(" & 0x%04x-0x%04x", link->io.BasePort2,
400 link->io.BasePort2+link->io.NumPorts2-1);
401 printk("\n");
402
403 link->state &= ~DEV_CONFIG_PENDING;
404
405 icard.para[0] = link->irq.AssignedIRQ;
406 icard.para[1] = link->io.BasePort1;
407 icard.protocol = protocol;
408 icard.typ = ISDN_CTYPE_ELSA_PCMCIA;
409
410 i = hisax_init_pcmcia(link, &(((local_info_t*)link->priv)->busy), &icard);
411 if (i < 0) {
412 printk(KERN_ERR "elsa_cs: failed to initialize Elsa PCMCIA %d at i/o %#x\n",
413 i, link->io.BasePort1);
414 elsa_cs_release(link);
415 } else
416 ((local_info_t*)link->priv)->cardnr = i;
417
418 return;
419cs_failed:
420 cs_error(link->handle, last_fn, i);
421 elsa_cs_release(link);
422} /* elsa_cs_config */
423
424/*======================================================================
425
426 After a card is removed, elsa_cs_release() will unregister the net
427 device, and release the PCMCIA configuration. If the device is
428 still open, this will be postponed until it is closed.
429
430======================================================================*/
431
432static void elsa_cs_release(dev_link_t *link)
433{
434 local_info_t *local = link->priv;
435
436 DEBUG(0, "elsa_cs_release(0x%p)\n", link);
437
438 if (local) {
439 if (local->cardnr >= 0) {
440 /* no unregister function with hisax */
441 HiSax_closecard(local->cardnr);
442 }
443 }
444 /* Unlink the device chain */
445 link->dev = NULL;
446
447 /* Don't bother checking to see if these succeed or not */
448 if (link->win)
449 pcmcia_release_window(link->win);
450 pcmcia_release_configuration(link->handle);
451 pcmcia_release_io(link->handle, &link->io);
452 pcmcia_release_irq(link->handle, &link->irq);
453 link->state &= ~DEV_CONFIG;
454} /* elsa_cs_release */
455
456/*======================================================================
457
458 The card status event handler. Mostly, this schedules other
459 stuff to run after an event is received. A CARD_REMOVAL event
460 also sets some flags to discourage the net drivers from trying
461 to talk to the card any more.
462
463 When a CARD_REMOVAL event is received, we immediately set a flag
464 to block future accesses to this device. All the functions that
465 actually access the device should check this flag to make sure
466 the card is still present.
467
468======================================================================*/
469
470static int elsa_cs_event(event_t event, int priority,
471 event_callback_args_t *args)
472{
473 dev_link_t *link = args->client_data;
474 local_info_t *dev = link->priv;
475
476 DEBUG(1, "elsa_cs_event(%d)\n", event);
477
478 switch (event) {
479 case CS_EVENT_CARD_REMOVAL:
480 link->state &= ~DEV_PRESENT;
481 if (link->state & DEV_CONFIG) {
482 ((local_info_t*)link->priv)->busy = 1;
483 elsa_cs_release(link);
484 }
485 break;
486 case CS_EVENT_CARD_INSERTION:
487 link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
488 elsa_cs_config(link);
489 break;
490 case CS_EVENT_PM_SUSPEND:
491 link->state |= DEV_SUSPEND;
492 /* Fall through... */
493 case CS_EVENT_RESET_PHYSICAL:
494 /* Mark the device as stopped, to block IO until later */
495 dev->busy = 1;
496 if (link->state & DEV_CONFIG)
497 pcmcia_release_configuration(link->handle);
498 break;
499 case CS_EVENT_PM_RESUME:
500 link->state &= ~DEV_SUSPEND;
501 /* Fall through... */
502 case CS_EVENT_CARD_RESET:
503 if (link->state & DEV_CONFIG)
504 pcmcia_request_configuration(link->handle, &link->conf);
505 dev->busy = 0;
506 break;
507 }
508 return 0;
509} /* elsa_cs_event */
510
511static struct pcmcia_driver elsa_cs_driver = {
512 .owner = THIS_MODULE,
513 .drv = {
514 .name = "elsa_cs",
515 },
516 .attach = elsa_cs_attach,
517 .detach = elsa_cs_detach,
518};
519
520static int __init init_elsa_cs(void)
521{
522 return pcmcia_register_driver(&elsa_cs_driver);
523}
524
525static void __exit exit_elsa_cs(void)
526{
527 pcmcia_unregister_driver(&elsa_cs_driver);
528 BUG_ON(dev_list != NULL);
529}
530
531module_init(init_elsa_cs);
532module_exit(exit_elsa_cs);
diff --git a/drivers/isdn/hisax/elsa_ser.c b/drivers/isdn/hisax/elsa_ser.c
new file mode 100644
index 000000000000..689c83395693
--- /dev/null
+++ b/drivers/isdn/hisax/elsa_ser.c
@@ -0,0 +1,657 @@
1/* $Id: elsa_ser.c,v 2.14.2.3 2004/02/11 13:21:33 keil Exp $
2 *
3 * stuff for the serial modem on ELSA cards
4 *
5 * This software may be used and distributed according to the terms
6 * of the GNU General Public License, incorporated herein by reference.
7 *
8 */
9
10#include <linux/config.h>
11#include <linux/serial.h>
12#include <linux/serial_reg.h>
13
14#define MAX_MODEM_BUF 256
15#define WAKEUP_CHARS (MAX_MODEM_BUF/2)
16#define RS_ISR_PASS_LIMIT 256
17#define BASE_BAUD ( 1843200 / 16 )
18
19//#define SERIAL_DEBUG_OPEN 1
20//#define SERIAL_DEBUG_INTR 1
21//#define SERIAL_DEBUG_FLOW 1
22#undef SERIAL_DEBUG_OPEN
23#undef SERIAL_DEBUG_INTR
24#undef SERIAL_DEBUG_FLOW
25#undef SERIAL_DEBUG_REG
26//#define SERIAL_DEBUG_REG 1
27
28#ifdef SERIAL_DEBUG_REG
29static u_char deb[32];
30const char *ModemIn[] = {"RBR","IER","IIR","LCR","MCR","LSR","MSR","SCR"};
31const char *ModemOut[] = {"THR","IER","FCR","LCR","MCR","LSR","MSR","SCR"};
32#endif
33
34static char *MInit_1 = "AT&F&C1E0&D2\r\0";
35static char *MInit_2 = "ATL2M1S64=13\r\0";
36static char *MInit_3 = "AT+FCLASS=0\r\0";
37static char *MInit_4 = "ATV1S2=128X1\r\0";
38static char *MInit_5 = "AT\\V8\\N3\r\0";
39static char *MInit_6 = "ATL0M0&G0%E1\r\0";
40static char *MInit_7 = "AT%L1%M0%C3\r\0";
41
42static char *MInit_speed28800 = "AT%G0%B28800\r\0";
43
44static char *MInit_dialout = "ATs7=60 x1 d\r\0";
45static char *MInit_dialin = "ATs7=60 x1 a\r\0";
46
47
48static inline unsigned int serial_in(struct IsdnCardState *cs, int offset)
49{
50#ifdef SERIAL_DEBUG_REG
51 u_int val = inb(cs->hw.elsa.base + 8 + offset);
52 debugl1(cs,"in %s %02x",ModemIn[offset], val);
53 return(val);
54#else
55 return inb(cs->hw.elsa.base + 8 + offset);
56#endif
57}
58
59static inline unsigned int serial_inp(struct IsdnCardState *cs, int offset)
60{
61#ifdef SERIAL_DEBUG_REG
62#ifdef CONFIG_SERIAL_NOPAUSE_IO
63 u_int val = inb(cs->hw.elsa.base + 8 + offset);
64 debugl1(cs,"inp %s %02x",ModemIn[offset], val);
65#else
66 u_int val = inb_p(cs->hw.elsa.base + 8 + offset);
67 debugl1(cs,"inP %s %02x",ModemIn[offset], val);
68#endif
69 return(val);
70#else
71#ifdef CONFIG_SERIAL_NOPAUSE_IO
72 return inb(cs->hw.elsa.base + 8 + offset);
73#else
74 return inb_p(cs->hw.elsa.base + 8 + offset);
75#endif
76#endif
77}
78
79static inline void serial_out(struct IsdnCardState *cs, int offset, int value)
80{
81#ifdef SERIAL_DEBUG_REG
82 debugl1(cs,"out %s %02x",ModemOut[offset], value);
83#endif
84 outb(value, cs->hw.elsa.base + 8 + offset);
85}
86
87static inline void serial_outp(struct IsdnCardState *cs, int offset,
88 int value)
89{
90#ifdef SERIAL_DEBUG_REG
91#ifdef CONFIG_SERIAL_NOPAUSE_IO
92 debugl1(cs,"outp %s %02x",ModemOut[offset], value);
93#else
94 debugl1(cs,"outP %s %02x",ModemOut[offset], value);
95#endif
96#endif
97#ifdef CONFIG_SERIAL_NOPAUSE_IO
98 outb(value, cs->hw.elsa.base + 8 + offset);
99#else
100 outb_p(value, cs->hw.elsa.base + 8 + offset);
101#endif
102}
103
104/*
105 * This routine is called to set the UART divisor registers to match
106 * the specified baud rate for a serial port.
107 */
108static void change_speed(struct IsdnCardState *cs, int baud)
109{
110 int quot = 0, baud_base;
111 unsigned cval, fcr = 0;
112 int bits;
113
114
115 /* byte size and parity */
116 cval = 0x03; bits = 10;
117 /* Determine divisor based on baud rate */
118 baud_base = BASE_BAUD;
119 quot = baud_base / baud;
120 /* If the quotient is ever zero, default to 9600 bps */
121 if (!quot)
122 quot = baud_base / 9600;
123
124 /* Set up FIFO's */
125 if ((baud_base / quot) < 2400)
126 fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
127 else
128 fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8;
129 serial_outp(cs, UART_FCR, fcr);
130 /* CTS flow control flag and modem status interrupts */
131 cs->hw.elsa.IER &= ~UART_IER_MSI;
132 cs->hw.elsa.IER |= UART_IER_MSI;
133 serial_outp(cs, UART_IER, cs->hw.elsa.IER);
134
135 debugl1(cs,"modem quot=0x%x", quot);
136 serial_outp(cs, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */
137 serial_outp(cs, UART_DLL, quot & 0xff); /* LS of divisor */
138 serial_outp(cs, UART_DLM, quot >> 8); /* MS of divisor */
139 serial_outp(cs, UART_LCR, cval); /* reset DLAB */
140 serial_inp(cs, UART_RX);
141}
142
143static int mstartup(struct IsdnCardState *cs)
144{
145 int retval=0;
146
147 /*
148 * Clear the FIFO buffers and disable them
149 * (they will be reenabled in change_speed())
150 */
151 serial_outp(cs, UART_FCR, (UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT));
152
153 /*
154 * At this point there's no way the LSR could still be 0xFF;
155 * if it is, then bail out, because there's likely no UART
156 * here.
157 */
158 if (serial_inp(cs, UART_LSR) == 0xff) {
159 retval = -ENODEV;
160 goto errout;
161 }
162
163 /*
164 * Clear the interrupt registers.
165 */
166 (void) serial_inp(cs, UART_RX);
167 (void) serial_inp(cs, UART_IIR);
168 (void) serial_inp(cs, UART_MSR);
169
170 /*
171 * Now, initialize the UART
172 */
173 serial_outp(cs, UART_LCR, UART_LCR_WLEN8); /* reset DLAB */
174
175 cs->hw.elsa.MCR = 0;
176 cs->hw.elsa.MCR = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2;
177 serial_outp(cs, UART_MCR, cs->hw.elsa.MCR);
178
179 /*
180 * Finally, enable interrupts
181 */
182 cs->hw.elsa.IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI;
183 serial_outp(cs, UART_IER, cs->hw.elsa.IER); /* enable interrupts */
184
185 /*
186 * And clear the interrupt registers again for luck.
187 */
188 (void)serial_inp(cs, UART_LSR);
189 (void)serial_inp(cs, UART_RX);
190 (void)serial_inp(cs, UART_IIR);
191 (void)serial_inp(cs, UART_MSR);
192
193 cs->hw.elsa.transcnt = cs->hw.elsa.transp = 0;
194 cs->hw.elsa.rcvcnt = cs->hw.elsa.rcvp =0;
195
196 /*
197 * and set the speed of the serial port
198 */
199 change_speed(cs, BASE_BAUD);
200 cs->hw.elsa.MFlag = 1;
201errout:
202 return retval;
203}
204
205/*
206 * This routine will shutdown a serial port; interrupts are disabled, and
207 * DTR is dropped if the hangup on close termio flag is on.
208 */
209static void mshutdown(struct IsdnCardState *cs)
210{
211
212#ifdef SERIAL_DEBUG_OPEN
213 printk(KERN_DEBUG"Shutting down serial ....");
214#endif
215
216 /*
217 * clear delta_msr_wait queue to avoid mem leaks: we may free the irq
218 * here so the queue might never be waken up
219 */
220
221 cs->hw.elsa.IER = 0;
222 serial_outp(cs, UART_IER, 0x00); /* disable all intrs */
223 cs->hw.elsa.MCR &= ~UART_MCR_OUT2;
224
225 /* disable break condition */
226 serial_outp(cs, UART_LCR, serial_inp(cs, UART_LCR) & ~UART_LCR_SBC);
227
228 cs->hw.elsa.MCR &= ~(UART_MCR_DTR|UART_MCR_RTS);
229 serial_outp(cs, UART_MCR, cs->hw.elsa.MCR);
230
231 /* disable FIFO's */
232 serial_outp(cs, UART_FCR, (UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT));
233 serial_inp(cs, UART_RX); /* read data port to reset things */
234
235#ifdef SERIAL_DEBUG_OPEN
236 printk(" done\n");
237#endif
238}
239
240inline int
241write_modem(struct BCState *bcs) {
242 int ret=0;
243 struct IsdnCardState *cs = bcs->cs;
244 int count, len, fp;
245
246 if (!bcs->tx_skb)
247 return 0;
248 if (bcs->tx_skb->len <= 0)
249 return 0;
250 len = bcs->tx_skb->len;
251 if (len > MAX_MODEM_BUF - cs->hw.elsa.transcnt)
252 len = MAX_MODEM_BUF - cs->hw.elsa.transcnt;
253 fp = cs->hw.elsa.transcnt + cs->hw.elsa.transp;
254 fp &= (MAX_MODEM_BUF -1);
255 count = len;
256 if (count > MAX_MODEM_BUF - fp) {
257 count = MAX_MODEM_BUF - fp;
258 memcpy(cs->hw.elsa.transbuf + fp, bcs->tx_skb->data, count);
259 skb_pull(bcs->tx_skb, count);
260 cs->hw.elsa.transcnt += count;
261 ret = count;
262 count = len - count;
263 fp = 0;
264 }
265 memcpy((cs->hw.elsa.transbuf + fp), bcs->tx_skb->data, count);
266 skb_pull(bcs->tx_skb, count);
267 cs->hw.elsa.transcnt += count;
268 ret += count;
269
270 if (cs->hw.elsa.transcnt &&
271 !(cs->hw.elsa.IER & UART_IER_THRI)) {
272 cs->hw.elsa.IER |= UART_IER_THRI;
273 serial_outp(cs, UART_IER, cs->hw.elsa.IER);
274 }
275 return(ret);
276}
277
278inline void
279modem_fill(struct BCState *bcs) {
280
281 if (bcs->tx_skb) {
282 if (bcs->tx_skb->len) {
283 write_modem(bcs);
284 return;
285 } else {
286 if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) &&
287 (PACKET_NOACK != bcs->tx_skb->pkt_type)) {
288 u_long flags;
289 spin_lock_irqsave(&bcs->aclock, flags);
290 bcs->ackcnt += bcs->hw.hscx.count;
291 spin_unlock_irqrestore(&bcs->aclock, flags);
292 schedule_event(bcs, B_ACKPENDING);
293 }
294 dev_kfree_skb_any(bcs->tx_skb);
295 bcs->tx_skb = NULL;
296 }
297 }
298 if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
299 bcs->hw.hscx.count = 0;
300 test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
301 write_modem(bcs);
302 } else {
303 test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
304 schedule_event(bcs, B_XMTBUFREADY);
305 }
306}
307
308static inline void receive_chars(struct IsdnCardState *cs,
309 int *status)
310{
311 unsigned char ch;
312 struct sk_buff *skb;
313
314 do {
315 ch = serial_in(cs, UART_RX);
316 if (cs->hw.elsa.rcvcnt >= MAX_MODEM_BUF)
317 break;
318 cs->hw.elsa.rcvbuf[cs->hw.elsa.rcvcnt++] = ch;
319#ifdef SERIAL_DEBUG_INTR
320 printk("DR%02x:%02x...", ch, *status);
321#endif
322 if (*status & (UART_LSR_BI | UART_LSR_PE |
323 UART_LSR_FE | UART_LSR_OE)) {
324
325#ifdef SERIAL_DEBUG_INTR
326 printk("handling exept....");
327#endif
328 }
329 *status = serial_inp(cs, UART_LSR);
330 } while (*status & UART_LSR_DR);
331 if (cs->hw.elsa.MFlag == 2) {
332 if (!(skb = dev_alloc_skb(cs->hw.elsa.rcvcnt)))
333 printk(KERN_WARNING "ElsaSER: receive out of memory\n");
334 else {
335 memcpy(skb_put(skb, cs->hw.elsa.rcvcnt), cs->hw.elsa.rcvbuf,
336 cs->hw.elsa.rcvcnt);
337 skb_queue_tail(& cs->hw.elsa.bcs->rqueue, skb);
338 }
339 schedule_event(cs->hw.elsa.bcs, B_RCVBUFREADY);
340 } else {
341 char tmp[128];
342 char *t = tmp;
343
344 t += sprintf(t, "modem read cnt %d", cs->hw.elsa.rcvcnt);
345 QuickHex(t, cs->hw.elsa.rcvbuf, cs->hw.elsa.rcvcnt);
346 debugl1(cs, tmp);
347 }
348 cs->hw.elsa.rcvcnt = 0;
349}
350
351static inline void transmit_chars(struct IsdnCardState *cs, int *intr_done)
352{
353 int count;
354
355 debugl1(cs, "transmit_chars: p(%x) cnt(%x)", cs->hw.elsa.transp,
356 cs->hw.elsa.transcnt);
357
358 if (cs->hw.elsa.transcnt <= 0) {
359 cs->hw.elsa.IER &= ~UART_IER_THRI;
360 serial_out(cs, UART_IER, cs->hw.elsa.IER);
361 return;
362 }
363 count = 16;
364 do {
365 serial_outp(cs, UART_TX, cs->hw.elsa.transbuf[cs->hw.elsa.transp++]);
366 if (cs->hw.elsa.transp >= MAX_MODEM_BUF)
367 cs->hw.elsa.transp=0;
368 if (--cs->hw.elsa.transcnt <= 0)
369 break;
370 } while (--count > 0);
371 if ((cs->hw.elsa.transcnt < WAKEUP_CHARS) && (cs->hw.elsa.MFlag==2))
372 modem_fill(cs->hw.elsa.bcs);
373
374#ifdef SERIAL_DEBUG_INTR
375 printk("THRE...");
376#endif
377 if (intr_done)
378 *intr_done = 0;
379 if (cs->hw.elsa.transcnt <= 0) {
380 cs->hw.elsa.IER &= ~UART_IER_THRI;
381 serial_outp(cs, UART_IER, cs->hw.elsa.IER);
382 }
383}
384
385
386static void rs_interrupt_elsa(int irq, struct IsdnCardState *cs)
387{
388 int status, iir, msr;
389 int pass_counter = 0;
390
391#ifdef SERIAL_DEBUG_INTR
392 printk("rs_interrupt_single(%d)...", irq);
393#endif
394
395 do {
396 status = serial_inp(cs, UART_LSR);
397 debugl1(cs,"rs LSR %02x", status);
398#ifdef SERIAL_DEBUG_INTR
399 printk("status = %x...", status);
400#endif
401 if (status & UART_LSR_DR)
402 receive_chars(cs, &status);
403 if (status & UART_LSR_THRE)
404 transmit_chars(cs, NULL);
405 if (pass_counter++ > RS_ISR_PASS_LIMIT) {
406 printk("rs_single loop break.\n");
407 break;
408 }
409 iir = serial_inp(cs, UART_IIR);
410 debugl1(cs,"rs IIR %02x", iir);
411 if ((iir & 0xf) == 0) {
412 msr = serial_inp(cs, UART_MSR);
413 debugl1(cs,"rs MSR %02x", msr);
414 }
415 } while (!(iir & UART_IIR_NO_INT));
416#ifdef SERIAL_DEBUG_INTR
417 printk("end.\n");
418#endif
419}
420
421extern int open_hscxstate(struct IsdnCardState *cs, struct BCState *bcs);
422extern void modehscx(struct BCState *bcs, int mode, int bc);
423extern void hscx_l2l1(struct PStack *st, int pr, void *arg);
424
425void
426close_elsastate(struct BCState *bcs)
427{
428 modehscx(bcs, 0, bcs->channel);
429 if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) {
430 if (bcs->hw.hscx.rcvbuf) {
431 if (bcs->mode != L1_MODE_MODEM)
432 kfree(bcs->hw.hscx.rcvbuf);
433 bcs->hw.hscx.rcvbuf = NULL;
434 }
435 skb_queue_purge(&bcs->rqueue);
436 skb_queue_purge(&bcs->squeue);
437 if (bcs->tx_skb) {
438 dev_kfree_skb_any(bcs->tx_skb);
439 bcs->tx_skb = NULL;
440 test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
441 }
442 }
443}
444
445void
446modem_write_cmd(struct IsdnCardState *cs, u_char *buf, int len) {
447 int count, fp;
448 u_char *msg = buf;
449
450 if (!len)
451 return;
452 if (len > (MAX_MODEM_BUF - cs->hw.elsa.transcnt)) {
453 return;
454 }
455 fp = cs->hw.elsa.transcnt + cs->hw.elsa.transp;
456 fp &= (MAX_MODEM_BUF -1);
457 count = len;
458 if (count > MAX_MODEM_BUF - fp) {
459 count = MAX_MODEM_BUF - fp;
460 memcpy(cs->hw.elsa.transbuf + fp, msg, count);
461 cs->hw.elsa.transcnt += count;
462 msg += count;
463 count = len - count;
464 fp = 0;
465 }
466 memcpy(cs->hw.elsa.transbuf + fp, msg, count);
467 cs->hw.elsa.transcnt += count;
468 if (cs->hw.elsa.transcnt &&
469 !(cs->hw.elsa.IER & UART_IER_THRI)) {
470 cs->hw.elsa.IER |= UART_IER_THRI;
471 serial_outp(cs, UART_IER, cs->hw.elsa.IER);
472 }
473}
474
475void
476modem_set_init(struct IsdnCardState *cs) {
477 int timeout;
478
479#define RCV_DELAY 20000
480 modem_write_cmd(cs, MInit_1, strlen(MInit_1));
481 timeout = 1000;
482 while(timeout-- && cs->hw.elsa.transcnt)
483 udelay(1000);
484 debugl1(cs, "msi tout=%d", timeout);
485 udelay(RCV_DELAY);
486 modem_write_cmd(cs, MInit_2, strlen(MInit_2));
487 timeout = 1000;
488 while(timeout-- && cs->hw.elsa.transcnt)
489 udelay(1000);
490 debugl1(cs, "msi tout=%d", timeout);
491 udelay(RCV_DELAY);
492 modem_write_cmd(cs, MInit_3, strlen(MInit_3));
493 timeout = 1000;
494 while(timeout-- && cs->hw.elsa.transcnt)
495 udelay(1000);
496 debugl1(cs, "msi tout=%d", timeout);
497 udelay(RCV_DELAY);
498 modem_write_cmd(cs, MInit_4, strlen(MInit_4));
499 timeout = 1000;
500 while(timeout-- && cs->hw.elsa.transcnt)
501 udelay(1000);
502 debugl1(cs, "msi tout=%d", timeout);
503 udelay(RCV_DELAY );
504 modem_write_cmd(cs, MInit_5, strlen(MInit_5));
505 timeout = 1000;
506 while(timeout-- && cs->hw.elsa.transcnt)
507 udelay(1000);
508 debugl1(cs, "msi tout=%d", timeout);
509 udelay(RCV_DELAY);
510 modem_write_cmd(cs, MInit_6, strlen(MInit_6));
511 timeout = 1000;
512 while(timeout-- && cs->hw.elsa.transcnt)
513 udelay(1000);
514 debugl1(cs, "msi tout=%d", timeout);
515 udelay(RCV_DELAY);
516 modem_write_cmd(cs, MInit_7, strlen(MInit_7));
517 timeout = 1000;
518 while(timeout-- && cs->hw.elsa.transcnt)
519 udelay(1000);
520 debugl1(cs, "msi tout=%d", timeout);
521 udelay(RCV_DELAY);
522}
523
524void
525modem_set_dial(struct IsdnCardState *cs, int outgoing) {
526 int timeout;
527#define RCV_DELAY 20000
528
529 modem_write_cmd(cs, MInit_speed28800, strlen(MInit_speed28800));
530 timeout = 1000;
531 while(timeout-- && cs->hw.elsa.transcnt)
532 udelay(1000);
533 debugl1(cs, "msi tout=%d", timeout);
534 udelay(RCV_DELAY);
535 if (outgoing)
536 modem_write_cmd(cs, MInit_dialout, strlen(MInit_dialout));
537 else
538 modem_write_cmd(cs, MInit_dialin, strlen(MInit_dialin));
539 timeout = 1000;
540 while(timeout-- && cs->hw.elsa.transcnt)
541 udelay(1000);
542 debugl1(cs, "msi tout=%d", timeout);
543 udelay(RCV_DELAY);
544}
545
546void
547modem_l2l1(struct PStack *st, int pr, void *arg)
548{
549 struct BCState *bcs = st->l1.bcs;
550 struct sk_buff *skb = arg;
551 u_long flags;
552
553 if (pr == (PH_DATA | REQUEST)) {
554 spin_lock_irqsave(&bcs->cs->lock, flags);
555 if (bcs->tx_skb) {
556 skb_queue_tail(&bcs->squeue, skb);
557 } else {
558 bcs->tx_skb = skb;
559 test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
560 bcs->hw.hscx.count = 0;
561 write_modem(bcs);
562 }
563 spin_unlock_irqrestore(&bcs->cs->lock, flags);
564 } else if (pr == (PH_ACTIVATE | REQUEST)) {
565 test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag);
566 st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL);
567 set_arcofi(bcs->cs, st->l1.bc);
568 mstartup(bcs->cs);
569 modem_set_dial(bcs->cs, test_bit(FLG_ORIG, &st->l2.flag));
570 bcs->cs->hw.elsa.MFlag=2;
571 } else if (pr == (PH_DEACTIVATE | REQUEST)) {
572 test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag);
573 bcs->cs->dc.isac.arcofi_bc = st->l1.bc;
574 arcofi_fsm(bcs->cs, ARCOFI_START, &ARCOFI_XOP_0);
575 interruptible_sleep_on(&bcs->cs->dc.isac.arcofi_wait);
576 bcs->cs->hw.elsa.MFlag=1;
577 } else {
578 printk(KERN_WARNING"ElsaSer: unknown pr %x\n", pr);
579 }
580}
581
582int
583setstack_elsa(struct PStack *st, struct BCState *bcs)
584{
585
586 bcs->channel = st->l1.bc;
587 switch (st->l1.mode) {
588 case L1_MODE_HDLC:
589 case L1_MODE_TRANS:
590 if (open_hscxstate(st->l1.hardware, bcs))
591 return (-1);
592 st->l2.l2l1 = hscx_l2l1;
593 break;
594 case L1_MODE_MODEM:
595 bcs->mode = L1_MODE_MODEM;
596 if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
597 bcs->hw.hscx.rcvbuf = bcs->cs->hw.elsa.rcvbuf;
598 skb_queue_head_init(&bcs->rqueue);
599 skb_queue_head_init(&bcs->squeue);
600 }
601 bcs->tx_skb = NULL;
602 test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
603 bcs->event = 0;
604 bcs->hw.hscx.rcvidx = 0;
605 bcs->tx_cnt = 0;
606 bcs->cs->hw.elsa.bcs = bcs;
607 st->l2.l2l1 = modem_l2l1;
608 break;
609 }
610 st->l1.bcs = bcs;
611 setstack_manager(st);
612 bcs->st = st;
613 setstack_l1_B(st);
614 return (0);
615}
616
617void
618init_modem(struct IsdnCardState *cs) {
619
620 cs->bcs[0].BC_SetStack = setstack_elsa;
621 cs->bcs[1].BC_SetStack = setstack_elsa;
622 cs->bcs[0].BC_Close = close_elsastate;
623 cs->bcs[1].BC_Close = close_elsastate;
624 if (!(cs->hw.elsa.rcvbuf = kmalloc(MAX_MODEM_BUF,
625 GFP_ATOMIC))) {
626 printk(KERN_WARNING
627 "Elsa: No modem mem hw.elsa.rcvbuf\n");
628 return;
629 }
630 if (!(cs->hw.elsa.transbuf = kmalloc(MAX_MODEM_BUF,
631 GFP_ATOMIC))) {
632 printk(KERN_WARNING
633 "Elsa: No modem mem hw.elsa.transbuf\n");
634 kfree(cs->hw.elsa.rcvbuf);
635 cs->hw.elsa.rcvbuf = NULL;
636 return;
637 }
638 if (mstartup(cs)) {
639 printk(KERN_WARNING "Elsa: problem startup modem\n");
640 }
641 modem_set_init(cs);
642}
643
644void
645release_modem(struct IsdnCardState *cs) {
646
647 cs->hw.elsa.MFlag = 0;
648 if (cs->hw.elsa.transbuf) {
649 if (cs->hw.elsa.rcvbuf) {
650 mshutdown(cs);
651 kfree(cs->hw.elsa.rcvbuf);
652 cs->hw.elsa.rcvbuf = NULL;
653 }
654 kfree(cs->hw.elsa.transbuf);
655 cs->hw.elsa.transbuf = NULL;
656 }
657}
diff --git a/drivers/isdn/hisax/enternow.h b/drivers/isdn/hisax/enternow.h
new file mode 100644
index 000000000000..ed2eec5874c5
--- /dev/null
+++ b/drivers/isdn/hisax/enternow.h
@@ -0,0 +1,51 @@
1/* 2001/10/02
2 *
3 * enternow.h Header-file included by
4 * enternow_pci.c
5 *
6 * Author Christoph Ersfeld <info@formula-n.de>
7 * Formula-n Europe AG (www.formula-n.com)
8 * previously Gerdes AG
9 *
10 *
11 * This file is (c) under GNU PUBLIC LICENSE
12 */
13
14
15/* ***************************************************************************************** *
16 * ****************************** datatypes and macros ************************************* *
17 * ***************************************************************************************** */
18
19#define BYTE unsigned char
20#define WORD unsigned int
21#define HIBYTE(w) ((unsigned char)((w & 0xff00) / 256))
22#define LOBYTE(w) ((unsigned char)(w & 0x00ff))
23#define InByte(addr) inb(addr)
24#define OutByte(addr,val) outb(val,addr)
25
26
27
28/* ***************************************************************************************** *
29 * *********************************** card-specific *************************************** *
30 * ***************************************************************************************** */
31
32/* für PowerISDN PCI */
33#define TJ_AMD_IRQ 0x20
34#define TJ_LED1 0x40
35#define TJ_LED2 0x80
36
37
38/* Das Fenster zum AMD...
39 * Ab Adresse hw.njet.base + TJ_AMD_PORT werden vom AMD jeweils 8 Bit in
40 * den TigerJet i/o-Raum gemappt
41 * -> 0x01 des AMD bei hw.njet.base + 0C4 */
42#define TJ_AMD_PORT 0xC0
43
44
45
46/* ***************************************************************************************** *
47 * *************************************** Prototypen ************************************** *
48 * ***************************************************************************************** */
49
50BYTE ReadByteAmd7930(struct IsdnCardState *cs, BYTE offset);
51void WriteByteAmd7930(struct IsdnCardState *cs, BYTE offset, BYTE value);
diff --git a/drivers/isdn/hisax/enternow_pci.c b/drivers/isdn/hisax/enternow_pci.c
new file mode 100644
index 000000000000..1cc4d11e007a
--- /dev/null
+++ b/drivers/isdn/hisax/enternow_pci.c
@@ -0,0 +1,399 @@
1/* enternow_pci.c,v 0.99 2001/10/02
2 *
3 * enternow_pci.c Card-specific routines for
4 * Formula-n enter:now ISDN PCI ab
5 * Gerdes AG Power ISDN PCI
6 * Woerltronic SA 16 PCI
7 * (based on HiSax driver by Karsten Keil)
8 *
9 * Author Christoph Ersfeld <info@formula-n.de>
10 * Formula-n Europe AG (www.formula-n.com)
11 * previously Gerdes AG
12 *
13 *
14 * This file is (c) under GNU PUBLIC LICENSE
15 *
16 * Notes:
17 * This driver interfaces to netjet.c which performs B-channel
18 * processing.
19 *
20 * Version 0.99 is the first release of this driver and there are
21 * certainly a few bugs.
22 * It isn't testet on linux 2.4 yet, so consider this code to be
23 * beta.
24 *
25 * Please don't report me any malfunction without sending
26 * (compressed) debug-logs.
27 * It would be nearly impossible to retrace it.
28 *
29 * Log D-channel-processing as follows:
30 *
31 * 1. Load hisax with card-specific parameters, this example ist for
32 * Formula-n enter:now ISDN PCI and compatible
33 * (f.e. Gerdes Power ISDN PCI)
34 *
35 * modprobe hisax type=41 protocol=2 id=gerdes
36 *
37 * if you chose an other value for id, you need to modify the
38 * code below, too.
39 *
40 * 2. set debug-level
41 *
42 * hisaxctrl gerdes 1 0x3ff
43 * hisaxctrl gerdes 11 0x4f
44 * cat /dev/isdnctrl >> ~/log &
45 *
46 * Please take also a look into /var/log/messages if there is
47 * anything importand concerning HISAX.
48 *
49 *
50 * Credits:
51 * Programming the driver for Formula-n enter:now ISDN PCI and
52 * necessary the driver for the used Amd 7930 D-channel-controller
53 * was spnsored by Formula-n Europe AG.
54 * Thanks to Karsten Keil and Petr Novak, who gave me support in
55 * Hisax-specific questions.
56 * I want so say special thanks to Carl-Friedrich Braun, who had to
57 * answer a lot of questions about generally ISDN and about handling
58 * of the Amd-Chip.
59 *
60 */
61
62
63#include <linux/config.h>
64#include "hisax.h"
65#include "isac.h"
66#include "isdnl1.h"
67#include "amd7930_fn.h"
68#include "enternow.h"
69#include <linux/interrupt.h>
70#include <linux/ppp_defs.h>
71#include <linux/pci.h>
72#include <linux/init.h>
73#include "netjet.h"
74
75
76
77const char *enternow_pci_rev = "$Revision: 1.1.4.5 $";
78
79
80/* *************************** I/O-Interface functions ************************************* */
81
82
83/* cs->readisac, macro rByteAMD */
84BYTE
85ReadByteAmd7930(struct IsdnCardState *cs, BYTE offset)
86{
87 /* direktes Register */
88 if(offset < 8)
89 return (InByte(cs->hw.njet.isac + 4*offset));
90
91 /* indirektes Register */
92 else {
93 OutByte(cs->hw.njet.isac + 4*AMD_CR, offset);
94 return(InByte(cs->hw.njet.isac + 4*AMD_DR));
95 }
96}
97
98/* cs->writeisac, macro wByteAMD */
99void
100WriteByteAmd7930(struct IsdnCardState *cs, BYTE offset, BYTE value)
101{
102 /* direktes Register */
103 if(offset < 8)
104 OutByte(cs->hw.njet.isac + 4*offset, value);
105
106 /* indirektes Register */
107 else {
108 OutByte(cs->hw.njet.isac + 4*AMD_CR, offset);
109 OutByte(cs->hw.njet.isac + 4*AMD_DR, value);
110 }
111}
112
113
114void
115enpci_setIrqMask(struct IsdnCardState *cs, BYTE val) {
116 if (!val)
117 OutByte(cs->hw.njet.base+NETJET_IRQMASK1, 0x00);
118 else
119 OutByte(cs->hw.njet.base+NETJET_IRQMASK1, TJ_AMD_IRQ);
120}
121
122
123static BYTE dummyrr(struct IsdnCardState *cs, int chan, BYTE off)
124{
125 return(5);
126}
127
128static void dummywr(struct IsdnCardState *cs, int chan, BYTE off, BYTE value)
129{
130
131}
132
133
134/* ******************************************************************************** */
135
136
137static void
138reset_enpci(struct IsdnCardState *cs)
139{
140 if (cs->debug & L1_DEB_ISAC)
141 debugl1(cs, "enter:now PCI: reset");
142
143 /* Reset on, (also for AMD) */
144 cs->hw.njet.ctrl_reg = 0x07;
145 OutByte(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
146 mdelay(20);
147 /* Reset off */
148 cs->hw.njet.ctrl_reg = 0x30;
149 OutByte(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
150 /* 20ms delay */
151 mdelay(20);
152 cs->hw.njet.auxd = 0; // LED-status
153 cs->hw.njet.dmactrl = 0;
154 OutByte(cs->hw.njet.base + NETJET_AUXCTRL, ~TJ_AMD_IRQ);
155 OutByte(cs->hw.njet.base + NETJET_IRQMASK1, TJ_AMD_IRQ);
156 OutByte(cs->hw.njet.auxa, cs->hw.njet.auxd); // LED off
157}
158
159
160static int
161enpci_card_msg(struct IsdnCardState *cs, int mt, void *arg)
162{
163 u_long flags;
164 BYTE *chan;
165
166 if (cs->debug & L1_DEB_ISAC)
167 debugl1(cs, "enter:now PCI: card_msg: 0x%04X", mt);
168
169 switch (mt) {
170 case CARD_RESET:
171 spin_lock_irqsave(&cs->lock, flags);
172 reset_enpci(cs);
173 Amd7930_init(cs);
174 spin_unlock_irqrestore(&cs->lock, flags);
175 break;
176 case CARD_RELEASE:
177 release_io_netjet(cs);
178 break;
179 case CARD_INIT:
180 reset_enpci(cs);
181 inittiger(cs);
182 /* irq must be on here */
183 Amd7930_init(cs);
184 break;
185 case CARD_TEST:
186 break;
187 case MDL_ASSIGN:
188 /* TEI assigned, LED1 on */
189 cs->hw.njet.auxd = TJ_AMD_IRQ << 1;
190 OutByte(cs->hw.njet.base + NETJET_AUXDATA, cs->hw.njet.auxd);
191 break;
192 case MDL_REMOVE:
193 /* TEI removed, LEDs off */
194 cs->hw.njet.auxd = 0;
195 OutByte(cs->hw.njet.base + NETJET_AUXDATA, 0x00);
196 break;
197 case MDL_BC_ASSIGN:
198 /* activate B-channel */
199 chan = (BYTE *)arg;
200
201 if (cs->debug & L1_DEB_ISAC)
202 debugl1(cs, "enter:now PCI: assign phys. BC %d in AMD LMR1", *chan);
203
204 cs->dc.amd7930.ph_command(cs, (cs->dc.amd7930.lmr1 | (*chan + 1)), "MDL_BC_ASSIGN");
205 /* at least one b-channel in use, LED 2 on */
206 cs->hw.njet.auxd |= TJ_AMD_IRQ << 2;
207 OutByte(cs->hw.njet.base + NETJET_AUXDATA, cs->hw.njet.auxd);
208 break;
209 case MDL_BC_RELEASE:
210 /* deactivate B-channel */
211 chan = (BYTE *)arg;
212
213 if (cs->debug & L1_DEB_ISAC)
214 debugl1(cs, "enter:now PCI: release phys. BC %d in Amd LMR1", *chan);
215
216 cs->dc.amd7930.ph_command(cs, (cs->dc.amd7930.lmr1 & ~(*chan + 1)), "MDL_BC_RELEASE");
217 /* no b-channel active -> LED2 off */
218 if (!(cs->dc.amd7930.lmr1 & 3)) {
219 cs->hw.njet.auxd &= ~(TJ_AMD_IRQ << 2);
220 OutByte(cs->hw.njet.base + NETJET_AUXDATA, cs->hw.njet.auxd);
221 }
222 break;
223 default:
224 break;
225
226 }
227 return(0);
228}
229
230static irqreturn_t
231enpci_interrupt(int intno, void *dev_id, struct pt_regs *regs)
232{
233 struct IsdnCardState *cs = dev_id;
234 BYTE s0val, s1val, ir;
235 u_long flags;
236
237 spin_lock_irqsave(&cs->lock, flags);
238 s1val = InByte(cs->hw.njet.base + NETJET_IRQSTAT1);
239
240 /* AMD threw an interrupt */
241 if (!(s1val & TJ_AMD_IRQ)) {
242 /* read and clear interrupt-register */
243 ir = ReadByteAmd7930(cs, 0x00);
244 Amd7930_interrupt(cs, ir);
245 s1val = 1;
246 } else
247 s1val = 0;
248 s0val = InByte(cs->hw.njet.base + NETJET_IRQSTAT0);
249 if ((s0val | s1val)==0) { // shared IRQ
250 spin_unlock_irqrestore(&cs->lock, flags);
251 return IRQ_NONE;
252 }
253 if (s0val)
254 OutByte(cs->hw.njet.base + NETJET_IRQSTAT0, s0val);
255
256 /* DMA-Interrupt: B-channel-stuff */
257 /* set bits in sval to indicate which page is free */
258 if (inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR) <
259 inl(cs->hw.njet.base + NETJET_DMA_WRITE_IRQ))
260 /* the 2nd write page is free */
261 s0val = 0x08;
262 else /* the 1st write page is free */
263 s0val = 0x04;
264 if (inl(cs->hw.njet.base + NETJET_DMA_READ_ADR) <
265 inl(cs->hw.njet.base + NETJET_DMA_READ_IRQ))
266 /* the 2nd read page is free */
267 s0val = s0val | 0x02;
268 else /* the 1st read page is free */
269 s0val = s0val | 0x01;
270 if (s0val != cs->hw.njet.last_is0) /* we have a DMA interrupt */
271 {
272 if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
273 spin_unlock_irqrestore(&cs->lock, flags);
274 return IRQ_HANDLED;
275 }
276 cs->hw.njet.irqstat0 = s0val;
277 if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_READ) !=
278 (cs->hw.njet.last_is0 & NETJET_IRQM0_READ))
279 /* we have a read dma int */
280 read_tiger(cs);
281 if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_WRITE) !=
282 (cs->hw.njet.last_is0 & NETJET_IRQM0_WRITE))
283 /* we have a write dma int */
284 write_tiger(cs);
285 test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
286 }
287 spin_unlock_irqrestore(&cs->lock, flags);
288 return IRQ_HANDLED;
289}
290
291
292static struct pci_dev *dev_netjet __initdata = NULL;
293
294/* called by config.c */
295int __init
296setup_enternow_pci(struct IsdnCard *card)
297{
298 int bytecnt;
299 struct IsdnCardState *cs = card->cs;
300 char tmp[64];
301
302#ifdef CONFIG_PCI
303#ifdef __BIG_ENDIAN
304#error "not running on big endian machines now"
305#endif
306 strcpy(tmp, enternow_pci_rev);
307 printk(KERN_INFO "HiSax: Formula-n Europe AG enter:now ISDN PCI driver Rev. %s\n", HiSax_getrev(tmp));
308 if (cs->typ != ISDN_CTYPE_ENTERNOW)
309 return(0);
310 test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
311
312 for ( ;; )
313 {
314 if ((dev_netjet = pci_find_device(PCI_VENDOR_ID_TIGERJET,
315 PCI_DEVICE_ID_TIGERJET_300, dev_netjet))) {
316 if (pci_enable_device(dev_netjet))
317 return(0);
318 cs->irq = dev_netjet->irq;
319 if (!cs->irq) {
320 printk(KERN_WARNING "enter:now PCI: No IRQ for PCI card found\n");
321 return(0);
322 }
323 cs->hw.njet.base = pci_resource_start(dev_netjet, 0);
324 if (!cs->hw.njet.base) {
325 printk(KERN_WARNING "enter:now PCI: No IO-Adr for PCI card found\n");
326 return(0);
327 }
328 /* checks Sub-Vendor ID because system crashes with Traverse-Card */
329 if ((dev_netjet->subsystem_vendor != 0x55) ||
330 (dev_netjet->subsystem_device != 0x02)) {
331 printk(KERN_WARNING "enter:now: You tried to load this driver with an incompatible TigerJet-card\n");
332 printk(KERN_WARNING "Use type=20 for Traverse NetJet PCI Card.\n");
333 return(0);
334 }
335 } else {
336 printk(KERN_WARNING "enter:now PCI: No PCI card found\n");
337 return(0);
338 }
339
340 cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA;
341 cs->hw.njet.isac = cs->hw.njet.base + 0xC0; // Fenster zum AMD
342
343 /* Reset an */
344 cs->hw.njet.ctrl_reg = 0x07; // geändert von 0xff
345 OutByte(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
346 /* 20 ms Pause */
347 mdelay(20);
348
349 cs->hw.njet.ctrl_reg = 0x30; /* Reset Off and status read clear */
350 OutByte(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
351 mdelay(10);
352
353 cs->hw.njet.auxd = 0x00; // war 0xc0
354 cs->hw.njet.dmactrl = 0;
355
356 OutByte(cs->hw.njet.base + NETJET_AUXCTRL, ~TJ_AMD_IRQ);
357 OutByte(cs->hw.njet.base + NETJET_IRQMASK1, TJ_AMD_IRQ);
358 OutByte(cs->hw.njet.auxa, cs->hw.njet.auxd);
359
360 break;
361 }
362#else
363
364 printk(KERN_WARNING "enter:now PCI: NO_PCI_BIOS\n");
365 printk(KERN_WARNING "enter:now PCI: unable to config Formula-n enter:now ISDN PCI ab\n");
366 return (0);
367
368#endif /* CONFIG_PCI */
369
370 bytecnt = 256;
371
372 printk(KERN_INFO
373 "enter:now PCI: PCI card configured at 0x%lx IRQ %d\n",
374 cs->hw.njet.base, cs->irq);
375 if (!request_region(cs->hw.njet.base, bytecnt, "Fn_ISDN")) {
376 printk(KERN_WARNING
377 "HiSax: %s config port %lx-%lx already in use\n",
378 CardType[card->typ],
379 cs->hw.njet.base,
380 cs->hw.njet.base + bytecnt);
381 return (0);
382 }
383 setup_Amd7930(cs);
384 cs->hw.njet.last_is0 = 0;
385 /* macro rByteAMD */
386 cs->readisac = &ReadByteAmd7930;
387 /* macro wByteAMD */
388 cs->writeisac = &WriteByteAmd7930;
389 cs->dc.amd7930.setIrqMask = &enpci_setIrqMask;
390
391 cs->BC_Read_Reg = &dummyrr;
392 cs->BC_Write_Reg = &dummywr;
393 cs->BC_Send_Data = &netjet_fill_dma;
394 cs->cardmsg = &enpci_card_msg;
395 cs->irq_func = &enpci_interrupt;
396 cs->irq_flags |= SA_SHIRQ;
397
398 return (1);
399}
diff --git a/drivers/isdn/hisax/fsm.c b/drivers/isdn/hisax/fsm.c
new file mode 100644
index 000000000000..0d44a3f480ac
--- /dev/null
+++ b/drivers/isdn/hisax/fsm.c
@@ -0,0 +1,163 @@
1/* $Id: fsm.c,v 1.14.6.4 2001/09/23 22:24:47 kai Exp $
2 *
3 * Finite state machine
4 *
5 * Author Karsten Keil
6 * Copyright by Karsten Keil <keil@isdn4linux.de>
7 * by Kai Germaschewski <kai.germaschewski@gmx.de>
8 *
9 * This software may be used and distributed according to the terms
10 * of the GNU General Public License, incorporated herein by reference.
11 *
12 * Thanks to Jan den Ouden
13 * Fritz Elfert
14 *
15 */
16
17#include <linux/module.h>
18#include <linux/init.h>
19#include "hisax.h"
20
21#define FSM_TIMER_DEBUG 0
22
23int
24FsmNew(struct Fsm *fsm, struct FsmNode *fnlist, int fncount)
25{
26 int i;
27
28 fsm->jumpmatrix = (FSMFNPTR *)
29 kmalloc(sizeof (FSMFNPTR) * fsm->state_count * fsm->event_count, GFP_KERNEL);
30 if (!fsm->jumpmatrix)
31 return -ENOMEM;
32
33 memset(fsm->jumpmatrix, 0, sizeof (FSMFNPTR) * fsm->state_count * fsm->event_count);
34
35 for (i = 0; i < fncount; i++)
36 if ((fnlist[i].state>=fsm->state_count) || (fnlist[i].event>=fsm->event_count)) {
37 printk(KERN_ERR "FsmNew Error line %d st(%ld/%ld) ev(%ld/%ld)\n",
38 i,(long)fnlist[i].state,(long)fsm->state_count,
39 (long)fnlist[i].event,(long)fsm->event_count);
40 } else
41 fsm->jumpmatrix[fsm->state_count * fnlist[i].event +
42 fnlist[i].state] = (FSMFNPTR) fnlist[i].routine;
43 return 0;
44}
45
46void
47FsmFree(struct Fsm *fsm)
48{
49 kfree((void *) fsm->jumpmatrix);
50}
51
52int
53FsmEvent(struct FsmInst *fi, int event, void *arg)
54{
55 FSMFNPTR r;
56
57 if ((fi->state>=fi->fsm->state_count) || (event >= fi->fsm->event_count)) {
58 printk(KERN_ERR "FsmEvent Error st(%ld/%ld) ev(%d/%ld)\n",
59 (long)fi->state,(long)fi->fsm->state_count,event,(long)fi->fsm->event_count);
60 return(1);
61 }
62 r = fi->fsm->jumpmatrix[fi->fsm->state_count * event + fi->state];
63 if (r) {
64 if (fi->debug)
65 fi->printdebug(fi, "State %s Event %s",
66 fi->fsm->strState[fi->state],
67 fi->fsm->strEvent[event]);
68 r(fi, event, arg);
69 return (0);
70 } else {
71 if (fi->debug)
72 fi->printdebug(fi, "State %s Event %s no routine",
73 fi->fsm->strState[fi->state],
74 fi->fsm->strEvent[event]);
75 return (!0);
76 }
77}
78
79void
80FsmChangeState(struct FsmInst *fi, int newstate)
81{
82 fi->state = newstate;
83 if (fi->debug)
84 fi->printdebug(fi, "ChangeState %s",
85 fi->fsm->strState[newstate]);
86}
87
88static void
89FsmExpireTimer(struct FsmTimer *ft)
90{
91#if FSM_TIMER_DEBUG
92 if (ft->fi->debug)
93 ft->fi->printdebug(ft->fi, "FsmExpireTimer %lx", (long) ft);
94#endif
95 FsmEvent(ft->fi, ft->event, ft->arg);
96}
97
98void
99FsmInitTimer(struct FsmInst *fi, struct FsmTimer *ft)
100{
101 ft->fi = fi;
102 ft->tl.function = (void *) FsmExpireTimer;
103 ft->tl.data = (long) ft;
104#if FSM_TIMER_DEBUG
105 if (ft->fi->debug)
106 ft->fi->printdebug(ft->fi, "FsmInitTimer %lx", (long) ft);
107#endif
108 init_timer(&ft->tl);
109}
110
111void
112FsmDelTimer(struct FsmTimer *ft, int where)
113{
114#if FSM_TIMER_DEBUG
115 if (ft->fi->debug)
116 ft->fi->printdebug(ft->fi, "FsmDelTimer %lx %d", (long) ft, where);
117#endif
118 del_timer(&ft->tl);
119}
120
121int
122FsmAddTimer(struct FsmTimer *ft,
123 int millisec, int event, void *arg, int where)
124{
125
126#if FSM_TIMER_DEBUG
127 if (ft->fi->debug)
128 ft->fi->printdebug(ft->fi, "FsmAddTimer %lx %d %d",
129 (long) ft, millisec, where);
130#endif
131
132 if (timer_pending(&ft->tl)) {
133 printk(KERN_WARNING "FsmAddTimer: timer already active!\n");
134 ft->fi->printdebug(ft->fi, "FsmAddTimer already active!");
135 return -1;
136 }
137 init_timer(&ft->tl);
138 ft->event = event;
139 ft->arg = arg;
140 ft->tl.expires = jiffies + (millisec * HZ) / 1000;
141 add_timer(&ft->tl);
142 return 0;
143}
144
145void
146FsmRestartTimer(struct FsmTimer *ft,
147 int millisec, int event, void *arg, int where)
148{
149
150#if FSM_TIMER_DEBUG
151 if (ft->fi->debug)
152 ft->fi->printdebug(ft->fi, "FsmRestartTimer %lx %d %d",
153 (long) ft, millisec, where);
154#endif
155
156 if (timer_pending(&ft->tl))
157 del_timer(&ft->tl);
158 init_timer(&ft->tl);
159 ft->event = event;
160 ft->arg = arg;
161 ft->tl.expires = jiffies + (millisec * HZ) / 1000;
162 add_timer(&ft->tl);
163}
diff --git a/drivers/isdn/hisax/fsm.h b/drivers/isdn/hisax/fsm.h
new file mode 100644
index 000000000000..f02f7da1688d
--- /dev/null
+++ b/drivers/isdn/hisax/fsm.h
@@ -0,0 +1,61 @@
1/* $Id: fsm.h,v 1.3.2.2 2001/09/23 22:24:47 kai Exp $
2 *
3 * Finite state machine
4 *
5 * Author Karsten Keil
6 * Copyright by Karsten Keil <keil@isdn4linux.de>
7 * by Kai Germaschewski <kai.germaschewski@gmx.de>
8 *
9 * This software may be used and distributed according to the terms
10 * of the GNU General Public License, incorporated herein by reference.
11 *
12 */
13
14#ifndef __FSM_H__
15#define __FSM_H__
16
17#include <linux/timer.h>
18
19struct FsmInst;
20
21typedef void (* FSMFNPTR)(struct FsmInst *, int, void *);
22
23struct Fsm {
24 FSMFNPTR *jumpmatrix;
25 int state_count, event_count;
26 char **strEvent, **strState;
27};
28
29struct FsmInst {
30 struct Fsm *fsm;
31 int state;
32 int debug;
33 void *userdata;
34 int userint;
35 void (*printdebug) (struct FsmInst *, char *, ...);
36};
37
38struct FsmNode {
39 int state, event;
40 void (*routine) (struct FsmInst *, int, void *);
41};
42
43struct FsmTimer {
44 struct FsmInst *fi;
45 struct timer_list tl;
46 int event;
47 void *arg;
48};
49
50int FsmNew(struct Fsm *fsm, struct FsmNode *fnlist, int fncount);
51void FsmFree(struct Fsm *fsm);
52int FsmEvent(struct FsmInst *fi, int event, void *arg);
53void FsmChangeState(struct FsmInst *fi, int newstate);
54void FsmInitTimer(struct FsmInst *fi, struct FsmTimer *ft);
55int FsmAddTimer(struct FsmTimer *ft, int millisec, int event,
56 void *arg, int where);
57void FsmRestartTimer(struct FsmTimer *ft, int millisec, int event,
58 void *arg, int where);
59void FsmDelTimer(struct FsmTimer *ft, int where);
60
61#endif
diff --git a/drivers/isdn/hisax/gazel.c b/drivers/isdn/hisax/gazel.c
new file mode 100644
index 000000000000..24a05a43f33e
--- /dev/null
+++ b/drivers/isdn/hisax/gazel.c
@@ -0,0 +1,684 @@
1/* $Id: gazel.c,v 2.19.2.4 2004/01/14 16:04:48 keil Exp $
2 *
3 * low level stuff for Gazel isdn cards
4 *
5 * Author BeWan Systems
6 * based on source code from Karsten Keil
7 * Copyright by BeWan Systems
8 *
9 * This software may be used and distributed according to the terms
10 * of the GNU General Public License, incorporated herein by reference.
11 *
12 */
13
14#include <linux/config.h>
15#include <linux/init.h>
16#include "hisax.h"
17#include "isac.h"
18#include "hscx.h"
19#include "isdnl1.h"
20#include "ipac.h"
21#include <linux/pci.h>
22
23extern const char *CardType[];
24const char *gazel_revision = "$Revision: 2.19.2.4 $";
25
26#define R647 1
27#define R685 2
28#define R753 3
29#define R742 4
30
31#define PLX_CNTRL 0x50 /* registre de controle PLX */
32#define RESET_GAZEL 0x4
33#define RESET_9050 0x40000000
34#define PLX_INCSR 0x4C /* registre d'IT du 9050 */
35#define INT_ISAC_EN 0x8 /* 1 = enable IT isac */
36#define INT_ISAC 0x20 /* 1 = IT isac en cours */
37#define INT_HSCX_EN 0x1 /* 1 = enable IT hscx */
38#define INT_HSCX 0x4 /* 1 = IT hscx en cours */
39#define INT_PCI_EN 0x40 /* 1 = enable IT PCI */
40#define INT_IPAC_EN 0x3 /* enable IT ipac */
41
42
43#define byteout(addr,val) outb(val,addr)
44#define bytein(addr) inb(addr)
45
46static inline u_char
47readreg(unsigned int adr, u_short off)
48{
49 return bytein(adr + off);
50}
51
52static inline void
53writereg(unsigned int adr, u_short off, u_char data)
54{
55 byteout(adr + off, data);
56}
57
58
59static inline void
60read_fifo(unsigned int adr, u_char * data, int size)
61{
62 insb(adr, data, size);
63}
64
65static void
66write_fifo(unsigned int adr, u_char * data, int size)
67{
68 outsb(adr, data, size);
69}
70
71static inline u_char
72readreg_ipac(unsigned int adr, u_short off)
73{
74 register u_char ret;
75
76 byteout(adr, off);
77 ret = bytein(adr + 4);
78 return ret;
79}
80
81static inline void
82writereg_ipac(unsigned int adr, u_short off, u_char data)
83{
84 byteout(adr, off);
85 byteout(adr + 4, data);
86}
87
88
89static inline void
90read_fifo_ipac(unsigned int adr, u_short off, u_char * data, int size)
91{
92 byteout(adr, off);
93 insb(adr + 4, data, size);
94}
95
96static void
97write_fifo_ipac(unsigned int adr, u_short off, u_char * data, int size)
98{
99 byteout(adr, off);
100 outsb(adr + 4, data, size);
101}
102
103/* Interface functions */
104
105static u_char
106ReadISAC(struct IsdnCardState *cs, u_char offset)
107{
108 u_short off2 = offset;
109
110 switch (cs->subtyp) {
111 case R647:
112 off2 = ((off2 << 8 & 0xf000) | (off2 & 0xf));
113 case R685:
114 return (readreg(cs->hw.gazel.isac, off2));
115 case R753:
116 case R742:
117 return (readreg_ipac(cs->hw.gazel.ipac, 0x80 + off2));
118 }
119 return 0;
120}
121
122static void
123WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
124{
125 u_short off2 = offset;
126
127 switch (cs->subtyp) {
128 case R647:
129 off2 = ((off2 << 8 & 0xf000) | (off2 & 0xf));
130 case R685:
131 writereg(cs->hw.gazel.isac, off2, value);
132 break;
133 case R753:
134 case R742:
135 writereg_ipac(cs->hw.gazel.ipac, 0x80 + off2, value);
136 break;
137 }
138}
139
140static void
141ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
142{
143 switch (cs->subtyp) {
144 case R647:
145 case R685:
146 read_fifo(cs->hw.gazel.isacfifo, data, size);
147 break;
148 case R753:
149 case R742:
150 read_fifo_ipac(cs->hw.gazel.ipac, 0x80, data, size);
151 break;
152 }
153}
154
155static void
156WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
157{
158 switch (cs->subtyp) {
159 case R647:
160 case R685:
161 write_fifo(cs->hw.gazel.isacfifo, data, size);
162 break;
163 case R753:
164 case R742:
165 write_fifo_ipac(cs->hw.gazel.ipac, 0x80, data, size);
166 break;
167 }
168}
169
170static void
171ReadHSCXfifo(struct IsdnCardState *cs, int hscx, u_char * data, int size)
172{
173 switch (cs->subtyp) {
174 case R647:
175 case R685:
176 read_fifo(cs->hw.gazel.hscxfifo[hscx], data, size);
177 break;
178 case R753:
179 case R742:
180 read_fifo_ipac(cs->hw.gazel.ipac, hscx * 0x40, data, size);
181 break;
182 }
183}
184
185static void
186WriteHSCXfifo(struct IsdnCardState *cs, int hscx, u_char * data, int size)
187{
188 switch (cs->subtyp) {
189 case R647:
190 case R685:
191 write_fifo(cs->hw.gazel.hscxfifo[hscx], data, size);
192 break;
193 case R753:
194 case R742:
195 write_fifo_ipac(cs->hw.gazel.ipac, hscx * 0x40, data, size);
196 break;
197 }
198}
199
200static u_char
201ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
202{
203 u_short off2 = offset;
204
205 switch (cs->subtyp) {
206 case R647:
207 off2 = ((off2 << 8 & 0xf000) | (off2 & 0xf));
208 case R685:
209 return (readreg(cs->hw.gazel.hscx[hscx], off2));
210 case R753:
211 case R742:
212 return (readreg_ipac(cs->hw.gazel.ipac, hscx * 0x40 + off2));
213 }
214 return 0;
215}
216
217static void
218WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
219{
220 u_short off2 = offset;
221
222 switch (cs->subtyp) {
223 case R647:
224 off2 = ((off2 << 8 & 0xf000) | (off2 & 0xf));
225 case R685:
226 writereg(cs->hw.gazel.hscx[hscx], off2, value);
227 break;
228 case R753:
229 case R742:
230 writereg_ipac(cs->hw.gazel.ipac, hscx * 0x40 + off2, value);
231 break;
232 }
233}
234
235/*
236 * fast interrupt HSCX stuff goes here
237 */
238
239#define READHSCX(cs, nr, reg) ReadHSCX(cs, nr, reg)
240#define WRITEHSCX(cs, nr, reg, data) WriteHSCX(cs, nr, reg, data)
241#define READHSCXFIFO(cs, nr, ptr, cnt) ReadHSCXfifo(cs, nr, ptr, cnt)
242#define WRITEHSCXFIFO(cs, nr, ptr, cnt) WriteHSCXfifo(cs, nr, ptr, cnt)
243
244#include "hscx_irq.c"
245
246static irqreturn_t
247gazel_interrupt(int intno, void *dev_id, struct pt_regs *regs)
248{
249#define MAXCOUNT 5
250 struct IsdnCardState *cs = dev_id;
251 u_char valisac, valhscx;
252 int count = 0;
253 u_long flags;
254
255 spin_lock_irqsave(&cs->lock, flags);
256 do {
257 valhscx = ReadHSCX(cs, 1, HSCX_ISTA);
258 if (valhscx)
259 hscx_int_main(cs, valhscx);
260 valisac = ReadISAC(cs, ISAC_ISTA);
261 if (valisac)
262 isac_interrupt(cs, valisac);
263 count++;
264 } while ((valhscx || valisac) && (count < MAXCOUNT));
265
266 WriteHSCX(cs, 0, HSCX_MASK, 0xFF);
267 WriteHSCX(cs, 1, HSCX_MASK, 0xFF);
268 WriteISAC(cs, ISAC_MASK, 0xFF);
269 WriteISAC(cs, ISAC_MASK, 0x0);
270 WriteHSCX(cs, 0, HSCX_MASK, 0x0);
271 WriteHSCX(cs, 1, HSCX_MASK, 0x0);
272 spin_unlock_irqrestore(&cs->lock, flags);
273 return IRQ_HANDLED;
274}
275
276
277static irqreturn_t
278gazel_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs)
279{
280 struct IsdnCardState *cs = dev_id;
281 u_char ista, val;
282 int count = 0;
283 u_long flags;
284
285 spin_lock_irqsave(&cs->lock, flags);
286 ista = ReadISAC(cs, IPAC_ISTA - 0x80);
287 do {
288 if (ista & 0x0f) {
289 val = ReadHSCX(cs, 1, HSCX_ISTA);
290 if (ista & 0x01)
291 val |= 0x01;
292 if (ista & 0x04)
293 val |= 0x02;
294 if (ista & 0x08)
295 val |= 0x04;
296 if (val) {
297 hscx_int_main(cs, val);
298 }
299 }
300 if (ista & 0x20) {
301 val = 0xfe & ReadISAC(cs, ISAC_ISTA);
302 if (val) {
303 isac_interrupt(cs, val);
304 }
305 }
306 if (ista & 0x10) {
307 val = 0x01;
308 isac_interrupt(cs, val);
309 }
310 ista = ReadISAC(cs, IPAC_ISTA - 0x80);
311 count++;
312 }
313 while ((ista & 0x3f) && (count < MAXCOUNT));
314
315 WriteISAC(cs, IPAC_MASK - 0x80, 0xFF);
316 WriteISAC(cs, IPAC_MASK - 0x80, 0xC0);
317 spin_unlock_irqrestore(&cs->lock, flags);
318 return IRQ_HANDLED;
319}
320void
321release_io_gazel(struct IsdnCardState *cs)
322{
323 unsigned int i;
324
325 switch (cs->subtyp) {
326 case R647:
327 for (i = 0x0000; i < 0xC000; i += 0x1000)
328 release_region(i + cs->hw.gazel.hscx[0], 16);
329 release_region(0xC000 + cs->hw.gazel.hscx[0], 1);
330 break;
331
332 case R685:
333 release_region(cs->hw.gazel.hscx[0], 0x100);
334 release_region(cs->hw.gazel.cfg_reg, 0x80);
335 break;
336
337 case R753:
338 release_region(cs->hw.gazel.ipac, 0x8);
339 release_region(cs->hw.gazel.cfg_reg, 0x80);
340 break;
341
342 case R742:
343 release_region(cs->hw.gazel.ipac, 8);
344 break;
345 }
346}
347
348static int
349reset_gazel(struct IsdnCardState *cs)
350{
351 unsigned long plxcntrl, addr = cs->hw.gazel.cfg_reg;
352
353 switch (cs->subtyp) {
354 case R647:
355 writereg(addr, 0, 0);
356 HZDELAY(10);
357 writereg(addr, 0, 1);
358 HZDELAY(2);
359 break;
360 case R685:
361 plxcntrl = inl(addr + PLX_CNTRL);
362 plxcntrl |= (RESET_9050 + RESET_GAZEL);
363 outl(plxcntrl, addr + PLX_CNTRL);
364 plxcntrl &= ~(RESET_9050 + RESET_GAZEL);
365 HZDELAY(4);
366 outl(plxcntrl, addr + PLX_CNTRL);
367 HZDELAY(10);
368 outb(INT_ISAC_EN + INT_HSCX_EN + INT_PCI_EN, addr + PLX_INCSR);
369 break;
370 case R753:
371 plxcntrl = inl(addr + PLX_CNTRL);
372 plxcntrl |= (RESET_9050 + RESET_GAZEL);
373 outl(plxcntrl, addr + PLX_CNTRL);
374 plxcntrl &= ~(RESET_9050 + RESET_GAZEL);
375 WriteISAC(cs, IPAC_POTA2 - 0x80, 0x20);
376 HZDELAY(4);
377 outl(plxcntrl, addr + PLX_CNTRL);
378 HZDELAY(10);
379 WriteISAC(cs, IPAC_POTA2 - 0x80, 0x00);
380 WriteISAC(cs, IPAC_ACFG - 0x80, 0xff);
381 WriteISAC(cs, IPAC_AOE - 0x80, 0x0);
382 WriteISAC(cs, IPAC_MASK - 0x80, 0xff);
383 WriteISAC(cs, IPAC_CONF - 0x80, 0x1);
384 outb(INT_IPAC_EN + INT_PCI_EN, addr + PLX_INCSR);
385 WriteISAC(cs, IPAC_MASK - 0x80, 0xc0);
386 break;
387 case R742:
388 WriteISAC(cs, IPAC_POTA2 - 0x80, 0x20);
389 HZDELAY(4);
390 WriteISAC(cs, IPAC_POTA2 - 0x80, 0x00);
391 WriteISAC(cs, IPAC_ACFG - 0x80, 0xff);
392 WriteISAC(cs, IPAC_AOE - 0x80, 0x0);
393 WriteISAC(cs, IPAC_MASK - 0x80, 0xff);
394 WriteISAC(cs, IPAC_CONF - 0x80, 0x1);
395 WriteISAC(cs, IPAC_MASK - 0x80, 0xc0);
396 break;
397 }
398 return (0);
399}
400
401static int
402Gazel_card_msg(struct IsdnCardState *cs, int mt, void *arg)
403{
404 u_long flags;
405
406 switch (mt) {
407 case CARD_RESET:
408 spin_lock_irqsave(&cs->lock, flags);
409 reset_gazel(cs);
410 spin_unlock_irqrestore(&cs->lock, flags);
411 return (0);
412 case CARD_RELEASE:
413 release_io_gazel(cs);
414 return (0);
415 case CARD_INIT:
416 spin_lock_irqsave(&cs->lock, flags);
417 inithscxisac(cs, 1);
418 if ((cs->subtyp==R647)||(cs->subtyp==R685)) {
419 int i;
420 for (i=0;i<(2+MAX_WAITING_CALLS);i++) {
421 cs->bcs[i].hw.hscx.tsaxr0 = 0x1f;
422 cs->bcs[i].hw.hscx.tsaxr1 = 0x23;
423 }
424 }
425 spin_unlock_irqrestore(&cs->lock, flags);
426 return (0);
427 case CARD_TEST:
428 return (0);
429 }
430 return (0);
431}
432
433static int
434reserve_regions(struct IsdnCard *card, struct IsdnCardState *cs)
435{
436 unsigned int i, j, base = 0, adr = 0, len = 0;
437
438 switch (cs->subtyp) {
439 case R647:
440 base = cs->hw.gazel.hscx[0];
441 if (!request_region(adr = (0xC000 + base), len = 1, "gazel"))
442 goto error;
443 for (i = 0x0000; i < 0xC000; i += 0x1000) {
444 if (!request_region(adr = (i + base), len = 16, "gazel"))
445 goto error;
446 }
447 if (i != 0xC000) {
448 for (j = 0; j < i; j+= 0x1000)
449 release_region(j + base, 16);
450 release_region(0xC000 + base, 1);
451 goto error;
452 }
453 break;
454
455 case R685:
456 if (!request_region(adr = cs->hw.gazel.hscx[0], len = 0x100, "gazel"))
457 goto error;
458 if (!request_region(adr = cs->hw.gazel.cfg_reg, len = 0x80, "gazel")) {
459 release_region(cs->hw.gazel.hscx[0],0x100);
460 goto error;
461 }
462 break;
463
464 case R753:
465 if (!request_region(adr = cs->hw.gazel.ipac, len = 0x8, "gazel"))
466 goto error;
467 if (!request_region(adr = cs->hw.gazel.cfg_reg, len = 0x80, "gazel")) {
468 release_region(cs->hw.gazel.ipac, 8);
469 goto error;
470 }
471 break;
472
473 case R742:
474 if (!request_region(adr = cs->hw.gazel.ipac, len = 0x8, "gazel"))
475 goto error;
476 break;
477 }
478
479 return 0;
480
481 error:
482 printk(KERN_WARNING "Gazel: %s io ports 0x%x-0x%x already in use\n",
483 CardType[cs->typ], adr, adr + len);
484 return 1;
485}
486
487static int __init
488setup_gazelisa(struct IsdnCard *card, struct IsdnCardState *cs)
489{
490 printk(KERN_INFO "Gazel: ISA PnP card automatic recognition\n");
491 // we got an irq parameter, assume it is an ISA card
492 // R742 decodes address even in not started...
493 // R647 returns FF if not present or not started
494 // eventually needs improvment
495 if (readreg_ipac(card->para[1], IPAC_ID) == 1)
496 cs->subtyp = R742;
497 else
498 cs->subtyp = R647;
499
500 setup_isac(cs);
501 cs->hw.gazel.cfg_reg = card->para[1] + 0xC000;
502 cs->hw.gazel.ipac = card->para[1];
503 cs->hw.gazel.isac = card->para[1] + 0x8000;
504 cs->hw.gazel.hscx[0] = card->para[1];
505 cs->hw.gazel.hscx[1] = card->para[1] + 0x4000;
506 cs->irq = card->para[0];
507 cs->hw.gazel.isacfifo = cs->hw.gazel.isac;
508 cs->hw.gazel.hscxfifo[0] = cs->hw.gazel.hscx[0];
509 cs->hw.gazel.hscxfifo[1] = cs->hw.gazel.hscx[1];
510
511 switch (cs->subtyp) {
512 case R647:
513 printk(KERN_INFO "Gazel: Card ISA R647/R648 found\n");
514 cs->dc.isac.adf2 = 0x87;
515 printk(KERN_INFO
516 "Gazel: config irq:%d isac:0x%X cfg:0x%X\n",
517 cs->irq, cs->hw.gazel.isac, cs->hw.gazel.cfg_reg);
518 printk(KERN_INFO
519 "Gazel: hscx A:0x%X hscx B:0x%X\n",
520 cs->hw.gazel.hscx[0], cs->hw.gazel.hscx[1]);
521
522 break;
523 case R742:
524 printk(KERN_INFO "Gazel: Card ISA R742 found\n");
525 test_and_set_bit(HW_IPAC, &cs->HW_Flags);
526 printk(KERN_INFO
527 "Gazel: config irq:%d ipac:0x%X\n",
528 cs->irq, cs->hw.gazel.ipac);
529 break;
530 }
531
532 return (0);
533}
534
535static struct pci_dev *dev_tel __initdata = NULL;
536
537static int __init
538setup_gazelpci(struct IsdnCardState *cs)
539{
540 u_int pci_ioaddr0 = 0, pci_ioaddr1 = 0;
541 u_char pci_irq = 0, found;
542 u_int nbseek, seekcard;
543
544 printk(KERN_WARNING "Gazel: PCI card automatic recognition\n");
545
546 found = 0;
547 seekcard = PCI_DEVICE_ID_PLX_R685;
548 for (nbseek = 0; nbseek < 3; nbseek++) {
549 if ((dev_tel = pci_find_device(PCI_VENDOR_ID_PLX, seekcard, dev_tel))) {
550 if (pci_enable_device(dev_tel))
551 return 1;
552 pci_irq = dev_tel->irq;
553 pci_ioaddr0 = pci_resource_start(dev_tel, 1);
554 pci_ioaddr1 = pci_resource_start(dev_tel, 2);
555 found = 1;
556 }
557 if (found)
558 break;
559 else {
560 switch (seekcard) {
561 case PCI_DEVICE_ID_PLX_R685:
562 seekcard = PCI_DEVICE_ID_PLX_R753;
563 break;
564 case PCI_DEVICE_ID_PLX_R753:
565 seekcard = PCI_DEVICE_ID_PLX_DJINN_ITOO;
566 break;
567 }
568 }
569 }
570 if (!found) {
571 printk(KERN_WARNING "Gazel: No PCI card found\n");
572 return (1);
573 }
574 if (!pci_irq) {
575 printk(KERN_WARNING "Gazel: No IRQ for PCI card found\n");
576 return 1;
577 }
578 cs->hw.gazel.pciaddr[0] = pci_ioaddr0;
579 cs->hw.gazel.pciaddr[1] = pci_ioaddr1;
580 setup_isac(cs);
581 pci_ioaddr1 &= 0xfffe;
582 cs->hw.gazel.cfg_reg = pci_ioaddr0 & 0xfffe;
583 cs->hw.gazel.ipac = pci_ioaddr1;
584 cs->hw.gazel.isac = pci_ioaddr1 + 0x80;
585 cs->hw.gazel.hscx[0] = pci_ioaddr1;
586 cs->hw.gazel.hscx[1] = pci_ioaddr1 + 0x40;
587 cs->hw.gazel.isacfifo = cs->hw.gazel.isac;
588 cs->hw.gazel.hscxfifo[0] = cs->hw.gazel.hscx[0];
589 cs->hw.gazel.hscxfifo[1] = cs->hw.gazel.hscx[1];
590 cs->irq = pci_irq;
591 cs->irq_flags |= SA_SHIRQ;
592
593 switch (seekcard) {
594 case PCI_DEVICE_ID_PLX_R685:
595 printk(KERN_INFO "Gazel: Card PCI R685 found\n");
596 cs->subtyp = R685;
597 cs->dc.isac.adf2 = 0x87;
598 printk(KERN_INFO
599 "Gazel: config irq:%d isac:0x%X cfg:0x%X\n",
600 cs->irq, cs->hw.gazel.isac, cs->hw.gazel.cfg_reg);
601 printk(KERN_INFO
602 "Gazel: hscx A:0x%X hscx B:0x%X\n",
603 cs->hw.gazel.hscx[0], cs->hw.gazel.hscx[1]);
604 break;
605 case PCI_DEVICE_ID_PLX_R753:
606 case PCI_DEVICE_ID_PLX_DJINN_ITOO:
607 printk(KERN_INFO "Gazel: Card PCI R753 found\n");
608 cs->subtyp = R753;
609 test_and_set_bit(HW_IPAC, &cs->HW_Flags);
610 printk(KERN_INFO
611 "Gazel: config irq:%d ipac:0x%X cfg:0x%X\n",
612 cs->irq, cs->hw.gazel.ipac, cs->hw.gazel.cfg_reg);
613 break;
614 }
615
616 return (0);
617}
618
619int __init
620setup_gazel(struct IsdnCard *card)
621{
622 struct IsdnCardState *cs = card->cs;
623 char tmp[64];
624 u_char val;
625
626 strcpy(tmp, gazel_revision);
627 printk(KERN_INFO "Gazel: Driver Revision %s\n", HiSax_getrev(tmp));
628
629 if (cs->typ != ISDN_CTYPE_GAZEL)
630 return (0);
631
632 if (card->para[0]) {
633 if (setup_gazelisa(card, cs))
634 return (0);
635 } else {
636
637#ifdef CONFIG_PCI
638 if (setup_gazelpci(cs))
639 return (0);
640#else
641 printk(KERN_WARNING "Gazel: Card PCI requested and NO_PCI_BIOS, unable to config\n");
642 return (0);
643#endif /* CONFIG_PCI */
644 }
645
646 if (reserve_regions(card, cs)) {
647 return (0);
648 }
649 if (reset_gazel(cs)) {
650 printk(KERN_WARNING "Gazel: wrong IRQ\n");
651 release_io_gazel(cs);
652 return (0);
653 }
654 cs->readisac = &ReadISAC;
655 cs->writeisac = &WriteISAC;
656 cs->readisacfifo = &ReadISACfifo;
657 cs->writeisacfifo = &WriteISACfifo;
658 cs->BC_Read_Reg = &ReadHSCX;
659 cs->BC_Write_Reg = &WriteHSCX;
660 cs->BC_Send_Data = &hscx_fill_fifo;
661 cs->cardmsg = &Gazel_card_msg;
662
663 switch (cs->subtyp) {
664 case R647:
665 case R685:
666 cs->irq_func = &gazel_interrupt;
667 ISACVersion(cs, "Gazel:");
668 if (HscxVersion(cs, "Gazel:")) {
669 printk(KERN_WARNING
670 "Gazel: wrong HSCX versions check IO address\n");
671 release_io_gazel(cs);
672 return (0);
673 }
674 break;
675 case R742:
676 case R753:
677 cs->irq_func = &gazel_interrupt_ipac;
678 val = ReadISAC(cs, IPAC_ID - 0x80);
679 printk(KERN_INFO "Gazel: IPAC version %x\n", val);
680 break;
681 }
682
683 return (1);
684}
diff --git a/drivers/isdn/hisax/hfc4s8s_l1.c b/drivers/isdn/hisax/hfc4s8s_l1.c
new file mode 100644
index 000000000000..1ac46c26b936
--- /dev/null
+++ b/drivers/isdn/hisax/hfc4s8s_l1.c
@@ -0,0 +1,1714 @@
1/*************************************************************************/
2/* $Id: hfc4s8s_l1.c,v 1.10 2005/02/09 16:31:09 martinb1 Exp $ */
3/* HFC-4S/8S low layer interface for Cologne Chip HFC-4S/8S isdn chips */
4/* The low layer (L1) is implemented as a loadable module for usage with */
5/* the HiSax isdn driver for passive cards. */
6/* */
7/* Author: Werner Cornelius */
8/* (C) 2003 Cornelius Consult (werner@cornelius-consult.de) */
9/* */
10/* Driver maintained by Cologne Chip */
11/* - Martin Bachem, support@colognechip.com */
12/* */
13/* This driver only works with chip revisions >= 1, older revision 0 */
14/* engineering samples (only first manufacturer sample cards) will not */
15/* work and are rejected by the driver. */
16/* */
17/* This file distributed under the GNU GPL. */
18/* */
19/* See Version History at the end of this file */
20/* */
21/*************************************************************************/
22
23#include <linux/module.h>
24#include <linux/init.h>
25#include <linux/config.h>
26#include <linux/pci.h>
27#include <linux/interrupt.h>
28#include <linux/delay.h>
29#include <linux/timer.h>
30#include <linux/skbuff.h>
31#include <linux/wait.h>
32#include "hisax_if.h"
33#include "hfc4s8s_l1.h"
34
35static const char hfc4s8s_rev[] = "Revision: 1.10";
36
37/***************************************************************/
38/* adjustable transparent mode fifo threshold */
39/* The value defines the used fifo threshold with the equation */
40/* */
41/* notify number of bytes = 2 * 2 ^ TRANS_FIFO_THRES */
42/* */
43/* The default value is 5 which results in a buffer size of 64 */
44/* and an interrupt rate of 8ms. */
45/* The maximum value is 7 due to fifo size restrictions. */
46/* Values below 3-4 are not recommended due to high interrupt */
47/* load of the processor. For non critical applications the */
48/* value should be raised to 7 to reduce any interrupt overhead*/
49/***************************************************************/
50#define TRANS_FIFO_THRES 5
51
52/*************/
53/* constants */
54/*************/
55#define CLOCKMODE_0 0 /* ext. 24.576 MhZ clk freq, int. single clock mode */
56#define CLOCKMODE_1 1 /* ext. 49.576 MhZ clk freq, int. single clock mode */
57#define CHIP_ID_SHIFT 4
58#define HFC_MAX_ST 8
59#define MAX_D_FRAME_SIZE 270
60#define MAX_B_FRAME_SIZE 1536
61#define TRANS_TIMER_MODE (TRANS_FIFO_THRES & 0xf)
62#define TRANS_FIFO_BYTES (2 << TRANS_FIFO_THRES)
63#define MAX_F_CNT 0x0f
64
65#define CLKDEL_NT 0x6c
66#define CLKDEL_TE 0xf
67#define CTRL0_NT 4
68#define CTRL0_TE 0
69
70#define L1_TIMER_T4 2 /* minimum in jiffies */
71#define L1_TIMER_T3 (7 * HZ) /* activation timeout */
72#define L1_TIMER_T1 ((120 * HZ) / 1000) /* NT mode deactivation timeout */
73
74
75/******************/
76/* types and vars */
77/******************/
78static int card_cnt;
79
80/* private driver_data */
81typedef struct {
82 int chip_id;
83 int clock_mode;
84 int max_st_ports;
85 char *device_name;
86} hfc4s8s_param;
87
88static struct pci_device_id hfc4s8s_ids[] = {
89 {.vendor = PCI_VENDOR_ID_CCD,
90 .device = PCI_DEVICE_ID_4S,
91 .subvendor = 0x1397,
92 .subdevice = 0x08b4,
93 .driver_data =
94 (unsigned long) &((hfc4s8s_param) {CHIP_ID_4S, CLOCKMODE_0, 4,
95 "HFC-4S Evaluation Board"}),
96 },
97 {.vendor = PCI_VENDOR_ID_CCD,
98 .device = PCI_DEVICE_ID_8S,
99 .subvendor = 0x1397,
100 .subdevice = 0x16b8,
101 .driver_data =
102 (unsigned long) &((hfc4s8s_param) {CHIP_ID_8S, CLOCKMODE_0, 8,
103 "HFC-8S Evaluation Board"}),
104 },
105 {.vendor = PCI_VENDOR_ID_CCD,
106 .device = PCI_DEVICE_ID_4S,
107 .subvendor = 0x1397,
108 .subdevice = 0xb520,
109 .driver_data =
110 (unsigned long) &((hfc4s8s_param) {CHIP_ID_4S, CLOCKMODE_1, 4,
111 "IOB4ST"}),
112 },
113 {.vendor = PCI_VENDOR_ID_CCD,
114 .device = PCI_DEVICE_ID_8S,
115 .subvendor = 0x1397,
116 .subdevice = 0xb522,
117 .driver_data =
118 (unsigned long) &((hfc4s8s_param) {CHIP_ID_8S, CLOCKMODE_1, 8,
119 "IOB8ST"}),
120 },
121 {}
122};
123
124MODULE_DEVICE_TABLE(pci, hfc4s8s_ids);
125
126MODULE_AUTHOR("Werner Cornelius, werner@cornelius-consult.de");
127MODULE_DESCRIPTION("ISDN layer 1 for Cologne Chip HFC-4S/8S chips");
128MODULE_LICENSE("GPL");
129
130/***********/
131/* layer 1 */
132/***********/
133struct hfc4s8s_btype {
134 spinlock_t lock;
135 struct hisax_b_if b_if;
136 struct hfc4s8s_l1 *l1p;
137 struct sk_buff_head tx_queue;
138 struct sk_buff *tx_skb;
139 struct sk_buff *rx_skb;
140 __u8 *rx_ptr;
141 int tx_cnt;
142 int bchan;
143 int mode;
144};
145
146struct _hfc4s8s_hw;
147
148struct hfc4s8s_l1 {
149 spinlock_t lock;
150 struct _hfc4s8s_hw *hw; /* pointer to hardware area */
151 int l1_state; /* actual l1 state */
152 struct timer_list l1_timer; /* layer 1 timer structure */
153 int nt_mode; /* set to nt mode */
154 int st_num; /* own index */
155 int enabled; /* interface is enabled */
156 struct sk_buff_head d_tx_queue; /* send queue */
157 int tx_cnt; /* bytes to send */
158 struct hisax_d_if d_if; /* D-channel interface */
159 struct hfc4s8s_btype b_ch[2]; /* B-channel data */
160 struct hisax_b_if *b_table[2];
161};
162
163/**********************/
164/* hardware structure */
165/**********************/
166typedef struct _hfc4s8s_hw {
167 spinlock_t lock;
168
169 int cardnum;
170 int ifnum;
171 int iobase;
172 int nt_mode;
173 u_char *membase;
174 u_char *hw_membase;
175 void *pdev;
176 int max_fifo;
177 hfc4s8s_param driver_data;
178 int irq;
179 int fifo_sched_cnt;
180 struct work_struct tqueue;
181 struct hfc4s8s_l1 l1[HFC_MAX_ST];
182 char card_name[60];
183 struct {
184 u_char r_irq_ctrl;
185 u_char r_ctrl0;
186 volatile u_char r_irq_statech; /* active isdn l1 status */
187 u_char r_irqmsk_statchg; /* enabled isdn status ints */
188 u_char r_irq_fifo_blx[8]; /* fifo status registers */
189 u_char fifo_rx_trans_enables[8]; /* mask for enabled transparent rx fifos */
190 u_char fifo_slow_timer_service[8]; /* mask for fifos needing slower timer service */
191 volatile u_char r_irq_oview; /* contents of overview register */
192 volatile u_char timer_irq;
193 int timer_usg_cnt; /* number of channels using timer */
194 } mr;
195} hfc4s8s_hw;
196
197
198
199/***************************/
200/* inline function defines */
201/***************************/
202#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM /* inline functions mempry mapped */
203
204/* memory write and dummy IO read to avoid PCI byte merge problems */
205#define Write_hfc8(a,b,c) {(*((volatile u_char *)(a->membase+b)) = c); inb(a->iobase+4);}
206/* memory write without dummy IO access for fifo data access */
207#define fWrite_hfc8(a,b,c) (*((volatile u_char *)(a->membase+b)) = c)
208#define Read_hfc8(a,b) (*((volatile u_char *)(a->membase+b)))
209#define Write_hfc16(a,b,c) (*((volatile unsigned short *)(a->membase+b)) = c)
210#define Read_hfc16(a,b) (*((volatile unsigned short *)(a->membase+b)))
211#define Write_hfc32(a,b,c) (*((volatile unsigned long *)(a->membase+b)) = c)
212#define Read_hfc32(a,b) (*((volatile unsigned long *)(a->membase+b)))
213#define wait_busy(a) {while ((Read_hfc8(a, R_STATUS) & M_BUSY));}
214#define PCI_ENA_MEMIO 0x03
215
216#else
217
218/* inline functions io mapped */
219static inline void
220SetRegAddr(hfc4s8s_hw * a, u_char b)
221{
222 outb(b, (a->iobase) + 4);
223}
224
225static inline u_char
226GetRegAddr(hfc4s8s_hw * a)
227{
228 return (inb((volatile u_int) (a->iobase + 4)));
229}
230
231
232static inline void
233Write_hfc8(hfc4s8s_hw * a, u_char b, u_char c)
234{
235 SetRegAddr(a, b);
236 outb(c, a->iobase);
237}
238
239static inline void
240fWrite_hfc8(hfc4s8s_hw * a, u_char c)
241{
242 outb(c, a->iobase);
243}
244
245static inline void
246Write_hfc16(hfc4s8s_hw * a, u_char b, u_short c)
247{
248 SetRegAddr(a, b);
249 outw(c, a->iobase);
250}
251
252static inline void
253Write_hfc32(hfc4s8s_hw * a, u_char b, u_long c)
254{
255 SetRegAddr(a, b);
256 outl(c, a->iobase);
257}
258
259static inline void
260fWrite_hfc32(hfc4s8s_hw * a, u_long c)
261{
262 outl(c, a->iobase);
263}
264
265static inline u_char
266Read_hfc8(hfc4s8s_hw * a, u_char b)
267{
268 SetRegAddr(a, b);
269 return (inb((volatile u_int) a->iobase));
270}
271
272static inline u_char
273fRead_hfc8(hfc4s8s_hw * a)
274{
275 return (inb((volatile u_int) a->iobase));
276}
277
278
279static inline u_short
280Read_hfc16(hfc4s8s_hw * a, u_char b)
281{
282 SetRegAddr(a, b);
283 return (inw((volatile u_int) a->iobase));
284}
285
286static inline u_long
287Read_hfc32(hfc4s8s_hw * a, u_char b)
288{
289 SetRegAddr(a, b);
290 return (inl((volatile u_int) a->iobase));
291}
292
293static inline u_long
294fRead_hfc32(hfc4s8s_hw * a)
295{
296 return (inl((volatile u_int) a->iobase));
297}
298
299static inline void
300wait_busy(hfc4s8s_hw * a)
301{
302 SetRegAddr(a, R_STATUS);
303 while (inb((volatile u_int) a->iobase) & M_BUSY);
304}
305
306#define PCI_ENA_REGIO 0x01
307
308#endif /* CONFIG_HISAX_HFC4S8S_PCIMEM */
309
310/******************************************************/
311/* function to read critical counter registers that */
312/* may be udpated by the chip during read */
313/******************************************************/
314static volatile u_char
315Read_hfc8_stable(hfc4s8s_hw * hw, int reg)
316{
317 u_char ref8;
318 u_char in8;
319 ref8 = Read_hfc8(hw, reg);
320 while (((in8 = Read_hfc8(hw, reg)) != ref8)) {
321 ref8 = in8;
322 }
323 return in8;
324}
325
326static volatile int
327Read_hfc16_stable(hfc4s8s_hw * hw, int reg)
328{
329 int ref16;
330 int in16;
331
332 ref16 = Read_hfc16(hw, reg);
333 while (((in16 = Read_hfc16(hw, reg)) != ref16)) {
334 ref16 = in16;
335 }
336 return in16;
337}
338
339/*****************************/
340/* D-channel call from HiSax */
341/*****************************/
342static void
343dch_l2l1(struct hisax_d_if *iface, int pr, void *arg)
344{
345 struct hfc4s8s_l1 *l1 = iface->ifc.priv;
346 struct sk_buff *skb = (struct sk_buff *) arg;
347 u_long flags;
348
349 switch (pr) {
350
351 case (PH_DATA | REQUEST):
352 if (!l1->enabled) {
353 dev_kfree_skb(skb);
354 break;
355 }
356 spin_lock_irqsave(&l1->lock, flags);
357 skb_queue_tail(&l1->d_tx_queue, skb);
358 if ((skb_queue_len(&l1->d_tx_queue) == 1) &&
359 (l1->tx_cnt <= 0)) {
360 l1->hw->mr.r_irq_fifo_blx[l1->st_num] |=
361 0x10;
362 spin_unlock_irqrestore(&l1->lock, flags);
363 schedule_work(&l1->hw->tqueue);
364 } else
365 spin_unlock_irqrestore(&l1->lock, flags);
366 break;
367
368 case (PH_ACTIVATE | REQUEST):
369 if (!l1->enabled)
370 break;
371 if (!l1->nt_mode) {
372 if (l1->l1_state < 6) {
373 spin_lock_irqsave(&l1->lock,
374 flags);
375
376 Write_hfc8(l1->hw, R_ST_SEL,
377 l1->st_num);
378 Write_hfc8(l1->hw, A_ST_WR_STA,
379 0x60);
380 mod_timer(&l1->l1_timer,
381 jiffies + L1_TIMER_T3);
382 spin_unlock_irqrestore(&l1->lock,
383 flags);
384 } else if (l1->l1_state == 7)
385 l1->d_if.ifc.l1l2(&l1->d_if.ifc,
386 PH_ACTIVATE |
387 INDICATION,
388 NULL);
389 } else {
390 if (l1->l1_state != 3) {
391 spin_lock_irqsave(&l1->lock,
392 flags);
393 Write_hfc8(l1->hw, R_ST_SEL,
394 l1->st_num);
395 Write_hfc8(l1->hw, A_ST_WR_STA,
396 0x60);
397 spin_unlock_irqrestore(&l1->lock,
398 flags);
399 } else if (l1->l1_state == 3)
400 l1->d_if.ifc.l1l2(&l1->d_if.ifc,
401 PH_ACTIVATE |
402 INDICATION,
403 NULL);
404 }
405 break;
406
407 default:
408 printk(KERN_INFO
409 "HFC-4S/8S: Unknown D-chan cmd 0x%x received, ignored\n",
410 pr);
411 break;
412 }
413 if (!l1->enabled)
414 l1->d_if.ifc.l1l2(&l1->d_if.ifc,
415 PH_DEACTIVATE | INDICATION, NULL);
416} /* dch_l2l1 */
417
418/*****************************/
419/* B-channel call from HiSax */
420/*****************************/
421static void
422bch_l2l1(struct hisax_if *ifc, int pr, void *arg)
423{
424 struct hfc4s8s_btype *bch = ifc->priv;
425 struct hfc4s8s_l1 *l1 = bch->l1p;
426 struct sk_buff *skb = (struct sk_buff *) arg;
427 int mode = (int) arg;
428 u_long flags;
429
430 switch (pr) {
431
432 case (PH_DATA | REQUEST):
433 if (!l1->enabled || (bch->mode == L1_MODE_NULL)) {
434 dev_kfree_skb(skb);
435 break;
436 }
437 spin_lock_irqsave(&l1->lock, flags);
438 skb_queue_tail(&bch->tx_queue, skb);
439 if (!bch->tx_skb && (bch->tx_cnt <= 0)) {
440 l1->hw->mr.r_irq_fifo_blx[l1->st_num] |=
441 ((bch->bchan == 1) ? 1 : 4);
442 spin_unlock_irqrestore(&l1->lock, flags);
443 schedule_work(&l1->hw->tqueue);
444 } else
445 spin_unlock_irqrestore(&l1->lock, flags);
446 break;
447
448 case (PH_ACTIVATE | REQUEST):
449 case (PH_DEACTIVATE | REQUEST):
450 if (!l1->enabled)
451 break;
452 if (pr == (PH_DEACTIVATE | REQUEST))
453 mode = L1_MODE_NULL;
454
455 switch (mode) {
456 case L1_MODE_HDLC:
457 spin_lock_irqsave(&l1->lock,
458 flags);
459 l1->hw->mr.timer_usg_cnt++;
460 l1->hw->mr.
461 fifo_slow_timer_service[l1->
462 st_num]
463 |=
464 ((bch->bchan ==
465 1) ? 0x2 : 0x8);
466 Write_hfc8(l1->hw, R_FIFO,
467 (l1->st_num * 8 +
468 ((bch->bchan ==
469 1) ? 0 : 2)));
470 wait_busy(l1->hw);
471 Write_hfc8(l1->hw, A_CON_HDLC, 0xc); /* HDLC mode, flag fill, connect ST */
472 Write_hfc8(l1->hw, A_SUBCH_CFG, 0); /* 8 bits */
473 Write_hfc8(l1->hw, A_IRQ_MSK, 1); /* enable TX interrupts for hdlc */
474 Write_hfc8(l1->hw, A_INC_RES_FIFO, 2); /* reset fifo */
475 wait_busy(l1->hw);
476
477 Write_hfc8(l1->hw, R_FIFO,
478 (l1->st_num * 8 +
479 ((bch->bchan ==
480 1) ? 1 : 3)));
481 wait_busy(l1->hw);
482 Write_hfc8(l1->hw, A_CON_HDLC, 0xc); /* HDLC mode, flag fill, connect ST */
483 Write_hfc8(l1->hw, A_SUBCH_CFG, 0); /* 8 bits */
484 Write_hfc8(l1->hw, A_IRQ_MSK, 1); /* enable RX interrupts for hdlc */
485 Write_hfc8(l1->hw, A_INC_RES_FIFO, 2); /* reset fifo */
486
487 Write_hfc8(l1->hw, R_ST_SEL,
488 l1->st_num);
489 l1->hw->mr.r_ctrl0 |=
490 (bch->bchan & 3);
491 Write_hfc8(l1->hw, A_ST_CTRL0,
492 l1->hw->mr.r_ctrl0);
493 bch->mode = L1_MODE_HDLC;
494 spin_unlock_irqrestore(&l1->lock,
495 flags);
496
497 bch->b_if.ifc.l1l2(&bch->b_if.ifc,
498 PH_ACTIVATE |
499 INDICATION,
500 NULL);
501 break;
502
503 case L1_MODE_TRANS:
504 spin_lock_irqsave(&l1->lock,
505 flags);
506 l1->hw->mr.
507 fifo_rx_trans_enables[l1->
508 st_num]
509 |=
510 ((bch->bchan ==
511 1) ? 0x2 : 0x8);
512 l1->hw->mr.timer_usg_cnt++;
513 Write_hfc8(l1->hw, R_FIFO,
514 (l1->st_num * 8 +
515 ((bch->bchan ==
516 1) ? 0 : 2)));
517 wait_busy(l1->hw);
518 Write_hfc8(l1->hw, A_CON_HDLC, 0xf); /* Transparent mode, 1 fill, connect ST */
519 Write_hfc8(l1->hw, A_SUBCH_CFG, 0); /* 8 bits */
520 Write_hfc8(l1->hw, A_IRQ_MSK, 0); /* disable TX interrupts */
521 Write_hfc8(l1->hw, A_INC_RES_FIFO, 2); /* reset fifo */
522 wait_busy(l1->hw);
523
524 Write_hfc8(l1->hw, R_FIFO,
525 (l1->st_num * 8 +
526 ((bch->bchan ==
527 1) ? 1 : 3)));
528 wait_busy(l1->hw);
529 Write_hfc8(l1->hw, A_CON_HDLC, 0xf); /* Transparent mode, 1 fill, connect ST */
530 Write_hfc8(l1->hw, A_SUBCH_CFG, 0); /* 8 bits */
531 Write_hfc8(l1->hw, A_IRQ_MSK, 0); /* disable RX interrupts */
532 Write_hfc8(l1->hw, A_INC_RES_FIFO, 2); /* reset fifo */
533
534 Write_hfc8(l1->hw, R_ST_SEL,
535 l1->st_num);
536 l1->hw->mr.r_ctrl0 |=
537 (bch->bchan & 3);
538 Write_hfc8(l1->hw, A_ST_CTRL0,
539 l1->hw->mr.r_ctrl0);
540 bch->mode = L1_MODE_TRANS;
541 spin_unlock_irqrestore(&l1->lock,
542 flags);
543
544 bch->b_if.ifc.l1l2(&bch->b_if.ifc,
545 PH_ACTIVATE |
546 INDICATION,
547 NULL);
548 break;
549
550 default:
551 if (bch->mode == L1_MODE_NULL)
552 break;
553 spin_lock_irqsave(&l1->lock,
554 flags);
555 l1->hw->mr.
556 fifo_slow_timer_service[l1->
557 st_num]
558 &=
559 ~((bch->bchan ==
560 1) ? 0x3 : 0xc);
561 l1->hw->mr.
562 fifo_rx_trans_enables[l1->
563 st_num]
564 &=
565 ~((bch->bchan ==
566 1) ? 0x3 : 0xc);
567 l1->hw->mr.timer_usg_cnt--;
568 Write_hfc8(l1->hw, R_FIFO,
569 (l1->st_num * 8 +
570 ((bch->bchan ==
571 1) ? 0 : 2)));
572 wait_busy(l1->hw);
573 Write_hfc8(l1->hw, A_IRQ_MSK, 0); /* disable TX interrupts */
574 wait_busy(l1->hw);
575 Write_hfc8(l1->hw, R_FIFO,
576 (l1->st_num * 8 +
577 ((bch->bchan ==
578 1) ? 1 : 3)));
579 wait_busy(l1->hw);
580 Write_hfc8(l1->hw, A_IRQ_MSK, 0); /* disable RX interrupts */
581 Write_hfc8(l1->hw, R_ST_SEL,
582 l1->st_num);
583 l1->hw->mr.r_ctrl0 &=
584 ~(bch->bchan & 3);
585 Write_hfc8(l1->hw, A_ST_CTRL0,
586 l1->hw->mr.r_ctrl0);
587 spin_unlock_irqrestore(&l1->lock,
588 flags);
589
590 bch->mode = L1_MODE_NULL;
591 bch->b_if.ifc.l1l2(&bch->b_if.ifc,
592 PH_DEACTIVATE |
593 INDICATION,
594 NULL);
595 if (bch->tx_skb) {
596 dev_kfree_skb(bch->tx_skb);
597 bch->tx_skb = NULL;
598 }
599 if (bch->rx_skb) {
600 dev_kfree_skb(bch->rx_skb);
601 bch->rx_skb = NULL;
602 }
603 skb_queue_purge(&bch->tx_queue);
604 bch->tx_cnt = 0;
605 bch->rx_ptr = NULL;
606 break;
607 }
608
609 /* timer is only used when at least one b channel */
610 /* is set up to transparent mode */
611 if (l1->hw->mr.timer_usg_cnt) {
612 Write_hfc8(l1->hw, R_IRQMSK_MISC,
613 M_TI_IRQMSK);
614 } else {
615 Write_hfc8(l1->hw, R_IRQMSK_MISC, 0);
616 }
617
618 break;
619
620 default:
621 printk(KERN_INFO
622 "HFC-4S/8S: Unknown B-chan cmd 0x%x received, ignored\n",
623 pr);
624 break;
625 }
626 if (!l1->enabled)
627 bch->b_if.ifc.l1l2(&bch->b_if.ifc,
628 PH_DEACTIVATE | INDICATION, NULL);
629} /* bch_l2l1 */
630
631/**************************/
632/* layer 1 timer function */
633/**************************/
634static void
635hfc_l1_timer(struct hfc4s8s_l1 *l1)
636{
637 u_long flags;
638
639 if (!l1->enabled)
640 return;
641
642 spin_lock_irqsave(&l1->lock, flags);
643 if (l1->nt_mode) {
644 l1->l1_state = 1;
645 Write_hfc8(l1->hw, R_ST_SEL, l1->st_num);
646 Write_hfc8(l1->hw, A_ST_WR_STA, 0x11);
647 spin_unlock_irqrestore(&l1->lock, flags);
648 l1->d_if.ifc.l1l2(&l1->d_if.ifc,
649 PH_DEACTIVATE | INDICATION, NULL);
650 spin_lock_irqsave(&l1->lock, flags);
651 l1->l1_state = 1;
652 Write_hfc8(l1->hw, A_ST_WR_STA, 0x1);
653 spin_unlock_irqrestore(&l1->lock, flags);
654 } else {
655 /* activation timed out */
656 Write_hfc8(l1->hw, R_ST_SEL, l1->st_num);
657 Write_hfc8(l1->hw, A_ST_WR_STA, 0x13);
658 spin_unlock_irqrestore(&l1->lock, flags);
659 l1->d_if.ifc.l1l2(&l1->d_if.ifc,
660 PH_DEACTIVATE | INDICATION, NULL);
661 spin_lock_irqsave(&l1->lock, flags);
662 Write_hfc8(l1->hw, R_ST_SEL, l1->st_num);
663 Write_hfc8(l1->hw, A_ST_WR_STA, 0x3);
664 spin_unlock_irqrestore(&l1->lock, flags);
665 }
666} /* hfc_l1_timer */
667
668/****************************************/
669/* a complete D-frame has been received */
670/****************************************/
671static void
672rx_d_frame(struct hfc4s8s_l1 *l1p, int ech)
673{
674 int z1, z2;
675 u_char f1, f2, df;
676 struct sk_buff *skb;
677 u_char *cp;
678
679
680 if (!l1p->enabled)
681 return;
682 do {
683 /* E/D RX fifo */
684 Write_hfc8(l1p->hw, R_FIFO,
685 (l1p->st_num * 8 + ((ech) ? 7 : 5)));
686 wait_busy(l1p->hw);
687
688 f1 = Read_hfc8_stable(l1p->hw, A_F1);
689 f2 = Read_hfc8(l1p->hw, A_F2);
690 df = f1 - f2;
691 if ((f1 - f2) < 0)
692 df = f1 - f2 + MAX_F_CNT + 1;
693
694
695 if (!df) {
696 return; /* no complete frame in fifo */
697 }
698
699 z1 = Read_hfc16_stable(l1p->hw, A_Z1);
700 z2 = Read_hfc16(l1p->hw, A_Z2);
701
702 z1 = z1 - z2 + 1;
703 if (z1 < 0)
704 z1 += 384;
705
706 if (!(skb = dev_alloc_skb(MAX_D_FRAME_SIZE))) {
707 printk(KERN_INFO
708 "HFC-4S/8S: Could not allocate D/E "
709 "channel receive buffer");
710 Write_hfc8(l1p->hw, A_INC_RES_FIFO, 2);
711 wait_busy(l1p->hw);
712 return;
713 }
714
715 if (((z1 < 4) || (z1 > MAX_D_FRAME_SIZE))) {
716 if (skb)
717 dev_kfree_skb(skb);
718 /* remove errornous D frame */
719 if (df == 1) {
720 /* reset fifo */
721 Write_hfc8(l1p->hw, A_INC_RES_FIFO, 2);
722 wait_busy(l1p->hw);
723 return;
724 } else {
725 /* read errornous D frame */
726
727#ifndef CONFIG_HISAX_HFC4S8S_PCIMEM
728 SetRegAddr(l1p->hw, A_FIFO_DATA0);
729#endif
730
731 while (z1 >= 4) {
732#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM
733 Read_hfc32(l1p->hw, A_FIFO_DATA0);
734#else
735 fRead_hfc32(l1p->hw);
736#endif
737 z1 -= 4;
738 }
739
740 while (z1--)
741#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM
742 Read_hfc8(l1p->hw, A_FIFO_DATA0);
743#else
744 fRead_hfc8(l1p->hw);
745#endif
746
747 Write_hfc8(l1p->hw, A_INC_RES_FIFO, 1);
748 wait_busy(l1p->hw);
749 return;
750 }
751 }
752
753 cp = skb->data;
754
755#ifndef CONFIG_HISAX_HFC4S8S_PCIMEM
756 SetRegAddr(l1p->hw, A_FIFO_DATA0);
757#endif
758
759 while (z1 >= 4) {
760#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM
761 *((unsigned long *) cp) =
762 Read_hfc32(l1p->hw, A_FIFO_DATA0);
763#else
764 *((unsigned long *) cp) = fRead_hfc32(l1p->hw);
765#endif
766 cp += 4;
767 z1 -= 4;
768 }
769
770 while (z1--)
771#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM
772 *cp++ = Read_hfc8(l1p->hw, A_FIFO_DATA0);
773#else
774 *cp++ = fRead_hfc8(l1p->hw);
775#endif
776
777 Write_hfc8(l1p->hw, A_INC_RES_FIFO, 1); /* increment f counter */
778 wait_busy(l1p->hw);
779
780 if (*(--cp)) {
781 dev_kfree_skb(skb);
782 } else {
783 skb->len = (cp - skb->data) - 2;
784 if (ech)
785 l1p->d_if.ifc.l1l2(&l1p->d_if.ifc,
786 PH_DATA_E | INDICATION,
787 skb);
788 else
789 l1p->d_if.ifc.l1l2(&l1p->d_if.ifc,
790 PH_DATA | INDICATION,
791 skb);
792 }
793 } while (1);
794} /* rx_d_frame */
795
796/*************************************************************/
797/* a B-frame has been received (perhaps not fully completed) */
798/*************************************************************/
799static void
800rx_b_frame(struct hfc4s8s_btype *bch)
801{
802 int z1, z2, hdlc_complete;
803 u_char f1, f2;
804 struct hfc4s8s_l1 *l1 = bch->l1p;
805 struct sk_buff *skb;
806
807 if (!l1->enabled || (bch->mode == L1_MODE_NULL))
808 return;
809
810 do {
811 /* RX Fifo */
812 Write_hfc8(l1->hw, R_FIFO,
813 (l1->st_num * 8 + ((bch->bchan == 1) ? 1 : 3)));
814 wait_busy(l1->hw);
815
816 if (bch->mode == L1_MODE_HDLC) {
817 f1 = Read_hfc8_stable(l1->hw, A_F1);
818 f2 = Read_hfc8(l1->hw, A_F2);
819 hdlc_complete = ((f1 ^ f2) & MAX_F_CNT);
820 } else
821 hdlc_complete = 0;
822 z1 = Read_hfc16_stable(l1->hw, A_Z1);
823 z2 = Read_hfc16(l1->hw, A_Z2);
824 z1 = (z1 - z2);
825 if (hdlc_complete)
826 z1++;
827 if (z1 < 0)
828 z1 += 384;
829
830 if (!z1)
831 break;
832
833 if (!(skb = bch->rx_skb)) {
834 if (!
835 (skb =
836 dev_alloc_skb((bch->mode ==
837 L1_MODE_TRANS) ? z1
838 : (MAX_B_FRAME_SIZE + 3)))) {
839 printk(KERN_ERR
840 "HFC-4S/8S: Could not allocate B "
841 "channel receive buffer");
842 return;
843 }
844 bch->rx_ptr = skb->data;
845 bch->rx_skb = skb;
846 }
847
848 skb->len = (bch->rx_ptr - skb->data) + z1;
849
850 /* HDLC length check */
851 if ((bch->mode == L1_MODE_HDLC) &&
852 ((hdlc_complete && (skb->len < 4)) ||
853 (skb->len > (MAX_B_FRAME_SIZE + 3)))) {
854
855 skb->len = 0;
856 bch->rx_ptr = skb->data;
857 Write_hfc8(l1->hw, A_INC_RES_FIFO, 2); /* reset fifo */
858 wait_busy(l1->hw);
859 return;
860 }
861#ifndef CONFIG_HISAX_HFC4S8S_PCIMEM
862 SetRegAddr(l1->hw, A_FIFO_DATA0);
863#endif
864
865 while (z1 >= 4) {
866#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM
867 *((unsigned long *) bch->rx_ptr) =
868 Read_hfc32(l1->hw, A_FIFO_DATA0);
869#else
870 *((unsigned long *) bch->rx_ptr) =
871 fRead_hfc32(l1->hw);
872#endif
873 bch->rx_ptr += 4;
874 z1 -= 4;
875 }
876
877 while (z1--)
878#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM
879 *(bch->rx_ptr++) = Read_hfc8(l1->hw, A_FIFO_DATA0);
880#else
881 *(bch->rx_ptr++) = fRead_hfc8(l1->hw);
882#endif
883
884 if (hdlc_complete) {
885 /* increment f counter */
886 Write_hfc8(l1->hw, A_INC_RES_FIFO, 1);
887 wait_busy(l1->hw);
888
889 /* hdlc crc check */
890 bch->rx_ptr--;
891 if (*bch->rx_ptr) {
892 skb->len = 0;
893 bch->rx_ptr = skb->data;
894 continue;
895 }
896 skb->len -= 3;
897 }
898 if (hdlc_complete || (bch->mode == L1_MODE_TRANS)) {
899 bch->rx_skb = NULL;
900 bch->rx_ptr = NULL;
901 bch->b_if.ifc.l1l2(&bch->b_if.ifc,
902 PH_DATA | INDICATION, skb);
903 }
904
905 } while (1);
906} /* rx_b_frame */
907
908/********************************************/
909/* a D-frame has been/should be transmitted */
910/********************************************/
911static void
912tx_d_frame(struct hfc4s8s_l1 *l1p)
913{
914 struct sk_buff *skb;
915 u_char f1, f2;
916 u_char *cp;
917 int cnt;
918
919 if (l1p->l1_state != 7)
920 return;
921
922 /* TX fifo */
923 Write_hfc8(l1p->hw, R_FIFO, (l1p->st_num * 8 + 4));
924 wait_busy(l1p->hw);
925
926 f1 = Read_hfc8(l1p->hw, A_F1);
927 f2 = Read_hfc8_stable(l1p->hw, A_F2);
928
929 if ((f1 ^ f2) & MAX_F_CNT)
930 return; /* fifo is still filled */
931
932 if (l1p->tx_cnt > 0) {
933 cnt = l1p->tx_cnt;
934 l1p->tx_cnt = 0;
935 l1p->d_if.ifc.l1l2(&l1p->d_if.ifc, PH_DATA | CONFIRM,
936 (void *) cnt);
937 }
938
939 if ((skb = skb_dequeue(&l1p->d_tx_queue))) {
940 cp = skb->data;
941 cnt = skb->len;
942#ifndef CONFIG_HISAX_HFC4S8S_PCIMEM
943 SetRegAddr(l1p->hw, A_FIFO_DATA0);
944#endif
945
946 while (cnt >= 4) {
947#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM
948 fWrite_hfc32(l1p->hw, A_FIFO_DATA0,
949 *(unsigned long *) cp);
950#else
951 SetRegAddr(l1p->hw, A_FIFO_DATA0);
952 fWrite_hfc32(l1p->hw, *(unsigned long *) cp);
953#endif
954 cp += 4;
955 cnt -= 4;
956 }
957
958#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM
959 while (cnt--)
960 fWrite_hfc8(l1p->hw, A_FIFO_DATA0, *cp++);
961#else
962 while (cnt--)
963 fWrite_hfc8(l1p->hw, *cp++);
964#endif
965
966 l1p->tx_cnt = skb->truesize;
967 Write_hfc8(l1p->hw, A_INC_RES_FIFO, 1); /* increment f counter */
968 wait_busy(l1p->hw);
969
970 dev_kfree_skb(skb);
971 }
972} /* tx_d_frame */
973
974/******************************************************/
975/* a B-frame may be transmitted (or is not completed) */
976/******************************************************/
977static void
978tx_b_frame(struct hfc4s8s_btype *bch)
979{
980 struct sk_buff *skb;
981 struct hfc4s8s_l1 *l1 = bch->l1p;
982 u_char *cp;
983 int cnt, max, hdlc_num, ack_len = 0;
984
985 if (!l1->enabled || (bch->mode == L1_MODE_NULL))
986 return;
987
988 /* TX fifo */
989 Write_hfc8(l1->hw, R_FIFO,
990 (l1->st_num * 8 + ((bch->bchan == 1) ? 0 : 2)));
991 wait_busy(l1->hw);
992 do {
993
994 if (bch->mode == L1_MODE_HDLC) {
995 hdlc_num = Read_hfc8(l1->hw, A_F1) & MAX_F_CNT;
996 hdlc_num -=
997 (Read_hfc8_stable(l1->hw, A_F2) & MAX_F_CNT);
998 if (hdlc_num < 0)
999 hdlc_num += 16;
1000 if (hdlc_num >= 15)
1001 break; /* fifo still filled up with hdlc frames */
1002 } else
1003 hdlc_num = 0;
1004
1005 if (!(skb = bch->tx_skb)) {
1006 if (!(skb = skb_dequeue(&bch->tx_queue))) {
1007 l1->hw->mr.fifo_slow_timer_service[l1->
1008 st_num]
1009 &= ~((bch->bchan == 1) ? 1 : 4);
1010 break; /* list empty */
1011 }
1012 bch->tx_skb = skb;
1013 bch->tx_cnt = 0;
1014 }
1015
1016 if (!hdlc_num)
1017 l1->hw->mr.fifo_slow_timer_service[l1->st_num] |=
1018 ((bch->bchan == 1) ? 1 : 4);
1019 else
1020 l1->hw->mr.fifo_slow_timer_service[l1->st_num] &=
1021 ~((bch->bchan == 1) ? 1 : 4);
1022
1023 max = Read_hfc16_stable(l1->hw, A_Z2);
1024 max -= Read_hfc16(l1->hw, A_Z1);
1025 if (max <= 0)
1026 max += 384;
1027 max--;
1028
1029 if (max < 16)
1030 break; /* don't write to small amounts of bytes */
1031
1032 cnt = skb->len - bch->tx_cnt;
1033 if (cnt > max)
1034 cnt = max;
1035 cp = skb->data + bch->tx_cnt;
1036 bch->tx_cnt += cnt;
1037
1038#ifndef CONFIG_HISAX_HFC4S8S_PCIMEM
1039 SetRegAddr(l1->hw, A_FIFO_DATA0);
1040#endif
1041 while (cnt >= 4) {
1042#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM
1043 fWrite_hfc32(l1->hw, A_FIFO_DATA0,
1044 *(unsigned long *) cp);
1045#else
1046 fWrite_hfc32(l1->hw, *(unsigned long *) cp);
1047#endif
1048 cp += 4;
1049 cnt -= 4;
1050 }
1051
1052 while (cnt--)
1053#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM
1054 fWrite_hfc8(l1->hw, A_FIFO_DATA0, *cp++);
1055#else
1056 fWrite_hfc8(l1->hw, *cp++);
1057#endif
1058
1059 if (bch->tx_cnt >= skb->len) {
1060 if (bch->mode == L1_MODE_HDLC) {
1061 /* increment f counter */
1062 Write_hfc8(l1->hw, A_INC_RES_FIFO, 1);
1063 }
1064 ack_len += skb->truesize;
1065 bch->tx_skb = 0;
1066 bch->tx_cnt = 0;
1067 dev_kfree_skb(skb);
1068 } else
1069 /* Re-Select */
1070 Write_hfc8(l1->hw, R_FIFO,
1071 (l1->st_num * 8 +
1072 ((bch->bchan == 1) ? 0 : 2)));
1073 wait_busy(l1->hw);
1074 } while (1);
1075
1076 if (ack_len)
1077 bch->b_if.ifc.l1l2((struct hisax_if *) &bch->b_if,
1078 PH_DATA | CONFIRM, (void *) ack_len);
1079} /* tx_b_frame */
1080
1081/*************************************/
1082/* bottom half handler for interrupt */
1083/*************************************/
1084static void
1085hfc4s8s_bh(hfc4s8s_hw * hw)
1086{
1087 u_char b;
1088 struct hfc4s8s_l1 *l1p;
1089 volatile u_char *fifo_stat;
1090 int idx;
1091
1092 /* handle layer 1 state changes */
1093 b = 1;
1094 l1p = hw->l1;
1095 while (b) {
1096 if ((b & hw->mr.r_irq_statech)) {
1097 /* reset l1 event */
1098 hw->mr.r_irq_statech &= ~b;
1099 if (l1p->enabled) {
1100 if (l1p->nt_mode) {
1101 u_char oldstate = l1p->l1_state;
1102
1103 Write_hfc8(l1p->hw, R_ST_SEL,
1104 l1p->st_num);
1105 l1p->l1_state =
1106 Read_hfc8(l1p->hw,
1107 A_ST_RD_STA) & 0xf;
1108
1109 if ((oldstate == 3)
1110 && (l1p->l1_state != 3))
1111 l1p->d_if.ifc.l1l2(&l1p->
1112 d_if.
1113 ifc,
1114 PH_DEACTIVATE
1115 |
1116 INDICATION,
1117 NULL);
1118
1119 if (l1p->l1_state != 2) {
1120 del_timer(&l1p->l1_timer);
1121 if (l1p->l1_state == 3) {
1122 l1p->d_if.ifc.
1123 l1l2(&l1p->
1124 d_if.ifc,
1125 PH_ACTIVATE
1126 |
1127 INDICATION,
1128 NULL);
1129 }
1130 } else {
1131 /* allow transition */
1132 Write_hfc8(hw, A_ST_WR_STA,
1133 M_SET_G2_G3);
1134 mod_timer(&l1p->l1_timer,
1135 jiffies +
1136 L1_TIMER_T1);
1137 }
1138 printk(KERN_INFO
1139 "HFC-4S/8S: NT ch %d l1 state %d -> %d\n",
1140 l1p->st_num, oldstate,
1141 l1p->l1_state);
1142 } else {
1143 u_char oldstate = l1p->l1_state;
1144
1145 Write_hfc8(l1p->hw, R_ST_SEL,
1146 l1p->st_num);
1147 l1p->l1_state =
1148 Read_hfc8(l1p->hw,
1149 A_ST_RD_STA) & 0xf;
1150
1151 if (((l1p->l1_state == 3) &&
1152 ((oldstate == 7) ||
1153 (oldstate == 8))) ||
1154 ((timer_pending
1155 (&l1p->l1_timer))
1156 && (l1p->l1_state == 8))) {
1157 mod_timer(&l1p->l1_timer,
1158 L1_TIMER_T4 +
1159 jiffies);
1160 } else {
1161 if (l1p->l1_state == 7) {
1162 del_timer(&l1p->
1163 l1_timer);
1164 l1p->d_if.ifc.
1165 l1l2(&l1p->
1166 d_if.ifc,
1167 PH_ACTIVATE
1168 |
1169 INDICATION,
1170 NULL);
1171 tx_d_frame(l1p);
1172 }
1173 if (l1p->l1_state == 3) {
1174 if (oldstate != 3)
1175 l1p->d_if.
1176 ifc.
1177 l1l2
1178 (&l1p->
1179 d_if.
1180 ifc,
1181 PH_DEACTIVATE
1182 |
1183 INDICATION,
1184 NULL);
1185 }
1186 }
1187 printk(KERN_INFO
1188 "HFC-4S/8S: TE %d ch %d l1 state %d -> %d\n",
1189 l1p->hw->cardnum,
1190 l1p->st_num, oldstate,
1191 l1p->l1_state);
1192 }
1193 }
1194 }
1195 b <<= 1;
1196 l1p++;
1197 }
1198
1199 /* now handle the fifos */
1200 idx = 0;
1201 fifo_stat = hw->mr.r_irq_fifo_blx;
1202 l1p = hw->l1;
1203 while (idx < hw->driver_data.max_st_ports) {
1204
1205 if (hw->mr.timer_irq) {
1206 *fifo_stat |= hw->mr.fifo_rx_trans_enables[idx];
1207 if (hw->fifo_sched_cnt <= 0) {
1208 *fifo_stat |=
1209 hw->mr.fifo_slow_timer_service[l1p->
1210 st_num];
1211 }
1212 }
1213 /* ignore fifo 6 (TX E fifo) */
1214 *fifo_stat &= 0xff - 0x40;
1215
1216 while (*fifo_stat) {
1217
1218 if (!l1p->nt_mode) {
1219 /* RX Fifo has data to read */
1220 if ((*fifo_stat & 0x20)) {
1221 *fifo_stat &= ~0x20;
1222 rx_d_frame(l1p, 0);
1223 }
1224 /* E Fifo has data to read */
1225 if ((*fifo_stat & 0x80)) {
1226 *fifo_stat &= ~0x80;
1227 rx_d_frame(l1p, 1);
1228 }
1229 /* TX Fifo completed send */
1230 if ((*fifo_stat & 0x10)) {
1231 *fifo_stat &= ~0x10;
1232 tx_d_frame(l1p);
1233 }
1234 }
1235 /* B1 RX Fifo has data to read */
1236 if ((*fifo_stat & 0x2)) {
1237 *fifo_stat &= ~0x2;
1238 rx_b_frame(l1p->b_ch);
1239 }
1240 /* B1 TX Fifo has send completed */
1241 if ((*fifo_stat & 0x1)) {
1242 *fifo_stat &= ~0x1;
1243 tx_b_frame(l1p->b_ch);
1244 }
1245 /* B2 RX Fifo has data to read */
1246 if ((*fifo_stat & 0x8)) {
1247 *fifo_stat &= ~0x8;
1248 rx_b_frame(l1p->b_ch + 1);
1249 }
1250 /* B2 TX Fifo has send completed */
1251 if ((*fifo_stat & 0x4)) {
1252 *fifo_stat &= ~0x4;
1253 tx_b_frame(l1p->b_ch + 1);
1254 }
1255 }
1256 fifo_stat++;
1257 l1p++;
1258 idx++;
1259 }
1260
1261 if (hw->fifo_sched_cnt <= 0)
1262 hw->fifo_sched_cnt += (1 << (7 - TRANS_TIMER_MODE));
1263 hw->mr.timer_irq = 0; /* clear requested timer irq */
1264} /* hfc4s8s_bh */
1265
1266/*********************/
1267/* interrupt handler */
1268/*********************/
1269static irqreturn_t
1270hfc4s8s_interrupt(int intno, void *dev_id, struct pt_regs *regs)
1271{
1272 hfc4s8s_hw *hw = dev_id;
1273 u_char b, ovr;
1274 volatile u_char *ovp;
1275 int idx;
1276 u_char old_ioreg;
1277
1278 if (!hw || !(hw->mr.r_irq_ctrl & M_GLOB_IRQ_EN))
1279 return IRQ_NONE;
1280
1281#ifndef CONFIG_HISAX_HFC4S8S_PCIMEM
1282 /* read current selected regsister */
1283 old_ioreg = GetRegAddr(hw);
1284#endif
1285
1286 /* Layer 1 State change */
1287 hw->mr.r_irq_statech |=
1288 (Read_hfc8(hw, R_SCI) & hw->mr.r_irqmsk_statchg);
1289 if (!
1290 (b = (Read_hfc8(hw, R_STATUS) & (M_MISC_IRQSTA | M_FR_IRQSTA)))
1291&& !hw->mr.r_irq_statech) {
1292#ifndef CONFIG_HISAX_HFC4S8S_PCIMEM
1293 SetRegAddr(hw, old_ioreg);
1294#endif
1295 return IRQ_NONE;
1296 }
1297
1298 /* timer event */
1299 if (Read_hfc8(hw, R_IRQ_MISC) & M_TI_IRQ) {
1300 hw->mr.timer_irq = 1;
1301 hw->fifo_sched_cnt--;
1302 }
1303
1304 /* FIFO event */
1305 if ((ovr = Read_hfc8(hw, R_IRQ_OVIEW))) {
1306 hw->mr.r_irq_oview |= ovr;
1307 idx = R_IRQ_FIFO_BL0;
1308 ovp = hw->mr.r_irq_fifo_blx;
1309 while (ovr) {
1310 if ((ovr & 1)) {
1311 *ovp |= Read_hfc8(hw, idx);
1312 }
1313 ovp++;
1314 idx++;
1315 ovr >>= 1;
1316 }
1317 }
1318
1319 /* queue the request to allow other cards to interrupt */
1320 schedule_work(&hw->tqueue);
1321
1322#ifndef CONFIG_HISAX_HFC4S8S_PCIMEM
1323 SetRegAddr(hw, old_ioreg);
1324#endif
1325 return IRQ_HANDLED;
1326} /* hfc4s8s_interrupt */
1327
1328/***********************************************************************/
1329/* reset the complete chip, don't release the chips irq but disable it */
1330/***********************************************************************/
1331static void
1332chipreset(hfc4s8s_hw * hw)
1333{
1334 u_long flags;
1335
1336 spin_lock_irqsave(&hw->lock, flags);
1337 Write_hfc8(hw, R_CTRL, 0); /* use internal RAM */
1338 Write_hfc8(hw, R_RAM_MISC, 0); /* 32k*8 RAM */
1339 Write_hfc8(hw, R_FIFO_MD, 0); /* fifo mode 386 byte/fifo simple mode */
1340 Write_hfc8(hw, R_CIRM, M_SRES); /* reset chip */
1341 hw->mr.r_irq_ctrl = 0; /* interrupt is inactive */
1342 spin_unlock_irqrestore(&hw->lock, flags);
1343
1344 udelay(3);
1345 Write_hfc8(hw, R_CIRM, 0); /* disable reset */
1346 wait_busy(hw);
1347
1348 Write_hfc8(hw, R_PCM_MD0, M_PCM_MD); /* master mode */
1349 Write_hfc8(hw, R_RAM_MISC, M_FZ_MD); /* transmit fifo option */
1350 if (hw->driver_data.clock_mode == 1)
1351 Write_hfc8(hw, R_BRG_PCM_CFG, M_PCM_CLK); /* PCM clk / 2 */
1352 Write_hfc8(hw, R_TI_WD, TRANS_TIMER_MODE); /* timer interval */
1353
1354 memset(&hw->mr, 0, sizeof(hw->mr));
1355} /* chipreset */
1356
1357/********************************************/
1358/* disable/enable hardware in nt or te mode */
1359/********************************************/
1360void
1361hfc_hardware_enable(hfc4s8s_hw * hw, int enable, int nt_mode)
1362{
1363 u_long flags;
1364 char if_name[40];
1365 int i;
1366
1367 if (enable) {
1368 /* save system vars */
1369 hw->nt_mode = nt_mode;
1370
1371 /* enable fifo and state irqs, but not global irq enable */
1372 hw->mr.r_irq_ctrl = M_FIFO_IRQ;
1373 Write_hfc8(hw, R_IRQ_CTRL, hw->mr.r_irq_ctrl);
1374 hw->mr.r_irqmsk_statchg = 0;
1375 Write_hfc8(hw, R_SCI_MSK, hw->mr.r_irqmsk_statchg);
1376 Write_hfc8(hw, R_PWM_MD, 0x80);
1377 Write_hfc8(hw, R_PWM1, 26);
1378 if (!nt_mode)
1379 Write_hfc8(hw, R_ST_SYNC, M_AUTO_SYNC);
1380
1381 /* enable the line interfaces and fifos */
1382 for (i = 0; i < hw->driver_data.max_st_ports; i++) {
1383 hw->mr.r_irqmsk_statchg |= (1 << i);
1384 Write_hfc8(hw, R_SCI_MSK, hw->mr.r_irqmsk_statchg);
1385 Write_hfc8(hw, R_ST_SEL, i);
1386 Write_hfc8(hw, A_ST_CLK_DLY,
1387 ((nt_mode) ? CLKDEL_NT : CLKDEL_TE));
1388 hw->mr.r_ctrl0 = ((nt_mode) ? CTRL0_NT : CTRL0_TE);
1389 Write_hfc8(hw, A_ST_CTRL0, hw->mr.r_ctrl0);
1390 Write_hfc8(hw, A_ST_CTRL2, 3);
1391 Write_hfc8(hw, A_ST_WR_STA, 0); /* enable state machine */
1392
1393 hw->l1[i].enabled = 1;
1394 hw->l1[i].nt_mode = nt_mode;
1395
1396 if (!nt_mode) {
1397 /* setup E-fifo */
1398 Write_hfc8(hw, R_FIFO, i * 8 + 7); /* E fifo */
1399 wait_busy(hw);
1400 Write_hfc8(hw, A_CON_HDLC, 0x11); /* HDLC mode, 1 fill, connect ST */
1401 Write_hfc8(hw, A_SUBCH_CFG, 2); /* only 2 bits */
1402 Write_hfc8(hw, A_IRQ_MSK, 1); /* enable interrupt */
1403 Write_hfc8(hw, A_INC_RES_FIFO, 2); /* reset fifo */
1404 wait_busy(hw);
1405
1406 /* setup D RX-fifo */
1407 Write_hfc8(hw, R_FIFO, i * 8 + 5); /* RX fifo */
1408 wait_busy(hw);
1409 Write_hfc8(hw, A_CON_HDLC, 0x11); /* HDLC mode, 1 fill, connect ST */
1410 Write_hfc8(hw, A_SUBCH_CFG, 2); /* only 2 bits */
1411 Write_hfc8(hw, A_IRQ_MSK, 1); /* enable interrupt */
1412 Write_hfc8(hw, A_INC_RES_FIFO, 2); /* reset fifo */
1413 wait_busy(hw);
1414
1415 /* setup D TX-fifo */
1416 Write_hfc8(hw, R_FIFO, i * 8 + 4); /* TX fifo */
1417 wait_busy(hw);
1418 Write_hfc8(hw, A_CON_HDLC, 0x11); /* HDLC mode, 1 fill, connect ST */
1419 Write_hfc8(hw, A_SUBCH_CFG, 2); /* only 2 bits */
1420 Write_hfc8(hw, A_IRQ_MSK, 1); /* enable interrupt */
1421 Write_hfc8(hw, A_INC_RES_FIFO, 2); /* reset fifo */
1422 wait_busy(hw);
1423 }
1424
1425 sprintf(if_name, "hfc4s8s_%d%d_", hw->cardnum, i);
1426
1427 if (hisax_register
1428 (&hw->l1[i].d_if, hw->l1[i].b_table, if_name,
1429 ((nt_mode) ? 3 : 2))) {
1430
1431 hw->l1[i].enabled = 0;
1432 hw->mr.r_irqmsk_statchg &= ~(1 << i);
1433 Write_hfc8(hw, R_SCI_MSK,
1434 hw->mr.r_irqmsk_statchg);
1435 printk(KERN_INFO
1436 "HFC-4S/8S: Unable to register S/T device %s, break\n",
1437 if_name);
1438 break;
1439 }
1440 }
1441 spin_lock_irqsave(&hw->lock, flags);
1442 hw->mr.r_irq_ctrl |= M_GLOB_IRQ_EN;
1443 Write_hfc8(hw, R_IRQ_CTRL, hw->mr.r_irq_ctrl);
1444 spin_unlock_irqrestore(&hw->lock, flags);
1445 } else {
1446 /* disable hardware */
1447 spin_lock_irqsave(&hw->lock, flags);
1448 hw->mr.r_irq_ctrl &= ~M_GLOB_IRQ_EN;
1449 Write_hfc8(hw, R_IRQ_CTRL, hw->mr.r_irq_ctrl);
1450 spin_unlock_irqrestore(&hw->lock, flags);
1451
1452 for (i = hw->driver_data.max_st_ports - 1; i >= 0; i--) {
1453 hw->l1[i].enabled = 0;
1454 hisax_unregister(&hw->l1[i].d_if);
1455 del_timer(&hw->l1[i].l1_timer);
1456 skb_queue_purge(&hw->l1[i].d_tx_queue);
1457 skb_queue_purge(&hw->l1[i].b_ch[0].tx_queue);
1458 skb_queue_purge(&hw->l1[i].b_ch[1].tx_queue);
1459 }
1460 chipreset(hw);
1461 }
1462} /* hfc_hardware_enable */
1463
1464/******************************************/
1465/* disable memory mapped ports / io ports */
1466/******************************************/
1467void
1468release_pci_ports(hfc4s8s_hw * hw)
1469{
1470 pci_write_config_word(hw->pdev, PCI_COMMAND, 0);
1471#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM
1472 if (hw->membase)
1473 iounmap((void *) hw->membase);
1474#else
1475 if (hw->iobase)
1476 release_region(hw->iobase, 8);
1477#endif
1478}
1479
1480/*****************************************/
1481/* enable memory mapped ports / io ports */
1482/*****************************************/
1483void
1484enable_pci_ports(hfc4s8s_hw * hw)
1485{
1486#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM
1487 pci_write_config_word(hw->pdev, PCI_COMMAND, PCI_ENA_MEMIO);
1488#else
1489 pci_write_config_word(hw->pdev, PCI_COMMAND, PCI_ENA_REGIO);
1490#endif
1491}
1492
1493/*************************************/
1494/* initialise the HFC-4s/8s hardware */
1495/* return 0 on success. */
1496/*************************************/
1497static int __devinit
1498setup_instance(hfc4s8s_hw * hw)
1499{
1500 int err = -EIO;
1501 int i;
1502
1503 for (i = 0; i < HFC_MAX_ST; i++) {
1504 struct hfc4s8s_l1 *l1p;
1505
1506 l1p = hw->l1 + i;
1507 spin_lock_init(&l1p->lock);
1508 l1p->hw = hw;
1509 l1p->l1_timer.function = (void *) hfc_l1_timer;
1510 l1p->l1_timer.data = (long) (l1p);
1511 init_timer(&l1p->l1_timer);
1512 l1p->st_num = i;
1513 skb_queue_head_init(&l1p->d_tx_queue);
1514 l1p->d_if.ifc.priv = hw->l1 + i;
1515 l1p->d_if.ifc.l2l1 = (void *) dch_l2l1;
1516
1517 spin_lock_init(&l1p->b_ch[0].lock);
1518 l1p->b_ch[0].b_if.ifc.l2l1 = (void *) bch_l2l1;
1519 l1p->b_ch[0].b_if.ifc.priv = (void *) &l1p->b_ch[0];
1520 l1p->b_ch[0].l1p = hw->l1 + i;
1521 l1p->b_ch[0].bchan = 1;
1522 l1p->b_table[0] = &l1p->b_ch[0].b_if;
1523 skb_queue_head_init(&l1p->b_ch[0].tx_queue);
1524
1525 spin_lock_init(&l1p->b_ch[1].lock);
1526 l1p->b_ch[1].b_if.ifc.l2l1 = (void *) bch_l2l1;
1527 l1p->b_ch[1].b_if.ifc.priv = (void *) &l1p->b_ch[1];
1528 l1p->b_ch[1].l1p = hw->l1 + i;
1529 l1p->b_ch[1].bchan = 2;
1530 l1p->b_table[1] = &l1p->b_ch[1].b_if;
1531 skb_queue_head_init(&l1p->b_ch[1].tx_queue);
1532 }
1533
1534 enable_pci_ports(hw);
1535 chipreset(hw);
1536
1537 i = Read_hfc8(hw, R_CHIP_ID) >> CHIP_ID_SHIFT;
1538 if (i != hw->driver_data.chip_id) {
1539 printk(KERN_INFO
1540 "HFC-4S/8S: invalid chip id 0x%x instead of 0x%x, card ignored\n",
1541 i, hw->driver_data.chip_id);
1542 goto out;
1543 }
1544
1545 i = Read_hfc8(hw, R_CHIP_RV) & 0xf;
1546 if (!i) {
1547 printk(KERN_INFO
1548 "HFC-4S/8S: chip revision 0 not supported, card ignored\n");
1549 goto out;
1550 }
1551
1552 INIT_WORK(&hw->tqueue, (void *) (void *) hfc4s8s_bh, hw);
1553
1554 if (request_irq
1555 (hw->irq, hfc4s8s_interrupt, SA_SHIRQ, hw->card_name, hw)) {
1556 printk(KERN_INFO
1557 "HFC-4S/8S: unable to alloc irq %d, card ignored\n",
1558 hw->irq);
1559 goto out;
1560 }
1561#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM
1562 printk(KERN_INFO
1563 "HFC-4S/8S: found PCI card at membase 0x%p, irq %d\n",
1564 hw->hw_membase, hw->irq);
1565#else
1566 printk(KERN_INFO
1567 "HFC-4S/8S: found PCI card at iobase 0x%x, irq %d\n",
1568 hw->iobase, hw->irq);
1569#endif
1570
1571 hfc_hardware_enable(hw, 1, 0);
1572
1573 return (0);
1574
1575 out:
1576 hw->irq = 0;
1577 release_pci_ports(hw);
1578 kfree(hw);
1579 return (err);
1580}
1581
1582/*****************************************/
1583/* PCI hotplug interface: probe new card */
1584/*****************************************/
1585static int __devinit
1586hfc4s8s_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
1587{
1588 int err = -ENOMEM;
1589 hfc4s8s_param *driver_data = (hfc4s8s_param *) ent->driver_data;
1590 hfc4s8s_hw *hw;
1591
1592 if (!(hw = kmalloc(sizeof(hfc4s8s_hw), GFP_ATOMIC))) {
1593 printk(KERN_ERR "No kmem for HFC-4S/8S card\n");
1594 return (err);
1595 }
1596 memset(hw, 0, sizeof(hfc4s8s_hw));
1597
1598 hw->pdev = pdev;
1599 err = pci_enable_device(pdev);
1600
1601 if (err)
1602 goto out;
1603
1604 hw->cardnum = card_cnt;
1605 sprintf(hw->card_name, "hfc4s8s_%d", hw->cardnum);
1606 printk(KERN_INFO "HFC-4S/8S: found adapter %s (%s) at %s\n",
1607 driver_data->device_name, hw->card_name, pci_name(pdev));
1608
1609 spin_lock_init(&hw->lock);
1610
1611 hw->driver_data = *driver_data;
1612 hw->irq = pdev->irq;
1613 hw->iobase = pci_resource_start(pdev, 0);
1614
1615#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM
1616 hw->hw_membase = (u_char *) pci_resource_start(pdev, 1);
1617 hw->membase = ioremap((ulong) hw->hw_membase, 256);
1618#else
1619 if (!request_region(hw->iobase, 8, hw->card_name)) {
1620 printk(KERN_INFO
1621 "HFC-4S/8S: failed to rquest address space at 0x%04x\n",
1622 hw->iobase);
1623 goto out;
1624 }
1625#endif
1626
1627 pci_set_drvdata(pdev, hw);
1628 err = setup_instance(hw);
1629 if (!err)
1630 card_cnt++;
1631 return (err);
1632
1633 out:
1634 kfree(hw);
1635 return (err);
1636}
1637
1638/**************************************/
1639/* PCI hotplug interface: remove card */
1640/**************************************/
1641static void __devexit
1642hfc4s8s_remove(struct pci_dev *pdev)
1643{
1644 hfc4s8s_hw *hw = pci_get_drvdata(pdev);
1645
1646 printk(KERN_INFO "HFC-4S/8S: removing card %d\n", hw->cardnum);
1647 hfc_hardware_enable(hw, 0, 0);
1648
1649 if (hw->irq)
1650 free_irq(hw->irq, hw);
1651 hw->irq = 0;
1652 release_pci_ports(hw);
1653
1654 card_cnt--;
1655 pci_disable_device(pdev);
1656 kfree(hw);
1657 return;
1658}
1659
1660static struct pci_driver hfc4s8s_driver = {
1661 name:"hfc4s8s_l1",
1662 probe:hfc4s8s_probe,
1663 remove:__devexit_p(hfc4s8s_remove),
1664 id_table:hfc4s8s_ids,
1665};
1666
1667/**********************/
1668/* driver Module init */
1669/**********************/
1670static int __init
1671hfc4s8s_module_init(void)
1672{
1673 int err;
1674
1675 printk(KERN_INFO
1676 "HFC-4S/8S: Layer 1 driver module for HFC-4S/8S isdn chips, %s\n",
1677 hfc4s8s_rev);
1678 printk(KERN_INFO
1679 "HFC-4S/8S: (C) 2003 Cornelius Consult, www.cornelius-consult.de\n");
1680
1681 card_cnt = 0;
1682
1683 err = pci_register_driver(&hfc4s8s_driver);
1684 if (err < 0) {
1685 goto out;
1686 }
1687 printk(KERN_INFO "HFC-4S/8S: found %d cards\n", card_cnt);
1688
1689#if !defined(CONFIG_HOTPLUG)
1690 if (err == 0) {
1691 err = -ENODEV;
1692 pci_unregister_driver(&hfc4s8s_driver);
1693 goto out;
1694 }
1695#endif
1696
1697 return 0;
1698 out:
1699 return (err);
1700} /* hfc4s8s_init_hw */
1701
1702/*************************************/
1703/* driver module exit : */
1704/* release the HFC-4s/8s hardware */
1705/*************************************/
1706static void
1707hfc4s8s_module_exit(void)
1708{
1709 pci_unregister_driver(&hfc4s8s_driver);
1710 printk(KERN_INFO "HFC-4S/8S: module removed\n");
1711} /* hfc4s8s_release_hw */
1712
1713module_init(hfc4s8s_module_init);
1714module_exit(hfc4s8s_module_exit);
diff --git a/drivers/isdn/hisax/hfc4s8s_l1.h b/drivers/isdn/hisax/hfc4s8s_l1.h
new file mode 100644
index 000000000000..e8f9c077fa85
--- /dev/null
+++ b/drivers/isdn/hisax/hfc4s8s_l1.h
@@ -0,0 +1,88 @@
1/***************************************************************/
2/* $Id: hfc4s8s_l1.h,v 1.1 2005/02/02 17:28:55 martinb1 Exp $ */
3/* */
4/* This file is a minimal required extraction of hfc48scu.h */
5/* (Genero 3.2, HFC XML 1.7a for HFC-E1, HFC-4S and HFC-8S) */
6/* */
7/* To get this complete register description contact */
8/* Cologne Chip AG : */
9/* Internet: http://www.colognechip.com/ */
10/* E-Mail: info@colognechip.com */
11/***************************************************************/
12
13#ifndef _HFC4S8S_L1_H_
14#define _HFC4S8S_L1_H_
15
16
17/*
18* include Genero generated HFC-4S/8S header file hfc48scu.h
19* for comlete register description. This will define _HFC48SCU_H_
20* to prevent redefinitions
21*/
22
23// #include "hfc48scu.h"
24
25#ifndef _HFC48SCU_H_
26#define _HFC48SCU_H_
27
28#ifndef PCI_VENDOR_ID_CCD
29#define PCI_VENDOR_ID_CCD 0x1397
30#endif
31
32#define CHIP_ID_4S 0x0C
33#define CHIP_ID_8S 0x08
34#define PCI_DEVICE_ID_4S 0x08B4
35#define PCI_DEVICE_ID_8S 0x16B8
36
37#define R_IRQ_MISC 0x11
38#define M_TI_IRQ 0x02
39#define A_ST_RD_STA 0x30
40#define A_ST_WR_STA 0x30
41#define M_SET_G2_G3 0x80
42#define A_ST_CTRL0 0x31
43#define A_ST_CTRL2 0x33
44#define A_ST_CLK_DLY 0x37
45#define A_Z1 0x04
46#define A_Z2 0x06
47#define R_CIRM 0x00
48#define M_SRES 0x08
49#define R_CTRL 0x01
50#define R_BRG_PCM_CFG 0x02
51#define M_PCM_CLK 0x20
52#define R_RAM_MISC 0x0C
53#define M_FZ_MD 0x80
54#define R_FIFO_MD 0x0D
55#define A_INC_RES_FIFO 0x0E
56#define R_FIFO 0x0F
57#define A_F1 0x0C
58#define A_F2 0x0D
59#define R_IRQ_OVIEW 0x10
60#define R_CHIP_ID 0x16
61#define R_STATUS 0x1C
62#define M_BUSY 0x01
63#define M_MISC_IRQSTA 0x40
64#define M_FR_IRQSTA 0x80
65#define R_CHIP_RV 0x1F
66#define R_IRQ_CTRL 0x13
67#define M_FIFO_IRQ 0x01
68#define M_GLOB_IRQ_EN 0x08
69#define R_PCM_MD0 0x14
70#define M_PCM_MD 0x01
71#define A_FIFO_DATA0 0x80
72#define R_TI_WD 0x1A
73#define R_PWM1 0x39
74#define R_PWM_MD 0x46
75#define R_IRQ_FIFO_BL0 0xC8
76#define A_CON_HDLC 0xFA
77#define A_SUBCH_CFG 0xFB
78#define A_IRQ_MSK 0xFF
79#define R_SCI_MSK 0x12
80#define R_ST_SEL 0x16
81#define R_ST_SYNC 0x17
82#define M_AUTO_SYNC 0x08
83#define R_SCI 0x12
84#define R_IRQMSK_MISC 0x11
85#define M_TI_IRQMSK 0x02
86
87#endif /* _HFC4S8S_L1_H_ */
88#endif /* _HFC48SCU_H_ */
diff --git a/drivers/isdn/hisax/hfc_2bds0.c b/drivers/isdn/hisax/hfc_2bds0.c
new file mode 100644
index 000000000000..ebea3feef003
--- /dev/null
+++ b/drivers/isdn/hisax/hfc_2bds0.c
@@ -0,0 +1,1082 @@
1/* $Id: hfc_2bds0.c,v 1.18.2.6 2004/02/11 13:21:33 keil Exp $
2 *
3 * specific routines for CCD's HFC 2BDS0
4 *
5 * Author Karsten Keil
6 * Copyright by Karsten Keil <keil@isdn4linux.de>
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 */
12
13#include <linux/init.h>
14#include "hisax.h"
15#include "hfc_2bds0.h"
16#include "isdnl1.h"
17#include <linux/interrupt.h>
18/*
19#define KDEBUG_DEF
20#include "kdebug.h"
21*/
22
23#define byteout(addr,val) outb(val,addr)
24#define bytein(addr) inb(addr)
25
26static void
27dummyf(struct IsdnCardState *cs, u_char * data, int size)
28{
29 printk(KERN_WARNING "HiSax: hfcd dummy fifo called\n");
30}
31
32static inline u_char
33ReadReg(struct IsdnCardState *cs, int data, u_char reg)
34{
35 register u_char ret;
36
37 if (data) {
38 if (cs->hw.hfcD.cip != reg) {
39 cs->hw.hfcD.cip = reg;
40 byteout(cs->hw.hfcD.addr | 1, reg);
41 }
42 ret = bytein(cs->hw.hfcD.addr);
43#ifdef HFC_REG_DEBUG
44 if (cs->debug & L1_DEB_HSCX_FIFO && (data != 2))
45 debugl1(cs, "t3c RD %02x %02x", reg, ret);
46#endif
47 } else
48 ret = bytein(cs->hw.hfcD.addr | 1);
49 return (ret);
50}
51
52static inline void
53WriteReg(struct IsdnCardState *cs, int data, u_char reg, u_char value)
54{
55 if (cs->hw.hfcD.cip != reg) {
56 cs->hw.hfcD.cip = reg;
57 byteout(cs->hw.hfcD.addr | 1, reg);
58 }
59 if (data)
60 byteout(cs->hw.hfcD.addr, value);
61#ifdef HFC_REG_DEBUG
62 if (cs->debug & L1_DEB_HSCX_FIFO && (data != HFCD_DATA_NODEB))
63 debugl1(cs, "t3c W%c %02x %02x", data ? 'D' : 'C', reg, value);
64#endif
65}
66
67/* Interface functions */
68
69static u_char
70readreghfcd(struct IsdnCardState *cs, u_char offset)
71{
72 return(ReadReg(cs, HFCD_DATA, offset));
73}
74
75static void
76writereghfcd(struct IsdnCardState *cs, u_char offset, u_char value)
77{
78 WriteReg(cs, HFCD_DATA, offset, value);
79}
80
81static inline int
82WaitForBusy(struct IsdnCardState *cs)
83{
84 int to = 130;
85
86 while (!(ReadReg(cs, HFCD_DATA, HFCD_STAT) & HFCD_BUSY) && to) {
87 udelay(1);
88 to--;
89 }
90 if (!to)
91 printk(KERN_WARNING "HiSax: WaitForBusy timeout\n");
92 return (to);
93}
94
95static inline int
96WaitNoBusy(struct IsdnCardState *cs)
97{
98 int to = 130;
99
100 while ((ReadReg(cs, HFCD_STATUS, HFCD_STATUS) & HFCD_BUSY) && to) {
101 udelay(1);
102 to--;
103 }
104 if (!to)
105 printk(KERN_WARNING "HiSax: WaitNoBusy timeout\n");
106 return (to);
107}
108
109static int
110SelFiFo(struct IsdnCardState *cs, u_char FiFo)
111{
112 u_char cip;
113
114 if (cs->hw.hfcD.fifo == FiFo)
115 return(1);
116 switch(FiFo) {
117 case 0: cip = HFCB_FIFO | HFCB_Z1 | HFCB_SEND | HFCB_B1;
118 break;
119 case 1: cip = HFCB_FIFO | HFCB_Z1 | HFCB_REC | HFCB_B1;
120 break;
121 case 2: cip = HFCB_FIFO | HFCB_Z1 | HFCB_SEND | HFCB_B2;
122 break;
123 case 3: cip = HFCB_FIFO | HFCB_Z1 | HFCB_REC | HFCB_B2;
124 break;
125 case 4: cip = HFCD_FIFO | HFCD_Z1 | HFCD_SEND;
126 break;
127 case 5: cip = HFCD_FIFO | HFCD_Z1 | HFCD_REC;
128 break;
129 default:
130 debugl1(cs, "SelFiFo Error");
131 return(0);
132 }
133 cs->hw.hfcD.fifo = FiFo;
134 WaitNoBusy(cs);
135 cs->BC_Write_Reg(cs, HFCD_DATA, cip, 0);
136 WaitForBusy(cs);
137 return(2);
138}
139
140static int
141GetFreeFifoBytes_B(struct BCState *bcs)
142{
143 int s;
144
145 if (bcs->hw.hfc.f1 == bcs->hw.hfc.f2)
146 return (bcs->cs->hw.hfcD.bfifosize);
147 s = bcs->hw.hfc.send[bcs->hw.hfc.f1] - bcs->hw.hfc.send[bcs->hw.hfc.f2];
148 if (s <= 0)
149 s += bcs->cs->hw.hfcD.bfifosize;
150 s = bcs->cs->hw.hfcD.bfifosize - s;
151 return (s);
152}
153
154static int
155GetFreeFifoBytes_D(struct IsdnCardState *cs)
156{
157 int s;
158
159 if (cs->hw.hfcD.f1 == cs->hw.hfcD.f2)
160 return (cs->hw.hfcD.dfifosize);
161 s = cs->hw.hfcD.send[cs->hw.hfcD.f1] - cs->hw.hfcD.send[cs->hw.hfcD.f2];
162 if (s <= 0)
163 s += cs->hw.hfcD.dfifosize;
164 s = cs->hw.hfcD.dfifosize - s;
165 return (s);
166}
167
168static int
169ReadZReg(struct IsdnCardState *cs, u_char reg)
170{
171 int val;
172
173 WaitNoBusy(cs);
174 val = 256 * ReadReg(cs, HFCD_DATA, reg | HFCB_Z_HIGH);
175 WaitNoBusy(cs);
176 val += ReadReg(cs, HFCD_DATA, reg | HFCB_Z_LOW);
177 return (val);
178}
179
180static struct sk_buff
181*hfc_empty_fifo(struct BCState *bcs, int count)
182{
183 u_char *ptr;
184 struct sk_buff *skb;
185 struct IsdnCardState *cs = bcs->cs;
186 int idx;
187 int chksum;
188 u_char stat, cip;
189
190 if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
191 debugl1(cs, "hfc_empty_fifo");
192 idx = 0;
193 if (count > HSCX_BUFMAX + 3) {
194 if (cs->debug & L1_DEB_WARN)
195 debugl1(cs, "hfc_empty_fifo: incoming packet too large");
196 cip = HFCB_FIFO | HFCB_FIFO_OUT | HFCB_REC | HFCB_CHANNEL(bcs->channel);
197 while (idx++ < count) {
198 WaitNoBusy(cs);
199 ReadReg(cs, HFCD_DATA_NODEB, cip);
200 }
201 skb = NULL;
202 } else if (count < 4) {
203 if (cs->debug & L1_DEB_WARN)
204 debugl1(cs, "hfc_empty_fifo: incoming packet too small");
205 cip = HFCB_FIFO | HFCB_FIFO_OUT | HFCB_REC | HFCB_CHANNEL(bcs->channel);
206#ifdef ERROR_STATISTIC
207 bcs->err_inv++;
208#endif
209 while ((idx++ < count) && WaitNoBusy(cs))
210 ReadReg(cs, HFCD_DATA_NODEB, cip);
211 skb = NULL;
212 } else if (!(skb = dev_alloc_skb(count - 3)))
213 printk(KERN_WARNING "HFC: receive out of memory\n");
214 else {
215 ptr = skb_put(skb, count - 3);
216 idx = 0;
217 cip = HFCB_FIFO | HFCB_FIFO_OUT | HFCB_REC | HFCB_CHANNEL(bcs->channel);
218 while (idx < (count - 3)) {
219 if (!WaitNoBusy(cs))
220 break;
221 *ptr = ReadReg(cs, HFCD_DATA_NODEB, cip);
222 ptr++;
223 idx++;
224 }
225 if (idx != count - 3) {
226 debugl1(cs, "RFIFO BUSY error");
227 printk(KERN_WARNING "HFC FIFO channel %d BUSY Error\n", bcs->channel);
228 dev_kfree_skb_irq(skb);
229 skb = NULL;
230 } else {
231 WaitNoBusy(cs);
232 chksum = (ReadReg(cs, HFCD_DATA, cip) << 8);
233 WaitNoBusy(cs);
234 chksum += ReadReg(cs, HFCD_DATA, cip);
235 WaitNoBusy(cs);
236 stat = ReadReg(cs, HFCD_DATA, cip);
237 if (cs->debug & L1_DEB_HSCX)
238 debugl1(cs, "hfc_empty_fifo %d chksum %x stat %x",
239 bcs->channel, chksum, stat);
240 if (stat) {
241 debugl1(cs, "FIFO CRC error");
242 dev_kfree_skb_irq(skb);
243 skb = NULL;
244#ifdef ERROR_STATISTIC
245 bcs->err_crc++;
246#endif
247 }
248 }
249 }
250 WaitForBusy(cs);
251 WaitNoBusy(cs);
252 stat = ReadReg(cs, HFCD_DATA, HFCB_FIFO | HFCB_F2_INC |
253 HFCB_REC | HFCB_CHANNEL(bcs->channel));
254 WaitForBusy(cs);
255 return (skb);
256}
257
258static void
259hfc_fill_fifo(struct BCState *bcs)
260{
261 struct IsdnCardState *cs = bcs->cs;
262 int idx, fcnt;
263 int count;
264 u_char cip;
265
266 if (!bcs->tx_skb)
267 return;
268 if (bcs->tx_skb->len <= 0)
269 return;
270 SelFiFo(cs, HFCB_SEND | HFCB_CHANNEL(bcs->channel));
271 cip = HFCB_FIFO | HFCB_F1 | HFCB_SEND | HFCB_CHANNEL(bcs->channel);
272 WaitNoBusy(cs);
273 bcs->hw.hfc.f1 = ReadReg(cs, HFCD_DATA, cip);
274 WaitNoBusy(cs);
275 cip = HFCB_FIFO | HFCB_F2 | HFCB_SEND | HFCB_CHANNEL(bcs->channel);
276 WaitNoBusy(cs);
277 bcs->hw.hfc.f2 = ReadReg(cs, HFCD_DATA, cip);
278 bcs->hw.hfc.send[bcs->hw.hfc.f1] = ReadZReg(cs, HFCB_FIFO | HFCB_Z1 | HFCB_SEND | HFCB_CHANNEL(bcs->channel));
279 if (cs->debug & L1_DEB_HSCX)
280 debugl1(cs, "hfc_fill_fifo %d f1(%d) f2(%d) z1(%x)",
281 bcs->channel, bcs->hw.hfc.f1, bcs->hw.hfc.f2,
282 bcs->hw.hfc.send[bcs->hw.hfc.f1]);
283 fcnt = bcs->hw.hfc.f1 - bcs->hw.hfc.f2;
284 if (fcnt < 0)
285 fcnt += 32;
286 if (fcnt > 30) {
287 if (cs->debug & L1_DEB_HSCX)
288 debugl1(cs, "hfc_fill_fifo more as 30 frames");
289 return;
290 }
291 count = GetFreeFifoBytes_B(bcs);
292 if (cs->debug & L1_DEB_HSCX)
293 debugl1(cs, "hfc_fill_fifo %d count(%ld/%d),%lx",
294 bcs->channel, bcs->tx_skb->len,
295 count, current->state);
296 if (count < bcs->tx_skb->len) {
297 if (cs->debug & L1_DEB_HSCX)
298 debugl1(cs, "hfc_fill_fifo no fifo mem");
299 return;
300 }
301 cip = HFCB_FIFO | HFCB_FIFO_IN | HFCB_SEND | HFCB_CHANNEL(bcs->channel);
302 idx = 0;
303 WaitForBusy(cs);
304 WaitNoBusy(cs);
305 WriteReg(cs, HFCD_DATA_NODEB, cip, bcs->tx_skb->data[idx++]);
306 while (idx < bcs->tx_skb->len) {
307 if (!WaitNoBusy(cs))
308 break;
309 WriteReg(cs, HFCD_DATA_NODEB, cip, bcs->tx_skb->data[idx]);
310 idx++;
311 }
312 if (idx != bcs->tx_skb->len) {
313 debugl1(cs, "FIFO Send BUSY error");
314 printk(KERN_WARNING "HFC S FIFO channel %d BUSY Error\n", bcs->channel);
315 } else {
316 bcs->tx_cnt -= bcs->tx_skb->len;
317 if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) &&
318 (PACKET_NOACK != bcs->tx_skb->pkt_type)) {
319 u_long flags;
320 spin_lock_irqsave(&bcs->aclock, flags);
321 bcs->ackcnt += bcs->tx_skb->len;
322 spin_unlock_irqrestore(&bcs->aclock, flags);
323 schedule_event(bcs, B_ACKPENDING);
324 }
325 dev_kfree_skb_any(bcs->tx_skb);
326 bcs->tx_skb = NULL;
327 }
328 WaitForBusy(cs);
329 WaitNoBusy(cs);
330 ReadReg(cs, HFCD_DATA, HFCB_FIFO | HFCB_F1_INC | HFCB_SEND | HFCB_CHANNEL(bcs->channel));
331 WaitForBusy(cs);
332 test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
333 return;
334}
335
336static void
337hfc_send_data(struct BCState *bcs)
338{
339 struct IsdnCardState *cs = bcs->cs;
340
341 if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
342 hfc_fill_fifo(bcs);
343 test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
344 } else
345 debugl1(cs,"send_data %d blocked", bcs->channel);
346}
347
348void
349main_rec_2bds0(struct BCState *bcs)
350{
351 struct IsdnCardState *cs = bcs->cs;
352 int z1, z2, rcnt;
353 u_char f1, f2, cip;
354 int receive, count = 5;
355 struct sk_buff *skb;
356
357 Begin:
358 count--;
359 if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
360 debugl1(cs,"rec_data %d blocked", bcs->channel);
361 return;
362 }
363 SelFiFo(cs, HFCB_REC | HFCB_CHANNEL(bcs->channel));
364 cip = HFCB_FIFO | HFCB_F1 | HFCB_REC | HFCB_CHANNEL(bcs->channel);
365 WaitNoBusy(cs);
366 f1 = ReadReg(cs, HFCD_DATA, cip);
367 cip = HFCB_FIFO | HFCB_F2 | HFCB_REC | HFCB_CHANNEL(bcs->channel);
368 WaitNoBusy(cs);
369 f2 = ReadReg(cs, HFCD_DATA, cip);
370 if (f1 != f2) {
371 if (cs->debug & L1_DEB_HSCX)
372 debugl1(cs, "hfc rec %d f1(%d) f2(%d)",
373 bcs->channel, f1, f2);
374 z1 = ReadZReg(cs, HFCB_FIFO | HFCB_Z1 | HFCB_REC | HFCB_CHANNEL(bcs->channel));
375 z2 = ReadZReg(cs, HFCB_FIFO | HFCB_Z2 | HFCB_REC | HFCB_CHANNEL(bcs->channel));
376 rcnt = z1 - z2;
377 if (rcnt < 0)
378 rcnt += cs->hw.hfcD.bfifosize;
379 rcnt++;
380 if (cs->debug & L1_DEB_HSCX)
381 debugl1(cs, "hfc rec %d z1(%x) z2(%x) cnt(%d)",
382 bcs->channel, z1, z2, rcnt);
383 if ((skb = hfc_empty_fifo(bcs, rcnt))) {
384 skb_queue_tail(&bcs->rqueue, skb);
385 schedule_event(bcs, B_RCVBUFREADY);
386 }
387 rcnt = f1 -f2;
388 if (rcnt<0)
389 rcnt += 32;
390 if (rcnt>1)
391 receive = 1;
392 else
393 receive = 0;
394 } else
395 receive = 0;
396 test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
397 if (count && receive)
398 goto Begin;
399 return;
400}
401
402void
403mode_2bs0(struct BCState *bcs, int mode, int bc)
404{
405 struct IsdnCardState *cs = bcs->cs;
406
407 if (cs->debug & L1_DEB_HSCX)
408 debugl1(cs, "HFCD bchannel mode %d bchan %d/%d",
409 mode, bc, bcs->channel);
410 bcs->mode = mode;
411 bcs->channel = bc;
412 switch (mode) {
413 case (L1_MODE_NULL):
414 if (bc) {
415 cs->hw.hfcD.conn |= 0x18;
416 cs->hw.hfcD.sctrl &= ~SCTRL_B2_ENA;
417 } else {
418 cs->hw.hfcD.conn |= 0x3;
419 cs->hw.hfcD.sctrl &= ~SCTRL_B1_ENA;
420 }
421 break;
422 case (L1_MODE_TRANS):
423 if (bc) {
424 cs->hw.hfcD.ctmt |= 2;
425 cs->hw.hfcD.conn &= ~0x18;
426 cs->hw.hfcD.sctrl |= SCTRL_B2_ENA;
427 } else {
428 cs->hw.hfcD.ctmt |= 1;
429 cs->hw.hfcD.conn &= ~0x3;
430 cs->hw.hfcD.sctrl |= SCTRL_B1_ENA;
431 }
432 break;
433 case (L1_MODE_HDLC):
434 if (bc) {
435 cs->hw.hfcD.ctmt &= ~2;
436 cs->hw.hfcD.conn &= ~0x18;
437 cs->hw.hfcD.sctrl |= SCTRL_B2_ENA;
438 } else {
439 cs->hw.hfcD.ctmt &= ~1;
440 cs->hw.hfcD.conn &= ~0x3;
441 cs->hw.hfcD.sctrl |= SCTRL_B1_ENA;
442 }
443 break;
444 }
445 WriteReg(cs, HFCD_DATA, HFCD_SCTRL, cs->hw.hfcD.sctrl);
446 WriteReg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcD.ctmt);
447 WriteReg(cs, HFCD_DATA, HFCD_CONN, cs->hw.hfcD.conn);
448}
449
450static void
451hfc_l2l1(struct PStack *st, int pr, void *arg)
452{
453 struct BCState *bcs = st->l1.bcs;
454 struct sk_buff *skb = arg;
455 u_long flags;
456
457 switch (pr) {
458 case (PH_DATA | REQUEST):
459 spin_lock_irqsave(&bcs->cs->lock, flags);
460 if (bcs->tx_skb) {
461 skb_queue_tail(&bcs->squeue, skb);
462 } else {
463 bcs->tx_skb = skb;
464// test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
465 bcs->cs->BC_Send_Data(bcs);
466 }
467 spin_unlock_irqrestore(&bcs->cs->lock, flags);
468 break;
469 case (PH_PULL | INDICATION):
470 spin_lock_irqsave(&bcs->cs->lock, flags);
471 if (bcs->tx_skb) {
472 printk(KERN_WARNING "hfc_l2l1: this shouldn't happen\n");
473 } else {
474// test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
475 bcs->tx_skb = skb;
476 bcs->cs->BC_Send_Data(bcs);
477 }
478 spin_unlock_irqrestore(&bcs->cs->lock, flags);
479 break;
480 case (PH_PULL | REQUEST):
481 if (!bcs->tx_skb) {
482 test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
483 st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
484 } else
485 test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
486 break;
487 case (PH_ACTIVATE | REQUEST):
488 spin_lock_irqsave(&bcs->cs->lock, flags);
489 test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag);
490 mode_2bs0(bcs, st->l1.mode, st->l1.bc);
491 spin_unlock_irqrestore(&bcs->cs->lock, flags);
492 l1_msg_b(st, pr, arg);
493 break;
494 case (PH_DEACTIVATE | REQUEST):
495 l1_msg_b(st, pr, arg);
496 break;
497 case (PH_DEACTIVATE | CONFIRM):
498 spin_lock_irqsave(&bcs->cs->lock, flags);
499 test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag);
500 test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
501 mode_2bs0(bcs, 0, st->l1.bc);
502 spin_unlock_irqrestore(&bcs->cs->lock, flags);
503 st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
504 break;
505 }
506}
507
508void
509close_2bs0(struct BCState *bcs)
510{
511 mode_2bs0(bcs, 0, bcs->channel);
512 if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) {
513 skb_queue_purge(&bcs->rqueue);
514 skb_queue_purge(&bcs->squeue);
515 if (bcs->tx_skb) {
516 dev_kfree_skb_any(bcs->tx_skb);
517 bcs->tx_skb = NULL;
518 test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
519 }
520 }
521}
522
523static int
524open_hfcstate(struct IsdnCardState *cs, struct BCState *bcs)
525{
526 if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
527 skb_queue_head_init(&bcs->rqueue);
528 skb_queue_head_init(&bcs->squeue);
529 }
530 bcs->tx_skb = NULL;
531 test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
532 bcs->event = 0;
533 bcs->tx_cnt = 0;
534 return (0);
535}
536
537int
538setstack_2b(struct PStack *st, struct BCState *bcs)
539{
540 bcs->channel = st->l1.bc;
541 if (open_hfcstate(st->l1.hardware, bcs))
542 return (-1);
543 st->l1.bcs = bcs;
544 st->l2.l2l1 = hfc_l2l1;
545 setstack_manager(st);
546 bcs->st = st;
547 setstack_l1_B(st);
548 return (0);
549}
550
551static void
552hfcd_bh(struct IsdnCardState *cs)
553{
554 if (!cs)
555 return;
556 if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) {
557 switch (cs->dc.hfcd.ph_state) {
558 case (0):
559 l1_msg(cs, HW_RESET | INDICATION, NULL);
560 break;
561 case (3):
562 l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL);
563 break;
564 case (8):
565 l1_msg(cs, HW_RSYNC | INDICATION, NULL);
566 break;
567 case (6):
568 l1_msg(cs, HW_INFO2 | INDICATION, NULL);
569 break;
570 case (7):
571 l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
572 break;
573 default:
574 break;
575 }
576 }
577 if (test_and_clear_bit(D_RCVBUFREADY, &cs->event))
578 DChannel_proc_rcv(cs);
579 if (test_and_clear_bit(D_XMTBUFREADY, &cs->event))
580 DChannel_proc_xmt(cs);
581}
582
583static
584int receive_dmsg(struct IsdnCardState *cs)
585{
586 struct sk_buff *skb;
587 int idx;
588 int rcnt, z1, z2;
589 u_char stat, cip, f1, f2;
590 int chksum;
591 int count=5;
592 u_char *ptr;
593
594 if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
595 debugl1(cs, "rec_dmsg blocked");
596 return(1);
597 }
598 SelFiFo(cs, 4 | HFCD_REC);
599 cip = HFCD_FIFO | HFCD_F1 | HFCD_REC;
600 WaitNoBusy(cs);
601 f1 = cs->readisac(cs, cip) & 0xf;
602 cip = HFCD_FIFO | HFCD_F2 | HFCD_REC;
603 WaitNoBusy(cs);
604 f2 = cs->readisac(cs, cip) & 0xf;
605 while ((f1 != f2) && count--) {
606 z1 = ReadZReg(cs, HFCD_FIFO | HFCD_Z1 | HFCD_REC);
607 z2 = ReadZReg(cs, HFCD_FIFO | HFCD_Z2 | HFCD_REC);
608 rcnt = z1 - z2;
609 if (rcnt < 0)
610 rcnt += cs->hw.hfcD.dfifosize;
611 rcnt++;
612 if (cs->debug & L1_DEB_ISAC)
613 debugl1(cs, "hfcd recd f1(%d) f2(%d) z1(%x) z2(%x) cnt(%d)",
614 f1, f2, z1, z2, rcnt);
615 idx = 0;
616 cip = HFCD_FIFO | HFCD_FIFO_OUT | HFCD_REC;
617 if (rcnt > MAX_DFRAME_LEN + 3) {
618 if (cs->debug & L1_DEB_WARN)
619 debugl1(cs, "empty_fifo d: incoming packet too large");
620 while (idx < rcnt) {
621 if (!(WaitNoBusy(cs)))
622 break;
623 ReadReg(cs, HFCD_DATA_NODEB, cip);
624 idx++;
625 }
626 } else if (rcnt < 4) {
627 if (cs->debug & L1_DEB_WARN)
628 debugl1(cs, "empty_fifo d: incoming packet too small");
629 while ((idx++ < rcnt) && WaitNoBusy(cs))
630 ReadReg(cs, HFCD_DATA_NODEB, cip);
631 } else if ((skb = dev_alloc_skb(rcnt - 3))) {
632 ptr = skb_put(skb, rcnt - 3);
633 while (idx < (rcnt - 3)) {
634 if (!(WaitNoBusy(cs)))
635 break;
636 *ptr = ReadReg(cs, HFCD_DATA_NODEB, cip);
637 idx++;
638 ptr++;
639 }
640 if (idx != (rcnt - 3)) {
641 debugl1(cs, "RFIFO D BUSY error");
642 printk(KERN_WARNING "HFC DFIFO channel BUSY Error\n");
643 dev_kfree_skb_irq(skb);
644 skb = NULL;
645#ifdef ERROR_STATISTIC
646 cs->err_rx++;
647#endif
648 } else {
649 WaitNoBusy(cs);
650 chksum = (ReadReg(cs, HFCD_DATA, cip) << 8);
651 WaitNoBusy(cs);
652 chksum += ReadReg(cs, HFCD_DATA, cip);
653 WaitNoBusy(cs);
654 stat = ReadReg(cs, HFCD_DATA, cip);
655 if (cs->debug & L1_DEB_ISAC)
656 debugl1(cs, "empty_dfifo chksum %x stat %x",
657 chksum, stat);
658 if (stat) {
659 debugl1(cs, "FIFO CRC error");
660 dev_kfree_skb_irq(skb);
661 skb = NULL;
662#ifdef ERROR_STATISTIC
663 cs->err_crc++;
664#endif
665 } else {
666 skb_queue_tail(&cs->rq, skb);
667 schedule_event(cs, D_RCVBUFREADY);
668 }
669 }
670 } else
671 printk(KERN_WARNING "HFC: D receive out of memory\n");
672 WaitForBusy(cs);
673 cip = HFCD_FIFO | HFCD_F2_INC | HFCD_REC;
674 WaitNoBusy(cs);
675 stat = ReadReg(cs, HFCD_DATA, cip);
676 WaitForBusy(cs);
677 cip = HFCD_FIFO | HFCD_F2 | HFCD_REC;
678 WaitNoBusy(cs);
679 f2 = cs->readisac(cs, cip) & 0xf;
680 }
681 test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
682 return(1);
683}
684
685static void
686hfc_fill_dfifo(struct IsdnCardState *cs)
687{
688 int idx, fcnt;
689 int count;
690 u_char cip;
691
692 if (!cs->tx_skb)
693 return;
694 if (cs->tx_skb->len <= 0)
695 return;
696
697 SelFiFo(cs, 4 | HFCD_SEND);
698 cip = HFCD_FIFO | HFCD_F1 | HFCD_SEND;
699 WaitNoBusy(cs);
700 cs->hw.hfcD.f1 = ReadReg(cs, HFCD_DATA, cip) & 0xf;
701 WaitNoBusy(cs);
702 cip = HFCD_FIFO | HFCD_F2 | HFCD_SEND;
703 cs->hw.hfcD.f2 = ReadReg(cs, HFCD_DATA, cip) & 0xf;
704 cs->hw.hfcD.send[cs->hw.hfcD.f1] = ReadZReg(cs, HFCD_FIFO | HFCD_Z1 | HFCD_SEND);
705 if (cs->debug & L1_DEB_ISAC)
706 debugl1(cs, "hfc_fill_Dfifo f1(%d) f2(%d) z1(%x)",
707 cs->hw.hfcD.f1, cs->hw.hfcD.f2,
708 cs->hw.hfcD.send[cs->hw.hfcD.f1]);
709 fcnt = cs->hw.hfcD.f1 - cs->hw.hfcD.f2;
710 if (fcnt < 0)
711 fcnt += 16;
712 if (fcnt > 14) {
713 if (cs->debug & L1_DEB_HSCX)
714 debugl1(cs, "hfc_fill_Dfifo more as 14 frames");
715 return;
716 }
717 count = GetFreeFifoBytes_D(cs);
718 if (cs->debug & L1_DEB_ISAC)
719 debugl1(cs, "hfc_fill_Dfifo count(%ld/%d)",
720 cs->tx_skb->len, count);
721 if (count < cs->tx_skb->len) {
722 if (cs->debug & L1_DEB_ISAC)
723 debugl1(cs, "hfc_fill_Dfifo no fifo mem");
724 return;
725 }
726 cip = HFCD_FIFO | HFCD_FIFO_IN | HFCD_SEND;
727 idx = 0;
728 WaitForBusy(cs);
729 WaitNoBusy(cs);
730 WriteReg(cs, HFCD_DATA_NODEB, cip, cs->tx_skb->data[idx++]);
731 while (idx < cs->tx_skb->len) {
732 if (!(WaitNoBusy(cs)))
733 break;
734 WriteReg(cs, HFCD_DATA_NODEB, cip, cs->tx_skb->data[idx]);
735 idx++;
736 }
737 if (idx != cs->tx_skb->len) {
738 debugl1(cs, "DFIFO Send BUSY error");
739 printk(KERN_WARNING "HFC S DFIFO channel BUSY Error\n");
740 }
741 WaitForBusy(cs);
742 WaitNoBusy(cs);
743 ReadReg(cs, HFCD_DATA, HFCD_FIFO | HFCD_F1_INC | HFCD_SEND);
744 dev_kfree_skb_any(cs->tx_skb);
745 cs->tx_skb = NULL;
746 WaitForBusy(cs);
747 return;
748}
749
750static
751struct BCState *Sel_BCS(struct IsdnCardState *cs, int channel)
752{
753 if (cs->bcs[0].mode && (cs->bcs[0].channel == channel))
754 return(&cs->bcs[0]);
755 else if (cs->bcs[1].mode && (cs->bcs[1].channel == channel))
756 return(&cs->bcs[1]);
757 else
758 return(NULL);
759}
760
761void
762hfc2bds0_interrupt(struct IsdnCardState *cs, u_char val)
763{
764 u_char exval;
765 struct BCState *bcs;
766 int count=15;
767
768 if (cs->debug & L1_DEB_ISAC)
769 debugl1(cs, "HFCD irq %x %s", val,
770 test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags) ?
771 "locked" : "unlocked");
772 val &= cs->hw.hfcD.int_m1;
773 if (val & 0x40) { /* TE state machine irq */
774 exval = cs->readisac(cs, HFCD_STATES) & 0xf;
775 if (cs->debug & L1_DEB_ISAC)
776 debugl1(cs, "ph_state chg %d->%d", cs->dc.hfcd.ph_state,
777 exval);
778 cs->dc.hfcd.ph_state = exval;
779 schedule_event(cs, D_L1STATECHANGE);
780 val &= ~0x40;
781 }
782 while (val) {
783 if (test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
784 cs->hw.hfcD.int_s1 |= val;
785 return;
786 }
787 if (cs->hw.hfcD.int_s1 & 0x18) {
788 exval = val;
789 val = cs->hw.hfcD.int_s1;
790 cs->hw.hfcD.int_s1 = exval;
791 }
792 if (val & 0x08) {
793 if (!(bcs=Sel_BCS(cs, 0))) {
794 if (cs->debug)
795 debugl1(cs, "hfcd spurious 0x08 IRQ");
796 } else
797 main_rec_2bds0(bcs);
798 }
799 if (val & 0x10) {
800 if (!(bcs=Sel_BCS(cs, 1))) {
801 if (cs->debug)
802 debugl1(cs, "hfcd spurious 0x10 IRQ");
803 } else
804 main_rec_2bds0(bcs);
805 }
806 if (val & 0x01) {
807 if (!(bcs=Sel_BCS(cs, 0))) {
808 if (cs->debug)
809 debugl1(cs, "hfcd spurious 0x01 IRQ");
810 } else {
811 if (bcs->tx_skb) {
812 if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
813 hfc_fill_fifo(bcs);
814 test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
815 } else
816 debugl1(cs,"fill_data %d blocked", bcs->channel);
817 } else {
818 if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
819 if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
820 hfc_fill_fifo(bcs);
821 test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
822 } else
823 debugl1(cs,"fill_data %d blocked", bcs->channel);
824 } else {
825 schedule_event(bcs, B_XMTBUFREADY);
826 }
827 }
828 }
829 }
830 if (val & 0x02) {
831 if (!(bcs=Sel_BCS(cs, 1))) {
832 if (cs->debug)
833 debugl1(cs, "hfcd spurious 0x02 IRQ");
834 } else {
835 if (bcs->tx_skb) {
836 if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
837 hfc_fill_fifo(bcs);
838 test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
839 } else
840 debugl1(cs,"fill_data %d blocked", bcs->channel);
841 } else {
842 if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
843 if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
844 hfc_fill_fifo(bcs);
845 test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
846 } else
847 debugl1(cs,"fill_data %d blocked", bcs->channel);
848 } else {
849 schedule_event(bcs, B_XMTBUFREADY);
850 }
851 }
852 }
853 }
854 if (val & 0x20) { /* receive dframe */
855 receive_dmsg(cs);
856 }
857 if (val & 0x04) { /* dframe transmitted */
858 if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
859 del_timer(&cs->dbusytimer);
860 if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
861 schedule_event(cs, D_CLEARBUSY);
862 if (cs->tx_skb) {
863 if (cs->tx_skb->len) {
864 if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
865 hfc_fill_dfifo(cs);
866 test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
867 } else {
868 debugl1(cs, "hfc_fill_dfifo irq blocked");
869 }
870 goto afterXPR;
871 } else {
872 dev_kfree_skb_irq(cs->tx_skb);
873 cs->tx_cnt = 0;
874 cs->tx_skb = NULL;
875 }
876 }
877 if ((cs->tx_skb = skb_dequeue(&cs->sq))) {
878 cs->tx_cnt = 0;
879 if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
880 hfc_fill_dfifo(cs);
881 test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
882 } else {
883 debugl1(cs, "hfc_fill_dfifo irq blocked");
884 }
885 } else
886 schedule_event(cs, D_XMTBUFREADY);
887 }
888 afterXPR:
889 if (cs->hw.hfcD.int_s1 && count--) {
890 val = cs->hw.hfcD.int_s1;
891 cs->hw.hfcD.int_s1 = 0;
892 if (cs->debug & L1_DEB_ISAC)
893 debugl1(cs, "HFCD irq %x loop %d", val, 15-count);
894 } else
895 val = 0;
896 }
897}
898
899static void
900HFCD_l1hw(struct PStack *st, int pr, void *arg)
901{
902 struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
903 struct sk_buff *skb = arg;
904 u_long flags;
905
906 switch (pr) {
907 case (PH_DATA | REQUEST):
908 if (cs->debug & DEB_DLOG_HEX)
909 LogFrame(cs, skb->data, skb->len);
910 if (cs->debug & DEB_DLOG_VERBOSE)
911 dlogframe(cs, skb, 0);
912 spin_lock_irqsave(&cs->lock, flags);
913 if (cs->tx_skb) {
914 skb_queue_tail(&cs->sq, skb);
915#ifdef L2FRAME_DEBUG /* psa */
916 if (cs->debug & L1_DEB_LAPD)
917 Logl2Frame(cs, skb, "PH_DATA Queued", 0);
918#endif
919 } else {
920 cs->tx_skb = skb;
921 cs->tx_cnt = 0;
922#ifdef L2FRAME_DEBUG /* psa */
923 if (cs->debug & L1_DEB_LAPD)
924 Logl2Frame(cs, skb, "PH_DATA", 0);
925#endif
926 if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
927 hfc_fill_dfifo(cs);
928 test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
929 } else
930 debugl1(cs, "hfc_fill_dfifo blocked");
931
932 }
933 spin_unlock_irqrestore(&cs->lock, flags);
934 break;
935 case (PH_PULL | INDICATION):
936 spin_lock_irqsave(&cs->lock, flags);
937 if (cs->tx_skb) {
938 if (cs->debug & L1_DEB_WARN)
939 debugl1(cs, " l2l1 tx_skb exist this shouldn't happen");
940 skb_queue_tail(&cs->sq, skb);
941 spin_unlock_irqrestore(&cs->lock, flags);
942 break;
943 }
944 if (cs->debug & DEB_DLOG_HEX)
945 LogFrame(cs, skb->data, skb->len);
946 if (cs->debug & DEB_DLOG_VERBOSE)
947 dlogframe(cs, skb, 0);
948 cs->tx_skb = skb;
949 cs->tx_cnt = 0;
950#ifdef L2FRAME_DEBUG /* psa */
951 if (cs->debug & L1_DEB_LAPD)
952 Logl2Frame(cs, skb, "PH_DATA_PULLED", 0);
953#endif
954 if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
955 hfc_fill_dfifo(cs);
956 test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
957 } else
958 debugl1(cs, "hfc_fill_dfifo blocked");
959 spin_unlock_irqrestore(&cs->lock, flags);
960 break;
961 case (PH_PULL | REQUEST):
962#ifdef L2FRAME_DEBUG /* psa */
963 if (cs->debug & L1_DEB_LAPD)
964 debugl1(cs, "-> PH_REQUEST_PULL");
965#endif
966 if (!cs->tx_skb) {
967 test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
968 st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
969 } else
970 test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
971 break;
972 case (HW_RESET | REQUEST):
973 spin_lock_irqsave(&cs->lock, flags);
974 cs->writeisac(cs, HFCD_STATES, HFCD_LOAD_STATE | 3); /* HFC ST 3 */
975 udelay(6);
976 cs->writeisac(cs, HFCD_STATES, 3); /* HFC ST 2 */
977 cs->hw.hfcD.mst_m |= HFCD_MASTER;
978 cs->writeisac(cs, HFCD_MST_MODE, cs->hw.hfcD.mst_m);
979 cs->writeisac(cs, HFCD_STATES, HFCD_ACTIVATE | HFCD_DO_ACTION);
980 spin_unlock_irqrestore(&cs->lock, flags);
981 l1_msg(cs, HW_POWERUP | CONFIRM, NULL);
982 break;
983 case (HW_ENABLE | REQUEST):
984 spin_lock_irqsave(&cs->lock, flags);
985 cs->writeisac(cs, HFCD_STATES, HFCD_ACTIVATE | HFCD_DO_ACTION);
986 spin_unlock_irqrestore(&cs->lock, flags);
987 break;
988 case (HW_DEACTIVATE | REQUEST):
989 spin_lock_irqsave(&cs->lock, flags);
990 cs->hw.hfcD.mst_m &= ~HFCD_MASTER;
991 cs->writeisac(cs, HFCD_MST_MODE, cs->hw.hfcD.mst_m);
992 spin_unlock_irqrestore(&cs->lock, flags);
993 break;
994 case (HW_INFO3 | REQUEST):
995 spin_lock_irqsave(&cs->lock, flags);
996 cs->hw.hfcD.mst_m |= HFCD_MASTER;
997 cs->writeisac(cs, HFCD_MST_MODE, cs->hw.hfcD.mst_m);
998 spin_unlock_irqrestore(&cs->lock, flags);
999 break;
1000 default:
1001 if (cs->debug & L1_DEB_WARN)
1002 debugl1(cs, "hfcd_l1hw unknown pr %4x", pr);
1003 break;
1004 }
1005}
1006
1007void
1008setstack_hfcd(struct PStack *st, struct IsdnCardState *cs)
1009{
1010 st->l1.l1hw = HFCD_l1hw;
1011}
1012
1013static void
1014hfc_dbusy_timer(struct IsdnCardState *cs)
1015{
1016}
1017
1018unsigned int __init
1019*init_send_hfcd(int cnt)
1020{
1021 int i, *send;
1022
1023 if (!(send = kmalloc(cnt * sizeof(unsigned int), GFP_ATOMIC))) {
1024 printk(KERN_WARNING
1025 "HiSax: No memory for hfcd.send\n");
1026 return(NULL);
1027 }
1028 for (i = 0; i < cnt; i++)
1029 send[i] = 0x1fff;
1030 return(send);
1031}
1032
1033void __init
1034init2bds0(struct IsdnCardState *cs)
1035{
1036 cs->setstack_d = setstack_hfcd;
1037 if (!cs->hw.hfcD.send)
1038 cs->hw.hfcD.send = init_send_hfcd(16);
1039 if (!cs->bcs[0].hw.hfc.send)
1040 cs->bcs[0].hw.hfc.send = init_send_hfcd(32);
1041 if (!cs->bcs[1].hw.hfc.send)
1042 cs->bcs[1].hw.hfc.send = init_send_hfcd(32);
1043 cs->BC_Send_Data = &hfc_send_data;
1044 cs->bcs[0].BC_SetStack = setstack_2b;
1045 cs->bcs[1].BC_SetStack = setstack_2b;
1046 cs->bcs[0].BC_Close = close_2bs0;
1047 cs->bcs[1].BC_Close = close_2bs0;
1048 mode_2bs0(cs->bcs, 0, 0);
1049 mode_2bs0(cs->bcs + 1, 0, 1);
1050}
1051
1052void
1053release2bds0(struct IsdnCardState *cs)
1054{
1055 if (cs->bcs[0].hw.hfc.send) {
1056 kfree(cs->bcs[0].hw.hfc.send);
1057 cs->bcs[0].hw.hfc.send = NULL;
1058 }
1059 if (cs->bcs[1].hw.hfc.send) {
1060 kfree(cs->bcs[1].hw.hfc.send);
1061 cs->bcs[1].hw.hfc.send = NULL;
1062 }
1063 if (cs->hw.hfcD.send) {
1064 kfree(cs->hw.hfcD.send);
1065 cs->hw.hfcD.send = NULL;
1066 }
1067}
1068
1069void
1070set_cs_func(struct IsdnCardState *cs)
1071{
1072 cs->readisac = &readreghfcd;
1073 cs->writeisac = &writereghfcd;
1074 cs->readisacfifo = &dummyf;
1075 cs->writeisacfifo = &dummyf;
1076 cs->BC_Read_Reg = &ReadReg;
1077 cs->BC_Write_Reg = &WriteReg;
1078 cs->dbusytimer.function = (void *) hfc_dbusy_timer;
1079 cs->dbusytimer.data = (long) cs;
1080 init_timer(&cs->dbusytimer);
1081 INIT_WORK(&cs->tqueue, (void *)(void *) hfcd_bh, cs);
1082}
diff --git a/drivers/isdn/hisax/hfc_2bds0.h b/drivers/isdn/hisax/hfc_2bds0.h
new file mode 100644
index 000000000000..30f1924db91c
--- /dev/null
+++ b/drivers/isdn/hisax/hfc_2bds0.h
@@ -0,0 +1,128 @@
1/* $Id: hfc_2bds0.h,v 1.6.2.2 2004/01/12 22:52:26 keil Exp $
2 *
3 * specific defines for CCD's HFC 2BDS0
4 *
5 * Author Karsten Keil
6 * Copyright by Karsten Keil <keil@isdn4linux.de>
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 */
12
13#define HFCD_CIRM 0x18
14#define HFCD_CTMT 0x19
15#define HFCD_INT_M1 0x1A
16#define HFCD_INT_M2 0x1B
17#define HFCD_INT_S1 0x1E
18#define HFCD_STAT 0x1C
19#define HFCD_STAT_DISB 0x1D
20#define HFCD_STATES 0x30
21#define HFCD_SCTRL 0x31
22#define HFCD_TEST 0x32
23#define HFCD_SQ 0x34
24#define HFCD_CLKDEL 0x37
25#define HFCD_MST_MODE 0x2E
26#define HFCD_CONN 0x2F
27
28#define HFCD_FIFO 0x80
29#define HFCD_Z1 0x10
30#define HFCD_Z2 0x18
31#define HFCD_Z_LOW 0x00
32#define HFCD_Z_HIGH 0x04
33#define HFCD_F1_INC 0x12
34#define HFCD_FIFO_IN 0x16
35#define HFCD_F1 0x1a
36#define HFCD_F2 0x1e
37#define HFCD_F2_INC 0x22
38#define HFCD_FIFO_OUT 0x26
39#define HFCD_REC 0x01
40#define HFCD_SEND 0x00
41
42#define HFCB_FIFO 0x80
43#define HFCB_Z1 0x00
44#define HFCB_Z2 0x08
45#define HFCB_Z_LOW 0x00
46#define HFCB_Z_HIGH 0x04
47#define HFCB_F1_INC 0x28
48#define HFCB_FIFO_IN 0x2c
49#define HFCB_F1 0x30
50#define HFCB_F2 0x34
51#define HFCB_F2_INC 0x38
52#define HFCB_FIFO_OUT 0x3c
53#define HFCB_REC 0x01
54#define HFCB_SEND 0x00
55#define HFCB_B1 0x00
56#define HFCB_B2 0x02
57#define HFCB_CHANNEL(ch) (ch ? HFCB_B2 : HFCB_B1)
58
59#define HFCD_STATUS 0
60#define HFCD_DATA 1
61#define HFCD_DATA_NODEB 2
62
63/* Status (READ) */
64#define HFCD_BUSY 0x01
65#define HFCD_BUSY_NBUSY 0x04
66#define HFCD_TIMER_ELAP 0x10
67#define HFCD_STATINT 0x20
68#define HFCD_FRAMEINT 0x40
69#define HFCD_ANYINT 0x80
70
71/* CTMT (Write) */
72#define HFCD_CLTIMER 0x80
73#define HFCD_TIM25 0x00
74#define HFCD_TIM50 0x08
75#define HFCD_TIM400 0x10
76#define HFCD_TIM800 0x18
77#define HFCD_AUTO_TIMER 0x20
78#define HFCD_TRANSB2 0x02
79#define HFCD_TRANSB1 0x01
80
81/* CIRM (Write) */
82#define HFCD_RESET 0x08
83#define HFCD_MEM8K 0x10
84#define HFCD_INTA 0x01
85#define HFCD_INTB 0x02
86#define HFCD_INTC 0x03
87#define HFCD_INTD 0x04
88#define HFCD_INTE 0x05
89#define HFCD_INTF 0x06
90
91/* INT_M1;INT_S1 */
92#define HFCD_INTS_B1TRANS 0x01
93#define HFCD_INTS_B2TRANS 0x02
94#define HFCD_INTS_DTRANS 0x04
95#define HFCD_INTS_B1REC 0x08
96#define HFCD_INTS_B2REC 0x10
97#define HFCD_INTS_DREC 0x20
98#define HFCD_INTS_L1STATE 0x40
99#define HFCD_INTS_TIMER 0x80
100
101/* INT_M2 */
102#define HFCD_IRQ_ENABLE 0x08
103
104/* STATES */
105#define HFCD_LOAD_STATE 0x10
106#define HFCD_ACTIVATE 0x20
107#define HFCD_DO_ACTION 0x40
108
109/* HFCD_MST_MODE */
110#define HFCD_MASTER 0x01
111
112/* HFCD_SCTRL */
113#define SCTRL_B1_ENA 0x01
114#define SCTRL_B2_ENA 0x02
115#define SCTRL_LOW_PRIO 0x08
116#define SCTRL_SQ_ENA 0x10
117#define SCTRL_TEST 0x20
118#define SCTRL_NONE_CAP 0x40
119#define SCTRL_PWR_DOWN 0x80
120
121/* HFCD_TEST */
122#define HFCD_AUTO_AWAKE 0x01
123
124extern void main_irq_2bds0(struct BCState *bcs);
125extern void init2bds0(struct IsdnCardState *cs);
126extern void release2bds0(struct IsdnCardState *cs);
127extern void hfc2bds0_interrupt(struct IsdnCardState *cs, u_char val);
128extern void set_cs_func(struct IsdnCardState *cs);
diff --git a/drivers/isdn/hisax/hfc_2bs0.c b/drivers/isdn/hisax/hfc_2bs0.c
new file mode 100644
index 000000000000..bb376f39ac89
--- /dev/null
+++ b/drivers/isdn/hisax/hfc_2bs0.c
@@ -0,0 +1,593 @@
1/* $Id: hfc_2bs0.c,v 1.20.2.6 2004/02/11 13:21:33 keil Exp $
2 *
3 * specific routines for CCD's HFC 2BS0
4 *
5 * Author Karsten Keil
6 * Copyright by Karsten Keil <keil@isdn4linux.de>
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 */
12
13#include <linux/init.h>
14#include "hisax.h"
15#include "hfc_2bs0.h"
16#include "isac.h"
17#include "isdnl1.h"
18#include <linux/interrupt.h>
19
20static inline int
21WaitForBusy(struct IsdnCardState *cs)
22{
23 int to = 130;
24 u_char val;
25
26 while (!(cs->BC_Read_Reg(cs, HFC_STATUS, 0) & HFC_BUSY) && to) {
27 val = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2 |
28 (cs->hw.hfc.cip & 3));
29 udelay(1);
30 to--;
31 }
32 if (!to) {
33 printk(KERN_WARNING "HiSax: waitforBusy timeout\n");
34 return (0);
35 } else
36 return (to);
37}
38
39static inline int
40WaitNoBusy(struct IsdnCardState *cs)
41{
42 int to = 125;
43
44 while ((cs->BC_Read_Reg(cs, HFC_STATUS, 0) & HFC_BUSY) && to) {
45 udelay(1);
46 to--;
47 }
48 if (!to) {
49 printk(KERN_WARNING "HiSax: waitforBusy timeout\n");
50 return (0);
51 } else
52 return (to);
53}
54
55int
56GetFreeFifoBytes(struct BCState *bcs)
57{
58 int s;
59
60 if (bcs->hw.hfc.f1 == bcs->hw.hfc.f2)
61 return (bcs->cs->hw.hfc.fifosize);
62 s = bcs->hw.hfc.send[bcs->hw.hfc.f1] - bcs->hw.hfc.send[bcs->hw.hfc.f2];
63 if (s <= 0)
64 s += bcs->cs->hw.hfc.fifosize;
65 s = bcs->cs->hw.hfc.fifosize - s;
66 return (s);
67}
68
69int
70ReadZReg(struct BCState *bcs, u_char reg)
71{
72 int val;
73
74 WaitNoBusy(bcs->cs);
75 val = 256 * bcs->cs->BC_Read_Reg(bcs->cs, HFC_DATA, reg | HFC_CIP | HFC_Z_HIGH);
76 WaitNoBusy(bcs->cs);
77 val += bcs->cs->BC_Read_Reg(bcs->cs, HFC_DATA, reg | HFC_CIP | HFC_Z_LOW);
78 return (val);
79}
80
81static void
82hfc_clear_fifo(struct BCState *bcs)
83{
84 struct IsdnCardState *cs = bcs->cs;
85 int idx, cnt;
86 int rcnt, z1, z2;
87 u_char cip, f1, f2;
88
89 if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
90 debugl1(cs, "hfc_clear_fifo");
91 cip = HFC_CIP | HFC_F1 | HFC_REC | HFC_CHANNEL(bcs->channel);
92 if ((cip & 0xc3) != (cs->hw.hfc.cip & 0xc3)) {
93 cs->BC_Write_Reg(cs, HFC_STATUS, cip, cip);
94 WaitForBusy(cs);
95 }
96 WaitNoBusy(cs);
97 f1 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
98 cip = HFC_CIP | HFC_F2 | HFC_REC | HFC_CHANNEL(bcs->channel);
99 WaitNoBusy(cs);
100 f2 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
101 z1 = ReadZReg(bcs, HFC_Z1 | HFC_REC | HFC_CHANNEL(bcs->channel));
102 z2 = ReadZReg(bcs, HFC_Z2 | HFC_REC | HFC_CHANNEL(bcs->channel));
103 cnt = 32;
104 while (((f1 != f2) || (z1 != z2)) && cnt--) {
105 if (cs->debug & L1_DEB_HSCX)
106 debugl1(cs, "hfc clear %d f1(%d) f2(%d)",
107 bcs->channel, f1, f2);
108 rcnt = z1 - z2;
109 if (rcnt < 0)
110 rcnt += cs->hw.hfc.fifosize;
111 if (rcnt)
112 rcnt++;
113 if (cs->debug & L1_DEB_HSCX)
114 debugl1(cs, "hfc clear %d z1(%x) z2(%x) cnt(%d)",
115 bcs->channel, z1, z2, rcnt);
116 cip = HFC_CIP | HFC_FIFO_OUT | HFC_REC | HFC_CHANNEL(bcs->channel);
117 idx = 0;
118 while ((idx < rcnt) && WaitNoBusy(cs)) {
119 cs->BC_Read_Reg(cs, HFC_DATA_NODEB, cip);
120 idx++;
121 }
122 if (f1 != f2) {
123 WaitNoBusy(cs);
124 cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC |
125 HFC_CHANNEL(bcs->channel));
126 WaitForBusy(cs);
127 }
128 cip = HFC_CIP | HFC_F1 | HFC_REC | HFC_CHANNEL(bcs->channel);
129 WaitNoBusy(cs);
130 f1 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
131 cip = HFC_CIP | HFC_F2 | HFC_REC | HFC_CHANNEL(bcs->channel);
132 WaitNoBusy(cs);
133 f2 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
134 z1 = ReadZReg(bcs, HFC_Z1 | HFC_REC | HFC_CHANNEL(bcs->channel));
135 z2 = ReadZReg(bcs, HFC_Z2 | HFC_REC | HFC_CHANNEL(bcs->channel));
136 }
137 return;
138}
139
140
141static struct sk_buff
142*
143hfc_empty_fifo(struct BCState *bcs, int count)
144{
145 u_char *ptr;
146 struct sk_buff *skb;
147 struct IsdnCardState *cs = bcs->cs;
148 int idx;
149 int chksum;
150 u_char stat, cip;
151
152 if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
153 debugl1(cs, "hfc_empty_fifo");
154 idx = 0;
155 if (count > HSCX_BUFMAX + 3) {
156 if (cs->debug & L1_DEB_WARN)
157 debugl1(cs, "hfc_empty_fifo: incoming packet too large");
158 cip = HFC_CIP | HFC_FIFO_OUT | HFC_REC | HFC_CHANNEL(bcs->channel);
159 while ((idx++ < count) && WaitNoBusy(cs))
160 cs->BC_Read_Reg(cs, HFC_DATA_NODEB, cip);
161 WaitNoBusy(cs);
162 stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC |
163 HFC_CHANNEL(bcs->channel));
164 WaitForBusy(cs);
165 return (NULL);
166 }
167 if ((count < 4) && (bcs->mode != L1_MODE_TRANS)) {
168 if (cs->debug & L1_DEB_WARN)
169 debugl1(cs, "hfc_empty_fifo: incoming packet too small");
170 cip = HFC_CIP | HFC_FIFO_OUT | HFC_REC | HFC_CHANNEL(bcs->channel);
171 while ((idx++ < count) && WaitNoBusy(cs))
172 cs->BC_Read_Reg(cs, HFC_DATA_NODEB, cip);
173 WaitNoBusy(cs);
174 stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC |
175 HFC_CHANNEL(bcs->channel));
176 WaitForBusy(cs);
177#ifdef ERROR_STATISTIC
178 bcs->err_inv++;
179#endif
180 return (NULL);
181 }
182 if (bcs->mode == L1_MODE_TRANS)
183 count -= 1;
184 else
185 count -= 3;
186 if (!(skb = dev_alloc_skb(count)))
187 printk(KERN_WARNING "HFC: receive out of memory\n");
188 else {
189 ptr = skb_put(skb, count);
190 idx = 0;
191 cip = HFC_CIP | HFC_FIFO_OUT | HFC_REC | HFC_CHANNEL(bcs->channel);
192 while ((idx < count) && WaitNoBusy(cs)) {
193 *ptr++ = cs->BC_Read_Reg(cs, HFC_DATA_NODEB, cip);
194 idx++;
195 }
196 if (idx != count) {
197 debugl1(cs, "RFIFO BUSY error");
198 printk(KERN_WARNING "HFC FIFO channel %d BUSY Error\n", bcs->channel);
199 dev_kfree_skb_any(skb);
200 if (bcs->mode != L1_MODE_TRANS) {
201 WaitNoBusy(cs);
202 stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC |
203 HFC_CHANNEL(bcs->channel));
204 WaitForBusy(cs);
205 }
206 return (NULL);
207 }
208 if (bcs->mode != L1_MODE_TRANS) {
209 WaitNoBusy(cs);
210 chksum = (cs->BC_Read_Reg(cs, HFC_DATA, cip) << 8);
211 WaitNoBusy(cs);
212 chksum += cs->BC_Read_Reg(cs, HFC_DATA, cip);
213 WaitNoBusy(cs);
214 stat = cs->BC_Read_Reg(cs, HFC_DATA, cip);
215 if (cs->debug & L1_DEB_HSCX)
216 debugl1(cs, "hfc_empty_fifo %d chksum %x stat %x",
217 bcs->channel, chksum, stat);
218 if (stat) {
219 debugl1(cs, "FIFO CRC error");
220 dev_kfree_skb_any(skb);
221 skb = NULL;
222#ifdef ERROR_STATISTIC
223 bcs->err_crc++;
224#endif
225 }
226 WaitNoBusy(cs);
227 stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC |
228 HFC_CHANNEL(bcs->channel));
229 WaitForBusy(cs);
230 }
231 }
232 return (skb);
233}
234
235static void
236hfc_fill_fifo(struct BCState *bcs)
237{
238 struct IsdnCardState *cs = bcs->cs;
239 int idx, fcnt;
240 int count;
241 int z1, z2;
242 u_char cip;
243
244 if (!bcs->tx_skb)
245 return;
246 if (bcs->tx_skb->len <= 0)
247 return;
248
249 cip = HFC_CIP | HFC_F1 | HFC_SEND | HFC_CHANNEL(bcs->channel);
250 if ((cip & 0xc3) != (cs->hw.hfc.cip & 0xc3)) {
251 cs->BC_Write_Reg(cs, HFC_STATUS, cip, cip);
252 WaitForBusy(cs);
253 }
254 WaitNoBusy(cs);
255 if (bcs->mode != L1_MODE_TRANS) {
256 bcs->hw.hfc.f1 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
257 cip = HFC_CIP | HFC_F2 | HFC_SEND | HFC_CHANNEL(bcs->channel);
258 WaitNoBusy(cs);
259 bcs->hw.hfc.f2 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
260 bcs->hw.hfc.send[bcs->hw.hfc.f1] = ReadZReg(bcs, HFC_Z1 | HFC_SEND | HFC_CHANNEL(bcs->channel));
261 if (cs->debug & L1_DEB_HSCX)
262 debugl1(cs, "hfc_fill_fifo %d f1(%d) f2(%d) z1(%x)",
263 bcs->channel, bcs->hw.hfc.f1, bcs->hw.hfc.f2,
264 bcs->hw.hfc.send[bcs->hw.hfc.f1]);
265 fcnt = bcs->hw.hfc.f1 - bcs->hw.hfc.f2;
266 if (fcnt < 0)
267 fcnt += 32;
268 if (fcnt > 30) {
269 if (cs->debug & L1_DEB_HSCX)
270 debugl1(cs, "hfc_fill_fifo more as 30 frames");
271 return;
272 }
273 count = GetFreeFifoBytes(bcs);
274 }
275 else {
276 WaitForBusy(cs);
277 z1 = ReadZReg(bcs, HFC_Z1 | HFC_REC | HFC_CHANNEL(bcs->channel));
278 z2 = ReadZReg(bcs, HFC_Z2 | HFC_REC | HFC_CHANNEL(bcs->channel));
279 count = z1 - z2;
280 if (count < 0)
281 count += cs->hw.hfc.fifosize;
282 } /* L1_MODE_TRANS */
283 if (cs->debug & L1_DEB_HSCX)
284 debugl1(cs, "hfc_fill_fifo %d count(%ld/%d)",
285 bcs->channel, bcs->tx_skb->len,
286 count);
287 if (count < bcs->tx_skb->len) {
288 if (cs->debug & L1_DEB_HSCX)
289 debugl1(cs, "hfc_fill_fifo no fifo mem");
290 return;
291 }
292 cip = HFC_CIP | HFC_FIFO_IN | HFC_SEND | HFC_CHANNEL(bcs->channel);
293 idx = 0;
294 while ((idx < bcs->tx_skb->len) && WaitNoBusy(cs))
295 cs->BC_Write_Reg(cs, HFC_DATA_NODEB, cip, bcs->tx_skb->data[idx++]);
296 if (idx != bcs->tx_skb->len) {
297 debugl1(cs, "FIFO Send BUSY error");
298 printk(KERN_WARNING "HFC S FIFO channel %d BUSY Error\n", bcs->channel);
299 } else {
300 count = bcs->tx_skb->len;
301 bcs->tx_cnt -= count;
302 if (PACKET_NOACK == bcs->tx_skb->pkt_type)
303 count = -1;
304 dev_kfree_skb_any(bcs->tx_skb);
305 bcs->tx_skb = NULL;
306 if (bcs->mode != L1_MODE_TRANS) {
307 WaitForBusy(cs);
308 WaitNoBusy(cs);
309 cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F1_INC | HFC_SEND | HFC_CHANNEL(bcs->channel));
310 }
311 if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) &&
312 (count >= 0)) {
313 u_long flags;
314 spin_lock_irqsave(&bcs->aclock, flags);
315 bcs->ackcnt += count;
316 spin_unlock_irqrestore(&bcs->aclock, flags);
317 schedule_event(bcs, B_ACKPENDING);
318 }
319 test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
320 }
321 return;
322}
323
324void
325main_irq_hfc(struct BCState *bcs)
326{
327 struct IsdnCardState *cs = bcs->cs;
328 int z1, z2, rcnt;
329 u_char f1, f2, cip;
330 int receive, transmit, count = 5;
331 struct sk_buff *skb;
332
333 Begin:
334 count--;
335 cip = HFC_CIP | HFC_F1 | HFC_REC | HFC_CHANNEL(bcs->channel);
336 if ((cip & 0xc3) != (cs->hw.hfc.cip & 0xc3)) {
337 cs->BC_Write_Reg(cs, HFC_STATUS, cip, cip);
338 WaitForBusy(cs);
339 }
340 WaitNoBusy(cs);
341 receive = 0;
342 if (bcs->mode == L1_MODE_HDLC) {
343 f1 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
344 cip = HFC_CIP | HFC_F2 | HFC_REC | HFC_CHANNEL(bcs->channel);
345 WaitNoBusy(cs);
346 f2 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
347 if (f1 != f2) {
348 if (cs->debug & L1_DEB_HSCX)
349 debugl1(cs, "hfc rec %d f1(%d) f2(%d)",
350 bcs->channel, f1, f2);
351 receive = 1;
352 }
353 }
354 if (receive || (bcs->mode == L1_MODE_TRANS)) {
355 WaitForBusy(cs);
356 z1 = ReadZReg(bcs, HFC_Z1 | HFC_REC | HFC_CHANNEL(bcs->channel));
357 z2 = ReadZReg(bcs, HFC_Z2 | HFC_REC | HFC_CHANNEL(bcs->channel));
358 rcnt = z1 - z2;
359 if (rcnt < 0)
360 rcnt += cs->hw.hfc.fifosize;
361 if ((bcs->mode == L1_MODE_HDLC) || (rcnt)) {
362 rcnt++;
363 if (cs->debug & L1_DEB_HSCX)
364 debugl1(cs, "hfc rec %d z1(%x) z2(%x) cnt(%d)",
365 bcs->channel, z1, z2, rcnt);
366 /* sti(); */
367 if ((skb = hfc_empty_fifo(bcs, rcnt))) {
368 skb_queue_tail(&bcs->rqueue, skb);
369 schedule_event(bcs, B_RCVBUFREADY);
370 }
371 }
372 receive = 1;
373 }
374 if (bcs->tx_skb) {
375 transmit = 1;
376 test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
377 hfc_fill_fifo(bcs);
378 if (test_bit(BC_FLG_BUSY, &bcs->Flag))
379 transmit = 0;
380 } else {
381 if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
382 transmit = 1;
383 test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
384 hfc_fill_fifo(bcs);
385 if (test_bit(BC_FLG_BUSY, &bcs->Flag))
386 transmit = 0;
387 } else {
388 transmit = 0;
389 schedule_event(bcs, B_XMTBUFREADY);
390 }
391 }
392 if ((receive || transmit) && count)
393 goto Begin;
394 return;
395}
396
397void
398mode_hfc(struct BCState *bcs, int mode, int bc)
399{
400 struct IsdnCardState *cs = bcs->cs;
401
402 if (cs->debug & L1_DEB_HSCX)
403 debugl1(cs, "HFC 2BS0 mode %d bchan %d/%d",
404 mode, bc, bcs->channel);
405 bcs->mode = mode;
406 bcs->channel = bc;
407
408 switch (mode) {
409 case (L1_MODE_NULL):
410 if (bc) {
411 cs->hw.hfc.ctmt &= ~1;
412 cs->hw.hfc.isac_spcr &= ~0x03;
413 }
414 else {
415 cs->hw.hfc.ctmt &= ~2;
416 cs->hw.hfc.isac_spcr &= ~0x0c;
417 }
418 break;
419 case (L1_MODE_TRANS):
420 cs->hw.hfc.ctmt &= ~(1 << bc); /* set HDLC mode */
421 cs->BC_Write_Reg(cs, HFC_STATUS, cs->hw.hfc.ctmt, cs->hw.hfc.ctmt);
422 hfc_clear_fifo(bcs); /* complete fifo clear */
423 if (bc) {
424 cs->hw.hfc.ctmt |= 1;
425 cs->hw.hfc.isac_spcr &= ~0x03;
426 cs->hw.hfc.isac_spcr |= 0x02;
427 } else {
428 cs->hw.hfc.ctmt |= 2;
429 cs->hw.hfc.isac_spcr &= ~0x0c;
430 cs->hw.hfc.isac_spcr |= 0x08;
431 }
432 break;
433 case (L1_MODE_HDLC):
434 if (bc) {
435 cs->hw.hfc.ctmt &= ~1;
436 cs->hw.hfc.isac_spcr &= ~0x03;
437 cs->hw.hfc.isac_spcr |= 0x02;
438 } else {
439 cs->hw.hfc.ctmt &= ~2;
440 cs->hw.hfc.isac_spcr &= ~0x0c;
441 cs->hw.hfc.isac_spcr |= 0x08;
442 }
443 break;
444 }
445 cs->BC_Write_Reg(cs, HFC_STATUS, cs->hw.hfc.ctmt, cs->hw.hfc.ctmt);
446 cs->writeisac(cs, ISAC_SPCR, cs->hw.hfc.isac_spcr);
447 if (mode == L1_MODE_HDLC)
448 hfc_clear_fifo(bcs);
449}
450
451static void
452hfc_l2l1(struct PStack *st, int pr, void *arg)
453{
454 struct BCState *bcs = st->l1.bcs;
455 struct sk_buff *skb = arg;
456 u_long flags;
457
458 switch (pr) {
459 case (PH_DATA | REQUEST):
460 spin_lock_irqsave(&bcs->cs->lock, flags);
461 if (bcs->tx_skb) {
462 skb_queue_tail(&bcs->squeue, skb);
463 } else {
464 bcs->tx_skb = skb;
465 test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
466 bcs->cs->BC_Send_Data(bcs);
467 }
468 spin_unlock_irqrestore(&bcs->cs->lock, flags);
469 break;
470 case (PH_PULL | INDICATION):
471 spin_lock_irqsave(&bcs->cs->lock, flags);
472 if (bcs->tx_skb) {
473 printk(KERN_WARNING "hfc_l2l1: this shouldn't happen\n");
474 } else {
475 test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
476 bcs->tx_skb = skb;
477 bcs->cs->BC_Send_Data(bcs);
478 }
479 spin_unlock_irqrestore(&bcs->cs->lock, flags);
480 break;
481 case (PH_PULL | REQUEST):
482 if (!bcs->tx_skb) {
483 test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
484 st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
485 } else
486 test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
487 break;
488 case (PH_ACTIVATE | REQUEST):
489 spin_lock_irqsave(&bcs->cs->lock, flags);
490 test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag);
491 mode_hfc(bcs, st->l1.mode, st->l1.bc);
492 spin_unlock_irqrestore(&bcs->cs->lock, flags);
493 l1_msg_b(st, pr, arg);
494 break;
495 case (PH_DEACTIVATE | REQUEST):
496 l1_msg_b(st, pr, arg);
497 break;
498 case (PH_DEACTIVATE | CONFIRM):
499 spin_lock_irqsave(&bcs->cs->lock, flags);
500 test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag);
501 test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
502 mode_hfc(bcs, 0, st->l1.bc);
503 spin_unlock_irqrestore(&bcs->cs->lock, flags);
504 st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
505 break;
506 }
507}
508
509
510void
511close_hfcstate(struct BCState *bcs)
512{
513 mode_hfc(bcs, 0, bcs->channel);
514 if (test_bit(BC_FLG_INIT, &bcs->Flag)) {
515 skb_queue_purge(&bcs->rqueue);
516 skb_queue_purge(&bcs->squeue);
517 if (bcs->tx_skb) {
518 dev_kfree_skb_any(bcs->tx_skb);
519 bcs->tx_skb = NULL;
520 test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
521 }
522 }
523 test_and_clear_bit(BC_FLG_INIT, &bcs->Flag);
524}
525
526static int
527open_hfcstate(struct IsdnCardState *cs, struct BCState *bcs)
528{
529 if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
530 skb_queue_head_init(&bcs->rqueue);
531 skb_queue_head_init(&bcs->squeue);
532 }
533 bcs->tx_skb = NULL;
534 test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
535 bcs->event = 0;
536 bcs->tx_cnt = 0;
537 return (0);
538}
539
540int
541setstack_hfc(struct PStack *st, struct BCState *bcs)
542{
543 bcs->channel = st->l1.bc;
544 if (open_hfcstate(st->l1.hardware, bcs))
545 return (-1);
546 st->l1.bcs = bcs;
547 st->l2.l2l1 = hfc_l2l1;
548 setstack_manager(st);
549 bcs->st = st;
550 setstack_l1_B(st);
551 return (0);
552}
553
554void __init
555init_send(struct BCState *bcs)
556{
557 int i;
558
559 if (!(bcs->hw.hfc.send = kmalloc(32 * sizeof(unsigned int), GFP_ATOMIC))) {
560 printk(KERN_WARNING
561 "HiSax: No memory for hfc.send\n");
562 return;
563 }
564 for (i = 0; i < 32; i++)
565 bcs->hw.hfc.send[i] = 0x1fff;
566}
567
568void __init
569inithfc(struct IsdnCardState *cs)
570{
571 init_send(&cs->bcs[0]);
572 init_send(&cs->bcs[1]);
573 cs->BC_Send_Data = &hfc_fill_fifo;
574 cs->bcs[0].BC_SetStack = setstack_hfc;
575 cs->bcs[1].BC_SetStack = setstack_hfc;
576 cs->bcs[0].BC_Close = close_hfcstate;
577 cs->bcs[1].BC_Close = close_hfcstate;
578 mode_hfc(cs->bcs, 0, 0);
579 mode_hfc(cs->bcs + 1, 0, 0);
580}
581
582void
583releasehfc(struct IsdnCardState *cs)
584{
585 if (cs->bcs[0].hw.hfc.send) {
586 kfree(cs->bcs[0].hw.hfc.send);
587 cs->bcs[0].hw.hfc.send = NULL;
588 }
589 if (cs->bcs[1].hw.hfc.send) {
590 kfree(cs->bcs[1].hw.hfc.send);
591 cs->bcs[1].hw.hfc.send = NULL;
592 }
593}
diff --git a/drivers/isdn/hisax/hfc_2bs0.h b/drivers/isdn/hisax/hfc_2bs0.h
new file mode 100644
index 000000000000..1a50d4a5c968
--- /dev/null
+++ b/drivers/isdn/hisax/hfc_2bs0.h
@@ -0,0 +1,60 @@
1/* $Id: hfc_2bs0.h,v 1.5.2.2 2004/01/12 22:52:26 keil Exp $
2 *
3 * specific defines for CCD's HFC 2BS0
4 *
5 * Author Karsten Keil
6 * Copyright by Karsten Keil <keil@isdn4linux.de>
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 */
12
13#define HFC_CTMT 0xe0
14#define HFC_CIRM 0xc0
15#define HFC_CIP 0x80
16#define HFC_Z1 0x00
17#define HFC_Z2 0x08
18#define HFC_Z_LOW 0x00
19#define HFC_Z_HIGH 0x04
20#define HFC_F1_INC 0x28
21#define HFC_FIFO_IN 0x2c
22#define HFC_F1 0x30
23#define HFC_F2 0x34
24#define HFC_F2_INC 0x38
25#define HFC_FIFO_OUT 0x3c
26#define HFC_B1 0x00
27#define HFC_B2 0x02
28#define HFC_REC 0x01
29#define HFC_SEND 0x00
30#define HFC_CHANNEL(ch) (ch ? HFC_B2 : HFC_B1)
31
32#define HFC_STATUS 0
33#define HFC_DATA 1
34#define HFC_DATA_NODEB 2
35
36/* Status (READ) */
37#define HFC_BUSY 0x01
38#define HFC_TIMINT 0x02
39#define HFC_EXTINT 0x04
40
41/* CTMT (Write) */
42#define HFC_CLTIMER 0x10
43#define HFC_TIM50MS 0x08
44#define HFC_TIMIRQE 0x04
45#define HFC_TRANSB2 0x02
46#define HFC_TRANSB1 0x01
47
48/* CIRM (Write) */
49#define HFC_RESET 0x08
50#define HFC_MEM8K 0x10
51#define HFC_INTA 0x01
52#define HFC_INTB 0x02
53#define HFC_INTC 0x03
54#define HFC_INTD 0x04
55#define HFC_INTE 0x05
56#define HFC_INTF 0x06
57
58extern void main_irq_hfc(struct BCState *bcs);
59extern void inithfc(struct IsdnCardState *cs);
60extern void releasehfc(struct IsdnCardState *cs);
diff --git a/drivers/isdn/hisax/hfc_pci.c b/drivers/isdn/hisax/hfc_pci.c
new file mode 100644
index 000000000000..c2db52696a86
--- /dev/null
+++ b/drivers/isdn/hisax/hfc_pci.c
@@ -0,0 +1,1747 @@
1/* $Id: hfc_pci.c,v 1.48.2.4 2004/02/11 13:21:33 keil Exp $
2 *
3 * low level driver for CCD´s hfc-pci based cards
4 *
5 * Author Werner Cornelius
6 * based on existing driver for CCD hfc ISA cards
7 * Copyright by Werner Cornelius <werner@isdn4linux.de>
8 * by Karsten Keil <keil@isdn4linux.de>
9 *
10 * This software may be used and distributed according to the terms
11 * of the GNU General Public License, incorporated herein by reference.
12 *
13 * For changes and modifications please read
14 * Documentation/isdn/HiSax.cert
15 *
16 */
17
18#include <linux/init.h>
19#include <linux/config.h>
20#include "hisax.h"
21#include "hfc_pci.h"
22#include "isdnl1.h"
23#include <linux/pci.h>
24#include <linux/interrupt.h>
25
26extern const char *CardType[];
27
28static const char *hfcpci_revision = "$Revision: 1.48.2.4 $";
29
30/* table entry in the PCI devices list */
31typedef struct {
32 int vendor_id;
33 int device_id;
34 char *vendor_name;
35 char *card_name;
36} PCI_ENTRY;
37
38#define NT_T1_COUNT 20 /* number of 3.125ms interrupts for G2 timeout */
39#define CLKDEL_TE 0x0e /* CLKDEL in TE mode */
40#define CLKDEL_NT 0x6c /* CLKDEL in NT mode */
41
42static const PCI_ENTRY id_list[] =
43{
44 {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_2BD0, "CCD/Billion/Asuscom", "2BD0"},
45 {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B000, "Billion", "B000"},
46 {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B006, "Billion", "B006"},
47 {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B007, "Billion", "B007"},
48 {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B008, "Billion", "B008"},
49 {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B009, "Billion", "B009"},
50 {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B00A, "Billion", "B00A"},
51 {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B00B, "Billion", "B00B"},
52 {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B00C, "Billion", "B00C"},
53 {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B100, "Seyeon", "B100"},
54 {PCI_VENDOR_ID_ABOCOM, PCI_DEVICE_ID_ABOCOM_2BD1, "Abocom/Magitek", "2BD1"},
55 {PCI_VENDOR_ID_ASUSTEK, PCI_DEVICE_ID_ASUSTEK_0675, "Asuscom/Askey", "675"},
56 {PCI_VENDOR_ID_BERKOM, PCI_DEVICE_ID_BERKOM_T_CONCEPT, "German telekom", "T-Concept"},
57 {PCI_VENDOR_ID_BERKOM, PCI_DEVICE_ID_BERKOM_A1T, "German telekom", "A1T"},
58 {PCI_VENDOR_ID_ANIGMA, PCI_DEVICE_ID_ANIGMA_MC145575, "Motorola MC145575", "MC145575"},
59 {PCI_VENDOR_ID_ZOLTRIX, PCI_DEVICE_ID_ZOLTRIX_2BD0, "Zoltrix", "2BD0"},
60 {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_E,"Digi International", "Digi DataFire Micro V IOM2 (Europe)"},
61 {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_E,"Digi International", "Digi DataFire Micro V (Europe)"},
62 {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_A,"Digi International", "Digi DataFire Micro V IOM2 (North America)"},
63 {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_A,"Digi International", "Digi DataFire Micro V (North America)"},
64 {0, 0, NULL, NULL},
65};
66
67
68#ifdef CONFIG_PCI
69
70/******************************************/
71/* free hardware resources used by driver */
72/******************************************/
73void
74release_io_hfcpci(struct IsdnCardState *cs)
75{
76 printk(KERN_INFO "HiSax: release hfcpci at %p\n",
77 cs->hw.hfcpci.pci_io);
78 cs->hw.hfcpci.int_m2 = 0; /* interrupt output off ! */
79 Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2);
80 Write_hfc(cs, HFCPCI_CIRM, HFCPCI_RESET); /* Reset On */
81 mdelay(10);
82 Write_hfc(cs, HFCPCI_CIRM, 0); /* Reset Off */
83 mdelay(10);
84 Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2);
85 pci_write_config_word(cs->hw.hfcpci.dev, PCI_COMMAND, 0); /* disable memory mapped ports + busmaster */
86 del_timer(&cs->hw.hfcpci.timer);
87 kfree(cs->hw.hfcpci.share_start);
88 cs->hw.hfcpci.share_start = NULL;
89 iounmap((void *)cs->hw.hfcpci.pci_io);
90}
91
92/********************************************************************************/
93/* function called to reset the HFC PCI chip. A complete software reset of chip */
94/* and fifos is done. */
95/********************************************************************************/
96static void
97reset_hfcpci(struct IsdnCardState *cs)
98{
99 pci_write_config_word(cs->hw.hfcpci.dev, PCI_COMMAND, PCI_ENA_MEMIO); /* enable memory mapped ports, disable busmaster */
100 cs->hw.hfcpci.int_m2 = 0; /* interrupt output off ! */
101 Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2);
102
103 printk(KERN_INFO "HFC_PCI: resetting card\n");
104 pci_write_config_word(cs->hw.hfcpci.dev, PCI_COMMAND, PCI_ENA_MEMIO + PCI_ENA_MASTER); /* enable memory ports + busmaster */
105 Write_hfc(cs, HFCPCI_CIRM, HFCPCI_RESET); /* Reset On */
106 mdelay(10);
107 Write_hfc(cs, HFCPCI_CIRM, 0); /* Reset Off */
108 mdelay(10);
109 if (Read_hfc(cs, HFCPCI_STATUS) & 2)
110 printk(KERN_WARNING "HFC-PCI init bit busy\n");
111
112 cs->hw.hfcpci.fifo_en = 0x30; /* only D fifos enabled */
113 Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en);
114
115 cs->hw.hfcpci.trm = 0 + HFCPCI_BTRANS_THRESMASK; /* no echo connect , threshold */
116 Write_hfc(cs, HFCPCI_TRM, cs->hw.hfcpci.trm);
117
118 Write_hfc(cs, HFCPCI_CLKDEL, CLKDEL_TE); /* ST-Bit delay for TE-Mode */
119 cs->hw.hfcpci.sctrl_e = HFCPCI_AUTO_AWAKE;
120 Write_hfc(cs, HFCPCI_SCTRL_E, cs->hw.hfcpci.sctrl_e); /* S/T Auto awake */
121 cs->hw.hfcpci.bswapped = 0; /* no exchange */
122 cs->hw.hfcpci.nt_mode = 0; /* we are in TE mode */
123 cs->hw.hfcpci.ctmt = HFCPCI_TIM3_125 | HFCPCI_AUTO_TIMER;
124 Write_hfc(cs, HFCPCI_CTMT, cs->hw.hfcpci.ctmt);
125
126 cs->hw.hfcpci.int_m1 = HFCPCI_INTS_DTRANS | HFCPCI_INTS_DREC |
127 HFCPCI_INTS_L1STATE | HFCPCI_INTS_TIMER;
128 Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1);
129
130 /* Clear already pending ints */
131 if (Read_hfc(cs, HFCPCI_INT_S1));
132
133 Write_hfc(cs, HFCPCI_STATES, HFCPCI_LOAD_STATE | 2); /* HFC ST 2 */
134 udelay(10);
135 Write_hfc(cs, HFCPCI_STATES, 2); /* HFC ST 2 */
136 cs->hw.hfcpci.mst_m = HFCPCI_MASTER; /* HFC Master Mode */
137
138 Write_hfc(cs, HFCPCI_MST_MODE, cs->hw.hfcpci.mst_m);
139 cs->hw.hfcpci.sctrl = 0x40; /* set tx_lo mode, error in datasheet ! */
140 Write_hfc(cs, HFCPCI_SCTRL, cs->hw.hfcpci.sctrl);
141 cs->hw.hfcpci.sctrl_r = 0;
142 Write_hfc(cs, HFCPCI_SCTRL_R, cs->hw.hfcpci.sctrl_r);
143
144 /* Init GCI/IOM2 in master mode */
145 /* Slots 0 and 1 are set for B-chan 1 and 2 */
146 /* D- and monitor/CI channel are not enabled */
147 /* STIO1 is used as output for data, B1+B2 from ST->IOM+HFC */
148 /* STIO2 is used as data input, B1+B2 from IOM->ST */
149 /* ST B-channel send disabled -> continous 1s */
150 /* The IOM slots are always enabled */
151 cs->hw.hfcpci.conn = 0x36; /* set data flow directions */
152 Write_hfc(cs, HFCPCI_CONNECT, cs->hw.hfcpci.conn);
153 Write_hfc(cs, HFCPCI_B1_SSL, 0x80); /* B1-Slot 0 STIO1 out enabled */
154 Write_hfc(cs, HFCPCI_B2_SSL, 0x81); /* B2-Slot 1 STIO1 out enabled */
155 Write_hfc(cs, HFCPCI_B1_RSL, 0x80); /* B1-Slot 0 STIO2 in enabled */
156 Write_hfc(cs, HFCPCI_B2_RSL, 0x81); /* B2-Slot 1 STIO2 in enabled */
157
158 /* Finally enable IRQ output */
159 cs->hw.hfcpci.int_m2 = HFCPCI_IRQ_ENABLE;
160 Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2);
161 if (Read_hfc(cs, HFCPCI_INT_S1));
162}
163
164/***************************************************/
165/* Timer function called when kernel timer expires */
166/***************************************************/
167static void
168hfcpci_Timer(struct IsdnCardState *cs)
169{
170 cs->hw.hfcpci.timer.expires = jiffies + 75;
171 /* WD RESET */
172/* WriteReg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcpci.ctmt | 0x80);
173 add_timer(&cs->hw.hfcpci.timer);
174 */
175}
176
177
178/*********************************/
179/* schedule a new D-channel task */
180/*********************************/
181static void
182sched_event_D_pci(struct IsdnCardState *cs, int event)
183{
184 test_and_set_bit(event, &cs->event);
185 schedule_work(&cs->tqueue);
186}
187
188/*********************************/
189/* schedule a new b_channel task */
190/*********************************/
191static void
192hfcpci_sched_event(struct BCState *bcs, int event)
193{
194 test_and_set_bit(event, &bcs->event);
195 schedule_work(&bcs->tqueue);
196}
197
198/************************************************/
199/* select a b-channel entry matching and active */
200/************************************************/
201static
202struct BCState *
203Sel_BCS(struct IsdnCardState *cs, int channel)
204{
205 if (cs->bcs[0].mode && (cs->bcs[0].channel == channel))
206 return (&cs->bcs[0]);
207 else if (cs->bcs[1].mode && (cs->bcs[1].channel == channel))
208 return (&cs->bcs[1]);
209 else
210 return (NULL);
211}
212
213/***************************************/
214/* clear the desired B-channel rx fifo */
215/***************************************/
216static void hfcpci_clear_fifo_rx(struct IsdnCardState *cs, int fifo)
217{ u_char fifo_state;
218 bzfifo_type *bzr;
219
220 if (fifo) {
221 bzr = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxbz_b2;
222 fifo_state = cs->hw.hfcpci.fifo_en & HFCPCI_FIFOEN_B2RX;
223 } else {
224 bzr = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxbz_b1;
225 fifo_state = cs->hw.hfcpci.fifo_en & HFCPCI_FIFOEN_B1RX;
226 }
227 if (fifo_state)
228 cs->hw.hfcpci.fifo_en ^= fifo_state;
229 Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en);
230 cs->hw.hfcpci.last_bfifo_cnt[fifo] = 0;
231 bzr->za[MAX_B_FRAMES].z1 = B_FIFO_SIZE + B_SUB_VAL - 1;
232 bzr->za[MAX_B_FRAMES].z2 = bzr->za[MAX_B_FRAMES].z1;
233 bzr->f1 = MAX_B_FRAMES;
234 bzr->f2 = bzr->f1; /* init F pointers to remain constant */
235 if (fifo_state)
236 cs->hw.hfcpci.fifo_en |= fifo_state;
237 Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en);
238}
239
240/***************************************/
241/* clear the desired B-channel tx fifo */
242/***************************************/
243static void hfcpci_clear_fifo_tx(struct IsdnCardState *cs, int fifo)
244{ u_char fifo_state;
245 bzfifo_type *bzt;
246
247 if (fifo) {
248 bzt = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.txbz_b2;
249 fifo_state = cs->hw.hfcpci.fifo_en & HFCPCI_FIFOEN_B2TX;
250 } else {
251 bzt = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.txbz_b1;
252 fifo_state = cs->hw.hfcpci.fifo_en & HFCPCI_FIFOEN_B1TX;
253 }
254 if (fifo_state)
255 cs->hw.hfcpci.fifo_en ^= fifo_state;
256 Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en);
257 bzt->za[MAX_B_FRAMES].z1 = B_FIFO_SIZE + B_SUB_VAL - 1;
258 bzt->za[MAX_B_FRAMES].z2 = bzt->za[MAX_B_FRAMES].z1;
259 bzt->f1 = MAX_B_FRAMES;
260 bzt->f2 = bzt->f1; /* init F pointers to remain constant */
261 if (fifo_state)
262 cs->hw.hfcpci.fifo_en |= fifo_state;
263 Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en);
264}
265
266/*********************************************/
267/* read a complete B-frame out of the buffer */
268/*********************************************/
269static struct sk_buff
270*
271hfcpci_empty_fifo(struct BCState *bcs, bzfifo_type * bz, u_char * bdata, int count)
272{
273 u_char *ptr, *ptr1, new_f2;
274 struct sk_buff *skb;
275 struct IsdnCardState *cs = bcs->cs;
276 int total, maxlen, new_z2;
277 z_type *zp;
278
279 if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
280 debugl1(cs, "hfcpci_empty_fifo");
281 zp = &bz->za[bz->f2]; /* point to Z-Regs */
282 new_z2 = zp->z2 + count; /* new position in fifo */
283 if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL))
284 new_z2 -= B_FIFO_SIZE; /* buffer wrap */
285 new_f2 = (bz->f2 + 1) & MAX_B_FRAMES;
286 if ((count > HSCX_BUFMAX + 3) || (count < 4) ||
287 (*(bdata + (zp->z1 - B_SUB_VAL)))) {
288 if (cs->debug & L1_DEB_WARN)
289 debugl1(cs, "hfcpci_empty_fifo: incoming packet invalid length %d or crc", count);
290#ifdef ERROR_STATISTIC
291 bcs->err_inv++;
292#endif
293 bz->za[new_f2].z2 = new_z2;
294 bz->f2 = new_f2; /* next buffer */
295 skb = NULL;
296 } else if (!(skb = dev_alloc_skb(count - 3)))
297 printk(KERN_WARNING "HFCPCI: receive out of memory\n");
298 else {
299 total = count;
300 count -= 3;
301 ptr = skb_put(skb, count);
302
303 if (zp->z2 + count <= B_FIFO_SIZE + B_SUB_VAL)
304 maxlen = count; /* complete transfer */
305 else
306 maxlen = B_FIFO_SIZE + B_SUB_VAL - zp->z2; /* maximum */
307
308 ptr1 = bdata + (zp->z2 - B_SUB_VAL); /* start of data */
309 memcpy(ptr, ptr1, maxlen); /* copy data */
310 count -= maxlen;
311
312 if (count) { /* rest remaining */
313 ptr += maxlen;
314 ptr1 = bdata; /* start of buffer */
315 memcpy(ptr, ptr1, count); /* rest */
316 }
317 bz->za[new_f2].z2 = new_z2;
318 bz->f2 = new_f2; /* next buffer */
319
320 }
321 return (skb);
322}
323
324/*******************************/
325/* D-channel receive procedure */
326/*******************************/
327static
328int
329receive_dmsg(struct IsdnCardState *cs)
330{
331 struct sk_buff *skb;
332 int maxlen;
333 int rcnt, total;
334 int count = 5;
335 u_char *ptr, *ptr1;
336 dfifo_type *df;
337 z_type *zp;
338
339 df = &((fifo_area *) (cs->hw.hfcpci.fifos))->d_chan.d_rx;
340 if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
341 debugl1(cs, "rec_dmsg blocked");
342 return (1);
343 }
344 while (((df->f1 & D_FREG_MASK) != (df->f2 & D_FREG_MASK)) && count--) {
345 zp = &df->za[df->f2 & D_FREG_MASK];
346 rcnt = zp->z1 - zp->z2;
347 if (rcnt < 0)
348 rcnt += D_FIFO_SIZE;
349 rcnt++;
350 if (cs->debug & L1_DEB_ISAC)
351 debugl1(cs, "hfcpci recd f1(%d) f2(%d) z1(%x) z2(%x) cnt(%d)",
352 df->f1, df->f2, zp->z1, zp->z2, rcnt);
353
354 if ((rcnt > MAX_DFRAME_LEN + 3) || (rcnt < 4) ||
355 (df->data[zp->z1])) {
356 if (cs->debug & L1_DEB_WARN)
357 debugl1(cs, "empty_fifo hfcpci paket inv. len %d or crc %d", rcnt, df->data[zp->z1]);
358#ifdef ERROR_STATISTIC
359 cs->err_rx++;
360#endif
361 df->f2 = ((df->f2 + 1) & MAX_D_FRAMES) | (MAX_D_FRAMES + 1); /* next buffer */
362 df->za[df->f2 & D_FREG_MASK].z2 = (zp->z2 + rcnt) & (D_FIFO_SIZE - 1);
363 } else if ((skb = dev_alloc_skb(rcnt - 3))) {
364 total = rcnt;
365 rcnt -= 3;
366 ptr = skb_put(skb, rcnt);
367
368 if (zp->z2 + rcnt <= D_FIFO_SIZE)
369 maxlen = rcnt; /* complete transfer */
370 else
371 maxlen = D_FIFO_SIZE - zp->z2; /* maximum */
372
373 ptr1 = df->data + zp->z2; /* start of data */
374 memcpy(ptr, ptr1, maxlen); /* copy data */
375 rcnt -= maxlen;
376
377 if (rcnt) { /* rest remaining */
378 ptr += maxlen;
379 ptr1 = df->data; /* start of buffer */
380 memcpy(ptr, ptr1, rcnt); /* rest */
381 }
382 df->f2 = ((df->f2 + 1) & MAX_D_FRAMES) | (MAX_D_FRAMES + 1); /* next buffer */
383 df->za[df->f2 & D_FREG_MASK].z2 = (zp->z2 + total) & (D_FIFO_SIZE - 1);
384
385 skb_queue_tail(&cs->rq, skb);
386 sched_event_D_pci(cs, D_RCVBUFREADY);
387 } else
388 printk(KERN_WARNING "HFC-PCI: D receive out of memory\n");
389 }
390 test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
391 return (1);
392}
393
394/*******************************************************************************/
395/* check for transparent receive data and read max one threshold size if avail */
396/*******************************************************************************/
397int
398hfcpci_empty_fifo_trans(struct BCState *bcs, bzfifo_type * bz, u_char * bdata)
399{
400 unsigned short *z1r, *z2r;
401 int new_z2, fcnt, maxlen;
402 struct sk_buff *skb;
403 u_char *ptr, *ptr1;
404
405 z1r = &bz->za[MAX_B_FRAMES].z1; /* pointer to z reg */
406 z2r = z1r + 1;
407
408 if (!(fcnt = *z1r - *z2r))
409 return (0); /* no data avail */
410
411 if (fcnt <= 0)
412 fcnt += B_FIFO_SIZE; /* bytes actually buffered */
413 if (fcnt > HFCPCI_BTRANS_THRESHOLD)
414 fcnt = HFCPCI_BTRANS_THRESHOLD; /* limit size */
415
416 new_z2 = *z2r + fcnt; /* new position in fifo */
417 if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL))
418 new_z2 -= B_FIFO_SIZE; /* buffer wrap */
419
420 if (!(skb = dev_alloc_skb(fcnt)))
421 printk(KERN_WARNING "HFCPCI: receive out of memory\n");
422 else {
423 ptr = skb_put(skb, fcnt);
424 if (*z2r + fcnt <= B_FIFO_SIZE + B_SUB_VAL)
425 maxlen = fcnt; /* complete transfer */
426 else
427 maxlen = B_FIFO_SIZE + B_SUB_VAL - *z2r; /* maximum */
428
429 ptr1 = bdata + (*z2r - B_SUB_VAL); /* start of data */
430 memcpy(ptr, ptr1, maxlen); /* copy data */
431 fcnt -= maxlen;
432
433 if (fcnt) { /* rest remaining */
434 ptr += maxlen;
435 ptr1 = bdata; /* start of buffer */
436 memcpy(ptr, ptr1, fcnt); /* rest */
437 }
438 skb_queue_tail(&bcs->rqueue, skb);
439 hfcpci_sched_event(bcs, B_RCVBUFREADY);
440 }
441
442 *z2r = new_z2; /* new position */
443 return (1);
444} /* hfcpci_empty_fifo_trans */
445
446/**********************************/
447/* B-channel main receive routine */
448/**********************************/
449void
450main_rec_hfcpci(struct BCState *bcs)
451{
452 struct IsdnCardState *cs = bcs->cs;
453 int rcnt, real_fifo;
454 int receive, count = 5;
455 struct sk_buff *skb;
456 bzfifo_type *bz;
457 u_char *bdata;
458 z_type *zp;
459
460
461 if ((bcs->channel) && (!cs->hw.hfcpci.bswapped)) {
462 bz = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxbz_b2;
463 bdata = ((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxdat_b2;
464 real_fifo = 1;
465 } else {
466 bz = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxbz_b1;
467 bdata = ((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxdat_b1;
468 real_fifo = 0;
469 }
470 Begin:
471 count--;
472 if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
473 debugl1(cs, "rec_data %d blocked", bcs->channel);
474 return;
475 }
476 if (bz->f1 != bz->f2) {
477 if (cs->debug & L1_DEB_HSCX)
478 debugl1(cs, "hfcpci rec %d f1(%d) f2(%d)",
479 bcs->channel, bz->f1, bz->f2);
480 zp = &bz->za[bz->f2];
481
482 rcnt = zp->z1 - zp->z2;
483 if (rcnt < 0)
484 rcnt += B_FIFO_SIZE;
485 rcnt++;
486 if (cs->debug & L1_DEB_HSCX)
487 debugl1(cs, "hfcpci rec %d z1(%x) z2(%x) cnt(%d)",
488 bcs->channel, zp->z1, zp->z2, rcnt);
489 if ((skb = hfcpci_empty_fifo(bcs, bz, bdata, rcnt))) {
490 skb_queue_tail(&bcs->rqueue, skb);
491 hfcpci_sched_event(bcs, B_RCVBUFREADY);
492 }
493 rcnt = bz->f1 - bz->f2;
494 if (rcnt < 0)
495 rcnt += MAX_B_FRAMES + 1;
496 if (cs->hw.hfcpci.last_bfifo_cnt[real_fifo] > rcnt + 1) {
497 rcnt = 0;
498 hfcpci_clear_fifo_rx(cs, real_fifo);
499 }
500 cs->hw.hfcpci.last_bfifo_cnt[real_fifo] = rcnt;
501 if (rcnt > 1)
502 receive = 1;
503 else
504 receive = 0;
505 } else if (bcs->mode == L1_MODE_TRANS)
506 receive = hfcpci_empty_fifo_trans(bcs, bz, bdata);
507 else
508 receive = 0;
509 test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
510 if (count && receive)
511 goto Begin;
512 return;
513}
514
515/**************************/
516/* D-channel send routine */
517/**************************/
518static void
519hfcpci_fill_dfifo(struct IsdnCardState *cs)
520{
521 int fcnt;
522 int count, new_z1, maxlen;
523 dfifo_type *df;
524 u_char *src, *dst, new_f1;
525
526 if (!cs->tx_skb)
527 return;
528 if (cs->tx_skb->len <= 0)
529 return;
530
531 df = &((fifo_area *) (cs->hw.hfcpci.fifos))->d_chan.d_tx;
532
533 if (cs->debug & L1_DEB_ISAC)
534 debugl1(cs, "hfcpci_fill_Dfifo f1(%d) f2(%d) z1(f1)(%x)",
535 df->f1, df->f2,
536 df->za[df->f1 & D_FREG_MASK].z1);
537 fcnt = df->f1 - df->f2; /* frame count actually buffered */
538 if (fcnt < 0)
539 fcnt += (MAX_D_FRAMES + 1); /* if wrap around */
540 if (fcnt > (MAX_D_FRAMES - 1)) {
541 if (cs->debug & L1_DEB_ISAC)
542 debugl1(cs, "hfcpci_fill_Dfifo more as 14 frames");
543#ifdef ERROR_STATISTIC
544 cs->err_tx++;
545#endif
546 return;
547 }
548 /* now determine free bytes in FIFO buffer */
549 count = df->za[df->f2 & D_FREG_MASK].z2 - df->za[df->f1 & D_FREG_MASK].z1 - 1;
550 if (count <= 0)
551 count += D_FIFO_SIZE; /* count now contains available bytes */
552
553 if (cs->debug & L1_DEB_ISAC)
554 debugl1(cs, "hfcpci_fill_Dfifo count(%ld/%d)",
555 cs->tx_skb->len, count);
556 if (count < cs->tx_skb->len) {
557 if (cs->debug & L1_DEB_ISAC)
558 debugl1(cs, "hfcpci_fill_Dfifo no fifo mem");
559 return;
560 }
561 count = cs->tx_skb->len; /* get frame len */
562 new_z1 = (df->za[df->f1 & D_FREG_MASK].z1 + count) & (D_FIFO_SIZE - 1);
563 new_f1 = ((df->f1 + 1) & D_FREG_MASK) | (D_FREG_MASK + 1);
564 src = cs->tx_skb->data; /* source pointer */
565 dst = df->data + df->za[df->f1 & D_FREG_MASK].z1;
566 maxlen = D_FIFO_SIZE - df->za[df->f1 & D_FREG_MASK].z1; /* end fifo */
567 if (maxlen > count)
568 maxlen = count; /* limit size */
569 memcpy(dst, src, maxlen); /* first copy */
570
571 count -= maxlen; /* remaining bytes */
572 if (count) {
573 dst = df->data; /* start of buffer */
574 src += maxlen; /* new position */
575 memcpy(dst, src, count);
576 }
577 df->za[new_f1 & D_FREG_MASK].z1 = new_z1; /* for next buffer */
578 df->za[df->f1 & D_FREG_MASK].z1 = new_z1; /* new pos actual buffer */
579 df->f1 = new_f1; /* next frame */
580
581 dev_kfree_skb_any(cs->tx_skb);
582 cs->tx_skb = NULL;
583 return;
584}
585
586/**************************/
587/* B-channel send routine */
588/**************************/
589static void
590hfcpci_fill_fifo(struct BCState *bcs)
591{
592 struct IsdnCardState *cs = bcs->cs;
593 int maxlen, fcnt;
594 int count, new_z1;
595 bzfifo_type *bz;
596 u_char *bdata;
597 u_char new_f1, *src, *dst;
598 unsigned short *z1t, *z2t;
599
600 if (!bcs->tx_skb)
601 return;
602 if (bcs->tx_skb->len <= 0)
603 return;
604
605 if ((bcs->channel) && (!cs->hw.hfcpci.bswapped)) {
606 bz = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.txbz_b2;
607 bdata = ((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.txdat_b2;
608 } else {
609 bz = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.txbz_b1;
610 bdata = ((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.txdat_b1;
611 }
612
613 if (bcs->mode == L1_MODE_TRANS) {
614 z1t = &bz->za[MAX_B_FRAMES].z1;
615 z2t = z1t + 1;
616 if (cs->debug & L1_DEB_HSCX)
617 debugl1(cs, "hfcpci_fill_fifo_trans %d z1(%x) z2(%x)",
618 bcs->channel, *z1t, *z2t);
619 fcnt = *z2t - *z1t;
620 if (fcnt <= 0)
621 fcnt += B_FIFO_SIZE; /* fcnt contains available bytes in fifo */
622 fcnt = B_FIFO_SIZE - fcnt; /* remaining bytes to send */
623
624 while ((fcnt < 2 * HFCPCI_BTRANS_THRESHOLD) && (bcs->tx_skb)) {
625 if (bcs->tx_skb->len < B_FIFO_SIZE - fcnt) {
626 /* data is suitable for fifo */
627 count = bcs->tx_skb->len;
628
629 new_z1 = *z1t + count; /* new buffer Position */
630 if (new_z1 >= (B_FIFO_SIZE + B_SUB_VAL))
631 new_z1 -= B_FIFO_SIZE; /* buffer wrap */
632 src = bcs->tx_skb->data; /* source pointer */
633 dst = bdata + (*z1t - B_SUB_VAL);
634 maxlen = (B_FIFO_SIZE + B_SUB_VAL) - *z1t; /* end of fifo */
635 if (maxlen > count)
636 maxlen = count; /* limit size */
637 memcpy(dst, src, maxlen); /* first copy */
638
639 count -= maxlen; /* remaining bytes */
640 if (count) {
641 dst = bdata; /* start of buffer */
642 src += maxlen; /* new position */
643 memcpy(dst, src, count);
644 }
645 bcs->tx_cnt -= bcs->tx_skb->len;
646 fcnt += bcs->tx_skb->len;
647 *z1t = new_z1; /* now send data */
648 } else if (cs->debug & L1_DEB_HSCX)
649 debugl1(cs, "hfcpci_fill_fifo_trans %d frame length %d discarded",
650 bcs->channel, bcs->tx_skb->len);
651
652 if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) &&
653 (PACKET_NOACK != bcs->tx_skb->pkt_type)) {
654 u_long flags;
655 spin_lock_irqsave(&bcs->aclock, flags);
656 bcs->ackcnt += bcs->tx_skb->len;
657 spin_unlock_irqrestore(&bcs->aclock, flags);
658 schedule_event(bcs, B_ACKPENDING);
659 }
660
661 dev_kfree_skb_any(bcs->tx_skb);
662 bcs->tx_skb = skb_dequeue(&bcs->squeue); /* fetch next data */
663 }
664 test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
665 return;
666 }
667 if (cs->debug & L1_DEB_HSCX)
668 debugl1(cs, "hfcpci_fill_fifo_hdlc %d f1(%d) f2(%d) z1(f1)(%x)",
669 bcs->channel, bz->f1, bz->f2,
670 bz->za[bz->f1].z1);
671
672 fcnt = bz->f1 - bz->f2; /* frame count actually buffered */
673 if (fcnt < 0)
674 fcnt += (MAX_B_FRAMES + 1); /* if wrap around */
675 if (fcnt > (MAX_B_FRAMES - 1)) {
676 if (cs->debug & L1_DEB_HSCX)
677 debugl1(cs, "hfcpci_fill_Bfifo more as 14 frames");
678 return;
679 }
680 /* now determine free bytes in FIFO buffer */
681 count = bz->za[bz->f2].z2 - bz->za[bz->f1].z1 - 1;
682 if (count <= 0)
683 count += B_FIFO_SIZE; /* count now contains available bytes */
684
685 if (cs->debug & L1_DEB_HSCX)
686 debugl1(cs, "hfcpci_fill_fifo %d count(%ld/%d),%lx",
687 bcs->channel, bcs->tx_skb->len,
688 count, current->state);
689
690 if (count < bcs->tx_skb->len) {
691 if (cs->debug & L1_DEB_HSCX)
692 debugl1(cs, "hfcpci_fill_fifo no fifo mem");
693 return;
694 }
695 count = bcs->tx_skb->len; /* get frame len */
696 new_z1 = bz->za[bz->f1].z1 + count; /* new buffer Position */
697 if (new_z1 >= (B_FIFO_SIZE + B_SUB_VAL))
698 new_z1 -= B_FIFO_SIZE; /* buffer wrap */
699
700 new_f1 = ((bz->f1 + 1) & MAX_B_FRAMES);
701 src = bcs->tx_skb->data; /* source pointer */
702 dst = bdata + (bz->za[bz->f1].z1 - B_SUB_VAL);
703 maxlen = (B_FIFO_SIZE + B_SUB_VAL) - bz->za[bz->f1].z1; /* end fifo */
704 if (maxlen > count)
705 maxlen = count; /* limit size */
706 memcpy(dst, src, maxlen); /* first copy */
707
708 count -= maxlen; /* remaining bytes */
709 if (count) {
710 dst = bdata; /* start of buffer */
711 src += maxlen; /* new position */
712 memcpy(dst, src, count);
713 }
714 bcs->tx_cnt -= bcs->tx_skb->len;
715 if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) &&
716 (PACKET_NOACK != bcs->tx_skb->pkt_type)) {
717 u_long flags;
718 spin_lock_irqsave(&bcs->aclock, flags);
719 bcs->ackcnt += bcs->tx_skb->len;
720 spin_unlock_irqrestore(&bcs->aclock, flags);
721 schedule_event(bcs, B_ACKPENDING);
722 }
723
724 bz->za[new_f1].z1 = new_z1; /* for next buffer */
725 bz->f1 = new_f1; /* next frame */
726
727 dev_kfree_skb_any(bcs->tx_skb);
728 bcs->tx_skb = NULL;
729 test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
730 return;
731}
732
733/**********************************************/
734/* D-channel l1 state call for leased NT-mode */
735/**********************************************/
736static void
737dch_nt_l2l1(struct PStack *st, int pr, void *arg)
738{
739 struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
740
741 switch (pr) {
742 case (PH_DATA | REQUEST):
743 case (PH_PULL | REQUEST):
744 case (PH_PULL | INDICATION):
745 st->l1.l1hw(st, pr, arg);
746 break;
747 case (PH_ACTIVATE | REQUEST):
748 st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL);
749 break;
750 case (PH_TESTLOOP | REQUEST):
751 if (1 & (long) arg)
752 debugl1(cs, "PH_TEST_LOOP B1");
753 if (2 & (long) arg)
754 debugl1(cs, "PH_TEST_LOOP B2");
755 if (!(3 & (long) arg))
756 debugl1(cs, "PH_TEST_LOOP DISABLED");
757 st->l1.l1hw(st, HW_TESTLOOP | REQUEST, arg);
758 break;
759 default:
760 if (cs->debug)
761 debugl1(cs, "dch_nt_l2l1 msg %04X unhandled", pr);
762 break;
763 }
764}
765
766
767
768/***********************/
769/* set/reset echo mode */
770/***********************/
771static int
772hfcpci_auxcmd(struct IsdnCardState *cs, isdn_ctrl * ic)
773{
774 u_long flags;
775 int i = *(unsigned int *) ic->parm.num;
776
777 if ((ic->arg == 98) &&
778 (!(cs->hw.hfcpci.int_m1 & (HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC + HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC)))) {
779 spin_lock_irqsave(&cs->lock, flags);
780 Write_hfc(cs, HFCPCI_CLKDEL, CLKDEL_NT); /* ST-Bit delay for NT-Mode */
781 Write_hfc(cs, HFCPCI_STATES, HFCPCI_LOAD_STATE | 0); /* HFC ST G0 */
782 udelay(10);
783 cs->hw.hfcpci.sctrl |= SCTRL_MODE_NT;
784 Write_hfc(cs, HFCPCI_SCTRL, cs->hw.hfcpci.sctrl); /* set NT-mode */
785 udelay(10);
786 Write_hfc(cs, HFCPCI_STATES, HFCPCI_LOAD_STATE | 1); /* HFC ST G1 */
787 udelay(10);
788 Write_hfc(cs, HFCPCI_STATES, 1 | HFCPCI_ACTIVATE | HFCPCI_DO_ACTION);
789 cs->dc.hfcpci.ph_state = 1;
790 cs->hw.hfcpci.nt_mode = 1;
791 cs->hw.hfcpci.nt_timer = 0;
792 cs->stlist->l2.l2l1 = dch_nt_l2l1;
793 spin_unlock_irqrestore(&cs->lock, flags);
794 debugl1(cs, "NT mode activated");
795 return (0);
796 }
797 if ((cs->chanlimit > 1) || (cs->hw.hfcpci.bswapped) ||
798 (cs->hw.hfcpci.nt_mode) || (ic->arg != 12))
799 return (-EINVAL);
800
801 spin_lock_irqsave(&cs->lock, flags);
802 if (i) {
803 cs->logecho = 1;
804 cs->hw.hfcpci.trm |= 0x20; /* enable echo chan */
805 cs->hw.hfcpci.int_m1 |= HFCPCI_INTS_B2REC;
806 cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B2RX;
807 } else {
808 cs->logecho = 0;
809 cs->hw.hfcpci.trm &= ~0x20; /* disable echo chan */
810 cs->hw.hfcpci.int_m1 &= ~HFCPCI_INTS_B2REC;
811 cs->hw.hfcpci.fifo_en &= ~HFCPCI_FIFOEN_B2RX;
812 }
813 cs->hw.hfcpci.sctrl_r &= ~SCTRL_B2_ENA;
814 cs->hw.hfcpci.sctrl &= ~SCTRL_B2_ENA;
815 cs->hw.hfcpci.conn |= 0x10; /* B2-IOM -> B2-ST */
816 cs->hw.hfcpci.ctmt &= ~2;
817 Write_hfc(cs, HFCPCI_CTMT, cs->hw.hfcpci.ctmt);
818 Write_hfc(cs, HFCPCI_SCTRL_R, cs->hw.hfcpci.sctrl_r);
819 Write_hfc(cs, HFCPCI_SCTRL, cs->hw.hfcpci.sctrl);
820 Write_hfc(cs, HFCPCI_CONNECT, cs->hw.hfcpci.conn);
821 Write_hfc(cs, HFCPCI_TRM, cs->hw.hfcpci.trm);
822 Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en);
823 Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1);
824 spin_unlock_irqrestore(&cs->lock, flags);
825 return (0);
826} /* hfcpci_auxcmd */
827
828/*****************************/
829/* E-channel receive routine */
830/*****************************/
831static void
832receive_emsg(struct IsdnCardState *cs)
833{
834 int rcnt;
835 int receive, count = 5;
836 bzfifo_type *bz;
837 u_char *bdata;
838 z_type *zp;
839 u_char *ptr, *ptr1, new_f2;
840 int total, maxlen, new_z2;
841 u_char e_buffer[256];
842
843 bz = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxbz_b2;
844 bdata = ((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxdat_b2;
845 Begin:
846 count--;
847 if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
848 debugl1(cs, "echo_rec_data blocked");
849 return;
850 }
851 if (bz->f1 != bz->f2) {
852 if (cs->debug & L1_DEB_ISAC)
853 debugl1(cs, "hfcpci e_rec f1(%d) f2(%d)",
854 bz->f1, bz->f2);
855 zp = &bz->za[bz->f2];
856
857 rcnt = zp->z1 - zp->z2;
858 if (rcnt < 0)
859 rcnt += B_FIFO_SIZE;
860 rcnt++;
861 if (cs->debug & L1_DEB_ISAC)
862 debugl1(cs, "hfcpci e_rec z1(%x) z2(%x) cnt(%d)",
863 zp->z1, zp->z2, rcnt);
864 new_z2 = zp->z2 + rcnt; /* new position in fifo */
865 if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL))
866 new_z2 -= B_FIFO_SIZE; /* buffer wrap */
867 new_f2 = (bz->f2 + 1) & MAX_B_FRAMES;
868 if ((rcnt > 256 + 3) || (count < 4) ||
869 (*(bdata + (zp->z1 - B_SUB_VAL)))) {
870 if (cs->debug & L1_DEB_WARN)
871 debugl1(cs, "hfcpci_empty_echan: incoming packet invalid length %d or crc", rcnt);
872 bz->za[new_f2].z2 = new_z2;
873 bz->f2 = new_f2; /* next buffer */
874 } else {
875 total = rcnt;
876 rcnt -= 3;
877 ptr = e_buffer;
878
879 if (zp->z2 <= B_FIFO_SIZE + B_SUB_VAL)
880 maxlen = rcnt; /* complete transfer */
881 else
882 maxlen = B_FIFO_SIZE + B_SUB_VAL - zp->z2; /* maximum */
883
884 ptr1 = bdata + (zp->z2 - B_SUB_VAL); /* start of data */
885 memcpy(ptr, ptr1, maxlen); /* copy data */
886 rcnt -= maxlen;
887
888 if (rcnt) { /* rest remaining */
889 ptr += maxlen;
890 ptr1 = bdata; /* start of buffer */
891 memcpy(ptr, ptr1, rcnt); /* rest */
892 }
893 bz->za[new_f2].z2 = new_z2;
894 bz->f2 = new_f2; /* next buffer */
895 if (cs->debug & DEB_DLOG_HEX) {
896 ptr = cs->dlog;
897 if ((total - 3) < MAX_DLOG_SPACE / 3 - 10) {
898 *ptr++ = 'E';
899 *ptr++ = 'C';
900 *ptr++ = 'H';
901 *ptr++ = 'O';
902 *ptr++ = ':';
903 ptr += QuickHex(ptr, e_buffer, total - 3);
904 ptr--;
905 *ptr++ = '\n';
906 *ptr = 0;
907 HiSax_putstatus(cs, NULL, cs->dlog);
908 } else
909 HiSax_putstatus(cs, "LogEcho: ", "warning Frame too big (%d)", total - 3);
910 }
911 }
912
913 rcnt = bz->f1 - bz->f2;
914 if (rcnt < 0)
915 rcnt += MAX_B_FRAMES + 1;
916 if (rcnt > 1)
917 receive = 1;
918 else
919 receive = 0;
920 } else
921 receive = 0;
922 test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
923 if (count && receive)
924 goto Begin;
925 return;
926} /* receive_emsg */
927
928/*********************/
929/* Interrupt handler */
930/*********************/
931static irqreturn_t
932hfcpci_interrupt(int intno, void *dev_id, struct pt_regs *regs)
933{
934 u_long flags;
935 struct IsdnCardState *cs = dev_id;
936 u_char exval;
937 struct BCState *bcs;
938 int count = 15;
939 u_char val, stat;
940
941 if (!(cs->hw.hfcpci.int_m2 & 0x08)) {
942 debugl1(cs, "HFC-PCI: int_m2 %x not initialised", cs->hw.hfcpci.int_m2);
943 return IRQ_NONE; /* not initialised */
944 }
945 spin_lock_irqsave(&cs->lock, flags);
946 if (HFCPCI_ANYINT & (stat = Read_hfc(cs, HFCPCI_STATUS))) {
947 val = Read_hfc(cs, HFCPCI_INT_S1);
948 if (cs->debug & L1_DEB_ISAC)
949 debugl1(cs, "HFC-PCI: stat(%02x) s1(%02x)", stat, val);
950 } else {
951 spin_unlock_irqrestore(&cs->lock, flags);
952 return IRQ_NONE;
953 }
954 if (cs->debug & L1_DEB_ISAC)
955 debugl1(cs, "HFC-PCI irq %x %s", val,
956 test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags) ?
957 "locked" : "unlocked");
958 val &= cs->hw.hfcpci.int_m1;
959 if (val & 0x40) { /* state machine irq */
960 exval = Read_hfc(cs, HFCPCI_STATES) & 0xf;
961 if (cs->debug & L1_DEB_ISAC)
962 debugl1(cs, "ph_state chg %d->%d", cs->dc.hfcpci.ph_state,
963 exval);
964 cs->dc.hfcpci.ph_state = exval;
965 sched_event_D_pci(cs, D_L1STATECHANGE);
966 val &= ~0x40;
967 }
968 if (val & 0x80) { /* timer irq */
969 if (cs->hw.hfcpci.nt_mode) {
970 if ((--cs->hw.hfcpci.nt_timer) < 0)
971 sched_event_D_pci(cs, D_L1STATECHANGE);
972 }
973 val &= ~0x80;
974 Write_hfc(cs, HFCPCI_CTMT, cs->hw.hfcpci.ctmt | HFCPCI_CLTIMER);
975 }
976 while (val) {
977 if (test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
978 cs->hw.hfcpci.int_s1 |= val;
979 spin_unlock_irqrestore(&cs->lock, flags);
980 return IRQ_HANDLED;
981 }
982 if (cs->hw.hfcpci.int_s1 & 0x18) {
983 exval = val;
984 val = cs->hw.hfcpci.int_s1;
985 cs->hw.hfcpci.int_s1 = exval;
986 }
987 if (val & 0x08) {
988 if (!(bcs = Sel_BCS(cs, cs->hw.hfcpci.bswapped ? 1 : 0))) {
989 if (cs->debug)
990 debugl1(cs, "hfcpci spurious 0x08 IRQ");
991 } else
992 main_rec_hfcpci(bcs);
993 }
994 if (val & 0x10) {
995 if (cs->logecho)
996 receive_emsg(cs);
997 else if (!(bcs = Sel_BCS(cs, 1))) {
998 if (cs->debug)
999 debugl1(cs, "hfcpci spurious 0x10 IRQ");
1000 } else
1001 main_rec_hfcpci(bcs);
1002 }
1003 if (val & 0x01) {
1004 if (!(bcs = Sel_BCS(cs, cs->hw.hfcpci.bswapped ? 1 : 0))) {
1005 if (cs->debug)
1006 debugl1(cs, "hfcpci spurious 0x01 IRQ");
1007 } else {
1008 if (bcs->tx_skb) {
1009 if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
1010 hfcpci_fill_fifo(bcs);
1011 test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
1012 } else
1013 debugl1(cs, "fill_data %d blocked", bcs->channel);
1014 } else {
1015 if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
1016 if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
1017 hfcpci_fill_fifo(bcs);
1018 test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
1019 } else
1020 debugl1(cs, "fill_data %d blocked", bcs->channel);
1021 } else {
1022 hfcpci_sched_event(bcs, B_XMTBUFREADY);
1023 }
1024 }
1025 }
1026 }
1027 if (val & 0x02) {
1028 if (!(bcs = Sel_BCS(cs, 1))) {
1029 if (cs->debug)
1030 debugl1(cs, "hfcpci spurious 0x02 IRQ");
1031 } else {
1032 if (bcs->tx_skb) {
1033 if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
1034 hfcpci_fill_fifo(bcs);
1035 test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
1036 } else
1037 debugl1(cs, "fill_data %d blocked", bcs->channel);
1038 } else {
1039 if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
1040 if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
1041 hfcpci_fill_fifo(bcs);
1042 test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
1043 } else
1044 debugl1(cs, "fill_data %d blocked", bcs->channel);
1045 } else {
1046 hfcpci_sched_event(bcs, B_XMTBUFREADY);
1047 }
1048 }
1049 }
1050 }
1051 if (val & 0x20) { /* receive dframe */
1052 receive_dmsg(cs);
1053 }
1054 if (val & 0x04) { /* dframe transmitted */
1055 if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
1056 del_timer(&cs->dbusytimer);
1057 if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
1058 sched_event_D_pci(cs, D_CLEARBUSY);
1059 if (cs->tx_skb) {
1060 if (cs->tx_skb->len) {
1061 if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
1062 hfcpci_fill_dfifo(cs);
1063 test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
1064 } else {
1065 debugl1(cs, "hfcpci_fill_dfifo irq blocked");
1066 }
1067 goto afterXPR;
1068 } else {
1069 dev_kfree_skb_irq(cs->tx_skb);
1070 cs->tx_cnt = 0;
1071 cs->tx_skb = NULL;
1072 }
1073 }
1074 if ((cs->tx_skb = skb_dequeue(&cs->sq))) {
1075 cs->tx_cnt = 0;
1076 if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
1077 hfcpci_fill_dfifo(cs);
1078 test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
1079 } else {
1080 debugl1(cs, "hfcpci_fill_dfifo irq blocked");
1081 }
1082 } else
1083 sched_event_D_pci(cs, D_XMTBUFREADY);
1084 }
1085 afterXPR:
1086 if (cs->hw.hfcpci.int_s1 && count--) {
1087 val = cs->hw.hfcpci.int_s1;
1088 cs->hw.hfcpci.int_s1 = 0;
1089 if (cs->debug & L1_DEB_ISAC)
1090 debugl1(cs, "HFC-PCI irq %x loop %d", val, 15 - count);
1091 } else
1092 val = 0;
1093 }
1094 spin_unlock_irqrestore(&cs->lock, flags);
1095 return IRQ_HANDLED;
1096}
1097
1098/********************************************************************/
1099/* timer callback for D-chan busy resolution. Currently no function */
1100/********************************************************************/
1101static void
1102hfcpci_dbusy_timer(struct IsdnCardState *cs)
1103{
1104}
1105
1106/*************************************/
1107/* Layer 1 D-channel hardware access */
1108/*************************************/
1109static void
1110HFCPCI_l1hw(struct PStack *st, int pr, void *arg)
1111{
1112 u_long flags;
1113 struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
1114 struct sk_buff *skb = arg;
1115
1116 switch (pr) {
1117 case (PH_DATA | REQUEST):
1118 if (cs->debug & DEB_DLOG_HEX)
1119 LogFrame(cs, skb->data, skb->len);
1120 if (cs->debug & DEB_DLOG_VERBOSE)
1121 dlogframe(cs, skb, 0);
1122 spin_lock_irqsave(&cs->lock, flags);
1123 if (cs->tx_skb) {
1124 skb_queue_tail(&cs->sq, skb);
1125#ifdef L2FRAME_DEBUG /* psa */
1126 if (cs->debug & L1_DEB_LAPD)
1127 Logl2Frame(cs, skb, "PH_DATA Queued", 0);
1128#endif
1129 } else {
1130 cs->tx_skb = skb;
1131 cs->tx_cnt = 0;
1132#ifdef L2FRAME_DEBUG /* psa */
1133 if (cs->debug & L1_DEB_LAPD)
1134 Logl2Frame(cs, skb, "PH_DATA", 0);
1135#endif
1136 if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
1137 hfcpci_fill_dfifo(cs);
1138 test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
1139 } else
1140 debugl1(cs, "hfcpci_fill_dfifo blocked");
1141
1142 }
1143 spin_unlock_irqrestore(&cs->lock, flags);
1144 break;
1145 case (PH_PULL | INDICATION):
1146 spin_lock_irqsave(&cs->lock, flags);
1147 if (cs->tx_skb) {
1148 if (cs->debug & L1_DEB_WARN)
1149 debugl1(cs, " l2l1 tx_skb exist this shouldn't happen");
1150 skb_queue_tail(&cs->sq, skb);
1151 spin_unlock_irqrestore(&cs->lock, flags);
1152 break;
1153 }
1154 if (cs->debug & DEB_DLOG_HEX)
1155 LogFrame(cs, skb->data, skb->len);
1156 if (cs->debug & DEB_DLOG_VERBOSE)
1157 dlogframe(cs, skb, 0);
1158 cs->tx_skb = skb;
1159 cs->tx_cnt = 0;
1160#ifdef L2FRAME_DEBUG /* psa */
1161 if (cs->debug & L1_DEB_LAPD)
1162 Logl2Frame(cs, skb, "PH_DATA_PULLED", 0);
1163#endif
1164 if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
1165 hfcpci_fill_dfifo(cs);
1166 test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
1167 } else
1168 debugl1(cs, "hfcpci_fill_dfifo blocked");
1169 spin_unlock_irqrestore(&cs->lock, flags);
1170 break;
1171 case (PH_PULL | REQUEST):
1172#ifdef L2FRAME_DEBUG /* psa */
1173 if (cs->debug & L1_DEB_LAPD)
1174 debugl1(cs, "-> PH_REQUEST_PULL");
1175#endif
1176 if (!cs->tx_skb) {
1177 test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
1178 st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
1179 } else
1180 test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
1181 break;
1182 case (HW_RESET | REQUEST):
1183 spin_lock_irqsave(&cs->lock, flags);
1184 Write_hfc(cs, HFCPCI_STATES, HFCPCI_LOAD_STATE | 3); /* HFC ST 3 */
1185 udelay(6);
1186 Write_hfc(cs, HFCPCI_STATES, 3); /* HFC ST 2 */
1187 cs->hw.hfcpci.mst_m |= HFCPCI_MASTER;
1188 Write_hfc(cs, HFCPCI_MST_MODE, cs->hw.hfcpci.mst_m);
1189 Write_hfc(cs, HFCPCI_STATES, HFCPCI_ACTIVATE | HFCPCI_DO_ACTION);
1190 spin_unlock_irqrestore(&cs->lock, flags);
1191 l1_msg(cs, HW_POWERUP | CONFIRM, NULL);
1192 break;
1193 case (HW_ENABLE | REQUEST):
1194 spin_lock_irqsave(&cs->lock, flags);
1195 Write_hfc(cs, HFCPCI_STATES, HFCPCI_DO_ACTION);
1196 spin_unlock_irqrestore(&cs->lock, flags);
1197 break;
1198 case (HW_DEACTIVATE | REQUEST):
1199 spin_lock_irqsave(&cs->lock, flags);
1200 cs->hw.hfcpci.mst_m &= ~HFCPCI_MASTER;
1201 Write_hfc(cs, HFCPCI_MST_MODE, cs->hw.hfcpci.mst_m);
1202 spin_unlock_irqrestore(&cs->lock, flags);
1203 break;
1204 case (HW_INFO3 | REQUEST):
1205 spin_lock_irqsave(&cs->lock, flags);
1206 cs->hw.hfcpci.mst_m |= HFCPCI_MASTER;
1207 Write_hfc(cs, HFCPCI_MST_MODE, cs->hw.hfcpci.mst_m);
1208 spin_unlock_irqrestore(&cs->lock, flags);
1209 break;
1210 case (HW_TESTLOOP | REQUEST):
1211 spin_lock_irqsave(&cs->lock, flags);
1212 switch ((int) arg) {
1213 case (1):
1214 Write_hfc(cs, HFCPCI_B1_SSL, 0x80); /* tx slot */
1215 Write_hfc(cs, HFCPCI_B1_RSL, 0x80); /* rx slot */
1216 cs->hw.hfcpci.conn = (cs->hw.hfcpci.conn & ~7) | 1;
1217 Write_hfc(cs, HFCPCI_CONNECT, cs->hw.hfcpci.conn);
1218 break;
1219
1220 case (2):
1221 Write_hfc(cs, HFCPCI_B2_SSL, 0x81); /* tx slot */
1222 Write_hfc(cs, HFCPCI_B2_RSL, 0x81); /* rx slot */
1223 cs->hw.hfcpci.conn = (cs->hw.hfcpci.conn & ~0x38) | 0x08;
1224 Write_hfc(cs, HFCPCI_CONNECT, cs->hw.hfcpci.conn);
1225 break;
1226
1227 default:
1228 spin_unlock_irqrestore(&cs->lock, flags);
1229 if (cs->debug & L1_DEB_WARN)
1230 debugl1(cs, "hfcpci_l1hw loop invalid %4x", (int) arg);
1231 return;
1232 }
1233 cs->hw.hfcpci.trm |= 0x80; /* enable IOM-loop */
1234 Write_hfc(cs, HFCPCI_TRM, cs->hw.hfcpci.trm);
1235 spin_unlock_irqrestore(&cs->lock, flags);
1236 break;
1237 default:
1238 if (cs->debug & L1_DEB_WARN)
1239 debugl1(cs, "hfcpci_l1hw unknown pr %4x", pr);
1240 break;
1241 }
1242}
1243
1244/***********************************************/
1245/* called during init setting l1 stack pointer */
1246/***********************************************/
1247void
1248setstack_hfcpci(struct PStack *st, struct IsdnCardState *cs)
1249{
1250 st->l1.l1hw = HFCPCI_l1hw;
1251}
1252
1253/**************************************/
1254/* send B-channel data if not blocked */
1255/**************************************/
1256static void
1257hfcpci_send_data(struct BCState *bcs)
1258{
1259 struct IsdnCardState *cs = bcs->cs;
1260
1261 if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
1262 hfcpci_fill_fifo(bcs);
1263 test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
1264 } else
1265 debugl1(cs, "send_data %d blocked", bcs->channel);
1266}
1267
1268/***************************************************************/
1269/* activate/deactivate hardware for selected channels and mode */
1270/***************************************************************/
1271void
1272mode_hfcpci(struct BCState *bcs, int mode, int bc)
1273{
1274 struct IsdnCardState *cs = bcs->cs;
1275 int fifo2;
1276
1277 if (cs->debug & L1_DEB_HSCX)
1278 debugl1(cs, "HFCPCI bchannel mode %d bchan %d/%d",
1279 mode, bc, bcs->channel);
1280 bcs->mode = mode;
1281 bcs->channel = bc;
1282 fifo2 = bc;
1283 if (cs->chanlimit > 1) {
1284 cs->hw.hfcpci.bswapped = 0; /* B1 and B2 normal mode */
1285 cs->hw.hfcpci.sctrl_e &= ~0x80;
1286 } else {
1287 if (bc) {
1288 if (mode != L1_MODE_NULL) {
1289 cs->hw.hfcpci.bswapped = 1; /* B1 and B2 exchanged */
1290 cs->hw.hfcpci.sctrl_e |= 0x80;
1291 } else {
1292 cs->hw.hfcpci.bswapped = 0; /* B1 and B2 normal mode */
1293 cs->hw.hfcpci.sctrl_e &= ~0x80;
1294 }
1295 fifo2 = 0;
1296 } else {
1297 cs->hw.hfcpci.bswapped = 0; /* B1 and B2 normal mode */
1298 cs->hw.hfcpci.sctrl_e &= ~0x80;
1299 }
1300 }
1301 switch (mode) {
1302 case (L1_MODE_NULL):
1303 if (bc) {
1304 cs->hw.hfcpci.sctrl &= ~SCTRL_B2_ENA;
1305 cs->hw.hfcpci.sctrl_r &= ~SCTRL_B2_ENA;
1306 } else {
1307 cs->hw.hfcpci.sctrl &= ~SCTRL_B1_ENA;
1308 cs->hw.hfcpci.sctrl_r &= ~SCTRL_B1_ENA;
1309 }
1310 if (fifo2) {
1311 cs->hw.hfcpci.fifo_en &= ~HFCPCI_FIFOEN_B2;
1312 cs->hw.hfcpci.int_m1 &= ~(HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC);
1313 } else {
1314 cs->hw.hfcpci.fifo_en &= ~HFCPCI_FIFOEN_B1;
1315 cs->hw.hfcpci.int_m1 &= ~(HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC);
1316 }
1317 break;
1318 case (L1_MODE_TRANS):
1319 hfcpci_clear_fifo_rx(cs, fifo2);
1320 hfcpci_clear_fifo_tx(cs, fifo2);
1321 if (bc) {
1322 cs->hw.hfcpci.sctrl |= SCTRL_B2_ENA;
1323 cs->hw.hfcpci.sctrl_r |= SCTRL_B2_ENA;
1324 } else {
1325 cs->hw.hfcpci.sctrl |= SCTRL_B1_ENA;
1326 cs->hw.hfcpci.sctrl_r |= SCTRL_B1_ENA;
1327 }
1328 if (fifo2) {
1329 cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B2;
1330 cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC);
1331 cs->hw.hfcpci.ctmt |= 2;
1332 cs->hw.hfcpci.conn &= ~0x18;
1333 } else {
1334 cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B1;
1335 cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC);
1336 cs->hw.hfcpci.ctmt |= 1;
1337 cs->hw.hfcpci.conn &= ~0x03;
1338 }
1339 break;
1340 case (L1_MODE_HDLC):
1341 hfcpci_clear_fifo_rx(cs, fifo2);
1342 hfcpci_clear_fifo_tx(cs, fifo2);
1343 if (bc) {
1344 cs->hw.hfcpci.sctrl |= SCTRL_B2_ENA;
1345 cs->hw.hfcpci.sctrl_r |= SCTRL_B2_ENA;
1346 } else {
1347 cs->hw.hfcpci.sctrl |= SCTRL_B1_ENA;
1348 cs->hw.hfcpci.sctrl_r |= SCTRL_B1_ENA;
1349 }
1350 if (fifo2) {
1351 cs->hw.hfcpci.last_bfifo_cnt[1] = 0;
1352 cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B2;
1353 cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC);
1354 cs->hw.hfcpci.ctmt &= ~2;
1355 cs->hw.hfcpci.conn &= ~0x18;
1356 } else {
1357 cs->hw.hfcpci.last_bfifo_cnt[0] = 0;
1358 cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B1;
1359 cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC);
1360 cs->hw.hfcpci.ctmt &= ~1;
1361 cs->hw.hfcpci.conn &= ~0x03;
1362 }
1363 break;
1364 case (L1_MODE_EXTRN):
1365 if (bc) {
1366 cs->hw.hfcpci.conn |= 0x10;
1367 cs->hw.hfcpci.sctrl |= SCTRL_B2_ENA;
1368 cs->hw.hfcpci.sctrl_r |= SCTRL_B2_ENA;
1369 cs->hw.hfcpci.fifo_en &= ~HFCPCI_FIFOEN_B2;
1370 cs->hw.hfcpci.int_m1 &= ~(HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC);
1371 } else {
1372 cs->hw.hfcpci.conn |= 0x02;
1373 cs->hw.hfcpci.sctrl |= SCTRL_B1_ENA;
1374 cs->hw.hfcpci.sctrl_r |= SCTRL_B1_ENA;
1375 cs->hw.hfcpci.fifo_en &= ~HFCPCI_FIFOEN_B1;
1376 cs->hw.hfcpci.int_m1 &= ~(HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC);
1377 }
1378 break;
1379 }
1380 Write_hfc(cs, HFCPCI_SCTRL_E, cs->hw.hfcpci.sctrl_e);
1381 Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1);
1382 Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en);
1383 Write_hfc(cs, HFCPCI_SCTRL, cs->hw.hfcpci.sctrl);
1384 Write_hfc(cs, HFCPCI_SCTRL_R, cs->hw.hfcpci.sctrl_r);
1385 Write_hfc(cs, HFCPCI_CTMT, cs->hw.hfcpci.ctmt);
1386 Write_hfc(cs, HFCPCI_CONNECT, cs->hw.hfcpci.conn);
1387}
1388
1389/******************************/
1390/* Layer2 -> Layer 1 Transfer */
1391/******************************/
1392static void
1393hfcpci_l2l1(struct PStack *st, int pr, void *arg)
1394{
1395 struct BCState *bcs = st->l1.bcs;
1396 u_long flags;
1397 struct sk_buff *skb = arg;
1398
1399 switch (pr) {
1400 case (PH_DATA | REQUEST):
1401 spin_lock_irqsave(&bcs->cs->lock, flags);
1402 if (bcs->tx_skb) {
1403 skb_queue_tail(&bcs->squeue, skb);
1404 } else {
1405 bcs->tx_skb = skb;
1406// test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
1407 bcs->cs->BC_Send_Data(bcs);
1408 }
1409 spin_unlock_irqrestore(&bcs->cs->lock, flags);
1410 break;
1411 case (PH_PULL | INDICATION):
1412 spin_lock_irqsave(&bcs->cs->lock, flags);
1413 if (bcs->tx_skb) {
1414 spin_unlock_irqrestore(&bcs->cs->lock, flags);
1415 printk(KERN_WARNING "hfc_l2l1: this shouldn't happen\n");
1416 break;
1417 }
1418// test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
1419 bcs->tx_skb = skb;
1420 bcs->cs->BC_Send_Data(bcs);
1421 spin_unlock_irqrestore(&bcs->cs->lock, flags);
1422 break;
1423 case (PH_PULL | REQUEST):
1424 if (!bcs->tx_skb) {
1425 test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
1426 st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
1427 } else
1428 test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
1429 break;
1430 case (PH_ACTIVATE | REQUEST):
1431 spin_lock_irqsave(&bcs->cs->lock, flags);
1432 test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag);
1433 mode_hfcpci(bcs, st->l1.mode, st->l1.bc);
1434 spin_unlock_irqrestore(&bcs->cs->lock, flags);
1435 l1_msg_b(st, pr, arg);
1436 break;
1437 case (PH_DEACTIVATE | REQUEST):
1438 l1_msg_b(st, pr, arg);
1439 break;
1440 case (PH_DEACTIVATE | CONFIRM):
1441 spin_lock_irqsave(&bcs->cs->lock, flags);
1442 test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag);
1443 test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
1444 mode_hfcpci(bcs, 0, st->l1.bc);
1445 spin_unlock_irqrestore(&bcs->cs->lock, flags);
1446 st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
1447 break;
1448 }
1449}
1450
1451/******************************************/
1452/* deactivate B-channel access and queues */
1453/******************************************/
1454static void
1455close_hfcpci(struct BCState *bcs)
1456{
1457 mode_hfcpci(bcs, 0, bcs->channel);
1458 if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) {
1459 skb_queue_purge(&bcs->rqueue);
1460 skb_queue_purge(&bcs->squeue);
1461 if (bcs->tx_skb) {
1462 dev_kfree_skb_any(bcs->tx_skb);
1463 bcs->tx_skb = NULL;
1464 test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
1465 }
1466 }
1467}
1468
1469/*************************************/
1470/* init B-channel queues and control */
1471/*************************************/
1472static int
1473open_hfcpcistate(struct IsdnCardState *cs, struct BCState *bcs)
1474{
1475 if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
1476 skb_queue_head_init(&bcs->rqueue);
1477 skb_queue_head_init(&bcs->squeue);
1478 }
1479 bcs->tx_skb = NULL;
1480 test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
1481 bcs->event = 0;
1482 bcs->tx_cnt = 0;
1483 return (0);
1484}
1485
1486/*********************************/
1487/* inits the stack for B-channel */
1488/*********************************/
1489static int
1490setstack_2b(struct PStack *st, struct BCState *bcs)
1491{
1492 bcs->channel = st->l1.bc;
1493 if (open_hfcpcistate(st->l1.hardware, bcs))
1494 return (-1);
1495 st->l1.bcs = bcs;
1496 st->l2.l2l1 = hfcpci_l2l1;
1497 setstack_manager(st);
1498 bcs->st = st;
1499 setstack_l1_B(st);
1500 return (0);
1501}
1502
1503/***************************/
1504/* handle L1 state changes */
1505/***************************/
1506static void
1507hfcpci_bh(struct IsdnCardState *cs)
1508{
1509 u_long flags;
1510// struct PStack *stptr;
1511
1512 if (!cs)
1513 return;
1514 if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) {
1515 if (!cs->hw.hfcpci.nt_mode)
1516 switch (cs->dc.hfcpci.ph_state) {
1517 case (0):
1518 l1_msg(cs, HW_RESET | INDICATION, NULL);
1519 break;
1520 case (3):
1521 l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL);
1522 break;
1523 case (8):
1524 l1_msg(cs, HW_RSYNC | INDICATION, NULL);
1525 break;
1526 case (6):
1527 l1_msg(cs, HW_INFO2 | INDICATION, NULL);
1528 break;
1529 case (7):
1530 l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
1531 break;
1532 default:
1533 break;
1534 } else {
1535 spin_lock_irqsave(&cs->lock, flags);
1536 switch (cs->dc.hfcpci.ph_state) {
1537 case (2):
1538 if (cs->hw.hfcpci.nt_timer < 0) {
1539 cs->hw.hfcpci.nt_timer = 0;
1540 cs->hw.hfcpci.int_m1 &= ~HFCPCI_INTS_TIMER;
1541 Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1);
1542 /* Clear already pending ints */
1543 if (Read_hfc(cs, HFCPCI_INT_S1));
1544 Write_hfc(cs, HFCPCI_STATES, 4 | HFCPCI_LOAD_STATE);
1545 udelay(10);
1546 Write_hfc(cs, HFCPCI_STATES, 4);
1547 cs->dc.hfcpci.ph_state = 4;
1548 } else {
1549 cs->hw.hfcpci.int_m1 |= HFCPCI_INTS_TIMER;
1550 Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1);
1551 cs->hw.hfcpci.ctmt &= ~HFCPCI_AUTO_TIMER;
1552 cs->hw.hfcpci.ctmt |= HFCPCI_TIM3_125;
1553 Write_hfc(cs, HFCPCI_CTMT, cs->hw.hfcpci.ctmt | HFCPCI_CLTIMER);
1554 Write_hfc(cs, HFCPCI_CTMT, cs->hw.hfcpci.ctmt | HFCPCI_CLTIMER);
1555 cs->hw.hfcpci.nt_timer = NT_T1_COUNT;
1556 Write_hfc(cs, HFCPCI_STATES, 2 | HFCPCI_NT_G2_G3); /* allow G2 -> G3 transition */
1557 }
1558 break;
1559 case (1):
1560 case (3):
1561 case (4):
1562 cs->hw.hfcpci.nt_timer = 0;
1563 cs->hw.hfcpci.int_m1 &= ~HFCPCI_INTS_TIMER;
1564 Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1);
1565 break;
1566 default:
1567 break;
1568 }
1569 spin_unlock_irqrestore(&cs->lock, flags);
1570 }
1571 }
1572 if (test_and_clear_bit(D_RCVBUFREADY, &cs->event))
1573 DChannel_proc_rcv(cs);
1574 if (test_and_clear_bit(D_XMTBUFREADY, &cs->event))
1575 DChannel_proc_xmt(cs);
1576}
1577
1578
1579/********************************/
1580/* called for card init message */
1581/********************************/
1582void __init
1583inithfcpci(struct IsdnCardState *cs)
1584{
1585 cs->bcs[0].BC_SetStack = setstack_2b;
1586 cs->bcs[1].BC_SetStack = setstack_2b;
1587 cs->bcs[0].BC_Close = close_hfcpci;
1588 cs->bcs[1].BC_Close = close_hfcpci;
1589 cs->dbusytimer.function = (void *) hfcpci_dbusy_timer;
1590 cs->dbusytimer.data = (long) cs;
1591 init_timer(&cs->dbusytimer);
1592 mode_hfcpci(cs->bcs, 0, 0);
1593 mode_hfcpci(cs->bcs + 1, 0, 1);
1594}
1595
1596
1597
1598/*******************************************/
1599/* handle card messages from control layer */
1600/*******************************************/
1601static int
1602hfcpci_card_msg(struct IsdnCardState *cs, int mt, void *arg)
1603{
1604 u_long flags;
1605
1606 if (cs->debug & L1_DEB_ISAC)
1607 debugl1(cs, "HFCPCI: card_msg %x", mt);
1608 switch (mt) {
1609 case CARD_RESET:
1610 spin_lock_irqsave(&cs->lock, flags);
1611 reset_hfcpci(cs);
1612 spin_unlock_irqrestore(&cs->lock, flags);
1613 return (0);
1614 case CARD_RELEASE:
1615 release_io_hfcpci(cs);
1616 return (0);
1617 case CARD_INIT:
1618 spin_lock_irqsave(&cs->lock, flags);
1619 inithfcpci(cs);
1620 reset_hfcpci(cs);
1621 spin_unlock_irqrestore(&cs->lock, flags);
1622 msleep(80); /* Timeout 80ms */
1623 /* now switch timer interrupt off */
1624 spin_lock_irqsave(&cs->lock, flags);
1625 cs->hw.hfcpci.int_m1 &= ~HFCPCI_INTS_TIMER;
1626 Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1);
1627 /* reinit mode reg */
1628 Write_hfc(cs, HFCPCI_MST_MODE, cs->hw.hfcpci.mst_m);
1629 spin_unlock_irqrestore(&cs->lock, flags);
1630 return (0);
1631 case CARD_TEST:
1632 return (0);
1633 }
1634 return (0);
1635}
1636
1637
1638/* this variable is used as card index when more than one cards are present */
1639static struct pci_dev *dev_hfcpci __initdata = NULL;
1640
1641#endif /* CONFIG_PCI */
1642
1643int __init
1644setup_hfcpci(struct IsdnCard *card)
1645{
1646 u_long flags;
1647 struct IsdnCardState *cs = card->cs;
1648 char tmp[64];
1649 int i;
1650 struct pci_dev *tmp_hfcpci = NULL;
1651
1652#ifdef __BIG_ENDIAN
1653#error "not running on big endian machines now"
1654#endif
1655 strcpy(tmp, hfcpci_revision);
1656 printk(KERN_INFO "HiSax: HFC-PCI driver Rev. %s\n", HiSax_getrev(tmp));
1657#ifdef CONFIG_PCI
1658 cs->hw.hfcpci.int_s1 = 0;
1659 cs->dc.hfcpci.ph_state = 0;
1660 cs->hw.hfcpci.fifo = 255;
1661 if (cs->typ == ISDN_CTYPE_HFC_PCI) {
1662 i = 0;
1663 while (id_list[i].vendor_id) {
1664 tmp_hfcpci = pci_find_device(id_list[i].vendor_id,
1665 id_list[i].device_id,
1666 dev_hfcpci);
1667 i++;
1668 if (tmp_hfcpci) {
1669 if (pci_enable_device(tmp_hfcpci))
1670 continue;
1671 pci_set_master(tmp_hfcpci);
1672 if ((card->para[0]) && (card->para[0] != (tmp_hfcpci->resource[ 0].start & PCI_BASE_ADDRESS_IO_MASK)))
1673 continue;
1674 else
1675 break;
1676 }
1677 }
1678
1679 if (tmp_hfcpci) {
1680 i--;
1681 dev_hfcpci = tmp_hfcpci; /* old device */
1682 cs->hw.hfcpci.dev = dev_hfcpci;
1683 cs->irq = dev_hfcpci->irq;
1684 if (!cs->irq) {
1685 printk(KERN_WARNING "HFC-PCI: No IRQ for PCI card found\n");
1686 return (0);
1687 }
1688 cs->hw.hfcpci.pci_io = (char *) dev_hfcpci->resource[ 1].start;
1689 printk(KERN_INFO "HiSax: HFC-PCI card manufacturer: %s card name: %s\n", id_list[i].vendor_name, id_list[i].card_name);
1690 } else {
1691 printk(KERN_WARNING "HFC-PCI: No PCI card found\n");
1692 return (0);
1693 }
1694 if (!cs->hw.hfcpci.pci_io) {
1695 printk(KERN_WARNING "HFC-PCI: No IO-Mem for PCI card found\n");
1696 return (0);
1697 }
1698 /* Allocate memory for FIFOS */
1699 /* Because the HFC-PCI needs a 32K physical alignment, we */
1700 /* need to allocate the double mem and align the address */
1701 if (!(cs->hw.hfcpci.share_start = kmalloc(65536, GFP_KERNEL))) {
1702 printk(KERN_WARNING "HFC-PCI: Error allocating memory for FIFO!\n");
1703 return 0;
1704 }
1705 cs->hw.hfcpci.fifos = (void *)
1706 (((ulong) cs->hw.hfcpci.share_start) & ~0x7FFF) + 0x8000;
1707 pci_write_config_dword(cs->hw.hfcpci.dev, 0x80, (u_int) virt_to_bus(cs->hw.hfcpci.fifos));
1708 cs->hw.hfcpci.pci_io = ioremap((ulong) cs->hw.hfcpci.pci_io, 256);
1709 printk(KERN_INFO
1710 "HFC-PCI: defined at mem %#x fifo %#x(%#x) IRQ %d HZ %d\n",
1711 (u_int) cs->hw.hfcpci.pci_io,
1712 (u_int) cs->hw.hfcpci.fifos,
1713 (u_int) virt_to_bus(cs->hw.hfcpci.fifos),
1714 cs->irq, HZ);
1715 spin_lock_irqsave(&cs->lock, flags);
1716 pci_write_config_word(cs->hw.hfcpci.dev, PCI_COMMAND, PCI_ENA_MEMIO); /* enable memory mapped ports, disable busmaster */
1717 cs->hw.hfcpci.int_m2 = 0; /* disable alle interrupts */
1718 cs->hw.hfcpci.int_m1 = 0;
1719 Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1);
1720 Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2);
1721 /* At this point the needed PCI config is done */
1722 /* fifos are still not enabled */
1723 INIT_WORK(&cs->tqueue, (void *)(void *) hfcpci_bh, cs);
1724 cs->setstack_d = setstack_hfcpci;
1725 cs->BC_Send_Data = &hfcpci_send_data;
1726 cs->readisac = NULL;
1727 cs->writeisac = NULL;
1728 cs->readisacfifo = NULL;
1729 cs->writeisacfifo = NULL;
1730 cs->BC_Read_Reg = NULL;
1731 cs->BC_Write_Reg = NULL;
1732 cs->irq_func = &hfcpci_interrupt;
1733 cs->irq_flags |= SA_SHIRQ;
1734 cs->hw.hfcpci.timer.function = (void *) hfcpci_Timer;
1735 cs->hw.hfcpci.timer.data = (long) cs;
1736 init_timer(&cs->hw.hfcpci.timer);
1737 cs->cardmsg = &hfcpci_card_msg;
1738 cs->auxcmd = &hfcpci_auxcmd;
1739 spin_unlock_irqrestore(&cs->lock, flags);
1740 return (1);
1741 } else
1742 return (0); /* no valid card type */
1743#else
1744 printk(KERN_WARNING "HFC-PCI: NO_PCI_BIOS\n");
1745 return (0);
1746#endif /* CONFIG_PCI */
1747}
diff --git a/drivers/isdn/hisax/hfc_pci.h b/drivers/isdn/hisax/hfc_pci.h
new file mode 100644
index 000000000000..4df036ed1af0
--- /dev/null
+++ b/drivers/isdn/hisax/hfc_pci.h
@@ -0,0 +1,236 @@
1/* $Id: hfc_pci.h,v 1.10.2.2 2004/01/12 22:52:26 keil Exp $
2 *
3 * specific defines for CCD's HFC 2BDS0 PCI chips
4 *
5 * Author Werner Cornelius
6 * Copyright by Werner Cornelius <werner@isdn4linux.de>
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 */
12
13/*********************************************/
14/* thresholds for transparent B-channel mode */
15/* change mask and threshold simultaneously */
16/*********************************************/
17#define HFCPCI_BTRANS_THRESHOLD 128
18#define HFCPCI_BTRANS_THRESMASK 0x00
19
20
21
22/* defines for PCI config */
23
24#define PCI_ENA_MEMIO 0x02
25#define PCI_ENA_MASTER 0x04
26
27
28/* GCI/IOM bus monitor registers */
29
30#define HCFPCI_C_I 0x08
31#define HFCPCI_TRxR 0x0C
32#define HFCPCI_MON1_D 0x28
33#define HFCPCI_MON2_D 0x2C
34
35
36/* GCI/IOM bus timeslot registers */
37
38#define HFCPCI_B1_SSL 0x80
39#define HFCPCI_B2_SSL 0x84
40#define HFCPCI_AUX1_SSL 0x88
41#define HFCPCI_AUX2_SSL 0x8C
42#define HFCPCI_B1_RSL 0x90
43#define HFCPCI_B2_RSL 0x94
44#define HFCPCI_AUX1_RSL 0x98
45#define HFCPCI_AUX2_RSL 0x9C
46
47/* GCI/IOM bus data registers */
48
49#define HFCPCI_B1_D 0xA0
50#define HFCPCI_B2_D 0xA4
51#define HFCPCI_AUX1_D 0xA8
52#define HFCPCI_AUX2_D 0xAC
53
54/* GCI/IOM bus configuration registers */
55
56#define HFCPCI_MST_EMOD 0xB4
57#define HFCPCI_MST_MODE 0xB8
58#define HFCPCI_CONNECT 0xBC
59
60
61/* Interrupt and status registers */
62
63#define HFCPCI_FIFO_EN 0x44
64#define HFCPCI_TRM 0x48
65#define HFCPCI_B_MODE 0x4C
66#define HFCPCI_CHIP_ID 0x58
67#define HFCPCI_CIRM 0x60
68#define HFCPCI_CTMT 0x64
69#define HFCPCI_INT_M1 0x68
70#define HFCPCI_INT_M2 0x6C
71#define HFCPCI_INT_S1 0x78
72#define HFCPCI_INT_S2 0x7C
73#define HFCPCI_STATUS 0x70
74
75/* S/T section registers */
76
77#define HFCPCI_STATES 0xC0
78#define HFCPCI_SCTRL 0xC4
79#define HFCPCI_SCTRL_E 0xC8
80#define HFCPCI_SCTRL_R 0xCC
81#define HFCPCI_SQ 0xD0
82#define HFCPCI_CLKDEL 0xDC
83#define HFCPCI_B1_REC 0xF0
84#define HFCPCI_B1_SEND 0xF0
85#define HFCPCI_B2_REC 0xF4
86#define HFCPCI_B2_SEND 0xF4
87#define HFCPCI_D_REC 0xF8
88#define HFCPCI_D_SEND 0xF8
89#define HFCPCI_E_REC 0xFC
90
91
92/* bits in status register (READ) */
93#define HFCPCI_PCI_PROC 0x02
94#define HFCPCI_NBUSY 0x04
95#define HFCPCI_TIMER_ELAP 0x10
96#define HFCPCI_STATINT 0x20
97#define HFCPCI_FRAMEINT 0x40
98#define HFCPCI_ANYINT 0x80
99
100/* bits in CTMT (Write) */
101#define HFCPCI_CLTIMER 0x80
102#define HFCPCI_TIM3_125 0x04
103#define HFCPCI_TIM25 0x10
104#define HFCPCI_TIM50 0x14
105#define HFCPCI_TIM400 0x18
106#define HFCPCI_TIM800 0x1C
107#define HFCPCI_AUTO_TIMER 0x20
108#define HFCPCI_TRANSB2 0x02
109#define HFCPCI_TRANSB1 0x01
110
111/* bits in CIRM (Write) */
112#define HFCPCI_AUX_MSK 0x07
113#define HFCPCI_RESET 0x08
114#define HFCPCI_B1_REV 0x40
115#define HFCPCI_B2_REV 0x80
116
117/* bits in INT_M1 and INT_S1 */
118#define HFCPCI_INTS_B1TRANS 0x01
119#define HFCPCI_INTS_B2TRANS 0x02
120#define HFCPCI_INTS_DTRANS 0x04
121#define HFCPCI_INTS_B1REC 0x08
122#define HFCPCI_INTS_B2REC 0x10
123#define HFCPCI_INTS_DREC 0x20
124#define HFCPCI_INTS_L1STATE 0x40
125#define HFCPCI_INTS_TIMER 0x80
126
127/* bits in INT_M2 */
128#define HFCPCI_PROC_TRANS 0x01
129#define HFCPCI_GCI_I_CHG 0x02
130#define HFCPCI_GCI_MON_REC 0x04
131#define HFCPCI_IRQ_ENABLE 0x08
132#define HFCPCI_PMESEL 0x80
133
134/* bits in STATES */
135#define HFCPCI_STATE_MSK 0x0F
136#define HFCPCI_LOAD_STATE 0x10
137#define HFCPCI_ACTIVATE 0x20
138#define HFCPCI_DO_ACTION 0x40
139#define HFCPCI_NT_G2_G3 0x80
140
141/* bits in HFCD_MST_MODE */
142#define HFCPCI_MASTER 0x01
143#define HFCPCI_SLAVE 0x00
144/* remaining bits are for codecs control */
145
146/* bits in HFCD_SCTRL */
147#define SCTRL_B1_ENA 0x01
148#define SCTRL_B2_ENA 0x02
149#define SCTRL_MODE_TE 0x00
150#define SCTRL_MODE_NT 0x04
151#define SCTRL_LOW_PRIO 0x08
152#define SCTRL_SQ_ENA 0x10
153#define SCTRL_TEST 0x20
154#define SCTRL_NONE_CAP 0x40
155#define SCTRL_PWR_DOWN 0x80
156
157/* bits in SCTRL_E */
158#define HFCPCI_AUTO_AWAKE 0x01
159#define HFCPCI_DBIT_1 0x04
160#define HFCPCI_IGNORE_COL 0x08
161#define HFCPCI_CHG_B1_B2 0x80
162
163/****************************/
164/* bits in FIFO_EN register */
165/****************************/
166#define HFCPCI_FIFOEN_B1 0x03
167#define HFCPCI_FIFOEN_B2 0x0C
168#define HFCPCI_FIFOEN_DTX 0x10
169#define HFCPCI_FIFOEN_B1TX 0x01
170#define HFCPCI_FIFOEN_B1RX 0x02
171#define HFCPCI_FIFOEN_B2TX 0x04
172#define HFCPCI_FIFOEN_B2RX 0x08
173
174
175/***********************************/
176/* definitions of fifo memory area */
177/***********************************/
178#define MAX_D_FRAMES 15
179#define MAX_B_FRAMES 31
180#define B_SUB_VAL 0x200
181#define B_FIFO_SIZE (0x2000 - B_SUB_VAL)
182#define D_FIFO_SIZE 512
183#define D_FREG_MASK 0xF
184
185typedef struct {
186 unsigned short z1; /* Z1 pointer 16 Bit */
187 unsigned short z2; /* Z2 pointer 16 Bit */
188 } z_type;
189
190typedef struct {
191 u_char data[D_FIFO_SIZE]; /* FIFO data space */
192 u_char fill1[0x20A0-D_FIFO_SIZE]; /* reserved, do not use */
193 u_char f1,f2; /* f pointers */
194 u_char fill2[0x20C0-0x20A2]; /* reserved, do not use */
195 z_type za[MAX_D_FRAMES+1]; /* mask index with D_FREG_MASK for access */
196 u_char fill3[0x4000-0x2100]; /* align 16K */
197 } dfifo_type;
198
199typedef struct {
200 z_type za[MAX_B_FRAMES+1]; /* only range 0x0..0x1F allowed */
201 u_char f1,f2; /* f pointers */
202 u_char fill[0x2100-0x2082]; /* alignment */
203 } bzfifo_type;
204
205
206typedef union {
207 struct {
208 dfifo_type d_tx; /* D-send channel */
209 dfifo_type d_rx; /* D-receive channel */
210 } d_chan;
211 struct {
212 u_char fill1[0x200];
213 u_char txdat_b1[B_FIFO_SIZE];
214 bzfifo_type txbz_b1;
215
216 bzfifo_type txbz_b2;
217 u_char txdat_b2[B_FIFO_SIZE];
218
219 u_char fill2[D_FIFO_SIZE];
220
221 u_char rxdat_b1[B_FIFO_SIZE];
222 bzfifo_type rxbz_b1;
223
224 bzfifo_type rxbz_b2;
225 u_char rxdat_b2[B_FIFO_SIZE];
226 } b_chans;
227 u_char fill[32768];
228 } fifo_area;
229
230
231#define Write_hfc(a,b,c) (*(((u_char *)a->hw.hfcpci.pci_io)+b) = c)
232#define Read_hfc(a,b) (*(((u_char *)a->hw.hfcpci.pci_io)+b))
233
234extern void main_irq_hcpci(struct BCState *bcs);
235extern void inithfcpci(struct IsdnCardState *cs);
236extern void releasehfcpci(struct IsdnCardState *cs);
diff --git a/drivers/isdn/hisax/hfc_sx.c b/drivers/isdn/hisax/hfc_sx.c
new file mode 100644
index 000000000000..a307fcb6c634
--- /dev/null
+++ b/drivers/isdn/hisax/hfc_sx.c
@@ -0,0 +1,1521 @@
1/* $Id: hfc_sx.c,v 1.12.2.5 2004/02/11 13:21:33 keil Exp $
2 *
3 * level driver for Cologne Chip Designs hfc-s+/sp based cards
4 *
5 * Author Werner Cornelius
6 * based on existing driver for CCD HFC PCI cards
7 * Copyright by Werner Cornelius <werner@isdn4linux.de>
8 *
9 * This software may be used and distributed according to the terms
10 * of the GNU General Public License, incorporated herein by reference.
11 *
12 */
13
14#include <linux/init.h>
15#include "hisax.h"
16#include "hfc_sx.h"
17#include "isdnl1.h"
18#include <linux/interrupt.h>
19#include <linux/isapnp.h>
20
21extern const char *CardType[];
22
23static const char *hfcsx_revision = "$Revision: 1.12.2.5 $";
24
25/***************************************/
26/* IRQ-table for CCDs demo board */
27/* IRQs 6,5,10,11,12,15 are supported */
28/***************************************/
29
30/* Teles 16.3c Vendor Id TAG2620, Version 1.0, Vendor version 2.1
31 *
32 * Thanks to Uwe Wisniewski
33 *
34 * ISA-SLOT Signal PIN
35 * B25 IRQ3 92 IRQ_G
36 * B23 IRQ5 94 IRQ_A
37 * B4 IRQ2/9 95 IRQ_B
38 * D3 IRQ10 96 IRQ_C
39 * D4 IRQ11 97 IRQ_D
40 * D5 IRQ12 98 IRQ_E
41 * D6 IRQ15 99 IRQ_F
42 */
43
44#undef CCD_DEMO_BOARD
45#ifdef CCD_DEMO_BOARD
46static u_char ccd_sp_irqtab[16] = {
47 0,0,0,0,0,2,1,0,0,0,3,4,5,0,0,6
48};
49#else /* Teles 16.3c */
50static u_char ccd_sp_irqtab[16] = {
51 0,0,0,7,0,1,0,0,0,2,3,4,5,0,0,6
52};
53#endif
54#define NT_T1_COUNT 20 /* number of 3.125ms interrupts for G2 timeout */
55
56#define byteout(addr,val) outb(val,addr)
57#define bytein(addr) inb(addr)
58
59/******************************/
60/* In/Out access to registers */
61/******************************/
62static inline void
63Write_hfc(struct IsdnCardState *cs, u_char regnum, u_char val)
64{
65 byteout(cs->hw.hfcsx.base+1, regnum);
66 byteout(cs->hw.hfcsx.base, val);
67}
68
69static inline u_char
70Read_hfc(struct IsdnCardState *cs, u_char regnum)
71{
72 u_char ret;
73
74 byteout(cs->hw.hfcsx.base+1, regnum);
75 ret = bytein(cs->hw.hfcsx.base);
76 return(ret);
77}
78
79
80/**************************************************/
81/* select a fifo and remember which one for reuse */
82/**************************************************/
83static void
84fifo_select(struct IsdnCardState *cs, u_char fifo)
85{
86 if (fifo == cs->hw.hfcsx.last_fifo)
87 return; /* still valid */
88
89 byteout(cs->hw.hfcsx.base+1, HFCSX_FIF_SEL);
90 byteout(cs->hw.hfcsx.base, fifo);
91 while (bytein(cs->hw.hfcsx.base+1) & 1); /* wait for busy */
92 udelay(4);
93 byteout(cs->hw.hfcsx.base, fifo);
94 while (bytein(cs->hw.hfcsx.base+1) & 1); /* wait for busy */
95}
96
97/******************************************/
98/* reset the specified fifo to defaults. */
99/* If its a send fifo init needed markers */
100/******************************************/
101static void
102reset_fifo(struct IsdnCardState *cs, u_char fifo)
103{
104 fifo_select(cs, fifo); /* first select the fifo */
105 byteout(cs->hw.hfcsx.base+1, HFCSX_CIRM);
106 byteout(cs->hw.hfcsx.base, cs->hw.hfcsx.cirm | 0x80); /* reset cmd */
107 udelay(1);
108 while (bytein(cs->hw.hfcsx.base+1) & 1); /* wait for busy */
109}
110
111
112/*************************************************************/
113/* write_fifo writes the skb contents to the desired fifo */
114/* if no space is available or an error occurs 0 is returned */
115/* the skb is not released in any way. */
116/*************************************************************/
117static int
118write_fifo(struct IsdnCardState *cs, struct sk_buff *skb, u_char fifo, int trans_max)
119{
120 unsigned short *msp;
121 int fifo_size, count, z1, z2;
122 u_char f_msk, f1, f2, *src;
123
124 if (skb->len <= 0) return(0);
125 if (fifo & 1) return(0); /* no write fifo */
126
127 fifo_select(cs, fifo);
128 if (fifo & 4) {
129 fifo_size = D_FIFO_SIZE; /* D-channel */
130 f_msk = MAX_D_FRAMES;
131 if (trans_max) return(0); /* only HDLC */
132 }
133 else {
134 fifo_size = cs->hw.hfcsx.b_fifo_size; /* B-channel */
135 f_msk = MAX_B_FRAMES;
136 }
137
138 z1 = Read_hfc(cs, HFCSX_FIF_Z1H);
139 z1 = ((z1 << 8) | Read_hfc(cs, HFCSX_FIF_Z1L));
140
141 /* Check for transparent mode */
142 if (trans_max) {
143 z2 = Read_hfc(cs, HFCSX_FIF_Z2H);
144 z2 = ((z2 << 8) | Read_hfc(cs, HFCSX_FIF_Z2L));
145 count = z2 - z1;
146 if (count <= 0)
147 count += fifo_size; /* free bytes */
148 if (count < skb->len+1) return(0); /* no room */
149 count = fifo_size - count; /* bytes still not send */
150 if (count > 2 * trans_max) return(0); /* delay to long */
151 count = skb->len;
152 src = skb->data;
153 while (count--)
154 Write_hfc(cs, HFCSX_FIF_DWR, *src++);
155 return(1); /* success */
156 }
157
158 msp = ((struct hfcsx_extra *)(cs->hw.hfcsx.extra))->marker;
159 msp += (((fifo >> 1) & 3) * (MAX_B_FRAMES+1));
160 f1 = Read_hfc(cs, HFCSX_FIF_F1) & f_msk;
161 f2 = Read_hfc(cs, HFCSX_FIF_F2) & f_msk;
162
163 count = f1 - f2; /* frame count actually buffered */
164 if (count < 0)
165 count += (f_msk + 1); /* if wrap around */
166 if (count > f_msk-1) {
167 if (cs->debug & L1_DEB_ISAC_FIFO)
168 debugl1(cs, "hfcsx_write_fifo %d more as %d frames",fifo,f_msk-1);
169 return(0);
170 }
171
172 *(msp + f1) = z1; /* remember marker */
173
174 if (cs->debug & L1_DEB_ISAC_FIFO)
175 debugl1(cs, "hfcsx_write_fifo %d f1(%x) f2(%x) z1(f1)(%x)",
176 fifo, f1, f2, z1);
177 /* now determine free bytes in FIFO buffer */
178 count = *(msp + f2) - z1;
179 if (count <= 0)
180 count += fifo_size; /* count now contains available bytes */
181
182 if (cs->debug & L1_DEB_ISAC_FIFO)
183 debugl1(cs, "hfcsx_write_fifo %d count(%ld/%d)",
184 fifo, skb->len, count);
185 if (count < skb->len) {
186 if (cs->debug & L1_DEB_ISAC_FIFO)
187 debugl1(cs, "hfcsx_write_fifo %d no fifo mem", fifo);
188 return(0);
189 }
190
191 count = skb->len; /* get frame len */
192 src = skb->data; /* source pointer */
193 while (count--)
194 Write_hfc(cs, HFCSX_FIF_DWR, *src++);
195
196 Read_hfc(cs, HFCSX_FIF_INCF1); /* increment F1 */
197 udelay(1);
198 while (bytein(cs->hw.hfcsx.base+1) & 1); /* wait for busy */
199 return(1);
200}
201
202/***************************************************************/
203/* read_fifo reads data to an skb from the desired fifo */
204/* if no data is available or an error occurs NULL is returned */
205/* the skb is not released in any way. */
206/***************************************************************/
207static struct sk_buff *
208read_fifo(struct IsdnCardState *cs, u_char fifo, int trans_max)
209{ int fifo_size, count, z1, z2;
210 u_char f_msk, f1, f2, *dst;
211 struct sk_buff *skb;
212
213 if (!(fifo & 1)) return(NULL); /* no read fifo */
214 fifo_select(cs, fifo);
215 if (fifo & 4) {
216 fifo_size = D_FIFO_SIZE; /* D-channel */
217 f_msk = MAX_D_FRAMES;
218 if (trans_max) return(NULL); /* only hdlc */
219 }
220 else {
221 fifo_size = cs->hw.hfcsx.b_fifo_size; /* B-channel */
222 f_msk = MAX_B_FRAMES;
223 }
224
225 /* transparent mode */
226 if (trans_max) {
227 z1 = Read_hfc(cs, HFCSX_FIF_Z1H);
228 z1 = ((z1 << 8) | Read_hfc(cs, HFCSX_FIF_Z1L));
229 z2 = Read_hfc(cs, HFCSX_FIF_Z2H);
230 z2 = ((z2 << 8) | Read_hfc(cs, HFCSX_FIF_Z2L));
231 /* now determine bytes in actual FIFO buffer */
232 count = z1 - z2;
233 if (count <= 0)
234 count += fifo_size; /* count now contains buffered bytes */
235 count++;
236 if (count > trans_max)
237 count = trans_max; /* limit length */
238 if ((skb = dev_alloc_skb(count))) {
239 dst = skb_put(skb, count);
240 while (count--)
241 *dst++ = Read_hfc(cs, HFCSX_FIF_DRD);
242 return(skb);
243 }
244 else return(NULL); /* no memory */
245 }
246
247 do {
248 f1 = Read_hfc(cs, HFCSX_FIF_F1) & f_msk;
249 f2 = Read_hfc(cs, HFCSX_FIF_F2) & f_msk;
250
251 if (f1 == f2) return(NULL); /* no frame available */
252
253 z1 = Read_hfc(cs, HFCSX_FIF_Z1H);
254 z1 = ((z1 << 8) | Read_hfc(cs, HFCSX_FIF_Z1L));
255 z2 = Read_hfc(cs, HFCSX_FIF_Z2H);
256 z2 = ((z2 << 8) | Read_hfc(cs, HFCSX_FIF_Z2L));
257
258 if (cs->debug & L1_DEB_ISAC_FIFO)
259 debugl1(cs, "hfcsx_read_fifo %d f1(%x) f2(%x) z1(f2)(%x) z2(f2)(%x)",
260 fifo, f1, f2, z1, z2);
261 /* now determine bytes in actual FIFO buffer */
262 count = z1 - z2;
263 if (count <= 0)
264 count += fifo_size; /* count now contains buffered bytes */
265 count++;
266
267 if (cs->debug & L1_DEB_ISAC_FIFO)
268 debugl1(cs, "hfcsx_read_fifo %d count %ld)",
269 fifo, count);
270
271 if ((count > fifo_size) || (count < 4)) {
272 if (cs->debug & L1_DEB_WARN)
273 debugl1(cs, "hfcsx_read_fifo %d paket inv. len %d ", fifo , count);
274 while (count) {
275 count--; /* empty fifo */
276 Read_hfc(cs, HFCSX_FIF_DRD);
277 }
278 skb = NULL;
279 } else
280 if ((skb = dev_alloc_skb(count - 3))) {
281 count -= 3;
282 dst = skb_put(skb, count);
283
284 while (count--)
285 *dst++ = Read_hfc(cs, HFCSX_FIF_DRD);
286
287 Read_hfc(cs, HFCSX_FIF_DRD); /* CRC 1 */
288 Read_hfc(cs, HFCSX_FIF_DRD); /* CRC 2 */
289 if (Read_hfc(cs, HFCSX_FIF_DRD)) {
290 dev_kfree_skb_irq(skb);
291 if (cs->debug & L1_DEB_ISAC_FIFO)
292 debugl1(cs, "hfcsx_read_fifo %d crc error", fifo);
293 skb = NULL;
294 }
295 } else {
296 printk(KERN_WARNING "HFC-SX: receive out of memory\n");
297 return(NULL);
298 }
299
300 Read_hfc(cs, HFCSX_FIF_INCF2); /* increment F2 */
301 udelay(1);
302 while (bytein(cs->hw.hfcsx.base+1) & 1); /* wait for busy */
303 udelay(1);
304 } while (!skb); /* retry in case of crc error */
305 return(skb);
306}
307
308/******************************************/
309/* free hardware resources used by driver */
310/******************************************/
311void
312release_io_hfcsx(struct IsdnCardState *cs)
313{
314 cs->hw.hfcsx.int_m2 = 0; /* interrupt output off ! */
315 Write_hfc(cs, HFCSX_INT_M2, cs->hw.hfcsx.int_m2);
316 Write_hfc(cs, HFCSX_CIRM, HFCSX_RESET); /* Reset On */
317 msleep(30); /* Timeout 30ms */
318 Write_hfc(cs, HFCSX_CIRM, 0); /* Reset Off */
319 del_timer(&cs->hw.hfcsx.timer);
320 release_region(cs->hw.hfcsx.base, 2); /* release IO-Block */
321 kfree(cs->hw.hfcsx.extra);
322 cs->hw.hfcsx.extra = NULL;
323}
324
325/**********************************************************/
326/* set_fifo_size determines the size of the RAM and FIFOs */
327/* returning 0 -> need to reset the chip again. */
328/**********************************************************/
329static int set_fifo_size(struct IsdnCardState *cs)
330{
331
332 if (cs->hw.hfcsx.b_fifo_size) return(1); /* already determined */
333
334 if ((cs->hw.hfcsx.chip >> 4) == 9) {
335 cs->hw.hfcsx.b_fifo_size = B_FIFO_SIZE_32K;
336 return(1);
337 }
338
339 cs->hw.hfcsx.b_fifo_size = B_FIFO_SIZE_8K;
340 cs->hw.hfcsx.cirm |= 0x10; /* only 8K of ram */
341 return(0);
342
343}
344
345/********************************************************************************/
346/* function called to reset the HFC SX chip. A complete software reset of chip */
347/* and fifos is done. */
348/********************************************************************************/
349static void
350reset_hfcsx(struct IsdnCardState *cs)
351{
352 cs->hw.hfcsx.int_m2 = 0; /* interrupt output off ! */
353 Write_hfc(cs, HFCSX_INT_M2, cs->hw.hfcsx.int_m2);
354
355 printk(KERN_INFO "HFC_SX: resetting card\n");
356 while (1) {
357 Write_hfc(cs, HFCSX_CIRM, HFCSX_RESET | cs->hw.hfcsx.cirm ); /* Reset */
358 mdelay(30);
359 Write_hfc(cs, HFCSX_CIRM, cs->hw.hfcsx.cirm); /* Reset Off */
360 mdelay(20);
361 if (Read_hfc(cs, HFCSX_STATUS) & 2)
362 printk(KERN_WARNING "HFC-SX init bit busy\n");
363 cs->hw.hfcsx.last_fifo = 0xff; /* invalidate */
364 if (!set_fifo_size(cs)) continue;
365 break;
366 }
367
368 cs->hw.hfcsx.trm = 0 + HFCSX_BTRANS_THRESMASK; /* no echo connect , threshold */
369 Write_hfc(cs, HFCSX_TRM, cs->hw.hfcsx.trm);
370
371 Write_hfc(cs, HFCSX_CLKDEL, 0x0e); /* ST-Bit delay for TE-Mode */
372 cs->hw.hfcsx.sctrl_e = HFCSX_AUTO_AWAKE;
373 Write_hfc(cs, HFCSX_SCTRL_E, cs->hw.hfcsx.sctrl_e); /* S/T Auto awake */
374 cs->hw.hfcsx.bswapped = 0; /* no exchange */
375 cs->hw.hfcsx.nt_mode = 0; /* we are in TE mode */
376 cs->hw.hfcsx.ctmt = HFCSX_TIM3_125 | HFCSX_AUTO_TIMER;
377 Write_hfc(cs, HFCSX_CTMT, cs->hw.hfcsx.ctmt);
378
379 cs->hw.hfcsx.int_m1 = HFCSX_INTS_DTRANS | HFCSX_INTS_DREC |
380 HFCSX_INTS_L1STATE | HFCSX_INTS_TIMER;
381 Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1);
382
383 /* Clear already pending ints */
384 if (Read_hfc(cs, HFCSX_INT_S1));
385
386 Write_hfc(cs, HFCSX_STATES, HFCSX_LOAD_STATE | 2); /* HFC ST 2 */
387 udelay(10);
388 Write_hfc(cs, HFCSX_STATES, 2); /* HFC ST 2 */
389 cs->hw.hfcsx.mst_m = HFCSX_MASTER; /* HFC Master Mode */
390
391 Write_hfc(cs, HFCSX_MST_MODE, cs->hw.hfcsx.mst_m);
392 cs->hw.hfcsx.sctrl = 0x40; /* set tx_lo mode, error in datasheet ! */
393 Write_hfc(cs, HFCSX_SCTRL, cs->hw.hfcsx.sctrl);
394 cs->hw.hfcsx.sctrl_r = 0;
395 Write_hfc(cs, HFCSX_SCTRL_R, cs->hw.hfcsx.sctrl_r);
396
397 /* Init GCI/IOM2 in master mode */
398 /* Slots 0 and 1 are set for B-chan 1 and 2 */
399 /* D- and monitor/CI channel are not enabled */
400 /* STIO1 is used as output for data, B1+B2 from ST->IOM+HFC */
401 /* STIO2 is used as data input, B1+B2 from IOM->ST */
402 /* ST B-channel send disabled -> continous 1s */
403 /* The IOM slots are always enabled */
404 cs->hw.hfcsx.conn = 0x36; /* set data flow directions */
405 Write_hfc(cs, HFCSX_CONNECT, cs->hw.hfcsx.conn);
406 Write_hfc(cs, HFCSX_B1_SSL, 0x80); /* B1-Slot 0 STIO1 out enabled */
407 Write_hfc(cs, HFCSX_B2_SSL, 0x81); /* B2-Slot 1 STIO1 out enabled */
408 Write_hfc(cs, HFCSX_B1_RSL, 0x80); /* B1-Slot 0 STIO2 in enabled */
409 Write_hfc(cs, HFCSX_B2_RSL, 0x81); /* B2-Slot 1 STIO2 in enabled */
410
411 /* Finally enable IRQ output */
412 cs->hw.hfcsx.int_m2 = HFCSX_IRQ_ENABLE;
413 Write_hfc(cs, HFCSX_INT_M2, cs->hw.hfcsx.int_m2);
414 if (Read_hfc(cs, HFCSX_INT_S2));
415}
416
417/***************************************************/
418/* Timer function called when kernel timer expires */
419/***************************************************/
420static void
421hfcsx_Timer(struct IsdnCardState *cs)
422{
423 cs->hw.hfcsx.timer.expires = jiffies + 75;
424 /* WD RESET */
425/* WriteReg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcsx.ctmt | 0x80);
426 add_timer(&cs->hw.hfcsx.timer);
427 */
428}
429
430/************************************************/
431/* select a b-channel entry matching and active */
432/************************************************/
433static
434struct BCState *
435Sel_BCS(struct IsdnCardState *cs, int channel)
436{
437 if (cs->bcs[0].mode && (cs->bcs[0].channel == channel))
438 return (&cs->bcs[0]);
439 else if (cs->bcs[1].mode && (cs->bcs[1].channel == channel))
440 return (&cs->bcs[1]);
441 else
442 return (NULL);
443}
444
445/*******************************/
446/* D-channel receive procedure */
447/*******************************/
448static
449int
450receive_dmsg(struct IsdnCardState *cs)
451{
452 struct sk_buff *skb;
453 int count = 5;
454
455 if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
456 debugl1(cs, "rec_dmsg blocked");
457 return (1);
458 }
459
460 do {
461 skb = read_fifo(cs, HFCSX_SEL_D_RX, 0);
462 if (skb) {
463 skb_queue_tail(&cs->rq, skb);
464 schedule_event(cs, D_RCVBUFREADY);
465 }
466 } while (--count && skb);
467
468 test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
469 return (1);
470}
471
472/**********************************/
473/* B-channel main receive routine */
474/**********************************/
475void
476main_rec_hfcsx(struct BCState *bcs)
477{
478 struct IsdnCardState *cs = bcs->cs;
479 int count = 5;
480 struct sk_buff *skb;
481
482 Begin:
483 count--;
484 if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
485 debugl1(cs, "rec_data %d blocked", bcs->channel);
486 return;
487 }
488 skb = read_fifo(cs, ((bcs->channel) && (!cs->hw.hfcsx.bswapped)) ?
489 HFCSX_SEL_B2_RX : HFCSX_SEL_B1_RX,
490 (bcs->mode == L1_MODE_TRANS) ?
491 HFCSX_BTRANS_THRESHOLD : 0);
492
493 if (skb) {
494 skb_queue_tail(&bcs->rqueue, skb);
495 schedule_event(bcs, B_RCVBUFREADY);
496 }
497
498 test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
499 if (count && skb)
500 goto Begin;
501 return;
502}
503
504/**************************/
505/* D-channel send routine */
506/**************************/
507static void
508hfcsx_fill_dfifo(struct IsdnCardState *cs)
509{
510 if (!cs->tx_skb)
511 return;
512 if (cs->tx_skb->len <= 0)
513 return;
514
515 if (write_fifo(cs, cs->tx_skb, HFCSX_SEL_D_TX, 0)) {
516 dev_kfree_skb_any(cs->tx_skb);
517 cs->tx_skb = NULL;
518 }
519 return;
520}
521
522/**************************/
523/* B-channel send routine */
524/**************************/
525static void
526hfcsx_fill_fifo(struct BCState *bcs)
527{
528 struct IsdnCardState *cs = bcs->cs;
529
530 if (!bcs->tx_skb)
531 return;
532 if (bcs->tx_skb->len <= 0)
533 return;
534
535 if (write_fifo(cs, bcs->tx_skb,
536 ((bcs->channel) && (!cs->hw.hfcsx.bswapped)) ?
537 HFCSX_SEL_B2_TX : HFCSX_SEL_B1_TX,
538 (bcs->mode == L1_MODE_TRANS) ?
539 HFCSX_BTRANS_THRESHOLD : 0)) {
540
541 bcs->tx_cnt -= bcs->tx_skb->len;
542 if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) &&
543 (PACKET_NOACK != bcs->tx_skb->pkt_type)) {
544 u_long flags;
545 spin_lock_irqsave(&bcs->aclock, flags);
546 bcs->ackcnt += bcs->tx_skb->len;
547 spin_unlock_irqrestore(&bcs->aclock, flags);
548 schedule_event(bcs, B_ACKPENDING);
549 }
550 dev_kfree_skb_any(bcs->tx_skb);
551 bcs->tx_skb = NULL;
552 test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
553 }
554}
555
556/**********************************************/
557/* D-channel l1 state call for leased NT-mode */
558/**********************************************/
559static void
560dch_nt_l2l1(struct PStack *st, int pr, void *arg)
561{
562 struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
563
564 switch (pr) {
565 case (PH_DATA | REQUEST):
566 case (PH_PULL | REQUEST):
567 case (PH_PULL | INDICATION):
568 st->l1.l1hw(st, pr, arg);
569 break;
570 case (PH_ACTIVATE | REQUEST):
571 st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL);
572 break;
573 case (PH_TESTLOOP | REQUEST):
574 if (1 & (long) arg)
575 debugl1(cs, "PH_TEST_LOOP B1");
576 if (2 & (long) arg)
577 debugl1(cs, "PH_TEST_LOOP B2");
578 if (!(3 & (long) arg))
579 debugl1(cs, "PH_TEST_LOOP DISABLED");
580 st->l1.l1hw(st, HW_TESTLOOP | REQUEST, arg);
581 break;
582 default:
583 if (cs->debug)
584 debugl1(cs, "dch_nt_l2l1 msg %04X unhandled", pr);
585 break;
586 }
587}
588
589
590
591/***********************/
592/* set/reset echo mode */
593/***********************/
594static int
595hfcsx_auxcmd(struct IsdnCardState *cs, isdn_ctrl * ic)
596{
597 unsigned long flags;
598 int i = *(unsigned int *) ic->parm.num;
599
600 if ((ic->arg == 98) &&
601 (!(cs->hw.hfcsx.int_m1 & (HFCSX_INTS_B2TRANS + HFCSX_INTS_B2REC + HFCSX_INTS_B1TRANS + HFCSX_INTS_B1REC)))) {
602 spin_lock_irqsave(&cs->lock, flags);
603 Write_hfc(cs, HFCSX_STATES, HFCSX_LOAD_STATE | 0); /* HFC ST G0 */
604 udelay(10);
605 cs->hw.hfcsx.sctrl |= SCTRL_MODE_NT;
606 Write_hfc(cs, HFCSX_SCTRL, cs->hw.hfcsx.sctrl); /* set NT-mode */
607 udelay(10);
608 Write_hfc(cs, HFCSX_STATES, HFCSX_LOAD_STATE | 1); /* HFC ST G1 */
609 udelay(10);
610 Write_hfc(cs, HFCSX_STATES, 1 | HFCSX_ACTIVATE | HFCSX_DO_ACTION);
611 cs->dc.hfcsx.ph_state = 1;
612 cs->hw.hfcsx.nt_mode = 1;
613 cs->hw.hfcsx.nt_timer = 0;
614 spin_unlock_irqrestore(&cs->lock, flags);
615 cs->stlist->l2.l2l1 = dch_nt_l2l1;
616 debugl1(cs, "NT mode activated");
617 return (0);
618 }
619 if ((cs->chanlimit > 1) || (cs->hw.hfcsx.bswapped) ||
620 (cs->hw.hfcsx.nt_mode) || (ic->arg != 12))
621 return (-EINVAL);
622
623 if (i) {
624 cs->logecho = 1;
625 cs->hw.hfcsx.trm |= 0x20; /* enable echo chan */
626 cs->hw.hfcsx.int_m1 |= HFCSX_INTS_B2REC;
627 /* reset Channel !!!!! */
628 } else {
629 cs->logecho = 0;
630 cs->hw.hfcsx.trm &= ~0x20; /* disable echo chan */
631 cs->hw.hfcsx.int_m1 &= ~HFCSX_INTS_B2REC;
632 }
633 cs->hw.hfcsx.sctrl_r &= ~SCTRL_B2_ENA;
634 cs->hw.hfcsx.sctrl &= ~SCTRL_B2_ENA;
635 cs->hw.hfcsx.conn |= 0x10; /* B2-IOM -> B2-ST */
636 cs->hw.hfcsx.ctmt &= ~2;
637 spin_lock_irqsave(&cs->lock, flags);
638 Write_hfc(cs, HFCSX_CTMT, cs->hw.hfcsx.ctmt);
639 Write_hfc(cs, HFCSX_SCTRL_R, cs->hw.hfcsx.sctrl_r);
640 Write_hfc(cs, HFCSX_SCTRL, cs->hw.hfcsx.sctrl);
641 Write_hfc(cs, HFCSX_CONNECT, cs->hw.hfcsx.conn);
642 Write_hfc(cs, HFCSX_TRM, cs->hw.hfcsx.trm);
643 Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1);
644 spin_unlock_irqrestore(&cs->lock, flags);
645 return (0);
646} /* hfcsx_auxcmd */
647
648/*****************************/
649/* E-channel receive routine */
650/*****************************/
651static void
652receive_emsg(struct IsdnCardState *cs)
653{
654 int count = 5;
655 u_char *ptr;
656 struct sk_buff *skb;
657
658 if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
659 debugl1(cs, "echo_rec_data blocked");
660 return;
661 }
662 do {
663 skb = read_fifo(cs, HFCSX_SEL_B2_RX, 0);
664 if (skb) {
665 if (cs->debug & DEB_DLOG_HEX) {
666 ptr = cs->dlog;
667 if ((skb->len) < MAX_DLOG_SPACE / 3 - 10) {
668 *ptr++ = 'E';
669 *ptr++ = 'C';
670 *ptr++ = 'H';
671 *ptr++ = 'O';
672 *ptr++ = ':';
673 ptr += QuickHex(ptr, skb->data, skb->len);
674 ptr--;
675 *ptr++ = '\n';
676 *ptr = 0;
677 HiSax_putstatus(cs, NULL, cs->dlog);
678 } else
679 HiSax_putstatus(cs, "LogEcho: ", "warning Frame too big (%d)", skb->len);
680 }
681 dev_kfree_skb_any(skb);
682 }
683 } while (--count && skb);
684
685 test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
686 return;
687} /* receive_emsg */
688
689
690/*********************/
691/* Interrupt handler */
692/*********************/
693static irqreturn_t
694hfcsx_interrupt(int intno, void *dev_id, struct pt_regs *regs)
695{
696 struct IsdnCardState *cs = dev_id;
697 u_char exval;
698 struct BCState *bcs;
699 int count = 15;
700 u_long flags;
701 u_char val, stat;
702
703 if (!(cs->hw.hfcsx.int_m2 & 0x08))
704 return IRQ_NONE; /* not initialised */
705
706 spin_lock_irqsave(&cs->lock, flags);
707 if (HFCSX_ANYINT & (stat = Read_hfc(cs, HFCSX_STATUS))) {
708 val = Read_hfc(cs, HFCSX_INT_S1);
709 if (cs->debug & L1_DEB_ISAC)
710 debugl1(cs, "HFC-SX: stat(%02x) s1(%02x)", stat, val);
711 } else {
712 spin_unlock_irqrestore(&cs->lock, flags);
713 return IRQ_NONE;
714 }
715 if (cs->debug & L1_DEB_ISAC)
716 debugl1(cs, "HFC-SX irq %x %s", val,
717 test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags) ?
718 "locked" : "unlocked");
719 val &= cs->hw.hfcsx.int_m1;
720 if (val & 0x40) { /* state machine irq */
721 exval = Read_hfc(cs, HFCSX_STATES) & 0xf;
722 if (cs->debug & L1_DEB_ISAC)
723 debugl1(cs, "ph_state chg %d->%d", cs->dc.hfcsx.ph_state,
724 exval);
725 cs->dc.hfcsx.ph_state = exval;
726 schedule_event(cs, D_L1STATECHANGE);
727 val &= ~0x40;
728 }
729 if (val & 0x80) { /* timer irq */
730 if (cs->hw.hfcsx.nt_mode) {
731 if ((--cs->hw.hfcsx.nt_timer) < 0)
732 schedule_event(cs, D_L1STATECHANGE);
733 }
734 val &= ~0x80;
735 Write_hfc(cs, HFCSX_CTMT, cs->hw.hfcsx.ctmt | HFCSX_CLTIMER);
736 }
737 while (val) {
738 if (test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
739 cs->hw.hfcsx.int_s1 |= val;
740 spin_unlock_irqrestore(&cs->lock, flags);
741 return IRQ_HANDLED;
742 }
743 if (cs->hw.hfcsx.int_s1 & 0x18) {
744 exval = val;
745 val = cs->hw.hfcsx.int_s1;
746 cs->hw.hfcsx.int_s1 = exval;
747 }
748 if (val & 0x08) {
749 if (!(bcs = Sel_BCS(cs, cs->hw.hfcsx.bswapped ? 1 : 0))) {
750 if (cs->debug)
751 debugl1(cs, "hfcsx spurious 0x08 IRQ");
752 } else
753 main_rec_hfcsx(bcs);
754 }
755 if (val & 0x10) {
756 if (cs->logecho)
757 receive_emsg(cs);
758 else if (!(bcs = Sel_BCS(cs, 1))) {
759 if (cs->debug)
760 debugl1(cs, "hfcsx spurious 0x10 IRQ");
761 } else
762 main_rec_hfcsx(bcs);
763 }
764 if (val & 0x01) {
765 if (!(bcs = Sel_BCS(cs, cs->hw.hfcsx.bswapped ? 1 : 0))) {
766 if (cs->debug)
767 debugl1(cs, "hfcsx spurious 0x01 IRQ");
768 } else {
769 if (bcs->tx_skb) {
770 if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
771 hfcsx_fill_fifo(bcs);
772 test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
773 } else
774 debugl1(cs, "fill_data %d blocked", bcs->channel);
775 } else {
776 if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
777 if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
778 hfcsx_fill_fifo(bcs);
779 test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
780 } else
781 debugl1(cs, "fill_data %d blocked", bcs->channel);
782 } else {
783 schedule_event(bcs, B_XMTBUFREADY);
784 }
785 }
786 }
787 }
788 if (val & 0x02) {
789 if (!(bcs = Sel_BCS(cs, 1))) {
790 if (cs->debug)
791 debugl1(cs, "hfcsx spurious 0x02 IRQ");
792 } else {
793 if (bcs->tx_skb) {
794 if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
795 hfcsx_fill_fifo(bcs);
796 test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
797 } else
798 debugl1(cs, "fill_data %d blocked", bcs->channel);
799 } else {
800 if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
801 if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
802 hfcsx_fill_fifo(bcs);
803 test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
804 } else
805 debugl1(cs, "fill_data %d blocked", bcs->channel);
806 } else {
807 schedule_event(bcs, B_XMTBUFREADY);
808 }
809 }
810 }
811 }
812 if (val & 0x20) { /* receive dframe */
813 receive_dmsg(cs);
814 }
815 if (val & 0x04) { /* dframe transmitted */
816 if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
817 del_timer(&cs->dbusytimer);
818 if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
819 schedule_event(cs, D_CLEARBUSY);
820 if (cs->tx_skb) {
821 if (cs->tx_skb->len) {
822 if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
823 hfcsx_fill_dfifo(cs);
824 test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
825 } else {
826 debugl1(cs, "hfcsx_fill_dfifo irq blocked");
827 }
828 goto afterXPR;
829 } else {
830 dev_kfree_skb_irq(cs->tx_skb);
831 cs->tx_cnt = 0;
832 cs->tx_skb = NULL;
833 }
834 }
835 if ((cs->tx_skb = skb_dequeue(&cs->sq))) {
836 cs->tx_cnt = 0;
837 if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
838 hfcsx_fill_dfifo(cs);
839 test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
840 } else {
841 debugl1(cs, "hfcsx_fill_dfifo irq blocked");
842 }
843 } else
844 schedule_event(cs, D_XMTBUFREADY);
845 }
846 afterXPR:
847 if (cs->hw.hfcsx.int_s1 && count--) {
848 val = cs->hw.hfcsx.int_s1;
849 cs->hw.hfcsx.int_s1 = 0;
850 if (cs->debug & L1_DEB_ISAC)
851 debugl1(cs, "HFC-SX irq %x loop %d", val, 15 - count);
852 } else
853 val = 0;
854 }
855 spin_unlock_irqrestore(&cs->lock, flags);
856 return IRQ_HANDLED;
857}
858
859/********************************************************************/
860/* timer callback for D-chan busy resolution. Currently no function */
861/********************************************************************/
862static void
863hfcsx_dbusy_timer(struct IsdnCardState *cs)
864{
865}
866
867/*************************************/
868/* Layer 1 D-channel hardware access */
869/*************************************/
870static void
871HFCSX_l1hw(struct PStack *st, int pr, void *arg)
872{
873 struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
874 struct sk_buff *skb = arg;
875 u_long flags;
876
877 switch (pr) {
878 case (PH_DATA | REQUEST):
879 if (cs->debug & DEB_DLOG_HEX)
880 LogFrame(cs, skb->data, skb->len);
881 if (cs->debug & DEB_DLOG_VERBOSE)
882 dlogframe(cs, skb, 0);
883 spin_lock_irqsave(&cs->lock, flags);
884 if (cs->tx_skb) {
885 skb_queue_tail(&cs->sq, skb);
886#ifdef L2FRAME_DEBUG /* psa */
887 if (cs->debug & L1_DEB_LAPD)
888 Logl2Frame(cs, skb, "PH_DATA Queued", 0);
889#endif
890 } else {
891 cs->tx_skb = skb;
892 cs->tx_cnt = 0;
893#ifdef L2FRAME_DEBUG /* psa */
894 if (cs->debug & L1_DEB_LAPD)
895 Logl2Frame(cs, skb, "PH_DATA", 0);
896#endif
897 if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
898 hfcsx_fill_dfifo(cs);
899 test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
900 } else
901 debugl1(cs, "hfcsx_fill_dfifo blocked");
902
903 }
904 spin_unlock_irqrestore(&cs->lock, flags);
905 break;
906 case (PH_PULL | INDICATION):
907 spin_lock_irqsave(&cs->lock, flags);
908 if (cs->tx_skb) {
909 if (cs->debug & L1_DEB_WARN)
910 debugl1(cs, " l2l1 tx_skb exist this shouldn't happen");
911 skb_queue_tail(&cs->sq, skb);
912 spin_unlock_irqrestore(&cs->lock, flags);
913 break;
914 }
915 if (cs->debug & DEB_DLOG_HEX)
916 LogFrame(cs, skb->data, skb->len);
917 if (cs->debug & DEB_DLOG_VERBOSE)
918 dlogframe(cs, skb, 0);
919 cs->tx_skb = skb;
920 cs->tx_cnt = 0;
921#ifdef L2FRAME_DEBUG /* psa */
922 if (cs->debug & L1_DEB_LAPD)
923 Logl2Frame(cs, skb, "PH_DATA_PULLED", 0);
924#endif
925 if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
926 hfcsx_fill_dfifo(cs);
927 test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
928 } else
929 debugl1(cs, "hfcsx_fill_dfifo blocked");
930 spin_unlock_irqrestore(&cs->lock, flags);
931 break;
932 case (PH_PULL | REQUEST):
933#ifdef L2FRAME_DEBUG /* psa */
934 if (cs->debug & L1_DEB_LAPD)
935 debugl1(cs, "-> PH_REQUEST_PULL");
936#endif
937 if (!cs->tx_skb) {
938 test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
939 st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
940 } else
941 test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
942 break;
943 case (HW_RESET | REQUEST):
944 spin_lock_irqsave(&cs->lock, flags);
945 Write_hfc(cs, HFCSX_STATES, HFCSX_LOAD_STATE | 3); /* HFC ST 3 */
946 udelay(6);
947 Write_hfc(cs, HFCSX_STATES, 3); /* HFC ST 2 */
948 cs->hw.hfcsx.mst_m |= HFCSX_MASTER;
949 Write_hfc(cs, HFCSX_MST_MODE, cs->hw.hfcsx.mst_m);
950 Write_hfc(cs, HFCSX_STATES, HFCSX_ACTIVATE | HFCSX_DO_ACTION);
951 spin_unlock_irqrestore(&cs->lock, flags);
952 l1_msg(cs, HW_POWERUP | CONFIRM, NULL);
953 break;
954 case (HW_ENABLE | REQUEST):
955 spin_lock_irqsave(&cs->lock, flags);
956 Write_hfc(cs, HFCSX_STATES, HFCSX_ACTIVATE | HFCSX_DO_ACTION);
957 spin_unlock_irqrestore(&cs->lock, flags);
958 break;
959 case (HW_DEACTIVATE | REQUEST):
960 spin_lock_irqsave(&cs->lock, flags);
961 cs->hw.hfcsx.mst_m &= ~HFCSX_MASTER;
962 Write_hfc(cs, HFCSX_MST_MODE, cs->hw.hfcsx.mst_m);
963 spin_unlock_irqrestore(&cs->lock, flags);
964 break;
965 case (HW_INFO3 | REQUEST):
966 spin_lock_irqsave(&cs->lock, flags);
967 cs->hw.hfcsx.mst_m |= HFCSX_MASTER;
968 Write_hfc(cs, HFCSX_MST_MODE, cs->hw.hfcsx.mst_m);
969 spin_unlock_irqrestore(&cs->lock, flags);
970 break;
971 case (HW_TESTLOOP | REQUEST):
972 spin_lock_irqsave(&cs->lock, flags);
973 switch ((int) arg) {
974 case (1):
975 Write_hfc(cs, HFCSX_B1_SSL, 0x80); /* tx slot */
976 Write_hfc(cs, HFCSX_B1_RSL, 0x80); /* rx slot */
977 cs->hw.hfcsx.conn = (cs->hw.hfcsx.conn & ~7) | 1;
978 Write_hfc(cs, HFCSX_CONNECT, cs->hw.hfcsx.conn);
979 break;
980 case (2):
981 Write_hfc(cs, HFCSX_B2_SSL, 0x81); /* tx slot */
982 Write_hfc(cs, HFCSX_B2_RSL, 0x81); /* rx slot */
983 cs->hw.hfcsx.conn = (cs->hw.hfcsx.conn & ~0x38) | 0x08;
984 Write_hfc(cs, HFCSX_CONNECT, cs->hw.hfcsx.conn);
985 break;
986 default:
987 spin_unlock_irqrestore(&cs->lock, flags);
988 if (cs->debug & L1_DEB_WARN)
989 debugl1(cs, "hfcsx_l1hw loop invalid %4x", (int) arg);
990 return;
991 }
992 cs->hw.hfcsx.trm |= 0x80; /* enable IOM-loop */
993 Write_hfc(cs, HFCSX_TRM, cs->hw.hfcsx.trm);
994 spin_unlock_irqrestore(&cs->lock, flags);
995 break;
996 default:
997 if (cs->debug & L1_DEB_WARN)
998 debugl1(cs, "hfcsx_l1hw unknown pr %4x", pr);
999 break;
1000 }
1001}
1002
1003/***********************************************/
1004/* called during init setting l1 stack pointer */
1005/***********************************************/
1006void
1007setstack_hfcsx(struct PStack *st, struct IsdnCardState *cs)
1008{
1009 st->l1.l1hw = HFCSX_l1hw;
1010}
1011
1012/**************************************/
1013/* send B-channel data if not blocked */
1014/**************************************/
1015static void
1016hfcsx_send_data(struct BCState *bcs)
1017{
1018 struct IsdnCardState *cs = bcs->cs;
1019
1020 if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
1021 hfcsx_fill_fifo(bcs);
1022 test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
1023 } else
1024 debugl1(cs, "send_data %d blocked", bcs->channel);
1025}
1026
1027/***************************************************************/
1028/* activate/deactivate hardware for selected channels and mode */
1029/***************************************************************/
1030void
1031mode_hfcsx(struct BCState *bcs, int mode, int bc)
1032{
1033 struct IsdnCardState *cs = bcs->cs;
1034 int fifo2;
1035
1036 if (cs->debug & L1_DEB_HSCX)
1037 debugl1(cs, "HFCSX bchannel mode %d bchan %d/%d",
1038 mode, bc, bcs->channel);
1039 bcs->mode = mode;
1040 bcs->channel = bc;
1041 fifo2 = bc;
1042 if (cs->chanlimit > 1) {
1043 cs->hw.hfcsx.bswapped = 0; /* B1 and B2 normal mode */
1044 cs->hw.hfcsx.sctrl_e &= ~0x80;
1045 } else {
1046 if (bc) {
1047 if (mode != L1_MODE_NULL) {
1048 cs->hw.hfcsx.bswapped = 1; /* B1 and B2 exchanged */
1049 cs->hw.hfcsx.sctrl_e |= 0x80;
1050 } else {
1051 cs->hw.hfcsx.bswapped = 0; /* B1 and B2 normal mode */
1052 cs->hw.hfcsx.sctrl_e &= ~0x80;
1053 }
1054 fifo2 = 0;
1055 } else {
1056 cs->hw.hfcsx.bswapped = 0; /* B1 and B2 normal mode */
1057 cs->hw.hfcsx.sctrl_e &= ~0x80;
1058 }
1059 }
1060 switch (mode) {
1061 case (L1_MODE_NULL):
1062 if (bc) {
1063 cs->hw.hfcsx.sctrl &= ~SCTRL_B2_ENA;
1064 cs->hw.hfcsx.sctrl_r &= ~SCTRL_B2_ENA;
1065 } else {
1066 cs->hw.hfcsx.sctrl &= ~SCTRL_B1_ENA;
1067 cs->hw.hfcsx.sctrl_r &= ~SCTRL_B1_ENA;
1068 }
1069 if (fifo2) {
1070 cs->hw.hfcsx.int_m1 &= ~(HFCSX_INTS_B2TRANS + HFCSX_INTS_B2REC);
1071 } else {
1072 cs->hw.hfcsx.int_m1 &= ~(HFCSX_INTS_B1TRANS + HFCSX_INTS_B1REC);
1073 }
1074 break;
1075 case (L1_MODE_TRANS):
1076 if (bc) {
1077 cs->hw.hfcsx.sctrl |= SCTRL_B2_ENA;
1078 cs->hw.hfcsx.sctrl_r |= SCTRL_B2_ENA;
1079 } else {
1080 cs->hw.hfcsx.sctrl |= SCTRL_B1_ENA;
1081 cs->hw.hfcsx.sctrl_r |= SCTRL_B1_ENA;
1082 }
1083 if (fifo2) {
1084 cs->hw.hfcsx.int_m1 |= (HFCSX_INTS_B2TRANS + HFCSX_INTS_B2REC);
1085 cs->hw.hfcsx.ctmt |= 2;
1086 cs->hw.hfcsx.conn &= ~0x18;
1087 } else {
1088 cs->hw.hfcsx.int_m1 |= (HFCSX_INTS_B1TRANS + HFCSX_INTS_B1REC);
1089 cs->hw.hfcsx.ctmt |= 1;
1090 cs->hw.hfcsx.conn &= ~0x03;
1091 }
1092 break;
1093 case (L1_MODE_HDLC):
1094 if (bc) {
1095 cs->hw.hfcsx.sctrl |= SCTRL_B2_ENA;
1096 cs->hw.hfcsx.sctrl_r |= SCTRL_B2_ENA;
1097 } else {
1098 cs->hw.hfcsx.sctrl |= SCTRL_B1_ENA;
1099 cs->hw.hfcsx.sctrl_r |= SCTRL_B1_ENA;
1100 }
1101 if (fifo2) {
1102 cs->hw.hfcsx.int_m1 |= (HFCSX_INTS_B2TRANS + HFCSX_INTS_B2REC);
1103 cs->hw.hfcsx.ctmt &= ~2;
1104 cs->hw.hfcsx.conn &= ~0x18;
1105 } else {
1106 cs->hw.hfcsx.int_m1 |= (HFCSX_INTS_B1TRANS + HFCSX_INTS_B1REC);
1107 cs->hw.hfcsx.ctmt &= ~1;
1108 cs->hw.hfcsx.conn &= ~0x03;
1109 }
1110 break;
1111 case (L1_MODE_EXTRN):
1112 if (bc) {
1113 cs->hw.hfcsx.conn |= 0x10;
1114 cs->hw.hfcsx.sctrl |= SCTRL_B2_ENA;
1115 cs->hw.hfcsx.sctrl_r |= SCTRL_B2_ENA;
1116 cs->hw.hfcsx.int_m1 &= ~(HFCSX_INTS_B2TRANS + HFCSX_INTS_B2REC);
1117 } else {
1118 cs->hw.hfcsx.conn |= 0x02;
1119 cs->hw.hfcsx.sctrl |= SCTRL_B1_ENA;
1120 cs->hw.hfcsx.sctrl_r |= SCTRL_B1_ENA;
1121 cs->hw.hfcsx.int_m1 &= ~(HFCSX_INTS_B1TRANS + HFCSX_INTS_B1REC);
1122 }
1123 break;
1124 }
1125 Write_hfc(cs, HFCSX_SCTRL_E, cs->hw.hfcsx.sctrl_e);
1126 Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1);
1127 Write_hfc(cs, HFCSX_SCTRL, cs->hw.hfcsx.sctrl);
1128 Write_hfc(cs, HFCSX_SCTRL_R, cs->hw.hfcsx.sctrl_r);
1129 Write_hfc(cs, HFCSX_CTMT, cs->hw.hfcsx.ctmt);
1130 Write_hfc(cs, HFCSX_CONNECT, cs->hw.hfcsx.conn);
1131 if (mode != L1_MODE_EXTRN) {
1132 reset_fifo(cs, fifo2 ? HFCSX_SEL_B2_RX : HFCSX_SEL_B1_RX);
1133 reset_fifo(cs, fifo2 ? HFCSX_SEL_B2_TX : HFCSX_SEL_B1_TX);
1134 }
1135}
1136
1137/******************************/
1138/* Layer2 -> Layer 1 Transfer */
1139/******************************/
1140static void
1141hfcsx_l2l1(struct PStack *st, int pr, void *arg)
1142{
1143 struct BCState *bcs = st->l1.bcs;
1144 struct sk_buff *skb = arg;
1145 u_long flags;
1146
1147 switch (pr) {
1148 case (PH_DATA | REQUEST):
1149 spin_lock_irqsave(&bcs->cs->lock, flags);
1150 if (bcs->tx_skb) {
1151 skb_queue_tail(&bcs->squeue, skb);
1152 } else {
1153 bcs->tx_skb = skb;
1154// test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
1155 bcs->cs->BC_Send_Data(bcs);
1156 }
1157 spin_unlock_irqrestore(&bcs->cs->lock, flags);
1158 break;
1159 case (PH_PULL | INDICATION):
1160 spin_lock_irqsave(&bcs->cs->lock, flags);
1161 if (bcs->tx_skb) {
1162 printk(KERN_WARNING "hfc_l2l1: this shouldn't happen\n");
1163 } else {
1164// test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
1165 bcs->tx_skb = skb;
1166 bcs->cs->BC_Send_Data(bcs);
1167 }
1168 spin_unlock_irqrestore(&bcs->cs->lock, flags);
1169 break;
1170 case (PH_PULL | REQUEST):
1171 if (!bcs->tx_skb) {
1172 test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
1173 st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
1174 } else
1175 test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
1176 break;
1177 case (PH_ACTIVATE | REQUEST):
1178 spin_lock_irqsave(&bcs->cs->lock, flags);
1179 test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag);
1180 mode_hfcsx(bcs, st->l1.mode, st->l1.bc);
1181 spin_unlock_irqrestore(&bcs->cs->lock, flags);
1182 l1_msg_b(st, pr, arg);
1183 break;
1184 case (PH_DEACTIVATE | REQUEST):
1185 l1_msg_b(st, pr, arg);
1186 break;
1187 case (PH_DEACTIVATE | CONFIRM):
1188 spin_lock_irqsave(&bcs->cs->lock, flags);
1189 test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag);
1190 test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
1191 mode_hfcsx(bcs, 0, st->l1.bc);
1192 spin_unlock_irqrestore(&bcs->cs->lock, flags);
1193 st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
1194 break;
1195 }
1196}
1197
1198/******************************************/
1199/* deactivate B-channel access and queues */
1200/******************************************/
1201static void
1202close_hfcsx(struct BCState *bcs)
1203{
1204 mode_hfcsx(bcs, 0, bcs->channel);
1205 if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) {
1206 skb_queue_purge(&bcs->rqueue);
1207 skb_queue_purge(&bcs->squeue);
1208 if (bcs->tx_skb) {
1209 dev_kfree_skb_any(bcs->tx_skb);
1210 bcs->tx_skb = NULL;
1211 test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
1212 }
1213 }
1214}
1215
1216/*************************************/
1217/* init B-channel queues and control */
1218/*************************************/
1219static int
1220open_hfcsxstate(struct IsdnCardState *cs, struct BCState *bcs)
1221{
1222 if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
1223 skb_queue_head_init(&bcs->rqueue);
1224 skb_queue_head_init(&bcs->squeue);
1225 }
1226 bcs->tx_skb = NULL;
1227 test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
1228 bcs->event = 0;
1229 bcs->tx_cnt = 0;
1230 return (0);
1231}
1232
1233/*********************************/
1234/* inits the stack for B-channel */
1235/*********************************/
1236static int
1237setstack_2b(struct PStack *st, struct BCState *bcs)
1238{
1239 bcs->channel = st->l1.bc;
1240 if (open_hfcsxstate(st->l1.hardware, bcs))
1241 return (-1);
1242 st->l1.bcs = bcs;
1243 st->l2.l2l1 = hfcsx_l2l1;
1244 setstack_manager(st);
1245 bcs->st = st;
1246 setstack_l1_B(st);
1247 return (0);
1248}
1249
1250/***************************/
1251/* handle L1 state changes */
1252/***************************/
1253static void
1254hfcsx_bh(struct IsdnCardState *cs)
1255{
1256 u_long flags;
1257
1258 if (!cs)
1259 return;
1260 if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) {
1261 if (!cs->hw.hfcsx.nt_mode)
1262 switch (cs->dc.hfcsx.ph_state) {
1263 case (0):
1264 l1_msg(cs, HW_RESET | INDICATION, NULL);
1265 break;
1266 case (3):
1267 l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL);
1268 break;
1269 case (8):
1270 l1_msg(cs, HW_RSYNC | INDICATION, NULL);
1271 break;
1272 case (6):
1273 l1_msg(cs, HW_INFO2 | INDICATION, NULL);
1274 break;
1275 case (7):
1276 l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
1277 break;
1278 default:
1279 break;
1280 } else {
1281 switch (cs->dc.hfcsx.ph_state) {
1282 case (2):
1283 spin_lock_irqsave(&cs->lock, flags);
1284 if (cs->hw.hfcsx.nt_timer < 0) {
1285 cs->hw.hfcsx.nt_timer = 0;
1286 cs->hw.hfcsx.int_m1 &= ~HFCSX_INTS_TIMER;
1287 Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1);
1288 /* Clear already pending ints */
1289 if (Read_hfc(cs, HFCSX_INT_S1));
1290
1291 Write_hfc(cs, HFCSX_STATES, 4 | HFCSX_LOAD_STATE);
1292 udelay(10);
1293 Write_hfc(cs, HFCSX_STATES, 4);
1294 cs->dc.hfcsx.ph_state = 4;
1295 } else {
1296 cs->hw.hfcsx.int_m1 |= HFCSX_INTS_TIMER;
1297 Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1);
1298 cs->hw.hfcsx.ctmt &= ~HFCSX_AUTO_TIMER;
1299 cs->hw.hfcsx.ctmt |= HFCSX_TIM3_125;
1300 Write_hfc(cs, HFCSX_CTMT, cs->hw.hfcsx.ctmt | HFCSX_CLTIMER);
1301 Write_hfc(cs, HFCSX_CTMT, cs->hw.hfcsx.ctmt | HFCSX_CLTIMER);
1302 cs->hw.hfcsx.nt_timer = NT_T1_COUNT;
1303 Write_hfc(cs, HFCSX_STATES, 2 | HFCSX_NT_G2_G3); /* allow G2 -> G3 transition */
1304 }
1305 spin_unlock_irqrestore(&cs->lock, flags);
1306 break;
1307 case (1):
1308 case (3):
1309 case (4):
1310 spin_lock_irqsave(&cs->lock, flags);
1311 cs->hw.hfcsx.nt_timer = 0;
1312 cs->hw.hfcsx.int_m1 &= ~HFCSX_INTS_TIMER;
1313 Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1);
1314 spin_unlock_irqrestore(&cs->lock, flags);
1315 break;
1316 default:
1317 break;
1318 }
1319 }
1320 }
1321 if (test_and_clear_bit(D_RCVBUFREADY, &cs->event))
1322 DChannel_proc_rcv(cs);
1323 if (test_and_clear_bit(D_XMTBUFREADY, &cs->event))
1324 DChannel_proc_xmt(cs);
1325}
1326
1327
1328/********************************/
1329/* called for card init message */
1330/********************************/
1331void __devinit
1332inithfcsx(struct IsdnCardState *cs)
1333{
1334 cs->setstack_d = setstack_hfcsx;
1335 cs->BC_Send_Data = &hfcsx_send_data;
1336 cs->bcs[0].BC_SetStack = setstack_2b;
1337 cs->bcs[1].BC_SetStack = setstack_2b;
1338 cs->bcs[0].BC_Close = close_hfcsx;
1339 cs->bcs[1].BC_Close = close_hfcsx;
1340 mode_hfcsx(cs->bcs, 0, 0);
1341 mode_hfcsx(cs->bcs + 1, 0, 1);
1342}
1343
1344
1345
1346/*******************************************/
1347/* handle card messages from control layer */
1348/*******************************************/
1349static int
1350hfcsx_card_msg(struct IsdnCardState *cs, int mt, void *arg)
1351{
1352 u_long flags;
1353
1354 if (cs->debug & L1_DEB_ISAC)
1355 debugl1(cs, "HFCSX: card_msg %x", mt);
1356 switch (mt) {
1357 case CARD_RESET:
1358 spin_lock_irqsave(&cs->lock, flags);
1359 reset_hfcsx(cs);
1360 spin_unlock_irqrestore(&cs->lock, flags);
1361 return (0);
1362 case CARD_RELEASE:
1363 release_io_hfcsx(cs);
1364 return (0);
1365 case CARD_INIT:
1366 spin_lock_irqsave(&cs->lock, flags);
1367 inithfcsx(cs);
1368 spin_unlock_irqrestore(&cs->lock, flags);
1369 msleep(80); /* Timeout 80ms */
1370 /* now switch timer interrupt off */
1371 spin_lock_irqsave(&cs->lock, flags);
1372 cs->hw.hfcsx.int_m1 &= ~HFCSX_INTS_TIMER;
1373 Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1);
1374 /* reinit mode reg */
1375 Write_hfc(cs, HFCSX_MST_MODE, cs->hw.hfcsx.mst_m);
1376 spin_unlock_irqrestore(&cs->lock, flags);
1377 return (0);
1378 case CARD_TEST:
1379 return (0);
1380 }
1381 return (0);
1382}
1383
1384#ifdef __ISAPNP__
1385static struct isapnp_device_id hfc_ids[] __devinitdata = {
1386 { ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2620),
1387 ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2620),
1388 (unsigned long) "Teles 16.3c2" },
1389 { 0, }
1390};
1391
1392static struct isapnp_device_id *ipid __devinitdata = &hfc_ids[0];
1393static struct pnp_card *pnp_c __devinitdata = NULL;
1394#endif
1395
1396int __devinit
1397setup_hfcsx(struct IsdnCard *card)
1398{
1399 struct IsdnCardState *cs = card->cs;
1400 char tmp[64];
1401
1402 strcpy(tmp, hfcsx_revision);
1403 printk(KERN_INFO "HiSax: HFC-SX driver Rev. %s\n", HiSax_getrev(tmp));
1404#ifdef __ISAPNP__
1405 if (!card->para[1] && isapnp_present()) {
1406 struct pnp_dev *pnp_d;
1407 while(ipid->card_vendor) {
1408 if ((pnp_c = pnp_find_card(ipid->card_vendor,
1409 ipid->card_device, pnp_c))) {
1410 pnp_d = NULL;
1411 if ((pnp_d = pnp_find_dev(pnp_c,
1412 ipid->vendor, ipid->function, pnp_d))) {
1413 int err;
1414
1415 printk(KERN_INFO "HiSax: %s detected\n",
1416 (char *)ipid->driver_data);
1417 pnp_disable_dev(pnp_d);
1418 err = pnp_activate_dev(pnp_d);
1419 if (err<0) {
1420 printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
1421 __FUNCTION__, err);
1422 return(0);
1423 }
1424 card->para[1] = pnp_port_start(pnp_d, 0);
1425 card->para[0] = pnp_irq(pnp_d, 0);
1426 if (!card->para[0] || !card->para[1]) {
1427 printk(KERN_ERR "HFC PnP:some resources are missing %ld/%lx\n",
1428 card->para[0], card->para[1]);
1429 pnp_disable_dev(pnp_d);
1430 return(0);
1431 }
1432 break;
1433 } else {
1434 printk(KERN_ERR "HFC PnP: PnP error card found, no device\n");
1435 }
1436 }
1437 ipid++;
1438 pnp_c = NULL;
1439 }
1440 if (!ipid->card_vendor) {
1441 printk(KERN_INFO "HFC PnP: no ISAPnP card found\n");
1442 return(0);
1443 }
1444 }
1445#endif
1446 cs->hw.hfcsx.base = card->para[1] & 0xfffe;
1447 cs->irq = card->para[0];
1448 cs->hw.hfcsx.int_s1 = 0;
1449 cs->dc.hfcsx.ph_state = 0;
1450 cs->hw.hfcsx.fifo = 255;
1451 if ((cs->typ == ISDN_CTYPE_HFC_SX) ||
1452 (cs->typ == ISDN_CTYPE_HFC_SP_PCMCIA)) {
1453 if ((!cs->hw.hfcsx.base) || !request_region(cs->hw.hfcsx.base, 2, "HFCSX isdn")) {
1454 printk(KERN_WARNING
1455 "HiSax: HFC-SX io-base %#lx already in use\n",
1456 cs->hw.hfcsx.base);
1457 return(0);
1458 }
1459 byteout(cs->hw.hfcsx.base, cs->hw.hfcsx.base & 0xFF);
1460 byteout(cs->hw.hfcsx.base + 1,
1461 ((cs->hw.hfcsx.base >> 8) & 3) | 0x54);
1462 udelay(10);
1463 cs->hw.hfcsx.chip = Read_hfc(cs,HFCSX_CHIP_ID);
1464 switch (cs->hw.hfcsx.chip >> 4) {
1465 case 1:
1466 tmp[0] ='+';
1467 break;
1468 case 9:
1469 tmp[0] ='P';
1470 break;
1471 default:
1472 printk(KERN_WARNING
1473 "HFC-SX: invalid chip id 0x%x\n",
1474 cs->hw.hfcsx.chip >> 4);
1475 release_region(cs->hw.hfcsx.base, 2);
1476 return(0);
1477 }
1478 if (!ccd_sp_irqtab[cs->irq & 0xF]) {
1479 printk(KERN_WARNING
1480 "HFC_SX: invalid irq %d specified\n",cs->irq & 0xF);
1481 release_region(cs->hw.hfcsx.base, 2);
1482 return(0);
1483 }
1484 if (!(cs->hw.hfcsx.extra = (void *)
1485 kmalloc(sizeof(struct hfcsx_extra), GFP_ATOMIC))) {
1486 release_region(cs->hw.hfcsx.base, 2);
1487 printk(KERN_WARNING "HFC-SX: unable to allocate memory\n");
1488 return(0);
1489 }
1490 printk(KERN_INFO "HFC-S%c chip detected at base 0x%x IRQ %d HZ %d\n",
1491 tmp[0], (u_int) cs->hw.hfcsx.base, cs->irq, HZ);
1492 cs->hw.hfcsx.int_m2 = 0; /* disable alle interrupts */
1493 cs->hw.hfcsx.int_m1 = 0;
1494 Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1);
1495 Write_hfc(cs, HFCSX_INT_M2, cs->hw.hfcsx.int_m2);
1496 } else
1497 return (0); /* no valid card type */
1498
1499 cs->dbusytimer.function = (void *) hfcsx_dbusy_timer;
1500 cs->dbusytimer.data = (long) cs;
1501 init_timer(&cs->dbusytimer);
1502 INIT_WORK(&cs->tqueue, (void *)(void *) hfcsx_bh, cs);
1503 cs->readisac = NULL;
1504 cs->writeisac = NULL;
1505 cs->readisacfifo = NULL;
1506 cs->writeisacfifo = NULL;
1507 cs->BC_Read_Reg = NULL;
1508 cs->BC_Write_Reg = NULL;
1509 cs->irq_func = &hfcsx_interrupt;
1510
1511 cs->hw.hfcsx.timer.function = (void *) hfcsx_Timer;
1512 cs->hw.hfcsx.timer.data = (long) cs;
1513 cs->hw.hfcsx.b_fifo_size = 0; /* fifo size still unknown */
1514 cs->hw.hfcsx.cirm = ccd_sp_irqtab[cs->irq & 0xF]; /* RAM not evaluated */
1515 init_timer(&cs->hw.hfcsx.timer);
1516
1517 reset_hfcsx(cs);
1518 cs->cardmsg = &hfcsx_card_msg;
1519 cs->auxcmd = &hfcsx_auxcmd;
1520 return (1);
1521}
diff --git a/drivers/isdn/hisax/hfc_sx.h b/drivers/isdn/hisax/hfc_sx.h
new file mode 100644
index 000000000000..12f54159344a
--- /dev/null
+++ b/drivers/isdn/hisax/hfc_sx.h
@@ -0,0 +1,197 @@
1/* $Id: hfc_sx.h,v 1.2.6.1 2001/09/23 22:24:48 kai Exp $
2 *
3 * specific defines for CCD's HFC 2BDS0 S+,SP chips
4 *
5 * Author Werner Cornelius
6 * based on existing driver for CCD HFC PCI cards
7 * Copyright by Werner Cornelius <werner@isdn4linux.de>
8 *
9 * This software may be used and distributed according to the terms
10 * of the GNU General Public License, incorporated herein by reference.
11 *
12 */
13
14/*********************************************/
15/* thresholds for transparent B-channel mode */
16/* change mask and threshold simultaneously */
17/*********************************************/
18#define HFCSX_BTRANS_THRESHOLD 128
19#define HFCSX_BTRANS_THRESMASK 0x00
20
21/* GCI/IOM bus monitor registers */
22
23#define HFCSX_C_I 0x02
24#define HFCSX_TRxR 0x03
25#define HFCSX_MON1_D 0x0A
26#define HFCSX_MON2_D 0x0B
27
28
29/* GCI/IOM bus timeslot registers */
30
31#define HFCSX_B1_SSL 0x20
32#define HFCSX_B2_SSL 0x21
33#define HFCSX_AUX1_SSL 0x22
34#define HFCSX_AUX2_SSL 0x23
35#define HFCSX_B1_RSL 0x24
36#define HFCSX_B2_RSL 0x25
37#define HFCSX_AUX1_RSL 0x26
38#define HFCSX_AUX2_RSL 0x27
39
40/* GCI/IOM bus data registers */
41
42#define HFCSX_B1_D 0x28
43#define HFCSX_B2_D 0x29
44#define HFCSX_AUX1_D 0x2A
45#define HFCSX_AUX2_D 0x2B
46
47/* GCI/IOM bus configuration registers */
48
49#define HFCSX_MST_EMOD 0x2D
50#define HFCSX_MST_MODE 0x2E
51#define HFCSX_CONNECT 0x2F
52
53
54/* Interrupt and status registers */
55
56#define HFCSX_TRM 0x12
57#define HFCSX_B_MODE 0x13
58#define HFCSX_CHIP_ID 0x16
59#define HFCSX_CIRM 0x18
60#define HFCSX_CTMT 0x19
61#define HFCSX_INT_M1 0x1A
62#define HFCSX_INT_M2 0x1B
63#define HFCSX_INT_S1 0x1E
64#define HFCSX_INT_S2 0x1F
65#define HFCSX_STATUS 0x1C
66
67/* S/T section registers */
68
69#define HFCSX_STATES 0x30
70#define HFCSX_SCTRL 0x31
71#define HFCSX_SCTRL_E 0x32
72#define HFCSX_SCTRL_R 0x33
73#define HFCSX_SQ 0x34
74#define HFCSX_CLKDEL 0x37
75#define HFCSX_B1_REC 0x3C
76#define HFCSX_B1_SEND 0x3C
77#define HFCSX_B2_REC 0x3D
78#define HFCSX_B2_SEND 0x3D
79#define HFCSX_D_REC 0x3E
80#define HFCSX_D_SEND 0x3E
81#define HFCSX_E_REC 0x3F
82
83/****************/
84/* FIFO section */
85/****************/
86#define HFCSX_FIF_SEL 0x10
87#define HFCSX_FIF_Z1L 0x80
88#define HFCSX_FIF_Z1H 0x84
89#define HFCSX_FIF_Z2L 0x88
90#define HFCSX_FIF_Z2H 0x8C
91#define HFCSX_FIF_INCF1 0xA8
92#define HFCSX_FIF_DWR 0xAC
93#define HFCSX_FIF_F1 0xB0
94#define HFCSX_FIF_F2 0xB4
95#define HFCSX_FIF_INCF2 0xB8
96#define HFCSX_FIF_DRD 0xBC
97
98/* bits in status register (READ) */
99#define HFCSX_SX_PROC 0x02
100#define HFCSX_NBUSY 0x04
101#define HFCSX_TIMER_ELAP 0x10
102#define HFCSX_STATINT 0x20
103#define HFCSX_FRAMEINT 0x40
104#define HFCSX_ANYINT 0x80
105
106/* bits in CTMT (Write) */
107#define HFCSX_CLTIMER 0x80
108#define HFCSX_TIM3_125 0x04
109#define HFCSX_TIM25 0x10
110#define HFCSX_TIM50 0x14
111#define HFCSX_TIM400 0x18
112#define HFCSX_TIM800 0x1C
113#define HFCSX_AUTO_TIMER 0x20
114#define HFCSX_TRANSB2 0x02
115#define HFCSX_TRANSB1 0x01
116
117/* bits in CIRM (Write) */
118#define HFCSX_IRQ_SELMSK 0x07
119#define HFCSX_IRQ_SELDIS 0x00
120#define HFCSX_RESET 0x08
121#define HFCSX_FIFO_RESET 0x80
122
123
124/* bits in INT_M1 and INT_S1 */
125#define HFCSX_INTS_B1TRANS 0x01
126#define HFCSX_INTS_B2TRANS 0x02
127#define HFCSX_INTS_DTRANS 0x04
128#define HFCSX_INTS_B1REC 0x08
129#define HFCSX_INTS_B2REC 0x10
130#define HFCSX_INTS_DREC 0x20
131#define HFCSX_INTS_L1STATE 0x40
132#define HFCSX_INTS_TIMER 0x80
133
134/* bits in INT_M2 */
135#define HFCSX_PROC_TRANS 0x01
136#define HFCSX_GCI_I_CHG 0x02
137#define HFCSX_GCI_MON_REC 0x04
138#define HFCSX_IRQ_ENABLE 0x08
139
140/* bits in STATES */
141#define HFCSX_STATE_MSK 0x0F
142#define HFCSX_LOAD_STATE 0x10
143#define HFCSX_ACTIVATE 0x20
144#define HFCSX_DO_ACTION 0x40
145#define HFCSX_NT_G2_G3 0x80
146
147/* bits in HFCD_MST_MODE */
148#define HFCSX_MASTER 0x01
149#define HFCSX_SLAVE 0x00
150/* remaining bits are for codecs control */
151
152/* bits in HFCD_SCTRL */
153#define SCTRL_B1_ENA 0x01
154#define SCTRL_B2_ENA 0x02
155#define SCTRL_MODE_TE 0x00
156#define SCTRL_MODE_NT 0x04
157#define SCTRL_LOW_PRIO 0x08
158#define SCTRL_SQ_ENA 0x10
159#define SCTRL_TEST 0x20
160#define SCTRL_NONE_CAP 0x40
161#define SCTRL_PWR_DOWN 0x80
162
163/* bits in SCTRL_E */
164#define HFCSX_AUTO_AWAKE 0x01
165#define HFCSX_DBIT_1 0x04
166#define HFCSX_IGNORE_COL 0x08
167#define HFCSX_CHG_B1_B2 0x80
168
169/**********************************/
170/* definitions for FIFO selection */
171/**********************************/
172#define HFCSX_SEL_D_RX 5
173#define HFCSX_SEL_D_TX 4
174#define HFCSX_SEL_B1_RX 1
175#define HFCSX_SEL_B1_TX 0
176#define HFCSX_SEL_B2_RX 3
177#define HFCSX_SEL_B2_TX 2
178
179#define MAX_D_FRAMES 15
180#define MAX_B_FRAMES 31
181#define B_SUB_VAL_32K 0x0200
182#define B_FIFO_SIZE_32K (0x2000 - B_SUB_VAL_32K)
183#define B_SUB_VAL_8K 0x1A00
184#define B_FIFO_SIZE_8K (0x2000 - B_SUB_VAL_8K)
185#define D_FIFO_SIZE 512
186#define D_FREG_MASK 0xF
187
188/************************************************************/
189/* structure holding additional dynamic data -> send marker */
190/************************************************************/
191struct hfcsx_extra {
192 unsigned short marker[2*(MAX_B_FRAMES+1) + (MAX_D_FRAMES+1)];
193};
194
195extern void main_irq_hfcsx(struct BCState *bcs);
196extern void inithfcsx(struct IsdnCardState *cs);
197extern void releasehfcsx(struct IsdnCardState *cs);
diff --git a/drivers/isdn/hisax/hfc_usb.c b/drivers/isdn/hisax/hfc_usb.c
new file mode 100644
index 000000000000..ffd74b84f502
--- /dev/null
+++ b/drivers/isdn/hisax/hfc_usb.c
@@ -0,0 +1,1828 @@
1/*
2 * hfc_usb.c
3 *
4 * $Id: hfc_usb.c,v 4.34 2005/01/26 17:25:53 martinb1 Exp $
5 *
6 * modular HiSax ISDN driver for Colognechip HFC-S USB chip
7 *
8 * Authors : Peter Sprenger (sprenger@moving-bytes.de)
9 * Martin Bachem (info@colognechip.com)
10 *
11 * based on the first hfc_usb driver of
12 * Werner Cornelius (werner@isdn-development.de)
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2, or (at your option)
17 * any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 *
28 * See Version Histroy at the bottom of this file
29 *
30*/
31
32#include <linux/types.h>
33#include <linux/stddef.h>
34#include <linux/timer.h>
35#include <linux/config.h>
36#include <linux/init.h>
37#include <linux/module.h>
38#include <linux/kernel_stat.h>
39#include <linux/usb.h>
40#include <linux/kernel.h>
41#include <linux/smp_lock.h>
42#include <linux/sched.h>
43#include "hisax.h"
44#include "hisax_if.h"
45#include "hfc_usb.h"
46
47/*
48* Version Information
49* (do not modify the CVS Makros $Revision: 4.34 $ and $Date: 2005/01/26 17:25:53 $ !)
50*/
51static const char *hfcusb_revision =
52 "Revision: 4.34 $ Date: 2005/01/26 17:25:53 $ ";
53
54/* Hisax debug support
55* use "modprobe debug=x" where x is bitfield of USB_DBG & ISDN_DBG
56*/
57#ifdef CONFIG_HISAX_DEBUG
58#include <linux/moduleparam.h>
59#define __debug_variable hfc_debug
60#include "hisax_debug.h"
61static u_int debug;
62module_param(debug, uint, 0);
63int hfc_debug;
64#endif
65
66
67/****************************************/
68/* data defining the devices to be used */
69/****************************************/
70static struct usb_device_id hfc_usb_idtab[] = {
71 {USB_DEVICE(0x0959, 0x2bd0)}, /* Colognechip USB eval TA */
72 {USB_DEVICE(0x0675, 0x1688)}, /* DrayTek miniVigor 128 USB ISDN TA */
73 {USB_DEVICE(0x07b0, 0x0007)}, /* Billion USB TA 2 */
74 {USB_DEVICE(0x0742, 0x2008)}, /* Stollmann USB TA */
75 {USB_DEVICE(0x0742, 0x2009)}, /* Aceex USB ISDN TA */
76 {USB_DEVICE(0x0742, 0x200A)}, /* OEM USB ISDN TA */
77 {USB_DEVICE(0x08e3, 0x0301)}, /* OliTec ISDN USB */
78 {USB_DEVICE(0x07fa, 0x0846)}, /* Bewan ISDN USB TA */
79 {USB_DEVICE(0x07fa, 0x0847)}, /* Djinn Numeris USB */
80 {USB_DEVICE(0x07b0, 0x0006)}, /* Twister ISDN USB TA */
81 {} /* end with an all-zeroes entry */
82};
83
84/* driver internal device specific data:
85* VendorID, ProductID, Devicename, LED_SCHEME,
86* LED's BitMask in HFCUSB_P_DATA Register : LED_USB, LED_S0, LED_B1, LED_B2
87*/
88vendor_data vdata[] = {
89 /* CologneChip Eval TA */
90 {0x0959, 0x2bd0, "ISDN USB TA (Cologne Chip HFC-S USB based)",
91 LED_OFF, {4, 0, 2, 1}
92 }
93 ,
94 /* DrayTek miniVigor 128 USB ISDN TA */
95 {0x0675, 0x1688, "DrayTek miniVigor 128 USB ISDN TA",
96 LED_SCHEME1, {1, 2, 0, 0}
97 }
98 ,
99 /* Billion TA */
100 {0x07b0, 0x0007, "Billion tiny USB ISDN TA 128",
101 LED_SCHEME1, {0x80, -64, -32, -16}
102 }
103 ,
104 /* Stollmann TA */
105 {0x0742, 0x2008, "Stollmann USB TA",
106 LED_SCHEME1, {4, 0, 2, 1}
107 }
108 ,
109 /* Aceex USB ISDN TA */
110 {0x0742, 0x2009, "Aceex USB ISDN TA",
111 LED_SCHEME1, {4, 0, 2, 1}
112 }
113 ,
114 /* OEM USB ISDN TA */
115 {0x0742, 0x200A, "OEM USB ISDN TA",
116 LED_SCHEME1, {4, 0, 2, 1}
117 }
118 ,
119 /* Olitec TA */
120 {0x08e3, 0x0301, "Olitec USB RNIS",
121 LED_SCHEME1, {2, 0, 1, 4}
122 }
123 ,
124 /* Bewan TA */
125 {0x07fa, 0x0846, "Bewan Modem RNIS USB",
126 LED_SCHEME1, {0x80, -64, -32, -16}
127 }
128 ,
129 /* Bewan TA */
130 {0x07fa, 0x0847, "Djinn Numeris USB",
131 LED_SCHEME1, {0x80, -64, -32, -16}
132 }
133 ,
134 /* Twister ISDN TA */
135 {0x07b0, 0x0006, "Twister ISDN TA",
136 LED_SCHEME1, {0x80, -64, -32, -16}
137 }
138 ,
139 {0, 0, 0} /* EOL element */
140};
141
142/***************************************************************/
143/* structure defining input+output fifos (interrupt/bulk mode) */
144/***************************************************************/
145struct usb_fifo; /* forward definition */
146typedef struct iso_urb_struct {
147 struct urb *purb;
148 __u8 buffer[ISO_BUFFER_SIZE]; /* buffer incoming/outgoing data */
149 struct usb_fifo *owner_fifo; /* pointer to owner fifo */
150} iso_urb_struct;
151
152
153struct hfcusb_data; /* forward definition */
154typedef struct usb_fifo {
155 int fifonum; /* fifo index attached to this structure */
156 int active; /* fifo is currently active */
157 struct hfcusb_data *hfc; /* pointer to main structure */
158 int pipe; /* address of endpoint */
159 __u8 usb_packet_maxlen; /* maximum length for usb transfer */
160 unsigned int max_size; /* maximum size of receive/send packet */
161 __u8 intervall; /* interrupt interval */
162 struct sk_buff *skbuff; /* actual used buffer */
163 struct urb *urb; /* transfer structure for usb routines */
164 __u8 buffer[128]; /* buffer incoming/outgoing data */
165 int bit_line; /* how much bits are in the fifo? */
166
167 volatile __u8 usb_transfer_mode; /* switched between ISO and INT */
168 iso_urb_struct iso[2]; /* need two urbs to have one always for pending */
169 struct hisax_if *hif; /* hisax interface */
170 int delete_flg; /* only delete skbuff once */
171 int last_urblen; /* remember length of last packet */
172
173} usb_fifo;
174
175/*********************************************/
176/* structure holding all data for one device */
177/*********************************************/
178typedef struct hfcusb_data {
179 /* HiSax Interface for loadable Layer1 drivers */
180 struct hisax_d_if d_if; /* see hisax_if.h */
181 struct hisax_b_if b_if[2]; /* see hisax_if.h */
182 int protocol;
183
184 struct usb_device *dev; /* our device */
185 int if_used; /* used interface number */
186 int alt_used; /* used alternate config */
187 int ctrl_paksize; /* control pipe packet size */
188 int ctrl_in_pipe, ctrl_out_pipe; /* handles for control pipe */
189 int cfg_used; /* configuration index used */
190 int vend_idx; /* vendor found */
191 int b_mode[2]; /* B-channel mode */
192 int l1_activated; /* layer 1 activated */
193 int disc_flag; /* TRUE if device was disonnected to avoid some USB actions */
194 int packet_size, iso_packet_size;
195
196 /* control pipe background handling */
197 ctrl_buft ctrl_buff[HFC_CTRL_BUFSIZE]; /* buffer holding queued data */
198 volatile int ctrl_in_idx, ctrl_out_idx, ctrl_cnt; /* input/output pointer + count */
199 struct urb *ctrl_urb; /* transfer structure for control channel */
200
201 struct usb_ctrlrequest ctrl_write; /* buffer for control write request */
202 struct usb_ctrlrequest ctrl_read; /* same for read request */
203
204 __u8 old_led_state, led_state, led_new_data, led_b_active;
205
206 volatile __u8 threshold_mask; /* threshold actually reported */
207 volatile __u8 bch_enables; /* or mask for sctrl_r and sctrl register values */
208
209 usb_fifo fifos[HFCUSB_NUM_FIFOS]; /* structure holding all fifo data */
210
211 volatile __u8 l1_state; /* actual l1 state */
212 struct timer_list t3_timer; /* timer 3 for activation/deactivation */
213 struct timer_list t4_timer; /* timer 4 for activation/deactivation */
214 struct timer_list led_timer; /* timer flashing leds */
215
216} hfcusb_data;
217
218
219static void collect_rx_frame(usb_fifo * fifo, __u8 * data, int len,
220 int finish);
221
222
223static inline const char *
224symbolic(struct hfcusb_symbolic_list list[], const int num)
225{
226 int i;
227 for (i = 0; list[i].name != NULL; i++)
228 if (list[i].num == num)
229 return (list[i].name);
230 return "<unkown>";
231}
232
233
234/******************************************************/
235/* start next background transfer for control channel */
236/******************************************************/
237static void
238ctrl_start_transfer(hfcusb_data * hfc)
239{
240 if (hfc->ctrl_cnt) {
241 hfc->ctrl_urb->pipe = hfc->ctrl_out_pipe;
242 hfc->ctrl_urb->setup_packet = (u_char *) & hfc->ctrl_write;
243 hfc->ctrl_urb->transfer_buffer = NULL;
244 hfc->ctrl_urb->transfer_buffer_length = 0;
245 hfc->ctrl_write.wIndex =
246 hfc->ctrl_buff[hfc->ctrl_out_idx].hfc_reg;
247 hfc->ctrl_write.wValue =
248 hfc->ctrl_buff[hfc->ctrl_out_idx].reg_val;
249
250 usb_submit_urb(hfc->ctrl_urb, GFP_ATOMIC); /* start transfer */
251 }
252} /* ctrl_start_transfer */
253
254/************************************/
255/* queue a control transfer request */
256/* return 0 on success. */
257/************************************/
258static int
259queue_control_request(hfcusb_data * hfc, __u8 reg, __u8 val, int action)
260{
261 ctrl_buft *buf;
262
263 if (hfc->ctrl_cnt >= HFC_CTRL_BUFSIZE)
264 return (1); /* no space left */
265 buf = &hfc->ctrl_buff[hfc->ctrl_in_idx]; /* pointer to new index */
266 buf->hfc_reg = reg;
267 buf->reg_val = val;
268 buf->action = action;
269 if (++hfc->ctrl_in_idx >= HFC_CTRL_BUFSIZE)
270 hfc->ctrl_in_idx = 0; /* pointer wrap */
271 if (++hfc->ctrl_cnt == 1)
272 ctrl_start_transfer(hfc);
273 return (0);
274} /* queue_control_request */
275
276static int
277control_action_handler(hfcusb_data * hfc, int reg, int val, int action)
278{
279 if (!action)
280 return (1); /* no action defined */
281 return (0);
282}
283
284/***************************************************************/
285/* control completion routine handling background control cmds */
286/***************************************************************/
287static void
288ctrl_complete(struct urb *urb, struct pt_regs *regs)
289{
290 hfcusb_data *hfc = (hfcusb_data *) urb->context;
291 ctrl_buft *buf;
292
293 urb->dev = hfc->dev;
294 if (hfc->ctrl_cnt) {
295 buf = &hfc->ctrl_buff[hfc->ctrl_out_idx];
296 control_action_handler(hfc, buf->hfc_reg, buf->reg_val,
297 buf->action);
298
299 hfc->ctrl_cnt--; /* decrement actual count */
300 if (++hfc->ctrl_out_idx >= HFC_CTRL_BUFSIZE)
301 hfc->ctrl_out_idx = 0; /* pointer wrap */
302
303 ctrl_start_transfer(hfc); /* start next transfer */
304 }
305} /* ctrl_complete */
306
307/***************************************************/
308/* write led data to auxport & invert if necessary */
309/***************************************************/
310static void
311write_led(hfcusb_data * hfc, __u8 led_state)
312{
313 if (led_state != hfc->old_led_state) {
314 hfc->old_led_state = led_state;
315 queue_control_request(hfc, HFCUSB_P_DATA, led_state, 1);
316 }
317}
318
319/**************************/
320/* handle LED bits */
321/**************************/
322static void
323set_led_bit(hfcusb_data * hfc, signed short led_bits, int unset)
324{
325 if (unset) {
326 if (led_bits < 0)
327 hfc->led_state |= abs(led_bits);
328 else
329 hfc->led_state &= ~led_bits;
330 } else {
331 if (led_bits < 0)
332 hfc->led_state &= ~abs(led_bits);
333 else
334 hfc->led_state |= led_bits;
335 }
336}
337
338/******************************************/
339/* invert B-channel LEDs if data is sent */
340/******************************************/
341static void
342led_timer(hfcusb_data * hfc)
343{
344 static int cnt = 0;
345
346 if (cnt) {
347 if (hfc->led_b_active & 1)
348 set_led_bit(hfc, vdata[hfc->vend_idx].led_bits[2],
349 0);
350 if (hfc->led_b_active & 2)
351 set_led_bit(hfc, vdata[hfc->vend_idx].led_bits[3],
352 0);
353 } else {
354 if (!(hfc->led_b_active & 1) || hfc->led_new_data & 1)
355 set_led_bit(hfc, vdata[hfc->vend_idx].led_bits[2],
356 1);
357 if (!(hfc->led_b_active & 2) || hfc->led_new_data & 2)
358 set_led_bit(hfc, vdata[hfc->vend_idx].led_bits[3],
359 1);
360 }
361
362 write_led(hfc, hfc->led_state);
363 hfc->led_new_data = 0;
364
365 cnt = !cnt;
366
367 /* restart 4 hz timer */
368 if (!timer_pending(&hfc->led_timer)) {
369 add_timer(&hfc->led_timer);
370 hfc->led_timer.expires = jiffies + (LED_TIME * HZ) / 1000;
371 }
372}
373
374/**************************/
375/* handle LED requests */
376/**************************/
377static void
378handle_led(hfcusb_data * hfc, int event)
379{
380 /* if no scheme -> no LED action */
381 if (vdata[hfc->vend_idx].led_scheme == LED_OFF)
382 return;
383
384 switch (event) {
385 case LED_POWER_ON:
386 set_led_bit(hfc, vdata[hfc->vend_idx].led_bits[0],
387 0);
388 set_led_bit(hfc, vdata[hfc->vend_idx].led_bits[1],
389 1);
390 set_led_bit(hfc, vdata[hfc->vend_idx].led_bits[2],
391 1);
392 set_led_bit(hfc, vdata[hfc->vend_idx].led_bits[3],
393 1);
394 break;
395 case LED_POWER_OFF: /* no Power off handling */
396 break;
397 case LED_S0_ON:
398 set_led_bit(hfc, vdata[hfc->vend_idx].led_bits[1],
399 0);
400 break;
401 case LED_S0_OFF:
402 set_led_bit(hfc, vdata[hfc->vend_idx].led_bits[1],
403 1);
404 break;
405 case LED_B1_ON:
406 hfc->led_b_active |= 1;
407 break;
408 case LED_B1_OFF:
409 hfc->led_b_active &= ~1;
410 break;
411 case LED_B1_DATA:
412 hfc->led_new_data |= 1;
413 break;
414 case LED_B2_ON:
415 hfc->led_b_active |= 2;
416 break;
417 case LED_B2_OFF:
418 hfc->led_b_active &= ~2;
419 break;
420 case LED_B2_DATA:
421 hfc->led_new_data |= 2;
422 break;
423 }
424
425 write_led(hfc, hfc->led_state);
426}
427
428/********************************/
429/* called when timer t3 expires */
430/********************************/
431static void
432l1_timer_expire_t3(hfcusb_data * hfc)
433{
434 hfc->d_if.ifc.l1l2(&hfc->d_if.ifc, PH_DEACTIVATE | INDICATION,
435 NULL);
436#ifdef CONFIG_HISAX_DEBUG
437 DBG(ISDN_DBG,
438 "HFC-S USB: PH_DEACTIVATE | INDICATION sent (T3 expire)");
439#endif
440 hfc->l1_activated = FALSE;
441 handle_led(hfc, LED_S0_OFF);
442 /* deactivate : */
443 queue_control_request(hfc, HFCUSB_STATES, 0x10, 1);
444 queue_control_request(hfc, HFCUSB_STATES, 3, 1);
445}
446
447/********************************/
448/* called when timer t4 expires */
449/********************************/
450static void
451l1_timer_expire_t4(hfcusb_data * hfc)
452{
453 hfc->d_if.ifc.l1l2(&hfc->d_if.ifc, PH_DEACTIVATE | INDICATION,
454 NULL);
455#ifdef CONFIG_HISAX_DEBUG
456 DBG(ISDN_DBG,
457 "HFC-S USB: PH_DEACTIVATE | INDICATION sent (T4 expire)");
458#endif
459 hfc->l1_activated = FALSE;
460 handle_led(hfc, LED_S0_OFF);
461}
462
463/*****************************/
464/* handle S0 state changes */
465/*****************************/
466static void
467state_handler(hfcusb_data * hfc, __u8 state)
468{
469 __u8 old_state;
470
471 old_state = hfc->l1_state;
472 if (state == old_state || state < 1 || state > 8)
473 return;
474
475#ifdef CONFIG_HISAX_DEBUG
476 DBG(ISDN_DBG, "HFC-S USB: new S0 state:%d old_state:%d", state,
477 old_state);
478#endif
479 if (state < 4 || state == 7 || state == 8) {
480 if (timer_pending(&hfc->t3_timer))
481 del_timer(&hfc->t3_timer);
482#ifdef CONFIG_HISAX_DEBUG
483 DBG(ISDN_DBG, "HFC-S USB: T3 deactivated");
484#endif
485 }
486 if (state >= 7) {
487 if (timer_pending(&hfc->t4_timer))
488 del_timer(&hfc->t4_timer);
489#ifdef CONFIG_HISAX_DEBUG
490 DBG(ISDN_DBG, "HFC-S USB: T4 deactivated");
491#endif
492 }
493
494 if (state == 7 && !hfc->l1_activated) {
495 hfc->d_if.ifc.l1l2(&hfc->d_if.ifc,
496 PH_ACTIVATE | INDICATION, NULL);
497#ifdef CONFIG_HISAX_DEBUG
498 DBG(ISDN_DBG, "HFC-S USB: PH_ACTIVATE | INDICATION sent");
499#endif
500 hfc->l1_activated = TRUE;
501 handle_led(hfc, LED_S0_ON);
502 } else if (state <= 3 /* && activated */ ) {
503 if (old_state == 7 || old_state == 8) {
504#ifdef CONFIG_HISAX_DEBUG
505 DBG(ISDN_DBG, "HFC-S USB: T4 activated");
506#endif
507 if (!timer_pending(&hfc->t4_timer)) {
508 hfc->t4_timer.expires =
509 jiffies + (HFC_TIMER_T4 * HZ) / 1000;
510 add_timer(&hfc->t4_timer);
511 }
512 } else {
513 hfc->d_if.ifc.l1l2(&hfc->d_if.ifc,
514 PH_DEACTIVATE | INDICATION,
515 NULL);
516#ifdef CONFIG_HISAX_DEBUG
517 DBG(ISDN_DBG,
518 "HFC-S USB: PH_DEACTIVATE | INDICATION sent");
519#endif
520 hfc->l1_activated = FALSE;
521 handle_led(hfc, LED_S0_OFF);
522 }
523 }
524 hfc->l1_state = state;
525}
526
527/* prepare iso urb */
528static void
529fill_isoc_urb(struct urb *urb, struct usb_device *dev, unsigned int pipe,
530 void *buf, int num_packets, int packet_size, int interval,
531 usb_complete_t complete, void *context)
532{
533 int k;
534
535 spin_lock_init(&urb->lock);
536 urb->dev = dev;
537 urb->pipe = pipe;
538 urb->complete = complete;
539 urb->number_of_packets = num_packets;
540 urb->transfer_buffer_length = packet_size * num_packets;
541 urb->context = context;
542 urb->transfer_buffer = buf;
543 urb->transfer_flags = URB_ISO_ASAP;
544 urb->actual_length = 0;
545 urb->interval = interval;
546 for (k = 0; k < num_packets; k++) {
547 urb->iso_frame_desc[k].offset = packet_size * k;
548 urb->iso_frame_desc[k].length = packet_size;
549 urb->iso_frame_desc[k].actual_length = 0;
550 }
551}
552
553/* allocs urbs and start isoc transfer with two pending urbs to avoid
554 gaps in the transfer chain */
555static int
556start_isoc_chain(usb_fifo * fifo, int num_packets_per_urb,
557 usb_complete_t complete, int packet_size)
558{
559 int i, k, errcode;
560
561 printk(KERN_INFO "HFC-S USB: starting ISO-chain for Fifo %i\n",
562 fifo->fifonum);
563
564 /* allocate Memory for Iso out Urbs */
565 for (i = 0; i < 2; i++) {
566 if (!(fifo->iso[i].purb)) {
567 fifo->iso[i].purb =
568 usb_alloc_urb(num_packets_per_urb, GFP_KERNEL);
569 if (!(fifo->iso[i].purb)) {
570 printk(KERN_INFO
571 "alloc urb for fifo %i failed!!!",
572 fifo->fifonum);
573 }
574 fifo->iso[i].owner_fifo = (struct usb_fifo *) fifo;
575
576 /* Init the first iso */
577 if (ISO_BUFFER_SIZE >=
578 (fifo->usb_packet_maxlen *
579 num_packets_per_urb)) {
580 fill_isoc_urb(fifo->iso[i].purb,
581 fifo->hfc->dev, fifo->pipe,
582 fifo->iso[i].buffer,
583 num_packets_per_urb,
584 fifo->usb_packet_maxlen,
585 fifo->intervall, complete,
586 &fifo->iso[i]);
587 memset(fifo->iso[i].buffer, 0,
588 sizeof(fifo->iso[i].buffer));
589 /* defining packet delimeters in fifo->buffer */
590 for (k = 0; k < num_packets_per_urb; k++) {
591 fifo->iso[i].purb->
592 iso_frame_desc[k].offset =
593 k * packet_size;
594 fifo->iso[i].purb->
595 iso_frame_desc[k].length =
596 packet_size;
597 }
598 } else {
599 printk(KERN_INFO
600 "HFC-S USB: ISO Buffer size to small!\n");
601 }
602 }
603 fifo->bit_line = BITLINE_INF;
604
605 errcode = usb_submit_urb(fifo->iso[i].purb, GFP_KERNEL);
606 fifo->active = (errcode >= 0) ? 1 : 0;
607 if (errcode < 0) {
608 printk(KERN_INFO "HFC-S USB: %s URB nr:%d\n",
609 symbolic(urb_errlist, errcode), i);
610 };
611 }
612 return (fifo->active);
613}
614
615/* stops running iso chain and frees their pending urbs */
616static void
617stop_isoc_chain(usb_fifo * fifo)
618{
619 int i;
620
621 for (i = 0; i < 2; i++) {
622 if (fifo->iso[i].purb) {
623#ifdef CONFIG_HISAX_DEBUG
624 DBG(USB_DBG,
625 "HFC-S USB: Stopping iso chain for fifo %i.%i",
626 fifo->fifonum, i);
627#endif
628 usb_unlink_urb(fifo->iso[i].purb);
629 usb_free_urb(fifo->iso[i].purb);
630 fifo->iso[i].purb = NULL;
631 }
632 }
633 if (fifo->urb) {
634 usb_unlink_urb(fifo->urb);
635 usb_free_urb(fifo->urb);
636 fifo->urb = NULL;
637 }
638 fifo->active = 0;
639}
640
641/* defines how much ISO packets are handled in one URB */
642static int iso_packets[8] =
643 { ISOC_PACKETS_B, ISOC_PACKETS_B, ISOC_PACKETS_B, ISOC_PACKETS_B,
644 ISOC_PACKETS_D, ISOC_PACKETS_D, ISOC_PACKETS_D, ISOC_PACKETS_D
645};
646
647/*****************************************************/
648/* transmit completion routine for all ISO tx fifos */
649/*****************************************************/
650static void
651tx_iso_complete(struct urb *urb, struct pt_regs *regs)
652{
653 iso_urb_struct *context_iso_urb = (iso_urb_struct *) urb->context;
654 usb_fifo *fifo = context_iso_urb->owner_fifo;
655 hfcusb_data *hfc = fifo->hfc;
656 int k, tx_offset, num_isoc_packets, sink, len, current_len,
657 errcode;
658 int frame_complete, transp_mode, fifon, status;
659 __u8 threshbit;
660 __u8 threshtable[8] = { 1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80 };
661
662 fifon = fifo->fifonum;
663 status = urb->status;
664
665 tx_offset = 0;
666
667 if (fifo->active && !status) {
668 transp_mode = 0;
669 if (fifon < 4 && hfc->b_mode[fifon / 2] == L1_MODE_TRANS)
670 transp_mode = TRUE;
671
672 /* is FifoFull-threshold set for our channel? */
673 threshbit = threshtable[fifon] & hfc->threshold_mask;
674 num_isoc_packets = iso_packets[fifon];
675
676 /* predict dataflow to avoid fifo overflow */
677 if (fifon >= HFCUSB_D_TX) {
678 sink = (threshbit) ? SINK_DMIN : SINK_DMAX;
679 } else {
680 sink = (threshbit) ? SINK_MIN : SINK_MAX;
681 }
682 fill_isoc_urb(urb, fifo->hfc->dev, fifo->pipe,
683 context_iso_urb->buffer, num_isoc_packets,
684 fifo->usb_packet_maxlen, fifo->intervall,
685 tx_iso_complete, urb->context);
686 memset(context_iso_urb->buffer, 0,
687 sizeof(context_iso_urb->buffer));
688 frame_complete = FALSE;
689 /* Generate next Iso Packets */
690 for (k = 0; k < num_isoc_packets; ++k) {
691 if (fifo->skbuff) {
692 len = fifo->skbuff->len;
693 /* we lower data margin every msec */
694 fifo->bit_line -= sink;
695 current_len = (0 - fifo->bit_line) / 8;
696 /* maximum 15 byte for every ISO packet makes our life easier */
697 if (current_len > 14)
698 current_len = 14;
699 current_len =
700 (len <=
701 current_len) ? len : current_len;
702 /* how much bit do we put on the line? */
703 fifo->bit_line += current_len * 8;
704
705 context_iso_urb->buffer[tx_offset] = 0;
706 if (current_len == len) {
707 if (!transp_mode) {
708 /* here frame completion */
709 context_iso_urb->
710 buffer[tx_offset] = 1;
711 /* add 2 byte flags and 16bit CRC at end of ISDN frame */
712 fifo->bit_line += 32;
713 }
714 frame_complete = TRUE;
715 }
716
717 memcpy(context_iso_urb->buffer +
718 tx_offset + 1, fifo->skbuff->data,
719 current_len);
720 skb_pull(fifo->skbuff, current_len);
721
722 /* define packet delimeters within the URB buffer */
723 urb->iso_frame_desc[k].offset = tx_offset;
724 urb->iso_frame_desc[k].length =
725 current_len + 1;
726
727 tx_offset += (current_len + 1);
728 if (!transp_mode) {
729 if (fifon == HFCUSB_B1_TX)
730 handle_led(hfc,
731 LED_B1_DATA);
732 if (fifon == HFCUSB_B2_TX)
733 handle_led(hfc,
734 LED_B2_DATA);
735 }
736 } else {
737 urb->iso_frame_desc[k].offset =
738 tx_offset++;
739
740 urb->iso_frame_desc[k].length = 1;
741 fifo->bit_line -= sink; /* we lower data margin every msec */
742
743 if (fifo->bit_line < BITLINE_INF) {
744 fifo->bit_line = BITLINE_INF;
745 }
746 }
747
748 if (frame_complete) {
749 fifo->delete_flg = TRUE;
750 fifo->hif->l1l2(fifo->hif,
751 PH_DATA | CONFIRM,
752 (void *) fifo->skbuff->
753 truesize);
754 if (fifo->skbuff && fifo->delete_flg) {
755 dev_kfree_skb_any(fifo->skbuff);
756 fifo->skbuff = NULL;
757 fifo->delete_flg = FALSE;
758 }
759 frame_complete = FALSE;
760 }
761 }
762 errcode = usb_submit_urb(urb, GFP_ATOMIC);
763 if (errcode < 0) {
764 printk(KERN_INFO
765 "HFC-S USB: error submitting ISO URB: %d \n",
766 errcode);
767 }
768 } else {
769 if (status && !hfc->disc_flag) {
770 printk(KERN_INFO
771 "HFC-S USB: tx_iso_complete : urb->status %s (%i), fifonum=%d\n",
772 symbolic(urb_errlist, status), status,
773 fifon);
774 }
775 }
776} /* tx_iso_complete */
777
778/*****************************************************/
779/* receive completion routine for all ISO tx fifos */
780/*****************************************************/
781static void
782rx_iso_complete(struct urb *urb, struct pt_regs *regs)
783{
784 iso_urb_struct *context_iso_urb = (iso_urb_struct *) urb->context;
785 usb_fifo *fifo = context_iso_urb->owner_fifo;
786 hfcusb_data *hfc = fifo->hfc;
787 int k, len, errcode, offset, num_isoc_packets, fifon, maxlen,
788 status;
789 unsigned int iso_status;
790 __u8 *buf;
791 static __u8 eof[8];
792#ifdef CONFIG_HISAX_DEBUG
793 __u8 i;
794#endif
795
796 fifon = fifo->fifonum;
797 status = urb->status;
798
799 if (urb->status == -EOVERFLOW) {
800#ifdef CONFIG_HISAX_DEBUG
801 DBG(USB_DBG,
802 "HFC-USB: ignoring USB DATAOVERRUN for fifo %i \n",
803 fifon);
804#endif
805 status = 0;
806 }
807 if (fifo->active && !status) {
808 num_isoc_packets = iso_packets[fifon];
809 maxlen = fifo->usb_packet_maxlen;
810 for (k = 0; k < num_isoc_packets; ++k) {
811 len = urb->iso_frame_desc[k].actual_length;
812 offset = urb->iso_frame_desc[k].offset;
813 buf = context_iso_urb->buffer + offset;
814 iso_status = urb->iso_frame_desc[k].status;
815#ifdef CONFIG_HISAX_DEBUG
816 if (iso_status && !hfc->disc_flag)
817 DBG(USB_DBG,
818 "HFC-S USB: ISO packet failure - status:%x",
819 iso_status);
820
821 if ((fifon == 5) && (debug > 1)) {
822 printk(KERN_INFO
823 "HFC-S USB: ISO-D-RX lst_urblen:%2d "
824 "act_urblen:%2d max-urblen:%2d "
825 "EOF:0x%0x DATA: ",
826 fifo->last_urblen, len, maxlen,
827 eof[5]);
828 for (i = 0; i < len; i++)
829 printk("%.2x ", buf[i]);
830 printk("\n");
831 }
832#endif
833 if (fifo->last_urblen != maxlen) {
834 /* the threshold mask is in the 2nd status byte */
835 hfc->threshold_mask = buf[1];
836 /* care for L1 state only for D-Channel
837 to avoid overlapped iso completions */
838 if (fifon == 5) {
839 /* the S0 state is in the upper half
840 of the 1st status byte */
841 state_handler(hfc, buf[0] >> 4);
842 }
843 eof[fifon] = buf[0] & 1;
844 if (len > 2)
845 collect_rx_frame(fifo, buf + 2,
846 len - 2,
847 (len <
848 maxlen) ?
849 eof[fifon] : 0);
850 } else {
851 collect_rx_frame(fifo, buf, len,
852 (len <
853 maxlen) ? eof[fifon] :
854 0);
855 }
856 fifo->last_urblen = len;
857 }
858
859 fill_isoc_urb(urb, fifo->hfc->dev, fifo->pipe,
860 context_iso_urb->buffer, num_isoc_packets,
861 fifo->usb_packet_maxlen, fifo->intervall,
862 rx_iso_complete, urb->context);
863 errcode = usb_submit_urb(urb, GFP_ATOMIC);
864 if (errcode < 0) {
865 printk(KERN_INFO
866 "HFC-S USB: error submitting ISO URB: %d \n",
867 errcode);
868 }
869 } else {
870 if (status && !hfc->disc_flag) {
871 printk(KERN_INFO
872 "HFC-S USB: rx_iso_complete : "
873 "urb->status %d, fifonum %d\n",
874 status, fifon);
875 }
876 }
877} /* rx_iso_complete */
878
879/*****************************************************/
880/* collect data from interrupt or isochron in */
881/*****************************************************/
882static void
883collect_rx_frame(usb_fifo * fifo, __u8 * data, int len, int finish)
884{
885 hfcusb_data *hfc = fifo->hfc;
886 int transp_mode, fifon;
887#ifdef CONFIG_HISAX_DEBUG
888 int i;
889#endif
890 fifon = fifo->fifonum;
891 transp_mode = 0;
892 if (fifon < 4 && hfc->b_mode[fifon / 2] == L1_MODE_TRANS)
893 transp_mode = TRUE;
894
895 if (!fifo->skbuff) {
896 fifo->skbuff = dev_alloc_skb(fifo->max_size + 3);
897 if (!fifo->skbuff) {
898 printk(KERN_INFO
899 "HFC-S USB: cannot allocate buffer (dev_alloc_skb) fifo:%d\n",
900 fifon);
901 return;
902 }
903 }
904 if (len) {
905 if (fifo->skbuff->len + len < fifo->max_size) {
906 memcpy(skb_put(fifo->skbuff, len), data, len);
907 } else {
908#ifdef CONFIG_HISAX_DEBUG
909 printk(KERN_INFO "HFC-S USB: ");
910 for (i = 0; i < 15; i++)
911 printk("%.2x ",
912 fifo->skbuff->data[fifo->skbuff->
913 len - 15 + i]);
914 printk("\n");
915#endif
916 printk(KERN_INFO
917 "HCF-USB: got frame exceeded fifo->max_size:%d on fifo:%d\n",
918 fifo->max_size, fifon);
919 }
920 }
921 if (transp_mode && fifo->skbuff->len >= 128) {
922 fifo->hif->l1l2(fifo->hif, PH_DATA | INDICATION,
923 fifo->skbuff);
924 fifo->skbuff = NULL;
925 return;
926 }
927 /* we have a complete hdlc packet */
928 if (finish) {
929 if ((!fifo->skbuff->data[fifo->skbuff->len - 1])
930 && (fifo->skbuff->len > 3)) {
931 /* remove CRC & status */
932 skb_trim(fifo->skbuff, fifo->skbuff->len - 3);
933 if (fifon == HFCUSB_PCM_RX) {
934 fifo->hif->l1l2(fifo->hif,
935 PH_DATA_E | INDICATION,
936 fifo->skbuff);
937 } else
938 fifo->hif->l1l2(fifo->hif,
939 PH_DATA | INDICATION,
940 fifo->skbuff);
941 fifo->skbuff = NULL; /* buffer was freed from upper layer */
942 } else {
943 if (fifo->skbuff->len > 3) {
944 printk(KERN_INFO
945 "HFC-S USB: got frame %d bytes but CRC ERROR on fifo:%d!!!\n",
946 fifo->skbuff->len, fifon);
947#ifdef CONFIG_HISAX_DEBUG
948 if (debug > 1) {
949 printk(KERN_INFO "HFC-S USB: ");
950 for (i = 0; i < 15; i++)
951 printk("%.2x ",
952 fifo->skbuff->
953 data[fifo->skbuff->
954 len - 15 + i]);
955 printk("\n");
956 }
957#endif
958 }
959#ifdef CONFIG_HISAX_DEBUG
960 else {
961 printk(KERN_INFO
962 "HFC-S USB: frame to small (%d bytes)!!!\n",
963 fifo->skbuff->len);
964 }
965#endif
966 skb_trim(fifo->skbuff, 0);
967 }
968 }
969
970 /* LED flashing only in HDLC mode */
971 if (!transp_mode) {
972 if (fifon == HFCUSB_B1_RX)
973 handle_led(hfc, LED_B1_DATA);
974 if (fifon == HFCUSB_B2_RX)
975 handle_led(hfc, LED_B2_DATA);
976 }
977}
978
979/***********************************************/
980/* receive completion routine for all rx fifos */
981/***********************************************/
982static void
983rx_complete(struct urb *urb, struct pt_regs *regs)
984{
985 int len;
986 int status;
987 __u8 *buf, maxlen, fifon;
988 usb_fifo *fifo = (usb_fifo *) urb->context;
989 hfcusb_data *hfc = fifo->hfc;
990 static __u8 eof[8];
991#ifdef CONFIG_HISAX_DEBUG
992 __u8 i;
993#endif
994
995 urb->dev = hfc->dev; /* security init */
996
997 fifon = fifo->fifonum;
998 if ((!fifo->active) || (urb->status)) {
999#ifdef CONFIG_HISAX_DEBUG
1000 DBG(USB_DBG, "HFC-S USB: RX-Fifo %i is going down (%i)",
1001 fifon, urb->status);
1002#endif
1003 fifo->urb->interval = 0; /* cancel automatic rescheduling */
1004 if (fifo->skbuff) {
1005 dev_kfree_skb_any(fifo->skbuff);
1006 fifo->skbuff = NULL;
1007 }
1008 return;
1009 }
1010 len = urb->actual_length;
1011 buf = fifo->buffer;
1012 maxlen = fifo->usb_packet_maxlen;
1013
1014#ifdef CONFIG_HISAX_DEBUG
1015 if ((fifon == 5) && (debug > 1)) {
1016 printk(KERN_INFO
1017 "HFC-S USB: INT-D-RX lst_urblen:%2d act_urblen:%2d max-urblen:%2d EOF:0x%0x DATA: ",
1018 fifo->last_urblen, len, maxlen, eof[5]);
1019 for (i = 0; i < len; i++)
1020 printk("%.2x ", buf[i]);
1021 printk("\n");
1022 }
1023#endif
1024
1025 if (fifo->last_urblen != fifo->usb_packet_maxlen) {
1026 /* the threshold mask is in the 2nd status byte */
1027 hfc->threshold_mask = buf[1];
1028 /* the S0 state is in the upper half of the 1st status byte */
1029 state_handler(hfc, buf[0] >> 4);
1030 eof[fifon] = buf[0] & 1;
1031 /* if we have more than the 2 status bytes -> collect data */
1032 if (len > 2)
1033 collect_rx_frame(fifo, buf + 2,
1034 urb->actual_length - 2,
1035 (len < maxlen) ? eof[fifon] : 0);
1036 } else {
1037 collect_rx_frame(fifo, buf, urb->actual_length,
1038 (len < maxlen) ? eof[fifon] : 0);
1039 }
1040 fifo->last_urblen = urb->actual_length;
1041 status = usb_submit_urb(urb, GFP_ATOMIC);
1042 if (status) {
1043 printk(KERN_INFO
1044 "HFC-S USB: error resubmitting URN at rx_complete...\n");
1045 }
1046} /* rx_complete */
1047
1048/***************************************************/
1049/* start the interrupt transfer for the given fifo */
1050/***************************************************/
1051static void
1052start_int_fifo(usb_fifo * fifo)
1053{
1054 int errcode;
1055
1056 printk(KERN_INFO "HFC-S USB: starting intr IN fifo:%d\n",
1057 fifo->fifonum);
1058
1059 if (!fifo->urb) {
1060 fifo->urb = usb_alloc_urb(0, GFP_KERNEL);
1061 if (!fifo->urb)
1062 return;
1063 }
1064 usb_fill_int_urb(fifo->urb, fifo->hfc->dev, fifo->pipe,
1065 fifo->buffer, fifo->usb_packet_maxlen,
1066 rx_complete, fifo, fifo->intervall);
1067 fifo->active = 1; /* must be marked active */
1068 errcode = usb_submit_urb(fifo->urb, GFP_KERNEL);
1069 if (errcode) {
1070 printk(KERN_INFO
1071 "HFC-S USB: submit URB error(start_int_info): status:%i\n",
1072 errcode);
1073 fifo->active = 0;
1074 fifo->skbuff = NULL;
1075 }
1076} /* start_int_fifo */
1077
1078/*****************************/
1079/* set the B-channel mode */
1080/*****************************/
1081static void
1082set_hfcmode(hfcusb_data * hfc, int channel, int mode)
1083{
1084 __u8 val, idx_table[2] = { 0, 2 };
1085
1086 if (hfc->disc_flag) {
1087 return;
1088 }
1089#ifdef CONFIG_HISAX_DEBUG
1090 DBG(ISDN_DBG, "HFC-S USB: setting channel %d to mode %d", channel,
1091 mode);
1092#endif
1093 hfc->b_mode[channel] = mode;
1094
1095 /* setup CON_HDLC */
1096 val = 0;
1097 if (mode != L1_MODE_NULL)
1098 val = 8; /* enable fifo? */
1099 if (mode == L1_MODE_TRANS)
1100 val |= 2; /* set transparent bit */
1101
1102 /* set FIFO to transmit register */
1103 queue_control_request(hfc, HFCUSB_FIFO, idx_table[channel], 1);
1104 queue_control_request(hfc, HFCUSB_CON_HDLC, val, 1);
1105 /* reset fifo */
1106 queue_control_request(hfc, HFCUSB_INC_RES_F, 2, 1);
1107 /* set FIFO to receive register */
1108 queue_control_request(hfc, HFCUSB_FIFO, idx_table[channel] + 1, 1);
1109 queue_control_request(hfc, HFCUSB_CON_HDLC, val, 1);
1110 /* reset fifo */
1111 queue_control_request(hfc, HFCUSB_INC_RES_F, 2, 1);
1112
1113 val = 0x40;
1114 if (hfc->b_mode[0])
1115 val |= 1;
1116 if (hfc->b_mode[1])
1117 val |= 2;
1118 queue_control_request(hfc, HFCUSB_SCTRL, val, 1);
1119
1120 val = 0;
1121 if (hfc->b_mode[0])
1122 val |= 1;
1123 if (hfc->b_mode[1])
1124 val |= 2;
1125 queue_control_request(hfc, HFCUSB_SCTRL_R, val, 1);
1126
1127 if (mode == L1_MODE_NULL) {
1128 if (channel)
1129 handle_led(hfc, LED_B2_OFF);
1130 else
1131 handle_led(hfc, LED_B1_OFF);
1132 } else {
1133 if (channel)
1134 handle_led(hfc, LED_B2_ON);
1135 else
1136 handle_led(hfc, LED_B1_ON);
1137 }
1138}
1139
1140void
1141hfc_usb_l2l1(struct hisax_if *my_hisax_if, int pr, void *arg)
1142{
1143 usb_fifo *fifo = my_hisax_if->priv;
1144 hfcusb_data *hfc = fifo->hfc;
1145
1146 switch (pr) {
1147 case PH_ACTIVATE | REQUEST:
1148 if (fifo->fifonum == HFCUSB_D_TX) {
1149#ifdef CONFIG_HISAX_DEBUG
1150 DBG(ISDN_DBG,
1151 "HFC_USB: hfc_usb_d_l2l1 D-chan: PH_ACTIVATE | REQUEST");
1152#endif
1153 if (hfc->l1_state != 3
1154 && hfc->l1_state != 7) {
1155 hfc->d_if.ifc.l1l2(&hfc->d_if.ifc,
1156 PH_DEACTIVATE |
1157 INDICATION,
1158 NULL);
1159#ifdef CONFIG_HISAX_DEBUG
1160 DBG(ISDN_DBG,
1161 "HFC-S USB: PH_DEACTIVATE | INDICATION sent (not state 3 or 7)");
1162#endif
1163 } else {
1164 if (hfc->l1_state == 7) { /* l1 already active */
1165 hfc->d_if.ifc.l1l2(&hfc->
1166 d_if.
1167 ifc,
1168 PH_ACTIVATE
1169 |
1170 INDICATION,
1171 NULL);
1172#ifdef CONFIG_HISAX_DEBUG
1173 DBG(ISDN_DBG,
1174 "HFC-S USB: PH_ACTIVATE | INDICATION sent again ;)");
1175#endif
1176 } else {
1177 /* force sending sending INFO1 */
1178 queue_control_request(hfc,
1179 HFCUSB_STATES,
1180 0x14,
1181 1);
1182 mdelay(1);
1183 /* start l1 activation */
1184 queue_control_request(hfc,
1185 HFCUSB_STATES,
1186 0x04,
1187 1);
1188 if (!timer_pending
1189 (&hfc->t3_timer)) {
1190 hfc->t3_timer.
1191 expires =
1192 jiffies +
1193 (HFC_TIMER_T3 *
1194 HZ) / 1000;
1195 add_timer(&hfc->
1196 t3_timer);
1197 }
1198 }
1199 }
1200 } else {
1201#ifdef CONFIG_HISAX_DEBUG
1202 DBG(ISDN_DBG,
1203 "HFC_USB: hfc_usb_d_l2l1 Bx-chan: PH_ACTIVATE | REQUEST");
1204#endif
1205 set_hfcmode(hfc,
1206 (fifo->fifonum ==
1207 HFCUSB_B1_TX) ? 0 : 1,
1208 (int) arg);
1209 fifo->hif->l1l2(fifo->hif,
1210 PH_ACTIVATE | INDICATION,
1211 NULL);
1212 }
1213 break;
1214 case PH_DEACTIVATE | REQUEST:
1215 if (fifo->fifonum == HFCUSB_D_TX) {
1216#ifdef CONFIG_HISAX_DEBUG
1217 DBG(ISDN_DBG,
1218 "HFC_USB: hfc_usb_d_l2l1 D-chan: PH_DEACTIVATE | REQUEST");
1219#endif
1220 printk(KERN_INFO
1221 "HFC-S USB: ISDN TE device should not deativate...\n");
1222 } else {
1223#ifdef CONFIG_HISAX_DEBUG
1224 DBG(ISDN_DBG,
1225 "HFC_USB: hfc_usb_d_l2l1 Bx-chan: PH_DEACTIVATE | REQUEST");
1226#endif
1227 set_hfcmode(hfc,
1228 (fifo->fifonum ==
1229 HFCUSB_B1_TX) ? 0 : 1,
1230 (int) L1_MODE_NULL);
1231 fifo->hif->l1l2(fifo->hif,
1232 PH_DEACTIVATE | INDICATION,
1233 NULL);
1234 }
1235 break;
1236 case PH_DATA | REQUEST:
1237 if (fifo->skbuff && fifo->delete_flg) {
1238 dev_kfree_skb_any(fifo->skbuff);
1239 fifo->skbuff = NULL;
1240 fifo->delete_flg = FALSE;
1241 }
1242 fifo->skbuff = arg; /* we have a new buffer */
1243 break;
1244 default:
1245 printk(KERN_INFO
1246 "HFC_USB: hfc_usb_d_l2l1: unkown state : %#x\n",
1247 pr);
1248 break;
1249 }
1250}
1251
1252/***************************************************************************/
1253/* usb_init is called once when a new matching device is detected to setup */
1254/* main parameters. It registers the driver at the main hisax module. */
1255/* on success 0 is returned. */
1256/***************************************************************************/
1257static int
1258usb_init(hfcusb_data * hfc)
1259{
1260 usb_fifo *fifo;
1261 int i, err;
1262 u_char b;
1263 struct hisax_b_if *p_b_if[2];
1264
1265 /* check the chip id */
1266 if (read_usb(hfc, HFCUSB_CHIP_ID, &b) != 1) {
1267 printk(KERN_INFO "HFC-USB: cannot read chip id\n");
1268 return (1);
1269 }
1270 if (b != HFCUSB_CHIPID) {
1271 printk(KERN_INFO "HFC-S USB: Invalid chip id 0x%02x\n", b);
1272 return (1);
1273 }
1274
1275 /* first set the needed config, interface and alternate */
1276 err = usb_set_interface(hfc->dev, hfc->if_used, hfc->alt_used);
1277
1278 /* do Chip reset */
1279 write_usb(hfc, HFCUSB_CIRM, 8);
1280 /* aux = output, reset off */
1281 write_usb(hfc, HFCUSB_CIRM, 0x10);
1282
1283 /* set USB_SIZE to match the the wMaxPacketSize for INT or BULK transfers */
1284 write_usb(hfc, HFCUSB_USB_SIZE,
1285 (hfc->packet_size / 8) | ((hfc->packet_size / 8) << 4));
1286
1287 /* set USB_SIZE_I to match the the wMaxPacketSize for ISO transfers */
1288 write_usb(hfc, HFCUSB_USB_SIZE_I, hfc->iso_packet_size);
1289
1290 /* enable PCM/GCI master mode */
1291 write_usb(hfc, HFCUSB_MST_MODE1, 0); /* set default values */
1292 write_usb(hfc, HFCUSB_MST_MODE0, 1); /* enable master mode */
1293
1294 /* init the fifos */
1295 write_usb(hfc, HFCUSB_F_THRES,
1296 (HFCUSB_TX_THRESHOLD /
1297 8) | ((HFCUSB_RX_THRESHOLD / 8) << 4));
1298
1299 fifo = hfc->fifos;
1300 for (i = 0; i < HFCUSB_NUM_FIFOS; i++) {
1301 write_usb(hfc, HFCUSB_FIFO, i); /* select the desired fifo */
1302 fifo[i].skbuff = NULL; /* init buffer pointer */
1303 fifo[i].max_size =
1304 (i <= HFCUSB_B2_RX) ? MAX_BCH_SIZE : MAX_DFRAME_LEN;
1305 fifo[i].last_urblen = 0;
1306 /* set 2 bit for D- & E-channel */
1307 write_usb(hfc, HFCUSB_HDLC_PAR,
1308 ((i <= HFCUSB_B2_RX) ? 0 : 2));
1309 /* rx hdlc, enable IFF for D-channel */
1310 write_usb(hfc, HFCUSB_CON_HDLC,
1311 ((i == HFCUSB_D_TX) ? 0x09 : 0x08));
1312 write_usb(hfc, HFCUSB_INC_RES_F, 2); /* reset the fifo */
1313 }
1314
1315 write_usb(hfc, HFCUSB_CLKDEL, 0x0f); /* clock delay value */
1316 write_usb(hfc, HFCUSB_STATES, 3 | 0x10); /* set deactivated mode */
1317 write_usb(hfc, HFCUSB_STATES, 3); /* enable state machine */
1318
1319 write_usb(hfc, HFCUSB_SCTRL_R, 0); /* disable both B receivers */
1320 write_usb(hfc, HFCUSB_SCTRL, 0x40); /* disable B transmitters + capacitive mode */
1321
1322 /* set both B-channel to not connected */
1323 hfc->b_mode[0] = L1_MODE_NULL;
1324 hfc->b_mode[1] = L1_MODE_NULL;
1325
1326 hfc->l1_activated = FALSE;
1327 hfc->disc_flag = FALSE;
1328 hfc->led_state = 0;
1329 hfc->led_new_data = 0;
1330 hfc->old_led_state = 0;
1331
1332 /* init the t3 timer */
1333 init_timer(&hfc->t3_timer);
1334 hfc->t3_timer.data = (long) hfc;
1335 hfc->t3_timer.function = (void *) l1_timer_expire_t3;
1336
1337 /* init the t4 timer */
1338 init_timer(&hfc->t4_timer);
1339 hfc->t4_timer.data = (long) hfc;
1340 hfc->t4_timer.function = (void *) l1_timer_expire_t4;
1341
1342 /* init the led timer */
1343 init_timer(&hfc->led_timer);
1344 hfc->led_timer.data = (long) hfc;
1345 hfc->led_timer.function = (void *) led_timer;
1346
1347 /* trigger 4 hz led timer */
1348 if (!timer_pending(&hfc->led_timer)) {
1349 hfc->led_timer.expires = jiffies + (LED_TIME * HZ) / 1000;
1350 add_timer(&hfc->led_timer);
1351 }
1352
1353 /* init the background machinery for control requests */
1354 hfc->ctrl_read.bRequestType = 0xc0;
1355 hfc->ctrl_read.bRequest = 1;
1356 hfc->ctrl_read.wLength = 1;
1357 hfc->ctrl_write.bRequestType = 0x40;
1358 hfc->ctrl_write.bRequest = 0;
1359 hfc->ctrl_write.wLength = 0;
1360 usb_fill_control_urb(hfc->ctrl_urb,
1361 hfc->dev,
1362 hfc->ctrl_out_pipe,
1363 (u_char *) & hfc->ctrl_write,
1364 NULL, 0, ctrl_complete, hfc);
1365 /* Init All Fifos */
1366 for (i = 0; i < HFCUSB_NUM_FIFOS; i++) {
1367 hfc->fifos[i].iso[0].purb = NULL;
1368 hfc->fifos[i].iso[1].purb = NULL;
1369 hfc->fifos[i].active = 0;
1370 }
1371 /* register Modul to upper Hisax Layers */
1372 hfc->d_if.owner = THIS_MODULE;
1373 hfc->d_if.ifc.priv = &hfc->fifos[HFCUSB_D_TX];
1374 hfc->d_if.ifc.l2l1 = hfc_usb_l2l1;
1375 for (i = 0; i < 2; i++) {
1376 hfc->b_if[i].ifc.priv = &hfc->fifos[HFCUSB_B1_TX + i * 2];
1377 hfc->b_if[i].ifc.l2l1 = hfc_usb_l2l1;
1378 p_b_if[i] = &hfc->b_if[i];
1379 }
1380 /* default Prot: EURO ISDN, should be a module_param */
1381 hfc->protocol = 2;
1382 hisax_register(&hfc->d_if, p_b_if, "hfc_usb", hfc->protocol);
1383
1384#ifdef CONFIG_HISAX_DEBUG
1385 hfc_debug = debug;
1386#endif
1387
1388 for (i = 0; i < 4; i++)
1389 hfc->fifos[i].hif = &p_b_if[i / 2]->ifc;
1390 for (i = 4; i < 8; i++)
1391 hfc->fifos[i].hif = &hfc->d_if.ifc;
1392
1393 /* 3 (+1) INT IN + 3 ISO OUT */
1394 if (hfc->cfg_used == CNF_3INT3ISO || hfc->cfg_used == CNF_4INT3ISO) {
1395 start_int_fifo(hfc->fifos + HFCUSB_D_RX);
1396 if (hfc->fifos[HFCUSB_PCM_RX].pipe)
1397 start_int_fifo(hfc->fifos + HFCUSB_PCM_RX);
1398 start_int_fifo(hfc->fifos + HFCUSB_B1_RX);
1399 start_int_fifo(hfc->fifos + HFCUSB_B2_RX);
1400 }
1401 /* 3 (+1) ISO IN + 3 ISO OUT */
1402 if (hfc->cfg_used == CNF_3ISO3ISO || hfc->cfg_used == CNF_4ISO3ISO) {
1403 start_isoc_chain(hfc->fifos + HFCUSB_D_RX, ISOC_PACKETS_D,
1404 rx_iso_complete, 16);
1405 if (hfc->fifos[HFCUSB_PCM_RX].pipe)
1406 start_isoc_chain(hfc->fifos + HFCUSB_PCM_RX,
1407 ISOC_PACKETS_D, rx_iso_complete,
1408 16);
1409 start_isoc_chain(hfc->fifos + HFCUSB_B1_RX, ISOC_PACKETS_B,
1410 rx_iso_complete, 16);
1411 start_isoc_chain(hfc->fifos + HFCUSB_B2_RX, ISOC_PACKETS_B,
1412 rx_iso_complete, 16);
1413 }
1414
1415 start_isoc_chain(hfc->fifos + HFCUSB_D_TX, ISOC_PACKETS_D,
1416 tx_iso_complete, 1);
1417 start_isoc_chain(hfc->fifos + HFCUSB_B1_TX, ISOC_PACKETS_B,
1418 tx_iso_complete, 1);
1419 start_isoc_chain(hfc->fifos + HFCUSB_B2_TX, ISOC_PACKETS_B,
1420 tx_iso_complete, 1);
1421
1422 handle_led(hfc, LED_POWER_ON);
1423
1424 return (0);
1425} /* usb_init */
1426
1427/*************************************************/
1428/* function called to probe a new plugged device */
1429/*************************************************/
1430static int
1431hfc_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
1432{
1433 struct usb_device *dev = interface_to_usbdev(intf);
1434 hfcusb_data *context;
1435 struct usb_host_interface *iface = intf->cur_altsetting;
1436 struct usb_host_interface *iface_used = NULL;
1437 struct usb_host_endpoint *ep;
1438 int ifnum = iface->desc.bInterfaceNumber;
1439 int i, idx, alt_idx, probe_alt_setting, vend_idx, cfg_used, *vcf,
1440 attr, cfg_found, cidx, ep_addr;
1441 int cmptbl[16], small_match, iso_packet_size, packet_size,
1442 alt_used = 0;
1443
1444 vend_idx = 0xffff;
1445 for (i = 0; vdata[i].vendor; i++) {
1446 if (dev->descriptor.idVendor == vdata[i].vendor
1447 && dev->descriptor.idProduct == vdata[i].prod_id)
1448 vend_idx = i;
1449 }
1450#ifdef CONFIG_HISAX_DEBUG
1451 DBG(USB_DBG,
1452 "HFC-USB: probing interface(%d) actalt(%d) minor(%d)\n", ifnum,
1453 iface->desc.bAlternateSetting, intf->minor);
1454#endif
1455 printk(KERN_INFO
1456 "HFC-S USB: probing interface(%d) actalt(%d) minor(%d)\n",
1457 ifnum, iface->desc.bAlternateSetting, intf->minor);
1458
1459 if (vend_idx != 0xffff) {
1460#ifdef CONFIG_HISAX_DEBUG
1461 DBG(USB_DBG, "HFC-S USB: found vendor idx:%d name:%s",
1462 vend_idx, vdata[vend_idx].vend_name);
1463#endif
1464 /* if vendor and product ID is OK, start probing alternate settings */
1465 alt_idx = 0;
1466 small_match = 0xffff;
1467
1468 /* default settings */
1469 iso_packet_size = 16;
1470 packet_size = 64;
1471
1472 while (alt_idx < intf->num_altsetting) {
1473 iface = intf->altsetting + alt_idx;
1474 probe_alt_setting = iface->desc.bAlternateSetting;
1475 cfg_used = 0;
1476
1477 /* check for config EOL element */
1478 while (validconf[cfg_used][0]) {
1479 cfg_found = TRUE;
1480 vcf = validconf[cfg_used];
1481 /* first endpoint descriptor */
1482 ep = iface->endpoint;
1483#ifdef CONFIG_HISAX_DEBUG
1484 DBG(USB_DBG,
1485 "HFC-S USB: (if=%d alt=%d cfg_used=%d)\n",
1486 ifnum, probe_alt_setting, cfg_used);
1487#endif
1488 memcpy(cmptbl, vcf, 16 * sizeof(int));
1489
1490 /* check for all endpoints in this alternate setting */
1491 for (i = 0; i < iface->desc.bNumEndpoints;
1492 i++) {
1493 ep_addr =
1494 ep->desc.bEndpointAddress;
1495 /* get endpoint base */
1496 idx = ((ep_addr & 0x7f) - 1) * 2;
1497 if (ep_addr & 0x80)
1498 idx++;
1499 attr = ep->desc.bmAttributes;
1500 if (cmptbl[idx] == EP_NUL) {
1501 cfg_found = FALSE;
1502 }
1503 if (attr == USB_ENDPOINT_XFER_INT
1504 && cmptbl[idx] == EP_INT)
1505 cmptbl[idx] = EP_NUL;
1506 if (attr == USB_ENDPOINT_XFER_BULK
1507 && cmptbl[idx] == EP_BLK)
1508 cmptbl[idx] = EP_NUL;
1509 if (attr == USB_ENDPOINT_XFER_ISOC
1510 && cmptbl[idx] == EP_ISO)
1511 cmptbl[idx] = EP_NUL;
1512
1513 /* check if all INT endpoints match minimum interval */
1514 if (attr == USB_ENDPOINT_XFER_INT
1515 && ep->desc.bInterval <
1516 vcf[17]) {
1517#ifdef CONFIG_HISAX_DEBUG
1518 if (cfg_found)
1519 DBG(USB_DBG,
1520 "HFC-S USB: Interrupt Endpoint interval < %d found - skipping config",
1521 vcf[17]);
1522#endif
1523 cfg_found = FALSE;
1524 }
1525 ep++;
1526 }
1527 for (i = 0; i < 16; i++) {
1528 /* all entries must be EP_NOP or EP_NUL for a valid config */
1529 if (cmptbl[i] != EP_NOP
1530 && cmptbl[i] != EP_NUL)
1531 cfg_found = FALSE;
1532 }
1533 if (cfg_found) {
1534 if (cfg_used < small_match) {
1535 small_match = cfg_used;
1536 alt_used =
1537 probe_alt_setting;
1538 iface_used = iface;
1539 }
1540#ifdef CONFIG_HISAX_DEBUG
1541 DBG(USB_DBG,
1542 "HFC-USB: small_match=%x %x\n",
1543 small_match, alt_used);
1544#endif
1545 }
1546 cfg_used++;
1547 }
1548 alt_idx++;
1549 } /* (alt_idx < intf->num_altsetting) */
1550
1551 /* found a valid USB Ta Endpint config */
1552 if (small_match != 0xffff) {
1553 iface = iface_used;
1554 if (!
1555 (context =
1556 kmalloc(sizeof(hfcusb_data), GFP_KERNEL)))
1557 return (-ENOMEM); /* got no mem */
1558 memset(context, 0, sizeof(hfcusb_data));
1559
1560 ep = iface->endpoint;
1561 vcf = validconf[small_match];
1562
1563 for (i = 0; i < iface->desc.bNumEndpoints; i++) {
1564 ep_addr = ep->desc.bEndpointAddress;
1565 /* get endpoint base */
1566 idx = ((ep_addr & 0x7f) - 1) * 2;
1567 if (ep_addr & 0x80)
1568 idx++;
1569 cidx = idx & 7;
1570 attr = ep->desc.bmAttributes;
1571
1572 /* init Endpoints */
1573 if (vcf[idx] != EP_NOP
1574 && vcf[idx] != EP_NUL) {
1575 switch (attr) {
1576 case USB_ENDPOINT_XFER_INT:
1577 context->
1578 fifos[cidx].
1579 pipe =
1580 usb_rcvintpipe
1581 (dev,
1582 ep->desc.
1583 bEndpointAddress);
1584 context->
1585 fifos[cidx].
1586 usb_transfer_mode
1587 = USB_INT;
1588 packet_size =
1589 ep->desc.
1590 wMaxPacketSize;
1591 break;
1592 case USB_ENDPOINT_XFER_BULK:
1593 if (ep_addr & 0x80)
1594 context->
1595 fifos
1596 [cidx].
1597 pipe =
1598 usb_rcvbulkpipe
1599 (dev,
1600 ep->
1601 desc.
1602 bEndpointAddress);
1603 else
1604 context->
1605 fifos
1606 [cidx].
1607 pipe =
1608 usb_sndbulkpipe
1609 (dev,
1610 ep->
1611 desc.
1612 bEndpointAddress);
1613 context->
1614 fifos[cidx].
1615 usb_transfer_mode
1616 = USB_BULK;
1617 packet_size =
1618 ep->desc.
1619 wMaxPacketSize;
1620 break;
1621 case USB_ENDPOINT_XFER_ISOC:
1622 if (ep_addr & 0x80)
1623 context->
1624 fifos
1625 [cidx].
1626 pipe =
1627 usb_rcvisocpipe
1628 (dev,
1629 ep->
1630 desc.
1631 bEndpointAddress);
1632 else
1633 context->
1634 fifos
1635 [cidx].
1636 pipe =
1637 usb_sndisocpipe
1638 (dev,
1639 ep->
1640 desc.
1641 bEndpointAddress);
1642 context->
1643 fifos[cidx].
1644 usb_transfer_mode
1645 = USB_ISOC;
1646 iso_packet_size =
1647 ep->desc.
1648 wMaxPacketSize;
1649 break;
1650 default:
1651 context->
1652 fifos[cidx].
1653 pipe = 0;
1654 } /* switch attribute */
1655
1656 if (context->fifos[cidx].pipe) {
1657 context->fifos[cidx].
1658 fifonum = cidx;
1659 context->fifos[cidx].hfc =
1660 context;
1661 context->fifos[cidx].
1662 usb_packet_maxlen =
1663 ep->desc.
1664 wMaxPacketSize;
1665 context->fifos[cidx].
1666 intervall =
1667 ep->desc.bInterval;
1668 context->fifos[cidx].
1669 skbuff = NULL;
1670 }
1671 }
1672 ep++;
1673 }
1674 context->dev = dev; /* save device */
1675 context->if_used = ifnum; /* save used interface */
1676 context->alt_used = alt_used; /* and alternate config */
1677 context->ctrl_paksize = dev->descriptor.bMaxPacketSize0; /* control size */
1678 context->cfg_used = vcf[16]; /* store used config */
1679 context->vend_idx = vend_idx; /* store found vendor */
1680 context->packet_size = packet_size;
1681 context->iso_packet_size = iso_packet_size;
1682
1683 /* create the control pipes needed for register access */
1684 context->ctrl_in_pipe =
1685 usb_rcvctrlpipe(context->dev, 0);
1686 context->ctrl_out_pipe =
1687 usb_sndctrlpipe(context->dev, 0);
1688 context->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL);
1689
1690 printk(KERN_INFO
1691 "HFC-S USB: detected \"%s\"\n",
1692 vdata[vend_idx].vend_name);
1693#ifdef CONFIG_HISAX_DEBUG
1694 DBG(USB_DBG,
1695 "HFC-S USB: Endpoint-Config: %s (if=%d alt=%d)\n",
1696 conf_str[small_match], context->if_used,
1697 context->alt_used);
1698 printk(KERN_INFO
1699 "HFC-S USB: E-channel (\"ECHO:\") logging ");
1700 if (validconf[small_match][18])
1701 printk(" possible\n");
1702 else
1703 printk("NOT possible\n");
1704#endif
1705 /* init the chip and register the driver */
1706 if (usb_init(context)) {
1707 if (context->ctrl_urb) {
1708 usb_unlink_urb(context->ctrl_urb);
1709 usb_free_urb(context->ctrl_urb);
1710 context->ctrl_urb = NULL;
1711 }
1712 kfree(context);
1713 return (-EIO);
1714 }
1715 usb_set_intfdata(intf, context);
1716 return (0);
1717 }
1718 } else {
1719 printk(KERN_INFO
1720 "HFC-S USB: no valid vendor found in USB descriptor\n");
1721 }
1722 return (-EIO);
1723}
1724
1725/****************************************************/
1726/* function called when an active device is removed */
1727/****************************************************/
1728static void
1729hfc_usb_disconnect(struct usb_interface
1730 *intf)
1731{
1732 hfcusb_data *context = usb_get_intfdata(intf);
1733 int i;
1734 printk(KERN_INFO "HFC-S USB: device disconnect\n");
1735 context->disc_flag = TRUE;
1736 usb_set_intfdata(intf, NULL);
1737 if (!context)
1738 return;
1739 if (timer_pending(&context->t3_timer))
1740 del_timer(&context->t3_timer);
1741 if (timer_pending(&context->t4_timer))
1742 del_timer(&context->t4_timer);
1743 if (timer_pending(&context->led_timer))
1744 del_timer(&context->led_timer);
1745 /* tell all fifos to terminate */
1746 for (i = 0; i < HFCUSB_NUM_FIFOS; i++) {
1747 if (context->fifos[i].usb_transfer_mode == USB_ISOC) {
1748 if (context->fifos[i].active > 0) {
1749 stop_isoc_chain(&context->fifos[i]);
1750#ifdef CONFIG_HISAX_DEBUG
1751 DBG(USB_DBG,
1752 "HFC-S USB: hfc_usb_disconnect: stopping ISOC chain Fifo no %i",
1753 i);
1754#endif
1755 }
1756 } else {
1757 if (context->fifos[i].active > 0) {
1758 context->fifos[i].active = 0;
1759#ifdef CONFIG_HISAX_DEBUG
1760 DBG(USB_DBG,
1761 "HFC-S USB: hfc_usb_disconnect: unlinking URB for Fifo no %i",
1762 i);
1763#endif
1764 }
1765 if (context->fifos[i].urb) {
1766 usb_unlink_urb(context->fifos[i].urb);
1767 usb_free_urb(context->fifos[i].urb);
1768 context->fifos[i].urb = NULL;
1769 }
1770 }
1771 context->fifos[i].active = 0;
1772 }
1773 /* wait for all URBS to terminate */
1774 mdelay(10);
1775 if (context->ctrl_urb) {
1776 usb_unlink_urb(context->ctrl_urb);
1777 usb_free_urb(context->ctrl_urb);
1778 context->ctrl_urb = NULL;
1779 }
1780 hisax_unregister(&context->d_if);
1781 kfree(context); /* free our structure again */
1782} /* hfc_usb_disconnect */
1783
1784/************************************/
1785/* our driver information structure */
1786/************************************/
1787static struct usb_driver hfc_drv = {
1788 .owner = THIS_MODULE,.name =
1789 "hfc_usb",.id_table = hfc_usb_idtab,.probe =
1790 hfc_usb_probe,.disconnect = hfc_usb_disconnect,
1791};
1792static void __exit
1793hfc_usb_exit(void)
1794{
1795#ifdef CONFIG_HISAX_DEBUG
1796 DBG(USB_DBG, "HFC-S USB: calling \"hfc_usb_exit\" ...");
1797#endif
1798 usb_deregister(&hfc_drv); /* release our driver */
1799 printk(KERN_INFO "HFC-S USB: module removed\n");
1800}
1801
1802static int __init
1803hfc_usb_init(void)
1804{
1805#ifndef CONFIG_HISAX_DEBUG
1806 unsigned int debug = -1;
1807#endif
1808 char revstr[30], datestr[30], dummy[30];
1809 sscanf(hfcusb_revision,
1810 "%s %s $ %s %s %s $ ", dummy, revstr,
1811 dummy, datestr, dummy);
1812 printk(KERN_INFO
1813 "HFC-S USB: driver module revision %s date %s loaded, (debug=%i)\n",
1814 revstr, datestr, debug);
1815 if (usb_register(&hfc_drv)) {
1816 printk(KERN_INFO
1817 "HFC-S USB: Unable to register HFC-S USB module at usb stack\n");
1818 return (-1); /* unable to register */
1819 }
1820 return (0);
1821}
1822
1823module_init(hfc_usb_init);
1824module_exit(hfc_usb_exit);
1825MODULE_AUTHOR(DRIVER_AUTHOR);
1826MODULE_DESCRIPTION(DRIVER_DESC);
1827MODULE_LICENSE("GPL");
1828MODULE_DEVICE_TABLE(usb, hfc_usb_idtab);
diff --git a/drivers/isdn/hisax/hfc_usb.h b/drivers/isdn/hisax/hfc_usb.h
new file mode 100644
index 000000000000..b171600cf641
--- /dev/null
+++ b/drivers/isdn/hisax/hfc_usb.h
@@ -0,0 +1,228 @@
1/*
2* hfc_usb.h
3*
4* $Id: hfc_usb.h,v 4.1 2005/01/26 17:25:53 martinb1 Exp $
5*/
6
7#ifndef __HFC_USB_H__
8#define __HFC_USB_H__
9
10#define DRIVER_AUTHOR "Peter Sprenger (sprenger@moving-byters.de)"
11#define DRIVER_DESC "HFC-S USB based HiSAX ISDN driver"
12
13#define VERBOSE_USB_DEBUG
14
15#define TRUE 1
16#define FALSE 0
17
18
19/***********/
20/* defines */
21/***********/
22#define HFC_CTRL_TIMEOUT 20 /* 5ms timeout writing/reading regs */
23#define HFC_TIMER_T3 8000 /* timeout for l1 activation timer */
24#define HFC_TIMER_T4 500 /* time for state change interval */
25
26#define HFCUSB_L1_STATECHANGE 0 /* L1 state changed */
27#define HFCUSB_L1_DRX 1 /* D-frame received */
28#define HFCUSB_L1_ERX 2 /* E-frame received */
29#define HFCUSB_L1_DTX 4 /* D-frames completed */
30
31#define MAX_BCH_SIZE 2048 /* allowed B-channel packet size */
32
33#define HFCUSB_RX_THRESHOLD 64 /* threshold for fifo report bit rx */
34#define HFCUSB_TX_THRESHOLD 64 /* threshold for fifo report bit tx */
35
36#define HFCUSB_CHIP_ID 0x16 /* Chip ID register index */
37#define HFCUSB_CIRM 0x00 /* cirm register index */
38#define HFCUSB_USB_SIZE 0x07 /* int length register */
39#define HFCUSB_USB_SIZE_I 0x06 /* iso length register */
40#define HFCUSB_F_CROSS 0x0b /* bit order register */
41#define HFCUSB_CLKDEL 0x37 /* bit delay register */
42#define HFCUSB_CON_HDLC 0xfa /* channel connect register */
43#define HFCUSB_HDLC_PAR 0xfb
44#define HFCUSB_SCTRL 0x31 /* S-bus control register (tx) */
45#define HFCUSB_SCTRL_E 0x32 /* same for E and special funcs */
46#define HFCUSB_SCTRL_R 0x33 /* S-bus control register (rx) */
47#define HFCUSB_F_THRES 0x0c /* threshold register */
48#define HFCUSB_FIFO 0x0f /* fifo select register */
49#define HFCUSB_F_USAGE 0x1a /* fifo usage register */
50#define HFCUSB_MST_MODE0 0x14
51#define HFCUSB_MST_MODE1 0x15
52#define HFCUSB_P_DATA 0x1f
53#define HFCUSB_INC_RES_F 0x0e
54#define HFCUSB_STATES 0x30
55
56#define HFCUSB_CHIPID 0x40 /* ID value of HFC-S USB */
57
58/******************/
59/* fifo registers */
60/******************/
61#define HFCUSB_NUM_FIFOS 8 /* maximum number of fifos */
62#define HFCUSB_B1_TX 0 /* index for B1 transmit bulk/int */
63#define HFCUSB_B1_RX 1 /* index for B1 receive bulk/int */
64#define HFCUSB_B2_TX 2
65#define HFCUSB_B2_RX 3
66#define HFCUSB_D_TX 4
67#define HFCUSB_D_RX 5
68#define HFCUSB_PCM_TX 6
69#define HFCUSB_PCM_RX 7
70
71/*
72* used to switch snd_transfer_mode for different TA modes e.g. the Billion USB TA just
73* supports ISO out, while the Cologne Chip EVAL TA just supports BULK out
74*/
75#define USB_INT 0
76#define USB_BULK 1
77#define USB_ISOC 2
78
79#define ISOC_PACKETS_D 8
80#define ISOC_PACKETS_B 8
81#define ISO_BUFFER_SIZE 128
82
83// ISO send definitions
84#define SINK_MAX 68
85#define SINK_MIN 48
86#define SINK_DMIN 12
87#define SINK_DMAX 18
88#define BITLINE_INF (-64*8)
89
90
91/**********/
92/* macros */
93/**********/
94#define write_usb(a,b,c)usb_control_msg((a)->dev,(a)->ctrl_out_pipe,0,0x40,(c),(b),0,0,HFC_CTRL_TIMEOUT)
95#define read_usb(a,b,c) usb_control_msg((a)->dev,(a)->ctrl_in_pipe,1,0xC0,0,(b),(c),1,HFC_CTRL_TIMEOUT)
96
97
98/*******************/
99/* Debugging Flags */
100/*******************/
101#define USB_DBG 1
102#define ISDN_DBG 2
103
104
105/* *********************/
106/* USB related defines */
107/***********************/
108#define HFC_CTRL_BUFSIZE 32
109
110
111
112/*************************************************/
113/* entry and size of output/input control buffer */
114/*************************************************/
115typedef struct {
116 __u8 hfc_reg; /* register number */
117 __u8 reg_val; /* value to be written (or read) */
118 int action; /* data for action handler */
119} ctrl_buft;
120
121
122/********************/
123/* URB error codes: */
124/********************/
125/* Used to represent a list of values and their respective symbolic names */
126struct hfcusb_symbolic_list {
127 const int num;
128 const char *name;
129};
130
131static struct hfcusb_symbolic_list urb_errlist[] = {
132 {-ENOMEM, "No memory for allocation of internal structures"},
133 {-ENOSPC, "The host controller's bandwidth is already consumed"},
134 {-ENOENT, "URB was canceled by unlink_urb"},
135 {-EXDEV, "ISO transfer only partially completed"},
136 {-EAGAIN, "Too match scheduled for the future"},
137 {-ENXIO, "URB already queued"},
138 {-EFBIG, "Too much ISO frames requested"},
139 {-ENOSR, "Buffer error (overrun)"},
140 {-EPIPE, "Specified endpoint is stalled (device not responding)"},
141 {-EOVERFLOW, "Babble (bad cable?)"},
142 {-EPROTO, "Bit-stuff error (bad cable?)"},
143 {-EILSEQ, "CRC/Timeout"},
144 {-ETIMEDOUT, "NAK (device does not respond)"},
145 {-ESHUTDOWN, "Device unplugged"},
146 {-1, NULL}
147};
148
149
150/*****************************************************/
151/* device dependant information to support different */
152/* ISDN Ta's using the HFC-S USB chip */
153/*****************************************************/
154
155/* USB descriptor need to contain one of the following EndPoint combination: */
156#define CNF_4INT3ISO 1 // 4 INT IN, 3 ISO OUT
157#define CNF_3INT3ISO 2 // 3 INT IN, 3 ISO OUT
158#define CNF_4ISO3ISO 3 // 4 ISO IN, 3 ISO OUT
159#define CNF_3ISO3ISO 4 // 3 ISO IN, 3 ISO OUT
160
161#define EP_NUL 1 // Endpoint at this position not allowed
162#define EP_NOP 2 // all type of endpoints allowed at this position
163#define EP_ISO 3 // Isochron endpoint mandatory at this position
164#define EP_BLK 4 // Bulk endpoint mandatory at this position
165#define EP_INT 5 // Interrupt endpoint mandatory at this position
166
167/* this array represents all endpoints possible in the HCF-USB the last
168* 3 entries are the configuration number, the minimum interval for
169* Interrupt endpoints & boolean if E-channel logging possible
170*/
171int validconf[][19] = {
172 // INT in, ISO out config
173 {EP_NUL, EP_INT, EP_NUL, EP_INT, EP_NUL, EP_INT, EP_NOP, EP_INT,
174 EP_ISO, EP_NUL, EP_ISO, EP_NUL, EP_ISO, EP_NUL, EP_NUL, EP_NUL,
175 CNF_4INT3ISO, 2, 1},
176 {EP_NUL, EP_INT, EP_NUL, EP_INT, EP_NUL, EP_INT, EP_NUL, EP_NUL,
177 EP_ISO, EP_NUL, EP_ISO, EP_NUL, EP_ISO, EP_NUL, EP_NUL, EP_NUL,
178 CNF_3INT3ISO, 2, 0},
179 // ISO in, ISO out config
180 {EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL,
181 EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_NOP, EP_ISO,
182 CNF_4ISO3ISO, 2, 1},
183 {EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL,
184 EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_NUL, EP_NUL,
185 CNF_3ISO3ISO, 2, 0},
186 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} // EOL element
187};
188
189// string description of chosen config
190char *conf_str[] = {
191 "4 Interrupt IN + 3 Isochron OUT",
192 "3 Interrupt IN + 3 Isochron OUT",
193 "4 Isochron IN + 3 Isochron OUT",
194 "3 Isochron IN + 3 Isochron OUT"
195};
196
197
198typedef struct {
199 int vendor; // vendor id
200 int prod_id; // product id
201 char *vend_name; // vendor string
202 __u8 led_scheme; // led display scheme
203 signed short led_bits[8]; // array of 8 possible LED bitmask settings
204} vendor_data;
205
206#define LED_OFF 0 // no LED support
207#define LED_SCHEME1 1 // LED standard scheme
208#define LED_SCHEME2 2 // not used yet...
209
210#define LED_POWER_ON 1
211#define LED_POWER_OFF 2
212#define LED_S0_ON 3
213#define LED_S0_OFF 4
214#define LED_B1_ON 5
215#define LED_B1_OFF 6
216#define LED_B1_DATA 7
217#define LED_B2_ON 8
218#define LED_B2_OFF 9
219#define LED_B2_DATA 10
220
221#define LED_NORMAL 0 // LEDs are normal
222#define LED_INVERTED 1 // LEDs are inverted
223
224/* time in ms to perform a Flashing LED when B-Channel has traffic */
225#define LED_TIME 250
226
227
228#endif // __HFC_USB_H__
diff --git a/drivers/isdn/hisax/hfcscard.c b/drivers/isdn/hisax/hfcscard.c
new file mode 100644
index 000000000000..6fc55fea1702
--- /dev/null
+++ b/drivers/isdn/hisax/hfcscard.c
@@ -0,0 +1,266 @@
1/* $Id: hfcscard.c,v 1.10.2.4 2004/01/14 16:04:48 keil Exp $
2 *
3 * low level stuff for hfcs based cards (Teles3c, ACER P10)
4 *
5 * Author Karsten Keil
6 * Copyright by Karsten Keil <keil@isdn4linux.de>
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 */
12
13#include <linux/init.h>
14#include <linux/isapnp.h>
15#include "hisax.h"
16#include "hfc_2bds0.h"
17#include "isdnl1.h"
18
19extern const char *CardType[];
20
21static const char *hfcs_revision = "$Revision: 1.10.2.4 $";
22
23static irqreturn_t
24hfcs_interrupt(int intno, void *dev_id, struct pt_regs *regs)
25{
26 struct IsdnCardState *cs = dev_id;
27 u_char val, stat;
28 u_long flags;
29
30 spin_lock_irqsave(&cs->lock, flags);
31 if ((HFCD_ANYINT | HFCD_BUSY_NBUSY) &
32 (stat = cs->BC_Read_Reg(cs, HFCD_DATA, HFCD_STAT))) {
33 val = cs->BC_Read_Reg(cs, HFCD_DATA, HFCD_INT_S1);
34 if (cs->debug & L1_DEB_ISAC)
35 debugl1(cs, "HFCS: stat(%02x) s1(%02x)", stat, val);
36 hfc2bds0_interrupt(cs, val);
37 } else {
38 if (cs->debug & L1_DEB_ISAC)
39 debugl1(cs, "HFCS: irq_no_irq stat(%02x)", stat);
40 }
41 spin_unlock_irqrestore(&cs->lock, flags);
42 return IRQ_HANDLED;
43}
44
45static void
46hfcs_Timer(struct IsdnCardState *cs)
47{
48 cs->hw.hfcD.timer.expires = jiffies + 75;
49 /* WD RESET */
50/* WriteReg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcD.ctmt | 0x80);
51 add_timer(&cs->hw.hfcD.timer);
52*/
53}
54
55void
56release_io_hfcs(struct IsdnCardState *cs)
57{
58 release2bds0(cs);
59 del_timer(&cs->hw.hfcD.timer);
60 if (cs->hw.hfcD.addr)
61 release_region(cs->hw.hfcD.addr, 2);
62}
63
64static void
65reset_hfcs(struct IsdnCardState *cs)
66{
67 printk(KERN_INFO "HFCS: resetting card\n");
68 cs->hw.hfcD.cirm = HFCD_RESET;
69 if (cs->typ == ISDN_CTYPE_TELES3C)
70 cs->hw.hfcD.cirm |= HFCD_MEM8K;
71 cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm); /* Reset On */
72 mdelay(10);
73 cs->hw.hfcD.cirm = 0;
74 if (cs->typ == ISDN_CTYPE_TELES3C)
75 cs->hw.hfcD.cirm |= HFCD_MEM8K;
76 cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm); /* Reset Off */
77 mdelay(10);
78 if (cs->typ == ISDN_CTYPE_TELES3C)
79 cs->hw.hfcD.cirm |= HFCD_INTB;
80 else if (cs->typ == ISDN_CTYPE_ACERP10)
81 cs->hw.hfcD.cirm |= HFCD_INTA;
82 cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm);
83 cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CLKDEL, 0x0e);
84 cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_TEST, HFCD_AUTO_AWAKE); /* S/T Auto awake */
85 cs->hw.hfcD.ctmt = HFCD_TIM25 | HFCD_AUTO_TIMER;
86 cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcD.ctmt);
87 cs->hw.hfcD.int_m2 = HFCD_IRQ_ENABLE;
88 cs->hw.hfcD.int_m1 = HFCD_INTS_B1TRANS | HFCD_INTS_B2TRANS |
89 HFCD_INTS_DTRANS | HFCD_INTS_B1REC | HFCD_INTS_B2REC |
90 HFCD_INTS_DREC | HFCD_INTS_L1STATE;
91 cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_INT_M1, cs->hw.hfcD.int_m1);
92 cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_INT_M2, cs->hw.hfcD.int_m2);
93 cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_STATES, HFCD_LOAD_STATE | 2); /* HFC ST 2 */
94 udelay(10);
95 cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_STATES, 2); /* HFC ST 2 */
96 cs->hw.hfcD.mst_m = HFCD_MASTER;
97 cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_MST_MODE, cs->hw.hfcD.mst_m); /* HFC Master */
98 cs->hw.hfcD.sctrl = 0;
99 cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_SCTRL, cs->hw.hfcD.sctrl);
100}
101
102static int
103hfcs_card_msg(struct IsdnCardState *cs, int mt, void *arg)
104{
105 u_long flags;
106 int delay;
107
108 if (cs->debug & L1_DEB_ISAC)
109 debugl1(cs, "HFCS: card_msg %x", mt);
110 switch (mt) {
111 case CARD_RESET:
112 spin_lock_irqsave(&cs->lock, flags);
113 reset_hfcs(cs);
114 spin_unlock_irqrestore(&cs->lock, flags);
115 return(0);
116 case CARD_RELEASE:
117 release_io_hfcs(cs);
118 return(0);
119 case CARD_INIT:
120 delay = (75*HZ)/100 +1;
121 cs->hw.hfcD.timer.expires = jiffies + delay;
122 add_timer(&cs->hw.hfcD.timer);
123 spin_lock_irqsave(&cs->lock, flags);
124 reset_hfcs(cs);
125 init2bds0(cs);
126 spin_unlock_irqrestore(&cs->lock, flags);
127 delay = (80*HZ)/1000 +1;
128 msleep(80);
129 spin_lock_irqsave(&cs->lock, flags);
130 cs->hw.hfcD.ctmt |= HFCD_TIM800;
131 cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcD.ctmt);
132 cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_MST_MODE, cs->hw.hfcD.mst_m);
133 spin_unlock_irqrestore(&cs->lock, flags);
134 return(0);
135 case CARD_TEST:
136 return(0);
137 }
138 return(0);
139}
140
141#ifdef __ISAPNP__
142static struct isapnp_device_id hfc_ids[] __initdata = {
143 { ISAPNP_VENDOR('A', 'N', 'X'), ISAPNP_FUNCTION(0x1114),
144 ISAPNP_VENDOR('A', 'N', 'X'), ISAPNP_FUNCTION(0x1114),
145 (unsigned long) "Acer P10" },
146 { ISAPNP_VENDOR('B', 'I', 'L'), ISAPNP_FUNCTION(0x0002),
147 ISAPNP_VENDOR('B', 'I', 'L'), ISAPNP_FUNCTION(0x0002),
148 (unsigned long) "Billion 2" },
149 { ISAPNP_VENDOR('B', 'I', 'L'), ISAPNP_FUNCTION(0x0001),
150 ISAPNP_VENDOR('B', 'I', 'L'), ISAPNP_FUNCTION(0x0001),
151 (unsigned long) "Billion 1" },
152 { ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x7410),
153 ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x7410),
154 (unsigned long) "IStar PnP" },
155 { ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2610),
156 ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2610),
157 (unsigned long) "Teles 16.3c" },
158 { ISAPNP_VENDOR('S', 'F', 'M'), ISAPNP_FUNCTION(0x0001),
159 ISAPNP_VENDOR('S', 'F', 'M'), ISAPNP_FUNCTION(0x0001),
160 (unsigned long) "Tornado Tipa C" },
161 { ISAPNP_VENDOR('K', 'Y', 'E'), ISAPNP_FUNCTION(0x0001),
162 ISAPNP_VENDOR('K', 'Y', 'E'), ISAPNP_FUNCTION(0x0001),
163 (unsigned long) "Genius Speed Surfer" },
164 { 0, }
165};
166
167static struct isapnp_device_id *ipid __initdata = &hfc_ids[0];
168static struct pnp_card *pnp_c __devinitdata = NULL;
169#endif
170
171int __init
172setup_hfcs(struct IsdnCard *card)
173{
174 struct IsdnCardState *cs = card->cs;
175 char tmp[64];
176
177 strcpy(tmp, hfcs_revision);
178 printk(KERN_INFO "HiSax: HFC-S driver Rev. %s\n", HiSax_getrev(tmp));
179
180#ifdef __ISAPNP__
181 if (!card->para[1] && isapnp_present()) {
182 struct pnp_dev *pnp_d;
183 while(ipid->card_vendor) {
184 if ((pnp_c = pnp_find_card(ipid->card_vendor,
185 ipid->card_device, pnp_c))) {
186 pnp_d = NULL;
187 if ((pnp_d = pnp_find_dev(pnp_c,
188 ipid->vendor, ipid->function, pnp_d))) {
189 int err;
190
191 printk(KERN_INFO "HiSax: %s detected\n",
192 (char *)ipid->driver_data);
193 pnp_disable_dev(pnp_d);
194 err = pnp_activate_dev(pnp_d);
195 if (err<0) {
196 printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
197 __FUNCTION__, err);
198 return(0);
199 }
200 card->para[1] = pnp_port_start(pnp_d, 0);
201 card->para[0] = pnp_irq(pnp_d, 0);
202 if (!card->para[0] || !card->para[1]) {
203 printk(KERN_ERR "HFC PnP:some resources are missing %ld/%lx\n",
204 card->para[0], card->para[1]);
205 pnp_disable_dev(pnp_d);
206 return(0);
207 }
208 break;
209 } else {
210 printk(KERN_ERR "HFC PnP: PnP error card found, no device\n");
211 }
212 }
213 ipid++;
214 pnp_c = NULL;
215 }
216 if (!ipid->card_vendor) {
217 printk(KERN_INFO "HFC PnP: no ISAPnP card found\n");
218 return(0);
219 }
220 }
221#endif
222 cs->hw.hfcD.addr = card->para[1] & 0xfffe;
223 cs->irq = card->para[0];
224 cs->hw.hfcD.cip = 0;
225 cs->hw.hfcD.int_s1 = 0;
226 cs->hw.hfcD.send = NULL;
227 cs->bcs[0].hw.hfc.send = NULL;
228 cs->bcs[1].hw.hfc.send = NULL;
229 cs->hw.hfcD.dfifosize = 512;
230 cs->dc.hfcd.ph_state = 0;
231 cs->hw.hfcD.fifo = 255;
232 if (cs->typ == ISDN_CTYPE_TELES3C) {
233 cs->hw.hfcD.bfifosize = 1024 + 512;
234 } else if (cs->typ == ISDN_CTYPE_ACERP10) {
235 cs->hw.hfcD.bfifosize = 7*1024 + 512;
236 } else
237 return (0);
238 if (!request_region(cs->hw.hfcD.addr, 2, "HFCS isdn")) {
239 printk(KERN_WARNING
240 "HiSax: %s config port %x-%x already in use\n",
241 CardType[card->typ],
242 cs->hw.hfcD.addr,
243 cs->hw.hfcD.addr + 2);
244 return (0);
245 }
246 printk(KERN_INFO
247 "HFCS: defined at 0x%x IRQ %d HZ %d\n",
248 cs->hw.hfcD.addr,
249 cs->irq, HZ);
250 if (cs->typ == ISDN_CTYPE_TELES3C) {
251 /* Teles 16.3c IO ADR is 0x200 | YY0U (YY Bit 15/14 address) */
252 outb(0x00, cs->hw.hfcD.addr);
253 outb(0x56, cs->hw.hfcD.addr | 1);
254 } else if (cs->typ == ISDN_CTYPE_ACERP10) {
255 /* Acer P10 IO ADR is 0x300 */
256 outb(0x00, cs->hw.hfcD.addr);
257 outb(0x57, cs->hw.hfcD.addr | 1);
258 }
259 set_cs_func(cs);
260 cs->hw.hfcD.timer.function = (void *) hfcs_Timer;
261 cs->hw.hfcD.timer.data = (long) cs;
262 init_timer(&cs->hw.hfcD.timer);
263 cs->cardmsg = &hfcs_card_msg;
264 cs->irq_func = &hfcs_interrupt;
265 return (1);
266}
diff --git a/drivers/isdn/hisax/hisax.h b/drivers/isdn/hisax/hisax.h
new file mode 100644
index 000000000000..dc5791728d53
--- /dev/null
+++ b/drivers/isdn/hisax/hisax.h
@@ -0,0 +1,1341 @@
1/* $Id: hisax.h,v 2.64.2.4 2004/02/11 13:21:33 keil Exp $
2 *
3 * Basic declarations, defines and prototypes
4 *
5 * This software may be used and distributed according to the terms
6 * of the GNU General Public License, incorporated herein by reference.
7 *
8 */
9#include <linux/config.h>
10#include <linux/errno.h>
11#include <linux/fs.h>
12#include <linux/major.h>
13#include <asm/segment.h>
14#include <asm/io.h>
15#include <linux/delay.h>
16#include <linux/kernel.h>
17#include <linux/signal.h>
18#include <linux/slab.h>
19#include <linux/mm.h>
20#include <linux/mman.h>
21#include <linux/ioport.h>
22#include <linux/timer.h>
23#include <linux/wait.h>
24#include <linux/isdnif.h>
25#include <linux/tty.h>
26#include <linux/serial_reg.h>
27#include <linux/netdevice.h>
28
29#define ERROR_STATISTIC
30
31#define REQUEST 0
32#define CONFIRM 1
33#define INDICATION 2
34#define RESPONSE 3
35
36#define HW_ENABLE 0x0000
37#define HW_RESET 0x0004
38#define HW_POWERUP 0x0008
39#define HW_ACTIVATE 0x0010
40#define HW_DEACTIVATE 0x0018
41
42#define HW_INFO1 0x0010
43#define HW_INFO2 0x0020
44#define HW_INFO3 0x0030
45#define HW_INFO4 0x0040
46#define HW_INFO4_P8 0x0040
47#define HW_INFO4_P10 0x0048
48#define HW_RSYNC 0x0060
49#define HW_TESTLOOP 0x0070
50#define CARD_RESET 0x00F0
51#define CARD_INIT 0x00F2
52#define CARD_RELEASE 0x00F3
53#define CARD_TEST 0x00F4
54#define CARD_AUX_IND 0x00F5
55
56#define PH_ACTIVATE 0x0100
57#define PH_DEACTIVATE 0x0110
58#define PH_DATA 0x0120
59#define PH_PULL 0x0130
60#define PH_TESTLOOP 0x0140
61#define PH_PAUSE 0x0150
62#define MPH_ACTIVATE 0x0180
63#define MPH_DEACTIVATE 0x0190
64#define MPH_INFORMATION 0x01A0
65
66#define DL_ESTABLISH 0x0200
67#define DL_RELEASE 0x0210
68#define DL_DATA 0x0220
69#define DL_FLUSH 0x0224
70#define DL_UNIT_DATA 0x0230
71
72#define MDL_BC_RELEASE 0x0278 // Formula-n enter:now
73#define MDL_BC_ASSIGN 0x027C // Formula-n enter:now
74#define MDL_ASSIGN 0x0280
75#define MDL_REMOVE 0x0284
76#define MDL_ERROR 0x0288
77#define MDL_INFO_SETUP 0x02E0
78#define MDL_INFO_CONN 0x02E4
79#define MDL_INFO_REL 0x02E8
80
81#define CC_SETUP 0x0300
82#define CC_RESUME 0x0304
83#define CC_MORE_INFO 0x0310
84#define CC_IGNORE 0x0320
85#define CC_REJECT 0x0324
86#define CC_SETUP_COMPL 0x0330
87#define CC_PROCEEDING 0x0340
88#define CC_ALERTING 0x0344
89#define CC_PROGRESS 0x0348
90#define CC_CONNECT 0x0350
91#define CC_CHARGE 0x0354
92#define CC_NOTIFY 0x0358
93#define CC_DISCONNECT 0x0360
94#define CC_RELEASE 0x0368
95#define CC_SUSPEND 0x0370
96#define CC_PROCEED_SEND 0x0374
97#define CC_REDIR 0x0378
98#define CC_T302 0x0382
99#define CC_T303 0x0383
100#define CC_T304 0x0384
101#define CC_T305 0x0385
102#define CC_T308_1 0x0388
103#define CC_T308_2 0x038A
104#define CC_T309 0x0309
105#define CC_T310 0x0390
106#define CC_T313 0x0393
107#define CC_T318 0x0398
108#define CC_T319 0x0399
109#define CC_TSPID 0x03A0
110#define CC_NOSETUP_RSP 0x03E0
111#define CC_SETUP_ERR 0x03E1
112#define CC_SUSPEND_ERR 0x03E2
113#define CC_RESUME_ERR 0x03E3
114#define CC_CONNECT_ERR 0x03E4
115#define CC_RELEASE_ERR 0x03E5
116#define CC_RESTART 0x03F4
117#define CC_TDSS1_IO 0x13F4 /* DSS1 IO user timer */
118#define CC_TNI1_IO 0x13F5 /* NI1 IO user timer */
119
120/* define maximum number of possible waiting incoming calls */
121#define MAX_WAITING_CALLS 2
122
123
124#ifdef __KERNEL__
125
126/* include l3dss1 & ni1 specific process structures, but no other defines */
127#ifdef CONFIG_HISAX_EURO
128 #define l3dss1_process
129 #include "l3dss1.h"
130 #undef l3dss1_process
131#endif /* CONFIG_HISAX_EURO */
132
133#ifdef CONFIG_HISAX_NI1
134 #define l3ni1_process
135 #include "l3ni1.h"
136 #undef l3ni1_process
137#endif /* CONFIG_HISAX_NI1 */
138
139#define MAX_DFRAME_LEN 260
140#define MAX_DFRAME_LEN_L1 300
141#define HSCX_BUFMAX 4096
142#define MAX_DATA_SIZE (HSCX_BUFMAX - 4)
143#define MAX_DATA_MEM (HSCX_BUFMAX + 64)
144#define RAW_BUFMAX (((HSCX_BUFMAX*6)/5) + 5)
145#define MAX_HEADER_LEN 4
146#define MAX_WINDOW 8
147#define MAX_MON_FRAME 32
148#define MAX_DLOG_SPACE 2048
149#define MAX_BLOG_SPACE 256
150
151/* #define I4L_IRQ_FLAG SA_INTERRUPT */
152#define I4L_IRQ_FLAG 0
153
154/*
155 * Statemachine
156 */
157
158struct FsmInst;
159
160typedef void (* FSMFNPTR)(struct FsmInst *, int, void *);
161
162struct Fsm {
163 FSMFNPTR *jumpmatrix;
164 int state_count, event_count;
165 char **strEvent, **strState;
166};
167
168struct FsmInst {
169 struct Fsm *fsm;
170 int state;
171 int debug;
172 void *userdata;
173 int userint;
174 void (*printdebug) (struct FsmInst *, char *, ...);
175};
176
177struct FsmNode {
178 int state, event;
179 void (*routine) (struct FsmInst *, int, void *);
180};
181
182struct FsmTimer {
183 struct FsmInst *fi;
184 struct timer_list tl;
185 int event;
186 void *arg;
187};
188
189struct L3Timer {
190 struct l3_process *pc;
191 struct timer_list tl;
192 int event;
193};
194
195#define FLG_L1_ACTIVATING 1
196#define FLG_L1_ACTIVATED 2
197#define FLG_L1_DEACTTIMER 3
198#define FLG_L1_ACTTIMER 4
199#define FLG_L1_T3RUN 5
200#define FLG_L1_PULL_REQ 6
201#define FLG_L1_UINT 7
202
203struct Layer1 {
204 void *hardware;
205 struct BCState *bcs;
206 struct PStack **stlistp;
207 long Flags;
208 struct FsmInst l1m;
209 struct FsmTimer timer;
210 void (*l1l2) (struct PStack *, int, void *);
211 void (*l1hw) (struct PStack *, int, void *);
212 void (*l1tei) (struct PStack *, int, void *);
213 int mode, bc;
214 int delay;
215};
216
217#define GROUP_TEI 127
218#define TEI_SAPI 63
219#define CTRL_SAPI 0
220#define PACKET_NOACK 250
221
222/* Layer2 Flags */
223
224#define FLG_LAPB 0
225#define FLG_LAPD 1
226#define FLG_ORIG 2
227#define FLG_MOD128 3
228#define FLG_PEND_REL 4
229#define FLG_L3_INIT 5
230#define FLG_T200_RUN 6
231#define FLG_ACK_PEND 7
232#define FLG_REJEXC 8
233#define FLG_OWN_BUSY 9
234#define FLG_PEER_BUSY 10
235#define FLG_DCHAN_BUSY 11
236#define FLG_L1_ACTIV 12
237#define FLG_ESTAB_PEND 13
238#define FLG_PTP 14
239#define FLG_FIXED_TEI 15
240#define FLG_L2BLOCK 16
241
242struct Layer2 {
243 int tei;
244 int sap;
245 int maxlen;
246 u_long flag;
247 spinlock_t lock;
248 u_int vs, va, vr;
249 int rc;
250 unsigned int window;
251 unsigned int sow;
252 struct sk_buff *windowar[MAX_WINDOW];
253 struct sk_buff_head i_queue;
254 struct sk_buff_head ui_queue;
255 void (*l2l1) (struct PStack *, int, void *);
256 void (*l2l3) (struct PStack *, int, void *);
257 void (*l2tei) (struct PStack *, int, void *);
258 struct FsmInst l2m;
259 struct FsmTimer t200, t203;
260 int T200, N200, T203;
261 int debug;
262 char debug_id[16];
263};
264
265struct Layer3 {
266 void (*l3l4) (struct PStack *, int, void *);
267 void (*l3ml3) (struct PStack *, int, void *);
268 void (*l3l2) (struct PStack *, int, void *);
269 struct FsmInst l3m;
270 struct FsmTimer l3m_timer;
271 struct sk_buff_head squeue;
272 struct l3_process *proc;
273 struct l3_process *global;
274 int N303;
275 int debug;
276 char debug_id[8];
277};
278
279struct LLInterface {
280 void (*l4l3) (struct PStack *, int, void *);
281 int (*l4l3_proto) (struct PStack *, isdn_ctrl *);
282 void *userdata;
283 u_long flag;
284};
285
286#define FLG_LLI_L1WAKEUP 1
287#define FLG_LLI_L2WAKEUP 2
288
289struct Management {
290 int ri;
291 struct FsmInst tei_m;
292 struct FsmTimer t202;
293 int T202, N202, debug;
294 void (*layer) (struct PStack *, int, void *);
295};
296
297#define NO_CAUSE 254
298
299struct Param {
300 u_char cause;
301 u_char loc;
302 u_char diag[6];
303 int bchannel;
304 int chargeinfo;
305 int spv; /* SPV Flag */
306 setup_parm setup; /* from isdnif.h numbers and Serviceindicator */
307 u_char moderate; /* transfer mode and rate (bearer octet 4) */
308};
309
310
311struct PStack {
312 struct PStack *next;
313 struct Layer1 l1;
314 struct Layer2 l2;
315 struct Layer3 l3;
316 struct LLInterface lli;
317 struct Management ma;
318 int protocol; /* EDSS1, 1TR6 or NI1 */
319
320 /* protocol specific data fields */
321 union
322 { u_char uuuu; /* only as dummy */
323#ifdef CONFIG_HISAX_EURO
324 dss1_stk_priv dss1; /* private dss1 data */
325#endif /* CONFIG_HISAX_EURO */
326#ifdef CONFIG_HISAX_NI1
327 ni1_stk_priv ni1; /* private ni1 data */
328#endif /* CONFIG_HISAX_NI1 */
329 } prot;
330};
331
332struct l3_process {
333 int callref;
334 int state;
335 struct L3Timer timer;
336 int N303;
337 int debug;
338 struct Param para;
339 struct Channel *chan;
340 struct PStack *st;
341 struct l3_process *next;
342 ulong redir_result;
343
344 /* protocol specific data fields */
345 union
346 { u_char uuuu; /* only when euro not defined, avoiding empty union */
347#ifdef CONFIG_HISAX_EURO
348 dss1_proc_priv dss1; /* private dss1 data */
349#endif /* CONFIG_HISAX_EURO */
350#ifdef CONFIG_HISAX_NI1
351 ni1_proc_priv ni1; /* private ni1 data */
352#endif /* CONFIG_HISAX_NI1 */
353 } prot;
354};
355
356struct hscx_hw {
357 int hscx;
358 int rcvidx;
359 int count; /* Current skb sent count */
360 u_char *rcvbuf; /* B-Channel receive Buffer */
361 u_char tsaxr0;
362 u_char tsaxr1;
363};
364
365struct w6692B_hw {
366 int bchan;
367 int rcvidx;
368 int count; /* Current skb sent count */
369 u_char *rcvbuf; /* B-Channel receive Buffer */
370};
371
372struct isar_reg {
373 unsigned long Flags;
374 volatile u_char bstat;
375 volatile u_char iis;
376 volatile u_char cmsb;
377 volatile u_char clsb;
378 volatile u_char par[8];
379};
380
381struct isar_hw {
382 int dpath;
383 int rcvidx;
384 int txcnt;
385 int mml;
386 u_char state;
387 u_char cmd;
388 u_char mod;
389 u_char newcmd;
390 u_char newmod;
391 char try_mod;
392 struct timer_list ftimer;
393 u_char *rcvbuf; /* B-Channel receive Buffer */
394 u_char conmsg[16];
395 struct isar_reg *reg;
396};
397
398struct hdlc_stat_reg {
399#ifdef __BIG_ENDIAN
400 u_char fill __attribute__((packed));
401 u_char mode __attribute__((packed));
402 u_char xml __attribute__((packed));
403 u_char cmd __attribute__((packed));
404#else
405 u_char cmd __attribute__((packed));
406 u_char xml __attribute__((packed));
407 u_char mode __attribute__((packed));
408 u_char fill __attribute__((packed));
409#endif
410};
411
412struct hdlc_hw {
413 union {
414 u_int ctrl;
415 struct hdlc_stat_reg sr;
416 } ctrl;
417 u_int stat;
418 int rcvidx;
419 int count; /* Current skb sent count */
420 u_char *rcvbuf; /* B-Channel receive Buffer */
421};
422
423struct hfcB_hw {
424 unsigned int *send;
425 int f1;
426 int f2;
427};
428
429struct tiger_hw {
430 u_int *send;
431 u_int *s_irq;
432 u_int *s_end;
433 u_int *sendp;
434 u_int *rec;
435 int free;
436 u_char *rcvbuf;
437 u_char *sendbuf;
438 u_char *sp;
439 int sendcnt;
440 u_int s_tot;
441 u_int r_bitcnt;
442 u_int r_tot;
443 u_int r_err;
444 u_int r_fcs;
445 u_char r_state;
446 u_char r_one;
447 u_char r_val;
448 u_char s_state;
449};
450
451struct amd7930_hw {
452 u_char *tx_buff;
453 u_char *rv_buff;
454 int rv_buff_in;
455 int rv_buff_out;
456 struct sk_buff *rv_skb;
457 struct hdlc_state *hdlc_state;
458 struct work_struct tq_rcv;
459 struct work_struct tq_xmt;
460};
461
462#define BC_FLG_INIT 1
463#define BC_FLG_ACTIV 2
464#define BC_FLG_BUSY 3
465#define BC_FLG_NOFRAME 4
466#define BC_FLG_HALF 5
467#define BC_FLG_EMPTY 6
468#define BC_FLG_ORIG 7
469#define BC_FLG_DLEETX 8
470#define BC_FLG_LASTDLE 9
471#define BC_FLG_FIRST 10
472#define BC_FLG_LASTDATA 11
473#define BC_FLG_NMD_DATA 12
474#define BC_FLG_FTI_RUN 13
475#define BC_FLG_LL_OK 14
476#define BC_FLG_LL_CONN 15
477#define BC_FLG_FTI_FTS 16
478#define BC_FLG_FRH_WAIT 17
479
480#define L1_MODE_NULL 0
481#define L1_MODE_TRANS 1
482#define L1_MODE_HDLC 2
483#define L1_MODE_EXTRN 3
484#define L1_MODE_HDLC_56K 4
485#define L1_MODE_MODEM 7
486#define L1_MODE_V32 8
487#define L1_MODE_FAX 9
488
489struct BCState {
490 int channel;
491 int mode;
492 u_long Flag;
493 struct IsdnCardState *cs;
494 int tx_cnt; /* B-Channel transmit counter */
495 struct sk_buff *tx_skb; /* B-Channel transmit Buffer */
496 struct sk_buff_head rqueue; /* B-Channel receive Queue */
497 struct sk_buff_head squeue; /* B-Channel send Queue */
498 int ackcnt;
499 spinlock_t aclock;
500 struct PStack *st;
501 u_char *blog;
502 u_char *conmsg;
503 struct timer_list transbusy;
504 struct work_struct tqueue;
505 u_long event;
506 int (*BC_SetStack) (struct PStack *, struct BCState *);
507 void (*BC_Close) (struct BCState *);
508#ifdef ERROR_STATISTIC
509 int err_crc;
510 int err_tx;
511 int err_rdo;
512 int err_inv;
513#endif
514 union {
515 struct hscx_hw hscx;
516 struct hdlc_hw hdlc;
517 struct isar_hw isar;
518 struct hfcB_hw hfc;
519 struct tiger_hw tiger;
520 struct amd7930_hw amd7930;
521 struct w6692B_hw w6692;
522 struct hisax_b_if *b_if;
523 } hw;
524};
525
526struct Channel {
527 struct PStack *b_st, *d_st;
528 struct IsdnCardState *cs;
529 struct BCState *bcs;
530 int chan;
531 int incoming;
532 struct FsmInst fi;
533 struct FsmTimer drel_timer, dial_timer;
534 int debug;
535 int l2_protocol, l2_active_protocol;
536 int l3_protocol;
537 int data_open;
538 struct l3_process *proc;
539 setup_parm setup; /* from isdnif.h numbers and Serviceindicator */
540 u_long Flags; /* for remembering action done in l4 */
541 int leased;
542};
543
544struct elsa_hw {
545 struct pci_dev *dev;
546 unsigned long base;
547 unsigned int cfg;
548 unsigned int ctrl;
549 unsigned int ale;
550 unsigned int isac;
551 unsigned int itac;
552 unsigned int hscx;
553 unsigned int trig;
554 unsigned int timer;
555 unsigned int counter;
556 unsigned int status;
557 struct timer_list tl;
558 unsigned int MFlag;
559 struct BCState *bcs;
560 u_char *transbuf;
561 u_char *rcvbuf;
562 unsigned int transp;
563 unsigned int rcvp;
564 unsigned int transcnt;
565 unsigned int rcvcnt;
566 u_char IER;
567 u_char FCR;
568 u_char LCR;
569 u_char MCR;
570 u_char ctrl_reg;
571};
572
573struct teles3_hw {
574 unsigned int cfg_reg;
575 signed int isac;
576 signed int hscx[2];
577 signed int isacfifo;
578 signed int hscxfifo[2];
579};
580
581struct teles0_hw {
582 unsigned int cfg_reg;
583 void __iomem *membase;
584 unsigned long phymem;
585};
586
587struct avm_hw {
588 unsigned int cfg_reg;
589 unsigned int isac;
590 unsigned int hscx[2];
591 unsigned int isacfifo;
592 unsigned int hscxfifo[2];
593 unsigned int counter;
594 struct pci_dev *dev;
595};
596
597struct ix1_hw {
598 unsigned int cfg_reg;
599 unsigned int isac_ale;
600 unsigned int isac;
601 unsigned int hscx_ale;
602 unsigned int hscx;
603};
604
605struct diva_hw {
606 unsigned long cfg_reg;
607 unsigned long pci_cfg;
608 unsigned int ctrl;
609 unsigned long isac_adr;
610 unsigned int isac;
611 unsigned long hscx_adr;
612 unsigned int hscx;
613 unsigned int status;
614 struct timer_list tl;
615 u_char ctrl_reg;
616 struct pci_dev *dev;
617};
618
619struct asus_hw {
620 unsigned int cfg_reg;
621 unsigned int adr;
622 unsigned int isac;
623 unsigned int hscx;
624 unsigned int u7;
625 unsigned int pots;
626};
627
628
629struct hfc_hw {
630 unsigned int addr;
631 unsigned int fifosize;
632 unsigned char cirm;
633 unsigned char ctmt;
634 unsigned char cip;
635 u_char isac_spcr;
636 struct timer_list timer;
637};
638
639struct sedl_hw {
640 unsigned int cfg_reg;
641 unsigned int adr;
642 unsigned int isac;
643 unsigned int hscx;
644 unsigned int reset_on;
645 unsigned int reset_off;
646 struct isar_reg isar;
647 unsigned int chip;
648 unsigned int bus;
649 struct pci_dev *dev;
650};
651
652struct spt_hw {
653 unsigned int cfg_reg;
654 unsigned int isac;
655 unsigned int hscx[2];
656 unsigned char res_irq;
657};
658
659struct mic_hw {
660 unsigned int cfg_reg;
661 unsigned int adr;
662 unsigned int isac;
663 unsigned int hscx;
664};
665
666struct njet_hw {
667 unsigned long base;
668 unsigned int isac;
669 unsigned int auxa;
670 unsigned char auxd;
671 unsigned char dmactrl;
672 unsigned char ctrl_reg;
673 unsigned char irqmask0;
674 unsigned char irqstat0;
675 unsigned char last_is0;
676 struct pci_dev *dev;
677};
678
679struct hfcPCI_hw {
680 unsigned char cirm;
681 unsigned char ctmt;
682 unsigned char conn;
683 unsigned char mst_m;
684 unsigned char int_m1;
685 unsigned char int_m2;
686 unsigned char int_s1;
687 unsigned char sctrl;
688 unsigned char sctrl_r;
689 unsigned char sctrl_e;
690 unsigned char trm;
691 unsigned char stat;
692 unsigned char fifo;
693 unsigned char fifo_en;
694 unsigned char bswapped;
695 unsigned char nt_mode;
696 int nt_timer;
697 struct pci_dev *dev;
698 unsigned char *pci_io; /* start of PCI IO memory */
699 void *share_start; /* shared memory for Fifos start */
700 void *fifos; /* FIFO memory */
701 int last_bfifo_cnt[2]; /* marker saving last b-fifo frame count */
702 struct timer_list timer;
703};
704
705struct hfcSX_hw {
706 unsigned long base;
707 unsigned char cirm;
708 unsigned char ctmt;
709 unsigned char conn;
710 unsigned char mst_m;
711 unsigned char int_m1;
712 unsigned char int_m2;
713 unsigned char int_s1;
714 unsigned char sctrl;
715 unsigned char sctrl_r;
716 unsigned char sctrl_e;
717 unsigned char trm;
718 unsigned char stat;
719 unsigned char fifo;
720 unsigned char bswapped;
721 unsigned char nt_mode;
722 unsigned char chip;
723 int b_fifo_size;
724 unsigned char last_fifo;
725 void *extra;
726 int nt_timer;
727 struct timer_list timer;
728};
729
730struct hfcD_hw {
731 unsigned int addr;
732 unsigned int bfifosize;
733 unsigned int dfifosize;
734 unsigned char cirm;
735 unsigned char ctmt;
736 unsigned char cip;
737 unsigned char conn;
738 unsigned char mst_m;
739 unsigned char int_m1;
740 unsigned char int_m2;
741 unsigned char int_s1;
742 unsigned char sctrl;
743 unsigned char stat;
744 unsigned char fifo;
745 unsigned char f1;
746 unsigned char f2;
747 unsigned int *send;
748 struct timer_list timer;
749};
750
751struct isurf_hw {
752 unsigned int reset;
753 unsigned long phymem;
754 void __iomem *isac;
755 void __iomem *isar;
756 struct isar_reg isar_r;
757};
758
759struct saphir_hw {
760 struct pci_dev *dev;
761 unsigned int cfg_reg;
762 unsigned int ale;
763 unsigned int isac;
764 unsigned int hscx;
765 struct timer_list timer;
766};
767
768struct bkm_hw {
769 struct pci_dev *dev;
770 unsigned long base;
771 /* A4T stuff */
772 unsigned long isac_adr;
773 unsigned int isac_ale;
774 unsigned long jade_adr;
775 unsigned int jade_ale;
776 /* Scitel Quadro stuff */
777 unsigned long plx_adr;
778 unsigned long data_adr;
779};
780
781struct gazel_hw {
782 struct pci_dev *dev;
783 unsigned int cfg_reg;
784 unsigned int pciaddr[2];
785 signed int ipac;
786 signed int isac;
787 signed int hscx[2];
788 signed int isacfifo;
789 signed int hscxfifo[2];
790 unsigned char timeslot;
791 unsigned char iom2;
792};
793
794struct w6692_hw {
795 struct pci_dev *dev;
796 unsigned int iobase;
797 struct timer_list timer;
798};
799
800#ifdef CONFIG_HISAX_TESTEMU
801struct te_hw {
802 unsigned char *sfifo;
803 unsigned char *sfifo_w;
804 unsigned char *sfifo_r;
805 unsigned char *sfifo_e;
806 int sfifo_cnt;
807 unsigned int stat;
808 wait_queue_head_t rwaitq;
809 wait_queue_head_t swaitq;
810};
811#endif
812
813struct arcofi_msg {
814 struct arcofi_msg *next;
815 u_char receive;
816 u_char len;
817 u_char msg[10];
818};
819
820struct isac_chip {
821 int ph_state;
822 u_char *mon_tx;
823 u_char *mon_rx;
824 int mon_txp;
825 int mon_txc;
826 int mon_rxp;
827 struct arcofi_msg *arcofi_list;
828 struct timer_list arcofitimer;
829 wait_queue_head_t arcofi_wait;
830 u_char arcofi_bc;
831 u_char arcofi_state;
832 u_char mocr;
833 u_char adf2;
834};
835
836struct hfcd_chip {
837 int ph_state;
838};
839
840struct hfcpci_chip {
841 int ph_state;
842};
843
844struct hfcsx_chip {
845 int ph_state;
846};
847
848struct w6692_chip {
849 int ph_state;
850};
851
852struct amd7930_chip {
853 u_char lmr1;
854 u_char ph_state;
855 u_char old_state;
856 u_char flg_t3;
857 unsigned int tx_xmtlen;
858 struct timer_list timer3;
859 void (*ph_command) (struct IsdnCardState *, u_char, char *);
860 void (*setIrqMask) (struct IsdnCardState *, u_char);
861};
862
863struct icc_chip {
864 int ph_state;
865 u_char *mon_tx;
866 u_char *mon_rx;
867 int mon_txp;
868 int mon_txc;
869 int mon_rxp;
870 struct arcofi_msg *arcofi_list;
871 struct timer_list arcofitimer;
872 wait_queue_head_t arcofi_wait;
873 u_char arcofi_bc;
874 u_char arcofi_state;
875 u_char mocr;
876 u_char adf2;
877};
878
879#define HW_IOM1 0
880#define HW_IPAC 1
881#define HW_ISAR 2
882#define HW_ARCOFI 3
883#define FLG_TWO_DCHAN 4
884#define FLG_L1_DBUSY 5
885#define FLG_DBUSY_TIMER 6
886#define FLG_LOCK_ATOMIC 7
887#define FLG_ARCOFI_TIMER 8
888#define FLG_ARCOFI_ERROR 9
889#define FLG_HW_L1_UINT 10
890
891struct IsdnCardState {
892 spinlock_t lock;
893 u_char typ;
894 u_char subtyp;
895 int protocol;
896 u_int irq;
897 u_long irq_flags;
898 u_long HW_Flags;
899 int *busy_flag;
900 int chanlimit; /* limited number of B-chans to use */
901 int logecho; /* log echo if supported by card */
902 union {
903 struct elsa_hw elsa;
904 struct teles0_hw teles0;
905 struct teles3_hw teles3;
906 struct avm_hw avm;
907 struct ix1_hw ix1;
908 struct diva_hw diva;
909 struct asus_hw asus;
910 struct hfc_hw hfc;
911 struct sedl_hw sedl;
912 struct spt_hw spt;
913 struct mic_hw mic;
914 struct njet_hw njet;
915 struct hfcD_hw hfcD;
916 struct hfcPCI_hw hfcpci;
917 struct hfcSX_hw hfcsx;
918 struct ix1_hw niccy;
919 struct isurf_hw isurf;
920 struct saphir_hw saphir;
921#ifdef CONFIG_HISAX_TESTEMU
922 struct te_hw te;
923#endif
924 struct bkm_hw ax;
925 struct gazel_hw gazel;
926 struct w6692_hw w6692;
927 struct hisax_d_if *hisax_d_if;
928 } hw;
929 int myid;
930 isdn_if iif;
931 spinlock_t statlock;
932 u_char *status_buf;
933 u_char *status_read;
934 u_char *status_write;
935 u_char *status_end;
936 u_char (*readisac) (struct IsdnCardState *, u_char);
937 void (*writeisac) (struct IsdnCardState *, u_char, u_char);
938 void (*readisacfifo) (struct IsdnCardState *, u_char *, int);
939 void (*writeisacfifo) (struct IsdnCardState *, u_char *, int);
940 u_char (*BC_Read_Reg) (struct IsdnCardState *, int, u_char);
941 void (*BC_Write_Reg) (struct IsdnCardState *, int, u_char, u_char);
942 void (*BC_Send_Data) (struct BCState *);
943 int (*cardmsg) (struct IsdnCardState *, int, void *);
944 void (*setstack_d) (struct PStack *, struct IsdnCardState *);
945 void (*DC_Close) (struct IsdnCardState *);
946 int (*irq_func) (int, void *, struct pt_regs *);
947 int (*auxcmd) (struct IsdnCardState *, isdn_ctrl *);
948 struct Channel channel[2+MAX_WAITING_CALLS];
949 struct BCState bcs[2+MAX_WAITING_CALLS];
950 struct PStack *stlist;
951 struct sk_buff_head rq, sq; /* D-channel queues */
952 int cardnr;
953 char *dlog;
954 int debug;
955 union {
956 struct isac_chip isac;
957 struct hfcd_chip hfcd;
958 struct hfcpci_chip hfcpci;
959 struct hfcsx_chip hfcsx;
960 struct w6692_chip w6692;
961 struct amd7930_chip amd7930;
962 struct icc_chip icc;
963 } dc;
964 u_char *rcvbuf;
965 int rcvidx;
966 struct sk_buff *tx_skb;
967 int tx_cnt;
968 u_long event;
969 struct work_struct tqueue;
970 struct timer_list dbusytimer;
971#ifdef ERROR_STATISTIC
972 int err_crc;
973 int err_tx;
974 int err_rx;
975#endif
976};
977
978
979#define schedule_event(s, ev) do {test_and_set_bit(ev, &s->event);schedule_work(&s->tqueue); } while(0)
980
981#define MON0_RX 1
982#define MON1_RX 2
983#define MON0_TX 4
984#define MON1_TX 8
985
986
987#ifdef ISDN_CHIP_ISAC
988#undef ISDN_CHIP_ISAC
989#endif
990
991#ifdef CONFIG_HISAX_16_0
992#define CARD_TELES0 1
993#ifndef ISDN_CHIP_ISAC
994#define ISDN_CHIP_ISAC 1
995#endif
996#else
997#define CARD_TELES0 0
998#endif
999
1000#ifdef CONFIG_HISAX_16_3
1001#define CARD_TELES3 1
1002#ifndef ISDN_CHIP_ISAC
1003#define ISDN_CHIP_ISAC 1
1004#endif
1005#else
1006#define CARD_TELES3 0
1007#endif
1008
1009#ifdef CONFIG_HISAX_TELESPCI
1010#define CARD_TELESPCI 1
1011#ifndef ISDN_CHIP_ISAC
1012#define ISDN_CHIP_ISAC 1
1013#endif
1014#else
1015#define CARD_TELESPCI 0
1016#endif
1017
1018#ifdef CONFIG_HISAX_AVM_A1
1019#define CARD_AVM_A1 1
1020#ifndef ISDN_CHIP_ISAC
1021#define ISDN_CHIP_ISAC 1
1022#endif
1023#else
1024#define CARD_AVM_A1 0
1025#endif
1026
1027#ifdef CONFIG_HISAX_AVM_A1_PCMCIA
1028#define CARD_AVM_A1_PCMCIA 1
1029#ifndef ISDN_CHIP_ISAC
1030#define ISDN_CHIP_ISAC 1
1031#endif
1032#else
1033#define CARD_AVM_A1_PCMCIA 0
1034#endif
1035
1036#ifdef CONFIG_HISAX_FRITZPCI
1037#define CARD_FRITZPCI 1
1038#ifndef ISDN_CHIP_ISAC
1039#define ISDN_CHIP_ISAC 1
1040#endif
1041#else
1042#define CARD_FRITZPCI 0
1043#endif
1044
1045#ifdef CONFIG_HISAX_ELSA
1046#define CARD_ELSA 1
1047#ifndef ISDN_CHIP_ISAC
1048#define ISDN_CHIP_ISAC 1
1049#endif
1050#else
1051#define CARD_ELSA 0
1052#endif
1053
1054#ifdef CONFIG_HISAX_IX1MICROR2
1055#define CARD_IX1MICROR2 1
1056#ifndef ISDN_CHIP_ISAC
1057#define ISDN_CHIP_ISAC 1
1058#endif
1059#else
1060#define CARD_IX1MICROR2 0
1061#endif
1062
1063#ifdef CONFIG_HISAX_DIEHLDIVA
1064#define CARD_DIEHLDIVA 1
1065#ifndef ISDN_CHIP_ISAC
1066#define ISDN_CHIP_ISAC 1
1067#endif
1068#else
1069#define CARD_DIEHLDIVA 0
1070#endif
1071
1072#ifdef CONFIG_HISAX_ASUSCOM
1073#define CARD_ASUSCOM 1
1074#ifndef ISDN_CHIP_ISAC
1075#define ISDN_CHIP_ISAC 1
1076#endif
1077#else
1078#define CARD_ASUSCOM 0
1079#endif
1080
1081#ifdef CONFIG_HISAX_TELEINT
1082#define CARD_TELEINT 1
1083#ifndef ISDN_CHIP_ISAC
1084#define ISDN_CHIP_ISAC 1
1085#endif
1086#else
1087#define CARD_TELEINT 0
1088#endif
1089
1090#ifdef CONFIG_HISAX_SEDLBAUER
1091#define CARD_SEDLBAUER 1
1092#ifndef ISDN_CHIP_ISAC
1093#define ISDN_CHIP_ISAC 1
1094#endif
1095#else
1096#define CARD_SEDLBAUER 0
1097#endif
1098
1099#ifdef CONFIG_HISAX_SPORTSTER
1100#define CARD_SPORTSTER 1
1101#ifndef ISDN_CHIP_ISAC
1102#define ISDN_CHIP_ISAC 1
1103#endif
1104#else
1105#define CARD_SPORTSTER 0
1106#endif
1107
1108#ifdef CONFIG_HISAX_MIC
1109#define CARD_MIC 1
1110#ifndef ISDN_CHIP_ISAC
1111#define ISDN_CHIP_ISAC 1
1112#endif
1113#else
1114#define CARD_MIC 0
1115#endif
1116
1117#ifdef CONFIG_HISAX_NETJET
1118#define CARD_NETJET_S 1
1119#ifndef ISDN_CHIP_ISAC
1120#define ISDN_CHIP_ISAC 1
1121#endif
1122#else
1123#define CARD_NETJET_S 0
1124#endif
1125
1126#ifdef CONFIG_HISAX_HFCS
1127#define CARD_HFCS 1
1128#else
1129#define CARD_HFCS 0
1130#endif
1131
1132#ifdef CONFIG_HISAX_HFC_PCI
1133#define CARD_HFC_PCI 1
1134#else
1135#define CARD_HFC_PCI 0
1136#endif
1137
1138#ifdef CONFIG_HISAX_HFC_SX
1139#define CARD_HFC_SX 1
1140#else
1141#define CARD_HFC_SX 0
1142#endif
1143
1144#ifdef CONFIG_HISAX_AMD7930
1145#define CARD_AMD7930 1
1146#else
1147#define CARD_AMD7930 0
1148#endif
1149
1150#ifdef CONFIG_HISAX_NICCY
1151#define CARD_NICCY 1
1152#ifndef ISDN_CHIP_ISAC
1153#define ISDN_CHIP_ISAC 1
1154#endif
1155#else
1156#define CARD_NICCY 0
1157#endif
1158
1159#ifdef CONFIG_HISAX_ISURF
1160#define CARD_ISURF 1
1161#ifndef ISDN_CHIP_ISAC
1162#define ISDN_CHIP_ISAC 1
1163#endif
1164#else
1165#define CARD_ISURF 0
1166#endif
1167
1168#ifdef CONFIG_HISAX_S0BOX
1169#define CARD_S0BOX 1
1170#ifndef ISDN_CHIP_ISAC
1171#define ISDN_CHIP_ISAC 1
1172#endif
1173#else
1174#define CARD_S0BOX 0
1175#endif
1176
1177#ifdef CONFIG_HISAX_HSTSAPHIR
1178#define CARD_HSTSAPHIR 1
1179#ifndef ISDN_CHIP_ISAC
1180#define ISDN_CHIP_ISAC 1
1181#endif
1182#else
1183#define CARD_HSTSAPHIR 0
1184#endif
1185
1186#ifdef CONFIG_HISAX_TESTEMU
1187#define CARD_TESTEMU 1
1188#define ISDN_CTYPE_TESTEMU 99
1189#undef ISDN_CTYPE_COUNT
1190#define ISDN_CTYPE_COUNT ISDN_CTYPE_TESTEMU
1191#else
1192#define CARD_TESTEMU 0
1193#endif
1194
1195#ifdef CONFIG_HISAX_BKM_A4T
1196#define CARD_BKM_A4T 1
1197#ifndef ISDN_CHIP_ISAC
1198#define ISDN_CHIP_ISAC 1
1199#endif
1200#else
1201#define CARD_BKM_A4T 0
1202#endif
1203
1204#ifdef CONFIG_HISAX_SCT_QUADRO
1205#define CARD_SCT_QUADRO 1
1206#ifndef ISDN_CHIP_ISAC
1207#define ISDN_CHIP_ISAC 1
1208#endif
1209#else
1210#define CARD_SCT_QUADRO 0
1211#endif
1212
1213#ifdef CONFIG_HISAX_GAZEL
1214#define CARD_GAZEL 1
1215#ifndef ISDN_CHIP_ISAC
1216#define ISDN_CHIP_ISAC 1
1217#endif
1218#else
1219#define CARD_GAZEL 0
1220#endif
1221
1222#ifdef CONFIG_HISAX_W6692
1223#define CARD_W6692 1
1224#ifndef ISDN_CHIP_W6692
1225#define ISDN_CHIP_W6692 1
1226#endif
1227#else
1228#define CARD_W6692 0
1229#endif
1230
1231#ifdef CONFIG_HISAX_NETJET_U
1232#define CARD_NETJET_U 1
1233#ifndef ISDN_CHIP_ICC
1234#define ISDN_CHIP_ICC 1
1235#endif
1236#ifndef HISAX_UINTERFACE
1237#define HISAX_UINTERFACE 1
1238#endif
1239#else
1240#define CARD_NETJET_U 0
1241#endif
1242
1243#ifdef CONFIG_HISAX_ENTERNOW_PCI
1244#define CARD_FN_ENTERNOW_PCI 1
1245#endif
1246
1247#define TEI_PER_CARD 1
1248
1249/* L1 Debug */
1250#define L1_DEB_WARN 0x01
1251#define L1_DEB_INTSTAT 0x02
1252#define L1_DEB_ISAC 0x04
1253#define L1_DEB_ISAC_FIFO 0x08
1254#define L1_DEB_HSCX 0x10
1255#define L1_DEB_HSCX_FIFO 0x20
1256#define L1_DEB_LAPD 0x40
1257#define L1_DEB_IPAC 0x80
1258#define L1_DEB_RECEIVE_FRAME 0x100
1259#define L1_DEB_MONITOR 0x200
1260#define DEB_DLOG_HEX 0x400
1261#define DEB_DLOG_VERBOSE 0x800
1262
1263#define L2FRAME_DEBUG
1264
1265#ifdef L2FRAME_DEBUG
1266extern void Logl2Frame(struct IsdnCardState *cs, struct sk_buff *skb, char *buf, int dir);
1267#endif
1268
1269#include "hisax_cfg.h"
1270
1271void init_bcstate(struct IsdnCardState *cs, int bc);
1272
1273void setstack_HiSax(struct PStack *st, struct IsdnCardState *cs);
1274unsigned int random_ri(void);
1275void HiSax_addlist(struct IsdnCardState *sp, struct PStack *st);
1276void HiSax_rmlist(struct IsdnCardState *sp, struct PStack *st);
1277
1278void setstack_l1_B(struct PStack *st);
1279
1280void setstack_tei(struct PStack *st);
1281void setstack_manager(struct PStack *st);
1282
1283void setstack_isdnl2(struct PStack *st, char *debug_id);
1284void releasestack_isdnl2(struct PStack *st);
1285void setstack_transl2(struct PStack *st);
1286void releasestack_transl2(struct PStack *st);
1287void lli_writewakeup(struct PStack *st, int len);
1288
1289void setstack_l3dc(struct PStack *st, struct Channel *chanp);
1290void setstack_l3bc(struct PStack *st, struct Channel *chanp);
1291void releasestack_isdnl3(struct PStack *st);
1292
1293u_char *findie(u_char * p, int size, u_char ie, int wanted_set);
1294int getcallref(u_char * p);
1295int newcallref(void);
1296
1297int FsmNew(struct Fsm *fsm, struct FsmNode *fnlist, int fncount);
1298void FsmFree(struct Fsm *fsm);
1299int FsmEvent(struct FsmInst *fi, int event, void *arg);
1300void FsmChangeState(struct FsmInst *fi, int newstate);
1301void FsmInitTimer(struct FsmInst *fi, struct FsmTimer *ft);
1302int FsmAddTimer(struct FsmTimer *ft, int millisec, int event,
1303 void *arg, int where);
1304void FsmRestartTimer(struct FsmTimer *ft, int millisec, int event,
1305 void *arg, int where);
1306void FsmDelTimer(struct FsmTimer *ft, int where);
1307int jiftime(char *s, long mark);
1308
1309int HiSax_command(isdn_ctrl * ic);
1310int HiSax_writebuf_skb(int id, int chan, int ack, struct sk_buff *skb);
1311void HiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, ...);
1312void VHiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, va_list args);
1313void HiSax_reportcard(int cardnr, int sel);
1314int QuickHex(char *txt, u_char * p, int cnt);
1315void LogFrame(struct IsdnCardState *cs, u_char * p, int size);
1316void dlogframe(struct IsdnCardState *cs, struct sk_buff *skb, int dir);
1317void iecpy(u_char * dest, u_char * iestart, int ieoffset);
1318#ifdef ISDN_CHIP_ISAC
1319void setstack_isac(struct PStack *st, struct IsdnCardState *cs);
1320#endif /* ISDN_CHIP_ISAC */
1321#endif /* __KERNEL__ */
1322
1323#define HZDELAY(jiffs) {int tout = jiffs; while (tout--) udelay(1000000/HZ);}
1324
1325int ll_run(struct IsdnCardState *cs, int addfeatures);
1326void ll_stop(struct IsdnCardState *cs);
1327int CallcNew(void);
1328void CallcFree(void);
1329int CallcNewChan(struct IsdnCardState *cs);
1330void CallcFreeChan(struct IsdnCardState *cs);
1331int Isdnl1New(void);
1332void Isdnl1Free(void);
1333int Isdnl2New(void);
1334void Isdnl2Free(void);
1335int Isdnl3New(void);
1336void Isdnl3Free(void);
1337void init_tei(struct IsdnCardState *cs, int protocol);
1338void release_tei(struct IsdnCardState *cs);
1339char *HiSax_getrev(const char *revision);
1340int TeiNew(void);
1341void TeiFree(void);
diff --git a/drivers/isdn/hisax/hisax_cfg.h b/drivers/isdn/hisax/hisax_cfg.h
new file mode 100644
index 000000000000..ca3fe6259bca
--- /dev/null
+++ b/drivers/isdn/hisax/hisax_cfg.h
@@ -0,0 +1,64 @@
1/* $Id: hisax_cfg.h,v 1.1.2.1 2004/01/24 20:47:23 keil Exp $
2 * define of the basic HiSax configuration structures
3 * and pcmcia interface
4 *
5 * This software may be used and distributed according to the terms
6 * of the GNU General Public License, incorporated herein by reference.
7 *
8 */
9
10#define ISDN_CTYPE_16_0 1
11#define ISDN_CTYPE_8_0 2
12#define ISDN_CTYPE_16_3 3
13#define ISDN_CTYPE_PNP 4
14#define ISDN_CTYPE_A1 5
15#define ISDN_CTYPE_ELSA 6
16#define ISDN_CTYPE_ELSA_PNP 7
17#define ISDN_CTYPE_TELESPCMCIA 8
18#define ISDN_CTYPE_IX1MICROR2 9
19#define ISDN_CTYPE_ELSA_PCMCIA 10
20#define ISDN_CTYPE_DIEHLDIVA 11
21#define ISDN_CTYPE_ASUSCOM 12
22#define ISDN_CTYPE_TELEINT 13
23#define ISDN_CTYPE_TELES3C 14
24#define ISDN_CTYPE_SEDLBAUER 15
25#define ISDN_CTYPE_SPORTSTER 16
26#define ISDN_CTYPE_MIC 17
27#define ISDN_CTYPE_ELSA_PCI 18
28#define ISDN_CTYPE_COMPAQ_ISA 19
29#define ISDN_CTYPE_NETJET_S 20
30#define ISDN_CTYPE_TELESPCI 21
31#define ISDN_CTYPE_SEDLBAUER_PCMCIA 22
32#define ISDN_CTYPE_AMD7930 23
33#define ISDN_CTYPE_NICCY 24
34#define ISDN_CTYPE_S0BOX 25
35#define ISDN_CTYPE_A1_PCMCIA 26
36#define ISDN_CTYPE_FRITZPCI 27
37#define ISDN_CTYPE_SEDLBAUER_FAX 28
38#define ISDN_CTYPE_ISURF 29
39#define ISDN_CTYPE_ACERP10 30
40#define ISDN_CTYPE_HSTSAPHIR 31
41#define ISDN_CTYPE_BKM_A4T 32
42#define ISDN_CTYPE_SCT_QUADRO 33
43#define ISDN_CTYPE_GAZEL 34
44#define ISDN_CTYPE_HFC_PCI 35
45#define ISDN_CTYPE_W6692 36
46#define ISDN_CTYPE_HFC_SX 37
47#define ISDN_CTYPE_NETJET_U 38
48#define ISDN_CTYPE_HFC_SP_PCMCIA 39
49#define ISDN_CTYPE_DYNAMIC 40
50#define ISDN_CTYPE_ENTERNOW 41
51#define ISDN_CTYPE_COUNT 41
52
53typedef struct IsdnCardState IsdnCardState_t;
54typedef struct IsdnCard IsdnCard_t;
55
56struct IsdnCard {
57 int typ;
58 int protocol; /* EDSS1, 1TR6 or NI1 */
59 unsigned long para[4];
60 IsdnCardState_t *cs;
61};
62
63extern void HiSax_closecard(int);
64extern int hisax_init_pcmcia(void *, int *, IsdnCard_t *);
diff --git a/drivers/isdn/hisax/hisax_debug.h b/drivers/isdn/hisax/hisax_debug.h
new file mode 100644
index 000000000000..ba518a7a7fb7
--- /dev/null
+++ b/drivers/isdn/hisax/hisax_debug.h
@@ -0,0 +1,81 @@
1/*
2 * Common debugging macros for use with the hisax driver
3 *
4 * Author Frode Isaksen
5 * Copyright 2001 by Frode Isaksen <fisaksen@bewan.com>
6 * 2001 by Kai Germaschewski <kai.germaschewski@gmx.de>
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 * How to use:
12 *
13 * Before including this file, you need to
14 * #define __debug_variable my_debug
15 * where my_debug is a variable in your code which
16 * determines the debug bitmask.
17 *
18 * If CONFIG_HISAX_DEBUG is not set, all macros evaluate to nothing
19 *
20 */
21
22#ifndef __HISAX_DEBUG_H__
23#define __HISAX_DEBUG_H__
24
25#include <linux/config.h>
26
27#ifdef CONFIG_HISAX_DEBUG
28
29#define DBG(level, format, arg...) do { \
30if (level & __debug_variable) \
31printk(KERN_DEBUG "%s: " format "\n" , __FUNCTION__ , ## arg); \
32} while (0)
33
34#define DBG_PACKET(level,data,count) \
35 if (level & __debug_variable) dump_packet(__FUNCTION__,data,count)
36
37#define DBG_SKB(level,skb) \
38 if ((level & __debug_variable) && skb) dump_packet(__FUNCTION__,skb->data,skb->len)
39
40
41static void __attribute__((unused))
42dump_packet(const char *name,const u_char *data,int pkt_len)
43{
44#define DUMP_HDR_SIZE 20
45#define DUMP_TLR_SIZE 8
46 if (pkt_len) {
47 int i,len1,len2;
48
49 printk(KERN_DEBUG "%s: length=%d,data=",name,pkt_len);
50
51 if (pkt_len > DUMP_HDR_SIZE+ DUMP_TLR_SIZE) {
52 len1 = DUMP_HDR_SIZE;
53 len2 = DUMP_TLR_SIZE;
54 } else {
55 len1 = pkt_len > DUMP_HDR_SIZE ? DUMP_HDR_SIZE : pkt_len;
56 len2 = 0;
57 }
58 for (i = 0; i < len1; ++i) {
59 printk ("%.2x", data[i]);
60 }
61 if (len2) {
62 printk ("..");
63 for (i = pkt_len-DUMP_TLR_SIZE; i < pkt_len; ++i) {
64 printk ("%.2x", data[i]);
65 }
66 }
67 printk ("\n");
68 }
69#undef DUMP_HDR_SIZE
70#undef DUMP_TLR_SIZE
71}
72
73#else
74
75#define DBG(level, format, arg...) do {} while (0)
76#define DBG_PACKET(level,data,count) do {} while (0)
77#define DBG_SKB(level,skb) do {} while (0)
78
79#endif
80
81#endif
diff --git a/drivers/isdn/hisax/hisax_fcpcipnp.c b/drivers/isdn/hisax/hisax_fcpcipnp.c
new file mode 100644
index 000000000000..b4d795d40154
--- /dev/null
+++ b/drivers/isdn/hisax/hisax_fcpcipnp.c
@@ -0,0 +1,1028 @@
1/*
2 * Driver for AVM Fritz!PCI, Fritz!PCI v2, Fritz!PnP ISDN cards
3 *
4 * Author Kai Germaschewski
5 * Copyright 2001 by Kai Germaschewski <kai.germaschewski@gmx.de>
6 * 2001 by Karsten Keil <keil@isdn4linux.de>
7 *
8 * based upon Karsten Keil's original avm_pci.c driver
9 *
10 * This software may be used and distributed according to the terms
11 * of the GNU General Public License, incorporated herein by reference.
12 *
13 * Thanks to Wizard Computersysteme GmbH, Bremervoerde and
14 * SoHaNet Technology GmbH, Berlin
15 * for supporting the development of this driver
16 */
17
18
19/* TODO:
20 *
21 * o POWER PC
22 * o clean up debugging
23 * o tx_skb at PH_DEACTIVATE time
24 */
25
26#include <linux/version.h>
27#include <linux/module.h>
28#include <linux/init.h>
29#include <linux/pci.h>
30#include <linux/isapnp.h>
31#include <linux/kmod.h>
32#include <linux/slab.h>
33#include <linux/skbuff.h>
34#include <linux/netdevice.h>
35#include <linux/delay.h>
36
37#include <asm/io.h>
38
39#include "hisax_fcpcipnp.h"
40
41// debugging cruft
42#define __debug_variable debug
43#include "hisax_debug.h"
44
45#ifdef CONFIG_HISAX_DEBUG
46static int debug = 0;
47/* static int hdlcfifosize = 32; */
48module_param(debug, int, 0);
49/* module_param(hdlcfifosize, int, 0); */
50#endif
51
52MODULE_AUTHOR("Kai Germaschewski <kai.germaschewski@gmx.de>/Karsten Keil <kkeil@suse.de>");
53MODULE_DESCRIPTION("AVM Fritz!PCI/PnP ISDN driver");
54
55static struct pci_device_id fcpci_ids[] = {
56 { .vendor = PCI_VENDOR_ID_AVM,
57 .device = PCI_DEVICE_ID_AVM_A1,
58 .subvendor = PCI_ANY_ID,
59 .subdevice = PCI_ANY_ID,
60 .driver_data = (unsigned long) "Fritz!Card PCI",
61 },
62 { .vendor = PCI_VENDOR_ID_AVM,
63 .device = PCI_DEVICE_ID_AVM_A1_V2,
64 .subvendor = PCI_ANY_ID,
65 .subdevice = PCI_ANY_ID,
66 .driver_data = (unsigned long) "Fritz!Card PCI v2" },
67 {}
68};
69
70MODULE_DEVICE_TABLE(pci, fcpci_ids);
71
72#ifdef __ISAPNP__
73static struct pnp_device_id fcpnp_ids[] __devinitdata = {
74 {
75 .id = "AVM0900",
76 .driver_data = (unsigned long) "Fritz!Card PnP",
77 },
78};
79
80MODULE_DEVICE_TABLE(isapnp, fcpnp_ids);
81#endif
82
83static int protocol = 2; /* EURO-ISDN Default */
84module_param(protocol, int, 0);
85MODULE_LICENSE("GPL");
86
87// ----------------------------------------------------------------------
88
89#define AVM_INDEX 0x04
90#define AVM_DATA 0x10
91
92#define AVM_IDX_HDLC_1 0x00
93#define AVM_IDX_HDLC_2 0x01
94#define AVM_IDX_ISAC_FIFO 0x02
95#define AVM_IDX_ISAC_REG_LOW 0x04
96#define AVM_IDX_ISAC_REG_HIGH 0x06
97
98#define AVM_STATUS0 0x02
99
100#define AVM_STATUS0_IRQ_ISAC 0x01
101#define AVM_STATUS0_IRQ_HDLC 0x02
102#define AVM_STATUS0_IRQ_TIMER 0x04
103#define AVM_STATUS0_IRQ_MASK 0x07
104
105#define AVM_STATUS0_RESET 0x01
106#define AVM_STATUS0_DIS_TIMER 0x02
107#define AVM_STATUS0_RES_TIMER 0x04
108#define AVM_STATUS0_ENA_IRQ 0x08
109#define AVM_STATUS0_TESTBIT 0x10
110
111#define AVM_STATUS1 0x03
112#define AVM_STATUS1_ENA_IOM 0x80
113
114#define HDLC_FIFO 0x0
115#define HDLC_STATUS 0x4
116#define HDLC_CTRL 0x4
117
118#define HDLC_MODE_ITF_FLG 0x01
119#define HDLC_MODE_TRANS 0x02
120#define HDLC_MODE_CCR_7 0x04
121#define HDLC_MODE_CCR_16 0x08
122#define HDLC_MODE_TESTLOOP 0x80
123
124#define HDLC_INT_XPR 0x80
125#define HDLC_INT_XDU 0x40
126#define HDLC_INT_RPR 0x20
127#define HDLC_INT_MASK 0xE0
128
129#define HDLC_STAT_RME 0x01
130#define HDLC_STAT_RDO 0x10
131#define HDLC_STAT_CRCVFRRAB 0x0E
132#define HDLC_STAT_CRCVFR 0x06
133#define HDLC_STAT_RML_MASK 0xff00
134
135#define HDLC_CMD_XRS 0x80
136#define HDLC_CMD_XME 0x01
137#define HDLC_CMD_RRS 0x20
138#define HDLC_CMD_XML_MASK 0xff00
139
140#define AVM_HDLC_FIFO_1 0x10
141#define AVM_HDLC_FIFO_2 0x18
142
143#define AVM_HDLC_STATUS_1 0x14
144#define AVM_HDLC_STATUS_2 0x1c
145
146#define AVM_ISACSX_INDEX 0x04
147#define AVM_ISACSX_DATA 0x08
148
149// ----------------------------------------------------------------------
150// Fritz!PCI
151
152static unsigned char fcpci_read_isac(struct isac *isac, unsigned char offset)
153{
154 struct fritz_adapter *adapter = isac->priv;
155 unsigned char idx = (offset > 0x2f) ?
156 AVM_IDX_ISAC_REG_HIGH : AVM_IDX_ISAC_REG_LOW;
157 unsigned char val;
158 unsigned long flags;
159
160 spin_lock_irqsave(&adapter->hw_lock, flags);
161 outb(idx, adapter->io + AVM_INDEX);
162 val = inb(adapter->io + AVM_DATA + (offset & 0xf));
163 spin_unlock_irqrestore(&adapter->hw_lock, flags);
164 DBG(0x1000, " port %#x, value %#x",
165 offset, val);
166 return val;
167}
168
169static void fcpci_write_isac(struct isac *isac, unsigned char offset,
170 unsigned char value)
171{
172 struct fritz_adapter *adapter = isac->priv;
173 unsigned char idx = (offset > 0x2f) ?
174 AVM_IDX_ISAC_REG_HIGH : AVM_IDX_ISAC_REG_LOW;
175 unsigned long flags;
176
177 DBG(0x1000, " port %#x, value %#x",
178 offset, value);
179 spin_lock_irqsave(&adapter->hw_lock, flags);
180 outb(idx, adapter->io + AVM_INDEX);
181 outb(value, adapter->io + AVM_DATA + (offset & 0xf));
182 spin_unlock_irqrestore(&adapter->hw_lock, flags);
183}
184
185static void fcpci_read_isac_fifo(struct isac *isac, unsigned char * data,
186 int size)
187{
188 struct fritz_adapter *adapter = isac->priv;
189 unsigned long flags;
190
191 spin_lock_irqsave(&adapter->hw_lock, flags);
192 outb(AVM_IDX_ISAC_FIFO, adapter->io + AVM_INDEX);
193 insb(adapter->io + AVM_DATA, data, size);
194 spin_unlock_irqrestore(&adapter->hw_lock, flags);
195}
196
197static void fcpci_write_isac_fifo(struct isac *isac, unsigned char * data,
198 int size)
199{
200 struct fritz_adapter *adapter = isac->priv;
201 unsigned long flags;
202
203 spin_lock_irqsave(&adapter->hw_lock, flags);
204 outb(AVM_IDX_ISAC_FIFO, adapter->io + AVM_INDEX);
205 outsb(adapter->io + AVM_DATA, data, size);
206 spin_unlock_irqrestore(&adapter->hw_lock, flags);
207}
208
209static u32 fcpci_read_hdlc_status(struct fritz_adapter *adapter, int nr)
210{
211 u32 val;
212 int idx = nr ? AVM_IDX_HDLC_2 : AVM_IDX_HDLC_1;
213 unsigned long flags;
214
215 spin_lock_irqsave(&adapter->hw_lock, flags);
216 outl(idx, adapter->io + AVM_INDEX);
217 val = inl(adapter->io + AVM_DATA + HDLC_STATUS);
218 spin_unlock_irqrestore(&adapter->hw_lock, flags);
219 return val;
220}
221
222static void __fcpci_write_ctrl(struct fritz_bcs *bcs, int which)
223{
224 struct fritz_adapter *adapter = bcs->adapter;
225 int idx = bcs->channel ? AVM_IDX_HDLC_2 : AVM_IDX_HDLC_1;
226
227 DBG(0x40, "hdlc %c wr%x ctrl %x",
228 'A' + bcs->channel, which, bcs->ctrl.ctrl);
229
230 outl(idx, adapter->io + AVM_INDEX);
231 outl(bcs->ctrl.ctrl, adapter->io + AVM_DATA + HDLC_CTRL);
232}
233
234static void fcpci_write_ctrl(struct fritz_bcs *bcs, int which)
235{
236 struct fritz_adapter *adapter = bcs->adapter;
237 unsigned long flags;
238
239 spin_lock_irqsave(&adapter->hw_lock, flags);
240 __fcpci_write_ctrl(bcs, which);
241 spin_unlock_irqrestore(&adapter->hw_lock, flags);
242}
243
244// ----------------------------------------------------------------------
245// Fritz!PCI v2
246
247static unsigned char fcpci2_read_isac(struct isac *isac, unsigned char offset)
248{
249 struct fritz_adapter *adapter = isac->priv;
250 unsigned char val;
251 unsigned long flags;
252
253 spin_lock_irqsave(&adapter->hw_lock, flags);
254 outl(offset, adapter->io + AVM_ISACSX_INDEX);
255 val = inl(adapter->io + AVM_ISACSX_DATA);
256 spin_unlock_irqrestore(&adapter->hw_lock, flags);
257 DBG(0x1000, " port %#x, value %#x",
258 offset, val);
259
260 return val;
261}
262
263static void fcpci2_write_isac(struct isac *isac, unsigned char offset,
264 unsigned char value)
265{
266 struct fritz_adapter *adapter = isac->priv;
267 unsigned long flags;
268
269 DBG(0x1000, " port %#x, value %#x",
270 offset, value);
271 spin_lock_irqsave(&adapter->hw_lock, flags);
272 outl(offset, adapter->io + AVM_ISACSX_INDEX);
273 outl(value, adapter->io + AVM_ISACSX_DATA);
274 spin_unlock_irqrestore(&adapter->hw_lock, flags);
275}
276
277static void fcpci2_read_isac_fifo(struct isac *isac, unsigned char * data,
278 int size)
279{
280 struct fritz_adapter *adapter = isac->priv;
281 int i;
282 unsigned long flags;
283
284 spin_lock_irqsave(&adapter->hw_lock, flags);
285 outl(0, adapter->io + AVM_ISACSX_INDEX);
286 for (i = 0; i < size; i++)
287 data[i] = inl(adapter->io + AVM_ISACSX_DATA);
288 spin_unlock_irqrestore(&adapter->hw_lock, flags);
289}
290
291static void fcpci2_write_isac_fifo(struct isac *isac, unsigned char * data,
292 int size)
293{
294 struct fritz_adapter *adapter = isac->priv;
295 int i;
296 unsigned long flags;
297
298 spin_lock_irqsave(&adapter->hw_lock, flags);
299 outl(0, adapter->io + AVM_ISACSX_INDEX);
300 for (i = 0; i < size; i++)
301 outl(data[i], adapter->io + AVM_ISACSX_DATA);
302 spin_unlock_irqrestore(&adapter->hw_lock, flags);
303}
304
305static u32 fcpci2_read_hdlc_status(struct fritz_adapter *adapter, int nr)
306{
307 int offset = nr ? AVM_HDLC_STATUS_2 : AVM_HDLC_STATUS_1;
308
309 return inl(adapter->io + offset);
310}
311
312static void fcpci2_write_ctrl(struct fritz_bcs *bcs, int which)
313{
314 struct fritz_adapter *adapter = bcs->adapter;
315 int offset = bcs->channel ? AVM_HDLC_STATUS_2 : AVM_HDLC_STATUS_1;
316
317 DBG(0x40, "hdlc %c wr%x ctrl %x",
318 'A' + bcs->channel, which, bcs->ctrl.ctrl);
319
320 outl(bcs->ctrl.ctrl, adapter->io + offset);
321}
322
323// ----------------------------------------------------------------------
324// Fritz!PnP (ISAC access as for Fritz!PCI)
325
326static u32 fcpnp_read_hdlc_status(struct fritz_adapter *adapter, int nr)
327{
328 unsigned char idx = nr ? AVM_IDX_HDLC_2 : AVM_IDX_HDLC_1;
329 u32 val;
330 unsigned long flags;
331
332 spin_lock_irqsave(&adapter->hw_lock, flags);
333 outb(idx, adapter->io + AVM_INDEX);
334 val = inb(adapter->io + AVM_DATA + HDLC_STATUS);
335 if (val & HDLC_INT_RPR)
336 val |= inb(adapter->io + AVM_DATA + HDLC_STATUS + 1) << 8;
337 spin_unlock_irqrestore(&adapter->hw_lock, flags);
338 return val;
339}
340
341static void __fcpnp_write_ctrl(struct fritz_bcs *bcs, int which)
342{
343 struct fritz_adapter *adapter = bcs->adapter;
344 unsigned char idx = bcs->channel ? AVM_IDX_HDLC_2 : AVM_IDX_HDLC_1;
345
346 DBG(0x40, "hdlc %c wr%x ctrl %x",
347 'A' + bcs->channel, which, bcs->ctrl.ctrl);
348
349 outb(idx, adapter->io + AVM_INDEX);
350 if (which & 4)
351 outb(bcs->ctrl.sr.mode,
352 adapter->io + AVM_DATA + HDLC_STATUS + 2);
353 if (which & 2)
354 outb(bcs->ctrl.sr.xml,
355 adapter->io + AVM_DATA + HDLC_STATUS + 1);
356 if (which & 1)
357 outb(bcs->ctrl.sr.cmd,
358 adapter->io + AVM_DATA + HDLC_STATUS + 0);
359}
360
361static void fcpnp_write_ctrl(struct fritz_bcs *bcs, int which)
362{
363 struct fritz_adapter *adapter = bcs->adapter;
364 unsigned long flags;
365
366 spin_lock_irqsave(&adapter->hw_lock, flags);
367 __fcpnp_write_ctrl(bcs, which);
368 spin_unlock_irqrestore(&adapter->hw_lock, flags);
369}
370
371// ----------------------------------------------------------------------
372
373static inline void B_L1L2(struct fritz_bcs *bcs, int pr, void *arg)
374{
375 struct hisax_if *ifc = (struct hisax_if *) &bcs->b_if;
376
377 DBG(2, "pr %#x", pr);
378 ifc->l1l2(ifc, pr, arg);
379}
380
381static void hdlc_fill_fifo(struct fritz_bcs *bcs)
382{
383 struct fritz_adapter *adapter = bcs->adapter;
384 struct sk_buff *skb = bcs->tx_skb;
385 int count;
386 unsigned long flags;
387 unsigned char *p;
388
389 DBG(0x40, "hdlc_fill_fifo");
390
391 if (skb->len == 0)
392 BUG();
393
394 bcs->ctrl.sr.cmd &= ~HDLC_CMD_XME;
395 if (bcs->tx_skb->len > bcs->fifo_size) {
396 count = bcs->fifo_size;
397 } else {
398 count = bcs->tx_skb->len;
399 if (bcs->mode != L1_MODE_TRANS)
400 bcs->ctrl.sr.cmd |= HDLC_CMD_XME;
401 }
402 DBG(0x40, "hdlc_fill_fifo %d/%d", count, bcs->tx_skb->len);
403 p = bcs->tx_skb->data;
404 skb_pull(bcs->tx_skb, count);
405 bcs->tx_cnt += count;
406 bcs->ctrl.sr.xml = ((count == bcs->fifo_size) ? 0 : count);
407
408 switch (adapter->type) {
409 case AVM_FRITZ_PCI:
410 spin_lock_irqsave(&adapter->hw_lock, flags);
411 // sets the correct AVM_INDEX, too
412 __fcpci_write_ctrl(bcs, 3);
413 outsl(adapter->io + AVM_DATA + HDLC_FIFO,
414 p, (count + 3) / 4);
415 spin_unlock_irqrestore(&adapter->hw_lock, flags);
416 break;
417 case AVM_FRITZ_PCIV2:
418 fcpci2_write_ctrl(bcs, 3);
419 outsl(adapter->io +
420 (bcs->channel ? AVM_HDLC_FIFO_2 : AVM_HDLC_FIFO_1),
421 p, (count + 3) / 4);
422 break;
423 case AVM_FRITZ_PNP:
424 spin_lock_irqsave(&adapter->hw_lock, flags);
425 // sets the correct AVM_INDEX, too
426 __fcpnp_write_ctrl(bcs, 3);
427 outsb(adapter->io + AVM_DATA, p, count);
428 spin_unlock_irqrestore(&adapter->hw_lock, flags);
429 break;
430 }
431}
432
433static inline void hdlc_empty_fifo(struct fritz_bcs *bcs, int count)
434{
435 struct fritz_adapter *adapter = bcs->adapter;
436 unsigned char *p;
437 unsigned char idx = bcs->channel ? AVM_IDX_HDLC_2 : AVM_IDX_HDLC_1;
438
439 DBG(0x10, "hdlc_empty_fifo %d", count);
440 if (bcs->rcvidx + count > HSCX_BUFMAX) {
441 DBG(0x10, "hdlc_empty_fifo: incoming packet too large");
442 return;
443 }
444 p = bcs->rcvbuf + bcs->rcvidx;
445 bcs->rcvidx += count;
446 switch (adapter->type) {
447 case AVM_FRITZ_PCI:
448 spin_lock(&adapter->hw_lock);
449 outl(idx, adapter->io + AVM_INDEX);
450 insl(adapter->io + AVM_DATA + HDLC_FIFO,
451 p, (count + 3) / 4);
452 spin_unlock(&adapter->hw_lock);
453 break;
454 case AVM_FRITZ_PCIV2:
455 insl(adapter->io +
456 (bcs->channel ? AVM_HDLC_FIFO_2 : AVM_HDLC_FIFO_1),
457 p, (count + 3) / 4);
458 break;
459 case AVM_FRITZ_PNP:
460 spin_lock(&adapter->hw_lock);
461 outb(idx, adapter->io + AVM_INDEX);
462 insb(adapter->io + AVM_DATA, p, count);
463 spin_unlock(&adapter->hw_lock);
464 break;
465 }
466}
467
468static inline void hdlc_rpr_irq(struct fritz_bcs *bcs, u32 stat)
469{
470 struct fritz_adapter *adapter = bcs->adapter;
471 struct sk_buff *skb;
472 int len;
473
474 if (stat & HDLC_STAT_RDO) {
475 DBG(0x10, "RDO");
476 bcs->ctrl.sr.xml = 0;
477 bcs->ctrl.sr.cmd |= HDLC_CMD_RRS;
478 adapter->write_ctrl(bcs, 1);
479 bcs->ctrl.sr.cmd &= ~HDLC_CMD_RRS;
480 adapter->write_ctrl(bcs, 1);
481 bcs->rcvidx = 0;
482 return;
483 }
484
485 len = (stat & HDLC_STAT_RML_MASK) >> 8;
486 if (len == 0)
487 len = bcs->fifo_size;
488
489 hdlc_empty_fifo(bcs, len);
490
491 if ((stat & HDLC_STAT_RME) || (bcs->mode == L1_MODE_TRANS)) {
492 if (((stat & HDLC_STAT_CRCVFRRAB)== HDLC_STAT_CRCVFR) ||
493 (bcs->mode == L1_MODE_TRANS)) {
494 skb = dev_alloc_skb(bcs->rcvidx);
495 if (!skb) {
496 printk(KERN_WARNING "HDLC: receive out of memory\n");
497 } else {
498 memcpy(skb_put(skb, bcs->rcvidx), bcs->rcvbuf,
499 bcs->rcvidx);
500 DBG_SKB(1, skb);
501 B_L1L2(bcs, PH_DATA | INDICATION, skb);
502 }
503 bcs->rcvidx = 0;
504 } else {
505 DBG(0x10, "ch%d invalid frame %#x",
506 bcs->channel, stat);
507 bcs->rcvidx = 0;
508 }
509 }
510}
511
512static inline void hdlc_xdu_irq(struct fritz_bcs *bcs)
513{
514 struct fritz_adapter *adapter = bcs->adapter;
515
516
517 /* Here we lost an TX interrupt, so
518 * restart transmitting the whole frame.
519 */
520 bcs->ctrl.sr.xml = 0;
521 bcs->ctrl.sr.cmd |= HDLC_CMD_XRS;
522 adapter->write_ctrl(bcs, 1);
523 bcs->ctrl.sr.cmd &= ~HDLC_CMD_XRS;
524
525 if (!bcs->tx_skb) {
526 DBG(0x10, "XDU without skb");
527 adapter->write_ctrl(bcs, 1);
528 return;
529 }
530 /* only hdlc restarts the frame, transparent mode must continue */
531 if (bcs->mode == L1_MODE_HDLC) {
532 skb_push(bcs->tx_skb, bcs->tx_cnt);
533 bcs->tx_cnt = 0;
534 }
535}
536
537static inline void hdlc_xpr_irq(struct fritz_bcs *bcs)
538{
539 struct sk_buff *skb;
540
541 skb = bcs->tx_skb;
542 if (!skb)
543 return;
544
545 if (skb->len) {
546 hdlc_fill_fifo(bcs);
547 return;
548 }
549 bcs->tx_cnt = 0;
550 bcs->tx_skb = NULL;
551 B_L1L2(bcs, PH_DATA | CONFIRM, (void *) skb->truesize);
552 dev_kfree_skb_irq(skb);
553}
554
555static void hdlc_irq_one(struct fritz_bcs *bcs, u32 stat)
556{
557 DBG(0x10, "ch%d stat %#x", bcs->channel, stat);
558 if (stat & HDLC_INT_RPR) {
559 DBG(0x10, "RPR");
560 hdlc_rpr_irq(bcs, stat);
561 }
562 if (stat & HDLC_INT_XDU) {
563 DBG(0x10, "XDU");
564 hdlc_xdu_irq(bcs);
565 hdlc_xpr_irq(bcs);
566 return;
567 }
568 if (stat & HDLC_INT_XPR) {
569 DBG(0x10, "XPR");
570 hdlc_xpr_irq(bcs);
571 }
572}
573
574static inline void hdlc_irq(struct fritz_adapter *adapter)
575{
576 int nr;
577 u32 stat;
578
579 for (nr = 0; nr < 2; nr++) {
580 stat = adapter->read_hdlc_status(adapter, nr);
581 DBG(0x10, "HDLC %c stat %#x", 'A' + nr, stat);
582 if (stat & HDLC_INT_MASK)
583 hdlc_irq_one(&adapter->bcs[nr], stat);
584 }
585}
586
587static void modehdlc(struct fritz_bcs *bcs, int mode)
588{
589 struct fritz_adapter *adapter = bcs->adapter;
590
591 DBG(0x40, "hdlc %c mode %d --> %d",
592 'A' + bcs->channel, bcs->mode, mode);
593
594 if (bcs->mode == mode)
595 return;
596
597 bcs->fifo_size = 32;
598 bcs->ctrl.ctrl = 0;
599 bcs->ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS;
600 switch (mode) {
601 case L1_MODE_NULL:
602 bcs->ctrl.sr.mode = HDLC_MODE_TRANS;
603 adapter->write_ctrl(bcs, 5);
604 break;
605 case L1_MODE_TRANS:
606 case L1_MODE_HDLC:
607 bcs->rcvidx = 0;
608 bcs->tx_cnt = 0;
609 bcs->tx_skb = NULL;
610 if (mode == L1_MODE_TRANS) {
611 bcs->ctrl.sr.mode = HDLC_MODE_TRANS;
612 } else {
613 bcs->ctrl.sr.mode = HDLC_MODE_ITF_FLG;
614 }
615 adapter->write_ctrl(bcs, 5);
616 bcs->ctrl.sr.cmd = HDLC_CMD_XRS;
617 adapter->write_ctrl(bcs, 1);
618 bcs->ctrl.sr.cmd = 0;
619 break;
620 }
621 bcs->mode = mode;
622}
623
624static void fritz_b_l2l1(struct hisax_if *ifc, int pr, void *arg)
625{
626 struct fritz_bcs *bcs = ifc->priv;
627 struct sk_buff *skb = arg;
628 int mode;
629
630 DBG(0x10, "pr %#x", pr);
631
632 switch (pr) {
633 case PH_DATA | REQUEST:
634 if (bcs->tx_skb)
635 BUG();
636
637 bcs->tx_skb = skb;
638 DBG_SKB(1, skb);
639 hdlc_fill_fifo(bcs);
640 break;
641 case PH_ACTIVATE | REQUEST:
642 mode = (int) arg;
643 DBG(4,"B%d,PH_ACTIVATE_REQUEST %d", bcs->channel + 1, mode);
644 modehdlc(bcs, mode);
645 B_L1L2(bcs, PH_ACTIVATE | INDICATION, NULL);
646 break;
647 case PH_DEACTIVATE | REQUEST:
648 DBG(4,"B%d,PH_DEACTIVATE_REQUEST", bcs->channel + 1);
649 modehdlc(bcs, L1_MODE_NULL);
650 B_L1L2(bcs, PH_DEACTIVATE | INDICATION, NULL);
651 break;
652 }
653}
654
655// ----------------------------------------------------------------------
656
657static irqreturn_t
658fcpci2_irq(int intno, void *dev, struct pt_regs *regs)
659{
660 struct fritz_adapter *adapter = dev;
661 unsigned char val;
662
663 val = inb(adapter->io + AVM_STATUS0);
664 if (!(val & AVM_STATUS0_IRQ_MASK))
665 /* hopefully a shared IRQ reqest */
666 return IRQ_NONE;
667 DBG(2, "STATUS0 %#x", val);
668 if (val & AVM_STATUS0_IRQ_ISAC)
669 isacsx_irq(&adapter->isac);
670 if (val & AVM_STATUS0_IRQ_HDLC)
671 hdlc_irq(adapter);
672 if (val & AVM_STATUS0_IRQ_ISAC)
673 isacsx_irq(&adapter->isac);
674 return IRQ_HANDLED;
675}
676
677static irqreturn_t
678fcpci_irq(int intno, void *dev, struct pt_regs *regs)
679{
680 struct fritz_adapter *adapter = dev;
681 unsigned char sval;
682
683 sval = inb(adapter->io + 2);
684 if ((sval & AVM_STATUS0_IRQ_MASK) == AVM_STATUS0_IRQ_MASK)
685 /* possibly a shared IRQ reqest */
686 return IRQ_NONE;
687 DBG(2, "sval %#x", sval);
688 if (!(sval & AVM_STATUS0_IRQ_ISAC))
689 isac_irq(&adapter->isac);
690
691 if (!(sval & AVM_STATUS0_IRQ_HDLC))
692 hdlc_irq(adapter);
693 return IRQ_HANDLED;
694}
695
696// ----------------------------------------------------------------------
697
698static inline void fcpci2_init(struct fritz_adapter *adapter)
699{
700 outb(AVM_STATUS0_RES_TIMER, adapter->io + AVM_STATUS0);
701 outb(AVM_STATUS0_ENA_IRQ, adapter->io + AVM_STATUS0);
702
703}
704
705static inline void fcpci_init(struct fritz_adapter *adapter)
706{
707 outb(AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER |
708 AVM_STATUS0_ENA_IRQ, adapter->io + AVM_STATUS0);
709
710 outb(AVM_STATUS1_ENA_IOM | adapter->irq,
711 adapter->io + AVM_STATUS1);
712 mdelay(10);
713}
714
715// ----------------------------------------------------------------------
716
717static int __devinit fcpcipnp_setup(struct fritz_adapter *adapter)
718{
719 u32 val = 0;
720 int retval;
721
722 DBG(1,"");
723
724 isac_init(&adapter->isac); // FIXME is this okay now
725
726 retval = -EBUSY;
727 if (!request_region(adapter->io, 32, "fcpcipnp"))
728 goto err;
729
730 switch (adapter->type) {
731 case AVM_FRITZ_PCIV2:
732 retval = request_irq(adapter->irq, fcpci2_irq, SA_SHIRQ,
733 "fcpcipnp", adapter);
734 break;
735 case AVM_FRITZ_PCI:
736 retval = request_irq(adapter->irq, fcpci_irq, SA_SHIRQ,
737 "fcpcipnp", adapter);
738 break;
739 case AVM_FRITZ_PNP:
740 retval = request_irq(adapter->irq, fcpci_irq, 0,
741 "fcpcipnp", adapter);
742 break;
743 }
744 if (retval)
745 goto err_region;
746
747 switch (adapter->type) {
748 case AVM_FRITZ_PCIV2:
749 case AVM_FRITZ_PCI:
750 val = inl(adapter->io);
751 break;
752 case AVM_FRITZ_PNP:
753 val = inb(adapter->io);
754 val |= inb(adapter->io + 1) << 8;
755 break;
756 }
757
758 DBG(1, "stat %#x Class %X Rev %d",
759 val, val & 0xff, (val>>8) & 0xff);
760
761 spin_lock_init(&adapter->hw_lock);
762 adapter->isac.priv = adapter;
763 switch (adapter->type) {
764 case AVM_FRITZ_PCIV2:
765 adapter->isac.read_isac = &fcpci2_read_isac;
766 adapter->isac.write_isac = &fcpci2_write_isac;
767 adapter->isac.read_isac_fifo = &fcpci2_read_isac_fifo;
768 adapter->isac.write_isac_fifo = &fcpci2_write_isac_fifo;
769
770 adapter->read_hdlc_status = &fcpci2_read_hdlc_status;
771 adapter->write_ctrl = &fcpci2_write_ctrl;
772 break;
773 case AVM_FRITZ_PCI:
774 adapter->isac.read_isac = &fcpci_read_isac;
775 adapter->isac.write_isac = &fcpci_write_isac;
776 adapter->isac.read_isac_fifo = &fcpci_read_isac_fifo;
777 adapter->isac.write_isac_fifo = &fcpci_write_isac_fifo;
778
779 adapter->read_hdlc_status = &fcpci_read_hdlc_status;
780 adapter->write_ctrl = &fcpci_write_ctrl;
781 break;
782 case AVM_FRITZ_PNP:
783 adapter->isac.read_isac = &fcpci_read_isac;
784 adapter->isac.write_isac = &fcpci_write_isac;
785 adapter->isac.read_isac_fifo = &fcpci_read_isac_fifo;
786 adapter->isac.write_isac_fifo = &fcpci_write_isac_fifo;
787
788 adapter->read_hdlc_status = &fcpnp_read_hdlc_status;
789 adapter->write_ctrl = &fcpnp_write_ctrl;
790 break;
791 }
792
793 // Reset
794 outb(0, adapter->io + AVM_STATUS0);
795 mdelay(10);
796 outb(AVM_STATUS0_RESET, adapter->io + AVM_STATUS0);
797 mdelay(10);
798 outb(0, adapter->io + AVM_STATUS0);
799 mdelay(10);
800
801 switch (adapter->type) {
802 case AVM_FRITZ_PCIV2:
803 fcpci2_init(adapter);
804 isacsx_setup(&adapter->isac);
805 break;
806 case AVM_FRITZ_PCI:
807 case AVM_FRITZ_PNP:
808 fcpci_init(adapter);
809 isac_setup(&adapter->isac);
810 break;
811 }
812 val = adapter->read_hdlc_status(adapter, 0);
813 DBG(0x20, "HDLC A STA %x", val);
814 val = adapter->read_hdlc_status(adapter, 1);
815 DBG(0x20, "HDLC B STA %x", val);
816
817 adapter->bcs[0].mode = -1;
818 adapter->bcs[1].mode = -1;
819 modehdlc(&adapter->bcs[0], L1_MODE_NULL);
820 modehdlc(&adapter->bcs[1], L1_MODE_NULL);
821
822 return 0;
823
824 err_region:
825 release_region(adapter->io, 32);
826 err:
827 return retval;
828}
829
830static void __devexit fcpcipnp_release(struct fritz_adapter *adapter)
831{
832 DBG(1,"");
833
834 outb(0, adapter->io + AVM_STATUS0);
835 free_irq(adapter->irq, adapter);
836 release_region(adapter->io, 32);
837}
838
839// ----------------------------------------------------------------------
840
841static struct fritz_adapter * __devinit
842new_adapter(void)
843{
844 struct fritz_adapter *adapter;
845 struct hisax_b_if *b_if[2];
846 int i;
847
848 adapter = kmalloc(sizeof(struct fritz_adapter), GFP_KERNEL);
849 if (!adapter)
850 return NULL;
851
852 memset(adapter, 0, sizeof(struct fritz_adapter));
853
854 adapter->isac.hisax_d_if.owner = THIS_MODULE;
855 adapter->isac.hisax_d_if.ifc.priv = &adapter->isac;
856 adapter->isac.hisax_d_if.ifc.l2l1 = isac_d_l2l1;
857
858 for (i = 0; i < 2; i++) {
859 adapter->bcs[i].adapter = adapter;
860 adapter->bcs[i].channel = i;
861 adapter->bcs[i].b_if.ifc.priv = &adapter->bcs[i];
862 adapter->bcs[i].b_if.ifc.l2l1 = fritz_b_l2l1;
863 }
864
865 for (i = 0; i < 2; i++)
866 b_if[i] = &adapter->bcs[i].b_if;
867
868 hisax_register(&adapter->isac.hisax_d_if, b_if, "fcpcipnp", protocol);
869
870 return adapter;
871}
872
873static void delete_adapter(struct fritz_adapter *adapter)
874{
875 hisax_unregister(&adapter->isac.hisax_d_if);
876 kfree(adapter);
877}
878
879static int __devinit fcpci_probe(struct pci_dev *pdev,
880 const struct pci_device_id *ent)
881{
882 struct fritz_adapter *adapter;
883 int retval;
884
885 retval = -ENOMEM;
886 adapter = new_adapter();
887 if (!adapter)
888 goto err;
889
890 pci_set_drvdata(pdev, adapter);
891
892 if (pdev->device == PCI_DEVICE_ID_AVM_A1_V2)
893 adapter->type = AVM_FRITZ_PCIV2;
894 else
895 adapter->type = AVM_FRITZ_PCI;
896
897 retval = pci_enable_device(pdev);
898 if (retval)
899 goto err_free;
900
901 adapter->io = pci_resource_start(pdev, 1);
902 adapter->irq = pdev->irq;
903
904 printk(KERN_INFO "hisax_fcpcipnp: found adapter %s at %s\n",
905 (char *) ent->driver_data, pci_name(pdev));
906
907 retval = fcpcipnp_setup(adapter);
908 if (retval)
909 goto err_free;
910
911 return 0;
912
913 err_free:
914 delete_adapter(adapter);
915 err:
916 return retval;
917}
918
919#ifdef __ISAPNP__
920static int __devinit fcpnp_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
921{
922 struct fritz_adapter *adapter;
923 int retval;
924
925 if (!pdev)
926 return(-ENODEV);
927
928 retval = -ENOMEM;
929 adapter = new_adapter();
930 if (!adapter)
931 goto err;
932
933 pnp_set_drvdata(pdev, adapter);
934
935 adapter->type = AVM_FRITZ_PNP;
936
937 pnp_disable_dev(pdev);
938 retval = pnp_activate_dev(pdev);
939 if (retval < 0) {
940 printk(KERN_WARNING "%s: pnp_activate_dev(%s) ret(%d)\n", __FUNCTION__,
941 (char *)dev_id->driver_data, retval);
942 goto err_free;
943 }
944 adapter->io = pnp_port_start(pdev, 0);
945 adapter->irq = pnp_irq(pdev, 0);
946
947 printk(KERN_INFO "hisax_fcpcipnp: found adapter %s at IO %#x irq %d\n",
948 (char *) dev_id->driver_data, adapter->io, adapter->irq);
949
950 retval = fcpcipnp_setup(adapter);
951 if (retval)
952 goto err_free;
953
954 return 0;
955
956 err_free:
957 delete_adapter(adapter);
958 err:
959 return retval;
960}
961
962static void __devexit fcpnp_remove(struct pnp_dev *pdev)
963{
964 struct fritz_adapter *adapter = pnp_get_drvdata(pdev);
965
966 if (adapter) {
967 fcpcipnp_release(adapter);
968 delete_adapter(adapter);
969 }
970 pnp_disable_dev(pdev);
971}
972
973static struct pnp_driver fcpnp_driver = {
974 .name = "fcpnp",
975 .probe = fcpnp_probe,
976 .remove = __devexit_p(fcpnp_remove),
977 .id_table = fcpnp_ids,
978};
979#endif
980
981static void __devexit fcpci_remove(struct pci_dev *pdev)
982{
983 struct fritz_adapter *adapter = pci_get_drvdata(pdev);
984
985 fcpcipnp_release(adapter);
986 pci_disable_device(pdev);
987 delete_adapter(adapter);
988}
989
990static struct pci_driver fcpci_driver = {
991 .name = "fcpci",
992 .probe = fcpci_probe,
993 .remove = __devexit_p(fcpci_remove),
994 .id_table = fcpci_ids,
995};
996
997static int __init hisax_fcpcipnp_init(void)
998{
999 int retval;
1000
1001 printk(KERN_INFO "hisax_fcpcipnp: Fritz!Card PCI/PCIv2/PnP ISDN driver v0.0.1\n");
1002
1003 retval = pci_register_driver(&fcpci_driver);
1004 if (retval)
1005 goto out;
1006#ifdef __ISAPNP__
1007 retval = pnp_register_driver(&fcpnp_driver);
1008 if (retval < 0)
1009 goto out_unregister_pci;
1010#endif
1011 return 0;
1012
1013 out_unregister_pci:
1014 pci_unregister_driver(&fcpci_driver);
1015 out:
1016 return retval;
1017}
1018
1019static void __exit hisax_fcpcipnp_exit(void)
1020{
1021#ifdef __ISAPNP__
1022 pnp_unregister_driver(&fcpnp_driver);
1023#endif
1024 pci_unregister_driver(&fcpci_driver);
1025}
1026
1027module_init(hisax_fcpcipnp_init);
1028module_exit(hisax_fcpcipnp_exit);
diff --git a/drivers/isdn/hisax/hisax_fcpcipnp.h b/drivers/isdn/hisax/hisax_fcpcipnp.h
new file mode 100644
index 000000000000..bd8a22e4d6a2
--- /dev/null
+++ b/drivers/isdn/hisax/hisax_fcpcipnp.h
@@ -0,0 +1,58 @@
1#include "hisax_if.h"
2#include "hisax_isac.h"
3#include <linux/pci.h>
4
5#define HSCX_BUFMAX 4096
6
7enum {
8 AVM_FRITZ_PCI,
9 AVM_FRITZ_PNP,
10 AVM_FRITZ_PCIV2,
11};
12
13struct hdlc_stat_reg {
14#ifdef __BIG_ENDIAN
15 u_char fill __attribute__((packed));
16 u_char mode __attribute__((packed));
17 u_char xml __attribute__((packed));
18 u_char cmd __attribute__((packed));
19#else
20 u_char cmd __attribute__((packed));
21 u_char xml __attribute__((packed));
22 u_char mode __attribute__((packed));
23 u_char fill __attribute__((packed));
24#endif
25};
26
27struct fritz_bcs {
28 struct hisax_b_if b_if;
29 struct fritz_adapter *adapter;
30 int mode;
31 int channel;
32
33 union {
34 u_int ctrl;
35 struct hdlc_stat_reg sr;
36 } ctrl;
37 u_int stat;
38 int rcvidx;
39 int fifo_size;
40 u_char rcvbuf[HSCX_BUFMAX]; /* B-Channel receive Buffer */
41
42 int tx_cnt; /* B-Channel transmit counter */
43 struct sk_buff *tx_skb; /* B-Channel transmit Buffer */
44};
45
46struct fritz_adapter {
47 int type;
48 spinlock_t hw_lock;
49 unsigned int io;
50 unsigned int irq;
51 struct isac isac;
52
53 struct fritz_bcs bcs[2];
54
55 u32 (*read_hdlc_status) (struct fritz_adapter *adapter, int nr);
56 void (*write_ctrl) (struct fritz_bcs *bcs, int which);
57};
58
diff --git a/drivers/isdn/hisax/hisax_if.h b/drivers/isdn/hisax/hisax_if.h
new file mode 100644
index 000000000000..4898fce2d509
--- /dev/null
+++ b/drivers/isdn/hisax/hisax_if.h
@@ -0,0 +1,66 @@
1/*
2 * Interface between low level (hardware) drivers and
3 * HiSax protocol stack
4 *
5 * Author Kai Germaschewski
6 * Copyright 2001 by Kai Germaschewski <kai.germaschewski@gmx.de>
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 */
12
13#ifndef __HISAX_IF_H__
14#define __HISAX_IF_H__
15
16#include <linux/skbuff.h>
17
18#define REQUEST 0
19#define CONFIRM 1
20#define INDICATION 2
21#define RESPONSE 3
22
23#define PH_ACTIVATE 0x0100
24#define PH_DEACTIVATE 0x0110
25#define PH_DATA 0x0120
26#define PH_PULL 0x0130
27#define PH_DATA_E 0x0140
28
29#define L1_MODE_NULL 0
30#define L1_MODE_TRANS 1
31#define L1_MODE_HDLC 2
32#define L1_MODE_EXTRN 3
33#define L1_MODE_HDLC_56K 4
34#define L1_MODE_MODEM 7
35#define L1_MODE_V32 8
36#define L1_MODE_FAX 9
37
38struct hisax_if {
39 void *priv; // private to driver
40 void (*l1l2)(struct hisax_if *, int pr, void *arg);
41 void (*l2l1)(struct hisax_if *, int pr, void *arg);
42};
43
44struct hisax_b_if {
45 struct hisax_if ifc;
46
47 // private to hisax
48 struct BCState *bcs;
49};
50
51struct hisax_d_if {
52 struct hisax_if ifc;
53
54 // private to hisax
55 struct module *owner;
56 struct IsdnCardState *cs;
57 struct hisax_b_if *b_if[2];
58 struct sk_buff_head erq;
59 long ph_state;
60};
61
62int hisax_register(struct hisax_d_if *hisax_if, struct hisax_b_if *b_if[],
63 char *name, int protocol);
64void hisax_unregister(struct hisax_d_if *hisax_if);
65
66#endif
diff --git a/drivers/isdn/hisax/hisax_isac.c b/drivers/isdn/hisax/hisax_isac.c
new file mode 100644
index 000000000000..f4972f6c1f5d
--- /dev/null
+++ b/drivers/isdn/hisax/hisax_isac.c
@@ -0,0 +1,897 @@
1/*
2 * Driver for ISAC-S and ISAC-SX
3 * ISDN Subscriber Access Controller for Terminals
4 *
5 * Author Kai Germaschewski
6 * Copyright 2001 by Kai Germaschewski <kai.germaschewski@gmx.de>
7 * 2001 by Karsten Keil <keil@isdn4linux.de>
8 *
9 * based upon Karsten Keil's original isac.c driver
10 *
11 * This software may be used and distributed according to the terms
12 * of the GNU General Public License, incorporated herein by reference.
13 *
14 * Thanks to Wizard Computersysteme GmbH, Bremervoerde and
15 * SoHaNet Technology GmbH, Berlin
16 * for supporting the development of this driver
17 */
18
19/* TODO:
20 * specifically handle level vs edge triggered?
21 */
22
23#include <linux/module.h>
24#include <linux/init.h>
25#include <linux/netdevice.h>
26#include "hisax_isac.h"
27
28// debugging cruft
29
30#define __debug_variable debug
31#include "hisax_debug.h"
32
33#ifdef CONFIG_HISAX_DEBUG
34static int debug = 1;
35module_param(debug, int, 0);
36
37static char *ISACVer[] = {
38 "2086/2186 V1.1",
39 "2085 B1",
40 "2085 B2",
41 "2085 V2.3"
42};
43#endif
44
45MODULE_AUTHOR("Kai Germaschewski <kai.germaschewski@gmx.de>/Karsten Keil <kkeil@suse.de>");
46MODULE_DESCRIPTION("ISAC/ISAC-SX driver");
47MODULE_LICENSE("GPL");
48
49#define DBG_WARN 0x0001
50#define DBG_IRQ 0x0002
51#define DBG_L1M 0x0004
52#define DBG_PR 0x0008
53#define DBG_RFIFO 0x0100
54#define DBG_RPACKET 0x0200
55#define DBG_XFIFO 0x1000
56#define DBG_XPACKET 0x2000
57
58// we need to distinguish ISAC-S and ISAC-SX
59#define TYPE_ISAC 0x00
60#define TYPE_ISACSX 0x01
61
62// registers etc.
63#define ISAC_MASK 0x20
64#define ISAC_ISTA 0x20
65#define ISAC_ISTA_EXI 0x01
66#define ISAC_ISTA_SIN 0x02
67#define ISAC_ISTA_CISQ 0x04
68#define ISAC_ISTA_XPR 0x10
69#define ISAC_ISTA_RSC 0x20
70#define ISAC_ISTA_RPF 0x40
71#define ISAC_ISTA_RME 0x80
72
73#define ISAC_STAR 0x21
74#define ISAC_CMDR 0x21
75#define ISAC_CMDR_XRES 0x01
76#define ISAC_CMDR_XME 0x02
77#define ISAC_CMDR_XTF 0x08
78#define ISAC_CMDR_RRES 0x40
79#define ISAC_CMDR_RMC 0x80
80
81#define ISAC_EXIR 0x24
82#define ISAC_EXIR_MOS 0x04
83#define ISAC_EXIR_XDU 0x40
84#define ISAC_EXIR_XMR 0x80
85
86#define ISAC_ADF2 0x39
87#define ISAC_SPCR 0x30
88#define ISAC_ADF1 0x38
89
90#define ISAC_CIR0 0x31
91#define ISAC_CIX0 0x31
92#define ISAC_CIR0_CIC0 0x02
93#define ISAC_CIR0_CIC1 0x01
94
95#define ISAC_CIR1 0x33
96#define ISAC_CIX1 0x33
97#define ISAC_STCR 0x37
98#define ISAC_MODE 0x22
99
100#define ISAC_RSTA 0x27
101#define ISAC_RSTA_RDO 0x40
102#define ISAC_RSTA_CRC 0x20
103#define ISAC_RSTA_RAB 0x10
104
105#define ISAC_RBCL 0x25
106#define ISAC_RBCH 0x2A
107#define ISAC_TIMR 0x23
108#define ISAC_SQXR 0x3b
109#define ISAC_MOSR 0x3a
110#define ISAC_MOCR 0x3a
111#define ISAC_MOR0 0x32
112#define ISAC_MOX0 0x32
113#define ISAC_MOR1 0x34
114#define ISAC_MOX1 0x34
115
116#define ISAC_RBCH_XAC 0x80
117
118#define ISAC_CMD_TIM 0x0
119#define ISAC_CMD_RES 0x1
120#define ISAC_CMD_SSP 0x2
121#define ISAC_CMD_SCP 0x3
122#define ISAC_CMD_AR8 0x8
123#define ISAC_CMD_AR10 0x9
124#define ISAC_CMD_ARL 0xa
125#define ISAC_CMD_DI 0xf
126
127#define ISACSX_MASK 0x60
128#define ISACSX_ISTA 0x60
129#define ISACSX_ISTA_ICD 0x01
130#define ISACSX_ISTA_CIC 0x10
131
132#define ISACSX_MASKD 0x20
133#define ISACSX_ISTAD 0x20
134#define ISACSX_ISTAD_XDU 0x04
135#define ISACSX_ISTAD_XMR 0x08
136#define ISACSX_ISTAD_XPR 0x10
137#define ISACSX_ISTAD_RFO 0x20
138#define ISACSX_ISTAD_RPF 0x40
139#define ISACSX_ISTAD_RME 0x80
140
141#define ISACSX_CMDRD 0x21
142#define ISACSX_CMDRD_XRES 0x01
143#define ISACSX_CMDRD_XME 0x02
144#define ISACSX_CMDRD_XTF 0x08
145#define ISACSX_CMDRD_RRES 0x40
146#define ISACSX_CMDRD_RMC 0x80
147
148#define ISACSX_MODED 0x22
149
150#define ISACSX_RBCLD 0x26
151
152#define ISACSX_RSTAD 0x28
153#define ISACSX_RSTAD_RAB 0x10
154#define ISACSX_RSTAD_CRC 0x20
155#define ISACSX_RSTAD_RDO 0x40
156#define ISACSX_RSTAD_VFR 0x80
157
158#define ISACSX_CIR0 0x2e
159#define ISACSX_CIR0_CIC0 0x08
160#define ISACSX_CIX0 0x2e
161
162#define ISACSX_TR_CONF0 0x30
163
164#define ISACSX_TR_CONF2 0x32
165
166static struct Fsm l1fsm;
167
168enum {
169 ST_L1_RESET,
170 ST_L1_F3_PDOWN,
171 ST_L1_F3_PUP,
172 ST_L1_F3_PEND_DEACT,
173 ST_L1_F4,
174 ST_L1_F5,
175 ST_L1_F6,
176 ST_L1_F7,
177 ST_L1_F8,
178};
179
180#define L1_STATE_COUNT (ST_L1_F8+1)
181
182static char *strL1State[] =
183{
184 "ST_L1_RESET",
185 "ST_L1_F3_PDOWN",
186 "ST_L1_F3_PUP",
187 "ST_L1_F3_PEND_DEACT",
188 "ST_L1_F4",
189 "ST_L1_F5",
190 "ST_L1_F6",
191 "ST_L1_F7",
192 "ST_L1_F8",
193};
194
195enum {
196 EV_PH_DR, // 0000
197 EV_PH_RES, // 0001
198 EV_PH_TMA, // 0010
199 EV_PH_SLD, // 0011
200 EV_PH_RSY, // 0100
201 EV_PH_DR6, // 0101
202 EV_PH_EI, // 0110
203 EV_PH_PU, // 0111
204 EV_PH_AR, // 1000
205 EV_PH_9, // 1001
206 EV_PH_ARL, // 1010
207 EV_PH_CVR, // 1011
208 EV_PH_AI8, // 1100
209 EV_PH_AI10, // 1101
210 EV_PH_AIL, // 1110
211 EV_PH_DC, // 1111
212 EV_PH_ACTIVATE_REQ,
213 EV_PH_DEACTIVATE_REQ,
214 EV_TIMER3,
215};
216
217#define L1_EVENT_COUNT (EV_TIMER3 + 1)
218
219static char *strL1Event[] =
220{
221 "EV_PH_DR", // 0000
222 "EV_PH_RES", // 0001
223 "EV_PH_TMA", // 0010
224 "EV_PH_SLD", // 0011
225 "EV_PH_RSY", // 0100
226 "EV_PH_DR6", // 0101
227 "EV_PH_EI", // 0110
228 "EV_PH_PU", // 0111
229 "EV_PH_AR", // 1000
230 "EV_PH_9", // 1001
231 "EV_PH_ARL", // 1010
232 "EV_PH_CVR", // 1011
233 "EV_PH_AI8", // 1100
234 "EV_PH_AI10", // 1101
235 "EV_PH_AIL", // 1110
236 "EV_PH_DC", // 1111
237 "EV_PH_ACTIVATE_REQ",
238 "EV_PH_DEACTIVATE_REQ",
239 "EV_TIMER3",
240};
241
242static inline void D_L1L2(struct isac *isac, int pr, void *arg)
243{
244 struct hisax_if *ifc = (struct hisax_if *) &isac->hisax_d_if;
245
246 DBG(DBG_PR, "pr %#x", pr);
247 ifc->l1l2(ifc, pr, arg);
248}
249
250static void ph_command(struct isac *isac, unsigned int command)
251{
252 DBG(DBG_L1M, "ph_command %#x", command);
253 switch (isac->type) {
254 case TYPE_ISAC:
255 isac->write_isac(isac, ISAC_CIX0, (command << 2) | 3);
256 break;
257 case TYPE_ISACSX:
258 isac->write_isac(isac, ISACSX_CIX0, (command << 4) | (7 << 1));
259 break;
260 }
261}
262
263// ----------------------------------------------------------------------
264
265static void l1_di(struct FsmInst *fi, int event, void *arg)
266{
267 struct isac *isac = fi->userdata;
268
269 FsmChangeState(fi, ST_L1_RESET);
270 ph_command(isac, ISAC_CMD_DI);
271}
272
273static void l1_di_deact_ind(struct FsmInst *fi, int event, void *arg)
274{
275 struct isac *isac = fi->userdata;
276
277 FsmChangeState(fi, ST_L1_RESET);
278 D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL);
279 ph_command(isac, ISAC_CMD_DI);
280}
281
282static void l1_go_f3pdown(struct FsmInst *fi, int event, void *arg)
283{
284 FsmChangeState(fi, ST_L1_F3_PDOWN);
285}
286
287static void l1_go_f3pend_deact_ind(struct FsmInst *fi, int event, void *arg)
288{
289 struct isac *isac = fi->userdata;
290
291 FsmChangeState(fi, ST_L1_F3_PEND_DEACT);
292 D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL);
293 ph_command(isac, ISAC_CMD_DI);
294}
295
296static void l1_go_f3pend(struct FsmInst *fi, int event, void *arg)
297{
298 struct isac *isac = fi->userdata;
299
300 FsmChangeState(fi, ST_L1_F3_PEND_DEACT);
301 ph_command(isac, ISAC_CMD_DI);
302}
303
304static void l1_go_f4(struct FsmInst *fi, int event, void *arg)
305{
306 FsmChangeState(fi, ST_L1_F4);
307}
308
309static void l1_go_f5(struct FsmInst *fi, int event, void *arg)
310{
311 FsmChangeState(fi, ST_L1_F5);
312}
313
314static void l1_go_f6(struct FsmInst *fi, int event, void *arg)
315{
316 FsmChangeState(fi, ST_L1_F6);
317}
318
319static void l1_go_f6_deact_ind(struct FsmInst *fi, int event, void *arg)
320{
321 struct isac *isac = fi->userdata;
322
323 FsmChangeState(fi, ST_L1_F6);
324 D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL);
325}
326
327static void l1_go_f7_act_ind(struct FsmInst *fi, int event, void *arg)
328{
329 struct isac *isac = fi->userdata;
330
331 FsmDelTimer(&isac->timer, 0);
332 FsmChangeState(fi, ST_L1_F7);
333 ph_command(isac, ISAC_CMD_AR8);
334 D_L1L2(isac, PH_ACTIVATE | INDICATION, NULL);
335}
336
337static void l1_go_f8(struct FsmInst *fi, int event, void *arg)
338{
339 FsmChangeState(fi, ST_L1_F8);
340}
341
342static void l1_go_f8_deact_ind(struct FsmInst *fi, int event, void *arg)
343{
344 struct isac *isac = fi->userdata;
345
346 FsmChangeState(fi, ST_L1_F8);
347 D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL);
348}
349
350static void l1_ar8(struct FsmInst *fi, int event, void *arg)
351{
352 struct isac *isac = fi->userdata;
353
354 FsmRestartTimer(&isac->timer, TIMER3_VALUE, EV_TIMER3, NULL, 2);
355 ph_command(isac, ISAC_CMD_AR8);
356}
357
358static void l1_timer3(struct FsmInst *fi, int event, void *arg)
359{
360 struct isac *isac = fi->userdata;
361
362 ph_command(isac, ISAC_CMD_DI);
363 D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL);
364}
365
366// state machines according to data sheet PSB 2186 / 3186
367
368static struct FsmNode L1FnList[] __initdata =
369{
370 {ST_L1_RESET, EV_PH_RES, l1_di},
371 {ST_L1_RESET, EV_PH_EI, l1_di},
372 {ST_L1_RESET, EV_PH_DC, l1_go_f3pdown},
373 {ST_L1_RESET, EV_PH_AR, l1_go_f6},
374 {ST_L1_RESET, EV_PH_AI8, l1_go_f7_act_ind},
375
376 {ST_L1_F3_PDOWN, EV_PH_RES, l1_di},
377 {ST_L1_F3_PDOWN, EV_PH_EI, l1_di},
378 {ST_L1_F3_PDOWN, EV_PH_AR, l1_go_f6},
379 {ST_L1_F3_PDOWN, EV_PH_RSY, l1_go_f5},
380 {ST_L1_F3_PDOWN, EV_PH_PU, l1_go_f4},
381 {ST_L1_F3_PDOWN, EV_PH_AI8, l1_go_f7_act_ind},
382 {ST_L1_F3_PDOWN, EV_PH_ACTIVATE_REQ, l1_ar8},
383 {ST_L1_F3_PDOWN, EV_TIMER3, l1_timer3},
384
385 {ST_L1_F3_PEND_DEACT, EV_PH_RES, l1_di},
386 {ST_L1_F3_PEND_DEACT, EV_PH_EI, l1_di},
387 {ST_L1_F3_PEND_DEACT, EV_PH_DC, l1_go_f3pdown},
388 {ST_L1_F3_PEND_DEACT, EV_PH_RSY, l1_go_f5},
389 {ST_L1_F3_PEND_DEACT, EV_PH_AR, l1_go_f6},
390 {ST_L1_F3_PEND_DEACT, EV_PH_AI8, l1_go_f7_act_ind},
391
392 {ST_L1_F4, EV_PH_RES, l1_di},
393 {ST_L1_F4, EV_PH_EI, l1_di},
394 {ST_L1_F4, EV_PH_RSY, l1_go_f5},
395 {ST_L1_F4, EV_PH_AI8, l1_go_f7_act_ind},
396 {ST_L1_F4, EV_TIMER3, l1_timer3},
397 {ST_L1_F4, EV_PH_DC, l1_go_f3pdown},
398
399 {ST_L1_F5, EV_PH_RES, l1_di},
400 {ST_L1_F5, EV_PH_EI, l1_di},
401 {ST_L1_F5, EV_PH_AR, l1_go_f6},
402 {ST_L1_F5, EV_PH_AI8, l1_go_f7_act_ind},
403 {ST_L1_F5, EV_TIMER3, l1_timer3},
404 {ST_L1_F5, EV_PH_DR, l1_go_f3pend},
405 {ST_L1_F5, EV_PH_DC, l1_go_f3pdown},
406
407 {ST_L1_F6, EV_PH_RES, l1_di},
408 {ST_L1_F6, EV_PH_EI, l1_di},
409 {ST_L1_F6, EV_PH_RSY, l1_go_f8},
410 {ST_L1_F6, EV_PH_AI8, l1_go_f7_act_ind},
411 {ST_L1_F6, EV_PH_DR6, l1_go_f3pend},
412 {ST_L1_F6, EV_TIMER3, l1_timer3},
413 {ST_L1_F6, EV_PH_DC, l1_go_f3pdown},
414
415 {ST_L1_F7, EV_PH_RES, l1_di_deact_ind},
416 {ST_L1_F7, EV_PH_EI, l1_di_deact_ind},
417 {ST_L1_F7, EV_PH_AR, l1_go_f6_deact_ind},
418 {ST_L1_F7, EV_PH_RSY, l1_go_f8_deact_ind},
419 {ST_L1_F7, EV_PH_DR, l1_go_f3pend_deact_ind},
420
421 {ST_L1_F8, EV_PH_RES, l1_di},
422 {ST_L1_F8, EV_PH_EI, l1_di},
423 {ST_L1_F8, EV_PH_AR, l1_go_f6},
424 {ST_L1_F8, EV_PH_DR, l1_go_f3pend},
425 {ST_L1_F8, EV_PH_AI8, l1_go_f7_act_ind},
426 {ST_L1_F8, EV_TIMER3, l1_timer3},
427 {ST_L1_F8, EV_PH_DC, l1_go_f3pdown},
428};
429
430static void l1m_debug(struct FsmInst *fi, char *fmt, ...)
431{
432 va_list args;
433 char buf[256];
434
435 va_start(args, fmt);
436 vsprintf(buf, fmt, args);
437 DBG(DBG_L1M, "%s", buf);
438 va_end(args);
439}
440
441static void isac_version(struct isac *cs)
442{
443 int val;
444
445 val = cs->read_isac(cs, ISAC_RBCH);
446 DBG(1, "ISAC version (%x): %s", val, ISACVer[(val >> 5) & 3]);
447}
448
449static void isac_empty_fifo(struct isac *isac, int count)
450{
451 // this also works for isacsx, since
452 // CMDR(D) register works the same
453 u_char *ptr;
454
455 DBG(DBG_IRQ, "count %d", count);
456
457 if ((isac->rcvidx + count) >= MAX_DFRAME_LEN_L1) {
458 DBG(DBG_WARN, "overrun %d", isac->rcvidx + count);
459 isac->write_isac(isac, ISAC_CMDR, ISAC_CMDR_RMC);
460 isac->rcvidx = 0;
461 return;
462 }
463 ptr = isac->rcvbuf + isac->rcvidx;
464 isac->rcvidx += count;
465 isac->read_isac_fifo(isac, ptr, count);
466 isac->write_isac(isac, ISAC_CMDR, ISAC_CMDR_RMC);
467 DBG_PACKET(DBG_RFIFO, ptr, count);
468}
469
470static void isac_fill_fifo(struct isac *isac)
471{
472 // this also works for isacsx, since
473 // CMDR(D) register works the same
474
475 int count;
476 unsigned char cmd;
477 u_char *ptr;
478
479 if (!isac->tx_skb)
480 BUG();
481
482 count = isac->tx_skb->len;
483 if (count <= 0)
484 BUG();
485
486 DBG(DBG_IRQ, "count %d", count);
487
488 if (count > 0x20) {
489 count = 0x20;
490 cmd = ISAC_CMDR_XTF;
491 } else {
492 cmd = ISAC_CMDR_XTF | ISAC_CMDR_XME;
493 }
494
495 ptr = isac->tx_skb->data;
496 skb_pull(isac->tx_skb, count);
497 isac->tx_cnt += count;
498 DBG_PACKET(DBG_XFIFO, ptr, count);
499 isac->write_isac_fifo(isac, ptr, count);
500 isac->write_isac(isac, ISAC_CMDR, cmd);
501}
502
503static void isac_retransmit(struct isac *isac)
504{
505 if (!isac->tx_skb) {
506 DBG(DBG_WARN, "no skb");
507 return;
508 }
509 skb_push(isac->tx_skb, isac->tx_cnt);
510 isac->tx_cnt = 0;
511}
512
513
514static inline void isac_cisq_interrupt(struct isac *isac)
515{
516 unsigned char val;
517
518 val = isac->read_isac(isac, ISAC_CIR0);
519 DBG(DBG_IRQ, "CIR0 %#x", val);
520 if (val & ISAC_CIR0_CIC0) {
521 DBG(DBG_IRQ, "CODR0 %#x", (val >> 2) & 0xf);
522 FsmEvent(&isac->l1m, (val >> 2) & 0xf, NULL);
523 }
524 if (val & ISAC_CIR0_CIC1) {
525 val = isac->read_isac(isac, ISAC_CIR1);
526 DBG(DBG_WARN, "ISAC CIR1 %#x", val );
527 }
528}
529
530static inline void isac_rme_interrupt(struct isac *isac)
531{
532 unsigned char val;
533 int count;
534 struct sk_buff *skb;
535
536 val = isac->read_isac(isac, ISAC_RSTA);
537 if ((val & (ISAC_RSTA_RDO | ISAC_RSTA_CRC | ISAC_RSTA_RAB) )
538 != ISAC_RSTA_CRC) {
539 DBG(DBG_WARN, "RSTA %#x, dropped", val);
540 isac->write_isac(isac, ISAC_CMDR, ISAC_CMDR_RMC);
541 goto out;
542 }
543
544 count = isac->read_isac(isac, ISAC_RBCL) & 0x1f;
545 DBG(DBG_IRQ, "RBCL %#x", count);
546 if (count == 0)
547 count = 0x20;
548
549 isac_empty_fifo(isac, count);
550 count = isac->rcvidx;
551 if (count < 1) {
552 DBG(DBG_WARN, "count %d < 1", count);
553 goto out;
554 }
555
556 skb = alloc_skb(count, GFP_ATOMIC);
557 if (!skb) {
558 DBG(DBG_WARN, "no memory, dropping\n");
559 goto out;
560 }
561 memcpy(skb_put(skb, count), isac->rcvbuf, count);
562 DBG_SKB(DBG_RPACKET, skb);
563 D_L1L2(isac, PH_DATA | INDICATION, skb);
564 out:
565 isac->rcvidx = 0;
566}
567
568static inline void isac_xpr_interrupt(struct isac *isac)
569{
570 if (!isac->tx_skb)
571 return;
572
573 if (isac->tx_skb->len > 0) {
574 isac_fill_fifo(isac);
575 return;
576 }
577 dev_kfree_skb_irq(isac->tx_skb);
578 isac->tx_cnt = 0;
579 isac->tx_skb = NULL;
580 D_L1L2(isac, PH_DATA | CONFIRM, NULL);
581}
582
583static inline void isac_exi_interrupt(struct isac *isac)
584{
585 unsigned char val;
586
587 val = isac->read_isac(isac, ISAC_EXIR);
588 DBG(2, "EXIR %#x", val);
589
590 if (val & ISAC_EXIR_XMR) {
591 DBG(DBG_WARN, "ISAC XMR");
592 isac_retransmit(isac);
593 }
594 if (val & ISAC_EXIR_XDU) {
595 DBG(DBG_WARN, "ISAC XDU");
596 isac_retransmit(isac);
597 }
598 if (val & ISAC_EXIR_MOS) { /* MOS */
599 DBG(DBG_WARN, "MOS");
600 val = isac->read_isac(isac, ISAC_MOSR);
601 DBG(2, "ISAC MOSR %#x", val);
602 }
603}
604
605void isac_irq(struct isac *isac)
606{
607 unsigned char val;
608
609 val = isac->read_isac(isac, ISAC_ISTA);
610 DBG(DBG_IRQ, "ISTA %#x", val);
611
612 if (val & ISAC_ISTA_EXI) {
613 DBG(DBG_IRQ, "EXI");
614 isac_exi_interrupt(isac);
615 }
616 if (val & ISAC_ISTA_XPR) {
617 DBG(DBG_IRQ, "XPR");
618 isac_xpr_interrupt(isac);
619 }
620 if (val & ISAC_ISTA_RME) {
621 DBG(DBG_IRQ, "RME");
622 isac_rme_interrupt(isac);
623 }
624 if (val & ISAC_ISTA_RPF) {
625 DBG(DBG_IRQ, "RPF");
626 isac_empty_fifo(isac, 0x20);
627 }
628 if (val & ISAC_ISTA_CISQ) {
629 DBG(DBG_IRQ, "CISQ");
630 isac_cisq_interrupt(isac);
631 }
632 if (val & ISAC_ISTA_RSC) {
633 DBG(DBG_WARN, "RSC");
634 }
635 if (val & ISAC_ISTA_SIN) {
636 DBG(DBG_WARN, "SIN");
637 }
638 isac->write_isac(isac, ISAC_MASK, 0xff);
639 isac->write_isac(isac, ISAC_MASK, 0x00);
640}
641
642// ======================================================================
643
644static inline void isacsx_cic_interrupt(struct isac *isac)
645{
646 unsigned char val;
647
648 val = isac->read_isac(isac, ISACSX_CIR0);
649 DBG(DBG_IRQ, "CIR0 %#x", val);
650 if (val & ISACSX_CIR0_CIC0) {
651 DBG(DBG_IRQ, "CODR0 %#x", val >> 4);
652 FsmEvent(&isac->l1m, val >> 4, NULL);
653 }
654}
655
656static inline void isacsx_rme_interrupt(struct isac *isac)
657{
658 int count;
659 struct sk_buff *skb;
660 unsigned char val;
661
662 val = isac->read_isac(isac, ISACSX_RSTAD);
663 if ((val & (ISACSX_RSTAD_VFR |
664 ISACSX_RSTAD_RDO |
665 ISACSX_RSTAD_CRC |
666 ISACSX_RSTAD_RAB))
667 != (ISACSX_RSTAD_VFR | ISACSX_RSTAD_CRC)) {
668 DBG(DBG_WARN, "RSTAD %#x, dropped", val);
669 isac->write_isac(isac, ISACSX_CMDRD, ISACSX_CMDRD_RMC);
670 goto out;
671 }
672
673 count = isac->read_isac(isac, ISACSX_RBCLD) & 0x1f;
674 DBG(DBG_IRQ, "RBCLD %#x", count);
675 if (count == 0)
676 count = 0x20;
677
678 isac_empty_fifo(isac, count);
679 // strip trailing status byte
680 count = isac->rcvidx - 1;
681 if (count < 1) {
682 DBG(DBG_WARN, "count %d < 1", count);
683 goto out;
684 }
685
686 skb = dev_alloc_skb(count);
687 if (!skb) {
688 DBG(DBG_WARN, "no memory, dropping");
689 goto out;
690 }
691 memcpy(skb_put(skb, count), isac->rcvbuf, count);
692 DBG_SKB(DBG_RPACKET, skb);
693 D_L1L2(isac, PH_DATA | INDICATION, skb);
694 out:
695 isac->rcvidx = 0;
696}
697
698static inline void isacsx_xpr_interrupt(struct isac *isac)
699{
700 if (!isac->tx_skb)
701 return;
702
703 if (isac->tx_skb->len > 0) {
704 isac_fill_fifo(isac);
705 return;
706 }
707 dev_kfree_skb_irq(isac->tx_skb);
708 isac->tx_skb = NULL;
709 isac->tx_cnt = 0;
710 D_L1L2(isac, PH_DATA | CONFIRM, NULL);
711}
712
713static inline void isacsx_icd_interrupt(struct isac *isac)
714{
715 unsigned char val;
716
717 val = isac->read_isac(isac, ISACSX_ISTAD);
718 DBG(DBG_IRQ, "ISTAD %#x", val);
719 if (val & ISACSX_ISTAD_XDU) {
720 DBG(DBG_WARN, "ISTAD XDU");
721 isac_retransmit(isac);
722 }
723 if (val & ISACSX_ISTAD_XMR) {
724 DBG(DBG_WARN, "ISTAD XMR");
725 isac_retransmit(isac);
726 }
727 if (val & ISACSX_ISTAD_XPR) {
728 DBG(DBG_IRQ, "ISTAD XPR");
729 isacsx_xpr_interrupt(isac);
730 }
731 if (val & ISACSX_ISTAD_RFO) {
732 DBG(DBG_WARN, "ISTAD RFO");
733 isac->write_isac(isac, ISACSX_CMDRD, ISACSX_CMDRD_RMC);
734 }
735 if (val & ISACSX_ISTAD_RME) {
736 DBG(DBG_IRQ, "ISTAD RME");
737 isacsx_rme_interrupt(isac);
738 }
739 if (val & ISACSX_ISTAD_RPF) {
740 DBG(DBG_IRQ, "ISTAD RPF");
741 isac_empty_fifo(isac, 0x20);
742 }
743}
744
745void isacsx_irq(struct isac *isac)
746{
747 unsigned char val;
748
749 val = isac->read_isac(isac, ISACSX_ISTA);
750 DBG(DBG_IRQ, "ISTA %#x", val);
751
752 if (val & ISACSX_ISTA_ICD)
753 isacsx_icd_interrupt(isac);
754 if (val & ISACSX_ISTA_CIC)
755 isacsx_cic_interrupt(isac);
756}
757
758void isac_init(struct isac *isac)
759{
760 isac->tx_skb = NULL;
761 isac->l1m.fsm = &l1fsm;
762 isac->l1m.state = ST_L1_RESET;
763#ifdef CONFIG_HISAX_DEBUG
764 isac->l1m.debug = 1;
765#else
766 isac->l1m.debug = 0;
767#endif
768 isac->l1m.userdata = isac;
769 isac->l1m.printdebug = l1m_debug;
770 FsmInitTimer(&isac->l1m, &isac->timer);
771}
772
773void isac_setup(struct isac *isac)
774{
775 int val, eval;
776
777 isac->type = TYPE_ISAC;
778 isac_version(isac);
779
780 ph_command(isac, ISAC_CMD_RES);
781
782 isac->write_isac(isac, ISAC_MASK, 0xff);
783 isac->mocr = 0xaa;
784 if (test_bit(ISAC_IOM1, &isac->flags)) {
785 /* IOM 1 Mode */
786 isac->write_isac(isac, ISAC_ADF2, 0x0);
787 isac->write_isac(isac, ISAC_SPCR, 0xa);
788 isac->write_isac(isac, ISAC_ADF1, 0x2);
789 isac->write_isac(isac, ISAC_STCR, 0x70);
790 isac->write_isac(isac, ISAC_MODE, 0xc9);
791 } else {
792 /* IOM 2 Mode */
793 if (!isac->adf2)
794 isac->adf2 = 0x80;
795 isac->write_isac(isac, ISAC_ADF2, isac->adf2);
796 isac->write_isac(isac, ISAC_SQXR, 0x2f);
797 isac->write_isac(isac, ISAC_SPCR, 0x00);
798 isac->write_isac(isac, ISAC_STCR, 0x70);
799 isac->write_isac(isac, ISAC_MODE, 0xc9);
800 isac->write_isac(isac, ISAC_TIMR, 0x00);
801 isac->write_isac(isac, ISAC_ADF1, 0x00);
802 }
803 val = isac->read_isac(isac, ISAC_STAR);
804 DBG(2, "ISAC STAR %x", val);
805 val = isac->read_isac(isac, ISAC_MODE);
806 DBG(2, "ISAC MODE %x", val);
807 val = isac->read_isac(isac, ISAC_ADF2);
808 DBG(2, "ISAC ADF2 %x", val);
809 val = isac->read_isac(isac, ISAC_ISTA);
810 DBG(2, "ISAC ISTA %x", val);
811 if (val & 0x01) {
812 eval = isac->read_isac(isac, ISAC_EXIR);
813 DBG(2, "ISAC EXIR %x", eval);
814 }
815 val = isac->read_isac(isac, ISAC_CIR0);
816 DBG(2, "ISAC CIR0 %x", val);
817 FsmEvent(&isac->l1m, (val >> 2) & 0xf, NULL);
818
819 isac->write_isac(isac, ISAC_MASK, 0x0);
820 // RESET Receiver and Transmitter
821 isac->write_isac(isac, ISAC_CMDR, ISAC_CMDR_XRES | ISAC_CMDR_RRES);
822}
823
824void isacsx_setup(struct isac *isac)
825{
826 isac->type = TYPE_ISACSX;
827 // clear LDD
828 isac->write_isac(isac, ISACSX_TR_CONF0, 0x00);
829 // enable transmitter
830 isac->write_isac(isac, ISACSX_TR_CONF2, 0x00);
831 // transparent mode 0, RAC, stop/go
832 isac->write_isac(isac, ISACSX_MODED, 0xc9);
833 // all HDLC IRQ unmasked
834 isac->write_isac(isac, ISACSX_MASKD, 0x03);
835 // unmask ICD, CID IRQs
836 isac->write_isac(isac, ISACSX_MASK,
837 ~(ISACSX_ISTA_ICD | ISACSX_ISTA_CIC));
838}
839
840void isac_d_l2l1(struct hisax_if *hisax_d_if, int pr, void *arg)
841{
842 struct isac *isac = hisax_d_if->priv;
843 struct sk_buff *skb = arg;
844
845 DBG(DBG_PR, "pr %#x", pr);
846
847 switch (pr) {
848 case PH_ACTIVATE | REQUEST:
849 FsmEvent(&isac->l1m, EV_PH_ACTIVATE_REQ, NULL);
850 break;
851 case PH_DEACTIVATE | REQUEST:
852 FsmEvent(&isac->l1m, EV_PH_DEACTIVATE_REQ, NULL);
853 break;
854 case PH_DATA | REQUEST:
855 DBG(DBG_PR, "PH_DATA REQUEST len %d", skb->len);
856 DBG_SKB(DBG_XPACKET, skb);
857 if (isac->l1m.state != ST_L1_F7) {
858 DBG(1, "L1 wrong state %d\n", isac->l1m.state);
859 dev_kfree_skb(skb);
860 break;
861 }
862 if (isac->tx_skb)
863 BUG();
864
865 isac->tx_skb = skb;
866 isac_fill_fifo(isac);
867 break;
868 }
869}
870
871static int __init hisax_isac_init(void)
872{
873 printk(KERN_INFO "hisax_isac: ISAC-S/ISAC-SX ISDN driver v0.1.0\n");
874
875 l1fsm.state_count = L1_STATE_COUNT;
876 l1fsm.event_count = L1_EVENT_COUNT;
877 l1fsm.strState = strL1State;
878 l1fsm.strEvent = strL1Event;
879 return FsmNew(&l1fsm, L1FnList, ARRAY_SIZE(L1FnList));
880}
881
882static void __exit hisax_isac_exit(void)
883{
884 FsmFree(&l1fsm);
885}
886
887EXPORT_SYMBOL(isac_init);
888EXPORT_SYMBOL(isac_d_l2l1);
889
890EXPORT_SYMBOL(isacsx_setup);
891EXPORT_SYMBOL(isacsx_irq);
892
893EXPORT_SYMBOL(isac_setup);
894EXPORT_SYMBOL(isac_irq);
895
896module_init(hisax_isac_init);
897module_exit(hisax_isac_exit);
diff --git a/drivers/isdn/hisax/hisax_isac.h b/drivers/isdn/hisax/hisax_isac.h
new file mode 100644
index 000000000000..08890cf4d923
--- /dev/null
+++ b/drivers/isdn/hisax/hisax_isac.h
@@ -0,0 +1,45 @@
1#ifndef __HISAX_ISAC_H__
2#define __HISAX_ISAC_H__
3
4#include <linux/kernel.h>
5#include "fsm.h"
6#include "hisax_if.h"
7
8#define TIMER3_VALUE 7000
9#define MAX_DFRAME_LEN_L1 300
10
11#define ISAC_IOM1 0
12
13struct isac {
14 void *priv;
15
16 u_long flags;
17 struct hisax_d_if hisax_d_if;
18 struct FsmInst l1m;
19 struct FsmTimer timer;
20 u_char mocr;
21 u_char adf2;
22 int type;
23
24 u_char rcvbuf[MAX_DFRAME_LEN_L1];
25 int rcvidx;
26
27 struct sk_buff *tx_skb;
28 int tx_cnt;
29
30 u_char (*read_isac) (struct isac *, u_char);
31 void (*write_isac) (struct isac *, u_char, u_char);
32 void (*read_isac_fifo) (struct isac *, u_char *, int);
33 void (*write_isac_fifo)(struct isac *, u_char *, int);
34};
35
36void isac_init(struct isac *isac);
37void isac_d_l2l1(struct hisax_if *hisax_d_if, int pr, void *arg);
38
39void isac_setup(struct isac *isac);
40void isac_irq(struct isac *isac);
41
42void isacsx_setup(struct isac *isac);
43void isacsx_irq(struct isac *isac);
44
45#endif
diff --git a/drivers/isdn/hisax/hscx.c b/drivers/isdn/hisax/hscx.c
new file mode 100644
index 000000000000..5bbbe3e95125
--- /dev/null
+++ b/drivers/isdn/hisax/hscx.c
@@ -0,0 +1,280 @@
1/* $Id: hscx.c,v 1.24.2.4 2004/01/24 20:47:23 keil Exp $
2 *
3 * HSCX specific routines
4 *
5 * Author Karsten Keil
6 * Copyright by Karsten Keil <keil@isdn4linux.de>
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 */
12
13#include <linux/init.h>
14#include "hisax.h"
15#include "hscx.h"
16#include "isac.h"
17#include "isdnl1.h"
18#include <linux/interrupt.h>
19
20static char *HSCXVer[] =
21{"A1", "?1", "A2", "?3", "A3", "V2.1", "?6", "?7",
22 "?8", "?9", "?10", "?11", "?12", "?13", "?14", "???"};
23
24int
25HscxVersion(struct IsdnCardState *cs, char *s)
26{
27 int verA, verB;
28
29 verA = cs->BC_Read_Reg(cs, 0, HSCX_VSTR) & 0xf;
30 verB = cs->BC_Read_Reg(cs, 1, HSCX_VSTR) & 0xf;
31 printk(KERN_INFO "%s HSCX version A: %s B: %s\n", s,
32 HSCXVer[verA], HSCXVer[verB]);
33 if ((verA == 0) | (verA == 0xf) | (verB == 0) | (verB == 0xf))
34 return (1);
35 else
36 return (0);
37}
38
39void
40modehscx(struct BCState *bcs, int mode, int bc)
41{
42 struct IsdnCardState *cs = bcs->cs;
43 int hscx = bcs->hw.hscx.hscx;
44
45 if (cs->debug & L1_DEB_HSCX)
46 debugl1(cs, "hscx %c mode %d ichan %d",
47 'A' + hscx, mode, bc);
48 bcs->mode = mode;
49 bcs->channel = bc;
50 cs->BC_Write_Reg(cs, hscx, HSCX_XAD1, 0xFF);
51 cs->BC_Write_Reg(cs, hscx, HSCX_XAD2, 0xFF);
52 cs->BC_Write_Reg(cs, hscx, HSCX_RAH2, 0xFF);
53 cs->BC_Write_Reg(cs, hscx, HSCX_XBCH, 0x0);
54 cs->BC_Write_Reg(cs, hscx, HSCX_RLCR, 0x0);
55 cs->BC_Write_Reg(cs, hscx, HSCX_CCR1,
56 test_bit(HW_IPAC, &cs->HW_Flags) ? 0x82 : 0x85);
57 cs->BC_Write_Reg(cs, hscx, HSCX_CCR2, 0x30);
58 cs->BC_Write_Reg(cs, hscx, HSCX_XCCR, 7);
59 cs->BC_Write_Reg(cs, hscx, HSCX_RCCR, 7);
60
61 /* Switch IOM 1 SSI */
62 if (test_bit(HW_IOM1, &cs->HW_Flags) && (hscx == 0))
63 bc = 1 - bc;
64
65 if (bc == 0) {
66 cs->BC_Write_Reg(cs, hscx, HSCX_TSAX,
67 test_bit(HW_IOM1, &cs->HW_Flags) ? 0x7 : bcs->hw.hscx.tsaxr0);
68 cs->BC_Write_Reg(cs, hscx, HSCX_TSAR,
69 test_bit(HW_IOM1, &cs->HW_Flags) ? 0x7 : bcs->hw.hscx.tsaxr0);
70 } else {
71 cs->BC_Write_Reg(cs, hscx, HSCX_TSAX, bcs->hw.hscx.tsaxr1);
72 cs->BC_Write_Reg(cs, hscx, HSCX_TSAR, bcs->hw.hscx.tsaxr1);
73 }
74 switch (mode) {
75 case (L1_MODE_NULL):
76 cs->BC_Write_Reg(cs, hscx, HSCX_TSAX, 0x1f);
77 cs->BC_Write_Reg(cs, hscx, HSCX_TSAR, 0x1f);
78 cs->BC_Write_Reg(cs, hscx, HSCX_MODE, 0x84);
79 break;
80 case (L1_MODE_TRANS):
81 cs->BC_Write_Reg(cs, hscx, HSCX_MODE, 0xe4);
82 break;
83 case (L1_MODE_HDLC):
84 cs->BC_Write_Reg(cs, hscx, HSCX_CCR1,
85 test_bit(HW_IPAC, &cs->HW_Flags) ? 0x8a : 0x8d);
86 cs->BC_Write_Reg(cs, hscx, HSCX_MODE, 0x8c);
87 break;
88 }
89 if (mode)
90 cs->BC_Write_Reg(cs, hscx, HSCX_CMDR, 0x41);
91 cs->BC_Write_Reg(cs, hscx, HSCX_ISTA, 0x00);
92}
93
94void
95hscx_l2l1(struct PStack *st, int pr, void *arg)
96{
97 struct BCState *bcs = st->l1.bcs;
98 u_long flags;
99 struct sk_buff *skb = arg;
100
101 switch (pr) {
102 case (PH_DATA | REQUEST):
103 spin_lock_irqsave(&bcs->cs->lock, flags);
104 if (bcs->tx_skb) {
105 skb_queue_tail(&bcs->squeue, skb);
106 } else {
107 bcs->tx_skb = skb;
108 test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
109 bcs->hw.hscx.count = 0;
110 bcs->cs->BC_Send_Data(bcs);
111 }
112 spin_unlock_irqrestore(&bcs->cs->lock, flags);
113 break;
114 case (PH_PULL | INDICATION):
115 spin_lock_irqsave(&bcs->cs->lock, flags);
116 if (bcs->tx_skb) {
117 printk(KERN_WARNING "hscx_l2l1: this shouldn't happen\n");
118 } else {
119 test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
120 bcs->tx_skb = skb;
121 bcs->hw.hscx.count = 0;
122 bcs->cs->BC_Send_Data(bcs);
123 }
124 spin_unlock_irqrestore(&bcs->cs->lock, flags);
125 break;
126 case (PH_PULL | REQUEST):
127 if (!bcs->tx_skb) {
128 test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
129 st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
130 } else
131 test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
132 break;
133 case (PH_ACTIVATE | REQUEST):
134 spin_lock_irqsave(&bcs->cs->lock, flags);
135 test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag);
136 modehscx(bcs, st->l1.mode, st->l1.bc);
137 spin_unlock_irqrestore(&bcs->cs->lock, flags);
138 l1_msg_b(st, pr, arg);
139 break;
140 case (PH_DEACTIVATE | REQUEST):
141 l1_msg_b(st, pr, arg);
142 break;
143 case (PH_DEACTIVATE | CONFIRM):
144 spin_lock_irqsave(&bcs->cs->lock, flags);
145 test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag);
146 test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
147 modehscx(bcs, 0, st->l1.bc);
148 spin_unlock_irqrestore(&bcs->cs->lock, flags);
149 st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
150 break;
151 }
152}
153
154void
155close_hscxstate(struct BCState *bcs)
156{
157 modehscx(bcs, 0, bcs->channel);
158 if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) {
159 if (bcs->hw.hscx.rcvbuf) {
160 kfree(bcs->hw.hscx.rcvbuf);
161 bcs->hw.hscx.rcvbuf = NULL;
162 }
163 if (bcs->blog) {
164 kfree(bcs->blog);
165 bcs->blog = NULL;
166 }
167 skb_queue_purge(&bcs->rqueue);
168 skb_queue_purge(&bcs->squeue);
169 if (bcs->tx_skb) {
170 dev_kfree_skb_any(bcs->tx_skb);
171 bcs->tx_skb = NULL;
172 test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
173 }
174 }
175}
176
177int
178open_hscxstate(struct IsdnCardState *cs, struct BCState *bcs)
179{
180 if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
181 if (!(bcs->hw.hscx.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) {
182 printk(KERN_WARNING
183 "HiSax: No memory for hscx.rcvbuf\n");
184 test_and_clear_bit(BC_FLG_INIT, &bcs->Flag);
185 return (1);
186 }
187 if (!(bcs->blog = kmalloc(MAX_BLOG_SPACE, GFP_ATOMIC))) {
188 printk(KERN_WARNING
189 "HiSax: No memory for bcs->blog\n");
190 test_and_clear_bit(BC_FLG_INIT, &bcs->Flag);
191 kfree(bcs->hw.hscx.rcvbuf);
192 bcs->hw.hscx.rcvbuf = NULL;
193 return (2);
194 }
195 skb_queue_head_init(&bcs->rqueue);
196 skb_queue_head_init(&bcs->squeue);
197 }
198 bcs->tx_skb = NULL;
199 test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
200 bcs->event = 0;
201 bcs->hw.hscx.rcvidx = 0;
202 bcs->tx_cnt = 0;
203 return (0);
204}
205
206int
207setstack_hscx(struct PStack *st, struct BCState *bcs)
208{
209 bcs->channel = st->l1.bc;
210 if (open_hscxstate(st->l1.hardware, bcs))
211 return (-1);
212 st->l1.bcs = bcs;
213 st->l2.l2l1 = hscx_l2l1;
214 setstack_manager(st);
215 bcs->st = st;
216 setstack_l1_B(st);
217 return (0);
218}
219
220void
221clear_pending_hscx_ints(struct IsdnCardState *cs)
222{
223 int val, eval;
224
225 val = cs->BC_Read_Reg(cs, 1, HSCX_ISTA);
226 debugl1(cs, "HSCX B ISTA %x", val);
227 if (val & 0x01) {
228 eval = cs->BC_Read_Reg(cs, 1, HSCX_EXIR);
229 debugl1(cs, "HSCX B EXIR %x", eval);
230 }
231 if (val & 0x02) {
232 eval = cs->BC_Read_Reg(cs, 0, HSCX_EXIR);
233 debugl1(cs, "HSCX A EXIR %x", eval);
234 }
235 val = cs->BC_Read_Reg(cs, 0, HSCX_ISTA);
236 debugl1(cs, "HSCX A ISTA %x", val);
237 val = cs->BC_Read_Reg(cs, 1, HSCX_STAR);
238 debugl1(cs, "HSCX B STAR %x", val);
239 val = cs->BC_Read_Reg(cs, 0, HSCX_STAR);
240 debugl1(cs, "HSCX A STAR %x", val);
241 /* disable all IRQ */
242 cs->BC_Write_Reg(cs, 0, HSCX_MASK, 0xFF);
243 cs->BC_Write_Reg(cs, 1, HSCX_MASK, 0xFF);
244}
245
246void
247inithscx(struct IsdnCardState *cs)
248{
249 cs->bcs[0].BC_SetStack = setstack_hscx;
250 cs->bcs[1].BC_SetStack = setstack_hscx;
251 cs->bcs[0].BC_Close = close_hscxstate;
252 cs->bcs[1].BC_Close = close_hscxstate;
253 cs->bcs[0].hw.hscx.hscx = 0;
254 cs->bcs[1].hw.hscx.hscx = 1;
255 cs->bcs[0].hw.hscx.tsaxr0 = 0x2f;
256 cs->bcs[0].hw.hscx.tsaxr1 = 3;
257 cs->bcs[1].hw.hscx.tsaxr0 = 0x2f;
258 cs->bcs[1].hw.hscx.tsaxr1 = 3;
259 modehscx(cs->bcs, 0, 0);
260 modehscx(cs->bcs + 1, 0, 0);
261}
262
263void
264inithscxisac(struct IsdnCardState *cs, int part)
265{
266 if (part & 1) {
267 clear_pending_isac_ints(cs);
268 clear_pending_hscx_ints(cs);
269 initisac(cs);
270 inithscx(cs);
271 }
272 if (part & 2) {
273 /* Reenable all IRQ */
274 cs->writeisac(cs, ISAC_MASK, 0);
275 cs->BC_Write_Reg(cs, 0, HSCX_MASK, 0);
276 cs->BC_Write_Reg(cs, 1, HSCX_MASK, 0);
277 /* RESET Receiver and Transmitter */
278 cs->writeisac(cs, ISAC_CMDR, 0x41);
279 }
280}
diff --git a/drivers/isdn/hisax/hscx.h b/drivers/isdn/hisax/hscx.h
new file mode 100644
index 000000000000..268bfd3549b0
--- /dev/null
+++ b/drivers/isdn/hisax/hscx.h
@@ -0,0 +1,41 @@
1/* $Id: hscx.h,v 1.8.2.2 2004/01/12 22:52:26 keil Exp $
2 *
3 * HSCX specific defines
4 *
5 * Author Karsten Keil
6 * Copyright by Karsten Keil <keil@isdn4linux.de>
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 */
12
13/* All Registers original Siemens Spec */
14
15#define HSCX_ISTA 0x20
16#define HSCX_CCR1 0x2f
17#define HSCX_CCR2 0x2c
18#define HSCX_TSAR 0x31
19#define HSCX_TSAX 0x30
20#define HSCX_XCCR 0x32
21#define HSCX_RCCR 0x33
22#define HSCX_MODE 0x22
23#define HSCX_CMDR 0x21
24#define HSCX_EXIR 0x24
25#define HSCX_XAD1 0x24
26#define HSCX_XAD2 0x25
27#define HSCX_RAH2 0x27
28#define HSCX_RSTA 0x27
29#define HSCX_TIMR 0x23
30#define HSCX_STAR 0x21
31#define HSCX_RBCL 0x25
32#define HSCX_XBCH 0x2d
33#define HSCX_VSTR 0x2e
34#define HSCX_RLCR 0x2e
35#define HSCX_MASK 0x20
36
37extern int HscxVersion(struct IsdnCardState *cs, char *s);
38extern void modehscx(struct BCState *bcs, int mode, int bc);
39extern void clear_pending_hscx_ints(struct IsdnCardState *cs);
40extern void inithscx(struct IsdnCardState *cs);
41extern void inithscxisac(struct IsdnCardState *cs, int part);
diff --git a/drivers/isdn/hisax/hscx_irq.c b/drivers/isdn/hisax/hscx_irq.c
new file mode 100644
index 000000000000..5fe9d42d03a3
--- /dev/null
+++ b/drivers/isdn/hisax/hscx_irq.c
@@ -0,0 +1,292 @@
1/* $Id: hscx_irq.c,v 1.18.2.3 2004/02/11 13:21:34 keil Exp $
2 *
3 * low level b-channel stuff for Siemens HSCX
4 *
5 * Author Karsten Keil
6 * Copyright by Karsten Keil <keil@isdn4linux.de>
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 * This is an include file for fast inline IRQ stuff
12 *
13 */
14
15
16static inline void
17waitforCEC(struct IsdnCardState *cs, int hscx)
18{
19 int to = 50;
20
21 while ((READHSCX(cs, hscx, HSCX_STAR) & 0x04) && to) {
22 udelay(1);
23 to--;
24 }
25 if (!to)
26 printk(KERN_WARNING "HiSax: waitforCEC timeout\n");
27}
28
29
30static inline void
31waitforXFW(struct IsdnCardState *cs, int hscx)
32{
33 int to = 50;
34
35 while ((!(READHSCX(cs, hscx, HSCX_STAR) & 0x44) == 0x40) && to) {
36 udelay(1);
37 to--;
38 }
39 if (!to)
40 printk(KERN_WARNING "HiSax: waitforXFW timeout\n");
41}
42
43static inline void
44WriteHSCXCMDR(struct IsdnCardState *cs, int hscx, u_char data)
45{
46 waitforCEC(cs, hscx);
47 WRITEHSCX(cs, hscx, HSCX_CMDR, data);
48}
49
50
51
52static void
53hscx_empty_fifo(struct BCState *bcs, int count)
54{
55 u_char *ptr;
56 struct IsdnCardState *cs = bcs->cs;
57
58 if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
59 debugl1(cs, "hscx_empty_fifo");
60
61 if (bcs->hw.hscx.rcvidx + count > HSCX_BUFMAX) {
62 if (cs->debug & L1_DEB_WARN)
63 debugl1(cs, "hscx_empty_fifo: incoming packet too large");
64 WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x80);
65 bcs->hw.hscx.rcvidx = 0;
66 return;
67 }
68 ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx;
69 bcs->hw.hscx.rcvidx += count;
70 READHSCXFIFO(cs, bcs->hw.hscx.hscx, ptr, count);
71 WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x80);
72 if (cs->debug & L1_DEB_HSCX_FIFO) {
73 char *t = bcs->blog;
74
75 t += sprintf(t, "hscx_empty_fifo %c cnt %d",
76 bcs->hw.hscx.hscx ? 'B' : 'A', count);
77 QuickHex(t, ptr, count);
78 debugl1(cs, bcs->blog);
79 }
80}
81
82static void
83hscx_fill_fifo(struct BCState *bcs)
84{
85 struct IsdnCardState *cs = bcs->cs;
86 int more, count;
87 int fifo_size = test_bit(HW_IPAC, &cs->HW_Flags)? 64: 32;
88 u_char *ptr;
89
90 if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
91 debugl1(cs, "hscx_fill_fifo");
92
93 if (!bcs->tx_skb)
94 return;
95 if (bcs->tx_skb->len <= 0)
96 return;
97
98 more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0;
99 if (bcs->tx_skb->len > fifo_size) {
100 more = !0;
101 count = fifo_size;
102 } else
103 count = bcs->tx_skb->len;
104
105 waitforXFW(cs, bcs->hw.hscx.hscx);
106 ptr = bcs->tx_skb->data;
107 skb_pull(bcs->tx_skb, count);
108 bcs->tx_cnt -= count;
109 bcs->hw.hscx.count += count;
110 WRITEHSCXFIFO(cs, bcs->hw.hscx.hscx, ptr, count);
111 WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, more ? 0x8 : 0xa);
112 if (cs->debug & L1_DEB_HSCX_FIFO) {
113 char *t = bcs->blog;
114
115 t += sprintf(t, "hscx_fill_fifo %c cnt %d",
116 bcs->hw.hscx.hscx ? 'B' : 'A', count);
117 QuickHex(t, ptr, count);
118 debugl1(cs, bcs->blog);
119 }
120}
121
122static inline void
123hscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx)
124{
125 u_char r;
126 struct BCState *bcs = cs->bcs + hscx;
127 struct sk_buff *skb;
128 int fifo_size = test_bit(HW_IPAC, &cs->HW_Flags)? 64: 32;
129 int count;
130
131 if (!test_bit(BC_FLG_INIT, &bcs->Flag))
132 return;
133
134 if (val & 0x80) { /* RME */
135 r = READHSCX(cs, hscx, HSCX_RSTA);
136 if ((r & 0xf0) != 0xa0) {
137 if (!(r & 0x80)) {
138 if (cs->debug & L1_DEB_WARN)
139 debugl1(cs, "HSCX invalid frame");
140#ifdef ERROR_STATISTIC
141 bcs->err_inv++;
142#endif
143 }
144 if ((r & 0x40) && bcs->mode) {
145 if (cs->debug & L1_DEB_WARN)
146 debugl1(cs, "HSCX RDO mode=%d",
147 bcs->mode);
148#ifdef ERROR_STATISTIC
149 bcs->err_rdo++;
150#endif
151 }
152 if (!(r & 0x20)) {
153 if (cs->debug & L1_DEB_WARN)
154 debugl1(cs, "HSCX CRC error");
155#ifdef ERROR_STATISTIC
156 bcs->err_crc++;
157#endif
158 }
159 WriteHSCXCMDR(cs, hscx, 0x80);
160 } else {
161 count = READHSCX(cs, hscx, HSCX_RBCL) & (
162 test_bit(HW_IPAC, &cs->HW_Flags)? 0x3f: 0x1f);
163 if (count == 0)
164 count = fifo_size;
165 hscx_empty_fifo(bcs, count);
166 if ((count = bcs->hw.hscx.rcvidx - 1) > 0) {
167 if (cs->debug & L1_DEB_HSCX_FIFO)
168 debugl1(cs, "HX Frame %d", count);
169 if (!(skb = dev_alloc_skb(count)))
170 printk(KERN_WARNING "HSCX: receive out of memory\n");
171 else {
172 memcpy(skb_put(skb, count), bcs->hw.hscx.rcvbuf, count);
173 skb_queue_tail(&bcs->rqueue, skb);
174 }
175 }
176 }
177 bcs->hw.hscx.rcvidx = 0;
178 schedule_event(bcs, B_RCVBUFREADY);
179 }
180 if (val & 0x40) { /* RPF */
181 hscx_empty_fifo(bcs, fifo_size);
182 if (bcs->mode == L1_MODE_TRANS) {
183 /* receive audio data */
184 if (!(skb = dev_alloc_skb(fifo_size)))
185 printk(KERN_WARNING "HiSax: receive out of memory\n");
186 else {
187 memcpy(skb_put(skb, fifo_size), bcs->hw.hscx.rcvbuf, fifo_size);
188 skb_queue_tail(&bcs->rqueue, skb);
189 }
190 bcs->hw.hscx.rcvidx = 0;
191 schedule_event(bcs, B_RCVBUFREADY);
192 }
193 }
194 if (val & 0x10) { /* XPR */
195 if (bcs->tx_skb) {
196 if (bcs->tx_skb->len) {
197 hscx_fill_fifo(bcs);
198 return;
199 } else {
200 if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) &&
201 (PACKET_NOACK != bcs->tx_skb->pkt_type)) {
202 u_long flags;
203 spin_lock_irqsave(&bcs->aclock, flags);
204 bcs->ackcnt += bcs->hw.hscx.count;
205 spin_unlock_irqrestore(&bcs->aclock, flags);
206 schedule_event(bcs, B_ACKPENDING);
207 }
208 dev_kfree_skb_irq(bcs->tx_skb);
209 bcs->hw.hscx.count = 0;
210 bcs->tx_skb = NULL;
211 }
212 }
213 if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
214 bcs->hw.hscx.count = 0;
215 test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
216 hscx_fill_fifo(bcs);
217 } else {
218 test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
219 schedule_event(bcs, B_XMTBUFREADY);
220 }
221 }
222}
223
224static inline void
225hscx_int_main(struct IsdnCardState *cs, u_char val)
226{
227
228 u_char exval;
229 struct BCState *bcs;
230
231 if (val & 0x01) {
232 bcs = cs->bcs + 1;
233 exval = READHSCX(cs, 1, HSCX_EXIR);
234 if (exval & 0x40) {
235 if (bcs->mode == 1)
236 hscx_fill_fifo(bcs);
237 else {
238#ifdef ERROR_STATISTIC
239 bcs->err_tx++;
240#endif
241 /* Here we lost an TX interrupt, so
242 * restart transmitting the whole frame.
243 */
244 if (bcs->tx_skb) {
245 skb_push(bcs->tx_skb, bcs->hw.hscx.count);
246 bcs->tx_cnt += bcs->hw.hscx.count;
247 bcs->hw.hscx.count = 0;
248 }
249 WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x01);
250 if (cs->debug & L1_DEB_WARN)
251 debugl1(cs, "HSCX B EXIR %x Lost TX", exval);
252 }
253 } else if (cs->debug & L1_DEB_HSCX)
254 debugl1(cs, "HSCX B EXIR %x", exval);
255 }
256 if (val & 0xf8) {
257 if (cs->debug & L1_DEB_HSCX)
258 debugl1(cs, "HSCX B interrupt %x", val);
259 hscx_interrupt(cs, val, 1);
260 }
261 if (val & 0x02) {
262 bcs = cs->bcs;
263 exval = READHSCX(cs, 0, HSCX_EXIR);
264 if (exval & 0x40) {
265 if (bcs->mode == L1_MODE_TRANS)
266 hscx_fill_fifo(bcs);
267 else {
268 /* Here we lost an TX interrupt, so
269 * restart transmitting the whole frame.
270 */
271#ifdef ERROR_STATISTIC
272 bcs->err_tx++;
273#endif
274 if (bcs->tx_skb) {
275 skb_push(bcs->tx_skb, bcs->hw.hscx.count);
276 bcs->tx_cnt += bcs->hw.hscx.count;
277 bcs->hw.hscx.count = 0;
278 }
279 WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x01);
280 if (cs->debug & L1_DEB_WARN)
281 debugl1(cs, "HSCX A EXIR %x Lost TX", exval);
282 }
283 } else if (cs->debug & L1_DEB_HSCX)
284 debugl1(cs, "HSCX A EXIR %x", exval);
285 }
286 if (val & 0x04) {
287 exval = READHSCX(cs, 0, HSCX_ISTA);
288 if (cs->debug & L1_DEB_HSCX)
289 debugl1(cs, "HSCX A interrupt %x", exval);
290 hscx_interrupt(cs, exval, 0);
291 }
292}
diff --git a/drivers/isdn/hisax/icc.c b/drivers/isdn/hisax/icc.c
new file mode 100644
index 000000000000..dcf31f83c600
--- /dev/null
+++ b/drivers/isdn/hisax/icc.c
@@ -0,0 +1,685 @@
1/* $Id: icc.c,v 1.8.2.3 2004/01/13 14:31:25 keil Exp $
2 *
3 * ICC specific routines
4 *
5 * Author Matt Henderson & Guy Ellis
6 * Copyright by Traverse Technologies Pty Ltd, www.travers.com.au
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 * 1999.6.25 Initial implementation of routines for Siemens ISDN
12 * Communication Controller PEB 2070 based on the ISAC routines
13 * written by Karsten Keil.
14 *
15 */
16
17#include <linux/init.h>
18#include "hisax.h"
19#include "icc.h"
20// #include "arcofi.h"
21#include "isdnl1.h"
22#include <linux/interrupt.h>
23
24#define DBUSY_TIMER_VALUE 80
25#define ARCOFI_USE 0
26
27static char *ICCVer[] __initdata =
28{"2070 A1/A3", "2070 B1", "2070 B2/B3", "2070 V2.4"};
29
30void __init
31ICCVersion(struct IsdnCardState *cs, char *s)
32{
33 int val;
34
35 val = cs->readisac(cs, ICC_RBCH);
36 printk(KERN_INFO "%s ICC version (%x): %s\n", s, val, ICCVer[(val >> 5) & 3]);
37}
38
39static void
40ph_command(struct IsdnCardState *cs, unsigned int command)
41{
42 if (cs->debug & L1_DEB_ISAC)
43 debugl1(cs, "ph_command %x", command);
44 cs->writeisac(cs, ICC_CIX0, (command << 2) | 3);
45}
46
47
48static void
49icc_new_ph(struct IsdnCardState *cs)
50{
51 switch (cs->dc.icc.ph_state) {
52 case (ICC_IND_EI1):
53 ph_command(cs, ICC_CMD_DI);
54 l1_msg(cs, HW_RESET | INDICATION, NULL);
55 break;
56 case (ICC_IND_DC):
57 l1_msg(cs, HW_DEACTIVATE | CONFIRM, NULL);
58 break;
59 case (ICC_IND_DR):
60 l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL);
61 break;
62 case (ICC_IND_PU):
63 l1_msg(cs, HW_POWERUP | CONFIRM, NULL);
64 break;
65 case (ICC_IND_FJ):
66 l1_msg(cs, HW_RSYNC | INDICATION, NULL);
67 break;
68 case (ICC_IND_AR):
69 l1_msg(cs, HW_INFO2 | INDICATION, NULL);
70 break;
71 case (ICC_IND_AI):
72 l1_msg(cs, HW_INFO4 | INDICATION, NULL);
73 break;
74 default:
75 break;
76 }
77}
78
79static void
80icc_bh(struct IsdnCardState *cs)
81{
82 struct PStack *stptr;
83
84 if (!cs)
85 return;
86 if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) {
87 if (cs->debug)
88 debugl1(cs, "D-Channel Busy cleared");
89 stptr = cs->stlist;
90 while (stptr != NULL) {
91 stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL);
92 stptr = stptr->next;
93 }
94 }
95 if (test_and_clear_bit(D_L1STATECHANGE, &cs->event))
96 icc_new_ph(cs);
97 if (test_and_clear_bit(D_RCVBUFREADY, &cs->event))
98 DChannel_proc_rcv(cs);
99 if (test_and_clear_bit(D_XMTBUFREADY, &cs->event))
100 DChannel_proc_xmt(cs);
101#if ARCOFI_USE
102 if (!test_bit(HW_ARCOFI, &cs->HW_Flags))
103 return;
104 if (test_and_clear_bit(D_RX_MON1, &cs->event))
105 arcofi_fsm(cs, ARCOFI_RX_END, NULL);
106 if (test_and_clear_bit(D_TX_MON1, &cs->event))
107 arcofi_fsm(cs, ARCOFI_TX_END, NULL);
108#endif
109}
110
111void
112icc_empty_fifo(struct IsdnCardState *cs, int count)
113{
114 u_char *ptr;
115
116 if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
117 debugl1(cs, "icc_empty_fifo");
118
119 if ((cs->rcvidx + count) >= MAX_DFRAME_LEN_L1) {
120 if (cs->debug & L1_DEB_WARN)
121 debugl1(cs, "icc_empty_fifo overrun %d",
122 cs->rcvidx + count);
123 cs->writeisac(cs, ICC_CMDR, 0x80);
124 cs->rcvidx = 0;
125 return;
126 }
127 ptr = cs->rcvbuf + cs->rcvidx;
128 cs->rcvidx += count;
129 cs->readisacfifo(cs, ptr, count);
130 cs->writeisac(cs, ICC_CMDR, 0x80);
131 if (cs->debug & L1_DEB_ISAC_FIFO) {
132 char *t = cs->dlog;
133
134 t += sprintf(t, "icc_empty_fifo cnt %d", count);
135 QuickHex(t, ptr, count);
136 debugl1(cs, cs->dlog);
137 }
138}
139
140static void
141icc_fill_fifo(struct IsdnCardState *cs)
142{
143 int count, more;
144 u_char *ptr;
145
146 if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
147 debugl1(cs, "icc_fill_fifo");
148
149 if (!cs->tx_skb)
150 return;
151
152 count = cs->tx_skb->len;
153 if (count <= 0)
154 return;
155
156 more = 0;
157 if (count > 32) {
158 more = !0;
159 count = 32;
160 }
161 ptr = cs->tx_skb->data;
162 skb_pull(cs->tx_skb, count);
163 cs->tx_cnt += count;
164 cs->writeisacfifo(cs, ptr, count);
165 cs->writeisac(cs, ICC_CMDR, more ? 0x8 : 0xa);
166 if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
167 debugl1(cs, "icc_fill_fifo dbusytimer running");
168 del_timer(&cs->dbusytimer);
169 }
170 init_timer(&cs->dbusytimer);
171 cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000);
172 add_timer(&cs->dbusytimer);
173 if (cs->debug & L1_DEB_ISAC_FIFO) {
174 char *t = cs->dlog;
175
176 t += sprintf(t, "icc_fill_fifo cnt %d", count);
177 QuickHex(t, ptr, count);
178 debugl1(cs, cs->dlog);
179 }
180}
181
182void
183icc_interrupt(struct IsdnCardState *cs, u_char val)
184{
185 u_char exval, v1;
186 struct sk_buff *skb;
187 unsigned int count;
188
189 if (cs->debug & L1_DEB_ISAC)
190 debugl1(cs, "ICC interrupt %x", val);
191 if (val & 0x80) { /* RME */
192 exval = cs->readisac(cs, ICC_RSTA);
193 if ((exval & 0x70) != 0x20) {
194 if (exval & 0x40) {
195 if (cs->debug & L1_DEB_WARN)
196 debugl1(cs, "ICC RDO");
197#ifdef ERROR_STATISTIC
198 cs->err_rx++;
199#endif
200 }
201 if (!(exval & 0x20)) {
202 if (cs->debug & L1_DEB_WARN)
203 debugl1(cs, "ICC CRC error");
204#ifdef ERROR_STATISTIC
205 cs->err_crc++;
206#endif
207 }
208 cs->writeisac(cs, ICC_CMDR, 0x80);
209 } else {
210 count = cs->readisac(cs, ICC_RBCL) & 0x1f;
211 if (count == 0)
212 count = 32;
213 icc_empty_fifo(cs, count);
214 if ((count = cs->rcvidx) > 0) {
215 cs->rcvidx = 0;
216 if (!(skb = alloc_skb(count, GFP_ATOMIC)))
217 printk(KERN_WARNING "HiSax: D receive out of memory\n");
218 else {
219 memcpy(skb_put(skb, count), cs->rcvbuf, count);
220 skb_queue_tail(&cs->rq, skb);
221 }
222 }
223 }
224 cs->rcvidx = 0;
225 schedule_event(cs, D_RCVBUFREADY);
226 }
227 if (val & 0x40) { /* RPF */
228 icc_empty_fifo(cs, 32);
229 }
230 if (val & 0x20) { /* RSC */
231 /* never */
232 if (cs->debug & L1_DEB_WARN)
233 debugl1(cs, "ICC RSC interrupt");
234 }
235 if (val & 0x10) { /* XPR */
236 if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
237 del_timer(&cs->dbusytimer);
238 if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
239 schedule_event(cs, D_CLEARBUSY);
240 if (cs->tx_skb) {
241 if (cs->tx_skb->len) {
242 icc_fill_fifo(cs);
243 goto afterXPR;
244 } else {
245 dev_kfree_skb_irq(cs->tx_skb);
246 cs->tx_cnt = 0;
247 cs->tx_skb = NULL;
248 }
249 }
250 if ((cs->tx_skb = skb_dequeue(&cs->sq))) {
251 cs->tx_cnt = 0;
252 icc_fill_fifo(cs);
253 } else
254 schedule_event(cs, D_XMTBUFREADY);
255 }
256 afterXPR:
257 if (val & 0x04) { /* CISQ */
258 exval = cs->readisac(cs, ICC_CIR0);
259 if (cs->debug & L1_DEB_ISAC)
260 debugl1(cs, "ICC CIR0 %02X", exval );
261 if (exval & 2) {
262 cs->dc.icc.ph_state = (exval >> 2) & 0xf;
263 if (cs->debug & L1_DEB_ISAC)
264 debugl1(cs, "ph_state change %x", cs->dc.icc.ph_state);
265 schedule_event(cs, D_L1STATECHANGE);
266 }
267 if (exval & 1) {
268 exval = cs->readisac(cs, ICC_CIR1);
269 if (cs->debug & L1_DEB_ISAC)
270 debugl1(cs, "ICC CIR1 %02X", exval );
271 }
272 }
273 if (val & 0x02) { /* SIN */
274 /* never */
275 if (cs->debug & L1_DEB_WARN)
276 debugl1(cs, "ICC SIN interrupt");
277 }
278 if (val & 0x01) { /* EXI */
279 exval = cs->readisac(cs, ICC_EXIR);
280 if (cs->debug & L1_DEB_WARN)
281 debugl1(cs, "ICC EXIR %02x", exval);
282 if (exval & 0x80) { /* XMR */
283 debugl1(cs, "ICC XMR");
284 printk(KERN_WARNING "HiSax: ICC XMR\n");
285 }
286 if (exval & 0x40) { /* XDU */
287 debugl1(cs, "ICC XDU");
288 printk(KERN_WARNING "HiSax: ICC XDU\n");
289#ifdef ERROR_STATISTIC
290 cs->err_tx++;
291#endif
292 if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
293 del_timer(&cs->dbusytimer);
294 if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
295 schedule_event(cs, D_CLEARBUSY);
296 if (cs->tx_skb) { /* Restart frame */
297 skb_push(cs->tx_skb, cs->tx_cnt);
298 cs->tx_cnt = 0;
299 icc_fill_fifo(cs);
300 } else {
301 printk(KERN_WARNING "HiSax: ICC XDU no skb\n");
302 debugl1(cs, "ICC XDU no skb");
303 }
304 }
305 if (exval & 0x04) { /* MOS */
306 v1 = cs->readisac(cs, ICC_MOSR);
307 if (cs->debug & L1_DEB_MONITOR)
308 debugl1(cs, "ICC MOSR %02x", v1);
309#if ARCOFI_USE
310 if (v1 & 0x08) {
311 if (!cs->dc.icc.mon_rx) {
312 if (!(cs->dc.icc.mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) {
313 if (cs->debug & L1_DEB_WARN)
314 debugl1(cs, "ICC MON RX out of memory!");
315 cs->dc.icc.mocr &= 0xf0;
316 cs->dc.icc.mocr |= 0x0a;
317 cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
318 goto afterMONR0;
319 } else
320 cs->dc.icc.mon_rxp = 0;
321 }
322 if (cs->dc.icc.mon_rxp >= MAX_MON_FRAME) {
323 cs->dc.icc.mocr &= 0xf0;
324 cs->dc.icc.mocr |= 0x0a;
325 cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
326 cs->dc.icc.mon_rxp = 0;
327 if (cs->debug & L1_DEB_WARN)
328 debugl1(cs, "ICC MON RX overflow!");
329 goto afterMONR0;
330 }
331 cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp++] = cs->readisac(cs, ICC_MOR0);
332 if (cs->debug & L1_DEB_MONITOR)
333 debugl1(cs, "ICC MOR0 %02x", cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp -1]);
334 if (cs->dc.icc.mon_rxp == 1) {
335 cs->dc.icc.mocr |= 0x04;
336 cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
337 }
338 }
339 afterMONR0:
340 if (v1 & 0x80) {
341 if (!cs->dc.icc.mon_rx) {
342 if (!(cs->dc.icc.mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) {
343 if (cs->debug & L1_DEB_WARN)
344 debugl1(cs, "ICC MON RX out of memory!");
345 cs->dc.icc.mocr &= 0x0f;
346 cs->dc.icc.mocr |= 0xa0;
347 cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
348 goto afterMONR1;
349 } else
350 cs->dc.icc.mon_rxp = 0;
351 }
352 if (cs->dc.icc.mon_rxp >= MAX_MON_FRAME) {
353 cs->dc.icc.mocr &= 0x0f;
354 cs->dc.icc.mocr |= 0xa0;
355 cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
356 cs->dc.icc.mon_rxp = 0;
357 if (cs->debug & L1_DEB_WARN)
358 debugl1(cs, "ICC MON RX overflow!");
359 goto afterMONR1;
360 }
361 cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp++] = cs->readisac(cs, ICC_MOR1);
362 if (cs->debug & L1_DEB_MONITOR)
363 debugl1(cs, "ICC MOR1 %02x", cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp -1]);
364 cs->dc.icc.mocr |= 0x40;
365 cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
366 }
367 afterMONR1:
368 if (v1 & 0x04) {
369 cs->dc.icc.mocr &= 0xf0;
370 cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
371 cs->dc.icc.mocr |= 0x0a;
372 cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
373 schedule_event(cs, D_RX_MON0);
374 }
375 if (v1 & 0x40) {
376 cs->dc.icc.mocr &= 0x0f;
377 cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
378 cs->dc.icc.mocr |= 0xa0;
379 cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
380 schedule_event(cs, D_RX_MON1);
381 }
382 if (v1 & 0x02) {
383 if ((!cs->dc.icc.mon_tx) || (cs->dc.icc.mon_txc &&
384 (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc) &&
385 !(v1 & 0x08))) {
386 cs->dc.icc.mocr &= 0xf0;
387 cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
388 cs->dc.icc.mocr |= 0x0a;
389 cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
390 if (cs->dc.icc.mon_txc &&
391 (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc))
392 schedule_event(cs, D_TX_MON0);
393 goto AfterMOX0;
394 }
395 if (cs->dc.icc.mon_txc && (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc)) {
396 schedule_event(cs, D_TX_MON0);
397 goto AfterMOX0;
398 }
399 cs->writeisac(cs, ICC_MOX0,
400 cs->dc.icc.mon_tx[cs->dc.icc.mon_txp++]);
401 if (cs->debug & L1_DEB_MONITOR)
402 debugl1(cs, "ICC %02x -> MOX0", cs->dc.icc.mon_tx[cs->dc.icc.mon_txp -1]);
403 }
404 AfterMOX0:
405 if (v1 & 0x20) {
406 if ((!cs->dc.icc.mon_tx) || (cs->dc.icc.mon_txc &&
407 (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc) &&
408 !(v1 & 0x80))) {
409 cs->dc.icc.mocr &= 0x0f;
410 cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
411 cs->dc.icc.mocr |= 0xa0;
412 cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
413 if (cs->dc.icc.mon_txc &&
414 (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc))
415 schedule_event(cs, D_TX_MON1);
416 goto AfterMOX1;
417 }
418 if (cs->dc.icc.mon_txc && (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc)) {
419 schedule_event(cs, D_TX_MON1);
420 goto AfterMOX1;
421 }
422 cs->writeisac(cs, ICC_MOX1,
423 cs->dc.icc.mon_tx[cs->dc.icc.mon_txp++]);
424 if (cs->debug & L1_DEB_MONITOR)
425 debugl1(cs, "ICC %02x -> MOX1", cs->dc.icc.mon_tx[cs->dc.icc.mon_txp -1]);
426 }
427 AfterMOX1:
428#endif
429 }
430 }
431}
432
433static void
434ICC_l1hw(struct PStack *st, int pr, void *arg)
435{
436 struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
437 struct sk_buff *skb = arg;
438 u_long flags;
439 int val;
440
441 switch (pr) {
442 case (PH_DATA |REQUEST):
443 if (cs->debug & DEB_DLOG_HEX)
444 LogFrame(cs, skb->data, skb->len);
445 if (cs->debug & DEB_DLOG_VERBOSE)
446 dlogframe(cs, skb, 0);
447 spin_lock_irqsave(&cs->lock, flags);
448 if (cs->tx_skb) {
449 skb_queue_tail(&cs->sq, skb);
450#ifdef L2FRAME_DEBUG /* psa */
451 if (cs->debug & L1_DEB_LAPD)
452 Logl2Frame(cs, skb, "PH_DATA Queued", 0);
453#endif
454 } else {
455 cs->tx_skb = skb;
456 cs->tx_cnt = 0;
457#ifdef L2FRAME_DEBUG /* psa */
458 if (cs->debug & L1_DEB_LAPD)
459 Logl2Frame(cs, skb, "PH_DATA", 0);
460#endif
461 icc_fill_fifo(cs);
462 }
463 spin_unlock_irqrestore(&cs->lock, flags);
464 break;
465 case (PH_PULL |INDICATION):
466 spin_lock_irqsave(&cs->lock, flags);
467 if (cs->tx_skb) {
468 if (cs->debug & L1_DEB_WARN)
469 debugl1(cs, " l2l1 tx_skb exist this shouldn't happen");
470 skb_queue_tail(&cs->sq, skb);
471 break;
472 }
473 if (cs->debug & DEB_DLOG_HEX)
474 LogFrame(cs, skb->data, skb->len);
475 if (cs->debug & DEB_DLOG_VERBOSE)
476 dlogframe(cs, skb, 0);
477 cs->tx_skb = skb;
478 cs->tx_cnt = 0;
479#ifdef L2FRAME_DEBUG /* psa */
480 if (cs->debug & L1_DEB_LAPD)
481 Logl2Frame(cs, skb, "PH_DATA_PULLED", 0);
482#endif
483 icc_fill_fifo(cs);
484 spin_unlock_irqrestore(&cs->lock, flags);
485 break;
486 case (PH_PULL | REQUEST):
487#ifdef L2FRAME_DEBUG /* psa */
488 if (cs->debug & L1_DEB_LAPD)
489 debugl1(cs, "-> PH_REQUEST_PULL");
490#endif
491 if (!cs->tx_skb) {
492 test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
493 st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
494 } else
495 test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
496 break;
497 case (HW_RESET | REQUEST):
498 spin_lock_irqsave(&cs->lock, flags);
499 if ((cs->dc.icc.ph_state == ICC_IND_EI1) ||
500 (cs->dc.icc.ph_state == ICC_IND_DR))
501 ph_command(cs, ICC_CMD_DI);
502 else
503 ph_command(cs, ICC_CMD_RES);
504 spin_unlock_irqrestore(&cs->lock, flags);
505 break;
506 case (HW_ENABLE | REQUEST):
507 spin_lock_irqsave(&cs->lock, flags);
508 ph_command(cs, ICC_CMD_DI);
509 spin_unlock_irqrestore(&cs->lock, flags);
510 break;
511 case (HW_INFO1 | REQUEST):
512 spin_lock_irqsave(&cs->lock, flags);
513 ph_command(cs, ICC_CMD_AR);
514 spin_unlock_irqrestore(&cs->lock, flags);
515 break;
516 case (HW_INFO3 | REQUEST):
517 spin_lock_irqsave(&cs->lock, flags);
518 ph_command(cs, ICC_CMD_AI);
519 spin_unlock_irqrestore(&cs->lock, flags);
520 break;
521 case (HW_TESTLOOP | REQUEST):
522 spin_lock_irqsave(&cs->lock, flags);
523 val = 0;
524 if (1 & (long) arg)
525 val |= 0x0c;
526 if (2 & (long) arg)
527 val |= 0x3;
528 if (test_bit(HW_IOM1, &cs->HW_Flags)) {
529 /* IOM 1 Mode */
530 if (!val) {
531 cs->writeisac(cs, ICC_SPCR, 0xa);
532 cs->writeisac(cs, ICC_ADF1, 0x2);
533 } else {
534 cs->writeisac(cs, ICC_SPCR, val);
535 cs->writeisac(cs, ICC_ADF1, 0xa);
536 }
537 } else {
538 /* IOM 2 Mode */
539 cs->writeisac(cs, ICC_SPCR, val);
540 if (val)
541 cs->writeisac(cs, ICC_ADF1, 0x8);
542 else
543 cs->writeisac(cs, ICC_ADF1, 0x0);
544 }
545 spin_unlock_irqrestore(&cs->lock, flags);
546 break;
547 case (HW_DEACTIVATE | RESPONSE):
548 skb_queue_purge(&cs->rq);
549 skb_queue_purge(&cs->sq);
550 if (cs->tx_skb) {
551 dev_kfree_skb_any(cs->tx_skb);
552 cs->tx_skb = NULL;
553 }
554 if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
555 del_timer(&cs->dbusytimer);
556 if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
557 schedule_event(cs, D_CLEARBUSY);
558 break;
559 default:
560 if (cs->debug & L1_DEB_WARN)
561 debugl1(cs, "icc_l1hw unknown %04x", pr);
562 break;
563 }
564}
565
566void
567setstack_icc(struct PStack *st, struct IsdnCardState *cs)
568{
569 st->l1.l1hw = ICC_l1hw;
570}
571
572void
573DC_Close_icc(struct IsdnCardState *cs) {
574 if (cs->dc.icc.mon_rx) {
575 kfree(cs->dc.icc.mon_rx);
576 cs->dc.icc.mon_rx = NULL;
577 }
578 if (cs->dc.icc.mon_tx) {
579 kfree(cs->dc.icc.mon_tx);
580 cs->dc.icc.mon_tx = NULL;
581 }
582}
583
584static void
585dbusy_timer_handler(struct IsdnCardState *cs)
586{
587 struct PStack *stptr;
588 int rbch, star;
589
590 if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
591 rbch = cs->readisac(cs, ICC_RBCH);
592 star = cs->readisac(cs, ICC_STAR);
593 if (cs->debug)
594 debugl1(cs, "D-Channel Busy RBCH %02x STAR %02x",
595 rbch, star);
596 if (rbch & ICC_RBCH_XAC) { /* D-Channel Busy */
597 test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags);
598 stptr = cs->stlist;
599 while (stptr != NULL) {
600 stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL);
601 stptr = stptr->next;
602 }
603 } else {
604 /* discard frame; reset transceiver */
605 test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags);
606 if (cs->tx_skb) {
607 dev_kfree_skb_any(cs->tx_skb);
608 cs->tx_cnt = 0;
609 cs->tx_skb = NULL;
610 } else {
611 printk(KERN_WARNING "HiSax: ICC D-Channel Busy no skb\n");
612 debugl1(cs, "D-Channel Busy no skb");
613 }
614 cs->writeisac(cs, ICC_CMDR, 0x01); /* Transmitter reset */
615 cs->irq_func(cs->irq, cs, NULL);
616 }
617 }
618}
619
620void __init
621initicc(struct IsdnCardState *cs)
622{
623 cs->setstack_d = setstack_icc;
624 cs->DC_Close = DC_Close_icc;
625 cs->dc.icc.mon_tx = NULL;
626 cs->dc.icc.mon_rx = NULL;
627 cs->writeisac(cs, ICC_MASK, 0xff);
628 cs->dc.icc.mocr = 0xaa;
629 if (test_bit(HW_IOM1, &cs->HW_Flags)) {
630 /* IOM 1 Mode */
631 cs->writeisac(cs, ICC_ADF2, 0x0);
632 cs->writeisac(cs, ICC_SPCR, 0xa);
633 cs->writeisac(cs, ICC_ADF1, 0x2);
634 cs->writeisac(cs, ICC_STCR, 0x70);
635 cs->writeisac(cs, ICC_MODE, 0xc9);
636 } else {
637 /* IOM 2 Mode */
638 if (!cs->dc.icc.adf2)
639 cs->dc.icc.adf2 = 0x80;
640 cs->writeisac(cs, ICC_ADF2, cs->dc.icc.adf2);
641 cs->writeisac(cs, ICC_SQXR, 0xa0);
642 cs->writeisac(cs, ICC_SPCR, 0x20);
643 cs->writeisac(cs, ICC_STCR, 0x70);
644 cs->writeisac(cs, ICC_MODE, 0xca);
645 cs->writeisac(cs, ICC_TIMR, 0x00);
646 cs->writeisac(cs, ICC_ADF1, 0x20);
647 }
648 ph_command(cs, ICC_CMD_RES);
649 cs->writeisac(cs, ICC_MASK, 0x0);
650 ph_command(cs, ICC_CMD_DI);
651}
652
653void __init
654clear_pending_icc_ints(struct IsdnCardState *cs)
655{
656 int val, eval;
657
658 val = cs->readisac(cs, ICC_STAR);
659 debugl1(cs, "ICC STAR %x", val);
660 val = cs->readisac(cs, ICC_MODE);
661 debugl1(cs, "ICC MODE %x", val);
662 val = cs->readisac(cs, ICC_ADF2);
663 debugl1(cs, "ICC ADF2 %x", val);
664 val = cs->readisac(cs, ICC_ISTA);
665 debugl1(cs, "ICC ISTA %x", val);
666 if (val & 0x01) {
667 eval = cs->readisac(cs, ICC_EXIR);
668 debugl1(cs, "ICC EXIR %x", eval);
669 }
670 val = cs->readisac(cs, ICC_CIR0);
671 debugl1(cs, "ICC CIR0 %x", val);
672 cs->dc.icc.ph_state = (val >> 2) & 0xf;
673 schedule_event(cs, D_L1STATECHANGE);
674 /* Disable all IRQ */
675 cs->writeisac(cs, ICC_MASK, 0xFF);
676}
677
678void __devinit
679setup_icc(struct IsdnCardState *cs)
680{
681 INIT_WORK(&cs->tqueue, (void *)(void *) icc_bh, cs);
682 cs->dbusytimer.function = (void *) dbusy_timer_handler;
683 cs->dbusytimer.data = (long) cs;
684 init_timer(&cs->dbusytimer);
685}
diff --git a/drivers/isdn/hisax/icc.h b/drivers/isdn/hisax/icc.h
new file mode 100644
index 000000000000..b3bb3d5de532
--- /dev/null
+++ b/drivers/isdn/hisax/icc.h
@@ -0,0 +1,72 @@
1/* $Id: icc.h,v 1.4.2.2 2004/01/12 22:52:26 keil Exp $
2 *
3 * ICC specific routines
4 *
5 * Author Matt Henderson & Guy Ellis
6 * Copyright by Traverse Technologies Pty Ltd, www.travers.com.au
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 * 1999.7.14 Initial implementation of routines for Siemens ISDN
12 * Communication Controller PEB 2070 based on the ISAC routines
13 * written by Karsten Keil.
14 */
15
16/* All Registers original Siemens Spec */
17
18#define ICC_MASK 0x20
19#define ICC_ISTA 0x20
20#define ICC_STAR 0x21
21#define ICC_CMDR 0x21
22#define ICC_EXIR 0x24
23#define ICC_ADF2 0x39
24#define ICC_SPCR 0x30
25#define ICC_ADF1 0x38
26#define ICC_CIR0 0x31
27#define ICC_CIX0 0x31
28#define ICC_CIR1 0x33
29#define ICC_CIX1 0x33
30#define ICC_STCR 0x37
31#define ICC_MODE 0x22
32#define ICC_RSTA 0x27
33#define ICC_RBCL 0x25
34#define ICC_RBCH 0x2A
35#define ICC_TIMR 0x23
36#define ICC_SQXR 0x3b
37#define ICC_MOSR 0x3a
38#define ICC_MOCR 0x3a
39#define ICC_MOR0 0x32
40#define ICC_MOX0 0x32
41#define ICC_MOR1 0x34
42#define ICC_MOX1 0x34
43
44#define ICC_RBCH_XAC 0x80
45
46#define ICC_CMD_TIM 0x0
47#define ICC_CMD_RES 0x1
48#define ICC_CMD_DU 0x3
49#define ICC_CMD_EI1 0x4
50#define ICC_CMD_SSP 0x5
51#define ICC_CMD_DT 0x6
52#define ICC_CMD_AR 0x8
53#define ICC_CMD_ARL 0xA
54#define ICC_CMD_AI 0xC
55#define ICC_CMD_DI 0xF
56
57#define ICC_IND_DR 0x0
58#define ICC_IND_FJ 0x2
59#define ICC_IND_EI1 0x4
60#define ICC_IND_INT 0x6
61#define ICC_IND_PU 0x7
62#define ICC_IND_AR 0x8
63#define ICC_IND_ARL 0xA
64#define ICC_IND_AI 0xC
65#define ICC_IND_AIL 0xE
66#define ICC_IND_DC 0xF
67
68extern void __init ICCVersion(struct IsdnCardState *cs, char *s);
69extern void initicc(struct IsdnCardState *cs);
70extern void icc_interrupt(struct IsdnCardState *cs, u_char val);
71extern void clear_pending_icc_ints(struct IsdnCardState *cs);
72extern void setup_icc(struct IsdnCardState *);
diff --git a/drivers/isdn/hisax/ipac.h b/drivers/isdn/hisax/ipac.h
new file mode 100644
index 000000000000..f92a04a92826
--- /dev/null
+++ b/drivers/isdn/hisax/ipac.h
@@ -0,0 +1,29 @@
1/* $Id: ipac.h,v 1.7.2.2 2004/01/12 22:52:26 keil Exp $
2 *
3 * IPAC specific defines
4 *
5 * Author Karsten Keil
6 * Copyright by Karsten Keil <keil@isdn4linux.de>
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 */
12
13/* All Registers original Siemens Spec */
14
15#define IPAC_CONF 0xC0
16#define IPAC_MASK 0xC1
17#define IPAC_ISTA 0xC1
18#define IPAC_ID 0xC2
19#define IPAC_ACFG 0xC3
20#define IPAC_AOE 0xC4
21#define IPAC_ARX 0xC5
22#define IPAC_ATX 0xC5
23#define IPAC_PITA1 0xC6
24#define IPAC_PITA2 0xC7
25#define IPAC_POTA1 0xC8
26#define IPAC_POTA2 0xC9
27#define IPAC_PCFG 0xCA
28#define IPAC_SCFG 0xCB
29#define IPAC_TIMR2 0xCC
diff --git a/drivers/isdn/hisax/ipacx.c b/drivers/isdn/hisax/ipacx.c
new file mode 100644
index 000000000000..6485e232d869
--- /dev/null
+++ b/drivers/isdn/hisax/ipacx.c
@@ -0,0 +1,1004 @@
1/*
2 *
3 * IPACX specific routines
4 *
5 * Author Joerg Petersohn
6 * Derived from hisax_isac.c, isac.c, hscx.c and others
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 */
12#include <linux/kernel.h>
13#include <linux/config.h>
14#include <linux/init.h>
15#include "hisax_if.h"
16#include "hisax.h"
17#include "isdnl1.h"
18#include "ipacx.h"
19
20#define DBUSY_TIMER_VALUE 80
21#define TIMER3_VALUE 7000
22#define MAX_DFRAME_LEN_L1 300
23#define B_FIFO_SIZE 64
24#define D_FIFO_SIZE 32
25
26
27// ipacx interrupt mask values
28#define _MASK_IMASK 0x2E // global mask
29#define _MASKB_IMASK 0x0B
30#define _MASKD_IMASK 0x03 // all on
31
32//----------------------------------------------------------
33// local function declarations
34//----------------------------------------------------------
35static void ph_command(struct IsdnCardState *cs, unsigned int command);
36static inline void cic_int(struct IsdnCardState *cs);
37static void dch_l2l1(struct PStack *st, int pr, void *arg);
38static void dbusy_timer_handler(struct IsdnCardState *cs);
39static void ipacx_new_ph(struct IsdnCardState *cs);
40static void dch_bh(struct IsdnCardState *cs);
41static void dch_empty_fifo(struct IsdnCardState *cs, int count);
42static void dch_fill_fifo(struct IsdnCardState *cs);
43static inline void dch_int(struct IsdnCardState *cs);
44static void __devinit dch_setstack(struct PStack *st, struct IsdnCardState *cs);
45static void __devinit dch_init(struct IsdnCardState *cs);
46static void bch_l2l1(struct PStack *st, int pr, void *arg);
47static void bch_empty_fifo(struct BCState *bcs, int count);
48static void bch_fill_fifo(struct BCState *bcs);
49static void bch_int(struct IsdnCardState *cs, u_char hscx);
50static void bch_mode(struct BCState *bcs, int mode, int bc);
51static void bch_close_state(struct BCState *bcs);
52static int bch_open_state(struct IsdnCardState *cs, struct BCState *bcs);
53static int bch_setstack(struct PStack *st, struct BCState *bcs);
54static void __devinit bch_init(struct IsdnCardState *cs, int hscx);
55static void __init clear_pending_ints(struct IsdnCardState *cs);
56
57//----------------------------------------------------------
58// Issue Layer 1 command to chip
59//----------------------------------------------------------
60static void
61ph_command(struct IsdnCardState *cs, unsigned int command)
62{
63 if (cs->debug &L1_DEB_ISAC)
64 debugl1(cs, "ph_command (%#x) in (%#x)", command,
65 cs->dc.isac.ph_state);
66//###################################
67// printk(KERN_INFO "ph_command (%#x)\n", command);
68//###################################
69 cs->writeisac(cs, IPACX_CIX0, (command << 4) | 0x0E);
70}
71
72//----------------------------------------------------------
73// Transceiver interrupt handler
74//----------------------------------------------------------
75static inline void
76cic_int(struct IsdnCardState *cs)
77{
78 u_char event;
79
80 event = cs->readisac(cs, IPACX_CIR0) >> 4;
81 if (cs->debug &L1_DEB_ISAC) debugl1(cs, "cic_int(event=%#x)", event);
82//#########################################
83// printk(KERN_INFO "cic_int(%x)\n", event);
84//#########################################
85 cs->dc.isac.ph_state = event;
86 schedule_event(cs, D_L1STATECHANGE);
87}
88
89//==========================================================
90// D channel functions
91//==========================================================
92
93//----------------------------------------------------------
94// Command entry point
95//----------------------------------------------------------
96static void
97dch_l2l1(struct PStack *st, int pr, void *arg)
98{
99 struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
100 struct sk_buff *skb = arg;
101 u_char cda1_cr, cda2_cr;
102
103 switch (pr) {
104 case (PH_DATA |REQUEST):
105 if (cs->debug &DEB_DLOG_HEX) LogFrame(cs, skb->data, skb->len);
106 if (cs->debug &DEB_DLOG_VERBOSE) dlogframe(cs, skb, 0);
107 if (cs->tx_skb) {
108 skb_queue_tail(&cs->sq, skb);
109#ifdef L2FRAME_DEBUG
110 if (cs->debug &L1_DEB_LAPD) Logl2Frame(cs, skb, "PH_DATA Queued", 0);
111#endif
112 } else {
113 cs->tx_skb = skb;
114 cs->tx_cnt = 0;
115#ifdef L2FRAME_DEBUG
116 if (cs->debug &L1_DEB_LAPD) Logl2Frame(cs, skb, "PH_DATA", 0);
117#endif
118 dch_fill_fifo(cs);
119 }
120 break;
121
122 case (PH_PULL |INDICATION):
123 if (cs->tx_skb) {
124 if (cs->debug & L1_DEB_WARN)
125 debugl1(cs, " l2l1 tx_skb exist this shouldn't happen");
126 skb_queue_tail(&cs->sq, skb);
127 break;
128 }
129 if (cs->debug & DEB_DLOG_HEX) LogFrame(cs, skb->data, skb->len);
130 if (cs->debug & DEB_DLOG_VERBOSE) dlogframe(cs, skb, 0);
131 cs->tx_skb = skb;
132 cs->tx_cnt = 0;
133#ifdef L2FRAME_DEBUG
134 if (cs->debug & L1_DEB_LAPD) Logl2Frame(cs, skb, "PH_DATA_PULLED", 0);
135#endif
136 dch_fill_fifo(cs);
137 break;
138
139 case (PH_PULL | REQUEST):
140#ifdef L2FRAME_DEBUG
141 if (cs->debug & L1_DEB_LAPD) debugl1(cs, "-> PH_REQUEST_PULL");
142#endif
143 if (!cs->tx_skb) {
144 clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
145 st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
146 } else
147 set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
148 break;
149
150 case (HW_RESET | REQUEST):
151 case (HW_ENABLE | REQUEST):
152 if ((cs->dc.isac.ph_state == IPACX_IND_RES) ||
153 (cs->dc.isac.ph_state == IPACX_IND_DR) ||
154 (cs->dc.isac.ph_state == IPACX_IND_DC))
155 ph_command(cs, IPACX_CMD_TIM);
156 else
157 ph_command(cs, IPACX_CMD_RES);
158 break;
159
160 case (HW_INFO3 | REQUEST):
161 ph_command(cs, IPACX_CMD_AR8);
162 break;
163
164 case (HW_TESTLOOP | REQUEST):
165 cs->writeisac(cs, IPACX_CDA_TSDP10, 0x80); // Timeslot 0 is B1
166 cs->writeisac(cs, IPACX_CDA_TSDP11, 0x81); // Timeslot 0 is B1
167 cda1_cr = cs->readisac(cs, IPACX_CDA1_CR);
168 cda2_cr = cs->readisac(cs, IPACX_CDA2_CR);
169 if ((long)arg &1) { // loop B1
170 cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr |0x0a);
171 }
172 else { // B1 off
173 cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr &~0x0a);
174 }
175 if ((long)arg &2) { // loop B2
176 cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr |0x14);
177 }
178 else { // B2 off
179 cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr &~0x14);
180 }
181 break;
182
183 case (HW_DEACTIVATE | RESPONSE):
184 skb_queue_purge(&cs->rq);
185 skb_queue_purge(&cs->sq);
186 if (cs->tx_skb) {
187 dev_kfree_skb_any(cs->tx_skb);
188 cs->tx_skb = NULL;
189 }
190 if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
191 del_timer(&cs->dbusytimer);
192 break;
193
194 default:
195 if (cs->debug &L1_DEB_WARN) debugl1(cs, "dch_l2l1 unknown %04x", pr);
196 break;
197 }
198}
199
200//----------------------------------------------------------
201//----------------------------------------------------------
202static void
203dbusy_timer_handler(struct IsdnCardState *cs)
204{
205 struct PStack *st;
206 int rbchd, stard;
207
208 if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
209 rbchd = cs->readisac(cs, IPACX_RBCHD);
210 stard = cs->readisac(cs, IPACX_STARD);
211 if (cs->debug)
212 debugl1(cs, "D-Channel Busy RBCHD %02x STARD %02x", rbchd, stard);
213 if (!(stard &0x40)) { // D-Channel Busy
214 set_bit(FLG_L1_DBUSY, &cs->HW_Flags);
215 for (st = cs->stlist; st; st = st->next) {
216 st->l1.l1l2(st, PH_PAUSE | INDICATION, NULL); // flow control on
217 }
218 } else {
219 // seems we lost an interrupt; reset transceiver */
220 clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags);
221 if (cs->tx_skb) {
222 dev_kfree_skb_any(cs->tx_skb);
223 cs->tx_cnt = 0;
224 cs->tx_skb = NULL;
225 } else {
226 printk(KERN_WARNING "HiSax: ISAC D-Channel Busy no skb\n");
227 debugl1(cs, "D-Channel Busy no skb");
228 }
229 cs->writeisac(cs, IPACX_CMDRD, 0x01); // Tx reset, generates XPR
230 }
231 }
232}
233
234//----------------------------------------------------------
235// L1 state machine intermediate layer to isdnl1 module
236//----------------------------------------------------------
237static void
238ipacx_new_ph(struct IsdnCardState *cs)
239{
240 switch (cs->dc.isac.ph_state) {
241 case (IPACX_IND_RES):
242 ph_command(cs, IPACX_CMD_DI);
243 l1_msg(cs, HW_RESET | INDICATION, NULL);
244 break;
245
246 case (IPACX_IND_DC):
247 l1_msg(cs, HW_DEACTIVATE | CONFIRM, NULL);
248 break;
249
250 case (IPACX_IND_DR):
251 l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL);
252 break;
253
254 case (IPACX_IND_PU):
255 l1_msg(cs, HW_POWERUP | CONFIRM, NULL);
256 break;
257
258 case (IPACX_IND_RSY):
259 l1_msg(cs, HW_RSYNC | INDICATION, NULL);
260 break;
261
262 case (IPACX_IND_AR):
263 l1_msg(cs, HW_INFO2 | INDICATION, NULL);
264 break;
265
266 case (IPACX_IND_AI8):
267 l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
268 break;
269
270 case (IPACX_IND_AI10):
271 l1_msg(cs, HW_INFO4_P10 | INDICATION, NULL);
272 break;
273
274 default:
275 break;
276 }
277}
278
279//----------------------------------------------------------
280// bottom half handler for D channel
281//----------------------------------------------------------
282static void
283dch_bh(struct IsdnCardState *cs)
284{
285 struct PStack *st;
286
287 if (!cs) return;
288
289 if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) {
290 if (cs->debug) debugl1(cs, "D-Channel Busy cleared");
291 for (st = cs->stlist; st; st = st->next) {
292 st->l1.l1l2(st, PH_PAUSE | CONFIRM, NULL);
293 }
294 }
295
296 if (test_and_clear_bit(D_RCVBUFREADY, &cs->event)) {
297 DChannel_proc_rcv(cs);
298 }
299
300 if (test_and_clear_bit(D_XMTBUFREADY, &cs->event)) {
301 DChannel_proc_xmt(cs);
302 }
303
304 if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) {
305 ipacx_new_ph(cs);
306 }
307}
308
309//----------------------------------------------------------
310// Fill buffer from receive FIFO
311//----------------------------------------------------------
312static void
313dch_empty_fifo(struct IsdnCardState *cs, int count)
314{
315 u_char *ptr;
316
317 if ((cs->debug &L1_DEB_ISAC) && !(cs->debug &L1_DEB_ISAC_FIFO))
318 debugl1(cs, "dch_empty_fifo()");
319
320 // message too large, remove
321 if ((cs->rcvidx + count) >= MAX_DFRAME_LEN_L1) {
322 if (cs->debug &L1_DEB_WARN)
323 debugl1(cs, "dch_empty_fifo() incoming message too large");
324 cs->writeisac(cs, IPACX_CMDRD, 0x80); // RMC
325 cs->rcvidx = 0;
326 return;
327 }
328
329 ptr = cs->rcvbuf + cs->rcvidx;
330 cs->rcvidx += count;
331
332 cs->readisacfifo(cs, ptr, count);
333 cs->writeisac(cs, IPACX_CMDRD, 0x80); // RMC
334
335 if (cs->debug &L1_DEB_ISAC_FIFO) {
336 char *t = cs->dlog;
337
338 t += sprintf(t, "dch_empty_fifo() cnt %d", count);
339 QuickHex(t, ptr, count);
340 debugl1(cs, cs->dlog);
341 }
342}
343
344//----------------------------------------------------------
345// Fill transmit FIFO
346//----------------------------------------------------------
347static void
348dch_fill_fifo(struct IsdnCardState *cs)
349{
350 int count;
351 u_char cmd, *ptr;
352
353 if ((cs->debug &L1_DEB_ISAC) && !(cs->debug &L1_DEB_ISAC_FIFO))
354 debugl1(cs, "dch_fill_fifo()");
355
356 if (!cs->tx_skb) return;
357 count = cs->tx_skb->len;
358 if (count <= 0) return;
359
360 if (count > D_FIFO_SIZE) {
361 count = D_FIFO_SIZE;
362 cmd = 0x08; // XTF
363 } else {
364 cmd = 0x0A; // XTF | XME
365 }
366
367 ptr = cs->tx_skb->data;
368 skb_pull(cs->tx_skb, count);
369 cs->tx_cnt += count;
370 cs->writeisacfifo(cs, ptr, count);
371 cs->writeisac(cs, IPACX_CMDRD, cmd);
372
373 // set timeout for transmission contol
374 if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
375 debugl1(cs, "dch_fill_fifo dbusytimer running");
376 del_timer(&cs->dbusytimer);
377 }
378 init_timer(&cs->dbusytimer);
379 cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000);
380 add_timer(&cs->dbusytimer);
381
382 if (cs->debug &L1_DEB_ISAC_FIFO) {
383 char *t = cs->dlog;
384
385 t += sprintf(t, "dch_fill_fifo() cnt %d", count);
386 QuickHex(t, ptr, count);
387 debugl1(cs, cs->dlog);
388 }
389}
390
391//----------------------------------------------------------
392// D channel interrupt handler
393//----------------------------------------------------------
394static inline void
395dch_int(struct IsdnCardState *cs)
396{
397 struct sk_buff *skb;
398 u_char istad, rstad;
399 int count;
400
401 istad = cs->readisac(cs, IPACX_ISTAD);
402//##############################################
403// printk(KERN_WARNING "dch_int(istad=%02x)\n", istad);
404//##############################################
405
406 if (istad &0x80) { // RME
407 rstad = cs->readisac(cs, IPACX_RSTAD);
408 if ((rstad &0xf0) != 0xa0) { // !(VFR && !RDO && CRC && !RAB)
409 if (!(rstad &0x80))
410 if (cs->debug &L1_DEB_WARN)
411 debugl1(cs, "dch_int(): invalid frame");
412 if ((rstad &0x40))
413 if (cs->debug &L1_DEB_WARN)
414 debugl1(cs, "dch_int(): RDO");
415 if (!(rstad &0x20))
416 if (cs->debug &L1_DEB_WARN)
417 debugl1(cs, "dch_int(): CRC error");
418 cs->writeisac(cs, IPACX_CMDRD, 0x80); // RMC
419 } else { // received frame ok
420 count = cs->readisac(cs, IPACX_RBCLD);
421 if (count) count--; // RSTAB is last byte
422 count &= D_FIFO_SIZE-1;
423 if (count == 0) count = D_FIFO_SIZE;
424 dch_empty_fifo(cs, count);
425 if ((count = cs->rcvidx) > 0) {
426 cs->rcvidx = 0;
427 if (!(skb = dev_alloc_skb(count)))
428 printk(KERN_WARNING "HiSax dch_int(): receive out of memory\n");
429 else {
430 memcpy(skb_put(skb, count), cs->rcvbuf, count);
431 skb_queue_tail(&cs->rq, skb);
432 }
433 }
434 }
435 cs->rcvidx = 0;
436 schedule_event(cs, D_RCVBUFREADY);
437 }
438
439 if (istad &0x40) { // RPF
440 dch_empty_fifo(cs, D_FIFO_SIZE);
441 }
442
443 if (istad &0x20) { // RFO
444 if (cs->debug &L1_DEB_WARN) debugl1(cs, "dch_int(): RFO");
445 cs->writeisac(cs, IPACX_CMDRD, 0x40); //RRES
446 }
447
448 if (istad &0x10) { // XPR
449 if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
450 del_timer(&cs->dbusytimer);
451 if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
452 schedule_event(cs, D_CLEARBUSY);
453 if (cs->tx_skb) {
454 if (cs->tx_skb->len) {
455 dch_fill_fifo(cs);
456 goto afterXPR;
457 }
458 else {
459 dev_kfree_skb_irq(cs->tx_skb);
460 cs->tx_skb = NULL;
461 cs->tx_cnt = 0;
462 }
463 }
464 if ((cs->tx_skb = skb_dequeue(&cs->sq))) {
465 cs->tx_cnt = 0;
466 dch_fill_fifo(cs);
467 }
468 else {
469 schedule_event(cs, D_XMTBUFREADY);
470 }
471 }
472 afterXPR:
473
474 if (istad &0x0C) { // XDU or XMR
475 if (cs->debug &L1_DEB_WARN) debugl1(cs, "dch_int(): XDU");
476 if (cs->tx_skb) {
477 skb_push(cs->tx_skb, cs->tx_cnt); // retransmit
478 cs->tx_cnt = 0;
479 dch_fill_fifo(cs);
480 } else {
481 printk(KERN_WARNING "HiSax: ISAC XDU no skb\n");
482 debugl1(cs, "ISAC XDU no skb");
483 }
484 }
485}
486
487//----------------------------------------------------------
488//----------------------------------------------------------
489static void __devinit
490dch_setstack(struct PStack *st, struct IsdnCardState *cs)
491{
492 st->l1.l1hw = dch_l2l1;
493}
494
495//----------------------------------------------------------
496//----------------------------------------------------------
497static void __devinit
498dch_init(struct IsdnCardState *cs)
499{
500 printk(KERN_INFO "HiSax: IPACX ISDN driver v0.1.0\n");
501
502 cs->setstack_d = dch_setstack;
503
504 cs->dbusytimer.function = (void *) dbusy_timer_handler;
505 cs->dbusytimer.data = (long) cs;
506 init_timer(&cs->dbusytimer);
507
508 cs->writeisac(cs, IPACX_TR_CONF0, 0x00); // clear LDD
509 cs->writeisac(cs, IPACX_TR_CONF2, 0x00); // enable transmitter
510 cs->writeisac(cs, IPACX_MODED, 0xC9); // transparent mode 0, RAC, stop/go
511 cs->writeisac(cs, IPACX_MON_CR, 0x00); // disable monitor channel
512}
513
514
515//==========================================================
516// B channel functions
517//==========================================================
518
519//----------------------------------------------------------
520// Entry point for commands
521//----------------------------------------------------------
522static void
523bch_l2l1(struct PStack *st, int pr, void *arg)
524{
525 struct BCState *bcs = st->l1.bcs;
526 struct sk_buff *skb = arg;
527 u_long flags;
528
529 switch (pr) {
530 case (PH_DATA | REQUEST):
531 spin_lock_irqsave(&bcs->cs->lock, flags);
532 if (bcs->tx_skb) {
533 skb_queue_tail(&bcs->squeue, skb);
534 } else {
535 bcs->tx_skb = skb;
536 set_bit(BC_FLG_BUSY, &bcs->Flag);
537 bcs->hw.hscx.count = 0;
538 bch_fill_fifo(bcs);
539 }
540 spin_unlock_irqrestore(&bcs->cs->lock, flags);
541 break;
542 case (PH_PULL | INDICATION):
543 spin_lock_irqsave(&bcs->cs->lock, flags);
544 if (bcs->tx_skb) {
545 printk(KERN_WARNING "HiSax bch_l2l1(): this shouldn't happen\n");
546 } else {
547 set_bit(BC_FLG_BUSY, &bcs->Flag);
548 bcs->tx_skb = skb;
549 bcs->hw.hscx.count = 0;
550 bch_fill_fifo(bcs);
551 }
552 spin_unlock_irqrestore(&bcs->cs->lock, flags);
553 break;
554 case (PH_PULL | REQUEST):
555 if (!bcs->tx_skb) {
556 clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
557 st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
558 } else
559 set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
560 break;
561 case (PH_ACTIVATE | REQUEST):
562 spin_lock_irqsave(&bcs->cs->lock, flags);
563 set_bit(BC_FLG_ACTIV, &bcs->Flag);
564 bch_mode(bcs, st->l1.mode, st->l1.bc);
565 spin_unlock_irqrestore(&bcs->cs->lock, flags);
566 l1_msg_b(st, pr, arg);
567 break;
568 case (PH_DEACTIVATE | REQUEST):
569 l1_msg_b(st, pr, arg);
570 break;
571 case (PH_DEACTIVATE | CONFIRM):
572 spin_lock_irqsave(&bcs->cs->lock, flags);
573 clear_bit(BC_FLG_ACTIV, &bcs->Flag);
574 clear_bit(BC_FLG_BUSY, &bcs->Flag);
575 bch_mode(bcs, 0, st->l1.bc);
576 spin_unlock_irqrestore(&bcs->cs->lock, flags);
577 st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
578 break;
579 }
580}
581
582//----------------------------------------------------------
583// Read B channel fifo to receive buffer
584//----------------------------------------------------------
585static void
586bch_empty_fifo(struct BCState *bcs, int count)
587{
588 u_char *ptr, hscx;
589 struct IsdnCardState *cs;
590 int cnt;
591
592 cs = bcs->cs;
593 hscx = bcs->hw.hscx.hscx;
594 if ((cs->debug &L1_DEB_HSCX) && !(cs->debug &L1_DEB_HSCX_FIFO))
595 debugl1(cs, "bch_empty_fifo()");
596
597 // message too large, remove
598 if (bcs->hw.hscx.rcvidx + count > HSCX_BUFMAX) {
599 if (cs->debug &L1_DEB_WARN)
600 debugl1(cs, "bch_empty_fifo() incoming packet too large");
601 cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x80); // RMC
602 bcs->hw.hscx.rcvidx = 0;
603 return;
604 }
605
606 ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx;
607 cnt = count;
608 while (cnt--) *ptr++ = cs->BC_Read_Reg(cs, hscx, IPACX_RFIFOB);
609 cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x80); // RMC
610
611 ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx;
612 bcs->hw.hscx.rcvidx += count;
613
614 if (cs->debug &L1_DEB_HSCX_FIFO) {
615 char *t = bcs->blog;
616
617 t += sprintf(t, "bch_empty_fifo() B-%d cnt %d", hscx, count);
618 QuickHex(t, ptr, count);
619 debugl1(cs, bcs->blog);
620 }
621}
622
623//----------------------------------------------------------
624// Fill buffer to transmit FIFO
625//----------------------------------------------------------
626static void
627bch_fill_fifo(struct BCState *bcs)
628{
629 struct IsdnCardState *cs;
630 int more, count, cnt;
631 u_char *ptr, *p, hscx;
632
633 cs = bcs->cs;
634 if ((cs->debug &L1_DEB_HSCX) && !(cs->debug &L1_DEB_HSCX_FIFO))
635 debugl1(cs, "bch_fill_fifo()");
636
637 if (!bcs->tx_skb) return;
638 if (bcs->tx_skb->len <= 0) return;
639
640 hscx = bcs->hw.hscx.hscx;
641 more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0;
642 if (bcs->tx_skb->len > B_FIFO_SIZE) {
643 more = 1;
644 count = B_FIFO_SIZE;
645 } else {
646 count = bcs->tx_skb->len;
647 }
648 cnt = count;
649
650 p = ptr = bcs->tx_skb->data;
651 skb_pull(bcs->tx_skb, count);
652 bcs->tx_cnt -= count;
653 bcs->hw.hscx.count += count;
654 while (cnt--) cs->BC_Write_Reg(cs, hscx, IPACX_XFIFOB, *p++);
655 cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, (more ? 0x08 : 0x0a));
656
657 if (cs->debug &L1_DEB_HSCX_FIFO) {
658 char *t = bcs->blog;
659
660 t += sprintf(t, "chb_fill_fifo() B-%d cnt %d", hscx, count);
661 QuickHex(t, ptr, count);
662 debugl1(cs, bcs->blog);
663 }
664}
665
666//----------------------------------------------------------
667// B channel interrupt handler
668//----------------------------------------------------------
669static void
670bch_int(struct IsdnCardState *cs, u_char hscx)
671{
672 u_char istab;
673 struct BCState *bcs;
674 struct sk_buff *skb;
675 int count;
676 u_char rstab;
677
678 bcs = cs->bcs + hscx;
679 istab = cs->BC_Read_Reg(cs, hscx, IPACX_ISTAB);
680//##############################################
681// printk(KERN_WARNING "bch_int(istab=%02x)\n", istab);
682//##############################################
683 if (!test_bit(BC_FLG_INIT, &bcs->Flag)) return;
684
685 if (istab &0x80) { // RME
686 rstab = cs->BC_Read_Reg(cs, hscx, IPACX_RSTAB);
687 if ((rstab &0xf0) != 0xa0) { // !(VFR && !RDO && CRC && !RAB)
688 if (!(rstab &0x80))
689 if (cs->debug &L1_DEB_WARN)
690 debugl1(cs, "bch_int() B-%d: invalid frame", hscx);
691 if ((rstab &0x40) && (bcs->mode != L1_MODE_NULL))
692 if (cs->debug &L1_DEB_WARN)
693 debugl1(cs, "bch_int() B-%d: RDO mode=%d", hscx, bcs->mode);
694 if (!(rstab &0x20))
695 if (cs->debug &L1_DEB_WARN)
696 debugl1(cs, "bch_int() B-%d: CRC error", hscx);
697 cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x80); // RMC
698 }
699 else { // received frame ok
700 count = cs->BC_Read_Reg(cs, hscx, IPACX_RBCLB) &(B_FIFO_SIZE-1);
701 if (count == 0) count = B_FIFO_SIZE;
702 bch_empty_fifo(bcs, count);
703 if ((count = bcs->hw.hscx.rcvidx - 1) > 0) {
704 if (cs->debug &L1_DEB_HSCX_FIFO)
705 debugl1(cs, "bch_int Frame %d", count);
706 if (!(skb = dev_alloc_skb(count)))
707 printk(KERN_WARNING "HiSax bch_int(): receive frame out of memory\n");
708 else {
709 memcpy(skb_put(skb, count), bcs->hw.hscx.rcvbuf, count);
710 skb_queue_tail(&bcs->rqueue, skb);
711 }
712 }
713 }
714 bcs->hw.hscx.rcvidx = 0;
715 schedule_event(bcs, B_RCVBUFREADY);
716 }
717
718 if (istab &0x40) { // RPF
719 bch_empty_fifo(bcs, B_FIFO_SIZE);
720
721 if (bcs->mode == L1_MODE_TRANS) { // queue every chunk
722 // receive transparent audio data
723 if (!(skb = dev_alloc_skb(B_FIFO_SIZE)))
724 printk(KERN_WARNING "HiSax bch_int(): receive transparent out of memory\n");
725 else {
726 memcpy(skb_put(skb, B_FIFO_SIZE), bcs->hw.hscx.rcvbuf, B_FIFO_SIZE);
727 skb_queue_tail(&bcs->rqueue, skb);
728 }
729 bcs->hw.hscx.rcvidx = 0;
730 schedule_event(bcs, B_RCVBUFREADY);
731 }
732 }
733
734 if (istab &0x20) { // RFO
735 if (cs->debug &L1_DEB_WARN)
736 debugl1(cs, "bch_int() B-%d: RFO error", hscx);
737 cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x40); // RRES
738 }
739
740 if (istab &0x10) { // XPR
741 if (bcs->tx_skb) {
742 if (bcs->tx_skb->len) {
743 bch_fill_fifo(bcs);
744 goto afterXPR;
745 } else {
746 if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) &&
747 (PACKET_NOACK != bcs->tx_skb->pkt_type)) {
748 u_long flags;
749 spin_lock_irqsave(&bcs->aclock, flags);
750 bcs->ackcnt += bcs->hw.hscx.count;
751 spin_unlock_irqrestore(&bcs->aclock, flags);
752 schedule_event(bcs, B_ACKPENDING);
753 }
754 }
755 dev_kfree_skb_irq(bcs->tx_skb);
756 bcs->hw.hscx.count = 0;
757 bcs->tx_skb = NULL;
758 }
759 if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
760 bcs->hw.hscx.count = 0;
761 set_bit(BC_FLG_BUSY, &bcs->Flag);
762 bch_fill_fifo(bcs);
763 } else {
764 clear_bit(BC_FLG_BUSY, &bcs->Flag);
765 schedule_event(bcs, B_XMTBUFREADY);
766 }
767 }
768 afterXPR:
769
770 if (istab &0x04) { // XDU
771 if (bcs->mode == L1_MODE_TRANS) {
772 bch_fill_fifo(bcs);
773 }
774 else {
775 if (bcs->tx_skb) { // restart transmitting the whole frame
776 skb_push(bcs->tx_skb, bcs->hw.hscx.count);
777 bcs->tx_cnt += bcs->hw.hscx.count;
778 bcs->hw.hscx.count = 0;
779 }
780 cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x01); // XRES
781 if (cs->debug &L1_DEB_WARN)
782 debugl1(cs, "bch_int() B-%d XDU error", hscx);
783 }
784 }
785}
786
787//----------------------------------------------------------
788//----------------------------------------------------------
789static void
790bch_mode(struct BCState *bcs, int mode, int bc)
791{
792 struct IsdnCardState *cs = bcs->cs;
793 int hscx = bcs->hw.hscx.hscx;
794
795 bc = bc ? 1 : 0; // in case bc is greater than 1
796 if (cs->debug & L1_DEB_HSCX)
797 debugl1(cs, "mode_bch() switch B-% mode %d chan %d", hscx, mode, bc);
798 bcs->mode = mode;
799 bcs->channel = bc;
800
801 // map controller to according timeslot
802 if (!hscx)
803 {
804 cs->writeisac(cs, IPACX_BCHA_TSDP_BC1, 0x80 | bc);
805 cs->writeisac(cs, IPACX_BCHA_CR, 0x88);
806 }
807 else
808 {
809 cs->writeisac(cs, IPACX_BCHB_TSDP_BC1, 0x80 | bc);
810 cs->writeisac(cs, IPACX_BCHB_CR, 0x88);
811 }
812
813 switch (mode) {
814 case (L1_MODE_NULL):
815 cs->BC_Write_Reg(cs, hscx, IPACX_MODEB, 0xC0); // rec off
816 cs->BC_Write_Reg(cs, hscx, IPACX_EXMB, 0x30); // std adj.
817 cs->BC_Write_Reg(cs, hscx, IPACX_MASKB, 0xFF); // ints off
818 cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x41); // validate adjustments
819 break;
820 case (L1_MODE_TRANS):
821 cs->BC_Write_Reg(cs, hscx, IPACX_MODEB, 0x88); // ext transp mode
822 cs->BC_Write_Reg(cs, hscx, IPACX_EXMB, 0x00); // xxx00000
823 cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x41); // validate adjustments
824 cs->BC_Write_Reg(cs, hscx, IPACX_MASKB, _MASKB_IMASK);
825 break;
826 case (L1_MODE_HDLC):
827 cs->BC_Write_Reg(cs, hscx, IPACX_MODEB, 0xC8); // transp mode 0
828 cs->BC_Write_Reg(cs, hscx, IPACX_EXMB, 0x01); // idle=hdlc flags crc enabled
829 cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x41); // validate adjustments
830 cs->BC_Write_Reg(cs, hscx, IPACX_MASKB, _MASKB_IMASK);
831 break;
832 }
833}
834
835//----------------------------------------------------------
836//----------------------------------------------------------
837static void
838bch_close_state(struct BCState *bcs)
839{
840 bch_mode(bcs, 0, bcs->channel);
841 if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) {
842 if (bcs->hw.hscx.rcvbuf) {
843 kfree(bcs->hw.hscx.rcvbuf);
844 bcs->hw.hscx.rcvbuf = NULL;
845 }
846 if (bcs->blog) {
847 kfree(bcs->blog);
848 bcs->blog = NULL;
849 }
850 skb_queue_purge(&bcs->rqueue);
851 skb_queue_purge(&bcs->squeue);
852 if (bcs->tx_skb) {
853 dev_kfree_skb_any(bcs->tx_skb);
854 bcs->tx_skb = NULL;
855 clear_bit(BC_FLG_BUSY, &bcs->Flag);
856 }
857 }
858}
859
860//----------------------------------------------------------
861//----------------------------------------------------------
862static int
863bch_open_state(struct IsdnCardState *cs, struct BCState *bcs)
864{
865 if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
866 if (!(bcs->hw.hscx.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) {
867 printk(KERN_WARNING
868 "HiSax open_bchstate(): No memory for hscx.rcvbuf\n");
869 clear_bit(BC_FLG_INIT, &bcs->Flag);
870 return (1);
871 }
872 if (!(bcs->blog = kmalloc(MAX_BLOG_SPACE, GFP_ATOMIC))) {
873 printk(KERN_WARNING
874 "HiSax open_bchstate: No memory for bcs->blog\n");
875 clear_bit(BC_FLG_INIT, &bcs->Flag);
876 kfree(bcs->hw.hscx.rcvbuf);
877 bcs->hw.hscx.rcvbuf = NULL;
878 return (2);
879 }
880 skb_queue_head_init(&bcs->rqueue);
881 skb_queue_head_init(&bcs->squeue);
882 }
883 bcs->tx_skb = NULL;
884 clear_bit(BC_FLG_BUSY, &bcs->Flag);
885 bcs->event = 0;
886 bcs->hw.hscx.rcvidx = 0;
887 bcs->tx_cnt = 0;
888 return (0);
889}
890
891//----------------------------------------------------------
892//----------------------------------------------------------
893static int
894bch_setstack(struct PStack *st, struct BCState *bcs)
895{
896 bcs->channel = st->l1.bc;
897 if (bch_open_state(st->l1.hardware, bcs)) return (-1);
898 st->l1.bcs = bcs;
899 st->l2.l2l1 = bch_l2l1;
900 setstack_manager(st);
901 bcs->st = st;
902 setstack_l1_B(st);
903 return (0);
904}
905
906//----------------------------------------------------------
907//----------------------------------------------------------
908static void __devinit
909bch_init(struct IsdnCardState *cs, int hscx)
910{
911 cs->bcs[hscx].BC_SetStack = bch_setstack;
912 cs->bcs[hscx].BC_Close = bch_close_state;
913 cs->bcs[hscx].hw.hscx.hscx = hscx;
914 cs->bcs[hscx].cs = cs;
915 bch_mode(cs->bcs + hscx, 0, hscx);
916}
917
918
919//==========================================================
920// Shared functions
921//==========================================================
922
923//----------------------------------------------------------
924// Main interrupt handler
925//----------------------------------------------------------
926void
927interrupt_ipacx(struct IsdnCardState *cs)
928{
929 u_char ista;
930
931 while ((ista = cs->readisac(cs, IPACX_ISTA))) {
932//#################################################
933// printk(KERN_WARNING "interrupt_ipacx(ista=%02x)\n", ista);
934//#################################################
935 if (ista &0x80) bch_int(cs, 0); // B channel interrupts
936 if (ista &0x40) bch_int(cs, 1);
937
938 if (ista &0x01) dch_int(cs); // D channel
939 if (ista &0x10) cic_int(cs); // Layer 1 state
940 }
941}
942
943//----------------------------------------------------------
944// Clears chip interrupt status
945//----------------------------------------------------------
946static void __init
947clear_pending_ints(struct IsdnCardState *cs)
948{
949 int ista;
950
951 // all interrupts off
952 cs->writeisac(cs, IPACX_MASK, 0xff);
953 cs->writeisac(cs, IPACX_MASKD, 0xff);
954 cs->BC_Write_Reg(cs, 0, IPACX_MASKB, 0xff);
955 cs->BC_Write_Reg(cs, 1, IPACX_MASKB, 0xff);
956
957 ista = cs->readisac(cs, IPACX_ISTA);
958 if (ista &0x80) cs->BC_Read_Reg(cs, 0, IPACX_ISTAB);
959 if (ista &0x40) cs->BC_Read_Reg(cs, 1, IPACX_ISTAB);
960 if (ista &0x10) cs->readisac(cs, IPACX_CIR0);
961 if (ista &0x01) cs->readisac(cs, IPACX_ISTAD);
962}
963
964//----------------------------------------------------------
965// Does chip configuration work
966// Work to do depends on bit mask in part
967//----------------------------------------------------------
968void __init
969init_ipacx(struct IsdnCardState *cs, int part)
970{
971 if (part &1) { // initialise chip
972//##################################################
973// printk(KERN_INFO "init_ipacx(%x)\n", part);
974//##################################################
975 clear_pending_ints(cs);
976 bch_init(cs, 0);
977 bch_init(cs, 1);
978 dch_init(cs);
979 }
980 if (part &2) { // reenable all interrupts and start chip
981 cs->BC_Write_Reg(cs, 0, IPACX_MASKB, _MASKB_IMASK);
982 cs->BC_Write_Reg(cs, 1, IPACX_MASKB, _MASKB_IMASK);
983 cs->writeisac(cs, IPACX_MASKD, _MASKD_IMASK);
984 cs->writeisac(cs, IPACX_MASK, _MASK_IMASK); // global mask register
985
986 // reset HDLC Transmitters/receivers
987 cs->writeisac(cs, IPACX_CMDRD, 0x41);
988 cs->BC_Write_Reg(cs, 0, IPACX_CMDRB, 0x41);
989 cs->BC_Write_Reg(cs, 1, IPACX_CMDRB, 0x41);
990 ph_command(cs, IPACX_CMD_RES);
991 }
992}
993
994
995void __devinit
996setup_ipacx(struct IsdnCardState *cs)
997{
998 INIT_WORK(&cs->tqueue, (void *)(void *) dch_bh, cs);
999 cs->dbusytimer.function = (void *) dbusy_timer_handler;
1000 cs->dbusytimer.data = (long) cs;
1001 init_timer(&cs->dbusytimer);
1002}
1003//----------------- end of file -----------------------
1004
diff --git a/drivers/isdn/hisax/ipacx.h b/drivers/isdn/hisax/ipacx.h
new file mode 100644
index 000000000000..e8a22e8f34b6
--- /dev/null
+++ b/drivers/isdn/hisax/ipacx.h
@@ -0,0 +1,162 @@
1/*
2 *
3 * IPACX specific defines
4 *
5 * This software may be used and distributed according to the terms
6 * of the GNU General Public License, incorporated herein by reference.
7 *
8 */
9
10/* All Registers original Siemens Spec */
11
12#ifndef INCLUDE_IPACX_H
13#define INCLUDE_IPACX_H
14
15/* D-channel registers */
16#define IPACX_RFIFOD 0x00 /* RD */
17#define IPACX_XFIFOD 0x00 /* WR */
18#define IPACX_ISTAD 0x20 /* RD */
19#define IPACX_MASKD 0x20 /* WR */
20#define IPACX_STARD 0x21 /* RD */
21#define IPACX_CMDRD 0x21 /* WR */
22#define IPACX_MODED 0x22 /* RD/WR */
23#define IPACX_EXMD1 0x23 /* RD/WR */
24#define IPACX_TIMR1 0x24 /* RD/WR */
25#define IPACX_SAP1 0x25 /* WR */
26#define IPACX_SAP2 0x26 /* WR */
27#define IPACX_RBCLD 0x26 /* RD */
28#define IPACX_RBCHD 0x27 /* RD */
29#define IPACX_TEI1 0x27 /* WR */
30#define IPACX_TEI2 0x28 /* WR */
31#define IPACX_RSTAD 0x28 /* RD */
32#define IPACX_TMD 0x29 /* RD/WR */
33#define IPACX_CIR0 0x2E /* RD */
34#define IPACX_CIX0 0x2E /* WR */
35#define IPACX_CIR1 0x2F /* RD */
36#define IPACX_CIX1 0x2F /* WR */
37
38/* Transceiver registers */
39#define IPACX_TR_CONF0 0x30 /* RD/WR */
40#define IPACX_TR_CONF1 0x31 /* RD/WR */
41#define IPACX_TR_CONF2 0x32 /* RD/WR */
42#define IPACX_TR_STA 0x33 /* RD */
43#define IPACX_TR_CMD 0x34 /* RD/WR */
44#define IPACX_SQRR1 0x35 /* RD */
45#define IPACX_SQXR1 0x35 /* WR */
46#define IPACX_SQRR2 0x36 /* RD */
47#define IPACX_SQXR2 0x36 /* WR */
48#define IPACX_SQRR3 0x37 /* RD */
49#define IPACX_SQXR3 0x37 /* WR */
50#define IPACX_ISTATR 0x38 /* RD */
51#define IPACX_MASKTR 0x39 /* RD/WR */
52#define IPACX_TR_MODE 0x3A /* RD/WR */
53#define IPACX_ACFG1 0x3C /* RD/WR */
54#define IPACX_ACFG2 0x3D /* RD/WR */
55#define IPACX_AOE 0x3E /* RD/WR */
56#define IPACX_ARX 0x3F /* RD */
57#define IPACX_ATX 0x3F /* WR */
58
59/* IOM: Timeslot, DPS, CDA */
60#define IPACX_CDA10 0x40 /* RD/WR */
61#define IPACX_CDA11 0x41 /* RD/WR */
62#define IPACX_CDA20 0x42 /* RD/WR */
63#define IPACX_CDA21 0x43 /* RD/WR */
64#define IPACX_CDA_TSDP10 0x44 /* RD/WR */
65#define IPACX_CDA_TSDP11 0x45 /* RD/WR */
66#define IPACX_CDA_TSDP20 0x46 /* RD/WR */
67#define IPACX_CDA_TSDP21 0x47 /* RD/WR */
68#define IPACX_BCHA_TSDP_BC1 0x48 /* RD/WR */
69#define IPACX_BCHA_TSDP_BC2 0x49 /* RD/WR */
70#define IPACX_BCHB_TSDP_BC1 0x4A /* RD/WR */
71#define IPACX_BCHB_TSDP_BC2 0x4B /* RD/WR */
72#define IPACX_TR_TSDP_BC1 0x4C /* RD/WR */
73#define IPACX_TR_TSDP_BC2 0x4D /* RD/WR */
74#define IPACX_CDA1_CR 0x4E /* RD/WR */
75#define IPACX_CDA2_CR 0x4F /* RD/WR */
76
77/* IOM: Contol, Sync transfer, Monitor */
78#define IPACX_TR_CR 0x50 /* RD/WR */
79#define IPACX_TRC_CR 0x50 /* RD/WR */
80#define IPACX_BCHA_CR 0x51 /* RD/WR */
81#define IPACX_BCHB_CR 0x52 /* RD/WR */
82#define IPACX_DCI_CR 0x53 /* RD/WR */
83#define IPACX_DCIC_CR 0x53 /* RD/WR */
84#define IPACX_MON_CR 0x54 /* RD/WR */
85#define IPACX_SDS1_CR 0x55 /* RD/WR */
86#define IPACX_SDS2_CR 0x56 /* RD/WR */
87#define IPACX_IOM_CR 0x57 /* RD/WR */
88#define IPACX_STI 0x58 /* RD */
89#define IPACX_ASTI 0x58 /* WR */
90#define IPACX_MSTI 0x59 /* RD/WR */
91#define IPACX_SDS_CONF 0x5A /* RD/WR */
92#define IPACX_MCDA 0x5B /* RD */
93#define IPACX_MOR 0x5C /* RD */
94#define IPACX_MOX 0x5C /* WR */
95#define IPACX_MOSR 0x5D /* RD */
96#define IPACX_MOCR 0x5E /* RD/WR */
97#define IPACX_MSTA 0x5F /* RD */
98#define IPACX_MCONF 0x5F /* WR */
99
100/* Interrupt and general registers */
101#define IPACX_ISTA 0x60 /* RD */
102#define IPACX_MASK 0x60 /* WR */
103#define IPACX_AUXI 0x61 /* RD */
104#define IPACX_AUXM 0x61 /* WR */
105#define IPACX_MODE1 0x62 /* RD/WR */
106#define IPACX_MODE2 0x63 /* RD/WR */
107#define IPACX_ID 0x64 /* RD */
108#define IPACX_SRES 0x64 /* WR */
109#define IPACX_TIMR2 0x65 /* RD/WR */
110
111/* B-channel registers */
112#define IPACX_OFF_B1 0x70
113#define IPACX_OFF_B2 0x80
114
115#define IPACX_ISTAB 0x00 /* RD */
116#define IPACX_MASKB 0x00 /* WR */
117#define IPACX_STARB 0x01 /* RD */
118#define IPACX_CMDRB 0x01 /* WR */
119#define IPACX_MODEB 0x02 /* RD/WR */
120#define IPACX_EXMB 0x03 /* RD/WR */
121#define IPACX_RAH1 0x05 /* WR */
122#define IPACX_RAH2 0x06 /* WR */
123#define IPACX_RBCLB 0x06 /* RD */
124#define IPACX_RBCHB 0x07 /* RD */
125#define IPACX_RAL1 0x07 /* WR */
126#define IPACX_RAL2 0x08 /* WR */
127#define IPACX_RSTAB 0x08 /* RD */
128#define IPACX_TMB 0x09 /* RD/WR */
129#define IPACX_RFIFOB 0x0A /*- RD */
130#define IPACX_XFIFOB 0x0A /*- WR */
131
132/* Layer 1 Commands */
133#define IPACX_CMD_TIM 0x0
134#define IPACX_CMD_RES 0x1
135#define IPACX_CMD_SSP 0x2
136#define IPACX_CMD_SCP 0x3
137#define IPACX_CMD_AR8 0x8
138#define IPACX_CMD_AR10 0x9
139#define IPACX_CMD_ARL 0xa
140#define IPACX_CMD_DI 0xf
141
142/* Layer 1 Indications */
143#define IPACX_IND_DR 0x0
144#define IPACX_IND_RES 0x1
145#define IPACX_IND_TMA 0x2
146#define IPACX_IND_SLD 0x3
147#define IPACX_IND_RSY 0x4
148#define IPACX_IND_DR6 0x5
149#define IPACX_IND_PU 0x7
150#define IPACX_IND_AR 0x8
151#define IPACX_IND_ARL 0xa
152#define IPACX_IND_CVR 0xb
153#define IPACX_IND_AI8 0xc
154#define IPACX_IND_AI10 0xd
155#define IPACX_IND_AIL 0xe
156#define IPACX_IND_DC 0xf
157
158extern void init_ipacx(struct IsdnCardState *, int);
159extern void interrupt_ipacx(struct IsdnCardState *);
160extern void setup_isac(struct IsdnCardState *);
161
162#endif
diff --git a/drivers/isdn/hisax/isac.c b/drivers/isdn/hisax/isac.c
new file mode 100644
index 000000000000..20b949952952
--- /dev/null
+++ b/drivers/isdn/hisax/isac.c
@@ -0,0 +1,684 @@
1/* $Id: isac.c,v 1.31.2.3 2004/01/13 14:31:25 keil Exp $
2 *
3 * ISAC specific routines
4 *
5 * Author Karsten Keil
6 * Copyright by Karsten Keil <keil@isdn4linux.de>
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 * For changes and modifications please read
12 * Documentation/isdn/HiSax.cert
13 *
14 */
15
16#include "hisax.h"
17#include "isac.h"
18#include "arcofi.h"
19#include "isdnl1.h"
20#include <linux/interrupt.h>
21#include <linux/init.h>
22
23#define DBUSY_TIMER_VALUE 80
24#define ARCOFI_USE 1
25
26static char *ISACVer[] __devinitdata =
27{"2086/2186 V1.1", "2085 B1", "2085 B2",
28 "2085 V2.3"};
29
30void
31ISACVersion(struct IsdnCardState *cs, char *s)
32{
33 int val;
34
35 val = cs->readisac(cs, ISAC_RBCH);
36 printk(KERN_INFO "%s ISAC version (%x): %s\n", s, val, ISACVer[(val >> 5) & 3]);
37}
38
39static void
40ph_command(struct IsdnCardState *cs, unsigned int command)
41{
42 if (cs->debug & L1_DEB_ISAC)
43 debugl1(cs, "ph_command %x", command);
44 cs->writeisac(cs, ISAC_CIX0, (command << 2) | 3);
45}
46
47
48static void
49isac_new_ph(struct IsdnCardState *cs)
50{
51 switch (cs->dc.isac.ph_state) {
52 case (ISAC_IND_RS):
53 case (ISAC_IND_EI):
54 ph_command(cs, ISAC_CMD_DUI);
55 l1_msg(cs, HW_RESET | INDICATION, NULL);
56 break;
57 case (ISAC_IND_DID):
58 l1_msg(cs, HW_DEACTIVATE | CONFIRM, NULL);
59 break;
60 case (ISAC_IND_DR):
61 l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL);
62 break;
63 case (ISAC_IND_PU):
64 l1_msg(cs, HW_POWERUP | CONFIRM, NULL);
65 break;
66 case (ISAC_IND_RSY):
67 l1_msg(cs, HW_RSYNC | INDICATION, NULL);
68 break;
69 case (ISAC_IND_ARD):
70 l1_msg(cs, HW_INFO2 | INDICATION, NULL);
71 break;
72 case (ISAC_IND_AI8):
73 l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
74 break;
75 case (ISAC_IND_AI10):
76 l1_msg(cs, HW_INFO4_P10 | INDICATION, NULL);
77 break;
78 default:
79 break;
80 }
81}
82
83static void
84isac_bh(struct IsdnCardState *cs)
85{
86 struct PStack *stptr;
87
88 if (!cs)
89 return;
90 if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) {
91 if (cs->debug)
92 debugl1(cs, "D-Channel Busy cleared");
93 stptr = cs->stlist;
94 while (stptr != NULL) {
95 stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL);
96 stptr = stptr->next;
97 }
98 }
99 if (test_and_clear_bit(D_L1STATECHANGE, &cs->event))
100 isac_new_ph(cs);
101 if (test_and_clear_bit(D_RCVBUFREADY, &cs->event))
102 DChannel_proc_rcv(cs);
103 if (test_and_clear_bit(D_XMTBUFREADY, &cs->event))
104 DChannel_proc_xmt(cs);
105#if ARCOFI_USE
106 if (!test_bit(HW_ARCOFI, &cs->HW_Flags))
107 return;
108 if (test_and_clear_bit(D_RX_MON1, &cs->event))
109 arcofi_fsm(cs, ARCOFI_RX_END, NULL);
110 if (test_and_clear_bit(D_TX_MON1, &cs->event))
111 arcofi_fsm(cs, ARCOFI_TX_END, NULL);
112#endif
113}
114
115void
116isac_empty_fifo(struct IsdnCardState *cs, int count)
117{
118 u_char *ptr;
119
120 if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
121 debugl1(cs, "isac_empty_fifo");
122
123 if ((cs->rcvidx + count) >= MAX_DFRAME_LEN_L1) {
124 if (cs->debug & L1_DEB_WARN)
125 debugl1(cs, "isac_empty_fifo overrun %d",
126 cs->rcvidx + count);
127 cs->writeisac(cs, ISAC_CMDR, 0x80);
128 cs->rcvidx = 0;
129 return;
130 }
131 ptr = cs->rcvbuf + cs->rcvidx;
132 cs->rcvidx += count;
133 cs->readisacfifo(cs, ptr, count);
134 cs->writeisac(cs, ISAC_CMDR, 0x80);
135 if (cs->debug & L1_DEB_ISAC_FIFO) {
136 char *t = cs->dlog;
137
138 t += sprintf(t, "isac_empty_fifo cnt %d", count);
139 QuickHex(t, ptr, count);
140 debugl1(cs, cs->dlog);
141 }
142}
143
144static void
145isac_fill_fifo(struct IsdnCardState *cs)
146{
147 int count, more;
148 u_char *ptr;
149
150 if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
151 debugl1(cs, "isac_fill_fifo");
152
153 if (!cs->tx_skb)
154 return;
155
156 count = cs->tx_skb->len;
157 if (count <= 0)
158 return;
159
160 more = 0;
161 if (count > 32) {
162 more = !0;
163 count = 32;
164 }
165 ptr = cs->tx_skb->data;
166 skb_pull(cs->tx_skb, count);
167 cs->tx_cnt += count;
168 cs->writeisacfifo(cs, ptr, count);
169 cs->writeisac(cs, ISAC_CMDR, more ? 0x8 : 0xa);
170 if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
171 debugl1(cs, "isac_fill_fifo dbusytimer running");
172 del_timer(&cs->dbusytimer);
173 }
174 init_timer(&cs->dbusytimer);
175 cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000);
176 add_timer(&cs->dbusytimer);
177 if (cs->debug & L1_DEB_ISAC_FIFO) {
178 char *t = cs->dlog;
179
180 t += sprintf(t, "isac_fill_fifo cnt %d", count);
181 QuickHex(t, ptr, count);
182 debugl1(cs, cs->dlog);
183 }
184}
185
186void
187isac_interrupt(struct IsdnCardState *cs, u_char val)
188{
189 u_char exval, v1;
190 struct sk_buff *skb;
191 unsigned int count;
192
193 if (cs->debug & L1_DEB_ISAC)
194 debugl1(cs, "ISAC interrupt %x", val);
195 if (val & 0x80) { /* RME */
196 exval = cs->readisac(cs, ISAC_RSTA);
197 if ((exval & 0x70) != 0x20) {
198 if (exval & 0x40) {
199 if (cs->debug & L1_DEB_WARN)
200 debugl1(cs, "ISAC RDO");
201#ifdef ERROR_STATISTIC
202 cs->err_rx++;
203#endif
204 }
205 if (!(exval & 0x20)) {
206 if (cs->debug & L1_DEB_WARN)
207 debugl1(cs, "ISAC CRC error");
208#ifdef ERROR_STATISTIC
209 cs->err_crc++;
210#endif
211 }
212 cs->writeisac(cs, ISAC_CMDR, 0x80);
213 } else {
214 count = cs->readisac(cs, ISAC_RBCL) & 0x1f;
215 if (count == 0)
216 count = 32;
217 isac_empty_fifo(cs, count);
218 if ((count = cs->rcvidx) > 0) {
219 cs->rcvidx = 0;
220 if (!(skb = alloc_skb(count, GFP_ATOMIC)))
221 printk(KERN_WARNING "HiSax: D receive out of memory\n");
222 else {
223 memcpy(skb_put(skb, count), cs->rcvbuf, count);
224 skb_queue_tail(&cs->rq, skb);
225 }
226 }
227 }
228 cs->rcvidx = 0;
229 schedule_event(cs, D_RCVBUFREADY);
230 }
231 if (val & 0x40) { /* RPF */
232 isac_empty_fifo(cs, 32);
233 }
234 if (val & 0x20) { /* RSC */
235 /* never */
236 if (cs->debug & L1_DEB_WARN)
237 debugl1(cs, "ISAC RSC interrupt");
238 }
239 if (val & 0x10) { /* XPR */
240 if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
241 del_timer(&cs->dbusytimer);
242 if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
243 schedule_event(cs, D_CLEARBUSY);
244 if (cs->tx_skb) {
245 if (cs->tx_skb->len) {
246 isac_fill_fifo(cs);
247 goto afterXPR;
248 } else {
249 dev_kfree_skb_irq(cs->tx_skb);
250 cs->tx_cnt = 0;
251 cs->tx_skb = NULL;
252 }
253 }
254 if ((cs->tx_skb = skb_dequeue(&cs->sq))) {
255 cs->tx_cnt = 0;
256 isac_fill_fifo(cs);
257 } else
258 schedule_event(cs, D_XMTBUFREADY);
259 }
260 afterXPR:
261 if (val & 0x04) { /* CISQ */
262 exval = cs->readisac(cs, ISAC_CIR0);
263 if (cs->debug & L1_DEB_ISAC)
264 debugl1(cs, "ISAC CIR0 %02X", exval );
265 if (exval & 2) {
266 cs->dc.isac.ph_state = (exval >> 2) & 0xf;
267 if (cs->debug & L1_DEB_ISAC)
268 debugl1(cs, "ph_state change %x", cs->dc.isac.ph_state);
269 schedule_event(cs, D_L1STATECHANGE);
270 }
271 if (exval & 1) {
272 exval = cs->readisac(cs, ISAC_CIR1);
273 if (cs->debug & L1_DEB_ISAC)
274 debugl1(cs, "ISAC CIR1 %02X", exval );
275 }
276 }
277 if (val & 0x02) { /* SIN */
278 /* never */
279 if (cs->debug & L1_DEB_WARN)
280 debugl1(cs, "ISAC SIN interrupt");
281 }
282 if (val & 0x01) { /* EXI */
283 exval = cs->readisac(cs, ISAC_EXIR);
284 if (cs->debug & L1_DEB_WARN)
285 debugl1(cs, "ISAC EXIR %02x", exval);
286 if (exval & 0x80) { /* XMR */
287 debugl1(cs, "ISAC XMR");
288 printk(KERN_WARNING "HiSax: ISAC XMR\n");
289 }
290 if (exval & 0x40) { /* XDU */
291 debugl1(cs, "ISAC XDU");
292 printk(KERN_WARNING "HiSax: ISAC XDU\n");
293#ifdef ERROR_STATISTIC
294 cs->err_tx++;
295#endif
296 if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
297 del_timer(&cs->dbusytimer);
298 if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
299 schedule_event(cs, D_CLEARBUSY);
300 if (cs->tx_skb) { /* Restart frame */
301 skb_push(cs->tx_skb, cs->tx_cnt);
302 cs->tx_cnt = 0;
303 isac_fill_fifo(cs);
304 } else {
305 printk(KERN_WARNING "HiSax: ISAC XDU no skb\n");
306 debugl1(cs, "ISAC XDU no skb");
307 }
308 }
309 if (exval & 0x04) { /* MOS */
310 v1 = cs->readisac(cs, ISAC_MOSR);
311 if (cs->debug & L1_DEB_MONITOR)
312 debugl1(cs, "ISAC MOSR %02x", v1);
313#if ARCOFI_USE
314 if (v1 & 0x08) {
315 if (!cs->dc.isac.mon_rx) {
316 if (!(cs->dc.isac.mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) {
317 if (cs->debug & L1_DEB_WARN)
318 debugl1(cs, "ISAC MON RX out of memory!");
319 cs->dc.isac.mocr &= 0xf0;
320 cs->dc.isac.mocr |= 0x0a;
321 cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
322 goto afterMONR0;
323 } else
324 cs->dc.isac.mon_rxp = 0;
325 }
326 if (cs->dc.isac.mon_rxp >= MAX_MON_FRAME) {
327 cs->dc.isac.mocr &= 0xf0;
328 cs->dc.isac.mocr |= 0x0a;
329 cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
330 cs->dc.isac.mon_rxp = 0;
331 if (cs->debug & L1_DEB_WARN)
332 debugl1(cs, "ISAC MON RX overflow!");
333 goto afterMONR0;
334 }
335 cs->dc.isac.mon_rx[cs->dc.isac.mon_rxp++] = cs->readisac(cs, ISAC_MOR0);
336 if (cs->debug & L1_DEB_MONITOR)
337 debugl1(cs, "ISAC MOR0 %02x", cs->dc.isac.mon_rx[cs->dc.isac.mon_rxp -1]);
338 if (cs->dc.isac.mon_rxp == 1) {
339 cs->dc.isac.mocr |= 0x04;
340 cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
341 }
342 }
343 afterMONR0:
344 if (v1 & 0x80) {
345 if (!cs->dc.isac.mon_rx) {
346 if (!(cs->dc.isac.mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) {
347 if (cs->debug & L1_DEB_WARN)
348 debugl1(cs, "ISAC MON RX out of memory!");
349 cs->dc.isac.mocr &= 0x0f;
350 cs->dc.isac.mocr |= 0xa0;
351 cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
352 goto afterMONR1;
353 } else
354 cs->dc.isac.mon_rxp = 0;
355 }
356 if (cs->dc.isac.mon_rxp >= MAX_MON_FRAME) {
357 cs->dc.isac.mocr &= 0x0f;
358 cs->dc.isac.mocr |= 0xa0;
359 cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
360 cs->dc.isac.mon_rxp = 0;
361 if (cs->debug & L1_DEB_WARN)
362 debugl1(cs, "ISAC MON RX overflow!");
363 goto afterMONR1;
364 }
365 cs->dc.isac.mon_rx[cs->dc.isac.mon_rxp++] = cs->readisac(cs, ISAC_MOR1);
366 if (cs->debug & L1_DEB_MONITOR)
367 debugl1(cs, "ISAC MOR1 %02x", cs->dc.isac.mon_rx[cs->dc.isac.mon_rxp -1]);
368 cs->dc.isac.mocr |= 0x40;
369 cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
370 }
371 afterMONR1:
372 if (v1 & 0x04) {
373 cs->dc.isac.mocr &= 0xf0;
374 cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
375 cs->dc.isac.mocr |= 0x0a;
376 cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
377 schedule_event(cs, D_RX_MON0);
378 }
379 if (v1 & 0x40) {
380 cs->dc.isac.mocr &= 0x0f;
381 cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
382 cs->dc.isac.mocr |= 0xa0;
383 cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
384 schedule_event(cs, D_RX_MON1);
385 }
386 if (v1 & 0x02) {
387 if ((!cs->dc.isac.mon_tx) || (cs->dc.isac.mon_txc &&
388 (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc) &&
389 !(v1 & 0x08))) {
390 cs->dc.isac.mocr &= 0xf0;
391 cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
392 cs->dc.isac.mocr |= 0x0a;
393 cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
394 if (cs->dc.isac.mon_txc &&
395 (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc))
396 schedule_event(cs, D_TX_MON0);
397 goto AfterMOX0;
398 }
399 if (cs->dc.isac.mon_txc && (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc)) {
400 schedule_event(cs, D_TX_MON0);
401 goto AfterMOX0;
402 }
403 cs->writeisac(cs, ISAC_MOX0,
404 cs->dc.isac.mon_tx[cs->dc.isac.mon_txp++]);
405 if (cs->debug & L1_DEB_MONITOR)
406 debugl1(cs, "ISAC %02x -> MOX0", cs->dc.isac.mon_tx[cs->dc.isac.mon_txp -1]);
407 }
408 AfterMOX0:
409 if (v1 & 0x20) {
410 if ((!cs->dc.isac.mon_tx) || (cs->dc.isac.mon_txc &&
411 (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc) &&
412 !(v1 & 0x80))) {
413 cs->dc.isac.mocr &= 0x0f;
414 cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
415 cs->dc.isac.mocr |= 0xa0;
416 cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
417 if (cs->dc.isac.mon_txc &&
418 (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc))
419 schedule_event(cs, D_TX_MON1);
420 goto AfterMOX1;
421 }
422 if (cs->dc.isac.mon_txc && (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc)) {
423 schedule_event(cs, D_TX_MON1);
424 goto AfterMOX1;
425 }
426 cs->writeisac(cs, ISAC_MOX1,
427 cs->dc.isac.mon_tx[cs->dc.isac.mon_txp++]);
428 if (cs->debug & L1_DEB_MONITOR)
429 debugl1(cs, "ISAC %02x -> MOX1", cs->dc.isac.mon_tx[cs->dc.isac.mon_txp -1]);
430 }
431 AfterMOX1:;
432#endif
433 }
434 }
435}
436
437static void
438ISAC_l1hw(struct PStack *st, int pr, void *arg)
439{
440 struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
441 struct sk_buff *skb = arg;
442 u_long flags;
443 int val;
444
445 switch (pr) {
446 case (PH_DATA |REQUEST):
447 if (cs->debug & DEB_DLOG_HEX)
448 LogFrame(cs, skb->data, skb->len);
449 if (cs->debug & DEB_DLOG_VERBOSE)
450 dlogframe(cs, skb, 0);
451 spin_lock_irqsave(&cs->lock, flags);
452 if (cs->tx_skb) {
453 skb_queue_tail(&cs->sq, skb);
454#ifdef L2FRAME_DEBUG /* psa */
455 if (cs->debug & L1_DEB_LAPD)
456 Logl2Frame(cs, skb, "PH_DATA Queued", 0);
457#endif
458 } else {
459 cs->tx_skb = skb;
460 cs->tx_cnt = 0;
461#ifdef L2FRAME_DEBUG /* psa */
462 if (cs->debug & L1_DEB_LAPD)
463 Logl2Frame(cs, skb, "PH_DATA", 0);
464#endif
465 isac_fill_fifo(cs);
466 }
467 spin_unlock_irqrestore(&cs->lock, flags);
468 break;
469 case (PH_PULL |INDICATION):
470 spin_lock_irqsave(&cs->lock, flags);
471 if (cs->tx_skb) {
472 if (cs->debug & L1_DEB_WARN)
473 debugl1(cs, " l2l1 tx_skb exist this shouldn't happen");
474 skb_queue_tail(&cs->sq, skb);
475 } else {
476 if (cs->debug & DEB_DLOG_HEX)
477 LogFrame(cs, skb->data, skb->len);
478 if (cs->debug & DEB_DLOG_VERBOSE)
479 dlogframe(cs, skb, 0);
480 cs->tx_skb = skb;
481 cs->tx_cnt = 0;
482#ifdef L2FRAME_DEBUG /* psa */
483 if (cs->debug & L1_DEB_LAPD)
484 Logl2Frame(cs, skb, "PH_DATA_PULLED", 0);
485#endif
486 isac_fill_fifo(cs);
487 }
488 spin_unlock_irqrestore(&cs->lock, flags);
489 break;
490 case (PH_PULL | REQUEST):
491#ifdef L2FRAME_DEBUG /* psa */
492 if (cs->debug & L1_DEB_LAPD)
493 debugl1(cs, "-> PH_REQUEST_PULL");
494#endif
495 if (!cs->tx_skb) {
496 test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
497 st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
498 } else
499 test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
500 break;
501 case (HW_RESET | REQUEST):
502 spin_lock_irqsave(&cs->lock, flags);
503 if ((cs->dc.isac.ph_state == ISAC_IND_EI) ||
504 (cs->dc.isac.ph_state == ISAC_IND_DR) ||
505 (cs->dc.isac.ph_state == ISAC_IND_RS))
506 ph_command(cs, ISAC_CMD_TIM);
507 else
508 ph_command(cs, ISAC_CMD_RS);
509 spin_unlock_irqrestore(&cs->lock, flags);
510 break;
511 case (HW_ENABLE | REQUEST):
512 spin_lock_irqsave(&cs->lock, flags);
513 ph_command(cs, ISAC_CMD_TIM);
514 spin_unlock_irqrestore(&cs->lock, flags);
515 break;
516 case (HW_INFO3 | REQUEST):
517 spin_lock_irqsave(&cs->lock, flags);
518 ph_command(cs, ISAC_CMD_AR8);
519 spin_unlock_irqrestore(&cs->lock, flags);
520 break;
521 case (HW_TESTLOOP | REQUEST):
522 spin_lock_irqsave(&cs->lock, flags);
523 val = 0;
524 if (1 & (long) arg)
525 val |= 0x0c;
526 if (2 & (long) arg)
527 val |= 0x3;
528 if (test_bit(HW_IOM1, &cs->HW_Flags)) {
529 /* IOM 1 Mode */
530 if (!val) {
531 cs->writeisac(cs, ISAC_SPCR, 0xa);
532 cs->writeisac(cs, ISAC_ADF1, 0x2);
533 } else {
534 cs->writeisac(cs, ISAC_SPCR, val);
535 cs->writeisac(cs, ISAC_ADF1, 0xa);
536 }
537 } else {
538 /* IOM 2 Mode */
539 cs->writeisac(cs, ISAC_SPCR, val);
540 if (val)
541 cs->writeisac(cs, ISAC_ADF1, 0x8);
542 else
543 cs->writeisac(cs, ISAC_ADF1, 0x0);
544 }
545 spin_unlock_irqrestore(&cs->lock, flags);
546 break;
547 case (HW_DEACTIVATE | RESPONSE):
548 skb_queue_purge(&cs->rq);
549 skb_queue_purge(&cs->sq);
550 if (cs->tx_skb) {
551 dev_kfree_skb_any(cs->tx_skb);
552 cs->tx_skb = NULL;
553 }
554 if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
555 del_timer(&cs->dbusytimer);
556 if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
557 schedule_event(cs, D_CLEARBUSY);
558 break;
559 default:
560 if (cs->debug & L1_DEB_WARN)
561 debugl1(cs, "isac_l1hw unknown %04x", pr);
562 break;
563 }
564}
565
566void
567setstack_isac(struct PStack *st, struct IsdnCardState *cs)
568{
569 st->l1.l1hw = ISAC_l1hw;
570}
571
572void
573DC_Close_isac(struct IsdnCardState *cs) {
574 if (cs->dc.isac.mon_rx) {
575 kfree(cs->dc.isac.mon_rx);
576 cs->dc.isac.mon_rx = NULL;
577 }
578 if (cs->dc.isac.mon_tx) {
579 kfree(cs->dc.isac.mon_tx);
580 cs->dc.isac.mon_tx = NULL;
581 }
582}
583
584static void
585dbusy_timer_handler(struct IsdnCardState *cs)
586{
587 struct PStack *stptr;
588 int rbch, star;
589
590 if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
591 rbch = cs->readisac(cs, ISAC_RBCH);
592 star = cs->readisac(cs, ISAC_STAR);
593 if (cs->debug)
594 debugl1(cs, "D-Channel Busy RBCH %02x STAR %02x",
595 rbch, star);
596 if (rbch & ISAC_RBCH_XAC) { /* D-Channel Busy */
597 test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags);
598 stptr = cs->stlist;
599 while (stptr != NULL) {
600 stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL);
601 stptr = stptr->next;
602 }
603 } else {
604 /* discard frame; reset transceiver */
605 test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags);
606 if (cs->tx_skb) {
607 dev_kfree_skb_any(cs->tx_skb);
608 cs->tx_cnt = 0;
609 cs->tx_skb = NULL;
610 } else {
611 printk(KERN_WARNING "HiSax: ISAC D-Channel Busy no skb\n");
612 debugl1(cs, "D-Channel Busy no skb");
613 }
614 cs->writeisac(cs, ISAC_CMDR, 0x01); /* Transmitter reset */
615 cs->irq_func(cs->irq, cs, NULL);
616 }
617 }
618}
619
620void __devinit
621initisac(struct IsdnCardState *cs)
622{
623 cs->setstack_d = setstack_isac;
624 cs->DC_Close = DC_Close_isac;
625 cs->dc.isac.mon_tx = NULL;
626 cs->dc.isac.mon_rx = NULL;
627 cs->writeisac(cs, ISAC_MASK, 0xff);
628 cs->dc.isac.mocr = 0xaa;
629 if (test_bit(HW_IOM1, &cs->HW_Flags)) {
630 /* IOM 1 Mode */
631 cs->writeisac(cs, ISAC_ADF2, 0x0);
632 cs->writeisac(cs, ISAC_SPCR, 0xa);
633 cs->writeisac(cs, ISAC_ADF1, 0x2);
634 cs->writeisac(cs, ISAC_STCR, 0x70);
635 cs->writeisac(cs, ISAC_MODE, 0xc9);
636 } else {
637 /* IOM 2 Mode */
638 if (!cs->dc.isac.adf2)
639 cs->dc.isac.adf2 = 0x80;
640 cs->writeisac(cs, ISAC_ADF2, cs->dc.isac.adf2);
641 cs->writeisac(cs, ISAC_SQXR, 0x2f);
642 cs->writeisac(cs, ISAC_SPCR, 0x00);
643 cs->writeisac(cs, ISAC_STCR, 0x70);
644 cs->writeisac(cs, ISAC_MODE, 0xc9);
645 cs->writeisac(cs, ISAC_TIMR, 0x00);
646 cs->writeisac(cs, ISAC_ADF1, 0x00);
647 }
648 ph_command(cs, ISAC_CMD_RS);
649 cs->writeisac(cs, ISAC_MASK, 0x0);
650}
651
652void __devinit
653clear_pending_isac_ints(struct IsdnCardState *cs)
654{
655 int val, eval;
656
657 val = cs->readisac(cs, ISAC_STAR);
658 debugl1(cs, "ISAC STAR %x", val);
659 val = cs->readisac(cs, ISAC_MODE);
660 debugl1(cs, "ISAC MODE %x", val);
661 val = cs->readisac(cs, ISAC_ADF2);
662 debugl1(cs, "ISAC ADF2 %x", val);
663 val = cs->readisac(cs, ISAC_ISTA);
664 debugl1(cs, "ISAC ISTA %x", val);
665 if (val & 0x01) {
666 eval = cs->readisac(cs, ISAC_EXIR);
667 debugl1(cs, "ISAC EXIR %x", eval);
668 }
669 val = cs->readisac(cs, ISAC_CIR0);
670 debugl1(cs, "ISAC CIR0 %x", val);
671 cs->dc.isac.ph_state = (val >> 2) & 0xf;
672 schedule_event(cs, D_L1STATECHANGE);
673 /* Disable all IRQ */
674 cs->writeisac(cs, ISAC_MASK, 0xFF);
675}
676
677void __devinit
678setup_isac(struct IsdnCardState *cs)
679{
680 INIT_WORK(&cs->tqueue, (void *)(void *) isac_bh, cs);
681 cs->dbusytimer.function = (void *) dbusy_timer_handler;
682 cs->dbusytimer.data = (long) cs;
683 init_timer(&cs->dbusytimer);
684}
diff --git a/drivers/isdn/hisax/isac.h b/drivers/isdn/hisax/isac.h
new file mode 100644
index 000000000000..8f8331e44866
--- /dev/null
+++ b/drivers/isdn/hisax/isac.h
@@ -0,0 +1,70 @@
1/* $Id: isac.h,v 1.9.2.2 2004/01/12 22:52:27 keil Exp $
2 *
3 * ISAC specific defines
4 *
5 * Author Karsten Keil
6 * Copyright by Karsten Keil <keil@isdn4linux.de>
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 */
12
13/* All Registers original Siemens Spec */
14
15#define ISAC_MASK 0x20
16#define ISAC_ISTA 0x20
17#define ISAC_STAR 0x21
18#define ISAC_CMDR 0x21
19#define ISAC_EXIR 0x24
20#define ISAC_ADF2 0x39
21#define ISAC_SPCR 0x30
22#define ISAC_ADF1 0x38
23#define ISAC_CIR0 0x31
24#define ISAC_CIX0 0x31
25#define ISAC_CIR1 0x33
26#define ISAC_CIX1 0x33
27#define ISAC_STCR 0x37
28#define ISAC_MODE 0x22
29#define ISAC_RSTA 0x27
30#define ISAC_RBCL 0x25
31#define ISAC_RBCH 0x2A
32#define ISAC_TIMR 0x23
33#define ISAC_SQXR 0x3b
34#define ISAC_MOSR 0x3a
35#define ISAC_MOCR 0x3a
36#define ISAC_MOR0 0x32
37#define ISAC_MOX0 0x32
38#define ISAC_MOR1 0x34
39#define ISAC_MOX1 0x34
40
41#define ISAC_RBCH_XAC 0x80
42
43#define ISAC_CMD_TIM 0x0
44#define ISAC_CMD_RS 0x1
45#define ISAC_CMD_SCZ 0x4
46#define ISAC_CMD_SSZ 0x2
47#define ISAC_CMD_AR8 0x8
48#define ISAC_CMD_AR10 0x9
49#define ISAC_CMD_ARL 0xA
50#define ISAC_CMD_DUI 0xF
51
52#define ISAC_IND_RS 0x1
53#define ISAC_IND_PU 0x7
54#define ISAC_IND_DR 0x0
55#define ISAC_IND_SD 0x2
56#define ISAC_IND_DIS 0x3
57#define ISAC_IND_EI 0x6
58#define ISAC_IND_RSY 0x4
59#define ISAC_IND_ARD 0x8
60#define ISAC_IND_TI 0xA
61#define ISAC_IND_ATI 0xB
62#define ISAC_IND_AI8 0xC
63#define ISAC_IND_AI10 0xD
64#define ISAC_IND_DID 0xF
65
66extern void ISACVersion(struct IsdnCardState *, char *);
67extern void setup_isac(struct IsdnCardState *);
68extern void initisac(struct IsdnCardState *);
69extern void isac_interrupt(struct IsdnCardState *, u_char);
70extern void clear_pending_isac_ints(struct IsdnCardState *);
diff --git a/drivers/isdn/hisax/isar.c b/drivers/isdn/hisax/isar.c
new file mode 100644
index 000000000000..ee081321efb2
--- /dev/null
+++ b/drivers/isdn/hisax/isar.c
@@ -0,0 +1,1909 @@
1/* $Id: isar.c,v 1.22.2.6 2004/02/11 13:21:34 keil Exp $
2 *
3 * isar.c ISAR (Siemens PSB 7110) specific routines
4 *
5 * Author Karsten Keil (keil@isdn4linux.de)
6 *
7 * This file is (c) under GNU General Public License
8 *
9 */
10
11#include <linux/init.h>
12#include "hisax.h"
13#include "isar.h"
14#include "isdnl1.h"
15#include <linux/interrupt.h>
16
17#define DBG_LOADFIRM 0
18#define DUMP_MBOXFRAME 2
19
20#define DLE 0x10
21#define ETX 0x03
22
23#define FAXMODCNT 13
24const u_char faxmodulation[] = {3,24,48,72,73,74,96,97,98,121,122,145,146};
25static u_int modmask = 0x1fff;
26static int frm_extra_delay = 2;
27static int para_TOA = 6;
28const u_char *FC1_CMD[] = {"FAE", "FTS", "FRS", "FTM", "FRM", "FTH", "FRH", "CTRL" };
29
30void isar_setup(struct IsdnCardState *cs);
31static void isar_pump_cmd(struct BCState *bcs, u_char cmd, u_char para);
32static void ll_deliver_faxstat(struct BCState *bcs, u_char status);
33
34static inline int
35waitforHIA(struct IsdnCardState *cs, int timeout)
36{
37
38 while ((cs->BC_Read_Reg(cs, 0, ISAR_HIA) & 1) && timeout) {
39 udelay(1);
40 timeout--;
41 }
42 if (!timeout)
43 printk(KERN_WARNING "HiSax: ISAR waitforHIA timeout\n");
44 return(timeout);
45}
46
47
48int
49sendmsg(struct IsdnCardState *cs, u_char his, u_char creg, u_char len,
50 u_char *msg)
51{
52 int i;
53
54 if (!waitforHIA(cs, 4000))
55 return(0);
56#if DUMP_MBOXFRAME
57 if (cs->debug & L1_DEB_HSCX)
58 debugl1(cs, "sendmsg(%02x,%02x,%d)", his, creg, len);
59#endif
60 cs->BC_Write_Reg(cs, 0, ISAR_CTRL_H, creg);
61 cs->BC_Write_Reg(cs, 0, ISAR_CTRL_L, len);
62 cs->BC_Write_Reg(cs, 0, ISAR_WADR, 0);
63 if (msg && len) {
64 cs->BC_Write_Reg(cs, 1, ISAR_MBOX, msg[0]);
65 for (i=1; i<len; i++)
66 cs->BC_Write_Reg(cs, 2, ISAR_MBOX, msg[i]);
67#if DUMP_MBOXFRAME>1
68 if (cs->debug & L1_DEB_HSCX_FIFO) {
69 char tmp[256], *t;
70
71 i = len;
72 while (i>0) {
73 t = tmp;
74 t += sprintf(t, "sendmbox cnt %d", len);
75 QuickHex(t, &msg[len-i], (i>64) ? 64:i);
76 debugl1(cs, tmp);
77 i -= 64;
78 }
79 }
80#endif
81 }
82 cs->BC_Write_Reg(cs, 1, ISAR_HIS, his);
83 waitforHIA(cs, 10000);
84 return(1);
85}
86
87/* Call only with IRQ disabled !!! */
88inline void
89rcv_mbox(struct IsdnCardState *cs, struct isar_reg *ireg, u_char *msg)
90{
91 int i;
92
93 cs->BC_Write_Reg(cs, 1, ISAR_RADR, 0);
94 if (msg && ireg->clsb) {
95 msg[0] = cs->BC_Read_Reg(cs, 1, ISAR_MBOX);
96 for (i=1; i < ireg->clsb; i++)
97 msg[i] = cs->BC_Read_Reg(cs, 2, ISAR_MBOX);
98#if DUMP_MBOXFRAME>1
99 if (cs->debug & L1_DEB_HSCX_FIFO) {
100 char tmp[256], *t;
101
102 i = ireg->clsb;
103 while (i>0) {
104 t = tmp;
105 t += sprintf(t, "rcv_mbox cnt %d", ireg->clsb);
106 QuickHex(t, &msg[ireg->clsb-i], (i>64) ? 64:i);
107 debugl1(cs, tmp);
108 i -= 64;
109 }
110 }
111#endif
112 }
113 cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
114}
115
116/* Call only with IRQ disabled !!! */
117inline void
118get_irq_infos(struct IsdnCardState *cs, struct isar_reg *ireg)
119{
120 ireg->iis = cs->BC_Read_Reg(cs, 1, ISAR_IIS);
121 ireg->cmsb = cs->BC_Read_Reg(cs, 1, ISAR_CTRL_H);
122 ireg->clsb = cs->BC_Read_Reg(cs, 1, ISAR_CTRL_L);
123#if DUMP_MBOXFRAME
124 if (cs->debug & L1_DEB_HSCX)
125 debugl1(cs, "irq_stat(%02x,%02x,%d)", ireg->iis, ireg->cmsb,
126 ireg->clsb);
127#endif
128}
129
130int
131waitrecmsg(struct IsdnCardState *cs, u_char *len,
132 u_char *msg, int maxdelay)
133{
134 int timeout = 0;
135 struct isar_reg *ir = cs->bcs[0].hw.isar.reg;
136
137
138 while((!(cs->BC_Read_Reg(cs, 0, ISAR_IRQBIT) & ISAR_IRQSTA)) &&
139 (timeout++ < maxdelay))
140 udelay(1);
141 if (timeout >= maxdelay) {
142 printk(KERN_WARNING"isar recmsg IRQSTA timeout\n");
143 return(0);
144 }
145 get_irq_infos(cs, ir);
146 rcv_mbox(cs, ir, msg);
147 *len = ir->clsb;
148 return(1);
149}
150
151int
152ISARVersion(struct IsdnCardState *cs, char *s)
153{
154 int ver;
155 u_char msg[] = ISAR_MSG_HWVER;
156 u_char tmp[64];
157 u_char len;
158 u_long flags;
159 int debug;
160
161 cs->cardmsg(cs, CARD_RESET, NULL);
162 spin_lock_irqsave(&cs->lock, flags);
163 /* disable ISAR IRQ */
164 cs->BC_Write_Reg(cs, 0, ISAR_IRQBIT, 0);
165 debug = cs->debug;
166 cs->debug &= ~(L1_DEB_HSCX | L1_DEB_HSCX_FIFO);
167 if (!sendmsg(cs, ISAR_HIS_VNR, 0, 3, msg)) {
168 spin_unlock_irqrestore(&cs->lock, flags);
169 return(-1);
170 }
171 if (!waitrecmsg(cs, &len, tmp, 100000)) {
172 spin_unlock_irqrestore(&cs->lock, flags);
173 return(-2);
174 }
175 cs->debug = debug;
176 if (cs->bcs[0].hw.isar.reg->iis == ISAR_IIS_VNR) {
177 if (len == 1) {
178 ver = tmp[0] & 0xf;
179 printk(KERN_INFO "%s ISAR version %d\n", s, ver);
180 } else
181 ver = -3;
182 } else
183 ver = -4;
184 spin_unlock_irqrestore(&cs->lock, flags);
185 return(ver);
186}
187
188int
189isar_load_firmware(struct IsdnCardState *cs, u_char __user *buf)
190{
191 int ret, size, cnt, debug;
192 u_char len, nom, noc;
193 u_short sadr, left, *sp;
194 u_char __user *p = buf;
195 u_char *msg, *tmpmsg, *mp, tmp[64];
196 u_long flags;
197 struct isar_reg *ireg = cs->bcs[0].hw.isar.reg;
198
199 struct {u_short sadr;
200 u_short len;
201 u_short d_key;
202 } blk_head;
203
204#define BLK_HEAD_SIZE 6
205 if (1 != (ret = ISARVersion(cs, "Testing"))) {
206 printk(KERN_ERR"isar_load_firmware wrong isar version %d\n", ret);
207 return(1);
208 }
209 debug = cs->debug;
210#if DBG_LOADFIRM<2
211 cs->debug &= ~(L1_DEB_HSCX | L1_DEB_HSCX_FIFO);
212#endif
213
214 if ((ret = copy_from_user(&size, p, sizeof(int)))) {
215 printk(KERN_ERR"isar_load_firmware copy_from_user ret %d\n", ret);
216 return ret;
217 }
218 p += sizeof(int);
219 printk(KERN_DEBUG"isar_load_firmware size: %d\n", size);
220 cnt = 0;
221 /* disable ISAR IRQ */
222 cs->BC_Write_Reg(cs, 0, ISAR_IRQBIT, 0);
223 if (!(msg = kmalloc(256, GFP_KERNEL))) {
224 printk(KERN_ERR"isar_load_firmware no buffer\n");
225 return (1);
226 }
227 if (!(tmpmsg = kmalloc(256, GFP_KERNEL))) {
228 printk(KERN_ERR"isar_load_firmware no tmp buffer\n");
229 kfree(msg);
230 return (1);
231 }
232 spin_lock_irqsave(&cs->lock, flags);
233 /* disable ISAR IRQ */
234 cs->BC_Write_Reg(cs, 0, ISAR_IRQBIT, 0);
235 spin_unlock_irqrestore(&cs->lock, flags);
236 while (cnt < size) {
237 if ((ret = copy_from_user(&blk_head, p, BLK_HEAD_SIZE))) {
238 printk(KERN_ERR"isar_load_firmware copy_from_user ret %d\n", ret);
239 goto reterror;
240 }
241#ifdef __BIG_ENDIAN
242 sadr = (blk_head.sadr & 0xff)*256 + blk_head.sadr/256;
243 blk_head.sadr = sadr;
244 sadr = (blk_head.len & 0xff)*256 + blk_head.len/256;
245 blk_head.len = sadr;
246 sadr = (blk_head.d_key & 0xff)*256 + blk_head.d_key/256;
247 blk_head.d_key = sadr;
248#endif /* __BIG_ENDIAN */
249 cnt += BLK_HEAD_SIZE;
250 p += BLK_HEAD_SIZE;
251 printk(KERN_DEBUG"isar firmware block (%#x,%5d,%#x)\n",
252 blk_head.sadr, blk_head.len, blk_head.d_key & 0xff);
253 sadr = blk_head.sadr;
254 left = blk_head.len;
255 spin_lock_irqsave(&cs->lock, flags);
256 if (!sendmsg(cs, ISAR_HIS_DKEY, blk_head.d_key & 0xff, 0, NULL)) {
257 printk(KERN_ERR"isar sendmsg dkey failed\n");
258 ret = 1;goto reterr_unlock;
259 }
260 if (!waitrecmsg(cs, &len, tmp, 100000)) {
261 printk(KERN_ERR"isar waitrecmsg dkey failed\n");
262 ret = 1;goto reterr_unlock;
263 }
264 if ((ireg->iis != ISAR_IIS_DKEY) || ireg->cmsb || len) {
265 printk(KERN_ERR"isar wrong dkey response (%x,%x,%x)\n",
266 ireg->iis, ireg->cmsb, len);
267 ret = 1;goto reterr_unlock;
268 }
269 spin_unlock_irqrestore(&cs->lock, flags);
270 while (left>0) {
271 if (left > 126)
272 noc = 126;
273 else
274 noc = left;
275 nom = 2*noc;
276 mp = msg;
277 *mp++ = sadr / 256;
278 *mp++ = sadr % 256;
279 left -= noc;
280 *mp++ = noc;
281 if ((ret = copy_from_user(tmpmsg, p, nom))) {
282 printk(KERN_ERR"isar_load_firmware copy_from_user ret %d\n", ret);
283 goto reterror;
284 }
285 p += nom;
286 cnt += nom;
287 nom += 3;
288 sp = (u_short *)tmpmsg;
289#if DBG_LOADFIRM
290 printk(KERN_DEBUG"isar: load %3d words at %04x left %d\n",
291 noc, sadr, left);
292#endif
293 sadr += noc;
294 while(noc) {
295#ifdef __BIG_ENDIAN
296 *mp++ = *sp % 256;
297 *mp++ = *sp / 256;
298#else
299 *mp++ = *sp / 256;
300 *mp++ = *sp % 256;
301#endif /* __BIG_ENDIAN */
302 sp++;
303 noc--;
304 }
305 spin_lock_irqsave(&cs->lock, flags);
306 if (!sendmsg(cs, ISAR_HIS_FIRM, 0, nom, msg)) {
307 printk(KERN_ERR"isar sendmsg prog failed\n");
308 ret = 1;goto reterr_unlock;
309 }
310 if (!waitrecmsg(cs, &len, tmp, 100000)) {
311 printk(KERN_ERR"isar waitrecmsg prog failed\n");
312 ret = 1;goto reterr_unlock;
313 }
314 if ((ireg->iis != ISAR_IIS_FIRM) || ireg->cmsb || len) {
315 printk(KERN_ERR"isar wrong prog response (%x,%x,%x)\n",
316 ireg->iis, ireg->cmsb, len);
317 ret = 1;goto reterr_unlock;
318 }
319 spin_unlock_irqrestore(&cs->lock, flags);
320 }
321 printk(KERN_DEBUG"isar firmware block %5d words loaded\n",
322 blk_head.len);
323 }
324 /* 10ms delay */
325 cnt = 10;
326 while (cnt--)
327 udelay(1000);
328 msg[0] = 0xff;
329 msg[1] = 0xfe;
330 ireg->bstat = 0;
331 spin_lock_irqsave(&cs->lock, flags);
332 if (!sendmsg(cs, ISAR_HIS_STDSP, 0, 2, msg)) {
333 printk(KERN_ERR"isar sendmsg start dsp failed\n");
334 ret = 1;goto reterr_unlock;
335 }
336 if (!waitrecmsg(cs, &len, tmp, 100000)) {
337 printk(KERN_ERR"isar waitrecmsg start dsp failed\n");
338 ret = 1;goto reterr_unlock;
339 }
340 if ((ireg->iis != ISAR_IIS_STDSP) || ireg->cmsb || len) {
341 printk(KERN_ERR"isar wrong start dsp response (%x,%x,%x)\n",
342 ireg->iis, ireg->cmsb, len);
343 ret = 1;goto reterr_unlock;
344 } else
345 printk(KERN_DEBUG"isar start dsp success\n");
346 /* NORMAL mode entered */
347 /* Enable IRQs of ISAR */
348 cs->BC_Write_Reg(cs, 0, ISAR_IRQBIT, ISAR_IRQSTA);
349 spin_unlock_irqrestore(&cs->lock, flags);
350 cnt = 1000; /* max 1s */
351 while ((!ireg->bstat) && cnt) {
352 udelay(1000);
353 cnt--;
354 }
355 if (!cnt) {
356 printk(KERN_ERR"isar no general status event received\n");
357 ret = 1;goto reterror;
358 } else {
359 printk(KERN_DEBUG"isar general status event %x\n",
360 ireg->bstat);
361 }
362 /* 10ms delay */
363 cnt = 10;
364 while (cnt--)
365 udelay(1000);
366 spin_lock_irqsave(&cs->lock, flags);
367 ireg->iis = 0;
368 if (!sendmsg(cs, ISAR_HIS_DIAG, ISAR_CTRL_STST, 0, NULL)) {
369 printk(KERN_ERR"isar sendmsg self tst failed\n");
370 ret = 1;goto reterr_unlock;
371 }
372 cnt = 10000; /* max 100 ms */
373 spin_unlock_irqrestore(&cs->lock, flags);
374 while ((ireg->iis != ISAR_IIS_DIAG) && cnt) {
375 udelay(10);
376 cnt--;
377 }
378 udelay(1000);
379 if (!cnt) {
380 printk(KERN_ERR"isar no self tst response\n");
381 ret = 1;goto reterror;
382 }
383 if ((ireg->cmsb == ISAR_CTRL_STST) && (ireg->clsb == 1)
384 && (ireg->par[0] == 0)) {
385 printk(KERN_DEBUG"isar selftest OK\n");
386 } else {
387 printk(KERN_DEBUG"isar selftest not OK %x/%x/%x\n",
388 ireg->cmsb, ireg->clsb, ireg->par[0]);
389 ret = 1;goto reterror;
390 }
391 spin_lock_irqsave(&cs->lock, flags);
392 ireg->iis = 0;
393 if (!sendmsg(cs, ISAR_HIS_DIAG, ISAR_CTRL_SWVER, 0, NULL)) {
394 printk(KERN_ERR"isar RQST SVN failed\n");
395 ret = 1;goto reterr_unlock;
396 }
397 spin_unlock_irqrestore(&cs->lock, flags);
398 cnt = 30000; /* max 300 ms */
399 while ((ireg->iis != ISAR_IIS_DIAG) && cnt) {
400 udelay(10);
401 cnt--;
402 }
403 udelay(1000);
404 if (!cnt) {
405 printk(KERN_ERR"isar no SVN response\n");
406 ret = 1;goto reterror;
407 } else {
408 if ((ireg->cmsb == ISAR_CTRL_SWVER) && (ireg->clsb == 1))
409 printk(KERN_DEBUG"isar software version %#x\n",
410 ireg->par[0]);
411 else {
412 printk(KERN_ERR"isar wrong swver response (%x,%x) cnt(%d)\n",
413 ireg->cmsb, ireg->clsb, cnt);
414 ret = 1;goto reterror;
415 }
416 }
417 spin_lock_irqsave(&cs->lock, flags);
418 cs->debug = debug;
419 isar_setup(cs);
420
421 ret = 0;
422reterr_unlock:
423 spin_unlock_irqrestore(&cs->lock, flags);
424reterror:
425 cs->debug = debug;
426 if (ret)
427 /* disable ISAR IRQ */
428 cs->BC_Write_Reg(cs, 0, ISAR_IRQBIT, 0);
429 kfree(msg);
430 kfree(tmpmsg);
431 return(ret);
432}
433
434extern void BChannel_bh(struct BCState *);
435#define B_LL_NOCARRIER 8
436#define B_LL_CONNECT 9
437#define B_LL_OK 10
438
439static void
440isar_bh(struct BCState *bcs)
441{
442 BChannel_bh(bcs);
443 if (test_and_clear_bit(B_LL_NOCARRIER, &bcs->event))
444 ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_NOCARR);
445 if (test_and_clear_bit(B_LL_CONNECT, &bcs->event))
446 ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_CONNECT);
447 if (test_and_clear_bit(B_LL_OK, &bcs->event))
448 ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_OK);
449}
450
451static void
452send_DLE_ETX(struct BCState *bcs)
453{
454 u_char dleetx[2] = {DLE,ETX};
455 struct sk_buff *skb;
456
457 if ((skb = dev_alloc_skb(2))) {
458 memcpy(skb_put(skb, 2), dleetx, 2);
459 skb_queue_tail(&bcs->rqueue, skb);
460 schedule_event(bcs, B_RCVBUFREADY);
461 } else {
462 printk(KERN_WARNING "HiSax: skb out of memory\n");
463 }
464}
465
466static inline int
467dle_count(unsigned char *buf, int len)
468{
469 int count = 0;
470
471 while (len--)
472 if (*buf++ == DLE)
473 count++;
474 return count;
475}
476
477static inline void
478insert_dle(unsigned char *dest, unsigned char *src, int count) {
479 /* <DLE> in input stream have to be flagged as <DLE><DLE> */
480 while (count--) {
481 *dest++ = *src;
482 if (*src++ == DLE)
483 *dest++ = DLE;
484 }
485}
486
487static void
488isar_rcv_frame(struct IsdnCardState *cs, struct BCState *bcs)
489{
490 u_char *ptr;
491 struct sk_buff *skb;
492 struct isar_reg *ireg = bcs->hw.isar.reg;
493
494 if (!ireg->clsb) {
495 debugl1(cs, "isar zero len frame");
496 cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
497 return;
498 }
499 switch (bcs->mode) {
500 case L1_MODE_NULL:
501 debugl1(cs, "isar mode 0 spurious IIS_RDATA %x/%x/%x",
502 ireg->iis, ireg->cmsb, ireg->clsb);
503 printk(KERN_WARNING"isar mode 0 spurious IIS_RDATA %x/%x/%x\n",
504 ireg->iis, ireg->cmsb, ireg->clsb);
505 cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
506 break;
507 case L1_MODE_TRANS:
508 case L1_MODE_V32:
509 if ((skb = dev_alloc_skb(ireg->clsb))) {
510 rcv_mbox(cs, ireg, (u_char *)skb_put(skb, ireg->clsb));
511 skb_queue_tail(&bcs->rqueue, skb);
512 schedule_event(bcs, B_RCVBUFREADY);
513 } else {
514 printk(KERN_WARNING "HiSax: skb out of memory\n");
515 cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
516 }
517 break;
518 case L1_MODE_HDLC:
519 if ((bcs->hw.isar.rcvidx + ireg->clsb) > HSCX_BUFMAX) {
520 if (cs->debug & L1_DEB_WARN)
521 debugl1(cs, "isar_rcv_frame: incoming packet too large");
522 cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
523 bcs->hw.isar.rcvidx = 0;
524 } else if (ireg->cmsb & HDLC_ERROR) {
525 if (cs->debug & L1_DEB_WARN)
526 debugl1(cs, "isar frame error %x len %d",
527 ireg->cmsb, ireg->clsb);
528#ifdef ERROR_STATISTIC
529 if (ireg->cmsb & HDLC_ERR_RER)
530 bcs->err_inv++;
531 if (ireg->cmsb & HDLC_ERR_CER)
532 bcs->err_crc++;
533#endif
534 bcs->hw.isar.rcvidx = 0;
535 cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
536 } else {
537 if (ireg->cmsb & HDLC_FSD)
538 bcs->hw.isar.rcvidx = 0;
539 ptr = bcs->hw.isar.rcvbuf + bcs->hw.isar.rcvidx;
540 bcs->hw.isar.rcvidx += ireg->clsb;
541 rcv_mbox(cs, ireg, ptr);
542 if (ireg->cmsb & HDLC_FED) {
543 if (bcs->hw.isar.rcvidx < 3) { /* last 2 bytes are the FCS */
544 if (cs->debug & L1_DEB_WARN)
545 debugl1(cs, "isar frame to short %d",
546 bcs->hw.isar.rcvidx);
547 } else if (!(skb = dev_alloc_skb(bcs->hw.isar.rcvidx-2))) {
548 printk(KERN_WARNING "ISAR: receive out of memory\n");
549 } else {
550 memcpy(skb_put(skb, bcs->hw.isar.rcvidx-2),
551 bcs->hw.isar.rcvbuf, bcs->hw.isar.rcvidx-2);
552 skb_queue_tail(&bcs->rqueue, skb);
553 schedule_event(bcs, B_RCVBUFREADY);
554 }
555 bcs->hw.isar.rcvidx = 0;
556 }
557 }
558 break;
559 case L1_MODE_FAX:
560 if (bcs->hw.isar.state != STFAX_ACTIV) {
561 if (cs->debug & L1_DEB_WARN)
562 debugl1(cs, "isar_rcv_frame: not ACTIV");
563 cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
564 bcs->hw.isar.rcvidx = 0;
565 break;
566 }
567 if (bcs->hw.isar.cmd == PCTRL_CMD_FRM) {
568 rcv_mbox(cs, ireg, bcs->hw.isar.rcvbuf);
569 bcs->hw.isar.rcvidx = ireg->clsb +
570 dle_count(bcs->hw.isar.rcvbuf, ireg->clsb);
571 if (cs->debug & L1_DEB_HSCX)
572 debugl1(cs, "isar_rcv_frame: raw(%d) dle(%d)",
573 ireg->clsb, bcs->hw.isar.rcvidx);
574 if ((skb = dev_alloc_skb(bcs->hw.isar.rcvidx))) {
575 insert_dle((u_char *)skb_put(skb, bcs->hw.isar.rcvidx),
576 bcs->hw.isar.rcvbuf, ireg->clsb);
577 skb_queue_tail(&bcs->rqueue, skb);
578 schedule_event(bcs, B_RCVBUFREADY);
579 if (ireg->cmsb & SART_NMD) { /* ABORT */
580 if (cs->debug & L1_DEB_WARN)
581 debugl1(cs, "isar_rcv_frame: no more data");
582 bcs->hw.isar.rcvidx = 0;
583 send_DLE_ETX(bcs);
584 sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) |
585 ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC,
586 0, NULL);
587 bcs->hw.isar.state = STFAX_ESCAPE;
588 schedule_event(bcs, B_LL_NOCARRIER);
589 }
590 } else {
591 printk(KERN_WARNING "HiSax: skb out of memory\n");
592 }
593 break;
594 }
595 if (bcs->hw.isar.cmd != PCTRL_CMD_FRH) {
596 if (cs->debug & L1_DEB_WARN)
597 debugl1(cs, "isar_rcv_frame: unknown fax mode %x",
598 bcs->hw.isar.cmd);
599 cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
600 bcs->hw.isar.rcvidx = 0;
601 break;
602 }
603 /* PCTRL_CMD_FRH */
604 if ((bcs->hw.isar.rcvidx + ireg->clsb) > HSCX_BUFMAX) {
605 if (cs->debug & L1_DEB_WARN)
606 debugl1(cs, "isar_rcv_frame: incoming packet too large");
607 cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
608 bcs->hw.isar.rcvidx = 0;
609 } else if (ireg->cmsb & HDLC_ERROR) {
610 if (cs->debug & L1_DEB_WARN)
611 debugl1(cs, "isar frame error %x len %d",
612 ireg->cmsb, ireg->clsb);
613 bcs->hw.isar.rcvidx = 0;
614 cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
615 } else {
616 if (ireg->cmsb & HDLC_FSD) {
617 bcs->hw.isar.rcvidx = 0;
618 }
619 ptr = bcs->hw.isar.rcvbuf + bcs->hw.isar.rcvidx;
620 bcs->hw.isar.rcvidx += ireg->clsb;
621 rcv_mbox(cs, ireg, ptr);
622 if (ireg->cmsb & HDLC_FED) {
623 int len = bcs->hw.isar.rcvidx +
624 dle_count(bcs->hw.isar.rcvbuf, bcs->hw.isar.rcvidx);
625 if (bcs->hw.isar.rcvidx < 3) { /* last 2 bytes are the FCS */
626 if (cs->debug & L1_DEB_WARN)
627 debugl1(cs, "isar frame to short %d",
628 bcs->hw.isar.rcvidx);
629 printk(KERN_WARNING "ISAR: frame to short %d\n",
630 bcs->hw.isar.rcvidx);
631 } else if (!(skb = dev_alloc_skb(len))) {
632 printk(KERN_WARNING "ISAR: receive out of memory\n");
633 } else {
634 insert_dle((u_char *)skb_put(skb, len),
635 bcs->hw.isar.rcvbuf,
636 bcs->hw.isar.rcvidx);
637 skb_queue_tail(&bcs->rqueue, skb);
638 schedule_event(bcs, B_RCVBUFREADY);
639 send_DLE_ETX(bcs);
640 schedule_event(bcs, B_LL_OK);
641 test_and_clear_bit(BC_FLG_FRH_WAIT, &bcs->Flag);
642 }
643 bcs->hw.isar.rcvidx = 0;
644 }
645 }
646 if (ireg->cmsb & SART_NMD) { /* ABORT */
647 if (cs->debug & L1_DEB_WARN)
648 debugl1(cs, "isar_rcv_frame: no more data");
649 bcs->hw.isar.rcvidx = 0;
650 sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) |
651 ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC, 0, NULL);
652 bcs->hw.isar.state = STFAX_ESCAPE;
653 if (test_and_clear_bit(BC_FLG_FRH_WAIT, &bcs->Flag)) {
654 send_DLE_ETX(bcs);
655 schedule_event(bcs, B_LL_NOCARRIER);
656 }
657 }
658 break;
659 default:
660 printk(KERN_ERR"isar_rcv_frame mode (%x)error\n", bcs->mode);
661 cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
662 break;
663 }
664}
665
666void
667isar_fill_fifo(struct BCState *bcs)
668{
669 struct IsdnCardState *cs = bcs->cs;
670 int count;
671 u_char msb;
672 u_char *ptr;
673
674 if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
675 debugl1(cs, "isar_fill_fifo");
676 if (!bcs->tx_skb)
677 return;
678 if (bcs->tx_skb->len <= 0)
679 return;
680 if (!(bcs->hw.isar.reg->bstat &
681 (bcs->hw.isar.dpath == 1 ? BSTAT_RDM1 : BSTAT_RDM2)))
682 return;
683 if (bcs->tx_skb->len > bcs->hw.isar.mml) {
684 msb = 0;
685 count = bcs->hw.isar.mml;
686 } else {
687 count = bcs->tx_skb->len;
688 msb = HDLC_FED;
689 }
690 ptr = bcs->tx_skb->data;
691 if (!bcs->hw.isar.txcnt) {
692 msb |= HDLC_FST;
693 if ((bcs->mode == L1_MODE_FAX) &&
694 (bcs->hw.isar.cmd == PCTRL_CMD_FTH)) {
695 if (bcs->tx_skb->len > 1) {
696 if ((ptr[0]== 0xff) && (ptr[1] == 0x13))
697 /* last frame */
698 test_and_set_bit(BC_FLG_LASTDATA,
699 &bcs->Flag);
700 }
701 }
702 }
703 skb_pull(bcs->tx_skb, count);
704 bcs->tx_cnt -= count;
705 bcs->hw.isar.txcnt += count;
706 switch (bcs->mode) {
707 case L1_MODE_NULL:
708 printk(KERN_ERR"isar_fill_fifo wrong mode 0\n");
709 break;
710 case L1_MODE_TRANS:
711 case L1_MODE_V32:
712 sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | ISAR_HIS_SDATA,
713 0, count, ptr);
714 break;
715 case L1_MODE_HDLC:
716 sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | ISAR_HIS_SDATA,
717 msb, count, ptr);
718 break;
719 case L1_MODE_FAX:
720 if (bcs->hw.isar.state != STFAX_ACTIV) {
721 if (cs->debug & L1_DEB_WARN)
722 debugl1(cs, "isar_fill_fifo: not ACTIV");
723 } else if (bcs->hw.isar.cmd == PCTRL_CMD_FTH) {
724 sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | ISAR_HIS_SDATA,
725 msb, count, ptr);
726 } else if (bcs->hw.isar.cmd == PCTRL_CMD_FTM) {
727 sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | ISAR_HIS_SDATA,
728 0, count, ptr);
729 } else {
730 if (cs->debug & L1_DEB_WARN)
731 debugl1(cs, "isar_fill_fifo: not FTH/FTM");
732 }
733 break;
734 default:
735 if (cs->debug)
736 debugl1(cs, "isar_fill_fifo mode(%x) error", bcs->mode);
737 printk(KERN_ERR"isar_fill_fifo mode(%x) error\n", bcs->mode);
738 break;
739 }
740}
741
742inline
743struct BCState *sel_bcs_isar(struct IsdnCardState *cs, u_char dpath)
744{
745 if ((!dpath) || (dpath == 3))
746 return(NULL);
747 if (cs->bcs[0].hw.isar.dpath == dpath)
748 return(&cs->bcs[0]);
749 if (cs->bcs[1].hw.isar.dpath == dpath)
750 return(&cs->bcs[1]);
751 return(NULL);
752}
753
754void
755send_frames(struct BCState *bcs)
756{
757 if (bcs->tx_skb) {
758 if (bcs->tx_skb->len) {
759 isar_fill_fifo(bcs);
760 return;
761 } else {
762 if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) &&
763 (PACKET_NOACK != bcs->tx_skb->pkt_type)) {
764 u_long flags;
765 spin_lock_irqsave(&bcs->aclock, flags);
766 bcs->ackcnt += bcs->hw.isar.txcnt;
767 spin_unlock_irqrestore(&bcs->aclock, flags);
768 schedule_event(bcs, B_ACKPENDING);
769 }
770 if (bcs->mode == L1_MODE_FAX) {
771 if (bcs->hw.isar.cmd == PCTRL_CMD_FTH) {
772 if (test_bit(BC_FLG_LASTDATA, &bcs->Flag)) {
773 test_and_set_bit(BC_FLG_NMD_DATA, &bcs->Flag);
774 }
775 } else if (bcs->hw.isar.cmd == PCTRL_CMD_FTM) {
776 if (test_bit(BC_FLG_DLEETX, &bcs->Flag)) {
777 test_and_set_bit(BC_FLG_LASTDATA, &bcs->Flag);
778 test_and_set_bit(BC_FLG_NMD_DATA, &bcs->Flag);
779 }
780 }
781 }
782 dev_kfree_skb_any(bcs->tx_skb);
783 bcs->hw.isar.txcnt = 0;
784 bcs->tx_skb = NULL;
785 }
786 }
787 if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
788 bcs->hw.isar.txcnt = 0;
789 test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
790 isar_fill_fifo(bcs);
791 } else {
792 if (test_and_clear_bit(BC_FLG_DLEETX, &bcs->Flag)) {
793 if (test_and_clear_bit(BC_FLG_LASTDATA, &bcs->Flag)) {
794 if (test_and_clear_bit(BC_FLG_NMD_DATA, &bcs->Flag)) {
795 u_char dummy = 0;
796 sendmsg(bcs->cs, SET_DPS(bcs->hw.isar.dpath) |
797 ISAR_HIS_SDATA, 0x01, 1, &dummy);
798 }
799 test_and_set_bit(BC_FLG_LL_OK, &bcs->Flag);
800 } else {
801 schedule_event(bcs, B_LL_CONNECT);
802 }
803 }
804 test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
805 schedule_event(bcs, B_XMTBUFREADY);
806 }
807}
808
809inline void
810check_send(struct IsdnCardState *cs, u_char rdm)
811{
812 struct BCState *bcs;
813
814 if (rdm & BSTAT_RDM1) {
815 if ((bcs = sel_bcs_isar(cs, 1))) {
816 if (bcs->mode) {
817 send_frames(bcs);
818 }
819 }
820 }
821 if (rdm & BSTAT_RDM2) {
822 if ((bcs = sel_bcs_isar(cs, 2))) {
823 if (bcs->mode) {
824 send_frames(bcs);
825 }
826 }
827 }
828
829}
830
831const char *dmril[] = {"NO SPEED", "1200/75", "NODEF2", "75/1200", "NODEF4",
832 "300", "600", "1200", "2400", "4800", "7200",
833 "9600nt", "9600t", "12000", "14400", "WRONG"};
834const char *dmrim[] = {"NO MOD", "NO DEF", "V32/V32b", "V22", "V21",
835 "Bell103", "V23", "Bell202", "V17", "V29", "V27ter"};
836
837static void
838isar_pump_status_rsp(struct BCState *bcs, struct isar_reg *ireg) {
839 struct IsdnCardState *cs = bcs->cs;
840 u_char ril = ireg->par[0];
841 u_char rim;
842
843 if (!test_and_clear_bit(ISAR_RATE_REQ, &bcs->hw.isar.reg->Flags))
844 return;
845 if (ril > 14) {
846 if (cs->debug & L1_DEB_WARN)
847 debugl1(cs, "wrong pstrsp ril=%d",ril);
848 ril = 15;
849 }
850 switch(ireg->par[1]) {
851 case 0:
852 rim = 0;
853 break;
854 case 0x20:
855 rim = 2;
856 break;
857 case 0x40:
858 rim = 3;
859 break;
860 case 0x41:
861 rim = 4;
862 break;
863 case 0x51:
864 rim = 5;
865 break;
866 case 0x61:
867 rim = 6;
868 break;
869 case 0x71:
870 rim = 7;
871 break;
872 case 0x82:
873 rim = 8;
874 break;
875 case 0x92:
876 rim = 9;
877 break;
878 case 0xa2:
879 rim = 10;
880 break;
881 default:
882 rim = 1;
883 break;
884 }
885 sprintf(bcs->hw.isar.conmsg,"%s %s", dmril[ril], dmrim[rim]);
886 bcs->conmsg = bcs->hw.isar.conmsg;
887 if (cs->debug & L1_DEB_HSCX)
888 debugl1(cs, "pump strsp %s", bcs->conmsg);
889}
890
891static void
892isar_pump_statev_modem(struct BCState *bcs, u_char devt) {
893 struct IsdnCardState *cs = bcs->cs;
894 u_char dps = SET_DPS(bcs->hw.isar.dpath);
895
896 switch(devt) {
897 case PSEV_10MS_TIMER:
898 if (cs->debug & L1_DEB_HSCX)
899 debugl1(cs, "pump stev TIMER");
900 break;
901 case PSEV_CON_ON:
902 if (cs->debug & L1_DEB_HSCX)
903 debugl1(cs, "pump stev CONNECT");
904 l1_msg_b(bcs->st, PH_ACTIVATE | REQUEST, NULL);
905 break;
906 case PSEV_CON_OFF:
907 if (cs->debug & L1_DEB_HSCX)
908 debugl1(cs, "pump stev NO CONNECT");
909 sendmsg(cs, dps | ISAR_HIS_PSTREQ, 0, 0, NULL);
910 l1_msg_b(bcs->st, PH_DEACTIVATE | REQUEST, NULL);
911 break;
912 case PSEV_V24_OFF:
913 if (cs->debug & L1_DEB_HSCX)
914 debugl1(cs, "pump stev V24 OFF");
915 break;
916 case PSEV_CTS_ON:
917 if (cs->debug & L1_DEB_HSCX)
918 debugl1(cs, "pump stev CTS ON");
919 break;
920 case PSEV_CTS_OFF:
921 if (cs->debug & L1_DEB_HSCX)
922 debugl1(cs, "pump stev CTS OFF");
923 break;
924 case PSEV_DCD_ON:
925 if (cs->debug & L1_DEB_HSCX)
926 debugl1(cs, "pump stev CARRIER ON");
927 test_and_set_bit(ISAR_RATE_REQ, &bcs->hw.isar.reg->Flags);
928 sendmsg(cs, dps | ISAR_HIS_PSTREQ, 0, 0, NULL);
929 break;
930 case PSEV_DCD_OFF:
931 if (cs->debug & L1_DEB_HSCX)
932 debugl1(cs, "pump stev CARRIER OFF");
933 break;
934 case PSEV_DSR_ON:
935 if (cs->debug & L1_DEB_HSCX)
936 debugl1(cs, "pump stev DSR ON");
937 break;
938 case PSEV_DSR_OFF:
939 if (cs->debug & L1_DEB_HSCX)
940 debugl1(cs, "pump stev DSR_OFF");
941 break;
942 case PSEV_REM_RET:
943 if (cs->debug & L1_DEB_HSCX)
944 debugl1(cs, "pump stev REMOTE RETRAIN");
945 break;
946 case PSEV_REM_REN:
947 if (cs->debug & L1_DEB_HSCX)
948 debugl1(cs, "pump stev REMOTE RENEGOTIATE");
949 break;
950 case PSEV_GSTN_CLR:
951 if (cs->debug & L1_DEB_HSCX)
952 debugl1(cs, "pump stev GSTN CLEAR", devt);
953 break;
954 default:
955 if (cs->debug & L1_DEB_HSCX)
956 debugl1(cs, "unknown pump stev %x", devt);
957 break;
958 }
959}
960
961static void
962ll_deliver_faxstat(struct BCState *bcs, u_char status)
963{
964 isdn_ctrl ic;
965 struct Channel *chanp = (struct Channel *) bcs->st->lli.userdata;
966
967 if (bcs->cs->debug & L1_DEB_HSCX)
968 debugl1(bcs->cs, "HL->LL FAXIND %x", status);
969 ic.driver = bcs->cs->myid;
970 ic.command = ISDN_STAT_FAXIND;
971 ic.arg = chanp->chan;
972 ic.parm.aux.cmd = status;
973 bcs->cs->iif.statcallb(&ic);
974}
975
976static void
977isar_pump_statev_fax(struct BCState *bcs, u_char devt) {
978 struct IsdnCardState *cs = bcs->cs;
979 u_char dps = SET_DPS(bcs->hw.isar.dpath);
980 u_char p1;
981
982 switch(devt) {
983 case PSEV_10MS_TIMER:
984 if (cs->debug & L1_DEB_HSCX)
985 debugl1(cs, "pump stev TIMER");
986 break;
987 case PSEV_RSP_READY:
988 if (cs->debug & L1_DEB_HSCX)
989 debugl1(cs, "pump stev RSP_READY");
990 bcs->hw.isar.state = STFAX_READY;
991 l1_msg_b(bcs->st, PH_ACTIVATE | REQUEST, NULL);
992 if (test_bit(BC_FLG_ORIG, &bcs->Flag)) {
993 isar_pump_cmd(bcs, ISDN_FAX_CLASS1_FRH, 3);
994 } else {
995 isar_pump_cmd(bcs, ISDN_FAX_CLASS1_FTH, 3);
996 }
997 break;
998 case PSEV_LINE_TX_H:
999 if (bcs->hw.isar.state == STFAX_LINE) {
1000 if (cs->debug & L1_DEB_HSCX)
1001 debugl1(cs, "pump stev LINE_TX_H");
1002 bcs->hw.isar.state = STFAX_CONT;
1003 sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_CONT, 0, NULL);
1004 } else {
1005 if (cs->debug & L1_DEB_WARN)
1006 debugl1(cs, "pump stev LINE_TX_H wrong st %x",
1007 bcs->hw.isar.state);
1008 }
1009 break;
1010 case PSEV_LINE_RX_H:
1011 if (bcs->hw.isar.state == STFAX_LINE) {
1012 if (cs->debug & L1_DEB_HSCX)
1013 debugl1(cs, "pump stev LINE_RX_H");
1014 bcs->hw.isar.state = STFAX_CONT;
1015 sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_CONT, 0, NULL);
1016 } else {
1017 if (cs->debug & L1_DEB_WARN)
1018 debugl1(cs, "pump stev LINE_RX_H wrong st %x",
1019 bcs->hw.isar.state);
1020 }
1021 break;
1022 case PSEV_LINE_TX_B:
1023 if (bcs->hw.isar.state == STFAX_LINE) {
1024 if (cs->debug & L1_DEB_HSCX)
1025 debugl1(cs, "pump stev LINE_TX_B");
1026 bcs->hw.isar.state = STFAX_CONT;
1027 sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_CONT, 0, NULL);
1028 } else {
1029 if (cs->debug & L1_DEB_WARN)
1030 debugl1(cs, "pump stev LINE_TX_B wrong st %x",
1031 bcs->hw.isar.state);
1032 }
1033 break;
1034 case PSEV_LINE_RX_B:
1035 if (bcs->hw.isar.state == STFAX_LINE) {
1036 if (cs->debug & L1_DEB_HSCX)
1037 debugl1(cs, "pump stev LINE_RX_B");
1038 bcs->hw.isar.state = STFAX_CONT;
1039 sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_CONT, 0, NULL);
1040 } else {
1041 if (cs->debug & L1_DEB_WARN)
1042 debugl1(cs, "pump stev LINE_RX_B wrong st %x",
1043 bcs->hw.isar.state);
1044 }
1045 break;
1046 case PSEV_RSP_CONN:
1047 if (bcs->hw.isar.state == STFAX_CONT) {
1048 if (cs->debug & L1_DEB_HSCX)
1049 debugl1(cs, "pump stev RSP_CONN");
1050 bcs->hw.isar.state = STFAX_ACTIV;
1051 test_and_set_bit(ISAR_RATE_REQ, &bcs->hw.isar.reg->Flags);
1052 sendmsg(cs, dps | ISAR_HIS_PSTREQ, 0, 0, NULL);
1053 if (bcs->hw.isar.cmd == PCTRL_CMD_FTH) {
1054 /* 1s Flags before data */
1055 if (test_and_set_bit(BC_FLG_FTI_RUN, &bcs->Flag))
1056 del_timer(&bcs->hw.isar.ftimer);
1057 /* 1000 ms */
1058 bcs->hw.isar.ftimer.expires =
1059 jiffies + ((1000 * HZ)/1000);
1060 test_and_set_bit(BC_FLG_LL_CONN,
1061 &bcs->Flag);
1062 add_timer(&bcs->hw.isar.ftimer);
1063 } else {
1064 schedule_event(bcs, B_LL_CONNECT);
1065 }
1066 } else {
1067 if (cs->debug & L1_DEB_WARN)
1068 debugl1(cs, "pump stev RSP_CONN wrong st %x",
1069 bcs->hw.isar.state);
1070 }
1071 break;
1072 case PSEV_FLAGS_DET:
1073 if (cs->debug & L1_DEB_HSCX)
1074 debugl1(cs, "pump stev FLAGS_DET");
1075 break;
1076 case PSEV_RSP_DISC:
1077 if (cs->debug & L1_DEB_HSCX)
1078 debugl1(cs, "pump stev RSP_DISC");
1079 if (bcs->hw.isar.state == STFAX_ESCAPE) {
1080 p1 = 5;
1081 switch(bcs->hw.isar.newcmd) {
1082 case 0:
1083 bcs->hw.isar.state = STFAX_READY;
1084 break;
1085 case PCTRL_CMD_FTM:
1086 p1 = 2;
1087 case PCTRL_CMD_FTH:
1088 sendmsg(cs, dps | ISAR_HIS_PUMPCTRL,
1089 PCTRL_CMD_SILON, 1, &p1);
1090 bcs->hw.isar.state = STFAX_SILDET;
1091 break;
1092 case PCTRL_CMD_FRM:
1093 if (frm_extra_delay)
1094 mdelay(frm_extra_delay);
1095 case PCTRL_CMD_FRH:
1096 p1 = bcs->hw.isar.mod = bcs->hw.isar.newmod;
1097 bcs->hw.isar.newmod = 0;
1098 bcs->hw.isar.cmd = bcs->hw.isar.newcmd;
1099 bcs->hw.isar.newcmd = 0;
1100 sendmsg(cs, dps | ISAR_HIS_PUMPCTRL,
1101 bcs->hw.isar.cmd, 1, &p1);
1102 bcs->hw.isar.state = STFAX_LINE;
1103 bcs->hw.isar.try_mod = 3;
1104 break;
1105 default:
1106 if (cs->debug & L1_DEB_HSCX)
1107 debugl1(cs, "RSP_DISC unknown newcmd %x", bcs->hw.isar.newcmd);
1108 break;
1109 }
1110 } else if (bcs->hw.isar.state == STFAX_ACTIV) {
1111 if (test_and_clear_bit(BC_FLG_LL_OK, &bcs->Flag)) {
1112 schedule_event(bcs, B_LL_OK);
1113 } else if (bcs->hw.isar.cmd == PCTRL_CMD_FRM) {
1114 send_DLE_ETX(bcs);
1115 schedule_event(bcs, B_LL_NOCARRIER);
1116 } else {
1117 ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_FCERROR);
1118 }
1119 bcs->hw.isar.state = STFAX_READY;
1120 } else {
1121 bcs->hw.isar.state = STFAX_READY;
1122 ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_FCERROR);
1123 }
1124 break;
1125 case PSEV_RSP_SILDET:
1126 if (cs->debug & L1_DEB_HSCX)
1127 debugl1(cs, "pump stev RSP_SILDET");
1128 if (bcs->hw.isar.state == STFAX_SILDET) {
1129 p1 = bcs->hw.isar.mod = bcs->hw.isar.newmod;
1130 bcs->hw.isar.newmod = 0;
1131 bcs->hw.isar.cmd = bcs->hw.isar.newcmd;
1132 bcs->hw.isar.newcmd = 0;
1133 sendmsg(cs, dps | ISAR_HIS_PUMPCTRL,
1134 bcs->hw.isar.cmd, 1, &p1);
1135 bcs->hw.isar.state = STFAX_LINE;
1136 bcs->hw.isar.try_mod = 3;
1137 }
1138 break;
1139 case PSEV_RSP_SILOFF:
1140 if (cs->debug & L1_DEB_HSCX)
1141 debugl1(cs, "pump stev RSP_SILOFF");
1142 break;
1143 case PSEV_RSP_FCERR:
1144 if (bcs->hw.isar.state == STFAX_LINE) {
1145 if (cs->debug & L1_DEB_HSCX)
1146 debugl1(cs, "pump stev RSP_FCERR try %d",
1147 bcs->hw.isar.try_mod);
1148 if (bcs->hw.isar.try_mod--) {
1149 sendmsg(cs, dps | ISAR_HIS_PUMPCTRL,
1150 bcs->hw.isar.cmd, 1,
1151 &bcs->hw.isar.mod);
1152 break;
1153 }
1154 }
1155 if (cs->debug & L1_DEB_HSCX)
1156 debugl1(cs, "pump stev RSP_FCERR");
1157 bcs->hw.isar.state = STFAX_ESCAPE;
1158 sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC, 0, NULL);
1159 ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_FCERROR);
1160 break;
1161 default:
1162 break;
1163 }
1164}
1165
1166static char debbuf[128];
1167
1168void
1169isar_int_main(struct IsdnCardState *cs)
1170{
1171 struct isar_reg *ireg = cs->bcs[0].hw.isar.reg;
1172 struct BCState *bcs;
1173
1174 get_irq_infos(cs, ireg);
1175 switch (ireg->iis & ISAR_IIS_MSCMSD) {
1176 case ISAR_IIS_RDATA:
1177 if ((bcs = sel_bcs_isar(cs, ireg->iis >> 6))) {
1178 isar_rcv_frame(cs, bcs);
1179 } else {
1180 debugl1(cs, "isar spurious IIS_RDATA %x/%x/%x",
1181 ireg->iis, ireg->cmsb, ireg->clsb);
1182 cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
1183 }
1184 break;
1185 case ISAR_IIS_GSTEV:
1186 cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
1187 ireg->bstat |= ireg->cmsb;
1188 check_send(cs, ireg->cmsb);
1189 break;
1190 case ISAR_IIS_BSTEV:
1191#ifdef ERROR_STATISTIC
1192 if ((bcs = sel_bcs_isar(cs, ireg->iis >> 6))) {
1193 if (ireg->cmsb == BSTEV_TBO)
1194 bcs->err_tx++;
1195 if (ireg->cmsb == BSTEV_RBO)
1196 bcs->err_rdo++;
1197 }
1198#endif
1199 if (cs->debug & L1_DEB_WARN)
1200 debugl1(cs, "Buffer STEV dpath%d msb(%x)",
1201 ireg->iis>>6, ireg->cmsb);
1202 cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
1203 break;
1204 case ISAR_IIS_PSTEV:
1205 if ((bcs = sel_bcs_isar(cs, ireg->iis >> 6))) {
1206 rcv_mbox(cs, ireg, (u_char *)ireg->par);
1207 if (bcs->mode == L1_MODE_V32) {
1208 isar_pump_statev_modem(bcs, ireg->cmsb);
1209 } else if (bcs->mode == L1_MODE_FAX) {
1210 isar_pump_statev_fax(bcs, ireg->cmsb);
1211 } else if (ireg->cmsb == PSEV_10MS_TIMER) {
1212 if (cs->debug & L1_DEB_HSCX)
1213 debugl1(cs, "pump stev TIMER");
1214 } else {
1215 if (cs->debug & L1_DEB_WARN)
1216 debugl1(cs, "isar IIS_PSTEV pmode %d stat %x",
1217 bcs->mode, ireg->cmsb);
1218 }
1219 } else {
1220 debugl1(cs, "isar spurious IIS_PSTEV %x/%x/%x",
1221 ireg->iis, ireg->cmsb, ireg->clsb);
1222 cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
1223 }
1224 break;
1225 case ISAR_IIS_PSTRSP:
1226 if ((bcs = sel_bcs_isar(cs, ireg->iis >> 6))) {
1227 rcv_mbox(cs, ireg, (u_char *)ireg->par);
1228 isar_pump_status_rsp(bcs, ireg);
1229 } else {
1230 debugl1(cs, "isar spurious IIS_PSTRSP %x/%x/%x",
1231 ireg->iis, ireg->cmsb, ireg->clsb);
1232 cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
1233 }
1234 break;
1235 case ISAR_IIS_DIAG:
1236 case ISAR_IIS_BSTRSP:
1237 case ISAR_IIS_IOM2RSP:
1238 rcv_mbox(cs, ireg, (u_char *)ireg->par);
1239 if ((cs->debug & (L1_DEB_HSCX | L1_DEB_HSCX_FIFO))
1240 == L1_DEB_HSCX) {
1241 u_char *tp=debbuf;
1242
1243 tp += sprintf(debbuf, "msg iis(%x) msb(%x)",
1244 ireg->iis, ireg->cmsb);
1245 QuickHex(tp, (u_char *)ireg->par, ireg->clsb);
1246 debugl1(cs, debbuf);
1247 }
1248 break;
1249 case ISAR_IIS_INVMSG:
1250 rcv_mbox(cs, ireg, debbuf);
1251 if (cs->debug & L1_DEB_WARN)
1252 debugl1(cs, "invalid msg his:%x",
1253 ireg->cmsb);
1254 break;
1255 default:
1256 rcv_mbox(cs, ireg, debbuf);
1257 if (cs->debug & L1_DEB_WARN)
1258 debugl1(cs, "unhandled msg iis(%x) ctrl(%x/%x)",
1259 ireg->iis, ireg->cmsb, ireg->clsb);
1260 break;
1261 }
1262}
1263
1264static void
1265ftimer_handler(struct BCState *bcs) {
1266 if (bcs->cs->debug)
1267 debugl1(bcs->cs, "ftimer flags %04x",
1268 bcs->Flag);
1269 test_and_clear_bit(BC_FLG_FTI_RUN, &bcs->Flag);
1270 if (test_and_clear_bit(BC_FLG_LL_CONN, &bcs->Flag)) {
1271 schedule_event(bcs, B_LL_CONNECT);
1272 }
1273 if (test_and_clear_bit(BC_FLG_FTI_FTS, &bcs->Flag)) {
1274 schedule_event(bcs, B_LL_OK);
1275 }
1276}
1277
1278static void
1279setup_pump(struct BCState *bcs) {
1280 struct IsdnCardState *cs = bcs->cs;
1281 u_char dps = SET_DPS(bcs->hw.isar.dpath);
1282 u_char ctrl, param[6];
1283
1284 switch (bcs->mode) {
1285 case L1_MODE_NULL:
1286 case L1_MODE_TRANS:
1287 case L1_MODE_HDLC:
1288 sendmsg(cs, dps | ISAR_HIS_PUMPCFG, PMOD_BYPASS, 0, NULL);
1289 break;
1290 case L1_MODE_V32:
1291 ctrl = PMOD_DATAMODEM;
1292 if (test_bit(BC_FLG_ORIG, &bcs->Flag)) {
1293 ctrl |= PCTRL_ORIG;
1294 param[5] = PV32P6_CTN;
1295 } else {
1296 param[5] = PV32P6_ATN;
1297 }
1298 param[0] = para_TOA; /* 6 db */
1299 param[1] = PV32P2_V23R | PV32P2_V22A | PV32P2_V22B |
1300 PV32P2_V22C | PV32P2_V21 | PV32P2_BEL;
1301 param[2] = PV32P3_AMOD | PV32P3_V32B | PV32P3_V23B;
1302 param[3] = PV32P4_UT144;
1303 param[4] = PV32P5_UT144;
1304 sendmsg(cs, dps | ISAR_HIS_PUMPCFG, ctrl, 6, param);
1305 break;
1306 case L1_MODE_FAX:
1307 ctrl = PMOD_FAX;
1308 if (test_bit(BC_FLG_ORIG, &bcs->Flag)) {
1309 ctrl |= PCTRL_ORIG;
1310 param[1] = PFAXP2_CTN;
1311 } else {
1312 param[1] = PFAXP2_ATN;
1313 }
1314 param[0] = para_TOA; /* 6 db */
1315 sendmsg(cs, dps | ISAR_HIS_PUMPCFG, ctrl, 2, param);
1316 bcs->hw.isar.state = STFAX_NULL;
1317 bcs->hw.isar.newcmd = 0;
1318 bcs->hw.isar.newmod = 0;
1319 test_and_set_bit(BC_FLG_FTI_RUN, &bcs->Flag);
1320 break;
1321 }
1322 udelay(1000);
1323 sendmsg(cs, dps | ISAR_HIS_PSTREQ, 0, 0, NULL);
1324 udelay(1000);
1325}
1326
1327static void
1328setup_sart(struct BCState *bcs) {
1329 struct IsdnCardState *cs = bcs->cs;
1330 u_char dps = SET_DPS(bcs->hw.isar.dpath);
1331 u_char ctrl, param[2];
1332
1333 switch (bcs->mode) {
1334 case L1_MODE_NULL:
1335 sendmsg(cs, dps | ISAR_HIS_SARTCFG, SMODE_DISABLE, 0,
1336 NULL);
1337 break;
1338 case L1_MODE_TRANS:
1339 sendmsg(cs, dps | ISAR_HIS_SARTCFG, SMODE_BINARY, 2,
1340 "\0\0");
1341 break;
1342 case L1_MODE_HDLC:
1343 param[0] = 0;
1344 sendmsg(cs, dps | ISAR_HIS_SARTCFG, SMODE_HDLC, 1,
1345 param);
1346 break;
1347 case L1_MODE_V32:
1348 ctrl = SMODE_V14 | SCTRL_HDMC_BOTH;
1349 param[0] = S_P1_CHS_8;
1350 param[1] = S_P2_BFT_DEF;
1351 sendmsg(cs, dps | ISAR_HIS_SARTCFG, ctrl, 2,
1352 param);
1353 break;
1354 case L1_MODE_FAX:
1355 /* SART must not configured with FAX */
1356 break;
1357 }
1358 udelay(1000);
1359 sendmsg(cs, dps | ISAR_HIS_BSTREQ, 0, 0, NULL);
1360 udelay(1000);
1361}
1362
1363static void
1364setup_iom2(struct BCState *bcs) {
1365 struct IsdnCardState *cs = bcs->cs;
1366 u_char dps = SET_DPS(bcs->hw.isar.dpath);
1367 u_char cmsb = IOM_CTRL_ENA, msg[5] = {IOM_P1_TXD,0,0,0,0};
1368
1369 if (bcs->channel)
1370 msg[1] = msg[3] = 1;
1371 switch (bcs->mode) {
1372 case L1_MODE_NULL:
1373 cmsb = 0;
1374 /* dummy slot */
1375 msg[1] = msg[3] = bcs->hw.isar.dpath + 2;
1376 break;
1377 case L1_MODE_TRANS:
1378 case L1_MODE_HDLC:
1379 break;
1380 case L1_MODE_V32:
1381 case L1_MODE_FAX:
1382 cmsb |= IOM_CTRL_ALAW | IOM_CTRL_RCV;
1383 break;
1384 }
1385 sendmsg(cs, dps | ISAR_HIS_IOM2CFG, cmsb, 5, msg);
1386 udelay(1000);
1387 sendmsg(cs, dps | ISAR_HIS_IOM2REQ, 0, 0, NULL);
1388 udelay(1000);
1389}
1390
1391int
1392modeisar(struct BCState *bcs, int mode, int bc)
1393{
1394 struct IsdnCardState *cs = bcs->cs;
1395
1396 /* Here we are selecting the best datapath for requested mode */
1397 if(bcs->mode == L1_MODE_NULL) { /* New Setup */
1398 bcs->channel = bc;
1399 switch (mode) {
1400 case L1_MODE_NULL: /* init */
1401 if (!bcs->hw.isar.dpath)
1402 /* no init for dpath 0 */
1403 return(0);
1404 break;
1405 case L1_MODE_TRANS:
1406 case L1_MODE_HDLC:
1407 /* best is datapath 2 */
1408 if (!test_and_set_bit(ISAR_DP2_USE,
1409 &bcs->hw.isar.reg->Flags))
1410 bcs->hw.isar.dpath = 2;
1411 else if (!test_and_set_bit(ISAR_DP1_USE,
1412 &bcs->hw.isar.reg->Flags))
1413 bcs->hw.isar.dpath = 1;
1414 else {
1415 printk(KERN_WARNING"isar modeisar both pathes in use\n");
1416 return(1);
1417 }
1418 break;
1419 case L1_MODE_V32:
1420 case L1_MODE_FAX:
1421 /* only datapath 1 */
1422 if (!test_and_set_bit(ISAR_DP1_USE,
1423 &bcs->hw.isar.reg->Flags))
1424 bcs->hw.isar.dpath = 1;
1425 else {
1426 printk(KERN_WARNING"isar modeisar analog funktions only with DP1\n");
1427 debugl1(cs, "isar modeisar analog funktions only with DP1");
1428 return(1);
1429 }
1430 break;
1431 }
1432 }
1433 if (cs->debug & L1_DEB_HSCX)
1434 debugl1(cs, "isar dp%d mode %d->%d ichan %d",
1435 bcs->hw.isar.dpath, bcs->mode, mode, bc);
1436 bcs->mode = mode;
1437 setup_pump(bcs);
1438 setup_iom2(bcs);
1439 setup_sart(bcs);
1440 if (bcs->mode == L1_MODE_NULL) {
1441 /* Clear resources */
1442 if (bcs->hw.isar.dpath == 1)
1443 test_and_clear_bit(ISAR_DP1_USE, &bcs->hw.isar.reg->Flags);
1444 else if (bcs->hw.isar.dpath == 2)
1445 test_and_clear_bit(ISAR_DP2_USE, &bcs->hw.isar.reg->Flags);
1446 bcs->hw.isar.dpath = 0;
1447 }
1448 return(0);
1449}
1450
1451static void
1452isar_pump_cmd(struct BCState *bcs, u_char cmd, u_char para)
1453{
1454 struct IsdnCardState *cs = bcs->cs;
1455 u_char dps = SET_DPS(bcs->hw.isar.dpath);
1456 u_char ctrl = 0, nom = 0, p1 = 0;
1457
1458 switch(cmd) {
1459 case ISDN_FAX_CLASS1_FTM:
1460 test_and_clear_bit(BC_FLG_FRH_WAIT, &bcs->Flag);
1461 if (bcs->hw.isar.state == STFAX_READY) {
1462 p1 = para;
1463 ctrl = PCTRL_CMD_FTM;
1464 nom = 1;
1465 bcs->hw.isar.state = STFAX_LINE;
1466 bcs->hw.isar.cmd = ctrl;
1467 bcs->hw.isar.mod = para;
1468 bcs->hw.isar.newmod = 0;
1469 bcs->hw.isar.newcmd = 0;
1470 bcs->hw.isar.try_mod = 3;
1471 } else if ((bcs->hw.isar.state == STFAX_ACTIV) &&
1472 (bcs->hw.isar.cmd == PCTRL_CMD_FTM) &&
1473 (bcs->hw.isar.mod == para)) {
1474 ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_CONNECT);
1475 } else {
1476 bcs->hw.isar.newmod = para;
1477 bcs->hw.isar.newcmd = PCTRL_CMD_FTM;
1478 nom = 0;
1479 ctrl = PCTRL_CMD_ESC;
1480 bcs->hw.isar.state = STFAX_ESCAPE;
1481 }
1482 break;
1483 case ISDN_FAX_CLASS1_FTH:
1484 test_and_clear_bit(BC_FLG_FRH_WAIT, &bcs->Flag);
1485 if (bcs->hw.isar.state == STFAX_READY) {
1486 p1 = para;
1487 ctrl = PCTRL_CMD_FTH;
1488 nom = 1;
1489 bcs->hw.isar.state = STFAX_LINE;
1490 bcs->hw.isar.cmd = ctrl;
1491 bcs->hw.isar.mod = para;
1492 bcs->hw.isar.newmod = 0;
1493 bcs->hw.isar.newcmd = 0;
1494 bcs->hw.isar.try_mod = 3;
1495 } else if ((bcs->hw.isar.state == STFAX_ACTIV) &&
1496 (bcs->hw.isar.cmd == PCTRL_CMD_FTH) &&
1497 (bcs->hw.isar.mod == para)) {
1498 ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_CONNECT);
1499 } else {
1500 bcs->hw.isar.newmod = para;
1501 bcs->hw.isar.newcmd = PCTRL_CMD_FTH;
1502 nom = 0;
1503 ctrl = PCTRL_CMD_ESC;
1504 bcs->hw.isar.state = STFAX_ESCAPE;
1505 }
1506 break;
1507 case ISDN_FAX_CLASS1_FRM:
1508 test_and_clear_bit(BC_FLG_FRH_WAIT, &bcs->Flag);
1509 if (bcs->hw.isar.state == STFAX_READY) {
1510 p1 = para;
1511 ctrl = PCTRL_CMD_FRM;
1512 nom = 1;
1513 bcs->hw.isar.state = STFAX_LINE;
1514 bcs->hw.isar.cmd = ctrl;
1515 bcs->hw.isar.mod = para;
1516 bcs->hw.isar.newmod = 0;
1517 bcs->hw.isar.newcmd = 0;
1518 bcs->hw.isar.try_mod = 3;
1519 } else if ((bcs->hw.isar.state == STFAX_ACTIV) &&
1520 (bcs->hw.isar.cmd == PCTRL_CMD_FRM) &&
1521 (bcs->hw.isar.mod == para)) {
1522 ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_CONNECT);
1523 } else {
1524 bcs->hw.isar.newmod = para;
1525 bcs->hw.isar.newcmd = PCTRL_CMD_FRM;
1526 nom = 0;
1527 ctrl = PCTRL_CMD_ESC;
1528 bcs->hw.isar.state = STFAX_ESCAPE;
1529 }
1530 break;
1531 case ISDN_FAX_CLASS1_FRH:
1532 test_and_set_bit(BC_FLG_FRH_WAIT, &bcs->Flag);
1533 if (bcs->hw.isar.state == STFAX_READY) {
1534 p1 = para;
1535 ctrl = PCTRL_CMD_FRH;
1536 nom = 1;
1537 bcs->hw.isar.state = STFAX_LINE;
1538 bcs->hw.isar.cmd = ctrl;
1539 bcs->hw.isar.mod = para;
1540 bcs->hw.isar.newmod = 0;
1541 bcs->hw.isar.newcmd = 0;
1542 bcs->hw.isar.try_mod = 3;
1543 } else if ((bcs->hw.isar.state == STFAX_ACTIV) &&
1544 (bcs->hw.isar.cmd == PCTRL_CMD_FRH) &&
1545 (bcs->hw.isar.mod == para)) {
1546 ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_CONNECT);
1547 } else {
1548 bcs->hw.isar.newmod = para;
1549 bcs->hw.isar.newcmd = PCTRL_CMD_FRH;
1550 nom = 0;
1551 ctrl = PCTRL_CMD_ESC;
1552 bcs->hw.isar.state = STFAX_ESCAPE;
1553 }
1554 break;
1555 case ISDN_FAXPUMP_HALT:
1556 bcs->hw.isar.state = STFAX_NULL;
1557 nom = 0;
1558 ctrl = PCTRL_CMD_HALT;
1559 break;
1560 }
1561 if (ctrl)
1562 sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, ctrl, nom, &p1);
1563}
1564
1565void
1566isar_setup(struct IsdnCardState *cs)
1567{
1568 u_char msg;
1569 int i;
1570
1571 /* Dpath 1, 2 */
1572 msg = 61;
1573 for (i=0; i<2; i++) {
1574 /* Buffer Config */
1575 sendmsg(cs, (i ? ISAR_HIS_DPS2 : ISAR_HIS_DPS1) |
1576 ISAR_HIS_P12CFG, 4, 1, &msg);
1577 cs->bcs[i].hw.isar.mml = msg;
1578 cs->bcs[i].mode = 0;
1579 cs->bcs[i].hw.isar.dpath = i + 1;
1580 modeisar(&cs->bcs[i], 0, 0);
1581 INIT_WORK(&cs->bcs[i].tqueue, (void *)(void *) isar_bh, &cs->bcs[i]);
1582 }
1583}
1584
1585void
1586isar_l2l1(struct PStack *st, int pr, void *arg)
1587{
1588 struct BCState *bcs = st->l1.bcs;
1589 struct sk_buff *skb = arg;
1590 int ret;
1591 u_long flags;
1592
1593 switch (pr) {
1594 case (PH_DATA | REQUEST):
1595 spin_lock_irqsave(&bcs->cs->lock, flags);
1596 if (bcs->tx_skb) {
1597 skb_queue_tail(&bcs->squeue, skb);
1598 } else {
1599 bcs->tx_skb = skb;
1600 test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
1601 if (bcs->cs->debug & L1_DEB_HSCX)
1602 debugl1(bcs->cs, "DRQ set BC_FLG_BUSY");
1603 bcs->hw.isar.txcnt = 0;
1604 bcs->cs->BC_Send_Data(bcs);
1605 }
1606 spin_unlock_irqrestore(&bcs->cs->lock, flags);
1607 break;
1608 case (PH_PULL | INDICATION):
1609 spin_lock_irqsave(&bcs->cs->lock, flags);
1610 if (bcs->tx_skb) {
1611 printk(KERN_WARNING "isar_l2l1: this shouldn't happen\n");
1612 } else {
1613 test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
1614 if (bcs->cs->debug & L1_DEB_HSCX)
1615 debugl1(bcs->cs, "PUI set BC_FLG_BUSY");
1616 bcs->tx_skb = skb;
1617 bcs->hw.isar.txcnt = 0;
1618 bcs->cs->BC_Send_Data(bcs);
1619 }
1620 spin_unlock_irqrestore(&bcs->cs->lock, flags);
1621 break;
1622 case (PH_PULL | REQUEST):
1623 if (!bcs->tx_skb) {
1624 test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
1625 st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
1626 } else
1627 test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
1628 break;
1629 case (PH_ACTIVATE | REQUEST):
1630 spin_lock_irqsave(&bcs->cs->lock, flags);
1631 test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag);
1632 bcs->hw.isar.conmsg[0] = 0;
1633 if (test_bit(FLG_ORIG, &st->l2.flag))
1634 test_and_set_bit(BC_FLG_ORIG, &bcs->Flag);
1635 else
1636 test_and_clear_bit(BC_FLG_ORIG, &bcs->Flag);
1637 switch(st->l1.mode) {
1638 case L1_MODE_TRANS:
1639 case L1_MODE_HDLC:
1640 ret = modeisar(bcs, st->l1.mode, st->l1.bc);
1641 spin_unlock_irqrestore(&bcs->cs->lock, flags);
1642 if (ret)
1643 l1_msg_b(st, PH_DEACTIVATE | REQUEST, arg);
1644 else
1645 l1_msg_b(st, PH_ACTIVATE | REQUEST, arg);
1646 break;
1647 case L1_MODE_V32:
1648 case L1_MODE_FAX:
1649 ret = modeisar(bcs, st->l1.mode, st->l1.bc);
1650 spin_unlock_irqrestore(&bcs->cs->lock, flags);
1651 if (ret)
1652 l1_msg_b(st, PH_DEACTIVATE | REQUEST, arg);
1653 break;
1654 default:
1655 spin_unlock_irqrestore(&bcs->cs->lock, flags);
1656 break;
1657 }
1658 break;
1659 case (PH_DEACTIVATE | REQUEST):
1660 l1_msg_b(st, pr, arg);
1661 break;
1662 case (PH_DEACTIVATE | CONFIRM):
1663 spin_lock_irqsave(&bcs->cs->lock, flags);
1664 switch(st->l1.mode) {
1665 case L1_MODE_TRANS:
1666 case L1_MODE_HDLC:
1667 case L1_MODE_V32:
1668 break;
1669 case L1_MODE_FAX:
1670 isar_pump_cmd(bcs, ISDN_FAXPUMP_HALT, 0);
1671 break;
1672 }
1673 test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag);
1674 test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
1675 if (bcs->cs->debug & L1_DEB_HSCX)
1676 debugl1(bcs->cs, "PDAC clear BC_FLG_BUSY");
1677 modeisar(bcs, 0, st->l1.bc);
1678 spin_unlock_irqrestore(&bcs->cs->lock, flags);
1679 st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
1680 break;
1681 }
1682}
1683
1684void
1685close_isarstate(struct BCState *bcs)
1686{
1687 modeisar(bcs, 0, bcs->channel);
1688 if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) {
1689 if (bcs->hw.isar.rcvbuf) {
1690 kfree(bcs->hw.isar.rcvbuf);
1691 bcs->hw.isar.rcvbuf = NULL;
1692 }
1693 skb_queue_purge(&bcs->rqueue);
1694 skb_queue_purge(&bcs->squeue);
1695 if (bcs->tx_skb) {
1696 dev_kfree_skb_any(bcs->tx_skb);
1697 bcs->tx_skb = NULL;
1698 test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
1699 if (bcs->cs->debug & L1_DEB_HSCX)
1700 debugl1(bcs->cs, "closeisar clear BC_FLG_BUSY");
1701 }
1702 }
1703 del_timer(&bcs->hw.isar.ftimer);
1704}
1705
1706int
1707open_isarstate(struct IsdnCardState *cs, struct BCState *bcs)
1708{
1709 if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
1710 if (!(bcs->hw.isar.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) {
1711 printk(KERN_WARNING
1712 "HiSax: No memory for isar.rcvbuf\n");
1713 return (1);
1714 }
1715 skb_queue_head_init(&bcs->rqueue);
1716 skb_queue_head_init(&bcs->squeue);
1717 }
1718 bcs->tx_skb = NULL;
1719 test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
1720 if (cs->debug & L1_DEB_HSCX)
1721 debugl1(cs, "openisar clear BC_FLG_BUSY");
1722 bcs->event = 0;
1723 bcs->hw.isar.rcvidx = 0;
1724 bcs->tx_cnt = 0;
1725 return (0);
1726}
1727
1728int
1729setstack_isar(struct PStack *st, struct BCState *bcs)
1730{
1731 bcs->channel = st->l1.bc;
1732 if (open_isarstate(st->l1.hardware, bcs))
1733 return (-1);
1734 st->l1.bcs = bcs;
1735 st->l2.l2l1 = isar_l2l1;
1736 setstack_manager(st);
1737 bcs->st = st;
1738 setstack_l1_B(st);
1739 return (0);
1740}
1741
1742int
1743isar_auxcmd(struct IsdnCardState *cs, isdn_ctrl *ic) {
1744 u_long adr;
1745 int features, i;
1746 struct BCState *bcs;
1747
1748 if (cs->debug & L1_DEB_HSCX)
1749 debugl1(cs, "isar_auxcmd cmd/ch %x/%d", ic->command, ic->arg);
1750 switch (ic->command) {
1751 case (ISDN_CMD_FAXCMD):
1752 bcs = cs->channel[ic->arg].bcs;
1753 if (cs->debug & L1_DEB_HSCX)
1754 debugl1(cs, "isar_auxcmd cmd/subcmd %d/%d",
1755 ic->parm.aux.cmd, ic->parm.aux.subcmd);
1756 switch(ic->parm.aux.cmd) {
1757 case ISDN_FAX_CLASS1_CTRL:
1758 if (ic->parm.aux.subcmd == ETX)
1759 test_and_set_bit(BC_FLG_DLEETX,
1760 &bcs->Flag);
1761 break;
1762 case ISDN_FAX_CLASS1_FTS:
1763 if (ic->parm.aux.subcmd == AT_QUERY) {
1764 ic->command = ISDN_STAT_FAXIND;
1765 ic->parm.aux.cmd = ISDN_FAX_CLASS1_OK;
1766 cs->iif.statcallb(ic);
1767 return(0);
1768 } else if (ic->parm.aux.subcmd == AT_EQ_QUERY) {
1769 strcpy(ic->parm.aux.para, "0-255");
1770 ic->command = ISDN_STAT_FAXIND;
1771 ic->parm.aux.cmd = ISDN_FAX_CLASS1_QUERY;
1772 cs->iif.statcallb(ic);
1773 return(0);
1774 } else if (ic->parm.aux.subcmd == AT_EQ_VALUE) {
1775 if (cs->debug & L1_DEB_HSCX)
1776 debugl1(cs, "isar_auxcmd %s=%d",
1777 FC1_CMD[ic->parm.aux.cmd], ic->parm.aux.para[0]);
1778 if (bcs->hw.isar.state == STFAX_READY) {
1779 if (! ic->parm.aux.para[0]) {
1780 ic->command = ISDN_STAT_FAXIND;
1781 ic->parm.aux.cmd = ISDN_FAX_CLASS1_OK;
1782 cs->iif.statcallb(ic);
1783 return(0);
1784 }
1785 if (! test_and_set_bit(BC_FLG_FTI_RUN, &bcs->Flag)) {
1786 /* n*10 ms */
1787 bcs->hw.isar.ftimer.expires =
1788 jiffies + ((ic->parm.aux.para[0] * 10 * HZ)/1000);
1789 test_and_set_bit(BC_FLG_FTI_FTS, &bcs->Flag);
1790 add_timer(&bcs->hw.isar.ftimer);
1791 return(0);
1792 } else {
1793 if (cs->debug)
1794 debugl1(cs, "isar FTS=%d and FTI busy",
1795 ic->parm.aux.para[0]);
1796 }
1797 } else {
1798 if (cs->debug)
1799 debugl1(cs, "isar FTS=%d and isar.state not ready(%x)",
1800 ic->parm.aux.para[0],bcs->hw.isar.state);
1801 }
1802 ic->command = ISDN_STAT_FAXIND;
1803 ic->parm.aux.cmd = ISDN_FAX_CLASS1_ERROR;
1804 cs->iif.statcallb(ic);
1805 }
1806 break;
1807 case ISDN_FAX_CLASS1_FRM:
1808 case ISDN_FAX_CLASS1_FRH:
1809 case ISDN_FAX_CLASS1_FTM:
1810 case ISDN_FAX_CLASS1_FTH:
1811 if (ic->parm.aux.subcmd == AT_QUERY) {
1812 sprintf(ic->parm.aux.para,
1813 "%d", bcs->hw.isar.mod);
1814 ic->command = ISDN_STAT_FAXIND;
1815 ic->parm.aux.cmd = ISDN_FAX_CLASS1_QUERY;
1816 cs->iif.statcallb(ic);
1817 return(0);
1818 } else if (ic->parm.aux.subcmd == AT_EQ_QUERY) {
1819 char *p = ic->parm.aux.para;
1820 for(i=0;i<FAXMODCNT;i++)
1821 if ((1<<i) & modmask)
1822 p += sprintf(p, "%d,", faxmodulation[i]);
1823 p--;
1824 *p=0;
1825 ic->command = ISDN_STAT_FAXIND;
1826 ic->parm.aux.cmd = ISDN_FAX_CLASS1_QUERY;
1827 cs->iif.statcallb(ic);
1828 return(0);
1829 } else if (ic->parm.aux.subcmd == AT_EQ_VALUE) {
1830 if (cs->debug & L1_DEB_HSCX)
1831 debugl1(cs, "isar_auxcmd %s=%d",
1832 FC1_CMD[ic->parm.aux.cmd], ic->parm.aux.para[0]);
1833 for(i=0;i<FAXMODCNT;i++)
1834 if (faxmodulation[i]==ic->parm.aux.para[0])
1835 break;
1836 if ((i < FAXMODCNT) && ((1<<i) & modmask) &&
1837 test_bit(BC_FLG_INIT, &bcs->Flag)) {
1838 isar_pump_cmd(bcs,
1839 ic->parm.aux.cmd,
1840 ic->parm.aux.para[0]);
1841 return(0);
1842 }
1843 }
1844 /* wrong modulation or not activ */
1845 /* fall through */
1846 default:
1847 ic->command = ISDN_STAT_FAXIND;
1848 ic->parm.aux.cmd = ISDN_FAX_CLASS1_ERROR;
1849 cs->iif.statcallb(ic);
1850 }
1851 break;
1852 case (ISDN_CMD_IOCTL):
1853 switch (ic->arg) {
1854 case 9: /* load firmware */
1855 features = ISDN_FEATURE_L2_MODEM |
1856 ISDN_FEATURE_L2_FAX |
1857 ISDN_FEATURE_L3_FCLASS1;
1858 memcpy(&adr, ic->parm.num, sizeof(ulong));
1859 if (isar_load_firmware(cs, (u_char __user *)adr))
1860 return(1);
1861 else
1862 ll_run(cs, features);
1863 break;
1864 case 20:
1865 features = *(unsigned int *) ic->parm.num;
1866 printk(KERN_DEBUG "HiSax: max modulation old(%04x) new(%04x)\n",
1867 modmask, features);
1868 modmask = features;
1869 break;
1870 case 21:
1871 features = *(unsigned int *) ic->parm.num;
1872 printk(KERN_DEBUG "HiSax: FRM extra delay old(%d) new(%d) ms\n",
1873 frm_extra_delay, features);
1874 if (features >= 0)
1875 frm_extra_delay = features;
1876 break;
1877 case 22:
1878 features = *(unsigned int *) ic->parm.num;
1879 printk(KERN_DEBUG "HiSax: TOA old(%d) new(%d) db\n",
1880 para_TOA, features);
1881 if (features >= 0 && features < 32)
1882 para_TOA = features;
1883 break;
1884 default:
1885 printk(KERN_DEBUG "HiSax: invalid ioctl %d\n",
1886 (int) ic->arg);
1887 return(-EINVAL);
1888 }
1889 break;
1890 default:
1891 return(-EINVAL);
1892 }
1893 return(0);
1894}
1895
1896void __devinit
1897initisar(struct IsdnCardState *cs)
1898{
1899 cs->bcs[0].BC_SetStack = setstack_isar;
1900 cs->bcs[1].BC_SetStack = setstack_isar;
1901 cs->bcs[0].BC_Close = close_isarstate;
1902 cs->bcs[1].BC_Close = close_isarstate;
1903 cs->bcs[0].hw.isar.ftimer.function = (void *) ftimer_handler;
1904 cs->bcs[0].hw.isar.ftimer.data = (long) &cs->bcs[0];
1905 init_timer(&cs->bcs[0].hw.isar.ftimer);
1906 cs->bcs[1].hw.isar.ftimer.function = (void *) ftimer_handler;
1907 cs->bcs[1].hw.isar.ftimer.data = (long) &cs->bcs[1];
1908 init_timer(&cs->bcs[1].hw.isar.ftimer);
1909}
diff --git a/drivers/isdn/hisax/isar.h b/drivers/isdn/hisax/isar.h
new file mode 100644
index 000000000000..bf7676586392
--- /dev/null
+++ b/drivers/isdn/hisax/isar.h
@@ -0,0 +1,222 @@
1/* $Id: isar.h,v 1.11.2.2 2004/01/12 22:52:27 keil Exp $
2 *
3 * ISAR (Siemens PSB 7110) specific defines
4 *
5 * Author Karsten Keil
6 * Copyright by Karsten Keil <keil@isdn4linux.de>
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 */
12
13#define ISAR_IRQMSK 0x04
14#define ISAR_IRQSTA 0x04
15#define ISAR_IRQBIT 0x75
16#define ISAR_CTRL_H 0x61
17#define ISAR_CTRL_L 0x60
18#define ISAR_IIS 0x58
19#define ISAR_IIA 0x58
20#define ISAR_HIS 0x50
21#define ISAR_HIA 0x50
22#define ISAR_MBOX 0x4c
23#define ISAR_WADR 0x4a
24#define ISAR_RADR 0x48
25
26#define ISAR_HIS_VNR 0x14
27#define ISAR_HIS_DKEY 0x02
28#define ISAR_HIS_FIRM 0x1e
29#define ISAR_HIS_STDSP 0x08
30#define ISAR_HIS_DIAG 0x05
31#define ISAR_HIS_WAITSTATE 0x27
32#define ISAR_HIS_TIMERIRQ 0x25
33#define ISAR_HIS_P0CFG 0x3c
34#define ISAR_HIS_P12CFG 0x24
35#define ISAR_HIS_SARTCFG 0x25
36#define ISAR_HIS_PUMPCFG 0x26
37#define ISAR_HIS_PUMPCTRL 0x2a
38#define ISAR_HIS_IOM2CFG 0x27
39#define ISAR_HIS_IOM2REQ 0x07
40#define ISAR_HIS_IOM2CTRL 0x2b
41#define ISAR_HIS_BSTREQ 0x0c
42#define ISAR_HIS_PSTREQ 0x0e
43#define ISAR_HIS_SDATA 0x20
44#define ISAR_HIS_DPS1 0x40
45#define ISAR_HIS_DPS2 0x80
46#define SET_DPS(x) ((x<<6) & 0xc0)
47
48#define ISAR_CMD_TIMERIRQ_OFF 0x20
49#define ISAR_CMD_TIMERIRQ_ON 0x21
50
51
52#define ISAR_IIS_MSCMSD 0x3f
53#define ISAR_IIS_VNR 0x15
54#define ISAR_IIS_DKEY 0x03
55#define ISAR_IIS_FIRM 0x1f
56#define ISAR_IIS_STDSP 0x09
57#define ISAR_IIS_DIAG 0x25
58#define ISAR_IIS_GSTEV 0x00
59#define ISAR_IIS_BSTEV 0x28
60#define ISAR_IIS_BSTRSP 0x2c
61#define ISAR_IIS_PSTRSP 0x2e
62#define ISAR_IIS_PSTEV 0x2a
63#define ISAR_IIS_IOM2RSP 0x27
64#define ISAR_IIS_RDATA 0x20
65#define ISAR_IIS_INVMSG 0x3f
66
67#define ISAR_CTRL_SWVER 0x10
68#define ISAR_CTRL_STST 0x40
69
70#define ISAR_MSG_HWVER {0x20, 0, 1}
71
72#define ISAR_DP1_USE 1
73#define ISAR_DP2_USE 2
74#define ISAR_RATE_REQ 3
75
76#define PMOD_DISABLE 0
77#define PMOD_FAX 1
78#define PMOD_DATAMODEM 2
79#define PMOD_HALFDUPLEX 3
80#define PMOD_V110 4
81#define PMOD_DTMF 5
82#define PMOD_DTMF_TRANS 6
83#define PMOD_BYPASS 7
84
85#define PCTRL_ORIG 0x80
86#define PV32P2_V23R 0x40
87#define PV32P2_V22A 0x20
88#define PV32P2_V22B 0x10
89#define PV32P2_V22C 0x08
90#define PV32P2_V21 0x02
91#define PV32P2_BEL 0x01
92
93// LSB MSB in ISAR doc wrong !!! Arghhh
94#define PV32P3_AMOD 0x80
95#define PV32P3_V32B 0x02
96#define PV32P3_V23B 0x01
97#define PV32P4_48 0x11
98#define PV32P5_48 0x05
99#define PV32P4_UT48 0x11
100#define PV32P5_UT48 0x0d
101#define PV32P4_96 0x11
102#define PV32P5_96 0x03
103#define PV32P4_UT96 0x11
104#define PV32P5_UT96 0x0f
105#define PV32P4_B96 0x91
106#define PV32P5_B96 0x0b
107#define PV32P4_UTB96 0xd1
108#define PV32P5_UTB96 0x0f
109#define PV32P4_120 0xb1
110#define PV32P5_120 0x09
111#define PV32P4_UT120 0xf1
112#define PV32P5_UT120 0x0f
113#define PV32P4_144 0x99
114#define PV32P5_144 0x09
115#define PV32P4_UT144 0xf9
116#define PV32P5_UT144 0x0f
117#define PV32P6_CTN 0x01
118#define PV32P6_ATN 0x02
119
120#define PFAXP2_CTN 0x01
121#define PFAXP2_ATN 0x04
122
123#define PSEV_10MS_TIMER 0x02
124#define PSEV_CON_ON 0x18
125#define PSEV_CON_OFF 0x19
126#define PSEV_V24_OFF 0x20
127#define PSEV_CTS_ON 0x21
128#define PSEV_CTS_OFF 0x22
129#define PSEV_DCD_ON 0x23
130#define PSEV_DCD_OFF 0x24
131#define PSEV_DSR_ON 0x25
132#define PSEV_DSR_OFF 0x26
133#define PSEV_REM_RET 0xcc
134#define PSEV_REM_REN 0xcd
135#define PSEV_GSTN_CLR 0xd4
136
137#define PSEV_RSP_READY 0xbc
138#define PSEV_LINE_TX_H 0xb3
139#define PSEV_LINE_TX_B 0xb2
140#define PSEV_LINE_RX_H 0xb1
141#define PSEV_LINE_RX_B 0xb0
142#define PSEV_RSP_CONN 0xb5
143#define PSEV_RSP_DISC 0xb7
144#define PSEV_RSP_FCERR 0xb9
145#define PSEV_RSP_SILDET 0xbe
146#define PSEV_RSP_SILOFF 0xab
147#define PSEV_FLAGS_DET 0xba
148
149#define PCTRL_CMD_FTH 0xa7
150#define PCTRL_CMD_FRH 0xa5
151#define PCTRL_CMD_FTM 0xa8
152#define PCTRL_CMD_FRM 0xa6
153#define PCTRL_CMD_SILON 0xac
154#define PCTRL_CMD_CONT 0xa2
155#define PCTRL_CMD_ESC 0xa4
156#define PCTRL_CMD_SILOFF 0xab
157#define PCTRL_CMD_HALT 0xa9
158
159#define PCTRL_LOC_RET 0xcf
160#define PCTRL_LOC_REN 0xce
161
162#define SMODE_DISABLE 0
163#define SMODE_V14 2
164#define SMODE_HDLC 3
165#define SMODE_BINARY 4
166#define SMODE_FSK_V14 5
167
168#define SCTRL_HDMC_BOTH 0x00
169#define SCTRL_HDMC_DTX 0x80
170#define SCTRL_HDMC_DRX 0x40
171#define S_P1_OVSP 0x40
172#define S_P1_SNP 0x20
173#define S_P1_EOP 0x10
174#define S_P1_EDP 0x08
175#define S_P1_NSB 0x04
176#define S_P1_CHS_8 0x03
177#define S_P1_CHS_7 0x02
178#define S_P1_CHS_6 0x01
179#define S_P1_CHS_5 0x00
180
181#define S_P2_BFT_DEF 0x10
182
183#define IOM_CTRL_ENA 0x80
184#define IOM_CTRL_NOPCM 0x00
185#define IOM_CTRL_ALAW 0x02
186#define IOM_CTRL_ULAW 0x04
187#define IOM_CTRL_RCV 0x01
188
189#define IOM_P1_TXD 0x10
190
191#define HDLC_FED 0x40
192#define HDLC_FSD 0x20
193#define HDLC_FST 0x20
194#define HDLC_ERROR 0x1c
195#define HDLC_ERR_FAD 0x10
196#define HDLC_ERR_RER 0x08
197#define HDLC_ERR_CER 0x04
198#define SART_NMD 0x01
199
200#define BSTAT_RDM0 0x1
201#define BSTAT_RDM1 0x2
202#define BSTAT_RDM2 0x4
203#define BSTAT_RDM3 0x8
204#define BSTEV_TBO 0x1f
205#define BSTEV_RBO 0x2f
206
207/* FAX State Machine */
208#define STFAX_NULL 0
209#define STFAX_READY 1
210#define STFAX_LINE 2
211#define STFAX_CONT 3
212#define STFAX_ACTIV 4
213#define STFAX_ESCAPE 5
214#define STFAX_SILDET 6
215
216#define ISDN_FAXPUMP_HALT 100
217
218extern int ISARVersion(struct IsdnCardState *cs, char *s);
219extern void isar_int_main(struct IsdnCardState *cs);
220extern void initisar(struct IsdnCardState *cs);
221extern void isar_fill_fifo(struct BCState *bcs);
222extern int isar_auxcmd(struct IsdnCardState *cs, isdn_ctrl *ic);
diff --git a/drivers/isdn/hisax/isdnhdlc.c b/drivers/isdn/hisax/isdnhdlc.c
new file mode 100644
index 000000000000..cbdf54c5af84
--- /dev/null
+++ b/drivers/isdn/hisax/isdnhdlc.c
@@ -0,0 +1,628 @@
1/*
2 * isdnhdlc.c -- General purpose ISDN HDLC decoder.
3 *
4 *Copyright (C) 2002 Wolfgang Mües <wolfgang@iksw-muees.de>
5 * 2001 Frode Isaksen <fisaksen@bewan.com>
6 * 2001 Kai Germaschewski <kai.germaschewski@gmx.de>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23#include <linux/module.h>
24#include <linux/init.h>
25#include <linux/crc-ccitt.h>
26#include "isdnhdlc.h"
27
28/*-------------------------------------------------------------------*/
29
30MODULE_AUTHOR("Wolfgang Mües <wolfgang@iksw-muees.de>, "
31 "Frode Isaksen <fisaksen@bewan.com>, "
32 "Kai Germaschewski <kai.germaschewski@gmx.de>");
33MODULE_DESCRIPTION("General purpose ISDN HDLC decoder");
34MODULE_LICENSE("GPL");
35
36/*-------------------------------------------------------------------*/
37
38/* bit swap table.
39 * Very handy for devices with different bit order,
40 * and neccessary for each transparent B-channel access for all
41 * devices which works with this HDLC decoder without bit reversal.
42 */
43const unsigned char isdnhdlc_bit_rev_tab[256] = {
44 0x00,0x80,0x40,0xC0,0x20,0xA0,0x60,0xE0,0x10,0x90,0x50,0xD0,0x30,0xB0,0x70,0xF0,
45 0x08,0x88,0x48,0xC8,0x28,0xA8,0x68,0xE8,0x18,0x98,0x58,0xD8,0x38,0xB8,0x78,0xF8,
46 0x04,0x84,0x44,0xC4,0x24,0xA4,0x64,0xE4,0x14,0x94,0x54,0xD4,0x34,0xB4,0x74,0xF4,
47 0x0C,0x8C,0x4C,0xCC,0x2C,0xAC,0x6C,0xEC,0x1C,0x9C,0x5C,0xDC,0x3C,0xBC,0x7C,0xFC,
48 0x02,0x82,0x42,0xC2,0x22,0xA2,0x62,0xE2,0x12,0x92,0x52,0xD2,0x32,0xB2,0x72,0xF2,
49 0x0A,0x8A,0x4A,0xCA,0x2A,0xAA,0x6A,0xEA,0x1A,0x9A,0x5A,0xDA,0x3A,0xBA,0x7A,0xFA,
50 0x06,0x86,0x46,0xC6,0x26,0xA6,0x66,0xE6,0x16,0x96,0x56,0xD6,0x36,0xB6,0x76,0xF6,
51 0x0E,0x8E,0x4E,0xCE,0x2E,0xAE,0x6E,0xEE,0x1E,0x9E,0x5E,0xDE,0x3E,0xBE,0x7E,0xFE,
52 0x01,0x81,0x41,0xC1,0x21,0xA1,0x61,0xE1,0x11,0x91,0x51,0xD1,0x31,0xB1,0x71,0xF1,
53 0x09,0x89,0x49,0xC9,0x29,0xA9,0x69,0xE9,0x19,0x99,0x59,0xD9,0x39,0xB9,0x79,0xF9,
54 0x05,0x85,0x45,0xC5,0x25,0xA5,0x65,0xE5,0x15,0x95,0x55,0xD5,0x35,0xB5,0x75,0xF5,
55 0x0D,0x8D,0x4D,0xCD,0x2D,0xAD,0x6D,0xED,0x1D,0x9D,0x5D,0xDD,0x3D,0xBD,0x7D,0xFD,
56 0x03,0x83,0x43,0xC3,0x23,0xA3,0x63,0xE3,0x13,0x93,0x53,0xD3,0x33,0xB3,0x73,0xF3,
57 0x0B,0x8B,0x4B,0xCB,0x2B,0xAB,0x6B,0xEB,0x1B,0x9B,0x5B,0xDB,0x3B,0xBB,0x7B,0xFB,
58 0x07,0x87,0x47,0xC7,0x27,0xA7,0x67,0xE7,0x17,0x97,0x57,0xD7,0x37,0xB7,0x77,0xF7,
59 0x0F,0x8F,0x4F,0xCF,0x2F,0xAF,0x6F,0xEF,0x1F,0x9F,0x5F,0xDF,0x3F,0xBF,0x7F,0xFF
60};
61
62enum {
63 HDLC_FAST_IDLE,HDLC_GET_FLAG_B0,HDLC_GETFLAG_B1A6,HDLC_GETFLAG_B7,
64 HDLC_GET_DATA,HDLC_FAST_FLAG
65};
66
67enum {
68 HDLC_SEND_DATA,HDLC_SEND_CRC1,HDLC_SEND_FAST_FLAG,
69 HDLC_SEND_FIRST_FLAG,HDLC_SEND_CRC2,HDLC_SEND_CLOSING_FLAG,
70 HDLC_SEND_IDLE1,HDLC_SEND_FAST_IDLE,HDLC_SENDFLAG_B0,
71 HDLC_SENDFLAG_B1A6,HDLC_SENDFLAG_B7,STOPPED
72};
73
74void isdnhdlc_rcv_init (struct isdnhdlc_vars *hdlc, int do_adapt56)
75{
76 hdlc->bit_shift = 0;
77 hdlc->hdlc_bits1 = 0;
78 hdlc->data_bits = 0;
79 hdlc->ffbit_shift = 0;
80 hdlc->data_received = 0;
81 hdlc->state = HDLC_GET_DATA;
82 hdlc->do_adapt56 = do_adapt56;
83 hdlc->dchannel = 0;
84 hdlc->crc = 0;
85 hdlc->cbin = 0;
86 hdlc->shift_reg = 0;
87 hdlc->ffvalue = 0;
88 hdlc->dstpos = 0;
89}
90
91void isdnhdlc_out_init (struct isdnhdlc_vars *hdlc, int is_d_channel, int do_adapt56)
92{
93 hdlc->bit_shift = 0;
94 hdlc->hdlc_bits1 = 0;
95 hdlc->data_bits = 0;
96 hdlc->ffbit_shift = 0;
97 hdlc->data_received = 0;
98 hdlc->do_closing = 0;
99 hdlc->ffvalue = 0;
100 if (is_d_channel) {
101 hdlc->dchannel = 1;
102 hdlc->state = HDLC_SEND_FIRST_FLAG;
103 } else {
104 hdlc->dchannel = 0;
105 hdlc->state = HDLC_SEND_FAST_FLAG;
106 hdlc->ffvalue = 0x7e;
107 }
108 hdlc->cbin = 0x7e;
109 hdlc->bit_shift = 0;
110 if(do_adapt56){
111 hdlc->do_adapt56 = 1;
112 hdlc->data_bits = 0;
113 hdlc->state = HDLC_SENDFLAG_B0;
114 } else {
115 hdlc->do_adapt56 = 0;
116 hdlc->data_bits = 8;
117 }
118 hdlc->shift_reg = 0;
119}
120
121/*
122 isdnhdlc_decode - decodes HDLC frames from a transparent bit stream.
123
124 The source buffer is scanned for valid HDLC frames looking for
125 flags (01111110) to indicate the start of a frame. If the start of
126 the frame is found, the bit stuffing is removed (0 after 5 1's).
127 When a new flag is found, the complete frame has been received
128 and the CRC is checked.
129 If a valid frame is found, the function returns the frame length
130 excluding the CRC with the bit HDLC_END_OF_FRAME set.
131 If the beginning of a valid frame is found, the function returns
132 the length.
133 If a framing error is found (too many 1s and not a flag) the function
134 returns the length with the bit HDLC_FRAMING_ERROR set.
135 If a CRC error is found the function returns the length with the
136 bit HDLC_CRC_ERROR set.
137 If the frame length exceeds the destination buffer size, the function
138 returns the length with the bit HDLC_LENGTH_ERROR set.
139
140 src - source buffer
141 slen - source buffer length
142 count - number of bytes removed (decoded) from the source buffer
143 dst _ destination buffer
144 dsize - destination buffer size
145 returns - number of decoded bytes in the destination buffer and status
146 flag.
147 */
148int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src,
149 int slen, int *count, unsigned char *dst, int dsize)
150{
151 int status=0;
152
153 static const unsigned char fast_flag[]={
154 0x00,0x00,0x00,0x20,0x30,0x38,0x3c,0x3e,0x3f
155 };
156
157 static const unsigned char fast_flag_value[]={
158 0x00,0x7e,0xfc,0xf9,0xf3,0xe7,0xcf,0x9f,0x3f
159 };
160
161 static const unsigned char fast_abort[]={
162 0x00,0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff
163 };
164
165 *count = slen;
166
167 while(slen > 0){
168 if(hdlc->bit_shift==0){
169 hdlc->cbin = *src++;
170 slen--;
171 hdlc->bit_shift = 8;
172 if(hdlc->do_adapt56){
173 hdlc->bit_shift --;
174 }
175 }
176
177 switch(hdlc->state){
178 case STOPPED:
179 return 0;
180 case HDLC_FAST_IDLE:
181 if(hdlc->cbin == 0xff){
182 hdlc->bit_shift = 0;
183 break;
184 }
185 hdlc->state = HDLC_GET_FLAG_B0;
186 hdlc->hdlc_bits1 = 0;
187 hdlc->bit_shift = 8;
188 break;
189 case HDLC_GET_FLAG_B0:
190 if(!(hdlc->cbin & 0x80)) {
191 hdlc->state = HDLC_GETFLAG_B1A6;
192 hdlc->hdlc_bits1 = 0;
193 } else {
194 if(!hdlc->do_adapt56){
195 if(++hdlc->hdlc_bits1 >=8 ) if(hdlc->bit_shift==1)
196 hdlc->state = HDLC_FAST_IDLE;
197 }
198 }
199 hdlc->cbin<<=1;
200 hdlc->bit_shift --;
201 break;
202 case HDLC_GETFLAG_B1A6:
203 if(hdlc->cbin & 0x80){
204 hdlc->hdlc_bits1++;
205 if(hdlc->hdlc_bits1==6){
206 hdlc->state = HDLC_GETFLAG_B7;
207 }
208 } else {
209 hdlc->hdlc_bits1 = 0;
210 }
211 hdlc->cbin<<=1;
212 hdlc->bit_shift --;
213 break;
214 case HDLC_GETFLAG_B7:
215 if(hdlc->cbin & 0x80) {
216 hdlc->state = HDLC_GET_FLAG_B0;
217 } else {
218 hdlc->state = HDLC_GET_DATA;
219 hdlc->crc = 0xffff;
220 hdlc->shift_reg = 0;
221 hdlc->hdlc_bits1 = 0;
222 hdlc->data_bits = 0;
223 hdlc->data_received = 0;
224 }
225 hdlc->cbin<<=1;
226 hdlc->bit_shift --;
227 break;
228 case HDLC_GET_DATA:
229 if(hdlc->cbin & 0x80){
230 hdlc->hdlc_bits1++;
231 switch(hdlc->hdlc_bits1){
232 case 6:
233 break;
234 case 7:
235 if(hdlc->data_received) {
236 // bad frame
237 status = -HDLC_FRAMING_ERROR;
238 }
239 if(!hdlc->do_adapt56){
240 if(hdlc->cbin==fast_abort[hdlc->bit_shift+1]){
241 hdlc->state = HDLC_FAST_IDLE;
242 hdlc->bit_shift=1;
243 break;
244 }
245 } else {
246 hdlc->state = HDLC_GET_FLAG_B0;
247 }
248 break;
249 default:
250 hdlc->shift_reg>>=1;
251 hdlc->shift_reg |= 0x80;
252 hdlc->data_bits++;
253 break;
254 }
255 } else {
256 switch(hdlc->hdlc_bits1){
257 case 5:
258 break;
259 case 6:
260 if(hdlc->data_received){
261 if (hdlc->dstpos < 2) {
262 status = -HDLC_FRAMING_ERROR;
263 } else if (hdlc->crc != 0xf0b8){
264 // crc error
265 status = -HDLC_CRC_ERROR;
266 } else {
267 // remove CRC
268 hdlc->dstpos -= 2;
269 // good frame
270 status = hdlc->dstpos;
271 }
272 }
273 hdlc->crc = 0xffff;
274 hdlc->shift_reg = 0;
275 hdlc->data_bits = 0;
276 if(!hdlc->do_adapt56){
277 if(hdlc->cbin==fast_flag[hdlc->bit_shift]){
278 hdlc->ffvalue = fast_flag_value[hdlc->bit_shift];
279 hdlc->state = HDLC_FAST_FLAG;
280 hdlc->ffbit_shift = hdlc->bit_shift;
281 hdlc->bit_shift = 1;
282 } else {
283 hdlc->state = HDLC_GET_DATA;
284 hdlc->data_received = 0;
285 }
286 } else {
287 hdlc->state = HDLC_GET_DATA;
288 hdlc->data_received = 0;
289 }
290 break;
291 default:
292 hdlc->shift_reg>>=1;
293 hdlc->data_bits++;
294 break;
295 }
296 hdlc->hdlc_bits1 = 0;
297 }
298 if (status) {
299 hdlc->dstpos = 0;
300 *count -= slen;
301 hdlc->cbin <<= 1;
302 hdlc->bit_shift--;
303 return status;
304 }
305 if(hdlc->data_bits==8){
306 hdlc->data_bits = 0;
307 hdlc->data_received = 1;
308 hdlc->crc = crc_ccitt_byte(hdlc->crc, hdlc->shift_reg);
309
310 // good byte received
311 if (hdlc->dstpos < dsize) {
312 dst[hdlc->dstpos++] = hdlc->shift_reg;
313 } else {
314 // frame too long
315 status = -HDLC_LENGTH_ERROR;
316 hdlc->dstpos = 0;
317 }
318 }
319 hdlc->cbin <<= 1;
320 hdlc->bit_shift--;
321 break;
322 case HDLC_FAST_FLAG:
323 if(hdlc->cbin==hdlc->ffvalue){
324 hdlc->bit_shift = 0;
325 break;
326 } else {
327 if(hdlc->cbin == 0xff){
328 hdlc->state = HDLC_FAST_IDLE;
329 hdlc->bit_shift=0;
330 } else if(hdlc->ffbit_shift==8){
331 hdlc->state = HDLC_GETFLAG_B7;
332 break;
333 } else {
334 hdlc->shift_reg = fast_abort[hdlc->ffbit_shift-1];
335 hdlc->hdlc_bits1 = hdlc->ffbit_shift-2;
336 if(hdlc->hdlc_bits1<0)hdlc->hdlc_bits1 = 0;
337 hdlc->data_bits = hdlc->ffbit_shift-1;
338 hdlc->state = HDLC_GET_DATA;
339 hdlc->data_received = 0;
340 }
341 }
342 break;
343 default:
344 break;
345 }
346 }
347 *count -= slen;
348 return 0;
349}
350
351/*
352 isdnhdlc_encode - encodes HDLC frames to a transparent bit stream.
353
354 The bit stream starts with a beginning flag (01111110). After
355 that each byte is added to the bit stream with bit stuffing added
356 (0 after 5 1's).
357 When the last byte has been removed from the source buffer, the
358 CRC (2 bytes is added) and the frame terminates with the ending flag.
359 For the dchannel, the idle character (all 1's) is also added at the end.
360 If this function is called with empty source buffer (slen=0), flags or
361 idle character will be generated.
362
363 src - source buffer
364 slen - source buffer length
365 count - number of bytes removed (encoded) from source buffer
366 dst _ destination buffer
367 dsize - destination buffer size
368 returns - number of encoded bytes in the destination buffer
369*/
370int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src,
371 unsigned short slen, int *count,
372 unsigned char *dst, int dsize)
373{
374 static const unsigned char xfast_flag_value[] = {
375 0x7e,0x3f,0x9f,0xcf,0xe7,0xf3,0xf9,0xfc,0x7e
376 };
377
378 int len = 0;
379
380 *count = slen;
381
382 while (dsize > 0) {
383 if(hdlc->bit_shift==0){
384 if(slen && !hdlc->do_closing){
385 hdlc->shift_reg = *src++;
386 slen--;
387 if (slen == 0)
388 hdlc->do_closing = 1; /* closing sequence, CRC + flag(s) */
389 hdlc->bit_shift = 8;
390 } else {
391 if(hdlc->state == HDLC_SEND_DATA){
392 if(hdlc->data_received){
393 hdlc->state = HDLC_SEND_CRC1;
394 hdlc->crc ^= 0xffff;
395 hdlc->bit_shift = 8;
396 hdlc->shift_reg = hdlc->crc & 0xff;
397 } else if(!hdlc->do_adapt56){
398 hdlc->state = HDLC_SEND_FAST_FLAG;
399 } else {
400 hdlc->state = HDLC_SENDFLAG_B0;
401 }
402 }
403
404 }
405 }
406
407 switch(hdlc->state){
408 case STOPPED:
409 while (dsize--)
410 *dst++ = 0xff;
411
412 return dsize;
413 case HDLC_SEND_FAST_FLAG:
414 hdlc->do_closing = 0;
415 if(slen == 0){
416 *dst++ = hdlc->ffvalue;
417 len++;
418 dsize--;
419 break;
420 }
421 if(hdlc->bit_shift==8){
422 hdlc->cbin = hdlc->ffvalue>>(8-hdlc->data_bits);
423 hdlc->state = HDLC_SEND_DATA;
424 hdlc->crc = 0xffff;
425 hdlc->hdlc_bits1 = 0;
426 hdlc->data_received = 1;
427 }
428 break;
429 case HDLC_SENDFLAG_B0:
430 hdlc->do_closing = 0;
431 hdlc->cbin <<= 1;
432 hdlc->data_bits++;
433 hdlc->hdlc_bits1 = 0;
434 hdlc->state = HDLC_SENDFLAG_B1A6;
435 break;
436 case HDLC_SENDFLAG_B1A6:
437 hdlc->cbin <<= 1;
438 hdlc->data_bits++;
439 hdlc->cbin++;
440 if(++hdlc->hdlc_bits1 == 6)
441 hdlc->state = HDLC_SENDFLAG_B7;
442 break;
443 case HDLC_SENDFLAG_B7:
444 hdlc->cbin <<= 1;
445 hdlc->data_bits++;
446 if(slen == 0){
447 hdlc->state = HDLC_SENDFLAG_B0;
448 break;
449 }
450 if(hdlc->bit_shift==8){
451 hdlc->state = HDLC_SEND_DATA;
452 hdlc->crc = 0xffff;
453 hdlc->hdlc_bits1 = 0;
454 hdlc->data_received = 1;
455 }
456 break;
457 case HDLC_SEND_FIRST_FLAG:
458 hdlc->data_received = 1;
459 if(hdlc->data_bits==8){
460 hdlc->state = HDLC_SEND_DATA;
461 hdlc->crc = 0xffff;
462 hdlc->hdlc_bits1 = 0;
463 break;
464 }
465 hdlc->cbin <<= 1;
466 hdlc->data_bits++;
467 if(hdlc->shift_reg & 0x01)
468 hdlc->cbin++;
469 hdlc->shift_reg >>= 1;
470 hdlc->bit_shift--;
471 if(hdlc->bit_shift==0){
472 hdlc->state = HDLC_SEND_DATA;
473 hdlc->crc = 0xffff;
474 hdlc->hdlc_bits1 = 0;
475 }
476 break;
477 case HDLC_SEND_DATA:
478 hdlc->cbin <<= 1;
479 hdlc->data_bits++;
480 if(hdlc->hdlc_bits1 == 5){
481 hdlc->hdlc_bits1 = 0;
482 break;
483 }
484 if(hdlc->bit_shift==8){
485 hdlc->crc = crc_ccitt_byte(hdlc->crc, hdlc->shift_reg);
486 }
487 if(hdlc->shift_reg & 0x01){
488 hdlc->hdlc_bits1++;
489 hdlc->cbin++;
490 hdlc->shift_reg >>= 1;
491 hdlc->bit_shift--;
492 } else {
493 hdlc->hdlc_bits1 = 0;
494 hdlc->shift_reg >>= 1;
495 hdlc->bit_shift--;
496 }
497 break;
498 case HDLC_SEND_CRC1:
499 hdlc->cbin <<= 1;
500 hdlc->data_bits++;
501 if(hdlc->hdlc_bits1 == 5){
502 hdlc->hdlc_bits1 = 0;
503 break;
504 }
505 if(hdlc->shift_reg & 0x01){
506 hdlc->hdlc_bits1++;
507 hdlc->cbin++;
508 hdlc->shift_reg >>= 1;
509 hdlc->bit_shift--;
510 } else {
511 hdlc->hdlc_bits1 = 0;
512 hdlc->shift_reg >>= 1;
513 hdlc->bit_shift--;
514 }
515 if(hdlc->bit_shift==0){
516 hdlc->shift_reg = (hdlc->crc >> 8);
517 hdlc->state = HDLC_SEND_CRC2;
518 hdlc->bit_shift = 8;
519 }
520 break;
521 case HDLC_SEND_CRC2:
522 hdlc->cbin <<= 1;
523 hdlc->data_bits++;
524 if(hdlc->hdlc_bits1 == 5){
525 hdlc->hdlc_bits1 = 0;
526 break;
527 }
528 if(hdlc->shift_reg & 0x01){
529 hdlc->hdlc_bits1++;
530 hdlc->cbin++;
531 hdlc->shift_reg >>= 1;
532 hdlc->bit_shift--;
533 } else {
534 hdlc->hdlc_bits1 = 0;
535 hdlc->shift_reg >>= 1;
536 hdlc->bit_shift--;
537 }
538 if(hdlc->bit_shift==0){
539 hdlc->shift_reg = 0x7e;
540 hdlc->state = HDLC_SEND_CLOSING_FLAG;
541 hdlc->bit_shift = 8;
542 }
543 break;
544 case HDLC_SEND_CLOSING_FLAG:
545 hdlc->cbin <<= 1;
546 hdlc->data_bits++;
547 if(hdlc->hdlc_bits1 == 5){
548 hdlc->hdlc_bits1 = 0;
549 break;
550 }
551 if(hdlc->shift_reg & 0x01){
552 hdlc->cbin++;
553 }
554 hdlc->shift_reg >>= 1;
555 hdlc->bit_shift--;
556 if(hdlc->bit_shift==0){
557 hdlc->ffvalue = xfast_flag_value[hdlc->data_bits];
558 if(hdlc->dchannel){
559 hdlc->ffvalue = 0x7e;
560 hdlc->state = HDLC_SEND_IDLE1;
561 hdlc->bit_shift = 8-hdlc->data_bits;
562 if(hdlc->bit_shift==0)
563 hdlc->state = HDLC_SEND_FAST_IDLE;
564 } else {
565 if(!hdlc->do_adapt56){
566 hdlc->state = HDLC_SEND_FAST_FLAG;
567 hdlc->data_received = 0;
568 } else {
569 hdlc->state = HDLC_SENDFLAG_B0;
570 hdlc->data_received = 0;
571 }
572 // Finished with this frame, send flags
573 if (dsize > 1) dsize = 1;
574 }
575 }
576 break;
577 case HDLC_SEND_IDLE1:
578 hdlc->do_closing = 0;
579 hdlc->cbin <<= 1;
580 hdlc->cbin++;
581 hdlc->data_bits++;
582 hdlc->bit_shift--;
583 if(hdlc->bit_shift==0){
584 hdlc->state = HDLC_SEND_FAST_IDLE;
585 hdlc->bit_shift = 0;
586 }
587 break;
588 case HDLC_SEND_FAST_IDLE:
589 hdlc->do_closing = 0;
590 hdlc->cbin = 0xff;
591 hdlc->data_bits = 8;
592 if(hdlc->bit_shift == 8){
593 hdlc->cbin = 0x7e;
594 hdlc->state = HDLC_SEND_FIRST_FLAG;
595 } else {
596 *dst++ = hdlc->cbin;
597 hdlc->bit_shift = hdlc->data_bits = 0;
598 len++;
599 dsize = 0;
600 }
601 break;
602 default:
603 break;
604 }
605 if(hdlc->do_adapt56){
606 if(hdlc->data_bits==7){
607 hdlc->cbin <<= 1;
608 hdlc->cbin++;
609 hdlc->data_bits++;
610 }
611 }
612 if(hdlc->data_bits==8){
613 *dst++ = hdlc->cbin;
614 hdlc->data_bits = 0;
615 len++;
616 dsize--;
617 }
618 }
619 *count -= slen;
620
621 return len;
622}
623
624EXPORT_SYMBOL(isdnhdlc_bit_rev_tab);
625EXPORT_SYMBOL(isdnhdlc_rcv_init);
626EXPORT_SYMBOL(isdnhdlc_decode);
627EXPORT_SYMBOL(isdnhdlc_out_init);
628EXPORT_SYMBOL(isdnhdlc_encode);
diff --git a/drivers/isdn/hisax/isdnhdlc.h b/drivers/isdn/hisax/isdnhdlc.h
new file mode 100644
index 000000000000..269315988dc8
--- /dev/null
+++ b/drivers/isdn/hisax/isdnhdlc.h
@@ -0,0 +1,72 @@
1/*
2 * isdnhdlc.h -- General purpose ISDN HDLC decoder.
3 *
4 * Implementation of a HDLC decoder/encoder in software.
5 * Neccessary because some ISDN devices don't have HDLC
6 * controllers. Also included: a bit reversal table.
7 *
8 *Copyright (C) 2002 Wolfgang Mües <wolfgang@iksw-muees.de>
9 * 2001 Frode Isaksen <fisaksen@bewan.com>
10 * 2001 Kai Germaschewski <kai.germaschewski@gmx.de>
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 */
26
27#ifndef __ISDNHDLC_H__
28#define __ISDNHDLC_H__
29
30struct isdnhdlc_vars {
31 int bit_shift;
32 int hdlc_bits1;
33 int data_bits;
34 int ffbit_shift; // encoding only
35 int state;
36 int dstpos;
37
38 unsigned short crc;
39
40 unsigned char cbin;
41 unsigned char shift_reg;
42 unsigned char ffvalue;
43
44 int data_received:1; // set if transferring data
45 int dchannel:1; // set if D channel (send idle instead of flags)
46 int do_adapt56:1; // set if 56K adaptation
47 int do_closing:1; // set if in closing phase (need to send CRC + flag
48};
49
50
51/*
52 The return value from isdnhdlc_decode is
53 the frame length, 0 if no complete frame was decoded,
54 or a negative error number
55*/
56#define HDLC_FRAMING_ERROR 1
57#define HDLC_CRC_ERROR 2
58#define HDLC_LENGTH_ERROR 3
59
60extern const unsigned char isdnhdlc_bit_rev_tab[256];
61
62extern void isdnhdlc_rcv_init (struct isdnhdlc_vars *hdlc, int do_adapt56);
63
64extern int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src, int slen,int *count,
65 unsigned char *dst, int dsize);
66
67extern void isdnhdlc_out_init (struct isdnhdlc_vars *hdlc,int is_d_channel,int do_adapt56);
68
69extern int isdnhdlc_encode (struct isdnhdlc_vars *hdlc,const unsigned char *src,unsigned short slen,int *count,
70 unsigned char *dst,int dsize);
71
72#endif /* __ISDNHDLC_H__ */
diff --git a/drivers/isdn/hisax/isdnl1.c b/drivers/isdn/hisax/isdnl1.c
new file mode 100644
index 000000000000..4d08d27f1499
--- /dev/null
+++ b/drivers/isdn/hisax/isdnl1.c
@@ -0,0 +1,932 @@
1/* $Id: isdnl1.c,v 2.46.2.5 2004/02/11 13:21:34 keil Exp $
2 *
3 * common low level stuff for Siemens Chipsetbased isdn cards
4 *
5 * Author Karsten Keil
6 * based on the teles driver from Jan den Ouden
7 * Copyright by Karsten Keil <keil@isdn4linux.de>
8 *
9 * This software may be used and distributed according to the terms
10 * of the GNU General Public License, incorporated herein by reference.
11 *
12 * For changes and modifications please read
13 * Documentation/isdn/HiSax.cert
14 *
15 * Thanks to Jan den Ouden
16 * Fritz Elfert
17 * Beat Doebeli
18 *
19 */
20
21const char *l1_revision = "$Revision: 2.46.2.5 $";
22
23#include <linux/init.h>
24#include "hisax.h"
25#include "isdnl1.h"
26
27#define TIMER3_VALUE 7000
28
29static struct Fsm l1fsm_b;
30static struct Fsm l1fsm_s;
31
32enum {
33 ST_L1_F2,
34 ST_L1_F3,
35 ST_L1_F4,
36 ST_L1_F5,
37 ST_L1_F6,
38 ST_L1_F7,
39 ST_L1_F8,
40};
41
42#define L1S_STATE_COUNT (ST_L1_F8+1)
43
44static char *strL1SState[] =
45{
46 "ST_L1_F2",
47 "ST_L1_F3",
48 "ST_L1_F4",
49 "ST_L1_F5",
50 "ST_L1_F6",
51 "ST_L1_F7",
52 "ST_L1_F8",
53};
54
55#ifdef HISAX_UINTERFACE
56static
57struct Fsm l1fsm_u =
58{NULL, 0, 0, NULL, NULL};
59
60enum {
61 ST_L1_RESET,
62 ST_L1_DEACT,
63 ST_L1_SYNC2,
64 ST_L1_TRANS,
65};
66
67#define L1U_STATE_COUNT (ST_L1_TRANS+1)
68
69static char *strL1UState[] =
70{
71 "ST_L1_RESET",
72 "ST_L1_DEACT",
73 "ST_L1_SYNC2",
74 "ST_L1_TRANS",
75};
76#endif
77
78enum {
79 ST_L1_NULL,
80 ST_L1_WAIT_ACT,
81 ST_L1_WAIT_DEACT,
82 ST_L1_ACTIV,
83};
84
85#define L1B_STATE_COUNT (ST_L1_ACTIV+1)
86
87static char *strL1BState[] =
88{
89 "ST_L1_NULL",
90 "ST_L1_WAIT_ACT",
91 "ST_L1_WAIT_DEACT",
92 "ST_L1_ACTIV",
93};
94
95enum {
96 EV_PH_ACTIVATE,
97 EV_PH_DEACTIVATE,
98 EV_RESET_IND,
99 EV_DEACT_CNF,
100 EV_DEACT_IND,
101 EV_POWER_UP,
102 EV_RSYNC_IND,
103 EV_INFO2_IND,
104 EV_INFO4_IND,
105 EV_TIMER_DEACT,
106 EV_TIMER_ACT,
107 EV_TIMER3,
108};
109
110#define L1_EVENT_COUNT (EV_TIMER3 + 1)
111
112static char *strL1Event[] =
113{
114 "EV_PH_ACTIVATE",
115 "EV_PH_DEACTIVATE",
116 "EV_RESET_IND",
117 "EV_DEACT_CNF",
118 "EV_DEACT_IND",
119 "EV_POWER_UP",
120 "EV_RSYNC_IND",
121 "EV_INFO2_IND",
122 "EV_INFO4_IND",
123 "EV_TIMER_DEACT",
124 "EV_TIMER_ACT",
125 "EV_TIMER3",
126};
127
128void
129debugl1(struct IsdnCardState *cs, char *fmt, ...)
130{
131 va_list args;
132 char tmp[8];
133
134 va_start(args, fmt);
135 sprintf(tmp, "Card%d ", cs->cardnr + 1);
136 VHiSax_putstatus(cs, tmp, fmt, args);
137 va_end(args);
138}
139
140static void
141l1m_debug(struct FsmInst *fi, char *fmt, ...)
142{
143 va_list args;
144 struct PStack *st = fi->userdata;
145 struct IsdnCardState *cs = st->l1.hardware;
146 char tmp[8];
147
148 va_start(args, fmt);
149 sprintf(tmp, "Card%d ", cs->cardnr + 1);
150 VHiSax_putstatus(cs, tmp, fmt, args);
151 va_end(args);
152}
153
154void
155L1activated(struct IsdnCardState *cs)
156{
157 struct PStack *st;
158
159 st = cs->stlist;
160 while (st) {
161 if (test_and_clear_bit(FLG_L1_ACTIVATING, &st->l1.Flags))
162 st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL);
163 else
164 st->l1.l1l2(st, PH_ACTIVATE | INDICATION, NULL);
165 st = st->next;
166 }
167}
168
169void
170L1deactivated(struct IsdnCardState *cs)
171{
172 struct PStack *st;
173
174 st = cs->stlist;
175 while (st) {
176 if (test_bit(FLG_L1_DBUSY, &cs->HW_Flags))
177 st->l1.l1l2(st, PH_PAUSE | CONFIRM, NULL);
178 st->l1.l1l2(st, PH_DEACTIVATE | INDICATION, NULL);
179 st = st->next;
180 }
181 test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags);
182}
183
184void
185DChannel_proc_xmt(struct IsdnCardState *cs)
186{
187 struct PStack *stptr;
188
189 if (cs->tx_skb)
190 return;
191
192 stptr = cs->stlist;
193 while (stptr != NULL) {
194 if (test_and_clear_bit(FLG_L1_PULL_REQ, &stptr->l1.Flags)) {
195 stptr->l1.l1l2(stptr, PH_PULL | CONFIRM, NULL);
196 break;
197 } else
198 stptr = stptr->next;
199 }
200}
201
202void
203DChannel_proc_rcv(struct IsdnCardState *cs)
204{
205 struct sk_buff *skb, *nskb;
206 struct PStack *stptr = cs->stlist;
207 int found, tei, sapi;
208
209 if (stptr)
210 if (test_bit(FLG_L1_ACTTIMER, &stptr->l1.Flags))
211 FsmEvent(&stptr->l1.l1m, EV_TIMER_ACT, NULL);
212 while ((skb = skb_dequeue(&cs->rq))) {
213#ifdef L2FRAME_DEBUG /* psa */
214 if (cs->debug & L1_DEB_LAPD)
215 Logl2Frame(cs, skb, "PH_DATA", 1);
216#endif
217 stptr = cs->stlist;
218 if (skb->len<3) {
219 debugl1(cs, "D-channel frame too short(%d)",skb->len);
220 dev_kfree_skb(skb);
221 return;
222 }
223 if ((skb->data[0] & 1) || !(skb->data[1] &1)) {
224 debugl1(cs, "D-channel frame wrong EA0/EA1");
225 dev_kfree_skb(skb);
226 return;
227 }
228 sapi = skb->data[0] >> 2;
229 tei = skb->data[1] >> 1;
230 if (cs->debug & DEB_DLOG_HEX)
231 LogFrame(cs, skb->data, skb->len);
232 if (cs->debug & DEB_DLOG_VERBOSE)
233 dlogframe(cs, skb, 1);
234 if (tei == GROUP_TEI) {
235 if (sapi == CTRL_SAPI) { /* sapi 0 */
236 while (stptr != NULL) {
237 if ((nskb = skb_clone(skb, GFP_ATOMIC)))
238 stptr->l1.l1l2(stptr, PH_DATA | INDICATION, nskb);
239 else
240 printk(KERN_WARNING "HiSax: isdn broadcast buffer shortage\n");
241 stptr = stptr->next;
242 }
243 } else if (sapi == TEI_SAPI) {
244 while (stptr != NULL) {
245 if ((nskb = skb_clone(skb, GFP_ATOMIC)))
246 stptr->l1.l1tei(stptr, PH_DATA | INDICATION, nskb);
247 else
248 printk(KERN_WARNING "HiSax: tei broadcast buffer shortage\n");
249 stptr = stptr->next;
250 }
251 }
252 dev_kfree_skb(skb);
253 } else if (sapi == CTRL_SAPI) { /* sapi 0 */
254 found = 0;
255 while (stptr != NULL)
256 if (tei == stptr->l2.tei) {
257 stptr->l1.l1l2(stptr, PH_DATA | INDICATION, skb);
258 found = !0;
259 break;
260 } else
261 stptr = stptr->next;
262 if (!found)
263 dev_kfree_skb(skb);
264 } else
265 dev_kfree_skb(skb);
266 }
267}
268
269static void
270BChannel_proc_xmt(struct BCState *bcs)
271{
272 struct PStack *st = bcs->st;
273
274 if (test_bit(BC_FLG_BUSY, &bcs->Flag)) {
275 debugl1(bcs->cs, "BC_BUSY Error");
276 return;
277 }
278
279 if (test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags))
280 st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
281 if (!test_bit(BC_FLG_ACTIV, &bcs->Flag)) {
282 if (!test_bit(BC_FLG_BUSY, &bcs->Flag) && (!skb_queue_len(&bcs->squeue))) {
283 st->l2.l2l1(st, PH_DEACTIVATE | CONFIRM, NULL);
284 }
285 }
286}
287
288static void
289BChannel_proc_rcv(struct BCState *bcs)
290{
291 struct sk_buff *skb;
292
293 if (bcs->st->l1.l1m.state == ST_L1_WAIT_ACT) {
294 FsmDelTimer(&bcs->st->l1.timer, 4);
295 FsmEvent(&bcs->st->l1.l1m, EV_TIMER_ACT, NULL);
296 }
297 while ((skb = skb_dequeue(&bcs->rqueue))) {
298 bcs->st->l1.l1l2(bcs->st, PH_DATA | INDICATION, skb);
299 }
300}
301
302static void
303BChannel_proc_ack(struct BCState *bcs)
304{
305 u_long flags;
306 int ack;
307
308 spin_lock_irqsave(&bcs->aclock, flags);
309 ack = bcs->ackcnt;
310 bcs->ackcnt = 0;
311 spin_unlock_irqrestore(&bcs->aclock, flags);
312 if (ack)
313 lli_writewakeup(bcs->st, ack);
314}
315
316void
317BChannel_bh(struct BCState *bcs)
318{
319 if (!bcs)
320 return;
321 if (test_and_clear_bit(B_RCVBUFREADY, &bcs->event))
322 BChannel_proc_rcv(bcs);
323 if (test_and_clear_bit(B_XMTBUFREADY, &bcs->event))
324 BChannel_proc_xmt(bcs);
325 if (test_and_clear_bit(B_ACKPENDING, &bcs->event))
326 BChannel_proc_ack(bcs);
327}
328
329void
330HiSax_addlist(struct IsdnCardState *cs,
331 struct PStack *st)
332{
333 st->next = cs->stlist;
334 cs->stlist = st;
335}
336
337void
338HiSax_rmlist(struct IsdnCardState *cs,
339 struct PStack *st)
340{
341 struct PStack *p;
342
343 FsmDelTimer(&st->l1.timer, 0);
344 if (cs->stlist == st)
345 cs->stlist = st->next;
346 else {
347 p = cs->stlist;
348 while (p)
349 if (p->next == st) {
350 p->next = st->next;
351 return;
352 } else
353 p = p->next;
354 }
355}
356
357void
358init_bcstate(struct IsdnCardState *cs, int bc)
359{
360 struct BCState *bcs = cs->bcs + bc;
361
362 bcs->cs = cs;
363 bcs->channel = bc;
364 INIT_WORK(&bcs->tqueue, (void *)(void *) BChannel_bh, bcs);
365 spin_lock_init(&bcs->aclock);
366 bcs->BC_SetStack = NULL;
367 bcs->BC_Close = NULL;
368 bcs->Flag = 0;
369}
370
371#ifdef L2FRAME_DEBUG /* psa */
372
373char *
374l2cmd(u_char cmd)
375{
376 switch (cmd & ~0x10) {
377 case 1:
378 return "RR";
379 case 5:
380 return "RNR";
381 case 9:
382 return "REJ";
383 case 0x6f:
384 return "SABME";
385 case 0x0f:
386 return "DM";
387 case 3:
388 return "UI";
389 case 0x43:
390 return "DISC";
391 case 0x63:
392 return "UA";
393 case 0x87:
394 return "FRMR";
395 case 0xaf:
396 return "XID";
397 default:
398 if (!(cmd & 1))
399 return "I";
400 else
401 return "invalid command";
402 }
403}
404
405static char tmpdeb[32];
406
407char *
408l2frames(u_char * ptr)
409{
410 switch (ptr[2] & ~0x10) {
411 case 1:
412 case 5:
413 case 9:
414 sprintf(tmpdeb, "%s[%d](nr %d)", l2cmd(ptr[2]), ptr[3] & 1, ptr[3] >> 1);
415 break;
416 case 0x6f:
417 case 0x0f:
418 case 3:
419 case 0x43:
420 case 0x63:
421 case 0x87:
422 case 0xaf:
423 sprintf(tmpdeb, "%s[%d]", l2cmd(ptr[2]), (ptr[2] & 0x10) >> 4);
424 break;
425 default:
426 if (!(ptr[2] & 1)) {
427 sprintf(tmpdeb, "I[%d](ns %d, nr %d)", ptr[3] & 1, ptr[2] >> 1, ptr[3] >> 1);
428 break;
429 } else
430 return "invalid command";
431 }
432
433
434 return tmpdeb;
435}
436
437void
438Logl2Frame(struct IsdnCardState *cs, struct sk_buff *skb, char *buf, int dir)
439{
440 u_char *ptr;
441
442 ptr = skb->data;
443
444 if (ptr[0] & 1 || !(ptr[1] & 1))
445 debugl1(cs, "Address not LAPD");
446 else
447 debugl1(cs, "%s %s: %s%c (sapi %d, tei %d)",
448 (dir ? "<-" : "->"), buf, l2frames(ptr),
449 ((ptr[0] & 2) >> 1) == dir ? 'C' : 'R', ptr[0] >> 2, ptr[1] >> 1);
450}
451#endif
452
453static void
454l1_reset(struct FsmInst *fi, int event, void *arg)
455{
456 FsmChangeState(fi, ST_L1_F3);
457}
458
459static void
460l1_deact_cnf(struct FsmInst *fi, int event, void *arg)
461{
462 struct PStack *st = fi->userdata;
463
464 FsmChangeState(fi, ST_L1_F3);
465 if (test_bit(FLG_L1_ACTIVATING, &st->l1.Flags))
466 st->l1.l1hw(st, HW_ENABLE | REQUEST, NULL);
467}
468
469static void
470l1_deact_req_s(struct FsmInst *fi, int event, void *arg)
471{
472 struct PStack *st = fi->userdata;
473
474 FsmChangeState(fi, ST_L1_F3);
475 FsmRestartTimer(&st->l1.timer, 550, EV_TIMER_DEACT, NULL, 2);
476 test_and_set_bit(FLG_L1_DEACTTIMER, &st->l1.Flags);
477}
478
479static void
480l1_power_up_s(struct FsmInst *fi, int event, void *arg)
481{
482 struct PStack *st = fi->userdata;
483
484 if (test_bit(FLG_L1_ACTIVATING, &st->l1.Flags)) {
485 FsmChangeState(fi, ST_L1_F4);
486 st->l1.l1hw(st, HW_INFO3 | REQUEST, NULL);
487 FsmRestartTimer(&st->l1.timer, TIMER3_VALUE, EV_TIMER3, NULL, 2);
488 test_and_set_bit(FLG_L1_T3RUN, &st->l1.Flags);
489 } else
490 FsmChangeState(fi, ST_L1_F3);
491}
492
493static void
494l1_go_F5(struct FsmInst *fi, int event, void *arg)
495{
496 FsmChangeState(fi, ST_L1_F5);
497}
498
499static void
500l1_go_F8(struct FsmInst *fi, int event, void *arg)
501{
502 FsmChangeState(fi, ST_L1_F8);
503}
504
505static void
506l1_info2_ind(struct FsmInst *fi, int event, void *arg)
507{
508 struct PStack *st = fi->userdata;
509
510#ifdef HISAX_UINTERFACE
511 if (test_bit(FLG_L1_UINT, &st->l1.Flags))
512 FsmChangeState(fi, ST_L1_SYNC2);
513 else
514#endif
515 FsmChangeState(fi, ST_L1_F6);
516 st->l1.l1hw(st, HW_INFO3 | REQUEST, NULL);
517}
518
519static void
520l1_info4_ind(struct FsmInst *fi, int event, void *arg)
521{
522 struct PStack *st = fi->userdata;
523
524#ifdef HISAX_UINTERFACE
525 if (test_bit(FLG_L1_UINT, &st->l1.Flags))
526 FsmChangeState(fi, ST_L1_TRANS);
527 else
528#endif
529 FsmChangeState(fi, ST_L1_F7);
530 st->l1.l1hw(st, HW_INFO3 | REQUEST, NULL);
531 if (test_and_clear_bit(FLG_L1_DEACTTIMER, &st->l1.Flags))
532 FsmDelTimer(&st->l1.timer, 4);
533 if (!test_bit(FLG_L1_ACTIVATED, &st->l1.Flags)) {
534 if (test_and_clear_bit(FLG_L1_T3RUN, &st->l1.Flags))
535 FsmDelTimer(&st->l1.timer, 3);
536 FsmRestartTimer(&st->l1.timer, 110, EV_TIMER_ACT, NULL, 2);
537 test_and_set_bit(FLG_L1_ACTTIMER, &st->l1.Flags);
538 }
539}
540
541static void
542l1_timer3(struct FsmInst *fi, int event, void *arg)
543{
544 struct PStack *st = fi->userdata;
545
546 test_and_clear_bit(FLG_L1_T3RUN, &st->l1.Flags);
547 if (test_and_clear_bit(FLG_L1_ACTIVATING, &st->l1.Flags))
548 L1deactivated(st->l1.hardware);
549
550#ifdef HISAX_UINTERFACE
551 if (!test_bit(FLG_L1_UINT, &st->l1.Flags))
552#endif
553 if (st->l1.l1m.state != ST_L1_F6) {
554 FsmChangeState(fi, ST_L1_F3);
555 st->l1.l1hw(st, HW_ENABLE | REQUEST, NULL);
556 }
557}
558
559static void
560l1_timer_act(struct FsmInst *fi, int event, void *arg)
561{
562 struct PStack *st = fi->userdata;
563
564 test_and_clear_bit(FLG_L1_ACTTIMER, &st->l1.Flags);
565 test_and_set_bit(FLG_L1_ACTIVATED, &st->l1.Flags);
566 L1activated(st->l1.hardware);
567}
568
569static void
570l1_timer_deact(struct FsmInst *fi, int event, void *arg)
571{
572 struct PStack *st = fi->userdata;
573
574 test_and_clear_bit(FLG_L1_DEACTTIMER, &st->l1.Flags);
575 test_and_clear_bit(FLG_L1_ACTIVATED, &st->l1.Flags);
576 L1deactivated(st->l1.hardware);
577 st->l1.l1hw(st, HW_DEACTIVATE | RESPONSE, NULL);
578}
579
580static void
581l1_activate_s(struct FsmInst *fi, int event, void *arg)
582{
583 struct PStack *st = fi->userdata;
584
585 st->l1.l1hw(st, HW_RESET | REQUEST, NULL);
586}
587
588static void
589l1_activate_no(struct FsmInst *fi, int event, void *arg)
590{
591 struct PStack *st = fi->userdata;
592
593 if ((!test_bit(FLG_L1_DEACTTIMER, &st->l1.Flags)) && (!test_bit(FLG_L1_T3RUN, &st->l1.Flags))) {
594 test_and_clear_bit(FLG_L1_ACTIVATING, &st->l1.Flags);
595 L1deactivated(st->l1.hardware);
596 }
597}
598
599static struct FsmNode L1SFnList[] __initdata =
600{
601 {ST_L1_F3, EV_PH_ACTIVATE, l1_activate_s},
602 {ST_L1_F6, EV_PH_ACTIVATE, l1_activate_no},
603 {ST_L1_F8, EV_PH_ACTIVATE, l1_activate_no},
604 {ST_L1_F3, EV_RESET_IND, l1_reset},
605 {ST_L1_F4, EV_RESET_IND, l1_reset},
606 {ST_L1_F5, EV_RESET_IND, l1_reset},
607 {ST_L1_F6, EV_RESET_IND, l1_reset},
608 {ST_L1_F7, EV_RESET_IND, l1_reset},
609 {ST_L1_F8, EV_RESET_IND, l1_reset},
610 {ST_L1_F3, EV_DEACT_CNF, l1_deact_cnf},
611 {ST_L1_F4, EV_DEACT_CNF, l1_deact_cnf},
612 {ST_L1_F5, EV_DEACT_CNF, l1_deact_cnf},
613 {ST_L1_F6, EV_DEACT_CNF, l1_deact_cnf},
614 {ST_L1_F7, EV_DEACT_CNF, l1_deact_cnf},
615 {ST_L1_F8, EV_DEACT_CNF, l1_deact_cnf},
616 {ST_L1_F6, EV_DEACT_IND, l1_deact_req_s},
617 {ST_L1_F7, EV_DEACT_IND, l1_deact_req_s},
618 {ST_L1_F8, EV_DEACT_IND, l1_deact_req_s},
619 {ST_L1_F3, EV_POWER_UP, l1_power_up_s},
620 {ST_L1_F4, EV_RSYNC_IND, l1_go_F5},
621 {ST_L1_F6, EV_RSYNC_IND, l1_go_F8},
622 {ST_L1_F7, EV_RSYNC_IND, l1_go_F8},
623 {ST_L1_F3, EV_INFO2_IND, l1_info2_ind},
624 {ST_L1_F4, EV_INFO2_IND, l1_info2_ind},
625 {ST_L1_F5, EV_INFO2_IND, l1_info2_ind},
626 {ST_L1_F7, EV_INFO2_IND, l1_info2_ind},
627 {ST_L1_F8, EV_INFO2_IND, l1_info2_ind},
628 {ST_L1_F3, EV_INFO4_IND, l1_info4_ind},
629 {ST_L1_F4, EV_INFO4_IND, l1_info4_ind},
630 {ST_L1_F5, EV_INFO4_IND, l1_info4_ind},
631 {ST_L1_F6, EV_INFO4_IND, l1_info4_ind},
632 {ST_L1_F8, EV_INFO4_IND, l1_info4_ind},
633 {ST_L1_F3, EV_TIMER3, l1_timer3},
634 {ST_L1_F4, EV_TIMER3, l1_timer3},
635 {ST_L1_F5, EV_TIMER3, l1_timer3},
636 {ST_L1_F6, EV_TIMER3, l1_timer3},
637 {ST_L1_F8, EV_TIMER3, l1_timer3},
638 {ST_L1_F7, EV_TIMER_ACT, l1_timer_act},
639 {ST_L1_F3, EV_TIMER_DEACT, l1_timer_deact},
640 {ST_L1_F4, EV_TIMER_DEACT, l1_timer_deact},
641 {ST_L1_F5, EV_TIMER_DEACT, l1_timer_deact},
642 {ST_L1_F6, EV_TIMER_DEACT, l1_timer_deact},
643 {ST_L1_F7, EV_TIMER_DEACT, l1_timer_deact},
644 {ST_L1_F8, EV_TIMER_DEACT, l1_timer_deact},
645};
646
647#define L1S_FN_COUNT (sizeof(L1SFnList)/sizeof(struct FsmNode))
648
649#ifdef HISAX_UINTERFACE
650static void
651l1_deact_req_u(struct FsmInst *fi, int event, void *arg)
652{
653 struct PStack *st = fi->userdata;
654
655 FsmChangeState(fi, ST_L1_RESET);
656 FsmRestartTimer(&st->l1.timer, 550, EV_TIMER_DEACT, NULL, 2);
657 test_and_set_bit(FLG_L1_DEACTTIMER, &st->l1.Flags);
658 st->l1.l1hw(st, HW_ENABLE | REQUEST, NULL);
659}
660
661static void
662l1_power_up_u(struct FsmInst *fi, int event, void *arg)
663{
664 struct PStack *st = fi->userdata;
665
666 FsmRestartTimer(&st->l1.timer, TIMER3_VALUE, EV_TIMER3, NULL, 2);
667 test_and_set_bit(FLG_L1_T3RUN, &st->l1.Flags);
668}
669
670static void
671l1_info0_ind(struct FsmInst *fi, int event, void *arg)
672{
673 FsmChangeState(fi, ST_L1_DEACT);
674}
675
676static void
677l1_activate_u(struct FsmInst *fi, int event, void *arg)
678{
679 struct PStack *st = fi->userdata;
680
681 st->l1.l1hw(st, HW_INFO1 | REQUEST, NULL);
682}
683
684static struct FsmNode L1UFnList[] __initdata =
685{
686 {ST_L1_RESET, EV_DEACT_IND, l1_deact_req_u},
687 {ST_L1_DEACT, EV_DEACT_IND, l1_deact_req_u},
688 {ST_L1_SYNC2, EV_DEACT_IND, l1_deact_req_u},
689 {ST_L1_TRANS, EV_DEACT_IND, l1_deact_req_u},
690 {ST_L1_DEACT, EV_PH_ACTIVATE, l1_activate_u},
691 {ST_L1_DEACT, EV_POWER_UP, l1_power_up_u},
692 {ST_L1_DEACT, EV_INFO2_IND, l1_info2_ind},
693 {ST_L1_TRANS, EV_INFO2_IND, l1_info2_ind},
694 {ST_L1_RESET, EV_DEACT_CNF, l1_info0_ind},
695 {ST_L1_DEACT, EV_INFO4_IND, l1_info4_ind},
696 {ST_L1_SYNC2, EV_INFO4_IND, l1_info4_ind},
697 {ST_L1_RESET, EV_INFO4_IND, l1_info4_ind},
698 {ST_L1_DEACT, EV_TIMER3, l1_timer3},
699 {ST_L1_SYNC2, EV_TIMER3, l1_timer3},
700 {ST_L1_TRANS, EV_TIMER_ACT, l1_timer_act},
701 {ST_L1_DEACT, EV_TIMER_DEACT, l1_timer_deact},
702 {ST_L1_SYNC2, EV_TIMER_DEACT, l1_timer_deact},
703 {ST_L1_RESET, EV_TIMER_DEACT, l1_timer_deact},
704};
705
706#define L1U_FN_COUNT (sizeof(L1UFnList)/sizeof(struct FsmNode))
707
708#endif
709
710static void
711l1b_activate(struct FsmInst *fi, int event, void *arg)
712{
713 struct PStack *st = fi->userdata;
714
715 FsmChangeState(fi, ST_L1_WAIT_ACT);
716 FsmRestartTimer(&st->l1.timer, st->l1.delay, EV_TIMER_ACT, NULL, 2);
717}
718
719static void
720l1b_deactivate(struct FsmInst *fi, int event, void *arg)
721{
722 struct PStack *st = fi->userdata;
723
724 FsmChangeState(fi, ST_L1_WAIT_DEACT);
725 FsmRestartTimer(&st->l1.timer, 10, EV_TIMER_DEACT, NULL, 2);
726}
727
728static void
729l1b_timer_act(struct FsmInst *fi, int event, void *arg)
730{
731 struct PStack *st = fi->userdata;
732
733 FsmChangeState(fi, ST_L1_ACTIV);
734 st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL);
735}
736
737static void
738l1b_timer_deact(struct FsmInst *fi, int event, void *arg)
739{
740 struct PStack *st = fi->userdata;
741
742 FsmChangeState(fi, ST_L1_NULL);
743 st->l2.l2l1(st, PH_DEACTIVATE | CONFIRM, NULL);
744}
745
746static struct FsmNode L1BFnList[] __initdata =
747{
748 {ST_L1_NULL, EV_PH_ACTIVATE, l1b_activate},
749 {ST_L1_WAIT_ACT, EV_TIMER_ACT, l1b_timer_act},
750 {ST_L1_ACTIV, EV_PH_DEACTIVATE, l1b_deactivate},
751 {ST_L1_WAIT_DEACT, EV_TIMER_DEACT, l1b_timer_deact},
752};
753
754#define L1B_FN_COUNT (sizeof(L1BFnList)/sizeof(struct FsmNode))
755
756int __init
757Isdnl1New(void)
758{
759 int retval;
760
761 l1fsm_s.state_count = L1S_STATE_COUNT;
762 l1fsm_s.event_count = L1_EVENT_COUNT;
763 l1fsm_s.strEvent = strL1Event;
764 l1fsm_s.strState = strL1SState;
765 retval = FsmNew(&l1fsm_s, L1SFnList, L1S_FN_COUNT);
766 if (retval)
767 return retval;
768
769 l1fsm_b.state_count = L1B_STATE_COUNT;
770 l1fsm_b.event_count = L1_EVENT_COUNT;
771 l1fsm_b.strEvent = strL1Event;
772 l1fsm_b.strState = strL1BState;
773 retval = FsmNew(&l1fsm_b, L1BFnList, L1B_FN_COUNT);
774 if (retval) {
775 FsmFree(&l1fsm_s);
776 return retval;
777 }
778#ifdef HISAX_UINTERFACE
779 l1fsm_u.state_count = L1U_STATE_COUNT;
780 l1fsm_u.event_count = L1_EVENT_COUNT;
781 l1fsm_u.strEvent = strL1Event;
782 l1fsm_u.strState = strL1UState;
783 retval = FsmNew(&l1fsm_u, L1UFnList, L1U_FN_COUNT);
784 if (retval) {
785 FsmFree(&l1fsm_s);
786 FsmFree(&l1fsm_b);
787 return retval;
788 }
789#endif
790 return 0;
791}
792
793void Isdnl1Free(void)
794{
795#ifdef HISAX_UINTERFACE
796 FsmFree(&l1fsm_u);
797#endif
798 FsmFree(&l1fsm_s);
799 FsmFree(&l1fsm_b);
800}
801
802static void
803dch_l2l1(struct PStack *st, int pr, void *arg)
804{
805 struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
806
807 switch (pr) {
808 case (PH_DATA | REQUEST):
809 case (PH_PULL | REQUEST):
810 case (PH_PULL |INDICATION):
811 st->l1.l1hw(st, pr, arg);
812 break;
813 case (PH_ACTIVATE | REQUEST):
814 if (cs->debug)
815 debugl1(cs, "PH_ACTIVATE_REQ %s",
816 st->l1.l1m.fsm->strState[st->l1.l1m.state]);
817 if (test_bit(FLG_L1_ACTIVATED, &st->l1.Flags))
818 st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL);
819 else {
820 test_and_set_bit(FLG_L1_ACTIVATING, &st->l1.Flags);
821 FsmEvent(&st->l1.l1m, EV_PH_ACTIVATE, arg);
822 }
823 break;
824 case (PH_TESTLOOP | REQUEST):
825 if (1 & (long) arg)
826 debugl1(cs, "PH_TEST_LOOP B1");
827 if (2 & (long) arg)
828 debugl1(cs, "PH_TEST_LOOP B2");
829 if (!(3 & (long) arg))
830 debugl1(cs, "PH_TEST_LOOP DISABLED");
831 st->l1.l1hw(st, HW_TESTLOOP | REQUEST, arg);
832 break;
833 default:
834 if (cs->debug)
835 debugl1(cs, "dch_l2l1 msg %04X unhandled", pr);
836 break;
837 }
838}
839
840void
841l1_msg(struct IsdnCardState *cs, int pr, void *arg) {
842 struct PStack *st;
843
844 st = cs->stlist;
845
846 while (st) {
847 switch(pr) {
848 case (HW_RESET | INDICATION):
849 FsmEvent(&st->l1.l1m, EV_RESET_IND, arg);
850 break;
851 case (HW_DEACTIVATE | CONFIRM):
852 FsmEvent(&st->l1.l1m, EV_DEACT_CNF, arg);
853 break;
854 case (HW_DEACTIVATE | INDICATION):
855 FsmEvent(&st->l1.l1m, EV_DEACT_IND, arg);
856 break;
857 case (HW_POWERUP | CONFIRM):
858 FsmEvent(&st->l1.l1m, EV_POWER_UP, arg);
859 break;
860 case (HW_RSYNC | INDICATION):
861 FsmEvent(&st->l1.l1m, EV_RSYNC_IND, arg);
862 break;
863 case (HW_INFO2 | INDICATION):
864 FsmEvent(&st->l1.l1m, EV_INFO2_IND, arg);
865 break;
866 case (HW_INFO4_P8 | INDICATION):
867 case (HW_INFO4_P10 | INDICATION):
868 FsmEvent(&st->l1.l1m, EV_INFO4_IND, arg);
869 break;
870 default:
871 if (cs->debug)
872 debugl1(cs, "l1msg %04X unhandled", pr);
873 break;
874 }
875 st = st->next;
876 }
877}
878
879void
880l1_msg_b(struct PStack *st, int pr, void *arg) {
881 switch(pr) {
882 case (PH_ACTIVATE | REQUEST):
883 FsmEvent(&st->l1.l1m, EV_PH_ACTIVATE, NULL);
884 break;
885 case (PH_DEACTIVATE | REQUEST):
886 FsmEvent(&st->l1.l1m, EV_PH_DEACTIVATE, NULL);
887 break;
888 }
889}
890
891void
892setstack_HiSax(struct PStack *st, struct IsdnCardState *cs)
893{
894 st->l1.hardware = cs;
895 st->protocol = cs->protocol;
896 st->l1.l1m.fsm = &l1fsm_s;
897 st->l1.l1m.state = ST_L1_F3;
898 st->l1.Flags = 0;
899#ifdef HISAX_UINTERFACE
900 if (test_bit(FLG_HW_L1_UINT, &cs->HW_Flags)) {
901 st->l1.l1m.fsm = &l1fsm_u;
902 st->l1.l1m.state = ST_L1_RESET;
903 st->l1.Flags = FLG_L1_UINT;
904 }
905#endif
906 st->l1.l1m.debug = cs->debug;
907 st->l1.l1m.userdata = st;
908 st->l1.l1m.userint = 0;
909 st->l1.l1m.printdebug = l1m_debug;
910 FsmInitTimer(&st->l1.l1m, &st->l1.timer);
911 setstack_tei(st);
912 setstack_manager(st);
913 st->l1.stlistp = &(cs->stlist);
914 st->l2.l2l1 = dch_l2l1;
915 if (cs->setstack_d)
916 cs->setstack_d(st, cs);
917}
918
919void
920setstack_l1_B(struct PStack *st)
921{
922 struct IsdnCardState *cs = st->l1.hardware;
923
924 st->l1.l1m.fsm = &l1fsm_b;
925 st->l1.l1m.state = ST_L1_NULL;
926 st->l1.l1m.debug = cs->debug;
927 st->l1.l1m.userdata = st;
928 st->l1.l1m.userint = 0;
929 st->l1.l1m.printdebug = l1m_debug;
930 st->l1.Flags = 0;
931 FsmInitTimer(&st->l1.l1m, &st->l1.timer);
932}
diff --git a/drivers/isdn/hisax/isdnl1.h b/drivers/isdn/hisax/isdnl1.h
new file mode 100644
index 000000000000..0e88cfabdf10
--- /dev/null
+++ b/drivers/isdn/hisax/isdnl1.h
@@ -0,0 +1,32 @@
1/* $Id: isdnl1.h,v 2.12.2.3 2004/02/11 13:21:34 keil Exp $
2 *
3 * Layer 1 defines
4 *
5 * This software may be used and distributed according to the terms
6 * of the GNU General Public License, incorporated herein by reference.
7 *
8 */
9
10#define D_RCVBUFREADY 0
11#define D_XMTBUFREADY 1
12#define D_L1STATECHANGE 2
13#define D_CLEARBUSY 3
14#define D_RX_MON0 4
15#define D_RX_MON1 5
16#define D_TX_MON0 6
17#define D_TX_MON1 7
18#define E_RCVBUFREADY 8
19
20#define B_RCVBUFREADY 0
21#define B_XMTBUFREADY 1
22#define B_ACKPENDING 2
23
24extern void debugl1(struct IsdnCardState *cs, char *fmt, ...);
25extern void DChannel_proc_xmt(struct IsdnCardState *cs);
26extern void DChannel_proc_rcv(struct IsdnCardState *cs);
27extern void l1_msg(struct IsdnCardState *cs, int pr, void *arg);
28extern void l1_msg_b(struct PStack *st, int pr, void *arg);
29
30#ifdef L2FRAME_DEBUG
31extern void Logl2Frame(struct IsdnCardState *cs, struct sk_buff *skb, char *buf, int dir);
32#endif
diff --git a/drivers/isdn/hisax/isdnl2.c b/drivers/isdn/hisax/isdnl2.c
new file mode 100644
index 000000000000..d311b5fbf895
--- /dev/null
+++ b/drivers/isdn/hisax/isdnl2.c
@@ -0,0 +1,1860 @@
1/* $Id: isdnl2.c,v 2.30.2.4 2004/02/11 13:21:34 keil Exp $
2 *
3 * Author Karsten Keil
4 * based on the teles driver from Jan den Ouden
5 * Copyright by Karsten Keil <keil@isdn4linux.de>
6 *
7 * This software may be used and distributed according to the terms
8 * of the GNU General Public License, incorporated herein by reference.
9 *
10 * For changes and modifications please read
11 * Documentation/isdn/HiSax.cert
12 *
13 * Thanks to Jan den Ouden
14 * Fritz Elfert
15 *
16 */
17
18#include <linux/init.h>
19#include "hisax.h"
20#include "isdnl2.h"
21
22const char *l2_revision = "$Revision: 2.30.2.4 $";
23
24static void l2m_debug(struct FsmInst *fi, char *fmt, ...);
25
26static struct Fsm l2fsm;
27
28enum {
29 ST_L2_1,
30 ST_L2_2,
31 ST_L2_3,
32 ST_L2_4,
33 ST_L2_5,
34 ST_L2_6,
35 ST_L2_7,
36 ST_L2_8,
37};
38
39#define L2_STATE_COUNT (ST_L2_8+1)
40
41static char *strL2State[] =
42{
43 "ST_L2_1",
44 "ST_L2_2",
45 "ST_L2_3",
46 "ST_L2_4",
47 "ST_L2_5",
48 "ST_L2_6",
49 "ST_L2_7",
50 "ST_L2_8",
51};
52
53enum {
54 EV_L2_UI,
55 EV_L2_SABME,
56 EV_L2_DISC,
57 EV_L2_DM,
58 EV_L2_UA,
59 EV_L2_FRMR,
60 EV_L2_SUPER,
61 EV_L2_I,
62 EV_L2_DL_DATA,
63 EV_L2_ACK_PULL,
64 EV_L2_DL_UNIT_DATA,
65 EV_L2_DL_ESTABLISH_REQ,
66 EV_L2_DL_RELEASE_REQ,
67 EV_L2_MDL_ASSIGN,
68 EV_L2_MDL_REMOVE,
69 EV_L2_MDL_ERROR,
70 EV_L1_DEACTIVATE,
71 EV_L2_T200,
72 EV_L2_T203,
73 EV_L2_SET_OWN_BUSY,
74 EV_L2_CLEAR_OWN_BUSY,
75 EV_L2_FRAME_ERROR,
76};
77
78#define L2_EVENT_COUNT (EV_L2_FRAME_ERROR+1)
79
80static char *strL2Event[] =
81{
82 "EV_L2_UI",
83 "EV_L2_SABME",
84 "EV_L2_DISC",
85 "EV_L2_DM",
86 "EV_L2_UA",
87 "EV_L2_FRMR",
88 "EV_L2_SUPER",
89 "EV_L2_I",
90 "EV_L2_DL_DATA",
91 "EV_L2_ACK_PULL",
92 "EV_L2_DL_UNIT_DATA",
93 "EV_L2_DL_ESTABLISH_REQ",
94 "EV_L2_DL_RELEASE_REQ",
95 "EV_L2_MDL_ASSIGN",
96 "EV_L2_MDL_REMOVE",
97 "EV_L2_MDL_ERROR",
98 "EV_L1_DEACTIVATE",
99 "EV_L2_T200",
100 "EV_L2_T203",
101 "EV_L2_SET_OWN_BUSY",
102 "EV_L2_CLEAR_OWN_BUSY",
103 "EV_L2_FRAME_ERROR",
104};
105
106static int l2addrsize(struct Layer2 *l2);
107
108static void
109set_peer_busy(struct Layer2 *l2) {
110 test_and_set_bit(FLG_PEER_BUSY, &l2->flag);
111 if (skb_queue_len(&l2->i_queue) || skb_queue_len(&l2->ui_queue))
112 test_and_set_bit(FLG_L2BLOCK, &l2->flag);
113}
114
115static void
116clear_peer_busy(struct Layer2 *l2) {
117 if (test_and_clear_bit(FLG_PEER_BUSY, &l2->flag))
118 test_and_clear_bit(FLG_L2BLOCK, &l2->flag);
119}
120
121static void
122InitWin(struct Layer2 *l2)
123{
124 int i;
125
126 for (i = 0; i < MAX_WINDOW; i++)
127 l2->windowar[i] = NULL;
128}
129
130static int
131freewin1(struct Layer2 *l2)
132{
133 int i, cnt = 0;
134
135 for (i = 0; i < MAX_WINDOW; i++) {
136 if (l2->windowar[i]) {
137 cnt++;
138 dev_kfree_skb(l2->windowar[i]);
139 l2->windowar[i] = NULL;
140 }
141 }
142 return cnt;
143}
144
145inline void
146freewin(struct PStack *st)
147{
148 freewin1(&st->l2);
149}
150
151static void
152ReleaseWin(struct Layer2 *l2)
153{
154 int cnt;
155
156 if((cnt = freewin1(l2)))
157 printk(KERN_WARNING "isdl2 freed %d skbuffs in release\n", cnt);
158}
159
160inline unsigned int
161cansend(struct PStack *st)
162{
163 unsigned int p1;
164
165 if(test_bit(FLG_MOD128, &st->l2.flag))
166 p1 = (st->l2.vs - st->l2.va) % 128;
167 else
168 p1 = (st->l2.vs - st->l2.va) % 8;
169 return ((p1 < st->l2.window) && !test_bit(FLG_PEER_BUSY, &st->l2.flag));
170}
171
172inline void
173clear_exception(struct Layer2 *l2)
174{
175 test_and_clear_bit(FLG_ACK_PEND, &l2->flag);
176 test_and_clear_bit(FLG_REJEXC, &l2->flag);
177 test_and_clear_bit(FLG_OWN_BUSY, &l2->flag);
178 clear_peer_busy(l2);
179}
180
181inline int
182l2headersize(struct Layer2 *l2, int ui)
183{
184 return (((test_bit(FLG_MOD128, &l2->flag) && (!ui)) ? 2 : 1) +
185 (test_bit(FLG_LAPD, &l2->flag) ? 2 : 1));
186}
187
188inline int
189l2addrsize(struct Layer2 *l2)
190{
191 return (test_bit(FLG_LAPD, &l2->flag) ? 2 : 1);
192}
193
194static int
195sethdraddr(struct Layer2 *l2, u_char * header, int rsp)
196{
197 u_char *ptr = header;
198 int crbit = rsp;
199
200 if (test_bit(FLG_LAPD, &l2->flag)) {
201 *ptr++ = (l2->sap << 2) | (rsp ? 2 : 0);
202 *ptr++ = (l2->tei << 1) | 1;
203 return (2);
204 } else {
205 if (test_bit(FLG_ORIG, &l2->flag))
206 crbit = !crbit;
207 if (crbit)
208 *ptr++ = 1;
209 else
210 *ptr++ = 3;
211 return (1);
212 }
213}
214
215inline static void
216enqueue_super(struct PStack *st,
217 struct sk_buff *skb)
218{
219 if (test_bit(FLG_LAPB, &st->l2.flag))
220 st->l1.bcs->tx_cnt += skb->len;
221 st->l2.l2l1(st, PH_DATA | REQUEST, skb);
222}
223
224#define enqueue_ui(a, b) enqueue_super(a, b)
225
226inline int
227IsUI(u_char * data)
228{
229 return ((data[0] & 0xef) == UI);
230}
231
232inline int
233IsUA(u_char * data)
234{
235 return ((data[0] & 0xef) == UA);
236}
237
238inline int
239IsDM(u_char * data)
240{
241 return ((data[0] & 0xef) == DM);
242}
243
244inline int
245IsDISC(u_char * data)
246{
247 return ((data[0] & 0xef) == DISC);
248}
249
250inline int
251IsRR(u_char * data, struct PStack *st)
252{
253 if (test_bit(FLG_MOD128, &st->l2.flag))
254 return (data[0] == RR);
255 else
256 return ((data[0] & 0xf) == 1);
257}
258
259inline int
260IsSFrame(u_char * data, struct PStack *st)
261{
262 register u_char d = *data;
263
264 if (!test_bit(FLG_MOD128, &st->l2.flag))
265 d &= 0xf;
266 return(((d & 0xf3) == 1) && ((d & 0x0c) != 0x0c));
267}
268
269inline int
270IsSABME(u_char * data, struct PStack *st)
271{
272 u_char d = data[0] & ~0x10;
273
274 return (test_bit(FLG_MOD128, &st->l2.flag) ? d == SABME : d == SABM);
275}
276
277inline int
278IsREJ(u_char * data, struct PStack *st)
279{
280 return (test_bit(FLG_MOD128, &st->l2.flag) ? data[0] == REJ : (data[0] & 0xf) == REJ);
281}
282
283inline int
284IsFRMR(u_char * data)
285{
286 return ((data[0] & 0xef) == FRMR);
287}
288
289inline int
290IsRNR(u_char * data, struct PStack *st)
291{
292 return (test_bit(FLG_MOD128, &st->l2.flag) ? data[0] == RNR : (data[0] & 0xf) == RNR);
293}
294
295int
296iframe_error(struct PStack *st, struct sk_buff *skb)
297{
298 int i = l2addrsize(&st->l2) + (test_bit(FLG_MOD128, &st->l2.flag) ? 2 : 1);
299 int rsp = *skb->data & 0x2;
300
301 if (test_bit(FLG_ORIG, &st->l2.flag))
302 rsp = !rsp;
303
304 if (rsp)
305 return 'L';
306
307
308 if (skb->len < i)
309 return 'N';
310
311 if ((skb->len - i) > st->l2.maxlen)
312 return 'O';
313
314
315 return 0;
316}
317
318int
319super_error(struct PStack *st, struct sk_buff *skb)
320{
321 if (skb->len != l2addrsize(&st->l2) +
322 (test_bit(FLG_MOD128, &st->l2.flag) ? 2 : 1))
323 return 'N';
324
325 return 0;
326}
327
328int
329unnum_error(struct PStack *st, struct sk_buff *skb, int wantrsp)
330{
331 int rsp = (*skb->data & 0x2) >> 1;
332 if (test_bit(FLG_ORIG, &st->l2.flag))
333 rsp = !rsp;
334
335 if (rsp != wantrsp)
336 return 'L';
337
338 if (skb->len != l2addrsize(&st->l2) + 1)
339 return 'N';
340
341 return 0;
342}
343
344int
345UI_error(struct PStack *st, struct sk_buff *skb)
346{
347 int rsp = *skb->data & 0x2;
348 if (test_bit(FLG_ORIG, &st->l2.flag))
349 rsp = !rsp;
350
351 if (rsp)
352 return 'L';
353
354 if (skb->len > st->l2.maxlen + l2addrsize(&st->l2) + 1)
355 return 'O';
356
357 return 0;
358}
359
360int
361FRMR_error(struct PStack *st, struct sk_buff *skb)
362{
363 int headers = l2addrsize(&st->l2) + 1;
364 u_char *datap = skb->data + headers;
365 int rsp = *skb->data & 0x2;
366
367 if (test_bit(FLG_ORIG, &st->l2.flag))
368 rsp = !rsp;
369
370 if (!rsp)
371 return 'L';
372
373 if (test_bit(FLG_MOD128, &st->l2.flag)) {
374 if (skb->len < headers + 5)
375 return 'N';
376 else
377 l2m_debug(&st->l2.l2m, "FRMR information %2x %2x %2x %2x %2x",
378 datap[0], datap[1], datap[2],
379 datap[3], datap[4]);
380 } else {
381 if (skb->len < headers + 3)
382 return 'N';
383 else
384 l2m_debug(&st->l2.l2m, "FRMR information %2x %2x %2x",
385 datap[0], datap[1], datap[2]);
386 }
387
388 return 0;
389}
390
391static unsigned int
392legalnr(struct PStack *st, unsigned int nr)
393{
394 struct Layer2 *l2 = &st->l2;
395
396 if(test_bit(FLG_MOD128, &l2->flag))
397 return ((nr - l2->va) % 128) <= ((l2->vs - l2->va) % 128);
398 else
399 return ((nr - l2->va) % 8) <= ((l2->vs - l2->va) % 8);
400}
401
402static void
403setva(struct PStack *st, unsigned int nr)
404{
405 struct Layer2 *l2 = &st->l2;
406 int len;
407 u_long flags;
408
409 spin_lock_irqsave(&l2->lock, flags);
410 while (l2->va != nr) {
411 (l2->va)++;
412 if(test_bit(FLG_MOD128, &l2->flag))
413 l2->va %= 128;
414 else
415 l2->va %= 8;
416 len = l2->windowar[l2->sow]->len;
417 if (PACKET_NOACK == l2->windowar[l2->sow]->pkt_type)
418 len = -1;
419 dev_kfree_skb(l2->windowar[l2->sow]);
420 l2->windowar[l2->sow] = NULL;
421 l2->sow = (l2->sow + 1) % l2->window;
422 spin_unlock_irqrestore(&l2->lock, flags);
423 if (test_bit(FLG_LLI_L2WAKEUP, &st->lli.flag) && (len >=0))
424 lli_writewakeup(st, len);
425 spin_lock_irqsave(&l2->lock, flags);
426 }
427 spin_unlock_irqrestore(&l2->lock, flags);
428}
429
430static void
431send_uframe(struct PStack *st, u_char cmd, u_char cr)
432{
433 struct sk_buff *skb;
434 u_char tmp[MAX_HEADER_LEN];
435 int i;
436
437 i = sethdraddr(&st->l2, tmp, cr);
438 tmp[i++] = cmd;
439 if (!(skb = alloc_skb(i, GFP_ATOMIC))) {
440 printk(KERN_WARNING "isdl2 can't alloc sbbuff for send_uframe\n");
441 return;
442 }
443 memcpy(skb_put(skb, i), tmp, i);
444 enqueue_super(st, skb);
445}
446
447inline u_char
448get_PollFlag(struct PStack * st, struct sk_buff * skb)
449{
450 return (skb->data[l2addrsize(&(st->l2))] & 0x10);
451}
452
453inline void
454FreeSkb(struct sk_buff *skb)
455{
456 dev_kfree_skb(skb);
457}
458
459
460inline u_char
461get_PollFlagFree(struct PStack *st, struct sk_buff *skb)
462{
463 u_char PF;
464
465 PF = get_PollFlag(st, skb);
466 FreeSkb(skb);
467 return (PF);
468}
469
470inline void
471start_t200(struct PStack *st, int i)
472{
473 FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, i);
474 test_and_set_bit(FLG_T200_RUN, &st->l2.flag);
475}
476
477inline void
478restart_t200(struct PStack *st, int i)
479{
480 FsmRestartTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, i);
481 test_and_set_bit(FLG_T200_RUN, &st->l2.flag);
482}
483
484inline void
485stop_t200(struct PStack *st, int i)
486{
487 if(test_and_clear_bit(FLG_T200_RUN, &st->l2.flag))
488 FsmDelTimer(&st->l2.t200, i);
489}
490
491inline void
492st5_dl_release_l2l3(struct PStack *st)
493{
494 int pr;
495
496 if(test_and_clear_bit(FLG_PEND_REL, &st->l2.flag))
497 pr = DL_RELEASE | CONFIRM;
498 else
499 pr = DL_RELEASE | INDICATION;
500
501 st->l2.l2l3(st, pr, NULL);
502}
503
504inline void
505lapb_dl_release_l2l3(struct PStack *st, int f)
506{
507 if (test_bit(FLG_LAPB, &st->l2.flag))
508 st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL);
509 st->l2.l2l3(st, DL_RELEASE | f, NULL);
510}
511
512static void
513establishlink(struct FsmInst *fi)
514{
515 struct PStack *st = fi->userdata;
516 u_char cmd;
517
518 clear_exception(&st->l2);
519 st->l2.rc = 0;
520 cmd = (test_bit(FLG_MOD128, &st->l2.flag) ? SABME : SABM) | 0x10;
521 send_uframe(st, cmd, CMD);
522 FsmDelTimer(&st->l2.t203, 1);
523 restart_t200(st, 1);
524 test_and_clear_bit(FLG_PEND_REL, &st->l2.flag);
525 freewin(st);
526 FsmChangeState(fi, ST_L2_5);
527}
528
529static void
530l2_mdl_error_ua(struct FsmInst *fi, int event, void *arg)
531{
532 struct sk_buff *skb = arg;
533 struct PStack *st = fi->userdata;
534
535 if (get_PollFlagFree(st, skb))
536 st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'C');
537 else
538 st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'D');
539}
540
541static void
542l2_mdl_error_dm(struct FsmInst *fi, int event, void *arg)
543{
544 struct sk_buff *skb = arg;
545 struct PStack *st = fi->userdata;
546
547 if (get_PollFlagFree(st, skb))
548 st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'B');
549 else {
550 st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'E');
551 establishlink(fi);
552 test_and_clear_bit(FLG_L3_INIT, &st->l2.flag);
553 }
554}
555
556static void
557l2_st8_mdl_error_dm(struct FsmInst *fi, int event, void *arg)
558{
559 struct sk_buff *skb = arg;
560 struct PStack *st = fi->userdata;
561
562 if (get_PollFlagFree(st, skb))
563 st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'B');
564 else {
565 st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'E');
566 }
567 establishlink(fi);
568 test_and_clear_bit(FLG_L3_INIT, &st->l2.flag);
569}
570
571static void
572l2_go_st3(struct FsmInst *fi, int event, void *arg)
573{
574 FsmChangeState(fi, ST_L2_3);
575}
576
577static void
578l2_mdl_assign(struct FsmInst *fi, int event, void *arg)
579{
580 struct PStack *st = fi->userdata;
581
582 FsmChangeState(fi, ST_L2_3);
583 st->l2.l2tei(st, MDL_ASSIGN | INDICATION, NULL);
584}
585
586static void
587l2_queue_ui_assign(struct FsmInst *fi, int event, void *arg)
588{
589 struct PStack *st = fi->userdata;
590 struct sk_buff *skb = arg;
591
592 skb_queue_tail(&st->l2.ui_queue, skb);
593 FsmChangeState(fi, ST_L2_2);
594 st->l2.l2tei(st, MDL_ASSIGN | INDICATION, NULL);
595}
596
597static void
598l2_queue_ui(struct FsmInst *fi, int event, void *arg)
599{
600 struct PStack *st = fi->userdata;
601 struct sk_buff *skb = arg;
602
603 skb_queue_tail(&st->l2.ui_queue, skb);
604}
605
606static void
607tx_ui(struct PStack *st)
608{
609 struct sk_buff *skb;
610 u_char header[MAX_HEADER_LEN];
611 int i;
612
613 i = sethdraddr(&(st->l2), header, CMD);
614 header[i++] = UI;
615 while ((skb = skb_dequeue(&st->l2.ui_queue))) {
616 memcpy(skb_push(skb, i), header, i);
617 enqueue_ui(st, skb);
618 }
619}
620
621static void
622l2_send_ui(struct FsmInst *fi, int event, void *arg)
623{
624 struct PStack *st = fi->userdata;
625 struct sk_buff *skb = arg;
626
627 skb_queue_tail(&st->l2.ui_queue, skb);
628 tx_ui(st);
629}
630
631static void
632l2_got_ui(struct FsmInst *fi, int event, void *arg)
633{
634 struct PStack *st = fi->userdata;
635 struct sk_buff *skb = arg;
636
637 skb_pull(skb, l2headersize(&st->l2, 1));
638 st->l2.l2l3(st, DL_UNIT_DATA | INDICATION, skb);
639/* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
640 * in states 1-3 for broadcast
641 */
642
643
644}
645
646static void
647l2_establish(struct FsmInst *fi, int event, void *arg)
648{
649 struct PStack *st = fi->userdata;
650
651 establishlink(fi);
652 test_and_set_bit(FLG_L3_INIT, &st->l2.flag);
653}
654
655static void
656l2_discard_i_setl3(struct FsmInst *fi, int event, void *arg)
657{
658 struct PStack *st = fi->userdata;
659
660 skb_queue_purge(&st->l2.i_queue);
661 test_and_set_bit(FLG_L3_INIT, &st->l2.flag);
662 test_and_clear_bit(FLG_PEND_REL, &st->l2.flag);
663}
664
665static void
666l2_l3_reestablish(struct FsmInst *fi, int event, void *arg)
667{
668 struct PStack *st = fi->userdata;
669
670 skb_queue_purge(&st->l2.i_queue);
671 establishlink(fi);
672 test_and_set_bit(FLG_L3_INIT, &st->l2.flag);
673}
674
675static void
676l2_release(struct FsmInst *fi, int event, void *arg)
677{
678 struct PStack *st = fi->userdata;
679
680 st->l2.l2l3(st, DL_RELEASE | CONFIRM, NULL);
681}
682
683static void
684l2_pend_rel(struct FsmInst *fi, int event, void *arg)
685{
686 struct PStack *st = fi->userdata;
687
688 test_and_set_bit(FLG_PEND_REL, &st->l2.flag);
689}
690
691static void
692l2_disconnect(struct FsmInst *fi, int event, void *arg)
693{
694 struct PStack *st = fi->userdata;
695
696 skb_queue_purge(&st->l2.i_queue);
697 freewin(st);
698 FsmChangeState(fi, ST_L2_6);
699 st->l2.rc = 0;
700 send_uframe(st, DISC | 0x10, CMD);
701 FsmDelTimer(&st->l2.t203, 1);
702 restart_t200(st, 2);
703}
704
705static void
706l2_start_multi(struct FsmInst *fi, int event, void *arg)
707{
708 struct PStack *st = fi->userdata;
709 struct sk_buff *skb = arg;
710
711 send_uframe(st, UA | get_PollFlagFree(st, skb), RSP);
712
713 clear_exception(&st->l2);
714 st->l2.vs = 0;
715 st->l2.va = 0;
716 st->l2.vr = 0;
717 st->l2.sow = 0;
718 FsmChangeState(fi, ST_L2_7);
719 FsmAddTimer(&st->l2.t203, st->l2.T203, EV_L2_T203, NULL, 3);
720
721 st->l2.l2l3(st, DL_ESTABLISH | INDICATION, NULL);
722}
723
724static void
725l2_send_UA(struct FsmInst *fi, int event, void *arg)
726{
727 struct PStack *st = fi->userdata;
728 struct sk_buff *skb = arg;
729
730 send_uframe(st, UA | get_PollFlagFree(st, skb), RSP);
731}
732
733static void
734l2_send_DM(struct FsmInst *fi, int event, void *arg)
735{
736 struct PStack *st = fi->userdata;
737 struct sk_buff *skb = arg;
738
739 send_uframe(st, DM | get_PollFlagFree(st, skb), RSP);
740}
741
742static void
743l2_restart_multi(struct FsmInst *fi, int event, void *arg)
744{
745 struct PStack *st = fi->userdata;
746 struct sk_buff *skb = arg;
747 int est = 0, state;
748
749 state = fi->state;
750
751 send_uframe(st, UA | get_PollFlagFree(st, skb), RSP);
752
753 st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'F');
754
755 if (st->l2.vs != st->l2.va) {
756 skb_queue_purge(&st->l2.i_queue);
757 est = 1;
758 }
759
760 clear_exception(&st->l2);
761 st->l2.vs = 0;
762 st->l2.va = 0;
763 st->l2.vr = 0;
764 st->l2.sow = 0;
765 FsmChangeState(fi, ST_L2_7);
766 stop_t200(st, 3);
767 FsmRestartTimer(&st->l2.t203, st->l2.T203, EV_L2_T203, NULL, 3);
768
769 if (est)
770 st->l2.l2l3(st, DL_ESTABLISH | INDICATION, NULL);
771
772 if ((ST_L2_7==state) || (ST_L2_8 == state))
773 if (skb_queue_len(&st->l2.i_queue) && cansend(st))
774 st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
775}
776
777static void
778l2_stop_multi(struct FsmInst *fi, int event, void *arg)
779{
780 struct PStack *st = fi->userdata;
781 struct sk_buff *skb = arg;
782
783 FsmChangeState(fi, ST_L2_4);
784 FsmDelTimer(&st->l2.t203, 3);
785 stop_t200(st, 4);
786
787 send_uframe(st, UA | get_PollFlagFree(st, skb), RSP);
788
789 skb_queue_purge(&st->l2.i_queue);
790 freewin(st);
791 lapb_dl_release_l2l3(st, INDICATION);
792}
793
794static void
795l2_connected(struct FsmInst *fi, int event, void *arg)
796{
797 struct PStack *st = fi->userdata;
798 struct sk_buff *skb = arg;
799 int pr=-1;
800
801 if (!get_PollFlag(st, skb)) {
802 l2_mdl_error_ua(fi, event, arg);
803 return;
804 }
805 FreeSkb(skb);
806
807 if (test_and_clear_bit(FLG_PEND_REL, &st->l2.flag))
808 l2_disconnect(fi, event, arg);
809
810 if (test_and_clear_bit(FLG_L3_INIT, &st->l2.flag)) {
811 pr = DL_ESTABLISH | CONFIRM;
812 } else if (st->l2.vs != st->l2.va) {
813 skb_queue_purge(&st->l2.i_queue);
814 pr = DL_ESTABLISH | INDICATION;
815 }
816
817 stop_t200(st, 5);
818
819 st->l2.vr = 0;
820 st->l2.vs = 0;
821 st->l2.va = 0;
822 st->l2.sow = 0;
823 FsmChangeState(fi, ST_L2_7);
824 FsmAddTimer(&st->l2.t203, st->l2.T203, EV_L2_T203, NULL, 4);
825
826 if (pr != -1)
827 st->l2.l2l3(st, pr, NULL);
828
829 if (skb_queue_len(&st->l2.i_queue) && cansend(st))
830 st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
831}
832
833static void
834l2_released(struct FsmInst *fi, int event, void *arg)
835{
836 struct PStack *st = fi->userdata;
837 struct sk_buff *skb = arg;
838
839 if (!get_PollFlag(st, skb)) {
840 l2_mdl_error_ua(fi, event, arg);
841 return;
842 }
843 FreeSkb(skb);
844
845 stop_t200(st, 6);
846 lapb_dl_release_l2l3(st, CONFIRM);
847 FsmChangeState(fi, ST_L2_4);
848}
849
850static void
851l2_reestablish(struct FsmInst *fi, int event, void *arg)
852{
853 struct PStack *st = fi->userdata;
854 struct sk_buff *skb = arg;
855
856 if (!get_PollFlagFree(st, skb)) {
857 establishlink(fi);
858 test_and_set_bit(FLG_L3_INIT, &st->l2.flag);
859 }
860}
861
862static void
863l2_st5_dm_release(struct FsmInst *fi, int event, void *arg)
864{
865 struct PStack *st = fi->userdata;
866 struct sk_buff *skb = arg;
867
868 if (get_PollFlagFree(st, skb)) {
869 stop_t200(st, 7);
870 if (!test_bit(FLG_L3_INIT, &st->l2.flag))
871 skb_queue_purge(&st->l2.i_queue);
872 if (test_bit(FLG_LAPB, &st->l2.flag))
873 st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL);
874 st5_dl_release_l2l3(st);
875 FsmChangeState(fi, ST_L2_4);
876 }
877}
878
879static void
880l2_st6_dm_release(struct FsmInst *fi, int event, void *arg)
881{
882 struct PStack *st = fi->userdata;
883 struct sk_buff *skb = arg;
884
885 if (get_PollFlagFree(st, skb)) {
886 stop_t200(st, 8);
887 lapb_dl_release_l2l3(st, CONFIRM);
888 FsmChangeState(fi, ST_L2_4);
889 }
890}
891
892inline void
893enquiry_cr(struct PStack *st, u_char typ, u_char cr, u_char pf)
894{
895 struct sk_buff *skb;
896 struct Layer2 *l2;
897 u_char tmp[MAX_HEADER_LEN];
898 int i;
899
900 l2 = &st->l2;
901 i = sethdraddr(l2, tmp, cr);
902 if (test_bit(FLG_MOD128, &l2->flag)) {
903 tmp[i++] = typ;
904 tmp[i++] = (l2->vr << 1) | (pf ? 1 : 0);
905 } else
906 tmp[i++] = (l2->vr << 5) | typ | (pf ? 0x10 : 0);
907 if (!(skb = alloc_skb(i, GFP_ATOMIC))) {
908 printk(KERN_WARNING "isdl2 can't alloc sbbuff for enquiry_cr\n");
909 return;
910 }
911 memcpy(skb_put(skb, i), tmp, i);
912 enqueue_super(st, skb);
913}
914
915inline void
916enquiry_response(struct PStack *st)
917{
918 if (test_bit(FLG_OWN_BUSY, &st->l2.flag))
919 enquiry_cr(st, RNR, RSP, 1);
920 else
921 enquiry_cr(st, RR, RSP, 1);
922 test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag);
923}
924
925inline void
926transmit_enquiry(struct PStack *st)
927{
928 if (test_bit(FLG_OWN_BUSY, &st->l2.flag))
929 enquiry_cr(st, RNR, CMD, 1);
930 else
931 enquiry_cr(st, RR, CMD, 1);
932 test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag);
933 start_t200(st, 9);
934}
935
936
937static void
938nrerrorrecovery(struct FsmInst *fi)
939{
940 struct PStack *st = fi->userdata;
941
942 st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'J');
943 establishlink(fi);
944 test_and_clear_bit(FLG_L3_INIT, &st->l2.flag);
945}
946
947static void
948invoke_retransmission(struct PStack *st, unsigned int nr)
949{
950 struct Layer2 *l2 = &st->l2;
951 u_int p1;
952 u_long flags;
953
954 spin_lock_irqsave(&l2->lock, flags);
955 if (l2->vs != nr) {
956 while (l2->vs != nr) {
957 (l2->vs)--;
958 if(test_bit(FLG_MOD128, &l2->flag)) {
959 l2->vs %= 128;
960 p1 = (l2->vs - l2->va) % 128;
961 } else {
962 l2->vs %= 8;
963 p1 = (l2->vs - l2->va) % 8;
964 }
965 p1 = (p1 + l2->sow) % l2->window;
966 if (test_bit(FLG_LAPB, &l2->flag))
967 st->l1.bcs->tx_cnt += l2->windowar[p1]->len + l2headersize(l2, 0);
968 skb_queue_head(&l2->i_queue, l2->windowar[p1]);
969 l2->windowar[p1] = NULL;
970 }
971 spin_unlock_irqrestore(&l2->lock, flags);
972 st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
973 return;
974 }
975 spin_unlock_irqrestore(&l2->lock, flags);
976}
977
978static void
979l2_st7_got_super(struct FsmInst *fi, int event, void *arg)
980{
981 struct PStack *st = fi->userdata;
982 struct sk_buff *skb = arg;
983 int PollFlag, rsp, typ = RR;
984 unsigned int nr;
985 struct Layer2 *l2 = &st->l2;
986
987 rsp = *skb->data & 0x2;
988 if (test_bit(FLG_ORIG, &l2->flag))
989 rsp = !rsp;
990
991 skb_pull(skb, l2addrsize(l2));
992 if (IsRNR(skb->data, st)) {
993 set_peer_busy(l2);
994 typ = RNR;
995 } else
996 clear_peer_busy(l2);
997 if (IsREJ(skb->data, st))
998 typ = REJ;
999
1000 if (test_bit(FLG_MOD128, &l2->flag)) {
1001 PollFlag = (skb->data[1] & 0x1) == 0x1;
1002 nr = skb->data[1] >> 1;
1003 } else {
1004 PollFlag = (skb->data[0] & 0x10);
1005 nr = (skb->data[0] >> 5) & 0x7;
1006 }
1007 FreeSkb(skb);
1008
1009 if (PollFlag) {
1010 if (rsp)
1011 st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'A');
1012 else
1013 enquiry_response(st);
1014 }
1015 if (legalnr(st, nr)) {
1016 if (typ == REJ) {
1017 setva(st, nr);
1018 invoke_retransmission(st, nr);
1019 stop_t200(st, 10);
1020 if (FsmAddTimer(&st->l2.t203, st->l2.T203,
1021 EV_L2_T203, NULL, 6))
1022 l2m_debug(&st->l2.l2m, "Restart T203 ST7 REJ");
1023 } else if ((nr == l2->vs) && (typ == RR)) {
1024 setva(st, nr);
1025 stop_t200(st, 11);
1026 FsmRestartTimer(&st->l2.t203, st->l2.T203,
1027 EV_L2_T203, NULL, 7);
1028 } else if ((l2->va != nr) || (typ == RNR)) {
1029 setva(st, nr);
1030 if(typ != RR) FsmDelTimer(&st->l2.t203, 9);
1031 restart_t200(st, 12);
1032 }
1033 if (skb_queue_len(&st->l2.i_queue) && (typ == RR))
1034 st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
1035 } else
1036 nrerrorrecovery(fi);
1037}
1038
1039static void
1040l2_feed_i_if_reest(struct FsmInst *fi, int event, void *arg)
1041{
1042 struct PStack *st = fi->userdata;
1043 struct sk_buff *skb = arg;
1044
1045 if (test_bit(FLG_LAPB, &st->l2.flag))
1046 st->l1.bcs->tx_cnt += skb->len + l2headersize(&st->l2, 0);
1047 if (!test_bit(FLG_L3_INIT, &st->l2.flag))
1048 skb_queue_tail(&st->l2.i_queue, skb);
1049 else
1050 FreeSkb(skb);
1051}
1052
1053static void
1054l2_feed_i_pull(struct FsmInst *fi, int event, void *arg)
1055{
1056 struct PStack *st = fi->userdata;
1057 struct sk_buff *skb = arg;
1058
1059 if (test_bit(FLG_LAPB, &st->l2.flag))
1060 st->l1.bcs->tx_cnt += skb->len + l2headersize(&st->l2, 0);
1061 skb_queue_tail(&st->l2.i_queue, skb);
1062 st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
1063}
1064
1065static void
1066l2_feed_iqueue(struct FsmInst *fi, int event, void *arg)
1067{
1068 struct PStack *st = fi->userdata;
1069 struct sk_buff *skb = arg;
1070
1071 if (test_bit(FLG_LAPB, &st->l2.flag))
1072 st->l1.bcs->tx_cnt += skb->len + l2headersize(&st->l2, 0);
1073 skb_queue_tail(&st->l2.i_queue, skb);
1074}
1075
1076static void
1077l2_got_iframe(struct FsmInst *fi, int event, void *arg)
1078{
1079 struct PStack *st = fi->userdata;
1080 struct sk_buff *skb = arg;
1081 struct Layer2 *l2 = &(st->l2);
1082 int PollFlag, ns, i;
1083 unsigned int nr;
1084
1085 i = l2addrsize(l2);
1086 if (test_bit(FLG_MOD128, &l2->flag)) {
1087 PollFlag = ((skb->data[i + 1] & 0x1) == 0x1);
1088 ns = skb->data[i] >> 1;
1089 nr = (skb->data[i + 1] >> 1) & 0x7f;
1090 } else {
1091 PollFlag = (skb->data[i] & 0x10);
1092 ns = (skb->data[i] >> 1) & 0x7;
1093 nr = (skb->data[i] >> 5) & 0x7;
1094 }
1095 if (test_bit(FLG_OWN_BUSY, &l2->flag)) {
1096 FreeSkb(skb);
1097 if(PollFlag) enquiry_response(st);
1098 } else if (l2->vr == ns) {
1099 (l2->vr)++;
1100 if(test_bit(FLG_MOD128, &l2->flag))
1101 l2->vr %= 128;
1102 else
1103 l2->vr %= 8;
1104 test_and_clear_bit(FLG_REJEXC, &l2->flag);
1105
1106 if (PollFlag)
1107 enquiry_response(st);
1108 else
1109 test_and_set_bit(FLG_ACK_PEND, &l2->flag);
1110 skb_pull(skb, l2headersize(l2, 0));
1111 st->l2.l2l3(st, DL_DATA | INDICATION, skb);
1112 } else {
1113 /* n(s)!=v(r) */
1114 FreeSkb(skb);
1115 if (test_and_set_bit(FLG_REJEXC, &l2->flag)) {
1116 if (PollFlag)
1117 enquiry_response(st);
1118 } else {
1119 enquiry_cr(st, REJ, RSP, PollFlag);
1120 test_and_clear_bit(FLG_ACK_PEND, &l2->flag);
1121 }
1122 }
1123
1124 if (legalnr(st, nr)) {
1125 if (!test_bit(FLG_PEER_BUSY, &st->l2.flag) && (fi->state == ST_L2_7)) {
1126 if (nr == st->l2.vs) {
1127 stop_t200(st, 13);
1128 FsmRestartTimer(&st->l2.t203, st->l2.T203,
1129 EV_L2_T203, NULL, 7);
1130 } else if (nr != st->l2.va)
1131 restart_t200(st, 14);
1132 }
1133 setva(st, nr);
1134 } else {
1135 nrerrorrecovery(fi);
1136 return;
1137 }
1138
1139 if (skb_queue_len(&st->l2.i_queue) && (fi->state == ST_L2_7))
1140 st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
1141 if (test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag))
1142 enquiry_cr(st, RR, RSP, 0);
1143}
1144
1145static void
1146l2_got_tei(struct FsmInst *fi, int event, void *arg)
1147{
1148 struct PStack *st = fi->userdata;
1149
1150 st->l2.tei = (long) arg;
1151
1152 if (fi->state == ST_L2_3) {
1153 establishlink(fi);
1154 test_and_set_bit(FLG_L3_INIT, &st->l2.flag);
1155 } else
1156 FsmChangeState(fi, ST_L2_4);
1157 if (skb_queue_len(&st->l2.ui_queue))
1158 tx_ui(st);
1159}
1160
1161static void
1162l2_st5_tout_200(struct FsmInst *fi, int event, void *arg)
1163{
1164 struct PStack *st = fi->userdata;
1165
1166 if (test_bit(FLG_LAPD, &st->l2.flag) &&
1167 test_bit(FLG_DCHAN_BUSY, &st->l2.flag)) {
1168 FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 9);
1169 } else if (st->l2.rc == st->l2.N200) {
1170 FsmChangeState(fi, ST_L2_4);
1171 test_and_clear_bit(FLG_T200_RUN, &st->l2.flag);
1172 skb_queue_purge(&st->l2.i_queue);
1173 st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'G');
1174 if (test_bit(FLG_LAPB, &st->l2.flag))
1175 st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL);
1176 st5_dl_release_l2l3(st);
1177 } else {
1178 st->l2.rc++;
1179 FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 9);
1180 send_uframe(st, (test_bit(FLG_MOD128, &st->l2.flag) ? SABME : SABM)
1181 | 0x10, CMD);
1182 }
1183}
1184
1185static void
1186l2_st6_tout_200(struct FsmInst *fi, int event, void *arg)
1187{
1188 struct PStack *st = fi->userdata;
1189
1190 if (test_bit(FLG_LAPD, &st->l2.flag) &&
1191 test_bit(FLG_DCHAN_BUSY, &st->l2.flag)) {
1192 FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 9);
1193 } else if (st->l2.rc == st->l2.N200) {
1194 FsmChangeState(fi, ST_L2_4);
1195 test_and_clear_bit(FLG_T200_RUN, &st->l2.flag);
1196 st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'H');
1197 lapb_dl_release_l2l3(st, CONFIRM);
1198 } else {
1199 st->l2.rc++;
1200 FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200,
1201 NULL, 9);
1202 send_uframe(st, DISC | 0x10, CMD);
1203 }
1204}
1205
1206static void
1207l2_st7_tout_200(struct FsmInst *fi, int event, void *arg)
1208{
1209 struct PStack *st = fi->userdata;
1210
1211 if (test_bit(FLG_LAPD, &st->l2.flag) &&
1212 test_bit(FLG_DCHAN_BUSY, &st->l2.flag)) {
1213 FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 9);
1214 return;
1215 }
1216 test_and_clear_bit(FLG_T200_RUN, &st->l2.flag);
1217 st->l2.rc = 0;
1218 FsmChangeState(fi, ST_L2_8);
1219
1220 transmit_enquiry(st);
1221 st->l2.rc++;
1222}
1223
1224static void
1225l2_st8_tout_200(struct FsmInst *fi, int event, void *arg)
1226{
1227 struct PStack *st = fi->userdata;
1228
1229 if (test_bit(FLG_LAPD, &st->l2.flag) &&
1230 test_bit(FLG_DCHAN_BUSY, &st->l2.flag)) {
1231 FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 9);
1232 return;
1233 }
1234 test_and_clear_bit(FLG_T200_RUN, &st->l2.flag);
1235 if (st->l2.rc == st->l2.N200) {
1236 st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'I');
1237 establishlink(fi);
1238 test_and_clear_bit(FLG_L3_INIT, &st->l2.flag);
1239 } else {
1240 transmit_enquiry(st);
1241 st->l2.rc++;
1242 }
1243}
1244
1245static void
1246l2_st7_tout_203(struct FsmInst *fi, int event, void *arg)
1247{
1248 struct PStack *st = fi->userdata;
1249
1250 if (test_bit(FLG_LAPD, &st->l2.flag) &&
1251 test_bit(FLG_DCHAN_BUSY, &st->l2.flag)) {
1252 FsmAddTimer(&st->l2.t203, st->l2.T203, EV_L2_T203, NULL, 9);
1253 return;
1254 }
1255 FsmChangeState(fi, ST_L2_8);
1256 transmit_enquiry(st);
1257 st->l2.rc = 0;
1258}
1259
1260static void
1261l2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
1262{
1263 struct PStack *st = fi->userdata;
1264 struct sk_buff *skb, *oskb;
1265 struct Layer2 *l2 = &st->l2;
1266 u_char header[MAX_HEADER_LEN];
1267 int i;
1268 int unsigned p1;
1269 u_long flags;
1270
1271 if (!cansend(st))
1272 return;
1273
1274 skb = skb_dequeue(&l2->i_queue);
1275 if (!skb)
1276 return;
1277
1278 spin_lock_irqsave(&l2->lock, flags);
1279 if(test_bit(FLG_MOD128, &l2->flag))
1280 p1 = (l2->vs - l2->va) % 128;
1281 else
1282 p1 = (l2->vs - l2->va) % 8;
1283 p1 = (p1 + l2->sow) % l2->window;
1284 if (l2->windowar[p1]) {
1285 printk(KERN_WARNING "isdnl2 try overwrite ack queue entry %d\n",
1286 p1);
1287 dev_kfree_skb(l2->windowar[p1]);
1288 }
1289 l2->windowar[p1] = skb_clone(skb, GFP_ATOMIC);
1290
1291 i = sethdraddr(&st->l2, header, CMD);
1292
1293 if (test_bit(FLG_MOD128, &l2->flag)) {
1294 header[i++] = l2->vs << 1;
1295 header[i++] = l2->vr << 1;
1296 l2->vs = (l2->vs + 1) % 128;
1297 } else {
1298 header[i++] = (l2->vr << 5) | (l2->vs << 1);
1299 l2->vs = (l2->vs + 1) % 8;
1300 }
1301 spin_unlock_irqrestore(&l2->lock, flags);
1302 p1 = skb->data - skb->head;
1303 if (p1 >= i)
1304 memcpy(skb_push(skb, i), header, i);
1305 else {
1306 printk(KERN_WARNING
1307 "isdl2 pull_iqueue skb header(%d/%d) too short\n", i, p1);
1308 oskb = skb;
1309 skb = alloc_skb(oskb->len + i, GFP_ATOMIC);
1310 memcpy(skb_put(skb, i), header, i);
1311 memcpy(skb_put(skb, oskb->len), oskb->data, oskb->len);
1312 FreeSkb(oskb);
1313 }
1314 st->l2.l2l1(st, PH_PULL | INDICATION, skb);
1315 test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag);
1316 if (!test_and_set_bit(FLG_T200_RUN, &st->l2.flag)) {
1317 FsmDelTimer(&st->l2.t203, 13);
1318 FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 11);
1319 }
1320 if (skb_queue_len(&l2->i_queue) && cansend(st))
1321 st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
1322}
1323
1324static void
1325l2_st8_got_super(struct FsmInst *fi, int event, void *arg)
1326{
1327 struct PStack *st = fi->userdata;
1328 struct sk_buff *skb = arg;
1329 int PollFlag, rsp, rnr = 0;
1330 unsigned int nr;
1331 struct Layer2 *l2 = &st->l2;
1332
1333 rsp = *skb->data & 0x2;
1334 if (test_bit(FLG_ORIG, &l2->flag))
1335 rsp = !rsp;
1336
1337 skb_pull(skb, l2addrsize(l2));
1338
1339 if (IsRNR(skb->data, st)) {
1340 set_peer_busy(l2);
1341 rnr = 1;
1342 } else
1343 clear_peer_busy(l2);
1344
1345 if (test_bit(FLG_MOD128, &l2->flag)) {
1346 PollFlag = (skb->data[1] & 0x1) == 0x1;
1347 nr = skb->data[1] >> 1;
1348 } else {
1349 PollFlag = (skb->data[0] & 0x10);
1350 nr = (skb->data[0] >> 5) & 0x7;
1351 }
1352 FreeSkb(skb);
1353
1354 if (rsp && PollFlag) {
1355 if (legalnr(st, nr)) {
1356 if (rnr) {
1357 restart_t200(st, 15);
1358 } else {
1359 stop_t200(st, 16);
1360 FsmAddTimer(&l2->t203, l2->T203,
1361 EV_L2_T203, NULL, 5);
1362 setva(st, nr);
1363 }
1364 invoke_retransmission(st, nr);
1365 FsmChangeState(fi, ST_L2_7);
1366 if (skb_queue_len(&l2->i_queue) && cansend(st))
1367 st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
1368 } else
1369 nrerrorrecovery(fi);
1370 } else {
1371 if (!rsp && PollFlag)
1372 enquiry_response(st);
1373 if (legalnr(st, nr)) {
1374 setva(st, nr);
1375 } else
1376 nrerrorrecovery(fi);
1377 }
1378}
1379
1380static void
1381l2_got_FRMR(struct FsmInst *fi, int event, void *arg)
1382{
1383 struct PStack *st = fi->userdata;
1384 struct sk_buff *skb = arg;
1385
1386 skb_pull(skb, l2addrsize(&st->l2) + 1);
1387
1388 if (!(skb->data[0] & 1) || ((skb->data[0] & 3) == 1) || /* I or S */
1389 (IsUA(skb->data) && (fi->state == ST_L2_7))) {
1390 st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'K');
1391 establishlink(fi);
1392 test_and_clear_bit(FLG_L3_INIT, &st->l2.flag);
1393 }
1394 FreeSkb(skb);
1395}
1396
1397static void
1398l2_st24_tei_remove(struct FsmInst *fi, int event, void *arg)
1399{
1400 struct PStack *st = fi->userdata;
1401
1402 skb_queue_purge(&st->l2.ui_queue);
1403 st->l2.tei = -1;
1404 FsmChangeState(fi, ST_L2_1);
1405}
1406
1407static void
1408l2_st3_tei_remove(struct FsmInst *fi, int event, void *arg)
1409{
1410 struct PStack *st = fi->userdata;
1411
1412 skb_queue_purge(&st->l2.ui_queue);
1413 st->l2.tei = -1;
1414 st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL);
1415 FsmChangeState(fi, ST_L2_1);
1416}
1417
1418static void
1419l2_st5_tei_remove(struct FsmInst *fi, int event, void *arg)
1420{
1421 struct PStack *st = fi->userdata;
1422
1423 skb_queue_purge(&st->l2.i_queue);
1424 skb_queue_purge(&st->l2.ui_queue);
1425 freewin(st);
1426 st->l2.tei = -1;
1427 stop_t200(st, 17);
1428 st5_dl_release_l2l3(st);
1429 FsmChangeState(fi, ST_L2_1);
1430}
1431
1432static void
1433l2_st6_tei_remove(struct FsmInst *fi, int event, void *arg)
1434{
1435 struct PStack *st = fi->userdata;
1436
1437 skb_queue_purge(&st->l2.ui_queue);
1438 st->l2.tei = -1;
1439 stop_t200(st, 18);
1440 st->l2.l2l3(st, DL_RELEASE | CONFIRM, NULL);
1441 FsmChangeState(fi, ST_L2_1);
1442}
1443
1444static void
1445l2_tei_remove(struct FsmInst *fi, int event, void *arg)
1446{
1447 struct PStack *st = fi->userdata;
1448
1449 skb_queue_purge(&st->l2.i_queue);
1450 skb_queue_purge(&st->l2.ui_queue);
1451 freewin(st);
1452 st->l2.tei = -1;
1453 stop_t200(st, 17);
1454 FsmDelTimer(&st->l2.t203, 19);
1455 st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL);
1456 FsmChangeState(fi, ST_L2_1);
1457}
1458
1459static void
1460l2_st14_persistant_da(struct FsmInst *fi, int event, void *arg)
1461{
1462 struct PStack *st = fi->userdata;
1463
1464 skb_queue_purge(&st->l2.i_queue);
1465 skb_queue_purge(&st->l2.ui_queue);
1466 if (test_and_clear_bit(FLG_ESTAB_PEND, &st->l2.flag))
1467 st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL);
1468}
1469
1470static void
1471l2_st5_persistant_da(struct FsmInst *fi, int event, void *arg)
1472{
1473 struct PStack *st = fi->userdata;
1474
1475 skb_queue_purge(&st->l2.i_queue);
1476 skb_queue_purge(&st->l2.ui_queue);
1477 freewin(st);
1478 stop_t200(st, 19);
1479 st5_dl_release_l2l3(st);
1480 FsmChangeState(fi, ST_L2_4);
1481}
1482
1483static void
1484l2_st6_persistant_da(struct FsmInst *fi, int event, void *arg)
1485{
1486 struct PStack *st = fi->userdata;
1487
1488 skb_queue_purge(&st->l2.ui_queue);
1489 stop_t200(st, 20);
1490 st->l2.l2l3(st, DL_RELEASE | CONFIRM, NULL);
1491 FsmChangeState(fi, ST_L2_4);
1492}
1493
1494static void
1495l2_persistant_da(struct FsmInst *fi, int event, void *arg)
1496{
1497 struct PStack *st = fi->userdata;
1498
1499 skb_queue_purge(&st->l2.i_queue);
1500 skb_queue_purge(&st->l2.ui_queue);
1501 freewin(st);
1502 stop_t200(st, 19);
1503 FsmDelTimer(&st->l2.t203, 19);
1504 st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL);
1505 FsmChangeState(fi, ST_L2_4);
1506}
1507
1508static void
1509l2_set_own_busy(struct FsmInst *fi, int event, void *arg)
1510{
1511 struct PStack *st = fi->userdata;
1512
1513 if(!test_and_set_bit(FLG_OWN_BUSY, &st->l2.flag)) {
1514 enquiry_cr(st, RNR, RSP, 0);
1515 test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag);
1516 }
1517}
1518
1519static void
1520l2_clear_own_busy(struct FsmInst *fi, int event, void *arg)
1521{
1522 struct PStack *st = fi->userdata;
1523
1524 if(!test_and_clear_bit(FLG_OWN_BUSY, &st->l2.flag)) {
1525 enquiry_cr(st, RR, RSP, 0);
1526 test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag);
1527 }
1528}
1529
1530static void
1531l2_frame_error(struct FsmInst *fi, int event, void *arg)
1532{
1533 struct PStack *st = fi->userdata;
1534
1535 st->ma.layer(st, MDL_ERROR | INDICATION, arg);
1536}
1537
1538static void
1539l2_frame_error_reest(struct FsmInst *fi, int event, void *arg)
1540{
1541 struct PStack *st = fi->userdata;
1542
1543 st->ma.layer(st, MDL_ERROR | INDICATION, arg);
1544 establishlink(fi);
1545 test_and_clear_bit(FLG_L3_INIT, &st->l2.flag);
1546}
1547
1548static struct FsmNode L2FnList[] __initdata =
1549{
1550 {ST_L2_1, EV_L2_DL_ESTABLISH_REQ, l2_mdl_assign},
1551 {ST_L2_2, EV_L2_DL_ESTABLISH_REQ, l2_go_st3},
1552 {ST_L2_4, EV_L2_DL_ESTABLISH_REQ, l2_establish},
1553 {ST_L2_5, EV_L2_DL_ESTABLISH_REQ, l2_discard_i_setl3},
1554 {ST_L2_7, EV_L2_DL_ESTABLISH_REQ, l2_l3_reestablish},
1555 {ST_L2_8, EV_L2_DL_ESTABLISH_REQ, l2_l3_reestablish},
1556 {ST_L2_4, EV_L2_DL_RELEASE_REQ, l2_release},
1557 {ST_L2_5, EV_L2_DL_RELEASE_REQ, l2_pend_rel},
1558 {ST_L2_7, EV_L2_DL_RELEASE_REQ, l2_disconnect},
1559 {ST_L2_8, EV_L2_DL_RELEASE_REQ, l2_disconnect},
1560 {ST_L2_5, EV_L2_DL_DATA, l2_feed_i_if_reest},
1561 {ST_L2_7, EV_L2_DL_DATA, l2_feed_i_pull},
1562 {ST_L2_8, EV_L2_DL_DATA, l2_feed_iqueue},
1563 {ST_L2_1, EV_L2_DL_UNIT_DATA, l2_queue_ui_assign},
1564 {ST_L2_2, EV_L2_DL_UNIT_DATA, l2_queue_ui},
1565 {ST_L2_3, EV_L2_DL_UNIT_DATA, l2_queue_ui},
1566 {ST_L2_4, EV_L2_DL_UNIT_DATA, l2_send_ui},
1567 {ST_L2_5, EV_L2_DL_UNIT_DATA, l2_send_ui},
1568 {ST_L2_6, EV_L2_DL_UNIT_DATA, l2_send_ui},
1569 {ST_L2_7, EV_L2_DL_UNIT_DATA, l2_send_ui},
1570 {ST_L2_8, EV_L2_DL_UNIT_DATA, l2_send_ui},
1571 {ST_L2_1, EV_L2_MDL_ASSIGN, l2_got_tei},
1572 {ST_L2_2, EV_L2_MDL_ASSIGN, l2_got_tei},
1573 {ST_L2_3, EV_L2_MDL_ASSIGN, l2_got_tei},
1574 {ST_L2_2, EV_L2_MDL_ERROR, l2_st24_tei_remove},
1575 {ST_L2_3, EV_L2_MDL_ERROR, l2_st3_tei_remove},
1576 {ST_L2_4, EV_L2_MDL_REMOVE, l2_st24_tei_remove},
1577 {ST_L2_5, EV_L2_MDL_REMOVE, l2_st5_tei_remove},
1578 {ST_L2_6, EV_L2_MDL_REMOVE, l2_st6_tei_remove},
1579 {ST_L2_7, EV_L2_MDL_REMOVE, l2_tei_remove},
1580 {ST_L2_8, EV_L2_MDL_REMOVE, l2_tei_remove},
1581 {ST_L2_4, EV_L2_SABME, l2_start_multi},
1582 {ST_L2_5, EV_L2_SABME, l2_send_UA},
1583 {ST_L2_6, EV_L2_SABME, l2_send_DM},
1584 {ST_L2_7, EV_L2_SABME, l2_restart_multi},
1585 {ST_L2_8, EV_L2_SABME, l2_restart_multi},
1586 {ST_L2_4, EV_L2_DISC, l2_send_DM},
1587 {ST_L2_5, EV_L2_DISC, l2_send_DM},
1588 {ST_L2_6, EV_L2_DISC, l2_send_UA},
1589 {ST_L2_7, EV_L2_DISC, l2_stop_multi},
1590 {ST_L2_8, EV_L2_DISC, l2_stop_multi},
1591 {ST_L2_4, EV_L2_UA, l2_mdl_error_ua},
1592 {ST_L2_5, EV_L2_UA, l2_connected},
1593 {ST_L2_6, EV_L2_UA, l2_released},
1594 {ST_L2_7, EV_L2_UA, l2_mdl_error_ua},
1595 {ST_L2_8, EV_L2_UA, l2_mdl_error_ua},
1596 {ST_L2_4, EV_L2_DM, l2_reestablish},
1597 {ST_L2_5, EV_L2_DM, l2_st5_dm_release},
1598 {ST_L2_6, EV_L2_DM, l2_st6_dm_release},
1599 {ST_L2_7, EV_L2_DM, l2_mdl_error_dm},
1600 {ST_L2_8, EV_L2_DM, l2_st8_mdl_error_dm},
1601 {ST_L2_1, EV_L2_UI, l2_got_ui},
1602 {ST_L2_2, EV_L2_UI, l2_got_ui},
1603 {ST_L2_3, EV_L2_UI, l2_got_ui},
1604 {ST_L2_4, EV_L2_UI, l2_got_ui},
1605 {ST_L2_5, EV_L2_UI, l2_got_ui},
1606 {ST_L2_6, EV_L2_UI, l2_got_ui},
1607 {ST_L2_7, EV_L2_UI, l2_got_ui},
1608 {ST_L2_8, EV_L2_UI, l2_got_ui},
1609 {ST_L2_7, EV_L2_FRMR, l2_got_FRMR},
1610 {ST_L2_8, EV_L2_FRMR, l2_got_FRMR},
1611 {ST_L2_7, EV_L2_SUPER, l2_st7_got_super},
1612 {ST_L2_8, EV_L2_SUPER, l2_st8_got_super},
1613 {ST_L2_7, EV_L2_I, l2_got_iframe},
1614 {ST_L2_8, EV_L2_I, l2_got_iframe},
1615 {ST_L2_5, EV_L2_T200, l2_st5_tout_200},
1616 {ST_L2_6, EV_L2_T200, l2_st6_tout_200},
1617 {ST_L2_7, EV_L2_T200, l2_st7_tout_200},
1618 {ST_L2_8, EV_L2_T200, l2_st8_tout_200},
1619 {ST_L2_7, EV_L2_T203, l2_st7_tout_203},
1620 {ST_L2_7, EV_L2_ACK_PULL, l2_pull_iqueue},
1621 {ST_L2_7, EV_L2_SET_OWN_BUSY, l2_set_own_busy},
1622 {ST_L2_8, EV_L2_SET_OWN_BUSY, l2_set_own_busy},
1623 {ST_L2_7, EV_L2_CLEAR_OWN_BUSY, l2_clear_own_busy},
1624 {ST_L2_8, EV_L2_CLEAR_OWN_BUSY, l2_clear_own_busy},
1625 {ST_L2_4, EV_L2_FRAME_ERROR, l2_frame_error},
1626 {ST_L2_5, EV_L2_FRAME_ERROR, l2_frame_error},
1627 {ST_L2_6, EV_L2_FRAME_ERROR, l2_frame_error},
1628 {ST_L2_7, EV_L2_FRAME_ERROR, l2_frame_error_reest},
1629 {ST_L2_8, EV_L2_FRAME_ERROR, l2_frame_error_reest},
1630 {ST_L2_1, EV_L1_DEACTIVATE, l2_st14_persistant_da},
1631 {ST_L2_2, EV_L1_DEACTIVATE, l2_st24_tei_remove},
1632 {ST_L2_3, EV_L1_DEACTIVATE, l2_st3_tei_remove},
1633 {ST_L2_4, EV_L1_DEACTIVATE, l2_st14_persistant_da},
1634 {ST_L2_5, EV_L1_DEACTIVATE, l2_st5_persistant_da},
1635 {ST_L2_6, EV_L1_DEACTIVATE, l2_st6_persistant_da},
1636 {ST_L2_7, EV_L1_DEACTIVATE, l2_persistant_da},
1637 {ST_L2_8, EV_L1_DEACTIVATE, l2_persistant_da},
1638};
1639
1640#define L2_FN_COUNT (sizeof(L2FnList)/sizeof(struct FsmNode))
1641
1642static void
1643isdnl2_l1l2(struct PStack *st, int pr, void *arg)
1644{
1645 struct sk_buff *skb = arg;
1646 u_char *datap;
1647 int ret = 1, len;
1648 int c = 0;
1649
1650 switch (pr) {
1651 case (PH_DATA | INDICATION):
1652 datap = skb->data;
1653 len = l2addrsize(&st->l2);
1654 if (skb->len > len)
1655 datap += len;
1656 else {
1657 FsmEvent(&st->l2.l2m, EV_L2_FRAME_ERROR, (void *) 'N');
1658 FreeSkb(skb);
1659 return;
1660 }
1661 if (!(*datap & 1)) { /* I-Frame */
1662 if(!(c = iframe_error(st, skb)))
1663 ret = FsmEvent(&st->l2.l2m, EV_L2_I, skb);
1664 } else if (IsSFrame(datap, st)) { /* S-Frame */
1665 if(!(c = super_error(st, skb)))
1666 ret = FsmEvent(&st->l2.l2m, EV_L2_SUPER, skb);
1667 } else if (IsUI(datap)) {
1668 if(!(c = UI_error(st, skb)))
1669 ret = FsmEvent(&st->l2.l2m, EV_L2_UI, skb);
1670 } else if (IsSABME(datap, st)) {
1671 if(!(c = unnum_error(st, skb, CMD)))
1672 ret = FsmEvent(&st->l2.l2m, EV_L2_SABME, skb);
1673 } else if (IsUA(datap)) {
1674 if(!(c = unnum_error(st, skb, RSP)))
1675 ret = FsmEvent(&st->l2.l2m, EV_L2_UA, skb);
1676 } else if (IsDISC(datap)) {
1677 if(!(c = unnum_error(st, skb, CMD)))
1678 ret = FsmEvent(&st->l2.l2m, EV_L2_DISC, skb);
1679 } else if (IsDM(datap)) {
1680 if(!(c = unnum_error(st, skb, RSP)))
1681 ret = FsmEvent(&st->l2.l2m, EV_L2_DM, skb);
1682 } else if (IsFRMR(datap)) {
1683 if(!(c = FRMR_error(st,skb)))
1684 ret = FsmEvent(&st->l2.l2m, EV_L2_FRMR, skb);
1685 } else {
1686 FsmEvent(&st->l2.l2m, EV_L2_FRAME_ERROR, (void *) 'L');
1687 FreeSkb(skb);
1688 ret = 0;
1689 }
1690 if(c) {
1691 FreeSkb(skb);
1692 FsmEvent(&st->l2.l2m, EV_L2_FRAME_ERROR, (void *)(long)c);
1693 ret = 0;
1694 }
1695 if (ret)
1696 FreeSkb(skb);
1697 break;
1698 case (PH_PULL | CONFIRM):
1699 FsmEvent(&st->l2.l2m, EV_L2_ACK_PULL, arg);
1700 break;
1701 case (PH_PAUSE | INDICATION):
1702 test_and_set_bit(FLG_DCHAN_BUSY, &st->l2.flag);
1703 break;
1704 case (PH_PAUSE | CONFIRM):
1705 test_and_clear_bit(FLG_DCHAN_BUSY, &st->l2.flag);
1706 break;
1707 case (PH_ACTIVATE | CONFIRM):
1708 case (PH_ACTIVATE | INDICATION):
1709 test_and_set_bit(FLG_L1_ACTIV, &st->l2.flag);
1710 if (test_and_clear_bit(FLG_ESTAB_PEND, &st->l2.flag))
1711 FsmEvent(&st->l2.l2m, EV_L2_DL_ESTABLISH_REQ, arg);
1712 break;
1713 case (PH_DEACTIVATE | INDICATION):
1714 case (PH_DEACTIVATE | CONFIRM):
1715 test_and_clear_bit(FLG_L1_ACTIV, &st->l2.flag);
1716 FsmEvent(&st->l2.l2m, EV_L1_DEACTIVATE, arg);
1717 break;
1718 default:
1719 l2m_debug(&st->l2.l2m, "l2 unknown pr %04x", pr);
1720 break;
1721 }
1722}
1723
1724static void
1725isdnl2_l3l2(struct PStack *st, int pr, void *arg)
1726{
1727 switch (pr) {
1728 case (DL_DATA | REQUEST):
1729 if (FsmEvent(&st->l2.l2m, EV_L2_DL_DATA, arg)) {
1730 dev_kfree_skb((struct sk_buff *) arg);
1731 }
1732 break;
1733 case (DL_UNIT_DATA | REQUEST):
1734 if (FsmEvent(&st->l2.l2m, EV_L2_DL_UNIT_DATA, arg)) {
1735 dev_kfree_skb((struct sk_buff *) arg);
1736 }
1737 break;
1738 case (DL_ESTABLISH | REQUEST):
1739 if (test_bit(FLG_L1_ACTIV, &st->l2.flag)) {
1740 if (test_bit(FLG_LAPD, &st->l2.flag) ||
1741 test_bit(FLG_ORIG, &st->l2.flag)) {
1742 FsmEvent(&st->l2.l2m, EV_L2_DL_ESTABLISH_REQ, arg);
1743 }
1744 } else {
1745 if (test_bit(FLG_LAPD, &st->l2.flag) ||
1746 test_bit(FLG_ORIG, &st->l2.flag)) {
1747 test_and_set_bit(FLG_ESTAB_PEND, &st->l2.flag);
1748 }
1749 st->l2.l2l1(st, PH_ACTIVATE, NULL);
1750 }
1751 break;
1752 case (DL_RELEASE | REQUEST):
1753 if (test_bit(FLG_LAPB, &st->l2.flag)) {
1754 st->l2.l2l1(st, PH_DEACTIVATE, NULL);
1755 }
1756 FsmEvent(&st->l2.l2m, EV_L2_DL_RELEASE_REQ, arg);
1757 break;
1758 case (MDL_ASSIGN | REQUEST):
1759 FsmEvent(&st->l2.l2m, EV_L2_MDL_ASSIGN, arg);
1760 break;
1761 case (MDL_REMOVE | REQUEST):
1762 FsmEvent(&st->l2.l2m, EV_L2_MDL_REMOVE, arg);
1763 break;
1764 case (MDL_ERROR | RESPONSE):
1765 FsmEvent(&st->l2.l2m, EV_L2_MDL_ERROR, arg);
1766 break;
1767 }
1768}
1769
1770void
1771releasestack_isdnl2(struct PStack *st)
1772{
1773 FsmDelTimer(&st->l2.t200, 21);
1774 FsmDelTimer(&st->l2.t203, 16);
1775 skb_queue_purge(&st->l2.i_queue);
1776 skb_queue_purge(&st->l2.ui_queue);
1777 ReleaseWin(&st->l2);
1778}
1779
1780static void
1781l2m_debug(struct FsmInst *fi, char *fmt, ...)
1782{
1783 va_list args;
1784 struct PStack *st = fi->userdata;
1785
1786 va_start(args, fmt);
1787 VHiSax_putstatus(st->l1.hardware, st->l2.debug_id, fmt, args);
1788 va_end(args);
1789}
1790
1791void
1792setstack_isdnl2(struct PStack *st, char *debug_id)
1793{
1794 spin_lock_init(&st->l2.lock);
1795 st->l1.l1l2 = isdnl2_l1l2;
1796 st->l3.l3l2 = isdnl2_l3l2;
1797
1798 skb_queue_head_init(&st->l2.i_queue);
1799 skb_queue_head_init(&st->l2.ui_queue);
1800 InitWin(&st->l2);
1801 st->l2.debug = 0;
1802
1803 st->l2.l2m.fsm = &l2fsm;
1804 if (test_bit(FLG_LAPB, &st->l2.flag))
1805 st->l2.l2m.state = ST_L2_4;
1806 else
1807 st->l2.l2m.state = ST_L2_1;
1808 st->l2.l2m.debug = 0;
1809 st->l2.l2m.userdata = st;
1810 st->l2.l2m.userint = 0;
1811 st->l2.l2m.printdebug = l2m_debug;
1812 strcpy(st->l2.debug_id, debug_id);
1813
1814 FsmInitTimer(&st->l2.l2m, &st->l2.t200);
1815 FsmInitTimer(&st->l2.l2m, &st->l2.t203);
1816}
1817
1818static void
1819transl2_l3l2(struct PStack *st, int pr, void *arg)
1820{
1821 switch (pr) {
1822 case (DL_DATA | REQUEST):
1823 case (DL_UNIT_DATA | REQUEST):
1824 st->l2.l2l1(st, PH_DATA | REQUEST, arg);
1825 break;
1826 case (DL_ESTABLISH | REQUEST):
1827 st->l2.l2l1(st, PH_ACTIVATE | REQUEST, NULL);
1828 break;
1829 case (DL_RELEASE | REQUEST):
1830 st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL);
1831 break;
1832 }
1833}
1834
1835void
1836setstack_transl2(struct PStack *st)
1837{
1838 st->l3.l3l2 = transl2_l3l2;
1839}
1840
1841void
1842releasestack_transl2(struct PStack *st)
1843{
1844}
1845
1846int __init
1847Isdnl2New(void)
1848{
1849 l2fsm.state_count = L2_STATE_COUNT;
1850 l2fsm.event_count = L2_EVENT_COUNT;
1851 l2fsm.strEvent = strL2Event;
1852 l2fsm.strState = strL2State;
1853 return FsmNew(&l2fsm, L2FnList, L2_FN_COUNT);
1854}
1855
1856void
1857Isdnl2Free(void)
1858{
1859 FsmFree(&l2fsm);
1860}
diff --git a/drivers/isdn/hisax/isdnl2.h b/drivers/isdn/hisax/isdnl2.h
new file mode 100644
index 000000000000..0cdab1b73fac
--- /dev/null
+++ b/drivers/isdn/hisax/isdnl2.h
@@ -0,0 +1,26 @@
1/* $Id: isdnl2.h,v 1.3.6.2 2001/09/23 22:24:49 kai Exp $
2 *
3 * Layer 2 defines
4 *
5 * This software may be used and distributed according to the terms
6 * of the GNU General Public License, incorporated herein by reference.
7 *
8 */
9
10#define RR 0x01
11#define RNR 0x05
12#define REJ 0x09
13#define SABME 0x6f
14#define SABM 0x2f
15#define DM 0x0f
16#define UI 0x03
17#define DISC 0x43
18#define UA 0x63
19#define FRMR 0x87
20#define XID 0xaf
21
22#define CMD 0
23#define RSP 1
24
25#define LC_FLUSH_WAIT 1
26
diff --git a/drivers/isdn/hisax/isdnl3.c b/drivers/isdn/hisax/isdnl3.c
new file mode 100644
index 000000000000..f571b5d18e91
--- /dev/null
+++ b/drivers/isdn/hisax/isdnl3.c
@@ -0,0 +1,610 @@
1/* $Id: isdnl3.c,v 2.22.2.3 2004/01/13 14:31:25 keil Exp $
2 *
3 * Author Karsten Keil
4 * based on the teles driver from Jan den Ouden
5 * Copyright by Karsten Keil <keil@isdn4linux.de>
6 *
7 * This software may be used and distributed according to the terms
8 * of the GNU General Public License, incorporated herein by reference.
9 *
10 * For changes and modifications please read
11 * Documentation/isdn/HiSax.cert
12 *
13 * Thanks to Jan den Ouden
14 * Fritz Elfert
15 *
16 */
17
18#include <linux/init.h>
19#include "hisax.h"
20#include "isdnl3.h"
21#include <linux/config.h>
22
23const char *l3_revision = "$Revision: 2.22.2.3 $";
24
25static struct Fsm l3fsm;
26
27enum {
28 ST_L3_LC_REL,
29 ST_L3_LC_ESTAB_WAIT,
30 ST_L3_LC_REL_DELAY,
31 ST_L3_LC_REL_WAIT,
32 ST_L3_LC_ESTAB,
33};
34
35#define L3_STATE_COUNT (ST_L3_LC_ESTAB+1)
36
37static char *strL3State[] =
38{
39 "ST_L3_LC_REL",
40 "ST_L3_LC_ESTAB_WAIT",
41 "ST_L3_LC_REL_DELAY",
42 "ST_L3_LC_REL_WAIT",
43 "ST_L3_LC_ESTAB",
44};
45
46enum {
47 EV_ESTABLISH_REQ,
48 EV_ESTABLISH_IND,
49 EV_ESTABLISH_CNF,
50 EV_RELEASE_REQ,
51 EV_RELEASE_CNF,
52 EV_RELEASE_IND,
53 EV_TIMEOUT,
54};
55
56#define L3_EVENT_COUNT (EV_TIMEOUT+1)
57
58static char *strL3Event[] =
59{
60 "EV_ESTABLISH_REQ",
61 "EV_ESTABLISH_IND",
62 "EV_ESTABLISH_CNF",
63 "EV_RELEASE_REQ",
64 "EV_RELEASE_CNF",
65 "EV_RELEASE_IND",
66 "EV_TIMEOUT",
67};
68
69static void
70l3m_debug(struct FsmInst *fi, char *fmt, ...)
71{
72 va_list args;
73 struct PStack *st = fi->userdata;
74
75 va_start(args, fmt);
76 VHiSax_putstatus(st->l1.hardware, st->l3.debug_id, fmt, args);
77 va_end(args);
78}
79
80u_char *
81findie(u_char * p, int size, u_char ie, int wanted_set)
82{
83 int l, codeset, maincodeset;
84 u_char *pend = p + size;
85
86 /* skip protocol discriminator, callref and message type */
87 p++;
88 l = (*p++) & 0xf;
89 p += l;
90 p++;
91 codeset = 0;
92 maincodeset = 0;
93 /* while there are bytes left... */
94 while (p < pend) {
95 if ((*p & 0xf0) == 0x90) {
96 codeset = *p & 0x07;
97 if (!(*p & 0x08))
98 maincodeset = codeset;
99 }
100 if (*p & 0x80)
101 p++;
102 else {
103 if (codeset == wanted_set) {
104 if (*p == ie)
105 { /* improved length check (Werner Cornelius) */
106 if ((pend - p) < 2)
107 return(NULL);
108 if (*(p+1) > (pend - (p+2)))
109 return(NULL);
110 return (p);
111 }
112
113 if (*p > ie)
114 return (NULL);
115 }
116 p++;
117 l = *p++;
118 p += l;
119 codeset = maincodeset;
120 }
121 }
122 return (NULL);
123}
124
125int
126getcallref(u_char * p)
127{
128 int l, cr = 0;
129
130 p++; /* prot discr */
131 if (*p & 0xfe) /* wrong callref BRI only 1 octet*/
132 return(-2);
133 l = 0xf & *p++; /* callref length */
134 if (!l) /* dummy CallRef */
135 return(-1);
136 cr = *p++;
137 return (cr);
138}
139
140static int OrigCallRef = 0;
141
142int
143newcallref(void)
144{
145 if (OrigCallRef == 127)
146 OrigCallRef = 1;
147 else
148 OrigCallRef++;
149 return (OrigCallRef);
150}
151
152void
153newl3state(struct l3_process *pc, int state)
154{
155 if (pc->debug & L3_DEB_STATE)
156 l3_debug(pc->st, "newstate cr %d %d --> %d",
157 pc->callref & 0x7F,
158 pc->state, state);
159 pc->state = state;
160}
161
162static void
163L3ExpireTimer(struct L3Timer *t)
164{
165 t->pc->st->lli.l4l3(t->pc->st, t->event, t->pc);
166}
167
168void
169L3InitTimer(struct l3_process *pc, struct L3Timer *t)
170{
171 t->pc = pc;
172 t->tl.function = (void *) L3ExpireTimer;
173 t->tl.data = (long) t;
174 init_timer(&t->tl);
175}
176
177void
178L3DelTimer(struct L3Timer *t)
179{
180 del_timer(&t->tl);
181}
182
183int
184L3AddTimer(struct L3Timer *t,
185 int millisec, int event)
186{
187 if (timer_pending(&t->tl)) {
188 printk(KERN_WARNING "L3AddTimer: timer already active!\n");
189 return -1;
190 }
191 init_timer(&t->tl);
192 t->event = event;
193 t->tl.expires = jiffies + (millisec * HZ) / 1000;
194 add_timer(&t->tl);
195 return 0;
196}
197
198void
199StopAllL3Timer(struct l3_process *pc)
200{
201 L3DelTimer(&pc->timer);
202}
203
204struct sk_buff *
205l3_alloc_skb(int len)
206{
207 struct sk_buff *skb;
208
209 if (!(skb = alloc_skb(len + MAX_HEADER_LEN, GFP_ATOMIC))) {
210 printk(KERN_WARNING "HiSax: No skb for D-channel\n");
211 return (NULL);
212 }
213 skb_reserve(skb, MAX_HEADER_LEN);
214 return (skb);
215}
216
217static void
218no_l3_proto(struct PStack *st, int pr, void *arg)
219{
220 struct sk_buff *skb = arg;
221
222 HiSax_putstatus(st->l1.hardware, "L3", "no D protocol");
223 if (skb) {
224 dev_kfree_skb(skb);
225 }
226}
227
228static int
229no_l3_proto_spec(struct PStack *st, isdn_ctrl *ic)
230{
231 printk(KERN_WARNING "HiSax: no specific protocol handler for proto %lu\n",ic->arg & 0xFF);
232 return(-1);
233}
234
235#ifdef CONFIG_HISAX_EURO
236extern void setstack_dss1(struct PStack *st);
237#endif
238
239#ifdef CONFIG_HISAX_NI1
240extern void setstack_ni1(struct PStack *st);
241#endif
242
243#ifdef CONFIG_HISAX_1TR6
244extern void setstack_1tr6(struct PStack *st);
245#endif
246
247struct l3_process
248*getl3proc(struct PStack *st, int cr)
249{
250 struct l3_process *p = st->l3.proc;
251
252 while (p)
253 if (p->callref == cr)
254 return (p);
255 else
256 p = p->next;
257 return (NULL);
258}
259
260struct l3_process
261*new_l3_process(struct PStack *st, int cr)
262{
263 struct l3_process *p, *np;
264
265 if (!(p = kmalloc(sizeof(struct l3_process), GFP_ATOMIC))) {
266 printk(KERN_ERR "HiSax can't get memory for cr %d\n", cr);
267 return (NULL);
268 }
269 if (!st->l3.proc)
270 st->l3.proc = p;
271 else {
272 np = st->l3.proc;
273 while (np->next)
274 np = np->next;
275 np->next = p;
276 }
277 p->next = NULL;
278 p->debug = st->l3.debug;
279 p->callref = cr;
280 p->state = 0;
281 p->chan = NULL;
282 p->st = st;
283 p->N303 = st->l3.N303;
284 L3InitTimer(p, &p->timer);
285 return (p);
286};
287
288void
289release_l3_process(struct l3_process *p)
290{
291 struct l3_process *np, *pp = NULL;
292
293 if (!p)
294 return;
295 np = p->st->l3.proc;
296 while (np) {
297 if (np == p) {
298 StopAllL3Timer(p);
299 if (pp)
300 pp->next = np->next;
301 else if (!(p->st->l3.proc = np->next) &&
302 !test_bit(FLG_PTP, &p->st->l2.flag)) {
303 if (p->debug)
304 l3_debug(p->st, "release_l3_process: last process");
305 if (!skb_queue_len(&p->st->l3.squeue)) {
306 if (p->debug)
307 l3_debug(p->st, "release_l3_process: release link");
308 if (p->st->protocol != ISDN_PTYPE_NI1)
309 FsmEvent(&p->st->l3.l3m, EV_RELEASE_REQ, NULL);
310 else
311 FsmEvent(&p->st->l3.l3m, EV_RELEASE_IND, NULL);
312 } else {
313 if (p->debug)
314 l3_debug(p->st, "release_l3_process: not release link");
315 }
316 }
317 kfree(p);
318 return;
319 }
320 pp = np;
321 np = np->next;
322 }
323 printk(KERN_ERR "HiSax internal L3 error CR(%d) not in list\n", p->callref);
324 l3_debug(p->st, "HiSax internal L3 error CR(%d) not in list", p->callref);
325};
326
327static void
328l3ml3p(struct PStack *st, int pr)
329{
330 struct l3_process *p = st->l3.proc;
331 struct l3_process *np;
332
333 while (p) {
334 /* p might be kfreed under us, so we need to save where we want to go on */
335 np = p->next;
336 st->l3.l3ml3(st, pr, p);
337 p = np;
338 }
339}
340
341void
342setstack_l3dc(struct PStack *st, struct Channel *chanp)
343{
344 char tmp[64];
345
346 st->l3.proc = NULL;
347 st->l3.global = NULL;
348 skb_queue_head_init(&st->l3.squeue);
349 st->l3.l3m.fsm = &l3fsm;
350 st->l3.l3m.state = ST_L3_LC_REL;
351 st->l3.l3m.debug = 1;
352 st->l3.l3m.userdata = st;
353 st->l3.l3m.userint = 0;
354 st->l3.l3m.printdebug = l3m_debug;
355 FsmInitTimer(&st->l3.l3m, &st->l3.l3m_timer);
356 strcpy(st->l3.debug_id, "L3DC ");
357 st->lli.l4l3_proto = no_l3_proto_spec;
358
359#ifdef CONFIG_HISAX_EURO
360 if (st->protocol == ISDN_PTYPE_EURO) {
361 setstack_dss1(st);
362 } else
363#endif
364#ifdef CONFIG_HISAX_NI1
365 if (st->protocol == ISDN_PTYPE_NI1) {
366 setstack_ni1(st);
367 } else
368#endif
369#ifdef CONFIG_HISAX_1TR6
370 if (st->protocol == ISDN_PTYPE_1TR6) {
371 setstack_1tr6(st);
372 } else
373#endif
374 if (st->protocol == ISDN_PTYPE_LEASED) {
375 st->lli.l4l3 = no_l3_proto;
376 st->l2.l2l3 = no_l3_proto;
377 st->l3.l3ml3 = no_l3_proto;
378 printk(KERN_INFO "HiSax: Leased line mode\n");
379 } else {
380 st->lli.l4l3 = no_l3_proto;
381 st->l2.l2l3 = no_l3_proto;
382 st->l3.l3ml3 = no_l3_proto;
383 sprintf(tmp, "protocol %s not supported",
384 (st->protocol == ISDN_PTYPE_1TR6) ? "1tr6" :
385 (st->protocol == ISDN_PTYPE_EURO) ? "euro" :
386 (st->protocol == ISDN_PTYPE_NI1) ? "ni1" :
387 "unknown");
388 printk(KERN_WARNING "HiSax: %s\n", tmp);
389 st->protocol = -1;
390 }
391}
392
393void
394isdnl3_trans(struct PStack *st, int pr, void *arg) {
395 st->l3.l3l2(st, pr, arg);
396}
397
398void
399releasestack_isdnl3(struct PStack *st)
400{
401 while (st->l3.proc)
402 release_l3_process(st->l3.proc);
403 if (st->l3.global) {
404 StopAllL3Timer(st->l3.global);
405 kfree(st->l3.global);
406 st->l3.global = NULL;
407 }
408 FsmDelTimer(&st->l3.l3m_timer, 54);
409 skb_queue_purge(&st->l3.squeue);
410}
411
412void
413setstack_l3bc(struct PStack *st, struct Channel *chanp)
414{
415
416 st->l3.proc = NULL;
417 st->l3.global = NULL;
418 skb_queue_head_init(&st->l3.squeue);
419 st->l3.l3m.fsm = &l3fsm;
420 st->l3.l3m.state = ST_L3_LC_REL;
421 st->l3.l3m.debug = 1;
422 st->l3.l3m.userdata = st;
423 st->l3.l3m.userint = 0;
424 st->l3.l3m.printdebug = l3m_debug;
425 strcpy(st->l3.debug_id, "L3BC ");
426 st->lli.l4l3 = isdnl3_trans;
427}
428
429#define DREL_TIMER_VALUE 40000
430
431static void
432lc_activate(struct FsmInst *fi, int event, void *arg)
433{
434 struct PStack *st = fi->userdata;
435
436 FsmChangeState(fi, ST_L3_LC_ESTAB_WAIT);
437 st->l3.l3l2(st, DL_ESTABLISH | REQUEST, NULL);
438}
439
440static void
441lc_connect(struct FsmInst *fi, int event, void *arg)
442{
443 struct PStack *st = fi->userdata;
444 struct sk_buff *skb = arg;
445 int dequeued = 0;
446
447 FsmChangeState(fi, ST_L3_LC_ESTAB);
448 while ((skb = skb_dequeue(&st->l3.squeue))) {
449 st->l3.l3l2(st, DL_DATA | REQUEST, skb);
450 dequeued++;
451 }
452 if ((!st->l3.proc) && dequeued) {
453 if (st->l3.debug)
454 l3_debug(st, "lc_connect: release link");
455 FsmEvent(&st->l3.l3m, EV_RELEASE_REQ, NULL);
456 } else
457 l3ml3p(st, DL_ESTABLISH | INDICATION);
458}
459
460static void
461lc_connected(struct FsmInst *fi, int event, void *arg)
462{
463 struct PStack *st = fi->userdata;
464 struct sk_buff *skb = arg;
465 int dequeued = 0;
466
467 FsmDelTimer(&st->l3.l3m_timer, 51);
468 FsmChangeState(fi, ST_L3_LC_ESTAB);
469 while ((skb = skb_dequeue(&st->l3.squeue))) {
470 st->l3.l3l2(st, DL_DATA | REQUEST, skb);
471 dequeued++;
472 }
473 if ((!st->l3.proc) && dequeued) {
474 if (st->l3.debug)
475 l3_debug(st, "lc_connected: release link");
476 FsmEvent(&st->l3.l3m, EV_RELEASE_REQ, NULL);
477 } else
478 l3ml3p(st, DL_ESTABLISH | CONFIRM);
479}
480
481static void
482lc_start_delay(struct FsmInst *fi, int event, void *arg)
483{
484 struct PStack *st = fi->userdata;
485
486 FsmChangeState(fi, ST_L3_LC_REL_DELAY);
487 FsmAddTimer(&st->l3.l3m_timer, DREL_TIMER_VALUE, EV_TIMEOUT, NULL, 50);
488}
489
490static void
491lc_start_delay_check(struct FsmInst *fi, int event, void *arg)
492/* 20/09/00 - GE timer not user for NI-1 as layer 2 should stay up */
493{
494 struct PStack *st = fi->userdata;
495
496 FsmChangeState(fi, ST_L3_LC_REL_DELAY);
497 /* 19/09/00 - GE timer not user for NI-1 */
498 if (st->protocol != ISDN_PTYPE_NI1)
499 FsmAddTimer(&st->l3.l3m_timer, DREL_TIMER_VALUE, EV_TIMEOUT, NULL, 50);
500}
501
502static void
503lc_release_req(struct FsmInst *fi, int event, void *arg)
504{
505 struct PStack *st = fi->userdata;
506
507 if (test_bit(FLG_L2BLOCK, &st->l2.flag)) {
508 if (st->l3.debug)
509 l3_debug(st, "lc_release_req: l2 blocked");
510 /* restart release timer */
511 FsmAddTimer(&st->l3.l3m_timer, DREL_TIMER_VALUE, EV_TIMEOUT, NULL, 51);
512 } else {
513 FsmChangeState(fi, ST_L3_LC_REL_WAIT);
514 st->l3.l3l2(st, DL_RELEASE | REQUEST, NULL);
515 }
516}
517
518static void
519lc_release_ind(struct FsmInst *fi, int event, void *arg)
520{
521 struct PStack *st = fi->userdata;
522
523 FsmDelTimer(&st->l3.l3m_timer, 52);
524 FsmChangeState(fi, ST_L3_LC_REL);
525 skb_queue_purge(&st->l3.squeue);
526 l3ml3p(st, DL_RELEASE | INDICATION);
527}
528
529static void
530lc_release_cnf(struct FsmInst *fi, int event, void *arg)
531{
532 struct PStack *st = fi->userdata;
533
534 FsmChangeState(fi, ST_L3_LC_REL);
535 skb_queue_purge(&st->l3.squeue);
536 l3ml3p(st, DL_RELEASE | CONFIRM);
537}
538
539
540/* *INDENT-OFF* */
541static struct FsmNode L3FnList[] __initdata =
542{
543 {ST_L3_LC_REL, EV_ESTABLISH_REQ, lc_activate},
544 {ST_L3_LC_REL, EV_ESTABLISH_IND, lc_connect},
545 {ST_L3_LC_REL, EV_ESTABLISH_CNF, lc_connect},
546 {ST_L3_LC_ESTAB_WAIT, EV_ESTABLISH_CNF, lc_connected},
547 {ST_L3_LC_ESTAB_WAIT, EV_RELEASE_REQ, lc_start_delay},
548 {ST_L3_LC_ESTAB_WAIT, EV_RELEASE_IND, lc_release_ind},
549 {ST_L3_LC_ESTAB, EV_RELEASE_IND, lc_release_ind},
550 {ST_L3_LC_ESTAB, EV_RELEASE_REQ, lc_start_delay_check},
551 {ST_L3_LC_REL_DELAY, EV_RELEASE_IND, lc_release_ind},
552 {ST_L3_LC_REL_DELAY, EV_ESTABLISH_REQ, lc_connected},
553 {ST_L3_LC_REL_DELAY, EV_TIMEOUT, lc_release_req},
554 {ST_L3_LC_REL_WAIT, EV_RELEASE_CNF, lc_release_cnf},
555 {ST_L3_LC_REL_WAIT, EV_ESTABLISH_REQ, lc_activate},
556};
557/* *INDENT-ON* */
558
559#define L3_FN_COUNT (sizeof(L3FnList)/sizeof(struct FsmNode))
560
561void
562l3_msg(struct PStack *st, int pr, void *arg)
563{
564 switch (pr) {
565 case (DL_DATA | REQUEST):
566 if (st->l3.l3m.state == ST_L3_LC_ESTAB) {
567 st->l3.l3l2(st, pr, arg);
568 } else {
569 struct sk_buff *skb = arg;
570
571 skb_queue_tail(&st->l3.squeue, skb);
572 FsmEvent(&st->l3.l3m, EV_ESTABLISH_REQ, NULL);
573 }
574 break;
575 case (DL_ESTABLISH | REQUEST):
576 FsmEvent(&st->l3.l3m, EV_ESTABLISH_REQ, NULL);
577 break;
578 case (DL_ESTABLISH | CONFIRM):
579 FsmEvent(&st->l3.l3m, EV_ESTABLISH_CNF, NULL);
580 break;
581 case (DL_ESTABLISH | INDICATION):
582 FsmEvent(&st->l3.l3m, EV_ESTABLISH_IND, NULL);
583 break;
584 case (DL_RELEASE | INDICATION):
585 FsmEvent(&st->l3.l3m, EV_RELEASE_IND, NULL);
586 break;
587 case (DL_RELEASE | CONFIRM):
588 FsmEvent(&st->l3.l3m, EV_RELEASE_CNF, NULL);
589 break;
590 case (DL_RELEASE | REQUEST):
591 FsmEvent(&st->l3.l3m, EV_RELEASE_REQ, NULL);
592 break;
593 }
594}
595
596int __init
597Isdnl3New(void)
598{
599 l3fsm.state_count = L3_STATE_COUNT;
600 l3fsm.event_count = L3_EVENT_COUNT;
601 l3fsm.strEvent = strL3Event;
602 l3fsm.strState = strL3State;
603 return FsmNew(&l3fsm, L3FnList, L3_FN_COUNT);
604}
605
606void
607Isdnl3Free(void)
608{
609 FsmFree(&l3fsm);
610}
diff --git a/drivers/isdn/hisax/isdnl3.h b/drivers/isdn/hisax/isdnl3.h
new file mode 100644
index 000000000000..1dbe0297a506
--- /dev/null
+++ b/drivers/isdn/hisax/isdnl3.h
@@ -0,0 +1,37 @@
1/* $Id: isdnl3.h,v 2.6.6.2 2001/09/23 22:24:49 kai Exp $
2 *
3 * This software may be used and distributed according to the terms
4 * of the GNU General Public License, incorporated herein by reference.
5 *
6 */
7
8#define SBIT(state) (1<<state)
9#define ALL_STATES 0x03ffffff
10
11#define PROTO_DIS_EURO 0x08
12
13#define L3_DEB_WARN 0x01
14#define L3_DEB_PROTERR 0x02
15#define L3_DEB_STATE 0x04
16#define L3_DEB_CHARGE 0x08
17#define L3_DEB_CHECK 0x10
18#define L3_DEB_SI 0x20
19
20struct stateentry {
21 int state;
22 int primitive;
23 void (*rout) (struct l3_process *, u8, void *);
24};
25
26#define l3_debug(st, fmt, args...) HiSax_putstatus(st->l1.hardware, "l3 ", fmt, ## args)
27
28extern void newl3state(struct l3_process *pc, int state);
29extern void L3InitTimer(struct l3_process *pc, struct L3Timer *t);
30extern void L3DelTimer(struct L3Timer *t);
31extern int L3AddTimer(struct L3Timer *t, int millisec, int event);
32extern void StopAllL3Timer(struct l3_process *pc);
33extern struct sk_buff *l3_alloc_skb(int len);
34extern struct l3_process *new_l3_process(struct PStack *st, int cr);
35extern void release_l3_process(struct l3_process *p);
36extern struct l3_process *getl3proc(struct PStack *st, int cr);
37extern void l3_msg(struct PStack *st, int pr, void *arg);
diff --git a/drivers/isdn/hisax/isurf.c b/drivers/isdn/hisax/isurf.c
new file mode 100644
index 000000000000..af5171da7345
--- /dev/null
+++ b/drivers/isdn/hisax/isurf.c
@@ -0,0 +1,306 @@
1/* $Id: isurf.c,v 1.12.2.4 2004/01/13 21:46:03 keil Exp $
2 *
3 * low level stuff for Siemens I-Surf/I-Talk cards
4 *
5 * Author Karsten Keil
6 * Copyright by Karsten Keil <keil@isdn4linux.de>
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 */
12
13#include <linux/init.h>
14#include "hisax.h"
15#include "isac.h"
16#include "isar.h"
17#include "isdnl1.h"
18#include <linux/isapnp.h>
19
20extern const char *CardType[];
21
22static const char *ISurf_revision = "$Revision: 1.12.2.4 $";
23
24#define byteout(addr,val) outb(val,addr)
25#define bytein(addr) inb(addr)
26
27#define ISURF_ISAR_RESET 1
28#define ISURF_ISAC_RESET 2
29#define ISURF_ISAR_EA 4
30#define ISURF_ARCOFI_RESET 8
31#define ISURF_RESET (ISURF_ISAR_RESET | ISURF_ISAC_RESET | ISURF_ARCOFI_RESET)
32
33#define ISURF_ISAR_OFFSET 0
34#define ISURF_ISAC_OFFSET 0x100
35#define ISURF_IOMEM_SIZE 0x400
36/* Interface functions */
37
38static u_char
39ReadISAC(struct IsdnCardState *cs, u_char offset)
40{
41 return (readb(cs->hw.isurf.isac + offset));
42}
43
44static void
45WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
46{
47 writeb(value, cs->hw.isurf.isac + offset); mb();
48}
49
50static void
51ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
52{
53 register int i;
54 for (i = 0; i < size; i++)
55 data[i] = readb(cs->hw.isurf.isac);
56}
57
58static void
59WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
60{
61 register int i;
62 for (i = 0; i < size; i++){
63 writeb(data[i], cs->hw.isurf.isac);mb();
64 }
65}
66
67/* ISAR access routines
68 * mode = 0 access with IRQ on
69 * mode = 1 access with IRQ off
70 * mode = 2 access with IRQ off and using last offset
71 */
72
73static u_char
74ReadISAR(struct IsdnCardState *cs, int mode, u_char offset)
75{
76 return(readb(cs->hw.isurf.isar + offset));
77}
78
79static void
80WriteISAR(struct IsdnCardState *cs, int mode, u_char offset, u_char value)
81{
82 writeb(value, cs->hw.isurf.isar + offset);mb();
83}
84
85static irqreturn_t
86isurf_interrupt(int intno, void *dev_id, struct pt_regs *regs)
87{
88 struct IsdnCardState *cs = dev_id;
89 u_char val;
90 int cnt = 5;
91 u_long flags;
92
93 spin_lock_irqsave(&cs->lock, flags);
94 val = readb(cs->hw.isurf.isar + ISAR_IRQBIT);
95 Start_ISAR:
96 if (val & ISAR_IRQSTA)
97 isar_int_main(cs);
98 val = readb(cs->hw.isurf.isac + ISAC_ISTA);
99 Start_ISAC:
100 if (val)
101 isac_interrupt(cs, val);
102 val = readb(cs->hw.isurf.isar + ISAR_IRQBIT);
103 if ((val & ISAR_IRQSTA) && --cnt) {
104 if (cs->debug & L1_DEB_HSCX)
105 debugl1(cs, "ISAR IntStat after IntRoutine");
106 goto Start_ISAR;
107 }
108 val = readb(cs->hw.isurf.isac + ISAC_ISTA);
109 if (val && --cnt) {
110 if (cs->debug & L1_DEB_ISAC)
111 debugl1(cs, "ISAC IntStat after IntRoutine");
112 goto Start_ISAC;
113 }
114 if (!cnt)
115 printk(KERN_WARNING "ISurf IRQ LOOP\n");
116
117 writeb(0, cs->hw.isurf.isar + ISAR_IRQBIT); mb();
118 writeb(0xFF, cs->hw.isurf.isac + ISAC_MASK);mb();
119 writeb(0, cs->hw.isurf.isac + ISAC_MASK);mb();
120 writeb(ISAR_IRQMSK, cs->hw.isurf.isar + ISAR_IRQBIT); mb();
121 spin_unlock_irqrestore(&cs->lock, flags);
122 return IRQ_HANDLED;
123}
124
125void
126release_io_isurf(struct IsdnCardState *cs)
127{
128 release_region(cs->hw.isurf.reset, 1);
129 iounmap(cs->hw.isurf.isar);
130 release_mem_region(cs->hw.isurf.phymem, ISURF_IOMEM_SIZE);
131}
132
133static void
134reset_isurf(struct IsdnCardState *cs, u_char chips)
135{
136 printk(KERN_INFO "ISurf: resetting card\n");
137
138 byteout(cs->hw.isurf.reset, chips); /* Reset On */
139 mdelay(10);
140 byteout(cs->hw.isurf.reset, ISURF_ISAR_EA); /* Reset Off */
141 mdelay(10);
142}
143
144static int
145ISurf_card_msg(struct IsdnCardState *cs, int mt, void *arg)
146{
147 u_long flags;
148
149 switch (mt) {
150 case CARD_RESET:
151 spin_lock_irqsave(&cs->lock, flags);
152 reset_isurf(cs, ISURF_RESET);
153 spin_unlock_irqrestore(&cs->lock, flags);
154 return(0);
155 case CARD_RELEASE:
156 release_io_isurf(cs);
157 return(0);
158 case CARD_INIT:
159 spin_lock_irqsave(&cs->lock, flags);
160 reset_isurf(cs, ISURF_RESET);
161 clear_pending_isac_ints(cs);
162 writeb(0, cs->hw.isurf.isar+ISAR_IRQBIT);mb();
163 initisac(cs);
164 initisar(cs);
165 /* Reenable ISAC IRQ */
166 cs->writeisac(cs, ISAC_MASK, 0);
167 /* RESET Receiver and Transmitter */
168 cs->writeisac(cs, ISAC_CMDR, 0x41);
169 spin_unlock_irqrestore(&cs->lock, flags);
170 return(0);
171 case CARD_TEST:
172 return(0);
173 }
174 return(0);
175}
176
177static int
178isurf_auxcmd(struct IsdnCardState *cs, isdn_ctrl *ic) {
179 int ret;
180 u_long flags;
181
182 if ((ic->command == ISDN_CMD_IOCTL) && (ic->arg == 9)) {
183 ret = isar_auxcmd(cs, ic);
184 spin_lock_irqsave(&cs->lock, flags);
185 if (!ret) {
186 reset_isurf(cs, ISURF_ISAR_EA | ISURF_ISAC_RESET |
187 ISURF_ARCOFI_RESET);
188 initisac(cs);
189 cs->writeisac(cs, ISAC_MASK, 0);
190 cs->writeisac(cs, ISAC_CMDR, 0x41);
191 }
192 spin_unlock_irqrestore(&cs->lock, flags);
193 return(ret);
194 }
195 return(isar_auxcmd(cs, ic));
196}
197
198#ifdef __ISAPNP__
199static struct pnp_card *pnp_c __initdata = NULL;
200#endif
201
202int __init
203setup_isurf(struct IsdnCard *card)
204{
205 int ver;
206 struct IsdnCardState *cs = card->cs;
207 char tmp[64];
208
209 strcpy(tmp, ISurf_revision);
210 printk(KERN_INFO "HiSax: ISurf driver Rev. %s\n", HiSax_getrev(tmp));
211
212 if (cs->typ != ISDN_CTYPE_ISURF)
213 return(0);
214 if (card->para[1] && card->para[2]) {
215 cs->hw.isurf.reset = card->para[1];
216 cs->hw.isurf.phymem = card->para[2];
217 cs->irq = card->para[0];
218 } else {
219#ifdef __ISAPNP__
220 if (isapnp_present()) {
221 struct pnp_dev *pnp_d = NULL;
222 int err;
223
224 cs->subtyp = 0;
225 if ((pnp_c = pnp_find_card(
226 ISAPNP_VENDOR('S', 'I', 'E'),
227 ISAPNP_FUNCTION(0x0010), pnp_c))) {
228 if (!(pnp_d = pnp_find_dev(pnp_c,
229 ISAPNP_VENDOR('S', 'I', 'E'),
230 ISAPNP_FUNCTION(0x0010), pnp_d))) {
231 printk(KERN_ERR "ISurfPnP: PnP error card found, no device\n");
232 return (0);
233 }
234 pnp_disable_dev(pnp_d);
235 err = pnp_activate_dev(pnp_d);
236 cs->hw.isurf.reset = pnp_port_start(pnp_d, 0);
237 cs->hw.isurf.phymem = pnp_mem_start(pnp_d, 1);
238 cs->irq = pnp_irq(pnp_d, 0);
239 if (!cs->irq || !cs->hw.isurf.reset || !cs->hw.isurf.phymem) {
240 printk(KERN_ERR "ISurfPnP:some resources are missing %d/%x/%lx\n",
241 cs->irq, cs->hw.isurf.reset, cs->hw.isurf.phymem);
242 pnp_disable_dev(pnp_d);
243 return(0);
244 }
245 } else {
246 printk(KERN_INFO "ISurfPnP: no ISAPnP card found\n");
247 return(0);
248 }
249 } else {
250 printk(KERN_INFO "ISurfPnP: no ISAPnP bus found\n");
251 return(0);
252 }
253#else
254 printk(KERN_WARNING "HiSax: %s port/mem not set\n",
255 CardType[card->typ]);
256 return (0);
257#endif
258 }
259 if (!request_region(cs->hw.isurf.reset, 1, "isurf isdn")) {
260 printk(KERN_WARNING
261 "HiSax: %s config port %x already in use\n",
262 CardType[card->typ],
263 cs->hw.isurf.reset);
264 return (0);
265 }
266 if (!request_region(cs->hw.isurf.phymem, ISURF_IOMEM_SIZE, "isurf iomem")) {
267 printk(KERN_WARNING
268 "HiSax: %s memory region %lx-%lx already in use\n",
269 CardType[card->typ],
270 cs->hw.isurf.phymem,
271 cs->hw.isurf.phymem + ISURF_IOMEM_SIZE);
272 release_region(cs->hw.isurf.reset, 1);
273 return (0);
274 }
275 cs->hw.isurf.isar = ioremap(cs->hw.isurf.phymem, ISURF_IOMEM_SIZE);
276 cs->hw.isurf.isac = cs->hw.isurf.isar + ISURF_ISAC_OFFSET;
277 printk(KERN_INFO
278 "ISurf: defined at 0x%x 0x%lx IRQ %d\n",
279 cs->hw.isurf.reset,
280 cs->hw.isurf.phymem,
281 cs->irq);
282
283 setup_isac(cs);
284 cs->cardmsg = &ISurf_card_msg;
285 cs->irq_func = &isurf_interrupt;
286 cs->auxcmd = &isurf_auxcmd;
287 cs->readisac = &ReadISAC;
288 cs->writeisac = &WriteISAC;
289 cs->readisacfifo = &ReadISACfifo;
290 cs->writeisacfifo = &WriteISACfifo;
291 cs->bcs[0].hw.isar.reg = &cs->hw.isurf.isar_r;
292 cs->bcs[1].hw.isar.reg = &cs->hw.isurf.isar_r;
293 test_and_set_bit(HW_ISAR, &cs->HW_Flags);
294 ISACVersion(cs, "ISurf:");
295 cs->BC_Read_Reg = &ReadISAR;
296 cs->BC_Write_Reg = &WriteISAR;
297 cs->BC_Send_Data = &isar_fill_fifo;
298 ver = ISARVersion(cs, "ISurf:");
299 if (ver < 0) {
300 printk(KERN_WARNING
301 "ISurf: wrong ISAR version (ret = %d)\n", ver);
302 release_io_isurf(cs);
303 return (0);
304 }
305 return (1);
306}
diff --git a/drivers/isdn/hisax/ix1_micro.c b/drivers/isdn/hisax/ix1_micro.c
new file mode 100644
index 000000000000..b843b7509ae2
--- /dev/null
+++ b/drivers/isdn/hisax/ix1_micro.c
@@ -0,0 +1,318 @@
1/* $Id: ix1_micro.c,v 2.12.2.4 2004/01/13 23:48:39 keil Exp $
2 *
3 * low level stuff for ITK ix1-micro Rev.2 isdn cards
4 * derived from the original file teles3.c from Karsten Keil
5 *
6 * Author Klaus-Peter Nischke
7 * Copyright by Klaus-Peter Nischke, ITK AG
8 * <klaus@nischke.do.eunet.de>
9 * by Karsten Keil <keil@isdn4linux.de>
10 *
11 * This software may be used and distributed according to the terms
12 * of the GNU General Public License, incorporated herein by reference.
13 *
14 * Klaus-Peter Nischke
15 * Deusener Str. 287
16 * 44369 Dortmund
17 * Germany
18 */
19
20#include <linux/init.h>
21#include <linux/isapnp.h>
22#include "hisax.h"
23#include "isac.h"
24#include "hscx.h"
25#include "isdnl1.h"
26
27extern const char *CardType[];
28const char *ix1_revision = "$Revision: 2.12.2.4 $";
29
30#define byteout(addr,val) outb(val,addr)
31#define bytein(addr) inb(addr)
32
33#define SPECIAL_PORT_OFFSET 3
34
35#define ISAC_COMMAND_OFFSET 2
36#define ISAC_DATA_OFFSET 0
37#define HSCX_COMMAND_OFFSET 2
38#define HSCX_DATA_OFFSET 1
39
40#define TIMEOUT 50
41
42static inline u_char
43readreg(unsigned int ale, unsigned int adr, u_char off)
44{
45 register u_char ret;
46
47 byteout(ale, off);
48 ret = bytein(adr);
49 return (ret);
50}
51
52static inline void
53readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
54{
55 byteout(ale, off);
56 insb(adr, data, size);
57}
58
59
60static inline void
61writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
62{
63 byteout(ale, off);
64 byteout(adr, data);
65}
66
67static inline void
68writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
69{
70 byteout(ale, off);
71 outsb(adr, data, size);
72}
73
74/* Interface functions */
75
76static u_char
77ReadISAC(struct IsdnCardState *cs, u_char offset)
78{
79 return (readreg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, offset));
80}
81
82static void
83WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
84{
85 writereg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, offset, value);
86}
87
88static void
89ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
90{
91 readfifo(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, 0, data, size);
92}
93
94static void
95WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
96{
97 writefifo(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, 0, data, size);
98}
99
100static u_char
101ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
102{
103 return (readreg(cs->hw.ix1.hscx_ale,
104 cs->hw.ix1.hscx, offset + (hscx ? 0x40 : 0)));
105}
106
107static void
108WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
109{
110 writereg(cs->hw.ix1.hscx_ale,
111 cs->hw.ix1.hscx, offset + (hscx ? 0x40 : 0), value);
112}
113
114#define READHSCX(cs, nr, reg) readreg(cs->hw.ix1.hscx_ale, \
115 cs->hw.ix1.hscx, reg + (nr ? 0x40 : 0))
116#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.ix1.hscx_ale, \
117 cs->hw.ix1.hscx, reg + (nr ? 0x40 : 0), data)
118
119#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.ix1.hscx_ale, \
120 cs->hw.ix1.hscx, (nr ? 0x40 : 0), ptr, cnt)
121
122#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.ix1.hscx_ale, \
123 cs->hw.ix1.hscx, (nr ? 0x40 : 0), ptr, cnt)
124
125#include "hscx_irq.c"
126
127static irqreturn_t
128ix1micro_interrupt(int intno, void *dev_id, struct pt_regs *regs)
129{
130 struct IsdnCardState *cs = dev_id;
131 u_char val;
132 u_long flags;
133
134 spin_lock_irqsave(&cs->lock, flags);
135 val = readreg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_ISTA + 0x40);
136 Start_HSCX:
137 if (val)
138 hscx_int_main(cs, val);
139 val = readreg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_ISTA);
140 Start_ISAC:
141 if (val)
142 isac_interrupt(cs, val);
143 val = readreg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_ISTA + 0x40);
144 if (val) {
145 if (cs->debug & L1_DEB_HSCX)
146 debugl1(cs, "HSCX IntStat after IntRoutine");
147 goto Start_HSCX;
148 }
149 val = readreg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_ISTA);
150 if (val) {
151 if (cs->debug & L1_DEB_ISAC)
152 debugl1(cs, "ISAC IntStat after IntRoutine");
153 goto Start_ISAC;
154 }
155 writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK, 0xFF);
156 writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK + 0x40, 0xFF);
157 writereg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_MASK, 0xFF);
158 writereg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_MASK, 0);
159 writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK, 0);
160 writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK + 0x40, 0);
161 spin_unlock_irqrestore(&cs->lock, flags);
162 return IRQ_HANDLED;
163}
164
165void
166release_io_ix1micro(struct IsdnCardState *cs)
167{
168 if (cs->hw.ix1.cfg_reg)
169 release_region(cs->hw.ix1.cfg_reg, 4);
170}
171
172static void
173ix1_reset(struct IsdnCardState *cs)
174{
175 int cnt;
176
177 /* reset isac */
178 cnt = 3 * (HZ / 10) + 1;
179 while (cnt--) {
180 byteout(cs->hw.ix1.cfg_reg + SPECIAL_PORT_OFFSET, 1);
181 HZDELAY(1); /* wait >=10 ms */
182 }
183 byteout(cs->hw.ix1.cfg_reg + SPECIAL_PORT_OFFSET, 0);
184}
185
186static int
187ix1_card_msg(struct IsdnCardState *cs, int mt, void *arg)
188{
189 u_long flags;
190
191 switch (mt) {
192 case CARD_RESET:
193 spin_lock_irqsave(&cs->lock, flags);
194 ix1_reset(cs);
195 spin_unlock_irqrestore(&cs->lock, flags);
196 return(0);
197 case CARD_RELEASE:
198 release_io_ix1micro(cs);
199 return(0);
200 case CARD_INIT:
201 spin_lock_irqsave(&cs->lock, flags);
202 ix1_reset(cs);
203 inithscxisac(cs, 3);
204 spin_unlock_irqrestore(&cs->lock, flags);
205 return(0);
206 case CARD_TEST:
207 return(0);
208 }
209 return(0);
210}
211
212#ifdef __ISAPNP__
213static struct isapnp_device_id itk_ids[] __initdata = {
214 { ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x25),
215 ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x25),
216 (unsigned long) "ITK micro 2" },
217 { ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x29),
218 ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x29),
219 (unsigned long) "ITK micro 2." },
220 { 0, }
221};
222
223static struct isapnp_device_id *ipid __initdata = &itk_ids[0];
224static struct pnp_card *pnp_c __devinitdata = NULL;
225#endif
226
227
228int __init
229setup_ix1micro(struct IsdnCard *card)
230{
231 struct IsdnCardState *cs = card->cs;
232 char tmp[64];
233
234 strcpy(tmp, ix1_revision);
235 printk(KERN_INFO "HiSax: ITK IX1 driver Rev. %s\n", HiSax_getrev(tmp));
236 if (cs->typ != ISDN_CTYPE_IX1MICROR2)
237 return (0);
238
239#ifdef __ISAPNP__
240 if (!card->para[1] && isapnp_present()) {
241 struct pnp_dev *pnp_d;
242 while(ipid->card_vendor) {
243 if ((pnp_c = pnp_find_card(ipid->card_vendor,
244 ipid->card_device, pnp_c))) {
245 pnp_d = NULL;
246 if ((pnp_d = pnp_find_dev(pnp_c,
247 ipid->vendor, ipid->function, pnp_d))) {
248 int err;
249
250 printk(KERN_INFO "HiSax: %s detected\n",
251 (char *)ipid->driver_data);
252 pnp_disable_dev(pnp_d);
253 err = pnp_activate_dev(pnp_d);
254 if (err<0) {
255 printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
256 __FUNCTION__, err);
257 return(0);
258 }
259 card->para[1] = pnp_port_start(pnp_d, 0);
260 card->para[0] = pnp_irq(pnp_d, 0);
261 if (!card->para[0] || !card->para[1]) {
262 printk(KERN_ERR "ITK PnP:some resources are missing %ld/%lx\n",
263 card->para[0], card->para[1]);
264 pnp_disable_dev(pnp_d);
265 return(0);
266 }
267 break;
268 } else {
269 printk(KERN_ERR "ITK PnP: PnP error card found, no device\n");
270 }
271 }
272 ipid++;
273 pnp_c = NULL;
274 }
275 if (!ipid->card_vendor) {
276 printk(KERN_INFO "ITK PnP: no ISAPnP card found\n");
277 return(0);
278 }
279 }
280#endif
281 /* IO-Ports */
282 cs->hw.ix1.isac_ale = card->para[1] + ISAC_COMMAND_OFFSET;
283 cs->hw.ix1.hscx_ale = card->para[1] + HSCX_COMMAND_OFFSET;
284 cs->hw.ix1.isac = card->para[1] + ISAC_DATA_OFFSET;
285 cs->hw.ix1.hscx = card->para[1] + HSCX_DATA_OFFSET;
286 cs->hw.ix1.cfg_reg = card->para[1];
287 cs->irq = card->para[0];
288 if (cs->hw.ix1.cfg_reg) {
289 if (!request_region(cs->hw.ix1.cfg_reg, 4, "ix1micro cfg")) {
290 printk(KERN_WARNING
291 "HiSax: %s config port %x-%x already in use\n",
292 CardType[card->typ],
293 cs->hw.ix1.cfg_reg,
294 cs->hw.ix1.cfg_reg + 4);
295 return (0);
296 }
297 }
298 printk(KERN_INFO "HiSax: %s config irq:%d io:0x%X\n",
299 CardType[cs->typ], cs->irq, cs->hw.ix1.cfg_reg);
300 setup_isac(cs);
301 cs->readisac = &ReadISAC;
302 cs->writeisac = &WriteISAC;
303 cs->readisacfifo = &ReadISACfifo;
304 cs->writeisacfifo = &WriteISACfifo;
305 cs->BC_Read_Reg = &ReadHSCX;
306 cs->BC_Write_Reg = &WriteHSCX;
307 cs->BC_Send_Data = &hscx_fill_fifo;
308 cs->cardmsg = &ix1_card_msg;
309 cs->irq_func = &ix1micro_interrupt;
310 ISACVersion(cs, "ix1-Micro:");
311 if (HscxVersion(cs, "ix1-Micro:")) {
312 printk(KERN_WARNING
313 "ix1-Micro: wrong HSCX versions check IO address\n");
314 release_io_ix1micro(cs);
315 return (0);
316 }
317 return (1);
318}
diff --git a/drivers/isdn/hisax/jade.c b/drivers/isdn/hisax/jade.c
new file mode 100644
index 000000000000..f05d52757557
--- /dev/null
+++ b/drivers/isdn/hisax/jade.c
@@ -0,0 +1,318 @@
1/* $Id: jade.c,v 1.9.2.4 2004/01/14 16:04:48 keil Exp $
2 *
3 * JADE stuff (derived from original hscx.c)
4 *
5 * Author Roland Klabunde
6 * Copyright by Roland Klabunde <R.Klabunde@Berkom.de>
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 */
12
13
14#include <linux/init.h>
15#include "hisax.h"
16#include "hscx.h"
17#include "jade.h"
18#include "isdnl1.h"
19#include <linux/interrupt.h>
20
21
22int __init
23JadeVersion(struct IsdnCardState *cs, char *s)
24{
25 int ver,i;
26 int to = 50;
27 cs->BC_Write_Reg(cs, -1, 0x50, 0x19);
28 i=0;
29 while (to) {
30 udelay(1);
31 ver = cs->BC_Read_Reg(cs, -1, 0x60);
32 to--;
33 if (ver)
34 break;
35 if (!to) {
36 printk(KERN_INFO "%s JADE version not obtainable\n", s);
37 return (0);
38 }
39 }
40 /* Wait for the JADE */
41 udelay(10);
42 /* Read version */
43 ver = cs->BC_Read_Reg(cs, -1, 0x60);
44 printk(KERN_INFO "%s JADE version: %d\n", s, ver);
45 return (1);
46}
47
48/* Write to indirect accessible jade register set */
49static void
50jade_write_indirect(struct IsdnCardState *cs, u_char reg, u_char value)
51{
52 int to = 50;
53 u_char ret;
54
55 /* Write the data */
56 cs->BC_Write_Reg(cs, -1, COMM_JADE+1, value);
57 /* Say JADE we wanna write indirect reg 'reg' */
58 cs->BC_Write_Reg(cs, -1, COMM_JADE, reg);
59 to = 50;
60 /* Wait for RDY goes high */
61 while (to) {
62 udelay(1);
63 ret = cs->BC_Read_Reg(cs, -1, COMM_JADE);
64 to--;
65 if (ret & 1)
66 /* Got acknowledge */
67 break;
68 if (!to) {
69 printk(KERN_INFO "Can not see ready bit from JADE DSP (reg=0x%X, value=0x%X)\n", reg, value);
70 return;
71 }
72 }
73}
74
75
76
77void
78modejade(struct BCState *bcs, int mode, int bc)
79{
80 struct IsdnCardState *cs = bcs->cs;
81 int jade = bcs->hw.hscx.hscx;
82
83 if (cs->debug & L1_DEB_HSCX) {
84 char tmp[40];
85 sprintf(tmp, "jade %c mode %d ichan %d",
86 'A' + jade, mode, bc);
87 debugl1(cs, tmp);
88 }
89 bcs->mode = mode;
90 bcs->channel = bc;
91
92 cs->BC_Write_Reg(cs, jade, jade_HDLC_MODE, (mode == L1_MODE_TRANS ? jadeMODE_TMO:0x00));
93 cs->BC_Write_Reg(cs, jade, jade_HDLC_CCR0, (jadeCCR0_PU|jadeCCR0_ITF));
94 cs->BC_Write_Reg(cs, jade, jade_HDLC_CCR1, 0x00);
95
96 jade_write_indirect(cs, jade_HDLC1SERRXPATH, 0x08);
97 jade_write_indirect(cs, jade_HDLC2SERRXPATH, 0x08);
98 jade_write_indirect(cs, jade_HDLC1SERTXPATH, 0x00);
99 jade_write_indirect(cs, jade_HDLC2SERTXPATH, 0x00);
100
101 cs->BC_Write_Reg(cs, jade, jade_HDLC_XCCR, 0x07);
102 cs->BC_Write_Reg(cs, jade, jade_HDLC_RCCR, 0x07);
103
104 if (bc == 0) {
105 cs->BC_Write_Reg(cs, jade, jade_HDLC_TSAX, 0x00);
106 cs->BC_Write_Reg(cs, jade, jade_HDLC_TSAR, 0x00);
107 } else {
108 cs->BC_Write_Reg(cs, jade, jade_HDLC_TSAX, 0x04);
109 cs->BC_Write_Reg(cs, jade, jade_HDLC_TSAR, 0x04);
110 }
111 switch (mode) {
112 case (L1_MODE_NULL):
113 cs->BC_Write_Reg(cs, jade, jade_HDLC_MODE, jadeMODE_TMO);
114 break;
115 case (L1_MODE_TRANS):
116 cs->BC_Write_Reg(cs, jade, jade_HDLC_MODE, (jadeMODE_TMO|jadeMODE_RAC|jadeMODE_XAC));
117 break;
118 case (L1_MODE_HDLC):
119 cs->BC_Write_Reg(cs, jade, jade_HDLC_MODE, (jadeMODE_RAC|jadeMODE_XAC));
120 break;
121 }
122 if (mode) {
123 cs->BC_Write_Reg(cs, jade, jade_HDLC_RCMD, (jadeRCMD_RRES|jadeRCMD_RMC));
124 cs->BC_Write_Reg(cs, jade, jade_HDLC_XCMD, jadeXCMD_XRES);
125 /* Unmask ints */
126 cs->BC_Write_Reg(cs, jade, jade_HDLC_IMR, 0xF8);
127 }
128 else
129 /* Mask ints */
130 cs->BC_Write_Reg(cs, jade, jade_HDLC_IMR, 0x00);
131}
132
133static void
134jade_l2l1(struct PStack *st, int pr, void *arg)
135{
136 struct BCState *bcs = st->l1.bcs;
137 struct sk_buff *skb = arg;
138 u_long flags;
139
140 switch (pr) {
141 case (PH_DATA | REQUEST):
142 spin_lock_irqsave(&bcs->cs->lock, flags);
143 if (bcs->tx_skb) {
144 skb_queue_tail(&bcs->squeue, skb);
145 } else {
146 bcs->tx_skb = skb;
147 test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
148 bcs->hw.hscx.count = 0;
149 bcs->cs->BC_Send_Data(bcs);
150 }
151 spin_unlock_irqrestore(&bcs->cs->lock, flags);
152 break;
153 case (PH_PULL | INDICATION):
154 spin_lock_irqsave(&bcs->cs->lock, flags);
155 if (bcs->tx_skb) {
156 printk(KERN_WARNING "jade_l2l1: this shouldn't happen\n");
157 } else {
158 test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
159 bcs->tx_skb = skb;
160 bcs->hw.hscx.count = 0;
161 bcs->cs->BC_Send_Data(bcs);
162 }
163 spin_unlock_irqrestore(&bcs->cs->lock, flags);
164 break;
165 case (PH_PULL | REQUEST):
166 if (!bcs->tx_skb) {
167 test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
168 st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
169 } else
170 test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
171 break;
172 case (PH_ACTIVATE | REQUEST):
173 spin_lock_irqsave(&bcs->cs->lock, flags);
174 test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag);
175 modejade(bcs, st->l1.mode, st->l1.bc);
176 spin_unlock_irqrestore(&bcs->cs->lock, flags);
177 l1_msg_b(st, pr, arg);
178 break;
179 case (PH_DEACTIVATE | REQUEST):
180 l1_msg_b(st, pr, arg);
181 break;
182 case (PH_DEACTIVATE | CONFIRM):
183 spin_lock_irqsave(&bcs->cs->lock, flags);
184 test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag);
185 test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
186 modejade(bcs, 0, st->l1.bc);
187 spin_unlock_irqrestore(&bcs->cs->lock, flags);
188 st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
189 break;
190 }
191}
192
193void
194close_jadestate(struct BCState *bcs)
195{
196 modejade(bcs, 0, bcs->channel);
197 if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) {
198 if (bcs->hw.hscx.rcvbuf) {
199 kfree(bcs->hw.hscx.rcvbuf);
200 bcs->hw.hscx.rcvbuf = NULL;
201 }
202 if (bcs->blog) {
203 kfree(bcs->blog);
204 bcs->blog = NULL;
205 }
206 skb_queue_purge(&bcs->rqueue);
207 skb_queue_purge(&bcs->squeue);
208 if (bcs->tx_skb) {
209 dev_kfree_skb_any(bcs->tx_skb);
210 bcs->tx_skb = NULL;
211 test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
212 }
213 }
214}
215
216static int
217open_jadestate(struct IsdnCardState *cs, struct BCState *bcs)
218{
219 if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
220 if (!(bcs->hw.hscx.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) {
221 printk(KERN_WARNING
222 "HiSax: No memory for hscx.rcvbuf\n");
223 test_and_clear_bit(BC_FLG_INIT, &bcs->Flag);
224 return (1);
225 }
226 if (!(bcs->blog = kmalloc(MAX_BLOG_SPACE, GFP_ATOMIC))) {
227 printk(KERN_WARNING
228 "HiSax: No memory for bcs->blog\n");
229 test_and_clear_bit(BC_FLG_INIT, &bcs->Flag);
230 kfree(bcs->hw.hscx.rcvbuf);
231 bcs->hw.hscx.rcvbuf = NULL;
232 return (2);
233 }
234 skb_queue_head_init(&bcs->rqueue);
235 skb_queue_head_init(&bcs->squeue);
236 }
237 bcs->tx_skb = NULL;
238 test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
239 bcs->event = 0;
240 bcs->hw.hscx.rcvidx = 0;
241 bcs->tx_cnt = 0;
242 return (0);
243}
244
245
246int
247setstack_jade(struct PStack *st, struct BCState *bcs)
248{
249 bcs->channel = st->l1.bc;
250 if (open_jadestate(st->l1.hardware, bcs))
251 return (-1);
252 st->l1.bcs = bcs;
253 st->l2.l2l1 = jade_l2l1;
254 setstack_manager(st);
255 bcs->st = st;
256 setstack_l1_B(st);
257 return (0);
258}
259
260void __init
261clear_pending_jade_ints(struct IsdnCardState *cs)
262{
263 int val;
264 char tmp[64];
265
266 cs->BC_Write_Reg(cs, 0, jade_HDLC_IMR, 0x00);
267 cs->BC_Write_Reg(cs, 1, jade_HDLC_IMR, 0x00);
268
269 val = cs->BC_Read_Reg(cs, 1, jade_HDLC_ISR);
270 sprintf(tmp, "jade B ISTA %x", val);
271 debugl1(cs, tmp);
272 val = cs->BC_Read_Reg(cs, 0, jade_HDLC_ISR);
273 sprintf(tmp, "jade A ISTA %x", val);
274 debugl1(cs, tmp);
275 val = cs->BC_Read_Reg(cs, 1, jade_HDLC_STAR);
276 sprintf(tmp, "jade B STAR %x", val);
277 debugl1(cs, tmp);
278 val = cs->BC_Read_Reg(cs, 0, jade_HDLC_STAR);
279 sprintf(tmp, "jade A STAR %x", val);
280 debugl1(cs, tmp);
281 /* Unmask ints */
282 cs->BC_Write_Reg(cs, 0, jade_HDLC_IMR, 0xF8);
283 cs->BC_Write_Reg(cs, 1, jade_HDLC_IMR, 0xF8);
284}
285
286void __init
287initjade(struct IsdnCardState *cs)
288{
289 cs->bcs[0].BC_SetStack = setstack_jade;
290 cs->bcs[1].BC_SetStack = setstack_jade;
291 cs->bcs[0].BC_Close = close_jadestate;
292 cs->bcs[1].BC_Close = close_jadestate;
293 cs->bcs[0].hw.hscx.hscx = 0;
294 cs->bcs[1].hw.hscx.hscx = 1;
295
296 /* Stop DSP audio tx/rx */
297 jade_write_indirect(cs, 0x11, 0x0f);
298 jade_write_indirect(cs, 0x17, 0x2f);
299
300 /* Transparent Mode, RxTx inactive, No Test, No RFS/TFS */
301 cs->BC_Write_Reg(cs, 0, jade_HDLC_MODE, jadeMODE_TMO);
302 cs->BC_Write_Reg(cs, 1, jade_HDLC_MODE, jadeMODE_TMO);
303 /* Power down, 1-Idle, RxTx least significant bit first */
304 cs->BC_Write_Reg(cs, 0, jade_HDLC_CCR0, 0x00);
305 cs->BC_Write_Reg(cs, 1, jade_HDLC_CCR0, 0x00);
306 /* Mask all interrupts */
307 cs->BC_Write_Reg(cs, 0, jade_HDLC_IMR, 0x00);
308 cs->BC_Write_Reg(cs, 1, jade_HDLC_IMR, 0x00);
309 /* Setup host access to hdlc controller */
310 jade_write_indirect(cs, jade_HDLCCNTRACCESS, (jadeINDIRECT_HAH1|jadeINDIRECT_HAH2));
311 /* Unmask HDLC int (don´t forget DSP int later on)*/
312 cs->BC_Write_Reg(cs, -1,jade_INT, (jadeINT_HDLC1|jadeINT_HDLC2));
313
314 /* once again TRANSPARENT */
315 modejade(cs->bcs, 0, 0);
316 modejade(cs->bcs + 1, 0, 0);
317}
318
diff --git a/drivers/isdn/hisax/jade.h b/drivers/isdn/hisax/jade.h
new file mode 100644
index 000000000000..fa2944485994
--- /dev/null
+++ b/drivers/isdn/hisax/jade.h
@@ -0,0 +1,135 @@
1/* $Id: jade.h,v 1.5.2.3 2004/01/14 16:04:48 keil Exp $
2 *
3 * JADE specific defines
4 *
5 * Author Roland Klabunde
6 * Copyright by Roland Klabunde <R.Klabunde@Berkom.de>
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 */
12
13/* All Registers original Siemens Spec */
14#ifndef __JADE_H__
15#define __JADE_H__
16
17/* Special registers for access to indirect accessible JADE regs */
18#define DIRECT_IO_JADE 0x0000 /* Jade direct io access area */
19#define COMM_JADE 0x0040 /* Jade communication area */
20
21/********************************************************************/
22/* JADE-HDLC registers */
23/********************************************************************/
24#define jade_HDLC_RFIFO 0x00 /* R */
25#define jade_HDLC_XFIFO 0x00 /* W */
26
27#define jade_HDLC_STAR 0x20 /* R */
28 #define jadeSTAR_XDOV 0x80
29 #define jadeSTAR_XFW 0x40 /* Does not work*/
30 #define jadeSTAR_XCEC 0x20
31 #define jadeSTAR_RCEC 0x10
32 #define jadeSTAR_BSY 0x08
33 #define jadeSTAR_RNA 0x04
34 #define jadeSTAR_STR 0x02
35 #define jadeSTAR_STX 0x01
36
37#define jade_HDLC_XCMD 0x20 /* W */
38 #define jadeXCMD_XF 0x80
39 #define jadeXCMD_XME 0x40
40 #define jadeXCMD_XRES 0x20
41 #define jadeXCMD_STX 0x01
42
43#define jade_HDLC_RSTA 0x21 /* R */
44 #define jadeRSTA_VFR 0x80
45 #define jadeRSTA_RDO 0x40
46 #define jadeRSTA_CRC 0x20
47 #define jadeRSTA_RAB 0x10
48 #define jadeRSTA_MASK 0xF0
49
50#define jade_HDLC_MODE 0x22 /* RW*/
51 #define jadeMODE_TMO 0x80
52 #define jadeMODE_RAC 0x40
53 #define jadeMODE_XAC 0x20
54 #define jadeMODE_TLP 0x10
55 #define jadeMODE_ERFS 0x02
56 #define jadeMODE_ETFS 0x01
57
58#define jade_HDLC_RBCH 0x24 /* R */
59
60#define jade_HDLC_RBCL 0x25 /* R */
61#define jade_HDLC_RCMD 0x25 /* W */
62 #define jadeRCMD_RMC 0x80
63 #define jadeRCMD_RRES 0x40
64 #define jadeRCMD_RMD 0x20
65 #define jadeRCMD_STR 0x02
66
67#define jade_HDLC_CCR0 0x26 /* RW*/
68 #define jadeCCR0_PU 0x80
69 #define jadeCCR0_ITF 0x40
70 #define jadeCCR0_C32 0x20
71 #define jadeCCR0_CRL 0x10
72 #define jadeCCR0_RCRC 0x08
73 #define jadeCCR0_XCRC 0x04
74 #define jadeCCR0_RMSB 0x02
75 #define jadeCCR0_XMSB 0x01
76
77#define jade_HDLC_CCR1 0x27 /* RW*/
78 #define jadeCCR1_RCS0 0x80
79 #define jadeCCR1_RCONT 0x40
80 #define jadeCCR1_RFDIS 0x20
81 #define jadeCCR1_XCS0 0x10
82 #define jadeCCR1_XCONT 0x08
83 #define jadeCCR1_XFDIS 0x04
84
85#define jade_HDLC_TSAR 0x28 /* RW*/
86#define jade_HDLC_TSAX 0x29 /* RW*/
87#define jade_HDLC_RCCR 0x2A /* RW*/
88#define jade_HDLC_XCCR 0x2B /* RW*/
89
90#define jade_HDLC_ISR 0x2C /* R */
91#define jade_HDLC_IMR 0x2C /* W */
92 #define jadeISR_RME 0x80
93 #define jadeISR_RPF 0x40
94 #define jadeISR_RFO 0x20
95 #define jadeISR_XPR 0x10
96 #define jadeISR_XDU 0x08
97 #define jadeISR_ALLS 0x04
98
99#define jade_INT 0x75
100 #define jadeINT_HDLC1 0x02
101 #define jadeINT_HDLC2 0x01
102 #define jadeINT_DSP 0x04
103#define jade_INTR 0x70
104
105/********************************************************************/
106/* Indirect accessible JADE registers of common interest */
107/********************************************************************/
108#define jade_CHIPVERSIONNR 0x00 /* Does not work*/
109
110#define jade_HDLCCNTRACCESS 0x10
111 #define jadeINDIRECT_HAH1 0x02
112 #define jadeINDIRECT_HAH2 0x01
113
114#define jade_HDLC1SERRXPATH 0x1D
115#define jade_HDLC1SERTXPATH 0x1E
116#define jade_HDLC2SERRXPATH 0x1F
117#define jade_HDLC2SERTXPATH 0x20
118 #define jadeINDIRECT_SLIN1 0x10
119 #define jadeINDIRECT_SLIN0 0x08
120 #define jadeINDIRECT_LMOD1 0x04
121 #define jadeINDIRECT_LMOD0 0x02
122 #define jadeINDIRECT_HHR 0x01
123 #define jadeINDIRECT_HHX 0x01
124
125#define jade_RXAUDIOCH1CFG 0x11
126#define jade_RXAUDIOCH2CFG 0x14
127#define jade_TXAUDIOCH1CFG 0x17
128#define jade_TXAUDIOCH2CFG 0x1A
129
130extern int JadeVersion(struct IsdnCardState *cs, char *s);
131extern void modejade(struct BCState *bcs, int mode, int bc);
132extern void clear_pending_jade_ints(struct IsdnCardState *cs);
133extern void initjade(struct IsdnCardState *cs);
134
135#endif /* __JADE_H__ */
diff --git a/drivers/isdn/hisax/jade_irq.c b/drivers/isdn/hisax/jade_irq.c
new file mode 100644
index 000000000000..08563400e4fd
--- /dev/null
+++ b/drivers/isdn/hisax/jade_irq.c
@@ -0,0 +1,236 @@
1/* $Id: jade_irq.c,v 1.7.2.4 2004/02/11 13:21:34 keil Exp $
2 *
3 * Low level JADE IRQ stuff (derived from original hscx_irq.c)
4 *
5 * Author Roland Klabunde
6 * Copyright by Roland Klabunde <R.Klabunde@Berkom.de>
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 */
12
13static inline void
14waitforCEC(struct IsdnCardState *cs, int jade, int reg)
15{
16 int to = 50;
17 int mask = (reg == jade_HDLC_XCMD ? jadeSTAR_XCEC : jadeSTAR_RCEC);
18 while ((READJADE(cs, jade, jade_HDLC_STAR) & mask) && to) {
19 udelay(1);
20 to--;
21 }
22 if (!to)
23 printk(KERN_WARNING "HiSax: waitforCEC (jade) timeout\n");
24}
25
26
27static inline void
28waitforXFW(struct IsdnCardState *cs, int jade)
29{
30 /* Does not work on older jade versions, don't care */
31}
32
33static inline void
34WriteJADECMDR(struct IsdnCardState *cs, int jade, int reg, u_char data)
35{
36 waitforCEC(cs, jade, reg);
37 WRITEJADE(cs, jade, reg, data);
38}
39
40
41
42static void
43jade_empty_fifo(struct BCState *bcs, int count)
44{
45 u_char *ptr;
46 struct IsdnCardState *cs = bcs->cs;
47
48 if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
49 debugl1(cs, "jade_empty_fifo");
50
51 if (bcs->hw.hscx.rcvidx + count > HSCX_BUFMAX) {
52 if (cs->debug & L1_DEB_WARN)
53 debugl1(cs, "jade_empty_fifo: incoming packet too large");
54 WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_RCMD, jadeRCMD_RMC);
55 bcs->hw.hscx.rcvidx = 0;
56 return;
57 }
58 ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx;
59 bcs->hw.hscx.rcvidx += count;
60 READJADEFIFO(cs, bcs->hw.hscx.hscx, ptr, count);
61 WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_RCMD, jadeRCMD_RMC);
62 if (cs->debug & L1_DEB_HSCX_FIFO) {
63 char *t = bcs->blog;
64
65 t += sprintf(t, "jade_empty_fifo %c cnt %d",
66 bcs->hw.hscx.hscx ? 'B' : 'A', count);
67 QuickHex(t, ptr, count);
68 debugl1(cs, bcs->blog);
69 }
70}
71
72static void
73jade_fill_fifo(struct BCState *bcs)
74{
75 struct IsdnCardState *cs = bcs->cs;
76 int more, count;
77 int fifo_size = 32;
78 u_char *ptr;
79
80 if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
81 debugl1(cs, "jade_fill_fifo");
82
83 if (!bcs->tx_skb)
84 return;
85 if (bcs->tx_skb->len <= 0)
86 return;
87
88 more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0;
89 if (bcs->tx_skb->len > fifo_size) {
90 more = !0;
91 count = fifo_size;
92 } else
93 count = bcs->tx_skb->len;
94
95 waitforXFW(cs, bcs->hw.hscx.hscx);
96 ptr = bcs->tx_skb->data;
97 skb_pull(bcs->tx_skb, count);
98 bcs->tx_cnt -= count;
99 bcs->hw.hscx.count += count;
100 WRITEJADEFIFO(cs, bcs->hw.hscx.hscx, ptr, count);
101 WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_XCMD, more ? jadeXCMD_XF : (jadeXCMD_XF|jadeXCMD_XME));
102 if (cs->debug & L1_DEB_HSCX_FIFO) {
103 char *t = bcs->blog;
104
105 t += sprintf(t, "jade_fill_fifo %c cnt %d",
106 bcs->hw.hscx.hscx ? 'B' : 'A', count);
107 QuickHex(t, ptr, count);
108 debugl1(cs, bcs->blog);
109 }
110}
111
112
113static inline void
114jade_interrupt(struct IsdnCardState *cs, u_char val, u_char jade)
115{
116 u_char r;
117 struct BCState *bcs = cs->bcs + jade;
118 struct sk_buff *skb;
119 int fifo_size = 32;
120 int count;
121 int i_jade = (int) jade; /* To satisfy the compiler */
122
123 if (!test_bit(BC_FLG_INIT, &bcs->Flag))
124 return;
125
126 if (val & 0x80) { /* RME */
127 r = READJADE(cs, i_jade, jade_HDLC_RSTA);
128 if ((r & 0xf0) != 0xa0) {
129 if (!(r & 0x80))
130 if (cs->debug & L1_DEB_WARN)
131 debugl1(cs, "JADE %s invalid frame", (jade ? "B":"A"));
132 if ((r & 0x40) && bcs->mode)
133 if (cs->debug & L1_DEB_WARN)
134 debugl1(cs, "JADE %c RDO mode=%d", 'A'+jade, bcs->mode);
135 if (!(r & 0x20))
136 if (cs->debug & L1_DEB_WARN)
137 debugl1(cs, "JADE %c CRC error", 'A'+jade);
138 WriteJADECMDR(cs, jade, jade_HDLC_RCMD, jadeRCMD_RMC);
139 } else {
140 count = READJADE(cs, i_jade, jade_HDLC_RBCL) & 0x1F;
141 if (count == 0)
142 count = fifo_size;
143 jade_empty_fifo(bcs, count);
144 if ((count = bcs->hw.hscx.rcvidx - 1) > 0) {
145 if (cs->debug & L1_DEB_HSCX_FIFO)
146 debugl1(cs, "HX Frame %d", count);
147 if (!(skb = dev_alloc_skb(count)))
148 printk(KERN_WARNING "JADE %s receive out of memory\n", (jade ? "B":"A"));
149 else {
150 memcpy(skb_put(skb, count), bcs->hw.hscx.rcvbuf, count);
151 skb_queue_tail(&bcs->rqueue, skb);
152 }
153 }
154 }
155 bcs->hw.hscx.rcvidx = 0;
156 schedule_event(bcs, B_RCVBUFREADY);
157 }
158 if (val & 0x40) { /* RPF */
159 jade_empty_fifo(bcs, fifo_size);
160 if (bcs->mode == L1_MODE_TRANS) {
161 /* receive audio data */
162 if (!(skb = dev_alloc_skb(fifo_size)))
163 printk(KERN_WARNING "HiSax: receive out of memory\n");
164 else {
165 memcpy(skb_put(skb, fifo_size), bcs->hw.hscx.rcvbuf, fifo_size);
166 skb_queue_tail(&bcs->rqueue, skb);
167 }
168 bcs->hw.hscx.rcvidx = 0;
169 schedule_event(bcs, B_RCVBUFREADY);
170 }
171 }
172 if (val & 0x10) { /* XPR */
173 if (bcs->tx_skb) {
174 if (bcs->tx_skb->len) {
175 jade_fill_fifo(bcs);
176 return;
177 } else {
178 if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) &&
179 (PACKET_NOACK != bcs->tx_skb->pkt_type)) {
180 u_long flags;
181 spin_lock_irqsave(&bcs->aclock, flags);
182 bcs->ackcnt += bcs->hw.hscx.count;
183 spin_unlock_irqrestore(&bcs->aclock, flags);
184 schedule_event(bcs, B_ACKPENDING);
185 }
186 dev_kfree_skb_irq(bcs->tx_skb);
187 bcs->hw.hscx.count = 0;
188 bcs->tx_skb = NULL;
189 }
190 }
191 if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
192 bcs->hw.hscx.count = 0;
193 test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
194 jade_fill_fifo(bcs);
195 } else {
196 test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
197 schedule_event(bcs, B_XMTBUFREADY);
198 }
199 }
200}
201
202static inline void
203jade_int_main(struct IsdnCardState *cs, u_char val, int jade)
204{
205 struct BCState *bcs;
206 bcs = cs->bcs + jade;
207
208 if (val & jadeISR_RFO) {
209 /* handled with RDO */
210 val &= ~jadeISR_RFO;
211 }
212 if (val & jadeISR_XDU) {
213 /* relevant in HDLC mode only */
214 /* don't reset XPR here */
215 if (bcs->mode == 1)
216 jade_fill_fifo(bcs);
217 else {
218 /* Here we lost an TX interrupt, so
219 * restart transmitting the whole frame.
220 */
221 if (bcs->tx_skb) {
222 skb_push(bcs->tx_skb, bcs->hw.hscx.count);
223 bcs->tx_cnt += bcs->hw.hscx.count;
224 bcs->hw.hscx.count = 0;
225 }
226 WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_XCMD, jadeXCMD_XRES);
227 if (cs->debug & L1_DEB_WARN)
228 debugl1(cs, "JADE %c EXIR %x Lost TX", 'A'+jade, val);
229 }
230 }
231 if (val & (jadeISR_RME|jadeISR_RPF|jadeISR_XPR)) {
232 if (cs->debug & L1_DEB_HSCX)
233 debugl1(cs, "JADE %c interrupt %x", 'A'+jade, val);
234 jade_interrupt(cs, val, jade);
235 }
236}
diff --git a/drivers/isdn/hisax/l3_1tr6.c b/drivers/isdn/hisax/l3_1tr6.c
new file mode 100644
index 000000000000..d6c1c8f8329d
--- /dev/null
+++ b/drivers/isdn/hisax/l3_1tr6.c
@@ -0,0 +1,955 @@
1/* $Id: l3_1tr6.c,v 2.15.2.3 2004/01/13 14:31:25 keil Exp $
2 *
3 * German 1TR6 D-channel protocol
4 *
5 * Author Karsten Keil
6 * Copyright by Karsten Keil <keil@isdn4linux.de>
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 * For changes and modifications please read
12 * Documentation/isdn/HiSax.cert
13 *
14 */
15
16#include "hisax.h"
17#include "l3_1tr6.h"
18#include "isdnl3.h"
19#include <linux/ctype.h>
20
21extern char *HiSax_getrev(const char *revision);
22const char *l3_1tr6_revision = "$Revision: 2.15.2.3 $";
23
24#define MsgHead(ptr, cref, mty, dis) \
25 *ptr++ = dis; \
26 *ptr++ = 0x1; \
27 *ptr++ = cref ^ 0x80; \
28 *ptr++ = mty
29
30static void
31l3_1TR6_message(struct l3_process *pc, u_char mt, u_char pd)
32{
33 struct sk_buff *skb;
34 u_char *p;
35
36 if (!(skb = l3_alloc_skb(4)))
37 return;
38 p = skb_put(skb, 4);
39 MsgHead(p, pc->callref, mt, pd);
40 l3_msg(pc->st, DL_DATA | REQUEST, skb);
41}
42
43static void
44l3_1tr6_release_req(struct l3_process *pc, u_char pr, void *arg)
45{
46 StopAllL3Timer(pc);
47 newl3state(pc, 19);
48 l3_1TR6_message(pc, MT_N1_REL, PROTO_DIS_N1);
49 L3AddTimer(&pc->timer, T308, CC_T308_1);
50}
51
52static void
53l3_1tr6_invalid(struct l3_process *pc, u_char pr, void *arg)
54{
55 struct sk_buff *skb = arg;
56
57 dev_kfree_skb(skb);
58 l3_1tr6_release_req(pc, 0, NULL);
59}
60
61static void
62l3_1tr6_error(struct l3_process *pc, u_char *msg, struct sk_buff *skb)
63{
64 dev_kfree_skb(skb);
65 if (pc->st->l3.debug & L3_DEB_WARN)
66 l3_debug(pc->st, msg);
67 l3_1tr6_release_req(pc, 0, NULL);
68}
69
70static void
71l3_1tr6_setup_req(struct l3_process *pc, u_char pr, void *arg)
72{
73 struct sk_buff *skb;
74 u_char tmp[128];
75 u_char *p = tmp;
76 u_char *teln;
77 u_char *eaz;
78 u_char channel = 0;
79 int l;
80
81 MsgHead(p, pc->callref, MT_N1_SETUP, PROTO_DIS_N1);
82 teln = pc->para.setup.phone;
83 pc->para.spv = 0;
84 if (!isdigit(*teln)) {
85 switch (0x5f & *teln) {
86 case 'S':
87 pc->para.spv = 1;
88 break;
89 case 'C':
90 channel = 0x08;
91 case 'P':
92 channel |= 0x80;
93 teln++;
94 if (*teln == '1')
95 channel |= 0x01;
96 else
97 channel |= 0x02;
98 break;
99 default:
100 if (pc->st->l3.debug & L3_DEB_WARN)
101 l3_debug(pc->st, "Wrong MSN Code");
102 break;
103 }
104 teln++;
105 }
106 if (channel) {
107 *p++ = 0x18; /* channel indicator */
108 *p++ = 1;
109 *p++ = channel;
110 }
111 if (pc->para.spv) { /* SPV ? */
112 /* NSF SPV */
113 *p++ = WE0_netSpecFac;
114 *p++ = 4; /* Laenge */
115 *p++ = 0;
116 *p++ = FAC_SPV; /* SPV */
117 *p++ = pc->para.setup.si1; /* 0 for all Services */
118 *p++ = pc->para.setup.si2; /* 0 for all Services */
119 *p++ = WE0_netSpecFac;
120 *p++ = 4; /* Laenge */
121 *p++ = 0;
122 *p++ = FAC_Activate; /* aktiviere SPV (default) */
123 *p++ = pc->para.setup.si1; /* 0 for all Services */
124 *p++ = pc->para.setup.si2; /* 0 for all Services */
125 }
126 eaz = pc->para.setup.eazmsn;
127 if (*eaz) {
128 *p++ = WE0_origAddr;
129 *p++ = strlen(eaz) + 1;
130 /* Classify as AnyPref. */
131 *p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
132 while (*eaz)
133 *p++ = *eaz++ & 0x7f;
134 }
135 *p++ = WE0_destAddr;
136 *p++ = strlen(teln) + 1;
137 /* Classify as AnyPref. */
138 *p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
139 while (*teln)
140 *p++ = *teln++ & 0x7f;
141
142 *p++ = WE_Shift_F6;
143 /* Codesatz 6 fuer Service */
144 *p++ = WE6_serviceInd;
145 *p++ = 2; /* len=2 info,info2 */
146 *p++ = pc->para.setup.si1;
147 *p++ = pc->para.setup.si2;
148
149 l = p - tmp;
150 if (!(skb = l3_alloc_skb(l)))
151 return;
152 memcpy(skb_put(skb, l), tmp, l);
153 L3DelTimer(&pc->timer);
154 L3AddTimer(&pc->timer, T303, CC_T303);
155 newl3state(pc, 1);
156 l3_msg(pc->st, DL_DATA | REQUEST, skb);
157}
158
159static void
160l3_1tr6_setup(struct l3_process *pc, u_char pr, void *arg)
161{
162 u_char *p;
163 int bcfound = 0;
164 char tmp[80];
165 struct sk_buff *skb = arg;
166
167 p = skb->data;
168
169 /* Channel Identification */
170 p = skb->data;
171 if ((p = findie(p, skb->len, WE0_chanID, 0))) {
172 if (p[1] != 1) {
173 l3_1tr6_error(pc, "setup wrong chanID len", skb);
174 return;
175 }
176 if ((p[2] & 0xf4) != 0x80) {
177 l3_1tr6_error(pc, "setup wrong WE0_chanID", skb);
178 return;
179 }
180 if ((pc->para.bchannel = p[2] & 0x3))
181 bcfound++;
182 } else {
183 l3_1tr6_error(pc, "missing setup chanID", skb);
184 return;
185 }
186
187 p = skb->data;
188 if ((p = findie(p, skb->len, WE6_serviceInd, 6))) {
189 pc->para.setup.si1 = p[2];
190 pc->para.setup.si2 = p[3];
191 } else {
192 l3_1tr6_error(pc, "missing setup SI", skb);
193 return;
194 }
195
196 p = skb->data;
197 if ((p = findie(p, skb->len, WE0_destAddr, 0)))
198 iecpy(pc->para.setup.eazmsn, p, 1);
199 else
200 pc->para.setup.eazmsn[0] = 0;
201
202 p = skb->data;
203 if ((p = findie(p, skb->len, WE0_origAddr, 0))) {
204 iecpy(pc->para.setup.phone, p, 1);
205 } else
206 pc->para.setup.phone[0] = 0;
207
208 p = skb->data;
209 pc->para.spv = 0;
210 if ((p = findie(p, skb->len, WE0_netSpecFac, 0))) {
211 if ((FAC_SPV == p[3]) || (FAC_Activate == p[3]))
212 pc->para.spv = 1;
213 }
214 dev_kfree_skb(skb);
215
216 /* Signal all services, linklevel takes care of Service-Indicator */
217 if (bcfound) {
218 if ((pc->para.setup.si1 != 7) && (pc->st->l3.debug & L3_DEB_WARN)) {
219 sprintf(tmp, "non-digital call: %s -> %s",
220 pc->para.setup.phone,
221 pc->para.setup.eazmsn);
222 l3_debug(pc->st, tmp);
223 }
224 newl3state(pc, 6);
225 pc->st->l3.l3l4(pc->st, CC_SETUP | INDICATION, pc);
226 } else
227 release_l3_process(pc);
228}
229
230static void
231l3_1tr6_setup_ack(struct l3_process *pc, u_char pr, void *arg)
232{
233 u_char *p;
234 struct sk_buff *skb = arg;
235
236 L3DelTimer(&pc->timer);
237 p = skb->data;
238 newl3state(pc, 2);
239 if ((p = findie(p, skb->len, WE0_chanID, 0))) {
240 if (p[1] != 1) {
241 l3_1tr6_error(pc, "setup_ack wrong chanID len", skb);
242 return;
243 }
244 if ((p[2] & 0xf4) != 0x80) {
245 l3_1tr6_error(pc, "setup_ack wrong WE0_chanID", skb);
246 return;
247 }
248 pc->para.bchannel = p[2] & 0x3;
249 } else {
250 l3_1tr6_error(pc, "missing setup_ack WE0_chanID", skb);
251 return;
252 }
253 dev_kfree_skb(skb);
254 L3AddTimer(&pc->timer, T304, CC_T304);
255 pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc);
256}
257
258static void
259l3_1tr6_call_sent(struct l3_process *pc, u_char pr, void *arg)
260{
261 u_char *p;
262 struct sk_buff *skb = arg;
263
264 L3DelTimer(&pc->timer);
265 p = skb->data;
266 if ((p = findie(p, skb->len, WE0_chanID, 0))) {
267 if (p[1] != 1) {
268 l3_1tr6_error(pc, "call sent wrong chanID len", skb);
269 return;
270 }
271 if ((p[2] & 0xf4) != 0x80) {
272 l3_1tr6_error(pc, "call sent wrong WE0_chanID", skb);
273 return;
274 }
275 if ((pc->state == 2) && (pc->para.bchannel != (p[2] & 0x3))) {
276 l3_1tr6_error(pc, "call sent wrong chanID value", skb);
277 return;
278 }
279 pc->para.bchannel = p[2] & 0x3;
280 } else {
281 l3_1tr6_error(pc, "missing call sent WE0_chanID", skb);
282 return;
283 }
284 dev_kfree_skb(skb);
285 L3AddTimer(&pc->timer, T310, CC_T310);
286 newl3state(pc, 3);
287 pc->st->l3.l3l4(pc->st, CC_PROCEEDING | INDICATION, pc);
288}
289
290static void
291l3_1tr6_alert(struct l3_process *pc, u_char pr, void *arg)
292{
293 struct sk_buff *skb = arg;
294
295 dev_kfree_skb(skb);
296 L3DelTimer(&pc->timer); /* T304 */
297 newl3state(pc, 4);
298 pc->st->l3.l3l4(pc->st, CC_ALERTING | INDICATION, pc);
299}
300
301static void
302l3_1tr6_info(struct l3_process *pc, u_char pr, void *arg)
303{
304 u_char *p;
305 int i, tmpcharge = 0;
306 char a_charge[8], tmp[32];
307 struct sk_buff *skb = arg;
308
309 p = skb->data;
310 if ((p = findie(p, skb->len, WE6_chargingInfo, 6))) {
311 iecpy(a_charge, p, 1);
312 for (i = 0; i < strlen(a_charge); i++) {
313 tmpcharge *= 10;
314 tmpcharge += a_charge[i] & 0xf;
315 }
316 if (tmpcharge > pc->para.chargeinfo) {
317 pc->para.chargeinfo = tmpcharge;
318 pc->st->l3.l3l4(pc->st, CC_CHARGE | INDICATION, pc);
319 }
320 if (pc->st->l3.debug & L3_DEB_CHARGE) {
321 sprintf(tmp, "charging info %d", pc->para.chargeinfo);
322 l3_debug(pc->st, tmp);
323 }
324 } else if (pc->st->l3.debug & L3_DEB_CHARGE)
325 l3_debug(pc->st, "charging info not found");
326 dev_kfree_skb(skb);
327
328}
329
330static void
331l3_1tr6_info_s2(struct l3_process *pc, u_char pr, void *arg)
332{
333 struct sk_buff *skb = arg;
334
335 dev_kfree_skb(skb);
336}
337
338static void
339l3_1tr6_connect(struct l3_process *pc, u_char pr, void *arg)
340{
341 struct sk_buff *skb = arg;
342
343 L3DelTimer(&pc->timer); /* T310 */
344 if (!findie(skb->data, skb->len, WE6_date, 6)) {
345 l3_1tr6_error(pc, "missing connect date", skb);
346 return;
347 }
348 newl3state(pc, 10);
349 dev_kfree_skb(skb);
350 pc->para.chargeinfo = 0;
351 pc->st->l3.l3l4(pc->st, CC_SETUP | CONFIRM, pc);
352}
353
354static void
355l3_1tr6_rel(struct l3_process *pc, u_char pr, void *arg)
356{
357 struct sk_buff *skb = arg;
358 u_char *p;
359
360 p = skb->data;
361 if ((p = findie(p, skb->len, WE0_cause, 0))) {
362 if (p[1] > 0) {
363 pc->para.cause = p[2];
364 if (p[1] > 1)
365 pc->para.loc = p[3];
366 else
367 pc->para.loc = 0;
368 } else {
369 pc->para.cause = 0;
370 pc->para.loc = 0;
371 }
372 } else {
373 pc->para.cause = NO_CAUSE;
374 l3_1tr6_error(pc, "missing REL cause", skb);
375 return;
376 }
377 dev_kfree_skb(skb);
378 StopAllL3Timer(pc);
379 newl3state(pc, 0);
380 l3_1TR6_message(pc, MT_N1_REL_ACK, PROTO_DIS_N1);
381 pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
382 release_l3_process(pc);
383}
384
385static void
386l3_1tr6_rel_ack(struct l3_process *pc, u_char pr, void *arg)
387{
388 struct sk_buff *skb = arg;
389
390 dev_kfree_skb(skb);
391 StopAllL3Timer(pc);
392 newl3state(pc, 0);
393 pc->para.cause = NO_CAUSE;
394 pc->st->l3.l3l4(pc->st, CC_RELEASE | CONFIRM, pc);
395 release_l3_process(pc);
396}
397
398static void
399l3_1tr6_disc(struct l3_process *pc, u_char pr, void *arg)
400{
401 struct sk_buff *skb = arg;
402 u_char *p;
403 int i, tmpcharge = 0;
404 char a_charge[8], tmp[32];
405
406 StopAllL3Timer(pc);
407 p = skb->data;
408 if ((p = findie(p, skb->len, WE6_chargingInfo, 6))) {
409 iecpy(a_charge, p, 1);
410 for (i = 0; i < strlen(a_charge); i++) {
411 tmpcharge *= 10;
412 tmpcharge += a_charge[i] & 0xf;
413 }
414 if (tmpcharge > pc->para.chargeinfo) {
415 pc->para.chargeinfo = tmpcharge;
416 pc->st->l3.l3l4(pc->st, CC_CHARGE | INDICATION, pc);
417 }
418 if (pc->st->l3.debug & L3_DEB_CHARGE) {
419 sprintf(tmp, "charging info %d", pc->para.chargeinfo);
420 l3_debug(pc->st, tmp);
421 }
422 } else if (pc->st->l3.debug & L3_DEB_CHARGE)
423 l3_debug(pc->st, "charging info not found");
424
425
426 p = skb->data;
427 if ((p = findie(p, skb->len, WE0_cause, 0))) {
428 if (p[1] > 0) {
429 pc->para.cause = p[2];
430 if (p[1] > 1)
431 pc->para.loc = p[3];
432 else
433 pc->para.loc = 0;
434 } else {
435 pc->para.cause = 0;
436 pc->para.loc = 0;
437 }
438 } else {
439 if (pc->st->l3.debug & L3_DEB_WARN)
440 l3_debug(pc->st, "cause not found");
441 pc->para.cause = NO_CAUSE;
442 }
443 if (!findie(skb->data, skb->len, WE6_date, 6)) {
444 l3_1tr6_error(pc, "missing connack date", skb);
445 return;
446 }
447 dev_kfree_skb(skb);
448 newl3state(pc, 12);
449 pc->st->l3.l3l4(pc->st, CC_DISCONNECT | INDICATION, pc);
450}
451
452
453static void
454l3_1tr6_connect_ack(struct l3_process *pc, u_char pr, void *arg)
455{
456 struct sk_buff *skb = arg;
457
458 if (!findie(skb->data, skb->len, WE6_date, 6)) {
459 l3_1tr6_error(pc, "missing connack date", skb);
460 return;
461 }
462 dev_kfree_skb(skb);
463 newl3state(pc, 10);
464 pc->para.chargeinfo = 0;
465 L3DelTimer(&pc->timer);
466 pc->st->l3.l3l4(pc->st, CC_SETUP_COMPL | INDICATION, pc);
467}
468
469static void
470l3_1tr6_alert_req(struct l3_process *pc, u_char pr, void *arg)
471{
472 newl3state(pc, 7);
473 l3_1TR6_message(pc, MT_N1_ALERT, PROTO_DIS_N1);
474}
475
476static void
477l3_1tr6_setup_rsp(struct l3_process *pc, u_char pr, void *arg)
478{
479 struct sk_buff *skb;
480 u_char tmp[24];
481 u_char *p = tmp;
482 int l;
483
484 MsgHead(p, pc->callref, MT_N1_CONN, PROTO_DIS_N1);
485 if (pc->para.spv) { /* SPV ? */
486 /* NSF SPV */
487 *p++ = WE0_netSpecFac;
488 *p++ = 4; /* Laenge */
489 *p++ = 0;
490 *p++ = FAC_SPV; /* SPV */
491 *p++ = pc->para.setup.si1;
492 *p++ = pc->para.setup.si2;
493 *p++ = WE0_netSpecFac;
494 *p++ = 4; /* Laenge */
495 *p++ = 0;
496 *p++ = FAC_Activate; /* aktiviere SPV */
497 *p++ = pc->para.setup.si1;
498 *p++ = pc->para.setup.si2;
499 }
500 newl3state(pc, 8);
501 l = p - tmp;
502 if (!(skb = l3_alloc_skb(l)))
503 return;
504 memcpy(skb_put(skb, l), tmp, l);
505 l3_msg(pc->st, DL_DATA | REQUEST, skb);
506 L3DelTimer(&pc->timer);
507 L3AddTimer(&pc->timer, T313, CC_T313);
508}
509
510static void
511l3_1tr6_reset(struct l3_process *pc, u_char pr, void *arg)
512{
513 release_l3_process(pc);
514}
515
516static void
517l3_1tr6_disconnect_req(struct l3_process *pc, u_char pr, void *arg)
518{
519 struct sk_buff *skb;
520 u_char tmp[16];
521 u_char *p = tmp;
522 int l;
523 u_char cause = 0x10;
524 u_char clen = 1;
525
526 if (pc->para.cause > 0)
527 cause = pc->para.cause;
528 /* Map DSS1 causes */
529 switch (cause & 0x7f) {
530 case 0x10:
531 clen = 0;
532 break;
533 case 0x11:
534 cause = CAUSE_UserBusy;
535 break;
536 case 0x15:
537 cause = CAUSE_CallRejected;
538 break;
539 }
540 StopAllL3Timer(pc);
541 MsgHead(p, pc->callref, MT_N1_DISC, PROTO_DIS_N1);
542 *p++ = WE0_cause;
543 *p++ = clen; /* Laenge */
544 if (clen)
545 *p++ = cause | 0x80;
546 newl3state(pc, 11);
547 l = p - tmp;
548 if (!(skb = l3_alloc_skb(l)))
549 return;
550 memcpy(skb_put(skb, l), tmp, l);
551 l3_msg(pc->st, DL_DATA | REQUEST, skb);
552 L3AddTimer(&pc->timer, T305, CC_T305);
553}
554
555static void
556l3_1tr6_t303(struct l3_process *pc, u_char pr, void *arg)
557{
558 if (pc->N303 > 0) {
559 pc->N303--;
560 L3DelTimer(&pc->timer);
561 l3_1tr6_setup_req(pc, pr, arg);
562 } else {
563 L3DelTimer(&pc->timer);
564 pc->para.cause = 0;
565 l3_1tr6_disconnect_req(pc, 0, NULL);
566 }
567}
568
569static void
570l3_1tr6_t304(struct l3_process *pc, u_char pr, void *arg)
571{
572 L3DelTimer(&pc->timer);
573 pc->para.cause = 0xE6;
574 l3_1tr6_disconnect_req(pc, pr, NULL);
575 pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
576}
577
578static void
579l3_1tr6_t305(struct l3_process *pc, u_char pr, void *arg)
580{
581 struct sk_buff *skb;
582 u_char tmp[16];
583 u_char *p = tmp;
584 int l;
585 u_char cause = 0x90;
586 u_char clen = 1;
587
588 L3DelTimer(&pc->timer);
589 if (pc->para.cause != NO_CAUSE)
590 cause = pc->para.cause;
591 /* Map DSS1 causes */
592 switch (cause & 0x7f) {
593 case 0x10:
594 clen = 0;
595 break;
596 case 0x15:
597 cause = CAUSE_CallRejected;
598 break;
599 }
600 MsgHead(p, pc->callref, MT_N1_REL, PROTO_DIS_N1);
601 *p++ = WE0_cause;
602 *p++ = clen; /* Laenge */
603 if (clen)
604 *p++ = cause;
605 newl3state(pc, 19);
606 l = p - tmp;
607 if (!(skb = l3_alloc_skb(l)))
608 return;
609 memcpy(skb_put(skb, l), tmp, l);
610 l3_msg(pc->st, DL_DATA | REQUEST, skb);
611 L3AddTimer(&pc->timer, T308, CC_T308_1);
612}
613
614static void
615l3_1tr6_t310(struct l3_process *pc, u_char pr, void *arg)
616{
617 L3DelTimer(&pc->timer);
618 pc->para.cause = 0xE6;
619 l3_1tr6_disconnect_req(pc, pr, NULL);
620 pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
621}
622
623static void
624l3_1tr6_t313(struct l3_process *pc, u_char pr, void *arg)
625{
626 L3DelTimer(&pc->timer);
627 pc->para.cause = 0xE6;
628 l3_1tr6_disconnect_req(pc, pr, NULL);
629 pc->st->l3.l3l4(pc->st, CC_CONNECT_ERR, pc);
630}
631
632static void
633l3_1tr6_t308_1(struct l3_process *pc, u_char pr, void *arg)
634{
635 L3DelTimer(&pc->timer);
636 l3_1TR6_message(pc, MT_N1_REL, PROTO_DIS_N1);
637 L3AddTimer(&pc->timer, T308, CC_T308_2);
638 newl3state(pc, 19);
639}
640
641static void
642l3_1tr6_t308_2(struct l3_process *pc, u_char pr, void *arg)
643{
644 L3DelTimer(&pc->timer);
645 pc->st->l3.l3l4(pc->st, CC_RELEASE_ERR, pc);
646 release_l3_process(pc);
647}
648
649static void
650l3_1tr6_dl_reset(struct l3_process *pc, u_char pr, void *arg)
651{
652 pc->para.cause = CAUSE_LocalProcErr;
653 l3_1tr6_disconnect_req(pc, pr, NULL);
654 pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
655}
656
657static void
658l3_1tr6_dl_release(struct l3_process *pc, u_char pr, void *arg)
659{
660 newl3state(pc, 0);
661 pc->para.cause = 0x1b; /* Destination out of order */
662 pc->para.loc = 0;
663 pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
664 release_l3_process(pc);
665}
666
667/* *INDENT-OFF* */
668static struct stateentry downstl[] =
669{
670 {SBIT(0),
671 CC_SETUP | REQUEST, l3_1tr6_setup_req},
672 {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(6) | SBIT(7) | SBIT(8) |
673 SBIT(10),
674 CC_DISCONNECT | REQUEST, l3_1tr6_disconnect_req},
675 {SBIT(12),
676 CC_RELEASE | REQUEST, l3_1tr6_release_req},
677 {SBIT(6),
678 CC_IGNORE | REQUEST, l3_1tr6_reset},
679 {SBIT(6),
680 CC_REJECT | REQUEST, l3_1tr6_disconnect_req},
681 {SBIT(6),
682 CC_ALERTING | REQUEST, l3_1tr6_alert_req},
683 {SBIT(6) | SBIT(7),
684 CC_SETUP | RESPONSE, l3_1tr6_setup_rsp},
685 {SBIT(1),
686 CC_T303, l3_1tr6_t303},
687 {SBIT(2),
688 CC_T304, l3_1tr6_t304},
689 {SBIT(3),
690 CC_T310, l3_1tr6_t310},
691 {SBIT(8),
692 CC_T313, l3_1tr6_t313},
693 {SBIT(11),
694 CC_T305, l3_1tr6_t305},
695 {SBIT(19),
696 CC_T308_1, l3_1tr6_t308_1},
697 {SBIT(19),
698 CC_T308_2, l3_1tr6_t308_2},
699};
700
701#define DOWNSTL_LEN \
702 (sizeof(downstl) / sizeof(struct stateentry))
703
704static struct stateentry datastln1[] =
705{
706 {SBIT(0),
707 MT_N1_INVALID, l3_1tr6_invalid},
708 {SBIT(0),
709 MT_N1_SETUP, l3_1tr6_setup},
710 {SBIT(1),
711 MT_N1_SETUP_ACK, l3_1tr6_setup_ack},
712 {SBIT(1) | SBIT(2),
713 MT_N1_CALL_SENT, l3_1tr6_call_sent},
714 {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(10),
715 MT_N1_DISC, l3_1tr6_disc},
716 {SBIT(2) | SBIT(3) | SBIT(4),
717 MT_N1_ALERT, l3_1tr6_alert},
718 {SBIT(2) | SBIT(3) | SBIT(4),
719 MT_N1_CONN, l3_1tr6_connect},
720 {SBIT(2),
721 MT_N1_INFO, l3_1tr6_info_s2},
722 {SBIT(8),
723 MT_N1_CONN_ACK, l3_1tr6_connect_ack},
724 {SBIT(10),
725 MT_N1_INFO, l3_1tr6_info},
726 {SBIT(0) | SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) |
727 SBIT(10) | SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17),
728 MT_N1_REL, l3_1tr6_rel},
729 {SBIT(19),
730 MT_N1_REL, l3_1tr6_rel_ack},
731 {SBIT(0) | SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) |
732 SBIT(10) | SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17),
733 MT_N1_REL_ACK, l3_1tr6_invalid},
734 {SBIT(19),
735 MT_N1_REL_ACK, l3_1tr6_rel_ack}
736};
737
738#define DATASTLN1_LEN \
739 (sizeof(datastln1) / sizeof(struct stateentry))
740
741static struct stateentry manstatelist[] =
742{
743 {SBIT(2),
744 DL_ESTABLISH | INDICATION, l3_1tr6_dl_reset},
745 {ALL_STATES,
746 DL_RELEASE | INDICATION, l3_1tr6_dl_release},
747};
748
749#define MANSLLEN \
750 (sizeof(manstatelist) / sizeof(struct stateentry))
751/* *INDENT-ON* */
752
753static void
754up1tr6(struct PStack *st, int pr, void *arg)
755{
756 int i, mt, cr;
757 struct l3_process *proc;
758 struct sk_buff *skb = arg;
759 char tmp[80];
760
761 switch (pr) {
762 case (DL_DATA | INDICATION):
763 case (DL_UNIT_DATA | INDICATION):
764 break;
765 case (DL_ESTABLISH | CONFIRM):
766 case (DL_ESTABLISH | INDICATION):
767 case (DL_RELEASE | INDICATION):
768 case (DL_RELEASE | CONFIRM):
769 l3_msg(st, pr, arg);
770 return;
771 break;
772 }
773 if (skb->len < 4) {
774 if (st->l3.debug & L3_DEB_PROTERR) {
775 sprintf(tmp, "up1tr6 len only %d", skb->len);
776 l3_debug(st, tmp);
777 }
778 dev_kfree_skb(skb);
779 return;
780 }
781 if ((skb->data[0] & 0xfe) != PROTO_DIS_N0) {
782 if (st->l3.debug & L3_DEB_PROTERR) {
783 sprintf(tmp, "up1tr6%sunexpected discriminator %x message len %d",
784 (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ",
785 skb->data[0], skb->len);
786 l3_debug(st, tmp);
787 }
788 dev_kfree_skb(skb);
789 return;
790 }
791 if (skb->data[1] != 1) {
792 if (st->l3.debug & L3_DEB_PROTERR) {
793 sprintf(tmp, "up1tr6 CR len not 1");
794 l3_debug(st, tmp);
795 }
796 dev_kfree_skb(skb);
797 return;
798 }
799 cr = skb->data[2];
800 mt = skb->data[3];
801 if (skb->data[0] == PROTO_DIS_N0) {
802 dev_kfree_skb(skb);
803 if (st->l3.debug & L3_DEB_STATE) {
804 sprintf(tmp, "up1tr6%s N0 mt %x unhandled",
805 (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", mt);
806 l3_debug(st, tmp);
807 }
808 } else if (skb->data[0] == PROTO_DIS_N1) {
809 if (!(proc = getl3proc(st, cr))) {
810 if (mt == MT_N1_SETUP) {
811 if (cr < 128) {
812 if (!(proc = new_l3_process(st, cr))) {
813 if (st->l3.debug & L3_DEB_PROTERR) {
814 sprintf(tmp, "up1tr6 no roc mem");
815 l3_debug(st, tmp);
816 }
817 dev_kfree_skb(skb);
818 return;
819 }
820 } else {
821 dev_kfree_skb(skb);
822 return;
823 }
824 } else if ((mt == MT_N1_REL) || (mt == MT_N1_REL_ACK) ||
825 (mt == MT_N1_CANC_ACK) || (mt == MT_N1_CANC_REJ) ||
826 (mt == MT_N1_REG_ACK) || (mt == MT_N1_REG_REJ) ||
827 (mt == MT_N1_SUSP_ACK) || (mt == MT_N1_RES_REJ) ||
828 (mt == MT_N1_INFO)) {
829 dev_kfree_skb(skb);
830 return;
831 } else {
832 if (!(proc = new_l3_process(st, cr))) {
833 if (st->l3.debug & L3_DEB_PROTERR) {
834 sprintf(tmp, "up1tr6 no roc mem");
835 l3_debug(st, tmp);
836 }
837 dev_kfree_skb(skb);
838 return;
839 }
840 mt = MT_N1_INVALID;
841 }
842 }
843 for (i = 0; i < DATASTLN1_LEN; i++)
844 if ((mt == datastln1[i].primitive) &&
845 ((1 << proc->state) & datastln1[i].state))
846 break;
847 if (i == DATASTLN1_LEN) {
848 dev_kfree_skb(skb);
849 if (st->l3.debug & L3_DEB_STATE) {
850 sprintf(tmp, "up1tr6%sstate %d mt %x unhandled",
851 (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ",
852 proc->state, mt);
853 l3_debug(st, tmp);
854 }
855 return;
856 } else {
857 if (st->l3.debug & L3_DEB_STATE) {
858 sprintf(tmp, "up1tr6%sstate %d mt %x",
859 (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ",
860 proc->state, mt);
861 l3_debug(st, tmp);
862 }
863 datastln1[i].rout(proc, pr, skb);
864 }
865 }
866}
867
868static void
869down1tr6(struct PStack *st, int pr, void *arg)
870{
871 int i, cr;
872 struct l3_process *proc;
873 struct Channel *chan;
874 char tmp[80];
875
876 if ((DL_ESTABLISH | REQUEST)== pr) {
877 l3_msg(st, pr, NULL);
878 return;
879 } else if ((CC_SETUP | REQUEST) == pr) {
880 chan = arg;
881 cr = newcallref();
882 cr |= 0x80;
883 if (!(proc = new_l3_process(st, cr))) {
884 return;
885 } else {
886 proc->chan = chan;
887 chan->proc = proc;
888 memcpy(&proc->para.setup, &chan->setup, sizeof(setup_parm));
889 proc->callref = cr;
890 }
891 } else {
892 proc = arg;
893 }
894
895 for (i = 0; i < DOWNSTL_LEN; i++)
896 if ((pr == downstl[i].primitive) &&
897 ((1 << proc->state) & downstl[i].state))
898 break;
899 if (i == DOWNSTL_LEN) {
900 if (st->l3.debug & L3_DEB_STATE) {
901 sprintf(tmp, "down1tr6 state %d prim %d unhandled",
902 proc->state, pr);
903 l3_debug(st, tmp);
904 }
905 } else {
906 if (st->l3.debug & L3_DEB_STATE) {
907 sprintf(tmp, "down1tr6 state %d prim %d",
908 proc->state, pr);
909 l3_debug(st, tmp);
910 }
911 downstl[i].rout(proc, pr, arg);
912 }
913}
914
915static void
916man1tr6(struct PStack *st, int pr, void *arg)
917{
918 int i;
919 struct l3_process *proc = arg;
920
921 if (!proc) {
922 printk(KERN_ERR "HiSax man1tr6 without proc pr=%04x\n", pr);
923 return;
924 }
925 for (i = 0; i < MANSLLEN; i++)
926 if ((pr == manstatelist[i].primitive) &&
927 ((1 << proc->state) & manstatelist[i].state))
928 break;
929 if (i == MANSLLEN) {
930 if (st->l3.debug & L3_DEB_STATE) {
931 l3_debug(st, "cr %d man1tr6 state %d prim %d unhandled",
932 proc->callref & 0x7f, proc->state, pr);
933 }
934 } else {
935 if (st->l3.debug & L3_DEB_STATE) {
936 l3_debug(st, "cr %d man1tr6 state %d prim %d",
937 proc->callref & 0x7f, proc->state, pr);
938 }
939 manstatelist[i].rout(proc, pr, arg);
940 }
941}
942
943void
944setstack_1tr6(struct PStack *st)
945{
946 char tmp[64];
947
948 st->lli.l4l3 = down1tr6;
949 st->l2.l2l3 = up1tr6;
950 st->l3.l3ml3 = man1tr6;
951 st->l3.N303 = 0;
952
953 strcpy(tmp, l3_1tr6_revision);
954 printk(KERN_INFO "HiSax: 1TR6 Rev. %s\n", HiSax_getrev(tmp));
955}
diff --git a/drivers/isdn/hisax/l3_1tr6.h b/drivers/isdn/hisax/l3_1tr6.h
new file mode 100644
index 000000000000..43215c00cada
--- /dev/null
+++ b/drivers/isdn/hisax/l3_1tr6.h
@@ -0,0 +1,164 @@
1/* $Id: l3_1tr6.h,v 2.2.6.2 2001/09/23 22:24:49 kai Exp $
2 *
3 * German 1TR6 D-channel protocol defines
4 *
5 * This software may be used and distributed according to the terms
6 * of the GNU General Public License, incorporated herein by reference.
7 *
8 */
9
10#ifndef l3_1tr6
11#define l3_1tr6
12
13#define PROTO_DIS_N0 0x40
14#define PROTO_DIS_N1 0x41
15
16/*
17 * MsgType N0
18 */
19#define MT_N0_REG_IND 0x61
20#define MT_N0_CANC_IND 0x62
21#define MT_N0_FAC_STA 0x63
22#define MT_N0_STA_ACK 0x64
23#define MT_N0_STA_REJ 0x65
24#define MT_N0_FAC_INF 0x66
25#define MT_N0_INF_ACK 0x67
26#define MT_N0_INF_REJ 0x68
27#define MT_N0_CLOSE 0x75
28#define MT_N0_CLO_ACK 0x77
29
30/*
31 * MsgType N1
32 */
33
34#define MT_N1_ESC 0x00
35#define MT_N1_ALERT 0x01
36#define MT_N1_CALL_SENT 0x02
37#define MT_N1_CONN 0x07
38#define MT_N1_CONN_ACK 0x0F
39#define MT_N1_SETUP 0x05
40#define MT_N1_SETUP_ACK 0x0D
41#define MT_N1_RES 0x26
42#define MT_N1_RES_ACK 0x2E
43#define MT_N1_RES_REJ 0x22
44#define MT_N1_SUSP 0x25
45#define MT_N1_SUSP_ACK 0x2D
46#define MT_N1_SUSP_REJ 0x21
47#define MT_N1_USER_INFO 0x20
48#define MT_N1_DET 0x40
49#define MT_N1_DISC 0x45
50#define MT_N1_REL 0x4D
51#define MT_N1_REL_ACK 0x5A
52#define MT_N1_CANC_ACK 0x6E
53#define MT_N1_CANC_REJ 0x67
54#define MT_N1_CON_CON 0x69
55#define MT_N1_FAC 0x60
56#define MT_N1_FAC_ACK 0x68
57#define MT_N1_FAC_CAN 0x66
58#define MT_N1_FAC_REG 0x64
59#define MT_N1_FAC_REJ 0x65
60#define MT_N1_INFO 0x6D
61#define MT_N1_REG_ACK 0x6C
62#define MT_N1_REG_REJ 0x6F
63#define MT_N1_STAT 0x63
64#define MT_N1_INVALID 0
65
66/*
67 * W Elemente
68 */
69
70#define WE_Shift_F0 0x90
71#define WE_Shift_F6 0x96
72#define WE_Shift_OF0 0x98
73#define WE_Shift_OF6 0x9E
74
75#define WE0_cause 0x08
76#define WE0_connAddr 0x0C
77#define WE0_callID 0x10
78#define WE0_chanID 0x18
79#define WE0_netSpecFac 0x20
80#define WE0_display 0x28
81#define WE0_keypad 0x2C
82#define WE0_origAddr 0x6C
83#define WE0_destAddr 0x70
84#define WE0_userInfo 0x7E
85
86#define WE0_moreData 0xA0
87#define WE0_congestLevel 0xB0
88
89#define WE6_serviceInd 0x01
90#define WE6_chargingInfo 0x02
91#define WE6_date 0x03
92#define WE6_facSelect 0x05
93#define WE6_facStatus 0x06
94#define WE6_statusCalled 0x07
95#define WE6_addTransAttr 0x08
96
97/*
98 * FacCodes
99 */
100#define FAC_Sperre 0x01
101#define FAC_Sperre_All 0x02
102#define FAC_Sperre_Fern 0x03
103#define FAC_Sperre_Intl 0x04
104#define FAC_Sperre_Interk 0x05
105
106#define FAC_Forward1 0x02
107#define FAC_Forward2 0x03
108#define FAC_Konferenz 0x06
109#define FAC_GrabBchan 0x0F
110#define FAC_Reactivate 0x10
111#define FAC_Konferenz3 0x11
112#define FAC_Dienstwechsel1 0x12
113#define FAC_Dienstwechsel2 0x13
114#define FAC_NummernIdent 0x14
115#define FAC_GBG 0x15
116#define FAC_DisplayUebergeben 0x17
117#define FAC_DisplayUmgeleitet 0x1A
118#define FAC_Unterdruecke 0x1B
119#define FAC_Deactivate 0x1E
120#define FAC_Activate 0x1D
121#define FAC_SPV 0x1F
122#define FAC_Rueckwechsel 0x23
123#define FAC_Umleitung 0x24
124
125/*
126 * Cause codes
127 */
128#define CAUSE_InvCRef 0x01
129#define CAUSE_BearerNotImpl 0x03
130#define CAUSE_CIDunknown 0x07
131#define CAUSE_CIDinUse 0x08
132#define CAUSE_NoChans 0x0A
133#define CAUSE_FacNotImpl 0x10
134#define CAUSE_FacNotSubscr 0x11
135#define CAUSE_OutgoingBarred 0x20
136#define CAUSE_UserAccessBusy 0x21
137#define CAUSE_NegativeGBG 0x22
138#define CAUSE_UnknownGBG 0x23
139#define CAUSE_NoSPVknown 0x25
140#define CAUSE_DestNotObtain 0x35
141#define CAUSE_NumberChanged 0x38
142#define CAUSE_OutOfOrder 0x39
143#define CAUSE_NoUserResponse 0x3A
144#define CAUSE_UserBusy 0x3B
145#define CAUSE_IncomingBarred 0x3D
146#define CAUSE_CallRejected 0x3E
147#define CAUSE_NetworkCongestion 0x59
148#define CAUSE_RemoteUser 0x5A
149#define CAUSE_LocalProcErr 0x70
150#define CAUSE_RemoteProcErr 0x71
151#define CAUSE_RemoteUserSuspend 0x72
152#define CAUSE_RemoteUserResumed 0x73
153#define CAUSE_UserInfoDiscarded 0x7F
154
155#define T303 4000
156#define T304 20000
157#define T305 4000
158#define T308 4000
159#define T310 120000
160#define T313 4000
161#define T318 4000
162#define T319 4000
163
164#endif
diff --git a/drivers/isdn/hisax/l3dss1.c b/drivers/isdn/hisax/l3dss1.c
new file mode 100644
index 000000000000..ec92308c1efc
--- /dev/null
+++ b/drivers/isdn/hisax/l3dss1.c
@@ -0,0 +1,3238 @@
1/* $Id: l3dss1.c,v 2.32.2.3 2004/01/13 14:31:25 keil Exp $
2 *
3 * EURO/DSS1 D-channel protocol
4 *
5 * German 1TR6 D-channel protocol
6 *
7 * Author Karsten Keil
8 * based on the teles driver from Jan den Ouden
9 * Copyright by Karsten Keil <keil@isdn4linux.de>
10 *
11 * This software may be used and distributed according to the terms
12 * of the GNU General Public License, incorporated herein by reference.
13 *
14 * For changes and modifications please read
15 * Documentation/isdn/HiSax.cert
16 *
17 * Thanks to Jan den Ouden
18 * Fritz Elfert
19 *
20 */
21
22#include "hisax.h"
23#include "isdnl3.h"
24#include "l3dss1.h"
25#include <linux/ctype.h>
26#include <linux/config.h>
27
28extern char *HiSax_getrev(const char *revision);
29const char *dss1_revision = "$Revision: 2.32.2.3 $";
30
31#define EXT_BEARER_CAPS 1
32
33#define MsgHead(ptr, cref, mty) \
34 *ptr++ = 0x8; \
35 if (cref == -1) { \
36 *ptr++ = 0x0; \
37 } else { \
38 *ptr++ = 0x1; \
39 *ptr++ = cref^0x80; \
40 } \
41 *ptr++ = mty
42
43
44/**********************************************/
45/* get a new invoke id for remote operations. */
46/* Only a return value != 0 is valid */
47/**********************************************/
48static unsigned char new_invoke_id(struct PStack *p)
49{
50 unsigned char retval;
51 int i;
52
53 i = 32; /* maximum search depth */
54
55 retval = p->prot.dss1.last_invoke_id + 1; /* try new id */
56 while ((i) && (p->prot.dss1.invoke_used[retval >> 3] == 0xFF)) {
57 p->prot.dss1.last_invoke_id = (retval & 0xF8) + 8;
58 i--;
59 }
60 if (i) {
61 while (p->prot.dss1.invoke_used[retval >> 3] & (1 << (retval & 7)))
62 retval++;
63 } else
64 retval = 0;
65 p->prot.dss1.last_invoke_id = retval;
66 p->prot.dss1.invoke_used[retval >> 3] |= (1 << (retval & 7));
67 return(retval);
68} /* new_invoke_id */
69
70/*************************/
71/* free a used invoke id */
72/*************************/
73static void free_invoke_id(struct PStack *p, unsigned char id)
74{
75
76 if (!id) return; /* 0 = invalid value */
77
78 p->prot.dss1.invoke_used[id >> 3] &= ~(1 << (id & 7));
79} /* free_invoke_id */
80
81
82/**********************************************************/
83/* create a new l3 process and fill in dss1 specific data */
84/**********************************************************/
85static struct l3_process
86*dss1_new_l3_process(struct PStack *st, int cr)
87{ struct l3_process *proc;
88
89 if (!(proc = new_l3_process(st, cr)))
90 return(NULL);
91
92 proc->prot.dss1.invoke_id = 0;
93 proc->prot.dss1.remote_operation = 0;
94 proc->prot.dss1.uus1_data[0] = '\0';
95
96 return(proc);
97} /* dss1_new_l3_process */
98
99/************************************************/
100/* free a l3 process and all dss1 specific data */
101/************************************************/
102static void
103dss1_release_l3_process(struct l3_process *p)
104{
105 free_invoke_id(p->st,p->prot.dss1.invoke_id);
106 release_l3_process(p);
107} /* dss1_release_l3_process */
108
109/********************************************************/
110/* search a process with invoke id id and dummy callref */
111/********************************************************/
112static struct l3_process *
113l3dss1_search_dummy_proc(struct PStack *st, int id)
114{ struct l3_process *pc = st->l3.proc; /* start of processes */
115
116 if (!id) return(NULL);
117
118 while (pc)
119 { if ((pc->callref == -1) && (pc->prot.dss1.invoke_id == id))
120 return(pc);
121 pc = pc->next;
122 }
123 return(NULL);
124} /* l3dss1_search_dummy_proc */
125
126/*******************************************************************/
127/* called when a facility message with a dummy callref is received */
128/* and a return result is delivered. id specifies the invoke id. */
129/*******************************************************************/
130static void
131l3dss1_dummy_return_result(struct PStack *st, int id, u_char *p, u_char nlen)
132{ isdn_ctrl ic;
133 struct IsdnCardState *cs;
134 struct l3_process *pc = NULL;
135
136 if ((pc = l3dss1_search_dummy_proc(st, id)))
137 { L3DelTimer(&pc->timer); /* remove timer */
138
139 cs = pc->st->l1.hardware;
140 ic.driver = cs->myid;
141 ic.command = ISDN_STAT_PROT;
142 ic.arg = DSS1_STAT_INVOKE_RES;
143 ic.parm.dss1_io.hl_id = pc->prot.dss1.invoke_id;
144 ic.parm.dss1_io.ll_id = pc->prot.dss1.ll_id;
145 ic.parm.dss1_io.proc = pc->prot.dss1.proc;
146 ic.parm.dss1_io.timeout= 0;
147 ic.parm.dss1_io.datalen = nlen;
148 ic.parm.dss1_io.data = p;
149 free_invoke_id(pc->st, pc->prot.dss1.invoke_id);
150 pc->prot.dss1.invoke_id = 0; /* reset id */
151
152 cs->iif.statcallb(&ic);
153 dss1_release_l3_process(pc);
154 }
155 else
156 l3_debug(st, "dummy return result id=0x%x result len=%d",id,nlen);
157} /* l3dss1_dummy_return_result */
158
159/*******************************************************************/
160/* called when a facility message with a dummy callref is received */
161/* and a return error is delivered. id specifies the invoke id. */
162/*******************************************************************/
163static void
164l3dss1_dummy_error_return(struct PStack *st, int id, ulong error)
165{ isdn_ctrl ic;
166 struct IsdnCardState *cs;
167 struct l3_process *pc = NULL;
168
169 if ((pc = l3dss1_search_dummy_proc(st, id)))
170 { L3DelTimer(&pc->timer); /* remove timer */
171
172 cs = pc->st->l1.hardware;
173 ic.driver = cs->myid;
174 ic.command = ISDN_STAT_PROT;
175 ic.arg = DSS1_STAT_INVOKE_ERR;
176 ic.parm.dss1_io.hl_id = pc->prot.dss1.invoke_id;
177 ic.parm.dss1_io.ll_id = pc->prot.dss1.ll_id;
178 ic.parm.dss1_io.proc = pc->prot.dss1.proc;
179 ic.parm.dss1_io.timeout= error;
180 ic.parm.dss1_io.datalen = 0;
181 ic.parm.dss1_io.data = NULL;
182 free_invoke_id(pc->st, pc->prot.dss1.invoke_id);
183 pc->prot.dss1.invoke_id = 0; /* reset id */
184
185 cs->iif.statcallb(&ic);
186 dss1_release_l3_process(pc);
187 }
188 else
189 l3_debug(st, "dummy return error id=0x%x error=0x%lx",id,error);
190} /* l3dss1_error_return */
191
192/*******************************************************************/
193/* called when a facility message with a dummy callref is received */
194/* and a invoke is delivered. id specifies the invoke id. */
195/*******************************************************************/
196static void
197l3dss1_dummy_invoke(struct PStack *st, int cr, int id,
198 int ident, u_char *p, u_char nlen)
199{ isdn_ctrl ic;
200 struct IsdnCardState *cs;
201
202 l3_debug(st, "dummy invoke %s id=0x%x ident=0x%x datalen=%d",
203 (cr == -1) ? "local" : "broadcast",id,ident,nlen);
204 if (cr >= -1) return; /* ignore local data */
205
206 cs = st->l1.hardware;
207 ic.driver = cs->myid;
208 ic.command = ISDN_STAT_PROT;
209 ic.arg = DSS1_STAT_INVOKE_BRD;
210 ic.parm.dss1_io.hl_id = id;
211 ic.parm.dss1_io.ll_id = 0;
212 ic.parm.dss1_io.proc = ident;
213 ic.parm.dss1_io.timeout= 0;
214 ic.parm.dss1_io.datalen = nlen;
215 ic.parm.dss1_io.data = p;
216
217 cs->iif.statcallb(&ic);
218} /* l3dss1_dummy_invoke */
219
220static void
221l3dss1_parse_facility(struct PStack *st, struct l3_process *pc,
222 int cr, u_char * p)
223{
224 int qd_len = 0;
225 unsigned char nlen = 0, ilen, cp_tag;
226 int ident, id;
227 ulong err_ret;
228
229 if (pc)
230 st = pc->st; /* valid Stack */
231 else
232 if ((!st) || (cr >= 0)) return; /* neither pc nor st specified */
233
234 p++;
235 qd_len = *p++;
236 if (qd_len == 0) {
237 l3_debug(st, "qd_len == 0");
238 return;
239 }
240 if ((*p & 0x1F) != 0x11) { /* Service discriminator, supplementary service */
241 l3_debug(st, "supplementary service != 0x11");
242 return;
243 }
244 while (qd_len > 0 && !(*p & 0x80)) { /* extension ? */
245 p++;
246 qd_len--;
247 }
248 if (qd_len < 2) {
249 l3_debug(st, "qd_len < 2");
250 return;
251 }
252 p++;
253 qd_len--;
254 if ((*p & 0xE0) != 0xA0) { /* class and form */
255 l3_debug(st, "class and form != 0xA0");
256 return;
257 }
258
259 cp_tag = *p & 0x1F; /* remember tag value */
260
261 p++;
262 qd_len--;
263 if (qd_len < 1)
264 { l3_debug(st, "qd_len < 1");
265 return;
266 }
267 if (*p & 0x80)
268 { /* length format indefinite or limited */
269 nlen = *p++ & 0x7F; /* number of len bytes or indefinite */
270 if ((qd_len-- < ((!nlen) ? 3 : (1 + nlen))) ||
271 (nlen > 1))
272 { l3_debug(st, "length format error or not implemented");
273 return;
274 }
275 if (nlen == 1)
276 { nlen = *p++; /* complete length */
277 qd_len--;
278 }
279 else
280 { qd_len -= 2; /* trailing null bytes */
281 if ((*(p+qd_len)) || (*(p+qd_len+1)))
282 { l3_debug(st,"length format indefinite error");
283 return;
284 }
285 nlen = qd_len;
286 }
287 }
288 else
289 { nlen = *p++;
290 qd_len--;
291 }
292 if (qd_len < nlen)
293 { l3_debug(st, "qd_len < nlen");
294 return;
295 }
296 qd_len -= nlen;
297
298 if (nlen < 2)
299 { l3_debug(st, "nlen < 2");
300 return;
301 }
302 if (*p != 0x02)
303 { /* invoke identifier tag */
304 l3_debug(st, "invoke identifier tag !=0x02");
305 return;
306 }
307 p++;
308 nlen--;
309 if (*p & 0x80)
310 { /* length format */
311 l3_debug(st, "invoke id length format 2");
312 return;
313 }
314 ilen = *p++;
315 nlen--;
316 if (ilen > nlen || ilen == 0)
317 { l3_debug(st, "ilen > nlen || ilen == 0");
318 return;
319 }
320 nlen -= ilen;
321 id = 0;
322 while (ilen > 0)
323 { id = (id << 8) | (*p++ & 0xFF); /* invoke identifier */
324 ilen--;
325 }
326
327 switch (cp_tag) { /* component tag */
328 case 1: /* invoke */
329 if (nlen < 2) {
330 l3_debug(st, "nlen < 2 22");
331 return;
332 }
333 if (*p != 0x02) { /* operation value */
334 l3_debug(st, "operation value !=0x02");
335 return;
336 }
337 p++;
338 nlen--;
339 ilen = *p++;
340 nlen--;
341 if (ilen > nlen || ilen == 0) {
342 l3_debug(st, "ilen > nlen || ilen == 0 22");
343 return;
344 }
345 nlen -= ilen;
346 ident = 0;
347 while (ilen > 0) {
348 ident = (ident << 8) | (*p++ & 0xFF);
349 ilen--;
350 }
351
352 if (!pc)
353 { l3dss1_dummy_invoke(st, cr, id, ident, p, nlen);
354 return;
355 }
356#if HISAX_DE_AOC
357 {
358
359#define FOO1(s,a,b) \
360 while(nlen > 1) { \
361 int ilen = p[1]; \
362 if(nlen < ilen+2) { \
363 l3_debug(st, "FOO1 nlen < ilen+2"); \
364 return; \
365 } \
366 nlen -= ilen+2; \
367 if((*p & 0xFF) == (a)) { \
368 int nlen = ilen; \
369 p += 2; \
370 b; \
371 } else { \
372 p += ilen+2; \
373 } \
374 }
375
376 switch (ident) {
377 case 0x22: /* during */
378 FOO1("1A", 0x30, FOO1("1C", 0xA1, FOO1("1D", 0x30, FOO1("1E", 0x02, ( {
379 ident = 0;
380 nlen = (nlen)?nlen:0; /* Make gcc happy */
381 while (ilen > 0) {
382 ident = (ident << 8) | *p++;
383 ilen--;
384 }
385 if (ident > pc->para.chargeinfo) {
386 pc->para.chargeinfo = ident;
387 st->l3.l3l4(st, CC_CHARGE | INDICATION, pc);
388 }
389 if (st->l3.debug & L3_DEB_CHARGE) {
390 if (*(p + 2) == 0) {
391 l3_debug(st, "charging info during %d", pc->para.chargeinfo);
392 }
393 else {
394 l3_debug(st, "charging info final %d", pc->para.chargeinfo);
395 }
396 }
397 }
398 )))))
399 break;
400 case 0x24: /* final */
401 FOO1("2A", 0x30, FOO1("2B", 0x30, FOO1("2C", 0xA1, FOO1("2D", 0x30, FOO1("2E", 0x02, ( {
402 ident = 0;
403 nlen = (nlen)?nlen:0; /* Make gcc happy */
404 while (ilen > 0) {
405 ident = (ident << 8) | *p++;
406 ilen--;
407 }
408 if (ident > pc->para.chargeinfo) {
409 pc->para.chargeinfo = ident;
410 st->l3.l3l4(st, CC_CHARGE | INDICATION, pc);
411 }
412 if (st->l3.debug & L3_DEB_CHARGE) {
413 l3_debug(st, "charging info final %d", pc->para.chargeinfo);
414 }
415 }
416 ))))))
417 break;
418 default:
419 l3_debug(st, "invoke break invalid ident %02x",ident);
420 break;
421 }
422#undef FOO1
423
424 }
425#else /* not HISAX_DE_AOC */
426 l3_debug(st, "invoke break");
427#endif /* not HISAX_DE_AOC */
428 break;
429 case 2: /* return result */
430 /* if no process available handle separately */
431 if (!pc)
432 { if (cr == -1)
433 l3dss1_dummy_return_result(st, id, p, nlen);
434 return;
435 }
436 if ((pc->prot.dss1.invoke_id) && (pc->prot.dss1.invoke_id == id))
437 { /* Diversion successful */
438 free_invoke_id(st,pc->prot.dss1.invoke_id);
439 pc->prot.dss1.remote_result = 0; /* success */
440 pc->prot.dss1.invoke_id = 0;
441 pc->redir_result = pc->prot.dss1.remote_result;
442 st->l3.l3l4(st, CC_REDIR | INDICATION, pc); } /* Diversion successful */
443 else
444 l3_debug(st,"return error unknown identifier");
445 break;
446 case 3: /* return error */
447 err_ret = 0;
448 if (nlen < 2)
449 { l3_debug(st, "return error nlen < 2");
450 return;
451 }
452 if (*p != 0x02)
453 { /* result tag */
454 l3_debug(st, "invoke error tag !=0x02");
455 return;
456 }
457 p++;
458 nlen--;
459 if (*p > 4)
460 { /* length format */
461 l3_debug(st, "invoke return errlen > 4 ");
462 return;
463 }
464 ilen = *p++;
465 nlen--;
466 if (ilen > nlen || ilen == 0)
467 { l3_debug(st, "error return ilen > nlen || ilen == 0");
468 return;
469 }
470 nlen -= ilen;
471 while (ilen > 0)
472 { err_ret = (err_ret << 8) | (*p++ & 0xFF); /* error value */
473 ilen--;
474 }
475 /* if no process available handle separately */
476 if (!pc)
477 { if (cr == -1)
478 l3dss1_dummy_error_return(st, id, err_ret);
479 return;
480 }
481 if ((pc->prot.dss1.invoke_id) && (pc->prot.dss1.invoke_id == id))
482 { /* Deflection error */
483 free_invoke_id(st,pc->prot.dss1.invoke_id);
484 pc->prot.dss1.remote_result = err_ret; /* result */
485 pc->prot.dss1.invoke_id = 0;
486 pc->redir_result = pc->prot.dss1.remote_result;
487 st->l3.l3l4(st, CC_REDIR | INDICATION, pc);
488 } /* Deflection error */
489 else
490 l3_debug(st,"return result unknown identifier");
491 break;
492 default:
493 l3_debug(st, "facility default break tag=0x%02x",cp_tag);
494 break;
495 }
496}
497
498static void
499l3dss1_message(struct l3_process *pc, u_char mt)
500{
501 struct sk_buff *skb;
502 u_char *p;
503
504 if (!(skb = l3_alloc_skb(4)))
505 return;
506 p = skb_put(skb, 4);
507 MsgHead(p, pc->callref, mt);
508 l3_msg(pc->st, DL_DATA | REQUEST, skb);
509}
510
511static void
512l3dss1_message_cause(struct l3_process *pc, u_char mt, u_char cause)
513{
514 struct sk_buff *skb;
515 u_char tmp[16];
516 u_char *p = tmp;
517 int l;
518
519 MsgHead(p, pc->callref, mt);
520 *p++ = IE_CAUSE;
521 *p++ = 0x2;
522 *p++ = 0x80;
523 *p++ = cause | 0x80;
524
525 l = p - tmp;
526 if (!(skb = l3_alloc_skb(l)))
527 return;
528 memcpy(skb_put(skb, l), tmp, l);
529 l3_msg(pc->st, DL_DATA | REQUEST, skb);
530}
531
532static void
533l3dss1_status_send(struct l3_process *pc, u_char pr, void *arg)
534{
535 u_char tmp[16];
536 u_char *p = tmp;
537 int l;
538 struct sk_buff *skb;
539
540 MsgHead(p, pc->callref, MT_STATUS);
541
542 *p++ = IE_CAUSE;
543 *p++ = 0x2;
544 *p++ = 0x80;
545 *p++ = pc->para.cause | 0x80;
546
547 *p++ = IE_CALL_STATE;
548 *p++ = 0x1;
549 *p++ = pc->state & 0x3f;
550
551 l = p - tmp;
552 if (!(skb = l3_alloc_skb(l)))
553 return;
554 memcpy(skb_put(skb, l), tmp, l);
555 l3_msg(pc->st, DL_DATA | REQUEST, skb);
556}
557
558static void
559l3dss1_msg_without_setup(struct l3_process *pc, u_char pr, void *arg)
560{
561 /* This routine is called if here was no SETUP made (checks in dss1up and in
562 * l3dss1_setup) and a RELEASE_COMPLETE have to be sent with an error code
563 * MT_STATUS_ENQUIRE in the NULL state is handled too
564 */
565 u_char tmp[16];
566 u_char *p = tmp;
567 int l;
568 struct sk_buff *skb;
569
570 switch (pc->para.cause) {
571 case 81: /* invalid callreference */
572 case 88: /* incomp destination */
573 case 96: /* mandory IE missing */
574 case 100: /* invalid IE contents */
575 case 101: /* incompatible Callstate */
576 MsgHead(p, pc->callref, MT_RELEASE_COMPLETE);
577 *p++ = IE_CAUSE;
578 *p++ = 0x2;
579 *p++ = 0x80;
580 *p++ = pc->para.cause | 0x80;
581 break;
582 default:
583 printk(KERN_ERR "HiSax l3dss1_msg_without_setup wrong cause %d\n",
584 pc->para.cause);
585 return;
586 }
587 l = p - tmp;
588 if (!(skb = l3_alloc_skb(l)))
589 return;
590 memcpy(skb_put(skb, l), tmp, l);
591 l3_msg(pc->st, DL_DATA | REQUEST, skb);
592 dss1_release_l3_process(pc);
593}
594
595static int ie_ALERTING[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1,
596 IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, IE_HLC,
597 IE_USER_USER, -1};
598static int ie_CALL_PROCEEDING[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1,
599 IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_HLC, -1};
600static int ie_CONNECT[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1,
601 IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_DATE, IE_SIGNAL,
602 IE_CONNECT_PN, IE_CONNECT_SUB, IE_LLC, IE_HLC, IE_USER_USER, -1};
603static int ie_CONNECT_ACKNOWLEDGE[] = {IE_CHANNEL_ID, IE_DISPLAY, IE_SIGNAL, -1};
604static int ie_DISCONNECT[] = {IE_CAUSE | IE_MANDATORY, IE_FACILITY,
605 IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, IE_USER_USER, -1};
606static int ie_INFORMATION[] = {IE_COMPLETE, IE_DISPLAY, IE_KEYPAD, IE_SIGNAL,
607 IE_CALLED_PN, -1};
608static int ie_NOTIFY[] = {IE_BEARER, IE_NOTIFY | IE_MANDATORY, IE_DISPLAY, -1};
609static int ie_PROGRESS[] = {IE_BEARER, IE_CAUSE, IE_FACILITY, IE_PROGRESS |
610 IE_MANDATORY, IE_DISPLAY, IE_HLC, IE_USER_USER, -1};
611static int ie_RELEASE[] = {IE_CAUSE | IE_MANDATORY_1, IE_FACILITY, IE_DISPLAY,
612 IE_SIGNAL, IE_USER_USER, -1};
613/* a RELEASE_COMPLETE with errors don't require special actions
614static int ie_RELEASE_COMPLETE[] = {IE_CAUSE | IE_MANDATORY_1, IE_DISPLAY, IE_SIGNAL, IE_USER_USER, -1};
615*/
616static int ie_RESUME_ACKNOWLEDGE[] = {IE_CHANNEL_ID| IE_MANDATORY, IE_FACILITY,
617 IE_DISPLAY, -1};
618static int ie_RESUME_REJECT[] = {IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1};
619static int ie_SETUP[] = {IE_COMPLETE, IE_BEARER | IE_MANDATORY,
620 IE_CHANNEL_ID| IE_MANDATORY, IE_FACILITY, IE_PROGRESS,
621 IE_NET_FAC, IE_DISPLAY, IE_KEYPAD, IE_SIGNAL, IE_CALLING_PN,
622 IE_CALLING_SUB, IE_CALLED_PN, IE_CALLED_SUB, IE_REDIR_NR,
623 IE_LLC, IE_HLC, IE_USER_USER, -1};
624static int ie_SETUP_ACKNOWLEDGE[] = {IE_CHANNEL_ID | IE_MANDATORY, IE_FACILITY,
625 IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, -1};
626static int ie_STATUS[] = {IE_CAUSE | IE_MANDATORY, IE_CALL_STATE |
627 IE_MANDATORY, IE_DISPLAY, -1};
628static int ie_STATUS_ENQUIRY[] = {IE_DISPLAY, -1};
629static int ie_SUSPEND_ACKNOWLEDGE[] = {IE_DISPLAY, IE_FACILITY, -1};
630static int ie_SUSPEND_REJECT[] = {IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1};
631/* not used
632 * static int ie_CONGESTION_CONTROL[] = {IE_CONGESTION | IE_MANDATORY,
633 * IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1};
634 * static int ie_USER_INFORMATION[] = {IE_MORE_DATA, IE_USER_USER | IE_MANDATORY, -1};
635 * static int ie_RESTART[] = {IE_CHANNEL_ID, IE_DISPLAY, IE_RESTART_IND |
636 * IE_MANDATORY, -1};
637 */
638static int ie_FACILITY[] = {IE_FACILITY | IE_MANDATORY, IE_DISPLAY, -1};
639static int comp_required[] = {1,2,3,5,6,7,9,10,11,14,15,-1};
640static int l3_valid_states[] = {0,1,2,3,4,6,7,8,9,10,11,12,15,17,19,25,-1};
641
642struct ie_len {
643 int ie;
644 int len;
645};
646
647static
648struct ie_len max_ie_len[] = {
649 {IE_SEGMENT, 4},
650 {IE_BEARER, 12},
651 {IE_CAUSE, 32},
652 {IE_CALL_ID, 10},
653 {IE_CALL_STATE, 3},
654 {IE_CHANNEL_ID, 34},
655 {IE_FACILITY, 255},
656 {IE_PROGRESS, 4},
657 {IE_NET_FAC, 255},
658 {IE_NOTIFY, 3},
659 {IE_DISPLAY, 82},
660 {IE_DATE, 8},
661 {IE_KEYPAD, 34},
662 {IE_SIGNAL, 3},
663 {IE_INFORATE, 6},
664 {IE_E2E_TDELAY, 11},
665 {IE_TDELAY_SEL, 5},
666 {IE_PACK_BINPARA, 3},
667 {IE_PACK_WINSIZE, 4},
668 {IE_PACK_SIZE, 4},
669 {IE_CUG, 7},
670 {IE_REV_CHARGE, 3},
671 {IE_CALLING_PN, 24},
672 {IE_CALLING_SUB, 23},
673 {IE_CALLED_PN, 24},
674 {IE_CALLED_SUB, 23},
675 {IE_REDIR_NR, 255},
676 {IE_TRANS_SEL, 255},
677 {IE_RESTART_IND, 3},
678 {IE_LLC, 18},
679 {IE_HLC, 5},
680 {IE_USER_USER, 131},
681 {-1,0},
682};
683
684static int
685getmax_ie_len(u_char ie) {
686 int i = 0;
687 while (max_ie_len[i].ie != -1) {
688 if (max_ie_len[i].ie == ie)
689 return(max_ie_len[i].len);
690 i++;
691 }
692 return(255);
693}
694
695static int
696ie_in_set(struct l3_process *pc, u_char ie, int *checklist) {
697 int ret = 1;
698
699 while (*checklist != -1) {
700 if ((*checklist & 0xff) == ie) {
701 if (ie & 0x80)
702 return(-ret);
703 else
704 return(ret);
705 }
706 ret++;
707 checklist++;
708 }
709 return(0);
710}
711
712static int
713check_infoelements(struct l3_process *pc, struct sk_buff *skb, int *checklist)
714{
715 int *cl = checklist;
716 u_char mt;
717 u_char *p, ie;
718 int l, newpos, oldpos;
719 int err_seq = 0, err_len = 0, err_compr = 0, err_ureg = 0;
720 u_char codeset = 0;
721 u_char old_codeset = 0;
722 u_char codelock = 1;
723
724 p = skb->data;
725 /* skip cr */
726 p++;
727 l = (*p++) & 0xf;
728 p += l;
729 mt = *p++;
730 oldpos = 0;
731 while ((p - skb->data) < skb->len) {
732 if ((*p & 0xf0) == 0x90) { /* shift codeset */
733 old_codeset = codeset;
734 codeset = *p & 7;
735 if (*p & 0x08)
736 codelock = 0;
737 else
738 codelock = 1;
739 if (pc->debug & L3_DEB_CHECK)
740 l3_debug(pc->st, "check IE shift%scodeset %d->%d",
741 codelock ? " locking ": " ", old_codeset, codeset);
742 p++;
743 continue;
744 }
745 if (!codeset) { /* only codeset 0 */
746 if ((newpos = ie_in_set(pc, *p, cl))) {
747 if (newpos > 0) {
748 if (newpos < oldpos)
749 err_seq++;
750 else
751 oldpos = newpos;
752 }
753 } else {
754 if (ie_in_set(pc, *p, comp_required))
755 err_compr++;
756 else
757 err_ureg++;
758 }
759 }
760 ie = *p++;
761 if (ie & 0x80) {
762 l = 1;
763 } else {
764 l = *p++;
765 p += l;
766 l += 2;
767 }
768 if (!codeset && (l > getmax_ie_len(ie)))
769 err_len++;
770 if (!codelock) {
771 if (pc->debug & L3_DEB_CHECK)
772 l3_debug(pc->st, "check IE shift back codeset %d->%d",
773 codeset, old_codeset);
774 codeset = old_codeset;
775 codelock = 1;
776 }
777 }
778 if (err_compr | err_ureg | err_len | err_seq) {
779 if (pc->debug & L3_DEB_CHECK)
780 l3_debug(pc->st, "check IE MT(%x) %d/%d/%d/%d",
781 mt, err_compr, err_ureg, err_len, err_seq);
782 if (err_compr)
783 return(ERR_IE_COMPREHENSION);
784 if (err_ureg)
785 return(ERR_IE_UNRECOGNIZED);
786 if (err_len)
787 return(ERR_IE_LENGTH);
788 if (err_seq)
789 return(ERR_IE_SEQUENCE);
790 }
791 return(0);
792}
793
794/* verify if a message type exists and contain no IE error */
795static int
796l3dss1_check_messagetype_validity(struct l3_process *pc, int mt, void *arg)
797{
798 switch (mt) {
799 case MT_ALERTING:
800 case MT_CALL_PROCEEDING:
801 case MT_CONNECT:
802 case MT_CONNECT_ACKNOWLEDGE:
803 case MT_DISCONNECT:
804 case MT_INFORMATION:
805 case MT_FACILITY:
806 case MT_NOTIFY:
807 case MT_PROGRESS:
808 case MT_RELEASE:
809 case MT_RELEASE_COMPLETE:
810 case MT_SETUP:
811 case MT_SETUP_ACKNOWLEDGE:
812 case MT_RESUME_ACKNOWLEDGE:
813 case MT_RESUME_REJECT:
814 case MT_SUSPEND_ACKNOWLEDGE:
815 case MT_SUSPEND_REJECT:
816 case MT_USER_INFORMATION:
817 case MT_RESTART:
818 case MT_RESTART_ACKNOWLEDGE:
819 case MT_CONGESTION_CONTROL:
820 case MT_STATUS:
821 case MT_STATUS_ENQUIRY:
822 if (pc->debug & L3_DEB_CHECK)
823 l3_debug(pc->st, "l3dss1_check_messagetype_validity mt(%x) OK", mt);
824 break;
825 case MT_RESUME: /* RESUME only in user->net */
826 case MT_SUSPEND: /* SUSPEND only in user->net */
827 default:
828 if (pc->debug & (L3_DEB_CHECK | L3_DEB_WARN))
829 l3_debug(pc->st, "l3dss1_check_messagetype_validity mt(%x) fail", mt);
830 pc->para.cause = 97;
831 l3dss1_status_send(pc, 0, NULL);
832 return(1);
833 }
834 return(0);
835}
836
837static void
838l3dss1_std_ie_err(struct l3_process *pc, int ret) {
839
840 if (pc->debug & L3_DEB_CHECK)
841 l3_debug(pc->st, "check_infoelements ret %d", ret);
842 switch(ret) {
843 case 0:
844 break;
845 case ERR_IE_COMPREHENSION:
846 pc->para.cause = 96;
847 l3dss1_status_send(pc, 0, NULL);
848 break;
849 case ERR_IE_UNRECOGNIZED:
850 pc->para.cause = 99;
851 l3dss1_status_send(pc, 0, NULL);
852 break;
853 case ERR_IE_LENGTH:
854 pc->para.cause = 100;
855 l3dss1_status_send(pc, 0, NULL);
856 break;
857 case ERR_IE_SEQUENCE:
858 default:
859 break;
860 }
861}
862
863static int
864l3dss1_get_channel_id(struct l3_process *pc, struct sk_buff *skb) {
865 u_char *p;
866
867 p = skb->data;
868 if ((p = findie(p, skb->len, IE_CHANNEL_ID, 0))) {
869 p++;
870 if (*p != 1) { /* len for BRI = 1 */
871 if (pc->debug & L3_DEB_WARN)
872 l3_debug(pc->st, "wrong chid len %d", *p);
873 return (-2);
874 }
875 p++;
876 if (*p & 0x60) { /* only base rate interface */
877 if (pc->debug & L3_DEB_WARN)
878 l3_debug(pc->st, "wrong chid %x", *p);
879 return (-3);
880 }
881 return(*p & 0x3);
882 } else
883 return(-1);
884}
885
886static int
887l3dss1_get_cause(struct l3_process *pc, struct sk_buff *skb) {
888 u_char l, i=0;
889 u_char *p;
890
891 p = skb->data;
892 pc->para.cause = 31;
893 pc->para.loc = 0;
894 if ((p = findie(p, skb->len, IE_CAUSE, 0))) {
895 p++;
896 l = *p++;
897 if (l>30)
898 return(1);
899 if (l) {
900 pc->para.loc = *p++;
901 l--;
902 } else {
903 return(2);
904 }
905 if (l && !(pc->para.loc & 0x80)) {
906 l--;
907 p++; /* skip recommendation */
908 }
909 if (l) {
910 pc->para.cause = *p++;
911 l--;
912 if (!(pc->para.cause & 0x80))
913 return(3);
914 } else
915 return(4);
916 while (l && (i<6)) {
917 pc->para.diag[i++] = *p++;
918 l--;
919 }
920 } else
921 return(-1);
922 return(0);
923}
924
925static void
926l3dss1_msg_with_uus(struct l3_process *pc, u_char cmd)
927{
928 struct sk_buff *skb;
929 u_char tmp[16+40];
930 u_char *p = tmp;
931 int l;
932
933 MsgHead(p, pc->callref, cmd);
934
935 if (pc->prot.dss1.uus1_data[0])
936 { *p++ = IE_USER_USER; /* UUS info element */
937 *p++ = strlen(pc->prot.dss1.uus1_data) + 1;
938 *p++ = 0x04; /* IA5 chars */
939 strcpy(p,pc->prot.dss1.uus1_data);
940 p += strlen(pc->prot.dss1.uus1_data);
941 pc->prot.dss1.uus1_data[0] = '\0';
942 }
943
944 l = p - tmp;
945 if (!(skb = l3_alloc_skb(l)))
946 return;
947 memcpy(skb_put(skb, l), tmp, l);
948 l3_msg(pc->st, DL_DATA | REQUEST, skb);
949} /* l3dss1_msg_with_uus */
950
951static void
952l3dss1_release_req(struct l3_process *pc, u_char pr, void *arg)
953{
954 StopAllL3Timer(pc);
955 newl3state(pc, 19);
956 if (!pc->prot.dss1.uus1_data[0])
957 l3dss1_message(pc, MT_RELEASE);
958 else
959 l3dss1_msg_with_uus(pc, MT_RELEASE);
960 L3AddTimer(&pc->timer, T308, CC_T308_1);
961}
962
963static void
964l3dss1_release_cmpl(struct l3_process *pc, u_char pr, void *arg)
965{
966 struct sk_buff *skb = arg;
967 int ret;
968
969 if ((ret = l3dss1_get_cause(pc, skb))>0) {
970 if (pc->debug & L3_DEB_WARN)
971 l3_debug(pc->st, "RELCMPL get_cause ret(%d)",ret);
972 } else if (ret < 0)
973 pc->para.cause = NO_CAUSE;
974 StopAllL3Timer(pc);
975 newl3state(pc, 0);
976 pc->st->l3.l3l4(pc->st, CC_RELEASE | CONFIRM, pc);
977 dss1_release_l3_process(pc);
978}
979
980#if EXT_BEARER_CAPS
981
982static u_char *
983EncodeASyncParams(u_char * p, u_char si2)
984{ // 7c 06 88 90 21 42 00 bb
985
986 p[0] = 0;
987 p[1] = 0x40; // Intermediate rate: 16 kbit/s jj 2000.02.19
988 p[2] = 0x80;
989 if (si2 & 32) // 7 data bits
990
991 p[2] += 16;
992 else // 8 data bits
993
994 p[2] += 24;
995
996 if (si2 & 16) // 2 stop bits
997
998 p[2] += 96;
999 else // 1 stop bit
1000
1001 p[2] += 32;
1002
1003 if (si2 & 8) // even parity
1004
1005 p[2] += 2;
1006 else // no parity
1007
1008 p[2] += 3;
1009
1010 switch (si2 & 0x07) {
1011 case 0:
1012 p[0] = 66; // 1200 bit/s
1013
1014 break;
1015 case 1:
1016 p[0] = 88; // 1200/75 bit/s
1017
1018 break;
1019 case 2:
1020 p[0] = 87; // 75/1200 bit/s
1021
1022 break;
1023 case 3:
1024 p[0] = 67; // 2400 bit/s
1025
1026 break;
1027 case 4:
1028 p[0] = 69; // 4800 bit/s
1029
1030 break;
1031 case 5:
1032 p[0] = 72; // 9600 bit/s
1033
1034 break;
1035 case 6:
1036 p[0] = 73; // 14400 bit/s
1037
1038 break;
1039 case 7:
1040 p[0] = 75; // 19200 bit/s
1041
1042 break;
1043 }
1044 return p + 3;
1045}
1046
1047static u_char
1048EncodeSyncParams(u_char si2, u_char ai)
1049{
1050
1051 switch (si2) {
1052 case 0:
1053 return ai + 2; // 1200 bit/s
1054
1055 case 1:
1056 return ai + 24; // 1200/75 bit/s
1057
1058 case 2:
1059 return ai + 23; // 75/1200 bit/s
1060
1061 case 3:
1062 return ai + 3; // 2400 bit/s
1063
1064 case 4:
1065 return ai + 5; // 4800 bit/s
1066
1067 case 5:
1068 return ai + 8; // 9600 bit/s
1069
1070 case 6:
1071 return ai + 9; // 14400 bit/s
1072
1073 case 7:
1074 return ai + 11; // 19200 bit/s
1075
1076 case 8:
1077 return ai + 14; // 48000 bit/s
1078
1079 case 9:
1080 return ai + 15; // 56000 bit/s
1081
1082 case 15:
1083 return ai + 40; // negotiate bit/s
1084
1085 default:
1086 break;
1087 }
1088 return ai;
1089}
1090
1091
1092static u_char
1093DecodeASyncParams(u_char si2, u_char * p)
1094{
1095 u_char info;
1096
1097 switch (p[5]) {
1098 case 66: // 1200 bit/s
1099
1100 break; // si2 don't change
1101
1102 case 88: // 1200/75 bit/s
1103
1104 si2 += 1;
1105 break;
1106 case 87: // 75/1200 bit/s
1107
1108 si2 += 2;
1109 break;
1110 case 67: // 2400 bit/s
1111
1112 si2 += 3;
1113 break;
1114 case 69: // 4800 bit/s
1115
1116 si2 += 4;
1117 break;
1118 case 72: // 9600 bit/s
1119
1120 si2 += 5;
1121 break;
1122 case 73: // 14400 bit/s
1123
1124 si2 += 6;
1125 break;
1126 case 75: // 19200 bit/s
1127
1128 si2 += 7;
1129 break;
1130 }
1131
1132 info = p[7] & 0x7f;
1133 if ((info & 16) && (!(info & 8))) // 7 data bits
1134
1135 si2 += 32; // else 8 data bits
1136
1137 if ((info & 96) == 96) // 2 stop bits
1138
1139 si2 += 16; // else 1 stop bit
1140
1141 if ((info & 2) && (!(info & 1))) // even parity
1142
1143 si2 += 8; // else no parity
1144
1145 return si2;
1146}
1147
1148
1149static u_char
1150DecodeSyncParams(u_char si2, u_char info)
1151{
1152 info &= 0x7f;
1153 switch (info) {
1154 case 40: // bit/s negotiation failed ai := 165 not 175!
1155
1156 return si2 + 15;
1157 case 15: // 56000 bit/s failed, ai := 0 not 169 !
1158
1159 return si2 + 9;
1160 case 14: // 48000 bit/s
1161
1162 return si2 + 8;
1163 case 11: // 19200 bit/s
1164
1165 return si2 + 7;
1166 case 9: // 14400 bit/s
1167
1168 return si2 + 6;
1169 case 8: // 9600 bit/s
1170
1171 return si2 + 5;
1172 case 5: // 4800 bit/s
1173
1174 return si2 + 4;
1175 case 3: // 2400 bit/s
1176
1177 return si2 + 3;
1178 case 23: // 75/1200 bit/s
1179
1180 return si2 + 2;
1181 case 24: // 1200/75 bit/s
1182
1183 return si2 + 1;
1184 default: // 1200 bit/s
1185
1186 return si2;
1187 }
1188}
1189
1190static u_char
1191DecodeSI2(struct sk_buff *skb)
1192{
1193 u_char *p; //, *pend=skb->data + skb->len;
1194
1195 if ((p = findie(skb->data, skb->len, 0x7c, 0))) {
1196 switch (p[4] & 0x0f) {
1197 case 0x01:
1198 if (p[1] == 0x04) // sync. Bitratenadaption
1199
1200 return DecodeSyncParams(160, p[5]); // V.110/X.30
1201
1202 else if (p[1] == 0x06) // async. Bitratenadaption
1203
1204 return DecodeASyncParams(192, p); // V.110/X.30
1205
1206 break;
1207 case 0x08: // if (p[5] == 0x02) // sync. Bitratenadaption
1208 if (p[1] > 3)
1209 return DecodeSyncParams(176, p[5]); // V.120
1210 break;
1211 }
1212 }
1213 return 0;
1214}
1215
1216#endif
1217
1218
1219static void
1220l3dss1_setup_req(struct l3_process *pc, u_char pr,
1221 void *arg)
1222{
1223 struct sk_buff *skb;
1224 u_char tmp[128];
1225 u_char *p = tmp;
1226 u_char channel = 0;
1227
1228 u_char send_keypad;
1229 u_char screen = 0x80;
1230 u_char *teln;
1231 u_char *msn;
1232 u_char *sub;
1233 u_char *sp;
1234 int l;
1235
1236 MsgHead(p, pc->callref, MT_SETUP);
1237
1238 teln = pc->para.setup.phone;
1239#ifndef CONFIG_HISAX_NO_KEYPAD
1240 send_keypad = (strchr(teln,'*') || strchr(teln,'#')) ? 1 : 0;
1241#else
1242 send_keypad = 0;
1243#endif
1244#ifndef CONFIG_HISAX_NO_SENDCOMPLETE
1245 if (!send_keypad)
1246 *p++ = 0xa1; /* complete indicator */
1247#endif
1248 /*
1249 * Set Bearer Capability, Map info from 1TR6-convention to EDSS1
1250 */
1251 switch (pc->para.setup.si1) {
1252 case 1: /* Telephony */
1253 *p++ = IE_BEARER;
1254 *p++ = 0x3; /* Length */
1255 *p++ = 0x90; /* Coding Std. CCITT, 3.1 kHz audio */
1256 *p++ = 0x90; /* Circuit-Mode 64kbps */
1257 *p++ = 0xa3; /* A-Law Audio */
1258 break;
1259 case 5: /* Datatransmission 64k, BTX */
1260 case 7: /* Datatransmission 64k */
1261 default:
1262 *p++ = IE_BEARER;
1263 *p++ = 0x2; /* Length */
1264 *p++ = 0x88; /* Coding Std. CCITT, unrestr. dig. Inform. */
1265 *p++ = 0x90; /* Circuit-Mode 64kbps */
1266 break;
1267 }
1268
1269 if (send_keypad) {
1270 *p++ = IE_KEYPAD;
1271 *p++ = strlen(teln);
1272 while (*teln)
1273 *p++ = (*teln++) & 0x7F;
1274 }
1275
1276 /*
1277 * What about info2? Mapping to High-Layer-Compatibility?
1278 */
1279 if ((*teln) && (!send_keypad)) {
1280 /* parse number for special things */
1281 if (!isdigit(*teln)) {
1282 switch (0x5f & *teln) {
1283 case 'C':
1284 channel = 0x08;
1285 case 'P':
1286 channel |= 0x80;
1287 teln++;
1288 if (*teln == '1')
1289 channel |= 0x01;
1290 else
1291 channel |= 0x02;
1292 break;
1293 case 'R':
1294 screen = 0xA0;
1295 break;
1296 case 'D':
1297 screen = 0x80;
1298 break;
1299
1300 default:
1301 if (pc->debug & L3_DEB_WARN)
1302 l3_debug(pc->st, "Wrong MSN Code");
1303 break;
1304 }
1305 teln++;
1306 }
1307 }
1308 if (channel) {
1309 *p++ = IE_CHANNEL_ID;
1310 *p++ = 1;
1311 *p++ = channel;
1312 }
1313 msn = pc->para.setup.eazmsn;
1314 sub = NULL;
1315 sp = msn;
1316 while (*sp) {
1317 if ('.' == *sp) {
1318 sub = sp;
1319 *sp = 0;
1320 } else
1321 sp++;
1322 }
1323 if (*msn) {
1324 *p++ = IE_CALLING_PN;
1325 *p++ = strlen(msn) + (screen ? 2 : 1);
1326 /* Classify as AnyPref. */
1327 if (screen) {
1328 *p++ = 0x01; /* Ext = '0'B, Type = '000'B, Plan = '0001'B. */
1329 *p++ = screen;
1330 } else
1331 *p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
1332 while (*msn)
1333 *p++ = *msn++ & 0x7f;
1334 }
1335 if (sub) {
1336 *sub++ = '.';
1337 *p++ = IE_CALLING_SUB;
1338 *p++ = strlen(sub) + 2;
1339 *p++ = 0x80; /* NSAP coded */
1340 *p++ = 0x50; /* local IDI format */
1341 while (*sub)
1342 *p++ = *sub++ & 0x7f;
1343 }
1344 sub = NULL;
1345 sp = teln;
1346 while (*sp) {
1347 if ('.' == *sp) {
1348 sub = sp;
1349 *sp = 0;
1350 } else
1351 sp++;
1352 }
1353
1354 if (!send_keypad) {
1355 *p++ = IE_CALLED_PN;
1356 *p++ = strlen(teln) + 1;
1357 /* Classify as AnyPref. */
1358 *p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
1359 while (*teln)
1360 *p++ = *teln++ & 0x7f;
1361
1362 if (sub) {
1363 *sub++ = '.';
1364 *p++ = IE_CALLED_SUB;
1365 *p++ = strlen(sub) + 2;
1366 *p++ = 0x80; /* NSAP coded */
1367 *p++ = 0x50; /* local IDI format */
1368 while (*sub)
1369 *p++ = *sub++ & 0x7f;
1370 }
1371 }
1372#if EXT_BEARER_CAPS
1373 if ((pc->para.setup.si2 >= 160) && (pc->para.setup.si2 <= 175)) { // sync. Bitratenadaption, V.110/X.30
1374
1375 *p++ = IE_LLC;
1376 *p++ = 0x04;
1377 *p++ = 0x88;
1378 *p++ = 0x90;
1379 *p++ = 0x21;
1380 *p++ = EncodeSyncParams(pc->para.setup.si2 - 160, 0x80);
1381 } else if ((pc->para.setup.si2 >= 176) && (pc->para.setup.si2 <= 191)) { // sync. Bitratenadaption, V.120
1382
1383 *p++ = IE_LLC;
1384 *p++ = 0x05;
1385 *p++ = 0x88;
1386 *p++ = 0x90;
1387 *p++ = 0x28;
1388 *p++ = EncodeSyncParams(pc->para.setup.si2 - 176, 0);
1389 *p++ = 0x82;
1390 } else if (pc->para.setup.si2 >= 192) { // async. Bitratenadaption, V.110/X.30
1391
1392 *p++ = IE_LLC;
1393 *p++ = 0x06;
1394 *p++ = 0x88;
1395 *p++ = 0x90;
1396 *p++ = 0x21;
1397 p = EncodeASyncParams(p, pc->para.setup.si2 - 192);
1398#ifndef CONFIG_HISAX_NO_LLC
1399 } else {
1400 switch (pc->para.setup.si1) {
1401 case 1: /* Telephony */
1402 *p++ = IE_LLC;
1403 *p++ = 0x3; /* Length */
1404 *p++ = 0x90; /* Coding Std. CCITT, 3.1 kHz audio */
1405 *p++ = 0x90; /* Circuit-Mode 64kbps */
1406 *p++ = 0xa3; /* A-Law Audio */
1407 break;
1408 case 5: /* Datatransmission 64k, BTX */
1409 case 7: /* Datatransmission 64k */
1410 default:
1411 *p++ = IE_LLC;
1412 *p++ = 0x2; /* Length */
1413 *p++ = 0x88; /* Coding Std. CCITT, unrestr. dig. Inform. */
1414 *p++ = 0x90; /* Circuit-Mode 64kbps */
1415 break;
1416 }
1417#endif
1418 }
1419#endif
1420 l = p - tmp;
1421 if (!(skb = l3_alloc_skb(l)))
1422 return;
1423 memcpy(skb_put(skb, l), tmp, l);
1424 L3DelTimer(&pc->timer);
1425 L3AddTimer(&pc->timer, T303, CC_T303);
1426 newl3state(pc, 1);
1427 l3_msg(pc->st, DL_DATA | REQUEST, skb);
1428}
1429
1430static void
1431l3dss1_call_proc(struct l3_process *pc, u_char pr, void *arg)
1432{
1433 struct sk_buff *skb = arg;
1434 int id, ret;
1435
1436 if ((id = l3dss1_get_channel_id(pc, skb)) >= 0) {
1437 if ((0 == id) || ((3 == id) && (0x10 == pc->para.moderate))) {
1438 if (pc->debug & L3_DEB_WARN)
1439 l3_debug(pc->st, "setup answer with wrong chid %x", id);
1440 pc->para.cause = 100;
1441 l3dss1_status_send(pc, pr, NULL);
1442 return;
1443 }
1444 pc->para.bchannel = id;
1445 } else if (1 == pc->state) {
1446 if (pc->debug & L3_DEB_WARN)
1447 l3_debug(pc->st, "setup answer wrong chid (ret %d)", id);
1448 if (id == -1)
1449 pc->para.cause = 96;
1450 else
1451 pc->para.cause = 100;
1452 l3dss1_status_send(pc, pr, NULL);
1453 return;
1454 }
1455 /* Now we are on none mandatory IEs */
1456 ret = check_infoelements(pc, skb, ie_CALL_PROCEEDING);
1457 if (ERR_IE_COMPREHENSION == ret) {
1458 l3dss1_std_ie_err(pc, ret);
1459 return;
1460 }
1461 L3DelTimer(&pc->timer);
1462 newl3state(pc, 3);
1463 L3AddTimer(&pc->timer, T310, CC_T310);
1464 if (ret) /* STATUS for none mandatory IE errors after actions are taken */
1465 l3dss1_std_ie_err(pc, ret);
1466 pc->st->l3.l3l4(pc->st, CC_PROCEEDING | INDICATION, pc);
1467}
1468
1469static void
1470l3dss1_setup_ack(struct l3_process *pc, u_char pr, void *arg)
1471{
1472 struct sk_buff *skb = arg;
1473 int id, ret;
1474
1475 if ((id = l3dss1_get_channel_id(pc, skb)) >= 0) {
1476 if ((0 == id) || ((3 == id) && (0x10 == pc->para.moderate))) {
1477 if (pc->debug & L3_DEB_WARN)
1478 l3_debug(pc->st, "setup answer with wrong chid %x", id);
1479 pc->para.cause = 100;
1480 l3dss1_status_send(pc, pr, NULL);
1481 return;
1482 }
1483 pc->para.bchannel = id;
1484 } else {
1485 if (pc->debug & L3_DEB_WARN)
1486 l3_debug(pc->st, "setup answer wrong chid (ret %d)", id);
1487 if (id == -1)
1488 pc->para.cause = 96;
1489 else
1490 pc->para.cause = 100;
1491 l3dss1_status_send(pc, pr, NULL);
1492 return;
1493 }
1494 /* Now we are on none mandatory IEs */
1495 ret = check_infoelements(pc, skb, ie_SETUP_ACKNOWLEDGE);
1496 if (ERR_IE_COMPREHENSION == ret) {
1497 l3dss1_std_ie_err(pc, ret);
1498 return;
1499 }
1500 L3DelTimer(&pc->timer);
1501 newl3state(pc, 2);
1502 L3AddTimer(&pc->timer, T304, CC_T304);
1503 if (ret) /* STATUS for none mandatory IE errors after actions are taken */
1504 l3dss1_std_ie_err(pc, ret);
1505 pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc);
1506}
1507
1508static void
1509l3dss1_disconnect(struct l3_process *pc, u_char pr, void *arg)
1510{
1511 struct sk_buff *skb = arg;
1512 u_char *p;
1513 int ret;
1514 u_char cause = 0;
1515
1516 StopAllL3Timer(pc);
1517 if ((ret = l3dss1_get_cause(pc, skb))) {
1518 if (pc->debug & L3_DEB_WARN)
1519 l3_debug(pc->st, "DISC get_cause ret(%d)", ret);
1520 if (ret < 0)
1521 cause = 96;
1522 else if (ret > 0)
1523 cause = 100;
1524 }
1525 if ((p = findie(skb->data, skb->len, IE_FACILITY, 0)))
1526 l3dss1_parse_facility(pc->st, pc, pc->callref, p);
1527 ret = check_infoelements(pc, skb, ie_DISCONNECT);
1528 if (ERR_IE_COMPREHENSION == ret)
1529 cause = 96;
1530 else if ((!cause) && (ERR_IE_UNRECOGNIZED == ret))
1531 cause = 99;
1532 ret = pc->state;
1533 newl3state(pc, 12);
1534 if (cause)
1535 newl3state(pc, 19);
1536 if (11 != ret)
1537 pc->st->l3.l3l4(pc->st, CC_DISCONNECT | INDICATION, pc);
1538 else if (!cause)
1539 l3dss1_release_req(pc, pr, NULL);
1540 if (cause) {
1541 l3dss1_message_cause(pc, MT_RELEASE, cause);
1542 L3AddTimer(&pc->timer, T308, CC_T308_1);
1543 }
1544}
1545
1546static void
1547l3dss1_connect(struct l3_process *pc, u_char pr, void *arg)
1548{
1549 struct sk_buff *skb = arg;
1550 int ret;
1551
1552 ret = check_infoelements(pc, skb, ie_CONNECT);
1553 if (ERR_IE_COMPREHENSION == ret) {
1554 l3dss1_std_ie_err(pc, ret);
1555 return;
1556 }
1557 L3DelTimer(&pc->timer); /* T310 */
1558 newl3state(pc, 10);
1559 pc->para.chargeinfo = 0;
1560 /* here should inserted COLP handling KKe */
1561 if (ret)
1562 l3dss1_std_ie_err(pc, ret);
1563 pc->st->l3.l3l4(pc->st, CC_SETUP | CONFIRM, pc);
1564}
1565
1566static void
1567l3dss1_alerting(struct l3_process *pc, u_char pr, void *arg)
1568{
1569 struct sk_buff *skb = arg;
1570 int ret;
1571
1572 ret = check_infoelements(pc, skb, ie_ALERTING);
1573 if (ERR_IE_COMPREHENSION == ret) {
1574 l3dss1_std_ie_err(pc, ret);
1575 return;
1576 }
1577 L3DelTimer(&pc->timer); /* T304 */
1578 newl3state(pc, 4);
1579 if (ret)
1580 l3dss1_std_ie_err(pc, ret);
1581 pc->st->l3.l3l4(pc->st, CC_ALERTING | INDICATION, pc);
1582}
1583
1584static void
1585l3dss1_setup(struct l3_process *pc, u_char pr, void *arg)
1586{
1587 u_char *p;
1588 int bcfound = 0;
1589 char tmp[80];
1590 struct sk_buff *skb = arg;
1591 int id;
1592 int err = 0;
1593
1594 /*
1595 * Bearer Capabilities
1596 */
1597 p = skb->data;
1598 /* only the first occurence 'll be detected ! */
1599 if ((p = findie(p, skb->len, 0x04, 0))) {
1600 if ((p[1] < 2) || (p[1] > 11))
1601 err = 1;
1602 else {
1603 pc->para.setup.si2 = 0;
1604 switch (p[2] & 0x7f) {
1605 case 0x00: /* Speech */
1606 case 0x10: /* 3.1 Khz audio */
1607 pc->para.setup.si1 = 1;
1608 break;
1609 case 0x08: /* Unrestricted digital information */
1610 pc->para.setup.si1 = 7;
1611/* JIM, 05.11.97 I wanna set service indicator 2 */
1612#if EXT_BEARER_CAPS
1613 pc->para.setup.si2 = DecodeSI2(skb);
1614#endif
1615 break;
1616 case 0x09: /* Restricted digital information */
1617 pc->para.setup.si1 = 2;
1618 break;
1619 case 0x11:
1620 /* Unrestr. digital information with
1621 * tones/announcements ( or 7 kHz audio
1622 */
1623 pc->para.setup.si1 = 3;
1624 break;
1625 case 0x18: /* Video */
1626 pc->para.setup.si1 = 4;
1627 break;
1628 default:
1629 err = 2;
1630 break;
1631 }
1632 switch (p[3] & 0x7f) {
1633 case 0x40: /* packed mode */
1634 pc->para.setup.si1 = 8;
1635 break;
1636 case 0x10: /* 64 kbit */
1637 case 0x11: /* 2*64 kbit */
1638 case 0x13: /* 384 kbit */
1639 case 0x15: /* 1536 kbit */
1640 case 0x17: /* 1920 kbit */
1641 pc->para.moderate = p[3] & 0x7f;
1642 break;
1643 default:
1644 err = 3;
1645 break;
1646 }
1647 }
1648 if (pc->debug & L3_DEB_SI)
1649 l3_debug(pc->st, "SI=%d, AI=%d",
1650 pc->para.setup.si1, pc->para.setup.si2);
1651 if (err) {
1652 if (pc->debug & L3_DEB_WARN)
1653 l3_debug(pc->st, "setup with wrong bearer(l=%d:%x,%x)",
1654 p[1], p[2], p[3]);
1655 pc->para.cause = 100;
1656 l3dss1_msg_without_setup(pc, pr, NULL);
1657 return;
1658 }
1659 } else {
1660 if (pc->debug & L3_DEB_WARN)
1661 l3_debug(pc->st, "setup without bearer capabilities");
1662 /* ETS 300-104 1.3.3 */
1663 pc->para.cause = 96;
1664 l3dss1_msg_without_setup(pc, pr, NULL);
1665 return;
1666 }
1667 /*
1668 * Channel Identification
1669 */
1670 if ((id = l3dss1_get_channel_id(pc, skb)) >= 0) {
1671 if ((pc->para.bchannel = id)) {
1672 if ((3 == id) && (0x10 == pc->para.moderate)) {
1673 if (pc->debug & L3_DEB_WARN)
1674 l3_debug(pc->st, "setup with wrong chid %x",
1675 id);
1676 pc->para.cause = 100;
1677 l3dss1_msg_without_setup(pc, pr, NULL);
1678 return;
1679 }
1680 bcfound++;
1681 } else
1682 { if (pc->debug & L3_DEB_WARN)
1683 l3_debug(pc->st, "setup without bchannel, call waiting");
1684 bcfound++;
1685 }
1686 } else {
1687 if (pc->debug & L3_DEB_WARN)
1688 l3_debug(pc->st, "setup with wrong chid ret %d", id);
1689 if (id == -1)
1690 pc->para.cause = 96;
1691 else
1692 pc->para.cause = 100;
1693 l3dss1_msg_without_setup(pc, pr, NULL);
1694 return;
1695 }
1696 /* Now we are on none mandatory IEs */
1697 err = check_infoelements(pc, skb, ie_SETUP);
1698 if (ERR_IE_COMPREHENSION == err) {
1699 pc->para.cause = 96;
1700 l3dss1_msg_without_setup(pc, pr, NULL);
1701 return;
1702 }
1703 p = skb->data;
1704 if ((p = findie(p, skb->len, 0x70, 0)))
1705 iecpy(pc->para.setup.eazmsn, p, 1);
1706 else
1707 pc->para.setup.eazmsn[0] = 0;
1708
1709 p = skb->data;
1710 if ((p = findie(p, skb->len, 0x71, 0))) {
1711 /* Called party subaddress */
1712 if ((p[1] >= 2) && (p[2] == 0x80) && (p[3] == 0x50)) {
1713 tmp[0] = '.';
1714 iecpy(&tmp[1], p, 2);
1715 strcat(pc->para.setup.eazmsn, tmp);
1716 } else if (pc->debug & L3_DEB_WARN)
1717 l3_debug(pc->st, "wrong called subaddress");
1718 }
1719 p = skb->data;
1720 if ((p = findie(p, skb->len, 0x6c, 0))) {
1721 pc->para.setup.plan = p[2];
1722 if (p[2] & 0x80) {
1723 iecpy(pc->para.setup.phone, p, 1);
1724 pc->para.setup.screen = 0;
1725 } else {
1726 iecpy(pc->para.setup.phone, p, 2);
1727 pc->para.setup.screen = p[3];
1728 }
1729 } else {
1730 pc->para.setup.phone[0] = 0;
1731 pc->para.setup.plan = 0;
1732 pc->para.setup.screen = 0;
1733 }
1734 p = skb->data;
1735 if ((p = findie(p, skb->len, 0x6d, 0))) {
1736 /* Calling party subaddress */
1737 if ((p[1] >= 2) && (p[2] == 0x80) && (p[3] == 0x50)) {
1738 tmp[0] = '.';
1739 iecpy(&tmp[1], p, 2);
1740 strcat(pc->para.setup.phone, tmp);
1741 } else if (pc->debug & L3_DEB_WARN)
1742 l3_debug(pc->st, "wrong calling subaddress");
1743 }
1744 newl3state(pc, 6);
1745 if (err) /* STATUS for none mandatory IE errors after actions are taken */
1746 l3dss1_std_ie_err(pc, err);
1747 pc->st->l3.l3l4(pc->st, CC_SETUP | INDICATION, pc);
1748}
1749
1750static void
1751l3dss1_reset(struct l3_process *pc, u_char pr, void *arg)
1752{
1753 dss1_release_l3_process(pc);
1754}
1755
1756static void
1757l3dss1_disconnect_req(struct l3_process *pc, u_char pr, void *arg)
1758{
1759 struct sk_buff *skb;
1760 u_char tmp[16+40];
1761 u_char *p = tmp;
1762 int l;
1763 u_char cause = 16;
1764
1765 if (pc->para.cause != NO_CAUSE)
1766 cause = pc->para.cause;
1767
1768 StopAllL3Timer(pc);
1769
1770 MsgHead(p, pc->callref, MT_DISCONNECT);
1771
1772 *p++ = IE_CAUSE;
1773 *p++ = 0x2;
1774 *p++ = 0x80;
1775 *p++ = cause | 0x80;
1776
1777 if (pc->prot.dss1.uus1_data[0])
1778 { *p++ = IE_USER_USER; /* UUS info element */
1779 *p++ = strlen(pc->prot.dss1.uus1_data) + 1;
1780 *p++ = 0x04; /* IA5 chars */
1781 strcpy(p,pc->prot.dss1.uus1_data);
1782 p += strlen(pc->prot.dss1.uus1_data);
1783 pc->prot.dss1.uus1_data[0] = '\0';
1784 }
1785
1786 l = p - tmp;
1787 if (!(skb = l3_alloc_skb(l)))
1788 return;
1789 memcpy(skb_put(skb, l), tmp, l);
1790 newl3state(pc, 11);
1791 l3_msg(pc->st, DL_DATA | REQUEST, skb);
1792 L3AddTimer(&pc->timer, T305, CC_T305);
1793}
1794
1795static void
1796l3dss1_setup_rsp(struct l3_process *pc, u_char pr,
1797 void *arg)
1798{
1799 if (!pc->para.bchannel)
1800 { if (pc->debug & L3_DEB_WARN)
1801 l3_debug(pc->st, "D-chan connect for waiting call");
1802 l3dss1_disconnect_req(pc, pr, arg);
1803 return;
1804 }
1805 newl3state(pc, 8);
1806 l3dss1_message(pc, MT_CONNECT);
1807 L3DelTimer(&pc->timer);
1808 L3AddTimer(&pc->timer, T313, CC_T313);
1809}
1810
1811static void
1812l3dss1_connect_ack(struct l3_process *pc, u_char pr, void *arg)
1813{
1814 struct sk_buff *skb = arg;
1815 int ret;
1816
1817 ret = check_infoelements(pc, skb, ie_CONNECT_ACKNOWLEDGE);
1818 if (ERR_IE_COMPREHENSION == ret) {
1819 l3dss1_std_ie_err(pc, ret);
1820 return;
1821 }
1822 newl3state(pc, 10);
1823 L3DelTimer(&pc->timer);
1824 if (ret)
1825 l3dss1_std_ie_err(pc, ret);
1826 pc->st->l3.l3l4(pc->st, CC_SETUP_COMPL | INDICATION, pc);
1827}
1828
1829static void
1830l3dss1_reject_req(struct l3_process *pc, u_char pr, void *arg)
1831{
1832 struct sk_buff *skb;
1833 u_char tmp[16];
1834 u_char *p = tmp;
1835 int l;
1836 u_char cause = 21;
1837
1838 if (pc->para.cause != NO_CAUSE)
1839 cause = pc->para.cause;
1840
1841 MsgHead(p, pc->callref, MT_RELEASE_COMPLETE);
1842
1843 *p++ = IE_CAUSE;
1844 *p++ = 0x2;
1845 *p++ = 0x80;
1846 *p++ = cause | 0x80;
1847
1848 l = p - tmp;
1849 if (!(skb = l3_alloc_skb(l)))
1850 return;
1851 memcpy(skb_put(skb, l), tmp, l);
1852 l3_msg(pc->st, DL_DATA | REQUEST, skb);
1853 pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
1854 newl3state(pc, 0);
1855 dss1_release_l3_process(pc);
1856}
1857
1858static void
1859l3dss1_release(struct l3_process *pc, u_char pr, void *arg)
1860{
1861 struct sk_buff *skb = arg;
1862 u_char *p;
1863 int ret, cause=0;
1864
1865 StopAllL3Timer(pc);
1866 if ((ret = l3dss1_get_cause(pc, skb))>0) {
1867 if (pc->debug & L3_DEB_WARN)
1868 l3_debug(pc->st, "REL get_cause ret(%d)", ret);
1869 } else if (ret<0)
1870 pc->para.cause = NO_CAUSE;
1871 if ((p = findie(skb->data, skb->len, IE_FACILITY, 0))) {
1872 l3dss1_parse_facility(pc->st, pc, pc->callref, p);
1873 }
1874 if ((ret<0) && (pc->state != 11))
1875 cause = 96;
1876 else if (ret>0)
1877 cause = 100;
1878 ret = check_infoelements(pc, skb, ie_RELEASE);
1879 if (ERR_IE_COMPREHENSION == ret)
1880 cause = 96;
1881 else if ((ERR_IE_UNRECOGNIZED == ret) && (!cause))
1882 cause = 99;
1883 if (cause)
1884 l3dss1_message_cause(pc, MT_RELEASE_COMPLETE, cause);
1885 else
1886 l3dss1_message(pc, MT_RELEASE_COMPLETE);
1887 pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
1888 newl3state(pc, 0);
1889 dss1_release_l3_process(pc);
1890}
1891
1892static void
1893l3dss1_alert_req(struct l3_process *pc, u_char pr,
1894 void *arg)
1895{
1896 newl3state(pc, 7);
1897 if (!pc->prot.dss1.uus1_data[0])
1898 l3dss1_message(pc, MT_ALERTING);
1899 else
1900 l3dss1_msg_with_uus(pc, MT_ALERTING);
1901}
1902
1903static void
1904l3dss1_proceed_req(struct l3_process *pc, u_char pr,
1905 void *arg)
1906{
1907 newl3state(pc, 9);
1908 l3dss1_message(pc, MT_CALL_PROCEEDING);
1909 pc->st->l3.l3l4(pc->st, CC_PROCEED_SEND | INDICATION, pc);
1910}
1911
1912static void
1913l3dss1_setup_ack_req(struct l3_process *pc, u_char pr,
1914 void *arg)
1915{
1916 newl3state(pc, 25);
1917 L3DelTimer(&pc->timer);
1918 L3AddTimer(&pc->timer, T302, CC_T302);
1919 l3dss1_message(pc, MT_SETUP_ACKNOWLEDGE);
1920}
1921
1922/********************************************/
1923/* deliver a incoming display message to HL */
1924/********************************************/
1925static void
1926l3dss1_deliver_display(struct l3_process *pc, int pr, u_char *infp)
1927{ u_char len;
1928 isdn_ctrl ic;
1929 struct IsdnCardState *cs;
1930 char *p;
1931
1932 if (*infp++ != IE_DISPLAY) return;
1933 if ((len = *infp++) > 80) return; /* total length <= 82 */
1934 if (!pc->chan) return;
1935
1936 p = ic.parm.display;
1937 while (len--)
1938 *p++ = *infp++;
1939 *p = '\0';
1940 ic.command = ISDN_STAT_DISPLAY;
1941 cs = pc->st->l1.hardware;
1942 ic.driver = cs->myid;
1943 ic.arg = pc->chan->chan;
1944 cs->iif.statcallb(&ic);
1945} /* l3dss1_deliver_display */
1946
1947
1948static void
1949l3dss1_progress(struct l3_process *pc, u_char pr, void *arg)
1950{
1951 struct sk_buff *skb = arg;
1952 int err = 0;
1953 u_char *p;
1954
1955 if ((p = findie(skb->data, skb->len, IE_PROGRESS, 0))) {
1956 if (p[1] != 2) {
1957 err = 1;
1958 pc->para.cause = 100;
1959 } else if (!(p[2] & 0x70)) {
1960 switch (p[2]) {
1961 case 0x80:
1962 case 0x81:
1963 case 0x82:
1964 case 0x84:
1965 case 0x85:
1966 case 0x87:
1967 case 0x8a:
1968 switch (p[3]) {
1969 case 0x81:
1970 case 0x82:
1971 case 0x83:
1972 case 0x84:
1973 case 0x88:
1974 break;
1975 default:
1976 err = 2;
1977 pc->para.cause = 100;
1978 break;
1979 }
1980 break;
1981 default:
1982 err = 3;
1983 pc->para.cause = 100;
1984 break;
1985 }
1986 }
1987 } else {
1988 pc->para.cause = 96;
1989 err = 4;
1990 }
1991 if (err) {
1992 if (pc->debug & L3_DEB_WARN)
1993 l3_debug(pc->st, "progress error %d", err);
1994 l3dss1_status_send(pc, pr, NULL);
1995 return;
1996 }
1997 /* Now we are on none mandatory IEs */
1998 err = check_infoelements(pc, skb, ie_PROGRESS);
1999 if (err)
2000 l3dss1_std_ie_err(pc, err);
2001 if (ERR_IE_COMPREHENSION != err)
2002 pc->st->l3.l3l4(pc->st, CC_PROGRESS | INDICATION, pc);
2003}
2004
2005static void
2006l3dss1_notify(struct l3_process *pc, u_char pr, void *arg)
2007{
2008 struct sk_buff *skb = arg;
2009 int err = 0;
2010 u_char *p;
2011
2012 if ((p = findie(skb->data, skb->len, IE_NOTIFY, 0))) {
2013 if (p[1] != 1) {
2014 err = 1;
2015 pc->para.cause = 100;
2016 } else {
2017 switch (p[2]) {
2018 case 0x80:
2019 case 0x81:
2020 case 0x82:
2021 break;
2022 default:
2023 pc->para.cause = 100;
2024 err = 2;
2025 break;
2026 }
2027 }
2028 } else {
2029 pc->para.cause = 96;
2030 err = 3;
2031 }
2032 if (err) {
2033 if (pc->debug & L3_DEB_WARN)
2034 l3_debug(pc->st, "notify error %d", err);
2035 l3dss1_status_send(pc, pr, NULL);
2036 return;
2037 }
2038 /* Now we are on none mandatory IEs */
2039 err = check_infoelements(pc, skb, ie_NOTIFY);
2040 if (err)
2041 l3dss1_std_ie_err(pc, err);
2042 if (ERR_IE_COMPREHENSION != err)
2043 pc->st->l3.l3l4(pc->st, CC_NOTIFY | INDICATION, pc);
2044}
2045
2046static void
2047l3dss1_status_enq(struct l3_process *pc, u_char pr, void *arg)
2048{
2049 int ret;
2050 struct sk_buff *skb = arg;
2051
2052 ret = check_infoelements(pc, skb, ie_STATUS_ENQUIRY);
2053 l3dss1_std_ie_err(pc, ret);
2054 pc->para.cause = 30; /* response to STATUS_ENQUIRY */
2055 l3dss1_status_send(pc, pr, NULL);
2056}
2057
2058static void
2059l3dss1_information(struct l3_process *pc, u_char pr, void *arg)
2060{
2061 int ret;
2062 struct sk_buff *skb = arg;
2063 u_char *p;
2064 char tmp[32];
2065
2066 ret = check_infoelements(pc, skb, ie_INFORMATION);
2067 if (ret)
2068 l3dss1_std_ie_err(pc, ret);
2069 if (pc->state == 25) { /* overlap receiving */
2070 L3DelTimer(&pc->timer);
2071 p = skb->data;
2072 if ((p = findie(p, skb->len, 0x70, 0))) {
2073 iecpy(tmp, p, 1);
2074 strcat(pc->para.setup.eazmsn, tmp);
2075 pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc);
2076 }
2077 L3AddTimer(&pc->timer, T302, CC_T302);
2078 }
2079}
2080
2081/******************************/
2082/* handle deflection requests */
2083/******************************/
2084static void l3dss1_redir_req(struct l3_process *pc, u_char pr, void *arg)
2085{
2086 struct sk_buff *skb;
2087 u_char tmp[128];
2088 u_char *p = tmp;
2089 u_char *subp;
2090 u_char len_phone = 0;
2091 u_char len_sub = 0;
2092 int l;
2093
2094
2095 strcpy(pc->prot.dss1.uus1_data,pc->chan->setup.eazmsn); /* copy uus element if available */
2096 if (!pc->chan->setup.phone[0])
2097 { pc->para.cause = -1;
2098 l3dss1_disconnect_req(pc,pr,arg); /* disconnect immediately */
2099 return;
2100 } /* only uus */
2101
2102 if (pc->prot.dss1.invoke_id)
2103 free_invoke_id(pc->st,pc->prot.dss1.invoke_id);
2104
2105 if (!(pc->prot.dss1.invoke_id = new_invoke_id(pc->st)))
2106 return;
2107
2108 MsgHead(p, pc->callref, MT_FACILITY);
2109
2110 for (subp = pc->chan->setup.phone; (*subp) && (*subp != '.'); subp++) len_phone++; /* len of phone number */
2111 if (*subp++ == '.') len_sub = strlen(subp) + 2; /* length including info subaddress element */
2112
2113 *p++ = 0x1c; /* Facility info element */
2114 *p++ = len_phone + len_sub + 2 + 2 + 8 + 3 + 3; /* length of element */
2115 *p++ = 0x91; /* remote operations protocol */
2116 *p++ = 0xa1; /* invoke component */
2117
2118 *p++ = len_phone + len_sub + 2 + 2 + 8 + 3; /* length of data */
2119 *p++ = 0x02; /* invoke id tag, integer */
2120 *p++ = 0x01; /* length */
2121 *p++ = pc->prot.dss1.invoke_id; /* invoke id */
2122 *p++ = 0x02; /* operation value tag, integer */
2123 *p++ = 0x01; /* length */
2124 *p++ = 0x0D; /* Call Deflect */
2125
2126 *p++ = 0x30; /* sequence phone number */
2127 *p++ = len_phone + 2 + 2 + 3 + len_sub; /* length */
2128
2129 *p++ = 0x30; /* Deflected to UserNumber */
2130 *p++ = len_phone+2+len_sub; /* length */
2131 *p++ = 0x80; /* NumberDigits */
2132 *p++ = len_phone; /* length */
2133 for (l = 0; l < len_phone; l++)
2134 *p++ = pc->chan->setup.phone[l];
2135
2136 if (len_sub)
2137 { *p++ = 0x04; /* called party subaddress */
2138 *p++ = len_sub - 2;
2139 while (*subp) *p++ = *subp++;
2140 }
2141
2142 *p++ = 0x01; /* screening identifier */
2143 *p++ = 0x01;
2144 *p++ = pc->chan->setup.screen;
2145
2146 l = p - tmp;
2147 if (!(skb = l3_alloc_skb(l))) return;
2148 memcpy(skb_put(skb, l), tmp, l);
2149
2150 l3_msg(pc->st, DL_DATA | REQUEST, skb);
2151} /* l3dss1_redir_req */
2152
2153/********************************************/
2154/* handle deflection request in early state */
2155/********************************************/
2156static void l3dss1_redir_req_early(struct l3_process *pc, u_char pr, void *arg)
2157{
2158 l3dss1_proceed_req(pc,pr,arg);
2159 l3dss1_redir_req(pc,pr,arg);
2160} /* l3dss1_redir_req_early */
2161
2162/***********************************************/
2163/* handle special commands for this protocol. */
2164/* Examples are call independant services like */
2165/* remote operations with dummy callref. */
2166/***********************************************/
2167static int l3dss1_cmd_global(struct PStack *st, isdn_ctrl *ic)
2168{ u_char id;
2169 u_char temp[265];
2170 u_char *p = temp;
2171 int i, l, proc_len;
2172 struct sk_buff *skb;
2173 struct l3_process *pc = NULL;
2174
2175 switch (ic->arg)
2176 { case DSS1_CMD_INVOKE:
2177 if (ic->parm.dss1_io.datalen < 0) return(-2); /* invalid parameter */
2178
2179 for (proc_len = 1, i = ic->parm.dss1_io.proc >> 8; i; i++)
2180 i = i >> 8; /* add one byte */
2181 l = ic->parm.dss1_io.datalen + proc_len + 8; /* length excluding ie header */
2182 if (l > 255)
2183 return(-2); /* too long */
2184
2185 if (!(id = new_invoke_id(st)))
2186 return(0); /* first get a invoke id -> return if no available */
2187
2188 i = -1;
2189 MsgHead(p, i, MT_FACILITY); /* build message head */
2190 *p++ = 0x1C; /* Facility IE */
2191 *p++ = l; /* length of ie */
2192 *p++ = 0x91; /* remote operations */
2193 *p++ = 0xA1; /* invoke */
2194 *p++ = l - 3; /* length of invoke */
2195 *p++ = 0x02; /* invoke id tag */
2196 *p++ = 0x01; /* length is 1 */
2197 *p++ = id; /* invoke id */
2198 *p++ = 0x02; /* operation */
2199 *p++ = proc_len; /* length of operation */
2200
2201 for (i = proc_len; i; i--)
2202 *p++ = (ic->parm.dss1_io.proc >> (i-1)) & 0xFF;
2203 memcpy(p, ic->parm.dss1_io.data, ic->parm.dss1_io.datalen); /* copy data */
2204 l = (p - temp) + ic->parm.dss1_io.datalen; /* total length */
2205
2206 if (ic->parm.dss1_io.timeout > 0)
2207 if (!(pc = dss1_new_l3_process(st, -1)))
2208 { free_invoke_id(st, id);
2209 return(-2);
2210 }
2211 pc->prot.dss1.ll_id = ic->parm.dss1_io.ll_id; /* remember id */
2212 pc->prot.dss1.proc = ic->parm.dss1_io.proc; /* and procedure */
2213
2214 if (!(skb = l3_alloc_skb(l)))
2215 { free_invoke_id(st, id);
2216 if (pc) dss1_release_l3_process(pc);
2217 return(-2);
2218 }
2219 memcpy(skb_put(skb, l), temp, l);
2220
2221 if (pc)
2222 { pc->prot.dss1.invoke_id = id; /* remember id */
2223 L3AddTimer(&pc->timer, ic->parm.dss1_io.timeout, CC_TDSS1_IO | REQUEST);
2224 }
2225
2226 l3_msg(st, DL_DATA | REQUEST, skb);
2227 ic->parm.dss1_io.hl_id = id; /* return id */
2228 return(0);
2229
2230 case DSS1_CMD_INVOKE_ABORT:
2231 if ((pc = l3dss1_search_dummy_proc(st, ic->parm.dss1_io.hl_id)))
2232 { L3DelTimer(&pc->timer); /* remove timer */
2233 dss1_release_l3_process(pc);
2234 return(0);
2235 }
2236 else
2237 { l3_debug(st, "l3dss1_cmd_global abort unknown id");
2238 return(-2);
2239 }
2240 break;
2241
2242 default:
2243 l3_debug(st, "l3dss1_cmd_global unknown cmd 0x%lx", ic->arg);
2244 return(-1);
2245 } /* switch ic-> arg */
2246 return(-1);
2247} /* l3dss1_cmd_global */
2248
2249static void
2250l3dss1_io_timer(struct l3_process *pc)
2251{ isdn_ctrl ic;
2252 struct IsdnCardState *cs = pc->st->l1.hardware;
2253
2254 L3DelTimer(&pc->timer); /* remove timer */
2255
2256 ic.driver = cs->myid;
2257 ic.command = ISDN_STAT_PROT;
2258 ic.arg = DSS1_STAT_INVOKE_ERR;
2259 ic.parm.dss1_io.hl_id = pc->prot.dss1.invoke_id;
2260 ic.parm.dss1_io.ll_id = pc->prot.dss1.ll_id;
2261 ic.parm.dss1_io.proc = pc->prot.dss1.proc;
2262 ic.parm.dss1_io.timeout= -1;
2263 ic.parm.dss1_io.datalen = 0;
2264 ic.parm.dss1_io.data = NULL;
2265 free_invoke_id(pc->st, pc->prot.dss1.invoke_id);
2266 pc->prot.dss1.invoke_id = 0; /* reset id */
2267
2268 cs->iif.statcallb(&ic);
2269
2270 dss1_release_l3_process(pc);
2271} /* l3dss1_io_timer */
2272
2273static void
2274l3dss1_release_ind(struct l3_process *pc, u_char pr, void *arg)
2275{
2276 u_char *p;
2277 struct sk_buff *skb = arg;
2278 int callState = 0;
2279 p = skb->data;
2280
2281 if ((p = findie(p, skb->len, IE_CALL_STATE, 0))) {
2282 p++;
2283 if (1 == *p++)
2284 callState = *p;
2285 }
2286 if (callState == 0) {
2287 /* ETS 300-104 7.6.1, 8.6.1, 10.6.1... and 16.1
2288 * set down layer 3 without sending any message
2289 */
2290 pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
2291 newl3state(pc, 0);
2292 dss1_release_l3_process(pc);
2293 } else {
2294 pc->st->l3.l3l4(pc->st, CC_IGNORE | INDICATION, pc);
2295 }
2296}
2297
2298static void
2299l3dss1_dummy(struct l3_process *pc, u_char pr, void *arg)
2300{
2301}
2302
2303static void
2304l3dss1_t302(struct l3_process *pc, u_char pr, void *arg)
2305{
2306 L3DelTimer(&pc->timer);
2307 pc->para.loc = 0;
2308 pc->para.cause = 28; /* invalid number */
2309 l3dss1_disconnect_req(pc, pr, NULL);
2310 pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
2311}
2312
2313static void
2314l3dss1_t303(struct l3_process *pc, u_char pr, void *arg)
2315{
2316 if (pc->N303 > 0) {
2317 pc->N303--;
2318 L3DelTimer(&pc->timer);
2319 l3dss1_setup_req(pc, pr, arg);
2320 } else {
2321 L3DelTimer(&pc->timer);
2322 l3dss1_message_cause(pc, MT_RELEASE_COMPLETE, 102);
2323 pc->st->l3.l3l4(pc->st, CC_NOSETUP_RSP, pc);
2324 dss1_release_l3_process(pc);
2325 }
2326}
2327
2328static void
2329l3dss1_t304(struct l3_process *pc, u_char pr, void *arg)
2330{
2331 L3DelTimer(&pc->timer);
2332 pc->para.loc = 0;
2333 pc->para.cause = 102;
2334 l3dss1_disconnect_req(pc, pr, NULL);
2335 pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
2336
2337}
2338
2339static void
2340l3dss1_t305(struct l3_process *pc, u_char pr, void *arg)
2341{
2342 u_char tmp[16];
2343 u_char *p = tmp;
2344 int l;
2345 struct sk_buff *skb;
2346 u_char cause = 16;
2347
2348 L3DelTimer(&pc->timer);
2349 if (pc->para.cause != NO_CAUSE)
2350 cause = pc->para.cause;
2351
2352 MsgHead(p, pc->callref, MT_RELEASE);
2353
2354 *p++ = IE_CAUSE;
2355 *p++ = 0x2;
2356 *p++ = 0x80;
2357 *p++ = cause | 0x80;
2358
2359 l = p - tmp;
2360 if (!(skb = l3_alloc_skb(l)))
2361 return;
2362 memcpy(skb_put(skb, l), tmp, l);
2363 newl3state(pc, 19);
2364 l3_msg(pc->st, DL_DATA | REQUEST, skb);
2365 L3AddTimer(&pc->timer, T308, CC_T308_1);
2366}
2367
2368static void
2369l3dss1_t310(struct l3_process *pc, u_char pr, void *arg)
2370{
2371 L3DelTimer(&pc->timer);
2372 pc->para.loc = 0;
2373 pc->para.cause = 102;
2374 l3dss1_disconnect_req(pc, pr, NULL);
2375 pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
2376}
2377
2378static void
2379l3dss1_t313(struct l3_process *pc, u_char pr, void *arg)
2380{
2381 L3DelTimer(&pc->timer);
2382 pc->para.loc = 0;
2383 pc->para.cause = 102;
2384 l3dss1_disconnect_req(pc, pr, NULL);
2385 pc->st->l3.l3l4(pc->st, CC_CONNECT_ERR, pc);
2386}
2387
2388static void
2389l3dss1_t308_1(struct l3_process *pc, u_char pr, void *arg)
2390{
2391 newl3state(pc, 19);
2392 L3DelTimer(&pc->timer);
2393 l3dss1_message(pc, MT_RELEASE);
2394 L3AddTimer(&pc->timer, T308, CC_T308_2);
2395}
2396
2397static void
2398l3dss1_t308_2(struct l3_process *pc, u_char pr, void *arg)
2399{
2400 L3DelTimer(&pc->timer);
2401 pc->st->l3.l3l4(pc->st, CC_RELEASE_ERR, pc);
2402 dss1_release_l3_process(pc);
2403}
2404
2405static void
2406l3dss1_t318(struct l3_process *pc, u_char pr, void *arg)
2407{
2408 L3DelTimer(&pc->timer);
2409 pc->para.cause = 102; /* Timer expiry */
2410 pc->para.loc = 0; /* local */
2411 pc->st->l3.l3l4(pc->st, CC_RESUME_ERR, pc);
2412 newl3state(pc, 19);
2413 l3dss1_message(pc, MT_RELEASE);
2414 L3AddTimer(&pc->timer, T308, CC_T308_1);
2415}
2416
2417static void
2418l3dss1_t319(struct l3_process *pc, u_char pr, void *arg)
2419{
2420 L3DelTimer(&pc->timer);
2421 pc->para.cause = 102; /* Timer expiry */
2422 pc->para.loc = 0; /* local */
2423 pc->st->l3.l3l4(pc->st, CC_SUSPEND_ERR, pc);
2424 newl3state(pc, 10);
2425}
2426
2427static void
2428l3dss1_restart(struct l3_process *pc, u_char pr, void *arg)
2429{
2430 L3DelTimer(&pc->timer);
2431 pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
2432 dss1_release_l3_process(pc);
2433}
2434
2435static void
2436l3dss1_status(struct l3_process *pc, u_char pr, void *arg)
2437{
2438 u_char *p;
2439 struct sk_buff *skb = arg;
2440 int ret;
2441 u_char cause = 0, callState = 0;
2442
2443 if ((ret = l3dss1_get_cause(pc, skb))) {
2444 if (pc->debug & L3_DEB_WARN)
2445 l3_debug(pc->st, "STATUS get_cause ret(%d)",ret);
2446 if (ret < 0)
2447 cause = 96;
2448 else if (ret > 0)
2449 cause = 100;
2450 }
2451 if ((p = findie(skb->data, skb->len, IE_CALL_STATE, 0))) {
2452 p++;
2453 if (1 == *p++) {
2454 callState = *p;
2455 if (!ie_in_set(pc, *p, l3_valid_states))
2456 cause = 100;
2457 } else
2458 cause = 100;
2459 } else
2460 cause = 96;
2461 if (!cause) { /* no error before */
2462 ret = check_infoelements(pc, skb, ie_STATUS);
2463 if (ERR_IE_COMPREHENSION == ret)
2464 cause = 96;
2465 else if (ERR_IE_UNRECOGNIZED == ret)
2466 cause = 99;
2467 }
2468 if (cause) {
2469 u_char tmp;
2470
2471 if (pc->debug & L3_DEB_WARN)
2472 l3_debug(pc->st, "STATUS error(%d/%d)",ret,cause);
2473 tmp = pc->para.cause;
2474 pc->para.cause = cause;
2475 l3dss1_status_send(pc, 0, NULL);
2476 if (cause == 99)
2477 pc->para.cause = tmp;
2478 else
2479 return;
2480 }
2481 cause = pc->para.cause;
2482 if (((cause & 0x7f) == 111) && (callState == 0)) {
2483 /* ETS 300-104 7.6.1, 8.6.1, 10.6.1...
2484 * if received MT_STATUS with cause == 111 and call
2485 * state == 0, then we must set down layer 3
2486 */
2487 pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
2488 newl3state(pc, 0);
2489 dss1_release_l3_process(pc);
2490 }
2491}
2492
2493static void
2494l3dss1_facility(struct l3_process *pc, u_char pr, void *arg)
2495{
2496 struct sk_buff *skb = arg;
2497 int ret;
2498
2499 ret = check_infoelements(pc, skb, ie_FACILITY);
2500 l3dss1_std_ie_err(pc, ret);
2501 {
2502 u_char *p;
2503 if ((p = findie(skb->data, skb->len, IE_FACILITY, 0)))
2504 l3dss1_parse_facility(pc->st, pc, pc->callref, p);
2505 }
2506}
2507
2508static void
2509l3dss1_suspend_req(struct l3_process *pc, u_char pr, void *arg)
2510{
2511 struct sk_buff *skb;
2512 u_char tmp[32];
2513 u_char *p = tmp;
2514 u_char i, l;
2515 u_char *msg = pc->chan->setup.phone;
2516
2517 MsgHead(p, pc->callref, MT_SUSPEND);
2518 l = *msg++;
2519 if (l && (l <= 10)) { /* Max length 10 octets */
2520 *p++ = IE_CALL_ID;
2521 *p++ = l;
2522 for (i = 0; i < l; i++)
2523 *p++ = *msg++;
2524 } else if (l) {
2525 l3_debug(pc->st, "SUS wrong CALL_ID len %d", l);
2526 return;
2527 }
2528 l = p - tmp;
2529 if (!(skb = l3_alloc_skb(l)))
2530 return;
2531 memcpy(skb_put(skb, l), tmp, l);
2532 l3_msg(pc->st, DL_DATA | REQUEST, skb);
2533 newl3state(pc, 15);
2534 L3AddTimer(&pc->timer, T319, CC_T319);
2535}
2536
2537static void
2538l3dss1_suspend_ack(struct l3_process *pc, u_char pr, void *arg)
2539{
2540 struct sk_buff *skb = arg;
2541 int ret;
2542
2543 L3DelTimer(&pc->timer);
2544 newl3state(pc, 0);
2545 pc->para.cause = NO_CAUSE;
2546 pc->st->l3.l3l4(pc->st, CC_SUSPEND | CONFIRM, pc);
2547 /* We don't handle suspend_ack for IE errors now */
2548 if ((ret = check_infoelements(pc, skb, ie_SUSPEND_ACKNOWLEDGE)))
2549 if (pc->debug & L3_DEB_WARN)
2550 l3_debug(pc->st, "SUSPACK check ie(%d)",ret);
2551 dss1_release_l3_process(pc);
2552}
2553
2554static void
2555l3dss1_suspend_rej(struct l3_process *pc, u_char pr, void *arg)
2556{
2557 struct sk_buff *skb = arg;
2558 int ret;
2559
2560 if ((ret = l3dss1_get_cause(pc, skb))) {
2561 if (pc->debug & L3_DEB_WARN)
2562 l3_debug(pc->st, "SUSP_REJ get_cause ret(%d)",ret);
2563 if (ret < 0)
2564 pc->para.cause = 96;
2565 else
2566 pc->para.cause = 100;
2567 l3dss1_status_send(pc, pr, NULL);
2568 return;
2569 }
2570 ret = check_infoelements(pc, skb, ie_SUSPEND_REJECT);
2571 if (ERR_IE_COMPREHENSION == ret) {
2572 l3dss1_std_ie_err(pc, ret);
2573 return;
2574 }
2575 L3DelTimer(&pc->timer);
2576 pc->st->l3.l3l4(pc->st, CC_SUSPEND_ERR, pc);
2577 newl3state(pc, 10);
2578 if (ret) /* STATUS for none mandatory IE errors after actions are taken */
2579 l3dss1_std_ie_err(pc, ret);
2580}
2581
2582static void
2583l3dss1_resume_req(struct l3_process *pc, u_char pr, void *arg)
2584{
2585 struct sk_buff *skb;
2586 u_char tmp[32];
2587 u_char *p = tmp;
2588 u_char i, l;
2589 u_char *msg = pc->para.setup.phone;
2590
2591 MsgHead(p, pc->callref, MT_RESUME);
2592
2593 l = *msg++;
2594 if (l && (l <= 10)) { /* Max length 10 octets */
2595 *p++ = IE_CALL_ID;
2596 *p++ = l;
2597 for (i = 0; i < l; i++)
2598 *p++ = *msg++;
2599 } else if (l) {
2600 l3_debug(pc->st, "RES wrong CALL_ID len %d", l);
2601 return;
2602 }
2603 l = p - tmp;
2604 if (!(skb = l3_alloc_skb(l)))
2605 return;
2606 memcpy(skb_put(skb, l), tmp, l);
2607 l3_msg(pc->st, DL_DATA | REQUEST, skb);
2608 newl3state(pc, 17);
2609 L3AddTimer(&pc->timer, T318, CC_T318);
2610}
2611
2612static void
2613l3dss1_resume_ack(struct l3_process *pc, u_char pr, void *arg)
2614{
2615 struct sk_buff *skb = arg;
2616 int id, ret;
2617
2618 if ((id = l3dss1_get_channel_id(pc, skb)) > 0) {
2619 if ((0 == id) || ((3 == id) && (0x10 == pc->para.moderate))) {
2620 if (pc->debug & L3_DEB_WARN)
2621 l3_debug(pc->st, "resume ack with wrong chid %x", id);
2622 pc->para.cause = 100;
2623 l3dss1_status_send(pc, pr, NULL);
2624 return;
2625 }
2626 pc->para.bchannel = id;
2627 } else if (1 == pc->state) {
2628 if (pc->debug & L3_DEB_WARN)
2629 l3_debug(pc->st, "resume ack without chid (ret %d)", id);
2630 pc->para.cause = 96;
2631 l3dss1_status_send(pc, pr, NULL);
2632 return;
2633 }
2634 ret = check_infoelements(pc, skb, ie_RESUME_ACKNOWLEDGE);
2635 if (ERR_IE_COMPREHENSION == ret) {
2636 l3dss1_std_ie_err(pc, ret);
2637 return;
2638 }
2639 L3DelTimer(&pc->timer);
2640 pc->st->l3.l3l4(pc->st, CC_RESUME | CONFIRM, pc);
2641 newl3state(pc, 10);
2642 if (ret) /* STATUS for none mandatory IE errors after actions are taken */
2643 l3dss1_std_ie_err(pc, ret);
2644}
2645
2646static void
2647l3dss1_resume_rej(struct l3_process *pc, u_char pr, void *arg)
2648{
2649 struct sk_buff *skb = arg;
2650 int ret;
2651
2652 if ((ret = l3dss1_get_cause(pc, skb))) {
2653 if (pc->debug & L3_DEB_WARN)
2654 l3_debug(pc->st, "RES_REJ get_cause ret(%d)",ret);
2655 if (ret < 0)
2656 pc->para.cause = 96;
2657 else
2658 pc->para.cause = 100;
2659 l3dss1_status_send(pc, pr, NULL);
2660 return;
2661 }
2662 ret = check_infoelements(pc, skb, ie_RESUME_REJECT);
2663 if (ERR_IE_COMPREHENSION == ret) {
2664 l3dss1_std_ie_err(pc, ret);
2665 return;
2666 }
2667 L3DelTimer(&pc->timer);
2668 pc->st->l3.l3l4(pc->st, CC_RESUME_ERR, pc);
2669 newl3state(pc, 0);
2670 if (ret) /* STATUS for none mandatory IE errors after actions are taken */
2671 l3dss1_std_ie_err(pc, ret);
2672 dss1_release_l3_process(pc);
2673}
2674
2675static void
2676l3dss1_global_restart(struct l3_process *pc, u_char pr, void *arg)
2677{
2678 u_char tmp[32];
2679 u_char *p;
2680 u_char ri, ch = 0, chan = 0;
2681 int l;
2682 struct sk_buff *skb = arg;
2683 struct l3_process *up;
2684
2685 newl3state(pc, 2);
2686 L3DelTimer(&pc->timer);
2687 p = skb->data;
2688 if ((p = findie(p, skb->len, IE_RESTART_IND, 0))) {
2689 ri = p[2];
2690 l3_debug(pc->st, "Restart %x", ri);
2691 } else {
2692 l3_debug(pc->st, "Restart without restart IE");
2693 ri = 0x86;
2694 }
2695 p = skb->data;
2696 if ((p = findie(p, skb->len, IE_CHANNEL_ID, 0))) {
2697 chan = p[2] & 3;
2698 ch = p[2];
2699 if (pc->st->l3.debug)
2700 l3_debug(pc->st, "Restart for channel %d", chan);
2701 }
2702 newl3state(pc, 2);
2703 up = pc->st->l3.proc;
2704 while (up) {
2705 if ((ri & 7) == 7)
2706 up->st->lli.l4l3(up->st, CC_RESTART | REQUEST, up);
2707 else if (up->para.bchannel == chan)
2708 up->st->lli.l4l3(up->st, CC_RESTART | REQUEST, up);
2709 up = up->next;
2710 }
2711 p = tmp;
2712 MsgHead(p, pc->callref, MT_RESTART_ACKNOWLEDGE);
2713 if (chan) {
2714 *p++ = IE_CHANNEL_ID;
2715 *p++ = 1;
2716 *p++ = ch | 0x80;
2717 }
2718 *p++ = 0x79; /* RESTART Ind */
2719 *p++ = 1;
2720 *p++ = ri;
2721 l = p - tmp;
2722 if (!(skb = l3_alloc_skb(l)))
2723 return;
2724 memcpy(skb_put(skb, l), tmp, l);
2725 newl3state(pc, 0);
2726 l3_msg(pc->st, DL_DATA | REQUEST, skb);
2727}
2728
2729static void
2730l3dss1_dl_reset(struct l3_process *pc, u_char pr, void *arg)
2731{
2732 pc->para.cause = 0x29; /* Temporary failure */
2733 pc->para.loc = 0;
2734 l3dss1_disconnect_req(pc, pr, NULL);
2735 pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
2736}
2737
2738static void
2739l3dss1_dl_release(struct l3_process *pc, u_char pr, void *arg)
2740{
2741 newl3state(pc, 0);
2742 pc->para.cause = 0x1b; /* Destination out of order */
2743 pc->para.loc = 0;
2744 pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
2745 release_l3_process(pc);
2746}
2747
2748static void
2749l3dss1_dl_reestablish(struct l3_process *pc, u_char pr, void *arg)
2750{
2751 L3DelTimer(&pc->timer);
2752 L3AddTimer(&pc->timer, T309, CC_T309);
2753 l3_msg(pc->st, DL_ESTABLISH | REQUEST, NULL);
2754}
2755
2756static void
2757l3dss1_dl_reest_status(struct l3_process *pc, u_char pr, void *arg)
2758{
2759 L3DelTimer(&pc->timer);
2760
2761 pc->para.cause = 0x1F; /* normal, unspecified */
2762 l3dss1_status_send(pc, 0, NULL);
2763}
2764
2765/* *INDENT-OFF* */
2766static struct stateentry downstatelist[] =
2767{
2768 {SBIT(0),
2769 CC_SETUP | REQUEST, l3dss1_setup_req},
2770 {SBIT(0),
2771 CC_RESUME | REQUEST, l3dss1_resume_req},
2772 {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(6) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(25),
2773 CC_DISCONNECT | REQUEST, l3dss1_disconnect_req},
2774 {SBIT(12),
2775 CC_RELEASE | REQUEST, l3dss1_release_req},
2776 {ALL_STATES,
2777 CC_RESTART | REQUEST, l3dss1_restart},
2778 {SBIT(6) | SBIT(25),
2779 CC_IGNORE | REQUEST, l3dss1_reset},
2780 {SBIT(6) | SBIT(25),
2781 CC_REJECT | REQUEST, l3dss1_reject_req},
2782 {SBIT(6) | SBIT(25),
2783 CC_PROCEED_SEND | REQUEST, l3dss1_proceed_req},
2784 {SBIT(6),
2785 CC_MORE_INFO | REQUEST, l3dss1_setup_ack_req},
2786 {SBIT(25),
2787 CC_MORE_INFO | REQUEST, l3dss1_dummy},
2788 {SBIT(6) | SBIT(9) | SBIT(25),
2789 CC_ALERTING | REQUEST, l3dss1_alert_req},
2790 {SBIT(6) | SBIT(7) | SBIT(9) | SBIT(25),
2791 CC_SETUP | RESPONSE, l3dss1_setup_rsp},
2792 {SBIT(10),
2793 CC_SUSPEND | REQUEST, l3dss1_suspend_req},
2794 {SBIT(7) | SBIT(9) | SBIT(25),
2795 CC_REDIR | REQUEST, l3dss1_redir_req},
2796 {SBIT(6),
2797 CC_REDIR | REQUEST, l3dss1_redir_req_early},
2798 {SBIT(9) | SBIT(25),
2799 CC_DISCONNECT | REQUEST, l3dss1_disconnect_req},
2800 {SBIT(25),
2801 CC_T302, l3dss1_t302},
2802 {SBIT(1),
2803 CC_T303, l3dss1_t303},
2804 {SBIT(2),
2805 CC_T304, l3dss1_t304},
2806 {SBIT(3),
2807 CC_T310, l3dss1_t310},
2808 {SBIT(8),
2809 CC_T313, l3dss1_t313},
2810 {SBIT(11),
2811 CC_T305, l3dss1_t305},
2812 {SBIT(15),
2813 CC_T319, l3dss1_t319},
2814 {SBIT(17),
2815 CC_T318, l3dss1_t318},
2816 {SBIT(19),
2817 CC_T308_1, l3dss1_t308_1},
2818 {SBIT(19),
2819 CC_T308_2, l3dss1_t308_2},
2820 {SBIT(10),
2821 CC_T309, l3dss1_dl_release},
2822};
2823
2824#define DOWNSLLEN \
2825 (sizeof(downstatelist) / sizeof(struct stateentry))
2826
2827static struct stateentry datastatelist[] =
2828{
2829 {ALL_STATES,
2830 MT_STATUS_ENQUIRY, l3dss1_status_enq},
2831 {ALL_STATES,
2832 MT_FACILITY, l3dss1_facility},
2833 {SBIT(19),
2834 MT_STATUS, l3dss1_release_ind},
2835 {ALL_STATES,
2836 MT_STATUS, l3dss1_status},
2837 {SBIT(0),
2838 MT_SETUP, l3dss1_setup},
2839 {SBIT(6) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(11) | SBIT(12) |
2840 SBIT(15) | SBIT(17) | SBIT(19) | SBIT(25),
2841 MT_SETUP, l3dss1_dummy},
2842 {SBIT(1) | SBIT(2),
2843 MT_CALL_PROCEEDING, l3dss1_call_proc},
2844 {SBIT(1),
2845 MT_SETUP_ACKNOWLEDGE, l3dss1_setup_ack},
2846 {SBIT(2) | SBIT(3),
2847 MT_ALERTING, l3dss1_alerting},
2848 {SBIT(2) | SBIT(3),
2849 MT_PROGRESS, l3dss1_progress},
2850 {SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) |
2851 SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(19) | SBIT(25),
2852 MT_INFORMATION, l3dss1_information},
2853 {SBIT(10) | SBIT(11) | SBIT(15),
2854 MT_NOTIFY, l3dss1_notify},
2855 {SBIT(0) | SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(10) |
2856 SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(19) | SBIT(25),
2857 MT_RELEASE_COMPLETE, l3dss1_release_cmpl},
2858 {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(25),
2859 MT_RELEASE, l3dss1_release},
2860 {SBIT(19), MT_RELEASE, l3dss1_release_ind},
2861 {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(11) | SBIT(15) | SBIT(17) | SBIT(25),
2862 MT_DISCONNECT, l3dss1_disconnect},
2863 {SBIT(19),
2864 MT_DISCONNECT, l3dss1_dummy},
2865 {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4),
2866 MT_CONNECT, l3dss1_connect},
2867 {SBIT(8),
2868 MT_CONNECT_ACKNOWLEDGE, l3dss1_connect_ack},
2869 {SBIT(15),
2870 MT_SUSPEND_ACKNOWLEDGE, l3dss1_suspend_ack},
2871 {SBIT(15),
2872 MT_SUSPEND_REJECT, l3dss1_suspend_rej},
2873 {SBIT(17),
2874 MT_RESUME_ACKNOWLEDGE, l3dss1_resume_ack},
2875 {SBIT(17),
2876 MT_RESUME_REJECT, l3dss1_resume_rej},
2877};
2878
2879#define DATASLLEN \
2880 (sizeof(datastatelist) / sizeof(struct stateentry))
2881
2882static struct stateentry globalmes_list[] =
2883{
2884 {ALL_STATES,
2885 MT_STATUS, l3dss1_status},
2886 {SBIT(0),
2887 MT_RESTART, l3dss1_global_restart},
2888/* {SBIT(1),
2889 MT_RESTART_ACKNOWLEDGE, l3dss1_restart_ack},
2890*/
2891};
2892#define GLOBALM_LEN \
2893 (sizeof(globalmes_list) / sizeof(struct stateentry))
2894
2895static struct stateentry manstatelist[] =
2896{
2897 {SBIT(2),
2898 DL_ESTABLISH | INDICATION, l3dss1_dl_reset},
2899 {SBIT(10),
2900 DL_ESTABLISH | CONFIRM, l3dss1_dl_reest_status},
2901 {SBIT(10),
2902 DL_RELEASE | INDICATION, l3dss1_dl_reestablish},
2903 {ALL_STATES,
2904 DL_RELEASE | INDICATION, l3dss1_dl_release},
2905};
2906
2907#define MANSLLEN \
2908 (sizeof(manstatelist) / sizeof(struct stateentry))
2909/* *INDENT-ON* */
2910
2911
2912static void
2913global_handler(struct PStack *st, int mt, struct sk_buff *skb)
2914{
2915 u_char tmp[16];
2916 u_char *p = tmp;
2917 int l;
2918 int i;
2919 struct l3_process *proc = st->l3.global;
2920
2921 proc->callref = skb->data[2]; /* cr flag */
2922 for (i = 0; i < GLOBALM_LEN; i++)
2923 if ((mt == globalmes_list[i].primitive) &&
2924 ((1 << proc->state) & globalmes_list[i].state))
2925 break;
2926 if (i == GLOBALM_LEN) {
2927 if (st->l3.debug & L3_DEB_STATE) {
2928 l3_debug(st, "dss1 global state %d mt %x unhandled",
2929 proc->state, mt);
2930 }
2931 MsgHead(p, proc->callref, MT_STATUS);
2932 *p++ = IE_CAUSE;
2933 *p++ = 0x2;
2934 *p++ = 0x80;
2935 *p++ = 81 |0x80; /* invalid cr */
2936 *p++ = 0x14; /* CallState */
2937 *p++ = 0x1;
2938 *p++ = proc->state & 0x3f;
2939 l = p - tmp;
2940 if (!(skb = l3_alloc_skb(l)))
2941 return;
2942 memcpy(skb_put(skb, l), tmp, l);
2943 l3_msg(proc->st, DL_DATA | REQUEST, skb);
2944 } else {
2945 if (st->l3.debug & L3_DEB_STATE) {
2946 l3_debug(st, "dss1 global %d mt %x",
2947 proc->state, mt);
2948 }
2949 globalmes_list[i].rout(proc, mt, skb);
2950 }
2951}
2952
2953static void
2954dss1up(struct PStack *st, int pr, void *arg)
2955{
2956 int i, mt, cr, cause, callState;
2957 char *ptr;
2958 u_char *p;
2959 struct sk_buff *skb = arg;
2960 struct l3_process *proc;
2961
2962 switch (pr) {
2963 case (DL_DATA | INDICATION):
2964 case (DL_UNIT_DATA | INDICATION):
2965 break;
2966 case (DL_ESTABLISH | CONFIRM):
2967 case (DL_ESTABLISH | INDICATION):
2968 case (DL_RELEASE | INDICATION):
2969 case (DL_RELEASE | CONFIRM):
2970 l3_msg(st, pr, arg);
2971 return;
2972 break;
2973 default:
2974 printk(KERN_ERR "HiSax dss1up unknown pr=%04x\n", pr);
2975 return;
2976 }
2977 if (skb->len < 3) {
2978 l3_debug(st, "dss1up frame too short(%d)", skb->len);
2979 dev_kfree_skb(skb);
2980 return;
2981 }
2982
2983 if (skb->data[0] != PROTO_DIS_EURO) {
2984 if (st->l3.debug & L3_DEB_PROTERR) {
2985 l3_debug(st, "dss1up%sunexpected discriminator %x message len %d",
2986 (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ",
2987 skb->data[0], skb->len);
2988 }
2989 dev_kfree_skb(skb);
2990 return;
2991 }
2992 cr = getcallref(skb->data);
2993 if (skb->len < ((skb->data[1] & 0x0f) + 3)) {
2994 l3_debug(st, "dss1up frame too short(%d)", skb->len);
2995 dev_kfree_skb(skb);
2996 return;
2997 }
2998 mt = skb->data[skb->data[1] + 2];
2999 if (st->l3.debug & L3_DEB_STATE)
3000 l3_debug(st, "dss1up cr %d", cr);
3001 if (cr == -2) { /* wrong Callref */
3002 if (st->l3.debug & L3_DEB_WARN)
3003 l3_debug(st, "dss1up wrong Callref");
3004 dev_kfree_skb(skb);
3005 return;
3006 } else if (cr == -1) { /* Dummy Callref */
3007 if (mt == MT_FACILITY)
3008 if ((p = findie(skb->data, skb->len, IE_FACILITY, 0))) {
3009 l3dss1_parse_facility(st, NULL,
3010 (pr == (DL_DATA | INDICATION)) ? -1 : -2, p);
3011 dev_kfree_skb(skb);
3012 return;
3013 }
3014 if (st->l3.debug & L3_DEB_WARN)
3015 l3_debug(st, "dss1up dummy Callref (no facility msg or ie)");
3016 dev_kfree_skb(skb);
3017 return;
3018 } else if ((((skb->data[1] & 0x0f) == 1) && (0==(cr & 0x7f))) ||
3019 (((skb->data[1] & 0x0f) == 2) && (0==(cr & 0x7fff)))) { /* Global CallRef */
3020 if (st->l3.debug & L3_DEB_STATE)
3021 l3_debug(st, "dss1up Global CallRef");
3022 global_handler(st, mt, skb);
3023 dev_kfree_skb(skb);
3024 return;
3025 } else if (!(proc = getl3proc(st, cr))) {
3026 /* No transaction process exist, that means no call with
3027 * this callreference is active
3028 */
3029 if (mt == MT_SETUP) {
3030 /* Setup creates a new transaction process */
3031 if (skb->data[2] & 0x80) {
3032 /* Setup with wrong CREF flag */
3033 if (st->l3.debug & L3_DEB_STATE)
3034 l3_debug(st, "dss1up wrong CRef flag");
3035 dev_kfree_skb(skb);
3036 return;
3037 }
3038 if (!(proc = dss1_new_l3_process(st, cr))) {
3039 /* May be to answer with RELEASE_COMPLETE and
3040 * CAUSE 0x2f "Resource unavailable", but this
3041 * need a new_l3_process too ... arghh
3042 */
3043 dev_kfree_skb(skb);
3044 return;
3045 }
3046 } else if (mt == MT_STATUS) {
3047 cause = 0;
3048 if ((ptr = findie(skb->data, skb->len, IE_CAUSE, 0)) != NULL) {
3049 ptr++;
3050 if (*ptr++ == 2)
3051 ptr++;
3052 cause = *ptr & 0x7f;
3053 }
3054 callState = 0;
3055 if ((ptr = findie(skb->data, skb->len, IE_CALL_STATE, 0)) != NULL) {
3056 ptr++;
3057 if (*ptr++ == 2)
3058 ptr++;
3059 callState = *ptr;
3060 }
3061 /* ETS 300-104 part 2.4.1
3062 * if setup has not been made and a message type
3063 * MT_STATUS is received with call state == 0,
3064 * we must send nothing
3065 */
3066 if (callState != 0) {
3067 /* ETS 300-104 part 2.4.2
3068 * if setup has not been made and a message type
3069 * MT_STATUS is received with call state != 0,
3070 * we must send MT_RELEASE_COMPLETE cause 101
3071 */
3072 if ((proc = dss1_new_l3_process(st, cr))) {
3073 proc->para.cause = 101;
3074 l3dss1_msg_without_setup(proc, 0, NULL);
3075 }
3076 }
3077 dev_kfree_skb(skb);
3078 return;
3079 } else if (mt == MT_RELEASE_COMPLETE) {
3080 dev_kfree_skb(skb);
3081 return;
3082 } else {
3083 /* ETS 300-104 part 2
3084 * if setup has not been made and a message type
3085 * (except MT_SETUP and RELEASE_COMPLETE) is received,
3086 * we must send MT_RELEASE_COMPLETE cause 81 */
3087 dev_kfree_skb(skb);
3088 if ((proc = dss1_new_l3_process(st, cr))) {
3089 proc->para.cause = 81;
3090 l3dss1_msg_without_setup(proc, 0, NULL);
3091 }
3092 return;
3093 }
3094 }
3095 if (l3dss1_check_messagetype_validity(proc, mt, skb)) {
3096 dev_kfree_skb(skb);
3097 return;
3098 }
3099 if ((p = findie(skb->data, skb->len, IE_DISPLAY, 0)) != NULL)
3100 l3dss1_deliver_display(proc, pr, p); /* Display IE included */
3101 for (i = 0; i < DATASLLEN; i++)
3102 if ((mt == datastatelist[i].primitive) &&
3103 ((1 << proc->state) & datastatelist[i].state))
3104 break;
3105 if (i == DATASLLEN) {
3106 if (st->l3.debug & L3_DEB_STATE) {
3107 l3_debug(st, "dss1up%sstate %d mt %#x unhandled",
3108 (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ",
3109 proc->state, mt);
3110 }
3111 if ((MT_RELEASE_COMPLETE != mt) && (MT_RELEASE != mt)) {
3112 proc->para.cause = 101;
3113 l3dss1_status_send(proc, pr, skb);
3114 }
3115 } else {
3116 if (st->l3.debug & L3_DEB_STATE) {
3117 l3_debug(st, "dss1up%sstate %d mt %x",
3118 (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ",
3119 proc->state, mt);
3120 }
3121 datastatelist[i].rout(proc, pr, skb);
3122 }
3123 dev_kfree_skb(skb);
3124 return;
3125}
3126
3127static void
3128dss1down(struct PStack *st, int pr, void *arg)
3129{
3130 int i, cr;
3131 struct l3_process *proc;
3132 struct Channel *chan;
3133
3134 if ((DL_ESTABLISH | REQUEST) == pr) {
3135 l3_msg(st, pr, NULL);
3136 return;
3137 } else if (((CC_SETUP | REQUEST) == pr) || ((CC_RESUME | REQUEST) == pr)) {
3138 chan = arg;
3139 cr = newcallref();
3140 cr |= 0x80;
3141 if ((proc = dss1_new_l3_process(st, cr))) {
3142 proc->chan = chan;
3143 chan->proc = proc;
3144 memcpy(&proc->para.setup, &chan->setup, sizeof(setup_parm));
3145 proc->callref = cr;
3146 }
3147 } else {
3148 proc = arg;
3149 }
3150 if (!proc) {
3151 printk(KERN_ERR "HiSax dss1down without proc pr=%04x\n", pr);
3152 return;
3153 }
3154
3155 if ( pr == (CC_TDSS1_IO | REQUEST)) {
3156 l3dss1_io_timer(proc); /* timer expires */
3157 return;
3158 }
3159
3160 for (i = 0; i < DOWNSLLEN; i++)
3161 if ((pr == downstatelist[i].primitive) &&
3162 ((1 << proc->state) & downstatelist[i].state))
3163 break;
3164 if (i == DOWNSLLEN) {
3165 if (st->l3.debug & L3_DEB_STATE) {
3166 l3_debug(st, "dss1down state %d prim %#x unhandled",
3167 proc->state, pr);
3168 }
3169 } else {
3170 if (st->l3.debug & L3_DEB_STATE) {
3171 l3_debug(st, "dss1down state %d prim %#x",
3172 proc->state, pr);
3173 }
3174 downstatelist[i].rout(proc, pr, arg);
3175 }
3176}
3177
3178static void
3179dss1man(struct PStack *st, int pr, void *arg)
3180{
3181 int i;
3182 struct l3_process *proc = arg;
3183
3184 if (!proc) {
3185 printk(KERN_ERR "HiSax dss1man without proc pr=%04x\n", pr);
3186 return;
3187 }
3188 for (i = 0; i < MANSLLEN; i++)
3189 if ((pr == manstatelist[i].primitive) &&
3190 ((1 << proc->state) & manstatelist[i].state))
3191 break;
3192 if (i == MANSLLEN) {
3193 if (st->l3.debug & L3_DEB_STATE) {
3194 l3_debug(st, "cr %d dss1man state %d prim %#x unhandled",
3195 proc->callref & 0x7f, proc->state, pr);
3196 }
3197 } else {
3198 if (st->l3.debug & L3_DEB_STATE) {
3199 l3_debug(st, "cr %d dss1man state %d prim %#x",
3200 proc->callref & 0x7f, proc->state, pr);
3201 }
3202 manstatelist[i].rout(proc, pr, arg);
3203 }
3204}
3205
3206void
3207setstack_dss1(struct PStack *st)
3208{
3209 char tmp[64];
3210 int i;
3211
3212 st->lli.l4l3 = dss1down;
3213 st->lli.l4l3_proto = l3dss1_cmd_global;
3214 st->l2.l2l3 = dss1up;
3215 st->l3.l3ml3 = dss1man;
3216 st->l3.N303 = 1;
3217 st->prot.dss1.last_invoke_id = 0;
3218 st->prot.dss1.invoke_used[0] = 1; /* Bit 0 must always be set to 1 */
3219 i = 1;
3220 while (i < 32)
3221 st->prot.dss1.invoke_used[i++] = 0;
3222
3223 if (!(st->l3.global = kmalloc(sizeof(struct l3_process), GFP_ATOMIC))) {
3224 printk(KERN_ERR "HiSax can't get memory for dss1 global CR\n");
3225 } else {
3226 st->l3.global->state = 0;
3227 st->l3.global->callref = 0;
3228 st->l3.global->next = NULL;
3229 st->l3.global->debug = L3_DEB_WARN;
3230 st->l3.global->st = st;
3231 st->l3.global->N303 = 1;
3232 st->l3.global->prot.dss1.invoke_id = 0;
3233
3234 L3InitTimer(st->l3.global, &st->l3.global->timer);
3235 }
3236 strcpy(tmp, dss1_revision);
3237 printk(KERN_INFO "HiSax: DSS1 Rev. %s\n", HiSax_getrev(tmp));
3238}
diff --git a/drivers/isdn/hisax/l3dss1.h b/drivers/isdn/hisax/l3dss1.h
new file mode 100644
index 000000000000..6da47f05ef2a
--- /dev/null
+++ b/drivers/isdn/hisax/l3dss1.h
@@ -0,0 +1,124 @@
1/* $Id: l3dss1.h,v 1.10.6.2 2001/09/23 22:24:50 kai Exp $
2 *
3 * DSS1 (Euro) D-channel protocol defines
4 *
5 * This software may be used and distributed according to the terms
6 * of the GNU General Public License, incorporated herein by reference.
7 *
8 */
9
10#ifndef l3dss1_process
11
12#define T302 15000
13#define T303 4000
14#define T304 30000
15#define T305 30000
16#define T308 4000
17/* for layer 1 certification T309 < layer1 T3 (e.g. 4000) */
18/* This makes some tests easier and quicker */
19#define T309 40000
20#define T310 30000
21#define T313 4000
22#define T318 4000
23#define T319 4000
24
25/*
26 * Message-Types
27 */
28
29#define MT_ALERTING 0x01
30#define MT_CALL_PROCEEDING 0x02
31#define MT_CONNECT 0x07
32#define MT_CONNECT_ACKNOWLEDGE 0x0f
33#define MT_PROGRESS 0x03
34#define MT_SETUP 0x05
35#define MT_SETUP_ACKNOWLEDGE 0x0d
36#define MT_RESUME 0x26
37#define MT_RESUME_ACKNOWLEDGE 0x2e
38#define MT_RESUME_REJECT 0x22
39#define MT_SUSPEND 0x25
40#define MT_SUSPEND_ACKNOWLEDGE 0x2d
41#define MT_SUSPEND_REJECT 0x21
42#define MT_USER_INFORMATION 0x20
43#define MT_DISCONNECT 0x45
44#define MT_RELEASE 0x4d
45#define MT_RELEASE_COMPLETE 0x5a
46#define MT_RESTART 0x46
47#define MT_RESTART_ACKNOWLEDGE 0x4e
48#define MT_SEGMENT 0x60
49#define MT_CONGESTION_CONTROL 0x79
50#define MT_INFORMATION 0x7b
51#define MT_FACILITY 0x62
52#define MT_NOTIFY 0x6e
53#define MT_STATUS 0x7d
54#define MT_STATUS_ENQUIRY 0x75
55
56#define IE_SEGMENT 0x00
57#define IE_BEARER 0x04
58#define IE_CAUSE 0x08
59#define IE_CALL_ID 0x10
60#define IE_CALL_STATE 0x14
61#define IE_CHANNEL_ID 0x18
62#define IE_FACILITY 0x1c
63#define IE_PROGRESS 0x1e
64#define IE_NET_FAC 0x20
65#define IE_NOTIFY 0x27
66#define IE_DISPLAY 0x28
67#define IE_DATE 0x29
68#define IE_KEYPAD 0x2c
69#define IE_SIGNAL 0x34
70#define IE_INFORATE 0x40
71#define IE_E2E_TDELAY 0x42
72#define IE_TDELAY_SEL 0x43
73#define IE_PACK_BINPARA 0x44
74#define IE_PACK_WINSIZE 0x45
75#define IE_PACK_SIZE 0x46
76#define IE_CUG 0x47
77#define IE_REV_CHARGE 0x4a
78#define IE_CONNECT_PN 0x4c
79#define IE_CONNECT_SUB 0x4d
80#define IE_CALLING_PN 0x6c
81#define IE_CALLING_SUB 0x6d
82#define IE_CALLED_PN 0x70
83#define IE_CALLED_SUB 0x71
84#define IE_REDIR_NR 0x74
85#define IE_TRANS_SEL 0x78
86#define IE_RESTART_IND 0x79
87#define IE_LLC 0x7c
88#define IE_HLC 0x7d
89#define IE_USER_USER 0x7e
90#define IE_ESCAPE 0x7f
91#define IE_SHIFT 0x90
92#define IE_MORE_DATA 0xa0
93#define IE_COMPLETE 0xa1
94#define IE_CONGESTION 0xb0
95#define IE_REPEAT 0xd0
96
97#define IE_MANDATORY 0x0100
98/* mandatory not in every case */
99#define IE_MANDATORY_1 0x0200
100
101#define ERR_IE_COMPREHENSION 1
102#define ERR_IE_UNRECOGNIZED -1
103#define ERR_IE_LENGTH -2
104#define ERR_IE_SEQUENCE -3
105
106#else /* only l3dss1_process */
107
108/* l3dss1 specific data in l3 process */
109typedef struct
110 { unsigned char invoke_id; /* used invoke id in remote ops, 0 = not active */
111 ulong ll_id; /* remebered ll id */
112 u8 remote_operation; /* handled remote operation, 0 = not active */
113 int proc; /* rememered procedure */
114 ulong remote_result; /* result of remote operation for statcallb */
115 char uus1_data[35]; /* data send during alerting or disconnect */
116 } dss1_proc_priv;
117
118/* l3dss1 specific data in protocol stack */
119typedef struct
120 { unsigned char last_invoke_id; /* last used value for invoking */
121 unsigned char invoke_used[32]; /* 256 bits for 256 values */
122 } dss1_stk_priv;
123
124#endif /* only l3dss1_process */
diff --git a/drivers/isdn/hisax/l3ni1.c b/drivers/isdn/hisax/l3ni1.c
new file mode 100644
index 000000000000..3ab3a54daac1
--- /dev/null
+++ b/drivers/isdn/hisax/l3ni1.c
@@ -0,0 +1,3189 @@
1/* $Id: l3ni1.c,v 2.8.2.3 2004/01/13 14:31:25 keil Exp $
2 *
3 * NI1 D-channel protocol
4 *
5 * Author Matt Henderson & Guy Ellis
6 * Copyright by Traverse Technologies Pty Ltd, www.travers.com.au
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 * 2000.6.6 Initial implementation of routines for US NI1
12 * Layer 3 protocol based on the EURO/DSS1 D-channel protocol
13 * driver written by Karsten Keil et al.
14 * NI-1 Hall of Fame - Thanks to....
15 * Ragnar Paulson - for some handy code fragments
16 * Will Scales - beta tester extraordinaire
17 * Brett Whittacre - beta tester and remote devel system in Vegas
18 *
19 */
20
21#include "hisax.h"
22#include "isdnl3.h"
23#include "l3ni1.h"
24#include <linux/ctype.h>
25
26extern char *HiSax_getrev(const char *revision);
27const char *ni1_revision = "$Revision: 2.8.2.3 $";
28
29#define EXT_BEARER_CAPS 1
30
31#define MsgHead(ptr, cref, mty) \
32 *ptr++ = 0x8; \
33 if (cref == -1) { \
34 *ptr++ = 0x0; \
35 } else { \
36 *ptr++ = 0x1; \
37 *ptr++ = cref^0x80; \
38 } \
39 *ptr++ = mty
40
41
42/**********************************************/
43/* get a new invoke id for remote operations. */
44/* Only a return value != 0 is valid */
45/**********************************************/
46static unsigned char new_invoke_id(struct PStack *p)
47{
48 unsigned char retval;
49 int i;
50
51 i = 32; /* maximum search depth */
52
53 retval = p->prot.ni1.last_invoke_id + 1; /* try new id */
54 while ((i) && (p->prot.ni1.invoke_used[retval >> 3] == 0xFF)) {
55 p->prot.ni1.last_invoke_id = (retval & 0xF8) + 8;
56 i--;
57 }
58 if (i) {
59 while (p->prot.ni1.invoke_used[retval >> 3] & (1 << (retval & 7)))
60 retval++;
61 } else
62 retval = 0;
63 p->prot.ni1.last_invoke_id = retval;
64 p->prot.ni1.invoke_used[retval >> 3] |= (1 << (retval & 7));
65 return(retval);
66} /* new_invoke_id */
67
68/*************************/
69/* free a used invoke id */
70/*************************/
71static void free_invoke_id(struct PStack *p, unsigned char id)
72{
73
74 if (!id) return; /* 0 = invalid value */
75
76 p->prot.ni1.invoke_used[id >> 3] &= ~(1 << (id & 7));
77} /* free_invoke_id */
78
79
80/**********************************************************/
81/* create a new l3 process and fill in ni1 specific data */
82/**********************************************************/
83static struct l3_process
84*ni1_new_l3_process(struct PStack *st, int cr)
85{ struct l3_process *proc;
86
87 if (!(proc = new_l3_process(st, cr)))
88 return(NULL);
89
90 proc->prot.ni1.invoke_id = 0;
91 proc->prot.ni1.remote_operation = 0;
92 proc->prot.ni1.uus1_data[0] = '\0';
93
94 return(proc);
95} /* ni1_new_l3_process */
96
97/************************************************/
98/* free a l3 process and all ni1 specific data */
99/************************************************/
100static void
101ni1_release_l3_process(struct l3_process *p)
102{
103 free_invoke_id(p->st,p->prot.ni1.invoke_id);
104 release_l3_process(p);
105} /* ni1_release_l3_process */
106
107/********************************************************/
108/* search a process with invoke id id and dummy callref */
109/********************************************************/
110static struct l3_process *
111l3ni1_search_dummy_proc(struct PStack *st, int id)
112{ struct l3_process *pc = st->l3.proc; /* start of processes */
113
114 if (!id) return(NULL);
115
116 while (pc)
117 { if ((pc->callref == -1) && (pc->prot.ni1.invoke_id == id))
118 return(pc);
119 pc = pc->next;
120 }
121 return(NULL);
122} /* l3ni1_search_dummy_proc */
123
124/*******************************************************************/
125/* called when a facility message with a dummy callref is received */
126/* and a return result is delivered. id specifies the invoke id. */
127/*******************************************************************/
128static void
129l3ni1_dummy_return_result(struct PStack *st, int id, u_char *p, u_char nlen)
130{ isdn_ctrl ic;
131 struct IsdnCardState *cs;
132 struct l3_process *pc = NULL;
133
134 if ((pc = l3ni1_search_dummy_proc(st, id)))
135 { L3DelTimer(&pc->timer); /* remove timer */
136
137 cs = pc->st->l1.hardware;
138 ic.driver = cs->myid;
139 ic.command = ISDN_STAT_PROT;
140 ic.arg = NI1_STAT_INVOKE_RES;
141 ic.parm.ni1_io.hl_id = pc->prot.ni1.invoke_id;
142 ic.parm.ni1_io.ll_id = pc->prot.ni1.ll_id;
143 ic.parm.ni1_io.proc = pc->prot.ni1.proc;
144 ic.parm.ni1_io.timeout= 0;
145 ic.parm.ni1_io.datalen = nlen;
146 ic.parm.ni1_io.data = p;
147 free_invoke_id(pc->st, pc->prot.ni1.invoke_id);
148 pc->prot.ni1.invoke_id = 0; /* reset id */
149
150 cs->iif.statcallb(&ic);
151 ni1_release_l3_process(pc);
152 }
153 else
154 l3_debug(st, "dummy return result id=0x%x result len=%d",id,nlen);
155} /* l3ni1_dummy_return_result */
156
157/*******************************************************************/
158/* called when a facility message with a dummy callref is received */
159/* and a return error is delivered. id specifies the invoke id. */
160/*******************************************************************/
161static void
162l3ni1_dummy_error_return(struct PStack *st, int id, ulong error)
163{ isdn_ctrl ic;
164 struct IsdnCardState *cs;
165 struct l3_process *pc = NULL;
166
167 if ((pc = l3ni1_search_dummy_proc(st, id)))
168 { L3DelTimer(&pc->timer); /* remove timer */
169
170 cs = pc->st->l1.hardware;
171 ic.driver = cs->myid;
172 ic.command = ISDN_STAT_PROT;
173 ic.arg = NI1_STAT_INVOKE_ERR;
174 ic.parm.ni1_io.hl_id = pc->prot.ni1.invoke_id;
175 ic.parm.ni1_io.ll_id = pc->prot.ni1.ll_id;
176 ic.parm.ni1_io.proc = pc->prot.ni1.proc;
177 ic.parm.ni1_io.timeout= error;
178 ic.parm.ni1_io.datalen = 0;
179 ic.parm.ni1_io.data = NULL;
180 free_invoke_id(pc->st, pc->prot.ni1.invoke_id);
181 pc->prot.ni1.invoke_id = 0; /* reset id */
182
183 cs->iif.statcallb(&ic);
184 ni1_release_l3_process(pc);
185 }
186 else
187 l3_debug(st, "dummy return error id=0x%x error=0x%lx",id,error);
188} /* l3ni1_error_return */
189
190/*******************************************************************/
191/* called when a facility message with a dummy callref is received */
192/* and a invoke is delivered. id specifies the invoke id. */
193/*******************************************************************/
194static void
195l3ni1_dummy_invoke(struct PStack *st, int cr, int id,
196 int ident, u_char *p, u_char nlen)
197{ isdn_ctrl ic;
198 struct IsdnCardState *cs;
199
200 l3_debug(st, "dummy invoke %s id=0x%x ident=0x%x datalen=%d",
201 (cr == -1) ? "local" : "broadcast",id,ident,nlen);
202 if (cr >= -1) return; /* ignore local data */
203
204 cs = st->l1.hardware;
205 ic.driver = cs->myid;
206 ic.command = ISDN_STAT_PROT;
207 ic.arg = NI1_STAT_INVOKE_BRD;
208 ic.parm.ni1_io.hl_id = id;
209 ic.parm.ni1_io.ll_id = 0;
210 ic.parm.ni1_io.proc = ident;
211 ic.parm.ni1_io.timeout= 0;
212 ic.parm.ni1_io.datalen = nlen;
213 ic.parm.ni1_io.data = p;
214
215 cs->iif.statcallb(&ic);
216} /* l3ni1_dummy_invoke */
217
218static void
219l3ni1_parse_facility(struct PStack *st, struct l3_process *pc,
220 int cr, u_char * p)
221{
222 int qd_len = 0;
223 unsigned char nlen = 0, ilen, cp_tag;
224 int ident, id;
225 ulong err_ret;
226
227 if (pc)
228 st = pc->st; /* valid Stack */
229 else
230 if ((!st) || (cr >= 0)) return; /* neither pc nor st specified */
231
232 p++;
233 qd_len = *p++;
234 if (qd_len == 0) {
235 l3_debug(st, "qd_len == 0");
236 return;
237 }
238 if ((*p & 0x1F) != 0x11) { /* Service discriminator, supplementary service */
239 l3_debug(st, "supplementary service != 0x11");
240 return;
241 }
242 while (qd_len > 0 && !(*p & 0x80)) { /* extension ? */
243 p++;
244 qd_len--;
245 }
246 if (qd_len < 2) {
247 l3_debug(st, "qd_len < 2");
248 return;
249 }
250 p++;
251 qd_len--;
252 if ((*p & 0xE0) != 0xA0) { /* class and form */
253 l3_debug(st, "class and form != 0xA0");
254 return;
255 }
256
257 cp_tag = *p & 0x1F; /* remember tag value */
258
259 p++;
260 qd_len--;
261 if (qd_len < 1)
262 { l3_debug(st, "qd_len < 1");
263 return;
264 }
265 if (*p & 0x80)
266 { /* length format indefinite or limited */
267 nlen = *p++ & 0x7F; /* number of len bytes or indefinite */
268 if ((qd_len-- < ((!nlen) ? 3 : (1 + nlen))) ||
269 (nlen > 1))
270 { l3_debug(st, "length format error or not implemented");
271 return;
272 }
273 if (nlen == 1)
274 { nlen = *p++; /* complete length */
275 qd_len--;
276 }
277 else
278 { qd_len -= 2; /* trailing null bytes */
279 if ((*(p+qd_len)) || (*(p+qd_len+1)))
280 { l3_debug(st,"length format indefinite error");
281 return;
282 }
283 nlen = qd_len;
284 }
285 }
286 else
287 { nlen = *p++;
288 qd_len--;
289 }
290 if (qd_len < nlen)
291 { l3_debug(st, "qd_len < nlen");
292 return;
293 }
294 qd_len -= nlen;
295
296 if (nlen < 2)
297 { l3_debug(st, "nlen < 2");
298 return;
299 }
300 if (*p != 0x02)
301 { /* invoke identifier tag */
302 l3_debug(st, "invoke identifier tag !=0x02");
303 return;
304 }
305 p++;
306 nlen--;
307 if (*p & 0x80)
308 { /* length format */
309 l3_debug(st, "invoke id length format 2");
310 return;
311 }
312 ilen = *p++;
313 nlen--;
314 if (ilen > nlen || ilen == 0)
315 { l3_debug(st, "ilen > nlen || ilen == 0");
316 return;
317 }
318 nlen -= ilen;
319 id = 0;
320 while (ilen > 0)
321 { id = (id << 8) | (*p++ & 0xFF); /* invoke identifier */
322 ilen--;
323 }
324
325 switch (cp_tag) { /* component tag */
326 case 1: /* invoke */
327 if (nlen < 2) {
328 l3_debug(st, "nlen < 2 22");
329 return;
330 }
331 if (*p != 0x02) { /* operation value */
332 l3_debug(st, "operation value !=0x02");
333 return;
334 }
335 p++;
336 nlen--;
337 ilen = *p++;
338 nlen--;
339 if (ilen > nlen || ilen == 0) {
340 l3_debug(st, "ilen > nlen || ilen == 0 22");
341 return;
342 }
343 nlen -= ilen;
344 ident = 0;
345 while (ilen > 0) {
346 ident = (ident << 8) | (*p++ & 0xFF);
347 ilen--;
348 }
349
350 if (!pc)
351 {
352 l3ni1_dummy_invoke(st, cr, id, ident, p, nlen);
353 return;
354 }
355 l3_debug(st, "invoke break");
356 break;
357 case 2: /* return result */
358 /* if no process available handle separately */
359 if (!pc)
360 { if (cr == -1)
361 l3ni1_dummy_return_result(st, id, p, nlen);
362 return;
363 }
364 if ((pc->prot.ni1.invoke_id) && (pc->prot.ni1.invoke_id == id))
365 { /* Diversion successful */
366 free_invoke_id(st,pc->prot.ni1.invoke_id);
367 pc->prot.ni1.remote_result = 0; /* success */
368 pc->prot.ni1.invoke_id = 0;
369 pc->redir_result = pc->prot.ni1.remote_result;
370 st->l3.l3l4(st, CC_REDIR | INDICATION, pc); } /* Diversion successful */
371 else
372 l3_debug(st,"return error unknown identifier");
373 break;
374 case 3: /* return error */
375 err_ret = 0;
376 if (nlen < 2)
377 { l3_debug(st, "return error nlen < 2");
378 return;
379 }
380 if (*p != 0x02)
381 { /* result tag */
382 l3_debug(st, "invoke error tag !=0x02");
383 return;
384 }
385 p++;
386 nlen--;
387 if (*p > 4)
388 { /* length format */
389 l3_debug(st, "invoke return errlen > 4 ");
390 return;
391 }
392 ilen = *p++;
393 nlen--;
394 if (ilen > nlen || ilen == 0)
395 { l3_debug(st, "error return ilen > nlen || ilen == 0");
396 return;
397 }
398 nlen -= ilen;
399 while (ilen > 0)
400 { err_ret = (err_ret << 8) | (*p++ & 0xFF); /* error value */
401 ilen--;
402 }
403 /* if no process available handle separately */
404 if (!pc)
405 { if (cr == -1)
406 l3ni1_dummy_error_return(st, id, err_ret);
407 return;
408 }
409 if ((pc->prot.ni1.invoke_id) && (pc->prot.ni1.invoke_id == id))
410 { /* Deflection error */
411 free_invoke_id(st,pc->prot.ni1.invoke_id);
412 pc->prot.ni1.remote_result = err_ret; /* result */
413 pc->prot.ni1.invoke_id = 0;
414 pc->redir_result = pc->prot.ni1.remote_result;
415 st->l3.l3l4(st, CC_REDIR | INDICATION, pc);
416 } /* Deflection error */
417 else
418 l3_debug(st,"return result unknown identifier");
419 break;
420 default:
421 l3_debug(st, "facility default break tag=0x%02x",cp_tag);
422 break;
423 }
424}
425
426static void
427l3ni1_message(struct l3_process *pc, u_char mt)
428{
429 struct sk_buff *skb;
430 u_char *p;
431
432 if (!(skb = l3_alloc_skb(4)))
433 return;
434 p = skb_put(skb, 4);
435 MsgHead(p, pc->callref, mt);
436 l3_msg(pc->st, DL_DATA | REQUEST, skb);
437}
438
439static void
440l3ni1_message_plus_chid(struct l3_process *pc, u_char mt)
441/* sends an l3 messages plus channel id - added GE 05/09/00 */
442{
443 struct sk_buff *skb;
444 u_char tmp[16];
445 u_char *p = tmp;
446 u_char chid;
447
448 chid = (u_char)(pc->para.bchannel & 0x03) | 0x88;
449 MsgHead(p, pc->callref, mt);
450 *p++ = IE_CHANNEL_ID;
451 *p++ = 0x01;
452 *p++ = chid;
453
454 if (!(skb = l3_alloc_skb(7)))
455 return;
456 memcpy(skb_put(skb, 7), tmp, 7);
457 l3_msg(pc->st, DL_DATA | REQUEST, skb);
458}
459
460static void
461l3ni1_message_cause(struct l3_process *pc, u_char mt, u_char cause)
462{
463 struct sk_buff *skb;
464 u_char tmp[16];
465 u_char *p = tmp;
466 int l;
467
468 MsgHead(p, pc->callref, mt);
469 *p++ = IE_CAUSE;
470 *p++ = 0x2;
471 *p++ = 0x80;
472 *p++ = cause | 0x80;
473
474 l = p - tmp;
475 if (!(skb = l3_alloc_skb(l)))
476 return;
477 memcpy(skb_put(skb, l), tmp, l);
478 l3_msg(pc->st, DL_DATA | REQUEST, skb);
479}
480
481static void
482l3ni1_status_send(struct l3_process *pc, u_char pr, void *arg)
483{
484 u_char tmp[16];
485 u_char *p = tmp;
486 int l;
487 struct sk_buff *skb;
488
489 MsgHead(p, pc->callref, MT_STATUS);
490
491 *p++ = IE_CAUSE;
492 *p++ = 0x2;
493 *p++ = 0x80;
494 *p++ = pc->para.cause | 0x80;
495
496 *p++ = IE_CALL_STATE;
497 *p++ = 0x1;
498 *p++ = pc->state & 0x3f;
499
500 l = p - tmp;
501 if (!(skb = l3_alloc_skb(l)))
502 return;
503 memcpy(skb_put(skb, l), tmp, l);
504 l3_msg(pc->st, DL_DATA | REQUEST, skb);
505}
506
507static void
508l3ni1_msg_without_setup(struct l3_process *pc, u_char pr, void *arg)
509{
510 /* This routine is called if here was no SETUP made (checks in ni1up and in
511 * l3ni1_setup) and a RELEASE_COMPLETE have to be sent with an error code
512 * MT_STATUS_ENQUIRE in the NULL state is handled too
513 */
514 u_char tmp[16];
515 u_char *p = tmp;
516 int l;
517 struct sk_buff *skb;
518
519 switch (pc->para.cause) {
520 case 81: /* invalid callreference */
521 case 88: /* incomp destination */
522 case 96: /* mandory IE missing */
523 case 100: /* invalid IE contents */
524 case 101: /* incompatible Callstate */
525 MsgHead(p, pc->callref, MT_RELEASE_COMPLETE);
526 *p++ = IE_CAUSE;
527 *p++ = 0x2;
528 *p++ = 0x80;
529 *p++ = pc->para.cause | 0x80;
530 break;
531 default:
532 printk(KERN_ERR "HiSax l3ni1_msg_without_setup wrong cause %d\n",
533 pc->para.cause);
534 return;
535 }
536 l = p - tmp;
537 if (!(skb = l3_alloc_skb(l)))
538 return;
539 memcpy(skb_put(skb, l), tmp, l);
540 l3_msg(pc->st, DL_DATA | REQUEST, skb);
541 ni1_release_l3_process(pc);
542}
543
544static int ie_ALERTING[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1,
545 IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, IE_HLC,
546 IE_USER_USER, -1};
547static int ie_CALL_PROCEEDING[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1,
548 IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_HLC, -1};
549static int ie_CONNECT[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1,
550 IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_DATE, IE_SIGNAL,
551 IE_CONNECT_PN, IE_CONNECT_SUB, IE_LLC, IE_HLC, IE_USER_USER, -1};
552static int ie_CONNECT_ACKNOWLEDGE[] = {IE_CHANNEL_ID, IE_DISPLAY, IE_SIGNAL, -1};
553static int ie_DISCONNECT[] = {IE_CAUSE | IE_MANDATORY, IE_FACILITY,
554 IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, IE_USER_USER, -1};
555static int ie_INFORMATION[] = {IE_COMPLETE, IE_DISPLAY, IE_KEYPAD, IE_SIGNAL,
556 IE_CALLED_PN, -1};
557static int ie_NOTIFY[] = {IE_BEARER, IE_NOTIFY | IE_MANDATORY, IE_DISPLAY, -1};
558static int ie_PROGRESS[] = {IE_BEARER, IE_CAUSE, IE_FACILITY, IE_PROGRESS |
559 IE_MANDATORY, IE_DISPLAY, IE_HLC, IE_USER_USER, -1};
560static int ie_RELEASE[] = {IE_CAUSE | IE_MANDATORY_1, IE_FACILITY, IE_DISPLAY,
561 IE_SIGNAL, IE_USER_USER, -1};
562/* a RELEASE_COMPLETE with errors don't require special actions
563static int ie_RELEASE_COMPLETE[] = {IE_CAUSE | IE_MANDATORY_1, IE_DISPLAY, IE_SIGNAL, IE_USER_USER, -1};
564*/
565static int ie_RESUME_ACKNOWLEDGE[] = {IE_CHANNEL_ID| IE_MANDATORY, IE_FACILITY,
566 IE_DISPLAY, -1};
567static int ie_RESUME_REJECT[] = {IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1};
568static int ie_SETUP[] = {IE_COMPLETE, IE_BEARER | IE_MANDATORY,
569 IE_CHANNEL_ID| IE_MANDATORY, IE_FACILITY, IE_PROGRESS,
570 IE_NET_FAC, IE_DISPLAY, IE_KEYPAD, IE_SIGNAL, IE_CALLING_PN,
571 IE_CALLING_SUB, IE_CALLED_PN, IE_CALLED_SUB, IE_REDIR_NR,
572 IE_LLC, IE_HLC, IE_USER_USER, -1};
573static int ie_SETUP_ACKNOWLEDGE[] = {IE_CHANNEL_ID | IE_MANDATORY, IE_FACILITY,
574 IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, -1};
575static int ie_STATUS[] = {IE_CAUSE | IE_MANDATORY, IE_CALL_STATE |
576 IE_MANDATORY, IE_DISPLAY, -1};
577static int ie_STATUS_ENQUIRY[] = {IE_DISPLAY, -1};
578static int ie_SUSPEND_ACKNOWLEDGE[] = {IE_DISPLAY, IE_FACILITY, -1};
579static int ie_SUSPEND_REJECT[] = {IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1};
580/* not used
581 * static int ie_CONGESTION_CONTROL[] = {IE_CONGESTION | IE_MANDATORY,
582 * IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1};
583 * static int ie_USER_INFORMATION[] = {IE_MORE_DATA, IE_USER_USER | IE_MANDATORY, -1};
584 * static int ie_RESTART[] = {IE_CHANNEL_ID, IE_DISPLAY, IE_RESTART_IND |
585 * IE_MANDATORY, -1};
586 */
587static int ie_FACILITY[] = {IE_FACILITY | IE_MANDATORY, IE_DISPLAY, -1};
588static int comp_required[] = {1,2,3,5,6,7,9,10,11,14,15,-1};
589static int l3_valid_states[] = {0,1,2,3,4,6,7,8,9,10,11,12,15,17,19,25,-1};
590
591struct ie_len {
592 int ie;
593 int len;
594};
595
596static
597struct ie_len max_ie_len[] = {
598 {IE_SEGMENT, 4},
599 {IE_BEARER, 12},
600 {IE_CAUSE, 32},
601 {IE_CALL_ID, 10},
602 {IE_CALL_STATE, 3},
603 {IE_CHANNEL_ID, 34},
604 {IE_FACILITY, 255},
605 {IE_PROGRESS, 4},
606 {IE_NET_FAC, 255},
607 {IE_NOTIFY, 3},
608 {IE_DISPLAY, 82},
609 {IE_DATE, 8},
610 {IE_KEYPAD, 34},
611 {IE_SIGNAL, 3},
612 {IE_INFORATE, 6},
613 {IE_E2E_TDELAY, 11},
614 {IE_TDELAY_SEL, 5},
615 {IE_PACK_BINPARA, 3},
616 {IE_PACK_WINSIZE, 4},
617 {IE_PACK_SIZE, 4},
618 {IE_CUG, 7},
619 {IE_REV_CHARGE, 3},
620 {IE_CALLING_PN, 24},
621 {IE_CALLING_SUB, 23},
622 {IE_CALLED_PN, 24},
623 {IE_CALLED_SUB, 23},
624 {IE_REDIR_NR, 255},
625 {IE_TRANS_SEL, 255},
626 {IE_RESTART_IND, 3},
627 {IE_LLC, 18},
628 {IE_HLC, 5},
629 {IE_USER_USER, 131},
630 {-1,0},
631};
632
633static int
634getmax_ie_len(u_char ie) {
635 int i = 0;
636 while (max_ie_len[i].ie != -1) {
637 if (max_ie_len[i].ie == ie)
638 return(max_ie_len[i].len);
639 i++;
640 }
641 return(255);
642}
643
644static int
645ie_in_set(struct l3_process *pc, u_char ie, int *checklist) {
646 int ret = 1;
647
648 while (*checklist != -1) {
649 if ((*checklist & 0xff) == ie) {
650 if (ie & 0x80)
651 return(-ret);
652 else
653 return(ret);
654 }
655 ret++;
656 checklist++;
657 }
658 return(0);
659}
660
661static int
662check_infoelements(struct l3_process *pc, struct sk_buff *skb, int *checklist)
663{
664 int *cl = checklist;
665 u_char mt;
666 u_char *p, ie;
667 int l, newpos, oldpos;
668 int err_seq = 0, err_len = 0, err_compr = 0, err_ureg = 0;
669 u_char codeset = 0;
670 u_char old_codeset = 0;
671 u_char codelock = 1;
672
673 p = skb->data;
674 /* skip cr */
675 p++;
676 l = (*p++) & 0xf;
677 p += l;
678 mt = *p++;
679 oldpos = 0;
680 while ((p - skb->data) < skb->len) {
681 if ((*p & 0xf0) == 0x90) { /* shift codeset */
682 old_codeset = codeset;
683 codeset = *p & 7;
684 if (*p & 0x08)
685 codelock = 0;
686 else
687 codelock = 1;
688 if (pc->debug & L3_DEB_CHECK)
689 l3_debug(pc->st, "check IE shift%scodeset %d->%d",
690 codelock ? " locking ": " ", old_codeset, codeset);
691 p++;
692 continue;
693 }
694 if (!codeset) { /* only codeset 0 */
695 if ((newpos = ie_in_set(pc, *p, cl))) {
696 if (newpos > 0) {
697 if (newpos < oldpos)
698 err_seq++;
699 else
700 oldpos = newpos;
701 }
702 } else {
703 if (ie_in_set(pc, *p, comp_required))
704 err_compr++;
705 else
706 err_ureg++;
707 }
708 }
709 ie = *p++;
710 if (ie & 0x80) {
711 l = 1;
712 } else {
713 l = *p++;
714 p += l;
715 l += 2;
716 }
717 if (!codeset && (l > getmax_ie_len(ie)))
718 err_len++;
719 if (!codelock) {
720 if (pc->debug & L3_DEB_CHECK)
721 l3_debug(pc->st, "check IE shift back codeset %d->%d",
722 codeset, old_codeset);
723 codeset = old_codeset;
724 codelock = 1;
725 }
726 }
727 if (err_compr | err_ureg | err_len | err_seq) {
728 if (pc->debug & L3_DEB_CHECK)
729 l3_debug(pc->st, "check IE MT(%x) %d/%d/%d/%d",
730 mt, err_compr, err_ureg, err_len, err_seq);
731 if (err_compr)
732 return(ERR_IE_COMPREHENSION);
733 if (err_ureg)
734 return(ERR_IE_UNRECOGNIZED);
735 if (err_len)
736 return(ERR_IE_LENGTH);
737 if (err_seq)
738 return(ERR_IE_SEQUENCE);
739 }
740 return(0);
741}
742
743/* verify if a message type exists and contain no IE error */
744static int
745l3ni1_check_messagetype_validity(struct l3_process *pc, int mt, void *arg)
746{
747 switch (mt) {
748 case MT_ALERTING:
749 case MT_CALL_PROCEEDING:
750 case MT_CONNECT:
751 case MT_CONNECT_ACKNOWLEDGE:
752 case MT_DISCONNECT:
753 case MT_INFORMATION:
754 case MT_FACILITY:
755 case MT_NOTIFY:
756 case MT_PROGRESS:
757 case MT_RELEASE:
758 case MT_RELEASE_COMPLETE:
759 case MT_SETUP:
760 case MT_SETUP_ACKNOWLEDGE:
761 case MT_RESUME_ACKNOWLEDGE:
762 case MT_RESUME_REJECT:
763 case MT_SUSPEND_ACKNOWLEDGE:
764 case MT_SUSPEND_REJECT:
765 case MT_USER_INFORMATION:
766 case MT_RESTART:
767 case MT_RESTART_ACKNOWLEDGE:
768 case MT_CONGESTION_CONTROL:
769 case MT_STATUS:
770 case MT_STATUS_ENQUIRY:
771 if (pc->debug & L3_DEB_CHECK)
772 l3_debug(pc->st, "l3ni1_check_messagetype_validity mt(%x) OK", mt);
773 break;
774 case MT_RESUME: /* RESUME only in user->net */
775 case MT_SUSPEND: /* SUSPEND only in user->net */
776 default:
777 if (pc->debug & (L3_DEB_CHECK | L3_DEB_WARN))
778 l3_debug(pc->st, "l3ni1_check_messagetype_validity mt(%x) fail", mt);
779 pc->para.cause = 97;
780 l3ni1_status_send(pc, 0, NULL);
781 return(1);
782 }
783 return(0);
784}
785
786static void
787l3ni1_std_ie_err(struct l3_process *pc, int ret) {
788
789 if (pc->debug & L3_DEB_CHECK)
790 l3_debug(pc->st, "check_infoelements ret %d", ret);
791 switch(ret) {
792 case 0:
793 break;
794 case ERR_IE_COMPREHENSION:
795 pc->para.cause = 96;
796 l3ni1_status_send(pc, 0, NULL);
797 break;
798 case ERR_IE_UNRECOGNIZED:
799 pc->para.cause = 99;
800 l3ni1_status_send(pc, 0, NULL);
801 break;
802 case ERR_IE_LENGTH:
803 pc->para.cause = 100;
804 l3ni1_status_send(pc, 0, NULL);
805 break;
806 case ERR_IE_SEQUENCE:
807 default:
808 break;
809 }
810}
811
812static int
813l3ni1_get_channel_id(struct l3_process *pc, struct sk_buff *skb) {
814 u_char *p;
815
816 p = skb->data;
817 if ((p = findie(p, skb->len, IE_CHANNEL_ID, 0))) {
818 p++;
819 if (*p != 1) { /* len for BRI = 1 */
820 if (pc->debug & L3_DEB_WARN)
821 l3_debug(pc->st, "wrong chid len %d", *p);
822 return (-2);
823 }
824 p++;
825 if (*p & 0x60) { /* only base rate interface */
826 if (pc->debug & L3_DEB_WARN)
827 l3_debug(pc->st, "wrong chid %x", *p);
828 return (-3);
829 }
830 return(*p & 0x3);
831 } else
832 return(-1);
833}
834
835static int
836l3ni1_get_cause(struct l3_process *pc, struct sk_buff *skb) {
837 u_char l, i=0;
838 u_char *p;
839
840 p = skb->data;
841 pc->para.cause = 31;
842 pc->para.loc = 0;
843 if ((p = findie(p, skb->len, IE_CAUSE, 0))) {
844 p++;
845 l = *p++;
846 if (l>30)
847 return(1);
848 if (l) {
849 pc->para.loc = *p++;
850 l--;
851 } else {
852 return(2);
853 }
854 if (l && !(pc->para.loc & 0x80)) {
855 l--;
856 p++; /* skip recommendation */
857 }
858 if (l) {
859 pc->para.cause = *p++;
860 l--;
861 if (!(pc->para.cause & 0x80))
862 return(3);
863 } else
864 return(4);
865 while (l && (i<6)) {
866 pc->para.diag[i++] = *p++;
867 l--;
868 }
869 } else
870 return(-1);
871 return(0);
872}
873
874static void
875l3ni1_msg_with_uus(struct l3_process *pc, u_char cmd)
876{
877 struct sk_buff *skb;
878 u_char tmp[16+40];
879 u_char *p = tmp;
880 int l;
881
882 MsgHead(p, pc->callref, cmd);
883
884 if (pc->prot.ni1.uus1_data[0])
885 { *p++ = IE_USER_USER; /* UUS info element */
886 *p++ = strlen(pc->prot.ni1.uus1_data) + 1;
887 *p++ = 0x04; /* IA5 chars */
888 strcpy(p,pc->prot.ni1.uus1_data);
889 p += strlen(pc->prot.ni1.uus1_data);
890 pc->prot.ni1.uus1_data[0] = '\0';
891 }
892
893 l = p - tmp;
894 if (!(skb = l3_alloc_skb(l)))
895 return;
896 memcpy(skb_put(skb, l), tmp, l);
897 l3_msg(pc->st, DL_DATA | REQUEST, skb);
898} /* l3ni1_msg_with_uus */
899
900static void
901l3ni1_release_req(struct l3_process *pc, u_char pr, void *arg)
902{
903 StopAllL3Timer(pc);
904 newl3state(pc, 19);
905 if (!pc->prot.ni1.uus1_data[0])
906 l3ni1_message(pc, MT_RELEASE);
907 else
908 l3ni1_msg_with_uus(pc, MT_RELEASE);
909 L3AddTimer(&pc->timer, T308, CC_T308_1);
910}
911
912static void
913l3ni1_release_cmpl(struct l3_process *pc, u_char pr, void *arg)
914{
915 struct sk_buff *skb = arg;
916 int ret;
917
918 if ((ret = l3ni1_get_cause(pc, skb))>0) {
919 if (pc->debug & L3_DEB_WARN)
920 l3_debug(pc->st, "RELCMPL get_cause ret(%d)",ret);
921 } else if (ret < 0)
922 pc->para.cause = NO_CAUSE;
923 StopAllL3Timer(pc);
924 newl3state(pc, 0);
925 pc->st->l3.l3l4(pc->st, CC_RELEASE | CONFIRM, pc);
926 ni1_release_l3_process(pc);
927}
928
929#if EXT_BEARER_CAPS
930
931static u_char *
932EncodeASyncParams(u_char * p, u_char si2)
933{ // 7c 06 88 90 21 42 00 bb
934
935 p[0] = 0;
936 p[1] = 0x40; // Intermediate rate: 16 kbit/s jj 2000.02.19
937 p[2] = 0x80;
938 if (si2 & 32) // 7 data bits
939
940 p[2] += 16;
941 else // 8 data bits
942
943 p[2] += 24;
944
945 if (si2 & 16) // 2 stop bits
946
947 p[2] += 96;
948 else // 1 stop bit
949
950 p[2] += 32;
951
952 if (si2 & 8) // even parity
953
954 p[2] += 2;
955 else // no parity
956
957 p[2] += 3;
958
959 switch (si2 & 0x07) {
960 case 0:
961 p[0] = 66; // 1200 bit/s
962
963 break;
964 case 1:
965 p[0] = 88; // 1200/75 bit/s
966
967 break;
968 case 2:
969 p[0] = 87; // 75/1200 bit/s
970
971 break;
972 case 3:
973 p[0] = 67; // 2400 bit/s
974
975 break;
976 case 4:
977 p[0] = 69; // 4800 bit/s
978
979 break;
980 case 5:
981 p[0] = 72; // 9600 bit/s
982
983 break;
984 case 6:
985 p[0] = 73; // 14400 bit/s
986
987 break;
988 case 7:
989 p[0] = 75; // 19200 bit/s
990
991 break;
992 }
993 return p + 3;
994}
995
996static u_char
997EncodeSyncParams(u_char si2, u_char ai)
998{
999
1000 switch (si2) {
1001 case 0:
1002 return ai + 2; // 1200 bit/s
1003
1004 case 1:
1005 return ai + 24; // 1200/75 bit/s
1006
1007 case 2:
1008 return ai + 23; // 75/1200 bit/s
1009
1010 case 3:
1011 return ai + 3; // 2400 bit/s
1012
1013 case 4:
1014 return ai + 5; // 4800 bit/s
1015
1016 case 5:
1017 return ai + 8; // 9600 bit/s
1018
1019 case 6:
1020 return ai + 9; // 14400 bit/s
1021
1022 case 7:
1023 return ai + 11; // 19200 bit/s
1024
1025 case 8:
1026 return ai + 14; // 48000 bit/s
1027
1028 case 9:
1029 return ai + 15; // 56000 bit/s
1030
1031 case 15:
1032 return ai + 40; // negotiate bit/s
1033
1034 default:
1035 break;
1036 }
1037 return ai;
1038}
1039
1040
1041static u_char
1042DecodeASyncParams(u_char si2, u_char * p)
1043{
1044 u_char info;
1045
1046 switch (p[5]) {
1047 case 66: // 1200 bit/s
1048
1049 break; // si2 don't change
1050
1051 case 88: // 1200/75 bit/s
1052
1053 si2 += 1;
1054 break;
1055 case 87: // 75/1200 bit/s
1056
1057 si2 += 2;
1058 break;
1059 case 67: // 2400 bit/s
1060
1061 si2 += 3;
1062 break;
1063 case 69: // 4800 bit/s
1064
1065 si2 += 4;
1066 break;
1067 case 72: // 9600 bit/s
1068
1069 si2 += 5;
1070 break;
1071 case 73: // 14400 bit/s
1072
1073 si2 += 6;
1074 break;
1075 case 75: // 19200 bit/s
1076
1077 si2 += 7;
1078 break;
1079 }
1080
1081 info = p[7] & 0x7f;
1082 if ((info & 16) && (!(info & 8))) // 7 data bits
1083
1084 si2 += 32; // else 8 data bits
1085
1086 if ((info & 96) == 96) // 2 stop bits
1087
1088 si2 += 16; // else 1 stop bit
1089
1090 if ((info & 2) && (!(info & 1))) // even parity
1091
1092 si2 += 8; // else no parity
1093
1094 return si2;
1095}
1096
1097
1098static u_char
1099DecodeSyncParams(u_char si2, u_char info)
1100{
1101 info &= 0x7f;
1102 switch (info) {
1103 case 40: // bit/s negotiation failed ai := 165 not 175!
1104
1105 return si2 + 15;
1106 case 15: // 56000 bit/s failed, ai := 0 not 169 !
1107
1108 return si2 + 9;
1109 case 14: // 48000 bit/s
1110
1111 return si2 + 8;
1112 case 11: // 19200 bit/s
1113
1114 return si2 + 7;
1115 case 9: // 14400 bit/s
1116
1117 return si2 + 6;
1118 case 8: // 9600 bit/s
1119
1120 return si2 + 5;
1121 case 5: // 4800 bit/s
1122
1123 return si2 + 4;
1124 case 3: // 2400 bit/s
1125
1126 return si2 + 3;
1127 case 23: // 75/1200 bit/s
1128
1129 return si2 + 2;
1130 case 24: // 1200/75 bit/s
1131
1132 return si2 + 1;
1133 default: // 1200 bit/s
1134
1135 return si2;
1136 }
1137}
1138
1139static u_char
1140DecodeSI2(struct sk_buff *skb)
1141{
1142 u_char *p; //, *pend=skb->data + skb->len;
1143
1144 if ((p = findie(skb->data, skb->len, 0x7c, 0))) {
1145 switch (p[4] & 0x0f) {
1146 case 0x01:
1147 if (p[1] == 0x04) // sync. Bitratenadaption
1148
1149 return DecodeSyncParams(160, p[5]); // V.110/X.30
1150
1151 else if (p[1] == 0x06) // async. Bitratenadaption
1152
1153 return DecodeASyncParams(192, p); // V.110/X.30
1154
1155 break;
1156 case 0x08: // if (p[5] == 0x02) // sync. Bitratenadaption
1157 if (p[1] > 3)
1158 return DecodeSyncParams(176, p[5]); // V.120
1159 break;
1160 }
1161 }
1162 return 0;
1163}
1164
1165#endif
1166
1167
1168static void
1169l3ni1_setup_req(struct l3_process *pc, u_char pr,
1170 void *arg)
1171{
1172 struct sk_buff *skb;
1173 u_char tmp[128];
1174 u_char *p = tmp;
1175
1176 u_char *teln;
1177 u_char *sub;
1178 u_char *sp;
1179 int l;
1180
1181 MsgHead(p, pc->callref, MT_SETUP);
1182
1183 teln = pc->para.setup.phone;
1184
1185 *p++ = 0xa1; /* complete indicator */
1186 /*
1187 * Set Bearer Capability, Map info from 1TR6-convention to NI1
1188 */
1189 switch (pc->para.setup.si1) {
1190 case 1: /* Telephony */
1191 *p++ = IE_BEARER;
1192 *p++ = 0x3; /* Length */
1193 *p++ = 0x90; /* 3.1khz Audio */
1194 *p++ = 0x90; /* Circuit-Mode 64kbps */
1195 *p++ = 0xa2; /* u-Law Audio */
1196 break;
1197 case 5: /* Datatransmission 64k, BTX */
1198 case 7: /* Datatransmission 64k */
1199 default:
1200 *p++ = IE_BEARER;
1201 *p++ = 0x2; /* Length */
1202 *p++ = 0x88; /* Coding Std. CCITT, unrestr. dig. Inform. */
1203 *p++ = 0x90; /* Circuit-Mode 64kbps */
1204 break;
1205 }
1206
1207 sub = NULL;
1208 sp = teln;
1209 while (*sp) {
1210 if ('.' == *sp) {
1211 sub = sp;
1212 *sp = 0;
1213 } else
1214 sp++;
1215 }
1216
1217 *p++ = IE_KEYPAD;
1218 *p++ = strlen(teln);
1219 while (*teln)
1220 *p++ = (*teln++) & 0x7F;
1221
1222 if (sub)
1223 *sub++ = '.';
1224
1225#if EXT_BEARER_CAPS
1226 if ((pc->para.setup.si2 >= 160) && (pc->para.setup.si2 <= 175)) { // sync. Bitratenadaption, V.110/X.30
1227
1228 *p++ = IE_LLC;
1229 *p++ = 0x04;
1230 *p++ = 0x88;
1231 *p++ = 0x90;
1232 *p++ = 0x21;
1233 *p++ = EncodeSyncParams(pc->para.setup.si2 - 160, 0x80);
1234 } else if ((pc->para.setup.si2 >= 176) && (pc->para.setup.si2 <= 191)) { // sync. Bitratenadaption, V.120
1235
1236 *p++ = IE_LLC;
1237 *p++ = 0x05;
1238 *p++ = 0x88;
1239 *p++ = 0x90;
1240 *p++ = 0x28;
1241 *p++ = EncodeSyncParams(pc->para.setup.si2 - 176, 0);
1242 *p++ = 0x82;
1243 } else if (pc->para.setup.si2 >= 192) { // async. Bitratenadaption, V.110/X.30
1244
1245 *p++ = IE_LLC;
1246 *p++ = 0x06;
1247 *p++ = 0x88;
1248 *p++ = 0x90;
1249 *p++ = 0x21;
1250 p = EncodeASyncParams(p, pc->para.setup.si2 - 192);
1251 } else {
1252 switch (pc->para.setup.si1) {
1253 case 1: /* Telephony */
1254 *p++ = IE_LLC;
1255 *p++ = 0x3; /* Length */
1256 *p++ = 0x90; /* Coding Std. CCITT, 3.1 kHz audio */
1257 *p++ = 0x90; /* Circuit-Mode 64kbps */
1258 *p++ = 0xa2; /* u-Law Audio */
1259 break;
1260 case 5: /* Datatransmission 64k, BTX */
1261 case 7: /* Datatransmission 64k */
1262 default:
1263 *p++ = IE_LLC;
1264 *p++ = 0x2; /* Length */
1265 *p++ = 0x88; /* Coding Std. CCITT, unrestr. dig. Inform. */
1266 *p++ = 0x90; /* Circuit-Mode 64kbps */
1267 break;
1268 }
1269 }
1270#endif
1271 l = p - tmp;
1272 if (!(skb = l3_alloc_skb(l)))
1273{
1274 return;
1275}
1276 memcpy(skb_put(skb, l), tmp, l);
1277 L3DelTimer(&pc->timer);
1278 L3AddTimer(&pc->timer, T303, CC_T303);
1279 newl3state(pc, 1);
1280 l3_msg(pc->st, DL_DATA | REQUEST, skb);
1281}
1282
1283static void
1284l3ni1_call_proc(struct l3_process *pc, u_char pr, void *arg)
1285{
1286 struct sk_buff *skb = arg;
1287 int id, ret;
1288
1289 if ((id = l3ni1_get_channel_id(pc, skb)) >= 0) {
1290 if ((0 == id) || ((3 == id) && (0x10 == pc->para.moderate))) {
1291 if (pc->debug & L3_DEB_WARN)
1292 l3_debug(pc->st, "setup answer with wrong chid %x", id);
1293 pc->para.cause = 100;
1294 l3ni1_status_send(pc, pr, NULL);
1295 return;
1296 }
1297 pc->para.bchannel = id;
1298 } else if (1 == pc->state) {
1299 if (pc->debug & L3_DEB_WARN)
1300 l3_debug(pc->st, "setup answer wrong chid (ret %d)", id);
1301 if (id == -1)
1302 pc->para.cause = 96;
1303 else
1304 pc->para.cause = 100;
1305 l3ni1_status_send(pc, pr, NULL);
1306 return;
1307 }
1308 /* Now we are on none mandatory IEs */
1309 ret = check_infoelements(pc, skb, ie_CALL_PROCEEDING);
1310 if (ERR_IE_COMPREHENSION == ret) {
1311 l3ni1_std_ie_err(pc, ret);
1312 return;
1313 }
1314 L3DelTimer(&pc->timer);
1315 newl3state(pc, 3);
1316 L3AddTimer(&pc->timer, T310, CC_T310);
1317 if (ret) /* STATUS for none mandatory IE errors after actions are taken */
1318 l3ni1_std_ie_err(pc, ret);
1319 pc->st->l3.l3l4(pc->st, CC_PROCEEDING | INDICATION, pc);
1320}
1321
1322static void
1323l3ni1_setup_ack(struct l3_process *pc, u_char pr, void *arg)
1324{
1325 struct sk_buff *skb = arg;
1326 int id, ret;
1327
1328 if ((id = l3ni1_get_channel_id(pc, skb)) >= 0) {
1329 if ((0 == id) || ((3 == id) && (0x10 == pc->para.moderate))) {
1330 if (pc->debug & L3_DEB_WARN)
1331 l3_debug(pc->st, "setup answer with wrong chid %x", id);
1332 pc->para.cause = 100;
1333 l3ni1_status_send(pc, pr, NULL);
1334 return;
1335 }
1336 pc->para.bchannel = id;
1337 } else {
1338 if (pc->debug & L3_DEB_WARN)
1339 l3_debug(pc->st, "setup answer wrong chid (ret %d)", id);
1340 if (id == -1)
1341 pc->para.cause = 96;
1342 else
1343 pc->para.cause = 100;
1344 l3ni1_status_send(pc, pr, NULL);
1345 return;
1346 }
1347 /* Now we are on none mandatory IEs */
1348 ret = check_infoelements(pc, skb, ie_SETUP_ACKNOWLEDGE);
1349 if (ERR_IE_COMPREHENSION == ret) {
1350 l3ni1_std_ie_err(pc, ret);
1351 return;
1352 }
1353 L3DelTimer(&pc->timer);
1354 newl3state(pc, 2);
1355 L3AddTimer(&pc->timer, T304, CC_T304);
1356 if (ret) /* STATUS for none mandatory IE errors after actions are taken */
1357 l3ni1_std_ie_err(pc, ret);
1358 pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc);
1359}
1360
1361static void
1362l3ni1_disconnect(struct l3_process *pc, u_char pr, void *arg)
1363{
1364 struct sk_buff *skb = arg;
1365 u_char *p;
1366 int ret;
1367 u_char cause = 0;
1368
1369 StopAllL3Timer(pc);
1370 if ((ret = l3ni1_get_cause(pc, skb))) {
1371 if (pc->debug & L3_DEB_WARN)
1372 l3_debug(pc->st, "DISC get_cause ret(%d)", ret);
1373 if (ret < 0)
1374 cause = 96;
1375 else if (ret > 0)
1376 cause = 100;
1377 }
1378 if ((p = findie(skb->data, skb->len, IE_FACILITY, 0)))
1379 l3ni1_parse_facility(pc->st, pc, pc->callref, p);
1380 ret = check_infoelements(pc, skb, ie_DISCONNECT);
1381 if (ERR_IE_COMPREHENSION == ret)
1382 cause = 96;
1383 else if ((!cause) && (ERR_IE_UNRECOGNIZED == ret))
1384 cause = 99;
1385 ret = pc->state;
1386 newl3state(pc, 12);
1387 if (cause)
1388 newl3state(pc, 19);
1389 if (11 != ret)
1390 pc->st->l3.l3l4(pc->st, CC_DISCONNECT | INDICATION, pc);
1391 else if (!cause)
1392 l3ni1_release_req(pc, pr, NULL);
1393 if (cause) {
1394 l3ni1_message_cause(pc, MT_RELEASE, cause);
1395 L3AddTimer(&pc->timer, T308, CC_T308_1);
1396 }
1397}
1398
1399static void
1400l3ni1_connect(struct l3_process *pc, u_char pr, void *arg)
1401{
1402 struct sk_buff *skb = arg;
1403 int ret;
1404
1405 ret = check_infoelements(pc, skb, ie_CONNECT);
1406 if (ERR_IE_COMPREHENSION == ret) {
1407 l3ni1_std_ie_err(pc, ret);
1408 return;
1409 }
1410 L3DelTimer(&pc->timer); /* T310 */
1411 newl3state(pc, 10);
1412 pc->para.chargeinfo = 0;
1413 /* here should inserted COLP handling KKe */
1414 if (ret)
1415 l3ni1_std_ie_err(pc, ret);
1416 pc->st->l3.l3l4(pc->st, CC_SETUP | CONFIRM, pc);
1417}
1418
1419static void
1420l3ni1_alerting(struct l3_process *pc, u_char pr, void *arg)
1421{
1422 struct sk_buff *skb = arg;
1423 int ret;
1424
1425 ret = check_infoelements(pc, skb, ie_ALERTING);
1426 if (ERR_IE_COMPREHENSION == ret) {
1427 l3ni1_std_ie_err(pc, ret);
1428 return;
1429 }
1430 L3DelTimer(&pc->timer); /* T304 */
1431 newl3state(pc, 4);
1432 if (ret)
1433 l3ni1_std_ie_err(pc, ret);
1434 pc->st->l3.l3l4(pc->st, CC_ALERTING | INDICATION, pc);
1435}
1436
1437static void
1438l3ni1_setup(struct l3_process *pc, u_char pr, void *arg)
1439{
1440 u_char *p;
1441 int bcfound = 0;
1442 char tmp[80];
1443 struct sk_buff *skb = arg;
1444 int id;
1445 int err = 0;
1446
1447 /*
1448 * Bearer Capabilities
1449 */
1450 p = skb->data;
1451 /* only the first occurence 'll be detected ! */
1452 if ((p = findie(p, skb->len, 0x04, 0))) {
1453 if ((p[1] < 2) || (p[1] > 11))
1454 err = 1;
1455 else {
1456 pc->para.setup.si2 = 0;
1457 switch (p[2] & 0x7f) {
1458 case 0x00: /* Speech */
1459 case 0x10: /* 3.1 Khz audio */
1460 pc->para.setup.si1 = 1;
1461 break;
1462 case 0x08: /* Unrestricted digital information */
1463 pc->para.setup.si1 = 7;
1464/* JIM, 05.11.97 I wanna set service indicator 2 */
1465#if EXT_BEARER_CAPS
1466 pc->para.setup.si2 = DecodeSI2(skb);
1467#endif
1468 break;
1469 case 0x09: /* Restricted digital information */
1470 pc->para.setup.si1 = 2;
1471 break;
1472 case 0x11:
1473 /* Unrestr. digital information with
1474 * tones/announcements ( or 7 kHz audio
1475 */
1476 pc->para.setup.si1 = 3;
1477 break;
1478 case 0x18: /* Video */
1479 pc->para.setup.si1 = 4;
1480 break;
1481 default:
1482 err = 2;
1483 break;
1484 }
1485 switch (p[3] & 0x7f) {
1486 case 0x40: /* packed mode */
1487 pc->para.setup.si1 = 8;
1488 break;
1489 case 0x10: /* 64 kbit */
1490 case 0x11: /* 2*64 kbit */
1491 case 0x13: /* 384 kbit */
1492 case 0x15: /* 1536 kbit */
1493 case 0x17: /* 1920 kbit */
1494 pc->para.moderate = p[3] & 0x7f;
1495 break;
1496 default:
1497 err = 3;
1498 break;
1499 }
1500 }
1501 if (pc->debug & L3_DEB_SI)
1502 l3_debug(pc->st, "SI=%d, AI=%d",
1503 pc->para.setup.si1, pc->para.setup.si2);
1504 if (err) {
1505 if (pc->debug & L3_DEB_WARN)
1506 l3_debug(pc->st, "setup with wrong bearer(l=%d:%x,%x)",
1507 p[1], p[2], p[3]);
1508 pc->para.cause = 100;
1509 l3ni1_msg_without_setup(pc, pr, NULL);
1510 return;
1511 }
1512 } else {
1513 if (pc->debug & L3_DEB_WARN)
1514 l3_debug(pc->st, "setup without bearer capabilities");
1515 /* ETS 300-104 1.3.3 */
1516 pc->para.cause = 96;
1517 l3ni1_msg_without_setup(pc, pr, NULL);
1518 return;
1519 }
1520 /*
1521 * Channel Identification
1522 */
1523 if ((id = l3ni1_get_channel_id(pc, skb)) >= 0) {
1524 if ((pc->para.bchannel = id)) {
1525 if ((3 == id) && (0x10 == pc->para.moderate)) {
1526 if (pc->debug & L3_DEB_WARN)
1527 l3_debug(pc->st, "setup with wrong chid %x",
1528 id);
1529 pc->para.cause = 100;
1530 l3ni1_msg_without_setup(pc, pr, NULL);
1531 return;
1532 }
1533 bcfound++;
1534 } else
1535 { if (pc->debug & L3_DEB_WARN)
1536 l3_debug(pc->st, "setup without bchannel, call waiting");
1537 bcfound++;
1538 }
1539 } else {
1540 if (pc->debug & L3_DEB_WARN)
1541 l3_debug(pc->st, "setup with wrong chid ret %d", id);
1542 if (id == -1)
1543 pc->para.cause = 96;
1544 else
1545 pc->para.cause = 100;
1546 l3ni1_msg_without_setup(pc, pr, NULL);
1547 return;
1548 }
1549 /* Now we are on none mandatory IEs */
1550 err = check_infoelements(pc, skb, ie_SETUP);
1551 if (ERR_IE_COMPREHENSION == err) {
1552 pc->para.cause = 96;
1553 l3ni1_msg_without_setup(pc, pr, NULL);
1554 return;
1555 }
1556 p = skb->data;
1557 if ((p = findie(p, skb->len, 0x70, 0)))
1558 iecpy(pc->para.setup.eazmsn, p, 1);
1559 else
1560 pc->para.setup.eazmsn[0] = 0;
1561
1562 p = skb->data;
1563 if ((p = findie(p, skb->len, 0x71, 0))) {
1564 /* Called party subaddress */
1565 if ((p[1] >= 2) && (p[2] == 0x80) && (p[3] == 0x50)) {
1566 tmp[0] = '.';
1567 iecpy(&tmp[1], p, 2);
1568 strcat(pc->para.setup.eazmsn, tmp);
1569 } else if (pc->debug & L3_DEB_WARN)
1570 l3_debug(pc->st, "wrong called subaddress");
1571 }
1572 p = skb->data;
1573 if ((p = findie(p, skb->len, 0x6c, 0))) {
1574 pc->para.setup.plan = p[2];
1575 if (p[2] & 0x80) {
1576 iecpy(pc->para.setup.phone, p, 1);
1577 pc->para.setup.screen = 0;
1578 } else {
1579 iecpy(pc->para.setup.phone, p, 2);
1580 pc->para.setup.screen = p[3];
1581 }
1582 } else {
1583 pc->para.setup.phone[0] = 0;
1584 pc->para.setup.plan = 0;
1585 pc->para.setup.screen = 0;
1586 }
1587 p = skb->data;
1588 if ((p = findie(p, skb->len, 0x6d, 0))) {
1589 /* Calling party subaddress */
1590 if ((p[1] >= 2) && (p[2] == 0x80) && (p[3] == 0x50)) {
1591 tmp[0] = '.';
1592 iecpy(&tmp[1], p, 2);
1593 strcat(pc->para.setup.phone, tmp);
1594 } else if (pc->debug & L3_DEB_WARN)
1595 l3_debug(pc->st, "wrong calling subaddress");
1596 }
1597 newl3state(pc, 6);
1598 if (err) /* STATUS for none mandatory IE errors after actions are taken */
1599 l3ni1_std_ie_err(pc, err);
1600 pc->st->l3.l3l4(pc->st, CC_SETUP | INDICATION, pc);
1601}
1602
1603static void
1604l3ni1_reset(struct l3_process *pc, u_char pr, void *arg)
1605{
1606 ni1_release_l3_process(pc);
1607}
1608
1609static void
1610l3ni1_disconnect_req(struct l3_process *pc, u_char pr, void *arg)
1611{
1612 struct sk_buff *skb;
1613 u_char tmp[16+40];
1614 u_char *p = tmp;
1615 int l;
1616 u_char cause = 16;
1617
1618 if (pc->para.cause != NO_CAUSE)
1619 cause = pc->para.cause;
1620
1621 StopAllL3Timer(pc);
1622
1623 MsgHead(p, pc->callref, MT_DISCONNECT);
1624
1625 *p++ = IE_CAUSE;
1626 *p++ = 0x2;
1627 *p++ = 0x80;
1628 *p++ = cause | 0x80;
1629
1630 if (pc->prot.ni1.uus1_data[0])
1631 { *p++ = IE_USER_USER; /* UUS info element */
1632 *p++ = strlen(pc->prot.ni1.uus1_data) + 1;
1633 *p++ = 0x04; /* IA5 chars */
1634 strcpy(p,pc->prot.ni1.uus1_data);
1635 p += strlen(pc->prot.ni1.uus1_data);
1636 pc->prot.ni1.uus1_data[0] = '\0';
1637 }
1638
1639 l = p - tmp;
1640 if (!(skb = l3_alloc_skb(l)))
1641 return;
1642 memcpy(skb_put(skb, l), tmp, l);
1643 newl3state(pc, 11);
1644 l3_msg(pc->st, DL_DATA | REQUEST, skb);
1645 L3AddTimer(&pc->timer, T305, CC_T305);
1646}
1647
1648static void
1649l3ni1_setup_rsp(struct l3_process *pc, u_char pr,
1650 void *arg)
1651{
1652 if (!pc->para.bchannel)
1653 { if (pc->debug & L3_DEB_WARN)
1654 l3_debug(pc->st, "D-chan connect for waiting call");
1655 l3ni1_disconnect_req(pc, pr, arg);
1656 return;
1657 }
1658 newl3state(pc, 8);
1659 if (pc->debug & L3_DEB_WARN)
1660 l3_debug(pc->st, "D-chan connect for waiting call");
1661 l3ni1_message_plus_chid(pc, MT_CONNECT); /* GE 05/09/00 */
1662 L3DelTimer(&pc->timer);
1663 L3AddTimer(&pc->timer, T313, CC_T313);
1664}
1665
1666static void
1667l3ni1_connect_ack(struct l3_process *pc, u_char pr, void *arg)
1668{
1669 struct sk_buff *skb = arg;
1670 int ret;
1671
1672 ret = check_infoelements(pc, skb, ie_CONNECT_ACKNOWLEDGE);
1673 if (ERR_IE_COMPREHENSION == ret) {
1674 l3ni1_std_ie_err(pc, ret);
1675 return;
1676 }
1677 newl3state(pc, 10);
1678 L3DelTimer(&pc->timer);
1679 if (ret)
1680 l3ni1_std_ie_err(pc, ret);
1681 pc->st->l3.l3l4(pc->st, CC_SETUP_COMPL | INDICATION, pc);
1682}
1683
1684static void
1685l3ni1_reject_req(struct l3_process *pc, u_char pr, void *arg)
1686{
1687 struct sk_buff *skb;
1688 u_char tmp[16];
1689 u_char *p = tmp;
1690 int l;
1691 u_char cause = 21;
1692
1693 if (pc->para.cause != NO_CAUSE)
1694 cause = pc->para.cause;
1695
1696 MsgHead(p, pc->callref, MT_RELEASE_COMPLETE);
1697
1698 *p++ = IE_CAUSE;
1699 *p++ = 0x2;
1700 *p++ = 0x80;
1701 *p++ = cause | 0x80;
1702
1703 l = p - tmp;
1704 if (!(skb = l3_alloc_skb(l)))
1705 return;
1706 memcpy(skb_put(skb, l), tmp, l);
1707 l3_msg(pc->st, DL_DATA | REQUEST, skb);
1708 pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
1709 newl3state(pc, 0);
1710 ni1_release_l3_process(pc);
1711}
1712
1713static void
1714l3ni1_release(struct l3_process *pc, u_char pr, void *arg)
1715{
1716 struct sk_buff *skb = arg;
1717 u_char *p;
1718 int ret, cause=0;
1719
1720 StopAllL3Timer(pc);
1721 if ((ret = l3ni1_get_cause(pc, skb))>0) {
1722 if (pc->debug & L3_DEB_WARN)
1723 l3_debug(pc->st, "REL get_cause ret(%d)", ret);
1724 } else if (ret<0)
1725 pc->para.cause = NO_CAUSE;
1726 if ((p = findie(skb->data, skb->len, IE_FACILITY, 0))) {
1727 l3ni1_parse_facility(pc->st, pc, pc->callref, p);
1728 }
1729 if ((ret<0) && (pc->state != 11))
1730 cause = 96;
1731 else if (ret>0)
1732 cause = 100;
1733 ret = check_infoelements(pc, skb, ie_RELEASE);
1734 if (ERR_IE_COMPREHENSION == ret)
1735 cause = 96;
1736 else if ((ERR_IE_UNRECOGNIZED == ret) && (!cause))
1737 cause = 99;
1738 if (cause)
1739 l3ni1_message_cause(pc, MT_RELEASE_COMPLETE, cause);
1740 else
1741 l3ni1_message(pc, MT_RELEASE_COMPLETE);
1742 pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
1743 newl3state(pc, 0);
1744 ni1_release_l3_process(pc);
1745}
1746
1747static void
1748l3ni1_alert_req(struct l3_process *pc, u_char pr,
1749 void *arg)
1750{
1751 newl3state(pc, 7);
1752 if (!pc->prot.ni1.uus1_data[0])
1753 l3ni1_message(pc, MT_ALERTING);
1754 else
1755 l3ni1_msg_with_uus(pc, MT_ALERTING);
1756}
1757
1758static void
1759l3ni1_proceed_req(struct l3_process *pc, u_char pr,
1760 void *arg)
1761{
1762 newl3state(pc, 9);
1763 l3ni1_message(pc, MT_CALL_PROCEEDING);
1764 pc->st->l3.l3l4(pc->st, CC_PROCEED_SEND | INDICATION, pc);
1765}
1766
1767static void
1768l3ni1_setup_ack_req(struct l3_process *pc, u_char pr,
1769 void *arg)
1770{
1771 newl3state(pc, 25);
1772 L3DelTimer(&pc->timer);
1773 L3AddTimer(&pc->timer, T302, CC_T302);
1774 l3ni1_message(pc, MT_SETUP_ACKNOWLEDGE);
1775}
1776
1777/********************************************/
1778/* deliver a incoming display message to HL */
1779/********************************************/
1780static void
1781l3ni1_deliver_display(struct l3_process *pc, int pr, u_char *infp)
1782{ u_char len;
1783 isdn_ctrl ic;
1784 struct IsdnCardState *cs;
1785 char *p;
1786
1787 if (*infp++ != IE_DISPLAY) return;
1788 if ((len = *infp++) > 80) return; /* total length <= 82 */
1789 if (!pc->chan) return;
1790
1791 p = ic.parm.display;
1792 while (len--)
1793 *p++ = *infp++;
1794 *p = '\0';
1795 ic.command = ISDN_STAT_DISPLAY;
1796 cs = pc->st->l1.hardware;
1797 ic.driver = cs->myid;
1798 ic.arg = pc->chan->chan;
1799 cs->iif.statcallb(&ic);
1800} /* l3ni1_deliver_display */
1801
1802
1803static void
1804l3ni1_progress(struct l3_process *pc, u_char pr, void *arg)
1805{
1806 struct sk_buff *skb = arg;
1807 int err = 0;
1808 u_char *p;
1809
1810 if ((p = findie(skb->data, skb->len, IE_PROGRESS, 0))) {
1811 if (p[1] != 2) {
1812 err = 1;
1813 pc->para.cause = 100;
1814 } else if (!(p[2] & 0x70)) {
1815 switch (p[2]) {
1816 case 0x80:
1817 case 0x81:
1818 case 0x82:
1819 case 0x84:
1820 case 0x85:
1821 case 0x87:
1822 case 0x8a:
1823 switch (p[3]) {
1824 case 0x81:
1825 case 0x82:
1826 case 0x83:
1827 case 0x84:
1828 case 0x88:
1829 break;
1830 default:
1831 err = 2;
1832 pc->para.cause = 100;
1833 break;
1834 }
1835 break;
1836 default:
1837 err = 3;
1838 pc->para.cause = 100;
1839 break;
1840 }
1841 }
1842 } else {
1843 pc->para.cause = 96;
1844 err = 4;
1845 }
1846 if (err) {
1847 if (pc->debug & L3_DEB_WARN)
1848 l3_debug(pc->st, "progress error %d", err);
1849 l3ni1_status_send(pc, pr, NULL);
1850 return;
1851 }
1852 /* Now we are on none mandatory IEs */
1853 err = check_infoelements(pc, skb, ie_PROGRESS);
1854 if (err)
1855 l3ni1_std_ie_err(pc, err);
1856 if (ERR_IE_COMPREHENSION != err)
1857 pc->st->l3.l3l4(pc->st, CC_PROGRESS | INDICATION, pc);
1858}
1859
1860static void
1861l3ni1_notify(struct l3_process *pc, u_char pr, void *arg)
1862{
1863 struct sk_buff *skb = arg;
1864 int err = 0;
1865 u_char *p;
1866
1867 if ((p = findie(skb->data, skb->len, IE_NOTIFY, 0))) {
1868 if (p[1] != 1) {
1869 err = 1;
1870 pc->para.cause = 100;
1871 } else {
1872 switch (p[2]) {
1873 case 0x80:
1874 case 0x81:
1875 case 0x82:
1876 break;
1877 default:
1878 pc->para.cause = 100;
1879 err = 2;
1880 break;
1881 }
1882 }
1883 } else {
1884 pc->para.cause = 96;
1885 err = 3;
1886 }
1887 if (err) {
1888 if (pc->debug & L3_DEB_WARN)
1889 l3_debug(pc->st, "notify error %d", err);
1890 l3ni1_status_send(pc, pr, NULL);
1891 return;
1892 }
1893 /* Now we are on none mandatory IEs */
1894 err = check_infoelements(pc, skb, ie_NOTIFY);
1895 if (err)
1896 l3ni1_std_ie_err(pc, err);
1897 if (ERR_IE_COMPREHENSION != err)
1898 pc->st->l3.l3l4(pc->st, CC_NOTIFY | INDICATION, pc);
1899}
1900
1901static void
1902l3ni1_status_enq(struct l3_process *pc, u_char pr, void *arg)
1903{
1904 int ret;
1905 struct sk_buff *skb = arg;
1906
1907 ret = check_infoelements(pc, skb, ie_STATUS_ENQUIRY);
1908 l3ni1_std_ie_err(pc, ret);
1909 pc->para.cause = 30; /* response to STATUS_ENQUIRY */
1910 l3ni1_status_send(pc, pr, NULL);
1911}
1912
1913static void
1914l3ni1_information(struct l3_process *pc, u_char pr, void *arg)
1915{
1916 int ret;
1917 struct sk_buff *skb = arg;
1918 u_char *p;
1919 char tmp[32];
1920
1921 ret = check_infoelements(pc, skb, ie_INFORMATION);
1922 if (ret)
1923 l3ni1_std_ie_err(pc, ret);
1924 if (pc->state == 25) { /* overlap receiving */
1925 L3DelTimer(&pc->timer);
1926 p = skb->data;
1927 if ((p = findie(p, skb->len, 0x70, 0))) {
1928 iecpy(tmp, p, 1);
1929 strcat(pc->para.setup.eazmsn, tmp);
1930 pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc);
1931 }
1932 L3AddTimer(&pc->timer, T302, CC_T302);
1933 }
1934}
1935
1936/******************************/
1937/* handle deflection requests */
1938/******************************/
1939static void l3ni1_redir_req(struct l3_process *pc, u_char pr, void *arg)
1940{
1941 struct sk_buff *skb;
1942 u_char tmp[128];
1943 u_char *p = tmp;
1944 u_char *subp;
1945 u_char len_phone = 0;
1946 u_char len_sub = 0;
1947 int l;
1948
1949
1950 strcpy(pc->prot.ni1.uus1_data,pc->chan->setup.eazmsn); /* copy uus element if available */
1951 if (!pc->chan->setup.phone[0])
1952 { pc->para.cause = -1;
1953 l3ni1_disconnect_req(pc,pr,arg); /* disconnect immediately */
1954 return;
1955 } /* only uus */
1956
1957 if (pc->prot.ni1.invoke_id)
1958 free_invoke_id(pc->st,pc->prot.ni1.invoke_id);
1959
1960 if (!(pc->prot.ni1.invoke_id = new_invoke_id(pc->st)))
1961 return;
1962
1963 MsgHead(p, pc->callref, MT_FACILITY);
1964
1965 for (subp = pc->chan->setup.phone; (*subp) && (*subp != '.'); subp++) len_phone++; /* len of phone number */
1966 if (*subp++ == '.') len_sub = strlen(subp) + 2; /* length including info subaddress element */
1967
1968 *p++ = 0x1c; /* Facility info element */
1969 *p++ = len_phone + len_sub + 2 + 2 + 8 + 3 + 3; /* length of element */
1970 *p++ = 0x91; /* remote operations protocol */
1971 *p++ = 0xa1; /* invoke component */
1972
1973 *p++ = len_phone + len_sub + 2 + 2 + 8 + 3; /* length of data */
1974 *p++ = 0x02; /* invoke id tag, integer */
1975 *p++ = 0x01; /* length */
1976 *p++ = pc->prot.ni1.invoke_id; /* invoke id */
1977 *p++ = 0x02; /* operation value tag, integer */
1978 *p++ = 0x01; /* length */
1979 *p++ = 0x0D; /* Call Deflect */
1980
1981 *p++ = 0x30; /* sequence phone number */
1982 *p++ = len_phone + 2 + 2 + 3 + len_sub; /* length */
1983
1984 *p++ = 0x30; /* Deflected to UserNumber */
1985 *p++ = len_phone+2+len_sub; /* length */
1986 *p++ = 0x80; /* NumberDigits */
1987 *p++ = len_phone; /* length */
1988 for (l = 0; l < len_phone; l++)
1989 *p++ = pc->chan->setup.phone[l];
1990
1991 if (len_sub)
1992 { *p++ = 0x04; /* called party subaddress */
1993 *p++ = len_sub - 2;
1994 while (*subp) *p++ = *subp++;
1995 }
1996
1997 *p++ = 0x01; /* screening identifier */
1998 *p++ = 0x01;
1999 *p++ = pc->chan->setup.screen;
2000
2001 l = p - tmp;
2002 if (!(skb = l3_alloc_skb(l))) return;
2003 memcpy(skb_put(skb, l), tmp, l);
2004
2005 l3_msg(pc->st, DL_DATA | REQUEST, skb);
2006} /* l3ni1_redir_req */
2007
2008/********************************************/
2009/* handle deflection request in early state */
2010/********************************************/
2011static void l3ni1_redir_req_early(struct l3_process *pc, u_char pr, void *arg)
2012{
2013 l3ni1_proceed_req(pc,pr,arg);
2014 l3ni1_redir_req(pc,pr,arg);
2015} /* l3ni1_redir_req_early */
2016
2017/***********************************************/
2018/* handle special commands for this protocol. */
2019/* Examples are call independant services like */
2020/* remote operations with dummy callref. */
2021/***********************************************/
2022static int l3ni1_cmd_global(struct PStack *st, isdn_ctrl *ic)
2023{ u_char id;
2024 u_char temp[265];
2025 u_char *p = temp;
2026 int i, l, proc_len;
2027 struct sk_buff *skb;
2028 struct l3_process *pc = NULL;
2029
2030 switch (ic->arg)
2031 { case NI1_CMD_INVOKE:
2032 if (ic->parm.ni1_io.datalen < 0) return(-2); /* invalid parameter */
2033
2034 for (proc_len = 1, i = ic->parm.ni1_io.proc >> 8; i; i++)
2035 i = i >> 8; /* add one byte */
2036 l = ic->parm.ni1_io.datalen + proc_len + 8; /* length excluding ie header */
2037 if (l > 255)
2038 return(-2); /* too long */
2039
2040 if (!(id = new_invoke_id(st)))
2041 return(0); /* first get a invoke id -> return if no available */
2042
2043 i = -1;
2044 MsgHead(p, i, MT_FACILITY); /* build message head */
2045 *p++ = 0x1C; /* Facility IE */
2046 *p++ = l; /* length of ie */
2047 *p++ = 0x91; /* remote operations */
2048 *p++ = 0xA1; /* invoke */
2049 *p++ = l - 3; /* length of invoke */
2050 *p++ = 0x02; /* invoke id tag */
2051 *p++ = 0x01; /* length is 1 */
2052 *p++ = id; /* invoke id */
2053 *p++ = 0x02; /* operation */
2054 *p++ = proc_len; /* length of operation */
2055
2056 for (i = proc_len; i; i--)
2057 *p++ = (ic->parm.ni1_io.proc >> (i-1)) & 0xFF;
2058 memcpy(p, ic->parm.ni1_io.data, ic->parm.ni1_io.datalen); /* copy data */
2059 l = (p - temp) + ic->parm.ni1_io.datalen; /* total length */
2060
2061 if (ic->parm.ni1_io.timeout > 0)
2062 if (!(pc = ni1_new_l3_process(st, -1)))
2063 { free_invoke_id(st, id);
2064 return(-2);
2065 }
2066 pc->prot.ni1.ll_id = ic->parm.ni1_io.ll_id; /* remember id */
2067 pc->prot.ni1.proc = ic->parm.ni1_io.proc; /* and procedure */
2068
2069 if (!(skb = l3_alloc_skb(l)))
2070 { free_invoke_id(st, id);
2071 if (pc) ni1_release_l3_process(pc);
2072 return(-2);
2073 }
2074 memcpy(skb_put(skb, l), temp, l);
2075
2076 if (pc)
2077 { pc->prot.ni1.invoke_id = id; /* remember id */
2078 L3AddTimer(&pc->timer, ic->parm.ni1_io.timeout, CC_TNI1_IO | REQUEST);
2079 }
2080
2081 l3_msg(st, DL_DATA | REQUEST, skb);
2082 ic->parm.ni1_io.hl_id = id; /* return id */
2083 return(0);
2084
2085 case NI1_CMD_INVOKE_ABORT:
2086 if ((pc = l3ni1_search_dummy_proc(st, ic->parm.ni1_io.hl_id)))
2087 { L3DelTimer(&pc->timer); /* remove timer */
2088 ni1_release_l3_process(pc);
2089 return(0);
2090 }
2091 else
2092 { l3_debug(st, "l3ni1_cmd_global abort unknown id");
2093 return(-2);
2094 }
2095 break;
2096
2097 default:
2098 l3_debug(st, "l3ni1_cmd_global unknown cmd 0x%lx", ic->arg);
2099 return(-1);
2100 } /* switch ic-> arg */
2101 return(-1);
2102} /* l3ni1_cmd_global */
2103
2104static void
2105l3ni1_io_timer(struct l3_process *pc)
2106{ isdn_ctrl ic;
2107 struct IsdnCardState *cs = pc->st->l1.hardware;
2108
2109 L3DelTimer(&pc->timer); /* remove timer */
2110
2111 ic.driver = cs->myid;
2112 ic.command = ISDN_STAT_PROT;
2113 ic.arg = NI1_STAT_INVOKE_ERR;
2114 ic.parm.ni1_io.hl_id = pc->prot.ni1.invoke_id;
2115 ic.parm.ni1_io.ll_id = pc->prot.ni1.ll_id;
2116 ic.parm.ni1_io.proc = pc->prot.ni1.proc;
2117 ic.parm.ni1_io.timeout= -1;
2118 ic.parm.ni1_io.datalen = 0;
2119 ic.parm.ni1_io.data = NULL;
2120 free_invoke_id(pc->st, pc->prot.ni1.invoke_id);
2121 pc->prot.ni1.invoke_id = 0; /* reset id */
2122
2123 cs->iif.statcallb(&ic);
2124
2125 ni1_release_l3_process(pc);
2126} /* l3ni1_io_timer */
2127
2128static void
2129l3ni1_release_ind(struct l3_process *pc, u_char pr, void *arg)
2130{
2131 u_char *p;
2132 struct sk_buff *skb = arg;
2133 int callState = 0;
2134 p = skb->data;
2135
2136 if ((p = findie(p, skb->len, IE_CALL_STATE, 0))) {
2137 p++;
2138 if (1 == *p++)
2139 callState = *p;
2140 }
2141 if (callState == 0) {
2142 /* ETS 300-104 7.6.1, 8.6.1, 10.6.1... and 16.1
2143 * set down layer 3 without sending any message
2144 */
2145 pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
2146 newl3state(pc, 0);
2147 ni1_release_l3_process(pc);
2148 } else {
2149 pc->st->l3.l3l4(pc->st, CC_IGNORE | INDICATION, pc);
2150 }
2151}
2152
2153static void
2154l3ni1_dummy(struct l3_process *pc, u_char pr, void *arg)
2155{
2156}
2157
2158static void
2159l3ni1_t302(struct l3_process *pc, u_char pr, void *arg)
2160{
2161 L3DelTimer(&pc->timer);
2162 pc->para.loc = 0;
2163 pc->para.cause = 28; /* invalid number */
2164 l3ni1_disconnect_req(pc, pr, NULL);
2165 pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
2166}
2167
2168static void
2169l3ni1_t303(struct l3_process *pc, u_char pr, void *arg)
2170{
2171 if (pc->N303 > 0) {
2172 pc->N303--;
2173 L3DelTimer(&pc->timer);
2174 l3ni1_setup_req(pc, pr, arg);
2175 } else {
2176 L3DelTimer(&pc->timer);
2177 l3ni1_message_cause(pc, MT_RELEASE_COMPLETE, 102);
2178 pc->st->l3.l3l4(pc->st, CC_NOSETUP_RSP, pc);
2179 ni1_release_l3_process(pc);
2180 }
2181}
2182
2183static void
2184l3ni1_t304(struct l3_process *pc, u_char pr, void *arg)
2185{
2186 L3DelTimer(&pc->timer);
2187 pc->para.loc = 0;
2188 pc->para.cause = 102;
2189 l3ni1_disconnect_req(pc, pr, NULL);
2190 pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
2191
2192}
2193
2194static void
2195l3ni1_t305(struct l3_process *pc, u_char pr, void *arg)
2196{
2197 u_char tmp[16];
2198 u_char *p = tmp;
2199 int l;
2200 struct sk_buff *skb;
2201 u_char cause = 16;
2202
2203 L3DelTimer(&pc->timer);
2204 if (pc->para.cause != NO_CAUSE)
2205 cause = pc->para.cause;
2206
2207 MsgHead(p, pc->callref, MT_RELEASE);
2208
2209 *p++ = IE_CAUSE;
2210 *p++ = 0x2;
2211 *p++ = 0x80;
2212 *p++ = cause | 0x80;
2213
2214 l = p - tmp;
2215 if (!(skb = l3_alloc_skb(l)))
2216 return;
2217 memcpy(skb_put(skb, l), tmp, l);
2218 newl3state(pc, 19);
2219 l3_msg(pc->st, DL_DATA | REQUEST, skb);
2220 L3AddTimer(&pc->timer, T308, CC_T308_1);
2221}
2222
2223static void
2224l3ni1_t310(struct l3_process *pc, u_char pr, void *arg)
2225{
2226 L3DelTimer(&pc->timer);
2227 pc->para.loc = 0;
2228 pc->para.cause = 102;
2229 l3ni1_disconnect_req(pc, pr, NULL);
2230 pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
2231}
2232
2233static void
2234l3ni1_t313(struct l3_process *pc, u_char pr, void *arg)
2235{
2236 L3DelTimer(&pc->timer);
2237 pc->para.loc = 0;
2238 pc->para.cause = 102;
2239 l3ni1_disconnect_req(pc, pr, NULL);
2240 pc->st->l3.l3l4(pc->st, CC_CONNECT_ERR, pc);
2241}
2242
2243static void
2244l3ni1_t308_1(struct l3_process *pc, u_char pr, void *arg)
2245{
2246 newl3state(pc, 19);
2247 L3DelTimer(&pc->timer);
2248 l3ni1_message(pc, MT_RELEASE);
2249 L3AddTimer(&pc->timer, T308, CC_T308_2);
2250}
2251
2252static void
2253l3ni1_t308_2(struct l3_process *pc, u_char pr, void *arg)
2254{
2255 L3DelTimer(&pc->timer);
2256 pc->st->l3.l3l4(pc->st, CC_RELEASE_ERR, pc);
2257 ni1_release_l3_process(pc);
2258}
2259
2260static void
2261l3ni1_t318(struct l3_process *pc, u_char pr, void *arg)
2262{
2263 L3DelTimer(&pc->timer);
2264 pc->para.cause = 102; /* Timer expiry */
2265 pc->para.loc = 0; /* local */
2266 pc->st->l3.l3l4(pc->st, CC_RESUME_ERR, pc);
2267 newl3state(pc, 19);
2268 l3ni1_message(pc, MT_RELEASE);
2269 L3AddTimer(&pc->timer, T308, CC_T308_1);
2270}
2271
2272static void
2273l3ni1_t319(struct l3_process *pc, u_char pr, void *arg)
2274{
2275 L3DelTimer(&pc->timer);
2276 pc->para.cause = 102; /* Timer expiry */
2277 pc->para.loc = 0; /* local */
2278 pc->st->l3.l3l4(pc->st, CC_SUSPEND_ERR, pc);
2279 newl3state(pc, 10);
2280}
2281
2282static void
2283l3ni1_restart(struct l3_process *pc, u_char pr, void *arg)
2284{
2285 L3DelTimer(&pc->timer);
2286 pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
2287 ni1_release_l3_process(pc);
2288}
2289
2290static void
2291l3ni1_status(struct l3_process *pc, u_char pr, void *arg)
2292{
2293 u_char *p;
2294 struct sk_buff *skb = arg;
2295 int ret;
2296 u_char cause = 0, callState = 0;
2297
2298 if ((ret = l3ni1_get_cause(pc, skb))) {
2299 if (pc->debug & L3_DEB_WARN)
2300 l3_debug(pc->st, "STATUS get_cause ret(%d)",ret);
2301 if (ret < 0)
2302 cause = 96;
2303 else if (ret > 0)
2304 cause = 100;
2305 }
2306 if ((p = findie(skb->data, skb->len, IE_CALL_STATE, 0))) {
2307 p++;
2308 if (1 == *p++) {
2309 callState = *p;
2310 if (!ie_in_set(pc, *p, l3_valid_states))
2311 cause = 100;
2312 } else
2313 cause = 100;
2314 } else
2315 cause = 96;
2316 if (!cause) { /* no error before */
2317 ret = check_infoelements(pc, skb, ie_STATUS);
2318 if (ERR_IE_COMPREHENSION == ret)
2319 cause = 96;
2320 else if (ERR_IE_UNRECOGNIZED == ret)
2321 cause = 99;
2322 }
2323 if (cause) {
2324 u_char tmp;
2325
2326 if (pc->debug & L3_DEB_WARN)
2327 l3_debug(pc->st, "STATUS error(%d/%d)",ret,cause);
2328 tmp = pc->para.cause;
2329 pc->para.cause = cause;
2330 l3ni1_status_send(pc, 0, NULL);
2331 if (cause == 99)
2332 pc->para.cause = tmp;
2333 else
2334 return;
2335 }
2336 cause = pc->para.cause;
2337 if (((cause & 0x7f) == 111) && (callState == 0)) {
2338 /* ETS 300-104 7.6.1, 8.6.1, 10.6.1...
2339 * if received MT_STATUS with cause == 111 and call
2340 * state == 0, then we must set down layer 3
2341 */
2342 pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
2343 newl3state(pc, 0);
2344 ni1_release_l3_process(pc);
2345 }
2346}
2347
2348static void
2349l3ni1_facility(struct l3_process *pc, u_char pr, void *arg)
2350{
2351 struct sk_buff *skb = arg;
2352 int ret;
2353
2354 ret = check_infoelements(pc, skb, ie_FACILITY);
2355 l3ni1_std_ie_err(pc, ret);
2356 {
2357 u_char *p;
2358 if ((p = findie(skb->data, skb->len, IE_FACILITY, 0)))
2359 l3ni1_parse_facility(pc->st, pc, pc->callref, p);
2360 }
2361}
2362
2363static void
2364l3ni1_suspend_req(struct l3_process *pc, u_char pr, void *arg)
2365{
2366 struct sk_buff *skb;
2367 u_char tmp[32];
2368 u_char *p = tmp;
2369 u_char i, l;
2370 u_char *msg = pc->chan->setup.phone;
2371
2372 MsgHead(p, pc->callref, MT_SUSPEND);
2373 l = *msg++;
2374 if (l && (l <= 10)) { /* Max length 10 octets */
2375 *p++ = IE_CALL_ID;
2376 *p++ = l;
2377 for (i = 0; i < l; i++)
2378 *p++ = *msg++;
2379 } else if (l) {
2380 l3_debug(pc->st, "SUS wrong CALL_ID len %d", l);
2381 return;
2382 }
2383 l = p - tmp;
2384 if (!(skb = l3_alloc_skb(l)))
2385 return;
2386 memcpy(skb_put(skb, l), tmp, l);
2387 l3_msg(pc->st, DL_DATA | REQUEST, skb);
2388 newl3state(pc, 15);
2389 L3AddTimer(&pc->timer, T319, CC_T319);
2390}
2391
2392static void
2393l3ni1_suspend_ack(struct l3_process *pc, u_char pr, void *arg)
2394{
2395 struct sk_buff *skb = arg;
2396 int ret;
2397
2398 L3DelTimer(&pc->timer);
2399 newl3state(pc, 0);
2400 pc->para.cause = NO_CAUSE;
2401 pc->st->l3.l3l4(pc->st, CC_SUSPEND | CONFIRM, pc);
2402 /* We don't handle suspend_ack for IE errors now */
2403 if ((ret = check_infoelements(pc, skb, ie_SUSPEND_ACKNOWLEDGE)))
2404 if (pc->debug & L3_DEB_WARN)
2405 l3_debug(pc->st, "SUSPACK check ie(%d)",ret);
2406 ni1_release_l3_process(pc);
2407}
2408
2409static void
2410l3ni1_suspend_rej(struct l3_process *pc, u_char pr, void *arg)
2411{
2412 struct sk_buff *skb = arg;
2413 int ret;
2414
2415 if ((ret = l3ni1_get_cause(pc, skb))) {
2416 if (pc->debug & L3_DEB_WARN)
2417 l3_debug(pc->st, "SUSP_REJ get_cause ret(%d)",ret);
2418 if (ret < 0)
2419 pc->para.cause = 96;
2420 else
2421 pc->para.cause = 100;
2422 l3ni1_status_send(pc, pr, NULL);
2423 return;
2424 }
2425 ret = check_infoelements(pc, skb, ie_SUSPEND_REJECT);
2426 if (ERR_IE_COMPREHENSION == ret) {
2427 l3ni1_std_ie_err(pc, ret);
2428 return;
2429 }
2430 L3DelTimer(&pc->timer);
2431 pc->st->l3.l3l4(pc->st, CC_SUSPEND_ERR, pc);
2432 newl3state(pc, 10);
2433 if (ret) /* STATUS for none mandatory IE errors after actions are taken */
2434 l3ni1_std_ie_err(pc, ret);
2435}
2436
2437static void
2438l3ni1_resume_req(struct l3_process *pc, u_char pr, void *arg)
2439{
2440 struct sk_buff *skb;
2441 u_char tmp[32];
2442 u_char *p = tmp;
2443 u_char i, l;
2444 u_char *msg = pc->para.setup.phone;
2445
2446 MsgHead(p, pc->callref, MT_RESUME);
2447
2448 l = *msg++;
2449 if (l && (l <= 10)) { /* Max length 10 octets */
2450 *p++ = IE_CALL_ID;
2451 *p++ = l;
2452 for (i = 0; i < l; i++)
2453 *p++ = *msg++;
2454 } else if (l) {
2455 l3_debug(pc->st, "RES wrong CALL_ID len %d", l);
2456 return;
2457 }
2458 l = p - tmp;
2459 if (!(skb = l3_alloc_skb(l)))
2460 return;
2461 memcpy(skb_put(skb, l), tmp, l);
2462 l3_msg(pc->st, DL_DATA | REQUEST, skb);
2463 newl3state(pc, 17);
2464 L3AddTimer(&pc->timer, T318, CC_T318);
2465}
2466
2467static void
2468l3ni1_resume_ack(struct l3_process *pc, u_char pr, void *arg)
2469{
2470 struct sk_buff *skb = arg;
2471 int id, ret;
2472
2473 if ((id = l3ni1_get_channel_id(pc, skb)) > 0) {
2474 if ((0 == id) || ((3 == id) && (0x10 == pc->para.moderate))) {
2475 if (pc->debug & L3_DEB_WARN)
2476 l3_debug(pc->st, "resume ack with wrong chid %x", id);
2477 pc->para.cause = 100;
2478 l3ni1_status_send(pc, pr, NULL);
2479 return;
2480 }
2481 pc->para.bchannel = id;
2482 } else if (1 == pc->state) {
2483 if (pc->debug & L3_DEB_WARN)
2484 l3_debug(pc->st, "resume ack without chid (ret %d)", id);
2485 pc->para.cause = 96;
2486 l3ni1_status_send(pc, pr, NULL);
2487 return;
2488 }
2489 ret = check_infoelements(pc, skb, ie_RESUME_ACKNOWLEDGE);
2490 if (ERR_IE_COMPREHENSION == ret) {
2491 l3ni1_std_ie_err(pc, ret);
2492 return;
2493 }
2494 L3DelTimer(&pc->timer);
2495 pc->st->l3.l3l4(pc->st, CC_RESUME | CONFIRM, pc);
2496 newl3state(pc, 10);
2497 if (ret) /* STATUS for none mandatory IE errors after actions are taken */
2498 l3ni1_std_ie_err(pc, ret);
2499}
2500
2501static void
2502l3ni1_resume_rej(struct l3_process *pc, u_char pr, void *arg)
2503{
2504 struct sk_buff *skb = arg;
2505 int ret;
2506
2507 if ((ret = l3ni1_get_cause(pc, skb))) {
2508 if (pc->debug & L3_DEB_WARN)
2509 l3_debug(pc->st, "RES_REJ get_cause ret(%d)",ret);
2510 if (ret < 0)
2511 pc->para.cause = 96;
2512 else
2513 pc->para.cause = 100;
2514 l3ni1_status_send(pc, pr, NULL);
2515 return;
2516 }
2517 ret = check_infoelements(pc, skb, ie_RESUME_REJECT);
2518 if (ERR_IE_COMPREHENSION == ret) {
2519 l3ni1_std_ie_err(pc, ret);
2520 return;
2521 }
2522 L3DelTimer(&pc->timer);
2523 pc->st->l3.l3l4(pc->st, CC_RESUME_ERR, pc);
2524 newl3state(pc, 0);
2525 if (ret) /* STATUS for none mandatory IE errors after actions are taken */
2526 l3ni1_std_ie_err(pc, ret);
2527 ni1_release_l3_process(pc);
2528}
2529
2530static void
2531l3ni1_global_restart(struct l3_process *pc, u_char pr, void *arg)
2532{
2533 u_char tmp[32];
2534 u_char *p;
2535 u_char ri, ch = 0, chan = 0;
2536 int l;
2537 struct sk_buff *skb = arg;
2538 struct l3_process *up;
2539
2540 newl3state(pc, 2);
2541 L3DelTimer(&pc->timer);
2542 p = skb->data;
2543 if ((p = findie(p, skb->len, IE_RESTART_IND, 0))) {
2544 ri = p[2];
2545 l3_debug(pc->st, "Restart %x", ri);
2546 } else {
2547 l3_debug(pc->st, "Restart without restart IE");
2548 ri = 0x86;
2549 }
2550 p = skb->data;
2551 if ((p = findie(p, skb->len, IE_CHANNEL_ID, 0))) {
2552 chan = p[2] & 3;
2553 ch = p[2];
2554 if (pc->st->l3.debug)
2555 l3_debug(pc->st, "Restart for channel %d", chan);
2556 }
2557 newl3state(pc, 2);
2558 up = pc->st->l3.proc;
2559 while (up) {
2560 if ((ri & 7) == 7)
2561 up->st->lli.l4l3(up->st, CC_RESTART | REQUEST, up);
2562 else if (up->para.bchannel == chan)
2563 up->st->lli.l4l3(up->st, CC_RESTART | REQUEST, up);
2564
2565 up = up->next;
2566 }
2567 p = tmp;
2568 MsgHead(p, pc->callref, MT_RESTART_ACKNOWLEDGE);
2569 if (chan) {
2570 *p++ = IE_CHANNEL_ID;
2571 *p++ = 1;
2572 *p++ = ch | 0x80;
2573 }
2574 *p++ = 0x79; /* RESTART Ind */
2575 *p++ = 1;
2576 *p++ = ri;
2577 l = p - tmp;
2578 if (!(skb = l3_alloc_skb(l)))
2579 return;
2580 memcpy(skb_put(skb, l), tmp, l);
2581 newl3state(pc, 0);
2582 l3_msg(pc->st, DL_DATA | REQUEST, skb);
2583}
2584
2585static void
2586l3ni1_dl_reset(struct l3_process *pc, u_char pr, void *arg)
2587{
2588 pc->para.cause = 0x29; /* Temporary failure */
2589 pc->para.loc = 0;
2590 l3ni1_disconnect_req(pc, pr, NULL);
2591 pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
2592}
2593
2594static void
2595l3ni1_dl_release(struct l3_process *pc, u_char pr, void *arg)
2596{
2597 newl3state(pc, 0);
2598 pc->para.cause = 0x1b; /* Destination out of order */
2599 pc->para.loc = 0;
2600 pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
2601 release_l3_process(pc);
2602}
2603
2604static void
2605l3ni1_dl_reestablish(struct l3_process *pc, u_char pr, void *arg)
2606{
2607 L3DelTimer(&pc->timer);
2608 L3AddTimer(&pc->timer, T309, CC_T309);
2609 l3_msg(pc->st, DL_ESTABLISH | REQUEST, NULL);
2610}
2611
2612static void
2613l3ni1_dl_reest_status(struct l3_process *pc, u_char pr, void *arg)
2614{
2615 L3DelTimer(&pc->timer);
2616
2617 pc->para.cause = 0x1F; /* normal, unspecified */
2618 l3ni1_status_send(pc, 0, NULL);
2619}
2620
2621static void l3ni1_SendSpid( struct l3_process *pc, u_char pr, struct sk_buff *skb, int iNewState )
2622{
2623 u_char * p;
2624 char * pSPID;
2625 struct Channel * pChan = pc->st->lli.userdata;
2626 int l;
2627
2628 if ( skb )
2629 dev_kfree_skb( skb);
2630
2631 if ( !( pSPID = strchr( pChan->setup.eazmsn, ':' ) ) )
2632 {
2633 printk( KERN_ERR "SPID not supplied in EAZMSN %s\n", pChan->setup.eazmsn );
2634 newl3state( pc, 0 );
2635 pc->st->l3.l3l2( pc->st, DL_RELEASE | REQUEST, NULL );
2636 return;
2637 }
2638
2639 l = strlen( ++pSPID );
2640 if ( !( skb = l3_alloc_skb( 5+l ) ) )
2641 {
2642 printk( KERN_ERR "HiSax can't get memory to send SPID\n" );
2643 return;
2644 }
2645
2646 p = skb_put( skb, 5 );
2647 *p++ = PROTO_DIS_EURO;
2648 *p++ = 0;
2649 *p++ = MT_INFORMATION;
2650 *p++ = IE_SPID;
2651 *p++ = l;
2652
2653 memcpy( skb_put( skb, l ), pSPID, l );
2654
2655 newl3state( pc, iNewState );
2656
2657 L3DelTimer( &pc->timer );
2658 L3AddTimer( &pc->timer, TSPID, CC_TSPID );
2659
2660 pc->st->l3.l3l2( pc->st, DL_DATA | REQUEST, skb );
2661}
2662
2663static void l3ni1_spid_send( struct l3_process *pc, u_char pr, void *arg )
2664{
2665 l3ni1_SendSpid( pc, pr, arg, 20 );
2666}
2667
2668void l3ni1_spid_epid( struct l3_process *pc, u_char pr, void *arg )
2669{
2670 struct sk_buff *skb = arg;
2671
2672 if ( skb->data[ 1 ] == 0 )
2673 if ( skb->data[ 3 ] == IE_ENDPOINT_ID )
2674 {
2675 L3DelTimer( &pc->timer );
2676 newl3state( pc, 0 );
2677 l3_msg( pc->st, DL_ESTABLISH | CONFIRM, NULL );
2678 }
2679 dev_kfree_skb( skb);
2680}
2681
2682static void l3ni1_spid_tout( struct l3_process *pc, u_char pr, void *arg )
2683{
2684 if ( pc->state < 22 )
2685 l3ni1_SendSpid( pc, pr, arg, pc->state+1 );
2686 else
2687 {
2688 L3DelTimer( &pc->timer );
2689 dev_kfree_skb( arg);
2690
2691 printk( KERN_ERR "SPID not accepted\n" );
2692 newl3state( pc, 0 );
2693 pc->st->l3.l3l2( pc->st, DL_RELEASE | REQUEST, NULL );
2694 }
2695}
2696
2697/* *INDENT-OFF* */
2698static struct stateentry downstatelist[] =
2699{
2700 {SBIT(0),
2701 CC_SETUP | REQUEST, l3ni1_setup_req},
2702 {SBIT(0),
2703 CC_RESUME | REQUEST, l3ni1_resume_req},
2704 {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(6) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(25),
2705 CC_DISCONNECT | REQUEST, l3ni1_disconnect_req},
2706 {SBIT(12),
2707 CC_RELEASE | REQUEST, l3ni1_release_req},
2708 {ALL_STATES,
2709 CC_RESTART | REQUEST, l3ni1_restart},
2710 {SBIT(6) | SBIT(25),
2711 CC_IGNORE | REQUEST, l3ni1_reset},
2712 {SBIT(6) | SBIT(25),
2713 CC_REJECT | REQUEST, l3ni1_reject_req},
2714 {SBIT(6) | SBIT(25),
2715 CC_PROCEED_SEND | REQUEST, l3ni1_proceed_req},
2716 {SBIT(6),
2717 CC_MORE_INFO | REQUEST, l3ni1_setup_ack_req},
2718 {SBIT(25),
2719 CC_MORE_INFO | REQUEST, l3ni1_dummy},
2720 {SBIT(6) | SBIT(9) | SBIT(25),
2721 CC_ALERTING | REQUEST, l3ni1_alert_req},
2722 {SBIT(6) | SBIT(7) | SBIT(9) | SBIT(25),
2723 CC_SETUP | RESPONSE, l3ni1_setup_rsp},
2724 {SBIT(10),
2725 CC_SUSPEND | REQUEST, l3ni1_suspend_req},
2726 {SBIT(7) | SBIT(9) | SBIT(25),
2727 CC_REDIR | REQUEST, l3ni1_redir_req},
2728 {SBIT(6),
2729 CC_REDIR | REQUEST, l3ni1_redir_req_early},
2730 {SBIT(9) | SBIT(25),
2731 CC_DISCONNECT | REQUEST, l3ni1_disconnect_req},
2732 {SBIT(25),
2733 CC_T302, l3ni1_t302},
2734 {SBIT(1),
2735 CC_T303, l3ni1_t303},
2736 {SBIT(2),
2737 CC_T304, l3ni1_t304},
2738 {SBIT(3),
2739 CC_T310, l3ni1_t310},
2740 {SBIT(8),
2741 CC_T313, l3ni1_t313},
2742 {SBIT(11),
2743 CC_T305, l3ni1_t305},
2744 {SBIT(15),
2745 CC_T319, l3ni1_t319},
2746 {SBIT(17),
2747 CC_T318, l3ni1_t318},
2748 {SBIT(19),
2749 CC_T308_1, l3ni1_t308_1},
2750 {SBIT(19),
2751 CC_T308_2, l3ni1_t308_2},
2752 {SBIT(10),
2753 CC_T309, l3ni1_dl_release},
2754 { SBIT( 20 ) | SBIT( 21 ) | SBIT( 22 ),
2755 CC_TSPID, l3ni1_spid_tout },
2756};
2757
2758#define DOWNSLLEN \
2759 (sizeof(downstatelist) / sizeof(struct stateentry))
2760
2761static struct stateentry datastatelist[] =
2762{
2763 {ALL_STATES,
2764 MT_STATUS_ENQUIRY, l3ni1_status_enq},
2765 {ALL_STATES,
2766 MT_FACILITY, l3ni1_facility},
2767 {SBIT(19),
2768 MT_STATUS, l3ni1_release_ind},
2769 {ALL_STATES,
2770 MT_STATUS, l3ni1_status},
2771 {SBIT(0),
2772 MT_SETUP, l3ni1_setup},
2773 {SBIT(6) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(11) | SBIT(12) |
2774 SBIT(15) | SBIT(17) | SBIT(19) | SBIT(25),
2775 MT_SETUP, l3ni1_dummy},
2776 {SBIT(1) | SBIT(2),
2777 MT_CALL_PROCEEDING, l3ni1_call_proc},
2778 {SBIT(1),
2779 MT_SETUP_ACKNOWLEDGE, l3ni1_setup_ack},
2780 {SBIT(2) | SBIT(3),
2781 MT_ALERTING, l3ni1_alerting},
2782 {SBIT(2) | SBIT(3),
2783 MT_PROGRESS, l3ni1_progress},
2784 {SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) |
2785 SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(19) | SBIT(25),
2786 MT_INFORMATION, l3ni1_information},
2787 {SBIT(10) | SBIT(11) | SBIT(15),
2788 MT_NOTIFY, l3ni1_notify},
2789 {SBIT(0) | SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(10) |
2790 SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(19) | SBIT(25),
2791 MT_RELEASE_COMPLETE, l3ni1_release_cmpl},
2792 {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(25),
2793 MT_RELEASE, l3ni1_release},
2794 {SBIT(19), MT_RELEASE, l3ni1_release_ind},
2795 {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(11) | SBIT(15) | SBIT(17) | SBIT(25),
2796 MT_DISCONNECT, l3ni1_disconnect},
2797 {SBIT(19),
2798 MT_DISCONNECT, l3ni1_dummy},
2799 {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4),
2800 MT_CONNECT, l3ni1_connect},
2801 {SBIT(8),
2802 MT_CONNECT_ACKNOWLEDGE, l3ni1_connect_ack},
2803 {SBIT(15),
2804 MT_SUSPEND_ACKNOWLEDGE, l3ni1_suspend_ack},
2805 {SBIT(15),
2806 MT_SUSPEND_REJECT, l3ni1_suspend_rej},
2807 {SBIT(17),
2808 MT_RESUME_ACKNOWLEDGE, l3ni1_resume_ack},
2809 {SBIT(17),
2810 MT_RESUME_REJECT, l3ni1_resume_rej},
2811};
2812
2813#define DATASLLEN \
2814 (sizeof(datastatelist) / sizeof(struct stateentry))
2815
2816static struct stateentry globalmes_list[] =
2817{
2818 {ALL_STATES,
2819 MT_STATUS, l3ni1_status},
2820 {SBIT(0),
2821 MT_RESTART, l3ni1_global_restart},
2822/* {SBIT(1),
2823 MT_RESTART_ACKNOWLEDGE, l3ni1_restart_ack},
2824*/
2825 { SBIT( 0 ), MT_DL_ESTABLISHED, l3ni1_spid_send },
2826 { SBIT( 20 ) | SBIT( 21 ) | SBIT( 22 ), MT_INFORMATION, l3ni1_spid_epid },
2827};
2828#define GLOBALM_LEN \
2829 (sizeof(globalmes_list) / sizeof(struct stateentry))
2830
2831static struct stateentry manstatelist[] =
2832{
2833 {SBIT(2),
2834 DL_ESTABLISH | INDICATION, l3ni1_dl_reset},
2835 {SBIT(10),
2836 DL_ESTABLISH | CONFIRM, l3ni1_dl_reest_status},
2837 {SBIT(10),
2838 DL_RELEASE | INDICATION, l3ni1_dl_reestablish},
2839 {ALL_STATES,
2840 DL_RELEASE | INDICATION, l3ni1_dl_release},
2841};
2842
2843#define MANSLLEN \
2844 (sizeof(manstatelist) / sizeof(struct stateentry))
2845/* *INDENT-ON* */
2846
2847
2848static void
2849global_handler(struct PStack *st, int mt, struct sk_buff *skb)
2850{
2851 u_char tmp[16];
2852 u_char *p = tmp;
2853 int l;
2854 int i;
2855 struct l3_process *proc = st->l3.global;
2856
2857 if ( skb )
2858 proc->callref = skb->data[2]; /* cr flag */
2859 else
2860 proc->callref = 0;
2861 for (i = 0; i < GLOBALM_LEN; i++)
2862 if ((mt == globalmes_list[i].primitive) &&
2863 ((1 << proc->state) & globalmes_list[i].state))
2864 break;
2865 if (i == GLOBALM_LEN) {
2866 if (st->l3.debug & L3_DEB_STATE) {
2867 l3_debug(st, "ni1 global state %d mt %x unhandled",
2868 proc->state, mt);
2869 }
2870 MsgHead(p, proc->callref, MT_STATUS);
2871 *p++ = IE_CAUSE;
2872 *p++ = 0x2;
2873 *p++ = 0x80;
2874 *p++ = 81 |0x80; /* invalid cr */
2875 *p++ = 0x14; /* CallState */
2876 *p++ = 0x1;
2877 *p++ = proc->state & 0x3f;
2878 l = p - tmp;
2879 if (!(skb = l3_alloc_skb(l)))
2880 return;
2881 memcpy(skb_put(skb, l), tmp, l);
2882 l3_msg(proc->st, DL_DATA | REQUEST, skb);
2883 } else {
2884 if (st->l3.debug & L3_DEB_STATE) {
2885 l3_debug(st, "ni1 global %d mt %x",
2886 proc->state, mt);
2887 }
2888 globalmes_list[i].rout(proc, mt, skb);
2889 }
2890}
2891
2892static void
2893ni1up(struct PStack *st, int pr, void *arg)
2894{
2895 int i, mt, cr, cause, callState;
2896 char *ptr;
2897 u_char *p;
2898 struct sk_buff *skb = arg;
2899 struct l3_process *proc;
2900
2901 switch (pr) {
2902 case (DL_DATA | INDICATION):
2903 case (DL_UNIT_DATA | INDICATION):
2904 break;
2905 case (DL_ESTABLISH | INDICATION):
2906 case (DL_RELEASE | INDICATION):
2907 case (DL_RELEASE | CONFIRM):
2908 l3_msg(st, pr, arg);
2909 return;
2910 break;
2911
2912 case (DL_ESTABLISH | CONFIRM):
2913 global_handler( st, MT_DL_ESTABLISHED, NULL );
2914 return;
2915
2916 default:
2917 printk(KERN_ERR "HiSax ni1up unknown pr=%04x\n", pr);
2918 return;
2919 }
2920 if (skb->len < 3) {
2921 l3_debug(st, "ni1up frame too short(%d)", skb->len);
2922 dev_kfree_skb(skb);
2923 return;
2924 }
2925
2926 if (skb->data[0] != PROTO_DIS_EURO) {
2927 if (st->l3.debug & L3_DEB_PROTERR) {
2928 l3_debug(st, "ni1up%sunexpected discriminator %x message len %d",
2929 (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ",
2930 skb->data[0], skb->len);
2931 }
2932 dev_kfree_skb(skb);
2933 return;
2934 }
2935 cr = getcallref(skb->data);
2936 if (skb->len < ((skb->data[1] & 0x0f) + 3)) {
2937 l3_debug(st, "ni1up frame too short(%d)", skb->len);
2938 dev_kfree_skb(skb);
2939 return;
2940 }
2941 mt = skb->data[skb->data[1] + 2];
2942 if (st->l3.debug & L3_DEB_STATE)
2943 l3_debug(st, "ni1up cr %d", cr);
2944 if (cr == -2) { /* wrong Callref */
2945 if (st->l3.debug & L3_DEB_WARN)
2946 l3_debug(st, "ni1up wrong Callref");
2947 dev_kfree_skb(skb);
2948 return;
2949 } else if (cr == -1) { /* Dummy Callref */
2950 if (mt == MT_FACILITY)
2951 {
2952 if ((p = findie(skb->data, skb->len, IE_FACILITY, 0))) {
2953 l3ni1_parse_facility(st, NULL,
2954 (pr == (DL_DATA | INDICATION)) ? -1 : -2, p);
2955 dev_kfree_skb(skb);
2956 return;
2957 }
2958 }
2959 else
2960 {
2961 global_handler(st, mt, skb);
2962 return;
2963 }
2964
2965 if (st->l3.debug & L3_DEB_WARN)
2966 l3_debug(st, "ni1up dummy Callref (no facility msg or ie)");
2967 dev_kfree_skb(skb);
2968 return;
2969 } else if ((((skb->data[1] & 0x0f) == 1) && (0==(cr & 0x7f))) ||
2970 (((skb->data[1] & 0x0f) == 2) && (0==(cr & 0x7fff)))) { /* Global CallRef */
2971 if (st->l3.debug & L3_DEB_STATE)
2972 l3_debug(st, "ni1up Global CallRef");
2973 global_handler(st, mt, skb);
2974 dev_kfree_skb(skb);
2975 return;
2976 } else if (!(proc = getl3proc(st, cr))) {
2977 /* No transaction process exist, that means no call with
2978 * this callreference is active
2979 */
2980 if (mt == MT_SETUP) {
2981 /* Setup creates a new transaction process */
2982 if (skb->data[2] & 0x80) {
2983 /* Setup with wrong CREF flag */
2984 if (st->l3.debug & L3_DEB_STATE)
2985 l3_debug(st, "ni1up wrong CRef flag");
2986 dev_kfree_skb(skb);
2987 return;
2988 }
2989 if (!(proc = ni1_new_l3_process(st, cr))) {
2990 /* May be to answer with RELEASE_COMPLETE and
2991 * CAUSE 0x2f "Resource unavailable", but this
2992 * need a new_l3_process too ... arghh
2993 */
2994 dev_kfree_skb(skb);
2995 return;
2996 }
2997 } else if (mt == MT_STATUS) {
2998 cause = 0;
2999 if ((ptr = findie(skb->data, skb->len, IE_CAUSE, 0)) != NULL) {
3000 ptr++;
3001 if (*ptr++ == 2)
3002 ptr++;
3003 cause = *ptr & 0x7f;
3004 }
3005 callState = 0;
3006 if ((ptr = findie(skb->data, skb->len, IE_CALL_STATE, 0)) != NULL) {
3007 ptr++;
3008 if (*ptr++ == 2)
3009 ptr++;
3010 callState = *ptr;
3011 }
3012 /* ETS 300-104 part 2.4.1
3013 * if setup has not been made and a message type
3014 * MT_STATUS is received with call state == 0,
3015 * we must send nothing
3016 */
3017 if (callState != 0) {
3018 /* ETS 300-104 part 2.4.2
3019 * if setup has not been made and a message type
3020 * MT_STATUS is received with call state != 0,
3021 * we must send MT_RELEASE_COMPLETE cause 101
3022 */
3023 if ((proc = ni1_new_l3_process(st, cr))) {
3024 proc->para.cause = 101;
3025 l3ni1_msg_without_setup(proc, 0, NULL);
3026 }
3027 }
3028 dev_kfree_skb(skb);
3029 return;
3030 } else if (mt == MT_RELEASE_COMPLETE) {
3031 dev_kfree_skb(skb);
3032 return;
3033 } else {
3034 /* ETS 300-104 part 2
3035 * if setup has not been made and a message type
3036 * (except MT_SETUP and RELEASE_COMPLETE) is received,
3037 * we must send MT_RELEASE_COMPLETE cause 81 */
3038 dev_kfree_skb(skb);
3039 if ((proc = ni1_new_l3_process(st, cr))) {
3040 proc->para.cause = 81;
3041 l3ni1_msg_without_setup(proc, 0, NULL);
3042 }
3043 return;
3044 }
3045 }
3046 if (l3ni1_check_messagetype_validity(proc, mt, skb)) {
3047 dev_kfree_skb(skb);
3048 return;
3049 }
3050 if ((p = findie(skb->data, skb->len, IE_DISPLAY, 0)) != NULL)
3051 l3ni1_deliver_display(proc, pr, p); /* Display IE included */
3052 for (i = 0; i < DATASLLEN; i++)
3053 if ((mt == datastatelist[i].primitive) &&
3054 ((1 << proc->state) & datastatelist[i].state))
3055 break;
3056 if (i == DATASLLEN) {
3057 if (st->l3.debug & L3_DEB_STATE) {
3058 l3_debug(st, "ni1up%sstate %d mt %#x unhandled",
3059 (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ",
3060 proc->state, mt);
3061 }
3062 if ((MT_RELEASE_COMPLETE != mt) && (MT_RELEASE != mt)) {
3063 proc->para.cause = 101;
3064 l3ni1_status_send(proc, pr, skb);
3065 }
3066 } else {
3067 if (st->l3.debug & L3_DEB_STATE) {
3068 l3_debug(st, "ni1up%sstate %d mt %x",
3069 (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ",
3070 proc->state, mt);
3071 }
3072 datastatelist[i].rout(proc, pr, skb);
3073 }
3074 dev_kfree_skb(skb);
3075 return;
3076}
3077
3078static void
3079ni1down(struct PStack *st, int pr, void *arg)
3080{
3081 int i, cr;
3082 struct l3_process *proc;
3083 struct Channel *chan;
3084
3085 if ((DL_ESTABLISH | REQUEST) == pr) {
3086 l3_msg(st, pr, NULL);
3087 return;
3088 } else if (((CC_SETUP | REQUEST) == pr) || ((CC_RESUME | REQUEST) == pr)) {
3089 chan = arg;
3090 cr = newcallref();
3091 cr |= 0x80;
3092 if ((proc = ni1_new_l3_process(st, cr))) {
3093 proc->chan = chan;
3094 chan->proc = proc;
3095 memcpy(&proc->para.setup, &chan->setup, sizeof(setup_parm));
3096 proc->callref = cr;
3097 }
3098 } else {
3099 proc = arg;
3100 }
3101 if (!proc) {
3102 printk(KERN_ERR "HiSax ni1down without proc pr=%04x\n", pr);
3103 return;
3104 }
3105
3106 if ( pr == (CC_TNI1_IO | REQUEST)) {
3107 l3ni1_io_timer(proc); /* timer expires */
3108 return;
3109 }
3110
3111 for (i = 0; i < DOWNSLLEN; i++)
3112 if ((pr == downstatelist[i].primitive) &&
3113 ((1 << proc->state) & downstatelist[i].state))
3114 break;
3115 if (i == DOWNSLLEN) {
3116 if (st->l3.debug & L3_DEB_STATE) {
3117 l3_debug(st, "ni1down state %d prim %#x unhandled",
3118 proc->state, pr);
3119 }
3120 } else {
3121 if (st->l3.debug & L3_DEB_STATE) {
3122 l3_debug(st, "ni1down state %d prim %#x",
3123 proc->state, pr);
3124 }
3125 downstatelist[i].rout(proc, pr, arg);
3126 }
3127}
3128
3129static void
3130ni1man(struct PStack *st, int pr, void *arg)
3131{
3132 int i;
3133 struct l3_process *proc = arg;
3134
3135 if (!proc) {
3136 printk(KERN_ERR "HiSax ni1man without proc pr=%04x\n", pr);
3137 return;
3138 }
3139 for (i = 0; i < MANSLLEN; i++)
3140 if ((pr == manstatelist[i].primitive) &&
3141 ((1 << proc->state) & manstatelist[i].state))
3142 break;
3143 if (i == MANSLLEN) {
3144 if (st->l3.debug & L3_DEB_STATE) {
3145 l3_debug(st, "cr %d ni1man state %d prim %#x unhandled",
3146 proc->callref & 0x7f, proc->state, pr);
3147 }
3148 } else {
3149 if (st->l3.debug & L3_DEB_STATE) {
3150 l3_debug(st, "cr %d ni1man state %d prim %#x",
3151 proc->callref & 0x7f, proc->state, pr);
3152 }
3153 manstatelist[i].rout(proc, pr, arg);
3154 }
3155}
3156
3157void
3158setstack_ni1(struct PStack *st)
3159{
3160 char tmp[64];
3161 int i;
3162
3163 st->lli.l4l3 = ni1down;
3164 st->lli.l4l3_proto = l3ni1_cmd_global;
3165 st->l2.l2l3 = ni1up;
3166 st->l3.l3ml3 = ni1man;
3167 st->l3.N303 = 1;
3168 st->prot.ni1.last_invoke_id = 0;
3169 st->prot.ni1.invoke_used[0] = 1; /* Bit 0 must always be set to 1 */
3170 i = 1;
3171 while (i < 32)
3172 st->prot.ni1.invoke_used[i++] = 0;
3173
3174 if (!(st->l3.global = kmalloc(sizeof(struct l3_process), GFP_ATOMIC))) {
3175 printk(KERN_ERR "HiSax can't get memory for ni1 global CR\n");
3176 } else {
3177 st->l3.global->state = 0;
3178 st->l3.global->callref = 0;
3179 st->l3.global->next = NULL;
3180 st->l3.global->debug = L3_DEB_WARN;
3181 st->l3.global->st = st;
3182 st->l3.global->N303 = 1;
3183 st->l3.global->prot.ni1.invoke_id = 0;
3184
3185 L3InitTimer(st->l3.global, &st->l3.global->timer);
3186 }
3187 strcpy(tmp, ni1_revision);
3188 printk(KERN_INFO "HiSax: National ISDN-1 Rev. %s\n", HiSax_getrev(tmp));
3189}
diff --git a/drivers/isdn/hisax/l3ni1.h b/drivers/isdn/hisax/l3ni1.h
new file mode 100644
index 000000000000..4066da2fe5a2
--- /dev/null
+++ b/drivers/isdn/hisax/l3ni1.h
@@ -0,0 +1,136 @@
1/* $Id: l3ni1.h,v 2.3.6.2 2001/09/23 22:24:50 kai Exp $
2 *
3 * NI1 D-channel protocol
4 *
5 * Author Matt Henderson & Guy Ellis
6 * Copyright by Traverse Technologies Pty Ltd, www.travers.com.au
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 * 2000.6.6 Initial implementation of routines for US NI1
12 * Layer 3 protocol based on the EURO/DSS1 D-channel protocol
13 * driver written by Karsten Keil et al. Thanks also for the
14 * code provided by Ragnar Paulson.
15 *
16 */
17
18#ifndef l3ni1_process
19
20#define T302 15000
21#define T303 4000
22#define T304 30000
23#define T305 30000
24#define T308 4000
25/* for layer 1 certification T309 < layer1 T3 (e.g. 4000) */
26/* This makes some tests easier and quicker */
27#define T309 40000
28#define T310 30000
29#define T313 4000
30#define T318 4000
31#define T319 4000
32#define TSPID 5000 /* was 2000 - Guy Ellis */
33
34/*
35 * Message-Types
36 */
37
38#define MT_ALERTING 0x01
39#define MT_CALL_PROCEEDING 0x02
40#define MT_CONNECT 0x07
41#define MT_CONNECT_ACKNOWLEDGE 0x0f
42#define MT_PROGRESS 0x03
43#define MT_SETUP 0x05
44#define MT_SETUP_ACKNOWLEDGE 0x0d
45#define MT_RESUME 0x26
46#define MT_RESUME_ACKNOWLEDGE 0x2e
47#define MT_RESUME_REJECT 0x22
48#define MT_SUSPEND 0x25
49#define MT_SUSPEND_ACKNOWLEDGE 0x2d
50#define MT_SUSPEND_REJECT 0x21
51#define MT_USER_INFORMATION 0x20
52#define MT_DISCONNECT 0x45
53#define MT_RELEASE 0x4d
54#define MT_RELEASE_COMPLETE 0x5a
55#define MT_RESTART 0x46
56#define MT_RESTART_ACKNOWLEDGE 0x4e
57#define MT_SEGMENT 0x60
58#define MT_CONGESTION_CONTROL 0x79
59#define MT_INFORMATION 0x7b
60#define MT_FACILITY 0x62
61#define MT_NOTIFY 0x6e
62#define MT_STATUS 0x7d
63#define MT_STATUS_ENQUIRY 0x75
64#define MT_DL_ESTABLISHED 0xfe
65
66#define IE_SEGMENT 0x00
67#define IE_BEARER 0x04
68#define IE_CAUSE 0x08
69#define IE_CALL_ID 0x10
70#define IE_CALL_STATE 0x14
71#define IE_CHANNEL_ID 0x18
72#define IE_FACILITY 0x1c
73#define IE_PROGRESS 0x1e
74#define IE_NET_FAC 0x20
75#define IE_NOTIFY 0x27
76#define IE_DISPLAY 0x28
77#define IE_DATE 0x29
78#define IE_KEYPAD 0x2c
79#define IE_SIGNAL 0x34
80#define IE_SPID 0x3a
81#define IE_ENDPOINT_ID 0x3b
82#define IE_INFORATE 0x40
83#define IE_E2E_TDELAY 0x42
84#define IE_TDELAY_SEL 0x43
85#define IE_PACK_BINPARA 0x44
86#define IE_PACK_WINSIZE 0x45
87#define IE_PACK_SIZE 0x46
88#define IE_CUG 0x47
89#define IE_REV_CHARGE 0x4a
90#define IE_CONNECT_PN 0x4c
91#define IE_CONNECT_SUB 0x4d
92#define IE_CALLING_PN 0x6c
93#define IE_CALLING_SUB 0x6d
94#define IE_CALLED_PN 0x70
95#define IE_CALLED_SUB 0x71
96#define IE_REDIR_NR 0x74
97#define IE_TRANS_SEL 0x78
98#define IE_RESTART_IND 0x79
99#define IE_LLC 0x7c
100#define IE_HLC 0x7d
101#define IE_USER_USER 0x7e
102#define IE_ESCAPE 0x7f
103#define IE_SHIFT 0x90
104#define IE_MORE_DATA 0xa0
105#define IE_COMPLETE 0xa1
106#define IE_CONGESTION 0xb0
107#define IE_REPEAT 0xd0
108
109#define IE_MANDATORY 0x0100
110/* mandatory not in every case */
111#define IE_MANDATORY_1 0x0200
112
113#define ERR_IE_COMPREHENSION 1
114#define ERR_IE_UNRECOGNIZED -1
115#define ERR_IE_LENGTH -2
116#define ERR_IE_SEQUENCE -3
117
118#else /* only l3ni1_process */
119
120/* l3ni1 specific data in l3 process */
121typedef struct
122 { unsigned char invoke_id; /* used invoke id in remote ops, 0 = not active */
123 ulong ll_id; /* remebered ll id */
124 u8 remote_operation; /* handled remote operation, 0 = not active */
125 int proc; /* rememered procedure */
126 ulong remote_result; /* result of remote operation for statcallb */
127 char uus1_data[35]; /* data send during alerting or disconnect */
128 } ni1_proc_priv;
129
130/* l3dni1 specific data in protocol stack */
131typedef struct
132 { unsigned char last_invoke_id; /* last used value for invoking */
133 unsigned char invoke_used[32]; /* 256 bits for 256 values */
134 } ni1_stk_priv;
135
136#endif /* only l3dni1_process */
diff --git a/drivers/isdn/hisax/lmgr.c b/drivers/isdn/hisax/lmgr.c
new file mode 100644
index 000000000000..d4f86d654de0
--- /dev/null
+++ b/drivers/isdn/hisax/lmgr.c
@@ -0,0 +1,50 @@
1/* $Id: lmgr.c,v 1.7.6.2 2001/09/23 22:24:50 kai Exp $
2 *
3 * Layermanagement module
4 *
5 * Author Karsten Keil
6 * Copyright by Karsten Keil <keil@isdn4linux.de>
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 */
12
13#include "hisax.h"
14
15static void
16error_handling_dchan(struct PStack *st, int Error)
17{
18 switch (Error) {
19 case 'C':
20 case 'D':
21 case 'G':
22 case 'H':
23 st->l2.l2tei(st, MDL_ERROR | REQUEST, NULL);
24 break;
25 }
26}
27
28static void
29hisax_manager(struct PStack *st, int pr, void *arg)
30{
31 long Code;
32
33 switch (pr) {
34 case (MDL_ERROR | INDICATION):
35 Code = (long) arg;
36 HiSax_putstatus(st->l1.hardware, "manager: MDL_ERROR",
37 " %c %s", (char)Code,
38 test_bit(FLG_LAPD, &st->l2.flag) ?
39 "D-channel" : "B-channel");
40 if (test_bit(FLG_LAPD, &st->l2.flag))
41 error_handling_dchan(st, Code);
42 break;
43 }
44}
45
46void
47setstack_manager(struct PStack *st)
48{
49 st->ma.layer = hisax_manager;
50}
diff --git a/drivers/isdn/hisax/mic.c b/drivers/isdn/hisax/mic.c
new file mode 100644
index 000000000000..3ac4484a4886
--- /dev/null
+++ b/drivers/isdn/hisax/mic.c
@@ -0,0 +1,239 @@
1/* $Id: mic.c,v 1.12.2.4 2004/01/13 23:48:39 keil Exp $
2 *
3 * low level stuff for mic cards
4 *
5 * Author Stephan von Krawczynski
6 * Copyright by Stephan von Krawczynski <skraw@ithnet.com>
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 */
12
13#include <linux/init.h>
14#include "hisax.h"
15#include "isac.h"
16#include "hscx.h"
17#include "isdnl1.h"
18
19extern const char *CardType[];
20
21const char *mic_revision = "$Revision: 1.12.2.4 $";
22
23#define byteout(addr,val) outb(val,addr)
24#define bytein(addr) inb(addr)
25
26#define MIC_ISAC 2
27#define MIC_HSCX 1
28#define MIC_ADR 7
29
30/* CARD_ADR (Write) */
31#define MIC_RESET 0x3 /* same as DOS driver */
32
33static inline u_char
34readreg(unsigned int ale, unsigned int adr, u_char off)
35{
36 register u_char ret;
37
38 byteout(ale, off);
39 ret = bytein(adr);
40 return (ret);
41}
42
43static inline void
44readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
45{
46 byteout(ale, off);
47 insb(adr, data, size);
48}
49
50
51static inline void
52writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
53{
54 byteout(ale, off);
55 byteout(adr, data);
56}
57
58static inline void
59writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
60{
61 byteout(ale, off);
62 outsb(adr, data, size);
63}
64
65/* Interface functions */
66
67static u_char
68ReadISAC(struct IsdnCardState *cs, u_char offset)
69{
70 return (readreg(cs->hw.mic.adr, cs->hw.mic.isac, offset));
71}
72
73static void
74WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
75{
76 writereg(cs->hw.mic.adr, cs->hw.mic.isac, offset, value);
77}
78
79static void
80ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
81{
82 readfifo(cs->hw.mic.adr, cs->hw.mic.isac, 0, data, size);
83}
84
85static void
86WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
87{
88 writefifo(cs->hw.mic.adr, cs->hw.mic.isac, 0, data, size);
89}
90
91static u_char
92ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
93{
94 return (readreg(cs->hw.mic.adr,
95 cs->hw.mic.hscx, offset + (hscx ? 0x40 : 0)));
96}
97
98static void
99WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
100{
101 writereg(cs->hw.mic.adr,
102 cs->hw.mic.hscx, offset + (hscx ? 0x40 : 0), value);
103}
104
105/*
106 * fast interrupt HSCX stuff goes here
107 */
108
109#define READHSCX(cs, nr, reg) readreg(cs->hw.mic.adr, \
110 cs->hw.mic.hscx, reg + (nr ? 0x40 : 0))
111#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.mic.adr, \
112 cs->hw.mic.hscx, reg + (nr ? 0x40 : 0), data)
113
114#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.mic.adr, \
115 cs->hw.mic.hscx, (nr ? 0x40 : 0), ptr, cnt)
116
117#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.mic.adr, \
118 cs->hw.mic.hscx, (nr ? 0x40 : 0), ptr, cnt)
119
120#include "hscx_irq.c"
121
122static irqreturn_t
123mic_interrupt(int intno, void *dev_id, struct pt_regs *regs)
124{
125 struct IsdnCardState *cs = dev_id;
126 u_char val;
127 u_long flags;
128
129 spin_lock_irqsave(&cs->lock, flags);
130 val = readreg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_ISTA + 0x40);
131 Start_HSCX:
132 if (val)
133 hscx_int_main(cs, val);
134 val = readreg(cs->hw.mic.adr, cs->hw.mic.isac, ISAC_ISTA);
135 Start_ISAC:
136 if (val)
137 isac_interrupt(cs, val);
138 val = readreg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_ISTA + 0x40);
139 if (val) {
140 if (cs->debug & L1_DEB_HSCX)
141 debugl1(cs, "HSCX IntStat after IntRoutine");
142 goto Start_HSCX;
143 }
144 val = readreg(cs->hw.mic.adr, cs->hw.mic.isac, ISAC_ISTA);
145 if (val) {
146 if (cs->debug & L1_DEB_ISAC)
147 debugl1(cs, "ISAC IntStat after IntRoutine");
148 goto Start_ISAC;
149 }
150 writereg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_MASK, 0xFF);
151 writereg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_MASK + 0x40, 0xFF);
152 writereg(cs->hw.mic.adr, cs->hw.mic.isac, ISAC_MASK, 0xFF);
153 writereg(cs->hw.mic.adr, cs->hw.mic.isac, ISAC_MASK, 0x0);
154 writereg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_MASK, 0x0);
155 writereg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_MASK + 0x40, 0x0);
156 spin_unlock_irqrestore(&cs->lock, flags);
157 return IRQ_HANDLED;
158}
159
160void
161release_io_mic(struct IsdnCardState *cs)
162{
163 int bytecnt = 8;
164
165 if (cs->hw.mic.cfg_reg)
166 release_region(cs->hw.mic.cfg_reg, bytecnt);
167}
168
169static int
170mic_card_msg(struct IsdnCardState *cs, int mt, void *arg)
171{
172 u_long flags;
173
174 switch (mt) {
175 case CARD_RESET:
176 return(0);
177 case CARD_RELEASE:
178 release_io_mic(cs);
179 return(0);
180 case CARD_INIT:
181 spin_lock_irqsave(&cs->lock, flags);
182 inithscx(cs); /* /RTSA := ISAC RST */
183 inithscxisac(cs, 3);
184 spin_unlock_irqrestore(&cs->lock, flags);
185 return(0);
186 case CARD_TEST:
187 return(0);
188 }
189 return(0);
190}
191
192int __init
193setup_mic(struct IsdnCard *card)
194{
195 int bytecnt;
196 struct IsdnCardState *cs = card->cs;
197 char tmp[64];
198
199 strcpy(tmp, mic_revision);
200 printk(KERN_INFO "HiSax: mic driver Rev. %s\n", HiSax_getrev(tmp));
201 if (cs->typ != ISDN_CTYPE_MIC)
202 return (0);
203
204 bytecnt = 8;
205 cs->hw.mic.cfg_reg = card->para[1];
206 cs->irq = card->para[0];
207 cs->hw.mic.adr = cs->hw.mic.cfg_reg + MIC_ADR;
208 cs->hw.mic.isac = cs->hw.mic.cfg_reg + MIC_ISAC;
209 cs->hw.mic.hscx = cs->hw.mic.cfg_reg + MIC_HSCX;
210
211 if (!request_region(cs->hw.mic.cfg_reg, bytecnt, "mic isdn")) {
212 printk(KERN_WARNING
213 "HiSax: %s config port %x-%x already in use\n",
214 CardType[card->typ],
215 cs->hw.mic.cfg_reg,
216 cs->hw.mic.cfg_reg + bytecnt);
217 return (0);
218 }
219 printk(KERN_INFO "mic: defined at 0x%x IRQ %d\n",
220 cs->hw.mic.cfg_reg, cs->irq);
221 setup_isac(cs);
222 cs->readisac = &ReadISAC;
223 cs->writeisac = &WriteISAC;
224 cs->readisacfifo = &ReadISACfifo;
225 cs->writeisacfifo = &WriteISACfifo;
226 cs->BC_Read_Reg = &ReadHSCX;
227 cs->BC_Write_Reg = &WriteHSCX;
228 cs->BC_Send_Data = &hscx_fill_fifo;
229 cs->cardmsg = &mic_card_msg;
230 cs->irq_func = &mic_interrupt;
231 ISACVersion(cs, "mic:");
232 if (HscxVersion(cs, "mic:")) {
233 printk(KERN_WARNING
234 "mic: wrong HSCX versions check IO address\n");
235 release_io_mic(cs);
236 return (0);
237 }
238 return (1);
239}
diff --git a/drivers/isdn/hisax/netjet.c b/drivers/isdn/hisax/netjet.c
new file mode 100644
index 000000000000..fe61d26365d3
--- /dev/null
+++ b/drivers/isdn/hisax/netjet.c
@@ -0,0 +1,996 @@
1/* $Id: netjet.c,v 1.29.2.4 2004/02/11 13:21:34 keil Exp $
2 *
3 * low level stuff for Traverse Technologie NETJet ISDN cards
4 *
5 * Author Karsten Keil
6 * Copyright by Karsten Keil <keil@isdn4linux.de>
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 * Thanks to Traverse Technologies Australia for documents and information
12 *
13 * 16-Apr-2002 - led code added - Guy Ellis (guy@traverse.com.au)
14 *
15 */
16
17#include <linux/init.h>
18#include "hisax.h"
19#include "isac.h"
20#include "hscx.h"
21#include "isdnl1.h"
22#include <linux/pci.h>
23#include <linux/interrupt.h>
24#include <linux/ppp_defs.h>
25#include <asm/io.h>
26#include "netjet.h"
27
28const char *NETjet_revision = "$Revision: 1.29.2.4 $";
29
30/* Interface functions */
31
32u_char
33NETjet_ReadIC(struct IsdnCardState *cs, u_char offset)
34{
35 u_char ret;
36
37 cs->hw.njet.auxd &= 0xfc;
38 cs->hw.njet.auxd |= (offset>>4) & 3;
39 byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
40 ret = bytein(cs->hw.njet.isac + ((offset & 0xf)<<2));
41 return(ret);
42}
43
44void
45NETjet_WriteIC(struct IsdnCardState *cs, u_char offset, u_char value)
46{
47 cs->hw.njet.auxd &= 0xfc;
48 cs->hw.njet.auxd |= (offset>>4) & 3;
49 byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
50 byteout(cs->hw.njet.isac + ((offset & 0xf)<<2), value);
51}
52
53void
54NETjet_ReadICfifo(struct IsdnCardState *cs, u_char *data, int size)
55{
56 cs->hw.njet.auxd &= 0xfc;
57 byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
58 insb(cs->hw.njet.isac, data, size);
59}
60
61void
62NETjet_WriteICfifo(struct IsdnCardState *cs, u_char *data, int size)
63{
64 cs->hw.njet.auxd &= 0xfc;
65 byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
66 outsb(cs->hw.njet.isac, data, size);
67}
68
69void fill_mem(struct BCState *bcs, u_int *pos, u_int cnt, int chan, u_char fill)
70{
71 u_int mask=0x000000ff, val = 0, *p=pos;
72 u_int i;
73
74 val |= fill;
75 if (chan) {
76 val <<= 8;
77 mask <<= 8;
78 }
79 mask ^= 0xffffffff;
80 for (i=0; i<cnt; i++) {
81 *p &= mask;
82 *p++ |= val;
83 if (p > bcs->hw.tiger.s_end)
84 p = bcs->hw.tiger.send;
85 }
86}
87
88void
89mode_tiger(struct BCState *bcs, int mode, int bc)
90{
91 struct IsdnCardState *cs = bcs->cs;
92 u_char led;
93
94 if (cs->debug & L1_DEB_HSCX)
95 debugl1(cs, "Tiger mode %d bchan %d/%d",
96 mode, bc, bcs->channel);
97 bcs->mode = mode;
98 bcs->channel = bc;
99 switch (mode) {
100 case (L1_MODE_NULL):
101 fill_mem(bcs, bcs->hw.tiger.send,
102 NETJET_DMA_TXSIZE, bc, 0xff);
103 if (cs->debug & L1_DEB_HSCX)
104 debugl1(cs, "Tiger stat rec %d/%d send %d",
105 bcs->hw.tiger.r_tot, bcs->hw.tiger.r_err,
106 bcs->hw.tiger.s_tot);
107 if ((cs->bcs[0].mode == L1_MODE_NULL) &&
108 (cs->bcs[1].mode == L1_MODE_NULL)) {
109 cs->hw.njet.dmactrl = 0;
110 byteout(cs->hw.njet.base + NETJET_DMACTRL,
111 cs->hw.njet.dmactrl);
112 byteout(cs->hw.njet.base + NETJET_IRQMASK0, 0);
113 }
114 if (cs->typ == ISDN_CTYPE_NETJET_S)
115 {
116 // led off
117 led = bc & 0x01;
118 led = 0x01 << (6 + led); // convert to mask
119 led = ~led;
120 cs->hw.njet.auxd &= led;
121 byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
122 }
123 break;
124 case (L1_MODE_TRANS):
125 break;
126 case (L1_MODE_HDLC_56K):
127 case (L1_MODE_HDLC):
128 fill_mem(bcs, bcs->hw.tiger.send,
129 NETJET_DMA_TXSIZE, bc, 0xff);
130 bcs->hw.tiger.r_state = HDLC_ZERO_SEARCH;
131 bcs->hw.tiger.r_tot = 0;
132 bcs->hw.tiger.r_bitcnt = 0;
133 bcs->hw.tiger.r_one = 0;
134 bcs->hw.tiger.r_err = 0;
135 bcs->hw.tiger.s_tot = 0;
136 if (! cs->hw.njet.dmactrl) {
137 fill_mem(bcs, bcs->hw.tiger.send,
138 NETJET_DMA_TXSIZE, !bc, 0xff);
139 cs->hw.njet.dmactrl = 1;
140 byteout(cs->hw.njet.base + NETJET_DMACTRL,
141 cs->hw.njet.dmactrl);
142 byteout(cs->hw.njet.base + NETJET_IRQMASK0, 0x0f);
143 /* was 0x3f now 0x0f for TJ300 and TJ320 GE 13/07/00 */
144 }
145 bcs->hw.tiger.sendp = bcs->hw.tiger.send;
146 bcs->hw.tiger.free = NETJET_DMA_TXSIZE;
147 test_and_set_bit(BC_FLG_EMPTY, &bcs->Flag);
148 if (cs->typ == ISDN_CTYPE_NETJET_S)
149 {
150 // led on
151 led = bc & 0x01;
152 led = 0x01 << (6 + led); // convert to mask
153 cs->hw.njet.auxd |= led;
154 byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
155 }
156 break;
157 }
158 if (cs->debug & L1_DEB_HSCX)
159 debugl1(cs, "tiger: set %x %x %x %x/%x pulse=%d",
160 bytein(cs->hw.njet.base + NETJET_DMACTRL),
161 bytein(cs->hw.njet.base + NETJET_IRQMASK0),
162 bytein(cs->hw.njet.base + NETJET_IRQSTAT0),
163 inl(cs->hw.njet.base + NETJET_DMA_READ_ADR),
164 inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR),
165 bytein(cs->hw.njet.base + NETJET_PULSE_CNT));
166}
167
168static void printframe(struct IsdnCardState *cs, u_char *buf, int count, char *s) {
169 char tmp[128];
170 char *t = tmp;
171 int i=count,j;
172 u_char *p = buf;
173
174 t += sprintf(t, "tiger %s(%4d)", s, count);
175 while (i>0) {
176 if (i>16)
177 j=16;
178 else
179 j=i;
180 QuickHex(t, p, j);
181 debugl1(cs, tmp);
182 p += j;
183 i -= j;
184 t = tmp;
185 t += sprintf(t, "tiger %s ", s);
186 }
187}
188
189// macro for 64k
190
191#define MAKE_RAW_BYTE for (j=0; j<8; j++) { \
192 bitcnt++;\
193 s_val >>= 1;\
194 if (val & 1) {\
195 s_one++;\
196 s_val |= 0x80;\
197 } else {\
198 s_one = 0;\
199 s_val &= 0x7f;\
200 }\
201 if (bitcnt==8) {\
202 bcs->hw.tiger.sendbuf[s_cnt++] = s_val;\
203 bitcnt = 0;\
204 }\
205 if (s_one == 5) {\
206 s_val >>= 1;\
207 s_val &= 0x7f;\
208 bitcnt++;\
209 s_one = 0;\
210 }\
211 if (bitcnt==8) {\
212 bcs->hw.tiger.sendbuf[s_cnt++] = s_val;\
213 bitcnt = 0;\
214 }\
215 val >>= 1;\
216 }
217
218static int make_raw_data(struct BCState *bcs) {
219// this make_raw is for 64k
220 register u_int i,s_cnt=0;
221 register u_char j;
222 register u_char val;
223 register u_char s_one = 0;
224 register u_char s_val = 0;
225 register u_char bitcnt = 0;
226 u_int fcs;
227
228 if (!bcs->tx_skb) {
229 debugl1(bcs->cs, "tiger make_raw: NULL skb");
230 return(1);
231 }
232 bcs->hw.tiger.sendbuf[s_cnt++] = HDLC_FLAG_VALUE;
233 fcs = PPP_INITFCS;
234 for (i=0; i<bcs->tx_skb->len; i++) {
235 val = bcs->tx_skb->data[i];
236 fcs = PPP_FCS (fcs, val);
237 MAKE_RAW_BYTE;
238 }
239 fcs ^= 0xffff;
240 val = fcs & 0xff;
241 MAKE_RAW_BYTE;
242 val = (fcs>>8) & 0xff;
243 MAKE_RAW_BYTE;
244 val = HDLC_FLAG_VALUE;
245 for (j=0; j<8; j++) {
246 bitcnt++;
247 s_val >>= 1;
248 if (val & 1)
249 s_val |= 0x80;
250 else
251 s_val &= 0x7f;
252 if (bitcnt==8) {
253 bcs->hw.tiger.sendbuf[s_cnt++] = s_val;
254 bitcnt = 0;
255 }
256 val >>= 1;
257 }
258 if (bcs->cs->debug & L1_DEB_HSCX)
259 debugl1(bcs->cs,"tiger make_raw: in %ld out %d.%d",
260 bcs->tx_skb->len, s_cnt, bitcnt);
261 if (bitcnt) {
262 while (8>bitcnt++) {
263 s_val >>= 1;
264 s_val |= 0x80;
265 }
266 bcs->hw.tiger.sendbuf[s_cnt++] = s_val;
267 bcs->hw.tiger.sendbuf[s_cnt++] = 0xff; // NJ<->NJ thoughput bug fix
268 }
269 bcs->hw.tiger.sendcnt = s_cnt;
270 bcs->tx_cnt -= bcs->tx_skb->len;
271 bcs->hw.tiger.sp = bcs->hw.tiger.sendbuf;
272 return(0);
273}
274
275// macro for 56k
276
277#define MAKE_RAW_BYTE_56K for (j=0; j<8; j++) { \
278 bitcnt++;\
279 s_val >>= 1;\
280 if (val & 1) {\
281 s_one++;\
282 s_val |= 0x80;\
283 } else {\
284 s_one = 0;\
285 s_val &= 0x7f;\
286 }\
287 if (bitcnt==7) {\
288 s_val >>= 1;\
289 s_val |= 0x80;\
290 bcs->hw.tiger.sendbuf[s_cnt++] = s_val;\
291 bitcnt = 0;\
292 }\
293 if (s_one == 5) {\
294 s_val >>= 1;\
295 s_val &= 0x7f;\
296 bitcnt++;\
297 s_one = 0;\
298 }\
299 if (bitcnt==7) {\
300 s_val >>= 1;\
301 s_val |= 0x80;\
302 bcs->hw.tiger.sendbuf[s_cnt++] = s_val;\
303 bitcnt = 0;\
304 }\
305 val >>= 1;\
306 }
307
308static int make_raw_data_56k(struct BCState *bcs) {
309// this make_raw is for 56k
310 register u_int i,s_cnt=0;
311 register u_char j;
312 register u_char val;
313 register u_char s_one = 0;
314 register u_char s_val = 0;
315 register u_char bitcnt = 0;
316 u_int fcs;
317
318 if (!bcs->tx_skb) {
319 debugl1(bcs->cs, "tiger make_raw_56k: NULL skb");
320 return(1);
321 }
322 val = HDLC_FLAG_VALUE;
323 for (j=0; j<8; j++) {
324 bitcnt++;
325 s_val >>= 1;
326 if (val & 1)
327 s_val |= 0x80;
328 else
329 s_val &= 0x7f;
330 if (bitcnt==7) {
331 s_val >>= 1;
332 s_val |= 0x80;
333 bcs->hw.tiger.sendbuf[s_cnt++] = s_val;
334 bitcnt = 0;
335 }
336 val >>= 1;
337 };
338 fcs = PPP_INITFCS;
339 for (i=0; i<bcs->tx_skb->len; i++) {
340 val = bcs->tx_skb->data[i];
341 fcs = PPP_FCS (fcs, val);
342 MAKE_RAW_BYTE_56K;
343 }
344 fcs ^= 0xffff;
345 val = fcs & 0xff;
346 MAKE_RAW_BYTE_56K;
347 val = (fcs>>8) & 0xff;
348 MAKE_RAW_BYTE_56K;
349 val = HDLC_FLAG_VALUE;
350 for (j=0; j<8; j++) {
351 bitcnt++;
352 s_val >>= 1;
353 if (val & 1)
354 s_val |= 0x80;
355 else
356 s_val &= 0x7f;
357 if (bitcnt==7) {
358 s_val >>= 1;
359 s_val |= 0x80;
360 bcs->hw.tiger.sendbuf[s_cnt++] = s_val;
361 bitcnt = 0;
362 }
363 val >>= 1;
364 }
365 if (bcs->cs->debug & L1_DEB_HSCX)
366 debugl1(bcs->cs,"tiger make_raw_56k: in %ld out %d.%d",
367 bcs->tx_skb->len, s_cnt, bitcnt);
368 if (bitcnt) {
369 while (8>bitcnt++) {
370 s_val >>= 1;
371 s_val |= 0x80;
372 }
373 bcs->hw.tiger.sendbuf[s_cnt++] = s_val;
374 bcs->hw.tiger.sendbuf[s_cnt++] = 0xff; // NJ<->NJ thoughput bug fix
375 }
376 bcs->hw.tiger.sendcnt = s_cnt;
377 bcs->tx_cnt -= bcs->tx_skb->len;
378 bcs->hw.tiger.sp = bcs->hw.tiger.sendbuf;
379 return(0);
380}
381
382static void got_frame(struct BCState *bcs, int count) {
383 struct sk_buff *skb;
384
385 if (!(skb = dev_alloc_skb(count)))
386 printk(KERN_WARNING "TIGER: receive out of memory\n");
387 else {
388 memcpy(skb_put(skb, count), bcs->hw.tiger.rcvbuf, count);
389 skb_queue_tail(&bcs->rqueue, skb);
390 }
391 test_and_set_bit(B_RCVBUFREADY, &bcs->event);
392 schedule_work(&bcs->tqueue);
393
394 if (bcs->cs->debug & L1_DEB_RECEIVE_FRAME)
395 printframe(bcs->cs, bcs->hw.tiger.rcvbuf, count, "rec");
396}
397
398
399
400static void read_raw(struct BCState *bcs, u_int *buf, int cnt){
401 int i;
402 register u_char j;
403 register u_char val;
404 u_int *pend = bcs->hw.tiger.rec +NETJET_DMA_RXSIZE -1;
405 register u_char state = bcs->hw.tiger.r_state;
406 register u_char r_one = bcs->hw.tiger.r_one;
407 register u_char r_val = bcs->hw.tiger.r_val;
408 register u_int bitcnt = bcs->hw.tiger.r_bitcnt;
409 u_int *p = buf;
410 int bits;
411 u_char mask;
412
413 if (bcs->mode == L1_MODE_HDLC) { // it's 64k
414 mask = 0xff;
415 bits = 8;
416 }
417 else { // it's 56K
418 mask = 0x7f;
419 bits = 7;
420 };
421 for (i=0;i<cnt;i++) {
422 val = bcs->channel ? ((*p>>8) & 0xff) : (*p & 0xff);
423 p++;
424 if (p > pend)
425 p = bcs->hw.tiger.rec;
426 if ((val & mask) == mask) {
427 state = HDLC_ZERO_SEARCH;
428 bcs->hw.tiger.r_tot++;
429 bitcnt = 0;
430 r_one = 0;
431 continue;
432 }
433 for (j=0;j<bits;j++) {
434 if (state == HDLC_ZERO_SEARCH) {
435 if (val & 1) {
436 r_one++;
437 } else {
438 r_one=0;
439 state= HDLC_FLAG_SEARCH;
440 if (bcs->cs->debug & L1_DEB_HSCX)
441 debugl1(bcs->cs,"tiger read_raw: zBit(%d,%d,%d) %x",
442 bcs->hw.tiger.r_tot,i,j,val);
443 }
444 } else if (state == HDLC_FLAG_SEARCH) {
445 if (val & 1) {
446 r_one++;
447 if (r_one>6) {
448 state=HDLC_ZERO_SEARCH;
449 }
450 } else {
451 if (r_one==6) {
452 bitcnt=0;
453 r_val=0;
454 state=HDLC_FLAG_FOUND;
455 if (bcs->cs->debug & L1_DEB_HSCX)
456 debugl1(bcs->cs,"tiger read_raw: flag(%d,%d,%d) %x",
457 bcs->hw.tiger.r_tot,i,j,val);
458 }
459 r_one=0;
460 }
461 } else if (state == HDLC_FLAG_FOUND) {
462 if (val & 1) {
463 r_one++;
464 if (r_one>6) {
465 state=HDLC_ZERO_SEARCH;
466 } else {
467 r_val >>= 1;
468 r_val |= 0x80;
469 bitcnt++;
470 }
471 } else {
472 if (r_one==6) {
473 bitcnt=0;
474 r_val=0;
475 r_one=0;
476 val >>= 1;
477 continue;
478 } else if (r_one!=5) {
479 r_val >>= 1;
480 r_val &= 0x7f;
481 bitcnt++;
482 }
483 r_one=0;
484 }
485 if ((state != HDLC_ZERO_SEARCH) &&
486 !(bitcnt & 7)) {
487 state=HDLC_FRAME_FOUND;
488 bcs->hw.tiger.r_fcs = PPP_INITFCS;
489 bcs->hw.tiger.rcvbuf[0] = r_val;
490 bcs->hw.tiger.r_fcs = PPP_FCS (bcs->hw.tiger.r_fcs, r_val);
491 if (bcs->cs->debug & L1_DEB_HSCX)
492 debugl1(bcs->cs,"tiger read_raw: byte1(%d,%d,%d) rval %x val %x i %x",
493 bcs->hw.tiger.r_tot,i,j,r_val,val,
494 bcs->cs->hw.njet.irqstat0);
495 }
496 } else if (state == HDLC_FRAME_FOUND) {
497 if (val & 1) {
498 r_one++;
499 if (r_one>6) {
500 state=HDLC_ZERO_SEARCH;
501 bitcnt=0;
502 } else {
503 r_val >>= 1;
504 r_val |= 0x80;
505 bitcnt++;
506 }
507 } else {
508 if (r_one==6) {
509 r_val=0;
510 r_one=0;
511 bitcnt++;
512 if (bitcnt & 7) {
513 debugl1(bcs->cs, "tiger: frame not byte aligned");
514 state=HDLC_FLAG_SEARCH;
515 bcs->hw.tiger.r_err++;
516#ifdef ERROR_STATISTIC
517 bcs->err_inv++;
518#endif
519 } else {
520 if (bcs->cs->debug & L1_DEB_HSCX)
521 debugl1(bcs->cs,"tiger frame end(%d,%d): fcs(%x) i %x",
522 i,j,bcs->hw.tiger.r_fcs, bcs->cs->hw.njet.irqstat0);
523 if (bcs->hw.tiger.r_fcs == PPP_GOODFCS) {
524 got_frame(bcs, (bitcnt>>3)-3);
525 } else {
526 if (bcs->cs->debug) {
527 debugl1(bcs->cs, "tiger FCS error");
528 printframe(bcs->cs, bcs->hw.tiger.rcvbuf,
529 (bitcnt>>3)-1, "rec");
530 bcs->hw.tiger.r_err++;
531 }
532#ifdef ERROR_STATISTIC
533 bcs->err_crc++;
534#endif
535 }
536 state=HDLC_FLAG_FOUND;
537 }
538 bitcnt=0;
539 } else if (r_one==5) {
540 val >>= 1;
541 r_one=0;
542 continue;
543 } else {
544 r_val >>= 1;
545 r_val &= 0x7f;
546 bitcnt++;
547 }
548 r_one=0;
549 }
550 if ((state == HDLC_FRAME_FOUND) &&
551 !(bitcnt & 7)) {
552 if ((bitcnt>>3)>=HSCX_BUFMAX) {
553 debugl1(bcs->cs, "tiger: frame too big");
554 r_val=0;
555 state=HDLC_FLAG_SEARCH;
556 bcs->hw.tiger.r_err++;
557#ifdef ERROR_STATISTIC
558 bcs->err_inv++;
559#endif
560 } else {
561 bcs->hw.tiger.rcvbuf[(bitcnt>>3)-1] = r_val;
562 bcs->hw.tiger.r_fcs =
563 PPP_FCS (bcs->hw.tiger.r_fcs, r_val);
564 }
565 }
566 }
567 val >>= 1;
568 }
569 bcs->hw.tiger.r_tot++;
570 }
571 bcs->hw.tiger.r_state = state;
572 bcs->hw.tiger.r_one = r_one;
573 bcs->hw.tiger.r_val = r_val;
574 bcs->hw.tiger.r_bitcnt = bitcnt;
575}
576
577void read_tiger(struct IsdnCardState *cs) {
578 u_int *p;
579 int cnt = NETJET_DMA_RXSIZE/2;
580
581 if ((cs->hw.njet.irqstat0 & cs->hw.njet.last_is0) & NETJET_IRQM0_READ) {
582 debugl1(cs,"tiger warn read double dma %x/%x",
583 cs->hw.njet.irqstat0, cs->hw.njet.last_is0);
584#ifdef ERROR_STATISTIC
585 if (cs->bcs[0].mode)
586 cs->bcs[0].err_rdo++;
587 if (cs->bcs[1].mode)
588 cs->bcs[1].err_rdo++;
589#endif
590 return;
591 } else {
592 cs->hw.njet.last_is0 &= ~NETJET_IRQM0_READ;
593 cs->hw.njet.last_is0 |= (cs->hw.njet.irqstat0 & NETJET_IRQM0_READ);
594 }
595 if (cs->hw.njet.irqstat0 & NETJET_IRQM0_READ_1)
596 p = cs->bcs[0].hw.tiger.rec + NETJET_DMA_RXSIZE - 1;
597 else
598 p = cs->bcs[0].hw.tiger.rec + cnt - 1;
599 if ((cs->bcs[0].mode == L1_MODE_HDLC) || (cs->bcs[0].mode == L1_MODE_HDLC_56K))
600 read_raw(cs->bcs, p, cnt);
601
602 if ((cs->bcs[1].mode == L1_MODE_HDLC) || (cs->bcs[1].mode == L1_MODE_HDLC_56K))
603 read_raw(cs->bcs + 1, p, cnt);
604 cs->hw.njet.irqstat0 &= ~NETJET_IRQM0_READ;
605}
606
607static void write_raw(struct BCState *bcs, u_int *buf, int cnt);
608
609void netjet_fill_dma(struct BCState *bcs)
610{
611 register u_int *p, *sp;
612 register int cnt;
613
614 if (!bcs->tx_skb)
615 return;
616 if (bcs->cs->debug & L1_DEB_HSCX)
617 debugl1(bcs->cs,"tiger fill_dma1: c%d %4x", bcs->channel,
618 bcs->Flag);
619 if (test_and_set_bit(BC_FLG_BUSY, &bcs->Flag))
620 return;
621 if (bcs->mode == L1_MODE_HDLC) { // it's 64k
622 if (make_raw_data(bcs))
623 return;
624 }
625 else { // it's 56k
626 if (make_raw_data_56k(bcs))
627 return;
628 };
629 if (bcs->cs->debug & L1_DEB_HSCX)
630 debugl1(bcs->cs,"tiger fill_dma2: c%d %4x", bcs->channel,
631 bcs->Flag);
632 if (test_and_clear_bit(BC_FLG_NOFRAME, &bcs->Flag)) {
633 write_raw(bcs, bcs->hw.tiger.sendp, bcs->hw.tiger.free);
634 } else if (test_and_clear_bit(BC_FLG_HALF, &bcs->Flag)) {
635 p = bus_to_virt(inl(bcs->cs->hw.njet.base + NETJET_DMA_READ_ADR));
636 sp = bcs->hw.tiger.sendp;
637 if (p == bcs->hw.tiger.s_end)
638 p = bcs->hw.tiger.send -1;
639 if (sp == bcs->hw.tiger.s_end)
640 sp = bcs->hw.tiger.send -1;
641 cnt = p - sp;
642 if (cnt <0) {
643 write_raw(bcs, bcs->hw.tiger.sendp, bcs->hw.tiger.free);
644 } else {
645 p++;
646 cnt++;
647 if (p > bcs->hw.tiger.s_end)
648 p = bcs->hw.tiger.send;
649 p++;
650 cnt++;
651 if (p > bcs->hw.tiger.s_end)
652 p = bcs->hw.tiger.send;
653 write_raw(bcs, p, bcs->hw.tiger.free - cnt);
654 }
655 } else if (test_and_clear_bit(BC_FLG_EMPTY, &bcs->Flag)) {
656 p = bus_to_virt(inl(bcs->cs->hw.njet.base + NETJET_DMA_READ_ADR));
657 cnt = bcs->hw.tiger.s_end - p;
658 if (cnt < 2) {
659 p = bcs->hw.tiger.send + 1;
660 cnt = NETJET_DMA_TXSIZE/2 - 2;
661 } else {
662 p++;
663 p++;
664 if (cnt <= (NETJET_DMA_TXSIZE/2))
665 cnt += NETJET_DMA_TXSIZE/2;
666 cnt--;
667 cnt--;
668 }
669 write_raw(bcs, p, cnt);
670 }
671 if (bcs->cs->debug & L1_DEB_HSCX)
672 debugl1(bcs->cs,"tiger fill_dma3: c%d %4x", bcs->channel,
673 bcs->Flag);
674}
675
676static void write_raw(struct BCState *bcs, u_int *buf, int cnt) {
677 u_int mask, val, *p=buf;
678 u_int i, s_cnt;
679
680 if (cnt <= 0)
681 return;
682 if (test_bit(BC_FLG_BUSY, &bcs->Flag)) {
683 if (bcs->hw.tiger.sendcnt> cnt) {
684 s_cnt = cnt;
685 bcs->hw.tiger.sendcnt -= cnt;
686 } else {
687 s_cnt = bcs->hw.tiger.sendcnt;
688 bcs->hw.tiger.sendcnt = 0;
689 }
690 if (bcs->channel)
691 mask = 0xffff00ff;
692 else
693 mask = 0xffffff00;
694 for (i=0; i<s_cnt; i++) {
695 val = bcs->channel ? ((bcs->hw.tiger.sp[i] <<8) & 0xff00) :
696 (bcs->hw.tiger.sp[i]);
697 *p &= mask;
698 *p++ |= val;
699 if (p>bcs->hw.tiger.s_end)
700 p = bcs->hw.tiger.send;
701 }
702 bcs->hw.tiger.s_tot += s_cnt;
703 if (bcs->cs->debug & L1_DEB_HSCX)
704 debugl1(bcs->cs,"tiger write_raw: c%d %p-%p %d/%d %d %x", bcs->channel,
705 buf, p, s_cnt, cnt,
706 bcs->hw.tiger.sendcnt, bcs->cs->hw.njet.irqstat0);
707 if (bcs->cs->debug & L1_DEB_HSCX_FIFO)
708 printframe(bcs->cs, bcs->hw.tiger.sp, s_cnt, "snd");
709 bcs->hw.tiger.sp += s_cnt;
710 bcs->hw.tiger.sendp = p;
711 if (!bcs->hw.tiger.sendcnt) {
712 if (!bcs->tx_skb) {
713 debugl1(bcs->cs,"tiger write_raw: NULL skb s_cnt %d", s_cnt);
714 } else {
715 if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) &&
716 (PACKET_NOACK != bcs->tx_skb->pkt_type)) {
717 u_long flags;
718 spin_lock_irqsave(&bcs->aclock, flags);
719 bcs->ackcnt += bcs->tx_skb->len;
720 spin_unlock_irqrestore(&bcs->aclock, flags);
721 schedule_event(bcs, B_ACKPENDING);
722 }
723 dev_kfree_skb_any(bcs->tx_skb);
724 bcs->tx_skb = NULL;
725 }
726 test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
727 bcs->hw.tiger.free = cnt - s_cnt;
728 if (bcs->hw.tiger.free > (NETJET_DMA_TXSIZE/2))
729 test_and_set_bit(BC_FLG_HALF, &bcs->Flag);
730 else {
731 test_and_clear_bit(BC_FLG_HALF, &bcs->Flag);
732 test_and_set_bit(BC_FLG_NOFRAME, &bcs->Flag);
733 }
734 if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
735 netjet_fill_dma(bcs);
736 } else {
737 mask ^= 0xffffffff;
738 if (s_cnt < cnt) {
739 for (i=s_cnt; i<cnt;i++) {
740 *p++ |= mask;
741 if (p>bcs->hw.tiger.s_end)
742 p = bcs->hw.tiger.send;
743 }
744 if (bcs->cs->debug & L1_DEB_HSCX)
745 debugl1(bcs->cs, "tiger write_raw: fill rest %d",
746 cnt - s_cnt);
747 }
748 test_and_set_bit(B_XMTBUFREADY, &bcs->event);
749 schedule_work(&bcs->tqueue);
750 }
751 }
752 } else if (test_and_clear_bit(BC_FLG_NOFRAME, &bcs->Flag)) {
753 test_and_set_bit(BC_FLG_HALF, &bcs->Flag);
754 fill_mem(bcs, buf, cnt, bcs->channel, 0xff);
755 bcs->hw.tiger.free += cnt;
756 if (bcs->cs->debug & L1_DEB_HSCX)
757 debugl1(bcs->cs,"tiger write_raw: fill half");
758 } else if (test_and_clear_bit(BC_FLG_HALF, &bcs->Flag)) {
759 test_and_set_bit(BC_FLG_EMPTY, &bcs->Flag);
760 fill_mem(bcs, buf, cnt, bcs->channel, 0xff);
761 if (bcs->cs->debug & L1_DEB_HSCX)
762 debugl1(bcs->cs,"tiger write_raw: fill full");
763 }
764}
765
766void write_tiger(struct IsdnCardState *cs) {
767 u_int *p, cnt = NETJET_DMA_TXSIZE/2;
768
769 if ((cs->hw.njet.irqstat0 & cs->hw.njet.last_is0) & NETJET_IRQM0_WRITE) {
770 debugl1(cs,"tiger warn write double dma %x/%x",
771 cs->hw.njet.irqstat0, cs->hw.njet.last_is0);
772#ifdef ERROR_STATISTIC
773 if (cs->bcs[0].mode)
774 cs->bcs[0].err_tx++;
775 if (cs->bcs[1].mode)
776 cs->bcs[1].err_tx++;
777#endif
778 return;
779 } else {
780 cs->hw.njet.last_is0 &= ~NETJET_IRQM0_WRITE;
781 cs->hw.njet.last_is0 |= (cs->hw.njet.irqstat0 & NETJET_IRQM0_WRITE);
782 }
783 if (cs->hw.njet.irqstat0 & NETJET_IRQM0_WRITE_1)
784 p = cs->bcs[0].hw.tiger.send + NETJET_DMA_TXSIZE - 1;
785 else
786 p = cs->bcs[0].hw.tiger.send + cnt - 1;
787 if ((cs->bcs[0].mode == L1_MODE_HDLC) || (cs->bcs[0].mode == L1_MODE_HDLC_56K))
788 write_raw(cs->bcs, p, cnt);
789 if ((cs->bcs[1].mode == L1_MODE_HDLC) || (cs->bcs[1].mode == L1_MODE_HDLC_56K))
790 write_raw(cs->bcs + 1, p, cnt);
791 cs->hw.njet.irqstat0 &= ~NETJET_IRQM0_WRITE;
792}
793
794static void
795tiger_l2l1(struct PStack *st, int pr, void *arg)
796{
797 struct BCState *bcs = st->l1.bcs;
798 struct sk_buff *skb = arg;
799 u_long flags;
800
801 switch (pr) {
802 case (PH_DATA | REQUEST):
803 spin_lock_irqsave(&bcs->cs->lock, flags);
804 if (bcs->tx_skb) {
805 skb_queue_tail(&bcs->squeue, skb);
806 } else {
807 bcs->tx_skb = skb;
808 bcs->cs->BC_Send_Data(bcs);
809 }
810 spin_unlock_irqrestore(&bcs->cs->lock, flags);
811 break;
812 case (PH_PULL | INDICATION):
813 spin_lock_irqsave(&bcs->cs->lock, flags);
814 if (bcs->tx_skb) {
815 printk(KERN_WARNING "tiger_l2l1: this shouldn't happen\n");
816 } else {
817 bcs->tx_skb = skb;
818 bcs->cs->BC_Send_Data(bcs);
819 }
820 spin_unlock_irqrestore(&bcs->cs->lock, flags);
821 break;
822 case (PH_PULL | REQUEST):
823 if (!bcs->tx_skb) {
824 test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
825 st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
826 } else
827 test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
828 break;
829 case (PH_ACTIVATE | REQUEST):
830 spin_lock_irqsave(&bcs->cs->lock, flags);
831 test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag);
832 mode_tiger(bcs, st->l1.mode, st->l1.bc);
833 /* 2001/10/04 Christoph Ersfeld, Formula-n Europe AG */
834 spin_unlock_irqrestore(&bcs->cs->lock, flags);
835 bcs->cs->cardmsg(bcs->cs, MDL_BC_ASSIGN, (void *)(&st->l1.bc));
836 l1_msg_b(st, pr, arg);
837 break;
838 case (PH_DEACTIVATE | REQUEST):
839 /* 2001/10/04 Christoph Ersfeld, Formula-n Europe AG */
840 bcs->cs->cardmsg(bcs->cs, MDL_BC_RELEASE, (void *)(&st->l1.bc));
841 l1_msg_b(st, pr, arg);
842 break;
843 case (PH_DEACTIVATE | CONFIRM):
844 spin_lock_irqsave(&bcs->cs->lock, flags);
845 test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag);
846 test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
847 mode_tiger(bcs, 0, st->l1.bc);
848 spin_unlock_irqrestore(&bcs->cs->lock, flags);
849 st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
850 break;
851 }
852}
853
854
855void
856close_tigerstate(struct BCState *bcs)
857{
858 mode_tiger(bcs, 0, bcs->channel);
859 if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) {
860 if (bcs->hw.tiger.rcvbuf) {
861 kfree(bcs->hw.tiger.rcvbuf);
862 bcs->hw.tiger.rcvbuf = NULL;
863 }
864 if (bcs->hw.tiger.sendbuf) {
865 kfree(bcs->hw.tiger.sendbuf);
866 bcs->hw.tiger.sendbuf = NULL;
867 }
868 skb_queue_purge(&bcs->rqueue);
869 skb_queue_purge(&bcs->squeue);
870 if (bcs->tx_skb) {
871 dev_kfree_skb_any(bcs->tx_skb);
872 bcs->tx_skb = NULL;
873 test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
874 }
875 }
876}
877
878static int
879open_tigerstate(struct IsdnCardState *cs, struct BCState *bcs)
880{
881 if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
882 if (!(bcs->hw.tiger.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) {
883 printk(KERN_WARNING
884 "HiSax: No memory for tiger.rcvbuf\n");
885 return (1);
886 }
887 if (!(bcs->hw.tiger.sendbuf = kmalloc(RAW_BUFMAX, GFP_ATOMIC))) {
888 printk(KERN_WARNING
889 "HiSax: No memory for tiger.sendbuf\n");
890 return (1);
891 }
892 skb_queue_head_init(&bcs->rqueue);
893 skb_queue_head_init(&bcs->squeue);
894 }
895 bcs->tx_skb = NULL;
896 bcs->hw.tiger.sendcnt = 0;
897 test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
898 bcs->event = 0;
899 bcs->tx_cnt = 0;
900 return (0);
901}
902
903int
904setstack_tiger(struct PStack *st, struct BCState *bcs)
905{
906 bcs->channel = st->l1.bc;
907 if (open_tigerstate(st->l1.hardware, bcs))
908 return (-1);
909 st->l1.bcs = bcs;
910 st->l2.l2l1 = tiger_l2l1;
911 setstack_manager(st);
912 bcs->st = st;
913 setstack_l1_B(st);
914 return (0);
915}
916
917
918void __init
919inittiger(struct IsdnCardState *cs)
920{
921 if (!(cs->bcs[0].hw.tiger.send = kmalloc(NETJET_DMA_TXSIZE * sizeof(unsigned int),
922 GFP_KERNEL | GFP_DMA))) {
923 printk(KERN_WARNING
924 "HiSax: No memory for tiger.send\n");
925 return;
926 }
927 cs->bcs[0].hw.tiger.s_irq = cs->bcs[0].hw.tiger.send + NETJET_DMA_TXSIZE/2 - 1;
928 cs->bcs[0].hw.tiger.s_end = cs->bcs[0].hw.tiger.send + NETJET_DMA_TXSIZE - 1;
929 cs->bcs[1].hw.tiger.send = cs->bcs[0].hw.tiger.send;
930 cs->bcs[1].hw.tiger.s_irq = cs->bcs[0].hw.tiger.s_irq;
931 cs->bcs[1].hw.tiger.s_end = cs->bcs[0].hw.tiger.s_end;
932
933 memset(cs->bcs[0].hw.tiger.send, 0xff, NETJET_DMA_TXSIZE * sizeof(unsigned int));
934 debugl1(cs, "tiger: send buf %p - %p", cs->bcs[0].hw.tiger.send,
935 cs->bcs[0].hw.tiger.send + NETJET_DMA_TXSIZE - 1);
936 outl(virt_to_bus(cs->bcs[0].hw.tiger.send),
937 cs->hw.njet.base + NETJET_DMA_READ_START);
938 outl(virt_to_bus(cs->bcs[0].hw.tiger.s_irq),
939 cs->hw.njet.base + NETJET_DMA_READ_IRQ);
940 outl(virt_to_bus(cs->bcs[0].hw.tiger.s_end),
941 cs->hw.njet.base + NETJET_DMA_READ_END);
942 if (!(cs->bcs[0].hw.tiger.rec = kmalloc(NETJET_DMA_RXSIZE * sizeof(unsigned int),
943 GFP_KERNEL | GFP_DMA))) {
944 printk(KERN_WARNING
945 "HiSax: No memory for tiger.rec\n");
946 return;
947 }
948 debugl1(cs, "tiger: rec buf %p - %p", cs->bcs[0].hw.tiger.rec,
949 cs->bcs[0].hw.tiger.rec + NETJET_DMA_RXSIZE - 1);
950 cs->bcs[1].hw.tiger.rec = cs->bcs[0].hw.tiger.rec;
951 memset(cs->bcs[0].hw.tiger.rec, 0xff, NETJET_DMA_RXSIZE * sizeof(unsigned int));
952 outl(virt_to_bus(cs->bcs[0].hw.tiger.rec),
953 cs->hw.njet.base + NETJET_DMA_WRITE_START);
954 outl(virt_to_bus(cs->bcs[0].hw.tiger.rec + NETJET_DMA_RXSIZE/2 - 1),
955 cs->hw.njet.base + NETJET_DMA_WRITE_IRQ);
956 outl(virt_to_bus(cs->bcs[0].hw.tiger.rec + NETJET_DMA_RXSIZE - 1),
957 cs->hw.njet.base + NETJET_DMA_WRITE_END);
958 debugl1(cs, "tiger: dmacfg %x/%x pulse=%d",
959 inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR),
960 inl(cs->hw.njet.base + NETJET_DMA_READ_ADR),
961 bytein(cs->hw.njet.base + NETJET_PULSE_CNT));
962 cs->hw.njet.last_is0 = 0;
963 cs->bcs[0].BC_SetStack = setstack_tiger;
964 cs->bcs[1].BC_SetStack = setstack_tiger;
965 cs->bcs[0].BC_Close = close_tigerstate;
966 cs->bcs[1].BC_Close = close_tigerstate;
967}
968
969void
970releasetiger(struct IsdnCardState *cs)
971{
972 if (cs->bcs[0].hw.tiger.send) {
973 kfree(cs->bcs[0].hw.tiger.send);
974 cs->bcs[0].hw.tiger.send = NULL;
975 }
976 if (cs->bcs[1].hw.tiger.send) {
977 cs->bcs[1].hw.tiger.send = NULL;
978 }
979 if (cs->bcs[0].hw.tiger.rec) {
980 kfree(cs->bcs[0].hw.tiger.rec);
981 cs->bcs[0].hw.tiger.rec = NULL;
982 }
983 if (cs->bcs[1].hw.tiger.rec) {
984 cs->bcs[1].hw.tiger.rec = NULL;
985 }
986}
987
988void
989release_io_netjet(struct IsdnCardState *cs)
990{
991 byteout(cs->hw.njet.base + NETJET_IRQMASK0, 0);
992 byteout(cs->hw.njet.base + NETJET_IRQMASK1, 0);
993 releasetiger(cs);
994 release_region(cs->hw.njet.base, 256);
995}
996
diff --git a/drivers/isdn/hisax/netjet.h b/drivers/isdn/hisax/netjet.h
new file mode 100644
index 000000000000..1080508f3c6a
--- /dev/null
+++ b/drivers/isdn/hisax/netjet.h
@@ -0,0 +1,72 @@
1/* $Id: netjet.h,v 2.8.2.2 2004/01/12 22:52:28 keil Exp $
2 *
3 * NETjet common header file
4 *
5 * Author Karsten Keil
6 * Copyright by Karsten Keil <keil@isdn4linux.de>
7 * by Matt Henderson,
8 * Traverse Technologies P/L www.traverse.com.au
9 *
10 * This software may be used and distributed according to the terms
11 * of the GNU General Public License, incorporated herein by reference.
12 *
13 */
14
15extern const char *CardType[];
16
17#define byteout(addr,val) outb(val,addr)
18#define bytein(addr) inb(addr)
19
20#define NETJET_CTRL 0x00
21#define NETJET_DMACTRL 0x01
22#define NETJET_AUXCTRL 0x02
23#define NETJET_AUXDATA 0x03
24#define NETJET_IRQMASK0 0x04
25#define NETJET_IRQMASK1 0x05
26#define NETJET_IRQSTAT0 0x06
27#define NETJET_IRQSTAT1 0x07
28#define NETJET_DMA_READ_START 0x08
29#define NETJET_DMA_READ_IRQ 0x0c
30#define NETJET_DMA_READ_END 0x10
31#define NETJET_DMA_READ_ADR 0x14
32#define NETJET_DMA_WRITE_START 0x18
33#define NETJET_DMA_WRITE_IRQ 0x1c
34#define NETJET_DMA_WRITE_END 0x20
35#define NETJET_DMA_WRITE_ADR 0x24
36#define NETJET_PULSE_CNT 0x28
37
38#define NETJET_ISAC_OFF 0xc0
39#define NETJET_ISACIRQ 0x10
40#define NETJET_IRQM0_READ 0x0c
41#define NETJET_IRQM0_READ_1 0x04
42#define NETJET_IRQM0_READ_2 0x08
43#define NETJET_IRQM0_WRITE 0x03
44#define NETJET_IRQM0_WRITE_1 0x01
45#define NETJET_IRQM0_WRITE_2 0x02
46
47#define NETJET_DMA_TXSIZE 512
48#define NETJET_DMA_RXSIZE 128
49
50#define HDLC_ZERO_SEARCH 0
51#define HDLC_FLAG_SEARCH 1
52#define HDLC_FLAG_FOUND 2
53#define HDLC_FRAME_FOUND 3
54#define HDLC_NULL 4
55#define HDLC_PART 5
56#define HDLC_FULL 6
57
58#define HDLC_FLAG_VALUE 0x7e
59
60u_char NETjet_ReadIC(struct IsdnCardState *cs, u_char offset);
61void NETjet_WriteIC(struct IsdnCardState *cs, u_char offset, u_char value);
62void NETjet_ReadICfifo(struct IsdnCardState *cs, u_char *data, int size);
63void NETjet_WriteICfifo(struct IsdnCardState *cs, u_char *data, int size);
64
65void read_tiger(struct IsdnCardState *cs);
66void write_tiger(struct IsdnCardState *cs);
67
68void netjet_fill_dma(struct BCState *bcs);
69void netjet_interrupt(int intno, void *dev_id, struct pt_regs *regs);
70void inittiger(struct IsdnCardState *cs);
71void release_io_netjet(struct IsdnCardState *cs);
72
diff --git a/drivers/isdn/hisax/niccy.c b/drivers/isdn/hisax/niccy.c
new file mode 100644
index 000000000000..cf77d8360975
--- /dev/null
+++ b/drivers/isdn/hisax/niccy.c
@@ -0,0 +1,389 @@
1/* $Id: niccy.c,v 1.21.2.4 2004/01/13 23:48:39 keil Exp $
2 *
3 * low level stuff for Dr. Neuhaus NICCY PnP and NICCY PCI and
4 * compatible (SAGEM cybermodem)
5 *
6 * Author Karsten Keil
7 * Copyright by Karsten Keil <keil@isdn4linux.de>
8 *
9 * This software may be used and distributed according to the terms
10 * of the GNU General Public License, incorporated herein by reference.
11 *
12 * Thanks to Dr. Neuhaus and SAGEM for information
13 *
14 */
15
16
17#include <linux/config.h>
18#include <linux/init.h>
19#include "hisax.h"
20#include "isac.h"
21#include "hscx.h"
22#include "isdnl1.h"
23#include <linux/pci.h>
24#include <linux/isapnp.h>
25
26extern const char *CardType[];
27const char *niccy_revision = "$Revision: 1.21.2.4 $";
28
29#define byteout(addr,val) outb(val,addr)
30#define bytein(addr) inb(addr)
31
32#define ISAC_PCI_DATA 0
33#define HSCX_PCI_DATA 1
34#define ISAC_PCI_ADDR 2
35#define HSCX_PCI_ADDR 3
36#define ISAC_PNP 0
37#define HSCX_PNP 1
38
39/* SUB Types */
40#define NICCY_PNP 1
41#define NICCY_PCI 2
42
43/* PCI stuff */
44#define PCI_IRQ_CTRL_REG 0x38
45#define PCI_IRQ_ENABLE 0x1f00
46#define PCI_IRQ_DISABLE 0xff0000
47#define PCI_IRQ_ASSERT 0x800000
48
49static inline u_char
50readreg(unsigned int ale, unsigned int adr, u_char off)
51{
52 register u_char ret;
53
54 byteout(ale, off);
55 ret = bytein(adr);
56 return (ret);
57}
58
59static inline void
60readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
61{
62 byteout(ale, off);
63 insb(adr, data, size);
64}
65
66
67static inline void
68writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
69{
70 byteout(ale, off);
71 byteout(adr, data);
72}
73
74static inline void
75writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
76{
77 byteout(ale, off);
78 outsb(adr, data, size);
79}
80
81/* Interface functions */
82
83static u_char
84ReadISAC(struct IsdnCardState *cs, u_char offset)
85{
86 return (readreg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, offset));
87}
88
89static void
90WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
91{
92 writereg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, offset, value);
93}
94
95static void
96ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
97{
98 readfifo(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, 0, data, size);
99}
100
101static void
102WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
103{
104 writefifo(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, 0, data, size);
105}
106
107static u_char
108ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
109{
110 return (readreg(cs->hw.niccy.hscx_ale,
111 cs->hw.niccy.hscx, offset + (hscx ? 0x40 : 0)));
112}
113
114static void
115WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
116{
117 writereg(cs->hw.niccy.hscx_ale,
118 cs->hw.niccy.hscx, offset + (hscx ? 0x40 : 0), value);
119}
120
121#define READHSCX(cs, nr, reg) readreg(cs->hw.niccy.hscx_ale, \
122 cs->hw.niccy.hscx, reg + (nr ? 0x40 : 0))
123#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.niccy.hscx_ale, \
124 cs->hw.niccy.hscx, reg + (nr ? 0x40 : 0), data)
125
126#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.niccy.hscx_ale, \
127 cs->hw.niccy.hscx, (nr ? 0x40 : 0), ptr, cnt)
128
129#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.niccy.hscx_ale, \
130 cs->hw.niccy.hscx, (nr ? 0x40 : 0), ptr, cnt)
131
132#include "hscx_irq.c"
133
134static irqreturn_t
135niccy_interrupt(int intno, void *dev_id, struct pt_regs *regs)
136{
137 struct IsdnCardState *cs = dev_id;
138 u_char val;
139 u_long flags;
140
141 spin_lock_irqsave(&cs->lock, flags);
142 if (cs->subtyp == NICCY_PCI) {
143 int ival;
144 ival = inl(cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
145 if (!(ival & PCI_IRQ_ASSERT)) { /* IRQ not for us (shared) */
146 spin_unlock_irqrestore(&cs->lock, flags);
147 return IRQ_NONE;
148 }
149 outl(ival, cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
150 }
151 val = readreg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_ISTA + 0x40);
152 Start_HSCX:
153 if (val)
154 hscx_int_main(cs, val);
155 val = readreg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_ISTA);
156 Start_ISAC:
157 if (val)
158 isac_interrupt(cs, val);
159 val = readreg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_ISTA + 0x40);
160 if (val) {
161 if (cs->debug & L1_DEB_HSCX)
162 debugl1(cs, "HSCX IntStat after IntRoutine");
163 goto Start_HSCX;
164 }
165 val = readreg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_ISTA);
166 if (val) {
167 if (cs->debug & L1_DEB_ISAC)
168 debugl1(cs, "ISAC IntStat after IntRoutine");
169 goto Start_ISAC;
170 }
171 writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK, 0xFF);
172 writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK + 0x40, 0xFF);
173 writereg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_MASK, 0xFF);
174 writereg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_MASK, 0);
175 writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK, 0);
176 writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK + 0x40, 0);
177 spin_unlock_irqrestore(&cs->lock, flags);
178 return IRQ_HANDLED;
179}
180
181void
182release_io_niccy(struct IsdnCardState *cs)
183{
184 if (cs->subtyp == NICCY_PCI) {
185 int val;
186
187 val = inl(cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
188 val &= PCI_IRQ_DISABLE;
189 outl(val, cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
190 release_region(cs->hw.niccy.cfg_reg, 0x40);
191 release_region(cs->hw.niccy.isac, 4);
192 } else {
193 release_region(cs->hw.niccy.isac, 2);
194 release_region(cs->hw.niccy.isac_ale, 2);
195 }
196}
197
198static void
199niccy_reset(struct IsdnCardState *cs)
200{
201 if (cs->subtyp == NICCY_PCI) {
202 int val;
203
204 val = inl(cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
205 val |= PCI_IRQ_ENABLE;
206 outl(val, cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
207 }
208 inithscxisac(cs, 3);
209}
210
211static int
212niccy_card_msg(struct IsdnCardState *cs, int mt, void *arg)
213{
214 u_long flags;
215
216 switch (mt) {
217 case CARD_RESET:
218 spin_lock_irqsave(&cs->lock, flags);
219 niccy_reset(cs);
220 spin_unlock_irqrestore(&cs->lock, flags);
221 return(0);
222 case CARD_RELEASE:
223 release_io_niccy(cs);
224 return(0);
225 case CARD_INIT:
226 spin_lock_irqsave(&cs->lock, flags);
227 niccy_reset(cs);
228 spin_unlock_irqrestore(&cs->lock, flags);
229 return(0);
230 case CARD_TEST:
231 return(0);
232 }
233 return(0);
234}
235
236static struct pci_dev *niccy_dev __initdata = NULL;
237#ifdef __ISAPNP__
238static struct pnp_card *pnp_c __devinitdata = NULL;
239#endif
240
241int __init
242setup_niccy(struct IsdnCard *card)
243{
244 struct IsdnCardState *cs = card->cs;
245 char tmp[64];
246
247 strcpy(tmp, niccy_revision);
248 printk(KERN_INFO "HiSax: Niccy driver Rev. %s\n", HiSax_getrev(tmp));
249 if (cs->typ != ISDN_CTYPE_NICCY)
250 return (0);
251#ifdef __ISAPNP__
252 if (!card->para[1] && isapnp_present()) {
253 struct pnp_dev *pnp_d = NULL;
254 int err;
255
256 if ((pnp_c = pnp_find_card(
257 ISAPNP_VENDOR('S', 'D', 'A'),
258 ISAPNP_FUNCTION(0x0150), pnp_c))) {
259 if (!(pnp_d = pnp_find_dev(pnp_c,
260 ISAPNP_VENDOR('S', 'D', 'A'),
261 ISAPNP_FUNCTION(0x0150), pnp_d))) {
262 printk(KERN_ERR "NiccyPnP: PnP error card found, no device\n");
263 return (0);
264 }
265 pnp_disable_dev(pnp_d);
266 err = pnp_activate_dev(pnp_d);
267 if (err<0) {
268 printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
269 __FUNCTION__, err);
270 return(0);
271 }
272 card->para[1] = pnp_port_start(pnp_d, 0);
273 card->para[2] = pnp_port_start(pnp_d, 1);
274 card->para[0] = pnp_irq(pnp_d, 0);
275 if (!card->para[0] || !card->para[1] || !card->para[2]) {
276 printk(KERN_ERR "NiccyPnP:some resources are missing %ld/%lx/%lx\n",
277 card->para[0], card->para[1], card->para[2]);
278 pnp_disable_dev(pnp_d);
279 return(0);
280 }
281 } else {
282 printk(KERN_INFO "NiccyPnP: no ISAPnP card found\n");
283 }
284 }
285#endif
286 if (card->para[1]) {
287 cs->hw.niccy.isac = card->para[1] + ISAC_PNP;
288 cs->hw.niccy.hscx = card->para[1] + HSCX_PNP;
289 cs->hw.niccy.isac_ale = card->para[2] + ISAC_PNP;
290 cs->hw.niccy.hscx_ale = card->para[2] + HSCX_PNP;
291 cs->hw.niccy.cfg_reg = 0;
292 cs->subtyp = NICCY_PNP;
293 cs->irq = card->para[0];
294 if (!request_region(cs->hw.niccy.isac, 2, "niccy data")) {
295 printk(KERN_WARNING
296 "HiSax: %s data port %x-%x already in use\n",
297 CardType[card->typ],
298 cs->hw.niccy.isac,
299 cs->hw.niccy.isac + 1);
300 return (0);
301 }
302 if (!request_region(cs->hw.niccy.isac_ale, 2, "niccy addr")) {
303 printk(KERN_WARNING
304 "HiSax: %s address port %x-%x already in use\n",
305 CardType[card->typ],
306 cs->hw.niccy.isac_ale,
307 cs->hw.niccy.isac_ale + 1);
308 release_region(cs->hw.niccy.isac, 2);
309 return (0);
310 }
311 } else {
312#ifdef CONFIG_PCI
313 u_int pci_ioaddr;
314 cs->subtyp = 0;
315 if ((niccy_dev = pci_find_device(PCI_VENDOR_ID_SATSAGEM,
316 PCI_DEVICE_ID_SATSAGEM_NICCY, niccy_dev))) {
317 if (pci_enable_device(niccy_dev))
318 return(0);
319 /* get IRQ */
320 if (!niccy_dev->irq) {
321 printk(KERN_WARNING "Niccy: No IRQ for PCI card found\n");
322 return(0);
323 }
324 cs->irq = niccy_dev->irq;
325 cs->hw.niccy.cfg_reg = pci_resource_start(niccy_dev, 0);
326 if (!cs->hw.niccy.cfg_reg) {
327 printk(KERN_WARNING "Niccy: No IO-Adr for PCI cfg found\n");
328 return(0);
329 }
330 pci_ioaddr = pci_resource_start(niccy_dev, 1);
331 if (!pci_ioaddr) {
332 printk(KERN_WARNING "Niccy: No IO-Adr for PCI card found\n");
333 return(0);
334 }
335 cs->subtyp = NICCY_PCI;
336 } else {
337 printk(KERN_WARNING "Niccy: No PCI card found\n");
338 return(0);
339 }
340 cs->irq_flags |= SA_SHIRQ;
341 cs->hw.niccy.isac = pci_ioaddr + ISAC_PCI_DATA;
342 cs->hw.niccy.isac_ale = pci_ioaddr + ISAC_PCI_ADDR;
343 cs->hw.niccy.hscx = pci_ioaddr + HSCX_PCI_DATA;
344 cs->hw.niccy.hscx_ale = pci_ioaddr + HSCX_PCI_ADDR;
345 if (!request_region(cs->hw.niccy.isac, 4, "niccy")) {
346 printk(KERN_WARNING
347 "HiSax: %s data port %x-%x already in use\n",
348 CardType[card->typ],
349 cs->hw.niccy.isac,
350 cs->hw.niccy.isac + 4);
351 return (0);
352 }
353 if (!request_region(cs->hw.niccy.cfg_reg, 0x40, "niccy pci")) {
354 printk(KERN_WARNING
355 "HiSax: %s pci port %x-%x already in use\n",
356 CardType[card->typ],
357 cs->hw.niccy.cfg_reg,
358 cs->hw.niccy.cfg_reg + 0x40);
359 release_region(cs->hw.niccy.isac, 4);
360 return (0);
361 }
362#else
363 printk(KERN_WARNING "Niccy: io0 0 and NO_PCI_BIOS\n");
364 printk(KERN_WARNING "Niccy: unable to config NICCY PCI\n");
365 return (0);
366#endif /* CONFIG_PCI */
367 }
368 printk(KERN_INFO "HiSax: %s %s config irq:%d data:0x%X ale:0x%X\n",
369 CardType[cs->typ], (cs->subtyp==1) ? "PnP":"PCI",
370 cs->irq, cs->hw.niccy.isac, cs->hw.niccy.isac_ale);
371 setup_isac(cs);
372 cs->readisac = &ReadISAC;
373 cs->writeisac = &WriteISAC;
374 cs->readisacfifo = &ReadISACfifo;
375 cs->writeisacfifo = &WriteISACfifo;
376 cs->BC_Read_Reg = &ReadHSCX;
377 cs->BC_Write_Reg = &WriteHSCX;
378 cs->BC_Send_Data = &hscx_fill_fifo;
379 cs->cardmsg = &niccy_card_msg;
380 cs->irq_func = &niccy_interrupt;
381 ISACVersion(cs, "Niccy:");
382 if (HscxVersion(cs, "Niccy:")) {
383 printk(KERN_WARNING
384 "Niccy: wrong HSCX versions check IO address\n");
385 release_io_niccy(cs);
386 return (0);
387 }
388 return (1);
389}
diff --git a/drivers/isdn/hisax/nj_s.c b/drivers/isdn/hisax/nj_s.c
new file mode 100644
index 000000000000..fd664697f821
--- /dev/null
+++ b/drivers/isdn/hisax/nj_s.c
@@ -0,0 +1,278 @@
1/* $Id: nj_s.c,v 2.13.2.4 2004/01/16 01:53:48 keil Exp $
2 *
3 * This software may be used and distributed according to the terms
4 * of the GNU General Public License, incorporated herein by reference.
5 *
6 */
7
8#include <linux/config.h>
9#include <linux/init.h>
10#include "hisax.h"
11#include "isac.h"
12#include "isdnl1.h"
13#include <linux/pci.h>
14#include <linux/interrupt.h>
15#include <linux/ppp_defs.h>
16#include "netjet.h"
17
18const char *NETjet_S_revision = "$Revision: 2.13.2.4 $";
19
20static u_char dummyrr(struct IsdnCardState *cs, int chan, u_char off)
21{
22 return(5);
23}
24
25static void dummywr(struct IsdnCardState *cs, int chan, u_char off, u_char value)
26{
27}
28
29static irqreturn_t
30netjet_s_interrupt(int intno, void *dev_id, struct pt_regs *regs)
31{
32 struct IsdnCardState *cs = dev_id;
33 u_char val, s1val, s0val;
34 u_long flags;
35
36 spin_lock_irqsave(&cs->lock, flags);
37 s1val = bytein(cs->hw.njet.base + NETJET_IRQSTAT1);
38 if (!(s1val & NETJET_ISACIRQ)) {
39 val = NETjet_ReadIC(cs, ISAC_ISTA);
40 if (cs->debug & L1_DEB_ISAC)
41 debugl1(cs, "tiger: i1 %x %x", s1val, val);
42 if (val) {
43 isac_interrupt(cs, val);
44 NETjet_WriteIC(cs, ISAC_MASK, 0xFF);
45 NETjet_WriteIC(cs, ISAC_MASK, 0x0);
46 }
47 s1val = 1;
48 } else
49 s1val = 0;
50 /*
51 * read/write stat0 is better, because lower IRQ rate
52 * Note the IRQ is on for 125 us if a condition match
53 * thats long on modern CPU and so the IRQ is reentered
54 * all the time.
55 */
56 s0val = bytein(cs->hw.njet.base + NETJET_IRQSTAT0);
57 if ((s0val | s1val)==0) { // shared IRQ
58 spin_unlock_irqrestore(&cs->lock, flags);
59 return IRQ_NONE;
60 }
61 if (s0val)
62 byteout(cs->hw.njet.base + NETJET_IRQSTAT0, s0val);
63 /* start new code 13/07/00 GE */
64 /* set bits in sval to indicate which page is free */
65 if (inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR) <
66 inl(cs->hw.njet.base + NETJET_DMA_WRITE_IRQ))
67 /* the 2nd write page is free */
68 s0val = 0x08;
69 else /* the 1st write page is free */
70 s0val = 0x04;
71 if (inl(cs->hw.njet.base + NETJET_DMA_READ_ADR) <
72 inl(cs->hw.njet.base + NETJET_DMA_READ_IRQ))
73 /* the 2nd read page is free */
74 s0val |= 0x02;
75 else /* the 1st read page is free */
76 s0val |= 0x01;
77 if (s0val != cs->hw.njet.last_is0) /* we have a DMA interrupt */
78 {
79 if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
80 printk(KERN_WARNING "nj LOCK_ATOMIC s0val %x->%x\n",
81 cs->hw.njet.last_is0, s0val);
82 spin_unlock_irqrestore(&cs->lock, flags);
83 return IRQ_HANDLED;
84 }
85 cs->hw.njet.irqstat0 = s0val;
86 if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_READ) !=
87 (cs->hw.njet.last_is0 & NETJET_IRQM0_READ))
88 /* we have a read dma int */
89 read_tiger(cs);
90 if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_WRITE) !=
91 (cs->hw.njet.last_is0 & NETJET_IRQM0_WRITE))
92 /* we have a write dma int */
93 write_tiger(cs);
94 /* end new code 13/07/00 GE */
95 test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
96 }
97 spin_unlock_irqrestore(&cs->lock, flags);
98 return IRQ_HANDLED;
99}
100
101static void
102reset_netjet_s(struct IsdnCardState *cs)
103{
104 cs->hw.njet.ctrl_reg = 0xff; /* Reset On */
105 byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
106 mdelay(10);
107 /* now edge triggered for TJ320 GE 13/07/00 */
108 /* see comment in IRQ function */
109 if (cs->subtyp) /* TJ320 */
110 cs->hw.njet.ctrl_reg = 0x40; /* Reset Off and status read clear */
111 else
112 cs->hw.njet.ctrl_reg = 0x00; /* Reset Off and status read clear */
113 byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
114 mdelay(10);
115 cs->hw.njet.auxd = 0;
116 cs->hw.njet.dmactrl = 0;
117 byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ);
118 byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ);
119 byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
120}
121
122static int
123NETjet_S_card_msg(struct IsdnCardState *cs, int mt, void *arg)
124{
125 u_long flags;
126
127 switch (mt) {
128 case CARD_RESET:
129 spin_lock_irqsave(&cs->lock, flags);
130 reset_netjet_s(cs);
131 spin_unlock_irqrestore(&cs->lock, flags);
132 return(0);
133 case CARD_RELEASE:
134 release_io_netjet(cs);
135 return(0);
136 case CARD_INIT:
137 reset_netjet_s(cs);
138 inittiger(cs);
139 spin_lock_irqsave(&cs->lock, flags);
140 clear_pending_isac_ints(cs);
141 initisac(cs);
142 /* Reenable all IRQ */
143 cs->writeisac(cs, ISAC_MASK, 0);
144 spin_unlock_irqrestore(&cs->lock, flags);
145 return(0);
146 case CARD_TEST:
147 return(0);
148 }
149 return(0);
150}
151
152static struct pci_dev *dev_netjet __initdata = NULL;
153
154int __init
155setup_netjet_s(struct IsdnCard *card)
156{
157 int bytecnt,cfg;
158 struct IsdnCardState *cs = card->cs;
159 char tmp[64];
160
161#ifdef __BIG_ENDIAN
162#error "not running on big endian machines now"
163#endif
164 strcpy(tmp, NETjet_S_revision);
165 printk(KERN_INFO "HiSax: Traverse Tech. NETjet-S driver Rev. %s\n", HiSax_getrev(tmp));
166 if (cs->typ != ISDN_CTYPE_NETJET_S)
167 return(0);
168 test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
169
170#ifdef CONFIG_PCI
171
172 for ( ;; )
173 {
174 if ((dev_netjet = pci_find_device(PCI_VENDOR_ID_TIGERJET,
175 PCI_DEVICE_ID_TIGERJET_300, dev_netjet))) {
176 if (pci_enable_device(dev_netjet))
177 return(0);
178 pci_set_master(dev_netjet);
179 cs->irq = dev_netjet->irq;
180 if (!cs->irq) {
181 printk(KERN_WARNING "NETjet-S: No IRQ for PCI card found\n");
182 return(0);
183 }
184 cs->hw.njet.base = pci_resource_start(dev_netjet, 0);
185 if (!cs->hw.njet.base) {
186 printk(KERN_WARNING "NETjet-S: No IO-Adr for PCI card found\n");
187 return(0);
188 }
189 /* the TJ300 and TJ320 must be detected, the IRQ handling is different
190 * unfortunatly the chips use the same device ID, but the TJ320 has
191 * the bit20 in status PCI cfg register set
192 */
193 pci_read_config_dword(dev_netjet, 0x04, &cfg);
194 if (cfg & 0x00100000)
195 cs->subtyp = 1; /* TJ320 */
196 else
197 cs->subtyp = 0; /* TJ300 */
198 /* 2001/10/04 Christoph Ersfeld, Formula-n Europe AG www.formula-n.com */
199 if ((dev_netjet->subsystem_vendor == 0x55) &&
200 (dev_netjet->subsystem_device == 0x02)) {
201 printk(KERN_WARNING "Netjet: You tried to load this driver with an incompatible TigerJet-card\n");
202 printk(KERN_WARNING "Use type=41 for Formula-n enter:now ISDN PCI and compatible\n");
203 return(0);
204 }
205 /* end new code */
206 } else {
207 printk(KERN_WARNING "NETjet-S: No PCI card found\n");
208 return(0);
209 }
210
211 cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA;
212 cs->hw.njet.isac = cs->hw.njet.base | NETJET_ISAC_OFF;
213
214 cs->hw.njet.ctrl_reg = 0xff; /* Reset On */
215 byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
216 mdelay(10);
217
218 cs->hw.njet.ctrl_reg = 0x00; /* Reset Off and status read clear */
219 byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
220 mdelay(10);
221
222 cs->hw.njet.auxd = 0xC0;
223 cs->hw.njet.dmactrl = 0;
224
225 byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ);
226 byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ);
227 byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
228
229 switch ( ( ( NETjet_ReadIC( cs, ISAC_RBCH ) >> 5 ) & 3 ) )
230 {
231 case 0 :
232 break;
233
234 case 3 :
235 printk( KERN_WARNING "NETjet-S: NETspider-U PCI card found\n" );
236 continue;
237
238 default :
239 printk( KERN_WARNING "NETjet-S: No PCI card found\n" );
240 return 0;
241 }
242 break;
243 }
244#else
245
246 printk(KERN_WARNING "NETjet-S: NO_PCI_BIOS\n");
247 printk(KERN_WARNING "NETjet-S: unable to config NETJET-S PCI\n");
248 return (0);
249
250#endif /* CONFIG_PCI */
251
252 bytecnt = 256;
253
254 printk(KERN_INFO
255 "NETjet-S: %s card configured at %#lx IRQ %d\n",
256 cs->subtyp ? "TJ320" : "TJ300", cs->hw.njet.base, cs->irq);
257 if (!request_region(cs->hw.njet.base, bytecnt, "netjet-s isdn")) {
258 printk(KERN_WARNING
259 "HiSax: %s config port %#lx-%#lx already in use\n",
260 CardType[card->typ],
261 cs->hw.njet.base,
262 cs->hw.njet.base + bytecnt);
263 return (0);
264 }
265 cs->readisac = &NETjet_ReadIC;
266 cs->writeisac = &NETjet_WriteIC;
267 cs->readisacfifo = &NETjet_ReadICfifo;
268 cs->writeisacfifo = &NETjet_WriteICfifo;
269 cs->BC_Read_Reg = &dummyrr;
270 cs->BC_Write_Reg = &dummywr;
271 cs->BC_Send_Data = &netjet_fill_dma;
272 setup_isac(cs);
273 cs->cardmsg = &NETjet_S_card_msg;
274 cs->irq_func = &netjet_s_interrupt;
275 cs->irq_flags |= SA_SHIRQ;
276 ISACVersion(cs, "NETjet-S:");
277 return (1);
278}
diff --git a/drivers/isdn/hisax/nj_u.c b/drivers/isdn/hisax/nj_u.c
new file mode 100644
index 000000000000..3d6441e9633c
--- /dev/null
+++ b/drivers/isdn/hisax/nj_u.c
@@ -0,0 +1,244 @@
1/* $Id: nj_u.c,v 2.14.2.3 2004/01/13 14:31:26 keil Exp $
2 *
3 * This software may be used and distributed according to the terms
4 * of the GNU General Public License, incorporated herein by reference.
5 *
6 */
7
8#include <linux/config.h>
9#include <linux/init.h>
10#include "hisax.h"
11#include "icc.h"
12#include "isdnl1.h"
13#include <linux/pci.h>
14#include <linux/interrupt.h>
15#include <linux/ppp_defs.h>
16#include "netjet.h"
17
18const char *NETjet_U_revision = "$Revision: 2.14.2.3 $";
19
20static u_char dummyrr(struct IsdnCardState *cs, int chan, u_char off)
21{
22 return(5);
23}
24
25static void dummywr(struct IsdnCardState *cs, int chan, u_char off, u_char value)
26{
27}
28
29static irqreturn_t
30netjet_u_interrupt(int intno, void *dev_id, struct pt_regs *regs)
31{
32 struct IsdnCardState *cs = dev_id;
33 u_char val, sval;
34 u_long flags;
35
36 spin_lock_irqsave(&cs->lock, flags);
37 if (!((sval = bytein(cs->hw.njet.base + NETJET_IRQSTAT1)) &
38 NETJET_ISACIRQ)) {
39 val = NETjet_ReadIC(cs, ICC_ISTA);
40 if (cs->debug & L1_DEB_ISAC)
41 debugl1(cs, "tiger: i1 %x %x", sval, val);
42 if (val) {
43 icc_interrupt(cs, val);
44 NETjet_WriteIC(cs, ICC_MASK, 0xFF);
45 NETjet_WriteIC(cs, ICC_MASK, 0x0);
46 }
47 }
48 /* start new code 13/07/00 GE */
49 /* set bits in sval to indicate which page is free */
50 if (inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR) <
51 inl(cs->hw.njet.base + NETJET_DMA_WRITE_IRQ))
52 /* the 2nd write page is free */
53 sval = 0x08;
54 else /* the 1st write page is free */
55 sval = 0x04;
56 if (inl(cs->hw.njet.base + NETJET_DMA_READ_ADR) <
57 inl(cs->hw.njet.base + NETJET_DMA_READ_IRQ))
58 /* the 2nd read page is free */
59 sval = sval | 0x02;
60 else /* the 1st read page is free */
61 sval = sval | 0x01;
62 if (sval != cs->hw.njet.last_is0) /* we have a DMA interrupt */
63 {
64 if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
65 spin_unlock_irqrestore(&cs->lock, flags);
66 return IRQ_HANDLED;
67 }
68 cs->hw.njet.irqstat0 = sval;
69 if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_READ) !=
70 (cs->hw.njet.last_is0 & NETJET_IRQM0_READ))
71 /* we have a read dma int */
72 read_tiger(cs);
73 if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_WRITE) !=
74 (cs->hw.njet.last_is0 & NETJET_IRQM0_WRITE))
75 /* we have a write dma int */
76 write_tiger(cs);
77 /* end new code 13/07/00 GE */
78 test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
79 }
80 spin_unlock_irqrestore(&cs->lock, flags);
81 return IRQ_HANDLED;
82}
83
84static void
85reset_netjet_u(struct IsdnCardState *cs)
86{
87 cs->hw.njet.ctrl_reg = 0xff; /* Reset On */
88 byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
89 mdelay(10);
90 cs->hw.njet.ctrl_reg = 0x40; /* Reset Off and status read clear */
91 /* now edge triggered for TJ320 GE 13/07/00 */
92 byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
93 mdelay(10);
94 cs->hw.njet.auxd = 0xC0;
95 cs->hw.njet.dmactrl = 0;
96 byteout(cs->hw.njet.auxa, 0);
97 byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ);
98 byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ);
99 byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
100}
101
102static int
103NETjet_U_card_msg(struct IsdnCardState *cs, int mt, void *arg)
104{
105 u_long flags;
106
107 switch (mt) {
108 case CARD_RESET:
109 spin_lock_irqsave(&cs->lock, flags);
110 reset_netjet_u(cs);
111 spin_unlock_irqrestore(&cs->lock, flags);
112 return(0);
113 case CARD_RELEASE:
114 release_io_netjet(cs);
115 return(0);
116 case CARD_INIT:
117 spin_lock_irqsave(&cs->lock, flags);
118 inittiger(cs);
119 reset_netjet_u(cs);
120 clear_pending_icc_ints(cs);
121 initicc(cs);
122 /* Reenable all IRQ */
123 cs->writeisac(cs, ICC_MASK, 0);
124 spin_unlock_irqrestore(&cs->lock, flags);
125 return(0);
126 case CARD_TEST:
127 return(0);
128 }
129 return(0);
130}
131
132static struct pci_dev *dev_netjet __initdata = NULL;
133
134int __init
135setup_netjet_u(struct IsdnCard *card)
136{
137 int bytecnt;
138 struct IsdnCardState *cs = card->cs;
139 char tmp[64];
140#ifdef CONFIG_PCI
141#endif
142#ifdef __BIG_ENDIAN
143#error "not running on big endian machines now"
144#endif
145 strcpy(tmp, NETjet_U_revision);
146 printk(KERN_INFO "HiSax: Traverse Tech. NETspider-U driver Rev. %s\n", HiSax_getrev(tmp));
147 if (cs->typ != ISDN_CTYPE_NETJET_U)
148 return(0);
149 test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
150
151#ifdef CONFIG_PCI
152
153 for ( ;; )
154 {
155 if ((dev_netjet = pci_find_device(PCI_VENDOR_ID_TIGERJET,
156 PCI_DEVICE_ID_TIGERJET_300, dev_netjet))) {
157 if (pci_enable_device(dev_netjet))
158 return(0);
159 pci_set_master(dev_netjet);
160 cs->irq = dev_netjet->irq;
161 if (!cs->irq) {
162 printk(KERN_WARNING "NETspider-U: No IRQ for PCI card found\n");
163 return(0);
164 }
165 cs->hw.njet.base = pci_resource_start(dev_netjet, 0);
166 if (!cs->hw.njet.base) {
167 printk(KERN_WARNING "NETspider-U: No IO-Adr for PCI card found\n");
168 return(0);
169 }
170 } else {
171 printk(KERN_WARNING "NETspider-U: No PCI card found\n");
172 return(0);
173 }
174
175 cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA;
176 cs->hw.njet.isac = cs->hw.njet.base | NETJET_ISAC_OFF;
177 mdelay(10);
178
179 cs->hw.njet.ctrl_reg = 0xff; /* Reset On */
180 byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
181 mdelay(10);
182
183 cs->hw.njet.ctrl_reg = 0x00; /* Reset Off and status read clear */
184 byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
185 mdelay(10);
186
187 cs->hw.njet.auxd = 0xC0;
188 cs->hw.njet.dmactrl = 0;
189
190 byteout(cs->hw.njet.auxa, 0);
191 byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ);
192 byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ);
193 byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
194
195 switch ( ( ( NETjet_ReadIC( cs, ICC_RBCH ) >> 5 ) & 3 ) )
196 {
197 case 3 :
198 break;
199
200 case 0 :
201 printk( KERN_WARNING "NETspider-U: NETjet-S PCI card found\n" );
202 continue;
203
204 default :
205 printk( KERN_WARNING "NETspider-U: No PCI card found\n" );
206 return 0;
207 }
208 break;
209 }
210#else
211
212 printk(KERN_WARNING "NETspider-U: NO_PCI_BIOS\n");
213 printk(KERN_WARNING "NETspider-U: unable to config NETspider-U PCI\n");
214 return (0);
215
216#endif /* CONFIG_PCI */
217
218 bytecnt = 256;
219
220 printk(KERN_INFO
221 "NETspider-U: PCI card configured at %#lx IRQ %d\n",
222 cs->hw.njet.base, cs->irq);
223 if (!request_region(cs->hw.njet.base, bytecnt, "netspider-u isdn")) {
224 printk(KERN_WARNING
225 "HiSax: %s config port %#lx-%#lx already in use\n",
226 CardType[card->typ],
227 cs->hw.njet.base,
228 cs->hw.njet.base + bytecnt);
229 return (0);
230 }
231 setup_icc(cs);
232 cs->readisac = &NETjet_ReadIC;
233 cs->writeisac = &NETjet_WriteIC;
234 cs->readisacfifo = &NETjet_ReadICfifo;
235 cs->writeisacfifo = &NETjet_WriteICfifo;
236 cs->BC_Read_Reg = &dummyrr;
237 cs->BC_Write_Reg = &dummywr;
238 cs->BC_Send_Data = &netjet_fill_dma;
239 cs->cardmsg = &NETjet_U_card_msg;
240 cs->irq_func = &netjet_u_interrupt;
241 cs->irq_flags |= SA_SHIRQ;
242 ICCVersion(cs, "NETspider-U:");
243 return (1);
244}
diff --git a/drivers/isdn/hisax/q931.c b/drivers/isdn/hisax/q931.c
new file mode 100644
index 000000000000..170fcd4a3984
--- /dev/null
+++ b/drivers/isdn/hisax/q931.c
@@ -0,0 +1,1522 @@
1/* $Id: q931.c,v 1.12.2.3 2004/01/13 14:31:26 keil Exp $
2 *
3 * code to decode ITU Q.931 call control messages
4 *
5 * Author Jan den Ouden
6 * Copyright by Jan den Ouden
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 * Changelog:
12 *
13 * Pauline Middelink general improvements
14 * Beat Doebeli cause texts, display information element
15 * Karsten Keil cause texts, display information element for 1TR6
16 *
17 */
18
19
20#include "hisax.h"
21#include "l3_1tr6.h"
22
23void
24iecpy(u_char * dest, u_char * iestart, int ieoffset)
25{
26 u_char *p;
27 int l;
28
29 p = iestart + ieoffset + 2;
30 l = iestart[1] - ieoffset;
31 while (l--)
32 *dest++ = *p++;
33 *dest++ = '\0';
34}
35
36/*
37 * According to Table 4-2/Q.931
38 */
39static
40struct MessageType {
41 u_char nr;
42 char *descr;
43} mtlist[] = {
44
45 {
46 0x1, "ALERTING"
47 },
48 {
49 0x2, "CALL PROCEEDING"
50 },
51 {
52 0x7, "CONNECT"
53 },
54 {
55 0xf, "CONNECT ACKNOWLEDGE"
56 },
57 {
58 0x3, "PROGRESS"
59 },
60 {
61 0x5, "SETUP"
62 },
63 {
64 0xd, "SETUP ACKNOWLEDGE"
65 },
66 {
67 0x24, "HOLD"
68 },
69 {
70 0x28, "HOLD ACKNOWLEDGE"
71 },
72 {
73 0x30, "HOLD REJECT"
74 },
75 {
76 0x31, "RETRIEVE"
77 },
78 {
79 0x33, "RETRIEVE ACKNOWLEDGE"
80 },
81 {
82 0x37, "RETRIEVE REJECT"
83 },
84 {
85 0x26, "RESUME"
86 },
87 {
88 0x2e, "RESUME ACKNOWLEDGE"
89 },
90 {
91 0x22, "RESUME REJECT"
92 },
93 {
94 0x25, "SUSPEND"
95 },
96 {
97 0x2d, "SUSPEND ACKNOWLEDGE"
98 },
99 {
100 0x21, "SUSPEND REJECT"
101 },
102 {
103 0x20, "USER INFORMATION"
104 },
105 {
106 0x45, "DISCONNECT"
107 },
108 {
109 0x4d, "RELEASE"
110 },
111 {
112 0x5a, "RELEASE COMPLETE"
113 },
114 {
115 0x46, "RESTART"
116 },
117 {
118 0x4e, "RESTART ACKNOWLEDGE"
119 },
120 {
121 0x60, "SEGMENT"
122 },
123 {
124 0x79, "CONGESTION CONTROL"
125 },
126 {
127 0x7b, "INFORMATION"
128 },
129 {
130 0x62, "FACILITY"
131 },
132 {
133 0x6e, "NOTIFY"
134 },
135 {
136 0x7d, "STATUS"
137 },
138 {
139 0x75, "STATUS ENQUIRY"
140 }
141};
142
143#define MTSIZE sizeof(mtlist)/sizeof(struct MessageType)
144
145static
146struct MessageType mt_n0[] =
147{
148 {MT_N0_REG_IND, "REGister INDication"},
149 {MT_N0_CANC_IND, "CANCel INDication"},
150 {MT_N0_FAC_STA, "FACility STAtus"},
151 {MT_N0_STA_ACK, "STAtus ACKnowledge"},
152 {MT_N0_STA_REJ, "STAtus REJect"},
153 {MT_N0_FAC_INF, "FACility INFormation"},
154 {MT_N0_INF_ACK, "INFormation ACKnowledge"},
155 {MT_N0_INF_REJ, "INFormation REJect"},
156 {MT_N0_CLOSE, "CLOSE"},
157 {MT_N0_CLO_ACK, "CLOse ACKnowledge"}
158};
159
160#define MT_N0_LEN (sizeof(mt_n0) / sizeof(struct MessageType))
161
162static
163struct MessageType mt_n1[] =
164{
165 {MT_N1_ESC, "ESCape"},
166 {MT_N1_ALERT, "ALERT"},
167 {MT_N1_CALL_SENT, "CALL SENT"},
168 {MT_N1_CONN, "CONNect"},
169 {MT_N1_CONN_ACK, "CONNect ACKnowledge"},
170 {MT_N1_SETUP, "SETUP"},
171 {MT_N1_SETUP_ACK, "SETUP ACKnowledge"},
172 {MT_N1_RES, "RESume"},
173 {MT_N1_RES_ACK, "RESume ACKnowledge"},
174 {MT_N1_RES_REJ, "RESume REJect"},
175 {MT_N1_SUSP, "SUSPend"},
176 {MT_N1_SUSP_ACK, "SUSPend ACKnowledge"},
177 {MT_N1_SUSP_REJ, "SUSPend REJect"},
178 {MT_N1_USER_INFO, "USER INFO"},
179 {MT_N1_DET, "DETach"},
180 {MT_N1_DISC, "DISConnect"},
181 {MT_N1_REL, "RELease"},
182 {MT_N1_REL_ACK, "RELease ACKnowledge"},
183 {MT_N1_CANC_ACK, "CANCel ACKnowledge"},
184 {MT_N1_CANC_REJ, "CANCel REJect"},
185 {MT_N1_CON_CON, "CONgestion CONtrol"},
186 {MT_N1_FAC, "FACility"},
187 {MT_N1_FAC_ACK, "FACility ACKnowledge"},
188 {MT_N1_FAC_CAN, "FACility CANcel"},
189 {MT_N1_FAC_REG, "FACility REGister"},
190 {MT_N1_FAC_REJ, "FACility REJect"},
191 {MT_N1_INFO, "INFOrmation"},
192 {MT_N1_REG_ACK, "REGister ACKnowledge"},
193 {MT_N1_REG_REJ, "REGister REJect"},
194 {MT_N1_STAT, "STATus"}
195};
196
197#define MT_N1_LEN (sizeof(mt_n1) / sizeof(struct MessageType))
198
199
200static int
201prbits(char *dest, u_char b, int start, int len)
202{
203 char *dp = dest;
204
205 b = b << (8 - start);
206 while (len--) {
207 if (b & 0x80)
208 *dp++ = '1';
209 else
210 *dp++ = '0';
211 b = b << 1;
212 }
213 return (dp - dest);
214}
215
216static
217u_char *
218skipext(u_char * p)
219{
220 while (!(*p++ & 0x80));
221 return (p);
222}
223
224/*
225 * Cause Values According to Q.850
226 * edescr: English description
227 * ddescr: German description used by Swissnet II (Swiss Telecom
228 * not yet written...
229 */
230
231static
232struct CauseValue {
233 u_char nr;
234 char *edescr;
235 char *ddescr;
236} cvlist[] = {
237
238 {
239 0x01, "Unallocated (unassigned) number", "Nummer nicht zugeteilt"
240 },
241 {
242 0x02, "No route to specified transit network", ""
243 },
244 {
245 0x03, "No route to destination", ""
246 },
247 {
248 0x04, "Send special information tone", ""
249 },
250 {
251 0x05, "Misdialled trunk prefix", ""
252 },
253 {
254 0x06, "Channel unacceptable", "Kanal nicht akzeptierbar"
255 },
256 {
257 0x07, "Channel awarded and being delivered in an established channel", ""
258 },
259 {
260 0x08, "Preemption", ""
261 },
262 {
263 0x09, "Preemption - circuit reserved for reuse", ""
264 },
265 {
266 0x10, "Normal call clearing", "Normale Ausloesung"
267 },
268 {
269 0x11, "User busy", "TNB besetzt"
270 },
271 {
272 0x12, "No user responding", ""
273 },
274 {
275 0x13, "No answer from user (user alerted)", ""
276 },
277 {
278 0x14, "Subscriber absent", ""
279 },
280 {
281 0x15, "Call rejected", ""
282 },
283 {
284 0x16, "Number changed", ""
285 },
286 {
287 0x1a, "non-selected user clearing", ""
288 },
289 {
290 0x1b, "Destination out of order", ""
291 },
292 {
293 0x1c, "Invalid number format (address incomplete)", ""
294 },
295 {
296 0x1d, "Facility rejected", ""
297 },
298 {
299 0x1e, "Response to Status enquiry", ""
300 },
301 {
302 0x1f, "Normal, unspecified", ""
303 },
304 {
305 0x22, "No circuit/channel available", ""
306 },
307 {
308 0x26, "Network out of order", ""
309 },
310 {
311 0x27, "Permanent frame mode connection out-of-service", ""
312 },
313 {
314 0x28, "Permanent frame mode connection operational", ""
315 },
316 {
317 0x29, "Temporary failure", ""
318 },
319 {
320 0x2a, "Switching equipment congestion", ""
321 },
322 {
323 0x2b, "Access information discarded", ""
324 },
325 {
326 0x2c, "Requested circuit/channel not available", ""
327 },
328 {
329 0x2e, "Precedence call blocked", ""
330 },
331 {
332 0x2f, "Resource unavailable, unspecified", ""
333 },
334 {
335 0x31, "Quality of service unavailable", ""
336 },
337 {
338 0x32, "Requested facility not subscribed", ""
339 },
340 {
341 0x35, "Outgoing calls barred within CUG", ""
342 },
343 {
344 0x37, "Incoming calls barred within CUG", ""
345 },
346 {
347 0x39, "Bearer capability not authorized", ""
348 },
349 {
350 0x3a, "Bearer capability not presently available", ""
351 },
352 {
353 0x3e, "Inconsistency in designated outgoing access information and subscriber class ", " "
354 },
355 {
356 0x3f, "Service or option not available, unspecified", ""
357 },
358 {
359 0x41, "Bearer capability not implemented", ""
360 },
361 {
362 0x42, "Channel type not implemented", ""
363 },
364 {
365 0x43, "Requested facility not implemented", ""
366 },
367 {
368 0x44, "Only restricted digital information bearer capability is available", ""
369 },
370 {
371 0x4f, "Service or option not implemented", ""
372 },
373 {
374 0x51, "Invalid call reference value", ""
375 },
376 {
377 0x52, "Identified channel does not exist", ""
378 },
379 {
380 0x53, "A suspended call exists, but this call identity does not", ""
381 },
382 {
383 0x54, "Call identity in use", ""
384 },
385 {
386 0x55, "No call suspended", ""
387 },
388 {
389 0x56, "Call having the requested call identity has been cleared", ""
390 },
391 {
392 0x57, "User not member of CUG", ""
393 },
394 {
395 0x58, "Incompatible destination", ""
396 },
397 {
398 0x5a, "Non-existent CUG", ""
399 },
400 {
401 0x5b, "Invalid transit network selection", ""
402 },
403 {
404 0x5f, "Invalid message, unspecified", ""
405 },
406 {
407 0x60, "Mandatory information element is missing", ""
408 },
409 {
410 0x61, "Message type non-existent or not implemented", ""
411 },
412 {
413 0x62, "Message not compatible with call state or message type non-existent or not implemented ", " "
414 },
415 {
416 0x63, "Information element/parameter non-existent or not implemented", ""
417 },
418 {
419 0x64, "Invalid information element contents", ""
420 },
421 {
422 0x65, "Message not compatible with call state", ""
423 },
424 {
425 0x66, "Recovery on timer expiry", ""
426 },
427 {
428 0x67, "Parameter non-existent or not implemented - passed on", ""
429 },
430 {
431 0x6e, "Message with unrecognized parameter discarded", ""
432 },
433 {
434 0x6f, "Protocol error, unspecified", ""
435 },
436 {
437 0x7f, "Interworking, unspecified", ""
438 },
439};
440
441#define CVSIZE sizeof(cvlist)/sizeof(struct CauseValue)
442
443static
444int
445prcause(char *dest, u_char * p)
446{
447 u_char *end;
448 char *dp = dest;
449 int i, cause;
450
451 end = p + p[1] + 1;
452 p += 2;
453 dp += sprintf(dp, " coding ");
454 dp += prbits(dp, *p, 7, 2);
455 dp += sprintf(dp, " location ");
456 dp += prbits(dp, *p, 4, 4);
457 *dp++ = '\n';
458 p = skipext(p);
459
460 cause = 0x7f & *p++;
461
462 /* locate cause value */
463 for (i = 0; i < CVSIZE; i++)
464 if (cvlist[i].nr == cause)
465 break;
466
467 /* display cause value if it exists */
468 if (i == CVSIZE)
469 dp += sprintf(dp, "Unknown cause type %x!\n", cause);
470 else
471 dp += sprintf(dp, " cause value %x : %s \n", cause, cvlist[i].edescr);
472
473 while (!0) {
474 if (p > end)
475 break;
476 dp += sprintf(dp, " diag attribute %d ", *p++ & 0x7f);
477 dp += sprintf(dp, " rej %d ", *p & 0x7f);
478 if (*p & 0x80) {
479 *dp++ = '\n';
480 break;
481 } else
482 dp += sprintf(dp, " av %d\n", (*++p) & 0x7f);
483 }
484 return (dp - dest);
485
486}
487
488static
489struct MessageType cause_1tr6[] =
490{
491 {CAUSE_InvCRef, "Invalid Call Reference"},
492 {CAUSE_BearerNotImpl, "Bearer Service Not Implemented"},
493 {CAUSE_CIDunknown, "Caller Identity unknown"},
494 {CAUSE_CIDinUse, "Caller Identity in Use"},
495 {CAUSE_NoChans, "No Channels available"},
496 {CAUSE_FacNotImpl, "Facility Not Implemented"},
497 {CAUSE_FacNotSubscr, "Facility Not Subscribed"},
498 {CAUSE_OutgoingBarred, "Outgoing calls barred"},
499 {CAUSE_UserAccessBusy, "User Access Busy"},
500 {CAUSE_NegativeGBG, "Negative GBG"},
501 {CAUSE_UnknownGBG, "Unknown GBG"},
502 {CAUSE_NoSPVknown, "No SPV known"},
503 {CAUSE_DestNotObtain, "Destination not obtainable"},
504 {CAUSE_NumberChanged, "Number changed"},
505 {CAUSE_OutOfOrder, "Out Of Order"},
506 {CAUSE_NoUserResponse, "No User Response"},
507 {CAUSE_UserBusy, "User Busy"},
508 {CAUSE_IncomingBarred, "Incoming Barred"},
509 {CAUSE_CallRejected, "Call Rejected"},
510 {CAUSE_NetworkCongestion, "Network Congestion"},
511 {CAUSE_RemoteUser, "Remote User initiated"},
512 {CAUSE_LocalProcErr, "Local Procedure Error"},
513 {CAUSE_RemoteProcErr, "Remote Procedure Error"},
514 {CAUSE_RemoteUserSuspend, "Remote User Suspend"},
515 {CAUSE_RemoteUserResumed, "Remote User Resumed"},
516 {CAUSE_UserInfoDiscarded, "User Info Discarded"}
517};
518
519int cause_1tr6_len = (sizeof(cause_1tr6) / sizeof(struct MessageType));
520
521static int
522prcause_1tr6(char *dest, u_char * p)
523{
524 char *dp = dest;
525 int i, cause;
526
527 p++;
528 if (0 == *p) {
529 dp += sprintf(dp, " OK (cause length=0)\n");
530 return (dp - dest);
531 } else if (*p > 1) {
532 dp += sprintf(dp, " coding ");
533 dp += prbits(dp, p[2], 7, 2);
534 dp += sprintf(dp, " location ");
535 dp += prbits(dp, p[2], 4, 4);
536 *dp++ = '\n';
537 }
538 p++;
539 cause = 0x7f & *p;
540
541 /* locate cause value */
542 for (i = 0; i < cause_1tr6_len; i++)
543 if (cause_1tr6[i].nr == cause)
544 break;
545
546 /* display cause value if it exists */
547 if (i == cause_1tr6_len)
548 dp += sprintf(dp, "Unknown cause type %x!\n", cause);
549 else
550 dp += sprintf(dp, " cause value %x : %s \n", cause, cause_1tr6[i].descr);
551
552 return (dp - dest);
553
554}
555
556static int
557prchident(char *dest, u_char * p)
558{
559 char *dp = dest;
560
561 p += 2;
562 dp += sprintf(dp, " octet 3 ");
563 dp += prbits(dp, *p, 8, 8);
564 *dp++ = '\n';
565 return (dp - dest);
566}
567
568static int
569prcalled(char *dest, u_char * p)
570{
571 int l;
572 char *dp = dest;
573
574 p++;
575 l = *p++ - 1;
576 dp += sprintf(dp, " octet 3 ");
577 dp += prbits(dp, *p++, 8, 8);
578 *dp++ = '\n';
579 dp += sprintf(dp, " number digits ");
580 while (l--)
581 *dp++ = *p++;
582 *dp++ = '\n';
583 return (dp - dest);
584}
585static int
586prcalling(char *dest, u_char * p)
587{
588 int l;
589 char *dp = dest;
590
591 p++;
592 l = *p++ - 1;
593 dp += sprintf(dp, " octet 3 ");
594 dp += prbits(dp, *p, 8, 8);
595 *dp++ = '\n';
596 if (!(*p & 0x80)) {
597 dp += sprintf(dp, " octet 3a ");
598 dp += prbits(dp, *++p, 8, 8);
599 *dp++ = '\n';
600 l--;
601 };
602 p++;
603
604 dp += sprintf(dp, " number digits ");
605 while (l--)
606 *dp++ = *p++;
607 *dp++ = '\n';
608 return (dp - dest);
609}
610
611static
612int
613prbearer(char *dest, u_char * p)
614{
615 char *dp = dest, ch;
616
617 p += 2;
618 dp += sprintf(dp, " octet 3 ");
619 dp += prbits(dp, *p++, 8, 8);
620 *dp++ = '\n';
621 dp += sprintf(dp, " octet 4 ");
622 dp += prbits(dp, *p, 8, 8);
623 *dp++ = '\n';
624 if ((*p++ & 0x1f) == 0x18) {
625 dp += sprintf(dp, " octet 4.1 ");
626 dp += prbits(dp, *p++, 8, 8);
627 *dp++ = '\n';
628 }
629 /* check for user information layer 1 */
630 if ((*p & 0x60) == 0x20) {
631 ch = ' ';
632 do {
633 dp += sprintf(dp, " octet 5%c ", ch);
634 dp += prbits(dp, *p, 8, 8);
635 *dp++ = '\n';
636 if (ch == ' ')
637 ch = 'a';
638 else
639 ch++;
640 }
641 while (!(*p++ & 0x80));
642 }
643 /* check for user information layer 2 */
644 if ((*p & 0x60) == 0x40) {
645 dp += sprintf(dp, " octet 6 ");
646 dp += prbits(dp, *p++, 8, 8);
647 *dp++ = '\n';
648 }
649 /* check for user information layer 3 */
650 if ((*p & 0x60) == 0x60) {
651 dp += sprintf(dp, " octet 7 ");
652 dp += prbits(dp, *p++, 8, 8);
653 *dp++ = '\n';
654 }
655 return (dp - dest);
656}
657
658
659static
660int
661prbearer_ni1(char *dest, u_char * p)
662{
663 char *dp = dest;
664 u_char len;
665
666 p++;
667 len = *p++;
668 dp += sprintf(dp, " octet 3 ");
669 dp += prbits(dp, *p, 8, 8);
670 switch (*p++) {
671 case 0x80:
672 dp += sprintf(dp, " Speech");
673 break;
674 case 0x88:
675 dp += sprintf(dp, " Unrestricted digital information");
676 break;
677 case 0x90:
678 dp += sprintf(dp, " 3.1 kHz audio");
679 break;
680 default:
681 dp += sprintf(dp, " Unknown information-transfer capability");
682 }
683 *dp++ = '\n';
684 dp += sprintf(dp, " octet 4 ");
685 dp += prbits(dp, *p, 8, 8);
686 switch (*p++) {
687 case 0x90:
688 dp += sprintf(dp, " 64 kbps, circuit mode");
689 break;
690 case 0xc0:
691 dp += sprintf(dp, " Packet mode");
692 break;
693 default:
694 dp += sprintf(dp, " Unknown transfer mode");
695 }
696 *dp++ = '\n';
697 if (len > 2) {
698 dp += sprintf(dp, " octet 5 ");
699 dp += prbits(dp, *p, 8, 8);
700 switch (*p++) {
701 case 0x21:
702 dp += sprintf(dp, " Rate adaption\n");
703 dp += sprintf(dp, " octet 5a ");
704 dp += prbits(dp, *p, 8, 8);
705 break;
706 case 0xa2:
707 dp += sprintf(dp, " u-law");
708 break;
709 default:
710 dp += sprintf(dp, " Unknown UI layer 1 protocol");
711 }
712 *dp++ = '\n';
713 }
714 return (dp - dest);
715}
716
717static int
718general(char *dest, u_char * p)
719{
720 char *dp = dest;
721 char ch = ' ';
722 int l, octet = 3;
723
724 p++;
725 l = *p++;
726 /* Iterate over all octets in the information element */
727 while (l--) {
728 dp += sprintf(dp, " octet %d%c ", octet, ch);
729 dp += prbits(dp, *p++, 8, 8);
730 *dp++ = '\n';
731
732 /* last octet in group? */
733 if (*p & 0x80) {
734 octet++;
735 ch = ' ';
736 } else if (ch == ' ')
737 ch = 'a';
738 else
739 ch++;
740 }
741 return (dp - dest);
742}
743
744static int
745general_ni1(char *dest, u_char * p)
746{
747 char *dp = dest;
748 char ch = ' ';
749 int l, octet = 3;
750
751 p++;
752 l = *p++;
753 /* Iterate over all octets in the information element */
754 while (l--) {
755 dp += sprintf(dp, " octet %d%c ", octet, ch);
756 dp += prbits(dp, *p, 8, 8);
757 *dp++ = '\n';
758
759 /* last octet in group? */
760 if (*p++ & 0x80) {
761 octet++;
762 ch = ' ';
763 } else if (ch == ' ')
764 ch = 'a';
765 else
766 ch++;
767 }
768 return (dp - dest);
769}
770
771static int
772prcharge(char *dest, u_char * p)
773{
774 char *dp = dest;
775 int l;
776
777 p++;
778 l = *p++ - 1;
779 dp += sprintf(dp, " GEA ");
780 dp += prbits(dp, *p++, 8, 8);
781 dp += sprintf(dp, " Anzahl: ");
782 /* Iterate over all octets in the * information element */
783 while (l--)
784 *dp++ = *p++;
785 *dp++ = '\n';
786 return (dp - dest);
787}
788static int
789prtext(char *dest, u_char * p)
790{
791 char *dp = dest;
792 int l;
793
794 p++;
795 l = *p++;
796 dp += sprintf(dp, " ");
797 /* Iterate over all octets in the * information element */
798 while (l--)
799 *dp++ = *p++;
800 *dp++ = '\n';
801 return (dp - dest);
802}
803
804static int
805prfeatureind(char *dest, u_char * p)
806{
807 char *dp = dest;
808
809 p += 2; /* skip id, len */
810 dp += sprintf(dp, " octet 3 ");
811 dp += prbits(dp, *p, 8, 8);
812 *dp++ = '\n';
813 if (!(*p++ & 80)) {
814 dp += sprintf(dp, " octet 4 ");
815 dp += prbits(dp, *p++, 8, 8);
816 *dp++ = '\n';
817 }
818 dp += sprintf(dp, " Status: ");
819 switch (*p) {
820 case 0:
821 dp += sprintf(dp, "Idle");
822 break;
823 case 1:
824 dp += sprintf(dp, "Active");
825 break;
826 case 2:
827 dp += sprintf(dp, "Prompt");
828 break;
829 case 3:
830 dp += sprintf(dp, "Pending");
831 break;
832 default:
833 dp += sprintf(dp, "(Reserved)");
834 break;
835 }
836 *dp++ = '\n';
837 return (dp - dest);
838}
839
840static
841struct DTag { /* Display tags */
842 u_char nr;
843 char *descr;
844} dtaglist[] = {
845 { 0x82, "Continuation" },
846 { 0x83, "Called address" },
847 { 0x84, "Cause" },
848 { 0x85, "Progress indicator" },
849 { 0x86, "Notification indicator" },
850 { 0x87, "Prompt" },
851 { 0x88, "Accumlated digits" },
852 { 0x89, "Status" },
853 { 0x8a, "Inband" },
854 { 0x8b, "Calling address" },
855 { 0x8c, "Reason" },
856 { 0x8d, "Calling party name" },
857 { 0x8e, "Called party name" },
858 { 0x8f, "Orignal called name" },
859 { 0x90, "Redirecting name" },
860 { 0x91, "Connected name" },
861 { 0x92, "Originating restrictions" },
862 { 0x93, "Date & time of day" },
863 { 0x94, "Call Appearance ID" },
864 { 0x95, "Feature address" },
865 { 0x96, "Redirection name" },
866 { 0x9e, "Text" },
867};
868#define DTAGSIZE sizeof(dtaglist)/sizeof(struct DTag)
869
870static int
871disptext_ni1(char *dest, u_char * p)
872{
873 char *dp = dest;
874 int l, tag, len, i;
875
876 p++;
877 l = *p++ - 1;
878 if (*p++ != 0x80) {
879 dp += sprintf(dp, " Unknown display type\n");
880 return (dp - dest);
881 }
882 /* Iterate over all tag,length,text fields */
883 while (l > 0) {
884 tag = *p++;
885 len = *p++;
886 l -= len + 2;
887 /* Don't space or skip */
888 if ((tag == 0x80) || (tag == 0x81)) p++;
889 else {
890 for (i = 0; i < DTAGSIZE; i++)
891 if (tag == dtaglist[i].nr)
892 break;
893
894 /* When not found, give appropriate msg */
895 if (i != DTAGSIZE) {
896 dp += sprintf(dp, " %s: ", dtaglist[i].descr);
897 while (len--)
898 *dp++ = *p++;
899 } else {
900 dp += sprintf(dp, " (unknown display tag %2x): ", tag);
901 while (len--)
902 *dp++ = *p++;
903 }
904 dp += sprintf(dp, "\n");
905 }
906 }
907 return (dp - dest);
908}
909static int
910display(char *dest, u_char * p)
911{
912 char *dp = dest;
913 char ch = ' ';
914 int l, octet = 3;
915
916 p++;
917 l = *p++;
918 /* Iterate over all octets in the * display-information element */
919 dp += sprintf(dp, " \"");
920 while (l--) {
921 dp += sprintf(dp, "%c", *p++);
922
923 /* last octet in group? */
924 if (*p & 0x80) {
925 octet++;
926 ch = ' ';
927 } else if (ch == ' ')
928 ch = 'a';
929
930 else
931 ch++;
932 }
933 *dp++ = '\"';
934 *dp++ = '\n';
935 return (dp - dest);
936}
937
938int
939prfacility(char *dest, u_char * p)
940{
941 char *dp = dest;
942 int l, l2;
943
944 p++;
945 l = *p++;
946 dp += sprintf(dp, " octet 3 ");
947 dp += prbits(dp, *p++, 8, 8);
948 dp += sprintf(dp, "\n");
949 l -= 1;
950
951 while (l > 0) {
952 dp += sprintf(dp, " octet 4 ");
953 dp += prbits(dp, *p++, 8, 8);
954 dp += sprintf(dp, "\n");
955 dp += sprintf(dp, " octet 5 %d\n", l2 = *p++ & 0x7f);
956 l -= 2;
957 dp += sprintf(dp, " contents ");
958 while (l2--) {
959 dp += sprintf(dp, "%2x ", *p++);
960 l--;
961 }
962 dp += sprintf(dp, "\n");
963 }
964
965 return (dp - dest);
966}
967
968static
969struct InformationElement {
970 u_char nr;
971 char *descr;
972 int (*f) (char *, u_char *);
973} ielist[] = {
974
975 {
976 0x00, "Segmented message", general
977 },
978 {
979 0x04, "Bearer capability", prbearer
980 },
981 {
982 0x08, "Cause", prcause
983 },
984 {
985 0x10, "Call identity", general
986 },
987 {
988 0x14, "Call state", general
989 },
990 {
991 0x18, "Channel identification", prchident
992 },
993 {
994 0x1c, "Facility", prfacility
995 },
996 {
997 0x1e, "Progress indicator", general
998 },
999 {
1000 0x20, "Network-specific facilities", general
1001 },
1002 {
1003 0x27, "Notification indicator", general
1004 },
1005 {
1006 0x28, "Display", display
1007 },
1008 {
1009 0x29, "Date/Time", general
1010 },
1011 {
1012 0x2c, "Keypad facility", general
1013 },
1014 {
1015 0x34, "Signal", general
1016 },
1017 {
1018 0x40, "Information rate", general
1019 },
1020 {
1021 0x42, "End-to-end delay", general
1022 },
1023 {
1024 0x43, "Transit delay selection and indication", general
1025 },
1026 {
1027 0x44, "Packet layer binary parameters", general
1028 },
1029 {
1030 0x45, "Packet layer window size", general
1031 },
1032 {
1033 0x46, "Packet size", general
1034 },
1035 {
1036 0x47, "Closed user group", general
1037 },
1038 {
1039 0x4a, "Reverse charge indication", general
1040 },
1041 {
1042 0x6c, "Calling party number", prcalling
1043 },
1044 {
1045 0x6d, "Calling party subaddress", general
1046 },
1047 {
1048 0x70, "Called party number", prcalled
1049 },
1050 {
1051 0x71, "Called party subaddress", general
1052 },
1053 {
1054 0x74, "Redirecting number", general
1055 },
1056 {
1057 0x78, "Transit network selection", general
1058 },
1059 {
1060 0x79, "Restart indicator", general
1061 },
1062 {
1063 0x7c, "Low layer compatibility", general
1064 },
1065 {
1066 0x7d, "High layer compatibility", general
1067 },
1068 {
1069 0x7e, "User-user", general
1070 },
1071 {
1072 0x7f, "Escape for extension", general
1073 },
1074};
1075
1076
1077#define IESIZE sizeof(ielist)/sizeof(struct InformationElement)
1078
1079static
1080struct InformationElement ielist_ni1[] = {
1081 { 0x04, "Bearer Capability", prbearer_ni1 },
1082 { 0x08, "Cause", prcause },
1083 { 0x14, "Call State", general_ni1 },
1084 { 0x18, "Channel Identification", prchident },
1085 { 0x1e, "Progress Indicator", general_ni1 },
1086 { 0x27, "Notification Indicator", general_ni1 },
1087 { 0x2c, "Keypad Facility", prtext },
1088 { 0x32, "Information Request", general_ni1 },
1089 { 0x34, "Signal", general_ni1 },
1090 { 0x38, "Feature Activation", general_ni1 },
1091 { 0x39, "Feature Indication", prfeatureind },
1092 { 0x3a, "Service Profile Identification (SPID)", prtext },
1093 { 0x3b, "Endpoint Identifier", general_ni1 },
1094 { 0x6c, "Calling Party Number", prcalling },
1095 { 0x6d, "Calling Party Subaddress", general_ni1 },
1096 { 0x70, "Called Party Number", prcalled },
1097 { 0x71, "Called Party Subaddress", general_ni1 },
1098 { 0x74, "Redirecting Number", general_ni1 },
1099 { 0x78, "Transit Network Selection", general_ni1 },
1100 { 0x7c, "Low Layer Compatibility", general_ni1 },
1101 { 0x7d, "High Layer Compatibility", general_ni1 },
1102};
1103
1104
1105#define IESIZE_NI1 sizeof(ielist_ni1)/sizeof(struct InformationElement)
1106
1107static
1108struct InformationElement ielist_ni1_cs5[] = {
1109 { 0x1d, "Operator system access", general_ni1 },
1110 { 0x2a, "Display text", disptext_ni1 },
1111};
1112
1113#define IESIZE_NI1_CS5 sizeof(ielist_ni1_cs5)/sizeof(struct InformationElement)
1114
1115static
1116struct InformationElement ielist_ni1_cs6[] = {
1117 { 0x7b, "Call appearance", general_ni1 },
1118};
1119
1120#define IESIZE_NI1_CS6 sizeof(ielist_ni1_cs6)/sizeof(struct InformationElement)
1121
1122static struct InformationElement we_0[] =
1123{
1124 {WE0_cause, "Cause", prcause_1tr6},
1125 {WE0_connAddr, "Connecting Address", prcalled},
1126 {WE0_callID, "Call IDentity", general},
1127 {WE0_chanID, "Channel IDentity", general},
1128 {WE0_netSpecFac, "Network Specific Facility", general},
1129 {WE0_display, "Display", general},
1130 {WE0_keypad, "Keypad", general},
1131 {WE0_origAddr, "Origination Address", prcalled},
1132 {WE0_destAddr, "Destination Address", prcalled},
1133 {WE0_userInfo, "User Info", general}
1134};
1135
1136#define WE_0_LEN (sizeof(we_0) / sizeof(struct InformationElement))
1137
1138static struct InformationElement we_6[] =
1139{
1140 {WE6_serviceInd, "Service Indicator", general},
1141 {WE6_chargingInfo, "Charging Information", prcharge},
1142 {WE6_date, "Date", prtext},
1143 {WE6_facSelect, "Facility Select", general},
1144 {WE6_facStatus, "Facility Status", general},
1145 {WE6_statusCalled, "Status Called", general},
1146 {WE6_addTransAttr, "Additional Transmission Attributes", general}
1147};
1148#define WE_6_LEN (sizeof(we_6) / sizeof(struct InformationElement))
1149
1150int
1151QuickHex(char *txt, u_char * p, int cnt)
1152{
1153 register int i;
1154 register char *t = txt;
1155 register u_char w;
1156
1157 for (i = 0; i < cnt; i++) {
1158 *t++ = ' ';
1159 w = (p[i] >> 4) & 0x0f;
1160 if (w < 10)
1161 *t++ = '0' + w;
1162 else
1163 *t++ = 'A' - 10 + w;
1164 w = p[i] & 0x0f;
1165 if (w < 10)
1166 *t++ = '0' + w;
1167 else
1168 *t++ = 'A' - 10 + w;
1169 }
1170 *t++ = 0;
1171 return (t - txt);
1172}
1173
1174void
1175LogFrame(struct IsdnCardState *cs, u_char * buf, int size)
1176{
1177 char *dp;
1178
1179 if (size < 1)
1180 return;
1181 dp = cs->dlog;
1182 if (size < MAX_DLOG_SPACE / 3 - 10) {
1183 *dp++ = 'H';
1184 *dp++ = 'E';
1185 *dp++ = 'X';
1186 *dp++ = ':';
1187 dp += QuickHex(dp, buf, size);
1188 dp--;
1189 *dp++ = '\n';
1190 *dp = 0;
1191 HiSax_putstatus(cs, NULL, cs->dlog);
1192 } else
1193 HiSax_putstatus(cs, "LogFrame: ", "warning Frame too big (%d)", size);
1194}
1195
1196void
1197dlogframe(struct IsdnCardState *cs, struct sk_buff *skb, int dir)
1198{
1199 u_char *bend, *buf;
1200 char *dp;
1201 unsigned char pd, cr_l, cr, mt;
1202 unsigned char sapi, tei, ftyp;
1203 int i, cset = 0, cs_old = 0, cs_fest = 0;
1204 int size, finish = 0;
1205
1206 if (skb->len < 3)
1207 return;
1208 /* display header */
1209 dp = cs->dlog;
1210 dp += jiftime(dp, jiffies);
1211 *dp++ = ' ';
1212 sapi = skb->data[0] >> 2;
1213 tei = skb->data[1] >> 1;
1214 ftyp = skb->data[2];
1215 buf = skb->data;
1216 dp += sprintf(dp, "frame %s ", dir ? "network->user" : "user->network");
1217 size = skb->len;
1218
1219 if (tei == GROUP_TEI) {
1220 if (sapi == CTRL_SAPI) { /* sapi 0 */
1221 if (ftyp == 3) {
1222 dp += sprintf(dp, "broadcast\n");
1223 buf += 3;
1224 size -= 3;
1225 } else {
1226 dp += sprintf(dp, "no UI broadcast\n");
1227 finish = 1;
1228 }
1229 } else if (sapi == TEI_SAPI) {
1230 dp += sprintf(dp, "tei management\n");
1231 finish = 1;
1232 } else {
1233 dp += sprintf(dp, "unknown sapi %d broadcast\n", sapi);
1234 finish = 1;
1235 }
1236 } else {
1237 if (sapi == CTRL_SAPI) {
1238 if (!(ftyp & 1)) { /* IFrame */
1239 dp += sprintf(dp, "with tei %d\n", tei);
1240 buf += 4;
1241 size -= 4;
1242 } else {
1243 dp += sprintf(dp, "SFrame with tei %d\n", tei);
1244 finish = 1;
1245 }
1246 } else {
1247 dp += sprintf(dp, "unknown sapi %d tei %d\n", sapi, tei);
1248 finish = 1;
1249 }
1250 }
1251 bend = skb->data + skb->len;
1252 if (buf >= bend) {
1253 dp += sprintf(dp, "frame too short\n");
1254 finish = 1;
1255 }
1256 if (finish) {
1257 *dp = 0;
1258 HiSax_putstatus(cs, NULL, cs->dlog);
1259 return;
1260 }
1261 if ((0xfe & buf[0]) == PROTO_DIS_N0) { /* 1TR6 */
1262 /* locate message type */
1263 pd = *buf++;
1264 cr_l = *buf++;
1265 if (cr_l)
1266 cr = *buf++;
1267 else
1268 cr = 0;
1269 mt = *buf++;
1270 if (pd == PROTO_DIS_N0) { /* N0 */
1271 for (i = 0; i < MT_N0_LEN; i++)
1272 if (mt_n0[i].nr == mt)
1273 break;
1274 /* display message type if it exists */
1275 if (i == MT_N0_LEN)
1276 dp += sprintf(dp, "callref %d %s size %d unknown message type N0 %x!\n",
1277 cr & 0x7f, (cr & 0x80) ? "called" : "caller",
1278 size, mt);
1279 else
1280 dp += sprintf(dp, "callref %d %s size %d message type %s\n",
1281 cr & 0x7f, (cr & 0x80) ? "called" : "caller",
1282 size, mt_n0[i].descr);
1283 } else { /* N1 */
1284 for (i = 0; i < MT_N1_LEN; i++)
1285 if (mt_n1[i].nr == mt)
1286 break;
1287 /* display message type if it exists */
1288 if (i == MT_N1_LEN)
1289 dp += sprintf(dp, "callref %d %s size %d unknown message type N1 %x!\n",
1290 cr & 0x7f, (cr & 0x80) ? "called" : "caller",
1291 size, mt);
1292 else
1293 dp += sprintf(dp, "callref %d %s size %d message type %s\n",
1294 cr & 0x7f, (cr & 0x80) ? "called" : "caller",
1295 size, mt_n1[i].descr);
1296 }
1297
1298 /* display each information element */
1299 while (buf < bend) {
1300 /* Is it a single octet information element? */
1301 if (*buf & 0x80) {
1302 switch ((*buf >> 4) & 7) {
1303 case 1:
1304 dp += sprintf(dp, " Shift %x\n", *buf & 0xf);
1305 cs_old = cset;
1306 cset = *buf & 7;
1307 cs_fest = *buf & 8;
1308 break;
1309 case 3:
1310 dp += sprintf(dp, " Congestion level %x\n", *buf & 0xf);
1311 break;
1312 case 2:
1313 if (*buf == 0xa0) {
1314 dp += sprintf(dp, " More data\n");
1315 break;
1316 }
1317 if (*buf == 0xa1) {
1318 dp += sprintf(dp, " Sending complete\n");
1319 }
1320 break;
1321 /* fall through */
1322 default:
1323 dp += sprintf(dp, " Reserved %x\n", *buf);
1324 break;
1325 }
1326 buf++;
1327 continue;
1328 }
1329 /* No, locate it in the table */
1330 if (cset == 0) {
1331 for (i = 0; i < WE_0_LEN; i++)
1332 if (*buf == we_0[i].nr)
1333 break;
1334
1335 /* When found, give appropriate msg */
1336 if (i != WE_0_LEN) {
1337 dp += sprintf(dp, " %s\n", we_0[i].descr);
1338 dp += we_0[i].f(dp, buf);
1339 } else
1340 dp += sprintf(dp, " Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]);
1341 } else if (cset == 6) {
1342 for (i = 0; i < WE_6_LEN; i++)
1343 if (*buf == we_6[i].nr)
1344 break;
1345
1346 /* When found, give appropriate msg */
1347 if (i != WE_6_LEN) {
1348 dp += sprintf(dp, " %s\n", we_6[i].descr);
1349 dp += we_6[i].f(dp, buf);
1350 } else
1351 dp += sprintf(dp, " Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]);
1352 } else
1353 dp += sprintf(dp, " Unknown Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]);
1354 /* Skip to next element */
1355 if (cs_fest == 8) {
1356 cset = cs_old;
1357 cs_old = 0;
1358 cs_fest = 0;
1359 }
1360 buf += buf[1] + 2;
1361 }
1362 } else if ((buf[0] == 8) && (cs->protocol == ISDN_PTYPE_NI1)) { /* NI-1 */
1363 /* locate message type */
1364 buf++;
1365 cr_l = *buf++;
1366 if (cr_l)
1367 cr = *buf++;
1368 else
1369 cr = 0;
1370 mt = *buf++;
1371 for (i = 0; i < MTSIZE; i++)
1372 if (mtlist[i].nr == mt)
1373 break;
1374
1375 /* display message type if it exists */
1376 if (i == MTSIZE)
1377 dp += sprintf(dp, "callref %d %s size %d unknown message type %x!\n",
1378 cr & 0x7f, (cr & 0x80) ? "called" : "caller",
1379 size, mt);
1380 else
1381 dp += sprintf(dp, "callref %d %s size %d message type %s\n",
1382 cr & 0x7f, (cr & 0x80) ? "called" : "caller",
1383 size, mtlist[i].descr);
1384
1385 /* display each information element */
1386 while (buf < bend) {
1387 /* Is it a single octet information element? */
1388 if (*buf & 0x80) {
1389 switch ((*buf >> 4) & 7) {
1390 case 1:
1391 dp += sprintf(dp, " Shift %x\n", *buf & 0xf);
1392 cs_old = cset;
1393 cset = *buf & 7;
1394 cs_fest = *buf & 8;
1395 break;
1396 default:
1397 dp += sprintf(dp, " Unknown single-octet IE %x\n", *buf);
1398 break;
1399 }
1400 buf++;
1401 continue;
1402 }
1403 /* No, locate it in the table */
1404 if (cset == 0) {
1405 for (i = 0; i < IESIZE; i++)
1406 if (*buf == ielist_ni1[i].nr)
1407 break;
1408
1409 /* When not found, give appropriate msg */
1410 if (i != IESIZE) {
1411 dp += sprintf(dp, " %s\n", ielist_ni1[i].descr);
1412 dp += ielist_ni1[i].f(dp, buf);
1413 } else
1414 dp += sprintf(dp, " attribute %x attribute size %d\n", *buf, buf[1]);
1415 } else if (cset == 5) {
1416 for (i = 0; i < IESIZE_NI1_CS5; i++)
1417 if (*buf == ielist_ni1_cs5[i].nr)
1418 break;
1419
1420 /* When not found, give appropriate msg */
1421 if (i != IESIZE_NI1_CS5) {
1422 dp += sprintf(dp, " %s\n", ielist_ni1_cs5[i].descr);
1423 dp += ielist_ni1_cs5[i].f(dp, buf);
1424 } else
1425 dp += sprintf(dp, " attribute %x attribute size %d\n", *buf, buf[1]);
1426 } else if (cset == 6) {
1427 for (i = 0; i < IESIZE_NI1_CS6; i++)
1428 if (*buf == ielist_ni1_cs6[i].nr)
1429 break;
1430
1431 /* When not found, give appropriate msg */
1432 if (i != IESIZE_NI1_CS6) {
1433 dp += sprintf(dp, " %s\n", ielist_ni1_cs6[i].descr);
1434 dp += ielist_ni1_cs6[i].f(dp, buf);
1435 } else
1436 dp += sprintf(dp, " attribute %x attribute size %d\n", *buf, buf[1]);
1437 } else
1438 dp += sprintf(dp, " Unknown Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]);
1439
1440 /* Skip to next element */
1441 if (cs_fest == 8) {
1442 cset = cs_old;
1443 cs_old = 0;
1444 cs_fest = 0;
1445 }
1446 buf += buf[1] + 2;
1447 }
1448 } else if ((buf[0] == 8) && (cs->protocol == ISDN_PTYPE_EURO)) { /* EURO */
1449 /* locate message type */
1450 buf++;
1451 cr_l = *buf++;
1452 if (cr_l)
1453 cr = *buf++;
1454 else
1455 cr = 0;
1456 mt = *buf++;
1457 for (i = 0; i < MTSIZE; i++)
1458 if (mtlist[i].nr == mt)
1459 break;
1460
1461 /* display message type if it exists */
1462 if (i == MTSIZE)
1463 dp += sprintf(dp, "callref %d %s size %d unknown message type %x!\n",
1464 cr & 0x7f, (cr & 0x80) ? "called" : "caller",
1465 size, mt);
1466 else
1467 dp += sprintf(dp, "callref %d %s size %d message type %s\n",
1468 cr & 0x7f, (cr & 0x80) ? "called" : "caller",
1469 size, mtlist[i].descr);
1470
1471 /* display each information element */
1472 while (buf < bend) {
1473 /* Is it a single octet information element? */
1474 if (*buf & 0x80) {
1475 switch ((*buf >> 4) & 7) {
1476 case 1:
1477 dp += sprintf(dp, " Shift %x\n", *buf & 0xf);
1478 break;
1479 case 3:
1480 dp += sprintf(dp, " Congestion level %x\n", *buf & 0xf);
1481 break;
1482 case 5:
1483 dp += sprintf(dp, " Repeat indicator %x\n", *buf & 0xf);
1484 break;
1485 case 2:
1486 if (*buf == 0xa0) {
1487 dp += sprintf(dp, " More data\n");
1488 break;
1489 }
1490 if (*buf == 0xa1) {
1491 dp += sprintf(dp, " Sending complete\n");
1492 }
1493 break;
1494 /* fall through */
1495 default:
1496 dp += sprintf(dp, " Reserved %x\n", *buf);
1497 break;
1498 }
1499 buf++;
1500 continue;
1501 }
1502 /* No, locate it in the table */
1503 for (i = 0; i < IESIZE; i++)
1504 if (*buf == ielist[i].nr)
1505 break;
1506
1507 /* When not found, give appropriate msg */
1508 if (i != IESIZE) {
1509 dp += sprintf(dp, " %s\n", ielist[i].descr);
1510 dp += ielist[i].f(dp, buf);
1511 } else
1512 dp += sprintf(dp, " attribute %x attribute size %d\n", *buf, buf[1]);
1513
1514 /* Skip to next element */
1515 buf += buf[1] + 2;
1516 }
1517 } else {
1518 dp += sprintf(dp, "Unknown protocol %x!", buf[0]);
1519 }
1520 *dp = 0;
1521 HiSax_putstatus(cs, NULL, cs->dlog);
1522}
diff --git a/drivers/isdn/hisax/s0box.c b/drivers/isdn/hisax/s0box.c
new file mode 100644
index 000000000000..f3c481384a4e
--- /dev/null
+++ b/drivers/isdn/hisax/s0box.c
@@ -0,0 +1,266 @@
1/* $Id: s0box.c,v 2.6.2.4 2004/01/13 23:48:39 keil Exp $
2 *
3 * low level stuff for Creatix S0BOX
4 *
5 * Author Enrik Berkhan
6 * Copyright by Enrik Berkhan <enrik@starfleet.inka.de>
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 */
12
13#include <linux/init.h>
14#include "hisax.h"
15#include "isac.h"
16#include "hscx.h"
17#include "isdnl1.h"
18
19extern const char *CardType[];
20const char *s0box_revision = "$Revision: 2.6.2.4 $";
21
22static inline void
23writereg(unsigned int padr, signed int addr, u_char off, u_char val) {
24 outb_p(0x1c,padr+2);
25 outb_p(0x14,padr+2);
26 outb_p((addr+off)&0x7f,padr);
27 outb_p(0x16,padr+2);
28 outb_p(val,padr);
29 outb_p(0x17,padr+2);
30 outb_p(0x14,padr+2);
31 outb_p(0x1c,padr+2);
32}
33
34static u_char nibtab[] = { 1, 9, 5, 0xd, 3, 0xb, 7, 0xf,
35 0, 0, 0, 0, 0, 0, 0, 0,
36 0, 8, 4, 0xc, 2, 0xa, 6, 0xe } ;
37
38static inline u_char
39readreg(unsigned int padr, signed int addr, u_char off) {
40 register u_char n1, n2;
41
42 outb_p(0x1c,padr+2);
43 outb_p(0x14,padr+2);
44 outb_p((addr+off)|0x80,padr);
45 outb_p(0x16,padr+2);
46 outb_p(0x17,padr+2);
47 n1 = (inb_p(padr+1) >> 3) & 0x17;
48 outb_p(0x16,padr+2);
49 n2 = (inb_p(padr+1) >> 3) & 0x17;
50 outb_p(0x14,padr+2);
51 outb_p(0x1c,padr+2);
52 return nibtab[n1] | (nibtab[n2] << 4);
53}
54
55static inline void
56read_fifo(unsigned int padr, signed int adr, u_char * data, int size)
57{
58 int i;
59 register u_char n1, n2;
60
61 outb_p(0x1c, padr+2);
62 outb_p(0x14, padr+2);
63 outb_p(adr|0x80, padr);
64 outb_p(0x16, padr+2);
65 for (i=0; i<size; i++) {
66 outb_p(0x17, padr+2);
67 n1 = (inb_p(padr+1) >> 3) & 0x17;
68 outb_p(0x16,padr+2);
69 n2 = (inb_p(padr+1) >> 3) & 0x17;
70 *(data++)=nibtab[n1] | (nibtab[n2] << 4);
71 }
72 outb_p(0x14,padr+2);
73 outb_p(0x1c,padr+2);
74 return;
75}
76
77static inline void
78write_fifo(unsigned int padr, signed int adr, u_char * data, int size)
79{
80 int i;
81 outb_p(0x1c, padr+2);
82 outb_p(0x14, padr+2);
83 outb_p(adr&0x7f, padr);
84 for (i=0; i<size; i++) {
85 outb_p(0x16, padr+2);
86 outb_p(*(data++), padr);
87 outb_p(0x17, padr+2);
88 }
89 outb_p(0x14,padr+2);
90 outb_p(0x1c,padr+2);
91 return;
92}
93
94/* Interface functions */
95
96static u_char
97ReadISAC(struct IsdnCardState *cs, u_char offset)
98{
99 return (readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, offset));
100}
101
102static void
103WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
104{
105 writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, offset, value);
106}
107
108static void
109ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
110{
111 read_fifo(cs->hw.teles3.cfg_reg, cs->hw.teles3.isacfifo, data, size);
112}
113
114static void
115WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
116{
117 write_fifo(cs->hw.teles3.cfg_reg, cs->hw.teles3.isacfifo, data, size);
118}
119
120static u_char
121ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
122{
123 return (readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[hscx], offset));
124}
125
126static void
127WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
128{
129 writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[hscx], offset, value);
130}
131
132/*
133 * fast interrupt HSCX stuff goes here
134 */
135
136#define READHSCX(cs, nr, reg) readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[nr], reg)
137#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[nr], reg, data)
138#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscxfifo[nr], ptr, cnt)
139#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscxfifo[nr], ptr, cnt)
140
141#include "hscx_irq.c"
142
143static irqreturn_t
144s0box_interrupt(int intno, void *dev_id, struct pt_regs *regs)
145{
146#define MAXCOUNT 5
147 struct IsdnCardState *cs = dev_id;
148 u_char val;
149 u_long flags;
150 int count = 0;
151
152 spin_lock_irqsave(&cs->lock, flags);
153 val = readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[1], HSCX_ISTA);
154 Start_HSCX:
155 if (val)
156 hscx_int_main(cs, val);
157 val = readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, ISAC_ISTA);
158 Start_ISAC:
159 if (val)
160 isac_interrupt(cs, val);
161 count++;
162 val = readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[1], HSCX_ISTA);
163 if (val && count < MAXCOUNT) {
164 if (cs->debug & L1_DEB_HSCX)
165 debugl1(cs, "HSCX IntStat after IntRoutine");
166 goto Start_HSCX;
167 }
168 val = readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, ISAC_ISTA);
169 if (val && count < MAXCOUNT) {
170 if (cs->debug & L1_DEB_ISAC)
171 debugl1(cs, "ISAC IntStat after IntRoutine");
172 goto Start_ISAC;
173 }
174 if (count >= MAXCOUNT)
175 printk(KERN_WARNING "S0Box: more than %d loops in s0box_interrupt\n", count);
176 writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[0], HSCX_MASK, 0xFF);
177 writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[1], HSCX_MASK, 0xFF);
178 writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, ISAC_MASK, 0xFF);
179 writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, ISAC_MASK, 0x0);
180 writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[0], HSCX_MASK, 0x0);
181 writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[1], HSCX_MASK, 0x0);
182 spin_unlock_irqrestore(&cs->lock, flags);
183 return IRQ_HANDLED;
184}
185
186void
187release_io_s0box(struct IsdnCardState *cs)
188{
189 release_region(cs->hw.teles3.cfg_reg, 8);
190}
191
192static int
193S0Box_card_msg(struct IsdnCardState *cs, int mt, void *arg)
194{
195 u_long flags;
196
197 switch (mt) {
198 case CARD_RESET:
199 break;
200 case CARD_RELEASE:
201 release_io_s0box(cs);
202 break;
203 case CARD_INIT:
204 spin_lock_irqsave(&cs->lock, flags);
205 inithscxisac(cs, 3);
206 spin_unlock_irqrestore(&cs->lock, flags);
207 break;
208 case CARD_TEST:
209 break;
210 }
211 return(0);
212}
213
214int __init
215setup_s0box(struct IsdnCard *card)
216{
217 struct IsdnCardState *cs = card->cs;
218 char tmp[64];
219
220 strcpy(tmp, s0box_revision);
221 printk(KERN_INFO "HiSax: S0Box IO driver Rev. %s\n", HiSax_getrev(tmp));
222 if (cs->typ != ISDN_CTYPE_S0BOX)
223 return (0);
224
225 cs->hw.teles3.cfg_reg = card->para[1];
226 cs->hw.teles3.hscx[0] = -0x20;
227 cs->hw.teles3.hscx[1] = 0x0;
228 cs->hw.teles3.isac = 0x20;
229 cs->hw.teles3.isacfifo = cs->hw.teles3.isac + 0x3e;
230 cs->hw.teles3.hscxfifo[0] = cs->hw.teles3.hscx[0] + 0x3e;
231 cs->hw.teles3.hscxfifo[1] = cs->hw.teles3.hscx[1] + 0x3e;
232 cs->irq = card->para[0];
233 if (!request_region(cs->hw.teles3.cfg_reg,8, "S0Box parallel I/O")) {
234 printk(KERN_WARNING
235 "HiSax: %s ports %x-%x already in use\n",
236 CardType[cs->typ],
237 cs->hw.teles3.cfg_reg,
238 cs->hw.teles3.cfg_reg + 7);
239 return 0;
240 }
241 printk(KERN_INFO
242 "HiSax: %s config irq:%d isac:0x%x cfg:0x%x\n",
243 CardType[cs->typ], cs->irq,
244 cs->hw.teles3.isac, cs->hw.teles3.cfg_reg);
245 printk(KERN_INFO
246 "HiSax: hscx A:0x%x hscx B:0x%x\n",
247 cs->hw.teles3.hscx[0], cs->hw.teles3.hscx[1]);
248 setup_isac(cs);
249 cs->readisac = &ReadISAC;
250 cs->writeisac = &WriteISAC;
251 cs->readisacfifo = &ReadISACfifo;
252 cs->writeisacfifo = &WriteISACfifo;
253 cs->BC_Read_Reg = &ReadHSCX;
254 cs->BC_Write_Reg = &WriteHSCX;
255 cs->BC_Send_Data = &hscx_fill_fifo;
256 cs->cardmsg = &S0Box_card_msg;
257 cs->irq_func = &s0box_interrupt;
258 ISACVersion(cs, "S0Box:");
259 if (HscxVersion(cs, "S0Box:")) {
260 printk(KERN_WARNING
261 "S0Box: wrong HSCX versions check IO address\n");
262 release_io_s0box(cs);
263 return (0);
264 }
265 return (1);
266}
diff --git a/drivers/isdn/hisax/saphir.c b/drivers/isdn/hisax/saphir.c
new file mode 100644
index 000000000000..9e6d3d686cce
--- /dev/null
+++ b/drivers/isdn/hisax/saphir.c
@@ -0,0 +1,300 @@
1/* $Id: saphir.c,v 1.10.2.4 2004/01/13 23:48:39 keil Exp $
2 *
3 * low level stuff for HST Saphir 1
4 *
5 * Author Karsten Keil
6 * Copyright by Karsten Keil <keil@isdn4linux.de>
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 * Thanks to HST High Soft Tech GmbH
12 *
13 */
14
15#include <linux/init.h>
16#include "hisax.h"
17#include "isac.h"
18#include "hscx.h"
19#include "isdnl1.h"
20
21extern const char *CardType[];
22static char *saphir_rev = "$Revision: 1.10.2.4 $";
23
24#define byteout(addr,val) outb(val,addr)
25#define bytein(addr) inb(addr)
26
27#define ISAC_DATA 0
28#define HSCX_DATA 1
29#define ADDRESS_REG 2
30#define IRQ_REG 3
31#define SPARE_REG 4
32#define RESET_REG 5
33
34static inline u_char
35readreg(unsigned int ale, unsigned int adr, u_char off)
36{
37 register u_char ret;
38
39 byteout(ale, off);
40 ret = bytein(adr);
41 return (ret);
42}
43
44static inline void
45readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
46{
47 byteout(ale, off);
48 insb(adr, data, size);
49}
50
51
52static inline void
53writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
54{
55 byteout(ale, off);
56 byteout(adr, data);
57}
58
59static inline void
60writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
61{
62 byteout(ale, off);
63 outsb(adr, data, size);
64}
65
66/* Interface functions */
67
68static u_char
69ReadISAC(struct IsdnCardState *cs, u_char offset)
70{
71 return (readreg(cs->hw.saphir.ale, cs->hw.saphir.isac, offset));
72}
73
74static void
75WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
76{
77 writereg(cs->hw.saphir.ale, cs->hw.saphir.isac, offset, value);
78}
79
80static void
81ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
82{
83 readfifo(cs->hw.saphir.ale, cs->hw.saphir.isac, 0, data, size);
84}
85
86static void
87WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
88{
89 writefifo(cs->hw.saphir.ale, cs->hw.saphir.isac, 0, data, size);
90}
91
92static u_char
93ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
94{
95 return (readreg(cs->hw.saphir.ale, cs->hw.saphir.hscx,
96 offset + (hscx ? 0x40 : 0)));
97}
98
99static void
100WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
101{
102 writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx,
103 offset + (hscx ? 0x40 : 0), value);
104}
105
106#define READHSCX(cs, nr, reg) readreg(cs->hw.saphir.ale, \
107 cs->hw.saphir.hscx, reg + (nr ? 0x40 : 0))
108#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.saphir.ale, \
109 cs->hw.saphir.hscx, reg + (nr ? 0x40 : 0), data)
110
111#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.saphir.ale, \
112 cs->hw.saphir.hscx, (nr ? 0x40 : 0), ptr, cnt)
113
114#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.saphir.ale, \
115 cs->hw.saphir.hscx, (nr ? 0x40 : 0), ptr, cnt)
116
117#include "hscx_irq.c"
118
119static irqreturn_t
120saphir_interrupt(int intno, void *dev_id, struct pt_regs *regs)
121{
122 struct IsdnCardState *cs = dev_id;
123 u_char val;
124 u_long flags;
125
126 spin_lock_irqsave(&cs->lock, flags);
127 val = readreg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_ISTA + 0x40);
128 Start_HSCX:
129 if (val)
130 hscx_int_main(cs, val);
131 val = readreg(cs->hw.saphir.ale, cs->hw.saphir.isac, ISAC_ISTA);
132 Start_ISAC:
133 if (val)
134 isac_interrupt(cs, val);
135 val = readreg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_ISTA + 0x40);
136 if (val) {
137 if (cs->debug & L1_DEB_HSCX)
138 debugl1(cs, "HSCX IntStat after IntRoutine");
139 goto Start_HSCX;
140 }
141 val = readreg(cs->hw.saphir.ale, cs->hw.saphir.isac, ISAC_ISTA);
142 if (val) {
143 if (cs->debug & L1_DEB_ISAC)
144 debugl1(cs, "ISAC IntStat after IntRoutine");
145 goto Start_ISAC;
146 }
147 /* Watchdog */
148 if (cs->hw.saphir.timer.function)
149 mod_timer(&cs->hw.saphir.timer, jiffies+1*HZ);
150 else
151 printk(KERN_WARNING "saphir: Spurious timer!\n");
152 writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_MASK, 0xFF);
153 writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_MASK + 0x40, 0xFF);
154 writereg(cs->hw.saphir.ale, cs->hw.saphir.isac, ISAC_MASK, 0xFF);
155 writereg(cs->hw.saphir.ale, cs->hw.saphir.isac, ISAC_MASK, 0);
156 writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_MASK, 0);
157 writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_MASK + 0x40, 0);
158 spin_unlock_irqrestore(&cs->lock, flags);
159 return IRQ_HANDLED;
160}
161
162static void
163SaphirWatchDog(struct IsdnCardState *cs)
164{
165 u_long flags;
166
167 spin_lock_irqsave(&cs->lock, flags);
168 /* 5 sec WatchDog, so read at least every 4 sec */
169 cs->readisac(cs, ISAC_RBCH);
170 spin_unlock_irqrestore(&cs->lock, flags);
171 mod_timer(&cs->hw.saphir.timer, jiffies+1*HZ);
172}
173
174void
175release_io_saphir(struct IsdnCardState *cs)
176{
177 byteout(cs->hw.saphir.cfg_reg + IRQ_REG, 0xff);
178 del_timer(&cs->hw.saphir.timer);
179 cs->hw.saphir.timer.function = NULL;
180 if (cs->hw.saphir.cfg_reg)
181 release_region(cs->hw.saphir.cfg_reg, 6);
182}
183
184static int
185saphir_reset(struct IsdnCardState *cs)
186{
187 u_char irq_val;
188
189 switch(cs->irq) {
190 case 5: irq_val = 0;
191 break;
192 case 3: irq_val = 1;
193 break;
194 case 11:
195 irq_val = 2;
196 break;
197 case 12:
198 irq_val = 3;
199 break;
200 case 15:
201 irq_val = 4;
202 break;
203 default:
204 printk(KERN_WARNING "HiSax: saphir wrong IRQ %d\n",
205 cs->irq);
206 return (1);
207 }
208 byteout(cs->hw.saphir.cfg_reg + IRQ_REG, irq_val);
209 byteout(cs->hw.saphir.cfg_reg + RESET_REG, 1);
210 mdelay(10);
211 byteout(cs->hw.saphir.cfg_reg + RESET_REG, 0);
212 mdelay(10);
213 byteout(cs->hw.saphir.cfg_reg + IRQ_REG, irq_val);
214 byteout(cs->hw.saphir.cfg_reg + SPARE_REG, 0x02);
215 return (0);
216}
217
218static int
219saphir_card_msg(struct IsdnCardState *cs, int mt, void *arg)
220{
221 u_long flags;
222
223 switch (mt) {
224 case CARD_RESET:
225 spin_lock_irqsave(&cs->lock, flags);
226 saphir_reset(cs);
227 spin_unlock_irqrestore(&cs->lock, flags);
228 return(0);
229 case CARD_RELEASE:
230 release_io_saphir(cs);
231 return(0);
232 case CARD_INIT:
233 spin_lock_irqsave(&cs->lock, flags);
234 inithscxisac(cs, 3);
235 spin_unlock_irqrestore(&cs->lock, flags);
236 return(0);
237 case CARD_TEST:
238 return(0);
239 }
240 return(0);
241}
242
243
244int __init
245setup_saphir(struct IsdnCard *card)
246{
247 struct IsdnCardState *cs = card->cs;
248 char tmp[64];
249
250 strcpy(tmp, saphir_rev);
251 printk(KERN_INFO "HiSax: HST Saphir driver Rev. %s\n", HiSax_getrev(tmp));
252 if (cs->typ != ISDN_CTYPE_HSTSAPHIR)
253 return (0);
254
255 /* IO-Ports */
256 cs->hw.saphir.cfg_reg = card->para[1];
257 cs->hw.saphir.isac = card->para[1] + ISAC_DATA;
258 cs->hw.saphir.hscx = card->para[1] + HSCX_DATA;
259 cs->hw.saphir.ale = card->para[1] + ADDRESS_REG;
260 cs->irq = card->para[0];
261 if (!request_region(cs->hw.saphir.cfg_reg, 6, "saphir")) {
262 printk(KERN_WARNING
263 "HiSax: %s config port %x-%x already in use\n",
264 CardType[card->typ],
265 cs->hw.saphir.cfg_reg,
266 cs->hw.saphir.cfg_reg + 5);
267 return (0);
268 }
269
270 printk(KERN_INFO "HiSax: %s config irq:%d io:0x%X\n",
271 CardType[cs->typ], cs->irq, cs->hw.saphir.cfg_reg);
272
273 setup_isac(cs);
274 cs->hw.saphir.timer.function = (void *) SaphirWatchDog;
275 cs->hw.saphir.timer.data = (long) cs;
276 init_timer(&cs->hw.saphir.timer);
277 cs->hw.saphir.timer.expires = jiffies + 4*HZ;
278 add_timer(&cs->hw.saphir.timer);
279 if (saphir_reset(cs)) {
280 release_io_saphir(cs);
281 return (0);
282 }
283 cs->readisac = &ReadISAC;
284 cs->writeisac = &WriteISAC;
285 cs->readisacfifo = &ReadISACfifo;
286 cs->writeisacfifo = &WriteISACfifo;
287 cs->BC_Read_Reg = &ReadHSCX;
288 cs->BC_Write_Reg = &WriteHSCX;
289 cs->BC_Send_Data = &hscx_fill_fifo;
290 cs->cardmsg = &saphir_card_msg;
291 cs->irq_func = &saphir_interrupt;
292 ISACVersion(cs, "saphir:");
293 if (HscxVersion(cs, "saphir:")) {
294 printk(KERN_WARNING
295 "saphir: wrong HSCX versions check IO address\n");
296 release_io_saphir(cs);
297 return (0);
298 }
299 return (1);
300}
diff --git a/drivers/isdn/hisax/sedlbauer.c b/drivers/isdn/hisax/sedlbauer.c
new file mode 100644
index 000000000000..8390f1606853
--- /dev/null
+++ b/drivers/isdn/hisax/sedlbauer.c
@@ -0,0 +1,833 @@
1/* $Id: sedlbauer.c,v 1.34.2.6 2004/01/24 20:47:24 keil Exp $
2 *
3 * low level stuff for Sedlbauer cards
4 * includes support for the Sedlbauer speed star (speed star II),
5 * support for the Sedlbauer speed fax+,
6 * support for the Sedlbauer ISDN-Controller PC/104 and
7 * support for the Sedlbauer speed pci
8 * derived from the original file asuscom.c from Karsten Keil
9 *
10 * Author Marcus Niemann
11 * Copyright by Marcus Niemann <niemann@www-bib.fh-bielefeld.de>
12 *
13 * This software may be used and distributed according to the terms
14 * of the GNU General Public License, incorporated herein by reference.
15 *
16 * Thanks to Karsten Keil
17 * Sedlbauer AG for informations
18 * Edgar Toernig
19 *
20 */
21
22/* Supported cards:
23 * Card: Chip: Configuration: Comment:
24 * ---------------------------------------------------------------------
25 * Speed Card ISAC_HSCX DIP-SWITCH
26 * Speed Win ISAC_HSCX ISAPNP
27 * Speed Fax+ ISAC_ISAR ISAPNP Full analog support
28 * Speed Star ISAC_HSCX CARDMGR
29 * Speed Win2 IPAC ISAPNP
30 * ISDN PC/104 IPAC DIP-SWITCH
31 * Speed Star2 IPAC CARDMGR
32 * Speed PCI IPAC PCI PNP
33 * Speed Fax+ ISAC_ISAR PCI PNP Full analog support
34 *
35 * Important:
36 * For the sedlbauer speed fax+ to work properly you have to download
37 * the firmware onto the card.
38 * For example: hisaxctrl <DriverID> 9 ISAR.BIN
39*/
40
41#include <linux/init.h>
42#include <linux/config.h>
43#include "hisax.h"
44#include "isac.h"
45#include "ipac.h"
46#include "hscx.h"
47#include "isar.h"
48#include "isdnl1.h"
49#include <linux/pci.h>
50#include <linux/isapnp.h>
51
52extern const char *CardType[];
53
54const char *Sedlbauer_revision = "$Revision: 1.34.2.6 $";
55
56const char *Sedlbauer_Types[] =
57 {"None", "speed card/win", "speed star", "speed fax+",
58 "speed win II / ISDN PC/104", "speed star II", "speed pci",
59 "speed fax+ pyramid", "speed fax+ pci", "HST Saphir III"};
60
61#define PCI_SUBVENDOR_SPEEDFAX_PYRAMID 0x51
62#define PCI_SUBVENDOR_HST_SAPHIR3 0x52
63#define PCI_SUBVENDOR_SEDLBAUER_PCI 0x53
64#define PCI_SUBVENDOR_SPEEDFAX_PCI 0x54
65#define PCI_SUB_ID_SEDLBAUER 0x01
66
67#define SEDL_SPEED_CARD_WIN 1
68#define SEDL_SPEED_STAR 2
69#define SEDL_SPEED_FAX 3
70#define SEDL_SPEED_WIN2_PC104 4
71#define SEDL_SPEED_STAR2 5
72#define SEDL_SPEED_PCI 6
73#define SEDL_SPEEDFAX_PYRAMID 7
74#define SEDL_SPEEDFAX_PCI 8
75#define HST_SAPHIR3 9
76
77#define SEDL_CHIP_TEST 0
78#define SEDL_CHIP_ISAC_HSCX 1
79#define SEDL_CHIP_ISAC_ISAR 2
80#define SEDL_CHIP_IPAC 3
81
82#define SEDL_BUS_ISA 1
83#define SEDL_BUS_PCI 2
84#define SEDL_BUS_PCMCIA 3
85
86#define byteout(addr,val) outb(val,addr)
87#define bytein(addr) inb(addr)
88
89#define SEDL_HSCX_ISA_RESET_ON 0
90#define SEDL_HSCX_ISA_RESET_OFF 1
91#define SEDL_HSCX_ISA_ISAC 2
92#define SEDL_HSCX_ISA_HSCX 3
93#define SEDL_HSCX_ISA_ADR 4
94
95#define SEDL_HSCX_PCMCIA_RESET 0
96#define SEDL_HSCX_PCMCIA_ISAC 1
97#define SEDL_HSCX_PCMCIA_HSCX 2
98#define SEDL_HSCX_PCMCIA_ADR 4
99
100#define SEDL_ISAR_ISA_ISAC 4
101#define SEDL_ISAR_ISA_ISAR 6
102#define SEDL_ISAR_ISA_ADR 8
103#define SEDL_ISAR_ISA_ISAR_RESET_ON 10
104#define SEDL_ISAR_ISA_ISAR_RESET_OFF 12
105
106#define SEDL_IPAC_ANY_ADR 0
107#define SEDL_IPAC_ANY_IPAC 2
108
109#define SEDL_IPAC_PCI_BASE 0
110#define SEDL_IPAC_PCI_ADR 0xc0
111#define SEDL_IPAC_PCI_IPAC 0xc8
112#define SEDL_ISAR_PCI_ADR 0xc8
113#define SEDL_ISAR_PCI_ISAC 0xd0
114#define SEDL_ISAR_PCI_ISAR 0xe0
115#define SEDL_ISAR_PCI_ISAR_RESET_ON 0x01
116#define SEDL_ISAR_PCI_ISAR_RESET_OFF 0x18
117#define SEDL_ISAR_PCI_LED1 0x08
118#define SEDL_ISAR_PCI_LED2 0x10
119
120#define SEDL_RESET 0x3 /* same as DOS driver */
121
122static inline u_char
123readreg(unsigned int ale, unsigned int adr, u_char off)
124{
125 register u_char ret;
126
127 byteout(ale, off);
128 ret = bytein(adr);
129 return (ret);
130}
131
132static inline void
133readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
134{
135 byteout(ale, off);
136 insb(adr, data, size);
137}
138
139
140static inline void
141writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
142{
143 byteout(ale, off);
144 byteout(adr, data);
145}
146
147static inline void
148writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
149{
150 byteout(ale, off);
151 outsb(adr, data, size);
152}
153
154/* Interface functions */
155
156static u_char
157ReadISAC(struct IsdnCardState *cs, u_char offset)
158{
159 return (readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, offset));
160}
161
162static void
163WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
164{
165 writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, offset, value);
166}
167
168static void
169ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
170{
171 readfifo(cs->hw.sedl.adr, cs->hw.sedl.isac, 0, data, size);
172}
173
174static void
175WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
176{
177 writefifo(cs->hw.sedl.adr, cs->hw.sedl.isac, 0, data, size);
178}
179
180static u_char
181ReadISAC_IPAC(struct IsdnCardState *cs, u_char offset)
182{
183 return (readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, offset|0x80));
184}
185
186static void
187WriteISAC_IPAC(struct IsdnCardState *cs, u_char offset, u_char value)
188{
189 writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, offset|0x80, value);
190}
191
192static void
193ReadISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size)
194{
195 readfifo(cs->hw.sedl.adr, cs->hw.sedl.isac, 0x80, data, size);
196}
197
198static void
199WriteISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size)
200{
201 writefifo(cs->hw.sedl.adr, cs->hw.sedl.isac, 0x80, data, size);
202}
203
204static u_char
205ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
206{
207 return (readreg(cs->hw.sedl.adr,
208 cs->hw.sedl.hscx, offset + (hscx ? 0x40 : 0)));
209}
210
211static void
212WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
213{
214 writereg(cs->hw.sedl.adr,
215 cs->hw.sedl.hscx, offset + (hscx ? 0x40 : 0), value);
216}
217
218/* ISAR access routines
219 * mode = 0 access with IRQ on
220 * mode = 1 access with IRQ off
221 * mode = 2 access with IRQ off and using last offset
222 */
223
224static u_char
225ReadISAR(struct IsdnCardState *cs, int mode, u_char offset)
226{
227 if (mode == 0)
228 return (readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, offset));
229 else if (mode == 1)
230 byteout(cs->hw.sedl.adr, offset);
231 return(bytein(cs->hw.sedl.hscx));
232}
233
234static void
235WriteISAR(struct IsdnCardState *cs, int mode, u_char offset, u_char value)
236{
237 if (mode == 0)
238 writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, offset, value);
239 else {
240 if (mode == 1)
241 byteout(cs->hw.sedl.adr, offset);
242 byteout(cs->hw.sedl.hscx, value);
243 }
244}
245
246/*
247 * fast interrupt HSCX stuff goes here
248 */
249
250#define READHSCX(cs, nr, reg) readreg(cs->hw.sedl.adr, \
251 cs->hw.sedl.hscx, reg + (nr ? 0x40 : 0))
252#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.sedl.adr, \
253 cs->hw.sedl.hscx, reg + (nr ? 0x40 : 0), data)
254
255#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.sedl.adr, \
256 cs->hw.sedl.hscx, (nr ? 0x40 : 0), ptr, cnt)
257
258#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.sedl.adr, \
259 cs->hw.sedl.hscx, (nr ? 0x40 : 0), ptr, cnt)
260
261#include "hscx_irq.c"
262
263static irqreturn_t
264sedlbauer_interrupt(int intno, void *dev_id, struct pt_regs *regs)
265{
266 struct IsdnCardState *cs = dev_id;
267 u_char val;
268 u_long flags;
269
270 spin_lock_irqsave(&cs->lock, flags);
271 if ((cs->hw.sedl.bus == SEDL_BUS_PCMCIA) && (*cs->busy_flag == 1)) {
272 /* The card tends to generate interrupts while being removed
273 causing us to just crash the kernel. bad. */
274 spin_unlock_irqrestore(&cs->lock, flags);
275 printk(KERN_WARNING "Sedlbauer: card not available!\n");
276 return IRQ_NONE;
277 }
278
279 val = readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_ISTA + 0x40);
280 Start_HSCX:
281 if (val)
282 hscx_int_main(cs, val);
283 val = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_ISTA);
284 Start_ISAC:
285 if (val)
286 isac_interrupt(cs, val);
287 val = readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_ISTA + 0x40);
288 if (val) {
289 if (cs->debug & L1_DEB_HSCX)
290 debugl1(cs, "HSCX IntStat after IntRoutine");
291 goto Start_HSCX;
292 }
293 val = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_ISTA);
294 if (val) {
295 if (cs->debug & L1_DEB_ISAC)
296 debugl1(cs, "ISAC IntStat after IntRoutine");
297 goto Start_ISAC;
298 }
299 writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_MASK, 0xFF);
300 writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_MASK + 0x40, 0xFF);
301 writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_MASK, 0xFF);
302 writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_MASK, 0x0);
303 writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_MASK, 0x0);
304 writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_MASK + 0x40, 0x0);
305 spin_unlock_irqrestore(&cs->lock, flags);
306 return IRQ_HANDLED;
307}
308
309static irqreturn_t
310sedlbauer_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs)
311{
312 struct IsdnCardState *cs = dev_id;
313 u_char ista, val, icnt = 5;
314 u_long flags;
315
316 spin_lock_irqsave(&cs->lock, flags);
317 ista = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_ISTA);
318Start_IPAC:
319 if (cs->debug & L1_DEB_IPAC)
320 debugl1(cs, "IPAC ISTA %02X", ista);
321 if (ista & 0x0f) {
322 val = readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_ISTA + 0x40);
323 if (ista & 0x01)
324 val |= 0x01;
325 if (ista & 0x04)
326 val |= 0x02;
327 if (ista & 0x08)
328 val |= 0x04;
329 if (val)
330 hscx_int_main(cs, val);
331 }
332 if (ista & 0x20) {
333 val = 0xfe & readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_ISTA | 0x80);
334 if (val) {
335 isac_interrupt(cs, val);
336 }
337 }
338 if (ista & 0x10) {
339 val = 0x01;
340 isac_interrupt(cs, val);
341 }
342 ista = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_ISTA);
343 if ((ista & 0x3f) && icnt) {
344 icnt--;
345 goto Start_IPAC;
346 }
347 if (!icnt)
348 if (cs->debug & L1_DEB_ISAC)
349 debugl1(cs, "Sedlbauer IRQ LOOP");
350 writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_MASK, 0xFF);
351 writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_MASK, 0xC0);
352 spin_unlock_irqrestore(&cs->lock, flags);
353 return IRQ_HANDLED;
354}
355
356static irqreturn_t
357sedlbauer_interrupt_isar(int intno, void *dev_id, struct pt_regs *regs)
358{
359 struct IsdnCardState *cs = dev_id;
360 u_char val;
361 int cnt = 5;
362 u_long flags;
363
364 spin_lock_irqsave(&cs->lock, flags);
365 val = readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, ISAR_IRQBIT);
366 Start_ISAR:
367 if (val & ISAR_IRQSTA)
368 isar_int_main(cs);
369 val = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_ISTA);
370 Start_ISAC:
371 if (val)
372 isac_interrupt(cs, val);
373 val = readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, ISAR_IRQBIT);
374 if ((val & ISAR_IRQSTA) && --cnt) {
375 if (cs->debug & L1_DEB_HSCX)
376 debugl1(cs, "ISAR IntStat after IntRoutine");
377 goto Start_ISAR;
378 }
379 val = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_ISTA);
380 if (val && --cnt) {
381 if (cs->debug & L1_DEB_ISAC)
382 debugl1(cs, "ISAC IntStat after IntRoutine");
383 goto Start_ISAC;
384 }
385 if (!cnt)
386 if (cs->debug & L1_DEB_ISAC)
387 debugl1(cs, "Sedlbauer IRQ LOOP");
388
389 writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, ISAR_IRQBIT, 0);
390 writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_MASK, 0xFF);
391 writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_MASK, 0x0);
392 writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, ISAR_IRQBIT, ISAR_IRQMSK);
393 spin_unlock_irqrestore(&cs->lock, flags);
394 return IRQ_HANDLED;
395}
396
397void
398release_io_sedlbauer(struct IsdnCardState *cs)
399{
400 int bytecnt = 8;
401
402 if (cs->subtyp == SEDL_SPEED_FAX) {
403 bytecnt = 16;
404 } else if (cs->hw.sedl.bus == SEDL_BUS_PCI) {
405 bytecnt = 256;
406 }
407 if (cs->hw.sedl.cfg_reg)
408 release_region(cs->hw.sedl.cfg_reg, bytecnt);
409}
410
411static void
412reset_sedlbauer(struct IsdnCardState *cs)
413{
414 printk(KERN_INFO "Sedlbauer: resetting card\n");
415
416 if (!((cs->hw.sedl.bus == SEDL_BUS_PCMCIA) &&
417 (cs->hw.sedl.chip == SEDL_CHIP_ISAC_HSCX))) {
418 if (cs->hw.sedl.chip == SEDL_CHIP_IPAC) {
419 writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_POTA2, 0x20);
420 mdelay(2);
421 writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_POTA2, 0x0);
422 mdelay(10);
423 writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_CONF, 0x0);
424 writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_ACFG, 0xff);
425 writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_AOE, 0x0);
426 writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_MASK, 0xc0);
427 writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_PCFG, 0x12);
428 } else if ((cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) &&
429 (cs->hw.sedl.bus == SEDL_BUS_PCI)) {
430 byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_on);
431 mdelay(2);
432 byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off);
433 mdelay(10);
434 } else {
435 byteout(cs->hw.sedl.reset_on, SEDL_RESET); /* Reset On */
436 mdelay(2);
437 byteout(cs->hw.sedl.reset_off, 0); /* Reset Off */
438 mdelay(10);
439 }
440 }
441}
442
443static int
444Sedl_card_msg(struct IsdnCardState *cs, int mt, void *arg)
445{
446 u_long flags;
447
448 switch (mt) {
449 case CARD_RESET:
450 spin_lock_irqsave(&cs->lock, flags);
451 reset_sedlbauer(cs);
452 spin_unlock_irqrestore(&cs->lock, flags);
453 return(0);
454 case CARD_RELEASE:
455 if (cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) {
456 spin_lock_irqsave(&cs->lock, flags);
457 writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx,
458 ISAR_IRQBIT, 0);
459 writereg(cs->hw.sedl.adr, cs->hw.sedl.isac,
460 ISAC_MASK, 0xFF);
461 reset_sedlbauer(cs);
462 writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx,
463 ISAR_IRQBIT, 0);
464 writereg(cs->hw.sedl.adr, cs->hw.sedl.isac,
465 ISAC_MASK, 0xFF);
466 spin_unlock_irqrestore(&cs->lock, flags);
467 }
468 release_io_sedlbauer(cs);
469 return(0);
470 case CARD_INIT:
471 spin_lock_irqsave(&cs->lock, flags);
472 reset_sedlbauer(cs);
473 if (cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) {
474 clear_pending_isac_ints(cs);
475 writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx,
476 ISAR_IRQBIT, 0);
477 initisac(cs);
478 initisar(cs);
479 /* Reenable all IRQ */
480 cs->writeisac(cs, ISAC_MASK, 0);
481 /* RESET Receiver and Transmitter */
482 cs->writeisac(cs, ISAC_CMDR, 0x41);
483 } else {
484 inithscxisac(cs, 3);
485 }
486 spin_unlock_irqrestore(&cs->lock, flags);
487 return(0);
488 case CARD_TEST:
489 return(0);
490 case MDL_INFO_CONN:
491 if (cs->subtyp != SEDL_SPEEDFAX_PYRAMID)
492 return(0);
493 spin_lock_irqsave(&cs->lock, flags);
494 if ((long) arg)
495 cs->hw.sedl.reset_off &= ~SEDL_ISAR_PCI_LED2;
496 else
497 cs->hw.sedl.reset_off &= ~SEDL_ISAR_PCI_LED1;
498 byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off);
499 spin_unlock_irqrestore(&cs->lock, flags);
500 break;
501 case MDL_INFO_REL:
502 if (cs->subtyp != SEDL_SPEEDFAX_PYRAMID)
503 return(0);
504 spin_lock_irqsave(&cs->lock, flags);
505 if ((long) arg)
506 cs->hw.sedl.reset_off |= SEDL_ISAR_PCI_LED2;
507 else
508 cs->hw.sedl.reset_off |= SEDL_ISAR_PCI_LED1;
509 byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off);
510 spin_unlock_irqrestore(&cs->lock, flags);
511 break;
512 }
513 return(0);
514}
515
516static struct pci_dev *dev_sedl __devinitdata = NULL;
517
518#ifdef __ISAPNP__
519static struct isapnp_device_id sedl_ids[] __devinitdata = {
520 { ISAPNP_VENDOR('S', 'A', 'G'), ISAPNP_FUNCTION(0x01),
521 ISAPNP_VENDOR('S', 'A', 'G'), ISAPNP_FUNCTION(0x01),
522 (unsigned long) "Speed win" },
523 { ISAPNP_VENDOR('S', 'A', 'G'), ISAPNP_FUNCTION(0x02),
524 ISAPNP_VENDOR('S', 'A', 'G'), ISAPNP_FUNCTION(0x02),
525 (unsigned long) "Speed Fax+" },
526 { 0, }
527};
528
529static struct isapnp_device_id *ipid __devinitdata = &sedl_ids[0];
530static struct pnp_card *pnp_c __devinitdata = NULL;
531#endif
532
533int __devinit
534setup_sedlbauer(struct IsdnCard *card)
535{
536 int bytecnt, ver, val;
537 struct IsdnCardState *cs = card->cs;
538 char tmp[64];
539 u16 sub_vendor_id, sub_id;
540
541 strcpy(tmp, Sedlbauer_revision);
542 printk(KERN_INFO "HiSax: Sedlbauer driver Rev. %s\n", HiSax_getrev(tmp));
543
544 if (cs->typ == ISDN_CTYPE_SEDLBAUER) {
545 cs->subtyp = SEDL_SPEED_CARD_WIN;
546 cs->hw.sedl.bus = SEDL_BUS_ISA;
547 cs->hw.sedl.chip = SEDL_CHIP_TEST;
548 } else if (cs->typ == ISDN_CTYPE_SEDLBAUER_PCMCIA) {
549 cs->subtyp = SEDL_SPEED_STAR;
550 cs->hw.sedl.bus = SEDL_BUS_PCMCIA;
551 cs->hw.sedl.chip = SEDL_CHIP_TEST;
552 } else if (cs->typ == ISDN_CTYPE_SEDLBAUER_FAX) {
553 cs->subtyp = SEDL_SPEED_FAX;
554 cs->hw.sedl.bus = SEDL_BUS_ISA;
555 cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
556 } else
557 return (0);
558
559 bytecnt = 8;
560 if (card->para[1]) {
561 cs->hw.sedl.cfg_reg = card->para[1];
562 cs->irq = card->para[0];
563 if (cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) {
564 bytecnt = 16;
565 }
566 } else {
567#ifdef __ISAPNP__
568 if (isapnp_present()) {
569 struct pnp_dev *pnp_d;
570 while(ipid->card_vendor) {
571 if ((pnp_c = pnp_find_card(ipid->card_vendor,
572 ipid->card_device, pnp_c))) {
573 pnp_d = NULL;
574 if ((pnp_d = pnp_find_dev(pnp_c,
575 ipid->vendor, ipid->function, pnp_d))) {
576 int err;
577
578 printk(KERN_INFO "HiSax: %s detected\n",
579 (char *)ipid->driver_data);
580 pnp_disable_dev(pnp_d);
581 err = pnp_activate_dev(pnp_d);
582 if (err<0) {
583 printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
584 __FUNCTION__, err);
585 return(0);
586 }
587 card->para[1] = pnp_port_start(pnp_d, 0);
588 card->para[0] = pnp_irq(pnp_d, 0);
589
590 if (!card->para[0] || !card->para[1]) {
591 printk(KERN_ERR "Sedlbauer PnP:some resources are missing %ld/%lx\n",
592 card->para[0], card->para[1]);
593 pnp_disable_dev(pnp_d);
594 return(0);
595 }
596 cs->hw.sedl.cfg_reg = card->para[1];
597 cs->irq = card->para[0];
598 if (ipid->function == ISAPNP_FUNCTION(0x2)) {
599 cs->subtyp = SEDL_SPEED_FAX;
600 cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
601 bytecnt = 16;
602 } else {
603 cs->subtyp = SEDL_SPEED_CARD_WIN;
604 cs->hw.sedl.chip = SEDL_CHIP_TEST;
605 }
606 goto ready;
607 } else {
608 printk(KERN_ERR "Sedlbauer PnP: PnP error card found, no device\n");
609 return(0);
610 }
611 }
612 ipid++;
613 pnp_c = NULL;
614 }
615 if (!ipid->card_vendor) {
616 printk(KERN_INFO "Sedlbauer PnP: no ISAPnP card found\n");
617 }
618 }
619#endif
620/* Probe for Sedlbauer speed pci */
621#ifdef CONFIG_PCI
622 if ((dev_sedl = pci_find_device(PCI_VENDOR_ID_TIGERJET,
623 PCI_DEVICE_ID_TIGERJET_100, dev_sedl))) {
624 if (pci_enable_device(dev_sedl))
625 return(0);
626 cs->irq = dev_sedl->irq;
627 if (!cs->irq) {
628 printk(KERN_WARNING "Sedlbauer: No IRQ for PCI card found\n");
629 return(0);
630 }
631 cs->hw.sedl.cfg_reg = pci_resource_start(dev_sedl, 0);
632 } else {
633 printk(KERN_WARNING "Sedlbauer: No PCI card found\n");
634 return(0);
635 }
636 cs->irq_flags |= SA_SHIRQ;
637 cs->hw.sedl.bus = SEDL_BUS_PCI;
638 sub_vendor_id = dev_sedl->subsystem_vendor;
639 sub_id = dev_sedl->subsystem_device;
640 printk(KERN_INFO "Sedlbauer: PCI subvendor:%x subid %x\n",
641 sub_vendor_id, sub_id);
642 printk(KERN_INFO "Sedlbauer: PCI base adr %#x\n",
643 cs->hw.sedl.cfg_reg);
644 if (sub_id != PCI_SUB_ID_SEDLBAUER) {
645 printk(KERN_ERR "Sedlbauer: unknown sub id %#x\n", sub_id);
646 return(0);
647 }
648 if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PYRAMID) {
649 cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
650 cs->subtyp = SEDL_SPEEDFAX_PYRAMID;
651 } else if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PCI) {
652 cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
653 cs->subtyp = SEDL_SPEEDFAX_PCI;
654 } else if (sub_vendor_id == PCI_SUBVENDOR_HST_SAPHIR3) {
655 cs->hw.sedl.chip = SEDL_CHIP_IPAC;
656 cs->subtyp = HST_SAPHIR3;
657 } else if (sub_vendor_id == PCI_SUBVENDOR_SEDLBAUER_PCI) {
658 cs->hw.sedl.chip = SEDL_CHIP_IPAC;
659 cs->subtyp = SEDL_SPEED_PCI;
660 } else {
661 printk(KERN_ERR "Sedlbauer: unknown sub vendor id %#x\n",
662 sub_vendor_id);
663 return(0);
664 }
665 bytecnt = 256;
666 cs->hw.sedl.reset_on = SEDL_ISAR_PCI_ISAR_RESET_ON;
667 cs->hw.sedl.reset_off = SEDL_ISAR_PCI_ISAR_RESET_OFF;
668 byteout(cs->hw.sedl.cfg_reg, 0xff);
669 byteout(cs->hw.sedl.cfg_reg, 0x00);
670 byteout(cs->hw.sedl.cfg_reg+ 2, 0xdd);
671 byteout(cs->hw.sedl.cfg_reg+ 5, 0x02);
672 byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_on);
673 mdelay(2);
674 byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off);
675 mdelay(10);
676#else
677 printk(KERN_WARNING "Sedlbauer: NO_PCI_BIOS\n");
678 return (0);
679#endif /* CONFIG_PCI */
680 }
681ready:
682 /* In case of the sedlbauer pcmcia card, this region is in use,
683 * reserved for us by the card manager. So we do not check it
684 * here, it would fail.
685 */
686 if (cs->hw.sedl.bus != SEDL_BUS_PCMCIA &&
687 !request_region(cs->hw.sedl.cfg_reg, bytecnt, "sedlbauer isdn")) {
688 printk(KERN_WARNING
689 "HiSax: %s config port %x-%x already in use\n",
690 CardType[card->typ],
691 cs->hw.sedl.cfg_reg,
692 cs->hw.sedl.cfg_reg + bytecnt);
693 return (0);
694 }
695
696 printk(KERN_INFO
697 "Sedlbauer: defined at 0x%x-0x%x IRQ %d\n",
698 cs->hw.sedl.cfg_reg,
699 cs->hw.sedl.cfg_reg + bytecnt,
700 cs->irq);
701
702 cs->BC_Read_Reg = &ReadHSCX;
703 cs->BC_Write_Reg = &WriteHSCX;
704 cs->BC_Send_Data = &hscx_fill_fifo;
705 cs->cardmsg = &Sedl_card_msg;
706
707/*
708 * testing ISA and PCMCIA Cards for IPAC, default is ISAC
709 * do not test for PCI card, because ports are different
710 * and PCI card uses only IPAC (for the moment)
711 */
712 if (cs->hw.sedl.bus != SEDL_BUS_PCI) {
713 val = readreg(cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_ADR,
714 cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_IPAC, IPAC_ID);
715 printk(KERN_DEBUG "Sedlbauer: testing IPAC version %x\n", val);
716 if ((val == 1) || (val == 2)) {
717 /* IPAC */
718 cs->subtyp = SEDL_SPEED_WIN2_PC104;
719 if (cs->hw.sedl.bus == SEDL_BUS_PCMCIA) {
720 cs->subtyp = SEDL_SPEED_STAR2;
721 }
722 cs->hw.sedl.chip = SEDL_CHIP_IPAC;
723 } else {
724 /* ISAC_HSCX oder ISAC_ISAR */
725 if (cs->hw.sedl.chip == SEDL_CHIP_TEST) {
726 cs->hw.sedl.chip = SEDL_CHIP_ISAC_HSCX;
727 }
728 }
729 }
730
731/*
732 * hw.sedl.chip is now properly set
733 */
734 printk(KERN_INFO "Sedlbauer: %s detected\n",
735 Sedlbauer_Types[cs->subtyp]);
736
737 setup_isac(cs);
738 if (cs->hw.sedl.chip == SEDL_CHIP_IPAC) {
739 if (cs->hw.sedl.bus == SEDL_BUS_PCI) {
740 cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_IPAC_PCI_ADR;
741 cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_IPAC_PCI_IPAC;
742 cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_IPAC_PCI_IPAC;
743 } else {
744 cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_ADR;
745 cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_IPAC;
746 cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_IPAC;
747 }
748 test_and_set_bit(HW_IPAC, &cs->HW_Flags);
749 cs->readisac = &ReadISAC_IPAC;
750 cs->writeisac = &WriteISAC_IPAC;
751 cs->readisacfifo = &ReadISACfifo_IPAC;
752 cs->writeisacfifo = &WriteISACfifo_IPAC;
753 cs->irq_func = &sedlbauer_interrupt_ipac;
754 val = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_ID);
755 printk(KERN_INFO "Sedlbauer: IPAC version %x\n", val);
756 } else {
757 /* ISAC_HSCX oder ISAC_ISAR */
758 cs->readisac = &ReadISAC;
759 cs->writeisac = &WriteISAC;
760 cs->readisacfifo = &ReadISACfifo;
761 cs->writeisacfifo = &WriteISACfifo;
762 if (cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) {
763 if (cs->hw.sedl.bus == SEDL_BUS_PCI) {
764 cs->hw.sedl.adr = cs->hw.sedl.cfg_reg +
765 SEDL_ISAR_PCI_ADR;
766 cs->hw.sedl.isac = cs->hw.sedl.cfg_reg +
767 SEDL_ISAR_PCI_ISAC;
768 cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg +
769 SEDL_ISAR_PCI_ISAR;
770 } else {
771 cs->hw.sedl.adr = cs->hw.sedl.cfg_reg +
772 SEDL_ISAR_ISA_ADR;
773 cs->hw.sedl.isac = cs->hw.sedl.cfg_reg +
774 SEDL_ISAR_ISA_ISAC;
775 cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg +
776 SEDL_ISAR_ISA_ISAR;
777 cs->hw.sedl.reset_on = cs->hw.sedl.cfg_reg +
778 SEDL_ISAR_ISA_ISAR_RESET_ON;
779 cs->hw.sedl.reset_off = cs->hw.sedl.cfg_reg +
780 SEDL_ISAR_ISA_ISAR_RESET_OFF;
781 }
782 cs->bcs[0].hw.isar.reg = &cs->hw.sedl.isar;
783 cs->bcs[1].hw.isar.reg = &cs->hw.sedl.isar;
784 test_and_set_bit(HW_ISAR, &cs->HW_Flags);
785 cs->irq_func = &sedlbauer_interrupt_isar;
786 cs->auxcmd = &isar_auxcmd;
787 ISACVersion(cs, "Sedlbauer:");
788 cs->BC_Read_Reg = &ReadISAR;
789 cs->BC_Write_Reg = &WriteISAR;
790 cs->BC_Send_Data = &isar_fill_fifo;
791 bytecnt = 3;
792 while (bytecnt) {
793 ver = ISARVersion(cs, "Sedlbauer:");
794 if (ver < 0)
795 printk(KERN_WARNING
796 "Sedlbauer: wrong ISAR version (ret = %d)\n", ver);
797 else
798 break;
799 reset_sedlbauer(cs);
800 bytecnt--;
801 }
802 if (!bytecnt) {
803 release_io_sedlbauer(cs);
804 return (0);
805 }
806 } else {
807 if (cs->hw.sedl.bus == SEDL_BUS_PCMCIA) {
808 cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_ADR;
809 cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_ISAC;
810 cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_HSCX;
811 cs->hw.sedl.reset_on = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_RESET;
812 cs->hw.sedl.reset_off = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_RESET;
813 cs->irq_flags |= SA_SHIRQ;
814 } else {
815 cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_ADR;
816 cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_ISAC;
817 cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_HSCX;
818 cs->hw.sedl.reset_on = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_RESET_ON;
819 cs->hw.sedl.reset_off = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_RESET_OFF;
820 }
821 cs->irq_func = &sedlbauer_interrupt;
822 ISACVersion(cs, "Sedlbauer:");
823
824 if (HscxVersion(cs, "Sedlbauer:")) {
825 printk(KERN_WARNING
826 "Sedlbauer: wrong HSCX versions check IO address\n");
827 release_io_sedlbauer(cs);
828 return (0);
829 }
830 }
831 }
832 return (1);
833}
diff --git a/drivers/isdn/hisax/sedlbauer_cs.c b/drivers/isdn/hisax/sedlbauer_cs.c
new file mode 100644
index 000000000000..449651241477
--- /dev/null
+++ b/drivers/isdn/hisax/sedlbauer_cs.c
@@ -0,0 +1,640 @@
1/*======================================================================
2
3 A Sedlbauer PCMCIA client driver
4
5 This driver is for the Sedlbauer Speed Star and Speed Star II,
6 which are ISDN PCMCIA Cards.
7
8 The contents of this file are subject to the Mozilla Public
9 License Version 1.1 (the "License"); you may not use this file
10 except in compliance with the License. You may obtain a copy of
11 the License at http://www.mozilla.org/MPL/
12
13 Software distributed under the License is distributed on an "AS
14 IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
15 implied. See the License for the specific language governing
16 rights and limitations under the License.
17
18 The initial developer of the original code is David A. Hinds
19 <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
20 are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
21
22 Modifications from dummy_cs.c are Copyright (C) 1999-2001 Marcus Niemann
23 <maniemann@users.sourceforge.net>. All Rights Reserved.
24
25 Alternatively, the contents of this file may be used under the
26 terms of the GNU General Public License version 2 (the "GPL"), in
27 which case the provisions of the GPL are applicable instead of the
28 above. If you wish to allow the use of your version of this file
29 only under the terms of the GPL and not to allow others to use
30 your version of this file under the MPL, indicate your decision
31 by deleting the provisions above and replace them with the notice
32 and other provisions required by the GPL. If you do not delete
33 the provisions above, a recipient may use your version of this
34 file under either the MPL or the GPL.
35
36======================================================================*/
37
38#include <linux/kernel.h>
39#include <linux/module.h>
40#include <linux/init.h>
41#include <linux/sched.h>
42#include <linux/ptrace.h>
43#include <linux/slab.h>
44#include <linux/string.h>
45#include <linux/timer.h>
46#include <linux/ioport.h>
47#include <asm/io.h>
48#include <asm/system.h>
49
50#include <pcmcia/version.h>
51#include <pcmcia/cs_types.h>
52#include <pcmcia/cs.h>
53#include <pcmcia/cistpl.h>
54#include <pcmcia/cisreg.h>
55#include <pcmcia/ds.h>
56#include "hisax_cfg.h"
57
58MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for Sedlbauer cards");
59MODULE_AUTHOR("Marcus Niemann");
60MODULE_LICENSE("Dual MPL/GPL");
61
62/*
63 All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If
64 you do not define PCMCIA_DEBUG at all, all the debug code will be
65 left out. If you compile with PCMCIA_DEBUG=0, the debug code will
66 be present but disabled -- but it can then be enabled for specific
67 modules at load time with a 'pc_debug=#' option to insmod.
68*/
69
70#ifdef PCMCIA_DEBUG
71static int pc_debug = PCMCIA_DEBUG;
72module_param(pc_debug, int, 0);
73#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args);
74static char *version =
75"sedlbauer_cs.c 1.1a 2001/01/28 15:04:04 (M.Niemann)";
76#else
77#define DEBUG(n, args...)
78#endif
79
80
81/*====================================================================*/
82
83/* Parameters that can be set with 'insmod' */
84
85static int protocol = 2; /* EURO-ISDN Default */
86module_param(protocol, int, 0);
87
88/*====================================================================*/
89
90/*
91 The event() function is this driver's Card Services event handler.
92 It will be called by Card Services when an appropriate card status
93 event is received. The config() and release() entry points are
94 used to configure or release a socket, in response to card
95 insertion and ejection events. They are invoked from the sedlbauer
96 event handler.
97*/
98
99static void sedlbauer_config(dev_link_t *link);
100static void sedlbauer_release(dev_link_t *link);
101static int sedlbauer_event(event_t event, int priority,
102 event_callback_args_t *args);
103
104/*
105 The attach() and detach() entry points are used to create and destroy
106 "instances" of the driver, where each instance represents everything
107 needed to manage one actual PCMCIA card.
108*/
109
110static dev_link_t *sedlbauer_attach(void);
111static void sedlbauer_detach(dev_link_t *);
112
113/*
114 You'll also need to prototype all the functions that will actually
115 be used to talk to your device. See 'memory_cs' for a good example
116 of a fully self-sufficient driver; the other drivers rely more or
117 less on other parts of the kernel.
118*/
119
120/*
121 The dev_info variable is the "key" that is used to match up this
122 device driver with appropriate cards, through the card configuration
123 database.
124*/
125
126static dev_info_t dev_info = "sedlbauer_cs";
127
128/*
129 A linked list of "instances" of the sedlbauer device. Each actual
130 PCMCIA card corresponds to one device instance, and is described
131 by one dev_link_t structure (defined in ds.h).
132
133 You may not want to use a linked list for this -- for example, the
134 memory card driver uses an array of dev_link_t pointers, where minor
135 device numbers are used to derive the corresponding array index.
136*/
137
138static dev_link_t *dev_list = NULL;
139
140/*
141 A dev_link_t structure has fields for most things that are needed
142 to keep track of a socket, but there will usually be some device
143 specific information that also needs to be kept track of. The
144 'priv' pointer in a dev_link_t structure can be used to point to
145 a device-specific private data structure, like this.
146
147 To simplify the data structure handling, we actually include the
148 dev_link_t structure in the device's private data structure.
149
150 A driver needs to provide a dev_node_t structure for each device
151 on a card. In some cases, there is only one device per card (for
152 example, ethernet cards, modems). In other cases, there may be
153 many actual or logical devices (SCSI adapters, memory cards with
154 multiple partitions). The dev_node_t structures need to be kept
155 in a linked list starting at the 'dev' field of a dev_link_t
156 structure. We allocate them in the card's private data structure,
157 because they generally shouldn't be allocated dynamically.
158
159 In this case, we also provide a flag to indicate if a device is
160 "stopped" due to a power management event, or card ejection. The
161 device IO routines can use a flag like this to throttle IO to a
162 card that is not ready to accept it.
163*/
164
165typedef struct local_info_t {
166 dev_link_t link;
167 dev_node_t node;
168 int stop;
169 int cardnr;
170} local_info_t;
171
172/*======================================================================
173
174 sedlbauer_attach() creates an "instance" of the driver, allocating
175 local data structures for one device. The device is registered
176 with Card Services.
177
178 The dev_link structure is initialized, but we don't actually
179 configure the card at this point -- we wait until we receive a
180 card insertion event.
181
182======================================================================*/
183
184static dev_link_t *sedlbauer_attach(void)
185{
186 local_info_t *local;
187 dev_link_t *link;
188 client_reg_t client_reg;
189 int ret;
190
191 DEBUG(0, "sedlbauer_attach()\n");
192
193 /* Allocate space for private device-specific data */
194 local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
195 if (!local) return NULL;
196 memset(local, 0, sizeof(local_info_t));
197 local->cardnr = -1;
198 link = &local->link; link->priv = local;
199
200 /* Interrupt setup */
201 link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
202 link->irq.IRQInfo1 = IRQ_LEVEL_ID;
203 link->irq.Handler = NULL;
204
205 /*
206 General socket configuration defaults can go here. In this
207 client, we assume very little, and rely on the CIS for almost
208 everything. In most clients, many details (i.e., number, sizes,
209 and attributes of IO windows) are fixed by the nature of the
210 device, and can be hard-wired here.
211 */
212
213 /* from old sedl_cs
214 */
215 /* The io structure describes IO port mapping */
216 link->io.NumPorts1 = 8;
217 link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
218 link->io.IOAddrLines = 3;
219
220
221 link->conf.Attributes = 0;
222 link->conf.Vcc = 50;
223 link->conf.IntType = INT_MEMORY_AND_IO;
224
225 /* Register with Card Services */
226 link->next = dev_list;
227 dev_list = link;
228 client_reg.dev_info = &dev_info;
229 client_reg.EventMask =
230 CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
231 CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
232 CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
233 client_reg.event_handler = &sedlbauer_event;
234 client_reg.Version = 0x0210;
235 client_reg.event_callback_args.client_data = link;
236 ret = pcmcia_register_client(&link->handle, &client_reg);
237 if (ret != CS_SUCCESS) {
238 cs_error(link->handle, RegisterClient, ret);
239 sedlbauer_detach(link);
240 return NULL;
241 }
242
243 return link;
244} /* sedlbauer_attach */
245
246/*======================================================================
247
248 This deletes a driver "instance". The device is de-registered
249 with Card Services. If it has been released, all local data
250 structures are freed. Otherwise, the structures will be freed
251 when the device is released.
252
253======================================================================*/
254
255static void sedlbauer_detach(dev_link_t *link)
256{
257 dev_link_t **linkp;
258
259 DEBUG(0, "sedlbauer_detach(0x%p)\n", link);
260
261 /* Locate device structure */
262 for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
263 if (*linkp == link) break;
264 if (*linkp == NULL)
265 return;
266
267 /*
268 If the device is currently configured and active, we won't
269 actually delete it yet. Instead, it is marked so that when
270 the release() function is called, that will trigger a proper
271 detach().
272 */
273 if (link->state & DEV_CONFIG) {
274#ifdef PCMCIA_DEBUG
275 printk(KERN_DEBUG "sedlbauer_cs: detach postponed, '%s' "
276 "still locked\n", link->dev->dev_name);
277#endif
278 link->state |= DEV_STALE_LINK;
279 return;
280 }
281
282 /* Break the link with Card Services */
283 if (link->handle)
284 pcmcia_deregister_client(link->handle);
285
286 /* Unlink device structure, and free it */
287 *linkp = link->next;
288 /* This points to the parent local_info_t struct */
289 kfree(link->priv);
290} /* sedlbauer_detach */
291
292/*======================================================================
293
294 sedlbauer_config() is scheduled to run after a CARD_INSERTION event
295 is received, to configure the PCMCIA socket, and to make the
296 device available to the system.
297
298======================================================================*/
299#define CS_CHECK(fn, ret) \
300do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
301
302static void sedlbauer_config(dev_link_t *link)
303{
304 client_handle_t handle = link->handle;
305 local_info_t *dev = link->priv;
306 tuple_t tuple;
307 cisparse_t parse;
308 int last_fn, last_ret;
309 u8 buf[64];
310 config_info_t conf;
311 win_req_t req;
312 memreq_t map;
313 IsdnCard_t icard;
314
315 DEBUG(0, "sedlbauer_config(0x%p)\n", link);
316
317 /*
318 This reads the card's CONFIG tuple to find its configuration
319 registers.
320 */
321 tuple.DesiredTuple = CISTPL_CONFIG;
322 tuple.Attributes = 0;
323 tuple.TupleData = buf;
324 tuple.TupleDataMax = sizeof(buf);
325 tuple.TupleOffset = 0;
326 CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
327 CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
328 CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
329 link->conf.ConfigBase = parse.config.base;
330 link->conf.Present = parse.config.rmask[0];
331
332 /* Configure card */
333 link->state |= DEV_CONFIG;
334
335 /* Look up the current Vcc */
336 CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(handle, &conf));
337 link->conf.Vcc = conf.Vcc;
338
339 /*
340 In this loop, we scan the CIS for configuration table entries,
341 each of which describes a valid card configuration, including
342 voltage, IO window, memory window, and interrupt settings.
343
344 We make no assumptions about the card to be configured: we use
345 just the information available in the CIS. In an ideal world,
346 this would work for any PCMCIA card, but it requires a complete
347 and accurate CIS. In practice, a driver usually "knows" most of
348 these things without consulting the CIS, and most client drivers
349 will only use the CIS to fill in implementation-defined details.
350 */
351 tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
352 CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
353 while (1) {
354 cistpl_cftable_entry_t dflt = { 0 };
355 cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
356 if (pcmcia_get_tuple_data(handle, &tuple) != 0 ||
357 pcmcia_parse_tuple(handle, &tuple, &parse) != 0)
358 goto next_entry;
359
360 if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg;
361 if (cfg->index == 0) goto next_entry;
362 link->conf.ConfigIndex = cfg->index;
363
364 /* Does this card need audio output? */
365 if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
366 link->conf.Attributes |= CONF_ENABLE_SPKR;
367 link->conf.Status = CCSR_AUDIO_ENA;
368 }
369
370 /* Use power settings for Vcc and Vpp if present */
371 /* Note that the CIS values need to be rescaled */
372 if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) {
373 if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM]/10000)
374 goto next_entry;
375 } else if (dflt.vcc.present & (1<<CISTPL_POWER_VNOM)) {
376 if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM]/10000)
377 goto next_entry;
378 }
379
380 if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM))
381 link->conf.Vpp1 = link->conf.Vpp2 =
382 cfg->vpp1.param[CISTPL_POWER_VNOM]/10000;
383 else if (dflt.vpp1.present & (1<<CISTPL_POWER_VNOM))
384 link->conf.Vpp1 = link->conf.Vpp2 =
385 dflt.vpp1.param[CISTPL_POWER_VNOM]/10000;
386
387 /* Do we need to allocate an interrupt? */
388 if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1)
389 link->conf.Attributes |= CONF_ENABLE_IRQ;
390
391 /* IO window settings */
392 link->io.NumPorts1 = link->io.NumPorts2 = 0;
393 if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
394 cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
395 link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
396 if (!(io->flags & CISTPL_IO_8BIT))
397 link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
398 if (!(io->flags & CISTPL_IO_16BIT))
399 link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
400/* new in dummy.cs 2001/01/28 MN
401 link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
402*/
403 link->io.BasePort1 = io->win[0].base;
404 link->io.NumPorts1 = io->win[0].len;
405 if (io->nwin > 1) {
406 link->io.Attributes2 = link->io.Attributes1;
407 link->io.BasePort2 = io->win[1].base;
408 link->io.NumPorts2 = io->win[1].len;
409 }
410 /* This reserves IO space but doesn't actually enable it */
411 if (pcmcia_request_io(link->handle, &link->io) != 0)
412 goto next_entry;
413 }
414
415 /*
416 Now set up a common memory window, if needed. There is room
417 in the dev_link_t structure for one memory window handle,
418 but if the base addresses need to be saved, or if multiple
419 windows are needed, the info should go in the private data
420 structure for this device.
421
422 Note that the memory window base is a physical address, and
423 needs to be mapped to virtual space with ioremap() before it
424 is used.
425 */
426 if ((cfg->mem.nwin > 0) || (dflt.mem.nwin > 0)) {
427 cistpl_mem_t *mem =
428 (cfg->mem.nwin) ? &cfg->mem : &dflt.mem;
429 req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM;
430 req.Attributes |= WIN_ENABLE;
431 req.Base = mem->win[0].host_addr;
432 req.Size = mem->win[0].len;
433/* new in dummy.cs 2001/01/28 MN
434 if (req.Size < 0x1000)
435 req.Size = 0x1000;
436*/
437 req.AccessSpeed = 0;
438 if (pcmcia_request_window(&link->handle, &req, &link->win) != 0)
439 goto next_entry;
440 map.Page = 0; map.CardOffset = mem->win[0].card_addr;
441 if (pcmcia_map_mem_page(link->win, &map) != 0)
442 goto next_entry;
443 }
444 /* If we got this far, we're cool! */
445 break;
446
447 next_entry:
448/* new in dummy.cs 2001/01/28 MN
449 if (link->io.NumPorts1)
450 pcmcia_release_io(link->handle, &link->io);
451*/
452 CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple));
453 }
454
455 /*
456 Allocate an interrupt line. Note that this does not assign a
457 handler to the interrupt, unless the 'Handler' member of the
458 irq structure is initialized.
459 */
460 if (link->conf.Attributes & CONF_ENABLE_IRQ)
461 CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq));
462
463 /*
464 This actually configures the PCMCIA socket -- setting up
465 the I/O windows and the interrupt mapping, and putting the
466 card and host interface into "Memory and IO" mode.
467 */
468 CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf));
469
470 /*
471 At this point, the dev_node_t structure(s) need to be
472 initialized and arranged in a linked list at link->dev.
473 */
474 sprintf(dev->node.dev_name, "sedlbauer");
475 dev->node.major = dev->node.minor = 0;
476 link->dev = &dev->node;
477
478 /* Finally, report what we've done */
479 printk(KERN_INFO "%s: index 0x%02x: Vcc %d.%d",
480 dev->node.dev_name, link->conf.ConfigIndex,
481 link->conf.Vcc/10, link->conf.Vcc%10);
482 if (link->conf.Vpp1)
483 printk(", Vpp %d.%d", link->conf.Vpp1/10, link->conf.Vpp1%10);
484 if (link->conf.Attributes & CONF_ENABLE_IRQ)
485 printk(", irq %d", link->irq.AssignedIRQ);
486 if (link->io.NumPorts1)
487 printk(", io 0x%04x-0x%04x", link->io.BasePort1,
488 link->io.BasePort1+link->io.NumPorts1-1);
489 if (link->io.NumPorts2)
490 printk(" & 0x%04x-0x%04x", link->io.BasePort2,
491 link->io.BasePort2+link->io.NumPorts2-1);
492 if (link->win)
493 printk(", mem 0x%06lx-0x%06lx", req.Base,
494 req.Base+req.Size-1);
495 printk("\n");
496
497 link->state &= ~DEV_CONFIG_PENDING;
498
499 icard.para[0] = link->irq.AssignedIRQ;
500 icard.para[1] = link->io.BasePort1;
501 icard.protocol = protocol;
502 icard.typ = ISDN_CTYPE_SEDLBAUER_PCMCIA;
503
504 last_ret = hisax_init_pcmcia(link, &(((local_info_t*)link->priv)->stop), &icard);
505 if (last_ret < 0) {
506 printk(KERN_ERR "sedlbauer_cs: failed to initialize SEDLBAUER PCMCIA %d at i/o %#x\n",
507 last_ret, link->io.BasePort1);
508 sedlbauer_release(link);
509 } else
510 ((local_info_t*)link->priv)->cardnr = last_ret;
511
512 return;
513
514cs_failed:
515 cs_error(link->handle, last_fn, last_ret);
516 sedlbauer_release(link);
517
518} /* sedlbauer_config */
519
520/*======================================================================
521
522 After a card is removed, sedlbauer_release() will unregister the
523 device, and release the PCMCIA configuration. If the device is
524 still open, this will be postponed until it is closed.
525
526======================================================================*/
527
528static void sedlbauer_release(dev_link_t *link)
529{
530 local_info_t *local = link->priv;
531 DEBUG(0, "sedlbauer_release(0x%p)\n", link);
532
533 if (local) {
534 if (local->cardnr >= 0) {
535 /* no unregister function with hisax */
536 HiSax_closecard(local->cardnr);
537 }
538 }
539 /* Unlink the device chain */
540 link->dev = NULL;
541
542 /*
543 In a normal driver, additional code may be needed to release
544 other kernel data structures associated with this device.
545 */
546
547 /* Don't bother checking to see if these succeed or not */
548 if (link->win)
549 pcmcia_release_window(link->win);
550 pcmcia_release_configuration(link->handle);
551 if (link->io.NumPorts1)
552 pcmcia_release_io(link->handle, &link->io);
553 if (link->irq.AssignedIRQ)
554 pcmcia_release_irq(link->handle, &link->irq);
555 link->state &= ~DEV_CONFIG;
556
557 if (link->state & DEV_STALE_LINK)
558 sedlbauer_detach(link);
559
560} /* sedlbauer_release */
561
562/*======================================================================
563
564 The card status event handler. Mostly, this schedules other
565 stuff to run after an event is received.
566
567 When a CARD_REMOVAL event is received, we immediately set a
568 private flag to block future accesses to this device. All the
569 functions that actually access the device should check this flag
570 to make sure the card is still present.
571
572======================================================================*/
573
574static int sedlbauer_event(event_t event, int priority,
575 event_callback_args_t *args)
576{
577 dev_link_t *link = args->client_data;
578 local_info_t *dev = link->priv;
579
580 DEBUG(1, "sedlbauer_event(0x%06x)\n", event);
581
582 switch (event) {
583 case CS_EVENT_CARD_REMOVAL:
584 link->state &= ~DEV_PRESENT;
585 if (link->state & DEV_CONFIG) {
586 ((local_info_t *)link->priv)->stop = 1;
587 sedlbauer_release(link);
588 }
589 break;
590 case CS_EVENT_CARD_INSERTION:
591 link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
592 sedlbauer_config(link);
593 break;
594 case CS_EVENT_PM_SUSPEND:
595 link->state |= DEV_SUSPEND;
596 /* Fall through... */
597 case CS_EVENT_RESET_PHYSICAL:
598 /* Mark the device as stopped, to block IO until later */
599 dev->stop = 1;
600 if (link->state & DEV_CONFIG)
601 pcmcia_release_configuration(link->handle);
602 break;
603 case CS_EVENT_PM_RESUME:
604 link->state &= ~DEV_SUSPEND;
605 /* Fall through... */
606 case CS_EVENT_CARD_RESET:
607 if (link->state & DEV_CONFIG)
608 pcmcia_request_configuration(link->handle, &link->conf);
609 dev->stop = 0;
610 /*
611 In a normal driver, additional code may go here to restore
612 the device state and restart IO.
613 */
614 break;
615 }
616 return 0;
617} /* sedlbauer_event */
618
619static struct pcmcia_driver sedlbauer_driver = {
620 .owner = THIS_MODULE,
621 .drv = {
622 .name = "sedlbauer_cs",
623 },
624 .attach = sedlbauer_attach,
625 .detach = sedlbauer_detach,
626};
627
628static int __init init_sedlbauer_cs(void)
629{
630 return pcmcia_register_driver(&sedlbauer_driver);
631}
632
633static void __exit exit_sedlbauer_cs(void)
634{
635 pcmcia_unregister_driver(&sedlbauer_driver);
636 BUG_ON(dev_list != NULL);
637}
638
639module_init(init_sedlbauer_cs);
640module_exit(exit_sedlbauer_cs);
diff --git a/drivers/isdn/hisax/sportster.c b/drivers/isdn/hisax/sportster.c
new file mode 100644
index 000000000000..132840b750ce
--- /dev/null
+++ b/drivers/isdn/hisax/sportster.c
@@ -0,0 +1,270 @@
1/* $Id: sportster.c,v 1.16.2.4 2004/01/13 23:48:39 keil Exp $
2 *
3 * low level stuff for USR Sportster internal TA
4 *
5 * Author Karsten Keil
6 * Copyright by Karsten Keil <keil@isdn4linux.de>
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 * Thanks to Christian "naddy" Weisgerber (3Com, US Robotics) for documentation
12 *
13 *
14 */
15#include <linux/init.h>
16#include "hisax.h"
17#include "isac.h"
18#include "hscx.h"
19#include "isdnl1.h"
20
21extern const char *CardType[];
22const char *sportster_revision = "$Revision: 1.16.2.4 $";
23
24#define byteout(addr,val) outb(val,addr)
25#define bytein(addr) inb(addr)
26
27#define SPORTSTER_ISAC 0xC000
28#define SPORTSTER_HSCXA 0x0000
29#define SPORTSTER_HSCXB 0x4000
30#define SPORTSTER_RES_IRQ 0x8000
31#define SPORTSTER_RESET 0x80
32#define SPORTSTER_INTE 0x40
33
34static inline int
35calc_off(unsigned int base, unsigned int off)
36{
37 return(base + ((off & 0xfc)<<8) + ((off & 3)<<1));
38}
39
40static inline void
41read_fifo(unsigned int adr, u_char * data, int size)
42{
43 insb(adr, data, size);
44}
45
46static void
47write_fifo(unsigned int adr, u_char * data, int size)
48{
49 outsb(adr, data, size);
50}
51
52/* Interface functions */
53
54static u_char
55ReadISAC(struct IsdnCardState *cs, u_char offset)
56{
57 return (bytein(calc_off(cs->hw.spt.isac, offset)));
58}
59
60static void
61WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
62{
63 byteout(calc_off(cs->hw.spt.isac, offset), value);
64}
65
66static void
67ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
68{
69 read_fifo(cs->hw.spt.isac, data, size);
70}
71
72static void
73WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
74{
75 write_fifo(cs->hw.spt.isac, data, size);
76}
77
78static u_char
79ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
80{
81 return (bytein(calc_off(cs->hw.spt.hscx[hscx], offset)));
82}
83
84static void
85WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
86{
87 byteout(calc_off(cs->hw.spt.hscx[hscx], offset), value);
88}
89
90/*
91 * fast interrupt HSCX stuff goes here
92 */
93
94#define READHSCX(cs, nr, reg) bytein(calc_off(cs->hw.spt.hscx[nr], reg))
95#define WRITEHSCX(cs, nr, reg, data) byteout(calc_off(cs->hw.spt.hscx[nr], reg), data)
96#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo(cs->hw.spt.hscx[nr], ptr, cnt)
97#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo(cs->hw.spt.hscx[nr], ptr, cnt)
98
99#include "hscx_irq.c"
100
101static irqreturn_t
102sportster_interrupt(int intno, void *dev_id, struct pt_regs *regs)
103{
104 struct IsdnCardState *cs = dev_id;
105 u_char val;
106 u_long flags;
107
108 spin_lock_irqsave(&cs->lock, flags);
109 val = READHSCX(cs, 1, HSCX_ISTA);
110 Start_HSCX:
111 if (val)
112 hscx_int_main(cs, val);
113 val = ReadISAC(cs, ISAC_ISTA);
114 Start_ISAC:
115 if (val)
116 isac_interrupt(cs, val);
117 val = READHSCX(cs, 1, HSCX_ISTA);
118 if (val) {
119 if (cs->debug & L1_DEB_HSCX)
120 debugl1(cs, "HSCX IntStat after IntRoutine");
121 goto Start_HSCX;
122 }
123 val = ReadISAC(cs, ISAC_ISTA);
124 if (val) {
125 if (cs->debug & L1_DEB_ISAC)
126 debugl1(cs, "ISAC IntStat after IntRoutine");
127 goto Start_ISAC;
128 }
129 /* get a new irq impulse if there any pending */
130 bytein(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ +1);
131 spin_unlock_irqrestore(&cs->lock, flags);
132 return IRQ_HANDLED;
133}
134
135void
136release_io_sportster(struct IsdnCardState *cs)
137{
138 int i, adr;
139
140 byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, 0);
141 for (i=0; i<64; i++) {
142 adr = cs->hw.spt.cfg_reg + i *1024;
143 release_region(adr, 8);
144 }
145}
146
147void
148reset_sportster(struct IsdnCardState *cs)
149{
150 cs->hw.spt.res_irq |= SPORTSTER_RESET; /* Reset On */
151 byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, cs->hw.spt.res_irq);
152 mdelay(10);
153 cs->hw.spt.res_irq &= ~SPORTSTER_RESET; /* Reset Off */
154 byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, cs->hw.spt.res_irq);
155 mdelay(10);
156}
157
158static int
159Sportster_card_msg(struct IsdnCardState *cs, int mt, void *arg)
160{
161 u_long flags;
162
163 switch (mt) {
164 case CARD_RESET:
165 spin_lock_irqsave(&cs->lock, flags);
166 reset_sportster(cs);
167 spin_unlock_irqrestore(&cs->lock, flags);
168 return(0);
169 case CARD_RELEASE:
170 release_io_sportster(cs);
171 return(0);
172 case CARD_INIT:
173 spin_lock_irqsave(&cs->lock, flags);
174 reset_sportster(cs);
175 inithscxisac(cs, 1);
176 cs->hw.spt.res_irq |= SPORTSTER_INTE; /* IRQ On */
177 byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, cs->hw.spt.res_irq);
178 inithscxisac(cs, 2);
179 spin_unlock_irqrestore(&cs->lock, flags);
180 return(0);
181 case CARD_TEST:
182 return(0);
183 }
184 return(0);
185}
186
187static int __init
188get_io_range(struct IsdnCardState *cs)
189{
190 int i, j, adr;
191
192 for (i=0;i<64;i++) {
193 adr = cs->hw.spt.cfg_reg + i *1024;
194 if (!request_region(adr, 8, "sportster")) {
195 printk(KERN_WARNING
196 "HiSax: %s config port %x-%x already in use\n",
197 CardType[cs->typ], adr, adr + 8);
198 break;
199 }
200 }
201 if (i==64)
202 return(1);
203 else {
204 for (j=0; j<i; j++) {
205 adr = cs->hw.spt.cfg_reg + j *1024;
206 release_region(adr, 8);
207 }
208 return(0);
209 }
210}
211
212int __init
213setup_sportster(struct IsdnCard *card)
214{
215 struct IsdnCardState *cs = card->cs;
216 char tmp[64];
217
218 strcpy(tmp, sportster_revision);
219 printk(KERN_INFO "HiSax: USR Sportster driver Rev. %s\n", HiSax_getrev(tmp));
220 if (cs->typ != ISDN_CTYPE_SPORTSTER)
221 return (0);
222
223 cs->hw.spt.cfg_reg = card->para[1];
224 cs->irq = card->para[0];
225 if (!get_io_range(cs))
226 return (0);
227 cs->hw.spt.isac = cs->hw.spt.cfg_reg + SPORTSTER_ISAC;
228 cs->hw.spt.hscx[0] = cs->hw.spt.cfg_reg + SPORTSTER_HSCXA;
229 cs->hw.spt.hscx[1] = cs->hw.spt.cfg_reg + SPORTSTER_HSCXB;
230
231 switch(cs->irq) {
232 case 5: cs->hw.spt.res_irq = 1;
233 break;
234 case 7: cs->hw.spt.res_irq = 2;
235 break;
236 case 10:cs->hw.spt.res_irq = 3;
237 break;
238 case 11:cs->hw.spt.res_irq = 4;
239 break;
240 case 12:cs->hw.spt.res_irq = 5;
241 break;
242 case 14:cs->hw.spt.res_irq = 6;
243 break;
244 case 15:cs->hw.spt.res_irq = 7;
245 break;
246 default:release_io_sportster(cs);
247 printk(KERN_WARNING "Sportster: wrong IRQ\n");
248 return(0);
249 }
250 printk(KERN_INFO "HiSax: %s config irq:%d cfg:0x%X\n",
251 CardType[cs->typ], cs->irq, cs->hw.spt.cfg_reg);
252 setup_isac(cs);
253 cs->readisac = &ReadISAC;
254 cs->writeisac = &WriteISAC;
255 cs->readisacfifo = &ReadISACfifo;
256 cs->writeisacfifo = &WriteISACfifo;
257 cs->BC_Read_Reg = &ReadHSCX;
258 cs->BC_Write_Reg = &WriteHSCX;
259 cs->BC_Send_Data = &hscx_fill_fifo;
260 cs->cardmsg = &Sportster_card_msg;
261 cs->irq_func = &sportster_interrupt;
262 ISACVersion(cs, "Sportster:");
263 if (HscxVersion(cs, "Sportster:")) {
264 printk(KERN_WARNING
265 "Sportster: wrong HSCX versions check IO address\n");
266 release_io_sportster(cs);
267 return (0);
268 }
269 return (1);
270}
diff --git a/drivers/isdn/hisax/st5481.h b/drivers/isdn/hisax/st5481.h
new file mode 100644
index 000000000000..e8177b017b1d
--- /dev/null
+++ b/drivers/isdn/hisax/st5481.h
@@ -0,0 +1,535 @@
1/*
2 * Driver for ST5481 USB ISDN modem
3 *
4 * Author Frode Isaksen
5 * Copyright 2001 by Frode Isaksen <fisaksen@bewan.com>
6 * 2001 by Kai Germaschewski <kai.germaschewski@gmx.de>
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 */
12
13#ifndef _ST5481_H_
14#define _ST5481_H_
15
16#include <linux/config.h>
17
18// USB IDs, the Product Id is in the range 0x4810-0x481F
19
20#define ST_VENDOR_ID 0x0483
21#define ST5481_PRODUCT_ID 0x4810
22#define ST5481_PRODUCT_ID_MASK 0xFFF0
23
24// ST5481 endpoints when using alternative setting 3 (2B+D).
25// To get the endpoint address, OR with 0x80 for IN endpoints.
26
27#define EP_CTRL 0x00U /* Control endpoint */
28#define EP_INT 0x01U /* Interrupt endpoint */
29#define EP_B1_OUT 0x02U /* B1 channel out */
30#define EP_B1_IN 0x03U /* B1 channel in */
31#define EP_B2_OUT 0x04U /* B2 channel out */
32#define EP_B2_IN 0x05U /* B2 channel in */
33#define EP_D_OUT 0x06U /* D channel out */
34#define EP_D_IN 0x07U /* D channel in */
35
36// Number of isochronous packets. With 20 packets we get
37// 50 interrupts/sec for each endpoint.
38
39#define NUM_ISO_PACKETS_D 20
40#define NUM_ISO_PACKETS_B 20
41
42// Size of each isochronous packet.
43// In outgoing direction we need to match ISDN data rates:
44// D: 2 bytes / msec -> 16 kbit / s
45// B: 16 bytes / msec -> 64 kbit / s
46#define SIZE_ISO_PACKETS_D_IN 16
47#define SIZE_ISO_PACKETS_D_OUT 2
48#define SIZE_ISO_PACKETS_B_IN 32
49#define SIZE_ISO_PACKETS_B_OUT 8
50
51// If we overrun/underrun, we send one packet with +/- 2 bytes
52#define B_FLOW_ADJUST 2
53
54// Registers that are written using vendor specific device request
55// on endpoint 0.
56
57#define LBA 0x02 /* S loopback */
58#define SET_DEFAULT 0x06 /* Soft reset */
59#define LBB 0x1D /* S maintenance loopback */
60#define STT 0x1e /* S force transmission signals */
61#define SDA_MIN 0x20 /* SDA-sin minimal value */
62#define SDA_MAX 0x21 /* SDA-sin maximal value */
63#define SDELAY_VALUE 0x22 /* Delay between Tx and Rx clock */
64#define IN_D_COUNTER 0x36 /* D receive channel fifo counter */
65#define OUT_D_COUNTER 0x37 /* D transmit channel fifo counter */
66#define IN_B1_COUNTER 0x38 /* B1 receive channel fifo counter */
67#define OUT_B1_COUNTER 0x39 /* B1 transmit channel fifo counter */
68#define IN_B2_COUNTER 0x3a /* B2 receive channel fifo counter */
69#define OUT_B2_COUNTER 0x3b /* B2 transmit channel fifo counter */
70#define FFCTRL_IN_D 0x3C /* D receive channel fifo threshold low */
71#define FFCTRH_IN_D 0x3D /* D receive channel fifo threshold high */
72#define FFCTRL_OUT_D 0x3E /* D transmit channel fifo threshold low */
73#define FFCTRH_OUT_D 0x3F /* D transmit channel fifo threshold high */
74#define FFCTRL_IN_B1 0x40 /* B1 receive channel fifo threshold low */
75#define FFCTRH_IN_B1 0x41 /* B1 receive channel fifo threshold high */
76#define FFCTRL_OUT_B1 0x42 /* B1 transmit channel fifo threshold low */
77#define FFCTRH_OUT_B1 0x43 /* B1 transmit channel fifo threshold high */
78#define FFCTRL_IN_B2 0x44 /* B2 receive channel fifo threshold low */
79#define FFCTRH_IN_B2 0x45 /* B2 receive channel fifo threshold high */
80#define FFCTRL_OUT_B2 0x46 /* B2 transmit channel fifo threshold low */
81#define FFCTRH_OUT_B2 0x47 /* B2 transmit channel fifo threshold high */
82#define MPMSK 0x4A /* Multi purpose interrupt MASK register */
83#define FFMSK_D 0x4c /* D fifo interrupt MASK register */
84#define FFMSK_B1 0x4e /* B1 fifo interrupt MASK register */
85#define FFMSK_B2 0x50 /* B2 fifo interrupt MASK register */
86#define GPIO_DIR 0x52 /* GPIO pins direction registers */
87#define GPIO_OUT 0x53 /* GPIO pins output register */
88#define GPIO_IN 0x54 /* GPIO pins input register */
89#define TXCI 0x56 /* CI command to be transmitted */
90
91
92// Format of the interrupt packet received on endpoint 1:
93//
94// +--------+--------+--------+--------+--------+--------+
95// !MPINT !FFINT_D !FFINT_B1!FFINT_B2!CCIST !GPIO_INT!
96// +--------+--------+--------+--------+--------+--------+
97
98// Offsets in the interrupt packet
99
100#define MPINT 0
101#define FFINT_D 1
102#define FFINT_B1 2
103#define FFINT_B2 3
104#define CCIST 4
105#define GPIO_INT 5
106#define INT_PKT_SIZE 6
107
108// MPINT
109#define LSD_INT 0x80 /* S line activity detected */
110#define RXCI_INT 0x40 /* Indicate primitive arrived */
111#define DEN_INT 0x20 /* Signal enabling data out of D Tx fifo */
112#define DCOLL_INT 0x10 /* D channel collision */
113#define AMIVN_INT 0x04 /* AMI violation number reached 2 */
114#define INFOI_INT 0x04 /* INFOi changed */
115#define DRXON_INT 0x02 /* Reception channel active */
116#define GPCHG_INT 0x01 /* GPIO pin value changed */
117
118// FFINT_x
119#define IN_OVERRUN 0x80 /* In fifo overrun */
120#define OUT_UNDERRUN 0x40 /* Out fifo underrun */
121#define IN_UP 0x20 /* In fifo thresholdh up-crossed */
122#define IN_DOWN 0x10 /* In fifo thresholdl down-crossed */
123#define OUT_UP 0x08 /* Out fifo thresholdh up-crossed */
124#define OUT_DOWN 0x04 /* Out fifo thresholdl down-crossed */
125#define IN_COUNTER_ZEROED 0x02 /* In down-counter reached 0 */
126#define OUT_COUNTER_ZEROED 0x01 /* Out down-counter reached 0 */
127
128#define ANY_REC_INT (IN_OVERRUN+IN_UP+IN_DOWN+IN_COUNTER_ZEROED)
129#define ANY_XMIT_INT (OUT_UNDERRUN+OUT_UP+OUT_DOWN+OUT_COUNTER_ZEROED)
130
131
132// Level 1 commands that are sent using the TXCI device request
133#define ST5481_CMD_DR 0x0 /* Deactivation Request */
134#define ST5481_CMD_RES 0x1 /* state machine RESet */
135#define ST5481_CMD_TM1 0x2 /* Test Mode 1 */
136#define ST5481_CMD_TM2 0x3 /* Test Mode 2 */
137#define ST5481_CMD_PUP 0x7 /* Power UP */
138#define ST5481_CMD_AR8 0x8 /* Activation Request class 1 */
139#define ST5481_CMD_AR10 0x9 /* Activation Request class 2 */
140#define ST5481_CMD_ARL 0xA /* Activation Request Loopback */
141#define ST5481_CMD_PDN 0xF /* Power DoWn */
142
143// Turn on/off the LEDs using the GPIO device request.
144// To use the B LEDs, number_of_leds must be set to 4
145#define B1_LED 0x10U
146#define B2_LED 0x20U
147#define GREEN_LED 0x40U
148#define RED_LED 0x80U
149
150// D channel out states
151enum {
152 ST_DOUT_NONE,
153
154 ST_DOUT_SHORT_INIT,
155 ST_DOUT_SHORT_WAIT_DEN,
156
157 ST_DOUT_LONG_INIT,
158 ST_DOUT_LONG_WAIT_DEN,
159 ST_DOUT_NORMAL,
160
161 ST_DOUT_WAIT_FOR_UNDERRUN,
162 ST_DOUT_WAIT_FOR_NOT_BUSY,
163 ST_DOUT_WAIT_FOR_STOP,
164 ST_DOUT_WAIT_FOR_RESET,
165};
166
167#define DOUT_STATE_COUNT (ST_DOUT_WAIT_FOR_RESET + 1)
168
169// D channel out events
170enum {
171 EV_DOUT_START_XMIT,
172 EV_DOUT_COMPLETE,
173 EV_DOUT_DEN,
174 EV_DOUT_RESETED,
175 EV_DOUT_STOPPED,
176 EV_DOUT_COLL,
177 EV_DOUT_UNDERRUN,
178};
179
180#define DOUT_EVENT_COUNT (EV_DOUT_UNDERRUN + 1)
181
182// ----------------------------------------------------------------------
183
184enum {
185 ST_L1_F3,
186 ST_L1_F4,
187 ST_L1_F6,
188 ST_L1_F7,
189 ST_L1_F8,
190};
191
192#define L1_STATE_COUNT (ST_L1_F8+1)
193
194// The first 16 entries match the Level 1 indications that
195// are found at offset 4 (CCIST) in the interrupt packet
196
197enum {
198 EV_IND_DP, // 0000 Deactivation Pending
199 EV_IND_1, // 0001
200 EV_IND_2, // 0010
201 EV_IND_3, // 0011
202 EV_IND_RSY, // 0100 ReSYnchronizing
203 EV_IND_5, // 0101
204 EV_IND_6, // 0110
205 EV_IND_7, // 0111
206 EV_IND_AP, // 1000 Activation Pending
207 EV_IND_9, // 1001
208 EV_IND_10, // 1010
209 EV_IND_11, // 1011
210 EV_IND_AI8, // 1100 Activation Indication class 8
211 EV_IND_AI10,// 1101 Activation Indication class 10
212 EV_IND_AIL, // 1110 Activation Indication Loopback
213 EV_IND_DI, // 1111 Deactivation Indication
214 EV_PH_ACTIVATE_REQ,
215 EV_PH_DEACTIVATE_REQ,
216 EV_TIMER3,
217};
218
219#define L1_EVENT_COUNT (EV_TIMER3 + 1)
220
221#define ERR(format, arg...) \
222printk(KERN_ERR "%s:%s: " format "\n" , __FILE__, __FUNCTION__ , ## arg)
223
224#define WARN(format, arg...) \
225printk(KERN_WARNING "%s:%s: " format "\n" , __FILE__, __FUNCTION__ , ## arg)
226
227#define INFO(format, arg...) \
228printk(KERN_INFO "%s:%s: " format "\n" , __FILE__, __FUNCTION__ , ## arg)
229
230#include "isdnhdlc.h"
231#include "fsm.h"
232#include "hisax_if.h"
233#include <linux/skbuff.h>
234
235/* ======================================================================
236 * FIFO handling
237 */
238
239/* Generic FIFO structure */
240struct fifo {
241 u_char r,w,count,size;
242 spinlock_t lock;
243};
244
245/*
246 * Init an FIFO
247 */
248static inline void fifo_init(struct fifo *fifo, int size)
249{
250 fifo->r = fifo->w = fifo->count = 0;
251 fifo->size = size;
252 spin_lock_init(&fifo->lock);
253}
254
255/*
256 * Add an entry to the FIFO
257 */
258static inline int fifo_add(struct fifo *fifo)
259{
260 unsigned long flags;
261 int index;
262
263 if (!fifo) {
264 return -1;
265 }
266
267 spin_lock_irqsave(&fifo->lock, flags);
268 if (fifo->count == fifo->size) {
269 // FIFO full
270 index = -1;
271 } else {
272 // Return index where to get the next data to add to the FIFO
273 index = fifo->w++ & (fifo->size-1);
274 fifo->count++;
275 }
276 spin_unlock_irqrestore(&fifo->lock, flags);
277 return index;
278}
279
280/*
281 * Remove an entry from the FIFO with the index returned.
282 */
283static inline int fifo_remove(struct fifo *fifo)
284{
285 unsigned long flags;
286 int index;
287
288 if (!fifo) {
289 return -1;
290 }
291
292 spin_lock_irqsave(&fifo->lock, flags);
293 if (!fifo->count) {
294 // FIFO empty
295 index = -1;
296 } else {
297 // Return index where to get the next data from the FIFO
298 index = fifo->r++ & (fifo->size-1);
299 fifo->count--;
300 }
301 spin_unlock_irqrestore(&fifo->lock, flags);
302
303 return index;
304}
305
306/* ======================================================================
307 * control pipe
308 */
309typedef void (*ctrl_complete_t)(void *);
310
311typedef struct ctrl_msg {
312 struct usb_ctrlrequest dr;
313 ctrl_complete_t complete;
314 void *context;
315} ctrl_msg;
316
317/* FIFO of ctrl messages waiting to be sent */
318#define MAX_EP0_MSG 16
319struct ctrl_msg_fifo {
320 struct fifo f;
321 struct ctrl_msg data[MAX_EP0_MSG];
322};
323
324#define MAX_DFRAME_LEN_L1 300
325#define HSCX_BUFMAX 4096
326
327struct st5481_ctrl {
328 struct ctrl_msg_fifo msg_fifo;
329 unsigned long busy;
330 struct urb *urb;
331};
332
333struct st5481_intr {
334 // struct evt_fifo evt_fifo;
335 struct urb *urb;
336};
337
338struct st5481_d_out {
339 struct isdnhdlc_vars hdlc_state;
340 struct urb *urb[2]; /* double buffering */
341 unsigned long busy;
342 struct sk_buff *tx_skb;
343 struct FsmInst fsm;
344};
345
346struct st5481_b_out {
347 struct isdnhdlc_vars hdlc_state;
348 struct urb *urb[2]; /* double buffering */
349 u_char flow_event;
350 u_long busy;
351 struct sk_buff *tx_skb;
352};
353
354struct st5481_in {
355 struct isdnhdlc_vars hdlc_state;
356 struct urb *urb[2]; /* double buffering */
357 int mode;
358 int bufsize;
359 unsigned int num_packets;
360 unsigned int packet_size;
361 unsigned char ep, counter;
362 unsigned char *rcvbuf;
363 struct st5481_adapter *adapter;
364 struct hisax_if *hisax_if;
365};
366
367int st5481_setup_in(struct st5481_in *in);
368void st5481_release_in(struct st5481_in *in);
369void st5481_in_mode(struct st5481_in *in, int mode);
370
371struct st5481_bcs {
372 struct hisax_b_if b_if;
373 struct st5481_adapter *adapter;
374 struct st5481_in b_in;
375 struct st5481_b_out b_out;
376 int channel;
377 int mode;
378};
379
380struct st5481_adapter {
381 struct list_head list;
382 int number_of_leds;
383 struct usb_device *usb_dev;
384 struct hisax_d_if hisax_d_if;
385
386 struct st5481_ctrl ctrl;
387 struct st5481_intr intr;
388 struct st5481_in d_in;
389 struct st5481_d_out d_out;
390
391 unsigned char leds;
392 unsigned int led_counter;
393
394 unsigned long event;
395
396 struct FsmInst l1m;
397 struct FsmTimer timer;
398
399 struct st5481_bcs bcs[2];
400};
401
402#define TIMER3_VALUE 7000
403
404/* ======================================================================
405 *
406 */
407
408/*
409 * Submit an URB with error reporting. This is a macro so
410 * the __FUNCTION__ returns the caller function name.
411 */
412#define SUBMIT_URB(urb, mem_flags) \
413({ \
414 int status; \
415 if ((status = usb_submit_urb(urb, mem_flags)) < 0) { \
416 WARN("usb_submit_urb failed,status=%d", status); \
417 } \
418 status; \
419})
420
421/*
422 * USB double buffering, return the URB index (0 or 1).
423 */
424static inline int get_buf_nr(struct urb *urbs[], struct urb *urb)
425{
426 return (urbs[0]==urb ? 0 : 1);
427}
428
429/* ---------------------------------------------------------------------- */
430
431/* B Channel */
432
433int st5481_setup_b(struct st5481_bcs *bcs);
434void st5481_release_b(struct st5481_bcs *bcs);
435void st5481_d_l2l1(struct hisax_if *hisax_d_if, int pr, void *arg);
436
437/* D Channel */
438
439int st5481_setup_d(struct st5481_adapter *adapter);
440void st5481_release_d(struct st5481_adapter *adapter);
441void st5481_b_l2l1(struct hisax_if *b_if, int pr, void *arg);
442int st5481_d_init(void);
443void st5481_d_exit(void);
444
445/* USB */
446void st5481_ph_command(struct st5481_adapter *adapter, unsigned int command);
447int st5481_setup_isocpipes(struct urb* urb[2], struct usb_device *dev,
448 unsigned int pipe, int num_packets,
449 int packet_size, int buf_size,
450 usb_complete_t complete, void *context);
451void st5481_release_isocpipes(struct urb* urb[2]);
452
453int st5481_isoc_flatten(struct urb *urb);
454void st5481_usb_pipe_reset(struct st5481_adapter *adapter,
455 u_char pipe, ctrl_complete_t complete, void *context);
456void st5481_usb_ctrl_msg(struct st5481_adapter *adapter,
457 u8 request, u8 requesttype, u16 value, u16 index,
458 ctrl_complete_t complete, void *context);
459void st5481_usb_device_ctrl_msg(struct st5481_adapter *adapter,
460 u8 request, u16 value,
461 ctrl_complete_t complete, void *context);
462int st5481_setup_usb(struct st5481_adapter *adapter);
463void st5481_release_usb(struct st5481_adapter *adapter);
464void st5481_start(struct st5481_adapter *adapter);
465void st5481_stop(struct st5481_adapter *adapter);
466
467// ----------------------------------------------------------------------
468// debugging macros
469
470#define __debug_variable st5481_debug
471#include "hisax_debug.h"
472
473#ifdef CONFIG_HISAX_DEBUG
474
475extern int st5481_debug;
476
477#define DBG_ISO_PACKET(level,urb) \
478 if (level & __debug_variable) dump_iso_packet(__FUNCTION__,urb)
479
480static void __attribute__((unused))
481dump_iso_packet(const char *name, struct urb *urb)
482{
483 int i,j;
484 int len,ofs;
485 u_char *data;
486
487 printk(KERN_DEBUG "%s: packets=%d,errors=%d\n",
488 name,urb->number_of_packets,urb->error_count);
489 for (i = 0; i < urb->number_of_packets; ++i) {
490 if (urb->pipe & USB_DIR_IN) {
491 len = urb->iso_frame_desc[i].actual_length;
492 } else {
493 len = urb->iso_frame_desc[i].length;
494 }
495 ofs = urb->iso_frame_desc[i].offset;
496 printk(KERN_DEBUG "len=%.2d,ofs=%.3d ",len,ofs);
497 if (len) {
498 data = urb->transfer_buffer+ofs;
499 for (j=0; j < len; j++) {
500 printk ("%.2x", data[j]);
501 }
502 }
503 printk("\n");
504 }
505}
506
507static inline const char *ST5481_CMD_string(int evt)
508{
509 static char s[16];
510
511 switch (evt) {
512 case ST5481_CMD_DR: return "DR";
513 case ST5481_CMD_RES: return "RES";
514 case ST5481_CMD_TM1: return "TM1";
515 case ST5481_CMD_TM2: return "TM2";
516 case ST5481_CMD_PUP: return "PUP";
517 case ST5481_CMD_AR8: return "AR8";
518 case ST5481_CMD_AR10: return "AR10";
519 case ST5481_CMD_ARL: return "ARL";
520 case ST5481_CMD_PDN: return "PDN";
521 };
522
523 sprintf(s,"0x%x",evt);
524 return s;
525}
526
527#else
528
529#define DBG_ISO_PACKET(level,urb) do {} while (0)
530
531#endif
532
533
534
535#endif
diff --git a/drivers/isdn/hisax/st5481_b.c b/drivers/isdn/hisax/st5481_b.c
new file mode 100644
index 000000000000..2fcd093921d8
--- /dev/null
+++ b/drivers/isdn/hisax/st5481_b.c
@@ -0,0 +1,374 @@
1/*
2 * Driver for ST5481 USB ISDN modem
3 *
4 * Author Frode Isaksen
5 * Copyright 2001 by Frode Isaksen <fisaksen@bewan.com>
6 * 2001 by Kai Germaschewski <kai.germaschewski@gmx.de>
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 */
12
13#include <linux/init.h>
14#include <linux/usb.h>
15#include <linux/slab.h>
16#include <linux/netdevice.h>
17#include "st5481.h"
18
19static inline void B_L1L2(struct st5481_bcs *bcs, int pr, void *arg)
20{
21 struct hisax_if *ifc = (struct hisax_if *) &bcs->b_if;
22
23 ifc->l1l2(ifc, pr, arg);
24}
25
26/*
27 * Encode and transmit next frame.
28 */
29static void usb_b_out(struct st5481_bcs *bcs,int buf_nr)
30{
31 struct st5481_b_out *b_out = &bcs->b_out;
32 struct st5481_adapter *adapter = bcs->adapter;
33 struct urb *urb;
34 unsigned int packet_size,offset;
35 int len,buf_size,bytes_sent;
36 int i;
37 struct sk_buff *skb;
38
39 if (test_and_set_bit(buf_nr, &b_out->busy)) {
40 DBG(4,"ep %d urb %d busy",(bcs->channel+1)*2,buf_nr);
41 return;
42 }
43 urb = b_out->urb[buf_nr];
44
45 // Adjust isoc buffer size according to flow state
46 if(b_out->flow_event & (OUT_DOWN | OUT_UNDERRUN)) {
47 buf_size = NUM_ISO_PACKETS_B*SIZE_ISO_PACKETS_B_OUT + B_FLOW_ADJUST;
48 packet_size = SIZE_ISO_PACKETS_B_OUT + B_FLOW_ADJUST;
49 DBG(4,"B%d,adjust flow,add %d bytes",bcs->channel+1,B_FLOW_ADJUST);
50 } else if(b_out->flow_event & OUT_UP){
51 buf_size = NUM_ISO_PACKETS_B*SIZE_ISO_PACKETS_B_OUT - B_FLOW_ADJUST;
52 packet_size = SIZE_ISO_PACKETS_B_OUT - B_FLOW_ADJUST;
53 DBG(4,"B%d,adjust flow,remove %d bytes",bcs->channel+1,B_FLOW_ADJUST);
54 } else {
55 buf_size = NUM_ISO_PACKETS_B*SIZE_ISO_PACKETS_B_OUT;
56 packet_size = 8;
57 }
58 b_out->flow_event = 0;
59
60 len = 0;
61 while (len < buf_size) {
62 if ((skb = b_out->tx_skb)) {
63 DBG_SKB(0x100, skb);
64 DBG(4,"B%d,len=%d",bcs->channel+1,skb->len);
65
66 if (bcs->mode == L1_MODE_TRANS) {
67 bytes_sent = buf_size - len;
68 if (skb->len < bytes_sent)
69 bytes_sent = skb->len;
70 { /* swap tx bytes to get hearable audio data */
71 register unsigned char *src = skb->data;
72 register unsigned char *dest = urb->transfer_buffer+len;
73 register unsigned int count;
74 for (count = 0; count < bytes_sent; count++)
75 *dest++ = isdnhdlc_bit_rev_tab[*src++];
76 }
77 len += bytes_sent;
78 } else {
79 len += isdnhdlc_encode(&b_out->hdlc_state,
80 skb->data, skb->len, &bytes_sent,
81 urb->transfer_buffer+len, buf_size-len);
82 }
83
84 skb_pull(skb, bytes_sent);
85
86 if (!skb->len) {
87 // Frame sent
88 b_out->tx_skb = NULL;
89 B_L1L2(bcs, PH_DATA | CONFIRM, (void *) skb->truesize);
90 dev_kfree_skb_any(skb);
91
92/* if (!(bcs->tx_skb = skb_dequeue(&bcs->sq))) { */
93/* st5481B_sched_event(bcs, B_XMTBUFREADY); */
94/* } */
95 }
96 } else {
97 if (bcs->mode == L1_MODE_TRANS) {
98 memset(urb->transfer_buffer+len, 0xff, buf_size-len);
99 len = buf_size;
100 } else {
101 // Send flags
102 len += isdnhdlc_encode(&b_out->hdlc_state,
103 NULL, 0, &bytes_sent,
104 urb->transfer_buffer+len, buf_size-len);
105 }
106 }
107 }
108
109 // Prepare the URB
110 for (i = 0, offset = 0; offset < len; i++) {
111 urb->iso_frame_desc[i].offset = offset;
112 urb->iso_frame_desc[i].length = packet_size;
113 offset += packet_size;
114 packet_size = SIZE_ISO_PACKETS_B_OUT;
115 }
116 urb->transfer_buffer_length = len;
117 urb->number_of_packets = i;
118 urb->dev = adapter->usb_dev;
119
120 DBG_ISO_PACKET(0x200,urb);
121
122 SUBMIT_URB(urb, GFP_NOIO);
123}
124
125/*
126 * Start transfering (flags or data) on the B channel, since
127 * FIFO counters has been set to a non-zero value.
128 */
129static void st5481B_start_xfer(void *context)
130{
131 struct st5481_bcs *bcs = context;
132
133 DBG(4,"B%d",bcs->channel+1);
134
135 // Start transmitting (flags or data) on B channel
136
137 usb_b_out(bcs,0);
138 usb_b_out(bcs,1);
139}
140
141/*
142 * If the adapter has only 2 LEDs, the green
143 * LED will blink with a rate depending
144 * on the number of channels opened.
145 */
146static void led_blink(struct st5481_adapter *adapter)
147{
148 u_char leds = adapter->leds;
149
150 // 50 frames/sec for each channel
151 if (++adapter->led_counter % 50) {
152 return;
153 }
154
155 if (adapter->led_counter % 100) {
156 leds |= GREEN_LED;
157 } else {
158 leds &= ~GREEN_LED;
159 }
160
161 st5481_usb_device_ctrl_msg(adapter, GPIO_OUT, leds, NULL, NULL);
162}
163
164static void usb_b_out_complete(struct urb *urb, struct pt_regs *regs)
165{
166 struct st5481_bcs *bcs = urb->context;
167 struct st5481_b_out *b_out = &bcs->b_out;
168 struct st5481_adapter *adapter = bcs->adapter;
169 int buf_nr;
170
171 buf_nr = get_buf_nr(b_out->urb, urb);
172 test_and_clear_bit(buf_nr, &b_out->busy);
173
174 if (unlikely(urb->status < 0)) {
175 if (urb->status != -ENOENT && urb->status != -ESHUTDOWN) {
176 WARN("urb status %d",urb->status);
177 if (b_out->busy == 0) {
178 st5481_usb_pipe_reset(adapter, (bcs->channel+1)*2 | USB_DIR_OUT, NULL, NULL);
179 }
180 } else {
181 DBG(1,"urb killed");
182 return; // Give up
183 }
184 }
185
186 usb_b_out(bcs,buf_nr);
187
188 if (adapter->number_of_leds == 2)
189 led_blink(adapter);
190}
191
192/*
193 * Start or stop the transfer on the B channel.
194 */
195static void st5481B_mode(struct st5481_bcs *bcs, int mode)
196{
197 struct st5481_b_out *b_out = &bcs->b_out;
198 struct st5481_adapter *adapter = bcs->adapter;
199
200 DBG(4,"B%d,mode=%d", bcs->channel + 1, mode);
201
202 if (bcs->mode == mode)
203 return;
204
205 bcs->mode = mode;
206
207 // Cancel all USB transfers on this B channel
208 usb_unlink_urb(b_out->urb[0]);
209 usb_unlink_urb(b_out->urb[1]);
210 b_out->busy = 0;
211
212 st5481_in_mode(&bcs->b_in, mode);
213 if (bcs->mode != L1_MODE_NULL) {
214 // Open the B channel
215 if (bcs->mode != L1_MODE_TRANS) {
216 isdnhdlc_out_init(&b_out->hdlc_state, 0, bcs->mode == L1_MODE_HDLC_56K);
217 }
218 st5481_usb_pipe_reset(adapter, (bcs->channel+1)*2, NULL, NULL);
219
220 // Enable B channel interrupts
221 st5481_usb_device_ctrl_msg(adapter, FFMSK_B1+(bcs->channel*2),
222 OUT_UP+OUT_DOWN+OUT_UNDERRUN, NULL, NULL);
223
224 // Enable B channel FIFOs
225 st5481_usb_device_ctrl_msg(adapter, OUT_B1_COUNTER+(bcs->channel*2), 32, st5481B_start_xfer, bcs);
226 if (adapter->number_of_leds == 4) {
227 if (bcs->channel == 0) {
228 adapter->leds |= B1_LED;
229 } else {
230 adapter->leds |= B2_LED;
231 }
232 }
233 } else {
234 // Disble B channel interrupts
235 st5481_usb_device_ctrl_msg(adapter, FFMSK_B1+(bcs->channel*2), 0, NULL, NULL);
236
237 // Disable B channel FIFOs
238 st5481_usb_device_ctrl_msg(adapter, OUT_B1_COUNTER+(bcs->channel*2), 0, NULL, NULL);
239
240 if (adapter->number_of_leds == 4) {
241 if (bcs->channel == 0) {
242 adapter->leds &= ~B1_LED;
243 } else {
244 adapter->leds &= ~B2_LED;
245 }
246 } else {
247 st5481_usb_device_ctrl_msg(adapter, GPIO_OUT, adapter->leds, NULL, NULL);
248 }
249 if (b_out->tx_skb) {
250 dev_kfree_skb_any(b_out->tx_skb);
251 b_out->tx_skb = NULL;
252 }
253
254 }
255}
256
257static int st5481_setup_b_out(struct st5481_bcs *bcs)
258{
259 struct usb_device *dev = bcs->adapter->usb_dev;
260 struct usb_interface *intf;
261 struct usb_host_interface *altsetting = NULL;
262 struct usb_host_endpoint *endpoint;
263 struct st5481_b_out *b_out = &bcs->b_out;
264
265 DBG(4,"");
266
267 intf = usb_ifnum_to_if(dev, 0);
268 if (intf)
269 altsetting = usb_altnum_to_altsetting(intf, 3);
270 if (!altsetting)
271 return -ENXIO;
272
273 // Allocate URBs and buffers for the B channel out
274 endpoint = &altsetting->endpoint[EP_B1_OUT - 1 + bcs->channel * 2];
275
276 DBG(4,"endpoint address=%02x,packet size=%d",
277 endpoint->desc.bEndpointAddress, le16_to_cpu(endpoint->desc.wMaxPacketSize));
278
279 // Allocate memory for 8000bytes/sec + extra bytes if underrun
280 return st5481_setup_isocpipes(b_out->urb, dev,
281 usb_sndisocpipe(dev, endpoint->desc.bEndpointAddress),
282 NUM_ISO_PACKETS_B, SIZE_ISO_PACKETS_B_OUT,
283 NUM_ISO_PACKETS_B * SIZE_ISO_PACKETS_B_OUT + B_FLOW_ADJUST,
284 usb_b_out_complete, bcs);
285}
286
287static void st5481_release_b_out(struct st5481_bcs *bcs)
288{
289 struct st5481_b_out *b_out = &bcs->b_out;
290
291 DBG(4,"");
292
293 st5481_release_isocpipes(b_out->urb);
294}
295
296int st5481_setup_b(struct st5481_bcs *bcs)
297{
298 int retval;
299
300 DBG(4,"");
301
302 retval = st5481_setup_b_out(bcs);
303 if (retval)
304 goto err;
305 bcs->b_in.bufsize = HSCX_BUFMAX;
306 bcs->b_in.num_packets = NUM_ISO_PACKETS_B;
307 bcs->b_in.packet_size = SIZE_ISO_PACKETS_B_IN;
308 bcs->b_in.ep = (bcs->channel ? EP_B2_IN : EP_B1_IN) | USB_DIR_IN;
309 bcs->b_in.counter = bcs->channel ? IN_B2_COUNTER : IN_B1_COUNTER;
310 bcs->b_in.adapter = bcs->adapter;
311 bcs->b_in.hisax_if = &bcs->b_if.ifc;
312 retval = st5481_setup_in(&bcs->b_in);
313 if (retval)
314 goto err_b_out;
315
316
317 return 0;
318
319 err_b_out:
320 st5481_release_b_out(bcs);
321 err:
322 return retval;
323}
324
325/*
326 * Release buffers and URBs for the B channels
327 */
328void st5481_release_b(struct st5481_bcs *bcs)
329{
330 DBG(4,"");
331
332 st5481_release_in(&bcs->b_in);
333 st5481_release_b_out(bcs);
334}
335
336/*
337 * st5481_b_l2l1 is the entry point for upper layer routines that want to
338 * transmit on the B channel. PH_DATA | REQUEST is a normal packet that
339 * we either start transmitting (if idle) or queue (if busy).
340 * PH_PULL | REQUEST can be called to request a callback message
341 * (PH_PULL | CONFIRM)
342 * once the link is idle. After a "pull" callback, the upper layer
343 * routines can use PH_PULL | INDICATION to send data.
344 */
345void st5481_b_l2l1(struct hisax_if *ifc, int pr, void *arg)
346{
347 struct st5481_bcs *bcs = ifc->priv;
348 struct sk_buff *skb = arg;
349 int mode;
350
351 DBG(4, "");
352
353 switch (pr) {
354 case PH_DATA | REQUEST:
355 if (bcs->b_out.tx_skb)
356 BUG();
357
358 bcs->b_out.tx_skb = skb;
359 break;
360 case PH_ACTIVATE | REQUEST:
361 mode = (int) arg;
362 DBG(4,"B%d,PH_ACTIVATE_REQUEST %d", bcs->channel + 1, mode);
363 st5481B_mode(bcs, mode);
364 B_L1L2(bcs, PH_ACTIVATE | INDICATION, NULL);
365 break;
366 case PH_DEACTIVATE | REQUEST:
367 DBG(4,"B%d,PH_DEACTIVATE_REQUEST", bcs->channel + 1);
368 st5481B_mode(bcs, L1_MODE_NULL);
369 B_L1L2(bcs, PH_DEACTIVATE | INDICATION, NULL);
370 break;
371 default:
372 WARN("pr %#x\n", pr);
373 }
374}
diff --git a/drivers/isdn/hisax/st5481_d.c b/drivers/isdn/hisax/st5481_d.c
new file mode 100644
index 000000000000..071b1d31999f
--- /dev/null
+++ b/drivers/isdn/hisax/st5481_d.c
@@ -0,0 +1,776 @@
1/*
2 * Driver for ST5481 USB ISDN modem
3 *
4 * Author Frode Isaksen
5 * Copyright 2001 by Frode Isaksen <fisaksen@bewan.com>
6 * 2001 by Kai Germaschewski <kai.germaschewski@gmx.de>
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 */
12
13#include <linux/init.h>
14#include <linux/usb.h>
15#include <linux/slab.h>
16#include <linux/netdevice.h>
17#include "st5481.h"
18
19static void ph_connect(struct st5481_adapter *adapter);
20static void ph_disconnect(struct st5481_adapter *adapter);
21
22static struct Fsm l1fsm;
23
24static char *strL1State[] =
25{
26 "ST_L1_F3",
27 "ST_L1_F4",
28 "ST_L1_F6",
29 "ST_L1_F7",
30 "ST_L1_F8",
31};
32
33static char *strL1Event[] =
34{
35 "EV_IND_DP",
36 "EV_IND_1",
37 "EV_IND_2",
38 "EV_IND_3",
39 "EV_IND_RSY",
40 "EV_IND_5",
41 "EV_IND_6",
42 "EV_IND_7",
43 "EV_IND_AP",
44 "EV_IND_9",
45 "EV_IND_10",
46 "EV_IND_11",
47 "EV_IND_AI8",
48 "EV_IND_AI10",
49 "EV_IND_AIL",
50 "EV_IND_DI",
51 "EV_PH_ACTIVATE_REQ",
52 "EV_PH_DEACTIVATE_REQ",
53 "EV_TIMER3",
54};
55
56static inline void D_L1L2(struct st5481_adapter *adapter, int pr, void *arg)
57{
58 struct hisax_if *ifc = (struct hisax_if *) &adapter->hisax_d_if;
59
60 ifc->l1l2(ifc, pr, arg);
61}
62
63static void
64l1_go_f3(struct FsmInst *fi, int event, void *arg)
65{
66 struct st5481_adapter *adapter = fi->userdata;
67
68 if (fi->state == ST_L1_F7)
69 ph_disconnect(adapter);
70
71 FsmChangeState(fi, ST_L1_F3);
72 D_L1L2(adapter, PH_DEACTIVATE | INDICATION, NULL);
73}
74
75static void
76l1_go_f6(struct FsmInst *fi, int event, void *arg)
77{
78 struct st5481_adapter *adapter = fi->userdata;
79
80 if (fi->state == ST_L1_F7)
81 ph_disconnect(adapter);
82
83 FsmChangeState(fi, ST_L1_F6);
84}
85
86static void
87l1_go_f7(struct FsmInst *fi, int event, void *arg)
88{
89 struct st5481_adapter *adapter = fi->userdata;
90
91 FsmDelTimer(&adapter->timer, 0);
92 ph_connect(adapter);
93 FsmChangeState(fi, ST_L1_F7);
94 D_L1L2(adapter, PH_ACTIVATE | INDICATION, NULL);
95}
96
97static void
98l1_go_f8(struct FsmInst *fi, int event, void *arg)
99{
100 struct st5481_adapter *adapter = fi->userdata;
101
102 if (fi->state == ST_L1_F7)
103 ph_disconnect(adapter);
104
105 FsmChangeState(fi, ST_L1_F8);
106}
107
108static void
109l1_timer3(struct FsmInst *fi, int event, void *arg)
110{
111 struct st5481_adapter *adapter = fi->userdata;
112
113 st5481_ph_command(adapter, ST5481_CMD_DR);
114 FsmChangeState(fi, ST_L1_F3);
115 D_L1L2(adapter, PH_DEACTIVATE | INDICATION, NULL);
116}
117
118static void
119l1_ignore(struct FsmInst *fi, int event, void *arg)
120{
121}
122
123static void
124l1_activate(struct FsmInst *fi, int event, void *arg)
125{
126 struct st5481_adapter *adapter = fi->userdata;
127
128 st5481_ph_command(adapter, ST5481_CMD_DR);
129 st5481_ph_command(adapter, ST5481_CMD_PUP);
130 FsmRestartTimer(&adapter->timer, TIMER3_VALUE, EV_TIMER3, NULL, 2);
131 st5481_ph_command(adapter, ST5481_CMD_AR8);
132 FsmChangeState(fi, ST_L1_F4);
133}
134
135static struct FsmNode L1FnList[] __initdata =
136{
137 {ST_L1_F3, EV_IND_DP, l1_ignore},
138 {ST_L1_F3, EV_IND_AP, l1_go_f6},
139 {ST_L1_F3, EV_IND_AI8, l1_go_f7},
140 {ST_L1_F3, EV_IND_AI10, l1_go_f7},
141 {ST_L1_F3, EV_PH_ACTIVATE_REQ, l1_activate},
142
143 {ST_L1_F4, EV_TIMER3, l1_timer3},
144 {ST_L1_F4, EV_IND_DP, l1_go_f3},
145 {ST_L1_F4, EV_IND_AP, l1_go_f6},
146 {ST_L1_F4, EV_IND_AI8, l1_go_f7},
147 {ST_L1_F4, EV_IND_AI10, l1_go_f7},
148
149 {ST_L1_F6, EV_TIMER3, l1_timer3},
150 {ST_L1_F6, EV_IND_DP, l1_go_f3},
151 {ST_L1_F6, EV_IND_AP, l1_ignore},
152 {ST_L1_F6, EV_IND_AI8, l1_go_f7},
153 {ST_L1_F6, EV_IND_AI10, l1_go_f7},
154 {ST_L1_F7, EV_IND_RSY, l1_go_f8},
155
156 {ST_L1_F7, EV_IND_DP, l1_go_f3},
157 {ST_L1_F7, EV_IND_AP, l1_go_f6},
158 {ST_L1_F7, EV_IND_AI8, l1_ignore},
159 {ST_L1_F7, EV_IND_AI10, l1_ignore},
160 {ST_L1_F7, EV_IND_RSY, l1_go_f8},
161
162 {ST_L1_F8, EV_TIMER3, l1_timer3},
163 {ST_L1_F8, EV_IND_DP, l1_go_f3},
164 {ST_L1_F8, EV_IND_AP, l1_go_f6},
165 {ST_L1_F8, EV_IND_AI8, l1_go_f8},
166 {ST_L1_F8, EV_IND_AI10, l1_go_f8},
167 {ST_L1_F8, EV_IND_RSY, l1_ignore},
168};
169
170static void l1m_debug(struct FsmInst *fi, char *fmt, ...)
171{
172 va_list args;
173 char buf[256];
174
175 va_start(args, fmt);
176 vsprintf(buf, fmt, args);
177 DBG(8, "%s", buf);
178 va_end(args);
179}
180
181/* ======================================================================
182 * D-Channel out
183 */
184
185/*
186 D OUT state machine:
187 ====================
188
189 Transmit short frame (< 16 bytes of encoded data):
190
191 L1 FRAME D_OUT_STATE USB D CHANNEL
192 -------- ----------- --- ---------
193
194 FIXME
195
196 -> [xx..xx] SHORT_INIT -> [7Exx..xxC1C27EFF]
197 SHORT_WAIT_DEN <> OUT_D_COUNTER=16
198
199 END_OF_SHORT <- DEN_EVENT -> 7Exx
200 xxxx
201 xxxx
202 xxxx
203 xxxx
204 xxxx
205 C1C1
206 7EFF
207 WAIT_FOR_RESET_IDLE <- D_UNDERRUN <- (8ms)
208 IDLE <> Reset pipe
209
210
211
212 Transmit long frame (>= 16 bytes of encoded data):
213
214 L1 FRAME D_OUT_STATE USB D CHANNEL
215 -------- ----------- --- ---------
216
217 -> [xx...xx] IDLE
218 WAIT_FOR_STOP <> OUT_D_COUNTER=0
219 WAIT_FOR_RESET <> Reset pipe
220 STOP
221 INIT_LONG_FRAME -> [7Exx..xx]
222 WAIT_DEN <> OUT_D_COUNTER=16
223 OUT_NORMAL <- DEN_EVENT -> 7Exx
224 END_OF_FRAME_BUSY -> [xxxx] xxxx
225 END_OF_FRAME_NOT_BUSY -> [xxxx] xxxx
226 -> [xxxx] xxxx
227 -> [C1C2] xxxx
228 -> [7EFF] xxxx
229 xxxx
230 xxxx
231 ....
232 xxxx
233 C1C2
234 7EFF
235 <- D_UNDERRUN <- (> 8ms)
236 WAIT_FOR_STOP <> OUT_D_COUNTER=0
237 WAIT_FOR_RESET <> Reset pipe
238 STOP
239
240*/
241
242static struct Fsm dout_fsm;
243
244static char *strDoutState[] =
245{
246 "ST_DOUT_NONE",
247
248 "ST_DOUT_SHORT_INIT",
249 "ST_DOUT_SHORT_WAIT_DEN",
250
251 "ST_DOUT_LONG_INIT",
252 "ST_DOUT_LONG_WAIT_DEN",
253 "ST_DOUT_NORMAL",
254
255 "ST_DOUT_WAIT_FOR_UNDERRUN",
256 "ST_DOUT_WAIT_FOR_NOT_BUSY",
257 "ST_DOUT_WAIT_FOR_STOP",
258 "ST_DOUT_WAIT_FOR_RESET",
259};
260
261static char *strDoutEvent[] =
262{
263 "EV_DOUT_START_XMIT",
264 "EV_DOUT_COMPLETE",
265 "EV_DOUT_DEN",
266 "EV_DOUT_RESETED",
267 "EV_DOUT_STOPPED",
268 "EV_DOUT_COLL",
269 "EV_DOUT_UNDERRUN",
270};
271
272static void dout_debug(struct FsmInst *fi, char *fmt, ...)
273{
274 va_list args;
275 char buf[256];
276
277 va_start(args, fmt);
278 vsprintf(buf, fmt, args);
279 DBG(0x2, "%s", buf);
280 va_end(args);
281}
282
283static void dout_stop_event(void *context)
284{
285 struct st5481_adapter *adapter = context;
286
287 FsmEvent(&adapter->d_out.fsm, EV_DOUT_STOPPED, NULL);
288}
289
290/*
291 * Start the transfer of a D channel frame.
292 */
293static void usb_d_out(struct st5481_adapter *adapter, int buf_nr)
294{
295 struct st5481_d_out *d_out = &adapter->d_out;
296 struct urb *urb;
297 unsigned int num_packets, packet_offset;
298 int len, buf_size, bytes_sent;
299 struct sk_buff *skb;
300 struct usb_iso_packet_descriptor *desc;
301
302 if (d_out->fsm.state != ST_DOUT_NORMAL)
303 return;
304
305 if (test_and_set_bit(buf_nr, &d_out->busy)) {
306 DBG(2, "ep %d urb %d busy %#lx", EP_D_OUT, buf_nr, d_out->busy);
307 return;
308 }
309 urb = d_out->urb[buf_nr];
310
311 skb = d_out->tx_skb;
312
313 buf_size = NUM_ISO_PACKETS_D * SIZE_ISO_PACKETS_D_OUT;
314
315 if (skb) {
316 len = isdnhdlc_encode(&d_out->hdlc_state,
317 skb->data, skb->len, &bytes_sent,
318 urb->transfer_buffer, buf_size);
319 skb_pull(skb,bytes_sent);
320 } else {
321 // Send flags or idle
322 len = isdnhdlc_encode(&d_out->hdlc_state,
323 NULL, 0, &bytes_sent,
324 urb->transfer_buffer, buf_size);
325 }
326
327 if (len < buf_size) {
328 FsmChangeState(&d_out->fsm, ST_DOUT_WAIT_FOR_UNDERRUN);
329 }
330 if (skb && !skb->len) {
331 d_out->tx_skb = NULL;
332 D_L1L2(adapter, PH_DATA | CONFIRM, NULL);
333 dev_kfree_skb_any(skb);
334 }
335
336 // Prepare the URB
337 urb->transfer_buffer_length = len;
338 num_packets = 0;
339 packet_offset = 0;
340 while (packet_offset < len) {
341 desc = &urb->iso_frame_desc[num_packets];
342 desc->offset = packet_offset;
343 desc->length = SIZE_ISO_PACKETS_D_OUT;
344 if (len - packet_offset < desc->length)
345 desc->length = len - packet_offset;
346 num_packets++;
347 packet_offset += desc->length;
348 }
349 urb->number_of_packets = num_packets;
350
351 // Prepare the URB
352 urb->dev = adapter->usb_dev;
353 // Need to transmit the next buffer 2ms after the DEN_EVENT
354 urb->transfer_flags = 0;
355 urb->start_frame = usb_get_current_frame_number(adapter->usb_dev)+2;
356
357 DBG_ISO_PACKET(0x20,urb);
358
359 if (usb_submit_urb(urb, GFP_KERNEL) < 0) {
360 // There is another URB queued up
361 urb->transfer_flags = URB_ISO_ASAP;
362 SUBMIT_URB(urb, GFP_KERNEL);
363 }
364}
365
366static void fifo_reseted(void *context)
367{
368 struct st5481_adapter *adapter = context;
369
370 FsmEvent(&adapter->d_out.fsm, EV_DOUT_RESETED, NULL);
371}
372
373static void usb_d_out_complete(struct urb *urb, struct pt_regs *regs)
374{
375 struct st5481_adapter *adapter = urb->context;
376 struct st5481_d_out *d_out = &adapter->d_out;
377 int buf_nr;
378
379 DBG(2, "");
380
381 buf_nr = get_buf_nr(d_out->urb, urb);
382 test_and_clear_bit(buf_nr, &d_out->busy);
383
384 if (unlikely(urb->status < 0)) {
385 if (urb->status != -ENOENT && urb->status != -ESHUTDOWN) {
386 WARN("urb status %d",urb->status);
387 if (d_out->busy == 0) {
388 st5481_usb_pipe_reset(adapter, EP_D_OUT | USB_DIR_OUT, fifo_reseted, adapter);
389 }
390 return;
391 } else {
392 DBG(1,"urb killed");
393 return; // Give up
394 }
395 }
396
397 FsmEvent(&adapter->d_out.fsm, EV_DOUT_COMPLETE, (void *) buf_nr);
398}
399
400/* ====================================================================== */
401
402static void dout_start_xmit(struct FsmInst *fsm, int event, void *arg)
403{
404 // FIXME unify?
405 struct st5481_adapter *adapter = fsm->userdata;
406 struct st5481_d_out *d_out = &adapter->d_out;
407 struct urb *urb;
408 int len, bytes_sent;
409 struct sk_buff *skb;
410 int buf_nr = 0;
411
412 skb = d_out->tx_skb;
413
414 DBG(2,"len=%d",skb->len);
415
416 isdnhdlc_out_init(&d_out->hdlc_state, 1, 0);
417
418 if (test_and_set_bit(buf_nr, &d_out->busy)) {
419 WARN("ep %d urb %d busy %#lx", EP_D_OUT, buf_nr, d_out->busy);
420 return;
421 }
422 urb = d_out->urb[buf_nr];
423
424 DBG_SKB(0x10, skb);
425 len = isdnhdlc_encode(&d_out->hdlc_state,
426 skb->data, skb->len, &bytes_sent,
427 urb->transfer_buffer, 16);
428 skb_pull(skb, bytes_sent);
429
430 if(len < 16)
431 FsmChangeState(&d_out->fsm, ST_DOUT_SHORT_INIT);
432 else
433 FsmChangeState(&d_out->fsm, ST_DOUT_LONG_INIT);
434
435 if (skb->len == 0) {
436 d_out->tx_skb = NULL;
437 D_L1L2(adapter, PH_DATA | CONFIRM, NULL);
438 dev_kfree_skb_any(skb);
439 }
440
441// Prepare the URB
442 urb->transfer_buffer_length = len;
443
444 urb->iso_frame_desc[0].offset = 0;
445 urb->iso_frame_desc[0].length = len;
446 urb->number_of_packets = 1;
447
448 // Prepare the URB
449 urb->dev = adapter->usb_dev;
450 urb->transfer_flags = URB_ISO_ASAP;
451
452 DBG_ISO_PACKET(0x20,urb);
453 SUBMIT_URB(urb, GFP_KERNEL);
454}
455
456static void dout_short_fifo(struct FsmInst *fsm, int event, void *arg)
457{
458 struct st5481_adapter *adapter = fsm->userdata;
459 struct st5481_d_out *d_out = &adapter->d_out;
460
461 FsmChangeState(&d_out->fsm, ST_DOUT_SHORT_WAIT_DEN);
462 st5481_usb_device_ctrl_msg(adapter, OUT_D_COUNTER, 16, NULL, NULL);
463}
464
465static void dout_end_short_frame(struct FsmInst *fsm, int event, void *arg)
466{
467 struct st5481_adapter *adapter = fsm->userdata;
468 struct st5481_d_out *d_out = &adapter->d_out;
469
470 FsmChangeState(&d_out->fsm, ST_DOUT_WAIT_FOR_UNDERRUN);
471}
472
473static void dout_long_enable_fifo(struct FsmInst *fsm, int event, void *arg)
474{
475 struct st5481_adapter *adapter = fsm->userdata;
476 struct st5481_d_out *d_out = &adapter->d_out;
477
478 st5481_usb_device_ctrl_msg(adapter, OUT_D_COUNTER, 16, NULL, NULL);
479 FsmChangeState(&d_out->fsm, ST_DOUT_LONG_WAIT_DEN);
480}
481
482static void dout_long_den(struct FsmInst *fsm, int event, void *arg)
483{
484 struct st5481_adapter *adapter = fsm->userdata;
485 struct st5481_d_out *d_out = &adapter->d_out;
486
487 FsmChangeState(&d_out->fsm, ST_DOUT_NORMAL);
488 usb_d_out(adapter, 0);
489 usb_d_out(adapter, 1);
490}
491
492static void dout_reset(struct FsmInst *fsm, int event, void *arg)
493{
494 struct st5481_adapter *adapter = fsm->userdata;
495 struct st5481_d_out *d_out = &adapter->d_out;
496
497 FsmChangeState(&d_out->fsm, ST_DOUT_WAIT_FOR_RESET);
498 st5481_usb_pipe_reset(adapter, EP_D_OUT | USB_DIR_OUT, fifo_reseted, adapter);
499}
500
501static void dout_stop(struct FsmInst *fsm, int event, void *arg)
502{
503 struct st5481_adapter *adapter = fsm->userdata;
504 struct st5481_d_out *d_out = &adapter->d_out;
505
506 FsmChangeState(&d_out->fsm, ST_DOUT_WAIT_FOR_STOP);
507 st5481_usb_device_ctrl_msg(adapter, OUT_D_COUNTER, 0, dout_stop_event, adapter);
508}
509
510static void dout_underrun(struct FsmInst *fsm, int event, void *arg)
511{
512 struct st5481_adapter *adapter = fsm->userdata;
513 struct st5481_d_out *d_out = &adapter->d_out;
514
515 if (test_bit(0, &d_out->busy) || test_bit(1, &d_out->busy)) {
516 FsmChangeState(&d_out->fsm, ST_DOUT_WAIT_FOR_NOT_BUSY);
517 } else {
518 dout_stop(fsm, event, arg);
519 }
520}
521
522static void dout_check_busy(struct FsmInst *fsm, int event, void *arg)
523{
524 struct st5481_adapter *adapter = fsm->userdata;
525 struct st5481_d_out *d_out = &adapter->d_out;
526
527 if (!test_bit(0, &d_out->busy) && !test_bit(1, &d_out->busy))
528 dout_stop(fsm, event, arg);
529}
530
531static void dout_reseted(struct FsmInst *fsm, int event, void *arg)
532{
533 struct st5481_adapter *adapter = fsm->userdata;
534 struct st5481_d_out *d_out = &adapter->d_out;
535
536 FsmChangeState(&d_out->fsm, ST_DOUT_NONE);
537 // FIXME locking
538 if (d_out->tx_skb)
539 FsmEvent(&d_out->fsm, EV_DOUT_START_XMIT, NULL);
540}
541
542static void dout_complete(struct FsmInst *fsm, int event, void *arg)
543{
544 struct st5481_adapter *adapter = fsm->userdata;
545 int buf_nr = (int) arg;
546
547 usb_d_out(adapter, buf_nr);
548}
549
550static void dout_ignore(struct FsmInst *fsm, int event, void *arg)
551{
552}
553
554static struct FsmNode DoutFnList[] __initdata =
555{
556 {ST_DOUT_NONE, EV_DOUT_START_XMIT, dout_start_xmit},
557
558 {ST_DOUT_SHORT_INIT, EV_DOUT_COMPLETE, dout_short_fifo},
559
560 {ST_DOUT_SHORT_WAIT_DEN, EV_DOUT_DEN, dout_end_short_frame},
561 {ST_DOUT_SHORT_WAIT_DEN, EV_DOUT_UNDERRUN, dout_underrun},
562
563 {ST_DOUT_LONG_INIT, EV_DOUT_COMPLETE, dout_long_enable_fifo},
564
565 {ST_DOUT_LONG_WAIT_DEN, EV_DOUT_DEN, dout_long_den},
566 {ST_DOUT_LONG_WAIT_DEN, EV_DOUT_UNDERRUN, dout_underrun},
567
568 {ST_DOUT_NORMAL, EV_DOUT_UNDERRUN, dout_underrun},
569 {ST_DOUT_NORMAL, EV_DOUT_COMPLETE, dout_complete},
570
571 {ST_DOUT_WAIT_FOR_UNDERRUN, EV_DOUT_UNDERRUN, dout_underrun},
572 {ST_DOUT_WAIT_FOR_UNDERRUN, EV_DOUT_COMPLETE, dout_ignore},
573
574 {ST_DOUT_WAIT_FOR_NOT_BUSY, EV_DOUT_COMPLETE, dout_check_busy},
575
576 {ST_DOUT_WAIT_FOR_STOP, EV_DOUT_STOPPED, dout_reset},
577
578 {ST_DOUT_WAIT_FOR_RESET, EV_DOUT_RESETED, dout_reseted},
579};
580
581void st5481_d_l2l1(struct hisax_if *hisax_d_if, int pr, void *arg)
582{
583 struct st5481_adapter *adapter = hisax_d_if->priv;
584 struct sk_buff *skb = arg;
585
586 switch (pr) {
587 case PH_ACTIVATE | REQUEST:
588 FsmEvent(&adapter->l1m, EV_PH_ACTIVATE_REQ, NULL);
589 break;
590 case PH_DEACTIVATE | REQUEST:
591 FsmEvent(&adapter->l1m, EV_PH_DEACTIVATE_REQ, NULL);
592 break;
593 case PH_DATA | REQUEST:
594 DBG(2, "PH_DATA REQUEST len %d", skb->len);
595 if (adapter->d_out.tx_skb)
596 BUG();
597
598 adapter->d_out.tx_skb = skb;
599 FsmEvent(&adapter->d_out.fsm, EV_DOUT_START_XMIT, NULL);
600 break;
601 default:
602 WARN("pr %#x\n", pr);
603 break;
604 }
605}
606
607/* ======================================================================
608 */
609
610/*
611 * Start receiving on the D channel since entered state F7.
612 */
613static void ph_connect(struct st5481_adapter *adapter)
614{
615 struct st5481_d_out *d_out = &adapter->d_out;
616 struct st5481_in *d_in = &adapter->d_in;
617
618 DBG(8,"");
619
620 FsmChangeState(&d_out->fsm, ST_DOUT_NONE);
621
622 // st5481_usb_device_ctrl_msg(adapter, FFMSK_D, OUT_UNDERRUN, NULL, NULL);
623 st5481_usb_device_ctrl_msg(adapter, FFMSK_D, 0xfc, NULL, NULL);
624 st5481_in_mode(d_in, L1_MODE_HDLC);
625
626#ifdef LOOPBACK
627 // Turn loopback on (data sent on B and D looped back)
628 st5481_usb_device_ctrl_msg(cs, LBB, 0x04, NULL, NULL);
629#endif
630
631 st5481_usb_pipe_reset(adapter, EP_D_OUT | USB_DIR_OUT, NULL, NULL);
632
633 // Turn on the green LED to tell that we are in state F7
634 adapter->leds |= GREEN_LED;
635 st5481_usb_device_ctrl_msg(adapter, GPIO_OUT, adapter->leds, NULL, NULL);
636}
637
638/*
639 * Stop receiving on the D channel since not in state F7.
640 */
641static void ph_disconnect(struct st5481_adapter *adapter)
642{
643 DBG(8,"");
644
645 st5481_in_mode(&adapter->d_in, L1_MODE_NULL);
646
647 // Turn off the green LED to tell that we left state F7
648 adapter->leds &= ~GREEN_LED;
649 st5481_usb_device_ctrl_msg(adapter, GPIO_OUT, adapter->leds, NULL, NULL);
650}
651
652static int st5481_setup_d_out(struct st5481_adapter *adapter)
653{
654 struct usb_device *dev = adapter->usb_dev;
655 struct usb_interface *intf;
656 struct usb_host_interface *altsetting = NULL;
657 struct usb_host_endpoint *endpoint;
658 struct st5481_d_out *d_out = &adapter->d_out;
659
660 DBG(2,"");
661
662 intf = usb_ifnum_to_if(dev, 0);
663 if (intf)
664 altsetting = usb_altnum_to_altsetting(intf, 3);
665 if (!altsetting)
666 return -ENXIO;
667
668 // Allocate URBs and buffers for the D channel out
669 endpoint = &altsetting->endpoint[EP_D_OUT-1];
670
671 DBG(2,"endpoint address=%02x,packet size=%d",
672 endpoint->desc.bEndpointAddress, le16_to_cpu(endpoint->desc.wMaxPacketSize));
673
674 return st5481_setup_isocpipes(d_out->urb, dev,
675 usb_sndisocpipe(dev, endpoint->desc.bEndpointAddress),
676 NUM_ISO_PACKETS_D, SIZE_ISO_PACKETS_D_OUT,
677 NUM_ISO_PACKETS_D * SIZE_ISO_PACKETS_D_OUT,
678 usb_d_out_complete, adapter);
679}
680
681static void st5481_release_d_out(struct st5481_adapter *adapter)
682{
683 struct st5481_d_out *d_out = &adapter->d_out;
684
685 DBG(2,"");
686
687 st5481_release_isocpipes(d_out->urb);
688}
689
690int st5481_setup_d(struct st5481_adapter *adapter)
691{
692 int retval;
693
694 DBG(2,"");
695
696 retval = st5481_setup_d_out(adapter);
697 if (retval)
698 goto err;
699 adapter->d_in.bufsize = MAX_DFRAME_LEN_L1;
700 adapter->d_in.num_packets = NUM_ISO_PACKETS_D;
701 adapter->d_in.packet_size = SIZE_ISO_PACKETS_D_IN;
702 adapter->d_in.ep = EP_D_IN | USB_DIR_IN;
703 adapter->d_in.counter = IN_D_COUNTER;
704 adapter->d_in.adapter = adapter;
705 adapter->d_in.hisax_if = &adapter->hisax_d_if.ifc;
706 retval = st5481_setup_in(&adapter->d_in);
707 if (retval)
708 goto err_d_out;
709
710 adapter->l1m.fsm = &l1fsm;
711 adapter->l1m.state = ST_L1_F3;
712 adapter->l1m.debug = 1;
713 adapter->l1m.userdata = adapter;
714 adapter->l1m.printdebug = l1m_debug;
715 FsmInitTimer(&adapter->l1m, &adapter->timer);
716
717 adapter->d_out.fsm.fsm = &dout_fsm;
718 adapter->d_out.fsm.state = ST_DOUT_NONE;
719 adapter->d_out.fsm.debug = 1;
720 adapter->d_out.fsm.userdata = adapter;
721 adapter->d_out.fsm.printdebug = dout_debug;
722
723 return 0;
724
725 err_d_out:
726 st5481_release_d_out(adapter);
727 err:
728 return retval;
729}
730
731void st5481_release_d(struct st5481_adapter *adapter)
732{
733 DBG(2,"");
734
735 st5481_release_in(&adapter->d_in);
736 st5481_release_d_out(adapter);
737}
738
739/* ======================================================================
740 * init / exit
741 */
742
743int __init st5481_d_init(void)
744{
745 int retval;
746
747 l1fsm.state_count = L1_STATE_COUNT;
748 l1fsm.event_count = L1_EVENT_COUNT;
749 l1fsm.strEvent = strL1Event;
750 l1fsm.strState = strL1State;
751 retval = FsmNew(&l1fsm, L1FnList, ARRAY_SIZE(L1FnList));
752 if (retval)
753 goto err;
754
755 dout_fsm.state_count = DOUT_STATE_COUNT;
756 dout_fsm.event_count = DOUT_EVENT_COUNT;
757 dout_fsm.strEvent = strDoutEvent;
758 dout_fsm.strState = strDoutState;
759 retval = FsmNew(&dout_fsm, DoutFnList, ARRAY_SIZE(DoutFnList));
760 if (retval)
761 goto err_l1;
762
763 return 0;
764
765 err_l1:
766 FsmFree(&l1fsm);
767 err:
768 return retval;
769}
770
771// can't be __exit
772void st5481_d_exit(void)
773{
774 FsmFree(&l1fsm);
775 FsmFree(&dout_fsm);
776}
diff --git a/drivers/isdn/hisax/st5481_hdlc.c b/drivers/isdn/hisax/st5481_hdlc.c
new file mode 100644
index 000000000000..680f42e9a993
--- /dev/null
+++ b/drivers/isdn/hisax/st5481_hdlc.c
@@ -0,0 +1,580 @@
1/*
2 * Driver for ST5481 USB ISDN modem
3 *
4 * Author Frode Isaksen
5 * Copyright 2001 by Frode Isaksen <fisaksen@bewan.com>
6 * 2001 by Kai Germaschewski <kai.germaschewski@gmx.de>
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 */
12
13#include <linux/crc-ccitt.h>
14#include "st5481_hdlc.h"
15
16
17enum {
18 HDLC_FAST_IDLE,HDLC_GET_FLAG_B0,HDLC_GETFLAG_B1A6,HDLC_GETFLAG_B7,
19 HDLC_GET_DATA,HDLC_FAST_FLAG
20};
21
22enum {
23 HDLC_SEND_DATA,HDLC_SEND_CRC1,HDLC_SEND_FAST_FLAG,
24 HDLC_SEND_FIRST_FLAG,HDLC_SEND_CRC2,HDLC_SEND_CLOSING_FLAG,
25 HDLC_SEND_IDLE1,HDLC_SEND_FAST_IDLE,HDLC_SENDFLAG_B0,
26 HDLC_SENDFLAG_B1A6,HDLC_SENDFLAG_B7,STOPPED
27};
28
29void
30hdlc_rcv_init(struct hdlc_vars *hdlc, int do_adapt56)
31{
32 hdlc->bit_shift = 0;
33 hdlc->hdlc_bits1 = 0;
34 hdlc->data_bits = 0;
35 hdlc->ffbit_shift = 0;
36 hdlc->data_received = 0;
37 hdlc->state = HDLC_GET_DATA;
38 hdlc->do_adapt56 = do_adapt56;
39 hdlc->dchannel = 0;
40 hdlc->crc = 0;
41 hdlc->cbin = 0;
42 hdlc->shift_reg = 0;
43 hdlc->ffvalue = 0;
44 hdlc->dstpos = 0;
45}
46
47void
48hdlc_out_init(struct hdlc_vars *hdlc, int is_d_channel, int do_adapt56)
49{
50 hdlc->bit_shift = 0;
51 hdlc->hdlc_bits1 = 0;
52 hdlc->data_bits = 0;
53 hdlc->ffbit_shift = 0;
54 hdlc->data_received = 0;
55 hdlc->do_closing = 0;
56 hdlc->ffvalue = 0;
57 if (is_d_channel) {
58 hdlc->dchannel = 1;
59 hdlc->state = HDLC_SEND_FIRST_FLAG;
60 } else {
61 hdlc->dchannel = 0;
62 hdlc->state = HDLC_SEND_FAST_FLAG;
63 hdlc->ffvalue = 0x7e;
64 }
65 hdlc->cbin = 0x7e;
66 hdlc->bit_shift = 0;
67 if(do_adapt56){
68 hdlc->do_adapt56 = 1;
69 hdlc->data_bits = 0;
70 hdlc->state = HDLC_SENDFLAG_B0;
71 } else {
72 hdlc->do_adapt56 = 0;
73 hdlc->data_bits = 8;
74 }
75 hdlc->shift_reg = 0;
76}
77
78/*
79 hdlc_decode - decodes HDLC frames from a transparent bit stream.
80
81 The source buffer is scanned for valid HDLC frames looking for
82 flags (01111110) to indicate the start of a frame. If the start of
83 the frame is found, the bit stuffing is removed (0 after 5 1's).
84 When a new flag is found, the complete frame has been received
85 and the CRC is checked.
86 If a valid frame is found, the function returns the frame length
87 excluding the CRC with the bit HDLC_END_OF_FRAME set.
88 If the beginning of a valid frame is found, the function returns
89 the length.
90 If a framing error is found (too many 1s and not a flag) the function
91 returns the length with the bit HDLC_FRAMING_ERROR set.
92 If a CRC error is found the function returns the length with the
93 bit HDLC_CRC_ERROR set.
94 If the frame length exceeds the destination buffer size, the function
95 returns the length with the bit HDLC_LENGTH_ERROR set.
96
97 src - source buffer
98 slen - source buffer length
99 count - number of bytes removed (decoded) from the source buffer
100 dst _ destination buffer
101 dsize - destination buffer size
102 returns - number of decoded bytes in the destination buffer and status
103 flag.
104 */
105int hdlc_decode(struct hdlc_vars *hdlc, const unsigned char *src,
106 int slen, int *count, unsigned char *dst, int dsize)
107{
108 int status=0;
109
110 static const unsigned char fast_flag[]={
111 0x00,0x00,0x00,0x20,0x30,0x38,0x3c,0x3e,0x3f
112 };
113
114 static const unsigned char fast_flag_value[]={
115 0x00,0x7e,0xfc,0xf9,0xf3,0xe7,0xcf,0x9f,0x3f
116 };
117
118 static const unsigned char fast_abort[]={
119 0x00,0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff
120 };
121
122 *count = slen;
123
124 while(slen > 0){
125 if(hdlc->bit_shift==0){
126 hdlc->cbin = *src++;
127 slen--;
128 hdlc->bit_shift = 8;
129 if(hdlc->do_adapt56){
130 hdlc->bit_shift --;
131 }
132 }
133
134 switch(hdlc->state){
135 case STOPPED:
136 return 0;
137 case HDLC_FAST_IDLE:
138 if(hdlc->cbin == 0xff){
139 hdlc->bit_shift = 0;
140 break;
141 }
142 hdlc->state = HDLC_GET_FLAG_B0;
143 hdlc->hdlc_bits1 = 0;
144 hdlc->bit_shift = 8;
145 break;
146 case HDLC_GET_FLAG_B0:
147 if(!(hdlc->cbin & 0x80)) {
148 hdlc->state = HDLC_GETFLAG_B1A6;
149 hdlc->hdlc_bits1 = 0;
150 } else {
151 if(!hdlc->do_adapt56){
152 if(++hdlc->hdlc_bits1 >=8 ) if(hdlc->bit_shift==1)
153 hdlc->state = HDLC_FAST_IDLE;
154 }
155 }
156 hdlc->cbin<<=1;
157 hdlc->bit_shift --;
158 break;
159 case HDLC_GETFLAG_B1A6:
160 if(hdlc->cbin & 0x80){
161 hdlc->hdlc_bits1++;
162 if(hdlc->hdlc_bits1==6){
163 hdlc->state = HDLC_GETFLAG_B7;
164 }
165 } else {
166 hdlc->hdlc_bits1 = 0;
167 }
168 hdlc->cbin<<=1;
169 hdlc->bit_shift --;
170 break;
171 case HDLC_GETFLAG_B7:
172 if(hdlc->cbin & 0x80) {
173 hdlc->state = HDLC_GET_FLAG_B0;
174 } else {
175 hdlc->state = HDLC_GET_DATA;
176 hdlc->crc = 0xffff;
177 hdlc->shift_reg = 0;
178 hdlc->hdlc_bits1 = 0;
179 hdlc->data_bits = 0;
180 hdlc->data_received = 0;
181 }
182 hdlc->cbin<<=1;
183 hdlc->bit_shift --;
184 break;
185 case HDLC_GET_DATA:
186 if(hdlc->cbin & 0x80){
187 hdlc->hdlc_bits1++;
188 switch(hdlc->hdlc_bits1){
189 case 6:
190 break;
191 case 7:
192 if(hdlc->data_received) {
193 // bad frame
194 status = -HDLC_FRAMING_ERROR;
195 }
196 if(!hdlc->do_adapt56){
197 if(hdlc->cbin==fast_abort[hdlc->bit_shift+1]){
198 hdlc->state = HDLC_FAST_IDLE;
199 hdlc->bit_shift=1;
200 break;
201 }
202 } else {
203 hdlc->state = HDLC_GET_FLAG_B0;
204 }
205 break;
206 default:
207 hdlc->shift_reg>>=1;
208 hdlc->shift_reg |= 0x80;
209 hdlc->data_bits++;
210 break;
211 }
212 } else {
213 switch(hdlc->hdlc_bits1){
214 case 5:
215 break;
216 case 6:
217 if(hdlc->data_received){
218 if (hdlc->dstpos < 2) {
219 status = -HDLC_FRAMING_ERROR;
220 } else if (hdlc->crc != 0xf0b8){
221 // crc error
222 status = -HDLC_CRC_ERROR;
223 } else {
224 // remove CRC
225 hdlc->dstpos -= 2;
226 // good frame
227 status = hdlc->dstpos;
228 }
229 }
230 hdlc->crc = 0xffff;
231 hdlc->shift_reg = 0;
232 hdlc->data_bits = 0;
233 if(!hdlc->do_adapt56){
234 if(hdlc->cbin==fast_flag[hdlc->bit_shift]){
235 hdlc->ffvalue = fast_flag_value[hdlc->bit_shift];
236 hdlc->state = HDLC_FAST_FLAG;
237 hdlc->ffbit_shift = hdlc->bit_shift;
238 hdlc->bit_shift = 1;
239 } else {
240 hdlc->state = HDLC_GET_DATA;
241 hdlc->data_received = 0;
242 }
243 } else {
244 hdlc->state = HDLC_GET_DATA;
245 hdlc->data_received = 0;
246 }
247 break;
248 default:
249 hdlc->shift_reg>>=1;
250 hdlc->data_bits++;
251 break;
252 }
253 hdlc->hdlc_bits1 = 0;
254 }
255 if (status) {
256 hdlc->dstpos = 0;
257 *count -= slen;
258 hdlc->cbin <<= 1;
259 hdlc->bit_shift--;
260 return status;
261 }
262 if(hdlc->data_bits==8){
263 hdlc->data_bits = 0;
264 hdlc->data_received = 1;
265 hdlc->crc = crc_ccitt_byte(hdlc->crc, hdlc->shift_reg);
266
267 // good byte received
268 if (dsize--) {
269 dst[hdlc->dstpos++] = hdlc->shift_reg;
270 } else {
271 // frame too long
272 status = -HDLC_LENGTH_ERROR;
273 hdlc->dstpos = 0;
274 }
275 }
276 hdlc->cbin <<= 1;
277 hdlc->bit_shift--;
278 break;
279 case HDLC_FAST_FLAG:
280 if(hdlc->cbin==hdlc->ffvalue){
281 hdlc->bit_shift = 0;
282 break;
283 } else {
284 if(hdlc->cbin == 0xff){
285 hdlc->state = HDLC_FAST_IDLE;
286 hdlc->bit_shift=0;
287 } else if(hdlc->ffbit_shift==8){
288 hdlc->state = HDLC_GETFLAG_B7;
289 break;
290 } else {
291 hdlc->shift_reg = fast_abort[hdlc->ffbit_shift-1];
292 hdlc->hdlc_bits1 = hdlc->ffbit_shift-2;
293 if(hdlc->hdlc_bits1<0)hdlc->hdlc_bits1 = 0;
294 hdlc->data_bits = hdlc->ffbit_shift-1;
295 hdlc->state = HDLC_GET_DATA;
296 hdlc->data_received = 0;
297 }
298 }
299 break;
300 default:
301 break;
302 }
303 }
304 *count -= slen;
305 return 0;
306}
307
308/*
309 hdlc_encode - encodes HDLC frames to a transparent bit stream.
310
311 The bit stream starts with a beginning flag (01111110). After
312 that each byte is added to the bit stream with bit stuffing added
313 (0 after 5 1's).
314 When the last byte has been removed from the source buffer, the
315 CRC (2 bytes is added) and the frame terminates with the ending flag.
316 For the dchannel, the idle character (all 1's) is also added at the end.
317 If this function is called with empty source buffer (slen=0), flags or
318 idle character will be generated.
319
320 src - source buffer
321 slen - source buffer length
322 count - number of bytes removed (encoded) from source buffer
323 dst _ destination buffer
324 dsize - destination buffer size
325 returns - number of encoded bytes in the destination buffer
326*/
327int hdlc_encode(struct hdlc_vars *hdlc, const unsigned char *src,
328 unsigned short slen, int *count,
329 unsigned char *dst, int dsize)
330{
331 static const unsigned char xfast_flag_value[] = {
332 0x7e,0x3f,0x9f,0xcf,0xe7,0xf3,0xf9,0xfc,0x7e
333 };
334
335 int len = 0;
336
337 *count = slen;
338
339 while (dsize > 0) {
340 if(hdlc->bit_shift==0){
341 if(slen && !hdlc->do_closing){
342 hdlc->shift_reg = *src++;
343 slen--;
344 if (slen == 0)
345 hdlc->do_closing = 1; /* closing sequence, CRC + flag(s) */
346 hdlc->bit_shift = 8;
347 } else {
348 if(hdlc->state == HDLC_SEND_DATA){
349 if(hdlc->data_received){
350 hdlc->state = HDLC_SEND_CRC1;
351 hdlc->crc ^= 0xffff;
352 hdlc->bit_shift = 8;
353 hdlc->shift_reg = hdlc->crc & 0xff;
354 } else if(!hdlc->do_adapt56){
355 hdlc->state = HDLC_SEND_FAST_FLAG;
356 } else {
357 hdlc->state = HDLC_SENDFLAG_B0;
358 }
359 }
360
361 }
362 }
363
364 switch(hdlc->state){
365 case STOPPED:
366 while (dsize--)
367 *dst++ = 0xff;
368
369 return dsize;
370 case HDLC_SEND_FAST_FLAG:
371 hdlc->do_closing = 0;
372 if(slen == 0){
373 *dst++ = hdlc->ffvalue;
374 len++;
375 dsize--;
376 break;
377 }
378 if(hdlc->bit_shift==8){
379 hdlc->cbin = hdlc->ffvalue>>(8-hdlc->data_bits);
380 hdlc->state = HDLC_SEND_DATA;
381 hdlc->crc = 0xffff;
382 hdlc->hdlc_bits1 = 0;
383 hdlc->data_received = 1;
384 }
385 break;
386 case HDLC_SENDFLAG_B0:
387 hdlc->do_closing = 0;
388 hdlc->cbin <<= 1;
389 hdlc->data_bits++;
390 hdlc->hdlc_bits1 = 0;
391 hdlc->state = HDLC_SENDFLAG_B1A6;
392 break;
393 case HDLC_SENDFLAG_B1A6:
394 hdlc->cbin <<= 1;
395 hdlc->data_bits++;
396 hdlc->cbin++;
397 if(++hdlc->hdlc_bits1 == 6)
398 hdlc->state = HDLC_SENDFLAG_B7;
399 break;
400 case HDLC_SENDFLAG_B7:
401 hdlc->cbin <<= 1;
402 hdlc->data_bits++;
403 if(slen == 0){
404 hdlc->state = HDLC_SENDFLAG_B0;
405 break;
406 }
407 if(hdlc->bit_shift==8){
408 hdlc->state = HDLC_SEND_DATA;
409 hdlc->crc = 0xffff;
410 hdlc->hdlc_bits1 = 0;
411 hdlc->data_received = 1;
412 }
413 break;
414 case HDLC_SEND_FIRST_FLAG:
415 hdlc->data_received = 1;
416 if(hdlc->data_bits==8){
417 hdlc->state = HDLC_SEND_DATA;
418 hdlc->crc = 0xffff;
419 hdlc->hdlc_bits1 = 0;
420 break;
421 }
422 hdlc->cbin <<= 1;
423 hdlc->data_bits++;
424 if(hdlc->shift_reg & 0x01)
425 hdlc->cbin++;
426 hdlc->shift_reg >>= 1;
427 hdlc->bit_shift--;
428 if(hdlc->bit_shift==0){
429 hdlc->state = HDLC_SEND_DATA;
430 hdlc->crc = 0xffff;
431 hdlc->hdlc_bits1 = 0;
432 }
433 break;
434 case HDLC_SEND_DATA:
435 hdlc->cbin <<= 1;
436 hdlc->data_bits++;
437 if(hdlc->hdlc_bits1 == 5){
438 hdlc->hdlc_bits1 = 0;
439 break;
440 }
441 if(hdlc->bit_shift==8){
442 hdlc->crc = crc_ccitt_byte(hdlc->crc, hdlc->shift_reg);
443 }
444 if(hdlc->shift_reg & 0x01){
445 hdlc->hdlc_bits1++;
446 hdlc->cbin++;
447 hdlc->shift_reg >>= 1;
448 hdlc->bit_shift--;
449 } else {
450 hdlc->hdlc_bits1 = 0;
451 hdlc->shift_reg >>= 1;
452 hdlc->bit_shift--;
453 }
454 break;
455 case HDLC_SEND_CRC1:
456 hdlc->cbin <<= 1;
457 hdlc->data_bits++;
458 if(hdlc->hdlc_bits1 == 5){
459 hdlc->hdlc_bits1 = 0;
460 break;
461 }
462 if(hdlc->shift_reg & 0x01){
463 hdlc->hdlc_bits1++;
464 hdlc->cbin++;
465 hdlc->shift_reg >>= 1;
466 hdlc->bit_shift--;
467 } else {
468 hdlc->hdlc_bits1 = 0;
469 hdlc->shift_reg >>= 1;
470 hdlc->bit_shift--;
471 }
472 if(hdlc->bit_shift==0){
473 hdlc->shift_reg = (hdlc->crc >> 8);
474 hdlc->state = HDLC_SEND_CRC2;
475 hdlc->bit_shift = 8;
476 }
477 break;
478 case HDLC_SEND_CRC2:
479 hdlc->cbin <<= 1;
480 hdlc->data_bits++;
481 if(hdlc->hdlc_bits1 == 5){
482 hdlc->hdlc_bits1 = 0;
483 break;
484 }
485 if(hdlc->shift_reg & 0x01){
486 hdlc->hdlc_bits1++;
487 hdlc->cbin++;
488 hdlc->shift_reg >>= 1;
489 hdlc->bit_shift--;
490 } else {
491 hdlc->hdlc_bits1 = 0;
492 hdlc->shift_reg >>= 1;
493 hdlc->bit_shift--;
494 }
495 if(hdlc->bit_shift==0){
496 hdlc->shift_reg = 0x7e;
497 hdlc->state = HDLC_SEND_CLOSING_FLAG;
498 hdlc->bit_shift = 8;
499 }
500 break;
501 case HDLC_SEND_CLOSING_FLAG:
502 hdlc->cbin <<= 1;
503 hdlc->data_bits++;
504 if(hdlc->hdlc_bits1 == 5){
505 hdlc->hdlc_bits1 = 0;
506 break;
507 }
508 if(hdlc->shift_reg & 0x01){
509 hdlc->cbin++;
510 }
511 hdlc->shift_reg >>= 1;
512 hdlc->bit_shift--;
513 if(hdlc->bit_shift==0){
514 hdlc->ffvalue = xfast_flag_value[hdlc->data_bits];
515 if(hdlc->dchannel){
516 hdlc->ffvalue = 0x7e;
517 hdlc->state = HDLC_SEND_IDLE1;
518 hdlc->bit_shift = 8-hdlc->data_bits;
519 if(hdlc->bit_shift==0)
520 hdlc->state = HDLC_SEND_FAST_IDLE;
521 } else {
522 if(!hdlc->do_adapt56){
523 hdlc->state = HDLC_SEND_FAST_FLAG;
524 hdlc->data_received = 0;
525 } else {
526 hdlc->state = HDLC_SENDFLAG_B0;
527 hdlc->data_received = 0;
528 }
529 // Finished with this frame, send flags
530 if (dsize > 1) dsize = 1;
531 }
532 }
533 break;
534 case HDLC_SEND_IDLE1:
535 hdlc->do_closing = 0;
536 hdlc->cbin <<= 1;
537 hdlc->cbin++;
538 hdlc->data_bits++;
539 hdlc->bit_shift--;
540 if(hdlc->bit_shift==0){
541 hdlc->state = HDLC_SEND_FAST_IDLE;
542 hdlc->bit_shift = 0;
543 }
544 break;
545 case HDLC_SEND_FAST_IDLE:
546 hdlc->do_closing = 0;
547 hdlc->cbin = 0xff;
548 hdlc->data_bits = 8;
549 if(hdlc->bit_shift == 8){
550 hdlc->cbin = 0x7e;
551 hdlc->state = HDLC_SEND_FIRST_FLAG;
552 } else {
553 *dst++ = hdlc->cbin;
554 hdlc->bit_shift = hdlc->data_bits = 0;
555 len++;
556 dsize = 0;
557 }
558 break;
559 default:
560 break;
561 }
562 if(hdlc->do_adapt56){
563 if(hdlc->data_bits==7){
564 hdlc->cbin <<= 1;
565 hdlc->cbin++;
566 hdlc->data_bits++;
567 }
568 }
569 if(hdlc->data_bits==8){
570 *dst++ = hdlc->cbin;
571 hdlc->data_bits = 0;
572 len++;
573 dsize--;
574 }
575 }
576 *count -= slen;
577
578 return len;
579}
580
diff --git a/drivers/isdn/hisax/st5481_hdlc.h b/drivers/isdn/hisax/st5481_hdlc.h
new file mode 100644
index 000000000000..495432f0f6ba
--- /dev/null
+++ b/drivers/isdn/hisax/st5481_hdlc.h
@@ -0,0 +1,62 @@
1/*
2 * Driver for ST5481 USB ISDN modem
3 *
4 * Author Frode Isaksen
5 * Copyright 2001 by Frode Isaksen <fisaksen@bewan.com>
6 * 2001 by Kai Germaschewski <kai.germaschewski@gmx.de>
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 */
12
13#ifndef __ST5481_HDLC_H__
14#define __ST5481_HDLC_H__
15
16struct hdlc_vars {
17 int bit_shift;
18 int hdlc_bits1;
19 int data_bits;
20 int ffbit_shift; // encoding only
21 int state;
22 int dstpos;
23
24 int data_received:1; // set if transferring data
25 int dchannel:1; // set if D channel (send idle instead of flags)
26 int do_adapt56:1; // set if 56K adaptation
27 int do_closing:1; // set if in closing phase (need to send CRC + flag
28
29 unsigned short crc;
30
31 unsigned char cbin;
32 unsigned char shift_reg;
33 unsigned char ffvalue;
34
35};
36
37
38/*
39 The return value from hdlc_decode is
40 the frame length, 0 if no complete frame was decoded,
41 or a negative error number
42*/
43
44#define HDLC_FRAMING_ERROR 1
45#define HDLC_CRC_ERROR 2
46#define HDLC_LENGTH_ERROR 3
47
48void
49hdlc_rcv_init(struct hdlc_vars *hdlc, int do_adapt56);
50
51int
52hdlc_decode(struct hdlc_vars *hdlc, const unsigned char *src, int slen,int *count,
53 unsigned char *dst, int dsize);
54
55void
56hdlc_out_init(struct hdlc_vars *hdlc,int is_d_channel,int do_adapt56);
57
58int
59hdlc_encode(struct hdlc_vars *hdlc,const unsigned char *src,unsigned short slen,int *count,
60 unsigned char *dst,int dsize);
61
62#endif
diff --git a/drivers/isdn/hisax/st5481_init.c b/drivers/isdn/hisax/st5481_init.c
new file mode 100644
index 000000000000..7aa810d5d333
--- /dev/null
+++ b/drivers/isdn/hisax/st5481_init.c
@@ -0,0 +1,224 @@
1/*
2 * Driver for ST5481 USB ISDN modem
3 *
4 * Author Frode Isaksen
5 * Copyright 2001 by Frode Isaksen <fisaksen@bewan.com>
6 * 2001 by Kai Germaschewski <kai.germaschewski@gmx.de>
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 */
12
13/*
14 * TODO:
15 *
16 * b layer1 delay?
17 * hotplug / unregister issues
18 * mod_inc/dec_use_count
19 * unify parts of d/b channel usb handling
20 * file header
21 * avoid copy to isoc buffer?
22 * improve usb delay?
23 * merge l1 state machines?
24 * clean up debug
25 */
26
27#include <linux/config.h>
28#include <linux/version.h>
29#include <linux/module.h>
30#include <linux/init.h>
31#include <linux/usb.h>
32#include <linux/slab.h>
33#include "st5481.h"
34
35MODULE_DESCRIPTION("ISDN4Linux: driver for ST5481 USB ISDN adapter");
36MODULE_AUTHOR("Frode Isaksen");
37MODULE_LICENSE("GPL");
38
39static int protocol = 2; /* EURO-ISDN Default */
40module_param(protocol, int, 0);
41
42static int number_of_leds = 2; /* 2 LEDs on the adpater default */
43module_param(number_of_leds, int, 0);
44
45#ifdef CONFIG_HISAX_DEBUG
46static int debug = 0x1;
47module_param(debug, int, 0);
48int st5481_debug;
49#endif
50
51static LIST_HEAD(adapter_list);
52
53/* ======================================================================
54 * registration/deregistration with the USB layer
55 */
56
57/*
58 * This function will be called when the adapter is plugged
59 * into the USB bus.
60 */
61static int probe_st5481(struct usb_interface *intf,
62 const struct usb_device_id *id)
63{
64 struct usb_device *dev = interface_to_usbdev(intf);
65 struct st5481_adapter *adapter;
66 struct hisax_b_if *b_if[2];
67 int retval, i;
68
69 printk(KERN_INFO "st541: found adapter VendorId %04x, ProductId %04x, LEDs %d\n",
70 le16_to_cpu(dev->descriptor.idVendor),
71 le16_to_cpu(dev->descriptor.idProduct),
72 number_of_leds);
73
74 adapter = kmalloc(sizeof(struct st5481_adapter), GFP_KERNEL);
75 if (!adapter)
76 return -ENOMEM;
77
78 memset(adapter, 0, sizeof(struct st5481_adapter));
79
80 adapter->number_of_leds = number_of_leds;
81 adapter->usb_dev = dev;
82
83 adapter->hisax_d_if.owner = THIS_MODULE;
84 adapter->hisax_d_if.ifc.priv = adapter;
85 adapter->hisax_d_if.ifc.l2l1 = st5481_d_l2l1;
86
87 for (i = 0; i < 2; i++) {
88 adapter->bcs[i].adapter = adapter;
89 adapter->bcs[i].channel = i;
90 adapter->bcs[i].b_if.ifc.priv = &adapter->bcs[i];
91 adapter->bcs[i].b_if.ifc.l2l1 = st5481_b_l2l1;
92 }
93 list_add(&adapter->list, &adapter_list);
94
95 retval = st5481_setup_usb(adapter);
96 if (retval < 0)
97 goto err;
98
99 retval = st5481_setup_d(adapter);
100 if (retval < 0)
101 goto err_usb;
102
103 retval = st5481_setup_b(&adapter->bcs[0]);
104 if (retval < 0)
105 goto err_d;
106
107 retval = st5481_setup_b(&adapter->bcs[1]);
108 if (retval < 0)
109 goto err_b;
110
111 for (i = 0; i < 2; i++)
112 b_if[i] = &adapter->bcs[i].b_if;
113
114 hisax_register(&adapter->hisax_d_if, b_if, "st5481_usb", protocol);
115 st5481_start(adapter);
116
117 usb_set_intfdata(intf, adapter);
118 return 0;
119
120 err_b:
121 st5481_release_b(&adapter->bcs[0]);
122 err_d:
123 st5481_release_d(adapter);
124 err_usb:
125 st5481_release_usb(adapter);
126 err:
127 return -EIO;
128}
129
130/*
131 * This function will be called when the adapter is removed
132 * from the USB bus.
133 */
134static void disconnect_st5481(struct usb_interface *intf)
135{
136 struct st5481_adapter *adapter = usb_get_intfdata(intf);
137
138 DBG(1,"");
139
140 usb_set_intfdata(intf, NULL);
141 if (!adapter)
142 return;
143
144 list_del(&adapter->list);
145
146 st5481_stop(adapter);
147 st5481_release_b(&adapter->bcs[1]);
148 st5481_release_b(&adapter->bcs[0]);
149 st5481_release_d(adapter);
150 // we would actually better wait for completion of outstanding urbs
151 mdelay(2);
152 st5481_release_usb(adapter);
153
154 hisax_unregister(&adapter->hisax_d_if);
155
156 kfree(adapter);
157}
158
159/*
160 * The last 4 bits in the Product Id is set with 4 pins on the chip.
161 */
162static struct usb_device_id st5481_ids[] = {
163 { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0x0) },
164 { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0x1) },
165 { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0x2) },
166 { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0x3) },
167 { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0x4) },
168 { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0x5) },
169 { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0x6) },
170 { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0x7) },
171 { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0x8) },
172 { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0x9) },
173 { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0xA) },
174 { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0xB) },
175 { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0xC) },
176 { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0xD) },
177 { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0xE) },
178 { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0xF) },
179 { }
180};
181MODULE_DEVICE_TABLE (usb, st5481_ids);
182
183static struct usb_driver st5481_usb_driver = {
184 .owner = THIS_MODULE,
185 .name = "st5481_usb",
186 .probe = probe_st5481,
187 .disconnect = disconnect_st5481,
188 .id_table = st5481_ids,
189};
190
191static int __init st5481_usb_init(void)
192{
193 int retval;
194
195#ifdef CONFIG_HISAX_DEBUG
196 st5481_debug = debug;
197#endif
198
199 printk(KERN_INFO "hisax_st5481: ST5481 USB ISDN driver $Revision: 2.4.2.3 $\n");
200
201 retval = st5481_d_init();
202 if (retval < 0)
203 goto out;
204
205 retval = usb_register(&st5481_usb_driver);
206 if (retval < 0)
207 goto out_d_exit;
208
209 return 0;
210
211 out_d_exit:
212 st5481_d_exit();
213 out:
214 return retval;
215}
216
217static void __exit st5481_usb_exit(void)
218{
219 usb_deregister(&st5481_usb_driver);
220 st5481_d_exit();
221}
222
223module_init(st5481_usb_init);
224module_exit(st5481_usb_exit);
diff --git a/drivers/isdn/hisax/st5481_usb.c b/drivers/isdn/hisax/st5481_usb.c
new file mode 100644
index 000000000000..2369180b1cb1
--- /dev/null
+++ b/drivers/isdn/hisax/st5481_usb.c
@@ -0,0 +1,650 @@
1/*
2 * Driver for ST5481 USB ISDN modem
3 *
4 * Author Frode Isaksen
5 * Copyright 2001 by Frode Isaksen <fisaksen@bewan.com>
6 * 2001 by Kai Germaschewski <kai.germaschewski@gmx.de>
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 */
12
13#include <linux/init.h>
14#include <linux/usb.h>
15#include <linux/slab.h>
16#include "st5481.h"
17
18/* ======================================================================
19 * control pipe
20 */
21
22/*
23 * Send the next endpoint 0 request stored in the FIFO.
24 * Called either by the completion or by usb_ctrl_msg.
25 */
26static void usb_next_ctrl_msg(struct urb *urb,
27 struct st5481_adapter *adapter)
28{
29 struct st5481_ctrl *ctrl = &adapter->ctrl;
30 int r_index;
31
32 if (test_and_set_bit(0, &ctrl->busy)) {
33 return;
34 }
35
36 if ((r_index = fifo_remove(&ctrl->msg_fifo.f)) < 0) {
37 test_and_clear_bit(0,&ctrl->busy);
38 return;
39 }
40 urb->setup_packet =
41 (unsigned char *)&ctrl->msg_fifo.data[r_index];
42
43 DBG(1,"request=0x%02x,value=0x%04x,index=%x",
44 ((struct ctrl_msg *)urb->setup_packet)->dr.bRequest,
45 ((struct ctrl_msg *)urb->setup_packet)->dr.wValue,
46 ((struct ctrl_msg *)urb->setup_packet)->dr.wIndex);
47
48 // Prepare the URB
49 urb->dev = adapter->usb_dev;
50
51 SUBMIT_URB(urb, GFP_ATOMIC);
52}
53
54/*
55 * Asynchronous endpoint 0 request (async version of usb_control_msg).
56 * The request will be queued up in a FIFO if the endpoint is busy.
57 */
58void usb_ctrl_msg(struct st5481_adapter *adapter,
59 u8 request, u8 requesttype, u16 value, u16 index,
60 ctrl_complete_t complete, void *context)
61{
62 struct st5481_ctrl *ctrl = &adapter->ctrl;
63 int w_index;
64 struct ctrl_msg *ctrl_msg;
65
66 if ((w_index = fifo_add(&ctrl->msg_fifo.f)) < 0) {
67 WARN("control msg FIFO full");
68 return;
69 }
70 ctrl_msg = &ctrl->msg_fifo.data[w_index];
71
72 ctrl_msg->dr.bRequestType = requesttype;
73 ctrl_msg->dr.bRequest = request;
74 ctrl_msg->dr.wValue = cpu_to_le16p(&value);
75 ctrl_msg->dr.wIndex = cpu_to_le16p(&index);
76 ctrl_msg->dr.wLength = 0;
77 ctrl_msg->complete = complete;
78 ctrl_msg->context = context;
79
80 usb_next_ctrl_msg(ctrl->urb, adapter);
81}
82
83/*
84 * Asynchronous endpoint 0 device request.
85 */
86void st5481_usb_device_ctrl_msg(struct st5481_adapter *adapter,
87 u8 request, u16 value,
88 ctrl_complete_t complete, void *context)
89{
90 usb_ctrl_msg(adapter, request,
91 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
92 value, 0, complete, context);
93}
94
95/*
96 * Asynchronous pipe reset (async version of usb_clear_halt).
97 */
98void st5481_usb_pipe_reset(struct st5481_adapter *adapter,
99 u_char pipe,
100 ctrl_complete_t complete, void *context)
101{
102 DBG(1,"pipe=%02x",pipe);
103
104 usb_ctrl_msg(adapter,
105 USB_REQ_CLEAR_FEATURE, USB_DIR_OUT | USB_RECIP_ENDPOINT,
106 0, pipe, complete, context);
107}
108
109
110/*
111 Physical level functions
112*/
113
114void st5481_ph_command(struct st5481_adapter *adapter, unsigned int command)
115{
116 DBG(8,"command=%s", ST5481_CMD_string(command));
117
118 st5481_usb_device_ctrl_msg(adapter, TXCI, command, NULL, NULL);
119}
120
121/*
122 * The request on endpoint 0 has completed.
123 * Call the user provided completion routine and try
124 * to send the next request.
125 */
126static void usb_ctrl_complete(struct urb *urb, struct pt_regs *regs)
127{
128 struct st5481_adapter *adapter = urb->context;
129 struct st5481_ctrl *ctrl = &adapter->ctrl;
130 struct ctrl_msg *ctrl_msg;
131
132 if (unlikely(urb->status < 0)) {
133 if (urb->status != -ENOENT && urb->status != -ESHUTDOWN) {
134 WARN("urb status %d",urb->status);
135 } else {
136 DBG(1,"urb killed");
137 return; // Give up
138 }
139 }
140
141 ctrl_msg = (struct ctrl_msg *)urb->setup_packet;
142
143 if (ctrl_msg->dr.bRequest == USB_REQ_CLEAR_FEATURE) {
144 /* Special case handling for pipe reset */
145 le16_to_cpus(&ctrl_msg->dr.wIndex);
146
147 /* toggle is reset on clear */
148 usb_settoggle(adapter->usb_dev,
149 ctrl_msg->dr.wIndex & ~USB_DIR_IN,
150 (ctrl_msg->dr.wIndex & USB_DIR_IN) == 0,
151 0);
152
153
154 }
155
156 if (ctrl_msg->complete)
157 ctrl_msg->complete(ctrl_msg->context);
158
159 clear_bit(0, &ctrl->busy);
160
161 // Try to send next control message
162 usb_next_ctrl_msg(urb, adapter);
163 return;
164}
165
166/* ======================================================================
167 * interrupt pipe
168 */
169
170/*
171 * The interrupt endpoint will be called when any
172 * of the 6 registers changes state (depending on masks).
173 * Decode the register values and schedule a private event.
174 * Called at interrupt.
175 */
176static void usb_int_complete(struct urb *urb, struct pt_regs *regs)
177{
178 u8 *data = urb->transfer_buffer;
179 u8 irqbyte;
180 struct st5481_adapter *adapter = urb->context;
181 int j;
182 int status;
183
184 switch (urb->status) {
185 case 0:
186 /* success */
187 break;
188 case -ECONNRESET:
189 case -ENOENT:
190 case -ESHUTDOWN:
191 /* this urb is terminated, clean up */
192 DBG(1, "urb shutting down with status: %d", urb->status);
193 return;
194 default:
195 WARN("nonzero urb status received: %d", urb->status);
196 goto exit;
197 }
198
199
200 DBG_PACKET(1, data, INT_PKT_SIZE);
201
202 if (urb->actual_length == 0) {
203 goto exit;
204 }
205
206 irqbyte = data[MPINT];
207 if (irqbyte & DEN_INT)
208 FsmEvent(&adapter->d_out.fsm, EV_DOUT_DEN, NULL);
209
210 if (irqbyte & DCOLL_INT)
211 FsmEvent(&adapter->d_out.fsm, EV_DOUT_COLL, NULL);
212
213 irqbyte = data[FFINT_D];
214 if (irqbyte & OUT_UNDERRUN)
215 FsmEvent(&adapter->d_out.fsm, EV_DOUT_UNDERRUN, NULL);
216
217 if (irqbyte & OUT_DOWN)
218;// printk("OUT_DOWN\n");
219
220 irqbyte = data[MPINT];
221 if (irqbyte & RXCI_INT)
222 FsmEvent(&adapter->l1m, data[CCIST] & 0x0f, NULL);
223
224 for (j = 0; j < 2; j++)
225 adapter->bcs[j].b_out.flow_event |= data[FFINT_B1 + j];
226
227 urb->actual_length = 0;
228
229exit:
230 status = usb_submit_urb (urb, GFP_ATOMIC);
231 if (status)
232 WARN("usb_submit_urb failed with result %d", status);
233}
234
235/* ======================================================================
236 * initialization
237 */
238
239int st5481_setup_usb(struct st5481_adapter *adapter)
240{
241 struct usb_device *dev = adapter->usb_dev;
242 struct st5481_ctrl *ctrl = &adapter->ctrl;
243 struct st5481_intr *intr = &adapter->intr;
244 struct usb_interface *intf;
245 struct usb_host_interface *altsetting = NULL;
246 struct usb_host_endpoint *endpoint;
247 int status;
248 struct urb *urb;
249 u8 *buf;
250
251 DBG(1,"");
252
253 if ((status = usb_reset_configuration (dev)) < 0) {
254 WARN("reset_configuration failed,status=%d",status);
255 return status;
256 }
257
258 intf = usb_ifnum_to_if(dev, 0);
259 if (intf)
260 altsetting = usb_altnum_to_altsetting(intf, 3);
261 if (!altsetting)
262 return -ENXIO;
263
264 // Check if the config is sane
265 if ( altsetting->desc.bNumEndpoints != 7 ) {
266 WARN("expecting 7 got %d endpoints!", altsetting->desc.bNumEndpoints);
267 return -EINVAL;
268 }
269
270 // The descriptor is wrong for some early samples of the ST5481 chip
271 altsetting->endpoint[3].desc.wMaxPacketSize = __constant_cpu_to_le16(32);
272 altsetting->endpoint[4].desc.wMaxPacketSize = __constant_cpu_to_le16(32);
273
274 // Use alternative setting 3 on interface 0 to have 2B+D
275 if ((status = usb_set_interface (dev, 0, 3)) < 0) {
276 WARN("usb_set_interface failed,status=%d",status);
277 return status;
278 }
279
280 // Allocate URB for control endpoint
281 urb = usb_alloc_urb(0, GFP_KERNEL);
282 if (!urb) {
283 return -ENOMEM;
284 }
285 ctrl->urb = urb;
286
287 // Fill the control URB
288 usb_fill_control_urb (urb, dev,
289 usb_sndctrlpipe(dev, 0),
290 NULL, NULL, 0, usb_ctrl_complete, adapter);
291
292
293 fifo_init(&ctrl->msg_fifo.f, ARRAY_SIZE(ctrl->msg_fifo.data));
294
295 // Allocate URBs and buffers for interrupt endpoint
296 urb = usb_alloc_urb(0, GFP_KERNEL);
297 if (!urb) {
298 return -ENOMEM;
299 }
300 intr->urb = urb;
301
302 buf = kmalloc(INT_PKT_SIZE, GFP_KERNEL);
303 if (!buf) {
304 return -ENOMEM;
305 }
306
307 endpoint = &altsetting->endpoint[EP_INT-1];
308
309 // Fill the interrupt URB
310 usb_fill_int_urb(urb, dev,
311 usb_rcvintpipe(dev, endpoint->desc.bEndpointAddress),
312 buf, INT_PKT_SIZE,
313 usb_int_complete, adapter,
314 endpoint->desc.bInterval);
315
316 return 0;
317}
318
319/*
320 * Release buffers and URBs for the interrupt and control
321 * endpoint.
322 */
323void st5481_release_usb(struct st5481_adapter *adapter)
324{
325 struct st5481_intr *intr = &adapter->intr;
326 struct st5481_ctrl *ctrl = &adapter->ctrl;
327
328 DBG(1,"");
329
330 // Stop and free Control and Interrupt URBs
331 usb_unlink_urb(ctrl->urb);
332 if (ctrl->urb->transfer_buffer)
333 kfree(ctrl->urb->transfer_buffer);
334 usb_free_urb(ctrl->urb);
335
336 usb_unlink_urb(intr->urb);
337 if (intr->urb->transfer_buffer)
338 kfree(intr->urb->transfer_buffer);
339 usb_free_urb(intr->urb);
340}
341
342/*
343 * Initialize the adapter.
344 */
345void st5481_start(struct st5481_adapter *adapter)
346{
347 static const u8 init_cmd_table[]={
348 SET_DEFAULT,0,
349 STT,0,
350 SDA_MIN,0x0d,
351 SDA_MAX,0x29,
352 SDELAY_VALUE,0x14,
353 GPIO_DIR,0x01,
354 GPIO_OUT,RED_LED,
355// FFCTRL_OUT_D,4,
356// FFCTRH_OUT_D,12,
357 FFCTRL_OUT_B1,6,
358 FFCTRH_OUT_B1,20,
359 FFCTRL_OUT_B2,6,
360 FFCTRH_OUT_B2,20,
361 MPMSK,RXCI_INT+DEN_INT+DCOLL_INT,
362 0
363 };
364 struct st5481_intr *intr = &adapter->intr;
365 int i = 0;
366 u8 request,value;
367
368 DBG(8,"");
369
370 adapter->leds = RED_LED;
371
372 // Start receiving on the interrupt endpoint
373 SUBMIT_URB(intr->urb, GFP_KERNEL);
374
375 while ((request = init_cmd_table[i++])) {
376 value = init_cmd_table[i++];
377 st5481_usb_device_ctrl_msg(adapter, request, value, NULL, NULL);
378 }
379 st5481_ph_command(adapter, ST5481_CMD_PUP);
380}
381
382/*
383 * Reset the adapter to default values.
384 */
385void st5481_stop(struct st5481_adapter *adapter)
386{
387 DBG(8,"");
388
389 st5481_usb_device_ctrl_msg(adapter, SET_DEFAULT, 0, NULL, NULL);
390}
391
392/* ======================================================================
393 * isochronous USB helpers
394 */
395
396static void
397fill_isoc_urb(struct urb *urb, struct usb_device *dev,
398 unsigned int pipe, void *buf, int num_packets,
399 int packet_size, usb_complete_t complete,
400 void *context)
401{
402 int k;
403
404 spin_lock_init(&urb->lock);
405 urb->dev=dev;
406 urb->pipe=pipe;
407 urb->transfer_buffer=buf;
408 urb->number_of_packets = num_packets;
409 urb->transfer_buffer_length=num_packets*packet_size;
410 urb->actual_length = 0;
411 urb->complete=complete;
412 urb->context=context;
413 urb->transfer_flags=URB_ISO_ASAP;
414 for (k = 0; k < num_packets; k++) {
415 urb->iso_frame_desc[k].offset = packet_size * k;
416 urb->iso_frame_desc[k].length = packet_size;
417 urb->iso_frame_desc[k].actual_length = 0;
418 }
419}
420
421int
422st5481_setup_isocpipes(struct urb* urb[2], struct usb_device *dev,
423 unsigned int pipe, int num_packets,
424 int packet_size, int buf_size,
425 usb_complete_t complete, void *context)
426{
427 int j, retval;
428 unsigned char *buf;
429
430 for (j = 0; j < 2; j++) {
431 retval = -ENOMEM;
432 urb[j] = usb_alloc_urb(num_packets, GFP_KERNEL);
433 if (!urb[j])
434 goto err;
435
436 // Allocate memory for 2000bytes/sec (16Kb/s)
437 buf = kmalloc(buf_size, GFP_KERNEL);
438 if (!buf)
439 goto err;
440
441 // Fill the isochronous URB
442 fill_isoc_urb(urb[j], dev, pipe, buf,
443 num_packets, packet_size, complete,
444 context);
445 }
446 return 0;
447
448 err:
449 for (j = 0; j < 2; j++) {
450 if (urb[j]) {
451 if (urb[j]->transfer_buffer)
452 kfree(urb[j]->transfer_buffer);
453 usb_free_urb(urb[j]);
454 }
455 }
456 return retval;
457}
458
459void st5481_release_isocpipes(struct urb* urb[2])
460{
461 int j;
462
463 for (j = 0; j < 2; j++) {
464 usb_unlink_urb(urb[j]);
465 if (urb[j]->transfer_buffer)
466 kfree(urb[j]->transfer_buffer);
467 usb_free_urb(urb[j]);
468 }
469}
470
471/*
472 * Decode frames received on the B/D channel.
473 * Note that this function will be called continously
474 * with 64Kbit/s / 16Kbit/s of data and hence it will be
475 * called 50 times per second with 20 ISOC descriptors.
476 * Called at interrupt.
477 */
478static void usb_in_complete(struct urb *urb, struct pt_regs *regs)
479{
480 struct st5481_in *in = urb->context;
481 unsigned char *ptr;
482 struct sk_buff *skb;
483 int len, count, status;
484
485 if (unlikely(urb->status < 0)) {
486 if (urb->status != -ENOENT && urb->status != -ESHUTDOWN) {
487 WARN("urb status %d",urb->status);
488 } else {
489 DBG(1,"urb killed");
490 return; // Give up
491 }
492 }
493
494 DBG_ISO_PACKET(0x80,urb);
495
496 len = st5481_isoc_flatten(urb);
497 ptr = urb->transfer_buffer;
498 while (len > 0) {
499 if (in->mode == L1_MODE_TRANS) {
500 memcpy(in->rcvbuf, ptr, len);
501 status = len;
502 len = 0;
503 } else {
504 status = isdnhdlc_decode(&in->hdlc_state, ptr, len, &count,
505 in->rcvbuf, in->bufsize);
506 ptr += count;
507 len -= count;
508 }
509
510 if (status > 0) {
511 // Good frame received
512 DBG(4,"count=%d",status);
513 DBG_PACKET(0x400, in->rcvbuf, status);
514 if (!(skb = dev_alloc_skb(status))) {
515 WARN("receive out of memory\n");
516 break;
517 }
518 memcpy(skb_put(skb, status), in->rcvbuf, status);
519 in->hisax_if->l1l2(in->hisax_if, PH_DATA | INDICATION, skb);
520 } else if (status == -HDLC_CRC_ERROR) {
521 INFO("CRC error");
522 } else if (status == -HDLC_FRAMING_ERROR) {
523 INFO("framing error");
524 } else if (status == -HDLC_LENGTH_ERROR) {
525 INFO("length error");
526 }
527 }
528
529 // Prepare URB for next transfer
530 urb->dev = in->adapter->usb_dev;
531 urb->actual_length = 0;
532
533 SUBMIT_URB(urb, GFP_ATOMIC);
534}
535
536int st5481_setup_in(struct st5481_in *in)
537{
538 struct usb_device *dev = in->adapter->usb_dev;
539 int retval;
540
541 DBG(4,"");
542
543 in->rcvbuf = kmalloc(in->bufsize, GFP_KERNEL);
544 retval = -ENOMEM;
545 if (!in->rcvbuf)
546 goto err;
547
548 retval = st5481_setup_isocpipes(in->urb, dev,
549 usb_rcvisocpipe(dev, in->ep),
550 in->num_packets, in->packet_size,
551 in->num_packets * in->packet_size,
552 usb_in_complete, in);
553 if (retval)
554 goto err_free;
555 return 0;
556
557 err_free:
558 kfree(in->rcvbuf);
559 err:
560 return retval;
561}
562
563void st5481_release_in(struct st5481_in *in)
564{
565 DBG(2,"");
566
567 st5481_release_isocpipes(in->urb);
568}
569
570/*
571 * Make the transfer_buffer contiguous by
572 * copying from the iso descriptors if necessary.
573 */
574int st5481_isoc_flatten(struct urb *urb)
575{
576 struct usb_iso_packet_descriptor *pipd,*pend;
577 unsigned char *src,*dst;
578 unsigned int len;
579
580 if (urb->status < 0) {
581 return urb->status;
582 }
583 for (pipd = &urb->iso_frame_desc[0],
584 pend = &urb->iso_frame_desc[urb->number_of_packets],
585 dst = urb->transfer_buffer;
586 pipd < pend;
587 pipd++) {
588
589 if (pipd->status < 0) {
590 return (pipd->status);
591 }
592
593 len = pipd->actual_length;
594 pipd->actual_length = 0;
595 src = urb->transfer_buffer+pipd->offset;
596
597 if (src != dst) {
598 // Need to copy since isoc buffers not full
599 while (len--) {
600 *dst++ = *src++;
601 }
602 } else {
603 // No need to copy, just update destination buffer
604 dst += len;
605 }
606 }
607 // Return size of flattened buffer
608 return (dst - (unsigned char *)urb->transfer_buffer);
609}
610
611static void st5481_start_rcv(void *context)
612{
613 struct st5481_in *in = context;
614 struct st5481_adapter *adapter = in->adapter;
615
616 DBG(4,"");
617
618 in->urb[0]->dev = adapter->usb_dev;
619 SUBMIT_URB(in->urb[0], GFP_KERNEL);
620
621 in->urb[1]->dev = adapter->usb_dev;
622 SUBMIT_URB(in->urb[1], GFP_KERNEL);
623}
624
625void st5481_in_mode(struct st5481_in *in, int mode)
626{
627 if (in->mode == mode)
628 return;
629
630 in->mode = mode;
631
632 usb_unlink_urb(in->urb[0]);
633 usb_unlink_urb(in->urb[1]);
634
635 if (in->mode != L1_MODE_NULL) {
636 if (in->mode != L1_MODE_TRANS)
637 isdnhdlc_rcv_init(&in->hdlc_state,
638 in->mode == L1_MODE_HDLC_56K);
639
640 st5481_usb_pipe_reset(in->adapter, in->ep, NULL, NULL);
641 st5481_usb_device_ctrl_msg(in->adapter, in->counter,
642 in->packet_size,
643 NULL, NULL);
644 st5481_start_rcv(in);
645 } else {
646 st5481_usb_device_ctrl_msg(in->adapter, in->counter,
647 0, NULL, NULL);
648 }
649}
650
diff --git a/drivers/isdn/hisax/tei.c b/drivers/isdn/hisax/tei.c
new file mode 100644
index 000000000000..082726db3985
--- /dev/null
+++ b/drivers/isdn/hisax/tei.c
@@ -0,0 +1,466 @@
1/* $Id: tei.c,v 2.20.2.3 2004/01/13 14:31:26 keil Exp $
2 *
3 * Author Karsten Keil
4 * based on the teles driver from Jan den Ouden
5 * Copyright by Karsten Keil <keil@isdn4linux.de>
6 *
7 * This software may be used and distributed according to the terms
8 * of the GNU General Public License, incorporated herein by reference.
9 *
10 * For changes and modifications please read
11 * Documentation/isdn/HiSax.cert
12 *
13 * Thanks to Jan den Ouden
14 * Fritz Elfert
15 *
16 */
17
18#include "hisax.h"
19#include "isdnl2.h"
20#include <linux/init.h>
21#include <linux/random.h>
22
23const char *tei_revision = "$Revision: 2.20.2.3 $";
24
25#define ID_REQUEST 1
26#define ID_ASSIGNED 2
27#define ID_DENIED 3
28#define ID_CHK_REQ 4
29#define ID_CHK_RES 5
30#define ID_REMOVE 6
31#define ID_VERIFY 7
32
33#define TEI_ENTITY_ID 0xf
34
35static struct Fsm teifsm;
36
37void tei_handler(struct PStack *st, u_char pr, struct sk_buff *skb);
38
39enum {
40 ST_TEI_NOP,
41 ST_TEI_IDREQ,
42 ST_TEI_IDVERIFY,
43};
44
45#define TEI_STATE_COUNT (ST_TEI_IDVERIFY+1)
46
47static char *strTeiState[] =
48{
49 "ST_TEI_NOP",
50 "ST_TEI_IDREQ",
51 "ST_TEI_IDVERIFY",
52};
53
54enum {
55 EV_IDREQ,
56 EV_ASSIGN,
57 EV_DENIED,
58 EV_CHKREQ,
59 EV_REMOVE,
60 EV_VERIFY,
61 EV_T202,
62};
63
64#define TEI_EVENT_COUNT (EV_T202+1)
65
66static char *strTeiEvent[] =
67{
68 "EV_IDREQ",
69 "EV_ASSIGN",
70 "EV_DENIED",
71 "EV_CHKREQ",
72 "EV_REMOVE",
73 "EV_VERIFY",
74 "EV_T202",
75};
76
77unsigned int
78random_ri(void)
79{
80 unsigned int x;
81
82 get_random_bytes(&x, sizeof(x));
83 return (x & 0xffff);
84}
85
86static struct PStack *
87findtei(struct PStack *st, int tei)
88{
89 struct PStack *ptr = *(st->l1.stlistp);
90
91 if (tei == 127)
92 return (NULL);
93
94 while (ptr)
95 if (ptr->l2.tei == tei)
96 return (ptr);
97 else
98 ptr = ptr->next;
99 return (NULL);
100}
101
102static void
103put_tei_msg(struct PStack *st, u_char m_id, unsigned int ri, u_char tei)
104{
105 struct sk_buff *skb;
106 u_char *bp;
107
108 if (!(skb = alloc_skb(8, GFP_ATOMIC))) {
109 printk(KERN_WARNING "HiSax: No skb for TEI manager\n");
110 return;
111 }
112 bp = skb_put(skb, 3);
113 bp[0] = (TEI_SAPI << 2);
114 bp[1] = (GROUP_TEI << 1) | 0x1;
115 bp[2] = UI;
116 bp = skb_put(skb, 5);
117 bp[0] = TEI_ENTITY_ID;
118 bp[1] = ri >> 8;
119 bp[2] = ri & 0xff;
120 bp[3] = m_id;
121 bp[4] = (tei << 1) | 1;
122 st->l2.l2l1(st, PH_DATA | REQUEST, skb);
123}
124
125static void
126tei_id_request(struct FsmInst *fi, int event, void *arg)
127{
128 struct PStack *st = fi->userdata;
129
130 if (st->l2.tei != -1) {
131 st->ma.tei_m.printdebug(&st->ma.tei_m,
132 "assign request for allready asigned tei %d",
133 st->l2.tei);
134 return;
135 }
136 st->ma.ri = random_ri();
137 if (st->ma.debug)
138 st->ma.tei_m.printdebug(&st->ma.tei_m,
139 "assign request ri %d", st->ma.ri);
140 put_tei_msg(st, ID_REQUEST, st->ma.ri, 127);
141 FsmChangeState(&st->ma.tei_m, ST_TEI_IDREQ);
142 FsmAddTimer(&st->ma.t202, st->ma.T202, EV_T202, NULL, 1);
143 st->ma.N202 = 3;
144}
145
146static void
147tei_id_assign(struct FsmInst *fi, int event, void *arg)
148{
149 struct PStack *ost, *st = fi->userdata;
150 struct sk_buff *skb = arg;
151 struct IsdnCardState *cs;
152 int ri, tei;
153
154 ri = ((unsigned int) skb->data[1] << 8) + skb->data[2];
155 tei = skb->data[4] >> 1;
156 if (st->ma.debug)
157 st->ma.tei_m.printdebug(&st->ma.tei_m,
158 "identity assign ri %d tei %d", ri, tei);
159 if ((ost = findtei(st, tei))) { /* same tei is in use */
160 if (ri != ost->ma.ri) {
161 st->ma.tei_m.printdebug(&st->ma.tei_m,
162 "possible duplicate assignment tei %d", tei);
163 ost->l2.l2tei(ost, MDL_ERROR | RESPONSE, NULL);
164 }
165 } else if (ri == st->ma.ri) {
166 FsmDelTimer(&st->ma.t202, 1);
167 FsmChangeState(&st->ma.tei_m, ST_TEI_NOP);
168 st->l3.l3l2(st, MDL_ASSIGN | REQUEST, (void *) (long) tei);
169 cs = (struct IsdnCardState *) st->l1.hardware;
170 cs->cardmsg(cs, MDL_ASSIGN | REQUEST, NULL);
171 }
172}
173
174static void
175tei_id_test_dup(struct FsmInst *fi, int event, void *arg)
176{
177 struct PStack *ost, *st = fi->userdata;
178 struct sk_buff *skb = arg;
179 int tei, ri;
180
181 ri = ((unsigned int) skb->data[1] << 8) + skb->data[2];
182 tei = skb->data[4] >> 1;
183 if (st->ma.debug)
184 st->ma.tei_m.printdebug(&st->ma.tei_m,
185 "foreign identity assign ri %d tei %d", ri, tei);
186 if ((ost = findtei(st, tei))) { /* same tei is in use */
187 if (ri != ost->ma.ri) { /* and it wasn't our request */
188 st->ma.tei_m.printdebug(&st->ma.tei_m,
189 "possible duplicate assignment tei %d", tei);
190 FsmEvent(&ost->ma.tei_m, EV_VERIFY, NULL);
191 }
192 }
193}
194
195static void
196tei_id_denied(struct FsmInst *fi, int event, void *arg)
197{
198 struct PStack *st = fi->userdata;
199 struct sk_buff *skb = arg;
200 int ri, tei;
201
202 ri = ((unsigned int) skb->data[1] << 8) + skb->data[2];
203 tei = skb->data[4] >> 1;
204 if (st->ma.debug)
205 st->ma.tei_m.printdebug(&st->ma.tei_m,
206 "identity denied ri %d tei %d", ri, tei);
207}
208
209static void
210tei_id_chk_req(struct FsmInst *fi, int event, void *arg)
211{
212 struct PStack *st = fi->userdata;
213 struct sk_buff *skb = arg;
214 int tei;
215
216 tei = skb->data[4] >> 1;
217 if (st->ma.debug)
218 st->ma.tei_m.printdebug(&st->ma.tei_m,
219 "identity check req tei %d", tei);
220 if ((st->l2.tei != -1) && ((tei == GROUP_TEI) || (tei == st->l2.tei))) {
221 FsmDelTimer(&st->ma.t202, 4);
222 FsmChangeState(&st->ma.tei_m, ST_TEI_NOP);
223 put_tei_msg(st, ID_CHK_RES, random_ri(), st->l2.tei);
224 }
225}
226
227static void
228tei_id_remove(struct FsmInst *fi, int event, void *arg)
229{
230 struct PStack *st = fi->userdata;
231 struct sk_buff *skb = arg;
232 struct IsdnCardState *cs;
233 int tei;
234
235 tei = skb->data[4] >> 1;
236 if (st->ma.debug)
237 st->ma.tei_m.printdebug(&st->ma.tei_m,
238 "identity remove tei %d", tei);
239 if ((st->l2.tei != -1) && ((tei == GROUP_TEI) || (tei == st->l2.tei))) {
240 FsmDelTimer(&st->ma.t202, 5);
241 FsmChangeState(&st->ma.tei_m, ST_TEI_NOP);
242 st->l3.l3l2(st, MDL_REMOVE | REQUEST, NULL);
243 cs = (struct IsdnCardState *) st->l1.hardware;
244 cs->cardmsg(cs, MDL_REMOVE | REQUEST, NULL);
245 }
246}
247
248static void
249tei_id_verify(struct FsmInst *fi, int event, void *arg)
250{
251 struct PStack *st = fi->userdata;
252
253 if (st->ma.debug)
254 st->ma.tei_m.printdebug(&st->ma.tei_m,
255 "id verify request for tei %d", st->l2.tei);
256 put_tei_msg(st, ID_VERIFY, 0, st->l2.tei);
257 FsmChangeState(&st->ma.tei_m, ST_TEI_IDVERIFY);
258 FsmAddTimer(&st->ma.t202, st->ma.T202, EV_T202, NULL, 2);
259 st->ma.N202 = 2;
260}
261
262static void
263tei_id_req_tout(struct FsmInst *fi, int event, void *arg)
264{
265 struct PStack *st = fi->userdata;
266 struct IsdnCardState *cs;
267
268 if (--st->ma.N202) {
269 st->ma.ri = random_ri();
270 if (st->ma.debug)
271 st->ma.tei_m.printdebug(&st->ma.tei_m,
272 "assign req(%d) ri %d", 4 - st->ma.N202,
273 st->ma.ri);
274 put_tei_msg(st, ID_REQUEST, st->ma.ri, 127);
275 FsmAddTimer(&st->ma.t202, st->ma.T202, EV_T202, NULL, 3);
276 } else {
277 st->ma.tei_m.printdebug(&st->ma.tei_m, "assign req failed");
278 st->l3.l3l2(st, MDL_ERROR | RESPONSE, NULL);
279 cs = (struct IsdnCardState *) st->l1.hardware;
280 cs->cardmsg(cs, MDL_REMOVE | REQUEST, NULL);
281 FsmChangeState(fi, ST_TEI_NOP);
282 }
283}
284
285static void
286tei_id_ver_tout(struct FsmInst *fi, int event, void *arg)
287{
288 struct PStack *st = fi->userdata;
289 struct IsdnCardState *cs;
290
291 if (--st->ma.N202) {
292 if (st->ma.debug)
293 st->ma.tei_m.printdebug(&st->ma.tei_m,
294 "id verify req(%d) for tei %d",
295 3 - st->ma.N202, st->l2.tei);
296 put_tei_msg(st, ID_VERIFY, 0, st->l2.tei);
297 FsmAddTimer(&st->ma.t202, st->ma.T202, EV_T202, NULL, 4);
298 } else {
299 st->ma.tei_m.printdebug(&st->ma.tei_m,
300 "verify req for tei %d failed", st->l2.tei);
301 st->l3.l3l2(st, MDL_REMOVE | REQUEST, NULL);
302 cs = (struct IsdnCardState *) st->l1.hardware;
303 cs->cardmsg(cs, MDL_REMOVE | REQUEST, NULL);
304 FsmChangeState(fi, ST_TEI_NOP);
305 }
306}
307
308static void
309tei_l1l2(struct PStack *st, int pr, void *arg)
310{
311 struct sk_buff *skb = arg;
312 int mt;
313
314 if (test_bit(FLG_FIXED_TEI, &st->l2.flag)) {
315 dev_kfree_skb(skb);
316 return;
317 }
318
319 if (pr == (PH_DATA | INDICATION)) {
320 if (skb->len < 3) {
321 st->ma.tei_m.printdebug(&st->ma.tei_m,
322 "short mgr frame %ld/3", skb->len);
323 } else if ((skb->data[0] != ((TEI_SAPI << 2) | 2)) ||
324 (skb->data[1] != ((GROUP_TEI << 1) | 1))) {
325 st->ma.tei_m.printdebug(&st->ma.tei_m,
326 "wrong mgr sapi/tei %x/%x",
327 skb->data[0], skb->data[1]);
328 } else if ((skb->data[2] & 0xef) != UI) {
329 st->ma.tei_m.printdebug(&st->ma.tei_m,
330 "mgr frame is not ui %x", skb->data[2]);
331 } else {
332 skb_pull(skb, 3);
333 if (skb->len < 5) {
334 st->ma.tei_m.printdebug(&st->ma.tei_m,
335 "short mgr frame %ld/5", skb->len);
336 } else if (skb->data[0] != TEI_ENTITY_ID) {
337 /* wrong management entity identifier, ignore */
338 st->ma.tei_m.printdebug(&st->ma.tei_m,
339 "tei handler wrong entity id %x",
340 skb->data[0]);
341 } else {
342 mt = skb->data[3];
343 if (mt == ID_ASSIGNED)
344 FsmEvent(&st->ma.tei_m, EV_ASSIGN, skb);
345 else if (mt == ID_DENIED)
346 FsmEvent(&st->ma.tei_m, EV_DENIED, skb);
347 else if (mt == ID_CHK_REQ)
348 FsmEvent(&st->ma.tei_m, EV_CHKREQ, skb);
349 else if (mt == ID_REMOVE)
350 FsmEvent(&st->ma.tei_m, EV_REMOVE, skb);
351 else {
352 st->ma.tei_m.printdebug(&st->ma.tei_m,
353 "tei handler wrong mt %x\n", mt);
354 }
355 }
356 }
357 } else {
358 st->ma.tei_m.printdebug(&st->ma.tei_m,
359 "tei handler wrong pr %x\n", pr);
360 }
361 dev_kfree_skb(skb);
362}
363
364static void
365tei_l2tei(struct PStack *st, int pr, void *arg)
366{
367 struct IsdnCardState *cs;
368
369 if (test_bit(FLG_FIXED_TEI, &st->l2.flag)) {
370 if (pr == (MDL_ASSIGN | INDICATION)) {
371 if (st->ma.debug)
372 st->ma.tei_m.printdebug(&st->ma.tei_m,
373 "fixed assign tei %d", st->l2.tei);
374 st->l3.l3l2(st, MDL_ASSIGN | REQUEST, (void *) (long) st->l2.tei);
375 cs = (struct IsdnCardState *) st->l1.hardware;
376 cs->cardmsg(cs, MDL_ASSIGN | REQUEST, NULL);
377 }
378 return;
379 }
380 switch (pr) {
381 case (MDL_ASSIGN | INDICATION):
382 FsmEvent(&st->ma.tei_m, EV_IDREQ, arg);
383 break;
384 case (MDL_ERROR | REQUEST):
385 FsmEvent(&st->ma.tei_m, EV_VERIFY, arg);
386 break;
387 default:
388 break;
389 }
390}
391
392static void
393tei_debug(struct FsmInst *fi, char *fmt, ...)
394{
395 va_list args;
396 struct PStack *st = fi->userdata;
397
398 va_start(args, fmt);
399 VHiSax_putstatus(st->l1.hardware, "tei ", fmt, args);
400 va_end(args);
401}
402
403void
404setstack_tei(struct PStack *st)
405{
406 st->l2.l2tei = tei_l2tei;
407 st->ma.T202 = 2000; /* T202 2000 milliseconds */
408 st->l1.l1tei = tei_l1l2;
409 st->ma.debug = 1;
410 st->ma.tei_m.fsm = &teifsm;
411 st->ma.tei_m.state = ST_TEI_NOP;
412 st->ma.tei_m.debug = 1;
413 st->ma.tei_m.userdata = st;
414 st->ma.tei_m.userint = 0;
415 st->ma.tei_m.printdebug = tei_debug;
416 FsmInitTimer(&st->ma.tei_m, &st->ma.t202);
417}
418
419void
420init_tei(struct IsdnCardState *cs, int protocol)
421{
422}
423
424void
425release_tei(struct IsdnCardState *cs)
426{
427 struct PStack *st = cs->stlist;
428
429 while (st) {
430 FsmDelTimer(&st->ma.t202, 1);
431 st = st->next;
432 }
433}
434
435static struct FsmNode TeiFnList[] __initdata =
436{
437 {ST_TEI_NOP, EV_IDREQ, tei_id_request},
438 {ST_TEI_NOP, EV_ASSIGN, tei_id_test_dup},
439 {ST_TEI_NOP, EV_VERIFY, tei_id_verify},
440 {ST_TEI_NOP, EV_REMOVE, tei_id_remove},
441 {ST_TEI_NOP, EV_CHKREQ, tei_id_chk_req},
442 {ST_TEI_IDREQ, EV_T202, tei_id_req_tout},
443 {ST_TEI_IDREQ, EV_ASSIGN, tei_id_assign},
444 {ST_TEI_IDREQ, EV_DENIED, tei_id_denied},
445 {ST_TEI_IDVERIFY, EV_T202, tei_id_ver_tout},
446 {ST_TEI_IDVERIFY, EV_REMOVE, tei_id_remove},
447 {ST_TEI_IDVERIFY, EV_CHKREQ, tei_id_chk_req},
448};
449
450#define TEI_FN_COUNT (sizeof(TeiFnList)/sizeof(struct FsmNode))
451
452int __init
453TeiNew(void)
454{
455 teifsm.state_count = TEI_STATE_COUNT;
456 teifsm.event_count = TEI_EVENT_COUNT;
457 teifsm.strEvent = strTeiEvent;
458 teifsm.strState = strTeiState;
459 return FsmNew(&teifsm, TeiFnList, TEI_FN_COUNT);
460}
461
462void
463TeiFree(void)
464{
465 FsmFree(&teifsm);
466}
diff --git a/drivers/isdn/hisax/teleint.c b/drivers/isdn/hisax/teleint.c
new file mode 100644
index 000000000000..ef8984c5f1f7
--- /dev/null
+++ b/drivers/isdn/hisax/teleint.c
@@ -0,0 +1,339 @@
1/* $Id: teleint.c,v 1.16.2.5 2004/01/19 15:31:50 keil Exp $
2 *
3 * low level stuff for TeleInt isdn cards
4 *
5 * Author Karsten Keil
6 * Copyright by Karsten Keil <keil@isdn4linux.de>
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 */
12
13#include <linux/init.h>
14#include "hisax.h"
15#include "isac.h"
16#include "hfc_2bs0.h"
17#include "isdnl1.h"
18
19extern const char *CardType[];
20
21const char *TeleInt_revision = "$Revision: 1.16.2.5 $";
22
23#define byteout(addr,val) outb(val,addr)
24#define bytein(addr) inb(addr)
25
26static inline u_char
27readreg(unsigned int ale, unsigned int adr, u_char off)
28{
29 register u_char ret;
30 int max_delay = 2000;
31
32 byteout(ale, off);
33 ret = HFC_BUSY & bytein(ale);
34 while (ret && --max_delay)
35 ret = HFC_BUSY & bytein(ale);
36 if (!max_delay) {
37 printk(KERN_WARNING "TeleInt Busy not inactive\n");
38 return (0);
39 }
40 ret = bytein(adr);
41 return (ret);
42}
43
44static inline void
45readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
46{
47 register u_char ret;
48 register int max_delay = 20000;
49 register int i;
50
51 byteout(ale, off);
52 for (i = 0; i<size; i++) {
53 ret = HFC_BUSY & bytein(ale);
54 while (ret && --max_delay)
55 ret = HFC_BUSY & bytein(ale);
56 if (!max_delay) {
57 printk(KERN_WARNING "TeleInt Busy not inactive\n");
58 return;
59 }
60 data[i] = bytein(adr);
61 }
62}
63
64
65static inline void
66writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
67{
68 register u_char ret;
69 int max_delay = 2000;
70
71 byteout(ale, off);
72 ret = HFC_BUSY & bytein(ale);
73 while (ret && --max_delay)
74 ret = HFC_BUSY & bytein(ale);
75 if (!max_delay) {
76 printk(KERN_WARNING "TeleInt Busy not inactive\n");
77 return;
78 }
79 byteout(adr, data);
80}
81
82static inline void
83writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
84{
85 register u_char ret;
86 register int max_delay = 20000;
87 register int i;
88
89 byteout(ale, off);
90 for (i = 0; i<size; i++) {
91 ret = HFC_BUSY & bytein(ale);
92 while (ret && --max_delay)
93 ret = HFC_BUSY & bytein(ale);
94 if (!max_delay) {
95 printk(KERN_WARNING "TeleInt Busy not inactive\n");
96 return;
97 }
98 byteout(adr, data[i]);
99 }
100}
101
102/* Interface functions */
103
104static u_char
105ReadISAC(struct IsdnCardState *cs, u_char offset)
106{
107 cs->hw.hfc.cip = offset;
108 return (readreg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, offset));
109}
110
111static void
112WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
113{
114 cs->hw.hfc.cip = offset;
115 writereg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, offset, value);
116}
117
118static void
119ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
120{
121 cs->hw.hfc.cip = 0;
122 readfifo(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, 0, data, size);
123}
124
125static void
126WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
127{
128 cs->hw.hfc.cip = 0;
129 writefifo(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, 0, data, size);
130}
131
132static u_char
133ReadHFC(struct IsdnCardState *cs, int data, u_char reg)
134{
135 register u_char ret;
136
137 if (data) {
138 cs->hw.hfc.cip = reg;
139 byteout(cs->hw.hfc.addr | 1, reg);
140 ret = bytein(cs->hw.hfc.addr);
141 if (cs->debug & L1_DEB_HSCX_FIFO && (data != 2))
142 debugl1(cs, "hfc RD %02x %02x", reg, ret);
143 } else
144 ret = bytein(cs->hw.hfc.addr | 1);
145 return (ret);
146}
147
148static void
149WriteHFC(struct IsdnCardState *cs, int data, u_char reg, u_char value)
150{
151 byteout(cs->hw.hfc.addr | 1, reg);
152 cs->hw.hfc.cip = reg;
153 if (data)
154 byteout(cs->hw.hfc.addr, value);
155 if (cs->debug & L1_DEB_HSCX_FIFO && (data != 2))
156 debugl1(cs, "hfc W%c %02x %02x", data ? 'D' : 'C', reg, value);
157}
158
159static irqreturn_t
160TeleInt_interrupt(int intno, void *dev_id, struct pt_regs *regs)
161{
162 struct IsdnCardState *cs = dev_id;
163 u_char val;
164 u_long flags;
165
166 spin_lock_irqsave(&cs->lock, flags);
167 val = readreg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, ISAC_ISTA);
168 Start_ISAC:
169 if (val)
170 isac_interrupt(cs, val);
171 val = readreg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, ISAC_ISTA);
172 if (val) {
173 if (cs->debug & L1_DEB_ISAC)
174 debugl1(cs, "ISAC IntStat after IntRoutine");
175 goto Start_ISAC;
176 }
177 writereg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, ISAC_MASK, 0xFF);
178 writereg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, ISAC_MASK, 0x0);
179 spin_unlock_irqrestore(&cs->lock, flags);
180 return IRQ_HANDLED;
181}
182
183static void
184TeleInt_Timer(struct IsdnCardState *cs)
185{
186 int stat = 0;
187 u_long flags;
188
189 spin_lock_irqsave(&cs->lock, flags);
190 if (cs->bcs[0].mode) {
191 stat |= 1;
192 main_irq_hfc(&cs->bcs[0]);
193 }
194 if (cs->bcs[1].mode) {
195 stat |= 2;
196 main_irq_hfc(&cs->bcs[1]);
197 }
198 spin_unlock_irqrestore(&cs->lock, flags);
199 stat = HZ/100;
200 if (!stat)
201 stat = 1;
202 cs->hw.hfc.timer.expires = jiffies + stat;
203 add_timer(&cs->hw.hfc.timer);
204}
205
206void
207release_io_TeleInt(struct IsdnCardState *cs)
208{
209 del_timer(&cs->hw.hfc.timer);
210 releasehfc(cs);
211 if (cs->hw.hfc.addr)
212 release_region(cs->hw.hfc.addr, 2);
213}
214
215static void
216reset_TeleInt(struct IsdnCardState *cs)
217{
218 printk(KERN_INFO "TeleInt: resetting card\n");
219 cs->hw.hfc.cirm |= HFC_RESET;
220 byteout(cs->hw.hfc.addr | 1, cs->hw.hfc.cirm); /* Reset On */
221 mdelay(10);
222 cs->hw.hfc.cirm &= ~HFC_RESET;
223 byteout(cs->hw.hfc.addr | 1, cs->hw.hfc.cirm); /* Reset Off */
224 mdelay(10);
225}
226
227static int
228TeleInt_card_msg(struct IsdnCardState *cs, int mt, void *arg)
229{
230 u_long flags;
231 int delay;
232
233 switch (mt) {
234 case CARD_RESET:
235 spin_lock_irqsave(&cs->lock, flags);
236 reset_TeleInt(cs);
237 spin_unlock_irqrestore(&cs->lock, flags);
238 return(0);
239 case CARD_RELEASE:
240 release_io_TeleInt(cs);
241 return(0);
242 case CARD_INIT:
243 spin_lock_irqsave(&cs->lock, flags);
244 reset_TeleInt(cs);
245 inithfc(cs);
246 clear_pending_isac_ints(cs);
247 initisac(cs);
248 /* Reenable all IRQ */
249 cs->writeisac(cs, ISAC_MASK, 0);
250 cs->writeisac(cs, ISAC_CMDR, 0x41);
251 spin_unlock_irqrestore(&cs->lock, flags);
252 delay = HZ/100;
253 if (!delay)
254 delay = 1;
255 cs->hw.hfc.timer.expires = jiffies + delay;
256 add_timer(&cs->hw.hfc.timer);
257 return(0);
258 case CARD_TEST:
259 return(0);
260 }
261 return(0);
262}
263
264int __init
265setup_TeleInt(struct IsdnCard *card)
266{
267 struct IsdnCardState *cs = card->cs;
268 char tmp[64];
269
270 strcpy(tmp, TeleInt_revision);
271 printk(KERN_INFO "HiSax: TeleInt driver Rev. %s\n", HiSax_getrev(tmp));
272 if (cs->typ != ISDN_CTYPE_TELEINT)
273 return (0);
274
275 cs->hw.hfc.addr = card->para[1] & 0x3fe;
276 cs->irq = card->para[0];
277 cs->hw.hfc.cirm = HFC_CIRM;
278 cs->hw.hfc.isac_spcr = 0x00;
279 cs->hw.hfc.cip = 0;
280 cs->hw.hfc.ctmt = HFC_CTMT | HFC_CLTIMER;
281 cs->bcs[0].hw.hfc.send = NULL;
282 cs->bcs[1].hw.hfc.send = NULL;
283 cs->hw.hfc.fifosize = 7 * 1024 + 512;
284 cs->hw.hfc.timer.function = (void *) TeleInt_Timer;
285 cs->hw.hfc.timer.data = (long) cs;
286 init_timer(&cs->hw.hfc.timer);
287 if (!request_region(cs->hw.hfc.addr, 2, "TeleInt isdn")) {
288 printk(KERN_WARNING
289 "HiSax: %s config port %x-%x already in use\n",
290 CardType[card->typ],
291 cs->hw.hfc.addr,
292 cs->hw.hfc.addr + 2);
293 return (0);
294 }
295 /* HW IO = IO */
296 byteout(cs->hw.hfc.addr, cs->hw.hfc.addr & 0xff);
297 byteout(cs->hw.hfc.addr | 1, ((cs->hw.hfc.addr & 0x300) >> 8) | 0x54);
298 switch (cs->irq) {
299 case 3:
300 cs->hw.hfc.cirm |= HFC_INTA;
301 break;
302 case 4:
303 cs->hw.hfc.cirm |= HFC_INTB;
304 break;
305 case 5:
306 cs->hw.hfc.cirm |= HFC_INTC;
307 break;
308 case 7:
309 cs->hw.hfc.cirm |= HFC_INTD;
310 break;
311 case 10:
312 cs->hw.hfc.cirm |= HFC_INTE;
313 break;
314 case 11:
315 cs->hw.hfc.cirm |= HFC_INTF;
316 break;
317 default:
318 printk(KERN_WARNING "TeleInt: wrong IRQ\n");
319 release_io_TeleInt(cs);
320 return (0);
321 }
322 byteout(cs->hw.hfc.addr | 1, cs->hw.hfc.cirm);
323 byteout(cs->hw.hfc.addr | 1, cs->hw.hfc.ctmt);
324
325 printk(KERN_INFO "TeleInt: defined at 0x%x IRQ %d\n",
326 cs->hw.hfc.addr, cs->irq);
327
328 setup_isac(cs);
329 cs->readisac = &ReadISAC;
330 cs->writeisac = &WriteISAC;
331 cs->readisacfifo = &ReadISACfifo;
332 cs->writeisacfifo = &WriteISACfifo;
333 cs->BC_Read_Reg = &ReadHFC;
334 cs->BC_Write_Reg = &WriteHFC;
335 cs->cardmsg = &TeleInt_card_msg;
336 cs->irq_func = &TeleInt_interrupt;
337 ISACVersion(cs, "TeleInt:");
338 return (1);
339}
diff --git a/drivers/isdn/hisax/teles0.c b/drivers/isdn/hisax/teles0.c
new file mode 100644
index 000000000000..5ec5ec3e1eab
--- /dev/null
+++ b/drivers/isdn/hisax/teles0.c
@@ -0,0 +1,367 @@
1/* $Id: teles0.c,v 2.15.2.4 2004/01/13 23:48:39 keil Exp $
2 *
3 * low level stuff for Teles Memory IO isdn cards
4 *
5 * Author Karsten Keil
6 * based on the teles driver from Jan den Ouden
7 * Copyright by Karsten Keil <keil@isdn4linux.de>
8 *
9 * This software may be used and distributed according to the terms
10 * of the GNU General Public License, incorporated herein by reference.
11 *
12 * Thanks to Jan den Ouden
13 * Fritz Elfert
14 * Beat Doebeli
15 *
16 */
17
18#include <linux/init.h>
19#include "hisax.h"
20#include "isdnl1.h"
21#include "isac.h"
22#include "hscx.h"
23
24extern const char *CardType[];
25
26const char *teles0_revision = "$Revision: 2.15.2.4 $";
27
28#define TELES_IOMEM_SIZE 0x400
29#define byteout(addr,val) outb(val,addr)
30#define bytein(addr) inb(addr)
31
32static inline u_char
33readisac(void __iomem *adr, u_char off)
34{
35 return readb(adr + ((off & 1) ? 0x2ff : 0x100) + off);
36}
37
38static inline void
39writeisac(void __iomem *adr, u_char off, u_char data)
40{
41 writeb(data, adr + ((off & 1) ? 0x2ff : 0x100) + off); mb();
42}
43
44
45static inline u_char
46readhscx(void __iomem *adr, int hscx, u_char off)
47{
48 return readb(adr + (hscx ? 0x1c0 : 0x180) +
49 ((off & 1) ? 0x1ff : 0) + off);
50}
51
52static inline void
53writehscx(void __iomem *adr, int hscx, u_char off, u_char data)
54{
55 writeb(data, adr + (hscx ? 0x1c0 : 0x180) +
56 ((off & 1) ? 0x1ff : 0) + off); mb();
57}
58
59static inline void
60read_fifo_isac(void __iomem *adr, u_char * data, int size)
61{
62 register int i;
63 register u_char __iomem *ad = adr + 0x100;
64 for (i = 0; i < size; i++)
65 data[i] = readb(ad);
66}
67
68static inline void
69write_fifo_isac(void __iomem *adr, u_char * data, int size)
70{
71 register int i;
72 register u_char __iomem *ad = adr + 0x100;
73 for (i = 0; i < size; i++) {
74 writeb(data[i], ad); mb();
75 }
76}
77
78static inline void
79read_fifo_hscx(void __iomem *adr, int hscx, u_char * data, int size)
80{
81 register int i;
82 register u_char __iomem *ad = adr + (hscx ? 0x1c0 : 0x180);
83 for (i = 0; i < size; i++)
84 data[i] = readb(ad);
85}
86
87static inline void
88write_fifo_hscx(void __iomem *adr, int hscx, u_char * data, int size)
89{
90 int i;
91 register u_char __iomem *ad = adr + (hscx ? 0x1c0 : 0x180);
92 for (i = 0; i < size; i++) {
93 writeb(data[i], ad); mb();
94 }
95}
96
97/* Interface functions */
98
99static u_char
100ReadISAC(struct IsdnCardState *cs, u_char offset)
101{
102 return (readisac(cs->hw.teles0.membase, offset));
103}
104
105static void
106WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
107{
108 writeisac(cs->hw.teles0.membase, offset, value);
109}
110
111static void
112ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
113{
114 read_fifo_isac(cs->hw.teles0.membase, data, size);
115}
116
117static void
118WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
119{
120 write_fifo_isac(cs->hw.teles0.membase, data, size);
121}
122
123static u_char
124ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
125{
126 return (readhscx(cs->hw.teles0.membase, hscx, offset));
127}
128
129static void
130WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
131{
132 writehscx(cs->hw.teles0.membase, hscx, offset, value);
133}
134
135/*
136 * fast interrupt HSCX stuff goes here
137 */
138
139#define READHSCX(cs, nr, reg) readhscx(cs->hw.teles0.membase, nr, reg)
140#define WRITEHSCX(cs, nr, reg, data) writehscx(cs->hw.teles0.membase, nr, reg, data)
141#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo_hscx(cs->hw.teles0.membase, nr, ptr, cnt)
142#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo_hscx(cs->hw.teles0.membase, nr, ptr, cnt)
143
144#include "hscx_irq.c"
145
146static irqreturn_t
147teles0_interrupt(int intno, void *dev_id, struct pt_regs *regs)
148{
149 struct IsdnCardState *cs = dev_id;
150 u_char val;
151 u_long flags;
152 int count = 0;
153
154 spin_lock_irqsave(&cs->lock, flags);
155 val = readhscx(cs->hw.teles0.membase, 1, HSCX_ISTA);
156 Start_HSCX:
157 if (val)
158 hscx_int_main(cs, val);
159 val = readisac(cs->hw.teles0.membase, ISAC_ISTA);
160 Start_ISAC:
161 if (val)
162 isac_interrupt(cs, val);
163 count++;
164 val = readhscx(cs->hw.teles0.membase, 1, HSCX_ISTA);
165 if (val && count < 5) {
166 if (cs->debug & L1_DEB_HSCX)
167 debugl1(cs, "HSCX IntStat after IntRoutine");
168 goto Start_HSCX;
169 }
170 val = readisac(cs->hw.teles0.membase, ISAC_ISTA);
171 if (val && count < 5) {
172 if (cs->debug & L1_DEB_ISAC)
173 debugl1(cs, "ISAC IntStat after IntRoutine");
174 goto Start_ISAC;
175 }
176 writehscx(cs->hw.teles0.membase, 0, HSCX_MASK, 0xFF);
177 writehscx(cs->hw.teles0.membase, 1, HSCX_MASK, 0xFF);
178 writeisac(cs->hw.teles0.membase, ISAC_MASK, 0xFF);
179 writeisac(cs->hw.teles0.membase, ISAC_MASK, 0x0);
180 writehscx(cs->hw.teles0.membase, 0, HSCX_MASK, 0x0);
181 writehscx(cs->hw.teles0.membase, 1, HSCX_MASK, 0x0);
182 spin_unlock_irqrestore(&cs->lock, flags);
183 return IRQ_HANDLED;
184}
185
186void
187release_io_teles0(struct IsdnCardState *cs)
188{
189 if (cs->hw.teles0.cfg_reg)
190 release_region(cs->hw.teles0.cfg_reg, 8);
191 iounmap(cs->hw.teles0.membase);
192 release_mem_region(cs->hw.teles0.phymem, TELES_IOMEM_SIZE);
193}
194
195static int
196reset_teles0(struct IsdnCardState *cs)
197{
198 u_char cfval;
199
200 if (cs->hw.teles0.cfg_reg) {
201 switch (cs->irq) {
202 case 2:
203 case 9:
204 cfval = 0x00;
205 break;
206 case 3:
207 cfval = 0x02;
208 break;
209 case 4:
210 cfval = 0x04;
211 break;
212 case 5:
213 cfval = 0x06;
214 break;
215 case 10:
216 cfval = 0x08;
217 break;
218 case 11:
219 cfval = 0x0A;
220 break;
221 case 12:
222 cfval = 0x0C;
223 break;
224 case 15:
225 cfval = 0x0E;
226 break;
227 default:
228 return(1);
229 }
230 cfval |= ((cs->hw.teles0.phymem >> 9) & 0xF0);
231 byteout(cs->hw.teles0.cfg_reg + 4, cfval);
232 HZDELAY(HZ / 10 + 1);
233 byteout(cs->hw.teles0.cfg_reg + 4, cfval | 1);
234 HZDELAY(HZ / 10 + 1);
235 }
236 writeb(0, cs->hw.teles0.membase + 0x80); mb();
237 HZDELAY(HZ / 5 + 1);
238 writeb(1, cs->hw.teles0.membase + 0x80); mb();
239 HZDELAY(HZ / 5 + 1);
240 return(0);
241}
242
243static int
244Teles_card_msg(struct IsdnCardState *cs, int mt, void *arg)
245{
246 u_long flags;
247
248 switch (mt) {
249 case CARD_RESET:
250 spin_lock_irqsave(&cs->lock, flags);
251 reset_teles0(cs);
252 spin_unlock_irqrestore(&cs->lock, flags);
253 return(0);
254 case CARD_RELEASE:
255 release_io_teles0(cs);
256 return(0);
257 case CARD_INIT:
258 spin_lock_irqsave(&cs->lock, flags);
259 inithscxisac(cs, 3);
260 spin_unlock_irqrestore(&cs->lock, flags);
261 return(0);
262 case CARD_TEST:
263 return(0);
264 }
265 return(0);
266}
267
268int __init
269setup_teles0(struct IsdnCard *card)
270{
271 u_char val;
272 struct IsdnCardState *cs = card->cs;
273 char tmp[64];
274
275 strcpy(tmp, teles0_revision);
276 printk(KERN_INFO "HiSax: Teles 8.0/16.0 driver Rev. %s\n", HiSax_getrev(tmp));
277 if ((cs->typ != ISDN_CTYPE_16_0) && (cs->typ != ISDN_CTYPE_8_0))
278 return (0);
279
280 if (cs->typ == ISDN_CTYPE_16_0)
281 cs->hw.teles0.cfg_reg = card->para[2];
282 else /* 8.0 */
283 cs->hw.teles0.cfg_reg = 0;
284
285 if (card->para[1] < 0x10000) {
286 card->para[1] <<= 4;
287 printk(KERN_INFO
288 "Teles0: membase configured DOSish, assuming 0x%lx\n",
289 (unsigned long) card->para[1]);
290 }
291 cs->irq = card->para[0];
292 if (cs->hw.teles0.cfg_reg) {
293 if (!request_region(cs->hw.teles0.cfg_reg, 8, "teles cfg")) {
294 printk(KERN_WARNING
295 "HiSax: %s config port %x-%x already in use\n",
296 CardType[card->typ],
297 cs->hw.teles0.cfg_reg,
298 cs->hw.teles0.cfg_reg + 8);
299 return (0);
300 }
301 }
302 if (cs->hw.teles0.cfg_reg) {
303 if ((val = bytein(cs->hw.teles0.cfg_reg + 0)) != 0x51) {
304 printk(KERN_WARNING "Teles0: 16.0 Byte at %x is %x\n",
305 cs->hw.teles0.cfg_reg + 0, val);
306 release_region(cs->hw.teles0.cfg_reg, 8);
307 return (0);
308 }
309 if ((val = bytein(cs->hw.teles0.cfg_reg + 1)) != 0x93) {
310 printk(KERN_WARNING "Teles0: 16.0 Byte at %x is %x\n",
311 cs->hw.teles0.cfg_reg + 1, val);
312 release_region(cs->hw.teles0.cfg_reg, 8);
313 return (0);
314 }
315 val = bytein(cs->hw.teles0.cfg_reg + 2); /* 0x1e=without AB
316 * 0x1f=with AB
317 * 0x1c 16.3 ???
318 */
319 if (val != 0x1e && val != 0x1f) {
320 printk(KERN_WARNING "Teles0: 16.0 Byte at %x is %x\n",
321 cs->hw.teles0.cfg_reg + 2, val);
322 release_region(cs->hw.teles0.cfg_reg, 8);
323 return (0);
324 }
325 }
326 /* 16.0 and 8.0 designed for IOM1 */
327 test_and_set_bit(HW_IOM1, &cs->HW_Flags);
328 cs->hw.teles0.phymem = card->para[1];
329 if (!request_mem_region(cs->hw.teles0.phymem, TELES_IOMEM_SIZE, "teles iomem")) {
330 printk(KERN_WARNING
331 "HiSax: %s memory region %lx-%lx already in use\n",
332 CardType[card->typ],
333 cs->hw.teles0.phymem,
334 cs->hw.teles0.phymem + TELES_IOMEM_SIZE);
335 if (cs->hw.teles0.cfg_reg)
336 release_region(cs->hw.teles0.cfg_reg, 8);
337 return (0);
338 }
339 cs->hw.teles0.membase = ioremap(cs->hw.teles0.phymem, TELES_IOMEM_SIZE);
340 printk(KERN_INFO
341 "HiSax: %s config irq:%d mem:%p cfg:0x%X\n",
342 CardType[cs->typ], cs->irq,
343 cs->hw.teles0.membase, cs->hw.teles0.cfg_reg);
344 if (reset_teles0(cs)) {
345 printk(KERN_WARNING "Teles0: wrong IRQ\n");
346 release_io_teles0(cs);
347 return (0);
348 }
349 setup_isac(cs);
350 cs->readisac = &ReadISAC;
351 cs->writeisac = &WriteISAC;
352 cs->readisacfifo = &ReadISACfifo;
353 cs->writeisacfifo = &WriteISACfifo;
354 cs->BC_Read_Reg = &ReadHSCX;
355 cs->BC_Write_Reg = &WriteHSCX;
356 cs->BC_Send_Data = &hscx_fill_fifo;
357 cs->cardmsg = &Teles_card_msg;
358 cs->irq_func = &teles0_interrupt;
359 ISACVersion(cs, "Teles0:");
360 if (HscxVersion(cs, "Teles0:")) {
361 printk(KERN_WARNING
362 "Teles0: wrong HSCX versions check IO/MEM addresses\n");
363 release_io_teles0(cs);
364 return (0);
365 }
366 return (1);
367}
diff --git a/drivers/isdn/hisax/teles3.c b/drivers/isdn/hisax/teles3.c
new file mode 100644
index 000000000000..c5b1f65f7275
--- /dev/null
+++ b/drivers/isdn/hisax/teles3.c
@@ -0,0 +1,499 @@
1/* $Id: teles3.c,v 2.19.2.4 2004/01/13 23:48:39 keil Exp $
2 *
3 * low level stuff for Teles 16.3 & PNP isdn cards
4 *
5 * Author Karsten Keil
6 * Copyright by Karsten Keil <keil@isdn4linux.de>
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 * Thanks to Jan den Ouden
12 * Fritz Elfert
13 * Beat Doebeli
14 *
15 */
16#include <linux/init.h>
17#include <linux/isapnp.h>
18#include "hisax.h"
19#include "isac.h"
20#include "hscx.h"
21#include "isdnl1.h"
22
23extern const char *CardType[];
24const char *teles3_revision = "$Revision: 2.19.2.4 $";
25
26#define byteout(addr,val) outb(val,addr)
27#define bytein(addr) inb(addr)
28
29static inline u_char
30readreg(unsigned int adr, u_char off)
31{
32 return (bytein(adr + off));
33}
34
35static inline void
36writereg(unsigned int adr, u_char off, u_char data)
37{
38 byteout(adr + off, data);
39}
40
41
42static inline void
43read_fifo(unsigned int adr, u_char * data, int size)
44{
45 insb(adr, data, size);
46}
47
48static void
49write_fifo(unsigned int adr, u_char * data, int size)
50{
51 outsb(adr, data, size);
52}
53
54/* Interface functions */
55
56static u_char
57ReadISAC(struct IsdnCardState *cs, u_char offset)
58{
59 return (readreg(cs->hw.teles3.isac, offset));
60}
61
62static void
63WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
64{
65 writereg(cs->hw.teles3.isac, offset, value);
66}
67
68static void
69ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
70{
71 read_fifo(cs->hw.teles3.isacfifo, data, size);
72}
73
74static void
75WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
76{
77 write_fifo(cs->hw.teles3.isacfifo, data, size);
78}
79
80static u_char
81ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
82{
83 return (readreg(cs->hw.teles3.hscx[hscx], offset));
84}
85
86static void
87WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
88{
89 writereg(cs->hw.teles3.hscx[hscx], offset, value);
90}
91
92/*
93 * fast interrupt HSCX stuff goes here
94 */
95
96#define READHSCX(cs, nr, reg) readreg(cs->hw.teles3.hscx[nr], reg)
97#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.teles3.hscx[nr], reg, data)
98#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo(cs->hw.teles3.hscxfifo[nr], ptr, cnt)
99#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo(cs->hw.teles3.hscxfifo[nr], ptr, cnt)
100
101#include "hscx_irq.c"
102
103static irqreturn_t
104teles3_interrupt(int intno, void *dev_id, struct pt_regs *regs)
105{
106#define MAXCOUNT 5
107 struct IsdnCardState *cs = dev_id;
108 u_char val;
109 u_long flags;
110 int count = 0;
111
112 spin_lock_irqsave(&cs->lock, flags);
113 val = readreg(cs->hw.teles3.hscx[1], HSCX_ISTA);
114 Start_HSCX:
115 if (val)
116 hscx_int_main(cs, val);
117 val = readreg(cs->hw.teles3.isac, ISAC_ISTA);
118 Start_ISAC:
119 if (val)
120 isac_interrupt(cs, val);
121 count++;
122 val = readreg(cs->hw.teles3.hscx[1], HSCX_ISTA);
123 if (val && count < MAXCOUNT) {
124 if (cs->debug & L1_DEB_HSCX)
125 debugl1(cs, "HSCX IntStat after IntRoutine");
126 goto Start_HSCX;
127 }
128 val = readreg(cs->hw.teles3.isac, ISAC_ISTA);
129 if (val && count < MAXCOUNT) {
130 if (cs->debug & L1_DEB_ISAC)
131 debugl1(cs, "ISAC IntStat after IntRoutine");
132 goto Start_ISAC;
133 }
134 if (count >= MAXCOUNT)
135 printk(KERN_WARNING "Teles3: more than %d loops in teles3_interrupt\n", count);
136 writereg(cs->hw.teles3.hscx[0], HSCX_MASK, 0xFF);
137 writereg(cs->hw.teles3.hscx[1], HSCX_MASK, 0xFF);
138 writereg(cs->hw.teles3.isac, ISAC_MASK, 0xFF);
139 writereg(cs->hw.teles3.isac, ISAC_MASK, 0x0);
140 writereg(cs->hw.teles3.hscx[0], HSCX_MASK, 0x0);
141 writereg(cs->hw.teles3.hscx[1], HSCX_MASK, 0x0);
142 spin_unlock_irqrestore(&cs->lock, flags);
143 return IRQ_HANDLED;
144}
145
146inline static void
147release_ioregs(struct IsdnCardState *cs, int mask)
148{
149 if (mask & 1)
150 release_region(cs->hw.teles3.isac + 32, 32);
151 if (mask & 2)
152 release_region(cs->hw.teles3.hscx[0] + 32, 32);
153 if (mask & 4)
154 release_region(cs->hw.teles3.hscx[1] + 32, 32);
155}
156
157void
158release_io_teles3(struct IsdnCardState *cs)
159{
160 if (cs->typ == ISDN_CTYPE_TELESPCMCIA) {
161 release_region(cs->hw.teles3.hscx[1], 96);
162 } else {
163 if (cs->hw.teles3.cfg_reg) {
164 if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
165 release_region(cs->hw.teles3.cfg_reg, 1);
166 } else {
167 release_region(cs->hw.teles3.cfg_reg, 8);
168 }
169 }
170 release_ioregs(cs, 0x7);
171 }
172}
173
174static int
175reset_teles3(struct IsdnCardState *cs)
176{
177 u_char irqcfg;
178
179 if (cs->typ != ISDN_CTYPE_TELESPCMCIA) {
180 if ((cs->hw.teles3.cfg_reg) && (cs->typ != ISDN_CTYPE_COMPAQ_ISA)) {
181 switch (cs->irq) {
182 case 2:
183 case 9:
184 irqcfg = 0x00;
185 break;
186 case 3:
187 irqcfg = 0x02;
188 break;
189 case 4:
190 irqcfg = 0x04;
191 break;
192 case 5:
193 irqcfg = 0x06;
194 break;
195 case 10:
196 irqcfg = 0x08;
197 break;
198 case 11:
199 irqcfg = 0x0A;
200 break;
201 case 12:
202 irqcfg = 0x0C;
203 break;
204 case 15:
205 irqcfg = 0x0E;
206 break;
207 default:
208 return(1);
209 }
210 byteout(cs->hw.teles3.cfg_reg + 4, irqcfg);
211 HZDELAY(HZ / 10 + 1);
212 byteout(cs->hw.teles3.cfg_reg + 4, irqcfg | 1);
213 HZDELAY(HZ / 10 + 1);
214 } else if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
215 byteout(cs->hw.teles3.cfg_reg, 0xff);
216 HZDELAY(2);
217 byteout(cs->hw.teles3.cfg_reg, 0x00);
218 HZDELAY(2);
219 } else {
220 /* Reset off for 16.3 PnP , thanks to Georg Acher */
221 byteout(cs->hw.teles3.isac + 0x3c, 0);
222 HZDELAY(2);
223 byteout(cs->hw.teles3.isac + 0x3c, 1);
224 HZDELAY(2);
225 }
226 }
227 return(0);
228}
229
230static int
231Teles_card_msg(struct IsdnCardState *cs, int mt, void *arg)
232{
233 u_long flags;
234
235 switch (mt) {
236 case CARD_RESET:
237 spin_lock_irqsave(&cs->lock, flags);
238 reset_teles3(cs);
239 spin_unlock_irqrestore(&cs->lock, flags);
240 return(0);
241 case CARD_RELEASE:
242 release_io_teles3(cs);
243 return(0);
244 case CARD_INIT:
245 spin_lock_irqsave(&cs->lock, flags);
246 inithscxisac(cs, 3);
247 spin_unlock_irqrestore(&cs->lock, flags);
248 return(0);
249 case CARD_TEST:
250 return(0);
251 }
252 return(0);
253}
254
255#ifdef __ISAPNP__
256
257static struct isapnp_device_id teles_ids[] __devinitdata = {
258 { ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2110),
259 ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2110),
260 (unsigned long) "Teles 16.3 PnP" },
261 { ISAPNP_VENDOR('C', 'T', 'X'), ISAPNP_FUNCTION(0x0),
262 ISAPNP_VENDOR('C', 'T', 'X'), ISAPNP_FUNCTION(0x0),
263 (unsigned long) "Creatix 16.3 PnP" },
264 { ISAPNP_VENDOR('C', 'P', 'Q'), ISAPNP_FUNCTION(0x1002),
265 ISAPNP_VENDOR('C', 'P', 'Q'), ISAPNP_FUNCTION(0x1002),
266 (unsigned long) "Compaq ISDN S0" },
267 { 0, }
268};
269
270static struct isapnp_device_id *ipid __devinitdata = &teles_ids[0];
271static struct pnp_card *pnp_c __devinitdata = NULL;
272#endif
273
274int __devinit
275setup_teles3(struct IsdnCard *card)
276{
277 u_char val;
278 struct IsdnCardState *cs = card->cs;
279 char tmp[64];
280
281 strcpy(tmp, teles3_revision);
282 printk(KERN_INFO "HiSax: Teles IO driver Rev. %s\n", HiSax_getrev(tmp));
283 if ((cs->typ != ISDN_CTYPE_16_3) && (cs->typ != ISDN_CTYPE_PNP)
284 && (cs->typ != ISDN_CTYPE_TELESPCMCIA) && (cs->typ != ISDN_CTYPE_COMPAQ_ISA))
285 return (0);
286
287#ifdef __ISAPNP__
288 if (!card->para[1] && isapnp_present()) {
289 struct pnp_dev *pnp_d;
290 while(ipid->card_vendor) {
291 if ((pnp_c = pnp_find_card(ipid->card_vendor,
292 ipid->card_device, pnp_c))) {
293 pnp_d = NULL;
294 if ((pnp_d = pnp_find_dev(pnp_c,
295 ipid->vendor, ipid->function, pnp_d))) {
296 int err;
297
298 printk(KERN_INFO "HiSax: %s detected\n",
299 (char *)ipid->driver_data);
300 pnp_disable_dev(pnp_d);
301 err = pnp_activate_dev(pnp_d);
302 if (err<0) {
303 printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
304 __FUNCTION__, err);
305 return(0);
306 }
307 card->para[3] = pnp_port_start(pnp_d, 2);
308 card->para[2] = pnp_port_start(pnp_d, 1);
309 card->para[1] = pnp_port_start(pnp_d, 0);
310 card->para[0] = pnp_irq(pnp_d, 0);
311 if (!card->para[0] || !card->para[1] || !card->para[2]) {
312 printk(KERN_ERR "Teles PnP:some resources are missing %ld/%lx/%lx\n",
313 card->para[0], card->para[1], card->para[2]);
314 pnp_disable_dev(pnp_d);
315 return(0);
316 }
317 break;
318 } else {
319 printk(KERN_ERR "Teles PnP: PnP error card found, no device\n");
320 }
321 }
322 ipid++;
323 pnp_c = NULL;
324 }
325 if (!ipid->card_vendor) {
326 printk(KERN_INFO "Teles PnP: no ISAPnP card found\n");
327 return(0);
328 }
329 }
330#endif
331 if (cs->typ == ISDN_CTYPE_16_3) {
332 cs->hw.teles3.cfg_reg = card->para[1];
333 switch (cs->hw.teles3.cfg_reg) {
334 case 0x180:
335 case 0x280:
336 case 0x380:
337 cs->hw.teles3.cfg_reg |= 0xc00;
338 break;
339 }
340 cs->hw.teles3.isac = cs->hw.teles3.cfg_reg - 0x420;
341 cs->hw.teles3.hscx[0] = cs->hw.teles3.cfg_reg - 0xc20;
342 cs->hw.teles3.hscx[1] = cs->hw.teles3.cfg_reg - 0x820;
343 } else if (cs->typ == ISDN_CTYPE_TELESPCMCIA) {
344 cs->hw.teles3.cfg_reg = 0;
345 cs->hw.teles3.hscx[0] = card->para[1] - 0x20;
346 cs->hw.teles3.hscx[1] = card->para[1];
347 cs->hw.teles3.isac = card->para[1] + 0x20;
348 } else if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
349 cs->hw.teles3.cfg_reg = card->para[3];
350 cs->hw.teles3.isac = card->para[2] - 32;
351 cs->hw.teles3.hscx[0] = card->para[1] - 32;
352 cs->hw.teles3.hscx[1] = card->para[1];
353 } else { /* PNP */
354 cs->hw.teles3.cfg_reg = 0;
355 cs->hw.teles3.isac = card->para[1] - 32;
356 cs->hw.teles3.hscx[0] = card->para[2] - 32;
357 cs->hw.teles3.hscx[1] = card->para[2];
358 }
359 cs->irq = card->para[0];
360 cs->hw.teles3.isacfifo = cs->hw.teles3.isac + 0x3e;
361 cs->hw.teles3.hscxfifo[0] = cs->hw.teles3.hscx[0] + 0x3e;
362 cs->hw.teles3.hscxfifo[1] = cs->hw.teles3.hscx[1] + 0x3e;
363 if (cs->typ == ISDN_CTYPE_TELESPCMCIA) {
364 if (!request_region(cs->hw.teles3.hscx[1], 96, "HiSax Teles PCMCIA")) {
365 printk(KERN_WARNING
366 "HiSax: %s ports %x-%x already in use\n",
367 CardType[cs->typ],
368 cs->hw.teles3.hscx[1],
369 cs->hw.teles3.hscx[1] + 96);
370 return (0);
371 }
372 } else {
373 if (cs->hw.teles3.cfg_reg) {
374 if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
375 if (!request_region(cs->hw.teles3.cfg_reg, 1, "teles3 cfg")) {
376 printk(KERN_WARNING
377 "HiSax: %s config port %x already in use\n",
378 CardType[card->typ],
379 cs->hw.teles3.cfg_reg);
380 return (0);
381 }
382 } else {
383 if (!request_region(cs->hw.teles3.cfg_reg, 8, "teles3 cfg")) {
384 printk(KERN_WARNING
385 "HiSax: %s config port %x-%x already in use\n",
386 CardType[card->typ],
387 cs->hw.teles3.cfg_reg,
388 cs->hw.teles3.cfg_reg + 8);
389 return (0);
390 }
391 }
392 }
393 if (!request_region(cs->hw.teles3.isac + 32, 32, "HiSax isac")) {
394 printk(KERN_WARNING
395 "HiSax: %s isac ports %x-%x already in use\n",
396 CardType[cs->typ],
397 cs->hw.teles3.isac + 32,
398 cs->hw.teles3.isac + 64);
399 if (cs->hw.teles3.cfg_reg) {
400 if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
401 release_region(cs->hw.teles3.cfg_reg, 1);
402 } else {
403 release_region(cs->hw.teles3.cfg_reg, 8);
404 }
405 }
406 return (0);
407 }
408 if (!request_region(cs->hw.teles3.hscx[0] + 32, 32, "HiSax hscx A")) {
409 printk(KERN_WARNING
410 "HiSax: %s hscx A ports %x-%x already in use\n",
411 CardType[cs->typ],
412 cs->hw.teles3.hscx[0] + 32,
413 cs->hw.teles3.hscx[0] + 64);
414 if (cs->hw.teles3.cfg_reg) {
415 if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
416 release_region(cs->hw.teles3.cfg_reg, 1);
417 } else {
418 release_region(cs->hw.teles3.cfg_reg, 8);
419 }
420 }
421 release_ioregs(cs, 1);
422 return (0);
423 }
424 if (!request_region(cs->hw.teles3.hscx[1] + 32, 32, "HiSax hscx B")) {
425 printk(KERN_WARNING
426 "HiSax: %s hscx B ports %x-%x already in use\n",
427 CardType[cs->typ],
428 cs->hw.teles3.hscx[1] + 32,
429 cs->hw.teles3.hscx[1] + 64);
430 if (cs->hw.teles3.cfg_reg) {
431 if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
432 release_region(cs->hw.teles3.cfg_reg, 1);
433 } else {
434 release_region(cs->hw.teles3.cfg_reg, 8);
435 }
436 }
437 release_ioregs(cs, 3);
438 return (0);
439 }
440 }
441 if ((cs->hw.teles3.cfg_reg) && (cs->typ != ISDN_CTYPE_COMPAQ_ISA)) {
442 if ((val = bytein(cs->hw.teles3.cfg_reg + 0)) != 0x51) {
443 printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n",
444 cs->hw.teles3.cfg_reg + 0, val);
445 release_io_teles3(cs);
446 return (0);
447 }
448 if ((val = bytein(cs->hw.teles3.cfg_reg + 1)) != 0x93) {
449 printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n",
450 cs->hw.teles3.cfg_reg + 1, val);
451 release_io_teles3(cs);
452 return (0);
453 }
454 val = bytein(cs->hw.teles3.cfg_reg + 2);/* 0x1e=without AB
455 * 0x1f=with AB
456 * 0x1c 16.3 ???
457 * 0x39 16.3 1.1
458 * 0x38 16.3 1.3
459 * 0x46 16.3 with AB + Video (Teles-Vision)
460 */
461 if (val != 0x46 && val != 0x39 && val != 0x38 && val != 0x1c && val != 0x1e && val != 0x1f) {
462 printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n",
463 cs->hw.teles3.cfg_reg + 2, val);
464 release_io_teles3(cs);
465 return (0);
466 }
467 }
468 printk(KERN_INFO
469 "HiSax: %s config irq:%d isac:0x%X cfg:0x%X\n",
470 CardType[cs->typ], cs->irq,
471 cs->hw.teles3.isac + 32, cs->hw.teles3.cfg_reg);
472 printk(KERN_INFO
473 "HiSax: hscx A:0x%X hscx B:0x%X\n",
474 cs->hw.teles3.hscx[0] + 32, cs->hw.teles3.hscx[1] + 32);
475
476 setup_isac(cs);
477 if (reset_teles3(cs)) {
478 printk(KERN_WARNING "Teles3: wrong IRQ\n");
479 release_io_teles3(cs);
480 return (0);
481 }
482 cs->readisac = &ReadISAC;
483 cs->writeisac = &WriteISAC;
484 cs->readisacfifo = &ReadISACfifo;
485 cs->writeisacfifo = &WriteISACfifo;
486 cs->BC_Read_Reg = &ReadHSCX;
487 cs->BC_Write_Reg = &WriteHSCX;
488 cs->BC_Send_Data = &hscx_fill_fifo;
489 cs->cardmsg = &Teles_card_msg;
490 cs->irq_func = &teles3_interrupt;
491 ISACVersion(cs, "Teles3:");
492 if (HscxVersion(cs, "Teles3:")) {
493 printk(KERN_WARNING
494 "Teles3: wrong HSCX versions check IO address\n");
495 release_io_teles3(cs);
496 return (0);
497 }
498 return (1);
499}
diff --git a/drivers/isdn/hisax/teles_cs.c b/drivers/isdn/hisax/teles_cs.c
new file mode 100644
index 000000000000..63e8e20c17a8
--- /dev/null
+++ b/drivers/isdn/hisax/teles_cs.c
@@ -0,0 +1,513 @@
1/* $Id: teles_cs.c,v 1.1.2.2 2004/01/25 15:07:06 keil Exp $ */
2/*======================================================================
3
4 A teles S0 PCMCIA client driver
5
6 Based on skeleton by David Hinds, dhinds@allegro.stanford.edu
7 Written by Christof Petig, christof.petig@wtal.de
8
9 Also inspired by ELSA PCMCIA driver
10 by Klaus Lichtenwalder <Lichtenwalder@ACM.org>
11
12 Extentions to new hisax_pcmcia by Karsten Keil
13
14 minor changes to be compatible with kernel 2.4.x
15 by Jan.Schubert@GMX.li
16
17======================================================================*/
18
19#include <linux/kernel.h>
20#include <linux/module.h>
21#include <linux/init.h>
22#include <linux/sched.h>
23#include <linux/ptrace.h>
24#include <linux/slab.h>
25#include <linux/string.h>
26#include <linux/timer.h>
27#include <linux/ioport.h>
28#include <asm/io.h>
29#include <asm/system.h>
30
31#include <pcmcia/version.h>
32#include <pcmcia/cs_types.h>
33#include <pcmcia/cs.h>
34#include <pcmcia/cistpl.h>
35#include <pcmcia/cisreg.h>
36#include <pcmcia/ds.h>
37#include "hisax_cfg.h"
38
39MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for Teles PCMCIA cards");
40MODULE_AUTHOR("Christof Petig, christof.petig@wtal.de, Karsten Keil, kkeil@suse.de");
41MODULE_LICENSE("GPL");
42
43/*
44 All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If
45 you do not define PCMCIA_DEBUG at all, all the debug code will be
46 left out. If you compile with PCMCIA_DEBUG=0, the debug code will
47 be present but disabled -- but it can then be enabled for specific
48 modules at load time with a 'pc_debug=#' option to insmod.
49*/
50
51#ifdef PCMCIA_DEBUG
52static int pc_debug = PCMCIA_DEBUG;
53module_param(pc_debug, int, 0);
54#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args);
55static char *version =
56"teles_cs.c 2.10 2002/07/30 22:23:34 kkeil";
57#else
58#define DEBUG(n, args...)
59#endif
60
61/*====================================================================*/
62
63/* Parameters that can be set with 'insmod' */
64
65static int protocol = 2; /* EURO-ISDN Default */
66module_param(protocol, int, 0);
67
68/*====================================================================*/
69
70/*
71 The event() function is this driver's Card Services event handler.
72 It will be called by Card Services when an appropriate card status
73 event is received. The config() and release() entry points are
74 used to configure or release a socket, in response to card insertion
75 and ejection events. They are invoked from the teles_cs event
76 handler.
77*/
78
79static void teles_cs_config(dev_link_t *link);
80static void teles_cs_release(dev_link_t *link);
81static int teles_cs_event(event_t event, int priority,
82 event_callback_args_t *args);
83
84/*
85 The attach() and detach() entry points are used to create and destroy
86 "instances" of the driver, where each instance represents everything
87 needed to manage one actual PCMCIA card.
88*/
89
90static dev_link_t *teles_attach(void);
91static void teles_detach(dev_link_t *);
92
93/*
94 The dev_info variable is the "key" that is used to match up this
95 device driver with appropriate cards, through the card configuration
96 database.
97*/
98
99static dev_info_t dev_info = "teles_cs";
100
101/*
102 A linked list of "instances" of the teles_cs device. Each actual
103 PCMCIA card corresponds to one device instance, and is described
104 by one dev_link_t structure (defined in ds.h).
105
106 You may not want to use a linked list for this -- for example, the
107 memory card driver uses an array of dev_link_t pointers, where minor
108 device numbers are used to derive the corresponding array index.
109*/
110
111static dev_link_t *dev_list = NULL;
112
113/*
114 A dev_link_t structure has fields for most things that are needed
115 to keep track of a socket, but there will usually be some device
116 specific information that also needs to be kept track of. The
117 'priv' pointer in a dev_link_t structure can be used to point to
118 a device-specific private data structure, like this.
119
120 To simplify the data structure handling, we actually include the
121 dev_link_t structure in the device's private data structure.
122
123 A driver needs to provide a dev_node_t structure for each device
124 on a card. In some cases, there is only one device per card (for
125 example, ethernet cards, modems). In other cases, there may be
126 many actual or logical devices (SCSI adapters, memory cards with
127 multiple partitions). The dev_node_t structures need to be kept
128 in a linked list starting at the 'dev' field of a dev_link_t
129 structure. We allocate them in the card's private data structure,
130 because they generally shouldn't be allocated dynamically.
131 In this case, we also provide a flag to indicate if a device is
132 "stopped" due to a power management event, or card ejection. The
133 device IO routines can use a flag like this to throttle IO to a
134 card that is not ready to accept it.
135*/
136
137typedef struct local_info_t {
138 dev_link_t link;
139 dev_node_t node;
140 int busy;
141 int cardnr;
142} local_info_t;
143
144/*======================================================================
145
146 teles_attach() creates an "instance" of the driver, allocatingx
147 local data structures for one device. The device is registered
148 with Card Services.
149
150 The dev_link structure is initialized, but we don't actually
151 configure the card at this point -- we wait until we receive a
152 card insertion event.
153
154======================================================================*/
155
156static dev_link_t *teles_attach(void)
157{
158 client_reg_t client_reg;
159 dev_link_t *link;
160 local_info_t *local;
161 int ret;
162
163 DEBUG(0, "teles_attach()\n");
164
165 /* Allocate space for private device-specific data */
166 local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
167 if (!local) return NULL;
168 memset(local, 0, sizeof(local_info_t));
169 local->cardnr = -1;
170 link = &local->link; link->priv = local;
171
172 /* Interrupt setup */
173 link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED;
174 link->irq.IRQInfo1 = IRQ_LEVEL_ID|IRQ_SHARE_ID;
175 link->irq.Handler = NULL;
176
177 /*
178 General socket configuration defaults can go here. In this
179 client, we assume very little, and rely on the CIS for almost
180 everything. In most clients, many details (i.e., number, sizes,
181 and attributes of IO windows) are fixed by the nature of the
182 device, and can be hard-wired here.
183 */
184 link->io.NumPorts1 = 96;
185 link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
186 link->io.IOAddrLines = 5;
187
188 link->conf.Attributes = CONF_ENABLE_IRQ;
189 link->conf.Vcc = 50;
190 link->conf.IntType = INT_MEMORY_AND_IO;
191
192 /* Register with Card Services */
193 link->next = dev_list;
194 dev_list = link;
195 client_reg.dev_info = &dev_info;
196 client_reg.EventMask =
197 CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
198 CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
199 CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
200 client_reg.event_handler = &teles_cs_event;
201 client_reg.Version = 0x0210;
202 client_reg.event_callback_args.client_data = link;
203 ret = pcmcia_register_client(&link->handle, &client_reg);
204 if (ret != CS_SUCCESS) {
205 cs_error(link->handle, RegisterClient, ret);
206 teles_detach(link);
207 return NULL;
208 }
209
210 return link;
211} /* teles_attach */
212
213/*======================================================================
214
215 This deletes a driver "instance". The device is de-registered
216 with Card Services. If it has been released, all local data
217 structures are freed. Otherwise, the structures will be freed
218 when the device is released.
219
220======================================================================*/
221
222static void teles_detach(dev_link_t *link)
223{
224 dev_link_t **linkp;
225 local_info_t *info = link->priv;
226 int ret;
227
228 DEBUG(0, "teles_detach(0x%p)\n", link);
229
230 /* Locate device structure */
231 for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
232 if (*linkp == link) break;
233 if (*linkp == NULL)
234 return;
235
236 if (link->state & DEV_CONFIG)
237 teles_cs_release(link);
238
239 /* Break the link with Card Services */
240 if (link->handle) {
241 ret = pcmcia_deregister_client(link->handle);
242 if (ret != CS_SUCCESS)
243 cs_error(link->handle, DeregisterClient, ret);
244 }
245
246 /* Unlink device structure and free it */
247 *linkp = link->next;
248 kfree(info);
249
250} /* teles_detach */
251
252/*======================================================================
253
254 teles_cs_config() is scheduled to run after a CARD_INSERTION event
255 is received, to configure the PCMCIA socket, and to make the
256 device available to the system.
257
258======================================================================*/
259static int get_tuple(client_handle_t handle, tuple_t *tuple,
260 cisparse_t *parse)
261{
262 int i = pcmcia_get_tuple_data(handle, tuple);
263 if (i != CS_SUCCESS) return i;
264 return pcmcia_parse_tuple(handle, tuple, parse);
265}
266
267static int first_tuple(client_handle_t handle, tuple_t *tuple,
268 cisparse_t *parse)
269{
270 int i = pcmcia_get_first_tuple(handle, tuple);
271 if (i != CS_SUCCESS) return i;
272 return get_tuple(handle, tuple, parse);
273}
274
275static int next_tuple(client_handle_t handle, tuple_t *tuple,
276 cisparse_t *parse)
277{
278 int i = pcmcia_get_next_tuple(handle, tuple);
279 if (i != CS_SUCCESS) return i;
280 return get_tuple(handle, tuple, parse);
281}
282
283static void teles_cs_config(dev_link_t *link)
284{
285 client_handle_t handle;
286 tuple_t tuple;
287 cisparse_t parse;
288 local_info_t *dev;
289 int i, j, last_fn;
290 u_short buf[128];
291 cistpl_cftable_entry_t *cf = &parse.cftable_entry;
292 IsdnCard_t icard;
293
294 DEBUG(0, "teles_config(0x%p)\n", link);
295 handle = link->handle;
296 dev = link->priv;
297
298 /*
299 This reads the card's CONFIG tuple to find its configuration
300 registers.
301 */
302 tuple.DesiredTuple = CISTPL_CONFIG;
303 tuple.TupleData = (cisdata_t *)buf;
304 tuple.TupleDataMax = 255;
305 tuple.TupleOffset = 0;
306 tuple.Attributes = 0;
307 i = first_tuple(handle, &tuple, &parse);
308 if (i != CS_SUCCESS) {
309 last_fn = ParseTuple;
310 goto cs_failed;
311 }
312 link->conf.ConfigBase = parse.config.base;
313 link->conf.Present = parse.config.rmask[0];
314
315 /* Configure card */
316 link->state |= DEV_CONFIG;
317
318 tuple.TupleData = (cisdata_t *)buf;
319 tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
320 tuple.Attributes = 0;
321 tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
322 i = first_tuple(handle, &tuple, &parse);
323 while (i == CS_SUCCESS) {
324 if ( (cf->io.nwin > 0) && cf->io.win[0].base) {
325 printk(KERN_INFO "(teles_cs: looks like the 96 model)\n");
326 link->conf.ConfigIndex = cf->index;
327 link->io.BasePort1 = cf->io.win[0].base;
328 i = pcmcia_request_io(link->handle, &link->io);
329 if (i == CS_SUCCESS) break;
330 } else {
331 printk(KERN_INFO "(teles_cs: looks like the 97 model)\n");
332 link->conf.ConfigIndex = cf->index;
333 for (i = 0, j = 0x2f0; j > 0x100; j -= 0x10) {
334 link->io.BasePort1 = j;
335 i = pcmcia_request_io(link->handle, &link->io);
336 if (i == CS_SUCCESS) break;
337 }
338 break;
339 }
340 i = next_tuple(handle, &tuple, &parse);
341 }
342
343 if (i != CS_SUCCESS) {
344 last_fn = RequestIO;
345 goto cs_failed;
346 }
347
348 i = pcmcia_request_irq(link->handle, &link->irq);
349 if (i != CS_SUCCESS) {
350 link->irq.AssignedIRQ = 0;
351 last_fn = RequestIRQ;
352 goto cs_failed;
353 }
354
355 i = pcmcia_request_configuration(link->handle, &link->conf);
356 if (i != CS_SUCCESS) {
357 last_fn = RequestConfiguration;
358 goto cs_failed;
359 }
360
361 /* At this point, the dev_node_t structure(s) should be
362 initialized and arranged in a linked list at link->dev. *//* */
363 sprintf(dev->node.dev_name, "teles");
364 dev->node.major = dev->node.minor = 0x0;
365
366 link->dev = &dev->node;
367
368 /* Finally, report what we've done */
369 printk(KERN_INFO "%s: index 0x%02x: Vcc %d.%d",
370 dev->node.dev_name, link->conf.ConfigIndex,
371 link->conf.Vcc/10, link->conf.Vcc%10);
372 if (link->conf.Vpp1)
373 printk(", Vpp %d.%d", link->conf.Vpp1/10, link->conf.Vpp1%10);
374 if (link->conf.Attributes & CONF_ENABLE_IRQ)
375 printk(", irq %d", link->irq.AssignedIRQ);
376 if (link->io.NumPorts1)
377 printk(", io 0x%04x-0x%04x", link->io.BasePort1,
378 link->io.BasePort1+link->io.NumPorts1-1);
379 if (link->io.NumPorts2)
380 printk(" & 0x%04x-0x%04x", link->io.BasePort2,
381 link->io.BasePort2+link->io.NumPorts2-1);
382 printk("\n");
383
384 link->state &= ~DEV_CONFIG_PENDING;
385
386 icard.para[0] = link->irq.AssignedIRQ;
387 icard.para[1] = link->io.BasePort1;
388 icard.protocol = protocol;
389 icard.typ = ISDN_CTYPE_TELESPCMCIA;
390
391 i = hisax_init_pcmcia(link, &(((local_info_t*)link->priv)->busy), &icard);
392 if (i < 0) {
393 printk(KERN_ERR "teles_cs: failed to initialize Teles PCMCIA %d at i/o %#x\n",
394 i, link->io.BasePort1);
395 teles_cs_release(link);
396 } else
397 ((local_info_t*)link->priv)->cardnr = i;
398
399 return;
400cs_failed:
401 cs_error(link->handle, last_fn, i);
402 teles_cs_release(link);
403} /* teles_cs_config */
404
405/*======================================================================
406
407 After a card is removed, teles_cs_release() will unregister the net
408 device, and release the PCMCIA configuration. If the device is
409 still open, this will be postponed until it is closed.
410
411======================================================================*/
412
413static void teles_cs_release(dev_link_t *link)
414{
415 local_info_t *local = link->priv;
416
417 DEBUG(0, "teles_cs_release(0x%p)\n", link);
418
419 if (local) {
420 if (local->cardnr >= 0) {
421 /* no unregister function with hisax */
422 HiSax_closecard(local->cardnr);
423 }
424 }
425 /* Unlink the device chain */
426 link->dev = NULL;
427
428 /* Don't bother checking to see if these succeed or not */
429 if (link->win)
430 pcmcia_release_window(link->win);
431 pcmcia_release_configuration(link->handle);
432 pcmcia_release_io(link->handle, &link->io);
433 pcmcia_release_irq(link->handle, &link->irq);
434 link->state &= ~DEV_CONFIG;
435} /* teles_cs_release */
436
437/*======================================================================
438
439 The card status event handler. Mostly, this schedules other
440 stuff to run after an event is received. A CARD_REMOVAL event
441 also sets some flags to discourage the net drivers from trying
442 to talk to the card any more.
443
444 When a CARD_REMOVAL event is received, we immediately set a flag
445 to block future accesses to this device. All the functions that
446 actually access the device should check this flag to make sure
447 the card is still present.
448
449======================================================================*/
450
451static int teles_cs_event(event_t event, int priority,
452 event_callback_args_t *args)
453{
454 dev_link_t *link = args->client_data;
455 local_info_t *dev = link->priv;
456
457 DEBUG(1, "teles_cs_event(%d)\n", event);
458
459 switch (event) {
460 case CS_EVENT_CARD_REMOVAL:
461 link->state &= ~DEV_PRESENT;
462 if (link->state & DEV_CONFIG) {
463 ((local_info_t*)link->priv)->busy = 1;
464 teles_cs_release(link);
465 }
466 break;
467 case CS_EVENT_CARD_INSERTION:
468 link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
469 teles_cs_config(link);
470 break;
471 case CS_EVENT_PM_SUSPEND:
472 link->state |= DEV_SUSPEND;
473 /* Fall through... */
474 case CS_EVENT_RESET_PHYSICAL:
475 /* Mark the device as stopped, to block IO until later */
476 dev->busy = 1;
477 if (link->state & DEV_CONFIG)
478 pcmcia_release_configuration(link->handle);
479 break;
480 case CS_EVENT_PM_RESUME:
481 link->state &= ~DEV_SUSPEND;
482 /* Fall through... */
483 case CS_EVENT_CARD_RESET:
484 if (link->state & DEV_CONFIG)
485 pcmcia_request_configuration(link->handle, &link->conf);
486 dev->busy = 0;
487 break;
488 }
489 return 0;
490} /* teles_cs_event */
491
492static struct pcmcia_driver teles_cs_driver = {
493 .owner = THIS_MODULE,
494 .drv = {
495 .name = "teles_cs",
496 },
497 .attach = teles_attach,
498 .detach = teles_detach,
499};
500
501static int __init init_teles_cs(void)
502{
503 return pcmcia_register_driver(&teles_cs_driver);
504}
505
506static void __exit exit_teles_cs(void)
507{
508 pcmcia_unregister_driver(&teles_cs_driver);
509 BUG_ON(dev_list != NULL);
510}
511
512module_init(init_teles_cs);
513module_exit(exit_teles_cs);
diff --git a/drivers/isdn/hisax/telespci.c b/drivers/isdn/hisax/telespci.c
new file mode 100644
index 000000000000..0661c6c31ad0
--- /dev/null
+++ b/drivers/isdn/hisax/telespci.c
@@ -0,0 +1,359 @@
1/* $Id: telespci.c,v 2.23.2.3 2004/01/13 14:31:26 keil Exp $
2 *
3 * low level stuff for Teles PCI isdn cards
4 *
5 * Author Ton van Rosmalen
6 * Karsten Keil
7 * Copyright by Ton van Rosmalen
8 * by Karsten Keil <keil@isdn4linux.de>
9 *
10 * This software may be used and distributed according to the terms
11 * of the GNU General Public License, incorporated herein by reference.
12 *
13 */
14
15#include <linux/init.h>
16#include <linux/config.h>
17#include "hisax.h"
18#include "isac.h"
19#include "hscx.h"
20#include "isdnl1.h"
21#include <linux/pci.h>
22
23extern const char *CardType[];
24const char *telespci_revision = "$Revision: 2.23.2.3 $";
25
26#define ZORAN_PO_RQ_PEN 0x02000000
27#define ZORAN_PO_WR 0x00800000
28#define ZORAN_PO_GID0 0x00000000
29#define ZORAN_PO_GID1 0x00100000
30#define ZORAN_PO_GREG0 0x00000000
31#define ZORAN_PO_GREG1 0x00010000
32#define ZORAN_PO_DMASK 0xFF
33
34#define WRITE_ADDR_ISAC (ZORAN_PO_WR | ZORAN_PO_GID0 | ZORAN_PO_GREG0)
35#define READ_DATA_ISAC (ZORAN_PO_GID0 | ZORAN_PO_GREG1)
36#define WRITE_DATA_ISAC (ZORAN_PO_WR | ZORAN_PO_GID0 | ZORAN_PO_GREG1)
37#define WRITE_ADDR_HSCX (ZORAN_PO_WR | ZORAN_PO_GID1 | ZORAN_PO_GREG0)
38#define READ_DATA_HSCX (ZORAN_PO_GID1 | ZORAN_PO_GREG1)
39#define WRITE_DATA_HSCX (ZORAN_PO_WR | ZORAN_PO_GID1 | ZORAN_PO_GREG1)
40
41#define ZORAN_WAIT_NOBUSY do { \
42 portdata = readl(adr + 0x200); \
43 } while (portdata & ZORAN_PO_RQ_PEN)
44
45static inline u_char
46readisac(void __iomem *adr, u_char off)
47{
48 register unsigned int portdata;
49
50 ZORAN_WAIT_NOBUSY;
51
52 /* set address for ISAC */
53 writel(WRITE_ADDR_ISAC | off, adr + 0x200);
54 ZORAN_WAIT_NOBUSY;
55
56 /* read data from ISAC */
57 writel(READ_DATA_ISAC, adr + 0x200);
58 ZORAN_WAIT_NOBUSY;
59 return((u_char)(portdata & ZORAN_PO_DMASK));
60}
61
62static inline void
63writeisac(void __iomem *adr, u_char off, u_char data)
64{
65 register unsigned int portdata;
66
67 ZORAN_WAIT_NOBUSY;
68
69 /* set address for ISAC */
70 writel(WRITE_ADDR_ISAC | off, adr + 0x200);
71 ZORAN_WAIT_NOBUSY;
72
73 /* write data to ISAC */
74 writel(WRITE_DATA_ISAC | data, adr + 0x200);
75 ZORAN_WAIT_NOBUSY;
76}
77
78static inline u_char
79readhscx(void __iomem *adr, int hscx, u_char off)
80{
81 register unsigned int portdata;
82
83 ZORAN_WAIT_NOBUSY;
84 /* set address for HSCX */
85 writel(WRITE_ADDR_HSCX | ((hscx ? 0x40:0) + off), adr + 0x200);
86 ZORAN_WAIT_NOBUSY;
87
88 /* read data from HSCX */
89 writel(READ_DATA_HSCX, adr + 0x200);
90 ZORAN_WAIT_NOBUSY;
91 return ((u_char)(portdata & ZORAN_PO_DMASK));
92}
93
94static inline void
95writehscx(void __iomem *adr, int hscx, u_char off, u_char data)
96{
97 register unsigned int portdata;
98
99 ZORAN_WAIT_NOBUSY;
100 /* set address for HSCX */
101 writel(WRITE_ADDR_HSCX | ((hscx ? 0x40:0) + off), adr + 0x200);
102 ZORAN_WAIT_NOBUSY;
103
104 /* write data to HSCX */
105 writel(WRITE_DATA_HSCX | data, adr + 0x200);
106 ZORAN_WAIT_NOBUSY;
107}
108
109static inline void
110read_fifo_isac(void __iomem *adr, u_char * data, int size)
111{
112 register unsigned int portdata;
113 register int i;
114
115 ZORAN_WAIT_NOBUSY;
116 /* read data from ISAC */
117 for (i = 0; i < size; i++) {
118 /* set address for ISAC fifo */
119 writel(WRITE_ADDR_ISAC | 0x1E, adr + 0x200);
120 ZORAN_WAIT_NOBUSY;
121 writel(READ_DATA_ISAC, adr + 0x200);
122 ZORAN_WAIT_NOBUSY;
123 data[i] = (u_char)(portdata & ZORAN_PO_DMASK);
124 }
125}
126
127static void
128write_fifo_isac(void __iomem *adr, u_char * data, int size)
129{
130 register unsigned int portdata;
131 register int i;
132
133 ZORAN_WAIT_NOBUSY;
134 /* write data to ISAC */
135 for (i = 0; i < size; i++) {
136 /* set address for ISAC fifo */
137 writel(WRITE_ADDR_ISAC | 0x1E, adr + 0x200);
138 ZORAN_WAIT_NOBUSY;
139 writel(WRITE_DATA_ISAC | data[i], adr + 0x200);
140 ZORAN_WAIT_NOBUSY;
141 }
142}
143
144static inline void
145read_fifo_hscx(void __iomem *adr, int hscx, u_char * data, int size)
146{
147 register unsigned int portdata;
148 register int i;
149
150 ZORAN_WAIT_NOBUSY;
151 /* read data from HSCX */
152 for (i = 0; i < size; i++) {
153 /* set address for HSCX fifo */
154 writel(WRITE_ADDR_HSCX |(hscx ? 0x5F:0x1F), adr + 0x200);
155 ZORAN_WAIT_NOBUSY;
156 writel(READ_DATA_HSCX, adr + 0x200);
157 ZORAN_WAIT_NOBUSY;
158 data[i] = (u_char) (portdata & ZORAN_PO_DMASK);
159 }
160}
161
162static inline void
163write_fifo_hscx(void __iomem *adr, int hscx, u_char * data, int size)
164{
165 unsigned int portdata;
166 register int i;
167
168 ZORAN_WAIT_NOBUSY;
169 /* write data to HSCX */
170 for (i = 0; i < size; i++) {
171 /* set address for HSCX fifo */
172 writel(WRITE_ADDR_HSCX |(hscx ? 0x5F:0x1F), adr + 0x200);
173 ZORAN_WAIT_NOBUSY;
174 writel(WRITE_DATA_HSCX | data[i], adr + 0x200);
175 ZORAN_WAIT_NOBUSY;
176 udelay(10);
177 }
178}
179
180/* Interface functions */
181
182static u_char
183ReadISAC(struct IsdnCardState *cs, u_char offset)
184{
185 return (readisac(cs->hw.teles0.membase, offset));
186}
187
188static void
189WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
190{
191 writeisac(cs->hw.teles0.membase, offset, value);
192}
193
194static void
195ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
196{
197 read_fifo_isac(cs->hw.teles0.membase, data, size);
198}
199
200static void
201WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
202{
203 write_fifo_isac(cs->hw.teles0.membase, data, size);
204}
205
206static u_char
207ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
208{
209 return (readhscx(cs->hw.teles0.membase, hscx, offset));
210}
211
212static void
213WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
214{
215 writehscx(cs->hw.teles0.membase, hscx, offset, value);
216}
217
218/*
219 * fast interrupt HSCX stuff goes here
220 */
221
222#define READHSCX(cs, nr, reg) readhscx(cs->hw.teles0.membase, nr, reg)
223#define WRITEHSCX(cs, nr, reg, data) writehscx(cs->hw.teles0.membase, nr, reg, data)
224#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo_hscx(cs->hw.teles0.membase, nr, ptr, cnt)
225#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo_hscx(cs->hw.teles0.membase, nr, ptr, cnt)
226
227#include "hscx_irq.c"
228
229static irqreturn_t
230telespci_interrupt(int intno, void *dev_id, struct pt_regs *regs)
231{
232 struct IsdnCardState *cs = dev_id;
233 u_char hval, ival;
234 u_long flags;
235
236 spin_lock_irqsave(&cs->lock, flags);
237 hval = readhscx(cs->hw.teles0.membase, 1, HSCX_ISTA);
238 if (hval)
239 hscx_int_main(cs, hval);
240 ival = readisac(cs->hw.teles0.membase, ISAC_ISTA);
241 if ((hval | ival) == 0) {
242 spin_unlock_irqrestore(&cs->lock, flags);
243 return IRQ_NONE;
244 }
245 if (ival)
246 isac_interrupt(cs, ival);
247 /* Clear interrupt register for Zoran PCI controller */
248 writel(0x70000000, cs->hw.teles0.membase + 0x3C);
249
250 writehscx(cs->hw.teles0.membase, 0, HSCX_MASK, 0xFF);
251 writehscx(cs->hw.teles0.membase, 1, HSCX_MASK, 0xFF);
252 writeisac(cs->hw.teles0.membase, ISAC_MASK, 0xFF);
253 writeisac(cs->hw.teles0.membase, ISAC_MASK, 0x0);
254 writehscx(cs->hw.teles0.membase, 0, HSCX_MASK, 0x0);
255 writehscx(cs->hw.teles0.membase, 1, HSCX_MASK, 0x0);
256 spin_unlock_irqrestore(&cs->lock, flags);
257 return IRQ_HANDLED;
258}
259
260void
261release_io_telespci(struct IsdnCardState *cs)
262{
263 iounmap(cs->hw.teles0.membase);
264}
265
266static int
267TelesPCI_card_msg(struct IsdnCardState *cs, int mt, void *arg)
268{
269 u_long flags;
270
271 switch (mt) {
272 case CARD_RESET:
273 return(0);
274 case CARD_RELEASE:
275 release_io_telespci(cs);
276 return(0);
277 case CARD_INIT:
278 spin_lock_irqsave(&cs->lock, flags);
279 inithscxisac(cs, 3);
280 spin_unlock_irqrestore(&cs->lock, flags);
281 return(0);
282 case CARD_TEST:
283 return(0);
284 }
285 return(0);
286}
287
288static struct pci_dev *dev_tel __initdata = NULL;
289
290int __init
291setup_telespci(struct IsdnCard *card)
292{
293 struct IsdnCardState *cs = card->cs;
294 char tmp[64];
295
296#ifdef __BIG_ENDIAN
297#error "not running on big endian machines now"
298#endif
299 strcpy(tmp, telespci_revision);
300 printk(KERN_INFO "HiSax: Teles/PCI driver Rev. %s\n", HiSax_getrev(tmp));
301 if (cs->typ != ISDN_CTYPE_TELESPCI)
302 return (0);
303#ifdef CONFIG_PCI
304 if ((dev_tel = pci_find_device (PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36120, dev_tel))) {
305 if (pci_enable_device(dev_tel))
306 return(0);
307 cs->irq = dev_tel->irq;
308 if (!cs->irq) {
309 printk(KERN_WARNING "Teles: No IRQ for PCI card found\n");
310 return(0);
311 }
312 cs->hw.teles0.membase = ioremap(pci_resource_start(dev_tel, 0),
313 PAGE_SIZE);
314 printk(KERN_INFO "Found: Zoran, base-address: 0x%lx, irq: 0x%x\n",
315 pci_resource_start(dev_tel, 0), dev_tel->irq);
316 } else {
317 printk(KERN_WARNING "TelesPCI: No PCI card found\n");
318 return(0);
319 }
320#else
321 printk(KERN_WARNING "HiSax: Teles/PCI and NO_PCI_BIOS\n");
322 printk(KERN_WARNING "HiSax: Teles/PCI unable to config\n");
323 return (0);
324#endif /* CONFIG_PCI */
325
326 /* Initialize Zoran PCI controller */
327 writel(0x00000000, cs->hw.teles0.membase + 0x28);
328 writel(0x01000000, cs->hw.teles0.membase + 0x28);
329 writel(0x01000000, cs->hw.teles0.membase + 0x28);
330 writel(0x7BFFFFFF, cs->hw.teles0.membase + 0x2C);
331 writel(0x70000000, cs->hw.teles0.membase + 0x3C);
332 writel(0x61000000, cs->hw.teles0.membase + 0x40);
333 /* writel(0x00800000, cs->hw.teles0.membase + 0x200); */
334
335 printk(KERN_INFO
336 "HiSax: %s config irq:%d mem:%p\n",
337 CardType[cs->typ], cs->irq,
338 cs->hw.teles0.membase);
339
340 setup_isac(cs);
341 cs->readisac = &ReadISAC;
342 cs->writeisac = &WriteISAC;
343 cs->readisacfifo = &ReadISACfifo;
344 cs->writeisacfifo = &WriteISACfifo;
345 cs->BC_Read_Reg = &ReadHSCX;
346 cs->BC_Write_Reg = &WriteHSCX;
347 cs->BC_Send_Data = &hscx_fill_fifo;
348 cs->cardmsg = &TelesPCI_card_msg;
349 cs->irq_func = &telespci_interrupt;
350 cs->irq_flags |= SA_SHIRQ;
351 ISACVersion(cs, "TelesPCI:");
352 if (HscxVersion(cs, "TelesPCI:")) {
353 printk(KERN_WARNING
354 "TelesPCI: wrong HSCX versions check IO/MEM addresses\n");
355 release_io_telespci(cs);
356 return (0);
357 }
358 return (1);
359}
diff --git a/drivers/isdn/hisax/w6692.c b/drivers/isdn/hisax/w6692.c
new file mode 100644
index 000000000000..d2b6b8e72980
--- /dev/null
+++ b/drivers/isdn/hisax/w6692.c
@@ -0,0 +1,1096 @@
1/* $Id: w6692.c,v 1.18.2.4 2004/02/11 13:21:34 keil Exp $
2 *
3 * Winbond W6692 specific routines
4 *
5 * Author Petr Novak
6 * Copyright by Petr Novak <petr.novak@i.cz>
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 */
12
13#include <linux/config.h>
14#include <linux/init.h>
15#include "hisax.h"
16#include "w6692.h"
17#include "isdnl1.h"
18#include <linux/interrupt.h>
19#include <linux/pci.h>
20
21/* table entry in the PCI devices list */
22typedef struct {
23 int vendor_id;
24 int device_id;
25 char *vendor_name;
26 char *card_name;
27} PCI_ENTRY;
28
29static const PCI_ENTRY id_list[] =
30{
31 {PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND2_6692, "Winbond", "W6692"},
32 {PCI_VENDOR_ID_DYNALINK, PCI_DEVICE_ID_DYNALINK_IS64PH, "Dynalink/AsusCom", "IS64PH"},
33 {0, 0, "U.S.Robotics", "ISDN PCI Card TA"}
34};
35
36#define W6692_SV_USR 0x16ec
37#define W6692_SD_USR 0x3409
38#define W6692_WINBOND 0
39#define W6692_DYNALINK 1
40#define W6692_USR 2
41
42extern const char *CardType[];
43
44const char *w6692_revision = "$Revision: 1.18.2.4 $";
45
46#define DBUSY_TIMER_VALUE 80
47
48static char *W6692Ver[] __initdata =
49{"W6692 V00", "W6692 V01", "W6692 V10",
50 "W6692 V11"};
51
52static void __init
53W6692Version(struct IsdnCardState *cs, char *s)
54{
55 int val;
56
57 val = cs->readW6692(cs, W_D_RBCH);
58 printk(KERN_INFO "%s Winbond W6692 version (%x): %s\n", s, val, W6692Ver[(val >> 6) & 3]);
59}
60
61static void
62ph_command(struct IsdnCardState *cs, unsigned int command)
63{
64 if (cs->debug & L1_DEB_ISAC)
65 debugl1(cs, "ph_command %x", command);
66 cs->writeisac(cs, W_CIX, command);
67}
68
69
70static void
71W6692_new_ph(struct IsdnCardState *cs)
72{
73 switch (cs->dc.w6692.ph_state) {
74 case (W_L1CMD_RST):
75 ph_command(cs, W_L1CMD_DRC);
76 l1_msg(cs, HW_RESET | INDICATION, NULL);
77 /* fallthru */
78 case (W_L1IND_CD):
79 l1_msg(cs, HW_DEACTIVATE | CONFIRM, NULL);
80 break;
81 case (W_L1IND_DRD):
82 l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL);
83 break;
84 case (W_L1IND_CE):
85 l1_msg(cs, HW_POWERUP | CONFIRM, NULL);
86 break;
87 case (W_L1IND_LD):
88 l1_msg(cs, HW_RSYNC | INDICATION, NULL);
89 break;
90 case (W_L1IND_ARD):
91 l1_msg(cs, HW_INFO2 | INDICATION, NULL);
92 break;
93 case (W_L1IND_AI8):
94 l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
95 break;
96 case (W_L1IND_AI10):
97 l1_msg(cs, HW_INFO4_P10 | INDICATION, NULL);
98 break;
99 default:
100 break;
101 }
102}
103
104static void
105W6692_bh(struct IsdnCardState *cs)
106{
107 struct PStack *stptr;
108
109 if (!cs)
110 return;
111 if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) {
112 if (cs->debug)
113 debugl1(cs, "D-Channel Busy cleared");
114 stptr = cs->stlist;
115 while (stptr != NULL) {
116 stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL);
117 stptr = stptr->next;
118 }
119 }
120 if (test_and_clear_bit(D_L1STATECHANGE, &cs->event))
121 W6692_new_ph(cs);
122 if (test_and_clear_bit(D_RCVBUFREADY, &cs->event))
123 DChannel_proc_rcv(cs);
124 if (test_and_clear_bit(D_XMTBUFREADY, &cs->event))
125 DChannel_proc_xmt(cs);
126/*
127 if (test_and_clear_bit(D_RX_MON1, &cs->event))
128 arcofi_fsm(cs, ARCOFI_RX_END, NULL);
129 if (test_and_clear_bit(D_TX_MON1, &cs->event))
130 arcofi_fsm(cs, ARCOFI_TX_END, NULL);
131 */
132}
133
134static void
135W6692_empty_fifo(struct IsdnCardState *cs, int count)
136{
137 u_char *ptr;
138
139 if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
140 debugl1(cs, "W6692_empty_fifo");
141
142 if ((cs->rcvidx + count) >= MAX_DFRAME_LEN_L1) {
143 if (cs->debug & L1_DEB_WARN)
144 debugl1(cs, "W6692_empty_fifo overrun %d",
145 cs->rcvidx + count);
146 cs->writeW6692(cs, W_D_CMDR, W_D_CMDR_RACK);
147 cs->rcvidx = 0;
148 return;
149 }
150 ptr = cs->rcvbuf + cs->rcvidx;
151 cs->rcvidx += count;
152 cs->readW6692fifo(cs, ptr, count);
153 cs->writeW6692(cs, W_D_CMDR, W_D_CMDR_RACK);
154 if (cs->debug & L1_DEB_ISAC_FIFO) {
155 char *t = cs->dlog;
156
157 t += sprintf(t, "W6692_empty_fifo cnt %d", count);
158 QuickHex(t, ptr, count);
159 debugl1(cs, cs->dlog);
160 }
161}
162
163static void
164W6692_fill_fifo(struct IsdnCardState *cs)
165{
166 int count, more;
167 u_char *ptr;
168
169 if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
170 debugl1(cs, "W6692_fill_fifo");
171
172 if (!cs->tx_skb)
173 return;
174
175 count = cs->tx_skb->len;
176 if (count <= 0)
177 return;
178
179 more = 0;
180 if (count > W_D_FIFO_THRESH) {
181 more = !0;
182 count = W_D_FIFO_THRESH;
183 }
184 ptr = cs->tx_skb->data;
185 skb_pull(cs->tx_skb, count);
186 cs->tx_cnt += count;
187 cs->writeW6692fifo(cs, ptr, count);
188 cs->writeW6692(cs, W_D_CMDR, more ? W_D_CMDR_XMS : (W_D_CMDR_XMS | W_D_CMDR_XME));
189 if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
190 debugl1(cs, "W6692_fill_fifo dbusytimer running");
191 del_timer(&cs->dbusytimer);
192 }
193 init_timer(&cs->dbusytimer);
194 cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ) / 1000);
195 add_timer(&cs->dbusytimer);
196 if (cs->debug & L1_DEB_ISAC_FIFO) {
197 char *t = cs->dlog;
198
199 t += sprintf(t, "W6692_fill_fifo cnt %d", count);
200 QuickHex(t, ptr, count);
201 debugl1(cs, cs->dlog);
202 }
203}
204
205static void
206W6692B_empty_fifo(struct BCState *bcs, int count)
207{
208 u_char *ptr;
209 struct IsdnCardState *cs = bcs->cs;
210
211 if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
212 debugl1(cs, "W6692B_empty_fifo");
213
214 if (bcs->hw.w6692.rcvidx + count > HSCX_BUFMAX) {
215 if (cs->debug & L1_DEB_WARN)
216 debugl1(cs, "W6692B_empty_fifo: incoming packet too large");
217 cs->BC_Write_Reg(cs, bcs->channel, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT);
218 bcs->hw.w6692.rcvidx = 0;
219 return;
220 }
221 ptr = bcs->hw.w6692.rcvbuf + bcs->hw.w6692.rcvidx;
222 bcs->hw.w6692.rcvidx += count;
223 READW6692BFIFO(cs, bcs->channel, ptr, count);
224 cs->BC_Write_Reg(cs, bcs->channel, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT);
225 if (cs->debug & L1_DEB_HSCX_FIFO) {
226 char *t = bcs->blog;
227
228 t += sprintf(t, "W6692B_empty_fifo %c cnt %d",
229 bcs->channel + '1', count);
230 QuickHex(t, ptr, count);
231 debugl1(cs, bcs->blog);
232 }
233}
234
235static void
236W6692B_fill_fifo(struct BCState *bcs)
237{
238 struct IsdnCardState *cs = bcs->cs;
239 int more, count;
240 u_char *ptr;
241
242 if (!bcs->tx_skb)
243 return;
244 if (bcs->tx_skb->len <= 0)
245 return;
246
247 more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0;
248 if (bcs->tx_skb->len > W_B_FIFO_THRESH) {
249 more = 1;
250 count = W_B_FIFO_THRESH;
251 } else
252 count = bcs->tx_skb->len;
253
254 if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
255 debugl1(cs, "W6692B_fill_fifo%s%d", (more ? " ": " last "), count);
256
257 ptr = bcs->tx_skb->data;
258 skb_pull(bcs->tx_skb, count);
259 bcs->tx_cnt -= count;
260 bcs->hw.w6692.count += count;
261 WRITEW6692BFIFO(cs, bcs->channel, ptr, count);
262 cs->BC_Write_Reg(cs, bcs->channel, W_B_CMDR, W_B_CMDR_RACT | W_B_CMDR_XMS | (more ? 0 : W_B_CMDR_XME));
263 if (cs->debug & L1_DEB_HSCX_FIFO) {
264 char *t = bcs->blog;
265
266 t += sprintf(t, "W6692B_fill_fifo %c cnt %d",
267 bcs->channel + '1', count);
268 QuickHex(t, ptr, count);
269 debugl1(cs, bcs->blog);
270 }
271}
272
273static void
274W6692B_interrupt(struct IsdnCardState *cs, u_char bchan)
275{
276 u_char val;
277 u_char r;
278 struct BCState *bcs;
279 struct sk_buff *skb;
280 int count;
281
282 bcs = (cs->bcs->channel == bchan) ? cs->bcs : (cs->bcs+1);
283 val = cs->BC_Read_Reg(cs, bchan, W_B_EXIR);
284 debugl1(cs, "W6692B chan %d B_EXIR 0x%02X", bchan, val);
285
286 if (!test_bit(BC_FLG_INIT, &bcs->Flag)) {
287 debugl1(cs, "W6692B not INIT yet");
288 return;
289 }
290 if (val & W_B_EXI_RME) { /* RME */
291 r = cs->BC_Read_Reg(cs, bchan, W_B_STAR);
292 if (r & (W_B_STAR_RDOV | W_B_STAR_CRCE | W_B_STAR_RMB)) {
293 if (cs->debug & L1_DEB_WARN)
294 debugl1(cs, "W6692 B STAR %x", r);
295 if ((r & W_B_STAR_RDOV) && bcs->mode)
296 if (cs->debug & L1_DEB_WARN)
297 debugl1(cs, "W6692 B RDOV mode=%d",
298 bcs->mode);
299 if (r & W_B_STAR_CRCE)
300 if (cs->debug & L1_DEB_WARN)
301 debugl1(cs, "W6692 B CRC error");
302 cs->BC_Write_Reg(cs, bchan, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RRST | W_B_CMDR_RACT);
303 } else {
304 count = cs->BC_Read_Reg(cs, bchan, W_B_RBCL) & (W_B_FIFO_THRESH - 1);
305 if (count == 0)
306 count = W_B_FIFO_THRESH;
307 W6692B_empty_fifo(bcs, count);
308 if ((count = bcs->hw.w6692.rcvidx) > 0) {
309 if (cs->debug & L1_DEB_HSCX_FIFO)
310 debugl1(cs, "W6692 Bchan Frame %d", count);
311 if (!(skb = dev_alloc_skb(count)))
312 printk(KERN_WARNING "W6692: Bchan receive out of memory\n");
313 else {
314 memcpy(skb_put(skb, count), bcs->hw.w6692.rcvbuf, count);
315 skb_queue_tail(&bcs->rqueue, skb);
316 }
317 }
318 }
319 bcs->hw.w6692.rcvidx = 0;
320 schedule_event(bcs, B_RCVBUFREADY);
321 }
322 if (val & W_B_EXI_RMR) { /* RMR */
323 W6692B_empty_fifo(bcs, W_B_FIFO_THRESH);
324 r = cs->BC_Read_Reg(cs, bchan, W_B_STAR);
325 if (r & W_B_STAR_RDOV) {
326 if (cs->debug & L1_DEB_WARN)
327 debugl1(cs, "W6692 B RDOV(RMR) mode=%d",bcs->mode);
328 cs->BC_Write_Reg(cs, bchan, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RRST | W_B_CMDR_RACT);
329 if (bcs->mode != L1_MODE_TRANS)
330 bcs->hw.w6692.rcvidx = 0;
331 }
332 if (bcs->mode == L1_MODE_TRANS) {
333 /* receive audio data */
334 if (!(skb = dev_alloc_skb(W_B_FIFO_THRESH)))
335 printk(KERN_WARNING "HiSax: receive out of memory\n");
336 else {
337 memcpy(skb_put(skb, W_B_FIFO_THRESH), bcs->hw.w6692.rcvbuf, W_B_FIFO_THRESH);
338 skb_queue_tail(&bcs->rqueue, skb);
339 }
340 bcs->hw.w6692.rcvidx = 0;
341 schedule_event(bcs, B_RCVBUFREADY);
342 }
343 }
344 if (val & W_B_EXI_XDUN) { /* XDUN */
345 cs->BC_Write_Reg(cs, bchan, W_B_CMDR, W_B_CMDR_XRST | W_B_CMDR_RACT);
346 if (cs->debug & L1_DEB_WARN)
347 debugl1(cs, "W6692 B EXIR %x Lost TX", val);
348 if (bcs->mode == 1)
349 W6692B_fill_fifo(bcs);
350 else {
351 /* Here we lost an TX interrupt, so
352 * restart transmitting the whole frame.
353 */
354 if (bcs->tx_skb) {
355 skb_push(bcs->tx_skb, bcs->hw.w6692.count);
356 bcs->tx_cnt += bcs->hw.w6692.count;
357 bcs->hw.w6692.count = 0;
358 }
359 }
360 return;
361 }
362 if (val & W_B_EXI_XFR) { /* XFR */
363 r = cs->BC_Read_Reg(cs, bchan, W_B_STAR);
364 if (r & W_B_STAR_XDOW) {
365 if (cs->debug & L1_DEB_WARN)
366 debugl1(cs, "W6692 B STAR %x XDOW", r);
367 cs->BC_Write_Reg(cs, bchan, W_B_CMDR, W_B_CMDR_XRST | W_B_CMDR_RACT);
368 if (bcs->tx_skb && (bcs->mode != 1)) {
369 skb_push(bcs->tx_skb, bcs->hw.w6692.count);
370 bcs->tx_cnt += bcs->hw.w6692.count;
371 bcs->hw.w6692.count = 0;
372 }
373 }
374 if (bcs->tx_skb) {
375 if (bcs->tx_skb->len) {
376 W6692B_fill_fifo(bcs);
377 return;
378 } else {
379 if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) &&
380 (PACKET_NOACK != bcs->tx_skb->pkt_type)) {
381 u_long flags;
382 spin_lock_irqsave(&bcs->aclock, flags);
383 bcs->ackcnt += bcs->hw.w6692.count;
384 spin_unlock_irqrestore(&bcs->aclock, flags);
385 schedule_event(bcs, B_ACKPENDING);
386 }
387 dev_kfree_skb_irq(bcs->tx_skb);
388 bcs->hw.w6692.count = 0;
389 bcs->tx_skb = NULL;
390 }
391 }
392 if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
393 bcs->hw.w6692.count = 0;
394 test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
395 W6692B_fill_fifo(bcs);
396 } else {
397 test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
398 schedule_event(bcs, B_XMTBUFREADY);
399 }
400 }
401}
402
403static irqreturn_t
404W6692_interrupt(int intno, void *dev_id, struct pt_regs *regs)
405{
406 struct IsdnCardState *cs = dev_id;
407 u_char val, exval, v1;
408 struct sk_buff *skb;
409 u_int count;
410 u_long flags;
411 int icnt = 5;
412
413 spin_lock_irqsave(&cs->lock, flags);
414 val = cs->readW6692(cs, W_ISTA);
415 if (!val) {
416 spin_unlock_irqrestore(&cs->lock, flags);
417 return IRQ_NONE;
418 }
419 StartW6692:
420 if (cs->debug & L1_DEB_ISAC)
421 debugl1(cs, "W6692 ISTA %x", val);
422
423 if (val & W_INT_D_RME) { /* RME */
424 exval = cs->readW6692(cs, W_D_RSTA);
425 if (exval & (W_D_RSTA_RDOV | W_D_RSTA_CRCE | W_D_RSTA_RMB)) {
426 if (exval & W_D_RSTA_RDOV)
427 if (cs->debug & L1_DEB_WARN)
428 debugl1(cs, "W6692 RDOV");
429 if (exval & W_D_RSTA_CRCE)
430 if (cs->debug & L1_DEB_WARN)
431 debugl1(cs, "W6692 D-channel CRC error");
432 if (exval & W_D_RSTA_RMB)
433 if (cs->debug & L1_DEB_WARN)
434 debugl1(cs, "W6692 D-channel ABORT");
435 cs->writeW6692(cs, W_D_CMDR, W_D_CMDR_RACK | W_D_CMDR_RRST);
436 } else {
437 count = cs->readW6692(cs, W_D_RBCL) & (W_D_FIFO_THRESH - 1);
438 if (count == 0)
439 count = W_D_FIFO_THRESH;
440 W6692_empty_fifo(cs, count);
441 if ((count = cs->rcvidx) > 0) {
442 cs->rcvidx = 0;
443 if (!(skb = alloc_skb(count, GFP_ATOMIC)))
444 printk(KERN_WARNING "HiSax: D receive out of memory\n");
445 else {
446 memcpy(skb_put(skb, count), cs->rcvbuf, count);
447 skb_queue_tail(&cs->rq, skb);
448 }
449 }
450 }
451 cs->rcvidx = 0;
452 schedule_event(cs, D_RCVBUFREADY);
453 }
454 if (val & W_INT_D_RMR) { /* RMR */
455 W6692_empty_fifo(cs, W_D_FIFO_THRESH);
456 }
457 if (val & W_INT_D_XFR) { /* XFR */
458 if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
459 del_timer(&cs->dbusytimer);
460 if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
461 schedule_event(cs, D_CLEARBUSY);
462 if (cs->tx_skb) {
463 if (cs->tx_skb->len) {
464 W6692_fill_fifo(cs);
465 goto afterXFR;
466 } else {
467 dev_kfree_skb_irq(cs->tx_skb);
468 cs->tx_cnt = 0;
469 cs->tx_skb = NULL;
470 }
471 }
472 if ((cs->tx_skb = skb_dequeue(&cs->sq))) {
473 cs->tx_cnt = 0;
474 W6692_fill_fifo(cs);
475 } else
476 schedule_event(cs, D_XMTBUFREADY);
477 }
478 afterXFR:
479 if (val & (W_INT_XINT0 | W_INT_XINT1)) { /* XINT0/1 - never */
480 if (cs->debug & L1_DEB_ISAC)
481 debugl1(cs, "W6692 spurious XINT!");
482 }
483 if (val & W_INT_D_EXI) { /* EXI */
484 exval = cs->readW6692(cs, W_D_EXIR);
485 if (cs->debug & L1_DEB_WARN)
486 debugl1(cs, "W6692 D_EXIR %02x", exval);
487 if (exval & (W_D_EXI_XDUN | W_D_EXI_XCOL)) { /* Transmit underrun/collision */
488 debugl1(cs, "W6692 D-chan underrun/collision");
489 printk(KERN_WARNING "HiSax: W6692 XDUN/XCOL\n");
490 if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
491 del_timer(&cs->dbusytimer);
492 if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
493 schedule_event(cs, D_CLEARBUSY);
494 if (cs->tx_skb) { /* Restart frame */
495 skb_push(cs->tx_skb, cs->tx_cnt);
496 cs->tx_cnt = 0;
497 W6692_fill_fifo(cs);
498 } else {
499 printk(KERN_WARNING "HiSax: W6692 XDUN/XCOL no skb\n");
500 debugl1(cs, "W6692 XDUN/XCOL no skb");
501 cs->writeW6692(cs, W_D_CMDR, W_D_CMDR_XRST);
502 }
503 }
504 if (exval & W_D_EXI_RDOV) { /* RDOV */
505 debugl1(cs, "W6692 D-channel RDOV");
506 printk(KERN_WARNING "HiSax: W6692 D-RDOV\n");
507 cs->writeW6692(cs, W_D_CMDR, W_D_CMDR_RRST);
508 }
509 if (exval & W_D_EXI_TIN2) { /* TIN2 - never */
510 debugl1(cs, "W6692 spurious TIN2 interrupt");
511 }
512 if (exval & W_D_EXI_MOC) { /* MOC - not supported */
513 debugl1(cs, "W6692 spurious MOC interrupt");
514 v1 = cs->readW6692(cs, W_MOSR);
515 debugl1(cs, "W6692 MOSR %02x", v1);
516 }
517 if (exval & W_D_EXI_ISC) { /* ISC - Level1 change */
518 v1 = cs->readW6692(cs, W_CIR);
519 if (cs->debug & L1_DEB_ISAC)
520 debugl1(cs, "W6692 ISC CIR=0x%02X", v1);
521 if (v1 & W_CIR_ICC) {
522 cs->dc.w6692.ph_state = v1 & W_CIR_COD_MASK;
523 if (cs->debug & L1_DEB_ISAC)
524 debugl1(cs, "ph_state_change %x", cs->dc.w6692.ph_state);
525 schedule_event(cs, D_L1STATECHANGE);
526 }
527 if (v1 & W_CIR_SCC) {
528 v1 = cs->readW6692(cs, W_SQR);
529 debugl1(cs, "W6692 SCC SQR=0x%02X", v1);
530 }
531 }
532 if (exval & W_D_EXI_WEXP) {
533 debugl1(cs, "W6692 spurious WEXP interrupt!");
534 }
535 if (exval & W_D_EXI_TEXP) {
536 debugl1(cs, "W6692 spurious TEXP interrupt!");
537 }
538 }
539 if (val & W_INT_B1_EXI) {
540 debugl1(cs, "W6692 B channel 1 interrupt");
541 W6692B_interrupt(cs, 0);
542 }
543 if (val & W_INT_B2_EXI) {
544 debugl1(cs, "W6692 B channel 2 interrupt");
545 W6692B_interrupt(cs, 1);
546 }
547 val = cs->readW6692(cs, W_ISTA);
548 if (val && icnt) {
549 icnt--;
550 goto StartW6692;
551 }
552 if (!icnt) {
553 printk(KERN_WARNING "W6692 IRQ LOOP\n");
554 cs->writeW6692(cs, W_IMASK, 0xff);
555 }
556 spin_unlock_irqrestore(&cs->lock, flags);
557 return IRQ_HANDLED;
558}
559
560static void
561W6692_l1hw(struct PStack *st, int pr, void *arg)
562{
563 struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
564 struct sk_buff *skb = arg;
565 u_long flags;
566 int val;
567
568 switch (pr) {
569 case (PH_DATA | REQUEST):
570 if (cs->debug & DEB_DLOG_HEX)
571 LogFrame(cs, skb->data, skb->len);
572 if (cs->debug & DEB_DLOG_VERBOSE)
573 dlogframe(cs, skb, 0);
574 spin_lock_irqsave(&cs->lock, flags);
575 if (cs->tx_skb) {
576 skb_queue_tail(&cs->sq, skb);
577#ifdef L2FRAME_DEBUG /* psa */
578 if (cs->debug & L1_DEB_LAPD)
579 Logl2Frame(cs, skb, "PH_DATA Queued", 0);
580#endif
581 } else {
582 cs->tx_skb = skb;
583 cs->tx_cnt = 0;
584#ifdef L2FRAME_DEBUG /* psa */
585 if (cs->debug & L1_DEB_LAPD)
586 Logl2Frame(cs, skb, "PH_DATA", 0);
587#endif
588 W6692_fill_fifo(cs);
589 }
590 spin_unlock_irqrestore(&cs->lock, flags);
591 break;
592 case (PH_PULL | INDICATION):
593 spin_lock_irqsave(&cs->lock, flags);
594 if (cs->tx_skb) {
595 if (cs->debug & L1_DEB_WARN)
596 debugl1(cs, " l2l1 tx_skb exist this shouldn't happen");
597 skb_queue_tail(&cs->sq, skb);
598 spin_unlock_irqrestore(&cs->lock, flags);
599 break;
600 }
601 if (cs->debug & DEB_DLOG_HEX)
602 LogFrame(cs, skb->data, skb->len);
603 if (cs->debug & DEB_DLOG_VERBOSE)
604 dlogframe(cs, skb, 0);
605 cs->tx_skb = skb;
606 cs->tx_cnt = 0;
607#ifdef L2FRAME_DEBUG /* psa */
608 if (cs->debug & L1_DEB_LAPD)
609 Logl2Frame(cs, skb, "PH_DATA_PULLED", 0);
610#endif
611 W6692_fill_fifo(cs);
612 spin_unlock_irqrestore(&cs->lock, flags);
613 break;
614 case (PH_PULL | REQUEST):
615#ifdef L2FRAME_DEBUG /* psa */
616 if (cs->debug & L1_DEB_LAPD)
617 debugl1(cs, "-> PH_REQUEST_PULL");
618#endif
619 if (!cs->tx_skb) {
620 test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
621 st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
622 } else
623 test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
624 break;
625 case (HW_RESET | REQUEST):
626 spin_lock_irqsave(&cs->lock, flags);
627 if ((cs->dc.w6692.ph_state == W_L1IND_DRD)) {
628 ph_command(cs, W_L1CMD_ECK);
629 spin_unlock_irqrestore(&cs->lock, flags);
630 } else {
631 ph_command(cs, W_L1CMD_RST);
632 cs->dc.w6692.ph_state = W_L1CMD_RST;
633 spin_unlock_irqrestore(&cs->lock, flags);
634 W6692_new_ph(cs);
635 }
636 break;
637 case (HW_ENABLE | REQUEST):
638 spin_lock_irqsave(&cs->lock, flags);
639 ph_command(cs, W_L1CMD_ECK);
640 spin_unlock_irqrestore(&cs->lock, flags);
641 break;
642 case (HW_INFO3 | REQUEST):
643 spin_lock_irqsave(&cs->lock, flags);
644 ph_command(cs, W_L1CMD_AR8);
645 spin_unlock_irqrestore(&cs->lock, flags);
646 break;
647 case (HW_TESTLOOP | REQUEST):
648 val = 0;
649 if (1 & (long) arg)
650 val |= 0x0c;
651 if (2 & (long) arg)
652 val |= 0x3;
653 /* !!! not implemented yet */
654 break;
655 case (HW_DEACTIVATE | RESPONSE):
656 skb_queue_purge(&cs->rq);
657 skb_queue_purge(&cs->sq);
658 if (cs->tx_skb) {
659 dev_kfree_skb_any(cs->tx_skb);
660 cs->tx_skb = NULL;
661 }
662 if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
663 del_timer(&cs->dbusytimer);
664 if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
665 schedule_event(cs, D_CLEARBUSY);
666 break;
667 default:
668 if (cs->debug & L1_DEB_WARN)
669 debugl1(cs, "W6692_l1hw unknown %04x", pr);
670 break;
671 }
672}
673
674static void
675setstack_W6692(struct PStack *st, struct IsdnCardState *cs)
676{
677 st->l1.l1hw = W6692_l1hw;
678}
679
680static void
681DC_Close_W6692(struct IsdnCardState *cs)
682{
683}
684
685static void
686dbusy_timer_handler(struct IsdnCardState *cs)
687{
688 struct PStack *stptr;
689 int rbch, star;
690 u_long flags;
691
692 spin_lock_irqsave(&cs->lock, flags);
693 if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
694 rbch = cs->readW6692(cs, W_D_RBCH);
695 star = cs->readW6692(cs, W_D_STAR);
696 if (cs->debug)
697 debugl1(cs, "D-Channel Busy D_RBCH %02x D_STAR %02x",
698 rbch, star);
699 if (star & W_D_STAR_XBZ) { /* D-Channel Busy */
700 test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags);
701 stptr = cs->stlist;
702 while (stptr != NULL) {
703 stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL);
704 stptr = stptr->next;
705 }
706 } else {
707 /* discard frame; reset transceiver */
708 test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags);
709 if (cs->tx_skb) {
710 dev_kfree_skb_any(cs->tx_skb);
711 cs->tx_cnt = 0;
712 cs->tx_skb = NULL;
713 } else {
714 printk(KERN_WARNING "HiSax: W6692 D-Channel Busy no skb\n");
715 debugl1(cs, "D-Channel Busy no skb");
716 }
717 cs->writeW6692(cs, W_D_CMDR, W_D_CMDR_XRST); /* Transmitter reset */
718 spin_unlock_irqrestore(&cs->lock, flags);
719 cs->irq_func(cs->irq, cs, NULL);
720 return;
721 }
722 }
723 spin_unlock_irqrestore(&cs->lock, flags);
724}
725
726static void
727W6692Bmode(struct BCState *bcs, int mode, int bchan)
728{
729 struct IsdnCardState *cs = bcs->cs;
730
731 if (cs->debug & L1_DEB_HSCX)
732 debugl1(cs, "w6692 %c mode %d ichan %d",
733 '1' + bchan, mode, bchan);
734 bcs->mode = mode;
735 bcs->channel = bchan;
736 bcs->hw.w6692.bchan = bchan;
737
738 switch (mode) {
739 case (L1_MODE_NULL):
740 cs->BC_Write_Reg(cs, bchan, W_B_MODE, 0);
741 break;
742 case (L1_MODE_TRANS):
743 cs->BC_Write_Reg(cs, bchan, W_B_MODE, W_B_MODE_MMS);
744 break;
745 case (L1_MODE_HDLC):
746 cs->BC_Write_Reg(cs, bchan, W_B_MODE, W_B_MODE_ITF);
747 cs->BC_Write_Reg(cs, bchan, W_B_ADM1, 0xff);
748 cs->BC_Write_Reg(cs, bchan, W_B_ADM2, 0xff);
749 break;
750 }
751 if (mode)
752 cs->BC_Write_Reg(cs, bchan, W_B_CMDR, W_B_CMDR_RRST |
753 W_B_CMDR_RACT | W_B_CMDR_XRST);
754 cs->BC_Write_Reg(cs, bchan, W_B_EXIM, 0x00);
755}
756
757static void
758W6692_l2l1(struct PStack *st, int pr, void *arg)
759{
760 struct sk_buff *skb = arg;
761 struct BCState *bcs = st->l1.bcs;
762 u_long flags;
763
764 switch (pr) {
765 case (PH_DATA | REQUEST):
766 spin_lock_irqsave(&bcs->cs->lock, flags);
767 if (bcs->tx_skb) {
768 skb_queue_tail(&bcs->squeue, skb);
769 } else {
770 bcs->tx_skb = skb;
771 test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
772 bcs->hw.w6692.count = 0;
773 bcs->cs->BC_Send_Data(bcs);
774 }
775 spin_unlock_irqrestore(&bcs->cs->lock, flags);
776 break;
777 case (PH_PULL | INDICATION):
778 if (bcs->tx_skb) {
779 printk(KERN_WARNING "W6692_l2l1: this shouldn't happen\n");
780 break;
781 }
782 spin_lock_irqsave(&bcs->cs->lock, flags);
783 test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
784 bcs->tx_skb = skb;
785 bcs->hw.w6692.count = 0;
786 bcs->cs->BC_Send_Data(bcs);
787 spin_unlock_irqrestore(&bcs->cs->lock, flags);
788 break;
789 case (PH_PULL | REQUEST):
790 if (!bcs->tx_skb) {
791 test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
792 st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
793 } else
794 test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
795 break;
796 case (PH_ACTIVATE | REQUEST):
797 spin_lock_irqsave(&bcs->cs->lock, flags);
798 test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag);
799 W6692Bmode(bcs, st->l1.mode, st->l1.bc);
800 spin_unlock_irqrestore(&bcs->cs->lock, flags);
801 l1_msg_b(st, pr, arg);
802 break;
803 case (PH_DEACTIVATE | REQUEST):
804 l1_msg_b(st, pr, arg);
805 break;
806 case (PH_DEACTIVATE | CONFIRM):
807 spin_lock_irqsave(&bcs->cs->lock, flags);
808 test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag);
809 test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
810 W6692Bmode(bcs, 0, st->l1.bc);
811 spin_unlock_irqrestore(&bcs->cs->lock, flags);
812 st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
813 break;
814 }
815}
816
817static void
818close_w6692state(struct BCState *bcs)
819{
820 W6692Bmode(bcs, 0, bcs->channel);
821 if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) {
822 if (bcs->hw.w6692.rcvbuf) {
823 kfree(bcs->hw.w6692.rcvbuf);
824 bcs->hw.w6692.rcvbuf = NULL;
825 }
826 if (bcs->blog) {
827 kfree(bcs->blog);
828 bcs->blog = NULL;
829 }
830 skb_queue_purge(&bcs->rqueue);
831 skb_queue_purge(&bcs->squeue);
832 if (bcs->tx_skb) {
833 dev_kfree_skb_any(bcs->tx_skb);
834 bcs->tx_skb = NULL;
835 test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
836 }
837 }
838}
839
840static int
841open_w6692state(struct IsdnCardState *cs, struct BCState *bcs)
842{
843 if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
844 if (!(bcs->hw.w6692.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) {
845 printk(KERN_WARNING
846 "HiSax: No memory for w6692.rcvbuf\n");
847 test_and_clear_bit(BC_FLG_INIT, &bcs->Flag);
848 return (1);
849 }
850 if (!(bcs->blog = kmalloc(MAX_BLOG_SPACE, GFP_ATOMIC))) {
851 printk(KERN_WARNING
852 "HiSax: No memory for bcs->blog\n");
853 test_and_clear_bit(BC_FLG_INIT, &bcs->Flag);
854 kfree(bcs->hw.w6692.rcvbuf);
855 bcs->hw.w6692.rcvbuf = NULL;
856 return (2);
857 }
858 skb_queue_head_init(&bcs->rqueue);
859 skb_queue_head_init(&bcs->squeue);
860 }
861 bcs->tx_skb = NULL;
862 test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
863 bcs->event = 0;
864 bcs->hw.w6692.rcvidx = 0;
865 bcs->tx_cnt = 0;
866 return (0);
867}
868
869static int
870setstack_w6692(struct PStack *st, struct BCState *bcs)
871{
872 bcs->channel = st->l1.bc;
873 if (open_w6692state(st->l1.hardware, bcs))
874 return (-1);
875 st->l1.bcs = bcs;
876 st->l2.l2l1 = W6692_l2l1;
877 setstack_manager(st);
878 bcs->st = st;
879 setstack_l1_B(st);
880 return (0);
881}
882
883void resetW6692(struct IsdnCardState *cs)
884{
885 cs->writeW6692(cs, W_D_CTL, W_D_CTL_SRST);
886 mdelay(10);
887 cs->writeW6692(cs, W_D_CTL, 0x00);
888 mdelay(10);
889 cs->writeW6692(cs, W_IMASK, 0xff);
890 cs->writeW6692(cs, W_D_SAM, 0xff);
891 cs->writeW6692(cs, W_D_TAM, 0xff);
892 cs->writeW6692(cs, W_D_EXIM, 0x00);
893 cs->writeW6692(cs, W_D_MODE, W_D_MODE_RACT);
894 cs->writeW6692(cs, W_IMASK, 0x18);
895 if (cs->subtyp == W6692_USR) {
896 /* seems that USR implemented some power control features
897 * Pin 79 is connected to the oscilator circuit so we
898 * have to handle it here
899 */
900 cs->writeW6692(cs, W_PCTL, 0x80);
901 cs->writeW6692(cs, W_XDATA, 0x00);
902 }
903}
904
905void __init initW6692(struct IsdnCardState *cs, int part)
906{
907 if (part & 1) {
908 cs->setstack_d = setstack_W6692;
909 cs->DC_Close = DC_Close_W6692;
910 cs->dbusytimer.function = (void *) dbusy_timer_handler;
911 cs->dbusytimer.data = (long) cs;
912 init_timer(&cs->dbusytimer);
913 resetW6692(cs);
914 ph_command(cs, W_L1CMD_RST);
915 cs->dc.w6692.ph_state = W_L1CMD_RST;
916 W6692_new_ph(cs);
917 ph_command(cs, W_L1CMD_ECK);
918
919 cs->bcs[0].BC_SetStack = setstack_w6692;
920 cs->bcs[1].BC_SetStack = setstack_w6692;
921 cs->bcs[0].BC_Close = close_w6692state;
922 cs->bcs[1].BC_Close = close_w6692state;
923 W6692Bmode(cs->bcs, 0, 0);
924 W6692Bmode(cs->bcs + 1, 0, 0);
925 }
926 if (part & 2) {
927 /* Reenable all IRQ */
928 cs->writeW6692(cs, W_IMASK, 0x18);
929 cs->writeW6692(cs, W_D_EXIM, 0x00);
930 cs->BC_Write_Reg(cs, 0, W_B_EXIM, 0x00);
931 cs->BC_Write_Reg(cs, 1, W_B_EXIM, 0x00);
932 /* Reset D-chan receiver and transmitter */
933 cs->writeW6692(cs, W_D_CMDR, W_D_CMDR_RRST | W_D_CMDR_XRST);
934 }
935}
936
937/* Interface functions */
938
939static u_char
940ReadW6692(struct IsdnCardState *cs, u_char offset)
941{
942 return (inb(cs->hw.w6692.iobase + offset));
943}
944
945static void
946WriteW6692(struct IsdnCardState *cs, u_char offset, u_char value)
947{
948 outb(value, cs->hw.w6692.iobase + offset);
949}
950
951static void
952ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
953{
954 insb(cs->hw.w6692.iobase + W_D_RFIFO, data, size);
955}
956
957static void
958WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
959{
960 outsb(cs->hw.w6692.iobase + W_D_XFIFO, data, size);
961}
962
963static u_char
964ReadW6692B(struct IsdnCardState *cs, int bchan, u_char offset)
965{
966 return (inb(cs->hw.w6692.iobase + (bchan ? 0x40 : 0) + offset));
967}
968
969static void
970WriteW6692B(struct IsdnCardState *cs, int bchan, u_char offset, u_char value)
971{
972 outb(value, cs->hw.w6692.iobase + (bchan ? 0x40 : 0) + offset);
973}
974
975static int
976w6692_card_msg(struct IsdnCardState *cs, int mt, void *arg)
977{
978 switch (mt) {
979 case CARD_RESET:
980 resetW6692(cs);
981 return (0);
982 case CARD_RELEASE:
983 cs->writeW6692(cs, W_IMASK, 0xff);
984 release_region(cs->hw.w6692.iobase, 256);
985 if (cs->subtyp == W6692_USR) {
986 cs->writeW6692(cs, W_XDATA, 0x04);
987 }
988 return (0);
989 case CARD_INIT:
990 initW6692(cs, 3);
991 return (0);
992 case CARD_TEST:
993 return (0);
994 }
995 return (0);
996}
997
998static int id_idx ;
999
1000static struct pci_dev *dev_w6692 __initdata = NULL;
1001
1002int __init
1003setup_w6692(struct IsdnCard *card)
1004{
1005 struct IsdnCardState *cs = card->cs;
1006 char tmp[64];
1007 u_char found = 0;
1008 u_char pci_irq = 0;
1009 u_int pci_ioaddr = 0;
1010
1011 strcpy(tmp, w6692_revision);
1012 printk(KERN_INFO "HiSax: W6692 driver Rev. %s\n", HiSax_getrev(tmp));
1013 if (cs->typ != ISDN_CTYPE_W6692)
1014 return (0);
1015#ifdef CONFIG_PCI
1016 while (id_list[id_idx].vendor_id) {
1017 dev_w6692 = pci_find_device(id_list[id_idx].vendor_id,
1018 id_list[id_idx].device_id,
1019 dev_w6692);
1020 if (dev_w6692) {
1021 if (pci_enable_device(dev_w6692))
1022 continue;
1023 cs->subtyp = id_idx;
1024 break;
1025 }
1026 id_idx++;
1027 }
1028 if (dev_w6692) {
1029 found = 1;
1030 pci_irq = dev_w6692->irq;
1031 /* I think address 0 is allways the configuration area */
1032 /* and address 1 is the real IO space KKe 03.09.99 */
1033 pci_ioaddr = pci_resource_start(dev_w6692, 1);
1034 /* USR ISDN PCI card TA need some special handling */
1035 if (cs->subtyp == W6692_WINBOND) {
1036 if ((W6692_SV_USR == dev_w6692->subsystem_vendor) &&
1037 (W6692_SD_USR == dev_w6692->subsystem_device)) {
1038 cs->subtyp = W6692_USR;
1039 }
1040 }
1041 }
1042 if (!found) {
1043 printk(KERN_WARNING "W6692: No PCI card found\n");
1044 return (0);
1045 }
1046 cs->irq = pci_irq;
1047 if (!cs->irq) {
1048 printk(KERN_WARNING "W6692: No IRQ for PCI card found\n");
1049 return (0);
1050 }
1051 if (!pci_ioaddr) {
1052 printk(KERN_WARNING "W6692: NO I/O Base Address found\n");
1053 return (0);
1054 }
1055 cs->hw.w6692.iobase = pci_ioaddr;
1056 printk(KERN_INFO "Found: %s %s, I/O base: 0x%x, irq: %d\n",
1057 id_list[cs->subtyp].vendor_name, id_list[cs->subtyp].card_name,
1058 pci_ioaddr, pci_irq);
1059 if (!request_region(cs->hw.w6692.iobase, 256, id_list[cs->subtyp].card_name)) {
1060 printk(KERN_WARNING
1061 "HiSax: %s I/O ports %x-%x already in use\n",
1062 id_list[cs->subtyp].card_name,
1063 cs->hw.w6692.iobase,
1064 cs->hw.w6692.iobase + 255);
1065 return (0);
1066 }
1067#else
1068 printk(KERN_WARNING "HiSax: W6692 and NO_PCI_BIOS\n");
1069 printk(KERN_WARNING "HiSax: W6692 unable to config\n");
1070 return (0);
1071#endif /* CONFIG_PCI */
1072
1073 printk(KERN_INFO
1074 "HiSax: %s config irq:%d I/O:%x\n",
1075 id_list[cs->subtyp].card_name, cs->irq,
1076 cs->hw.w6692.iobase);
1077
1078 INIT_WORK(&cs->tqueue, (void *)(void *) W6692_bh, cs);
1079 cs->readW6692 = &ReadW6692;
1080 cs->writeW6692 = &WriteW6692;
1081 cs->readisacfifo = &ReadISACfifo;
1082 cs->writeisacfifo = &WriteISACfifo;
1083 cs->BC_Read_Reg = &ReadW6692B;
1084 cs->BC_Write_Reg = &WriteW6692B;
1085 cs->BC_Send_Data = &W6692B_fill_fifo;
1086 cs->cardmsg = &w6692_card_msg;
1087 cs->irq_func = &W6692_interrupt;
1088 cs->irq_flags |= SA_SHIRQ;
1089 W6692Version(cs, "W6692:");
1090 printk(KERN_INFO "W6692 ISTA=0x%X\n", ReadW6692(cs, W_ISTA));
1091 printk(KERN_INFO "W6692 IMASK=0x%X\n", ReadW6692(cs, W_IMASK));
1092 printk(KERN_INFO "W6692 D_EXIR=0x%X\n", ReadW6692(cs, W_D_EXIR));
1093 printk(KERN_INFO "W6692 D_EXIM=0x%X\n", ReadW6692(cs, W_D_EXIM));
1094 printk(KERN_INFO "W6692 D_RSTA=0x%X\n", ReadW6692(cs, W_D_RSTA));
1095 return (1);
1096}
diff --git a/drivers/isdn/hisax/w6692.h b/drivers/isdn/hisax/w6692.h
new file mode 100644
index 000000000000..c79c81e0401f
--- /dev/null
+++ b/drivers/isdn/hisax/w6692.h
@@ -0,0 +1,184 @@
1/* $Id: w6692.h,v 1.4.2.2 2004/01/12 22:52:29 keil Exp $
2 *
3 * Winbond W6692 specific defines
4 *
5 * Author Petr Novak
6 * Copyright by Petr Novak <petr.novak@i.cz>
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 */
12
13/* map W6692 functions to ISAC functions */
14#define readW6692 readisac
15#define writeW6692 writeisac
16#define readW6692fifo readisacfifo
17#define writeW6692fifo writeisacfifo
18
19/* B-channel FIFO read/write routines */
20
21#define READW6692BFIFO(cs,bchan,ptr,count) \
22 insb(cs->hw.w6692.iobase+W_B_RFIFO+(bchan?0x40:0),ptr,count)
23
24#define WRITEW6692BFIFO(cs,bchan,ptr,count) \
25 outsb(cs->hw.w6692.iobase+W_B_XFIFO+(bchan?0x40:0),ptr,count)
26
27/* Specifications of W6692 registers */
28
29#define W_D_RFIFO 0x00 /* R */
30#define W_D_XFIFO 0x04 /* W */
31#define W_D_CMDR 0x08 /* W */
32#define W_D_MODE 0x0c /* R/W */
33#define W_D_TIMR 0x10 /* R/W */
34#define W_ISTA 0x14 /* R_clr */
35#define W_IMASK 0x18 /* R/W */
36#define W_D_EXIR 0x1c /* R_clr */
37#define W_D_EXIM 0x20 /* R/W */
38#define W_D_STAR 0x24 /* R */
39#define W_D_RSTA 0x28 /* R */
40#define W_D_SAM 0x2c /* R/W */
41#define W_D_SAP1 0x30 /* R/W */
42#define W_D_SAP2 0x34 /* R/W */
43#define W_D_TAM 0x38 /* R/W */
44#define W_D_TEI1 0x3c /* R/W */
45#define W_D_TEI2 0x40 /* R/W */
46#define W_D_RBCH 0x44 /* R */
47#define W_D_RBCL 0x48 /* R */
48#define W_TIMR2 0x4c /* W */
49#define W_L1_RC 0x50 /* R/W */
50#define W_D_CTL 0x54 /* R/W */
51#define W_CIR 0x58 /* R */
52#define W_CIX 0x5c /* W */
53#define W_SQR 0x60 /* R */
54#define W_SQX 0x64 /* W */
55#define W_PCTL 0x68 /* R/W */
56#define W_MOR 0x6c /* R */
57#define W_MOX 0x70 /* R/W */
58#define W_MOSR 0x74 /* R_clr */
59#define W_MOCR 0x78 /* R/W */
60#define W_GCR 0x7c /* R/W */
61
62#define W_B_RFIFO 0x80 /* R */
63#define W_B_XFIFO 0x84 /* W */
64#define W_B_CMDR 0x88 /* W */
65#define W_B_MODE 0x8c /* R/W */
66#define W_B_EXIR 0x90 /* R_clr */
67#define W_B_EXIM 0x94 /* R/W */
68#define W_B_STAR 0x98 /* R */
69#define W_B_ADM1 0x9c /* R/W */
70#define W_B_ADM2 0xa0 /* R/W */
71#define W_B_ADR1 0xa4 /* R/W */
72#define W_B_ADR2 0xa8 /* R/W */
73#define W_B_RBCL 0xac /* R */
74#define W_B_RBCH 0xb0 /* R */
75
76#define W_XADDR 0xf4 /* R/W */
77#define W_XDATA 0xf8 /* R/W */
78#define W_EPCTL 0xfc /* W */
79
80/* W6692 register bits */
81
82#define W_D_CMDR_XRST 0x01
83#define W_D_CMDR_XME 0x02
84#define W_D_CMDR_XMS 0x08
85#define W_D_CMDR_STT 0x10
86#define W_D_CMDR_RRST 0x40
87#define W_D_CMDR_RACK 0x80
88
89#define W_D_MODE_RLP 0x01
90#define W_D_MODE_DLP 0x02
91#define W_D_MODE_MFD 0x04
92#define W_D_MODE_TEE 0x08
93#define W_D_MODE_TMS 0x10
94#define W_D_MODE_RACT 0x40
95#define W_D_MODE_MMS 0x80
96
97#define W_INT_B2_EXI 0x01
98#define W_INT_B1_EXI 0x02
99#define W_INT_D_EXI 0x04
100#define W_INT_XINT0 0x08
101#define W_INT_XINT1 0x10
102#define W_INT_D_XFR 0x20
103#define W_INT_D_RME 0x40
104#define W_INT_D_RMR 0x80
105
106#define W_D_EXI_WEXP 0x01
107#define W_D_EXI_TEXP 0x02
108#define W_D_EXI_ISC 0x04
109#define W_D_EXI_MOC 0x08
110#define W_D_EXI_TIN2 0x10
111#define W_D_EXI_XCOL 0x20
112#define W_D_EXI_XDUN 0x40
113#define W_D_EXI_RDOV 0x80
114
115#define W_D_STAR_DRDY 0x10
116#define W_D_STAR_XBZ 0x20
117#define W_D_STAR_XDOW 0x80
118
119#define W_D_RSTA_RMB 0x10
120#define W_D_RSTA_CRCE 0x20
121#define W_D_RSTA_RDOV 0x40
122
123#define W_D_CTL_SRST 0x20
124
125#define W_CIR_SCC 0x80
126#define W_CIR_ICC 0x40
127#define W_CIR_COD_MASK 0x0f
128
129#define W_B_CMDR_XRST 0x01
130#define W_B_CMDR_XME 0x02
131#define W_B_CMDR_XMS 0x04
132#define W_B_CMDR_RACT 0x20
133#define W_B_CMDR_RRST 0x40
134#define W_B_CMDR_RACK 0x80
135
136#define W_B_MODE_FTS0 0x01
137#define W_B_MODE_FTS1 0x02
138#define W_B_MODE_SW56 0x04
139#define W_B_MODE_BSW0 0x08
140#define W_B_MODE_BSW1 0x10
141#define W_B_MODE_EPCM 0x20
142#define W_B_MODE_ITF 0x40
143#define W_B_MODE_MMS 0x80
144
145#define W_B_EXI_XDUN 0x01
146#define W_B_EXI_XFR 0x02
147#define W_B_EXI_RDOV 0x10
148#define W_B_EXI_RME 0x20
149#define W_B_EXI_RMR 0x40
150
151#define W_B_STAR_XBZ 0x01
152#define W_B_STAR_XDOW 0x04
153#define W_B_STAR_RMB 0x10
154#define W_B_STAR_CRCE 0x20
155#define W_B_STAR_RDOV 0x40
156
157#define W_B_RBCH_LOV 0x20
158
159/* W6692 Layer1 commands */
160
161#define W_L1CMD_ECK 0x00
162#define W_L1CMD_RST 0x01
163#define W_L1CMD_SCP 0x04
164#define W_L1CMD_SSP 0x02
165#define W_L1CMD_AR8 0x08
166#define W_L1CMD_AR10 0x09
167#define W_L1CMD_EAL 0x0a
168#define W_L1CMD_DRC 0x0f
169
170/* W6692 Layer1 indications */
171
172#define W_L1IND_CE 0x07
173#define W_L1IND_DRD 0x00
174#define W_L1IND_LD 0x04
175#define W_L1IND_ARD 0x08
176#define W_L1IND_TI 0x0a
177#define W_L1IND_ATI 0x0b
178#define W_L1IND_AI8 0x0c
179#define W_L1IND_AI10 0x0d
180#define W_L1IND_CD 0x0f
181
182/* FIFO thresholds */
183#define W_D_FIFO_THRESH 64
184#define W_B_FIFO_THRESH 64
diff --git a/drivers/isdn/hysdn/Kconfig b/drivers/isdn/hysdn/Kconfig
new file mode 100644
index 000000000000..c6d8a7042988
--- /dev/null
+++ b/drivers/isdn/hysdn/Kconfig
@@ -0,0 +1,18 @@
1#
2# Config.in for HYSDN ISDN driver
3#
4config HYSDN
5 tristate "Hypercope HYSDN cards (Champ, Ergo, Metro) support (module only)"
6 depends on m && PROC_FS && PCI && BROKEN_ON_SMP
7 help
8 Say Y here if you have one of Hypercope's active PCI ISDN cards
9 Champ, Ergo and Metro. You will then get a module called hysdn.
10 Please read the file <file:Documentation/isdn/README.hysdn> for more
11 information.
12
13config HYSDN_CAPI
14 bool "HYSDN CAPI 2.0 support"
15 depends on HYSDN && ISDN_CAPI
16 help
17 Say Y here if you like to use Hypercope's CAPI 2.0 interface.
18
diff --git a/drivers/isdn/hysdn/Makefile b/drivers/isdn/hysdn/Makefile
new file mode 100644
index 000000000000..da63b636267d
--- /dev/null
+++ b/drivers/isdn/hysdn/Makefile
@@ -0,0 +1,11 @@
1# Makefile for the hysdn ISDN device driver
2
3# Each configuration option enables a list of files.
4
5obj-$(CONFIG_HYSDN) += hysdn.o
6
7# Multipart objects.
8
9hysdn-y := hysdn_procconf.o hysdn_proclog.o boardergo.o \
10 hysdn_boot.o hysdn_sched.o hysdn_net.o hysdn_init.o
11hysdn-$(CONFIG_HYSDN_CAPI) += hycapi.o
diff --git a/drivers/isdn/hysdn/boardergo.c b/drivers/isdn/hysdn/boardergo.c
new file mode 100644
index 000000000000..e19a01a305a9
--- /dev/null
+++ b/drivers/isdn/hysdn/boardergo.c
@@ -0,0 +1,453 @@
1/* $Id: boardergo.c,v 1.5.6.7 2001/11/06 21:58:19 kai Exp $
2 *
3 * Linux driver for HYSDN cards, specific routines for ergo type boards.
4 *
5 * Author Werner Cornelius (werner@titro.de) for Hypercope GmbH
6 * Copyright 1999 by Werner Cornelius (werner@titro.de)
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 * As all Linux supported cards Champ2, Ergo and Metro2/4 use the same
12 * DPRAM interface and layout with only minor differences all related
13 * stuff is done here, not in separate modules.
14 *
15 */
16
17#include <linux/config.h>
18#include <linux/sched.h>
19#include <linux/signal.h>
20#include <linux/kernel.h>
21#include <linux/ioport.h>
22#include <linux/interrupt.h>
23#include <linux/vmalloc.h>
24#include <linux/delay.h>
25#include <asm/io.h>
26
27#include "hysdn_defs.h"
28#include "boardergo.h"
29
30#define byteout(addr,val) outb(val,addr)
31#define bytein(addr) inb(addr)
32
33/***************************************************/
34/* The cards interrupt handler. Called from system */
35/***************************************************/
36static irqreturn_t
37ergo_interrupt(int intno, void *dev_id, struct pt_regs *regs)
38{
39 hysdn_card *card = dev_id; /* parameter from irq */
40 tErgDpram *dpr;
41 ulong flags;
42 uchar volatile b;
43
44 if (!card)
45 return IRQ_NONE; /* error -> spurious interrupt */
46 if (!card->irq_enabled)
47 return IRQ_NONE; /* other device interrupting or irq switched off */
48
49 save_flags(flags);
50 cli(); /* no further irqs allowed */
51
52 if (!(bytein(card->iobase + PCI9050_INTR_REG) & PCI9050_INTR_REG_STAT1)) {
53 restore_flags(flags); /* restore old state */
54 return IRQ_NONE; /* no interrupt requested by E1 */
55 }
56 /* clear any pending ints on the board */
57 dpr = card->dpram;
58 b = dpr->ToPcInt; /* clear for ergo */
59 b |= dpr->ToPcIntMetro; /* same for metro */
60 b |= dpr->ToHyInt; /* and for champ */
61
62 /* start kernel task immediately after leaving all interrupts */
63 if (!card->hw_lock)
64 schedule_work(&card->irq_queue);
65 restore_flags(flags);
66 return IRQ_HANDLED;
67} /* ergo_interrupt */
68
69/******************************************************************************/
70/* ergo_irq_bh is the function called by the immediate kernel task list after */
71/* being activated with queue_task and no interrupts active. This task is the */
72/* only one handling data transfer from or to the card after booting. The task */
73/* may be queued from everywhere (interrupts included). */
74/******************************************************************************/
75static void
76ergo_irq_bh(hysdn_card * card)
77{
78 tErgDpram *dpr;
79 int again;
80 ulong flags;
81
82 if (card->state != CARD_STATE_RUN)
83 return; /* invalid call */
84
85 dpr = card->dpram; /* point to DPRAM */
86
87 save_flags(flags);
88 cli();
89 if (card->hw_lock) {
90 restore_flags(flags); /* hardware currently unavailable */
91 return;
92 }
93 card->hw_lock = 1; /* we now lock the hardware */
94
95 do {
96 sti(); /* reenable other ints */
97 again = 0; /* assume loop not to be repeated */
98
99 if (!dpr->ToHyFlag) {
100 /* we are able to send a buffer */
101
102 if (hysdn_sched_tx(card, dpr->ToHyBuf, &dpr->ToHySize, &dpr->ToHyChannel,
103 ERG_TO_HY_BUF_SIZE)) {
104 dpr->ToHyFlag = 1; /* enable tx */
105 again = 1; /* restart loop */
106 }
107 } /* we are able to send a buffer */
108 if (dpr->ToPcFlag) {
109 /* a message has arrived for us, handle it */
110
111 if (hysdn_sched_rx(card, dpr->ToPcBuf, dpr->ToPcSize, dpr->ToPcChannel)) {
112 dpr->ToPcFlag = 0; /* we worked the data */
113 again = 1; /* restart loop */
114 }
115 } /* a message has arrived for us */
116 cli(); /* no further ints */
117 if (again) {
118 dpr->ToHyInt = 1;
119 dpr->ToPcInt = 1; /* interrupt to E1 for all cards */
120 } else
121 card->hw_lock = 0; /* free hardware again */
122 } while (again); /* until nothing more to do */
123
124 restore_flags(flags);
125} /* ergo_irq_bh */
126
127
128/*********************************************************/
129/* stop the card (hardware reset) and disable interrupts */
130/*********************************************************/
131static void
132ergo_stopcard(hysdn_card * card)
133{
134 ulong flags;
135 uchar val;
136
137 hysdn_net_release(card); /* first release the net device if existing */
138#ifdef CONFIG_HYSDN_CAPI
139 hycapi_capi_stop(card);
140#endif /* CONFIG_HYSDN_CAPI */
141 save_flags(flags);
142 cli();
143 val = bytein(card->iobase + PCI9050_INTR_REG); /* get actual value */
144 val &= ~(PCI9050_INTR_REG_ENPCI | PCI9050_INTR_REG_EN1); /* mask irq */
145 byteout(card->iobase + PCI9050_INTR_REG, val);
146 card->irq_enabled = 0;
147 byteout(card->iobase + PCI9050_USER_IO, PCI9050_E1_RESET); /* reset E1 processor */
148 card->state = CARD_STATE_UNUSED;
149 card->err_log_state = ERRLOG_STATE_OFF; /* currently no log active */
150
151 restore_flags(flags);
152} /* ergo_stopcard */
153
154/**************************************************************************/
155/* enable or disable the cards error log. The event is queued if possible */
156/**************************************************************************/
157static void
158ergo_set_errlog_state(hysdn_card * card, int on)
159{
160 ulong flags;
161
162 if (card->state != CARD_STATE_RUN) {
163 card->err_log_state = ERRLOG_STATE_OFF; /* must be off */
164 return;
165 }
166 save_flags(flags);
167 cli();
168
169 if (((card->err_log_state == ERRLOG_STATE_OFF) && !on) ||
170 ((card->err_log_state == ERRLOG_STATE_ON) && on)) {
171 restore_flags(flags);
172 return; /* nothing to do */
173 }
174 if (on)
175 card->err_log_state = ERRLOG_STATE_START; /* request start */
176 else
177 card->err_log_state = ERRLOG_STATE_STOP; /* request stop */
178
179 restore_flags(flags);
180 schedule_work(&card->irq_queue);
181} /* ergo_set_errlog_state */
182
183/******************************************/
184/* test the cards RAM and return 0 if ok. */
185/******************************************/
186static const char TestText[36] = "This Message is filler, why read it";
187
188static int
189ergo_testram(hysdn_card * card)
190{
191 tErgDpram *dpr = card->dpram;
192
193 memset(dpr->TrapTable, 0, sizeof(dpr->TrapTable)); /* clear all Traps */
194 dpr->ToHyInt = 1; /* E1 INTR state forced */
195
196 memcpy(&dpr->ToHyBuf[ERG_TO_HY_BUF_SIZE - sizeof(TestText)], TestText,
197 sizeof(TestText));
198 if (memcmp(&dpr->ToHyBuf[ERG_TO_HY_BUF_SIZE - sizeof(TestText)], TestText,
199 sizeof(TestText)))
200 return (-1);
201
202 memcpy(&dpr->ToPcBuf[ERG_TO_PC_BUF_SIZE - sizeof(TestText)], TestText,
203 sizeof(TestText));
204 if (memcmp(&dpr->ToPcBuf[ERG_TO_PC_BUF_SIZE - sizeof(TestText)], TestText,
205 sizeof(TestText)))
206 return (-1);
207
208 return (0);
209} /* ergo_testram */
210
211/*****************************************************************************/
212/* this function is intended to write stage 1 boot image to the cards buffer */
213/* this is done in two steps. First the 1024 hi-words are written (offs=0), */
214/* then the 1024 lo-bytes are written. The remaining DPRAM is cleared, the */
215/* PCI-write-buffers flushed and the card is taken out of reset. */
216/* The function then waits for a reaction of the E1 processor or a timeout. */
217/* Negative return values are interpreted as errors. */
218/*****************************************************************************/
219static int
220ergo_writebootimg(struct HYSDN_CARD *card, uchar * buf, ulong offs)
221{
222 uchar *dst;
223 tErgDpram *dpram;
224 int cnt = (BOOT_IMG_SIZE >> 2); /* number of words to move and swap (byte order!) */
225
226 if (card->debug_flags & LOG_POF_CARD)
227 hysdn_addlog(card, "ERGO: write bootldr offs=0x%lx ", offs);
228
229 dst = card->dpram; /* pointer to start of DPRAM */
230 dst += (offs + ERG_DPRAM_FILL_SIZE); /* offset in the DPRAM */
231 while (cnt--) {
232 *dst++ = *(buf + 1); /* high byte */
233 *dst++ = *buf; /* low byte */
234 dst += 2; /* point to next longword */
235 buf += 2; /* buffer only filled with words */
236 }
237
238 /* if low words (offs = 2) have been written, clear the rest of the DPRAM, */
239 /* flush the PCI-write-buffer and take the E1 out of reset */
240 if (offs) {
241 memset(card->dpram, 0, ERG_DPRAM_FILL_SIZE); /* fill the DPRAM still not cleared */
242 dpram = card->dpram; /* get pointer to dpram structure */
243 dpram->ToHyNoDpramErrLog = 0xFF; /* write a dpram register */
244 while (!dpram->ToHyNoDpramErrLog); /* reread volatile register to flush PCI */
245
246 byteout(card->iobase + PCI9050_USER_IO, PCI9050_E1_RUN); /* start E1 processor */
247 /* the interrupts are still masked */
248
249 sti();
250 msleep_interruptible(20); /* Timeout 20ms */
251
252 if (((tDpramBootSpooler *) card->dpram)->Len != DPRAM_SPOOLER_DATA_SIZE) {
253 if (card->debug_flags & LOG_POF_CARD)
254 hysdn_addlog(card, "ERGO: write bootldr no answer");
255 return (-ERR_BOOTIMG_FAIL);
256 }
257 } /* start_boot_img */
258 return (0); /* successful */
259} /* ergo_writebootimg */
260
261/********************************************************************************/
262/* ergo_writebootseq writes the buffer containing len bytes to the E1 processor */
263/* using the boot spool mechanism. If everything works fine 0 is returned. In */
264/* case of errors a negative error value is returned. */
265/********************************************************************************/
266static int
267ergo_writebootseq(struct HYSDN_CARD *card, uchar * buf, int len)
268{
269 tDpramBootSpooler *sp = (tDpramBootSpooler *) card->dpram;
270 uchar *dst;
271 uchar buflen;
272 int nr_write;
273 uchar tmp_rdptr;
274 uchar wr_mirror;
275 int i;
276
277 if (card->debug_flags & LOG_POF_CARD)
278 hysdn_addlog(card, "ERGO: write boot seq len=%d ", len);
279
280 dst = sp->Data; /* point to data in spool structure */
281 buflen = sp->Len; /* maximum len of spooled data */
282 wr_mirror = sp->WrPtr; /* only once read */
283 sti();
284
285 /* try until all bytes written or error */
286 i = 0x1000; /* timeout value */
287 while (len) {
288
289 /* first determine the number of bytes that may be buffered */
290 do {
291 tmp_rdptr = sp->RdPtr; /* first read the pointer */
292 i--; /* decrement timeout */
293 } while (i && (tmp_rdptr != sp->RdPtr)); /* wait for stable pointer */
294
295 if (!i) {
296 if (card->debug_flags & LOG_POF_CARD)
297 hysdn_addlog(card, "ERGO: write boot seq timeout");
298 return (-ERR_BOOTSEQ_FAIL); /* value not stable -> timeout */
299 }
300 if ((nr_write = tmp_rdptr - wr_mirror - 1) < 0)
301 nr_write += buflen; /* now we got number of free bytes - 1 in buffer */
302
303 if (!nr_write)
304 continue; /* no free bytes in buffer */
305
306 if (nr_write > len)
307 nr_write = len; /* limit if last few bytes */
308 i = 0x1000; /* reset timeout value */
309
310 /* now we know how much bytes we may put in the puffer */
311 len -= nr_write; /* we savely could adjust len before output */
312 while (nr_write--) {
313 *(dst + wr_mirror) = *buf++; /* output one byte */
314 if (++wr_mirror >= buflen)
315 wr_mirror = 0;
316 sp->WrPtr = wr_mirror; /* announce the next byte to E1 */
317 } /* while (nr_write) */
318
319 } /* while (len) */
320 return (0);
321} /* ergo_writebootseq */
322
323/***********************************************************************************/
324/* ergo_waitpofready waits for a maximum of 10 seconds for the completition of the */
325/* boot process. If the process has been successful 0 is returned otherwise a */
326/* negative error code is returned. */
327/***********************************************************************************/
328static int
329ergo_waitpofready(struct HYSDN_CARD *card)
330{
331 tErgDpram *dpr = card->dpram; /* pointer to DPRAM structure */
332 int timecnt = 10000 / 50; /* timeout is 10 secs max. */
333 ulong flags;
334 int msg_size;
335 int i;
336
337 if (card->debug_flags & LOG_POF_CARD)
338 hysdn_addlog(card, "ERGO: waiting for pof ready");
339 while (timecnt--) {
340 /* wait until timeout */
341
342 if (dpr->ToPcFlag) {
343 /* data has arrived */
344
345 if ((dpr->ToPcChannel != CHAN_SYSTEM) ||
346 (dpr->ToPcSize < MIN_RDY_MSG_SIZE) ||
347 (dpr->ToPcSize > MAX_RDY_MSG_SIZE) ||
348 ((*(ulong *) dpr->ToPcBuf) != RDY_MAGIC))
349 break; /* an error occurred */
350
351 /* Check for additional data delivered during SysReady */
352 msg_size = dpr->ToPcSize - RDY_MAGIC_SIZE;
353 if (msg_size > 0)
354 if (EvalSysrTokData(card, dpr->ToPcBuf + RDY_MAGIC_SIZE, msg_size))
355 break;
356
357 if (card->debug_flags & LOG_POF_RECORD)
358 hysdn_addlog(card, "ERGO: pof boot success");
359 save_flags(flags);
360 cli();
361
362 card->state = CARD_STATE_RUN; /* now card is running */
363 /* enable the cards interrupt */
364 byteout(card->iobase + PCI9050_INTR_REG,
365 bytein(card->iobase + PCI9050_INTR_REG) |
366 (PCI9050_INTR_REG_ENPCI | PCI9050_INTR_REG_EN1));
367 card->irq_enabled = 1; /* we are ready to receive interrupts */
368
369 dpr->ToPcFlag = 0; /* reset data indicator */
370 dpr->ToHyInt = 1;
371 dpr->ToPcInt = 1; /* interrupt to E1 for all cards */
372
373 restore_flags(flags);
374 if ((hynet_enable & (1 << card->myid))
375 && (i = hysdn_net_create(card)))
376 {
377 ergo_stopcard(card);
378 card->state = CARD_STATE_BOOTERR;
379 return (i);
380 }
381#ifdef CONFIG_HYSDN_CAPI
382 if((i = hycapi_capi_create(card))) {
383 printk(KERN_WARNING "HYSDN: failed to create capi-interface.\n");
384 }
385#endif /* CONFIG_HYSDN_CAPI */
386 return (0); /* success */
387 } /* data has arrived */
388 sti();
389 msleep_interruptible(50); /* Timeout 50ms */
390 } /* wait until timeout */
391
392 if (card->debug_flags & LOG_POF_CARD)
393 hysdn_addlog(card, "ERGO: pof boot ready timeout");
394 return (-ERR_POF_TIMEOUT);
395} /* ergo_waitpofready */
396
397
398
399/************************************************************************************/
400/* release the cards hardware. Before releasing do a interrupt disable and hardware */
401/* reset. Also unmap dpram. */
402/* Use only during module release. */
403/************************************************************************************/
404static void
405ergo_releasehardware(hysdn_card * card)
406{
407 ergo_stopcard(card); /* first stop the card if not already done */
408 free_irq(card->irq, card); /* release interrupt */
409 release_region(card->iobase + PCI9050_INTR_REG, 1); /* release all io ports */
410 release_region(card->iobase + PCI9050_USER_IO, 1);
411 vfree(card->dpram);
412 card->dpram = NULL; /* release shared mem */
413} /* ergo_releasehardware */
414
415
416/*********************************************************************************/
417/* acquire the needed hardware ports and map dpram. If an error occurs a nonzero */
418/* value is returned. */
419/* Use only during module init. */
420/*********************************************************************************/
421int
422ergo_inithardware(hysdn_card * card)
423{
424 if (!request_region(card->iobase + PCI9050_INTR_REG, 1, "HYSDN"))
425 return (-1);
426 if (!request_region(card->iobase + PCI9050_USER_IO, 1, "HYSDN")) {
427 release_region(card->iobase + PCI9050_INTR_REG, 1);
428 return (-1); /* ports already in use */
429 }
430 card->memend = card->membase + ERG_DPRAM_PAGE_SIZE - 1;
431 if (!(card->dpram = ioremap(card->membase, ERG_DPRAM_PAGE_SIZE))) {
432 release_region(card->iobase + PCI9050_INTR_REG, 1);
433 release_region(card->iobase + PCI9050_USER_IO, 1);
434 return (-1);
435 }
436
437 ergo_stopcard(card); /* disable interrupts */
438 if (request_irq(card->irq, ergo_interrupt, SA_SHIRQ, "HYSDN", card)) {
439 ergo_releasehardware(card); /* return the acquired hardware */
440 return (-1);
441 }
442 /* success, now setup the function pointers */
443 card->stopcard = ergo_stopcard;
444 card->releasehardware = ergo_releasehardware;
445 card->testram = ergo_testram;
446 card->writebootimg = ergo_writebootimg;
447 card->writebootseq = ergo_writebootseq;
448 card->waitpofready = ergo_waitpofready;
449 card->set_errlog_state = ergo_set_errlog_state;
450 INIT_WORK(&card->irq_queue, (void *) (void *) ergo_irq_bh, card);
451
452 return (0);
453} /* ergo_inithardware */
diff --git a/drivers/isdn/hysdn/boardergo.h b/drivers/isdn/hysdn/boardergo.h
new file mode 100644
index 000000000000..b56ff0889ead
--- /dev/null
+++ b/drivers/isdn/hysdn/boardergo.h
@@ -0,0 +1,100 @@
1/* $Id: boardergo.h,v 1.2.6.1 2001/09/23 22:24:54 kai Exp $
2 *
3 * Linux driver for HYSDN cards, definitions for ergo type boards (buffers..).
4 *
5 * Author Werner Cornelius (werner@titro.de) for Hypercope GmbH
6 * Copyright 1999 by Werner Cornelius (werner@titro.de)
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 */
12
13
14/************************************************/
15/* defines for the dual port memory of the card */
16/************************************************/
17#define ERG_DPRAM_PAGE_SIZE 0x2000 /* DPRAM occupies a 8K page */
18#define BOOT_IMG_SIZE 4096
19#define ERG_DPRAM_FILL_SIZE (ERG_DPRAM_PAGE_SIZE - BOOT_IMG_SIZE)
20
21#define ERG_TO_HY_BUF_SIZE 0x0E00 /* 3072 bytes buffer size to card */
22#define ERG_TO_PC_BUF_SIZE 0x0E00 /* 3072 bytes to PC, too */
23
24/* following DPRAM layout copied from OS2-driver boarderg.h */
25typedef struct ErgDpram_tag {
26/*0000 */ uchar ToHyBuf[ERG_TO_HY_BUF_SIZE];
27/*0E00 */ uchar ToPcBuf[ERG_TO_PC_BUF_SIZE];
28
29 /*1C00 */ uchar bSoftUart[SIZE_RSV_SOFT_UART];
30 /* size 0x1B0 */
31
32 /*1DB0 *//* tErrLogEntry */ uchar volatile ErrLogMsg[64];
33 /* size 64 bytes */
34 /*1DB0 ulong ulErrType; */
35 /*1DB4 ulong ulErrSubtype; */
36 /*1DB8 ulong ucTextSize; */
37 /*1DB9 ulong ucText[ERRLOG_TEXT_SIZE]; *//* ASCIIZ of len ucTextSize-1 */
38 /*1DF0 */
39
40/*1DF0 */ word volatile ToHyChannel;
41/*1DF2 */ word volatile ToHySize;
42 /*1DF4 */ uchar volatile ToHyFlag;
43 /* !=0: msg for Hy waiting */
44 /*1DF5 */ uchar volatile ToPcFlag;
45 /* !=0: msg for PC waiting */
46/*1DF6 */ word volatile ToPcChannel;
47/*1DF8 */ word volatile ToPcSize;
48 /*1DFA */ uchar bRes1DBA[0x1E00 - 0x1DFA];
49 /* 6 bytes */
50
51/*1E00 */ uchar bRestOfEntryTbl[0x1F00 - 0x1E00];
52/*1F00 */ ulong TrapTable[62];
53 /*1FF8 */ uchar bRes1FF8[0x1FFB - 0x1FF8];
54 /* low part of reset vetor */
55/*1FFB */ uchar ToPcIntMetro;
56 /* notes:
57 * - metro has 32-bit boot ram - accessing
58 * ToPcInt and ToHyInt would be the same;
59 * so we moved ToPcInt to 1FFB.
60 * Because on the PC side both vars are
61 * readonly (reseting on int from E1 to PC),
62 * we can read both vars on both cards
63 * without destroying anything.
64 * - 1FFB is the high byte of the reset vector,
65 * so E1 side should NOT change this byte
66 * when writing!
67 */
68/*1FFC */ uchar volatile ToHyNoDpramErrLog;
69 /* note: ToHyNoDpramErrLog is used to inform
70 * boot loader, not to use DPRAM based
71 * ErrLog; when DOS driver is rewritten
72 * this becomes obsolete
73 */
74/*1FFD */ uchar bRes1FFD;
75 /*1FFE */ uchar ToPcInt;
76 /* E1_intclear; on CHAMP2: E1_intset */
77 /*1FFF */ uchar ToHyInt;
78 /* E1_intset; on CHAMP2: E1_intclear */
79} tErgDpram;
80
81/**********************************************/
82/* PCI9050 controller local register offsets: */
83/* copied from boarderg.c */
84/**********************************************/
85#define PCI9050_INTR_REG 0x4C /* Interrupt register */
86#define PCI9050_USER_IO 0x51 /* User I/O register */
87
88 /* bitmask for PCI9050_INTR_REG: */
89#define PCI9050_INTR_REG_EN1 0x01 /* 1= enable (def.), 0= disable */
90#define PCI9050_INTR_REG_POL1 0x02 /* 1= active high (def.), 0= active low */
91#define PCI9050_INTR_REG_STAT1 0x04 /* 1= intr. active, 0= intr. not active (def.) */
92#define PCI9050_INTR_REG_ENPCI 0x40 /* 1= PCI interrupts enable (def.) */
93
94 /* bitmask for PCI9050_USER_IO: */
95#define PCI9050_USER_IO_EN3 0x02 /* 1= disable , 0= enable (def.) */
96#define PCI9050_USER_IO_DIR3 0x04 /* 1= output (def.), 0= input */
97#define PCI9050_USER_IO_DAT3 0x08 /* 1= high (def.) , 0= low */
98
99#define PCI9050_E1_RESET ( PCI9050_USER_IO_DIR3) /* 0x04 */
100#define PCI9050_E1_RUN (PCI9050_USER_IO_DAT3|PCI9050_USER_IO_DIR3) /* 0x0C */
diff --git a/drivers/isdn/hysdn/hycapi.c b/drivers/isdn/hysdn/hycapi.c
new file mode 100644
index 000000000000..8ee25b2ccce1
--- /dev/null
+++ b/drivers/isdn/hysdn/hycapi.c
@@ -0,0 +1,797 @@
1/* $Id: hycapi.c,v 1.8.6.4 2001/09/23 22:24:54 kai Exp $
2 *
3 * Linux driver for HYSDN cards, CAPI2.0-Interface.
4 *
5 * Author Ulrich Albrecht <u.albrecht@hypercope.de> for Hypercope GmbH
6 * Copyright 2000 by Hypercope GmbH
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 */
12
13#include <linux/module.h>
14#include <linux/version.h>
15#include <linux/signal.h>
16#include <linux/kernel.h>
17#include <linux/skbuff.h>
18#include <linux/netdevice.h>
19
20#define VER_DRIVER 0
21#define VER_CARDTYPE 1
22#define VER_HWID 2
23#define VER_SERIAL 3
24#define VER_OPTION 4
25#define VER_PROTO 5
26#define VER_PROFILE 6
27#define VER_CAPI 7
28
29#include "hysdn_defs.h"
30#include <linux/kernelcapi.h>
31
32static char hycapi_revision[]="$Revision: 1.8.6.4 $";
33
34unsigned int hycapi_enable = 0xffffffff;
35MODULE_PARM(hycapi_enable, "i");
36
37typedef struct _hycapi_appl {
38 unsigned int ctrl_mask;
39 capi_register_params rp;
40 struct sk_buff *listen_req[CAPI_MAXCONTR];
41} hycapi_appl;
42
43static hycapi_appl hycapi_applications[CAPI_MAXAPPL];
44
45static inline int _hycapi_appCheck(int app_id, int ctrl_no)
46{
47 if((ctrl_no <= 0) || (ctrl_no > CAPI_MAXCONTR) || (app_id <= 0) ||
48 (app_id > CAPI_MAXAPPL))
49 {
50 printk(KERN_ERR "HYCAPI: Invalid request app_id %d for controller %d", app_id, ctrl_no);
51 return -1;
52 }
53 return ((hycapi_applications[app_id-1].ctrl_mask & (1 << (ctrl_no-1))) != 0);
54}
55
56/******************************
57Kernel-Capi callback reset_ctr
58******************************/
59
60void
61hycapi_reset_ctr(struct capi_ctr *ctrl)
62{
63 hycapictrl_info *cinfo = ctrl->driverdata;
64
65#ifdef HYCAPI_PRINTFNAMES
66 printk(KERN_NOTICE "HYCAPI hycapi_reset_ctr\n");
67#endif
68 capilib_release(&cinfo->ncci_head);
69 capi_ctr_reseted(ctrl);
70}
71
72/******************************
73Kernel-Capi callback remove_ctr
74******************************/
75
76void
77hycapi_remove_ctr(struct capi_ctr *ctrl)
78{
79 int i;
80 hycapictrl_info *cinfo = NULL;
81 hysdn_card *card = NULL;
82#ifdef HYCAPI_PRINTFNAMES
83 printk(KERN_NOTICE "HYCAPI hycapi_remove_ctr\n");
84#endif
85 cinfo = (hycapictrl_info *)(ctrl->driverdata);
86 if(!cinfo) {
87 printk(KERN_ERR "No hycapictrl_info set!");
88 return;
89 }
90 card = cinfo->card;
91 capi_ctr_suspend_output(ctrl);
92 for(i=0; i<CAPI_MAXAPPL;i++) {
93 if(hycapi_applications[i].listen_req[ctrl->cnr-1]) {
94 kfree_skb(hycapi_applications[i].listen_req[ctrl->cnr-1]);
95 hycapi_applications[i].listen_req[ctrl->cnr-1] = NULL;
96 }
97 }
98 detach_capi_ctr(ctrl);
99 ctrl->driverdata = NULL;
100 kfree(card->hyctrlinfo);
101
102
103 card->hyctrlinfo = NULL;
104}
105
106/***********************************************************
107
108Queue a CAPI-message to the controller.
109
110***********************************************************/
111
112static void
113hycapi_sendmsg_internal(struct capi_ctr *ctrl, struct sk_buff *skb)
114{
115 hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata);
116 hysdn_card *card = cinfo->card;
117
118 spin_lock_irq(&cinfo->lock);
119#ifdef HYCAPI_PRINTFNAMES
120 printk(KERN_NOTICE "hycapi_send_message\n");
121#endif
122 cinfo->skbs[cinfo->in_idx++] = skb; /* add to buffer list */
123 if (cinfo->in_idx >= HYSDN_MAX_CAPI_SKB)
124 cinfo->in_idx = 0; /* wrap around */
125 cinfo->sk_count++; /* adjust counter */
126 if (cinfo->sk_count >= HYSDN_MAX_CAPI_SKB) {
127 /* inform upper layers we're full */
128 printk(KERN_ERR "HYSDN Card%d: CAPI-buffer overrun!\n",
129 card->myid);
130 capi_ctr_suspend_output(ctrl);
131 }
132 cinfo->tx_skb = skb;
133 spin_unlock_irq(&cinfo->lock);
134 schedule_work(&card->irq_queue);
135}
136
137/***********************************************************
138hycapi_register_internal
139
140Send down the CAPI_REGISTER-Command to the controller.
141This functions will also be used if the adapter has been rebooted to
142re-register any applications in the private list.
143
144************************************************************/
145
146static void
147hycapi_register_internal(struct capi_ctr *ctrl, __u16 appl,
148 capi_register_params *rp)
149{
150 char ExtFeatureDefaults[] = "49 /0/0/0/0,*/1,*/2,*/3,*/4,*/5,*/6,*/7,*/8,*/9,*";
151 hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata);
152 hysdn_card *card = cinfo->card;
153 struct sk_buff *skb;
154 __u16 len;
155 __u8 _command = 0xa0, _subcommand = 0x80;
156 __u16 MessageNumber = 0x0000;
157 __u16 MessageBufferSize = 0;
158 int slen = strlen(ExtFeatureDefaults);
159#ifdef HYCAPI_PRINTFNAMES
160 printk(KERN_NOTICE "hycapi_register_appl\n");
161#endif
162 MessageBufferSize = rp->level3cnt * rp->datablkcnt * rp->datablklen;
163
164 len = CAPI_MSG_BASELEN + 8 + slen + 1;
165 if (!(skb = alloc_skb(len, GFP_ATOMIC))) {
166 printk(KERN_ERR "HYSDN card%d: memory squeeze in hycapi_register_appl\n",
167 card->myid);
168 return;
169 }
170 memcpy(skb_put(skb,sizeof(__u16)), &len, sizeof(__u16));
171 memcpy(skb_put(skb,sizeof(__u16)), &appl, sizeof(__u16));
172 memcpy(skb_put(skb,sizeof(__u8)), &_command, sizeof(_command));
173 memcpy(skb_put(skb,sizeof(__u8)), &_subcommand, sizeof(_subcommand));
174 memcpy(skb_put(skb,sizeof(__u16)), &MessageNumber, sizeof(__u16));
175 memcpy(skb_put(skb,sizeof(__u16)), &MessageBufferSize, sizeof(__u16));
176 memcpy(skb_put(skb,sizeof(__u16)), &(rp->level3cnt), sizeof(__u16));
177 memcpy(skb_put(skb,sizeof(__u16)), &(rp->datablkcnt), sizeof(__u16));
178 memcpy(skb_put(skb,sizeof(__u16)), &(rp->datablklen), sizeof(__u16));
179 memcpy(skb_put(skb,slen), ExtFeatureDefaults, slen);
180 hycapi_applications[appl-1].ctrl_mask |= (1 << (ctrl->cnr-1));
181 hycapi_send_message(ctrl, skb);
182}
183
184/************************************************************
185hycapi_restart_internal
186
187After an adapter has been rebootet, re-register all applications and
188send a LISTEN_REQ (if there has been such a thing )
189
190*************************************************************/
191
192static void hycapi_restart_internal(struct capi_ctr *ctrl)
193{
194 int i;
195 struct sk_buff *skb;
196#ifdef HYCAPI_PRINTFNAMES
197 printk(KERN_WARNING "HYSDN: hycapi_restart_internal");
198#endif
199 for(i=0; i<CAPI_MAXAPPL; i++) {
200 if(_hycapi_appCheck(i+1, ctrl->cnr) == 1) {
201 hycapi_register_internal(ctrl, i+1,
202 &hycapi_applications[i].rp);
203 if(hycapi_applications[i].listen_req[ctrl->cnr-1]) {
204 skb = skb_copy(hycapi_applications[i].listen_req[ctrl->cnr-1], GFP_ATOMIC);
205 hycapi_sendmsg_internal(ctrl, skb);
206 }
207 }
208 }
209}
210
211/*************************************************************
212Register an application.
213Error-checking is done for CAPI-compliance.
214
215The application is recorded in the internal list.
216*************************************************************/
217
218void
219hycapi_register_appl(struct capi_ctr *ctrl, __u16 appl,
220 capi_register_params *rp)
221{
222 int MaxLogicalConnections = 0, MaxBDataBlocks = 0, MaxBDataLen = 0;
223 hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata);
224 hysdn_card *card = cinfo->card;
225 int chk = _hycapi_appCheck(appl, ctrl->cnr);
226 if(chk < 0) {
227 return;
228 }
229 if(chk == 1) {
230 printk(KERN_INFO "HYSDN: apl %d already registered\n", appl);
231 return;
232 }
233 MaxBDataBlocks = rp->datablkcnt > CAPI_MAXDATAWINDOW ? CAPI_MAXDATAWINDOW : rp->datablkcnt;
234 rp->datablkcnt = MaxBDataBlocks;
235 MaxBDataLen = rp->datablklen < 1024 ? 1024 : rp->datablklen ;
236 rp->datablklen = MaxBDataLen;
237
238 MaxLogicalConnections = rp->level3cnt;
239 if (MaxLogicalConnections < 0) {
240 MaxLogicalConnections = card->bchans * -MaxLogicalConnections;
241 }
242 if (MaxLogicalConnections == 0) {
243 MaxLogicalConnections = card->bchans;
244 }
245
246 rp->level3cnt = MaxLogicalConnections;
247 memcpy(&hycapi_applications[appl-1].rp,
248 rp, sizeof(capi_register_params));
249}
250
251/*********************************************************************
252
253hycapi_release_internal
254
255Send down a CAPI_RELEASE to the controller.
256*********************************************************************/
257
258static void hycapi_release_internal(struct capi_ctr *ctrl, __u16 appl)
259{
260 hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata);
261 hysdn_card *card = cinfo->card;
262 struct sk_buff *skb;
263 __u16 len;
264 __u8 _command = 0xa1, _subcommand = 0x80;
265 __u16 MessageNumber = 0x0000;
266
267 capilib_release_appl(&cinfo->ncci_head, appl);
268
269#ifdef HYCAPI_PRINTFNAMES
270 printk(KERN_NOTICE "hycapi_release_appl\n");
271#endif
272 len = CAPI_MSG_BASELEN;
273 if (!(skb = alloc_skb(len, GFP_ATOMIC))) {
274 printk(KERN_ERR "HYSDN card%d: memory squeeze in hycapi_register_appl\n",
275 card->myid);
276 return;
277 }
278 memcpy(skb_put(skb,sizeof(__u16)), &len, sizeof(__u16));
279 memcpy(skb_put(skb,sizeof(__u16)), &appl, sizeof(__u16));
280 memcpy(skb_put(skb,sizeof(__u8)), &_command, sizeof(_command));
281 memcpy(skb_put(skb,sizeof(__u8)), &_subcommand, sizeof(_subcommand));
282 memcpy(skb_put(skb,sizeof(__u16)), &MessageNumber, sizeof(__u16));
283 hycapi_send_message(ctrl, skb);
284 hycapi_applications[appl-1].ctrl_mask &= ~(1 << (ctrl->cnr-1));
285}
286
287/******************************************************************
288hycapi_release_appl
289
290Release the application from the internal list an remove it's
291registration at controller-level
292******************************************************************/
293
294void
295hycapi_release_appl(struct capi_ctr *ctrl, __u16 appl)
296{
297 int chk;
298
299 chk = _hycapi_appCheck(appl, ctrl->cnr);
300 if(chk<0) {
301 printk(KERN_ERR "HYCAPI: Releasing invalid appl %d on controller %d\n", appl, ctrl->cnr);
302 return;
303 }
304 if(hycapi_applications[appl-1].listen_req[ctrl->cnr-1]) {
305 kfree_skb(hycapi_applications[appl-1].listen_req[ctrl->cnr-1]);
306 hycapi_applications[appl-1].listen_req[ctrl->cnr-1] = NULL;
307 }
308 if(chk == 1)
309 {
310 hycapi_release_internal(ctrl, appl);
311 }
312}
313
314
315/**************************************************************
316Kill a single controller.
317**************************************************************/
318
319int hycapi_capi_release(hysdn_card *card)
320{
321 hycapictrl_info *cinfo = card->hyctrlinfo;
322 struct capi_ctr *ctrl;
323#ifdef HYCAPI_PRINTFNAMES
324 printk(KERN_NOTICE "hycapi_capi_release\n");
325#endif
326 if(cinfo) {
327 ctrl = &cinfo->capi_ctrl;
328 hycapi_remove_ctr(ctrl);
329 }
330 return 0;
331}
332
333/**************************************************************
334hycapi_capi_stop
335
336Stop CAPI-Output on a card. (e.g. during reboot)
337***************************************************************/
338
339int hycapi_capi_stop(hysdn_card *card)
340{
341 hycapictrl_info *cinfo = card->hyctrlinfo;
342 struct capi_ctr *ctrl;
343#ifdef HYCAPI_PRINTFNAMES
344 printk(KERN_NOTICE "hycapi_capi_stop\n");
345#endif
346 if(cinfo) {
347 ctrl = &cinfo->capi_ctrl;
348/* ctrl->suspend_output(ctrl); */
349 capi_ctr_reseted(ctrl);
350 }
351 return 0;
352}
353
354/***************************************************************
355hycapi_send_message
356
357Send a message to the controller.
358
359Messages are parsed for their Command/Subcommand-type, and appropriate
360action's are performed.
361
362Note that we have to muck around with a 64Bit-DATA_REQ as there are
363firmware-releases that do not check the MsgLen-Indication!
364
365***************************************************************/
366
367u16 hycapi_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
368{
369 __u16 appl_id;
370 int _len, _len2;
371 __u8 msghead[64];
372 hycapictrl_info *cinfo = ctrl->driverdata;
373 u16 retval = CAPI_NOERROR;
374
375 appl_id = CAPIMSG_APPID(skb->data);
376 switch(_hycapi_appCheck(appl_id, ctrl->cnr))
377 {
378 case 0:
379/* printk(KERN_INFO "Need to register\n"); */
380 hycapi_register_internal(ctrl,
381 appl_id,
382 &(hycapi_applications[appl_id-1].rp));
383 break;
384 case 1:
385 break;
386 default:
387 printk(KERN_ERR "HYCAPI: Controller mixup!\n");
388 retval = CAPI_ILLAPPNR;
389 goto out;
390 }
391 switch(CAPIMSG_CMD(skb->data)) {
392 case CAPI_DISCONNECT_B3_RESP:
393 capilib_free_ncci(&cinfo->ncci_head, appl_id,
394 CAPIMSG_NCCI(skb->data));
395 break;
396 case CAPI_DATA_B3_REQ:
397 _len = CAPIMSG_LEN(skb->data);
398 if (_len > 22) {
399 _len2 = _len - 22;
400 memcpy(msghead, skb->data, 22);
401 memcpy(skb->data + _len2, msghead, 22);
402 skb_pull(skb, _len2);
403 CAPIMSG_SETLEN(skb->data, 22);
404 retval = capilib_data_b3_req(&cinfo->ncci_head,
405 CAPIMSG_APPID(skb->data),
406 CAPIMSG_NCCI(skb->data),
407 CAPIMSG_MSGID(skb->data));
408 }
409 break;
410 case CAPI_LISTEN_REQ:
411 if(hycapi_applications[appl_id-1].listen_req[ctrl->cnr-1])
412 {
413 kfree_skb(hycapi_applications[appl_id-1].listen_req[ctrl->cnr-1]);
414 hycapi_applications[appl_id-1].listen_req[ctrl->cnr-1] = NULL;
415 }
416 if (!(hycapi_applications[appl_id-1].listen_req[ctrl->cnr-1] = skb_copy(skb, GFP_ATOMIC)))
417 {
418 printk(KERN_ERR "HYSDN: memory squeeze in private_listen\n");
419 }
420 break;
421 default:
422 break;
423 }
424 out:
425 if (retval == CAPI_NOERROR)
426 hycapi_sendmsg_internal(ctrl, skb);
427 else
428 dev_kfree_skb_any(skb);
429
430 return retval;
431}
432
433/*********************************************************************
434hycapi_read_proc
435
436Informations provided in the /proc/capi-entries.
437
438*********************************************************************/
439
440int hycapi_read_proc(char *page, char **start, off_t off,
441 int count, int *eof, struct capi_ctr *ctrl)
442{
443 hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata);
444 hysdn_card *card = cinfo->card;
445 int len = 0;
446 char *s;
447#ifdef HYCAPI_PRINTFNAMES
448 printk(KERN_NOTICE "hycapi_read_proc\n");
449#endif
450 len += sprintf(page+len, "%-16s %s\n", "name", cinfo->cardname);
451 len += sprintf(page+len, "%-16s 0x%x\n", "io", card->iobase);
452 len += sprintf(page+len, "%-16s %d\n", "irq", card->irq);
453
454 switch (card->brdtype) {
455 case BD_PCCARD: s = "HYSDN Hycard"; break;
456 case BD_ERGO: s = "HYSDN Ergo2"; break;
457 case BD_METRO: s = "HYSDN Metro4"; break;
458 case BD_CHAMP2: s = "HYSDN Champ2"; break;
459 case BD_PLEXUS: s = "HYSDN Plexus30"; break;
460 default: s = "???"; break;
461 }
462 len += sprintf(page+len, "%-16s %s\n", "type", s);
463 if ((s = cinfo->version[VER_DRIVER]) != 0)
464 len += sprintf(page+len, "%-16s %s\n", "ver_driver", s);
465 if ((s = cinfo->version[VER_CARDTYPE]) != 0)
466 len += sprintf(page+len, "%-16s %s\n", "ver_cardtype", s);
467 if ((s = cinfo->version[VER_SERIAL]) != 0)
468 len += sprintf(page+len, "%-16s %s\n", "ver_serial", s);
469
470 len += sprintf(page+len, "%-16s %s\n", "cardname", cinfo->cardname);
471
472 if (off+count >= len)
473 *eof = 1;
474 if (len < off)
475 return 0;
476 *start = page + off;
477 return ((count < len-off) ? count : len-off);
478}
479
480/**************************************************************
481hycapi_load_firmware
482
483This does NOT load any firmware, but the callback somehow is needed
484on capi-interface registration.
485
486**************************************************************/
487
488int hycapi_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
489{
490#ifdef HYCAPI_PRINTFNAMES
491 printk(KERN_NOTICE "hycapi_load_firmware\n");
492#endif
493 return 0;
494}
495
496
497char *hycapi_procinfo(struct capi_ctr *ctrl)
498{
499 hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata);
500#ifdef HYCAPI_PRINTFNAMES
501 printk(KERN_NOTICE "hycapi_proc_info\n");
502#endif
503 if (!cinfo)
504 return "";
505 sprintf(cinfo->infobuf, "%s %s 0x%x %d %s",
506 cinfo->cardname[0] ? cinfo->cardname : "-",
507 cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-",
508 cinfo->card ? cinfo->card->iobase : 0x0,
509 cinfo->card ? cinfo->card->irq : 0,
510 hycapi_revision
511 );
512 return cinfo->infobuf;
513}
514
515/******************************************************************
516hycapi_rx_capipkt
517
518Receive a capi-message.
519
520All B3_DATA_IND are converted to 64K-extension compatible format.
521New nccis are created if necessary.
522*******************************************************************/
523
524void
525hycapi_rx_capipkt(hysdn_card * card, uchar * buf, word len)
526{
527 struct sk_buff *skb;
528 hycapictrl_info *cinfo = card->hyctrlinfo;
529 struct capi_ctr *ctrl;
530 __u16 ApplId;
531 __u16 MsgLen, info;
532 __u16 len2, CapiCmd;
533 __u32 CP64[2] = {0,0};
534#ifdef HYCAPI_PRINTFNAMES
535 printk(KERN_NOTICE "hycapi_rx_capipkt\n");
536#endif
537 if(!cinfo) {
538 return;
539 }
540 ctrl = &cinfo->capi_ctrl;
541 if(len < CAPI_MSG_BASELEN) {
542 printk(KERN_ERR "HYSDN Card%d: invalid CAPI-message, lenght %d!\n",
543 card->myid, len);
544 return;
545 }
546 MsgLen = CAPIMSG_LEN(buf);
547 ApplId = CAPIMSG_APPID(buf);
548 CapiCmd = CAPIMSG_CMD(buf);
549
550 if((CapiCmd == CAPI_DATA_B3_IND) && (MsgLen < 30)) {
551 len2 = len + (30 - MsgLen);
552 if (!(skb = alloc_skb(len2, GFP_ATOMIC))) {
553 printk(KERN_ERR "HYSDN Card%d: incoming packet dropped\n",
554 card->myid);
555 return;
556 }
557 memcpy(skb_put(skb, MsgLen), buf, MsgLen);
558 memcpy(skb_put(skb, 2*sizeof(__u32)), CP64, 2* sizeof(__u32));
559 memcpy(skb_put(skb, len - MsgLen), buf + MsgLen,
560 len - MsgLen);
561 CAPIMSG_SETLEN(skb->data, 30);
562 } else {
563 if (!(skb = alloc_skb(len, GFP_ATOMIC))) {
564 printk(KERN_ERR "HYSDN Card%d: incoming packet dropped\n",
565 card->myid);
566 return;
567 }
568 memcpy(skb_put(skb, len), buf, len);
569 }
570 switch(CAPIMSG_CMD(skb->data))
571 {
572 case CAPI_CONNECT_B3_CONF:
573/* Check info-field for error-indication: */
574 info = CAPIMSG_U16(skb->data, 12);
575 switch(info)
576 {
577 case 0:
578 capilib_new_ncci(&cinfo->ncci_head, ApplId, CAPIMSG_NCCI(skb->data),
579 hycapi_applications[ApplId-1].rp.datablkcnt);
580
581 break;
582 case 0x0001:
583 printk(KERN_ERR "HYSDN Card%d: NCPI not supported by current "
584 "protocol. NCPI ignored.\n", card->myid);
585 break;
586 case 0x2001:
587 printk(KERN_ERR "HYSDN Card%d: Message not supported in"
588 " current state\n", card->myid);
589 break;
590 case 0x2002:
591 printk(KERN_ERR "HYSDN Card%d: invalid PLCI\n", card->myid);
592 break;
593 case 0x2004:
594 printk(KERN_ERR "HYSDN Card%d: out of NCCI\n", card->myid);
595 break;
596 case 0x3008:
597 printk(KERN_ERR "HYSDN Card%d: NCPI not supported\n",
598 card->myid);
599 break;
600 default:
601 printk(KERN_ERR "HYSDN Card%d: Info in CONNECT_B3_CONF: %d\n",
602 card->myid, info);
603 break;
604 }
605 break;
606 case CAPI_CONNECT_B3_IND:
607 capilib_new_ncci(&cinfo->ncci_head, ApplId,
608 CAPIMSG_NCCI(skb->data),
609 hycapi_applications[ApplId-1].rp.datablkcnt);
610 break;
611 case CAPI_DATA_B3_CONF:
612 capilib_data_b3_conf(&cinfo->ncci_head, ApplId,
613 CAPIMSG_NCCI(skb->data),
614 CAPIMSG_MSGID(skb->data));
615 break;
616 default:
617 break;
618 }
619 capi_ctr_handle_message(ctrl, ApplId, skb);
620}
621
622/******************************************************************
623hycapi_tx_capiack
624
625Internally acknowledge a msg sent. This will remove the msg from the
626internal queue.
627
628*******************************************************************/
629
630void hycapi_tx_capiack(hysdn_card * card)
631{
632 hycapictrl_info *cinfo = card->hyctrlinfo;
633#ifdef HYCAPI_PRINTFNAMES
634 printk(KERN_NOTICE "hycapi_tx_capiack\n");
635#endif
636 if(!cinfo) {
637 return;
638 }
639 spin_lock_irq(&cinfo->lock);
640 kfree_skb(cinfo->skbs[cinfo->out_idx]); /* free skb */
641 cinfo->skbs[cinfo->out_idx++] = NULL;
642 if (cinfo->out_idx >= HYSDN_MAX_CAPI_SKB)
643 cinfo->out_idx = 0; /* wrap around */
644
645 if (cinfo->sk_count-- == HYSDN_MAX_CAPI_SKB) /* dec usage count */
646 capi_ctr_resume_output(&cinfo->capi_ctrl);
647 spin_unlock_irq(&cinfo->lock);
648}
649
650/***************************************************************
651hycapi_tx_capiget(hysdn_card *card)
652
653This is called when polling for messages to SEND.
654
655****************************************************************/
656
657struct sk_buff *
658hycapi_tx_capiget(hysdn_card *card)
659{
660 hycapictrl_info *cinfo = card->hyctrlinfo;
661 if(!cinfo) {
662 return (struct sk_buff *)NULL;
663 }
664 if (!cinfo->sk_count)
665 return (struct sk_buff *)NULL; /* nothing available */
666
667 return (cinfo->skbs[cinfo->out_idx]); /* next packet to send */
668}
669
670
671/**********************************************************
672int hycapi_init()
673
674attach the capi-driver to the kernel-capi.
675
676***********************************************************/
677
678int hycapi_init(void)
679{
680 int i;
681 for(i=0;i<CAPI_MAXAPPL;i++) {
682 memset(&(hycapi_applications[i]), 0, sizeof(hycapi_appl));
683 }
684 return(0);
685}
686
687/**************************************************************
688hycapi_cleanup(void)
689
690detach the capi-driver to the kernel-capi. Actually this should
691free some more ressources. Do that later.
692**************************************************************/
693
694void
695hycapi_cleanup(void)
696{
697}
698
699/********************************************************************
700hycapi_capi_create(hysdn_card *card)
701
702Attach the card with its capi-ctrl.
703*********************************************************************/
704
705static void hycapi_fill_profile(hysdn_card *card)
706{
707 hycapictrl_info *cinfo = NULL;
708 struct capi_ctr *ctrl = NULL;
709 cinfo = card->hyctrlinfo;
710 if(!cinfo) return;
711 ctrl = &cinfo->capi_ctrl;
712 strcpy(ctrl->manu, "Hypercope");
713 ctrl->version.majorversion = 2;
714 ctrl->version.minorversion = 0;
715 ctrl->version.majormanuversion = 3;
716 ctrl->version.minormanuversion = 2;
717 ctrl->profile.ncontroller = card->myid;
718 ctrl->profile.nbchannel = card->bchans;
719 ctrl->profile.goptions = GLOBAL_OPTION_INTERNAL_CONTROLLER |
720 GLOBAL_OPTION_B_CHANNEL_OPERATION;
721 ctrl->profile.support1 = B1_PROT_64KBIT_HDLC |
722 (card->faxchans ? B1_PROT_T30 : 0) |
723 B1_PROT_64KBIT_TRANSPARENT;
724 ctrl->profile.support2 = B2_PROT_ISO7776 |
725 (card->faxchans ? B2_PROT_T30 : 0) |
726 B2_PROT_TRANSPARENT;
727 ctrl->profile.support3 = B3_PROT_TRANSPARENT |
728 B3_PROT_T90NL |
729 (card->faxchans ? B3_PROT_T30 : 0) |
730 (card->faxchans ? B3_PROT_T30EXT : 0) |
731 B3_PROT_ISO8208;
732}
733
734int
735hycapi_capi_create(hysdn_card *card)
736{
737 hycapictrl_info *cinfo = NULL;
738 struct capi_ctr *ctrl = NULL;
739 int retval;
740#ifdef HYCAPI_PRINTFNAMES
741 printk(KERN_NOTICE "hycapi_capi_create\n");
742#endif
743 if((hycapi_enable & (1 << card->myid)) == 0) {
744 return 1;
745 }
746 if (!card->hyctrlinfo) {
747 cinfo = (hycapictrl_info *) kmalloc(sizeof(hycapictrl_info), GFP_ATOMIC);
748 if (!cinfo) {
749 printk(KERN_WARNING "HYSDN: no memory for capi-ctrl.\n");
750 return -ENOMEM;
751 }
752 memset(cinfo, 0, sizeof(hycapictrl_info));
753 card->hyctrlinfo = cinfo;
754 cinfo->card = card;
755 spin_lock_init(&cinfo->lock);
756 INIT_LIST_HEAD(&cinfo->ncci_head);
757
758 switch (card->brdtype) {
759 case BD_PCCARD: strcpy(cinfo->cardname,"HYSDN Hycard"); break;
760 case BD_ERGO: strcpy(cinfo->cardname,"HYSDN Ergo2"); break;
761 case BD_METRO: strcpy(cinfo->cardname,"HYSDN Metro4"); break;
762 case BD_CHAMP2: strcpy(cinfo->cardname,"HYSDN Champ2"); break;
763 case BD_PLEXUS: strcpy(cinfo->cardname,"HYSDN Plexus30"); break;
764 default: strcpy(cinfo->cardname,"HYSDN ???"); break;
765 }
766
767 ctrl = &cinfo->capi_ctrl;
768 ctrl->driver_name = "hycapi";
769 ctrl->driverdata = cinfo;
770 ctrl->register_appl = hycapi_register_appl;
771 ctrl->release_appl = hycapi_release_appl;
772 ctrl->send_message = hycapi_send_message;
773 ctrl->load_firmware = hycapi_load_firmware;
774 ctrl->reset_ctr = hycapi_reset_ctr;
775 ctrl->procinfo = hycapi_procinfo;
776 ctrl->ctr_read_proc = hycapi_read_proc;
777 strcpy(ctrl->name, cinfo->cardname);
778 ctrl->owner = THIS_MODULE;
779
780 retval = attach_capi_ctr(ctrl);
781 if (retval) {
782 printk(KERN_ERR "hycapi: attach controller failed.\n");
783 return -EBUSY;
784 }
785 /* fill in the blanks: */
786 hycapi_fill_profile(card);
787 capi_ctr_ready(ctrl);
788 } else {
789 /* resume output on stopped ctrl */
790 ctrl = &card->hyctrlinfo->capi_ctrl;
791 hycapi_fill_profile(card);
792 capi_ctr_ready(ctrl);
793 hycapi_restart_internal(ctrl);
794/* ctrl->resume_output(ctrl); */
795 }
796 return 0;
797}
diff --git a/drivers/isdn/hysdn/hysdn_boot.c b/drivers/isdn/hysdn/hysdn_boot.c
new file mode 100644
index 000000000000..6c04281e57b8
--- /dev/null
+++ b/drivers/isdn/hysdn/hysdn_boot.c
@@ -0,0 +1,399 @@
1/* $Id: hysdn_boot.c,v 1.4.6.4 2001/09/23 22:24:54 kai Exp $
2 *
3 * Linux driver for HYSDN cards
4 * specific routines for booting and pof handling
5 *
6 * Author Werner Cornelius (werner@titro.de) for Hypercope GmbH
7 * Copyright 1999 by Werner Cornelius (werner@titro.de)
8 *
9 * This software may be used and distributed according to the terms
10 * of the GNU General Public License, incorporated herein by reference.
11 *
12 */
13
14#include <linux/vmalloc.h>
15#include <linux/slab.h>
16#include <asm/uaccess.h>
17
18#include "hysdn_defs.h"
19#include "hysdn_pof.h"
20
21/********************************/
22/* defines for pof read handler */
23/********************************/
24#define POF_READ_FILE_HEAD 0
25#define POF_READ_TAG_HEAD 1
26#define POF_READ_TAG_DATA 2
27
28/************************************************************/
29/* definition of boot specific data area. This data is only */
30/* needed during boot and so allocated dynamically. */
31/************************************************************/
32struct boot_data {
33 word Cryptor; /* for use with Decrypt function */
34 word Nrecs; /* records remaining in file */
35 uchar pof_state; /* actual state of read handler */
36 uchar is_crypted; /* card data is crypted */
37 int BufSize; /* actual number of bytes bufferd */
38 int last_error; /* last occurred error */
39 word pof_recid; /* actual pof recid */
40 ulong pof_reclen; /* total length of pof record data */
41 ulong pof_recoffset; /* actual offset inside pof record */
42 union {
43 uchar BootBuf[BOOT_BUF_SIZE]; /* buffer as byte count */
44 tPofRecHdr PofRecHdr; /* header for actual record/chunk */
45 tPofFileHdr PofFileHdr; /* header from POF file */
46 tPofTimeStamp PofTime; /* time information */
47 } buf;
48};
49
50/*****************************************************/
51/* start decryption of successive POF file chuncks. */
52/* */
53/* to be called at start of POF file reading, */
54/* before starting any decryption on any POF record. */
55/*****************************************************/
56void
57StartDecryption(struct boot_data *boot)
58{
59 boot->Cryptor = CRYPT_STARTTERM;
60} /* StartDecryption */
61
62
63/***************************************************************/
64/* decrypt complete BootBuf */
65/* NOTE: decryption must be applied to all or none boot tags - */
66/* to HI and LO boot loader and (all) seq tags, because */
67/* global Cryptor is started for whole POF. */
68/***************************************************************/
69void
70DecryptBuf(struct boot_data *boot, int cnt)
71{
72 uchar *bufp = boot->buf.BootBuf;
73
74 while (cnt--) {
75 boot->Cryptor = (boot->Cryptor >> 1) ^ ((boot->Cryptor & 1U) ? CRYPT_FEEDTERM : 0);
76 *bufp++ ^= (uchar) boot->Cryptor;
77 }
78} /* DecryptBuf */
79
80/********************************************************************************/
81/* pof_handle_data executes the required actions dependent on the active record */
82/* id. If successful 0 is returned, a negative value shows an error. */
83/********************************************************************************/
84static int
85pof_handle_data(hysdn_card * card, int datlen)
86{
87 struct boot_data *boot = card->boot; /* pointer to boot specific data */
88 long l;
89 uchar *imgp;
90 int img_len;
91
92 /* handle the different record types */
93 switch (boot->pof_recid) {
94
95 case TAG_TIMESTMP:
96 if (card->debug_flags & LOG_POF_RECORD)
97 hysdn_addlog(card, "POF created %s", boot->buf.PofTime.DateTimeText);
98 break;
99
100 case TAG_CBOOTDTA:
101 DecryptBuf(boot, datlen); /* we need to encrypt the buffer */
102 case TAG_BOOTDTA:
103 if (card->debug_flags & LOG_POF_RECORD)
104 hysdn_addlog(card, "POF got %s len=%d offs=0x%lx",
105 (boot->pof_recid == TAG_CBOOTDTA) ? "CBOOTDATA" : "BOOTDTA",
106 datlen, boot->pof_recoffset);
107
108 if (boot->pof_reclen != POF_BOOT_LOADER_TOTAL_SIZE) {
109 boot->last_error = EPOF_BAD_IMG_SIZE; /* invalid length */
110 return (boot->last_error);
111 }
112 imgp = boot->buf.BootBuf; /* start of buffer */
113 img_len = datlen; /* maximum length to transfer */
114
115 l = POF_BOOT_LOADER_OFF_IN_PAGE -
116 (boot->pof_recoffset & (POF_BOOT_LOADER_PAGE_SIZE - 1));
117 if (l > 0) {
118 /* buffer needs to be truncated */
119 imgp += l; /* advance pointer */
120 img_len -= l; /* adjust len */
121 }
122 /* at this point no special handling for data wrapping over buffer */
123 /* is necessary, because the boot image always will be adjusted to */
124 /* match a page boundary inside the buffer. */
125 /* The buffer for the boot image on the card is filled in 2 cycles */
126 /* first the 1024 hi-words are put in the buffer, then the low 1024 */
127 /* word are handled in the same way with different offset. */
128
129 if (img_len > 0) {
130 /* data available for copy */
131 if ((boot->last_error =
132 card->writebootimg(card, imgp,
133 (boot->pof_recoffset > POF_BOOT_LOADER_PAGE_SIZE) ? 2 : 0)) < 0)
134 return (boot->last_error);
135 }
136 break; /* end of case boot image hi/lo */
137
138 case TAG_CABSDATA:
139 DecryptBuf(boot, datlen); /* we need to encrypt the buffer */
140 case TAG_ABSDATA:
141 if (card->debug_flags & LOG_POF_RECORD)
142 hysdn_addlog(card, "POF got %s len=%d offs=0x%lx",
143 (boot->pof_recid == TAG_CABSDATA) ? "CABSDATA" : "ABSDATA",
144 datlen, boot->pof_recoffset);
145
146 if ((boot->last_error = card->writebootseq(card, boot->buf.BootBuf, datlen) < 0))
147 return (boot->last_error); /* error writing data */
148
149 if (boot->pof_recoffset + datlen >= boot->pof_reclen)
150 return (card->waitpofready(card)); /* data completely spooled, wait for ready */
151
152 break; /* end of case boot seq data */
153
154 default:
155 if (card->debug_flags & LOG_POF_RECORD)
156 hysdn_addlog(card, "POF got data(id=0x%lx) len=%d offs=0x%lx", boot->pof_recid,
157 datlen, boot->pof_recoffset);
158
159 break; /* simply skip record */
160 } /* switch boot->pof_recid */
161
162 return (0);
163} /* pof_handle_data */
164
165
166/******************************************************************************/
167/* pof_write_buffer is called when the buffer has been filled with the needed */
168/* number of data bytes. The number delivered is additionally supplied for */
169/* verification. The functions handles the data and returns the needed number */
170/* of bytes for the next action. If the returned value is 0 or less an error */
171/* occurred and booting must be aborted. */
172/******************************************************************************/
173int
174pof_write_buffer(hysdn_card * card, int datlen)
175{
176 struct boot_data *boot = card->boot; /* pointer to boot specific data */
177
178 if (!boot)
179 return (-EFAULT); /* invalid call */
180 if (boot->last_error < 0)
181 return (boot->last_error); /* repeated error */
182
183 if (card->debug_flags & LOG_POF_WRITE)
184 hysdn_addlog(card, "POF write: got %d bytes ", datlen);
185
186 switch (boot->pof_state) {
187 case POF_READ_FILE_HEAD:
188 if (card->debug_flags & LOG_POF_WRITE)
189 hysdn_addlog(card, "POF write: checking file header");
190
191 if (datlen != sizeof(tPofFileHdr)) {
192 boot->last_error = -EPOF_INTERNAL;
193 break;
194 }
195 if (boot->buf.PofFileHdr.Magic != TAGFILEMAGIC) {
196 boot->last_error = -EPOF_BAD_MAGIC;
197 break;
198 }
199 /* Setup the new state and vars */
200 boot->Nrecs = (word) (boot->buf.PofFileHdr.N_PofRecs); /* limited to 65535 */
201 boot->pof_state = POF_READ_TAG_HEAD; /* now start with single tags */
202 boot->last_error = sizeof(tPofRecHdr); /* new length */
203 break;
204
205 case POF_READ_TAG_HEAD:
206 if (card->debug_flags & LOG_POF_WRITE)
207 hysdn_addlog(card, "POF write: checking tag header");
208
209 if (datlen != sizeof(tPofRecHdr)) {
210 boot->last_error = -EPOF_INTERNAL;
211 break;
212 }
213 boot->pof_recid = boot->buf.PofRecHdr.PofRecId; /* actual pof recid */
214 boot->pof_reclen = boot->buf.PofRecHdr.PofRecDataLen; /* total length */
215 boot->pof_recoffset = 0; /* no starting offset */
216
217 if (card->debug_flags & LOG_POF_RECORD)
218 hysdn_addlog(card, "POF: got record id=0x%lx length=%ld ",
219 boot->pof_recid, boot->pof_reclen);
220
221 boot->pof_state = POF_READ_TAG_DATA; /* now start with tag data */
222 if (boot->pof_reclen < BOOT_BUF_SIZE)
223 boot->last_error = boot->pof_reclen; /* limit size */
224 else
225 boot->last_error = BOOT_BUF_SIZE; /* maximum */
226
227 if (!boot->last_error) { /* no data inside record */
228 boot->pof_state = POF_READ_TAG_HEAD; /* now start with single tags */
229 boot->last_error = sizeof(tPofRecHdr); /* new length */
230 }
231 break;
232
233 case POF_READ_TAG_DATA:
234 if (card->debug_flags & LOG_POF_WRITE)
235 hysdn_addlog(card, "POF write: getting tag data");
236
237 if (datlen != boot->last_error) {
238 boot->last_error = -EPOF_INTERNAL;
239 break;
240 }
241 if ((boot->last_error = pof_handle_data(card, datlen)) < 0)
242 return (boot->last_error); /* an error occurred */
243 boot->pof_recoffset += datlen;
244 if (boot->pof_recoffset >= boot->pof_reclen) {
245 boot->pof_state = POF_READ_TAG_HEAD; /* now start with single tags */
246 boot->last_error = sizeof(tPofRecHdr); /* new length */
247 } else {
248 if (boot->pof_reclen - boot->pof_recoffset < BOOT_BUF_SIZE)
249 boot->last_error = boot->pof_reclen - boot->pof_recoffset; /* limit size */
250 else
251 boot->last_error = BOOT_BUF_SIZE; /* maximum */
252 }
253 break;
254
255 default:
256 boot->last_error = -EPOF_INTERNAL; /* unknown state */
257 break;
258 } /* switch (boot->pof_state) */
259
260 return (boot->last_error);
261} /* pof_write_buffer */
262
263
264/*******************************************************************************/
265/* pof_write_open is called when an open for boot on the cardlog device occurs. */
266/* The function returns the needed number of bytes for the next operation. If */
267/* the returned number is less or equal 0 an error specified by this code */
268/* occurred. Additionally the pointer to the buffer data area is set on success */
269/*******************************************************************************/
270int
271pof_write_open(hysdn_card * card, uchar ** bufp)
272{
273 struct boot_data *boot; /* pointer to boot specific data */
274
275 if (card->boot) {
276 if (card->debug_flags & LOG_POF_OPEN)
277 hysdn_addlog(card, "POF open: already opened for boot");
278 return (-ERR_ALREADY_BOOT); /* boot already active */
279 }
280 /* error no mem available */
281 if (!(boot = kmalloc(sizeof(struct boot_data), GFP_KERNEL))) {
282 if (card->debug_flags & LOG_MEM_ERR)
283 hysdn_addlog(card, "POF open: unable to allocate mem");
284 return (-EFAULT);
285 }
286 card->boot = boot;
287 card->state = CARD_STATE_BOOTING;
288 memset(boot, 0, sizeof(struct boot_data));
289
290 card->stopcard(card); /* first stop the card */
291 if (card->testram(card)) {
292 if (card->debug_flags & LOG_POF_OPEN)
293 hysdn_addlog(card, "POF open: DPRAM test failure");
294 boot->last_error = -ERR_BOARD_DPRAM;
295 card->state = CARD_STATE_BOOTERR; /* show boot error */
296 return (boot->last_error);
297 }
298 boot->BufSize = 0; /* Buffer is empty */
299 boot->pof_state = POF_READ_FILE_HEAD; /* read file header */
300 StartDecryption(boot); /* if POF File should be encrypted */
301
302 if (card->debug_flags & LOG_POF_OPEN)
303 hysdn_addlog(card, "POF open: success");
304
305 *bufp = boot->buf.BootBuf; /* point to buffer */
306 return (sizeof(tPofFileHdr));
307} /* pof_write_open */
308
309/********************************************************************************/
310/* pof_write_close is called when an close of boot on the cardlog device occurs. */
311/* The return value must be 0 if everything has happened as desired. */
312/********************************************************************************/
313int
314pof_write_close(hysdn_card * card)
315{
316 struct boot_data *boot = card->boot; /* pointer to boot specific data */
317
318 if (!boot)
319 return (-EFAULT); /* invalid call */
320
321 card->boot = NULL; /* no boot active */
322 kfree(boot);
323
324 if (card->state == CARD_STATE_RUN)
325 card->set_errlog_state(card, 1); /* activate error log */
326
327 if (card->debug_flags & LOG_POF_OPEN)
328 hysdn_addlog(card, "POF close: success");
329
330 return (0);
331} /* pof_write_close */
332
333/*********************************************************************************/
334/* EvalSysrTokData checks additional records delivered with the Sysready Message */
335/* when POF has been booted. A return value of 0 is used if no error occurred. */
336/*********************************************************************************/
337int
338EvalSysrTokData(hysdn_card * card, uchar * cp, int len)
339{
340 u_char *p;
341 u_char crc;
342
343 if (card->debug_flags & LOG_POF_RECORD)
344 hysdn_addlog(card, "SysReady Token data length %d", len);
345
346 if (len < 2) {
347 hysdn_addlog(card, "SysReady Token Data to short");
348 return (1);
349 }
350 for (p = cp, crc = 0; p < (cp + len - 2); p++)
351 if ((crc & 0x80))
352 crc = (((u_char) (crc << 1)) + 1) + *p;
353 else
354 crc = ((u_char) (crc << 1)) + *p;
355 crc = ~crc;
356 if (crc != *(cp + len - 1)) {
357 hysdn_addlog(card, "SysReady Token Data invalid CRC");
358 return (1);
359 }
360 len--; /* don't check CRC byte */
361 while (len > 0) {
362
363 if (*cp == SYSR_TOK_END)
364 return (0); /* End of Token stream */
365
366 if (len < (*(cp + 1) + 2)) {
367 hysdn_addlog(card, "token 0x%x invalid length %d", *cp, *(cp + 1));
368 return (1);
369 }
370 switch (*cp) {
371 case SYSR_TOK_B_CHAN: /* 1 */
372 if (*(cp + 1) != 1)
373 return (1); /* length invalid */
374 card->bchans = *(cp + 2);
375 break;
376
377 case SYSR_TOK_FAX_CHAN: /* 2 */
378 if (*(cp + 1) != 1)
379 return (1); /* length invalid */
380 card->faxchans = *(cp + 2);
381 break;
382
383 case SYSR_TOK_MAC_ADDR: /* 3 */
384 if (*(cp + 1) != 6)
385 return (1); /* length invalid */
386 memcpy(card->mac_addr, cp + 2, 6);
387 break;
388
389 default:
390 hysdn_addlog(card, "unknown token 0x%02x length %d", *cp, *(cp + 1));
391 break;
392 }
393 len -= (*(cp + 1) + 2); /* adjust len */
394 cp += (*(cp + 1) + 2); /* and pointer */
395 }
396
397 hysdn_addlog(card, "no end token found");
398 return (1);
399} /* EvalSysrTokData */
diff --git a/drivers/isdn/hysdn/hysdn_defs.h b/drivers/isdn/hysdn/hysdn_defs.h
new file mode 100644
index 000000000000..4cee26e558ee
--- /dev/null
+++ b/drivers/isdn/hysdn/hysdn_defs.h
@@ -0,0 +1,298 @@
1/* $Id: hysdn_defs.h,v 1.5.6.3 2001/09/23 22:24:54 kai Exp $
2 *
3 * Linux driver for HYSDN cards
4 * global definitions and exported vars and functions.
5 *
6 * Author Werner Cornelius (werner@titro.de) for Hypercope GmbH
7 * Copyright 1999 by Werner Cornelius (werner@titro.de)
8 *
9 * This software may be used and distributed according to the terms
10 * of the GNU General Public License, incorporated herein by reference.
11 *
12 */
13
14#ifndef HYSDN_DEFS_H
15#define HYSDN_DEFS_H
16
17#include <linux/config.h>
18#include <linux/hysdn_if.h>
19#include <linux/interrupt.h>
20#include <linux/workqueue.h>
21#include <linux/skbuff.h>
22
23/****************************/
24/* storage type definitions */
25/****************************/
26#define uchar unsigned char
27#define uint unsigned int
28#define ulong unsigned long
29#define word unsigned short
30
31#include "ince1pc.h"
32
33#ifdef CONFIG_HYSDN_CAPI
34#include <linux/capi.h>
35#include <linux/isdn/capicmd.h>
36#include <linux/isdn/capiutil.h>
37#include <linux/isdn/capilli.h>
38
39/***************************/
40/* CAPI-Profile values. */
41/***************************/
42
43#define GLOBAL_OPTION_INTERNAL_CONTROLLER 0x0001
44#define GLOBAL_OPTION_EXTERNAL_CONTROLLER 0x0002
45#define GLOBAL_OPTION_HANDSET 0x0004
46#define GLOBAL_OPTION_DTMF 0x0008
47#define GLOBAL_OPTION_SUPPL_SERVICES 0x0010
48#define GLOBAL_OPTION_CHANNEL_ALLOCATION 0x0020
49#define GLOBAL_OPTION_B_CHANNEL_OPERATION 0x0040
50
51#define B1_PROT_64KBIT_HDLC 0x0001
52#define B1_PROT_64KBIT_TRANSPARENT 0x0002
53#define B1_PROT_V110_ASYNCH 0x0004
54#define B1_PROT_V110_SYNCH 0x0008
55#define B1_PROT_T30 0x0010
56#define B1_PROT_64KBIT_INV_HDLC 0x0020
57#define B1_PROT_56KBIT_TRANSPARENT 0x0040
58
59#define B2_PROT_ISO7776 0x0001
60#define B2_PROT_TRANSPARENT 0x0002
61#define B2_PROT_SDLC 0x0004
62#define B2_PROT_LAPD 0x0008
63#define B2_PROT_T30 0x0010
64#define B2_PROT_PPP 0x0020
65#define B2_PROT_TRANSPARENT_IGNORE_B1_FRAMING_ERRORS 0x0040
66
67#define B3_PROT_TRANSPARENT 0x0001
68#define B3_PROT_T90NL 0x0002
69#define B3_PROT_ISO8208 0x0004
70#define B3_PROT_X25_DCE 0x0008
71#define B3_PROT_T30 0x0010
72#define B3_PROT_T30EXT 0x0020
73
74#define HYSDN_MAXVERSION 8
75
76/* Number of sendbuffers in CAPI-queue */
77#define HYSDN_MAX_CAPI_SKB 20
78
79#endif /* CONFIG_HYSDN_CAPI*/
80
81/************************************************/
82/* constants and bits for debugging/log outputs */
83/************************************************/
84#define LOG_MAX_LINELEN 120
85#define DEB_OUT_SYSLOG 0x80000000 /* output to syslog instead of proc fs */
86#define LOG_MEM_ERR 0x00000001 /* log memory errors like kmalloc failure */
87#define LOG_POF_OPEN 0x00000010 /* log pof open and close activities */
88#define LOG_POF_RECORD 0x00000020 /* log pof record parser */
89#define LOG_POF_WRITE 0x00000040 /* log detailed pof write operation */
90#define LOG_POF_CARD 0x00000080 /* log pof related card functions */
91#define LOG_CNF_LINE 0x00000100 /* all conf lines are put to procfs */
92#define LOG_CNF_DATA 0x00000200 /* non comment conf lines are shown with channel */
93#define LOG_CNF_MISC 0x00000400 /* additional conf line debug outputs */
94#define LOG_SCHED_ASYN 0x00001000 /* debug schedulers async tx routines */
95#define LOG_PROC_OPEN 0x00100000 /* open and close from procfs are logged */
96#define LOG_PROC_ALL 0x00200000 /* all actions from procfs are logged */
97#define LOG_NET_INIT 0x00010000 /* network init and deinit logging */
98
99#define DEF_DEB_FLAGS 0x7fff000f /* everything is logged to procfs */
100
101/**********************************/
102/* proc filesystem name constants */
103/**********************************/
104#define PROC_SUBDIR_NAME "hysdn"
105#define PROC_CONF_BASENAME "cardconf"
106#define PROC_LOG_BASENAME "cardlog"
107
108/***********************************/
109/* PCI 32 bit parms for IO and MEM */
110/***********************************/
111#define PCI_REG_PLX_MEM_BASE 0
112#define PCI_REG_PLX_IO_BASE 1
113#define PCI_REG_MEMORY_BASE 3
114
115/**************/
116/* card types */
117/**************/
118#define BD_NONE 0U
119#define BD_PERFORMANCE 1U
120#define BD_VALUE 2U
121#define BD_PCCARD 3U
122#define BD_ERGO 4U
123#define BD_METRO 5U
124#define BD_CHAMP2 6U
125#define BD_PLEXUS 7U
126
127/******************************************************/
128/* defined states for cards shown by reading cardconf */
129/******************************************************/
130#define CARD_STATE_UNUSED 0 /* never been used or booted */
131#define CARD_STATE_BOOTING 1 /* booting is in progress */
132#define CARD_STATE_BOOTERR 2 /* a previous boot was aborted */
133#define CARD_STATE_RUN 3 /* card is active */
134
135/*******************************/
136/* defines for error_log_state */
137/*******************************/
138#define ERRLOG_STATE_OFF 0 /* error log is switched off, nothing to do */
139#define ERRLOG_STATE_ON 1 /* error log is switched on, wait for data */
140#define ERRLOG_STATE_START 2 /* start error logging */
141#define ERRLOG_STATE_STOP 3 /* stop error logging */
142
143/*******************************/
144/* data structure for one card */
145/*******************************/
146typedef struct HYSDN_CARD {
147
148 /* general variables for the cards */
149 int myid; /* own driver card id */
150 uchar bus; /* pci bus the card is connected to */
151 uchar devfn; /* slot+function bit encoded */
152 word subsysid; /* PCI subsystem id */
153 uchar brdtype; /* type of card */
154 uint bchans; /* number of available B-channels */
155 uint faxchans; /* number of available fax-channels */
156 uchar mac_addr[6]; /* MAC Address read from card */
157 uint irq; /* interrupt number */
158 uint iobase; /* IO-port base address */
159 ulong plxbase; /* PLX memory base */
160 ulong membase; /* DPRAM memory base */
161 ulong memend; /* DPRAM memory end */
162 void *dpram; /* mapped dpram */
163 int state; /* actual state of card -> CARD_STATE_** */
164 struct HYSDN_CARD *next; /* pointer to next card */
165
166 /* data areas for the /proc file system */
167 void *proclog; /* pointer to proclog filesystem specific data */
168 void *procconf; /* pointer to procconf filesystem specific data */
169
170 /* debugging and logging */
171 uchar err_log_state; /* actual error log state of the card */
172 ulong debug_flags; /* tells what should be debugged and where */
173 void (*set_errlog_state) (struct HYSDN_CARD *, int);
174
175 /* interrupt handler + interrupt synchronisation */
176 struct work_struct irq_queue; /* interrupt task queue */
177 uchar volatile irq_enabled; /* interrupt enabled if != 0 */
178 uchar volatile hw_lock; /* hardware is currently locked -> no access */
179
180 /* boot process */
181 void *boot; /* pointer to boot private data */
182 int (*writebootimg) (struct HYSDN_CARD *, uchar *, ulong);
183 int (*writebootseq) (struct HYSDN_CARD *, uchar *, int);
184 int (*waitpofready) (struct HYSDN_CARD *);
185 int (*testram) (struct HYSDN_CARD *);
186
187 /* scheduler for data transfer (only async parts) */
188 uchar async_data[256]; /* async data to be sent (normally for config) */
189 word volatile async_len; /* length of data to sent */
190 word volatile async_channel; /* channel number for async transfer */
191 int volatile async_busy; /* flag != 0 sending in progress */
192 int volatile net_tx_busy; /* a network packet tx is in progress */
193
194 /* network interface */
195 void *netif; /* pointer to network structure */
196
197 /* init and deinit stopcard for booting, too */
198 void (*stopcard) (struct HYSDN_CARD *);
199 void (*releasehardware) (struct HYSDN_CARD *);
200#ifdef CONFIG_HYSDN_CAPI
201 struct hycapictrl_info {
202 char cardname[32];
203 spinlock_t lock;
204 int versionlen;
205 char versionbuf[1024];
206 char *version[HYSDN_MAXVERSION];
207
208 char infobuf[128]; /* for function procinfo */
209
210 struct HYSDN_CARD *card;
211 struct capi_ctr capi_ctrl;
212 struct sk_buff *skbs[HYSDN_MAX_CAPI_SKB];
213 int in_idx, out_idx; /* indexes to buffer ring */
214 int sk_count; /* number of buffers currently in ring */
215 struct sk_buff *tx_skb; /* buffer for tx operation */
216
217 struct list_head ncci_head;
218 } *hyctrlinfo;
219#endif /* CONFIG_HYSDN_CAPI */
220} hysdn_card;
221
222#ifdef CONFIG_HYSDN_CAPI
223typedef struct hycapictrl_info hycapictrl_info;
224#endif /* CONFIG_HYSDN_CAPI */
225
226
227/*****************/
228/* exported vars */
229/*****************/
230extern int cardmax; /* number of found cards */
231extern hysdn_card *card_root; /* pointer to first card */
232
233
234
235/*************************/
236/* im/exported functions */
237/*************************/
238extern char *hysdn_getrev(const char *);
239
240/* hysdn_procconf.c */
241extern int hysdn_procconf_init(void); /* init proc config filesys */
242extern void hysdn_procconf_release(void); /* deinit proc config filesys */
243
244/* hysdn_proclog.c */
245extern int hysdn_proclog_init(hysdn_card *); /* init proc log entry */
246extern void hysdn_proclog_release(hysdn_card *); /* deinit proc log entry */
247extern void put_log_buffer(hysdn_card *, char *); /* output log data */
248extern void hysdn_addlog(hysdn_card *, char *,...); /* output data to log */
249extern void hysdn_card_errlog(hysdn_card *, tErrLogEntry *, int); /* output card log */
250
251/* boardergo.c */
252extern int ergo_inithardware(hysdn_card * card); /* get hardware -> module init */
253
254/* hysdn_boot.c */
255extern int pof_write_close(hysdn_card *); /* close proc file after writing pof */
256extern int pof_write_open(hysdn_card *, uchar **); /* open proc file for writing pof */
257extern int pof_write_buffer(hysdn_card *, int); /* write boot data to card */
258extern int EvalSysrTokData(hysdn_card *, uchar *, int); /* Check Sysready Token Data */
259
260/* hysdn_sched.c */
261extern int hysdn_sched_tx(hysdn_card *, uchar *, word volatile *, word volatile *,
262 word);
263extern int hysdn_sched_rx(hysdn_card *, uchar *, word, word);
264extern int hysdn_tx_cfgline(hysdn_card *, uchar *, word); /* send one cfg line */
265
266/* hysdn_net.c */
267extern unsigned int hynet_enable;
268extern char *hysdn_net_revision;
269extern int hysdn_net_create(hysdn_card *); /* create a new net device */
270extern int hysdn_net_release(hysdn_card *); /* delete the device */
271extern char *hysdn_net_getname(hysdn_card *); /* get name of net interface */
272extern void hysdn_tx_netack(hysdn_card *); /* acknowledge a packet tx */
273extern struct sk_buff *hysdn_tx_netget(hysdn_card *); /* get next network packet */
274extern void hysdn_rx_netpkt(hysdn_card *, uchar *, word); /* rxed packet from network */
275
276#ifdef CONFIG_HYSDN_CAPI
277extern unsigned int hycapi_enable;
278extern int hycapi_capi_create(hysdn_card *); /* create a new capi device */
279extern int hycapi_capi_release(hysdn_card *); /* delete the device */
280extern int hycapi_capi_stop(hysdn_card *card); /* suspend */
281extern int hycapi_load_firmware(struct capi_ctr *, capiloaddata *);
282extern void hycapi_reset_ctr(struct capi_ctr *);
283extern void hycapi_remove_ctr(struct capi_ctr *);
284extern void hycapi_register_appl(struct capi_ctr *, __u16 appl,
285 capi_register_params *);
286extern void hycapi_release_appl(struct capi_ctr *, __u16 appl);
287extern u16 hycapi_send_message(struct capi_ctr *, struct sk_buff *skb);
288extern char *hycapi_procinfo(struct capi_ctr *);
289extern int hycapi_read_proc(char *page, char **start, off_t off,
290 int count, int *eof, struct capi_ctr *card);
291extern void hycapi_rx_capipkt(hysdn_card * card, uchar * buf, word len);
292extern void hycapi_tx_capiack(hysdn_card * card);
293extern struct sk_buff *hycapi_tx_capiget(hysdn_card *card);
294extern int hycapi_init(void);
295extern void hycapi_cleanup(void);
296#endif /* CONFIG_HYSDN_CAPI */
297
298#endif /* HYSDN_DEFS_H */
diff --git a/drivers/isdn/hysdn/hysdn_init.c b/drivers/isdn/hysdn/hysdn_init.c
new file mode 100644
index 000000000000..5cac2bf5f4b0
--- /dev/null
+++ b/drivers/isdn/hysdn/hysdn_init.c
@@ -0,0 +1,254 @@
1/* $Id: hysdn_init.c,v 1.6.6.6 2001/09/23 22:24:54 kai Exp $
2 *
3 * Linux driver for HYSDN cards, init functions.
4 *
5 * Author Werner Cornelius (werner@titro.de) for Hypercope GmbH
6 * Copyright 1999 by Werner Cornelius (werner@titro.de)
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 */
12
13#include <linux/config.h>
14#include <linux/module.h>
15#include <linux/init.h>
16#include <linux/version.h>
17#include <linux/poll.h>
18#include <linux/vmalloc.h>
19#include <linux/slab.h>
20#include <linux/pci.h>
21
22#include "hysdn_defs.h"
23
24static struct pci_device_id hysdn_pci_tbl[] = {
25 {PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_METRO},
26 {PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2},
27 {PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_ERGO},
28 {PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_OLD_ERGO},
29 { } /* Terminating entry */
30};
31MODULE_DEVICE_TABLE(pci, hysdn_pci_tbl);
32MODULE_DESCRIPTION("ISDN4Linux: Driver for HYSDN cards");
33MODULE_AUTHOR("Werner Cornelius");
34MODULE_LICENSE("GPL");
35
36static char *hysdn_init_revision = "$Revision: 1.6.6.6 $";
37int cardmax; /* number of found cards */
38hysdn_card *card_root = NULL; /* pointer to first card */
39
40/**********************************************/
41/* table assigning PCI-sub ids to board types */
42/* the last entry contains all 0 */
43/**********************************************/
44static struct {
45 word subid; /* PCI sub id */
46 uchar cardtyp; /* card type assigned */
47} pci_subid_map[] = {
48
49 {
50 PCI_SUBDEVICE_ID_HYPERCOPE_METRO, BD_METRO
51 },
52 {
53 PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2, BD_CHAMP2
54 },
55 {
56 PCI_SUBDEVICE_ID_HYPERCOPE_ERGO, BD_ERGO
57 },
58 {
59 PCI_SUBDEVICE_ID_HYPERCOPE_OLD_ERGO, BD_ERGO
60 },
61 {
62 0, 0
63 } /* terminating entry */
64};
65
66
67/*********************************************************************/
68/* search_cards searches for available cards in the pci config data. */
69/* If a card is found, the card structure is allocated and the cards */
70/* ressources are reserved. cardmax is incremented. */
71/*********************************************************************/
72static void
73search_cards(void)
74{
75 struct pci_dev *akt_pcidev = NULL;
76 hysdn_card *card, *card_last;
77 int i;
78
79 card_root = NULL;
80 card_last = NULL;
81 while ((akt_pcidev = pci_find_device(PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX,
82 akt_pcidev)) != NULL) {
83 if (pci_enable_device(akt_pcidev))
84 continue;
85
86 if (!(card = kmalloc(sizeof(hysdn_card), GFP_KERNEL))) {
87 printk(KERN_ERR "HYSDN: unable to alloc device mem \n");
88 return;
89 }
90 memset(card, 0, sizeof(hysdn_card));
91 card->myid = cardmax; /* set own id */
92 card->bus = akt_pcidev->bus->number;
93 card->devfn = akt_pcidev->devfn; /* slot + function */
94 card->subsysid = akt_pcidev->subsystem_device;
95 card->irq = akt_pcidev->irq;
96 card->iobase = pci_resource_start(akt_pcidev, PCI_REG_PLX_IO_BASE);
97 card->plxbase = pci_resource_start(akt_pcidev, PCI_REG_PLX_MEM_BASE);
98 card->membase = pci_resource_start(akt_pcidev, PCI_REG_MEMORY_BASE);
99 card->brdtype = BD_NONE; /* unknown */
100 card->debug_flags = DEF_DEB_FLAGS; /* set default debug */
101 card->faxchans = 0; /* default no fax channels */
102 card->bchans = 2; /* and 2 b-channels */
103 for (i = 0; pci_subid_map[i].subid; i++)
104 if (pci_subid_map[i].subid == card->subsysid) {
105 card->brdtype = pci_subid_map[i].cardtyp;
106 break;
107 }
108 if (card->brdtype != BD_NONE) {
109 if (ergo_inithardware(card)) {
110 printk(KERN_WARNING "HYSDN: card at io 0x%04x already in use\n", card->iobase);
111 kfree(card);
112 continue;
113 }
114 } else {
115 printk(KERN_WARNING "HYSDN: unknown card id 0x%04x\n", card->subsysid);
116 kfree(card); /* release mem */
117 continue;
118 }
119 cardmax++;
120 card->next = NULL; /*end of chain */
121 if (card_last)
122 card_last->next = card; /* pointer to next card */
123 else
124 card_root = card;
125 card_last = card; /* new chain end */
126 } /* device found */
127} /* search_cards */
128
129/************************************************************************************/
130/* free_resources frees the acquired PCI resources and returns the allocated memory */
131/************************************************************************************/
132static void
133free_resources(void)
134{
135 hysdn_card *card;
136
137 while (card_root) {
138 card = card_root;
139 if (card->releasehardware)
140 card->releasehardware(card); /* free all hardware resources */
141 card_root = card_root->next; /* remove card from chain */
142 kfree(card); /* return mem */
143
144 } /* while card_root */
145} /* free_resources */
146
147/**************************************************************************/
148/* stop_cards disables (hardware resets) all cards and disables interrupt */
149/**************************************************************************/
150static void
151stop_cards(void)
152{
153 hysdn_card *card;
154
155 card = card_root; /* first in chain */
156 while (card) {
157 if (card->stopcard)
158 card->stopcard(card);
159 card = card->next; /* remove card from chain */
160 } /* while card */
161} /* stop_cards */
162
163
164/****************************************************************************/
165/* The module startup and shutdown code. Only compiled when used as module. */
166/* Using the driver as module is always advisable, because the booting */
167/* image becomes smaller and the driver code is only loaded when needed. */
168/* Additionally newer versions may be activated without rebooting. */
169/****************************************************************************/
170
171/******************************************************/
172/* extract revision number from string for log output */
173/******************************************************/
174char *
175hysdn_getrev(const char *revision)
176{
177 char *rev;
178 char *p;
179
180 if ((p = strchr(revision, ':'))) {
181 rev = p + 2;
182 p = strchr(rev, '$');
183 *--p = 0;
184 } else
185 rev = "???";
186 return rev;
187}
188
189
190/****************************************************************************/
191/* init_module is called once when the module is loaded to do all necessary */
192/* things like autodetect... */
193/* If the return value of this function is 0 the init has been successful */
194/* and the module is added to the list in /proc/modules, otherwise an error */
195/* is assumed and the module will not be kept in memory. */
196/****************************************************************************/
197static int __init
198hysdn_init(void)
199{
200 char tmp[50];
201
202 strcpy(tmp, hysdn_init_revision);
203 printk(KERN_NOTICE "HYSDN: module Rev: %s loaded\n", hysdn_getrev(tmp));
204 strcpy(tmp, hysdn_net_revision);
205 printk(KERN_NOTICE "HYSDN: network interface Rev: %s \n", hysdn_getrev(tmp));
206 search_cards();
207 printk(KERN_INFO "HYSDN: %d card(s) found.\n", cardmax);
208
209 if (hysdn_procconf_init()) {
210 free_resources(); /* proc file_sys not created */
211 return (-1);
212 }
213#ifdef CONFIG_HYSDN_CAPI
214 if(cardmax > 0) {
215 if(hycapi_init()) {
216 printk(KERN_ERR "HYCAPI: init failed\n");
217 return(-1);
218 }
219 }
220#endif /* CONFIG_HYSDN_CAPI */
221 return (0); /* no error */
222} /* init_module */
223
224
225/***********************************************************************/
226/* cleanup_module is called when the module is released by the kernel. */
227/* The routine is only called if init_module has been successful and */
228/* the module counter has a value of 0. Otherwise this function will */
229/* not be called. This function must release all resources still allo- */
230/* cated as after the return from this function the module code will */
231/* be removed from memory. */
232/***********************************************************************/
233static void __exit
234hysdn_exit(void)
235{
236#ifdef CONFIG_HYSDN_CAPI
237 hysdn_card *card;
238#endif /* CONFIG_HYSDN_CAPI */
239 stop_cards();
240#ifdef CONFIG_HYSDN_CAPI
241 card = card_root; /* first in chain */
242 while (card) {
243 hycapi_capi_release(card);
244 card = card->next; /* remove card from chain */
245 } /* while card */
246 hycapi_cleanup();
247#endif /* CONFIG_HYSDN_CAPI */
248 hysdn_procconf_release();
249 free_resources();
250 printk(KERN_NOTICE "HYSDN: module unloaded\n");
251} /* cleanup_module */
252
253module_init(hysdn_init);
254module_exit(hysdn_exit);
diff --git a/drivers/isdn/hysdn/hysdn_net.c b/drivers/isdn/hysdn/hysdn_net.c
new file mode 100644
index 000000000000..babec8157ae6
--- /dev/null
+++ b/drivers/isdn/hysdn/hysdn_net.c
@@ -0,0 +1,348 @@
1/* $Id: hysdn_net.c,v 1.8.6.4 2001/09/23 22:24:54 kai Exp $
2 *
3 * Linux driver for HYSDN cards, net (ethernet type) handling routines.
4 *
5 * Author Werner Cornelius (werner@titro.de) for Hypercope GmbH
6 * Copyright 1999 by Werner Cornelius (werner@titro.de)
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 * This net module has been inspired by the skeleton driver from
12 * Donald Becker (becker@CESDIS.gsfc.nasa.gov)
13 *
14 */
15
16#include <linux/module.h>
17#include <linux/version.h>
18#include <linux/signal.h>
19#include <linux/kernel.h>
20#include <linux/netdevice.h>
21#include <linux/etherdevice.h>
22#include <linux/skbuff.h>
23#include <linux/inetdevice.h>
24
25#include "hysdn_defs.h"
26
27unsigned int hynet_enable = 0xffffffff;
28MODULE_PARM(hynet_enable, "i");
29
30/* store the actual version for log reporting */
31char *hysdn_net_revision = "$Revision: 1.8.6.4 $";
32
33#define MAX_SKB_BUFFERS 20 /* number of buffers for keeping TX-data */
34
35/****************************************************************************/
36/* structure containing the complete network data. The structure is aligned */
37/* in a way that both, the device and statistics are kept inside it. */
38/* for proper access, the device structure MUST be the first var/struct */
39/* inside the definition. */
40/****************************************************************************/
41struct net_local {
42 struct net_device netdev; /* the network device */
43 struct net_device_stats stats;
44 /* additional vars may be added here */
45 char dev_name[9]; /* our own device name */
46
47 /* Tx control lock. This protects the transmit buffer ring
48 * state along with the "tx full" state of the driver. This
49 * means all netif_queue flow control actions are protected
50 * by this lock as well.
51 */
52 spinlock_t lock;
53 struct sk_buff *skbs[MAX_SKB_BUFFERS]; /* pointers to tx-skbs */
54 int in_idx, out_idx; /* indexes to buffer ring */
55 int sk_count; /* number of buffers currently in ring */
56}; /* net_local */
57
58
59/*****************************************************/
60/* Get the current statistics for this card. */
61/* This may be called with the card open or closed ! */
62/*****************************************************/
63static struct net_device_stats *
64net_get_stats(struct net_device *dev)
65{
66 return (&((struct net_local *) dev)->stats);
67} /* net_device_stats */
68
69/*********************************************************************/
70/* Open/initialize the board. This is called (in the current kernel) */
71/* sometime after booting when the 'ifconfig' program is run. */
72/* This routine should set everything up anew at each open, even */
73/* registers that "should" only need to be set once at boot, so that */
74/* there is non-reboot way to recover if something goes wrong. */
75/*********************************************************************/
76static int
77net_open(struct net_device *dev)
78{
79 struct in_device *in_dev;
80 hysdn_card *card = dev->priv;
81 int i;
82
83 netif_start_queue(dev); /* start tx-queueing */
84
85 /* Fill in the MAC-level header (if not already set) */
86 if (!card->mac_addr[0]) {
87 for (i = 0; i < ETH_ALEN - sizeof(ulong); i++)
88 dev->dev_addr[i] = 0xfc;
89 if ((in_dev = dev->ip_ptr) != NULL) {
90 struct in_ifaddr *ifa = in_dev->ifa_list;
91 if (ifa != NULL)
92 memcpy(dev->dev_addr + (ETH_ALEN - sizeof(ulong)), &ifa->ifa_local, sizeof(ulong));
93 }
94 } else
95 memcpy(dev->dev_addr, card->mac_addr, ETH_ALEN);
96
97 return (0);
98} /* net_open */
99
100/*******************************************/
101/* flush the currently occupied tx-buffers */
102/* must only be called when device closed */
103/*******************************************/
104static void
105flush_tx_buffers(struct net_local *nl)
106{
107
108 while (nl->sk_count) {
109 dev_kfree_skb(nl->skbs[nl->out_idx++]); /* free skb */
110 if (nl->out_idx >= MAX_SKB_BUFFERS)
111 nl->out_idx = 0; /* wrap around */
112 nl->sk_count--;
113 }
114} /* flush_tx_buffers */
115
116
117/*********************************************************************/
118/* close/decativate the device. The device is not removed, but only */
119/* deactivated. */
120/*********************************************************************/
121static int
122net_close(struct net_device *dev)
123{
124
125 netif_stop_queue(dev); /* disable queueing */
126
127 flush_tx_buffers((struct net_local *) dev);
128
129 return (0); /* success */
130} /* net_close */
131
132/************************************/
133/* send a packet on this interface. */
134/* new style for kernel >= 2.3.33 */
135/************************************/
136static int
137net_send_packet(struct sk_buff *skb, struct net_device *dev)
138{
139 struct net_local *lp = (struct net_local *) dev;
140
141 spin_lock_irq(&lp->lock);
142
143 lp->skbs[lp->in_idx++] = skb; /* add to buffer list */
144 if (lp->in_idx >= MAX_SKB_BUFFERS)
145 lp->in_idx = 0; /* wrap around */
146 lp->sk_count++; /* adjust counter */
147 dev->trans_start = jiffies;
148
149 /* If we just used up the very last entry in the
150 * TX ring on this device, tell the queueing
151 * layer to send no more.
152 */
153 if (lp->sk_count >= MAX_SKB_BUFFERS)
154 netif_stop_queue(dev);
155
156 /* When the TX completion hw interrupt arrives, this
157 * is when the transmit statistics are updated.
158 */
159
160 spin_unlock_irq(&lp->lock);
161
162 if (lp->sk_count <= 3) {
163 schedule_work(&((hysdn_card *) dev->priv)->irq_queue);
164 }
165 return (0); /* success */
166} /* net_send_packet */
167
168
169
170/***********************************************************************/
171/* acknowlegde a packet send. The network layer will be informed about */
172/* completion */
173/***********************************************************************/
174void
175hysdn_tx_netack(hysdn_card * card)
176{
177 struct net_local *lp = card->netif;
178
179 if (!lp)
180 return; /* non existing device */
181
182
183 if (!lp->sk_count)
184 return; /* error condition */
185
186 lp->stats.tx_packets++;
187 lp->stats.tx_bytes += lp->skbs[lp->out_idx]->len;
188
189 dev_kfree_skb(lp->skbs[lp->out_idx++]); /* free skb */
190 if (lp->out_idx >= MAX_SKB_BUFFERS)
191 lp->out_idx = 0; /* wrap around */
192
193 if (lp->sk_count-- == MAX_SKB_BUFFERS) /* dec usage count */
194 netif_start_queue((struct net_device *) lp);
195} /* hysdn_tx_netack */
196
197/*****************************************************/
198/* we got a packet from the network, go and queue it */
199/*****************************************************/
200void
201hysdn_rx_netpkt(hysdn_card * card, uchar * buf, word len)
202{
203 struct net_local *lp = card->netif;
204 struct sk_buff *skb;
205
206 if (!lp)
207 return; /* non existing device */
208
209 lp->stats.rx_bytes += len;
210
211 skb = dev_alloc_skb(len);
212 if (skb == NULL) {
213 printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n",
214 lp->netdev.name);
215 lp->stats.rx_dropped++;
216 return;
217 }
218 skb->dev = &lp->netdev;
219
220 /* copy the data */
221 memcpy(skb_put(skb, len), buf, len);
222
223 /* determine the used protocol */
224 skb->protocol = eth_type_trans(skb, &lp->netdev);
225
226 netif_rx(skb);
227 lp->stats.rx_packets++; /* adjust packet count */
228
229} /* hysdn_rx_netpkt */
230
231/*****************************************************/
232/* return the pointer to a network packet to be send */
233/*****************************************************/
234struct sk_buff *
235hysdn_tx_netget(hysdn_card * card)
236{
237 struct net_local *lp = card->netif;
238
239 if (!lp)
240 return (NULL); /* non existing device */
241
242 if (!lp->sk_count)
243 return (NULL); /* nothing available */
244
245 return (lp->skbs[lp->out_idx]); /* next packet to send */
246} /* hysdn_tx_netget */
247
248
249/*******************************************/
250/* init function called by register device */
251/*******************************************/
252static int
253net_init(struct net_device *dev)
254{
255 /* setup the function table */
256 dev->open = net_open;
257 dev->stop = net_close;
258 dev->hard_start_xmit = net_send_packet;
259 dev->get_stats = net_get_stats;
260
261 /* Fill in the fields of the device structure with ethernet values. */
262 ether_setup(dev);
263
264 return (0); /* success */
265} /* net_init */
266
267/*****************************************************************************/
268/* hysdn_net_create creates a new net device for the given card. If a device */
269/* already exists, it will be deleted and created a new one. The return value */
270/* 0 announces success, else a negative error code will be returned. */
271/*****************************************************************************/
272int
273hysdn_net_create(hysdn_card * card)
274{
275 struct net_device *dev;
276 int i;
277 if(!card) {
278 printk(KERN_WARNING "No card-pt in hysdn_net_create!\n");
279 return (-ENOMEM);
280 }
281 hysdn_net_release(card); /* release an existing net device */
282 if ((dev = kmalloc(sizeof(struct net_local), GFP_KERNEL)) == NULL) {
283 printk(KERN_WARNING "HYSDN: unable to allocate mem\n");
284 return (-ENOMEM);
285 }
286 memset(dev, 0, sizeof(struct net_local)); /* clean the structure */
287
288 spin_lock_init(&((struct net_local *) dev)->lock);
289
290 /* initialise necessary or informing fields */
291 dev->base_addr = card->iobase; /* IO address */
292 dev->irq = card->irq; /* irq */
293 dev->init = net_init; /* the init function of the device */
294 if(dev->name) {
295 strcpy(dev->name, ((struct net_local *) dev)->dev_name);
296 }
297 if ((i = register_netdev(dev))) {
298 printk(KERN_WARNING "HYSDN: unable to create network device\n");
299 kfree(dev);
300 return (i);
301 }
302 dev->priv = card; /* remember pointer to own data structure */
303 card->netif = dev; /* setup the local pointer */
304
305 if (card->debug_flags & LOG_NET_INIT)
306 hysdn_addlog(card, "network device created");
307 return (0); /* and return success */
308} /* hysdn_net_create */
309
310/***************************************************************************/
311/* hysdn_net_release deletes the net device for the given card. The return */
312/* value 0 announces success, else a negative error code will be returned. */
313/***************************************************************************/
314int
315hysdn_net_release(hysdn_card * card)
316{
317 struct net_device *dev = card->netif;
318
319 if (!dev)
320 return (0); /* non existing */
321
322 card->netif = NULL; /* clear out pointer */
323 dev->stop(dev); /* close the device */
324
325 flush_tx_buffers((struct net_local *) dev); /* empty buffers */
326
327 unregister_netdev(dev); /* release the device */
328 free_netdev(dev); /* release the memory allocated */
329 if (card->debug_flags & LOG_NET_INIT)
330 hysdn_addlog(card, "network device deleted");
331
332 return (0); /* always successful */
333} /* hysdn_net_release */
334
335/*****************************************************************************/
336/* hysdn_net_getname returns a pointer to the name of the network interface. */
337/* if the interface is not existing, a "-" is returned. */
338/*****************************************************************************/
339char *
340hysdn_net_getname(hysdn_card * card)
341{
342 struct net_device *dev = card->netif;
343
344 if (!dev)
345 return ("-"); /* non existing */
346
347 return (dev->name);
348} /* hysdn_net_getname */
diff --git a/drivers/isdn/hysdn/hysdn_pof.h b/drivers/isdn/hysdn/hysdn_pof.h
new file mode 100644
index 000000000000..6cd81b9b08bc
--- /dev/null
+++ b/drivers/isdn/hysdn/hysdn_pof.h
@@ -0,0 +1,78 @@
1/* $Id: hysdn_pof.h,v 1.2.6.1 2001/09/23 22:24:54 kai Exp $
2 *
3 * Linux driver for HYSDN cards, definitions used for handling pof-files.
4 *
5 * Author Werner Cornelius (werner@titro.de) for Hypercope GmbH
6 * Copyright 1999 by Werner Cornelius (werner@titro.de)
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 */
12
13/************************/
14/* POF specific defines */
15/************************/
16#define BOOT_BUF_SIZE 0x1000 /* =4096, maybe moved to other h file */
17#define CRYPT_FEEDTERM 0x8142
18#define CRYPT_STARTTERM 0x81a5
19 /* max. timeout time in seconds
20 * from end of booting to POF is ready
21 */
22#define POF_READY_TIME_OUT_SEC 10
23
24/**********************************/
25/* defines for 1.stage boot image */
26/**********************************/
27
28/* the POF file record containing the boot loader image
29 * has 2 pages a 16KB:
30 * 1. page contains the high 16-bit part of the 32-bit E1 words
31 * 2. page contains the low 16-bit part of the 32-bit E1 words
32 *
33 * In each 16KB page we assume the start of the boot loader code
34 * in the highest 2KB part (at offset 0x3800);
35 * the rest (0x0000..0x37FF) is assumed to contain 0 bytes.
36 */
37
38#define POF_BOOT_LOADER_PAGE_SIZE 0x4000 /* =16384U */
39#define POF_BOOT_LOADER_TOTAL_SIZE (2U*POF_BOOT_LOADER_PAGE_SIZE)
40
41#define POF_BOOT_LOADER_CODE_SIZE 0x0800 /* =2KB =2048U */
42
43 /* offset in boot page, where loader code may start */
44 /* =0x3800= 14336U */
45#define POF_BOOT_LOADER_OFF_IN_PAGE (POF_BOOT_LOADER_PAGE_SIZE-POF_BOOT_LOADER_CODE_SIZE)
46
47
48/*--------------------------------------POF file record structs------------*/
49typedef struct PofFileHdr_tag { /* Pof file header */
50/*00 */ ulong Magic __attribute__((packed));
51/*04 */ ulong N_PofRecs __attribute__((packed));
52/*08 */
53} tPofFileHdr;
54
55typedef struct PofRecHdr_tag { /* Pof record header */
56/*00 */ word PofRecId __attribute__((packed));
57/*02 */ ulong PofRecDataLen __attribute__((packed));
58/*06 */
59} tPofRecHdr;
60
61typedef struct PofTimeStamp_tag {
62/*00 */ ulong UnixTime __attribute__((packed));
63 /*04 */ uchar DateTimeText[0x28] __attribute__((packed));
64 /* =40 */
65/*2C */
66} tPofTimeStamp;
67
68 /* tPofFileHdr.Magic value: */
69#define TAGFILEMAGIC 0x464F501AUL
70 /* tPofRecHdr.PofRecId values: */
71#define TAG_ABSDATA 0x1000 /* abs. data */
72#define TAG_BOOTDTA 0x1001 /* boot data */
73#define TAG_COMMENT 0x0020
74#define TAG_SYSCALL 0x0021
75#define TAG_FLOWCTRL 0x0022
76#define TAG_TIMESTMP 0x0010 /* date/time stamp of version */
77#define TAG_CABSDATA 0x1100 /* crypted abs. data */
78#define TAG_CBOOTDTA 0x1101 /* crypted boot data */
diff --git a/drivers/isdn/hysdn/hysdn_procconf.c b/drivers/isdn/hysdn/hysdn_procconf.c
new file mode 100644
index 000000000000..5da507e532fc
--- /dev/null
+++ b/drivers/isdn/hysdn/hysdn_procconf.c
@@ -0,0 +1,443 @@
1/* $Id: hysdn_procconf.c,v 1.8.6.4 2001/09/23 22:24:54 kai Exp $
2 *
3 * Linux driver for HYSDN cards, /proc/net filesystem dir and conf functions.
4 *
5 * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
6 *
7 * Copyright 1999 by Werner Cornelius (werner@titro.de)
8 *
9 * This software may be used and distributed according to the terms
10 * of the GNU General Public License, incorporated herein by reference.
11 *
12 */
13
14#include <linux/module.h>
15#include <linux/version.h>
16#include <linux/poll.h>
17#include <linux/proc_fs.h>
18#include <linux/pci.h>
19#include <linux/smp_lock.h>
20
21#include "hysdn_defs.h"
22
23static char *hysdn_procconf_revision = "$Revision: 1.8.6.4 $";
24
25#define INFO_OUT_LEN 80 /* length of info line including lf */
26
27/********************************************************/
28/* defines and data structure for conf write operations */
29/********************************************************/
30#define CONF_STATE_DETECT 0 /* waiting for detect */
31#define CONF_STATE_CONF 1 /* writing config data */
32#define CONF_STATE_POF 2 /* writing pof data */
33#define CONF_LINE_LEN 255 /* 255 chars max */
34
35struct conf_writedata {
36 hysdn_card *card; /* card the device is connected to */
37 int buf_size; /* actual number of bytes in the buffer */
38 int needed_size; /* needed size when reading pof */
39 int state; /* actual interface states from above constants */
40 uchar conf_line[CONF_LINE_LEN]; /* buffered conf line */
41 word channel; /* active channel number */
42 uchar *pof_buffer; /* buffer when writing pof */
43};
44
45/***********************************************************************/
46/* process_line parses one config line and transfers it to the card if */
47/* necessary. */
48/* if the return value is negative an error occurred. */
49/***********************************************************************/
50static int
51process_line(struct conf_writedata *cnf)
52{
53 uchar *cp = cnf->conf_line;
54 int i;
55
56 if (cnf->card->debug_flags & LOG_CNF_LINE)
57 hysdn_addlog(cnf->card, "conf line: %s", cp);
58
59 if (*cp == '-') { /* option */
60 cp++; /* point to option char */
61
62 if (*cp++ != 'c')
63 return (0); /* option unknown or used */
64 i = 0; /* start value for channel */
65 while ((*cp <= '9') && (*cp >= '0'))
66 i = i * 10 + *cp++ - '0'; /* get decimal number */
67 if (i > 65535) {
68 if (cnf->card->debug_flags & LOG_CNF_MISC)
69 hysdn_addlog(cnf->card, "conf channel invalid %d", i);
70 return (-ERR_INV_CHAN); /* invalid channel */
71 }
72 cnf->channel = i & 0xFFFF; /* set new channel number */
73 return (0); /* success */
74 } /* option */
75 if (*cp == '*') { /* line to send */
76 if (cnf->card->debug_flags & LOG_CNF_DATA)
77 hysdn_addlog(cnf->card, "conf chan=%d %s", cnf->channel, cp);
78 return (hysdn_tx_cfgline(cnf->card, cnf->conf_line + 1,
79 cnf->channel)); /* send the line without * */
80 } /* line to send */
81 return (0);
82} /* process_line */
83
84/***********************************/
85/* conf file operations and tables */
86/***********************************/
87
88/****************************************************/
89/* write conf file -> boot or send cfg line to card */
90/****************************************************/
91static ssize_t
92hysdn_conf_write(struct file *file, const char __user *buf, size_t count, loff_t * off)
93{
94 struct conf_writedata *cnf;
95 int i;
96 uchar ch, *cp;
97
98 if (!count)
99 return (0); /* nothing to handle */
100
101 if (!(cnf = file->private_data))
102 return (-EFAULT); /* should never happen */
103
104 if (cnf->state == CONF_STATE_DETECT) { /* auto detect cnf or pof data */
105 if (copy_from_user(&ch, buf, 1)) /* get first char for detect */
106 return (-EFAULT);
107
108 if (ch == 0x1A) {
109 /* we detected a pof file */
110 if ((cnf->needed_size = pof_write_open(cnf->card, &cnf->pof_buffer)) <= 0)
111 return (cnf->needed_size); /* an error occurred -> exit */
112 cnf->buf_size = 0; /* buffer is empty */
113 cnf->state = CONF_STATE_POF; /* new state */
114 } else {
115 /* conf data has been detected */
116 cnf->buf_size = 0; /* buffer is empty */
117 cnf->state = CONF_STATE_CONF; /* requested conf data write */
118 if (cnf->card->state != CARD_STATE_RUN)
119 return (-ERR_NOT_BOOTED);
120 cnf->conf_line[CONF_LINE_LEN - 1] = 0; /* limit string length */
121 cnf->channel = 4098; /* default channel for output */
122 }
123 } /* state was auto detect */
124 if (cnf->state == CONF_STATE_POF) { /* pof write active */
125 i = cnf->needed_size - cnf->buf_size; /* bytes still missing for write */
126 if (i <= 0)
127 return (-EINVAL); /* size error handling pof */
128
129 if (i < count)
130 count = i; /* limit requested number of bytes */
131 if (copy_from_user(cnf->pof_buffer + cnf->buf_size, buf, count))
132 return (-EFAULT); /* error while copying */
133 cnf->buf_size += count;
134
135 if (cnf->needed_size == cnf->buf_size) {
136 cnf->needed_size = pof_write_buffer(cnf->card, cnf->buf_size); /* write data */
137 if (cnf->needed_size <= 0) {
138 cnf->card->state = CARD_STATE_BOOTERR; /* show boot error */
139 return (cnf->needed_size); /* an error occurred */
140 }
141 cnf->buf_size = 0; /* buffer is empty again */
142 }
143 }
144 /* pof write active */
145 else { /* conf write active */
146
147 if (cnf->card->state != CARD_STATE_RUN) {
148 if (cnf->card->debug_flags & LOG_CNF_MISC)
149 hysdn_addlog(cnf->card, "cnf write denied -> not booted");
150 return (-ERR_NOT_BOOTED);
151 }
152 i = (CONF_LINE_LEN - 1) - cnf->buf_size; /* bytes available in buffer */
153 if (i > 0) {
154 /* copy remaining bytes into buffer */
155
156 if (count > i)
157 count = i; /* limit transfer */
158 if (copy_from_user(cnf->conf_line + cnf->buf_size, buf, count))
159 return (-EFAULT); /* error while copying */
160
161 i = count; /* number of chars in buffer */
162 cp = cnf->conf_line + cnf->buf_size;
163 while (i) {
164 /* search for end of line */
165 if ((*cp < ' ') && (*cp != 9))
166 break; /* end of line found */
167 cp++;
168 i--;
169 } /* search for end of line */
170
171 if (i) {
172 /* delimiter found */
173 *cp++ = 0; /* string termination */
174 count -= (i - 1); /* subtract remaining bytes from count */
175 while ((i) && (*cp < ' ') && (*cp != 9)) {
176 i--; /* discard next char */
177 count++; /* mark as read */
178 cp++; /* next char */
179 }
180 cnf->buf_size = 0; /* buffer is empty after transfer */
181 if ((i = process_line(cnf)) < 0) /* handle the line */
182 count = i; /* return the error */
183 }
184 /* delimiter found */
185 else {
186 cnf->buf_size += count; /* add chars to string */
187 if (cnf->buf_size >= CONF_LINE_LEN - 1) {
188 if (cnf->card->debug_flags & LOG_CNF_MISC)
189 hysdn_addlog(cnf->card, "cnf line too long %d chars pos %d", cnf->buf_size, count);
190 return (-ERR_CONF_LONG);
191 }
192 } /* not delimited */
193
194 }
195 /* copy remaining bytes into buffer */
196 else {
197 if (cnf->card->debug_flags & LOG_CNF_MISC)
198 hysdn_addlog(cnf->card, "cnf line too long");
199 return (-ERR_CONF_LONG);
200 }
201 } /* conf write active */
202
203 return (count);
204} /* hysdn_conf_write */
205
206/*******************************************/
207/* read conf file -> output card info data */
208/*******************************************/
209static ssize_t
210hysdn_conf_read(struct file *file, char __user *buf, size_t count, loff_t * off)
211{
212 char *cp;
213 int i;
214
215 if (file->f_mode & FMODE_READ) {
216 if (!(cp = file->private_data))
217 return (-EFAULT); /* should never happen */
218 i = strlen(cp); /* get total string length */
219 if (*off < i) {
220 /* still bytes to transfer */
221 cp += *off; /* point to desired data offset */
222 i -= *off; /* remaining length */
223 if (i > count)
224 i = count; /* limit length to transfer */
225 if (copy_to_user(buf, cp, i))
226 return (-EFAULT); /* copy error */
227 *off += i; /* adjust offset */
228 } else
229 return (0);
230 } else
231 return (-EPERM); /* no permission to read */
232
233 return (i);
234} /* hysdn_conf_read */
235
236/******************/
237/* open conf file */
238/******************/
239static int
240hysdn_conf_open(struct inode *ino, struct file *filep)
241{
242 hysdn_card *card;
243 struct proc_dir_entry *pd;
244 struct conf_writedata *cnf;
245 char *cp, *tmp;
246
247 /* now search the addressed card */
248 lock_kernel();
249 card = card_root;
250 while (card) {
251 pd = card->procconf;
252 if (pd == PDE(ino))
253 break;
254 card = card->next; /* search next entry */
255 }
256 if (!card) {
257 unlock_kernel();
258 return (-ENODEV); /* device is unknown/invalid */
259 }
260 if (card->debug_flags & (LOG_PROC_OPEN | LOG_PROC_ALL))
261 hysdn_addlog(card, "config open for uid=%d gid=%d mode=0x%x",
262 filep->f_uid, filep->f_gid, filep->f_mode);
263
264 if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) {
265 /* write only access -> write boot file or conf line */
266
267 if (!(cnf = kmalloc(sizeof(struct conf_writedata), GFP_KERNEL))) {
268 unlock_kernel();
269 return (-EFAULT);
270 }
271 cnf->card = card;
272 cnf->buf_size = 0; /* nothing buffered */
273 cnf->state = CONF_STATE_DETECT; /* start auto detect */
274 filep->private_data = cnf;
275
276 } else if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) {
277 /* read access -> output card info data */
278
279 if (!(tmp = (char *) kmalloc(INFO_OUT_LEN * 2 + 2, GFP_KERNEL))) {
280 unlock_kernel();
281 return (-EFAULT); /* out of memory */
282 }
283 filep->private_data = tmp; /* start of string */
284
285 /* first output a headline */
286 sprintf(tmp, "id bus slot type irq iobase dp-mem b-chans fax-chans state device");
287 cp = tmp; /* start of string */
288 while (*cp)
289 cp++;
290 while (((cp - tmp) % (INFO_OUT_LEN + 1)) != INFO_OUT_LEN)
291 *cp++ = ' ';
292 *cp++ = '\n';
293
294 /* and now the data */
295 sprintf(cp, "%d %3d %4d %4d %3d 0x%04x 0x%08lx %7d %9d %3d %s",
296 card->myid,
297 card->bus,
298 PCI_SLOT(card->devfn),
299 card->brdtype,
300 card->irq,
301 card->iobase,
302 card->membase,
303 card->bchans,
304 card->faxchans,
305 card->state,
306 hysdn_net_getname(card));
307 while (*cp)
308 cp++;
309 while (((cp - tmp) % (INFO_OUT_LEN + 1)) != INFO_OUT_LEN)
310 *cp++ = ' ';
311 *cp++ = '\n';
312 *cp = 0; /* end of string */
313 } else { /* simultaneous read/write access forbidden ! */
314 unlock_kernel();
315 return (-EPERM); /* no permission this time */
316 }
317 unlock_kernel();
318 return nonseekable_open(ino, filep);
319} /* hysdn_conf_open */
320
321/***************************/
322/* close a config file. */
323/***************************/
324static int
325hysdn_conf_close(struct inode *ino, struct file *filep)
326{
327 hysdn_card *card;
328 struct conf_writedata *cnf;
329 int retval = 0;
330 struct proc_dir_entry *pd;
331
332 lock_kernel();
333 /* search the addressed card */
334 card = card_root;
335 while (card) {
336 pd = card->procconf;
337 if (pd == PDE(ino))
338 break;
339 card = card->next; /* search next entry */
340 }
341 if (!card) {
342 unlock_kernel();
343 return (-ENODEV); /* device is unknown/invalid */
344 }
345 if (card->debug_flags & (LOG_PROC_OPEN | LOG_PROC_ALL))
346 hysdn_addlog(card, "config close for uid=%d gid=%d mode=0x%x",
347 filep->f_uid, filep->f_gid, filep->f_mode);
348
349 if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) {
350 /* write only access -> write boot file or conf line */
351 if (filep->private_data) {
352 cnf = filep->private_data;
353
354 if (cnf->state == CONF_STATE_POF)
355 retval = pof_write_close(cnf->card); /* close the pof write */
356 kfree(filep->private_data); /* free allocated memory for buffer */
357
358 } /* handle write private data */
359 } else if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) {
360 /* read access -> output card info data */
361
362 if (filep->private_data)
363 kfree(filep->private_data); /* release memory */
364 }
365 unlock_kernel();
366 return (retval);
367} /* hysdn_conf_close */
368
369/******************************************************/
370/* table for conf filesystem functions defined above. */
371/******************************************************/
372static struct file_operations conf_fops =
373{
374 .llseek = no_llseek,
375 .read = hysdn_conf_read,
376 .write = hysdn_conf_write,
377 .open = hysdn_conf_open,
378 .release = hysdn_conf_close,
379};
380
381/*****************************/
382/* hysdn subdir in /proc/net */
383/*****************************/
384struct proc_dir_entry *hysdn_proc_entry = NULL;
385
386/*******************************************************************************/
387/* hysdn_procconf_init is called when the module is loaded and after the cards */
388/* have been detected. The needed proc dir and card config files are created. */
389/* The log init is called at last. */
390/*******************************************************************************/
391int
392hysdn_procconf_init(void)
393{
394 hysdn_card *card;
395 uchar conf_name[20];
396
397 hysdn_proc_entry = create_proc_entry(PROC_SUBDIR_NAME, S_IFDIR | S_IRUGO | S_IXUGO, proc_net);
398 if (!hysdn_proc_entry) {
399 printk(KERN_ERR "HYSDN: unable to create hysdn subdir\n");
400 return (-1);
401 }
402 card = card_root; /* point to first card */
403 while (card) {
404
405 sprintf(conf_name, "%s%d", PROC_CONF_BASENAME, card->myid);
406 if ((card->procconf = (void *) create_proc_entry(conf_name,
407 S_IFREG | S_IRUGO | S_IWUSR,
408 hysdn_proc_entry)) != NULL) {
409 ((struct proc_dir_entry *) card->procconf)->proc_fops = &conf_fops;
410 ((struct proc_dir_entry *) card->procconf)->owner = THIS_MODULE;
411 hysdn_proclog_init(card); /* init the log file entry */
412 }
413 card = card->next; /* next entry */
414 }
415
416 printk(KERN_NOTICE "HYSDN: procfs Rev. %s initialised\n", hysdn_getrev(hysdn_procconf_revision));
417 return (0);
418} /* hysdn_procconf_init */
419
420/*************************************************************************************/
421/* hysdn_procconf_release is called when the module is unloaded and before the cards */
422/* resources are released. The module counter is assumed to be 0 ! */
423/*************************************************************************************/
424void
425hysdn_procconf_release(void)
426{
427 hysdn_card *card;
428 uchar conf_name[20];
429
430 card = card_root; /* start with first card */
431 while (card) {
432
433 sprintf(conf_name, "%s%d", PROC_CONF_BASENAME, card->myid);
434 if (card->procconf)
435 remove_proc_entry(conf_name, hysdn_proc_entry);
436
437 hysdn_proclog_release(card); /* init the log file entry */
438
439 card = card->next; /* point to next card */
440 }
441
442 remove_proc_entry(PROC_SUBDIR_NAME, proc_net);
443}
diff --git a/drivers/isdn/hysdn/hysdn_proclog.c b/drivers/isdn/hysdn/hysdn_proclog.c
new file mode 100644
index 000000000000..8ef2b7c952a6
--- /dev/null
+++ b/drivers/isdn/hysdn/hysdn_proclog.c
@@ -0,0 +1,441 @@
1/* $Id: hysdn_proclog.c,v 1.9.6.3 2001/09/23 22:24:54 kai Exp $
2 *
3 * Linux driver for HYSDN cards, /proc/net filesystem log functions.
4 *
5 * Author Werner Cornelius (werner@titro.de) for Hypercope GmbH
6 * Copyright 1999 by Werner Cornelius (werner@titro.de)
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 */
12
13#include <linux/module.h>
14#include <linux/version.h>
15#include <linux/poll.h>
16#include <linux/proc_fs.h>
17#include <linux/pci.h>
18#include <linux/smp_lock.h>
19
20#include "hysdn_defs.h"
21
22/* the proc subdir for the interface is defined in the procconf module */
23extern struct proc_dir_entry *hysdn_proc_entry;
24
25/*************************************************/
26/* structure keeping ascii log for device output */
27/*************************************************/
28struct log_data {
29 struct log_data *next;
30 ulong usage_cnt; /* number of files still to work */
31 void *proc_ctrl; /* pointer to own control procdata structure */
32 char log_start[2]; /* log string start (final len aligned by size) */
33};
34
35/**********************************************/
36/* structure holding proc entrys for one card */
37/**********************************************/
38struct procdata {
39 struct proc_dir_entry *log; /* log entry */
40 char log_name[15]; /* log filename */
41 struct log_data *log_head, *log_tail; /* head and tail for queue */
42 int if_used; /* open count for interface */
43 int volatile del_lock; /* lock for delete operations */
44 uchar logtmp[LOG_MAX_LINELEN];
45 wait_queue_head_t rd_queue;
46};
47
48
49/**********************************************/
50/* log function for cards error log interface */
51/**********************************************/
52void
53hysdn_card_errlog(hysdn_card * card, tErrLogEntry * logp, int maxsize)
54{
55 char buf[ERRLOG_TEXT_SIZE + 40];
56
57 sprintf(buf, "LOG 0x%08lX 0x%08lX : %s\n", logp->ulErrType, logp->ulErrSubtype, logp->ucText);
58 put_log_buffer(card, buf); /* output the string */
59} /* hysdn_card_errlog */
60
61/***************************************************/
62/* Log function using format specifiers for output */
63/***************************************************/
64void
65hysdn_addlog(hysdn_card * card, char *fmt,...)
66{
67 struct procdata *pd = card->proclog;
68 char *cp;
69 va_list args;
70
71 if (!pd)
72 return; /* log structure non existent */
73
74 cp = pd->logtmp;
75 cp += sprintf(cp, "HYSDN: card %d ", card->myid);
76
77 va_start(args, fmt);
78 cp += vsprintf(cp, fmt, args);
79 va_end(args);
80 *cp++ = '\n';
81 *cp = 0;
82
83 if (card->debug_flags & DEB_OUT_SYSLOG)
84 printk(KERN_INFO "%s", pd->logtmp);
85 else
86 put_log_buffer(card, pd->logtmp);
87
88} /* hysdn_addlog */
89
90/********************************************/
91/* put an log buffer into the log queue. */
92/* This buffer will be kept until all files */
93/* opened for read got the contents. */
94/* Flushes buffers not longer in use. */
95/********************************************/
96void
97put_log_buffer(hysdn_card * card, char *cp)
98{
99 struct log_data *ib;
100 struct procdata *pd = card->proclog;
101 int i;
102 unsigned long flags;
103
104 if (!pd)
105 return;
106 if (!cp)
107 return;
108 if (!*cp)
109 return;
110 if (pd->if_used <= 0)
111 return; /* no open file for read */
112
113 if (!(ib = (struct log_data *) kmalloc(sizeof(struct log_data) + strlen(cp), GFP_ATOMIC)))
114 return; /* no memory */
115 strcpy(ib->log_start, cp); /* set output string */
116 ib->next = NULL;
117 ib->proc_ctrl = pd; /* point to own control structure */
118 save_flags(flags);
119 cli();
120 ib->usage_cnt = pd->if_used;
121 if (!pd->log_head)
122 pd->log_head = ib; /* new head */
123 else
124 pd->log_tail->next = ib; /* follows existing messages */
125 pd->log_tail = ib; /* new tail */
126 i = pd->del_lock++; /* get lock state */
127 restore_flags(flags);
128
129 /* delete old entrys */
130 if (!i)
131 while (pd->log_head->next) {
132 if ((pd->log_head->usage_cnt <= 0) &&
133 (pd->log_head->next->usage_cnt <= 0)) {
134 ib = pd->log_head;
135 pd->log_head = pd->log_head->next;
136 kfree(ib);
137 } else
138 break;
139 } /* pd->log_head->next */
140 pd->del_lock--; /* release lock level */
141 wake_up_interruptible(&(pd->rd_queue)); /* announce new entry */
142} /* put_log_buffer */
143
144
145/******************************/
146/* file operations and tables */
147/******************************/
148
149/****************************************/
150/* write log file -> set log level bits */
151/****************************************/
152static ssize_t
153hysdn_log_write(struct file *file, const char __user *buf, size_t count, loff_t * off)
154{
155 ulong u = 0;
156 int found = 0;
157 uchar *cp, valbuf[128];
158 long base = 10;
159 hysdn_card *card = (hysdn_card *) file->private_data;
160
161 if (count > (sizeof(valbuf) - 1))
162 count = sizeof(valbuf) - 1; /* limit length */
163 if (copy_from_user(valbuf, buf, count))
164 return (-EFAULT); /* copy failed */
165
166 valbuf[count] = 0; /* terminating 0 */
167 cp = valbuf;
168 if ((count > 2) && (valbuf[0] == '0') && (valbuf[1] == 'x')) {
169 cp += 2; /* pointer after hex modifier */
170 base = 16;
171 }
172 /* scan the input for debug flags */
173 while (*cp) {
174 if ((*cp >= '0') && (*cp <= '9')) {
175 found = 1;
176 u *= base; /* adjust to next digit */
177 u += *cp++ - '0';
178 continue;
179 }
180 if (base != 16)
181 break; /* end of number */
182
183 if ((*cp >= 'a') && (*cp <= 'f')) {
184 found = 1;
185 u *= base; /* adjust to next digit */
186 u += *cp++ - 'a' + 10;
187 continue;
188 }
189 break; /* terminated */
190 }
191
192 if (found) {
193 card->debug_flags = u; /* remember debug flags */
194 hysdn_addlog(card, "debug set to 0x%lx", card->debug_flags);
195 }
196 return (count);
197} /* hysdn_log_write */
198
199/******************/
200/* read log file */
201/******************/
202static ssize_t
203hysdn_log_read(struct file *file, char __user *buf, size_t count, loff_t * off)
204{
205 struct log_data *inf;
206 int len;
207 struct proc_dir_entry *pde = PDE(file->f_dentry->d_inode);
208 struct procdata *pd = NULL;
209 hysdn_card *card;
210
211 if (!*((struct log_data **) file->private_data)) {
212 if (file->f_flags & O_NONBLOCK)
213 return (-EAGAIN);
214
215 /* sorry, but we need to search the card */
216 card = card_root;
217 while (card) {
218 pd = card->proclog;
219 if (pd->log == pde)
220 break;
221 card = card->next; /* search next entry */
222 }
223 if (card)
224 interruptible_sleep_on(&(pd->rd_queue));
225 else
226 return (-EAGAIN);
227
228 }
229 if (!(inf = *((struct log_data **) file->private_data)))
230 return (0);
231
232 inf->usage_cnt--; /* new usage count */
233 file->private_data = &inf->next; /* next structure */
234 if ((len = strlen(inf->log_start)) <= count) {
235 if (copy_to_user(buf, inf->log_start, len))
236 return -EFAULT;
237 *off += len;
238 return (len);
239 }
240 return (0);
241} /* hysdn_log_read */
242
243/******************/
244/* open log file */
245/******************/
246static int
247hysdn_log_open(struct inode *ino, struct file *filep)
248{
249 hysdn_card *card;
250 struct procdata *pd = NULL;
251 ulong flags;
252
253 lock_kernel();
254 card = card_root;
255 while (card) {
256 pd = card->proclog;
257 if (pd->log == PDE(ino))
258 break;
259 card = card->next; /* search next entry */
260 }
261 if (!card) {
262 unlock_kernel();
263 return (-ENODEV); /* device is unknown/invalid */
264 }
265 filep->private_data = card; /* remember our own card */
266
267 if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) {
268 /* write only access -> write log level only */
269 } else if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) {
270
271 /* read access -> log/debug read */
272 save_flags(flags);
273 cli();
274 pd->if_used++;
275 if (pd->log_head)
276 filep->private_data = &pd->log_tail->next;
277 else
278 filep->private_data = &pd->log_head;
279 restore_flags(flags);
280 } else { /* simultaneous read/write access forbidden ! */
281 unlock_kernel();
282 return (-EPERM); /* no permission this time */
283 }
284 unlock_kernel();
285 return nonseekable_open(ino, filep);
286} /* hysdn_log_open */
287
288/*******************************************************************************/
289/* close a cardlog file. If the file has been opened for exclusive write it is */
290/* assumed as pof data input and the pof loader is noticed about. */
291/* Otherwise file is handled as log output. In this case the interface usage */
292/* count is decremented and all buffers are noticed of closing. If this file */
293/* was the last one to be closed, all buffers are freed. */
294/*******************************************************************************/
295static int
296hysdn_log_close(struct inode *ino, struct file *filep)
297{
298 struct log_data *inf;
299 struct procdata *pd;
300 hysdn_card *card;
301 int retval = 0;
302 unsigned long flags;
303
304
305 lock_kernel();
306 if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) {
307 /* write only access -> write debug level written */
308 retval = 0; /* success */
309 } else {
310 /* read access -> log/debug read, mark one further file as closed */
311
312 pd = NULL;
313 save_flags(flags);
314 cli();
315 inf = *((struct log_data **) filep->private_data); /* get first log entry */
316 if (inf)
317 pd = (struct procdata *) inf->proc_ctrl; /* still entries there */
318 else {
319 /* no info available -> search card */
320 card = card_root;
321 while (card) {
322 pd = card->proclog;
323 if (pd->log == PDE(ino))
324 break;
325 card = card->next; /* search next entry */
326 }
327 if (card)
328 pd = card->proclog; /* pointer to procfs log */
329 }
330 if (pd)
331 pd->if_used--; /* decrement interface usage count by one */
332
333 while (inf) {
334 inf->usage_cnt--; /* decrement usage count for buffers */
335 inf = inf->next;
336 }
337 restore_flags(flags);
338
339 if (pd)
340 if (pd->if_used <= 0) /* delete buffers if last file closed */
341 while (pd->log_head) {
342 inf = pd->log_head;
343 pd->log_head = pd->log_head->next;
344 kfree(inf);
345 }
346 } /* read access */
347 unlock_kernel();
348
349 return (retval);
350} /* hysdn_log_close */
351
352/*************************************************/
353/* select/poll routine to be able using select() */
354/*************************************************/
355static unsigned int
356hysdn_log_poll(struct file *file, poll_table * wait)
357{
358 unsigned int mask = 0;
359 struct proc_dir_entry *pde = PDE(file->f_dentry->d_inode);
360 hysdn_card *card;
361 struct procdata *pd = NULL;
362
363 if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE)
364 return (mask); /* no polling for write supported */
365
366 /* we need to search the card */
367 card = card_root;
368 while (card) {
369 pd = card->proclog;
370 if (pd->log == pde)
371 break;
372 card = card->next; /* search next entry */
373 }
374 if (!card)
375 return (mask); /* card not found */
376
377 poll_wait(file, &(pd->rd_queue), wait);
378
379 if (*((struct log_data **) file->private_data))
380 mask |= POLLIN | POLLRDNORM;
381
382 return mask;
383} /* hysdn_log_poll */
384
385/**************************************************/
386/* table for log filesystem functions defined above. */
387/**************************************************/
388static struct file_operations log_fops =
389{
390 .llseek = no_llseek,
391 .read = hysdn_log_read,
392 .write = hysdn_log_write,
393 .poll = hysdn_log_poll,
394 .open = hysdn_log_open,
395 .release = hysdn_log_close,
396};
397
398
399/***********************************************************************************/
400/* hysdn_proclog_init is called when the module is loaded after creating the cards */
401/* conf files. */
402/***********************************************************************************/
403int
404hysdn_proclog_init(hysdn_card * card)
405{
406 struct procdata *pd;
407
408 /* create a cardlog proc entry */
409
410 if ((pd = (struct procdata *) kmalloc(sizeof(struct procdata), GFP_KERNEL)) != NULL) {
411 memset(pd, 0, sizeof(struct procdata));
412 sprintf(pd->log_name, "%s%d", PROC_LOG_BASENAME, card->myid);
413 if ((pd->log = create_proc_entry(pd->log_name, S_IFREG | S_IRUGO | S_IWUSR, hysdn_proc_entry)) != NULL) {
414 pd->log->proc_fops = &log_fops;
415 pd->log->owner = THIS_MODULE;
416 }
417
418 init_waitqueue_head(&(pd->rd_queue));
419
420 card->proclog = (void *) pd; /* remember procfs structure */
421 }
422 return (0);
423} /* hysdn_proclog_init */
424
425/************************************************************************************/
426/* hysdn_proclog_release is called when the module is unloaded and before the cards */
427/* conf file is released */
428/* The module counter is assumed to be 0 ! */
429/************************************************************************************/
430void
431hysdn_proclog_release(hysdn_card * card)
432{
433 struct procdata *pd;
434
435 if ((pd = (struct procdata *) card->proclog) != NULL) {
436 if (pd->log)
437 remove_proc_entry(pd->log_name, hysdn_proc_entry);
438 kfree(pd); /* release memory */
439 card->proclog = NULL;
440 }
441} /* hysdn_proclog_release */
diff --git a/drivers/isdn/hysdn/hysdn_sched.c b/drivers/isdn/hysdn/hysdn_sched.c
new file mode 100644
index 000000000000..4fa3b01707cd
--- /dev/null
+++ b/drivers/isdn/hysdn/hysdn_sched.c
@@ -0,0 +1,207 @@
1/* $Id: hysdn_sched.c,v 1.5.6.4 2001/11/06 21:58:19 kai Exp $
2 *
3 * Linux driver for HYSDN cards
4 * scheduler routines for handling exchange card <-> pc.
5 *
6 * Author Werner Cornelius (werner@titro.de) for Hypercope GmbH
7 * Copyright 1999 by Werner Cornelius (werner@titro.de)
8 *
9 * This software may be used and distributed according to the terms
10 * of the GNU General Public License, incorporated herein by reference.
11 *
12 */
13
14#include <linux/config.h>
15#include <linux/sched.h>
16#include <linux/signal.h>
17#include <linux/kernel.h>
18#include <linux/ioport.h>
19#include <linux/interrupt.h>
20#include <linux/delay.h>
21#include <asm/io.h>
22
23#include "hysdn_defs.h"
24
25/*****************************************************************************/
26/* hysdn_sched_rx is called from the cards handler to announce new data is */
27/* available from the card. The routine has to handle the data and return */
28/* with a nonzero code if the data could be worked (or even thrown away), if */
29/* no room to buffer the data is available a zero return tells the card */
30/* to keep the data until later. */
31/*****************************************************************************/
32int
33hysdn_sched_rx(hysdn_card * card, uchar * buf, word len, word chan)
34{
35
36 switch (chan) {
37 case CHAN_NDIS_DATA:
38 if (hynet_enable & (1 << card->myid)) {
39 /* give packet to network handler */
40 hysdn_rx_netpkt(card, buf, len);
41 }
42 break;
43
44 case CHAN_ERRLOG:
45 hysdn_card_errlog(card, (tErrLogEntry *) buf, len);
46 if (card->err_log_state == ERRLOG_STATE_ON)
47 card->err_log_state = ERRLOG_STATE_START; /* start new fetch */
48 break;
49#ifdef CONFIG_HYSDN_CAPI
50 case CHAN_CAPI:
51/* give packet to CAPI handler */
52 if (hycapi_enable & (1 << card->myid)) {
53 hycapi_rx_capipkt(card, buf, len);
54 }
55 break;
56#endif /* CONFIG_HYSDN_CAPI */
57 default:
58 printk(KERN_INFO "irq message channel %d len %d unhandled \n", chan, len);
59 break;
60
61 } /* switch rx channel */
62
63 return (1); /* always handled */
64} /* hysdn_sched_rx */
65
66/*****************************************************************************/
67/* hysdn_sched_tx is called from the cards handler to announce that there is */
68/* room in the tx-buffer to the card and data may be sent if needed. */
69/* If the routine wants to send data it must fill buf, len and chan with the */
70/* appropriate data and return a nonzero value. With a zero return no new */
71/* data to send is assumed. maxlen specifies the buffer size available for */
72/* sending. */
73/*****************************************************************************/
74int
75hysdn_sched_tx(hysdn_card * card, uchar * buf, word volatile *len, word volatile *chan, word maxlen)
76{
77 struct sk_buff *skb;
78
79 if (card->net_tx_busy) {
80 card->net_tx_busy = 0; /* reset flag */
81 hysdn_tx_netack(card); /* acknowledge packet send */
82 } /* a network packet has completely been transferred */
83 /* first of all async requests are handled */
84 if (card->async_busy) {
85 if (card->async_len <= maxlen) {
86 memcpy(buf, card->async_data, card->async_len);
87 *len = card->async_len;
88 *chan = card->async_channel;
89 card->async_busy = 0; /* reset request */
90 return (1);
91 }
92 card->async_busy = 0; /* in case of length error */
93 } /* async request */
94 if ((card->err_log_state == ERRLOG_STATE_START) &&
95 (maxlen >= ERRLOG_CMD_REQ_SIZE)) {
96 strcpy(buf, ERRLOG_CMD_REQ); /* copy the command */
97 *len = ERRLOG_CMD_REQ_SIZE; /* buffer length */
98 *chan = CHAN_ERRLOG; /* and channel */
99 card->err_log_state = ERRLOG_STATE_ON; /* new state is on */
100 return (1); /* tell that data should be send */
101 } /* error log start and able to send */
102 if ((card->err_log_state == ERRLOG_STATE_STOP) &&
103 (maxlen >= ERRLOG_CMD_STOP_SIZE)) {
104 strcpy(buf, ERRLOG_CMD_STOP); /* copy the command */
105 *len = ERRLOG_CMD_STOP_SIZE; /* buffer length */
106 *chan = CHAN_ERRLOG; /* and channel */
107 card->err_log_state = ERRLOG_STATE_OFF; /* new state is off */
108 return (1); /* tell that data should be send */
109 } /* error log start and able to send */
110 /* now handle network interface packets */
111 if ((hynet_enable & (1 << card->myid)) &&
112 (skb = hysdn_tx_netget(card)) != NULL)
113 {
114 if (skb->len <= maxlen) {
115 memcpy(buf, skb->data, skb->len); /* copy the packet to the buffer */
116 *len = skb->len;
117 *chan = CHAN_NDIS_DATA;
118 card->net_tx_busy = 1; /* we are busy sending network data */
119 return (1); /* go and send the data */
120 } else
121 hysdn_tx_netack(card); /* aknowledge packet -> throw away */
122 } /* send a network packet if available */
123#ifdef CONFIG_HYSDN_CAPI
124 if( ((hycapi_enable & (1 << card->myid))) &&
125 ((skb = hycapi_tx_capiget(card)) != NULL) )
126 {
127 if (skb->len <= maxlen) {
128 memcpy(buf, skb->data, skb->len);
129 *len = skb->len;
130 *chan = CHAN_CAPI;
131 hycapi_tx_capiack(card);
132 return (1); /* go and send the data */
133 }
134 }
135#endif /* CONFIG_HYSDN_CAPI */
136 return (0); /* nothing to send */
137} /* hysdn_sched_tx */
138
139
140/*****************************************************************************/
141/* send one config line to the card and return 0 if successful, otherwise a */
142/* negative error code. */
143/* The function works with timeouts perhaps not giving the greatest speed */
144/* sending the line, but this should be meaningless beacuse only some lines */
145/* are to be sent and this happens very seldom. */
146/*****************************************************************************/
147int
148hysdn_tx_cfgline(hysdn_card * card, uchar * line, word chan)
149{
150 int cnt = 50; /* timeout intervalls */
151 ulong flags;
152
153 if (card->debug_flags & LOG_SCHED_ASYN)
154 hysdn_addlog(card, "async tx-cfg chan=%d len=%d", chan, strlen(line) + 1);
155
156 save_flags(flags);
157 cli();
158 while (card->async_busy) {
159 sti();
160
161 if (card->debug_flags & LOG_SCHED_ASYN)
162 hysdn_addlog(card, "async tx-cfg delayed");
163
164 msleep_interruptible(20); /* Timeout 20ms */
165 if (!--cnt) {
166 restore_flags(flags);
167 return (-ERR_ASYNC_TIME); /* timed out */
168 }
169 cli();
170 } /* wait for buffer to become free */
171
172 strcpy(card->async_data, line);
173 card->async_len = strlen(line) + 1;
174 card->async_channel = chan;
175 card->async_busy = 1; /* request transfer */
176
177 /* now queue the task */
178 schedule_work(&card->irq_queue);
179 sti();
180
181 if (card->debug_flags & LOG_SCHED_ASYN)
182 hysdn_addlog(card, "async tx-cfg data queued");
183
184 cnt++; /* short delay */
185 cli();
186
187 while (card->async_busy) {
188 sti();
189
190 if (card->debug_flags & LOG_SCHED_ASYN)
191 hysdn_addlog(card, "async tx-cfg waiting for tx-ready");
192
193 msleep_interruptible(20); /* Timeout 20ms */
194 if (!--cnt) {
195 restore_flags(flags);
196 return (-ERR_ASYNC_TIME); /* timed out */
197 }
198 cli();
199 } /* wait for buffer to become free again */
200
201 restore_flags(flags);
202
203 if (card->debug_flags & LOG_SCHED_ASYN)
204 hysdn_addlog(card, "async tx-cfg data send");
205
206 return (0); /* line send correctly */
207} /* hysdn_tx_cfgline */
diff --git a/drivers/isdn/hysdn/ince1pc.h b/drivers/isdn/hysdn/ince1pc.h
new file mode 100644
index 000000000000..4a115a87c782
--- /dev/null
+++ b/drivers/isdn/hysdn/ince1pc.h
@@ -0,0 +1,134 @@
1/*
2 * Linux driver for HYSDN cards
3 * common definitions for both sides of the bus:
4 * - conventions both spoolers must know
5 * - channel numbers agreed upon
6 *
7 * Author M. Steinkopf
8 * Copyright 1999 by M. Steinkopf
9 *
10 * This software may be used and distributed according to the terms
11 * of the GNU General Public License, incorporated herein by reference.
12 *
13 */
14
15#ifndef __INCE1PC_H__
16#define __INCE1PC_H__
17
18/* basic scalar definitions have same meanning,
19 * but their declaration location depends on environment
20 */
21
22/*--------------------------------------channel numbers---------------------*/
23#define CHAN_SYSTEM 0x0001 /* system channel (spooler to spooler) */
24#define CHAN_ERRLOG 0x0005 /* error logger */
25#define CHAN_CAPI 0x0064 /* CAPI interface */
26#define CHAN_NDIS_DATA 0x1001 /* NDIS data transfer */
27
28/*--------------------------------------POF ready msg-----------------------*/
29 /* NOTE: after booting POF sends system ready message to PC: */
30#define RDY_MAGIC 0x52535953UL /* 'SYSR' reversed */
31#define RDY_MAGIC_SIZE 4 /* size in bytes */
32
33#define MAX_N_TOK_BYTES 255
34
35#define MIN_RDY_MSG_SIZE RDY_MAGIC_SIZE
36#define MAX_RDY_MSG_SIZE (RDY_MAGIC_SIZE+MAX_N_TOK_BYTES)
37
38#define SYSR_TOK_END 0
39#define SYSR_TOK_B_CHAN 1 /* nr. of B-Channels; DataLen=1; def: 2 */
40#define SYSR_TOK_FAX_CHAN 2 /* nr. of FAX Channels; DataLen=1; def: 0 */
41#define SYSR_TOK_MAC_ADDR 3 /* MAC-Address; DataLen=6; def: auto */
42#define SYSR_TOK_ESC 255 /* undefined data size yet */
43 /* default values, if not corrected by token: */
44#define SYSR_TOK_B_CHAN_DEF 2 /* assume 2 B-Channels */
45#define SYSR_TOK_FAX_CHAN_DEF 1 /* assume 1 FAX Channel */
46
47/* syntax of new SYSR token stream:
48 * channel: CHAN_SYSTEM
49 * msgsize: MIN_RDY_MSG_SIZE <= x <= MAX_RDY_MSG_SIZE
50 * RDY_MAGIC_SIZE <= x <= (RDY_MAGIC_SIZE+MAX_N_TOK_BYTES)
51 * msg : 0 1 2 3 {4 5 6 ..}
52 * S Y S R MAX_N_TOK_BYTES bytes of TokenStream
53 *
54 * TokenStream := empty
55 * | {NonEndTokenChunk} EndToken RotlCRC
56 * NonEndTokenChunk:= NonEndTokenId DataLen [Data]
57 * NonEndTokenId := 0x01 .. 0xFE 1 BYTE
58 * DataLen := 0x00 .. 0xFF 1 BYTE
59 * Data := DataLen bytes
60 * EndToken := 0x00
61 * RotlCRC := special 1 byte CRC over all NonEndTokenChunk bytes
62 * s. RotlCRC algorithm
63 *
64 * RotlCRC algorithm:
65 * ucSum= 0 1 uchar
66 * for all NonEndTokenChunk bytes:
67 * ROTL(ucSum,1) rotate left by 1
68 * ucSum += Char; add current byte with swap around
69 * RotlCRC= ~ucSum; invert all bits for result
70 *
71 * note:
72 * - for 16-bit FIFO add padding 0 byte to achieve even token data bytes!
73 */
74
75/*--------------------------------------error logger------------------------*/
76 /* note: pof needs final 0 ! */
77#define ERRLOG_CMD_REQ "ERRLOG ON"
78#define ERRLOG_CMD_REQ_SIZE 10 /* with final 0 byte ! */
79#define ERRLOG_CMD_STOP "ERRLOG OFF"
80#define ERRLOG_CMD_STOP_SIZE 11 /* with final 0 byte ! */
81
82#define ERRLOG_ENTRY_SIZE 64 /* sizeof(tErrLogEntry) */
83 /* remaining text size = 55 */
84#define ERRLOG_TEXT_SIZE (ERRLOG_ENTRY_SIZE-2*4-1)
85
86typedef struct ErrLogEntry_tag {
87
88/*00 */ ulong ulErrType;
89
90/*04 */ ulong ulErrSubtype;
91
92/*08 */ uchar ucTextSize;
93
94 /*09 */ uchar ucText[ERRLOG_TEXT_SIZE];
95 /* ASCIIZ of len ucTextSize-1 */
96
97/*40 */
98} tErrLogEntry;
99
100
101#if defined(__TURBOC__)
102#if sizeof(tErrLogEntry) != ERRLOG_ENTRY_SIZE
103#error size of tErrLogEntry != ERRLOG_ENTRY_SIZE
104#endif /* */
105#endif /* */
106
107/*--------------------------------------DPRAM boot spooler------------------*/
108 /* this is the struture used between pc and
109 * hyperstone to exchange boot data
110 */
111#define DPRAM_SPOOLER_DATA_SIZE 0x20
112typedef struct DpramBootSpooler_tag {
113
114/*00 */ uchar Len;
115
116/*01 */ volatile uchar RdPtr;
117
118/*02 */ uchar WrPtr;
119
120/*03 */ uchar Data[DPRAM_SPOOLER_DATA_SIZE];
121
122/*23 */
123} tDpramBootSpooler;
124
125
126#define DPRAM_SPOOLER_MIN_SIZE 5 /* Len+RdPtr+Wrptr+2*data */
127#define DPRAM_SPOOLER_DEF_SIZE 0x23 /* current default size */
128
129/*--------------------------------------HYCARD/ERGO DPRAM SoftUart----------*/
130 /* at DPRAM offset 0x1C00: */
131#define SIZE_RSV_SOFT_UART 0x1B0 /* 432 bytes reserved for SoftUart */
132
133
134#endif /* __INCE1PC_H__ */
diff --git a/drivers/isdn/i4l/Kconfig b/drivers/isdn/i4l/Kconfig
new file mode 100644
index 000000000000..1789b607f090
--- /dev/null
+++ b/drivers/isdn/i4l/Kconfig
@@ -0,0 +1,141 @@
1#
2# Old ISDN4Linux config
3#
4
5config ISDN_PPP
6 bool "Support synchronous PPP"
7 depends on INET
8 help
9 Over digital connections such as ISDN, there is no need to
10 synchronize sender and recipient's clocks with start and stop bits
11 as is done over analog telephone lines. Instead, one can use
12 "synchronous PPP". Saying Y here will include this protocol. This
13 protocol is used by Cisco and Sun for example. So you want to say Y
14 here if the other end of your ISDN connection supports it. You will
15 need a special version of pppd (called ipppd) for using this
16 feature. See <file:Documentation/isdn/README.syncppp> and
17 <file:Documentation/isdn/syncPPP.FAQ> for more information.
18
19config ISDN_PPP_VJ
20 bool "Use VJ-compression with synchronous PPP"
21 depends on ISDN_PPP
22 help
23 This enables Van Jacobson header compression for synchronous PPP.
24 Say Y if the other end of the connection supports it.
25
26config ISDN_MPP
27 bool "Support generic MP (RFC 1717)"
28 depends on ISDN_PPP
29 help
30 With synchronous PPP enabled, it is possible to increase throughput
31 by bundling several ISDN-connections, using this protocol. See
32 <file:Documentation/isdn/README.syncppp> for more information.
33
34config IPPP_FILTER
35 bool "Filtering for synchronous PPP"
36 depends on ISDN_PPP
37 help
38 Say Y here if you want to be able to filter the packets passing over
39 IPPP interfaces. This allows you to control which packets count as
40 activity (i.e. which packets will reset the idle timer or bring up
41 a demand-dialled link) and which packets are to be dropped entirely.
42 You need to say Y here if you wish to use the pass-filter and
43 active-filter options to ipppd.
44
45config ISDN_PPP_BSDCOMP
46 tristate "Support BSD compression"
47 depends on ISDN_PPP
48 help
49 Support for the BSD-Compress compression method for PPP, which uses
50 the LZW compression method to compress each PPP packet before it is
51 sent over the wire. The machine at the other end of the PPP link
52 (usually your ISP) has to support the BSD-Compress compression
53 method as well for this to be useful. Even if they don't support it,
54 it is safe to say Y here.
55
56config ISDN_AUDIO
57 bool "Support audio via ISDN"
58 help
59 If you say Y here, the modem-emulator will support a subset of the
60 EIA Class 8 Voice commands. Using a getty with voice-support
61 (mgetty+sendfax by <gert@greenie.muc.de> with an extension, available
62 with the ISDN utility package for example), you will be able to use
63 your Linux box as an ISDN-answering machine. Of course, this must be
64 supported by the lowlevel driver also. Currently, the HiSax driver
65 is the only voice-supporting driver. See
66 <file:Documentation/isdn/README.audio> for more information.
67
68config ISDN_TTY_FAX
69 bool "Support AT-Fax Class 1 and 2 commands"
70 depends on ISDN_AUDIO
71 help
72 If you say Y here, the modem-emulator will support a subset of the
73 Fax Class 1 and 2 commands. Using a getty with fax-support
74 (mgetty+sendfax, hylafax), you will be able to use your Linux box as
75 an ISDN-fax-machine. This must be supported by the lowlevel driver
76 also. See <file:Documentation/isdn/README.fax> for more information.
77
78config ISDN_X25
79 bool "X.25 PLP on top of ISDN"
80 depends on X25
81 help
82 This feature provides the X.25 protocol over ISDN connections.
83 See <file:Documentation/isdn/README.x25> for more information
84 if you are thinking about using this.
85
86
87menu "ISDN feature submodules"
88 depends on ISDN
89
90config ISDN_DRV_LOOP
91 tristate "isdnloop support"
92 depends on BROKEN_ON_SMP
93 help
94 This driver provides a virtual ISDN card. Its primary purpose is
95 testing of linklevel features or configuration without getting
96 charged by your service-provider for lots of phone calls.
97 You need will need the loopctrl utility from the latest isdn4k-utils
98 package to set up this driver.
99
100config ISDN_DIVERSION
101 tristate "Support isdn diversion services"
102 depends on ISDN && ISDN_I4L
103 help
104 This option allows you to use some supplementary diversion
105 services in conjunction with the HiSax driver on an EURO/DSS1
106 line.
107
108 Supported options are CD (call deflection), CFU (Call forward
109 unconditional), CFB (Call forward when busy) and CFNR (call forward
110 not reachable). Additionally the actual CFU, CFB and CFNR state may
111 be interrogated.
112
113 The use of CFU, CFB, CFNR and interrogation may be limited to some
114 countries. The keypad protocol is still not implemented. CD should
115 work in all countries if the service has been subscribed to.
116
117 Please read the file <file:Documentation/isdn/README.diversion>.
118
119endmenu
120
121comment "ISDN4Linux hardware drivers"
122 depends on NET && ISDN && ISDN_I4L
123
124source "drivers/isdn/hisax/Kconfig"
125
126
127menu "Active cards"
128 depends on NET && ISDN && ISDN_I4L!=n
129
130source "drivers/isdn/icn/Kconfig"
131
132source "drivers/isdn/pcbit/Kconfig"
133
134source "drivers/isdn/sc/Kconfig"
135
136source "drivers/isdn/act2000/Kconfig"
137
138source "drivers/isdn/hysdn/Kconfig"
139
140endmenu
141
diff --git a/drivers/isdn/i4l/Makefile b/drivers/isdn/i4l/Makefile
new file mode 100644
index 000000000000..49a06c0005dd
--- /dev/null
+++ b/drivers/isdn/i4l/Makefile
@@ -0,0 +1,18 @@
1# Makefile for the kernel ISDN subsystem and device drivers.
2
3# Each configuration option enables a list of files.
4
5obj-$(CONFIG_ISDN_I4L) += isdn.o
6obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o
7
8# Multipart objects.
9
10isdn-y := isdn_net.o isdn_tty.o isdn_v110.o isdn_common.o
11
12# Optional parts of multipart objects.
13
14isdn-$(CONFIG_ISDN_PPP) += isdn_ppp.o
15isdn-$(CONFIG_ISDN_X25) += isdn_concap.o isdn_x25iface.o
16isdn-$(CONFIG_ISDN_AUDIO) += isdn_audio.o
17isdn-$(CONFIG_ISDN_TTY_FAX) += isdn_ttyfax.o
18
diff --git a/drivers/isdn/i4l/isdn_audio.c b/drivers/isdn/i4l/isdn_audio.c
new file mode 100644
index 000000000000..5350836a4f98
--- /dev/null
+++ b/drivers/isdn/i4l/isdn_audio.c
@@ -0,0 +1,720 @@
1/* $Id: isdn_audio.c,v 1.1.2.2 2004/01/12 22:37:18 keil Exp $
2 *
3 * Linux ISDN subsystem, audio conversion and compression (linklevel).
4 *
5 * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
6 * DTMF code (c) 1996 by Christian Mock (cm@kukuruz.ping.at)
7 * Silence detection (c) 1998 by Armin Schindler (mac@gismo.telekom.de)
8 *
9 * This software may be used and distributed according to the terms
10 * of the GNU General Public License, incorporated herein by reference.
11 *
12 */
13
14#include <linux/isdn.h>
15#include "isdn_audio.h"
16#include "isdn_common.h"
17
18char *isdn_audio_revision = "$Revision: 1.1.2.2 $";
19
20/*
21 * Misc. lookup-tables.
22 */
23
24/* ulaw -> signed 16-bit */
25static short isdn_audio_ulaw_to_s16[] =
26{
27 0x8284, 0x8684, 0x8a84, 0x8e84, 0x9284, 0x9684, 0x9a84, 0x9e84,
28 0xa284, 0xa684, 0xaa84, 0xae84, 0xb284, 0xb684, 0xba84, 0xbe84,
29 0xc184, 0xc384, 0xc584, 0xc784, 0xc984, 0xcb84, 0xcd84, 0xcf84,
30 0xd184, 0xd384, 0xd584, 0xd784, 0xd984, 0xdb84, 0xdd84, 0xdf84,
31 0xe104, 0xe204, 0xe304, 0xe404, 0xe504, 0xe604, 0xe704, 0xe804,
32 0xe904, 0xea04, 0xeb04, 0xec04, 0xed04, 0xee04, 0xef04, 0xf004,
33 0xf0c4, 0xf144, 0xf1c4, 0xf244, 0xf2c4, 0xf344, 0xf3c4, 0xf444,
34 0xf4c4, 0xf544, 0xf5c4, 0xf644, 0xf6c4, 0xf744, 0xf7c4, 0xf844,
35 0xf8a4, 0xf8e4, 0xf924, 0xf964, 0xf9a4, 0xf9e4, 0xfa24, 0xfa64,
36 0xfaa4, 0xfae4, 0xfb24, 0xfb64, 0xfba4, 0xfbe4, 0xfc24, 0xfc64,
37 0xfc94, 0xfcb4, 0xfcd4, 0xfcf4, 0xfd14, 0xfd34, 0xfd54, 0xfd74,
38 0xfd94, 0xfdb4, 0xfdd4, 0xfdf4, 0xfe14, 0xfe34, 0xfe54, 0xfe74,
39 0xfe8c, 0xfe9c, 0xfeac, 0xfebc, 0xfecc, 0xfedc, 0xfeec, 0xfefc,
40 0xff0c, 0xff1c, 0xff2c, 0xff3c, 0xff4c, 0xff5c, 0xff6c, 0xff7c,
41 0xff88, 0xff90, 0xff98, 0xffa0, 0xffa8, 0xffb0, 0xffb8, 0xffc0,
42 0xffc8, 0xffd0, 0xffd8, 0xffe0, 0xffe8, 0xfff0, 0xfff8, 0x0000,
43 0x7d7c, 0x797c, 0x757c, 0x717c, 0x6d7c, 0x697c, 0x657c, 0x617c,
44 0x5d7c, 0x597c, 0x557c, 0x517c, 0x4d7c, 0x497c, 0x457c, 0x417c,
45 0x3e7c, 0x3c7c, 0x3a7c, 0x387c, 0x367c, 0x347c, 0x327c, 0x307c,
46 0x2e7c, 0x2c7c, 0x2a7c, 0x287c, 0x267c, 0x247c, 0x227c, 0x207c,
47 0x1efc, 0x1dfc, 0x1cfc, 0x1bfc, 0x1afc, 0x19fc, 0x18fc, 0x17fc,
48 0x16fc, 0x15fc, 0x14fc, 0x13fc, 0x12fc, 0x11fc, 0x10fc, 0x0ffc,
49 0x0f3c, 0x0ebc, 0x0e3c, 0x0dbc, 0x0d3c, 0x0cbc, 0x0c3c, 0x0bbc,
50 0x0b3c, 0x0abc, 0x0a3c, 0x09bc, 0x093c, 0x08bc, 0x083c, 0x07bc,
51 0x075c, 0x071c, 0x06dc, 0x069c, 0x065c, 0x061c, 0x05dc, 0x059c,
52 0x055c, 0x051c, 0x04dc, 0x049c, 0x045c, 0x041c, 0x03dc, 0x039c,
53 0x036c, 0x034c, 0x032c, 0x030c, 0x02ec, 0x02cc, 0x02ac, 0x028c,
54 0x026c, 0x024c, 0x022c, 0x020c, 0x01ec, 0x01cc, 0x01ac, 0x018c,
55 0x0174, 0x0164, 0x0154, 0x0144, 0x0134, 0x0124, 0x0114, 0x0104,
56 0x00f4, 0x00e4, 0x00d4, 0x00c4, 0x00b4, 0x00a4, 0x0094, 0x0084,
57 0x0078, 0x0070, 0x0068, 0x0060, 0x0058, 0x0050, 0x0048, 0x0040,
58 0x0038, 0x0030, 0x0028, 0x0020, 0x0018, 0x0010, 0x0008, 0x0000
59};
60
61/* alaw -> signed 16-bit */
62static short isdn_audio_alaw_to_s16[] =
63{
64 0x13fc, 0xec04, 0x0144, 0xfebc, 0x517c, 0xae84, 0x051c, 0xfae4,
65 0x0a3c, 0xf5c4, 0x0048, 0xffb8, 0x287c, 0xd784, 0x028c, 0xfd74,
66 0x1bfc, 0xe404, 0x01cc, 0xfe34, 0x717c, 0x8e84, 0x071c, 0xf8e4,
67 0x0e3c, 0xf1c4, 0x00c4, 0xff3c, 0x387c, 0xc784, 0x039c, 0xfc64,
68 0x0ffc, 0xf004, 0x0104, 0xfefc, 0x417c, 0xbe84, 0x041c, 0xfbe4,
69 0x083c, 0xf7c4, 0x0008, 0xfff8, 0x207c, 0xdf84, 0x020c, 0xfdf4,
70 0x17fc, 0xe804, 0x018c, 0xfe74, 0x617c, 0x9e84, 0x061c, 0xf9e4,
71 0x0c3c, 0xf3c4, 0x0084, 0xff7c, 0x307c, 0xcf84, 0x030c, 0xfcf4,
72 0x15fc, 0xea04, 0x0164, 0xfe9c, 0x597c, 0xa684, 0x059c, 0xfa64,
73 0x0b3c, 0xf4c4, 0x0068, 0xff98, 0x2c7c, 0xd384, 0x02cc, 0xfd34,
74 0x1dfc, 0xe204, 0x01ec, 0xfe14, 0x797c, 0x8684, 0x07bc, 0xf844,
75 0x0f3c, 0xf0c4, 0x00e4, 0xff1c, 0x3c7c, 0xc384, 0x03dc, 0xfc24,
76 0x11fc, 0xee04, 0x0124, 0xfedc, 0x497c, 0xb684, 0x049c, 0xfb64,
77 0x093c, 0xf6c4, 0x0028, 0xffd8, 0x247c, 0xdb84, 0x024c, 0xfdb4,
78 0x19fc, 0xe604, 0x01ac, 0xfe54, 0x697c, 0x9684, 0x069c, 0xf964,
79 0x0d3c, 0xf2c4, 0x00a4, 0xff5c, 0x347c, 0xcb84, 0x034c, 0xfcb4,
80 0x12fc, 0xed04, 0x0134, 0xfecc, 0x4d7c, 0xb284, 0x04dc, 0xfb24,
81 0x09bc, 0xf644, 0x0038, 0xffc8, 0x267c, 0xd984, 0x026c, 0xfd94,
82 0x1afc, 0xe504, 0x01ac, 0xfe54, 0x6d7c, 0x9284, 0x06dc, 0xf924,
83 0x0dbc, 0xf244, 0x00b4, 0xff4c, 0x367c, 0xc984, 0x036c, 0xfc94,
84 0x0f3c, 0xf0c4, 0x00f4, 0xff0c, 0x3e7c, 0xc184, 0x03dc, 0xfc24,
85 0x07bc, 0xf844, 0x0008, 0xfff8, 0x1efc, 0xe104, 0x01ec, 0xfe14,
86 0x16fc, 0xe904, 0x0174, 0xfe8c, 0x5d7c, 0xa284, 0x05dc, 0xfa24,
87 0x0bbc, 0xf444, 0x0078, 0xff88, 0x2e7c, 0xd184, 0x02ec, 0xfd14,
88 0x14fc, 0xeb04, 0x0154, 0xfeac, 0x557c, 0xaa84, 0x055c, 0xfaa4,
89 0x0abc, 0xf544, 0x0058, 0xffa8, 0x2a7c, 0xd584, 0x02ac, 0xfd54,
90 0x1cfc, 0xe304, 0x01cc, 0xfe34, 0x757c, 0x8a84, 0x075c, 0xf8a4,
91 0x0ebc, 0xf144, 0x00d4, 0xff2c, 0x3a7c, 0xc584, 0x039c, 0xfc64,
92 0x10fc, 0xef04, 0x0114, 0xfeec, 0x457c, 0xba84, 0x045c, 0xfba4,
93 0x08bc, 0xf744, 0x0018, 0xffe8, 0x227c, 0xdd84, 0x022c, 0xfdd4,
94 0x18fc, 0xe704, 0x018c, 0xfe74, 0x657c, 0x9a84, 0x065c, 0xf9a4,
95 0x0cbc, 0xf344, 0x0094, 0xff6c, 0x327c, 0xcd84, 0x032c, 0xfcd4
96};
97
98/* alaw -> ulaw */
99static char isdn_audio_alaw_to_ulaw[] =
100{
101 0xab, 0x2b, 0xe3, 0x63, 0x8b, 0x0b, 0xc9, 0x49,
102 0xba, 0x3a, 0xf6, 0x76, 0x9b, 0x1b, 0xd7, 0x57,
103 0xa3, 0x23, 0xdd, 0x5d, 0x83, 0x03, 0xc1, 0x41,
104 0xb2, 0x32, 0xeb, 0x6b, 0x93, 0x13, 0xcf, 0x4f,
105 0xaf, 0x2f, 0xe7, 0x67, 0x8f, 0x0f, 0xcd, 0x4d,
106 0xbe, 0x3e, 0xfe, 0x7e, 0x9f, 0x1f, 0xdb, 0x5b,
107 0xa7, 0x27, 0xdf, 0x5f, 0x87, 0x07, 0xc5, 0x45,
108 0xb6, 0x36, 0xef, 0x6f, 0x97, 0x17, 0xd3, 0x53,
109 0xa9, 0x29, 0xe1, 0x61, 0x89, 0x09, 0xc7, 0x47,
110 0xb8, 0x38, 0xf2, 0x72, 0x99, 0x19, 0xd5, 0x55,
111 0xa1, 0x21, 0xdc, 0x5c, 0x81, 0x01, 0xbf, 0x3f,
112 0xb0, 0x30, 0xe9, 0x69, 0x91, 0x11, 0xce, 0x4e,
113 0xad, 0x2d, 0xe5, 0x65, 0x8d, 0x0d, 0xcb, 0x4b,
114 0xbc, 0x3c, 0xfa, 0x7a, 0x9d, 0x1d, 0xd9, 0x59,
115 0xa5, 0x25, 0xde, 0x5e, 0x85, 0x05, 0xc3, 0x43,
116 0xb4, 0x34, 0xed, 0x6d, 0x95, 0x15, 0xd1, 0x51,
117 0xac, 0x2c, 0xe4, 0x64, 0x8c, 0x0c, 0xca, 0x4a,
118 0xbb, 0x3b, 0xf8, 0x78, 0x9c, 0x1c, 0xd8, 0x58,
119 0xa4, 0x24, 0xde, 0x5e, 0x84, 0x04, 0xc2, 0x42,
120 0xb3, 0x33, 0xec, 0x6c, 0x94, 0x14, 0xd0, 0x50,
121 0xb0, 0x30, 0xe8, 0x68, 0x90, 0x10, 0xce, 0x4e,
122 0xbf, 0x3f, 0xfe, 0x7e, 0xa0, 0x20, 0xdc, 0x5c,
123 0xa8, 0x28, 0xe0, 0x60, 0x88, 0x08, 0xc6, 0x46,
124 0xb7, 0x37, 0xf0, 0x70, 0x98, 0x18, 0xd4, 0x54,
125 0xaa, 0x2a, 0xe2, 0x62, 0x8a, 0x0a, 0xc8, 0x48,
126 0xb9, 0x39, 0xf4, 0x74, 0x9a, 0x1a, 0xd6, 0x56,
127 0xa2, 0x22, 0xdd, 0x5d, 0x82, 0x02, 0xc0, 0x40,
128 0xb1, 0x31, 0xea, 0x6a, 0x92, 0x12, 0xcf, 0x4f,
129 0xae, 0x2e, 0xe6, 0x66, 0x8e, 0x0e, 0xcc, 0x4c,
130 0xbd, 0x3d, 0xfc, 0x7c, 0x9e, 0x1e, 0xda, 0x5a,
131 0xa6, 0x26, 0xdf, 0x5f, 0x86, 0x06, 0xc4, 0x44,
132 0xb5, 0x35, 0xee, 0x6e, 0x96, 0x16, 0xd2, 0x52
133};
134
135/* ulaw -> alaw */
136static char isdn_audio_ulaw_to_alaw[] =
137{
138 0xab, 0x55, 0xd5, 0x15, 0x95, 0x75, 0xf5, 0x35,
139 0xb5, 0x45, 0xc5, 0x05, 0x85, 0x65, 0xe5, 0x25,
140 0xa5, 0x5d, 0xdd, 0x1d, 0x9d, 0x7d, 0xfd, 0x3d,
141 0xbd, 0x4d, 0xcd, 0x0d, 0x8d, 0x6d, 0xed, 0x2d,
142 0xad, 0x51, 0xd1, 0x11, 0x91, 0x71, 0xf1, 0x31,
143 0xb1, 0x41, 0xc1, 0x01, 0x81, 0x61, 0xe1, 0x21,
144 0x59, 0xd9, 0x19, 0x99, 0x79, 0xf9, 0x39, 0xb9,
145 0x49, 0xc9, 0x09, 0x89, 0x69, 0xe9, 0x29, 0xa9,
146 0xd7, 0x17, 0x97, 0x77, 0xf7, 0x37, 0xb7, 0x47,
147 0xc7, 0x07, 0x87, 0x67, 0xe7, 0x27, 0xa7, 0xdf,
148 0x9f, 0x7f, 0xff, 0x3f, 0xbf, 0x4f, 0xcf, 0x0f,
149 0x8f, 0x6f, 0xef, 0x2f, 0x53, 0x13, 0x73, 0x33,
150 0xb3, 0x43, 0xc3, 0x03, 0x83, 0x63, 0xe3, 0x23,
151 0xa3, 0x5b, 0xdb, 0x1b, 0x9b, 0x7b, 0xfb, 0x3b,
152 0xbb, 0xbb, 0x4b, 0x4b, 0xcb, 0xcb, 0x0b, 0x0b,
153 0x8b, 0x8b, 0x6b, 0x6b, 0xeb, 0xeb, 0x2b, 0x2b,
154 0xab, 0x54, 0xd4, 0x14, 0x94, 0x74, 0xf4, 0x34,
155 0xb4, 0x44, 0xc4, 0x04, 0x84, 0x64, 0xe4, 0x24,
156 0xa4, 0x5c, 0xdc, 0x1c, 0x9c, 0x7c, 0xfc, 0x3c,
157 0xbc, 0x4c, 0xcc, 0x0c, 0x8c, 0x6c, 0xec, 0x2c,
158 0xac, 0x50, 0xd0, 0x10, 0x90, 0x70, 0xf0, 0x30,
159 0xb0, 0x40, 0xc0, 0x00, 0x80, 0x60, 0xe0, 0x20,
160 0x58, 0xd8, 0x18, 0x98, 0x78, 0xf8, 0x38, 0xb8,
161 0x48, 0xc8, 0x08, 0x88, 0x68, 0xe8, 0x28, 0xa8,
162 0xd6, 0x16, 0x96, 0x76, 0xf6, 0x36, 0xb6, 0x46,
163 0xc6, 0x06, 0x86, 0x66, 0xe6, 0x26, 0xa6, 0xde,
164 0x9e, 0x7e, 0xfe, 0x3e, 0xbe, 0x4e, 0xce, 0x0e,
165 0x8e, 0x6e, 0xee, 0x2e, 0x52, 0x12, 0x72, 0x32,
166 0xb2, 0x42, 0xc2, 0x02, 0x82, 0x62, 0xe2, 0x22,
167 0xa2, 0x5a, 0xda, 0x1a, 0x9a, 0x7a, 0xfa, 0x3a,
168 0xba, 0xba, 0x4a, 0x4a, 0xca, 0xca, 0x0a, 0x0a,
169 0x8a, 0x8a, 0x6a, 0x6a, 0xea, 0xea, 0x2a, 0x2a
170};
171
172#define NCOEFF 8 /* number of frequencies to be analyzed */
173#define DTMF_TRESH 4000 /* above this is dtmf */
174#define SILENCE_TRESH 200 /* below this is silence */
175#define AMP_BITS 9 /* bits per sample, reduced to avoid overflow */
176#define LOGRP 0
177#define HIGRP 1
178
179/* For DTMF recognition:
180 * 2 * cos(2 * PI * k / N) precalculated for all k
181 */
182static int cos2pik[NCOEFF] =
183{
184 55813, 53604, 51193, 48591, 38114, 33057, 25889, 18332
185};
186
187static char dtmf_matrix[4][4] =
188{
189 {'1', '2', '3', 'A'},
190 {'4', '5', '6', 'B'},
191 {'7', '8', '9', 'C'},
192 {'*', '0', '#', 'D'}
193};
194
195static inline void
196isdn_audio_tlookup(const u_char *table, u_char *buff, unsigned long n)
197{
198#ifdef __i386__
199 unsigned long d0, d1, d2, d3;
200 __asm__ __volatile__(
201 "cld\n"
202 "1:\tlodsb\n\t"
203 "xlatb\n\t"
204 "stosb\n\t"
205 "loop 1b\n\t"
206 : "=&b"(d0), "=&c"(d1), "=&D"(d2), "=&S"(d3)
207 : "0"((long) table), "1"(n), "2"((long) buff), "3"((long) buff)
208 : "memory", "ax");
209#else
210 while (n--)
211 *buff = table[*(unsigned char *)buff], buff++;
212#endif
213}
214
215void
216isdn_audio_ulaw2alaw(unsigned char *buff, unsigned long len)
217{
218 isdn_audio_tlookup(isdn_audio_ulaw_to_alaw, buff, len);
219}
220
221void
222isdn_audio_alaw2ulaw(unsigned char *buff, unsigned long len)
223{
224 isdn_audio_tlookup(isdn_audio_alaw_to_ulaw, buff, len);
225}
226
227/*
228 * linear <-> adpcm conversion stuff
229 * Most parts from the mgetty-package.
230 * (C) by Gert Doering and Klaus Weidner
231 * Used by permission of Gert Doering
232 */
233
234
235#define ZEROTRAP /* turn on the trap as per the MIL-STD */
236#undef ZEROTRAP
237#define BIAS 0x84 /* define the add-in bias for 16 bit samples */
238#define CLIP 32635
239
240static unsigned char
241isdn_audio_linear2ulaw(int sample)
242{
243 static int exp_lut[256] =
244 {
245 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
246 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
247 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
248 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
249 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
250 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
251 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
252 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
253 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
254 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
255 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
256 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
257 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
258 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
259 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
260 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
261 };
262 int sign,
263 exponent,
264 mantissa;
265 unsigned char ulawbyte;
266
267 /* Get the sample into sign-magnitude. */
268 sign = (sample >> 8) & 0x80; /* set aside the sign */
269 if (sign != 0)
270 sample = -sample; /* get magnitude */
271 if (sample > CLIP)
272 sample = CLIP; /* clip the magnitude */
273
274 /* Convert from 16 bit linear to ulaw. */
275 sample = sample + BIAS;
276 exponent = exp_lut[(sample >> 7) & 0xFF];
277 mantissa = (sample >> (exponent + 3)) & 0x0F;
278 ulawbyte = ~(sign | (exponent << 4) | mantissa);
279#ifdef ZEROTRAP
280 /* optional CCITT trap */
281 if (ulawbyte == 0)
282 ulawbyte = 0x02;
283#endif
284 return (ulawbyte);
285}
286
287
288static int Mx[3][8] =
289{
290 {0x3800, 0x5600, 0, 0, 0, 0, 0, 0},
291 {0x399a, 0x3a9f, 0x4d14, 0x6607, 0, 0, 0, 0},
292 {0x3556, 0x3556, 0x399A, 0x3A9F, 0x4200, 0x4D14, 0x6607, 0x6607},
293};
294
295static int bitmask[9] =
296{
297 0, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff
298};
299
300static int
301isdn_audio_get_bits(adpcm_state * s, unsigned char **in, int *len)
302{
303 while (s->nleft < s->nbits) {
304 int d = *((*in)++);
305 (*len)--;
306 s->word = (s->word << 8) | d;
307 s->nleft += 8;
308 }
309 s->nleft -= s->nbits;
310 return (s->word >> s->nleft) & bitmask[s->nbits];
311}
312
313static void
314isdn_audio_put_bits(int data, int nbits, adpcm_state * s,
315 unsigned char **out, int *len)
316{
317 s->word = (s->word << nbits) | (data & bitmask[nbits]);
318 s->nleft += nbits;
319 while (s->nleft >= 8) {
320 int d = (s->word >> (s->nleft - 8));
321 *(out[0]++) = d & 255;
322 (*len)++;
323 s->nleft -= 8;
324 }
325}
326
327adpcm_state *
328isdn_audio_adpcm_init(adpcm_state * s, int nbits)
329{
330 if (!s)
331 s = (adpcm_state *) kmalloc(sizeof(adpcm_state), GFP_ATOMIC);
332 if (s) {
333 s->a = 0;
334 s->d = 5;
335 s->word = 0;
336 s->nleft = 0;
337 s->nbits = nbits;
338 }
339 return s;
340}
341
342dtmf_state *
343isdn_audio_dtmf_init(dtmf_state * s)
344{
345 if (!s)
346 s = (dtmf_state *) kmalloc(sizeof(dtmf_state), GFP_ATOMIC);
347 if (s) {
348 s->idx = 0;
349 s->last = ' ';
350 }
351 return s;
352}
353
354/*
355 * Decompression of adpcm data to a/u-law
356 *
357 */
358
359int
360isdn_audio_adpcm2xlaw(adpcm_state * s, int fmt, unsigned char *in,
361 unsigned char *out, int len)
362{
363 int a = s->a;
364 int d = s->d;
365 int nbits = s->nbits;
366 int olen = 0;
367
368 while (len) {
369 int e = isdn_audio_get_bits(s, &in, &len);
370 int sign;
371
372 if (nbits == 4 && e == 0)
373 d = 4;
374 sign = (e >> (nbits - 1)) ? -1 : 1;
375 e &= bitmask[nbits - 1];
376 a += sign * ((e << 1) + 1) * d >> 1;
377 if (d & 1)
378 a++;
379 if (fmt)
380 *out++ = isdn_audio_ulaw_to_alaw[
381 isdn_audio_linear2ulaw(a << 2)];
382 else
383 *out++ = isdn_audio_linear2ulaw(a << 2);
384 olen++;
385 d = (d * Mx[nbits - 2][e] + 0x2000) >> 14;
386 if (d < 5)
387 d = 5;
388 }
389 s->a = a;
390 s->d = d;
391 return olen;
392}
393
394int
395isdn_audio_2adpcm_flush(adpcm_state * s, unsigned char *out)
396{
397 int olen = 0;
398
399 if (s->nleft)
400 isdn_audio_put_bits(0, 8 - s->nleft, s, &out, &olen);
401 return olen;
402}
403
404int
405isdn_audio_xlaw2adpcm(adpcm_state * s, int fmt, unsigned char *in,
406 unsigned char *out, int len)
407{
408 int a = s->a;
409 int d = s->d;
410 int nbits = s->nbits;
411 int olen = 0;
412
413 while (len--) {
414 int e = 0,
415 nmax = 1 << (nbits - 1);
416 int sign,
417 delta;
418
419 if (fmt)
420 delta = (isdn_audio_alaw_to_s16[*in++] >> 2) - a;
421 else
422 delta = (isdn_audio_ulaw_to_s16[*in++] >> 2) - a;
423 if (delta < 0) {
424 e = nmax;
425 delta = -delta;
426 }
427 while (--nmax && delta > d) {
428 delta -= d;
429 e++;
430 }
431 if (nbits == 4 && ((e & 0x0f) == 0))
432 e = 8;
433 isdn_audio_put_bits(e, nbits, s, &out, &olen);
434 sign = (e >> (nbits - 1)) ? -1 : 1;
435 e &= bitmask[nbits - 1];
436
437 a += sign * ((e << 1) + 1) * d >> 1;
438 if (d & 1)
439 a++;
440 d = (d * Mx[nbits - 2][e] + 0x2000) >> 14;
441 if (d < 5)
442 d = 5;
443 }
444 s->a = a;
445 s->d = d;
446 return olen;
447}
448
449/*
450 * Goertzel algorithm.
451 * See http://ptolemy.eecs.berkeley.edu/~pino/Ptolemy/papers/96/dtmf_ict/
452 * for more info.
453 * Result is stored into an sk_buff and queued up for later
454 * evaluation.
455 */
456static void
457isdn_audio_goertzel(int *sample, modem_info * info)
458{
459 int sk,
460 sk1,
461 sk2;
462 int k,
463 n;
464 struct sk_buff *skb;
465 int *result;
466
467 skb = dev_alloc_skb(sizeof(int) * NCOEFF);
468 if (!skb) {
469 printk(KERN_WARNING
470 "isdn_audio: Could not alloc DTMF result for ttyI%d\n",
471 info->line);
472 return;
473 }
474 result = (int *) skb_put(skb, sizeof(int) * NCOEFF);
475 for (k = 0; k < NCOEFF; k++) {
476 sk = sk1 = sk2 = 0;
477 for (n = 0; n < DTMF_NPOINTS; n++) {
478 sk = sample[n] + ((cos2pik[k] * sk1) >> 15) - sk2;
479 sk2 = sk1;
480 sk1 = sk;
481 }
482 /* Avoid overflows */
483 sk >>= 1;
484 sk2 >>= 1;
485 /* compute |X(k)|**2 */
486 /* report overflows. This should not happen. */
487 /* Comment this out if desired */
488 if (sk < -32768 || sk > 32767)
489 printk(KERN_DEBUG
490 "isdn_audio: dtmf goertzel overflow, sk=%d\n", sk);
491 if (sk2 < -32768 || sk2 > 32767)
492 printk(KERN_DEBUG
493 "isdn_audio: dtmf goertzel overflow, sk2=%d\n", sk2);
494 result[k] =
495 ((sk * sk) >> AMP_BITS) -
496 ((((cos2pik[k] * sk) >> 15) * sk2) >> AMP_BITS) +
497 ((sk2 * sk2) >> AMP_BITS);
498 }
499 skb_queue_tail(&info->dtmf_queue, skb);
500 isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
501}
502
503void
504isdn_audio_eval_dtmf(modem_info * info)
505{
506 struct sk_buff *skb;
507 int *result;
508 dtmf_state *s;
509 int silence;
510 int i;
511 int di;
512 int ch;
513 int grp[2];
514 char what;
515 char *p;
516 int thresh;
517
518 while ((skb = skb_dequeue(&info->dtmf_queue))) {
519 result = (int *) skb->data;
520 s = info->dtmf_state;
521 grp[LOGRP] = grp[HIGRP] = -1;
522 silence = 0;
523 thresh = 0;
524 for (i = 0; i < NCOEFF; i++) {
525 if (result[i] > DTMF_TRESH) {
526 if (result[i] > thresh)
527 thresh = result[i];
528 }
529 else if (result[i] < SILENCE_TRESH)
530 silence++;
531 }
532 if (silence == NCOEFF)
533 what = ' ';
534 else {
535 if (thresh > 0) {
536 thresh = thresh >> 4; /* touchtones must match within 12 dB */
537 for (i = 0; i < NCOEFF; i++) {
538 if (result[i] < thresh)
539 continue; /* ignore */
540 /* good level found. This is allowed only one time per group */
541 if (i < NCOEFF / 2) {
542 /* lowgroup*/
543 if (grp[LOGRP] >= 0) {
544 // Bad. Another tone found. */
545 grp[LOGRP] = -1;
546 break;
547 }
548 else
549 grp[LOGRP] = i;
550 }
551 else { /* higroup */
552 if (grp[HIGRP] >= 0) { // Bad. Another tone found. */
553 grp[HIGRP] = -1;
554 break;
555 }
556 else
557 grp[HIGRP] = i - NCOEFF/2;
558 }
559 }
560 if ((grp[LOGRP] >= 0) && (grp[HIGRP] >= 0)) {
561 what = dtmf_matrix[grp[LOGRP]][grp[HIGRP]];
562 if (s->last != ' ' && s->last != '.')
563 s->last = what; /* min. 1 non-DTMF between DTMF */
564 } else
565 what = '.';
566 }
567 else
568 what = '.';
569 }
570 if ((what != s->last) && (what != ' ') && (what != '.')) {
571 printk(KERN_DEBUG "dtmf: tt='%c'\n", what);
572 p = skb->data;
573 *p++ = 0x10;
574 *p = what;
575 skb_trim(skb, 2);
576 ISDN_AUDIO_SKB_DLECOUNT(skb) = 0;
577 ISDN_AUDIO_SKB_LOCK(skb) = 0;
578 di = info->isdn_driver;
579 ch = info->isdn_channel;
580 __skb_queue_tail(&dev->drv[di]->rpqueue[ch], skb);
581 dev->drv[di]->rcvcount[ch] += 2;
582 /* Schedule dequeuing */
583 if ((dev->modempoll) && (info->rcvsched))
584 isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
585 wake_up_interruptible(&dev->drv[di]->rcv_waitq[ch]);
586 } else
587 kfree_skb(skb);
588 s->last = what;
589 }
590}
591
592/*
593 * Decode DTMF tones, queue result in separate sk_buf for
594 * later examination.
595 * Parameters:
596 * s = pointer to state-struct.
597 * buf = input audio data
598 * len = size of audio data.
599 * fmt = audio data format (0 = ulaw, 1 = alaw)
600 */
601void
602isdn_audio_calc_dtmf(modem_info * info, unsigned char *buf, int len, int fmt)
603{
604 dtmf_state *s = info->dtmf_state;
605 int i;
606 int c;
607
608 while (len) {
609 c = DTMF_NPOINTS - s->idx;
610 if (c > len)
611 c = len;
612 if (c <= 0)
613 break;
614 for (i = 0; i < c; i++) {
615 if (fmt)
616 s->buf[s->idx++] =
617 isdn_audio_alaw_to_s16[*buf++] >> (15 - AMP_BITS);
618 else
619 s->buf[s->idx++] =
620 isdn_audio_ulaw_to_s16[*buf++] >> (15 - AMP_BITS);
621 }
622 if (s->idx == DTMF_NPOINTS) {
623 isdn_audio_goertzel(s->buf, info);
624 s->idx = 0;
625 }
626 len -= c;
627 }
628}
629
630silence_state *
631isdn_audio_silence_init(silence_state * s)
632{
633 if (!s)
634 s = (silence_state *) kmalloc(sizeof(silence_state), GFP_ATOMIC);
635 if (s) {
636 s->idx = 0;
637 s->state = 0;
638 }
639 return s;
640}
641
642void
643isdn_audio_calc_silence(modem_info * info, unsigned char *buf, int len, int fmt)
644{
645 silence_state *s = info->silence_state;
646 int i;
647 signed char c;
648
649 if (!info->emu.vpar[1]) return;
650
651 for (i = 0; i < len; i++) {
652 if (fmt)
653 c = isdn_audio_alaw_to_ulaw[*buf++];
654 else
655 c = *buf++;
656
657 if (c > 0) c -= 128;
658 c = abs(c);
659
660 if (c > (info->emu.vpar[1] * 4)) {
661 s->idx = 0;
662 s->state = 1;
663 } else {
664 if (s->idx < 210000) s->idx++;
665 }
666 }
667}
668
669void
670isdn_audio_put_dle_code(modem_info * info, u_char code)
671{
672 struct sk_buff *skb;
673 int di;
674 int ch;
675 char *p;
676
677 skb = dev_alloc_skb(2);
678 if (!skb) {
679 printk(KERN_WARNING
680 "isdn_audio: Could not alloc skb for ttyI%d\n",
681 info->line);
682 return;
683 }
684 p = (char *) skb_put(skb, 2);
685 p[0] = 0x10;
686 p[1] = code;
687 ISDN_AUDIO_SKB_DLECOUNT(skb) = 0;
688 ISDN_AUDIO_SKB_LOCK(skb) = 0;
689 di = info->isdn_driver;
690 ch = info->isdn_channel;
691 __skb_queue_tail(&dev->drv[di]->rpqueue[ch], skb);
692 dev->drv[di]->rcvcount[ch] += 2;
693 /* Schedule dequeuing */
694 if ((dev->modempoll) && (info->rcvsched))
695 isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
696 wake_up_interruptible(&dev->drv[di]->rcv_waitq[ch]);
697}
698
699void
700isdn_audio_eval_silence(modem_info * info)
701{
702 silence_state *s = info->silence_state;
703 char what;
704
705 what = ' ';
706
707 if (s->idx > (info->emu.vpar[2] * 800)) {
708 s->idx = 0;
709 if (!s->state) { /* silence from beginning of rec */
710 what = 's';
711 } else {
712 what = 'q';
713 }
714 }
715 if ((what == 's') || (what == 'q')) {
716 printk(KERN_DEBUG "ttyI%d: %s\n", info->line,
717 (what=='s') ? "silence":"quiet");
718 isdn_audio_put_dle_code(info, what);
719 }
720}
diff --git a/drivers/isdn/i4l/isdn_audio.h b/drivers/isdn/i4l/isdn_audio.h
new file mode 100644
index 000000000000..5a977b21dcfa
--- /dev/null
+++ b/drivers/isdn/i4l/isdn_audio.h
@@ -0,0 +1,45 @@
1/* $Id: isdn_audio.h,v 1.1.2.2 2004/01/12 22:37:18 keil Exp $
2 *
3 * Linux ISDN subsystem, audio conversion and compression (linklevel).
4 *
5 * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
6 *
7 * This software may be used and distributed according to the terms
8 * of the GNU General Public License, incorporated herein by reference.
9 *
10 */
11
12#define DTMF_NPOINTS 205 /* Number of samples for DTMF recognition */
13typedef struct adpcm_state {
14 int a;
15 int d;
16 int word;
17 int nleft;
18 int nbits;
19} adpcm_state;
20
21typedef struct dtmf_state {
22 char last;
23 char llast;
24 int idx;
25 int buf[DTMF_NPOINTS];
26} dtmf_state;
27
28typedef struct silence_state {
29 int state;
30 unsigned int idx;
31} silence_state;
32
33extern void isdn_audio_ulaw2alaw(unsigned char *, unsigned long);
34extern void isdn_audio_alaw2ulaw(unsigned char *, unsigned long);
35extern adpcm_state *isdn_audio_adpcm_init(adpcm_state *, int);
36extern int isdn_audio_adpcm2xlaw(adpcm_state *, int, unsigned char *, unsigned char *, int);
37extern int isdn_audio_xlaw2adpcm(adpcm_state *, int, unsigned char *, unsigned char *, int);
38extern int isdn_audio_2adpcm_flush(adpcm_state * s, unsigned char *out);
39extern void isdn_audio_calc_dtmf(modem_info *, unsigned char *, int, int);
40extern void isdn_audio_eval_dtmf(modem_info *);
41dtmf_state *isdn_audio_dtmf_init(dtmf_state *);
42extern void isdn_audio_calc_silence(modem_info *, unsigned char *, int, int);
43extern void isdn_audio_eval_silence(modem_info *);
44silence_state *isdn_audio_silence_init(silence_state *);
45extern void isdn_audio_put_dle_code(modem_info *, u_char);
diff --git a/drivers/isdn/i4l/isdn_bsdcomp.c b/drivers/isdn/i4l/isdn_bsdcomp.c
new file mode 100644
index 000000000000..baf4bcad9bf9
--- /dev/null
+++ b/drivers/isdn/i4l/isdn_bsdcomp.c
@@ -0,0 +1,937 @@
1/*
2 * BSD compression module
3 *
4 * Patched version for ISDN syncPPP written 1997/1998 by Michael Hipp
5 * The whole module is now SKB based.
6 *
7 */
8
9/*
10 * Update: The Berkeley copyright was changed, and the change
11 * is retroactive to all "true" BSD software (ie everything
12 * from UCB as opposed to other peoples code that just carried
13 * the same license). The new copyright doesn't clash with the
14 * GPL, so the module-only restriction has been removed..
15 */
16
17/*
18 * Original copyright notice:
19 *
20 * Copyright (c) 1985, 1986 The Regents of the University of California.
21 * All rights reserved.
22 *
23 * This code is derived from software contributed to Berkeley by
24 * James A. Woods, derived from original work by Spencer Thomas
25 * and Joseph Orost.
26 *
27 * Redistribution and use in source and binary forms, with or without
28 * modification, are permitted provided that the following conditions
29 * are met:
30 * 1. Redistributions of source code must retain the above copyright
31 * notice, this list of conditions and the following disclaimer.
32 * 2. Redistributions in binary form must reproduce the above copyright
33 * notice, this list of conditions and the following disclaimer in the
34 * documentation and/or other materials provided with the distribution.
35 * 3. All advertising materials mentioning features or use of this software
36 * must display the following acknowledgement:
37 * This product includes software developed by the University of
38 * California, Berkeley and its contributors.
39 * 4. Neither the name of the University nor the names of its contributors
40 * may be used to endorse or promote products derived from this software
41 * without specific prior written permission.
42 *
43 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
44 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
45 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
47 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
48 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
49 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
50 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
51 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
52 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
53 * SUCH DAMAGE.
54 */
55
56#include <linux/module.h>
57#include <linux/init.h>
58#include <linux/kernel.h>
59#include <linux/sched.h>
60#include <linux/types.h>
61#include <linux/fcntl.h>
62#include <linux/interrupt.h>
63#include <linux/ptrace.h>
64#include <linux/ioport.h>
65#include <linux/in.h>
66#include <linux/slab.h>
67#include <linux/tty.h>
68#include <linux/errno.h>
69#include <linux/string.h> /* used in new tty drivers */
70#include <linux/signal.h> /* used in new tty drivers */
71#include <linux/bitops.h>
72
73#include <asm/system.h>
74#include <asm/byteorder.h>
75#include <asm/types.h>
76
77#include <linux/if.h>
78
79#include <linux/if_ether.h>
80#include <linux/netdevice.h>
81#include <linux/skbuff.h>
82#include <linux/inet.h>
83#include <linux/ioctl.h>
84#include <linux/vmalloc.h>
85
86#include <linux/ppp_defs.h>
87
88#include <linux/isdn.h>
89#include <linux/isdn_ppp.h>
90#include <linux/ip.h>
91#include <linux/tcp.h>
92#include <linux/if_arp.h>
93#include <linux/ppp-comp.h>
94
95#include "isdn_ppp.h"
96
97MODULE_DESCRIPTION("ISDN4Linux: BSD Compression for PPP over ISDN");
98MODULE_LICENSE("Dual BSD/GPL");
99
100#define BSD_VERSION(x) ((x) >> 5)
101#define BSD_NBITS(x) ((x) & 0x1F)
102
103#define BSD_CURRENT_VERSION 1
104
105#define DEBUG 1
106
107/*
108 * A dictionary for doing BSD compress.
109 */
110
111struct bsd_dict {
112 u32 fcode;
113 u16 codem1; /* output of hash table -1 */
114 u16 cptr; /* map code to hash table entry */
115};
116
117struct bsd_db {
118 int totlen; /* length of this structure */
119 unsigned int hsize; /* size of the hash table */
120 unsigned char hshift; /* used in hash function */
121 unsigned char n_bits; /* current bits/code */
122 unsigned char maxbits; /* maximum bits/code */
123 unsigned char debug; /* non-zero if debug desired */
124 unsigned char unit; /* ppp unit number */
125 u16 seqno; /* sequence # of next packet */
126 unsigned int mru; /* size of receive (decompress) bufr */
127 unsigned int maxmaxcode; /* largest valid code */
128 unsigned int max_ent; /* largest code in use */
129 unsigned int in_count; /* uncompressed bytes, aged */
130 unsigned int bytes_out; /* compressed bytes, aged */
131 unsigned int ratio; /* recent compression ratio */
132 unsigned int checkpoint; /* when to next check the ratio */
133 unsigned int clear_count; /* times dictionary cleared */
134 unsigned int incomp_count; /* incompressible packets */
135 unsigned int incomp_bytes; /* incompressible bytes */
136 unsigned int uncomp_count; /* uncompressed packets */
137 unsigned int uncomp_bytes; /* uncompressed bytes */
138 unsigned int comp_count; /* compressed packets */
139 unsigned int comp_bytes; /* compressed bytes */
140 unsigned short *lens; /* array of lengths of codes */
141 struct bsd_dict *dict; /* dictionary */
142 int xmit;
143};
144
145#define BSD_OVHD 2 /* BSD compress overhead/packet */
146#define MIN_BSD_BITS 9
147#define BSD_INIT_BITS MIN_BSD_BITS
148#define MAX_BSD_BITS 15
149
150/*
151 * the next two codes should not be changed lightly, as they must not
152 * lie within the contiguous general code space.
153 */
154#define CLEAR 256 /* table clear output code */
155#define FIRST 257 /* first free entry */
156#define LAST 255
157
158#define MAXCODE(b) ((1 << (b)) - 1)
159#define BADCODEM1 MAXCODE(MAX_BSD_BITS);
160
161#define BSD_HASH(prefix,suffix,hshift) ((((unsigned long)(suffix))<<(hshift)) \
162 ^ (unsigned long)(prefix))
163#define BSD_KEY(prefix,suffix) ((((unsigned long)(suffix)) << 16) \
164 + (unsigned long)(prefix))
165
166#define CHECK_GAP 10000 /* Ratio check interval */
167
168#define RATIO_SCALE_LOG 8
169#define RATIO_SCALE (1<<RATIO_SCALE_LOG)
170#define RATIO_MAX (0x7fffffff>>RATIO_SCALE_LOG)
171
172/*
173 * clear the dictionary
174 */
175
176static void bsd_clear(struct bsd_db *db)
177{
178 db->clear_count++;
179 db->max_ent = FIRST-1;
180 db->n_bits = BSD_INIT_BITS;
181 db->bytes_out = 0;
182 db->in_count = 0;
183 db->incomp_count = 0;
184 db->ratio = 0;
185 db->checkpoint = CHECK_GAP;
186}
187
188/*
189 * If the dictionary is full, then see if it is time to reset it.
190 *
191 * Compute the compression ratio using fixed-point arithmetic
192 * with 8 fractional bits.
193 *
194 * Since we have an infinite stream instead of a single file,
195 * watch only the local compression ratio.
196 *
197 * Since both peers must reset the dictionary at the same time even in
198 * the absence of CLEAR codes (while packets are incompressible), they
199 * must compute the same ratio.
200 */
201static int bsd_check (struct bsd_db *db) /* 1=output CLEAR */
202{
203 unsigned int new_ratio;
204
205 if (db->in_count >= db->checkpoint)
206 {
207 /* age the ratio by limiting the size of the counts */
208 if (db->in_count >= RATIO_MAX || db->bytes_out >= RATIO_MAX)
209 {
210 db->in_count -= (db->in_count >> 2);
211 db->bytes_out -= (db->bytes_out >> 2);
212 }
213
214 db->checkpoint = db->in_count + CHECK_GAP;
215
216 if (db->max_ent >= db->maxmaxcode)
217 {
218 /* Reset the dictionary only if the ratio is worse,
219 * or if it looks as if it has been poisoned
220 * by incompressible data.
221 *
222 * This does not overflow, because
223 * db->in_count <= RATIO_MAX.
224 */
225
226 new_ratio = db->in_count << RATIO_SCALE_LOG;
227 if (db->bytes_out != 0)
228 {
229 new_ratio /= db->bytes_out;
230 }
231
232 if (new_ratio < db->ratio || new_ratio < 1 * RATIO_SCALE)
233 {
234 bsd_clear (db);
235 return 1;
236 }
237 db->ratio = new_ratio;
238 }
239 }
240 return 0;
241}
242
243/*
244 * Return statistics.
245 */
246
247static void bsd_stats (void *state, struct compstat *stats)
248{
249 struct bsd_db *db = (struct bsd_db *) state;
250
251 stats->unc_bytes = db->uncomp_bytes;
252 stats->unc_packets = db->uncomp_count;
253 stats->comp_bytes = db->comp_bytes;
254 stats->comp_packets = db->comp_count;
255 stats->inc_bytes = db->incomp_bytes;
256 stats->inc_packets = db->incomp_count;
257 stats->in_count = db->in_count;
258 stats->bytes_out = db->bytes_out;
259}
260
261/*
262 * Reset state, as on a CCP ResetReq.
263 */
264static void bsd_reset (void *state,unsigned char code, unsigned char id,
265 unsigned char *data, unsigned len,
266 struct isdn_ppp_resetparams *rsparm)
267{
268 struct bsd_db *db = (struct bsd_db *) state;
269
270 bsd_clear(db);
271 db->seqno = 0;
272 db->clear_count = 0;
273}
274
275/*
276 * Release the compression structure
277 */
278static void bsd_free (void *state)
279{
280 struct bsd_db *db = (struct bsd_db *) state;
281
282 if (db) {
283 /*
284 * Release the dictionary
285 */
286 if (db->dict) {
287 vfree (db->dict);
288 db->dict = NULL;
289 }
290
291 /*
292 * Release the string buffer
293 */
294 if (db->lens) {
295 vfree (db->lens);
296 db->lens = NULL;
297 }
298
299 /*
300 * Finally release the structure itself.
301 */
302 kfree (db);
303 }
304}
305
306
307/*
308 * Allocate space for a (de) compressor.
309 */
310static void *bsd_alloc (struct isdn_ppp_comp_data *data)
311{
312 int bits;
313 unsigned int hsize, hshift, maxmaxcode;
314 struct bsd_db *db;
315 int decomp;
316
317 static unsigned int htab[][2] = {
318 { 5003 , 4 } , { 5003 , 4 } , { 5003 , 4 } , { 5003 , 4 } ,
319 { 9001 , 5 } , { 18013 , 6 } , { 35023 , 7 } , { 69001 , 8 }
320 };
321
322 if (data->optlen != 1 || data->num != CI_BSD_COMPRESS
323 || BSD_VERSION(data->options[0]) != BSD_CURRENT_VERSION)
324 return NULL;
325
326 bits = BSD_NBITS(data->options[0]);
327
328 if(bits < 9 || bits > 15)
329 return NULL;
330
331 hsize = htab[bits-9][0];
332 hshift = htab[bits-9][1];
333
334 /*
335 * Allocate the main control structure for this instance.
336 */
337 maxmaxcode = MAXCODE(bits);
338 db = (struct bsd_db *) kmalloc (sizeof (struct bsd_db),GFP_KERNEL);
339 if (!db)
340 return NULL;
341
342 memset (db, 0, sizeof(struct bsd_db));
343
344 db->xmit = data->flags & IPPP_COMP_FLAG_XMIT;
345 decomp = db->xmit ? 0 : 1;
346
347 /*
348 * Allocate space for the dictionary. This may be more than one page in
349 * length.
350 */
351 db->dict = (struct bsd_dict *) vmalloc (hsize * sizeof (struct bsd_dict));
352 if (!db->dict) {
353 bsd_free (db);
354 return NULL;
355 }
356
357 /*
358 * If this is the compression buffer then there is no length data.
359 * For decompression, the length information is needed as well.
360 */
361 if (!decomp)
362 db->lens = NULL;
363 else {
364 db->lens = (unsigned short *) vmalloc ((maxmaxcode + 1) *
365 sizeof (db->lens[0]));
366 if (!db->lens) {
367 bsd_free (db);
368 return (NULL);
369 }
370 }
371
372 /*
373 * Initialize the data information for the compression code
374 */
375 db->totlen = sizeof (struct bsd_db) + (sizeof (struct bsd_dict) * hsize);
376 db->hsize = hsize;
377 db->hshift = hshift;
378 db->maxmaxcode = maxmaxcode;
379 db->maxbits = bits;
380
381 return (void *) db;
382}
383
384/*
385 * Initialize the database.
386 */
387static int bsd_init (void *state, struct isdn_ppp_comp_data *data, int unit, int debug)
388{
389 struct bsd_db *db = state;
390 int indx;
391 int decomp;
392
393 if(!state || !data) {
394 printk(KERN_ERR "isdn_bsd_init: [%d] ERR, state %lx data %lx\n",unit,(long)state,(long)data);
395 return 0;
396 }
397
398 decomp = db->xmit ? 0 : 1;
399
400 if (data->optlen != 1 || data->num != CI_BSD_COMPRESS
401 || (BSD_VERSION(data->options[0]) != BSD_CURRENT_VERSION)
402 || (BSD_NBITS(data->options[0]) != db->maxbits)
403 || (decomp && db->lens == NULL)) {
404 printk(KERN_ERR "isdn_bsd: %d %d %d %d %lx\n",data->optlen,data->num,data->options[0],decomp,(unsigned long)db->lens);
405 return 0;
406 }
407
408 if (decomp)
409 for(indx=LAST;indx>=0;indx--)
410 db->lens[indx] = 1;
411
412 indx = db->hsize;
413 while (indx-- != 0) {
414 db->dict[indx].codem1 = BADCODEM1;
415 db->dict[indx].cptr = 0;
416 }
417
418 db->unit = unit;
419 db->mru = 0;
420
421 db->debug = 1;
422
423 bsd_reset(db,0,0,NULL,0,NULL);
424
425 return 1;
426}
427
428/*
429 * Obtain pointers to the various structures in the compression tables
430 */
431
432#define dict_ptrx(p,idx) &(p->dict[idx])
433#define lens_ptrx(p,idx) &(p->lens[idx])
434
435#ifdef DEBUG
436static unsigned short *lens_ptr(struct bsd_db *db, int idx)
437{
438 if ((unsigned int) idx > (unsigned int) db->maxmaxcode) {
439 printk (KERN_DEBUG "<9>ppp: lens_ptr(%d) > max\n", idx);
440 idx = 0;
441 }
442 return lens_ptrx (db, idx);
443}
444
445static struct bsd_dict *dict_ptr(struct bsd_db *db, int idx)
446{
447 if ((unsigned int) idx >= (unsigned int) db->hsize) {
448 printk (KERN_DEBUG "<9>ppp: dict_ptr(%d) > max\n", idx);
449 idx = 0;
450 }
451 return dict_ptrx (db, idx);
452}
453
454#else
455#define lens_ptr(db,idx) lens_ptrx(db,idx)
456#define dict_ptr(db,idx) dict_ptrx(db,idx)
457#endif
458
459/*
460 * compress a packet
461 */
462static int bsd_compress (void *state, struct sk_buff *skb_in, struct sk_buff *skb_out,int proto)
463{
464 struct bsd_db *db;
465 int hshift;
466 unsigned int max_ent;
467 unsigned int n_bits;
468 unsigned int bitno;
469 unsigned long accm;
470 int ent;
471 unsigned long fcode;
472 struct bsd_dict *dictp;
473 unsigned char c;
474 int hval,disp,ilen,mxcode;
475 unsigned char *rptr = skb_in->data;
476 int isize = skb_in->len;
477
478#define OUTPUT(ent) \
479 { \
480 bitno -= n_bits; \
481 accm |= ((ent) << bitno); \
482 do { \
483 if(skb_out && skb_tailroom(skb_out) > 0) \
484 *(skb_put(skb_out,1)) = (unsigned char) (accm>>24); \
485 accm <<= 8; \
486 bitno += 8; \
487 } while (bitno <= 24); \
488 }
489
490 /*
491 * If the protocol is not in the range we're interested in,
492 * just return without compressing the packet. If it is,
493 * the protocol becomes the first byte to compress.
494 */
495 printk(KERN_DEBUG "bsd_compress called with %x\n",proto);
496
497 ent = proto;
498 if (proto < 0x21 || proto > 0xf9 || !(proto & 0x1) )
499 return 0;
500
501 db = (struct bsd_db *) state;
502 hshift = db->hshift;
503 max_ent = db->max_ent;
504 n_bits = db->n_bits;
505 bitno = 32;
506 accm = 0;
507 mxcode = MAXCODE (n_bits);
508
509 /* This is the PPP header information */
510 if(skb_out && skb_tailroom(skb_out) >= 2) {
511 char *v = skb_put(skb_out,2);
512 /* we only push our own data on the header,
513 AC,PC and protos is pushed by caller */
514 v[0] = db->seqno >> 8;
515 v[1] = db->seqno;
516 }
517
518 ilen = ++isize; /* This is off by one, but that is what is in draft! */
519
520 while (--ilen > 0) {
521 c = *rptr++;
522 fcode = BSD_KEY (ent, c);
523 hval = BSD_HASH (ent, c, hshift);
524 dictp = dict_ptr (db, hval);
525
526 /* Validate and then check the entry. */
527 if (dictp->codem1 >= max_ent)
528 goto nomatch;
529
530 if (dictp->fcode == fcode) {
531 ent = dictp->codem1 + 1;
532 continue; /* found (prefix,suffix) */
533 }
534
535 /* continue probing until a match or invalid entry */
536 disp = (hval == 0) ? 1 : hval;
537
538 do {
539 hval += disp;
540 if (hval >= db->hsize)
541 hval -= db->hsize;
542 dictp = dict_ptr (db, hval);
543 if (dictp->codem1 >= max_ent)
544 goto nomatch;
545 } while (dictp->fcode != fcode);
546
547 ent = dictp->codem1 + 1; /* finally found (prefix,suffix) */
548 continue;
549
550nomatch:
551 OUTPUT(ent); /* output the prefix */
552
553 /* code -> hashtable */
554 if (max_ent < db->maxmaxcode) {
555 struct bsd_dict *dictp2;
556 struct bsd_dict *dictp3;
557 int indx;
558
559 /* expand code size if needed */
560 if (max_ent >= mxcode) {
561 db->n_bits = ++n_bits;
562 mxcode = MAXCODE (n_bits);
563 }
564
565 /*
566 * Invalidate old hash table entry using
567 * this code, and then take it over.
568 */
569 dictp2 = dict_ptr (db, max_ent + 1);
570 indx = dictp2->cptr;
571 dictp3 = dict_ptr (db, indx);
572
573 if (dictp3->codem1 == max_ent)
574 dictp3->codem1 = BADCODEM1;
575
576 dictp2->cptr = hval;
577 dictp->codem1 = max_ent;
578 dictp->fcode = fcode;
579 db->max_ent = ++max_ent;
580
581 if (db->lens) {
582 unsigned short *len1 = lens_ptr (db, max_ent);
583 unsigned short *len2 = lens_ptr (db, ent);
584 *len1 = *len2 + 1;
585 }
586 }
587 ent = c;
588 }
589
590 OUTPUT(ent); /* output the last code */
591
592 if(skb_out)
593 db->bytes_out += skb_out->len; /* Do not count bytes from here */
594 db->uncomp_bytes += isize;
595 db->in_count += isize;
596 ++db->uncomp_count;
597 ++db->seqno;
598
599 if (bitno < 32)
600 ++db->bytes_out; /* must be set before calling bsd_check */
601
602 /*
603 * Generate the clear command if needed
604 */
605
606 if (bsd_check(db))
607 OUTPUT (CLEAR);
608
609 /*
610 * Pad dribble bits of last code with ones.
611 * Do not emit a completely useless byte of ones.
612 */
613 if (bitno < 32 && skb_out && skb_tailroom(skb_out) > 0)
614 *(skb_put(skb_out,1)) = (unsigned char) ((accm | (0xff << (bitno-8))) >> 24);
615
616 /*
617 * Increase code size if we would have without the packet
618 * boundary because the decompressor will do so.
619 */
620 if (max_ent >= mxcode && max_ent < db->maxmaxcode)
621 db->n_bits++;
622
623 /* If output length is too large then this is an incompressible frame. */
624 if (!skb_out || (skb_out && skb_out->len >= skb_in->len) ) {
625 ++db->incomp_count;
626 db->incomp_bytes += isize;
627 return 0;
628 }
629
630 /* Count the number of compressed frames */
631 ++db->comp_count;
632 db->comp_bytes += skb_out->len;
633 return skb_out->len;
634
635#undef OUTPUT
636}
637
638/*
639 * Update the "BSD Compress" dictionary on the receiver for
640 * incompressible data by pretending to compress the incoming data.
641 */
642static void bsd_incomp (void *state, struct sk_buff *skb_in,int proto)
643{
644 bsd_compress (state, skb_in, NULL, proto);
645}
646
647/*
648 * Decompress "BSD Compress".
649 */
650static int bsd_decompress (void *state, struct sk_buff *skb_in, struct sk_buff *skb_out,
651 struct isdn_ppp_resetparams *rsparm)
652{
653 struct bsd_db *db;
654 unsigned int max_ent;
655 unsigned long accm;
656 unsigned int bitno; /* 1st valid bit in accm */
657 unsigned int n_bits;
658 unsigned int tgtbitno; /* bitno when we have a code */
659 struct bsd_dict *dictp;
660 int seq;
661 unsigned int incode;
662 unsigned int oldcode;
663 unsigned int finchar;
664 unsigned char *p,*ibuf;
665 int ilen;
666 int codelen;
667 int extra;
668
669 db = (struct bsd_db *) state;
670 max_ent = db->max_ent;
671 accm = 0;
672 bitno = 32; /* 1st valid bit in accm */
673 n_bits = db->n_bits;
674 tgtbitno = 32 - n_bits; /* bitno when we have a code */
675
676 printk(KERN_DEBUG "bsd_decompress called\n");
677
678 if(!skb_in || !skb_out) {
679 printk(KERN_ERR "bsd_decompress called with NULL parameter\n");
680 return DECOMP_ERROR;
681 }
682
683 /*
684 * Get the sequence number.
685 */
686 if( (p = skb_pull(skb_in,2)) == NULL) {
687 return DECOMP_ERROR;
688 }
689 p-=2;
690 seq = (p[0] << 8) + p[1];
691 ilen = skb_in->len;
692 ibuf = skb_in->data;
693
694 /*
695 * Check the sequence number and give up if it differs from
696 * the value we're expecting.
697 */
698 if (seq != db->seqno) {
699 if (db->debug) {
700 printk(KERN_DEBUG "bsd_decomp%d: bad sequence # %d, expected %d\n",
701 db->unit, seq, db->seqno - 1);
702 }
703 return DECOMP_ERROR;
704 }
705
706 ++db->seqno;
707 db->bytes_out += ilen;
708
709 if(skb_tailroom(skb_out) > 0)
710 *(skb_put(skb_out,1)) = 0;
711 else
712 return DECOMP_ERR_NOMEM;
713
714 oldcode = CLEAR;
715
716 /*
717 * Keep the checkpoint correctly so that incompressible packets
718 * clear the dictionary at the proper times.
719 */
720
721 for (;;) {
722 if (ilen-- <= 0) {
723 db->in_count += (skb_out->len - 1); /* don't count the header */
724 break;
725 }
726
727 /*
728 * Accumulate bytes until we have a complete code.
729 * Then get the next code, relying on the 32-bit,
730 * unsigned accm to mask the result.
731 */
732
733 bitno -= 8;
734 accm |= *ibuf++ << bitno;
735 if (tgtbitno < bitno)
736 continue;
737
738 incode = accm >> tgtbitno;
739 accm <<= n_bits;
740 bitno += n_bits;
741
742 /*
743 * The dictionary must only be cleared at the end of a packet.
744 */
745
746 if (incode == CLEAR) {
747 if (ilen > 0) {
748 if (db->debug)
749 printk(KERN_DEBUG "bsd_decomp%d: bad CLEAR\n", db->unit);
750 return DECOMP_FATALERROR; /* probably a bug */
751 }
752 bsd_clear(db);
753 break;
754 }
755
756 if ((incode > max_ent + 2) || (incode > db->maxmaxcode)
757 || (incode > max_ent && oldcode == CLEAR)) {
758 if (db->debug) {
759 printk(KERN_DEBUG "bsd_decomp%d: bad code 0x%x oldcode=0x%x ",
760 db->unit, incode, oldcode);
761 printk(KERN_DEBUG "max_ent=0x%x skb->Len=%d seqno=%d\n",
762 max_ent, skb_out->len, db->seqno);
763 }
764 return DECOMP_FATALERROR; /* probably a bug */
765 }
766
767 /* Special case for KwKwK string. */
768 if (incode > max_ent) {
769 finchar = oldcode;
770 extra = 1;
771 } else {
772 finchar = incode;
773 extra = 0;
774 }
775
776 codelen = *(lens_ptr (db, finchar));
777 if( skb_tailroom(skb_out) < codelen + extra) {
778 if (db->debug) {
779 printk(KERN_DEBUG "bsd_decomp%d: ran out of mru\n", db->unit);
780#ifdef DEBUG
781 printk(KERN_DEBUG " len=%d, finchar=0x%x, codelen=%d,skblen=%d\n",
782 ilen, finchar, codelen, skb_out->len);
783#endif
784 }
785 return DECOMP_FATALERROR;
786 }
787
788 /*
789 * Decode this code and install it in the decompressed buffer.
790 */
791
792 p = skb_put(skb_out,codelen);
793 p += codelen;
794 while (finchar > LAST) {
795 struct bsd_dict *dictp2 = dict_ptr (db, finchar);
796
797 dictp = dict_ptr (db, dictp2->cptr);
798
799#ifdef DEBUG
800 if (--codelen <= 0 || dictp->codem1 != finchar-1) {
801 if (codelen <= 0) {
802 printk(KERN_ERR "bsd_decomp%d: fell off end of chain ", db->unit);
803 printk(KERN_ERR "0x%x at 0x%x by 0x%x, max_ent=0x%x\n", incode, finchar, dictp2->cptr, max_ent);
804 } else {
805 if (dictp->codem1 != finchar-1) {
806 printk(KERN_ERR "bsd_decomp%d: bad code chain 0x%x finchar=0x%x ",db->unit, incode, finchar);
807 printk(KERN_ERR "oldcode=0x%x cptr=0x%x codem1=0x%x\n", oldcode, dictp2->cptr, dictp->codem1);
808 }
809 }
810 return DECOMP_FATALERROR;
811 }
812#endif
813
814 {
815 u32 fcode = dictp->fcode;
816 *--p = (fcode >> 16) & 0xff;
817 finchar = fcode & 0xffff;
818 }
819 }
820 *--p = finchar;
821
822#ifdef DEBUG
823 if (--codelen != 0)
824 printk(KERN_ERR "bsd_decomp%d: short by %d after code 0x%x, max_ent=0x%x\n", db->unit, codelen, incode, max_ent);
825#endif
826
827 if (extra) /* the KwKwK case again */
828 *(skb_put(skb_out,1)) = finchar;
829
830 /*
831 * If not first code in a packet, and
832 * if not out of code space, then allocate a new code.
833 *
834 * Keep the hash table correct so it can be used
835 * with uncompressed packets.
836 */
837 if (oldcode != CLEAR && max_ent < db->maxmaxcode) {
838 struct bsd_dict *dictp2, *dictp3;
839 u16 *lens1, *lens2;
840 unsigned long fcode;
841 int hval, disp, indx;
842
843 fcode = BSD_KEY(oldcode,finchar);
844 hval = BSD_HASH(oldcode,finchar,db->hshift);
845 dictp = dict_ptr (db, hval);
846
847 /* look for a free hash table entry */
848 if (dictp->codem1 < max_ent) {
849 disp = (hval == 0) ? 1 : hval;
850 do {
851 hval += disp;
852 if (hval >= db->hsize)
853 hval -= db->hsize;
854 dictp = dict_ptr (db, hval);
855 } while (dictp->codem1 < max_ent);
856 }
857
858 /*
859 * Invalidate previous hash table entry
860 * assigned this code, and then take it over
861 */
862
863 dictp2 = dict_ptr (db, max_ent + 1);
864 indx = dictp2->cptr;
865 dictp3 = dict_ptr (db, indx);
866
867 if (dictp3->codem1 == max_ent)
868 dictp3->codem1 = BADCODEM1;
869
870 dictp2->cptr = hval;
871 dictp->codem1 = max_ent;
872 dictp->fcode = fcode;
873 db->max_ent = ++max_ent;
874
875 /* Update the length of this string. */
876 lens1 = lens_ptr (db, max_ent);
877 lens2 = lens_ptr (db, oldcode);
878 *lens1 = *lens2 + 1;
879
880 /* Expand code size if needed. */
881 if (max_ent >= MAXCODE(n_bits) && max_ent < db->maxmaxcode) {
882 db->n_bits = ++n_bits;
883 tgtbitno = 32-n_bits;
884 }
885 }
886 oldcode = incode;
887 }
888
889 ++db->comp_count;
890 ++db->uncomp_count;
891 db->comp_bytes += skb_in->len - BSD_OVHD;
892 db->uncomp_bytes += skb_out->len;
893
894 if (bsd_check(db)) {
895 if (db->debug)
896 printk(KERN_DEBUG "bsd_decomp%d: peer should have cleared dictionary on %d\n",
897 db->unit, db->seqno - 1);
898 }
899 return skb_out->len;
900}
901
902/*************************************************************
903 * Table of addresses for the BSD compression module
904 *************************************************************/
905
906static struct isdn_ppp_compressor ippp_bsd_compress = {
907 .owner = THIS_MODULE,
908 .num = CI_BSD_COMPRESS,
909 .alloc = bsd_alloc,
910 .free = bsd_free,
911 .init = bsd_init,
912 .reset = bsd_reset,
913 .compress = bsd_compress,
914 .decompress = bsd_decompress,
915 .incomp = bsd_incomp,
916 .stat = bsd_stats,
917};
918
919/*************************************************************
920 * Module support routines
921 *************************************************************/
922
923static int __init isdn_bsdcomp_init(void)
924{
925 int answer = isdn_ppp_register_compressor (&ippp_bsd_compress);
926 if (answer == 0)
927 printk (KERN_INFO "PPP BSD Compression module registered\n");
928 return answer;
929}
930
931static void __exit isdn_bsdcomp_exit(void)
932{
933 isdn_ppp_unregister_compressor (&ippp_bsd_compress);
934}
935
936module_init(isdn_bsdcomp_init);
937module_exit(isdn_bsdcomp_exit);
diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c
new file mode 100644
index 000000000000..c406df6f268a
--- /dev/null
+++ b/drivers/isdn/i4l/isdn_common.c
@@ -0,0 +1,2253 @@
1/* $Id: isdn_common.c,v 1.1.2.3 2004/02/10 01:07:13 keil Exp $
2 *
3 * Linux ISDN subsystem, common used functions (linklevel).
4 *
5 * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
6 * Copyright 1995,96 Thinking Objects Software GmbH Wuerzburg
7 * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
8 *
9 * This software may be used and distributed according to the terms
10 * of the GNU General Public License, incorporated herein by reference.
11 *
12 */
13
14#include <linux/config.h>
15#include <linux/module.h>
16#include <linux/init.h>
17#include <linux/version.h>
18#include <linux/poll.h>
19#include <linux/vmalloc.h>
20#include <linux/isdn.h>
21#include <linux/smp_lock.h>
22#include "isdn_common.h"
23#include "isdn_tty.h"
24#include "isdn_net.h"
25#include "isdn_ppp.h"
26#ifdef CONFIG_ISDN_AUDIO
27#include "isdn_audio.h"
28#endif
29#ifdef CONFIG_ISDN_DIVERSION_MODULE
30#define CONFIG_ISDN_DIVERSION
31#endif
32#ifdef CONFIG_ISDN_DIVERSION
33#include <linux/isdn_divertif.h>
34#endif /* CONFIG_ISDN_DIVERSION */
35#include "isdn_v110.h"
36
37/* Debugflags */
38#undef ISDN_DEBUG_STATCALLB
39
40MODULE_DESCRIPTION("ISDN4Linux: link layer");
41MODULE_AUTHOR("Fritz Elfert");
42MODULE_LICENSE("GPL");
43
44isdn_dev *dev;
45
46static char *isdn_revision = "$Revision: 1.1.2.3 $";
47
48extern char *isdn_net_revision;
49extern char *isdn_tty_revision;
50#ifdef CONFIG_ISDN_PPP
51extern char *isdn_ppp_revision;
52#else
53static char *isdn_ppp_revision = ": none $";
54#endif
55#ifdef CONFIG_ISDN_AUDIO
56extern char *isdn_audio_revision;
57#else
58static char *isdn_audio_revision = ": none $";
59#endif
60extern char *isdn_v110_revision;
61
62#ifdef CONFIG_ISDN_DIVERSION
63static isdn_divert_if *divert_if; /* = NULL */
64#endif /* CONFIG_ISDN_DIVERSION */
65
66
67static int isdn_writebuf_stub(int, int, const u_char __user *, int);
68static void set_global_features(void);
69static int isdn_wildmat(char *s, char *p);
70
71
72static inline void
73isdn_lock_driver(isdn_driver_t *drv)
74{
75 try_module_get(drv->interface->owner);
76 drv->locks++;
77}
78
79void
80isdn_lock_drivers(void)
81{
82 int i;
83
84 for (i = 0; i < ISDN_MAX_DRIVERS; i++) {
85 if (!dev->drv[i])
86 continue;
87 isdn_lock_driver(dev->drv[i]);
88 }
89}
90
91static inline void
92isdn_unlock_driver(isdn_driver_t *drv)
93{
94 if (drv->locks > 0) {
95 drv->locks--;
96 module_put(drv->interface->owner);
97 }
98}
99
100void
101isdn_unlock_drivers(void)
102{
103 int i;
104
105 for (i = 0; i < ISDN_MAX_DRIVERS; i++) {
106 if (!dev->drv[i])
107 continue;
108 isdn_unlock_driver(dev->drv[i]);
109 }
110}
111
112#if defined(ISDN_DEBUG_NET_DUMP) || defined(ISDN_DEBUG_MODEM_DUMP)
113void
114isdn_dumppkt(char *s, u_char * p, int len, int dumplen)
115{
116 int dumpc;
117
118 printk(KERN_DEBUG "%s(%d) ", s, len);
119 for (dumpc = 0; (dumpc < dumplen) && (len); len--, dumpc++)
120 printk(" %02x", *p++);
121 printk("\n");
122}
123#endif
124
125/*
126 * I picked the pattern-matching-functions from an old GNU-tar version (1.10)
127 * It was originally written and put to PD by rs@mirror.TMC.COM (Rich Salz)
128 */
129static int
130isdn_star(char *s, char *p)
131{
132 while (isdn_wildmat(s, p)) {
133 if (*++s == '\0')
134 return (2);
135 }
136 return (0);
137}
138
139/*
140 * Shell-type Pattern-matching for incoming caller-Ids
141 * This function gets a string in s and checks, if it matches the pattern
142 * given in p.
143 *
144 * Return:
145 * 0 = match.
146 * 1 = no match.
147 * 2 = no match. Would eventually match, if s would be longer.
148 *
149 * Possible Patterns:
150 *
151 * '?' matches one character
152 * '*' matches zero or more characters
153 * [xyz] matches the set of characters in brackets.
154 * [^xyz] matches any single character not in the set of characters
155 */
156
157static int
158isdn_wildmat(char *s, char *p)
159{
160 register int last;
161 register int matched;
162 register int reverse;
163 register int nostar = 1;
164
165 if (!(*s) && !(*p))
166 return(1);
167 for (; *p; s++, p++)
168 switch (*p) {
169 case '\\':
170 /*
171 * Literal match with following character,
172 * fall through.
173 */
174 p++;
175 default:
176 if (*s != *p)
177 return (*s == '\0')?2:1;
178 continue;
179 case '?':
180 /* Match anything. */
181 if (*s == '\0')
182 return (2);
183 continue;
184 case '*':
185 nostar = 0;
186 /* Trailing star matches everything. */
187 return (*++p ? isdn_star(s, p) : 0);
188 case '[':
189 /* [^....] means inverse character class. */
190 if ((reverse = (p[1] == '^')))
191 p++;
192 for (last = 0, matched = 0; *++p && (*p != ']'); last = *p)
193 /* This next line requires a good C compiler. */
194 if (*p == '-' ? *s <= *++p && *s >= last : *s == *p)
195 matched = 1;
196 if (matched == reverse)
197 return (1);
198 continue;
199 }
200 return (*s == '\0')?0:nostar;
201}
202
203int isdn_msncmp( const char * msn1, const char * msn2 )
204{
205 char TmpMsn1[ ISDN_MSNLEN ];
206 char TmpMsn2[ ISDN_MSNLEN ];
207 char *p;
208
209 for ( p = TmpMsn1; *msn1 && *msn1 != ':'; ) // Strip off a SPID
210 *p++ = *msn1++;
211 *p = '\0';
212
213 for ( p = TmpMsn2; *msn2 && *msn2 != ':'; ) // Strip off a SPID
214 *p++ = *msn2++;
215 *p = '\0';
216
217 return isdn_wildmat( TmpMsn1, TmpMsn2 );
218}
219
220int
221isdn_dc2minor(int di, int ch)
222{
223 int i;
224 for (i = 0; i < ISDN_MAX_CHANNELS; i++)
225 if (dev->chanmap[i] == ch && dev->drvmap[i] == di)
226 return i;
227 return -1;
228}
229
230static int isdn_timer_cnt1 = 0;
231static int isdn_timer_cnt2 = 0;
232static int isdn_timer_cnt3 = 0;
233
234static void
235isdn_timer_funct(ulong dummy)
236{
237 int tf = dev->tflags;
238 if (tf & ISDN_TIMER_FAST) {
239 if (tf & ISDN_TIMER_MODEMREAD)
240 isdn_tty_readmodem();
241 if (tf & ISDN_TIMER_MODEMPLUS)
242 isdn_tty_modem_escape();
243 if (tf & ISDN_TIMER_MODEMXMIT)
244 isdn_tty_modem_xmit();
245 }
246 if (tf & ISDN_TIMER_SLOW) {
247 if (++isdn_timer_cnt1 >= ISDN_TIMER_02SEC) {
248 isdn_timer_cnt1 = 0;
249 if (tf & ISDN_TIMER_NETDIAL)
250 isdn_net_dial();
251 }
252 if (++isdn_timer_cnt2 >= ISDN_TIMER_1SEC) {
253 isdn_timer_cnt2 = 0;
254 if (tf & ISDN_TIMER_NETHANGUP)
255 isdn_net_autohup();
256 if (++isdn_timer_cnt3 >= ISDN_TIMER_RINGING) {
257 isdn_timer_cnt3 = 0;
258 if (tf & ISDN_TIMER_MODEMRING)
259 isdn_tty_modem_ring();
260 }
261 if (tf & ISDN_TIMER_CARRIER)
262 isdn_tty_carrier_timeout();
263 }
264 }
265 if (tf)
266 mod_timer(&dev->timer, jiffies+ISDN_TIMER_RES);
267}
268
269void
270isdn_timer_ctrl(int tf, int onoff)
271{
272 unsigned long flags;
273 int old_tflags;
274
275 spin_lock_irqsave(&dev->timerlock, flags);
276 if ((tf & ISDN_TIMER_SLOW) && (!(dev->tflags & ISDN_TIMER_SLOW))) {
277 /* If the slow-timer wasn't activated until now */
278 isdn_timer_cnt1 = 0;
279 isdn_timer_cnt2 = 0;
280 }
281 old_tflags = dev->tflags;
282 if (onoff)
283 dev->tflags |= tf;
284 else
285 dev->tflags &= ~tf;
286 if (dev->tflags && !old_tflags)
287 mod_timer(&dev->timer, jiffies+ISDN_TIMER_RES);
288 spin_unlock_irqrestore(&dev->timerlock, flags);
289}
290
291/*
292 * Receive a packet from B-Channel. (Called from low-level-module)
293 */
294static void
295isdn_receive_skb_callback(int di, int channel, struct sk_buff *skb)
296{
297 int i;
298
299 if ((i = isdn_dc2minor(di, channel)) == -1) {
300 dev_kfree_skb(skb);
301 return;
302 }
303 /* Update statistics */
304 dev->ibytes[i] += skb->len;
305
306 /* First, try to deliver data to network-device */
307 if (isdn_net_rcv_skb(i, skb))
308 return;
309
310 /* V.110 handling
311 * makes sense for async streams only, so it is
312 * called after possible net-device delivery.
313 */
314 if (dev->v110[i]) {
315 atomic_inc(&dev->v110use[i]);
316 skb = isdn_v110_decode(dev->v110[i], skb);
317 atomic_dec(&dev->v110use[i]);
318 if (!skb)
319 return;
320 }
321
322 /* No network-device found, deliver to tty or raw-channel */
323 if (skb->len) {
324 if (isdn_tty_rcv_skb(i, di, channel, skb))
325 return;
326 wake_up_interruptible(&dev->drv[di]->rcv_waitq[channel]);
327 } else
328 dev_kfree_skb(skb);
329}
330
331/*
332 * Intercept command from Linklevel to Lowlevel.
333 * If layer 2 protocol is V.110 and this is not supported by current
334 * lowlevel-driver, use driver's transparent mode and handle V.110 in
335 * linklevel instead.
336 */
337int
338isdn_command(isdn_ctrl *cmd)
339{
340 if (cmd->driver == -1) {
341 printk(KERN_WARNING "isdn_command command(%x) driver -1\n", cmd->command);
342 return(1);
343 }
344 if (cmd->command == ISDN_CMD_SETL2) {
345 int idx = isdn_dc2minor(cmd->driver, cmd->arg & 255);
346 unsigned long l2prot = (cmd->arg >> 8) & 255;
347 unsigned long features = (dev->drv[cmd->driver]->interface->features
348 >> ISDN_FEATURE_L2_SHIFT) &
349 ISDN_FEATURE_L2_MASK;
350 unsigned long l2_feature = (1 << l2prot);
351
352 switch (l2prot) {
353 case ISDN_PROTO_L2_V11096:
354 case ISDN_PROTO_L2_V11019:
355 case ISDN_PROTO_L2_V11038:
356 /* If V.110 requested, but not supported by
357 * HL-driver, set emulator-flag and change
358 * Layer-2 to transparent
359 */
360 if (!(features & l2_feature)) {
361 dev->v110emu[idx] = l2prot;
362 cmd->arg = (cmd->arg & 255) |
363 (ISDN_PROTO_L2_TRANS << 8);
364 } else
365 dev->v110emu[idx] = 0;
366 }
367 }
368 return dev->drv[cmd->driver]->interface->command(cmd);
369}
370
371void
372isdn_all_eaz(int di, int ch)
373{
374 isdn_ctrl cmd;
375
376 if (di < 0)
377 return;
378 cmd.driver = di;
379 cmd.arg = ch;
380 cmd.command = ISDN_CMD_SETEAZ;
381 cmd.parm.num[0] = '\0';
382 isdn_command(&cmd);
383}
384
385/*
386 * Begin of a CAPI like LL<->HL interface, currently used only for
387 * supplementary service (CAPI 2.0 part III)
388 */
389#include <linux/isdn/capicmd.h>
390
391int
392isdn_capi_rec_hl_msg(capi_msg *cm) {
393
394 int di;
395 int ch;
396
397 di = (cm->adr.Controller & 0x7f) -1;
398 ch = isdn_dc2minor(di, (cm->adr.Controller>>8)& 0x7f);
399 switch(cm->Command) {
400 case CAPI_FACILITY:
401 /* in the moment only handled in tty */
402 return(isdn_tty_capi_facility(cm));
403 default:
404 return(-1);
405 }
406}
407
408static int
409isdn_status_callback(isdn_ctrl * c)
410{
411 int di;
412 u_long flags;
413 int i;
414 int r;
415 int retval = 0;
416 isdn_ctrl cmd;
417 isdn_net_dev *p;
418
419 di = c->driver;
420 i = isdn_dc2minor(di, c->arg);
421 switch (c->command) {
422 case ISDN_STAT_BSENT:
423 if (i < 0)
424 return -1;
425 if (dev->global_flags & ISDN_GLOBAL_STOPPED)
426 return 0;
427 if (isdn_net_stat_callback(i, c))
428 return 0;
429 if (isdn_v110_stat_callback(i, c))
430 return 0;
431 if (isdn_tty_stat_callback(i, c))
432 return 0;
433 wake_up_interruptible(&dev->drv[di]->snd_waitq[c->arg]);
434 break;
435 case ISDN_STAT_STAVAIL:
436 dev->drv[di]->stavail += c->arg;
437 wake_up_interruptible(&dev->drv[di]->st_waitq);
438 break;
439 case ISDN_STAT_RUN:
440 dev->drv[di]->flags |= DRV_FLAG_RUNNING;
441 for (i = 0; i < ISDN_MAX_CHANNELS; i++)
442 if (dev->drvmap[i] == di)
443 isdn_all_eaz(di, dev->chanmap[i]);
444 set_global_features();
445 break;
446 case ISDN_STAT_STOP:
447 dev->drv[di]->flags &= ~DRV_FLAG_RUNNING;
448 break;
449 case ISDN_STAT_ICALL:
450 if (i < 0)
451 return -1;
452#ifdef ISDN_DEBUG_STATCALLB
453 printk(KERN_DEBUG "ICALL (net): %d %ld %s\n", di, c->arg, c->parm.num);
454#endif
455 if (dev->global_flags & ISDN_GLOBAL_STOPPED) {
456 cmd.driver = di;
457 cmd.arg = c->arg;
458 cmd.command = ISDN_CMD_HANGUP;
459 isdn_command(&cmd);
460 return 0;
461 }
462 /* Try to find a network-interface which will accept incoming call */
463 r = ((c->command == ISDN_STAT_ICALLW) ? 0 : isdn_net_find_icall(di, c->arg, i, &c->parm.setup));
464 switch (r) {
465 case 0:
466 /* No network-device replies.
467 * Try ttyI's.
468 * These return 0 on no match, 1 on match and
469 * 3 on eventually match, if CID is longer.
470 */
471 if (c->command == ISDN_STAT_ICALL)
472 if ((retval = isdn_tty_find_icall(di, c->arg, &c->parm.setup))) return(retval);
473#ifdef CONFIG_ISDN_DIVERSION
474 if (divert_if)
475 if ((retval = divert_if->stat_callback(c)))
476 return(retval); /* processed */
477#endif /* CONFIG_ISDN_DIVERSION */
478 if ((!retval) && (dev->drv[di]->flags & DRV_FLAG_REJBUS)) {
479 /* No tty responding */
480 cmd.driver = di;
481 cmd.arg = c->arg;
482 cmd.command = ISDN_CMD_HANGUP;
483 isdn_command(&cmd);
484 retval = 2;
485 }
486 break;
487 case 1:
488 /* Schedule connection-setup */
489 isdn_net_dial();
490 cmd.driver = di;
491 cmd.arg = c->arg;
492 cmd.command = ISDN_CMD_ACCEPTD;
493 for ( p = dev->netdev; p; p = p->next )
494 if ( p->local->isdn_channel == cmd.arg )
495 {
496 strcpy( cmd.parm.setup.eazmsn, p->local->msn );
497 isdn_command(&cmd);
498 retval = 1;
499 break;
500 }
501 break;
502
503 case 2: /* For calling back, first reject incoming call ... */
504 case 3: /* Interface found, but down, reject call actively */
505 retval = 2;
506 printk(KERN_INFO "isdn: Rejecting Call\n");
507 cmd.driver = di;
508 cmd.arg = c->arg;
509 cmd.command = ISDN_CMD_HANGUP;
510 isdn_command(&cmd);
511 if (r == 3)
512 break;
513 /* Fall through */
514 case 4:
515 /* ... then start callback. */
516 isdn_net_dial();
517 break;
518 case 5:
519 /* Number would eventually match, if longer */
520 retval = 3;
521 break;
522 }
523#ifdef ISDN_DEBUG_STATCALLB
524 printk(KERN_DEBUG "ICALL: ret=%d\n", retval);
525#endif
526 return retval;
527 break;
528 case ISDN_STAT_CINF:
529 if (i < 0)
530 return -1;
531#ifdef ISDN_DEBUG_STATCALLB
532 printk(KERN_DEBUG "CINF: %ld %s\n", c->arg, c->parm.num);
533#endif
534 if (dev->global_flags & ISDN_GLOBAL_STOPPED)
535 return 0;
536 if (strcmp(c->parm.num, "0"))
537 isdn_net_stat_callback(i, c);
538 isdn_tty_stat_callback(i, c);
539 break;
540 case ISDN_STAT_CAUSE:
541#ifdef ISDN_DEBUG_STATCALLB
542 printk(KERN_DEBUG "CAUSE: %ld %s\n", c->arg, c->parm.num);
543#endif
544 printk(KERN_INFO "isdn: %s,ch%ld cause: %s\n",
545 dev->drvid[di], c->arg, c->parm.num);
546 isdn_tty_stat_callback(i, c);
547#ifdef CONFIG_ISDN_DIVERSION
548 if (divert_if)
549 divert_if->stat_callback(c);
550#endif /* CONFIG_ISDN_DIVERSION */
551 break;
552 case ISDN_STAT_DISPLAY:
553#ifdef ISDN_DEBUG_STATCALLB
554 printk(KERN_DEBUG "DISPLAY: %ld %s\n", c->arg, c->parm.display);
555#endif
556 isdn_tty_stat_callback(i, c);
557#ifdef CONFIG_ISDN_DIVERSION
558 if (divert_if)
559 divert_if->stat_callback(c);
560#endif /* CONFIG_ISDN_DIVERSION */
561 break;
562 case ISDN_STAT_DCONN:
563 if (i < 0)
564 return -1;
565#ifdef ISDN_DEBUG_STATCALLB
566 printk(KERN_DEBUG "DCONN: %ld\n", c->arg);
567#endif
568 if (dev->global_flags & ISDN_GLOBAL_STOPPED)
569 return 0;
570 /* Find any net-device, waiting for D-channel setup */
571 if (isdn_net_stat_callback(i, c))
572 break;
573 isdn_v110_stat_callback(i, c);
574 /* Find any ttyI, waiting for D-channel setup */
575 if (isdn_tty_stat_callback(i, c)) {
576 cmd.driver = di;
577 cmd.arg = c->arg;
578 cmd.command = ISDN_CMD_ACCEPTB;
579 isdn_command(&cmd);
580 break;
581 }
582 break;
583 case ISDN_STAT_DHUP:
584 if (i < 0)
585 return -1;
586#ifdef ISDN_DEBUG_STATCALLB
587 printk(KERN_DEBUG "DHUP: %ld\n", c->arg);
588#endif
589 if (dev->global_flags & ISDN_GLOBAL_STOPPED)
590 return 0;
591 dev->drv[di]->online &= ~(1 << (c->arg));
592 isdn_info_update();
593 /* Signal hangup to network-devices */
594 if (isdn_net_stat_callback(i, c))
595 break;
596 isdn_v110_stat_callback(i, c);
597 if (isdn_tty_stat_callback(i, c))
598 break;
599#ifdef CONFIG_ISDN_DIVERSION
600 if (divert_if)
601 divert_if->stat_callback(c);
602#endif /* CONFIG_ISDN_DIVERSION */
603 break;
604 break;
605 case ISDN_STAT_BCONN:
606 if (i < 0)
607 return -1;
608#ifdef ISDN_DEBUG_STATCALLB
609 printk(KERN_DEBUG "BCONN: %ld\n", c->arg);
610#endif
611 /* Signal B-channel-connect to network-devices */
612 if (dev->global_flags & ISDN_GLOBAL_STOPPED)
613 return 0;
614 dev->drv[di]->online |= (1 << (c->arg));
615 isdn_info_update();
616 if (isdn_net_stat_callback(i, c))
617 break;
618 isdn_v110_stat_callback(i, c);
619 if (isdn_tty_stat_callback(i, c))
620 break;
621 break;
622 case ISDN_STAT_BHUP:
623 if (i < 0)
624 return -1;
625#ifdef ISDN_DEBUG_STATCALLB
626 printk(KERN_DEBUG "BHUP: %ld\n", c->arg);
627#endif
628 if (dev->global_flags & ISDN_GLOBAL_STOPPED)
629 return 0;
630 dev->drv[di]->online &= ~(1 << (c->arg));
631 isdn_info_update();
632#ifdef CONFIG_ISDN_X25
633 /* Signal hangup to network-devices */
634 if (isdn_net_stat_callback(i, c))
635 break;
636#endif
637 isdn_v110_stat_callback(i, c);
638 if (isdn_tty_stat_callback(i, c))
639 break;
640 break;
641 case ISDN_STAT_NODCH:
642 if (i < 0)
643 return -1;
644#ifdef ISDN_DEBUG_STATCALLB
645 printk(KERN_DEBUG "NODCH: %ld\n", c->arg);
646#endif
647 if (dev->global_flags & ISDN_GLOBAL_STOPPED)
648 return 0;
649 if (isdn_net_stat_callback(i, c))
650 break;
651 if (isdn_tty_stat_callback(i, c))
652 break;
653 break;
654 case ISDN_STAT_ADDCH:
655 spin_lock_irqsave(&dev->lock, flags);
656 if (isdn_add_channels(dev->drv[di], di, c->arg, 1)) {
657 spin_unlock_irqrestore(&dev->lock, flags);
658 return -1;
659 }
660 spin_unlock_irqrestore(&dev->lock, flags);
661 isdn_info_update();
662 break;
663 case ISDN_STAT_DISCH:
664 spin_lock_irqsave(&dev->lock, flags);
665 for (i = 0; i < ISDN_MAX_CHANNELS; i++)
666 if ((dev->drvmap[i] == di) &&
667 (dev->chanmap[i] == c->arg)) {
668 if (c->parm.num[0])
669 dev->usage[i] &= ~ISDN_USAGE_DISABLED;
670 else
671 if (USG_NONE(dev->usage[i])) {
672 dev->usage[i] |= ISDN_USAGE_DISABLED;
673 }
674 else
675 retval = -1;
676 break;
677 }
678 spin_unlock_irqrestore(&dev->lock, flags);
679 isdn_info_update();
680 break;
681 case ISDN_STAT_UNLOAD:
682 while (dev->drv[di]->locks > 0) {
683 isdn_unlock_driver(dev->drv[di]);
684 }
685 spin_lock_irqsave(&dev->lock, flags);
686 isdn_tty_stat_callback(i, c);
687 for (i = 0; i < ISDN_MAX_CHANNELS; i++)
688 if (dev->drvmap[i] == di) {
689 dev->drvmap[i] = -1;
690 dev->chanmap[i] = -1;
691 dev->usage[i] &= ~ISDN_USAGE_DISABLED;
692 }
693 dev->drivers--;
694 dev->channels -= dev->drv[di]->channels;
695 kfree(dev->drv[di]->rcverr);
696 kfree(dev->drv[di]->rcvcount);
697 for (i = 0; i < dev->drv[di]->channels; i++)
698 skb_queue_purge(&dev->drv[di]->rpqueue[i]);
699 kfree(dev->drv[di]->rpqueue);
700 kfree(dev->drv[di]->rcv_waitq);
701 kfree(dev->drv[di]);
702 dev->drv[di] = NULL;
703 dev->drvid[di][0] = '\0';
704 isdn_info_update();
705 set_global_features();
706 spin_unlock_irqrestore(&dev->lock, flags);
707 return 0;
708 case ISDN_STAT_L1ERR:
709 break;
710 case CAPI_PUT_MESSAGE:
711 return(isdn_capi_rec_hl_msg(&c->parm.cmsg));
712#ifdef CONFIG_ISDN_TTY_FAX
713 case ISDN_STAT_FAXIND:
714 isdn_tty_stat_callback(i, c);
715 break;
716#endif
717#ifdef CONFIG_ISDN_AUDIO
718 case ISDN_STAT_AUDIO:
719 isdn_tty_stat_callback(i, c);
720 break;
721#endif
722#ifdef CONFIG_ISDN_DIVERSION
723 case ISDN_STAT_PROT:
724 case ISDN_STAT_REDIR:
725 if (divert_if)
726 return(divert_if->stat_callback(c));
727#endif /* CONFIG_ISDN_DIVERSION */
728 default:
729 return -1;
730 }
731 return 0;
732}
733
734/*
735 * Get integer from char-pointer, set pointer to end of number
736 */
737int
738isdn_getnum(char **p)
739{
740 int v = -1;
741
742 while (*p[0] >= '0' && *p[0] <= '9')
743 v = ((v < 0) ? 0 : (v * 10)) + (int) ((*p[0]++) - '0');
744 return v;
745}
746
747#define DLE 0x10
748
749/*
750 * isdn_readbchan() tries to get data from the read-queue.
751 * It MUST be called with interrupts off.
752 *
753 * Be aware that this is not an atomic operation when sleep != 0, even though
754 * interrupts are turned off! Well, like that we are currently only called
755 * on behalf of a read system call on raw device files (which are documented
756 * to be dangerous and for for debugging purpose only). The inode semaphore
757 * takes care that this is not called for the same minor device number while
758 * we are sleeping, but access is not serialized against simultaneous read()
759 * from the corresponding ttyI device. Can other ugly events, like changes
760 * of the mapping (di,ch)<->minor, happen during the sleep? --he
761 */
762int
763isdn_readbchan(int di, int channel, u_char * buf, u_char * fp, int len, wait_queue_head_t *sleep)
764{
765 int count;
766 int count_pull;
767 int count_put;
768 int dflag;
769 struct sk_buff *skb;
770 u_char *cp;
771
772 if (!dev->drv[di])
773 return 0;
774 if (skb_queue_empty(&dev->drv[di]->rpqueue[channel])) {
775 if (sleep)
776 interruptible_sleep_on(sleep);
777 else
778 return 0;
779 }
780 if (len > dev->drv[di]->rcvcount[channel])
781 len = dev->drv[di]->rcvcount[channel];
782 cp = buf;
783 count = 0;
784 while (len) {
785 if (!(skb = skb_peek(&dev->drv[di]->rpqueue[channel])))
786 break;
787#ifdef CONFIG_ISDN_AUDIO
788 if (ISDN_AUDIO_SKB_LOCK(skb))
789 break;
790 ISDN_AUDIO_SKB_LOCK(skb) = 1;
791 if ((ISDN_AUDIO_SKB_DLECOUNT(skb)) || (dev->drv[di]->DLEflag & (1 << channel))) {
792 char *p = skb->data;
793 unsigned long DLEmask = (1 << channel);
794
795 dflag = 0;
796 count_pull = count_put = 0;
797 while ((count_pull < skb->len) && (len > 0)) {
798 len--;
799 if (dev->drv[di]->DLEflag & DLEmask) {
800 *cp++ = DLE;
801 dev->drv[di]->DLEflag &= ~DLEmask;
802 } else {
803 *cp++ = *p;
804 if (*p == DLE) {
805 dev->drv[di]->DLEflag |= DLEmask;
806 (ISDN_AUDIO_SKB_DLECOUNT(skb))--;
807 }
808 p++;
809 count_pull++;
810 }
811 count_put++;
812 }
813 if (count_pull >= skb->len)
814 dflag = 1;
815 } else {
816#endif
817 /* No DLE's in buff, so simply copy it */
818 dflag = 1;
819 if ((count_pull = skb->len) > len) {
820 count_pull = len;
821 dflag = 0;
822 }
823 count_put = count_pull;
824 memcpy(cp, skb->data, count_put);
825 cp += count_put;
826 len -= count_put;
827#ifdef CONFIG_ISDN_AUDIO
828 }
829#endif
830 count += count_put;
831 if (fp) {
832 memset(fp, 0, count_put);
833 fp += count_put;
834 }
835 if (dflag) {
836 /* We got all the data in this buff.
837 * Now we can dequeue it.
838 */
839 if (fp)
840 *(fp - 1) = 0xff;
841#ifdef CONFIG_ISDN_AUDIO
842 ISDN_AUDIO_SKB_LOCK(skb) = 0;
843#endif
844 skb = skb_dequeue(&dev->drv[di]->rpqueue[channel]);
845 dev_kfree_skb(skb);
846 } else {
847 /* Not yet emptied this buff, so it
848 * must stay in the queue, for further calls
849 * but we pull off the data we got until now.
850 */
851 skb_pull(skb, count_pull);
852#ifdef CONFIG_ISDN_AUDIO
853 ISDN_AUDIO_SKB_LOCK(skb) = 0;
854#endif
855 }
856 dev->drv[di]->rcvcount[channel] -= count_put;
857 }
858 return count;
859}
860
861static __inline int
862isdn_minor2drv(int minor)
863{
864 return (dev->drvmap[minor]);
865}
866
867static __inline int
868isdn_minor2chan(int minor)
869{
870 return (dev->chanmap[minor]);
871}
872
873static char *
874isdn_statstr(void)
875{
876 static char istatbuf[2048];
877 char *p;
878 int i;
879
880 sprintf(istatbuf, "idmap:\t");
881 p = istatbuf + strlen(istatbuf);
882 for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
883 sprintf(p, "%s ", (dev->drvmap[i] < 0) ? "-" : dev->drvid[dev->drvmap[i]]);
884 p = istatbuf + strlen(istatbuf);
885 }
886 sprintf(p, "\nchmap:\t");
887 p = istatbuf + strlen(istatbuf);
888 for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
889 sprintf(p, "%d ", dev->chanmap[i]);
890 p = istatbuf + strlen(istatbuf);
891 }
892 sprintf(p, "\ndrmap:\t");
893 p = istatbuf + strlen(istatbuf);
894 for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
895 sprintf(p, "%d ", dev->drvmap[i]);
896 p = istatbuf + strlen(istatbuf);
897 }
898 sprintf(p, "\nusage:\t");
899 p = istatbuf + strlen(istatbuf);
900 for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
901 sprintf(p, "%d ", dev->usage[i]);
902 p = istatbuf + strlen(istatbuf);
903 }
904 sprintf(p, "\nflags:\t");
905 p = istatbuf + strlen(istatbuf);
906 for (i = 0; i < ISDN_MAX_DRIVERS; i++) {
907 if (dev->drv[i]) {
908 sprintf(p, "%ld ", dev->drv[i]->online);
909 p = istatbuf + strlen(istatbuf);
910 } else {
911 sprintf(p, "? ");
912 p = istatbuf + strlen(istatbuf);
913 }
914 }
915 sprintf(p, "\nphone:\t");
916 p = istatbuf + strlen(istatbuf);
917 for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
918 sprintf(p, "%s ", dev->num[i]);
919 p = istatbuf + strlen(istatbuf);
920 }
921 sprintf(p, "\n");
922 return istatbuf;
923}
924
925/* Module interface-code */
926
927void
928isdn_info_update(void)
929{
930 infostruct *p = dev->infochain;
931
932 while (p) {
933 *(p->private) = 1;
934 p = (infostruct *) p->next;
935 }
936 wake_up_interruptible(&(dev->info_waitq));
937}
938
939static ssize_t
940isdn_read(struct file *file, char __user *buf, size_t count, loff_t * off)
941{
942 uint minor = MINOR(file->f_dentry->d_inode->i_rdev);
943 int len = 0;
944 int drvidx;
945 int chidx;
946 int retval;
947 char *p;
948
949 lock_kernel();
950 if (minor == ISDN_MINOR_STATUS) {
951 if (!file->private_data) {
952 if (file->f_flags & O_NONBLOCK) {
953 retval = -EAGAIN;
954 goto out;
955 }
956 interruptible_sleep_on(&(dev->info_waitq));
957 }
958 p = isdn_statstr();
959 file->private_data = NULL;
960 if ((len = strlen(p)) <= count) {
961 if (copy_to_user(buf, p, len)) {
962 retval = -EFAULT;
963 goto out;
964 }
965 *off += len;
966 retval = len;
967 goto out;
968 }
969 retval = 0;
970 goto out;
971 }
972 if (!dev->drivers) {
973 retval = -ENODEV;
974 goto out;
975 }
976 if (minor <= ISDN_MINOR_BMAX) {
977 printk(KERN_WARNING "isdn_read minor %d obsolete!\n", minor);
978 drvidx = isdn_minor2drv(minor);
979 if (drvidx < 0) {
980 retval = -ENODEV;
981 goto out;
982 }
983 if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) {
984 retval = -ENODEV;
985 goto out;
986 }
987 chidx = isdn_minor2chan(minor);
988 if (!(p = kmalloc(count, GFP_KERNEL))) {
989 retval = -ENOMEM;
990 goto out;
991 }
992 len = isdn_readbchan(drvidx, chidx, p, NULL, count,
993 &dev->drv[drvidx]->rcv_waitq[chidx]);
994 *off += len;
995 if (copy_to_user(buf,p,len))
996 len = -EFAULT;
997 kfree(p);
998 retval = len;
999 goto out;
1000 }
1001 if (minor <= ISDN_MINOR_CTRLMAX) {
1002 drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
1003 if (drvidx < 0) {
1004 retval = -ENODEV;
1005 goto out;
1006 }
1007 if (!dev->drv[drvidx]->stavail) {
1008 if (file->f_flags & O_NONBLOCK) {
1009 retval = -EAGAIN;
1010 goto out;
1011 }
1012 interruptible_sleep_on(&(dev->drv[drvidx]->st_waitq));
1013 }
1014 if (dev->drv[drvidx]->interface->readstat) {
1015 if (count > dev->drv[drvidx]->stavail)
1016 count = dev->drv[drvidx]->stavail;
1017 len = dev->drv[drvidx]->interface->
1018 readstat(buf, count, drvidx,
1019 isdn_minor2chan(minor));
1020 } else {
1021 len = 0;
1022 }
1023 if (len)
1024 dev->drv[drvidx]->stavail -= len;
1025 else
1026 dev->drv[drvidx]->stavail = 0;
1027 *off += len;
1028 retval = len;
1029 goto out;
1030 }
1031#ifdef CONFIG_ISDN_PPP
1032 if (minor <= ISDN_MINOR_PPPMAX) {
1033 retval = isdn_ppp_read(minor - ISDN_MINOR_PPP, file, buf, count);
1034 goto out;
1035 }
1036#endif
1037 retval = -ENODEV;
1038 out:
1039 unlock_kernel();
1040 return retval;
1041}
1042
1043static ssize_t
1044isdn_write(struct file *file, const char __user *buf, size_t count, loff_t * off)
1045{
1046 uint minor = MINOR(file->f_dentry->d_inode->i_rdev);
1047 int drvidx;
1048 int chidx;
1049 int retval;
1050
1051 if (minor == ISDN_MINOR_STATUS)
1052 return -EPERM;
1053 if (!dev->drivers)
1054 return -ENODEV;
1055
1056 lock_kernel();
1057 if (minor <= ISDN_MINOR_BMAX) {
1058 printk(KERN_WARNING "isdn_write minor %d obsolete!\n", minor);
1059 drvidx = isdn_minor2drv(minor);
1060 if (drvidx < 0) {
1061 retval = -ENODEV;
1062 goto out;
1063 }
1064 if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) {
1065 retval = -ENODEV;
1066 goto out;
1067 }
1068 chidx = isdn_minor2chan(minor);
1069 while (isdn_writebuf_stub(drvidx, chidx, buf, count) != count)
1070 interruptible_sleep_on(&dev->drv[drvidx]->snd_waitq[chidx]);
1071 retval = count;
1072 goto out;
1073 }
1074 if (minor <= ISDN_MINOR_CTRLMAX) {
1075 drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
1076 if (drvidx < 0) {
1077 retval = -ENODEV;
1078 goto out;
1079 }
1080 /*
1081 * We want to use the isdnctrl device to load the firmware
1082 *
1083 if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING))
1084 return -ENODEV;
1085 */
1086 if (dev->drv[drvidx]->interface->writecmd)
1087 retval = dev->drv[drvidx]->interface->
1088 writecmd(buf, count, drvidx, isdn_minor2chan(minor));
1089 else
1090 retval = count;
1091 goto out;
1092 }
1093#ifdef CONFIG_ISDN_PPP
1094 if (minor <= ISDN_MINOR_PPPMAX) {
1095 retval = isdn_ppp_write(minor - ISDN_MINOR_PPP, file, buf, count);
1096 goto out;
1097 }
1098#endif
1099 retval = -ENODEV;
1100 out:
1101 unlock_kernel();
1102 return retval;
1103}
1104
1105static unsigned int
1106isdn_poll(struct file *file, poll_table * wait)
1107{
1108 unsigned int mask = 0;
1109 unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
1110 int drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
1111
1112 lock_kernel();
1113 if (minor == ISDN_MINOR_STATUS) {
1114 poll_wait(file, &(dev->info_waitq), wait);
1115 /* mask = POLLOUT | POLLWRNORM; */
1116 if (file->private_data) {
1117 mask |= POLLIN | POLLRDNORM;
1118 }
1119 goto out;
1120 }
1121 if (minor >= ISDN_MINOR_CTRL && minor <= ISDN_MINOR_CTRLMAX) {
1122 if (drvidx < 0) {
1123 /* driver deregistered while file open */
1124 mask = POLLHUP;
1125 goto out;
1126 }
1127 poll_wait(file, &(dev->drv[drvidx]->st_waitq), wait);
1128 mask = POLLOUT | POLLWRNORM;
1129 if (dev->drv[drvidx]->stavail) {
1130 mask |= POLLIN | POLLRDNORM;
1131 }
1132 goto out;
1133 }
1134#ifdef CONFIG_ISDN_PPP
1135 if (minor <= ISDN_MINOR_PPPMAX) {
1136 mask = isdn_ppp_poll(file, wait);
1137 goto out;
1138 }
1139#endif
1140 mask = POLLERR;
1141 out:
1142 unlock_kernel();
1143 return mask;
1144}
1145
1146
1147static int
1148isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
1149{
1150 uint minor = MINOR(inode->i_rdev);
1151 isdn_ctrl c;
1152 int drvidx;
1153 int chidx;
1154 int ret;
1155 int i;
1156 char __user *p;
1157 char *s;
1158 union iocpar {
1159 char name[10];
1160 char bname[22];
1161 isdn_ioctl_struct iocts;
1162 isdn_net_ioctl_phone phone;
1163 isdn_net_ioctl_cfg cfg;
1164 } iocpar;
1165 void __user *argp = (void __user *)arg;
1166
1167#define name iocpar.name
1168#define bname iocpar.bname
1169#define iocts iocpar.iocts
1170#define phone iocpar.phone
1171#define cfg iocpar.cfg
1172
1173 if (minor == ISDN_MINOR_STATUS) {
1174 switch (cmd) {
1175 case IIOCGETDVR:
1176 return (TTY_DV +
1177 (NET_DV << 8) +
1178 (INF_DV << 16));
1179 case IIOCGETCPS:
1180 if (arg) {
1181 ulong __user *p = argp;
1182 int i;
1183 if (!access_ok(VERIFY_WRITE, p,
1184 sizeof(ulong) * ISDN_MAX_CHANNELS * 2))
1185 return -EFAULT;
1186 for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
1187 put_user(dev->ibytes[i], p++);
1188 put_user(dev->obytes[i], p++);
1189 }
1190 return 0;
1191 } else
1192 return -EINVAL;
1193 break;
1194#ifdef CONFIG_NETDEVICES
1195 case IIOCNETGPN:
1196 /* Get peer phone number of a connected
1197 * isdn network interface */
1198 if (arg) {
1199 if (copy_from_user(&phone, argp, sizeof(phone)))
1200 return -EFAULT;
1201 return isdn_net_getpeer(&phone, argp);
1202 } else
1203 return -EINVAL;
1204#endif
1205 default:
1206 return -EINVAL;
1207 }
1208 }
1209 if (!dev->drivers)
1210 return -ENODEV;
1211 if (minor <= ISDN_MINOR_BMAX) {
1212 drvidx = isdn_minor2drv(minor);
1213 if (drvidx < 0)
1214 return -ENODEV;
1215 chidx = isdn_minor2chan(minor);
1216 if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING))
1217 return -ENODEV;
1218 return 0;
1219 }
1220 if (minor <= ISDN_MINOR_CTRLMAX) {
1221/*
1222 * isdn net devices manage lots of configuration variables as linked lists.
1223 * Those lists must only be manipulated from user space. Some of the ioctl's
1224 * service routines access user space and are not atomic. Therefor, ioctl's
1225 * manipulating the lists and ioctl's sleeping while accessing the lists
1226 * are serialized by means of a semaphore.
1227 */
1228 switch (cmd) {
1229 case IIOCNETDWRSET:
1230 printk(KERN_INFO "INFO: ISDN_DW_ABC_EXTENSION not enabled\n");
1231 return(-EINVAL);
1232 case IIOCNETLCR:
1233 printk(KERN_INFO "INFO: ISDN_ABC_LCR_SUPPORT not enabled\n");
1234 return -ENODEV;
1235#ifdef CONFIG_NETDEVICES
1236 case IIOCNETAIF:
1237 /* Add a network-interface */
1238 if (arg) {
1239 if (copy_from_user(name, argp, sizeof(name)))
1240 return -EFAULT;
1241 s = name;
1242 } else {
1243 s = NULL;
1244 }
1245 ret = down_interruptible(&dev->sem);
1246 if( ret ) return ret;
1247 if ((s = isdn_net_new(s, NULL))) {
1248 if (copy_to_user(argp, s, strlen(s) + 1)){
1249 ret = -EFAULT;
1250 } else {
1251 ret = 0;
1252 }
1253 } else
1254 ret = -ENODEV;
1255 up(&dev->sem);
1256 return ret;
1257 case IIOCNETASL:
1258 /* Add a slave to a network-interface */
1259 if (arg) {
1260 if (copy_from_user(bname, argp, sizeof(bname) - 1))
1261 return -EFAULT;
1262 } else
1263 return -EINVAL;
1264 ret = down_interruptible(&dev->sem);
1265 if( ret ) return ret;
1266 if ((s = isdn_net_newslave(bname))) {
1267 if (copy_to_user(argp, s, strlen(s) + 1)){
1268 ret = -EFAULT;
1269 } else {
1270 ret = 0;
1271 }
1272 } else
1273 ret = -ENODEV;
1274 up(&dev->sem);
1275 return ret;
1276 case IIOCNETDIF:
1277 /* Delete a network-interface */
1278 if (arg) {
1279 if (copy_from_user(name, argp, sizeof(name)))
1280 return -EFAULT;
1281 ret = down_interruptible(&dev->sem);
1282 if( ret ) return ret;
1283 ret = isdn_net_rm(name);
1284 up(&dev->sem);
1285 return ret;
1286 } else
1287 return -EINVAL;
1288 case IIOCNETSCF:
1289 /* Set configurable parameters of a network-interface */
1290 if (arg) {
1291 if (copy_from_user(&cfg, argp, sizeof(cfg)))
1292 return -EFAULT;
1293 return isdn_net_setcfg(&cfg);
1294 } else
1295 return -EINVAL;
1296 case IIOCNETGCF:
1297 /* Get configurable parameters of a network-interface */
1298 if (arg) {
1299 if (copy_from_user(&cfg, argp, sizeof(cfg)))
1300 return -EFAULT;
1301 if (!(ret = isdn_net_getcfg(&cfg))) {
1302 if (copy_to_user(argp, &cfg, sizeof(cfg)))
1303 return -EFAULT;
1304 }
1305 return ret;
1306 } else
1307 return -EINVAL;
1308 case IIOCNETANM:
1309 /* Add a phone-number to a network-interface */
1310 if (arg) {
1311 if (copy_from_user(&phone, argp, sizeof(phone)))
1312 return -EFAULT;
1313 ret = down_interruptible(&dev->sem);
1314 if( ret ) return ret;
1315 ret = isdn_net_addphone(&phone);
1316 up(&dev->sem);
1317 return ret;
1318 } else
1319 return -EINVAL;
1320 case IIOCNETGNM:
1321 /* Get list of phone-numbers of a network-interface */
1322 if (arg) {
1323 if (copy_from_user(&phone, argp, sizeof(phone)))
1324 return -EFAULT;
1325 ret = down_interruptible(&dev->sem);
1326 if( ret ) return ret;
1327 ret = isdn_net_getphones(&phone, argp);
1328 up(&dev->sem);
1329 return ret;
1330 } else
1331 return -EINVAL;
1332 case IIOCNETDNM:
1333 /* Delete a phone-number of a network-interface */
1334 if (arg) {
1335 if (copy_from_user(&phone, argp, sizeof(phone)))
1336 return -EFAULT;
1337 ret = down_interruptible(&dev->sem);
1338 if( ret ) return ret;
1339 ret = isdn_net_delphone(&phone);
1340 up(&dev->sem);
1341 return ret;
1342 } else
1343 return -EINVAL;
1344 case IIOCNETDIL:
1345 /* Force dialing of a network-interface */
1346 if (arg) {
1347 if (copy_from_user(name, argp, sizeof(name)))
1348 return -EFAULT;
1349 return isdn_net_force_dial(name);
1350 } else
1351 return -EINVAL;
1352#ifdef CONFIG_ISDN_PPP
1353 case IIOCNETALN:
1354 if (!arg)
1355 return -EINVAL;
1356 if (copy_from_user(name, argp, sizeof(name)))
1357 return -EFAULT;
1358 return isdn_ppp_dial_slave(name);
1359 case IIOCNETDLN:
1360 if (!arg)
1361 return -EINVAL;
1362 if (copy_from_user(name, argp, sizeof(name)))
1363 return -EFAULT;
1364 return isdn_ppp_hangup_slave(name);
1365#endif
1366 case IIOCNETHUP:
1367 /* Force hangup of a network-interface */
1368 if (!arg)
1369 return -EINVAL;
1370 if (copy_from_user(name, argp, sizeof(name)))
1371 return -EFAULT;
1372 return isdn_net_force_hangup(name);
1373 break;
1374#endif /* CONFIG_NETDEVICES */
1375 case IIOCSETVER:
1376 dev->net_verbose = arg;
1377 printk(KERN_INFO "isdn: Verbose-Level is %d\n", dev->net_verbose);
1378 return 0;
1379 case IIOCSETGST:
1380 if (arg)
1381 dev->global_flags |= ISDN_GLOBAL_STOPPED;
1382 else
1383 dev->global_flags &= ~ISDN_GLOBAL_STOPPED;
1384 printk(KERN_INFO "isdn: Global Mode %s\n",
1385 (dev->global_flags & ISDN_GLOBAL_STOPPED) ? "stopped" : "running");
1386 return 0;
1387 case IIOCSETBRJ:
1388 drvidx = -1;
1389 if (arg) {
1390 int i;
1391 char *p;
1392 if (copy_from_user(&iocts, argp,
1393 sizeof(isdn_ioctl_struct)))
1394 return -EFAULT;
1395 if (strlen(iocts.drvid)) {
1396 if ((p = strchr(iocts.drvid, ',')))
1397 *p = 0;
1398 drvidx = -1;
1399 for (i = 0; i < ISDN_MAX_DRIVERS; i++)
1400 if (!(strcmp(dev->drvid[i], iocts.drvid))) {
1401 drvidx = i;
1402 break;
1403 }
1404 }
1405 }
1406 if (drvidx == -1)
1407 return -ENODEV;
1408 if (iocts.arg)
1409 dev->drv[drvidx]->flags |= DRV_FLAG_REJBUS;
1410 else
1411 dev->drv[drvidx]->flags &= ~DRV_FLAG_REJBUS;
1412 return 0;
1413 case IIOCSIGPRF:
1414 dev->profd = current;
1415 return 0;
1416 break;
1417 case IIOCGETPRF:
1418 /* Get all Modem-Profiles */
1419 if (arg) {
1420 char __user *p = argp;
1421 int i;
1422
1423 if (!access_ok(VERIFY_WRITE, argp,
1424 (ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN)
1425 * ISDN_MAX_CHANNELS))
1426 return -EFAULT;
1427
1428 for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
1429 if (copy_to_user(p, dev->mdm.info[i].emu.profile,
1430 ISDN_MODEM_NUMREG))
1431 return -EFAULT;
1432 p += ISDN_MODEM_NUMREG;
1433 if (copy_to_user(p, dev->mdm.info[i].emu.pmsn, ISDN_MSNLEN))
1434 return -EFAULT;
1435 p += ISDN_MSNLEN;
1436 if (copy_to_user(p, dev->mdm.info[i].emu.plmsn, ISDN_LMSNLEN))
1437 return -EFAULT;
1438 p += ISDN_LMSNLEN;
1439 }
1440 return (ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN) * ISDN_MAX_CHANNELS;
1441 } else
1442 return -EINVAL;
1443 break;
1444 case IIOCSETPRF:
1445 /* Set all Modem-Profiles */
1446 if (arg) {
1447 char __user *p = argp;
1448 int i;
1449
1450 if (!access_ok(VERIFY_READ, argp,
1451 (ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN)
1452 * ISDN_MAX_CHANNELS))
1453 return -EFAULT;
1454
1455 for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
1456 if (copy_from_user(dev->mdm.info[i].emu.profile, p,
1457 ISDN_MODEM_NUMREG))
1458 return -EFAULT;
1459 p += ISDN_MODEM_NUMREG;
1460 if (copy_from_user(dev->mdm.info[i].emu.plmsn, p, ISDN_LMSNLEN))
1461 return -EFAULT;
1462 p += ISDN_LMSNLEN;
1463 if (copy_from_user(dev->mdm.info[i].emu.pmsn, p, ISDN_MSNLEN))
1464 return -EFAULT;
1465 p += ISDN_MSNLEN;
1466 }
1467 return 0;
1468 } else
1469 return -EINVAL;
1470 break;
1471 case IIOCSETMAP:
1472 case IIOCGETMAP:
1473 /* Set/Get MSN->EAZ-Mapping for a driver */
1474 if (arg) {
1475
1476 if (copy_from_user(&iocts, argp,
1477 sizeof(isdn_ioctl_struct)))
1478 return -EFAULT;
1479 if (strlen(iocts.drvid)) {
1480 drvidx = -1;
1481 for (i = 0; i < ISDN_MAX_DRIVERS; i++)
1482 if (!(strcmp(dev->drvid[i], iocts.drvid))) {
1483 drvidx = i;
1484 break;
1485 }
1486 } else
1487 drvidx = 0;
1488 if (drvidx == -1)
1489 return -ENODEV;
1490 if (cmd == IIOCSETMAP) {
1491 int loop = 1;
1492
1493 p = (char __user *) iocts.arg;
1494 i = 0;
1495 while (loop) {
1496 int j = 0;
1497
1498 while (1) {
1499 if (!access_ok(VERIFY_READ, p, 1))
1500 return -EFAULT;
1501 get_user(bname[j], p++);
1502 switch (bname[j]) {
1503 case '\0':
1504 loop = 0;
1505 /* Fall through */
1506 case ',':
1507 bname[j] = '\0';
1508 strcpy(dev->drv[drvidx]->msn2eaz[i], bname);
1509 j = ISDN_MSNLEN;
1510 break;
1511 default:
1512 j++;
1513 }
1514 if (j >= ISDN_MSNLEN)
1515 break;
1516 }
1517 if (++i > 9)
1518 break;
1519 }
1520 } else {
1521 p = (char __user *) iocts.arg;
1522 for (i = 0; i < 10; i++) {
1523 sprintf(bname, "%s%s",
1524 strlen(dev->drv[drvidx]->msn2eaz[i]) ?
1525 dev->drv[drvidx]->msn2eaz[i] : "_",
1526 (i < 9) ? "," : "\0");
1527 if (copy_to_user(p, bname, strlen(bname) + 1))
1528 return -EFAULT;
1529 p += strlen(bname);
1530 }
1531 }
1532 return 0;
1533 } else
1534 return -EINVAL;
1535 case IIOCDBGVAR:
1536 if (arg) {
1537 if (copy_to_user(argp, &dev, sizeof(ulong)))
1538 return -EFAULT;
1539 return 0;
1540 } else
1541 return -EINVAL;
1542 break;
1543 default:
1544 if ((cmd & IIOCDRVCTL) == IIOCDRVCTL)
1545 cmd = ((cmd >> _IOC_NRSHIFT) & _IOC_NRMASK) & ISDN_DRVIOCTL_MASK;
1546 else
1547 return -EINVAL;
1548 if (arg) {
1549 int i;
1550 char *p;
1551 if (copy_from_user(&iocts, argp, sizeof(isdn_ioctl_struct)))
1552 return -EFAULT;
1553 if (strlen(iocts.drvid)) {
1554 if ((p = strchr(iocts.drvid, ',')))
1555 *p = 0;
1556 drvidx = -1;
1557 for (i = 0; i < ISDN_MAX_DRIVERS; i++)
1558 if (!(strcmp(dev->drvid[i], iocts.drvid))) {
1559 drvidx = i;
1560 break;
1561 }
1562 } else
1563 drvidx = 0;
1564 if (drvidx == -1)
1565 return -ENODEV;
1566 if (!access_ok(VERIFY_WRITE, argp,
1567 sizeof(isdn_ioctl_struct)))
1568 return -EFAULT;
1569 c.driver = drvidx;
1570 c.command = ISDN_CMD_IOCTL;
1571 c.arg = cmd;
1572 memcpy(c.parm.num, &iocts.arg, sizeof(ulong));
1573 ret = isdn_command(&c);
1574 memcpy(&iocts.arg, c.parm.num, sizeof(ulong));
1575 if (copy_to_user(argp, &iocts, sizeof(isdn_ioctl_struct)))
1576 return -EFAULT;
1577 return ret;
1578 } else
1579 return -EINVAL;
1580 }
1581 }
1582#ifdef CONFIG_ISDN_PPP
1583 if (minor <= ISDN_MINOR_PPPMAX)
1584 return (isdn_ppp_ioctl(minor - ISDN_MINOR_PPP, file, cmd, arg));
1585#endif
1586 return -ENODEV;
1587
1588#undef name
1589#undef bname
1590#undef iocts
1591#undef phone
1592#undef cfg
1593}
1594
1595/*
1596 * Open the device code.
1597 */
1598static int
1599isdn_open(struct inode *ino, struct file *filep)
1600{
1601 uint minor = MINOR(ino->i_rdev);
1602 int drvidx;
1603 int chidx;
1604 int retval = -ENODEV;
1605
1606
1607 if (minor == ISDN_MINOR_STATUS) {
1608 infostruct *p;
1609
1610 if ((p = kmalloc(sizeof(infostruct), GFP_KERNEL))) {
1611 p->next = (char *) dev->infochain;
1612 p->private = (char *) &(filep->private_data);
1613 dev->infochain = p;
1614 /* At opening we allow a single update */
1615 filep->private_data = (char *) 1;
1616 retval = 0;
1617 goto out;
1618 } else {
1619 retval = -ENOMEM;
1620 goto out;
1621 }
1622 }
1623 if (!dev->channels)
1624 goto out;
1625 if (minor <= ISDN_MINOR_BMAX) {
1626 printk(KERN_WARNING "isdn_open minor %d obsolete!\n", minor);
1627 drvidx = isdn_minor2drv(minor);
1628 if (drvidx < 0)
1629 goto out;
1630 chidx = isdn_minor2chan(minor);
1631 if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING))
1632 goto out;
1633 if (!(dev->drv[drvidx]->online & (1 << chidx)))
1634 goto out;
1635 isdn_lock_drivers();
1636 retval = 0;
1637 goto out;
1638 }
1639 if (minor <= ISDN_MINOR_CTRLMAX) {
1640 drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
1641 if (drvidx < 0)
1642 goto out;
1643 isdn_lock_drivers();
1644 retval = 0;
1645 goto out;
1646 }
1647#ifdef CONFIG_ISDN_PPP
1648 if (minor <= ISDN_MINOR_PPPMAX) {
1649 retval = isdn_ppp_open(minor - ISDN_MINOR_PPP, filep);
1650 if (retval == 0)
1651 isdn_lock_drivers();
1652 goto out;
1653 }
1654#endif
1655 out:
1656 nonseekable_open(ino, filep);
1657 return retval;
1658}
1659
1660static int
1661isdn_close(struct inode *ino, struct file *filep)
1662{
1663 uint minor = MINOR(ino->i_rdev);
1664
1665 lock_kernel();
1666 if (minor == ISDN_MINOR_STATUS) {
1667 infostruct *p = dev->infochain;
1668 infostruct *q = NULL;
1669
1670 while (p) {
1671 if (p->private == (char *) &(filep->private_data)) {
1672 if (q)
1673 q->next = p->next;
1674 else
1675 dev->infochain = (infostruct *) (p->next);
1676 kfree(p);
1677 goto out;
1678 }
1679 q = p;
1680 p = (infostruct *) (p->next);
1681 }
1682 printk(KERN_WARNING "isdn: No private data while closing isdnctrl\n");
1683 goto out;
1684 }
1685 isdn_unlock_drivers();
1686 if (minor <= ISDN_MINOR_BMAX)
1687 goto out;
1688 if (minor <= ISDN_MINOR_CTRLMAX) {
1689 if (dev->profd == current)
1690 dev->profd = NULL;
1691 goto out;
1692 }
1693#ifdef CONFIG_ISDN_PPP
1694 if (minor <= ISDN_MINOR_PPPMAX)
1695 isdn_ppp_release(minor - ISDN_MINOR_PPP, filep);
1696#endif
1697
1698 out:
1699 unlock_kernel();
1700 return 0;
1701}
1702
1703static struct file_operations isdn_fops =
1704{
1705 .owner = THIS_MODULE,
1706 .llseek = no_llseek,
1707 .read = isdn_read,
1708 .write = isdn_write,
1709 .poll = isdn_poll,
1710 .ioctl = isdn_ioctl,
1711 .open = isdn_open,
1712 .release = isdn_close,
1713};
1714
1715char *
1716isdn_map_eaz2msn(char *msn, int di)
1717{
1718 isdn_driver_t *this = dev->drv[di];
1719 int i;
1720
1721 if (strlen(msn) == 1) {
1722 i = msn[0] - '0';
1723 if ((i >= 0) && (i <= 9))
1724 if (strlen(this->msn2eaz[i]))
1725 return (this->msn2eaz[i]);
1726 }
1727 return (msn);
1728}
1729
1730/*
1731 * Find an unused ISDN-channel, whose feature-flags match the
1732 * given L2- and L3-protocols.
1733 */
1734#define L2V (~(ISDN_FEATURE_L2_V11096|ISDN_FEATURE_L2_V11019|ISDN_FEATURE_L2_V11038))
1735
1736/*
1737 * This function must be called with holding the dev->lock.
1738 */
1739int
1740isdn_get_free_channel(int usage, int l2_proto, int l3_proto, int pre_dev
1741 ,int pre_chan, char *msn)
1742{
1743 int i;
1744 ulong features;
1745 ulong vfeatures;
1746
1747 features = ((1 << l2_proto) | (0x10000 << l3_proto));
1748 vfeatures = (((1 << l2_proto) | (0x10000 << l3_proto)) &
1749 ~(ISDN_FEATURE_L2_V11096|ISDN_FEATURE_L2_V11019|ISDN_FEATURE_L2_V11038));
1750 /* If Layer-2 protocol is V.110, accept drivers with
1751 * transparent feature even if these don't support V.110
1752 * because we can emulate this in linklevel.
1753 */
1754 for (i = 0; i < ISDN_MAX_CHANNELS; i++)
1755 if (USG_NONE(dev->usage[i]) &&
1756 (dev->drvmap[i] != -1)) {
1757 int d = dev->drvmap[i];
1758 if ((dev->usage[i] & ISDN_USAGE_EXCLUSIVE) &&
1759 ((pre_dev != d) || (pre_chan != dev->chanmap[i])))
1760 continue;
1761 if (!strcmp(isdn_map_eaz2msn(msn, d), "-"))
1762 continue;
1763 if (dev->usage[i] & ISDN_USAGE_DISABLED)
1764 continue; /* usage not allowed */
1765 if (dev->drv[d]->flags & DRV_FLAG_RUNNING) {
1766 if (((dev->drv[d]->interface->features & features) == features) ||
1767 (((dev->drv[d]->interface->features & vfeatures) == vfeatures) &&
1768 (dev->drv[d]->interface->features & ISDN_FEATURE_L2_TRANS))) {
1769 if ((pre_dev < 0) || (pre_chan < 0)) {
1770 dev->usage[i] &= ISDN_USAGE_EXCLUSIVE;
1771 dev->usage[i] |= usage;
1772 isdn_info_update();
1773 return i;
1774 } else {
1775 if ((pre_dev == d) && (pre_chan == dev->chanmap[i])) {
1776 dev->usage[i] &= ISDN_USAGE_EXCLUSIVE;
1777 dev->usage[i] |= usage;
1778 isdn_info_update();
1779 return i;
1780 }
1781 }
1782 }
1783 }
1784 }
1785 return -1;
1786}
1787
1788/*
1789 * Set state of ISDN-channel to 'unused'
1790 */
1791void
1792isdn_free_channel(int di, int ch, int usage)
1793{
1794 int i;
1795
1796 for (i = 0; i < ISDN_MAX_CHANNELS; i++)
1797 if (((!usage) || ((dev->usage[i] & ISDN_USAGE_MASK) == usage)) &&
1798 (dev->drvmap[i] == di) &&
1799 (dev->chanmap[i] == ch)) {
1800 dev->usage[i] &= (ISDN_USAGE_NONE | ISDN_USAGE_EXCLUSIVE);
1801 strcpy(dev->num[i], "???");
1802 dev->ibytes[i] = 0;
1803 dev->obytes[i] = 0;
1804// 20.10.99 JIM, try to reinitialize v110 !
1805 dev->v110emu[i] = 0;
1806 atomic_set(&(dev->v110use[i]), 0);
1807 isdn_v110_close(dev->v110[i]);
1808 dev->v110[i] = NULL;
1809// 20.10.99 JIM, try to reinitialize v110 !
1810 isdn_info_update();
1811 skb_queue_purge(&dev->drv[di]->rpqueue[ch]);
1812 }
1813}
1814
1815/*
1816 * Cancel Exclusive-Flag for ISDN-channel
1817 */
1818void
1819isdn_unexclusive_channel(int di, int ch)
1820{
1821 int i;
1822
1823 for (i = 0; i < ISDN_MAX_CHANNELS; i++)
1824 if ((dev->drvmap[i] == di) &&
1825 (dev->chanmap[i] == ch)) {
1826 dev->usage[i] &= ~ISDN_USAGE_EXCLUSIVE;
1827 isdn_info_update();
1828 return;
1829 }
1830}
1831
1832/*
1833 * writebuf replacement for SKB_ABLE drivers
1834 */
1835static int
1836isdn_writebuf_stub(int drvidx, int chan, const u_char __user * buf, int len)
1837{
1838 int ret;
1839 int hl = dev->drv[drvidx]->interface->hl_hdrlen;
1840 struct sk_buff *skb = alloc_skb(hl + len, GFP_ATOMIC);
1841
1842 if (!skb)
1843 return 0;
1844 skb_reserve(skb, hl);
1845 copy_from_user(skb_put(skb, len), buf, len);
1846 ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, 1, skb);
1847 if (ret <= 0)
1848 dev_kfree_skb(skb);
1849 if (ret > 0)
1850 dev->obytes[isdn_dc2minor(drvidx, chan)] += ret;
1851 return ret;
1852}
1853
1854/*
1855 * Return: length of data on success, -ERRcode on failure.
1856 */
1857int
1858isdn_writebuf_skb_stub(int drvidx, int chan, int ack, struct sk_buff *skb)
1859{
1860 int ret;
1861 struct sk_buff *nskb = NULL;
1862 int v110_ret = skb->len;
1863 int idx = isdn_dc2minor(drvidx, chan);
1864
1865 if (dev->v110[idx]) {
1866 atomic_inc(&dev->v110use[idx]);
1867 nskb = isdn_v110_encode(dev->v110[idx], skb);
1868 atomic_dec(&dev->v110use[idx]);
1869 if (!nskb)
1870 return 0;
1871 v110_ret = *((int *)nskb->data);
1872 skb_pull(nskb, sizeof(int));
1873 if (!nskb->len) {
1874 dev_kfree_skb(nskb);
1875 return v110_ret;
1876 }
1877 /* V.110 must always be acknowledged */
1878 ack = 1;
1879 ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, ack, nskb);
1880 } else {
1881 int hl = dev->drv[drvidx]->interface->hl_hdrlen;
1882
1883 if( skb_headroom(skb) < hl ){
1884 /*
1885 * This should only occur when new HL driver with
1886 * increased hl_hdrlen was loaded after netdevice
1887 * was created and connected to the new driver.
1888 *
1889 * The V.110 branch (re-allocates on its own) does
1890 * not need this
1891 */
1892 struct sk_buff * skb_tmp;
1893
1894 skb_tmp = skb_realloc_headroom(skb, hl);
1895 printk(KERN_DEBUG "isdn_writebuf_skb_stub: reallocating headroom%s\n", skb_tmp ? "" : " failed");
1896 if (!skb_tmp) return -ENOMEM; /* 0 better? */
1897 ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, ack, skb_tmp);
1898 if( ret > 0 ){
1899 dev_kfree_skb(skb);
1900 } else {
1901 dev_kfree_skb(skb_tmp);
1902 }
1903 } else {
1904 ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, ack, skb);
1905 }
1906 }
1907 if (ret > 0) {
1908 dev->obytes[idx] += ret;
1909 if (dev->v110[idx]) {
1910 atomic_inc(&dev->v110use[idx]);
1911 dev->v110[idx]->skbuser++;
1912 atomic_dec(&dev->v110use[idx]);
1913 /* For V.110 return unencoded data length */
1914 ret = v110_ret;
1915 /* if the complete frame was send we free the skb;
1916 if not upper function will requeue the skb */
1917 if (ret == skb->len)
1918 dev_kfree_skb(skb);
1919 }
1920 } else
1921 if (dev->v110[idx])
1922 dev_kfree_skb(nskb);
1923 return ret;
1924}
1925
1926int
1927isdn_add_channels(isdn_driver_t *d, int drvidx, int n, int adding)
1928{
1929 int j, k, m;
1930
1931 init_waitqueue_head(&d->st_waitq);
1932 if (d->flags & DRV_FLAG_RUNNING)
1933 return -1;
1934 if (n < 1) return 0;
1935
1936 m = (adding) ? d->channels + n : n;
1937
1938 if (dev->channels + n > ISDN_MAX_CHANNELS) {
1939 printk(KERN_WARNING "register_isdn: Max. %d channels supported\n",
1940 ISDN_MAX_CHANNELS);
1941 return -1;
1942 }
1943
1944 if ((adding) && (d->rcverr))
1945 kfree(d->rcverr);
1946 if (!(d->rcverr = kmalloc(sizeof(int) * m, GFP_ATOMIC))) {
1947 printk(KERN_WARNING "register_isdn: Could not alloc rcverr\n");
1948 return -1;
1949 }
1950 memset((char *) d->rcverr, 0, sizeof(int) * m);
1951
1952 if ((adding) && (d->rcvcount))
1953 kfree(d->rcvcount);
1954 if (!(d->rcvcount = kmalloc(sizeof(int) * m, GFP_ATOMIC))) {
1955 printk(KERN_WARNING "register_isdn: Could not alloc rcvcount\n");
1956 if (!adding) kfree(d->rcverr);
1957 return -1;
1958 }
1959 memset((char *) d->rcvcount, 0, sizeof(int) * m);
1960
1961 if ((adding) && (d->rpqueue)) {
1962 for (j = 0; j < d->channels; j++)
1963 skb_queue_purge(&d->rpqueue[j]);
1964 kfree(d->rpqueue);
1965 }
1966 if (!(d->rpqueue = kmalloc(sizeof(struct sk_buff_head) * m, GFP_ATOMIC))) {
1967 printk(KERN_WARNING "register_isdn: Could not alloc rpqueue\n");
1968 if (!adding) {
1969 kfree(d->rcvcount);
1970 kfree(d->rcverr);
1971 }
1972 return -1;
1973 }
1974 for (j = 0; j < m; j++) {
1975 skb_queue_head_init(&d->rpqueue[j]);
1976 }
1977
1978 if ((adding) && (d->rcv_waitq))
1979 kfree(d->rcv_waitq);
1980 d->rcv_waitq = kmalloc(sizeof(wait_queue_head_t) * 2 * m, GFP_ATOMIC);
1981 if (!d->rcv_waitq) {
1982 printk(KERN_WARNING "register_isdn: Could not alloc rcv_waitq\n");
1983 if (!adding) {
1984 kfree(d->rpqueue);
1985 kfree(d->rcvcount);
1986 kfree(d->rcverr);
1987 }
1988 return -1;
1989 }
1990 d->snd_waitq = d->rcv_waitq + m;
1991 for (j = 0; j < m; j++) {
1992 init_waitqueue_head(&d->rcv_waitq[j]);
1993 init_waitqueue_head(&d->snd_waitq[j]);
1994 }
1995
1996 dev->channels += n;
1997 for (j = d->channels; j < m; j++)
1998 for (k = 0; k < ISDN_MAX_CHANNELS; k++)
1999 if (dev->chanmap[k] < 0) {
2000 dev->chanmap[k] = j;
2001 dev->drvmap[k] = drvidx;
2002 break;
2003 }
2004 d->channels = m;
2005 return 0;
2006}
2007
2008/*
2009 * Low-level-driver registration
2010 */
2011
2012static void
2013set_global_features(void)
2014{
2015 int drvidx;
2016
2017 dev->global_features = 0;
2018 for (drvidx = 0; drvidx < ISDN_MAX_DRIVERS; drvidx++) {
2019 if (!dev->drv[drvidx])
2020 continue;
2021 if (dev->drv[drvidx]->interface)
2022 dev->global_features |= dev->drv[drvidx]->interface->features;
2023 }
2024}
2025
2026#ifdef CONFIG_ISDN_DIVERSION
2027
2028static char *map_drvname(int di)
2029{
2030 if ((di < 0) || (di >= ISDN_MAX_DRIVERS))
2031 return(NULL);
2032 return(dev->drvid[di]); /* driver name */
2033} /* map_drvname */
2034
2035static int map_namedrv(char *id)
2036{ int i;
2037
2038 for (i = 0; i < ISDN_MAX_DRIVERS; i++)
2039 { if (!strcmp(dev->drvid[i],id))
2040 return(i);
2041 }
2042 return(-1);
2043} /* map_namedrv */
2044
2045int DIVERT_REG_NAME(isdn_divert_if *i_div)
2046{
2047 if (i_div->if_magic != DIVERT_IF_MAGIC)
2048 return(DIVERT_VER_ERR);
2049 switch (i_div->cmd)
2050 {
2051 case DIVERT_CMD_REL:
2052 if (divert_if != i_div)
2053 return(DIVERT_REL_ERR);
2054 divert_if = NULL; /* free interface */
2055 return(DIVERT_NO_ERR);
2056
2057 case DIVERT_CMD_REG:
2058 if (divert_if)
2059 return(DIVERT_REG_ERR);
2060 i_div->ll_cmd = isdn_command; /* set command function */
2061 i_div->drv_to_name = map_drvname;
2062 i_div->name_to_drv = map_namedrv;
2063 divert_if = i_div; /* remember interface */
2064 return(DIVERT_NO_ERR);
2065
2066 default:
2067 return(DIVERT_CMD_ERR);
2068 }
2069} /* DIVERT_REG_NAME */
2070
2071EXPORT_SYMBOL(DIVERT_REG_NAME);
2072
2073#endif /* CONFIG_ISDN_DIVERSION */
2074
2075
2076EXPORT_SYMBOL(register_isdn);
2077#ifdef CONFIG_ISDN_PPP
2078EXPORT_SYMBOL(isdn_ppp_register_compressor);
2079EXPORT_SYMBOL(isdn_ppp_unregister_compressor);
2080#endif
2081
2082int
2083register_isdn(isdn_if * i)
2084{
2085 isdn_driver_t *d;
2086 int j;
2087 ulong flags;
2088 int drvidx;
2089
2090 if (dev->drivers >= ISDN_MAX_DRIVERS) {
2091 printk(KERN_WARNING "register_isdn: Max. %d drivers supported\n",
2092 ISDN_MAX_DRIVERS);
2093 return 0;
2094 }
2095 if (!i->writebuf_skb) {
2096 printk(KERN_WARNING "register_isdn: No write routine given.\n");
2097 return 0;
2098 }
2099 if (!(d = kmalloc(sizeof(isdn_driver_t), GFP_KERNEL))) {
2100 printk(KERN_WARNING "register_isdn: Could not alloc driver-struct\n");
2101 return 0;
2102 }
2103 memset((char *) d, 0, sizeof(isdn_driver_t));
2104
2105 d->maxbufsize = i->maxbufsize;
2106 d->pktcount = 0;
2107 d->stavail = 0;
2108 d->flags = DRV_FLAG_LOADED;
2109 d->online = 0;
2110 d->interface = i;
2111 d->channels = 0;
2112 spin_lock_irqsave(&dev->lock, flags);
2113 for (drvidx = 0; drvidx < ISDN_MAX_DRIVERS; drvidx++)
2114 if (!dev->drv[drvidx])
2115 break;
2116 if (isdn_add_channels(d, drvidx, i->channels, 0)) {
2117 spin_unlock_irqrestore(&dev->lock, flags);
2118 kfree(d);
2119 return 0;
2120 }
2121 i->channels = drvidx;
2122 i->rcvcallb_skb = isdn_receive_skb_callback;
2123 i->statcallb = isdn_status_callback;
2124 if (!strlen(i->id))
2125 sprintf(i->id, "line%d", drvidx);
2126 for (j = 0; j < drvidx; j++)
2127 if (!strcmp(i->id, dev->drvid[j]))
2128 sprintf(i->id, "line%d", drvidx);
2129 dev->drv[drvidx] = d;
2130 strcpy(dev->drvid[drvidx], i->id);
2131 isdn_info_update();
2132 dev->drivers++;
2133 set_global_features();
2134 spin_unlock_irqrestore(&dev->lock, flags);
2135 return 1;
2136}
2137
2138/*
2139 *****************************************************************************
2140 * And now the modules code.
2141 *****************************************************************************
2142 */
2143
2144static char *
2145isdn_getrev(const char *revision)
2146{
2147 char *rev;
2148 char *p;
2149
2150 if ((p = strchr(revision, ':'))) {
2151 rev = p + 2;
2152 p = strchr(rev, '$');
2153 *--p = 0;
2154 } else
2155 rev = "???";
2156 return rev;
2157}
2158
2159/*
2160 * Allocate and initialize all data, register modem-devices
2161 */
2162static int __init isdn_init(void)
2163{
2164 int i;
2165 char tmprev[50];
2166
2167 if (!(dev = (isdn_dev *) vmalloc(sizeof(isdn_dev)))) {
2168 printk(KERN_WARNING "isdn: Could not allocate device-struct.\n");
2169 return -EIO;
2170 }
2171 memset((char *) dev, 0, sizeof(isdn_dev));
2172 init_timer(&dev->timer);
2173 dev->timer.function = isdn_timer_funct;
2174 spin_lock_init(&dev->lock);
2175 spin_lock_init(&dev->timerlock);
2176#ifdef MODULE
2177 dev->owner = THIS_MODULE;
2178#endif
2179 init_MUTEX(&dev->sem);
2180 init_waitqueue_head(&dev->info_waitq);
2181 for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
2182 dev->drvmap[i] = -1;
2183 dev->chanmap[i] = -1;
2184 dev->m_idx[i] = -1;
2185 strcpy(dev->num[i], "???");
2186 init_waitqueue_head(&dev->mdm.info[i].open_wait);
2187 init_waitqueue_head(&dev->mdm.info[i].close_wait);
2188 }
2189 if (register_chrdev(ISDN_MAJOR, "isdn", &isdn_fops)) {
2190 printk(KERN_WARNING "isdn: Could not register control devices\n");
2191 vfree(dev);
2192 return -EIO;
2193 }
2194 if ((isdn_tty_modem_init()) < 0) {
2195 printk(KERN_WARNING "isdn: Could not register tty devices\n");
2196 vfree(dev);
2197 unregister_chrdev(ISDN_MAJOR, "isdn");
2198 return -EIO;
2199 }
2200#ifdef CONFIG_ISDN_PPP
2201 if (isdn_ppp_init() < 0) {
2202 printk(KERN_WARNING "isdn: Could not create PPP-device-structs\n");
2203 isdn_tty_exit();
2204 unregister_chrdev(ISDN_MAJOR, "isdn");
2205 vfree(dev);
2206 return -EIO;
2207 }
2208#endif /* CONFIG_ISDN_PPP */
2209
2210 strcpy(tmprev, isdn_revision);
2211 printk(KERN_NOTICE "ISDN subsystem Rev: %s/", isdn_getrev(tmprev));
2212 strcpy(tmprev, isdn_tty_revision);
2213 printk("%s/", isdn_getrev(tmprev));
2214 strcpy(tmprev, isdn_net_revision);
2215 printk("%s/", isdn_getrev(tmprev));
2216 strcpy(tmprev, isdn_ppp_revision);
2217 printk("%s/", isdn_getrev(tmprev));
2218 strcpy(tmprev, isdn_audio_revision);
2219 printk("%s/", isdn_getrev(tmprev));
2220 strcpy(tmprev, isdn_v110_revision);
2221 printk("%s", isdn_getrev(tmprev));
2222
2223#ifdef MODULE
2224 printk(" loaded\n");
2225#else
2226 printk("\n");
2227#endif
2228 isdn_info_update();
2229 return 0;
2230}
2231
2232/*
2233 * Unload module
2234 */
2235static void __exit isdn_exit(void)
2236{
2237#ifdef CONFIG_ISDN_PPP
2238 isdn_ppp_cleanup();
2239#endif
2240 if (isdn_net_rmall() < 0) {
2241 printk(KERN_WARNING "isdn: net-device busy, remove cancelled\n");
2242 return;
2243 }
2244 isdn_tty_exit();
2245 unregister_chrdev(ISDN_MAJOR, "isdn");
2246 del_timer(&dev->timer);
2247 /* call vfree with interrupts enabled, else it will hang */
2248 vfree(dev);
2249 printk(KERN_NOTICE "ISDN-subsystem unloaded\n");
2250}
2251
2252module_init(isdn_init);
2253module_exit(isdn_exit);
diff --git a/drivers/isdn/i4l/isdn_common.h b/drivers/isdn/i4l/isdn_common.h
new file mode 100644
index 000000000000..808135c427ad
--- /dev/null
+++ b/drivers/isdn/i4l/isdn_common.h
@@ -0,0 +1,47 @@
1/* $Id: isdn_common.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
2 *
3 * header for Linux ISDN subsystem
4 * common used functions and debugging-switches (linklevel).
5 *
6 * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
7 * Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg
8 * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
9 *
10 * This software may be used and distributed according to the terms
11 * of the GNU General Public License, incorporated herein by reference.
12 *
13 */
14
15#undef ISDN_DEBUG_MODEM_OPEN
16#undef ISDN_DEBUG_MODEM_IOCTL
17#undef ISDN_DEBUG_MODEM_WAITSENT
18#undef ISDN_DEBUG_MODEM_HUP
19#undef ISDN_DEBUG_MODEM_ICALL
20#undef ISDN_DEBUG_MODEM_DUMP
21#undef ISDN_DEBUG_MODEM_VOICE
22#undef ISDN_DEBUG_AT
23#undef ISDN_DEBUG_NET_DUMP
24#undef ISDN_DEBUG_NET_DIAL
25#undef ISDN_DEBUG_NET_ICALL
26
27/* Prototypes */
28extern void isdn_lock_drivers(void);
29extern void isdn_unlock_drivers(void);
30extern void isdn_free_channel(int di, int ch, int usage);
31extern void isdn_all_eaz(int di, int ch);
32extern int isdn_command(isdn_ctrl *);
33extern int isdn_dc2minor(int di, int ch);
34extern void isdn_info_update(void);
35extern char *isdn_map_eaz2msn(char *msn, int di);
36extern void isdn_timer_ctrl(int tf, int onoff);
37extern void isdn_unexclusive_channel(int di, int ch);
38extern int isdn_getnum(char **);
39extern int isdn_readbchan(int, int, u_char *, u_char *, int, wait_queue_head_t *);
40extern int isdn_get_free_channel(int, int, int, int, int, char *);
41extern int isdn_writebuf_skb_stub(int, int, int, struct sk_buff *);
42extern int register_isdn(isdn_if * i);
43extern int isdn_msncmp( const char *, const char *);
44extern int isdn_add_channels(isdn_driver_t *, int, int, int);
45#if defined(ISDN_DEBUG_NET_DUMP) || defined(ISDN_DEBUG_MODEM_DUMP)
46extern void isdn_dumppkt(char *, u_char *, int, int);
47#endif
diff --git a/drivers/isdn/i4l/isdn_concap.c b/drivers/isdn/i4l/isdn_concap.c
new file mode 100644
index 000000000000..83a4f5382bc2
--- /dev/null
+++ b/drivers/isdn/i4l/isdn_concap.c
@@ -0,0 +1,108 @@
1/* $Id: isdn_concap.c,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
2 *
3 * Linux ISDN subsystem, protocol encapsulation
4 *
5 * This software may be used and distributed according to the terms
6 * of the GNU General Public License, incorporated herein by reference.
7 *
8 */
9
10/* Stuff to support the concap_proto by isdn4linux. isdn4linux - specific
11 * stuff goes here. Stuff that depends only on the concap protocol goes to
12 * another -- protocol specific -- source file.
13 *
14 */
15
16
17#include <linux/isdn.h>
18#include "isdn_x25iface.h"
19#include "isdn_net.h"
20#include <linux/concap.h>
21#include "isdn_concap.h"
22
23
24/* The following set of device service operations are for encapsulation
25 protocols that require for reliable datalink semantics. That means:
26
27 - before any data is to be submitted the connection must explicitly
28 be set up.
29 - after the successful set up of the connection is signalled the
30 connection is considered to be reliably up.
31
32 Auto-dialing ist not compatible with this requirements. Thus, auto-dialing
33 is completely bypassed.
34
35 It might be possible to implement a (non standardized) datalink protocol
36 that provides a reliable data link service while using some auto dialing
37 mechanism. Such a protocol would need an auxiliary channel (i.e. user-user-
38 signaling on the D-channel) while the B-channel is down.
39 */
40
41
42int isdn_concap_dl_data_req(struct concap_proto *concap, struct sk_buff *skb)
43{
44 struct net_device *ndev = concap -> net_dev;
45 isdn_net_dev *nd = ((isdn_net_local *) ndev->priv)->netdev;
46 isdn_net_local *lp = isdn_net_get_locked_lp(nd);
47
48 IX25DEBUG( "isdn_concap_dl_data_req: %s \n", concap->net_dev->name);
49 if (!lp) {
50 IX25DEBUG( "isdn_concap_dl_data_req: %s : isdn_net_send_skb returned %d\n", concap -> net_dev -> name, 1);
51 return 1;
52 }
53 lp->huptimer = 0;
54 isdn_net_writebuf_skb(lp, skb);
55 spin_unlock_bh(&lp->xmit_lock);
56 IX25DEBUG( "isdn_concap_dl_data_req: %s : isdn_net_send_skb returned %d\n", concap -> net_dev -> name, 0);
57 return 0;
58}
59
60
61int isdn_concap_dl_connect_req(struct concap_proto *concap)
62{
63 struct net_device *ndev = concap -> net_dev;
64 isdn_net_local *lp = (isdn_net_local *) ndev->priv;
65 int ret;
66 IX25DEBUG( "isdn_concap_dl_connect_req: %s \n", ndev -> name);
67
68 /* dial ... */
69 ret = isdn_net_dial_req( lp );
70 if ( ret ) IX25DEBUG("dialing failed\n");
71 return ret;
72}
73
74int isdn_concap_dl_disconn_req(struct concap_proto *concap)
75{
76 IX25DEBUG( "isdn_concap_dl_disconn_req: %s \n", concap -> net_dev -> name);
77
78 isdn_net_hangup( concap -> net_dev );
79 return 0;
80}
81
82struct concap_device_ops isdn_concap_reliable_dl_dops = {
83 &isdn_concap_dl_data_req,
84 &isdn_concap_dl_connect_req,
85 &isdn_concap_dl_disconn_req
86};
87
88struct concap_device_ops isdn_concap_demand_dial_dops = {
89 NULL, /* set this first entry to something like &isdn_net_start_xmit,
90 but the entry part of the current isdn_net_start_xmit must be
91 separated first. */
92 /* no connection control for demand dial semantics */
93 NULL,
94 NULL,
95};
96
97/* The following should better go into a dedicated source file such that
98 this sourcefile does not need to include any protocol specific header
99 files. For now:
100 */
101struct concap_proto * isdn_concap_new( int encap )
102{
103 switch ( encap ) {
104 case ISDN_NET_ENCAP_X25IFACE:
105 return isdn_x25iface_proto_new();
106 }
107 return NULL;
108}
diff --git a/drivers/isdn/i4l/isdn_concap.h b/drivers/isdn/i4l/isdn_concap.h
new file mode 100644
index 000000000000..306eb180438f
--- /dev/null
+++ b/drivers/isdn/i4l/isdn_concap.h
@@ -0,0 +1,14 @@
1/* $Id: isdn_concap.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
2 *
3 * Linux ISDN subsystem, protocol encapsulation
4 *
5 * This software may be used and distributed according to the terms
6 * of the GNU General Public License, incorporated herein by reference.
7 *
8 */
9
10extern struct concap_device_ops isdn_concap_reliable_dl_dops;
11extern struct concap_device_ops isdn_concap_demand_dial_dops;
12extern struct concap_proto * isdn_concap_new( int );
13
14
diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c
new file mode 100644
index 000000000000..e2b790e34510
--- /dev/null
+++ b/drivers/isdn/i4l/isdn_net.c
@@ -0,0 +1,3222 @@
1/* $Id: isdn_net.c,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
2 *
3 * Linux ISDN subsystem, network interfaces and related functions (linklevel).
4 *
5 * Copyright 1994-1998 by Fritz Elfert (fritz@isdn4linux.de)
6 * Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg
7 * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
8 *
9 * This software may be used and distributed according to the terms
10 * of the GNU General Public License, incorporated herein by reference.
11 *
12 * Data Over Voice (DOV) support added - Guy Ellis 23-Mar-02
13 * guy@traverse.com.au
14 * Outgoing calls - looks for a 'V' in first char of dialed number
15 * Incoming calls - checks first character of eaz as follows:
16 * Numeric - accept DATA only - original functionality
17 * 'V' - accept VOICE (DOV) only
18 * 'B' - accept BOTH DATA and DOV types
19 *
20 * Jan 2001: fix CISCO HDLC Bjoern A. Zeeb <i4l@zabbadoz.net>
21 * for info on the protocol, see
22 * http://i4l.zabbadoz.net/i4l/cisco-hdlc.txt
23 */
24
25#include <linux/config.h>
26#include <linux/isdn.h>
27#include <net/arp.h>
28#include <net/dst.h>
29#include <net/pkt_sched.h>
30#include <linux/inetdevice.h>
31#include "isdn_common.h"
32#include "isdn_net.h"
33#ifdef CONFIG_ISDN_PPP
34#include "isdn_ppp.h"
35#endif
36#ifdef CONFIG_ISDN_X25
37#include <linux/concap.h>
38#include "isdn_concap.h"
39#endif
40
41
42/*
43 * Outline of new tbusy handling:
44 *
45 * Old method, roughly spoken, consisted of setting tbusy when entering
46 * isdn_net_start_xmit() and at several other locations and clearing
47 * it from isdn_net_start_xmit() thread when sending was successful.
48 *
49 * With 2.3.x multithreaded network core, to prevent problems, tbusy should
50 * only be set by the isdn_net_start_xmit() thread and only when a tx-busy
51 * condition is detected. Other threads (in particular isdn_net_stat_callb())
52 * are only allowed to clear tbusy.
53 *
54 * -HE
55 */
56
57/*
58 * About SOFTNET:
59 * Most of the changes were pretty obvious and basically done by HE already.
60 *
61 * One problem of the isdn net device code is that is uses struct net_device
62 * for masters and slaves. However, only master interface are registered to
63 * the network layer, and therefore, it only makes sense to call netif_*
64 * functions on them.
65 *
66 * --KG
67 */
68
69/*
70 * Find out if the netdevice has been ifup-ed yet.
71 * For slaves, look at the corresponding master.
72 */
73static __inline__ int isdn_net_device_started(isdn_net_dev *n)
74{
75 isdn_net_local *lp = n->local;
76 struct net_device *dev;
77
78 if (lp->master)
79 dev = lp->master;
80 else
81 dev = &n->dev;
82 return netif_running(dev);
83}
84
85/*
86 * wake up the network -> net_device queue.
87 * For slaves, wake the corresponding master interface.
88 */
89static __inline__ void isdn_net_device_wake_queue(isdn_net_local *lp)
90{
91 if (lp->master)
92 netif_wake_queue(lp->master);
93 else
94 netif_wake_queue(&lp->netdev->dev);
95}
96
97/*
98 * stop the network -> net_device queue.
99 * For slaves, stop the corresponding master interface.
100 */
101static __inline__ void isdn_net_device_stop_queue(isdn_net_local *lp)
102{
103 if (lp->master)
104 netif_stop_queue(lp->master);
105 else
106 netif_stop_queue(&lp->netdev->dev);
107}
108
109/*
110 * find out if the net_device which this lp belongs to (lp can be
111 * master or slave) is busy. It's busy iff all (master and slave)
112 * queues are busy
113 */
114static __inline__ int isdn_net_device_busy(isdn_net_local *lp)
115{
116 isdn_net_local *nlp;
117 isdn_net_dev *nd;
118 unsigned long flags;
119
120 if (!isdn_net_lp_busy(lp))
121 return 0;
122
123 if (lp->master)
124 nd = ((isdn_net_local *) lp->master->priv)->netdev;
125 else
126 nd = lp->netdev;
127
128 spin_lock_irqsave(&nd->queue_lock, flags);
129 nlp = lp->next;
130 while (nlp != lp) {
131 if (!isdn_net_lp_busy(nlp)) {
132 spin_unlock_irqrestore(&nd->queue_lock, flags);
133 return 0;
134 }
135 nlp = nlp->next;
136 }
137 spin_unlock_irqrestore(&nd->queue_lock, flags);
138 return 1;
139}
140
141static __inline__ void isdn_net_inc_frame_cnt(isdn_net_local *lp)
142{
143 atomic_inc(&lp->frame_cnt);
144 if (isdn_net_device_busy(lp))
145 isdn_net_device_stop_queue(lp);
146}
147
148static __inline__ void isdn_net_dec_frame_cnt(isdn_net_local *lp)
149{
150 atomic_dec(&lp->frame_cnt);
151
152 if (!(isdn_net_device_busy(lp))) {
153 if (!skb_queue_empty(&lp->super_tx_queue)) {
154 schedule_work(&lp->tqueue);
155 } else {
156 isdn_net_device_wake_queue(lp);
157 }
158 }
159}
160
161static __inline__ void isdn_net_zero_frame_cnt(isdn_net_local *lp)
162{
163 atomic_set(&lp->frame_cnt, 0);
164}
165
166/* For 2.2.x we leave the transmitter busy timeout at 2 secs, just
167 * to be safe.
168 * For 2.3.x we push it up to 20 secs, because call establishment
169 * (in particular callback) may take such a long time, and we
170 * don't want confusing messages in the log. However, there is a slight
171 * possibility that this large timeout will break other things like MPPP,
172 * which might rely on the tx timeout. If so, we'll find out this way...
173 */
174
175#define ISDN_NET_TX_TIMEOUT (20*HZ)
176
177/* Prototypes */
178
179int isdn_net_force_dial_lp(isdn_net_local *);
180static int isdn_net_start_xmit(struct sk_buff *, struct net_device *);
181
182static void isdn_net_ciscohdlck_connected(isdn_net_local *lp);
183static void isdn_net_ciscohdlck_disconnected(isdn_net_local *lp);
184
185char *isdn_net_revision = "$Revision: 1.1.2.2 $";
186
187 /*
188 * Code for raw-networking over ISDN
189 */
190
191static void
192isdn_net_unreachable(struct net_device *dev, struct sk_buff *skb, char *reason)
193{
194 if(skb) {
195
196 u_short proto = ntohs(skb->protocol);
197
198 printk(KERN_DEBUG "isdn_net: %s: %s, signalling dst_link_failure %s\n",
199 dev->name,
200 (reason != NULL) ? reason : "unknown",
201 (proto != ETH_P_IP) ? "Protocol != ETH_P_IP" : "");
202
203 dst_link_failure(skb);
204 }
205 else { /* dial not triggered by rawIP packet */
206 printk(KERN_DEBUG "isdn_net: %s: %s\n",
207 dev->name,
208 (reason != NULL) ? reason : "reason unknown");
209 }
210}
211
212static void
213isdn_net_reset(struct net_device *dev)
214{
215#ifdef CONFIG_ISDN_X25
216 struct concap_device_ops * dops =
217 ( (isdn_net_local *) dev->priv ) -> dops;
218 struct concap_proto * cprot =
219 ( (isdn_net_local *) dev->priv ) -> netdev -> cprot;
220#endif
221#ifdef CONFIG_ISDN_X25
222 if( cprot && cprot -> pops && dops )
223 cprot -> pops -> restart ( cprot, dev, dops );
224#endif
225}
226
227/* Open/initialize the board. */
228static int
229isdn_net_open(struct net_device *dev)
230{
231 int i;
232 struct net_device *p;
233 struct in_device *in_dev;
234
235 /* moved here from isdn_net_reset, because only the master has an
236 interface associated which is supposed to be started. BTW:
237 we need to call netif_start_queue, not netif_wake_queue here */
238 netif_start_queue(dev);
239
240 isdn_net_reset(dev);
241 /* Fill in the MAC-level header (not needed, but for compatibility... */
242 for (i = 0; i < ETH_ALEN - sizeof(u32); i++)
243 dev->dev_addr[i] = 0xfc;
244 if ((in_dev = dev->ip_ptr) != NULL) {
245 /*
246 * Any address will do - we take the first
247 */
248 struct in_ifaddr *ifa = in_dev->ifa_list;
249 if (ifa != NULL)
250 memcpy(dev->dev_addr+2, &ifa->ifa_local, 4);
251 }
252
253 /* If this interface has slaves, start them also */
254
255 if ((p = (((isdn_net_local *) dev->priv)->slave))) {
256 while (p) {
257 isdn_net_reset(p);
258 p = (((isdn_net_local *) p->priv)->slave);
259 }
260 }
261 isdn_lock_drivers();
262 return 0;
263}
264
265/*
266 * Assign an ISDN-channel to a net-interface
267 */
268static void
269isdn_net_bind_channel(isdn_net_local * lp, int idx)
270{
271 lp->flags |= ISDN_NET_CONNECTED;
272 lp->isdn_device = dev->drvmap[idx];
273 lp->isdn_channel = dev->chanmap[idx];
274 dev->rx_netdev[idx] = lp->netdev;
275 dev->st_netdev[idx] = lp->netdev;
276}
277
278/*
279 * unbind a net-interface (resets interface after an error)
280 */
281static void
282isdn_net_unbind_channel(isdn_net_local * lp)
283{
284 skb_queue_purge(&lp->super_tx_queue);
285
286 if (!lp->master) { /* reset only master device */
287 /* Moral equivalent of dev_purge_queues():
288 BEWARE! This chunk of code cannot be called from hardware
289 interrupt handler. I hope it is true. --ANK
290 */
291 qdisc_reset(lp->netdev->dev.qdisc);
292 }
293 lp->dialstate = 0;
294 dev->rx_netdev[isdn_dc2minor(lp->isdn_device, lp->isdn_channel)] = NULL;
295 dev->st_netdev[isdn_dc2minor(lp->isdn_device, lp->isdn_channel)] = NULL;
296 isdn_free_channel(lp->isdn_device, lp->isdn_channel, ISDN_USAGE_NET);
297 lp->flags &= ~ISDN_NET_CONNECTED;
298 lp->isdn_device = -1;
299 lp->isdn_channel = -1;
300}
301
302/*
303 * Perform auto-hangup and cps-calculation for net-interfaces.
304 *
305 * auto-hangup:
306 * Increment idle-counter (this counter is reset on any incoming or
307 * outgoing packet), if counter exceeds configured limit either do a
308 * hangup immediately or - if configured - wait until just before the next
309 * charge-info.
310 *
311 * cps-calculation (needed for dynamic channel-bundling):
312 * Since this function is called every second, simply reset the
313 * byte-counter of the interface after copying it to the cps-variable.
314 */
315unsigned long last_jiffies = -HZ;
316
317void
318isdn_net_autohup(void)
319{
320 isdn_net_dev *p = dev->netdev;
321 int anymore;
322
323 anymore = 0;
324 while (p) {
325 isdn_net_local *l = p->local;
326 if (jiffies == last_jiffies)
327 l->cps = l->transcount;
328 else
329 l->cps = (l->transcount * HZ) / (jiffies - last_jiffies);
330 l->transcount = 0;
331 if (dev->net_verbose > 3)
332 printk(KERN_DEBUG "%s: %d bogocps\n", l->name, l->cps);
333 if ((l->flags & ISDN_NET_CONNECTED) && (!l->dialstate)) {
334 anymore = 1;
335 l->huptimer++;
336 /*
337 * if there is some dialmode where timeout-hangup
338 * should _not_ be done, check for that here
339 */
340 if ((l->onhtime) &&
341 (l->huptimer > l->onhtime))
342 {
343 if (l->hupflags & ISDN_MANCHARGE &&
344 l->hupflags & ISDN_CHARGEHUP) {
345 while (time_after(jiffies, l->chargetime + l->chargeint))
346 l->chargetime += l->chargeint;
347 if (time_after(jiffies, l->chargetime + l->chargeint - 2 * HZ))
348 if (l->outgoing || l->hupflags & ISDN_INHUP)
349 isdn_net_hangup(&p->dev);
350 } else if (l->outgoing) {
351 if (l->hupflags & ISDN_CHARGEHUP) {
352 if (l->hupflags & ISDN_WAITCHARGE) {
353 printk(KERN_DEBUG "isdn_net: Hupflags of %s are %X\n",
354 l->name, l->hupflags);
355 isdn_net_hangup(&p->dev);
356 } else if (time_after(jiffies, l->chargetime + l->chargeint)) {
357 printk(KERN_DEBUG
358 "isdn_net: %s: chtime = %lu, chint = %d\n",
359 l->name, l->chargetime, l->chargeint);
360 isdn_net_hangup(&p->dev);
361 }
362 } else
363 isdn_net_hangup(&p->dev);
364 } else if (l->hupflags & ISDN_INHUP)
365 isdn_net_hangup(&p->dev);
366 }
367
368 if(dev->global_flags & ISDN_GLOBAL_STOPPED || (ISDN_NET_DIALMODE(*l) == ISDN_NET_DM_OFF)) {
369 isdn_net_hangup(&p->dev);
370 break;
371 }
372 }
373 p = (isdn_net_dev *) p->next;
374 }
375 last_jiffies = jiffies;
376 isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, anymore);
377}
378
379static void isdn_net_lp_disconnected(isdn_net_local *lp)
380{
381 isdn_net_rm_from_bundle(lp);
382}
383
384/*
385 * Handle status-messages from ISDN-interfacecard.
386 * This function is called from within the main-status-dispatcher
387 * isdn_status_callback, which itself is called from the low-level driver.
388 * Return: 1 = Event handled, 0 = not for us or unknown Event.
389 */
390int
391isdn_net_stat_callback(int idx, isdn_ctrl *c)
392{
393 isdn_net_dev *p = dev->st_netdev[idx];
394 int cmd = c->command;
395
396 if (p) {
397 isdn_net_local *lp = p->local;
398#ifdef CONFIG_ISDN_X25
399 struct concap_proto *cprot = lp->netdev->cprot;
400 struct concap_proto_ops *pops = cprot ? cprot->pops : NULL;
401#endif
402 switch (cmd) {
403 case ISDN_STAT_BSENT:
404 /* A packet has successfully been sent out */
405 if ((lp->flags & ISDN_NET_CONNECTED) &&
406 (!lp->dialstate)) {
407 isdn_net_dec_frame_cnt(lp);
408 lp->stats.tx_packets++;
409 lp->stats.tx_bytes += c->parm.length;
410 }
411 return 1;
412 case ISDN_STAT_DCONN:
413 /* D-Channel is up */
414 switch (lp->dialstate) {
415 case 4:
416 case 7:
417 case 8:
418 lp->dialstate++;
419 return 1;
420 case 12:
421 lp->dialstate = 5;
422 return 1;
423 }
424 break;
425 case ISDN_STAT_DHUP:
426 /* Either D-Channel-hangup or error during dialout */
427#ifdef CONFIG_ISDN_X25
428 /* If we are not connencted then dialing had
429 failed. If there are generic encap protocol
430 receiver routines signal the closure of
431 the link*/
432
433 if( !(lp->flags & ISDN_NET_CONNECTED)
434 && pops && pops -> disconn_ind )
435 pops -> disconn_ind(cprot);
436#endif /* CONFIG_ISDN_X25 */
437 if ((!lp->dialstate) && (lp->flags & ISDN_NET_CONNECTED)) {
438 if (lp->p_encap == ISDN_NET_ENCAP_CISCOHDLCK)
439 isdn_net_ciscohdlck_disconnected(lp);
440#ifdef CONFIG_ISDN_PPP
441 if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
442 isdn_ppp_free(lp);
443#endif
444 isdn_net_lp_disconnected(lp);
445 isdn_all_eaz(lp->isdn_device, lp->isdn_channel);
446 printk(KERN_INFO "%s: remote hangup\n", lp->name);
447 printk(KERN_INFO "%s: Chargesum is %d\n", lp->name,
448 lp->charge);
449 isdn_net_unbind_channel(lp);
450 return 1;
451 }
452 break;
453#ifdef CONFIG_ISDN_X25
454 case ISDN_STAT_BHUP:
455 /* B-Channel-hangup */
456 /* try if there are generic encap protocol
457 receiver routines and signal the closure of
458 the link */
459 if( pops && pops -> disconn_ind ){
460 pops -> disconn_ind(cprot);
461 return 1;
462 }
463 break;
464#endif /* CONFIG_ISDN_X25 */
465 case ISDN_STAT_BCONN:
466 /* B-Channel is up */
467 isdn_net_zero_frame_cnt(lp);
468 switch (lp->dialstate) {
469 case 5:
470 case 6:
471 case 7:
472 case 8:
473 case 9:
474 case 10:
475 case 12:
476 if (lp->dialstate <= 6) {
477 dev->usage[idx] |= ISDN_USAGE_OUTGOING;
478 isdn_info_update();
479 } else
480 dev->rx_netdev[idx] = p;
481 lp->dialstate = 0;
482 isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, 1);
483 if (lp->p_encap == ISDN_NET_ENCAP_CISCOHDLCK)
484 isdn_net_ciscohdlck_connected(lp);
485 if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP) {
486 if (lp->master) { /* is lp a slave? */
487 isdn_net_dev *nd = ((isdn_net_local *)lp->master->priv)->netdev;
488 isdn_net_add_to_bundle(nd, lp);
489 }
490 }
491 printk(KERN_INFO "isdn_net: %s connected\n", lp->name);
492 /* If first Chargeinfo comes before B-Channel connect,
493 * we correct the timestamp here.
494 */
495 lp->chargetime = jiffies;
496
497 /* reset dial-timeout */
498 lp->dialstarted = 0;
499 lp->dialwait_timer = 0;
500
501#ifdef CONFIG_ISDN_PPP
502 if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
503 isdn_ppp_wakeup_daemon(lp);
504#endif
505#ifdef CONFIG_ISDN_X25
506 /* try if there are generic concap receiver routines */
507 if( pops )
508 if( pops->connect_ind)
509 pops->connect_ind(cprot);
510#endif /* CONFIG_ISDN_X25 */
511 /* ppp needs to do negotiations first */
512 if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP)
513 isdn_net_device_wake_queue(lp);
514 return 1;
515 }
516 break;
517 case ISDN_STAT_NODCH:
518 /* No D-Channel avail. */
519 if (lp->dialstate == 4) {
520 lp->dialstate--;
521 return 1;
522 }
523 break;
524 case ISDN_STAT_CINF:
525 /* Charge-info from TelCo. Calculate interval between
526 * charge-infos and set timestamp for last info for
527 * usage by isdn_net_autohup()
528 */
529 lp->charge++;
530 if (lp->hupflags & ISDN_HAVECHARGE) {
531 lp->hupflags &= ~ISDN_WAITCHARGE;
532 lp->chargeint = jiffies - lp->chargetime - (2 * HZ);
533 }
534 if (lp->hupflags & ISDN_WAITCHARGE)
535 lp->hupflags |= ISDN_HAVECHARGE;
536 lp->chargetime = jiffies;
537 printk(KERN_DEBUG "isdn_net: Got CINF chargetime of %s now %lu\n",
538 lp->name, lp->chargetime);
539 return 1;
540 }
541 }
542 return 0;
543}
544
545/*
546 * Perform dialout for net-interfaces and timeout-handling for
547 * D-Channel-up and B-Channel-up Messages.
548 * This function is initially called from within isdn_net_start_xmit() or
549 * or isdn_net_find_icall() after initializing the dialstate for an
550 * interface. If further calls are needed, the function schedules itself
551 * for a timer-callback via isdn_timer_function().
552 * The dialstate is also affected by incoming status-messages from
553 * the ISDN-Channel which are handled in isdn_net_stat_callback() above.
554 */
555void
556isdn_net_dial(void)
557{
558 isdn_net_dev *p = dev->netdev;
559 int anymore = 0;
560 int i;
561 isdn_ctrl cmd;
562 u_char *phone_number;
563
564 while (p) {
565 isdn_net_local *lp = p->local;
566
567#ifdef ISDN_DEBUG_NET_DIAL
568 if (lp->dialstate)
569 printk(KERN_DEBUG "%s: dialstate=%d\n", lp->name, lp->dialstate);
570#endif
571 switch (lp->dialstate) {
572 case 0:
573 /* Nothing to do for this interface */
574 break;
575 case 1:
576 /* Initiate dialout. Set phone-number-pointer to first number
577 * of interface.
578 */
579 lp->dial = lp->phone[1];
580 if (!lp->dial) {
581 printk(KERN_WARNING "%s: phone number deleted?\n",
582 lp->name);
583 isdn_net_hangup(&p->dev);
584 break;
585 }
586 anymore = 1;
587
588 if(lp->dialtimeout > 0)
589 if(lp->dialstarted == 0 || time_after(jiffies, lp->dialstarted + lp->dialtimeout + lp->dialwait)) {
590 lp->dialstarted = jiffies;
591 lp->dialwait_timer = 0;
592 }
593
594 lp->dialstate++;
595 /* Fall through */
596 case 2:
597 /* Prepare dialing. Clear EAZ, then set EAZ. */
598 cmd.driver = lp->isdn_device;
599 cmd.arg = lp->isdn_channel;
600 cmd.command = ISDN_CMD_CLREAZ;
601 isdn_command(&cmd);
602 sprintf(cmd.parm.num, "%s", isdn_map_eaz2msn(lp->msn, cmd.driver));
603 cmd.command = ISDN_CMD_SETEAZ;
604 isdn_command(&cmd);
605 lp->dialretry = 0;
606 anymore = 1;
607 lp->dialstate++;
608 /* Fall through */
609 case 3:
610 /* Setup interface, dial current phone-number, switch to next number.
611 * If list of phone-numbers is exhausted, increment
612 * retry-counter.
613 */
614 if(dev->global_flags & ISDN_GLOBAL_STOPPED || (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF)) {
615 char *s;
616 if (dev->global_flags & ISDN_GLOBAL_STOPPED)
617 s = "dial suppressed: isdn system stopped";
618 else
619 s = "dial suppressed: dialmode `off'";
620 isdn_net_unreachable(&p->dev, NULL, s);
621 isdn_net_hangup(&p->dev);
622 break;
623 }
624 cmd.driver = lp->isdn_device;
625 cmd.command = ISDN_CMD_SETL2;
626 cmd.arg = lp->isdn_channel + (lp->l2_proto << 8);
627 isdn_command(&cmd);
628 cmd.driver = lp->isdn_device;
629 cmd.command = ISDN_CMD_SETL3;
630 cmd.arg = lp->isdn_channel + (lp->l3_proto << 8);
631 isdn_command(&cmd);
632 cmd.driver = lp->isdn_device;
633 cmd.arg = lp->isdn_channel;
634 if (!lp->dial) {
635 printk(KERN_WARNING "%s: phone number deleted?\n",
636 lp->name);
637 isdn_net_hangup(&p->dev);
638 break;
639 }
640 if (!strncmp(lp->dial->num, "LEASED", strlen("LEASED"))) {
641 lp->dialstate = 4;
642 printk(KERN_INFO "%s: Open leased line ...\n", lp->name);
643 } else {
644 if(lp->dialtimeout > 0)
645 if (time_after(jiffies, lp->dialstarted + lp->dialtimeout)) {
646 lp->dialwait_timer = jiffies + lp->dialwait;
647 lp->dialstarted = 0;
648 isdn_net_unreachable(&p->dev, NULL, "dial: timed out");
649 isdn_net_hangup(&p->dev);
650 break;
651 }
652
653 cmd.driver = lp->isdn_device;
654 cmd.command = ISDN_CMD_DIAL;
655 cmd.parm.setup.si2 = 0;
656
657 /* check for DOV */
658 phone_number = lp->dial->num;
659 if ((*phone_number == 'v') ||
660 (*phone_number == 'V')) { /* DOV call */
661 cmd.parm.setup.si1 = 1;
662 } else { /* DATA call */
663 cmd.parm.setup.si1 = 7;
664 }
665
666 strcpy(cmd.parm.setup.phone, phone_number);
667 /*
668 * Switch to next number or back to start if at end of list.
669 */
670 if (!(lp->dial = (isdn_net_phone *) lp->dial->next)) {
671 lp->dial = lp->phone[1];
672 lp->dialretry++;
673
674 if (lp->dialretry > lp->dialmax) {
675 if (lp->dialtimeout == 0) {
676 lp->dialwait_timer = jiffies + lp->dialwait;
677 lp->dialstarted = 0;
678 isdn_net_unreachable(&p->dev, NULL, "dial: tried all numbers dialmax times");
679 }
680 isdn_net_hangup(&p->dev);
681 break;
682 }
683 }
684 sprintf(cmd.parm.setup.eazmsn, "%s",
685 isdn_map_eaz2msn(lp->msn, cmd.driver));
686 i = isdn_dc2minor(lp->isdn_device, lp->isdn_channel);
687 if (i >= 0) {
688 strcpy(dev->num[i], cmd.parm.setup.phone);
689 dev->usage[i] |= ISDN_USAGE_OUTGOING;
690 isdn_info_update();
691 }
692 printk(KERN_INFO "%s: dialing %d %s... %s\n", lp->name,
693 lp->dialretry, cmd.parm.setup.phone,
694 (cmd.parm.setup.si1 == 1) ? "DOV" : "");
695 lp->dtimer = 0;
696#ifdef ISDN_DEBUG_NET_DIAL
697 printk(KERN_DEBUG "dial: d=%d c=%d\n", lp->isdn_device,
698 lp->isdn_channel);
699#endif
700 isdn_command(&cmd);
701 }
702 lp->huptimer = 0;
703 lp->outgoing = 1;
704 if (lp->chargeint) {
705 lp->hupflags |= ISDN_HAVECHARGE;
706 lp->hupflags &= ~ISDN_WAITCHARGE;
707 } else {
708 lp->hupflags |= ISDN_WAITCHARGE;
709 lp->hupflags &= ~ISDN_HAVECHARGE;
710 }
711 anymore = 1;
712 lp->dialstate =
713 (lp->cbdelay &&
714 (lp->flags & ISDN_NET_CBOUT)) ? 12 : 4;
715 break;
716 case 4:
717 /* Wait for D-Channel-connect.
718 * If timeout, switch back to state 3.
719 * Dialmax-handling moved to state 3.
720 */
721 if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT10)
722 lp->dialstate = 3;
723 anymore = 1;
724 break;
725 case 5:
726 /* Got D-Channel-Connect, send B-Channel-request */
727 cmd.driver = lp->isdn_device;
728 cmd.arg = lp->isdn_channel;
729 cmd.command = ISDN_CMD_ACCEPTB;
730 anymore = 1;
731 lp->dtimer = 0;
732 lp->dialstate++;
733 isdn_command(&cmd);
734 break;
735 case 6:
736 /* Wait for B- or D-Channel-connect. If timeout,
737 * switch back to state 3.
738 */
739#ifdef ISDN_DEBUG_NET_DIAL
740 printk(KERN_DEBUG "dialtimer2: %d\n", lp->dtimer);
741#endif
742 if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT10)
743 lp->dialstate = 3;
744 anymore = 1;
745 break;
746 case 7:
747 /* Got incoming Call, setup L2 and L3 protocols,
748 * then wait for D-Channel-connect
749 */
750#ifdef ISDN_DEBUG_NET_DIAL
751 printk(KERN_DEBUG "dialtimer4: %d\n", lp->dtimer);
752#endif
753 cmd.driver = lp->isdn_device;
754 cmd.command = ISDN_CMD_SETL2;
755 cmd.arg = lp->isdn_channel + (lp->l2_proto << 8);
756 isdn_command(&cmd);
757 cmd.driver = lp->isdn_device;
758 cmd.command = ISDN_CMD_SETL3;
759 cmd.arg = lp->isdn_channel + (lp->l3_proto << 8);
760 isdn_command(&cmd);
761 if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT15)
762 isdn_net_hangup(&p->dev);
763 else {
764 anymore = 1;
765 lp->dialstate++;
766 }
767 break;
768 case 9:
769 /* Got incoming D-Channel-Connect, send B-Channel-request */
770 cmd.driver = lp->isdn_device;
771 cmd.arg = lp->isdn_channel;
772 cmd.command = ISDN_CMD_ACCEPTB;
773 isdn_command(&cmd);
774 anymore = 1;
775 lp->dtimer = 0;
776 lp->dialstate++;
777 break;
778 case 8:
779 case 10:
780 /* Wait for B- or D-channel-connect */
781#ifdef ISDN_DEBUG_NET_DIAL
782 printk(KERN_DEBUG "dialtimer4: %d\n", lp->dtimer);
783#endif
784 if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT10)
785 isdn_net_hangup(&p->dev);
786 else
787 anymore = 1;
788 break;
789 case 11:
790 /* Callback Delay */
791 if (lp->dtimer++ > lp->cbdelay)
792 lp->dialstate = 1;
793 anymore = 1;
794 break;
795 case 12:
796 /* Remote does callback. Hangup after cbdelay, then wait for incoming
797 * call (in state 4).
798 */
799 if (lp->dtimer++ > lp->cbdelay)
800 {
801 printk(KERN_INFO "%s: hangup waiting for callback ...\n", lp->name);
802 lp->dtimer = 0;
803 lp->dialstate = 4;
804 cmd.driver = lp->isdn_device;
805 cmd.command = ISDN_CMD_HANGUP;
806 cmd.arg = lp->isdn_channel;
807 isdn_command(&cmd);
808 isdn_all_eaz(lp->isdn_device, lp->isdn_channel);
809 }
810 anymore = 1;
811 break;
812 default:
813 printk(KERN_WARNING "isdn_net: Illegal dialstate %d for device %s\n",
814 lp->dialstate, lp->name);
815 }
816 p = (isdn_net_dev *) p->next;
817 }
818 isdn_timer_ctrl(ISDN_TIMER_NETDIAL, anymore);
819}
820
821/*
822 * Perform hangup for a net-interface.
823 */
824void
825isdn_net_hangup(struct net_device *d)
826{
827 isdn_net_local *lp = (isdn_net_local *) d->priv;
828 isdn_ctrl cmd;
829#ifdef CONFIG_ISDN_X25
830 struct concap_proto *cprot = lp->netdev->cprot;
831 struct concap_proto_ops *pops = cprot ? cprot->pops : NULL;
832#endif
833
834 if (lp->flags & ISDN_NET_CONNECTED) {
835 if (lp->slave != NULL) {
836 isdn_net_local *slp = (isdn_net_local *)lp->slave->priv;
837 if (slp->flags & ISDN_NET_CONNECTED) {
838 printk(KERN_INFO
839 "isdn_net: hang up slave %s before %s\n",
840 slp->name, lp->name);
841 isdn_net_hangup(lp->slave);
842 }
843 }
844 printk(KERN_INFO "isdn_net: local hangup %s\n", lp->name);
845#ifdef CONFIG_ISDN_PPP
846 if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
847 isdn_ppp_free(lp);
848#endif
849 isdn_net_lp_disconnected(lp);
850#ifdef CONFIG_ISDN_X25
851 /* try if there are generic encap protocol
852 receiver routines and signal the closure of
853 the link */
854 if( pops && pops -> disconn_ind )
855 pops -> disconn_ind(cprot);
856#endif /* CONFIG_ISDN_X25 */
857
858 cmd.driver = lp->isdn_device;
859 cmd.command = ISDN_CMD_HANGUP;
860 cmd.arg = lp->isdn_channel;
861 isdn_command(&cmd);
862 printk(KERN_INFO "%s: Chargesum is %d\n", lp->name, lp->charge);
863 isdn_all_eaz(lp->isdn_device, lp->isdn_channel);
864 }
865 isdn_net_unbind_channel(lp);
866}
867
868typedef struct {
869 unsigned short source;
870 unsigned short dest;
871} ip_ports;
872
873static void
874isdn_net_log_skb(struct sk_buff * skb, isdn_net_local * lp)
875{
876 u_char *p = skb->nh.raw; /* hopefully, this was set correctly */
877 unsigned short proto = ntohs(skb->protocol);
878 int data_ofs;
879 ip_ports *ipp;
880 char addinfo[100];
881
882 addinfo[0] = '\0';
883 /* This check stolen from 2.1.72 dev_queue_xmit_nit() */
884 if (skb->nh.raw < skb->data || skb->nh.raw >= skb->tail) {
885 /* fall back to old isdn_net_log_packet method() */
886 char * buf = skb->data;
887
888 printk(KERN_DEBUG "isdn_net: protocol %04x is buggy, dev %s\n", skb->protocol, lp->name);
889 p = buf;
890 proto = ETH_P_IP;
891 switch (lp->p_encap) {
892 case ISDN_NET_ENCAP_IPTYP:
893 proto = ntohs(*(unsigned short *) &buf[0]);
894 p = &buf[2];
895 break;
896 case ISDN_NET_ENCAP_ETHER:
897 proto = ntohs(*(unsigned short *) &buf[12]);
898 p = &buf[14];
899 break;
900 case ISDN_NET_ENCAP_CISCOHDLC:
901 proto = ntohs(*(unsigned short *) &buf[2]);
902 p = &buf[4];
903 break;
904#ifdef CONFIG_ISDN_PPP
905 case ISDN_NET_ENCAP_SYNCPPP:
906 proto = ntohs(skb->protocol);
907 p = &buf[IPPP_MAX_HEADER];
908 break;
909#endif
910 }
911 }
912 data_ofs = ((p[0] & 15) * 4);
913 switch (proto) {
914 case ETH_P_IP:
915 switch (p[9]) {
916 case 1:
917 strcpy(addinfo, " ICMP");
918 break;
919 case 2:
920 strcpy(addinfo, " IGMP");
921 break;
922 case 4:
923 strcpy(addinfo, " IPIP");
924 break;
925 case 6:
926 ipp = (ip_ports *) (&p[data_ofs]);
927 sprintf(addinfo, " TCP, port: %d -> %d", ntohs(ipp->source),
928 ntohs(ipp->dest));
929 break;
930 case 8:
931 strcpy(addinfo, " EGP");
932 break;
933 case 12:
934 strcpy(addinfo, " PUP");
935 break;
936 case 17:
937 ipp = (ip_ports *) (&p[data_ofs]);
938 sprintf(addinfo, " UDP, port: %d -> %d", ntohs(ipp->source),
939 ntohs(ipp->dest));
940 break;
941 case 22:
942 strcpy(addinfo, " IDP");
943 break;
944 }
945 printk(KERN_INFO
946 "OPEN: %d.%d.%d.%d -> %d.%d.%d.%d%s\n",
947
948 p[12], p[13], p[14], p[15],
949 p[16], p[17], p[18], p[19],
950 addinfo);
951 break;
952 case ETH_P_ARP:
953 printk(KERN_INFO
954 "OPEN: ARP %d.%d.%d.%d -> *.*.*.* ?%d.%d.%d.%d\n",
955 p[14], p[15], p[16], p[17],
956 p[24], p[25], p[26], p[27]);
957 break;
958 }
959}
960
961/*
962 * this function is used to send supervisory data, i.e. data which was
963 * not received from the network layer, but e.g. frames from ipppd, CCP
964 * reset frames etc.
965 */
966void isdn_net_write_super(isdn_net_local *lp, struct sk_buff *skb)
967{
968 if (in_irq()) {
969 // we can't grab the lock from irq context,
970 // so we just queue the packet
971 skb_queue_tail(&lp->super_tx_queue, skb);
972 schedule_work(&lp->tqueue);
973 return;
974 }
975
976 spin_lock_bh(&lp->xmit_lock);
977 if (!isdn_net_lp_busy(lp)) {
978 isdn_net_writebuf_skb(lp, skb);
979 } else {
980 skb_queue_tail(&lp->super_tx_queue, skb);
981 }
982 spin_unlock_bh(&lp->xmit_lock);
983}
984
985/*
986 * called from tq_immediate
987 */
988static void isdn_net_softint(void *private)
989{
990 isdn_net_local *lp = private;
991 struct sk_buff *skb;
992
993 spin_lock_bh(&lp->xmit_lock);
994 while (!isdn_net_lp_busy(lp)) {
995 skb = skb_dequeue(&lp->super_tx_queue);
996 if (!skb)
997 break;
998 isdn_net_writebuf_skb(lp, skb);
999 }
1000 spin_unlock_bh(&lp->xmit_lock);
1001}
1002
1003/*
1004 * all frames sent from the (net) LL to a HL driver should go via this function
1005 * it's serialized by the caller holding the lp->xmit_lock spinlock
1006 */
1007void isdn_net_writebuf_skb(isdn_net_local *lp, struct sk_buff *skb)
1008{
1009 int ret;
1010 int len = skb->len; /* save len */
1011
1012 /* before obtaining the lock the caller should have checked that
1013 the lp isn't busy */
1014 if (isdn_net_lp_busy(lp)) {
1015 printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__);
1016 goto error;
1017 }
1018
1019 if (!(lp->flags & ISDN_NET_CONNECTED)) {
1020 printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__);
1021 goto error;
1022 }
1023 ret = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, 1, skb);
1024 if (ret != len) {
1025 /* we should never get here */
1026 printk(KERN_WARNING "%s: HL driver queue full\n", lp->name);
1027 goto error;
1028 }
1029
1030 lp->transcount += len;
1031 isdn_net_inc_frame_cnt(lp);
1032 return;
1033
1034 error:
1035 dev_kfree_skb(skb);
1036 lp->stats.tx_errors++;
1037
1038}
1039
1040
1041/*
1042 * Helper function for isdn_net_start_xmit.
1043 * When called, the connection is already established.
1044 * Based on cps-calculation, check if device is overloaded.
1045 * If so, and if a slave exists, trigger dialing for it.
1046 * If any slave is online, deliver packets using a simple round robin
1047 * scheme.
1048 *
1049 * Return: 0 on success, !0 on failure.
1050 */
1051
1052static int
1053isdn_net_xmit(struct net_device *ndev, struct sk_buff *skb)
1054{
1055 isdn_net_dev *nd;
1056 isdn_net_local *slp;
1057 isdn_net_local *lp = (isdn_net_local *) ndev->priv;
1058 int retv = 0;
1059
1060 if (((isdn_net_local *) (ndev->priv))->master) {
1061 printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__);
1062 dev_kfree_skb(skb);
1063 return 0;
1064 }
1065
1066 /* For the other encaps the header has already been built */
1067#ifdef CONFIG_ISDN_PPP
1068 if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) {
1069 return isdn_ppp_xmit(skb, ndev);
1070 }
1071#endif
1072 nd = ((isdn_net_local *) ndev->priv)->netdev;
1073 lp = isdn_net_get_locked_lp(nd);
1074 if (!lp) {
1075 printk(KERN_WARNING "%s: all channels busy - requeuing!\n", ndev->name);
1076 return 1;
1077 }
1078 /* we have our lp locked from now on */
1079
1080 /* Reset hangup-timeout */
1081 lp->huptimer = 0; // FIXME?
1082 isdn_net_writebuf_skb(lp, skb);
1083 spin_unlock_bh(&lp->xmit_lock);
1084
1085 /* the following stuff is here for backwards compatibility.
1086 * in future, start-up and hangup of slaves (based on current load)
1087 * should move to userspace and get based on an overall cps
1088 * calculation
1089 */
1090 if (lp->cps > lp->triggercps) {
1091 if (lp->slave) {
1092 if (!lp->sqfull) {
1093 /* First time overload: set timestamp only */
1094 lp->sqfull = 1;
1095 lp->sqfull_stamp = jiffies;
1096 } else {
1097 /* subsequent overload: if slavedelay exceeded, start dialing */
1098 if (time_after(jiffies, lp->sqfull_stamp + lp->slavedelay)) {
1099 slp = lp->slave->priv;
1100 if (!(slp->flags & ISDN_NET_CONNECTED)) {
1101 isdn_net_force_dial_lp((isdn_net_local *) lp->slave->priv);
1102 }
1103 }
1104 }
1105 }
1106 } else {
1107 if (lp->sqfull && time_after(jiffies, lp->sqfull_stamp + lp->slavedelay + (10 * HZ))) {
1108 lp->sqfull = 0;
1109 }
1110 /* this is a hack to allow auto-hangup for slaves on moderate loads */
1111 nd->queue = nd->local;
1112 }
1113
1114 return retv;
1115
1116}
1117
1118static void
1119isdn_net_adjust_hdr(struct sk_buff *skb, struct net_device *dev)
1120{
1121 isdn_net_local *lp = (isdn_net_local *) dev->priv;
1122 if (!skb)
1123 return;
1124 if (lp->p_encap == ISDN_NET_ENCAP_ETHER) {
1125 int pullsize = (ulong)skb->nh.raw - (ulong)skb->data - ETH_HLEN;
1126 if (pullsize > 0) {
1127 printk(KERN_DEBUG "isdn_net: Pull junk %d\n", pullsize);
1128 skb_pull(skb, pullsize);
1129 }
1130 }
1131}
1132
1133
1134void isdn_net_tx_timeout(struct net_device * ndev)
1135{
1136 isdn_net_local *lp = (isdn_net_local *) ndev->priv;
1137
1138 printk(KERN_WARNING "isdn_tx_timeout dev %s dialstate %d\n", ndev->name, lp->dialstate);
1139 if (!lp->dialstate){
1140 lp->stats.tx_errors++;
1141 /*
1142 * There is a certain probability that this currently
1143 * works at all because if we always wake up the interface,
1144 * then upper layer will try to send the next packet
1145 * immediately. And then, the old clean_up logic in the
1146 * driver will hopefully continue to work as it used to do.
1147 *
1148 * This is rather primitive right know, we better should
1149 * clean internal queues here, in particular for multilink and
1150 * ppp, and reset HL driver's channel, too. --HE
1151 *
1152 * actually, this may not matter at all, because ISDN hardware
1153 * should not see transmitter hangs at all IMO
1154 * changed KERN_DEBUG to KERN_WARNING to find out if this is
1155 * ever called --KG
1156 */
1157 }
1158 ndev->trans_start = jiffies;
1159 netif_wake_queue(ndev);
1160}
1161
1162/*
1163 * Try sending a packet.
1164 * If this interface isn't connected to a ISDN-Channel, find a free channel,
1165 * and start dialing.
1166 */
1167static int
1168isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
1169{
1170 isdn_net_local *lp = (isdn_net_local *) ndev->priv;
1171#ifdef CONFIG_ISDN_X25
1172 struct concap_proto * cprot = lp -> netdev -> cprot;
1173/* At this point hard_start_xmit() passes control to the encapsulation
1174 protocol (if present).
1175 For X.25 auto-dialing is completly bypassed because:
1176 - It does not conform with the semantics of a reliable datalink
1177 service as needed by X.25 PLP.
1178 - I don't want that the interface starts dialing when the network layer
1179 sends a message which requests to disconnect the lapb link (or if it
1180 sends any other message not resulting in data transmission).
1181 Instead, dialing will be initiated by the encapsulation protocol entity
1182 when a dl_establish request is received from the upper layer.
1183*/
1184 if (cprot && cprot -> pops) {
1185 int ret = cprot -> pops -> encap_and_xmit ( cprot , skb);
1186
1187 if (ret)
1188 netif_stop_queue(ndev);
1189 return ret;
1190 } else
1191#endif
1192 /* auto-dialing xmit function */
1193 {
1194#ifdef ISDN_DEBUG_NET_DUMP
1195 u_char *buf;
1196#endif
1197 isdn_net_adjust_hdr(skb, ndev);
1198#ifdef ISDN_DEBUG_NET_DUMP
1199 buf = skb->data;
1200 isdn_dumppkt("S:", buf, skb->len, 40);
1201#endif
1202
1203 if (!(lp->flags & ISDN_NET_CONNECTED)) {
1204 int chi;
1205 /* only do autodial if allowed by config */
1206 if (!(ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_AUTO)) {
1207 isdn_net_unreachable(ndev, skb, "dial rejected: interface not in dialmode `auto'");
1208 dev_kfree_skb(skb);
1209 return 0;
1210 }
1211 if (lp->phone[1]) {
1212 ulong flags;
1213
1214 if(lp->dialwait_timer <= 0)
1215 if(lp->dialstarted > 0 && lp->dialtimeout > 0 && time_before(jiffies, lp->dialstarted + lp->dialtimeout + lp->dialwait))
1216 lp->dialwait_timer = lp->dialstarted + lp->dialtimeout + lp->dialwait;
1217
1218 if(lp->dialwait_timer > 0) {
1219 if(time_before(jiffies, lp->dialwait_timer)) {
1220 isdn_net_unreachable(ndev, skb, "dial rejected: retry-time not reached");
1221 dev_kfree_skb(skb);
1222 return 0;
1223 } else
1224 lp->dialwait_timer = 0;
1225 }
1226 /* Grab a free ISDN-Channel */
1227 spin_lock_irqsave(&dev->lock, flags);
1228 if (((chi =
1229 isdn_get_free_channel(
1230 ISDN_USAGE_NET,
1231 lp->l2_proto,
1232 lp->l3_proto,
1233 lp->pre_device,
1234 lp->pre_channel,
1235 lp->msn)
1236 ) < 0) &&
1237 ((chi =
1238 isdn_get_free_channel(
1239 ISDN_USAGE_NET,
1240 lp->l2_proto,
1241 lp->l3_proto,
1242 lp->pre_device,
1243 lp->pre_channel^1,
1244 lp->msn)
1245 ) < 0)) {
1246 spin_unlock_irqrestore(&dev->lock, flags);
1247 isdn_net_unreachable(ndev, skb,
1248 "No channel");
1249 dev_kfree_skb(skb);
1250 return 0;
1251 }
1252 /* Log packet, which triggered dialing */
1253 if (dev->net_verbose)
1254 isdn_net_log_skb(skb, lp);
1255 lp->dialstate = 1;
1256 /* Connect interface with channel */
1257 isdn_net_bind_channel(lp, chi);
1258#ifdef CONFIG_ISDN_PPP
1259 if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) {
1260 /* no 'first_skb' handling for syncPPP */
1261 if (isdn_ppp_bind(lp) < 0) {
1262 dev_kfree_skb(skb);
1263 isdn_net_unbind_channel(lp);
1264 spin_unlock_irqrestore(&dev->lock, flags);
1265 return 0; /* STN (skb to nirvana) ;) */
1266 }
1267#ifdef CONFIG_IPPP_FILTER
1268 if (isdn_ppp_autodial_filter(skb, lp)) {
1269 isdn_ppp_free(lp);
1270 isdn_net_unbind_channel(lp);
1271 spin_unlock_irqrestore(&dev->lock, flags);
1272 isdn_net_unreachable(ndev, skb, "dial rejected: packet filtered");
1273 dev_kfree_skb(skb);
1274 return 0;
1275 }
1276#endif
1277 spin_unlock_irqrestore(&dev->lock, flags);
1278 isdn_net_dial(); /* Initiate dialing */
1279 netif_stop_queue(ndev);
1280 return 1; /* let upper layer requeue skb packet */
1281 }
1282#endif
1283 /* Initiate dialing */
1284 spin_unlock_irqrestore(&dev->lock, flags);
1285 isdn_net_dial();
1286 isdn_net_device_stop_queue(lp);
1287 return 1;
1288 } else {
1289 isdn_net_unreachable(ndev, skb,
1290 "No phone number");
1291 dev_kfree_skb(skb);
1292 return 0;
1293 }
1294 } else {
1295 /* Device is connected to an ISDN channel */
1296 ndev->trans_start = jiffies;
1297 if (!lp->dialstate) {
1298 /* ISDN connection is established, try sending */
1299 int ret;
1300 ret = (isdn_net_xmit(ndev, skb));
1301 if(ret) netif_stop_queue(ndev);
1302 return ret;
1303 } else
1304 netif_stop_queue(ndev);
1305 }
1306 }
1307 return 1;
1308}
1309
1310/*
1311 * Shutdown a net-interface.
1312 */
1313static int
1314isdn_net_close(struct net_device *dev)
1315{
1316 struct net_device *p;
1317#ifdef CONFIG_ISDN_X25
1318 struct concap_proto * cprot =
1319 ( (isdn_net_local *) dev->priv ) -> netdev -> cprot;
1320 /* printk(KERN_DEBUG "isdn_net_close %s\n" , dev-> name ); */
1321#endif
1322
1323#ifdef CONFIG_ISDN_X25
1324 if( cprot && cprot -> pops ) cprot -> pops -> close( cprot );
1325#endif
1326 netif_stop_queue(dev);
1327 if ((p = (((isdn_net_local *) dev->priv)->slave))) {
1328 /* If this interface has slaves, stop them also */
1329 while (p) {
1330#ifdef CONFIG_ISDN_X25
1331 cprot = ( (isdn_net_local *) p->priv )
1332 -> netdev -> cprot;
1333 if( cprot && cprot -> pops )
1334 cprot -> pops -> close( cprot );
1335#endif
1336 isdn_net_hangup(p);
1337 p = (((isdn_net_local *) p->priv)->slave);
1338 }
1339 }
1340 isdn_net_hangup(dev);
1341 isdn_unlock_drivers();
1342 return 0;
1343}
1344
1345/*
1346 * Get statistics
1347 */
1348static struct net_device_stats *
1349isdn_net_get_stats(struct net_device *dev)
1350{
1351 isdn_net_local *lp = (isdn_net_local *) dev->priv;
1352 return &lp->stats;
1353}
1354
1355/* This is simply a copy from std. eth.c EXCEPT we pull ETH_HLEN
1356 * instead of dev->hard_header_len off. This is done because the
1357 * lowlevel-driver has already pulled off its stuff when we get
1358 * here and this routine only gets called with p_encap == ETHER.
1359 * Determine the packet's protocol ID. The rule here is that we
1360 * assume 802.3 if the type field is short enough to be a length.
1361 * This is normal practice and works for any 'now in use' protocol.
1362 */
1363
1364static unsigned short
1365isdn_net_type_trans(struct sk_buff *skb, struct net_device *dev)
1366{
1367 struct ethhdr *eth;
1368 unsigned char *rawp;
1369
1370 skb->mac.raw = skb->data;
1371 skb_pull(skb, ETH_HLEN);
1372 eth = eth_hdr(skb);
1373
1374 if (*eth->h_dest & 1) {
1375 if (memcmp(eth->h_dest, dev->broadcast, ETH_ALEN) == 0)
1376 skb->pkt_type = PACKET_BROADCAST;
1377 else
1378 skb->pkt_type = PACKET_MULTICAST;
1379 }
1380 /*
1381 * This ALLMULTI check should be redundant by 1.4
1382 * so don't forget to remove it.
1383 */
1384
1385 else if (dev->flags & (IFF_PROMISC /*| IFF_ALLMULTI*/)) {
1386 if (memcmp(eth->h_dest, dev->dev_addr, ETH_ALEN))
1387 skb->pkt_type = PACKET_OTHERHOST;
1388 }
1389 if (ntohs(eth->h_proto) >= 1536)
1390 return eth->h_proto;
1391
1392 rawp = skb->data;
1393
1394 /*
1395 * This is a magic hack to spot IPX packets. Older Novell breaks
1396 * the protocol design and runs IPX over 802.3 without an 802.2 LLC
1397 * layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This
1398 * won't work for fault tolerant netware but does for the rest.
1399 */
1400 if (*(unsigned short *) rawp == 0xFFFF)
1401 return htons(ETH_P_802_3);
1402 /*
1403 * Real 802.2 LLC
1404 */
1405 return htons(ETH_P_802_2);
1406}
1407
1408
1409/*
1410 * CISCO HDLC keepalive specific stuff
1411 */
1412static struct sk_buff*
1413isdn_net_ciscohdlck_alloc_skb(isdn_net_local *lp, int len)
1414{
1415 unsigned short hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen;
1416 struct sk_buff *skb;
1417
1418 skb = alloc_skb(hl + len, GFP_ATOMIC);
1419 if (skb)
1420 skb_reserve(skb, hl);
1421 else
1422 printk("isdn out of mem at %s:%d!\n", __FILE__, __LINE__);
1423 return skb;
1424}
1425
1426/* cisco hdlck device private ioctls */
1427int
1428isdn_ciscohdlck_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
1429{
1430 isdn_net_local *lp = (isdn_net_local *) dev->priv;
1431 unsigned long len = 0;
1432 unsigned long expires = 0;
1433 int tmp = 0;
1434 int period = lp->cisco_keepalive_period;
1435 s8 debserint = lp->cisco_debserint;
1436 int rc = 0;
1437
1438 if (lp->p_encap != ISDN_NET_ENCAP_CISCOHDLCK)
1439 return -EINVAL;
1440
1441 switch (cmd) {
1442 /* get/set keepalive period */
1443 case SIOCGKEEPPERIOD:
1444 len = (unsigned long)sizeof(lp->cisco_keepalive_period);
1445 if (copy_to_user(ifr->ifr_data,
1446 &lp->cisco_keepalive_period, len))
1447 rc = -EFAULT;
1448 break;
1449 case SIOCSKEEPPERIOD:
1450 tmp = lp->cisco_keepalive_period;
1451 len = (unsigned long)sizeof(lp->cisco_keepalive_period);
1452 if (copy_from_user(&period, ifr->ifr_data, len))
1453 rc = -EFAULT;
1454 if ((period > 0) && (period <= 32767))
1455 lp->cisco_keepalive_period = period;
1456 else
1457 rc = -EINVAL;
1458 if (!rc && (tmp != lp->cisco_keepalive_period)) {
1459 expires = (unsigned long)(jiffies +
1460 lp->cisco_keepalive_period * HZ);
1461 mod_timer(&lp->cisco_timer, expires);
1462 printk(KERN_INFO "%s: Keepalive period set "
1463 "to %d seconds.\n",
1464 lp->name, lp->cisco_keepalive_period);
1465 }
1466 break;
1467
1468 /* get/set debugging */
1469 case SIOCGDEBSERINT:
1470 len = (unsigned long)sizeof(lp->cisco_debserint);
1471 if (copy_to_user(ifr->ifr_data,
1472 &lp->cisco_debserint, len))
1473 rc = -EFAULT;
1474 break;
1475 case SIOCSDEBSERINT:
1476 len = (unsigned long)sizeof(lp->cisco_debserint);
1477 if (copy_from_user(&debserint,
1478 ifr->ifr_data, len))
1479 rc = -EFAULT;
1480 if ((debserint >= 0) && (debserint <= 64))
1481 lp->cisco_debserint = debserint;
1482 else
1483 rc = -EINVAL;
1484 break;
1485
1486 default:
1487 rc = -EINVAL;
1488 break;
1489 }
1490 return (rc);
1491}
1492
1493/* called via cisco_timer.function */
1494static void
1495isdn_net_ciscohdlck_slarp_send_keepalive(unsigned long data)
1496{
1497 isdn_net_local *lp = (isdn_net_local *) data;
1498 struct sk_buff *skb;
1499 unsigned char *p;
1500 unsigned long last_cisco_myseq = lp->cisco_myseq;
1501 int myseq_diff = 0;
1502
1503 if (!(lp->flags & ISDN_NET_CONNECTED) || lp->dialstate) {
1504 printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__);
1505 return;
1506 }
1507 lp->cisco_myseq++;
1508
1509 myseq_diff = (lp->cisco_myseq - lp->cisco_mineseen);
1510 if ((lp->cisco_line_state) && ((myseq_diff >= 3)||(myseq_diff <= -3))) {
1511 /* line up -> down */
1512 lp->cisco_line_state = 0;
1513 printk (KERN_WARNING
1514 "UPDOWN: Line protocol on Interface %s,"
1515 " changed state to down\n", lp->name);
1516 /* should stop routing higher-level data accross */
1517 } else if ((!lp->cisco_line_state) &&
1518 (myseq_diff >= 0) && (myseq_diff <= 2)) {
1519 /* line down -> up */
1520 lp->cisco_line_state = 1;
1521 printk (KERN_WARNING
1522 "UPDOWN: Line protocol on Interface %s,"
1523 " changed state to up\n", lp->name);
1524 /* restart routing higher-level data accross */
1525 }
1526
1527 if (lp->cisco_debserint)
1528 printk (KERN_DEBUG "%s: HDLC "
1529 "myseq %lu, mineseen %lu%c, yourseen %lu, %s\n",
1530 lp->name, last_cisco_myseq, lp->cisco_mineseen,
1531 ((last_cisco_myseq == lp->cisco_mineseen) ? '*' : 040),
1532 lp->cisco_yourseq,
1533 ((lp->cisco_line_state) ? "line up" : "line down"));
1534
1535 skb = isdn_net_ciscohdlck_alloc_skb(lp, 4 + 14);
1536 if (!skb)
1537 return;
1538
1539 p = skb_put(skb, 4 + 14);
1540
1541 /* cisco header */
1542 p += put_u8 (p, CISCO_ADDR_UNICAST);
1543 p += put_u8 (p, CISCO_CTRL);
1544 p += put_u16(p, CISCO_TYPE_SLARP);
1545
1546 /* slarp keepalive */
1547 p += put_u32(p, CISCO_SLARP_KEEPALIVE);
1548 p += put_u32(p, lp->cisco_myseq);
1549 p += put_u32(p, lp->cisco_yourseq);
1550 p += put_u16(p, 0xffff); // reliablity, always 0xffff
1551
1552 isdn_net_write_super(lp, skb);
1553
1554 lp->cisco_timer.expires = jiffies + lp->cisco_keepalive_period * HZ;
1555
1556 add_timer(&lp->cisco_timer);
1557}
1558
1559static void
1560isdn_net_ciscohdlck_slarp_send_request(isdn_net_local *lp)
1561{
1562 struct sk_buff *skb;
1563 unsigned char *p;
1564
1565 skb = isdn_net_ciscohdlck_alloc_skb(lp, 4 + 14);
1566 if (!skb)
1567 return;
1568
1569 p = skb_put(skb, 4 + 14);
1570
1571 /* cisco header */
1572 p += put_u8 (p, CISCO_ADDR_UNICAST);
1573 p += put_u8 (p, CISCO_CTRL);
1574 p += put_u16(p, CISCO_TYPE_SLARP);
1575
1576 /* slarp request */
1577 p += put_u32(p, CISCO_SLARP_REQUEST);
1578 p += put_u32(p, 0); // address
1579 p += put_u32(p, 0); // netmask
1580 p += put_u16(p, 0); // unused
1581
1582 isdn_net_write_super(lp, skb);
1583}
1584
1585static void
1586isdn_net_ciscohdlck_connected(isdn_net_local *lp)
1587{
1588 lp->cisco_myseq = 0;
1589 lp->cisco_mineseen = 0;
1590 lp->cisco_yourseq = 0;
1591 lp->cisco_keepalive_period = ISDN_TIMER_KEEPINT;
1592 lp->cisco_last_slarp_in = 0;
1593 lp->cisco_line_state = 0;
1594 lp->cisco_debserint = 0;
1595
1596 /* send slarp request because interface/seq.no.s reset */
1597 isdn_net_ciscohdlck_slarp_send_request(lp);
1598
1599 init_timer(&lp->cisco_timer);
1600 lp->cisco_timer.data = (unsigned long) lp;
1601 lp->cisco_timer.function = isdn_net_ciscohdlck_slarp_send_keepalive;
1602 lp->cisco_timer.expires = jiffies + lp->cisco_keepalive_period * HZ;
1603 add_timer(&lp->cisco_timer);
1604}
1605
1606static void
1607isdn_net_ciscohdlck_disconnected(isdn_net_local *lp)
1608{
1609 del_timer(&lp->cisco_timer);
1610}
1611
1612static void
1613isdn_net_ciscohdlck_slarp_send_reply(isdn_net_local *lp)
1614{
1615 struct sk_buff *skb;
1616 unsigned char *p;
1617 struct in_device *in_dev = NULL;
1618 u32 addr = 0; /* local ipv4 address */
1619 u32 mask = 0; /* local netmask */
1620
1621 if ((in_dev = lp->netdev->dev.ip_ptr) != NULL) {
1622 /* take primary(first) address of interface */
1623 struct in_ifaddr *ifa = in_dev->ifa_list;
1624 if (ifa != NULL) {
1625 addr = ifa->ifa_local;
1626 mask = ifa->ifa_mask;
1627 }
1628 }
1629
1630 skb = isdn_net_ciscohdlck_alloc_skb(lp, 4 + 14);
1631 if (!skb)
1632 return;
1633
1634 p = skb_put(skb, 4 + 14);
1635
1636 /* cisco header */
1637 p += put_u8 (p, CISCO_ADDR_UNICAST);
1638 p += put_u8 (p, CISCO_CTRL);
1639 p += put_u16(p, CISCO_TYPE_SLARP);
1640
1641 /* slarp reply, send own ip/netmask; if values are nonsense remote
1642 * should think we are unable to provide it with an address via SLARP */
1643 p += put_u32(p, CISCO_SLARP_REPLY);
1644 p += put_u32(p, addr); // address
1645 p += put_u32(p, mask); // netmask
1646 p += put_u16(p, 0); // unused
1647
1648 isdn_net_write_super(lp, skb);
1649}
1650
1651static void
1652isdn_net_ciscohdlck_slarp_in(isdn_net_local *lp, struct sk_buff *skb)
1653{
1654 unsigned char *p;
1655 int period;
1656 u32 code;
1657 u32 my_seq, addr;
1658 u32 your_seq, mask;
1659 u32 local;
1660 u16 unused;
1661
1662 if (skb->len < 14)
1663 return;
1664
1665 p = skb->data;
1666 p += get_u32(p, &code);
1667
1668 switch (code) {
1669 case CISCO_SLARP_REQUEST:
1670 lp->cisco_yourseq = 0;
1671 isdn_net_ciscohdlck_slarp_send_reply(lp);
1672 break;
1673 case CISCO_SLARP_REPLY:
1674 addr = ntohl(*(u32 *)p);
1675 mask = ntohl(*(u32 *)(p+4));
1676 if (mask != 0xfffffffc)
1677 goto slarp_reply_out;
1678 if ((addr & 3) == 0 || (addr & 3) == 3)
1679 goto slarp_reply_out;
1680 local = addr ^ 3;
1681 printk(KERN_INFO "%s: got slarp reply: "
1682 "remote ip: %d.%d.%d.%d, "
1683 "local ip: %d.%d.%d.%d "
1684 "mask: %d.%d.%d.%d\n",
1685 lp->name,
1686 HIPQUAD(addr),
1687 HIPQUAD(local),
1688 HIPQUAD(mask));
1689 break;
1690 slarp_reply_out:
1691 printk(KERN_INFO "%s: got invalid slarp "
1692 "reply (%d.%d.%d.%d/%d.%d.%d.%d) "
1693 "- ignored\n", lp->name,
1694 HIPQUAD(addr), HIPQUAD(mask));
1695 break;
1696 case CISCO_SLARP_KEEPALIVE:
1697 period = (int)((jiffies - lp->cisco_last_slarp_in
1698 + HZ/2 - 1) / HZ);
1699 if (lp->cisco_debserint &&
1700 (period != lp->cisco_keepalive_period) &&
1701 lp->cisco_last_slarp_in) {
1702 printk(KERN_DEBUG "%s: Keepalive period mismatch - "
1703 "is %d but should be %d.\n",
1704 lp->name, period, lp->cisco_keepalive_period);
1705 }
1706 lp->cisco_last_slarp_in = jiffies;
1707 p += get_u32(p, &my_seq);
1708 p += get_u32(p, &your_seq);
1709 p += get_u16(p, &unused);
1710 lp->cisco_yourseq = my_seq;
1711 lp->cisco_mineseen = your_seq;
1712 break;
1713 }
1714}
1715
1716static void
1717isdn_net_ciscohdlck_receive(isdn_net_local *lp, struct sk_buff *skb)
1718{
1719 unsigned char *p;
1720 u8 addr;
1721 u8 ctrl;
1722 u16 type;
1723
1724 if (skb->len < 4)
1725 goto out_free;
1726
1727 p = skb->data;
1728 p += get_u8 (p, &addr);
1729 p += get_u8 (p, &ctrl);
1730 p += get_u16(p, &type);
1731 skb_pull(skb, 4);
1732
1733 if (addr != CISCO_ADDR_UNICAST && addr != CISCO_ADDR_BROADCAST) {
1734 printk(KERN_WARNING "%s: Unknown Cisco addr 0x%02x\n",
1735 lp->name, addr);
1736 goto out_free;
1737 }
1738 if (ctrl != CISCO_CTRL) {
1739 printk(KERN_WARNING "%s: Unknown Cisco ctrl 0x%02x\n",
1740 lp->name, ctrl);
1741 goto out_free;
1742 }
1743
1744 switch (type) {
1745 case CISCO_TYPE_SLARP:
1746 isdn_net_ciscohdlck_slarp_in(lp, skb);
1747 goto out_free;
1748 case CISCO_TYPE_CDP:
1749 if (lp->cisco_debserint)
1750 printk(KERN_DEBUG "%s: Received CDP packet. use "
1751 "\"no cdp enable\" on cisco.\n", lp->name);
1752 goto out_free;
1753 default:
1754 /* no special cisco protocol */
1755 skb->protocol = htons(type);
1756 netif_rx(skb);
1757 return;
1758 }
1759
1760 out_free:
1761 kfree_skb(skb);
1762}
1763
1764/*
1765 * Got a packet from ISDN-Channel.
1766 */
1767static void
1768isdn_net_receive(struct net_device *ndev, struct sk_buff *skb)
1769{
1770 isdn_net_local *lp = (isdn_net_local *) ndev->priv;
1771 isdn_net_local *olp = lp; /* original 'lp' */
1772#ifdef CONFIG_ISDN_X25
1773 struct concap_proto *cprot = lp -> netdev -> cprot;
1774#endif
1775 lp->transcount += skb->len;
1776
1777 lp->stats.rx_packets++;
1778 lp->stats.rx_bytes += skb->len;
1779 if (lp->master) {
1780 /* Bundling: If device is a slave-device, deliver to master, also
1781 * handle master's statistics and hangup-timeout
1782 */
1783 ndev = lp->master;
1784 lp = (isdn_net_local *) ndev->priv;
1785 lp->stats.rx_packets++;
1786 lp->stats.rx_bytes += skb->len;
1787 }
1788 skb->dev = ndev;
1789 skb->input_dev = ndev;
1790 skb->pkt_type = PACKET_HOST;
1791 skb->mac.raw = skb->data;
1792#ifdef ISDN_DEBUG_NET_DUMP
1793 isdn_dumppkt("R:", skb->data, skb->len, 40);
1794#endif
1795 switch (lp->p_encap) {
1796 case ISDN_NET_ENCAP_ETHER:
1797 /* Ethernet over ISDN */
1798 olp->huptimer = 0;
1799 lp->huptimer = 0;
1800 skb->protocol = isdn_net_type_trans(skb, ndev);
1801 break;
1802 case ISDN_NET_ENCAP_UIHDLC:
1803 /* HDLC with UI-frame (for ispa with -h1 option) */
1804 olp->huptimer = 0;
1805 lp->huptimer = 0;
1806 skb_pull(skb, 2);
1807 /* Fall through */
1808 case ISDN_NET_ENCAP_RAWIP:
1809 /* RAW-IP without MAC-Header */
1810 olp->huptimer = 0;
1811 lp->huptimer = 0;
1812 skb->protocol = htons(ETH_P_IP);
1813 break;
1814 case ISDN_NET_ENCAP_CISCOHDLCK:
1815 isdn_net_ciscohdlck_receive(lp, skb);
1816 return;
1817 case ISDN_NET_ENCAP_CISCOHDLC:
1818 /* CISCO-HDLC IP with type field and fake I-frame-header */
1819 skb_pull(skb, 2);
1820 /* Fall through */
1821 case ISDN_NET_ENCAP_IPTYP:
1822 /* IP with type field */
1823 olp->huptimer = 0;
1824 lp->huptimer = 0;
1825 skb->protocol = *(unsigned short *) &(skb->data[0]);
1826 skb_pull(skb, 2);
1827 if (*(unsigned short *) skb->data == 0xFFFF)
1828 skb->protocol = htons(ETH_P_802_3);
1829 break;
1830#ifdef CONFIG_ISDN_PPP
1831 case ISDN_NET_ENCAP_SYNCPPP:
1832 /* huptimer is done in isdn_ppp_push_higher */
1833 isdn_ppp_receive(lp->netdev, olp, skb);
1834 return;
1835#endif
1836
1837 default:
1838#ifdef CONFIG_ISDN_X25
1839 /* try if there are generic sync_device receiver routines */
1840 if(cprot) if(cprot -> pops)
1841 if( cprot -> pops -> data_ind){
1842 cprot -> pops -> data_ind(cprot,skb);
1843 return;
1844 };
1845#endif /* CONFIG_ISDN_X25 */
1846 printk(KERN_WARNING "%s: unknown encapsulation, dropping\n",
1847 lp->name);
1848 kfree_skb(skb);
1849 return;
1850 }
1851
1852 netif_rx(skb);
1853 return;
1854}
1855
1856/*
1857 * A packet arrived via ISDN. Search interface-chain for a corresponding
1858 * interface. If found, deliver packet to receiver-function and return 1,
1859 * else return 0.
1860 */
1861int
1862isdn_net_rcv_skb(int idx, struct sk_buff *skb)
1863{
1864 isdn_net_dev *p = dev->rx_netdev[idx];
1865
1866 if (p) {
1867 isdn_net_local *lp = p->local;
1868 if ((lp->flags & ISDN_NET_CONNECTED) &&
1869 (!lp->dialstate)) {
1870 isdn_net_receive(&p->dev, skb);
1871 return 1;
1872 }
1873 }
1874 return 0;
1875}
1876
1877static int
1878my_eth_header(struct sk_buff *skb, struct net_device *dev, unsigned short type,
1879 void *daddr, void *saddr, unsigned len)
1880{
1881 struct ethhdr *eth = (struct ethhdr *) skb_push(skb, ETH_HLEN);
1882
1883 /*
1884 * Set the protocol type. For a packet of type ETH_P_802_3 we
1885 * put the length here instead. It is up to the 802.2 layer to
1886 * carry protocol information.
1887 */
1888
1889 if (type != ETH_P_802_3)
1890 eth->h_proto = htons(type);
1891 else
1892 eth->h_proto = htons(len);
1893
1894 /*
1895 * Set the source hardware address.
1896 */
1897 if (saddr)
1898 memcpy(eth->h_source, saddr, dev->addr_len);
1899 else
1900 memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
1901
1902 /*
1903 * Anyway, the loopback-device should never use this function...
1904 */
1905
1906 if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) {
1907 memset(eth->h_dest, 0, dev->addr_len);
1908 return ETH_HLEN /*(dev->hard_header_len)*/;
1909 }
1910 if (daddr) {
1911 memcpy(eth->h_dest, daddr, dev->addr_len);
1912 return ETH_HLEN /*dev->hard_header_len*/;
1913 }
1914 return -ETH_HLEN /*dev->hard_header_len*/;
1915}
1916
1917/*
1918 * build an header
1919 * depends on encaps that is being used.
1920 */
1921
1922static int
1923isdn_net_header(struct sk_buff *skb, struct net_device *dev, unsigned short type,
1924 void *daddr, void *saddr, unsigned plen)
1925{
1926 isdn_net_local *lp = dev->priv;
1927 unsigned char *p;
1928 ushort len = 0;
1929
1930 switch (lp->p_encap) {
1931 case ISDN_NET_ENCAP_ETHER:
1932 len = my_eth_header(skb, dev, type, daddr, saddr, plen);
1933 break;
1934#ifdef CONFIG_ISDN_PPP
1935 case ISDN_NET_ENCAP_SYNCPPP:
1936 /* stick on a fake header to keep fragmentation code happy. */
1937 len = IPPP_MAX_HEADER;
1938 skb_push(skb,len);
1939 break;
1940#endif
1941 case ISDN_NET_ENCAP_RAWIP:
1942 printk(KERN_WARNING "isdn_net_header called with RAW_IP!\n");
1943 len = 0;
1944 break;
1945 case ISDN_NET_ENCAP_IPTYP:
1946 /* ethernet type field */
1947 *((ushort *) skb_push(skb, 2)) = htons(type);
1948 len = 2;
1949 break;
1950 case ISDN_NET_ENCAP_UIHDLC:
1951 /* HDLC with UI-Frames (for ispa with -h1 option) */
1952 *((ushort *) skb_push(skb, 2)) = htons(0x0103);
1953 len = 2;
1954 break;
1955 case ISDN_NET_ENCAP_CISCOHDLC:
1956 case ISDN_NET_ENCAP_CISCOHDLCK:
1957 p = skb_push(skb, 4);
1958 p += put_u8 (p, CISCO_ADDR_UNICAST);
1959 p += put_u8 (p, CISCO_CTRL);
1960 p += put_u16(p, type);
1961 len = 4;
1962 break;
1963#ifdef CONFIG_ISDN_X25
1964 default:
1965 /* try if there are generic concap protocol routines */
1966 if( lp-> netdev -> cprot ){
1967 printk(KERN_WARNING "isdn_net_header called with concap_proto!\n");
1968 len = 0;
1969 break;
1970 }
1971 break;
1972#endif /* CONFIG_ISDN_X25 */
1973 }
1974 return len;
1975}
1976
1977/* We don't need to send arp, because we have point-to-point connections. */
1978static int
1979isdn_net_rebuild_header(struct sk_buff *skb)
1980{
1981 struct net_device *dev = skb->dev;
1982 isdn_net_local *lp = dev->priv;
1983 int ret = 0;
1984
1985 if (lp->p_encap == ISDN_NET_ENCAP_ETHER) {
1986 struct ethhdr *eth = (struct ethhdr *) skb->data;
1987
1988 /*
1989 * Only ARP/IP is currently supported
1990 */
1991
1992 if (eth->h_proto != htons(ETH_P_IP)) {
1993 printk(KERN_WARNING
1994 "isdn_net: %s don't know how to resolve type %d addresses?\n",
1995 dev->name, (int) eth->h_proto);
1996 memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
1997 return 0;
1998 }
1999 /*
2000 * Try to get ARP to resolve the header.
2001 */
2002#ifdef CONFIG_INET
2003 ret = arp_find(eth->h_dest, skb);
2004#endif
2005 }
2006 return ret;
2007}
2008
2009/*
2010 * Interface-setup. (just after registering a new interface)
2011 */
2012static int
2013isdn_net_init(struct net_device *ndev)
2014{
2015 ushort max_hlhdr_len = 0;
2016 isdn_net_local *lp = (isdn_net_local *) ndev->priv;
2017 int drvidx, i;
2018
2019 ether_setup(ndev);
2020 lp->org_hhc = ndev->hard_header_cache;
2021 lp->org_hcu = ndev->header_cache_update;
2022
2023 /* Setup the generic properties */
2024
2025 ndev->hard_header = NULL;
2026 ndev->hard_header_cache = NULL;
2027 ndev->header_cache_update = NULL;
2028 ndev->mtu = 1500;
2029 ndev->flags = IFF_NOARP|IFF_POINTOPOINT;
2030 ndev->type = ARPHRD_ETHER;
2031 ndev->addr_len = ETH_ALEN;
2032
2033 /* for clients with MPPP maybe higher values better */
2034 ndev->tx_queue_len = 30;
2035
2036 for (i = 0; i < ETH_ALEN; i++)
2037 ndev->broadcast[i] = 0xff;
2038
2039 /* The ISDN-specific entries in the device structure. */
2040 ndev->open = &isdn_net_open;
2041 ndev->hard_start_xmit = &isdn_net_start_xmit;
2042
2043 /*
2044 * up till binding we ask the protocol layer to reserve as much
2045 * as we might need for HL layer
2046 */
2047
2048 for (drvidx = 0; drvidx < ISDN_MAX_DRIVERS; drvidx++)
2049 if (dev->drv[drvidx])
2050 if (max_hlhdr_len < dev->drv[drvidx]->interface->hl_hdrlen)
2051 max_hlhdr_len = dev->drv[drvidx]->interface->hl_hdrlen;
2052
2053 ndev->hard_header_len = ETH_HLEN + max_hlhdr_len;
2054 ndev->stop = &isdn_net_close;
2055 ndev->get_stats = &isdn_net_get_stats;
2056 ndev->rebuild_header = &isdn_net_rebuild_header;
2057 ndev->do_ioctl = NULL;
2058 return 0;
2059}
2060
2061static void
2062isdn_net_swapbind(int drvidx)
2063{
2064 isdn_net_dev *p;
2065
2066#ifdef ISDN_DEBUG_NET_ICALL
2067 printk(KERN_DEBUG "n_fi: swapping ch of %d\n", drvidx);
2068#endif
2069 p = dev->netdev;
2070 while (p) {
2071 if (p->local->pre_device == drvidx)
2072 switch (p->local->pre_channel) {
2073 case 0:
2074 p->local->pre_channel = 1;
2075 break;
2076 case 1:
2077 p->local->pre_channel = 0;
2078 break;
2079 }
2080 p = (isdn_net_dev *) p->next;
2081 }
2082}
2083
2084static void
2085isdn_net_swap_usage(int i1, int i2)
2086{
2087 int u1 = dev->usage[i1] & ISDN_USAGE_EXCLUSIVE;
2088 int u2 = dev->usage[i2] & ISDN_USAGE_EXCLUSIVE;
2089
2090#ifdef ISDN_DEBUG_NET_ICALL
2091 printk(KERN_DEBUG "n_fi: usage of %d and %d\n", i1, i2);
2092#endif
2093 dev->usage[i1] &= ~ISDN_USAGE_EXCLUSIVE;
2094 dev->usage[i1] |= u2;
2095 dev->usage[i2] &= ~ISDN_USAGE_EXCLUSIVE;
2096 dev->usage[i2] |= u1;
2097 isdn_info_update();
2098}
2099
2100/*
2101 * An incoming call-request has arrived.
2102 * Search the interface-chain for an appropriate interface.
2103 * If found, connect the interface to the ISDN-channel and initiate
2104 * D- and B-Channel-setup. If secure-flag is set, accept only
2105 * configured phone-numbers. If callback-flag is set, initiate
2106 * callback-dialing.
2107 *
2108 * Return-Value: 0 = No appropriate interface for this call.
2109 * 1 = Call accepted
2110 * 2 = Reject call, wait cbdelay, then call back
2111 * 3 = Reject call
2112 * 4 = Wait cbdelay, then call back
2113 * 5 = No appropriate interface for this call,
2114 * would eventually match if CID was longer.
2115 */
2116
2117int
2118isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup)
2119{
2120 char *eaz;
2121 int si1;
2122 int si2;
2123 int ematch;
2124 int wret;
2125 int swapped;
2126 int sidx = 0;
2127 u_long flags;
2128 isdn_net_dev *p;
2129 isdn_net_phone *n;
2130 char nr[32];
2131 char *my_eaz;
2132
2133 /* Search name in netdev-chain */
2134 if (!setup->phone[0]) {
2135 nr[0] = '0';
2136 nr[1] = '\0';
2137 printk(KERN_INFO "isdn_net: Incoming call without OAD, assuming '0'\n");
2138 } else
2139 strcpy(nr, setup->phone);
2140 si1 = (int) setup->si1;
2141 si2 = (int) setup->si2;
2142 if (!setup->eazmsn[0]) {
2143 printk(KERN_WARNING "isdn_net: Incoming call without CPN, assuming '0'\n");
2144 eaz = "0";
2145 } else
2146 eaz = setup->eazmsn;
2147 if (dev->net_verbose > 1)
2148 printk(KERN_INFO "isdn_net: call from %s,%d,%d -> %s\n", nr, si1, si2, eaz);
2149 /* Accept DATA and VOICE calls at this stage
2150 * local eaz is checked later for allowed call types
2151 */
2152 if ((si1 != 7) && (si1 != 1)) {
2153 if (dev->net_verbose > 1)
2154 printk(KERN_INFO "isdn_net: Service-Indicator not 1 or 7, ignored\n");
2155 return 0;
2156 }
2157 n = (isdn_net_phone *) 0;
2158 p = dev->netdev;
2159 ematch = wret = swapped = 0;
2160#ifdef ISDN_DEBUG_NET_ICALL
2161 printk(KERN_DEBUG "n_fi: di=%d ch=%d idx=%d usg=%d\n", di, ch, idx,
2162 dev->usage[idx]);
2163#endif
2164 while (p) {
2165 int matchret;
2166 isdn_net_local *lp = p->local;
2167
2168 /* If last check has triggered as binding-swap, revert it */
2169 switch (swapped) {
2170 case 2:
2171 isdn_net_swap_usage(idx, sidx);
2172 /* fall through */
2173 case 1:
2174 isdn_net_swapbind(di);
2175 break;
2176 }
2177 swapped = 0;
2178 /* check acceptable call types for DOV */
2179 my_eaz = isdn_map_eaz2msn(lp->msn, di);
2180 if (si1 == 1) { /* it's a DOV call, check if we allow it */
2181 if (*my_eaz == 'v' || *my_eaz == 'V' ||
2182 *my_eaz == 'b' || *my_eaz == 'B')
2183 my_eaz++; /* skip to allow a match */
2184 else
2185 my_eaz = NULL; /* force non match */
2186 } else { /* it's a DATA call, check if we allow it */
2187 if (*my_eaz == 'b' || *my_eaz == 'B')
2188 my_eaz++; /* skip to allow a match */
2189 }
2190 if (my_eaz)
2191 matchret = isdn_msncmp(eaz, my_eaz);
2192 else
2193 matchret = 1;
2194 if (!matchret)
2195 ematch = 1;
2196
2197 /* Remember if more numbers eventually can match */
2198 if (matchret > wret)
2199 wret = matchret;
2200#ifdef ISDN_DEBUG_NET_ICALL
2201 printk(KERN_DEBUG "n_fi: if='%s', l.msn=%s, l.flags=%d, l.dstate=%d\n",
2202 lp->name, lp->msn, lp->flags, lp->dialstate);
2203#endif
2204 if ((!matchret) && /* EAZ is matching */
2205 (((!(lp->flags & ISDN_NET_CONNECTED)) && /* but not connected */
2206 (USG_NONE(dev->usage[idx]))) || /* and ch. unused or */
2207 ((((lp->dialstate == 4) || (lp->dialstate == 12)) && /* if dialing */
2208 (!(lp->flags & ISDN_NET_CALLBACK))) /* but no callback */
2209 )))
2210 {
2211#ifdef ISDN_DEBUG_NET_ICALL
2212 printk(KERN_DEBUG "n_fi: match1, pdev=%d pch=%d\n",
2213 lp->pre_device, lp->pre_channel);
2214#endif
2215 if (dev->usage[idx] & ISDN_USAGE_EXCLUSIVE) {
2216 if ((lp->pre_channel != ch) ||
2217 (lp->pre_device != di)) {
2218 /* Here we got a problem:
2219 * If using an ICN-Card, an incoming call is always signaled on
2220 * on the first channel of the card, if both channels are
2221 * down. However this channel may be bound exclusive. If the
2222 * second channel is free, this call should be accepted.
2223 * The solution is horribly but it runs, so what:
2224 * We exchange the exclusive bindings of the two channels, the
2225 * corresponding variables in the interface-structs.
2226 */
2227 if (ch == 0) {
2228 sidx = isdn_dc2minor(di, 1);
2229#ifdef ISDN_DEBUG_NET_ICALL
2230 printk(KERN_DEBUG "n_fi: ch is 0\n");
2231#endif
2232 if (USG_NONE(dev->usage[sidx])) {
2233 /* Second Channel is free, now see if it is bound
2234 * exclusive too. */
2235 if (dev->usage[sidx] & ISDN_USAGE_EXCLUSIVE) {
2236#ifdef ISDN_DEBUG_NET_ICALL
2237 printk(KERN_DEBUG "n_fi: 2nd channel is down and bound\n");
2238#endif
2239 /* Yes, swap bindings only, if the original
2240 * binding is bound to channel 1 of this driver */
2241 if ((lp->pre_device == di) &&
2242 (lp->pre_channel == 1)) {
2243 isdn_net_swapbind(di);
2244 swapped = 1;
2245 } else {
2246 /* ... else iterate next device */
2247 p = (isdn_net_dev *) p->next;
2248 continue;
2249 }
2250 } else {
2251#ifdef ISDN_DEBUG_NET_ICALL
2252 printk(KERN_DEBUG "n_fi: 2nd channel is down and unbound\n");
2253#endif
2254 /* No, swap always and swap excl-usage also */
2255 isdn_net_swap_usage(idx, sidx);
2256 isdn_net_swapbind(di);
2257 swapped = 2;
2258 }
2259 /* Now check for exclusive binding again */
2260#ifdef ISDN_DEBUG_NET_ICALL
2261 printk(KERN_DEBUG "n_fi: final check\n");
2262#endif
2263 if ((dev->usage[idx] & ISDN_USAGE_EXCLUSIVE) &&
2264 ((lp->pre_channel != ch) ||
2265 (lp->pre_device != di))) {
2266#ifdef ISDN_DEBUG_NET_ICALL
2267 printk(KERN_DEBUG "n_fi: final check failed\n");
2268#endif
2269 p = (isdn_net_dev *) p->next;
2270 continue;
2271 }
2272 }
2273 } else {
2274 /* We are already on the second channel, so nothing to do */
2275#ifdef ISDN_DEBUG_NET_ICALL
2276 printk(KERN_DEBUG "n_fi: already on 2nd channel\n");
2277#endif
2278 }
2279 }
2280 }
2281#ifdef ISDN_DEBUG_NET_ICALL
2282 printk(KERN_DEBUG "n_fi: match2\n");
2283#endif
2284 n = lp->phone[0];
2285 if (lp->flags & ISDN_NET_SECURE) {
2286 while (n) {
2287 if (!isdn_msncmp(nr, n->num))
2288 break;
2289 n = (isdn_net_phone *) n->next;
2290 }
2291 }
2292 if (n || (!(lp->flags & ISDN_NET_SECURE))) {
2293#ifdef ISDN_DEBUG_NET_ICALL
2294 printk(KERN_DEBUG "n_fi: match3\n");
2295#endif
2296 /* matching interface found */
2297
2298 /*
2299 * Is the state STOPPED?
2300 * If so, no dialin is allowed,
2301 * so reject actively.
2302 * */
2303 if (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF) {
2304 printk(KERN_INFO "incoming call, interface %s `stopped' -> rejected\n",
2305 lp->name);
2306 return 3;
2307 }
2308 /*
2309 * Is the interface up?
2310 * If not, reject the call actively.
2311 */
2312 if (!isdn_net_device_started(p)) {
2313 printk(KERN_INFO "%s: incoming call, interface down -> rejected\n",
2314 lp->name);
2315 return 3;
2316 }
2317 /* Interface is up, now see if it's a slave. If so, see if
2318 * it's master and parent slave is online. If not, reject the call.
2319 */
2320 if (lp->master) {
2321 isdn_net_local *mlp = (isdn_net_local *) lp->master->priv;
2322 printk(KERN_DEBUG "ICALLslv: %s\n", lp->name);
2323 printk(KERN_DEBUG "master=%s\n", mlp->name);
2324 if (mlp->flags & ISDN_NET_CONNECTED) {
2325 printk(KERN_DEBUG "master online\n");
2326 /* Master is online, find parent-slave (master if first slave) */
2327 while (mlp->slave) {
2328 if ((isdn_net_local *) mlp->slave->priv == lp)
2329 break;
2330 mlp = (isdn_net_local *) mlp->slave->priv;
2331 }
2332 } else
2333 printk(KERN_DEBUG "master offline\n");
2334 /* Found parent, if it's offline iterate next device */
2335 printk(KERN_DEBUG "mlpf: %d\n", mlp->flags & ISDN_NET_CONNECTED);
2336 if (!(mlp->flags & ISDN_NET_CONNECTED)) {
2337 p = (isdn_net_dev *) p->next;
2338 continue;
2339 }
2340 }
2341 if (lp->flags & ISDN_NET_CALLBACK) {
2342 int chi;
2343 /*
2344 * Is the state MANUAL?
2345 * If so, no callback can be made,
2346 * so reject actively.
2347 * */
2348 if (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF) {
2349 printk(KERN_INFO "incoming call for callback, interface %s `off' -> rejected\n",
2350 lp->name);
2351 return 3;
2352 }
2353 printk(KERN_DEBUG "%s: call from %s -> %s, start callback\n",
2354 lp->name, nr, eaz);
2355 if (lp->phone[1]) {
2356 /* Grab a free ISDN-Channel */
2357 spin_lock_irqsave(&dev->lock, flags);
2358 if ((chi =
2359 isdn_get_free_channel(
2360 ISDN_USAGE_NET,
2361 lp->l2_proto,
2362 lp->l3_proto,
2363 lp->pre_device,
2364 lp->pre_channel,
2365 lp->msn)
2366 ) < 0) {
2367
2368 printk(KERN_WARNING "isdn_net_find_icall: No channel for %s\n", lp->name);
2369 spin_unlock_irqrestore(&dev->lock, flags);
2370 return 0;
2371 }
2372 /* Setup dialstate. */
2373 lp->dtimer = 0;
2374 lp->dialstate = 11;
2375 /* Connect interface with channel */
2376 isdn_net_bind_channel(lp, chi);
2377#ifdef CONFIG_ISDN_PPP
2378 if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
2379 if (isdn_ppp_bind(lp) < 0) {
2380 spin_unlock_irqrestore(&dev->lock, flags);
2381 isdn_net_unbind_channel(lp);
2382 return 0;
2383 }
2384#endif
2385 spin_unlock_irqrestore(&dev->lock, flags);
2386 /* Initiate dialing by returning 2 or 4 */
2387 return (lp->flags & ISDN_NET_CBHUP) ? 2 : 4;
2388 } else
2389 printk(KERN_WARNING "isdn_net: %s: No phone number\n", lp->name);
2390 return 0;
2391 } else {
2392 printk(KERN_DEBUG "%s: call from %s -> %s accepted\n", lp->name, nr,
2393 eaz);
2394 /* if this interface is dialing, it does it probably on a different
2395 device, so free this device */
2396 if ((lp->dialstate == 4) || (lp->dialstate == 12)) {
2397#ifdef CONFIG_ISDN_PPP
2398 if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
2399 isdn_ppp_free(lp);
2400#endif
2401 isdn_net_lp_disconnected(lp);
2402 isdn_free_channel(lp->isdn_device, lp->isdn_channel,
2403 ISDN_USAGE_NET);
2404 }
2405 spin_lock_irqsave(&dev->lock, flags);
2406 dev->usage[idx] &= ISDN_USAGE_EXCLUSIVE;
2407 dev->usage[idx] |= ISDN_USAGE_NET;
2408 strcpy(dev->num[idx], nr);
2409 isdn_info_update();
2410 dev->st_netdev[idx] = lp->netdev;
2411 lp->isdn_device = di;
2412 lp->isdn_channel = ch;
2413 lp->ppp_slot = -1;
2414 lp->flags |= ISDN_NET_CONNECTED;
2415 lp->dialstate = 7;
2416 lp->dtimer = 0;
2417 lp->outgoing = 0;
2418 lp->huptimer = 0;
2419 lp->hupflags |= ISDN_WAITCHARGE;
2420 lp->hupflags &= ~ISDN_HAVECHARGE;
2421#ifdef CONFIG_ISDN_PPP
2422 if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) {
2423 if (isdn_ppp_bind(lp) < 0) {
2424 isdn_net_unbind_channel(lp);
2425 spin_unlock_irqrestore(&dev->lock, flags);
2426 return 0;
2427 }
2428 }
2429#endif
2430 spin_unlock_irqrestore(&dev->lock, flags);
2431 return 1;
2432 }
2433 }
2434 }
2435 p = (isdn_net_dev *) p->next;
2436 }
2437 /* If none of configured EAZ/MSN matched and not verbose, be silent */
2438 if (!ematch || dev->net_verbose)
2439 printk(KERN_INFO "isdn_net: call from %s -> %d %s ignored\n", nr, di, eaz);
2440 return (wret == 2)?5:0;
2441}
2442
2443/*
2444 * Search list of net-interfaces for an interface with given name.
2445 */
2446isdn_net_dev *
2447isdn_net_findif(char *name)
2448{
2449 isdn_net_dev *p = dev->netdev;
2450
2451 while (p) {
2452 if (!strcmp(p->local->name, name))
2453 return p;
2454 p = (isdn_net_dev *) p->next;
2455 }
2456 return (isdn_net_dev *) NULL;
2457}
2458
2459/*
2460 * Force a net-interface to dial out.
2461 * This is called from the userlevel-routine below or
2462 * from isdn_net_start_xmit().
2463 */
2464int
2465isdn_net_force_dial_lp(isdn_net_local * lp)
2466{
2467 if ((!(lp->flags & ISDN_NET_CONNECTED)) && !lp->dialstate) {
2468 int chi;
2469 if (lp->phone[1]) {
2470 ulong flags;
2471
2472 /* Grab a free ISDN-Channel */
2473 spin_lock_irqsave(&dev->lock, flags);
2474 if ((chi = isdn_get_free_channel(
2475 ISDN_USAGE_NET,
2476 lp->l2_proto,
2477 lp->l3_proto,
2478 lp->pre_device,
2479 lp->pre_channel,
2480 lp->msn)) < 0) {
2481 printk(KERN_WARNING "isdn_net_force_dial: No channel for %s\n", lp->name);
2482 spin_unlock_irqrestore(&dev->lock, flags);
2483 return -EAGAIN;
2484 }
2485 lp->dialstate = 1;
2486 /* Connect interface with channel */
2487 isdn_net_bind_channel(lp, chi);
2488#ifdef CONFIG_ISDN_PPP
2489 if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
2490 if (isdn_ppp_bind(lp) < 0) {
2491 isdn_net_unbind_channel(lp);
2492 spin_unlock_irqrestore(&dev->lock, flags);
2493 return -EAGAIN;
2494 }
2495#endif
2496 /* Initiate dialing */
2497 spin_unlock_irqrestore(&dev->lock, flags);
2498 isdn_net_dial();
2499 return 0;
2500 } else
2501 return -EINVAL;
2502 } else
2503 return -EBUSY;
2504}
2505
2506/*
2507 * This is called from certain upper protocol layers (multilink ppp
2508 * and x25iface encapsulation module) that want to initiate dialing
2509 * themselves.
2510 */
2511int
2512isdn_net_dial_req(isdn_net_local * lp)
2513{
2514 /* is there a better error code? */
2515 if (!(ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_AUTO)) return -EBUSY;
2516
2517 return isdn_net_force_dial_lp(lp);
2518}
2519
2520/*
2521 * Force a net-interface to dial out.
2522 * This is always called from within userspace (ISDN_IOCTL_NET_DIAL).
2523 */
2524int
2525isdn_net_force_dial(char *name)
2526{
2527 isdn_net_dev *p = isdn_net_findif(name);
2528
2529 if (!p)
2530 return -ENODEV;
2531 return (isdn_net_force_dial_lp(p->local));
2532}
2533
2534/*
2535 * Allocate a new network-interface and initialize its data structures.
2536 */
2537char *
2538isdn_net_new(char *name, struct net_device *master)
2539{
2540 isdn_net_dev *netdev;
2541
2542 /* Avoid creating an existing interface */
2543 if (isdn_net_findif(name)) {
2544 printk(KERN_WARNING "isdn_net: interface %s already exists\n", name);
2545 return NULL;
2546 }
2547 if (!(netdev = (isdn_net_dev *) kmalloc(sizeof(isdn_net_dev), GFP_KERNEL))) {
2548 printk(KERN_WARNING "isdn_net: Could not allocate net-device\n");
2549 return NULL;
2550 }
2551 memset(netdev, 0, sizeof(isdn_net_dev));
2552 if (!(netdev->local = (isdn_net_local *) kmalloc(sizeof(isdn_net_local), GFP_KERNEL))) {
2553 printk(KERN_WARNING "isdn_net: Could not allocate device locals\n");
2554 kfree(netdev);
2555 return NULL;
2556 }
2557 memset(netdev->local, 0, sizeof(isdn_net_local));
2558 if (name == NULL)
2559 strcpy(netdev->local->name, " ");
2560 else
2561 strcpy(netdev->local->name, name);
2562 strcpy(netdev->dev.name, netdev->local->name);
2563 netdev->dev.priv = netdev->local;
2564 netdev->dev.init = isdn_net_init;
2565 netdev->local->p_encap = ISDN_NET_ENCAP_RAWIP;
2566 if (master) {
2567 /* Device shall be a slave */
2568 struct net_device *p = (((isdn_net_local *) master->priv)->slave);
2569 struct net_device *q = master;
2570
2571 netdev->local->master = master;
2572 /* Put device at end of slave-chain */
2573 while (p) {
2574 q = p;
2575 p = (((isdn_net_local *) p->priv)->slave);
2576 }
2577 ((isdn_net_local *) q->priv)->slave = &(netdev->dev);
2578 } else {
2579 /* Device shall be a master */
2580 /*
2581 * Watchdog timer (currently) for master only.
2582 */
2583 netdev->dev.tx_timeout = isdn_net_tx_timeout;
2584 netdev->dev.watchdog_timeo = ISDN_NET_TX_TIMEOUT;
2585 if (register_netdev(&netdev->dev) != 0) {
2586 printk(KERN_WARNING "isdn_net: Could not register net-device\n");
2587 kfree(netdev->local);
2588 kfree(netdev);
2589 return NULL;
2590 }
2591 }
2592 netdev->local->magic = ISDN_NET_MAGIC;
2593
2594 netdev->queue = netdev->local;
2595 spin_lock_init(&netdev->queue_lock);
2596
2597 netdev->local->last = netdev->local;
2598 netdev->local->netdev = netdev;
2599 netdev->local->next = netdev->local;
2600
2601 INIT_WORK(&netdev->local->tqueue, (void *)(void *) isdn_net_softint, netdev->local);
2602 spin_lock_init(&netdev->local->xmit_lock);
2603
2604 netdev->local->isdn_device = -1;
2605 netdev->local->isdn_channel = -1;
2606 netdev->local->pre_device = -1;
2607 netdev->local->pre_channel = -1;
2608 netdev->local->exclusive = -1;
2609 netdev->local->ppp_slot = -1;
2610 netdev->local->pppbind = -1;
2611 skb_queue_head_init(&netdev->local->super_tx_queue);
2612 netdev->local->l2_proto = ISDN_PROTO_L2_X75I;
2613 netdev->local->l3_proto = ISDN_PROTO_L3_TRANS;
2614 netdev->local->triggercps = 6000;
2615 netdev->local->slavedelay = 10 * HZ;
2616 netdev->local->hupflags = ISDN_INHUP; /* Do hangup even on incoming calls */
2617 netdev->local->onhtime = 10; /* Default hangup-time for saving costs
2618 of those who forget configuring this */
2619 netdev->local->dialmax = 1;
2620 netdev->local->flags = ISDN_NET_CBHUP | ISDN_NET_DM_MANUAL; /* Hangup before Callback, manual dial */
2621 netdev->local->cbdelay = 25; /* Wait 5 secs before Callback */
2622 netdev->local->dialtimeout = -1; /* Infinite Dial-Timeout */
2623 netdev->local->dialwait = 5 * HZ; /* Wait 5 sec. after failed dial */
2624 netdev->local->dialstarted = 0; /* Jiffies of last dial-start */
2625 netdev->local->dialwait_timer = 0; /* Jiffies of earliest next dial-start */
2626
2627 /* Put into to netdev-chain */
2628 netdev->next = (void *) dev->netdev;
2629 dev->netdev = netdev;
2630 return netdev->dev.name;
2631}
2632
2633char *
2634isdn_net_newslave(char *parm)
2635{
2636 char *p = strchr(parm, ',');
2637 isdn_net_dev *n;
2638 char newname[10];
2639
2640 if (p) {
2641 /* Slave-Name MUST not be empty */
2642 if (!strlen(p + 1))
2643 return NULL;
2644 strcpy(newname, p + 1);
2645 *p = 0;
2646 /* Master must already exist */
2647 if (!(n = isdn_net_findif(parm)))
2648 return NULL;
2649 /* Master must be a real interface, not a slave */
2650 if (n->local->master)
2651 return NULL;
2652 /* Master must not be started yet */
2653 if (isdn_net_device_started(n))
2654 return NULL;
2655 return (isdn_net_new(newname, &(n->dev)));
2656 }
2657 return NULL;
2658}
2659
2660/*
2661 * Set interface-parameters.
2662 * Always set all parameters, so the user-level application is responsible
2663 * for not overwriting existing setups. It has to get the current
2664 * setup first, if only selected parameters are to be changed.
2665 */
2666int
2667isdn_net_setcfg(isdn_net_ioctl_cfg * cfg)
2668{
2669 isdn_net_dev *p = isdn_net_findif(cfg->name);
2670 ulong features;
2671 int i;
2672 int drvidx;
2673 int chidx;
2674 char drvid[25];
2675
2676 if (p) {
2677 isdn_net_local *lp = p->local;
2678
2679 /* See if any registered driver supports the features we want */
2680 features = ((1 << cfg->l2_proto) << ISDN_FEATURE_L2_SHIFT) |
2681 ((1 << cfg->l3_proto) << ISDN_FEATURE_L3_SHIFT);
2682 for (i = 0; i < ISDN_MAX_DRIVERS; i++)
2683 if (dev->drv[i])
2684 if ((dev->drv[i]->interface->features & features) == features)
2685 break;
2686 if (i == ISDN_MAX_DRIVERS) {
2687 printk(KERN_WARNING "isdn_net: No driver with selected features\n");
2688 return -ENODEV;
2689 }
2690 if (lp->p_encap != cfg->p_encap){
2691#ifdef CONFIG_ISDN_X25
2692 struct concap_proto * cprot = p -> cprot;
2693#endif
2694 if (isdn_net_device_started(p)) {
2695 printk(KERN_WARNING "%s: cannot change encap when if is up\n",
2696 lp->name);
2697 return -EBUSY;
2698 }
2699#ifdef CONFIG_ISDN_X25
2700 if( cprot && cprot -> pops )
2701 cprot -> pops -> proto_del ( cprot );
2702 p -> cprot = NULL;
2703 lp -> dops = NULL;
2704 /* ... , prepare for configuration of new one ... */
2705 switch ( cfg -> p_encap ){
2706 case ISDN_NET_ENCAP_X25IFACE:
2707 lp -> dops = &isdn_concap_reliable_dl_dops;
2708 }
2709 /* ... and allocate new one ... */
2710 p -> cprot = isdn_concap_new( cfg -> p_encap );
2711 /* p -> cprot == NULL now if p_encap is not supported
2712 by means of the concap_proto mechanism */
2713 /* the protocol is not configured yet; this will
2714 happen later when isdn_net_reset() is called */
2715#endif
2716 }
2717 switch ( cfg->p_encap ) {
2718 case ISDN_NET_ENCAP_SYNCPPP:
2719#ifndef CONFIG_ISDN_PPP
2720 printk(KERN_WARNING "%s: SyncPPP support not configured\n",
2721 lp->name);
2722 return -EINVAL;
2723#else
2724 p->dev.type = ARPHRD_PPP; /* change ARP type */
2725 p->dev.addr_len = 0;
2726 p->dev.do_ioctl = isdn_ppp_dev_ioctl;
2727#endif
2728 break;
2729 case ISDN_NET_ENCAP_X25IFACE:
2730#ifndef CONFIG_ISDN_X25
2731 printk(KERN_WARNING "%s: isdn-x25 support not configured\n",
2732 p->local->name);
2733 return -EINVAL;
2734#else
2735 p->dev.type = ARPHRD_X25; /* change ARP type */
2736 p->dev.addr_len = 0;
2737#endif
2738 break;
2739 case ISDN_NET_ENCAP_CISCOHDLCK:
2740 p->dev.do_ioctl = isdn_ciscohdlck_dev_ioctl;
2741 break;
2742 default:
2743 if( cfg->p_encap >= 0 &&
2744 cfg->p_encap <= ISDN_NET_ENCAP_MAX_ENCAP )
2745 break;
2746 printk(KERN_WARNING
2747 "%s: encapsulation protocol %d not supported\n",
2748 p->local->name, cfg->p_encap);
2749 return -EINVAL;
2750 }
2751 if (strlen(cfg->drvid)) {
2752 /* A bind has been requested ... */
2753 char *c,
2754 *e;
2755
2756 drvidx = -1;
2757 chidx = -1;
2758 strcpy(drvid, cfg->drvid);
2759 if ((c = strchr(drvid, ','))) {
2760 /* The channel-number is appended to the driver-Id with a comma */
2761 chidx = (int) simple_strtoul(c + 1, &e, 10);
2762 if (e == c)
2763 chidx = -1;
2764 *c = '\0';
2765 }
2766 for (i = 0; i < ISDN_MAX_DRIVERS; i++)
2767 /* Lookup driver-Id in array */
2768 if (!(strcmp(dev->drvid[i], drvid))) {
2769 drvidx = i;
2770 break;
2771 }
2772 if ((drvidx == -1) || (chidx == -1))
2773 /* Either driver-Id or channel-number invalid */
2774 return -ENODEV;
2775 } else {
2776 /* Parameters are valid, so get them */
2777 drvidx = lp->pre_device;
2778 chidx = lp->pre_channel;
2779 }
2780 if (cfg->exclusive > 0) {
2781 unsigned long flags;
2782
2783 /* If binding is exclusive, try to grab the channel */
2784 spin_lock_irqsave(&dev->lock, flags);
2785 if ((i = isdn_get_free_channel(ISDN_USAGE_NET,
2786 lp->l2_proto, lp->l3_proto, drvidx,
2787 chidx, lp->msn)) < 0) {
2788 /* Grab failed, because desired channel is in use */
2789 lp->exclusive = -1;
2790 spin_unlock_irqrestore(&dev->lock, flags);
2791 return -EBUSY;
2792 }
2793 /* All went ok, so update isdninfo */
2794 dev->usage[i] = ISDN_USAGE_EXCLUSIVE;
2795 isdn_info_update();
2796 spin_unlock_irqrestore(&dev->lock, flags);
2797 lp->exclusive = i;
2798 } else {
2799 /* Non-exclusive binding or unbind. */
2800 lp->exclusive = -1;
2801 if ((lp->pre_device != -1) && (cfg->exclusive == -1)) {
2802 isdn_unexclusive_channel(lp->pre_device, lp->pre_channel);
2803 isdn_free_channel(lp->pre_device, lp->pre_channel, ISDN_USAGE_NET);
2804 drvidx = -1;
2805 chidx = -1;
2806 }
2807 }
2808 strcpy(lp->msn, cfg->eaz);
2809 lp->pre_device = drvidx;
2810 lp->pre_channel = chidx;
2811 lp->onhtime = cfg->onhtime;
2812 lp->charge = cfg->charge;
2813 lp->l2_proto = cfg->l2_proto;
2814 lp->l3_proto = cfg->l3_proto;
2815 lp->cbdelay = cfg->cbdelay;
2816 lp->dialmax = cfg->dialmax;
2817 lp->triggercps = cfg->triggercps;
2818 lp->slavedelay = cfg->slavedelay * HZ;
2819 lp->pppbind = cfg->pppbind;
2820 lp->dialtimeout = cfg->dialtimeout >= 0 ? cfg->dialtimeout * HZ : -1;
2821 lp->dialwait = cfg->dialwait * HZ;
2822 if (cfg->secure)
2823 lp->flags |= ISDN_NET_SECURE;
2824 else
2825 lp->flags &= ~ISDN_NET_SECURE;
2826 if (cfg->cbhup)
2827 lp->flags |= ISDN_NET_CBHUP;
2828 else
2829 lp->flags &= ~ISDN_NET_CBHUP;
2830 switch (cfg->callback) {
2831 case 0:
2832 lp->flags &= ~(ISDN_NET_CALLBACK | ISDN_NET_CBOUT);
2833 break;
2834 case 1:
2835 lp->flags |= ISDN_NET_CALLBACK;
2836 lp->flags &= ~ISDN_NET_CBOUT;
2837 break;
2838 case 2:
2839 lp->flags |= ISDN_NET_CBOUT;
2840 lp->flags &= ~ISDN_NET_CALLBACK;
2841 break;
2842 }
2843 lp->flags &= ~ISDN_NET_DIALMODE_MASK; /* first all bits off */
2844 if (cfg->dialmode && !(cfg->dialmode & ISDN_NET_DIALMODE_MASK)) {
2845 /* old isdnctrl version, where only 0 or 1 is given */
2846 printk(KERN_WARNING
2847 "Old isdnctrl version detected! Please update.\n");
2848 lp->flags |= ISDN_NET_DM_OFF; /* turn on `off' bit */
2849 }
2850 else {
2851 lp->flags |= cfg->dialmode; /* turn on selected bits */
2852 }
2853 if (cfg->chargehup)
2854 lp->hupflags |= ISDN_CHARGEHUP;
2855 else
2856 lp->hupflags &= ~ISDN_CHARGEHUP;
2857 if (cfg->ihup)
2858 lp->hupflags |= ISDN_INHUP;
2859 else
2860 lp->hupflags &= ~ISDN_INHUP;
2861 if (cfg->chargeint > 10) {
2862 lp->hupflags |= ISDN_CHARGEHUP | ISDN_HAVECHARGE | ISDN_MANCHARGE;
2863 lp->chargeint = cfg->chargeint * HZ;
2864 }
2865 if (cfg->p_encap != lp->p_encap) {
2866 if (cfg->p_encap == ISDN_NET_ENCAP_RAWIP) {
2867 p->dev.hard_header = NULL;
2868 p->dev.hard_header_cache = NULL;
2869 p->dev.header_cache_update = NULL;
2870 p->dev.flags = IFF_NOARP|IFF_POINTOPOINT;
2871 } else {
2872 p->dev.hard_header = isdn_net_header;
2873 if (cfg->p_encap == ISDN_NET_ENCAP_ETHER) {
2874 p->dev.hard_header_cache = lp->org_hhc;
2875 p->dev.header_cache_update = lp->org_hcu;
2876 p->dev.flags = IFF_BROADCAST | IFF_MULTICAST;
2877 } else {
2878 p->dev.hard_header_cache = NULL;
2879 p->dev.header_cache_update = NULL;
2880 p->dev.flags = IFF_NOARP|IFF_POINTOPOINT;
2881 }
2882 }
2883 }
2884 lp->p_encap = cfg->p_encap;
2885 return 0;
2886 }
2887 return -ENODEV;
2888}
2889
2890/*
2891 * Perform get-interface-parameters.ioctl
2892 */
2893int
2894isdn_net_getcfg(isdn_net_ioctl_cfg * cfg)
2895{
2896 isdn_net_dev *p = isdn_net_findif(cfg->name);
2897
2898 if (p) {
2899 isdn_net_local *lp = p->local;
2900
2901 strcpy(cfg->eaz, lp->msn);
2902 cfg->exclusive = lp->exclusive;
2903 if (lp->pre_device >= 0) {
2904 sprintf(cfg->drvid, "%s,%d", dev->drvid[lp->pre_device],
2905 lp->pre_channel);
2906 } else
2907 cfg->drvid[0] = '\0';
2908 cfg->onhtime = lp->onhtime;
2909 cfg->charge = lp->charge;
2910 cfg->l2_proto = lp->l2_proto;
2911 cfg->l3_proto = lp->l3_proto;
2912 cfg->p_encap = lp->p_encap;
2913 cfg->secure = (lp->flags & ISDN_NET_SECURE) ? 1 : 0;
2914 cfg->callback = 0;
2915 if (lp->flags & ISDN_NET_CALLBACK)
2916 cfg->callback = 1;
2917 if (lp->flags & ISDN_NET_CBOUT)
2918 cfg->callback = 2;
2919 cfg->cbhup = (lp->flags & ISDN_NET_CBHUP) ? 1 : 0;
2920 cfg->dialmode = lp->flags & ISDN_NET_DIALMODE_MASK;
2921 cfg->chargehup = (lp->hupflags & 4) ? 1 : 0;
2922 cfg->ihup = (lp->hupflags & 8) ? 1 : 0;
2923 cfg->cbdelay = lp->cbdelay;
2924 cfg->dialmax = lp->dialmax;
2925 cfg->triggercps = lp->triggercps;
2926 cfg->slavedelay = lp->slavedelay / HZ;
2927 cfg->chargeint = (lp->hupflags & ISDN_CHARGEHUP) ?
2928 (lp->chargeint / HZ) : 0;
2929 cfg->pppbind = lp->pppbind;
2930 cfg->dialtimeout = lp->dialtimeout >= 0 ? lp->dialtimeout / HZ : -1;
2931 cfg->dialwait = lp->dialwait / HZ;
2932 if (lp->slave)
2933 strcpy(cfg->slave, ((isdn_net_local *) lp->slave->priv)->name);
2934 else
2935 cfg->slave[0] = '\0';
2936 if (lp->master)
2937 strcpy(cfg->master, ((isdn_net_local *) lp->master->priv)->name);
2938 else
2939 cfg->master[0] = '\0';
2940 return 0;
2941 }
2942 return -ENODEV;
2943}
2944
2945/*
2946 * Add a phone-number to an interface.
2947 */
2948int
2949isdn_net_addphone(isdn_net_ioctl_phone * phone)
2950{
2951 isdn_net_dev *p = isdn_net_findif(phone->name);
2952 isdn_net_phone *n;
2953
2954 if (p) {
2955 if (!(n = (isdn_net_phone *) kmalloc(sizeof(isdn_net_phone), GFP_KERNEL)))
2956 return -ENOMEM;
2957 strcpy(n->num, phone->phone);
2958 n->next = p->local->phone[phone->outgoing & 1];
2959 p->local->phone[phone->outgoing & 1] = n;
2960 return 0;
2961 }
2962 return -ENODEV;
2963}
2964
2965/*
2966 * Copy a string of all phone-numbers of an interface to user space.
2967 * This might sleep and must be called with the isdn semaphore down.
2968 */
2969int
2970isdn_net_getphones(isdn_net_ioctl_phone * phone, char __user *phones)
2971{
2972 isdn_net_dev *p = isdn_net_findif(phone->name);
2973 int inout = phone->outgoing & 1;
2974 int more = 0;
2975 int count = 0;
2976 isdn_net_phone *n;
2977
2978 if (!p)
2979 return -ENODEV;
2980 inout &= 1;
2981 for (n = p->local->phone[inout]; n; n = n->next) {
2982 if (more) {
2983 put_user(' ', phones++);
2984 count++;
2985 }
2986 if (copy_to_user(phones, n->num, strlen(n->num) + 1)) {
2987 return -EFAULT;
2988 }
2989 phones += strlen(n->num);
2990 count += strlen(n->num);
2991 more = 1;
2992 }
2993 put_user(0, phones);
2994 count++;
2995 return count;
2996}
2997
2998/*
2999 * Copy a string containing the peer's phone number of a connected interface
3000 * to user space.
3001 */
3002int
3003isdn_net_getpeer(isdn_net_ioctl_phone *phone, isdn_net_ioctl_phone __user *peer)
3004{
3005 isdn_net_dev *p = isdn_net_findif(phone->name);
3006 int ch, dv, idx;
3007
3008 if (!p) return -ENODEV;
3009 /*
3010 * Theoretical race: while this executes, the remote number might
3011 * become invalid (hang up) or change (new connection), resulting
3012 * in (partially) wrong number copied to user. This race
3013 * currently ignored.
3014 */
3015 ch = p->local->isdn_channel;
3016 dv = p->local->isdn_device;
3017 if(ch<0 && dv<0) return -ENOTCONN;
3018 idx = isdn_dc2minor(dv, ch);
3019 if (idx<0) return -ENODEV;
3020 /* for pre-bound channels, we need this extra check */
3021 if ( strncmp(dev->num[idx],"???",3) == 0 ) return -ENOTCONN;
3022 strncpy(phone->phone,dev->num[idx],ISDN_MSNLEN);
3023 phone->outgoing=USG_OUTGOING(dev->usage[idx]);
3024 if ( copy_to_user(peer,phone,sizeof(*peer)) ) return -EFAULT;
3025 return 0;
3026}
3027/*
3028 * Delete a phone-number from an interface.
3029 */
3030int
3031isdn_net_delphone(isdn_net_ioctl_phone * phone)
3032{
3033 isdn_net_dev *p = isdn_net_findif(phone->name);
3034 int inout = phone->outgoing & 1;
3035 isdn_net_phone *n;
3036 isdn_net_phone *m;
3037
3038 if (p) {
3039 n = p->local->phone[inout];
3040 m = NULL;
3041 while (n) {
3042 if (!strcmp(n->num, phone->phone)) {
3043 if (p->local->dial == n)
3044 p->local->dial = n->next;
3045 if (m)
3046 m->next = n->next;
3047 else
3048 p->local->phone[inout] = n->next;
3049 kfree(n);
3050 return 0;
3051 }
3052 m = n;
3053 n = (isdn_net_phone *) n->next;
3054 }
3055 return -EINVAL;
3056 }
3057 return -ENODEV;
3058}
3059
3060/*
3061 * Delete all phone-numbers of an interface.
3062 */
3063static int
3064isdn_net_rmallphone(isdn_net_dev * p)
3065{
3066 isdn_net_phone *n;
3067 isdn_net_phone *m;
3068 int i;
3069
3070 for (i = 0; i < 2; i++) {
3071 n = p->local->phone[i];
3072 while (n) {
3073 m = n->next;
3074 kfree(n);
3075 n = m;
3076 }
3077 p->local->phone[i] = NULL;
3078 }
3079 p->local->dial = NULL;
3080 return 0;
3081}
3082
3083/*
3084 * Force a hangup of a network-interface.
3085 */
3086int
3087isdn_net_force_hangup(char *name)
3088{
3089 isdn_net_dev *p = isdn_net_findif(name);
3090 struct net_device *q;
3091
3092 if (p) {
3093 if (p->local->isdn_device < 0)
3094 return 1;
3095 q = p->local->slave;
3096 /* If this interface has slaves, do a hangup for them also. */
3097 while (q) {
3098 isdn_net_hangup(q);
3099 q = (((isdn_net_local *) q->priv)->slave);
3100 }
3101 isdn_net_hangup(&p->dev);
3102 return 0;
3103 }
3104 return -ENODEV;
3105}
3106
3107/*
3108 * Helper-function for isdn_net_rm: Do the real work.
3109 */
3110static int
3111isdn_net_realrm(isdn_net_dev * p, isdn_net_dev * q)
3112{
3113 u_long flags;
3114
3115 if (isdn_net_device_started(p)) {
3116 return -EBUSY;
3117 }
3118#ifdef CONFIG_ISDN_X25
3119 if( p -> cprot && p -> cprot -> pops )
3120 p -> cprot -> pops -> proto_del ( p -> cprot );
3121#endif
3122 /* Free all phone-entries */
3123 isdn_net_rmallphone(p);
3124 /* If interface is bound exclusive, free channel-usage */
3125 if (p->local->exclusive != -1)
3126 isdn_unexclusive_channel(p->local->pre_device, p->local->pre_channel);
3127 if (p->local->master) {
3128 /* It's a slave-device, so update master's slave-pointer if necessary */
3129 if (((isdn_net_local *) (p->local->master->priv))->slave == &p->dev)
3130 ((isdn_net_local *) (p->local->master->priv))->slave = p->local->slave;
3131 } else {
3132 /* Unregister only if it's a master-device */
3133 p->dev.hard_header_cache = p->local->org_hhc;
3134 p->dev.header_cache_update = p->local->org_hcu;
3135 unregister_netdev(&p->dev);
3136 }
3137 /* Unlink device from chain */
3138 spin_lock_irqsave(&dev->lock, flags);
3139 if (q)
3140 q->next = p->next;
3141 else
3142 dev->netdev = p->next;
3143 if (p->local->slave) {
3144 /* If this interface has a slave, remove it also */
3145 char *slavename = ((isdn_net_local *) (p->local->slave->priv))->name;
3146 isdn_net_dev *n = dev->netdev;
3147 q = NULL;
3148 while (n) {
3149 if (!strcmp(n->local->name, slavename)) {
3150 spin_unlock_irqrestore(&dev->lock, flags);
3151 isdn_net_realrm(n, q);
3152 spin_lock_irqsave(&dev->lock, flags);
3153 break;
3154 }
3155 q = n;
3156 n = (isdn_net_dev *) n->next;
3157 }
3158 }
3159 spin_unlock_irqrestore(&dev->lock, flags);
3160 /* If no more net-devices remain, disable auto-hangup timer */
3161 if (dev->netdev == NULL)
3162 isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, 0);
3163 kfree(p->local);
3164 kfree(p);
3165
3166 return 0;
3167}
3168
3169/*
3170 * Remove a single network-interface.
3171 */
3172int
3173isdn_net_rm(char *name)
3174{
3175 u_long flags;
3176 isdn_net_dev *p;
3177 isdn_net_dev *q;
3178
3179 /* Search name in netdev-chain */
3180 spin_lock_irqsave(&dev->lock, flags);
3181 p = dev->netdev;
3182 q = NULL;
3183 while (p) {
3184 if (!strcmp(p->local->name, name)) {
3185 spin_unlock_irqrestore(&dev->lock, flags);
3186 return (isdn_net_realrm(p, q));
3187 }
3188 q = p;
3189 p = (isdn_net_dev *) p->next;
3190 }
3191 spin_unlock_irqrestore(&dev->lock, flags);
3192 /* If no more net-devices remain, disable auto-hangup timer */
3193 if (dev->netdev == NULL)
3194 isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, 0);
3195 return -ENODEV;
3196}
3197
3198/*
3199 * Remove all network-interfaces
3200 */
3201int
3202isdn_net_rmall(void)
3203{
3204 u_long flags;
3205 int ret;
3206
3207 /* Walk through netdev-chain */
3208 spin_lock_irqsave(&dev->lock, flags);
3209 while (dev->netdev) {
3210 if (!dev->netdev->local->master) {
3211 /* Remove master-devices only, slaves get removed with their master */
3212 spin_unlock_irqrestore(&dev->lock, flags);
3213 if ((ret = isdn_net_realrm(dev->netdev, NULL))) {
3214 return ret;
3215 }
3216 spin_lock_irqsave(&dev->lock, flags);
3217 }
3218 }
3219 dev->netdev = NULL;
3220 spin_unlock_irqrestore(&dev->lock, flags);
3221 return 0;
3222}
diff --git a/drivers/isdn/i4l/isdn_net.h b/drivers/isdn/i4l/isdn_net.h
new file mode 100644
index 000000000000..bc2f0dd962ea
--- /dev/null
+++ b/drivers/isdn/i4l/isdn_net.h
@@ -0,0 +1,190 @@
1/* $Id: isdn_net.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
2 *
3 * header for Linux ISDN subsystem, network related functions (linklevel).
4 *
5 * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
6 * Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg
7 * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
8 *
9 * This software may be used and distributed according to the terms
10 * of the GNU General Public License, incorporated herein by reference.
11 *
12 */
13
14 /* Definitions for hupflags: */
15#define ISDN_WAITCHARGE 1 /* did not get a charge info yet */
16#define ISDN_HAVECHARGE 2 /* We know a charge info */
17#define ISDN_CHARGEHUP 4 /* We want to use the charge mechanism */
18#define ISDN_INHUP 8 /* Even if incoming, close after huptimeout */
19#define ISDN_MANCHARGE 16 /* Charge Interval manually set */
20
21/*
22 * Definitions for Cisco-HDLC header.
23 */
24
25#define CISCO_ADDR_UNICAST 0x0f
26#define CISCO_ADDR_BROADCAST 0x8f
27#define CISCO_CTRL 0x00
28#define CISCO_TYPE_CDP 0x2000
29#define CISCO_TYPE_SLARP 0x8035
30#define CISCO_SLARP_REQUEST 0
31#define CISCO_SLARP_REPLY 1
32#define CISCO_SLARP_KEEPALIVE 2
33
34extern char *isdn_net_new(char *, struct net_device *);
35extern char *isdn_net_newslave(char *);
36extern int isdn_net_rm(char *);
37extern int isdn_net_rmall(void);
38extern int isdn_net_stat_callback(int, isdn_ctrl *);
39extern int isdn_net_setcfg(isdn_net_ioctl_cfg *);
40extern int isdn_net_getcfg(isdn_net_ioctl_cfg *);
41extern int isdn_net_addphone(isdn_net_ioctl_phone *);
42extern int isdn_net_getphones(isdn_net_ioctl_phone *, char __user *);
43extern int isdn_net_getpeer(isdn_net_ioctl_phone *, isdn_net_ioctl_phone __user *);
44extern int isdn_net_delphone(isdn_net_ioctl_phone *);
45extern int isdn_net_find_icall(int, int, int, setup_parm *);
46extern void isdn_net_hangup(struct net_device *);
47extern void isdn_net_dial(void);
48extern void isdn_net_autohup(void);
49extern int isdn_net_force_hangup(char *);
50extern int isdn_net_force_dial(char *);
51extern isdn_net_dev *isdn_net_findif(char *);
52extern int isdn_net_rcv_skb(int, struct sk_buff *);
53extern int isdn_net_dial_req(isdn_net_local *);
54extern void isdn_net_writebuf_skb(isdn_net_local *lp, struct sk_buff *skb);
55extern void isdn_net_write_super(isdn_net_local *lp, struct sk_buff *skb);
56
57#define ISDN_NET_MAX_QUEUE_LENGTH 2
58
59/*
60 * is this particular channel busy?
61 */
62static __inline__ int isdn_net_lp_busy(isdn_net_local *lp)
63{
64 if (atomic_read(&lp->frame_cnt) < ISDN_NET_MAX_QUEUE_LENGTH)
65 return 0;
66 else
67 return 1;
68}
69
70/*
71 * For the given net device, this will get a non-busy channel out of the
72 * corresponding bundle. The returned channel is locked.
73 */
74static __inline__ isdn_net_local * isdn_net_get_locked_lp(isdn_net_dev *nd)
75{
76 unsigned long flags;
77 isdn_net_local *lp;
78
79 spin_lock_irqsave(&nd->queue_lock, flags);
80 lp = nd->queue; /* get lp on top of queue */
81 spin_lock(&nd->queue->xmit_lock);
82 while (isdn_net_lp_busy(nd->queue)) {
83 spin_unlock(&nd->queue->xmit_lock);
84 nd->queue = nd->queue->next;
85 if (nd->queue == lp) { /* not found -- should never happen */
86 lp = NULL;
87 goto errout;
88 }
89 spin_lock(&nd->queue->xmit_lock);
90 }
91 lp = nd->queue;
92 nd->queue = nd->queue->next;
93 local_bh_disable();
94errout:
95 spin_unlock_irqrestore(&nd->queue_lock, flags);
96 return lp;
97}
98
99/*
100 * add a channel to a bundle
101 */
102static __inline__ void isdn_net_add_to_bundle(isdn_net_dev *nd, isdn_net_local *nlp)
103{
104 isdn_net_local *lp;
105 unsigned long flags;
106
107 spin_lock_irqsave(&nd->queue_lock, flags);
108
109 lp = nd->queue;
110// printk(KERN_DEBUG "%s: lp:%s(%p) nlp:%s(%p) last(%p)\n",
111// __FUNCTION__, lp->name, lp, nlp->name, nlp, lp->last);
112 nlp->last = lp->last;
113 lp->last->next = nlp;
114 lp->last = nlp;
115 nlp->next = lp;
116 nd->queue = nlp;
117
118 spin_unlock_irqrestore(&nd->queue_lock, flags);
119}
120/*
121 * remove a channel from the bundle it belongs to
122 */
123static __inline__ void isdn_net_rm_from_bundle(isdn_net_local *lp)
124{
125 isdn_net_local *master_lp = lp;
126 unsigned long flags;
127
128 if (lp->master)
129 master_lp = (isdn_net_local *) lp->master->priv;
130
131// printk(KERN_DEBUG "%s: lp:%s(%p) mlp:%s(%p) last(%p) next(%p) mndq(%p)\n",
132// __FUNCTION__, lp->name, lp, master_lp->name, master_lp, lp->last, lp->next, master_lp->netdev->queue);
133 spin_lock_irqsave(&master_lp->netdev->queue_lock, flags);
134 lp->last->next = lp->next;
135 lp->next->last = lp->last;
136 if (master_lp->netdev->queue == lp) {
137 master_lp->netdev->queue = lp->next;
138 if (lp->next == lp) { /* last in queue */
139 master_lp->netdev->queue = master_lp->netdev->local;
140 }
141 }
142 lp->next = lp->last = lp; /* (re)set own pointers */
143// printk(KERN_DEBUG "%s: mndq(%p)\n",
144// __FUNCTION__, master_lp->netdev->queue);
145 spin_unlock_irqrestore(&master_lp->netdev->queue_lock, flags);
146}
147
148static inline int
149put_u8(unsigned char *p, u8 x)
150{
151 *p = x;
152 return 1;
153}
154
155static inline int
156put_u16(unsigned char *p, u16 x)
157{
158 *((u16 *)p) = htons(x);
159 return 2;
160}
161
162static inline int
163put_u32(unsigned char *p, u32 x)
164{
165 *((u32 *)p) = htonl(x);
166 return 4;
167}
168
169static inline int
170get_u8(unsigned char *p, u8 *x)
171{
172 *x = *p;
173 return 1;
174}
175
176static inline int
177get_u16(unsigned char *p, u16 *x)
178{
179 *x = ntohs(*((u16 *)p));
180 return 2;
181}
182
183static inline int
184get_u32(unsigned char *p, u32 *x)
185{
186 *x = ntohl(*((u32 *)p));
187 return 4;
188}
189
190
diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c
new file mode 100644
index 000000000000..3c092117a8ea
--- /dev/null
+++ b/drivers/isdn/i4l/isdn_ppp.c
@@ -0,0 +1,3020 @@
1/* $Id: isdn_ppp.c,v 1.1.2.3 2004/02/10 01:07:13 keil Exp $
2 *
3 * Linux ISDN subsystem, functions for synchronous PPP (linklevel).
4 *
5 * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
6 *
7 * This software may be used and distributed according to the terms
8 * of the GNU General Public License, incorporated herein by reference.
9 *
10 */
11
12#include <linux/config.h>
13#include <linux/isdn.h>
14#include <linux/poll.h>
15#include <linux/ppp-comp.h>
16#ifdef CONFIG_IPPP_FILTER
17#include <linux/filter.h>
18#endif
19
20#include "isdn_common.h"
21#include "isdn_ppp.h"
22#include "isdn_net.h"
23
24#ifndef PPP_IPX
25#define PPP_IPX 0x002b
26#endif
27
28/* Prototypes */
29static int isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot);
30static int isdn_ppp_closewait(int slot);
31static void isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp,
32 struct sk_buff *skb, int proto);
33static int isdn_ppp_if_get_unit(char *namebuf);
34static int isdn_ppp_set_compressor(struct ippp_struct *is,struct isdn_ppp_comp_data *);
35static struct sk_buff *isdn_ppp_decompress(struct sk_buff *,
36 struct ippp_struct *,struct ippp_struct *,int *proto);
37static void isdn_ppp_receive_ccp(isdn_net_dev * net_dev, isdn_net_local * lp,
38 struct sk_buff *skb,int proto);
39static struct sk_buff *isdn_ppp_compress(struct sk_buff *skb_in,int *proto,
40 struct ippp_struct *is,struct ippp_struct *master,int type);
41static void isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp,
42 struct sk_buff *skb);
43
44/* New CCP stuff */
45static void isdn_ppp_ccp_kickup(struct ippp_struct *is);
46static void isdn_ppp_ccp_xmit_reset(struct ippp_struct *is, int proto,
47 unsigned char code, unsigned char id,
48 unsigned char *data, int len);
49static struct ippp_ccp_reset *isdn_ppp_ccp_reset_alloc(struct ippp_struct *is);
50static void isdn_ppp_ccp_reset_free(struct ippp_struct *is);
51static void isdn_ppp_ccp_reset_free_state(struct ippp_struct *is,
52 unsigned char id);
53static void isdn_ppp_ccp_timer_callback(unsigned long closure);
54static struct ippp_ccp_reset_state *isdn_ppp_ccp_reset_alloc_state(struct ippp_struct *is,
55 unsigned char id);
56static void isdn_ppp_ccp_reset_trans(struct ippp_struct *is,
57 struct isdn_ppp_resetparams *rp);
58static void isdn_ppp_ccp_reset_ack_rcvd(struct ippp_struct *is,
59 unsigned char id);
60
61
62
63#ifdef CONFIG_ISDN_MPP
64static ippp_bundle * isdn_ppp_bundle_arr = NULL;
65
66static int isdn_ppp_mp_bundle_array_init(void);
67static int isdn_ppp_mp_init( isdn_net_local * lp, ippp_bundle * add_to );
68static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp,
69 struct sk_buff *skb);
70static void isdn_ppp_mp_cleanup( isdn_net_local * lp );
71
72static int isdn_ppp_bundle(struct ippp_struct *, int unit);
73#endif /* CONFIG_ISDN_MPP */
74
75char *isdn_ppp_revision = "$Revision: 1.1.2.3 $";
76
77static struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS];
78
79static struct isdn_ppp_compressor *ipc_head = NULL;
80
81/*
82 * frame log (debug)
83 */
84static void
85isdn_ppp_frame_log(char *info, char *data, int len, int maxlen,int unit,int slot)
86{
87 int cnt,
88 j,
89 i;
90 char buf[80];
91
92 if (len < maxlen)
93 maxlen = len;
94
95 for (i = 0, cnt = 0; cnt < maxlen; i++) {
96 for (j = 0; j < 16 && cnt < maxlen; j++, cnt++)
97 sprintf(buf + j * 3, "%02x ", (unsigned char) data[cnt]);
98 printk(KERN_DEBUG "[%d/%d].%s[%d]: %s\n",unit,slot, info, i, buf);
99 }
100}
101
102/*
103 * unbind isdn_net_local <=> ippp-device
104 * note: it can happen, that we hangup/free the master before the slaves
105 * in this case we bind another lp to the master device
106 */
107int
108isdn_ppp_free(isdn_net_local * lp)
109{
110 struct ippp_struct *is;
111
112 if (lp->ppp_slot < 0 || lp->ppp_slot > ISDN_MAX_CHANNELS) {
113 printk(KERN_ERR "%s: ppp_slot(%d) out of range\n",
114 __FUNCTION__, lp->ppp_slot);
115 return 0;
116 }
117
118#ifdef CONFIG_ISDN_MPP
119 spin_lock(&lp->netdev->pb->lock);
120#endif
121 isdn_net_rm_from_bundle(lp);
122#ifdef CONFIG_ISDN_MPP
123 if (lp->netdev->pb->ref_ct == 1) /* last link in queue? */
124 isdn_ppp_mp_cleanup(lp);
125
126 lp->netdev->pb->ref_ct--;
127 spin_unlock(&lp->netdev->pb->lock);
128#endif /* CONFIG_ISDN_MPP */
129 if (lp->ppp_slot < 0 || lp->ppp_slot > ISDN_MAX_CHANNELS) {
130 printk(KERN_ERR "%s: ppp_slot(%d) now invalid\n",
131 __FUNCTION__, lp->ppp_slot);
132 return 0;
133 }
134 is = ippp_table[lp->ppp_slot];
135 if ((is->state & IPPP_CONNECT))
136 isdn_ppp_closewait(lp->ppp_slot); /* force wakeup on ippp device */
137 else if (is->state & IPPP_ASSIGNED)
138 is->state = IPPP_OPEN; /* fallback to 'OPEN but not ASSIGNED' state */
139
140 if (is->debug & 0x1)
141 printk(KERN_DEBUG "isdn_ppp_free %d %lx %lx\n", lp->ppp_slot, (long) lp, (long) is->lp);
142
143 is->lp = NULL; /* link is down .. set lp to NULL */
144 lp->ppp_slot = -1; /* is this OK ?? */
145
146 return 0;
147}
148
149/*
150 * bind isdn_net_local <=> ippp-device
151 *
152 * This function is allways called with holding dev->lock so
153 * no additional lock is needed
154 */
155int
156isdn_ppp_bind(isdn_net_local * lp)
157{
158 int i;
159 int unit = 0;
160 struct ippp_struct *is;
161 int retval;
162
163 if (lp->pppbind < 0) { /* device bounded to ippp device ? */
164 isdn_net_dev *net_dev = dev->netdev;
165 char exclusive[ISDN_MAX_CHANNELS]; /* exclusive flags */
166 memset(exclusive, 0, ISDN_MAX_CHANNELS);
167 while (net_dev) { /* step through net devices to find exclusive minors */
168 isdn_net_local *lp = net_dev->local;
169 if (lp->pppbind >= 0)
170 exclusive[lp->pppbind] = 1;
171 net_dev = net_dev->next;
172 }
173 /*
174 * search a free device / slot
175 */
176 for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
177 if (ippp_table[i]->state == IPPP_OPEN && !exclusive[ippp_table[i]->minor]) { /* OPEN, but not connected! */
178 break;
179 }
180 }
181 } else {
182 for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
183 if (ippp_table[i]->minor == lp->pppbind &&
184 (ippp_table[i]->state & IPPP_OPEN) == IPPP_OPEN)
185 break;
186 }
187 }
188
189 if (i >= ISDN_MAX_CHANNELS) {
190 printk(KERN_WARNING "isdn_ppp_bind: Can't find a (free) connection to the ipppd daemon.\n");
191 retval = -1;
192 goto out;
193 }
194 unit = isdn_ppp_if_get_unit(lp->name); /* get unit number from interface name .. ugly! */
195 if (unit < 0) {
196 printk(KERN_ERR "isdn_ppp_bind: illegal interface name %s.\n", lp->name);
197 retval = -1;
198 goto out;
199 }
200
201 lp->ppp_slot = i;
202 is = ippp_table[i];
203 is->lp = lp;
204 is->unit = unit;
205 is->state = IPPP_OPEN | IPPP_ASSIGNED; /* assigned to a netdevice but not connected */
206#ifdef CONFIG_ISDN_MPP
207 retval = isdn_ppp_mp_init(lp, NULL);
208 if (retval < 0)
209 goto out;
210#endif /* CONFIG_ISDN_MPP */
211
212 retval = lp->ppp_slot;
213
214 out:
215 return retval;
216}
217
218/*
219 * kick the ipppd on the device
220 * (wakes up daemon after B-channel connect)
221 */
222
223void
224isdn_ppp_wakeup_daemon(isdn_net_local * lp)
225{
226 if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {
227 printk(KERN_ERR "%s: ppp_slot(%d) out of range\n",
228 __FUNCTION__, lp->ppp_slot);
229 return;
230 }
231 ippp_table[lp->ppp_slot]->state = IPPP_OPEN | IPPP_CONNECT | IPPP_NOBLOCK;
232 wake_up_interruptible(&ippp_table[lp->ppp_slot]->wq);
233}
234
235/*
236 * there was a hangup on the netdevice
237 * force wakeup of the ippp device
238 * go into 'device waits for release' state
239 */
240static int
241isdn_ppp_closewait(int slot)
242{
243 struct ippp_struct *is;
244
245 if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
246 printk(KERN_ERR "%s: slot(%d) out of range\n",
247 __FUNCTION__, slot);
248 return 0;
249 }
250 is = ippp_table[slot];
251 if (is->state)
252 wake_up_interruptible(&is->wq);
253 is->state = IPPP_CLOSEWAIT;
254 return 1;
255}
256
257/*
258 * isdn_ppp_find_slot / isdn_ppp_free_slot
259 */
260
261static int
262isdn_ppp_get_slot(void)
263{
264 int i;
265 for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
266 if (!ippp_table[i]->state)
267 return i;
268 }
269 return -1;
270}
271
272/*
273 * isdn_ppp_open
274 */
275
276int
277isdn_ppp_open(int min, struct file *file)
278{
279 int slot;
280 struct ippp_struct *is;
281
282 if (min < 0 || min > ISDN_MAX_CHANNELS)
283 return -ENODEV;
284
285 slot = isdn_ppp_get_slot();
286 if (slot < 0) {
287 return -EBUSY;
288 }
289 is = file->private_data = ippp_table[slot];
290
291 printk(KERN_DEBUG "ippp, open, slot: %d, minor: %d, state: %04x\n",
292 slot, min, is->state);
293
294 /* compression stuff */
295 is->link_compressor = is->compressor = NULL;
296 is->link_decompressor = is->decompressor = NULL;
297 is->link_comp_stat = is->comp_stat = NULL;
298 is->link_decomp_stat = is->decomp_stat = NULL;
299 is->compflags = 0;
300
301 is->reset = isdn_ppp_ccp_reset_alloc(is);
302
303 is->lp = NULL;
304 is->mp_seqno = 0; /* MP sequence number */
305 is->pppcfg = 0; /* ppp configuration */
306 is->mpppcfg = 0; /* mppp configuration */
307 is->last_link_seqno = -1; /* MP: maybe set to Bundle-MIN, when joining a bundle ?? */
308 is->unit = -1; /* set, when we have our interface */
309 is->mru = 1524; /* MRU, default 1524 */
310 is->maxcid = 16; /* VJ: maxcid */
311 is->tk = current;
312 init_waitqueue_head(&is->wq);
313 is->first = is->rq + NUM_RCV_BUFFS - 1; /* receive queue */
314 is->last = is->rq;
315 is->minor = min;
316#ifdef CONFIG_ISDN_PPP_VJ
317 /*
318 * VJ header compression init
319 */
320 is->slcomp = slhc_init(16, 16); /* not necessary for 2. link in bundle */
321#endif
322#ifdef CONFIG_IPPP_FILTER
323 is->pass_filter = NULL;
324 is->active_filter = NULL;
325#endif
326 is->state = IPPP_OPEN;
327
328 return 0;
329}
330
331/*
332 * release ippp device
333 */
334void
335isdn_ppp_release(int min, struct file *file)
336{
337 int i;
338 struct ippp_struct *is;
339
340 if (min < 0 || min >= ISDN_MAX_CHANNELS)
341 return;
342 is = file->private_data;
343
344 if (!is) {
345 printk(KERN_ERR "%s: no file->private_data\n", __FUNCTION__);
346 return;
347 }
348 if (is->debug & 0x1)
349 printk(KERN_DEBUG "ippp: release, minor: %d %lx\n", min, (long) is->lp);
350
351 if (is->lp) { /* a lp address says: this link is still up */
352 isdn_net_dev *p = is->lp->netdev;
353
354 if (!p) {
355 printk(KERN_ERR "%s: no lp->netdev\n", __FUNCTION__);
356 return;
357 }
358 is->state &= ~IPPP_CONNECT; /* -> effect: no call of wakeup */
359 /*
360 * isdn_net_hangup() calls isdn_ppp_free()
361 * isdn_ppp_free() sets is->lp to NULL and lp->ppp_slot to -1
362 * removing the IPPP_CONNECT flag omits calling of isdn_ppp_wakeup_daemon()
363 */
364 isdn_net_hangup(&p->dev);
365 }
366 for (i = 0; i < NUM_RCV_BUFFS; i++) {
367 if (is->rq[i].buf) {
368 kfree(is->rq[i].buf);
369 is->rq[i].buf = NULL;
370 }
371 }
372 is->first = is->rq + NUM_RCV_BUFFS - 1; /* receive queue */
373 is->last = is->rq;
374
375#ifdef CONFIG_ISDN_PPP_VJ
376/* TODO: if this was the previous master: link the slcomp to the new master */
377 slhc_free(is->slcomp);
378 is->slcomp = NULL;
379#endif
380#ifdef CONFIG_IPPP_FILTER
381 if (is->pass_filter) {
382 kfree(is->pass_filter);
383 is->pass_filter = NULL;
384 }
385 if (is->active_filter) {
386 kfree(is->active_filter);
387 is->active_filter = NULL;
388 }
389#endif
390
391/* TODO: if this was the previous master: link the stuff to the new master */
392 if(is->comp_stat)
393 is->compressor->free(is->comp_stat);
394 if(is->link_comp_stat)
395 is->link_compressor->free(is->link_comp_stat);
396 if(is->link_decomp_stat)
397 is->link_decompressor->free(is->link_decomp_stat);
398 if(is->decomp_stat)
399 is->decompressor->free(is->decomp_stat);
400 is->compressor = is->link_compressor = NULL;
401 is->decompressor = is->link_decompressor = NULL;
402 is->comp_stat = is->link_comp_stat = NULL;
403 is->decomp_stat = is->link_decomp_stat = NULL;
404
405 /* Clean up if necessary */
406 if(is->reset)
407 isdn_ppp_ccp_reset_free(is);
408
409 /* this slot is ready for new connections */
410 is->state = 0;
411}
412
413/*
414 * get_arg .. ioctl helper
415 */
416static int
417get_arg(void __user *b, void *val, int len)
418{
419 if (len <= 0)
420 len = sizeof(void *);
421 if (copy_from_user(val, b, len))
422 return -EFAULT;
423 return 0;
424}
425
426/*
427 * set arg .. ioctl helper
428 */
429static int
430set_arg(void __user *b, void *val,int len)
431{
432 if(len <= 0)
433 len = sizeof(void *);
434 if (copy_to_user(b, val, len))
435 return -EFAULT;
436 return 0;
437}
438
439static int get_filter(void __user *arg, struct sock_filter **p)
440{
441 struct sock_fprog uprog;
442 struct sock_filter *code = NULL;
443 int len, err;
444
445 if (copy_from_user(&uprog, arg, sizeof(uprog)))
446 return -EFAULT;
447
448 if (!uprog.len) {
449 *p = NULL;
450 return 0;
451 }
452
453 /* uprog.len is unsigned short, so no overflow here */
454 len = uprog.len * sizeof(struct sock_filter);
455 code = kmalloc(len, GFP_KERNEL);
456 if (code == NULL)
457 return -ENOMEM;
458
459 if (copy_from_user(code, uprog.filter, len)) {
460 kfree(code);
461 return -EFAULT;
462 }
463
464 err = sk_chk_filter(code, uprog.len);
465 if (err) {
466 kfree(code);
467 return err;
468 }
469
470 *p = code;
471 return uprog.len;
472}
473
474/*
475 * ippp device ioctl
476 */
477int
478isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg)
479{
480 unsigned long val;
481 int r,i,j;
482 struct ippp_struct *is;
483 isdn_net_local *lp;
484 struct isdn_ppp_comp_data data;
485 void __user *argp = (void __user *)arg;
486
487 is = (struct ippp_struct *) file->private_data;
488 lp = is->lp;
489
490 if (is->debug & 0x1)
491 printk(KERN_DEBUG "isdn_ppp_ioctl: minor: %d cmd: %x state: %x\n", min, cmd, is->state);
492
493 if (!(is->state & IPPP_OPEN))
494 return -EINVAL;
495
496 switch (cmd) {
497 case PPPIOCBUNDLE:
498#ifdef CONFIG_ISDN_MPP
499 if (!(is->state & IPPP_CONNECT))
500 return -EINVAL;
501 if ((r = get_arg(argp, &val, sizeof(val) )))
502 return r;
503 printk(KERN_DEBUG "iPPP-bundle: minor: %d, slave unit: %d, master unit: %d\n",
504 (int) min, (int) is->unit, (int) val);
505 return isdn_ppp_bundle(is, val);
506#else
507 return -1;
508#endif
509 break;
510 case PPPIOCGUNIT: /* get ppp/isdn unit number */
511 if ((r = set_arg(argp, &is->unit, sizeof(is->unit) )))
512 return r;
513 break;
514 case PPPIOCGIFNAME:
515 if(!lp)
516 return -EINVAL;
517 if ((r = set_arg(argp, lp->name, strlen(lp->name))))
518 return r;
519 break;
520 case PPPIOCGMPFLAGS: /* get configuration flags */
521 if ((r = set_arg(argp, &is->mpppcfg, sizeof(is->mpppcfg) )))
522 return r;
523 break;
524 case PPPIOCSMPFLAGS: /* set configuration flags */
525 if ((r = get_arg(argp, &val, sizeof(val) )))
526 return r;
527 is->mpppcfg = val;
528 break;
529 case PPPIOCGFLAGS: /* get configuration flags */
530 if ((r = set_arg(argp, &is->pppcfg,sizeof(is->pppcfg) )))
531 return r;
532 break;
533 case PPPIOCSFLAGS: /* set configuration flags */
534 if ((r = get_arg(argp, &val, sizeof(val) ))) {
535 return r;
536 }
537 if (val & SC_ENABLE_IP && !(is->pppcfg & SC_ENABLE_IP) && (is->state & IPPP_CONNECT)) {
538 if (lp) {
539 /* OK .. we are ready to send buffers */
540 is->pppcfg = val; /* isdn_ppp_xmit test for SC_ENABLE_IP !!! */
541 netif_wake_queue(&lp->netdev->dev);
542 break;
543 }
544 }
545 is->pppcfg = val;
546 break;
547 case PPPIOCGIDLE: /* get idle time information */
548 if (lp) {
549 struct ppp_idle pidle;
550 pidle.xmit_idle = pidle.recv_idle = lp->huptimer;
551 if ((r = set_arg(argp, &pidle,sizeof(struct ppp_idle))))
552 return r;
553 }
554 break;
555 case PPPIOCSMRU: /* set receive unit size for PPP */
556 if ((r = get_arg(argp, &val, sizeof(val) )))
557 return r;
558 is->mru = val;
559 break;
560 case PPPIOCSMPMRU:
561 break;
562 case PPPIOCSMPMTU:
563 break;
564 case PPPIOCSMAXCID: /* set the maximum compression slot id */
565 if ((r = get_arg(argp, &val, sizeof(val) )))
566 return r;
567 val++;
568 if (is->maxcid != val) {
569#ifdef CONFIG_ISDN_PPP_VJ
570 struct slcompress *sltmp;
571#endif
572 if (is->debug & 0x1)
573 printk(KERN_DEBUG "ippp, ioctl: changed MAXCID to %ld\n", val);
574 is->maxcid = val;
575#ifdef CONFIG_ISDN_PPP_VJ
576 sltmp = slhc_init(16, val);
577 if (!sltmp) {
578 printk(KERN_ERR "ippp, can't realloc slhc struct\n");
579 return -ENOMEM;
580 }
581 if (is->slcomp)
582 slhc_free(is->slcomp);
583 is->slcomp = sltmp;
584#endif
585 }
586 break;
587 case PPPIOCGDEBUG:
588 if ((r = set_arg(argp, &is->debug, sizeof(is->debug) )))
589 return r;
590 break;
591 case PPPIOCSDEBUG:
592 if ((r = get_arg(argp, &val, sizeof(val) )))
593 return r;
594 is->debug = val;
595 break;
596 case PPPIOCGCOMPRESSORS:
597 {
598 unsigned long protos[8] = {0,};
599 struct isdn_ppp_compressor *ipc = ipc_head;
600 while(ipc) {
601 j = ipc->num / (sizeof(long)*8);
602 i = ipc->num % (sizeof(long)*8);
603 if(j < 8)
604 protos[j] |= (0x1<<i);
605 ipc = ipc->next;
606 }
607 if ((r = set_arg(argp,protos,8*sizeof(long) )))
608 return r;
609 }
610 break;
611 case PPPIOCSCOMPRESSOR:
612 if ((r = get_arg(argp, &data, sizeof(struct isdn_ppp_comp_data))))
613 return r;
614 return isdn_ppp_set_compressor(is, &data);
615 case PPPIOCGCALLINFO:
616 {
617 struct pppcallinfo pci;
618 memset((char *) &pci,0,sizeof(struct pppcallinfo));
619 if(lp)
620 {
621 strncpy(pci.local_num,lp->msn,63);
622 if(lp->dial) {
623 strncpy(pci.remote_num,lp->dial->num,63);
624 }
625 pci.charge_units = lp->charge;
626 if(lp->outgoing)
627 pci.calltype = CALLTYPE_OUTGOING;
628 else
629 pci.calltype = CALLTYPE_INCOMING;
630 if(lp->flags & ISDN_NET_CALLBACK)
631 pci.calltype |= CALLTYPE_CALLBACK;
632 }
633 return set_arg(argp,&pci,sizeof(struct pppcallinfo));
634 }
635#ifdef CONFIG_IPPP_FILTER
636 case PPPIOCSPASS:
637 {
638 struct sock_filter *code;
639 int len = get_filter(argp, &code);
640 if (len < 0)
641 return len;
642 kfree(is->pass_filter);
643 is->pass_filter = code;
644 is->pass_len = len;
645 break;
646 }
647 case PPPIOCSACTIVE:
648 {
649 struct sock_filter *code;
650 int len = get_filter(argp, &code);
651 if (len < 0)
652 return len;
653 kfree(is->active_filter);
654 is->active_filter = code;
655 is->active_len = len;
656 break;
657 }
658#endif /* CONFIG_IPPP_FILTER */
659 default:
660 break;
661 }
662 return 0;
663}
664
665unsigned int
666isdn_ppp_poll(struct file *file, poll_table * wait)
667{
668 u_int mask;
669 struct ippp_buf_queue *bf, *bl;
670 u_long flags;
671 struct ippp_struct *is;
672
673 is = file->private_data;
674
675 if (is->debug & 0x2)
676 printk(KERN_DEBUG "isdn_ppp_poll: minor: %d\n",
677 MINOR(file->f_dentry->d_inode->i_rdev));
678
679 /* just registers wait_queue hook. This doesn't really wait. */
680 poll_wait(file, &is->wq, wait);
681
682 if (!(is->state & IPPP_OPEN)) {
683 if(is->state == IPPP_CLOSEWAIT)
684 return POLLHUP;
685 printk(KERN_DEBUG "isdn_ppp: device not open\n");
686 return POLLERR;
687 }
688 /* we're always ready to send .. */
689 mask = POLLOUT | POLLWRNORM;
690
691 spin_lock_irqsave(&is->buflock, flags);
692 bl = is->last;
693 bf = is->first;
694 /*
695 * if IPPP_NOBLOCK is set we return even if we have nothing to read
696 */
697 if (bf->next != bl || (is->state & IPPP_NOBLOCK)) {
698 is->state &= ~IPPP_NOBLOCK;
699 mask |= POLLIN | POLLRDNORM;
700 }
701 spin_unlock_irqrestore(&is->buflock, flags);
702 return mask;
703}
704
705/*
706 * fill up isdn_ppp_read() queue ..
707 */
708
709static int
710isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot)
711{
712 struct ippp_buf_queue *bf, *bl;
713 u_long flags;
714 u_char *nbuf;
715 struct ippp_struct *is;
716
717 if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
718 printk(KERN_WARNING "ippp: illegal slot(%d).\n", slot);
719 return 0;
720 }
721 is = ippp_table[slot];
722
723 if (!(is->state & IPPP_CONNECT)) {
724 printk(KERN_DEBUG "ippp: device not activated.\n");
725 return 0;
726 }
727 nbuf = (unsigned char *) kmalloc(len + 4, GFP_ATOMIC);
728 if (!nbuf) {
729 printk(KERN_WARNING "ippp: Can't alloc buf\n");
730 return 0;
731 }
732 nbuf[0] = PPP_ALLSTATIONS;
733 nbuf[1] = PPP_UI;
734 nbuf[2] = proto >> 8;
735 nbuf[3] = proto & 0xff;
736 memcpy(nbuf + 4, buf, len);
737
738 spin_lock_irqsave(&is->buflock, flags);
739 bf = is->first;
740 bl = is->last;
741
742 if (bf == bl) {
743 printk(KERN_WARNING "ippp: Queue is full; discarding first buffer\n");
744 bf = bf->next;
745 kfree(bf->buf);
746 is->first = bf;
747 }
748 bl->buf = (char *) nbuf;
749 bl->len = len + 4;
750
751 is->last = bl->next;
752 spin_unlock_irqrestore(&is->buflock, flags);
753 wake_up_interruptible(&is->wq);
754 return len;
755}
756
757/*
758 * read() .. non-blocking: ipppd calls it only after select()
759 * reports, that there is data
760 */
761
762int
763isdn_ppp_read(int min, struct file *file, char __user *buf, int count)
764{
765 struct ippp_struct *is;
766 struct ippp_buf_queue *b;
767 u_long flags;
768 u_char *save_buf;
769
770 is = file->private_data;
771
772 if (!(is->state & IPPP_OPEN))
773 return 0;
774
775 if (!access_ok(VERIFY_WRITE, buf, count))
776 return -EFAULT;
777
778 spin_lock_irqsave(&is->buflock, flags);
779 b = is->first->next;
780 save_buf = b->buf;
781 if (!save_buf) {
782 spin_unlock_irqrestore(&is->buflock, flags);
783 return -EAGAIN;
784 }
785 if (b->len < count)
786 count = b->len;
787 b->buf = NULL;
788 is->first = b;
789
790 spin_unlock_irqrestore(&is->buflock, flags);
791 copy_to_user(buf, save_buf, count);
792 kfree(save_buf);
793
794 return count;
795}
796
797/*
798 * ipppd wanna write a packet to the card .. non-blocking
799 */
800
801int
802isdn_ppp_write(int min, struct file *file, const char __user *buf, int count)
803{
804 isdn_net_local *lp;
805 struct ippp_struct *is;
806 int proto;
807 unsigned char protobuf[4];
808
809 is = file->private_data;
810
811 if (!(is->state & IPPP_CONNECT))
812 return 0;
813
814 lp = is->lp;
815
816 /* -> push it directly to the lowlevel interface */
817
818 if (!lp)
819 printk(KERN_DEBUG "isdn_ppp_write: lp == NULL\n");
820 else {
821 /*
822 * Don't reset huptimer for
823 * LCP packets. (Echo requests).
824 */
825 if (copy_from_user(protobuf, buf, 4))
826 return -EFAULT;
827 proto = PPP_PROTOCOL(protobuf);
828 if (proto != PPP_LCP)
829 lp->huptimer = 0;
830
831 if (lp->isdn_device < 0 || lp->isdn_channel < 0)
832 return 0;
833
834 if ((dev->drv[lp->isdn_device]->flags & DRV_FLAG_RUNNING) &&
835 lp->dialstate == 0 &&
836 (lp->flags & ISDN_NET_CONNECTED)) {
837 unsigned short hl;
838 struct sk_buff *skb;
839 /*
840 * we need to reserve enought space in front of
841 * sk_buff. old call to dev_alloc_skb only reserved
842 * 16 bytes, now we are looking what the driver want
843 */
844 hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen;
845 skb = alloc_skb(hl+count, GFP_ATOMIC);
846 if (!skb) {
847 printk(KERN_WARNING "isdn_ppp_write: out of memory!\n");
848 return count;
849 }
850 skb_reserve(skb, hl);
851 if (copy_from_user(skb_put(skb, count), buf, count))
852 {
853 kfree_skb(skb);
854 return -EFAULT;
855 }
856 if (is->debug & 0x40) {
857 printk(KERN_DEBUG "ppp xmit: len %d\n", (int) skb->len);
858 isdn_ppp_frame_log("xmit", skb->data, skb->len, 32,is->unit,lp->ppp_slot);
859 }
860
861 isdn_ppp_send_ccp(lp->netdev,lp,skb); /* keeps CCP/compression states in sync */
862
863 isdn_net_write_super(lp, skb);
864 }
865 }
866 return count;
867}
868
869/*
870 * init memory, structures etc.
871 */
872
873int
874isdn_ppp_init(void)
875{
876 int i,
877 j;
878
879#ifdef CONFIG_ISDN_MPP
880 if( isdn_ppp_mp_bundle_array_init() < 0 )
881 return -ENOMEM;
882#endif /* CONFIG_ISDN_MPP */
883
884 for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
885 if (!(ippp_table[i] = (struct ippp_struct *)
886 kmalloc(sizeof(struct ippp_struct), GFP_KERNEL))) {
887 printk(KERN_WARNING "isdn_ppp_init: Could not alloc ippp_table\n");
888 for (j = 0; j < i; j++)
889 kfree(ippp_table[j]);
890 return -1;
891 }
892 memset((char *) ippp_table[i], 0, sizeof(struct ippp_struct));
893 spin_lock_init(&ippp_table[i]->buflock);
894 ippp_table[i]->state = 0;
895 ippp_table[i]->first = ippp_table[i]->rq + NUM_RCV_BUFFS - 1;
896 ippp_table[i]->last = ippp_table[i]->rq;
897
898 for (j = 0; j < NUM_RCV_BUFFS; j++) {
899 ippp_table[i]->rq[j].buf = NULL;
900 ippp_table[i]->rq[j].last = ippp_table[i]->rq +
901 (NUM_RCV_BUFFS + j - 1) % NUM_RCV_BUFFS;
902 ippp_table[i]->rq[j].next = ippp_table[i]->rq + (j + 1) % NUM_RCV_BUFFS;
903 }
904 }
905 return 0;
906}
907
908void
909isdn_ppp_cleanup(void)
910{
911 int i;
912
913 for (i = 0; i < ISDN_MAX_CHANNELS; i++)
914 kfree(ippp_table[i]);
915
916#ifdef CONFIG_ISDN_MPP
917 if (isdn_ppp_bundle_arr)
918 kfree(isdn_ppp_bundle_arr);
919#endif /* CONFIG_ISDN_MPP */
920
921}
922
923/*
924 * check for address/control field and skip if allowed
925 * retval != 0 -> discard packet silently
926 */
927static int isdn_ppp_skip_ac(struct ippp_struct *is, struct sk_buff *skb)
928{
929 if (skb->len < 1)
930 return -1;
931
932 if (skb->data[0] == 0xff) {
933 if (skb->len < 2)
934 return -1;
935
936 if (skb->data[1] != 0x03)
937 return -1;
938
939 // skip address/control (AC) field
940 skb_pull(skb, 2);
941 } else {
942 if (is->pppcfg & SC_REJ_COMP_AC)
943 // if AC compression was not negotiated, but used, discard packet
944 return -1;
945 }
946 return 0;
947}
948
949/*
950 * get the PPP protocol header and pull skb
951 * retval < 0 -> discard packet silently
952 */
953static int isdn_ppp_strip_proto(struct sk_buff *skb)
954{
955 int proto;
956
957 if (skb->len < 1)
958 return -1;
959
960 if (skb->data[0] & 0x1) {
961 // protocol field is compressed
962 proto = skb->data[0];
963 skb_pull(skb, 1);
964 } else {
965 if (skb->len < 2)
966 return -1;
967 proto = ((int) skb->data[0] << 8) + skb->data[1];
968 skb_pull(skb, 2);
969 }
970 return proto;
971}
972
973
974/*
975 * handler for incoming packets on a syncPPP interface
976 */
977void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *skb)
978{
979 struct ippp_struct *is;
980 int slot;
981 int proto;
982
983 if (net_dev->local->master)
984 BUG(); // we're called with the master device always
985
986 slot = lp->ppp_slot;
987 if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
988 printk(KERN_ERR "isdn_ppp_receive: lp->ppp_slot(%d)\n",
989 lp->ppp_slot);
990 kfree_skb(skb);
991 return;
992 }
993 is = ippp_table[slot];
994
995 if (is->debug & 0x4) {
996 printk(KERN_DEBUG "ippp_receive: is:%08lx lp:%08lx slot:%d unit:%d len:%d\n",
997 (long)is,(long)lp,lp->ppp_slot,is->unit,(int) skb->len);
998 isdn_ppp_frame_log("receive", skb->data, skb->len, 32,is->unit,lp->ppp_slot);
999 }
1000
1001 if (isdn_ppp_skip_ac(is, skb) < 0) {
1002 kfree_skb(skb);
1003 return;
1004 }
1005 proto = isdn_ppp_strip_proto(skb);
1006 if (proto < 0) {
1007 kfree_skb(skb);
1008 return;
1009 }
1010
1011#ifdef CONFIG_ISDN_MPP
1012 if (is->compflags & SC_LINK_DECOMP_ON) {
1013 skb = isdn_ppp_decompress(skb, is, NULL, &proto);
1014 if (!skb) // decompression error
1015 return;
1016 }
1017
1018 if (!(is->mpppcfg & SC_REJ_MP_PROT)) { // we agreed to receive MPPP
1019 if (proto == PPP_MP) {
1020 isdn_ppp_mp_receive(net_dev, lp, skb);
1021 return;
1022 }
1023 }
1024#endif
1025 isdn_ppp_push_higher(net_dev, lp, skb, proto);
1026}
1027
1028/*
1029 * we receive a reassembled frame, MPPP has been taken care of before.
1030 * address/control and protocol have been stripped from the skb
1031 * note: net_dev has to be master net_dev
1032 */
1033static void
1034isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *skb, int proto)
1035{
1036 struct net_device *dev = &net_dev->dev;
1037 struct ippp_struct *is, *mis;
1038 isdn_net_local *mlp = NULL;
1039 int slot;
1040
1041 slot = lp->ppp_slot;
1042 if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
1043 printk(KERN_ERR "isdn_ppp_push_higher: lp->ppp_slot(%d)\n",
1044 lp->ppp_slot);
1045 goto drop_packet;
1046 }
1047 is = ippp_table[slot];
1048
1049 if (lp->master) { // FIXME?
1050 mlp = (isdn_net_local *) lp->master->priv;
1051 slot = mlp->ppp_slot;
1052 if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
1053 printk(KERN_ERR "isdn_ppp_push_higher: master->ppp_slot(%d)\n",
1054 lp->ppp_slot);
1055 goto drop_packet;
1056 }
1057 }
1058 mis = ippp_table[slot];
1059
1060 if (is->debug & 0x10) {
1061 printk(KERN_DEBUG "push, skb %d %04x\n", (int) skb->len, proto);
1062 isdn_ppp_frame_log("rpush", skb->data, skb->len, 32,is->unit,lp->ppp_slot);
1063 }
1064 if (mis->compflags & SC_DECOMP_ON) {
1065 skb = isdn_ppp_decompress(skb, is, mis, &proto);
1066 if (!skb) // decompression error
1067 return;
1068 }
1069 switch (proto) {
1070 case PPP_IPX: /* untested */
1071 if (is->debug & 0x20)
1072 printk(KERN_DEBUG "isdn_ppp: IPX\n");
1073 skb->protocol = htons(ETH_P_IPX);
1074 break;
1075 case PPP_IP:
1076 if (is->debug & 0x20)
1077 printk(KERN_DEBUG "isdn_ppp: IP\n");
1078 skb->protocol = htons(ETH_P_IP);
1079 break;
1080 case PPP_COMP:
1081 case PPP_COMPFRAG:
1082 printk(KERN_INFO "isdn_ppp: unexpected compressed frame dropped\n");
1083 goto drop_packet;
1084#ifdef CONFIG_ISDN_PPP_VJ
1085 case PPP_VJC_UNCOMP:
1086 if (is->debug & 0x20)
1087 printk(KERN_DEBUG "isdn_ppp: VJC_UNCOMP\n");
1088 if (net_dev->local->ppp_slot < 0) {
1089 printk(KERN_ERR "%s: net_dev->local->ppp_slot(%d) out of range\n",
1090 __FUNCTION__, net_dev->local->ppp_slot);
1091 goto drop_packet;
1092 }
1093 if (slhc_remember(ippp_table[net_dev->local->ppp_slot]->slcomp, skb->data, skb->len) <= 0) {
1094 printk(KERN_WARNING "isdn_ppp: received illegal VJC_UNCOMP frame!\n");
1095 goto drop_packet;
1096 }
1097 skb->protocol = htons(ETH_P_IP);
1098 break;
1099 case PPP_VJC_COMP:
1100 if (is->debug & 0x20)
1101 printk(KERN_DEBUG "isdn_ppp: VJC_COMP\n");
1102 {
1103 struct sk_buff *skb_old = skb;
1104 int pkt_len;
1105 skb = dev_alloc_skb(skb_old->len + 128);
1106
1107 if (!skb) {
1108 printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name);
1109 skb = skb_old;
1110 goto drop_packet;
1111 }
1112 skb_put(skb, skb_old->len + 128);
1113 memcpy(skb->data, skb_old->data, skb_old->len);
1114 if (net_dev->local->ppp_slot < 0) {
1115 printk(KERN_ERR "%s: net_dev->local->ppp_slot(%d) out of range\n",
1116 __FUNCTION__, net_dev->local->ppp_slot);
1117 goto drop_packet;
1118 }
1119 pkt_len = slhc_uncompress(ippp_table[net_dev->local->ppp_slot]->slcomp,
1120 skb->data, skb_old->len);
1121 kfree_skb(skb_old);
1122 if (pkt_len < 0)
1123 goto drop_packet;
1124
1125 skb_trim(skb, pkt_len);
1126 skb->protocol = htons(ETH_P_IP);
1127 }
1128 break;
1129#endif
1130 case PPP_CCP:
1131 case PPP_CCPFRAG:
1132 isdn_ppp_receive_ccp(net_dev,lp,skb,proto);
1133 /* Dont pop up ResetReq/Ack stuff to the daemon any
1134 longer - the job is done already */
1135 if(skb->data[0] == CCP_RESETREQ ||
1136 skb->data[0] == CCP_RESETACK)
1137 break;
1138 /* fall through */
1139 default:
1140 isdn_ppp_fill_rq(skb->data, skb->len, proto, lp->ppp_slot); /* push data to pppd device */
1141 kfree_skb(skb);
1142 return;
1143 }
1144
1145#ifdef CONFIG_IPPP_FILTER
1146 /* check if the packet passes the pass and active filters
1147 * the filter instructions are constructed assuming
1148 * a four-byte PPP header on each packet (which is still present) */
1149 skb_push(skb, 4);
1150
1151 {
1152 u_int16_t *p = (u_int16_t *) skb->data;
1153
1154 *p = 0; /* indicate inbound in DLT_LINUX_SLL */
1155 }
1156
1157 if (is->pass_filter
1158 && sk_run_filter(skb, is->pass_filter, is->pass_len) == 0) {
1159 if (is->debug & 0x2)
1160 printk(KERN_DEBUG "IPPP: inbound frame filtered.\n");
1161 kfree_skb(skb);
1162 return;
1163 }
1164 if (!(is->active_filter
1165 && sk_run_filter(skb, is->active_filter,
1166 is->active_len) == 0)) {
1167 if (is->debug & 0x2)
1168 printk(KERN_DEBUG "IPPP: link-active filter: reseting huptimer.\n");
1169 lp->huptimer = 0;
1170 if (mlp)
1171 mlp->huptimer = 0;
1172 }
1173 skb_pull(skb, 4);
1174#else /* CONFIG_IPPP_FILTER */
1175 lp->huptimer = 0;
1176 if (mlp)
1177 mlp->huptimer = 0;
1178#endif /* CONFIG_IPPP_FILTER */
1179 skb->dev = dev;
1180 skb->input_dev = dev;
1181 skb->mac.raw = skb->data;
1182 netif_rx(skb);
1183 /* net_dev->local->stats.rx_packets++; done in isdn_net.c */
1184 return;
1185
1186 drop_packet:
1187 net_dev->local->stats.rx_dropped++;
1188 kfree_skb(skb);
1189}
1190
1191/*
1192 * isdn_ppp_skb_push ..
1193 * checks whether we have enough space at the beginning of the skb
1194 * and allocs a new SKB if necessary
1195 */
1196static unsigned char *isdn_ppp_skb_push(struct sk_buff **skb_p,int len)
1197{
1198 struct sk_buff *skb = *skb_p;
1199
1200 if(skb_headroom(skb) < len) {
1201 struct sk_buff *nskb = skb_realloc_headroom(skb, len);
1202
1203 if (!nskb) {
1204 printk(KERN_ERR "isdn_ppp_skb_push: can't realloc headroom!\n");
1205 dev_kfree_skb(skb);
1206 return NULL;
1207 }
1208 printk(KERN_DEBUG "isdn_ppp_skb_push:under %d %d\n",skb_headroom(skb),len);
1209 dev_kfree_skb(skb);
1210 *skb_p = nskb;
1211 return skb_push(nskb, len);
1212 }
1213 return skb_push(skb,len);
1214}
1215
1216/*
1217 * send ppp frame .. we expect a PIDCOMPressable proto --
1218 * (here: currently always PPP_IP,PPP_VJC_COMP,PPP_VJC_UNCOMP)
1219 *
1220 * VJ compression may change skb pointer!!! .. requeue with old
1221 * skb isn't allowed!!
1222 */
1223
1224int
1225isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev)
1226{
1227 isdn_net_local *lp,*mlp;
1228 isdn_net_dev *nd;
1229 unsigned int proto = PPP_IP; /* 0x21 */
1230 struct ippp_struct *ipt,*ipts;
1231 int slot, retval = 0;
1232
1233 mlp = (isdn_net_local *) (netdev->priv);
1234 nd = mlp->netdev; /* get master lp */
1235
1236 slot = mlp->ppp_slot;
1237 if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
1238 printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot(%d)\n",
1239 mlp->ppp_slot);
1240 kfree_skb(skb);
1241 goto out;
1242 }
1243 ipts = ippp_table[slot];
1244
1245 if (!(ipts->pppcfg & SC_ENABLE_IP)) { /* PPP connected ? */
1246 if (ipts->debug & 0x1)
1247 printk(KERN_INFO "%s: IP frame delayed.\n", netdev->name);
1248 retval = 1;
1249 goto out;
1250 }
1251
1252 switch (ntohs(skb->protocol)) {
1253 case ETH_P_IP:
1254 proto = PPP_IP;
1255 break;
1256 case ETH_P_IPX:
1257 proto = PPP_IPX; /* untested */
1258 break;
1259 default:
1260 printk(KERN_ERR "isdn_ppp: skipped unsupported protocol: %#x.\n",
1261 skb->protocol);
1262 dev_kfree_skb(skb);
1263 goto out;
1264 }
1265
1266 lp = isdn_net_get_locked_lp(nd);
1267 if (!lp) {
1268 printk(KERN_WARNING "%s: all channels busy - requeuing!\n", netdev->name);
1269 retval = 1;
1270 goto out;
1271 }
1272 /* we have our lp locked from now on */
1273
1274 slot = lp->ppp_slot;
1275 if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
1276 printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot(%d)\n",
1277 lp->ppp_slot);
1278 kfree_skb(skb);
1279 goto unlock;
1280 }
1281 ipt = ippp_table[slot];
1282
1283 /*
1284 * after this line .. requeueing in the device queue is no longer allowed!!!
1285 */
1286
1287 /* Pull off the fake header we stuck on earlier to keep
1288 * the fragmentation code happy.
1289 */
1290 skb_pull(skb,IPPP_MAX_HEADER);
1291
1292#ifdef CONFIG_IPPP_FILTER
1293 /* check if we should pass this packet
1294 * the filter instructions are constructed assuming
1295 * a four-byte PPP header on each packet */
1296 skb_push(skb, 4);
1297
1298 {
1299 u_int16_t *p = (u_int16_t *) skb->data;
1300
1301 *p++ = htons(4); /* indicate outbound in DLT_LINUX_SLL */
1302 *p = htons(proto);
1303 }
1304
1305 if (ipt->pass_filter
1306 && sk_run_filter(skb, ipt->pass_filter, ipt->pass_len) == 0) {
1307 if (ipt->debug & 0x4)
1308 printk(KERN_DEBUG "IPPP: outbound frame filtered.\n");
1309 kfree_skb(skb);
1310 goto unlock;
1311 }
1312 if (!(ipt->active_filter
1313 && sk_run_filter(skb, ipt->active_filter,
1314 ipt->active_len) == 0)) {
1315 if (ipt->debug & 0x4)
1316 printk(KERN_DEBUG "IPPP: link-active filter: reseting huptimer.\n");
1317 lp->huptimer = 0;
1318 }
1319 skb_pull(skb, 4);
1320#else /* CONFIG_IPPP_FILTER */
1321 lp->huptimer = 0;
1322#endif /* CONFIG_IPPP_FILTER */
1323
1324 if (ipt->debug & 0x4)
1325 printk(KERN_DEBUG "xmit skb, len %d\n", (int) skb->len);
1326 if (ipts->debug & 0x40)
1327 isdn_ppp_frame_log("xmit0", skb->data, skb->len, 32,ipts->unit,lp->ppp_slot);
1328
1329#ifdef CONFIG_ISDN_PPP_VJ
1330 if (proto == PPP_IP && ipts->pppcfg & SC_COMP_TCP) { /* ipts here? probably yes, but check this again */
1331 struct sk_buff *new_skb;
1332 unsigned short hl;
1333 /*
1334 * we need to reserve enought space in front of
1335 * sk_buff. old call to dev_alloc_skb only reserved
1336 * 16 bytes, now we are looking what the driver want.
1337 */
1338 hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen + IPPP_MAX_HEADER;
1339 /*
1340 * Note: hl might still be insufficient because the method
1341 * above does not account for a possibible MPPP slave channel
1342 * which had larger HL header space requirements than the
1343 * master.
1344 */
1345 new_skb = alloc_skb(hl+skb->len, GFP_ATOMIC);
1346 if (new_skb) {
1347 u_char *buf;
1348 int pktlen;
1349
1350 skb_reserve(new_skb, hl);
1351 new_skb->dev = skb->dev;
1352 skb_put(new_skb, skb->len);
1353 buf = skb->data;
1354
1355 pktlen = slhc_compress(ipts->slcomp, skb->data, skb->len, new_skb->data,
1356 &buf, !(ipts->pppcfg & SC_NO_TCP_CCID));
1357
1358 if (buf != skb->data) {
1359 if (new_skb->data != buf)
1360 printk(KERN_ERR "isdn_ppp: FATAL error after slhc_compress!!\n");
1361 dev_kfree_skb(skb);
1362 skb = new_skb;
1363 } else {
1364 dev_kfree_skb(new_skb);
1365 }
1366
1367 skb_trim(skb, pktlen);
1368 if (skb->data[0] & SL_TYPE_COMPRESSED_TCP) { /* cslip? style -> PPP */
1369 proto = PPP_VJC_COMP;
1370 skb->data[0] ^= SL_TYPE_COMPRESSED_TCP;
1371 } else {
1372 if (skb->data[0] >= SL_TYPE_UNCOMPRESSED_TCP)
1373 proto = PPP_VJC_UNCOMP;
1374 skb->data[0] = (skb->data[0] & 0x0f) | 0x40;
1375 }
1376 }
1377 }
1378#endif
1379
1380 /*
1381 * normal (single link) or bundle compression
1382 */
1383 if(ipts->compflags & SC_COMP_ON) {
1384 /* We send compressed only if both down- und upstream
1385 compression is negotiated, that means, CCP is up */
1386 if(ipts->compflags & SC_DECOMP_ON) {
1387 skb = isdn_ppp_compress(skb,&proto,ipt,ipts,0);
1388 } else {
1389 printk(KERN_DEBUG "isdn_ppp: CCP not yet up - sending as-is\n");
1390 }
1391 }
1392
1393 if (ipt->debug & 0x24)
1394 printk(KERN_DEBUG "xmit2 skb, len %d, proto %04x\n", (int) skb->len, proto);
1395
1396#ifdef CONFIG_ISDN_MPP
1397 if (ipt->mpppcfg & SC_MP_PROT) {
1398 /* we get mp_seqno from static isdn_net_local */
1399 long mp_seqno = ipts->mp_seqno;
1400 ipts->mp_seqno++;
1401 if (ipt->mpppcfg & SC_OUT_SHORT_SEQ) {
1402 unsigned char *data = isdn_ppp_skb_push(&skb, 3);
1403 if(!data)
1404 goto unlock;
1405 mp_seqno &= 0xfff;
1406 data[0] = MP_BEGIN_FRAG | MP_END_FRAG | ((mp_seqno >> 8) & 0xf); /* (B)egin & (E)ndbit .. */
1407 data[1] = mp_seqno & 0xff;
1408 data[2] = proto; /* PID compression */
1409 } else {
1410 unsigned char *data = isdn_ppp_skb_push(&skb, 5);
1411 if(!data)
1412 goto unlock;
1413 data[0] = MP_BEGIN_FRAG | MP_END_FRAG; /* (B)egin & (E)ndbit .. */
1414 data[1] = (mp_seqno >> 16) & 0xff; /* sequence number: 24bit */
1415 data[2] = (mp_seqno >> 8) & 0xff;
1416 data[3] = (mp_seqno >> 0) & 0xff;
1417 data[4] = proto; /* PID compression */
1418 }
1419 proto = PPP_MP; /* MP Protocol, 0x003d */
1420 }
1421#endif
1422
1423 /*
1424 * 'link in bundle' compression ...
1425 */
1426 if(ipt->compflags & SC_LINK_COMP_ON)
1427 skb = isdn_ppp_compress(skb,&proto,ipt,ipts,1);
1428
1429 if( (ipt->pppcfg & SC_COMP_PROT) && (proto <= 0xff) ) {
1430 unsigned char *data = isdn_ppp_skb_push(&skb,1);
1431 if(!data)
1432 goto unlock;
1433 data[0] = proto & 0xff;
1434 }
1435 else {
1436 unsigned char *data = isdn_ppp_skb_push(&skb,2);
1437 if(!data)
1438 goto unlock;
1439 data[0] = (proto >> 8) & 0xff;
1440 data[1] = proto & 0xff;
1441 }
1442 if(!(ipt->pppcfg & SC_COMP_AC)) {
1443 unsigned char *data = isdn_ppp_skb_push(&skb,2);
1444 if(!data)
1445 goto unlock;
1446 data[0] = 0xff; /* All Stations */
1447 data[1] = 0x03; /* Unnumbered information */
1448 }
1449
1450 /* tx-stats are now updated via BSENT-callback */
1451
1452 if (ipts->debug & 0x40) {
1453 printk(KERN_DEBUG "skb xmit: len: %d\n", (int) skb->len);
1454 isdn_ppp_frame_log("xmit", skb->data, skb->len, 32,ipt->unit,lp->ppp_slot);
1455 }
1456
1457 isdn_net_writebuf_skb(lp, skb);
1458
1459 unlock:
1460 spin_unlock_bh(&lp->xmit_lock);
1461 out:
1462 return retval;
1463}
1464
1465#ifdef CONFIG_IPPP_FILTER
1466/*
1467 * check if this packet may trigger auto-dial.
1468 */
1469
1470int isdn_ppp_autodial_filter(struct sk_buff *skb, isdn_net_local *lp)
1471{
1472 struct ippp_struct *is = ippp_table[lp->ppp_slot];
1473 u_int16_t proto;
1474 int drop = 0;
1475
1476 switch (ntohs(skb->protocol)) {
1477 case ETH_P_IP:
1478 proto = PPP_IP;
1479 break;
1480 case ETH_P_IPX:
1481 proto = PPP_IPX;
1482 break;
1483 default:
1484 printk(KERN_ERR "isdn_ppp_autodial_filter: unsupported protocol 0x%x.\n",
1485 skb->protocol);
1486 return 1;
1487 }
1488
1489 /* the filter instructions are constructed assuming
1490 * a four-byte PPP header on each packet. we have to
1491 * temporarily remove part of the fake header stuck on
1492 * earlier.
1493 */
1494 skb_pull(skb, IPPP_MAX_HEADER - 4);
1495
1496 {
1497 u_int16_t *p = (u_int16_t *) skb->data;
1498
1499 *p++ = htons(4); /* indicate outbound in DLT_LINUX_SLL */
1500 *p = htons(proto);
1501 }
1502
1503 drop |= is->pass_filter
1504 && sk_run_filter(skb, is->pass_filter, is->pass_len) == 0;
1505 drop |= is->active_filter
1506 && sk_run_filter(skb, is->active_filter, is->active_len) == 0;
1507
1508 skb_push(skb, IPPP_MAX_HEADER - 4);
1509 return drop;
1510}
1511#endif
1512#ifdef CONFIG_ISDN_MPP
1513
1514/* this is _not_ rfc1990 header, but something we convert both short and long
1515 * headers to for convinience's sake:
1516 * byte 0 is flags as in rfc1990
1517 * bytes 1...4 is 24-bit seqence number converted to host byte order
1518 */
1519#define MP_HEADER_LEN 5
1520
1521#define MP_LONGSEQ_MASK 0x00ffffff
1522#define MP_SHORTSEQ_MASK 0x00000fff
1523#define MP_LONGSEQ_MAX MP_LONGSEQ_MASK
1524#define MP_SHORTSEQ_MAX MP_SHORTSEQ_MASK
1525#define MP_LONGSEQ_MAXBIT ((MP_LONGSEQ_MASK+1)>>1)
1526#define MP_SHORTSEQ_MAXBIT ((MP_SHORTSEQ_MASK+1)>>1)
1527
1528/* sequence-wrap safe comparisions (for long sequence)*/
1529#define MP_LT(a,b) ((a-b)&MP_LONGSEQ_MAXBIT)
1530#define MP_LE(a,b) !((b-a)&MP_LONGSEQ_MAXBIT)
1531#define MP_GT(a,b) ((b-a)&MP_LONGSEQ_MAXBIT)
1532#define MP_GE(a,b) !((a-b)&MP_LONGSEQ_MAXBIT)
1533
1534#define MP_SEQ(f) ((*(u32*)(f->data+1)))
1535#define MP_FLAGS(f) (f->data[0])
1536
1537static int isdn_ppp_mp_bundle_array_init(void)
1538{
1539 int i;
1540 int sz = ISDN_MAX_CHANNELS*sizeof(ippp_bundle);
1541 if( (isdn_ppp_bundle_arr = (ippp_bundle*)kmalloc(sz,
1542 GFP_KERNEL)) == NULL )
1543 return -ENOMEM;
1544 memset(isdn_ppp_bundle_arr, 0, sz);
1545 for( i = 0; i < ISDN_MAX_CHANNELS; i++ )
1546 spin_lock_init(&isdn_ppp_bundle_arr[i].lock);
1547 return 0;
1548}
1549
1550static ippp_bundle * isdn_ppp_mp_bundle_alloc(void)
1551{
1552 int i;
1553 for( i = 0; i < ISDN_MAX_CHANNELS; i++ )
1554 if (isdn_ppp_bundle_arr[i].ref_ct <= 0)
1555 return (isdn_ppp_bundle_arr + i);
1556 return NULL;
1557}
1558
1559static int isdn_ppp_mp_init( isdn_net_local * lp, ippp_bundle * add_to )
1560{
1561 struct ippp_struct * is;
1562
1563 if (lp->ppp_slot < 0) {
1564 printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n",
1565 __FUNCTION__, lp->ppp_slot);
1566 return(-EINVAL);
1567 }
1568
1569 is = ippp_table[lp->ppp_slot];
1570 if (add_to) {
1571 if( lp->netdev->pb )
1572 lp->netdev->pb->ref_ct--;
1573 lp->netdev->pb = add_to;
1574 } else { /* first link in a bundle */
1575 is->mp_seqno = 0;
1576 if ((lp->netdev->pb = isdn_ppp_mp_bundle_alloc()) == NULL)
1577 return -ENOMEM;
1578 lp->next = lp->last = lp; /* nobody else in a queue */
1579 lp->netdev->pb->frags = NULL;
1580 lp->netdev->pb->frames = 0;
1581 lp->netdev->pb->seq = UINT_MAX;
1582 }
1583 lp->netdev->pb->ref_ct++;
1584
1585 is->last_link_seqno = 0;
1586 return 0;
1587}
1588
1589static u32 isdn_ppp_mp_get_seq( int short_seq,
1590 struct sk_buff * skb, u32 last_seq );
1591static struct sk_buff * isdn_ppp_mp_discard( ippp_bundle * mp,
1592 struct sk_buff * from, struct sk_buff * to );
1593static void isdn_ppp_mp_reassembly( isdn_net_dev * net_dev, isdn_net_local * lp,
1594 struct sk_buff * from, struct sk_buff * to );
1595static void isdn_ppp_mp_free_skb( ippp_bundle * mp, struct sk_buff * skb );
1596static void isdn_ppp_mp_print_recv_pkt( int slot, struct sk_buff * skb );
1597
1598static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp,
1599 struct sk_buff *skb)
1600{
1601 struct ippp_struct *is;
1602 isdn_net_local * lpq;
1603 ippp_bundle * mp;
1604 isdn_mppp_stats * stats;
1605 struct sk_buff * newfrag, * frag, * start, *nextf;
1606 u32 newseq, minseq, thisseq;
1607 unsigned long flags;
1608 int slot;
1609
1610 spin_lock_irqsave(&net_dev->pb->lock, flags);
1611 mp = net_dev->pb;
1612 stats = &mp->stats;
1613 slot = lp->ppp_slot;
1614 if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
1615 printk(KERN_ERR "%s: lp->ppp_slot(%d)\n",
1616 __FUNCTION__, lp->ppp_slot);
1617 stats->frame_drops++;
1618 dev_kfree_skb(skb);
1619 spin_unlock_irqrestore(&mp->lock, flags);
1620 return;
1621 }
1622 is = ippp_table[slot];
1623 if( ++mp->frames > stats->max_queue_len )
1624 stats->max_queue_len = mp->frames;
1625
1626 if (is->debug & 0x8)
1627 isdn_ppp_mp_print_recv_pkt(lp->ppp_slot, skb);
1628
1629 newseq = isdn_ppp_mp_get_seq(is->mpppcfg & SC_IN_SHORT_SEQ,
1630 skb, is->last_link_seqno);
1631
1632
1633 /* if this packet seq # is less than last already processed one,
1634 * toss it right away, but check for sequence start case first
1635 */
1636 if( mp->seq > MP_LONGSEQ_MAX && (newseq & MP_LONGSEQ_MAXBIT) ) {
1637 mp->seq = newseq; /* the first packet: required for
1638 * rfc1990 non-compliant clients --
1639 * prevents constant packet toss */
1640 } else if( MP_LT(newseq, mp->seq) ) {
1641 stats->frame_drops++;
1642 isdn_ppp_mp_free_skb(mp, skb);
1643 spin_unlock_irqrestore(&mp->lock, flags);
1644 return;
1645 }
1646
1647 /* find the minimum received sequence number over all links */
1648 is->last_link_seqno = minseq = newseq;
1649 for (lpq = net_dev->queue;;) {
1650 slot = lpq->ppp_slot;
1651 if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
1652 printk(KERN_ERR "%s: lpq->ppp_slot(%d)\n",
1653 __FUNCTION__, lpq->ppp_slot);
1654 } else {
1655 u32 lls = ippp_table[slot]->last_link_seqno;
1656 if (MP_LT(lls, minseq))
1657 minseq = lls;
1658 }
1659 if ((lpq = lpq->next) == net_dev->queue)
1660 break;
1661 }
1662 if (MP_LT(minseq, mp->seq))
1663 minseq = mp->seq; /* can't go beyond already processed
1664 * packets */
1665 newfrag = skb;
1666
1667 /* if this new fragment is before the first one, then enqueue it now. */
1668 if ((frag = mp->frags) == NULL || MP_LT(newseq, MP_SEQ(frag))) {
1669 newfrag->next = frag;
1670 mp->frags = frag = newfrag;
1671 newfrag = NULL;
1672 }
1673
1674 start = MP_FLAGS(frag) & MP_BEGIN_FRAG &&
1675 MP_SEQ(frag) == mp->seq ? frag : NULL;
1676
1677 /*
1678 * main fragment traversing loop
1679 *
1680 * try to accomplish several tasks:
1681 * - insert new fragment into the proper sequence slot (once that's done
1682 * newfrag will be set to NULL)
1683 * - reassemble any complete fragment sequence (non-null 'start'
1684 * indicates there is a continguous sequence present)
1685 * - discard any incomplete sequences that are below minseq -- due
1686 * to the fact that sender always increment sequence number, if there
1687 * is an incomplete sequence below minseq, no new fragments would
1688 * come to complete such sequence and it should be discarded
1689 *
1690 * loop completes when we accomplished the following tasks:
1691 * - new fragment is inserted in the proper sequence ('newfrag' is
1692 * set to NULL)
1693 * - we hit a gap in the sequence, so no reassembly/processing is
1694 * possible ('start' would be set to NULL)
1695 *
1696 * algorightm for this code is derived from code in the book
1697 * 'PPP Design And Debugging' by James Carlson (Addison-Wesley)
1698 */
1699 while (start != NULL || newfrag != NULL) {
1700
1701 thisseq = MP_SEQ(frag);
1702 nextf = frag->next;
1703
1704 /* drop any duplicate fragments */
1705 if (newfrag != NULL && thisseq == newseq) {
1706 isdn_ppp_mp_free_skb(mp, newfrag);
1707 newfrag = NULL;
1708 }
1709
1710 /* insert new fragment before next element if possible. */
1711 if (newfrag != NULL && (nextf == NULL ||
1712 MP_LT(newseq, MP_SEQ(nextf)))) {
1713 newfrag->next = nextf;
1714 frag->next = nextf = newfrag;
1715 newfrag = NULL;
1716 }
1717
1718 if (start != NULL) {
1719 /* check for misplaced start */
1720 if (start != frag && (MP_FLAGS(frag) & MP_BEGIN_FRAG)) {
1721 printk(KERN_WARNING"isdn_mppp(seq %d): new "
1722 "BEGIN flag with no prior END", thisseq);
1723 stats->seqerrs++;
1724 stats->frame_drops++;
1725 start = isdn_ppp_mp_discard(mp, start,frag);
1726 nextf = frag->next;
1727 }
1728 } else if (MP_LE(thisseq, minseq)) {
1729 if (MP_FLAGS(frag) & MP_BEGIN_FRAG)
1730 start = frag;
1731 else {
1732 if (MP_FLAGS(frag) & MP_END_FRAG)
1733 stats->frame_drops++;
1734 if( mp->frags == frag )
1735 mp->frags = nextf;
1736 isdn_ppp_mp_free_skb(mp, frag);
1737 frag = nextf;
1738 continue;
1739 }
1740 }
1741
1742 /* if start is non-null and we have end fragment, then
1743 * we have full reassembly sequence -- reassemble
1744 * and process packet now
1745 */
1746 if (start != NULL && (MP_FLAGS(frag) & MP_END_FRAG)) {
1747 minseq = mp->seq = (thisseq+1) & MP_LONGSEQ_MASK;
1748 /* Reassemble the packet then dispatch it */
1749 isdn_ppp_mp_reassembly(net_dev, lp, start, nextf);
1750
1751 start = NULL;
1752 frag = NULL;
1753
1754 mp->frags = nextf;
1755 }
1756
1757 /* check if need to update start pointer: if we just
1758 * reassembled the packet and sequence is contiguous
1759 * then next fragment should be the start of new reassembly
1760 * if sequence is contiguous, but we haven't reassembled yet,
1761 * keep going.
1762 * if sequence is not contiguous, either clear everyting
1763 * below low watermark and set start to the next frag or
1764 * clear start ptr.
1765 */
1766 if (nextf != NULL &&
1767 ((thisseq+1) & MP_LONGSEQ_MASK) == MP_SEQ(nextf)) {
1768 /* if we just reassembled and the next one is here,
1769 * then start another reassembly. */
1770
1771 if (frag == NULL) {
1772 if (MP_FLAGS(nextf) & MP_BEGIN_FRAG)
1773 start = nextf;
1774 else
1775 {
1776 printk(KERN_WARNING"isdn_mppp(seq %d):"
1777 " END flag with no following "
1778 "BEGIN", thisseq);
1779 stats->seqerrs++;
1780 }
1781 }
1782
1783 } else {
1784 if ( nextf != NULL && frag != NULL &&
1785 MP_LT(thisseq, minseq)) {
1786 /* we've got a break in the sequence
1787 * and we not at the end yet
1788 * and we did not just reassembled
1789 *(if we did, there wouldn't be anything before)
1790 * and we below the low watermark
1791 * discard all the frames below low watermark
1792 * and start over */
1793 stats->frame_drops++;
1794 mp->frags = isdn_ppp_mp_discard(mp,start,nextf);
1795 }
1796 /* break in the sequence, no reassembly */
1797 start = NULL;
1798 }
1799
1800 frag = nextf;
1801 } /* while -- main loop */
1802
1803 if (mp->frags == NULL)
1804 mp->frags = frag;
1805
1806 /* rather straighforward way to deal with (not very) possible
1807 * queue overflow */
1808 if (mp->frames > MP_MAX_QUEUE_LEN) {
1809 stats->overflows++;
1810 while (mp->frames > MP_MAX_QUEUE_LEN) {
1811 frag = mp->frags->next;
1812 isdn_ppp_mp_free_skb(mp, mp->frags);
1813 mp->frags = frag;
1814 }
1815 }
1816 spin_unlock_irqrestore(&mp->lock, flags);
1817}
1818
1819static void isdn_ppp_mp_cleanup( isdn_net_local * lp )
1820{
1821 struct sk_buff * frag = lp->netdev->pb->frags;
1822 struct sk_buff * nextfrag;
1823 while( frag ) {
1824 nextfrag = frag->next;
1825 isdn_ppp_mp_free_skb(lp->netdev->pb, frag);
1826 frag = nextfrag;
1827 }
1828 lp->netdev->pb->frags = NULL;
1829}
1830
1831static u32 isdn_ppp_mp_get_seq( int short_seq,
1832 struct sk_buff * skb, u32 last_seq )
1833{
1834 u32 seq;
1835 int flags = skb->data[0] & (MP_BEGIN_FRAG | MP_END_FRAG);
1836
1837 if( !short_seq )
1838 {
1839 seq = ntohl(*(u32*)skb->data) & MP_LONGSEQ_MASK;
1840 skb_push(skb,1);
1841 }
1842 else
1843 {
1844 /* convert 12-bit short seq number to 24-bit long one
1845 */
1846 seq = ntohs(*(u16*)skb->data) & MP_SHORTSEQ_MASK;
1847
1848 /* check for seqence wrap */
1849 if( !(seq & MP_SHORTSEQ_MAXBIT) &&
1850 (last_seq & MP_SHORTSEQ_MAXBIT) &&
1851 (unsigned long)last_seq <= MP_LONGSEQ_MAX )
1852 seq |= (last_seq + MP_SHORTSEQ_MAX+1) &
1853 (~MP_SHORTSEQ_MASK & MP_LONGSEQ_MASK);
1854 else
1855 seq |= last_seq & (~MP_SHORTSEQ_MASK & MP_LONGSEQ_MASK);
1856
1857 skb_push(skb, 3); /* put converted seqence back in skb */
1858 }
1859 *(u32*)(skb->data+1) = seq; /* put seqence back in _host_ byte
1860 * order */
1861 skb->data[0] = flags; /* restore flags */
1862 return seq;
1863}
1864
1865struct sk_buff * isdn_ppp_mp_discard( ippp_bundle * mp,
1866 struct sk_buff * from, struct sk_buff * to )
1867{
1868 if( from )
1869 while (from != to) {
1870 struct sk_buff * next = from->next;
1871 isdn_ppp_mp_free_skb(mp, from);
1872 from = next;
1873 }
1874 return from;
1875}
1876
1877void isdn_ppp_mp_reassembly( isdn_net_dev * net_dev, isdn_net_local * lp,
1878 struct sk_buff * from, struct sk_buff * to )
1879{
1880 ippp_bundle * mp = net_dev->pb;
1881 int proto;
1882 struct sk_buff * skb;
1883 unsigned int tot_len;
1884
1885 if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {
1886 printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n",
1887 __FUNCTION__, lp->ppp_slot);
1888 return;
1889 }
1890 if( MP_FLAGS(from) == (MP_BEGIN_FRAG | MP_END_FRAG) ) {
1891 if( ippp_table[lp->ppp_slot]->debug & 0x40 )
1892 printk(KERN_DEBUG "isdn_mppp: reassembly: frame %d, "
1893 "len %d\n", MP_SEQ(from), from->len );
1894 skb = from;
1895 skb_pull(skb, MP_HEADER_LEN);
1896 mp->frames--;
1897 } else {
1898 struct sk_buff * frag;
1899 int n;
1900
1901 for(tot_len=n=0, frag=from; frag != to; frag=frag->next, n++)
1902 tot_len += frag->len - MP_HEADER_LEN;
1903
1904 if( ippp_table[lp->ppp_slot]->debug & 0x40 )
1905 printk(KERN_DEBUG"isdn_mppp: reassembling frames %d "
1906 "to %d, len %d\n", MP_SEQ(from),
1907 (MP_SEQ(from)+n-1) & MP_LONGSEQ_MASK, tot_len );
1908 if( (skb = dev_alloc_skb(tot_len)) == NULL ) {
1909 printk(KERN_ERR "isdn_mppp: cannot allocate sk buff "
1910 "of size %d\n", tot_len);
1911 isdn_ppp_mp_discard(mp, from, to);
1912 return;
1913 }
1914
1915 while( from != to ) {
1916 unsigned int len = from->len - MP_HEADER_LEN;
1917
1918 memcpy(skb_put(skb,len), from->data+MP_HEADER_LEN, len);
1919 frag = from->next;
1920 isdn_ppp_mp_free_skb(mp, from);
1921 from = frag;
1922 }
1923 }
1924 proto = isdn_ppp_strip_proto(skb);
1925 isdn_ppp_push_higher(net_dev, lp, skb, proto);
1926}
1927
1928static void isdn_ppp_mp_free_skb(ippp_bundle * mp, struct sk_buff * skb)
1929{
1930 dev_kfree_skb(skb);
1931 mp->frames--;
1932}
1933
1934static void isdn_ppp_mp_print_recv_pkt( int slot, struct sk_buff * skb )
1935{
1936 printk(KERN_DEBUG "mp_recv: %d/%d -> %02x %02x %02x %02x %02x %02x\n",
1937 slot, (int) skb->len,
1938 (int) skb->data[0], (int) skb->data[1], (int) skb->data[2],
1939 (int) skb->data[3], (int) skb->data[4], (int) skb->data[5]);
1940}
1941
1942static int
1943isdn_ppp_bundle(struct ippp_struct *is, int unit)
1944{
1945 char ifn[IFNAMSIZ + 1];
1946 isdn_net_dev *p;
1947 isdn_net_local *lp, *nlp;
1948 int rc;
1949 unsigned long flags;
1950
1951 sprintf(ifn, "ippp%d", unit);
1952 p = isdn_net_findif(ifn);
1953 if (!p) {
1954 printk(KERN_ERR "ippp_bundle: cannot find %s\n", ifn);
1955 return -EINVAL;
1956 }
1957
1958 spin_lock_irqsave(&p->pb->lock, flags);
1959
1960 nlp = is->lp;
1961 lp = p->queue;
1962 if( nlp->ppp_slot < 0 || nlp->ppp_slot >= ISDN_MAX_CHANNELS ||
1963 lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS ) {
1964 printk(KERN_ERR "ippp_bundle: binding to invalid slot %d\n",
1965 nlp->ppp_slot < 0 || nlp->ppp_slot >= ISDN_MAX_CHANNELS ?
1966 nlp->ppp_slot : lp->ppp_slot );
1967 rc = -EINVAL;
1968 goto out;
1969 }
1970
1971 isdn_net_add_to_bundle(p, nlp);
1972
1973 ippp_table[nlp->ppp_slot]->unit = ippp_table[lp->ppp_slot]->unit;
1974
1975 /* maybe also SC_CCP stuff */
1976 ippp_table[nlp->ppp_slot]->pppcfg |= ippp_table[lp->ppp_slot]->pppcfg &
1977 (SC_ENABLE_IP | SC_NO_TCP_CCID | SC_REJ_COMP_TCP);
1978 ippp_table[nlp->ppp_slot]->mpppcfg |= ippp_table[lp->ppp_slot]->mpppcfg &
1979 (SC_MP_PROT | SC_REJ_MP_PROT | SC_OUT_SHORT_SEQ | SC_IN_SHORT_SEQ);
1980 rc = isdn_ppp_mp_init(nlp, p->pb);
1981out:
1982 spin_unlock_irqrestore(&p->pb->lock, flags);
1983 return rc;
1984}
1985
1986#endif /* CONFIG_ISDN_MPP */
1987
1988/*
1989 * network device ioctl handlers
1990 */
1991
1992static int
1993isdn_ppp_dev_ioctl_stats(int slot, struct ifreq *ifr, struct net_device *dev)
1994{
1995 struct ppp_stats __user *res = ifr->ifr_data;
1996 struct ppp_stats t;
1997 isdn_net_local *lp = (isdn_net_local *) dev->priv;
1998
1999 if (!access_ok(VERIFY_WRITE, res, sizeof(struct ppp_stats)))
2000 return -EFAULT;
2001
2002 /* build a temporary stat struct and copy it to user space */
2003
2004 memset(&t, 0, sizeof(struct ppp_stats));
2005 if (dev->flags & IFF_UP) {
2006 t.p.ppp_ipackets = lp->stats.rx_packets;
2007 t.p.ppp_ibytes = lp->stats.rx_bytes;
2008 t.p.ppp_ierrors = lp->stats.rx_errors;
2009 t.p.ppp_opackets = lp->stats.tx_packets;
2010 t.p.ppp_obytes = lp->stats.tx_bytes;
2011 t.p.ppp_oerrors = lp->stats.tx_errors;
2012#ifdef CONFIG_ISDN_PPP_VJ
2013 if (slot >= 0 && ippp_table[slot]->slcomp) {
2014 struct slcompress *slcomp = ippp_table[slot]->slcomp;
2015 t.vj.vjs_packets = slcomp->sls_o_compressed + slcomp->sls_o_uncompressed;
2016 t.vj.vjs_compressed = slcomp->sls_o_compressed;
2017 t.vj.vjs_searches = slcomp->sls_o_searches;
2018 t.vj.vjs_misses = slcomp->sls_o_misses;
2019 t.vj.vjs_errorin = slcomp->sls_i_error;
2020 t.vj.vjs_tossed = slcomp->sls_i_tossed;
2021 t.vj.vjs_uncompressedin = slcomp->sls_i_uncompressed;
2022 t.vj.vjs_compressedin = slcomp->sls_i_compressed;
2023 }
2024#endif
2025 }
2026 if (copy_to_user(res, &t, sizeof(struct ppp_stats)))
2027 return -EFAULT;
2028 return 0;
2029}
2030
2031int
2032isdn_ppp_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
2033{
2034 int error=0;
2035 int len;
2036 isdn_net_local *lp = (isdn_net_local *) dev->priv;
2037
2038
2039 if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP)
2040 return -EINVAL;
2041
2042 switch (cmd) {
2043#define PPP_VERSION "2.3.7"
2044 case SIOCGPPPVER:
2045 len = strlen(PPP_VERSION) + 1;
2046 if (copy_to_user(ifr->ifr_data, PPP_VERSION, len))
2047 error = -EFAULT;
2048 break;
2049
2050 case SIOCGPPPSTATS:
2051 error = isdn_ppp_dev_ioctl_stats(lp->ppp_slot, ifr, dev);
2052 break;
2053 default:
2054 error = -EINVAL;
2055 break;
2056 }
2057 return error;
2058}
2059
2060static int
2061isdn_ppp_if_get_unit(char *name)
2062{
2063 int len,
2064 i,
2065 unit = 0,
2066 deci;
2067
2068 len = strlen(name);
2069
2070 if (strncmp("ippp", name, 4) || len > 8)
2071 return -1;
2072
2073 for (i = 0, deci = 1; i < len; i++, deci *= 10) {
2074 char a = name[len - i - 1];
2075 if (a >= '0' && a <= '9')
2076 unit += (a - '0') * deci;
2077 else
2078 break;
2079 }
2080 if (!i || len - i != 4)
2081 unit = -1;
2082
2083 return unit;
2084}
2085
2086
2087int
2088isdn_ppp_dial_slave(char *name)
2089{
2090#ifdef CONFIG_ISDN_MPP
2091 isdn_net_dev *ndev;
2092 isdn_net_local *lp;
2093 struct net_device *sdev;
2094
2095 if (!(ndev = isdn_net_findif(name)))
2096 return 1;
2097 lp = ndev->local;
2098 if (!(lp->flags & ISDN_NET_CONNECTED))
2099 return 5;
2100
2101 sdev = lp->slave;
2102 while (sdev) {
2103 isdn_net_local *mlp = (isdn_net_local *) sdev->priv;
2104 if (!(mlp->flags & ISDN_NET_CONNECTED))
2105 break;
2106 sdev = mlp->slave;
2107 }
2108 if (!sdev)
2109 return 2;
2110
2111 isdn_net_dial_req((isdn_net_local *) sdev->priv);
2112 return 0;
2113#else
2114 return -1;
2115#endif
2116}
2117
2118int
2119isdn_ppp_hangup_slave(char *name)
2120{
2121#ifdef CONFIG_ISDN_MPP
2122 isdn_net_dev *ndev;
2123 isdn_net_local *lp;
2124 struct net_device *sdev;
2125
2126 if (!(ndev = isdn_net_findif(name)))
2127 return 1;
2128 lp = ndev->local;
2129 if (!(lp->flags & ISDN_NET_CONNECTED))
2130 return 5;
2131
2132 sdev = lp->slave;
2133 while (sdev) {
2134 isdn_net_local *mlp = (isdn_net_local *) sdev->priv;
2135
2136 if (mlp->slave) { /* find last connected link in chain */
2137 isdn_net_local *nlp = (isdn_net_local *) mlp->slave->priv;
2138
2139 if (!(nlp->flags & ISDN_NET_CONNECTED))
2140 break;
2141 } else if (mlp->flags & ISDN_NET_CONNECTED)
2142 break;
2143
2144 sdev = mlp->slave;
2145 }
2146 if (!sdev)
2147 return 2;
2148
2149 isdn_net_hangup(sdev);
2150 return 0;
2151#else
2152 return -1;
2153#endif
2154}
2155
2156/*
2157 * PPP compression stuff
2158 */
2159
2160
2161/* Push an empty CCP Data Frame up to the daemon to wake it up and let it
2162 generate a CCP Reset-Request or tear down CCP altogether */
2163
2164static void isdn_ppp_ccp_kickup(struct ippp_struct *is)
2165{
2166 isdn_ppp_fill_rq(NULL, 0, PPP_COMP, is->lp->ppp_slot);
2167}
2168
2169/* In-kernel handling of CCP Reset-Request and Reset-Ack is necessary,
2170 but absolutely nontrivial. The most abstruse problem we are facing is
2171 that the generation, reception and all the handling of timeouts and
2172 resends including proper request id management should be entirely left
2173 to the (de)compressor, but indeed is not covered by the current API to
2174 the (de)compressor. The API is a prototype version from PPP where only
2175 some (de)compressors have yet been implemented and all of them are
2176 rather simple in their reset handling. Especially, their is only one
2177 outstanding ResetAck at a time with all of them and ResetReq/-Acks do
2178 not have parameters. For this very special case it was sufficient to
2179 just return an error code from the decompressor and have a single
2180 reset() entry to communicate all the necessary information between
2181 the framework and the (de)compressor. Bad enough, LZS is different
2182 (and any other compressor may be different, too). It has multiple
2183 histories (eventually) and needs to Reset each of them independently
2184 and thus uses multiple outstanding Acks and history numbers as an
2185 additional parameter to Reqs/Acks.
2186 All that makes it harder to port the reset state engine into the
2187 kernel because it is not just the same simple one as in (i)pppd but
2188 it must be able to pass additional parameters and have multiple out-
2189 standing Acks. We are trying to achieve the impossible by handling
2190 reset transactions independent by their id. The id MUST change when
2191 the data portion changes, thus any (de)compressor who uses more than
2192 one resettable state must provide and recognize individual ids for
2193 each individual reset transaction. The framework itself does _only_
2194 differentiate them by id, because it has no other semantics like the
2195 (de)compressor might.
2196 This looks like a major redesign of the interface would be nice,
2197 but I don't have an idea how to do it better. */
2198
2199/* Send a CCP Reset-Request or Reset-Ack directly from the kernel. This is
2200 getting that lengthy because there is no simple "send-this-frame-out"
2201 function above but every wrapper does a bit different. Hope I guess
2202 correct in this hack... */
2203
2204static void isdn_ppp_ccp_xmit_reset(struct ippp_struct *is, int proto,
2205 unsigned char code, unsigned char id,
2206 unsigned char *data, int len)
2207{
2208 struct sk_buff *skb;
2209 unsigned char *p;
2210 int hl;
2211 int cnt = 0;
2212 isdn_net_local *lp = is->lp;
2213
2214 /* Alloc large enough skb */
2215 hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen;
2216 skb = alloc_skb(len + hl + 16,GFP_ATOMIC);
2217 if(!skb) {
2218 printk(KERN_WARNING
2219 "ippp: CCP cannot send reset - out of memory\n");
2220 return;
2221 }
2222 skb_reserve(skb, hl);
2223
2224 /* We may need to stuff an address and control field first */
2225 if(!(is->pppcfg & SC_COMP_AC)) {
2226 p = skb_put(skb, 2);
2227 *p++ = 0xff;
2228 *p++ = 0x03;
2229 }
2230
2231 /* Stuff proto, code, id and length */
2232 p = skb_put(skb, 6);
2233 *p++ = (proto >> 8);
2234 *p++ = (proto & 0xff);
2235 *p++ = code;
2236 *p++ = id;
2237 cnt = 4 + len;
2238 *p++ = (cnt >> 8);
2239 *p++ = (cnt & 0xff);
2240
2241 /* Now stuff remaining bytes */
2242 if(len) {
2243 p = skb_put(skb, len);
2244 memcpy(p, data, len);
2245 }
2246
2247 /* skb is now ready for xmit */
2248 printk(KERN_DEBUG "Sending CCP Frame:\n");
2249 isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, is->unit,lp->ppp_slot);
2250
2251 isdn_net_write_super(lp, skb);
2252}
2253
2254/* Allocate the reset state vector */
2255static struct ippp_ccp_reset *isdn_ppp_ccp_reset_alloc(struct ippp_struct *is)
2256{
2257 struct ippp_ccp_reset *r;
2258 r = kmalloc(sizeof(struct ippp_ccp_reset), GFP_KERNEL);
2259 if(!r) {
2260 printk(KERN_ERR "ippp_ccp: failed to allocate reset data"
2261 " structure - no mem\n");
2262 return NULL;
2263 }
2264 memset(r, 0, sizeof(struct ippp_ccp_reset));
2265 printk(KERN_DEBUG "ippp_ccp: allocated reset data structure %p\n", r);
2266 is->reset = r;
2267 return r;
2268}
2269
2270/* Destroy the reset state vector. Kill all pending timers first. */
2271static void isdn_ppp_ccp_reset_free(struct ippp_struct *is)
2272{
2273 unsigned int id;
2274
2275 printk(KERN_DEBUG "ippp_ccp: freeing reset data structure %p\n",
2276 is->reset);
2277 for(id = 0; id < 256; id++) {
2278 if(is->reset->rs[id]) {
2279 isdn_ppp_ccp_reset_free_state(is, (unsigned char)id);
2280 }
2281 }
2282 kfree(is->reset);
2283 is->reset = NULL;
2284}
2285
2286/* Free a given state and clear everything up for later reallocation */
2287static void isdn_ppp_ccp_reset_free_state(struct ippp_struct *is,
2288 unsigned char id)
2289{
2290 struct ippp_ccp_reset_state *rs;
2291
2292 if(is->reset->rs[id]) {
2293 printk(KERN_DEBUG "ippp_ccp: freeing state for id %d\n", id);
2294 rs = is->reset->rs[id];
2295 /* Make sure the kernel will not call back later */
2296 if(rs->ta)
2297 del_timer(&rs->timer);
2298 is->reset->rs[id] = NULL;
2299 kfree(rs);
2300 } else {
2301 printk(KERN_WARNING "ippp_ccp: id %d is not allocated\n", id);
2302 }
2303}
2304
2305/* The timer callback function which is called when a ResetReq has timed out,
2306 aka has never been answered by a ResetAck */
2307static void isdn_ppp_ccp_timer_callback(unsigned long closure)
2308{
2309 struct ippp_ccp_reset_state *rs =
2310 (struct ippp_ccp_reset_state *)closure;
2311
2312 if(!rs) {
2313 printk(KERN_ERR "ippp_ccp: timer cb with zero closure.\n");
2314 return;
2315 }
2316 if(rs->ta && rs->state == CCPResetSentReq) {
2317 /* We are correct here */
2318 if(!rs->expra) {
2319 /* Hmm, there is no Ack really expected. We can clean
2320 up the state now, it will be reallocated if the
2321 decompressor insists on another reset */
2322 rs->ta = 0;
2323 isdn_ppp_ccp_reset_free_state(rs->is, rs->id);
2324 return;
2325 }
2326 printk(KERN_DEBUG "ippp_ccp: CCP Reset timed out for id %d\n",
2327 rs->id);
2328 /* Push it again */
2329 isdn_ppp_ccp_xmit_reset(rs->is, PPP_CCP, CCP_RESETREQ, rs->id,
2330 rs->data, rs->dlen);
2331 /* Restart timer */
2332 rs->timer.expires = jiffies + HZ*5;
2333 add_timer(&rs->timer);
2334 } else {
2335 printk(KERN_WARNING "ippp_ccp: timer cb in wrong state %d\n",
2336 rs->state);
2337 }
2338}
2339
2340/* Allocate a new reset transaction state */
2341static struct ippp_ccp_reset_state *isdn_ppp_ccp_reset_alloc_state(struct ippp_struct *is,
2342 unsigned char id)
2343{
2344 struct ippp_ccp_reset_state *rs;
2345 if(is->reset->rs[id]) {
2346 printk(KERN_WARNING "ippp_ccp: old state exists for id %d\n",
2347 id);
2348 return NULL;
2349 } else {
2350 rs = kmalloc(sizeof(struct ippp_ccp_reset_state), GFP_KERNEL);
2351 if(!rs)
2352 return NULL;
2353 memset(rs, 0, sizeof(struct ippp_ccp_reset_state));
2354 rs->state = CCPResetIdle;
2355 rs->is = is;
2356 rs->id = id;
2357 rs->timer.data = (unsigned long)rs;
2358 rs->timer.function = isdn_ppp_ccp_timer_callback;
2359 is->reset->rs[id] = rs;
2360 }
2361 return rs;
2362}
2363
2364
2365/* A decompressor wants a reset with a set of parameters - do what is
2366 necessary to fulfill it */
2367static void isdn_ppp_ccp_reset_trans(struct ippp_struct *is,
2368 struct isdn_ppp_resetparams *rp)
2369{
2370 struct ippp_ccp_reset_state *rs;
2371
2372 if(rp->valid) {
2373 /* The decompressor defines parameters by itself */
2374 if(rp->rsend) {
2375 /* And he wants us to send a request */
2376 if(!(rp->idval)) {
2377 printk(KERN_ERR "ippp_ccp: decompressor must"
2378 " specify reset id\n");
2379 return;
2380 }
2381 if(is->reset->rs[rp->id]) {
2382 /* There is already a transaction in existence
2383 for this id. May be still waiting for a
2384 Ack or may be wrong. */
2385 rs = is->reset->rs[rp->id];
2386 if(rs->state == CCPResetSentReq && rs->ta) {
2387 printk(KERN_DEBUG "ippp_ccp: reset"
2388 " trans still in progress"
2389 " for id %d\n", rp->id);
2390 } else {
2391 printk(KERN_WARNING "ippp_ccp: reset"
2392 " trans in wrong state %d for"
2393 " id %d\n", rs->state, rp->id);
2394 }
2395 } else {
2396 /* Ok, this is a new transaction */
2397 printk(KERN_DEBUG "ippp_ccp: new trans for id"
2398 " %d to be started\n", rp->id);
2399 rs = isdn_ppp_ccp_reset_alloc_state(is, rp->id);
2400 if(!rs) {
2401 printk(KERN_ERR "ippp_ccp: out of mem"
2402 " allocing ccp trans\n");
2403 return;
2404 }
2405 rs->state = CCPResetSentReq;
2406 rs->expra = rp->expra;
2407 if(rp->dtval) {
2408 rs->dlen = rp->dlen;
2409 memcpy(rs->data, rp->data, rp->dlen);
2410 }
2411 /* HACK TODO - add link comp here */
2412 isdn_ppp_ccp_xmit_reset(is, PPP_CCP,
2413 CCP_RESETREQ, rs->id,
2414 rs->data, rs->dlen);
2415 /* Start the timer */
2416 rs->timer.expires = jiffies + 5*HZ;
2417 add_timer(&rs->timer);
2418 rs->ta = 1;
2419 }
2420 } else {
2421 printk(KERN_DEBUG "ippp_ccp: no reset sent\n");
2422 }
2423 } else {
2424 /* The reset params are invalid. The decompressor does not
2425 care about them, so we just send the minimal requests
2426 and increase ids only when an Ack is received for a
2427 given id */
2428 if(is->reset->rs[is->reset->lastid]) {
2429 /* There is already a transaction in existence
2430 for this id. May be still waiting for a
2431 Ack or may be wrong. */
2432 rs = is->reset->rs[is->reset->lastid];
2433 if(rs->state == CCPResetSentReq && rs->ta) {
2434 printk(KERN_DEBUG "ippp_ccp: reset"
2435 " trans still in progress"
2436 " for id %d\n", rp->id);
2437 } else {
2438 printk(KERN_WARNING "ippp_ccp: reset"
2439 " trans in wrong state %d for"
2440 " id %d\n", rs->state, rp->id);
2441 }
2442 } else {
2443 printk(KERN_DEBUG "ippp_ccp: new trans for id"
2444 " %d to be started\n", is->reset->lastid);
2445 rs = isdn_ppp_ccp_reset_alloc_state(is,
2446 is->reset->lastid);
2447 if(!rs) {
2448 printk(KERN_ERR "ippp_ccp: out of mem"
2449 " allocing ccp trans\n");
2450 return;
2451 }
2452 rs->state = CCPResetSentReq;
2453 /* We always expect an Ack if the decompressor doesn't
2454 know better */
2455 rs->expra = 1;
2456 rs->dlen = 0;
2457 /* HACK TODO - add link comp here */
2458 isdn_ppp_ccp_xmit_reset(is, PPP_CCP, CCP_RESETREQ,
2459 rs->id, NULL, 0);
2460 /* Start the timer */
2461 rs->timer.expires = jiffies + 5*HZ;
2462 add_timer(&rs->timer);
2463 rs->ta = 1;
2464 }
2465 }
2466}
2467
2468/* An Ack was received for this id. This means we stop the timer and clean
2469 up the state prior to calling the decompressors reset routine. */
2470static void isdn_ppp_ccp_reset_ack_rcvd(struct ippp_struct *is,
2471 unsigned char id)
2472{
2473 struct ippp_ccp_reset_state *rs = is->reset->rs[id];
2474
2475 if(rs) {
2476 if(rs->ta && rs->state == CCPResetSentReq) {
2477 /* Great, we are correct */
2478 if(!rs->expra)
2479 printk(KERN_DEBUG "ippp_ccp: ResetAck received"
2480 " for id %d but not expected\n", id);
2481 } else {
2482 printk(KERN_INFO "ippp_ccp: ResetAck received out of"
2483 "sync for id %d\n", id);
2484 }
2485 if(rs->ta) {
2486 rs->ta = 0;
2487 del_timer(&rs->timer);
2488 }
2489 isdn_ppp_ccp_reset_free_state(is, id);
2490 } else {
2491 printk(KERN_INFO "ippp_ccp: ResetAck received for unknown id"
2492 " %d\n", id);
2493 }
2494 /* Make sure the simple reset stuff uses a new id next time */
2495 is->reset->lastid++;
2496}
2497
2498/*
2499 * decompress packet
2500 *
2501 * if master = 0, we're trying to uncompress an per-link compressed packet,
2502 * as opposed to an compressed reconstructed-from-MPPP packet.
2503 * proto is updated to protocol field of uncompressed packet.
2504 *
2505 * retval: decompressed packet,
2506 * same packet if uncompressed,
2507 * NULL if decompression error
2508 */
2509
2510static struct sk_buff *isdn_ppp_decompress(struct sk_buff *skb,struct ippp_struct *is,struct ippp_struct *master,
2511 int *proto)
2512{
2513 void *stat = NULL;
2514 struct isdn_ppp_compressor *ipc = NULL;
2515 struct sk_buff *skb_out;
2516 int len;
2517 struct ippp_struct *ri;
2518 struct isdn_ppp_resetparams rsparm;
2519 unsigned char rsdata[IPPP_RESET_MAXDATABYTES];
2520
2521 if(!master) {
2522 // per-link decompression
2523 stat = is->link_decomp_stat;
2524 ipc = is->link_decompressor;
2525 ri = is;
2526 } else {
2527 stat = master->decomp_stat;
2528 ipc = master->decompressor;
2529 ri = master;
2530 }
2531
2532 if (!ipc) {
2533 // no decompressor -> we can't decompress.
2534 printk(KERN_DEBUG "ippp: no decompressor defined!\n");
2535 return skb;
2536 }
2537 if (!stat) // if we have a compressor, stat has been set as well
2538 BUG();
2539
2540 if((master && *proto == PPP_COMP) || (!master && *proto == PPP_COMPFRAG) ) {
2541 // compressed packets are compressed by their protocol type
2542
2543 // Set up reset params for the decompressor
2544 memset(&rsparm, 0, sizeof(rsparm));
2545 rsparm.data = rsdata;
2546 rsparm.maxdlen = IPPP_RESET_MAXDATABYTES;
2547
2548 skb_out = dev_alloc_skb(is->mru + PPP_HDRLEN);
2549 len = ipc->decompress(stat, skb, skb_out, &rsparm);
2550 kfree_skb(skb);
2551 if (len <= 0) {
2552 switch(len) {
2553 case DECOMP_ERROR:
2554 printk(KERN_INFO "ippp: decomp wants reset %s params\n",
2555 rsparm.valid ? "with" : "without");
2556
2557 isdn_ppp_ccp_reset_trans(ri, &rsparm);
2558 break;
2559 case DECOMP_FATALERROR:
2560 ri->pppcfg |= SC_DC_FERROR;
2561 /* Kick ipppd to recognize the error */
2562 isdn_ppp_ccp_kickup(ri);
2563 break;
2564 }
2565 kfree_skb(skb_out);
2566 return NULL;
2567 }
2568 *proto = isdn_ppp_strip_proto(skb_out);
2569 if (*proto < 0) {
2570 kfree_skb(skb_out);
2571 return NULL;
2572 }
2573 return skb_out;
2574 } else {
2575 // uncompressed packets are fed through the decompressor to
2576 // update the decompressor state
2577 ipc->incomp(stat, skb, *proto);
2578 return skb;
2579 }
2580}
2581
2582/*
2583 * compress a frame
2584 * type=0: normal/bundle compression
2585 * =1: link compression
2586 * returns original skb if we haven't compressed the frame
2587 * and a new skb pointer if we've done it
2588 */
2589static struct sk_buff *isdn_ppp_compress(struct sk_buff *skb_in,int *proto,
2590 struct ippp_struct *is,struct ippp_struct *master,int type)
2591{
2592 int ret;
2593 int new_proto;
2594 struct isdn_ppp_compressor *compressor;
2595 void *stat;
2596 struct sk_buff *skb_out;
2597
2598 /* we do not compress control protocols */
2599 if(*proto < 0 || *proto > 0x3fff) {
2600 return skb_in;
2601 }
2602
2603 if(type) { /* type=1 => Link compression */
2604 return skb_in;
2605 }
2606 else {
2607 if(!master) {
2608 compressor = is->compressor;
2609 stat = is->comp_stat;
2610 }
2611 else {
2612 compressor = master->compressor;
2613 stat = master->comp_stat;
2614 }
2615 new_proto = PPP_COMP;
2616 }
2617
2618 if(!compressor) {
2619 printk(KERN_ERR "isdn_ppp: No compressor set!\n");
2620 return skb_in;
2621 }
2622 if(!stat) {
2623 printk(KERN_ERR "isdn_ppp: Compressor not initialized?\n");
2624 return skb_in;
2625 }
2626
2627 /* Allow for at least 150 % expansion (for now) */
2628 skb_out = alloc_skb(skb_in->len + skb_in->len/2 + 32 +
2629 skb_headroom(skb_in), GFP_ATOMIC);
2630 if(!skb_out)
2631 return skb_in;
2632 skb_reserve(skb_out, skb_headroom(skb_in));
2633
2634 ret = (compressor->compress)(stat,skb_in,skb_out,*proto);
2635 if(!ret) {
2636 dev_kfree_skb(skb_out);
2637 return skb_in;
2638 }
2639
2640 dev_kfree_skb(skb_in);
2641 *proto = new_proto;
2642 return skb_out;
2643}
2644
2645/*
2646 * we received a CCP frame ..
2647 * not a clean solution, but we MUST handle a few cases in the kernel
2648 */
2649static void isdn_ppp_receive_ccp(isdn_net_dev *net_dev, isdn_net_local *lp,
2650 struct sk_buff *skb,int proto)
2651{
2652 struct ippp_struct *is;
2653 struct ippp_struct *mis;
2654 int len;
2655 struct isdn_ppp_resetparams rsparm;
2656 unsigned char rsdata[IPPP_RESET_MAXDATABYTES];
2657
2658 printk(KERN_DEBUG "Received CCP frame from peer slot(%d)\n",
2659 lp->ppp_slot);
2660 if (lp->ppp_slot < 0 || lp->ppp_slot > ISDN_MAX_CHANNELS) {
2661 printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n",
2662 __FUNCTION__, lp->ppp_slot);
2663 return;
2664 }
2665 is = ippp_table[lp->ppp_slot];
2666 isdn_ppp_frame_log("ccp-rcv", skb->data, skb->len, 32, is->unit,lp->ppp_slot);
2667
2668 if(lp->master) {
2669 int slot = ((isdn_net_local *) (lp->master->priv))->ppp_slot;
2670 if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
2671 printk(KERN_ERR "%s: slot(%d) out of range\n",
2672 __FUNCTION__, slot);
2673 return;
2674 }
2675 mis = ippp_table[slot];
2676 } else
2677 mis = is;
2678
2679 switch(skb->data[0]) {
2680 case CCP_CONFREQ:
2681 if(is->debug & 0x10)
2682 printk(KERN_DEBUG "Disable compression here!\n");
2683 if(proto == PPP_CCP)
2684 mis->compflags &= ~SC_COMP_ON;
2685 else
2686 is->compflags &= ~SC_LINK_COMP_ON;
2687 break;
2688 case CCP_TERMREQ:
2689 case CCP_TERMACK:
2690 if(is->debug & 0x10)
2691 printk(KERN_DEBUG "Disable (de)compression here!\n");
2692 if(proto == PPP_CCP)
2693 mis->compflags &= ~(SC_DECOMP_ON|SC_COMP_ON);
2694 else
2695 is->compflags &= ~(SC_LINK_DECOMP_ON|SC_LINK_COMP_ON);
2696 break;
2697 case CCP_CONFACK:
2698 /* if we RECEIVE an ackowledge we enable the decompressor */
2699 if(is->debug & 0x10)
2700 printk(KERN_DEBUG "Enable decompression here!\n");
2701 if(proto == PPP_CCP) {
2702 if (!mis->decompressor)
2703 break;
2704 mis->compflags |= SC_DECOMP_ON;
2705 } else {
2706 if (!is->decompressor)
2707 break;
2708 is->compflags |= SC_LINK_DECOMP_ON;
2709 }
2710 break;
2711
2712 case CCP_RESETACK:
2713 printk(KERN_DEBUG "Received ResetAck from peer\n");
2714 len = (skb->data[2] << 8) | skb->data[3];
2715 len -= 4;
2716
2717 if(proto == PPP_CCP) {
2718 /* If a reset Ack was outstanding for this id, then
2719 clean up the state engine */
2720 isdn_ppp_ccp_reset_ack_rcvd(mis, skb->data[1]);
2721 if(mis->decompressor && mis->decomp_stat)
2722 mis->decompressor->
2723 reset(mis->decomp_stat,
2724 skb->data[0],
2725 skb->data[1],
2726 len ? &skb->data[4] : NULL,
2727 len, NULL);
2728 /* TODO: This is not easy to decide here */
2729 mis->compflags &= ~SC_DECOMP_DISCARD;
2730 }
2731 else {
2732 isdn_ppp_ccp_reset_ack_rcvd(is, skb->data[1]);
2733 if(is->link_decompressor && is->link_decomp_stat)
2734 is->link_decompressor->
2735 reset(is->link_decomp_stat,
2736 skb->data[0],
2737 skb->data[1],
2738 len ? &skb->data[4] : NULL,
2739 len, NULL);
2740 /* TODO: neither here */
2741 is->compflags &= ~SC_LINK_DECOMP_DISCARD;
2742 }
2743 break;
2744
2745 case CCP_RESETREQ:
2746 printk(KERN_DEBUG "Received ResetReq from peer\n");
2747 /* Receiving a ResetReq means we must reset our compressor */
2748 /* Set up reset params for the reset entry */
2749 memset(&rsparm, 0, sizeof(rsparm));
2750 rsparm.data = rsdata;
2751 rsparm.maxdlen = IPPP_RESET_MAXDATABYTES;
2752 /* Isolate data length */
2753 len = (skb->data[2] << 8) | skb->data[3];
2754 len -= 4;
2755 if(proto == PPP_CCP) {
2756 if(mis->compressor && mis->comp_stat)
2757 mis->compressor->
2758 reset(mis->comp_stat,
2759 skb->data[0],
2760 skb->data[1],
2761 len ? &skb->data[4] : NULL,
2762 len, &rsparm);
2763 }
2764 else {
2765 if(is->link_compressor && is->link_comp_stat)
2766 is->link_compressor->
2767 reset(is->link_comp_stat,
2768 skb->data[0],
2769 skb->data[1],
2770 len ? &skb->data[4] : NULL,
2771 len, &rsparm);
2772 }
2773 /* Ack the Req as specified by rsparm */
2774 if(rsparm.valid) {
2775 /* Compressor reset handler decided how to answer */
2776 if(rsparm.rsend) {
2777 /* We should send a Frame */
2778 isdn_ppp_ccp_xmit_reset(is, proto, CCP_RESETACK,
2779 rsparm.idval ? rsparm.id
2780 : skb->data[1],
2781 rsparm.dtval ?
2782 rsparm.data : NULL,
2783 rsparm.dtval ?
2784 rsparm.dlen : 0);
2785 } else {
2786 printk(KERN_DEBUG "ResetAck suppressed\n");
2787 }
2788 } else {
2789 /* We answer with a straight reflected Ack */
2790 isdn_ppp_ccp_xmit_reset(is, proto, CCP_RESETACK,
2791 skb->data[1],
2792 len ? &skb->data[4] : NULL,
2793 len);
2794 }
2795 break;
2796 }
2797}
2798
2799
2800/*
2801 * Daemon sends a CCP frame ...
2802 */
2803
2804/* TODO: Clean this up with new Reset semantics */
2805
2806/* I believe the CCP handling as-is is done wrong. Compressed frames
2807 * should only be sent/received after CCP reaches UP state, which means
2808 * both sides have sent CONF_ACK. Currently, we handle both directions
2809 * independently, which means we may accept compressed frames too early
2810 * (supposedly not a problem), but may also mean we send compressed frames
2811 * too early, which may turn out to be a problem.
2812 * This part of state machine should actually be handled by (i)pppd, but
2813 * that's too big of a change now. --kai
2814 */
2815
2816/* Actually, we might turn this into an advantage: deal with the RFC in
2817 * the old tradition of beeing generous on what we accept, but beeing
2818 * strict on what we send. Thus we should just
2819 * - accept compressed frames as soon as decompression is negotiated
2820 * - send compressed frames only when decomp *and* comp are negotiated
2821 * - drop rx compressed frames if we cannot decomp (instead of pushing them
2822 * up to ipppd)
2823 * and I tried to modify this file according to that. --abp
2824 */
2825
2826static void isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, struct sk_buff *skb)
2827{
2828 struct ippp_struct *mis,*is;
2829 int proto, slot = lp->ppp_slot;
2830 unsigned char *data;
2831
2832 if(!skb || skb->len < 3)
2833 return;
2834 if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
2835 printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n",
2836 __FUNCTION__, slot);
2837 return;
2838 }
2839 is = ippp_table[slot];
2840 /* Daemon may send with or without address and control field comp */
2841 data = skb->data;
2842 if(!(is->pppcfg & SC_COMP_AC) && data[0] == 0xff && data[1] == 0x03) {
2843 data += 2;
2844 if(skb->len < 5)
2845 return;
2846 }
2847
2848 proto = ((int)data[0]<<8)+data[1];
2849 if(proto != PPP_CCP && proto != PPP_CCPFRAG)
2850 return;
2851
2852 printk(KERN_DEBUG "Received CCP frame from daemon:\n");
2853 isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, is->unit,lp->ppp_slot);
2854
2855 if (lp->master) {
2856 slot = ((isdn_net_local *) (lp->master->priv))->ppp_slot;
2857 if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
2858 printk(KERN_ERR "%s: slot(%d) out of range\n",
2859 __FUNCTION__, slot);
2860 return;
2861 }
2862 mis = ippp_table[slot];
2863 } else
2864 mis = is;
2865 if (mis != is)
2866 printk(KERN_DEBUG "isdn_ppp: Ouch! Master CCP sends on slave slot!\n");
2867
2868 switch(data[2]) {
2869 case CCP_CONFREQ:
2870 if(is->debug & 0x10)
2871 printk(KERN_DEBUG "Disable decompression here!\n");
2872 if(proto == PPP_CCP)
2873 is->compflags &= ~SC_DECOMP_ON;
2874 else
2875 is->compflags &= ~SC_LINK_DECOMP_ON;
2876 break;
2877 case CCP_TERMREQ:
2878 case CCP_TERMACK:
2879 if(is->debug & 0x10)
2880 printk(KERN_DEBUG "Disable (de)compression here!\n");
2881 if(proto == PPP_CCP)
2882 is->compflags &= ~(SC_DECOMP_ON|SC_COMP_ON);
2883 else
2884 is->compflags &= ~(SC_LINK_DECOMP_ON|SC_LINK_COMP_ON);
2885 break;
2886 case CCP_CONFACK:
2887 /* if we SEND an ackowledge we can/must enable the compressor */
2888 if(is->debug & 0x10)
2889 printk(KERN_DEBUG "Enable compression here!\n");
2890 if(proto == PPP_CCP) {
2891 if (!is->compressor)
2892 break;
2893 is->compflags |= SC_COMP_ON;
2894 } else {
2895 if (!is->compressor)
2896 break;
2897 is->compflags |= SC_LINK_COMP_ON;
2898 }
2899 break;
2900 case CCP_RESETACK:
2901 /* If we send a ACK we should reset our compressor */
2902 if(is->debug & 0x10)
2903 printk(KERN_DEBUG "Reset decompression state here!\n");
2904 printk(KERN_DEBUG "ResetAck from daemon passed by\n");
2905 if(proto == PPP_CCP) {
2906 /* link to master? */
2907 if(is->compressor && is->comp_stat)
2908 is->compressor->reset(is->comp_stat, 0, 0,
2909 NULL, 0, NULL);
2910 is->compflags &= ~SC_COMP_DISCARD;
2911 }
2912 else {
2913 if(is->link_compressor && is->link_comp_stat)
2914 is->link_compressor->reset(is->link_comp_stat,
2915 0, 0, NULL, 0, NULL);
2916 is->compflags &= ~SC_LINK_COMP_DISCARD;
2917 }
2918 break;
2919 case CCP_RESETREQ:
2920 /* Just let it pass by */
2921 printk(KERN_DEBUG "ResetReq from daemon passed by\n");
2922 break;
2923 }
2924}
2925
2926int isdn_ppp_register_compressor(struct isdn_ppp_compressor *ipc)
2927{
2928 ipc->next = ipc_head;
2929 ipc->prev = NULL;
2930 if(ipc_head) {
2931 ipc_head->prev = ipc;
2932 }
2933 ipc_head = ipc;
2934 return 0;
2935}
2936
2937int isdn_ppp_unregister_compressor(struct isdn_ppp_compressor *ipc)
2938{
2939 if(ipc->prev)
2940 ipc->prev->next = ipc->next;
2941 else
2942 ipc_head = ipc->next;
2943 if(ipc->next)
2944 ipc->next->prev = ipc->prev;
2945 ipc->prev = ipc->next = NULL;
2946 return 0;
2947}
2948
2949static int isdn_ppp_set_compressor(struct ippp_struct *is, struct isdn_ppp_comp_data *data)
2950{
2951 struct isdn_ppp_compressor *ipc = ipc_head;
2952 int ret;
2953 void *stat;
2954 int num = data->num;
2955
2956 if(is->debug & 0x10)
2957 printk(KERN_DEBUG "[%d] Set %s type %d\n",is->unit,
2958 (data->flags&IPPP_COMP_FLAG_XMIT)?"compressor":"decompressor",num);
2959
2960 /* If is has no valid reset state vector, we cannot allocate a
2961 decompressor. The decompressor would cause reset transactions
2962 sooner or later, and they need that vector. */
2963
2964 if(!(data->flags & IPPP_COMP_FLAG_XMIT) && !is->reset) {
2965 printk(KERN_ERR "ippp_ccp: no reset data structure - can't"
2966 " allow decompression.\n");
2967 return -ENOMEM;
2968 }
2969
2970 while(ipc) {
2971 if(ipc->num == num) {
2972 stat = ipc->alloc(data);
2973 if(stat) {
2974 ret = ipc->init(stat,data,is->unit,0);
2975 if(!ret) {
2976 printk(KERN_ERR "Can't init (de)compression!\n");
2977 ipc->free(stat);
2978 stat = NULL;
2979 break;
2980 }
2981 }
2982 else {
2983 printk(KERN_ERR "Can't alloc (de)compression!\n");
2984 break;
2985 }
2986
2987 if(data->flags & IPPP_COMP_FLAG_XMIT) {
2988 if(data->flags & IPPP_COMP_FLAG_LINK) {
2989 if(is->link_comp_stat)
2990 is->link_compressor->free(is->link_comp_stat);
2991 is->link_comp_stat = stat;
2992 is->link_compressor = ipc;
2993 }
2994 else {
2995 if(is->comp_stat)
2996 is->compressor->free(is->comp_stat);
2997 is->comp_stat = stat;
2998 is->compressor = ipc;
2999 }
3000 }
3001 else {
3002 if(data->flags & IPPP_COMP_FLAG_LINK) {
3003 if(is->link_decomp_stat)
3004 is->link_decompressor->free(is->link_decomp_stat);
3005 is->link_decomp_stat = stat;
3006 is->link_decompressor = ipc;
3007 }
3008 else {
3009 if(is->decomp_stat)
3010 is->decompressor->free(is->decomp_stat);
3011 is->decomp_stat = stat;
3012 is->decompressor = ipc;
3013 }
3014 }
3015 return 0;
3016 }
3017 ipc = ipc->next;
3018 }
3019 return -EINVAL;
3020}
diff --git a/drivers/isdn/i4l/isdn_ppp.h b/drivers/isdn/i4l/isdn_ppp.h
new file mode 100644
index 000000000000..8cc05c7ccf78
--- /dev/null
+++ b/drivers/isdn/i4l/isdn_ppp.h
@@ -0,0 +1,43 @@
1/* $Id: isdn_ppp.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
2 *
3 * header for Linux ISDN subsystem, functions for synchronous PPP (linklevel).
4 *
5 * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
6 *
7 * This software may be used and distributed according to the terms
8 * of the GNU General Public License, incorporated herein by reference.
9 *
10 */
11
12#include <linux/ppp_defs.h> /* for PPP_PROTOCOL */
13#include <linux/isdn_ppp.h> /* for isdn_ppp info */
14
15extern int isdn_ppp_read(int, struct file *, char __user *, int);
16extern int isdn_ppp_write(int, struct file *, const char __user *, int);
17extern int isdn_ppp_open(int, struct file *);
18extern int isdn_ppp_init(void);
19extern void isdn_ppp_cleanup(void);
20extern int isdn_ppp_free(isdn_net_local *);
21extern int isdn_ppp_bind(isdn_net_local *);
22extern int isdn_ppp_autodial_filter(struct sk_buff *, isdn_net_local *);
23extern int isdn_ppp_xmit(struct sk_buff *, struct net_device *);
24extern void isdn_ppp_receive(isdn_net_dev *, isdn_net_local *, struct sk_buff *);
25extern int isdn_ppp_dev_ioctl(struct net_device *, struct ifreq *, int);
26extern unsigned int isdn_ppp_poll(struct file *, struct poll_table_struct *);
27extern int isdn_ppp_ioctl(int, struct file *, unsigned int, unsigned long);
28extern void isdn_ppp_release(int, struct file *);
29extern int isdn_ppp_dial_slave(char *);
30extern void isdn_ppp_wakeup_daemon(isdn_net_local *);
31
32extern int isdn_ppp_register_compressor(struct isdn_ppp_compressor *ipc);
33extern int isdn_ppp_unregister_compressor(struct isdn_ppp_compressor *ipc);
34
35#define IPPP_OPEN 0x01
36#define IPPP_CONNECT 0x02
37#define IPPP_CLOSEWAIT 0x04
38#define IPPP_NOBLOCK 0x08
39#define IPPP_ASSIGNED 0x10
40
41#define IPPP_MAX_HEADER 10
42
43
diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c
new file mode 100644
index 000000000000..e21007eca0f0
--- /dev/null
+++ b/drivers/isdn/i4l/isdn_tty.c
@@ -0,0 +1,3911 @@
1/* $Id: isdn_tty.c,v 1.1.2.3 2004/02/10 01:07:13 keil Exp $
2 *
3 * Linux ISDN subsystem, tty functions and AT-command emulator (linklevel).
4 *
5 * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
6 * Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 */
12#undef ISDN_TTY_STAT_DEBUG
13
14#include <linux/config.h>
15#include <linux/isdn.h>
16#include <linux/delay.h>
17#include "isdn_common.h"
18#include "isdn_tty.h"
19#ifdef CONFIG_ISDN_AUDIO
20#include "isdn_audio.h"
21#define VBUF 0x3e0
22#define VBUFX (VBUF/16)
23#endif
24
25#define FIX_FILE_TRANSFER
26#define DUMMY_HAYES_AT
27
28/* Prototypes */
29
30static int isdn_tty_edit_at(const char *, int, modem_info *);
31static void isdn_tty_check_esc(const u_char *, u_char, int, int *, u_long *);
32static void isdn_tty_modem_reset_regs(modem_info *, int);
33static void isdn_tty_cmd_ATA(modem_info *);
34static void isdn_tty_flush_buffer(struct tty_struct *);
35static void isdn_tty_modem_result(int, modem_info *);
36#ifdef CONFIG_ISDN_AUDIO
37static int isdn_tty_countDLE(unsigned char *, int);
38#endif
39
40/* Leave this unchanged unless you know what you do! */
41#define MODEM_PARANOIA_CHECK
42#define MODEM_DO_RESTART
43
44static int bit2si[8] =
45{1, 5, 7, 7, 7, 7, 7, 7};
46static int si2bit[8] =
47{4, 1, 4, 4, 4, 4, 4, 4};
48
49char *isdn_tty_revision = "$Revision: 1.1.2.3 $";
50
51
52/* isdn_tty_try_read() is called from within isdn_tty_rcv_skb()
53 * to stuff incoming data directly into a tty's flip-buffer. This
54 * is done to speed up tty-receiving if the receive-queue is empty.
55 * This routine MUST be called with interrupts off.
56 * Return:
57 * 1 = Success
58 * 0 = Failure, data has to be buffered and later processed by
59 * isdn_tty_readmodem().
60 */
61static int
62isdn_tty_try_read(modem_info * info, struct sk_buff *skb)
63{
64 int c;
65 int len;
66 struct tty_struct *tty;
67
68 if (info->online) {
69 if ((tty = info->tty)) {
70 if (info->mcr & UART_MCR_RTS) {
71 c = TTY_FLIPBUF_SIZE - tty->flip.count;
72 len = skb->len
73#ifdef CONFIG_ISDN_AUDIO
74 + ISDN_AUDIO_SKB_DLECOUNT(skb)
75#endif
76 ;
77 if (c >= len) {
78#ifdef CONFIG_ISDN_AUDIO
79 if (ISDN_AUDIO_SKB_DLECOUNT(skb))
80 while (skb->len--) {
81 if (*skb->data == DLE)
82 tty_insert_flip_char(tty, DLE, 0);
83 tty_insert_flip_char(tty, *skb->data++, 0);
84 } else {
85#endif
86 memcpy(tty->flip.char_buf_ptr,
87 skb->data, len);
88 tty->flip.count += len;
89 tty->flip.char_buf_ptr += len;
90 memset(tty->flip.flag_buf_ptr, 0, len);
91 tty->flip.flag_buf_ptr += len;
92#ifdef CONFIG_ISDN_AUDIO
93 }
94#endif
95 if (info->emu.mdmreg[REG_CPPP] & BIT_CPPP)
96 tty->flip.flag_buf_ptr[len - 1] = 0xff;
97 schedule_delayed_work(&tty->flip.work, 1);
98 kfree_skb(skb);
99 return 1;
100 }
101 }
102 }
103 }
104 return 0;
105}
106
107/* isdn_tty_readmodem() is called periodically from within timer-interrupt.
108 * It tries getting received data from the receive queue an stuff it into
109 * the tty's flip-buffer.
110 */
111void
112isdn_tty_readmodem(void)
113{
114 int resched = 0;
115 int midx;
116 int i;
117 int c;
118 int r;
119 struct tty_struct *tty;
120 modem_info *info;
121
122 for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
123 if ((midx = dev->m_idx[i]) >= 0) {
124 info = &dev->mdm.info[midx];
125 if (info->online) {
126 r = 0;
127#ifdef CONFIG_ISDN_AUDIO
128 isdn_audio_eval_dtmf(info);
129 if ((info->vonline & 1) && (info->emu.vpar[1]))
130 isdn_audio_eval_silence(info);
131#endif
132 if ((tty = info->tty)) {
133 if (info->mcr & UART_MCR_RTS) {
134 c = TTY_FLIPBUF_SIZE - tty->flip.count;
135 if (c > 0) {
136 r = isdn_readbchan(info->isdn_driver, info->isdn_channel,
137 tty->flip.char_buf_ptr,
138 tty->flip.flag_buf_ptr, c, NULL);
139 /* CISCO AsyncPPP Hack */
140 if (!(info->emu.mdmreg[REG_CPPP] & BIT_CPPP))
141 memset(tty->flip.flag_buf_ptr, 0, r);
142 tty->flip.count += r;
143 tty->flip.flag_buf_ptr += r;
144 tty->flip.char_buf_ptr += r;
145 if (r)
146 schedule_delayed_work(&tty->flip.work, 1);
147 }
148 } else
149 r = 1;
150 } else
151 r = 1;
152 if (r) {
153 info->rcvsched = 0;
154 resched = 1;
155 } else
156 info->rcvsched = 1;
157 }
158 }
159 }
160 if (!resched)
161 isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 0);
162}
163
164int
165isdn_tty_rcv_skb(int i, int di, int channel, struct sk_buff *skb)
166{
167 ulong flags;
168 int midx;
169#ifdef CONFIG_ISDN_AUDIO
170 int ifmt;
171#endif
172 modem_info *info;
173
174 if ((midx = dev->m_idx[i]) < 0) {
175 /* if midx is invalid, packet is not for tty */
176 return 0;
177 }
178 info = &dev->mdm.info[midx];
179#ifdef CONFIG_ISDN_AUDIO
180 ifmt = 1;
181
182 if ((info->vonline) && (!info->emu.vpar[4]))
183 isdn_audio_calc_dtmf(info, skb->data, skb->len, ifmt);
184 if ((info->vonline & 1) && (info->emu.vpar[1]))
185 isdn_audio_calc_silence(info, skb->data, skb->len, ifmt);
186#endif
187 if ((info->online < 2)
188#ifdef CONFIG_ISDN_AUDIO
189 && (!(info->vonline & 1))
190#endif
191 ) {
192 /* If Modem not listening, drop data */
193 kfree_skb(skb);
194 return 1;
195 }
196 if (info->emu.mdmreg[REG_T70] & BIT_T70) {
197 if (info->emu.mdmreg[REG_T70] & BIT_T70_EXT) {
198 /* T.70 decoding: throw away the T.70 header (2 or 4 bytes) */
199 if (skb->data[0] == 3) /* pure data packet -> 4 byte headers */
200 skb_pull(skb, 4);
201 else
202 if (skb->data[0] == 1) /* keepalive packet -> 2 byte hdr */
203 skb_pull(skb, 2);
204 } else
205 /* T.70 decoding: Simply throw away the T.70 header (4 bytes) */
206 if ((skb->data[0] == 1) && ((skb->data[1] == 0) || (skb->data[1] == 1)))
207 skb_pull(skb, 4);
208 }
209#ifdef CONFIG_ISDN_AUDIO
210 ISDN_AUDIO_SKB_DLECOUNT(skb) = 0;
211 ISDN_AUDIO_SKB_LOCK(skb) = 0;
212 if (info->vonline & 1) {
213 /* voice conversion/compression */
214 switch (info->emu.vpar[3]) {
215 case 2:
216 case 3:
217 case 4:
218 /* adpcm
219 * Since compressed data takes less
220 * space, we can overwrite the buffer.
221 */
222 skb_trim(skb, isdn_audio_xlaw2adpcm(info->adpcmr,
223 ifmt,
224 skb->data,
225 skb->data,
226 skb->len));
227 break;
228 case 5:
229 /* a-law */
230 if (!ifmt)
231 isdn_audio_ulaw2alaw(skb->data, skb->len);
232 break;
233 case 6:
234 /* u-law */
235 if (ifmt)
236 isdn_audio_alaw2ulaw(skb->data, skb->len);
237 break;
238 }
239 ISDN_AUDIO_SKB_DLECOUNT(skb) =
240 isdn_tty_countDLE(skb->data, skb->len);
241 }
242#ifdef CONFIG_ISDN_TTY_FAX
243 else {
244 if (info->faxonline & 2) {
245 isdn_tty_fax_bitorder(info, skb);
246 ISDN_AUDIO_SKB_DLECOUNT(skb) =
247 isdn_tty_countDLE(skb->data, skb->len);
248 }
249 }
250#endif
251#endif
252 /* Try to deliver directly via tty-flip-buf if queue is empty */
253 spin_lock_irqsave(&info->readlock, flags);
254 if (skb_queue_empty(&dev->drv[di]->rpqueue[channel]))
255 if (isdn_tty_try_read(info, skb)) {
256 spin_unlock_irqrestore(&info->readlock, flags);
257 return 1;
258 }
259 /* Direct deliver failed or queue wasn't empty.
260 * Queue up for later dequeueing via timer-irq.
261 */
262 __skb_queue_tail(&dev->drv[di]->rpqueue[channel], skb);
263 dev->drv[di]->rcvcount[channel] +=
264 (skb->len
265#ifdef CONFIG_ISDN_AUDIO
266 + ISDN_AUDIO_SKB_DLECOUNT(skb)
267#endif
268 );
269 spin_unlock_irqrestore(&info->readlock, flags);
270 /* Schedule dequeuing */
271 if ((dev->modempoll) && (info->rcvsched))
272 isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
273 return 1;
274}
275
276void
277isdn_tty_cleanup_xmit(modem_info * info)
278{
279 skb_queue_purge(&info->xmit_queue);
280#ifdef CONFIG_ISDN_AUDIO
281 skb_queue_purge(&info->dtmf_queue);
282#endif
283}
284
285static void
286isdn_tty_tint(modem_info * info)
287{
288 struct sk_buff *skb = skb_dequeue(&info->xmit_queue);
289 int len, slen;
290
291 if (!skb)
292 return;
293 len = skb->len;
294 if ((slen = isdn_writebuf_skb_stub(info->isdn_driver,
295 info->isdn_channel, 1, skb)) == len) {
296 struct tty_struct *tty = info->tty;
297 info->send_outstanding++;
298 info->msr &= ~UART_MSR_CTS;
299 info->lsr &= ~UART_LSR_TEMT;
300 tty_wakeup(tty);
301 return;
302 }
303 if (slen < 0) {
304 /* Error: no channel, already shutdown, or wrong parameter */
305 dev_kfree_skb(skb);
306 return;
307 }
308 skb_queue_head(&info->xmit_queue, skb);
309}
310
311#ifdef CONFIG_ISDN_AUDIO
312static int
313isdn_tty_countDLE(unsigned char *buf, int len)
314{
315 int count = 0;
316
317 while (len--)
318 if (*buf++ == DLE)
319 count++;
320 return count;
321}
322
323/* This routine is called from within isdn_tty_write() to perform
324 * DLE-decoding when sending audio-data.
325 */
326static int
327isdn_tty_handleDLEdown(modem_info * info, atemu * m, int len)
328{
329 unsigned char *p = &info->xmit_buf[info->xmit_count];
330 int count = 0;
331
332 while (len > 0) {
333 if (m->lastDLE) {
334 m->lastDLE = 0;
335 switch (*p) {
336 case DLE:
337 /* Escape code */
338 if (len > 1)
339 memmove(p, p + 1, len - 1);
340 p--;
341 count++;
342 break;
343 case ETX:
344 /* End of data */
345 info->vonline |= 4;
346 return count;
347 case DC4:
348 /* Abort RX */
349 info->vonline &= ~1;
350#ifdef ISDN_DEBUG_MODEM_VOICE
351 printk(KERN_DEBUG
352 "DLEdown: got DLE-DC4, send DLE-ETX on ttyI%d\n",
353 info->line);
354#endif
355 isdn_tty_at_cout("\020\003", info);
356 if (!info->vonline) {
357#ifdef ISDN_DEBUG_MODEM_VOICE
358 printk(KERN_DEBUG
359 "DLEdown: send VCON on ttyI%d\n",
360 info->line);
361#endif
362 isdn_tty_at_cout("\r\nVCON\r\n", info);
363 }
364 /* Fall through */
365 case 'q':
366 case 's':
367 /* Silence */
368 if (len > 1)
369 memmove(p, p + 1, len - 1);
370 p--;
371 break;
372 }
373 } else {
374 if (*p == DLE)
375 m->lastDLE = 1;
376 else
377 count++;
378 }
379 p++;
380 len--;
381 }
382 if (len < 0) {
383 printk(KERN_WARNING "isdn_tty: len<0 in DLEdown\n");
384 return 0;
385 }
386 return count;
387}
388
389/* This routine is called from within isdn_tty_write() when receiving
390 * audio-data. It interrupts receiving, if an character other than
391 * ^S or ^Q is sent.
392 */
393static int
394isdn_tty_end_vrx(const char *buf, int c)
395{
396 char ch;
397
398 while (c--) {
399 ch = *buf;
400 if ((ch != 0x11) && (ch != 0x13))
401 return 1;
402 buf++;
403 }
404 return 0;
405}
406
407static int voice_cf[7] =
408{0, 0, 4, 3, 2, 0, 0};
409
410#endif /* CONFIG_ISDN_AUDIO */
411
412/* isdn_tty_senddown() is called either directly from within isdn_tty_write()
413 * or via timer-interrupt from within isdn_tty_modem_xmit(). It pulls
414 * outgoing data from the tty's xmit-buffer, handles voice-decompression or
415 * T.70 if necessary, and finally queues it up for sending via isdn_tty_tint.
416 */
417static void
418isdn_tty_senddown(modem_info * info)
419{
420 int buflen;
421 int skb_res;
422#ifdef CONFIG_ISDN_AUDIO
423 int audio_len;
424#endif
425 struct sk_buff *skb;
426
427#ifdef CONFIG_ISDN_AUDIO
428 if (info->vonline & 4) {
429 info->vonline &= ~6;
430 if (!info->vonline) {
431#ifdef ISDN_DEBUG_MODEM_VOICE
432 printk(KERN_DEBUG
433 "senddown: send VCON on ttyI%d\n",
434 info->line);
435#endif
436 isdn_tty_at_cout("\r\nVCON\r\n", info);
437 }
438 }
439#endif
440 if (!(buflen = info->xmit_count))
441 return;
442 if ((info->emu.mdmreg[REG_CTS] & BIT_CTS) != 0)
443 info->msr &= ~UART_MSR_CTS;
444 info->lsr &= ~UART_LSR_TEMT;
445 /* info->xmit_count is modified here and in isdn_tty_write().
446 * So we return here if isdn_tty_write() is in the
447 * critical section.
448 */
449 atomic_inc(&info->xmit_lock);
450 if (!(atomic_dec_and_test(&info->xmit_lock)))
451 return;
452 if (info->isdn_driver < 0) {
453 info->xmit_count = 0;
454 return;
455 }
456 skb_res = dev->drv[info->isdn_driver]->interface->hl_hdrlen + 4;
457#ifdef CONFIG_ISDN_AUDIO
458 if (info->vonline & 2)
459 audio_len = buflen * voice_cf[info->emu.vpar[3]];
460 else
461 audio_len = 0;
462 skb = dev_alloc_skb(skb_res + buflen + audio_len);
463#else
464 skb = dev_alloc_skb(skb_res + buflen);
465#endif
466 if (!skb) {
467 printk(KERN_WARNING
468 "isdn_tty: Out of memory in ttyI%d senddown\n",
469 info->line);
470 return;
471 }
472 skb_reserve(skb, skb_res);
473 memcpy(skb_put(skb, buflen), info->xmit_buf, buflen);
474 info->xmit_count = 0;
475#ifdef CONFIG_ISDN_AUDIO
476 if (info->vonline & 2) {
477 /* For now, ifmt is fixed to 1 (alaw), since this
478 * is used with ISDN everywhere in the world, except
479 * US, Canada and Japan.
480 * Later, when US-ISDN protocols are implemented,
481 * this setting will depend on the D-channel protocol.
482 */
483 int ifmt = 1;
484
485 /* voice conversion/decompression */
486 switch (info->emu.vpar[3]) {
487 case 2:
488 case 3:
489 case 4:
490 /* adpcm, compatible to ZyXel 1496 modem
491 * with ROM revision 6.01
492 */
493 audio_len = isdn_audio_adpcm2xlaw(info->adpcms,
494 ifmt,
495 skb->data,
496 skb_put(skb, audio_len),
497 buflen);
498 skb_pull(skb, buflen);
499 skb_trim(skb, audio_len);
500 break;
501 case 5:
502 /* a-law */
503 if (!ifmt)
504 isdn_audio_alaw2ulaw(skb->data,
505 buflen);
506 break;
507 case 6:
508 /* u-law */
509 if (ifmt)
510 isdn_audio_ulaw2alaw(skb->data,
511 buflen);
512 break;
513 }
514 }
515#endif /* CONFIG_ISDN_AUDIO */
516 if (info->emu.mdmreg[REG_T70] & BIT_T70) {
517 /* Add T.70 simplified header */
518 if (info->emu.mdmreg[REG_T70] & BIT_T70_EXT)
519 memcpy(skb_push(skb, 2), "\1\0", 2);
520 else
521 memcpy(skb_push(skb, 4), "\1\0\1\0", 4);
522 }
523 skb_queue_tail(&info->xmit_queue, skb);
524}
525
526/************************************************************
527 *
528 * Modem-functions
529 *
530 * mostly "stolen" from original Linux-serial.c and friends.
531 *
532 ************************************************************/
533
534/* The next routine is called once from within timer-interrupt
535 * triggered within isdn_tty_modem_ncarrier(). It calls
536 * isdn_tty_modem_result() to stuff a "NO CARRIER" Message
537 * into the tty's flip-buffer.
538 */
539static void
540isdn_tty_modem_do_ncarrier(unsigned long data)
541{
542 modem_info *info = (modem_info *) data;
543 isdn_tty_modem_result(RESULT_NO_CARRIER, info);
544}
545
546/* Next routine is called, whenever the DTR-signal is raised.
547 * It checks the ncarrier-flag, and triggers the above routine
548 * when necessary. The ncarrier-flag is set, whenever DTR goes
549 * low.
550 */
551static void
552isdn_tty_modem_ncarrier(modem_info * info)
553{
554 if (info->ncarrier) {
555 info->nc_timer.expires = jiffies + HZ;
556 add_timer(&info->nc_timer);
557 }
558}
559
560/*
561 * return the usage calculated by si and layer 2 protocol
562 */
563int
564isdn_calc_usage(int si, int l2)
565{
566 int usg = ISDN_USAGE_MODEM;
567
568#ifdef CONFIG_ISDN_AUDIO
569 if (si == 1) {
570 switch(l2) {
571 case ISDN_PROTO_L2_MODEM:
572 usg = ISDN_USAGE_MODEM;
573 break;
574#ifdef CONFIG_ISDN_TTY_FAX
575 case ISDN_PROTO_L2_FAX:
576 usg = ISDN_USAGE_FAX;
577 break;
578#endif
579 case ISDN_PROTO_L2_TRANS:
580 default:
581 usg = ISDN_USAGE_VOICE;
582 break;
583 }
584 }
585#endif
586 return(usg);
587}
588
589/* isdn_tty_dial() performs dialing of a tty an the necessary
590 * setup of the lower levels before that.
591 */
592static void
593isdn_tty_dial(char *n, modem_info * info, atemu * m)
594{
595 int usg = ISDN_USAGE_MODEM;
596 int si = 7;
597 int l2 = m->mdmreg[REG_L2PROT];
598 u_long flags;
599 isdn_ctrl cmd;
600 int i;
601 int j;
602
603 for (j = 7; j >= 0; j--)
604 if (m->mdmreg[REG_SI1] & (1 << j)) {
605 si = bit2si[j];
606 break;
607 }
608 usg = isdn_calc_usage(si, l2);
609#ifdef CONFIG_ISDN_AUDIO
610 if ((si == 1) &&
611 (l2 != ISDN_PROTO_L2_MODEM)
612#ifdef CONFIG_ISDN_TTY_FAX
613 && (l2 != ISDN_PROTO_L2_FAX)
614#endif
615 ) {
616 l2 = ISDN_PROTO_L2_TRANS;
617 usg = ISDN_USAGE_VOICE;
618 }
619#endif
620 m->mdmreg[REG_SI1I] = si2bit[si];
621 spin_lock_irqsave(&dev->lock, flags);
622 i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn);
623 if (i < 0) {
624 spin_unlock_irqrestore(&dev->lock, flags);
625 isdn_tty_modem_result(RESULT_NO_DIALTONE, info);
626 } else {
627 info->isdn_driver = dev->drvmap[i];
628 info->isdn_channel = dev->chanmap[i];
629 info->drv_index = i;
630 dev->m_idx[i] = info->line;
631 dev->usage[i] |= ISDN_USAGE_OUTGOING;
632 info->last_dir = 1;
633 strcpy(info->last_num, n);
634 isdn_info_update();
635 spin_unlock_irqrestore(&dev->lock, flags);
636 cmd.driver = info->isdn_driver;
637 cmd.arg = info->isdn_channel;
638 cmd.command = ISDN_CMD_CLREAZ;
639 isdn_command(&cmd);
640 strcpy(cmd.parm.num, isdn_map_eaz2msn(m->msn, info->isdn_driver));
641 cmd.driver = info->isdn_driver;
642 cmd.command = ISDN_CMD_SETEAZ;
643 isdn_command(&cmd);
644 cmd.driver = info->isdn_driver;
645 cmd.command = ISDN_CMD_SETL2;
646 info->last_l2 = l2;
647 cmd.arg = info->isdn_channel + (l2 << 8);
648 isdn_command(&cmd);
649 cmd.driver = info->isdn_driver;
650 cmd.command = ISDN_CMD_SETL3;
651 cmd.arg = info->isdn_channel + (m->mdmreg[REG_L3PROT] << 8);
652#ifdef CONFIG_ISDN_TTY_FAX
653 if (l2 == ISDN_PROTO_L2_FAX) {
654 cmd.parm.fax = info->fax;
655 info->fax->direction = ISDN_TTY_FAX_CONN_OUT;
656 }
657#endif
658 isdn_command(&cmd);
659 cmd.driver = info->isdn_driver;
660 cmd.arg = info->isdn_channel;
661 sprintf(cmd.parm.setup.phone, "%s", n);
662 sprintf(cmd.parm.setup.eazmsn, "%s",
663 isdn_map_eaz2msn(m->msn, info->isdn_driver));
664 cmd.parm.setup.si1 = si;
665 cmd.parm.setup.si2 = m->mdmreg[REG_SI2];
666 cmd.command = ISDN_CMD_DIAL;
667 info->dialing = 1;
668 info->emu.carrierwait = 0;
669 strcpy(dev->num[i], n);
670 isdn_info_update();
671 isdn_command(&cmd);
672 isdn_timer_ctrl(ISDN_TIMER_CARRIER, 1);
673 }
674}
675
676/* isdn_tty_hangup() disassociates a tty from the real
677 * ISDN-line (hangup). The usage-status is cleared
678 * and some cleanup is done also.
679 */
680void
681isdn_tty_modem_hup(modem_info * info, int local)
682{
683 isdn_ctrl cmd;
684 int di, ch;
685
686 if (!info)
687 return;
688
689 di = info->isdn_driver;
690 ch = info->isdn_channel;
691 if (di < 0 || ch < 0)
692 return;
693
694 info->isdn_driver = -1;
695 info->isdn_channel = -1;
696
697#ifdef ISDN_DEBUG_MODEM_HUP
698 printk(KERN_DEBUG "Mhup ttyI%d\n", info->line);
699#endif
700 info->rcvsched = 0;
701 isdn_tty_flush_buffer(info->tty);
702 if (info->online) {
703 info->last_lhup = local;
704 info->online = 0;
705 isdn_tty_modem_result(RESULT_NO_CARRIER, info);
706 }
707#ifdef CONFIG_ISDN_AUDIO
708 info->vonline = 0;
709#ifdef CONFIG_ISDN_TTY_FAX
710 info->faxonline = 0;
711 info->fax->phase = ISDN_FAX_PHASE_IDLE;
712#endif
713 info->emu.vpar[4] = 0;
714 info->emu.vpar[5] = 8;
715 if (info->dtmf_state) {
716 kfree(info->dtmf_state);
717 info->dtmf_state = NULL;
718 }
719 if (info->silence_state) {
720 kfree(info->silence_state);
721 info->silence_state = NULL;
722 }
723 if (info->adpcms) {
724 kfree(info->adpcms);
725 info->adpcms = NULL;
726 }
727 if (info->adpcmr) {
728 kfree(info->adpcmr);
729 info->adpcmr = NULL;
730 }
731#endif
732 if ((info->msr & UART_MSR_RI) &&
733 (info->emu.mdmreg[REG_RUNG] & BIT_RUNG))
734 isdn_tty_modem_result(RESULT_RUNG, info);
735 info->msr &= ~(UART_MSR_DCD | UART_MSR_RI);
736 info->lsr |= UART_LSR_TEMT;
737
738 if (local) {
739 cmd.driver = di;
740 cmd.command = ISDN_CMD_HANGUP;
741 cmd.arg = ch;
742 isdn_command(&cmd);
743 }
744
745 isdn_all_eaz(di, ch);
746 info->emu.mdmreg[REG_RINGCNT] = 0;
747 isdn_free_channel(di, ch, 0);
748
749 if (info->drv_index >= 0) {
750 dev->m_idx[info->drv_index] = -1;
751 info->drv_index = -1;
752 }
753}
754
755/*
756 * Begin of a CAPI like interface, currently used only for
757 * supplementary service (CAPI 2.0 part III)
758 */
759#include <linux/isdn/capicmd.h>
760
761int
762isdn_tty_capi_facility(capi_msg *cm) {
763 return(-1); /* dummy */
764}
765
766/* isdn_tty_suspend() tries to suspend the current tty connection
767 */
768static void
769isdn_tty_suspend(char *id, modem_info * info, atemu * m)
770{
771 isdn_ctrl cmd;
772
773 int l;
774
775 if (!info)
776 return;
777
778#ifdef ISDN_DEBUG_MODEM_SERVICES
779 printk(KERN_DEBUG "Msusp ttyI%d\n", info->line);
780#endif
781 l = strlen(id);
782 if ((info->isdn_driver >= 0)) {
783 cmd.parm.cmsg.Length = l+18;
784 cmd.parm.cmsg.Command = CAPI_FACILITY;
785 cmd.parm.cmsg.Subcommand = CAPI_REQ;
786 cmd.parm.cmsg.adr.Controller = info->isdn_driver + 1;
787 cmd.parm.cmsg.para[0] = 3; /* 16 bit 0x0003 suplementary service */
788 cmd.parm.cmsg.para[1] = 0;
789 cmd.parm.cmsg.para[2] = l + 3;
790 cmd.parm.cmsg.para[3] = 4; /* 16 bit 0x0004 Suspend */
791 cmd.parm.cmsg.para[4] = 0;
792 cmd.parm.cmsg.para[5] = l;
793 strncpy(&cmd.parm.cmsg.para[6], id, l);
794 cmd.command = CAPI_PUT_MESSAGE;
795 cmd.driver = info->isdn_driver;
796 cmd.arg = info->isdn_channel;
797 isdn_command(&cmd);
798 }
799}
800
801/* isdn_tty_resume() tries to resume a suspended call
802 * setup of the lower levels before that. unfortunatly here is no
803 * checking for compatibility of used protocols implemented by Q931
804 * It does the same things like isdn_tty_dial, the last command
805 * is different, may be we can merge it.
806 */
807
808static void
809isdn_tty_resume(char *id, modem_info * info, atemu * m)
810{
811 int usg = ISDN_USAGE_MODEM;
812 int si = 7;
813 int l2 = m->mdmreg[REG_L2PROT];
814 isdn_ctrl cmd;
815 ulong flags;
816 int i;
817 int j;
818 int l;
819
820 l = strlen(id);
821 for (j = 7; j >= 0; j--)
822 if (m->mdmreg[REG_SI1] & (1 << j)) {
823 si = bit2si[j];
824 break;
825 }
826 usg = isdn_calc_usage(si, l2);
827#ifdef CONFIG_ISDN_AUDIO
828 if ((si == 1) &&
829 (l2 != ISDN_PROTO_L2_MODEM)
830#ifdef CONFIG_ISDN_TTY_FAX
831 && (l2 != ISDN_PROTO_L2_FAX)
832#endif
833 ) {
834 l2 = ISDN_PROTO_L2_TRANS;
835 usg = ISDN_USAGE_VOICE;
836 }
837#endif
838 m->mdmreg[REG_SI1I] = si2bit[si];
839 spin_lock_irqsave(&dev->lock, flags);
840 i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn);
841 if (i < 0) {
842 spin_unlock_irqrestore(&dev->lock, flags);
843 isdn_tty_modem_result(RESULT_NO_DIALTONE, info);
844 } else {
845 info->isdn_driver = dev->drvmap[i];
846 info->isdn_channel = dev->chanmap[i];
847 info->drv_index = i;
848 dev->m_idx[i] = info->line;
849 dev->usage[i] |= ISDN_USAGE_OUTGOING;
850 info->last_dir = 1;
851// strcpy(info->last_num, n);
852 isdn_info_update();
853 spin_unlock_irqrestore(&dev->lock, flags);
854 cmd.driver = info->isdn_driver;
855 cmd.arg = info->isdn_channel;
856 cmd.command = ISDN_CMD_CLREAZ;
857 isdn_command(&cmd);
858 strcpy(cmd.parm.num, isdn_map_eaz2msn(m->msn, info->isdn_driver));
859 cmd.driver = info->isdn_driver;
860 cmd.command = ISDN_CMD_SETEAZ;
861 isdn_command(&cmd);
862 cmd.driver = info->isdn_driver;
863 cmd.command = ISDN_CMD_SETL2;
864 info->last_l2 = l2;
865 cmd.arg = info->isdn_channel + (l2 << 8);
866 isdn_command(&cmd);
867 cmd.driver = info->isdn_driver;
868 cmd.command = ISDN_CMD_SETL3;
869 cmd.arg = info->isdn_channel + (m->mdmreg[REG_L3PROT] << 8);
870 isdn_command(&cmd);
871 cmd.driver = info->isdn_driver;
872 cmd.arg = info->isdn_channel;
873 cmd.parm.cmsg.Length = l+18;
874 cmd.parm.cmsg.Command = CAPI_FACILITY;
875 cmd.parm.cmsg.Subcommand = CAPI_REQ;
876 cmd.parm.cmsg.adr.Controller = info->isdn_driver + 1;
877 cmd.parm.cmsg.para[0] = 3; /* 16 bit 0x0003 suplementary service */
878 cmd.parm.cmsg.para[1] = 0;
879 cmd.parm.cmsg.para[2] = l+3;
880 cmd.parm.cmsg.para[3] = 5; /* 16 bit 0x0005 Resume */
881 cmd.parm.cmsg.para[4] = 0;
882 cmd.parm.cmsg.para[5] = l;
883 strncpy(&cmd.parm.cmsg.para[6], id, l);
884 cmd.command =CAPI_PUT_MESSAGE;
885 info->dialing = 1;
886// strcpy(dev->num[i], n);
887 isdn_info_update();
888 isdn_command(&cmd);
889 isdn_timer_ctrl(ISDN_TIMER_CARRIER, 1);
890 }
891}
892
893/* isdn_tty_send_msg() sends a message to a HL driver
894 * This is used for hybrid modem cards to send AT commands to it
895 */
896
897static void
898isdn_tty_send_msg(modem_info * info, atemu * m, char *msg)
899{
900 int usg = ISDN_USAGE_MODEM;
901 int si = 7;
902 int l2 = m->mdmreg[REG_L2PROT];
903 isdn_ctrl cmd;
904 ulong flags;
905 int i;
906 int j;
907 int l;
908
909 l = strlen(msg);
910 if (!l) {
911 isdn_tty_modem_result(RESULT_ERROR, info);
912 return;
913 }
914 for (j = 7; j >= 0; j--)
915 if (m->mdmreg[REG_SI1] & (1 << j)) {
916 si = bit2si[j];
917 break;
918 }
919 usg = isdn_calc_usage(si, l2);
920#ifdef CONFIG_ISDN_AUDIO
921 if ((si == 1) &&
922 (l2 != ISDN_PROTO_L2_MODEM)
923#ifdef CONFIG_ISDN_TTY_FAX
924 && (l2 != ISDN_PROTO_L2_FAX)
925#endif
926 ) {
927 l2 = ISDN_PROTO_L2_TRANS;
928 usg = ISDN_USAGE_VOICE;
929 }
930#endif
931 m->mdmreg[REG_SI1I] = si2bit[si];
932 spin_lock_irqsave(&dev->lock, flags);
933 i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn);
934 if (i < 0) {
935 spin_unlock_irqrestore(&dev->lock, flags);
936 isdn_tty_modem_result(RESULT_NO_DIALTONE, info);
937 } else {
938 info->isdn_driver = dev->drvmap[i];
939 info->isdn_channel = dev->chanmap[i];
940 info->drv_index = i;
941 dev->m_idx[i] = info->line;
942 dev->usage[i] |= ISDN_USAGE_OUTGOING;
943 info->last_dir = 1;
944 isdn_info_update();
945 spin_unlock_irqrestore(&dev->lock, flags);
946 cmd.driver = info->isdn_driver;
947 cmd.arg = info->isdn_channel;
948 cmd.command = ISDN_CMD_CLREAZ;
949 isdn_command(&cmd);
950 strcpy(cmd.parm.num, isdn_map_eaz2msn(m->msn, info->isdn_driver));
951 cmd.driver = info->isdn_driver;
952 cmd.command = ISDN_CMD_SETEAZ;
953 isdn_command(&cmd);
954 cmd.driver = info->isdn_driver;
955 cmd.command = ISDN_CMD_SETL2;
956 info->last_l2 = l2;
957 cmd.arg = info->isdn_channel + (l2 << 8);
958 isdn_command(&cmd);
959 cmd.driver = info->isdn_driver;
960 cmd.command = ISDN_CMD_SETL3;
961 cmd.arg = info->isdn_channel + (m->mdmreg[REG_L3PROT] << 8);
962 isdn_command(&cmd);
963 cmd.driver = info->isdn_driver;
964 cmd.arg = info->isdn_channel;
965 cmd.parm.cmsg.Length = l+14;
966 cmd.parm.cmsg.Command = CAPI_MANUFACTURER;
967 cmd.parm.cmsg.Subcommand = CAPI_REQ;
968 cmd.parm.cmsg.adr.Controller = info->isdn_driver + 1;
969 cmd.parm.cmsg.para[0] = l+1;
970 strncpy(&cmd.parm.cmsg.para[1], msg, l);
971 cmd.parm.cmsg.para[l+1] = 0xd;
972 cmd.command =CAPI_PUT_MESSAGE;
973/* info->dialing = 1;
974 strcpy(dev->num[i], n);
975 isdn_info_update();
976*/
977 isdn_command(&cmd);
978 }
979}
980
981static inline int
982isdn_tty_paranoia_check(modem_info *info, char *name, const char *routine)
983{
984#ifdef MODEM_PARANOIA_CHECK
985 if (!info) {
986 printk(KERN_WARNING "isdn_tty: null info_struct for %s in %s\n",
987 name, routine);
988 return 1;
989 }
990 if (info->magic != ISDN_ASYNC_MAGIC) {
991 printk(KERN_WARNING "isdn_tty: bad magic for modem struct %s in %s\n",
992 name, routine);
993 return 1;
994 }
995#endif
996 return 0;
997}
998
999/*
1000 * This routine is called to set the UART divisor registers to match
1001 * the specified baud rate for a serial port.
1002 */
1003static void
1004isdn_tty_change_speed(modem_info * info)
1005{
1006 uint cflag,
1007 cval,
1008 fcr,
1009 quot;
1010 int i;
1011
1012 if (!info->tty || !info->tty->termios)
1013 return;
1014 cflag = info->tty->termios->c_cflag;
1015
1016 quot = i = cflag & CBAUD;
1017 if (i & CBAUDEX) {
1018 i &= ~CBAUDEX;
1019 if (i < 1 || i > 2)
1020 info->tty->termios->c_cflag &= ~CBAUDEX;
1021 else
1022 i += 15;
1023 }
1024 if (quot) {
1025 info->mcr |= UART_MCR_DTR;
1026 isdn_tty_modem_ncarrier(info);
1027 } else {
1028 info->mcr &= ~UART_MCR_DTR;
1029 if (info->emu.mdmreg[REG_DTRHUP] & BIT_DTRHUP) {
1030#ifdef ISDN_DEBUG_MODEM_HUP
1031 printk(KERN_DEBUG "Mhup in changespeed\n");
1032#endif
1033 if (info->online)
1034 info->ncarrier = 1;
1035 isdn_tty_modem_reset_regs(info, 0);
1036 isdn_tty_modem_hup(info, 1);
1037 }
1038 return;
1039 }
1040 /* byte size and parity */
1041 cval = cflag & (CSIZE | CSTOPB);
1042 cval >>= 4;
1043 if (cflag & PARENB)
1044 cval |= UART_LCR_PARITY;
1045 if (!(cflag & PARODD))
1046 cval |= UART_LCR_EPAR;
1047 fcr = 0;
1048
1049 /* CTS flow control flag and modem status interrupts */
1050 if (cflag & CRTSCTS) {
1051 info->flags |= ISDN_ASYNC_CTS_FLOW;
1052 } else
1053 info->flags &= ~ISDN_ASYNC_CTS_FLOW;
1054 if (cflag & CLOCAL)
1055 info->flags &= ~ISDN_ASYNC_CHECK_CD;
1056 else {
1057 info->flags |= ISDN_ASYNC_CHECK_CD;
1058 }
1059}
1060
1061static int
1062isdn_tty_startup(modem_info * info)
1063{
1064 if (info->flags & ISDN_ASYNC_INITIALIZED)
1065 return 0;
1066 isdn_lock_drivers();
1067#ifdef ISDN_DEBUG_MODEM_OPEN
1068 printk(KERN_DEBUG "starting up ttyi%d ...\n", info->line);
1069#endif
1070 /*
1071 * Now, initialize the UART
1072 */
1073 info->mcr = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2;
1074 if (info->tty)
1075 clear_bit(TTY_IO_ERROR, &info->tty->flags);
1076 /*
1077 * and set the speed of the serial port
1078 */
1079 isdn_tty_change_speed(info);
1080
1081 info->flags |= ISDN_ASYNC_INITIALIZED;
1082 info->msr |= (UART_MSR_DSR | UART_MSR_CTS);
1083 info->send_outstanding = 0;
1084 return 0;
1085}
1086
1087/*
1088 * This routine will shutdown a serial port; interrupts are disabled, and
1089 * DTR is dropped if the hangup on close termio flag is on.
1090 */
1091static void
1092isdn_tty_shutdown(modem_info * info)
1093{
1094 if (!(info->flags & ISDN_ASYNC_INITIALIZED))
1095 return;
1096#ifdef ISDN_DEBUG_MODEM_OPEN
1097 printk(KERN_DEBUG "Shutting down isdnmodem port %d ....\n", info->line);
1098#endif
1099 isdn_unlock_drivers();
1100 info->msr &= ~UART_MSR_RI;
1101 if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
1102 info->mcr &= ~(UART_MCR_DTR | UART_MCR_RTS);
1103 if (info->emu.mdmreg[REG_DTRHUP] & BIT_DTRHUP) {
1104 isdn_tty_modem_reset_regs(info, 0);
1105#ifdef ISDN_DEBUG_MODEM_HUP
1106 printk(KERN_DEBUG "Mhup in isdn_tty_shutdown\n");
1107#endif
1108 isdn_tty_modem_hup(info, 1);
1109 }
1110 }
1111 if (info->tty)
1112 set_bit(TTY_IO_ERROR, &info->tty->flags);
1113
1114 info->flags &= ~ISDN_ASYNC_INITIALIZED;
1115}
1116
1117/* isdn_tty_write() is the main send-routine. It is called from the upper
1118 * levels within the kernel to perform sending data. Depending on the
1119 * online-flag it either directs output to the at-command-interpreter or
1120 * to the lower level. Additional tasks done here:
1121 * - If online, check for escape-sequence (+++)
1122 * - If sending audio-data, call isdn_tty_DLEdown() to parse DLE-codes.
1123 * - If receiving audio-data, call isdn_tty_end_vrx() to abort if needed.
1124 * - If dialing, abort dial.
1125 */
1126static int
1127isdn_tty_write(struct tty_struct *tty, const u_char * buf, int count)
1128{
1129 int c;
1130 int total = 0;
1131 modem_info *info = (modem_info *) tty->driver_data;
1132 atemu *m = &info->emu;
1133
1134 if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_write"))
1135 return 0;
1136 /* See isdn_tty_senddown() */
1137 atomic_inc(&info->xmit_lock);
1138 while (1) {
1139 c = count;
1140 if (c > info->xmit_size - info->xmit_count)
1141 c = info->xmit_size - info->xmit_count;
1142 if (info->isdn_driver >= 0 && c > dev->drv[info->isdn_driver]->maxbufsize)
1143 c = dev->drv[info->isdn_driver]->maxbufsize;
1144 if (c <= 0)
1145 break;
1146 if ((info->online > 1)
1147#ifdef CONFIG_ISDN_AUDIO
1148 || (info->vonline & 3)
1149#endif
1150 ) {
1151#ifdef CONFIG_ISDN_AUDIO
1152 if (!info->vonline)
1153#endif
1154 isdn_tty_check_esc(buf, m->mdmreg[REG_ESC], c,
1155 &(m->pluscount),
1156 &(m->lastplus));
1157 memcpy(&(info->xmit_buf[info->xmit_count]), buf, c);
1158#ifdef CONFIG_ISDN_AUDIO
1159 if (info->vonline) {
1160 int cc = isdn_tty_handleDLEdown(info, m, c);
1161 if (info->vonline & 2) {
1162 if (!cc) {
1163 /* If DLE decoding results in zero-transmit, but
1164 * c originally was non-zero, do a wakeup.
1165 */
1166 tty_wakeup(tty);
1167 info->msr |= UART_MSR_CTS;
1168 info->lsr |= UART_LSR_TEMT;
1169 }
1170 info->xmit_count += cc;
1171 }
1172 if ((info->vonline & 3) == 1) {
1173 /* Do NOT handle Ctrl-Q or Ctrl-S
1174 * when in full-duplex audio mode.
1175 */
1176 if (isdn_tty_end_vrx(buf, c)) {
1177 info->vonline &= ~1;
1178#ifdef ISDN_DEBUG_MODEM_VOICE
1179 printk(KERN_DEBUG
1180 "got !^Q/^S, send DLE-ETX,VCON on ttyI%d\n",
1181 info->line);
1182#endif
1183 isdn_tty_at_cout("\020\003\r\nVCON\r\n", info);
1184 }
1185 }
1186 } else
1187 if (TTY_IS_FCLASS1(info)) {
1188 int cc = isdn_tty_handleDLEdown(info, m, c);
1189
1190 if (info->vonline & 4) { /* ETX seen */
1191 isdn_ctrl c;
1192
1193 c.command = ISDN_CMD_FAXCMD;
1194 c.driver = info->isdn_driver;
1195 c.arg = info->isdn_channel;
1196 c.parm.aux.cmd = ISDN_FAX_CLASS1_CTRL;
1197 c.parm.aux.subcmd = ETX;
1198 isdn_command(&c);
1199 }
1200 info->vonline = 0;
1201#ifdef ISDN_DEBUG_MODEM_VOICE
1202 printk(KERN_DEBUG "fax dle cc/c %d/%d\n", cc, c);
1203#endif
1204 info->xmit_count += cc;
1205 } else
1206#endif
1207 info->xmit_count += c;
1208 } else {
1209 info->msr |= UART_MSR_CTS;
1210 info->lsr |= UART_LSR_TEMT;
1211 if (info->dialing) {
1212 info->dialing = 0;
1213#ifdef ISDN_DEBUG_MODEM_HUP
1214 printk(KERN_DEBUG "Mhup in isdn_tty_write\n");
1215#endif
1216 isdn_tty_modem_result(RESULT_NO_CARRIER, info);
1217 isdn_tty_modem_hup(info, 1);
1218 } else
1219 c = isdn_tty_edit_at(buf, c, info);
1220 }
1221 buf += c;
1222 count -= c;
1223 total += c;
1224 }
1225 atomic_dec(&info->xmit_lock);
1226 if ((info->xmit_count) || (skb_queue_len(&info->xmit_queue))) {
1227 if (m->mdmreg[REG_DXMT] & BIT_DXMT) {
1228 isdn_tty_senddown(info);
1229 isdn_tty_tint(info);
1230 }
1231 isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, 1);
1232 }
1233 return total;
1234}
1235
1236static int
1237isdn_tty_write_room(struct tty_struct *tty)
1238{
1239 modem_info *info = (modem_info *) tty->driver_data;
1240 int ret;
1241
1242 if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_write_room"))
1243 return 0;
1244 if (!info->online)
1245 return info->xmit_size;
1246 ret = info->xmit_size - info->xmit_count;
1247 return (ret < 0) ? 0 : ret;
1248}
1249
1250static int
1251isdn_tty_chars_in_buffer(struct tty_struct *tty)
1252{
1253 modem_info *info = (modem_info *) tty->driver_data;
1254
1255 if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_chars_in_buffer"))
1256 return 0;
1257 if (!info->online)
1258 return 0;
1259 return (info->xmit_count);
1260}
1261
1262static void
1263isdn_tty_flush_buffer(struct tty_struct *tty)
1264{
1265 modem_info *info;
1266
1267 if (!tty) {
1268 return;
1269 }
1270 info = (modem_info *) tty->driver_data;
1271 if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_flush_buffer")) {
1272 return;
1273 }
1274 isdn_tty_cleanup_xmit(info);
1275 info->xmit_count = 0;
1276 wake_up_interruptible(&tty->write_wait);
1277 tty_wakeup(tty);
1278}
1279
1280static void
1281isdn_tty_flush_chars(struct tty_struct *tty)
1282{
1283 modem_info *info = (modem_info *) tty->driver_data;
1284
1285 if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_flush_chars"))
1286 return;
1287 if ((info->xmit_count) || (skb_queue_len(&info->xmit_queue)))
1288 isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, 1);
1289}
1290
1291/*
1292 * ------------------------------------------------------------
1293 * isdn_tty_throttle()
1294 *
1295 * This routine is called by the upper-layer tty layer to signal that
1296 * incoming characters should be throttled.
1297 * ------------------------------------------------------------
1298 */
1299static void
1300isdn_tty_throttle(struct tty_struct *tty)
1301{
1302 modem_info *info = (modem_info *) tty->driver_data;
1303
1304 if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_throttle"))
1305 return;
1306 if (I_IXOFF(tty))
1307 info->x_char = STOP_CHAR(tty);
1308 info->mcr &= ~UART_MCR_RTS;
1309}
1310
1311static void
1312isdn_tty_unthrottle(struct tty_struct *tty)
1313{
1314 modem_info *info = (modem_info *) tty->driver_data;
1315
1316 if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_unthrottle"))
1317 return;
1318 if (I_IXOFF(tty)) {
1319 if (info->x_char)
1320 info->x_char = 0;
1321 else
1322 info->x_char = START_CHAR(tty);
1323 }
1324 info->mcr |= UART_MCR_RTS;
1325}
1326
1327/*
1328 * ------------------------------------------------------------
1329 * isdn_tty_ioctl() and friends
1330 * ------------------------------------------------------------
1331 */
1332
1333/*
1334 * isdn_tty_get_lsr_info - get line status register info
1335 *
1336 * Purpose: Let user call ioctl() to get info when the UART physically
1337 * is emptied. On bus types like RS485, the transmitter must
1338 * release the bus after transmitting. This must be done when
1339 * the transmit shift register is empty, not be done when the
1340 * transmit holding register is empty. This functionality
1341 * allows RS485 driver to be written in user space.
1342 */
1343static int
1344isdn_tty_get_lsr_info(modem_info * info, uint __user * value)
1345{
1346 u_char status;
1347 uint result;
1348
1349 status = info->lsr;
1350 result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
1351 return put_user(result, value);
1352}
1353
1354
1355static int
1356isdn_tty_tiocmget(struct tty_struct *tty, struct file *file)
1357{
1358 modem_info *info = (modem_info *) tty->driver_data;
1359 u_char control, status;
1360
1361 if (isdn_tty_paranoia_check(info, tty->name, __FUNCTION__))
1362 return -ENODEV;
1363 if (tty->flags & (1 << TTY_IO_ERROR))
1364 return -EIO;
1365
1366#ifdef ISDN_DEBUG_MODEM_IOCTL
1367 printk(KERN_DEBUG "ttyI%d ioctl TIOCMGET\n", info->line);
1368#endif
1369
1370 control = info->mcr;
1371 status = info->msr;
1372 return ((control & UART_MCR_RTS) ? TIOCM_RTS : 0)
1373 | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0)
1374 | ((status & UART_MSR_DCD) ? TIOCM_CAR : 0)
1375 | ((status & UART_MSR_RI) ? TIOCM_RNG : 0)
1376 | ((status & UART_MSR_DSR) ? TIOCM_DSR : 0)
1377 | ((status & UART_MSR_CTS) ? TIOCM_CTS : 0);
1378}
1379
1380static int
1381isdn_tty_tiocmset(struct tty_struct *tty, struct file *file,
1382 unsigned int set, unsigned int clear)
1383{
1384 modem_info *info = (modem_info *) tty->driver_data;
1385
1386 if (isdn_tty_paranoia_check(info, tty->name, __FUNCTION__))
1387 return -ENODEV;
1388 if (tty->flags & (1 << TTY_IO_ERROR))
1389 return -EIO;
1390
1391#ifdef ISDN_DEBUG_MODEM_IOCTL
1392 printk(KERN_DEBUG "ttyI%d ioctl TIOCMxxx: %x %x\n", info->line, set, clear);
1393#endif
1394
1395 if (set & TIOCM_RTS)
1396 info->mcr |= UART_MCR_RTS;
1397 if (set & TIOCM_DTR) {
1398 info->mcr |= UART_MCR_DTR;
1399 isdn_tty_modem_ncarrier(info);
1400 }
1401
1402 if (clear & TIOCM_RTS)
1403 info->mcr &= ~UART_MCR_RTS;
1404 if (clear & TIOCM_DTR) {
1405 info->mcr &= ~UART_MCR_DTR;
1406 if (info->emu.mdmreg[REG_DTRHUP] & BIT_DTRHUP) {
1407 isdn_tty_modem_reset_regs(info, 0);
1408#ifdef ISDN_DEBUG_MODEM_HUP
1409 printk(KERN_DEBUG "Mhup in TIOCMSET\n");
1410#endif
1411 if (info->online)
1412 info->ncarrier = 1;
1413 isdn_tty_modem_hup(info, 1);
1414 }
1415 }
1416 return 0;
1417}
1418
1419static int
1420isdn_tty_ioctl(struct tty_struct *tty, struct file *file,
1421 uint cmd, ulong arg)
1422{
1423 modem_info *info = (modem_info *) tty->driver_data;
1424 int retval;
1425
1426 if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_ioctl"))
1427 return -ENODEV;
1428 if (tty->flags & (1 << TTY_IO_ERROR))
1429 return -EIO;
1430 switch (cmd) {
1431 case TCSBRK: /* SVID version: non-zero arg --> no break */
1432#ifdef ISDN_DEBUG_MODEM_IOCTL
1433 printk(KERN_DEBUG "ttyI%d ioctl TCSBRK\n", info->line);
1434#endif
1435 retval = tty_check_change(tty);
1436 if (retval)
1437 return retval;
1438 tty_wait_until_sent(tty, 0);
1439 return 0;
1440 case TCSBRKP: /* support for POSIX tcsendbreak() */
1441#ifdef ISDN_DEBUG_MODEM_IOCTL
1442 printk(KERN_DEBUG "ttyI%d ioctl TCSBRKP\n", info->line);
1443#endif
1444 retval = tty_check_change(tty);
1445 if (retval)
1446 return retval;
1447 tty_wait_until_sent(tty, 0);
1448 return 0;
1449 case TIOCGSOFTCAR:
1450#ifdef ISDN_DEBUG_MODEM_IOCTL
1451 printk(KERN_DEBUG "ttyI%d ioctl TIOCGSOFTCAR\n", info->line);
1452#endif
1453 return put_user(C_CLOCAL(tty) ? 1 : 0, (ulong __user *) arg);
1454 case TIOCSSOFTCAR:
1455#ifdef ISDN_DEBUG_MODEM_IOCTL
1456 printk(KERN_DEBUG "ttyI%d ioctl TIOCSSOFTCAR\n", info->line);
1457#endif
1458 if (get_user(arg, (ulong __user *) arg))
1459 return -EFAULT;
1460 tty->termios->c_cflag =
1461 ((tty->termios->c_cflag & ~CLOCAL) |
1462 (arg ? CLOCAL : 0));
1463 return 0;
1464 case TIOCSERGETLSR: /* Get line status register */
1465#ifdef ISDN_DEBUG_MODEM_IOCTL
1466 printk(KERN_DEBUG "ttyI%d ioctl TIOCSERGETLSR\n", info->line);
1467#endif
1468 return isdn_tty_get_lsr_info(info, (uint __user *) arg);
1469 default:
1470#ifdef ISDN_DEBUG_MODEM_IOCTL
1471 printk(KERN_DEBUG "UNKNOWN ioctl 0x%08x on ttyi%d\n", cmd, info->line);
1472#endif
1473 return -ENOIOCTLCMD;
1474 }
1475 return 0;
1476}
1477
1478static void
1479isdn_tty_set_termios(struct tty_struct *tty, struct termios *old_termios)
1480{
1481 modem_info *info = (modem_info *) tty->driver_data;
1482
1483 if (!old_termios)
1484 isdn_tty_change_speed(info);
1485 else {
1486 if (tty->termios->c_cflag == old_termios->c_cflag)
1487 return;
1488 isdn_tty_change_speed(info);
1489 if ((old_termios->c_cflag & CRTSCTS) &&
1490 !(tty->termios->c_cflag & CRTSCTS)) {
1491 tty->hw_stopped = 0;
1492 }
1493 }
1494}
1495
1496/*
1497 * ------------------------------------------------------------
1498 * isdn_tty_open() and friends
1499 * ------------------------------------------------------------
1500 */
1501static int
1502isdn_tty_block_til_ready(struct tty_struct *tty, struct file *filp, modem_info * info)
1503{
1504 DECLARE_WAITQUEUE(wait, NULL);
1505 int do_clocal = 0;
1506 int retval;
1507
1508 /*
1509 * If the device is in the middle of being closed, then block
1510 * until it's done, and then try again.
1511 */
1512 if (tty_hung_up_p(filp) ||
1513 (info->flags & ISDN_ASYNC_CLOSING)) {
1514 if (info->flags & ISDN_ASYNC_CLOSING)
1515 interruptible_sleep_on(&info->close_wait);
1516#ifdef MODEM_DO_RESTART
1517 if (info->flags & ISDN_ASYNC_HUP_NOTIFY)
1518 return -EAGAIN;
1519 else
1520 return -ERESTARTSYS;
1521#else
1522 return -EAGAIN;
1523#endif
1524 }
1525 /*
1526 * If non-blocking mode is set, then make the check up front
1527 * and then exit.
1528 */
1529 if ((filp->f_flags & O_NONBLOCK) ||
1530 (tty->flags & (1 << TTY_IO_ERROR))) {
1531 if (info->flags & ISDN_ASYNC_CALLOUT_ACTIVE)
1532 return -EBUSY;
1533 info->flags |= ISDN_ASYNC_NORMAL_ACTIVE;
1534 return 0;
1535 }
1536 if (info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) {
1537 if (info->normal_termios.c_cflag & CLOCAL)
1538 do_clocal = 1;
1539 } else {
1540 if (tty->termios->c_cflag & CLOCAL)
1541 do_clocal = 1;
1542 }
1543 /*
1544 * Block waiting for the carrier detect and the line to become
1545 * free (i.e., not in use by the callout). While we are in
1546 * this loop, info->count is dropped by one, so that
1547 * isdn_tty_close() knows when to free things. We restore it upon
1548 * exit, either normal or abnormal.
1549 */
1550 retval = 0;
1551 add_wait_queue(&info->open_wait, &wait);
1552#ifdef ISDN_DEBUG_MODEM_OPEN
1553 printk(KERN_DEBUG "isdn_tty_block_til_ready before block: ttyi%d, count = %d\n",
1554 info->line, info->count);
1555#endif
1556 if (!(tty_hung_up_p(filp)))
1557 info->count--;
1558 info->blocked_open++;
1559 while (1) {
1560 set_current_state(TASK_INTERRUPTIBLE);
1561 if (tty_hung_up_p(filp) ||
1562 !(info->flags & ISDN_ASYNC_INITIALIZED)) {
1563#ifdef MODEM_DO_RESTART
1564 if (info->flags & ISDN_ASYNC_HUP_NOTIFY)
1565 retval = -EAGAIN;
1566 else
1567 retval = -ERESTARTSYS;
1568#else
1569 retval = -EAGAIN;
1570#endif
1571 break;
1572 }
1573 if (!(info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) &&
1574 !(info->flags & ISDN_ASYNC_CLOSING) &&
1575 (do_clocal || (info->msr & UART_MSR_DCD))) {
1576 break;
1577 }
1578 if (signal_pending(current)) {
1579 retval = -ERESTARTSYS;
1580 break;
1581 }
1582#ifdef ISDN_DEBUG_MODEM_OPEN
1583 printk(KERN_DEBUG "isdn_tty_block_til_ready blocking: ttyi%d, count = %d\n",
1584 info->line, info->count);
1585#endif
1586 schedule();
1587 }
1588 current->state = TASK_RUNNING;
1589 remove_wait_queue(&info->open_wait, &wait);
1590 if (!tty_hung_up_p(filp))
1591 info->count++;
1592 info->blocked_open--;
1593#ifdef ISDN_DEBUG_MODEM_OPEN
1594 printk(KERN_DEBUG "isdn_tty_block_til_ready after blocking: ttyi%d, count = %d\n",
1595 info->line, info->count);
1596#endif
1597 if (retval)
1598 return retval;
1599 info->flags |= ISDN_ASYNC_NORMAL_ACTIVE;
1600 return 0;
1601}
1602
1603/*
1604 * This routine is called whenever a serial port is opened. It
1605 * enables interrupts for a serial port, linking in its async structure into
1606 * the IRQ chain. It also performs the serial-specific
1607 * initialization for the tty structure.
1608 */
1609static int
1610isdn_tty_open(struct tty_struct *tty, struct file *filp)
1611{
1612 modem_info *info;
1613 int retval, line;
1614
1615 line = tty->index;
1616 if (line < 0 || line > ISDN_MAX_CHANNELS)
1617 return -ENODEV;
1618 info = &dev->mdm.info[line];
1619 if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_open"))
1620 return -ENODEV;
1621 if (!try_module_get(info->owner)) {
1622 printk(KERN_WARNING "%s: cannot reserve module\n", __FUNCTION__);
1623 return -ENODEV;
1624 }
1625#ifdef ISDN_DEBUG_MODEM_OPEN
1626 printk(KERN_DEBUG "isdn_tty_open %s, count = %d\n", tty->name,
1627 info->count);
1628#endif
1629 info->count++;
1630 tty->driver_data = info;
1631 info->tty = tty;
1632 /*
1633 * Start up serial port
1634 */
1635 retval = isdn_tty_startup(info);
1636 if (retval) {
1637#ifdef ISDN_DEBUG_MODEM_OPEN
1638 printk(KERN_DEBUG "isdn_tty_open return after startup\n");
1639#endif
1640 module_put(info->owner);
1641 return retval;
1642 }
1643 retval = isdn_tty_block_til_ready(tty, filp, info);
1644 if (retval) {
1645#ifdef ISDN_DEBUG_MODEM_OPEN
1646 printk(KERN_DEBUG "isdn_tty_open return after isdn_tty_block_til_ready \n");
1647#endif
1648 module_put(info->owner);
1649 return retval;
1650 }
1651#ifdef ISDN_DEBUG_MODEM_OPEN
1652 printk(KERN_DEBUG "isdn_tty_open ttyi%d successful...\n", info->line);
1653#endif
1654 dev->modempoll++;
1655#ifdef ISDN_DEBUG_MODEM_OPEN
1656 printk(KERN_DEBUG "isdn_tty_open normal exit\n");
1657#endif
1658 return 0;
1659}
1660
1661static void
1662isdn_tty_close(struct tty_struct *tty, struct file *filp)
1663{
1664 modem_info *info = (modem_info *) tty->driver_data;
1665 ulong timeout;
1666
1667 if (!info || isdn_tty_paranoia_check(info, tty->name, "isdn_tty_close"))
1668 return;
1669 if (tty_hung_up_p(filp)) {
1670#ifdef ISDN_DEBUG_MODEM_OPEN
1671 printk(KERN_DEBUG "isdn_tty_close return after tty_hung_up_p\n");
1672#endif
1673 return;
1674 }
1675 if ((tty->count == 1) && (info->count != 1)) {
1676 /*
1677 * Uh, oh. tty->count is 1, which means that the tty
1678 * structure will be freed. Info->count should always
1679 * be one in these conditions. If it's greater than
1680 * one, we've got real problems, since it means the
1681 * serial port won't be shutdown.
1682 */
1683 printk(KERN_ERR "isdn_tty_close: bad port count; tty->count is 1, "
1684 "info->count is %d\n", info->count);
1685 info->count = 1;
1686 }
1687 if (--info->count < 0) {
1688 printk(KERN_ERR "isdn_tty_close: bad port count for ttyi%d: %d\n",
1689 info->line, info->count);
1690 info->count = 0;
1691 }
1692 if (info->count) {
1693#ifdef ISDN_DEBUG_MODEM_OPEN
1694 printk(KERN_DEBUG "isdn_tty_close after info->count != 0\n");
1695#endif
1696 return;
1697 }
1698 info->flags |= ISDN_ASYNC_CLOSING;
1699 /*
1700 * Save the termios structure, since this port may have
1701 * separate termios for callout and dialin.
1702 */
1703 if (info->flags & ISDN_ASYNC_NORMAL_ACTIVE)
1704 info->normal_termios = *tty->termios;
1705 if (info->flags & ISDN_ASYNC_CALLOUT_ACTIVE)
1706 info->callout_termios = *tty->termios;
1707
1708 tty->closing = 1;
1709 /*
1710 * At this point we stop accepting input. To do this, we
1711 * disable the receive line status interrupts, and tell the
1712 * interrupt driver to stop checking the data ready bit in the
1713 * line status register.
1714 */
1715 if (info->flags & ISDN_ASYNC_INITIALIZED) {
1716 tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */
1717 /*
1718 * Before we drop DTR, make sure the UART transmitter
1719 * has completely drained; this is especially
1720 * important if there is a transmit FIFO!
1721 */
1722 timeout = jiffies + HZ;
1723 while (!(info->lsr & UART_LSR_TEMT)) {
1724 set_current_state(TASK_INTERRUPTIBLE);
1725 schedule_timeout(20);
1726 if (time_after(jiffies,timeout))
1727 break;
1728 }
1729 }
1730 dev->modempoll--;
1731 isdn_tty_shutdown(info);
1732
1733 if (tty->driver->flush_buffer)
1734 tty->driver->flush_buffer(tty);
1735 tty_ldisc_flush(tty);
1736 info->tty = NULL;
1737 info->ncarrier = 0;
1738 tty->closing = 0;
1739 module_put(info->owner);
1740 if (info->blocked_open) {
1741 msleep_interruptible(500);
1742 wake_up_interruptible(&info->open_wait);
1743 }
1744 info->flags &= ~(ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CLOSING);
1745 wake_up_interruptible(&info->close_wait);
1746#ifdef ISDN_DEBUG_MODEM_OPEN
1747 printk(KERN_DEBUG "isdn_tty_close normal exit\n");
1748#endif
1749}
1750
1751/*
1752 * isdn_tty_hangup() --- called by tty_hangup() when a hangup is signaled.
1753 */
1754static void
1755isdn_tty_hangup(struct tty_struct *tty)
1756{
1757 modem_info *info = (modem_info *) tty->driver_data;
1758
1759 if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_hangup"))
1760 return;
1761 isdn_tty_shutdown(info);
1762 info->count = 0;
1763 info->flags &= ~(ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE);
1764 info->tty = NULL;
1765 wake_up_interruptible(&info->open_wait);
1766}
1767
1768/* This routine initializes all emulator-data.
1769 */
1770static void
1771isdn_tty_reset_profile(atemu * m)
1772{
1773 m->profile[0] = 0;
1774 m->profile[1] = 0;
1775 m->profile[2] = 43;
1776 m->profile[3] = 13;
1777 m->profile[4] = 10;
1778 m->profile[5] = 8;
1779 m->profile[6] = 3;
1780 m->profile[7] = 60;
1781 m->profile[8] = 2;
1782 m->profile[9] = 6;
1783 m->profile[10] = 7;
1784 m->profile[11] = 70;
1785 m->profile[12] = 0x45;
1786 m->profile[13] = 4;
1787 m->profile[14] = ISDN_PROTO_L2_X75I;
1788 m->profile[15] = ISDN_PROTO_L3_TRANS;
1789 m->profile[16] = ISDN_SERIAL_XMIT_SIZE / 16;
1790 m->profile[17] = ISDN_MODEM_WINSIZE;
1791 m->profile[18] = 4;
1792 m->profile[19] = 0;
1793 m->profile[20] = 0;
1794 m->profile[23] = 0;
1795 m->pmsn[0] = '\0';
1796 m->plmsn[0] = '\0';
1797}
1798
1799#ifdef CONFIG_ISDN_AUDIO
1800static void
1801isdn_tty_modem_reset_vpar(atemu * m)
1802{
1803 m->vpar[0] = 2; /* Voice-device (2 = phone line) */
1804 m->vpar[1] = 0; /* Silence detection level (0 = none ) */
1805 m->vpar[2] = 70; /* Silence interval (7 sec. ) */
1806 m->vpar[3] = 2; /* Compression type (1 = ADPCM-2 ) */
1807 m->vpar[4] = 0; /* DTMF detection level (0 = softcode ) */
1808 m->vpar[5] = 8; /* DTMF interval (8 * 5 ms. ) */
1809}
1810#endif
1811
1812#ifdef CONFIG_ISDN_TTY_FAX
1813static void
1814isdn_tty_modem_reset_faxpar(modem_info * info)
1815{
1816 T30_s *f = info->fax;
1817
1818 f->code = 0;
1819 f->phase = ISDN_FAX_PHASE_IDLE;
1820 f->direction = 0;
1821 f->resolution = 1; /* fine */
1822 f->rate = 5; /* 14400 bit/s */
1823 f->width = 0;
1824 f->length = 0;
1825 f->compression = 0;
1826 f->ecm = 0;
1827 f->binary = 0;
1828 f->scantime = 0;
1829 memset(&f->id[0], 32, FAXIDLEN - 1);
1830 f->id[FAXIDLEN - 1] = 0;
1831 f->badlin = 0;
1832 f->badmul = 0;
1833 f->bor = 0;
1834 f->nbc = 0;
1835 f->cq = 0;
1836 f->cr = 0;
1837 f->ctcrty = 0;
1838 f->minsp = 0;
1839 f->phcto = 30;
1840 f->rel = 0;
1841 memset(&f->pollid[0], 32, FAXIDLEN - 1);
1842 f->pollid[FAXIDLEN - 1] = 0;
1843}
1844#endif
1845
1846static void
1847isdn_tty_modem_reset_regs(modem_info * info, int force)
1848{
1849 atemu *m = &info->emu;
1850 if ((m->mdmreg[REG_DTRR] & BIT_DTRR) || force) {
1851 memcpy(m->mdmreg, m->profile, ISDN_MODEM_NUMREG);
1852 memcpy(m->msn, m->pmsn, ISDN_MSNLEN);
1853 memcpy(m->lmsn, m->plmsn, ISDN_LMSNLEN);
1854 info->xmit_size = m->mdmreg[REG_PSIZE] * 16;
1855 }
1856#ifdef CONFIG_ISDN_AUDIO
1857 isdn_tty_modem_reset_vpar(m);
1858#endif
1859#ifdef CONFIG_ISDN_TTY_FAX
1860 isdn_tty_modem_reset_faxpar(info);
1861#endif
1862 m->mdmcmdl = 0;
1863}
1864
1865static void
1866modem_write_profile(atemu * m)
1867{
1868 memcpy(m->profile, m->mdmreg, ISDN_MODEM_NUMREG);
1869 memcpy(m->pmsn, m->msn, ISDN_MSNLEN);
1870 memcpy(m->plmsn, m->lmsn, ISDN_LMSNLEN);
1871 if (dev->profd)
1872 send_sig(SIGIO, dev->profd, 1);
1873}
1874
1875static struct tty_operations modem_ops = {
1876 .open = isdn_tty_open,
1877 .close = isdn_tty_close,
1878 .write = isdn_tty_write,
1879 .flush_chars = isdn_tty_flush_chars,
1880 .write_room = isdn_tty_write_room,
1881 .chars_in_buffer = isdn_tty_chars_in_buffer,
1882 .flush_buffer = isdn_tty_flush_buffer,
1883 .ioctl = isdn_tty_ioctl,
1884 .throttle = isdn_tty_throttle,
1885 .unthrottle = isdn_tty_unthrottle,
1886 .set_termios = isdn_tty_set_termios,
1887 .hangup = isdn_tty_hangup,
1888 .tiocmget = isdn_tty_tiocmget,
1889 .tiocmset = isdn_tty_tiocmset,
1890};
1891
1892int
1893isdn_tty_modem_init(void)
1894{
1895 isdn_modem_t *m;
1896 int i, retval;
1897 modem_info *info;
1898
1899 m = &dev->mdm;
1900 m->tty_modem = alloc_tty_driver(ISDN_MAX_CHANNELS);
1901 if (!m->tty_modem)
1902 return -ENOMEM;
1903 m->tty_modem->name = "ttyI";
1904 m->tty_modem->devfs_name = "isdn/ttyI";
1905 m->tty_modem->major = ISDN_TTY_MAJOR;
1906 m->tty_modem->minor_start = 0;
1907 m->tty_modem->type = TTY_DRIVER_TYPE_SERIAL;
1908 m->tty_modem->subtype = SERIAL_TYPE_NORMAL;
1909 m->tty_modem->init_termios = tty_std_termios;
1910 m->tty_modem->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
1911 m->tty_modem->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
1912 m->tty_modem->driver_name = "isdn_tty";
1913 tty_set_operations(m->tty_modem, &modem_ops);
1914 retval = tty_register_driver(m->tty_modem);
1915 if (retval) {
1916 printk(KERN_WARNING "isdn_tty: Couldn't register modem-device\n");
1917 goto err;
1918 }
1919 for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
1920 info = &m->info[i];
1921#ifdef CONFIG_ISDN_TTY_FAX
1922 if (!(info->fax = kmalloc(sizeof(T30_s), GFP_KERNEL))) {
1923 printk(KERN_ERR "Could not allocate fax t30-buffer\n");
1924 retval = -ENOMEM;
1925 goto err_unregister;
1926 }
1927#endif
1928#ifdef MODULE
1929 info->owner = THIS_MODULE;
1930#endif
1931 spin_lock_init(&info->readlock);
1932 init_MUTEX(&info->write_sem);
1933 sprintf(info->last_cause, "0000");
1934 sprintf(info->last_num, "none");
1935 info->last_dir = 0;
1936 info->last_lhup = 1;
1937 info->last_l2 = -1;
1938 info->last_si = 0;
1939 isdn_tty_reset_profile(&info->emu);
1940 isdn_tty_modem_reset_regs(info, 1);
1941 info->magic = ISDN_ASYNC_MAGIC;
1942 info->line = i;
1943 info->tty = NULL;
1944 info->x_char = 0;
1945 info->count = 0;
1946 info->blocked_open = 0;
1947 init_waitqueue_head(&info->open_wait);
1948 init_waitqueue_head(&info->close_wait);
1949 info->isdn_driver = -1;
1950 info->isdn_channel = -1;
1951 info->drv_index = -1;
1952 info->xmit_size = ISDN_SERIAL_XMIT_SIZE;
1953 init_timer(&info->nc_timer);
1954 info->nc_timer.function = isdn_tty_modem_do_ncarrier;
1955 info->nc_timer.data = (unsigned long) info;
1956 skb_queue_head_init(&info->xmit_queue);
1957#ifdef CONFIG_ISDN_AUDIO
1958 skb_queue_head_init(&info->dtmf_queue);
1959#endif
1960 if (!(info->xmit_buf = kmalloc(ISDN_SERIAL_XMIT_MAX + 5, GFP_KERNEL))) {
1961 printk(KERN_ERR "Could not allocate modem xmit-buffer\n");
1962 retval = -ENOMEM;
1963 goto err_unregister;
1964 }
1965 /* Make room for T.70 header */
1966 info->xmit_buf += 4;
1967 }
1968 return 0;
1969err_unregister:
1970 for (i--; i >= 0; i--) {
1971 info = &m->info[i];
1972#ifdef CONFIG_ISDN_TTY_FAX
1973 kfree(info->fax);
1974#endif
1975 kfree(info->xmit_buf - 4);
1976 }
1977 tty_unregister_driver(m->tty_modem);
1978 err:
1979 put_tty_driver(m->tty_modem);
1980 m->tty_modem = NULL;
1981 return retval;
1982}
1983
1984void
1985isdn_tty_exit(void)
1986{
1987 modem_info *info;
1988 int i;
1989
1990 for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
1991 info = &dev->mdm.info[i];
1992 isdn_tty_cleanup_xmit(info);
1993#ifdef CONFIG_ISDN_TTY_FAX
1994 kfree(info->fax);
1995#endif
1996 kfree(info->xmit_buf - 4);
1997 }
1998 tty_unregister_driver(dev->mdm.tty_modem);
1999 put_tty_driver(dev->mdm.tty_modem);
2000 dev->mdm.tty_modem = NULL;
2001}
2002
2003
2004/*
2005 * isdn_tty_match_icall(char *MSN, atemu *tty_emulator, int dev_idx)
2006 * match the MSN against the MSNs (glob patterns) defined for tty_emulator,
2007 * and return 0 for match, 1 for no match, 2 if MSN could match if longer.
2008 */
2009
2010static int
2011isdn_tty_match_icall(char *cid, atemu *emu, int di)
2012{
2013#ifdef ISDN_DEBUG_MODEM_ICALL
2014 printk(KERN_DEBUG "m_fi: msn=%s lmsn=%s mmsn=%s mreg[SI1]=%d mreg[SI2]=%d\n",
2015 emu->msn, emu->lmsn, isdn_map_eaz2msn(emu->msn, di),
2016 emu->mdmreg[REG_SI1], emu->mdmreg[REG_SI2]);
2017#endif
2018 if (strlen(emu->lmsn)) {
2019 char *p = emu->lmsn;
2020 char *q;
2021 int tmp;
2022 int ret = 0;
2023
2024 while (1) {
2025 if ((q = strchr(p, ';')))
2026 *q = '\0';
2027 if ((tmp = isdn_msncmp(cid, isdn_map_eaz2msn(p, di))) > ret)
2028 ret = tmp;
2029#ifdef ISDN_DEBUG_MODEM_ICALL
2030 printk(KERN_DEBUG "m_fi: lmsnX=%s mmsn=%s -> tmp=%d\n",
2031 p, isdn_map_eaz2msn(emu->msn, di), tmp);
2032#endif
2033 if (q) {
2034 *q = ';';
2035 p = q;
2036 p++;
2037 }
2038 if (!tmp)
2039 return 0;
2040 if (!q)
2041 break;
2042 }
2043 return ret;
2044 } else {
2045 int tmp;
2046 tmp = isdn_msncmp(cid, isdn_map_eaz2msn(emu->msn, di));
2047#ifdef ISDN_DEBUG_MODEM_ICALL
2048 printk(KERN_DEBUG "m_fi: mmsn=%s -> tmp=%d\n",
2049 isdn_map_eaz2msn(emu->msn, di), tmp);
2050#endif
2051 return tmp;
2052 }
2053}
2054
2055/*
2056 * An incoming call-request has arrived.
2057 * Search the tty-devices for an appropriate device and bind
2058 * it to the ISDN-Channel.
2059 * Return:
2060 *
2061 * 0 = No matching device found.
2062 * 1 = A matching device found.
2063 * 3 = No match found, but eventually would match, if
2064 * CID is longer.
2065 */
2066int
2067isdn_tty_find_icall(int di, int ch, setup_parm *setup)
2068{
2069 char *eaz;
2070 int i;
2071 int wret;
2072 int idx;
2073 int si1;
2074 int si2;
2075 char *nr;
2076 ulong flags;
2077
2078 if (!setup->phone[0]) {
2079 nr = "0";
2080 printk(KERN_INFO "isdn_tty: Incoming call without OAD, assuming '0'\n");
2081 } else
2082 nr = setup->phone;
2083 si1 = (int) setup->si1;
2084 si2 = (int) setup->si2;
2085 if (!setup->eazmsn[0]) {
2086 printk(KERN_WARNING "isdn_tty: Incoming call without CPN, assuming '0'\n");
2087 eaz = "0";
2088 } else
2089 eaz = setup->eazmsn;
2090#ifdef ISDN_DEBUG_MODEM_ICALL
2091 printk(KERN_DEBUG "m_fi: eaz=%s si1=%d si2=%d\n", eaz, si1, si2);
2092#endif
2093 wret = 0;
2094 spin_lock_irqsave(&dev->lock, flags);
2095 for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
2096 modem_info *info = &dev->mdm.info[i];
2097
2098 if (info->count == 0)
2099 continue;
2100 if ((info->emu.mdmreg[REG_SI1] & si2bit[si1]) && /* SI1 is matching */
2101 (info->emu.mdmreg[REG_SI2] == si2)) { /* SI2 is matching */
2102 idx = isdn_dc2minor(di, ch);
2103#ifdef ISDN_DEBUG_MODEM_ICALL
2104 printk(KERN_DEBUG "m_fi: match1 wret=%d\n", wret);
2105 printk(KERN_DEBUG "m_fi: idx=%d flags=%08lx drv=%d ch=%d usg=%d\n", idx,
2106 info->flags, info->isdn_driver, info->isdn_channel,
2107 dev->usage[idx]);
2108#endif
2109 if (
2110#ifndef FIX_FILE_TRANSFER
2111 (info->flags & ISDN_ASYNC_NORMAL_ACTIVE) &&
2112#endif
2113 (info->isdn_driver == -1) &&
2114 (info->isdn_channel == -1) &&
2115 (USG_NONE(dev->usage[idx]))) {
2116 int matchret;
2117
2118 if ((matchret = isdn_tty_match_icall(eaz, &info->emu, di)) > wret)
2119 wret = matchret;
2120 if (!matchret) { /* EAZ is matching */
2121 info->isdn_driver = di;
2122 info->isdn_channel = ch;
2123 info->drv_index = idx;
2124 dev->m_idx[idx] = info->line;
2125 dev->usage[idx] &= ISDN_USAGE_EXCLUSIVE;
2126 dev->usage[idx] |= isdn_calc_usage(si1, info->emu.mdmreg[REG_L2PROT]);
2127 strcpy(dev->num[idx], nr);
2128 strcpy(info->emu.cpn, eaz);
2129 info->emu.mdmreg[REG_SI1I] = si2bit[si1];
2130 info->emu.mdmreg[REG_PLAN] = setup->plan;
2131 info->emu.mdmreg[REG_SCREEN] = setup->screen;
2132 isdn_info_update();
2133 spin_unlock_irqrestore(&dev->lock, flags);
2134 printk(KERN_INFO "isdn_tty: call from %s, -> RING on ttyI%d\n", nr,
2135 info->line);
2136 info->msr |= UART_MSR_RI;
2137 isdn_tty_modem_result(RESULT_RING, info);
2138 isdn_timer_ctrl(ISDN_TIMER_MODEMRING, 1);
2139 return 1;
2140 }
2141 }
2142 }
2143 }
2144 spin_unlock_irqrestore(&dev->lock, flags);
2145 printk(KERN_INFO "isdn_tty: call from %s -> %s %s\n", nr, eaz,
2146 ((dev->drv[di]->flags & DRV_FLAG_REJBUS) && (wret != 2))? "rejected" : "ignored");
2147 return (wret == 2)?3:0;
2148}
2149
2150#define TTY_IS_ACTIVE(info) \
2151 (info->flags & (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE))
2152
2153int
2154isdn_tty_stat_callback(int i, isdn_ctrl *c)
2155{
2156 int mi;
2157 modem_info *info;
2158 char *e;
2159
2160 if (i < 0)
2161 return 0;
2162 if ((mi = dev->m_idx[i]) >= 0) {
2163 info = &dev->mdm.info[mi];
2164 switch (c->command) {
2165 case ISDN_STAT_CINF:
2166 printk(KERN_DEBUG "CHARGEINFO on ttyI%d: %ld %s\n", info->line, c->arg, c->parm.num);
2167 info->emu.charge = (unsigned) simple_strtoul(c->parm.num, &e, 10);
2168 if (e == (char *)c->parm.num)
2169 info->emu.charge = 0;
2170
2171 break;
2172 case ISDN_STAT_BSENT:
2173#ifdef ISDN_TTY_STAT_DEBUG
2174 printk(KERN_DEBUG "tty_STAT_BSENT ttyI%d\n", info->line);
2175#endif
2176 if ((info->isdn_driver == c->driver) &&
2177 (info->isdn_channel == c->arg)) {
2178 info->msr |= UART_MSR_CTS;
2179 if (info->send_outstanding)
2180 if (!(--info->send_outstanding))
2181 info->lsr |= UART_LSR_TEMT;
2182 isdn_tty_tint(info);
2183 return 1;
2184 }
2185 break;
2186 case ISDN_STAT_CAUSE:
2187#ifdef ISDN_TTY_STAT_DEBUG
2188 printk(KERN_DEBUG "tty_STAT_CAUSE ttyI%d\n", info->line);
2189#endif
2190 /* Signal cause to tty-device */
2191 strncpy(info->last_cause, c->parm.num, 5);
2192 return 1;
2193 case ISDN_STAT_DISPLAY:
2194#ifdef ISDN_TTY_STAT_DEBUG
2195 printk(KERN_DEBUG "tty_STAT_DISPLAY ttyI%d\n", info->line);
2196#endif
2197 /* Signal display to tty-device */
2198 if ((info->emu.mdmreg[REG_DISPLAY] & BIT_DISPLAY) &&
2199 !(info->emu.mdmreg[REG_RESPNUM] & BIT_RESPNUM)) {
2200 isdn_tty_at_cout("\r\n", info);
2201 isdn_tty_at_cout("DISPLAY: ", info);
2202 isdn_tty_at_cout(c->parm.display, info);
2203 isdn_tty_at_cout("\r\n", info);
2204 }
2205 return 1;
2206 case ISDN_STAT_DCONN:
2207#ifdef ISDN_TTY_STAT_DEBUG
2208 printk(KERN_DEBUG "tty_STAT_DCONN ttyI%d\n", info->line);
2209#endif
2210 if (TTY_IS_ACTIVE(info)) {
2211 if (info->dialing == 1) {
2212 info->dialing = 2;
2213 return 1;
2214 }
2215 }
2216 break;
2217 case ISDN_STAT_DHUP:
2218#ifdef ISDN_TTY_STAT_DEBUG
2219 printk(KERN_DEBUG "tty_STAT_DHUP ttyI%d\n", info->line);
2220#endif
2221 if (TTY_IS_ACTIVE(info)) {
2222 if (info->dialing == 1)
2223 isdn_tty_modem_result(RESULT_BUSY, info);
2224 if (info->dialing > 1)
2225 isdn_tty_modem_result(RESULT_NO_CARRIER, info);
2226 info->dialing = 0;
2227#ifdef ISDN_DEBUG_MODEM_HUP
2228 printk(KERN_DEBUG "Mhup in ISDN_STAT_DHUP\n");
2229#endif
2230 isdn_tty_modem_hup(info, 0);
2231 return 1;
2232 }
2233 break;
2234 case ISDN_STAT_BCONN:
2235#ifdef ISDN_TTY_STAT_DEBUG
2236 printk(KERN_DEBUG "tty_STAT_BCONN ttyI%d\n", info->line);
2237#endif
2238 /* Wake up any processes waiting
2239 * for incoming call of this device when
2240 * DCD follow the state of incoming carrier
2241 */
2242 if (info->blocked_open &&
2243 (info->emu.mdmreg[REG_DCD] & BIT_DCD)) {
2244 wake_up_interruptible(&info->open_wait);
2245 }
2246
2247 /* Schedule CONNECT-Message to any tty
2248 * waiting for it and
2249 * set DCD-bit of its modem-status.
2250 */
2251 if (TTY_IS_ACTIVE(info) ||
2252 (info->blocked_open && (info->emu.mdmreg[REG_DCD] & BIT_DCD))) {
2253 info->msr |= UART_MSR_DCD;
2254 info->emu.charge = 0;
2255 if (info->dialing & 0xf)
2256 info->last_dir = 1;
2257 else
2258 info->last_dir = 0;
2259 info->dialing = 0;
2260 info->rcvsched = 1;
2261 if (USG_MODEM(dev->usage[i])) {
2262 if (info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM) {
2263 strcpy(info->emu.connmsg, c->parm.num);
2264 isdn_tty_modem_result(RESULT_CONNECT, info);
2265 } else
2266 isdn_tty_modem_result(RESULT_CONNECT64000, info);
2267 }
2268 if (USG_VOICE(dev->usage[i]))
2269 isdn_tty_modem_result(RESULT_VCON, info);
2270 return 1;
2271 }
2272 break;
2273 case ISDN_STAT_BHUP:
2274#ifdef ISDN_TTY_STAT_DEBUG
2275 printk(KERN_DEBUG "tty_STAT_BHUP ttyI%d\n", info->line);
2276#endif
2277 if (TTY_IS_ACTIVE(info)) {
2278#ifdef ISDN_DEBUG_MODEM_HUP
2279 printk(KERN_DEBUG "Mhup in ISDN_STAT_BHUP\n");
2280#endif
2281 isdn_tty_modem_hup(info, 0);
2282 return 1;
2283 }
2284 break;
2285 case ISDN_STAT_NODCH:
2286#ifdef ISDN_TTY_STAT_DEBUG
2287 printk(KERN_DEBUG "tty_STAT_NODCH ttyI%d\n", info->line);
2288#endif
2289 if (TTY_IS_ACTIVE(info)) {
2290 if (info->dialing) {
2291 info->dialing = 0;
2292 info->last_l2 = -1;
2293 info->last_si = 0;
2294 sprintf(info->last_cause, "0000");
2295 isdn_tty_modem_result(RESULT_NO_DIALTONE, info);
2296 }
2297 isdn_tty_modem_hup(info, 0);
2298 return 1;
2299 }
2300 break;
2301 case ISDN_STAT_UNLOAD:
2302#ifdef ISDN_TTY_STAT_DEBUG
2303 printk(KERN_DEBUG "tty_STAT_UNLOAD ttyI%d\n", info->line);
2304#endif
2305 for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
2306 info = &dev->mdm.info[i];
2307 if (info->isdn_driver == c->driver) {
2308 if (info->online)
2309 isdn_tty_modem_hup(info, 1);
2310 }
2311 }
2312 return 1;
2313#ifdef CONFIG_ISDN_TTY_FAX
2314 case ISDN_STAT_FAXIND:
2315 if (TTY_IS_ACTIVE(info)) {
2316 isdn_tty_fax_command(info, c);
2317 }
2318 break;
2319#endif
2320#ifdef CONFIG_ISDN_AUDIO
2321 case ISDN_STAT_AUDIO:
2322 if (TTY_IS_ACTIVE(info)) {
2323 switch(c->parm.num[0]) {
2324 case ISDN_AUDIO_DTMF:
2325 if (info->vonline) {
2326 isdn_audio_put_dle_code(info,
2327 c->parm.num[1]);
2328 }
2329 break;
2330 }
2331 }
2332 break;
2333#endif
2334 }
2335 }
2336 return 0;
2337}
2338
2339/*********************************************************************
2340 Modem-Emulator-Routines
2341 *********************************************************************/
2342
2343#define cmdchar(c) ((c>=' ')&&(c<=0x7f))
2344
2345/*
2346 * Put a message from the AT-emulator into receive-buffer of tty,
2347 * convert CR, LF, and BS to values in modem-registers 3, 4 and 5.
2348 */
2349void
2350isdn_tty_at_cout(char *msg, modem_info * info)
2351{
2352 struct tty_struct *tty;
2353 atemu *m = &info->emu;
2354 char *p;
2355 char c;
2356 u_long flags;
2357 struct sk_buff *skb = NULL;
2358 char *sp = NULL;
2359
2360 if (!msg) {
2361 printk(KERN_WARNING "isdn_tty: Null-Message in isdn_tty_at_cout\n");
2362 return;
2363 }
2364 spin_lock_irqsave(&info->readlock, flags);
2365 tty = info->tty;
2366 if ((info->flags & ISDN_ASYNC_CLOSING) || (!tty)) {
2367 spin_unlock_irqrestore(&info->readlock, flags);
2368 return;
2369 }
2370
2371 /* use queue instead of direct flip, if online and */
2372 /* data is in queue or flip buffer is full */
2373 if ((info->online) && (((tty->flip.count + strlen(msg)) >= TTY_FLIPBUF_SIZE) ||
2374 (!skb_queue_empty(&dev->drv[info->isdn_driver]->rpqueue[info->isdn_channel])))) {
2375 skb = alloc_skb(strlen(msg), GFP_ATOMIC);
2376 if (!skb) {
2377 spin_unlock_irqrestore(&info->readlock, flags);
2378 return;
2379 }
2380 sp = skb_put(skb, strlen(msg));
2381#ifdef CONFIG_ISDN_AUDIO
2382 ISDN_AUDIO_SKB_DLECOUNT(skb) = 0;
2383 ISDN_AUDIO_SKB_LOCK(skb) = 0;
2384#endif
2385 }
2386
2387 for (p = msg; *p; p++) {
2388 switch (*p) {
2389 case '\r':
2390 c = m->mdmreg[REG_CR];
2391 break;
2392 case '\n':
2393 c = m->mdmreg[REG_LF];
2394 break;
2395 case '\b':
2396 c = m->mdmreg[REG_BS];
2397 break;
2398 default:
2399 c = *p;
2400 }
2401 if (skb) {
2402 *sp++ = c;
2403 } else {
2404 if (tty->flip.count >= TTY_FLIPBUF_SIZE)
2405 break;
2406 tty_insert_flip_char(tty, c, 0);
2407 }
2408 }
2409 if (skb) {
2410 __skb_queue_tail(&dev->drv[info->isdn_driver]->rpqueue[info->isdn_channel], skb);
2411 dev->drv[info->isdn_driver]->rcvcount[info->isdn_channel] += skb->len;
2412 spin_unlock_irqrestore(&info->readlock, flags);
2413 /* Schedule dequeuing */
2414 if ((dev->modempoll) && (info->rcvsched))
2415 isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
2416
2417 } else {
2418 spin_unlock_irqrestore(&info->readlock, flags);
2419 schedule_delayed_work(&tty->flip.work, 1);
2420 }
2421}
2422
2423/*
2424 * Perform ATH Hangup
2425 */
2426static void
2427isdn_tty_on_hook(modem_info * info)
2428{
2429 if (info->isdn_channel >= 0) {
2430#ifdef ISDN_DEBUG_MODEM_HUP
2431 printk(KERN_DEBUG "Mhup in isdn_tty_on_hook\n");
2432#endif
2433 isdn_tty_modem_hup(info, 1);
2434 }
2435}
2436
2437static void
2438isdn_tty_off_hook(void)
2439{
2440 printk(KERN_DEBUG "isdn_tty_off_hook\n");
2441}
2442
2443#define PLUSWAIT1 (HZ/2) /* 0.5 sec. */
2444#define PLUSWAIT2 (HZ*3/2) /* 1.5 sec */
2445
2446/*
2447 * Check Buffer for Modem-escape-sequence, activate timer-callback to
2448 * isdn_tty_modem_escape() if sequence found.
2449 *
2450 * Parameters:
2451 * p pointer to databuffer
2452 * plus escape-character
2453 * count length of buffer
2454 * pluscount count of valid escape-characters so far
2455 * lastplus timestamp of last character
2456 */
2457static void
2458isdn_tty_check_esc(const u_char * p, u_char plus, int count, int *pluscount,
2459 u_long *lastplus)
2460{
2461 if (plus > 127)
2462 return;
2463 if (count > 3) {
2464 p += count - 3;
2465 count = 3;
2466 *pluscount = 0;
2467 }
2468 while (count > 0) {
2469 if (*(p++) == plus) {
2470 if ((*pluscount)++) {
2471 /* Time since last '+' > 0.5 sec. ? */
2472 if (time_after(jiffies, *lastplus + PLUSWAIT1))
2473 *pluscount = 1;
2474 } else {
2475 /* Time since last non-'+' < 1.5 sec. ? */
2476 if (time_before(jiffies, *lastplus + PLUSWAIT2))
2477 *pluscount = 0;
2478 }
2479 if ((*pluscount == 3) && (count == 1))
2480 isdn_timer_ctrl(ISDN_TIMER_MODEMPLUS, 1);
2481 if (*pluscount > 3)
2482 *pluscount = 1;
2483 } else
2484 *pluscount = 0;
2485 *lastplus = jiffies;
2486 count--;
2487 }
2488}
2489
2490/*
2491 * Return result of AT-emulator to tty-receive-buffer, depending on
2492 * modem-register 12, bit 0 and 1.
2493 * For CONNECT-messages also switch to online-mode.
2494 * For RING-message handle auto-ATA if register 0 != 0
2495 */
2496
2497static void
2498isdn_tty_modem_result(int code, modem_info * info)
2499{
2500 atemu *m = &info->emu;
2501 static char *msg[] =
2502 {"OK", "CONNECT", "RING", "NO CARRIER", "ERROR",
2503 "CONNECT 64000", "NO DIALTONE", "BUSY", "NO ANSWER",
2504 "RINGING", "NO MSN/EAZ", "VCON", "RUNG"};
2505 char s[ISDN_MSNLEN+10];
2506
2507 switch (code) {
2508 case RESULT_RING:
2509 m->mdmreg[REG_RINGCNT]++;
2510 if (m->mdmreg[REG_RINGCNT] == m->mdmreg[REG_RINGATA])
2511 /* Automatically accept incoming call */
2512 isdn_tty_cmd_ATA(info);
2513 break;
2514 case RESULT_NO_CARRIER:
2515#ifdef ISDN_DEBUG_MODEM_HUP
2516 printk(KERN_DEBUG "modem_result: NO CARRIER %d %d\n",
2517 (info->flags & ISDN_ASYNC_CLOSING),
2518 (!info->tty));
2519#endif
2520 m->mdmreg[REG_RINGCNT] = 0;
2521 del_timer(&info->nc_timer);
2522 info->ncarrier = 0;
2523 if ((info->flags & ISDN_ASYNC_CLOSING) || (!info->tty)) {
2524 return;
2525 }
2526#ifdef CONFIG_ISDN_AUDIO
2527 if (info->vonline & 1) {
2528#ifdef ISDN_DEBUG_MODEM_VOICE
2529 printk(KERN_DEBUG "res3: send DLE-ETX on ttyI%d\n",
2530 info->line);
2531#endif
2532 /* voice-recording, add DLE-ETX */
2533 isdn_tty_at_cout("\020\003", info);
2534 }
2535 if (info->vonline & 2) {
2536#ifdef ISDN_DEBUG_MODEM_VOICE
2537 printk(KERN_DEBUG "res3: send DLE-DC4 on ttyI%d\n",
2538 info->line);
2539#endif
2540 /* voice-playing, add DLE-DC4 */
2541 isdn_tty_at_cout("\020\024", info);
2542 }
2543#endif
2544 break;
2545 case RESULT_CONNECT:
2546 case RESULT_CONNECT64000:
2547 sprintf(info->last_cause, "0000");
2548 if (!info->online)
2549 info->online = 2;
2550 break;
2551 case RESULT_VCON:
2552#ifdef ISDN_DEBUG_MODEM_VOICE
2553 printk(KERN_DEBUG "res3: send VCON on ttyI%d\n",
2554 info->line);
2555#endif
2556 sprintf(info->last_cause, "0000");
2557 if (!info->online)
2558 info->online = 1;
2559 break;
2560 } /* switch(code) */
2561
2562 if (m->mdmreg[REG_RESP] & BIT_RESP) {
2563 /* Show results */
2564 if (m->mdmreg[REG_RESPNUM] & BIT_RESPNUM) {
2565 /* Show numeric results only */
2566 sprintf(s, "\r\n%d\r\n", code);
2567 isdn_tty_at_cout(s, info);
2568 } else {
2569 if (code == RESULT_RING) {
2570 /* return if "show RUNG" and ringcounter>1 */
2571 if ((m->mdmreg[REG_RUNG] & BIT_RUNG) &&
2572 (m->mdmreg[REG_RINGCNT] > 1))
2573 return;
2574 /* print CID, _before_ _every_ ring */
2575 if (!(m->mdmreg[REG_CIDONCE] & BIT_CIDONCE)) {
2576 isdn_tty_at_cout("\r\nCALLER NUMBER: ", info);
2577 isdn_tty_at_cout(dev->num[info->drv_index], info);
2578 if (m->mdmreg[REG_CDN] & BIT_CDN) {
2579 isdn_tty_at_cout("\r\nCALLED NUMBER: ", info);
2580 isdn_tty_at_cout(info->emu.cpn, info);
2581 }
2582 }
2583 }
2584 isdn_tty_at_cout("\r\n", info);
2585 isdn_tty_at_cout(msg[code], info);
2586 switch (code) {
2587 case RESULT_CONNECT:
2588 switch (m->mdmreg[REG_L2PROT]) {
2589 case ISDN_PROTO_L2_MODEM:
2590 isdn_tty_at_cout(" ", info);
2591 isdn_tty_at_cout(m->connmsg, info);
2592 break;
2593 }
2594 break;
2595 case RESULT_RING:
2596 /* Append CPN, if enabled */
2597 if ((m->mdmreg[REG_CPN] & BIT_CPN)) {
2598 sprintf(s, "/%s", m->cpn);
2599 isdn_tty_at_cout(s, info);
2600 }
2601 /* Print CID only once, _after_ 1st RING */
2602 if ((m->mdmreg[REG_CIDONCE] & BIT_CIDONCE) &&
2603 (m->mdmreg[REG_RINGCNT] == 1)) {
2604 isdn_tty_at_cout("\r\n", info);
2605 isdn_tty_at_cout("CALLER NUMBER: ", info);
2606 isdn_tty_at_cout(dev->num[info->drv_index], info);
2607 if (m->mdmreg[REG_CDN] & BIT_CDN) {
2608 isdn_tty_at_cout("\r\nCALLED NUMBER: ", info);
2609 isdn_tty_at_cout(info->emu.cpn, info);
2610 }
2611 }
2612 break;
2613 case RESULT_NO_CARRIER:
2614 case RESULT_NO_DIALTONE:
2615 case RESULT_BUSY:
2616 case RESULT_NO_ANSWER:
2617 m->mdmreg[REG_RINGCNT] = 0;
2618 /* Append Cause-Message if enabled */
2619 if (m->mdmreg[REG_RESPXT] & BIT_RESPXT) {
2620 sprintf(s, "/%s", info->last_cause);
2621 isdn_tty_at_cout(s, info);
2622 }
2623 break;
2624 case RESULT_CONNECT64000:
2625 /* Append Protocol to CONNECT message */
2626 switch (m->mdmreg[REG_L2PROT]) {
2627 case ISDN_PROTO_L2_X75I:
2628 case ISDN_PROTO_L2_X75UI:
2629 case ISDN_PROTO_L2_X75BUI:
2630 isdn_tty_at_cout("/X.75", info);
2631 break;
2632 case ISDN_PROTO_L2_HDLC:
2633 isdn_tty_at_cout("/HDLC", info);
2634 break;
2635 case ISDN_PROTO_L2_V11096:
2636 isdn_tty_at_cout("/V110/9600", info);
2637 break;
2638 case ISDN_PROTO_L2_V11019:
2639 isdn_tty_at_cout("/V110/19200", info);
2640 break;
2641 case ISDN_PROTO_L2_V11038:
2642 isdn_tty_at_cout("/V110/38400", info);
2643 break;
2644 }
2645 if (m->mdmreg[REG_T70] & BIT_T70) {
2646 isdn_tty_at_cout("/T.70", info);
2647 if (m->mdmreg[REG_T70] & BIT_T70_EXT)
2648 isdn_tty_at_cout("+", info);
2649 }
2650 break;
2651 }
2652 isdn_tty_at_cout("\r\n", info);
2653 }
2654 }
2655 if (code == RESULT_NO_CARRIER) {
2656 if ((info->flags & ISDN_ASYNC_CLOSING) || (!info->tty)) {
2657 return;
2658 }
2659 tty_ldisc_flush(info->tty);
2660 if ((info->flags & ISDN_ASYNC_CHECK_CD) &&
2661 (!((info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) &&
2662 (info->flags & ISDN_ASYNC_CALLOUT_NOHUP)))) {
2663 tty_hangup(info->tty);
2664 }
2665 }
2666}
2667
2668
2669/*
2670 * Display a modem-register-value.
2671 */
2672static void
2673isdn_tty_show_profile(int ridx, modem_info * info)
2674{
2675 char v[6];
2676
2677 sprintf(v, "\r\n%d", info->emu.mdmreg[ridx]);
2678 isdn_tty_at_cout(v, info);
2679}
2680
2681/*
2682 * Get MSN-string from char-pointer, set pointer to end of number
2683 */
2684static void
2685isdn_tty_get_msnstr(char *n, char **p)
2686{
2687 int limit = ISDN_MSNLEN - 1;
2688
2689 while (((*p[0] >= '0' && *p[0] <= '9') ||
2690 /* Why a comma ??? */
2691 (*p[0] == ',') || (*p[0] == ':')) &&
2692 (limit--))
2693 *n++ = *p[0]++;
2694 *n = '\0';
2695}
2696
2697/*
2698 * Get phone-number from modem-commandbuffer
2699 */
2700static void
2701isdn_tty_getdial(char *p, char *q,int cnt)
2702{
2703 int first = 1;
2704 int limit = ISDN_MSNLEN - 1; /* MUST match the size of interface var to avoid
2705 buffer overflow */
2706
2707 while (strchr(" 0123456789,#.*WPTS-", *p) && *p && --cnt>0) {
2708 if ((*p >= '0' && *p <= '9') || ((*p == 'S') && first) ||
2709 (*p == '*') || (*p == '#')) {
2710 *q++ = *p;
2711 limit--;
2712 }
2713 if(!limit)
2714 break;
2715 p++;
2716 first = 0;
2717 }
2718 *q = 0;
2719}
2720
2721#define PARSE_ERROR { isdn_tty_modem_result(RESULT_ERROR, info); return; }
2722#define PARSE_ERROR1 { isdn_tty_modem_result(RESULT_ERROR, info); return 1; }
2723
2724static void
2725isdn_tty_report(modem_info * info)
2726{
2727 atemu *m = &info->emu;
2728 char s[80];
2729
2730 isdn_tty_at_cout("\r\nStatistics of last connection:\r\n\r\n", info);
2731 sprintf(s, " Remote Number: %s\r\n", info->last_num);
2732 isdn_tty_at_cout(s, info);
2733 sprintf(s, " Direction: %s\r\n", info->last_dir ? "outgoing" : "incoming");
2734 isdn_tty_at_cout(s, info);
2735 isdn_tty_at_cout(" Layer-2 Protocol: ", info);
2736 switch (info->last_l2) {
2737 case ISDN_PROTO_L2_X75I:
2738 isdn_tty_at_cout("X.75i", info);
2739 break;
2740 case ISDN_PROTO_L2_X75UI:
2741 isdn_tty_at_cout("X.75ui", info);
2742 break;
2743 case ISDN_PROTO_L2_X75BUI:
2744 isdn_tty_at_cout("X.75bui", info);
2745 break;
2746 case ISDN_PROTO_L2_HDLC:
2747 isdn_tty_at_cout("HDLC", info);
2748 break;
2749 case ISDN_PROTO_L2_V11096:
2750 isdn_tty_at_cout("V.110 9600 Baud", info);
2751 break;
2752 case ISDN_PROTO_L2_V11019:
2753 isdn_tty_at_cout("V.110 19200 Baud", info);
2754 break;
2755 case ISDN_PROTO_L2_V11038:
2756 isdn_tty_at_cout("V.110 38400 Baud", info);
2757 break;
2758 case ISDN_PROTO_L2_TRANS:
2759 isdn_tty_at_cout("transparent", info);
2760 break;
2761 case ISDN_PROTO_L2_MODEM:
2762 isdn_tty_at_cout("modem", info);
2763 break;
2764 case ISDN_PROTO_L2_FAX:
2765 isdn_tty_at_cout("fax", info);
2766 break;
2767 default:
2768 isdn_tty_at_cout("unknown", info);
2769 break;
2770 }
2771 if (m->mdmreg[REG_T70] & BIT_T70) {
2772 isdn_tty_at_cout("/T.70", info);
2773 if (m->mdmreg[REG_T70] & BIT_T70_EXT)
2774 isdn_tty_at_cout("+", info);
2775 }
2776 isdn_tty_at_cout("\r\n", info);
2777 isdn_tty_at_cout(" Service: ", info);
2778 switch (info->last_si) {
2779 case 1:
2780 isdn_tty_at_cout("audio\r\n", info);
2781 break;
2782 case 5:
2783 isdn_tty_at_cout("btx\r\n", info);
2784 break;
2785 case 7:
2786 isdn_tty_at_cout("data\r\n", info);
2787 break;
2788 default:
2789 sprintf(s, "%d\r\n", info->last_si);
2790 isdn_tty_at_cout(s, info);
2791 break;
2792 }
2793 sprintf(s, " Hangup location: %s\r\n", info->last_lhup ? "local" : "remote");
2794 isdn_tty_at_cout(s, info);
2795 sprintf(s, " Last cause: %s\r\n", info->last_cause);
2796 isdn_tty_at_cout(s, info);
2797}
2798
2799/*
2800 * Parse AT&.. commands.
2801 */
2802static int
2803isdn_tty_cmd_ATand(char **p, modem_info * info)
2804{
2805 atemu *m = &info->emu;
2806 int i;
2807 char rb[100];
2808
2809#define MAXRB (sizeof(rb) - 1)
2810
2811 switch (*p[0]) {
2812 case 'B':
2813 /* &B - Set Buffersize */
2814 p[0]++;
2815 i = isdn_getnum(p);
2816 if ((i < 0) || (i > ISDN_SERIAL_XMIT_MAX))
2817 PARSE_ERROR1;
2818#ifdef CONFIG_ISDN_AUDIO
2819 if ((m->mdmreg[REG_SI1] & 1) && (i > VBUF))
2820 PARSE_ERROR1;
2821#endif
2822 m->mdmreg[REG_PSIZE] = i / 16;
2823 info->xmit_size = m->mdmreg[REG_PSIZE] * 16;
2824 switch (m->mdmreg[REG_L2PROT]) {
2825 case ISDN_PROTO_L2_V11096:
2826 case ISDN_PROTO_L2_V11019:
2827 case ISDN_PROTO_L2_V11038:
2828 info->xmit_size /= 10;
2829 }
2830 break;
2831 case 'C':
2832 /* &C - DCD Status */
2833 p[0]++;
2834 switch (isdn_getnum(p)) {
2835 case 0:
2836 m->mdmreg[REG_DCD] &= ~BIT_DCD;
2837 break;
2838 case 1:
2839 m->mdmreg[REG_DCD] |= BIT_DCD;
2840 break;
2841 default:
2842 PARSE_ERROR1
2843 }
2844 break;
2845 case 'D':
2846 /* &D - Set DTR-Low-behavior */
2847 p[0]++;
2848 switch (isdn_getnum(p)) {
2849 case 0:
2850 m->mdmreg[REG_DTRHUP] &= ~BIT_DTRHUP;
2851 m->mdmreg[REG_DTRR] &= ~BIT_DTRR;
2852 break;
2853 case 2:
2854 m->mdmreg[REG_DTRHUP] |= BIT_DTRHUP;
2855 m->mdmreg[REG_DTRR] &= ~BIT_DTRR;
2856 break;
2857 case 3:
2858 m->mdmreg[REG_DTRHUP] |= BIT_DTRHUP;
2859 m->mdmreg[REG_DTRR] |= BIT_DTRR;
2860 break;
2861 default:
2862 PARSE_ERROR1
2863 }
2864 break;
2865 case 'E':
2866 /* &E -Set EAZ/MSN */
2867 p[0]++;
2868 isdn_tty_get_msnstr(m->msn, p);
2869 break;
2870 case 'F':
2871 /* &F -Set Factory-Defaults */
2872 p[0]++;
2873 if (info->msr & UART_MSR_DCD)
2874 PARSE_ERROR1;
2875 isdn_tty_reset_profile(m);
2876 isdn_tty_modem_reset_regs(info, 1);
2877 break;
2878#ifdef DUMMY_HAYES_AT
2879 case 'K':
2880 /* only for be compilant with common scripts */
2881 /* &K Flowcontrol - no function */
2882 p[0]++;
2883 isdn_getnum(p);
2884 break;
2885#endif
2886 case 'L':
2887 /* &L -Set Numbers to listen on */
2888 p[0]++;
2889 i = 0;
2890 while (*p[0] && (strchr("0123456789,-*[]?;", *p[0])) &&
2891 (i < ISDN_LMSNLEN))
2892 m->lmsn[i++] = *p[0]++;
2893 m->lmsn[i] = '\0';
2894 break;
2895 case 'R':
2896 /* &R - Set V.110 bitrate adaption */
2897 p[0]++;
2898 i = isdn_getnum(p);
2899 switch (i) {
2900 case 0:
2901 /* Switch off V.110, back to X.75 */
2902 m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_X75I;
2903 m->mdmreg[REG_SI2] = 0;
2904 info->xmit_size = m->mdmreg[REG_PSIZE] * 16;
2905 break;
2906 case 9600:
2907 m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_V11096;
2908 m->mdmreg[REG_SI2] = 197;
2909 info->xmit_size = m->mdmreg[REG_PSIZE] * 16 / 10;
2910 break;
2911 case 19200:
2912 m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_V11019;
2913 m->mdmreg[REG_SI2] = 199;
2914 info->xmit_size = m->mdmreg[REG_PSIZE] * 16 / 10;
2915 break;
2916 case 38400:
2917 m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_V11038;
2918 m->mdmreg[REG_SI2] = 198; /* no existing standard for this */
2919 info->xmit_size = m->mdmreg[REG_PSIZE] * 16 / 10;
2920 break;
2921 default:
2922 PARSE_ERROR1;
2923 }
2924 /* Switch off T.70 */
2925 m->mdmreg[REG_T70] &= ~(BIT_T70 | BIT_T70_EXT);
2926 /* Set Service 7 */
2927 m->mdmreg[REG_SI1] |= 4;
2928 break;
2929 case 'S':
2930 /* &S - Set Windowsize */
2931 p[0]++;
2932 i = isdn_getnum(p);
2933 if ((i > 0) && (i < 9))
2934 m->mdmreg[REG_WSIZE] = i;
2935 else
2936 PARSE_ERROR1;
2937 break;
2938 case 'V':
2939 /* &V - Show registers */
2940 p[0]++;
2941 isdn_tty_at_cout("\r\n", info);
2942 for (i = 0; i < ISDN_MODEM_NUMREG; i++) {
2943 sprintf(rb, "S%02d=%03d%s", i,
2944 m->mdmreg[i], ((i + 1) % 10) ? " " : "\r\n");
2945 isdn_tty_at_cout(rb, info);
2946 }
2947 sprintf(rb, "\r\nEAZ/MSN: %.50s\r\n",
2948 strlen(m->msn) ? m->msn : "None");
2949 isdn_tty_at_cout(rb, info);
2950 if (strlen(m->lmsn)) {
2951 isdn_tty_at_cout("\r\nListen: ", info);
2952 isdn_tty_at_cout(m->lmsn, info);
2953 isdn_tty_at_cout("\r\n", info);
2954 }
2955 break;
2956 case 'W':
2957 /* &W - Write Profile */
2958 p[0]++;
2959 switch (*p[0]) {
2960 case '0':
2961 p[0]++;
2962 modem_write_profile(m);
2963 break;
2964 default:
2965 PARSE_ERROR1;
2966 }
2967 break;
2968 case 'X':
2969 /* &X - Switch to BTX-Mode and T.70 */
2970 p[0]++;
2971 switch (isdn_getnum(p)) {
2972 case 0:
2973 m->mdmreg[REG_T70] &= ~(BIT_T70 | BIT_T70_EXT);
2974 info->xmit_size = m->mdmreg[REG_PSIZE] * 16;
2975 break;
2976 case 1:
2977 m->mdmreg[REG_T70] |= BIT_T70;
2978 m->mdmreg[REG_T70] &= ~BIT_T70_EXT;
2979 m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_X75I;
2980 info->xmit_size = 112;
2981 m->mdmreg[REG_SI1] = 4;
2982 m->mdmreg[REG_SI2] = 0;
2983 break;
2984 case 2:
2985 m->mdmreg[REG_T70] |= (BIT_T70 | BIT_T70_EXT);
2986 m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_X75I;
2987 info->xmit_size = 112;
2988 m->mdmreg[REG_SI1] = 4;
2989 m->mdmreg[REG_SI2] = 0;
2990 break;
2991 default:
2992 PARSE_ERROR1;
2993 }
2994 break;
2995 default:
2996 PARSE_ERROR1;
2997 }
2998 return 0;
2999}
3000
3001static int
3002isdn_tty_check_ats(int mreg, int mval, modem_info * info, atemu * m)
3003{
3004 /* Some plausibility checks */
3005 switch (mreg) {
3006 case REG_L2PROT:
3007 if (mval > ISDN_PROTO_L2_MAX)
3008 return 1;
3009 break;
3010 case REG_PSIZE:
3011 if ((mval * 16) > ISDN_SERIAL_XMIT_MAX)
3012 return 1;
3013#ifdef CONFIG_ISDN_AUDIO
3014 if ((m->mdmreg[REG_SI1] & 1) && (mval > VBUFX))
3015 return 1;
3016#endif
3017 info->xmit_size = mval * 16;
3018 switch (m->mdmreg[REG_L2PROT]) {
3019 case ISDN_PROTO_L2_V11096:
3020 case ISDN_PROTO_L2_V11019:
3021 case ISDN_PROTO_L2_V11038:
3022 info->xmit_size /= 10;
3023 }
3024 break;
3025 case REG_SI1I:
3026 case REG_PLAN:
3027 case REG_SCREEN:
3028 /* readonly registers */
3029 return 1;
3030 }
3031 return 0;
3032}
3033
3034/*
3035 * Perform ATS command
3036 */
3037static int
3038isdn_tty_cmd_ATS(char **p, modem_info * info)
3039{
3040 atemu *m = &info->emu;
3041 int bitpos;
3042 int mreg;
3043 int mval;
3044 int bval;
3045
3046 mreg = isdn_getnum(p);
3047 if (mreg < 0 || mreg >= ISDN_MODEM_NUMREG)
3048 PARSE_ERROR1;
3049 switch (*p[0]) {
3050 case '=':
3051 p[0]++;
3052 mval = isdn_getnum(p);
3053 if (mval < 0 || mval > 255)
3054 PARSE_ERROR1;
3055 if (isdn_tty_check_ats(mreg, mval, info, m))
3056 PARSE_ERROR1;
3057 m->mdmreg[mreg] = mval;
3058 break;
3059 case '.':
3060 /* Set/Clear a single bit */
3061 p[0]++;
3062 bitpos = isdn_getnum(p);
3063 if ((bitpos < 0) || (bitpos > 7))
3064 PARSE_ERROR1;
3065 switch (*p[0]) {
3066 case '=':
3067 p[0]++;
3068 bval = isdn_getnum(p);
3069 if (bval < 0 || bval > 1)
3070 PARSE_ERROR1;
3071 if (bval)
3072 mval = m->mdmreg[mreg] | (1 << bitpos);
3073 else
3074 mval = m->mdmreg[mreg] & ~(1 << bitpos);
3075 if (isdn_tty_check_ats(mreg, mval, info, m))
3076 PARSE_ERROR1;
3077 m->mdmreg[mreg] = mval;
3078 break;
3079 case '?':
3080 p[0]++;
3081 isdn_tty_at_cout("\r\n", info);
3082 isdn_tty_at_cout((m->mdmreg[mreg] & (1 << bitpos)) ? "1" : "0",
3083 info);
3084 break;
3085 default:
3086 PARSE_ERROR1;
3087 }
3088 break;
3089 case '?':
3090 p[0]++;
3091 isdn_tty_show_profile(mreg, info);
3092 break;
3093 default:
3094 PARSE_ERROR1;
3095 break;
3096 }
3097 return 0;
3098}
3099
3100/*
3101 * Perform ATA command
3102 */
3103static void
3104isdn_tty_cmd_ATA(modem_info * info)
3105{
3106 atemu *m = &info->emu;
3107 isdn_ctrl cmd;
3108 int l2;
3109
3110 if (info->msr & UART_MSR_RI) {
3111 /* Accept incoming call */
3112 info->last_dir = 0;
3113 strcpy(info->last_num, dev->num[info->drv_index]);
3114 m->mdmreg[REG_RINGCNT] = 0;
3115 info->msr &= ~UART_MSR_RI;
3116 l2 = m->mdmreg[REG_L2PROT];
3117#ifdef CONFIG_ISDN_AUDIO
3118 /* If more than one bit set in reg18, autoselect Layer2 */
3119 if ((m->mdmreg[REG_SI1] & m->mdmreg[REG_SI1I]) != m->mdmreg[REG_SI1]) {
3120 if (m->mdmreg[REG_SI1I] == 1) {
3121 if ((l2 != ISDN_PROTO_L2_MODEM) && (l2 != ISDN_PROTO_L2_FAX))
3122 l2 = ISDN_PROTO_L2_TRANS;
3123 } else
3124 l2 = ISDN_PROTO_L2_X75I;
3125 }
3126#endif
3127 cmd.driver = info->isdn_driver;
3128 cmd.command = ISDN_CMD_SETL2;
3129 cmd.arg = info->isdn_channel + (l2 << 8);
3130 info->last_l2 = l2;
3131 isdn_command(&cmd);
3132 cmd.driver = info->isdn_driver;
3133 cmd.command = ISDN_CMD_SETL3;
3134 cmd.arg = info->isdn_channel + (m->mdmreg[REG_L3PROT] << 8);
3135#ifdef CONFIG_ISDN_TTY_FAX
3136 if (l2 == ISDN_PROTO_L2_FAX) {
3137 cmd.parm.fax = info->fax;
3138 info->fax->direction = ISDN_TTY_FAX_CONN_IN;
3139 }
3140#endif
3141 isdn_command(&cmd);
3142 cmd.driver = info->isdn_driver;
3143 cmd.arg = info->isdn_channel;
3144 cmd.command = ISDN_CMD_ACCEPTD;
3145 info->dialing = 16;
3146 info->emu.carrierwait = 0;
3147 isdn_command(&cmd);
3148 isdn_timer_ctrl(ISDN_TIMER_CARRIER, 1);
3149 } else
3150 isdn_tty_modem_result(RESULT_NO_ANSWER, info);
3151}
3152
3153#ifdef CONFIG_ISDN_AUDIO
3154/*
3155 * Parse AT+F.. commands
3156 */
3157static int
3158isdn_tty_cmd_PLUSF(char **p, modem_info * info)
3159{
3160 atemu *m = &info->emu;
3161 char rs[20];
3162
3163 if (!strncmp(p[0], "CLASS", 5)) {
3164 p[0] += 5;
3165 switch (*p[0]) {
3166 case '?':
3167 p[0]++;
3168 sprintf(rs, "\r\n%d",
3169 (m->mdmreg[REG_SI1] & 1) ? 8 : 0);
3170#ifdef CONFIG_ISDN_TTY_FAX
3171 if (TTY_IS_FCLASS2(info))
3172 sprintf(rs, "\r\n2");
3173 else if (TTY_IS_FCLASS1(info))
3174 sprintf(rs, "\r\n1");
3175#endif
3176 isdn_tty_at_cout(rs, info);
3177 break;
3178 case '=':
3179 p[0]++;
3180 switch (*p[0]) {
3181 case '0':
3182 p[0]++;
3183 m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_X75I;
3184 m->mdmreg[REG_L3PROT] = ISDN_PROTO_L3_TRANS;
3185 m->mdmreg[REG_SI1] = 4;
3186 info->xmit_size =
3187 m->mdmreg[REG_PSIZE] * 16;
3188 break;
3189#ifdef CONFIG_ISDN_TTY_FAX
3190 case '1':
3191 p[0]++;
3192 if (!(dev->global_features &
3193 ISDN_FEATURE_L3_FCLASS1))
3194 PARSE_ERROR1;
3195 m->mdmreg[REG_SI1] = 1;
3196 m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_FAX;
3197 m->mdmreg[REG_L3PROT] = ISDN_PROTO_L3_FCLASS1;
3198 info->xmit_size =
3199 m->mdmreg[REG_PSIZE] * 16;
3200 break;
3201 case '2':
3202 p[0]++;
3203 if (!(dev->global_features &
3204 ISDN_FEATURE_L3_FCLASS2))
3205 PARSE_ERROR1;
3206 m->mdmreg[REG_SI1] = 1;
3207 m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_FAX;
3208 m->mdmreg[REG_L3PROT] = ISDN_PROTO_L3_FCLASS2;
3209 info->xmit_size =
3210 m->mdmreg[REG_PSIZE] * 16;
3211 break;
3212#endif
3213 case '8':
3214 p[0]++;
3215 /* L2 will change on dialout with si=1 */
3216 m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_X75I;
3217 m->mdmreg[REG_L3PROT] = ISDN_PROTO_L3_TRANS;
3218 m->mdmreg[REG_SI1] = 5;
3219 info->xmit_size = VBUF;
3220 break;
3221 case '?':
3222 p[0]++;
3223 strcpy(rs, "\r\n0,");
3224#ifdef CONFIG_ISDN_TTY_FAX
3225 if (dev->global_features &
3226 ISDN_FEATURE_L3_FCLASS1)
3227 strcat(rs, "1,");
3228 if (dev->global_features &
3229 ISDN_FEATURE_L3_FCLASS2)
3230 strcat(rs, "2,");
3231#endif
3232 strcat(rs, "8");
3233 isdn_tty_at_cout(rs, info);
3234 break;
3235 default:
3236 PARSE_ERROR1;
3237 }
3238 break;
3239 default:
3240 PARSE_ERROR1;
3241 }
3242 return 0;
3243 }
3244#ifdef CONFIG_ISDN_TTY_FAX
3245 return (isdn_tty_cmd_PLUSF_FAX(p, info));
3246#else
3247 PARSE_ERROR1;
3248#endif
3249}
3250
3251/*
3252 * Parse AT+V.. commands
3253 */
3254static int
3255isdn_tty_cmd_PLUSV(char **p, modem_info * info)
3256{
3257 atemu *m = &info->emu;
3258 isdn_ctrl cmd;
3259 static char *vcmd[] =
3260 {"NH", "IP", "LS", "RX", "SD", "SM", "TX", "DD", NULL};
3261 int i;
3262 int par1;
3263 int par2;
3264 char rs[20];
3265
3266 i = 0;
3267 while (vcmd[i]) {
3268 if (!strncmp(vcmd[i], p[0], 2)) {
3269 p[0] += 2;
3270 break;
3271 }
3272 i++;
3273 }
3274 switch (i) {
3275 case 0:
3276 /* AT+VNH - Auto hangup feature */
3277 switch (*p[0]) {
3278 case '?':
3279 p[0]++;
3280 isdn_tty_at_cout("\r\n1", info);
3281 break;
3282 case '=':
3283 p[0]++;
3284 switch (*p[0]) {
3285 case '1':
3286 p[0]++;
3287 break;
3288 case '?':
3289 p[0]++;
3290 isdn_tty_at_cout("\r\n1", info);
3291 break;
3292 default:
3293 PARSE_ERROR1;
3294 }
3295 break;
3296 default:
3297 PARSE_ERROR1;
3298 }
3299 break;
3300 case 1:
3301 /* AT+VIP - Reset all voice parameters */
3302 isdn_tty_modem_reset_vpar(m);
3303 break;
3304 case 2:
3305 /* AT+VLS - Select device, accept incoming call */
3306 switch (*p[0]) {
3307 case '?':
3308 p[0]++;
3309 sprintf(rs, "\r\n%d", m->vpar[0]);
3310 isdn_tty_at_cout(rs, info);
3311 break;
3312 case '=':
3313 p[0]++;
3314 switch (*p[0]) {
3315 case '0':
3316 p[0]++;
3317 m->vpar[0] = 0;
3318 break;
3319 case '2':
3320 p[0]++;
3321 m->vpar[0] = 2;
3322 break;
3323 case '?':
3324 p[0]++;
3325 isdn_tty_at_cout("\r\n0,2", info);
3326 break;
3327 default:
3328 PARSE_ERROR1;
3329 }
3330 break;
3331 default:
3332 PARSE_ERROR1;
3333 }
3334 break;
3335 case 3:
3336 /* AT+VRX - Start recording */
3337 if (!m->vpar[0])
3338 PARSE_ERROR1;
3339 if (info->online != 1) {
3340 isdn_tty_modem_result(RESULT_NO_ANSWER, info);
3341 return 1;
3342 }
3343 info->dtmf_state = isdn_audio_dtmf_init(info->dtmf_state);
3344 if (!info->dtmf_state) {
3345 printk(KERN_WARNING "isdn_tty: Couldn't malloc dtmf state\n");
3346 PARSE_ERROR1;
3347 }
3348 info->silence_state = isdn_audio_silence_init(info->silence_state);
3349 if (!info->silence_state) {
3350 printk(KERN_WARNING "isdn_tty: Couldn't malloc silence state\n");
3351 PARSE_ERROR1;
3352 }
3353 if (m->vpar[3] < 5) {
3354 info->adpcmr = isdn_audio_adpcm_init(info->adpcmr, m->vpar[3]);
3355 if (!info->adpcmr) {
3356 printk(KERN_WARNING "isdn_tty: Couldn't malloc adpcm state\n");
3357 PARSE_ERROR1;
3358 }
3359 }
3360#ifdef ISDN_DEBUG_AT
3361 printk(KERN_DEBUG "AT: +VRX\n");
3362#endif
3363 info->vonline |= 1;
3364 isdn_tty_modem_result(RESULT_CONNECT, info);
3365 return 0;
3366 break;
3367 case 4:
3368 /* AT+VSD - Silence detection */
3369 switch (*p[0]) {
3370 case '?':
3371 p[0]++;
3372 sprintf(rs, "\r\n<%d>,<%d>",
3373 m->vpar[1],
3374 m->vpar[2]);
3375 isdn_tty_at_cout(rs, info);
3376 break;
3377 case '=':
3378 p[0]++;
3379 if ((*p[0]>='0') && (*p[0]<='9')) {
3380 par1 = isdn_getnum(p);
3381 if ((par1 < 0) || (par1 > 31))
3382 PARSE_ERROR1;
3383 if (*p[0] != ',')
3384 PARSE_ERROR1;
3385 p[0]++;
3386 par2 = isdn_getnum(p);
3387 if ((par2 < 0) || (par2 > 255))
3388 PARSE_ERROR1;
3389 m->vpar[1] = par1;
3390 m->vpar[2] = par2;
3391 break;
3392 } else
3393 if (*p[0] == '?') {
3394 p[0]++;
3395 isdn_tty_at_cout("\r\n<0-31>,<0-255>",
3396 info);
3397 break;
3398 } else
3399 PARSE_ERROR1;
3400 break;
3401 default:
3402 PARSE_ERROR1;
3403 }
3404 break;
3405 case 5:
3406 /* AT+VSM - Select compression */
3407 switch (*p[0]) {
3408 case '?':
3409 p[0]++;
3410 sprintf(rs, "\r\n<%d>,<%d><8000>",
3411 m->vpar[3],
3412 m->vpar[1]);
3413 isdn_tty_at_cout(rs, info);
3414 break;
3415 case '=':
3416 p[0]++;
3417 switch (*p[0]) {
3418 case '2':
3419 case '3':
3420 case '4':
3421 case '5':
3422 case '6':
3423 par1 = isdn_getnum(p);
3424 if ((par1 < 2) || (par1 > 6))
3425 PARSE_ERROR1;
3426 m->vpar[3] = par1;
3427 break;
3428 case '?':
3429 p[0]++;
3430 isdn_tty_at_cout("\r\n2;ADPCM;2;0;(8000)\r\n",
3431 info);
3432 isdn_tty_at_cout("3;ADPCM;3;0;(8000)\r\n",
3433 info);
3434 isdn_tty_at_cout("4;ADPCM;4;0;(8000)\r\n",
3435 info);
3436 isdn_tty_at_cout("5;ALAW;8;0;(8000)\r\n",
3437 info);
3438 isdn_tty_at_cout("6;ULAW;8;0;(8000)\r\n",
3439 info);
3440 break;
3441 default:
3442 PARSE_ERROR1;
3443 }
3444 break;
3445 default:
3446 PARSE_ERROR1;
3447 }
3448 break;
3449 case 6:
3450 /* AT+VTX - Start sending */
3451 if (!m->vpar[0])
3452 PARSE_ERROR1;
3453 if (info->online != 1) {
3454 isdn_tty_modem_result(RESULT_NO_ANSWER, info);
3455 return 1;
3456 }
3457 info->dtmf_state = isdn_audio_dtmf_init(info->dtmf_state);
3458 if (!info->dtmf_state) {
3459 printk(KERN_WARNING "isdn_tty: Couldn't malloc dtmf state\n");
3460 PARSE_ERROR1;
3461 }
3462 if (m->vpar[3] < 5) {
3463 info->adpcms = isdn_audio_adpcm_init(info->adpcms, m->vpar[3]);
3464 if (!info->adpcms) {
3465 printk(KERN_WARNING "isdn_tty: Couldn't malloc adpcm state\n");
3466 PARSE_ERROR1;
3467 }
3468 }
3469#ifdef ISDN_DEBUG_AT
3470 printk(KERN_DEBUG "AT: +VTX\n");
3471#endif
3472 m->lastDLE = 0;
3473 info->vonline |= 2;
3474 isdn_tty_modem_result(RESULT_CONNECT, info);
3475 return 0;
3476 break;
3477 case 7:
3478 /* AT+VDD - DTMF detection */
3479 switch (*p[0]) {
3480 case '?':
3481 p[0]++;
3482 sprintf(rs, "\r\n<%d>,<%d>",
3483 m->vpar[4],
3484 m->vpar[5]);
3485 isdn_tty_at_cout(rs, info);
3486 break;
3487 case '=':
3488 p[0]++;
3489 if ((*p[0]>='0') && (*p[0]<='9')) {
3490 if (info->online != 1)
3491 PARSE_ERROR1;
3492 par1 = isdn_getnum(p);
3493 if ((par1 < 0) || (par1 > 15))
3494 PARSE_ERROR1;
3495 if (*p[0] != ',')
3496 PARSE_ERROR1;
3497 p[0]++;
3498 par2 = isdn_getnum(p);
3499 if ((par2 < 0) || (par2 > 255))
3500 PARSE_ERROR1;
3501 m->vpar[4] = par1;
3502 m->vpar[5] = par2;
3503 cmd.driver = info->isdn_driver;
3504 cmd.command = ISDN_CMD_AUDIO;
3505 cmd.arg = info->isdn_channel + (ISDN_AUDIO_SETDD << 8);
3506 cmd.parm.num[0] = par1;
3507 cmd.parm.num[1] = par2;
3508 isdn_command(&cmd);
3509 break;
3510 } else
3511 if (*p[0] == '?') {
3512 p[0]++;
3513 isdn_tty_at_cout("\r\n<0-15>,<0-255>",
3514 info);
3515 break;
3516 } else
3517 PARSE_ERROR1;
3518 break;
3519 default:
3520 PARSE_ERROR1;
3521 }
3522 break;
3523 default:
3524 PARSE_ERROR1;
3525 }
3526 return 0;
3527}
3528#endif /* CONFIG_ISDN_AUDIO */
3529
3530/*
3531 * Parse and perform an AT-command-line.
3532 */
3533static void
3534isdn_tty_parse_at(modem_info * info)
3535{
3536 atemu *m = &info->emu;
3537 char *p;
3538 char ds[40];
3539
3540#ifdef ISDN_DEBUG_AT
3541 printk(KERN_DEBUG "AT: '%s'\n", m->mdmcmd);
3542#endif
3543 for (p = &m->mdmcmd[2]; *p;) {
3544 switch (*p) {
3545 case ' ':
3546 p++;
3547 break;
3548 case 'A':
3549 /* A - Accept incoming call */
3550 p++;
3551 isdn_tty_cmd_ATA(info);
3552 return;
3553 break;
3554 case 'D':
3555 /* D - Dial */
3556 if (info->msr & UART_MSR_DCD)
3557 PARSE_ERROR;
3558 if (info->msr & UART_MSR_RI) {
3559 isdn_tty_modem_result(RESULT_NO_CARRIER, info);
3560 return;
3561 }
3562 isdn_tty_getdial(++p, ds, sizeof ds);
3563 p += strlen(p);
3564 if (!strlen(m->msn))
3565 isdn_tty_modem_result(RESULT_NO_MSN_EAZ, info);
3566 else if (strlen(ds))
3567 isdn_tty_dial(ds, info, m);
3568 else
3569 PARSE_ERROR;
3570 return;
3571 case 'E':
3572 /* E - Turn Echo on/off */
3573 p++;
3574 switch (isdn_getnum(&p)) {
3575 case 0:
3576 m->mdmreg[REG_ECHO] &= ~BIT_ECHO;
3577 break;
3578 case 1:
3579 m->mdmreg[REG_ECHO] |= BIT_ECHO;
3580 break;
3581 default:
3582 PARSE_ERROR;
3583 }
3584 break;
3585 case 'H':
3586 /* H - On/Off-hook */
3587 p++;
3588 switch (*p) {
3589 case '0':
3590 p++;
3591 isdn_tty_on_hook(info);
3592 break;
3593 case '1':
3594 p++;
3595 isdn_tty_off_hook();
3596 break;
3597 default:
3598 isdn_tty_on_hook(info);
3599 break;
3600 }
3601 break;
3602 case 'I':
3603 /* I - Information */
3604 p++;
3605 isdn_tty_at_cout("\r\nLinux ISDN", info);
3606 switch (*p) {
3607 case '0':
3608 case '1':
3609 p++;
3610 break;
3611 case '2':
3612 p++;
3613 isdn_tty_report(info);
3614 break;
3615 case '3':
3616 p++;
3617 sprintf(ds, "\r\n%d", info->emu.charge);
3618 isdn_tty_at_cout(ds, info);
3619 break;
3620 default:;
3621 }
3622 break;
3623#ifdef DUMMY_HAYES_AT
3624 case 'L':
3625 case 'M':
3626 /* only for be compilant with common scripts */
3627 /* no function */
3628 p++;
3629 isdn_getnum(&p);
3630 break;
3631#endif
3632 case 'O':
3633 /* O - Go online */
3634 p++;
3635 if (info->msr & UART_MSR_DCD)
3636 /* if B-Channel is up */
3637 isdn_tty_modem_result((m->mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM) ? RESULT_CONNECT:RESULT_CONNECT64000, info);
3638 else
3639 isdn_tty_modem_result(RESULT_NO_CARRIER, info);
3640 return;
3641 case 'Q':
3642 /* Q - Turn Emulator messages on/off */
3643 p++;
3644 switch (isdn_getnum(&p)) {
3645 case 0:
3646 m->mdmreg[REG_RESP] |= BIT_RESP;
3647 break;
3648 case 1:
3649 m->mdmreg[REG_RESP] &= ~BIT_RESP;
3650 break;
3651 default:
3652 PARSE_ERROR;
3653 }
3654 break;
3655 case 'S':
3656 /* S - Set/Get Register */
3657 p++;
3658 if (isdn_tty_cmd_ATS(&p, info))
3659 return;
3660 break;
3661 case 'V':
3662 /* V - Numeric or ASCII Emulator-messages */
3663 p++;
3664 switch (isdn_getnum(&p)) {
3665 case 0:
3666 m->mdmreg[REG_RESP] |= BIT_RESPNUM;
3667 break;
3668 case 1:
3669 m->mdmreg[REG_RESP] &= ~BIT_RESPNUM;
3670 break;
3671 default:
3672 PARSE_ERROR;
3673 }
3674 break;
3675 case 'Z':
3676 /* Z - Load Registers from Profile */
3677 p++;
3678 if (info->msr & UART_MSR_DCD) {
3679 info->online = 0;
3680 isdn_tty_on_hook(info);
3681 }
3682 isdn_tty_modem_reset_regs(info, 1);
3683 break;
3684 case '+':
3685 p++;
3686 switch (*p) {
3687#ifdef CONFIG_ISDN_AUDIO
3688 case 'F':
3689 p++;
3690 if (isdn_tty_cmd_PLUSF(&p, info))
3691 return;
3692 break;
3693 case 'V':
3694 if ((!(m->mdmreg[REG_SI1] & 1)) ||
3695 (m->mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM))
3696 PARSE_ERROR;
3697 p++;
3698 if (isdn_tty_cmd_PLUSV(&p, info))
3699 return;
3700 break;
3701#endif /* CONFIG_ISDN_AUDIO */
3702 case 'S': /* SUSPEND */
3703 p++;
3704 isdn_tty_get_msnstr(ds, &p);
3705 isdn_tty_suspend(ds, info, m);
3706 break;
3707 case 'R': /* RESUME */
3708 p++;
3709 isdn_tty_get_msnstr(ds, &p);
3710 isdn_tty_resume(ds, info, m);
3711 break;
3712 case 'M': /* MESSAGE */
3713 p++;
3714 isdn_tty_send_msg(info, m, p);
3715 break;
3716 default:
3717 PARSE_ERROR;
3718 }
3719 break;
3720 case '&':
3721 p++;
3722 if (isdn_tty_cmd_ATand(&p, info))
3723 return;
3724 break;
3725 default:
3726 PARSE_ERROR;
3727 }
3728 }
3729#ifdef CONFIG_ISDN_AUDIO
3730 if (!info->vonline)
3731#endif
3732 isdn_tty_modem_result(RESULT_OK, info);
3733}
3734
3735/* Need own toupper() because standard-toupper is not available
3736 * within modules.
3737 */
3738#define my_toupper(c) (((c>='a')&&(c<='z'))?(c&0xdf):c)
3739
3740/*
3741 * Perform line-editing of AT-commands
3742 *
3743 * Parameters:
3744 * p inputbuffer
3745 * count length of buffer
3746 * channel index to line (minor-device)
3747 */
3748static int
3749isdn_tty_edit_at(const char *p, int count, modem_info * info)
3750{
3751 atemu *m = &info->emu;
3752 int total = 0;
3753 u_char c;
3754 char eb[2];
3755 int cnt;
3756
3757 for (cnt = count; cnt > 0; p++, cnt--) {
3758 c = *p;
3759 total++;
3760 if (c == m->mdmreg[REG_CR] || c == m->mdmreg[REG_LF]) {
3761 /* Separator (CR or LF) */
3762 m->mdmcmd[m->mdmcmdl] = 0;
3763 if (m->mdmreg[REG_ECHO] & BIT_ECHO) {
3764 eb[0] = c;
3765 eb[1] = 0;
3766 isdn_tty_at_cout(eb, info);
3767 }
3768 if ((m->mdmcmdl >= 2) && (!(strncmp(m->mdmcmd, "AT", 2))))
3769 isdn_tty_parse_at(info);
3770 m->mdmcmdl = 0;
3771 continue;
3772 }
3773 if (c == m->mdmreg[REG_BS] && m->mdmreg[REG_BS] < 128) {
3774 /* Backspace-Function */
3775 if ((m->mdmcmdl > 2) || (!m->mdmcmdl)) {
3776 if (m->mdmcmdl)
3777 m->mdmcmdl--;
3778 if (m->mdmreg[REG_ECHO] & BIT_ECHO)
3779 isdn_tty_at_cout("\b", info);
3780 }
3781 continue;
3782 }
3783 if (cmdchar(c)) {
3784 if (m->mdmreg[REG_ECHO] & BIT_ECHO) {
3785 eb[0] = c;
3786 eb[1] = 0;
3787 isdn_tty_at_cout(eb, info);
3788 }
3789 if (m->mdmcmdl < 255) {
3790 c = my_toupper(c);
3791 switch (m->mdmcmdl) {
3792 case 1:
3793 if (c == 'T') {
3794 m->mdmcmd[m->mdmcmdl] = c;
3795 m->mdmcmd[++m->mdmcmdl] = 0;
3796 break;
3797 } else
3798 m->mdmcmdl = 0;
3799 /* Fall through, check for 'A' */
3800 case 0:
3801 if (c == 'A') {
3802 m->mdmcmd[m->mdmcmdl] = c;
3803 m->mdmcmd[++m->mdmcmdl] = 0;
3804 }
3805 break;
3806 default:
3807 m->mdmcmd[m->mdmcmdl] = c;
3808 m->mdmcmd[++m->mdmcmdl] = 0;
3809 }
3810 }
3811 }
3812 }
3813 return total;
3814}
3815
3816/*
3817 * Switch all modem-channels who are online and got a valid
3818 * escape-sequence 1.5 seconds ago, to command-mode.
3819 * This function is called every second via timer-interrupt from within
3820 * timer-dispatcher isdn_timer_function()
3821 */
3822void
3823isdn_tty_modem_escape(void)
3824{
3825 int ton = 0;
3826 int i;
3827 int midx;
3828
3829 for (i = 0; i < ISDN_MAX_CHANNELS; i++)
3830 if (USG_MODEM(dev->usage[i]))
3831 if ((midx = dev->m_idx[i]) >= 0) {
3832 modem_info *info = &dev->mdm.info[midx];
3833 if (info->online) {
3834 ton = 1;
3835 if ((info->emu.pluscount == 3) &&
3836 time_after(jiffies , info->emu.lastplus + PLUSWAIT2)) {
3837 info->emu.pluscount = 0;
3838 info->online = 0;
3839 isdn_tty_modem_result(RESULT_OK, info);
3840 }
3841 }
3842 }
3843 isdn_timer_ctrl(ISDN_TIMER_MODEMPLUS, ton);
3844}
3845
3846/*
3847 * Put a RING-message to all modem-channels who have the RI-bit set.
3848 * This function is called every second via timer-interrupt from within
3849 * timer-dispatcher isdn_timer_function()
3850 */
3851void
3852isdn_tty_modem_ring(void)
3853{
3854 int ton = 0;
3855 int i;
3856
3857 for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
3858 modem_info *info = &dev->mdm.info[i];
3859 if (info->msr & UART_MSR_RI) {
3860 ton = 1;
3861 isdn_tty_modem_result(RESULT_RING, info);
3862 }
3863 }
3864 isdn_timer_ctrl(ISDN_TIMER_MODEMRING, ton);
3865}
3866
3867/*
3868 * For all online tty's, try sending data to
3869 * the lower levels.
3870 */
3871void
3872isdn_tty_modem_xmit(void)
3873{
3874 int ton = 1;
3875 int i;
3876
3877 for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
3878 modem_info *info = &dev->mdm.info[i];
3879 if (info->online) {
3880 ton = 1;
3881 isdn_tty_senddown(info);
3882 isdn_tty_tint(info);
3883 }
3884 }
3885 isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, ton);
3886}
3887
3888/*
3889 * Check all channels if we have a 'no carrier' timeout.
3890 * Timeout value is set by Register S7.
3891 */
3892void
3893isdn_tty_carrier_timeout(void)
3894{
3895 int ton = 0;
3896 int i;
3897
3898 for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
3899 modem_info *info = &dev->mdm.info[i];
3900 if (info->dialing) {
3901 if (info->emu.carrierwait++ > info->emu.mdmreg[REG_WAITC]) {
3902 info->dialing = 0;
3903 isdn_tty_modem_result(RESULT_NO_CARRIER, info);
3904 isdn_tty_modem_hup(info, 1);
3905 }
3906 else
3907 ton = 1;
3908 }
3909 }
3910 isdn_timer_ctrl(ISDN_TIMER_CARRIER, ton);
3911}
diff --git a/drivers/isdn/i4l/isdn_tty.h b/drivers/isdn/i4l/isdn_tty.h
new file mode 100644
index 000000000000..2423a7ff0cc3
--- /dev/null
+++ b/drivers/isdn/i4l/isdn_tty.h
@@ -0,0 +1,122 @@
1/* $Id: isdn_tty.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
2 *
3 * header for Linux ISDN subsystem, tty related functions (linklevel).
4 *
5 * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
6 * Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 */
12
13#include <linux/config.h>
14
15#define DLE 0x10
16#define ETX 0x03
17#define DC4 0x14
18
19
20/*
21 * Definition of some special Registers of AT-Emulator
22 */
23#define REG_RINGATA 0
24#define REG_RINGCNT 1 /* ring counter register */
25#define REG_ESC 2
26#define REG_CR 3
27#define REG_LF 4
28#define REG_BS 5
29
30#define REG_WAITC 7
31
32#define REG_RESP 12 /* show response messages register */
33#define BIT_RESP 1 /* show response messages bit */
34#define REG_RESPNUM 12 /* show numeric responses register */
35#define BIT_RESPNUM 2 /* show numeric responses bit */
36#define REG_ECHO 12
37#define BIT_ECHO 4
38#define REG_DCD 12
39#define BIT_DCD 8
40#define REG_CTS 12
41#define BIT_CTS 16
42#define REG_DTRR 12
43#define BIT_DTRR 32
44#define REG_DSR 12
45#define BIT_DSR 64
46#define REG_CPPP 12
47#define BIT_CPPP 128
48
49#define REG_DXMT 13
50#define BIT_DXMT 1
51#define REG_T70 13
52#define BIT_T70 2
53#define BIT_T70_EXT 32
54#define REG_DTRHUP 13
55#define BIT_DTRHUP 4
56#define REG_RESPXT 13
57#define BIT_RESPXT 8
58#define REG_CIDONCE 13
59#define BIT_CIDONCE 16
60#define REG_RUNG 13 /* show RUNG message register */
61#define BIT_RUNG 64 /* show RUNG message bit */
62#define REG_DISPLAY 13
63#define BIT_DISPLAY 128
64
65#define REG_L2PROT 14
66#define REG_L3PROT 15
67#define REG_PSIZE 16
68#define REG_WSIZE 17
69#define REG_SI1 18
70#define REG_SI2 19
71#define REG_SI1I 20
72#define REG_PLAN 21
73#define REG_SCREEN 22
74
75#define REG_CPN 23
76#define BIT_CPN 1
77#define REG_CPNFCON 23
78#define BIT_CPNFCON 2
79#define REG_CDN 23
80#define BIT_CDN 4
81
82/* defines for result codes */
83#define RESULT_OK 0
84#define RESULT_CONNECT 1
85#define RESULT_RING 2
86#define RESULT_NO_CARRIER 3
87#define RESULT_ERROR 4
88#define RESULT_CONNECT64000 5
89#define RESULT_NO_DIALTONE 6
90#define RESULT_BUSY 7
91#define RESULT_NO_ANSWER 8
92#define RESULT_RINGING 9
93#define RESULT_NO_MSN_EAZ 10
94#define RESULT_VCON 11
95#define RESULT_RUNG 12
96
97#define TTY_IS_FCLASS1(info) \
98 ((info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_FAX) && \
99 (info->emu.mdmreg[REG_L3PROT] == ISDN_PROTO_L3_FCLASS1))
100#define TTY_IS_FCLASS2(info) \
101 ((info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_FAX) && \
102 (info->emu.mdmreg[REG_L3PROT] == ISDN_PROTO_L3_FCLASS2))
103
104extern void isdn_tty_modem_escape(void);
105extern void isdn_tty_modem_ring(void);
106extern void isdn_tty_carrier_timeout(void);
107extern void isdn_tty_modem_xmit(void);
108extern int isdn_tty_modem_init(void);
109extern void isdn_tty_exit(void);
110extern void isdn_tty_readmodem(void);
111extern int isdn_tty_find_icall(int, int, setup_parm *);
112extern void isdn_tty_cleanup_xmit(modem_info *);
113extern int isdn_tty_stat_callback(int, isdn_ctrl *);
114extern int isdn_tty_rcv_skb(int, int, int, struct sk_buff *);
115extern int isdn_tty_capi_facility(capi_msg *cm);
116extern void isdn_tty_at_cout(char *, modem_info *);
117extern void isdn_tty_modem_hup(modem_info *, int);
118#ifdef CONFIG_ISDN_TTY_FAX
119extern int isdn_tty_cmd_PLUSF_FAX(char **, modem_info *);
120extern int isdn_tty_fax_command(modem_info *, isdn_ctrl *);
121extern void isdn_tty_fax_bitorder(modem_info *, struct sk_buff *);
122#endif
diff --git a/drivers/isdn/i4l/isdn_ttyfax.c b/drivers/isdn/i4l/isdn_ttyfax.c
new file mode 100644
index 000000000000..ce2c3ef92e46
--- /dev/null
+++ b/drivers/isdn/i4l/isdn_ttyfax.c
@@ -0,0 +1,1122 @@
1/* $Id: isdn_ttyfax.c,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
2 *
3 * Linux ISDN subsystem, tty_fax AT-command emulator (linklevel).
4 *
5 * Copyright 1999 by Armin Schindler (mac@melware.de)
6 * Copyright 1999 by Ralf Spachmann (mel@melware.de)
7 * Copyright 1999 by Cytronics & Melware
8 *
9 * This software may be used and distributed according to the terms
10 * of the GNU General Public License, incorporated herein by reference.
11 *
12 */
13
14#undef ISDN_TTY_FAX_STAT_DEBUG
15#undef ISDN_TTY_FAX_CMD_DEBUG
16
17#include <linux/isdn.h>
18#include "isdn_common.h"
19#include "isdn_tty.h"
20#include "isdn_ttyfax.h"
21
22
23static char *isdn_tty_fax_revision = "$Revision: 1.1.2.2 $";
24
25#define PARSE_ERROR1 { isdn_tty_fax_modem_result(1, info); return 1; }
26
27static char *
28isdn_getrev(const char *revision)
29{
30 char *rev;
31 char *p;
32
33 if ((p = strchr(revision, ':'))) {
34 rev = p + 2;
35 p = strchr(rev, '$');
36 *--p = 0;
37 } else
38 rev = "???";
39 return rev;
40}
41
42/*
43 * Fax Class 2 Modem results
44 *
45 */
46
47static void
48isdn_tty_fax_modem_result(int code, modem_info * info)
49{
50 atemu *m = &info->emu;
51 T30_s *f = info->fax;
52 char rs[50];
53 char rss[50];
54 char *rp;
55 int i;
56 static char *msg[] =
57 {"OK", "ERROR", "+FCON", "+FCSI:", "+FDIS:",
58 "+FHNG:", "+FDCS:", "CONNECT", "+FTSI:",
59 "+FCFR", "+FPTS:", "+FET:"};
60
61
62 isdn_tty_at_cout("\r\n", info);
63 isdn_tty_at_cout(msg[code], info);
64
65#ifdef ISDN_TTY_FAX_CMD_DEBUG
66 printk(KERN_DEBUG "isdn_tty: Fax send %s on ttyI%d\n",
67 msg[code], info->line);
68#endif
69 switch (code) {
70 case 0: /* OK */
71 break;
72 case 1: /* ERROR */
73 break;
74 case 2: /* +FCON */
75 /* Append CPN, if enabled */
76 if ((m->mdmreg[REG_CPNFCON] & BIT_CPNFCON) &&
77 (!(dev->usage[info->isdn_channel] & ISDN_USAGE_OUTGOING))) {
78 sprintf(rs, "/%s", m->cpn);
79 isdn_tty_at_cout(rs, info);
80 }
81 info->online = 1;
82 f->fet = 0;
83 if (f->phase == ISDN_FAX_PHASE_A)
84 f->phase = ISDN_FAX_PHASE_B;
85 break;
86 case 3: /* +FCSI */
87 case 8: /* +FTSI */
88 sprintf(rs, "\"%s\"", f->r_id);
89 isdn_tty_at_cout(rs, info);
90 break;
91 case 4: /* +FDIS */
92 rs[0] = 0;
93 rp = &f->r_resolution;
94 for (i = 0; i < 8; i++) {
95 sprintf(rss, "%c%s", rp[i] + 48,
96 (i < 7) ? "," : "");
97 strcat(rs, rss);
98 }
99 isdn_tty_at_cout(rs, info);
100#ifdef ISDN_TTY_FAX_CMD_DEBUG
101 printk(KERN_DEBUG "isdn_tty: Fax DIS=%s on ttyI%d\n",
102 rs, info->line);
103#endif
104 break;
105 case 5: /* +FHNG */
106 sprintf(rs, "%d", f->code);
107 isdn_tty_at_cout(rs, info);
108 info->faxonline = 0;
109 break;
110 case 6: /* +FDCS */
111 rs[0] = 0;
112 rp = &f->r_resolution;
113 for (i = 0; i < 8; i++) {
114 sprintf(rss, "%c%s", rp[i] + 48,
115 (i < 7) ? "," : "");
116 strcat(rs, rss);
117 }
118 isdn_tty_at_cout(rs, info);
119#ifdef ISDN_TTY_FAX_CMD_DEBUG
120 printk(KERN_DEBUG "isdn_tty: Fax DCS=%s on ttyI%d\n",
121 rs, info->line);
122#endif
123 break;
124 case 7: /* CONNECT */
125 info->faxonline |= 2;
126 break;
127 case 9: /* FCFR */
128 break;
129 case 10: /* FPTS */
130 isdn_tty_at_cout("1", info);
131 break;
132 case 11: /* FET */
133 sprintf(rs, "%d", f->fet);
134 isdn_tty_at_cout(rs, info);
135 break;
136 }
137
138 isdn_tty_at_cout("\r\n", info);
139
140 switch (code) {
141 case 7: /* CONNECT */
142 info->online = 2;
143 if (info->faxonline & 1) {
144 sprintf(rs, "%c", XON);
145 isdn_tty_at_cout(rs, info);
146 }
147 break;
148 }
149}
150
151int
152isdn_tty_fax_command1(modem_info * info, isdn_ctrl * c)
153{
154 static char *msg[] =
155 {"OK", "CONNECT", "NO CARRIER", "ERROR", "FCERROR"};
156
157#ifdef ISDN_TTY_FAX_CMD_DEBUG
158 printk(KERN_DEBUG "isdn_tty: FCLASS1 cmd(%d)\n", c->parm.aux.cmd);
159#endif
160 if (c->parm.aux.cmd < ISDN_FAX_CLASS1_QUERY) {
161 if (info->online)
162 info->online = 1;
163 isdn_tty_at_cout("\r\n", info);
164 isdn_tty_at_cout(msg[c->parm.aux.cmd], info);
165 isdn_tty_at_cout("\r\n", info);
166 }
167 switch (c->parm.aux.cmd) {
168 case ISDN_FAX_CLASS1_CONNECT:
169 info->online = 2;
170 break;
171 case ISDN_FAX_CLASS1_OK:
172 case ISDN_FAX_CLASS1_FCERROR:
173 case ISDN_FAX_CLASS1_ERROR:
174 case ISDN_FAX_CLASS1_NOCARR:
175 break;
176 case ISDN_FAX_CLASS1_QUERY:
177 isdn_tty_at_cout("\r\n", info);
178 if (!c->parm.aux.para[0]) {
179 isdn_tty_at_cout(msg[ISDN_FAX_CLASS1_ERROR], info);
180 isdn_tty_at_cout("\r\n", info);
181 } else {
182 isdn_tty_at_cout(c->parm.aux.para, info);
183 isdn_tty_at_cout("\r\nOK\r\n", info);
184 }
185 break;
186 }
187 return (0);
188}
189
190int
191isdn_tty_fax_command(modem_info * info, isdn_ctrl * c)
192{
193 T30_s *f = info->fax;
194 char rs[10];
195
196 if (TTY_IS_FCLASS1(info))
197 return (isdn_tty_fax_command1(info, c));
198
199#ifdef ISDN_TTY_FAX_CMD_DEBUG
200 printk(KERN_DEBUG "isdn_tty: Fax cmd %d on ttyI%d\n",
201 f->r_code, info->line);
202#endif
203 switch (f->r_code) {
204 case ISDN_TTY_FAX_FCON:
205 info->faxonline = 1;
206 isdn_tty_fax_modem_result(2, info); /* +FCON */
207 return (0);
208 case ISDN_TTY_FAX_FCON_I:
209 info->faxonline = 16;
210 isdn_tty_fax_modem_result(2, info); /* +FCON */
211 return (0);
212 case ISDN_TTY_FAX_RID:
213 if (info->faxonline & 1)
214 isdn_tty_fax_modem_result(3, info); /* +FCSI */
215 if (info->faxonline & 16)
216 isdn_tty_fax_modem_result(8, info); /* +FTSI */
217 return (0);
218 case ISDN_TTY_FAX_DIS:
219 isdn_tty_fax_modem_result(4, info); /* +FDIS */
220 return (0);
221 case ISDN_TTY_FAX_HNG:
222 if (f->phase == ISDN_FAX_PHASE_C) {
223 if (f->direction == ISDN_TTY_FAX_CONN_IN) {
224 sprintf(rs, "%c%c", DLE, ETX);
225 isdn_tty_at_cout(rs, info);
226 } else {
227 sprintf(rs, "%c", 0x18);
228 isdn_tty_at_cout(rs, info);
229 }
230 info->faxonline &= ~2; /* leave data mode */
231 info->online = 1;
232 }
233 f->phase = ISDN_FAX_PHASE_E;
234 isdn_tty_fax_modem_result(5, info); /* +FHNG */
235 isdn_tty_fax_modem_result(0, info); /* OK */
236 return (0);
237 case ISDN_TTY_FAX_DCS:
238 isdn_tty_fax_modem_result(6, info); /* +FDCS */
239 isdn_tty_fax_modem_result(7, info); /* CONNECT */
240 f->phase = ISDN_FAX_PHASE_C;
241 return (0);
242 case ISDN_TTY_FAX_TRAIN_OK:
243 isdn_tty_fax_modem_result(6, info); /* +FDCS */
244 isdn_tty_fax_modem_result(0, info); /* OK */
245 return (0);
246 case ISDN_TTY_FAX_SENT:
247 isdn_tty_fax_modem_result(0, info); /* OK */
248 return (0);
249 case ISDN_TTY_FAX_CFR:
250 isdn_tty_fax_modem_result(9, info); /* +FCFR */
251 return (0);
252 case ISDN_TTY_FAX_ET:
253 sprintf(rs, "%c%c", DLE, ETX);
254 isdn_tty_at_cout(rs, info);
255 isdn_tty_fax_modem_result(10, info); /* +FPTS */
256 isdn_tty_fax_modem_result(11, info); /* +FET */
257 isdn_tty_fax_modem_result(0, info); /* OK */
258 info->faxonline &= ~2; /* leave data mode */
259 info->online = 1;
260 f->phase = ISDN_FAX_PHASE_D;
261 return (0);
262 case ISDN_TTY_FAX_PTS:
263 isdn_tty_fax_modem_result(10, info); /* +FPTS */
264 if (f->direction == ISDN_TTY_FAX_CONN_OUT) {
265 if (f->fet == 1)
266 f->phase = ISDN_FAX_PHASE_B;
267 if (f->fet == 0)
268 isdn_tty_fax_modem_result(0, info); /* OK */
269 }
270 return (0);
271 case ISDN_TTY_FAX_EOP:
272 info->faxonline &= ~2; /* leave data mode */
273 info->online = 1;
274 f->phase = ISDN_FAX_PHASE_D;
275 return (0);
276
277 }
278 return (-1);
279}
280
281
282void
283isdn_tty_fax_bitorder(modem_info * info, struct sk_buff *skb)
284{
285 __u8 LeftMask;
286 __u8 RightMask;
287 __u8 fBit;
288 __u8 Data;
289 int i;
290
291 if (!info->fax->bor) {
292 for (i = 0; i < skb->len; i++) {
293 Data = skb->data[i];
294 for (
295 LeftMask = 0x80, RightMask = 0x01;
296 LeftMask > RightMask;
297 LeftMask >>= 1, RightMask <<= 1
298 ) {
299 fBit = (Data & LeftMask);
300 if (Data & RightMask)
301 Data |= LeftMask;
302 else
303 Data &= ~LeftMask;
304 if (fBit)
305 Data |= RightMask;
306 else
307 Data &= ~RightMask;
308
309 }
310 skb->data[i] = Data;
311 }
312 }
313}
314
315/*
316 * Parse AT+F.. FAX class 1 commands
317 */
318
319int
320isdn_tty_cmd_FCLASS1(char **p, modem_info * info)
321{
322 static char *cmd[] =
323 {"AE", "TS", "RS", "TM", "RM", "TH", "RH"};
324 isdn_ctrl c;
325 int par, i;
326 u_long flags;
327
328 for (c.parm.aux.cmd = 0; c.parm.aux.cmd < 7; c.parm.aux.cmd++)
329 if (!strncmp(p[0], cmd[c.parm.aux.cmd], 2))
330 break;
331
332#ifdef ISDN_TTY_FAX_CMD_DEBUG
333 printk(KERN_DEBUG "isdn_tty_cmd_FCLASS1 (%s,%d)\n", p[0], c.parm.aux.cmd);
334#endif
335 if (c.parm.aux.cmd == 7)
336 PARSE_ERROR1;
337
338 p[0] += 2;
339 switch (*p[0]) {
340 case '?':
341 p[0]++;
342 c.parm.aux.subcmd = AT_QUERY;
343 break;
344 case '=':
345 p[0]++;
346 if (*p[0] == '?') {
347 p[0]++;
348 c.parm.aux.subcmd = AT_EQ_QUERY;
349 } else {
350 par = isdn_getnum(p);
351 if ((par < 0) || (par > 255))
352 PARSE_ERROR1;
353 c.parm.aux.subcmd = AT_EQ_VALUE;
354 c.parm.aux.para[0] = par;
355 }
356 break;
357 case 0:
358 c.parm.aux.subcmd = AT_COMMAND;
359 break;
360 default:
361 PARSE_ERROR1;
362 }
363 c.command = ISDN_CMD_FAXCMD;
364#ifdef ISDN_TTY_FAX_CMD_DEBUG
365 printk(KERN_DEBUG "isdn_tty_cmd_FCLASS1 %d/%d/%d)\n",
366 c.parm.aux.cmd, c.parm.aux.subcmd, c.parm.aux.para[0]);
367#endif
368 if (info->isdn_driver < 0) {
369 if ((c.parm.aux.subcmd == AT_EQ_VALUE) ||
370 (c.parm.aux.subcmd == AT_COMMAND)) {
371 PARSE_ERROR1;
372 }
373 spin_lock_irqsave(&dev->lock, flags);
374 /* get a temporary connection to the first free fax driver */
375 i = isdn_get_free_channel(ISDN_USAGE_FAX, ISDN_PROTO_L2_FAX,
376 ISDN_PROTO_L3_FCLASS1, -1, -1, "00");
377 if (i < 0) {
378 spin_unlock_irqrestore(&dev->lock, flags);
379 PARSE_ERROR1;
380 }
381 info->isdn_driver = dev->drvmap[i];
382 info->isdn_channel = dev->chanmap[i];
383 info->drv_index = i;
384 dev->m_idx[i] = info->line;
385 spin_unlock_irqrestore(&dev->lock, flags);
386 c.driver = info->isdn_driver;
387 c.arg = info->isdn_channel;
388 isdn_command(&c);
389 spin_lock_irqsave(&dev->lock, flags);
390 isdn_free_channel(info->isdn_driver, info->isdn_channel,
391 ISDN_USAGE_FAX);
392 info->isdn_driver = -1;
393 info->isdn_channel = -1;
394 if (info->drv_index >= 0) {
395 dev->m_idx[info->drv_index] = -1;
396 info->drv_index = -1;
397 }
398 spin_unlock_irqrestore(&dev->lock, flags);
399 } else {
400 c.driver = info->isdn_driver;
401 c.arg = info->isdn_channel;
402 isdn_command(&c);
403 }
404 return 1;
405}
406
407/*
408 * Parse AT+F.. FAX class 2 commands
409 */
410
411int
412isdn_tty_cmd_FCLASS2(char **p, modem_info * info)
413{
414 atemu *m = &info->emu;
415 T30_s *f = info->fax;
416 isdn_ctrl cmd;
417 int par;
418 char rs[50];
419 char rss[50];
420 int maxdccval[] =
421 {1, 5, 2, 2, 3, 2, 0, 7};
422
423 /* FAA still unchanged */
424 if (!strncmp(p[0], "AA", 2)) { /* TODO */
425 p[0] += 2;
426 switch (*p[0]) {
427 case '?':
428 p[0]++;
429 sprintf(rs, "\r\n%d", 0);
430 isdn_tty_at_cout(rs, info);
431 break;
432 case '=':
433 p[0]++;
434 par = isdn_getnum(p);
435 if ((par < 0) || (par > 255))
436 PARSE_ERROR1;
437 break;
438 default:
439 PARSE_ERROR1;
440 }
441 return 0;
442 }
443 /* BADLIN=value - dummy 0=disable errorchk disabled, 1-255 nr. of lines for making page bad */
444 if (!strncmp(p[0], "BADLIN", 6)) {
445 p[0] += 6;
446 switch (*p[0]) {
447 case '?':
448 p[0]++;
449 sprintf(rs, "\r\n%d", f->badlin);
450 isdn_tty_at_cout(rs, info);
451 break;
452 case '=':
453 p[0]++;
454 if (*p[0] == '?') {
455 p[0]++;
456 sprintf(rs, "\r\n0-255");
457 isdn_tty_at_cout(rs, info);
458 } else {
459 par = isdn_getnum(p);
460 if ((par < 0) || (par > 255))
461 PARSE_ERROR1;
462 f->badlin = par;
463#ifdef ISDN_TTY_FAX_STAT_DEBUG
464 printk(KERN_DEBUG "isdn_tty: Fax FBADLIN=%d\n", par);
465#endif
466 }
467 break;
468 default:
469 PARSE_ERROR1;
470 }
471 return 0;
472 }
473 /* BADMUL=value - dummy 0=disable errorchk disabled (treshold multiplier) */
474 if (!strncmp(p[0], "BADMUL", 6)) {
475 p[0] += 6;
476 switch (*p[0]) {
477 case '?':
478 p[0]++;
479 sprintf(rs, "\r\n%d", f->badmul);
480 isdn_tty_at_cout(rs, info);
481 break;
482 case '=':
483 p[0]++;
484 if (*p[0] == '?') {
485 p[0]++;
486 sprintf(rs, "\r\n0-255");
487 isdn_tty_at_cout(rs, info);
488 } else {
489 par = isdn_getnum(p);
490 if ((par < 0) || (par > 255))
491 PARSE_ERROR1;
492 f->badmul = par;
493#ifdef ISDN_TTY_FAX_STAT_DEBUG
494 printk(KERN_DEBUG "isdn_tty: Fax FBADMUL=%d\n", par);
495#endif
496 }
497 break;
498 default:
499 PARSE_ERROR1;
500 }
501 return 0;
502 }
503 /* BOR=n - Phase C bit order, 0=direct, 1=reverse */
504 if (!strncmp(p[0], "BOR", 3)) {
505 p[0] += 3;
506 switch (*p[0]) {
507 case '?':
508 p[0]++;
509 sprintf(rs, "\r\n%d", f->bor);
510 isdn_tty_at_cout(rs, info);
511 break;
512 case '=':
513 p[0]++;
514 if (*p[0] == '?') {
515 p[0]++;
516 sprintf(rs, "\r\n0,1");
517 isdn_tty_at_cout(rs, info);
518 } else {
519 par = isdn_getnum(p);
520 if ((par < 0) || (par > 1))
521 PARSE_ERROR1;
522 f->bor = par;
523#ifdef ISDN_TTY_FAX_STAT_DEBUG
524 printk(KERN_DEBUG "isdn_tty: Fax FBOR=%d\n", par);
525#endif
526 }
527 break;
528 default:
529 PARSE_ERROR1;
530 }
531 return 0;
532 }
533 /* NBC=n - No Best Capabilities */
534 if (!strncmp(p[0], "NBC", 3)) {
535 p[0] += 3;
536 switch (*p[0]) {
537 case '?':
538 p[0]++;
539 sprintf(rs, "\r\n%d", f->nbc);
540 isdn_tty_at_cout(rs, info);
541 break;
542 case '=':
543 p[0]++;
544 if (*p[0] == '?') {
545 p[0]++;
546 sprintf(rs, "\r\n0,1");
547 isdn_tty_at_cout(rs, info);
548 } else {
549 par = isdn_getnum(p);
550 if ((par < 0) || (par > 1))
551 PARSE_ERROR1;
552 f->nbc = par;
553#ifdef ISDN_TTY_FAX_STAT_DEBUG
554 printk(KERN_DEBUG "isdn_tty: Fax FNBC=%d\n", par);
555#endif
556 }
557 break;
558 default:
559 PARSE_ERROR1;
560 }
561 return 0;
562 }
563 /* BUF? - Readonly buffersize readout */
564 if (!strncmp(p[0], "BUF?", 4)) {
565 p[0] += 4;
566#ifdef ISDN_TTY_FAX_STAT_DEBUG
567 printk(KERN_DEBUG "isdn_tty: Fax FBUF? (%d) \n", (16 * m->mdmreg[REG_PSIZE]));
568#endif
569 p[0]++;
570 sprintf(rs, "\r\n %d ", (16 * m->mdmreg[REG_PSIZE]));
571 isdn_tty_at_cout(rs, info);
572 return 0;
573 }
574 /* CIG=string - local fax station id string for polling rx */
575 if (!strncmp(p[0], "CIG", 3)) {
576 int i, r;
577 p[0] += 3;
578 switch (*p[0]) {
579 case '?':
580 p[0]++;
581 sprintf(rs, "\r\n\"%s\"", f->pollid);
582 isdn_tty_at_cout(rs, info);
583 break;
584 case '=':
585 p[0]++;
586 if (*p[0] == '?') {
587 p[0]++;
588 sprintf(rs, "\r\n\"STRING\"");
589 isdn_tty_at_cout(rs, info);
590 } else {
591 if (*p[0] == '"')
592 p[0]++;
593 for (i = 0; (*p[0]) && i < (FAXIDLEN - 1) && (*p[0] != '"'); i++) {
594 f->pollid[i] = *p[0]++;
595 }
596 if (*p[0] == '"')
597 p[0]++;
598 for (r = i; r < FAXIDLEN; r++) {
599 f->pollid[r] = 32;
600 }
601 f->pollid[FAXIDLEN - 1] = 0;
602#ifdef ISDN_TTY_FAX_STAT_DEBUG
603 printk(KERN_DEBUG "isdn_tty: Fax local poll ID rx \"%s\"\n", f->pollid);
604#endif
605 }
606 break;
607 default:
608 PARSE_ERROR1;
609 }
610 return 0;
611 }
612 /* CQ=n - copy qlty chk, 0= no chk, 1=only 1D chk, 2=1D+2D chk */
613 if (!strncmp(p[0], "CQ", 2)) {
614 p[0] += 2;
615 switch (*p[0]) {
616 case '?':
617 p[0]++;
618 sprintf(rs, "\r\n%d", f->cq);
619 isdn_tty_at_cout(rs, info);
620 break;
621 case '=':
622 p[0]++;
623 if (*p[0] == '?') {
624 p[0]++;
625 sprintf(rs, "\r\n0,1,2");
626 isdn_tty_at_cout(rs, info);
627 } else {
628 par = isdn_getnum(p);
629 if ((par < 0) || (par > 2))
630 PARSE_ERROR1;
631 f->cq = par;
632#ifdef ISDN_TTY_FAX_STAT_DEBUG
633 printk(KERN_DEBUG "isdn_tty: Fax FCQ=%d\n", par);
634#endif
635 }
636 break;
637 default:
638 PARSE_ERROR1;
639 }
640 return 0;
641 }
642 /* CR=n - can receive? 0= no data rx or poll remote dev, 1=do receive data or poll remote dev */
643 if (!strncmp(p[0], "CR", 2)) {
644 p[0] += 2;
645 switch (*p[0]) {
646 case '?':
647 p[0]++;
648 sprintf(rs, "\r\n%d", f->cr); /* read actual value from struct and print */
649 isdn_tty_at_cout(rs, info);
650 break;
651 case '=':
652 p[0]++;
653 if (*p[0] == '?') {
654 p[0]++;
655 sprintf(rs, "\r\n0,1"); /* display online help */
656 isdn_tty_at_cout(rs, info);
657 } else {
658 par = isdn_getnum(p);
659 if ((par < 0) || (par > 1))
660 PARSE_ERROR1;
661 f->cr = par;
662#ifdef ISDN_TTY_FAX_STAT_DEBUG
663 printk(KERN_DEBUG "isdn_tty: Fax FCR=%d\n", par);
664#endif
665 }
666 break;
667 default:
668 PARSE_ERROR1;
669 }
670 return 0;
671 }
672 /* CTCRTY=value - ECM retry count */
673 if (!strncmp(p[0], "CTCRTY", 6)) {
674 p[0] += 6;
675 switch (*p[0]) {
676 case '?':
677 p[0]++;
678 sprintf(rs, "\r\n%d", f->ctcrty);
679 isdn_tty_at_cout(rs, info);
680 break;
681 case '=':
682 p[0]++;
683 if (*p[0] == '?') {
684 p[0]++;
685 sprintf(rs, "\r\n0-255");
686 isdn_tty_at_cout(rs, info);
687 } else {
688 par = isdn_getnum(p);
689 if ((par < 0) || (par > 255))
690 PARSE_ERROR1;
691 f->ctcrty = par;
692#ifdef ISDN_TTY_FAX_STAT_DEBUG
693 printk(KERN_DEBUG "isdn_tty: Fax FCTCRTY=%d\n", par);
694#endif
695 }
696 break;
697 default:
698 PARSE_ERROR1;
699 }
700 return 0;
701 }
702 /* DCC=vr,br,wd,ln,df,ec,bf,st - DCE capabilities parms */
703 if (!strncmp(p[0], "DCC", 3)) {
704 char *rp = &f->resolution;
705 int i;
706
707 p[0] += 3;
708 switch (*p[0]) {
709 case '?':
710 p[0]++;
711 strcpy(rs, "\r\n");
712 for (i = 0; i < 8; i++) {
713 sprintf(rss, "%c%s", rp[i] + 48,
714 (i < 7) ? "," : "");
715 strcat(rs, rss);
716 }
717 isdn_tty_at_cout(rs, info);
718 break;
719 case '=':
720 p[0]++;
721 if (*p[0] == '?') {
722 isdn_tty_at_cout("\r\n(0,1),(0-5),(0-2),(0-2),(0-3),(0-2),(0),(0-7)", info);
723 p[0]++;
724 } else {
725 for (i = 0; (((*p[0] >= '0') && (*p[0] <= '9')) || (*p[0] == ',')) && (i < 8); i++) {
726 if (*p[0] != ',') {
727 if ((*p[0] - 48) > maxdccval[i]) {
728 PARSE_ERROR1;
729 }
730 rp[i] = *p[0] - 48;
731 p[0]++;
732 if (*p[0] == ',')
733 p[0]++;
734 } else
735 p[0]++;
736 }
737#ifdef ISDN_TTY_FAX_STAT_DEBUG
738 printk(KERN_DEBUG "isdn_tty: Fax FDCC capabilities DCE=%d,%d,%d,%d,%d,%d,%d,%d\n",
739 rp[0], rp[1], rp[2], rp[3], rp[4], rp[5], rp[6], rp[7]);
740#endif
741 }
742 break;
743 default:
744 PARSE_ERROR1;
745 }
746 return 0;
747 }
748 /* DIS=vr,br,wd,ln,df,ec,bf,st - current session parms */
749 if (!strncmp(p[0], "DIS", 3)) {
750 char *rp = &f->resolution;
751 int i;
752
753 p[0] += 3;
754 switch (*p[0]) {
755 case '?':
756 p[0]++;
757 strcpy(rs, "\r\n");
758 for (i = 0; i < 8; i++) {
759 sprintf(rss, "%c%s", rp[i] + 48,
760 (i < 7) ? "," : "");
761 strcat(rs, rss);
762 }
763 isdn_tty_at_cout(rs, info);
764 break;
765 case '=':
766 p[0]++;
767 if (*p[0] == '?') {
768 isdn_tty_at_cout("\r\n(0,1),(0-5),(0-2),(0-2),(0-3),(0-2),(0),(0-7)", info);
769 p[0]++;
770 } else {
771 for (i = 0; (((*p[0] >= '0') && (*p[0] <= '9')) || (*p[0] == ',')) && (i < 8); i++) {
772 if (*p[0] != ',') {
773 if ((*p[0] - 48) > maxdccval[i]) {
774 PARSE_ERROR1;
775 }
776 rp[i] = *p[0] - 48;
777 p[0]++;
778 if (*p[0] == ',')
779 p[0]++;
780 } else
781 p[0]++;
782 }
783#ifdef ISDN_TTY_FAX_STAT_DEBUG
784 printk(KERN_DEBUG "isdn_tty: Fax FDIS session parms=%d,%d,%d,%d,%d,%d,%d,%d\n",
785 rp[0], rp[1], rp[2], rp[3], rp[4], rp[5], rp[6], rp[7]);
786#endif
787 }
788 break;
789 default:
790 PARSE_ERROR1;
791 }
792 return 0;
793 }
794 /* DR - Receive Phase C data command, initiates document reception */
795 if (!strncmp(p[0], "DR", 2)) {
796 p[0] += 2;
797 if ((info->faxonline & 16) && /* incoming connection */
798 ((f->phase == ISDN_FAX_PHASE_B) || (f->phase == ISDN_FAX_PHASE_D))) {
799#ifdef ISDN_TTY_FAX_STAT_DEBUG
800 printk(KERN_DEBUG "isdn_tty: Fax FDR\n");
801#endif
802 f->code = ISDN_TTY_FAX_DR;
803 cmd.driver = info->isdn_driver;
804 cmd.arg = info->isdn_channel;
805 cmd.command = ISDN_CMD_FAXCMD;
806 isdn_command(&cmd);
807 if (f->phase == ISDN_FAX_PHASE_B) {
808 f->phase = ISDN_FAX_PHASE_C;
809 } else if (f->phase == ISDN_FAX_PHASE_D) {
810 switch (f->fet) {
811 case 0: /* next page will be received */
812 f->phase = ISDN_FAX_PHASE_C;
813 isdn_tty_fax_modem_result(7, info); /* CONNECT */
814 break;
815 case 1: /* next doc will be received */
816 f->phase = ISDN_FAX_PHASE_B;
817 break;
818 case 2: /* fax session is terminating */
819 f->phase = ISDN_FAX_PHASE_E;
820 break;
821 default:
822 PARSE_ERROR1;
823 }
824 }
825 } else {
826 PARSE_ERROR1;
827 }
828 return 1;
829 }
830 /* DT=df,vr,wd,ln - TX phase C data command (release DCE to proceed with negotiation) */
831 if (!strncmp(p[0], "DT", 2)) {
832 int i, val[] =
833 {4, 0, 2, 3};
834 char *rp = &f->resolution;
835
836 p[0] += 2;
837 if (!info->faxonline & 1) /* not outgoing connection */
838 PARSE_ERROR1;
839
840 for (i = 0; (((*p[0] >= '0') && (*p[0] <= '9')) || (*p[0] == ',')) && (i < 4); i++) {
841 if (*p[0] != ',') {
842 if ((*p[0] - 48) > maxdccval[val[i]]) {
843 PARSE_ERROR1;
844 }
845 rp[val[i]] = *p[0] - 48;
846 p[0]++;
847 if (*p[0] == ',')
848 p[0]++;
849 } else
850 p[0]++;
851 }
852#ifdef ISDN_TTY_FAX_STAT_DEBUG
853 printk(KERN_DEBUG "isdn_tty: Fax FDT tx data command parms=%d,%d,%d,%d\n",
854 rp[4], rp[0], rp[2], rp[3]);
855#endif
856 if ((f->phase == ISDN_FAX_PHASE_B) || (f->phase == ISDN_FAX_PHASE_D)) {
857 f->code = ISDN_TTY_FAX_DT;
858 cmd.driver = info->isdn_driver;
859 cmd.arg = info->isdn_channel;
860 cmd.command = ISDN_CMD_FAXCMD;
861 isdn_command(&cmd);
862 if (f->phase == ISDN_FAX_PHASE_D) {
863 f->phase = ISDN_FAX_PHASE_C;
864 isdn_tty_fax_modem_result(7, info); /* CONNECT */
865 }
866 } else {
867 PARSE_ERROR1;
868 }
869 return 1;
870 }
871 /* ECM=n - Error mode control 0=disabled, 2=enabled, handled by DCE alone incl. buff of partial pages */
872 if (!strncmp(p[0], "ECM", 3)) {
873 p[0] += 3;
874 switch (*p[0]) {
875 case '?':
876 p[0]++;
877 sprintf(rs, "\r\n%d", f->ecm);
878 isdn_tty_at_cout(rs, info);
879 break;
880 case '=':
881 p[0]++;
882 if (*p[0] == '?') {
883 p[0]++;
884 sprintf(rs, "\r\n0,2");
885 isdn_tty_at_cout(rs, info);
886 } else {
887 par = isdn_getnum(p);
888 if ((par != 0) && (par != 2))
889 PARSE_ERROR1;
890 f->ecm = par;
891#ifdef ISDN_TTY_FAX_STAT_DEBUG
892 printk(KERN_DEBUG "isdn_tty: Fax FECM=%d\n", par);
893#endif
894 }
895 break;
896 default:
897 PARSE_ERROR1;
898 }
899 return 0;
900 }
901 /* ET=n - End of page or document */
902 if (!strncmp(p[0], "ET=", 3)) {
903 p[0] += 3;
904 if (*p[0] == '?') {
905 p[0]++;
906 sprintf(rs, "\r\n0-2");
907 isdn_tty_at_cout(rs, info);
908 } else {
909 if ((f->phase != ISDN_FAX_PHASE_D) || (!info->faxonline & 1))
910 PARSE_ERROR1;
911 par = isdn_getnum(p);
912 if ((par < 0) || (par > 2))
913 PARSE_ERROR1;
914 f->fet = par;
915 f->code = ISDN_TTY_FAX_ET;
916 cmd.driver = info->isdn_driver;
917 cmd.arg = info->isdn_channel;
918 cmd.command = ISDN_CMD_FAXCMD;
919 isdn_command(&cmd);
920#ifdef ISDN_TTY_FAX_STAT_DEBUG
921 printk(KERN_DEBUG "isdn_tty: Fax FET=%d\n", par);
922#endif
923 return 1;
924 }
925 return 0;
926 }
927 /* K - terminate */
928 if (!strncmp(p[0], "K", 1)) {
929 p[0] += 1;
930 if ((f->phase == ISDN_FAX_PHASE_IDLE) || (f->phase == ISDN_FAX_PHASE_E))
931 PARSE_ERROR1;
932 isdn_tty_modem_hup(info, 1);
933 return 1;
934 }
935 /* LID=string - local fax ID */
936 if (!strncmp(p[0], "LID", 3)) {
937 int i, r;
938 p[0] += 3;
939 switch (*p[0]) {
940 case '?':
941 p[0]++;
942 sprintf(rs, "\r\n\"%s\"", f->id);
943 isdn_tty_at_cout(rs, info);
944 break;
945 case '=':
946 p[0]++;
947 if (*p[0] == '?') {
948 p[0]++;
949 sprintf(rs, "\r\n\"STRING\"");
950 isdn_tty_at_cout(rs, info);
951 } else {
952 if (*p[0] == '"')
953 p[0]++;
954 for (i = 0; (*p[0]) && i < (FAXIDLEN - 1) && (*p[0] != '"'); i++) {
955 f->id[i] = *p[0]++;
956 }
957 if (*p[0] == '"')
958 p[0]++;
959 for (r = i; r < FAXIDLEN; r++) {
960 f->id[r] = 32;
961 }
962 f->id[FAXIDLEN - 1] = 0;
963#ifdef ISDN_TTY_FAX_STAT_DEBUG
964 printk(KERN_DEBUG "isdn_tty: Fax local ID \"%s\"\n", f->id);
965#endif
966 }
967 break;
968 default:
969 PARSE_ERROR1;
970 }
971 return 0;
972 }
973
974 /* MDL? - DCE Model */
975 if (!strncmp(p[0], "MDL?", 4)) {
976 p[0] += 4;
977#ifdef ISDN_TTY_FAX_STAT_DEBUG
978 printk(KERN_DEBUG "isdn_tty: FMDL?\n");
979#endif
980 isdn_tty_at_cout("\r\nisdn4linux", info);
981 return 0;
982 }
983 /* MFR? - DCE Manufacturer */
984 if (!strncmp(p[0], "MFR?", 4)) {
985 p[0] += 4;
986#ifdef ISDN_TTY_FAX_STAT_DEBUG
987 printk(KERN_DEBUG "isdn_tty: FMFR?\n");
988#endif
989 isdn_tty_at_cout("\r\nisdn4linux", info);
990 return 0;
991 }
992 /* MINSP=n - Minimum Speed for Phase C */
993 if (!strncmp(p[0], "MINSP", 5)) {
994 p[0] += 5;
995 switch (*p[0]) {
996 case '?':
997 p[0]++;
998 sprintf(rs, "\r\n%d", f->minsp);
999 isdn_tty_at_cout(rs, info);
1000 break;
1001 case '=':
1002 p[0]++;
1003 if (*p[0] == '?') {
1004 p[0]++;
1005 sprintf(rs, "\r\n0-5");
1006 isdn_tty_at_cout(rs, info);
1007 } else {
1008 par = isdn_getnum(p);
1009 if ((par < 0) || (par > 5))
1010 PARSE_ERROR1;
1011 f->minsp = par;
1012#ifdef ISDN_TTY_FAX_STAT_DEBUG
1013 printk(KERN_DEBUG "isdn_tty: Fax FMINSP=%d\n", par);
1014#endif
1015 }
1016 break;
1017 default:
1018 PARSE_ERROR1;
1019 }
1020 return 0;
1021 }
1022 /* PHCTO=value - DTE phase C timeout */
1023 if (!strncmp(p[0], "PHCTO", 5)) {
1024 p[0] += 5;
1025 switch (*p[0]) {
1026 case '?':
1027 p[0]++;
1028 sprintf(rs, "\r\n%d", f->phcto);
1029 isdn_tty_at_cout(rs, info);
1030 break;
1031 case '=':
1032 p[0]++;
1033 if (*p[0] == '?') {
1034 p[0]++;
1035 sprintf(rs, "\r\n0-255");
1036 isdn_tty_at_cout(rs, info);
1037 } else {
1038 par = isdn_getnum(p);
1039 if ((par < 0) || (par > 255))
1040 PARSE_ERROR1;
1041 f->phcto = par;
1042#ifdef ISDN_TTY_FAX_STAT_DEBUG
1043 printk(KERN_DEBUG "isdn_tty: Fax FPHCTO=%d\n", par);
1044#endif
1045 }
1046 break;
1047 default:
1048 PARSE_ERROR1;
1049 }
1050 return 0;
1051 }
1052
1053 /* REL=n - Phase C received EOL alignment */
1054 if (!strncmp(p[0], "REL", 3)) {
1055 p[0] += 3;
1056 switch (*p[0]) {
1057 case '?':
1058 p[0]++;
1059 sprintf(rs, "\r\n%d", f->rel);
1060 isdn_tty_at_cout(rs, info);
1061 break;
1062 case '=':
1063 p[0]++;
1064 if (*p[0] == '?') {
1065 p[0]++;
1066 sprintf(rs, "\r\n0,1");
1067 isdn_tty_at_cout(rs, info);
1068 } else {
1069 par = isdn_getnum(p);
1070 if ((par < 0) || (par > 1))
1071 PARSE_ERROR1;
1072 f->rel = par;
1073#ifdef ISDN_TTY_FAX_STAT_DEBUG
1074 printk(KERN_DEBUG "isdn_tty: Fax FREL=%d\n", par);
1075#endif
1076 }
1077 break;
1078 default:
1079 PARSE_ERROR1;
1080 }
1081 return 0;
1082 }
1083 /* REV? - DCE Revision */
1084 if (!strncmp(p[0], "REV?", 4)) {
1085 p[0] += 4;
1086#ifdef ISDN_TTY_FAX_STAT_DEBUG
1087 printk(KERN_DEBUG "isdn_tty: FREV?\n");
1088#endif
1089 strcpy(rss, isdn_tty_fax_revision);
1090 sprintf(rs, "\r\nRev: %s", isdn_getrev(rss));
1091 isdn_tty_at_cout(rs, info);
1092 return 0;
1093 }
1094
1095 /* Phase C Transmit Data Block Size */
1096 if (!strncmp(p[0], "TBC=", 4)) { /* dummy, not used */
1097 p[0] += 4;
1098#ifdef ISDN_TTY_FAX_STAT_DEBUG
1099 printk(KERN_DEBUG "isdn_tty: Fax FTBC=%c\n", *p[0]);
1100#endif
1101 switch (*p[0]) {
1102 case '0':
1103 p[0]++;
1104 break;
1105 default:
1106 PARSE_ERROR1;
1107 }
1108 return 0;
1109 }
1110 printk(KERN_DEBUG "isdn_tty: unknown token=>AT+F%s<\n", p[0]);
1111 PARSE_ERROR1;
1112}
1113
1114int
1115isdn_tty_cmd_PLUSF_FAX(char **p, modem_info * info)
1116{
1117 if (TTY_IS_FCLASS2(info))
1118 return (isdn_tty_cmd_FCLASS2(p, info));
1119 else if (TTY_IS_FCLASS1(info))
1120 return (isdn_tty_cmd_FCLASS1(p, info));
1121 PARSE_ERROR1;
1122}
diff --git a/drivers/isdn/i4l/isdn_ttyfax.h b/drivers/isdn/i4l/isdn_ttyfax.h
new file mode 100644
index 000000000000..757a89010020
--- /dev/null
+++ b/drivers/isdn/i4l/isdn_ttyfax.h
@@ -0,0 +1,18 @@
1/* $Id: isdn_ttyfax.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
2 *
3 * header for Linux ISDN subsystem, tty_fax related functions (linklevel).
4 *
5 * Copyright 1999 by Armin Schindler (mac@melware.de)
6 * Copyright 1999 by Ralf Spachmann (mel@melware.de)
7 * Copyright 1999 by Cytronics & Melware
8 *
9 * This software may be used and distributed according to the terms
10 * of the GNU General Public License, incorporated herein by reference.
11 *
12 */
13
14
15#define XON 0x11
16#define XOFF 0x13
17#define DC2 0x12
18
diff --git a/drivers/isdn/i4l/isdn_v110.c b/drivers/isdn/i4l/isdn_v110.c
new file mode 100644
index 000000000000..f47f2b9846d8
--- /dev/null
+++ b/drivers/isdn/i4l/isdn_v110.c
@@ -0,0 +1,617 @@
1/* $Id: isdn_v110.c,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
2 *
3 * Linux ISDN subsystem, V.110 related functions (linklevel).
4 *
5 * Copyright by Thomas Pfeiffer (pfeiffer@pds.de)
6 *
7 * This software may be used and distributed according to the terms
8 * of the GNU General Public License, incorporated herein by reference.
9 *
10 */
11
12#include <linux/string.h>
13#include <linux/kernel.h>
14#include <linux/slab.h>
15#include <linux/mm.h>
16#include <linux/delay.h>
17
18#include <linux/isdn.h>
19#include "isdn_v110.h"
20
21#undef ISDN_V110_DEBUG
22
23char *isdn_v110_revision = "$Revision: 1.1.2.2 $";
24
25#define V110_38400 255
26#define V110_19200 15
27#define V110_9600 3
28
29/*
30 * The following data are precoded matrices, online and offline matrix
31 * for 9600, 19200 und 38400, respectively
32 */
33static unsigned char V110_OnMatrix_9600[] =
34{0xfc, 0xfc, 0xfc, 0xfc, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff,
35 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd,
36 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff,
37 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd};
38
39static unsigned char V110_OffMatrix_9600[] =
40{0xfc, 0xfc, 0xfc, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
41 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
42 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
43 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
44
45static unsigned char V110_OnMatrix_19200[] =
46{0xf0, 0xf0, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf7,
47 0xfd, 0xff, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf7};
48
49static unsigned char V110_OffMatrix_19200[] =
50{0xf0, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
51 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
52
53static unsigned char V110_OnMatrix_38400[] =
54{0x00, 0x7f, 0x7f, 0x7f, 0x7f, 0xfd, 0x7f, 0x7f, 0x7f, 0x7f};
55
56static unsigned char V110_OffMatrix_38400[] =
57{0x00, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff};
58
59/*
60 * FlipBits reorders sequences of keylen bits in one byte.
61 * E.g. source order 7654321 will be converted to 45670123 when keylen = 4,
62 * and to 67452301 when keylen = 2. This is necessary because ordering on
63 * the isdn line is the other way.
64 */
65static __inline unsigned char
66FlipBits(unsigned char c, int keylen)
67{
68 unsigned char b = c;
69 unsigned char bit = 128;
70 int i;
71 int j;
72 int hunks = (8 / keylen);
73
74 c = 0;
75 for (i = 0; i < hunks; i++) {
76 for (j = 0; j < keylen; j++) {
77 if (b & (bit >> j))
78 c |= bit >> (keylen - j - 1);
79 }
80 bit >>= keylen;
81 }
82 return c;
83}
84
85
86/* isdn_v110_open allocates and initializes private V.110 data
87 * structures and returns a pointer to these.
88 */
89static isdn_v110_stream *
90isdn_v110_open(unsigned char key, int hdrlen, int maxsize)
91{
92 int i;
93 isdn_v110_stream *v;
94
95 if ((v = kmalloc(sizeof(isdn_v110_stream), GFP_ATOMIC)) == NULL)
96 return NULL;
97 memset(v, 0, sizeof(isdn_v110_stream));
98 v->key = key;
99 v->nbits = 0;
100 for (i = 0; key & (1 << i); i++)
101 v->nbits++;
102
103 v->nbytes = 8 / v->nbits;
104 v->decodelen = 0;
105
106 switch (key) {
107 case V110_38400:
108 v->OnlineFrame = V110_OnMatrix_38400;
109 v->OfflineFrame = V110_OffMatrix_38400;
110 break;
111 case V110_19200:
112 v->OnlineFrame = V110_OnMatrix_19200;
113 v->OfflineFrame = V110_OffMatrix_19200;
114 break;
115 default:
116 v->OnlineFrame = V110_OnMatrix_9600;
117 v->OfflineFrame = V110_OffMatrix_9600;
118 break;
119 }
120 v->framelen = v->nbytes * 10;
121 v->SyncInit = 5;
122 v->introducer = 0;
123 v->dbit = 1;
124 v->b = 0;
125 v->skbres = hdrlen;
126 v->maxsize = maxsize - hdrlen;
127 if ((v->encodebuf = kmalloc(maxsize, GFP_ATOMIC)) == NULL) {
128 kfree(v);
129 return NULL;
130 }
131 return v;
132}
133
134/* isdn_v110_close frees private V.110 data structures */
135void
136isdn_v110_close(isdn_v110_stream * v)
137{
138 if (v == NULL)
139 return;
140#ifdef ISDN_V110_DEBUG
141 printk(KERN_DEBUG "v110 close\n");
142#endif
143 kfree(v->encodebuf);
144 kfree(v);
145}
146
147
148/*
149 * ValidHeaderBytes return the number of valid bytes in v->decodebuf
150 */
151static int
152ValidHeaderBytes(isdn_v110_stream * v)
153{
154 int i;
155 for (i = 0; (i < v->decodelen) && (i < v->nbytes); i++)
156 if ((v->decodebuf[i] & v->key) != 0)
157 break;
158 return i;
159}
160
161/*
162 * SyncHeader moves the decodebuf ptr to the next valid header
163 */
164static void
165SyncHeader(isdn_v110_stream * v)
166{
167 unsigned char *rbuf = v->decodebuf;
168 int len = v->decodelen;
169
170 if (len == 0)
171 return;
172 for (rbuf++, len--; len > 0; len--, rbuf++) /* such den SyncHeader in buf ! */
173 if ((*rbuf & v->key) == 0) /* erstes byte gefunden ? */
174 break; /* jupp! */
175 if (len)
176 memcpy(v->decodebuf, rbuf, len);
177
178 v->decodelen = len;
179#ifdef ISDN_V110_DEBUG
180 printk(KERN_DEBUG "isdn_v110: Header resync\n");
181#endif
182}
183
184/* DecodeMatrix takes n (n>=1) matrices (v110 frames, 10 bytes) where
185 len is the number of matrix-lines. len must be a multiple of 10, i.e.
186 only complete matices must be given.
187 From these, netto data is extracted and returned in buf. The return-value
188 is the bytecount of the decoded data.
189 */
190static int
191DecodeMatrix(isdn_v110_stream * v, unsigned char *m, int len, unsigned char *buf)
192{
193 int line = 0;
194 int buflen = 0;
195 int mbit = 64;
196 int introducer = v->introducer;
197 int dbit = v->dbit;
198 unsigned char b = v->b;
199
200 while (line < len) { /* Are we done with all lines of the matrix? */
201 if ((line % 10) == 0) { /* the 0. line of the matrix is always 0 ! */
202 if (m[line] != 0x00) { /* not 0 ? -> error! */
203#ifdef ISDN_V110_DEBUG
204 printk(KERN_DEBUG "isdn_v110: DecodeMatrix, V110 Bad Header\n");
205 /* returning now is not the right thing, though :-( */
206#endif
207 }
208 line++; /* next line of matrix */
209 continue;
210 } else if ((line % 10) == 5) { /* in line 5 there's only e-bits ! */
211 if ((m[line] & 0x70) != 0x30) { /* 011 has to be at the beginning! */
212#ifdef ISDN_V110_DEBUG
213 printk(KERN_DEBUG "isdn_v110: DecodeMatrix, V110 Bad 5th line\n");
214 /* returning now is not the right thing, though :-( */
215#endif
216 }
217 line++; /* next line */
218 continue;
219 } else if (!introducer) { /* every byte starts with 10 (stopbit, startbit) */
220 introducer = (m[line] & mbit) ? 0 : 1; /* current bit of the matrix */
221 next_byte:
222 if (mbit > 2) { /* was it the last bit in this line ? */
223 mbit >>= 1; /* no -> take next */
224 continue;
225 } /* otherwise start with leftmost bit in the next line */
226 mbit = 64;
227 line++;
228 continue;
229 } else { /* otherwise we need to set a data bit */
230 if (m[line] & mbit) /* was that bit set in the matrix ? */
231 b |= dbit; /* yes -> set it in the data byte */
232 else
233 b &= dbit - 1; /* no -> clear it in the data byte */
234 if (dbit < 128) /* is that data byte done ? */
235 dbit <<= 1; /* no, got the next bit */
236 else { /* data byte is done */
237 buf[buflen++] = b; /* copy byte into the output buffer */
238 introducer = b = 0; /* init of the intro sequence and of the data byte */
239 dbit = 1; /* next we look for the 0th bit */
240 }
241 goto next_byte; /* look for next bit in the matrix */
242 }
243 }
244 v->introducer = introducer;
245 v->dbit = dbit;
246 v->b = b;
247 return buflen; /* return number of bytes in the output buffer */
248}
249
250/*
251 * DecodeStream receives V.110 coded data from the input stream. It recovers the
252 * original frames.
253 * The input stream doesn't need to be framed
254 */
255struct sk_buff *
256isdn_v110_decode(isdn_v110_stream * v, struct sk_buff *skb)
257{
258 int i;
259 int j;
260 int len;
261 unsigned char *v110_buf;
262 unsigned char *rbuf;
263
264 if (!skb) {
265 printk(KERN_WARNING "isdn_v110_decode called with NULL skb!\n");
266 return NULL;
267 }
268 rbuf = skb->data;
269 len = skb->len;
270 if (v == NULL) {
271 /* invalid handle, no chance to proceed */
272 printk(KERN_WARNING "isdn_v110_decode called with NULL stream!\n");
273 dev_kfree_skb(skb);
274 return NULL;
275 }
276 if (v->decodelen == 0) /* cache empty? */
277 for (; len > 0; len--, rbuf++) /* scan for SyncHeader in buf */
278 if ((*rbuf & v->key) == 0)
279 break; /* found first byte */
280 if (len == 0) {
281 dev_kfree_skb(skb);
282 return NULL;
283 }
284 /* copy new data to decode-buffer */
285 memcpy(&(v->decodebuf[v->decodelen]), rbuf, len);
286 v->decodelen += len;
287 ReSync:
288 if (v->decodelen < v->nbytes) { /* got a new header ? */
289 dev_kfree_skb(skb);
290 return NULL; /* no, try later */
291 }
292 if (ValidHeaderBytes(v) != v->nbytes) { /* is that a valid header? */
293 SyncHeader(v); /* no -> look for header */
294 goto ReSync;
295 }
296 len = (v->decodelen - (v->decodelen % (10 * v->nbytes))) / v->nbytes;
297 if ((v110_buf = kmalloc(len, GFP_ATOMIC)) == NULL) {
298 printk(KERN_WARNING "isdn_v110_decode: Couldn't allocate v110_buf\n");
299 dev_kfree_skb(skb);
300 return NULL;
301 }
302 for (i = 0; i < len; i++) {
303 v110_buf[i] = 0;
304 for (j = 0; j < v->nbytes; j++)
305 v110_buf[i] |= (v->decodebuf[(i * v->nbytes) + j] & v->key) << (8 - ((j + 1) * v->nbits));
306 v110_buf[i] = FlipBits(v110_buf[i], v->nbits);
307 }
308 v->decodelen = (v->decodelen % (10 * v->nbytes));
309 memcpy(v->decodebuf, &(v->decodebuf[len * v->nbytes]), v->decodelen);
310
311 skb_trim(skb, DecodeMatrix(v, v110_buf, len, skb->data));
312 kfree(v110_buf);
313 if (skb->len)
314 return skb;
315 else {
316 kfree_skb(skb);
317 return NULL;
318 }
319}
320
321/* EncodeMatrix takes input data in buf, len is the bytecount.
322 Data is encoded into v110 frames in m. Return value is the number of
323 matrix-lines generated.
324 */
325static int
326EncodeMatrix(unsigned char *buf, int len, unsigned char *m, int mlen)
327{
328 int line = 0;
329 int i = 0;
330 int mbit = 128;
331 int dbit = 1;
332 int introducer = 3;
333 int ibit[] = {0, 1, 1};
334
335 while ((i < len) && (line < mlen)) { /* while we still have input data */
336 switch (line % 10) { /* in which line of the matrix are we? */
337 case 0:
338 m[line++] = 0x00; /* line 0 is always 0 */
339 mbit = 128; /* go on with the 7th bit */
340 break;
341 case 5:
342 m[line++] = 0xbf; /* line 5 is always 10111111 */
343 mbit = 128; /* go on with the 7th bit */
344 break;
345 }
346 if (line >= mlen) {
347 printk(KERN_WARNING "isdn_v110 (EncodeMatrix): buffer full!\n");
348 return line;
349 }
350 next_bit:
351 switch (mbit) { /* leftmost or rightmost bit ? */
352 case 1:
353 line++; /* rightmost -> go to next line */
354 if (line >= mlen) {
355 printk(KERN_WARNING "isdn_v110 (EncodeMatrix): buffer full!\n");
356 return line;
357 }
358 case 128:
359 m[line] = 128; /* leftmost -> set byte to 1000000 */
360 mbit = 64; /* current bit in the matrix line */
361 continue;
362 }
363 if (introducer) { /* set 110 sequence ? */
364 introducer--; /* set on digit less */
365 m[line] |= ibit[introducer] ? mbit : 0; /* set corresponding bit */
366 mbit >>= 1; /* bit of matrix line >> 1 */
367 goto next_bit; /* and go on there */
368 } /* else push data bits into the matrix! */
369 m[line] |= (buf[i] & dbit) ? mbit : 0; /* set data bit in matrix */
370 if (dbit == 128) { /* was it the last one? */
371 dbit = 1; /* then go on with first bit of */
372 i++; /* next byte in input buffer */
373 if (i < len) /* input buffer done ? */
374 introducer = 3; /* no, write introducer 110 */
375 else { /* input buffer done ! */
376 m[line] |= (mbit - 1) & 0xfe; /* set remaining bits in line to 1 */
377 break;
378 }
379 } else /* not the last data bit */
380 dbit <<= 1; /* then go to next data bit */
381 mbit >>= 1; /* go to next bit of matrix */
382 goto next_bit;
383
384 }
385 /* if necessary, generate remaining lines of the matrix... */
386 if ((line) && ((line + 10) < mlen))
387 switch (++line % 10) {
388 case 1:
389 m[line++] = 0xfe;
390 case 2:
391 m[line++] = 0xfe;
392 case 3:
393 m[line++] = 0xfe;
394 case 4:
395 m[line++] = 0xfe;
396 case 5:
397 m[line++] = 0xbf;
398 case 6:
399 m[line++] = 0xfe;
400 case 7:
401 m[line++] = 0xfe;
402 case 8:
403 m[line++] = 0xfe;
404 case 9:
405 m[line++] = 0xfe;
406 }
407 return line; /* that's how many lines we have */
408}
409
410/*
411 * Build a sync frame.
412 */
413static struct sk_buff *
414isdn_v110_sync(isdn_v110_stream *v)
415{
416 struct sk_buff *skb;
417
418 if (v == NULL) {
419 /* invalid handle, no chance to proceed */
420 printk(KERN_WARNING "isdn_v110_sync called with NULL stream!\n");
421 return NULL;
422 }
423 if ((skb = dev_alloc_skb(v->framelen + v->skbres))) {
424 skb_reserve(skb, v->skbres);
425 memcpy(skb_put(skb, v->framelen), v->OfflineFrame, v->framelen);
426 }
427 return skb;
428}
429
430/*
431 * Build an idle frame.
432 */
433static struct sk_buff *
434isdn_v110_idle(isdn_v110_stream *v)
435{
436 struct sk_buff *skb;
437
438 if (v == NULL) {
439 /* invalid handle, no chance to proceed */
440 printk(KERN_WARNING "isdn_v110_sync called with NULL stream!\n");
441 return NULL;
442 }
443 if ((skb = dev_alloc_skb(v->framelen + v->skbres))) {
444 skb_reserve(skb, v->skbres);
445 memcpy(skb_put(skb, v->framelen), v->OnlineFrame, v->framelen);
446 }
447 return skb;
448}
449
450struct sk_buff *
451isdn_v110_encode(isdn_v110_stream * v, struct sk_buff *skb)
452{
453 int i;
454 int j;
455 int rlen;
456 int mlen;
457 int olen;
458 int size;
459 int sval1;
460 int sval2;
461 int nframes;
462 unsigned char *v110buf;
463 unsigned char *rbuf;
464 struct sk_buff *nskb;
465
466 if (v == NULL) {
467 /* invalid handle, no chance to proceed */
468 printk(KERN_WARNING "isdn_v110_encode called with NULL stream!\n");
469 return NULL;
470 }
471 if (!skb) {
472 /* invalid skb, no chance to proceed */
473 printk(KERN_WARNING "isdn_v110_encode called with NULL skb!\n");
474 return NULL;
475 }
476 rlen = skb->len;
477 nframes = (rlen + 3) / 4;
478 v110buf = v->encodebuf;
479 if ((nframes * 40) > v->maxsize) {
480 size = v->maxsize;
481 rlen = v->maxsize / 40;
482 } else
483 size = nframes * 40;
484 if (!(nskb = dev_alloc_skb(size + v->skbres + sizeof(int)))) {
485 printk(KERN_WARNING "isdn_v110_encode: Couldn't alloc skb\n");
486 return NULL;
487 }
488 skb_reserve(nskb, v->skbres + sizeof(int));
489 if (skb->len == 0) {
490 memcpy(skb_put(nskb, v->framelen), v->OnlineFrame, v->framelen);
491 *((int *)skb_push(nskb, sizeof(int))) = 0;
492 return nskb;
493 }
494 mlen = EncodeMatrix(skb->data, rlen, v110buf, size);
495 /* now distribute 2 or 4 bits each to the output stream! */
496 rbuf = skb_put(nskb, size);
497 olen = 0;
498 sval1 = 8 - v->nbits;
499 sval2 = v->key << sval1;
500 for (i = 0; i < mlen; i++) {
501 v110buf[i] = FlipBits(v110buf[i], v->nbits);
502 for (j = 0; j < v->nbytes; j++) {
503 if (size--)
504 *rbuf++ = ~v->key | (((v110buf[i] << (j * v->nbits)) & sval2) >> sval1);
505 else {
506 printk(KERN_WARNING "isdn_v110_encode: buffers full!\n");
507 goto buffer_full;
508 }
509 olen++;
510 }
511 }
512buffer_full:
513 skb_trim(nskb, olen);
514 *((int *)skb_push(nskb, sizeof(int))) = rlen;
515 return nskb;
516}
517
518int
519isdn_v110_stat_callback(int idx, isdn_ctrl * c)
520{
521 isdn_v110_stream *v = NULL;
522 int i;
523 int ret;
524
525 if (idx < 0)
526 return 0;
527 switch (c->command) {
528 case ISDN_STAT_BSENT:
529 /* Keep the send-queue of the driver filled
530 * with frames:
531 * If number of outstanding frames < 3,
532 * send down an Idle-Frame (or an Sync-Frame, if
533 * v->SyncInit != 0).
534 */
535 if (!(v = dev->v110[idx]))
536 return 0;
537 atomic_inc(&dev->v110use[idx]);
538 for (i=0; i * v->framelen < c->parm.length; i++) {
539 if (v->skbidle > 0) {
540 v->skbidle--;
541 ret = 1;
542 } else {
543 if (v->skbuser > 0)
544 v->skbuser--;
545 ret = 0;
546 }
547 }
548 for (i = v->skbuser + v->skbidle; i < 2; i++) {
549 struct sk_buff *skb;
550 if (v->SyncInit > 0)
551 skb = isdn_v110_sync(v);
552 else
553 skb = isdn_v110_idle(v);
554 if (skb) {
555 if (dev->drv[c->driver]->interface->writebuf_skb(c->driver, c->arg, 1, skb) <= 0) {
556 dev_kfree_skb(skb);
557 break;
558 } else {
559 if (v->SyncInit)
560 v->SyncInit--;
561 v->skbidle++;
562 }
563 } else
564 break;
565 }
566 atomic_dec(&dev->v110use[idx]);
567 return ret;
568 case ISDN_STAT_DHUP:
569 case ISDN_STAT_BHUP:
570 while (1) {
571 atomic_inc(&dev->v110use[idx]);
572 if (atomic_dec_and_test(&dev->v110use[idx])) {
573 isdn_v110_close(dev->v110[idx]);
574 dev->v110[idx] = NULL;
575 break;
576 }
577 mdelay(1);
578 }
579 break;
580 case ISDN_STAT_BCONN:
581 if (dev->v110emu[idx] && (dev->v110[idx] == NULL)) {
582 int hdrlen = dev->drv[c->driver]->interface->hl_hdrlen;
583 int maxsize = dev->drv[c->driver]->interface->maxbufsize;
584 atomic_inc(&dev->v110use[idx]);
585 switch (dev->v110emu[idx]) {
586 case ISDN_PROTO_L2_V11096:
587 dev->v110[idx] = isdn_v110_open(V110_9600, hdrlen, maxsize);
588 break;
589 case ISDN_PROTO_L2_V11019:
590 dev->v110[idx] = isdn_v110_open(V110_19200, hdrlen, maxsize);
591 break;
592 case ISDN_PROTO_L2_V11038:
593 dev->v110[idx] = isdn_v110_open(V110_38400, hdrlen, maxsize);
594 break;
595 default:;
596 }
597 if ((v = dev->v110[idx])) {
598 while (v->SyncInit) {
599 struct sk_buff *skb = isdn_v110_sync(v);
600 if (dev->drv[c->driver]->interface->writebuf_skb(c->driver, c->arg, 1, skb) <= 0) {
601 dev_kfree_skb(skb);
602 /* Unable to send, try later */
603 break;
604 }
605 v->SyncInit--;
606 v->skbidle++;
607 }
608 } else
609 printk(KERN_WARNING "isdn_v110: Couldn't open stream for chan %d\n", idx);
610 atomic_dec(&dev->v110use[idx]);
611 }
612 break;
613 default:
614 return 0;
615 }
616 return 0;
617}
diff --git a/drivers/isdn/i4l/isdn_v110.h b/drivers/isdn/i4l/isdn_v110.h
new file mode 100644
index 000000000000..08f274bbc438
--- /dev/null
+++ b/drivers/isdn/i4l/isdn_v110.h
@@ -0,0 +1,29 @@
1/* $Id: isdn_v110.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
2 *
3 * Linux ISDN subsystem, V.110 related functions (linklevel).
4 *
5 * Copyright by Thomas Pfeiffer (pfeiffer@pds.de)
6 *
7 * This software may be used and distributed according to the terms
8 * of the GNU General Public License, incorporated herein by reference.
9 *
10 */
11
12#ifndef _isdn_v110_h_
13#define _isdn_v110_h_
14
15/*
16 * isdn_v110_encode will take raw data and encode it using V.110
17 */
18extern struct sk_buff *isdn_v110_encode(isdn_v110_stream *, struct sk_buff *);
19
20/*
21 * isdn_v110_decode receives V.110 coded data from the stream and rebuilds
22 * frames from them. The source stream doesn't need to be framed.
23 */
24extern struct sk_buff *isdn_v110_decode(isdn_v110_stream *, struct sk_buff *);
25
26extern int isdn_v110_stat_callback(int, isdn_ctrl *);
27extern void isdn_v110_close(isdn_v110_stream * v);
28
29#endif
diff --git a/drivers/isdn/i4l/isdn_x25iface.c b/drivers/isdn/i4l/isdn_x25iface.c
new file mode 100644
index 000000000000..4ab7600cf9c1
--- /dev/null
+++ b/drivers/isdn/i4l/isdn_x25iface.c
@@ -0,0 +1,328 @@
1/* $Id: isdn_x25iface.c,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
2 *
3 * Linux ISDN subsystem, X.25 related functions
4 *
5 * This software may be used and distributed according to the terms
6 * of the GNU General Public License, incorporated herein by reference.
7 *
8 * stuff needed to support the Linux X.25 PLP code on top of devices that
9 * can provide a lab_b service using the concap_proto mechanism.
10 * This module supports a network interface wich provides lapb_sematics
11 * -- as defined in Documentation/networking/x25-iface.txt -- to
12 * the upper layer and assumes that the lower layer provides a reliable
13 * data link service by means of the concap_device_ops callbacks.
14 *
15 * Only protocol specific stuff goes here. Device specific stuff
16 * goes to another -- device related -- concap_proto support source file.
17 *
18 */
19
20/* #include <linux/isdn.h> */
21#include <linux/netdevice.h>
22#include <linux/concap.h>
23#include <linux/wanrouter.h>
24#include <net/x25device.h>
25#include "isdn_x25iface.h"
26
27/* for debugging messages not to cause an oops when device pointer is NULL*/
28#define MY_DEVNAME(dev) ( (dev) ? (dev)->name : "DEVICE UNSPECIFIED" )
29
30
31typedef struct isdn_x25iface_proto_data {
32 int magic;
33 enum wan_states state;
34 /* Private stuff, not to be accessed via proto_data. We provide the
35 other storage for the concap_proto instance here as well,
36 enabling us to allocate both with just one kmalloc(): */
37 struct concap_proto priv;
38} ix25_pdata_t;
39
40
41
42/* is now in header file (extern): struct concap_proto * isdn_x25iface_proto_new(void); */
43void isdn_x25iface_proto_del( struct concap_proto * );
44int isdn_x25iface_proto_close( struct concap_proto * );
45int isdn_x25iface_proto_restart( struct concap_proto *,
46 struct net_device *,
47 struct concap_device_ops *);
48int isdn_x25iface_xmit( struct concap_proto *, struct sk_buff * );
49int isdn_x25iface_receive( struct concap_proto *, struct sk_buff * );
50int isdn_x25iface_connect_ind( struct concap_proto * );
51int isdn_x25iface_disconn_ind( struct concap_proto * );
52
53
54static struct concap_proto_ops ix25_pops = {
55 &isdn_x25iface_proto_new,
56 &isdn_x25iface_proto_del,
57 &isdn_x25iface_proto_restart,
58 &isdn_x25iface_proto_close,
59 &isdn_x25iface_xmit,
60 &isdn_x25iface_receive,
61 &isdn_x25iface_connect_ind,
62 &isdn_x25iface_disconn_ind
63};
64
65/* error message helper function */
66static void illegal_state_warn( unsigned state, unsigned char firstbyte)
67{
68 printk( KERN_WARNING "isdn_x25iface: firstbyte %x illegal in"
69 "current state %d\n",firstbyte, state );
70}
71
72/* check protocol data field for consistency */
73static int pdata_is_bad( ix25_pdata_t * pda ){
74
75 if( pda && pda -> magic == ISDN_X25IFACE_MAGIC ) return 0;
76 printk( KERN_WARNING
77 "isdn_x25iface_xxx: illegal pointer to proto data\n" );
78 return 1;
79}
80
81/* create a new x25 interface protocol instance
82 */
83struct concap_proto * isdn_x25iface_proto_new(void)
84{
85 ix25_pdata_t * tmp = kmalloc(sizeof(ix25_pdata_t),GFP_KERNEL);
86 IX25DEBUG("isdn_x25iface_proto_new\n");
87 if( tmp ){
88 tmp -> magic = ISDN_X25IFACE_MAGIC;
89 tmp -> state = WAN_UNCONFIGURED;
90 /* private data space used to hold the concap_proto data.
91 Only to be accessed via the returned pointer */
92 spin_lock_init(&tmp->priv.lock);
93 tmp -> priv.dops = NULL;
94 tmp -> priv.net_dev = NULL;
95 tmp -> priv.pops = &ix25_pops;
96 tmp -> priv.flags = 0;
97 tmp -> priv.proto_data = tmp;
98 return( &(tmp -> priv) );
99 }
100 return NULL;
101};
102
103/* close the x25iface encapsulation protocol
104 */
105int isdn_x25iface_proto_close(struct concap_proto *cprot){
106
107 ix25_pdata_t *tmp;
108 int ret = 0;
109 ulong flags;
110
111 if( ! cprot ){
112 printk( KERN_ERR "isdn_x25iface_proto_close: "
113 "invalid concap_proto pointer\n" );
114 return -1;
115 }
116 IX25DEBUG( "isdn_x25iface_proto_close %s \n", MY_DEVNAME(cprot -> net_dev) );
117 spin_lock_irqsave(&cprot->lock, flags);
118 cprot -> dops = NULL;
119 cprot -> net_dev = NULL;
120 tmp = cprot -> proto_data;
121 if( pdata_is_bad( tmp ) ){
122 ret = -1;
123 } else {
124 tmp -> state = WAN_UNCONFIGURED;
125 }
126 spin_unlock_irqrestore(&cprot->lock, flags);
127 return ret;
128}
129
130/* Delete the x25iface encapsulation protocol instance
131 */
132void isdn_x25iface_proto_del(struct concap_proto *cprot){
133
134 ix25_pdata_t * tmp;
135
136 IX25DEBUG( "isdn_x25iface_proto_del \n" );
137 if( ! cprot ){
138 printk( KERN_ERR "isdn_x25iface_proto_del: "
139 "concap_proto pointer is NULL\n" );
140 return;
141 }
142 tmp = cprot -> proto_data;
143 if( tmp == NULL ){
144 printk( KERN_ERR "isdn_x25iface_proto_del: inconsistent "
145 "proto_data pointer (maybe already deleted?)\n");
146 return;
147 }
148 /* close if the protocol is still open */
149 if( cprot -> dops ) isdn_x25iface_proto_close(cprot);
150 /* freeing the storage should be sufficient now. But some additional
151 settings might help to catch wild pointer bugs */
152 tmp -> magic = 0;
153 cprot -> proto_data = NULL;
154
155 kfree( tmp );
156 return;
157}
158
159/* (re-)initialize the data structures for x25iface encapsulation
160 */
161int isdn_x25iface_proto_restart(struct concap_proto *cprot,
162 struct net_device *ndev,
163 struct concap_device_ops *dops)
164{
165 ix25_pdata_t * pda = cprot -> proto_data ;
166 ulong flags;
167
168 IX25DEBUG( "isdn_x25iface_proto_restart %s \n", MY_DEVNAME(ndev) );
169
170 if ( pdata_is_bad( pda ) ) return -1;
171
172 if( !( dops && dops -> data_req && dops -> connect_req
173 && dops -> disconn_req ) ){
174 printk( KERN_WARNING "isdn_x25iface_restart: required dops"
175 " missing\n" );
176 isdn_x25iface_proto_close(cprot);
177 return -1;
178 }
179 spin_lock_irqsave(&cprot->lock, flags);
180 cprot -> net_dev = ndev;
181 cprot -> pops = &ix25_pops;
182 cprot -> dops = dops;
183 pda -> state = WAN_DISCONNECTED;
184 spin_unlock_irqrestore(&cprot->lock, flags);
185 return 0;
186}
187
188/* deliver a dl_data frame received from i4l HL driver to the network layer
189 */
190int isdn_x25iface_receive(struct concap_proto *cprot, struct sk_buff *skb)
191{
192 IX25DEBUG( "isdn_x25iface_receive %s \n", MY_DEVNAME(cprot->net_dev) );
193 if ( ( (ix25_pdata_t*) (cprot->proto_data) )
194 -> state == WAN_CONNECTED ){
195 if( skb_push(skb, 1)){
196 skb -> data[0]=0x00;
197 skb->protocol = x25_type_trans(skb, cprot->net_dev);
198 netif_rx(skb);
199 return 0;
200 }
201 }
202 printk(KERN_WARNING "isdn_x25iface_receive %s: not connected, skb dropped\n", MY_DEVNAME(cprot->net_dev) );
203 dev_kfree_skb(skb);
204 return -1;
205}
206
207/* a connection set up is indicated by lower layer
208 */
209int isdn_x25iface_connect_ind(struct concap_proto *cprot)
210{
211 struct sk_buff * skb = dev_alloc_skb(1);
212 enum wan_states *state_p
213 = &( ( (ix25_pdata_t*) (cprot->proto_data) ) -> state);
214 IX25DEBUG( "isdn_x25iface_connect_ind %s \n"
215 , MY_DEVNAME(cprot->net_dev) );
216 if( *state_p == WAN_UNCONFIGURED ){
217 printk(KERN_WARNING
218 "isdn_x25iface_connect_ind while unconfigured %s\n"
219 , MY_DEVNAME(cprot->net_dev) );
220 return -1;
221 }
222 *state_p = WAN_CONNECTED;
223 if( skb ){
224 *( skb_put(skb, 1) ) = 0x01;
225 skb->protocol = x25_type_trans(skb, cprot->net_dev);
226 netif_rx(skb);
227 return 0;
228 } else {
229 printk(KERN_WARNING "isdn_x25iface_connect_ind: "
230 " out of memory -- disconnecting\n");
231 cprot -> dops -> disconn_req(cprot);
232 return -1;
233 }
234}
235
236/* a disconnect is indicated by lower layer
237 */
238int isdn_x25iface_disconn_ind(struct concap_proto *cprot)
239{
240 struct sk_buff *skb;
241 enum wan_states *state_p
242 = &( ( (ix25_pdata_t*) (cprot->proto_data) ) -> state);
243 IX25DEBUG( "isdn_x25iface_disconn_ind %s \n", MY_DEVNAME(cprot -> net_dev) );
244 if( *state_p == WAN_UNCONFIGURED ){
245 printk(KERN_WARNING
246 "isdn_x25iface_disconn_ind while unconfigured\n");
247 return -1;
248 }
249 if(! cprot -> net_dev) return -1;
250 *state_p = WAN_DISCONNECTED;
251 skb = dev_alloc_skb(1);
252 if( skb ){
253 *( skb_put(skb, 1) ) = 0x02;
254 skb->protocol = x25_type_trans(skb, cprot->net_dev);
255 netif_rx(skb);
256 return 0;
257 } else {
258 printk(KERN_WARNING "isdn_x25iface_disconn_ind:"
259 " out of memory\n");
260 return -1;
261 }
262}
263
264/* process a frame handed over to us from linux network layer. First byte
265 semantics as defined in Documentation/networking/x25-iface.txt
266 */
267int isdn_x25iface_xmit(struct concap_proto *cprot, struct sk_buff *skb)
268{
269 unsigned char firstbyte = skb->data[0];
270 enum wan_states *state = &((ix25_pdata_t*)cprot->proto_data)->state;
271 int ret = 0;
272 IX25DEBUG( "isdn_x25iface_xmit: %s first=%x state=%d \n", MY_DEVNAME(cprot -> net_dev), firstbyte, *state );
273 switch ( firstbyte ){
274 case 0x00: /* dl_data request */
275 if( *state == WAN_CONNECTED ){
276 skb_pull(skb, 1);
277 cprot -> net_dev -> trans_start = jiffies;
278 ret = ( cprot -> dops -> data_req(cprot, skb) );
279 /* prepare for future retransmissions */
280 if( ret ) skb_push(skb,1);
281 return ret;
282 }
283 illegal_state_warn( *state, firstbyte );
284 break;
285 case 0x01: /* dl_connect request */
286 if( *state == WAN_DISCONNECTED ){
287 *state = WAN_CONNECTING;
288 ret = cprot -> dops -> connect_req(cprot);
289 if(ret){
290 /* reset state and notify upper layer about
291 * immidiatly failed attempts */
292 isdn_x25iface_disconn_ind(cprot);
293 }
294 } else {
295 illegal_state_warn( *state, firstbyte );
296 }
297 break;
298 case 0x02: /* dl_disconnect request */
299 switch ( *state ){
300 case WAN_DISCONNECTED:
301 /* Should not happen. However, give upper layer a
302 chance to recover from inconstistency but don't
303 trust the lower layer sending the disconn_confirm
304 when already disconnected */
305 printk(KERN_WARNING "isdn_x25iface_xmit: disconnect "
306 " requested while disconnected\n" );
307 isdn_x25iface_disconn_ind(cprot);
308 break; /* prevent infinite loops */
309 case WAN_CONNECTING:
310 case WAN_CONNECTED:
311 *state = WAN_DISCONNECTED;
312 cprot -> dops -> disconn_req(cprot);
313 break;
314 default:
315 illegal_state_warn( *state, firstbyte );
316 }
317 break;
318 case 0x03: /* changing lapb parameters requested */
319 printk(KERN_WARNING "isdn_x25iface_xmit: setting of lapb"
320 " options not yet supported\n");
321 break;
322 default:
323 printk(KERN_WARNING "isdn_x25iface_xmit: frame with illegal"
324 " first byte %x ignored:\n", firstbyte);
325 }
326 dev_kfree_skb(skb);
327 return 0;
328}
diff --git a/drivers/isdn/i4l/isdn_x25iface.h b/drivers/isdn/i4l/isdn_x25iface.h
new file mode 100644
index 000000000000..41a3d4977466
--- /dev/null
+++ b/drivers/isdn/i4l/isdn_x25iface.h
@@ -0,0 +1,39 @@
1/* $Id: isdn_x25iface.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
2 *
3 * header for Linux ISDN subsystem, x.25 related functions
4 *
5 * This software may be used and distributed according to the terms
6 * of the GNU General Public License, incorporated herein by reference.
7 *
8 */
9
10#ifndef _LINUX_ISDN_X25IFACE_H
11#define _LINUX_ISDN_X25IFACE_H
12
13#define ISDN_X25IFACE_MAGIC 0x1e75a2b9
14/* #define DEBUG_ISDN_X25 if you want isdn_x25 debugging messages */
15#ifdef DEBUG_ISDN_X25
16# define IX25DEBUG(fmt,args...) printk(KERN_DEBUG fmt , ## args)
17#else
18# define IX25DEBUG(fmt,args...)
19#endif
20
21#include <linux/skbuff.h>
22#include <linux/wanrouter.h>
23#include <linux/isdn.h>
24#include <linux/concap.h>
25
26extern struct concap_proto_ops * isdn_x25iface_concap_proto_ops_pt;
27extern struct concap_proto * isdn_x25iface_proto_new(void);
28
29
30
31#endif
32
33
34
35
36
37
38
39
diff --git a/drivers/isdn/icn/Kconfig b/drivers/isdn/icn/Kconfig
new file mode 100644
index 000000000000..fcb99f5f0b26
--- /dev/null
+++ b/drivers/isdn/icn/Kconfig
@@ -0,0 +1,16 @@
1#
2# Config.in for ICN ISDN driver
3#
4config ISDN_DRV_ICN
5 tristate "ICN 2B and 4B support"
6 depends on ISDN_I4L && ISA
7 help
8 This enables support for two kinds of ISDN-cards made by a German
9 company called ICN. 2B is the standard version for a single ISDN
10 line with two B-channels, 4B supports two ISDN lines. For running
11 this card, additional firmware is necessary, which has to be
12 downloaded into the card using a utility which is distributed
13 separately. See <file:Documentation/isdn/README> and
14 <file:Documentation/isdn/README.icn> for more
15 information.
16
diff --git a/drivers/isdn/icn/Makefile b/drivers/isdn/icn/Makefile
new file mode 100644
index 000000000000..d9b476fcf384
--- /dev/null
+++ b/drivers/isdn/icn/Makefile
@@ -0,0 +1,5 @@
1# Makefile for the icn ISDN device driver
2
3# Each configuration option enables a list of files.
4
5obj-$(CONFIG_ISDN_DRV_ICN) += icn.o
diff --git a/drivers/isdn/icn/icn.c b/drivers/isdn/icn/icn.c
new file mode 100644
index 000000000000..9fc0c1e03732
--- /dev/null
+++ b/drivers/isdn/icn/icn.c
@@ -0,0 +1,1691 @@
1/* $Id: icn.c,v 1.65.6.8 2001/09/23 22:24:55 kai Exp $
2 *
3 * ISDN low-level module for the ICN active ISDN-Card.
4 *
5 * Copyright 1994,95,96 by Fritz Elfert (fritz@isdn4linux.de)
6 *
7 * This software may be used and distributed according to the terms
8 * of the GNU General Public License, incorporated herein by reference.
9 *
10 */
11
12#include "icn.h"
13#include <linux/module.h>
14#include <linux/init.h>
15
16static int portbase = ICN_BASEADDR;
17static unsigned long membase = ICN_MEMADDR;
18static char *icn_id = "\0";
19static char *icn_id2 = "\0";
20
21MODULE_DESCRIPTION("ISDN4Linux: Driver for ICN active ISDN card");
22MODULE_AUTHOR("Fritz Elfert");
23MODULE_LICENSE("GPL");
24module_param(portbase, int, 0);
25MODULE_PARM_DESC(portbase, "Port address of first card");
26module_param(membase, ulong, 0);
27MODULE_PARM_DESC(membase, "Shared memory address of all cards");
28module_param(icn_id, charp, 0);
29MODULE_PARM_DESC(icn_id, "ID-String of first card");
30module_param(icn_id2, charp, 0);
31MODULE_PARM_DESC(icn_id2, "ID-String of first card, second S0 (4B only)");
32
33/*
34 * Verbose bootcode- and protocol-downloading.
35 */
36#undef BOOT_DEBUG
37
38/*
39 * Verbose Shmem-Mapping.
40 */
41#undef MAP_DEBUG
42
43static char
44*revision = "$Revision: 1.65.6.8 $";
45
46static int icn_addcard(int, char *, char *);
47
48/*
49 * Free send-queue completely.
50 * Parameter:
51 * card = pointer to card struct
52 * channel = channel number
53 */
54static void
55icn_free_queue(icn_card * card, int channel)
56{
57 struct sk_buff_head *queue = &card->spqueue[channel];
58 struct sk_buff *skb;
59
60 skb_queue_purge(queue);
61 card->xlen[channel] = 0;
62 card->sndcount[channel] = 0;
63 if ((skb = card->xskb[channel])) {
64 card->xskb[channel] = NULL;
65 dev_kfree_skb(skb);
66 }
67}
68
69/* Put a value into a shift-register, highest bit first.
70 * Parameters:
71 * port = port for output (bit 0 is significant)
72 * val = value to be output
73 * firstbit = Bit-Number of highest bit
74 * bitcount = Number of bits to output
75 */
76static inline void
77icn_shiftout(unsigned short port,
78 unsigned long val,
79 int firstbit,
80 int bitcount)
81{
82
83 register u_char s;
84 register u_char c;
85
86 for (s = firstbit, c = bitcount; c > 0; s--, c--)
87 OUTB_P((u_char) ((val >> s) & 1) ? 0xff : 0, port);
88}
89
90/*
91 * disable a cards shared memory
92 */
93static inline void
94icn_disable_ram(icn_card * card)
95{
96 OUTB_P(0, ICN_MAPRAM);
97}
98
99/*
100 * enable a cards shared memory
101 */
102static inline void
103icn_enable_ram(icn_card * card)
104{
105 OUTB_P(0xff, ICN_MAPRAM);
106}
107
108/*
109 * Map a cards channel0 (Bank0/Bank8) or channel1 (Bank4/Bank12)
110 *
111 * must called with holding the devlock
112 */
113static inline void
114icn_map_channel(icn_card * card, int channel)
115{
116#ifdef MAP_DEBUG
117 printk(KERN_DEBUG "icn_map_channel %d %d\n", dev.channel, channel);
118#endif
119 if ((channel == dev.channel) && (card == dev.mcard))
120 return;
121 if (dev.mcard)
122 icn_disable_ram(dev.mcard);
123 icn_shiftout(ICN_BANK, chan2bank[channel], 3, 4); /* Select Bank */
124 icn_enable_ram(card);
125 dev.mcard = card;
126 dev.channel = channel;
127#ifdef MAP_DEBUG
128 printk(KERN_DEBUG "icn_map_channel done\n");
129#endif
130}
131
132/*
133 * Lock a cards channel.
134 * Return 0 if requested card/channel is unmapped (failure).
135 * Return 1 on success.
136 *
137 * must called with holding the devlock
138 */
139static inline int
140icn_lock_channel(icn_card * card, int channel)
141{
142 register int retval;
143
144#ifdef MAP_DEBUG
145 printk(KERN_DEBUG "icn_lock_channel %d\n", channel);
146#endif
147 if ((dev.channel == channel) && (card == dev.mcard)) {
148 dev.chanlock++;
149 retval = 1;
150#ifdef MAP_DEBUG
151 printk(KERN_DEBUG "icn_lock_channel %d OK\n", channel);
152#endif
153 } else {
154 retval = 0;
155#ifdef MAP_DEBUG
156 printk(KERN_DEBUG "icn_lock_channel %d FAILED, dc=%d\n", channel, dev.channel);
157#endif
158 }
159 return retval;
160}
161
162/*
163 * Release current card/channel lock
164 *
165 * must called with holding the devlock
166 */
167static inline void
168__icn_release_channel(void)
169{
170#ifdef MAP_DEBUG
171 printk(KERN_DEBUG "icn_release_channel l=%d\n", dev.chanlock);
172#endif
173 if (dev.chanlock > 0)
174 dev.chanlock--;
175}
176
177/*
178 * Release current card/channel lock
179 */
180static inline void
181icn_release_channel(void)
182{
183 ulong flags;
184
185 spin_lock_irqsave(&dev.devlock, flags);
186 __icn_release_channel();
187 spin_unlock_irqrestore(&dev.devlock, flags);
188}
189
190/*
191 * Try to map and lock a cards channel.
192 * Return 1 on success, 0 on failure.
193 */
194static inline int
195icn_trymaplock_channel(icn_card * card, int channel)
196{
197 ulong flags;
198
199#ifdef MAP_DEBUG
200 printk(KERN_DEBUG "trymaplock c=%d dc=%d l=%d\n", channel, dev.channel,
201 dev.chanlock);
202#endif
203 spin_lock_irqsave(&dev.devlock, flags);
204 if ((!dev.chanlock) ||
205 ((dev.channel == channel) && (dev.mcard == card))) {
206 dev.chanlock++;
207 icn_map_channel(card, channel);
208 spin_unlock_irqrestore(&dev.devlock, flags);
209#ifdef MAP_DEBUG
210 printk(KERN_DEBUG "trymaplock %d OK\n", channel);
211#endif
212 return 1;
213 }
214 spin_unlock_irqrestore(&dev.devlock, flags);
215#ifdef MAP_DEBUG
216 printk(KERN_DEBUG "trymaplock %d FAILED\n", channel);
217#endif
218 return 0;
219}
220
221/*
222 * Release current card/channel lock,
223 * then map same or other channel without locking.
224 */
225static inline void
226icn_maprelease_channel(icn_card * card, int channel)
227{
228 ulong flags;
229
230#ifdef MAP_DEBUG
231 printk(KERN_DEBUG "map_release c=%d l=%d\n", channel, dev.chanlock);
232#endif
233 spin_lock_irqsave(&dev.devlock, flags);
234 if (dev.chanlock > 0)
235 dev.chanlock--;
236 if (!dev.chanlock)
237 icn_map_channel(card, channel);
238 spin_unlock_irqrestore(&dev.devlock, flags);
239}
240
241/* Get Data from the B-Channel, assemble fragmented packets and put them
242 * into receive-queue. Wake up any B-Channel-reading processes.
243 * This routine is called via timer-callback from icn_pollbchan().
244 */
245
246static void
247icn_pollbchan_receive(int channel, icn_card * card)
248{
249 int mch = channel + ((card->secondhalf) ? 2 : 0);
250 int eflag;
251 int cnt;
252 struct sk_buff *skb;
253
254 if (icn_trymaplock_channel(card, mch)) {
255 while (rbavl) {
256 cnt = readb(&rbuf_l);
257 if ((card->rcvidx[channel] + cnt) > 4000) {
258 printk(KERN_WARNING
259 "icn: (%s) bogus packet on ch%d, dropping.\n",
260 CID,
261 channel + 1);
262 card->rcvidx[channel] = 0;
263 eflag = 0;
264 } else {
265 memcpy_fromio(&card->rcvbuf[channel][card->rcvidx[channel]],
266 &rbuf_d, cnt);
267 card->rcvidx[channel] += cnt;
268 eflag = readb(&rbuf_f);
269 }
270 rbnext;
271 icn_maprelease_channel(card, mch & 2);
272 if (!eflag) {
273 if ((cnt = card->rcvidx[channel])) {
274 if (!(skb = dev_alloc_skb(cnt))) {
275 printk(KERN_WARNING "icn: receive out of memory\n");
276 break;
277 }
278 memcpy(skb_put(skb, cnt), card->rcvbuf[channel], cnt);
279 card->rcvidx[channel] = 0;
280 card->interface.rcvcallb_skb(card->myid, channel, skb);
281 }
282 }
283 if (!icn_trymaplock_channel(card, mch))
284 break;
285 }
286 icn_maprelease_channel(card, mch & 2);
287 }
288}
289
290/* Send data-packet to B-Channel, split it up into fragments of
291 * ICN_FRAGSIZE length. If last fragment is sent out, signal
292 * success to upper layers via statcallb with ISDN_STAT_BSENT argument.
293 * This routine is called via timer-callback from icn_pollbchan() or
294 * directly from icn_sendbuf().
295 */
296
297static void
298icn_pollbchan_send(int channel, icn_card * card)
299{
300 int mch = channel + ((card->secondhalf) ? 2 : 0);
301 int cnt;
302 unsigned long flags;
303 struct sk_buff *skb;
304 isdn_ctrl cmd;
305
306 if (!(card->sndcount[channel] || card->xskb[channel] ||
307 skb_queue_len(&card->spqueue[channel])))
308 return;
309 if (icn_trymaplock_channel(card, mch)) {
310 while (sbfree &&
311 (card->sndcount[channel] ||
312 skb_queue_len(&card->spqueue[channel]) ||
313 card->xskb[channel])) {
314 spin_lock_irqsave(&card->lock, flags);
315 if (card->xmit_lock[channel]) {
316 spin_unlock_irqrestore(&card->lock, flags);
317 break;
318 }
319 card->xmit_lock[channel]++;
320 spin_unlock_irqrestore(&card->lock, flags);
321 skb = card->xskb[channel];
322 if (!skb) {
323 skb = skb_dequeue(&card->spqueue[channel]);
324 if (skb) {
325 /* Pop ACK-flag off skb.
326 * Store length to xlen.
327 */
328 if (*(skb_pull(skb,1)))
329 card->xlen[channel] = skb->len;
330 else
331 card->xlen[channel] = 0;
332 }
333 }
334 if (!skb)
335 break;
336 if (skb->len > ICN_FRAGSIZE) {
337 writeb(0xff, &sbuf_f);
338 cnt = ICN_FRAGSIZE;
339 } else {
340 writeb(0x0, &sbuf_f);
341 cnt = skb->len;
342 }
343 writeb(cnt, &sbuf_l);
344 memcpy_toio(&sbuf_d, skb->data, cnt);
345 skb_pull(skb, cnt);
346 sbnext; /* switch to next buffer */
347 icn_maprelease_channel(card, mch & 2);
348 spin_lock_irqsave(&card->lock, flags);
349 card->sndcount[channel] -= cnt;
350 if (!skb->len) {
351 if (card->xskb[channel])
352 card->xskb[channel] = NULL;
353 card->xmit_lock[channel] = 0;
354 spin_unlock_irqrestore(&card->lock, flags);
355 dev_kfree_skb(skb);
356 if (card->xlen[channel]) {
357 cmd.command = ISDN_STAT_BSENT;
358 cmd.driver = card->myid;
359 cmd.arg = channel;
360 cmd.parm.length = card->xlen[channel];
361 card->interface.statcallb(&cmd);
362 }
363 } else {
364 card->xskb[channel] = skb;
365 card->xmit_lock[channel] = 0;
366 spin_unlock_irqrestore(&card->lock, flags);
367 }
368 if (!icn_trymaplock_channel(card, mch))
369 break;
370 }
371 icn_maprelease_channel(card, mch & 2);
372 }
373}
374
375/* Send/Receive Data to/from the B-Channel.
376 * This routine is called via timer-callback.
377 * It schedules itself while any B-Channel is open.
378 */
379
380static void
381icn_pollbchan(unsigned long data)
382{
383 icn_card *card = (icn_card *) data;
384 unsigned long flags;
385
386 if (card->flags & ICN_FLAGS_B1ACTIVE) {
387 icn_pollbchan_receive(0, card);
388 icn_pollbchan_send(0, card);
389 }
390 if (card->flags & ICN_FLAGS_B2ACTIVE) {
391 icn_pollbchan_receive(1, card);
392 icn_pollbchan_send(1, card);
393 }
394 if (card->flags & (ICN_FLAGS_B1ACTIVE | ICN_FLAGS_B2ACTIVE)) {
395 /* schedule b-channel polling again */
396 spin_lock_irqsave(&card->lock, flags);
397 mod_timer(&card->rb_timer, jiffies+ICN_TIMER_BCREAD);
398 card->flags |= ICN_FLAGS_RBTIMER;
399 spin_unlock_irqrestore(&card->lock, flags);
400 } else
401 card->flags &= ~ICN_FLAGS_RBTIMER;
402}
403
404typedef struct icn_stat {
405 char *statstr;
406 int command;
407 int action;
408} icn_stat;
409/* *INDENT-OFF* */
410static icn_stat icn_stat_table[] =
411{
412 {"BCON_", ISDN_STAT_BCONN, 1}, /* B-Channel connected */
413 {"BDIS_", ISDN_STAT_BHUP, 2}, /* B-Channel disconnected */
414 /*
415 ** add d-channel connect and disconnect support to link-level
416 */
417 {"DCON_", ISDN_STAT_DCONN, 10}, /* D-Channel connected */
418 {"DDIS_", ISDN_STAT_DHUP, 11}, /* D-Channel disconnected */
419 {"DCAL_I", ISDN_STAT_ICALL, 3}, /* Incoming call dialup-line */
420 {"DSCA_I", ISDN_STAT_ICALL, 3}, /* Incoming call 1TR6-SPV */
421 {"FCALL", ISDN_STAT_ICALL, 4}, /* Leased line connection up */
422 {"CIF", ISDN_STAT_CINF, 5}, /* Charge-info, 1TR6-type */
423 {"AOC", ISDN_STAT_CINF, 6}, /* Charge-info, DSS1-type */
424 {"CAU", ISDN_STAT_CAUSE, 7}, /* Cause code */
425 {"TEI OK", ISDN_STAT_RUN, 0}, /* Card connected to wallplug */
426 {"E_L1: ACT FAIL", ISDN_STAT_BHUP, 8}, /* Layer-1 activation failed */
427 {"E_L2: DATA LIN", ISDN_STAT_BHUP, 8}, /* Layer-2 data link lost */
428 {"E_L1: ACTIVATION FAILED",
429 ISDN_STAT_BHUP, 8}, /* Layer-1 activation failed */
430 {NULL, 0, -1}
431};
432/* *INDENT-ON* */
433
434
435/*
436 * Check Statusqueue-Pointer from isdn-cards.
437 * If there are new status-replies from the interface, check
438 * them against B-Channel-connects/disconnects and set flags accordingly.
439 * Wake-Up any processes, who are reading the status-device.
440 * If there are B-Channels open, initiate a timer-callback to
441 * icn_pollbchan().
442 * This routine is called periodically via timer.
443 */
444
445static void
446icn_parse_status(u_char * status, int channel, icn_card * card)
447{
448 icn_stat *s = icn_stat_table;
449 int action = -1;
450 unsigned long flags;
451 isdn_ctrl cmd;
452
453 while (s->statstr) {
454 if (!strncmp(status, s->statstr, strlen(s->statstr))) {
455 cmd.command = s->command;
456 action = s->action;
457 break;
458 }
459 s++;
460 }
461 if (action == -1)
462 return;
463 cmd.driver = card->myid;
464 cmd.arg = channel;
465 switch (action) {
466 case 11:
467 spin_lock_irqsave(&card->lock, flags);
468 icn_free_queue(card,channel);
469 card->rcvidx[channel] = 0;
470
471 if (card->flags &
472 ((channel)?ICN_FLAGS_B2ACTIVE:ICN_FLAGS_B1ACTIVE)) {
473
474 isdn_ctrl ncmd;
475
476 card->flags &= ~((channel)?
477 ICN_FLAGS_B2ACTIVE:ICN_FLAGS_B1ACTIVE);
478
479 memset(&ncmd, 0, sizeof(ncmd));
480
481 ncmd.driver = card->myid;
482 ncmd.arg = channel;
483 ncmd.command = ISDN_STAT_BHUP;
484 spin_unlock_irqrestore(&card->lock, flags);
485 card->interface.statcallb(&cmd);
486 } else
487 spin_unlock_irqrestore(&card->lock, flags);
488 break;
489 case 1:
490 spin_lock_irqsave(&card->lock, flags);
491 icn_free_queue(card,channel);
492 card->flags |= (channel) ?
493 ICN_FLAGS_B2ACTIVE : ICN_FLAGS_B1ACTIVE;
494 spin_unlock_irqrestore(&card->lock, flags);
495 break;
496 case 2:
497 spin_lock_irqsave(&card->lock, flags);
498 card->flags &= ~((channel) ?
499 ICN_FLAGS_B2ACTIVE : ICN_FLAGS_B1ACTIVE);
500 icn_free_queue(card, channel);
501 card->rcvidx[channel] = 0;
502 spin_unlock_irqrestore(&card->lock, flags);
503 break;
504 case 3:
505 {
506 char *t = status + 6;
507 char *s = strchr(t, ',');
508
509 *s++ = '\0';
510 strlcpy(cmd.parm.setup.phone, t,
511 sizeof(cmd.parm.setup.phone));
512 s = strchr(t = s, ',');
513 *s++ = '\0';
514 if (!strlen(t))
515 cmd.parm.setup.si1 = 0;
516 else
517 cmd.parm.setup.si1 =
518 simple_strtoul(t, NULL, 10);
519 s = strchr(t = s, ',');
520 *s++ = '\0';
521 if (!strlen(t))
522 cmd.parm.setup.si2 = 0;
523 else
524 cmd.parm.setup.si2 =
525 simple_strtoul(t, NULL, 10);
526 strlcpy(cmd.parm.setup.eazmsn, s,
527 sizeof(cmd.parm.setup.eazmsn));
528 }
529 cmd.parm.setup.plan = 0;
530 cmd.parm.setup.screen = 0;
531 break;
532 case 4:
533 sprintf(cmd.parm.setup.phone, "LEASED%d", card->myid);
534 sprintf(cmd.parm.setup.eazmsn, "%d", channel + 1);
535 cmd.parm.setup.si1 = 7;
536 cmd.parm.setup.si2 = 0;
537 cmd.parm.setup.plan = 0;
538 cmd.parm.setup.screen = 0;
539 break;
540 case 5:
541 strlcpy(cmd.parm.num, status + 3, sizeof(cmd.parm.num));
542 break;
543 case 6:
544 snprintf(cmd.parm.num, sizeof(cmd.parm.num), "%d",
545 (int) simple_strtoul(status + 7, NULL, 16));
546 break;
547 case 7:
548 status += 3;
549 if (strlen(status) == 4)
550 snprintf(cmd.parm.num, sizeof(cmd.parm.num), "%s%c%c",
551 status + 2, *status, *(status + 1));
552 else
553 strlcpy(cmd.parm.num, status + 1, sizeof(cmd.parm.num));
554 break;
555 case 8:
556 spin_lock_irqsave(&card->lock, flags);
557 card->flags &= ~ICN_FLAGS_B1ACTIVE;
558 icn_free_queue(card, 0);
559 card->rcvidx[0] = 0;
560 spin_unlock_irqrestore(&card->lock, flags);
561 cmd.arg = 0;
562 cmd.driver = card->myid;
563 card->interface.statcallb(&cmd);
564 cmd.command = ISDN_STAT_DHUP;
565 cmd.arg = 0;
566 cmd.driver = card->myid;
567 card->interface.statcallb(&cmd);
568 cmd.command = ISDN_STAT_BHUP;
569 spin_lock_irqsave(&card->lock, flags);
570 card->flags &= ~ICN_FLAGS_B2ACTIVE;
571 icn_free_queue(card, 1);
572 card->rcvidx[1] = 0;
573 spin_unlock_irqrestore(&card->lock, flags);
574 cmd.arg = 1;
575 cmd.driver = card->myid;
576 card->interface.statcallb(&cmd);
577 cmd.command = ISDN_STAT_DHUP;
578 cmd.arg = 1;
579 cmd.driver = card->myid;
580 break;
581 }
582 card->interface.statcallb(&cmd);
583 return;
584}
585
586static void
587icn_putmsg(icn_card * card, unsigned char c)
588{
589 ulong flags;
590
591 spin_lock_irqsave(&card->lock, flags);
592 *card->msg_buf_write++ = (c == 0xff) ? '\n' : c;
593 if (card->msg_buf_write == card->msg_buf_read) {
594 if (++card->msg_buf_read > card->msg_buf_end)
595 card->msg_buf_read = card->msg_buf;
596 }
597 if (card->msg_buf_write > card->msg_buf_end)
598 card->msg_buf_write = card->msg_buf;
599 spin_unlock_irqrestore(&card->lock, flags);
600}
601
602static void
603icn_polldchan(unsigned long data)
604{
605 icn_card *card = (icn_card *) data;
606 int mch = card->secondhalf ? 2 : 0;
607 int avail = 0;
608 int left;
609 u_char c;
610 int ch;
611 unsigned long flags;
612 int i;
613 u_char *p;
614 isdn_ctrl cmd;
615
616 if (icn_trymaplock_channel(card, mch)) {
617 avail = msg_avail;
618 for (left = avail, i = readb(&msg_o); left > 0; i++, left--) {
619 c = readb(&dev.shmem->comm_buffers.iopc_buf[i & 0xff]);
620 icn_putmsg(card, c);
621 if (c == 0xff) {
622 card->imsg[card->iptr] = 0;
623 card->iptr = 0;
624 if (card->imsg[0] == '0' && card->imsg[1] >= '0' &&
625 card->imsg[1] <= '2' && card->imsg[2] == ';') {
626 ch = (card->imsg[1] - '0') - 1;
627 p = &card->imsg[3];
628 icn_parse_status(p, ch, card);
629 } else {
630 p = card->imsg;
631 if (!strncmp(p, "DRV1.", 5)) {
632 u_char vstr[10];
633 u_char *q = vstr;
634
635 printk(KERN_INFO "icn: (%s) %s\n", CID, p);
636 if (!strncmp(p + 7, "TC", 2)) {
637 card->ptype = ISDN_PTYPE_1TR6;
638 card->interface.features |= ISDN_FEATURE_P_1TR6;
639 printk(KERN_INFO
640 "icn: (%s) 1TR6-Protocol loaded and running\n", CID);
641 }
642 if (!strncmp(p + 7, "EC", 2)) {
643 card->ptype = ISDN_PTYPE_EURO;
644 card->interface.features |= ISDN_FEATURE_P_EURO;
645 printk(KERN_INFO
646 "icn: (%s) Euro-Protocol loaded and running\n", CID);
647 }
648 p = strstr(card->imsg, "BRV") + 3;
649 while (*p) {
650 if (*p >= '0' && *p <= '9')
651 *q++ = *p;
652 p++;
653 }
654 *q = '\0';
655 strcat(vstr, "000");
656 vstr[3] = '\0';
657 card->fw_rev = (int) simple_strtoul(vstr, NULL, 10);
658 continue;
659
660 }
661 }
662 } else {
663 card->imsg[card->iptr] = c;
664 if (card->iptr < 59)
665 card->iptr++;
666 }
667 }
668 writeb((readb(&msg_o) + avail) & 0xff, &msg_o);
669 icn_release_channel();
670 }
671 if (avail) {
672 cmd.command = ISDN_STAT_STAVAIL;
673 cmd.driver = card->myid;
674 cmd.arg = avail;
675 card->interface.statcallb(&cmd);
676 }
677 spin_lock_irqsave(&card->lock, flags);
678 if (card->flags & (ICN_FLAGS_B1ACTIVE | ICN_FLAGS_B2ACTIVE))
679 if (!(card->flags & ICN_FLAGS_RBTIMER)) {
680 /* schedule b-channel polling */
681 card->flags |= ICN_FLAGS_RBTIMER;
682 del_timer(&card->rb_timer);
683 card->rb_timer.function = icn_pollbchan;
684 card->rb_timer.data = (unsigned long) card;
685 card->rb_timer.expires = jiffies + ICN_TIMER_BCREAD;
686 add_timer(&card->rb_timer);
687 }
688 /* schedule again */
689 mod_timer(&card->st_timer, jiffies+ICN_TIMER_DCREAD);
690 spin_unlock_irqrestore(&card->lock, flags);
691}
692
693/* Append a packet to the transmit buffer-queue.
694 * Parameters:
695 * channel = Number of B-channel
696 * skb = pointer to sk_buff
697 * card = pointer to card-struct
698 * Return:
699 * Number of bytes transferred, -E??? on error
700 */
701
702static int
703icn_sendbuf(int channel, int ack, struct sk_buff *skb, icn_card * card)
704{
705 int len = skb->len;
706 unsigned long flags;
707 struct sk_buff *nskb;
708
709 if (len > 4000) {
710 printk(KERN_WARNING
711 "icn: Send packet too large\n");
712 return -EINVAL;
713 }
714 if (len) {
715 if (!(card->flags & (channel) ? ICN_FLAGS_B2ACTIVE : ICN_FLAGS_B1ACTIVE))
716 return 0;
717 if (card->sndcount[channel] > ICN_MAX_SQUEUE)
718 return 0;
719 #warning TODO test headroom or use skb->nb to flag ACK
720 nskb = skb_clone(skb, GFP_ATOMIC);
721 if (nskb) {
722 /* Push ACK flag as one
723 * byte in front of data.
724 */
725 *(skb_push(nskb, 1)) = ack?1:0;
726 skb_queue_tail(&card->spqueue[channel], nskb);
727 dev_kfree_skb(skb);
728 } else
729 len = 0;
730 spin_lock_irqsave(&card->lock, flags);
731 card->sndcount[channel] += len;
732 spin_unlock_irqrestore(&card->lock, flags);
733 }
734 return len;
735}
736
737/*
738 * Check card's status after starting the bootstrap loader.
739 * On entry, the card's shared memory has already to be mapped.
740 * Return:
741 * 0 on success (Boot loader ready)
742 * -EIO on failure (timeout)
743 */
744static int
745icn_check_loader(int cardnumber)
746{
747 int timer = 0;
748
749 while (1) {
750#ifdef BOOT_DEBUG
751 printk(KERN_DEBUG "Loader %d ?\n", cardnumber);
752#endif
753 if (readb(&dev.shmem->data_control.scns) ||
754 readb(&dev.shmem->data_control.scnr)) {
755 if (timer++ > 5) {
756 printk(KERN_WARNING
757 "icn: Boot-Loader %d timed out.\n",
758 cardnumber);
759 icn_release_channel();
760 return -EIO;
761 }
762#ifdef BOOT_DEBUG
763 printk(KERN_DEBUG "Loader %d TO?\n", cardnumber);
764#endif
765 msleep_interruptible(ICN_BOOT_TIMEOUT1);
766 } else {
767#ifdef BOOT_DEBUG
768 printk(KERN_DEBUG "Loader %d OK\n", cardnumber);
769#endif
770 icn_release_channel();
771 return 0;
772 }
773 }
774}
775
776/* Load the boot-code into the interface-card's memory and start it.
777 * Always called from user-process.
778 *
779 * Parameters:
780 * buffer = pointer to packet
781 * Return:
782 * 0 if successfully loaded
783 */
784
785#ifdef BOOT_DEBUG
786#define SLEEP(sec) { \
787int slsec = sec; \
788 printk(KERN_DEBUG "SLEEP(%d)\n",slsec); \
789 while (slsec) { \
790 msleep_interruptible(1000); \
791 slsec--; \
792 } \
793}
794#else
795#define SLEEP(sec)
796#endif
797
798static int
799icn_loadboot(u_char __user * buffer, icn_card * card)
800{
801 int ret;
802 u_char *codebuf;
803 unsigned long flags;
804
805#ifdef BOOT_DEBUG
806 printk(KERN_DEBUG "icn_loadboot called, buffaddr=%08lx\n", (ulong) buffer);
807#endif
808 if (!(codebuf = kmalloc(ICN_CODE_STAGE1, GFP_KERNEL))) {
809 printk(KERN_WARNING "icn: Could not allocate code buffer\n");
810 ret = -ENOMEM;
811 goto out;
812 }
813 if (copy_from_user(codebuf, buffer, ICN_CODE_STAGE1)) {
814 ret = -EFAULT;
815 goto out_kfree;
816 }
817 if (!card->rvalid) {
818 if (!request_region(card->port, ICN_PORTLEN, card->regname)) {
819 printk(KERN_WARNING
820 "icn: (%s) ports 0x%03x-0x%03x in use.\n",
821 CID,
822 card->port,
823 card->port + ICN_PORTLEN);
824 ret = -EBUSY;
825 goto out_kfree;
826 }
827 card->rvalid = 1;
828 if (card->doubleS0)
829 card->other->rvalid = 1;
830 }
831 if (!dev.mvalid) {
832 if (!request_mem_region(dev.memaddr, 0x4000, "icn-isdn (all cards)")) {
833 printk(KERN_WARNING
834 "icn: memory at 0x%08lx in use.\n", dev.memaddr);
835 ret = -EBUSY;
836 goto out_kfree;
837 }
838 dev.shmem = ioremap(dev.memaddr, 0x4000);
839 dev.mvalid = 1;
840 }
841 OUTB_P(0, ICN_RUN); /* Reset Controller */
842 OUTB_P(0, ICN_MAPRAM); /* Disable RAM */
843 icn_shiftout(ICN_CFG, 0x0f, 3, 4); /* Windowsize= 16k */
844 icn_shiftout(ICN_CFG, dev.memaddr, 23, 10); /* Set RAM-Addr. */
845#ifdef BOOT_DEBUG
846 printk(KERN_DEBUG "shmem=%08lx\n", dev.memaddr);
847#endif
848 SLEEP(1);
849#ifdef BOOT_DEBUG
850 printk(KERN_DEBUG "Map Bank 0\n");
851#endif
852 spin_lock_irqsave(&dev.devlock, flags);
853 icn_map_channel(card, 0); /* Select Bank 0 */
854 icn_lock_channel(card, 0); /* Lock Bank 0 */
855 spin_unlock_irqrestore(&dev.devlock, flags);
856 SLEEP(1);
857 memcpy_toio(dev.shmem, codebuf, ICN_CODE_STAGE1); /* Copy code */
858#ifdef BOOT_DEBUG
859 printk(KERN_DEBUG "Bootloader transferred\n");
860#endif
861 if (card->doubleS0) {
862 SLEEP(1);
863#ifdef BOOT_DEBUG
864 printk(KERN_DEBUG "Map Bank 8\n");
865#endif
866 spin_lock_irqsave(&dev.devlock, flags);
867 __icn_release_channel();
868 icn_map_channel(card, 2); /* Select Bank 8 */
869 icn_lock_channel(card, 2); /* Lock Bank 8 */
870 spin_unlock_irqrestore(&dev.devlock, flags);
871 SLEEP(1);
872 memcpy_toio(dev.shmem, codebuf, ICN_CODE_STAGE1); /* Copy code */
873#ifdef BOOT_DEBUG
874 printk(KERN_DEBUG "Bootloader transferred\n");
875#endif
876 }
877 SLEEP(1);
878 OUTB_P(0xff, ICN_RUN); /* Start Boot-Code */
879 if ((ret = icn_check_loader(card->doubleS0 ? 2 : 1))) {
880 goto out_kfree;
881 }
882 if (!card->doubleS0) {
883 ret = 0;
884 goto out_kfree;
885 }
886 /* reached only, if we have a Double-S0-Card */
887#ifdef BOOT_DEBUG
888 printk(KERN_DEBUG "Map Bank 0\n");
889#endif
890 spin_lock_irqsave(&dev.devlock, flags);
891 icn_map_channel(card, 0); /* Select Bank 0 */
892 icn_lock_channel(card, 0); /* Lock Bank 0 */
893 spin_unlock_irqrestore(&dev.devlock, flags);
894 SLEEP(1);
895 ret = (icn_check_loader(1));
896
897 out_kfree:
898 kfree(codebuf);
899 out:
900 return ret;
901}
902
903static int
904icn_loadproto(u_char __user * buffer, icn_card * card)
905{
906 register u_char __user *p = buffer;
907 u_char codebuf[256];
908 uint left = ICN_CODE_STAGE2;
909 uint cnt;
910 int timer;
911 unsigned long flags;
912
913#ifdef BOOT_DEBUG
914 printk(KERN_DEBUG "icn_loadproto called\n");
915#endif
916 if (!access_ok(VERIFY_READ, buffer, ICN_CODE_STAGE2))
917 return -EFAULT;
918 timer = 0;
919 spin_lock_irqsave(&dev.devlock, flags);
920 if (card->secondhalf) {
921 icn_map_channel(card, 2);
922 icn_lock_channel(card, 2);
923 } else {
924 icn_map_channel(card, 0);
925 icn_lock_channel(card, 0);
926 }
927 spin_unlock_irqrestore(&dev.devlock, flags);
928 while (left) {
929 if (sbfree) { /* If there is a free buffer... */
930 cnt = left;
931 if (cnt > 256)
932 cnt = 256;
933 if (copy_from_user(codebuf, p, cnt)) {
934 icn_maprelease_channel(card, 0);
935 return -EFAULT;
936 }
937 memcpy_toio(&sbuf_l, codebuf, cnt); /* copy data */
938 sbnext; /* switch to next buffer */
939 p += cnt;
940 left -= cnt;
941 timer = 0;
942 } else {
943#ifdef BOOT_DEBUG
944 printk(KERN_DEBUG "boot 2 !sbfree\n");
945#endif
946 if (timer++ > 5) {
947 icn_maprelease_channel(card, 0);
948 return -EIO;
949 }
950 set_current_state(TASK_INTERRUPTIBLE);
951 schedule_timeout(10);
952 }
953 }
954 writeb(0x20, &sbuf_n);
955 timer = 0;
956 while (1) {
957 if (readb(&cmd_o) || readb(&cmd_i)) {
958#ifdef BOOT_DEBUG
959 printk(KERN_DEBUG "Proto?\n");
960#endif
961 if (timer++ > 5) {
962 printk(KERN_WARNING
963 "icn: (%s) Protocol timed out.\n",
964 CID);
965#ifdef BOOT_DEBUG
966 printk(KERN_DEBUG "Proto TO!\n");
967#endif
968 icn_maprelease_channel(card, 0);
969 return -EIO;
970 }
971#ifdef BOOT_DEBUG
972 printk(KERN_DEBUG "Proto TO?\n");
973#endif
974 msleep_interruptible(ICN_BOOT_TIMEOUT1);
975 } else {
976 if ((card->secondhalf) || (!card->doubleS0)) {
977#ifdef BOOT_DEBUG
978 printk(KERN_DEBUG "Proto loaded, install poll-timer %d\n",
979 card->secondhalf);
980#endif
981 spin_lock_irqsave(&card->lock, flags);
982 init_timer(&card->st_timer);
983 card->st_timer.expires = jiffies + ICN_TIMER_DCREAD;
984 card->st_timer.function = icn_polldchan;
985 card->st_timer.data = (unsigned long) card;
986 add_timer(&card->st_timer);
987 card->flags |= ICN_FLAGS_RUNNING;
988 if (card->doubleS0) {
989 init_timer(&card->other->st_timer);
990 card->other->st_timer.expires = jiffies + ICN_TIMER_DCREAD;
991 card->other->st_timer.function = icn_polldchan;
992 card->other->st_timer.data = (unsigned long) card->other;
993 add_timer(&card->other->st_timer);
994 card->other->flags |= ICN_FLAGS_RUNNING;
995 }
996 spin_unlock_irqrestore(&card->lock, flags);
997 }
998 icn_maprelease_channel(card, 0);
999 return 0;
1000 }
1001 }
1002}
1003
1004/* Read the Status-replies from the Interface */
1005static int
1006icn_readstatus(u_char __user *buf, int len, icn_card * card)
1007{
1008 int count;
1009 u_char __user *p;
1010
1011 for (p = buf, count = 0; count < len; p++, count++) {
1012 if (card->msg_buf_read == card->msg_buf_write)
1013 return count;
1014 put_user(*card->msg_buf_read++, p);
1015 if (card->msg_buf_read > card->msg_buf_end)
1016 card->msg_buf_read = card->msg_buf;
1017 }
1018 return count;
1019}
1020
1021/* Put command-strings into the command-queue of the Interface */
1022static int
1023icn_writecmd(const u_char * buf, int len, int user, icn_card * card)
1024{
1025 int mch = card->secondhalf ? 2 : 0;
1026 int pp;
1027 int i;
1028 int count;
1029 int xcount;
1030 int ocount;
1031 int loop;
1032 unsigned long flags;
1033 int lastmap_channel;
1034 struct icn_card *lastmap_card;
1035 u_char *p;
1036 isdn_ctrl cmd;
1037 u_char msg[0x100];
1038
1039 ocount = 1;
1040 xcount = loop = 0;
1041 while (len) {
1042 count = cmd_free;
1043 if (count > len)
1044 count = len;
1045 if (user) {
1046 if (copy_from_user(msg, buf, count))
1047 return -EFAULT;
1048 } else
1049 memcpy(msg, buf, count);
1050
1051 spin_lock_irqsave(&dev.devlock, flags);
1052 lastmap_card = dev.mcard;
1053 lastmap_channel = dev.channel;
1054 icn_map_channel(card, mch);
1055
1056 icn_putmsg(card, '>');
1057 for (p = msg, pp = readb(&cmd_i), i = count; i > 0; i--, p++, pp
1058 ++) {
1059 writeb((*p == '\n') ? 0xff : *p,
1060 &dev.shmem->comm_buffers.pcio_buf[pp & 0xff]);
1061 len--;
1062 xcount++;
1063 icn_putmsg(card, *p);
1064 if ((*p == '\n') && (i > 1)) {
1065 icn_putmsg(card, '>');
1066 ocount++;
1067 }
1068 ocount++;
1069 }
1070 writeb((readb(&cmd_i) + count) & 0xff, &cmd_i);
1071 if (lastmap_card)
1072 icn_map_channel(lastmap_card, lastmap_channel);
1073 spin_unlock_irqrestore(&dev.devlock, flags);
1074 if (len) {
1075 mdelay(1);
1076 if (loop++ > 20)
1077 break;
1078 } else
1079 break;
1080 }
1081 if (len && (!user))
1082 printk(KERN_WARNING "icn: writemsg incomplete!\n");
1083 cmd.command = ISDN_STAT_STAVAIL;
1084 cmd.driver = card->myid;
1085 cmd.arg = ocount;
1086 card->interface.statcallb(&cmd);
1087 return xcount;
1088}
1089
1090/*
1091 * Delete card's pending timers, send STOP to linklevel
1092 */
1093static void
1094icn_stopcard(icn_card * card)
1095{
1096 unsigned long flags;
1097 isdn_ctrl cmd;
1098
1099 spin_lock_irqsave(&card->lock, flags);
1100 if (card->flags & ICN_FLAGS_RUNNING) {
1101 card->flags &= ~ICN_FLAGS_RUNNING;
1102 del_timer(&card->st_timer);
1103 del_timer(&card->rb_timer);
1104 spin_unlock_irqrestore(&card->lock, flags);
1105 cmd.command = ISDN_STAT_STOP;
1106 cmd.driver = card->myid;
1107 card->interface.statcallb(&cmd);
1108 if (card->doubleS0)
1109 icn_stopcard(card->other);
1110 } else
1111 spin_unlock_irqrestore(&card->lock, flags);
1112}
1113
1114static void
1115icn_stopallcards(void)
1116{
1117 icn_card *p = cards;
1118
1119 while (p) {
1120 icn_stopcard(p);
1121 p = p->next;
1122 }
1123}
1124
1125/*
1126 * Unmap all cards, because some of them may be mapped accidetly during
1127 * autoprobing of some network drivers (SMC-driver?)
1128 */
1129static void
1130icn_disable_cards(void)
1131{
1132 icn_card *card = cards;
1133
1134 while (card) {
1135 if (!request_region(card->port, ICN_PORTLEN, "icn-isdn")) {
1136 printk(KERN_WARNING
1137 "icn: (%s) ports 0x%03x-0x%03x in use.\n",
1138 CID,
1139 card->port,
1140 card->port + ICN_PORTLEN);
1141 } else {
1142 OUTB_P(0, ICN_RUN); /* Reset Controller */
1143 OUTB_P(0, ICN_MAPRAM); /* Disable RAM */
1144 release_region(card->port, ICN_PORTLEN);
1145 }
1146 card = card->next;
1147 }
1148}
1149
1150static int
1151icn_command(isdn_ctrl * c, icn_card * card)
1152{
1153 ulong a;
1154 ulong flags;
1155 int i;
1156 char cbuf[60];
1157 isdn_ctrl cmd;
1158 icn_cdef cdef;
1159 char __user *arg;
1160
1161 switch (c->command) {
1162 case ISDN_CMD_IOCTL:
1163 memcpy(&a, c->parm.num, sizeof(ulong));
1164 arg = (char __user *)a;
1165 switch (c->arg) {
1166 case ICN_IOCTL_SETMMIO:
1167 if (dev.memaddr != (a & 0x0ffc000)) {
1168 if (!request_mem_region(a & 0x0ffc000, 0x4000, "icn-isdn (all cards)")) {
1169 printk(KERN_WARNING
1170 "icn: memory at 0x%08lx in use.\n",
1171 a & 0x0ffc000);
1172 return -EINVAL;
1173 }
1174 release_mem_region(a & 0x0ffc000, 0x4000);
1175 icn_stopallcards();
1176 spin_lock_irqsave(&card->lock, flags);
1177 if (dev.mvalid) {
1178 iounmap(dev.shmem);
1179 release_mem_region(dev.memaddr, 0x4000);
1180 }
1181 dev.mvalid = 0;
1182 dev.memaddr = a & 0x0ffc000;
1183 spin_unlock_irqrestore(&card->lock, flags);
1184 printk(KERN_INFO
1185 "icn: (%s) mmio set to 0x%08lx\n",
1186 CID,
1187 dev.memaddr);
1188 }
1189 break;
1190 case ICN_IOCTL_GETMMIO:
1191 return (long) dev.memaddr;
1192 case ICN_IOCTL_SETPORT:
1193 if (a == 0x300 || a == 0x310 || a == 0x320 || a == 0x330
1194 || a == 0x340 || a == 0x350 || a == 0x360 ||
1195 a == 0x308 || a == 0x318 || a == 0x328 || a == 0x338
1196 || a == 0x348 || a == 0x358 || a == 0x368) {
1197 if (card->port != (unsigned short) a) {
1198 if (!request_region((unsigned short) a, ICN_PORTLEN, "icn-isdn")) {
1199 printk(KERN_WARNING
1200 "icn: (%s) ports 0x%03x-0x%03x in use.\n",
1201 CID, (int) a, (int) a + ICN_PORTLEN);
1202 return -EINVAL;
1203 }
1204 release_region((unsigned short) a, ICN_PORTLEN);
1205 icn_stopcard(card);
1206 spin_lock_irqsave(&card->lock, flags);
1207 if (card->rvalid)
1208 release_region(card->port, ICN_PORTLEN);
1209 card->port = (unsigned short) a;
1210 card->rvalid = 0;
1211 if (card->doubleS0) {
1212 card->other->port = (unsigned short) a;
1213 card->other->rvalid = 0;
1214 }
1215 spin_unlock_irqrestore(&card->lock, flags);
1216 printk(KERN_INFO
1217 "icn: (%s) port set to 0x%03x\n",
1218 CID, card->port);
1219 }
1220 } else
1221 return -EINVAL;
1222 break;
1223 case ICN_IOCTL_GETPORT:
1224 return (int) card->port;
1225 case ICN_IOCTL_GETDOUBLE:
1226 return (int) card->doubleS0;
1227 case ICN_IOCTL_DEBUGVAR:
1228 if (copy_to_user(arg,
1229 &card,
1230 sizeof(ulong)))
1231 return -EFAULT;
1232 a += sizeof(ulong);
1233 {
1234 ulong l = (ulong) & dev;
1235 if (copy_to_user(arg,
1236 &l,
1237 sizeof(ulong)))
1238 return -EFAULT;
1239 }
1240 return 0;
1241 case ICN_IOCTL_LOADBOOT:
1242 if (dev.firstload) {
1243 icn_disable_cards();
1244 dev.firstload = 0;
1245 }
1246 icn_stopcard(card);
1247 return (icn_loadboot(arg, card));
1248 case ICN_IOCTL_LOADPROTO:
1249 icn_stopcard(card);
1250 if ((i = (icn_loadproto(arg, card))))
1251 return i;
1252 if (card->doubleS0)
1253 i = icn_loadproto(arg + ICN_CODE_STAGE2, card->other);
1254 return i;
1255 break;
1256 case ICN_IOCTL_ADDCARD:
1257 if (!dev.firstload)
1258 return -EBUSY;
1259 if (copy_from_user(&cdef,
1260 arg,
1261 sizeof(cdef)))
1262 return -EFAULT;
1263 return (icn_addcard(cdef.port, cdef.id1, cdef.id2));
1264 break;
1265 case ICN_IOCTL_LEASEDCFG:
1266 if (a) {
1267 if (!card->leased) {
1268 card->leased = 1;
1269 while (card->ptype == ISDN_PTYPE_UNKNOWN) {
1270 msleep_interruptible(ICN_BOOT_TIMEOUT1);
1271 }
1272 msleep_interruptible(ICN_BOOT_TIMEOUT1);
1273 sprintf(cbuf, "00;FV2ON\n01;EAZ%c\n02;EAZ%c\n",
1274 (a & 1)?'1':'C', (a & 2)?'2':'C');
1275 i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
1276 printk(KERN_INFO
1277 "icn: (%s) Leased-line mode enabled\n",
1278 CID);
1279 cmd.command = ISDN_STAT_RUN;
1280 cmd.driver = card->myid;
1281 cmd.arg = 0;
1282 card->interface.statcallb(&cmd);
1283 }
1284 } else {
1285 if (card->leased) {
1286 card->leased = 0;
1287 sprintf(cbuf, "00;FV2OFF\n");
1288 i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
1289 printk(KERN_INFO
1290 "icn: (%s) Leased-line mode disabled\n",
1291 CID);
1292 cmd.command = ISDN_STAT_RUN;
1293 cmd.driver = card->myid;
1294 cmd.arg = 0;
1295 card->interface.statcallb(&cmd);
1296 }
1297 }
1298 return 0;
1299 default:
1300 return -EINVAL;
1301 }
1302 break;
1303 case ISDN_CMD_DIAL:
1304 if (!card->flags & ICN_FLAGS_RUNNING)
1305 return -ENODEV;
1306 if (card->leased)
1307 break;
1308 if ((c->arg & 255) < ICN_BCH) {
1309 char *p;
1310 char dial[50];
1311 char dcode[4];
1312
1313 a = c->arg;
1314 p = c->parm.setup.phone;
1315 if (*p == 's' || *p == 'S') {
1316 /* Dial for SPV */
1317 p++;
1318 strcpy(dcode, "SCA");
1319 } else
1320 /* Normal Dial */
1321 strcpy(dcode, "CAL");
1322 strcpy(dial, p);
1323 sprintf(cbuf, "%02d;D%s_R%s,%02d,%02d,%s\n", (int) (a + 1),
1324 dcode, dial, c->parm.setup.si1,
1325 c->parm.setup.si2, c->parm.setup.eazmsn);
1326 i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
1327 }
1328 break;
1329 case ISDN_CMD_ACCEPTD:
1330 if (!card->flags & ICN_FLAGS_RUNNING)
1331 return -ENODEV;
1332 if (c->arg < ICN_BCH) {
1333 a = c->arg + 1;
1334 if (card->fw_rev >= 300) {
1335 switch (card->l2_proto[a - 1]) {
1336 case ISDN_PROTO_L2_X75I:
1337 sprintf(cbuf, "%02d;BX75\n", (int) a);
1338 break;
1339 case ISDN_PROTO_L2_HDLC:
1340 sprintf(cbuf, "%02d;BTRA\n", (int) a);
1341 break;
1342 }
1343 i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
1344 }
1345 sprintf(cbuf, "%02d;DCON_R\n", (int) a);
1346 i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
1347 }
1348 break;
1349 case ISDN_CMD_ACCEPTB:
1350 if (!card->flags & ICN_FLAGS_RUNNING)
1351 return -ENODEV;
1352 if (c->arg < ICN_BCH) {
1353 a = c->arg + 1;
1354 if (card->fw_rev >= 300)
1355 switch (card->l2_proto[a - 1]) {
1356 case ISDN_PROTO_L2_X75I:
1357 sprintf(cbuf, "%02d;BCON_R,BX75\n", (int) a);
1358 break;
1359 case ISDN_PROTO_L2_HDLC:
1360 sprintf(cbuf, "%02d;BCON_R,BTRA\n", (int) a);
1361 break;
1362 } else
1363 sprintf(cbuf, "%02d;BCON_R\n", (int) a);
1364 i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
1365 }
1366 break;
1367 case ISDN_CMD_HANGUP:
1368 if (!card->flags & ICN_FLAGS_RUNNING)
1369 return -ENODEV;
1370 if (c->arg < ICN_BCH) {
1371 a = c->arg + 1;
1372 sprintf(cbuf, "%02d;BDIS_R\n%02d;DDIS_R\n", (int) a, (int) a);
1373 i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
1374 }
1375 break;
1376 case ISDN_CMD_SETEAZ:
1377 if (!card->flags & ICN_FLAGS_RUNNING)
1378 return -ENODEV;
1379 if (card->leased)
1380 break;
1381 if (c->arg < ICN_BCH) {
1382 a = c->arg + 1;
1383 if (card->ptype == ISDN_PTYPE_EURO) {
1384 sprintf(cbuf, "%02d;MS%s%s\n", (int) a,
1385 c->parm.num[0] ? "N" : "ALL", c->parm.num);
1386 } else
1387 sprintf(cbuf, "%02d;EAZ%s\n", (int) a,
1388 c->parm.num[0] ? (char *)(c->parm.num) : "0123456789");
1389 i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
1390 }
1391 break;
1392 case ISDN_CMD_CLREAZ:
1393 if (!card->flags & ICN_FLAGS_RUNNING)
1394 return -ENODEV;
1395 if (card->leased)
1396 break;
1397 if (c->arg < ICN_BCH) {
1398 a = c->arg + 1;
1399 if (card->ptype == ISDN_PTYPE_EURO)
1400 sprintf(cbuf, "%02d;MSNC\n", (int) a);
1401 else
1402 sprintf(cbuf, "%02d;EAZC\n", (int) a);
1403 i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
1404 }
1405 break;
1406 case ISDN_CMD_SETL2:
1407 if (!card->flags & ICN_FLAGS_RUNNING)
1408 return -ENODEV;
1409 if ((c->arg & 255) < ICN_BCH) {
1410 a = c->arg;
1411 switch (a >> 8) {
1412 case ISDN_PROTO_L2_X75I:
1413 sprintf(cbuf, "%02d;BX75\n", (int) (a & 255) + 1);
1414 break;
1415 case ISDN_PROTO_L2_HDLC:
1416 sprintf(cbuf, "%02d;BTRA\n", (int) (a & 255) + 1);
1417 break;
1418 default:
1419 return -EINVAL;
1420 }
1421 i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
1422 card->l2_proto[a & 255] = (a >> 8);
1423 }
1424 break;
1425 case ISDN_CMD_SETL3:
1426 if (!card->flags & ICN_FLAGS_RUNNING)
1427 return -ENODEV;
1428 return 0;
1429 default:
1430 return -EINVAL;
1431 }
1432 return 0;
1433}
1434
1435/*
1436 * Find card with given driverId
1437 */
1438static inline icn_card *
1439icn_findcard(int driverid)
1440{
1441 icn_card *p = cards;
1442
1443 while (p) {
1444 if (p->myid == driverid)
1445 return p;
1446 p = p->next;
1447 }
1448 return (icn_card *) 0;
1449}
1450
1451/*
1452 * Wrapper functions for interface to linklevel
1453 */
1454static int
1455if_command(isdn_ctrl * c)
1456{
1457 icn_card *card = icn_findcard(c->driver);
1458
1459 if (card)
1460 return (icn_command(c, card));
1461 printk(KERN_ERR
1462 "icn: if_command %d called with invalid driverId %d!\n",
1463 c->command, c->driver);
1464 return -ENODEV;
1465}
1466
1467static int
1468if_writecmd(const u_char __user *buf, int len, int id, int channel)
1469{
1470 icn_card *card = icn_findcard(id);
1471
1472 if (card) {
1473 if (!card->flags & ICN_FLAGS_RUNNING)
1474 return -ENODEV;
1475 return (icn_writecmd(buf, len, 1, card));
1476 }
1477 printk(KERN_ERR
1478 "icn: if_writecmd called with invalid driverId!\n");
1479 return -ENODEV;
1480}
1481
1482static int
1483if_readstatus(u_char __user *buf, int len, int id, int channel)
1484{
1485 icn_card *card = icn_findcard(id);
1486
1487 if (card) {
1488 if (!card->flags & ICN_FLAGS_RUNNING)
1489 return -ENODEV;
1490 return (icn_readstatus(buf, len, card));
1491 }
1492 printk(KERN_ERR
1493 "icn: if_readstatus called with invalid driverId!\n");
1494 return -ENODEV;
1495}
1496
1497static int
1498if_sendbuf(int id, int channel, int ack, struct sk_buff *skb)
1499{
1500 icn_card *card = icn_findcard(id);
1501
1502 if (card) {
1503 if (!card->flags & ICN_FLAGS_RUNNING)
1504 return -ENODEV;
1505 return (icn_sendbuf(channel, ack, skb, card));
1506 }
1507 printk(KERN_ERR
1508 "icn: if_sendbuf called with invalid driverId!\n");
1509 return -ENODEV;
1510}
1511
1512/*
1513 * Allocate a new card-struct, initialize it
1514 * link it into cards-list and register it at linklevel.
1515 */
1516static icn_card *
1517icn_initcard(int port, char *id)
1518{
1519 icn_card *card;
1520 int i;
1521
1522 if (!(card = (icn_card *) kmalloc(sizeof(icn_card), GFP_KERNEL))) {
1523 printk(KERN_WARNING
1524 "icn: (%s) Could not allocate card-struct.\n", id);
1525 return (icn_card *) 0;
1526 }
1527 memset((char *) card, 0, sizeof(icn_card));
1528 spin_lock_init(&card->lock);
1529 card->port = port;
1530 card->interface.owner = THIS_MODULE;
1531 card->interface.hl_hdrlen = 1;
1532 card->interface.channels = ICN_BCH;
1533 card->interface.maxbufsize = 4000;
1534 card->interface.command = if_command;
1535 card->interface.writebuf_skb = if_sendbuf;
1536 card->interface.writecmd = if_writecmd;
1537 card->interface.readstat = if_readstatus;
1538 card->interface.features = ISDN_FEATURE_L2_X75I |
1539 ISDN_FEATURE_L2_HDLC |
1540 ISDN_FEATURE_L3_TRANS |
1541 ISDN_FEATURE_P_UNKNOWN;
1542 card->ptype = ISDN_PTYPE_UNKNOWN;
1543 strlcpy(card->interface.id, id, sizeof(card->interface.id));
1544 card->msg_buf_write = card->msg_buf;
1545 card->msg_buf_read = card->msg_buf;
1546 card->msg_buf_end = &card->msg_buf[sizeof(card->msg_buf) - 1];
1547 for (i = 0; i < ICN_BCH; i++) {
1548 card->l2_proto[i] = ISDN_PROTO_L2_X75I;
1549 skb_queue_head_init(&card->spqueue[i]);
1550 }
1551 card->next = cards;
1552 cards = card;
1553 if (!register_isdn(&card->interface)) {
1554 cards = cards->next;
1555 printk(KERN_WARNING
1556 "icn: Unable to register %s\n", id);
1557 kfree(card);
1558 return (icn_card *) 0;
1559 }
1560 card->myid = card->interface.channels;
1561 sprintf(card->regname, "icn-isdn (%s)", card->interface.id);
1562 return card;
1563}
1564
1565static int
1566icn_addcard(int port, char *id1, char *id2)
1567{
1568 icn_card *card;
1569 icn_card *card2;
1570
1571 if (!(card = icn_initcard(port, id1))) {
1572 return -EIO;
1573 }
1574 if (!strlen(id2)) {
1575 printk(KERN_INFO
1576 "icn: (%s) ICN-2B, port 0x%x added\n",
1577 card->interface.id, port);
1578 return 0;
1579 }
1580 if (!(card2 = icn_initcard(port, id2))) {
1581 printk(KERN_INFO
1582 "icn: (%s) half ICN-4B, port 0x%x added\n",
1583 card2->interface.id, port);
1584 return 0;
1585 }
1586 card->doubleS0 = 1;
1587 card->secondhalf = 0;
1588 card->other = card2;
1589 card2->doubleS0 = 1;
1590 card2->secondhalf = 1;
1591 card2->other = card;
1592 printk(KERN_INFO
1593 "icn: (%s and %s) ICN-4B, port 0x%x added\n",
1594 card->interface.id, card2->interface.id, port);
1595 return 0;
1596}
1597
1598#ifndef MODULE
1599static int __init
1600icn_setup(char *line)
1601{
1602 char *p, *str;
1603 int ints[3];
1604 static char sid[20];
1605 static char sid2[20];
1606
1607 str = get_options(line, 2, ints);
1608 if (ints[0])
1609 portbase = ints[1];
1610 if (ints[0] > 1)
1611 membase = (unsigned long)ints[2];
1612 if (str && *str) {
1613 strcpy(sid, str);
1614 icn_id = sid;
1615 if ((p = strchr(sid, ','))) {
1616 *p++ = 0;
1617 strcpy(sid2, p);
1618 icn_id2 = sid2;
1619 }
1620 }
1621 return(1);
1622}
1623__setup("icn=", icn_setup);
1624#endif /* MODULE */
1625
1626static int __init icn_init(void)
1627{
1628 char *p;
1629 char rev[10];
1630
1631 memset(&dev, 0, sizeof(icn_dev));
1632 dev.memaddr = (membase & 0x0ffc000);
1633 dev.channel = -1;
1634 dev.mcard = NULL;
1635 dev.firstload = 1;
1636 spin_lock_init(&dev.devlock);
1637
1638 if ((p = strchr(revision, ':'))) {
1639 strcpy(rev, p + 1);
1640 p = strchr(rev, '$');
1641 *p = 0;
1642 } else
1643 strcpy(rev, " ??? ");
1644 printk(KERN_NOTICE "ICN-ISDN-driver Rev%smem=0x%08lx\n", rev,
1645 dev.memaddr);
1646 return (icn_addcard(portbase, icn_id, icn_id2));
1647}
1648
1649static void __exit icn_exit(void)
1650{
1651 isdn_ctrl cmd;
1652 icn_card *card = cards;
1653 icn_card *last;
1654 int i;
1655 unsigned long flags;
1656
1657 icn_stopallcards();
1658 while (card) {
1659 cmd.command = ISDN_STAT_UNLOAD;
1660 cmd.driver = card->myid;
1661 card->interface.statcallb(&cmd);
1662 spin_lock_irqsave(&card->lock, flags);
1663 if (card->rvalid) {
1664 OUTB_P(0, ICN_RUN); /* Reset Controller */
1665 OUTB_P(0, ICN_MAPRAM); /* Disable RAM */
1666 if (card->secondhalf || (!card->doubleS0)) {
1667 release_region(card->port, ICN_PORTLEN);
1668 card->rvalid = 0;
1669 }
1670 for (i = 0; i < ICN_BCH; i++)
1671 icn_free_queue(card, i);
1672 }
1673 card = card->next;
1674 spin_unlock_irqrestore(&card->lock, flags);
1675 }
1676 card = cards;
1677 cards = NULL;
1678 while (card) {
1679 last = card;
1680 card = card->next;
1681 kfree(last);
1682 }
1683 if (dev.mvalid) {
1684 iounmap(dev.shmem);
1685 release_mem_region(dev.memaddr, 0x4000);
1686 }
1687 printk(KERN_NOTICE "ICN-ISDN-driver unloaded\n");
1688}
1689
1690module_init(icn_init);
1691module_exit(icn_exit);
diff --git a/drivers/isdn/icn/icn.h b/drivers/isdn/icn/icn.h
new file mode 100644
index 000000000000..9028cc3b5071
--- /dev/null
+++ b/drivers/isdn/icn/icn.h
@@ -0,0 +1,254 @@
1/* $Id: icn.h,v 1.30.6.5 2001/09/23 22:24:55 kai Exp $
2 *
3 * ISDN lowlevel-module for the ICN active ISDN-Card.
4 *
5 * Copyright 1994 by Fritz Elfert (fritz@isdn4linux.de)
6 *
7 * This software may be used and distributed according to the terms
8 * of the GNU General Public License, incorporated herein by reference.
9 *
10 */
11
12#ifndef icn_h
13#define icn_h
14
15#define ICN_IOCTL_SETMMIO 0
16#define ICN_IOCTL_GETMMIO 1
17#define ICN_IOCTL_SETPORT 2
18#define ICN_IOCTL_GETPORT 3
19#define ICN_IOCTL_LOADBOOT 4
20#define ICN_IOCTL_LOADPROTO 5
21#define ICN_IOCTL_LEASEDCFG 6
22#define ICN_IOCTL_GETDOUBLE 7
23#define ICN_IOCTL_DEBUGVAR 8
24#define ICN_IOCTL_ADDCARD 9
25
26/* Struct for adding new cards */
27typedef struct icn_cdef {
28 int port;
29 char id1[10];
30 char id2[10];
31} icn_cdef;
32
33#if defined(__KERNEL__) || defined(__DEBUGVAR__)
34
35#ifdef __KERNEL__
36/* Kernel includes */
37
38#include <linux/version.h>
39#include <linux/errno.h>
40#include <linux/fs.h>
41#include <linux/major.h>
42#include <asm/io.h>
43#include <linux/kernel.h>
44#include <linux/signal.h>
45#include <linux/slab.h>
46#include <linux/mm.h>
47#include <linux/mman.h>
48#include <linux/ioport.h>
49#include <linux/timer.h>
50#include <linux/wait.h>
51#include <linux/delay.h>
52#include <linux/isdnif.h>
53
54#endif /* __KERNEL__ */
55
56/* some useful macros for debugging */
57#ifdef ICN_DEBUG_PORT
58#define OUTB_P(v,p) {printk(KERN_DEBUG "icn: outb_p(0x%02x,0x%03x)\n",v,p); outb_p(v,p);}
59#else
60#define OUTB_P outb
61#endif
62
63/* Defaults for Port-Address and shared-memory */
64#define ICN_BASEADDR 0x320
65#define ICN_PORTLEN (0x04)
66#define ICN_MEMADDR 0x0d0000
67
68#define ICN_FLAGS_B1ACTIVE 1 /* B-Channel-1 is open */
69#define ICN_FLAGS_B2ACTIVE 2 /* B-Channel-2 is open */
70#define ICN_FLAGS_RUNNING 4 /* Cards driver activated */
71#define ICN_FLAGS_RBTIMER 8 /* cyclic scheduling of B-Channel-poll */
72
73#define ICN_BOOT_TIMEOUT1 1000 /* Delay for Boot-download (msecs) */
74
75#define ICN_TIMER_BCREAD (HZ/100) /* B-Channel poll-cycle */
76#define ICN_TIMER_DCREAD (HZ/2) /* D-Channel poll-cycle */
77
78#define ICN_CODE_STAGE1 4096 /* Size of bootcode */
79#define ICN_CODE_STAGE2 65536 /* Size of protocol-code */
80
81#define ICN_MAX_SQUEUE 8000 /* Max. outstanding send-data (2* hw-buf.) */
82#define ICN_FRAGSIZE (250) /* Max. size of send-fragments */
83#define ICN_BCH 2 /* Number of supported channels per card */
84
85/* type-definitions for accessing the mmap-io-areas */
86
87#define SHM_DCTL_OFFSET (0) /* Offset to data-controlstructures in shm */
88#define SHM_CCTL_OFFSET (0x1d2) /* Offset to comm-controlstructures in shm */
89#define SHM_CBUF_OFFSET (0x200) /* Offset to comm-buffers in shm */
90#define SHM_DBUF_OFFSET (0x2000) /* Offset to data-buffers in shm */
91
92/*
93 * Layout of card's data buffers
94 */
95typedef struct {
96 unsigned char length; /* Bytecount of fragment (max 250) */
97 unsigned char endflag; /* 0=last frag., 0xff=frag. continued */
98 unsigned char data[ICN_FRAGSIZE]; /* The data */
99 /* Fill to 256 bytes */
100 char unused[0x100 - ICN_FRAGSIZE - 2];
101} frag_buf;
102
103/*
104 * Layout of card's shared memory
105 */
106typedef union {
107 struct {
108 unsigned char scns; /* Index to free SendFrag. */
109 unsigned char scnr; /* Index to active SendFrag READONLY */
110 unsigned char ecns; /* Index to free RcvFrag. READONLY */
111 unsigned char ecnr; /* Index to valid RcvFrag */
112 char unused[6];
113 unsigned short fuell1; /* Internal Buf Bytecount */
114 } data_control;
115 struct {
116 char unused[SHM_CCTL_OFFSET];
117 unsigned char iopc_i; /* Read-Ptr Status-Queue READONLY */
118 unsigned char iopc_o; /* Write-Ptr Status-Queue */
119 unsigned char pcio_i; /* Write-Ptr Command-Queue */
120 unsigned char pcio_o; /* Read-Ptr Command Queue READONLY */
121 } comm_control;
122 struct {
123 char unused[SHM_CBUF_OFFSET];
124 unsigned char pcio_buf[0x100]; /* Ring-Buffer Command-Queue */
125 unsigned char iopc_buf[0x100]; /* Ring-Buffer Status-Queue */
126 } comm_buffers;
127 struct {
128 char unused[SHM_DBUF_OFFSET];
129 frag_buf receive_buf[0x10];
130 frag_buf send_buf[0x10];
131 } data_buffers;
132} icn_shmem;
133
134/*
135 * Per card driver data
136 */
137typedef struct icn_card {
138 struct icn_card *next; /* Pointer to next device struct */
139 struct icn_card *other; /* Pointer to other card for ICN4B */
140 unsigned short port; /* Base-port-address */
141 int myid; /* Driver-Nr. assigned by linklevel */
142 int rvalid; /* IO-portregion has been requested */
143 int leased; /* Flag: This Adapter is connected */
144 /* to a leased line */
145 unsigned short flags; /* Statusflags */
146 int doubleS0; /* Flag: ICN4B */
147 int secondhalf; /* Flag: Second half of a doubleS0 */
148 int fw_rev; /* Firmware revision loaded */
149 int ptype; /* Protocol type (1TR6 or Euro) */
150 struct timer_list st_timer; /* Timer for Status-Polls */
151 struct timer_list rb_timer; /* Timer for B-Channel-Polls */
152 u_char rcvbuf[ICN_BCH][4096]; /* B-Channel-Receive-Buffers */
153 int rcvidx[ICN_BCH]; /* Index for above buffers */
154 int l2_proto[ICN_BCH]; /* Current layer-2-protocol */
155 isdn_if interface; /* Interface to upper layer */
156 int iptr; /* Index to imsg-buffer */
157 char imsg[60]; /* Internal buf for status-parsing */
158 char msg_buf[2048]; /* Buffer for status-messages */
159 char *msg_buf_write; /* Writepointer for statusbuffer */
160 char *msg_buf_read; /* Readpointer for statusbuffer */
161 char *msg_buf_end; /* Pointer to end of statusbuffer */
162 int sndcount[ICN_BCH]; /* Byte-counters for B-Ch.-send */
163 int xlen[ICN_BCH]; /* Byte-counters/Flags for sent-ACK */
164 struct sk_buff *xskb[ICN_BCH]; /* Current transmitted skb */
165 struct sk_buff_head spqueue[ICN_BCH]; /* Sendqueue */
166 char regname[35]; /* Name used for request_region */
167 u_char xmit_lock[ICN_BCH]; /* Semaphore for pollbchan_send()*/
168 spinlock_t lock; /* protect critical operations */
169} icn_card;
170
171/*
172 * Main driver data
173 */
174typedef struct icn_dev {
175 spinlock_t devlock; /* spinlock to protect this struct */
176 unsigned long memaddr; /* Address of memory mapped buffers */
177 icn_shmem __iomem *shmem; /* Pointer to memory-mapped-buffers */
178 int mvalid; /* IO-shmem has been requested */
179 int channel; /* Currently mapped channel */
180 struct icn_card *mcard; /* Currently mapped card */
181 int chanlock; /* Semaphore for channel-mapping */
182 int firstload; /* Flag: firmware never loaded */
183} icn_dev;
184
185typedef icn_dev *icn_devptr;
186
187#ifdef __KERNEL__
188
189static icn_card *cards = (icn_card *) 0;
190static u_char chan2bank[] =
191{0, 4, 8, 12}; /* for icn_map_channel() */
192
193static icn_dev dev;
194
195#endif /* __KERNEL__ */
196
197/* Utility-Macros */
198
199/* Macros for accessing ports */
200#define ICN_CFG (card->port)
201#define ICN_MAPRAM (card->port+1)
202#define ICN_RUN (card->port+2)
203#define ICN_BANK (card->port+3)
204
205/* Return true, if there is a free transmit-buffer */
206#define sbfree (((readb(&dev.shmem->data_control.scns)+1) & 0xf) != \
207 readb(&dev.shmem->data_control.scnr))
208
209/* Switch to next transmit-buffer */
210#define sbnext (writeb((readb(&dev.shmem->data_control.scns)+1) & 0xf, \
211 &dev.shmem->data_control.scns))
212
213/* Shortcuts for transmit-buffer-access */
214#define sbuf_n dev.shmem->data_control.scns
215#define sbuf_d dev.shmem->data_buffers.send_buf[readb(&sbuf_n)].data
216#define sbuf_l dev.shmem->data_buffers.send_buf[readb(&sbuf_n)].length
217#define sbuf_f dev.shmem->data_buffers.send_buf[readb(&sbuf_n)].endflag
218
219/* Return true, if there is receive-data is available */
220#define rbavl (readb(&dev.shmem->data_control.ecnr) != \
221 readb(&dev.shmem->data_control.ecns))
222
223/* Switch to next receive-buffer */
224#define rbnext (writeb((readb(&dev.shmem->data_control.ecnr)+1) & 0xf, \
225 &dev.shmem->data_control.ecnr))
226
227/* Shortcuts for receive-buffer-access */
228#define rbuf_n dev.shmem->data_control.ecnr
229#define rbuf_d dev.shmem->data_buffers.receive_buf[readb(&rbuf_n)].data
230#define rbuf_l dev.shmem->data_buffers.receive_buf[readb(&rbuf_n)].length
231#define rbuf_f dev.shmem->data_buffers.receive_buf[readb(&rbuf_n)].endflag
232
233/* Shortcuts for command-buffer-access */
234#define cmd_o (dev.shmem->comm_control.pcio_o)
235#define cmd_i (dev.shmem->comm_control.pcio_i)
236
237/* Return free space in command-buffer */
238#define cmd_free ((readb(&cmd_i)>=readb(&cmd_o))? \
239 0x100-readb(&cmd_i)+readb(&cmd_o): \
240 readb(&cmd_o)-readb(&cmd_i))
241
242/* Shortcuts for message-buffer-access */
243#define msg_o (dev.shmem->comm_control.iopc_o)
244#define msg_i (dev.shmem->comm_control.iopc_i)
245
246/* Return length of Message, if avail. */
247#define msg_avail ((readb(&msg_o)>readb(&msg_i))? \
248 0x100-readb(&msg_o)+readb(&msg_i): \
249 readb(&msg_i)-readb(&msg_o))
250
251#define CID (card->interface.id)
252
253#endif /* defined(__KERNEL__) || defined(__DEBUGVAR__) */
254#endif /* icn_h */
diff --git a/drivers/isdn/isdnloop/Makefile b/drivers/isdn/isdnloop/Makefile
new file mode 100644
index 000000000000..317cd3c5b8ee
--- /dev/null
+++ b/drivers/isdn/isdnloop/Makefile
@@ -0,0 +1,5 @@
1# Makefile for the isdnloop ISDN device driver
2
3# Each configuration option enables a list of files.
4
5obj-$(CONFIG_ISDN_DRV_LOOP) += isdnloop.o
diff --git a/drivers/isdn/isdnloop/isdnloop.c b/drivers/isdn/isdnloop/isdnloop.c
new file mode 100644
index 000000000000..14e1f8fbc61f
--- /dev/null
+++ b/drivers/isdn/isdnloop/isdnloop.c
@@ -0,0 +1,1554 @@
1/* $Id: isdnloop.c,v 1.11.6.7 2001/11/11 19:54:31 kai Exp $
2 *
3 * ISDN low-level module implementing a dummy loop driver.
4 *
5 * Copyright 1997 by Fritz Elfert (fritz@isdn4linux.de)
6 *
7 * This software may be used and distributed according to the terms
8 * of the GNU General Public License, incorporated herein by reference.
9 *
10 */
11
12#include <linux/config.h>
13#include <linux/module.h>
14#include <linux/interrupt.h>
15#include <linux/init.h>
16#include <linux/sched.h>
17#include "isdnloop.h"
18
19static char *revision = "$Revision: 1.11.6.7 $";
20static char *isdnloop_id = "loop0";
21
22MODULE_DESCRIPTION("ISDN4Linux: Pseudo Driver that simulates an ISDN card");
23MODULE_AUTHOR("Fritz Elfert");
24MODULE_LICENSE("GPL");
25MODULE_PARM(isdnloop_id, "s");
26MODULE_PARM_DESC(isdnloop_id, "ID-String of first card");
27
28static int isdnloop_addcard(char *);
29
30/*
31 * Free queue completely.
32 *
33 * Parameter:
34 * card = pointer to card struct
35 * channel = channel number
36 */
37static void
38isdnloop_free_queue(isdnloop_card * card, int channel)
39{
40 struct sk_buff_head *queue = &card->bqueue[channel];
41
42 skb_queue_purge(queue);
43 card->sndcount[channel] = 0;
44}
45
46/*
47 * Send B-Channel data to another virtual card.
48 * This routine is called via timer-callback from isdnloop_pollbchan().
49 *
50 * Parameter:
51 * card = pointer to card struct.
52 * ch = channel number (0-based)
53 */
54static void
55isdnloop_bchan_send(isdnloop_card * card, int ch)
56{
57 isdnloop_card *rcard = card->rcard[ch];
58 int rch = card->rch[ch], len, ack;
59 struct sk_buff *skb;
60 isdn_ctrl cmd;
61
62 while (card->sndcount[ch]) {
63 if ((skb = skb_dequeue(&card->bqueue[ch]))) {
64 len = skb->len;
65 card->sndcount[ch] -= len;
66 ack = *(skb->head); /* used as scratch area */
67 cmd.driver = card->myid;
68 cmd.arg = ch;
69 if (rcard){
70 rcard->interface.rcvcallb_skb(rcard->myid, rch, skb);
71 } else {
72 printk(KERN_WARNING "isdnloop: no rcard, skb dropped\n");
73 dev_kfree_skb(skb);
74
75 };
76 cmd.command = ISDN_STAT_BSENT;
77 cmd.parm.length = len;
78 card->interface.statcallb(&cmd);
79 } else
80 card->sndcount[ch] = 0;
81 }
82}
83
84/*
85 * Send/Receive Data to/from the B-Channel.
86 * This routine is called via timer-callback.
87 * It schedules itself while any B-Channel is open.
88 *
89 * Parameter:
90 * data = pointer to card struct, set by kernel timer.data
91 */
92static void
93isdnloop_pollbchan(unsigned long data)
94{
95 isdnloop_card *card = (isdnloop_card *) data;
96 unsigned long flags;
97
98 if (card->flags & ISDNLOOP_FLAGS_B1ACTIVE)
99 isdnloop_bchan_send(card, 0);
100 if (card->flags & ISDNLOOP_FLAGS_B2ACTIVE)
101 isdnloop_bchan_send(card, 1);
102 if (card->flags & (ISDNLOOP_FLAGS_B1ACTIVE | ISDNLOOP_FLAGS_B2ACTIVE)) {
103 /* schedule b-channel polling again */
104 save_flags(flags);
105 cli();
106 card->rb_timer.expires = jiffies + ISDNLOOP_TIMER_BCREAD;
107 add_timer(&card->rb_timer);
108 card->flags |= ISDNLOOP_FLAGS_RBTIMER;
109 restore_flags(flags);
110 } else
111 card->flags &= ~ISDNLOOP_FLAGS_RBTIMER;
112}
113
114/*
115 * Parse ICN-type setup string and fill fields of setup-struct
116 * with parsed data.
117 *
118 * Parameter:
119 * setup = setup string, format: [caller-id],si1,si2,[called-id]
120 * cmd = pointer to struct to be filled.
121 */
122static void
123isdnloop_parse_setup(char *setup, isdn_ctrl * cmd)
124{
125 char *t = setup;
126 char *s = strchr(t, ',');
127
128 *s++ = '\0';
129 strlcpy(cmd->parm.setup.phone, t, sizeof(cmd->parm.setup.phone));
130 s = strchr(t = s, ',');
131 *s++ = '\0';
132 if (!strlen(t))
133 cmd->parm.setup.si1 = 0;
134 else
135 cmd->parm.setup.si1 = simple_strtoul(t, NULL, 10);
136 s = strchr(t = s, ',');
137 *s++ = '\0';
138 if (!strlen(t))
139 cmd->parm.setup.si2 = 0;
140 else
141 cmd->parm.setup.si2 =
142 simple_strtoul(t, NULL, 10);
143 strlcpy(cmd->parm.setup.eazmsn, s, sizeof(cmd->parm.setup.eazmsn));
144 cmd->parm.setup.plan = 0;
145 cmd->parm.setup.screen = 0;
146}
147
148typedef struct isdnloop_stat {
149 char *statstr;
150 int command;
151 int action;
152} isdnloop_stat;
153/* *INDENT-OFF* */
154static isdnloop_stat isdnloop_stat_table[] =
155{
156 {"BCON_", ISDN_STAT_BCONN, 1}, /* B-Channel connected */
157 {"BDIS_", ISDN_STAT_BHUP, 2}, /* B-Channel disconnected */
158 {"DCON_", ISDN_STAT_DCONN, 0}, /* D-Channel connected */
159 {"DDIS_", ISDN_STAT_DHUP, 0}, /* D-Channel disconnected */
160 {"DCAL_I", ISDN_STAT_ICALL, 3}, /* Incoming call dialup-line */
161 {"DSCA_I", ISDN_STAT_ICALL, 3}, /* Incoming call 1TR6-SPV */
162 {"FCALL", ISDN_STAT_ICALL, 4}, /* Leased line connection up */
163 {"CIF", ISDN_STAT_CINF, 5}, /* Charge-info, 1TR6-type */
164 {"AOC", ISDN_STAT_CINF, 6}, /* Charge-info, DSS1-type */
165 {"CAU", ISDN_STAT_CAUSE, 7}, /* Cause code */
166 {"TEI OK", ISDN_STAT_RUN, 0}, /* Card connected to wallplug */
167 {"E_L1: ACT FAIL", ISDN_STAT_BHUP, 8}, /* Layer-1 activation failed */
168 {"E_L2: DATA LIN", ISDN_STAT_BHUP, 8}, /* Layer-2 data link lost */
169 {"E_L1: ACTIVATION FAILED",
170 ISDN_STAT_BHUP, 8}, /* Layer-1 activation failed */
171 {NULL, 0, -1}
172};
173/* *INDENT-ON* */
174
175
176/*
177 * Parse Status message-strings from virtual card.
178 * Depending on status, call statcallb for sending messages to upper
179 * levels. Also set/reset B-Channel active-flags.
180 *
181 * Parameter:
182 * status = status string to parse.
183 * channel = channel where message comes from.
184 * card = card where message comes from.
185 */
186static void
187isdnloop_parse_status(u_char * status, int channel, isdnloop_card * card)
188{
189 isdnloop_stat *s = isdnloop_stat_table;
190 int action = -1;
191 isdn_ctrl cmd;
192
193 while (s->statstr) {
194 if (!strncmp(status, s->statstr, strlen(s->statstr))) {
195 cmd.command = s->command;
196 action = s->action;
197 break;
198 }
199 s++;
200 }
201 if (action == -1)
202 return;
203 cmd.driver = card->myid;
204 cmd.arg = channel;
205 switch (action) {
206 case 1:
207 /* BCON_x */
208 card->flags |= (channel) ?
209 ISDNLOOP_FLAGS_B2ACTIVE : ISDNLOOP_FLAGS_B1ACTIVE;
210 break;
211 case 2:
212 /* BDIS_x */
213 card->flags &= ~((channel) ?
214 ISDNLOOP_FLAGS_B2ACTIVE : ISDNLOOP_FLAGS_B1ACTIVE);
215 isdnloop_free_queue(card, channel);
216 break;
217 case 3:
218 /* DCAL_I and DSCA_I */
219 isdnloop_parse_setup(status + 6, &cmd);
220 break;
221 case 4:
222 /* FCALL */
223 sprintf(cmd.parm.setup.phone, "LEASED%d", card->myid);
224 sprintf(cmd.parm.setup.eazmsn, "%d", channel + 1);
225 cmd.parm.setup.si1 = 7;
226 cmd.parm.setup.si2 = 0;
227 cmd.parm.setup.plan = 0;
228 cmd.parm.setup.screen = 0;
229 break;
230 case 5:
231 /* CIF */
232 strlcpy(cmd.parm.num, status + 3, sizeof(cmd.parm.num));
233 break;
234 case 6:
235 /* AOC */
236 snprintf(cmd.parm.num, sizeof(cmd.parm.num), "%d",
237 (int) simple_strtoul(status + 7, NULL, 16));
238 break;
239 case 7:
240 /* CAU */
241 status += 3;
242 if (strlen(status) == 4)
243 snprintf(cmd.parm.num, sizeof(cmd.parm.num), "%s%c%c",
244 status + 2, *status, *(status + 1));
245 else
246 strlcpy(cmd.parm.num, status + 1, sizeof(cmd.parm.num));
247 break;
248 case 8:
249 /* Misc Errors on L1 and L2 */
250 card->flags &= ~ISDNLOOP_FLAGS_B1ACTIVE;
251 isdnloop_free_queue(card, 0);
252 cmd.arg = 0;
253 cmd.driver = card->myid;
254 card->interface.statcallb(&cmd);
255 cmd.command = ISDN_STAT_DHUP;
256 cmd.arg = 0;
257 cmd.driver = card->myid;
258 card->interface.statcallb(&cmd);
259 cmd.command = ISDN_STAT_BHUP;
260 card->flags &= ~ISDNLOOP_FLAGS_B2ACTIVE;
261 isdnloop_free_queue(card, 1);
262 cmd.arg = 1;
263 cmd.driver = card->myid;
264 card->interface.statcallb(&cmd);
265 cmd.command = ISDN_STAT_DHUP;
266 cmd.arg = 1;
267 cmd.driver = card->myid;
268 break;
269 }
270 card->interface.statcallb(&cmd);
271}
272
273/*
274 * Store a cwcharacter into ringbuffer for reading from /dev/isdnctrl
275 *
276 * Parameter:
277 * card = pointer to card struct.
278 * c = char to store.
279 */
280static void
281isdnloop_putmsg(isdnloop_card * card, unsigned char c)
282{
283 ulong flags;
284
285 save_flags(flags);
286 cli();
287 *card->msg_buf_write++ = (c == 0xff) ? '\n' : c;
288 if (card->msg_buf_write == card->msg_buf_read) {
289 if (++card->msg_buf_read > card->msg_buf_end)
290 card->msg_buf_read = card->msg_buf;
291 }
292 if (card->msg_buf_write > card->msg_buf_end)
293 card->msg_buf_write = card->msg_buf;
294 restore_flags(flags);
295}
296
297/*
298 * Poll a virtual cards message queue.
299 * If there are new status-replies from the card, copy them to
300 * ringbuffer for reading on /dev/isdnctrl and call
301 * isdnloop_parse_status() for processing them. Watch for special
302 * Firmware bootmessage and parse it, to get the D-Channel protocol.
303 * If there are B-Channels open, initiate a timer-callback to
304 * isdnloop_pollbchan().
305 * This routine is called periodically via timer interrupt.
306 *
307 * Parameter:
308 * data = pointer to card struct
309 */
310static void
311isdnloop_polldchan(unsigned long data)
312{
313 isdnloop_card *card = (isdnloop_card *) data;
314 struct sk_buff *skb;
315 int avail;
316 int left;
317 u_char c;
318 int ch;
319 unsigned long flags;
320 u_char *p;
321 isdn_ctrl cmd;
322
323 if ((skb = skb_dequeue(&card->dqueue)))
324 avail = skb->len;
325 else
326 avail = 0;
327 for (left = avail; left > 0; left--) {
328 c = *skb->data;
329 skb_pull(skb, 1);
330 isdnloop_putmsg(card, c);
331 card->imsg[card->iptr] = c;
332 if (card->iptr < 59)
333 card->iptr++;
334 if (!skb->len) {
335 avail++;
336 isdnloop_putmsg(card, '\n');
337 card->imsg[card->iptr] = 0;
338 card->iptr = 0;
339 if (card->imsg[0] == '0' && card->imsg[1] >= '0' &&
340 card->imsg[1] <= '2' && card->imsg[2] == ';') {
341 ch = (card->imsg[1] - '0') - 1;
342 p = &card->imsg[3];
343 isdnloop_parse_status(p, ch, card);
344 } else {
345 p = card->imsg;
346 if (!strncmp(p, "DRV1.", 5)) {
347 printk(KERN_INFO "isdnloop: (%s) %s\n", CID, p);
348 if (!strncmp(p + 7, "TC", 2)) {
349 card->ptype = ISDN_PTYPE_1TR6;
350 card->interface.features |= ISDN_FEATURE_P_1TR6;
351 printk(KERN_INFO
352 "isdnloop: (%s) 1TR6-Protocol loaded and running\n", CID);
353 }
354 if (!strncmp(p + 7, "EC", 2)) {
355 card->ptype = ISDN_PTYPE_EURO;
356 card->interface.features |= ISDN_FEATURE_P_EURO;
357 printk(KERN_INFO
358 "isdnloop: (%s) Euro-Protocol loaded and running\n", CID);
359 }
360 continue;
361
362 }
363 }
364 }
365 }
366 if (avail) {
367 cmd.command = ISDN_STAT_STAVAIL;
368 cmd.driver = card->myid;
369 cmd.arg = avail;
370 card->interface.statcallb(&cmd);
371 }
372 if (card->flags & (ISDNLOOP_FLAGS_B1ACTIVE | ISDNLOOP_FLAGS_B2ACTIVE))
373 if (!(card->flags & ISDNLOOP_FLAGS_RBTIMER)) {
374 /* schedule b-channel polling */
375 card->flags |= ISDNLOOP_FLAGS_RBTIMER;
376 save_flags(flags);
377 cli();
378 del_timer(&card->rb_timer);
379 card->rb_timer.function = isdnloop_pollbchan;
380 card->rb_timer.data = (unsigned long) card;
381 card->rb_timer.expires = jiffies + ISDNLOOP_TIMER_BCREAD;
382 add_timer(&card->rb_timer);
383 restore_flags(flags);
384 }
385 /* schedule again */
386 save_flags(flags);
387 cli();
388 card->st_timer.expires = jiffies + ISDNLOOP_TIMER_DCREAD;
389 add_timer(&card->st_timer);
390 restore_flags(flags);
391}
392
393/*
394 * Append a packet to the transmit buffer-queue.
395 *
396 * Parameter:
397 * channel = Number of B-channel
398 * skb = packet to send.
399 * card = pointer to card-struct
400 * Return:
401 * Number of bytes transferred, -E??? on error
402 */
403static int
404isdnloop_sendbuf(int channel, struct sk_buff *skb, isdnloop_card * card)
405{
406 int len = skb->len;
407 unsigned long flags;
408 struct sk_buff *nskb;
409
410 if (len > 4000) {
411 printk(KERN_WARNING
412 "isdnloop: Send packet too large\n");
413 return -EINVAL;
414 }
415 if (len) {
416 if (!(card->flags & (channel) ? ISDNLOOP_FLAGS_B2ACTIVE : ISDNLOOP_FLAGS_B1ACTIVE))
417 return 0;
418 if (card->sndcount[channel] > ISDNLOOP_MAX_SQUEUE)
419 return 0;
420 save_flags(flags);
421 cli();
422 nskb = dev_alloc_skb(skb->len);
423 if (nskb) {
424 memcpy(skb_put(nskb, len), skb->data, len);
425 skb_queue_tail(&card->bqueue[channel], nskb);
426 dev_kfree_skb(skb);
427 } else
428 len = 0;
429 card->sndcount[channel] += len;
430 restore_flags(flags);
431 }
432 return len;
433}
434
435/*
436 * Read the messages from the card's ringbuffer
437 *
438 * Parameter:
439 * buf = pointer to buffer.
440 * len = number of bytes to read.
441 * user = flag, 1: called from userlevel 0: called from kernel.
442 * card = pointer to card struct.
443 * Return:
444 * number of bytes actually transferred.
445 */
446static int
447isdnloop_readstatus(u_char __user *buf, int len, isdnloop_card * card)
448{
449 int count;
450 u_char __user *p;
451
452 for (p = buf, count = 0; count < len; p++, count++) {
453 if (card->msg_buf_read == card->msg_buf_write)
454 return count;
455 put_user(*card->msg_buf_read++, p);
456 if (card->msg_buf_read > card->msg_buf_end)
457 card->msg_buf_read = card->msg_buf;
458 }
459 return count;
460}
461
462/*
463 * Simulate a card's response by appending it to the cards
464 * message queue.
465 *
466 * Parameter:
467 * card = pointer to card struct.
468 * s = pointer to message-string.
469 * ch = channel: 0 = generic messages, 1 and 2 = D-channel messages.
470 * Return:
471 * 0 on success, 1 on memory squeeze.
472 */
473static int
474isdnloop_fake(isdnloop_card * card, char *s, int ch)
475{
476 struct sk_buff *skb;
477 int len = strlen(s) + ((ch >= 0) ? 3 : 0);
478
479 if (!(skb = dev_alloc_skb(len))) {
480 printk(KERN_WARNING "isdnloop: Out of memory in isdnloop_fake\n");
481 return 1;
482 }
483 if (ch >= 0)
484 sprintf(skb_put(skb, 3), "%02d;", ch);
485 memcpy(skb_put(skb, strlen(s)), s, strlen(s));
486 skb_queue_tail(&card->dqueue, skb);
487 return 0;
488}
489/* *INDENT-OFF* */
490static isdnloop_stat isdnloop_cmd_table[] =
491{
492 {"BCON_R", 0, 1}, /* B-Channel connect */
493 {"BCON_I", 0, 17}, /* B-Channel connect ind */
494 {"BDIS_R", 0, 2}, /* B-Channel disconnect */
495 {"DDIS_R", 0, 3}, /* D-Channel disconnect */
496 {"DCON_R", 0, 16}, /* D-Channel connect */
497 {"DSCA_R", 0, 4}, /* Dial 1TR6-SPV */
498 {"DCAL_R", 0, 5}, /* Dial */
499 {"EAZC", 0, 6}, /* Clear EAZ listener */
500 {"EAZ", 0, 7}, /* Set EAZ listener */
501 {"SEEAZ", 0, 8}, /* Get EAZ listener */
502 {"MSN", 0, 9}, /* Set/Clear MSN listener */
503 {"MSALL", 0, 10}, /* Set multi MSN listeners */
504 {"SETSIL", 0, 11}, /* Set SI list */
505 {"SEESIL", 0, 12}, /* Get SI list */
506 {"SILC", 0, 13}, /* Clear SI list */
507 {"LOCK", 0, -1}, /* LOCK channel */
508 {"UNLOCK", 0, -1}, /* UNLOCK channel */
509 {"FV2ON", 1, 14}, /* Leased mode on */
510 {"FV2OFF", 1, 15}, /* Leased mode off */
511 {NULL, 0, -1}
512};
513/* *INDENT-ON* */
514
515
516/*
517 * Simulate an error-response from a card.
518 *
519 * Parameter:
520 * card = pointer to card struct.
521 */
522static void
523isdnloop_fake_err(isdnloop_card * card)
524{
525 char buf[60];
526
527 sprintf(buf, "E%s", card->omsg);
528 isdnloop_fake(card, buf, -1);
529 isdnloop_fake(card, "NAK", -1);
530}
531
532static u_char ctable_eu[] =
533{0x00, 0x11, 0x01, 0x12};
534static u_char ctable_1t[] =
535{0x00, 0x3b, 0x01, 0x3a};
536
537/*
538 * Assemble a simplified cause message depending on the
539 * D-channel protocol used.
540 *
541 * Parameter:
542 * card = pointer to card struct.
543 * loc = location: 0 = local, 1 = remote.
544 * cau = cause: 1 = busy, 2 = nonexistent callerid, 3 = no user responding.
545 * Return:
546 * Pointer to buffer containing the assembled message.
547 */
548static char *
549isdnloop_unicause(isdnloop_card * card, int loc, int cau)
550{
551 static char buf[6];
552
553 switch (card->ptype) {
554 case ISDN_PTYPE_EURO:
555 sprintf(buf, "E%02X%02X", (loc) ? 4 : 2, ctable_eu[cau]);
556 break;
557 case ISDN_PTYPE_1TR6:
558 sprintf(buf, "%02X44", ctable_1t[cau]);
559 break;
560 default:
561 return ("0000");
562 }
563 return (buf);
564}
565
566/*
567 * Release a virtual connection. Called from timer interrupt, when
568 * called party did not respond.
569 *
570 * Parameter:
571 * card = pointer to card struct.
572 * ch = channel (0-based)
573 */
574static void
575isdnloop_atimeout(isdnloop_card * card, int ch)
576{
577 unsigned long flags;
578 char buf[60];
579
580 save_flags(flags);
581 cli();
582 if (card->rcard) {
583 isdnloop_fake(card->rcard[ch], "DDIS_I", card->rch[ch] + 1);
584 card->rcard[ch]->rcard[card->rch[ch]] = NULL;
585 card->rcard[ch] = NULL;
586 }
587 isdnloop_fake(card, "DDIS_I", ch + 1);
588 /* No user responding */
589 sprintf(buf, "CAU%s", isdnloop_unicause(card, 1, 3));
590 isdnloop_fake(card, buf, ch + 1);
591 restore_flags(flags);
592}
593
594/*
595 * Wrapper for isdnloop_atimeout().
596 */
597static void
598isdnloop_atimeout0(unsigned long data)
599{
600 isdnloop_card *card = (isdnloop_card *) data;
601 isdnloop_atimeout(card, 0);
602}
603
604/*
605 * Wrapper for isdnloop_atimeout().
606 */
607static void
608isdnloop_atimeout1(unsigned long data)
609{
610 isdnloop_card *card = (isdnloop_card *) data;
611 isdnloop_atimeout(card, 1);
612}
613
614/*
615 * Install a watchdog for a user, not responding.
616 *
617 * Parameter:
618 * card = pointer to card struct.
619 * ch = channel to watch for.
620 */
621static void
622isdnloop_start_ctimer(isdnloop_card * card, int ch)
623{
624 unsigned long flags;
625
626 save_flags(flags);
627 cli();
628 init_timer(&card->c_timer[ch]);
629 card->c_timer[ch].expires = jiffies + ISDNLOOP_TIMER_ALERTWAIT;
630 if (ch)
631 card->c_timer[ch].function = isdnloop_atimeout1;
632 else
633 card->c_timer[ch].function = isdnloop_atimeout0;
634 card->c_timer[ch].data = (unsigned long) card;
635 add_timer(&card->c_timer[ch]);
636 restore_flags(flags);
637}
638
639/*
640 * Kill a pending channel watchdog.
641 *
642 * Parameter:
643 * card = pointer to card struct.
644 * ch = channel (0-based).
645 */
646static void
647isdnloop_kill_ctimer(isdnloop_card * card, int ch)
648{
649 unsigned long flags;
650
651 save_flags(flags);
652 cli();
653 del_timer(&card->c_timer[ch]);
654 restore_flags(flags);
655}
656
657static u_char si2bit[] =
658{0, 1, 0, 0, 0, 2, 0, 4, 0, 0};
659static u_char bit2si[] =
660{1, 5, 7};
661
662/*
663 * Try finding a listener for an outgoing call.
664 *
665 * Parameter:
666 * card = pointer to calling card.
667 * p = pointer to ICN-type setup-string.
668 * lch = channel of calling card.
669 * cmd = pointer to struct to be filled when parsing setup.
670 * Return:
671 * 0 = found match, alerting should happen.
672 * 1 = found matching number but it is busy.
673 * 2 = no matching listener.
674 * 3 = found matching number but SI does not match.
675 */
676static int
677isdnloop_try_call(isdnloop_card * card, char *p, int lch, isdn_ctrl * cmd)
678{
679 isdnloop_card *cc = cards;
680 unsigned long flags;
681 int ch;
682 int num_match;
683 int i;
684 char *e;
685 char nbuf[32];
686
687 isdnloop_parse_setup(p, cmd);
688 while (cc) {
689 for (ch = 0; ch < 2; ch++) {
690 /* Exclude ourself */
691 if ((cc == card) && (ch == lch))
692 continue;
693 num_match = 0;
694 switch (cc->ptype) {
695 case ISDN_PTYPE_EURO:
696 for (i = 0; i < 3; i++)
697 if (!(strcmp(cc->s0num[i], cmd->parm.setup.phone)))
698 num_match = 1;
699 break;
700 case ISDN_PTYPE_1TR6:
701 e = cc->eazlist[ch];
702 while (*e) {
703 sprintf(nbuf, "%s%c", cc->s0num[0], *e);
704 if (!(strcmp(nbuf, cmd->parm.setup.phone)))
705 num_match = 1;
706 e++;
707 }
708 }
709 if (num_match) {
710 save_flags(flags);
711 cli();
712 /* channel idle? */
713 if (!(cc->rcard[ch])) {
714 /* Check SI */
715 if (!(si2bit[cmd->parm.setup.si1] & cc->sil[ch])) {
716 restore_flags(flags);
717 return 3;
718 }
719 /* ch is idle, si and number matches */
720 cc->rcard[ch] = card;
721 cc->rch[ch] = lch;
722 card->rcard[lch] = cc;
723 card->rch[lch] = ch;
724 restore_flags(flags);
725 return 0;
726 } else {
727 restore_flags(flags);
728 /* num matches, but busy */
729 if (ch == 1)
730 return 1;
731 }
732 }
733 }
734 cc = cc->next;
735 }
736 return 2;
737}
738
739/*
740 * Depending on D-channel protocol and caller/called, modify
741 * phone number.
742 *
743 * Parameter:
744 * card = pointer to card struct.
745 * phone = pointer phone number.
746 * caller = flag: 1 = caller, 0 = called.
747 * Return:
748 * pointer to new phone number.
749 */
750static char *
751isdnloop_vstphone(isdnloop_card * card, char *phone, int caller)
752{
753 int i;
754 static char nphone[30];
755
756 if (!card) {
757 printk("BUG!!!\n");
758 return "";
759 }
760 switch (card->ptype) {
761 case ISDN_PTYPE_EURO:
762 if (caller) {
763 for (i = 0; i < 2; i++)
764 if (!(strcmp(card->s0num[i], phone)))
765 return (phone);
766 return (card->s0num[0]);
767 }
768 return (phone);
769 break;
770 case ISDN_PTYPE_1TR6:
771 if (caller) {
772 sprintf(nphone, "%s%c", card->s0num[0], phone[0]);
773 return (nphone);
774 } else
775 return (&phone[strlen(phone) - 1]);
776 break;
777 }
778 return "";
779}
780
781/*
782 * Parse an ICN-type command string sent to the 'card'.
783 * Perform misc. actions depending on the command.
784 *
785 * Parameter:
786 * card = pointer to card struct.
787 */
788static void
789isdnloop_parse_cmd(isdnloop_card * card)
790{
791 char *p = card->omsg;
792 isdn_ctrl cmd;
793 char buf[60];
794 isdnloop_stat *s = isdnloop_cmd_table;
795 int action = -1;
796 int i;
797 int ch;
798
799 if ((card->omsg[0] != '0') && (card->omsg[2] != ';')) {
800 isdnloop_fake_err(card);
801 return;
802 }
803 ch = card->omsg[1] - '0';
804 if ((ch < 0) || (ch > 2)) {
805 isdnloop_fake_err(card);
806 return;
807 }
808 p += 3;
809 while (s->statstr) {
810 if (!strncmp(p, s->statstr, strlen(s->statstr))) {
811 action = s->action;
812 if (s->command && (ch != 0)) {
813 isdnloop_fake_err(card);
814 return;
815 }
816 break;
817 }
818 s++;
819 }
820 if (action == -1)
821 return;
822 switch (action) {
823 case 1:
824 /* 0x;BCON_R */
825 if (card->rcard[ch - 1]) {
826 isdnloop_fake(card->rcard[ch - 1], "BCON_I",
827 card->rch[ch - 1] + 1);
828 isdnloop_fake(card, "BCON_C", ch);
829 }
830 break;
831 case 17:
832 /* 0x;BCON_I */
833 if (card->rcard[ch - 1]) {
834 isdnloop_fake(card->rcard[ch - 1], "BCON_C",
835 card->rch[ch - 1] + 1);
836 }
837 break;
838 case 2:
839 /* 0x;BDIS_R */
840 isdnloop_fake(card, "BDIS_C", ch);
841 if (card->rcard[ch - 1]) {
842 isdnloop_fake(card->rcard[ch - 1], "BDIS_I",
843 card->rch[ch - 1] + 1);
844 }
845 break;
846 case 16:
847 /* 0x;DCON_R */
848 isdnloop_kill_ctimer(card, ch - 1);
849 if (card->rcard[ch - 1]) {
850 isdnloop_kill_ctimer(card->rcard[ch - 1], card->rch[ch - 1]);
851 isdnloop_fake(card->rcard[ch - 1], "DCON_C",
852 card->rch[ch - 1] + 1);
853 isdnloop_fake(card, "DCON_C", ch);
854 }
855 break;
856 case 3:
857 /* 0x;DDIS_R */
858 isdnloop_kill_ctimer(card, ch - 1);
859 if (card->rcard[ch - 1]) {
860 isdnloop_kill_ctimer(card->rcard[ch - 1], card->rch[ch - 1]);
861 isdnloop_fake(card->rcard[ch - 1], "DDIS_I",
862 card->rch[ch - 1] + 1);
863 card->rcard[ch - 1] = NULL;
864 }
865 isdnloop_fake(card, "DDIS_C", ch);
866 break;
867 case 4:
868 /* 0x;DSCA_Rdd,yy,zz,oo */
869 if (card->ptype != ISDN_PTYPE_1TR6) {
870 isdnloop_fake_err(card);
871 return;
872 }
873 /* Fall through */
874 case 5:
875 /* 0x;DCAL_Rdd,yy,zz,oo */
876 p += 6;
877 switch (isdnloop_try_call(card, p, ch - 1, &cmd)) {
878 case 0:
879 /* Alerting */
880 sprintf(buf, "D%s_I%s,%02d,%02d,%s",
881 (action == 4) ? "SCA" : "CAL",
882 isdnloop_vstphone(card, cmd.parm.setup.eazmsn, 1),
883 cmd.parm.setup.si1,
884 cmd.parm.setup.si2,
885 isdnloop_vstphone(card->rcard[ch - 1],
886 cmd.parm.setup.phone, 0));
887 isdnloop_fake(card->rcard[ch - 1], buf, card->rch[ch - 1] + 1);
888 /* Fall through */
889 case 3:
890 /* si1 does not match, don't alert but start timer */
891 isdnloop_start_ctimer(card, ch - 1);
892 break;
893 case 1:
894 /* Remote busy */
895 isdnloop_fake(card, "DDIS_I", ch);
896 sprintf(buf, "CAU%s", isdnloop_unicause(card, 1, 1));
897 isdnloop_fake(card, buf, ch);
898 break;
899 case 2:
900 /* No such user */
901 isdnloop_fake(card, "DDIS_I", ch);
902 sprintf(buf, "CAU%s", isdnloop_unicause(card, 1, 2));
903 isdnloop_fake(card, buf, ch);
904 break;
905 }
906 break;
907 case 6:
908 /* 0x;EAZC */
909 card->eazlist[ch - 1][0] = '\0';
910 break;
911 case 7:
912 /* 0x;EAZ */
913 p += 3;
914 strcpy(card->eazlist[ch - 1], p);
915 break;
916 case 8:
917 /* 0x;SEEAZ */
918 sprintf(buf, "EAZ-LIST: %s", card->eazlist[ch - 1]);
919 isdnloop_fake(card, buf, ch + 1);
920 break;
921 case 9:
922 /* 0x;MSN */
923 break;
924 case 10:
925 /* 0x;MSNALL */
926 break;
927 case 11:
928 /* 0x;SETSIL */
929 p += 6;
930 i = 0;
931 while (strchr("0157", *p)) {
932 if (i)
933 card->sil[ch - 1] |= si2bit[*p - '0'];
934 i = (*p++ == '0');
935 }
936 if (*p)
937 isdnloop_fake_err(card);
938 break;
939 case 12:
940 /* 0x;SEESIL */
941 sprintf(buf, "SIN-LIST: ");
942 p = buf + 10;
943 for (i = 0; i < 3; i++)
944 if (card->sil[ch - 1] & (1 << i))
945 p += sprintf(p, "%02d", bit2si[i]);
946 isdnloop_fake(card, buf, ch + 1);
947 break;
948 case 13:
949 /* 0x;SILC */
950 card->sil[ch - 1] = 0;
951 break;
952 case 14:
953 /* 00;FV2ON */
954 break;
955 case 15:
956 /* 00;FV2OFF */
957 break;
958 }
959}
960
961/*
962 * Put command-strings into the of the 'card'. In reality, execute them
963 * right in place by calling isdnloop_parse_cmd(). Also copy every
964 * command to the read message ringbuffer, preceeding it with a '>'.
965 * These mesagges can be read at /dev/isdnctrl.
966 *
967 * Parameter:
968 * buf = pointer to command buffer.
969 * len = length of buffer data.
970 * user = flag: 1 = called form userlevel, 0 called from kernel.
971 * card = pointer to card struct.
972 * Return:
973 * number of bytes transferred (currently always equals len).
974 */
975static int
976isdnloop_writecmd(const u_char * buf, int len, int user, isdnloop_card * card)
977{
978 int xcount = 0;
979 int ocount = 1;
980 isdn_ctrl cmd;
981
982 while (len) {
983 int count = len;
984 u_char *p;
985 u_char msg[0x100];
986
987 if (count > 255)
988 count = 255;
989 if (user) {
990 if (copy_from_user(msg, buf, count))
991 return -EFAULT;
992 } else
993 memcpy(msg, buf, count);
994 isdnloop_putmsg(card, '>');
995 for (p = msg; count > 0; count--, p++) {
996 len--;
997 xcount++;
998 isdnloop_putmsg(card, *p);
999 card->omsg[card->optr] = *p;
1000 if (*p == '\n') {
1001 card->omsg[card->optr] = '\0';
1002 card->optr = 0;
1003 isdnloop_parse_cmd(card);
1004 if (len) {
1005 isdnloop_putmsg(card, '>');
1006 ocount++;
1007 }
1008 } else {
1009 if (card->optr < 59)
1010 card->optr++;
1011 }
1012 ocount++;
1013 }
1014 }
1015 cmd.command = ISDN_STAT_STAVAIL;
1016 cmd.driver = card->myid;
1017 cmd.arg = ocount;
1018 card->interface.statcallb(&cmd);
1019 return xcount;
1020}
1021
1022/*
1023 * Delete card's pending timers, send STOP to linklevel
1024 */
1025static void
1026isdnloop_stopcard(isdnloop_card * card)
1027{
1028 unsigned long flags;
1029 isdn_ctrl cmd;
1030
1031 save_flags(flags);
1032 cli();
1033 if (card->flags & ISDNLOOP_FLAGS_RUNNING) {
1034 card->flags &= ~ISDNLOOP_FLAGS_RUNNING;
1035 del_timer(&card->st_timer);
1036 del_timer(&card->rb_timer);
1037 del_timer(&card->c_timer[0]);
1038 del_timer(&card->c_timer[1]);
1039 cmd.command = ISDN_STAT_STOP;
1040 cmd.driver = card->myid;
1041 card->interface.statcallb(&cmd);
1042 }
1043 restore_flags(flags);
1044}
1045
1046/*
1047 * Stop all cards before unload.
1048 */
1049static void
1050isdnloop_stopallcards(void)
1051{
1052 isdnloop_card *p = cards;
1053
1054 while (p) {
1055 isdnloop_stopcard(p);
1056 p = p->next;
1057 }
1058}
1059
1060/*
1061 * Start a 'card'. Simulate card's boot message and set the phone
1062 * number(s) of the virtual 'S0-Interface'. Install D-channel
1063 * poll timer.
1064 *
1065 * Parameter:
1066 * card = pointer to card struct.
1067 * sdefp = pointer to struct holding ioctl parameters.
1068 * Return:
1069 * 0 on success, -E??? otherwise.
1070 */
1071static int
1072isdnloop_start(isdnloop_card * card, isdnloop_sdef * sdefp)
1073{
1074 unsigned long flags;
1075 isdnloop_sdef sdef;
1076 int i;
1077
1078 if (card->flags & ISDNLOOP_FLAGS_RUNNING)
1079 return -EBUSY;
1080 if (copy_from_user((char *) &sdef, (char *) sdefp, sizeof(sdef)))
1081 return -EFAULT;
1082 save_flags(flags);
1083 cli();
1084 switch (sdef.ptype) {
1085 case ISDN_PTYPE_EURO:
1086 if (isdnloop_fake(card, "DRV1.23EC-Q.931-CAPI-CNS-BASIS-20.02.96",
1087 -1)) {
1088 restore_flags(flags);
1089 return -ENOMEM;
1090 }
1091 card->sil[0] = card->sil[1] = 4;
1092 if (isdnloop_fake(card, "TEI OK", 0)) {
1093 restore_flags(flags);
1094 return -ENOMEM;
1095 }
1096 for (i = 0; i < 3; i++)
1097 strcpy(card->s0num[i], sdef.num[i]);
1098 break;
1099 case ISDN_PTYPE_1TR6:
1100 if (isdnloop_fake(card, "DRV1.04TC-1TR6-CAPI-CNS-BASIS-29.11.95",
1101 -1)) {
1102 restore_flags(flags);
1103 return -ENOMEM;
1104 }
1105 card->sil[0] = card->sil[1] = 4;
1106 if (isdnloop_fake(card, "TEI OK", 0)) {
1107 restore_flags(flags);
1108 return -ENOMEM;
1109 }
1110 strcpy(card->s0num[0], sdef.num[0]);
1111 card->s0num[1][0] = '\0';
1112 card->s0num[2][0] = '\0';
1113 break;
1114 default:
1115 restore_flags(flags);
1116 printk(KERN_WARNING "isdnloop: Illegal D-channel protocol %d\n",
1117 sdef.ptype);
1118 return -EINVAL;
1119 }
1120 init_timer(&card->st_timer);
1121 card->st_timer.expires = jiffies + ISDNLOOP_TIMER_DCREAD;
1122 card->st_timer.function = isdnloop_polldchan;
1123 card->st_timer.data = (unsigned long) card;
1124 add_timer(&card->st_timer);
1125 card->flags |= ISDNLOOP_FLAGS_RUNNING;
1126 restore_flags(flags);
1127 return 0;
1128}
1129
1130/*
1131 * Main handler for commands sent by linklevel.
1132 */
1133static int
1134isdnloop_command(isdn_ctrl * c, isdnloop_card * card)
1135{
1136 ulong a;
1137 int i;
1138 char cbuf[60];
1139 isdn_ctrl cmd;
1140 isdnloop_cdef cdef;
1141
1142 switch (c->command) {
1143 case ISDN_CMD_IOCTL:
1144 memcpy(&a, c->parm.num, sizeof(ulong));
1145 switch (c->arg) {
1146 case ISDNLOOP_IOCTL_DEBUGVAR:
1147 return (ulong) card;
1148 case ISDNLOOP_IOCTL_STARTUP:
1149 if (!access_ok(VERIFY_READ, (void *) a, sizeof(isdnloop_sdef)))
1150 return -EFAULT;
1151 return (isdnloop_start(card, (isdnloop_sdef *) a));
1152 break;
1153 case ISDNLOOP_IOCTL_ADDCARD:
1154 if (copy_from_user((char *)&cdef,
1155 (char *)a,
1156 sizeof(cdef)))
1157 return -EFAULT;
1158 return (isdnloop_addcard(cdef.id1));
1159 break;
1160 case ISDNLOOP_IOCTL_LEASEDCFG:
1161 if (a) {
1162 if (!card->leased) {
1163 card->leased = 1;
1164 while (card->ptype == ISDN_PTYPE_UNKNOWN) {
1165 set_current_state(TASK_INTERRUPTIBLE);
1166 schedule_timeout(10);
1167 }
1168 set_current_state(TASK_INTERRUPTIBLE);
1169 schedule_timeout(10);
1170 sprintf(cbuf, "00;FV2ON\n01;EAZ1\n02;EAZ2\n");
1171 i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);
1172 printk(KERN_INFO
1173 "isdnloop: (%s) Leased-line mode enabled\n",
1174 CID);
1175 cmd.command = ISDN_STAT_RUN;
1176 cmd.driver = card->myid;
1177 cmd.arg = 0;
1178 card->interface.statcallb(&cmd);
1179 }
1180 } else {
1181 if (card->leased) {
1182 card->leased = 0;
1183 sprintf(cbuf, "00;FV2OFF\n");
1184 i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);
1185 printk(KERN_INFO
1186 "isdnloop: (%s) Leased-line mode disabled\n",
1187 CID);
1188 cmd.command = ISDN_STAT_RUN;
1189 cmd.driver = card->myid;
1190 cmd.arg = 0;
1191 card->interface.statcallb(&cmd);
1192 }
1193 }
1194 return 0;
1195 default:
1196 return -EINVAL;
1197 }
1198 break;
1199 case ISDN_CMD_DIAL:
1200 if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
1201 return -ENODEV;
1202 if (card->leased)
1203 break;
1204 if ((c->arg & 255) < ISDNLOOP_BCH) {
1205 char *p;
1206 char dial[50];
1207 char dcode[4];
1208
1209 a = c->arg;
1210 p = c->parm.setup.phone;
1211 if (*p == 's' || *p == 'S') {
1212 /* Dial for SPV */
1213 p++;
1214 strcpy(dcode, "SCA");
1215 } else
1216 /* Normal Dial */
1217 strcpy(dcode, "CAL");
1218 strcpy(dial, p);
1219 sprintf(cbuf, "%02d;D%s_R%s,%02d,%02d,%s\n", (int) (a + 1),
1220 dcode, dial, c->parm.setup.si1,
1221 c->parm.setup.si2, c->parm.setup.eazmsn);
1222 i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);
1223 }
1224 break;
1225 case ISDN_CMD_ACCEPTD:
1226 if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
1227 return -ENODEV;
1228 if (c->arg < ISDNLOOP_BCH) {
1229 a = c->arg + 1;
1230 cbuf[0] = 0;
1231 switch (card->l2_proto[a - 1]) {
1232 case ISDN_PROTO_L2_X75I:
1233 sprintf(cbuf, "%02d;BX75\n", (int) a);
1234 break;
1235#ifdef CONFIG_ISDN_X25
1236 case ISDN_PROTO_L2_X25DTE:
1237 sprintf(cbuf, "%02d;BX2T\n", (int) a);
1238 break;
1239 case ISDN_PROTO_L2_X25DCE:
1240 sprintf(cbuf, "%02d;BX2C\n", (int) a);
1241 break;
1242#endif
1243 case ISDN_PROTO_L2_HDLC:
1244 sprintf(cbuf, "%02d;BTRA\n", (int) a);
1245 break;
1246 }
1247 if (strlen(cbuf))
1248 i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);
1249 sprintf(cbuf, "%02d;DCON_R\n", (int) a);
1250 i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);
1251 }
1252 break;
1253 case ISDN_CMD_ACCEPTB:
1254 if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
1255 return -ENODEV;
1256 if (c->arg < ISDNLOOP_BCH) {
1257 a = c->arg + 1;
1258 switch (card->l2_proto[a - 1]) {
1259 case ISDN_PROTO_L2_X75I:
1260 sprintf(cbuf, "%02d;BCON_R,BX75\n", (int) a);
1261 break;
1262#ifdef CONFIG_ISDN_X25
1263 case ISDN_PROTO_L2_X25DTE:
1264 sprintf(cbuf, "%02d;BCON_R,BX2T\n", (int) a);
1265 break;
1266 case ISDN_PROTO_L2_X25DCE:
1267 sprintf(cbuf, "%02d;BCON_R,BX2C\n", (int) a);
1268 break;
1269#endif
1270 case ISDN_PROTO_L2_HDLC:
1271 sprintf(cbuf, "%02d;BCON_R,BTRA\n", (int) a);
1272 break;
1273 default:
1274 sprintf(cbuf, "%02d;BCON_R\n", (int) a);
1275 }
1276 printk(KERN_DEBUG "isdnloop writecmd '%s'\n", cbuf);
1277 i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);
1278 break;
1279 case ISDN_CMD_HANGUP:
1280 if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
1281 return -ENODEV;
1282 if (c->arg < ISDNLOOP_BCH) {
1283 a = c->arg + 1;
1284 sprintf(cbuf, "%02d;BDIS_R\n%02d;DDIS_R\n", (int) a, (int) a);
1285 i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);
1286 }
1287 break;
1288 case ISDN_CMD_SETEAZ:
1289 if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
1290 return -ENODEV;
1291 if (card->leased)
1292 break;
1293 if (c->arg < ISDNLOOP_BCH) {
1294 a = c->arg + 1;
1295 if (card->ptype == ISDN_PTYPE_EURO) {
1296 sprintf(cbuf, "%02d;MS%s%s\n", (int) a,
1297 c->parm.num[0] ? "N" : "ALL", c->parm.num);
1298 } else
1299 sprintf(cbuf, "%02d;EAZ%s\n", (int) a,
1300 c->parm.num[0] ? c->parm.num : (u_char *) "0123456789");
1301 i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);
1302 }
1303 break;
1304 case ISDN_CMD_CLREAZ:
1305 if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
1306 return -ENODEV;
1307 if (card->leased)
1308 break;
1309 if (c->arg < ISDNLOOP_BCH) {
1310 a = c->arg + 1;
1311 if (card->ptype == ISDN_PTYPE_EURO)
1312 sprintf(cbuf, "%02d;MSNC\n", (int) a);
1313 else
1314 sprintf(cbuf, "%02d;EAZC\n", (int) a);
1315 i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);
1316 }
1317 break;
1318 case ISDN_CMD_SETL2:
1319 if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
1320 return -ENODEV;
1321 if ((c->arg & 255) < ISDNLOOP_BCH) {
1322 a = c->arg;
1323 switch (a >> 8) {
1324 case ISDN_PROTO_L2_X75I:
1325 sprintf(cbuf, "%02d;BX75\n", (int) (a & 255) + 1);
1326 break;
1327#ifdef CONFIG_ISDN_X25
1328 case ISDN_PROTO_L2_X25DTE:
1329 sprintf(cbuf, "%02d;BX2T\n", (int) (a & 255) + 1);
1330 break;
1331 case ISDN_PROTO_L2_X25DCE:
1332 sprintf(cbuf, "%02d;BX2C\n", (int) (a & 255) + 1);
1333 break;
1334#endif
1335 case ISDN_PROTO_L2_HDLC:
1336 sprintf(cbuf, "%02d;BTRA\n", (int) (a & 255) + 1);
1337 break;
1338 case ISDN_PROTO_L2_TRANS:
1339 sprintf(cbuf, "%02d;BTRA\n", (int) (a & 255) + 1);
1340 break;
1341 default:
1342 return -EINVAL;
1343 }
1344 i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);
1345 card->l2_proto[a & 255] = (a >> 8);
1346 }
1347 break;
1348 case ISDN_CMD_SETL3:
1349 if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
1350 return -ENODEV;
1351 return 0;
1352 default:
1353 return -EINVAL;
1354 }
1355 }
1356 return 0;
1357}
1358
1359/*
1360 * Find card with given driverId
1361 */
1362static inline isdnloop_card *
1363isdnloop_findcard(int driverid)
1364{
1365 isdnloop_card *p = cards;
1366
1367 while (p) {
1368 if (p->myid == driverid)
1369 return p;
1370 p = p->next;
1371 }
1372 return (isdnloop_card *) 0;
1373}
1374
1375/*
1376 * Wrapper functions for interface to linklevel
1377 */
1378static int
1379if_command(isdn_ctrl * c)
1380{
1381 isdnloop_card *card = isdnloop_findcard(c->driver);
1382
1383 if (card)
1384 return (isdnloop_command(c, card));
1385 printk(KERN_ERR
1386 "isdnloop: if_command called with invalid driverId!\n");
1387 return -ENODEV;
1388}
1389
1390static int
1391if_writecmd(const u_char __user *buf, int len, int id, int channel)
1392{
1393 isdnloop_card *card = isdnloop_findcard(id);
1394
1395 if (card) {
1396 if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
1397 return -ENODEV;
1398 return (isdnloop_writecmd(buf, len, 1, card));
1399 }
1400 printk(KERN_ERR
1401 "isdnloop: if_writecmd called with invalid driverId!\n");
1402 return -ENODEV;
1403}
1404
1405static int
1406if_readstatus(u_char __user *buf, int len, int id, int channel)
1407{
1408 isdnloop_card *card = isdnloop_findcard(id);
1409
1410 if (card) {
1411 if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
1412 return -ENODEV;
1413 return (isdnloop_readstatus(buf, len, card));
1414 }
1415 printk(KERN_ERR
1416 "isdnloop: if_readstatus called with invalid driverId!\n");
1417 return -ENODEV;
1418}
1419
1420static int
1421if_sendbuf(int id, int channel, int ack, struct sk_buff *skb)
1422{
1423 isdnloop_card *card = isdnloop_findcard(id);
1424
1425 if (card) {
1426 if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
1427 return -ENODEV;
1428 /* ack request stored in skb scratch area */
1429 *(skb->head) = ack;
1430 return (isdnloop_sendbuf(channel, skb, card));
1431 }
1432 printk(KERN_ERR
1433 "isdnloop: if_sendbuf called with invalid driverId!\n");
1434 return -ENODEV;
1435}
1436
1437/*
1438 * Allocate a new card-struct, initialize it
1439 * link it into cards-list and register it at linklevel.
1440 */
1441static isdnloop_card *
1442isdnloop_initcard(char *id)
1443{
1444 isdnloop_card *card;
1445 int i;
1446
1447 if (!(card = (isdnloop_card *) kmalloc(sizeof(isdnloop_card), GFP_KERNEL))) {
1448 printk(KERN_WARNING
1449 "isdnloop: (%s) Could not allocate card-struct.\n", id);
1450 return (isdnloop_card *) 0;
1451 }
1452 memset((char *) card, 0, sizeof(isdnloop_card));
1453 card->interface.owner = THIS_MODULE;
1454 card->interface.channels = ISDNLOOP_BCH;
1455 card->interface.hl_hdrlen = 1; /* scratch area for storing ack flag*/
1456 card->interface.maxbufsize = 4000;
1457 card->interface.command = if_command;
1458 card->interface.writebuf_skb = if_sendbuf;
1459 card->interface.writecmd = if_writecmd;
1460 card->interface.readstat = if_readstatus;
1461 card->interface.features = ISDN_FEATURE_L2_X75I |
1462#ifdef CONFIG_ISDN_X25
1463 ISDN_FEATURE_L2_X25DTE |
1464 ISDN_FEATURE_L2_X25DCE |
1465#endif
1466 ISDN_FEATURE_L2_HDLC |
1467 ISDN_FEATURE_L3_TRANS |
1468 ISDN_FEATURE_P_UNKNOWN;
1469 card->ptype = ISDN_PTYPE_UNKNOWN;
1470 strlcpy(card->interface.id, id, sizeof(card->interface.id));
1471 card->msg_buf_write = card->msg_buf;
1472 card->msg_buf_read = card->msg_buf;
1473 card->msg_buf_end = &card->msg_buf[sizeof(card->msg_buf) - 1];
1474 for (i = 0; i < ISDNLOOP_BCH; i++) {
1475 card->l2_proto[i] = ISDN_PROTO_L2_X75I;
1476 skb_queue_head_init(&card->bqueue[i]);
1477 }
1478 skb_queue_head_init(&card->dqueue);
1479 card->next = cards;
1480 cards = card;
1481 if (!register_isdn(&card->interface)) {
1482 cards = cards->next;
1483 printk(KERN_WARNING
1484 "isdnloop: Unable to register %s\n", id);
1485 kfree(card);
1486 return (isdnloop_card *) 0;
1487 }
1488 card->myid = card->interface.channels;
1489 return card;
1490}
1491
1492static int
1493isdnloop_addcard(char *id1)
1494{
1495 isdnloop_card *card;
1496
1497 if (!(card = isdnloop_initcard(id1))) {
1498 return -EIO;
1499 }
1500 printk(KERN_INFO
1501 "isdnloop: (%s) virtual card added\n",
1502 card->interface.id);
1503 return 0;
1504}
1505
1506static int __init
1507isdnloop_init(void)
1508{
1509 char *p;
1510 char rev[10];
1511
1512 if ((p = strchr(revision, ':'))) {
1513 strcpy(rev, p + 1);
1514 p = strchr(rev, '$');
1515 *p = 0;
1516 } else
1517 strcpy(rev, " ??? ");
1518 printk(KERN_NOTICE "isdnloop-ISDN-driver Rev%s\n", rev);
1519
1520 if (isdnloop_id)
1521 return (isdnloop_addcard(isdnloop_id));
1522
1523 return 0;
1524}
1525
1526static void __exit
1527isdnloop_exit(void)
1528{
1529 isdn_ctrl cmd;
1530 isdnloop_card *card = cards;
1531 isdnloop_card *last;
1532 int i;
1533
1534 isdnloop_stopallcards();
1535 while (card) {
1536 cmd.command = ISDN_STAT_UNLOAD;
1537 cmd.driver = card->myid;
1538 card->interface.statcallb(&cmd);
1539 for (i = 0; i < ISDNLOOP_BCH; i++)
1540 isdnloop_free_queue(card, i);
1541 card = card->next;
1542 }
1543 card = cards;
1544 while (card) {
1545 last = card;
1546 skb_queue_purge(&card->dqueue);
1547 card = card->next;
1548 kfree(last);
1549 }
1550 printk(KERN_NOTICE "isdnloop-ISDN-driver unloaded\n");
1551}
1552
1553module_init(isdnloop_init);
1554module_exit(isdnloop_exit);
diff --git a/drivers/isdn/isdnloop/isdnloop.h b/drivers/isdn/isdnloop/isdnloop.h
new file mode 100644
index 000000000000..8fb7bc1bfe0f
--- /dev/null
+++ b/drivers/isdn/isdnloop/isdnloop.h
@@ -0,0 +1,112 @@
1/* $Id: isdnloop.h,v 1.5.6.3 2001/09/23 22:24:56 kai Exp $
2 *
3 * Loopback lowlevel module for testing of linklevel.
4 *
5 * Copyright 1997 by Fritz Elfert (fritz@isdn4linux.de)
6 *
7 * This software may be used and distributed according to the terms
8 * of the GNU General Public License, incorporated herein by reference.
9 *
10 */
11
12#ifndef isdnloop_h
13#define isdnloop_h
14
15#define ISDNLOOP_IOCTL_DEBUGVAR 0
16#define ISDNLOOP_IOCTL_ADDCARD 1
17#define ISDNLOOP_IOCTL_LEASEDCFG 2
18#define ISDNLOOP_IOCTL_STARTUP 3
19
20/* Struct for adding new cards */
21typedef struct isdnloop_cdef {
22 char id1[10];
23} isdnloop_cdef;
24
25/* Struct for configuring cards */
26typedef struct isdnloop_sdef {
27 int ptype;
28 char num[3][20];
29} isdnloop_sdef;
30
31#if defined(__KERNEL__) || defined(__DEBUGVAR__)
32
33#ifdef __KERNEL__
34/* Kernel includes */
35
36#include <linux/version.h>
37#include <linux/errno.h>
38#include <linux/fs.h>
39#include <linux/major.h>
40#include <asm/io.h>
41#include <linux/kernel.h>
42#include <linux/signal.h>
43#include <linux/slab.h>
44#include <linux/mm.h>
45#include <linux/mman.h>
46#include <linux/ioport.h>
47#include <linux/timer.h>
48#include <linux/wait.h>
49#include <linux/isdnif.h>
50
51#endif /* __KERNEL__ */
52
53#define ISDNLOOP_FLAGS_B1ACTIVE 1 /* B-Channel-1 is open */
54#define ISDNLOOP_FLAGS_B2ACTIVE 2 /* B-Channel-2 is open */
55#define ISDNLOOP_FLAGS_RUNNING 4 /* Cards driver activated */
56#define ISDNLOOP_FLAGS_RBTIMER 8 /* scheduling of B-Channel-poll */
57#define ISDNLOOP_TIMER_BCREAD 1 /* B-Channel poll-cycle */
58#define ISDNLOOP_TIMER_DCREAD (HZ/2) /* D-Channel poll-cycle */
59#define ISDNLOOP_TIMER_ALERTWAIT (10*HZ) /* Alert timeout */
60#define ISDNLOOP_MAX_SQUEUE 65536 /* Max. outstanding send-data */
61#define ISDNLOOP_BCH 2 /* channels per card */
62
63/*
64 * Per card driver data
65 */
66typedef struct isdnloop_card {
67 struct isdnloop_card *next; /* Pointer to next device struct */
68 struct isdnloop_card
69 *rcard[ISDNLOOP_BCH]; /* Pointer to 'remote' card */
70 int rch[ISDNLOOP_BCH]; /* 'remote' channel */
71 int myid; /* Driver-Nr. assigned by linklevel */
72 int leased; /* Flag: This Adapter is connected */
73 /* to a leased line */
74 int sil[ISDNLOOP_BCH]; /* SI's to listen for */
75 char eazlist[ISDNLOOP_BCH][11];
76 /* EAZ's to listen for */
77 char s0num[3][20]; /* 1TR6 base-number or MSN's */
78 unsigned short flags; /* Statusflags */
79 int ptype; /* Protocol type (1TR6 or Euro) */
80 struct timer_list st_timer; /* Timer for Status-Polls */
81 struct timer_list rb_timer; /* Timer for B-Channel-Polls */
82 struct timer_list
83 c_timer[ISDNLOOP_BCH]; /* Timer for Alerting */
84 int l2_proto[ISDNLOOP_BCH]; /* Current layer-2-protocol */
85 isdn_if interface; /* Interface to upper layer */
86 int iptr; /* Index to imsg-buffer */
87 char imsg[60]; /* Internal buf for status-parsing */
88 int optr; /* Index to omsg-buffer */
89 char omsg[60]; /* Internal buf for cmd-parsing */
90 char msg_buf[2048]; /* Buffer for status-messages */
91 char *msg_buf_write; /* Writepointer for statusbuffer */
92 char *msg_buf_read; /* Readpointer for statusbuffer */
93 char *msg_buf_end; /* Pointer to end of statusbuffer */
94 int sndcount[ISDNLOOP_BCH]; /* Byte-counters for B-Ch.-send */
95 struct sk_buff_head
96 bqueue[ISDNLOOP_BCH]; /* B-Channel queues */
97 struct sk_buff_head dqueue; /* D-Channel queue */
98} isdnloop_card;
99
100/*
101 * Main driver data
102 */
103#ifdef __KERNEL__
104static isdnloop_card *cards = (isdnloop_card *) 0;
105#endif /* __KERNEL__ */
106
107/* Utility-Macros */
108
109#define CID (card->interface.id)
110
111#endif /* defined(__KERNEL__) || defined(__DEBUGVAR__) */
112#endif /* isdnloop_h */
diff --git a/drivers/isdn/pcbit/Kconfig b/drivers/isdn/pcbit/Kconfig
new file mode 100644
index 000000000000..f06997faef16
--- /dev/null
+++ b/drivers/isdn/pcbit/Kconfig
@@ -0,0 +1,14 @@
1#
2# Config.in for PCBIT ISDN driver
3#
4config ISDN_DRV_PCBIT
5 tristate "PCBIT-D support"
6 depends on ISDN_I4L && ISA && (BROKEN || !PPC)
7 help
8 This enables support for the PCBIT ISDN-card. This card is
9 manufactured in Portugal by Octal. For running this card,
10 additional firmware is necessary, which has to be downloaded into
11 the card using a utility which is distributed separately. See
12 <file:Documentation/isdn/README> and
13 <file:Documentation/isdn/README.pcbit> for more information.
14
diff --git a/drivers/isdn/pcbit/Makefile b/drivers/isdn/pcbit/Makefile
new file mode 100644
index 000000000000..2d026c3242e8
--- /dev/null
+++ b/drivers/isdn/pcbit/Makefile
@@ -0,0 +1,9 @@
1# Makefile for the pcbit ISDN device driver
2
3# Each configuration option enables a list of files.
4
5obj-$(CONFIG_ISDN_DRV_PCBIT) += pcbit.o
6
7# Multipart objects.
8
9pcbit-y := module.o edss1.o drv.o layer2.o capi.o callbacks.o
diff --git a/drivers/isdn/pcbit/callbacks.c b/drivers/isdn/pcbit/callbacks.c
new file mode 100644
index 000000000000..692ec72d1ee8
--- /dev/null
+++ b/drivers/isdn/pcbit/callbacks.c
@@ -0,0 +1,367 @@
1/*
2 * Callbacks for the FSM
3 *
4 * Copyright (C) 1996 Universidade de Lisboa
5 *
6 * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
7 *
8 * This software may be used and distributed according to the terms of
9 * the GNU General Public License, incorporated herein by reference.
10 */
11
12/*
13 * Fix: 19981230 - Carlos Morgado <chbm@techie.com>
14 * Port of Nelson Escravana's <nelson.escravana@usa.net> fix to CalledPN
15 * NULL pointer dereference in cb_in_1 (originally fixed in 2.0)
16 */
17
18#include <linux/sched.h>
19#include <linux/string.h>
20#include <linux/kernel.h>
21
22#include <linux/types.h>
23#include <linux/slab.h>
24#include <linux/mm.h>
25#include <linux/skbuff.h>
26
27#include <asm/io.h>
28
29#include <linux/isdnif.h>
30
31#include "pcbit.h"
32#include "layer2.h"
33#include "edss1.h"
34#include "callbacks.h"
35#include "capi.h"
36
37ushort last_ref_num = 1;
38
39/*
40 * send_conn_req
41 *
42 */
43
44void cb_out_1(struct pcbit_dev * dev, struct pcbit_chan* chan,
45 struct callb_data *cbdata)
46{
47 struct sk_buff *skb;
48 int len;
49 ushort refnum;
50
51
52#ifdef DEBUG
53 printk(KERN_DEBUG "Called Party Number: %s\n",
54 cbdata->data.setup.CalledPN);
55#endif
56 /*
57 * hdr - kmalloc in capi_conn_req
58 * - kfree when msg has been sent
59 */
60
61 if ((len = capi_conn_req(cbdata->data.setup.CalledPN, &skb,
62 chan->proto)) < 0)
63 {
64 printk("capi_conn_req failed\n");
65 return;
66 }
67
68
69 refnum = last_ref_num++ & 0x7fffU;
70
71 chan->callref = 0;
72 chan->layer2link = 0;
73 chan->snum = 0;
74 chan->s_refnum = refnum;
75
76 pcbit_l2_write(dev, MSG_CONN_REQ, refnum, skb, len);
77}
78
79/*
80 * rcv CONNECT
81 * will go into ACTIVE state
82 * send CONN_ACTIVE_RESP
83 * send Select protocol request
84 */
85
86void cb_out_2(struct pcbit_dev * dev, struct pcbit_chan* chan,
87 struct callb_data *data)
88{
89 isdn_ctrl ictl;
90 struct sk_buff *skb;
91 int len;
92 ushort refnum;
93
94 if ((len=capi_conn_active_resp(chan, &skb)) < 0)
95 {
96 printk("capi_conn_active_req failed\n");
97 return;
98 }
99
100 refnum = last_ref_num++ & 0x7fffU;
101 chan->s_refnum = refnum;
102
103 pcbit_l2_write(dev, MSG_CONN_ACTV_RESP, refnum, skb, len);
104
105
106 ictl.command = ISDN_STAT_DCONN;
107 ictl.driver=dev->id;
108 ictl.arg=chan->id;
109 dev->dev_if->statcallb(&ictl);
110
111 /* ACTIVE D-channel */
112
113 /* Select protocol */
114
115 if ((len=capi_select_proto_req(chan, &skb, 1 /*outgoing*/)) < 0) {
116 printk("capi_select_proto_req failed\n");
117 return;
118 }
119
120 refnum = last_ref_num++ & 0x7fffU;
121 chan->s_refnum = refnum;
122
123 pcbit_l2_write(dev, MSG_SELP_REQ, refnum, skb, len);
124}
125
126
127/*
128 * Disconnect received (actually RELEASE COMPLETE)
129 * This means we were not able to establish connection with remote
130 * Inform the big boss above
131 */
132void cb_out_3(struct pcbit_dev * dev, struct pcbit_chan* chan,
133 struct callb_data *data)
134{
135 isdn_ctrl ictl;
136
137 ictl.command = ISDN_STAT_DHUP;
138 ictl.driver=dev->id;
139 ictl.arg=chan->id;
140 dev->dev_if->statcallb(&ictl);
141}
142
143
144/*
145 * Incoming call received
146 * inform user
147 */
148
149void cb_in_1(struct pcbit_dev * dev, struct pcbit_chan* chan,
150 struct callb_data *cbdata)
151{
152 isdn_ctrl ictl;
153 unsigned short refnum;
154 struct sk_buff *skb;
155 int len;
156
157
158 ictl.command = ISDN_STAT_ICALL;
159 ictl.driver=dev->id;
160 ictl.arg=chan->id;
161
162 /*
163 * ictl.num >= strlen() + strlen() + 5
164 */
165
166 if (cbdata->data.setup.CallingPN == NULL) {
167 printk(KERN_DEBUG "NULL CallingPN to phone; using 0\n");
168 strcpy(ictl.parm.setup.phone, "0");
169 }
170 else {
171 strcpy(ictl.parm.setup.phone, cbdata->data.setup.CallingPN);
172 }
173 if (cbdata->data.setup.CalledPN == NULL) {
174 printk(KERN_DEBUG "NULL CalledPN to eazmsn; using 0\n");
175 strcpy(ictl.parm.setup.eazmsn, "0");
176 }
177 else {
178 strcpy(ictl.parm.setup.eazmsn, cbdata->data.setup.CalledPN);
179 }
180 ictl.parm.setup.si1 = 7;
181 ictl.parm.setup.si2 = 0;
182 ictl.parm.setup.plan = 0;
183 ictl.parm.setup.screen = 0;
184
185#ifdef DEBUG
186 printk(KERN_DEBUG "statstr: %s\n", ictl.num);
187#endif
188
189 dev->dev_if->statcallb(&ictl);
190
191
192 if ((len=capi_conn_resp(chan, &skb)) < 0) {
193 printk(KERN_DEBUG "capi_conn_resp failed\n");
194 return;
195 }
196
197 refnum = last_ref_num++ & 0x7fffU;
198 chan->s_refnum = refnum;
199
200 pcbit_l2_write(dev, MSG_CONN_RESP, refnum, skb, len);
201}
202
203/*
204 * user has replied
205 * open the channel
206 * send CONNECT message CONNECT_ACTIVE_REQ in CAPI
207 */
208
209void cb_in_2(struct pcbit_dev * dev, struct pcbit_chan* chan,
210 struct callb_data *data)
211{
212 unsigned short refnum;
213 struct sk_buff *skb;
214 int len;
215
216 if ((len = capi_conn_active_req(chan, &skb)) < 0) {
217 printk(KERN_DEBUG "capi_conn_active_req failed\n");
218 return;
219 }
220
221
222 refnum = last_ref_num++ & 0x7fffU;
223 chan->s_refnum = refnum;
224
225 printk(KERN_DEBUG "sending MSG_CONN_ACTV_REQ\n");
226 pcbit_l2_write(dev, MSG_CONN_ACTV_REQ, refnum, skb, len);
227}
228
229/*
230 * CONN_ACK arrived
231 * start b-proto selection
232 *
233 */
234
235void cb_in_3(struct pcbit_dev * dev, struct pcbit_chan* chan,
236 struct callb_data *data)
237{
238 unsigned short refnum;
239 struct sk_buff *skb;
240 int len;
241
242 if ((len = capi_select_proto_req(chan, &skb, 0 /*incoming*/)) < 0)
243 {
244 printk("capi_select_proto_req failed\n");
245 return;
246 }
247
248 refnum = last_ref_num++ & 0x7fffU;
249 chan->s_refnum = refnum;
250
251 pcbit_l2_write(dev, MSG_SELP_REQ, refnum, skb, len);
252
253}
254
255
256/*
257 * Received disconnect ind on active state
258 * send disconnect resp
259 * send msg to user
260 */
261void cb_disc_1(struct pcbit_dev * dev, struct pcbit_chan* chan,
262 struct callb_data *data)
263{
264 struct sk_buff *skb;
265 int len;
266 ushort refnum;
267 isdn_ctrl ictl;
268
269 if ((len = capi_disc_resp(chan, &skb)) < 0) {
270 printk("capi_disc_resp failed\n");
271 return;
272 }
273
274 refnum = last_ref_num++ & 0x7fffU;
275 chan->s_refnum = refnum;
276
277 pcbit_l2_write(dev, MSG_DISC_RESP, refnum, skb, len);
278
279 ictl.command = ISDN_STAT_BHUP;
280 ictl.driver=dev->id;
281 ictl.arg=chan->id;
282 dev->dev_if->statcallb(&ictl);
283}
284
285
286/*
287 * User HANGUP on active/call proceeding state
288 * send disc.req
289 */
290void cb_disc_2(struct pcbit_dev * dev, struct pcbit_chan* chan,
291 struct callb_data *data)
292{
293 struct sk_buff *skb;
294 int len;
295 ushort refnum;
296
297 if ((len = capi_disc_req(chan->callref, &skb, CAUSE_NORMAL)) < 0)
298 {
299 printk("capi_disc_req failed\n");
300 return;
301 }
302
303 refnum = last_ref_num++ & 0x7fffU;
304 chan->s_refnum = refnum;
305
306 pcbit_l2_write(dev, MSG_DISC_REQ, refnum, skb, len);
307}
308
309/*
310 * Disc confirm received send BHUP
311 * Problem: when the HL driver sends the disc req itself
312 * LL receives BHUP
313 */
314void cb_disc_3(struct pcbit_dev * dev, struct pcbit_chan* chan,
315 struct callb_data *data)
316{
317 isdn_ctrl ictl;
318
319 ictl.command = ISDN_STAT_BHUP;
320 ictl.driver=dev->id;
321 ictl.arg=chan->id;
322 dev->dev_if->statcallb(&ictl);
323}
324
325void cb_notdone(struct pcbit_dev * dev, struct pcbit_chan* chan,
326 struct callb_data *data)
327{
328}
329
330/*
331 * send activate b-chan protocol
332 */
333void cb_selp_1(struct pcbit_dev * dev, struct pcbit_chan* chan,
334 struct callb_data *data)
335{
336 struct sk_buff *skb;
337 int len;
338 ushort refnum;
339
340 if ((len = capi_activate_transp_req(chan, &skb)) < 0)
341 {
342 printk("capi_conn_activate_transp_req failed\n");
343 return;
344 }
345
346 refnum = last_ref_num++ & 0x7fffU;
347 chan->s_refnum = refnum;
348
349 pcbit_l2_write(dev, MSG_ACT_TRANSP_REQ, refnum, skb, len);
350}
351
352/*
353 * Inform User that the B-channel is available
354 */
355void cb_open(struct pcbit_dev * dev, struct pcbit_chan* chan,
356 struct callb_data *data)
357{
358 isdn_ctrl ictl;
359
360 ictl.command = ISDN_STAT_BCONN;
361 ictl.driver=dev->id;
362 ictl.arg=chan->id;
363 dev->dev_if->statcallb(&ictl);
364}
365
366
367
diff --git a/drivers/isdn/pcbit/callbacks.h b/drivers/isdn/pcbit/callbacks.h
new file mode 100644
index 000000000000..f510dc56b57e
--- /dev/null
+++ b/drivers/isdn/pcbit/callbacks.h
@@ -0,0 +1,49 @@
1/*
2 * Callbacks prototypes for FSM
3 *
4 * Copyright (C) 1996 Universidade de Lisboa
5 *
6 * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
7 *
8 * This software may be used and distributed according to the terms of
9 * the GNU General Public License, incorporated herein by reference.
10 */
11
12#ifndef CALLBACKS_H
13#define CALLBACKS_H
14
15
16extern void cb_out_1(struct pcbit_dev * dev, struct pcbit_chan* chan,
17 struct callb_data *data);
18
19extern void cb_out_2(struct pcbit_dev * dev, struct pcbit_chan* chan,
20 struct callb_data *data);
21
22extern void cb_out_3(struct pcbit_dev * dev, struct pcbit_chan* chan,
23 struct callb_data *data);
24
25extern void cb_in_1(struct pcbit_dev * dev, struct pcbit_chan* chan,
26 struct callb_data *data);
27extern void cb_in_2(struct pcbit_dev * dev, struct pcbit_chan* chan,
28 struct callb_data *data);
29extern void cb_in_3(struct pcbit_dev * dev, struct pcbit_chan* chan,
30 struct callb_data *data);
31
32extern void cb_disc_1(struct pcbit_dev * dev, struct pcbit_chan* chan,
33 struct callb_data *data);
34extern void cb_disc_2(struct pcbit_dev * dev, struct pcbit_chan* chan,
35 struct callb_data *data);
36extern void cb_disc_3(struct pcbit_dev * dev, struct pcbit_chan* chan,
37 struct callb_data *data);
38
39extern void cb_notdone(struct pcbit_dev * dev, struct pcbit_chan* chan,
40 struct callb_data *data);
41
42extern void cb_selp_1(struct pcbit_dev * dev, struct pcbit_chan* chan,
43 struct callb_data *data);
44extern void cb_open(struct pcbit_dev * dev, struct pcbit_chan* chan,
45 struct callb_data *data);
46
47#endif
48
49
diff --git a/drivers/isdn/pcbit/capi.c b/drivers/isdn/pcbit/capi.c
new file mode 100644
index 000000000000..29eb03a8c29d
--- /dev/null
+++ b/drivers/isdn/pcbit/capi.c
@@ -0,0 +1,663 @@
1/*
2 * CAPI encoder/decoder for
3 * Portugal Telecom CAPI 2.0
4 *
5 * Copyright (C) 1996 Universidade de Lisboa
6 *
7 * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
8 *
9 * This software may be used and distributed according to the terms of
10 * the GNU General Public License, incorporated herein by reference.
11 *
12 * Not compatible with the AVM Gmbh. CAPI 2.0
13 *
14 */
15
16/*
17 * Documentation:
18 * - "Common ISDN API - Perfil Português - Versão 2.1",
19 * Telecom Portugal, Fev 1992.
20 * - "Common ISDN API - Especificação de protocolos para
21 * acesso aos canais B", Inesc, Jan 1994.
22 */
23
24/*
25 * TODO: better decoding of Information Elements
26 * for debug purposes mainly
27 * encode our number in CallerPN and ConnectedPN
28 */
29
30#include <linux/sched.h>
31#include <linux/string.h>
32#include <linux/kernel.h>
33
34#include <linux/types.h>
35#include <linux/slab.h>
36#include <linux/mm.h>
37
38#include <linux/skbuff.h>
39
40#include <asm/io.h>
41#include <asm/string.h>
42
43#include <linux/isdnif.h>
44
45#include "pcbit.h"
46#include "edss1.h"
47#include "capi.h"
48
49
50/*
51 * Encoding of CAPI messages
52 *
53 */
54
55int capi_conn_req(const char * calledPN, struct sk_buff **skb, int proto)
56{
57 ushort len;
58
59 /*
60 * length
61 * AppInfoMask - 2
62 * BC0 - 3
63 * BC1 - 1
64 * Chan - 2
65 * Keypad - 1
66 * CPN - 1
67 * CPSA - 1
68 * CalledPN - 2 + strlen
69 * CalledPSA - 1
70 * rest... - 4
71 * ----------------
72 * Total 18 + strlen
73 */
74
75 len = 18 + strlen(calledPN);
76
77 if (proto == ISDN_PROTO_L2_TRANS)
78 len++;
79
80 if ((*skb = dev_alloc_skb(len)) == NULL) {
81
82 printk(KERN_WARNING "capi_conn_req: alloc_skb failed\n");
83 return -1;
84 }
85
86 /* InfoElmMask */
87 *((ushort*) skb_put(*skb, 2)) = AppInfoMask;
88
89 if (proto == ISDN_PROTO_L2_TRANS)
90 {
91 /* Bearer Capability - Mandatory*/
92 *(skb_put(*skb, 1)) = 3; /* BC0.Length */
93 *(skb_put(*skb, 1)) = 0x80; /* Speech */
94 *(skb_put(*skb, 1)) = 0x10; /* Circuit Mode */
95 *(skb_put(*skb, 1)) = 0x23; /* A-law */
96 }
97 else
98 {
99 /* Bearer Capability - Mandatory*/
100 *(skb_put(*skb, 1)) = 2; /* BC0.Length */
101 *(skb_put(*skb, 1)) = 0x88; /* Digital Information */
102 *(skb_put(*skb, 1)) = 0x90; /* BC0.Octect4 */
103 }
104
105 /* Bearer Capability - Optional*/
106 *(skb_put(*skb, 1)) = 0; /* BC1.Length = 0 */
107
108 *(skb_put(*skb, 1)) = 1; /* ChannelID.Length = 1 */
109 *(skb_put(*skb, 1)) = 0x83; /* Basic Interface - Any Channel */
110
111 *(skb_put(*skb, 1)) = 0; /* Keypad.Length = 0 */
112
113
114 *(skb_put(*skb, 1)) = 0; /* CallingPN.Length = 0 */
115 *(skb_put(*skb, 1)) = 0; /* CallingPSA.Length = 0 */
116
117 /* Called Party Number */
118 *(skb_put(*skb, 1)) = strlen(calledPN) + 1;
119 *(skb_put(*skb, 1)) = 0x81;
120 memcpy(skb_put(*skb, strlen(calledPN)), calledPN, strlen(calledPN));
121
122 /* '#' */
123
124 *(skb_put(*skb, 1)) = 0; /* CalledPSA.Length = 0 */
125
126 /* LLC.Length = 0; */
127 /* HLC0.Length = 0; */
128 /* HLC1.Length = 0; */
129 /* UTUS.Length = 0; */
130 memset(skb_put(*skb, 4), 0, 4);
131
132 return len;
133}
134
135int capi_conn_resp(struct pcbit_chan* chan, struct sk_buff **skb)
136{
137
138 if ((*skb = dev_alloc_skb(5)) == NULL) {
139
140 printk(KERN_WARNING "capi_conn_resp: alloc_skb failed\n");
141 return -1;
142 }
143
144 *((ushort*) skb_put(*skb, 2) ) = chan->callref;
145 *(skb_put(*skb, 1)) = 0x01; /* ACCEPT_CALL */
146 *(skb_put(*skb, 1)) = 0;
147 *(skb_put(*skb, 1)) = 0;
148
149 return 5;
150}
151
152int capi_conn_active_req(struct pcbit_chan* chan, struct sk_buff **skb)
153{
154 /*
155 * 8 bytes
156 */
157
158 if ((*skb = dev_alloc_skb(8)) == NULL) {
159
160 printk(KERN_WARNING "capi_conn_active_req: alloc_skb failed\n");
161 return -1;
162 }
163
164 *((ushort*) skb_put(*skb, 2) ) = chan->callref;
165
166#ifdef DEBUG
167 printk(KERN_DEBUG "Call Reference: %04x\n", chan->callref);
168#endif
169
170 *(skb_put(*skb, 1)) = 0; /* BC.Length = 0; */
171 *(skb_put(*skb, 1)) = 0; /* ConnectedPN.Length = 0 */
172 *(skb_put(*skb, 1)) = 0; /* PSA.Length */
173 *(skb_put(*skb, 1)) = 0; /* LLC.Length = 0; */
174 *(skb_put(*skb, 1)) = 0; /* HLC.Length = 0; */
175 *(skb_put(*skb, 1)) = 0; /* UTUS.Length = 0; */
176
177 return 8;
178}
179
180int capi_conn_active_resp(struct pcbit_chan* chan, struct sk_buff **skb)
181{
182 /*
183 * 2 bytes
184 */
185
186 if ((*skb = dev_alloc_skb(2)) == NULL) {
187
188 printk(KERN_WARNING "capi_conn_active_resp: alloc_skb failed\n");
189 return -1;
190 }
191
192 *((ushort*) skb_put(*skb, 2) ) = chan->callref;
193
194 return 2;
195}
196
197
198int capi_select_proto_req(struct pcbit_chan *chan, struct sk_buff **skb,
199 int outgoing)
200{
201
202 /*
203 * 18 bytes
204 */
205
206 if ((*skb = dev_alloc_skb(18)) == NULL) {
207
208 printk(KERN_WARNING "capi_select_proto_req: alloc_skb failed\n");
209 return -1;
210 }
211
212 *((ushort*) skb_put(*skb, 2) ) = chan->callref;
213
214 /* Layer2 protocol */
215
216 switch (chan->proto) {
217 case ISDN_PROTO_L2_X75I:
218 *(skb_put(*skb, 1)) = 0x05; /* LAPB */
219 break;
220 case ISDN_PROTO_L2_HDLC:
221 *(skb_put(*skb, 1)) = 0x02;
222 break;
223 case ISDN_PROTO_L2_TRANS:
224 /*
225 * Voice (a-law)
226 */
227 *(skb_put(*skb, 1)) = 0x06;
228 break;
229 default:
230#ifdef DEBUG
231 printk(KERN_DEBUG "Transparent\n");
232#endif
233 *(skb_put(*skb, 1)) = 0x03;
234 break;
235 }
236
237 *(skb_put(*skb, 1)) = (outgoing ? 0x02 : 0x42); /* Don't ask */
238 *(skb_put(*skb, 1)) = 0x00;
239
240 *((ushort *) skb_put(*skb, 2)) = MRU;
241
242
243 *(skb_put(*skb, 1)) = 0x08; /* Modulo */
244 *(skb_put(*skb, 1)) = 0x07; /* Max Window */
245
246 *(skb_put(*skb, 1)) = 0x01; /* No Layer3 Protocol */
247
248 /*
249 * 2 - layer3 MTU [10]
250 * - Modulo [12]
251 * - Window
252 * - layer1 proto [14]
253 * - bitrate
254 * - sub-channel [16]
255 * - layer1dataformat [17]
256 */
257
258 memset(skb_put(*skb, 8), 0, 8);
259
260 return 18;
261}
262
263
264int capi_activate_transp_req(struct pcbit_chan *chan, struct sk_buff **skb)
265{
266
267 if ((*skb = dev_alloc_skb(7)) == NULL) {
268
269 printk(KERN_WARNING "capi_activate_transp_req: alloc_skb failed\n");
270 return -1;
271 }
272
273 *((ushort*) skb_put(*skb, 2) ) = chan->callref;
274
275
276 *(skb_put(*skb, 1)) = chan->layer2link; /* Layer2 id */
277 *(skb_put(*skb, 1)) = 0x00; /* Transmit by default */
278
279 *((ushort *) skb_put(*skb, 2)) = MRU;
280
281 *(skb_put(*skb, 1)) = 0x01; /* Enables reception*/
282
283 return 7;
284}
285
286int capi_tdata_req(struct pcbit_chan* chan, struct sk_buff *skb)
287{
288 ushort data_len;
289
290
291 /*
292 * callref - 2
293 * layer2link - 1
294 * wBlockLength - 2
295 * data - 4
296 * sernum - 1
297 */
298
299 data_len = skb->len;
300
301 if(skb_headroom(skb) < 10)
302 {
303 printk(KERN_CRIT "No headspace (%u) on headroom %p for capi header\n", skb_headroom(skb), skb);
304 }
305 else
306 {
307 skb_push(skb, 10);
308 }
309
310 *((u16 *) (skb->data)) = chan->callref;
311 skb->data[2] = chan->layer2link;
312 *((u16 *) (skb->data + 3)) = data_len;
313
314 chan->s_refnum = (chan->s_refnum + 1) % 8;
315 *((u32 *) (skb->data + 5)) = chan->s_refnum;
316
317 skb->data[9] = 0; /* HDLC frame number */
318
319 return 10;
320}
321
322int capi_tdata_resp(struct pcbit_chan *chan, struct sk_buff ** skb)
323
324{
325 if ((*skb = dev_alloc_skb(4)) == NULL) {
326
327 printk(KERN_WARNING "capi_tdata_resp: alloc_skb failed\n");
328 return -1;
329 }
330
331 *((ushort*) skb_put(*skb, 2) ) = chan->callref;
332
333 *(skb_put(*skb, 1)) = chan->layer2link;
334 *(skb_put(*skb, 1)) = chan->r_refnum;
335
336 return (*skb)->len;
337}
338
339int capi_disc_req(ushort callref, struct sk_buff **skb, u_char cause)
340{
341
342 if ((*skb = dev_alloc_skb(6)) == NULL) {
343
344 printk(KERN_WARNING "capi_disc_req: alloc_skb failed\n");
345 return -1;
346 }
347
348 *((ushort*) skb_put(*skb, 2) ) = callref;
349
350 *(skb_put(*skb, 1)) = 2; /* Cause.Length = 2; */
351 *(skb_put(*skb, 1)) = 0x80;
352 *(skb_put(*skb, 1)) = 0x80 | cause;
353
354 /*
355 * Change it: we should send 'Sic transit gloria Mundi' here ;-)
356 */
357
358 *(skb_put(*skb, 1)) = 0; /* UTUS.Length = 0; */
359
360 return 6;
361}
362
363int capi_disc_resp(struct pcbit_chan *chan, struct sk_buff **skb)
364{
365 if ((*skb = dev_alloc_skb(2)) == NULL) {
366
367 printk(KERN_WARNING "capi_disc_resp: alloc_skb failed\n");
368 return -1;
369 }
370
371 *((ushort*) skb_put(*skb, 2)) = chan->callref;
372
373 return 2;
374}
375
376
377/*
378 * Decoding of CAPI messages
379 *
380 */
381
382int capi_decode_conn_ind(struct pcbit_chan * chan,
383 struct sk_buff *skb,
384 struct callb_data *info)
385{
386 int CIlen, len;
387
388 /* Call Reference [CAPI] */
389 chan->callref = *((ushort*) skb->data);
390 skb_pull(skb, 2);
391
392#ifdef DEBUG
393 printk(KERN_DEBUG "Call Reference: %04x\n", chan->callref);
394#endif
395
396 /* Channel Identification */
397
398 /* Expect
399 Len = 1
400 Octect 3 = 0100 10CC - [ 7 Basic, 4 , 2-1 chan ]
401 */
402
403 CIlen = skb->data[0];
404#ifdef DEBUG
405 if (CIlen == 1) {
406
407 if ( ((skb->data[1]) & 0xFC) == 0x48 )
408 printk(KERN_DEBUG "decode_conn_ind: chan ok\n");
409 printk(KERN_DEBUG "phyChan = %d\n", skb->data[1] & 0x03);
410 }
411 else
412 printk(KERN_DEBUG "conn_ind: CIlen = %d\n", CIlen);
413#endif
414 skb_pull(skb, CIlen + 1);
415
416 /* Calling Party Number */
417 /* An "additional service" as far as Portugal Telecom is concerned */
418
419 len = skb->data[0];
420
421 if (len > 0) {
422 int count = 1;
423
424#ifdef DEBUG
425 printk(KERN_DEBUG "CPN: Octect 3 %02x\n", skb->data[1]);
426#endif
427 if ((skb->data[1] & 0x80) == 0)
428 count = 2;
429
430 if (!(info->data.setup.CallingPN = kmalloc(len - count + 1, GFP_ATOMIC)))
431 return -1;
432
433 memcpy(info->data.setup.CallingPN, skb->data + count + 1,
434 len - count);
435 info->data.setup.CallingPN[len - count] = 0;
436
437 }
438 else {
439 info->data.setup.CallingPN = NULL;
440 printk(KERN_DEBUG "NULL CallingPN\n");
441 }
442
443 skb_pull(skb, len + 1);
444
445 /* Calling Party Subaddress */
446 skb_pull(skb, skb->data[0] + 1);
447
448 /* Called Party Number */
449
450 len = skb->data[0];
451
452 if (len > 0) {
453 int count = 1;
454
455 if ((skb->data[1] & 0x80) == 0)
456 count = 2;
457
458 if (!(info->data.setup.CalledPN = kmalloc(len - count + 1, GFP_ATOMIC)))
459 return -1;
460
461 memcpy(info->data.setup.CalledPN, skb->data + count + 1,
462 len - count);
463 info->data.setup.CalledPN[len - count] = 0;
464
465 }
466 else {
467 info->data.setup.CalledPN = NULL;
468 printk(KERN_DEBUG "NULL CalledPN\n");
469 }
470
471 skb_pull(skb, len + 1);
472
473 /* Called Party Subaddress */
474 skb_pull(skb, skb->data[0] + 1);
475
476 /* LLC */
477 skb_pull(skb, skb->data[0] + 1);
478
479 /* HLC */
480 skb_pull(skb, skb->data[0] + 1);
481
482 /* U2U */
483 skb_pull(skb, skb->data[0] + 1);
484
485 return 0;
486}
487
488/*
489 * returns errcode
490 */
491
492int capi_decode_conn_conf(struct pcbit_chan * chan, struct sk_buff *skb,
493 int *complete)
494{
495 int errcode;
496
497 chan->callref = *((ushort *) skb->data); /* Update CallReference */
498 skb_pull(skb, 2);
499
500 errcode = *((ushort *) skb->data); /* read errcode */
501 skb_pull(skb, 2);
502
503 *complete = *(skb->data);
504 skb_pull(skb, 1);
505
506 /* FIX ME */
507 /* This is actually a firmware bug */
508 if (!*complete)
509 {
510 printk(KERN_DEBUG "complete=%02x\n", *complete);
511 *complete = 1;
512 }
513
514
515 /* Optional Bearer Capability */
516 skb_pull(skb, *(skb->data) + 1);
517
518 /* Channel Identification */
519 skb_pull(skb, *(skb->data) + 1);
520
521 /* High Layer Compatibility follows */
522 skb_pull(skb, *(skb->data) + 1);
523
524 return errcode;
525}
526
527int capi_decode_conn_actv_ind(struct pcbit_chan * chan, struct sk_buff *skb)
528{
529 ushort len;
530#ifdef DEBUG
531 char str[32];
532#endif
533
534 /* Yet Another Bearer Capability */
535 skb_pull(skb, *(skb->data) + 1);
536
537
538 /* Connected Party Number */
539 len=*(skb->data);
540
541#ifdef DEBUG
542 if (len > 1 && len < 31) {
543 memcpy(str, skb->data + 2, len - 1);
544 str[len] = 0;
545 printk(KERN_DEBUG "Connected Party Number: %s\n", str);
546 }
547 else
548 printk(KERN_DEBUG "actv_ind CPN len = %d\n", len);
549#endif
550
551 skb_pull(skb, len + 1);
552
553 /* Connected Subaddress */
554 skb_pull(skb, *(skb->data) + 1);
555
556 /* Low Layer Capability */
557 skb_pull(skb, *(skb->data) + 1);
558
559 /* High Layer Capability */
560 skb_pull(skb, *(skb->data) + 1);
561
562 return 0;
563}
564
565int capi_decode_conn_actv_conf(struct pcbit_chan * chan, struct sk_buff *skb)
566{
567 ushort errcode;
568
569 errcode = *((ushort*) skb->data);
570 skb_pull(skb, 2);
571
572 /* Channel Identification
573 skb_pull(skb, skb->data[0] + 1);
574 */
575 return errcode;
576}
577
578
579int capi_decode_sel_proto_conf(struct pcbit_chan *chan, struct sk_buff *skb)
580{
581 ushort errcode;
582
583 chan->layer2link = *(skb->data);
584 skb_pull(skb, 1);
585
586 errcode = *((ushort*) skb->data);
587 skb_pull(skb, 2);
588
589 return errcode;
590}
591
592int capi_decode_actv_trans_conf(struct pcbit_chan *chan, struct sk_buff *skb)
593{
594 ushort errcode;
595
596 if (chan->layer2link != *(skb->data) )
597 printk("capi_decode_actv_trans_conf: layer2link doesn't match\n");
598
599 skb_pull(skb, 1);
600
601 errcode = *((ushort*) skb->data);
602 skb_pull(skb, 2);
603
604 return errcode;
605}
606
607int capi_decode_disc_ind(struct pcbit_chan *chan, struct sk_buff *skb)
608{
609 ushort len;
610#ifdef DEBUG
611 int i;
612#endif
613 /* Cause */
614
615 len = *(skb->data);
616 skb_pull(skb, 1);
617
618#ifdef DEBUG
619
620 for (i=0; i<len; i++)
621 printk(KERN_DEBUG "Cause Octect %d: %02x\n", i+3,
622 *(skb->data + i));
623#endif
624
625 skb_pull(skb, len);
626
627 return 0;
628}
629
630int capi_decode_disc_conf(struct pcbit_chan *chan, struct sk_buff *skb)
631{
632 ushort errcode;
633
634 errcode = *((ushort*) skb->data);
635 skb_pull(skb, 2);
636
637 return errcode;
638}
639
640#ifdef DEBUG
641int capi_decode_debug_188(u_char *hdr, ushort hdrlen)
642{
643 char str[64];
644 int len;
645
646 len = hdr[0];
647
648 if (len < 64 && len == hdrlen - 1) {
649 memcpy(str, hdr + 1, hdrlen - 1);
650 str[hdrlen - 1] = 0;
651 printk("%s\n", str);
652 }
653 else
654 printk("debug message incorrect\n");
655
656 return 0;
657}
658#endif
659
660
661
662
663
diff --git a/drivers/isdn/pcbit/capi.h b/drivers/isdn/pcbit/capi.h
new file mode 100644
index 000000000000..18e6aa360a8f
--- /dev/null
+++ b/drivers/isdn/pcbit/capi.h
@@ -0,0 +1,88 @@
1/*
2 * CAPI encode/decode prototypes and defines
3 *
4 * Copyright (C) 1996 Universidade de Lisboa
5 *
6 * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
7 *
8 * This software may be used and distributed according to the terms of
9 * the GNU General Public License, incorporated herein by reference.
10 */
11
12#ifndef CAPI_H
13#define CAPI_H
14
15
16#define REQ_CAUSE 0x01
17#define REQ_DISPLAY 0x04
18#define REQ_USER_TO_USER 0x08
19
20#define AppInfoMask REQ_CAUSE|REQ_DISPLAY|REQ_USER_TO_USER
21
22/* Connection Setup */
23extern int capi_conn_req(const char * calledPN, struct sk_buff **buf,
24 int proto);
25extern int capi_decode_conn_conf(struct pcbit_chan * chan, struct sk_buff *skb,
26 int *complete);
27
28extern int capi_decode_conn_ind(struct pcbit_chan * chan, struct sk_buff *skb,
29 struct callb_data *info);
30extern int capi_conn_resp(struct pcbit_chan* chan, struct sk_buff **skb);
31
32extern int capi_conn_active_req(struct pcbit_chan* chan, struct sk_buff **skb);
33extern int capi_decode_conn_actv_conf(struct pcbit_chan * chan,
34 struct sk_buff *skb);
35
36extern int capi_decode_conn_actv_ind(struct pcbit_chan * chan,
37 struct sk_buff *skb);
38extern int capi_conn_active_resp(struct pcbit_chan* chan,
39 struct sk_buff **skb);
40
41/* Data */
42extern int capi_select_proto_req(struct pcbit_chan *chan, struct sk_buff **skb,
43 int outgoing);
44extern int capi_decode_sel_proto_conf(struct pcbit_chan *chan,
45 struct sk_buff *skb);
46
47extern int capi_activate_transp_req(struct pcbit_chan *chan,
48 struct sk_buff **skb);
49extern int capi_decode_actv_trans_conf(struct pcbit_chan *chan,
50 struct sk_buff *skb);
51
52extern int capi_tdata_req(struct pcbit_chan* chan, struct sk_buff *skb);
53extern int capi_tdata_resp(struct pcbit_chan *chan, struct sk_buff ** skb);
54
55/* Connection Termination */
56extern int capi_disc_req(ushort callref, struct sk_buff **skb, u_char cause);
57extern int capi_decode_disc_conf(struct pcbit_chan *chan, struct sk_buff *skb);
58
59extern int capi_decode_disc_ind(struct pcbit_chan *chan, struct sk_buff *skb);
60extern int capi_disc_resp(struct pcbit_chan *chan, struct sk_buff **skb);
61
62#ifdef DEBUG
63extern int capi_decode_debug_188(u_char *hdr, ushort hdrlen);
64#endif
65
66static inline struct pcbit_chan *
67capi_channel(struct pcbit_dev *dev, struct sk_buff *skb)
68{
69 ushort callref;
70
71 callref = *((ushort*) skb->data);
72 skb_pull(skb, 2);
73
74 if (dev->b1->callref == callref)
75 return dev->b1;
76 else if (dev->b2->callref == callref)
77 return dev->b2;
78
79 return NULL;
80}
81
82#endif
83
84
85
86
87
88
diff --git a/drivers/isdn/pcbit/drv.c b/drivers/isdn/pcbit/drv.c
new file mode 100644
index 000000000000..e98f9c48c184
--- /dev/null
+++ b/drivers/isdn/pcbit/drv.c
@@ -0,0 +1,1088 @@
1/*
2 * PCBIT-D interface with isdn4linux
3 *
4 * Copyright (C) 1996 Universidade de Lisboa
5 *
6 * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
7 *
8 * This software may be used and distributed according to the terms of
9 * the GNU General Public License, incorporated herein by reference.
10 */
11
12/*
13 * Fixes:
14 *
15 * Nuno Grilo <l38486@alfa.ist.utl.pt>
16 * fixed msn_list NULL pointer dereference.
17 *
18 */
19
20#include <linux/module.h>
21
22#include <linux/sched.h>
23
24#include <linux/kernel.h>
25
26#include <linux/types.h>
27#include <linux/slab.h>
28#include <linux/mm.h>
29#include <linux/interrupt.h>
30#include <linux/string.h>
31#include <linux/skbuff.h>
32
33#include <linux/isdnif.h>
34#include <asm/string.h>
35#include <asm/io.h>
36#include <linux/ioport.h>
37
38#include "pcbit.h"
39#include "edss1.h"
40#include "layer2.h"
41#include "capi.h"
42
43
44extern ushort last_ref_num;
45
46static int pcbit_ioctl(isdn_ctrl* ctl);
47
48static char* pcbit_devname[MAX_PCBIT_CARDS] = {
49 "pcbit0",
50 "pcbit1",
51 "pcbit2",
52 "pcbit3"
53};
54
55/*
56 * prototypes
57 */
58
59int pcbit_command(isdn_ctrl* ctl);
60int pcbit_stat(u_char __user * buf, int len, int, int);
61int pcbit_xmit(int driver, int chan, int ack, struct sk_buff *skb);
62int pcbit_writecmd(const u_char __user *, int, int, int);
63
64static int set_protocol_running(struct pcbit_dev * dev);
65
66static void pcbit_clear_msn(struct pcbit_dev *dev);
67static void pcbit_set_msn(struct pcbit_dev *dev, char *list);
68static int pcbit_check_msn(struct pcbit_dev *dev, char *msn);
69
70
71extern void pcbit_deliver(void * data);
72
73int pcbit_init_dev(int board, int mem_base, int irq)
74{
75 struct pcbit_dev *dev;
76 isdn_if *dev_if;
77
78 if ((dev=kmalloc(sizeof(struct pcbit_dev), GFP_KERNEL)) == NULL)
79 {
80 printk("pcbit_init: couldn't malloc pcbit_dev struct\n");
81 return -ENOMEM;
82 }
83
84 dev_pcbit[board] = dev;
85 memset(dev, 0, sizeof(struct pcbit_dev));
86 init_waitqueue_head(&dev->set_running_wq);
87 spin_lock_init(&dev->lock);
88
89 if (mem_base >= 0xA0000 && mem_base <= 0xFFFFF ) {
90 dev->ph_mem = mem_base;
91 if (!request_mem_region(dev->ph_mem, 4096, "PCBIT mem")) {
92 printk(KERN_WARNING
93 "PCBIT: memory region %lx-%lx already in use\n",
94 dev->ph_mem, dev->ph_mem + 4096);
95 kfree(dev);
96 dev_pcbit[board] = NULL;
97 return -EACCES;
98 }
99 dev->sh_mem = ioremap(dev->ph_mem, 4096);
100 }
101 else
102 {
103 printk("memory address invalid");
104 kfree(dev);
105 dev_pcbit[board] = NULL;
106 return -EACCES;
107 }
108
109 dev->b1 = kmalloc(sizeof(struct pcbit_chan), GFP_KERNEL);
110 if (!dev->b1) {
111 printk("pcbit_init: couldn't malloc pcbit_chan struct\n");
112 iounmap(dev->sh_mem);
113 release_mem_region(dev->ph_mem, 4096);
114 kfree(dev);
115 return -ENOMEM;
116 }
117
118 dev->b2 = kmalloc(sizeof(struct pcbit_chan), GFP_KERNEL);
119 if (!dev->b2) {
120 printk("pcbit_init: couldn't malloc pcbit_chan struct\n");
121 kfree(dev->b1);
122 iounmap(dev->sh_mem);
123 release_mem_region(dev->ph_mem, 4096);
124 kfree(dev);
125 return -ENOMEM;
126 }
127
128 memset(dev->b1, 0, sizeof(struct pcbit_chan));
129 memset(dev->b2, 0, sizeof(struct pcbit_chan));
130 dev->b2->id = 1;
131
132 INIT_WORK(&dev->qdelivery, pcbit_deliver, dev);
133
134 /*
135 * interrupts
136 */
137
138 if (request_irq(irq, &pcbit_irq_handler, 0, pcbit_devname[board], dev) != 0)
139 {
140 kfree(dev->b1);
141 kfree(dev->b2);
142 iounmap(dev->sh_mem);
143 release_mem_region(dev->ph_mem, 4096);
144 kfree(dev);
145 dev_pcbit[board] = NULL;
146 return -EIO;
147 }
148
149 dev->irq = irq;
150
151 /* next frame to be received */
152 dev->rcv_seq = 0;
153 dev->send_seq = 0;
154 dev->unack_seq = 0;
155
156 dev->hl_hdrlen = 16;
157
158 dev_if = kmalloc(sizeof(isdn_if), GFP_KERNEL);
159
160 if (!dev_if) {
161 free_irq(irq, dev);
162 kfree(dev->b1);
163 kfree(dev->b2);
164 iounmap(dev->sh_mem);
165 release_mem_region(dev->ph_mem, 4096);
166 kfree(dev);
167 dev_pcbit[board] = NULL;
168 return -EIO;
169 }
170
171 dev->dev_if = dev_if;
172
173 dev_if->owner = THIS_MODULE;
174
175 dev_if->channels = 2;
176
177 dev_if->features = (ISDN_FEATURE_P_EURO | ISDN_FEATURE_L3_TRANS |
178 ISDN_FEATURE_L2_HDLC | ISDN_FEATURE_L2_TRANS );
179
180 dev_if->writebuf_skb = pcbit_xmit;
181 dev_if->hl_hdrlen = 16;
182
183 dev_if->maxbufsize = MAXBUFSIZE;
184 dev_if->command = pcbit_command;
185
186 dev_if->writecmd = pcbit_writecmd;
187 dev_if->readstat = pcbit_stat;
188
189
190 strcpy(dev_if->id, pcbit_devname[board]);
191
192 if (!register_isdn(dev_if)) {
193 free_irq(irq, dev);
194 kfree(dev->b1);
195 kfree(dev->b2);
196 iounmap(dev->sh_mem);
197 release_mem_region(dev->ph_mem, 4096);
198 kfree(dev);
199 dev_pcbit[board] = NULL;
200 return -EIO;
201 }
202
203 dev->id = dev_if->channels;
204
205
206 dev->l2_state = L2_DOWN;
207 dev->free = 511;
208
209 /*
210 * set_protocol_running(dev);
211 */
212
213 return 0;
214}
215
216#ifdef MODULE
217void pcbit_terminate(int board)
218{
219 struct pcbit_dev * dev;
220
221 dev = dev_pcbit[board];
222
223 if (dev) {
224 /* unregister_isdn(dev->dev_if); */
225 free_irq(dev->irq, dev);
226 pcbit_clear_msn(dev);
227 kfree(dev->dev_if);
228 if (dev->b1->fsm_timer.function)
229 del_timer(&dev->b1->fsm_timer);
230 if (dev->b2->fsm_timer.function)
231 del_timer(&dev->b2->fsm_timer);
232 kfree(dev->b1);
233 kfree(dev->b2);
234 iounmap(dev->sh_mem);
235 release_mem_region(dev->ph_mem, 4096);
236 kfree(dev);
237 }
238}
239#endif
240
241int pcbit_command(isdn_ctrl* ctl)
242{
243 struct pcbit_dev *dev;
244 struct pcbit_chan *chan;
245 struct callb_data info;
246
247 dev = finddev(ctl->driver);
248
249 if (!dev)
250 {
251 printk("pcbit_command: unknown device\n");
252 return -1;
253 }
254
255 chan = (ctl->arg & 0x0F) ? dev->b2 : dev->b1;
256
257
258 switch(ctl->command) {
259 case ISDN_CMD_IOCTL:
260 return pcbit_ioctl(ctl);
261 break;
262 case ISDN_CMD_DIAL:
263 info.type = EV_USR_SETUP_REQ;
264 info.data.setup.CalledPN = (char *) &ctl->parm.setup.phone;
265 pcbit_fsm_event(dev, chan, EV_USR_SETUP_REQ, &info);
266 break;
267 case ISDN_CMD_ACCEPTD:
268 pcbit_fsm_event(dev, chan, EV_USR_SETUP_RESP, NULL);
269 break;
270 case ISDN_CMD_ACCEPTB:
271 printk("ISDN_CMD_ACCEPTB - not really needed\n");
272 break;
273 case ISDN_CMD_HANGUP:
274 pcbit_fsm_event(dev, chan, EV_USR_RELEASE_REQ, NULL);
275 break;
276 case ISDN_CMD_SETL2:
277 chan->proto = (ctl->arg >> 8);
278 break;
279 case ISDN_CMD_CLREAZ:
280 pcbit_clear_msn(dev);
281 break;
282 case ISDN_CMD_SETEAZ:
283 pcbit_set_msn(dev, ctl->parm.num);
284 break;
285 case ISDN_CMD_SETL3:
286 if ((ctl->arg >> 8) != ISDN_PROTO_L3_TRANS)
287 printk(KERN_DEBUG "L3 protocol unknown\n");
288 break;
289 default:
290 printk(KERN_DEBUG "pcbit_command: unknown command\n");
291 break;
292 };
293
294 return 0;
295}
296
297/*
298 * Another Hack :-(
299 * on some conditions the board stops sending TDATA_CONFs
300 * let's see if we can turn around the problem
301 */
302
303#ifdef BLOCK_TIMER
304static void pcbit_block_timer(unsigned long data)
305{
306 struct pcbit_chan *chan;
307 struct pcbit_dev * dev;
308 isdn_ctrl ictl;
309
310 chan = (struct pcbit_chan *) data;
311
312 dev = chan2dev(chan);
313
314 if (dev == NULL) {
315 printk(KERN_DEBUG "pcbit: chan2dev failed\n");
316 return;
317 }
318
319 del_timer(&chan->block_timer);
320 chan->block_timer.function = NULL;
321
322#ifdef DEBUG
323 printk(KERN_DEBUG "pcbit_block_timer\n");
324#endif
325 chan->queued = 0;
326 ictl.driver = dev->id;
327 ictl.command = ISDN_STAT_BSENT;
328 ictl.arg = chan->id;
329 dev->dev_if->statcallb(&ictl);
330}
331#endif
332
333int pcbit_xmit(int driver, int chnum, int ack, struct sk_buff *skb)
334{
335 ushort hdrlen;
336 int refnum, len;
337 struct pcbit_chan * chan;
338 struct pcbit_dev *dev;
339
340 dev = finddev(driver);
341 if (dev == NULL)
342 {
343 printk("finddev returned NULL");
344 return -1;
345 }
346
347 chan = chnum ? dev->b2 : dev->b1;
348
349
350 if (chan->fsm_state != ST_ACTIVE)
351 return -1;
352
353 if (chan->queued >= MAX_QUEUED )
354 {
355#ifdef DEBUG_QUEUE
356 printk(KERN_DEBUG
357 "pcbit: %d packets already in queue - write fails\n",
358 chan->queued);
359#endif
360 /*
361 * packet stays on the head of the device queue
362 * since dev_start_xmit will fail
363 * see net/core/dev.c
364 */
365#ifdef BLOCK_TIMER
366 if (chan->block_timer.function == NULL) {
367 init_timer(&chan->block_timer);
368 chan->block_timer.function = &pcbit_block_timer;
369 chan->block_timer.data = (long) chan;
370 chan->block_timer.expires = jiffies + 1 * HZ;
371 add_timer(&chan->block_timer);
372 }
373#endif
374 return 0;
375 }
376
377
378 chan->queued++;
379
380 len = skb->len;
381
382 hdrlen = capi_tdata_req(chan, skb);
383
384 refnum = last_ref_num++ & 0x7fffU;
385 chan->s_refnum = refnum;
386
387 pcbit_l2_write(dev, MSG_TDATA_REQ, refnum, skb, hdrlen);
388
389 return len;
390}
391
392int pcbit_writecmd(const u_char __user *buf, int len, int driver, int channel)
393{
394 struct pcbit_dev * dev;
395 int i, j;
396 const u_char * loadbuf;
397 u_char * ptr = NULL;
398 u_char *cbuf;
399
400 int errstat;
401
402 dev = finddev(driver);
403
404 if (!dev)
405 {
406 printk("pcbit_writecmd: couldn't find device");
407 return -ENODEV;
408 }
409
410 switch(dev->l2_state) {
411 case L2_LWMODE:
412 /* check (size <= rdp_size); write buf into board */
413 if (len < 0 || len > BANK4 + 1 || len > 1024)
414 {
415 printk("pcbit_writecmd: invalid length %d\n", len);
416 return -EINVAL;
417 }
418
419 cbuf = kmalloc(len, GFP_KERNEL);
420 if (!cbuf)
421 return -ENOMEM;
422
423 if (copy_from_user(cbuf, buf, len)) {
424 kfree(cbuf);
425 return -EFAULT;
426 }
427 memcpy_toio(dev->sh_mem, cbuf, len);
428 kfree(cbuf);
429 return len;
430 case L2_FWMODE:
431 /* this is the hard part */
432 /* dumb board */
433 /* get it into kernel space */
434 if ((ptr = kmalloc(len, GFP_KERNEL))==NULL)
435 return -ENOMEM;
436 if (copy_from_user(ptr, buf, len)) {
437 kfree(ptr);
438 return -EFAULT;
439 }
440 loadbuf = ptr;
441
442 errstat = 0;
443
444 for (i=0; i < len; i++)
445 {
446 for(j=0; j < LOAD_RETRY; j++)
447 if (!(readb(dev->sh_mem + dev->loadptr)))
448 break;
449
450 if (j == LOAD_RETRY)
451 {
452 errstat = -ETIME;
453 printk("TIMEOUT i=%d\n", i);
454 break;
455 }
456 writeb(loadbuf[i], dev->sh_mem + dev->loadptr + 1);
457 writeb(0x01, dev->sh_mem + dev->loadptr);
458
459 dev->loadptr += 2;
460 if (dev->loadptr > LOAD_ZONE_END)
461 dev->loadptr = LOAD_ZONE_START;
462 }
463 kfree(ptr);
464
465 return errstat ? errstat : len;
466 default:
467 return -EBUSY;
468 }
469}
470
471/*
472 * demultiplexing of messages
473 *
474 */
475
476void pcbit_l3_receive(struct pcbit_dev * dev, ulong msg,
477 struct sk_buff * skb,
478 ushort hdr_len, ushort refnum)
479{
480 struct pcbit_chan *chan;
481 struct sk_buff *skb2;
482 unsigned short len;
483 struct callb_data cbdata;
484 int complete, err;
485 isdn_ctrl ictl;
486
487 switch(msg) {
488
489 case MSG_TDATA_IND:
490 if (!(chan = capi_channel(dev, skb))) {
491 printk(KERN_WARNING
492 "CAPI header: unknown channel id\n");
493 break;
494 }
495 chan->r_refnum = skb->data[7];
496 skb_pull(skb, 8);
497
498 dev->dev_if->rcvcallb_skb(dev->id, chan->id, skb);
499
500 if (capi_tdata_resp(chan, &skb2) > 0)
501 pcbit_l2_write(dev, MSG_TDATA_RESP, refnum,
502 skb2, skb2->len);
503 return;
504 break;
505 case MSG_TDATA_CONF:
506 if (!(chan = capi_channel(dev, skb))) {
507 printk(KERN_WARNING
508 "CAPI header: unknown channel id\n");
509 break;
510 }
511
512#ifdef DEBUG
513 if ( (*((ushort *) (skb->data + 2) )) != 0) {
514 printk(KERN_DEBUG "TDATA_CONF error\n");
515 }
516#endif
517#ifdef BLOCK_TIMER
518 if (chan->queued == MAX_QUEUED) {
519 del_timer(&chan->block_timer);
520 chan->block_timer.function = NULL;
521 }
522
523#endif
524 chan->queued--;
525
526 ictl.driver = dev->id;
527 ictl.command = ISDN_STAT_BSENT;
528 ictl.arg = chan->id;
529 dev->dev_if->statcallb(&ictl);
530 break;
531
532 case MSG_CONN_IND:
533 /*
534 * channel: 1st not used will do
535 * if both are used we're in trouble
536 */
537
538 if (!dev->b1->fsm_state)
539 chan = dev->b1;
540 else if (!dev->b2->fsm_state)
541 chan = dev->b2;
542 else {
543 printk(KERN_INFO
544 "Incoming connection: no channels available");
545
546 if ((len = capi_disc_req(*(ushort*)(skb->data), &skb2, CAUSE_NOCHAN)) > 0)
547 pcbit_l2_write(dev, MSG_DISC_REQ, refnum, skb2, len);
548 break;
549 }
550
551 cbdata.data.setup.CalledPN = NULL;
552 cbdata.data.setup.CallingPN = NULL;
553
554 capi_decode_conn_ind(chan, skb, &cbdata);
555 cbdata.type = EV_NET_SETUP;
556
557 pcbit_fsm_event(dev, chan, EV_NET_SETUP, NULL);
558
559 if (pcbit_check_msn(dev, cbdata.data.setup.CallingPN))
560 pcbit_fsm_event(dev, chan, EV_USR_PROCED_REQ, &cbdata);
561 else
562 pcbit_fsm_event(dev, chan, EV_USR_RELEASE_REQ, NULL);
563
564 if (cbdata.data.setup.CalledPN)
565 kfree(cbdata.data.setup.CalledPN);
566 if (cbdata.data.setup.CallingPN)
567 kfree(cbdata.data.setup.CallingPN);
568 break;
569
570 case MSG_CONN_CONF:
571 /*
572 * We should be able to find the channel by the message
573 * reference number. The current version of the firmware
574 * doesn't sent the ref number correctly.
575 */
576#ifdef DEBUG
577 printk(KERN_DEBUG "refnum=%04x b1=%04x b2=%04x\n", refnum,
578 dev->b1->s_refnum,
579 dev->b2->s_refnum);
580#endif
581 /* We just try to find a channel in the right state */
582
583 if (dev->b1->fsm_state == ST_CALL_INIT)
584 chan = dev->b1;
585 else {
586 if (dev->b2->s_refnum == ST_CALL_INIT)
587 chan = dev->b2;
588 else {
589 chan = NULL;
590 printk(KERN_WARNING "Connection Confirm - no channel in Call Init state\n");
591 break;
592 }
593 }
594 if (capi_decode_conn_conf(chan, skb, &complete)) {
595 printk(KERN_DEBUG "conn_conf indicates error\n");
596 pcbit_fsm_event(dev, chan, EV_ERROR, NULL);
597 }
598 else
599 if (complete)
600 pcbit_fsm_event(dev, chan, EV_NET_CALL_PROC, NULL);
601 else
602 pcbit_fsm_event(dev, chan, EV_NET_SETUP_ACK, NULL);
603 break;
604 case MSG_CONN_ACTV_IND:
605
606 if (!(chan = capi_channel(dev, skb))) {
607 printk(KERN_WARNING
608 "CAPI header: unknown channel id\n");
609 break;
610 }
611
612 if (capi_decode_conn_actv_ind(chan, skb)) {
613 printk("error in capi_decode_conn_actv_ind\n");
614 /* pcbit_fsm_event(dev, chan, EV_ERROR, NULL); */
615 break;
616 }
617 chan->r_refnum = refnum;
618 pcbit_fsm_event(dev, chan, EV_NET_CONN, NULL);
619 break;
620 case MSG_CONN_ACTV_CONF:
621
622 if (!(chan = capi_channel(dev, skb))) {
623 printk(KERN_WARNING
624 "CAPI header: unknown channel id\n");
625 break;
626 }
627
628 if (capi_decode_conn_actv_conf(chan, skb) == 0)
629 pcbit_fsm_event(dev, chan, EV_NET_CONN_ACK, NULL);
630
631 else
632 printk(KERN_DEBUG "decode_conn_actv_conf failed\n");
633 break;
634
635 case MSG_SELP_CONF:
636
637 if (!(chan = capi_channel(dev, skb))) {
638 printk(KERN_WARNING
639 "CAPI header: unknown channel id\n");
640 break;
641 }
642
643 if (!(err = capi_decode_sel_proto_conf(chan, skb)))
644 pcbit_fsm_event(dev, chan, EV_NET_SELP_RESP, NULL);
645 else {
646 /* Error */
647 printk("error %d - capi_decode_sel_proto_conf\n", err);
648 }
649 break;
650 case MSG_ACT_TRANSP_CONF:
651 if (!(chan = capi_channel(dev, skb))) {
652 printk(KERN_WARNING
653 "CAPI header: unknown channel id\n");
654 break;
655 }
656
657 if (!capi_decode_actv_trans_conf(chan, skb))
658 pcbit_fsm_event(dev, chan, EV_NET_ACTV_RESP, NULL);
659 break;
660
661 case MSG_DISC_IND:
662
663 if (!(chan = capi_channel(dev, skb))) {
664 printk(KERN_WARNING
665 "CAPI header: unknown channel id\n");
666 break;
667 }
668
669 if (!capi_decode_disc_ind(chan, skb))
670 pcbit_fsm_event(dev, chan, EV_NET_DISC, NULL);
671 else
672 printk(KERN_WARNING "capi_decode_disc_ind - error\n");
673 break;
674 case MSG_DISC_CONF:
675 if (!(chan = capi_channel(dev, skb))) {
676 printk(KERN_WARNING
677 "CAPI header: unknown channel id\n");
678 break;
679 }
680
681 if (!capi_decode_disc_ind(chan, skb))
682 pcbit_fsm_event(dev, chan, EV_NET_RELEASE, NULL);
683 else
684 printk(KERN_WARNING "capi_decode_disc_conf - error\n");
685 break;
686 case MSG_INFO_IND:
687#ifdef DEBUG
688 printk(KERN_DEBUG "received Info Indication - discarded\n");
689#endif
690 break;
691#ifdef DEBUG
692 case MSG_DEBUG_188:
693 capi_decode_debug_188(skb->data, skb->len);
694 break;
695
696 default:
697 printk(KERN_DEBUG "pcbit_l3_receive: unknown message %08lx\n",
698 msg);
699 break;
700#endif
701 }
702
703 kfree_skb(skb);
704
705}
706
707/*
708 * Single statbuf
709 * should be a statbuf per device
710 */
711
712static char statbuf[STATBUF_LEN];
713static int stat_st = 0;
714static int stat_end = 0;
715
716int pcbit_stat(u_char __user *buf, int len, int driver, int channel)
717{
718 int stat_count;
719 stat_count = stat_end - stat_st;
720
721 if (stat_count < 0)
722 stat_count = STATBUF_LEN - stat_st + stat_end;
723
724 /* FIXME: should we sleep and wait for more cookies ? */
725 if (len > stat_count)
726 len = stat_count;
727
728 if (stat_st < stat_end)
729 {
730 copy_to_user(buf, statbuf + stat_st, len);
731 stat_st += len;
732 }
733 else
734 {
735 if (len > STATBUF_LEN - stat_st)
736 {
737 copy_to_user(buf, statbuf + stat_st,
738 STATBUF_LEN - stat_st);
739 copy_to_user(buf, statbuf,
740 len - (STATBUF_LEN - stat_st));
741
742 stat_st = len - (STATBUF_LEN - stat_st);
743 }
744 else
745 {
746 copy_to_user(buf, statbuf + stat_st, len);
747
748 stat_st += len;
749
750 if (stat_st == STATBUF_LEN)
751 stat_st = 0;
752 }
753 }
754
755 if (stat_st == stat_end)
756 stat_st = stat_end = 0;
757
758 return len;
759}
760
761static void pcbit_logstat(struct pcbit_dev *dev, char *str)
762{
763 int i;
764 isdn_ctrl ictl;
765
766 for (i=stat_end; i<strlen(str); i++)
767 {
768 statbuf[i]=str[i];
769 stat_end = (stat_end + 1) % STATBUF_LEN;
770 if (stat_end == stat_st)
771 stat_st = (stat_st + 1) % STATBUF_LEN;
772 }
773
774 ictl.command=ISDN_STAT_STAVAIL;
775 ictl.driver=dev->id;
776 ictl.arg=strlen(str);
777 dev->dev_if->statcallb(&ictl);
778}
779
780extern char * isdn_state_table[];
781extern char * strisdnevent(unsigned short);
782
783
784void pcbit_state_change(struct pcbit_dev * dev, struct pcbit_chan * chan,
785 unsigned short i, unsigned short ev, unsigned short f)
786{
787 char buf[256];
788
789 sprintf(buf, "change on device: %d channel:%d\n%s -> %s -> %s\n",
790 dev->id, chan->id,
791 isdn_state_table[i], strisdnevent(ev), isdn_state_table[f]
792 );
793
794#ifdef DEBUG
795 printk("%s", buf);
796#endif
797
798 pcbit_logstat(dev, buf);
799}
800
801static void set_running_timeout(unsigned long ptr)
802{
803 struct pcbit_dev * dev;
804
805#ifdef DEBUG
806 printk(KERN_DEBUG "set_running_timeout\n");
807#endif
808 dev = (struct pcbit_dev *) ptr;
809
810 wake_up_interruptible(&dev->set_running_wq);
811}
812
813static int set_protocol_running(struct pcbit_dev * dev)
814{
815 isdn_ctrl ctl;
816
817 init_timer(&dev->set_running_timer);
818
819 dev->set_running_timer.function = &set_running_timeout;
820 dev->set_running_timer.data = (ulong) dev;
821 dev->set_running_timer.expires = jiffies + SET_RUN_TIMEOUT;
822
823 /* kick it */
824
825 dev->l2_state = L2_STARTING;
826
827 writeb((0x80U | ((dev->rcv_seq & 0x07) << 3) | (dev->send_seq & 0x07)),
828 dev->sh_mem + BANK4);
829
830 add_timer(&dev->set_running_timer);
831
832 interruptible_sleep_on(&dev->set_running_wq);
833
834 del_timer(&dev->set_running_timer);
835
836 if (dev->l2_state == L2_RUNNING)
837 {
838 printk(KERN_DEBUG "pcbit: running\n");
839
840 dev->unack_seq = dev->send_seq;
841
842 dev->writeptr = dev->sh_mem;
843 dev->readptr = dev->sh_mem + BANK2;
844
845 /* tell the good news to the upper layer */
846 ctl.driver = dev->id;
847 ctl.command = ISDN_STAT_RUN;
848
849 dev->dev_if->statcallb(&ctl);
850 }
851 else
852 {
853 printk(KERN_DEBUG "pcbit: initialization failed\n");
854 printk(KERN_DEBUG "pcbit: firmware not loaded\n");
855
856 dev->l2_state = L2_DOWN;
857
858#ifdef DEBUG
859 printk(KERN_DEBUG "Bank3 = %02x\n",
860 readb(dev->sh_mem + BANK3));
861#endif
862 writeb(0x40, dev->sh_mem + BANK4);
863
864 /* warn the upper layer */
865 ctl.driver = dev->id;
866 ctl.command = ISDN_STAT_STOP;
867
868 dev->dev_if->statcallb(&ctl);
869
870 return -EL2HLT; /* Level 2 halted */
871 }
872
873 return 0;
874}
875
876static int pcbit_ioctl(isdn_ctrl* ctl)
877{
878 struct pcbit_dev * dev;
879 struct pcbit_ioctl *cmd;
880
881 dev = finddev(ctl->driver);
882
883 if (!dev)
884 {
885 printk(KERN_DEBUG "pcbit_ioctl: unknown device\n");
886 return -ENODEV;
887 }
888
889 cmd = (struct pcbit_ioctl *) ctl->parm.num;
890
891 switch(ctl->arg) {
892 case PCBIT_IOCTL_GETSTAT:
893 cmd->info.l2_status = dev->l2_state;
894 break;
895
896 case PCBIT_IOCTL_STRLOAD:
897 if (dev->l2_state == L2_RUNNING)
898 return -EBUSY;
899
900 dev->unack_seq = dev->send_seq = dev->rcv_seq = 0;
901
902 dev->writeptr = dev->sh_mem;
903 dev->readptr = dev->sh_mem + BANK2;
904
905 dev->l2_state = L2_LOADING;
906 break;
907
908 case PCBIT_IOCTL_LWMODE:
909 if (dev->l2_state != L2_LOADING)
910 return -EINVAL;
911
912 dev->l2_state = L2_LWMODE;
913 break;
914
915 case PCBIT_IOCTL_FWMODE:
916 if (dev->l2_state == L2_RUNNING)
917 return -EBUSY;
918 dev->loadptr = LOAD_ZONE_START;
919 dev->l2_state = L2_FWMODE;
920
921 break;
922 case PCBIT_IOCTL_ENDLOAD:
923 if (dev->l2_state == L2_RUNNING)
924 return -EBUSY;
925 dev->l2_state = L2_DOWN;
926 break;
927
928 case PCBIT_IOCTL_SETBYTE:
929 if (dev->l2_state == L2_RUNNING)
930 return -EBUSY;
931
932 /* check addr */
933 if (cmd->info.rdp_byte.addr > BANK4)
934 return -EFAULT;
935
936 writeb(cmd->info.rdp_byte.value, dev->sh_mem + cmd->info.rdp_byte.addr);
937 break;
938 case PCBIT_IOCTL_GETBYTE:
939 if (dev->l2_state == L2_RUNNING)
940 return -EBUSY;
941
942 /* check addr */
943
944 if (cmd->info.rdp_byte.addr > BANK4)
945 {
946 printk("getbyte: invalid addr %04x\n", cmd->info.rdp_byte.addr);
947 return -EFAULT;
948 }
949
950 cmd->info.rdp_byte.value = readb(dev->sh_mem + cmd->info.rdp_byte.addr);
951 break;
952 case PCBIT_IOCTL_RUNNING:
953 if (dev->l2_state == L2_RUNNING)
954 return -EBUSY;
955 return set_protocol_running(dev);
956 break;
957 case PCBIT_IOCTL_WATCH188:
958 if (dev->l2_state != L2_LOADING)
959 return -EINVAL;
960 pcbit_l2_write(dev, MSG_WATCH188, 0x0001, NULL, 0);
961 break;
962 case PCBIT_IOCTL_PING188:
963 if (dev->l2_state != L2_LOADING)
964 return -EINVAL;
965 pcbit_l2_write(dev, MSG_PING188_REQ, 0x0001, NULL, 0);
966 break;
967 case PCBIT_IOCTL_APION:
968 if (dev->l2_state != L2_LOADING)
969 return -EINVAL;
970 pcbit_l2_write(dev, MSG_API_ON, 0x0001, NULL, 0);
971 break;
972 case PCBIT_IOCTL_STOP:
973 dev->l2_state = L2_DOWN;
974 writeb(0x40, dev->sh_mem + BANK4);
975 dev->rcv_seq = 0;
976 dev->send_seq = 0;
977 dev->unack_seq = 0;
978 break;
979 default:
980 printk("error: unknown ioctl\n");
981 break;
982 };
983 return 0;
984}
985
986/*
987 * MSN list handling
988 *
989 * if null reject all calls
990 * if first entry has null MSN accept all calls
991 */
992
993static void pcbit_clear_msn(struct pcbit_dev *dev)
994{
995 struct msn_entry *ptr, *back;
996
997 for (ptr=dev->msn_list; ptr; )
998 {
999 back = ptr->next;
1000 kfree(ptr);
1001 ptr = back;
1002 }
1003
1004 dev->msn_list = NULL;
1005}
1006
1007static void pcbit_set_msn(struct pcbit_dev *dev, char *list)
1008{
1009 struct msn_entry *ptr;
1010 struct msn_entry *back = NULL;
1011 char *cp, *sp;
1012 int len;
1013
1014 if (strlen(list) == 0) {
1015 ptr = kmalloc(sizeof(struct msn_entry), GFP_ATOMIC);
1016 if (!ptr) {
1017 printk(KERN_WARNING "kmalloc failed\n");
1018 return;
1019 }
1020
1021 ptr->msn = NULL;
1022
1023 ptr->next = dev->msn_list;
1024 dev->msn_list = ptr;
1025
1026 return;
1027 }
1028
1029 if (dev->msn_list)
1030 for (back=dev->msn_list; back->next; back=back->next);
1031
1032 sp = list;
1033
1034 do {
1035 cp=strchr(sp, ',');
1036 if (cp)
1037 len = cp - sp;
1038 else
1039 len = strlen(sp);
1040
1041 ptr = kmalloc(sizeof(struct msn_entry), GFP_ATOMIC);
1042
1043 if (!ptr) {
1044 printk(KERN_WARNING "kmalloc failed\n");
1045 return;
1046 }
1047 ptr->next = NULL;
1048
1049 ptr->msn = kmalloc(len, GFP_ATOMIC);
1050 if (!ptr->msn) {
1051 printk(KERN_WARNING "kmalloc failed\n");
1052 kfree(ptr);
1053 return;
1054 }
1055
1056 memcpy(ptr->msn, sp, len - 1);
1057 ptr->msn[len] = 0;
1058
1059#ifdef DEBUG
1060 printk(KERN_DEBUG "msn: %s\n", ptr->msn);
1061#endif
1062 if (dev->msn_list == NULL)
1063 dev->msn_list = ptr;
1064 else
1065 back->next = ptr;
1066 back = ptr;
1067 sp += len;
1068 } while(cp);
1069}
1070
1071/*
1072 * check if we do signal or reject an incoming call
1073 */
1074static int pcbit_check_msn(struct pcbit_dev *dev, char *msn)
1075{
1076 struct msn_entry *ptr;
1077
1078 for (ptr=dev->msn_list; ptr; ptr=ptr->next) {
1079
1080 if (ptr->msn == NULL)
1081 return 1;
1082
1083 if (strcmp(ptr->msn, msn) == 0)
1084 return 1;
1085 }
1086
1087 return 0;
1088}
diff --git a/drivers/isdn/pcbit/edss1.c b/drivers/isdn/pcbit/edss1.c
new file mode 100644
index 000000000000..93ca7de5670b
--- /dev/null
+++ b/drivers/isdn/pcbit/edss1.c
@@ -0,0 +1,325 @@
1/*
2 * DSS.1 Finite State Machine
3 * base: ITU-T Rec Q.931
4 *
5 * Copyright (C) 1996 Universidade de Lisboa
6 *
7 * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
8 *
9 * This software may be used and distributed according to the terms of
10 * the GNU General Public License, incorporated herein by reference.
11 */
12
13/*
14 * TODO: complete the FSM
15 * move state/event descriptions to a user space logger
16 */
17
18#include <linux/sched.h>
19#include <linux/string.h>
20#include <linux/kernel.h>
21
22#include <linux/types.h>
23#include <linux/slab.h>
24#include <linux/mm.h>
25#include <linux/skbuff.h>
26
27#include <linux/timer.h>
28#include <asm/io.h>
29
30#include <linux/isdnif.h>
31
32#include "pcbit.h"
33#include "edss1.h"
34#include "layer2.h"
35#include "callbacks.h"
36
37
38extern void pcbit_state_change(struct pcbit_dev *, struct pcbit_chan *,
39 unsigned short i, unsigned short ev,
40 unsigned short f);
41
42extern struct pcbit_dev * dev_pcbit[MAX_PCBIT_CARDS];
43
44char * isdn_state_table[] = {
45 "Closed",
46 "Call initiated",
47 "Overlap sending",
48 "Outgoing call proceeding",
49 "NOT DEFINED",
50 "Call delivered",
51 "Call present",
52 "Call received",
53 "Connect request",
54 "Incoming call proceeding",
55 "Active",
56 "Disconnect request",
57 "Disconnect indication",
58 "NOT DEFINED",
59 "NOT DEFINED",
60 "Suspend request",
61 "NOT DEFINED",
62 "Resume request",
63 "NOT DEFINED",
64 "Release Request",
65 "NOT DEFINED",
66 "NOT DEFINED",
67 "NOT DEFINED",
68 "NOT DEFINED",
69 "NOT DEFINED",
70 "Overlap receiving",
71 "Select protocol on B-Channel",
72 "Activate B-channel protocol"
73};
74
75#ifdef DEBUG_ERRS
76static
77struct CauseValue {
78 byte nr;
79 char *descr;
80} cvlist[]={
81 {0x01,"Unallocated (unassigned) number"},
82 {0x02,"No route to specified transit network"},
83 {0x03,"No route to destination"},
84 {0x04,"Send special information tone"},
85 {0x05,"Misdialled trunk prefix"},
86 {0x06,"Channel unacceptable"},
87 {0x07,"Channel awarded and being delivered in an established channel"},
88 {0x08,"Preemption"},
89 {0x09,"Preemption - circuit reserved for reuse"},
90 {0x10,"Normal call clearing"},
91 {0x11,"User busy"},
92 {0x12,"No user responding"},
93 {0x13,"No answer from user (user alerted)"},
94 {0x14,"Subscriber absent"},
95 {0x15,"Call rejected"},
96 {0x16,"Number changed"},
97 {0x1a,"non-selected user clearing"},
98 {0x1b,"Destination out of order"},
99 {0x1c,"Invalid number format (address incomplete)"},
100 {0x1d,"Facility rejected"},
101 {0x1e,"Response to Status enquiry"},
102 {0x1f,"Normal, unspecified"},
103 {0x22,"No circuit/channel available"},
104 {0x26,"Network out of order"},
105 {0x27,"Permanent frame mode connection out-of-service"},
106 {0x28,"Permanent frame mode connection operational"},
107 {0x29,"Temporary failure"},
108 {0x2a,"Switching equipment congestion"},
109 {0x2b,"Access information discarded"},
110 {0x2c,"Requested circuit/channel not available"},
111 {0x2e,"Precedence call blocked"},
112 {0x2f,"Resource unavailable, unspecified"},
113 {0x31,"Quality of service unavailable"},
114 {0x32,"Requested facility not subscribed"},
115 {0x35,"Outgoing calls barred within CUG"},
116 {0x37,"Incoming calls barred within CUG"},
117 {0x39,"Bearer capability not authorized"},
118 {0x3a,"Bearer capability not presently available"},
119 {0x3e,"Inconsistency in designated outgoing access information and subscriber class"},
120 {0x3f,"Service or option not available, unspecified"},
121 {0x41,"Bearer capability not implemented"},
122 {0x42,"Channel type not implemented"},
123 {0x43,"Requested facility not implemented"},
124 {0x44,"Only restricted digital information bearer capability is available"},
125 {0x4f,"Service or option not implemented"},
126 {0x51,"Invalid call reference value"},
127 {0x52,"Identified channel does not exist"},
128 {0x53,"A suspended call exists, but this call identity does not"},
129 {0x54,"Call identity in use"},
130 {0x55,"No call suspended"},
131 {0x56,"Call having the requested call identity has been cleared"},
132 {0x57,"User not member of CUG"},
133 {0x58,"Incompatible destination"},
134 {0x5a,"Non-existent CUG"},
135 {0x5b,"Invalid transit network selection"},
136 {0x5f,"Invalid message, unspecified"},
137 {0x60,"Mandatory information element is missing"},
138 {0x61,"Message type non-existent or not implemented"},
139 {0x62,"Message not compatible with call state or message type non-existent or not implemented"},
140 {0x63,"Information element/parameter non-existent or not implemented"},
141 {0x64,"Invalid information element contents"},
142 {0x65,"Message not compatible with call state"},
143 {0x66,"Recovery on timer expiry"},
144 {0x67,"Parameter non-existent or not implemented - passed on"},
145 {0x6e,"Message with unrecognized parameter discarded"},
146 {0x6f,"Protocol error, unspecified"},
147 {0x7f,"Interworking, unspecified"}
148};
149
150#endif
151
152static struct isdn_event_desc {
153 unsigned short ev;
154 char * desc;
155} isdn_event_table [] = {
156 {EV_USR_SETUP_REQ, "CC->L3: Setup Request"},
157 {EV_USR_SETUP_RESP, "CC->L3: Setup Response"},
158 {EV_USR_PROCED_REQ, "CC->L3: Proceeding Request"},
159 {EV_USR_RELEASE_REQ, "CC->L3: Release Request"},
160
161 {EV_NET_SETUP, "NET->TE: setup "},
162 {EV_NET_CALL_PROC, "NET->TE: call proceeding"},
163 {EV_NET_SETUP_ACK, "NET->TE: setup acknowledge (more info needed)"},
164 {EV_NET_CONN, "NET->TE: connect"},
165 {EV_NET_CONN_ACK, "NET->TE: connect acknowledge"},
166 {EV_NET_DISC, "NET->TE: disconnect indication"},
167 {EV_NET_RELEASE, "NET->TE: release"},
168 {EV_NET_RELEASE_COMP, "NET->TE: release complete"},
169 {EV_NET_SELP_RESP, "Board: Select B-channel protocol ack"},
170 {EV_NET_ACTV_RESP, "Board: Activate B-channel protocol ack"},
171 {EV_TIMER, "Timeout"},
172 {0, "NULL"}
173};
174
175char * strisdnevent(ushort ev)
176{
177 struct isdn_event_desc * entry;
178
179 for (entry = isdn_event_table; entry->ev; entry++)
180 if (entry->ev == ev)
181 break;
182
183 return entry->desc;
184}
185
186/*
187 * Euro ISDN finite state machine
188 */
189
190static struct fsm_timer_entry fsm_timers[] = {
191 {ST_CALL_PROC, 10},
192 {ST_DISC_REQ, 2},
193 {ST_ACTIVE_SELP, 5},
194 {ST_ACTIVE_ACTV, 5},
195 {ST_INCM_PROC, 10},
196 {ST_CONN_REQ, 2},
197 {0xff, 0}
198};
199
200static struct fsm_entry fsm_table[] = {
201/* Connect Phase */
202 /* Outgoing */
203 {ST_NULL, ST_CALL_INIT, EV_USR_SETUP_REQ, cb_out_1},
204
205 {ST_CALL_INIT, ST_OVER_SEND, EV_NET_SETUP_ACK, cb_notdone},
206 {ST_CALL_INIT, ST_CALL_PROC, EV_NET_CALL_PROC, NULL},
207 {ST_CALL_INIT, ST_NULL, EV_NET_DISC, cb_out_2},
208
209 {ST_CALL_PROC, ST_ACTIVE_SELP, EV_NET_CONN, cb_out_2},
210 {ST_CALL_PROC, ST_NULL, EV_NET_DISC, cb_disc_1},
211 {ST_CALL_PROC, ST_DISC_REQ, EV_USR_RELEASE_REQ, cb_disc_2},
212
213 /* Incoming */
214 {ST_NULL, ST_CALL_PRES, EV_NET_SETUP, NULL},
215
216 {ST_CALL_PRES, ST_INCM_PROC, EV_USR_PROCED_REQ, cb_in_1},
217 {ST_CALL_PRES, ST_DISC_REQ, EV_USR_RELEASE_REQ, cb_disc_2},
218
219 {ST_INCM_PROC, ST_CONN_REQ, EV_USR_SETUP_RESP, cb_in_2},
220 {ST_INCM_PROC, ST_DISC_REQ, EV_USR_RELEASE_REQ, cb_disc_2},
221
222 {ST_CONN_REQ, ST_ACTIVE_SELP, EV_NET_CONN_ACK, cb_in_3},
223
224 /* Active */
225 {ST_ACTIVE, ST_NULL, EV_NET_DISC, cb_disc_1},
226 {ST_ACTIVE, ST_DISC_REQ, EV_USR_RELEASE_REQ, cb_disc_2},
227 {ST_ACTIVE, ST_NULL, EV_NET_RELEASE, cb_disc_3},
228
229 /* Disconnect */
230
231 {ST_DISC_REQ, ST_NULL, EV_NET_DISC, cb_disc_1},
232 {ST_DISC_REQ, ST_NULL, EV_NET_RELEASE, cb_disc_3},
233
234 /* protocol selection */
235 {ST_ACTIVE_SELP, ST_ACTIVE_ACTV, EV_NET_SELP_RESP, cb_selp_1},
236 {ST_ACTIVE_SELP, ST_DISC_REQ, EV_USR_RELEASE_REQ, cb_disc_2},
237
238 {ST_ACTIVE_ACTV, ST_ACTIVE, EV_NET_ACTV_RESP, cb_open},
239 {ST_ACTIVE_ACTV, ST_DISC_REQ, EV_USR_RELEASE_REQ, cb_disc_2},
240
241 /* Timers */
242 {ST_CALL_PROC, ST_DISC_REQ, EV_TIMER, cb_disc_2},
243 {ST_DISC_REQ, ST_NULL, EV_TIMER, cb_disc_3},
244 {ST_ACTIVE_SELP, ST_DISC_REQ, EV_TIMER, cb_disc_2},
245 {ST_ACTIVE_ACTV, ST_DISC_REQ, EV_TIMER, cb_disc_2},
246 {ST_INCM_PROC, ST_DISC_REQ, EV_TIMER, cb_disc_2},
247 {ST_CONN_REQ, ST_CONN_REQ, EV_TIMER, cb_in_2},
248
249 {0xff, 0, 0, NULL}
250};
251
252
253static void pcbit_fsm_timer(unsigned long data)
254{
255 struct pcbit_dev *dev;
256 struct pcbit_chan *chan;
257
258 chan = (struct pcbit_chan *) data;
259
260 del_timer(&chan->fsm_timer);
261 chan->fsm_timer.function = NULL;
262
263 dev = chan2dev(chan);
264
265 if (dev == NULL) {
266 printk(KERN_WARNING "pcbit: timer for unknown device\n");
267 return;
268 }
269
270 pcbit_fsm_event(dev, chan, EV_TIMER, NULL);
271}
272
273
274void pcbit_fsm_event(struct pcbit_dev *dev, struct pcbit_chan *chan,
275 unsigned short event, struct callb_data *data)
276{
277 struct fsm_entry * action;
278 struct fsm_timer_entry *tentry;
279 unsigned long flags;
280
281 spin_lock_irqsave(&dev->lock, flags);
282
283 for (action = fsm_table; action->init != 0xff; action++)
284 if (action->init == chan->fsm_state && action->event == event)
285 break;
286
287 if (action->init == 0xff) {
288
289 spin_unlock_irqrestore(&dev->lock, flags);
290 printk(KERN_DEBUG "fsm error: event %x on state %x\n",
291 event, chan->fsm_state);
292 return;
293 }
294
295 if (chan->fsm_timer.function) {
296 del_timer(&chan->fsm_timer);
297 chan->fsm_timer.function = NULL;
298 }
299
300 chan->fsm_state = action->final;
301
302 pcbit_state_change(dev, chan, action->init, event, action->final);
303
304 for (tentry = fsm_timers; tentry->init != 0xff; tentry++)
305 if (tentry->init == chan->fsm_state)
306 break;
307
308 if (tentry->init != 0xff) {
309 init_timer(&chan->fsm_timer);
310 chan->fsm_timer.function = &pcbit_fsm_timer;
311 chan->fsm_timer.data = (ulong) chan;
312 chan->fsm_timer.expires = jiffies + tentry->timeout * HZ;
313 add_timer(&chan->fsm_timer);
314 }
315
316 spin_unlock_irqrestore(&dev->lock, flags);
317
318 if (action->callb)
319 action->callb(dev, chan, data);
320
321}
322
323
324
325
diff --git a/drivers/isdn/pcbit/edss1.h b/drivers/isdn/pcbit/edss1.h
new file mode 100644
index 000000000000..6bb587005b86
--- /dev/null
+++ b/drivers/isdn/pcbit/edss1.h
@@ -0,0 +1,99 @@
1/*
2 * DSS.1 module definitions
3 *
4 * Copyright (C) 1996 Universidade de Lisboa
5 *
6 * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
7 *
8 * This software may be used and distributed according to the terms of
9 * the GNU General Public License, incorporated herein by reference.
10 */
11
12#ifndef EDSS1_H
13#define EDSS1_H
14
15/* ISDN states */
16
17#define ST_NULL 0
18#define ST_CALL_INIT 1 /* Call initiated */
19#define ST_OVER_SEND 2 /* Overlap sending - Requests More Info 4 call */
20#define ST_CALL_PROC 3 /* Call Proceeding */
21#define ST_CALL_DELV 4
22#define ST_CALL_PRES 6 /* Call Present - Received CONN.IND */
23#define ST_CALL_RECV 7 /* Alerting sent */
24#define ST_CONN_REQ 8 /* Answered - waiting 4 CONN.CONF */
25#define ST_INCM_PROC 9
26#define ST_ACTIVE 10
27#define ST_DISC_REQ 11
28#define ST_DISC_IND 12
29#define ST_SUSP_REQ 15
30#define ST_RESM_REQ 17
31#define ST_RELS_REQ 19
32#define ST_OVER_RECV 25
33
34#define ST_ACTIVE_SELP 26 /* Select protocol on B-Channel */
35#define ST_ACTIVE_ACTV 27 /* Activate B-channel protocol */
36
37#define MAX_STATE ST_ACTIVE_ACTV
38
39#define EV_NULL 0
40#define EV_USR_SETUP_REQ 1
41#define EV_USR_SETUP_RESP 2
42#define EV_USR_PROCED_REQ 3
43#define EV_USR_RELEASE_REQ 4
44#define EV_USR_REJECT_REQ 4
45
46#define EV_NET_SETUP 16
47#define EV_NET_CALL_PROC 17
48#define EV_NET_SETUP_ACK 18
49#define EV_NET_CONN 19
50#define EV_NET_CONN_ACK 20
51
52#define EV_NET_SELP_RESP 21
53#define EV_NET_ACTV_RESP 22
54
55#define EV_NET_DISC 23
56#define EV_NET_RELEASE 24
57#define EV_NET_RELEASE_COMP 25
58
59#define EV_TIMER 26
60#define EV_ERROR 32
61
62/*
63 * Cause values
64 * only the ones we use
65 */
66
67#define CAUSE_NORMAL 0x10U
68#define CAUSE_NOCHAN 0x22U
69
70struct callb_data {
71 unsigned short type;
72 union {
73 struct ConnInfo {
74 char *CalledPN;
75 char *CallingPN;
76 } setup;
77 unsigned short cause;
78 } data;
79};
80
81struct fsm_entry {
82 unsigned short init;
83 unsigned short final;
84 unsigned short event;
85 void (*callb)(struct pcbit_dev *, struct pcbit_chan *, struct callb_data*);
86};
87
88struct fsm_timer_entry {
89 unsigned short init;
90 unsigned long timeout; /* in seconds */
91};
92
93
94extern void pcbit_fsm_event(struct pcbit_dev *, struct pcbit_chan *,
95 unsigned short event, struct callb_data *);
96#endif
97
98
99
diff --git a/drivers/isdn/pcbit/layer2.c b/drivers/isdn/pcbit/layer2.c
new file mode 100644
index 000000000000..ba766930f088
--- /dev/null
+++ b/drivers/isdn/pcbit/layer2.c
@@ -0,0 +1,732 @@
1/*
2 * PCBIT-D low-layer interface
3 *
4 * Copyright (C) 1996 Universidade de Lisboa
5 *
6 * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
7 *
8 * This software may be used and distributed according to the terms of
9 * the GNU General Public License, incorporated herein by reference.
10 */
11
12/*
13 * 19991203 - Fernando Carvalho - takion@superbofh.org
14 * Hacked to compile with egcs and run with current version of isdn modules
15*/
16
17/*
18 * Based on documentation provided by Inesc:
19 * - "Interface com bus do PC para o PCBIT e PCBIT-D", Inesc, Jan 93
20 */
21
22/*
23 * TODO: better handling of errors
24 * re-write/remove debug printks
25 */
26
27#include <linux/sched.h>
28#include <linux/string.h>
29#include <linux/kernel.h>
30#include <linux/types.h>
31#include <linux/slab.h>
32#include <linux/interrupt.h>
33#include <linux/workqueue.h>
34#include <linux/mm.h>
35#include <linux/skbuff.h>
36
37#include <linux/isdnif.h>
38
39#include <asm/system.h>
40#include <asm/io.h>
41
42
43#include "pcbit.h"
44#include "layer2.h"
45#include "edss1.h"
46
47#undef DEBUG_FRAG
48
49
50
51/*
52 * task queue struct
53 */
54
55
56
57/*
58 * Layer 3 packet demultiplexer
59 * drv.c
60 */
61
62extern void pcbit_l3_receive(struct pcbit_dev *dev, ulong msg,
63 struct sk_buff *skb,
64 ushort hdr_len, ushort refnum);
65
66/*
67 * Prototypes
68 */
69
70void pcbit_deliver(void *data);
71static void pcbit_transmit(struct pcbit_dev *dev);
72
73static void pcbit_recv_ack(struct pcbit_dev *dev, unsigned char ack);
74
75static void pcbit_l2_error(struct pcbit_dev *dev);
76static void pcbit_l2_active_conf(struct pcbit_dev *dev, u_char info);
77static void pcbit_l2_err_recover(unsigned long data);
78
79static void pcbit_firmware_bug(struct pcbit_dev *dev);
80
81static __inline__ void
82pcbit_sched_delivery(struct pcbit_dev *dev)
83{
84 schedule_work(&dev->qdelivery);
85}
86
87
88/*
89 * Called from layer3
90 */
91
92int
93pcbit_l2_write(struct pcbit_dev *dev, ulong msg, ushort refnum,
94 struct sk_buff *skb, unsigned short hdr_len)
95{
96 struct frame_buf *frame,
97 *ptr;
98 unsigned long flags;
99
100 if (dev->l2_state != L2_RUNNING && dev->l2_state != L2_LOADING) {
101 dev_kfree_skb(skb);
102 return -1;
103 }
104 if ((frame = (struct frame_buf *) kmalloc(sizeof(struct frame_buf),
105 GFP_ATOMIC)) == NULL) {
106 printk(KERN_WARNING "pcbit_2_write: kmalloc failed\n");
107 dev_kfree_skb(skb);
108 return -1;
109 }
110 frame->msg = msg;
111 frame->refnum = refnum;
112 frame->copied = 0;
113 frame->hdr_len = hdr_len;
114
115 if (skb)
116 frame->dt_len = skb->len - hdr_len;
117 else
118 frame->dt_len = 0;
119
120 frame->skb = skb;
121
122 frame->next = NULL;
123
124 spin_lock_irqsave(&dev->lock, flags);
125
126 if (dev->write_queue == NULL) {
127 dev->write_queue = frame;
128 spin_unlock_irqrestore(&dev->lock, flags);
129 pcbit_transmit(dev);
130 } else {
131 for (ptr = dev->write_queue; ptr->next; ptr = ptr->next);
132 ptr->next = frame;
133
134 spin_unlock_irqrestore(&dev->lock, flags);
135 }
136 return 0;
137}
138
139static __inline__ void
140pcbit_tx_update(struct pcbit_dev *dev, ushort len)
141{
142 u_char info;
143
144 dev->send_seq = (dev->send_seq + 1) % 8;
145
146 dev->fsize[dev->send_seq] = len;
147 info = 0;
148 info |= dev->rcv_seq << 3;
149 info |= dev->send_seq;
150
151 writeb(info, dev->sh_mem + BANK4);
152
153}
154
155/*
156 * called by interrupt service routine or by write_2
157 */
158
159static void
160pcbit_transmit(struct pcbit_dev *dev)
161{
162 struct frame_buf *frame = NULL;
163 unsigned char unacked;
164 int flen; /* fragment frame length including all headers */
165 int free;
166 int count,
167 cp_len;
168 unsigned long flags;
169 unsigned short tt;
170
171 if (dev->l2_state != L2_RUNNING && dev->l2_state != L2_LOADING)
172 return;
173
174 unacked = (dev->send_seq + (8 - dev->unack_seq)) & 0x07;
175
176 spin_lock_irqsave(&dev->lock, flags);
177
178 if (dev->free > 16 && dev->write_queue && unacked < 7) {
179
180 if (!dev->w_busy)
181 dev->w_busy = 1;
182 else {
183 spin_unlock_irqrestore(&dev->lock, flags);
184 return;
185 }
186
187
188 frame = dev->write_queue;
189 free = dev->free;
190
191 spin_unlock_irqrestore(&dev->lock, flags);
192
193 if (frame->copied == 0) {
194
195 /* Type 0 frame */
196
197 ulong msg;
198
199 if (frame->skb)
200 flen = FRAME_HDR_LEN + PREHDR_LEN + frame->skb->len;
201 else
202 flen = FRAME_HDR_LEN + PREHDR_LEN;
203
204 if (flen > free)
205 flen = free;
206
207 msg = frame->msg;
208
209 /*
210 * Board level 2 header
211 */
212
213 pcbit_writew(dev, flen - FRAME_HDR_LEN);
214
215 pcbit_writeb(dev, GET_MSG_CPU(msg));
216
217 pcbit_writeb(dev, GET_MSG_PROC(msg));
218
219 /* TH */
220 pcbit_writew(dev, frame->hdr_len + PREHDR_LEN);
221
222 /* TD */
223 pcbit_writew(dev, frame->dt_len);
224
225
226 /*
227 * Board level 3 fixed-header
228 */
229
230 /* LEN = TH */
231 pcbit_writew(dev, frame->hdr_len + PREHDR_LEN);
232
233 /* XX */
234 pcbit_writew(dev, 0);
235
236 /* C + S */
237 pcbit_writeb(dev, GET_MSG_CMD(msg));
238 pcbit_writeb(dev, GET_MSG_SCMD(msg));
239
240 /* NUM */
241 pcbit_writew(dev, frame->refnum);
242
243 count = FRAME_HDR_LEN + PREHDR_LEN;
244 } else {
245 /* Type 1 frame */
246
247 flen = 2 + (frame->skb->len - frame->copied);
248
249 if (flen > free)
250 flen = free;
251
252 /* TT */
253 tt = ((ushort) (flen - 2)) | 0x8000U; /* Type 1 */
254 pcbit_writew(dev, tt);
255
256 count = 2;
257 }
258
259 if (frame->skb) {
260 cp_len = frame->skb->len - frame->copied;
261 if (cp_len > flen - count)
262 cp_len = flen - count;
263
264 memcpy_topcbit(dev, frame->skb->data + frame->copied,
265 cp_len);
266 frame->copied += cp_len;
267 }
268 /* bookkeeping */
269 dev->free -= flen;
270 pcbit_tx_update(dev, flen);
271
272 spin_lock_irqsave(&dev->lock, flags);
273
274 if (frame->skb == NULL || frame->copied == frame->skb->len) {
275
276 dev->write_queue = frame->next;
277
278 if (frame->skb != NULL) {
279 /* free frame */
280 dev_kfree_skb(frame->skb);
281 }
282 kfree(frame);
283 }
284 dev->w_busy = 0;
285 spin_unlock_irqrestore(&dev->lock, flags);
286 } else {
287 spin_unlock_irqrestore(&dev->lock, flags);
288#ifdef DEBUG
289 printk(KERN_DEBUG "unacked %d free %d write_queue %s\n",
290 unacked, dev->free, dev->write_queue ? "not empty" :
291 "empty");
292#endif
293 }
294}
295
296
297/*
298 * deliver a queued frame to the upper layer
299 */
300
301void
302pcbit_deliver(void *data)
303{
304 struct frame_buf *frame;
305 unsigned long flags, msg;
306 struct pcbit_dev *dev = (struct pcbit_dev *) data;
307
308 spin_lock_irqsave(&dev->lock, flags);
309
310 while ((frame = dev->read_queue)) {
311 dev->read_queue = frame->next;
312 spin_unlock_irqrestore(&dev->lock, flags);
313
314 SET_MSG_CPU(msg, 0);
315 SET_MSG_PROC(msg, 0);
316 SET_MSG_CMD(msg, frame->skb->data[2]);
317 SET_MSG_SCMD(msg, frame->skb->data[3]);
318
319 frame->refnum = *((ushort *) frame->skb->data + 4);
320 frame->msg = *((ulong *) & msg);
321
322 skb_pull(frame->skb, 6);
323
324 pcbit_l3_receive(dev, frame->msg, frame->skb, frame->hdr_len,
325 frame->refnum);
326
327 kfree(frame);
328
329 spin_lock_irqsave(&dev->lock, flags);
330 }
331
332 spin_unlock_irqrestore(&dev->lock, flags);
333}
334
335/*
336 * Reads BANK 2 & Reassembles
337 */
338
339static void
340pcbit_receive(struct pcbit_dev *dev)
341{
342 unsigned short tt;
343 u_char cpu,
344 proc;
345 struct frame_buf *frame = NULL;
346 unsigned long flags;
347 u_char type1;
348
349 if (dev->l2_state != L2_RUNNING && dev->l2_state != L2_LOADING)
350 return;
351
352 tt = pcbit_readw(dev);
353
354 if ((tt & 0x7fffU) > 511) {
355 printk(KERN_INFO "pcbit: invalid frame length -> TT=%04x\n",
356 tt);
357 pcbit_l2_error(dev);
358 return;
359 }
360 if (!(tt & 0x8000U)) { /* Type 0 */
361 type1 = 0;
362
363 if (dev->read_frame) {
364 printk(KERN_DEBUG "pcbit_receive: Type 0 frame and read_frame != NULL\n");
365 /* discard previous queued frame */
366 if (dev->read_frame->skb)
367 kfree_skb(dev->read_frame->skb);
368 kfree(dev->read_frame);
369 dev->read_frame = NULL;
370 }
371 frame = kmalloc(sizeof(struct frame_buf), GFP_ATOMIC);
372
373 if (frame == NULL) {
374 printk(KERN_WARNING "kmalloc failed\n");
375 return;
376 }
377 memset(frame, 0, sizeof(struct frame_buf));
378
379 cpu = pcbit_readb(dev);
380 proc = pcbit_readb(dev);
381
382
383 if (cpu != 0x06 && cpu != 0x02) {
384 printk(KERN_DEBUG "pcbit: invalid cpu value\n");
385 kfree(frame);
386 pcbit_l2_error(dev);
387 return;
388 }
389 /*
390 * we discard cpu & proc on receiving
391 * but we read it to update the pointer
392 */
393
394 frame->hdr_len = pcbit_readw(dev);
395 frame->dt_len = pcbit_readw(dev);
396
397 /*
398 * 0 sized packet
399 * I don't know if they are an error or not...
400 * But they are very frequent
401 * Not documented
402 */
403
404 if (frame->hdr_len == 0) {
405 kfree(frame);
406#ifdef DEBUG
407 printk(KERN_DEBUG "0 sized frame\n");
408#endif
409 pcbit_firmware_bug(dev);
410 return;
411 }
412 /* sanity check the length values */
413 if (frame->hdr_len > 1024 || frame->dt_len > 2048) {
414#ifdef DEBUG
415 printk(KERN_DEBUG "length problem: ");
416 printk(KERN_DEBUG "TH=%04x TD=%04x\n",
417 frame->hdr_len,
418 frame->dt_len);
419#endif
420 pcbit_l2_error(dev);
421 kfree(frame);
422 return;
423 }
424 /* minimum frame read */
425
426 frame->skb = dev_alloc_skb(frame->hdr_len + frame->dt_len +
427 ((frame->hdr_len + 15) & ~15));
428
429 if (!frame->skb) {
430 printk(KERN_DEBUG "pcbit_receive: out of memory\n");
431 kfree(frame);
432 return;
433 }
434 /* 16 byte alignment for IP */
435 if (frame->dt_len)
436 skb_reserve(frame->skb, (frame->hdr_len + 15) & ~15);
437
438 } else {
439 /* Type 1 */
440 type1 = 1;
441 tt &= 0x7fffU;
442
443 if (!(frame = dev->read_frame)) {
444 printk("Type 1 frame and no frame queued\n");
445 /* usually after an error: toss frame */
446 dev->readptr += tt;
447 if (dev->readptr > dev->sh_mem + BANK2 + BANKLEN)
448 dev->readptr -= BANKLEN;
449 return;
450
451 }
452 }
453
454 memcpy_frompcbit(dev, skb_put(frame->skb, tt), tt);
455
456 frame->copied += tt;
457 spin_lock_irqsave(&dev->lock, flags);
458 if (frame->copied == frame->hdr_len + frame->dt_len) {
459
460 if (type1) {
461 dev->read_frame = NULL;
462 }
463 if (dev->read_queue) {
464 struct frame_buf *ptr;
465 for (ptr = dev->read_queue; ptr->next; ptr = ptr->next);
466 ptr->next = frame;
467 } else
468 dev->read_queue = frame;
469
470 } else {
471 dev->read_frame = frame;
472 }
473 spin_unlock_irqrestore(&dev->lock, flags);
474}
475
476/*
477 * The board sends 0 sized frames
478 * They are TDATA_CONFs that get messed up somehow
479 * gotta send a fake acknowledgment to the upper layer somehow
480 */
481
482static __inline__ void
483pcbit_fake_conf(struct pcbit_dev *dev, struct pcbit_chan *chan)
484{
485 isdn_ctrl ictl;
486
487 if (chan->queued) {
488 chan->queued--;
489
490 ictl.driver = dev->id;
491 ictl.command = ISDN_STAT_BSENT;
492 ictl.arg = chan->id;
493 dev->dev_if->statcallb(&ictl);
494 }
495}
496
497static void
498pcbit_firmware_bug(struct pcbit_dev *dev)
499{
500 struct pcbit_chan *chan;
501
502 chan = dev->b1;
503
504 if (chan->fsm_state == ST_ACTIVE) {
505 pcbit_fake_conf(dev, chan);
506 }
507 chan = dev->b2;
508
509 if (chan->fsm_state == ST_ACTIVE) {
510 pcbit_fake_conf(dev, chan);
511 }
512}
513
514irqreturn_t
515pcbit_irq_handler(int interrupt, void *devptr, struct pt_regs *regs)
516{
517 struct pcbit_dev *dev;
518 u_char info,
519 ack_seq,
520 read_seq;
521
522 dev = (struct pcbit_dev *) devptr;
523
524 if (!dev) {
525 printk(KERN_WARNING "pcbit_irq_handler: wrong device\n");
526 return IRQ_NONE;
527 }
528 if (dev->interrupt) {
529 printk(KERN_DEBUG "pcbit: reentering interrupt hander\n");
530 return IRQ_HANDLED;
531 }
532 dev->interrupt = 1;
533
534 info = readb(dev->sh_mem + BANK3);
535
536 if (dev->l2_state == L2_STARTING || dev->l2_state == L2_ERROR) {
537 pcbit_l2_active_conf(dev, info);
538 dev->interrupt = 0;
539 return IRQ_HANDLED;
540 }
541 if (info & 0x40U) { /* E bit set */
542#ifdef DEBUG
543 printk(KERN_DEBUG "pcbit_irq_handler: E bit on\n");
544#endif
545 pcbit_l2_error(dev);
546 dev->interrupt = 0;
547 return IRQ_HANDLED;
548 }
549 if (dev->l2_state != L2_RUNNING && dev->l2_state != L2_LOADING) {
550 dev->interrupt = 0;
551 return IRQ_HANDLED;
552 }
553 ack_seq = (info >> 3) & 0x07U;
554 read_seq = (info & 0x07U);
555
556 dev->interrupt = 0;
557
558 if (read_seq != dev->rcv_seq) {
559 while (read_seq != dev->rcv_seq) {
560 pcbit_receive(dev);
561 dev->rcv_seq = (dev->rcv_seq + 1) % 8;
562 }
563 pcbit_sched_delivery(dev);
564 }
565 if (ack_seq != dev->unack_seq) {
566 pcbit_recv_ack(dev, ack_seq);
567 }
568 info = dev->rcv_seq << 3;
569 info |= dev->send_seq;
570
571 writeb(info, dev->sh_mem + BANK4);
572 return IRQ_HANDLED;
573}
574
575
576static void
577pcbit_l2_active_conf(struct pcbit_dev *dev, u_char info)
578{
579 u_char state;
580
581 state = dev->l2_state;
582
583#ifdef DEBUG
584 printk(KERN_DEBUG "layer2_active_confirm\n");
585#endif
586
587
588 if (info & 0x80U) {
589 dev->rcv_seq = info & 0x07U;
590 dev->l2_state = L2_RUNNING;
591 } else
592 dev->l2_state = L2_DOWN;
593
594 if (state == L2_STARTING)
595 wake_up_interruptible(&dev->set_running_wq);
596
597 if (state == L2_ERROR && dev->l2_state == L2_RUNNING) {
598 pcbit_transmit(dev);
599 }
600}
601
602static void
603pcbit_l2_err_recover(unsigned long data)
604{
605
606 struct pcbit_dev *dev;
607 struct frame_buf *frame;
608
609 dev = (struct pcbit_dev *) data;
610
611 del_timer(&dev->error_recover_timer);
612 if (dev->w_busy || dev->r_busy) {
613 init_timer(&dev->error_recover_timer);
614 dev->error_recover_timer.expires = jiffies + ERRTIME;
615 add_timer(&dev->error_recover_timer);
616 return;
617 }
618 dev->w_busy = dev->r_busy = 1;
619
620 if (dev->read_frame) {
621 if (dev->read_frame->skb)
622 kfree_skb(dev->read_frame->skb);
623 kfree(dev->read_frame);
624 dev->read_frame = NULL;
625 }
626 if (dev->write_queue) {
627 frame = dev->write_queue;
628#ifdef FREE_ON_ERROR
629 dev->write_queue = dev->write_queue->next;
630
631 if (frame->skb) {
632 dev_kfree_skb(frame->skb);
633 }
634 kfree(frame);
635#else
636 frame->copied = 0;
637#endif
638 }
639 dev->rcv_seq = dev->send_seq = dev->unack_seq = 0;
640 dev->free = 511;
641 dev->l2_state = L2_ERROR;
642
643 /* this is an hack... */
644 pcbit_firmware_bug(dev);
645
646 dev->writeptr = dev->sh_mem;
647 dev->readptr = dev->sh_mem + BANK2;
648
649 writeb((0x80U | ((dev->rcv_seq & 0x07) << 3) | (dev->send_seq & 0x07)),
650 dev->sh_mem + BANK4);
651 dev->w_busy = dev->r_busy = 0;
652
653}
654
655static void
656pcbit_l2_error(struct pcbit_dev *dev)
657{
658 if (dev->l2_state == L2_RUNNING) {
659
660 printk(KERN_INFO "pcbit: layer 2 error\n");
661
662#ifdef DEBUG
663 log_state(dev);
664#endif
665
666 dev->l2_state = L2_DOWN;
667
668 init_timer(&dev->error_recover_timer);
669 dev->error_recover_timer.function = &pcbit_l2_err_recover;
670 dev->error_recover_timer.data = (ulong) dev;
671 dev->error_recover_timer.expires = jiffies + ERRTIME;
672 add_timer(&dev->error_recover_timer);
673 }
674}
675
676/*
677 * Description:
678 * if board acks frames
679 * update dev->free
680 * call pcbit_transmit to write possible queued frames
681 */
682
683static void
684pcbit_recv_ack(struct pcbit_dev *dev, unsigned char ack)
685{
686 int i,
687 count;
688 int unacked;
689
690 unacked = (dev->send_seq + (8 - dev->unack_seq)) & 0x07;
691
692 /* dev->unack_seq < ack <= dev->send_seq; */
693
694 if (unacked) {
695
696 if (dev->send_seq > dev->unack_seq) {
697 if (ack <= dev->unack_seq || ack > dev->send_seq) {
698 printk(KERN_DEBUG
699 "layer 2 ack unacceptable - dev %d",
700 dev->id);
701
702 pcbit_l2_error(dev);
703 } else if (ack > dev->send_seq && ack <= dev->unack_seq) {
704 printk(KERN_DEBUG
705 "layer 2 ack unacceptable - dev %d",
706 dev->id);
707 pcbit_l2_error(dev);
708 }
709 }
710 /* ack is acceptable */
711
712
713 i = dev->unack_seq;
714
715 do {
716 dev->unack_seq = i = (i + 1) % 8;
717 dev->free += dev->fsize[i];
718 } while (i != ack);
719
720 count = 0;
721 while (count < 7 && dev->write_queue) {
722 u8 lsend_seq = dev->send_seq;
723
724 pcbit_transmit(dev);
725
726 if (dev->send_seq == lsend_seq)
727 break;
728 count++;
729 }
730 } else
731 printk(KERN_DEBUG "recv_ack: unacked = 0\n");
732}
diff --git a/drivers/isdn/pcbit/layer2.h b/drivers/isdn/pcbit/layer2.h
new file mode 100644
index 000000000000..0d99da3a3e2b
--- /dev/null
+++ b/drivers/isdn/pcbit/layer2.h
@@ -0,0 +1,288 @@
1/*
2 * PCBIT-D low-layer interface definitions
3 *
4 * Copyright (C) 1996 Universidade de Lisboa
5 *
6 * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
7 *
8 * This software may be used and distributed according to the terms of
9 * the GNU General Public License, incorporated herein by reference.
10 */
11
12/*
13 * 19991203 - Fernando Carvalho - takion@superbofh.org
14 * Hacked to compile with egcs and run with current version of isdn modules
15*/
16
17#ifndef LAYER2_H
18#define LAYER2_H
19
20#include <linux/interrupt.h>
21
22#include <asm/byteorder.h>
23
24#define BANK1 0x0000U /* PC -> Board */
25#define BANK2 0x01ffU /* Board -> PC */
26#define BANK3 0x03feU /* Att Board */
27#define BANK4 0x03ffU /* Att PC */
28
29#define BANKLEN 0x01FFU
30
31#define LOAD_ZONE_START 0x03f8U
32#define LOAD_ZONE_END 0x03fdU
33
34#define LOAD_RETRY 18000000
35
36
37
38/* TAM - XX - C - S - NUM */
39#define PREHDR_LEN 8
40/* TT - M - I - TH - TD */
41#define FRAME_HDR_LEN 8
42
43#define MSG_CONN_REQ 0x08000100
44#define MSG_CONN_CONF 0x00000101
45#define MSG_CONN_IND 0x00000102
46#define MSG_CONN_RESP 0x08000103
47
48#define MSG_CONN_ACTV_REQ 0x08000300
49#define MSG_CONN_ACTV_CONF 0x00000301
50#define MSG_CONN_ACTV_IND 0x00000302
51#define MSG_CONN_ACTV_RESP 0x08000303
52
53#define MSG_DISC_REQ 0x08000400
54#define MSG_DISC_CONF 0x00000401
55#define MSG_DISC_IND 0x00000402
56#define MSG_DISC_RESP 0x08000403
57
58#define MSG_TDATA_REQ 0x0908E200
59#define MSG_TDATA_CONF 0x0000E201
60#define MSG_TDATA_IND 0x0000E202
61#define MSG_TDATA_RESP 0x0908E203
62
63#define MSG_SELP_REQ 0x09004000
64#define MSG_SELP_CONF 0x00004001
65
66#define MSG_ACT_TRANSP_REQ 0x0908E000
67#define MSG_ACT_TRANSP_CONF 0x0000E001
68
69#define MSG_STPROT_REQ 0x09004100
70#define MSG_STPROT_CONF 0x00004101
71
72#define MSG_PING188_REQ 0x09030500
73#define MSG_PING188_CONF 0x000005bc
74
75#define MSG_WATCH188 0x09030400
76
77#define MSG_API_ON 0x08020102
78#define MSG_POOL_PCBIT 0x08020400
79#define MSG_POOL_PCBIT_CONF 0x00000401
80
81#define MSG_INFO_IND 0x00002602
82#define MSG_INFO_RESP 0x08002603
83
84#define MSG_DEBUG_188 0x0000ff00
85
86/*
87
88 long 4 3 2 1
89 Intel 1 2 3 4
90*/
91
92#ifdef __LITTLE_ENDIAN
93#define SET_MSG_SCMD(msg, ch) (msg = (msg & 0xffffff00) | (((ch) & 0xff)))
94#define SET_MSG_CMD(msg, ch) (msg = (msg & 0xffff00ff) | (((ch) & 0xff) << 8))
95#define SET_MSG_PROC(msg, ch) (msg = (msg & 0xff00ffff) | (((ch) & 0xff) << 16))
96#define SET_MSG_CPU(msg, ch) (msg = (msg & 0x00ffffff) | (((ch) & 0xff) << 24))
97
98#define GET_MSG_SCMD(msg) ((msg) & 0xFF)
99#define GET_MSG_CMD(msg) ((msg) >> 8 & 0xFF)
100#define GET_MSG_PROC(msg) ((msg) >> 16 & 0xFF)
101#define GET_MSG_CPU(msg) ((msg) >> 24)
102
103#else
104#error "Non-Intel CPU"
105#endif
106
107#define MAX_QUEUED 7
108
109#define SCHED_READ 0x01
110#define SCHED_WRITE 0x02
111
112#define SET_RUN_TIMEOUT 2*HZ /* 2 seconds */
113
114struct frame_buf {
115 ulong msg;
116 unsigned int refnum;
117 unsigned int dt_len;
118 unsigned int hdr_len;
119 struct sk_buff *skb;
120 unsigned int copied;
121 struct frame_buf * next;
122};
123
124extern int pcbit_l2_write(struct pcbit_dev * dev, ulong msg, ushort refnum,
125 struct sk_buff *skb, unsigned short hdr_len);
126
127extern irqreturn_t pcbit_irq_handler(int interrupt, void *, struct pt_regs *regs);
128
129extern struct pcbit_dev * dev_pcbit[MAX_PCBIT_CARDS];
130
131#ifdef DEBUG
132static __inline__ void log_state(struct pcbit_dev *dev) {
133 printk(KERN_DEBUG "writeptr = %ld\n",
134 (ulong) (dev->writeptr - dev->sh_mem));
135 printk(KERN_DEBUG "readptr = %ld\n",
136 (ulong) (dev->readptr - (dev->sh_mem + BANK2)));
137 printk(KERN_DEBUG "{rcv_seq=%01x, send_seq=%01x, unack_seq=%01x}\n",
138 dev->rcv_seq, dev->send_seq, dev->unack_seq);
139}
140#endif
141
142static __inline__ struct pcbit_dev * chan2dev(struct pcbit_chan * chan)
143{
144 struct pcbit_dev * dev;
145 int i;
146
147
148 for (i=0; i<MAX_PCBIT_CARDS; i++)
149 if ((dev=dev_pcbit[i]))
150 if (dev->b1 == chan || dev->b2 == chan)
151 return dev;
152 return NULL;
153
154}
155
156static __inline__ struct pcbit_dev * finddev(int id)
157{
158 struct pcbit_dev * dev;
159 int i;
160
161 for (i=0; i<MAX_PCBIT_CARDS; i++)
162 if ((dev=dev_pcbit[i]))
163 if (dev->id == id)
164 return dev;
165 return NULL;
166}
167
168
169/*
170 * Support routines for reading and writing in the board
171 */
172
173static __inline__ void pcbit_writeb(struct pcbit_dev *dev, unsigned char dt)
174{
175 writeb(dt, dev->writeptr++);
176 if (dev->writeptr == dev->sh_mem + BANKLEN)
177 dev->writeptr = dev->sh_mem;
178}
179
180static __inline__ void pcbit_writew(struct pcbit_dev *dev, unsigned short dt)
181{
182 int dist;
183
184 dist = BANKLEN - (dev->writeptr - dev->sh_mem);
185 switch (dist) {
186 case 2:
187 writew(dt, dev->writeptr);
188 dev->writeptr = dev->sh_mem;
189 break;
190 case 1:
191 writeb((u_char) (dt & 0x00ffU), dev->writeptr);
192 dev->writeptr = dev->sh_mem;
193 writeb((u_char) (dt >> 8), dev->writeptr++);
194 break;
195 default:
196 writew(dt, dev->writeptr);
197 dev->writeptr += 2;
198 break;
199 };
200}
201
202static __inline__ void memcpy_topcbit(struct pcbit_dev * dev, u_char * data,
203 int len)
204{
205 int diff;
206
207 diff = len - (BANKLEN - (dev->writeptr - dev->sh_mem) );
208
209 if (diff > 0)
210 {
211 memcpy_toio(dev->writeptr, data, len - diff);
212 memcpy_toio(dev->sh_mem, data + (len - diff), diff);
213 dev->writeptr = dev->sh_mem + diff;
214 }
215 else
216 {
217 memcpy_toio(dev->writeptr, data, len);
218
219 dev->writeptr += len;
220 if (diff == 0)
221 dev->writeptr = dev->sh_mem;
222 }
223}
224
225static __inline__ unsigned char pcbit_readb(struct pcbit_dev *dev)
226{
227 unsigned char val;
228
229 val = readb(dev->readptr++);
230 if (dev->readptr == dev->sh_mem + BANK2 + BANKLEN)
231 dev->readptr = dev->sh_mem + BANK2;
232
233 return val;
234}
235
236static __inline__ unsigned short pcbit_readw(struct pcbit_dev *dev)
237{
238 int dist;
239 unsigned short val;
240
241 dist = BANKLEN - ( dev->readptr - (dev->sh_mem + BANK2 ) );
242 switch (dist) {
243 case 2:
244 val = readw(dev->readptr);
245 dev->readptr = dev->sh_mem + BANK2;
246 break;
247 case 1:
248 val = readb(dev->readptr);
249 dev->readptr = dev->sh_mem + BANK2;
250 val = (readb(dev->readptr++) << 8) | val;
251 break;
252 default:
253 val = readw(dev->readptr);
254 dev->readptr += 2;
255 break;
256 };
257 return val;
258}
259
260static __inline__ void memcpy_frompcbit(struct pcbit_dev * dev, u_char * data, int len)
261{
262 int diff;
263
264 diff = len - (BANKLEN - (dev->readptr - (dev->sh_mem + BANK2) ) );
265 if (diff > 0)
266 {
267 memcpy_fromio(data, dev->readptr, len - diff);
268 memcpy_fromio(data + (len - diff), dev->sh_mem + BANK2 , diff);
269 dev->readptr = dev->sh_mem + BANK2 + diff;
270 }
271 else
272 {
273 memcpy_fromio(data, dev->readptr, len);
274 dev->readptr += len;
275 if (diff == 0)
276 dev->readptr = dev->sh_mem + BANK2;
277 }
278}
279
280
281#endif
282
283
284
285
286
287
288
diff --git a/drivers/isdn/pcbit/module.c b/drivers/isdn/pcbit/module.c
new file mode 100644
index 000000000000..282073a35d6a
--- /dev/null
+++ b/drivers/isdn/pcbit/module.c
@@ -0,0 +1,130 @@
1/*
2 * PCBIT-D module support
3 *
4 * Copyright (C) 1996 Universidade de Lisboa
5 *
6 * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
7 *
8 * This software may be used and distributed according to the terms of
9 * the GNU General Public License, incorporated herein by reference.
10 */
11
12#include <linux/module.h>
13#include <linux/init.h>
14#include <linux/sched.h>
15#include <linux/string.h>
16#include <linux/kernel.h>
17#include <linux/skbuff.h>
18
19#include <linux/isdnif.h>
20#include "pcbit.h"
21
22MODULE_DESCRIPTION("ISDN4Linux: Driver for PCBIT-T card");
23MODULE_AUTHOR("Pedro Roque Marques");
24MODULE_LICENSE("GPL");
25
26static int mem[MAX_PCBIT_CARDS];
27static int irq[MAX_PCBIT_CARDS];
28
29module_param_array(mem, int, NULL, 0);
30module_param_array(irq, int, NULL, 0);
31
32static int num_boards;
33struct pcbit_dev * dev_pcbit[MAX_PCBIT_CARDS];
34
35extern void pcbit_terminate(int board);
36extern int pcbit_init_dev(int board, int mem_base, int irq);
37
38static int __init pcbit_init(void)
39{
40 int board;
41
42 num_boards = 0;
43
44 printk(KERN_NOTICE
45 "PCBIT-D device driver v 0.5-fjpc0 19991204 - "
46 "Copyright (C) 1996 Universidade de Lisboa\n");
47
48 if (mem[0] || irq[0])
49 {
50 for (board=0; board < MAX_PCBIT_CARDS && mem[board] && irq[board]; board++)
51 {
52 if (!mem[board])
53 mem[board] = 0xD0000;
54 if (!irq[board])
55 irq[board] = 5;
56
57 if (pcbit_init_dev(board, mem[board], irq[board]) == 0)
58 num_boards++;
59
60 else
61 {
62 printk(KERN_WARNING
63 "pcbit_init failed for dev %d",
64 board + 1);
65 return -EIO;
66 }
67 }
68 }
69
70 /* Hardcoded default settings detection */
71
72 if (!num_boards)
73 {
74 printk(KERN_INFO
75 "Trying to detect board using default settings\n");
76 if (pcbit_init_dev(0, 0xD0000, 5) == 0)
77 num_boards++;
78 else
79 return -EIO;
80 }
81 return 0;
82}
83
84static void __exit pcbit_exit(void)
85{
86#ifdef MODULE
87 int board;
88
89 for (board = 0; board < num_boards; board++)
90 pcbit_terminate(board);
91 printk(KERN_NOTICE
92 "PCBIT-D module unloaded\n");
93#endif
94}
95
96#ifndef MODULE
97#define MAX_PARA (MAX_PCBIT_CARDS * 2)
98static int __init pcbit_setup(char *line)
99{
100 int i, j, argc;
101 char *str;
102 int ints[MAX_PARA+1];
103
104 str = get_options(line, MAX_PARA, ints);
105 argc = ints[0];
106 i = 0;
107 j = 1;
108
109 while (argc && (i<MAX_PCBIT_CARDS)) {
110
111 if (argc) {
112 mem[i] = ints[j];
113 j++; argc--;
114 }
115
116 if (argc) {
117 irq[i] = ints[j];
118 j++; argc--;
119 }
120
121 i++;
122 }
123 return(1);
124}
125__setup("pcbit=", pcbit_setup);
126#endif
127
128module_init(pcbit_init);
129module_exit(pcbit_exit);
130
diff --git a/drivers/isdn/pcbit/pcbit.h b/drivers/isdn/pcbit/pcbit.h
new file mode 100644
index 000000000000..388bacefd23a
--- /dev/null
+++ b/drivers/isdn/pcbit/pcbit.h
@@ -0,0 +1,169 @@
1/*
2 * PCBIT-D device driver definitions
3 *
4 * Copyright (C) 1996 Universidade de Lisboa
5 *
6 * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
7 *
8 * This software may be used and distributed according to the terms of
9 * the GNU General Public License, incorporated herein by reference.
10 */
11
12#ifndef PCBIT_H
13#define PCBIT_H
14
15#include <linux/workqueue.h>
16
17#define MAX_PCBIT_CARDS 4
18
19
20#define BLOCK_TIMER
21
22#ifdef __KERNEL__
23
24struct pcbit_chan {
25 unsigned short id;
26 unsigned short callref; /* Call Reference */
27 unsigned char proto; /* layer2protocol */
28 unsigned char queued; /* unacked data messages */
29 unsigned char layer2link; /* used in TData */
30 unsigned char snum; /* used in TData */
31 unsigned short s_refnum;
32 unsigned short r_refnum;
33 unsigned short fsm_state;
34 struct timer_list fsm_timer;
35#ifdef BLOCK_TIMER
36 struct timer_list block_timer;
37#endif
38};
39
40struct msn_entry {
41 char *msn;
42 struct msn_entry * next;
43};
44
45struct pcbit_dev {
46 /* board */
47
48 volatile unsigned char __iomem *sh_mem; /* RDP address */
49 unsigned long ph_mem;
50 unsigned int irq;
51 unsigned int id;
52 unsigned int interrupt; /* set during interrupt
53 processing */
54 spinlock_t lock;
55 /* isdn4linux */
56
57 struct msn_entry * msn_list; /* ISDN address list */
58
59 isdn_if * dev_if;
60
61 ushort ll_hdrlen;
62 ushort hl_hdrlen;
63
64 /* link layer */
65 unsigned char l2_state;
66
67 struct frame_buf *read_queue;
68 struct frame_buf *read_frame;
69 struct frame_buf *write_queue;
70
71 /* Protocol start */
72 wait_queue_head_t set_running_wq;
73 struct timer_list set_running_timer;
74
75 struct timer_list error_recover_timer;
76
77 struct work_struct qdelivery;
78
79 u_char w_busy;
80 u_char r_busy;
81
82 volatile unsigned char __iomem *readptr;
83 volatile unsigned char __iomem *writeptr;
84
85 ushort loadptr;
86
87 unsigned short fsize[8]; /* sent layer2 frames size */
88
89 unsigned char send_seq;
90 unsigned char rcv_seq;
91 unsigned char unack_seq;
92
93 unsigned short free;
94
95 /* channels */
96
97 struct pcbit_chan *b1;
98 struct pcbit_chan *b2;
99};
100
101#define STATS_TIMER (10*HZ)
102#define ERRTIME (HZ/10)
103
104/* MRU */
105#define MAXBUFSIZE 1534
106#define MRU MAXBUFSIZE
107
108#define STATBUF_LEN 2048
109/*
110 *
111 */
112
113#endif /* __KERNEL__ */
114
115/* isdn_ctrl only allows a long sized argument */
116
117struct pcbit_ioctl {
118 union {
119 struct byte_op {
120 ushort addr;
121 ushort value;
122 } rdp_byte;
123 unsigned long l2_status;
124 } info;
125};
126
127
128
129#define PCBIT_IOCTL_GETSTAT 0x01 /* layer2 status */
130#define PCBIT_IOCTL_LWMODE 0x02 /* linear write mode */
131#define PCBIT_IOCTL_STRLOAD 0x03 /* start load mode */
132#define PCBIT_IOCTL_ENDLOAD 0x04 /* end load mode */
133#define PCBIT_IOCTL_SETBYTE 0x05 /* set byte */
134#define PCBIT_IOCTL_GETBYTE 0x06 /* get byte */
135#define PCBIT_IOCTL_RUNNING 0x07 /* set protocol running */
136#define PCBIT_IOCTL_WATCH188 0x08 /* set watch 188 */
137#define PCBIT_IOCTL_PING188 0x09 /* ping 188 */
138#define PCBIT_IOCTL_FWMODE 0x0A /* firmware write mode */
139#define PCBIT_IOCTL_STOP 0x0B /* stop protocol */
140#define PCBIT_IOCTL_APION 0x0C /* issue API_ON */
141
142#ifndef __KERNEL__
143
144#define PCBIT_GETSTAT (PCBIT_IOCTL_GETSTAT + IIOCDRVCTL)
145#define PCBIT_LWMODE (PCBIT_IOCTL_LWMODE + IIOCDRVCTL)
146#define PCBIT_STRLOAD (PCBIT_IOCTL_STRLOAD + IIOCDRVCTL)
147#define PCBIT_ENDLOAD (PCBIT_IOCTL_ENDLOAD + IIOCDRVCTL)
148#define PCBIT_SETBYTE (PCBIT_IOCTL_SETBYTE + IIOCDRVCTL)
149#define PCBIT_GETBYTE (PCBIT_IOCTL_GETBYTE + IIOCDRVCTL)
150#define PCBIT_RUNNING (PCBIT_IOCTL_RUNNING + IIOCDRVCTL)
151#define PCBIT_WATCH188 (PCBIT_IOCTL_WATCH188 + IIOCDRVCTL)
152#define PCBIT_PING188 (PCBIT_IOCTL_PING188 + IIOCDRVCTL)
153#define PCBIT_FWMODE (PCBIT_IOCTL_FWMODE + IIOCDRVCTL)
154#define PCBIT_STOP (PCBIT_IOCTL_STOP + IIOCDRVCTL)
155#define PCBIT_APION (PCBIT_IOCTL_APION + IIOCDRVCTL)
156
157#define MAXSUPERLINE 3000
158
159#endif
160
161#define L2_DOWN 0
162#define L2_LOADING 1
163#define L2_LWMODE 2
164#define L2_FWMODE 3
165#define L2_STARTING 4
166#define L2_RUNNING 5
167#define L2_ERROR 6
168
169#endif
diff --git a/drivers/isdn/sc/Kconfig b/drivers/isdn/sc/Kconfig
new file mode 100644
index 000000000000..5346e33d816c
--- /dev/null
+++ b/drivers/isdn/sc/Kconfig
@@ -0,0 +1,12 @@
1#
2# Config.in for Spellcaster ISDN driver
3#
4config ISDN_DRV_SC
5 tristate "Spellcaster support"
6 depends on ISDN_I4L && ISA
7 help
8 This enables support for the Spellcaster BRI ISDN boards. This
9 driver currently builds only in a modularized version.
10 To build it, choose M here: the module will be called sc.
11 See <file:Documentation/isdn/README.sc> for more information.
12
diff --git a/drivers/isdn/sc/Makefile b/drivers/isdn/sc/Makefile
new file mode 100644
index 000000000000..9cc474cd0c44
--- /dev/null
+++ b/drivers/isdn/sc/Makefile
@@ -0,0 +1,10 @@
1# Makefile for the sc ISDN device driver
2
3# Each configuration option enables a list of files.
4
5obj-$(CONFIG_ISDN_DRV_SC) += sc.o
6
7# Multipart objects.
8
9sc-y := shmem.o init.o debug.o packet.o command.o event.o \
10 ioctl.o interrupt.o message.o timer.o
diff --git a/drivers/isdn/sc/card.h b/drivers/isdn/sc/card.h
new file mode 100644
index 000000000000..8e44928cdf1c
--- /dev/null
+++ b/drivers/isdn/sc/card.h
@@ -0,0 +1,101 @@
1/* $Id: card.h,v 1.1.10.1 2001/09/23 22:24:59 kai Exp $
2 *
3 * Driver parameters for SpellCaster ISA ISDN adapters
4 *
5 * Copyright (C) 1996 SpellCaster Telecommunications Inc.
6 *
7 * This software may be used and distributed according to the terms
8 * of the GNU General Public License, incorporated herein by reference.
9 *
10 * For more information, please contact gpl-info@spellcast.com or write:
11 *
12 * SpellCaster Telecommunications Inc.
13 * 5621 Finch Avenue East, Unit #3
14 * Scarborough, Ontario Canada
15 * M1B 2T9
16 * +1 (416) 297-8565
17 * +1 (416) 297-6433 Facsimile
18 */
19
20#ifndef CARD_H
21#define CARD_H
22
23/*
24 * We need these if they're not already included
25 */
26#include <linux/timer.h>
27#include <linux/time.h>
28#include <linux/isdnif.h>
29#include "message.h"
30
31/*
32 * Amount of time to wait for a reset to complete
33 */
34#define CHECKRESET_TIME msecs_to_jiffies(4000)
35
36/*
37 * Amount of time between line status checks
38 */
39#define CHECKSTAT_TIME msecs_to_jiffies(8000)
40
41/*
42 * The maximum amount of time to wait for a message response
43 * to arrive. Use exclusively by send_and_receive
44 */
45#define SAR_TIMEOUT msecs_to_jiffies(10000)
46
47/*
48 * Macro to determine is a card id is valid
49 */
50#define IS_VALID_CARD(x) ((x >= 0) && (x <= cinst))
51
52/*
53 * Per channel status and configuration
54 */
55typedef struct {
56 int l2_proto;
57 int l3_proto;
58 char dn[50];
59 unsigned long first_sendbuf; /* Offset of first send buffer */
60 unsigned int num_sendbufs; /* Number of send buffers */
61 unsigned int free_sendbufs; /* Number of free sendbufs */
62 unsigned int next_sendbuf; /* Next sequential buffer */
63 char eazlist[50]; /* Set with SETEAZ */
64 char sillist[50]; /* Set with SETSIL */
65 int eazclear; /* Don't accept calls if TRUE */
66} bchan;
67
68/*
69 * Everything you want to know about the adapter ...
70 */
71typedef struct {
72 int model;
73 int driverId; /* LL Id */
74 char devicename[20]; /* The device name */
75 isdn_if *card; /* ISDN4Linux structure */
76 bchan *channel; /* status of the B channels */
77 char nChannels; /* Number of channels */
78 unsigned int interrupt; /* Interrupt number */
79 int iobase; /* I/O Base address */
80 int ioport[MAX_IO_REGS]; /* Index to I/O ports */
81 int shmem_pgport; /* port for the exp mem page reg. */
82 int shmem_magic; /* adapter magic number */
83 unsigned int rambase; /* Shared RAM base address */
84 unsigned int ramsize; /* Size of shared memory */
85 RspMessage async_msg; /* Async response message */
86 int want_async_messages; /* Snoop the Q ? */
87 unsigned char seq_no; /* Next send seq. number */
88 struct timer_list reset_timer; /* Check reset timer */
89 struct timer_list stat_timer; /* Check startproc timer */
90 unsigned char nphystat; /* Latest PhyStat info */
91 unsigned char phystat; /* Last PhyStat info */
92 HWConfig_pl hwconfig; /* Hardware config info */
93 char load_ver[11]; /* CommManage Version string */
94 char proc_ver[11]; /* CommEngine Version */
95 int StartOnReset; /* Indicates startproc after reset */
96 int EngineUp; /* Indicates CommEngine Up */
97 int trace_mode; /* Indicate if tracing is on */
98 spinlock_t lock; /* local lock */
99} board;
100
101#endif /* CARD_H */
diff --git a/drivers/isdn/sc/command.c b/drivers/isdn/sc/command.c
new file mode 100644
index 000000000000..b2c4eac7cef5
--- /dev/null
+++ b/drivers/isdn/sc/command.c
@@ -0,0 +1,441 @@
1/* $Id: command.c,v 1.4.10.1 2001/09/23 22:24:59 kai Exp $
2 *
3 * Copyright (C) 1996 SpellCaster Telecommunications Inc.
4 *
5 * This software may be used and distributed according to the terms
6 * of the GNU General Public License, incorporated herein by reference.
7 *
8 * For more information, please contact gpl-info@spellcast.com or write:
9 *
10 * SpellCaster Telecommunications Inc.
11 * 5621 Finch Avenue East, Unit #3
12 * Scarborough, Ontario Canada
13 * M1B 2T9
14 * +1 (416) 297-8565
15 * +1 (416) 297-6433 Facsimile
16 */
17
18#include <linux/module.h>
19#include "includes.h" /* This must be first */
20#include "hardware.h"
21#include "message.h"
22#include "card.h"
23#include "scioc.h"
24
25int dial(int card, unsigned long channel, setup_parm setup);
26int hangup(int card, unsigned long channel);
27int answer(int card, unsigned long channel);
28int clreaz(int card, unsigned long channel);
29int seteaz(int card, unsigned long channel, char *);
30int setl2(int card, unsigned long arg);
31int setl3(int card, unsigned long arg);
32int acceptb(int card, unsigned long channel);
33
34extern int cinst;
35extern board *sc_adapter[];
36
37extern int sc_ioctl(int, scs_ioctl *);
38extern int setup_buffers(int, int, unsigned int);
39extern int indicate_status(int, int,ulong,char*);
40extern void check_reset(unsigned long);
41extern int send_and_receive(int, unsigned int, unsigned char, unsigned char,
42 unsigned char, unsigned char, unsigned char, unsigned char *,
43 RspMessage *, int);
44extern int sendmessage(int, unsigned int, unsigned int, unsigned int,
45 unsigned int, unsigned int, unsigned int, unsigned int *);
46extern inline void pullphone(char *, char *);
47
48#ifdef DEBUG
49/*
50 * Translate command codes to strings
51 */
52static char *commands[] = { "ISDN_CMD_IOCTL",
53 "ISDN_CMD_DIAL",
54 "ISDN_CMD_ACCEPTB",
55 "ISDN_CMD_ACCEPTB",
56 "ISDN_CMD_HANGUP",
57 "ISDN_CMD_CLREAZ",
58 "ISDN_CMD_SETEAZ",
59 NULL,
60 NULL,
61 NULL,
62 "ISDN_CMD_SETL2",
63 NULL,
64 "ISDN_CMD_SETL3",
65 NULL,
66 NULL,
67 NULL,
68 NULL,
69 NULL, };
70
71/*
72 * Translates ISDN4Linux protocol codes to strings for debug messages
73 */
74static char *l3protos[] = { "ISDN_PROTO_L3_TRANS" };
75static char *l2protos[] = { "ISDN_PROTO_L2_X75I",
76 "ISDN_PROTO_L2_X75UI",
77 "ISDN_PROTO_L2_X75BUI",
78 "ISDN_PROTO_L2_HDLC",
79 "ISDN_PROTO_L2_TRANS" };
80#endif
81
82int get_card_from_id(int driver)
83{
84 int i;
85
86 for(i = 0 ; i < cinst ; i++) {
87 if(sc_adapter[i]->driverId == driver)
88 return i;
89 }
90 return -ENODEV;
91}
92
93/*
94 * command
95 */
96
97int command(isdn_ctrl *cmd)
98{
99 int card;
100
101 card = get_card_from_id(cmd->driver);
102 if(!IS_VALID_CARD(card)) {
103 pr_debug("Invalid param: %d is not a valid card id\n", card);
104 return -ENODEV;
105 }
106
107 pr_debug("%s: Received %s command from Link Layer\n",
108 sc_adapter[card]->devicename, commands[cmd->command]);
109
110 /*
111 * Dispatch the command
112 */
113 switch(cmd->command) {
114 case ISDN_CMD_IOCTL:
115 {
116 unsigned long cmdptr;
117 scs_ioctl ioc;
118
119 memcpy(&cmdptr, cmd->parm.num, sizeof(unsigned long));
120 if (copy_from_user(&ioc, (scs_ioctl __user *)cmdptr,
121 sizeof(scs_ioctl))) {
122 pr_debug("%s: Failed to verify user space 0x%x\n",
123 sc_adapter[card]->devicename, cmdptr);
124 return -EFAULT;
125 }
126 return sc_ioctl(card, &ioc);
127 }
128 case ISDN_CMD_DIAL:
129 return dial(card, cmd->arg, cmd->parm.setup);
130 case ISDN_CMD_HANGUP:
131 return hangup(card, cmd->arg);
132 case ISDN_CMD_ACCEPTD:
133 return answer(card, cmd->arg);
134 case ISDN_CMD_ACCEPTB:
135 return acceptb(card, cmd->arg);
136 case ISDN_CMD_CLREAZ:
137 return clreaz(card, cmd->arg);
138 case ISDN_CMD_SETEAZ:
139 return seteaz(card, cmd->arg, cmd->parm.num);
140 case ISDN_CMD_SETL2:
141 return setl2(card, cmd->arg);
142 case ISDN_CMD_SETL3:
143 return setl3(card, cmd->arg);
144 default:
145 return -EINVAL;
146 }
147 return 0;
148}
149
150/*
151 * Confirm our ability to communicate with the board. This test assumes no
152 * other message activity is present
153 */
154int loopback(int card)
155{
156
157 int status;
158 static char testmsg[] = "Test Message";
159 RspMessage rspmsg;
160
161 if(!IS_VALID_CARD(card)) {
162 pr_debug("Invalid param: %d is not a valid card id\n", card);
163 return -ENODEV;
164 }
165
166 pr_debug("%s: Sending loopback message\n",
167 sc_adapter[card]->devicename);
168
169 /*
170 * Send the loopback message to confirm that memory transfer is
171 * operational
172 */
173 status = send_and_receive(card, CMPID, cmReqType1,
174 cmReqClass0,
175 cmReqMsgLpbk,
176 0,
177 (unsigned char) strlen(testmsg),
178 (unsigned char *)testmsg,
179 &rspmsg, SAR_TIMEOUT);
180
181
182 if (!status) {
183 pr_debug("%s: Loopback message successfully sent\n",
184 sc_adapter[card]->devicename);
185 if(strcmp(rspmsg.msg_data.byte_array, testmsg)) {
186 pr_debug("%s: Loopback return != sent\n",
187 sc_adapter[card]->devicename);
188 return -EIO;
189 }
190 return 0;
191 }
192 else {
193 pr_debug("%s: Send loopback message failed\n",
194 sc_adapter[card]->devicename);
195 return -EIO;
196 }
197
198}
199
200/*
201 * start the onboard firmware
202 */
203int startproc(int card)
204{
205 int status;
206
207 if(!IS_VALID_CARD(card)) {
208 pr_debug("Invalid param: %d is not a valid card id\n", card);
209 return -ENODEV;
210 }
211
212 /*
213 * send start msg
214 */
215 status = sendmessage(card, CMPID,cmReqType2,
216 cmReqClass0,
217 cmReqStartProc,
218 0,0,NULL);
219 pr_debug("%s: Sent startProc\n", sc_adapter[card]->devicename);
220
221 return status;
222}
223
224
225int loadproc(int card, char *data)
226{
227 return -1;
228}
229
230
231/*
232 * Dials the number passed in
233 */
234int dial(int card, unsigned long channel, setup_parm setup)
235{
236 int status;
237 char Phone[48];
238
239 if(!IS_VALID_CARD(card)) {
240 pr_debug("Invalid param: %d is not a valid card id\n", card);
241 return -ENODEV;
242 }
243
244 /*extract ISDN number to dial from eaz/msn string*/
245 strcpy(Phone,setup.phone);
246
247 /*send the connection message*/
248 status = sendmessage(card, CEPID,ceReqTypePhy,
249 ceReqClass1,
250 ceReqPhyConnect,
251 (unsigned char) channel+1,
252 strlen(Phone),
253 (unsigned int *) Phone);
254
255 pr_debug("%s: Dialing %s on channel %d\n",
256 sc_adapter[card]->devicename, Phone, channel+1);
257
258 return status;
259}
260
261/*
262 * Answer an incoming call
263 */
264int answer(int card, unsigned long channel)
265{
266 if(!IS_VALID_CARD(card)) {
267 pr_debug("Invalid param: %d is not a valid card id\n", card);
268 return -ENODEV;
269 }
270
271 if(setup_buffers(card, channel+1, BUFFER_SIZE)) {
272 hangup(card, channel+1);
273 return -ENOBUFS;
274 }
275
276 indicate_status(card, ISDN_STAT_BCONN,channel,NULL);
277 pr_debug("%s: Answered incoming call on channel %s\n",
278 sc_adapter[card]->devicename, channel+1);
279 return 0;
280}
281
282/*
283 * Hangup up the call on specified channel
284 */
285int hangup(int card, unsigned long channel)
286{
287 int status;
288
289 if(!IS_VALID_CARD(card)) {
290 pr_debug("Invalid param: %d is not a valid card id\n", card);
291 return -ENODEV;
292 }
293
294 status = sendmessage(card, CEPID, ceReqTypePhy,
295 ceReqClass1,
296 ceReqPhyDisconnect,
297 (unsigned char) channel+1,
298 0,
299 NULL);
300 pr_debug("%s: Sent HANGUP message to channel %d\n",
301 sc_adapter[card]->devicename, channel+1);
302 return status;
303}
304
305/*
306 * Set the layer 2 protocol (X.25, HDLC, Raw)
307 */
308int setl2(int card, unsigned long arg)
309{
310 int status =0;
311 int protocol,channel;
312
313 if(!IS_VALID_CARD(card)) {
314 pr_debug("Invalid param: %d is not a valid card id\n", card);
315 return -ENODEV;
316 }
317 protocol = arg >> 8;
318 channel = arg & 0xff;
319 sc_adapter[card]->channel[channel].l2_proto = protocol;
320 pr_debug("%s: Level 2 protocol for channel %d set to %s from %d\n",
321 sc_adapter[card]->devicename, channel+1,
322 l2protos[sc_adapter[card]->channel[channel].l2_proto],protocol);
323
324 /*
325 * check that the adapter is also set to the correct protocol
326 */
327 pr_debug("%s: Sending GetFrameFormat for channel %d\n",
328 sc_adapter[card]->devicename, channel+1);
329 status = sendmessage(card, CEPID, ceReqTypeCall,
330 ceReqClass0,
331 ceReqCallGetFrameFormat,
332 (unsigned char)channel+1,
333 1,
334 (unsigned int *) protocol);
335 if(status)
336 return status;
337 return 0;
338}
339
340/*
341 * Set the layer 3 protocol
342 */
343int setl3(int card, unsigned long channel)
344{
345 int protocol = channel >> 8;
346
347 if(!IS_VALID_CARD(card)) {
348 pr_debug("Invalid param: %d is not a valid card id\n", card);
349 return -ENODEV;
350 }
351
352 sc_adapter[card]->channel[channel].l3_proto = protocol;
353 pr_debug("%s: Level 3 protocol for channel %d set to %s\n",
354 sc_adapter[card]->devicename, channel+1, l3protos[protocol]);
355 return 0;
356}
357
358int acceptb(int card, unsigned long channel)
359{
360 if(!IS_VALID_CARD(card)) {
361 pr_debug("Invalid param: %d is not a valid card id\n", card);
362 return -ENODEV;
363 }
364
365 if(setup_buffers(card, channel+1, BUFFER_SIZE))
366 {
367 hangup(card, channel+1);
368 return -ENOBUFS;
369 }
370
371 pr_debug("%s: B-Channel connection accepted on channel %d\n",
372 sc_adapter[card]->devicename, channel+1);
373 indicate_status(card, ISDN_STAT_BCONN, channel, NULL);
374 return 0;
375}
376
377int clreaz(int card, unsigned long arg)
378{
379 if(!IS_VALID_CARD(card)) {
380 pr_debug("Invalid param: %d is not a valid card id\n", card);
381 return -ENODEV;
382 }
383
384 strcpy(sc_adapter[card]->channel[arg].eazlist, "");
385 sc_adapter[card]->channel[arg].eazclear = 1;
386 pr_debug("%s: EAZ List cleared for channel %d\n",
387 sc_adapter[card]->devicename, arg+1);
388 return 0;
389}
390
391int seteaz(int card, unsigned long arg, char *num)
392{
393 if(!IS_VALID_CARD(card)) {
394 pr_debug("Invalid param: %d is not a valid card id\n", card);
395 return -ENODEV;
396 }
397
398 strcpy(sc_adapter[card]->channel[arg].eazlist, num);
399 sc_adapter[card]->channel[arg].eazclear = 0;
400 pr_debug("%s: EAZ list for channel %d set to: %s\n",
401 sc_adapter[card]->devicename, arg+1,
402 sc_adapter[card]->channel[arg].eazlist);
403 return 0;
404}
405
406int reset(int card)
407{
408 unsigned long flags;
409
410 if(!IS_VALID_CARD(card)) {
411 pr_debug("Invalid param: %d is not a valid card id\n", card);
412 return -ENODEV;
413 }
414
415 indicate_status(card, ISDN_STAT_STOP, 0, NULL);
416
417 if(sc_adapter[card]->EngineUp) {
418 del_timer(&sc_adapter[card]->stat_timer);
419 }
420
421 sc_adapter[card]->EngineUp = 0;
422
423 spin_lock_irqsave(&sc_adapter[card]->lock, flags);
424 init_timer(&sc_adapter[card]->reset_timer);
425 sc_adapter[card]->reset_timer.function = check_reset;
426 sc_adapter[card]->reset_timer.data = card;
427 sc_adapter[card]->reset_timer.expires = jiffies + CHECKRESET_TIME;
428 add_timer(&sc_adapter[card]->reset_timer);
429 spin_unlock_irqrestore(&sc_adapter[card]->lock, flags);
430
431 outb(0x1,sc_adapter[card]->ioport[SFT_RESET]);
432
433 pr_debug("%s: Adapter Reset\n", sc_adapter[card]->devicename);
434 return 0;
435}
436
437void flushreadfifo (int card)
438{
439 while(inb(sc_adapter[card]->ioport[FIFO_STATUS]) & RF_HAS_DATA)
440 inb(sc_adapter[card]->ioport[FIFO_READ]);
441}
diff --git a/drivers/isdn/sc/debug.c b/drivers/isdn/sc/debug.c
new file mode 100644
index 000000000000..1a992a75868b
--- /dev/null
+++ b/drivers/isdn/sc/debug.c
@@ -0,0 +1,46 @@
1/* $Id: debug.c,v 1.5.6.1 2001/09/23 22:24:59 kai Exp $
2 *
3 * Copyright (C) 1996 SpellCaster Telecommunications Inc.
4 *
5 * This software may be used and distributed according to the terms
6 * of the GNU General Public License, incorporated herein by reference.
7 *
8 * For more information, please contact gpl-info@spellcast.com or write:
9 *
10 * SpellCaster Telecommunications Inc.
11 * 5621 Finch Avenue East, Unit #3
12 * Scarborough, Ontario Canada
13 * M1B 2T9
14 * +1 (416) 297-8565
15 * +1 (416) 297-6433 Facsimile
16 */
17
18#include <linux/kernel.h>
19#include <linux/string.h>
20
21int dbg_level = 0;
22static char dbg_funcname[255];
23
24void dbg_endfunc(void)
25{
26 if (dbg_level) {
27 printk("<-- Leaving function %s\n", dbg_funcname);
28 strcpy(dbg_funcname, "");
29 }
30}
31
32void dbg_func(char *func)
33{
34 strcpy(dbg_funcname, func);
35 if(dbg_level)
36 printk("--> Entering function %s\n", dbg_funcname);
37}
38
39inline void pullphone(char *dn, char *str)
40{
41 int i = 0;
42
43 while(dn[i] != ',')
44 str[i] = dn[i], i++;
45 str[i] = 0x0;
46}
diff --git a/drivers/isdn/sc/debug.h b/drivers/isdn/sc/debug.h
new file mode 100644
index 000000000000..e9db96ede4b2
--- /dev/null
+++ b/drivers/isdn/sc/debug.h
@@ -0,0 +1,19 @@
1/* $Id: debug.h,v 1.2.8.1 2001/09/23 22:24:59 kai Exp $
2 *
3 * Copyright (C) 1996 SpellCaster Telecommunications Inc.
4 *
5 * This software may be used and distributed according to the terms
6 * of the GNU General Public License, incorporated herein by reference.
7 *
8 * For more information, please contact gpl-info@spellcast.com or write:
9 *
10 * SpellCaster Telecommunications Inc.
11 * 5621 Finch Avenue East, Unit #3
12 * Scarborough, Ontario Canada
13 * M1B 2T9
14 * +1 (416) 297-8565
15 * +1 (416) 297-6433 Facsimile
16 */
17
18#define REQUEST_IRQ(a,b,c,d,e) request_irq(a,b,c,d,e)
19#define FREE_IRQ(a,b) free_irq(a,b)
diff --git a/drivers/isdn/sc/event.c b/drivers/isdn/sc/event.c
new file mode 100644
index 000000000000..5b8c7c1a7663
--- /dev/null
+++ b/drivers/isdn/sc/event.c
@@ -0,0 +1,69 @@
1/* $Id: event.c,v 1.4.8.1 2001/09/23 22:24:59 kai Exp $
2 *
3 * Copyright (C) 1996 SpellCaster Telecommunications Inc.
4 *
5 * This software may be used and distributed according to the terms
6 * of the GNU General Public License, incorporated herein by reference.
7 *
8 * For more information, please contact gpl-info@spellcast.com or write:
9 *
10 * SpellCaster Telecommunications Inc.
11 * 5621 Finch Avenue East, Unit #3
12 * Scarborough, Ontario Canada
13 * M1B 2T9
14 * +1 (416) 297-8565
15 * +1 (416) 297-6433 Facsimile
16 */
17
18#include "includes.h"
19#include "hardware.h"
20#include "message.h"
21#include "card.h"
22
23extern int cinst;
24extern board *sc_adapter[];
25
26#ifdef DEBUG
27static char *events[] = { "ISDN_STAT_STAVAIL",
28 "ISDN_STAT_ICALL",
29 "ISDN_STAT_RUN",
30 "ISDN_STAT_STOP",
31 "ISDN_STAT_DCONN",
32 "ISDN_STAT_BCONN",
33 "ISDN_STAT_DHUP",
34 "ISDN_STAT_BHUP",
35 "ISDN_STAT_CINF",
36 "ISDN_STAT_LOAD",
37 "ISDN_STAT_UNLOAD",
38 "ISDN_STAT_BSENT",
39 "ISDN_STAT_NODCH",
40 "ISDN_STAT_ADDCH",
41 "ISDN_STAT_CAUSE" };
42#endif
43
44int indicate_status(int card, int event,ulong Channel,char *Data)
45{
46 isdn_ctrl cmd;
47
48 pr_debug("%s: Indicating event %s on Channel %d\n",
49 sc_adapter[card]->devicename, events[event-256], Channel);
50 if (Data != NULL){
51 pr_debug("%s: Event data: %s\n", sc_adapter[card]->devicename,
52 Data);
53 switch (event) {
54 case ISDN_STAT_BSENT:
55 memcpy(&cmd.parm.length, Data, sizeof(cmd.parm.length));
56 break;
57 case ISDN_STAT_ICALL:
58 memcpy(&cmd.parm.setup, Data, sizeof(cmd.parm.setup));
59 break;
60 default:
61 strcpy(cmd.parm.num, Data);
62 }
63 }
64
65 cmd.command = event;
66 cmd.driver = sc_adapter[card]->driverId;
67 cmd.arg = Channel;
68 return sc_adapter[card]->card->statcallb(&cmd);
69}
diff --git a/drivers/isdn/sc/hardware.h b/drivers/isdn/sc/hardware.h
new file mode 100644
index 000000000000..9e6d5302bf8e
--- /dev/null
+++ b/drivers/isdn/sc/hardware.h
@@ -0,0 +1,110 @@
1/*
2 * Hardware specific macros, defines and structures
3 *
4 * This software may be used and distributed according to the terms
5 * of the GNU General Public License, incorporated herein by reference.
6 *
7 */
8
9#ifndef HARDWARE_H
10#define HARDWARE_H
11
12#include <asm/param.h> /* For HZ */
13
14/*
15 * General hardware parameters common to all ISA adapters
16 */
17
18#define MAX_CARDS 4 /* The maximum number of cards to
19 control or probe for. */
20
21#define SIGNATURE 0x87654321 /* Board reset signature */
22#define SIG_OFFSET 0x1004 /* Where to find signature in shared RAM */
23#define TRACE_OFFSET 0x1008 /* Trace enable word offset in shared RAM */
24#define BUFFER_OFFSET 0x1800 /* Beginning of buffers */
25
26/* I/O Port parameters */
27#define IOBASE_MIN 0x180 /* Lowest I/O port address */
28#define IOBASE_MAX 0x3C0 /* Highest I/O port address */
29#define IOBASE_OFFSET 0x20 /* Inter-board I/O port gap used during
30 probing */
31#define FIFORD_OFFSET 0x0
32#define FIFOWR_OFFSET 0x400
33#define FIFOSTAT_OFFSET 0x1000
34#define RESET_OFFSET 0x2800
35#define PG0_OFFSET 0x3000 /* Offset from I/O Base for Page 0 register */
36#define PG1_OFFSET 0x3400 /* Offset from I/O Base for Page 1 register */
37#define PG2_OFFSET 0x3800 /* Offset from I/O Base for Page 2 register */
38#define PG3_OFFSET 0x3C00 /* Offset from I/O Base for Page 3 register */
39
40#define FIFO_READ 0 /* FIFO Read register */
41#define FIFO_WRITE 1 /* FIFO Write rgister */
42#define LO_ADDR_PTR 2 /* Extended RAM Low Addr Pointer */
43#define HI_ADDR_PTR 3 /* Extended RAM High Addr Pointer */
44#define NOT_USED_1 4
45#define FIFO_STATUS 5 /* FIFO Status Register */
46#define NOT_USED_2 6
47#define MEM_OFFSET 7
48#define SFT_RESET 10 /* Reset Register */
49#define EXP_BASE 11 /* Shared RAM Base address */
50#define EXP_PAGE0 12 /* Shared RAM Page0 register */
51#define EXP_PAGE1 13 /* Shared RAM Page1 register */
52#define EXP_PAGE2 14 /* Shared RAM Page2 register */
53#define EXP_PAGE3 15 /* Shared RAM Page3 register */
54#define IRQ_SELECT 16 /* IRQ selection register */
55#define MAX_IO_REGS 17 /* Total number of I/O ports */
56
57/* FIFO register values */
58#define RF_HAS_DATA 0x01 /* fifo has data */
59#define RF_QUART_FULL 0x02 /* fifo quarter full */
60#define RF_HALF_FULL 0x04 /* fifo half full */
61#define RF_NOT_FULL 0x08 /* fifo not full */
62#define WF_HAS_DATA 0x10 /* fifo has data */
63#define WF_QUART_FULL 0x20 /* fifo quarter full */
64#define WF_HALF_FULL 0x40 /* fifo half full */
65#define WF_NOT_FULL 0x80 /* fifo not full */
66
67/* Shared RAM parameters */
68#define SRAM_MIN 0xC0000 /* Lowest host shared RAM address */
69#define SRAM_MAX 0xEFFFF /* Highest host shared RAM address */
70#define SRAM_PAGESIZE 0x4000 /* Size of one RAM page (16K) */
71
72/* Shared RAM buffer parameters */
73#define BUFFER_SIZE 0x800 /* The size of a buffer in bytes */
74#define BUFFER_BASE BUFFER_OFFSET /* Offset from start of shared RAM
75 where buffer start */
76#define BUFFERS_MAX 16 /* Maximum number of send/receive
77 buffers per channel */
78#define HDLC_PROTO 0x01 /* Frame Format for Layer 2 */
79
80#define BRI_BOARD 0
81#define POTS_BOARD 1
82#define PRI_BOARD 2
83
84/*
85 * Specific hardware parameters for the DataCommute/BRI
86 */
87#define BRI_CHANNELS 2 /* Number of B channels */
88#define BRI_BASEPG_VAL 0x98
89#define BRI_MAGIC 0x60000 /* Magic Number */
90#define BRI_MEMSIZE 0x10000 /* Ammount of RAM (64K) */
91#define BRI_PARTNO "72-029"
92#define BRI_FEATURES ISDN_FEATURE_L2_HDLC | ISDN_FEATURE_L3_TRANS;
93/*
94 * Specific hardware parameters for the DataCommute/PRI
95 */
96#define PRI_CHANNELS 23 /* Number of B channels */
97#define PRI_BASEPG_VAL 0x88
98#define PRI_MAGIC 0x20000 /* Magic Number */
99#define PRI_MEMSIZE 0x100000 /* Amount of RAM (1M) */
100#define PRI_PARTNO "72-030"
101#define PRI_FEATURES ISDN_FEATURE_L2_HDLC | ISDN_FEATURE_L3_TRANS;
102
103/*
104 * Some handy macros
105 */
106
107/* Determine if a channel number is valid for the adapter */
108#define IS_VALID_CHANNEL(y,x) ((x>0) && (x <= sc_adapter[y]->channels))
109
110#endif
diff --git a/drivers/isdn/sc/includes.h b/drivers/isdn/sc/includes.h
new file mode 100644
index 000000000000..4611da6e9231
--- /dev/null
+++ b/drivers/isdn/sc/includes.h
@@ -0,0 +1,18 @@
1/*
2 * This software may be used and distributed according to the terms
3 * of the GNU General Public License, incorporated herein by reference.
4 *
5 */
6
7#include <linux/version.h>
8#include <linux/errno.h>
9#include <asm/io.h>
10#include <linux/delay.h>
11#include <linux/kernel.h>
12#include <linux/slab.h>
13#include <linux/mm.h>
14#include <linux/ioport.h>
15#include <linux/timer.h>
16#include <linux/wait.h>
17#include <linux/isdnif.h>
18#include "debug.h"
diff --git a/drivers/isdn/sc/init.c b/drivers/isdn/sc/init.c
new file mode 100644
index 000000000000..efefedea37b9
--- /dev/null
+++ b/drivers/isdn/sc/init.c
@@ -0,0 +1,571 @@
1/*
2 * This software may be used and distributed according to the terms
3 * of the GNU General Public License, incorporated herein by reference.
4 *
5 */
6
7#include <linux/module.h>
8#include <linux/init.h>
9#include <linux/interrupt.h>
10#include <linux/delay.h>
11#include "includes.h"
12#include "hardware.h"
13#include "card.h"
14
15MODULE_DESCRIPTION("ISDN4Linux: Driver for Spellcaster card");
16MODULE_AUTHOR("Spellcaster Telecommunications Inc.");
17MODULE_LICENSE("GPL");
18
19board *sc_adapter[MAX_CARDS];
20int cinst;
21
22static char devname[] = "scX";
23const char version[] = "2.0b1";
24
25const char *boardname[] = { "DataCommute/BRI", "DataCommute/PRI", "TeleCommute/BRI" };
26
27/* insmod set parameters */
28static unsigned int io[] = {0,0,0,0};
29static unsigned char irq[] = {0,0,0,0};
30static unsigned long ram[] = {0,0,0,0};
31static int do_reset = 0;
32
33module_param_array(io, int, NULL, 0);
34module_param_array(irq, int, NULL, 0);
35module_param_array(ram, int, NULL, 0);
36module_param(do_reset, bool, 0);
37
38static int sup_irq[] = { 11, 10, 9, 5, 12, 14, 7, 3, 4, 6 };
39#define MAX_IRQS 10
40
41extern irqreturn_t interrupt_handler(int, void *, struct pt_regs *);
42extern int sndpkt(int, int, int, struct sk_buff *);
43extern int command(isdn_ctrl *);
44extern int indicate_status(int, int, ulong, char*);
45extern int reset(int);
46
47int identify_board(unsigned long, unsigned int);
48
49int irq_supported(int irq_x)
50{
51 int i;
52 for(i=0 ; i < MAX_IRQS ; i++) {
53 if(sup_irq[i] == irq_x)
54 return 1;
55 }
56 return 0;
57}
58
59static int __init sc_init(void)
60{
61 int b = -1;
62 int i, j;
63 int status = -ENODEV;
64
65 unsigned long memsize = 0;
66 unsigned long features = 0;
67 isdn_if *interface;
68 unsigned char channels;
69 unsigned char pgport;
70 unsigned long magic;
71 int model;
72 int last_base = IOBASE_MIN;
73 int probe_exhasted = 0;
74
75#ifdef MODULE
76 pr_info("SpellCaster ISA ISDN Adapter Driver rev. %s Loaded\n", version);
77#else
78 pr_info("SpellCaster ISA ISDN Adapter Driver rev. %s\n", version);
79#endif
80 pr_info("Copyright (C) 1996 SpellCaster Telecommunications Inc.\n");
81
82 while(b++ < MAX_CARDS - 1) {
83 pr_debug("Probing for adapter #%d\n", b);
84 /*
85 * Initialize reusable variables
86 */
87 model = -1;
88 magic = 0;
89 channels = 0;
90 pgport = 0;
91
92 /*
93 * See if we should probe for IO base
94 */
95 pr_debug("I/O Base for board %d is 0x%x, %s probe\n", b, io[b],
96 io[b] == 0 ? "will" : "won't");
97 if(io[b]) {
98 /*
99 * No, I/O Base has been provided
100 */
101 for (i = 0 ; i < MAX_IO_REGS - 1 ; i++) {
102 if(!request_region(io[b] + i * 0x400, 1, "sc test")) {
103 pr_debug("check_region for 0x%x failed\n", io[b] + i * 0x400);
104 io[b] = 0;
105 break;
106 } else
107 release_region(io[b] + i * 0x400, 1);
108 }
109
110 /*
111 * Confirm the I/O Address with a test
112 */
113 if(io[b] == 0) {
114 pr_debug("I/O Address 0x%x is in use.\n");
115 continue;
116 }
117
118 outb(0x18, io[b] + 0x400 * EXP_PAGE0);
119 if(inb(io[b] + 0x400 * EXP_PAGE0) != 0x18) {
120 pr_debug("I/O Base 0x%x fails test\n");
121 continue;
122 }
123 }
124 else {
125 /*
126 * Yes, probe for I/O Base
127 */
128 if(probe_exhasted) {
129 pr_debug("All probe addresses exhasted, skipping\n");
130 continue;
131 }
132 pr_debug("Probing for I/O...\n");
133 for (i = last_base ; i <= IOBASE_MAX ; i += IOBASE_OFFSET) {
134 int found_io = 1;
135 if (i == IOBASE_MAX) {
136 probe_exhasted = 1; /* No more addresses to probe */
137 pr_debug("End of Probes\n");
138 }
139 last_base = i + IOBASE_OFFSET;
140 pr_debug(" checking 0x%x...", i);
141 for ( j = 0 ; j < MAX_IO_REGS - 1 ; j++) {
142 if(!request_region(i + j * 0x400, 1, "sc test")) {
143 pr_debug("Failed\n");
144 found_io = 0;
145 break;
146 } else
147 release_region(i + j * 0x400, 1);
148 }
149
150 if(found_io) {
151 io[b] = i;
152 outb(0x18, io[b] + 0x400 * EXP_PAGE0);
153 if(inb(io[b] + 0x400 * EXP_PAGE0) != 0x18) {
154 pr_debug("Failed by test\n");
155 continue;
156 }
157 pr_debug("Passed\n");
158 break;
159 }
160 }
161 if(probe_exhasted) {
162 continue;
163 }
164 }
165
166 /*
167 * See if we should probe for shared RAM
168 */
169 if(do_reset) {
170 pr_debug("Doing a SAFE probe reset\n");
171 outb(0xFF, io[b] + RESET_OFFSET);
172 msleep_interruptible(10000);
173 }
174 pr_debug("RAM Base for board %d is 0x%x, %s probe\n", b, ram[b],
175 ram[b] == 0 ? "will" : "won't");
176
177 if(ram[b]) {
178 /*
179 * No, the RAM base has been provided
180 * Just look for a signature and ID the
181 * board model
182 */
183 if(request_region(ram[b], SRAM_PAGESIZE, "sc test")) {
184 pr_debug("request_region for RAM base 0x%x succeeded\n", ram[b]);
185 model = identify_board(ram[b], io[b]);
186 release_region(ram[b], SRAM_PAGESIZE);
187 }
188 }
189 else {
190 /*
191 * Yes, probe for free RAM and look for
192 * a signature and id the board model
193 */
194 for (i = SRAM_MIN ; i < SRAM_MAX ; i += SRAM_PAGESIZE) {
195 pr_debug("Checking RAM address 0x%x...\n", i);
196 if(request_region(i, SRAM_PAGESIZE, "sc test")) {
197 pr_debug(" check_region succeeded\n");
198 model = identify_board(i, io[b]);
199 release_region(i, SRAM_PAGESIZE);
200 if (model >= 0) {
201 pr_debug(" Identified a %s\n",
202 boardname[model]);
203 ram[b] = i;
204 break;
205 }
206 pr_debug(" Unidentifed or inaccessible\n");
207 continue;
208 }
209 pr_debug(" request failed\n");
210 }
211 }
212 /*
213 * See if we found free RAM and the board model
214 */
215 if(!ram[b] || model < 0) {
216 /*
217 * Nope, there was no place in RAM for the
218 * board, or it couldn't be identified
219 */
220 pr_debug("Failed to find an adapter at 0x%x\n", ram[b]);
221 continue;
222 }
223
224 /*
225 * Set the board's magic number, memory size and page register
226 */
227 switch(model) {
228 case PRI_BOARD:
229 channels = 23;
230 magic = 0x20000;
231 memsize = 0x100000;
232 features = PRI_FEATURES;
233 break;
234
235 case BRI_BOARD:
236 case POTS_BOARD:
237 channels = 2;
238 magic = 0x60000;
239 memsize = 0x10000;
240 features = BRI_FEATURES;
241 break;
242 }
243 switch(ram[b] >> 12 & 0x0F) {
244 case 0x0:
245 pr_debug("RAM Page register set to EXP_PAGE0\n");
246 pgport = EXP_PAGE0;
247 break;
248
249 case 0x4:
250 pr_debug("RAM Page register set to EXP_PAGE1\n");
251 pgport = EXP_PAGE1;
252 break;
253
254 case 0x8:
255 pr_debug("RAM Page register set to EXP_PAGE2\n");
256 pgport = EXP_PAGE2;
257 break;
258
259 case 0xC:
260 pr_debug("RAM Page register set to EXP_PAGE3\n");
261 pgport = EXP_PAGE3;
262 break;
263
264 default:
265 pr_debug("RAM base address doesn't fall on 16K boundary\n");
266 continue;
267 }
268
269 pr_debug("current IRQ: %d b: %d\n",irq[b],b);
270
271 /*
272 * Make sure we got an IRQ
273 */
274 if(!irq[b]) {
275 /*
276 * No interrupt could be used
277 */
278 pr_debug("Failed to acquire an IRQ line\n");
279 continue;
280 }
281
282 /*
283 * Horray! We found a board, Make sure we can register
284 * it with ISDN4Linux
285 */
286 interface = kmalloc(sizeof(isdn_if), GFP_KERNEL);
287 if (interface == NULL) {
288 /*
289 * Oops, can't malloc isdn_if
290 */
291 continue;
292 }
293 memset(interface, 0, sizeof(isdn_if));
294
295 interface->owner = THIS_MODULE;
296 interface->hl_hdrlen = 0;
297 interface->channels = channels;
298 interface->maxbufsize = BUFFER_SIZE;
299 interface->features = features;
300 interface->writebuf_skb = sndpkt;
301 interface->writecmd = NULL;
302 interface->command = command;
303 strcpy(interface->id, devname);
304 interface->id[2] = '0' + cinst;
305
306 /*
307 * Allocate the board structure
308 */
309 sc_adapter[cinst] = kmalloc(sizeof(board), GFP_KERNEL);
310 if (sc_adapter[cinst] == NULL) {
311 /*
312 * Oops, can't alloc memory for the board
313 */
314 kfree(interface);
315 continue;
316 }
317 memset(sc_adapter[cinst], 0, sizeof(board));
318 spin_lock_init(&sc_adapter[cinst]->lock);
319
320 if(!register_isdn(interface)) {
321 /*
322 * Oops, couldn't register for some reason
323 */
324 kfree(interface);
325 kfree(sc_adapter[cinst]);
326 continue;
327 }
328
329 sc_adapter[cinst]->card = interface;
330 sc_adapter[cinst]->driverId = interface->channels;
331 strcpy(sc_adapter[cinst]->devicename, interface->id);
332 sc_adapter[cinst]->nChannels = channels;
333 sc_adapter[cinst]->ramsize = memsize;
334 sc_adapter[cinst]->shmem_magic = magic;
335 sc_adapter[cinst]->shmem_pgport = pgport;
336 sc_adapter[cinst]->StartOnReset = 1;
337
338 /*
339 * Allocate channels status structures
340 */
341 sc_adapter[cinst]->channel = kmalloc(sizeof(bchan) * channels, GFP_KERNEL);
342 if (sc_adapter[cinst]->channel == NULL) {
343 /*
344 * Oops, can't alloc memory for the channels
345 */
346 indicate_status(cinst, ISDN_STAT_UNLOAD, 0, NULL); /* Fix me */
347 kfree(interface);
348 kfree(sc_adapter[cinst]);
349 continue;
350 }
351 memset(sc_adapter[cinst]->channel, 0, sizeof(bchan) * channels);
352
353 /*
354 * Lock down the hardware resources
355 */
356 sc_adapter[cinst]->interrupt = irq[b];
357 if (request_irq(sc_adapter[cinst]->interrupt, interrupt_handler,
358 SA_INTERRUPT, interface->id, NULL))
359 {
360 kfree(sc_adapter[cinst]->channel);
361 indicate_status(cinst, ISDN_STAT_UNLOAD, 0, NULL); /* Fix me */
362 kfree(interface);
363 kfree(sc_adapter[cinst]);
364 continue;
365
366 }
367 sc_adapter[cinst]->iobase = io[b];
368 for(i = 0 ; i < MAX_IO_REGS - 1 ; i++) {
369 sc_adapter[cinst]->ioport[i] = io[b] + i * 0x400;
370 request_region(sc_adapter[cinst]->ioport[i], 1,
371 interface->id);
372 pr_debug("Requesting I/O Port %#x\n",
373 sc_adapter[cinst]->ioport[i]);
374 }
375 sc_adapter[cinst]->ioport[IRQ_SELECT] = io[b] + 0x2;
376 request_region(sc_adapter[cinst]->ioport[IRQ_SELECT], 1,
377 interface->id);
378 pr_debug("Requesting I/O Port %#x\n",
379 sc_adapter[cinst]->ioport[IRQ_SELECT]);
380 sc_adapter[cinst]->rambase = ram[b];
381 request_region(sc_adapter[cinst]->rambase, SRAM_PAGESIZE,
382 interface->id);
383
384 pr_info(" %s (%d) - %s %d channels IRQ %d, I/O Base 0x%x, RAM Base 0x%lx\n",
385 sc_adapter[cinst]->devicename,
386 sc_adapter[cinst]->driverId,
387 boardname[model], channels, irq[b], io[b], ram[b]);
388
389 /*
390 * reset the adapter to put things in motion
391 */
392 reset(cinst);
393
394 cinst++;
395 status = 0;
396 }
397 if (status)
398 pr_info("Failed to find any adapters, driver unloaded\n");
399 return status;
400}
401
402static void __exit sc_exit(void)
403{
404 int i, j;
405
406 for(i = 0 ; i < cinst ; i++) {
407 pr_debug("Cleaning up after adapter %d\n", i);
408 /*
409 * kill the timers
410 */
411 del_timer(&(sc_adapter[i]->reset_timer));
412 del_timer(&(sc_adapter[i]->stat_timer));
413
414 /*
415 * Tell I4L we're toast
416 */
417 indicate_status(i, ISDN_STAT_STOP, 0, NULL);
418 indicate_status(i, ISDN_STAT_UNLOAD, 0, NULL);
419
420 /*
421 * Release shared RAM
422 */
423 release_region(sc_adapter[i]->rambase, SRAM_PAGESIZE);
424
425 /*
426 * Release the IRQ
427 */
428 FREE_IRQ(sc_adapter[i]->interrupt, NULL);
429
430 /*
431 * Reset for a clean start
432 */
433 outb(0xFF, sc_adapter[i]->ioport[SFT_RESET]);
434
435 /*
436 * Release the I/O Port regions
437 */
438 for(j = 0 ; j < MAX_IO_REGS - 1; j++) {
439 release_region(sc_adapter[i]->ioport[j], 1);
440 pr_debug("Releasing I/O Port %#x\n",
441 sc_adapter[i]->ioport[j]);
442 }
443 release_region(sc_adapter[i]->ioport[IRQ_SELECT], 1);
444 pr_debug("Releasing I/O Port %#x\n",
445 sc_adapter[i]->ioport[IRQ_SELECT]);
446
447 /*
448 * Release any memory we alloced
449 */
450 kfree(sc_adapter[i]->channel);
451 kfree(sc_adapter[i]->card);
452 kfree(sc_adapter[i]);
453 }
454 pr_info("SpellCaster ISA ISDN Adapter Driver Unloaded.\n");
455}
456
457int identify_board(unsigned long rambase, unsigned int iobase)
458{
459 unsigned int pgport;
460 unsigned long sig;
461 DualPortMemory *dpm;
462 RspMessage rcvmsg;
463 ReqMessage sndmsg;
464 HWConfig_pl hwci;
465 int x;
466
467 pr_debug("Attempting to identify adapter @ 0x%x io 0x%x\n",
468 rambase, iobase);
469
470 /*
471 * Enable the base pointer
472 */
473 outb(rambase >> 12, iobase + 0x2c00);
474
475 switch(rambase >> 12 & 0x0F) {
476 case 0x0:
477 pgport = iobase + PG0_OFFSET;
478 pr_debug("Page Register offset is 0x%x\n", PG0_OFFSET);
479 break;
480
481 case 0x4:
482 pgport = iobase + PG1_OFFSET;
483 pr_debug("Page Register offset is 0x%x\n", PG1_OFFSET);
484 break;
485
486 case 0x8:
487 pgport = iobase + PG2_OFFSET;
488 pr_debug("Page Register offset is 0x%x\n", PG2_OFFSET);
489 break;
490
491 case 0xC:
492 pgport = iobase + PG3_OFFSET;
493 pr_debug("Page Register offset is 0x%x\n", PG3_OFFSET);
494 break;
495 default:
496 pr_debug("Invalid rambase 0x%lx\n", rambase);
497 return -1;
498 }
499
500 /*
501 * Try to identify a PRI card
502 */
503 outb(PRI_BASEPG_VAL, pgport);
504 msleep_interruptible(1000);
505 sig = readl(rambase + SIG_OFFSET);
506 pr_debug("Looking for a signature, got 0x%x\n", sig);
507 if(sig == SIGNATURE)
508 return PRI_BOARD;
509
510 /*
511 * Try to identify a PRI card
512 */
513 outb(BRI_BASEPG_VAL, pgport);
514 msleep_interruptible(1000);
515 sig = readl(rambase + SIG_OFFSET);
516 pr_debug("Looking for a signature, got 0x%x\n", sig);
517 if(sig == SIGNATURE)
518 return BRI_BOARD;
519
520 return -1;
521
522 /*
523 * Try to spot a card
524 */
525 sig = readl(rambase + SIG_OFFSET);
526 pr_debug("Looking for a signature, got 0x%x\n", sig);
527 if(sig != SIGNATURE)
528 return -1;
529
530 dpm = (DualPortMemory *) rambase;
531
532 memset(&sndmsg, 0, MSG_LEN);
533 sndmsg.msg_byte_cnt = 3;
534 sndmsg.type = cmReqType1;
535 sndmsg.class = cmReqClass0;
536 sndmsg.code = cmReqHWConfig;
537 memcpy_toio(&(dpm->req_queue[dpm->req_head++]), &sndmsg, MSG_LEN);
538 outb(0, iobase + 0x400);
539 pr_debug("Sent HWConfig message\n");
540 /*
541 * Wait for the response
542 */
543 x = 0;
544 while((inb(iobase + FIFOSTAT_OFFSET) & RF_HAS_DATA) && x < 100) {
545 set_current_state(TASK_INTERRUPTIBLE);
546 schedule_timeout(1);
547 x++;
548 }
549 if(x == 100) {
550 pr_debug("Timeout waiting for response\n");
551 return -1;
552 }
553
554 memcpy_fromio(&rcvmsg, &(dpm->rsp_queue[dpm->rsp_tail]), MSG_LEN);
555 pr_debug("Got HWConfig response, status = 0x%x\n", rcvmsg.rsp_status);
556 memcpy(&hwci, &(rcvmsg.msg_data.HWCresponse), sizeof(HWConfig_pl));
557 pr_debug("Hardware Config: Interface: %s, RAM Size: %d, Serial: %s\n"
558 " Part: %s, Rev: %s\n",
559 hwci.st_u_sense ? "S/T" : "U", hwci.ram_size,
560 hwci.serial_no, hwci.part_no, hwci.rev_no);
561
562 if(!strncmp(PRI_PARTNO, hwci.part_no, 6))
563 return PRI_BOARD;
564 if(!strncmp(BRI_PARTNO, hwci.part_no, 6))
565 return BRI_BOARD;
566
567 return -1;
568}
569
570module_init(sc_init);
571module_exit(sc_exit);
diff --git a/drivers/isdn/sc/interrupt.c b/drivers/isdn/sc/interrupt.c
new file mode 100644
index 000000000000..e5e164aca7fa
--- /dev/null
+++ b/drivers/isdn/sc/interrupt.c
@@ -0,0 +1,260 @@
1/* $Id: interrupt.c,v 1.4.8.3 2001/09/23 22:24:59 kai Exp $
2 *
3 * Copyright (C) 1996 SpellCaster Telecommunications Inc.
4 *
5 * This software may be used and distributed according to the terms
6 * of the GNU General Public License, incorporated herein by reference.
7 *
8 * For more information, please contact gpl-info@spellcast.com or write:
9 *
10 * SpellCaster Telecommunications Inc.
11 * 5621 Finch Avenue East, Unit #3
12 * Scarborough, Ontario Canada
13 * M1B 2T9
14 * +1 (416) 297-8565
15 * +1 (416) 297-6433 Facsimile
16 */
17
18#include "includes.h"
19#include "hardware.h"
20#include "message.h"
21#include "card.h"
22#include <linux/interrupt.h>
23
24extern int indicate_status(int, int, ulong, char *);
25extern void check_phystat(unsigned long);
26extern int receivemessage(int, RspMessage *);
27extern int sendmessage(int, unsigned int, unsigned int, unsigned int,
28 unsigned int, unsigned int, unsigned int, unsigned int *);
29extern void rcvpkt(int, RspMessage *);
30
31extern int cinst;
32extern board *sc_adapter[];
33
34int get_card_from_irq(int irq)
35{
36 int i;
37
38 for(i = 0 ; i < cinst ; i++) {
39 if(sc_adapter[i]->interrupt == irq)
40 return i;
41 }
42 return -1;
43}
44
45/*
46 *
47 */
48irqreturn_t interrupt_handler(int interrupt, void *cardptr, struct pt_regs *regs)
49{
50
51 RspMessage rcvmsg;
52 int channel;
53 int card;
54
55 card = get_card_from_irq(interrupt);
56
57 if(!IS_VALID_CARD(card)) {
58 pr_debug("Invalid param: %d is not a valid card id\n", card);
59 return IRQ_NONE;
60 }
61
62 pr_debug("%s: Entered Interrupt handler\n",
63 sc_adapter[card]->devicename);
64
65 /*
66 * Pull all of the waiting messages off the response queue
67 */
68 while (!receivemessage(card, &rcvmsg)) {
69 /*
70 * Push the message to the adapter structure for
71 * send_and_receive to snoop
72 */
73 if(sc_adapter[card]->want_async_messages)
74 memcpy(&(sc_adapter[card]->async_msg),
75 &rcvmsg, sizeof(RspMessage));
76
77 channel = (unsigned int) rcvmsg.phy_link_no;
78
79 /*
80 * Trap Invalid request messages
81 */
82 if(IS_CM_MESSAGE(rcvmsg, 0, 0, Invalid)) {
83 pr_debug("%s: Invalid request Message, rsp_status = %d\n",
84 sc_adapter[card]->devicename,
85 rcvmsg.rsp_status);
86 break;
87 }
88
89 /*
90 * Check for a linkRead message
91 */
92 if (IS_CE_MESSAGE(rcvmsg, Lnk, 1, Read))
93 {
94 pr_debug("%s: Received packet 0x%x bytes long at 0x%x\n",
95 sc_adapter[card]->devicename,
96 rcvmsg.msg_data.response.msg_len,
97 rcvmsg.msg_data.response.buff_offset);
98 rcvpkt(card, &rcvmsg);
99 continue;
100
101 }
102
103 /*
104 * Handle a write acknoledgement
105 */
106 if(IS_CE_MESSAGE(rcvmsg, Lnk, 1, Write)) {
107 pr_debug("%s: Packet Send ACK on channel %d\n",
108 sc_adapter[card]->devicename,
109 rcvmsg.phy_link_no);
110 sc_adapter[card]->channel[rcvmsg.phy_link_no-1].free_sendbufs++;
111 continue;
112 }
113
114 /*
115 * Handle a connection message
116 */
117 if (IS_CE_MESSAGE(rcvmsg, Phy, 1, Connect))
118 {
119 unsigned int callid;
120 setup_parm setup;
121 pr_debug("%s: Connect message: line %d: status %d: cause 0x%x\n",
122 sc_adapter[card]->devicename,
123 rcvmsg.phy_link_no,
124 rcvmsg.rsp_status,
125 rcvmsg.msg_data.byte_array[2]);
126
127 memcpy(&callid,rcvmsg.msg_data.byte_array,sizeof(int));
128 if(callid>=0x8000 && callid<=0xFFFF)
129 {
130 pr_debug("%s: Got Dial-Out Rsp\n",
131 sc_adapter[card]->devicename);
132 indicate_status(card, ISDN_STAT_DCONN,
133 (unsigned long)rcvmsg.phy_link_no-1,NULL);
134
135 }
136 else if(callid>=0x0000 && callid<=0x7FFF)
137 {
138 pr_debug("%s: Got Incoming Call\n",
139 sc_adapter[card]->devicename);
140 strcpy(setup.phone,&(rcvmsg.msg_data.byte_array[4]));
141 strcpy(setup.eazmsn,
142 sc_adapter[card]->channel[rcvmsg.phy_link_no-1].dn);
143 setup.si1 = 7;
144 setup.si2 = 0;
145 setup.plan = 0;
146 setup.screen = 0;
147
148 indicate_status(card, ISDN_STAT_ICALL,(unsigned long)rcvmsg.phy_link_no-1,(char *)&setup);
149 indicate_status(card, ISDN_STAT_DCONN,(unsigned long)rcvmsg.phy_link_no-1,NULL);
150 }
151 continue;
152 }
153
154 /*
155 * Handle a disconnection message
156 */
157 if (IS_CE_MESSAGE(rcvmsg, Phy, 1, Disconnect))
158 {
159 pr_debug("%s: disconnect message: line %d: status %d: cause 0x%x\n",
160 sc_adapter[card]->devicename,
161 rcvmsg.phy_link_no,
162 rcvmsg.rsp_status,
163 rcvmsg.msg_data.byte_array[2]);
164
165 indicate_status(card, ISDN_STAT_BHUP,(unsigned long)rcvmsg.phy_link_no-1,NULL);
166 indicate_status(card, ISDN_STAT_DHUP,(unsigned long)rcvmsg.phy_link_no-1,NULL);
167 continue;
168
169 }
170
171 /*
172 * Handle a startProc engine up message
173 */
174 if (IS_CM_MESSAGE(rcvmsg, 5, 0, MiscEngineUp)) {
175 pr_debug("%s: Received EngineUp message\n",
176 sc_adapter[card]->devicename);
177 sc_adapter[card]->EngineUp = 1;
178 sendmessage(card, CEPID,ceReqTypeCall,ceReqClass0,ceReqCallGetMyNumber,1,0,NULL);
179 sendmessage(card, CEPID,ceReqTypeCall,ceReqClass0,ceReqCallGetMyNumber,2,0,NULL);
180 init_timer(&sc_adapter[card]->stat_timer);
181 sc_adapter[card]->stat_timer.function = check_phystat;
182 sc_adapter[card]->stat_timer.data = card;
183 sc_adapter[card]->stat_timer.expires = jiffies + CHECKSTAT_TIME;
184 add_timer(&sc_adapter[card]->stat_timer);
185 continue;
186 }
187
188 /*
189 * Start proc response
190 */
191 if (IS_CM_MESSAGE(rcvmsg, 2, 0, StartProc)) {
192 pr_debug("%s: StartProc Response Status %d\n",
193 sc_adapter[card]->devicename,
194 rcvmsg.rsp_status);
195 continue;
196 }
197
198 /*
199 * Handle a GetMyNumber Rsp
200 */
201 if (IS_CE_MESSAGE(rcvmsg,Call,0,GetMyNumber)){
202 strcpy(sc_adapter[card]->channel[rcvmsg.phy_link_no-1].dn,rcvmsg.msg_data.byte_array);
203 continue;
204 }
205
206 /*
207 * PhyStatus response
208 */
209 if(IS_CE_MESSAGE(rcvmsg, Phy, 2, Status)) {
210 unsigned int b1stat, b2stat;
211
212 /*
213 * Covert the message data to the adapter->phystat code
214 */
215 b1stat = (unsigned int) rcvmsg.msg_data.byte_array[0];
216 b2stat = (unsigned int) rcvmsg.msg_data.byte_array[1];
217
218 sc_adapter[card]->nphystat = (b2stat >> 8) | b1stat; /* endian?? */
219 pr_debug("%s: PhyStat is 0x%2x\n",
220 sc_adapter[card]->devicename,
221 sc_adapter[card]->nphystat);
222 continue;
223 }
224
225
226 /*
227 * Handle a GetFramFormat
228 */
229 if(IS_CE_MESSAGE(rcvmsg, Call, 0, GetFrameFormat)) {
230 if(rcvmsg.msg_data.byte_array[0] != HDLC_PROTO) {
231 unsigned int proto = HDLC_PROTO;
232 /*
233 * Set board format to HDLC if it wasn't already
234 */
235 pr_debug("%s: current frame format: 0x%x, will change to HDLC\n",
236 sc_adapter[card]->devicename,
237 rcvmsg.msg_data.byte_array[0]);
238 sendmessage(card, CEPID, ceReqTypeCall,
239 ceReqClass0,
240 ceReqCallSetFrameFormat,
241 (unsigned char) channel +1,
242 1,&proto);
243 }
244 continue;
245 }
246
247 /*
248 * Hmm...
249 */
250 pr_debug("%s: Received unhandled message (%d,%d,%d) link %d\n",
251 sc_adapter[card]->devicename,
252 rcvmsg.type, rcvmsg.class, rcvmsg.code,
253 rcvmsg.phy_link_no);
254
255 } /* while */
256
257 pr_debug("%s: Exiting Interrupt Handler\n",
258 sc_adapter[card]->devicename);
259 return IRQ_HANDLED;
260}
diff --git a/drivers/isdn/sc/ioctl.c b/drivers/isdn/sc/ioctl.c
new file mode 100644
index 000000000000..1371a990416a
--- /dev/null
+++ b/drivers/isdn/sc/ioctl.c
@@ -0,0 +1,601 @@
1/*
2 * Copyright (C) 1996 SpellCaster Telecommunications Inc.
3 *
4 * This software may be used and distributed according to the terms
5 * of the GNU General Public License, incorporated herein by reference.
6 *
7 */
8
9#include "includes.h"
10#include "hardware.h"
11#include "message.h"
12#include "card.h"
13#include "scioc.h"
14
15extern int indicate_status(int, int, unsigned long, char *);
16extern int startproc(int);
17extern int loadproc(int, char *record);
18extern int reset(int);
19extern int send_and_receive(int, unsigned int, unsigned char,unsigned char,
20 unsigned char,unsigned char,
21 unsigned char, unsigned char *, RspMessage *, int);
22
23extern board *sc_adapter[];
24
25
26int GetStatus(int card, boardInfo *);
27
28/*
29 * Process private IOCTL messages (typically from scctrl)
30 */
31int sc_ioctl(int card, scs_ioctl *data)
32{
33 int status;
34 RspMessage *rcvmsg;
35 char *spid;
36 char *dn;
37 char switchtype;
38 char speed;
39
40 rcvmsg = kmalloc(sizeof(RspMessage), GFP_KERNEL);
41 if (!rcvmsg)
42 return -ENOMEM;
43
44 switch(data->command) {
45 case SCIOCRESET: /* Perform a hard reset of the adapter */
46 {
47 pr_debug("%s: SCIOCRESET: ioctl received\n",
48 sc_adapter[card]->devicename);
49 sc_adapter[card]->StartOnReset = 0;
50 return (reset(card));
51 }
52
53 case SCIOCLOAD:
54 {
55 char *srec;
56
57 srec = kmalloc(SCIOC_SRECSIZE, GFP_KERNEL);
58 if (!srec) {
59 kfree(rcvmsg);
60 return -ENOMEM;
61 }
62 pr_debug("%s: SCIOLOAD: ioctl received\n",
63 sc_adapter[card]->devicename);
64 if(sc_adapter[card]->EngineUp) {
65 pr_debug("%s: SCIOCLOAD: command failed, LoadProc while engine running.\n",
66 sc_adapter[card]->devicename);
67 kfree(rcvmsg);
68 kfree(srec);
69 return -1;
70 }
71
72 /*
73 * Get the SRec from user space
74 */
75 if (copy_from_user(srec, data->dataptr, sizeof(srec))) {
76 kfree(rcvmsg);
77 kfree(srec);
78 return -EFAULT;
79 }
80
81 status = send_and_receive(card, CMPID, cmReqType2, cmReqClass0, cmReqLoadProc,
82 0, sizeof(srec), srec, rcvmsg, SAR_TIMEOUT);
83 kfree(rcvmsg);
84 kfree(srec);
85
86 if(status) {
87 pr_debug("%s: SCIOCLOAD: command failed, status = %d\n",
88 sc_adapter[card]->devicename, status);
89 return -1;
90 }
91 else {
92 pr_debug("%s: SCIOCLOAD: command successful\n",
93 sc_adapter[card]->devicename);
94 return 0;
95 }
96 }
97
98 case SCIOCSTART:
99 {
100 pr_debug("%s: SCIOSTART: ioctl received\n",
101 sc_adapter[card]->devicename);
102 if(sc_adapter[card]->EngineUp) {
103 pr_debug("%s: SCIOCSTART: command failed, engine already running.\n",
104 sc_adapter[card]->devicename);
105 return -1;
106 }
107
108 sc_adapter[card]->StartOnReset = 1;
109 startproc(card);
110 return 0;
111 }
112
113 case SCIOCSETSWITCH:
114 {
115 pr_debug("%s: SCIOSETSWITCH: ioctl received\n",
116 sc_adapter[card]->devicename);
117
118 /*
119 * Get the switch type from user space
120 */
121 if (copy_from_user(&switchtype, data->dataptr, sizeof(char))) {
122 kfree(rcvmsg);
123 return -EFAULT;
124 }
125
126 pr_debug("%s: SCIOCSETSWITCH: setting switch type to %d\n",
127 sc_adapter[card]->devicename,
128 switchtype);
129 status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0, ceReqCallSetSwitchType,
130 0, sizeof(char),&switchtype, rcvmsg, SAR_TIMEOUT);
131 if(!status && !(rcvmsg->rsp_status)) {
132 pr_debug("%s: SCIOCSETSWITCH: command successful\n",
133 sc_adapter[card]->devicename);
134 kfree(rcvmsg);
135 return 0;
136 }
137 else {
138 pr_debug("%s: SCIOCSETSWITCH: command failed (status = %d)\n",
139 sc_adapter[card]->devicename, status);
140 kfree(rcvmsg);
141 return status;
142 }
143 }
144
145 case SCIOCGETSWITCH:
146 {
147 pr_debug("%s: SCIOGETSWITCH: ioctl received\n",
148 sc_adapter[card]->devicename);
149
150 /*
151 * Get the switch type from the board
152 */
153 status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0,
154 ceReqCallGetSwitchType, 0, 0, NULL, rcvmsg, SAR_TIMEOUT);
155 if (!status && !(rcvmsg->rsp_status)) {
156 pr_debug("%s: SCIOCGETSWITCH: command successful\n",
157 sc_adapter[card]->devicename);
158 }
159 else {
160 pr_debug("%s: SCIOCGETSWITCH: command failed (status = %d)\n",
161 sc_adapter[card]->devicename, status);
162 kfree(rcvmsg);
163 return status;
164 }
165
166 switchtype = rcvmsg->msg_data.byte_array[0];
167
168 /*
169 * Package the switch type and send to user space
170 */
171 if (copy_to_user(data->dataptr, &switchtype,
172 sizeof(char))) {
173 kfree(rcvmsg);
174 return -EFAULT;
175 }
176
177 kfree(rcvmsg);
178 return 0;
179 }
180
181 case SCIOCGETSPID:
182 {
183 pr_debug("%s: SCIOGETSPID: ioctl received\n",
184 sc_adapter[card]->devicename);
185
186 spid = kmalloc(SCIOC_SPIDSIZE, GFP_KERNEL);
187 if(!spid) {
188 kfree(rcvmsg);
189 return -ENOMEM;
190 }
191 /*
192 * Get the spid from the board
193 */
194 status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0, ceReqCallGetSPID,
195 data->channel, 0, NULL, rcvmsg, SAR_TIMEOUT);
196 if (!status) {
197 pr_debug("%s: SCIOCGETSPID: command successful\n",
198 sc_adapter[card]->devicename);
199 }
200 else {
201 pr_debug("%s: SCIOCGETSPID: command failed (status = %d)\n",
202 sc_adapter[card]->devicename, status);
203 kfree(rcvmsg);
204 return status;
205 }
206 strcpy(spid, rcvmsg->msg_data.byte_array);
207
208 /*
209 * Package the switch type and send to user space
210 */
211 if (copy_to_user(data->dataptr, spid, SCIOC_SPIDSIZE)) {
212 kfree(spid);
213 kfree(rcvmsg);
214 return -EFAULT;
215 }
216
217 kfree(spid);
218 kfree(rcvmsg);
219 return 0;
220 }
221
222 case SCIOCSETSPID:
223 {
224 pr_debug("%s: DCBIOSETSPID: ioctl received\n",
225 sc_adapter[card]->devicename);
226
227 spid = kmalloc(SCIOC_SPIDSIZE, GFP_KERNEL);
228 if(!spid) {
229 kfree(rcvmsg);
230 return -ENOMEM;
231 }
232
233 /*
234 * Get the spid from user space
235 */
236 if (copy_from_user(spid, data->dataptr, SCIOC_SPIDSIZE)) {
237 kfree(rcvmsg);
238 return -EFAULT;
239 }
240
241 pr_debug("%s: SCIOCSETSPID: setting channel %d spid to %s\n",
242 sc_adapter[card]->devicename, data->channel, spid);
243 status = send_and_receive(card, CEPID, ceReqTypeCall,
244 ceReqClass0, ceReqCallSetSPID, data->channel,
245 strlen(spid), spid, rcvmsg, SAR_TIMEOUT);
246 if(!status && !(rcvmsg->rsp_status)) {
247 pr_debug("%s: SCIOCSETSPID: command successful\n",
248 sc_adapter[card]->devicename);
249 kfree(rcvmsg);
250 kfree(spid);
251 return 0;
252 }
253 else {
254 pr_debug("%s: SCIOCSETSPID: command failed (status = %d)\n",
255 sc_adapter[card]->devicename, status);
256 kfree(rcvmsg);
257 kfree(spid);
258 return status;
259 }
260 }
261
262 case SCIOCGETDN:
263 {
264 pr_debug("%s: SCIOGETDN: ioctl received\n",
265 sc_adapter[card]->devicename);
266
267 /*
268 * Get the dn from the board
269 */
270 status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0, ceReqCallGetMyNumber,
271 data->channel, 0, NULL, rcvmsg, SAR_TIMEOUT);
272 if (!status) {
273 pr_debug("%s: SCIOCGETDN: command successful\n",
274 sc_adapter[card]->devicename);
275 }
276 else {
277 pr_debug("%s: SCIOCGETDN: command failed (status = %d)\n",
278 sc_adapter[card]->devicename, status);
279 kfree(rcvmsg);
280 return status;
281 }
282
283 dn = kmalloc(SCIOC_DNSIZE, GFP_KERNEL);
284 if (!dn) {
285 kfree(rcvmsg);
286 return -ENOMEM;
287 }
288 strcpy(dn, rcvmsg->msg_data.byte_array);
289 kfree(rcvmsg);
290
291 /*
292 * Package the dn and send to user space
293 */
294 if (copy_to_user(data->dataptr, dn, SCIOC_DNSIZE)) {
295 kfree(dn);
296 return -EFAULT;
297 }
298 kfree(dn);
299 return 0;
300 }
301
302 case SCIOCSETDN:
303 {
304 pr_debug("%s: SCIOSETDN: ioctl received\n",
305 sc_adapter[card]->devicename);
306
307 dn = kmalloc(SCIOC_DNSIZE, GFP_KERNEL);
308 if (!dn) {
309 kfree(rcvmsg);
310 return -ENOMEM;
311 }
312 /*
313 * Get the spid from user space
314 */
315 if (copy_from_user(dn, data->dataptr, SCIOC_DNSIZE)) {
316 kfree(rcvmsg);
317 kfree(dn);
318 return -EFAULT;
319 }
320
321 pr_debug("%s: SCIOCSETDN: setting channel %d dn to %s\n",
322 sc_adapter[card]->devicename, data->channel, dn);
323 status = send_and_receive(card, CEPID, ceReqTypeCall,
324 ceReqClass0, ceReqCallSetMyNumber, data->channel,
325 strlen(dn),dn,rcvmsg, SAR_TIMEOUT);
326 if(!status && !(rcvmsg->rsp_status)) {
327 pr_debug("%s: SCIOCSETDN: command successful\n",
328 sc_adapter[card]->devicename);
329 kfree(rcvmsg);
330 kfree(dn);
331 return 0;
332 }
333 else {
334 pr_debug("%s: SCIOCSETDN: command failed (status = %d)\n",
335 sc_adapter[card]->devicename, status);
336 kfree(rcvmsg);
337 kfree(dn);
338 return status;
339 }
340 }
341
342 case SCIOCTRACE:
343
344 pr_debug("%s: SCIOTRACE: ioctl received\n",
345 sc_adapter[card]->devicename);
346/* sc_adapter[card]->trace = !sc_adapter[card]->trace;
347 pr_debug("%s: SCIOCTRACE: tracing turned %s\n",
348 sc_adapter[card]->devicename,
349 sc_adapter[card]->trace ? "ON" : "OFF"); */
350 break;
351
352 case SCIOCSTAT:
353 {
354 boardInfo *bi;
355
356 pr_debug("%s: SCIOSTAT: ioctl received\n",
357 sc_adapter[card]->devicename);
358
359 bi = kmalloc (sizeof(boardInfo), GFP_KERNEL);
360 if (!bi) {
361 kfree(rcvmsg);
362 return -ENOMEM;
363 }
364
365 kfree(rcvmsg);
366 GetStatus(card, bi);
367
368 if (copy_to_user(data->dataptr, bi, sizeof(boardInfo))) {
369 kfree(bi);
370 return -EFAULT;
371 }
372
373 kfree(bi);
374 return 0;
375 }
376
377 case SCIOCGETSPEED:
378 {
379 pr_debug("%s: SCIOGETSPEED: ioctl received\n",
380 sc_adapter[card]->devicename);
381
382 /*
383 * Get the speed from the board
384 */
385 status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0,
386 ceReqCallGetCallType, data->channel, 0, NULL, rcvmsg, SAR_TIMEOUT);
387 if (!status && !(rcvmsg->rsp_status)) {
388 pr_debug("%s: SCIOCGETSPEED: command successful\n",
389 sc_adapter[card]->devicename);
390 }
391 else {
392 pr_debug("%s: SCIOCGETSPEED: command failed (status = %d)\n",
393 sc_adapter[card]->devicename, status);
394 kfree(rcvmsg);
395 return status;
396 }
397
398 speed = rcvmsg->msg_data.byte_array[0];
399
400 kfree(rcvmsg);
401
402 /*
403 * Package the switch type and send to user space
404 */
405
406 if (copy_to_user(data->dataptr, &speed, sizeof(char)))
407 return -EFAULT;
408
409 return 0;
410 }
411
412 case SCIOCSETSPEED:
413 pr_debug("%s: SCIOCSETSPEED: ioctl received\n",
414 sc_adapter[card]->devicename);
415 break;
416
417 case SCIOCLOOPTST:
418 pr_debug("%s: SCIOCLOOPTST: ioctl received\n",
419 sc_adapter[card]->devicename);
420 break;
421
422 default:
423 kfree(rcvmsg);
424 return -1;
425 }
426
427 kfree(rcvmsg);
428 return 0;
429}
430
431int GetStatus(int card, boardInfo *bi)
432{
433 RspMessage rcvmsg;
434 int i, status;
435
436 /*
437 * Fill in some of the basic info about the board
438 */
439 bi->modelid = sc_adapter[card]->model;
440 strcpy(bi->serial_no, sc_adapter[card]->hwconfig.serial_no);
441 strcpy(bi->part_no, sc_adapter[card]->hwconfig.part_no);
442 bi->iobase = sc_adapter[card]->iobase;
443 bi->rambase = sc_adapter[card]->rambase;
444 bi->irq = sc_adapter[card]->interrupt;
445 bi->ramsize = sc_adapter[card]->hwconfig.ram_size;
446 bi->interface = sc_adapter[card]->hwconfig.st_u_sense;
447 strcpy(bi->load_ver, sc_adapter[card]->load_ver);
448 strcpy(bi->proc_ver, sc_adapter[card]->proc_ver);
449
450 /*
451 * Get the current PhyStats and LnkStats
452 */
453 status = send_and_receive(card, CEPID, ceReqTypePhy, ceReqClass2,
454 ceReqPhyStatus, 0, 0, NULL, &rcvmsg, SAR_TIMEOUT);
455 if(!status) {
456 if(sc_adapter[card]->model < PRI_BOARD) {
457 bi->l1_status = rcvmsg.msg_data.byte_array[2];
458 for(i = 0 ; i < BRI_CHANNELS ; i++)
459 bi->status.bristats[i].phy_stat =
460 rcvmsg.msg_data.byte_array[i];
461 }
462 else {
463 bi->l1_status = rcvmsg.msg_data.byte_array[0];
464 bi->l2_status = rcvmsg.msg_data.byte_array[1];
465 for(i = 0 ; i < PRI_CHANNELS ; i++)
466 bi->status.pristats[i].phy_stat =
467 rcvmsg.msg_data.byte_array[i+2];
468 }
469 }
470
471 /*
472 * Get the call types for each channel
473 */
474 for (i = 0 ; i < sc_adapter[card]->nChannels ; i++) {
475 status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0,
476 ceReqCallGetCallType, 0, 0, NULL, &rcvmsg, SAR_TIMEOUT);
477 if(!status) {
478 if (sc_adapter[card]->model == PRI_BOARD) {
479 bi->status.pristats[i].call_type =
480 rcvmsg.msg_data.byte_array[0];
481 }
482 else {
483 bi->status.bristats[i].call_type =
484 rcvmsg.msg_data.byte_array[0];
485 }
486 }
487 }
488
489 /*
490 * If PRI, get the call states and service states for each channel
491 */
492 if (sc_adapter[card]->model == PRI_BOARD) {
493 /*
494 * Get the call states
495 */
496 status = send_and_receive(card, CEPID, ceReqTypeStat, ceReqClass2,
497 ceReqPhyChCallState, 0, 0, NULL, &rcvmsg, SAR_TIMEOUT);
498 if(!status) {
499 for( i = 0 ; i < PRI_CHANNELS ; i++ )
500 bi->status.pristats[i].call_state =
501 rcvmsg.msg_data.byte_array[i];
502 }
503
504 /*
505 * Get the service states
506 */
507 status = send_and_receive(card, CEPID, ceReqTypeStat, ceReqClass2,
508 ceReqPhyChServState, 0, 0, NULL, &rcvmsg, SAR_TIMEOUT);
509 if(!status) {
510 for( i = 0 ; i < PRI_CHANNELS ; i++ )
511 bi->status.pristats[i].serv_state =
512 rcvmsg.msg_data.byte_array[i];
513 }
514
515 /*
516 * Get the link stats for the channels
517 */
518 for (i = 1 ; i <= PRI_CHANNELS ; i++) {
519 status = send_and_receive(card, CEPID, ceReqTypeLnk, ceReqClass0,
520 ceReqLnkGetStats, i, 0, NULL, &rcvmsg, SAR_TIMEOUT);
521 if (!status) {
522 bi->status.pristats[i-1].link_stats.tx_good =
523 (unsigned long)rcvmsg.msg_data.byte_array[0];
524 bi->status.pristats[i-1].link_stats.tx_bad =
525 (unsigned long)rcvmsg.msg_data.byte_array[4];
526 bi->status.pristats[i-1].link_stats.rx_good =
527 (unsigned long)rcvmsg.msg_data.byte_array[8];
528 bi->status.pristats[i-1].link_stats.rx_bad =
529 (unsigned long)rcvmsg.msg_data.byte_array[12];
530 }
531 }
532
533 /*
534 * Link stats for the D channel
535 */
536 status = send_and_receive(card, CEPID, ceReqTypeLnk, ceReqClass0,
537 ceReqLnkGetStats, 0, 0, NULL, &rcvmsg, SAR_TIMEOUT);
538 if (!status) {
539 bi->dch_stats.tx_good = (unsigned long)rcvmsg.msg_data.byte_array[0];
540 bi->dch_stats.tx_bad = (unsigned long)rcvmsg.msg_data.byte_array[4];
541 bi->dch_stats.rx_good = (unsigned long)rcvmsg.msg_data.byte_array[8];
542 bi->dch_stats.rx_bad = (unsigned long)rcvmsg.msg_data.byte_array[12];
543 }
544
545 return 0;
546 }
547
548 /*
549 * If BRI or POTS, Get SPID, DN and call types for each channel
550 */
551
552 /*
553 * Get the link stats for the channels
554 */
555 status = send_and_receive(card, CEPID, ceReqTypeLnk, ceReqClass0,
556 ceReqLnkGetStats, 0, 0, NULL, &rcvmsg, SAR_TIMEOUT);
557 if (!status) {
558 bi->dch_stats.tx_good = (unsigned long)rcvmsg.msg_data.byte_array[0];
559 bi->dch_stats.tx_bad = (unsigned long)rcvmsg.msg_data.byte_array[4];
560 bi->dch_stats.rx_good = (unsigned long)rcvmsg.msg_data.byte_array[8];
561 bi->dch_stats.rx_bad = (unsigned long)rcvmsg.msg_data.byte_array[12];
562 bi->status.bristats[0].link_stats.tx_good =
563 (unsigned long)rcvmsg.msg_data.byte_array[16];
564 bi->status.bristats[0].link_stats.tx_bad =
565 (unsigned long)rcvmsg.msg_data.byte_array[20];
566 bi->status.bristats[0].link_stats.rx_good =
567 (unsigned long)rcvmsg.msg_data.byte_array[24];
568 bi->status.bristats[0].link_stats.rx_bad =
569 (unsigned long)rcvmsg.msg_data.byte_array[28];
570 bi->status.bristats[1].link_stats.tx_good =
571 (unsigned long)rcvmsg.msg_data.byte_array[32];
572 bi->status.bristats[1].link_stats.tx_bad =
573 (unsigned long)rcvmsg.msg_data.byte_array[36];
574 bi->status.bristats[1].link_stats.rx_good =
575 (unsigned long)rcvmsg.msg_data.byte_array[40];
576 bi->status.bristats[1].link_stats.rx_bad =
577 (unsigned long)rcvmsg.msg_data.byte_array[44];
578 }
579
580 /*
581 * Get the SPIDs
582 */
583 for (i = 0 ; i < BRI_CHANNELS ; i++) {
584 status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0,
585 ceReqCallGetSPID, i+1, 0, NULL, &rcvmsg, SAR_TIMEOUT);
586 if (!status)
587 strcpy(bi->status.bristats[i].spid, rcvmsg.msg_data.byte_array);
588 }
589
590 /*
591 * Get the DNs
592 */
593 for (i = 0 ; i < BRI_CHANNELS ; i++) {
594 status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0,
595 ceReqCallGetMyNumber, i+1, 0, NULL, &rcvmsg, SAR_TIMEOUT);
596 if (!status)
597 strcpy(bi->status.bristats[i].dn, rcvmsg.msg_data.byte_array);
598 }
599
600 return 0;
601}
diff --git a/drivers/isdn/sc/message.c b/drivers/isdn/sc/message.c
new file mode 100644
index 000000000000..ca204da3257d
--- /dev/null
+++ b/drivers/isdn/sc/message.c
@@ -0,0 +1,241 @@
1/* $Id: message.c,v 1.5.8.2 2001/09/23 22:24:59 kai Exp $
2 *
3 * functions for sending and receiving control messages
4 *
5 * Copyright (C) 1996 SpellCaster Telecommunications Inc.
6 *
7 * This software may be used and distributed according to the terms
8 * of the GNU General Public License, incorporated herein by reference.
9 *
10 * For more information, please contact gpl-info@spellcast.com or write:
11 *
12 * SpellCaster Telecommunications Inc.
13 * 5621 Finch Avenue East, Unit #3
14 * Scarborough, Ontario Canada
15 * M1B 2T9
16 * +1 (416) 297-8565
17 * +1 (416) 297-6433 Facsimile
18 */
19
20#include "includes.h"
21#include "hardware.h"
22#include "message.h"
23#include "card.h"
24
25extern board *sc_adapter[];
26extern unsigned int cinst;
27
28/*
29 * Obligatory function prototypes
30 */
31extern int indicate_status(int,ulong,char*);
32extern int scm_command(isdn_ctrl *);
33
34
35/*
36 * receive a message from the board
37 */
38int receivemessage(int card, RspMessage *rspmsg)
39{
40 DualPortMemory *dpm;
41 unsigned long flags;
42
43 if (!IS_VALID_CARD(card)) {
44 pr_debug("Invalid param: %d is not a valid card id\n", card);
45 return -EINVAL;
46 }
47
48 pr_debug("%s: Entered receivemessage\n",
49 sc_adapter[card]->devicename);
50
51 /*
52 * See if there are messages waiting
53 */
54 if (inb(sc_adapter[card]->ioport[FIFO_STATUS]) & RF_HAS_DATA) {
55 /*
56 * Map in the DPM to the base page and copy the message
57 */
58 spin_lock_irqsave(&sc_adapter[card]->lock, flags);
59 outb((sc_adapter[card]->shmem_magic >> 14) | 0x80,
60 sc_adapter[card]->ioport[sc_adapter[card]->shmem_pgport]);
61 dpm = (DualPortMemory *) sc_adapter[card]->rambase;
62 memcpy_fromio(rspmsg, &(dpm->rsp_queue[dpm->rsp_tail]),
63 MSG_LEN);
64 dpm->rsp_tail = (dpm->rsp_tail+1) % MAX_MESSAGES;
65 inb(sc_adapter[card]->ioport[FIFO_READ]);
66 spin_unlock_irqrestore(&sc_adapter[card]->lock, flags);
67 /*
68 * Tell the board that the message is received
69 */
70 pr_debug("%s: Received Message seq:%d pid:%d time:%d cmd:%d "
71 "cnt:%d (type,class,code):(%d,%d,%d) "
72 "link:%d stat:0x%x\n",
73 sc_adapter[card]->devicename,
74 rspmsg->sequence_no,
75 rspmsg->process_id,
76 rspmsg->time_stamp,
77 rspmsg->cmd_sequence_no,
78 rspmsg->msg_byte_cnt,
79 rspmsg->type,
80 rspmsg->class,
81 rspmsg->code,
82 rspmsg->phy_link_no,
83 rspmsg->rsp_status);
84
85 return 0;
86 }
87 return -ENOMSG;
88}
89
90/*
91 * send a message to the board
92 */
93int sendmessage(int card,
94 unsigned int procid,
95 unsigned int type,
96 unsigned int class,
97 unsigned int code,
98 unsigned int link,
99 unsigned int data_len,
100 unsigned int *data)
101{
102 DualPortMemory *dpm;
103 ReqMessage sndmsg;
104 unsigned long flags;
105
106 if (!IS_VALID_CARD(card)) {
107 pr_debug("Invalid param: %d is not a valid card id\n", card);
108 return -EINVAL;
109 }
110
111 /*
112 * Make sure we only send CEPID messages when the engine is up
113 * and CMPID messages when it is down
114 */
115 if(sc_adapter[card]->EngineUp && procid == CMPID) {
116 pr_debug("%s: Attempt to send CM message with engine up\n",
117 sc_adapter[card]->devicename);
118 return -ESRCH;
119 }
120
121 if(!sc_adapter[card]->EngineUp && procid == CEPID) {
122 pr_debug("%s: Attempt to send CE message with engine down\n",
123 sc_adapter[card]->devicename);
124 return -ESRCH;
125 }
126
127 memset(&sndmsg, 0, MSG_LEN);
128 sndmsg.msg_byte_cnt = 4;
129 sndmsg.type = type;
130 sndmsg.class = class;
131 sndmsg.code = code;
132 sndmsg.phy_link_no = link;
133
134 if (data_len > 0) {
135 if (data_len > MSG_DATA_LEN)
136 data_len = MSG_DATA_LEN;
137 memcpy(&(sndmsg.msg_data), data, data_len);
138 sndmsg.msg_byte_cnt = data_len + 8;
139 }
140
141 sndmsg.process_id = procid;
142 sndmsg.sequence_no = sc_adapter[card]->seq_no++ % 256;
143
144 /*
145 * wait for an empty slot in the queue
146 */
147 while (!(inb(sc_adapter[card]->ioport[FIFO_STATUS]) & WF_NOT_FULL))
148 udelay(1);
149
150 /*
151 * Disable interrupts and map in shared memory
152 */
153 spin_lock_irqsave(&sc_adapter[card]->lock, flags);
154 outb((sc_adapter[card]->shmem_magic >> 14) | 0x80,
155 sc_adapter[card]->ioport[sc_adapter[card]->shmem_pgport]);
156 dpm = (DualPortMemory *) sc_adapter[card]->rambase; /* Fix me */
157 memcpy_toio(&(dpm->req_queue[dpm->req_head]),&sndmsg,MSG_LEN);
158 dpm->req_head = (dpm->req_head+1) % MAX_MESSAGES;
159 outb(sndmsg.sequence_no, sc_adapter[card]->ioport[FIFO_WRITE]);
160 spin_unlock_irqrestore(&sc_adapter[card]->lock, flags);
161
162 pr_debug("%s: Sent Message seq:%d pid:%d time:%d "
163 "cnt:%d (type,class,code):(%d,%d,%d) "
164 "link:%d\n ",
165 sc_adapter[card]->devicename,
166 sndmsg.sequence_no,
167 sndmsg.process_id,
168 sndmsg.time_stamp,
169 sndmsg.msg_byte_cnt,
170 sndmsg.type,
171 sndmsg.class,
172 sndmsg.code,
173 sndmsg.phy_link_no);
174
175 return 0;
176}
177
178int send_and_receive(int card,
179 unsigned int procid,
180 unsigned char type,
181 unsigned char class,
182 unsigned char code,
183 unsigned char link,
184 unsigned char data_len,
185 unsigned char *data,
186 RspMessage *mesgdata,
187 int timeout)
188{
189 int retval;
190 int tries;
191
192 if (!IS_VALID_CARD(card)) {
193 pr_debug("Invalid param: %d is not a valid card id\n", card);
194 return -EINVAL;
195 }
196
197 sc_adapter[card]->want_async_messages = 1;
198 retval = sendmessage(card, procid, type, class, code, link,
199 data_len, (unsigned int *) data);
200
201 if (retval) {
202 pr_debug("%s: SendMessage failed in SAR\n",
203 sc_adapter[card]->devicename);
204 sc_adapter[card]->want_async_messages = 0;
205 return -EIO;
206 }
207
208 tries = 0;
209 /* wait for the response */
210 while (tries < timeout) {
211 set_current_state(TASK_INTERRUPTIBLE);
212 schedule_timeout(1);
213
214 pr_debug("SAR waiting..\n");
215
216 /*
217 * See if we got our message back
218 */
219 if ((sc_adapter[card]->async_msg.type == type) &&
220 (sc_adapter[card]->async_msg.class == class) &&
221 (sc_adapter[card]->async_msg.code == code) &&
222 (sc_adapter[card]->async_msg.phy_link_no == link)) {
223
224 /*
225 * Got it!
226 */
227 pr_debug("%s: Got ASYNC message\n",
228 sc_adapter[card]->devicename);
229 memcpy(mesgdata, &(sc_adapter[card]->async_msg),
230 sizeof(RspMessage));
231 sc_adapter[card]->want_async_messages = 0;
232 return 0;
233 }
234
235 tries++;
236 }
237
238 pr_debug("%s: SAR message timeout\n", sc_adapter[card]->devicename);
239 sc_adapter[card]->want_async_messages = 0;
240 return -ETIME;
241}
diff --git a/drivers/isdn/sc/message.h b/drivers/isdn/sc/message.h
new file mode 100644
index 000000000000..8eb15e7306b2
--- /dev/null
+++ b/drivers/isdn/sc/message.h
@@ -0,0 +1,245 @@
1/* $Id: message.h,v 1.1.10.1 2001/09/23 22:24:59 kai Exp $
2 *
3 * Copyright (C) 1996 SpellCaster Telecommunications Inc.
4 *
5 * structures, macros and defines useful for sending
6 * messages to the adapter
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 * For more information, please contact gpl-info@spellcast.com or write:
12 *
13 * SpellCaster Telecommunications Inc.
14 * 5621 Finch Avenue East, Unit #3
15 * Scarborough, Ontario Canada
16 * M1B 2T9
17 * +1 (416) 297-8565
18 * +1 (416) 297-6433 Facsimile
19 */
20
21/*
22 * Board message macros, defines and structures
23 */
24
25#ifndef MESSAGE_H
26#define MESSAGE_H
27
28#define MAX_MESSAGES 32 /* Maximum messages that can be
29 queued */
30#define MSG_DATA_LEN 48 /* Maximum size of message payload */
31#define MSG_LEN 64 /* Size of a message */
32#define CMPID 0 /* Loader message process ID */
33#define CEPID 64 /* Firmware message process ID */
34
35/*
36 * Macro to determine if a message is a loader message
37 */
38#define IS_CM_MESSAGE(mesg, tx, cx, dx) \
39 ((mesg.type == cmRspType##tx) \
40 &&(mesg.class == cmRspClass##cx) \
41 &&(mesg.code == cmRsp##dx))
42
43/*
44 * Macro to determine if a message is a firmware message
45 */
46#define IS_CE_MESSAGE(mesg, tx, cx, dx) \
47 ((mesg.type == ceRspType##tx) \
48 &&(mesg.class == ceRspClass##cx) \
49 &&(mesg.code == ceRsp##tx##dx))
50
51/*
52 * Loader Request and Response Messages
53 */
54
55/* message types */
56#define cmReqType1 1
57#define cmReqType2 2
58#define cmRspType0 0
59#define cmRspType1 1
60#define cmRspType2 2
61#define cmRspType5 5
62
63/* message classes */
64#define cmReqClass0 0
65#define cmRspClass0 0
66
67/* message codes */
68#define cmReqHWConfig 1 /* 1,0,1 */
69#define cmReqMsgLpbk 2 /* 1,0,2 */
70#define cmReqVersion 3 /* 1,0,3 */
71#define cmReqLoadProc 1 /* 2,0,1 */
72#define cmReqStartProc 2 /* 2,0,2 */
73#define cmReqReadMem 6 /* 2,0,6 */
74#define cmRspHWConfig cmReqHWConfig
75#define cmRspMsgLpbk cmReqMsgLpbk
76#define cmRspVersion cmReqVersion
77#define cmRspLoadProc cmReqLoadProc
78#define cmRspStartProc cmReqStartProc
79#define cmRspReadMem cmReqReadMem
80#define cmRspMiscEngineUp 1 /* 5,0,1 */
81#define cmRspInvalid 0 /* 0,0,0 */
82
83
84/*
85 * Firmware Request and Response Messages
86 */
87
88/* message types */
89#define ceReqTypePhy 1
90#define ceReqTypeLnk 2
91#define ceReqTypeCall 3
92#define ceReqTypeStat 1
93#define ceRspTypeErr 0
94#define ceRspTypePhy ceReqTypePhy
95#define ceRspTypeLnk ceReqTypeLnk
96#define ceRspTypeCall ceReqTypeCall
97#define ceRspTypeStat ceReqTypeStat
98
99/* message classes */
100#define ceReqClass0 0
101#define ceReqClass1 1
102#define ceReqClass2 2
103#define ceReqClass3 3
104#define ceRspClass0 ceReqClass0
105#define ceRspClass1 ceReqClass1
106#define ceRspClass2 ceReqClass2
107#define ceRspClass3 ceReqClass3
108
109/* message codes (B) = BRI only, (P) = PRI only, (V) = POTS only */
110#define ceReqPhyProcInfo 1 /* 1,0,1 */
111#define ceReqPhyConnect 1 /* 1,1,1 */
112#define ceReqPhyDisconnect 2 /* 1,1,2 */
113#define ceReqPhySetParams 3 /* 1,1,3 (P) */
114#define ceReqPhyGetParams 4 /* 1,1,4 (P) */
115#define ceReqPhyStatus 1 /* 1,2,1 */
116#define ceReqPhyAcfaStatus 2 /* 1,2,2 (P) */
117#define ceReqPhyChCallState 3 /* 1,2,3 (P) */
118#define ceReqPhyChServState 4 /* 1,2,4 (P) */
119#define ceReqPhyRLoopBack 1 /* 1,3,1 */
120#define ceRspPhyProcInfo ceReqPhyProcInfo
121#define ceRspPhyConnect ceReqPhyConnect
122#define ceRspPhyDisconnect ceReqPhyDisconnect
123#define ceRspPhySetParams ceReqPhySetParams
124#define ceRspPhyGetParams ceReqPhyGetParams
125#define ceRspPhyStatus ceReqPhyStatus
126#define ceRspPhyAcfaStatus ceReqPhyAcfaStatus
127#define ceRspPhyChCallState ceReqPhyChCallState
128#define ceRspPhyChServState ceReqPhyChServState
129#define ceRspPhyRLoopBack ceReqphyRLoopBack
130#define ceReqLnkSetParam 1 /* 2,0,1 */
131#define ceReqLnkGetParam 2 /* 2,0,2 */
132#define ceReqLnkGetStats 3 /* 2,0,3 */
133#define ceReqLnkWrite 1 /* 2,1,1 */
134#define ceReqLnkRead 2 /* 2,1,2 */
135#define ceReqLnkFlush 3 /* 2,1,3 */
136#define ceReqLnkWrBufTrc 4 /* 2,1,4 */
137#define ceReqLnkRdBufTrc 5 /* 2,1,5 */
138#define ceRspLnkSetParam ceReqLnkSetParam
139#define ceRspLnkGetParam ceReqLnkGetParam
140#define ceRspLnkGetStats ceReqLnkGetStats
141#define ceRspLnkWrite ceReqLnkWrite
142#define ceRspLnkRead ceReqLnkRead
143#define ceRspLnkFlush ceReqLnkFlush
144#define ceRspLnkWrBufTrc ceReqLnkWrBufTrc
145#define ceRspLnkRdBufTrc ceReqLnkRdBufTrc
146#define ceReqCallSetSwitchType 1 /* 3,0,1 */
147#define ceReqCallGetSwitchType 2 /* 3,0,2 */
148#define ceReqCallSetFrameFormat 3 /* 3,0,3 */
149#define ceReqCallGetFrameFormat 4 /* 3,0,4 */
150#define ceReqCallSetCallType 5 /* 3,0,5 */
151#define ceReqCallGetCallType 6 /* 3,0,6 */
152#define ceReqCallSetSPID 7 /* 3,0,7 (!P) */
153#define ceReqCallGetSPID 8 /* 3,0,8 (!P) */
154#define ceReqCallSetMyNumber 9 /* 3,0,9 (!P) */
155#define ceReqCallGetMyNumber 10 /* 3,0,10 (!P) */
156#define ceRspCallSetSwitchType ceReqCallSetSwitchType
157#define ceRspCallGetSwitchType ceReqCallSetSwitchType
158#define ceRspCallSetFrameFormat ceReqCallSetFrameFormat
159#define ceRspCallGetFrameFormat ceReqCallGetFrameFormat
160#define ceRspCallSetCallType ceReqCallSetCallType
161#define ceRspCallGetCallType ceReqCallGetCallType
162#define ceRspCallSetSPID ceReqCallSetSPID
163#define ceRspCallGetSPID ceReqCallGetSPID
164#define ceRspCallSetMyNumber ceReqCallSetMyNumber
165#define ceRspCallGetMyNumber ceReqCallGetMyNumber
166#define ceRspStatAcfaStatus 2
167#define ceRspStat
168#define ceRspErrError 0 /* 0,0,0 */
169
170/*
171 * Call Types
172 */
173#define CALLTYPE_64K 0
174#define CALLTYPE_56K 1
175#define CALLTYPE_SPEECH 2
176#define CALLTYPE_31KHZ 3
177
178/*
179 * Link Level data contains a pointer to and the length of
180 * a buffer in shared RAM. Used by LnkRead and LnkWrite message
181 * types. Part of RspMsgStruct and ReqMsgStruct.
182 */
183typedef struct {
184 unsigned long buff_offset;
185 unsigned short msg_len;
186} LLData;
187
188
189/*
190 * Message payload template for an HWConfig message
191 */
192typedef struct {
193 char st_u_sense;
194 char powr_sense;
195 char sply_sense;
196 unsigned char asic_id;
197 long ram_size;
198 char serial_no[13];
199 char part_no[13];
200 char rev_no[2];
201} HWConfig_pl;
202
203/*
204 * A Message
205 */
206struct message {
207 unsigned char sequence_no;
208 unsigned char process_id;
209 unsigned char time_stamp;
210 unsigned char cmd_sequence_no; /* Rsp messages only */
211 unsigned char reserved1[3];
212 unsigned char msg_byte_cnt;
213 unsigned char type;
214 unsigned char class;
215 unsigned char code;
216 unsigned char phy_link_no;
217 unsigned char rsp_status; /* Rsp messages only */
218 unsigned char reseved2[3];
219 union {
220 unsigned char byte_array[MSG_DATA_LEN];
221 LLData response;
222 HWConfig_pl HWCresponse;
223 } msg_data;
224};
225
226typedef struct message ReqMessage; /* Request message */
227typedef struct message RspMessage; /* Response message */
228
229/*
230 * The first 5010 bytes of shared memory contain the message queues,
231 * indexes and other data. This structure is its template
232 */
233typedef struct {
234 volatile ReqMessage req_queue[MAX_MESSAGES];
235 volatile RspMessage rsp_queue[MAX_MESSAGES];
236 volatile unsigned char req_head;
237 volatile unsigned char req_tail;
238 volatile unsigned char rsp_head;
239 volatile unsigned char rsp_tail;
240 volatile unsigned long signature;
241 volatile unsigned long trace_enable;
242 volatile unsigned char reserved[4];
243} DualPortMemory;
244
245#endif
diff --git a/drivers/isdn/sc/packet.c b/drivers/isdn/sc/packet.c
new file mode 100644
index 000000000000..8e3fac3ba1a1
--- /dev/null
+++ b/drivers/isdn/sc/packet.c
@@ -0,0 +1,231 @@
1/* $Id: packet.c,v 1.5.8.1 2001/09/23 22:24:59 kai Exp $
2 *
3 * Copyright (C) 1996 SpellCaster Telecommunications Inc.
4 *
5 * This software may be used and distributed according to the terms
6 * of the GNU General Public License, incorporated herein by reference.
7 *
8 * For more information, please contact gpl-info@spellcast.com or write:
9 *
10 * SpellCaster Telecommunications Inc.
11 * 5621 Finch Avenue East, Unit #3
12 * Scarborough, Ontario Canada
13 * M1B 2T9
14 * +1 (416) 297-8565
15 * +1 (416) 297-6433 Facsimile
16 */
17
18#include "includes.h"
19#include "hardware.h"
20#include "message.h"
21#include "card.h"
22
23extern board *sc_adapter[];
24extern unsigned int cinst;
25
26extern int get_card_from_id(int);
27extern int indicate_status(int, int,ulong, char*);
28extern void memcpy_toshmem(int, void *, const void *, size_t);
29extern void memcpy_fromshmem(int, void *, const void *, size_t);
30extern int sendmessage(int, unsigned int, unsigned int, unsigned int,
31 unsigned int, unsigned int, unsigned int, unsigned int *);
32
33int sndpkt(int devId, int channel, struct sk_buff *data)
34{
35 LLData ReqLnkWrite;
36 int status;
37 int card;
38 unsigned long len;
39
40 card = get_card_from_id(devId);
41
42 if(!IS_VALID_CARD(card)) {
43 pr_debug("invalid param: %d is not a valid card id\n", card);
44 return -ENODEV;
45 }
46
47 pr_debug("%s: sndpkt: frst = 0x%x nxt = %d f = %d n = %d\n",
48 sc_adapter[card]->devicename,
49 sc_adapter[card]->channel[channel].first_sendbuf,
50 sc_adapter[card]->channel[channel].next_sendbuf,
51 sc_adapter[card]->channel[channel].free_sendbufs,
52 sc_adapter[card]->channel[channel].num_sendbufs);
53
54 if(!sc_adapter[card]->channel[channel].free_sendbufs) {
55 pr_debug("%s: out of TX buffers\n",
56 sc_adapter[card]->devicename);
57 return -EINVAL;
58 }
59
60 if(data->len > BUFFER_SIZE) {
61 pr_debug("%s: data overflows buffer size (data > buffer)\n",
62 sc_adapter[card]->devicename);
63 return -EINVAL;
64 }
65
66 ReqLnkWrite.buff_offset = sc_adapter[card]->channel[channel].next_sendbuf *
67 BUFFER_SIZE + sc_adapter[card]->channel[channel].first_sendbuf;
68 ReqLnkWrite.msg_len = data->len; /* sk_buff size */
69 pr_debug("%s: writing %d bytes to buffer offset 0x%x\n",
70 sc_adapter[card]->devicename,
71 ReqLnkWrite.msg_len, ReqLnkWrite.buff_offset);
72 memcpy_toshmem(card, (char *)ReqLnkWrite.buff_offset, data->data, ReqLnkWrite.msg_len);
73
74 /*
75 * sendmessage
76 */
77 pr_debug("%s: sndpkt size=%d, buf_offset=0x%x buf_indx=%d\n",
78 sc_adapter[card]->devicename,
79 ReqLnkWrite.msg_len, ReqLnkWrite.buff_offset,
80 sc_adapter[card]->channel[channel].next_sendbuf);
81
82 status = sendmessage(card, CEPID, ceReqTypeLnk, ceReqClass1, ceReqLnkWrite,
83 channel+1, sizeof(LLData), (unsigned int*)&ReqLnkWrite);
84 len = data->len;
85 if(status) {
86 pr_debug("%s: failed to send packet, status = %d\n",
87 sc_adapter[card]->devicename, status);
88 return -1;
89 }
90 else {
91 sc_adapter[card]->channel[channel].free_sendbufs--;
92 sc_adapter[card]->channel[channel].next_sendbuf =
93 ++sc_adapter[card]->channel[channel].next_sendbuf ==
94 sc_adapter[card]->channel[channel].num_sendbufs ? 0 :
95 sc_adapter[card]->channel[channel].next_sendbuf;
96 pr_debug("%s: packet sent successfully\n", sc_adapter[card]->devicename);
97 dev_kfree_skb(data);
98 indicate_status(card,ISDN_STAT_BSENT,channel, (char *)&len);
99 }
100 return len;
101}
102
103void rcvpkt(int card, RspMessage *rcvmsg)
104{
105 LLData newll;
106 struct sk_buff *skb;
107
108 if(!IS_VALID_CARD(card)) {
109 pr_debug("invalid param: %d is not a valid card id\n", card);
110 return;
111 }
112
113 switch(rcvmsg->rsp_status){
114 case 0x01:
115 case 0x02:
116 case 0x70:
117 pr_debug("%s: error status code: 0x%x\n",
118 sc_adapter[card]->devicename, rcvmsg->rsp_status);
119 return;
120 case 0x00:
121 if (!(skb = dev_alloc_skb(rcvmsg->msg_data.response.msg_len))) {
122 printk(KERN_WARNING "%s: rcvpkt out of memory, dropping packet\n",
123 sc_adapter[card]->devicename);
124 return;
125 }
126 skb_put(skb, rcvmsg->msg_data.response.msg_len);
127 pr_debug("%s: getting data from offset: 0x%x\n",
128 sc_adapter[card]->devicename,
129 rcvmsg->msg_data.response.buff_offset);
130 memcpy_fromshmem(card,
131 skb_put(skb, rcvmsg->msg_data.response.msg_len),
132 (char *)rcvmsg->msg_data.response.buff_offset,
133 rcvmsg->msg_data.response.msg_len);
134 sc_adapter[card]->card->rcvcallb_skb(sc_adapter[card]->driverId,
135 rcvmsg->phy_link_no-1, skb);
136
137 case 0x03:
138 /*
139 * Recycle the buffer
140 */
141 pr_debug("%s: buffer size : %d\n",
142 sc_adapter[card]->devicename, BUFFER_SIZE);
143/* memset_shmem(card, rcvmsg->msg_data.response.buff_offset, 0, BUFFER_SIZE); */
144 newll.buff_offset = rcvmsg->msg_data.response.buff_offset;
145 newll.msg_len = BUFFER_SIZE;
146 pr_debug("%s: recycled buffer at offset 0x%x size %d\n",
147 sc_adapter[card]->devicename,
148 newll.buff_offset, newll.msg_len);
149 sendmessage(card, CEPID, ceReqTypeLnk, ceReqClass1, ceReqLnkRead,
150 rcvmsg->phy_link_no, sizeof(LLData), (unsigned int *)&newll);
151 }
152
153}
154
155int setup_buffers(int card, int c)
156{
157 unsigned int nBuffers, i, cBase;
158 unsigned int buffer_size;
159 LLData RcvBuffOffset;
160
161 if(!IS_VALID_CARD(card)) {
162 pr_debug("invalid param: %d is not a valid card id\n", card);
163 return -ENODEV;
164 }
165
166 /*
167 * Calculate the buffer offsets (send/recv/send/recv)
168 */
169 pr_debug("%s: setting up channel buffer space in shared RAM\n",
170 sc_adapter[card]->devicename);
171 buffer_size = BUFFER_SIZE;
172 nBuffers = ((sc_adapter[card]->ramsize - BUFFER_BASE) / buffer_size) / 2;
173 nBuffers = nBuffers > BUFFERS_MAX ? BUFFERS_MAX : nBuffers;
174 pr_debug("%s: calculating buffer space: %d buffers, %d big\n",
175 sc_adapter[card]->devicename,
176 nBuffers, buffer_size);
177 if(nBuffers < 2) {
178 pr_debug("%s: not enough buffer space\n",
179 sc_adapter[card]->devicename);
180 return -1;
181 }
182 cBase = (nBuffers * buffer_size) * (c - 1);
183 pr_debug("%s: channel buffer offset from shared RAM: 0x%x\n",
184 sc_adapter[card]->devicename, cBase);
185 sc_adapter[card]->channel[c-1].first_sendbuf = BUFFER_BASE + cBase;
186 sc_adapter[card]->channel[c-1].num_sendbufs = nBuffers / 2;
187 sc_adapter[card]->channel[c-1].free_sendbufs = nBuffers / 2;
188 sc_adapter[card]->channel[c-1].next_sendbuf = 0;
189 pr_debug("%s: send buffer setup complete: first=0x%x n=%d f=%d, nxt=%d\n",
190 sc_adapter[card]->devicename,
191 sc_adapter[card]->channel[c-1].first_sendbuf,
192 sc_adapter[card]->channel[c-1].num_sendbufs,
193 sc_adapter[card]->channel[c-1].free_sendbufs,
194 sc_adapter[card]->channel[c-1].next_sendbuf);
195
196 /*
197 * Prep the receive buffers
198 */
199 pr_debug("%s: adding %d RecvBuffers:\n",
200 sc_adapter[card]->devicename, nBuffers /2);
201 for (i = 0 ; i < nBuffers / 2; i++) {
202 RcvBuffOffset.buff_offset =
203 ((sc_adapter[card]->channel[c-1].first_sendbuf +
204 (nBuffers / 2) * buffer_size) + (buffer_size * i));
205 RcvBuffOffset.msg_len = buffer_size;
206 pr_debug("%s: adding RcvBuffer #%d offset=0x%x sz=%d bufsz:%d\n",
207 sc_adapter[card]->devicename,
208 i + 1, RcvBuffOffset.buff_offset,
209 RcvBuffOffset.msg_len,buffer_size);
210 sendmessage(card, CEPID, ceReqTypeLnk, ceReqClass1, ceReqLnkRead,
211 c, sizeof(LLData), (unsigned int *)&RcvBuffOffset);
212 }
213 return 0;
214}
215
216int print_skb(int card,char *skb_p, int len){
217 int i,data;
218 pr_debug("%s: data at 0x%x len: 0x%x\n", sc_adapter[card]->devicename,
219 skb_p,len);
220 for(i=1;i<=len;i++,skb_p++){
221 data = (int) (0xff & (*skb_p));
222 pr_debug("%s: data = 0x%x", sc_adapter[card]->devicename,data);
223 if(!(i%4))
224 pr_debug(" ");
225 if(!(i%32))
226 pr_debug("\n");
227 }
228 pr_debug("\n");
229 return 0;
230}
231
diff --git a/drivers/isdn/sc/scioc.h b/drivers/isdn/sc/scioc.h
new file mode 100644
index 000000000000..d08e650c7b6a
--- /dev/null
+++ b/drivers/isdn/sc/scioc.h
@@ -0,0 +1,105 @@
1/*
2 * This software may be used and distributed according to the terms
3 * of the GNU General Public License, incorporated herein by reference.
4 */
5
6/*
7 * IOCTL Command Codes
8 */
9#define SCIOCLOAD 0x01 /* Load a firmware record */
10#define SCIOCRESET 0x02 /* Perform hard reset */
11#define SCIOCDEBUG 0x03 /* Set debug level */
12#define SCIOCREV 0x04 /* Get driver revision(s) */
13#define SCIOCSTART 0x05 /* Start the firmware */
14#define SCIOCGETSWITCH 0x06 /* Get switch type */
15#define SCIOCSETSWITCH 0x07 /* Set switch type */
16#define SCIOCGETSPID 0x08 /* Get channel SPID */
17#define SCIOCSETSPID 0x09 /* Set channel SPID */
18#define SCIOCGETDN 0x0A /* Get channel DN */
19#define SCIOCSETDN 0x0B /* Set channel DN */
20#define SCIOCTRACE 0x0C /* Toggle trace mode */
21#define SCIOCSTAT 0x0D /* Get line status */
22#define SCIOCGETSPEED 0x0E /* Set channel speed */
23#define SCIOCSETSPEED 0x0F /* Set channel speed */
24#define SCIOCLOOPTST 0x10 /* Perform loopback test */
25
26typedef struct {
27 int device;
28 int channel;
29 unsigned long command;
30 void __user *dataptr;
31} scs_ioctl;
32
33/* Size of strings */
34#define SCIOC_SPIDSIZE 49
35#define SCIOC_DNSIZE SCIOC_SPIDSIZE
36#define SCIOC_REVSIZE SCIOC_SPIDSIZE
37#define SCIOC_SRECSIZE 49
38
39typedef struct {
40 unsigned long tx_good;
41 unsigned long tx_bad;
42 unsigned long rx_good;
43 unsigned long rx_bad;
44} ChLinkStats;
45
46typedef struct {
47 char spid[49];
48 char dn[49];
49 char call_type;
50 char phy_stat;
51 ChLinkStats link_stats;
52} BRIStat;
53
54typedef BRIStat POTStat;
55
56typedef struct {
57 char call_type;
58 char call_state;
59 char serv_state;
60 char phy_stat;
61 ChLinkStats link_stats;
62} PRIStat;
63
64typedef char PRIInfo;
65typedef char BRIInfo;
66typedef char POTInfo;
67
68
69typedef struct {
70 char acfa_nos;
71 char acfa_ais;
72 char acfa_los;
73 char acfa_rra;
74 char acfa_slpp;
75 char acfa_slpn;
76 char acfa_fsrf;
77} ACFAStat;
78
79typedef struct {
80 unsigned char modelid;
81 char serial_no[13];
82 char part_no[13];
83 char load_ver[11];
84 char proc_ver[11];
85 int iobase;
86 long rambase;
87 char irq;
88 long ramsize;
89 char interface;
90 char switch_type;
91 char l1_status;
92 char l2_status;
93 ChLinkStats dch_stats;
94 ACFAStat AcfaStats;
95 union {
96 PRIStat pristats[23];
97 BRIStat bristats[2];
98 POTStat potsstats[2];
99 } status;
100 union {
101 PRIInfo priinfo;
102 BRIInfo briinfo;
103 POTInfo potsinfo;
104 } info;
105} boardInfo;
diff --git a/drivers/isdn/sc/shmem.c b/drivers/isdn/sc/shmem.c
new file mode 100644
index 000000000000..7bc2dfad0775
--- /dev/null
+++ b/drivers/isdn/sc/shmem.c
@@ -0,0 +1,143 @@
1/* $Id: shmem.c,v 1.2.10.1 2001/09/23 22:24:59 kai Exp $
2 *
3 * Copyright (C) 1996 SpellCaster Telecommunications Inc.
4 *
5 * Card functions implementing ISDN4Linux functionality
6 *
7 * This software may be used and distributed according to the terms
8 * of the GNU General Public License, incorporated herein by reference.
9 *
10 * For more information, please contact gpl-info@spellcast.com or write:
11 *
12 * SpellCaster Telecommunications Inc.
13 * 5621 Finch Avenue East, Unit #3
14 * Scarborough, Ontario Canada
15 * M1B 2T9
16 * +1 (416) 297-8565
17 * +1 (416) 297-6433 Facsimile
18 */
19
20#include "includes.h" /* This must be first */
21#include "hardware.h"
22#include "card.h"
23
24/*
25 * Main adapter array
26 */
27extern board *sc_adapter[];
28extern int cinst;
29
30/*
31 *
32 */
33void memcpy_toshmem(int card, void *dest, const void *src, size_t n)
34{
35 unsigned long flags;
36 unsigned char ch;
37
38 if(!IS_VALID_CARD(card)) {
39 pr_debug("Invalid param: %d is not a valid card id\n", card);
40 return;
41 }
42
43 if(n > SRAM_PAGESIZE) {
44 return;
45 }
46
47 /*
48 * determine the page to load from the address
49 */
50 ch = (unsigned long) dest / SRAM_PAGESIZE;
51 pr_debug("%s: loaded page %d\n", sc_adapter[card]->devicename,ch);
52 /*
53 * Block interrupts and load the page
54 */
55 spin_lock_irqsave(&sc_adapter[card]->lock, flags);
56
57 outb(((sc_adapter[card]->shmem_magic + ch * SRAM_PAGESIZE) >> 14) | 0x80,
58 sc_adapter[card]->ioport[sc_adapter[card]->shmem_pgport]);
59 memcpy_toio(sc_adapter[card]->rambase +
60 ((unsigned long) dest % 0x4000), src, n);
61 spin_unlock_irqrestore(&sc_adapter[card]->lock, flags);
62 pr_debug("%s: set page to %#x\n",sc_adapter[card]->devicename,
63 ((sc_adapter[card]->shmem_magic + ch * SRAM_PAGESIZE)>>14)|0x80);
64 pr_debug("%s: copying %d bytes from %#x to %#x\n",
65 sc_adapter[card]->devicename, n,
66 (unsigned long) src,
67 sc_adapter[card]->rambase + ((unsigned long) dest %0x4000));
68}
69
70/*
71 * Reverse of above
72 */
73void memcpy_fromshmem(int card, void *dest, const void *src, size_t n)
74{
75 unsigned long flags;
76 unsigned char ch;
77
78 if(!IS_VALID_CARD(card)) {
79 pr_debug("Invalid param: %d is not a valid card id\n", card);
80 return;
81 }
82
83 if(n > SRAM_PAGESIZE) {
84 return;
85 }
86
87 /*
88 * determine the page to load from the address
89 */
90 ch = (unsigned long) src / SRAM_PAGESIZE;
91 pr_debug("%s: loaded page %d\n", sc_adapter[card]->devicename,ch);
92
93
94 /*
95 * Block interrupts and load the page
96 */
97 spin_lock_irqsave(&sc_adapter[card]->lock, flags);
98
99 outb(((sc_adapter[card]->shmem_magic + ch * SRAM_PAGESIZE) >> 14) | 0x80,
100 sc_adapter[card]->ioport[sc_adapter[card]->shmem_pgport]);
101 memcpy_fromio(dest,(void *)(sc_adapter[card]->rambase +
102 ((unsigned long) src % 0x4000)), n);
103 spin_unlock_irqrestore(&sc_adapter[card]->lock, flags);
104 pr_debug("%s: set page to %#x\n",sc_adapter[card]->devicename,
105 ((sc_adapter[card]->shmem_magic + ch * SRAM_PAGESIZE)>>14)|0x80);
106/* pr_debug("%s: copying %d bytes from %#x to %#x\n",
107 sc_adapter[card]->devicename, n,
108 sc_adapter[card]->rambase + ((unsigned long) src %0x4000), (unsigned long) dest); */
109}
110
111void memset_shmem(int card, void *dest, int c, size_t n)
112{
113 unsigned long flags;
114 unsigned char ch;
115
116 if(!IS_VALID_CARD(card)) {
117 pr_debug("Invalid param: %d is not a valid card id\n", card);
118 return;
119 }
120
121 if(n > SRAM_PAGESIZE) {
122 return;
123 }
124
125 /*
126 * determine the page to load from the address
127 */
128 ch = (unsigned long) dest / SRAM_PAGESIZE;
129 pr_debug("%s: loaded page %d\n",sc_adapter[card]->devicename,ch);
130
131 /*
132 * Block interrupts and load the page
133 */
134 spin_lock_irqsave(&sc_adapter[card]->lock, flags);
135
136 outb(((sc_adapter[card]->shmem_magic + ch * SRAM_PAGESIZE) >> 14) | 0x80,
137 sc_adapter[card]->ioport[sc_adapter[card]->shmem_pgport]);
138 memset_io(sc_adapter[card]->rambase +
139 ((unsigned long) dest % 0x4000), c, n);
140 pr_debug("%s: set page to %#x\n",sc_adapter[card]->devicename,
141 ((sc_adapter[card]->shmem_magic + ch * SRAM_PAGESIZE)>>14)|0x80);
142 spin_unlock_irqrestore(&sc_adapter[card]->lock, flags);
143}
diff --git a/drivers/isdn/sc/timer.c b/drivers/isdn/sc/timer.c
new file mode 100644
index 000000000000..710d0f47ca35
--- /dev/null
+++ b/drivers/isdn/sc/timer.c
@@ -0,0 +1,147 @@
1/* $Id: timer.c,v 1.3.6.1 2001/09/23 22:24:59 kai Exp $
2 *
3 * Copyright (C) 1996 SpellCaster Telecommunications Inc.
4 *
5 * This software may be used and distributed according to the terms
6 * of the GNU General Public License, incorporated herein by reference.
7 *
8 * For more information, please contact gpl-info@spellcast.com or write:
9 *
10 * SpellCaster Telecommunications Inc.
11 * 5621 Finch Avenue East, Unit #3
12 * Scarborough, Ontario Canada
13 * M1B 2T9
14 * +1 (416) 297-8565
15 * +1 (416) 297-6433 Facsimile
16 */
17
18#include "includes.h"
19#include "hardware.h"
20#include "message.h"
21#include "card.h"
22
23extern board *sc_adapter[];
24
25extern void flushreadfifo(int);
26extern int startproc(int);
27extern int indicate_status(int, int, unsigned long, char *);
28extern int sendmessage(int, unsigned int, unsigned int, unsigned int,
29 unsigned int, unsigned int, unsigned int, unsigned int *);
30
31
32/*
33 * Write the proper values into the I/O ports following a reset
34 */
35void setup_ports(int card)
36{
37
38 outb((sc_adapter[card]->rambase >> 12), sc_adapter[card]->ioport[EXP_BASE]);
39
40 /* And the IRQ */
41 outb((sc_adapter[card]->interrupt | 0x80),
42 sc_adapter[card]->ioport[IRQ_SELECT]);
43}
44
45/*
46 * Timed function to check the status of a previous reset
47 * Must be very fast as this function runs in the context of
48 * an interrupt handler.
49 *
50 * Setup the ioports for the board that were cleared by the reset.
51 * Then, check to see if the signate has been set. Next, set the
52 * signature to a known value and issue a startproc if needed.
53 */
54void check_reset(unsigned long data)
55{
56 unsigned long flags;
57 unsigned long sig;
58 int card = (unsigned int) data;
59
60 pr_debug("%s: check_timer timer called\n",
61 sc_adapter[card]->devicename);
62
63 /* Setup the io ports */
64 setup_ports(card);
65
66 spin_lock_irqsave(&sc_adapter[card]->lock, flags);
67 outb(sc_adapter[card]->ioport[sc_adapter[card]->shmem_pgport],
68 (sc_adapter[card]->shmem_magic>>14) | 0x80);
69 sig = (unsigned long) *((unsigned long *)(sc_adapter[card]->rambase + SIG_OFFSET));
70
71 /* check the signature */
72 if(sig == SIGNATURE) {
73 flushreadfifo(card);
74 spin_unlock_irqrestore(&sc_adapter[card]->lock, flags);
75 /* See if we need to do a startproc */
76 if (sc_adapter[card]->StartOnReset)
77 startproc(card);
78 } else {
79 pr_debug("%s: No signature yet, waiting another %d jiffies.\n",
80 sc_adapter[card]->devicename, CHECKRESET_TIME);
81 mod_timer(&sc_adapter[card]->reset_timer, jiffies+CHECKRESET_TIME);
82 spin_unlock_irqrestore(&sc_adapter[card]->lock, flags);
83 }
84}
85
86/*
87 * Timed function to check the status of a previous reset
88 * Must be very fast as this function runs in the context of
89 * an interrupt handler.
90 *
91 * Send check sc_adapter->phystat to see if the channels are up
92 * If they are, tell ISDN4Linux that the board is up. If not,
93 * tell IADN4Linux that it is up. Always reset the timer to
94 * fire again (endless loop).
95 */
96void check_phystat(unsigned long data)
97{
98 unsigned long flags;
99 int card = (unsigned int) data;
100
101 pr_debug("%s: Checking status...\n", sc_adapter[card]->devicename);
102 /*
103 * check the results of the last PhyStat and change only if
104 * has changed drastically
105 */
106 if (sc_adapter[card]->nphystat && !sc_adapter[card]->phystat) { /* All is well */
107 pr_debug("PhyStat transition to RUN\n");
108 pr_info("%s: Switch contacted, transmitter enabled\n",
109 sc_adapter[card]->devicename);
110 indicate_status(card, ISDN_STAT_RUN, 0, NULL);
111 }
112 else if (!sc_adapter[card]->nphystat && sc_adapter[card]->phystat) { /* All is not well */
113 pr_debug("PhyStat transition to STOP\n");
114 pr_info("%s: Switch connection lost, transmitter disabled\n",
115 sc_adapter[card]->devicename);
116
117 indicate_status(card, ISDN_STAT_STOP, 0, NULL);
118 }
119
120 sc_adapter[card]->phystat = sc_adapter[card]->nphystat;
121
122 /* Reinitialize the timer */
123 spin_lock_irqsave(&sc_adapter[card]->lock, flags);
124 mod_timer(&sc_adapter[card]->stat_timer, jiffies+CHECKSTAT_TIME);
125 spin_unlock_irqrestore(&sc_adapter[card]->lock, flags);
126
127 /* Send a new cePhyStatus message */
128 sendmessage(card, CEPID,ceReqTypePhy,ceReqClass2,
129 ceReqPhyStatus,0,0,NULL);
130}
131
132/*
133 * When in trace mode, this callback is used to swap the working shared
134 * RAM page to the trace page(s) and process all received messages. It
135 * must be called often enough to get all of the messages out of RAM before
136 * it loops around.
137 * Trace messages are \n terminated strings.
138 * We output the messages in 64 byte chunks through readstat. Each chunk
139 * is scanned for a \n followed by a time stamp. If the timerstamp is older
140 * than the current time, scanning stops and the page and offset are recorded
141 * as the starting point the next time the trace timer is called. The final
142 * step is to restore the working page and reset the timer.
143 */
144void trace_timer(unsigned long data)
145{
146 /* not implemented */
147}