Home Home > GIT Browse
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@penguin.transmeta.com>2002-03-06 18:31:24 -0800
committerLinus Torvalds <torvalds@penguin.transmeta.com>2002-03-06 18:31:24 -0800
commit796297ff60390d887667b959c3ad23ccd6017344 (patch)
treea87845deb764beddad296b3ef54be4ab2110af9f
parent58c1bd4cfd0f1d25e13043fb08841c0e848f381c (diff)
parent5b17799f9693ac1b8a12534c43672c7231ddaf77 (diff)
Merge http://gkernel.bkbits.net/net-drivers-2.5
into penguin.transmeta.com:/home/penguin/torvalds/repositories/kernel/linux
-rw-r--r--Documentation/networking/generic-hdlc.txt115
-rw-r--r--Documentation/sound/alsa/CMIPCI.txt228
-rw-r--r--Documentation/sound/alsa/SB-Live-mixer.txt356
-rw-r--r--Documentation/sound/alsa/seq_oss.html409
-rw-r--r--Documentation/sound/oss/AD1816 (renamed from Documentation/sound/AD1816)0
-rw-r--r--Documentation/sound/oss/ALS (renamed from Documentation/sound/ALS)0
-rw-r--r--Documentation/sound/oss/AWE32 (renamed from Documentation/sound/AWE32)0
-rw-r--r--Documentation/sound/oss/AudioExcelDSP16 (renamed from Documentation/sound/AudioExcelDSP16)0
-rw-r--r--Documentation/sound/oss/CMI8330 (renamed from Documentation/sound/CMI8330)0
-rw-r--r--Documentation/sound/oss/CMI8338 (renamed from Documentation/sound/CMI8338)0
-rw-r--r--Documentation/sound/oss/CS4232 (renamed from Documentation/sound/CS4232)0
-rw-r--r--Documentation/sound/oss/ChangeLog.awe (renamed from Documentation/sound/ChangeLog.awe)0
-rw-r--r--Documentation/sound/oss/ChangeLog.multisound (renamed from Documentation/sound/ChangeLog.multisound)0
-rw-r--r--Documentation/sound/oss/ESS (renamed from Documentation/sound/ESS)0
-rw-r--r--Documentation/sound/oss/ESS1868 (renamed from Documentation/sound/ESS1868)0
-rw-r--r--Documentation/sound/oss/INSTALL.awe (renamed from Documentation/sound/INSTALL.awe)0
-rw-r--r--Documentation/sound/oss/Introduction (renamed from Documentation/sound/Introduction)0
-rw-r--r--Documentation/sound/oss/MAD16 (renamed from Documentation/sound/MAD16)0
-rw-r--r--Documentation/sound/oss/Maestro (renamed from Documentation/sound/Maestro)0
-rw-r--r--Documentation/sound/oss/Maestro3 (renamed from Documentation/sound/Maestro3)0
-rw-r--r--Documentation/sound/oss/MultiSound (renamed from Documentation/sound/MultiSound)0
-rw-r--r--Documentation/sound/oss/NEWS (renamed from Documentation/sound/NEWS)0
-rw-r--r--Documentation/sound/oss/NM256 (renamed from Documentation/sound/NM256)0
-rw-r--r--Documentation/sound/oss/OPL3 (renamed from Documentation/sound/OPL3)0
-rw-r--r--Documentation/sound/oss/OPL3-SA (renamed from Documentation/sound/OPL3-SA)0
-rw-r--r--Documentation/sound/oss/OPL3-SA2 (renamed from Documentation/sound/OPL3-SA2)0
-rw-r--r--Documentation/sound/oss/Opti (renamed from Documentation/sound/Opti)0
-rw-r--r--Documentation/sound/oss/PAS16 (renamed from Documentation/sound/PAS16)0
-rw-r--r--Documentation/sound/oss/PSS (renamed from Documentation/sound/PSS)0
-rw-r--r--Documentation/sound/oss/PSS-updates (renamed from Documentation/sound/PSS-updates)0
-rw-r--r--Documentation/sound/oss/README.OSS (renamed from Documentation/sound/README.OSS)0
-rw-r--r--Documentation/sound/oss/README.awe (renamed from Documentation/sound/README.awe)0
-rw-r--r--Documentation/sound/oss/README.modules (renamed from Documentation/sound/README.modules)0
-rw-r--r--Documentation/sound/oss/README.ymfsb (renamed from Documentation/sound/README.ymfsb)0
-rw-r--r--Documentation/sound/oss/SoundPro (renamed from Documentation/sound/SoundPro)0
-rw-r--r--Documentation/sound/oss/Soundblaster (renamed from Documentation/sound/Soundblaster)0
-rw-r--r--Documentation/sound/oss/Tropez+ (renamed from Documentation/sound/Tropez+)0
-rw-r--r--Documentation/sound/oss/VIA-chipset (renamed from Documentation/sound/VIA-chipset)0
-rw-r--r--Documentation/sound/oss/VIBRA16 (renamed from Documentation/sound/VIBRA16)0
-rw-r--r--Documentation/sound/oss/WaveArtist (renamed from Documentation/sound/WaveArtist)0
-rw-r--r--Documentation/sound/oss/Wavefront (renamed from Documentation/sound/Wavefront)0
-rw-r--r--Documentation/sound/oss/btaudio (renamed from Documentation/sound/btaudio)0
-rw-r--r--Documentation/sound/oss/cs46xx (renamed from Documentation/sound/cs46xx)0
-rw-r--r--Documentation/sound/oss/es1370 (renamed from Documentation/sound/es1370)0
-rw-r--r--Documentation/sound/oss/es1371 (renamed from Documentation/sound/es1371)0
-rw-r--r--Documentation/sound/oss/mwave (renamed from Documentation/sound/mwave)0
-rw-r--r--Documentation/sound/oss/solo1 (renamed from Documentation/sound/solo1)0
-rw-r--r--Documentation/sound/oss/sonicvibes (renamed from Documentation/sound/sonicvibes)0
-rw-r--r--Documentation/sound/oss/ultrasound (renamed from Documentation/sound/ultrasound)0
-rw-r--r--Documentation/sound/oss/vwsnd (renamed from Documentation/sound/vwsnd)0
-rw-r--r--drivers/net/wan/Config.help5
-rw-r--r--drivers/net/wan/Config.in15
-rw-r--r--drivers/net/wan/Makefile14
-rw-r--r--drivers/net/wan/c101.c117
-rw-r--r--drivers/net/wan/dscc4.c127
-rw-r--r--drivers/net/wan/farsync.c548
-rw-r--r--drivers/net/wan/farsync.h5
-rw-r--r--drivers/net/wan/hd64570.h8
-rw-r--r--drivers/net/wan/hd6457x.c250
-rw-r--r--drivers/net/wan/hdlc.c1453
-rw-r--r--drivers/net/wan/hdlc_cisco.c293
-rw-r--r--drivers/net/wan/hdlc_fr.c842
-rw-r--r--drivers/net/wan/hdlc_generic.c188
-rw-r--r--drivers/net/wan/hdlc_ppp.c119
-rw-r--r--drivers/net/wan/hdlc_raw.c84
-rw-r--r--drivers/net/wan/hdlc_x25.c219
-rw-r--r--drivers/net/wan/n2.c118
-rw-r--r--drivers/pci/pci.c2
-rw-r--r--include/linux/hdlc.h299
-rw-r--r--include/linux/hdlc/ioctl.h55
-rw-r--r--include/linux/if.h39
-rw-r--r--include/linux/if_ether.h1
-rw-r--r--include/linux/sockios.h2
-rw-r--r--include/sound/core.h4
-rw-r--r--include/sound/driver.h8
-rw-r--r--include/sound/info.h6
-rw-r--r--include/sound/pcm.h1
-rw-r--r--include/sound/pcm_params.h2
-rw-r--r--include/sound/version.h2
-rw-r--r--kernel/sched.c4
-rw-r--r--net/core/dev.c8
-rw-r--r--sound/Config.help7
-rw-r--r--sound/core/Config.help40
-rw-r--r--sound/core/Config.in9
-rw-r--r--sound/core/Makefile15
-rw-r--r--sound/core/info.c31
-rw-r--r--sound/core/info_oss.c2
-rw-r--r--sound/core/ioctl32/Makefile17
-rw-r--r--sound/core/ioctl32/hwdep32.c37
-rw-r--r--sound/core/ioctl32/ioctl32.c357
-rw-r--r--sound/core/ioctl32/ioctl32.h79
-rw-r--r--sound/core/ioctl32/pcm32.c296
-rw-r--r--sound/core/ioctl32/rawmidi32.c86
-rw-r--r--sound/core/ioctl32/timer32.c93
-rw-r--r--sound/core/oss/pcm_oss.c42
-rw-r--r--sound/core/rtctimer.c60
-rw-r--r--sound/core/seq/Makefile1
-rw-r--r--sound/core/seq/seq_midi_event.c13
-rw-r--r--sound/core/seq/seq_virmidi.c3
-rw-r--r--sound/core/sound_oss.c2
-rw-r--r--sound/drivers/Config.help18
-rw-r--r--sound/drivers/mpu401/Makefile1
-rw-r--r--sound/drivers/mpu401/mpu401_uart.c1
-rw-r--r--sound/drivers/mtpav.c1
-rw-r--r--sound/drivers/opl3/Makefile4
-rw-r--r--sound/drivers/opl3/opl3_lib.c1
-rw-r--r--sound/drivers/serial-u16550.c7
-rw-r--r--sound/i2c/Makefile2
-rw-r--r--sound/isa/Config.help99
-rw-r--r--sound/isa/ad1816a/ad1816a_lib.c1
-rw-r--r--sound/isa/ad1848/ad1848_lib.c1
-rw-r--r--sound/isa/azt2320.c2
-rw-r--r--sound/isa/cs423x/cs4231_lib.c1
-rw-r--r--sound/isa/es1688/es1688_lib.c1
-rw-r--r--sound/isa/gus/gus_main.c1
-rw-r--r--sound/isa/opl3sa2.c2
-rw-r--r--sound/isa/sb/Makefile4
-rw-r--r--sound/isa/sb/emu8000.c1
-rw-r--r--sound/isa/sb/sb16_main.c6
-rw-r--r--sound/isa/sb/sb8.c1
-rw-r--r--sound/isa/sb/sb_common.c1
-rw-r--r--sound/isa/sgalaxy.c2
-rw-r--r--sound/isa/wavefront/wavefront_synth.c45
-rw-r--r--sound/oss/via82cxxx_audio.c2
-rw-r--r--sound/pci/Config.help75
-rw-r--r--sound/pci/ymfpci/ymfpci.c2
-rw-r--r--sound/synth/Makefile2
127 files changed, 5039 insertions, 2381 deletions
diff --git a/Documentation/networking/generic-hdlc.txt b/Documentation/networking/generic-hdlc.txt
new file mode 100644
index 000000000000..37631c95b90a
--- /dev/null
+++ b/Documentation/networking/generic-hdlc.txt
@@ -0,0 +1,115 @@
+Generic HDLC layer for Linux kernel 2.4/2.5
+Krzysztof Halasa <khc@pm.waw.pl>
+May, 2001
+
+
+Generic HDLC layer currently supports:
+- Frame Relay (ANSI, CCITT and no LMI), with ARP support (no InARP),
+- raw HDLC (IPv4 only),
+- Cisco HDLC,
+- PPP (uses syncppp.c),
+- X.25 (uses X.25 routines).
+
+There are hardware drivers for the following cards:
+- C101 by Moxa Technologies Co., Ltd.
+- RISCom/N2 by SDL Communications Inc.
+- and others, some not in the official kernel.
+
+Make sure the hdlc.o and the hardware driver are loaded. It should
+create a number of "hdlc" (hdlc0 etc) network devices, one for each
+WAN port. You'll need the "sethdlc" utility, get it from:
+ http://hq.pm.waw.pl/hdlc/
+
+Compile sethdlc.c utility:
+ gcc -O2 -Wall -o sethdlc sethdlc.c
+Make sure you're using a correct version of sethdlc for your kernel.
+
+Use sethdlc to set physical interface, clock rate, HDLC mode used,
+and add any required PVCs if using Frame Relay.
+Usually you want something like:
+
+ sethdlc hdlc0 clock int rate 128000
+ sethdlc hdlc0 cisco interval 10 timeout 25
+or
+ sethdlc hdlc0 rs232 clock ext
+ sethdlc fr lmi ansi
+ sethdlc create 99
+
+In Frame Relay mode, ifconfig master hdlc device up (without assigning
+any IP address to it) before using pvc devices.
+
+
+Setting interface:
+
+* v35 | rs232 | x21 | t1 | e1 - sets physical interface for a given port
+ if the card has software-selectable interfaces
+ loopback - activate hardware loopback (for testing only)
+* clock ext - external clock (uses DTE RX and TX clock)
+* clock int - internal clock (provides clock signal on DCE clock output)
+* clock txint - TX internal, RX external (provides TX clock on DCE output)
+* clock txfromrx - TX clock derived from RX clock (TX clock on DCE output)
+* rate - sets clock rate in bps (not required for external clock or
+ for txfromrx)
+
+Setting protocol:
+
+* hdlc - sets raw HDLC (IP-only) mode
+ nrz / nrzi / fm-mark / fm-space / manchester - sets transmission code
+ no-parity / crc16 / crc16-pr0 (CRC16 with preset zeros) / crc32-itu
+ crc16-itu (CRC16 with ITU-T polynomial) / crc16-itu-pr0 - sets parity
+
+* cisco - sets Cisco HDLC mode (IP, IPv6 and IPX supported)
+ interval - time in seconds between keepalive packets
+ timeout - time in seconds after last received keepalive packet before
+ we assume the link is down
+
+* ppp - sets synchronous PPP mode
+
+* x25 - sets X.25 mode
+
+* fr - Frame Relay mode
+ lmi ansi / ccitt / none - LMI (link management) type
+ dce - Frame Relay DCE (network) side LMI instead of default DTE (user).
+ It has nothing to do with clocks!
+ t391 - link integrity verification polling timer (in seconds) - user
+ t392 - polling verification timer (in seconds) - network
+ n391 - full status polling counter - user
+ n392 - error threshold - both user and network
+ n393 - monitored events count - both user and network
+
+* create | delete n - FR only - adds / deletes PVC interface with DLCI #n.
+
+
+
+
+Board-specific issues
+---------------------
+
+n2.o and c101.o need parameters to work (note double quotes):
+
+ insmod n2 hw='"io,irq,ram,ports[:io,irq,...]"'
+example:
+ insmod n2 hw='"0x300,10,0xD0000,01"'
+
+or
+ insmod c101 hw='"irq,ram[:irq,...]"
+example:
+ insmod c101 hw='"9,0xdc000"'
+
+If built into the kernel, these drivers need kernel (command line) parameters:
+ n2=io,irq,ram,ports:...
+or
+ c101=irq,ram:...
+
+
+
+If you have a problem with N2 or C101 card, you can issue the "private"
+command to see port's packet descriptor rings:
+
+ sethdlc hdlc0 private
+
+The hardware driver have to be build with CONFIG_HDLC_DEBUG_RINGS.
+Attaching this info to bug reports would be helpful. Anyway, let me know
+if you have problems using this.
+
+For patches and other info look at http://hq.pm.waw.pl/hdlc/
diff --git a/Documentation/sound/alsa/CMIPCI.txt b/Documentation/sound/alsa/CMIPCI.txt
new file mode 100644
index 000000000000..582781b64b13
--- /dev/null
+++ b/Documentation/sound/alsa/CMIPCI.txt
@@ -0,0 +1,228 @@
+ Brief Notes on C-Media 8738/8338 Driver
+ =======================================
+
+ Takashi Iwai <tiwai@suse.de>
+
+
+Front/Rear Multi-channel Playback
+---------------------------------
+
+CM8x38 chip can use ADC as the second DAC so that two different stereo
+channels can be used for front/rear playbacks. Since there are two
+DACs, both streams are handled independently unlike the 4/6ch multi-
+channel playbacks in the section below.
+
+As default, ALSA driver assigns the first PCM device (i.e. hw:0,0 for
+card#0) for front and 4/6ch playbacks, while the second PCM device
+(hw:0,1) is assigned to the second DAC for rear playback.
+
+There are slight difference between two DACs.
+
+- The first DAC supports U8 and S16LE formats, while the second DAC
+ supports only S16LE.
+- The second DAC supports only two channel stereo.
+
+Please note that the CM8x38 DAC doesn't support continuous playback
+rate but only fixed rates: 5512, 8000, 11025, 16000, 22050, 32000,
+44100 and 48000 Hz.
+
+The rear output can be heard only when "Four Channel Mode" switch is
+disabled. Otherwise no signal will be routed to the rear speakers.
+As default it's turned on.
+
+*** WARNING ***
+When "Four Channel Mode" switch is off, the output from rear speakers
+will be FULL VOLUME regardless of Master and PCM volumes.
+This might damage your audio equipment. Please disconnect speakers
+before your turn off this switch.
+*** WARNING ***
+
+[ Well.. I once got the output with correct volume (i.e. same with the
+ front one) and was so excited. It was even with "Four Channel" bit
+ on and "double DAC" mode. Actually I could hear separate 4 channels
+ from front and rear speakers! But.. after reboot, all was gone.
+ It's a very pity that I didn't save the register dump at that
+ time.. Maybe there is an unknown register to achieve this... ]
+
+If your card has an extra output jack for the rear output, the rear
+playback should be routed there as default. If not, there is a
+control switch in the driver "Line-In As Rear", which you can change
+via alsamixer or somewhat else. When this switch is on, line-in jack
+is used as rear output.
+
+There are two more controls regarding to the rear output.
+The "Exchange DAC" switch is used to exchange front and rear playback
+routes, i.e. the 2nd DAC is output from front output.
+
+
+4/6 Multi-Channel Playback
+--------------------------
+
+The recent CM8738 chips support for the 4/6 multi-channel playback
+function. This is useful especially for AC3 decoding.
+
+When the multi-channel is supported, the driver name has a suffix
+"-MC" such like "CMI8738-MC6". You can check this name from
+/proc/asound/cards.
+
+When the 4/6-ch output is enabled, the front DAC accepts up to 6 (or
+4) channels. This is different from the dual DACs described in the
+previous section. While the dual DAC supports two different rates or
+formats, the 4/6-ch playback supports only the same condition for all
+channels.
+
+For using 4/6 channel playback, you need to specify the PCM channels
+as you like and set the format S16LE. For example, for playback with
+4 channels,
+
+ snd_pcm_hw_params_set_access(pcm, hw, SND_PCM_ACCESS_RW_INTERLEAVED);
+ // or mmap if you like
+ snd_pcm_hw_params_set_format(pcm, hw, SND_PCM_FORMAT_S16_LE);
+ snd_pcm_hw_params_set_channels(pcm, hw, 4);
+
+and use the interleaved 4 channel data.
+
+There is a control switch, "Line-In As Bass". As you can imagine from
+its name, the line-in jack is used for the bass (5th and 6th channels)
+output.
+
+
+Digital I/O
+-----------
+
+The CM8x38 provides the excellent SPDIF capability with very chip
+price (yes, that's the reason I bought the card :)
+
+The SPDIF playback and capture are done via the third PCM device
+(hw:0,2). Usually this is assigned to the PCM device "spdif".
+The available rates are 44100 and 48000 Hz.
+For playback with aplay, you can run like below:
+
+ % aplay -Dhw:0,2 foo.wav
+
+or
+
+ % aplay -Dspdif foo.wav
+
+So far, only S16LE format is supported. Still no 24bit. Sorry, not
+enough info for this.
+
+The playback and capture over SPDIF use normal DAC and ADC,
+respectively, so you cannot playback both analog and digital streams
+simultaneously.
+
+To enable SPDIF output, you need to turn on "IEC958 Output Switch"
+control via mixer or alsactl. Then you'll see the red light on from
+the card so you know that's working obviously :)
+The SPDIF input is always enabled, so you can hear SPDIF input data
+from line-out with "IEC958 In Monitor" switch at any time (see
+below).
+
+You can play via SPDIF even with the first device (hw:0,0),
+but SPDIF is enabled only when the proper format (S16LE), sample rate
+(441100 or 48000) and channels (2) are used. Otherwise it's turned
+off. (Also don't forget to turn on "IEC958 Output Switch", too.)
+
+
+Additionally there are relevant control switches:
+
+"IEC958 Mix Analog" - Mix analog PCM playback and FM-OPL/3 streams and
+ output through SPDIF. This switch appears only on old chip
+ models (CM8738 033 and 037).
+ Note: without this control you can output PCM to SPDIF.
+ This is "mixing" of streams, so e.g. it's not for AC3 output
+ (see the next section).
+
+"IEC958 In Select" - Select SPDIF input, the internal CD-in (false)
+ and the external input (true). This switch appears only on
+ the chip models 039 or later.
+
+"IEC958 Loop" - SPDIF input data is loop back into SPDIF
+ output (aka bypass)
+
+"IEC958 Copyright" - Set the copyright bit.
+
+"IEC958 5V" - Select 0.5V (coax) or 5V (optical) interface.
+ On some cards this doesn't work and you need to change the
+ configuration with hardware dip-switch.
+
+"IEC958 In Monitor" - SPDIF input is routed to DAC.
+
+"IEC958 In Phase Inverse" - Set SPDIF input format as inverse.
+ [FIXME: this doesn't work on all chips..]
+
+"IEC958 In Valid" - Set input validity flag detection.
+
+Note: When "PCM Playback Switch" is on, you'll hear the digital output
+stream through analog line-out.
+
+
+The AC3 (RAW DIGITAL) OUTPUT
+----------------------------
+
+The driver supports raw digital (typically AC3) i/o over SPDIF. This
+can be toggled via IEC958 playback control, but usually you need to
+access it via alsa-lib. See alsa-lib documents for more details.
+
+On the raw digital mode, the "PCM Playback Switch" is automatically
+turned off so that non-audio data is heard from the analog line-out.
+Similarly the following switches are off: "IEC958 Mix Analog" and
+"IEC958 Loop". The switches are resumed after closing the SPDIF PCM
+device automatically to the previous state.
+
+
+ANALOG MIXER INTERFACE
+----------------------
+
+The mixer interface on CM8x38 is similar to SB16.
+There are Master, PCM, Synth, CD, Line, Mic and PC Speaker playback
+volumes. Synth, CD, Line and Mic have playback and capture switches,
+too, as well as SB16.
+
+In addition to the standard SB mixer, CM8x38 provides more functions.
+- PCM playback switch
+- PCM capture switch (to capture the data sent to DAC)
+- Mic Boost switch
+- Mic capture volume
+- Aux playback volume/switch and capture switch
+- 3D control switch
+
+
+MIDI CONTROLLER
+---------------
+
+The MPU401-UART interface is enabled as default only for the first
+(CMIPCI) card. You need to set module option "snd_midi_port" properly
+for the 2nd (CMIPCI) card.
+
+There is _no_ hardware wavetable function on this chip (except for
+OPL3 synth below).
+What's said as MIDI synth on Windows is a software synthesizer
+emulation. On Linux use TiMidity or other softsynth program for
+playing MIDI music.
+
+
+FM OPL/3 Synth
+--------------
+
+The FM OPL/3 is also enabled as default only for the first card.
+Set "snd_fm_port" module option for more cards.
+
+The output quality of FM OPL/3 is, however, very weird.
+I don't know why..
+
+
+Joystick and Modem
+------------------
+
+The joystick and modem should be available by enabling the control
+switch "Joystick" and "Modem" respectively. But I myself have never
+tested them yet.
+
+
+Debugging Information
+---------------------
+
+The registers are shown in /proc/asound/cardX/cmipci. If you have any
+problem (especially unexpected behavior of mixer), please attach the
+output of this proc file together with the bug report.
diff --git a/Documentation/sound/alsa/SB-Live-mixer.txt b/Documentation/sound/alsa/SB-Live-mixer.txt
new file mode 100644
index 000000000000..d37b0e646e2f
--- /dev/null
+++ b/Documentation/sound/alsa/SB-Live-mixer.txt
@@ -0,0 +1,356 @@
+
+ Sound Blaster Live mixer / default DSP code
+ ===========================================
+
+
+The EMU10K1 chips have a DSP part which can be programmed to support
+various ways of sample processing, which is described here.
+(This acticle does not deal with the overall functionality of the
+EMU10K1 chips. See the manuals section for further details.)
+
+The ALSA driver programs this portion of chip by default code
+(can be altered later) which offers the following functionality:
+
+
+1) IEC958 (S/PDIF) raw PCM
+--------------------------
+
+This PCM device (it's the 4th PCM device (index 3!) and first subdevice
+(index 0) for a given card) allows to forward 48kHz, stereo, 16-bit
+little endian streams without any modifications to the digital output
+(coaxial or optical). The universal interface allows the creation of up
+to 8 raw PCM devices operating at 48kHz, 16-bit little endian. It would
+be easy to add support for multichannel devices to the current code,
+but the conversion routines exist only for stereo (2-channel streams)
+at the time.
+
+Look to tram_poke routines in lowlevel/emu10k1/emufx.c for more details.
+
+
+2) Digital mixer controls
+-------------------------
+
+These controls are built using the DSP instructions. They offer extended
+functionality. Only the default build-in code in the ALSA driver is described
+here. Note that the controls work as attenuators: the maximum value is the
+neutral position leaving the signal unchanged. Note that if the same destination
+is mentioned in multiple controls, the signal is accumulated and can be wrapped
+(set to maximal or minimal value without checking of overflow).
+
+
+Explanation of used abbreviations:
+
+DAC - digital to analog converter
+ADC - analog to digital converter
+I2S - one-way three wire serial bus for digital sound by Philips Semiconductors
+ (this standard is used for connecting standalone DAC and ADC converters)
+LFE - low frequency effects (subwoofer signal)
+AC97 - a chip containing an analog mixer, DAC and ADC converters
+IEC958 - S/PDIF
+FX-bus - the EMU10K1 chip has an effect bus containing 16 accumulators.
+ Each of the synthesizer voices can feed its output to these accumulators
+ and the DSP microcontroller can operate with the resulting sum.
+
+
+name='Wave Playback Volume',index=0
+
+This control is used to attenuate samples for left and right PCM FX-bus
+accumulators. ALSA uses accumulators 0 and 1 for left and right PCM samples.
+The result samples are forwarded to the front DAC PCM slots of the AC97 codec.
+
+name='Wave Surround Playback Volume',index=0
+
+This control is used to attenuate samples for left and right PCM FX-bus
+accumulators. ALSA uses accumulators 0 and 1 for left and right PCM samples.
+The result samples are forwarded to the rear I2S DACs. These DACs operates
+separately (they are not inside the AC97 codec).
+
+name='Wave Center Playback Volume',index=0
+
+This control is used to attenuate samples for left and right PCM FX-bus
+accumulators. ALSA uses accumulators 0 and 1 for left and right PCM samples.
+The result is mixed to mono signal (single channel) and forwarded to
+the ??rear?? right DAC PCM slot of the AC97 codec.
+
+name='Wave LFE Playback Volume',index=0
+
+This control is used to attenuate samples for left and right PCM FX-bus
+accumulators. ALSA uses accumulators 0 and 1 for left and right PCM.
+The result is mixed to mono signal (single channel) and forwarded to
+the ??rear?? left DAC PCM slot of the AC97 codec.
+
+name='Wave Capture Volume',index=0
+name='Wave Capture Switch',index=0
+
+These controls are used to attenuate samples for left and right PCM FX-bus
+accumulator. ALSA uses accumulators 0 and 1 for left and right PCM.
+The result is forwarded to the ADC capture FIFO (thus to the standard capture
+PCM device).
+
+name='Music Playback Volume',index=0
+
+This control is used to attenuate samples for left and right MIDI FX-bus
+accumulators. ALSA uses accumulators 4 and 5 for left and right MIDI samples.
+The result samples are forwarded to the front DAC PCM slots of the AC97 codec.
+
+name='Music Capture Volume',index=0
+name='Music Capture Switch',index=0
+
+These controls are used to attenuate samples for left and right MIDI FX-bus
+accumulator. ALSA uses accumulators 4 and 5 for left and right PCM.
+The result is forwarded to the ADC capture FIFO (thus to the standard capture
+PCM device).
+
+name='Surround Digital Playback Volume',index=0
+
+This control is used to attenuate samples for left and right rear PCM FX-bus
+accumulators. ALSA uses accumulators 2 and 3 for left and right rear PCM samples.
+The result samples are forwarded to the rear I2S DACs. These DACs operate
+separately (they are not inside the AC97 codec).
+
+name='Surround Digital Capture Volume',index=0
+name='Surround Digital Capture Switch',index=0
+
+These controls are used to attenuate samples for left and right rear PCM FX-bus
+accumulators. ALSA uses accumulators 2 and 3 for left and right rear PCM samples.
+The result is forwarded to the ADC capture FIFO (thus to the standard capture
+PCM device).
+
+name='Center Playback Volume',index=0
+
+This control is used to attenuate sample for center PCM FX-bus accumulator.
+ALSA uses accumulator 6 for center PCM sample. The result sample is forwarded
+to the ??rear?? right DAC PCM slot of the AC97 codec.
+
+name='LFE Playback Volume',index=0
+
+This control is used to attenuate sample for center PCM FX-bus accumulator.
+ALSA uses accumulator 6 for center PCM sample. The result sample is forwarded
+to the ??rear?? left DAC PCM slot of the AC97 codec.
+
+name='AC97 Playback Volume',index=0
+
+This control is used to attenuate samples for left and right front ADC PCM slots
+of the AC97 codec. The result samples are forwarded to the front DAC PCM
+slots of the AC97 codec.
+********************************************************************************
+*** Note: This control should be zero for the standard operations, otherwise ***
+*** a digital loopback is activated. ***
+********************************************************************************
+
+name='AC97 Capture Volume',index=0
+
+This control is used to attenuate samples for left and right front ADC PCM slots
+of the AC97 codec. The result is forwarded to the ADC capture FIFO (thus to
+the standard capture PCM device).
+********************************************************************************
+*** Note: This control should be 100 (maximal value), otherwise no analog ***
+*** inputs of the AC97 codec can be captured (recorded). ***
+********************************************************************************
+
+name='IEC958 TTL Playback Volume',index=0
+
+This control is used to attenuate samples from left and right IEC958 TTL
+digital inputs (usually used by a CDROM drive). The result samples are
+forwarded to the front DAC PCM slots of the AC97 codec.
+
+name='IEC958 TTL Capture Volume',index=0
+
+This control is used to attenuate samples from left and right IEC958 TTL
+digital inputs (usually used by a CDROM drive). The result samples are
+forwarded to the ADC capture FIFO (thus to the standard capture PCM device).
+
+name='Zoom Video Playback Volume',index=0
+
+This control is used to attenuate samples from left and right zoom video
+digital inputs (usually used by a CDROM drive). The result samples are
+forwarded to the front DAC PCM slots of the AC97 codec.
+
+name='Zoom Video Capture Volume',index=0
+
+This control is used to attenuate samples from left and right zoom video
+digital inputs (usually used by a CDROM drive). The result samples are
+forwarded to the ADC capture FIFO (thus to the standard capture PCM device).
+
+name='IEC958 Optical Playback Volume',index=0
+
+This control is used to attenuate samples from left and right IEC958 optical
+digital input. The result samples are forwarded to the front DAC PCM slots
+of the AC97 codec.
+
+name='IEC958 Optical Capture Volume',index=0
+
+This control is used to attenuate samples from left and right IEC958 optical
+digital inputs. The result samples are forwarded to the ADC capture FIFO
+(thus to the standard capture PCM device).
+
+name='IEC958 Coaxial Playback Volume',index=0
+
+This control is used to attenuate samples from left and right IEC958 coaxial
+digital inputs. The result samples are forwarded to the front DAC PCM slots
+of the AC97 codec.
+
+name='IEC958 Coaxial Capture Volume',index=0
+
+This control is used to attenuate samples from left and right IEC958 coaxial
+digital inputs. The result samples are forwarded to the ADC capture FIFO
+(thus to the standard capture PCM device).
+
+name='Line LiveDrive Playback Volume',index=0
+name='Line LiveDrive Playback Volume',index=1
+
+This control is used to attenuate samples from left and right I2S ADC
+inputs (on the LiveDrive). The result samples are forwarded to the front
+DAC PCM slots of the AC97 codec.
+
+name='Line LiveDrive Capture Volume',index=1
+name='Line LiveDrive Capture Volume',index=1
+
+This control is used to attenuate samples from left and right I2S ADC
+inputs (on the LiveDrive). The result samples are forwarded to the ADC
+capture FIFO (thus to the standard capture PCM device).
+
+name='Tone Control - Switch',index=0
+
+This control turns the tone control on or off. The samples for front, rear
+and center / LFE outputs are affected.
+
+name='Tone Control - Bass',index=0
+
+This control sets the bass intensity. There is no neutral value!!
+When the tone control code is activated, the samples are always modified.
+The closest value to pure signal is 20.
+
+name='Tone Control - Treble',index=0
+
+This control sets the treble intensity. There is no neutral value!!
+When the tone control code is activated, the samples are always modified.
+The closest value to pure signal is 20.
+
+name='IEC958 Optical Raw Playback Switch',index=0
+
+If this switch is on, then the samples for the IEC958 (S/PDIF) digital
+output are taken only from the raw FX8010 PCM, otherwise standard front
+PCM samples are taken.
+
+name='Headphone Playback Volume',index=1
+
+This control attenuates the samples for the headphone output.
+
+name='Headphone Center Playback Switch',index=1
+
+If this switch is on, then the sample for the center PCM is put to the
+left headphone output (useful for SB Live cards without separate center/LFE
+output).
+
+name='Headphone LFE Playback Switch',index=1
+
+If this switch is on, then the sample for the center PCM is put to the
+right headphone output (useful for SB Live cards without separate center/LFE
+output).
+
+
+3) PCM stream related controls
+------------------------------
+
+name='EMU10K1 PCM Volume',index 0-31
+
+Channel volume attenuation in range 0-0xffff. The maximum value (no
+attenuation) is default. The channel mapping for three values is
+as follows:
+
+ 0 - mono, default 0xffff (no attenuation)
+ 1 - left, default 0xffff (no attenuation)
+ 2 - right, default 0xffff (no attenuation)
+
+name='EMU10K1 PCM Send Routing',index 0-31
+
+This control specifies the destination - FX-bus accumulators. There are
+twelve values with this mapping:
+
+ 0 - mono, A destination (FX-bus 0-15), default 0
+ 1 - mono, B destination (FX-bus 0-15), default 1
+ 2 - mono, C destination (FX-bus 0-15), default 2
+ 3 - mono, D destination (FX-bus 0-15), default 3
+ 4 - left, A destination (FX-bus 0-15), default 0
+ 5 - left, B destination (FX-bus 0-15), default 1
+ 6 - left, C destination (FX-bus 0-15), default 2
+ 7 - left, D destination (FX-bus 0-15), default 3
+ 8 - right, A destination (FX-bus 0-15), default 0
+ 9 - right, B destination (FX-bus 0-15), default 1
+ 10 - right, C destination (FX-bus 0-15), default 2
+ 11 - right, D destination (FX-bus 0-15), default 3
+
+Don't forget that it's illegal to assign a channel to the same FX-bus accumulator
+more than once (it means 0=0 && 1=0 is an invalid combination).
+
+name='EMU10K1 PCM Send Volume',index 0-31
+
+It specifies the attenuation (amount) for given destination in range 0-255.
+The channel mapping is following:
+
+ 0 - mono, A destination attn, default 255 (no attenuation)
+ 1 - mono, B destination attn, default 255 (no attenuation)
+ 2 - mono, C destination attn, default 0 (mute)
+ 3 - mono, D destination attn, default 0 (mute)
+ 4 - left, A destination attn, default 255 (no attenuation)
+ 5 - left, B destination attn, default 0 (mute)
+ 6 - left, C destination attn, default 0 (mute)
+ 7 - left, D destination attn, default 0 (mute)
+ 8 - right, A destination attn, default 0 (mute)
+ 9 - right, B destination attn, default 255 (no attenuation)
+ 10 - right, C destination attn, default 0 (mute)
+ 11 - right, D destination attn, default 0 (mute)
+
+
+
+4) MANUALS/PATENTS:
+-------------------
+
+ftp://opensource.creative.com/pub/doc
+-------------------------------------
+
+ Files:
+ LM4545.pdf AC97 Codec
+
+ m2049.pdf The EMU10K1 Digital Audio Processor
+
+ hog63.ps FX8010 - A DSP Chip Architecture for Audio Effects
+
+
+WIPO Patents
+------------
+ Patent numbers:
+ WO 9901813 (A1) Audio Effects Processor with multiple asynchronous (Jan. 14, 1999)
+ streams
+
+ WO 9901814 (A1) Processor with Instruction Set for Audio Effects (Jan. 14, 1999)
+
+ WO 9901953 (A1) Audio Effects Processor having Decoupled Instruction
+ Execution and Audio Data Sequencing (Jan. 14, 1999)
+
+
+US Patents (http://www.uspto.gov/)
+----------------------------------
+
+ US 5925841 Digital Sampling Instrument employing cache memory (Jul. 20, 1999)
+
+ US 5928342 Audio Effects Processor integrated on a single chip (Jul. 27, 1999)
+ with a multiport memory onto which multiple asynchronous
+ digital sound samples can be concurrently loaded
+
+ US 5930158 Processor with Instruction Set for Audio Effects (Jul. 27, 1999)
+
+ US 6032235 Memory initialization circuit (Tram) (Feb. 29, 2000)
+
+ US 6138207 Interpolation looping of audio samples in cache connected to (Oct. 24, 2000)
+ system bus with prioritization and modification of bus transfers
+ in accordance with loop ends and minimum block sizes
+
+ US 6151670 Method for conserving memory storage using a (Nov. 21, 2000)
+ pool of short term memory registers
+
+ US 6195715 Interrupt control for multiple programs communicating with (Feb. 27, 2001)
+ a common interrupt by associating programs to GP registers,
+ defining interrupt register, polling GP registers, and invoking
+ callback routine associated with defined interrupt register
diff --git a/Documentation/sound/alsa/seq_oss.html b/Documentation/sound/alsa/seq_oss.html
new file mode 100644
index 000000000000..d9776cf60c07
--- /dev/null
+++ b/Documentation/sound/alsa/seq_oss.html
@@ -0,0 +1,409 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<HTML>
+<HEAD>
+ <TITLE>OSS Sequencer Emulation on ALSA</TITLE>
+</HEAD>
+<BODY>
+
+<CENTER>
+<H1>
+
+<HR WIDTH="100%"></H1></CENTER>
+
+<CENTER>
+<H1>
+OSS Sequencer Emulation on ALSA</H1></CENTER>
+
+<HR WIDTH="100%">
+<P>Copyright (c) 1998,1999 by Takashi Iwai
+<TT><A HREF="mailto:iwai@ww.uni-erlangen.de">&lt;iwai@ww.uni-erlangen.de></A></TT>
+<P>ver.0.1.8; Nov. 16, 1999
+<H2>
+
+<HR WIDTH="100%"></H2>
+
+<H2>
+1. Description</H2>
+This directory contains the OSS sequencer emulation driver on ALSA. Note
+that this program is still in the development state.
+<P>What this does - it provides the emulation of the OSS sequencer, access
+via
+<TT>/dev/sequencer</TT> and <TT>/dev/music</TT> devices.
+The most of applications using OSS can run if the appropriate ALSA
+sequencer is prepared.
+<P>The following features are emulated by this driver:
+<UL>
+<LI>
+Normal sequencer and MIDI events:</LI>
+
+<BR>They are converted to the ALSA sequencer events, and sent to the corresponding
+port.
+<LI>
+Timer events:</LI>
+
+<BR>The timer is not selectable by ioctl. The control rate is fixed to
+100 regardless of HZ. That is, even on Alpha system, a tick is always
+1/100 second. The base rate and tempo can be changed in <TT>/dev/music</TT>.
+
+<LI>
+Patch loading:</LI>
+
+<BR>It purely depends on the synth drivers whether it's supported since
+the patch loading is realized by callback to the synth driver.
+<LI>
+I/O controls:</LI>
+
+<BR>Most of controls are accepted. Some controls
+are dependent on the synth driver, as well as even on original OSS.</UL>
+Furthermore, you can find the following advanced features:
+<UL>
+<LI>
+Better queue mechanism:</LI>
+
+<BR>The events are queued before processing them.
+<LI>
+Multiple applications:</LI>
+
+<BR>You can run two or more applications simultaneously (even for OSS sequencer)!
+However, each MIDI device is exclusive - that is, if a MIDI device is opened
+once by some application, other applications can't use it. No such a restriction
+in synth devices.
+<LI>
+Real-time event processing:</LI>
+
+<BR>The events can be processed in real time without using out of bound
+ioctl. To switch to real-time mode, send ABSTIME 0 event. The followed
+events will be processed in real-time without queued. To switch off the
+real-time mode, send RELTIME 0 event.
+<LI>
+<TT>/proc</TT> interface:</LI>
+
+<BR>The status of applications and devices can be shown via <TT>/proc/asound/seq/oss</TT>
+at any time. In the later version, configuration will be changed via <TT>/proc</TT>
+interface, too.</UL>
+
+<H2>
+2. Installation</H2>
+Run configure script with both sequencer support (<TT>--with-sequencer=yes</TT>)
+and OSS emulation (<TT>--with-oss=yes</TT>) options. A module <TT>snd-seq-oss.o</TT>
+will be created. If the synth module of your sound card supports for OSS
+emulation (so far, only Emu8000 driver), this module will be loaded automatically.
+Otherwise, you need to load this module manually.
+<P>At beginning, this module probes all the MIDI ports which have been
+already connected to the sequencer. Once after that, the creation and deletion
+of ports are watched by announcement mechanism of ALSA sequencer.
+<P>The available synth and MIDI devices can be found in proc interface.
+Run "<TT>cat /proc/asound/seq/oss</TT>", and check the devices. For example,
+if you use an AWE64 card, you'll see like the following:
+<PRE>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; OSS sequencer emulation version 0.1.8
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ALSA client number 63
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ALSA receiver port 0
+
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Number of applications: 0
+
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Number of synth devices: 1
+
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; synth 0: [EMU8000]
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; type 0x1 : subtype 0x20 : voices 32
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; capabilties : ioctl enabled / load_patch enabled
+
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Number of MIDI devices: 3
+
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; midi 0: [Emu8000 Port-0] ALSA port 65:0
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; capability write / opened none
+
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; midi 1: [Emu8000 Port-1] ALSA port 65:1
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; capability write / opened none
+
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; midi 2: [0: MPU-401 (UART)] ALSA port 64:0
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; capability read/write / opened none</PRE>
+Note that the device number may be different from the information of
+<TT>/proc/asound/oss-devices</TT>
+or ones of the original OSS driver. Use the device number listed in <TT>/proc/asound/seq/oss</TT>
+to play via OSS sequencer emulation.
+<H2>
+3. Using Synthesizer Devices</H2>
+Run your favorite program. I've tested playmidi-2.4, awemidi-0.4.3, gmod-3.1
+and xmp-1.1.5. You can load samples via <TT>/dev/sequencer</TT> like sfxload,
+too.
+<P>If the lowlevel driver supports multiple access to synth devices (like
+Emu8000 driver), two or more applications are allowed to run at the same
+time.
+<H2>
+4. Using MIDI Devices</H2>
+So far, only MIDI output was tested. MIDI input was not checked at all,
+but hopefully it will work. Use the device number listed in <TT>/proc/asound/seq/oss</TT>.
+Be aware that these numbers are mostly different from the list in
+<TT>/proc/asound/oss-devices</TT>.
+<H2>
+5. Module Options</H2>
+The following module options are available:
+<UL>
+<LI>
+<TT>maxqlen</TT></LI>
+
+<BR>specifies the maximum read/write queue length. This queue is private
+for OSS sequencer, so that it is independent from the queue length of ALSA
+sequencer. Default value is 1024.
+<LI>
+<TT>seq_oss_debug</TT></LI>
+
+<BR>specifies the debug level and accepts zero (= no debug message) or
+positive integer. Default value is 0.</UL>
+
+<H2>
+6. Queue Mechanism</H2>
+OSS sequencer emulation uses an ALSA priority queue. The
+events from <TT>/dev/sequencer</TT> are processed and put onto the queue
+specified by module option.
+<P>All the events from <TT>/dev/sequencer</TT> are parsed at beginning.
+The timing events are also parsed at this moment, so that the events may
+be processed in real-time. Sending an event ABSTIME 0 switches the operation
+mode to real-time mode, and sending an event RELTIME 0 switches it off.
+In the real-time mode, all events are dispatched immediately.
+<P>The queued events are dispatched to the corresponding ALSA sequencer
+ports after scheduled time by ALSA sequencer dispatcher.
+<P>If the write-queue is full, the application sleeps until a certain amount
+(as default one half) becomes empty in blocking mode. The synchronization
+to write timing was implemented, too.
+<P>The input from MIDI devices or echo-back events are stored on read FIFO
+queue. If application reads <TT>/dev/sequencer</TT> in blocking mode, the
+process will be awaked.
+
+<H2>
+7. Interface to Synthesizer Device</H2>
+
+<H3>
+7.1. Registration</H3>
+To register an OSS synthesizer device, use <TT>snd_seq_oss_synth_register</TT>
+function.
+<PRE>int snd_seq_oss_synth_register(char *name, int type, int subtype, int nvoices,
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; snd_seq_oss_callback_t *oper, void *private_data)</PRE>
+The arguments <TT>name</TT>, <TT>type</TT>, <TT>subtype</TT> and
+<TT>nvoices</TT>
+are used for making the appropriate synth_info structure for ioctl. The
+return value is an index number of this device. This index must be remembered
+for unregister. If registration is failed, -errno will be returned.
+<P>To release this device, call <TT>snd_seq_oss_synth_unregister function</TT>:
+<PRE>int snd_seq_oss_synth_unregister(int index),</PRE>
+where the <TT>index</TT> is the index number returned by register function.
+<H3>
+7.2. Callbacks</H3>
+OSS synthesizer devices have capability for sample downloading and ioctls
+like sample reset. In OSS emulation, these special features are realized
+by using callbacks. The registration argument oper is used to specify these
+callbacks. The following callback functions must be defined:
+<PRE>snd_seq_oss_callback_t:
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int (*open)(snd_seq_oss_arg_t *p, void *closure);
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int (*close)(snd_seq_oss_arg_t *p);
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int (*ioctl)(snd_seq_oss_arg_t *p, unsigned int cmd, unsigned long arg);
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int (*load_patch)(snd_seq_oss_arg_t *p, int format, const char *buf, int offs, int count);
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int (*reset)(snd_seq_oss_arg_t *p);
+Except for <TT>open</TT> and <TT>close</TT> callbacks, they are allowed
+to be NULL.
+<P>Each callback function takes the argument type snd_seq_oss_arg_t as the
+first argument.
+<PRE>struct snd_seq_oss_arg_t {
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int app_index;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int file_mode;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int seq_mode;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; snd_seq_addr_t addr;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void *private_data;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int event_passing;
+};</PRE>
+The first three fields, <TT>app_index</TT>, <TT>file_mode</TT> and
+<TT>seq_mode</TT>
+are initialized by OSS sequencer. The <TT>app_index</TT> is the application
+index which is unique to each application opening OSS sequencer. The
+<TT>file_mode</TT>
+is bit-flags indicating the file operation mode. See
+<TT>seq_oss.h</TT>
+for its meaning. The <TT>seq_mode</TT> is sequencer operation mode. In
+the current version, only <TT>SND_OSSSEQ_MODE_SYNTH</TT> is used.
+<P>The next two fields, <TT>addr</TT> and <TT>private_data</TT>, must be
+filled by the synth driver at open callback. The <TT>addr</TT> contains
+the address of ALSA sequencer port which is assigned to this device. If
+the driver allocates memory for <TT>private_data</TT>, it must be released
+in close callback by itself.
+<P>The last field, <TT>event_passing</TT>, indicates how to translate note-on
+/ off events. In <TT>PROCESS_EVENTS</TT> mode, the note 255 is regarded
+as velocity change, and key pressure event is passed to the port. In <TT>PASS_EVENTS</TT>
+mode, all note on/off events are passed to the port without modified. <TT>PROCESS_KEYPRESS</TT>
+mode checks the note above 128 and regards it as key pressure event (mainly
+for Emu8000 driver).
+<H4>
+7.2.1. Open Callback</H4>
+The <TT>open</TT> is called at each time this device is opened by an application
+using OSS sequencer. This must not be NULL. Typically, the open callback
+does the following procedure:
+<OL>
+<LI>
+Allocate private data record.</LI>
+
+<LI>
+Create an ALSA sequencer port.</LI>
+
+<LI>
+Set the new port address on arg->addr.</LI>
+
+<LI>
+Set the private data record pointer on arg->private_data.</LI>
+</OL>
+Note that the type bit-flags in port_info of this synth port must NOT contain
+<TT>TYPE_MIDI_GENERIC</TT>
+bit. Instead, <TT>TYPE_SPECIFIC</TT> should be used. Also, <TT>CAP_SUBSCRIPTION</TT>
+bit should NOT be included, too. This is necessary to tell it from other
+normal MIDI devices. If the open procedure succeeded, return zero. Otherwise,
+return -errno.
+<H4>
+7.2.2 Ioctl Callback</H4>
+The <TT>ioctl</TT> callback is called when the sequencer receives device-specific
+ioctls. The following two ioctls should be processed by this callback:
+<UL>
+<LI>
+<TT>IOCTL_SEQ_RESET_SAMPLES</TT></LI>
+
+<BR>reset all samples on memory -- return 0
+<LI>
+<TT>IOCTL_SYNTH_MEMAVL</TT></LI>
+
+<BR>return the available memory size
+<LI>
+<TT>FM_4OP_ENABLE</TT></LI>
+
+<BR>can be ignored usually</UL>
+The other ioctls are processed inside the sequencer without passing to
+the lowlevel driver.
+<H4>
+7.2.3 Load_Patch Callback</H4>
+The <TT>load_patch</TT> callback is used for sample-downloading. This callback
+must read the data on user-space and transfer to each device. Return 0
+if succeeded, and -errno if failed. The format argument is the patch key
+in patch_info record. The buf is user-space pointer where patch_info record
+is stored. The offs can be ignored. The count is total data size of this
+sample data.
+<H4>
+7.2.4 Close Callback</H4>
+The <TT>close</TT> callback is called when this device is closed by the
+applicaion. If any private data was allocated in open callback, it must
+be released in the close callback. The deletion of ALSA port should be
+done here, too. This callback must not be NULL.
+<H4>
+7.2.5 Reset Callback</H4>
+The <TT>reset</TT> callback is called when sequencer device is reset or
+closed by applications. The callback should turn off the sounds on the
+relevant port immediately, and initialize the status of the port. If this
+callback is undefined, OSS seq sends a <TT>HEARTBEAT</TT> event to the
+port.
+<H3>
+7.3 Events</H3>
+Most of the events are processed by sequencer and translated to the adequate
+ALSA sequencer events, so that each synth device can receive by input_event
+callback of ALSA sequencer port. The following ALSA events should be implemented
+by the driver:
+<BR>&nbsp;
+<TABLE BORDER WIDTH="75%" NOSAVE >
+<TR NOSAVE>
+<TD NOSAVE><B>ALSA event</B></TD>
+
+<TD><B>Original OSS events</B></TD>
+</TR>
+
+<TR>
+<TD>NOTEON</TD>
+
+<TD>SEQ_NOTEON
+<BR>MIDI_NOTEON</TD>
+</TR>
+
+<TR>
+<TD>NOTE</TD>
+
+<TD>SEQ_NOTEOFF
+<BR>MIDI_NOTEOFF</TD>
+</TR>
+
+<TR NOSAVE>
+<TD NOSAVE>KEYPRESS</TD>
+
+<TD>MIDI_KEY_PRESSURE</TD>
+</TR>
+
+<TR NOSAVE>
+<TD>CHANPRESS</TD>
+
+<TD NOSAVE>SEQ_AFTERTOUCH
+<BR>MIDI_CHN_PRESSURE</TD>
+</TR>
+
+<TR NOSAVE>
+<TD NOSAVE>PGMCHANGE</TD>
+
+<TD NOSAVE>SEQ_PGMCHANGE
+<BR>MIDI_PGM_CHANGE</TD>
+</TR>
+
+<TR>
+<TD>PITCHBEND</TD>
+
+<TD>SEQ_CONTROLLER(CTRL_PITCH_BENDER)
+<BR>MIDI_PITCH_BEND</TD>
+</TR>
+
+<TR>
+<TD>CONTROLLER</TD>
+
+<TD>MIDI_CTL_CHANGE
+<BR>SEQ_BALANCE (with CTL_PAN)</TD>
+</TR>
+
+<TR>
+<TD>CONTROL14</TD>
+
+<TD>SEQ_CONTROLLER</TD>
+</TR>
+
+<TR>
+<TD>REGPARAM</TD>
+
+<TD>SEQ_CONTROLLER(CTRL_PITCH_BENDER_RANGE)</TD>
+</TR>
+
+<TR>
+<TD>SYSEX</TD>
+
+<TD>SEQ_SYSEX</TD>
+</TR>
+</TABLE>
+
+<P>The most of these behavior can be realized by MIDI emulation driver
+included in the Emu8000 lowlevel driver. In the future release, this module
+will be independent.
+<P>Some OSS events (<TT>SEQ_PRIVATE</TT> and <TT>SEQ_VOLUME</TT> events) are passed as event
+type SND_SEQ_OSS_PRIVATE. The OSS sequencer passes these event 8 byte
+packets without any modification. The lowlevel driver should process these
+events appropriately.
+<H2>
+8. Interface to MIDI Device</H2>
+Since the OSS emulation probes the creation and deletion of ALSA MIDI sequencer
+ports automatically by receiving announcement from ALSA sequencer, the
+MIDI devices don't need to be registered explicitly like synth devices.
+However, the MIDI port_info registered to ALSA sequencer must include a group
+name <TT>SND_SEQ_GROUP_DEVICE</TT> and a capability-bit <TT>CAP_READ</TT> or
+<TT>CAP_WRITE</TT>. Also, subscription capabilities, <TT>CAP_SUBS_READ</TT> or <TT>CAP_SUBS_WRITE</TT>,
+must be defined, too. If these conditions are not satisfied, the port is not
+registered as OSS sequencer MIDI device.
+<P>The events via MIDI devices are parsed in OSS sequencer and converted
+to the corresponding ALSA sequencer events. The input from MIDI sequencer
+is also converted to MIDI byte events by OSS sequencer. This works just
+a reverse way of seq_midi module.
+<H2>
+9. Known Problems / TODO's</H2>
+
+<UL>
+<LI>
+Patch loading via ALSA instrument layer is not implemented yet.</LI>
+</UL>
+
+</BODY>
+</HTML>
diff --git a/Documentation/sound/AD1816 b/Documentation/sound/oss/AD1816
index 14bd8f25d523..14bd8f25d523 100644
--- a/Documentation/sound/AD1816
+++ b/Documentation/sound/oss/AD1816
diff --git a/Documentation/sound/ALS b/Documentation/sound/oss/ALS
index d01ffbfd5808..d01ffbfd5808 100644
--- a/Documentation/sound/ALS
+++ b/Documentation/sound/oss/ALS
diff --git a/Documentation/sound/AWE32 b/Documentation/sound/oss/AWE32
index 0f50f5d24c28..0f50f5d24c28 100644
--- a/Documentation/sound/AWE32
+++ b/Documentation/sound/oss/AWE32
diff --git a/Documentation/sound/AudioExcelDSP16 b/Documentation/sound/oss/AudioExcelDSP16
index f4ffd9d0c2e1..f4ffd9d0c2e1 100644
--- a/Documentation/sound/AudioExcelDSP16
+++ b/Documentation/sound/oss/AudioExcelDSP16
diff --git a/Documentation/sound/CMI8330 b/Documentation/sound/oss/CMI8330
index 28779988406a..28779988406a 100644
--- a/Documentation/sound/CMI8330
+++ b/Documentation/sound/oss/CMI8330
diff --git a/Documentation/sound/CMI8338 b/Documentation/sound/oss/CMI8338
index 387d058c3f95..387d058c3f95 100644
--- a/Documentation/sound/CMI8338
+++ b/Documentation/sound/oss/CMI8338
diff --git a/Documentation/sound/CS4232 b/Documentation/sound/oss/CS4232
index 7d6af7a5c1c2..7d6af7a5c1c2 100644
--- a/Documentation/sound/CS4232
+++ b/Documentation/sound/oss/CS4232
diff --git a/Documentation/sound/ChangeLog.awe b/Documentation/sound/oss/ChangeLog.awe
index 330cc0e5f102..330cc0e5f102 100644
--- a/Documentation/sound/ChangeLog.awe
+++ b/Documentation/sound/oss/ChangeLog.awe
diff --git a/Documentation/sound/ChangeLog.multisound b/Documentation/sound/oss/ChangeLog.multisound
index a05a74365dd3..a05a74365dd3 100644
--- a/Documentation/sound/ChangeLog.multisound
+++ b/Documentation/sound/oss/ChangeLog.multisound
diff --git a/Documentation/sound/ESS b/Documentation/sound/oss/ESS
index bba93b4d2def..bba93b4d2def 100644
--- a/Documentation/sound/ESS
+++ b/Documentation/sound/oss/ESS
diff --git a/Documentation/sound/ESS1868 b/Documentation/sound/oss/ESS1868
index 55e922f21bc0..55e922f21bc0 100644
--- a/Documentation/sound/ESS1868
+++ b/Documentation/sound/oss/ESS1868
diff --git a/Documentation/sound/INSTALL.awe b/Documentation/sound/oss/INSTALL.awe
index 72219acb2790..72219acb2790 100644
--- a/Documentation/sound/INSTALL.awe
+++ b/Documentation/sound/oss/INSTALL.awe
diff --git a/Documentation/sound/Introduction b/Documentation/sound/oss/Introduction
index 0b7fdc9593a4..0b7fdc9593a4 100644
--- a/Documentation/sound/Introduction
+++ b/Documentation/sound/oss/Introduction
diff --git a/Documentation/sound/MAD16 b/Documentation/sound/oss/MAD16
index 1f3abf7f0db8..1f3abf7f0db8 100644
--- a/Documentation/sound/MAD16
+++ b/Documentation/sound/oss/MAD16
diff --git a/Documentation/sound/Maestro b/Documentation/sound/oss/Maestro
index 4a80eb3f8e00..4a80eb3f8e00 100644
--- a/Documentation/sound/Maestro
+++ b/Documentation/sound/oss/Maestro
diff --git a/Documentation/sound/Maestro3 b/Documentation/sound/oss/Maestro3
index ce6cf791ce6c..ce6cf791ce6c 100644
--- a/Documentation/sound/Maestro3
+++ b/Documentation/sound/oss/Maestro3
diff --git a/Documentation/sound/MultiSound b/Documentation/sound/oss/MultiSound
index e4a18bb7f73a..e4a18bb7f73a 100644
--- a/Documentation/sound/MultiSound
+++ b/Documentation/sound/oss/MultiSound
diff --git a/Documentation/sound/NEWS b/Documentation/sound/oss/NEWS
index de09b8c0a151..de09b8c0a151 100644
--- a/Documentation/sound/NEWS
+++ b/Documentation/sound/oss/NEWS
diff --git a/Documentation/sound/NM256 b/Documentation/sound/oss/NM256
index b503217488b3..b503217488b3 100644
--- a/Documentation/sound/NM256
+++ b/Documentation/sound/oss/NM256
diff --git a/Documentation/sound/OPL3 b/Documentation/sound/oss/OPL3
index 2468ff827688..2468ff827688 100644
--- a/Documentation/sound/OPL3
+++ b/Documentation/sound/oss/OPL3
diff --git a/Documentation/sound/OPL3-SA b/Documentation/sound/oss/OPL3-SA
index 0d91c8bf3b83..0d91c8bf3b83 100644
--- a/Documentation/sound/OPL3-SA
+++ b/Documentation/sound/oss/OPL3-SA
diff --git a/Documentation/sound/OPL3-SA2 b/Documentation/sound/oss/OPL3-SA2
index 5da5199a485b..5da5199a485b 100644
--- a/Documentation/sound/OPL3-SA2
+++ b/Documentation/sound/oss/OPL3-SA2
diff --git a/Documentation/sound/Opti b/Documentation/sound/oss/Opti
index 246f0224d789..246f0224d789 100644
--- a/Documentation/sound/Opti
+++ b/Documentation/sound/oss/Opti
diff --git a/Documentation/sound/PAS16 b/Documentation/sound/oss/PAS16
index fc0b6fe0716a..fc0b6fe0716a 100644
--- a/Documentation/sound/PAS16
+++ b/Documentation/sound/oss/PAS16
diff --git a/Documentation/sound/PSS b/Documentation/sound/oss/PSS
index 187b9525e1f6..187b9525e1f6 100644
--- a/Documentation/sound/PSS
+++ b/Documentation/sound/oss/PSS
diff --git a/Documentation/sound/PSS-updates b/Documentation/sound/oss/PSS-updates
index 004e894af5c8..004e894af5c8 100644
--- a/Documentation/sound/PSS-updates
+++ b/Documentation/sound/oss/PSS-updates
diff --git a/Documentation/sound/README.OSS b/Documentation/sound/oss/README.OSS
index ac1eaf5e977d..ac1eaf5e977d 100644
--- a/Documentation/sound/README.OSS
+++ b/Documentation/sound/oss/README.OSS
diff --git a/Documentation/sound/README.awe b/Documentation/sound/oss/README.awe
index 80054cd8fcde..80054cd8fcde 100644
--- a/Documentation/sound/README.awe
+++ b/Documentation/sound/oss/README.awe
diff --git a/Documentation/sound/README.modules b/Documentation/sound/oss/README.modules
index 98f525cab6c4..98f525cab6c4 100644
--- a/Documentation/sound/README.modules
+++ b/Documentation/sound/oss/README.modules
diff --git a/Documentation/sound/README.ymfsb b/Documentation/sound/oss/README.ymfsb
index af8a7d3a4e8e..af8a7d3a4e8e 100644
--- a/Documentation/sound/README.ymfsb
+++ b/Documentation/sound/oss/README.ymfsb
diff --git a/Documentation/sound/SoundPro b/Documentation/sound/oss/SoundPro
index 61b9a91973bf..61b9a91973bf 100644
--- a/Documentation/sound/SoundPro
+++ b/Documentation/sound/oss/SoundPro
diff --git a/Documentation/sound/Soundblaster b/Documentation/sound/oss/Soundblaster
index b288d464ba8b..b288d464ba8b 100644
--- a/Documentation/sound/Soundblaster
+++ b/Documentation/sound/oss/Soundblaster
diff --git a/Documentation/sound/Tropez+ b/Documentation/sound/oss/Tropez+
index b93a6b734fc0..b93a6b734fc0 100644
--- a/Documentation/sound/Tropez+
+++ b/Documentation/sound/oss/Tropez+
diff --git a/Documentation/sound/VIA-chipset b/Documentation/sound/oss/VIA-chipset
index 37865234e54d..37865234e54d 100644
--- a/Documentation/sound/VIA-chipset
+++ b/Documentation/sound/oss/VIA-chipset
diff --git a/Documentation/sound/VIBRA16 b/Documentation/sound/oss/VIBRA16
index 0a0aff9d7531..0a0aff9d7531 100644
--- a/Documentation/sound/VIBRA16
+++ b/Documentation/sound/oss/VIBRA16
diff --git a/Documentation/sound/WaveArtist b/Documentation/sound/oss/WaveArtist
index f4f3407cd818..f4f3407cd818 100644
--- a/Documentation/sound/WaveArtist
+++ b/Documentation/sound/oss/WaveArtist
diff --git a/Documentation/sound/Wavefront b/Documentation/sound/oss/Wavefront
index 5453af77f425..5453af77f425 100644
--- a/Documentation/sound/Wavefront
+++ b/Documentation/sound/oss/Wavefront
diff --git a/Documentation/sound/btaudio b/Documentation/sound/oss/btaudio
index 1a693e69d44b..1a693e69d44b 100644
--- a/Documentation/sound/btaudio
+++ b/Documentation/sound/oss/btaudio
diff --git a/Documentation/sound/cs46xx b/Documentation/sound/oss/cs46xx
index 1f93c03ceaa4..1f93c03ceaa4 100644
--- a/Documentation/sound/cs46xx
+++ b/Documentation/sound/oss/cs46xx
diff --git a/Documentation/sound/es1370 b/Documentation/sound/oss/es1370
index 7b38b1a096a3..7b38b1a096a3 100644
--- a/Documentation/sound/es1370
+++ b/Documentation/sound/oss/es1370
diff --git a/Documentation/sound/es1371 b/Documentation/sound/oss/es1371
index c3151266771c..c3151266771c 100644
--- a/Documentation/sound/es1371
+++ b/Documentation/sound/oss/es1371
diff --git a/Documentation/sound/mwave b/Documentation/sound/oss/mwave
index 858334bb46b0..858334bb46b0 100644
--- a/Documentation/sound/mwave
+++ b/Documentation/sound/oss/mwave
diff --git a/Documentation/sound/solo1 b/Documentation/sound/oss/solo1
index 6f53d407d027..6f53d407d027 100644
--- a/Documentation/sound/solo1
+++ b/Documentation/sound/oss/solo1
diff --git a/Documentation/sound/sonicvibes b/Documentation/sound/oss/sonicvibes
index 84dee2e0b37d..84dee2e0b37d 100644
--- a/Documentation/sound/sonicvibes
+++ b/Documentation/sound/oss/sonicvibes
diff --git a/Documentation/sound/ultrasound b/Documentation/sound/oss/ultrasound
index 32cd50478b36..32cd50478b36 100644
--- a/Documentation/sound/ultrasound
+++ b/Documentation/sound/oss/ultrasound
diff --git a/Documentation/sound/vwsnd b/Documentation/sound/oss/vwsnd
index a6ea0a1df9e4..a6ea0a1df9e4 100644
--- a/Documentation/sound/vwsnd
+++ b/Documentation/sound/oss/vwsnd
diff --git a/drivers/net/wan/Config.help b/drivers/net/wan/Config.help
index d9ecd0636727..eebc3287fa86 100644
--- a/drivers/net/wan/Config.help
+++ b/drivers/net/wan/Config.help
@@ -41,14 +41,15 @@ CONFIG_FARSYNC
This driver supports the FarSync T-Series X.21 (and V.35/V.24) cards
from FarSite Communications Ltd.
Synchronous communication is supported on all ports at speeds up to
- 8Mb/s (128K on V.24) using synchronous PPP or Cisco HDLC.
+ 8Mb/s (128K on V.24) using synchronous PPP, Cisco HDLC, raw HDLC,
+ Frame Relay or X.25/LAPB.
If you want to compile this driver as a module ( = code which can be
inserted in and removed from the running kernel whenever you want)
say M here and read <file:Documentation/modules.txt>.
The module will be called farsync.o and if you want the module to be
automatically loaded when the interface is referenced then you
- should add "alias syncX farsync" to /etc/modules.conf for each
+ should add "alias hdlcX farsync" to /etc/modules.conf for each
interface, where X is 0, 1, 2, ...
CONFIG_DLCI
diff --git a/drivers/net/wan/Config.in b/drivers/net/wan/Config.in
index 0a910e1611d9..9f0e4c3c5c1c 100644
--- a/drivers/net/wan/Config.in
+++ b/drivers/net/wan/Config.in
@@ -39,9 +39,6 @@ if [ "$CONFIG_WAN" = "y" ]; then
dep_tristate ' Etinc PCISYNC serial board support (EXPERIMENTAL)' CONFIG_DSCC4 m
-# FarSite Communications' cards
-
- tristate ' FarSync T-Series X.21 (and V.35/V.24) cards' CONFIG_FARSYNC
#
# Lan Media's board. Currently 1000, 1200, 5200, 5245
@@ -55,8 +52,13 @@ if [ "$CONFIG_WAN" = "y" ]; then
tristate ' SyncLink HDLC/SYNCPPP support' CONFIG_SYNCLINK_SYNCPPP
- tristate ' Generic HDLC driver' CONFIG_HDLC
+# Generic HDLC
+
+ tristate ' Generic HDLC layer' CONFIG_HDLC
if [ "$CONFIG_HDLC" != "n" ]; then
+ bool ' Raw HDLC support' CONFIG_HDLC_RAW
+ bool ' Cisco HDLC support' CONFIG_HDLC_CISCO
+ bool ' Frame Relay support' CONFIG_HDLC_FR
bool ' Synchronous Point-to-Point Protocol (PPP) support' CONFIG_HDLC_PPP
if [ "$CONFIG_LAPB" = "m" -a "$CONFIG_HDLC" = "m" -o "$CONFIG_LAPB" = "y" ]; then
bool ' X.25 protocol support' CONFIG_HDLC_X25
@@ -65,6 +67,11 @@ if [ "$CONFIG_WAN" = "y" ]; then
fi
dep_tristate ' SDL RISCom/N2 support' CONFIG_N2 $CONFIG_HDLC
dep_tristate ' Moxa C101 support' CONFIG_C101 $CONFIG_HDLC
+ dep_tristate ' FarSync T-Series support' CONFIG_FARSYNC $CONFIG_HDLC
+ bool ' Debug received/transmitted packets' CONFIG_HDLC_DEBUG_PKT
+ bool ' Debug hard_header routines' CONFIG_HDLC_DEBUG_HARD_HEADER
+ bool ' Debug FECN/BECN conditions' CONFIG_HDLC_DEBUG_ECN
+ bool ' Debug RX/TX packet rings' CONFIG_HDLC_DEBUG_RINGS
fi
tristate ' Frame relay DLCI support' CONFIG_DLCI
diff --git a/drivers/net/wan/Makefile b/drivers/net/wan/Makefile
index 988990ef0848..04e5538586bc 100644
--- a/drivers/net/wan/Makefile
+++ b/drivers/net/wan/Makefile
@@ -9,7 +9,7 @@ SUB_DIRS :=
O_TARGET := wan.o
-export-objs = z85230.o syncppp.o comx.o sdladrv.o cycx_drv.o hdlc.o
+export-objs = z85230.o syncppp.o comx.o sdladrv.o cycx_drv.o hdlc_generic.o
list-multi = wanpipe.o cyclomx.o
wanpipe-objs = sdlamain.o sdla_ft1.o $(wanpipe-y)
@@ -22,6 +22,11 @@ wanpipe-$(CONFIG_WANPIPE_MULTPPP) += wanpipe_multppp.o
cyclomx-objs = cycx_main.o $(cyclomx-y)
cyclomx-$(CONFIG_CYCLOMX_X25) += cycx_x25.o
+hdlc-$(CONFIG_HDLC_RAW) += hdlc_raw.o
+hdlc-$(CONFIG_HDLC_CISCO) += hdlc_cisco.o
+hdlc-$(CONFIG_HDLC_FR) += hdlc_fr.o
+hdlc-$(CONFIG_HDLC_PPP) += hdlc_ppp.o
+hdlc-$(CONFIG_HDLC_X25) += hdlc_x25.o
obj-$(CONFIG_HOSTESS_SV11) += z85230.o syncppp.o hostess_sv11.o
obj-$(CONFIG_SEALEVEL_4021) += z85230.o syncppp.o sealevel.o
@@ -56,12 +61,17 @@ obj-$(CONFIG_CYCLADES_SYNC) += cycx_drv.o cyclomx.o
obj-$(CONFIG_LAPBETHER) += lapbether.o
obj-$(CONFIG_SBNI) += sbni.o
obj-$(CONFIG_HDLC) += hdlc.o
-obj-$(CONFIG_HDLC_PPP) += syncppp.o
+ifeq ($(CONFIG_HDLC_PPP),y)
+ obj-$(CONFIG_HDLC) += syncppp.o
+endif
obj-$(CONFIG_N2) += n2.o
obj-$(CONFIG_C101) += c101.o
include $(TOPDIR)/Rules.make
+hdlc.o: hdlc_generic.o $(hdlc-y)
+ $(LD) -r -o $@ hdlc_generic.o $(hdlc-y)
+
wanpipe.o: $(wanpipe-objs)
$(LD) -r -o $@ $(wanpipe-objs)
diff --git a/drivers/net/wan/c101.c b/drivers/net/wan/c101.c
index e8f413ef9489..7474c9547e28 100644
--- a/drivers/net/wan/c101.c
+++ b/drivers/net/wan/c101.c
@@ -1,7 +1,7 @@
/*
* Moxa C101 synchronous serial card driver for Linux
*
- * Copyright (C) 2000 Krzysztof Halasa <khc@pm.waw.pl>
+ * Copyright (C) 2000-2001 Krzysztof Halasa <khc@pm.waw.pl>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
@@ -15,6 +15,7 @@
* Moxa C101 User's Manual
*/
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
@@ -29,10 +30,8 @@
#include "hd64570.h"
-#define DEBUG_RINGS
-/* #define DEBUG_PKT */
-static const char* version = "Moxa C101 driver revision: 1.02 for Linux 2.4";
+static const char* version = "Moxa C101 driver version: 1.09";
static const char* devname = "C101";
#define C101_PAGE 0x1D00
@@ -51,12 +50,12 @@ static char *hw; /* pointer to hw=xxx command line string */
typedef struct card_s {
hdlc_device hdlc; /* HDLC device struct - must be first */
spinlock_t lock; /* TX lock */
- int clkmode; /* clock mode */
- int clkrate; /* clock speed */
- int line; /* loopback only */
u8 *win0base; /* ISA window base address */
u32 phy_winbase; /* ISA physical base address */
u16 buff_offset; /* offset of first buffer of first channel */
+ sync_serial_settings settings;
+ unsigned short encoding;
+ unsigned short parity;
u8 rxs, txs, tmc; /* SCA registers */
u8 irq; /* IRQ (3-15) */
u8 ring_buffers; /* number of buffers in a ring */
@@ -72,6 +71,9 @@ typedef struct card_s {
typedef card_t port_t;
+static card_t *first_card;
+static card_t **new_card = &first_card;
+
#define sca_in(reg, card) readb((card)->win0base + C101_SCA + (reg))
#define sca_out(value, reg, card) writeb(value, (card)->win0base + C101_SCA + (reg))
@@ -105,13 +107,13 @@ static inline void openwin(card_t *card, u8 page)
#include "hd6457x.c"
-static int c101_set_clock(port_t *port, int value)
+static int c101_set_iface(port_t *port)
{
u8 msci = get_msci(port);
u8 rxs = port->rxs & CLK_BRG_MASK;
u8 txs = port->txs & CLK_BRG_MASK;
- switch(value) {
+ switch(port->settings.clock_type) {
case CLOCK_EXT:
rxs |= CLK_LINE_RX; /* RXC input */
txs |= CLK_LINE_TX; /* TXC input */
@@ -140,76 +142,76 @@ static int c101_set_clock(port_t *port, int value)
port->txs = txs;
sca_out(rxs, msci + RXS, port);
sca_out(txs, msci + TXS, port);
- port->clkmode = value;
+ sca_set_port(port);
return 0;
}
-static int c101_open(hdlc_device *hdlc)
+static int c101_open(struct net_device *dev)
{
+ hdlc_device *hdlc = dev_to_hdlc(dev);
port_t *port = hdlc_to_port(hdlc);
+ int result = hdlc_open(hdlc);
+ if (result)
+ return result;
MOD_INC_USE_COUNT;
writeb(1, port->win0base + C101_DTR);
sca_out(0, MSCI1_OFFSET + CTL, port); /* RTS uses ch#2 output */
sca_open(hdlc);
- c101_set_clock(port, port->clkmode);
- return 0;
+ return c101_set_iface(port);
}
-static void c101_close(hdlc_device *hdlc)
+static int c101_close(struct net_device *dev)
{
+ hdlc_device *hdlc = dev_to_hdlc(dev);
port_t *port = hdlc_to_port(hdlc);
sca_close(hdlc);
writeb(0, port->win0base + C101_DTR);
sca_out(CTL_NORTS, MSCI1_OFFSET + CTL, port);
+ hdlc_close(hdlc);
MOD_DEC_USE_COUNT;
+ return 0;
}
-static int c101_ioctl(hdlc_device *hdlc, struct ifreq *ifr, int cmd)
+static int c101_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
- int value = ifr->ifr_ifru.ifru_ivalue;
- int result = 0;
+ union line_settings *line = &ifr->ifr_settings->ifs_line;
+ const size_t size = sizeof(sync_serial_settings);
+ hdlc_device *hdlc = dev_to_hdlc(dev);
port_t *port = hdlc_to_port(hdlc);
- if(!capable(CAP_NET_ADMIN))
- return -EPERM;
-
- switch(cmd) {
- case HDLCSCLOCK:
- result = c101_set_clock(port, value);
- case HDLCGCLOCK:
- value = port->clkmode;
- break;
-
- case HDLCSCLOCKRATE:
- port->clkrate = value;
- sca_set_clock(port);
- case HDLCGCLOCKRATE:
- value = port->clkrate;
- break;
-
- case HDLCSLINE:
- result = sca_set_loopback(port, value);
- case HDLCGLINE:
- value = port->line;
- break;
-
-#ifdef DEBUG_RINGS
- case HDLCRUN:
+#ifdef CONFIG_HDLC_DEBUG_RINGS
+ if (cmd == SIOCDEVPRIVATE) {
sca_dump_rings(hdlc);
return 0;
-#endif /* DEBUG_RINGS */
+ }
+#endif
+ if (cmd != SIOCWANDEV)
+ return hdlc_ioctl(dev, ifr, cmd);
+
+ switch(ifr->ifr_settings->type) {
+ case IF_GET_IFACE:
+ ifr->ifr_settings->type = IF_IFACE_SYNC_SERIAL;
+ if (copy_to_user(&line->sync, &port->settings, size))
+ return -EFAULT;
+ return 0;
+
+ case IF_IFACE_SYNC_SERIAL:
+ if(!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ if (copy_from_user(&port->settings, &line->sync, size))
+ return -EFAULT;
+ /* FIXME - put sanity checks here */
+ return c101_set_iface(port);
default:
- return -EINVAL;
+ return hdlc_ioctl(dev, ifr, cmd);
}
-
- ifr->ifr_ifru.ifru_ivalue = value;
- return result;
}
@@ -231,6 +233,7 @@ static void c101_destroy_card(card_t *card)
static int c101_run(unsigned long irq, unsigned long winbase)
{
+ struct net_device *dev;
card_t *card;
int result;
@@ -284,15 +287,19 @@ static int c101_run(unsigned long irq, unsigned long winbase)
sca_init(card, 0);
+ dev = hdlc_to_dev(&card->hdlc);
+
spin_lock_init(&card->lock);
- hdlc_to_dev(&card->hdlc)->irq = irq;
- hdlc_to_dev(&card->hdlc)->mem_start = winbase;
- hdlc_to_dev(&card->hdlc)->mem_end = winbase + C101_MAPPED_RAM_SIZE - 1;
- hdlc_to_dev(&card->hdlc)->tx_queue_len = 50;
- card->hdlc.ioctl = c101_ioctl;
- card->hdlc.open = c101_open;
- card->hdlc.close = c101_close;
+ dev->irq = irq;
+ dev->mem_start = winbase;
+ dev->mem_end = winbase + C101_MAPPED_RAM_SIZE - 1;
+ dev->tx_queue_len = 50;
+ dev->do_ioctl = c101_ioctl;
+ dev->open = c101_open;
+ dev->stop = c101_close;
+ card->hdlc.attach = sca_attach;
card->hdlc.xmit = sca_xmit;
+ card->settings.clock_type = CLOCK_EXT;
result = register_hdlc_device(&card->hdlc);
if (result) {
@@ -319,7 +326,7 @@ static int __init c101_init(void)
return -ENOSYS; /* no parameters specified, abort */
}
- printk(KERN_INFO "%s\n", version);
+ printk(KERN_INFO "%s (SCA-%s)\n", version, sca_version);
do {
unsigned long irq, ram;
diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c
index cc48edb4c809..991996da0fb1 100644
--- a/drivers/net/wan/dscc4.c
+++ b/drivers/net/wan/dscc4.c
@@ -72,7 +72,7 @@
* the documentation/chipset releases. An on-line errata would be welcome.
*
* TODO:
- * - syncppp oopses. X25 untested.
+ * - test X25.
* - use polling at high irq/s,
* - performance analysis,
* - endianness.
@@ -91,6 +91,7 @@
#include <linux/module.h>
#include <linux/types.h>
#include <linux/errno.h>
+#include <linux/list.h>
#include <linux/ioport.h>
#include <linux/pci.h>
#include <linux/kernel.h>
@@ -114,7 +115,7 @@
#include <linux/hdlc.h>
/* Version */
-static const char version[] = "$Id: dscc4.c,v 1.157 2002/01/28 01:54:19 romieu Exp $\n";
+static const char version[] = "$Id: dscc4.c,v 1.158 2002/01/30 00:40:37 romieu Exp $\n";
static int debug;
static int quartz;
@@ -168,9 +169,9 @@ struct RxFD {
#define BRR_DIVIDER_MAX 64*0x00008000
#define dev_per_card 4
-#define SOURCE_ID(flags) ((flags >> 28 ) & 0x03)
-#define TO_SIZE(state) ((state >> 16) & 0x1fff)
-#define TO_STATE(len) cpu_to_le32((len & TxSizeMax) << 16)
+#define SOURCE_ID(flags) (((flags) >> 28 ) & 0x03)
+#define TO_SIZE(state) (((state) >> 16) & 0x1fff)
+#define TO_STATE(len) cpu_to_le32(((len) & TxSizeMax) << 16)
#define RX_MAX(len) ((((len) >> 5) + 1)<< 5)
#define SCC_REG_START(id) SCC_START+(id)*SCC_OFFSET
@@ -343,6 +344,11 @@ static inline int dscc4_set_quartz(struct dscc4_dev_priv *, int);
static int dscc4_tx_poll(struct dscc4_dev_priv *, struct net_device *);
#endif
+static inline struct dscc4_dev_priv *dscc4_priv(struct net_device *dev)
+{
+ return list_entry(dev, struct dscc4_dev_priv, hdlc.netdev);
+}
+
static inline void dscc4_patch_register(u32 ioaddr, u32 mask, u32 value)
{
u32 state;
@@ -479,52 +485,49 @@ static int dscc4_do_action(struct net_device *dev, char *msg)
static inline int dscc4_xpr_ack(struct dscc4_dev_priv *dpriv)
{
- int cur, ret = 0;
- s16 i;
+ int cur = dpriv->iqtx_current%IRQ_RING_SIZE;
+ s16 i = 0;
- cur = dpriv->iqtx_current%IRQ_RING_SIZE;
- for (i = 0; i >= 0; i++) {
+ do {
if (!(dpriv->flags & (NeedIDR | NeedIDT)) ||
(dpriv->iqtx[cur] & Xpr))
break;
smp_rmb();
- }
- if (i < 0) {
- printk(KERN_ERR "%s: %s timeout\n", "dscc4", "XPR");
- ret = -1;
- }
- return ret;
+ } while (i++ >= 0);
+
+ return i;
}
static inline void dscc4_rx_skb(struct dscc4_dev_priv *dpriv, int cur,
struct RxFD *rx_fd, struct net_device *dev)
{
+ struct net_device_stats *stats = &dev_to_hdlc(dev)->stats;
struct pci_dev *pdev = dpriv->pci_priv->pdev;
struct sk_buff *skb;
int pkt_len;
skb = dpriv->rx_skbuff[cur];
- pkt_len = TO_SIZE(rx_fd->state2) - 1;
- pci_dma_sync_single(pdev, rx_fd->data, pkt_len + 1, PCI_DMA_FROMDEVICE);
- if((skb->data[pkt_len] & FrameOk) == FrameOk) {
+ pkt_len = TO_SIZE(rx_fd->state2);
+ pci_dma_sync_single(pdev, rx_fd->data, pkt_len, PCI_DMA_FROMDEVICE);
+ if((skb->data[--pkt_len] & FrameOk) == FrameOk) {
pci_unmap_single(pdev, rx_fd->data, skb->len, PCI_DMA_FROMDEVICE);
- dev_to_hdlc(dev)->stats.rx_packets++;
- dev_to_hdlc(dev)->stats.rx_bytes += pkt_len;
+ stats->rx_packets++;
+ stats->rx_bytes += pkt_len;
skb->tail += pkt_len;
skb->len = pkt_len;
- if (netif_running(hdlc_to_dev(&dpriv->hdlc)))
+ if (netif_running(dev))
skb->protocol = htons(ETH_P_HDLC);
netif_rx(skb);
try_get_rx_skb(dpriv, cur, dev);
} else {
if(skb->data[pkt_len] & FrameRdo)
- dev_to_hdlc(dev)->stats.rx_fifo_errors++;
+ stats->rx_fifo_errors++;
else if(!(skb->data[pkt_len] | ~FrameCrc))
- dev_to_hdlc(dev)->stats.rx_crc_errors++;
+ stats->rx_crc_errors++;
else if(!(skb->data[pkt_len] | ~(FrameVfr | FrameRab)))
- dev_to_hdlc(dev)->stats.rx_length_errors++;
+ stats->rx_length_errors++;
else
- dev_to_hdlc(dev)->stats.rx_errors++;
+ stats->rx_errors++;
}
rx_fd->state1 |= Hold;
rx_fd->state2 = 0x00000000;
@@ -612,7 +615,7 @@ static int __init dscc4_init_one (struct pci_dev *pdev,
* SCC 0-3 private rx/tx irq structures
* IQRX/TXi needs to be set soon. Learned it the hard way...
*/
- for(i = 0; i < dev_per_card; i++) {
+ for (i = 0; i < dev_per_card; i++) {
dpriv = priv->root + i;
dpriv->iqtx = (u32 *) pci_alloc_consistent(pdev,
IRQ_RING_SIZE*sizeof(u32), &dpriv->iqtx_dma);
@@ -620,7 +623,7 @@ static int __init dscc4_init_one (struct pci_dev *pdev,
goto err_out_free_iqtx;
writel(dpriv->iqtx_dma, ioaddr + IQTX0 + i*4);
}
- for(i = 0; i < dev_per_card; i++) {
+ for (i = 0; i < dev_per_card; i++) {
dpriv = priv->root + i;
dpriv->iqrx = (u32 *) pci_alloc_consistent(pdev,
IRQ_RING_SIZE*sizeof(u32), &dpriv->iqrx_dma);
@@ -740,7 +743,6 @@ static int dscc4_found1(struct pci_dev *pdev, unsigned long ioaddr)
dpriv->dev_id = i;
dpriv->pci_priv = ppriv;
spin_lock_init(&dpriv->lock);
- d->priv = dpriv;
hdlc->xmit = dscc4_start_xmit;
hdlc->attach = dscc4_hdlc_attach;
@@ -778,7 +780,7 @@ static void dscc4_timer(unsigned long data)
struct dscc4_dev_priv *dpriv;
struct dscc4_pci_priv *ppriv;
- dpriv = dev->priv;
+ dpriv = dscc4_priv(dev);
if (netif_queue_stopped(dev) &&
((jiffies - dev->trans_start) > TX_TIMEOUT)) {
ppriv = dpriv->pci_priv;
@@ -844,7 +846,7 @@ static int dscc4_loopback_check(struct dscc4_dev_priv *dpriv)
static int dscc4_open(struct net_device *dev)
{
- struct dscc4_dev_priv *dpriv = dev->priv;
+ struct dscc4_dev_priv *dpriv = dscc4_priv(dev);
hdlc_device *hdlc = &dpriv->hdlc;
struct dscc4_pci_priv *ppriv;
u32 ioaddr;
@@ -893,8 +895,10 @@ static int dscc4_open(struct net_device *dev)
* WARNING, a really missing XPR usually means a hardware
* reset is needed. Suggestions anyone ?
*/
- if (dscc4_xpr_ack(dpriv))
+ if (dscc4_xpr_ack(dpriv) < 0) {
+ printk(KERN_ERR "%s: %s timeout\n", DRV_NAME, "XPR");
goto err_free_ring;
+ }
netif_start_queue(dev);
@@ -925,7 +929,7 @@ static int dscc4_tx_poll(struct dscc4_dev_priv *dpriv, struct net_device *dev)
static int dscc4_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
- struct dscc4_dev_priv *dpriv = dev->priv;
+ struct dscc4_dev_priv *dpriv = dscc4_priv(dev);
struct dscc4_pci_priv *ppriv;
struct TxFD *tx_fd;
int cur, next;
@@ -935,7 +939,6 @@ static int dscc4_start_xmit(struct sk_buff *skb, struct net_device *dev)
next = dpriv->tx_current%TX_RING_SIZE;
dpriv->tx_skbuff[next] = skb;
tx_fd = dpriv->tx_fd + next;
- printk(KERN_DEBUG "%s: %d sent\n", dev->name, skb->len);
tx_fd->state = FrameEnd | Hold | TO_STATE(skb->len);
tx_fd->data = pci_map_single(ppriv->pdev, skb->data, skb->len,
PCI_DMA_TODEVICE);
@@ -972,7 +975,7 @@ static int dscc4_start_xmit(struct sk_buff *skb, struct net_device *dev)
static int dscc4_close(struct net_device *dev)
{
- struct dscc4_dev_priv *dpriv = (struct dscc4_dev_priv *)dev->priv;
+ struct dscc4_dev_priv *dpriv = dscc4_priv(dev);
u32 ioaddr = dev->base_addr;
int dev_id;
hdlc_device *hdlc = dev_to_hdlc(dev);
@@ -1011,7 +1014,7 @@ static inline int dscc4_check_clock_ability(int port)
static int dscc4_set_clock(struct net_device *dev, u32 *bps, u32 *state)
{
- struct dscc4_dev_priv *dpriv = (struct dscc4_dev_priv *)dev->priv;
+ struct dscc4_dev_priv *dpriv = dscc4_priv(dev);
u32 brr;
*state &= ~Ccr0ClockMask;
@@ -1062,37 +1065,29 @@ static int dscc4_set_clock(struct net_device *dev, u32 *bps, u32 *state)
static int dscc4_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
- struct dscc4_dev_priv *dpriv = dev->priv;
- struct if_settings *if_s = &ifr->ifr_settings;
+ union line_settings *line = &ifr->ifr_settings->ifs_line;
+ struct dscc4_dev_priv *dpriv = dscc4_priv(dev);
const size_t size = sizeof(dpriv->settings);
int ret = 0;
if (dev->flags & IFF_UP)
return -EBUSY;
- if (cmd != SIOCDEVICE)
+ if (cmd != SIOCWANDEV)
return -EOPNOTSUPP;
- switch(ifr->ifr_settings.type) {
+ switch(ifr->ifr_settings->type) {
case IF_GET_IFACE:
- if_s->type = IF_IFACE_SYNC_SERIAL;
- if (if_s->data_length == 0)
- return 0;
- if (if_s->data_length < size)
- return -ENOMEM;
- if (copy_to_user(if_s->data, &dpriv->settings, size))
+ ifr->ifr_settings->type = IF_IFACE_SYNC_SERIAL;
+ if (copy_to_user(&line->sync, &dpriv->settings, size))
return -EFAULT;
- if_s->data_length = size;
break;
case IF_IFACE_SYNC_SERIAL:
if(!capable(CAP_NET_ADMIN))
return -EPERM;
- if (if_s->data_length != size)
- return -ENOMEM;
-
- if (copy_from_user(&dpriv->settings, if_s->data, size))
+ if (copy_from_user(&dpriv->settings, &line->sync, size))
return -EFAULT;
ret = dscc4_set_iface(dev);
break;
@@ -1133,7 +1128,7 @@ static int dscc4_match(struct thingie *p, int value)
static int dscc4_clock_setting(struct net_device *dev)
{
- struct dscc4_dev_priv *dpriv = dev->priv;
+ struct dscc4_dev_priv *dpriv = dscc4_priv(dev);
sync_serial_settings *settings = &dpriv->settings;
u32 bps, state;
u32 ioaddr;
@@ -1160,7 +1155,7 @@ static int dscc4_clock_setting(struct net_device *dev)
static int dscc4_encoding_setting(struct net_device *dev)
{
- struct dscc4_dev_priv *dpriv = dev->priv;
+ struct dscc4_dev_priv *dpriv = dscc4_priv(dev);
struct thingie encoding[] = {
{ ENCODING_NRZ, 0x00000000 },
{ ENCODING_NRZI, 0x00200000 },
@@ -1184,7 +1179,7 @@ static int dscc4_encoding_setting(struct net_device *dev)
static int dscc4_loopback_setting(struct net_device *dev)
{
- struct dscc4_dev_priv *dpriv = dev->priv;
+ struct dscc4_dev_priv *dpriv = dscc4_priv(dev);
sync_serial_settings *settings = &dpriv->settings;
u32 ioaddr, state;
@@ -1203,7 +1198,7 @@ static int dscc4_loopback_setting(struct net_device *dev)
static int dscc4_crc_setting(struct net_device *dev)
{
- struct dscc4_dev_priv *dpriv = dev->priv;
+ struct dscc4_dev_priv *dpriv = dscc4_priv(dev);
struct thingie crc[] = {
{ PARITY_CRC16_PR0_CCITT, 0x00000010 },
{ PARITY_CRC16_PR1_CCITT, 0x00000000 },
@@ -1516,7 +1511,6 @@ try:
}
} else { /* ! SccEvt */
#ifdef DEBUG_PARANOIA
- int i;
static struct {
u32 mask;
const char *irq_name;
@@ -1528,21 +1522,21 @@ try:
{ 0x00000008, "PLLA"},
{ 0x00000004, "CDSC"},
{ 0, NULL}
- };
+ }, *evt;
#endif /* DEBUG_PARANOIA */
state &= 0x00ffffff;
#ifdef DEBUG_PARANOIA
- for (i = 0; evts[i].irq_name; i++) {
- if (state & evts[i].mask) {
+ for (evt = evts; evt->irq_name; evt++) {
+ if (state & evt->mask) {
printk(KERN_DEBUG "%s: %s\n", dev->name,
- evts[i].irq_name);
- if (!(state &= ~evts[i].mask))
+ evt->irq_name);
+ if (!(state &= ~evt->mask))
goto try;
}
}
#endif /* DEBUG_PARANOIA */
/*
- * Receive Data Overflow (FIXME: untested)
+ * Receive Data Overflow (FIXME: fscked)
*/
if (state & Rdo) {
u32 ioaddr, scc_offset, scc_addr;
@@ -1633,7 +1627,7 @@ try:
static int dscc4_init_ring(struct net_device *dev)
{
- struct dscc4_dev_priv *dpriv = (struct dscc4_dev_priv *)dev->priv;
+ struct dscc4_dev_priv *dpriv = dscc4_priv(dev);
struct TxFD *tx_fd;
struct RxFD *rx_fd;
int i;
@@ -1654,7 +1648,7 @@ static int dscc4_init_ring(struct net_device *dev)
dpriv->tx_dirty = 0;
/* the dma core of the dscc4 will be locked on the first desc */
- for(i = 0; i < TX_RING_SIZE; ) {
+ for (i = 0; i < TX_RING_SIZE; ) {
reset_TxFD(tx_fd);
/* FIXME: NULL should be ok - to be tried */
tx_fd->data = dpriv->tx_fd_dma;
@@ -1689,7 +1683,7 @@ static int dscc4_init_ring(struct net_device *dev)
skb->len, PCI_DMA_TODEVICE);
dpriv->tx_skbuff[0] = skb;
}
- for (i = 0; i < RX_RING_SIZE;) {
+ for (i = 0; i < RX_RING_SIZE; ) {
/* size set by the host. Multiple of 4 bytes please */
rx_fd->state1 = HiDesc; /* Hi, no Hold */
rx_fd->state2 = 0x00000000;
@@ -1753,7 +1747,8 @@ static void __exit dscc4_remove_one(struct pci_dev *pdev)
static int dscc4_hdlc_attach(hdlc_device *hdlc, unsigned short encoding,
unsigned short parity)
{
- struct dscc4_dev_priv *dpriv = hdlc_to_dev(hdlc)->priv;
+ struct net_device *dev = hdlc_to_dev(hdlc);
+ struct dscc4_dev_priv *dpriv = dscc4_priv(dev);
if (encoding != ENCODING_NRZ &&
encoding != ENCODING_NRZI &&
@@ -1782,7 +1777,7 @@ static struct pci_device_id dscc4_pci_tbl[] __devinitdata = {
MODULE_DEVICE_TABLE(pci, dscc4_pci_tbl);
static struct pci_driver dscc4_driver = {
- name: "dscc4",
+ name: DRV_NAME,
id_table: dscc4_pci_tbl,
probe: dscc4_init_one,
remove: dscc4_remove_one,
diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c
index 64258f647ce4..f6be495fbb6c 100644
--- a/drivers/net/wan/farsync.c
+++ b/drivers/net/wan/farsync.c
@@ -1,5 +1,5 @@
/*
- * FarSync X21 driver for Linux (2.4.x kernel version)
+ * FarSync X21 driver for Linux (generic HDLC version)
*
* Actually sync driver for X.21, V.35 and V.24 on FarSync T-series cards
*
@@ -18,11 +18,10 @@
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/ioport.h>
-#include <linux/netdevice.h>
#include <linux/init.h>
-#include <linux/if_arp.h>
#include <asm/uaccess.h>
-#include <net/syncppp.h>
+#include <linux/if.h>
+#include <linux/hdlc.h>
#include "farsync.h"
@@ -32,6 +31,7 @@
*/
MODULE_AUTHOR("R.J.Dunlop <bob.dunlop@farsite.co.uk>");
MODULE_DESCRIPTION("FarSync T-Series X21 driver. FarSite Communications Ltd.");
+MODULE_LICENSE("GPL");
EXPORT_NO_SYMBOLS;
@@ -331,26 +331,15 @@ struct buf_window {
/* Per port (line or channel) information
*/
struct fst_port_info {
- void *if_ptr; /* Some drivers describe this as a
- * general purpose pointer. However if
- * using syncPPP it has a very specific
- * purpose: it must be the first item in
- * the structure pointed to by dev->priv
- * and must in turn point to the
- * associated ppp_device structure.
- */
+ hdlc_device hdlc; /* HDLC device struct - must be first */
struct fst_card_info *card; /* Card we're associated with */
int index; /* Port index on the card */
- int proto; /* Protocol we are running */
int hwif; /* Line hardware (lineInterface copy) */
int run; /* Port is running */
int rxpos; /* Next Rx buffer to use */
int txpos; /* Next Tx buffer to use */
int txipos; /* Next Tx buffer to check for free */
int txcnt; /* Count of Tx buffers in use */
- struct net_device *dev; /* Kernel network device entry */
- struct net_device_stats stats; /* Standard statistics */
- struct ppp_device pppdev; /* Link to syncPPP */
};
/* Per card information
@@ -370,6 +359,11 @@ struct fst_card_info {
struct fst_port_info ports[ FST_MAX_PORTS ];
};
+/* Convert an HDLC device pointer into a port info pointer and similar */
+#define hdlc_to_port(H) ((struct fst_port_info *)(H))
+#define dev_to_port(D) hdlc_to_port(dev_to_hdlc(D))
+#define port_to_dev(P) hdlc_to_dev(&(P)->hdlc)
+
/*
* Shared memory window access macros
@@ -632,25 +626,18 @@ fst_intr_ctlchg ( struct fst_card_info *card, struct fst_port_info *port )
if ( signals & (( port->hwif == X21 ) ? IPSTS_INDICATE : IPSTS_DCD ))
{
- if ( ! netif_carrier_ok ( port->dev ))
+ if ( ! netif_carrier_ok ( port_to_dev ( port )))
{
dbg ( DBG_INTR,"DCD active\n");
-
- /* Poke sPPP to renegotiate */
- if ( port->proto == FST_HDLC || port->proto == FST_PPP )
- {
- sppp_reopen ( port->dev );
- }
-
- netif_carrier_on ( port->dev );
+ netif_carrier_on ( port_to_dev ( port ));
}
}
else
{
- if ( netif_carrier_ok ( port->dev ))
+ if ( netif_carrier_ok ( port_to_dev ( port )))
{
dbg ( DBG_INTR,"DCD lost\n");
- netif_carrier_off ( port->dev );
+ netif_carrier_off ( port_to_dev ( port ));
}
}
}
@@ -693,24 +680,24 @@ fst_intr_rx ( struct fst_card_info *card, struct fst_port_info *port )
len );
if ( dmabits != ( RX_STP | RX_ENP ) || len > LEN_RX_BUFFER - 2 )
{
- port->stats.rx_errors++;
+ port->hdlc.stats.rx_errors++;
/* Update error stats and discard buffer */
if ( dmabits & RX_OFLO )
{
- port->stats.rx_fifo_errors++;
+ port->hdlc.stats.rx_fifo_errors++;
}
if ( dmabits & RX_CRC )
{
- port->stats.rx_crc_errors++;
+ port->hdlc.stats.rx_crc_errors++;
}
if ( dmabits & RX_FRAM )
{
- port->stats.rx_frame_errors++;
+ port->hdlc.stats.rx_frame_errors++;
}
if ( dmabits == ( RX_STP | RX_ENP ))
{
- port->stats.rx_length_errors++;
+ port->hdlc.stats.rx_length_errors++;
}
/* Discard buffer descriptors until we see the end of packet
@@ -747,7 +734,7 @@ fst_intr_rx ( struct fst_card_info *card, struct fst_port_info *port )
{
dbg ( DBG_RX,"intr_rx: can't allocate buffer\n");
- port->stats.rx_dropped++;
+ port->hdlc.stats.rx_dropped++;
/* Return descriptor to card */
FST_WRB ( card, rxDescrRing[pi][rxp].bits, DMA_OWN );
@@ -771,29 +758,16 @@ fst_intr_rx ( struct fst_card_info *card, struct fst_port_info *port )
port->rxpos = rxp;
/* Update stats */
- port->stats.rx_packets++;
- port->stats.rx_bytes += len;
+ port->hdlc.stats.rx_packets++;
+ port->hdlc.stats.rx_bytes += len;
/* Push upstream */
- if ( port->proto == FST_HDLC || port->proto == FST_PPP )
- {
- /* Mark for further processing by sPPP module */
- skb->protocol = htons ( ETH_P_WAN_PPP );
- }
- else
- {
- /* DEC customer specific protocol (since nothing defined for
- * marking raw data), at least one other driver uses this value
- * for this purpose.
- */
- skb->protocol = htons ( ETH_P_CUST );
- skb->pkt_type = PACKET_HOST;
- }
skb->mac.raw = skb->data;
- skb->dev = port->dev;
+ skb->dev = hdlc_to_dev ( &port->hdlc );
+ skb->protocol = htons ( ETH_P_HDLC );
netif_rx ( skb );
- port->dev->last_rx = jiffies;
+ port_to_dev ( port )->last_rx = jiffies;
}
@@ -844,7 +818,7 @@ fst_intr ( int irq, void *dev_id, struct pt_regs *regs )
case CTLB_CHG:
case CTLC_CHG:
case CTLD_CHG:
- if ( port->run && port->dev != NULL )
+ if ( port->run )
fst_intr_ctlchg ( card, port );
break;
@@ -863,9 +837,8 @@ fst_intr ( int irq, void *dev_id, struct pt_regs *regs )
* always load up the entire packet for DMA.
*/
dbg ( DBG_TX,"Tx underflow port %d\n", event & 0x03 );
-
- port->stats.tx_errors++;
- port->stats.tx_fifo_errors++;
+ port->hdlc.stats.tx_errors++;
+ port->hdlc.stats.tx_fifo_errors++;
break;
case INIT_CPLT:
@@ -890,7 +863,7 @@ fst_intr ( int irq, void *dev_id, struct pt_regs *regs )
for ( pi = 0, port = card->ports ; pi < card->nports ; pi++, port++ )
{
- if ( port->dev == NULL || ! port->run )
+ if ( ! port->run )
continue;
/* Check for rx completions */
@@ -907,7 +880,7 @@ fst_intr ( int irq, void *dev_id, struct pt_regs *regs )
--port->txcnt;
if ( ++port->txipos >= NUM_TX_BUFFER )
port->txipos = 0;
- netif_wake_queue ( port->dev );
+ netif_wake_queue ( port_to_dev ( port ));
}
}
@@ -969,145 +942,28 @@ check_started_ok ( struct fst_card_info *card )
static int
-fst_change_mtu ( struct net_device *dev, int new_mtu )
-{
- if ( new_mtu < 128 || new_mtu > FST_MAX_MTU )
- return -EINVAL;
- dev->mtu = new_mtu;
- return 0;
-}
-
-
-/* Sooner or later you can't avoid a forward declaration */
-static int fst_ioctl ( struct net_device *dev, struct ifreq *ifr, int cmd );
-
-static int
-switch_proto ( struct fst_port_info *port, int new_proto )
-{
- int err;
- int orig_mtu;
- struct net_device *dev;
-
- dev = port->dev;
-
- /* Turn off sPPP module ? */
- if (( new_proto != FST_HDLC && new_proto != FST_PPP )
- && ( port->proto == FST_HDLC || port->proto == FST_PPP ))
- {
- sppp_close ( port->pppdev.dev );
- sppp_detach ( port->pppdev.dev );
-
- /* Reset some fields overwritten by sPPP */
- dev->hard_header = NULL;
- dev->rebuild_header = NULL;
- dev->tx_queue_len = FST_TX_QUEUE_LEN;
- dev->type = ARPHRD_MYTYPE;
- dev->addr_len = 0;
- dev->hard_header_len = 0;
- dev->do_ioctl = fst_ioctl;
- dev->change_mtu = fst_change_mtu;
- dev->flags = IFF_POINTOPOINT|IFF_NOARP;
-
- return 0;
- }
-
- /* Turn on sPPP ? */
- if (( new_proto == FST_HDLC || new_proto == FST_PPP )
- && ( port->proto != FST_HDLC && port->proto != FST_PPP ))
- {
- orig_mtu = dev->mtu;
-
- /* Attach to sync PPP module */
- port->pppdev.dev = dev;
- sppp_attach ( &port->pppdev );
-
- if ( orig_mtu < dev->mtu )
- dev->change_mtu ( dev, orig_mtu );
-
- /* Claw back the ioctl routine. We promise to be good and call
- * the sync PPP routines once we've eliminated our functions.
- */
- dev->do_ioctl = fst_ioctl;
-
- /* Set the mode */
- if ( new_proto == FST_HDLC )
- {
- err = sppp_do_ioctl ( port->pppdev.dev, NULL,
- SPPPIOCCISCO );
- }
- else
- {
- err = sppp_do_ioctl ( port->pppdev.dev, NULL,
- SPPPIOCPPP );
- }
-
- /* Open the device */
- if ( err == 0 )
- {
- (void) sppp_open ( port->dev );
- }
-
- return err;
- }
-
- /* Switch sPPP mode to that desired */
- err = 0;
- if ( new_proto == FST_HDLC && port->pppdev.dev != NULL )
- {
- err = sppp_do_ioctl ( port->pppdev.dev, NULL, SPPPIOCCISCO );
- }
- else if ( new_proto == FST_PPP && port->pppdev.dev != NULL )
- {
- err = sppp_do_ioctl ( port->pppdev.dev, NULL, SPPPIOCPPP );
- }
-
- /* Anything else is switching from one raw mode to another which is
- * basically a NOP
- */
-
- return err;
-}
-
-
-static int
set_conf_from_info ( struct fst_card_info *card, struct fst_port_info *port,
struct fstioc_info *info )
{
int err;
- /* Set things according to the user set valid flags */
+ /* Set things according to the user set valid flags.
+ * Several of the old options have been invalidated/replaced by the
+ * generic HDLC package.
+ */
err = 0;
if ( info->valid & FSTVAL_PROTO )
- {
- if ( port->proto != info->proto )
- {
- err = switch_proto ( port, info->proto );
- if ( err == 0 )
- port->proto = info->proto;
- }
- }
+ err = -EINVAL;
if ( info->valid & FSTVAL_CABLE )
- {
- FST_WRB ( card, portConfig[port->index].lineInterface,
- info->lineInterface );
- port->hwif = info->lineInterface;
- }
+ err = -EINVAL;
if ( info->valid & FSTVAL_SPEED )
- {
- FST_WRL ( card, portConfig[port->index].lineSpeed,
- info->lineSpeed );
- FST_WRB ( card, portConfig[port->index].internalClock,
- info->internalClock );
- }
+ err = -EINVAL;
+
if ( info->valid & FSTVAL_MODE )
- {
FST_WRW ( card, cardMode, info->cardMode );
- }
#if FST_DEBUG
if ( info->valid & FSTVAL_DEBUG )
- {
fst_debug_mask = info->debug;
- }
#endif
return err;
@@ -1125,7 +981,7 @@ gather_conf_info ( struct fst_card_info *card, struct fst_port_info *port,
info->nports = card->nports;
info->type = card->type;
info->state = card->state;
- info->proto = port->proto;
+ info->proto = FST_GEN_HDLC;
info->index = i;
#if FST_DEBUG
info->debug = fst_debug_mask;
@@ -1154,6 +1010,102 @@ gather_conf_info ( struct fst_card_info *card, struct fst_port_info *port,
static int
+fst_set_iface ( struct fst_card_info *card, struct fst_port_info *port,
+ struct ifreq *ifr )
+{
+ union line_settings *line = &ifr->ifr_settings->ifs_line;
+ sync_serial_settings sync;
+ int i;
+
+ if ( copy_from_user ( &sync, &line->sync, sizeof ( sync )))
+ return -EFAULT;
+
+ if ( sync.loopback )
+ return -EINVAL;
+
+ i = port->index;
+
+ switch ( ifr->ifr_settings->type )
+ {
+ case IF_IFACE_V35:
+ FST_WRW ( card, portConfig[i].lineInterface, V35 );
+ port->hwif = V35;
+ break;
+
+ case IF_IFACE_V24:
+ FST_WRW ( card, portConfig[i].lineInterface, V24 );
+ port->hwif = V24;
+ break;
+
+ case IF_IFACE_X21:
+ FST_WRW ( card, portConfig[i].lineInterface, X21 );
+ port->hwif = X21;
+ break;
+
+ case IF_IFACE_SYNC_SERIAL:
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ switch ( sync.clock_type )
+ {
+ case CLOCK_EXT:
+ FST_WRB ( card, portConfig[i].internalClock, EXTCLK );
+ break;
+
+ case CLOCK_INT:
+ FST_WRB ( card, portConfig[i].internalClock, INTCLK );
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ FST_WRL ( card, portConfig[i].lineSpeed, sync.clock_rate );
+ return 0;
+}
+
+static int
+fst_get_iface ( struct fst_card_info *card, struct fst_port_info *port,
+ struct ifreq *ifr )
+{
+ union line_settings *line = &ifr->ifr_settings->ifs_line;
+ sync_serial_settings sync;
+ int i;
+
+ /* First check what line type is set, we'll default to reporting X.21
+ * if nothing is set as IF_IFACE_SYNC_SERIAL implies it can't be
+ * changed
+ */
+ switch ( port->hwif )
+ {
+ case V35:
+ ifr->ifr_settings->type = IF_IFACE_V35;
+ break;
+ case V24:
+ ifr->ifr_settings->type = IF_IFACE_V24;
+ break;
+ case X21:
+ default:
+ ifr->ifr_settings->type = IF_IFACE_X21;
+ break;
+ }
+
+ i = port->index;
+ sync.clock_rate = FST_RDL ( card, portConfig[i].lineSpeed );
+ /* Lucky card and linux use same encoding here */
+ sync.clock_type = FST_RDB ( card, portConfig[i].internalClock );
+ sync.loopback = 0;
+
+ if ( copy_to_user (&line->sync, &sync, sizeof ( sync )))
+ return -EFAULT;
+
+ return 0;
+}
+
+
+static int
fst_ioctl ( struct net_device *dev, struct ifreq *ifr, int cmd )
{
struct fst_card_info *card;
@@ -1164,7 +1116,7 @@ fst_ioctl ( struct net_device *dev, struct ifreq *ifr, int cmd )
dbg ( DBG_IOCTL,"ioctl: %x, %p\n", cmd, ifr->ifr_data );
- port = dev->priv;
+ port = dev_to_port ( dev );
card = port->card;
if ( !capable ( CAP_NET_ADMIN ))
@@ -1201,7 +1153,7 @@ fst_ioctl ( struct net_device *dev, struct ifreq *ifr, int cmd )
* when going over the top
*/
if ( wrthdr.size > FST_MEMSIZE || wrthdr.offset > FST_MEMSIZE
- || wrthdr.size + wrthdr.offset > FST_MEMSIZE )
+ || wrthdr.size + wrthdr.offset > FST_MEMSIZE )
{
return -ENXIO;
}
@@ -1261,6 +1213,9 @@ fst_ioctl ( struct net_device *dev, struct ifreq *ifr, int cmd )
case FSTSETCONF:
+ /* Most of the setting have been moved to the generic ioctls
+ * this just covers debug and board ident mode now
+ */
if ( copy_from_user ( &info, ifr->ifr_data, sizeof ( info )))
{
return -EFAULT;
@@ -1268,12 +1223,25 @@ fst_ioctl ( struct net_device *dev, struct ifreq *ifr, int cmd )
return set_conf_from_info ( card, port, &info );
+ case SIOCWANDEV:
+ switch ( ifr->ifr_settings->type )
+ {
+ case IF_GET_IFACE:
+ return fst_get_iface ( card, port, ifr );
+
+ case IF_IFACE_SYNC_SERIAL:
+ case IF_IFACE_V35:
+ case IF_IFACE_V24:
+ case IF_IFACE_X21:
+ return fst_set_iface ( card, port, ifr );
+
+ default:
+ return hdlc_ioctl ( dev, ifr, cmd );
+ }
+
default:
- /* Not one of ours. Pass it through to sPPP package */
- if ( port->proto == FST_HDLC || port->proto == FST_PPP )
- return sppp_do_ioctl ( dev, ifr, cmd );
- else
- return -EINVAL;
+ /* Not one of ours. Pass through to HDLC package */
+ return hdlc_ioctl ( dev, ifr, cmd );
}
}
@@ -1306,9 +1274,9 @@ fst_openport ( struct fst_port_info *port )
signals = FST_RDL ( port->card, v24DebouncedSts[port->index]);
if ( signals & (( port->hwif == X21 ) ? IPSTS_INDICATE
: IPSTS_DCD ))
- netif_carrier_on ( port->dev );
+ netif_carrier_on ( port_to_dev ( port ));
else
- netif_carrier_off ( port->dev );
+ netif_carrier_off ( port_to_dev ( port ));
}
}
@@ -1335,64 +1303,15 @@ fst_closeport ( struct fst_port_info *port )
static int
fst_open ( struct net_device *dev )
{
- struct fst_card_info *card;
- struct fst_port_info *port;
- int orig_mtu;
int err;
- MOD_INC_USE_COUNT;
-
- port = dev->priv;
- card = port->card;
-
- switch ( port->proto )
- {
- case FST_HDLC:
- case FST_PPP:
-
- orig_mtu = dev->mtu;
-
- /* Attach to sync PPP module */
- port->pppdev.dev = dev;
- sppp_attach ( &port->pppdev );
-
- if ( orig_mtu < dev->mtu )
- dev->change_mtu ( dev, orig_mtu );
-
- /* Claw back the ioctl routine. We promise to be good and call
- * the sync PPP routines once we've eliminated our functions.
- */
- dev->do_ioctl = fst_ioctl;
-
- err = sppp_do_ioctl ( dev, NULL, port->proto == FST_HDLC
- ? SPPPIOCCISCO : SPPPIOCPPP );
- if ( err )
- {
- sppp_detach ( dev );
- MOD_DEC_USE_COUNT;
- return err;
- }
-
- err = sppp_open ( dev );
- if ( err )
- {
- sppp_detach ( dev );
- MOD_DEC_USE_COUNT;
- return err;
- }
- break;
-
- case FST_MONITOR:
- case FST_RAW:
- break;
-
- default:
- dbg ( DBG_OPEN,"open: Unknown proto %d\n", port->proto );
- break;
- }
+ err = hdlc_open ( dev_to_hdlc ( dev ));
+ if ( err )
+ return err;
- fst_openport ( port );
+ MOD_INC_USE_COUNT;
+ fst_openport ( dev_to_port ( dev ));
netif_wake_queue ( dev );
return 0;
}
@@ -1400,34 +1319,22 @@ fst_open ( struct net_device *dev )
static int
fst_close ( struct net_device *dev )
{
- struct fst_port_info *port;
-
- port = dev->priv;
-
netif_stop_queue ( dev );
- switch ( port->proto )
- {
- case FST_HDLC:
- case FST_PPP:
- sppp_close ( dev );
- sppp_detach ( dev );
- break;
-
- case FST_MONITOR:
- case FST_RAW:
- break;
-
- default:
- dbg ( DBG_OPEN,"close: Unknown proto %d\n", port->proto );
- break;
- }
-
- fst_closeport ( port );
-
+ fst_closeport ( dev_to_port ( dev ));
+ hdlc_close ( dev_to_hdlc ( dev ));
MOD_DEC_USE_COUNT;
return 0;
}
+static int
+fst_attach ( hdlc_device *hdlc, unsigned short encoding, unsigned short parity )
+{
+ /* Setting currently fixed in FarSync card so we check and forget */
+ if ( encoding != ENCODING_NRZ || parity != PARITY_CRC16_PR1_CCITT )
+ return -EINVAL;
+ return 0;
+}
+
static void
fst_tx_timeout ( struct net_device *dev )
@@ -1436,10 +1343,10 @@ fst_tx_timeout ( struct net_device *dev )
dbg ( DBG_INTR | DBG_TX,"tx_timeout\n");
- port = dev->priv;
+ port = dev_to_port ( dev );
- port->stats.tx_errors++;
- port->stats.tx_aborted_errors++;
+ port->hdlc.stats.tx_errors++;
+ port->hdlc.stats.tx_aborted_errors++;
if ( port->txcnt > 0 )
fst_issue_cmd ( port, ABORTTX );
@@ -1459,22 +1366,15 @@ fst_start_xmit ( struct sk_buff *skb, struct net_device *dev )
int pi;
int txp;
- port = dev->priv;
+ port = dev_to_port ( dev );
card = port->card;
- /* Drop packet if in monitor (rx only) mode */
- if ( port->proto == FST_MONITOR )
- {
- dev_kfree_skb ( skb );
- return 0;
- }
-
/* Drop packet with error if we don't have carrier */
if ( ! netif_carrier_ok ( dev ))
{
dev_kfree_skb ( skb );
- port->stats.tx_errors++;
- port->stats.tx_carrier_errors++;
+ port->hdlc.stats.tx_errors++;
+ port->hdlc.stats.tx_carrier_errors++;
return 0;
}
@@ -1484,7 +1384,7 @@ fst_start_xmit ( struct sk_buff *skb, struct net_device *dev )
dbg ( DBG_TX,"Packet too large %d vs %d\n", skb->len,
LEN_TX_BUFFER );
dev_kfree_skb ( skb );
- port->stats.tx_errors++;
+ port->hdlc.stats.tx_errors++;
return 0;
}
@@ -1498,7 +1398,7 @@ fst_start_xmit ( struct sk_buff *skb, struct net_device *dev )
spin_unlock_irqrestore ( &card->card_lock, flags );
dbg ( DBG_TX,"Out of Tx buffers\n");
dev_kfree_skb ( skb );
- port->stats.tx_errors++;
+ port->hdlc.stats.tx_errors++;
return 0;
}
if ( ++port->txpos >= NUM_TX_BUFFER )
@@ -1518,8 +1418,8 @@ fst_start_xmit ( struct sk_buff *skb, struct net_device *dev )
FST_WRW ( card, txDescrRing[pi][txp].bcnt, cnv_bcnt ( skb->len ));
FST_WRB ( card, txDescrRing[pi][txp].bits, DMA_OWN | TX_STP | TX_ENP );
- port->stats.tx_packets++;
- port->stats.tx_bytes += skb->len;
+ port->hdlc.stats.tx_packets++;
+ port->hdlc.stats.tx_bytes += skb->len;
dev_kfree_skb ( skb );
@@ -1528,18 +1428,6 @@ fst_start_xmit ( struct sk_buff *skb, struct net_device *dev )
}
-static struct net_device_stats *
-fst_get_stats ( struct net_device *dev )
-{
- struct fst_port_info *port;
-
- if (( port = dev->priv ) != NULL )
- return &port->stats;
- else
- return NULL;
-}
-
-
/*
* Card setup having checked hardware resources.
* Should be pretty bizarre if we get an error here (kernel memory
@@ -1566,34 +1454,13 @@ fst_init_card ( struct fst_card_info *card )
*/
for ( i = 0 ; i < card->nports ; i++ )
{
- card->ports[i].if_ptr = &card->ports[i].pppdev;
card->ports[i].card = card;
card->ports[i].index = i;
- card->ports[i].proto = FST_HDLC;
card->ports[i].run = 0;
- dev = kmalloc ( sizeof ( struct net_device ), GFP_KERNEL );
- if ( dev == NULL )
- {
- printk_err ("Cannot allocate net_device for port %d\n",
- i );
- /* No point going any further */
- card->nports = i;
- break;
- }
- memset ( dev, 0, sizeof ( struct net_device ));
- card->ports[i].dev = dev;
-
- if ( dev_alloc_name ( dev, FST_NDEV_NAME "%d") < 0 )
- {
- printk_err ("Cannot allocate i/f name for port %d\n",
- i );
- kfree ( dev );
- card->nports = i;
- break;
- }
+ dev = hdlc_to_dev ( &card->ports[i].hdlc );
- /* Fill in remainder of the net device info */
+ /* Fill in the net device info */
/* Since this is a PCI setup this is purely
* informational. Give them the buffer addresses
* and basic card I/O.
@@ -1609,26 +1476,19 @@ fst_init_card ( struct fst_card_info *card )
dev->base_addr = card->pci_conf;
dev->irq = card->irq;
- dev->get_stats = fst_get_stats;
- dev->mtu = FST_DEF_MTU;
- dev->change_mtu = fst_change_mtu;
- dev->priv = &card->ports[i];
- dev->tx_queue_len = FST_TX_QUEUE_LEN;
- dev->type = ARPHRD_MYTYPE;
- dev->addr_len = 0;
- dev->open = fst_open;
- dev->stop = fst_close;
- dev->hard_start_xmit = fst_start_xmit;
- dev->do_ioctl = fst_ioctl;
- dev->watchdog_timeo = FST_TX_TIMEOUT;
- dev->tx_timeout = fst_tx_timeout;
- dev->flags = IFF_POINTOPOINT|IFF_NOARP;
-
- if (( err = register_netdev ( dev )) < 0 )
+ dev->tx_queue_len = FST_TX_QUEUE_LEN;
+ dev->open = fst_open;
+ dev->stop = fst_close;
+ dev->do_ioctl = fst_ioctl;
+ dev->watchdog_timeo = FST_TX_TIMEOUT;
+ dev->tx_timeout = fst_tx_timeout;
+ card->ports[i].hdlc.attach = fst_attach;
+ card->ports[i].hdlc.xmit = fst_start_xmit;
+
+ if (( err = register_hdlc_device ( &card->ports[i].hdlc )) < 0 )
{
- printk_err ("Cannot register %s (errno %d)\n",
- dev->name, -err );
- kfree ( dev );
+ printk_err ("Cannot register HDLC device for port %d"
+ " (errno %d)\n", i, -err );
card->nports = i;
break;
}
@@ -1637,8 +1497,8 @@ fst_init_card ( struct fst_card_info *card )
spin_lock_init ( &card->card_lock );
printk ( KERN_INFO "%s-%s: %s IRQ%d, %d ports\n",
- card->ports[0].dev->name,
- card->ports[card->nports-1].dev->name,
+ hdlc_to_dev(&card->ports[0].hdlc)->name,
+ hdlc_to_dev(&card->ports[card->nports-1].hdlc)->name,
type_strings[card->type], card->irq, card->nports );
}
@@ -1789,8 +1649,7 @@ fst_remove_one ( struct pci_dev *pdev )
for ( i = 0 ; i < card->nports ; i++ )
{
- unregister_netdev ( card->ports[i].dev );
- kfree ( card->ports[i].dev );
+ unregister_hdlc_device ( &card->ports[i].hdlc );
}
fst_disable_intr ( card );
@@ -1830,4 +1689,3 @@ fst_cleanup_module(void)
module_init ( fst_init );
module_exit ( fst_cleanup_module );
-MODULE_LICENSE("GPL");
diff --git a/drivers/net/wan/farsync.h b/drivers/net/wan/farsync.h
index bbc08a84ca07..f9e32e2f79b4 100644
--- a/drivers/net/wan/farsync.h
+++ b/drivers/net/wan/farsync.h
@@ -32,13 +32,8 @@
* A short common prefix is useful for routines within the driver to avoid
* conflict with other similar drivers and I chosen to use "fst_" for this
* purpose (FarSite T-series).
- *
- * Finally the device driver needs a short network interface name. Since
- * "hdlc" is already in use I've chosen the even less informative "sync"
- * for the present.
*/
#define FST_NAME "fst" /* In debug/info etc */
-#define FST_NDEV_NAME "sync" /* For net interface */
#define FST_DEV_NAME "farsync" /* For misc interfaces */
diff --git a/drivers/net/wan/hd64570.h b/drivers/net/wan/hd64570.h
index 9d22122dad11..cd3fcf86d6cf 100644
--- a/drivers/net/wan/hd64570.h
+++ b/drivers/net/wan/hd64570.h
@@ -152,7 +152,7 @@ typedef struct {
u32 bp; /* Buffer Pointer (24 bits) */
u16 len; /* Data Length */
u8 stat; /* Status */
- u8 unused2;
+ u8 unused; /* pads to 2-byte boundary */
}__attribute__ ((packed)) pkt_desc;
@@ -202,7 +202,11 @@ typedef struct {
#define MD0_CRC_ITU_0 0x06
#define MD0_CRC_ITU 0x07
-#define MD2_NRZI 0x20 /* NRZI mode */
+#define MD2_NRZ 0x00
+#define MD2_NRZI 0x20
+#define MD2_MANCHESTER 0x80
+#define MD2_FM_MARK 0xA0
+#define MD2_FM_SPACE 0xC0
#define MD2_LOOPBACK 0x03 /* Local data Loopback */
#define CTL_NORTS 0x01
diff --git a/drivers/net/wan/hd6457x.c b/drivers/net/wan/hd6457x.c
index ff976438932d..7f8677c62a04 100644
--- a/drivers/net/wan/hd6457x.c
+++ b/drivers/net/wan/hd6457x.c
@@ -42,13 +42,7 @@
#error Either hd64570.h or hd64572.h must be included
#endif
-
-static card_t *first_card;
-static card_t **new_card = &first_card;
-
-
-/* Maximum events to handle at each interrupt - should I increase it? */
-#define INTR_WORK 4
+static char sca_version[]="1.09";
#define get_msci(port) (phy_node(port) ? MSCI1_OFFSET : MSCI0_OFFSET)
#define get_dmac_rx(port) (phy_node(port) ? DMAC1RX_OFFSET : DMAC0RX_OFFSET)
@@ -63,11 +57,19 @@ static card_t **new_card = &first_card;
#define sca_ina(reg, card) sca_inw(reg, card)
#define writea(value, ptr) writew(value, ptr)
+#else /* HD64572 */
+#define sca_outa(value, reg, card) sca_outl(value, reg, card)
+#define sca_ina(reg, card) sca_inl(reg, card)
+#define writea(value, ptr) writel(value, ptr)
+#endif
+
static inline int sca_intr_status(card_t *card)
{
+ u8 result = 0;
+
+#ifdef __HD64570_H /* HD64570 */
u8 isr0 = sca_in(ISR0, card);
u8 isr1 = sca_in(ISR1, card);
- u8 result = 0;
if (isr1 & 0x03) result |= SCA_INTR_DMAC_RX(0);
if (isr1 & 0x0C) result |= SCA_INTR_DMAC_TX(0);
@@ -76,19 +78,8 @@ static inline int sca_intr_status(card_t *card)
if (isr0 & 0x0F) result |= SCA_INTR_MSCI(0);
if (isr0 & 0xF0) result |= SCA_INTR_MSCI(1);
- return result;
-}
-
#else /* HD64572 */
-#define sca_outa(value, reg, card) sca_outl(value, reg, card)
-#define sca_ina(reg, card) sca_inl(reg, card)
-#define writea(value, ptr) writel(value, ptr)
-
-
-static inline int sca_intr_status(card_t *card)
-{
u32 isr0 = sca_inl(ISR0, card);
- u8 result = 0;
if (isr0 & 0x0000000F) result |= SCA_INTR_DMAC_RX(0);
if (isr0 & 0x000000F0) result |= SCA_INTR_DMAC_TX(0);
@@ -97,11 +88,17 @@ static inline int sca_intr_status(card_t *card)
if (isr0 & 0x003E0000) result |= SCA_INTR_MSCI(0);
if (isr0 & 0x3E000000) result |= SCA_INTR_MSCI(1);
- return result;
-}
-
#endif /* HD64570 vs HD64572 */
+ if (!(result & SCA_INTR_DMAC_TX(0)))
+ if (sca_in(DSR_TX(0), card) & DSR_EOM)
+ result |= SCA_INTR_DMAC_TX(0);
+ if (!(result & SCA_INTR_DMAC_TX(1)))
+ if (sca_in(DSR_TX(1), card) & DSR_EOM)
+ result |= SCA_INTR_DMAC_TX(1);
+
+ return result;
+}
@@ -250,8 +247,7 @@ static inline void sca_msci_intr(port_t *port)
-static inline void sca_rx(card_t *card, port_t *port, pkt_desc *desc,
- u8 rxin)
+static inline void sca_rx(card_t *card, port_t *port, pkt_desc *desc, u8 rxin)
{
struct sk_buff *skb;
u16 len;
@@ -289,13 +285,16 @@ static inline void sca_rx(card_t *card, port_t *port, pkt_desc *desc,
openwin(card, 0);
#endif
skb_put(skb, len);
-#ifdef DEBUG_PKT
+#ifdef CONFIG_HDLC_DEBUG_PKT
printk(KERN_DEBUG "%s RX(%i):", hdlc_to_name(&port->hdlc), skb->len);
debug_frame(skb);
#endif
port->hdlc.stats.rx_packets++;
port->hdlc.stats.rx_bytes += skb->len;
- hdlc_netif_rx(&port->hdlc, skb);
+ skb->mac.raw = skb->data;
+ skb->dev = hdlc_to_dev(&port->hdlc);
+ skb->protocol = htons(ETH_P_HDLC);
+ netif_rx(skb);
}
@@ -320,14 +319,9 @@ static inline void sca_rx_intr(port_t *port)
pkt_desc *desc;
u32 cda = sca_ina(dmac + CDAL, card);
- if (cda == desc_off)
+ if ((cda >= desc_off) && (cda < desc_off + sizeof(pkt_desc)))
break; /* No frame received */
-#ifdef __HD64572_H
- if (cda == desc_off + 8)
- break; /* SCA-II updates CDA in 2 steps */
-#endif
-
desc = desc_address(port, port->rxin, 0);
stat = readb(&desc->stat);
if (!(stat & ST_RX_EOM))
@@ -371,20 +365,17 @@ static inline void sca_tx_intr(port_t *port)
DSR_TX(phy_node(port)), card);
while (1) {
- u32 desc_off = desc_offset(port, port->txlast, 1);
pkt_desc *desc;
- u16 len;
- if (sca_ina(dmac + CDAL, card) == desc_off)
+ u32 desc_off = desc_offset(port, port->txlast, 1);
+ u32 cda = sca_ina(dmac + CDAL, card);
+ if ((cda >= desc_off) && (cda < desc_off + sizeof(pkt_desc)))
break; /* Transmitter is/will_be sending this frame */
desc = desc_address(port, port->txlast, 1);
- len = readw(&desc->len);
-
port->hdlc.stats.tx_packets++;
- port->hdlc.stats.tx_bytes += len;
+ port->hdlc.stats.tx_bytes += readw(&desc->len);
writeb(0, &desc->stat); /* Free descriptor */
-
port->txlast = (port->txlast + 1) %
port_to_card(port)->ring_buffers;
}
@@ -398,7 +389,8 @@ static inline void sca_tx_intr(port_t *port)
static void sca_intr(int irq, void* dev_id, struct pt_regs *regs)
{
card_t *card = dev_id;
- int boguscnt = INTR_WORK;
+/* Maximum events to handle at each interrupt - should I increase it? */
+ int boguscnt = 4;
int i;
u8 stat;
@@ -421,9 +413,11 @@ static void sca_intr(int irq, void* dev_id, struct pt_regs *regs)
}
if (--boguscnt < 0) {
+#if 0
printk(KERN_ERR "%s: too much work at "
"interrupt\n",
hdlc_to_name(&port->hdlc));
+#endif
goto exit;
}
}
@@ -437,47 +431,22 @@ static void sca_intr(int irq, void* dev_id, struct pt_regs *regs)
-static inline int sca_set_loopback(port_t *port, int line)
+static void sca_set_port(port_t *port)
{
card_t* card = port_to_card(port);
u8 msci = get_msci(port);
u8 md2 = sca_in(msci + MD2, card);
-
- switch(line) {
- case LINE_DEFAULT:
- md2 &= ~MD2_LOOPBACK;
- port->line &= ~LINE_LOOPBACK;
- break;
-
- case LINE_LOOPBACK:
- md2 |= MD2_LOOPBACK;
- port->line |= LINE_LOOPBACK;
- break;
-
- default:
- return -EINVAL;
- }
-
- sca_out(md2, msci + MD2, card);
- return 0;
-}
-
-
-
-static void sca_set_clock(port_t *port)
-{
- card_t *card = port_to_card(port);
- u8 msci = get_msci(port);
unsigned int tmc, br = 10, brv = 1024;
- if (port->clkrate > 0) {
+
+ if (port->settings.clock_rate > 0) {
/* Try lower br for better accuracy*/
do {
br--;
brv >>= 1; /* brv = 2^9 = 512 max in specs */
/* Baud Rate = CLOCK_BASE / TMC / 2^BR */
- tmc = CLOCK_BASE / (brv * port->clkrate);
+ tmc = CLOCK_BASE / (brv * port->settings.clock_rate);
}while(br > 1 && tmc <= 128);
if (tmc < 1) {
@@ -487,11 +456,11 @@ static void sca_set_clock(port_t *port)
} else if (tmc > 255)
tmc = 256; /* tmc=0 means 256 - low baud rates */
- port->clkrate = CLOCK_BASE / (brv * tmc);
+ port->settings.clock_rate = CLOCK_BASE / (brv * tmc);
} else {
br = 9; /* Minimum clock rate */
tmc = 256; /* 8bit = 0 */
- port->clkrate = CLOCK_BASE / (256 * 512);
+ port->settings.clock_rate = CLOCK_BASE / (256 * 512);
}
port->rxs = (port->rxs & ~CLK_BRG_MASK) | br;
@@ -509,27 +478,59 @@ static void sca_set_clock(port_t *port)
/* Set BRG bits */
sca_out(port->rxs, msci + RXS, card);
sca_out(port->txs, msci + TXS, card);
+
+ if (port->settings.loopback)
+ md2 |= MD2_LOOPBACK;
+ else
+ md2 &= ~MD2_LOOPBACK;
+
+ sca_out(md2, msci + MD2, card);
+
}
-static void sca_set_hdlc_mode(port_t *port, u8 idle, u8 crc, u8 nrzi)
+static void sca_open(hdlc_device *hdlc)
{
+ port_t *port = hdlc_to_port(hdlc);
card_t* card = port_to_card(port);
u8 msci = get_msci(port);
- u8 md2 = (nrzi ? MD2_NRZI : 0) |
- ((port->line & LINE_LOOPBACK) ? MD2_LOOPBACK : 0);
- u8 ctl = (idle ? CTL_IDLE : 0);
-#ifdef __HD64572_H
- ctl |= CTL_URCT | CTL_URSKP; /* Skip the rest of underrun frame */
-#endif
+ u8 md0, md2;
+
+ switch(port->encoding) {
+ case ENCODING_NRZ: md2 = MD2_NRZ; break;
+ case ENCODING_NRZI: md2 = MD2_NRZI; break;
+ case ENCODING_FM_MARK: md2 = MD2_FM_MARK; break;
+ case ENCODING_FM_SPACE: md2 = MD2_FM_SPACE; break;
+ default: md2 = MD2_MANCHESTER;
+ }
+
+ if (port->settings.loopback)
+ md2 |= MD2_LOOPBACK;
+
+ switch(port->parity) {
+ case PARITY_CRC16_PR0: md0 = MD0_HDLC | MD0_CRC_16_0; break;
+ case PARITY_CRC16_PR1: md0 = MD0_HDLC | MD0_CRC_16; break;
+#ifdef __HD64570_H
+ case PARITY_CRC16_PR0_CCITT: md0 = MD0_HDLC | MD0_CRC_ITU_0; break;
+#else
+ case PARITY_CRC32_PR1_CCITT: md0 = MD0_HDLC | MD0_CRC_ITU32; break;
+#endif
+ case PARITY_CRC16_PR1_CCITT: md0 = MD0_HDLC | MD0_CRC_ITU; break;
+ default: md0 = MD0_HDLC | MD0_CRC_NONE;
+ }
sca_out(CMD_RESET, msci + CMD, card);
- sca_out(MD0_HDLC | crc, msci + MD0, card);
+ sca_out(md0, msci + MD0, card);
sca_out(0x00, msci + MD1, card); /* no address field check */
sca_out(md2, msci + MD2, card);
sca_out(0x7E, msci + IDL, card); /* flag character 0x7E */
- sca_out(ctl, msci + CTL, card);
+#ifdef __HD64570_H
+ sca_out(CTL_IDLE, msci + CTL, card);
+#else
+ /* Skip the rest of underrun frame */
+ sca_out(CTL_IDLE | CTL_URCT | CTL_URSKP, msci + CTL, card);
+#endif
#ifdef __HD64570_H
/* Allow at least 8 bytes before requesting RX DMA operation */
@@ -539,24 +540,28 @@ static void sca_set_hdlc_mode(port_t *port, u8 idle, u8 crc, u8 nrzi)
sca_out(0x14, msci + TRC1, card); /* +1=TXRDY/DMA deactiv condition */
#else
sca_out(0x0F, msci + RNR, card); /* +1=RX DMA activation condition */
- /* Setting than to larger value may cause Illegal Access */
- sca_out(0x20, msci + TNR0, card); /* =TX DMA activation condition */
- sca_out(0x30, msci + TNR1, card); /* +1=TX DMA deactivation condition*/
- sca_out(0x04, msci + TCR, card); /* =Critical TX DMA activ condition */
+ sca_out(0x3C, msci + TFS, card); /* +1 = TX start */
+ sca_out(0x38, msci + TCR, card); /* =Critical TX DMA activ condition */
+ sca_out(0x38, msci + TNR0, card); /* =TX DMA activation condition */
+ sca_out(0x3F, msci + TNR1, card); /* +1=TX DMA deactivation condition*/
#endif
+/* We're using the following interrupts:
+ - TXINT (DMAC completed all transmisions, underflow or CTS change)
+ - all DMA interrupts
+*/
#ifdef __HD64570_H
/* MSCI TX INT IRQ enable */
sca_out(IE0_TXINT, msci + IE0, card);
- sca_out(IE1_UDRN, msci + IE1, card); /* TX underrun IRQ */
+ sca_out(IE1_UDRN, msci + IE1, card); /* TX underrun -> TXINT */
sca_out(sca_in(IER0, card) | (phy_node(port) ? 0x80 : 0x08),
IER0, card);
/* DMA IRQ enable */
sca_out(sca_in(IER1, card) | (phy_node(port) ? 0xF0 : 0x0F),
IER1, card);
#else
- /* MSCI TX INT and underrrun IRQ enable */
+ /* MSCI TX INT IRQ enable */
sca_outl(IE0_TXINT | IE0_UDRN, msci + IE0, card);
/* DMA & MSCI IRQ enable */
sca_outl(sca_in(IER0, card) |
@@ -573,11 +578,52 @@ static void sca_set_hdlc_mode(port_t *port, u8 idle, u8 crc, u8 nrzi)
sca_out(port->txs, msci + TXS, card);
sca_out(CMD_TX_ENABLE, msci + CMD, card);
sca_out(CMD_RX_ENABLE, msci + CMD, card);
+
+ netif_start_queue(hdlc_to_dev(hdlc));
+}
+
+
+
+static void sca_close(hdlc_device *hdlc)
+{
+ port_t *port = hdlc_to_port(hdlc);
+
+ /* reset channel */
+ netif_stop_queue(hdlc_to_dev(hdlc));
+ sca_out(CMD_RESET, get_msci(port) + CMD, port_to_card(port));
}
-#ifdef DEBUG_RINGS
+static int sca_attach(hdlc_device *hdlc, unsigned short encoding,
+ unsigned short parity)
+{
+ if (encoding != ENCODING_NRZ &&
+ encoding != ENCODING_NRZI &&
+ encoding != ENCODING_FM_MARK &&
+ encoding != ENCODING_FM_SPACE &&
+ encoding != ENCODING_MANCHESTER)
+ return -EINVAL;
+
+ if (parity != PARITY_NONE &&
+ parity != PARITY_CRC16_PR0 &&
+ parity != PARITY_CRC16_PR1 &&
+#ifdef __HD64570_H
+ parity != PARITY_CRC16_PR0_CCITT &&
+#else
+ parity != PARITY_CRC32_PR1_CCITT &&
+#endif
+ parity != PARITY_CRC16_PR1_CCITT)
+ return -EINVAL;
+
+ hdlc_to_port(hdlc)->encoding = encoding;
+ hdlc_to_port(hdlc)->parity = parity;
+ return 0;
+}
+
+
+
+#ifdef CONFIG_HDLC_DEBUG_RINGS
static void sca_dump_rings(hdlc_device *hdlc)
{
port_t *port = hdlc_to_port(hdlc);
@@ -644,34 +690,14 @@ static void sca_dump_rings(hdlc_device *hdlc)
openwin(card, page); /* Restore original page */
#endif
}
-#endif /* DEBUG_RINGS */
-
-
-
-static void sca_open(hdlc_device *hdlc)
-{
- port_t *port = hdlc_to_port(hdlc);
-
- sca_set_hdlc_mode(port, 1, MD0_CRC_ITU, 0);
- netif_start_queue(hdlc_to_dev(hdlc));
-}
-
-
-static void sca_close(hdlc_device *hdlc)
-{
- port_t *port = hdlc_to_port(hdlc);
-
- /* reset channel */
- netif_stop_queue(hdlc_to_dev(hdlc));
- sca_out(CMD_RESET, get_msci(port) + CMD, port_to_card(port));
-}
+#endif /* CONFIG_HDLC_DEBUG_RINGS */
-static int sca_xmit(hdlc_device *hdlc, struct sk_buff *skb)
+static int sca_xmit(struct sk_buff *skb, struct net_device *dev)
{
+ hdlc_device *hdlc = dev_to_hdlc(dev);
port_t *port = hdlc_to_port(hdlc);
- struct net_device *dev = hdlc_to_dev(hdlc);
card_t *card = port_to_card(port);
pkt_desc *desc;
u32 buff, len;
@@ -685,7 +711,7 @@ static int sca_xmit(hdlc_device *hdlc, struct sk_buff *skb)
desc = desc_address(port, port->txin + 1, 1);
if (readb(&desc->stat)) { /* allow 1 packet gap */
/* should never happen - previous xmit should stop queue */
-#ifdef DEBUG_PKT
+#ifdef CONFIG_HDLC_DEBUG_PKT
printk(KERN_DEBUG "%s: transmitter buffer full\n", dev->name);
#endif
netif_stop_queue(dev);
@@ -693,7 +719,7 @@ static int sca_xmit(hdlc_device *hdlc, struct sk_buff *skb)
return 1; /* request packet to be queued */
}
-#ifdef DEBUG_PKT
+#ifdef CONFIG_HDLC_DEBUG_PKT
printk(KERN_DEBUG "%s TX(%i):", hdlc_to_name(hdlc), skb->len);
debug_frame(skb);
#endif
diff --git a/drivers/net/wan/hdlc.c b/drivers/net/wan/hdlc.c
deleted file mode 100644
index 34da9c73b4d9..000000000000
--- a/drivers/net/wan/hdlc.c
+++ /dev/null
@@ -1,1453 +0,0 @@
-/*
- * Generic HDLC support routines for Linux
- *
- * Copyright (C) 1999, 2000 Krzysztof Halasa <khc@pm.waw.pl>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * Current status:
- * - this is work in progress
- * - not heavily tested on SMP
- * - currently supported:
- * * raw IP-in-HDLC
- * * Cisco HDLC
- * * Frame Relay with ANSI or CCITT LMI (both user and network side)
- * * PPP (using syncppp.c)
- * * X.25
- *
- * Use sethdlc utility to set line parameters, protocol and PVCs
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/sched.h>
-#include <linux/errno.h>
-#include <linux/if_arp.h>
-#include <linux/init.h>
-#include <linux/skbuff.h>
-#include <linux/pkt_sched.h>
-#include <linux/inetdevice.h>
-#include <linux/lapb.h>
-#include <linux/rtnetlink.h>
-#include <linux/hdlc.h>
-
-/* #define DEBUG_PKT */
-/* #define DEBUG_HARD_HEADER */
-/* #define DEBUG_FECN */
-/* #define DEBUG_BECN */
-
-static const char* version = "HDLC support module revision 1.02 for Linux 2.4";
-
-
-#define CISCO_MULTICAST 0x8F /* Cisco multicast address */
-#define CISCO_UNICAST 0x0F /* Cisco unicast address */
-#define CISCO_KEEPALIVE 0x8035 /* Cisco keepalive protocol */
-#define CISCO_SYS_INFO 0x2000 /* Cisco interface/system info */
-#define CISCO_ADDR_REQ 0 /* Cisco address request */
-#define CISCO_ADDR_REPLY 1 /* Cisco address reply */
-#define CISCO_KEEPALIVE_REQ 2 /* Cisco keepalive request */
-
-static int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
-
-/********************************************************
- *
- * Cisco HDLC support
- *
- *******************************************************/
-
-static int cisco_hard_header(struct sk_buff *skb, struct net_device *dev,
- u16 type, void *daddr, void *saddr,
- unsigned int len)
-{
- hdlc_header *data;
-#ifdef DEBUG_HARD_HEADER
- printk(KERN_DEBUG "%s: cisco_hard_header called\n", dev->name);
-#endif
-
- skb_push(skb, sizeof(hdlc_header));
- data = (hdlc_header*)skb->data;
- if (type == CISCO_KEEPALIVE)
- data->address = CISCO_MULTICAST;
- else
- data->address = CISCO_UNICAST;
- data->control = 0;
- data->protocol = htons(type);
-
- return sizeof(hdlc_header);
-}
-
-
-
-static void cisco_keepalive_send(hdlc_device *hdlc, u32 type,
- u32 par1, u32 par2)
-{
- struct sk_buff *skb;
- cisco_packet *data;
-
- skb = dev_alloc_skb(sizeof(hdlc_header)+sizeof(cisco_packet));
- if (!skb) {
- printk(KERN_WARNING "%s: Memory squeeze on cisco_keepalive_send()\n",
- hdlc_to_name(hdlc));
- return;
- }
- skb_reserve(skb, 4);
- cisco_hard_header(skb, hdlc_to_dev(hdlc), CISCO_KEEPALIVE,
- NULL, NULL, 0);
- data = (cisco_packet*)skb->tail;
-
- data->type = htonl(type);
- data->par1 = htonl(par1);
- data->par2 = htonl(par2);
- data->rel = 0xFFFF;
- data->time = htonl(jiffies * 1000 / HZ);
-
- skb_put(skb, sizeof(cisco_packet));
- skb->priority = TC_PRIO_CONTROL;
- skb->dev = hdlc_to_dev(hdlc);
-
- dev_queue_xmit(skb);
-}
-
-
-
-static void cisco_netif(hdlc_device *hdlc, struct sk_buff *skb)
-{
- hdlc_header *data = (hdlc_header*)skb->data;
- cisco_packet *cisco_data;
- struct in_device *in_dev;
- u32 addr, mask;
-
- if (skb->len<sizeof(hdlc_header))
- goto rx_error;
-
- if (data->address != CISCO_MULTICAST &&
- data->address != CISCO_UNICAST)
- goto rx_error;
-
- skb_pull(skb, sizeof(hdlc_header));
-
- switch(ntohs(data->protocol)) {
- case ETH_P_IP:
- case ETH_P_IPX:
- case ETH_P_IPV6:
- skb->protocol = data->protocol;
- skb->dev = hdlc_to_dev(hdlc);
- netif_rx(skb);
- return;
-
- case CISCO_SYS_INFO:
- /* Packet is not needed, drop it. */
- dev_kfree_skb_any(skb);
- return;
-
- case CISCO_KEEPALIVE:
- if (skb->len != CISCO_PACKET_LEN &&
- skb->len != CISCO_BIG_PACKET_LEN) {
- printk(KERN_INFO "%s: Invalid length of Cisco "
- "control packet (%d bytes)\n",
- hdlc_to_name(hdlc), skb->len);
- goto rx_error;
- }
-
- cisco_data = (cisco_packet*)skb->data;
-
- switch(ntohl (cisco_data->type)) {
- case CISCO_ADDR_REQ: /* Stolen from syncppp.c :-) */
- in_dev = hdlc_to_dev(hdlc)->ip_ptr;
- addr = 0;
- mask = ~0; /* is the mask correct? */
-
- if (in_dev != NULL) {
- struct in_ifaddr **ifap = &in_dev->ifa_list;
-
- while (*ifap != NULL) {
- if (strcmp(hdlc_to_name(hdlc),
- (*ifap)->ifa_label) == 0) {
- addr = (*ifap)->ifa_local;
- mask = (*ifap)->ifa_mask;
- break;
- }
- ifap = &(*ifap)->ifa_next;
- }
-
- cisco_keepalive_send(hdlc, CISCO_ADDR_REPLY,
- addr, mask);
- }
- dev_kfree_skb_any(skb);
- return;
-
- case CISCO_ADDR_REPLY:
- printk(KERN_INFO "%s: Unexpected Cisco IP address "
- "reply\n", hdlc_to_name(hdlc));
- goto rx_error;
-
- case CISCO_KEEPALIVE_REQ:
- hdlc->lmi.rxseq = ntohl(cisco_data->par1);
- if (ntohl(cisco_data->par2) == hdlc->lmi.txseq) {
- hdlc->lmi.last_poll = jiffies;
- if (!(hdlc->lmi.state & LINK_STATE_RELIABLE)) {
- u32 sec, min, hrs, days;
- sec = ntohl(cisco_data->time) / 1000;
- min = sec / 60; sec -= min * 60;
- hrs = min / 60; min -= hrs * 60;
- days = hrs / 24; hrs -= days * 24;
- printk(KERN_INFO "%s: Link up (peer "
- "uptime %ud%uh%um%us)\n",
- hdlc_to_name(hdlc), days, hrs,
- min, sec);
- }
- hdlc->lmi.state |= LINK_STATE_RELIABLE;
- }
-
- dev_kfree_skb_any(skb);
- return;
- } /* switch(keepalive type) */
- } /* switch(protocol) */
-
- printk(KERN_INFO "%s: Unsupported protocol %x\n", hdlc_to_name(hdlc),
- data->protocol);
- dev_kfree_skb_any(skb);
- return;
-
- rx_error:
- hdlc->stats.rx_errors++; /* Mark error */
- dev_kfree_skb_any(skb);
-}
-
-
-
-static void cisco_timer(unsigned long arg)
-{
- hdlc_device *hdlc = (hdlc_device*)arg;
-
- if ((hdlc->lmi.state & LINK_STATE_RELIABLE) &&
- (jiffies - hdlc->lmi.last_poll >= hdlc->lmi.T392 * HZ)) {
- hdlc->lmi.state &= ~LINK_STATE_RELIABLE;
- printk(KERN_INFO "%s: Link down\n", hdlc_to_name(hdlc));
- }
-
- cisco_keepalive_send(hdlc, CISCO_KEEPALIVE_REQ, ++hdlc->lmi.txseq,
- hdlc->lmi.rxseq);
- hdlc->timer.expires = jiffies + hdlc->lmi.T391*HZ;
-
- hdlc->timer.function = cisco_timer;
- hdlc->timer.data = arg;
- add_timer(&hdlc->timer);
-}
-
-
-
-/******************************************************************
- *
- * generic Frame Relay routines
- *
- *****************************************************************/
-
-
-static int fr_hard_header(struct sk_buff *skb, struct net_device *dev,
- u16 type, void *daddr, void *saddr, unsigned int len)
-{
- u16 head_len;
-
- if (!daddr)
- daddr = dev->broadcast;
-
-#ifdef DEBUG_HARD_HEADER
- printk(KERN_DEBUG "%s: fr_hard_header called\n", dev->name);
-#endif
-
- switch(type) {
- case ETH_P_IP:
- head_len = 4;
- skb_push(skb, head_len);
- skb->data[3] = NLPID_IP;
- break;
-
- case ETH_P_IPV6:
- head_len = 4;
- skb_push(skb, head_len);
- skb->data[3] = NLPID_IPV6;
- break;
-
- case LMI_PROTO:
- head_len = 4;
- skb_push(skb, head_len);
- skb->data[3] = LMI_PROTO;
- break;
-
- default:
- head_len = 10;
- skb_push(skb, head_len);
- skb->data[3] = FR_PAD;
- skb->data[4] = NLPID_SNAP;
- skb->data[5] = FR_PAD;
- skb->data[6] = FR_PAD;
- skb->data[7] = FR_PAD;
- skb->data[8] = type>>8;
- skb->data[9] = (u8)type;
- }
-
- memcpy(skb->data, daddr, 2);
- skb->data[2] = FR_UI;
-
- return head_len;
-}
-
-
-
-static inline void fr_log_dlci_active(pvc_device *pvc)
-{
- printk(KERN_INFO "%s: %sactive%s\n", pvc_to_name(pvc),
- pvc->state & PVC_STATE_ACTIVE ? "" : "in",
- pvc->state & PVC_STATE_NEW ? " new" : "");
-}
-
-
-
-static inline u8 fr_lmi_nextseq(u8 x)
-{
- x++;
- return x ? x : 1;
-}
-
-
-
-static void fr_lmi_send(hdlc_device *hdlc, int fullrep)
-{
- struct sk_buff *skb;
- pvc_device *pvc = hdlc->first_pvc;
- int len = mode_is(hdlc, MODE_FR_ANSI) ? LMI_ANSI_LENGTH : LMI_LENGTH;
- int stat_len = 3;
- u8 *data;
- int i = 0;
-
- if (mode_is(hdlc, MODE_DCE) && fullrep) {
- len += hdlc->pvc_count * (2 + stat_len);
- if (len > HDLC_MAX_MTU) {
- printk(KERN_WARNING "%s: Too many PVCs while sending "
- "LMI full report\n", hdlc_to_name(hdlc));
- return;
- }
- }
-
- skb = dev_alloc_skb(len);
- if (!skb) {
- printk(KERN_WARNING "%s: Memory squeeze on fr_lmi_send()\n",
- hdlc_to_name(hdlc));
- return;
- }
- memset(skb->data, 0, len);
- skb_reserve(skb, 4);
- fr_hard_header(skb, hdlc_to_dev(hdlc), LMI_PROTO, NULL, NULL, 0);
- data = skb->tail;
- data[i++] = LMI_CALLREF;
- data[i++] = mode_is(hdlc, MODE_DCE) ? LMI_STATUS : LMI_STATUS_ENQUIRY;
- if (mode_is(hdlc, MODE_FR_ANSI))
- data[i++] = LMI_ANSI_LOCKSHIFT;
- data[i++] = mode_is(hdlc, MODE_FR_CCITT) ? LMI_CCITT_REPTYPE :
- LMI_REPTYPE;
- data[i++] = LMI_REPT_LEN;
- data[i++] = fullrep ? LMI_FULLREP : LMI_INTEGRITY;
-
- data[i++] = mode_is(hdlc, MODE_FR_CCITT) ? LMI_CCITT_ALIVE : LMI_ALIVE;
- data[i++] = LMI_INTEG_LEN;
- data[i++] = hdlc->lmi.txseq = fr_lmi_nextseq(hdlc->lmi.txseq);
- data[i++] = hdlc->lmi.rxseq;
-
- if (mode_is(hdlc, MODE_DCE) && fullrep) {
- while (pvc) {
- data[i++] = mode_is(hdlc, MODE_FR_CCITT) ?
- LMI_CCITT_PVCSTAT:LMI_PVCSTAT;
- data[i++] = stat_len;
-
- if ((hdlc->lmi.state & LINK_STATE_RELIABLE) &&
- (pvc->netdev.flags & IFF_UP) &&
- !(pvc->state & (PVC_STATE_ACTIVE|PVC_STATE_NEW))) {
- pvc->state |= PVC_STATE_NEW;
- fr_log_dlci_active(pvc);
- }
-
- dlci_to_status(hdlc, netdev_dlci(&pvc->netdev),
- data+i, pvc->state);
- i += stat_len;
- pvc = pvc->next;
- }
- }
-
- skb_put(skb, i);
- skb->priority = TC_PRIO_CONTROL;
- skb->dev = hdlc_to_dev(hdlc);
-
- dev_queue_xmit(skb);
-}
-
-
-
-static void fr_timer(unsigned long arg)
-{
- hdlc_device *hdlc = (hdlc_device*)arg;
- int i, cnt = 0, reliable;
- u32 list;
-
- if (mode_is(hdlc, MODE_DCE))
- reliable = (jiffies - hdlc->lmi.last_poll < hdlc->lmi.T392*HZ);
- else {
- hdlc->lmi.last_errors <<= 1; /* Shift the list */
- if (hdlc->lmi.state & LINK_STATE_REQUEST) {
- printk(KERN_INFO "%s: No LMI status reply received\n",
- hdlc_to_name(hdlc));
- hdlc->lmi.last_errors |= 1;
- }
-
- for (i = 0, list = hdlc->lmi.last_errors; i < hdlc->lmi.N393;
- i++, list >>= 1)
- cnt += (list & 1); /* errors count */
-
- reliable = (cnt < hdlc->lmi.N392);
- }
-
- if ((hdlc->lmi.state & LINK_STATE_RELIABLE) !=
- (reliable ? LINK_STATE_RELIABLE : 0)) {
- pvc_device *pvc = hdlc->first_pvc;
-
- while (pvc) {/* Deactivate all PVCs */
- pvc->state &= ~(PVC_STATE_NEW | PVC_STATE_ACTIVE);
- pvc = pvc->next;
- }
-
- hdlc->lmi.state ^= LINK_STATE_RELIABLE;
- printk(KERN_INFO "%s: Link %sreliable\n", hdlc_to_name(hdlc),
- reliable ? "" : "un");
-
- if (reliable) {
- hdlc->lmi.N391cnt = 0; /* Request full status */
- hdlc->lmi.state |= LINK_STATE_CHANGED;
- }
- }
-
- if (mode_is(hdlc, MODE_DCE))
- hdlc->timer.expires = jiffies + hdlc->lmi.T392*HZ;
- else {
- if (hdlc->lmi.N391cnt)
- hdlc->lmi.N391cnt--;
-
- fr_lmi_send(hdlc, hdlc->lmi.N391cnt == 0);
-
- hdlc->lmi.state |= LINK_STATE_REQUEST;
- hdlc->timer.expires = jiffies + hdlc->lmi.T391*HZ;
- }
-
- hdlc->timer.function = fr_timer;
- hdlc->timer.data = arg;
- add_timer(&hdlc->timer);
-}
-
-
-
-static int fr_lmi_recv(hdlc_device *hdlc, struct sk_buff *skb)
-{
- int stat_len;
- pvc_device *pvc;
- int reptype = -1, error;
- u8 rxseq, txseq;
- int i;
-
- if (skb->len < (mode_is(hdlc, MODE_FR_ANSI) ?
- LMI_ANSI_LENGTH : LMI_LENGTH)) {
- printk(KERN_INFO "%s: Short LMI frame\n", hdlc_to_name(hdlc));
- return 1;
- }
-
- if (skb->data[5] != (!mode_is(hdlc, MODE_DCE) ?
- LMI_STATUS : LMI_STATUS_ENQUIRY)) {
- printk(KERN_INFO "%s: LMI msgtype=%x, Not LMI status %s\n",
- hdlc_to_name(hdlc), skb->data[2],
- mode_is(hdlc, MODE_DCE) ? "enquiry" : "reply");
- return 1;
- }
-
- i = mode_is(hdlc, MODE_FR_ANSI) ? 7 : 6;
-
- if (skb->data[i] !=
- (mode_is(hdlc, MODE_FR_CCITT) ? LMI_CCITT_REPTYPE : LMI_REPTYPE)) {
- printk(KERN_INFO "%s: Not a report type=%x\n",
- hdlc_to_name(hdlc), skb->data[i]);
- return 1;
- }
- i++;
-
- i++; /* Skip length field */
-
- reptype = skb->data[i++];
-
- if (skb->data[i]!=
- (mode_is(hdlc, MODE_FR_CCITT) ? LMI_CCITT_ALIVE : LMI_ALIVE)) {
- printk(KERN_INFO "%s: Unsupported status element=%x\n",
- hdlc_to_name(hdlc), skb->data[i]);
- return 1;
- }
- i++;
-
- i++; /* Skip length field */
-
- hdlc->lmi.rxseq = skb->data[i++]; /* TX sequence from peer */
- rxseq = skb->data[i++]; /* Should confirm our sequence */
-
- txseq = hdlc->lmi.txseq;
-
- if (mode_is(hdlc, MODE_DCE)) {
- if (reptype != LMI_FULLREP && reptype != LMI_INTEGRITY) {
- printk(KERN_INFO "%s: Unsupported report type=%x\n",
- hdlc_to_name(hdlc), reptype);
- return 1;
- }
- }
-
- error = 0;
- if (!(hdlc->lmi.state & LINK_STATE_RELIABLE))
- error = 1;
-
- if (rxseq == 0 || rxseq != txseq) {
- hdlc->lmi.N391cnt = 0; /* Ask for full report next time */
- error = 1;
- }
-
- if (mode_is(hdlc, MODE_DCE)) {
- if ((hdlc->lmi.state & LINK_STATE_FULLREP_SENT) && !error) {
-/* Stop sending full report - the last one has been confirmed by DTE */
- hdlc->lmi.state &= ~LINK_STATE_FULLREP_SENT;
- pvc = hdlc->first_pvc;
- while (pvc) {
- if (pvc->state & PVC_STATE_NEW) {
- pvc->state &= ~PVC_STATE_NEW;
- pvc->state |= PVC_STATE_ACTIVE;
- fr_log_dlci_active(pvc);
-
-/* Tell DTE that new PVC is now active */
- hdlc->lmi.state |= LINK_STATE_CHANGED;
- }
- pvc = pvc->next;
- }
- }
-
- if (hdlc->lmi.state & LINK_STATE_CHANGED) {
- reptype = LMI_FULLREP;
- hdlc->lmi.state |= LINK_STATE_FULLREP_SENT;
- hdlc->lmi.state &= ~LINK_STATE_CHANGED;
- }
-
- fr_lmi_send(hdlc, reptype == LMI_FULLREP ? 1 : 0);
- return 0;
- }
-
- /* DTE */
-
- if (reptype != LMI_FULLREP || error)
- return 0;
-
- stat_len = 3;
- pvc = hdlc->first_pvc;
-
- while (pvc) {
- pvc->newstate = 0;
- pvc = pvc->next;
- }
-
- while (skb->len >= i + 2 + stat_len) {
- u16 dlci;
- u8 state = 0;
-
- if (skb->data[i] != (mode_is(hdlc, MODE_FR_CCITT) ?
- LMI_CCITT_PVCSTAT : LMI_PVCSTAT)) {
- printk(KERN_WARNING "%s: Invalid PVCSTAT ID: %x\n",
- hdlc_to_name(hdlc), skb->data[i]);
- return 1;
- }
- i++;
-
- if (skb->data[i] != stat_len) {
- printk(KERN_WARNING "%s: Invalid PVCSTAT length: %x\n",
- hdlc_to_name(hdlc), skb->data[i]);
- return 1;
- }
- i++;
-
- dlci = status_to_dlci(hdlc, skb->data+i, &state);
- pvc = find_pvc(hdlc, dlci);
-
- if (pvc)
- pvc->newstate = state;
- else if (state == PVC_STATE_NEW)
- printk(KERN_INFO "%s: new PVC available, DLCI=%u\n",
- hdlc_to_name(hdlc), dlci);
-
- i += stat_len;
- }
-
- pvc = hdlc->first_pvc;
-
- while (pvc) {
- if (pvc->newstate == PVC_STATE_NEW)
- pvc->newstate = PVC_STATE_ACTIVE;
-
- pvc->newstate |= (pvc->state &
- ~(PVC_STATE_NEW|PVC_STATE_ACTIVE));
- if (pvc->state != pvc->newstate) {
- pvc->state = pvc->newstate;
- fr_log_dlci_active(pvc);
- }
- pvc = pvc->next;
- }
-
- /* Next full report after N391 polls */
- hdlc->lmi.N391cnt = hdlc->lmi.N391;
-
- return 0;
-}
-
-
-
-static void fr_netif(hdlc_device *hdlc, struct sk_buff *skb)
-{
- fr_hdr *fh = (fr_hdr*)skb->data;
- u8 *data = skb->data;
- u16 dlci;
- pvc_device *pvc;
-
- if (skb->len<4 || fh->ea1 || data[2] != FR_UI)
- goto rx_error;
-
- dlci = q922_to_dlci(skb->data);
-
- if (dlci == LMI_DLCI) {
- if (data[3] == LMI_PROTO) {
- if (fr_lmi_recv(hdlc, skb))
- goto rx_error;
- else {
- /* No request pending */
- hdlc->lmi.state &= ~LINK_STATE_REQUEST;
- hdlc->lmi.last_poll = jiffies;
- dev_kfree_skb_any(skb);
- return;
- }
- }
-
- printk(KERN_INFO "%s: Received non-LMI frame with LMI DLCI\n",
- hdlc_to_name(hdlc));
- goto rx_error;
- }
-
- pvc = find_pvc(hdlc, dlci);
- if (!pvc) {
-#ifdef DEBUG_PKT
- printk(KERN_INFO "%s: No PVC for received frame's DLCI %d\n",
- hdlc_to_name(hdlc), dlci);
-#endif
- goto rx_error;
- }
-
- if ((pvc->netdev.flags & IFF_UP) == 0) {
-#ifdef DEBUG_PKT
- printk(KERN_INFO "%s: PVC for received frame's DLCI %d is down\n",
- hdlc_to_name(hdlc), dlci);
-#endif
- goto rx_error;
- }
-
- pvc->stats.rx_packets++; /* PVC traffic */
- pvc->stats.rx_bytes += skb->len;
-
- if ((pvc->state & PVC_STATE_FECN) != (fh->fecn ? PVC_STATE_FECN : 0)) {
-#ifdef DEBUG_FECN
- printk(KERN_DEBUG "%s: FECN O%s\n", pvc_to_name(pvc),
- fh->fecn ? "N" : "FF");
-#endif
- pvc->state ^= PVC_STATE_FECN;
- }
-
- if ((pvc->state & PVC_STATE_BECN) != (fh->becn ? PVC_STATE_BECN : 0)) {
-#ifdef DEBUG_FECN
- printk(KERN_DEBUG "%s: BECN O%s\n", pvc_to_name(pvc),
- fh->becn ? "N" : "FF");
-#endif
- pvc->state ^= PVC_STATE_BECN;
- }
-
- if (pvc->state & PVC_STATE_BECN)
- pvc->stats.rx_compressed++;
-
- if (data[3] == NLPID_IP) {
- skb_pull(skb, 4); /* Remove 4-byte header (hdr, UI, NLPID) */
- skb->protocol = htons(ETH_P_IP);
- skb->dev = &pvc->netdev;
- netif_rx(skb);
- return;
- }
-
-
- if (data[3] == NLPID_IPV6) {
- skb_pull(skb, 4); /* Remove 4-byte header (hdr, UI, NLPID) */
- skb->protocol = htons(ETH_P_IPV6);
- skb->dev = &pvc->netdev;
- netif_rx(skb);
- return;
- }
-
- if (data[3] == FR_PAD && data[4] == NLPID_SNAP && data[5] == FR_PAD &&
- data[6] == FR_PAD && data[7] == FR_PAD &&
- ((data[8]<<8) | data[9]) == ETH_P_ARP) {
- skb_pull(skb, 10);
- skb->protocol = htons(ETH_P_ARP);
- skb->dev = &pvc->netdev;
- netif_rx(skb);
- return;
- }
-
- printk(KERN_INFO "%s: Unusupported protocol %x\n",
- hdlc_to_name(hdlc), data[3]);
- dev_kfree_skb_any(skb);
- return;
-
- rx_error:
- hdlc->stats.rx_errors++; /* Mark error */
- dev_kfree_skb_any(skb);
-}
-
-
-
-static void fr_cisco_open(hdlc_device *hdlc)
-{
- hdlc->lmi.state = LINK_STATE_CHANGED;
- hdlc->lmi.txseq = hdlc->lmi.rxseq = 0;
- hdlc->lmi.last_errors = 0xFFFFFFFF;
- hdlc->lmi.N391cnt = 0;
-
- init_timer(&hdlc->timer);
- hdlc->timer.expires = jiffies + HZ; /* First poll after 1 second */
- hdlc->timer.function = mode_is(hdlc, MODE_FR) ? fr_timer : cisco_timer;
- hdlc->timer.data = (unsigned long)hdlc;
- add_timer(&hdlc->timer);
-}
-
-
-
-static void fr_cisco_close(hdlc_device *hdlc)
-{
- pvc_device *pvc = hdlc->first_pvc;
-
- del_timer_sync(&hdlc->timer);
-
- while(pvc) { /* NULL in Cisco mode */
- dev_close(&pvc->netdev); /* Shutdown all PVCs for this FRAD */
- pvc = pvc->next;
- }
-}
-
-
-
-/******************************************************************
- *
- * generic HDLC routines
- *
- *****************************************************************/
-
-
-
-static int hdlc_change_mtu(struct net_device *dev, int new_mtu)
-{
- if ((new_mtu < 68) || (new_mtu > HDLC_MAX_MTU))
- return -EINVAL;
- dev->mtu = new_mtu;
- return 0;
-}
-
-
-
-/********************************************************
- *
- * PVC device routines
- *
- *******************************************************/
-
-static int pvc_open(struct net_device *dev)
-{
- pvc_device *pvc = dev_to_pvc(dev);
- int result = 0;
-
- if ((hdlc_to_dev(pvc->master)->flags & IFF_UP) == 0)
- return -EIO; /* Master must be UP in order to activate PVC */
-
- memset(&(pvc->stats), 0, sizeof(struct net_device_stats));
- pvc->state = 0;
-
- if (!mode_is(pvc->master, MODE_SOFT) && pvc->master->open_pvc)
- result = pvc->master->open_pvc(pvc);
- if (result)
- return result;
-
- pvc->master->lmi.state |= LINK_STATE_CHANGED;
- return 0;
-}
-
-
-
-static int pvc_close(struct net_device *dev)
-{
- pvc_device *pvc = dev_to_pvc(dev);
- pvc->state = 0;
-
- if (!mode_is(pvc->master, MODE_SOFT) && pvc->master->close_pvc)
- pvc->master->close_pvc(pvc);
-
- pvc->master->lmi.state |= LINK_STATE_CHANGED;
- return 0;
-}
-
-
-
-static int pvc_xmit(struct sk_buff *skb, struct net_device *dev)
-{
- pvc_device *pvc = dev_to_pvc(dev);
-
- if (pvc->state & PVC_STATE_ACTIVE) {
- skb->dev = hdlc_to_dev(pvc->master);
- pvc->stats.tx_bytes += skb->len;
- pvc->stats.tx_packets++;
- if (pvc->state & PVC_STATE_FECN)
- pvc->stats.tx_compressed++; /* TX Congestion counter */
- dev_queue_xmit(skb);
- } else {
- pvc->stats.tx_dropped++;
- dev_kfree_skb(skb);
- }
-
- return 0;
-}
-
-
-
-static struct net_device_stats *pvc_get_stats(struct net_device *dev)
-{
- pvc_device *pvc = dev_to_pvc(dev);
- return &pvc->stats;
-}
-
-
-
-static int pvc_change_mtu(struct net_device *dev, int new_mtu)
-{
- if ((new_mtu < 68) || (new_mtu > HDLC_MAX_MTU))
- return -EINVAL;
- dev->mtu = new_mtu;
- return 0;
-}
-
-
-
-static void destroy_pvc_list(hdlc_device *hdlc)
-{
- pvc_device *pvc = hdlc->first_pvc;
- while(pvc) {
- pvc_device *next = pvc->next;
- unregister_netdevice(&pvc->netdev);
- kfree(pvc);
- pvc = next;
- }
-
- hdlc->first_pvc = NULL; /* All PVCs destroyed */
- hdlc->pvc_count = 0;
- hdlc->lmi.state |= LINK_STATE_CHANGED;
-}
-
-
-
-/********************************************************
- *
- * X.25 protocol support routines
- *
- *******************************************************/
-
-#ifdef CONFIG_HDLC_X25
-/* These functions are callbacks called by LAPB layer */
-
-void x25_connect_disconnect(void *token, int reason, int code)
-{
- hdlc_device *hdlc = token;
- struct sk_buff *skb;
- unsigned char *ptr;
-
- if ((skb = dev_alloc_skb(1)) == NULL) {
- printk(KERN_ERR "%s: out of memory\n", hdlc_to_name(hdlc));
- return;
- }
-
- ptr = skb_put(skb, 1);
- *ptr = code;
-
- skb->dev = hdlc_to_dev(hdlc);
- skb->protocol = htons(ETH_P_X25);
- skb->mac.raw = skb->data;
- skb->pkt_type = PACKET_HOST;
-
- netif_rx(skb);
-}
-
-void x25_connected(void *token, int reason)
-{
- x25_connect_disconnect(token, reason, 1);
-}
-
-void x25_disconnected(void *token, int reason)
-{
- x25_connect_disconnect(token, reason, 2);
-}
-
-
-int x25_data_indication(void *token, struct sk_buff *skb)
-{
- hdlc_device *hdlc = token;
- unsigned char *ptr;
-
- ptr = skb_push(skb, 1);
- *ptr = 0;
-
- skb->dev = hdlc_to_dev(hdlc);
- skb->protocol = htons(ETH_P_X25);
- skb->mac.raw = skb->data;
- skb->pkt_type = PACKET_HOST;
-
- return netif_rx(skb);
-}
-
-
-void x25_data_transmit(void *token, struct sk_buff *skb)
-{
- hdlc_device *hdlc = token;
- hdlc->xmit(hdlc, skb); /* Ignore return value :-( */
-}
-#endif /* CONFIG_HDLC_X25 */
-
-
-/********************************************************
- *
- * HDLC device routines
- *
- *******************************************************/
-
-static int hdlc_open(struct net_device *dev)
-{
- hdlc_device *hdlc = dev_to_hdlc(dev);
- int result;
-
- if (hdlc->mode == MODE_NONE)
- return -ENOSYS;
-
- memset(&(hdlc->stats), 0, sizeof(struct net_device_stats));
-
- if (mode_is(hdlc, MODE_FR | MODE_SOFT) ||
- mode_is(hdlc, MODE_CISCO | MODE_SOFT))
- fr_cisco_open(hdlc);
-#ifdef CONFIG_HDLC_PPP
- else if (mode_is(hdlc, MODE_PPP | MODE_SOFT)) {
- sppp_attach(&hdlc->pppdev);
- /* sppp_attach nukes them. We don't need syncppp's ioctl */
- dev->do_ioctl = hdlc_ioctl;
- hdlc->pppdev.sppp.pp_flags &= ~PP_CISCO;
- dev->type = ARPHRD_PPP;
- result = sppp_open(dev);
- if (result) {
- sppp_detach(dev);
- return result;
- }
- }
-#endif
-#ifdef CONFIG_HDLC_X25
- else if (mode_is(hdlc, MODE_X25)) {
- struct lapb_register_struct cb;
-
- cb.connect_confirmation = x25_connected;
- cb.connect_indication = x25_connected;
- cb.disconnect_confirmation = x25_disconnected;
- cb.disconnect_indication = x25_disconnected;
- cb.data_indication = x25_data_indication;
- cb.data_transmit = x25_data_transmit;
-
- result = lapb_register(hdlc, &cb);
- if (result != LAPB_OK)
- return result;
- }
-#endif
- result = hdlc->open(hdlc);
- if (result) {
- if (mode_is(hdlc, MODE_FR | MODE_SOFT) ||
- mode_is(hdlc, MODE_CISCO | MODE_SOFT))
- fr_cisco_close(hdlc);
-#ifdef CONFIG_HDLC_PPP
- else if (mode_is(hdlc, MODE_PPP | MODE_SOFT)) {
- sppp_close(dev);
- sppp_detach(dev);
- dev->rebuild_header = NULL;
- dev->change_mtu = hdlc_change_mtu;
- dev->mtu = HDLC_MAX_MTU;
- dev->hard_header_len = 16;
- }
-#endif
-#ifdef CONFIG_HDLC_X25
- else if (mode_is(hdlc, MODE_X25))
- lapb_unregister(hdlc);
-#endif
- }
-
- return result;
-}
-
-
-
-static int hdlc_close(struct net_device *dev)
-{
- hdlc_device *hdlc = dev_to_hdlc(dev);
-
- hdlc->close(hdlc);
-
- if (mode_is(hdlc, MODE_FR | MODE_SOFT) ||
- mode_is(hdlc, MODE_CISCO | MODE_SOFT))
- fr_cisco_close(hdlc);
-#ifdef CONFIG_HDLC_PPP
- else if (mode_is(hdlc, MODE_PPP | MODE_SOFT)) {
- sppp_close(dev);
- sppp_detach(dev);
- dev->rebuild_header = NULL;
- dev->change_mtu = hdlc_change_mtu;
- dev->mtu = HDLC_MAX_MTU;
- dev->hard_header_len = 16;
- }
-#endif
-#ifdef CONFIG_HDLC_X25
- else if (mode_is(hdlc, MODE_X25))
- lapb_unregister(hdlc);
-#endif
- return 0;
-}
-
-
-
-static int hdlc_xmit(struct sk_buff *skb, struct net_device *dev)
-{
- hdlc_device *hdlc = dev_to_hdlc(dev);
-
-#ifdef CONFIG_HDLC_X25
- if (mode_is(hdlc, MODE_X25 | MODE_SOFT)) {
- int result;
-
-
- /* X.25 to LAPB */
- switch (skb->data[0]) {
- case 0: /* Data to be transmitted */
- skb_pull(skb, 1);
- if ((result = lapb_data_request(hdlc, skb)) != LAPB_OK)
- dev_kfree_skb(skb);
- return 0;
-
- case 1:
- if ((result = lapb_connect_request(hdlc))!= LAPB_OK) {
- if (result == LAPB_CONNECTED) {
- /* Send connect confirm. msg to level 3 */
- x25_connected(hdlc, 0);
- } else {
- printk(KERN_ERR "%s: LAPB connect "
- "request failed, error code = "
- "%i\n", hdlc_to_name(hdlc),
- result);
- }
- }
- break;
-
- case 2:
- if ((result=lapb_disconnect_request(hdlc))!=LAPB_OK) {
- if (result == LAPB_NOTCONNECTED) {
- /* Send disconnect confirm. msg to level 3 */
- x25_disconnected(hdlc, 0);
- } else {
- printk(KERN_ERR "%s: LAPB disconnect "
- "request failed, error code = "
- "%i\n", hdlc_to_name(hdlc),
- result);
- }
- }
- break;
-
- default:
- /* to be defined */
- break;
- }
-
- dev_kfree_skb(skb);
- return 0;
- } /* MODE_X25 */
-#endif /* CONFIG_HDLC_X25 */
-
- return hdlc->xmit(hdlc, skb);
-}
-
-
-
-void hdlc_netif_rx(hdlc_device *hdlc, struct sk_buff *skb)
-{
-/* skb contains raw HDLC frame, in both hard- and software modes */
- skb->mac.raw = skb->data;
-
- switch(hdlc->mode & MODE_MASK) {
- case MODE_HDLC:
- skb->protocol = htons(ETH_P_IP);
- skb->dev = hdlc_to_dev(hdlc);
- netif_rx(skb);
- return;
-
- case MODE_FR:
- fr_netif(hdlc, skb);
- return;
-
- case MODE_CISCO:
- cisco_netif(hdlc, skb);
- return;
-
-#ifdef CONFIG_HDLC_PPP
- case MODE_PPP:
-#if 0
- sppp_input(hdlc_to_dev(hdlc), skb);
-#else
- skb->protocol = htons(ETH_P_WAN_PPP);
- skb->dev = hdlc_to_dev(hdlc);
- netif_rx(skb);
-#endif
- return;
-#endif
-#ifdef CONFIG_HDLC_X25
- case MODE_X25:
- skb->dev = hdlc_to_dev(hdlc);
- if (lapb_data_received(hdlc, skb) == LAPB_OK)
- return;
- break;
-#endif
- }
-
- hdlc->stats.rx_errors++;
- dev_kfree_skb_any(skb);
-}
-
-
-
-static struct net_device_stats *hdlc_get_stats(struct net_device *dev)
-{
- return &dev_to_hdlc(dev)->stats;
-}
-
-
-
-static int hdlc_set_mode(hdlc_device *hdlc, int mode)
-{
- int result = -1; /* Default to soft modes */
- struct net_device *dev = hdlc_to_dev(hdlc);
-
- if(!capable(CAP_NET_ADMIN))
- return -EPERM;
-
- if(dev->flags & IFF_UP)
- return -EBUSY;
-
- dev->addr_len = 0;
- dev->hard_header = NULL;
- hdlc->mode = MODE_NONE;
-
- if (!(mode & MODE_SOFT))
- switch(mode & MODE_MASK) {
- case MODE_HDLC:
- result = hdlc->set_mode ?
- hdlc->set_mode(hdlc, MODE_HDLC) : 0;
- break;
-
- case MODE_CISCO: /* By card */
-#ifdef CONFIG_HDLC_PPP
- case MODE_PPP:
-#endif
-#ifdef CONFIG_HDLC_X25
- case MODE_X25:
-#endif
- case MODE_FR:
- result = hdlc->set_mode ?
- hdlc->set_mode(hdlc, mode) : -ENOSYS;
- break;
-
- default:
- return -EINVAL;
- }
-
- if (result) {
- mode |= MODE_SOFT; /* Try "host software" protocol */
-
- switch(mode & MODE_MASK) {
- case MODE_CISCO:
- dev->hard_header = cisco_hard_header;
- break;
-
-#ifdef CONFIG_HDLC_PPP
- case MODE_PPP:
- break;
-#endif
-#ifdef CONFIG_HDLC_X25
- case MODE_X25:
- break;
-#endif
-
- case MODE_FR:
- dev->hard_header = fr_hard_header;
- dev->addr_len = 2;
- *(u16*)dev->dev_addr = htons(LMI_DLCI);
- dlci_to_q922(dev->broadcast, LMI_DLCI);
- break;
-
- default:
- return -EINVAL;
- }
-
- result = hdlc->set_mode ?
- hdlc->set_mode(hdlc, MODE_HDLC) : 0;
- }
-
- if (result)
- return result;
-
- hdlc->mode = mode;
- switch(mode & MODE_MASK) {
-#ifdef CONFIG_HDLC_PPP
- case MODE_PPP: dev->type = ARPHRD_PPP; break;
-#endif
-#ifdef CONFIG_HDLC_X25
- case MODE_X25: dev->type = ARPHRD_X25; break;
-#endif
- case MODE_FR: dev->type = ARPHRD_FRAD; break;
- case MODE_CISCO: dev->type = ARPHRD_CISCO; break;
- default: dev->type = ARPHRD_RAWHDLC;
- }
-
- memset(&(hdlc->stats), 0, sizeof(struct net_device_stats));
- destroy_pvc_list(hdlc);
- return 0;
-}
-
-
-
-static int hdlc_fr_pvc(hdlc_device *hdlc, int dlci)
-{
- pvc_device **pvc_p = &hdlc->first_pvc;
- pvc_device *pvc;
- int result, create = 1; /* Create or delete PVC */
-
- if(!capable(CAP_NET_ADMIN))
- return -EPERM;
-
- if(dlci<0) {
- dlci = -dlci;
- create = 0;
- }
-
- if(dlci <= 0 || dlci >= 1024)
- return -EINVAL; /* Only 10 bits for DLCI, DLCI=0 is reserved */
-
- if(!mode_is(hdlc, MODE_FR))
- return -EINVAL; /* Only meaningfull on FR */
-
- while(*pvc_p) {
- if (netdev_dlci(&(*pvc_p)->netdev) == dlci)
- break;
- pvc_p = &(*pvc_p)->next;
- }
-
- if (create) { /* Create PVC */
- if (*pvc_p != NULL)
- return -EEXIST;
-
- pvc = *pvc_p = kmalloc(sizeof(pvc_device), GFP_KERNEL);
- if (!pvc) {
- printk(KERN_WARNING "%s: Memory squeeze on "
- "hdlc_fr_pvc()\n", hdlc_to_name(hdlc));
- return -ENOBUFS;
- }
- memset(pvc, 0, sizeof(pvc_device));
-
- pvc->netdev.hard_start_xmit = pvc_xmit;
- pvc->netdev.get_stats = pvc_get_stats;
- pvc->netdev.open = pvc_open;
- pvc->netdev.stop = pvc_close;
- pvc->netdev.change_mtu = pvc_change_mtu;
- pvc->netdev.mtu = HDLC_MAX_MTU;
-
- pvc->netdev.type = ARPHRD_DLCI;
- pvc->netdev.hard_header_len = 16;
- pvc->netdev.hard_header = fr_hard_header;
- pvc->netdev.tx_queue_len = 0;
- pvc->netdev.flags = IFF_POINTOPOINT;
-
- pvc->master = hdlc;
- *(u16*)pvc->netdev.dev_addr = htons(dlci);
- dlci_to_q922(pvc->netdev.broadcast, dlci);
- pvc->netdev.addr_len = 2;
- pvc->netdev.irq = hdlc_to_dev(hdlc)->irq;
-
- result = dev_alloc_name(&pvc->netdev, "pvc%d");
- if (result < 0) {
- kfree(pvc);
- *pvc_p = NULL;
- return result;
- }
-
- if (register_netdevice(&pvc->netdev) != 0) {
- kfree(pvc);
- *pvc_p = NULL;
- return -EIO;
- }
-
- if (!mode_is(hdlc, MODE_SOFT) && hdlc->create_pvc) {
- result = hdlc->create_pvc(pvc);
- if (result) {
- unregister_netdevice(&pvc->netdev);
- kfree(pvc);
- *pvc_p = NULL;
- return result;
- }
- }
-
- hdlc->lmi.state |= LINK_STATE_CHANGED;
- hdlc->pvc_count++;
- return 0;
- }
-
- if (*pvc_p == NULL) /* Delete PVC */
- return -ENOENT;
-
- pvc = *pvc_p;
-
- if (pvc->netdev.flags & IFF_UP)
- return -EBUSY; /* PVC in use */
-
- if (!mode_is(hdlc, MODE_SOFT) && hdlc->destroy_pvc)
- hdlc->destroy_pvc(pvc);
-
- hdlc->lmi.state |= LINK_STATE_CHANGED;
- hdlc->pvc_count--;
- *pvc_p = pvc->next;
- unregister_netdevice(&pvc->netdev);
- kfree(pvc);
- return 0;
-}
-
-
-
-static int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
-{
- hdlc_device *hdlc = dev_to_hdlc(dev);
-
- switch(cmd) {
- case HDLCGMODE:
- ifr->ifr_ifru.ifru_ivalue = hdlc->mode;
- return 0;
-
- case HDLCSMODE:
- return hdlc_set_mode(hdlc, ifr->ifr_ifru.ifru_ivalue);
-
- case HDLCPVC:
- return hdlc_fr_pvc(hdlc, ifr->ifr_ifru.ifru_ivalue);
-
- default:
- if (hdlc->ioctl != NULL)
- return hdlc->ioctl(hdlc, ifr, cmd);
- }
-
- return -EINVAL;
-}
-
-
-
-static int hdlc_init(struct net_device *dev)
-{
- hdlc_device *hdlc = dev_to_hdlc(dev);
-
- memset(&(hdlc->stats), 0, sizeof(struct net_device_stats));
-
- dev->get_stats = hdlc_get_stats;
- dev->open = hdlc_open;
- dev->stop = hdlc_close;
- dev->hard_start_xmit = hdlc_xmit;
- dev->do_ioctl = hdlc_ioctl;
- dev->change_mtu = hdlc_change_mtu;
- dev->mtu = HDLC_MAX_MTU;
-
- dev->type = ARPHRD_RAWHDLC;
- dev->hard_header_len = 16;
-
- dev->flags = IFF_POINTOPOINT | IFF_NOARP;
-
- return 0;
-}
-
-
-
-int register_hdlc_device(hdlc_device *hdlc)
-{
- int result;
- struct net_device *dev = hdlc_to_dev(hdlc);
-
- dev->init = hdlc_init;
- dev->priv = &hdlc->syncppp_ptr;
- hdlc->syncppp_ptr = &hdlc->pppdev;
- hdlc->pppdev.dev = dev;
- hdlc->mode = MODE_NONE;
- hdlc->lmi.T391 = 10; /* polling verification timer */
- hdlc->lmi.T392 = 15; /* link integrity verification polling timer */
- hdlc->lmi.N391 = 6; /* full status polling counter */
- hdlc->lmi.N392 = 3; /* error threshold */
- hdlc->lmi.N393 = 4; /* monitored events count */
-
- result = dev_alloc_name(dev, "hdlc%d");
- if (result<0)
- return result;
-
- result = register_netdev(dev);
- if (result != 0)
- return -EIO;
-
- MOD_INC_USE_COUNT;
- return 0;
-}
-
-
-
-void unregister_hdlc_device(hdlc_device *hdlc)
-{
- destroy_pvc_list(hdlc);
- unregister_netdev(hdlc_to_dev(hdlc));
- MOD_DEC_USE_COUNT;
-}
-
-MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
-MODULE_DESCRIPTION("HDLC support module");
-MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL(hdlc_netif_rx);
-EXPORT_SYMBOL(register_hdlc_device);
-EXPORT_SYMBOL(unregister_hdlc_device);
-
-static int __init hdlc_module_init(void)
-{
- printk(KERN_INFO "%s\n", version);
- return 0;
-}
-
-
-module_init(hdlc_module_init);
diff --git a/drivers/net/wan/hdlc_cisco.c b/drivers/net/wan/hdlc_cisco.c
new file mode 100644
index 000000000000..038db895a46f
--- /dev/null
+++ b/drivers/net/wan/hdlc_cisco.c
@@ -0,0 +1,293 @@
+/*
+ * Generic HDLC support routines for Linux
+ * Cisco HDLC support
+ *
+ * Copyright (C) 2000 - 2001 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/if_arp.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/pkt_sched.h>
+#include <linux/inetdevice.h>
+#include <linux/lapb.h>
+#include <linux/rtnetlink.h>
+#include <linux/hdlc.h>
+
+
+#define CISCO_MULTICAST 0x8F /* Cisco multicast address */
+#define CISCO_UNICAST 0x0F /* Cisco unicast address */
+#define CISCO_KEEPALIVE 0x8035 /* Cisco keepalive protocol */
+#define CISCO_SYS_INFO 0x2000 /* Cisco interface/system info */
+#define CISCO_ADDR_REQ 0 /* Cisco address request */
+#define CISCO_ADDR_REPLY 1 /* Cisco address reply */
+#define CISCO_KEEPALIVE_REQ 2 /* Cisco keepalive request */
+
+
+static int cisco_hard_header(struct sk_buff *skb, struct net_device *dev,
+ u16 type, void *daddr, void *saddr,
+ unsigned int len)
+{
+ hdlc_header *data;
+#ifdef CONFIG_HDLC_DEBUG_HARD_HEADER
+ printk(KERN_DEBUG "%s: cisco_hard_header called\n", dev->name);
+#endif
+
+ skb_push(skb, sizeof(hdlc_header));
+ data = (hdlc_header*)skb->data;
+ if (type == CISCO_KEEPALIVE)
+ data->address = CISCO_MULTICAST;
+ else
+ data->address = CISCO_UNICAST;
+ data->control = 0;
+ data->protocol = htons(type);
+
+ return sizeof(hdlc_header);
+}
+
+
+
+static void cisco_keepalive_send(hdlc_device *hdlc, u32 type,
+ u32 par1, u32 par2)
+{
+ struct sk_buff *skb;
+ cisco_packet *data;
+
+ skb = dev_alloc_skb(sizeof(hdlc_header) + sizeof(cisco_packet));
+ if (!skb) {
+ printk(KERN_WARNING
+ "%s: Memory squeeze on cisco_keepalive_send()\n",
+ hdlc_to_name(hdlc));
+ return;
+ }
+ skb_reserve(skb, 4);
+ cisco_hard_header(skb, hdlc_to_dev(hdlc), CISCO_KEEPALIVE,
+ NULL, NULL, 0);
+ data = (cisco_packet*)skb->tail;
+
+ data->type = htonl(type);
+ data->par1 = htonl(par1);
+ data->par2 = htonl(par2);
+ data->rel = 0xFFFF;
+ data->time = htonl(jiffies * 1000 / HZ);
+
+ skb_put(skb, sizeof(cisco_packet));
+ skb->priority = TC_PRIO_CONTROL;
+ skb->dev = hdlc_to_dev(hdlc);
+
+ dev_queue_xmit(skb);
+}
+
+
+
+static void cisco_rx(struct sk_buff *skb)
+{
+ hdlc_device *hdlc = dev_to_hdlc(skb->dev);
+ hdlc_header *data = (hdlc_header*)skb->data;
+ cisco_packet *cisco_data;
+ struct in_device *in_dev;
+ u32 addr, mask;
+
+ if (skb->len < sizeof(hdlc_header))
+ goto rx_error;
+
+ if (data->address != CISCO_MULTICAST &&
+ data->address != CISCO_UNICAST)
+ goto rx_error;
+
+ skb_pull(skb, sizeof(hdlc_header));
+
+ switch(ntohs(data->protocol)) {
+ case ETH_P_IP:
+ case ETH_P_IPX:
+ case ETH_P_IPV6:
+ skb->protocol = data->protocol;
+ skb->dev = hdlc_to_dev(hdlc);
+ netif_rx(skb);
+ return;
+
+ case CISCO_SYS_INFO:
+ /* Packet is not needed, drop it. */
+ dev_kfree_skb_any(skb);
+ return;
+
+ case CISCO_KEEPALIVE:
+ if (skb->len != CISCO_PACKET_LEN &&
+ skb->len != CISCO_BIG_PACKET_LEN) {
+ printk(KERN_INFO "%s: Invalid length of Cisco "
+ "control packet (%d bytes)\n",
+ hdlc_to_name(hdlc), skb->len);
+ goto rx_error;
+ }
+
+ cisco_data = (cisco_packet*)skb->data;
+
+ switch(ntohl (cisco_data->type)) {
+ case CISCO_ADDR_REQ: /* Stolen from syncppp.c :-) */
+ in_dev = hdlc_to_dev(hdlc)->ip_ptr;
+ addr = 0;
+ mask = ~0; /* is the mask correct? */
+
+ if (in_dev != NULL) {
+ struct in_ifaddr **ifap = &in_dev->ifa_list;
+
+ while (*ifap != NULL) {
+ if (strcmp(hdlc_to_name(hdlc),
+ (*ifap)->ifa_label) == 0) {
+ addr = (*ifap)->ifa_local;
+ mask = (*ifap)->ifa_mask;
+ break;
+ }
+ ifap = &(*ifap)->ifa_next;
+ }
+
+ cisco_keepalive_send(hdlc, CISCO_ADDR_REPLY,
+ addr, mask);
+ }
+ dev_kfree_skb_any(skb);
+ return;
+
+ case CISCO_ADDR_REPLY:
+ printk(KERN_INFO "%s: Unexpected Cisco IP address "
+ "reply\n", hdlc_to_name(hdlc));
+ goto rx_error;
+
+ case CISCO_KEEPALIVE_REQ:
+ hdlc->state.cisco.rxseq = ntohl(cisco_data->par1);
+ if (ntohl(cisco_data->par2) == hdlc->state.cisco.txseq) {
+ hdlc->state.cisco.last_poll = jiffies;
+ if (!hdlc->state.cisco.up) {
+ u32 sec, min, hrs, days;
+ sec = ntohl(cisco_data->time) / 1000;
+ min = sec / 60; sec -= min * 60;
+ hrs = min / 60; min -= hrs * 60;
+ days = hrs / 24; hrs -= days * 24;
+ printk(KERN_INFO "%s: Link up (peer "
+ "uptime %ud%uh%um%us)\n",
+ hdlc_to_name(hdlc), days, hrs,
+ min, sec);
+ }
+ hdlc->state.cisco.up = 1;
+ }
+
+ dev_kfree_skb_any(skb);
+ return;
+ } /* switch(keepalive type) */
+ } /* switch(protocol) */
+
+ printk(KERN_INFO "%s: Unsupported protocol %x\n", hdlc_to_name(hdlc),
+ data->protocol);
+ dev_kfree_skb_any(skb);
+ return;
+
+ rx_error:
+ hdlc->stats.rx_errors++; /* Mark error */
+ dev_kfree_skb_any(skb);
+}
+
+
+
+static void cisco_timer(unsigned long arg)
+{
+ hdlc_device *hdlc = (hdlc_device*)arg;
+
+ if (hdlc->state.cisco.up &&
+ jiffies - hdlc->state.cisco.last_poll >=
+ hdlc->state.cisco.settings.timeout * HZ) {
+ hdlc->state.cisco.up = 0;
+ printk(KERN_INFO "%s: Link down\n", hdlc_to_name(hdlc));
+ }
+
+ cisco_keepalive_send(hdlc, CISCO_KEEPALIVE_REQ,
+ ++hdlc->state.cisco.txseq,
+ hdlc->state.cisco.rxseq);
+ hdlc->state.cisco.timer.expires = jiffies +
+ hdlc->state.cisco.settings.interval * HZ;
+ hdlc->state.cisco.timer.function = cisco_timer;
+ hdlc->state.cisco.timer.data = arg;
+ add_timer(&hdlc->state.cisco.timer);
+}
+
+
+
+static int cisco_open(hdlc_device *hdlc)
+{
+ hdlc->state.cisco.last_poll = 0;
+ hdlc->state.cisco.up = 0;
+ hdlc->state.cisco.txseq = hdlc->state.cisco.rxseq = 0;
+
+ init_timer(&hdlc->state.cisco.timer);
+ hdlc->state.cisco.timer.expires = jiffies + HZ; /*First poll after 1s*/
+ hdlc->state.cisco.timer.function = cisco_timer;
+ hdlc->state.cisco.timer.data = (unsigned long)hdlc;
+ add_timer(&hdlc->state.cisco.timer);
+ return 0;
+}
+
+
+
+static void cisco_close(hdlc_device *hdlc)
+{
+ del_timer_sync(&hdlc->state.cisco.timer);
+}
+
+
+
+int hdlc_cisco_ioctl(hdlc_device *hdlc, struct ifreq *ifr)
+{
+ cisco_proto *cisco_s = &ifr->ifr_settings->ifs_hdlc.cisco;
+ const size_t size = sizeof(cisco_proto);
+ struct net_device *dev = hdlc_to_dev(hdlc);
+ int result;
+
+ switch (ifr->ifr_settings->type) {
+ case IF_GET_PROTO:
+ ifr->ifr_settings->type = IF_PROTO_CISCO;
+ if (copy_to_user(cisco_s, &hdlc->state.cisco.settings, size))
+ return -EFAULT;
+ return 0;
+
+ case IF_PROTO_CISCO:
+ if(!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ if(dev->flags & IFF_UP)
+ return -EBUSY;
+
+ if (copy_from_user(&hdlc->state.cisco.settings, cisco_s, size))
+ return -EFAULT;
+
+ /* FIXME - put sanity checks here */
+ hdlc_detach(hdlc);
+
+ result=hdlc->attach(hdlc, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT);
+ if (result) {
+ hdlc->proto = -1;
+ return result;
+ }
+
+ hdlc->open = cisco_open;
+ hdlc->stop = cisco_close;
+ hdlc->netif_rx = cisco_rx;
+ hdlc->proto = IF_PROTO_CISCO;
+ dev->hard_start_xmit = hdlc->xmit;
+ dev->hard_header = cisco_hard_header;
+ dev->type = ARPHRD_CISCO;
+ dev->addr_len = 0;
+ return 0;
+ }
+
+ return -EINVAL;
+}
diff --git a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c
new file mode 100644
index 000000000000..b0b9d6743299
--- /dev/null
+++ b/drivers/net/wan/hdlc_fr.c
@@ -0,0 +1,842 @@
+/*
+ * Generic HDLC support routines for Linux
+ * Frame Relay support
+ *
+ * Copyright (C) 1999 - 2001 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/if_arp.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/pkt_sched.h>
+#include <linux/inetdevice.h>
+#include <linux/lapb.h>
+#include <linux/rtnetlink.h>
+#include <linux/hdlc.h>
+
+
+__inline__ pvc_device* find_pvc(hdlc_device *hdlc, u16 dlci)
+{
+ pvc_device *pvc=hdlc->state.fr.first_pvc;
+
+ while (pvc) {
+ if (netdev_dlci(&pvc->netdev) == dlci)
+ return pvc;
+ pvc = pvc->next;
+ }
+
+ return NULL;
+}
+
+
+
+__inline__ u16 status_to_dlci(hdlc_device *hdlc, u8 *status,
+ int *active, int *new)
+{
+ *new = (status[2] & 0x08);
+ *active = (!*new && (status[2] & 0x02));
+
+ return ((status[0] & 0x3F)<<4) | ((status[1] & 0x78)>>3);
+}
+
+
+__inline__ void dlci_to_status(hdlc_device *hdlc, u16 dlci, u8 *status,
+ int active, int new)
+{
+ status[0] = (dlci>>4) & 0x3F;
+ status[1] = ((dlci<<3) & 0x78) | 0x80;
+ status[2] = 0x80;
+
+ if (new)
+ status[2] |= 0x08;
+ else if (active)
+ status[2] |= 0x02;
+}
+
+
+
+static int fr_hard_header(struct sk_buff *skb, struct net_device *dev,
+ u16 type, void *daddr, void *saddr, unsigned int len)
+{
+ u16 head_len;
+
+ if (!daddr)
+ daddr = dev->broadcast;
+
+#ifdef CONFIG_HDLC_DEBUG_HARD_HEADER
+ printk(KERN_DEBUG "%s: fr_hard_header called\n", dev->name);
+#endif
+
+ switch(type) {
+ case ETH_P_IP:
+ head_len = 4;
+ skb_push(skb, head_len);
+ skb->data[3] = NLPID_IP;
+ break;
+
+ case ETH_P_IPV6:
+ head_len = 4;
+ skb_push(skb, head_len);
+ skb->data[3] = NLPID_IPV6;
+ break;
+
+ case LMI_PROTO:
+ head_len = 4;
+ skb_push(skb, head_len);
+ skb->data[3] = LMI_PROTO;
+ break;
+
+ default:
+ head_len = 10;
+ skb_push(skb, head_len);
+ skb->data[3] = FR_PAD;
+ skb->data[4] = NLPID_SNAP;
+ skb->data[5] = FR_PAD;
+ skb->data[6] = FR_PAD;
+ skb->data[7] = FR_PAD;
+ skb->data[8] = type>>8;
+ skb->data[9] = (u8)type;
+ }
+
+ memcpy(skb->data, daddr, 2);
+ skb->data[2] = FR_UI;
+
+ return head_len;
+}
+
+
+
+static int pvc_open(struct net_device *dev)
+{
+ pvc_device *pvc = dev_to_pvc(dev);
+
+ if ((hdlc_to_dev(pvc->master)->flags & IFF_UP) == 0)
+ return -EIO; /* Master must be UP in order to activate PVC */
+
+ if (pvc->master->state.fr.settings.lmi != LMI_NONE)
+ pvc->state.active = 0;
+ else
+ pvc->state.active = 1;
+
+ pvc->state.new = 0;
+ pvc->master->state.fr.changed = 1;
+ return 0;
+}
+
+
+
+static int pvc_close(struct net_device *dev)
+{
+ pvc_device *pvc = dev_to_pvc(dev);
+ pvc->state.active = pvc->state.new = 0;
+ pvc->master->state.fr.changed = 1;
+ return 0;
+}
+
+
+
+static int pvc_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ pvc_device *pvc = dev_to_pvc(dev);
+
+ if (pvc->state.active) {
+ skb->dev = hdlc_to_dev(pvc->master);
+ pvc->stats.tx_bytes += skb->len;
+ pvc->stats.tx_packets++;
+ if (pvc->state.fecn)
+ pvc->stats.tx_compressed++; /* TX Congestion counter */
+ dev_queue_xmit(skb);
+ } else {
+ pvc->stats.tx_dropped++;
+ dev_kfree_skb(skb);
+ }
+
+ return 0;
+}
+
+
+
+static struct net_device_stats *pvc_get_stats(struct net_device *dev)
+{
+ pvc_device *pvc = dev_to_pvc(dev);
+ return &pvc->stats;
+}
+
+
+
+static int pvc_change_mtu(struct net_device *dev, int new_mtu)
+{
+ if ((new_mtu < 68) || (new_mtu > HDLC_MAX_MTU))
+ return -EINVAL;
+ dev->mtu = new_mtu;
+ return 0;
+}
+
+
+
+static inline void fr_log_dlci_active(pvc_device *pvc)
+{
+ printk(KERN_INFO "%s: %sactive%s\n", pvc_to_name(pvc),
+ pvc->state.active ? "" : "in",
+ pvc->state.new ? " new" : "");
+}
+
+
+
+static inline u8 fr_lmi_nextseq(u8 x)
+{
+ x++;
+ return x ? x : 1;
+}
+
+
+
+static void fr_lmi_send(hdlc_device *hdlc, int fullrep)
+{
+ struct sk_buff *skb;
+ pvc_device *pvc = hdlc->state.fr.first_pvc;
+ int len = (hdlc->state.fr.settings.lmi == LMI_ANSI) ? LMI_ANSI_LENGTH
+ : LMI_LENGTH;
+ int stat_len = 3;
+ u8 *data;
+ int i = 0;
+
+ if (hdlc->state.fr.settings.dce && fullrep) {
+ len += hdlc->state.fr.pvc_count * (2 + stat_len);
+ if (len > HDLC_MAX_MTU) {
+ printk(KERN_WARNING "%s: Too many PVCs while sending "
+ "LMI full report\n", hdlc_to_name(hdlc));
+ return;
+ }
+ }
+
+ skb = dev_alloc_skb(len);
+ if (!skb) {
+ printk(KERN_WARNING "%s: Memory squeeze on fr_lmi_send()\n",
+ hdlc_to_name(hdlc));
+ return;
+ }
+ memset(skb->data, 0, len);
+ skb_reserve(skb, 4);
+ fr_hard_header(skb, hdlc_to_dev(hdlc), LMI_PROTO, NULL, NULL, 0);
+ data = skb->tail;
+ data[i++] = LMI_CALLREF;
+ data[i++] = hdlc->state.fr.settings.dce
+ ? LMI_STATUS : LMI_STATUS_ENQUIRY;
+ if (hdlc->state.fr.settings.lmi == LMI_ANSI)
+ data[i++] = LMI_ANSI_LOCKSHIFT;
+ data[i++] = (hdlc->state.fr.settings.lmi == LMI_CCITT)
+ ? LMI_CCITT_REPTYPE : LMI_REPTYPE;
+ data[i++] = LMI_REPT_LEN;
+ data[i++] = fullrep ? LMI_FULLREP : LMI_INTEGRITY;
+
+ data[i++] = (hdlc->state.fr.settings.lmi == LMI_CCITT)
+ ? LMI_CCITT_ALIVE : LMI_ALIVE;
+ data[i++] = LMI_INTEG_LEN;
+ data[i++] = hdlc->state.fr.txseq =fr_lmi_nextseq(hdlc->state.fr.txseq);
+ data[i++] = hdlc->state.fr.rxseq;
+
+ if (hdlc->state.fr.settings.dce && fullrep) {
+ while (pvc) {
+ data[i++] = (hdlc->state.fr.settings.lmi == LMI_CCITT)
+ ? LMI_CCITT_PVCSTAT : LMI_PVCSTAT;
+ data[i++] = stat_len;
+
+ if (hdlc->state.fr.reliable &&
+ (pvc->netdev.flags & IFF_UP) &&
+ !pvc->state.active &&
+ !pvc->state.new) {
+ pvc->state.new = 1;
+ fr_log_dlci_active(pvc);
+ }
+
+ dlci_to_status(hdlc, netdev_dlci(&pvc->netdev),
+ data + i,
+ pvc->state.active, pvc->state.new);
+ i += stat_len;
+ pvc = pvc->next;
+ }
+ }
+
+ skb_put(skb, i);
+ skb->priority = TC_PRIO_CONTROL;
+ skb->dev = hdlc_to_dev(hdlc);
+
+ dev_queue_xmit(skb);
+}
+
+
+
+static void fr_timer(unsigned long arg)
+{
+ hdlc_device *hdlc = (hdlc_device*)arg;
+ int i, cnt = 0, reliable;
+ u32 list;
+
+ if (hdlc->state.fr.settings.dce)
+ reliable = (jiffies - hdlc->state.fr.last_poll <
+ hdlc->state.fr.settings.t392 * HZ);
+ else {
+ hdlc->state.fr.last_errors <<= 1; /* Shift the list */
+ if (hdlc->state.fr.request) {
+ if (hdlc->state.fr.reliable)
+ printk(KERN_INFO "%s: No LMI status reply "
+ "received\n", hdlc_to_name(hdlc));
+ hdlc->state.fr.last_errors |= 1;
+ }
+
+ list = hdlc->state.fr.last_errors;
+ for (i = 0; i < hdlc->state.fr.settings.n393; i++, list >>= 1)
+ cnt += (list & 1); /* errors count */
+
+ reliable = (cnt < hdlc->state.fr.settings.n392);
+ }
+
+ if (hdlc->state.fr.reliable != reliable) {
+ pvc_device *pvc = hdlc->state.fr.first_pvc;
+
+ hdlc->state.fr.reliable = reliable;
+ printk(KERN_INFO "%s: Link %sreliable\n", hdlc_to_name(hdlc),
+ reliable ? "" : "un");
+
+ if (reliable) {
+ hdlc->state.fr.n391cnt = 0; /* Request full status */
+ hdlc->state.fr.changed = 1;
+ } else {
+ while (pvc) { /* Deactivate all PVCs */
+ pvc->state.new = pvc->state.active = 0;
+ pvc = pvc->next;
+ }
+ }
+ }
+
+ if (hdlc->state.fr.settings.dce)
+ hdlc->state.fr.timer.expires = jiffies +
+ hdlc->state.fr.settings.t392 * HZ;
+ else {
+ if (hdlc->state.fr.n391cnt)
+ hdlc->state.fr.n391cnt--;
+
+ fr_lmi_send(hdlc, hdlc->state.fr.n391cnt == 0);
+
+ hdlc->state.fr.request = 1;
+ hdlc->state.fr.timer.expires = jiffies +
+ hdlc->state.fr.settings.t391 * HZ;
+ }
+
+ hdlc->state.fr.timer.function = fr_timer;
+ hdlc->state.fr.timer.data = arg;
+ add_timer(&hdlc->state.fr.timer);
+}
+
+
+
+static int fr_lmi_recv(hdlc_device *hdlc, struct sk_buff *skb)
+{
+ int stat_len;
+ pvc_device *pvc;
+ int reptype = -1, error;
+ u8 rxseq, txseq;
+ int i;
+
+ if (skb->len < ((hdlc->state.fr.settings.lmi == LMI_ANSI)
+ ? LMI_ANSI_LENGTH : LMI_LENGTH)) {
+ printk(KERN_INFO "%s: Short LMI frame\n", hdlc_to_name(hdlc));
+ return 1;
+ }
+
+ if (skb->data[5] != (!hdlc->state.fr.settings.dce ?
+ LMI_STATUS : LMI_STATUS_ENQUIRY)) {
+ printk(KERN_INFO "%s: LMI msgtype=%x, Not LMI status %s\n",
+ hdlc_to_name(hdlc), skb->data[2],
+ hdlc->state.fr.settings.dce ? "enquiry" : "reply");
+ return 1;
+ }
+
+ i = (hdlc->state.fr.settings.lmi == LMI_ANSI) ? 7 : 6;
+
+ if (skb->data[i] !=
+ ((hdlc->state.fr.settings.lmi == LMI_CCITT)
+ ? LMI_CCITT_REPTYPE : LMI_REPTYPE)) {
+ printk(KERN_INFO "%s: Not a report type=%x\n",
+ hdlc_to_name(hdlc), skb->data[i]);
+ return 1;
+ }
+ i++;
+
+ i++; /* Skip length field */
+
+ reptype = skb->data[i++];
+
+ if (skb->data[i]!=
+ ((hdlc->state.fr.settings.lmi == LMI_CCITT)
+ ? LMI_CCITT_ALIVE : LMI_ALIVE)) {
+ printk(KERN_INFO "%s: Unsupported status element=%x\n",
+ hdlc_to_name(hdlc), skb->data[i]);
+ return 1;
+ }
+ i++;
+
+ i++; /* Skip length field */
+
+ hdlc->state.fr.rxseq = skb->data[i++]; /* TX sequence from peer */
+ rxseq = skb->data[i++]; /* Should confirm our sequence */
+
+ txseq = hdlc->state.fr.txseq;
+
+ if (hdlc->state.fr.settings.dce) {
+ if (reptype != LMI_FULLREP && reptype != LMI_INTEGRITY) {
+ printk(KERN_INFO "%s: Unsupported report type=%x\n",
+ hdlc_to_name(hdlc), reptype);
+ return 1;
+ }
+ }
+
+ error = 0;
+ if (!hdlc->state.fr.reliable)
+ error = 1;
+
+ if (rxseq == 0 || rxseq != txseq) {
+ hdlc->state.fr.n391cnt = 0; /* Ask for full report next time */
+ error = 1;
+ }
+
+ if (hdlc->state.fr.settings.dce) {
+ if (hdlc->state.fr.fullrep_sent && !error) {
+/* Stop sending full report - the last one has been confirmed by DTE */
+ hdlc->state.fr.fullrep_sent = 0;
+ pvc = hdlc->state.fr.first_pvc;
+ while (pvc) {
+ if (pvc->state.new) {
+ pvc->state.new = 0;
+ pvc->state.active = 1;
+ fr_log_dlci_active(pvc);
+
+/* Tell DTE that new PVC is now active */
+ hdlc->state.fr.changed = 1;
+ }
+ pvc = pvc->next;
+ }
+ }
+
+ if (hdlc->state.fr.changed) {
+ reptype = LMI_FULLREP;
+ hdlc->state.fr.fullrep_sent = 1;
+ hdlc->state.fr.changed = 0;
+ }
+
+ fr_lmi_send(hdlc, reptype == LMI_FULLREP ? 1 : 0);
+ return 0;
+ }
+
+ /* DTE */
+
+ if (reptype != LMI_FULLREP || error)
+ return 0;
+
+ stat_len = 3;
+ pvc = hdlc->state.fr.first_pvc;
+
+ while (pvc) {
+ pvc->state.deleted = pvc->state.active; /* mark active PVCs */
+ pvc = pvc->next;
+ }
+
+ while (skb->len >= i + 2 + stat_len) {
+ u16 dlci;
+ int active, new;
+
+ if (skb->data[i] != ((hdlc->state.fr.settings.lmi == LMI_CCITT)
+ ? LMI_CCITT_PVCSTAT : LMI_PVCSTAT)) {
+ printk(KERN_WARNING "%s: Invalid PVCSTAT ID: %x\n",
+ hdlc_to_name(hdlc), skb->data[i]);
+ return 1;
+ }
+ i++;
+
+ if (skb->data[i] != stat_len) {
+ printk(KERN_WARNING "%s: Invalid PVCSTAT length: %x\n",
+ hdlc_to_name(hdlc), skb->data[i]);
+ return 1;
+ }
+ i++;
+
+ dlci = status_to_dlci(hdlc, skb->data + i, &active, &new);
+ pvc = find_pvc(hdlc, dlci);
+
+ active |= new;
+ if (pvc) {
+ if (active && !pvc->state.active &&
+ (pvc->netdev.flags & IFF_UP)) {
+ pvc->state.active = active;
+ fr_log_dlci_active(pvc);
+ }
+ pvc->state.deleted = 0;
+ }
+ else if (new)
+ printk(KERN_INFO "%s: new PVC available, DLCI=%u\n",
+ hdlc_to_name(hdlc), dlci);
+
+ i += stat_len;
+ }
+
+ pvc = hdlc->state.fr.first_pvc;
+
+ while (pvc) {
+ if (pvc->state.deleted) {
+ pvc->state.active = pvc->state.new = 0;
+ fr_log_dlci_active(pvc);
+ pvc->state.deleted = 0;
+ }
+ pvc = pvc->next;
+ }
+
+ /* Next full report after N391 polls */
+ hdlc->state.fr.n391cnt = hdlc->state.fr.settings.n391;
+
+ return 0;
+}
+
+
+
+static void fr_rx(struct sk_buff *skb)
+{
+ hdlc_device *hdlc = dev_to_hdlc(skb->dev);
+ fr_hdr *fh = (fr_hdr*)skb->data;
+ u8 *data = skb->data;
+ u16 dlci;
+ pvc_device *pvc;
+
+ if (skb->len<4 || fh->ea1 || data[2] != FR_UI)
+ goto rx_error;
+
+ dlci = q922_to_dlci(skb->data);
+
+ if (dlci == LMI_DLCI) {
+ if (hdlc->state.fr.settings.lmi == LMI_NONE)
+ goto rx_error; /* LMI packet with no LMI? */
+
+ if (data[3] == LMI_PROTO) {
+ if (fr_lmi_recv(hdlc, skb))
+ goto rx_error;
+ else {
+ /* No request pending */
+ hdlc->state.fr.request = 0;
+ hdlc->state.fr.last_poll = jiffies;
+ dev_kfree_skb_any(skb);
+ return;
+ }
+ }
+
+ printk(KERN_INFO "%s: Received non-LMI frame with LMI DLCI\n",
+ hdlc_to_name(hdlc));
+ goto rx_error;
+ }
+
+ pvc = find_pvc(hdlc, dlci);
+ if (!pvc) {
+#ifdef CONFIG_HDLC_DEBUG_PKT
+ printk(KERN_INFO "%s: No PVC for received frame's DLCI %d\n",
+ hdlc_to_name(hdlc), dlci);
+#endif
+ goto rx_error;
+ }
+
+ if ((pvc->netdev.flags & IFF_UP) == 0) {
+#ifdef CONFIG_HDLC_DEBUG_PKT
+ printk(KERN_INFO "%s: PVC for received frame's DLCI %d is down\n",
+ hdlc_to_name(hdlc), dlci);
+#endif
+ goto rx_error;
+ }
+
+ pvc->stats.rx_packets++; /* PVC traffic */
+ pvc->stats.rx_bytes += skb->len;
+
+ if (pvc->state.fecn != (fh->fecn ? PVC_STATE_FECN : 0)) {
+#ifdef CONFIG_HDLC_DEBUG_ECN
+ printk(KERN_DEBUG "%s: FECN O%s\n", pvc_to_name(pvc),
+ fh->fecn ? "N" : "FF");
+#endif
+ pvc->state.fecn ^= 1;
+ }
+
+ if (pvc->state.becn != (fh->becn ? PVC_STATE_BECN : 0)) {
+#ifdef CONFIG_HDLC_DEBUG_ECN
+ printk(KERN_DEBUG "%s: BECN O%s\n", pvc_to_name(pvc),
+ fh->becn ? "N" : "FF");
+#endif
+ pvc->state.becn ^= 1;
+ }
+
+ if (pvc->state.becn)
+ pvc->stats.rx_compressed++;
+
+ skb->dev = &pvc->netdev;
+
+ if (data[3] == NLPID_IP) {
+ skb_pull(skb, 4); /* Remove 4-byte header (hdr, UI, NLPID) */
+ skb->protocol = htons(ETH_P_IP);
+ netif_rx(skb);
+ return;
+ }
+
+
+ if (data[3] == NLPID_IPV6) {
+ skb_pull(skb, 4); /* Remove 4-byte header (hdr, UI, NLPID) */
+ skb->protocol = htons(ETH_P_IPV6);
+ netif_rx(skb);
+ return;
+ }
+
+ if (data[3] == FR_PAD && data[4] == NLPID_SNAP && data[5] == FR_PAD) {
+ u16 oui = ntohl(*(u16*)(data + 6));
+ u16 pid = ntohl(*(u16*)(data + 8));
+ skb_pull(skb, 10);
+
+ switch ((((u32)oui) << 16) | pid) {
+ case ETH_P_ARP: /* routed frame with SNAP */
+ case ETH_P_IPX:
+ skb->protocol = htons(pid);
+ break;
+
+ default:
+ printk(KERN_INFO "%s: Unsupported protocol, OUI=%x "
+ "PID=%x\n", hdlc_to_name(hdlc), oui, pid);
+ dev_kfree_skb_any(skb);
+ return;
+ }
+
+ netif_rx(skb);
+ return;
+ }
+
+ printk(KERN_INFO "%s: Unsupported protocol, NLPID=%x\n",
+ hdlc_to_name(hdlc), data[3]);
+ dev_kfree_skb_any(skb);
+ return;
+
+ rx_error:
+ hdlc->stats.rx_errors++; /* Mark error */
+ dev_kfree_skb_any(skb);
+}
+
+
+
+static int fr_open(hdlc_device *hdlc)
+{
+ if (hdlc->state.fr.settings.lmi != LMI_NONE) {
+ hdlc->state.fr.last_poll = 0;
+ hdlc->state.fr.reliable = 0;
+ hdlc->state.fr.changed = 1;
+ hdlc->state.fr.request = 0;
+ hdlc->state.fr.fullrep_sent = 0;
+ hdlc->state.fr.last_errors = 0xFFFFFFFF;
+ hdlc->state.fr.n391cnt = 0;
+ hdlc->state.fr.txseq = hdlc->state.fr.rxseq = 0;
+
+ init_timer(&hdlc->state.fr.timer);
+ /* First poll after 1 s */
+ hdlc->state.fr.timer.expires = jiffies + HZ;
+ hdlc->state.fr.timer.function = fr_timer;
+ hdlc->state.fr.timer.data = (unsigned long)hdlc;
+ add_timer(&hdlc->state.fr.timer);
+ } else
+ hdlc->state.fr.reliable = 1;
+
+ return 0;
+}
+
+
+
+static void fr_close(hdlc_device *hdlc)
+{
+ pvc_device *pvc = hdlc->state.fr.first_pvc;
+
+ if (hdlc->state.fr.settings.lmi != LMI_NONE)
+ del_timer_sync(&hdlc->state.fr.timer);
+
+ while(pvc) {
+ dev_close(&pvc->netdev); /* Shutdown all PVCs for this FRAD */
+ pvc = pvc->next;
+ }
+}
+
+
+
+static int fr_pvc(hdlc_device *hdlc, unsigned int dlci, int create)
+{
+ pvc_device **pvc_p = &hdlc->state.fr.first_pvc;
+ pvc_device *pvc;
+ int result;
+
+ if(dlci <= 0 || dlci >= 1024)
+ return -EINVAL; /* Only 10 bits for DLCI, DLCI 0 reserved */
+
+ while(*pvc_p) {
+ if (netdev_dlci(&(*pvc_p)->netdev) == dlci)
+ break;
+ pvc_p = &(*pvc_p)->next;
+ }
+
+ if (create) { /* Create PVC */
+ if (*pvc_p != NULL)
+ return -EEXIST;
+
+ pvc = *pvc_p = kmalloc(sizeof(pvc_device), GFP_KERNEL);
+ if (!pvc) {
+ printk(KERN_WARNING "%s: Memory squeeze on fr_pvc()\n",
+ hdlc_to_name(hdlc));
+ return -ENOBUFS;
+ }
+ memset(pvc, 0, sizeof(pvc_device));
+
+ pvc->netdev.hard_start_xmit = pvc_xmit;
+ pvc->netdev.get_stats = pvc_get_stats;
+ pvc->netdev.open = pvc_open;
+ pvc->netdev.stop = pvc_close;
+ pvc->netdev.change_mtu = pvc_change_mtu;
+ pvc->netdev.mtu = HDLC_MAX_MTU;
+
+ pvc->netdev.type = ARPHRD_DLCI;
+ pvc->netdev.hard_header_len = 16;
+ pvc->netdev.hard_header = fr_hard_header;
+ pvc->netdev.tx_queue_len = 0;
+ pvc->netdev.flags = IFF_POINTOPOINT;
+
+ pvc->master = hdlc;
+ *(u16*)pvc->netdev.dev_addr = htons(dlci);
+ dlci_to_q922(pvc->netdev.broadcast, dlci);
+ pvc->netdev.addr_len = 2;
+
+ result = dev_alloc_name(&pvc->netdev, "pvc%d");
+ if (result < 0) {
+ kfree(pvc);
+ *pvc_p = NULL;
+ return result;
+ }
+
+ if (register_netdevice(&pvc->netdev) != 0) {
+ kfree(pvc);
+ *pvc_p = NULL;
+ return -EIO;
+ }
+
+ hdlc->state.fr.changed = 1;
+ hdlc->state.fr.pvc_count++;
+ return 0;
+ }
+
+ if (*pvc_p == NULL) /* Delete PVC */
+ return -ENOENT;
+
+ pvc = *pvc_p;
+
+ if (pvc->netdev.flags & IFF_UP)
+ return -EBUSY; /* PVC in use */
+
+ hdlc->state.fr.changed = 1;
+ hdlc->state.fr.pvc_count--;
+ *pvc_p = pvc->next;
+ unregister_netdevice(&pvc->netdev);
+ kfree(pvc);
+ return 0;
+}
+
+
+
+static void fr_destroy(hdlc_device *hdlc)
+{
+ pvc_device *pvc = hdlc->state.fr.first_pvc;
+ while(pvc) {
+ pvc_device *next = pvc->next;
+ unregister_netdevice(&pvc->netdev);
+ kfree(pvc);
+ pvc = next;
+ }
+
+ hdlc->state.fr.first_pvc = NULL; /* All PVCs destroyed */
+ hdlc->state.fr.pvc_count = 0;
+ hdlc->state.fr.changed = 1;
+}
+
+
+
+int hdlc_fr_ioctl(hdlc_device *hdlc, struct ifreq *ifr)
+{
+ fr_proto *fr_s = &ifr->ifr_settings->ifs_hdlc.fr;
+ const size_t size = sizeof(fr_proto);
+ struct net_device *dev = hdlc_to_dev(hdlc);
+ fr_proto_pvc pvc;
+ int result;
+
+ switch (ifr->ifr_settings->type) {
+ case IF_GET_PROTO:
+ ifr->ifr_settings->type = IF_PROTO_FR;
+ if (copy_to_user(fr_s, &hdlc->state.fr.settings, size))
+ return -EFAULT;
+ return 0;
+
+ case IF_PROTO_FR:
+ if(!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ if(dev->flags & IFF_UP)
+ return -EBUSY;
+
+ if (copy_from_user(&hdlc->state.fr.settings, fr_s, size))
+ return -EFAULT;
+
+ /* FIXME - put sanity checks here */
+ if (hdlc->proto != IF_PROTO_FR) {
+ hdlc_detach(hdlc);
+ hdlc->state.fr.first_pvc = NULL;
+ hdlc->state.fr.pvc_count = 0;
+ }
+
+ result=hdlc->attach(hdlc, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT);
+ if (result) {
+ hdlc->proto = -1;
+ return result;
+ }
+
+ hdlc->open = fr_open;
+ hdlc->stop = fr_close;
+ hdlc->netif_rx = fr_rx;
+ hdlc->detach = fr_destroy;
+ hdlc->proto = IF_PROTO_FR;
+ dev->hard_start_xmit = hdlc->xmit;
+ dev->hard_header = fr_hard_header;
+ dev->type = ARPHRD_FRAD;
+ dev->addr_len = 2;
+ *(u16*)dev->dev_addr = htons(LMI_DLCI);
+ dlci_to_q922(dev->broadcast, LMI_DLCI);
+ return 0;
+
+ case IF_PROTO_FR_ADD_PVC:
+ case IF_PROTO_FR_DEL_PVC:
+ if(!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ if (copy_from_user(&pvc, &ifr->ifr_settings->ifs_hdlc.fr_pvc,
+ sizeof(fr_proto_pvc)))
+ return -EFAULT;
+
+ return fr_pvc(hdlc, pvc.dlci,
+ ifr->ifr_settings->type == IF_PROTO_FR_ADD_PVC);
+ }
+
+ return -EINVAL;
+}
diff --git a/drivers/net/wan/hdlc_generic.c b/drivers/net/wan/hdlc_generic.c
new file mode 100644
index 000000000000..4f74808cbd7b
--- /dev/null
+++ b/drivers/net/wan/hdlc_generic.c
@@ -0,0 +1,188 @@
+/*
+ * Generic HDLC support routines for Linux
+ *
+ * Copyright (C) 1999 - 2001 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Current status:
+ * - this is work in progress
+ * - not heavily tested on SMP
+ * - currently supported:
+ * * raw IP-in-HDLC
+ * * Cisco HDLC
+ * * Frame Relay with ANSI or CCITT LMI (both user and network side)
+ * * PPP
+ * * X.25
+ *
+ * Use sethdlc utility to set line parameters, protocol and PVCs
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/if_arp.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/pkt_sched.h>
+#include <linux/inetdevice.h>
+#include <linux/lapb.h>
+#include <linux/rtnetlink.h>
+#include <linux/hdlc.h>
+
+
+static const char* version = "HDLC support module revision 1.08";
+
+
+static int hdlc_change_mtu(struct net_device *dev, int new_mtu)
+{
+ if ((new_mtu < 68) || (new_mtu > HDLC_MAX_MTU))
+ return -EINVAL;
+ dev->mtu = new_mtu;
+ return 0;
+}
+
+
+
+static struct net_device_stats *hdlc_get_stats(struct net_device *dev)
+{
+ return &dev_to_hdlc(dev)->stats;
+}
+
+
+
+static int hdlc_rcv(struct sk_buff *skb, struct net_device *dev,
+ struct packet_type *p)
+{
+ dev_to_hdlc(dev)->netif_rx(skb);
+ return 0;
+}
+
+
+
+int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+ hdlc_device *hdlc = dev_to_hdlc(dev);
+ unsigned int proto;
+
+ if (cmd != SIOCWANDEV)
+ return -EINVAL;
+
+ switch(ifr->ifr_settings->type) {
+ case IF_PROTO_HDLC:
+ case IF_PROTO_PPP:
+ case IF_PROTO_CISCO:
+ case IF_PROTO_FR:
+ case IF_PROTO_X25:
+ proto = ifr->ifr_settings->type;
+ break;
+
+ default:
+ proto = hdlc->proto;
+ }
+
+ switch(proto) {
+#ifdef CONFIG_HDLC_RAW
+ case IF_PROTO_HDLC: return hdlc_raw_ioctl(hdlc, ifr);
+#endif
+#ifdef CONFIG_HDLC_PPP
+ case IF_PROTO_PPP: return hdlc_ppp_ioctl(hdlc, ifr);
+#endif
+#ifdef CONFIG_HDLC_CISCO
+ case IF_PROTO_CISCO: return hdlc_cisco_ioctl(hdlc, ifr);
+#endif
+#ifdef CONFIG_HDLC_FR
+ case IF_PROTO_FR: return hdlc_fr_ioctl(hdlc, ifr);
+#endif
+#ifdef CONFIG_HDLC_X25
+ case IF_PROTO_X25: return hdlc_x25_ioctl(hdlc, ifr);
+#endif
+ default: return -ENOSYS;
+ }
+}
+
+
+
+int register_hdlc_device(hdlc_device *hdlc)
+{
+ int result;
+ struct net_device *dev = hdlc_to_dev(hdlc);
+
+ dev->get_stats = hdlc_get_stats;
+ dev->change_mtu = hdlc_change_mtu;
+ dev->mtu = HDLC_MAX_MTU;
+
+ dev->type = ARPHRD_RAWHDLC;
+ dev->hard_header_len = 16;
+
+ dev->flags = IFF_POINTOPOINT | IFF_NOARP;
+
+ hdlc->proto = -1;
+ hdlc->detach = NULL;
+
+ result = dev_alloc_name(dev, "hdlc%d");
+ if (result<0)
+ return result;
+
+ result = register_netdev(dev);
+ if (result != 0)
+ return -EIO;
+
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+
+
+void unregister_hdlc_device(hdlc_device *hdlc)
+{
+ hdlc_detach(hdlc);
+
+ unregister_netdev(hdlc_to_dev(hdlc));
+ MOD_DEC_USE_COUNT;
+}
+
+
+
+MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
+MODULE_DESCRIPTION("HDLC support module");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(hdlc_ioctl);
+EXPORT_SYMBOL(register_hdlc_device);
+EXPORT_SYMBOL(unregister_hdlc_device);
+
+struct packet_type hdlc_packet_type=
+{
+ __constant_htons(ETH_P_HDLC),
+ NULL,
+ hdlc_rcv,
+ NULL,
+ NULL
+};
+
+
+static int __init hdlc_module_init(void)
+{
+ printk(KERN_INFO "%s\n", version);
+ dev_add_pack(&hdlc_packet_type);
+ return 0;
+}
+
+
+
+static void __exit hdlc_module_exit(void)
+{
+ dev_remove_pack(&hdlc_packet_type);
+}
+
+
+module_init(hdlc_module_init);
+module_exit(hdlc_module_exit);
diff --git a/drivers/net/wan/hdlc_ppp.c b/drivers/net/wan/hdlc_ppp.c
new file mode 100644
index 000000000000..3632f7a1fff6
--- /dev/null
+++ b/drivers/net/wan/hdlc_ppp.c
@@ -0,0 +1,119 @@
+/*
+ * Generic HDLC support routines for Linux
+ * Point-to-point protocol support
+ *
+ * Copyright (C) 1999 - 2001 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/if_arp.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/pkt_sched.h>
+#include <linux/inetdevice.h>
+#include <linux/lapb.h>
+#include <linux/rtnetlink.h>
+#include <linux/hdlc.h>
+
+
+static int ppp_open(hdlc_device *hdlc)
+{
+ struct net_device *dev = hdlc_to_dev(hdlc);
+ void *old_ioctl;
+ int result;
+
+ dev->priv = &hdlc->state.ppp.syncppp_ptr;
+ hdlc->state.ppp.syncppp_ptr = &hdlc->state.ppp.pppdev;
+ hdlc->state.ppp.pppdev.dev = dev;
+
+ old_ioctl = dev->do_ioctl;
+ hdlc->state.ppp.old_change_mtu = dev->change_mtu;
+ sppp_attach(&hdlc->state.ppp.pppdev);
+ /* sppp_attach nukes them. We don't need syncppp's ioctl */
+ dev->do_ioctl = old_ioctl;
+ hdlc->state.ppp.pppdev.sppp.pp_flags &= ~PP_CISCO;
+ dev->type = ARPHRD_PPP;
+ result = sppp_open(dev);
+ if (result) {
+ sppp_detach(dev);
+ return result;
+ }
+
+ return 0;
+}
+
+
+
+static void ppp_close(hdlc_device *hdlc)
+{
+ struct net_device *dev = hdlc_to_dev(hdlc);
+
+ sppp_close(dev);
+ sppp_detach(dev);
+ dev->rebuild_header = NULL;
+ dev->change_mtu = hdlc->state.ppp.old_change_mtu;
+ dev->mtu = HDLC_MAX_MTU;
+ dev->hard_header_len = 16;
+}
+
+
+
+static void ppp_rx(struct sk_buff *skb)
+{
+ skb->protocol = htons(ETH_P_WAN_PPP);
+ netif_rx(skb);
+}
+
+
+
+int hdlc_ppp_ioctl(hdlc_device *hdlc, struct ifreq *ifr)
+{
+ struct net_device *dev = hdlc_to_dev(hdlc);
+ int result;
+
+ switch (ifr->ifr_settings->type) {
+ case IF_GET_PROTO:
+ ifr->ifr_settings->type = IF_PROTO_PPP;
+ return 0; /* return protocol only, no settable parameters */
+
+ case IF_PROTO_PPP:
+ if(!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ if(dev->flags & IFF_UP)
+ return -EBUSY;
+
+ /* no settable parameters */
+
+ hdlc_detach(hdlc);
+
+ result=hdlc->attach(hdlc, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT);
+ if (result) {
+ hdlc->proto = -1;
+ return result;
+ }
+
+ hdlc->open = ppp_open;
+ hdlc->stop = ppp_close;
+ hdlc->netif_rx = ppp_rx;
+ hdlc->proto = IF_PROTO_PPP;
+ dev->hard_start_xmit = hdlc->xmit;
+ dev->hard_header = NULL;
+ dev->type = ARPHRD_PPP;
+ dev->addr_len = 0;
+ return 0;
+ }
+
+ return -EINVAL;
+}
diff --git a/drivers/net/wan/hdlc_raw.c b/drivers/net/wan/hdlc_raw.c
new file mode 100644
index 000000000000..00400730dfb0
--- /dev/null
+++ b/drivers/net/wan/hdlc_raw.c
@@ -0,0 +1,84 @@
+/*
+ * Generic HDLC support routines for Linux
+ * HDLC support
+ *
+ * Copyright (C) 1999 - 2001 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/if_arp.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/pkt_sched.h>
+#include <linux/inetdevice.h>
+#include <linux/lapb.h>
+#include <linux/rtnetlink.h>
+#include <linux/hdlc.h>
+
+
+static void raw_rx(struct sk_buff *skb)
+{
+ skb->protocol = htons(ETH_P_IP);
+ netif_rx(skb);
+}
+
+
+
+int hdlc_raw_ioctl(hdlc_device *hdlc, struct ifreq *ifr)
+{
+ raw_hdlc_proto *raw_s = &ifr->ifr_settings->ifs_hdlc.raw_hdlc;
+ const size_t size = sizeof(raw_hdlc_proto);
+ struct net_device *dev = hdlc_to_dev(hdlc);
+ int result;
+
+ switch (ifr->ifr_settings->type) {
+ case IF_GET_PROTO:
+ if (copy_to_user(raw_s, &hdlc->state.raw_hdlc.settings, size))
+ return -EFAULT;
+ return 0;
+
+ case IF_PROTO_HDLC:
+ if(!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ if(dev->flags & IFF_UP)
+ return -EBUSY;
+
+ if (copy_from_user(&hdlc->state.raw_hdlc.settings, raw_s, size))
+ return -EFAULT;
+
+
+ /* FIXME - put sanity checks here */
+ hdlc_detach(hdlc);
+
+ result=hdlc->attach(hdlc, hdlc->state.raw_hdlc.settings.encoding,
+ hdlc->state.raw_hdlc.settings.parity);
+ if (result) {
+ hdlc->proto = -1;
+ return result;
+ }
+
+ hdlc->open = NULL;
+ hdlc->stop = NULL;
+ hdlc->netif_rx = raw_rx;
+ hdlc->proto = IF_PROTO_HDLC;
+ dev->hard_start_xmit = hdlc->xmit;
+ dev->hard_header = NULL;
+ dev->type = ARPHRD_RAWHDLC;
+ dev->addr_len = 0;
+ return 0;
+ }
+
+ return -EINVAL;
+}
diff --git a/drivers/net/wan/hdlc_x25.c b/drivers/net/wan/hdlc_x25.c
new file mode 100644
index 000000000000..55c3f173565b
--- /dev/null
+++ b/drivers/net/wan/hdlc_x25.c
@@ -0,0 +1,219 @@
+/*
+ * Generic HDLC support routines for Linux
+ * X.25 support
+ *
+ * Copyright (C) 1999 - 2001 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/if_arp.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/pkt_sched.h>
+#include <linux/inetdevice.h>
+#include <linux/lapb.h>
+#include <linux/rtnetlink.h>
+#include <linux/hdlc.h>
+
+/* These functions are callbacks called by LAPB layer */
+
+static void x25_connect_disconnect(void *token, int reason, int code)
+{
+ hdlc_device *hdlc = token;
+ struct sk_buff *skb;
+ unsigned char *ptr;
+
+ if ((skb = dev_alloc_skb(1)) == NULL) {
+ printk(KERN_ERR "%s: out of memory\n", hdlc_to_name(hdlc));
+ return;
+ }
+
+ ptr = skb_put(skb, 1);
+ *ptr = code;
+
+ skb->dev = hdlc_to_dev(hdlc);
+ skb->protocol = htons(ETH_P_X25);
+ skb->mac.raw = skb->data;
+ skb->pkt_type = PACKET_HOST;
+
+ netif_rx(skb);
+}
+
+
+
+static void x25_connected(void *token, int reason)
+{
+ x25_connect_disconnect(token, reason, 1);
+}
+
+
+
+static void x25_disconnected(void *token, int reason)
+{
+ x25_connect_disconnect(token, reason, 2);
+}
+
+
+
+static int x25_data_indication(void *token, struct sk_buff *skb)
+{
+ hdlc_device *hdlc = token;
+ unsigned char *ptr;
+
+ ptr = skb_push(skb, 1);
+ *ptr = 0;
+
+ skb->dev = hdlc_to_dev(hdlc);
+ skb->protocol = htons(ETH_P_X25);
+ skb->mac.raw = skb->data;
+ skb->pkt_type = PACKET_HOST;
+
+ return netif_rx(skb);
+}
+
+
+
+static void x25_data_transmit(void *token, struct sk_buff *skb)
+{
+ hdlc_device *hdlc = token;
+ hdlc->xmit(skb, hdlc_to_dev(hdlc)); /* Ignore return value :-( */
+}
+
+
+
+static int x25_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ hdlc_device *hdlc = dev_to_hdlc(dev);
+ int result;
+
+
+ /* X.25 to LAPB */
+ switch (skb->data[0]) {
+ case 0: /* Data to be transmitted */
+ skb_pull(skb, 1);
+ if ((result = lapb_data_request(hdlc, skb)) != LAPB_OK)
+ dev_kfree_skb(skb);
+ return 0;
+
+ case 1:
+ if ((result = lapb_connect_request(hdlc))!= LAPB_OK) {
+ if (result == LAPB_CONNECTED)
+ /* Send connect confirm. msg to level 3 */
+ x25_connected(hdlc, 0);
+ else
+ printk(KERN_ERR "%s: LAPB connect request "
+ "failed, error code = %i\n",
+ hdlc_to_name(hdlc), result);
+ }
+ break;
+
+ case 2:
+ if ((result = lapb_disconnect_request(hdlc)) != LAPB_OK) {
+ if (result == LAPB_NOTCONNECTED)
+ /* Send disconnect confirm. msg to level 3 */
+ x25_disconnected(hdlc, 0);
+ else
+ printk(KERN_ERR "%s: LAPB disconnect request "
+ "failed, error code = %i\n",
+ hdlc_to_name(hdlc), result);
+ }
+ break;
+
+ default: /* to be defined */
+ break;
+ }
+
+ dev_kfree_skb(skb);
+ return 0;
+}
+
+
+
+static int x25_open(hdlc_device *hdlc)
+{
+ struct lapb_register_struct cb;
+ int result;
+
+ cb.connect_confirmation = x25_connected;
+ cb.connect_indication = x25_connected;
+ cb.disconnect_confirmation = x25_disconnected;
+ cb.disconnect_indication = x25_disconnected;
+ cb.data_indication = x25_data_indication;
+ cb.data_transmit = x25_data_transmit;
+
+ result = lapb_register(hdlc, &cb);
+ if (result != LAPB_OK)
+ return result;
+ return 0;
+}
+
+
+
+static void x25_close(hdlc_device *hdlc)
+{
+ lapb_unregister(hdlc);
+}
+
+
+
+static void x25_rx(struct sk_buff *skb)
+{
+ hdlc_device *hdlc = dev_to_hdlc(skb->dev);
+
+ if (lapb_data_received(hdlc, skb) == LAPB_OK)
+ return;
+ hdlc->stats.rx_errors++;
+ dev_kfree_skb_any(skb);
+}
+
+
+
+int hdlc_x25_ioctl(hdlc_device *hdlc, struct ifreq *ifr)
+{
+ struct net_device *dev = hdlc_to_dev(hdlc);
+ int result;
+
+ switch (ifr->ifr_settings->type) {
+ case IF_GET_PROTO:
+ ifr->ifr_settings->type = IF_PROTO_X25;
+ return 0; /* return protocol only, no settable parameters */
+
+ case IF_PROTO_X25:
+ if(!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ if(dev->flags & IFF_UP)
+ return -EBUSY;
+
+ hdlc_detach(hdlc);
+
+ result=hdlc->attach(hdlc, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT);
+ if (result) {
+ hdlc->proto = -1;
+ return result;
+ }
+
+ hdlc->open = x25_open;
+ hdlc->stop = x25_close;
+ hdlc->netif_rx = x25_rx;
+ hdlc->proto = IF_PROTO_X25;
+ dev->hard_start_xmit = x25_xmit;
+ dev->hard_header = NULL;
+ dev->type = ARPHRD_X25;
+ dev->addr_len = 0;
+ return 0;
+ }
+
+ return -EINVAL;
+}
diff --git a/drivers/net/wan/n2.c b/drivers/net/wan/n2.c
index 4c0ae1d3a7fb..2874ef8aeb7b 100644
--- a/drivers/net/wan/n2.c
+++ b/drivers/net/wan/n2.c
@@ -1,7 +1,7 @@
/*
* SDL Inc. RISCom/N2 synchronous serial card driver for Linux
*
- * Copyright (C) 1998-2000 Krzysztof Halasa <khc@pm.waw.pl>
+ * Copyright (C) 1998-2001 Krzysztof Halasa <khc@pm.waw.pl>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
@@ -17,6 +17,7 @@
* SDL Inc. PPP/HDLC/CISCO driver
*/
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
@@ -33,10 +34,8 @@
#include <asm/io.h>
#include "hd64570.h"
-#define DEBUG_RINGS
-/* #define DEBUG_PKT */
-static const char* version = "SDL RISCom/N2 driver revision: 1.02 for Linux 2.4";
+static const char* version = "SDL RISCom/N2 driver version: 1.09";
static const char* devname = "RISCom/N2";
#define USE_WINDOWSIZE 16384
@@ -87,9 +86,9 @@ typedef struct port_s {
hdlc_device hdlc; /* HDLC device struct - must be first */
struct card_s *card;
spinlock_t lock; /* TX lock */
- int clkmode; /* clock mode */
- int clkrate; /* clock rate */
- int line; /* loopback only */
+ sync_serial_settings settings;
+ unsigned short encoding;
+ unsigned short parity;
u8 rxs, txs, tmc; /* SCA registers */
u8 valid; /* port enabled */
u8 phy_node; /* physical port # - 0 or 1 */
@@ -116,6 +115,9 @@ typedef struct card_s {
}card_t;
+static card_t *first_card;
+static card_t **new_card = &first_card;
+
#define sca_reg(reg, card) (0x8000 | (card)->io | \
((reg) & 0x0F) | (((reg) & 0xF0) << 6))
@@ -157,7 +159,7 @@ static __inline__ void close_windows(card_t *card)
-static int n2_set_clock(port_t *port, int value)
+static int n2_set_iface(port_t *port)
{
card_t *card = port->card;
int io = card->io;
@@ -166,7 +168,7 @@ static int n2_set_clock(port_t *port, int value)
u8 rxs = port->rxs & CLK_BRG_MASK;
u8 txs = port->txs & CLK_BRG_MASK;
- switch(value) {
+ switch(port->settings.clock_type) {
case CLOCK_EXT:
mcr &= port->phy_node ? ~CLOCK_OUT_PORT1 : ~CLOCK_OUT_PORT0;
rxs |= CLK_LINE_RX; /* RXC input */
@@ -200,17 +202,22 @@ static int n2_set_clock(port_t *port, int value)
port->txs = txs;
sca_out(rxs, msci + RXS, card);
sca_out(txs, msci + TXS, card);
- port->clkmode = value;
+ sca_set_port(port);
return 0;
}
-static int n2_open(hdlc_device *hdlc)
+static int n2_open(struct net_device *dev)
{
+ hdlc_device *hdlc = dev_to_hdlc(dev);
port_t *port = hdlc_to_port(hdlc);
int io = port->card->io;
- u8 mcr = inb(io + N2_MCR) | (port->phy_node ? TX422_PORT1 : TX422_PORT0);
+ u8 mcr = inb(io + N2_MCR) | (port->phy_node ? TX422_PORT1:TX422_PORT0);
+
+ int result = hdlc_open(hdlc);
+ if (result)
+ return result;
MOD_INC_USE_COUNT;
mcr &= port->phy_node ? ~DTR_PORT1 : ~DTR_PORT0; /* set DTR ON */
@@ -219,14 +226,14 @@ static int n2_open(hdlc_device *hdlc)
outb(inb(io + N2_PCR) | PCR_ENWIN, io + N2_PCR); /* open window */
outb(inb(io + N2_PSR) | PSR_DMAEN, io + N2_PSR); /* enable dma */
sca_open(hdlc);
- n2_set_clock(port, port->clkmode);
- return 0;
+ return n2_set_iface(port);
}
-static void n2_close(hdlc_device *hdlc)
+static int n2_close(struct net_device *dev)
{
+ hdlc_device *hdlc = dev_to_hdlc(dev);
port_t *port = hdlc_to_port(hdlc);
int io = port->card->io;
u8 mcr = inb(io+N2_MCR) | (port->phy_node ? TX422_PORT1 : TX422_PORT0);
@@ -234,52 +241,48 @@ static void n2_close(hdlc_device *hdlc)
sca_close(hdlc);
mcr |= port->phy_node ? DTR_PORT1 : DTR_PORT0; /* set DTR OFF */
outb(mcr, io + N2_MCR);
+ hdlc_close(hdlc);
MOD_DEC_USE_COUNT;
+ return 0;
}
-static int n2_ioctl(hdlc_device *hdlc, struct ifreq *ifr, int cmd)
+static int n2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
- int value = ifr->ifr_ifru.ifru_ivalue;
- int result = 0;
+ union line_settings *line = &ifr->ifr_settings->ifs_line;
+ const size_t size = sizeof(sync_serial_settings);
+ hdlc_device *hdlc = dev_to_hdlc(dev);
port_t *port = hdlc_to_port(hdlc);
- if(!capable(CAP_NET_ADMIN))
- return -EPERM;
-
- switch(cmd) {
- case HDLCSCLOCK:
- result = n2_set_clock(port, value);
- case HDLCGCLOCK:
- value = port->clkmode;
- break;
-
- case HDLCSCLOCKRATE:
- port->clkrate = value;
- sca_set_clock(port);
- case HDLCGCLOCKRATE:
- value = port->clkrate;
- break;
-
- case HDLCSLINE:
- result = sca_set_loopback(port, value);
- case HDLCGLINE:
- value = port->line;
- break;
-
-#ifdef DEBUG_RINGS
- case HDLCRUN:
+#ifdef CONFIG_HDLC_DEBUG_RINGS
+ if (cmd == SIOCDEVPRIVATE) {
sca_dump_rings(hdlc);
return 0;
-#endif /* DEBUG_RINGS */
+ }
+#endif
+ if (cmd != SIOCWANDEV)
+ return hdlc_ioctl(dev, ifr, cmd);
+
+ switch(ifr->ifr_settings->type) {
+ case IF_GET_IFACE:
+ ifr->ifr_settings->type = IF_IFACE_SYNC_SERIAL;
+ if (copy_to_user(&line->sync, &port->settings, size))
+ return -EFAULT;
+ return 0;
+
+ case IF_IFACE_SYNC_SERIAL:
+ if(!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ if (copy_from_user(&port->settings, &line->sync, size))
+ return -EFAULT;
+ /* FIXME - put sanity checks here */
+ return n2_set_iface(port);
default:
- return -EINVAL;
+ return hdlc_ioctl(dev, ifr, cmd);
}
-
- ifr->ifr_ifru.ifru_ivalue = value;
- return result;
}
@@ -465,6 +468,7 @@ static int n2_run(unsigned long io, unsigned long irq, unsigned long winbase,
sca_init(card, 0);
for (cnt = 0; cnt < 2; cnt++) {
port_t *port = &card->ports[cnt];
+ struct net_device *dev = hdlc_to_dev(&port->hdlc);
if ((cnt == 0 && !valid0) || (cnt == 1 && !valid1))
continue;
@@ -476,14 +480,16 @@ static int n2_run(unsigned long io, unsigned long irq, unsigned long winbase,
port->log_node = 1;
spin_lock_init(&port->lock);
- hdlc_to_dev(&port->hdlc)->irq = irq;
- hdlc_to_dev(&port->hdlc)->mem_start = winbase;
- hdlc_to_dev(&port->hdlc)->mem_end = winbase + USE_WINDOWSIZE-1;
- hdlc_to_dev(&port->hdlc)->tx_queue_len = 50;
- port->hdlc.ioctl = n2_ioctl;
- port->hdlc.open = n2_open;
- port->hdlc.close = n2_close;
+ dev->irq = irq;
+ dev->mem_start = winbase;
+ dev->mem_end = winbase + USE_WINDOWSIZE-1;
+ dev->tx_queue_len = 50;
+ dev->do_ioctl = n2_ioctl;
+ dev->open = n2_open;
+ dev->stop = n2_close;
+ port->hdlc.attach = sca_attach;
port->hdlc.xmit = sca_xmit;
+ port->settings.clock_type = CLOCK_EXT;
if (register_hdlc_device(&port->hdlc)) {
printk(KERN_WARNING "n2: unable to register hdlc "
@@ -515,7 +521,7 @@ static int __init n2_init(void)
return -ENOSYS; /* no parameters specified, abort */
}
- printk(KERN_INFO "%s\n", version);
+ printk(KERN_INFO "%s (SCA-%s)\n", version, sca_version);
do {
unsigned long io, irq, ram;
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index fdd083a62235..ff76c51e0da6 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -2117,11 +2117,13 @@ EXPORT_SYMBOL(pci_announce_device_to_drivers);
EXPORT_SYMBOL(pci_add_new_bus);
EXPORT_SYMBOL(pci_do_scan_bus);
EXPORT_SYMBOL(pci_scan_slot);
+#ifdef CONFIG_PROC_FS
EXPORT_SYMBOL(pci_proc_attach_device);
EXPORT_SYMBOL(pci_proc_detach_device);
EXPORT_SYMBOL(pci_proc_attach_bus);
EXPORT_SYMBOL(pci_proc_detach_bus);
#endif
+#endif
EXPORT_SYMBOL(pci_set_power_state);
EXPORT_SYMBOL(pci_save_state);
diff --git a/include/linux/hdlc.h b/include/linux/hdlc.h
index 3ac12961d802..c18e217f0550 100644
--- a/include/linux/hdlc.h
+++ b/include/linux/hdlc.h
@@ -1,7 +1,7 @@
/*
* Generic HDLC support routines for Linux
*
- * Copyright (C) 1999, 2000 Krzysztof Halasa <khc@pm.waw.pl>
+ * Copyright (C) 1999-2002 Krzysztof Halasa <khc@pm.waw.pl>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
@@ -12,64 +12,49 @@
#ifndef __HDLC_H
#define __HDLC_H
-/* Ioctls - to be changed */
-#define HDLCGSLOTMAP (0x89F4) /* E1/T1 slot bitmap */
-#define HDLCGCLOCK (0x89F5) /* clock sources */
-#define HDLCGCLOCKRATE (0x89F6) /* clock rate */
-#define HDLCGMODE (0x89F7) /* internal to hdlc.c - protocol used */
-#define HDLCGLINE (0x89F8) /* physical interface */
-#define HDLCSSLOTMAP (0x89F9)
-#define HDLCSCLOCK (0x89FA)
-#define HDLCSCLOCKRATE (0x89FB)
-#define HDLCSMODE (0x89FC) /* internal to hdlc.c - select protocol */
-#define HDLCPVC (0x89FD) /* internal to hdlc.c - create/delete PVC */
-#define HDLCSLINE (0x89FE)
-#define HDLCRUN (0x89FF) /* Download firmware and run board */
-
-/* Modes */
-#define MODE_NONE 0x00000000 /* Not initialized */
-#define MODE_DCE 0x00000080 /* DCE */
-#define MODE_HDLC 0x00000100 /* Raw HDLC frames */
-#define MODE_CISCO 0x00000200
-#define MODE_PPP 0x00000400
-#define MODE_FR 0x00000800 /* Any LMI */
-#define MODE_FR_ANSI 0x00000801
-#define MODE_FR_CCITT 0x00000802
-#define MODE_X25 0x00001000
-#define MODE_MASK 0x0000FF00
-#define MODE_SOFT 0x80000000 /* Driver modes, using hardware HDLC */
-
-/* Lines */
-#define LINE_DEFAULT 0x00000000
-#define LINE_V35 0x00000001
-#define LINE_RS232 0x00000002
-#define LINE_X21 0x00000003
-#define LINE_T1 0x00000004
-#define LINE_E1 0x00000005
-#define LINE_MASK 0x000000FF
-#define LINE_LOOPBACK 0x80000000 /* On-card loopback */
-
-#define CLOCK_EXT 0 /* External TX and RX clock - DTE */
-#define CLOCK_INT 1 /* Internal TX and RX clock - DCE */
-#define CLOCK_TXINT 2 /* Internal TX and external RX clock */
-#define CLOCK_TXFROMRX 3 /* TX clock derived from external RX clock */
+#define CLOCK_DEFAULT 0 /* Default (current) setting */
+#define CLOCK_EXT 1 /* External TX and RX clock - DTE */
+#define CLOCK_INT 2 /* Internal TX and RX clock - DCE */
+#define CLOCK_TXINT 3 /* Internal TX and external RX clock */
+#define CLOCK_TXFROMRX 4 /* TX clock derived from external RX clock */
-#define HDLC_MAX_MTU 1500 /* Ethernet 1500 bytes */
-#define HDLC_MAX_MRU (HDLC_MAX_MTU + 10) /* max 10 bytes for FR */
+#define ENCODING_DEFAULT 0 /* Default (current) setting */
+#define ENCODING_NRZ 1
+#define ENCODING_NRZI 2
+#define ENCODING_FM_MARK 3
+#define ENCODING_FM_SPACE 4
+#define ENCODING_MANCHESTER 5
+
+
+#define PARITY_DEFAULT 0 /* Default (current) setting */
+#define PARITY_NONE 1 /* No parity */
+#define PARITY_CRC16_PR0 2 /* CRC16, initial value 0x0000 */
+#define PARITY_CRC16_PR1 3 /* CRC16, initial value 0xFFFF */
+#define PARITY_CRC16_PR0_CCITT 4 /* CRC16, initial 0x0000, ITU-T version */
+#define PARITY_CRC16_PR1_CCITT 5 /* CRC16, initial 0xFFFF, ITU-T version */
+#define PARITY_CRC32_PR0_CCITT 6 /* CRC32, initial value 0x00000000 */
+#define PARITY_CRC32_PR1_CCITT 7 /* CRC32, initial value 0xFFFFFFFF */
+
+#define LMI_DEFAULT 0 /* Default (current) setting */
+#define LMI_NONE 1 /* No LMI, all PVCs are static */
+#define LMI_ANSI 2 /* ANSI Annex D */
+#define LMI_CCITT 3 /* ITU-T Annex A */
+
+/* PPP doesn't need any info now - supply length = 0 to ioctl */
+
#ifdef __KERNEL__
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <net/syncppp.h>
+#include <linux/hdlc/ioctl.h>
-#define MAXLEN_LMISTAT 20 /* max size of status enquiry frame */
+#define HDLC_MAX_MTU 1500 /* Ethernet 1500 bytes */
+#define HDLC_MAX_MRU (HDLC_MAX_MTU + 10) /* max 10 bytes for FR */
-#define LINK_STATE_RELIABLE 0x01
-#define LINK_STATE_REQUEST 0x02 /* full stat sent (DCE) / req pending (DTE) */
-#define LINK_STATE_CHANGED 0x04 /* change in PVCs state, send full report */
-#define LINK_STATE_FULLREP_SENT 0x08 /* full report sent */
+#define MAXLEN_LMISTAT 20 /* max size of status enquiry frame */
#define PVC_STATE_NEW 0x01
#define PVC_STATE_ACTIVE 0x02
@@ -112,6 +97,7 @@
typedef struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
unsigned ea1 : 1;
unsigned cr : 1;
unsigned dlcih: 6;
@@ -121,6 +107,19 @@ typedef struct {
unsigned becn : 1;
unsigned fecn : 1;
unsigned dlcil: 4;
+#elif defined (__BIG_ENDIAN_BITFIELD)
+ unsigned dlcih: 6;
+ unsigned cr : 1;
+ unsigned ea1 : 1;
+
+ unsigned dlcil: 4;
+ unsigned fecn : 1;
+ unsigned becn : 1;
+ unsigned de : 1;
+ unsigned ea2 : 1;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
}__attribute__ ((packed)) fr_hdr;
@@ -151,63 +150,96 @@ typedef struct pvc_device_struct {
struct hdlc_device_struct *master;
struct pvc_device_struct *next;
- u8 state;
- u8 newstate;
+ struct {
+ int active;
+ int new;
+ int deleted;
+ int fecn;
+ int becn;
+ }state;
}pvc_device;
-typedef struct {
- u32 last_errors; /* last errors bit list */
- int last_poll; /* ! */
- u8 T391; /* ! link integrity verification polling timer */
- u8 T392; /* ! polling verification timer */
- u8 N391; /* full status polling counter */
- u8 N392; /* error threshold */
- u8 N393; /* monitored events count */
- u8 N391cnt;
-
- u8 state; /* ! */
- u32 txseq; /* ! TX sequence number - Cisco uses 4 bytes */
- u32 rxseq; /* ! RX sequence number */
-}fr_lmi; /* ! means used in Cisco HDLC as well */
-
-
typedef struct hdlc_device_struct {
- /* to be initialized by hardware driver: */
+ /* To be initialized by hardware driver */
struct net_device netdev; /* master net device - must be first */
struct net_device_stats stats;
- struct ppp_device pppdev;
- struct ppp_device *syncppp_ptr;
+ /* used by HDLC layer to take control over HDLC device from hw driver*/
+ int (*attach)(struct hdlc_device_struct *hdlc,
+ unsigned short encoding, unsigned short parity);
+
+ /* hardware driver must handle this instead of dev->hard_start_xmit */
+ int (*xmit)(struct sk_buff *skb, struct net_device *dev);
+
- /* set_mode may be NULL if HDLC-only board */
- int (*set_mode)(struct hdlc_device_struct *hdlc, int mode);
+ /* Things below are for HDLC layer internal use only */
+ int (*ioctl)(struct net_device *dev, struct ifreq *ifr, int cmd);
int (*open)(struct hdlc_device_struct *hdlc);
- void (*close)(struct hdlc_device_struct *hdlc);
- int (*xmit)(struct hdlc_device_struct *hdlc, struct sk_buff *skb);
- int (*ioctl)(struct hdlc_device_struct *hdlc, struct ifreq *ifr,
- int cmd);
-
- /* Only in "hardware" FR modes etc. - may be NULL */
- int (*create_pvc)(pvc_device *pvc);
- void (*destroy_pvc)(pvc_device *pvc);
- int (*open_pvc)(pvc_device *pvc);
- void (*close_pvc)(pvc_device *pvc);
-
- /* for hdlc.c internal use only */
- pvc_device *first_pvc;
- u16 pvc_count;
- int mode;
-
- struct timer_list timer;
- fr_lmi lmi;
+ void (*stop)(struct hdlc_device_struct *hdlc);
+ void (*detach)(struct hdlc_device_struct *hdlc);
+ void (*netif_rx)(struct sk_buff *skb);
+ int proto; /* IF_PROTO_HDLC/CISCO/FR/etc. */
+
+ union {
+ struct {
+ fr_proto settings;
+ pvc_device *first_pvc;
+ int pvc_count;
+
+ struct timer_list timer;
+ int last_poll;
+ int reliable;
+ int changed;
+ int request;
+ int fullrep_sent;
+ u32 last_errors; /* last errors bit list */
+ u8 n391cnt;
+ u8 txseq; /* TX sequence number */
+ u8 rxseq; /* RX sequence number */
+ }fr;
+
+ struct {
+ cisco_proto settings;
+
+ struct timer_list timer;
+ int last_poll;
+ int up;
+ u32 txseq; /* TX sequence number */
+ u32 rxseq; /* RX sequence number */
+ }cisco;
+
+ struct {
+ raw_hdlc_proto settings;
+ }raw_hdlc;
+
+ struct {
+ struct ppp_device pppdev;
+ struct ppp_device *syncppp_ptr;
+ int (*old_change_mtu)(struct net_device *dev,
+ int new_mtu);
+ }ppp;
+ }state;
}hdlc_device;
+
+int hdlc_raw_ioctl(hdlc_device *hdlc, struct ifreq *ifr);
+int hdlc_cisco_ioctl(hdlc_device *hdlc, struct ifreq *ifr);
+int hdlc_ppp_ioctl(hdlc_device *hdlc, struct ifreq *ifr);
+int hdlc_fr_ioctl(hdlc_device *hdlc, struct ifreq *ifr);
+int hdlc_x25_ioctl(hdlc_device *hdlc, struct ifreq *ifr);
+
+
+/* Exported from hdlc.o */
+
+/* Called by hardware driver when a user requests HDLC service */
+int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
+
+/* Must be used by hardware driver on module startup/exit */
int register_hdlc_device(hdlc_device *hdlc);
void unregister_hdlc_device(hdlc_device *hdlc);
-void hdlc_netif_rx(hdlc_device *hdlc, struct sk_buff *skb);
static __inline__ struct net_device* hdlc_to_dev(hdlc_device *hdlc)
@@ -246,33 +278,6 @@ static __inline__ const char *pvc_to_name(pvc_device *pvc)
}
-static __inline__ u16 status_to_dlci(hdlc_device *hdlc, u8 *status, u8 *state)
-{
- *state &= ~(PVC_STATE_ACTIVE | PVC_STATE_NEW);
- if (status[2] & 0x08)
- *state |= PVC_STATE_NEW;
- else if (status[2] & 0x02)
- *state |= PVC_STATE_ACTIVE;
-
- return ((status[0] & 0x3F)<<4) | ((status[1] & 0x78)>>3);
-}
-
-
-static __inline__ void dlci_to_status(hdlc_device *hdlc, u16 dlci, u8 *status,
- u8 state)
-{
- status[0] = (dlci>>4) & 0x3F;
- status[1] = ((dlci<<3) & 0x78) | 0x80;
- status[2] = 0x80;
-
- if (state & PVC_STATE_NEW)
- status[2] |= 0x08;
- else if (state & PVC_STATE_ACTIVE)
- status[2] |= 0x02;
-}
-
-
-
static __inline__ u16 netdev_dlci(struct net_device *dev)
{
return ntohs(*(u16*)dev->dev_addr);
@@ -282,37 +287,15 @@ static __inline__ u16 netdev_dlci(struct net_device *dev)
static __inline__ u16 q922_to_dlci(u8 *hdr)
{
- return ((hdr[0] & 0xFC)<<2) | ((hdr[1] & 0xF0)>>4);
+ return ((hdr[0] & 0xFC) << 2) | ((hdr[1] & 0xF0) >> 4);
}
static __inline__ void dlci_to_q922(u8 *hdr, u16 dlci)
{
- hdr[0] = (dlci>>2) & 0xFC;
- hdr[1] = ((dlci<<4) & 0xF0) | 0x01;
-}
-
-
-
-static __inline__ int mode_is(hdlc_device *hdlc, int mask)
-{
- return (hdlc->mode & mask) == mask;
-}
-
-
-
-static __inline__ pvc_device* find_pvc(hdlc_device *hdlc, u16 dlci)
-{
- pvc_device *pvc=hdlc->first_pvc;
-
- while (pvc) {
- if (netdev_dlci(&pvc->netdev) == dlci)
- return pvc;
- pvc=pvc->next;
- }
-
- return NULL;
+ hdr[0] = (dlci >> 2) & 0xFC;
+ hdr[1] = ((dlci << 4) & 0xF0) | 0x01;
}
@@ -332,5 +315,35 @@ static __inline__ void debug_frame(const struct sk_buff *skb)
}
+
+/* Must be called by hardware driver when HDLC device is being opened */
+static __inline__ int hdlc_open(hdlc_device *hdlc)
+{
+ if (hdlc->proto == -1)
+ return -ENOSYS; /* no protocol attached */
+
+ if (hdlc->open)
+ return hdlc->open(hdlc);
+ return 0;
+}
+
+
+/* Must be called by hardware driver when HDLC device is being closed */
+static __inline__ void hdlc_close(hdlc_device *hdlc)
+{
+ if (hdlc->stop)
+ hdlc->stop(hdlc);
+}
+
+
+/* May be used by hardware driver to gain control over HDLC device */
+static __inline__ void hdlc_detach(hdlc_device *hdlc)
+{
+ if (hdlc->detach)
+ hdlc->detach(hdlc);
+ hdlc->detach = NULL;
+}
+
+
#endif /* __KERNEL */
#endif /* __HDLC_H */
diff --git a/include/linux/hdlc/ioctl.h b/include/linux/hdlc/ioctl.h
new file mode 100644
index 000000000000..c35e1a35d847
--- /dev/null
+++ b/include/linux/hdlc/ioctl.h
@@ -0,0 +1,55 @@
+#ifndef __HDLC_IOCTL_H__
+#define __HDLC_IOCTL_H__
+
+typedef struct {
+ unsigned int clock_rate; /* bits per second */
+ unsigned int clock_type; /* internal, external, TX-internal etc. */
+ unsigned short loopback;
+} sync_serial_settings; /* V.35, V.24, X.21 */
+
+typedef struct {
+ unsigned int clock_rate; /* bits per second */
+ unsigned int clock_type; /* internal, external, TX-internal etc. */
+ unsigned short loopback;
+ unsigned int slot_map;
+} te1_settings; /* T1, E1 */
+
+typedef struct {
+ unsigned short encoding;
+ unsigned short parity;
+} raw_hdlc_proto;
+
+typedef struct {
+ unsigned int t391;
+ unsigned int t392;
+ unsigned int n391;
+ unsigned int n392;
+ unsigned int n393;
+ unsigned short lmi;
+ unsigned short dce; /* 1 for DCE (network side) operation */
+} fr_proto;
+
+typedef struct {
+ unsigned int dlci;
+} fr_proto_pvc; /* for creating/deleting FR PVCs */
+
+typedef struct {
+ unsigned int interval;
+ unsigned int timeout;
+} cisco_proto;
+
+/* PPP doesn't need any info now - supply length = 0 to ioctl */
+
+union hdlc_settings {
+ raw_hdlc_proto raw_hdlc;
+ cisco_proto cisco;
+ fr_proto fr;
+ fr_proto_pvc fr_pvc;
+};
+
+union line_settings {
+ sync_serial_settings sync;
+ te1_settings te1;
+};
+
+#endif /* __HDLC_IOCTL_H__ */
diff --git a/include/linux/if.h b/include/linux/if.h
index 9a38b2e2ab33..a46d55dd576d 100644
--- a/include/linux/if.h
+++ b/include/linux/if.h
@@ -21,6 +21,7 @@
#include <linux/types.h> /* for "__kernel_caddr_t" et al */
#include <linux/socket.h> /* for "struct sockaddr" et al */
+#include <linux/hdlc/ioctl.h>
/* Standard interface flags (netdevice->flags). */
#define IFF_UP 0x1 /* interface is up */
@@ -48,6 +49,29 @@
/* Private (from user) interface flags (netdevice->priv_flags). */
#define IFF_802_1Q_VLAN 0x1 /* 802.1Q VLAN device. */
+
+#define IF_GET_IFACE 0x0001 /* for querying only */
+#define IF_GET_PROTO 0x0002
+
+/* For definitions see hdlc.h */
+#define IF_IFACE_V35 0x1000 /* V.35 serial interface */
+#define IF_IFACE_V24 0x1001 /* V.24 serial interface */
+#define IF_IFACE_X21 0x1002 /* X.21 serial interface */
+#define IF_IFACE_T1 0x1003 /* T1 telco serial interface */
+#define IF_IFACE_E1 0x1004 /* E1 telco serial interface */
+#define IF_IFACE_SYNC_SERIAL 0x1005 /* cant'b be set by software */
+
+/* For definitions see hdlc.h */
+#define IF_PROTO_HDLC 0x2000 /* raw HDLC protocol */
+#define IF_PROTO_PPP 0x2001 /* PPP protocol */
+#define IF_PROTO_CISCO 0x2002 /* Cisco HDLC protocol */
+#define IF_PROTO_FR 0x2003 /* Frame Relay protocol */
+#define IF_PROTO_FR_ADD_PVC 0x2004 /* Create FR PVC */
+#define IF_PROTO_FR_DEL_PVC 0x2005 /* Delete FR PVC */
+#define IF_PROTO_X25 0x2006 /* X.25 */
+
+
+
/*
* Device mapping structure. I'd just gone off and designed a
* beautiful scheme using only loadable modules with arguments
@@ -69,6 +93,19 @@ struct ifmap
/* 3 bytes spare */
};
+struct if_settings
+{
+ unsigned int type; /* Type of physical device or protocol */
+ union {
+ /* {atm/eth/dsl}_settings anyone ? */
+ union hdlc_settings ifsu_hdlc;
+ union line_settings ifsu_line;
+ } ifs_ifsu;
+};
+
+#define ifs_hdlc ifs_ifsu.ifsu_hdlc
+#define ifs_line ifs_ifsu.ifsu_line
+
/*
* Interface request structure used for socket
* ioctl's. All interface ioctl's must have parameter
@@ -98,6 +135,7 @@ struct ifreq
char ifru_slave[IFNAMSIZ]; /* Just fits the size */
char ifru_newname[IFNAMSIZ];
char * ifru_data;
+ struct if_settings *ifru_settings;
} ifr_ifru;
};
@@ -117,6 +155,7 @@ struct ifreq
#define ifr_bandwidth ifr_ifru.ifru_ivalue /* link bandwidth */
#define ifr_qlen ifr_ifru.ifru_ivalue /* Queue length */
#define ifr_newname ifr_ifru.ifru_newname /* New name */
+#define ifr_settings ifr_ifru.ifru_settings /* Device/proto settings*/
/*
* Structure used in SIOCGIFCONF request.
diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h
index b64559d713f9..dbeb3728ef24 100644
--- a/include/linux/if_ether.h
+++ b/include/linux/if_ether.h
@@ -85,6 +85,7 @@
#define ETH_P_CONTROL 0x0016 /* Card specific control frames */
#define ETH_P_IRDA 0x0017 /* Linux-IrDA */
#define ETH_P_ECONET 0x0018 /* Acorn Econet */
+#define ETH_P_HDLC 0x0019 /* HDLC frames */
/*
* This is an Ethernet frame header.
diff --git a/include/linux/sockios.h b/include/linux/sockios.h
index 0c5c4e1f803a..2c74362de047 100644
--- a/include/linux/sockios.h
+++ b/include/linux/sockios.h
@@ -81,6 +81,8 @@
#define SIOCGMIIREG 0x8948 /* Read MII PHY register. */
#define SIOCSMIIREG 0x8949 /* Write MII PHY register. */
+#define SIOCWANDEV 0x894A /* get/set netdev parameters */
+
/* ARP cache control calls. */
/* 0x8950 - 0x8952 * obsolete calls, don't re-use */
#define SIOCDARP 0x8953 /* delete ARP table entry */
diff --git a/include/sound/core.h b/include/sound/core.h
index 5744cdd5cc8e..94590bff56fb 100644
--- a/include/sound/core.h
+++ b/include/sound/core.h
@@ -22,6 +22,10 @@
*
*/
+#ifdef CONFIG_PM
+#include <linux/sched.h> /* wake_up() and struct semaphore */
+#endif
+
/* Typedef's */
typedef struct timeval snd_timestamp_t;
typedef struct sndrv_interval snd_interval_t;
diff --git a/include/sound/driver.h b/include/sound/driver.h
index ca4d4ab28e46..2fd88e2701b8 100644
--- a/include/sound/driver.h
+++ b/include/sound/driver.h
@@ -78,12 +78,4 @@ void snd_wrapper_vfree(void *);
#include "sndmagic.h"
-/*
- * Temporary hack, until linux/init.h is fixed.
- */
-#include <linux/init.h>
-#ifndef __devexit_p
-#define __devexit_p(x) x
-#endif
-
#endif /* __SOUND_DRIVER_H */
diff --git a/include/sound/info.h b/include/sound/info.h
index 98d58dad1495..ec841506e6db 100644
--- a/include/sound/info.h
+++ b/include/sound/info.h
@@ -104,6 +104,11 @@ extern int snd_info_minor_unregister(void);
#ifdef CONFIG_PROC_FS
extern snd_info_entry_t *snd_seq_root;
+#ifdef CONFIG_SND_OSSEMUL
+extern snd_info_entry_t *snd_oss_root;
+#else
+#define snd_oss_root NULL
+#endif
int snd_iprintf(snd_info_buffer_t * buffer, char *fmt,...) __attribute__ ((format (printf, 2, 3)));
int snd_info_init(void);
@@ -138,6 +143,7 @@ void snd_remove_proc_entry(struct proc_dir_entry *parent,
#else
#define snd_seq_root NULL
+#define snd_oss_root NULL
static inline int snd_iprintf(snd_info_buffer_t * buffer, char *fmt,...) { return 0; }
static inline int snd_info_init(void) { return 0; }
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index 3d24d3c04273..09653070905e 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -25,6 +25,7 @@
#include <sound/asound.h>
#include <linux/poll.h>
+#include <linux/bitops.h>
typedef sndrv_pcm_uframes_t snd_pcm_uframes_t;
typedef sndrv_pcm_sframes_t snd_pcm_sframes_t;
diff --git a/include/sound/pcm_params.h b/include/sound/pcm_params.h
index 9d008650e5f2..769d8738f2fd 100644
--- a/include/sound/pcm_params.h
+++ b/include/sound/pcm_params.h
@@ -22,8 +22,6 @@
*
*/
-#include <linux/bitops.h>
-
extern int snd_pcm_hw_param_mask(snd_pcm_substream_t *pcm, snd_pcm_hw_params_t *params,
snd_pcm_hw_param_t var, const snd_mask_t *val);
extern unsigned int snd_pcm_hw_param_value_min(const snd_pcm_hw_params_t *params,
diff --git a/include/sound/version.h b/include/sound/version.h
index 50a7e6f090d8..21ced3f5bc47 100644
--- a/include/sound/version.h
+++ b/include/sound/version.h
@@ -1,3 +1,3 @@
/* include/version.h. Generated automatically by configure. */
#define CONFIG_SND_VERSION "0.9.0beta12"
-#define CONFIG_SND_DATE " (Tue Feb 26 09:34:24 2002 UTC)"
+#define CONFIG_SND_DATE " (Wed Mar 06 07:56:20 2002 UTC)"
diff --git a/kernel/sched.c b/kernel/sched.c
index 81190071b159..45e3b6103360 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -1438,10 +1438,12 @@ void __init init_idle(task_t *idle, int cpu)
idle->prio = MAX_PRIO;
idle->state = TASK_RUNNING;
idle->thread_info->cpu = cpu;
- idle->thread_info->preempt_count = (idle->lock_depth >= 0);
double_rq_unlock(idle_rq, rq);
set_tsk_need_resched(idle);
__restore_flags(flags);
+
+ /* Set the preempt count _outside_ the spinlocks! */
+ idle->thread_info->preempt_count = (idle->lock_depth >= 0);
}
extern void init_timervecs(void);
diff --git a/net/core/dev.c b/net/core/dev.c
index 3afa0c27a4a1..6a510b1a8ea4 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2110,7 +2110,8 @@ static int dev_ifsioc(struct ifreq *ifr, unsigned int cmd)
cmd == SIOCETHTOOL ||
cmd == SIOCGMIIPHY ||
cmd == SIOCGMIIREG ||
- cmd == SIOCSMIIREG) {
+ cmd == SIOCSMIIREG ||
+ cmd == SIOCWANDEV) {
if (dev->do_ioctl) {
if (!netif_device_present(dev))
return -ENODEV;
@@ -2276,8 +2277,9 @@ int dev_ioctl(unsigned int cmd, void *arg)
*/
default:
- if (cmd >= SIOCDEVPRIVATE &&
- cmd <= SIOCDEVPRIVATE + 15) {
+ if (cmd == SIOCWANDEV ||
+ (cmd >= SIOCDEVPRIVATE &&
+ cmd <= SIOCDEVPRIVATE + 15)) {
dev_load(ifr.ifr_name);
dev_probe_lock();
rtnl_lock();
diff --git a/sound/Config.help b/sound/Config.help
new file mode 100644
index 000000000000..3d003545abaf
--- /dev/null
+++ b/sound/Config.help
@@ -0,0 +1,7 @@
+CONFIG_SOUND_PRIME
+ Say 'Y' or 'M' to enable Open Sound System drivers.
+
+CONFIG_SOUND_SND
+ Say 'Y' or 'M' to enable Advanced Linux Sound Architecture (ALSA) drivers.
+ You need to install also alsa-lib and alsa-utils packages available on
+ the ALSA website at <http://www.alsa-project.org>.
diff --git a/sound/core/Config.help b/sound/core/Config.help
new file mode 100644
index 000000000000..85541f1f97b1
--- /dev/null
+++ b/sound/core/Config.help
@@ -0,0 +1,40 @@
+CONFIG_SND_SEQUENCER
+ Say 'Y' or 'M' to enable MIDI sequencer and router support. This feature
+ allows routing and enqueing MIDI events. Events can be processed at given
+ time.
+
+CONFIG_SND_SEQ_DUMMY
+ Say 'Y' or 'M' to enable dummy sequencer client. This client is a simple
+ midi-through client. All normal input events are redirected to output port
+ immediately.
+
+CONFIG_SND_OSSEMUL
+ Say 'Y' to enable OSS (Open Sound System) API emulation code.
+
+CONFIG_SND_MIXER_OSS
+ Say 'Y' or 'M' to enable mixer OSS API emulation (/dev/mixer*).
+
+CONFIG_SND_PCM_OSS
+ Say 'Y' or 'M' to enable digital audio (PCM) OSS API emulation (/dev/dsp*).
+
+CONFIG_SND_SEQUENCER_OSS
+ Say 'Y' or 'M' to enable OSS sequencer emulation (both /dev/sequencer and
+ /dev/music interfaces).
+
+CONFIG_SND_RTCTIMER
+ Say 'Y' or 'M' to enable RTC timer support for ALSA. ALSA code uses RTC
+ timer as precise timing source and maps the RTC timer to the ALSA's timer
+ interface. ALSA sequencer code can also use this timing source.
+
+CONFIG_SND_VERBOSE_PRINTK
+ Say 'Y' to enable verbose log messages. These messages will help to
+ identify source file and position containing printed messages.
+
+CONFIG_SND_DEBUG
+ Say 'Y' to enable ALSA debug code.
+
+CONFIG_SND_DEBUG_MEMORY
+ Say 'Y' to enable debugging of memory allocation.
+
+CONFIG_SND_DEBUG_DETECTION
+ Say 'Y' to enable debugging of hardware detection.
diff --git a/sound/core/Config.in b/sound/core/Config.in
index 5e9b5a1c176a..38c93ed8bb1c 100644
--- a/sound/core/Config.in
+++ b/sound/core/Config.in
@@ -1,5 +1,14 @@
# ALSA soundcard-configuration
+if [ "$CONFIG_X86_64" = "y" -a "$CONFIG_IA32_EMULATION" = "y" ]; then
+ dep_tristate ' Emulation for 32-bit applications' CONFIG_SND_BIT32_EMUL
+fi
+if [ "$CONFIG_PPC64" = "y" ]; then
+ dep_tristate ' Emulation for 32-bit applications' CONFIG_SND_BIT32_EMUL
+fi
+if [ "$CONFIG_SPARC64" = "y" ]; then
+ dep_tristate ' Emulation for 32-bit applications' CONFIG_SND_BIT32_EMUL
+fi
dep_tristate ' Sequencer support' CONFIG_SND_SEQUENCER $CONFIG_SND
if [ "$CONFIG_SND_SEQUENCER" != "n" ]; then
dep_tristate ' Sequencer dummy client' CONFIG_SND_SEQ_DUMMY $CONFIG_SND_SEQUENCER
diff --git a/sound/core/Makefile b/sound/core/Makefile
index 50dd397f4843..83f5d792b5e7 100644
--- a/sound/core/Makefile
+++ b/sound/core/Makefile
@@ -45,6 +45,11 @@ endif
obj-$(CONFIG_SND_SEQUENCER) += snd-timer.o
+subdir-$(CONFIG_SND_BIT32_EMUL) += ioctl32
+ifeq ($(CONFIG_SND_BIT32_EMUL),y)
+ obj-y += ioctl32/_ioctl32.o
+endif
+
# Toplevel Module Dependency
obj-$(CONFIG_SND_DUMMY) += snd-pcm.o snd-timer.o snd.o
obj-$(CONFIG_SND_VIRMIDI) += snd-rawmidi.o snd.o snd-timer.o
@@ -72,8 +77,8 @@ obj-$(CONFIG_SND_OPTI92X_AD1848) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o sn
obj-$(CONFIG_SND_OPTI92X_CS4231) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_OPTI93X) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_SB8) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_SB16) += snd-pcm.o snd-timer.o snd.o snd-hwdep.o snd-rawmidi.o
-obj-$(CONFIG_SND_SBAWE) += snd-pcm.o snd-timer.o snd.o snd-hwdep.o snd-rawmidi.o
+obj-$(CONFIG_SND_SB16) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
+obj-$(CONFIG_SND_SBAWE) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
obj-$(CONFIG_SND_ES968) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
obj-$(CONFIG_SND_WAVEFRONT) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_ALS4000) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
@@ -85,7 +90,7 @@ obj-$(CONFIG_SND_ES1938) += snd-pcm.o snd-timer.o snd.o snd-hwdep.o snd-rawmidi.
obj-$(CONFIG_SND_ES1968) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
obj-$(CONFIG_SND_FM801) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_ICE1712) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
-obj-$(CONFIG_SND_INTEL8X0) += snd-pcm.o snd-timer.o snd.o
+obj-$(CONFIG_SND_INTEL8X0) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
obj-$(CONFIG_SND_MAESTRO3) += snd-pcm.o snd-timer.o snd.o
obj-$(CONFIG_SND_RME96) += snd-pcm.o snd-timer.o snd.o
obj-$(CONFIG_SND_SONICVIBES) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
@@ -100,6 +105,10 @@ obj-$(CONFIG_SND_RME9652) += snd-pcm.o snd-timer.o snd.o
obj-$(CONFIG_SND_TRIDENT) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
obj-$(CONFIG_SND_YMFPCI) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_POWERMAC) += snd-pcm.o snd-timer.o snd.o
+ifeq ($(CONFIG_SND_SB16_CSP),y)
+ obj-$(CONFIG_SND_SB16) += snd-hwdep.o
+ obj-$(CONFIG_SND_SBAWE) += snd-hwdep.o
+endif
include $(TOPDIR)/Rules.make
diff --git a/sound/core/info.c b/sound/core/info.c
index 5e6eb497eac4..da8e938bb6cd 100644
--- a/sound/core/info.c
+++ b/sound/core/info.c
@@ -24,12 +24,12 @@
#include <linux/init.h>
#include <linux/vmalloc.h>
#include <linux/time.h>
+#include <linux/smp_lock.h>
#include <sound/core.h>
#include <sound/minors.h>
#include <sound/info.h>
#include <sound/version.h>
#include <linux/proc_fs.h>
-#include <linux/smp_lock.h>
#ifdef CONFIG_DEVFS_FS
#include <linux/devfs_fs_kernel.h>
#endif
@@ -55,7 +55,7 @@ int snd_info_check_reserved_words(const char *str)
"memdebug",
"detect",
"devices",
- "oss-devices",
+ "oss",
"cards",
"timers",
"synth",
@@ -124,6 +124,9 @@ int snd_iprintf(snd_info_buffer_t * buffer, char *fmt,...)
struct proc_dir_entry *snd_proc_root = NULL;
struct proc_dir_entry *snd_proc_dev = NULL;
snd_info_entry_t *snd_seq_root = NULL;
+#ifdef CONFIG_SND_OSSEMUL
+snd_info_entry_t *snd_oss_root = NULL;
+#endif
#ifdef LINUX_2_2
static void snd_info_fill_inode(struct inode *inode, int fill)
@@ -163,11 +166,13 @@ static loff_t snd_info_entry_llseek(struct file *file, loff_t offset, int orig)
{
snd_info_private_data_t *data;
struct snd_info_entry *entry;
- int ret = -EINVAL;
+ loff_t ret;
data = snd_magic_cast(snd_info_private_data_t, file->private_data, return -ENXIO);
entry = data->entry;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 3)
lock_kernel();
+#endif
switch (entry->content) {
case SNDRV_INFO_CONTENT_TEXT:
switch (orig) {
@@ -181,6 +186,7 @@ static loff_t snd_info_entry_llseek(struct file *file, loff_t offset, int orig)
goto out;
case 2: /* SEEK_END */
default:
+ ret = -EINVAL;
goto out;
}
break;
@@ -195,7 +201,9 @@ static loff_t snd_info_entry_llseek(struct file *file, loff_t offset, int orig)
}
ret = -ENXIO;
out:
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 3)
unlock_kernel();
+#endif
return ret;
}
@@ -623,6 +631,19 @@ int __init snd_info_init(void)
if (p == NULL)
return -ENOMEM;
snd_proc_dev = p;
+#ifdef CONFIG_SND_OSSEMUL
+ {
+ snd_info_entry_t *entry;
+ if ((entry = snd_info_create_module_entry(THIS_MODULE, "oss", NULL)) == NULL)
+ return -ENOMEM;
+ entry->mode = S_IFDIR | S_IRUGO | S_IXUGO;
+ if (snd_info_register(entry) < 0) {
+ snd_info_free_entry(entry);
+ return -ENOMEM;
+ }
+ snd_oss_root = entry;
+ }
+#endif
#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
{
snd_info_entry_t *entry;
@@ -664,6 +685,10 @@ int __exit snd_info_done(void)
if (snd_seq_root)
snd_info_unregister(snd_seq_root);
#endif
+#ifdef CONFIG_SND_OSSEMUL
+ if (snd_oss_root)
+ snd_info_unregister(snd_oss_root);
+#endif
snd_remove_proc_entry(snd_proc_root, snd_proc_dev);
snd_remove_proc_entry(&proc_root, snd_proc_root);
}
diff --git a/sound/core/info_oss.c b/sound/core/info_oss.c
index 940882ff8531..85e7bcbb72eb 100644
--- a/sound/core/info_oss.c
+++ b/sound/core/info_oss.c
@@ -114,7 +114,7 @@ int snd_info_minor_register(void)
snd_info_entry_t *entry;
memset(snd_sndstat_strings, 0, sizeof(snd_sndstat_strings));
- if ((entry = snd_info_create_module_entry(THIS_MODULE, "sndstat", NULL)) != NULL) {
+ if ((entry = snd_info_create_module_entry(THIS_MODULE, "sndstat", snd_oss_root)) != NULL) {
entry->content = SNDRV_INFO_CONTENT_TEXT;
entry->c.text.read_size = 2048;
entry->c.text.read = snd_sndstat_proc_read;
diff --git a/sound/core/ioctl32/Makefile b/sound/core/ioctl32/Makefile
new file mode 100644
index 000000000000..ddd94bfd3dfd
--- /dev/null
+++ b/sound/core/ioctl32/Makefile
@@ -0,0 +1,17 @@
+#
+# Makefile for ALSA
+# Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>
+#
+
+O_TARGET := _ioctl32.o
+
+list-multi := snd-ioctl32.o
+
+snd-ioctl32-objs := ioctl32.o pcm32.o rawmidi32.o timer32.o hwdep32.o
+
+obj-$(CONFIG_SND_BIT32_EMUL) += snd-ioctl32.o
+
+include $(TOPDIR)/Rules.make
+
+snd-ioctl32.o: $(snd-ioctl32-objs)
+ $(LD) $(LD_RFLAG) -r -o $@ $(snd-ioctl32-objs)
diff --git a/sound/core/ioctl32/hwdep32.c b/sound/core/ioctl32/hwdep32.c
new file mode 100644
index 000000000000..5d0eb0cc3ee0
--- /dev/null
+++ b/sound/core/ioctl32/hwdep32.c
@@ -0,0 +1,37 @@
+/*
+ * 32bit -> 64bit ioctl wrapper for timer API
+ * Copyright (c) by Takashi Iwai <tiwai@suse.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#define __NO_VERSION__
+#include <sound/driver.h>
+#include <linux/time.h>
+#include <sound/core.h>
+#include <sound/timer.h>
+#include <asm/uaccess.h>
+#include "ioctl32.h"
+
+#define AP(x) snd_ioctl32_##x
+
+struct ioctl32_mapper hwdep_mappers[] = {
+ { SNDRV_HWDEP_IOCTL_PVERSION, NULL },
+ { SNDRV_HWDEP_IOCTL_INFO, NULL },
+ { SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE, NULL },
+ { SNDRV_CTL_IOCTL_HWDEP_INFO, NULL },
+ { 0 },
+};
diff --git a/sound/core/ioctl32/ioctl32.c b/sound/core/ioctl32/ioctl32.c
new file mode 100644
index 000000000000..cb22362f40b9
--- /dev/null
+++ b/sound/core/ioctl32/ioctl32.c
@@ -0,0 +1,357 @@
+/*
+ * 32bit -> 64bit ioctl wrapper for control API
+ * Copyright (c) by Takashi Iwai <tiwai@suse.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#define __NO_VERSION__
+#include <sound/driver.h>
+#include <linux/smp_lock.h>
+#include <linux/time.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include <asm/uaccess.h>
+#include "ioctl32.h"
+
+/*
+ * register/unregister mappers
+ * exported for other modules
+ */
+
+int register_ioctl32_conversion(unsigned int cmd, int (*handler)(unsigned int, unsigned int, unsigned long, struct file *));
+int unregister_ioctl32_conversion(unsigned int cmd);
+
+
+int snd_ioctl32_register(struct ioctl32_mapper *mappers)
+{
+ int err;
+ struct ioctl32_mapper *m;
+
+ lock_kernel();
+ for (m = mappers; m->cmd; m++) {
+ err = register_ioctl32_conversion(m->cmd, m->handler);
+ if (err < 0) {
+ unlock_kernel();
+ return err;
+ }
+ m->registered++;
+ }
+ return 0;
+}
+
+void snd_ioctl32_unregister(struct ioctl32_mapper *mappers)
+{
+ struct ioctl32_mapper *m;
+
+ lock_kernel();
+ for (m = mappers; m->cmd; m++) {
+ if (m->registered) {
+ unregister_ioctl32_conversion(m->cmd);
+ m->registered = 0;
+ }
+ }
+ unlock_kernel();
+}
+
+
+/*
+ * Controls
+ */
+
+struct sndrv_ctl_elem_list32 {
+ u32 offset;
+ u32 space;
+ u32 used;
+ u32 count;
+ u32 pids;
+ unsigned char reserved[50];
+};
+
+#define CVT_sndrv_ctl_elem_list()\
+{\
+ COPY(offset);\
+ COPY(space);\
+ COPY(used);\
+ COPY(count);\
+ CPTR(pids);\
+}
+
+DEFINE_ALSA_IOCTL(ctl_elem_list);
+
+
+/*
+ * control element info
+ * it uses union, so the things are not easy..
+ */
+
+struct sndrv_ctl_elem_info32 {
+ struct sndrv_ctl_elem_id id; // the size of struct is same
+ s32 type;
+ u32 access;
+ u32 count;
+ s32 owner;
+ union {
+ struct {
+ s32 min;
+ s32 max;
+ s32 step;
+ } integer;
+ struct {
+ u32 items;
+ u32 item;
+ char name[64];
+ } enumerated;
+ unsigned char reserved[128];
+ } value;
+ unsigned char reserved[64];
+};
+
+static int snd_ioctl32_ctl_elem_info(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file)
+{
+ struct sndrv_ctl_elem_info data;
+ struct sndrv_ctl_elem_info32 data32;
+ int err;
+
+ if (copy_from_user(&data32, (void*)arg, sizeof(data32)))
+ return -EFAULT;
+ memset(&data, 0, sizeof(data));
+ data.id = data32.id;
+ err = file->f_op->ioctl(file->f_dentry->d_inode, file, cmd, (unsigned long)&data);
+ if (err < 0)
+ return err;
+ /* restore info to 32bit */
+ data32.type = data.type;
+ data32.access = data.access;
+ data32.count = data.count;
+ data32.owner = data.owner;
+ switch (data.type) {
+ case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
+ case SNDRV_CTL_ELEM_TYPE_INTEGER:
+ data32.value.integer.min = data.value.integer.min;
+ data32.value.integer.max = data.value.integer.min;
+ data32.value.integer.step = data.value.integer.step;
+ break;
+ case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
+ data32.value.enumerated.items = data.value.enumerated.items;
+ data32.value.enumerated.item = data.value.enumerated.item;
+ memcpy(data32.value.enumerated.name, data.value.enumerated.name,
+ sizeof(data.value.enumerated.name));
+ break;
+ default:
+ break;
+ }
+ if (copy_to_user((void*)arg, &data32, sizeof(data32)))
+ return -EFAULT;
+ return err;
+}
+
+
+struct sndrv_ctl_elem_value32 {
+ struct sndrv_ctl_elem_id id;
+ unsigned int indirect: 1;
+ union {
+ union {
+ s32 value[128];
+ u32 value_ptr;
+ } integer;
+ union {
+ u32 item[128];
+ u32 item_ptr;
+ } enumerated;
+ union {
+ unsigned char data[512];
+ u32 data_ptr;
+ } bytes;
+ struct sndrv_aes_iec958 iec958;
+ } value;
+ unsigned char reserved[128];
+};
+
+
+/* hmm, it's so hard to retrieve the value type from the control id.. */
+static int get_ctl_type(struct file *file, snd_ctl_elem_id_t *id)
+{
+ snd_ctl_file_t *ctl;
+ snd_kcontrol_t *kctl;
+ snd_ctl_elem_info_t info;
+ int err;
+
+ ctl = snd_magic_cast(snd_ctl_file_t, file->private_data, return -ENXIO);
+
+ read_lock(&ctl->card->control_rwlock);
+ kctl = snd_ctl_find_id(ctl->card, id);
+ if (! kctl) {
+ read_unlock(&ctl->card->control_rwlock);
+ return -ENXIO;
+ }
+ info.id = *id;
+ err = kctl->info(kctl, &info);
+ if (err >= 0)
+ err = info.type;
+ read_unlock(&ctl->card->control_rwlock);
+ return err;
+}
+
+
+static int snd_ioctl32_ctl_elem_value(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file)
+{
+ // too big?
+ struct sndrv_ctl_elem_value data;
+ struct sndrv_ctl_elem_value32 data32;
+ int err, i;
+ int type;
+ /* FIXME: check the sane ioctl.. */
+
+ if (copy_from_user(&data32, (void*)arg, sizeof(data32)))
+ return -EFAULT;
+ memset(&data, 0, sizeof(data));
+ data.id = data32.id;
+ data.indirect = data32.indirect;
+ if (data.indirect) /* FIXME: this is not correct for long arrays */
+ data.value.integer.value_ptr = (void*)TO_PTR(data32.value.integer.value_ptr);
+ type = get_ctl_type(file, &data.id);
+ if (type < 0)
+ return type;
+ if (! data.indirect) {
+ switch (type) {
+ case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
+ case SNDRV_CTL_ELEM_TYPE_INTEGER:
+ for (i = 0; i < 128; i++)
+ data.value.integer.value[i] = data32.value.integer.value[i];
+ break;
+ case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
+ for (i = 0; i < 128; i++)
+ data.value.enumerated.item[i] = data32.value.enumerated.item[i];
+ break;
+ case SNDRV_CTL_ELEM_TYPE_BYTES:
+ memcpy(data.value.bytes.data, data32.value.bytes.data,
+ sizeof(data.value.bytes.data));
+ break;
+ case SNDRV_CTL_ELEM_TYPE_IEC958:
+ data.value.iec958 = data32.value.iec958;
+ break;
+ default:
+ break;
+ }
+ }
+
+ err = file->f_op->ioctl(file->f_dentry->d_inode, file, cmd, (unsigned long)&data);
+ if (err < 0)
+ return err;
+ /* restore info to 32bit */
+ if (! data.indirect) {
+ switch (type) {
+ case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
+ case SNDRV_CTL_ELEM_TYPE_INTEGER:
+ for (i = 0; i < 128; i++)
+ data.value.integer.value[i] = data32.value.integer.value[i];
+ break;
+ case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
+ for (i = 0; i < 128; i++)
+ data.value.enumerated.item[i] = data32.value.enumerated.item[i];
+ break;
+ case SNDRV_CTL_ELEM_TYPE_BYTES:
+ memcpy(data.value.bytes.data, data32.value.bytes.data,
+ sizeof(data.value.bytes.data));
+ break;
+ case SNDRV_CTL_ELEM_TYPE_IEC958:
+ data.value.iec958 = data32.value.iec958;
+ break;
+ default:
+ break;
+ }
+ }
+ if (copy_to_user((void*)arg, &data32, sizeof(data32)))
+ return -EFAULT;
+ return err;
+}
+
+
+/*
+ */
+
+#define AP(x) snd_ioctl32_##x
+
+static struct ioctl32_mapper control_mappers[] = {
+ /* controls (without rawmidi, hwdep, timer releated ones) */
+ { SNDRV_CTL_IOCTL_PVERSION, NULL },
+ { SNDRV_CTL_IOCTL_CARD_INFO , NULL },
+ { SNDRV_CTL_IOCTL_ELEM_LIST, AP(ctl_elem_list) },
+ { SNDRV_CTL_IOCTL_ELEM_INFO, AP(ctl_elem_info) },
+ { SNDRV_CTL_IOCTL_ELEM_READ, AP(ctl_elem_value) },
+ { SNDRV_CTL_IOCTL_ELEM_WRITE, AP(ctl_elem_value) },
+ { SNDRV_CTL_IOCTL_ELEM_LOCK, NULL },
+ { SNDRV_CTL_IOCTL_ELEM_UNLOCK, NULL },
+ { SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS, NULL },
+ { SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE, NULL },
+ { SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE, NULL },
+ { SNDRV_CTL_IOCTL_PCM_INFO, NULL },
+ { SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE, NULL },
+ { SNDRV_CTL_IOCTL_POWER, NULL },
+ { SNDRV_CTL_IOCTL_POWER_STATE, NULL },
+ { 0 }
+};
+
+
+/*
+ */
+
+extern struct ioctl32_mapper pcm_mappers[];
+extern struct ioctl32_mapper rawmidi_mappers[];
+extern struct ioctl32_mapper timer_mappers[];
+extern struct ioctl32_mapper hwdep_mappers[];
+
+static void snd_ioctl32_done(void)
+{
+ snd_ioctl32_unregister(hwdep_mappers);
+ snd_ioctl32_unregister(timer_mappers);
+ snd_ioctl32_unregister(rawmidi_mappers);
+ snd_ioctl32_unregister(pcm_mappers);
+ snd_ioctl32_unregister(control_mappers);
+}
+
+static int __init snd_ioctl32_init(void)
+{
+ int err;
+
+ err = snd_ioctl32_register(control_mappers);
+ if (err < 0)
+ return err;
+ err = snd_ioctl32_register(pcm_mappers);
+ if (err < 0) {
+ snd_ioctl32_done();
+ return err;
+ }
+ err = snd_ioctl32_register(rawmidi_mappers);
+ if (err < 0) {
+ snd_ioctl32_done();
+ return err;
+ }
+ err = snd_ioctl32_register(timer_mappers);
+ if (err < 0) {
+ snd_ioctl32_done();
+ return err;
+ }
+ err = snd_ioctl32_register(hwdep_mappers);
+ if (err < 0) {
+ snd_ioctl32_done();
+ return err;
+ }
+}
+
+module_init(snd_ioctl32_init)
+module_exit(snd_ioctl32_done)
diff --git a/sound/core/ioctl32/ioctl32.h b/sound/core/ioctl32/ioctl32.h
new file mode 100644
index 000000000000..08c20d58dd55
--- /dev/null
+++ b/sound/core/ioctl32/ioctl32.h
@@ -0,0 +1,79 @@
+/*
+ * 32bit -> 64bit ioctl helpers
+ * Copyright (c) by Takashi Iwai <tiwai@suse.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ *
+ * This file registers the converters from 32-bit ioctls to 64-bit ones.
+ * The converter assumes that a 32-bit user-pointer can be casted by A(x)
+ * macro to a valid 64-bit pointer which is accessible via copy_from/to_user.
+ *
+ */
+
+#ifndef __ALSA_IOCTL32_H
+#define __ALSA_IOCTL32_H
+
+#define TO_PTR(x) A(x)
+
+#define COPY(x) (dst->x = src->x)
+#define CPTR(x) (dst->x = (typeof(dst->x))A(src->x))
+
+#define convert_from_32(type, dstp, srcp)\
+{\
+ struct sndrv_##type *dst = dstp;\
+ struct sndrv_##type##32 *src = srcp;\
+ CVT_##sndrv_##type();\
+}
+
+#define convert_to_32(type, dstp, srcp)\
+{\
+ struct sndrv_##type *src = srcp;\
+ struct sndrv_##type##32 *dst = dstp;\
+ CVT_##sndrv_##type();\
+}
+
+
+#define DEFINE_ALSA_IOCTL(type) \
+static int snd_ioctl32_##type(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file)\
+{\
+ struct sndrv_##type##32 data32;\
+ struct sndrv_##type data;\
+ int err;\
+ if (copy_from_user(&data32, (void*)arg, sizeof(data32)))\
+ return -EFAULT;\
+ memset(&data, 0, sizeof(data));\
+ convert_from_32(type, &data, &data32);\
+ err = file->f_op->ioctl(file->f_dentry->d_inode, file, cmd, (unsigned long)&data);\
+ if (err < 0)\
+ return err;\
+ if (cmd & (_IOC_READ << _IOC_DIRSHIFT)) {\
+ convert_to_32(type, &data32, &data);\
+ if (copy_to_user((void*)arg, &data32, sizeof(data32)))\
+ return -EFAULT;\
+ }\
+ return err;\
+}
+
+struct ioctl32_mapper {
+ unsigned int cmd;
+ int (*handler)(unsigned int, unsigned int, unsigned long, struct file * filp);
+ int registered;
+};
+
+int snd_ioctl32_register(struct ioctl32_mapper *mappers);
+void snd_ioctl32_unregister(struct ioctl32_mapper *mappers);
+
+#endif /* __ALSA_IOCTL32_H */
diff --git a/sound/core/ioctl32/pcm32.c b/sound/core/ioctl32/pcm32.c
new file mode 100644
index 000000000000..3aa994c7bc74
--- /dev/null
+++ b/sound/core/ioctl32/pcm32.c
@@ -0,0 +1,296 @@
+/*
+ * 32bit -> 64bit ioctl wrapper for PCM API
+ * Copyright (c) by Takashi Iwai <tiwai@suse.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#define __NO_VERSION__
+#include <sound/driver.h>
+#include <linux/time.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include "ioctl32.h"
+
+
+/* wrapper for sndrv_pcm_[us]frames */
+struct sndrv_pcm_sframes_str {
+ sndrv_pcm_sframes_t val;
+};
+struct sndrv_pcm_sframes_str32 {
+ s32 val;
+};
+struct sndrv_pcm_uframes_str {
+ sndrv_pcm_uframes_t val;
+};
+struct sndrv_pcm_uframes_str32 {
+ u32 val;
+};
+
+#define CVT_sndrv_pcm_sframes_str() { COPY(val); }
+#define CVT_sndrv_pcm_uframes_str() { COPY(val); }
+
+
+struct sndrv_interval32 {
+ u32 min, max;
+ unsigned int openmin:1,
+ openmax:1,
+ integer:1,
+ empty:1;
+};
+
+struct sndrv_pcm_hw_params32 {
+ u32 flags;
+ u32 masks[SNDRV_PCM_HW_PARAM_LAST_MASK - SNDRV_PCM_HW_PARAM_FIRST_MASK + 1];
+ struct sndrv_interval32 intervals[SNDRV_PCM_HW_PARAM_LAST_INTERVAL - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL + 1];
+ u32 rmask;
+ u32 cmask;
+ u32 info;
+ u32 msbits;
+ u32 rate_num;
+ u32 rate_den;
+ u32 fifo_size;
+ unsigned char reserved[64];
+};
+
+#define numberof(array) (sizeof(array)/sizeof(array[0]))
+
+#define CVT_sndrv_pcm_hw_params()\
+{\
+ int i;\
+ COPY(flags);\
+ for (i = 0; i < numberof(dst->masks); i++)\
+ COPY(masks[i]);\
+ for (i = 0; i < numberof(dst->intervals); i++) {\
+ COPY(intervals[i].min);\
+ COPY(intervals[i].max);\
+ COPY(intervals[i].openmin);\
+ COPY(intervals[i].openmax);\
+ COPY(intervals[i].integer);\
+ COPY(intervals[i].empty);\
+ }\
+ COPY(rmask);\
+ COPY(cmask);\
+ COPY(info);\
+ COPY(msbits);\
+ COPY(rate_num);\
+ COPY(rate_den);\
+ COPY(fifo_size);\
+}
+
+struct sndrv_pcm_sw_params32 {
+ s32 tstamp_mode;
+ u32 period_step;
+ u32 sleep_min;
+ u32 avail_min;
+ u32 xfer_align;
+ u32 start_threshold;
+ u32 stop_threshold;
+ u32 silence_threshold;
+ u32 silence_size;
+ u32 boundary;
+ unsigned char reserved[64];
+};
+
+#define CVT_sndrv_pcm_sw_params()\
+{\
+ COPY(tstamp_mode);\
+ COPY(period_step);\
+ COPY(sleep_min);\
+ COPY(avail_min);\
+ COPY(xfer_align);\
+ COPY(start_threshold);\
+ COPY(stop_threshold);\
+ COPY(silence_threshold);\
+ COPY(silence_size);\
+ COPY(boundary);\
+}
+
+struct sndrv_pcm_channel_info32 {
+ u32 channel;
+ u32 offset;
+ u32 first;
+ u32 step;
+};
+
+#define CVT_sndrv_pcm_channel_info()\
+{\
+ COPY(channel);\
+ COPY(offset);\
+ COPY(first);\
+ COPY(step);\
+}
+
+struct timeval32 {
+ s32 tv_sec;
+ s32 tv_usec;
+};
+
+struct sndrv_pcm_status32 {
+ s32 state;
+ struct timeval32 trigger_tstamp;
+ struct timeval32 tstamp;
+ u32 appl_ptr;
+ u32 hw_ptr;
+ s32 delay;
+ u32 avail;
+ u32 avail_max;
+ u32 overrange;
+ s32 suspended_state;
+ unsigned char reserved[60];
+};
+
+#define CVT_sndrv_pcm_status()\
+{\
+ COPY(state);\
+ COPY(trigger_tstamp.tv_sec);\
+ COPY(trigger_tstamp.tv_usec);\
+ COPY(tstamp.tv_sec);\
+ COPY(tstamp.tv_usec);\
+ COPY(appl_ptr);\
+ COPY(hw_ptr);\
+ COPY(delay);\
+ COPY(avail);\
+ COPY(avail_max);\
+ COPY(overrange);\
+ COPY(suspended_state);\
+}
+
+struct sndrv_xferi32 {
+ s32 result;
+ u32 buf;
+ u32 frames;
+};
+
+#define CVT_sndrv_xferi()\
+{\
+ COPY(result);\
+ CPTR(buf);\
+ COPY(frames);\
+}
+
+DEFINE_ALSA_IOCTL(pcm_uframes_str);
+DEFINE_ALSA_IOCTL(pcm_sframes_str);
+DEFINE_ALSA_IOCTL(pcm_hw_params);
+DEFINE_ALSA_IOCTL(pcm_sw_params);
+DEFINE_ALSA_IOCTL(pcm_channel_info);
+DEFINE_ALSA_IOCTL(pcm_status);
+DEFINE_ALSA_IOCTL(xferi);
+
+/* snd_xfern needs remapping of bufs */
+struct sndrv_xfern32 {
+ s32 result;
+ u32 bufs; /* this is void **; */
+ u32 frames;
+};
+
+/*
+ * xfern ioctl nees to copy (up to) 128 pointers on stack.
+ * although we may pass the copied pointers through f_op->ioctl, but the ioctl
+ * handler there expands again the same 128 pointers on stack, so it is better
+ * to handle the function (calling pcm_readv/writev) directly in this handler.
+ */
+static int snd_ioctl32_xfern(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file)
+{
+ snd_pcm_file_t *pcm_file;
+ snd_pcm_substream_t *substream;
+ struct sndrv_xfern32 data32, *srcptr = (struct sndrv_xfern32*)arg;
+ void *bufs[128];
+ int err = 0, ch, i;
+ u32 *bufptr;
+
+ /* FIXME: need to check whether fop->ioctl is sane */
+
+ pcm_file = snd_magic_cast(snd_pcm_file_t, file->private_data, return -ENXIO);
+ substream = pcm_file->substream;
+ snd_assert(substream != NULL && substream->runtime, return -ENXIO);
+
+ /* check validty of the command */
+ switch (cmd) {
+ case SNDRV_PCM_IOCTL_WRITEN_FRAMES:
+ if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
+ return -EINVAL;
+ if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN)
+ return -EBADFD;
+ case SNDRV_PCM_IOCTL_READN_FRAMES:
+ if (substream->stream != SNDRV_PCM_STREAM_CAPTURE)
+ return -EINVAL;
+ break;
+ }
+ if ((ch = substream->runtime->channels) > 128)
+ return -EINVAL;
+ if (get_user(data32.frames, &srcptr->frames))
+ return -EFAULT;
+ __get_user(data32.bufs, &srcptr->bufs);
+ bufptr = (u32*)TO_PTR(data32.bufs);
+ for (i = 0; i < ch; i++) {
+ u32 ptr;
+ if (get_user(ptr, bufptr))
+ return -EFAULT;
+ bufs[ch] = (void*)TO_PTR(ptr);
+ bufptr++;
+ }
+ switch (cmd) {
+ case SNDRV_PCM_IOCTL_WRITEN_FRAMES:
+ err = snd_pcm_lib_writev(substream, bufs, data32.frames);
+ break;
+ case SNDRV_PCM_IOCTL_READN_FRAMES:
+ err = snd_pcm_lib_readv(substream, bufs, data32.frames);
+ break;
+ }
+
+ if (err < 0)
+ return err;
+ if (put_user(err, &srcptr->result))
+ return -EFAULT;
+ return err < 0 ? err : 0;
+}
+
+
+#define AP(x) snd_ioctl32_##x
+
+struct ioctl32_mapper pcm_mappers[] = {
+ { SNDRV_PCM_IOCTL_PVERSION, NULL },
+ { SNDRV_PCM_IOCTL_INFO, NULL },
+ { SNDRV_PCM_IOCTL_HW_REFINE, AP(pcm_hw_params) },
+ { SNDRV_PCM_IOCTL_HW_PARAMS, AP(pcm_hw_params) },
+ { SNDRV_PCM_IOCTL_HW_FREE, NULL },
+ { SNDRV_PCM_IOCTL_SW_PARAMS, AP(pcm_sw_params) },
+ { SNDRV_PCM_IOCTL_STATUS, AP(pcm_status) },
+ { SNDRV_PCM_IOCTL_DELAY, AP(pcm_sframes_str) },
+ { SNDRV_PCM_IOCTL_CHANNEL_INFO, AP(pcm_channel_info) },
+ { SNDRV_PCM_IOCTL_PREPARE, NULL },
+ { SNDRV_PCM_IOCTL_RESET, NULL },
+ { SNDRV_PCM_IOCTL_START, NULL },
+ { SNDRV_PCM_IOCTL_DROP, NULL },
+ { SNDRV_PCM_IOCTL_DRAIN, NULL },
+ { SNDRV_PCM_IOCTL_PAUSE, NULL },
+ { SNDRV_PCM_IOCTL_REWIND, AP(pcm_uframes_str) },
+ { SNDRV_PCM_IOCTL_RESUME, NULL },
+ { SNDRV_PCM_IOCTL_XRUN, NULL },
+ { SNDRV_PCM_IOCTL_WRITEI_FRAMES, AP(xferi) },
+ { SNDRV_PCM_IOCTL_READI_FRAMES, AP(xferi) },
+ { SNDRV_PCM_IOCTL_WRITEN_FRAMES, AP(xfern) },
+ { SNDRV_PCM_IOCTL_READN_FRAMES, AP(xfern) },
+ { SNDRV_PCM_IOCTL_LINK, NULL },
+ { SNDRV_PCM_IOCTL_UNLINK, NULL },
+
+ { SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE, NULL },
+ { SNDRV_CTL_IOCTL_PCM_INFO, NULL },
+ { SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE, NULL },
+
+ { 0 },
+};
diff --git a/sound/core/ioctl32/rawmidi32.c b/sound/core/ioctl32/rawmidi32.c
new file mode 100644
index 000000000000..d5e89ffd9f98
--- /dev/null
+++ b/sound/core/ioctl32/rawmidi32.c
@@ -0,0 +1,86 @@
+/*
+ * 32bit -> 64bit ioctl wrapper for raw MIDI API
+ * Copyright (c) by Takashi Iwai <tiwai@suse.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#define __NO_VERSION__
+#include <sound/driver.h>
+#include <linux/time.h>
+#include <sound/core.h>
+#include <sound/rawmidi.h>
+#include <asm/uaccess.h>
+#include "ioctl32.h"
+
+struct sndrv_rawmidi_params32 {
+ s32 stream;
+ u32 buffer_size;
+ u32 avail_min;
+ unsigned int no_active_sensing: 1;
+ unsigned char reserved[16];
+};
+
+#define CVT_sndrv_rawmidi_params()\
+{\
+ COPY(stream);\
+ COPY(buffer_size);\
+ COPY(avail_min);\
+ COPY(no_active_sensing);\
+}
+
+struct timeval32 {
+ s32 tv_sec;
+ s32 tv_usec;
+};
+
+struct sndrv_rawmidi_status32 {
+ s32 stream;
+ struct timeval32 tstamp;
+ u32 avail;
+ u32 xruns;
+ unsigned char reserved[16];
+};
+
+#define CVT_sndrv_rawmidi_status()\
+{\
+ COPY(stream);\
+ COPY(tstamp.tv_sec);\
+ COPY(tstamp.tv_usec);\
+ COPY(avail);\
+ COPY(xruns);\
+}
+
+DEFINE_ALSA_IOCTL(rawmidi_params);
+DEFINE_ALSA_IOCTL(rawmidi_status);
+
+
+#define AP(x) snd_ioctl32_##x
+
+struct ioctl32_mapper rawmidi_mappers[] = {
+ { SNDRV_RAWMIDI_IOCTL_PVERSION, NULL },
+ { SNDRV_RAWMIDI_IOCTL_INFO, NULL },
+ { SNDRV_RAWMIDI_IOCTL_PARAMS, AP(rawmidi_params) },
+ { SNDRV_RAWMIDI_IOCTL_STATUS, AP(rawmidi_status) },
+ { SNDRV_RAWMIDI_IOCTL_DROP, NULL },
+ { SNDRV_RAWMIDI_IOCTL_DRAIN, NULL },
+
+ { SNDRV_CTL_IOCTL_RAWMIDI_NEXT_DEVICE, NULL },
+ { SNDRV_CTL_IOCTL_RAWMIDI_INFO, NULL },
+ { SNDRV_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE, NULL },
+
+ { 0 },
+};
diff --git a/sound/core/ioctl32/timer32.c b/sound/core/ioctl32/timer32.c
new file mode 100644
index 000000000000..4e657f7a309f
--- /dev/null
+++ b/sound/core/ioctl32/timer32.c
@@ -0,0 +1,93 @@
+/*
+ * 32bit -> 64bit ioctl wrapper for timer API
+ * Copyright (c) by Takashi Iwai <tiwai@suse.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#define __NO_VERSION__
+#include <sound/driver.h>
+#include <linux/time.h>
+#include <sound/core.h>
+#include <sound/timer.h>
+#include <asm/uaccess.h>
+#include "ioctl32.h"
+
+struct sndrv_timer_info32 {
+ u32 flags;
+ s32 card;
+ unsigned char id[64];
+ unsigned char name[80];
+ u32 ticks;
+ u32 resolution;
+ unsigned char reserved[64];
+};
+
+#define CVT_sndrv_timer_info()\
+{\
+ COPY(flags);\
+ COPY(card);\
+ memcpy(dst->id, src->id, sizeof(src->id));\
+ memcpy(dst->name, src->name, sizeof(src->name));\
+ COPY(ticks);\
+ COPY(resolution);\
+}
+
+struct timeval32 {
+ s32 tv_sec;
+ s32 tv_usec;
+};
+
+struct sndrv_timer_status32 {
+ struct timeval32 tstamp;
+ u32 resolution;
+ u32 lost;
+ u32 overrun;
+ u32 queue;
+ unsigned char reserved[64];
+};
+
+#define CVT_sndrv_timer_status()\
+{\
+ COPY(tstamp.tv_sec);\
+ COPY(tstamp.tv_usec);\
+ COPY(resolution);\
+ COPY(lost);\
+ COPY(overrun);\
+ COPY(queue);\
+}
+
+DEFINE_ALSA_IOCTL(timer_info);
+DEFINE_ALSA_IOCTL(timer_status);
+
+
+/*
+ */
+
+#define AP(x) snd_ioctl32_##x
+
+struct ioctl32_mapper timer_mappers[] = {
+ { SNDRV_TIMER_IOCTL_PVERSION, NULL },
+ { SNDRV_TIMER_IOCTL_NEXT_DEVICE, NULL },
+ { SNDRV_TIMER_IOCTL_SELECT, NULL },
+ { SNDRV_TIMER_IOCTL_INFO, AP(timer_info) },
+ { SNDRV_TIMER_IOCTL_PARAMS, NULL },
+ { SNDRV_TIMER_IOCTL_STATUS, AP(timer_status) },
+ { SNDRV_TIMER_IOCTL_START, NULL },
+ { SNDRV_TIMER_IOCTL_STOP, NULL },
+ { SNDRV_TIMER_IOCTL_CONTINUE, NULL },
+ { 0 },
+};
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
index 57bcaa94802c..03cc8bce04b2 100644
--- a/sound/core/oss/pcm_oss.c
+++ b/sound/core/oss/pcm_oss.c
@@ -516,7 +516,6 @@ static int snd_pcm_oss_make_ready(snd_pcm_substream_t *substream)
snd_pcm_sframes_t snd_pcm_oss_write3(snd_pcm_substream_t *substream, const char *ptr, snd_pcm_uframes_t frames, int in_kernel)
{
snd_pcm_runtime_t *runtime = substream->runtime;
- mm_segment_t fs;
int ret;
while (1) {
if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
@@ -525,11 +524,14 @@ snd_pcm_sframes_t snd_pcm_oss_write3(snd_pcm_substream_t *substream, const char
if (ret < 0)
break;
}
- if (in_kernel)
+ if (in_kernel) {
+ mm_segment_t fs;
fs = snd_enter_user();
- ret = snd_pcm_lib_write(substream, ptr, frames);
- if (in_kernel)
+ ret = snd_pcm_lib_write(substream, ptr, frames);
snd_leave_user(fs);
+ } else {
+ ret = snd_pcm_lib_write(substream, ptr, frames);
+ }
if (ret != -EPIPE && ret != -ESTRPIPE)
break;
/* test, if we can't store new data, because the stream */
@@ -543,7 +545,6 @@ snd_pcm_sframes_t snd_pcm_oss_write3(snd_pcm_substream_t *substream, const char
snd_pcm_sframes_t snd_pcm_oss_read3(snd_pcm_substream_t *substream, char *ptr, snd_pcm_uframes_t frames, int in_kernel)
{
snd_pcm_runtime_t *runtime = substream->runtime;
- mm_segment_t fs;
int ret;
while (1) {
if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
@@ -556,11 +557,15 @@ snd_pcm_sframes_t snd_pcm_oss_read3(snd_pcm_substream_t *substream, char *ptr, s
if (ret < 0)
break;
}
- if (in_kernel)
- fs = snd_enter_user();
ret = snd_pcm_lib_read(substream, ptr, frames);
- if (in_kernel)
+ if (in_kernel) {
+ mm_segment_t fs;
+ fs = snd_enter_user();
+ ret = snd_pcm_lib_read(substream, ptr, frames);
snd_leave_user(fs);
+ } else {
+ ret = snd_pcm_lib_read(substream, ptr, frames);
+ }
if (ret != -EPIPE && ret != -ESTRPIPE)
break;
}
@@ -570,7 +575,6 @@ snd_pcm_sframes_t snd_pcm_oss_read3(snd_pcm_substream_t *substream, char *ptr, s
snd_pcm_sframes_t snd_pcm_oss_writev3(snd_pcm_substream_t *substream, void **bufs, snd_pcm_uframes_t frames, int in_kernel)
{
snd_pcm_runtime_t *runtime = substream->runtime;
- mm_segment_t fs;
int ret;
while (1) {
if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
@@ -579,13 +583,17 @@ snd_pcm_sframes_t snd_pcm_oss_writev3(snd_pcm_substream_t *substream, void **buf
if (ret < 0)
break;
}
- if (in_kernel)
+ if (in_kernel) {
+ mm_segment_t fs;
fs = snd_enter_user();
- ret = snd_pcm_lib_writev(substream, bufs, frames);
- if (in_kernel)
+ ret = snd_pcm_lib_writev(substream, bufs, frames);
snd_leave_user(fs);
+ } else {
+ ret = snd_pcm_lib_writev(substream, bufs, frames);
+ }
if (ret != -EPIPE && ret != -ESTRPIPE)
break;
+
/* test, if we can't store new data, because the stream */
/* has not been started */
if (runtime->status->state == SNDRV_PCM_STATE_PREPARED)
@@ -597,7 +605,6 @@ snd_pcm_sframes_t snd_pcm_oss_writev3(snd_pcm_substream_t *substream, void **buf
snd_pcm_sframes_t snd_pcm_oss_readv3(snd_pcm_substream_t *substream, void **bufs, snd_pcm_uframes_t frames, int in_kernel)
{
snd_pcm_runtime_t *runtime = substream->runtime;
- mm_segment_t fs;
int ret;
while (1) {
if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
@@ -610,11 +617,14 @@ snd_pcm_sframes_t snd_pcm_oss_readv3(snd_pcm_substream_t *substream, void **bufs
if (ret < 0)
break;
}
- if (in_kernel)
+ if (in_kernel) {
+ mm_segment_t fs;
fs = snd_enter_user();
- ret = snd_pcm_lib_readv(substream, bufs, frames);
- if (in_kernel)
+ ret = snd_pcm_lib_readv(substream, bufs, frames);
snd_leave_user(fs);
+ } else {
+ ret = snd_pcm_lib_readv(substream, bufs, frames);
+ }
if (ret != -EPIPE && ret != -ESTRPIPE)
break;
}
diff --git a/sound/core/rtctimer.c b/sound/core/rtctimer.c
index 51005b69d76b..c7085ae4aef5 100644
--- a/sound/core/rtctimer.c
+++ b/sound/core/rtctimer.c
@@ -18,19 +18,12 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
- *
- *================================================================
- * For enabling this timer, apply the patch file to your kernel.
- * The configure script checks the patch automatically.
- * The patches, rtc-xxx.dif, are found under utils/patches, where
- * xxx is the kernel version.
- *================================================================
- *
*/
#include <sound/driver.h>
#include <linux/init.h>
#include <linux/time.h>
+#include <linux/interrupt.h>
#include <sound/core.h>
#include <sound/timer.h>
#include <sound/info.h>
@@ -59,7 +52,7 @@ static int rtctimer_stop(snd_timer_t *t);
/*
- * The harware depenant description for this timer.
+ * The hardware dependent description for this timer.
*/
static struct _snd_timer_hardware rtc_hw = {
flags: SNDRV_TIMER_HW_FIRST|SNDRV_TIMER_HW_AUTO,
@@ -72,7 +65,7 @@ static struct _snd_timer_hardware rtc_hw = {
int rtctimer_freq = RTC_FREQ; /* frequency */
static snd_timer_t *rtctimer;
-static volatile int rtc_inc = 0;
+static atomic_t rtc_inc = ATOMIC_INIT(0);
static rtc_task_t rtc_task;
/* tasklet */
@@ -83,6 +76,10 @@ static struct tasklet_struct rtc_tq;
static int
rtctimer_open(snd_timer_t *t)
{
+ err = rtc_register(&rtc_task);
+ if (err < 0)
+ return err;
+ t->private_data = &rtc_task;
MOD_INC_USE_COUNT;
return 0;
}
@@ -90,6 +87,11 @@ rtctimer_open(snd_timer_t *t)
static int
rtctimer_close(snd_timer_t *t)
{
+ rtc_task_t *rtc = t->private_data;
+ if (rtc) {
+ rtc_unregister(rtc);
+ t->private_data = NULL;
+ }
MOD_DEC_USE_COUNT;
return 0;
}
@@ -101,7 +103,7 @@ rtctimer_start(snd_timer_t *timer)
snd_assert(rtc != NULL, return -EINVAL);
rtc_control(rtc, RTC_IRQP_SET, rtctimer_freq);
rtc_control(rtc, RTC_PIE_ON, 0);
- rtc_inc = 0;
+ atomic_set(&rtc_inc, 0);
return 0;
}
@@ -119,12 +121,15 @@ rtctimer_stop(snd_timer_t *timer)
*/
static void rtctimer_interrupt(void *private_data)
{
- rtc_inc++;
+ atomic_inc(&rtc_inc);
#ifdef USE_TASKLET
tasklet_hi_schedule(&rtc_tq);
#else
- snd_timer_interrupt((snd_timer_t*)private_data, rtc_inc);
- rtc_inc = 0;
+ {
+ int ticks = atomic_read(&rtc_inc);
+ snd_timer_interrupt((snd_timer_t*)private_data, ticks);
+ atomic_sub(ticks, &rtc_inc);
+ }
#endif /* USE_TASKLET */
}
@@ -132,20 +137,16 @@ static void rtctimer_interrupt(void *private_data)
static void rtctimer_interrupt2(unsigned long private_data)
{
snd_timer_t *timer = (snd_timer_t *)private_data;
+ int ticks;
+
snd_assert(timer != NULL, return);
do {
- snd_timer_interrupt(timer, 1);
- } while (--rtc_inc > 0);
+ ticks = atomic_read(&rtc_inc);
+ snd_timer_interrupt(timer, ticks);
+ } while (!atomic_sub_and_test(ticks, &rtc_inc));
}
#endif /* USE_TASKLET */
-static void rtctimer_private_free(snd_timer_t *timer)
-{
- rtc_task_t *rtc = timer->private_data;
- if (rtc)
- rtc_unregister(rtc);
-}
-
/*
* ENTRY functions
@@ -179,23 +180,16 @@ static int __init rtctimer_init(void)
timer->hw = rtc_hw;
timer->hw.resolution = NANO_SEC / rtctimer_freq;
- /* register RTC callback */
+ /* set up RTC callback */
rtc_task.func = rtctimer_interrupt;
rtc_task.private_data = timer;
- err = rtc_register(&rtc_task);
- if (err < 0) {
- snd_timer_global_free(timer);
- return err;
- }
- timer->private_data = &rtc_task;
- timer->private_free = rtctimer_private_free;
err = snd_timer_global_register(timer);
if (err < 0) {
snd_timer_global_free(timer);
return err;
}
- rtctimer = timer;
+ rtctimer = timer; /* remember this */
return 0;
}
@@ -210,7 +204,7 @@ static void __exit rtctimer_exit(void)
/*
- * exported stuffs
+ * exported stuff
*/
module_init(rtctimer_init)
module_exit(rtctimer_exit)
diff --git a/sound/core/seq/Makefile b/sound/core/seq/Makefile
index ef7fc7a9e5a5..569cd0ae110f 100644
--- a/sound/core/seq/Makefile
+++ b/sound/core/seq/Makefile
@@ -72,6 +72,7 @@ obj-$(CONFIG_SND_ES1938) += snd-seq-device.o snd-seq-midi-emul.o snd-seq.o snd-s
obj-$(CONFIG_SND_ES1968) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o
obj-$(CONFIG_SND_FM801) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o
obj-$(CONFIG_SND_ICE1712) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o
+obj-$(CONFIG_SND_INTEL8X0) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o
obj-$(CONFIG_SND_SONICVIBES) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o
obj-$(CONFIG_SND_VIA686) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o
obj-$(CONFIG_SND_ALI5451) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o
diff --git a/sound/core/seq/seq_midi_event.c b/sound/core/seq/seq_midi_event.c
index b3ced9438d91..7ebf0514b16b 100644
--- a/sound/core/seq/seq_midi_event.c
+++ b/sound/core/seq/seq_midi_event.c
@@ -68,8 +68,8 @@ static struct status_event_list_t {
event_decode_t decode;
} status_event[] = {
/* 0x80 - 0xf0 */
- {SNDRV_SEQ_EVENT_NOTEOFF, 2, note_event, note_decode},
- {SNDRV_SEQ_EVENT_NOTEON, 2, note_event, note_decode},
+ {SNDRV_SEQ_EVENT_NOTEOFF, 2, note_event, note_decode},
+ {SNDRV_SEQ_EVENT_NOTEON, 2, note_event, note_decode},
{SNDRV_SEQ_EVENT_KEYPRESS, 2, note_event, note_decode},
{SNDRV_SEQ_EVENT_CONTROLLER, 2, two_param_ctrl_event, two_param_decode},
{SNDRV_SEQ_EVENT_PGMCHANGE, 1, one_param_ctrl_event, one_param_decode},
@@ -78,9 +78,9 @@ static struct status_event_list_t {
{SNDRV_SEQ_EVENT_NONE, 0, NULL, NULL}, /* 0xf0 */
/* 0xf0 - 0xff */
{SNDRV_SEQ_EVENT_SYSEX, 1, NULL, NULL}, /* sysex: 0xf0 */
- {SNDRV_SEQ_EVENT_QFRAME, 1, one_param_event, one_param_decode}, /* 0xf1 */
- {SNDRV_SEQ_EVENT_SONGPOS, 2, songpos_event, songpos_decode}, /* 0xf2 */
- {SNDRV_SEQ_EVENT_SONGSEL, 1, one_param_event, one_param_decode}, /* 0xf3 */
+ {SNDRV_SEQ_EVENT_QFRAME, 1, one_param_event, one_param_decode}, /* 0xf1 */
+ {SNDRV_SEQ_EVENT_SONGPOS, 2, songpos_event, songpos_decode}, /* 0xf2 */
+ {SNDRV_SEQ_EVENT_SONGSEL, 1, one_param_event, one_param_decode}, /* 0xf3 */
{SNDRV_SEQ_EVENT_NONE, 0, NULL, NULL}, /* 0xf4 */
{SNDRV_SEQ_EVENT_NONE, 0, NULL, NULL}, /* 0xf5 */
{SNDRV_SEQ_EVENT_TUNE_REQUEST, 0, NULL, NULL}, /* 0xf6 */
@@ -92,7 +92,7 @@ static struct status_event_list_t {
{SNDRV_SEQ_EVENT_STOP, 0, NULL, NULL}, /* 0xfc */
{SNDRV_SEQ_EVENT_NONE, 0, NULL, NULL}, /* 0xfd */
{SNDRV_SEQ_EVENT_SENSING, 0, NULL, NULL}, /* 0xfe */
- {SNDRV_SEQ_EVENT_RESET, 0, NULL, NULL}, /* 0xff */
+ {SNDRV_SEQ_EVENT_RESET, 0, NULL, NULL}, /* 0xff */
};
static int extra_decode_ctrl14(snd_midi_event_t *dev, unsigned char *buf, int len, snd_seq_event_t *ev);
@@ -128,6 +128,7 @@ int snd_midi_event_new(int bufsize, snd_midi_event_t **rdev)
}
}
dev->bufsize = bufsize;
+ dev->lastcmd = 0xff;
spin_lock_init(&dev->lock);
*rdev = dev;
return 0;
diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c
index df7d693256ab..62271b8b21c8 100644
--- a/sound/core/seq/seq_virmidi.c
+++ b/sound/core/seq/seq_virmidi.c
@@ -233,8 +233,7 @@ static int snd_virmidi_output_open(snd_rawmidi_substream_t * substream)
}
vmidi->seq_mode = rdev->seq_mode;
vmidi->client = rdev->client;
- vmidi->port = rdev->port;
- snd_midi_event_init(vmidi->parser);
+ vmidi->port = rdev->port;
snd_virmidi_init_event(vmidi, &vmidi->event);
vmidi->rdev = rdev;
runtime->private_data = vmidi;
diff --git a/sound/core/sound_oss.c b/sound/core/sound_oss.c
index c3c363091fad..21ce042c818d 100644
--- a/sound/core/sound_oss.c
+++ b/sound/core/sound_oss.c
@@ -212,7 +212,7 @@ int __init snd_minor_info_oss_init(void)
{
snd_info_entry_t *entry;
- entry = snd_info_create_module_entry(THIS_MODULE, "oss-devices", NULL);
+ entry = snd_info_create_module_entry(THIS_MODULE, "devices", snd_oss_root);
if (entry) {
entry->content = SNDRV_INFO_CONTENT_TEXT;
entry->c.text.read_size = PAGE_SIZE;
diff --git a/sound/drivers/Config.help b/sound/drivers/Config.help
new file mode 100644
index 000000000000..7fea38481809
--- /dev/null
+++ b/sound/drivers/Config.help
@@ -0,0 +1,18 @@
+CONFIG_SND_DUMMY
+ Say 'Y' or 'M' to include dummy driver. This driver does nothing, but
+ emulates various mixer controls and PCM devices.
+
+CONFIG_SND_VIRMIDI
+ Say 'Y' or 'M' to include virtual MIDI driver. This driver allows to
+ connect applications using raw MIDI devices to sequencer.
+
+CONFIG_SND_MTPAV
+ Say 'Y' or 'M' to include support for MOTU MidiTimePiece AV multiport
+ MIDI adapter.
+
+CONFIG_SND_SERIAL_U16550
+ Say 'Y' or 'M' to include support for MIDI serial port driver. It works
+ with serial UARTs 16550 and better.
+
+CONFIG_SND_MPU401
+ Say 'Y' or 'M' to include support for MPU401 hardware using UART access.
diff --git a/sound/drivers/mpu401/Makefile b/sound/drivers/mpu401/Makefile
index 731ac31ac7f2..d21747f1cd30 100644
--- a/sound/drivers/mpu401/Makefile
+++ b/sound/drivers/mpu401/Makefile
@@ -37,6 +37,7 @@ obj-$(CONFIG_SND_ES1938) += snd-mpu401-uart.o
obj-$(CONFIG_SND_ES1968) += snd-mpu401-uart.o
obj-$(CONFIG_SND_FM801) += snd-mpu401-uart.o
obj-$(CONFIG_SND_ICE1712) += snd-mpu401-uart.o
+obj-$(CONFIG_SND_INTEL8X0) += snd-mpu401-uart.o
obj-$(CONFIG_SND_SONICVIBES) += snd-mpu401-uart.o
obj-$(CONFIG_SND_VIA686) += snd-mpu401-uart.o
obj-$(CONFIG_SND_ALI5451) += snd-mpu401-uart.o
diff --git a/sound/drivers/mpu401/mpu401_uart.c b/sound/drivers/mpu401/mpu401_uart.c
index 8993ade328cf..b399150e2a6f 100644
--- a/sound/drivers/mpu401/mpu401_uart.c
+++ b/sound/drivers/mpu401/mpu401_uart.c
@@ -28,6 +28,7 @@
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/slab.h>
+#include <linux/ioport.h>
#include <sound/core.h>
#include <sound/mpu401.h>
diff --git a/sound/drivers/mtpav.c b/sound/drivers/mtpav.c
index 64913d5104ba..450032e8a34a 100644
--- a/sound/drivers/mtpav.c
+++ b/sound/drivers/mtpav.c
@@ -54,6 +54,7 @@
#include <asm/io.h>
#include <linux/init.h>
#include <linux/slab.h>
+#include <linux/ioport.h>
#include <sound/core.h>
#define SNDRV_GET_ID
#include <sound/initval.h>
diff --git a/sound/drivers/opl3/Makefile b/sound/drivers/opl3/Makefile
index 77ce497b9877..371dfb9b1bfe 100644
--- a/sound/drivers/opl3/Makefile
+++ b/sound/drivers/opl3/Makefile
@@ -29,7 +29,7 @@ obj-$(CONFIG_SND_GUSEXTREME) += snd-opl3-lib.o
obj-$(CONFIG_SND_OPTI92X_AD1848) += snd-opl3-lib.o
obj-$(CONFIG_SND_OPTI92X_CS4231) += snd-opl3-lib.o
obj-$(CONFIG_SND_OPTI93X) += snd-opl3-lib.o
-obj-$(CONFIG_SND_SB) += snd-opl3-lib.o
+obj-$(CONFIG_SND_SB8) += snd-opl3-lib.o
obj-$(CONFIG_SND_SB16) += snd-opl3-lib.o
obj-$(CONFIG_SND_SBAWE) += snd-opl3-lib.o
obj-$(CONFIG_SND_WAVEFRONT) += snd-opl3-lib.o
@@ -54,7 +54,7 @@ ifeq ($(subst m,y,$(CONFIG_SND_SEQUENCER)),y)
obj-$(CONFIG_SND_OPTI92X_AD1848) += snd-opl3-synth.o
obj-$(CONFIG_SND_OPTI92X_CS4231) += snd-opl3-synth.o
obj-$(CONFIG_SND_OPTI93X) += snd-opl3-synth.o
- obj-$(CONFIG_SND_SB) += snd-opl3-synth.o
+ obj-$(CONFIG_SND_SB8) += snd-opl3-synth.o
obj-$(CONFIG_SND_SB16) += snd-opl3-synth.o
obj-$(CONFIG_SND_SBAWE) += snd-opl3-synth.o
obj-$(CONFIG_SND_WAVEFRONT) += snd-opl3-synth.o
diff --git a/sound/drivers/opl3/opl3_lib.c b/sound/drivers/opl3/opl3_lib.c
index 8f8400bee5f3..91faf5941b4b 100644
--- a/sound/drivers/opl3/opl3_lib.c
+++ b/sound/drivers/opl3/opl3_lib.c
@@ -28,6 +28,7 @@
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/slab.h>
+#include <linux/ioport.h>
#include <sound/minors.h>
MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>, Hannu Savolainen 1993-1996, Rob Hooft");
diff --git a/sound/drivers/serial-u16550.c b/sound/drivers/serial-u16550.c
index 51668110b772..b2ff32b30623 100644
--- a/sound/drivers/serial-u16550.c
+++ b/sound/drivers/serial-u16550.c
@@ -39,7 +39,7 @@
*
* Usage example for MS-124T, with A-B switch in A position:
* setserial /dev/ttyS0 uart none
- * /sbin/modprobe snd-card-serial snd_port=0x3f8 snd_irq=4 \
+ * /sbin/modprobe snd-serial-u16550 snd_port=0x3f8 snd_irq=4 \
* snd_adaptor=1 snd_speed=19200
*
* - In MS-124W S/A mode, one raw MIDI substream is supported
@@ -49,7 +49,7 @@
*
* Usage example for S/A mode:
* setserial /dev/ttyS0 uart none
- * /sbin/modprobe snd-card-serial snd_port=0x3f8 snd_irq=4 \
+ * /sbin/modprobe snd-serial-u16550 snd_port=0x3f8 snd_irq=4 \
* snd_adaptor=2
*
* - In MS-124W M/B mode, the driver supports 16 ALSA raw MIDI
@@ -67,7 +67,7 @@
*
* Usage example for M/B mode:
* setserial /dev/ttyS0 uart none
- * /sbin/insmod snd-card-serial snd_port=0x3f8 snd_irq=4 \
+ * /sbin/insmod snd-serial-u16550 snd_port=0x3f8 snd_irq=4 \
* snd_adaptor=3
*
* - The MS-124W hardware's M/A mode is currently not supported.
@@ -106,6 +106,7 @@
#include <asm/io.h>
#include <linux/init.h>
#include <linux/slab.h>
+#include <linux/ioport.h>
#include <sound/core.h>
#include <sound/rawmidi.h>
#define SNDRV_GET_ID
diff --git a/sound/i2c/Makefile b/sound/i2c/Makefile
index eff64d7553a5..b9c505fb552d 100644
--- a/sound/i2c/Makefile
+++ b/sound/i2c/Makefile
@@ -13,7 +13,7 @@ snd-i2c-objs := i2c.o
snd-cs8427-objs := cs8427.o
snd-tea6330t-objs := tea6330t.o
-# Module Dependency
+# Toplevel Module Dependency
obj-$(CONFIG_SND_INTERWAVE_STB) += snd-tea6330t.o snd-i2c.o
obj-$(CONFIG_SND_ICE1712) += snd-cs8427.o snd-i2c.o
diff --git a/sound/isa/Config.help b/sound/isa/Config.help
new file mode 100644
index 000000000000..eac9a93c8c19
--- /dev/null
+++ b/sound/isa/Config.help
@@ -0,0 +1,99 @@
+CONFIG_SND_AD1816A
+ Say 'Y' or 'M' to include support for Analog Devices SoundPort AD1816A or
+ compatible sound chips.
+
+CONFIG_SND_AD1848
+ Say 'Y' or 'M' to include support for AD1848 (Analog Devices) or CS4248
+ (Cirrus Logic - Crystal Semiconductors) chips. Please, for newer chips
+ from Cirrus Logic, use CS4231, CS4232 or CS4236+ driver.
+
+CONFIG_SND_CS4231
+ Say 'Y' or 'M' to include support for CS4231 chips from Cirrus Logic -
+ Crystal Semiconductors.
+
+CONFIG_SND_CS4232
+ Say 'Y' or 'M' to include support for CS4232 chips from Cirrus Logic -
+ Crystal Semiconductors.
+
+CONFIG_SND_CS4236
+ Say 'Y' or 'M' to include support for CS4235,CS4236,CS4237B,CS4238B,CS4239
+ chips from Cirrus Logic - Crystal Semiconductors.
+
+CONFIG_SND_ES968
+ Say 'Y' or 'M' to include support for ESS AudioDrive ES968 chip.
+
+CONFIG_SND_ES1688
+ Say 'Y' or 'M' to include support for ESS AudioDrive ES688 or ES1688 chips.
+
+CONFIG_SND_ES18XX
+ Say 'Y' or 'M' to include support for ESS AudioDrive ES18xx chips.
+
+CONFIG_SND_GUSCLASSIC
+ Say 'Y' or 'M' to include support for Gravis UltraSound Classic soundcard.
+
+CONFIG_SND_GUSEXTREME
+ Say 'Y' or 'M' to include support for Gravis UltraSound Extreme soundcard.
+
+CONFIG_SND_GUSMAX
+ Say 'Y' or 'M' to include support for Gravis UltraSound MAX soundcard.
+
+CONFIG_SND_INTERWAVE
+ Say 'Y' or 'M' to include support for AMD InterWave based soundcards
+ (Gravis UltraSound Plug & Play, STB SoundRage32, MED3210, Dynasonic Pro,
+ Panasonic PCA761AW).
+
+CONFIG_SND_INTERWAVE_STB
+ Say 'Y' or 'M' to include support for AMD InterWave based soundcards
+ with TEA6330T bass and treble regulator (UltraSound 32-Pro).
+
+CONFIG_SND_OPTI92X_AD1848
+ Say 'Y' or 'M' to include support for Opti92x soundcards equiped with
+ AD1848 codec.
+
+CONFIG_SND_OPTI92X_CS4231
+ Say 'Y' or 'M' to include support for Opti92x soundcards equiped with
+ CS4231 codec.
+
+CONFIG_SND_OPTI93X
+ Say 'Y' or 'M' to include support for Opti93x soundcards.
+
+CONFIG_SND_SB8
+ Say 'Y' or 'M' to include support for Sound Blaster 1.0/2.0/Pro (8-bit)
+ soundcards or 100% compatible from Creative.
+
+CONFIG_SND_SB16
+ Say 'Y' or 'M' to include support for Sound Blaster 16 (including
+ Plug and Play version).
+
+CONFIG_SND_SBAWE
+ Say 'Y' or 'M' to include support for Sound Blaster AWE (including
+ Plug and Play version).
+
+CONFIG_SND_SB16_CSP
+ Say 'Y' to include support for CSP core. This special coprocessor
+ can do variable tasks like various compression and decompression
+ algorithms.
+
+CONFIG_SND_WAVEFRONT
+ Say 'Y' or 'M' to include support for Turtle Beach Maui, Tropez
+ and Tropez+ soundcards based on Wavefront chip.
+
+CONFIG_SND_ALS100
+ Say 'Y' or 'M' to include support for Avance Logic ALS100, ALS110,
+ ALS120 and ALS200 soundcards.
+
+CONFIG_SND_AZT2320
+ Say 'Y' or 'M' to include support for Aztech Systems AZT2320 soundcard.
+
+CONFIG_SND_CMI8330
+ Say 'Y' or 'M' to include support for C-Media CMI8330 based soundcards.
+
+CONFIG_SND_DT0197H
+ Say 'Y' or 'M' to include support for Diamond Technologies DT-0197H
+ soundcards.
+
+CONFIG_SND_OPL3SA2
+ Say 'Y' or 'M' to include support for Yamaha OPL3SA2 or OPL3SA3 chips.
+
+CONFIG_SND_SGALAXY
+ Say 'Y' or 'M' to include support for Aztech Sound Galaxy.
diff --git a/sound/isa/ad1816a/ad1816a_lib.c b/sound/isa/ad1816a/ad1816a_lib.c
index 2688d1bba07a..4461706461c7 100644
--- a/sound/isa/ad1816a/ad1816a_lib.c
+++ b/sound/isa/ad1816a/ad1816a_lib.c
@@ -24,6 +24,7 @@
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/slab.h>
+#include <linux/ioport.h>
#include <sound/core.h>
#include <sound/ad1816a.h>
diff --git a/sound/isa/ad1848/ad1848_lib.c b/sound/isa/ad1848/ad1848_lib.c
index 9e69d06cd835..7680dbf77491 100644
--- a/sound/isa/ad1848/ad1848_lib.c
+++ b/sound/isa/ad1848/ad1848_lib.c
@@ -25,6 +25,7 @@
#include <asm/dma.h>
#include <linux/delay.h>
#include <linux/slab.h>
+#include <linux/ioport.h>
#include <sound/core.h>
#include <sound/ad1848.h>
diff --git a/sound/isa/azt2320.c b/sound/isa/azt2320.c
index fa55a9fdf120..8e84e21628be 100644
--- a/sound/isa/azt2320.c
+++ b/sound/isa/azt2320.c
@@ -134,7 +134,7 @@ static const struct isapnp_card_id *snd_azt2320_isapnp_id[SNDRV_CARDS] __devinit
static struct isapnp_card_id snd_azt2320_pnpids[] __devinitdata = {
/* PRO16V */
ISAPNP_AZT2320('A','Z','T',0x1008,0x1008,0x2001),
- /* --- */
+ /* Aztech Sound Galaxy 16 */
ISAPNP_AZT2320('A','Z','T',0x2320,0x0001,0x0002),
/* Packard Bell Sound III 336 AM/SP */
ISAPNP_AZT2320('A','Z','T',0x3000,0x1003,0x2001),
diff --git a/sound/isa/cs423x/cs4231_lib.c b/sound/isa/cs423x/cs4231_lib.c
index 23236e5c1111..f3c629c124ab 100644
--- a/sound/isa/cs423x/cs4231_lib.c
+++ b/sound/isa/cs423x/cs4231_lib.c
@@ -32,6 +32,7 @@
#include <linux/pm.h>
#include <linux/init.h>
#include <linux/slab.h>
+#include <linux/ioport.h>
#include <sound/core.h>
#include <sound/cs4231.h>
diff --git a/sound/isa/es1688/es1688_lib.c b/sound/isa/es1688/es1688_lib.c
index 3102bf15d916..b9f05ba2455d 100644
--- a/sound/isa/es1688/es1688_lib.c
+++ b/sound/isa/es1688/es1688_lib.c
@@ -25,6 +25,7 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/slab.h>
+#include <linux/ioport.h>
#include <sound/core.h>
#include <sound/es1688.h>
#include <sound/initval.h>
diff --git a/sound/isa/gus/gus_main.c b/sound/isa/gus/gus_main.c
index 262f2c163946..9d3a947bf3e9 100644
--- a/sound/isa/gus/gus_main.c
+++ b/sound/isa/gus/gus_main.c
@@ -24,6 +24,7 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/slab.h>
+#include <linux/ioport.h>
#include <sound/core.h>
#include <sound/gus.h>
#include <sound/control.h>
diff --git a/sound/isa/opl3sa2.c b/sound/isa/opl3sa2.c
index a389a6548c99..1c8ca4ac6857 100644
--- a/sound/isa/opl3sa2.c
+++ b/sound/isa/opl3sa2.c
@@ -177,7 +177,7 @@ static struct isapnp_card_id snd_opl3sa2_pnpids[] __devinitdata = {
ISAPNP_OPL3SA2('Y','M','H',0x0020,0x0021),
/* Yamaha OPL3-SA3 (integrated on Intel's Pentium II AL440LX motherboard) */
ISAPNP_OPL3SA2('Y','M','H',0x0030,0x0021),
- /* ??? */
+ /* Yamaha OPL3-SA2 */
ISAPNP_OPL3SA2('Y','M','H',0x0800,0x0021),
/* NeoMagic MagicWave 3DX */
ISAPNP_OPL3SA2('N','M','X',0x2200,0x2210),
diff --git a/sound/isa/sb/Makefile b/sound/isa/sb/Makefile
index abf402366675..37b6d10fe07d 100644
--- a/sound/isa/sb/Makefile
+++ b/sound/isa/sb/Makefile
@@ -27,12 +27,12 @@ obj-$(CONFIG_SND_DT0197H) += snd-sb16-dsp.o snd-sb-common.o
obj-$(CONFIG_SND_SB8) += snd-sb8.o snd-sb8-dsp.o snd-sb-common.o
obj-$(CONFIG_SND_SB16) += snd-sb16.o snd-sb16-dsp.o snd-sb-common.o
obj-$(CONFIG_SND_SBAWE) += snd-sbawe.o snd-sb16-dsp.o snd-sb-common.o
+obj-$(CONFIG_SND_ES968) += snd-es968.o snd-sb8-dsp.o snd-sb-common.o
+obj-$(CONFIG_SND_ALS4000) += snd-sb-common.o
ifeq ($(CONFIG_SND_SB16_CSP),y)
obj-$(CONFIG_SND_SB16) += snd-sb16-csp.o
obj-$(CONFIG_SND_SBAWE) += snd-sb16-csp.o
endif
-obj-$(CONFIG_SND_ES968) += snd-es968.o snd-sb8-dsp.o snd-sb-common.o
-obj-$(CONFIG_SND_ALS4000) += snd-sb-common.o
ifeq ($(subst m,y,$(CONFIG_SND_SEQUENCER)),y)
obj-$(CONFIG_SND_SBAWE) += snd-emu8000-synth.o
endif
diff --git a/sound/isa/sb/emu8000.c b/sound/isa/sb/emu8000.c
index 61f4a0130161..01f06bf66086 100644
--- a/sound/isa/sb/emu8000.c
+++ b/sound/isa/sb/emu8000.c
@@ -25,6 +25,7 @@
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/slab.h>
+#include <linux/ioport.h>
#include <sound/core.h>
#include <sound/emu8000.h>
#include <sound/emu8000_reg.h>
diff --git a/sound/isa/sb/sb16_main.c b/sound/isa/sb/sb16_main.c
index 0d59af55cd1b..bd3ddcf38e68 100644
--- a/sound/isa/sb/sb16_main.c
+++ b/sound/isa/sb/sb16_main.c
@@ -209,11 +209,11 @@ static void snd_sb16_csp_capture_close(sb_t *chip)
#else
#define snd_sb16_csp_playback_prepare(chip, runtime) /*nop*/
#define snd_sb16_csp_capture_prepare(chip, runtime) /*nop*/
-#define snd_sb16_csp_update(chip) /*nop*/
+#define snd_sb16_csp_update(chip) /*nop*/
#define snd_sb16_csp_playback_open(chip, runtime) /*nop*/
-#define snd_sb16_csp_playback_close(chip) /*nop*/
+#define snd_sb16_csp_playback_close(chip) /*nop*/
#define snd_sb16_csp_capture_open(chip, runtime) /*nop*/
-#define snd_sb16_csp_capture_close(chip) /*nop*/
+#define snd_sb16_csp_capture_close(chip) /*nop*/
#endif
diff --git a/sound/isa/sb/sb8.c b/sound/isa/sb/sb8.c
index d668a174621a..1cbf406d389f 100644
--- a/sound/isa/sb/sb8.c
+++ b/sound/isa/sb/sb8.c
@@ -22,6 +22,7 @@
#include <sound/driver.h>
#include <linux/init.h>
#include <linux/slab.h>
+#include <linux/ioport.h>
#include <sound/core.h>
#include <sound/sb.h>
#include <sound/opl3.h>
diff --git a/sound/isa/sb/sb_common.c b/sound/isa/sb/sb_common.c
index 22da20bf6f21..3f7a796773a0 100644
--- a/sound/isa/sb/sb_common.c
+++ b/sound/isa/sb/sb_common.c
@@ -26,6 +26,7 @@
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/slab.h>
+#include <linux/ioport.h>
#include <sound/core.h>
#include <sound/sb.h>
#include <sound/initval.h>
diff --git a/sound/isa/sgalaxy.c b/sound/isa/sgalaxy.c
index 10f4fdf0edb5..869c351d9fe8 100644
--- a/sound/isa/sgalaxy.c
+++ b/sound/isa/sgalaxy.c
@@ -119,7 +119,7 @@ static int __init snd_sgalaxy_setup_wss(unsigned long port, int irq, int dma)
static int dma_bits[] = {1, 2, 0, 3};
int tmp, tmp1;
- unsigned int flags;
+ unsigned long flags;
if ((tmp = inb(port + 3)) == 0xff)
{
diff --git a/sound/isa/wavefront/wavefront_synth.c b/sound/isa/wavefront/wavefront_synth.c
index b356878ebb87..777bb390fc0d 100644
--- a/sound/isa/wavefront/wavefront_synth.c
+++ b/sound/isa/wavefront/wavefront_synth.c
@@ -111,30 +111,6 @@ MODULE_PARM_DESC(ramcheck_time, "how many seconds to wait for the RAM test");
MODULE_PARM(osrun_time,"i");
MODULE_PARM_DESC(osrun_time, "how many seconds to wait for the ICS2115 OS");
-/*
- * This sucks, hopefully it'll get standardised
- */
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,18) && LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
-#define loops_per_sec loops_per_jiffy*HZ
-#elif LINUX_VERSION_CODE == KERNEL_VERSION(2,4,0) && defined(I_DIRTY_PAGES) /* linux/fs.h */
-#define loops_per_sec loops_per_jiffy*HZ
-#elif LINUX_VERSION_CODE > KERNEL_VERSION(2,4,0)
-#define loops_per_sec loops_per_jiffy*HZ
-#endif
-
-#if defined(__alpha__) || defined(__powerpc__)
-#ifdef __SMP__
-#define LOOPS_PER_SEC (cpu_data[smp_processor_id()].loops_per_sec)
-#else
-#define LOOPS_PER_SEC (loops_per_sec)
-#endif
-#endif
-
-#if defined(__i386__)
-#define LOOPS_PER_SEC (current_cpu_data.loops_per_sec)
-#endif
-
/* if WF_DEBUG not defined, no run-time debugging messages will
be available via the debug flag setting. Given the current
beta state of the driver, this will remain set until a future
@@ -323,26 +299,16 @@ wavefront_wait (snd_wavefront_t *dev, int mask)
{
int i;
- static int short_loop_cnt = 0;
-
- /* Compute the loop count that lets us sleep for about the
- right amount of time, cache issues, bus speeds and all
- other issues being unequal but largely irrelevant.
- */
-
- if (short_loop_cnt == 0) {
- short_loop_cnt = wait_usecs *
- (LOOPS_PER_SEC / 1000000);
- }
/* Spin for a short period of time, because >99% of all
requests to the WaveFront can be serviced inline like this.
*/
- for (i = 0; i < short_loop_cnt; i++) {
+ for (i = 0; i < wait_usecs; i += 5) {
if (wavefront_status (dev) & mask) {
return 1;
}
+ udelay(5);
}
for (i = 0; i < sleep_tries; i++) {
@@ -1316,18 +1282,21 @@ wavefront_fetch_multisample (snd_wavefront_t *dev,
for (i = 0; i < num_samples; i++) {
char d[2];
+ int val;
- if ((d[0] = wavefront_read (dev)) == -1) {
+ if ((val = wavefront_read (dev)) == -1) {
snd_printk ("upload multisample failed "
"during sample loop.\n");
return -(EIO);
}
+ d[0] = val;
- if ((d[1] = wavefront_read (dev)) == -1) {
+ if ((val = wavefront_read (dev)) == -1) {
snd_printk ("upload multisample failed "
"during sample loop.\n");
return -(EIO);
}
+ d[1] = val;
header->hdr.ms.SampleNumber[i] =
demunge_int32 ((unsigned char *) d, 2);
diff --git a/sound/oss/via82cxxx_audio.c b/sound/oss/via82cxxx_audio.c
index f49f2ca18c7f..70d27cb5621b 100644
--- a/sound/oss/via82cxxx_audio.c
+++ b/sound/oss/via82cxxx_audio.c
@@ -354,8 +354,6 @@ static inline void via_card_cleanup_proc (struct via_info *card) {}
static struct pci_device_id via_pci_tbl[] __initdata = {
{ PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_5,
PCI_ANY_ID, PCI_ANY_ID, },
- { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8233_5,
- PCI_ANY_ID, PCI_ANY_ID, },
{ 0, }
};
MODULE_DEVICE_TABLE(pci,via_pci_tbl);
diff --git a/sound/pci/Config.help b/sound/pci/Config.help
new file mode 100644
index 000000000000..98a97d30de3b
--- /dev/null
+++ b/sound/pci/Config.help
@@ -0,0 +1,75 @@
+CONFIG_SND_ALI5451
+ Say 'Y' or 'M' to include support for ALI PCI Audio M5451 sound core.
+
+CONFIG_SND_CS46XX
+ Say 'Y' or 'M' to include support for Cirrus Logic CS4610 / CS4612 /
+ CS4614 / CS4615 / CS4622 / CS4624 / CS4630 / CS4280 chips.
+
+CONFIG_SND_CS46XX_ACCEPT_VALID
+ Say 'Y' to allow sample resolution for mmap() transfers.
+
+CONFIG_SND_EMU10K1
+ Say 'Y' or 'M' to include support for Sound Blaster PCI 512, Live!,
+ Audigy and E-mu APS (partially supported).
+
+CONFIG_SND_KORG1212
+ Say 'Y' or 'M' to include support for Korg 1212IO.
+
+CONFIG_SND_NM256
+ Say 'Y' or 'M' to include support for NeoMagic NM256AV/ZX chips.
+
+CONFIG_SND_RME96
+ Say 'Y' or 'M' to include support for RME Digi96, Digi96/8 and
+ Digi96/8 PRO/PAD/PST.
+
+CONFIG_SND_RME9652
+ Say 'Y' or 'M' to include support for RME Hammerfall (RME Digi9652 /
+ Digi9636) soundcards.
+
+CONFIG_SND_TRIDENT
+
+CONFIG_SND_YMFPCI
+ Say 'Y' or 'M' to include support for Yamaha PCI audio chips -
+ YMF724, YMF724F, YMF740, YMF740C, YMF744, YMF754.
+
+CONFIG_SND_ALS4000
+ Say 'Y' or 'M' to include support for Avance Logic ALS4000.
+
+CONFIG_SND_CMIPCI
+ Say 'Y' or 'M' to include support for C-Media CMI8338 and 8738 PCI
+ soundcards.
+
+CONFIG_SND_ENS1370
+ Say 'Y' or 'M' to include support for Ensoniq AudioPCI ES1370.
+
+CONFIG_SND_ENS1371
+ Say 'Y' or 'M' to include support for Ensoniq AudioPCI ES1371 and
+ Sound Blaster PCI 64 or 128 soundcards.
+
+CONFIG_SND_ES1938
+ Say 'Y' or 'M' to include support for ESS Solo-1 (ES1938, ES1946)
+ soundcard.
+
+CONFIG_SND_ES1968
+ Say 'Y' or 'M' to include support for ESS Maestro 1/2/2E.
+
+CONFIG_SND_MAESTRO3
+ Say 'Y' or 'M' to include support for ESS Maestro 3 (Allegro) soundcard.
+
+CONFIG_SND_FM801
+ Say 'Y' or 'M' to include support for ForteMedia FM801 based soundcards.
+
+CONFIG_SND_ICE1712
+ Say 'Y' or 'M' to include support for ICE1712 (Envy24) based soundcards.
+
+CONFIG_SND_INTEL8X0
+ Say 'Y' or 'M' to include support for Intel8x0 based soundcards.
+
+CONFIG_SND_SONICVIBES
+ Say 'Y' or 'M' to include support for S3 SonicVibes based soundcards.
+
+CONFIG_SND_VIA686
+ Say 'Y' or 'M' to include support for VIA VT82C686A/B South Bridge.
+
+CONFIG_SND_VIA8233
+ Say 'Y' or 'M' to include support for VIA VT8233 South Bridge.
diff --git a/sound/pci/ymfpci/ymfpci.c b/sound/pci/ymfpci/ymfpci.c
index 1bfa2b6e4a65..9d9df8f76c5a 100644
--- a/sound/pci/ymfpci/ymfpci.c
+++ b/sound/pci/ymfpci/ymfpci.c
@@ -109,7 +109,7 @@ static int __devinit snd_card_ymfpci_probe(struct pci_dev *pci,
}
legacy_ctrl = 0;
- legacy_ctrl2 = 0;
+ legacy_ctrl2 = 0x0800; /* SMOD = 01 */
if (id->device >= 0x0010) { /* YMF 744/754 */
if (snd_fm_port[dev] < 0)
diff --git a/sound/synth/Makefile b/sound/synth/Makefile
index 6fc37031ca26..7bcf311f089d 100644
--- a/sound/synth/Makefile
+++ b/sound/synth/Makefile
@@ -15,8 +15,8 @@ export-objs := util_mem.o
snd-util-mem-objs := util_mem.o
# Toplevel Module Dependency
-obj-$(CONFIG_SND_TRIDENT) += snd-util-mem.o
obj-$(CONFIG_SND_EMU10K1) += snd-util-mem.o
+obj-$(CONFIG_SND_TRIDENT) += snd-util-mem.o
ifeq ($(subst m,y,$(CONFIG_SND_SEQUENCER)),y)
obj-$(CONFIG_SND_SBAWE) += snd-util-mem.o
endif