Compare commits

...

337 Commits

Author SHA1 Message Date
Daniel Potts cecb784778 Added GPLv2 clause 2007-05-31 03:23:23 +00:00
Andreas Eversberg 19890b650c Fixed some feature retieval stuff. Now it work!!
Modified Files:
	mISDN/drivers/isdn/hardware/mISDN/dsp_cmx.c
 	mISDN/drivers/isdn/hardware/mISDN/dsp_core.c
2007-04-03 19:42:45 +00:00
Andreas Eversberg f4a3d41cc4 fixed minor bug in dsp: if hardware features are disabled, we also must set feature flag to "received", else we wait until infinity for features
Modified Files:
 	mISDN/drivers/isdn/hardware/mISDN/dsp_core.c
2007-04-03 18:34:38 +00:00
Andreas Eversberg c4dd8765b4 improved memdebug
Modified Files:
 	mISDN/CHANGES mISDN/drivers/isdn/hardware/mISDN/memdbg.c
 	mISDN/drivers/isdn/hardware/mISDN/memdbg.h
2007-04-03 17:56:52 +00:00
Andreas Eversberg 34458d894d changed CMX processing to older version process.
note: recevie data to CMX is always required, even on hardware bridging
also it is required even if no conference or bridge is formed.
CMX process reclocks receive data and also processes echo, even with no bridge
or conference.

the queue_conf_id is left as is, additionally i added queue_dtmf flag to enable hardware or software dtmf as the features arrive.

what we can do later: hfcmulti can reply the feature message and bring features
by data body and not by writing to a pointer.

Modified Files:
 	mISDN/CHANGES mISDN/drivers/isdn/hardware/mISDN/dsp.h
 	mISDN/drivers/isdn/hardware/mISDN/dsp_cmx.c
 	mISDN/drivers/isdn/hardware/mISDN/dsp_core.c
2007-04-03 17:47:26 +00:00
Andreas Eversberg c24e757ff4 Enabling TX data during bridge. Read note in dsp_cmx.c (search for "#if 1")
Modified Files:
 	mISDN/CHANGES mISDN/drivers/isdn/hardware/mISDN/dsp_cmx.c
2007-04-03 16:15:17 +00:00
Nadi Sarrar 4a64d3fbc2 allow config lines like nt_ptp=1-7,9,10 in misdn-init.conf 2007-04-03 08:31:04 +00:00
Chrisian Richter fc245dc655 preparing for 1.1.2 2007-04-02 07:01:14 +00:00
Chrisian Richter 81e9a9193e added CHANGES file to reflect the modifications 2007-04-02 07:00:48 +00:00
Nadi Sarrar 9d76bbabf0 don't load hfcmulti if no hfcmulti cards configured 2007-03-28 11:04:33 +00:00
Andreas Eversberg b70f8ddd1c Changed my email address to jolly@eversberg.eu
Modified Files:
	mISDN/drivers/isdn/hardware/mISDN/Kconfig.v2.6
	mISDN/drivers/isdn/hardware/mISDN/dsp.h
	mISDN/drivers/isdn/hardware/mISDN/dsp_audio.c
	mISDN/drivers/isdn/hardware/mISDN/dsp_blowfish.c
	mISDN/drivers/isdn/hardware/mISDN/dsp_cmx.c
	mISDN/drivers/isdn/hardware/mISDN/dsp_core.c
	mISDN/drivers/isdn/hardware/mISDN/dsp_dtmf.c
	mISDN/drivers/isdn/hardware/mISDN/dsp_tones.c
	mISDN/drivers/isdn/hardware/mISDN/hfc_multi.c
	mISDN/drivers/isdn/hardware/mISDN/l1oip.c
	mISDN/drivers/isdn/hardware/mISDN/loop.c
	mISDN/drivers/isdn/hardware/mISDN/socket.c
	mISDN/drivers/isdn/hardware/mISDN/socket.h
2007-03-27 15:06:29 +00:00
Chrisian Richter c34e06a2dd workaround for Kernel Oops.. fixing real root soon :) 2007-03-23 17:23:03 +00:00
Chrisian Richter 8afd39d035 print fsmTimer debug only when debugflag set 2007-03-21 13:26:56 +00:00
Chrisian Richter 4b08981a7e added installing of mISDNif.h in the /usr/include/linux/ directory to allow userspace apps to compile for mISDN. can be specified by the -p parameter (inspired by jolly) 2007-03-06 20:51:51 +00:00
Chrisian Richter 0981be2474 added KVERS variable to make it possible to compile against a different than the just running kernel (thx. Igor Neves) 2007-03-05 23:22:01 +00:00
Chrisian Richter cfcd035054 fixed typo + added new subminor, preparation for new release.. 2007-03-02 18:14:19 +00:00
Chrisian Richter 1fa5c5942f * fixed support of new BN8S0 leds work now correct again
* fixed support of the B410P, which wasn't recognized correctly
* added an "opticalsupport" field to the PCI_ENTRY struct. Most e1 boards
  have no optical interface, so they should never be initialized with one
2007-03-02 14:00:38 +00:00
Chrisian Richter b87a76c616 added junghanns pci id (quadbri 2.0 board) 2007-02-27 21:16:08 +00:00
Chrisian Richter 04c6a25a2c adjusted Major/Minor in Makefile 2007-02-13 11:59:50 +00:00
Chrisian Richter dcc1f604e9 added README.mISDN which explains a bit the new xmls style config 2007-02-13 11:50:39 +00:00
Chrisian Richter b237b99a3e made the VERSION file .PHONY 2007-02-13 10:46:35 +00:00
Chrisian Richter 140f0044d0 added the config.h fix for kernels>=2.6.19 2007-02-13 10:43:46 +00:00
Chrisian Richter 1f4daf4e55 VERSION file needs to be generated for compiling 2007-02-13 10:28:53 +00:00
Chrisian Richter 26104aec84 added new BN8S+ which has 8 LEDS for each ISDN Port, also added VERSION printing to mISDN_core 2007-02-13 10:27:01 +00:00
Nadi Sarrar 2083ca73f1 new timer=(yes|no) parameter for hfcmulti 2007-01-25 13:58:27 +00:00
Chrisian Richter 84116778c7 added timer mechanism to misdn-init file 2007-01-24 16:45:12 +00:00
Chrisian Richter 6e6702b4df added 125us irq to clock ztdummy from zaptel, so they can be synchronized from our hfc chip and finally from the ISDN line. to enable this you need to add timer=1 as modparm to hfcmulti 2007-01-23 15:01:40 +00:00
Chrisian Richter b6351ddb11 added Michaels patch which improves the echocancel performance, thanks a lot 2007-01-22 14:54:04 +00:00
Chrisian Richter 7b172e73f0 a few more additions for the RESTART Message 2007-01-10 12:56:45 +00:00
Chrisian Richter 618cd071d2 added possibility to restart channels. works like broadcast facilities without a real process, the user just needs to use the MISDN_ID_DUMMY as l3id (dinfo). This is especially useful if the user Application thinks that there are free channels when the switch from the telco provider thinks there are busy channels, with this restart mechanism they can synchronize, restart_ack will be added when we can test that. 2007-01-09 16:51:47 +00:00
Chrisian Richter d45c93792d removed newline from l3_debug message which is unnecessary. we only print the RELEASE_COMPLETE without proc message on debug 2007-01-02 13:38:20 +00:00
Chrisian Richter 3f81fb08cb the mISDN_dsp parameter dtmftreshold is now correctly named dtmfthreshold 2007-01-02 10:11:18 +00:00
Andreas Eversberg 19a3869229 Added redirecting number.
NOTE:  mISDNuser  and all applications must be recompiled!!!

Modified Files:
	mISDN/drivers/isdn/hardware/mISDN/dss1.h
	mISDN/drivers/isdn/hardware/mISDN/l3_udss1.c
	mISDN/drivers/isdn/hardware/mISDN/l3helper.c
	mISDN/include/linux/mISDNif.h
2006-12-27 18:50:50 +00:00
Nadi Sarrar d300bb238d adding comments in autogenerated mISDN.conf 2006-12-21 16:46:47 +00:00
Nadi Sarrar d1e673c815 mark mISDN modules as used (don't allow to remove them), if userspace software opens /dev/mISDN. 2006-12-21 15:25:06 +00:00
Chrisian Richter 1c919ae75b added installation of new xml style configuration 2006-12-21 09:21:05 +00:00
Nadi Sarrar 440aacfdf4 user,group,mode of /dev/mISDN can now be configured in /etc/mISDN.conf 2006-12-15 10:42:49 +00:00
Nadi Sarrar 6120cb8cc5 create mISDN device node if not present 2006-12-15 10:15:31 +00:00
Nadi Sarrar 7fd00bc1bb combined singleport pci cards into one xsl stylesheet 2006-12-14 15:10:59 +00:00
Nadi Sarrar 183941be8c adding hfcpci and avmfritz support 2006-12-14 14:49:03 +00:00
Nadi Sarrar cacd47333c initial commit of the new xml way for card configuration and module loading.
caution: does not support everything misdn-init does, yet.
2006-12-14 12:51:41 +00:00
Günther Kelleter a48dd57635 Add missing ! to make AppPlciClearOtherApps() actually do something 2006-12-06 15:18:07 +00:00
Martin Bachem c54ddc246d command L1_ACTIVATE_NT replies with (PH_ACTIVATE | INDICATION) when already G3 2006-12-06 08:00:17 +00:00
Chrisian Richter 106461e7d2 dsp_poll option defaults now to 128 as well 2006-12-05 16:39:23 +00:00
Martin Bachem 4c96e1925c crab debug 2006-11-30 16:27:00 +00:00
Martin Bachem 2384b39092 reset frame_complete flag during packetizing ISO-URB sub packets 2006-11-30 16:25:34 +00:00
Martin Bachem b1bec05514 use SCTR_E to set D_U enable when NT mode 2006-11-30 15:40:14 +00:00
Martin Bachem 001d02742d do not use Interframe-Fill in DChannel TX when NT mode 2006-11-30 14:32:53 +00:00
Martin Bachem 2a1c2e8207 the return of the spinlock
(usb urb callbacks in interrupt context, so hfcsusb_l2l1 gets interrupted without locks)
2006-11-30 13:53:34 +00:00
Martin Bachem 926fa87208 NT mode:
- return (PH_ACTIVATE | INDICATION) after PH_ACTIVATE_REQUEST when in G3
  - send (PH_ACTIVATE | CONFIRM) when activation done
2006-11-28 16:58:42 +00:00
Chrisian Richter 17e4ca93cd fixed a little bug introduced by nadi in the misdn-init script :-) 2006-11-23 17:15:46 +00:00
Nadi Sarrar c6e604b80f adding support for dual E1 card 2006-11-23 16:41:22 +00:00
Chrisian Richter 88a4a4ec2a print this logs only when debug is on 2006-11-22 12:18:00 +00:00
Chrisian Richter 4254384a53 added swyx PCI ID for the 4S board. bug #75 2006-11-17 15:06:50 +00:00
Chrisian Richter 7dfe7cf810 some comments on master_clock option added 2006-11-17 09:06:46 +00:00
Chrisian Richter 25aebcc9b4 modified the misdn-init script so that it works with existing config files, it knows now about cards with fewer ports. also simplified some sed logic by using cut 2006-11-16 13:13:08 +00:00
Chrisian Richter f4e18a559d removed a printk 2006-11-14 15:20:05 +00:00
Chrisian Richter 6e66a0fb06 removed find_type_entry. we can use 2 static variables instead, these keep also track of cards with fewer ports than originally designed 2006-11-14 14:55:41 +00:00
Chrisian Richter 8d515d2fdf hfcmulti distinguishes now between types and ports. There are now only 3 different types: e1, 4S0 and 8S0, because there are only these 3 chips. But in fact cards which have fewer ports are now supported through the ports variable in the pci_id struct. Also modified the misdn-init script to handle that, and added a mini PCI HFC card with 1 Port 2006-11-14 12:17:02 +00:00
Martin Bachem 51ecee1ea0 still changes in debug modes 2006-11-13 16:45:41 +00:00
Martin Bachem a824a65c98 trace channel data to syslog 2006-11-13 16:27:19 +00:00
Chrisian Richter ae7ba0a377 preparing first release 1_0_4 2006-11-13 14:55:43 +00:00
Chrisian Richter a340296f95 added makefile targets for very basic release management, based on cvs tags 2006-11-13 14:53:48 +00:00
Chrisian Richter 1b39ae1623 removed some useless logs 2006-11-02 09:40:53 +00:00
srichter b2f839bd51 Applied patch from David Woodhouse:
- fix old mistake breaking HFC-PCI on bigendian (blame Simon)
 - get rid of config.h. Breaks builds against old kernels, so minor regression
2006-10-20 14:10:25 +00:00
Chrisian Richter 7baab3c770 added dsp_poll option to handle different dsp_polls from hfc polls, they might be multiples of 80 if the Timersetting is set 100Hz in the Kernel, default is none the dsp will autosense what is necessary 2006-10-20 12:51:56 +00:00
Chrisian Richter 53e5e1d7c7 added notfatal option for misdn-init, in case lsusb is not installed, we still go on. 2006-10-16 11:40:20 +00:00
Chrisian Richter 1ed9289f48 Modified change from gkelleter a bit. If you change things in the TE State machine, check the whole code! Disconnects might also be sent out in other States like outgoing Setup.. i've did your change only in state 7 == In Setup + Out Alerting, please check if that works for you. 2006-10-16 07:43:57 +00:00
Chrisian Richter 60be2d76f8 removed a lot of verbosity. Better commented the pcm_slave and ignore_pcm_frameclock options 2006-10-09 12:51:33 +00:00
Daniel Potts 36ade5e5f5 James Harper identified that locks were being taken twice along the same code path, causing a hang (on SMP). These have been removed. 2006-10-02 12:51:33 +00:00
Chrisian Richter 7de26421e1 we work now with 32bit access on the fifos. Also for the b410P we don't adjust the txgain anymore since -4 is quite too much 2006-09-27 08:28:50 +00:00
Günther Kelleter fca2dd211f kernels < 2.6.9 don't implement kcalloc 2006-09-15 08:38:20 +00:00
Günther Kelleter 643710ddbf endian fixes for BIGENDIAN systems. capi_profile and messages have to be little endian by definition 2006-09-14 15:51:46 +00:00
Günther Kelleter 2b7e0b8e84 in l3dss1_disconnect() the cause value was not taken from the DISCONNECT message, when it supplies one. Therefore an incoming DISCONNECT after incoming SETUP and outgoing ALERTING was not answered with RELEASE, since the cause was not evaluated properly. State 12 was entered instead of state 19 2006-09-14 15:47:22 +00:00
Günther Kelleter e42aada6cf set message type to MT_RELEASE_COMPLETE in message for CC_RELEASE_COMPLETE_REQ. MT_DISCONNECT was sent instead of MT_RELEASE_COMPLETE as required 2006-09-14 15:43:09 +00:00
Günther Kelleter d87bf83950 fix potential skb overflow when user-user-info is sent in an ALERTING message 2006-09-14 15:41:05 +00:00
Günther Kelleter f85a2af479 make compilable on non-i386 architectures 2006-09-14 15:39:52 +00:00
Günther Kelleter 0f20f5bdc6 fix debug output 2006-09-14 15:36:47 +00:00
Günther Kelleter 15f0d65a7f fix typo in hex constant 2006-09-14 15:34:12 +00:00
Günther Kelleter 70914a8e6f make kzalloc macro for kernels < 2.6.14 clear allocated memory 2006-09-14 15:30:42 +00:00
Chrisian Richter 216a4b1edd litle fix to make the leds work when the watchdog is enabled 2006-09-13 15:53:01 +00:00
Chrisian Richter 5787705119 added a 2 clocking options for the hfc e1 chips 2006-09-13 14:01:04 +00:00
Martin Bachem 89626fbade configure end of pulse control for ST mode (TE & NT) 2006-09-11 11:44:02 +00:00
Chrisian Richter a9c1ddd31c added some minipci hfcmulti based cards 2006-09-08 10:39:54 +00:00
Chrisian Richter 5d275ef7d7 don't print the NEXT_SKB EXISTS error.. for testing 2006-09-07 13:02:34 +00:00
Chrisian Richter 8ab0c38df3 added the new B410P HFC-4S based card. This card has Echocancelation in hardware. Modified mISDN_dsp to check for hw_echocan facilities. added possibility to control the gain from lower layers. Thanks to Matthew Fredrickson for most of the patches. 2006-09-06 17:24:22 +00:00
Nadi Sarrar 18df072e60 fixed typo 2006-08-25 11:50:41 +00:00
Martin Bachem c9d11dda5f rx skb mem range check 2006-08-15 09:38:07 +00:00
Chrisian Richter 01e13c7883 kzalloc is very new, only since 2.6.14 2006-08-10 15:00:03 +00:00
Karsten Keil 3606a753cd fix protocol parameter handling (bug 0000067) 2006-08-07 23:35:59 +00:00
Daniel Potts 7fa0d32c3e Pointer next_skb test fix.
Take lock on initialization in an attempt to fix SMP race.
2006-08-07 11:53:02 +00:00
Karsten Keil b2629bc4b7 fix for overflow in copy_pid 2006-08-04 17:08:31 +00:00
Karsten Keil 71aa0d3dc1 some addons from root@netsentry.superset.co.za
1)added a new card to hfc_multi seems to be junghans ...
2)added hotplug support for hfcsusb by exporting it to the modules list to
be picked up by hotplug works realy nicely
3)dont compile in devfs bits for new kernel (2.6.18 does not have any devfs)
2006-08-01 11:25:10 +00:00
Chrisian Richter cb7fbf931b added new Subdevice ID for new 2E1 beroNet card with watchdog for relais for the tranparent switched mode. 2006-07-31 12:55:31 +00:00
Chrisian Richter 9d468d79be moved misdn-init from /etc/init.d to /usr/sbin, added checks for bc / modprobe / ... in misdn-init 2006-07-28 12:12:55 +00:00
Chrisian Richter 6fa421dc88 T310 can be between 30-120 seconds. we use 120 seconds now. 2006-07-20 08:14:18 +00:00
Chrisian Richter a217cc8071 reworked the echocancel_chunk function, it works now exactly as under zaptel and cancels the echo much better now. 2006-07-18 14:44:51 +00:00
Chrisian Richter 7c9d3427c2 removed unused variable 2006-07-14 15:53:53 +00:00
Chrisian Richter 50bfd90684 readded the class_create_file stuff, that didn't harm anything but created compiler warnings 2006-07-14 15:48:17 +00:00
Chrisian Richter ab4597fde4 splitted the release_port function in a release_port and release_ports_hw functions, the ports_hw function disables all the hw related stuff and the release_port function removes lists and deregisters channels and stuff like that. Both functions are now only called in the unload module routine. On higher Kernelversions the release_port function is not called because it creates kernel oopses. ifdefed some sysfs_create_files. 2006-07-14 15:30:22 +00:00
Chrisian Richter 1c93a4f475 for kernels >2.6.10 we need to release the port in the RELEASE message, this is not everytime true, but it doesn't harm anything to do it.. only the leaving mSDNstackd processes. This really needs rework 2006-07-13 09:11:32 +00:00
Chrisian Richter fed7fcf52d remove printks 2006-07-13 07:22:27 +00:00
Chrisian Richter 86beb33815 default threshold of 100 is more accurate, also we unload the card modules after we've unloaded the layers 2006-07-12 15:57:24 +00:00
Chrisian Richter 25f37a1d92 made the dtmftreshold value changeable by modul parameter. This might help reducing wrong identified dtmftones. 2006-07-04 13:38:45 +00:00
Chrisian Richter 4d82d4de70 added the instance id for the l2mgr Log, so we can distinguish the Port which might be faulty 2006-07-03 12:44:37 +00:00
Chrisian Richter f15296da42 added poll option for the hfcsusb driver, also we pass the poll option for this driver and for the dsp modul now from the misdn-init script. This fixes the no-sound issue with the hfcsub cards. Many Thanks for James Harper who gave us this patch. In the future we might add some sort of autoconfiguration of the packetsizes. 2006-07-03 11:48:02 +00:00
Chrisian Richter 3ead35f330 we can have much more the 4ports in the hfcmulti 2006-07-03 10:04:04 +00:00
Karsten Keil 5036dcc9bc fix debug declaration 2006-06-29 10:40:23 +00:00
Karsten Keil 63a0047915 add some compatibility stuff 2006-06-29 09:11:29 +00:00
Karsten Keil 06b2b6d540 cleanup compatibility stuff 2006-06-29 09:11:08 +00:00
Karsten Keil 5d3fa852e7 fix warning about MODULE_PARM_T 2006-06-29 08:52:39 +00:00
Daniel Potts 5e56ba89ae add revision string to NETJet verbose 2006-06-29 01:50:07 +00:00
Daniel Potts 419a1afba1 NETJet config option 2006-06-29 01:49:17 +00:00
Karsten Keil 98c9e63081 some compatibility code for kernel version < 2.6.8 2006-06-28 18:03:53 +00:00
Daniel Potts e862e5aac1 Added driver for Traverse Tech. NETJet card 2006-06-28 14:06:03 +00:00
Karsten Keil 07a8ef6ac4 fix a double free/access after free problem.
Thanks to James Harper <james.harper@bendigoit.com.au> for tracking down.
2006-06-27 13:24:07 +00:00
Chrisian Richter c2def45158 for now we release only all the ports when the module is unloaded. It doesn't make really a lot of sense to release single ports on the hfcmulti cards. The better way would be to relase the ports from the queue instead. But the queue knows only about single stacks .. I propose to add a MODULE_REGISTER and MODULE_RELEASE to the mqueue, this one cleans up all the necessary stuff and we only send a MODULE_RELEASE from within the module_unload function. For now this fix should work in most cases. 2006-06-27 09:55:17 +00:00
Chrisian Richter b5f2e62aa8 we should also generate tones when we have no conference 2006-06-26 17:25:14 +00:00
Chrisian Richter a7034bc3fc when we do not ever want a CMX, we do not need the jitterbufferring, since the userspace handles this. So we check now if we really have a conf_id, else we just transceive the buffers, with the addition of gainctrl dtmf detection and echocancellation (this removes a lot of NEXT_FRAME exists) 2006-06-21 13:25:46 +00:00
Chrisian Richter 90439f3b95 added support for distros where bc is not in the default path 2006-06-20 07:42:54 +00:00
Chrisian Richter 2a7a305767 fixed the leds for the BN2S cards 2006-06-19 07:45:53 +00:00
Chrisian Richter ba1f784186 added a define for aggressive echo suppresssion 2006-06-09 08:41:26 +00:00
Chrisian Richter ba46ac67a7 readded CONFIG_MISDN_DSP 2006-06-01 16:38:25 +00:00
Chrisian Richter 958a2e6ae1 * added winsize 7 for E1
* added real_bc to the l3 process for correct CC_RESTART handling in E1
* reworked the MT_RESTART_ACKNOWLEDGE to support EXTCID
* Major of mISDNif.h is now 4 (comprehension req)
* Makefile checks now for the Major of mISDNif.h to report backwards
  incompatibility

WE ARE NOW FULLY L2/L3 COMPLIANT FOR S2M AND S0 !!!
2006-06-01 11:02:10 +00:00
Chrisian Richter 74399516a9 made l3_udss1.c compile without the fill1 element again 2006-05-31 02:25:52 +00:00
Chrisian Richter cf9dc7a520 added check for interface change of mISDNif.h 2006-05-31 02:18:55 +00:00
Karsten Keil 6a0e5e53be realign L3 struct on 32 bit bounds 2006-05-30 14:35:25 +00:00
Chrisian Richter df8ef49812 added mISDNif.h to make it compile again 2006-05-30 09:37:16 +00:00
Chrisian Richter 6f9233157a fixed some ETSI violations regarding L2 and L3. We now are fully L2 and L3 compliant (with chan_misdn-0.3.1-rc8) 2006-05-29 16:46:10 +00:00
Chrisian Richter 8e7b38b15f added Hanlding of MDL_ERROR|REQ from tei manager to pass L2 test for TE PTMP and PTPls 2006-05-29 09:25:36 +00:00
Chrisian Richter 318b7a7912 not sending something to the card when we're sure that we're bridged in hardware. This fixes a Kernel Oops which occurs together with the profiling option in the kernel somehow. 2006-05-28 14:13:52 +00:00
Chrisian Richter fabc822d5f #ifdefed the sysfs_create_* and sysfs_remove_* functions, we might add a CONFIG_MISDN_SYSFS to reenable it. 2006-05-23 12:06:48 +00:00
Chrisian Richter 08f6fd24ca added a litle queue for conference ids in the dsp. It creates the conference when the hardware is ready for sure.. before it was more luck if we had a hardware or software conference. Also added modules.d support for gentoo 2006-05-23 08:10:59 +00:00
Chrisian Richter 37c4b05c1c #if should better be #ifdef to avoid warning when not defined 2006-05-18 13:35:46 +00:00
Chrisian Richter 83db9f7a92 removed all sysfs_remove_* functions, since they still oops on different machines.. the class_unregister seems to remove the sysfs entries anyway 2006-05-18 13:33:28 +00:00
Chrisian Richter 37527f5a1e we detect the cards now in the order like we find it in the pci space, thats what hfcmulti also does, so we have less confusion about order with multiple different cards 2006-05-16 13:02:05 +00:00
Chrisian Richter 2b91aa829c fixed 4S find bug for more then 1 card 2006-05-14 15:20:13 +00:00
Chrisian Richter dd8d5c47c1 fixed depmod problem 2006-05-12 13:35:28 +00:00
Chrisian Richter f9a1f8a7c3 added a few debug options to the core to screen the sysfs related debug prints 2006-05-12 13:27:23 +00:00
Chrisian Richter 17c5b66c32 removed some useless #warnings to beautify compiling :), also removed the davor,danach fields since they where not used 2006-05-12 09:08:07 +00:00
Chrisian Richter bcf464c910 fixed some litle issues with the modprobe.d stuff. Also we're automatically creating the configuration now if it's not there and if we're called from the hotplug stuff 2006-05-09 07:11:37 +00:00
Chrisian Richter 0e9fc6c22e removed some unused variables and my bogus checkin from avm_fritz.c 2006-05-08 15:59:39 +00:00
Chrisian Richter 150992561e added a /etc/modprobe.d/mISDN file which uses the /etc/init.d/misdn-init script to load the mISDN modules. This makes it easier to load mISDN in hotplug based distros, which nearly all of them are now 2006-05-08 15:43:57 +00:00
Chrisian Richter 169c4dbded the depmod -a commit doesn't work proper.. 2006-05-08 11:11:07 +00:00
Chrisian Richter 82696e78fa depmod should be depmod -a 2006-05-05 15:02:13 +00:00
Martin Bachem a32900b2b3 channel.h calls misdn_log_frame, but data is piped to syslog... still have kernel crashes with netdev.c:misdn_chan_frame_xmit 2006-05-05 10:04:52 +00:00
Martin Bachem 14774a420f same same 2006-05-05 08:22:11 +00:00
Martin Bachem 7b48be70e0 stack ids 0x100,0x200 ... will create mISDN00,mISDN01 etc. devices 2006-05-05 08:19:49 +00:00
Chrisian Richter 4e29b84aae CONFIG_MISDN_NETDEV shouldn't even be n .. 2006-05-04 17:42:09 +00:00
Martin Bachem f95a570dbd useless printk 2006-05-04 17:31:44 +00:00
Martin Bachem aba7cf20e8 bugfix: list_add; sprintf still needs review! 2006-05-04 16:56:56 +00:00
Martin Bachem eda5eb22d6 netdev disabled by default ;) 2006-05-04 16:07:20 +00:00
Chrisian Richter 78503c4a80 make it possible to enable netdev by setting the config variable in the main Makefile 2006-05-04 15:36:26 +00:00
Chrisian Richter 46c23e5ddc netdev_main.h doesn't exist anymore 2006-05-04 15:15:54 +00:00
Chrisian Richter 790b0fb2e8 need the lapd_addr struct for the netdev stuff 2006-05-04 14:40:07 +00:00
Chrisian Richter c684d5e96d added GPIO Check for the NT/TE Jumper settings for the 4S based cards. If the protocol Configuration does not match the Jumper Settings we print out a warning now. Thanks to Martin Bachen who submitted this patch. 2006-05-04 14:03:03 +00:00
Chrisian Richter 534a86348f added Linux Netdevice support to enable L1 hdlc frame debugging with ethereal, that's just a first shot and doesn't work proper yet. It needs to be compiled in with CONFIG_MISDN_NETDEV. also modified the misdn-init script to makes it possible to only load a specific driver (for better hotplug support) 2006-05-04 13:42:44 +00:00
Martin Bachem fafb8122bb loading module capi 2006-05-04 08:14:08 +00:00
Chrisian Richter 88b1be3d4c make it possible to install mISDN as non root via INSTALL_PREFIX 2006-04-30 17:49:34 +00:00
Martin Bachem b972326e3d check for lsusb 2006-04-30 09:58:53 +00:00
Martin Bachem adb6cc7a2b 'scan' will find HFC-S USB adapters via lsusb 2006-04-30 09:08:07 +00:00
Chrisian Richter 00a3255aa0 when ignoring the missing pcm frame clock we ignore in the init phase missing irqs as well 2006-04-26 16:50:22 +00:00
Chrisian Richter aa72af8460 added chkconfig support for redhat 2006-04-25 09:35:49 +00:00
Chrisian Richter 99fa436487 added dual port E1 card from beronet 2006-04-21 09:53:55 +00:00
Martin Bachem 92e4c668ac missing linebreak at printk 2006-04-16 11:52:38 +00:00
Martin Bachem 755034c737 HFC-S USB L1 module is named 'hfcsusb' 2006-04-12 10:49:51 +00:00
Martin Bachem 4e0f56832c describe test loops enables by module param 2006-04-12 10:37:28 +00:00
Chrisian Richter 8e7e9cdf23 sysfs_remove_group does create a NULL Pointer reference since kernel 2.6.16 from inside of the class_unreg_device callbacks .. this works around it 2006-04-11 16:04:58 +00:00
Chrisian Richter 28beb2274c completed the module_param patch, now we compile on kernel <2.6.10 again 2006-04-11 13:13:30 +00:00
Chrisian Richter 076a14607e -1 is not valid for the pcm parameter 2006-04-11 10:16:27 +00:00
Karsten Keil d5189f2f1e Handle USR cards properly 2006-04-09 14:18:28 +00:00
Chrisian Richter 9a3adc568d workaround to fix unload Kernel Oops, it doesn't free the hc list so there will be some mem in use, but the kernel will not crash anymore which is far more important then this very small mem leak 2006-04-07 08:55:07 +00:00
Chrisian Richter 851bbdceec added BN2S card with 4S Chip :). Also fixed that the correct Subvendor IDs and Subdevice IDs are used and displayed, if some cards don't work mail me: cr@beronet.com. Advanced the misdn-init script to support the new 2S Card 2006-04-05 14:42:23 +00:00
Martin Bachem 7cac3cdb06 minor fixes, dos2unix lbreaks 2006-03-30 07:52:12 +00:00
Martin Bachem ad79ac6564 same same 2006-03-29 17:27:52 +00:00
Martin Bachem 46d8409e91 fixed bug: using same loop counter twice in internal loop 2006-03-29 17:24:12 +00:00
Karsten Keil d2bd2a6133 did remove the wrong file :-( 2006-03-23 13:52:18 +00:00
Karsten Keil d6dd9d2951 not needed 2006-03-23 13:16:58 +00:00
Karsten Keil ae3886bda9 mISDN_ctrl is already defined in mISDNif.h no need for ctrl.h (Yes EXPORT_SYMBOL was missing) 2006-03-23 13:11:43 +00:00
Chrisian Richter 6c0f392d36 added ctrl.h for central managing the global mISDN_ctrl function 2006-03-23 12:31:17 +00:00
Karsten Keil 84beff43b5 make central control a global function 2006-03-23 10:05:16 +00:00
Karsten Keil bec283bb85 fix typo 2006-03-22 23:29:59 +00:00
Karsten Keil 273ea59911 replace old MODULE_PARM stuff with module_param (Thanks to Stefan Schweizer) 2006-03-22 18:33:04 +00:00
Karsten Keil 3b80b6e75c fix packed attribute warnings (Thanks to Stefan Schweizer) 2006-03-22 18:28:34 +00:00
Martin Bachem 104996ce94 .owner obsolete in kernel 2.6.16 2006-03-20 14:01:49 +00:00
Martin Bachem 6baa0d7b32 stop abusing dchannel pointer when line interface is meant 2006-03-17 07:43:41 +00:00
Chrisian Richter cd6e0aca4a made it possible to change the user/group settings of /dev/mISDN if it didn't exist before 2006-03-16 10:12:00 +00:00
Martin Bachem 7375a33587 protect queueing ctrl urbs with spinlocks 2006-03-14 11:11:29 +00:00
Chrisian Richter 67b9799208 corrected bits for the hfcmulti config, we can now really bridge in HW 2006-03-10 09:48:42 +00:00
Chrisian Richter b7ce29e545 added hack, which frees the irq of the whole card, even if only 1 port is released, this fixes the bad bad rmmod hfcmulti oops, still there are the sysfs related oopses, which at least do not actually freeze the machine. with this patch the module unloads correctly 2006-03-09 16:28:59 +00:00
Martin Bachem ce4dbd587e - using excact chip name for syslog messages:
XHFC-4SU_PI0_0_0_D means this is an XHFC-4SU at processor interface 0,
    chip no 0, line interface 0, D Channel
2006-03-08 14:07:14 +00:00
Chrisian Richter 885ab66510 changed GFP_KERNEL to GFP_ATOMIC for kmalloc to avoid sleep in a irq-lock (echo cancellor init code) 2006-03-08 12:06:10 +00:00
Chrisian Richter 445c147d01 default value of pcm should be -1 for sofware bridging 2006-03-08 10:23:06 +00:00
Chrisian Richter 6a9d2d4907 added support for the a1 card from avm 2006-03-07 21:01:27 +00:00
Martin Bachem ebe6c8274c - allocating required kernel mem depending on autodected XHFC derivate 2006-03-07 13:28:28 +00:00
Martin Bachem 2a8655f939 - supporting multiple XHFC controllers at one PCI2PI pci bridge 2006-03-06 16:20:33 +00:00
Karsten Keil b267c6033f - move branch mqueue to HEAD 2006-03-06 12:58:31 +00:00
Karsten Keil 56f18961c0 - make mqueue branch HEAD 2006-03-06 12:52:08 +00:00
Karsten Keil 44cf601712 PCI_DEVICE_ID_SITECOM_DC105 ---> PCI_DEVICE_ID_SITECOM_DC105V2 2005-11-19 14:01:41 +00:00
Martin Bachem 229883dd7d - fixed unterminated device list 2005-11-15 10:10:34 +00:00
Karsten Keil 726e2a033e pci_find_subsys do not longer exist 2005-10-26 19:35:09 +00:00
Karsten Keil 0d1253ce86 do not save flags in a register value 2005-10-26 14:13:19 +00:00
Karsten Keil 21466f9b7b cleanup silence -> dsp_silence 2005-10-26 14:12:13 +00:00
Karsten Keil 786ab881f8 second fix for bug 7, component length was wrong 2005-06-26 11:35:40 +00:00
srichter 24f62a4c3c Portability fixes:
- use cpu_to_leXX and leXX_to_cpu in order to access the PCI bus in little
   endian mode on all architectures
 - use pci_alloc_consistent instead of kmalloc to allocate buffer memory
2005-06-24 16:48:45 +00:00
Karsten Keil 65eaeb3579 Fix bug #0000007 Capidivert doesnt work with mISDN an Fritz! PCI
- DUMMY CR messages from up was not handled in l3_udss1
2005-06-24 15:33:13 +00:00
Martin Bachem 514a4ab48c care for HW_POWERUP at l1 activation and force deactivation if activation fails (timer3) 2005-06-23 16:43:36 +00:00
Martin Bachem ea21d7f00e added hardware disclaimer to ensure users only HFC-S USB TAs are supported 2005-06-22 08:13:48 +00:00
Andreas Eversberg 5f5bbde7aa Fixed a bug in reporting SLIP / LOS / AIS due to bugreport by Rus.
WARNING: Never tested it!

Modified Files:
	mISDN/drivers/isdn/hardware/mISDN/hfc_multi.c
	mISDN/drivers/isdn/hardware/mISDN/hfc_multi.h
2005-06-05 14:19:52 +00:00
Martin Bachem c2faf5fcc0 ingore INFO3_P8, INFO3_P10, HW_POWERUP 2005-05-04 15:38:31 +00:00
Karsten Keil 00c2a28955 Fix X25 RESET_B3 DISCONNECT_B3 2005-05-02 12:30:30 +00:00
Karsten Keil 7b940e57d4 Fix race condition in DATA_B3 CONF handling 2005-05-02 12:29:22 +00:00
Andreas Eversberg 5892e8575e According to Q.932, notify messages are allowed at any state of call.
(Information about "call will be forwarded now" can be received before connect.)
2005-04-30 15:27:05 +00:00
Martin Bachem 53ad00795a support for Sitecom DC-105 2005-04-08 13:39:58 +00:00
Karsten Keil 2929c9e213 Errorcodes are more readable in decimal (Thanks to Matthias Urlich) 2005-04-07 08:59:41 +00:00
Karsten Keil 8101522abc debug wrong conf frames 2005-04-07 08:57:50 +00:00
Martin Bachem 4e09c93764 prevent memory leak 2005-04-06 12:10:46 +00:00
Martin Bachem b49b5d512b support for Cologne Chip HFC-S USB based ISDN TAs 2005-04-04 14:17:15 +00:00
Martin Bachem ad5d7ae143 support for Cologne Chip HFC-S USB based ISDN TAs 2005-04-04 14:01:00 +00:00
Karsten Keil eb05f41960 cleanup, add some comments 2005-03-09 03:09:06 +00:00
Karsten Keil 5e7f03944c fix for changes in driver_register for 2.6.10 and higher versions 2005-03-09 03:04:07 +00:00
Andreas Eversberg 2476232664 Fixed state change at CC_NOTIFY and CC_PROGRESS.
Added CC_NOTIFY | REQUEST and tested it.

Modified Files:
	mISDN/drivers/isdn/hardware/mISDN/l3_udss1.c
2005-03-03 19:03:03 +00:00
Karsten Keil dc7d9402b8 since the stack build is handled via the mISDNd, the CTRL_READY must be
syncronized with it, so handle it also via mISDNd
2005-02-24 12:48:08 +00:00
Andreas Eversberg 8035c5e67b Now it compiles :)
Modified Files:
	mISDN/drivers/isdn/hardware/mISDN/hfc_multi.c
2005-01-31 17:24:03 +00:00
Andreas Eversberg c102bdedde HFC-E1 supports now selection of receive clock or much more accurate PLL clock for PCM bus clock.
Modified Files:
	mISDN/drivers/isdn/hardware/mISDN/hfc_multi.c
	mISDN/drivers/isdn/hardware/mISDN/hfc_multi.h
2005-01-30 21:23:25 +00:00
Andreas Eversberg beb0f4faea DSP: removed bug that caused to allocate two timeslots for inter-chip communication rather than one. (now it is possible to make 32 calls on a 32 time slot PCM bus and not only 16)
HFC-E1: wrong write to register caused clock sync to to work correcly. the result was biterrors due to slips in frames. (bad to faxes and modem connects). also uncontrolled reset of the jitter buffers caused corrupt frames and slips (losses).

also: new flag to load E1 cards even if PCM clock is available (yet). it can be used to load a PCM slave before the PCM master is loaded.

Modified Files:
	mISDN/drivers/isdn/hardware/mISDN/dsp_cmx.c
	mISDN/drivers/isdn/hardware/mISDN/hfc_multi.c
	mISDN/drivers/isdn/hardware/mISDN/hfc_multi.h
2005-01-29 16:23:24 +00:00
Andreas Eversberg 17f2f8610b Finally PH_ACTIVATE/PH_DEACTIVATE is improved for HFC_E1 (PRI) and LEDS
are supported. RED shows LOS/AIS, GREEN shows ACTIVE state an FIFO activity.
Switches can be used to send LOS and AIS.

Modified Files:
	mISDN/drivers/isdn/hardware/mISDN/hfc_multi.c
	mISDN/drivers/isdn/hardware/mISDN/hfc_multi.h
2005-01-27 23:42:30 +00:00
Karsten Keil d2726ff9e2 Handle RESTART collition properly;Thanks to Bodo Pfelzer <Bodo.Pfelzer@web.de> 2005-01-18 16:01:33 +00:00
Andreas Eversberg 62079d9a77 Fixed bug in detecting PCI devices, if multiple cards of different type
are installed.

Modified Files:
	mISDN/drivers/isdn/hardware/mISDN/hfc_multi.c
2004-12-20 05:24:34 +00:00
Andreas Eversberg fdf3a2952b Finally the fix for the 'Raising Delay' bug. This fix will also available
in the mISDN_for_pbx4linux-fix4 file on isdn.jolly.de.
Losing IRQs cause a raising delay during lifetime of a conference or
crossconnection. You need only to replace the given file. Don't reinstall
the complete mISDN package:
- copy the dsp_cmx.c to the kernel source
- touch dsp_cmx.c (if older than your dsp_cmx.o)
- make modules (you see that dsp_cmx.c will be compiled)
- make modules_install
- stop pbx
- reload mISDN
- start pbx

Modified Files:
	mISDN/drivers/isdn/hardware/mISDN/dsp_cmx.c
2004-12-19 16:17:36 +00:00
Andreas Eversberg 8beec5109d Flushing FIFO after activation of layer 1, to remove corrput data
during activation sequence.

Modified Files:
	mISDN/drivers/isdn/hardware/mISDN/hfc_multi.c
2004-12-03 12:00:31 +00:00
Andreas Eversberg 9e0fc751ff Fixes:
- udevice works with kernel 2.6.8 and hopefully > 2.6.8
  (required for PBX4Linux & Asterisk channel driver)
- hfc_multi driver (HFC-4S/8S/E1) now works with kernel >= 2.6.8
- hfc_multi crash bug fix while unloading
- hfc_multi now uses correct leds display on HFC-4S boards
  (red blinking or off = layer 1 inactive
   red = layer 1 active
   green / green flashing = traffic on interface)

Modified Files:
	mISDN/drivers/isdn/hardware/mISDN/hfc_multi.c
	mISDN/drivers/isdn/hardware/mISDN/hfc_multi.h
	mISDN/drivers/isdn/hardware/mISDN/udevice.c
2004-11-19 18:47:40 +00:00
Andreas Eversberg 84921213dc minor fixes from Simon
Modified Files:
	mISDN/drivers/isdn/hardware/mISDN/hfc_multi.c
2004-11-08 08:08:12 +00:00
Andreas Eversberg 3891628b0b Now HFC multiport driver (HFC-4s/8s/e1) uses IO PCI access. With a kernel
option it still can be set to memory PCI access.

Modified Files:
	mISDN/drivers/isdn/hardware/mISDN/Kconfig.v2.6
	mISDN/drivers/isdn/hardware/mISDN/hfc_multi.c
	mISDN/drivers/isdn/hardware/mISDN/hfc_multi.h
2004-09-23 20:17:08 +00:00
Andreas Eversberg cf68d7e299 1. Finally hardware echo (channel looping) works. It is usefull to messure
delay and count biterrors.

2. New vendor IDs are added to the hfc_multi driver (Beronet Cards).

Modified Files:
	mISDN/drivers/isdn/hardware/mISDN/dsp.h
	mISDN/drivers/isdn/hardware/mISDN/dsp_cmx.c
	mISDN/drivers/isdn/hardware/mISDN/dsp_core.c
	mISDN/drivers/isdn/hardware/mISDN/hfc_multi.c
2004-08-28 12:35:26 +00:00
Andreas Eversberg 6a9dfe9e94 Bugfix of unregistering, that cause the crash when unloading the module.
Modified Files:
	mISDN/drivers/isdn/hardware/mISDN/hfc_multi.c
2004-08-01 14:55:41 +00:00
Karsten Keil 4e154aecee fix mISDN_headext 2004-07-08 00:58:20 +00:00
Karsten Keil 3d9f29d093 use mISDN_head_t also for user mode 2004-07-08 00:49:49 +00:00
Karsten Keil b7b532ca9d locking the dbg lists 2004-07-07 20:41:50 +00:00
Andreas Eversberg c5b8933b5b Fixed module unload bug. This occurred especially since kernel 2.6.6.
Modified Files:
	mISDN/drivers/isdn/hardware/mISDN/hfc_multi.c
2004-07-06 20:45:57 +00:00
Andreas Eversberg 13a54f711d Cleanup of dsp_tones.c.
Fixes and minor changes of hfc 4s/8s/e1 driver.

Modified Files:
	mISDN/drivers/isdn/hardware/mISDN/dsp_tones.c
	mISDN/drivers/isdn/hardware/mISDN/hfc_multi.c
	mISDN/drivers/isdn/hardware/mISDN/hfc_multi.h
2004-07-04 10:31:09 +00:00
Karsten Keil 62c911e0cd remove /dev/mISDN ringbuffers; use queues instead 2004-06-30 15:13:20 +00:00
Karsten Keil 918caa4018 use the common kernel list.h implementation for the lists in mISDN 2004-06-17 12:31:14 +00:00
Andreas Eversberg 818a365de2 Modified Files:
mISDN/drivers/isdn/hardware/mISDN/l3_udss1.c
Removed bug that caused crashed when receiving facility frame with
dummy call ref. These messages are only generated by some switches
(not EWSD).
2004-05-31 14:02:51 +00:00
Karsten Keil 1a7843297d add some CONFIG_PNP conditionals, so the driver also load on none ISAPNP
configs (Thanks to Ingo Krabbe/Joerg Dorchain for discover this)
2004-05-28 23:00:20 +00:00
Andreas Eversberg ebbb33b3de Fixed problem of hfc-4s/8s/e1 driver in conjunction with capi. Added delay
of 100ms until sending MGR_CTRLREADY from driver.
KKeil: Please review it and tell me why it is required to wait.

Modified Files:
	mISDN/drivers/isdn/hardware/mISDN/hfc_multi.c
2004-04-05 19:39:21 +00:00
Andreas Eversberg cc28674787 Now it compiles without error...
Modified Files:
	mISDN/drivers/isdn/hardware/mISDN/layer3.c
2004-03-28 17:52:36 +00:00
Andreas Eversberg ea898aa233 Now audio hardware support with automatic driver feature detection is
testet and works stable.

Modified Files:
	mISDN/drivers/isdn/hardware/mISDN/dsp.h
	mISDN/drivers/isdn/hardware/mISDN/dsp_audio.c
	mISDN/drivers/isdn/hardware/mISDN/dsp_blowfish.c
	mISDN/drivers/isdn/hardware/mISDN/dsp_cmx.c
	mISDN/drivers/isdn/hardware/mISDN/dsp_core.c
	mISDN/drivers/isdn/hardware/mISDN/dsp_dtmf.c
	mISDN/drivers/isdn/hardware/mISDN/dsp_tones.c
	mISDN/drivers/isdn/hardware/mISDN/Kconfig.v2.6
	mISDN/include/linux/mISDNif.h

E1 (PRI) interface now works stable including own layer 1 support.

Modified Files:
	mISDN/drivers/isdn/hardware/mISDN/hfc_multi.c
	mISDN/drivers/isdn/hardware/mISDN/hfc_multi.h

Layer 3 now handles PRI interfaces correctly.
 - each layer-3 instance with local callref counter
 - correct restart procedure (stays in state 0)
 - new feature flag for long callref (ISDN_PID_L3_CRLEN2)
 - MINOR FIX: when parsing the information elements, the second element
   found doesn't overwrite the first element anymore.

Modified Files:
	mISDN/drivers/isdn/hardware/mISDN/l3_udss1.c
	mISDN/drivers/isdn/hardware/mISDN/layer3.c
	mISDN/drivers/isdn/hardware/mISDN/layer3.h
	mISDN/include/linux/mISDNif.h
2004-03-28 17:13:08 +00:00
Andreas Eversberg 342ebbf58f Added missing file "dsp_blowfish.c"
Added Files:
	dsp_blowfish.c
2004-02-16 23:10:26 +00:00
Karsten Keil 412a999cf3 move reset behind IRQ request 2004-02-16 10:09:53 +00:00
Andreas Eversberg 23ae60a595 PCM connect/disconect bugfix.
Modified Files:
	mISDN/drivers/isdn/hardware/mISDN/hfc_multi.c
	mISDN/drivers/isdn/hardware/mISDN/hfc_multi.h
2004-02-16 08:18:25 +00:00
Andreas Eversberg f4d01aaa70 Removed obsolete "//jolly patch" comments.
Modified Files:
	mISDN/drivers/isdn/hardware/mISDN/l3_udss1.c
2004-02-15 23:02:41 +00:00
Andreas Eversberg d32e9d4184 Bugfixes when unloading the hfcmulti module.
Some better debugging.
Minor source changes.

Modified Files:
	mISDN/drivers/isdn/hardware/mISDN/dsp_cmx.c
	mISDN/drivers/isdn/hardware/mISDN/hfc_multi.c
2004-02-14 20:09:28 +00:00
Andreas Eversberg e8fae00343 Update of HFC multiport driver and dsp module. Ported to current api names.
Many fixes, hardware support for dtmf, conferences, crossconnects.
Blowfish crypt support for audio data (dsp).
Changes to Kconfig, Makefile and Rules.mISDN. Minor changes to mISDNif.h.

Modified Files:
	mISDN/drivers/isdn/hardware/mISDN/Kconfig.v2.6
	mISDN/drivers/isdn/hardware/mISDN/Makefile
	mISDN/drivers/isdn/hardware/mISDN/Makefile.v2.4
	mISDN/drivers/isdn/hardware/mISDN/Makefile.v2.6
	mISDN/drivers/isdn/hardware/mISDN/Rules.mISDN.v2.4
	mISDN/drivers/isdn/hardware/mISDN/dsp.h
	mISDN/drivers/isdn/hardware/mISDN/dsp_audio.c
	mISDN/drivers/isdn/hardware/mISDN/dsp_cmx.c
	mISDN/drivers/isdn/hardware/mISDN/dsp_core.c
	mISDN/drivers/isdn/hardware/mISDN/dsp_dtmf.c
	mISDN/drivers/isdn/hardware/mISDN/dsp_tones.c
	mISDN/drivers/isdn/hardware/mISDN/hfc_multi.c
	mISDN/drivers/isdn/hardware/mISDN/hfc_multi.h
	mISDN/include/linux/mISDNif.h
2004-02-14 17:43:15 +00:00
Karsten Keil c86cad1c3c first version of L2/L3 faxservice for CAPI ALPHA !!!
- need Sedlbauer Speedfax+
- Sendonly at the moment
- only SFF, 1-D MH
- Error handling not complete
- lot of debug messages
2004-02-05 21:21:18 +00:00
Karsten Keil 16ff314d9b fix ISAPNP declarations for 2.4 2004-01-31 00:04:36 +00:00
Karsten Keil f947bb1dda - CAPI BxConfiguration was not handled
- add CAPI protocol IDs
2004-01-30 23:46:39 +00:00
Karsten Keil 4520efea23 - fix transparent audio mode
- new PCI and PnP code
2004-01-29 00:54:41 +00:00
Karsten Keil dc3f532e70 - handle HASPROTOCOL
- cleanup not handled messages
2004-01-29 00:53:13 +00:00
Karsten Keil 29755c5e2a missing items for hfc_multi 2004-01-28 11:34:46 +00:00
Karsten Keil 534b91544a new items for hfc_multi driver 2004-01-28 10:06:40 +00:00
Karsten Keil 502df8c8cc fix mISDN_getrev if called twice 2004-01-28 09:40:04 +00:00
Karsten Keil 687d208d8e follow latest changes; still not compile 2004-01-28 08:27:40 +00:00
Karsten Keil ba3087428b remove MSDOS <CR> 2004-01-28 08:17:28 +00:00
Karsten Keil 1212f1ac39 add HFC multiport driver 2004-01-28 08:03:45 +00:00
Karsten Keil 03381a45d2 fix hang while loading firmware 2004-01-27 22:42:37 +00:00
Paul Slootman f26b3e2119 Only typedef irqreturn_t if IRQ_HANDLED isn't defined yet. 2004-01-27 18:09:18 +00:00
Karsten Keil 2099445d86 make direct compiles for 2.4 after ./std2kern possible 2004-01-27 16:37:59 +00:00
Karsten Keil a81680766c next version 2004-01-27 13:56:37 +00:00
Karsten Keil bd02c3349f LED handler 2004-01-27 12:55:55 +00:00
Karsten Keil 8c08d2452a changes for 2.4 2004-01-27 01:50:20 +00:00
Karsten Keil e16c026f52 - move common functions to mISDN_core and export them
- make it possible to compile into the kernel
2004-01-26 22:21:32 +00:00
Karsten Keil 5c8ff7788c sync i4l 2004-01-25 22:45:42 +00:00
Karsten Keil 71a70af6e4 remove old eicon dir 2004-01-19 11:09:02 +00:00
Karsten Keil 54bf56649a fix some minor capi problems 2004-01-19 11:02:48 +00:00
Karsten Keil 095ce49d2a remove unneeded sti - SMP cleaning 2004-01-19 11:01:11 +00:00
Karsten Keil e2da308e66 update release 2004-01-19 10:59:20 +00:00
Karsten Keil db16534050 delayed cmesg are not possible, since cmesg may contain local pointers or
pointers to allready freed skb if delayed. So we prepare the final skb
instead and queue it.
2004-01-13 13:38:02 +00:00
Karsten Keil 2723418266 implement put_message return value
this is needed for proper flowcontrol in case of full message queue
2004-01-12 16:20:26 +00:00
Karsten Keil d69a999fa3 now FritzPCI v2.0 should work 2004-01-12 16:18:20 +00:00
Karsten Keil e73f50283d new definition is u_long for bit field type variables 2004-01-11 14:07:36 +00:00
Karsten Keil 7c3b38f64b we hold a spinlock with disabled IRQs so we must use GFP_ATOMIC in kmalloc 2004-01-11 14:02:26 +00:00
Karsten Keil c361dcf36c fix module owner assign 2004-01-11 13:58:50 +00:00
Karsten Keil 69b589d9b1 fix cut&paste error in last fix 2004-01-03 23:10:43 +00:00
Karsten Keil 2a5c1b4d35 delete interface references if HW driver is released 2004-01-03 23:07:35 +00:00
Karsten Keil db2a923a8c - cleanup debug
- NCCI direct handling via second state machine
2003-12-14 15:20:38 +00:00
Karsten Keil 5a6a9edc86 -cleaner shutdown of a B-channel 2003-12-14 15:19:02 +00:00
Karsten Keil e504373ebf - the link stack is now part of the AppPLCI struct to allow more as one NCCI 2003-12-13 00:36:16 +00:00
Karsten Keil c4271592e3 - first version of X25/X31 DTE protocol (ISO 8208) 2003-12-10 23:01:16 +00:00
Karsten Keil ee11c08ca9 - use DINFO as unique ID field in Datamessages (only downstream at the moment)
- begin to support more as one NCCI per (App)PCLI
2003-12-03 14:32:46 +00:00
Karsten Keil a23e7a864e fix some warnings
fix new capidrv interface (2.6)
2003-11-25 11:28:32 +00:00
Karsten Keil 376ee65136 fix sequence 2003-11-21 23:51:05 +00:00
Karsten Keil 8d5f6a65d3 add memory resource debug
main use is to find memory and buffer leaks at the moment
2003-11-21 22:57:08 +00:00
Karsten Keil 85337c9851 big rewrite of the CAPI 2.0 implementation
- hopefully easier to understand and follow the dataflow
- no limitations in application count
- clean shutdown on errors
- use own kmem caches
- reduce stack usage, use dynamic allocated cmsg
2003-11-21 22:29:41 +00:00
Karsten Keil ffa91934b6 fix skb leak 2003-11-21 13:20:10 +00:00
Karsten Keil 6b768b38be now TEI verify is initiated on related MDL errors (see Appendix II/Table II-1 Q.921) 2003-11-16 19:34:00 +00:00
Karsten Keil 901de44f30 add HW_TEST function for monitoring B-channel 2003-11-13 13:01:55 +00:00
Karsten Keil 9875a66041 locking PH_CONTROL 2003-11-13 13:00:45 +00:00
Karsten Keil 07bdf740c4 fix fifo free bytes calculation
PTP now handled in set_dchannel_pid
2003-11-11 21:06:34 +00:00
Karsten Keil 60271ca2c4 - add headset volume control via MANUFACTURER REQUEST 2003-11-11 20:31:35 +00:00
Karsten Keil 9dbe8ab580 release 7 2003-11-11 10:46:39 +00:00
Karsten Keil 61dc94dc12 Handset support 2003-11-11 10:02:23 +00:00
Karsten Keil f981c59afa new process id handling (used by L3/L4 only at the moment) 2003-11-11 09:59:01 +00:00
Karsten Keil a804c5e387 typo fixes 2003-11-09 16:13:39 +00:00
Karsten Keil 34c2231099 release 6 2003-11-09 16:05:29 +00:00
Karsten Keil ac245e4f03 add overlap sending 2003-11-09 16:03:19 +00:00
Karsten Keil f5e8b76653 fix PTP startup 2003-11-09 16:02:36 +00:00
Karsten Keil 5b258f12f7 add PTP handling with protocol 2003-11-09 16:01:12 +00:00
Karsten Keil 732742f5ae fix bitorder 2003-11-09 11:37:40 +00:00
Karsten Keil 38b2c883d0 fix channel selection code 2003-11-09 09:54:02 +00:00
Karsten Keil 01eea674f4 add dsp patches from Andreas 2003-11-09 09:43:10 +00:00
Karsten Keil 9804ce04f3 add support for Winbond 6692 based cards 2003-11-09 09:33:22 +00:00
Karsten Keil de3ed4b928 fix global process skb bugs 2003-11-09 09:22:17 +00:00
Karsten Keil a07bcdbc73 fix dinfo data message bug 2003-11-09 09:21:28 +00:00
Karsten Keil 087341a247 fix no module bug 2003-11-09 09:20:41 +00:00
Karsten Keil 1323cf35ec add global options
add POTS support
2003-11-09 09:19:47 +00:00
Karsten Keil 6b4f858edd add function for discovering GLOBAL parameter for CAPI PROFILE 2003-11-09 09:16:16 +00:00
Karsten Keil 3bfc0bfb97 add more debug output
improve error handling of DATA B3
2003-11-09 09:14:24 +00:00
Karsten Keil 21c4453091 rename ASN1 debug function 2003-11-09 09:12:28 +00:00
Karsten Keil dbb4d39d89 remove warning - vmalloc kernel memory is not swapable
SET_MODULE_OWNER need pointer
2003-10-26 00:13:31 +00:00
Karsten Keil fdb4554989 small fixes from jolly 2003-10-24 21:27:28 +00:00
Karsten Keil a668767214 new release 2003-10-24 21:26:55 +00:00
Karsten Keil 21ba75f6fc compile audio DSP module 2003-10-24 21:26:34 +00:00
Karsten Keil 1dd41139d7 new DSP functions from jolly for conferencing and other audio processing 2003-10-24 21:23:05 +00:00
Karsten Keil a027d30557 fix iminor for 2.4 2003-10-22 13:19:57 +00:00
Karsten Keil a0230a1cd7 fix version specific 2003-10-22 10:32:16 +00:00
Karsten Keil 04e451b602 additional debug for contr/PLCI
do not remove plci if it is still accessed by the caller
2003-10-20 07:19:42 +00:00
Karsten Keil fddc1475e7 cleanup debug messages
default handler for mmanager
2003-09-06 17:13:02 +00:00
Karsten Keil 90ab30a38d cleanup locking, now ready for 2.6 2003-09-06 17:11:42 +00:00
Karsten Keil 0dc7dd5c8c multi kernel enviroment 2003-08-13 15:05:59 +00:00
Karsten Keil cdc52fe430 fix missing kfree 2003-08-12 17:08:50 +00:00
Karsten Keil a34671a12e - evaluate capi profile contence from stack 2003-08-02 21:17:58 +00:00
Karsten Keil 23bf3dfc13 - add stack parameter for needed header space
- set controler ready
- cleanup
2003-08-01 22:15:53 +00:00
Karsten Keil 4f4c070e39 add Rules.mISDN 2003-07-28 12:49:09 +00:00
Karsten Keil 002d7d9050 make changes for 2.5/2.6 2003-07-28 12:41:46 +00:00
Karsten Keil 8f07adb55c - more 2.5/26 compatibility 2003-07-28 12:05:47 +00:00
Karsten Keil f79ff2f3f5 cleanup warning and old stuff 2003-07-27 11:14:19 +00:00
138 changed files with 55599 additions and 10279 deletions

8
CHANGES Normal file
View File

@ -0,0 +1,8 @@
mISDN-1-1-2:
- added a workaround that fixes a kernel panic when bridging is done after already a few
voice frames where transceived on both legs (like when you transfer a call from SIP 2 ISDN)
- jollys mail has changed
- minor tweaks to misdn-init and to the Kernel-Patch script
- fix in CMX: sending is required even during PCM bridge, because sending data overrides bridging temporarily (for sending info tones during bridge)
- enabled CMX audio processing for RX data in all cases, because it is essential
- now it is save to free skb during interrupt, if memdebug is on

127
Makefile Normal file
View File

@ -0,0 +1,127 @@
BASEDIR=$(shell pwd)
MAJOR=1
MINOR=1
SUBMINOR=2
INSTALL_PREFIX := /
export INSTALL_PREFIX
#PATH to linux source/headers
#LINUX=/usr/src/linux
ifndef KVERS
KVERS:=$(shell uname -r)
endif
MODS=/lib/modules/$(KVERS)
LINUX=$(MODS)/build
LINUX_SOURCE=$(MODS)/source
UPDATE_MODULES=$(shell which update-modules)
MODULES_UPDATE=$(shell which modules-update)
DEPMOD=$(shell which depmod)
MISDNDIR=$(BASEDIR)
MISDN_SRC=$(MISDNDIR)/drivers/isdn/hardware/mISDN
########################################
# USER CONFIGS END
########################################
CONFIGS+=CONFIG_MISDN_DRV=m
CONFIGS+=CONFIG_MISDN_DSP=m
CONFIGS+=CONFIG_MISDN_HFCMULTI=m
CONFIGS+=CONFIG_MISDN_HFCPCI=m
CONFIGS+=CONFIG_MISDN_HFCUSB=m
CONFIGS+=CONFIG_MISDN_XHFC=m
CONFIGS+=CONFIG_MISDN_HFCMINI=m
CONFIGS+=CONFIG_MISDN_W6692=m
CONFIGS+=CONFIG_MISDN_SPEEDFAX=m
CONFIGS+=CONFIG_MISDN_AVM_FRITZ=m
CONFIGS+=CONFIG_MISDN_NETJET=m
#CONFIGS+=CONFIG_MISDN_NETDEV=y
MISDNVERSION=$(shell cat VERSION)
MINCLUDES+=-I$(MISDNDIR)/include
all: VERSION test_old_misdn
cp $(MISDNDIR)/drivers/isdn/hardware/mISDN/Makefile.v2.6 $(MISDNDIR)/drivers/isdn/hardware/mISDN/Makefile
export MINCLUDES=$(MISDNDIR)/include ; export MISDNVERSION=$(MISDNVERSION); make -C $(LINUX) SUBDIRS=$(MISDN_SRC) modules $(CONFIGS)
install: all modules-install misdn-init
$(DEPMOD)
$(UPDATE_MODULES)
$(MODULES_UPDATE)
make -C config install
modules-install:
cd $(LINUX) ; make INSTALL_MOD_PATH=$(INSTALL_PREFIX) SUBDIRS=$(MISDN_SRC) modules_install
mkdir -p $(INSTALL_PREFIX)/usr/include/linux/
cp $(MISDNDIR)/include/linux/*.h $(INSTALL_PREFIX)/usr/include/linux/
misdn-init:
mkdir -p $(INSTALL_PREFIX)/usr/sbin/
install -m755 misdn-init $(INSTALL_PREFIX)/usr/sbin/
if [ -d $(INSTALL_PREFIX)/etc/init.d ]; then \
if [ -e $(INSTALL_PREFIX)/etc/init.d/misdn-init ]; then rm -rf $(INSTALL_PREFIX)/etc/init.d/misdn-init; fi; \
ln -s $(INSTALL_PREFIX)/usr/sbin/misdn-init $(INSTALL_PREFIX)/etc/init.d/misdn-init; \
fi
mkdir -p $(INSTALL_PREFIX)/etc/modprobe.d
cp mISDN.modprobe.d $(INSTALL_PREFIX)/etc/modprobe.d/mISDN
mkdir -p $(INSTALL_PREFIX)/etc/modules.d
cp mISDN.modprobe.d $(INSTALL_PREFIX)/etc/modules.d/mISDN
test_old_misdn:
@if echo -ne "#include <linux/mISDNif.h>" | gcc -C -E - 2>/dev/null 1>/dev/null ; then \
if ! echo -ne "#include <linux/mISDNif.h>\n#if MISDN_MAJOR_VERSION < 4\n#error old mISDNif.h\n#endif\n" | gcc -C -E - 2>/dev/null 1>/dev/null ; then \
echo -ne "\n!!You should remove the following files:\n\n$(LINUX)/include/linux/mISDNif.h\n$(LINUX)/include/linux/isdn_compat.h\n/usr/include/linux/mISDNif.h\n/usr/include/linux/isdn_compat.h\n\nIn order to upgrade to the mqueue branch\n\n"; \
echo -ne "I can do that for you, just type: make force\n\n" ; \
exit 1; \
fi ;\
fi
.PHONY: modules-install install all clean misdn-init VERSION
force:
rm -f $(LINUX)/include/linux/mISDNif.h
rm -f $(LINUX)/include/linux/isdn_compat.h
rm -f /usr/include/linux/mISDNif.h
rm -f /usr/include/linux/isdn_compat.h
clean:
rm -rf drivers/isdn/hardware/mISDN/*.o
rm -rf drivers/isdn/hardware/mISDN/*.ko
rm -rf *~
find . -iname ".*.cmd" -exec rm -rf {} \;
find . -iname ".*.d" -exec rm -rf {} \;
find . -iname "*.mod.c" -exec rm -rf {} \;
find . -iname "*.mod" -exec rm -rf {} \;
VERSION:
if cvs status Makefile | grep "Sticky Tag" | grep none > /dev/null ; then \
echo $(MAJOR)_$(MINOR)_$(SUBMINOR)-$$(date +"20%y_%m_%d" | sed -e "s/\//_/g") > VERSION ; \
else \
echo $(MAJOR)_$(MINOR)_$(SUBMINOR) > VERSION ; \
fi
snapshot: clean
DIR=mISDN-$$(date +"20%y_%m_%d") ; \
echo $(MAJOR)_$(MINOR)_$(SUBMINOR)-$$(date +"20%y_%m_%d" | sed -e "s/\//_/g") > VERSION ; \
mkdir -p /tmp/$$DIR ; \
cp -a * /tmp/$$DIR ; \
cd /tmp/; \
tar czf $$DIR.tar.gz $$DIR
release: clean
DIR=mISDN-$(MAJOR)_$(MINOR)_$(SUBMINOR) ; \
echo $(MAJOR)_$(MINOR)_$(SUBMINOR) > VERSION ; \
mkdir -p /tmp/$$DIR ; \
cp -a * /tmp/$$DIR ; \
cd /tmp/; \
tar czf $$DIR.tar.gz $$DIR

55
README.misdn-init Normal file
View File

@ -0,0 +1,55 @@
misdn-init: init-script to auto-configure and load the mISDN kernel drivers
===========================================================================
This script makes it easy to configure and activate mISDN compatible
adapter cards. It scans an eyecandy config file named misdn-init.conf
for your card and port settings, then it loads the driver modules properly.
The misdn-init.conf can also be autogenerated by the misdn-init script.
---------------------------------------------------------------------------
Usage: /usr/sbin/misdn-init start|stop|restart|config|scan|help
--start scan /etc/misdn-init.conf and load the mISDN drivers
--stop unload the mISDN drivers
--restart see stop, then start
--config scan your PCI bus for mISDN compatible hardware and generate
a /etc/misdn-init.conf
--scan scan your PCI bus for mISDN compatible hardware and print
the results to the console
--help print the usage info
---------------------------------------------------------------------------
* Here is a quick overview on how to use misdn-init:
1) Get and install misdn-init:
$ wget http://www.beronet.com/downloads/chan_misdn/stable/chan_misdn.tar.gz
$ tar zxf chan_misdn.tar.gz
$ (as root) cp chan_misdn/misdn-init /usr/sbin/misdn-init
2) Let misdn-init scan your PCI bus for mISDN compatible hardware and write
the results into /etc/misdn-init.conf:
$ (as root) /usr/sbin/misdn-init config
3) (optional) Edit /etc/misdn-init.conf and set everything the way you want it.
This file is heavily commented, hence it should be self-explaining.
4) (optional, but recommended) Add misdn-init to your run level.
This is distribution dependend. Here an example for a debian system:
ATTENTION: If you have services in your runlevels that depend
on mISDN, make sure that misdn-init starts before, and
stops after them (this is done by changing the values
that are set to 60 in this example, more info: read the
manpage for update-rc.d).
$ (as root) update-rc.d misdn-init start 60 2 3 4 5 . stop 60 0 1 6 .
5) Run the following to start mISDN:
$ (as root) /usr/sbin/misdn-init start
---------------------------------------------------------------------------
* Report Bugs:
If you experience any bugs or have a feature request, please visit:
www.isdn4linux.de/mantis

View File

@ -1,3 +1,10 @@
# new mISDN driver as module
CONFIG_ISDN_DRV_mISDN=m
#
# Modular ISDN driver
#
CONFIG_MISDN_DRV=m
CONFIG_MISDN_AVM_FRITZ=y
CONFIG_MISDN_HFCPCI=y
CONFIG_MISDN_SPEEDFAX=y
CONFIG_MISDN_W6692=y
CONFIG_MISDN_DSP=y
CONFIG_MISDN_MEMDEBUG=y

11
config/Makefile Normal file
View File

@ -0,0 +1,11 @@
all:
@echo "Please run 'make install'."
install:
install -D -m755 mISDN $(INSTALL_PREFIX)/usr/sbin/mISDN
for file in $(shell echo *.xsl); do install -D -m644 $${file} $(INSTALL_PREFIX)/usr/lib/mISDN/$${file}; done
if [ -d $(INSTALL_PREFIX)/etc/init.d ]; then \
if [ -e $(INSTALL_PREFIX)/etc/init.d/mISDN ]; then rm -rf $(INSTALL_PREFIX)/etc/init.d/mISDN; fi; \
ln -s $(INSTALL_PREFIX)/usr/sbin/mISDN $(INSTALL_PREFIX)/etc/init.d/mISDN; \
fi

65
config/README.mISDN Normal file
View File

@ -0,0 +1,65 @@
'mISDN': init-script to auto-configure and load the mISDN kernel drivers
===========================================================================
This script makes it easy to configure and activate mISDN compatible
adapter cards. It scans an eyecandy config file named mISDN.conf
for your card and port settings, then it loads the driver modules properly.
The misdn-init.conf can also be autogenerated by the mISDN script.
---------------------------------------------------------------------------
Requirements:
The 'mISDN' script requires you to install the tool 'xsltproc'. To install
xsltproc on debian, just type:
$ apt-get install xsltproc (as root)
On other distros the package name might be libxmtools or likewise.
---------------------------------------------------------------------------
Usage: /usr/sbin/misdn-init start|stop|restart|config|scan|help
--start scan /etc/misdn-init.conf and load the mISDN drivers
--stop unload the mISDN drivers
--restart see stop, then start
--config scan your PCI bus for mISDN compatible hardware and generate
a /etc/mISDN.conf
--scan scan your PCI bus for mISDN compatible hardware and print
the results to the console
--help print the usage info
---------------------------------------------------------------------------
* Here is a quick overview on how to use mISDN:
1) Get and install mISDN:
$ wget http://www.misdn.org/downloads/mISDN.tar.gz
$ tar xzf mISDN.tar.gz
$ cd mISDN*
$ make install
2) Let mISDN scan your PCI bus for mISDN compatible hardware and write
the results into /etc/mISDN.conf:
$ (as root) mISDN config
3) (optional) Edit /etc/mISDN.conf and set everything the way you want it.
This file is heavily commented, hence it should be self-explaining.
4) (optional, but recommended) Add 'mISDN' to your run level.
This is distribution dependend. Here an example for a debian system:
ATTENTION: If you have services in your runlevels that depend
on mISDN, make sure that 'mISDN' starts before, and
stops after them (this is done by changing the values
that are set to 60 in this example, more info: read the
manpage for update-rc.d).
$ (as root) update-rc.d mISDN start 60 2 3 4 5 . stop 60 0 1 6 .
5) Run the following to start mISDN:
$ (as root) mISDN start
---------------------------------------------------------------------------
* Report Bugs:
If you experience any bugs or have a feature request, please visit:
www.isdn4linux.de/mantis

434
config/mISDN Executable file
View File

@ -0,0 +1,434 @@
#!/bin/bash
#----------------------------------------------
#
# CONFIGURATION:
#
MISDN_CONF="/etc/mISDN.conf"
MISDN_CONF_XSL="/usr/lib/mISDN/mISDN.conf.xsl"
#
#----------------------------------------------
SELF="${0}"
USAGE="Usage: ${SELF} start|stop|restart|config|scan|help"
function die {
echo "[!!] ${1}"
exit 1
}
function check_cmd
{
if ! which "${1}" > /dev/null; then
if [ "${2}" = "opt" ]; then
return
fi
if [ "$(id -u)" != "0" ]; then
die "$1 not in path, please install and/or be root."
else
die "$1 not in path, please install."
fi
exit 1
else
local var=$(echo ${1} | tr a-z A-Z)
eval "$var=`which ${1}`"
fi
}
function check_misdn_conf
{
if [ ! -f ${MISDN_CONF} ]; then
die "${MISDN_CONF} not found. Please run: ${SELF} config"
fi
}
check_cmd sed
check_cmd cut
check_cmd cp
check_cmd wc
check_cmd grep
check_cmd xsltproc
check_cmd modprobe
check_cmd sleep
check_cmd lspci
check_cmd lsusb opt
check_cmd mknod
check_cmd chown
check_cmd chmod
declare -a START_COMMANDS
declare -a STOP_COMMANDS
declare -a HFCMULTI_card
declare -a HFCMULTI_type
declare -a HFCMULTI_protocol
declare -a HFCMULTI_layermask
HFCMULTI_options=''
MISDNDSP_options=''
AVMFRITZ_protocol=''
AVMFRITZ_layermask=''
HFCPCI_protocol=''
HFCPCI_layermask=''
DEVNODE_user='root'
DEVNODE_group='root'
DEVNODE_mode='0644'
declare -a SCAN_card
declare -a SCAN_opts
declare -a SCAN_num_ports
declare -a SCAN_port_opts
function parse_config
{
local CONFIG=$(${XSLTPROC} ${MISDN_CONF_XSL} ${MISDN_CONF})
local t p l line i tmpcmd curr tmpstr
local IFS=$'\n'
START_COMMANDS[${#START_COMMANDS[@]}]="${MODPROBE} --ignore-install capi"
START_COMMANDS[${#START_COMMANDS[@]}]="${MODPROBE} --ignore-install mISDN_core debug=0"
START_COMMANDS[${#START_COMMANDS[@]}]="${MODPROBE} --ignore-install mISDN_l1 debug=0"
START_COMMANDS[${#START_COMMANDS[@]}]="${MODPROBE} --ignore-install mISDN_l2 debug=0"
START_COMMANDS[${#START_COMMANDS[@]}]="${MODPROBE} --ignore-install l3udss1 debug=0"
START_COMMANDS[${#START_COMMANDS[@]}]="${MODPROBE} --ignore-install mISDN_capi"
for line in ${CONFIG}; do
case "${line}" in
DEVNODE:mISDN*)
tmpstr=$(echo ${line} | ${SED} -n 's/.*user:\([^ ]*\).*/\1/p')
if [ ! -z "${tmpstr}" ]; then
DEVNODE_user="${tmpstr}"
fi
tmpstr=$(echo ${line} | ${SED} -n 's/.*group:\([^ ]*\).*/\1/p')
if [ ! -z "${tmpstr}" ]; then
DEVNODE_group="${tmpstr}"
fi
tmpstr=$(echo ${line} | ${SED} -n 's/.*mode:\([^ ]*\).*/\1/p')
if [ ! -z "${tmpstr}" ]; then
DEVNODE_mode="${tmpstr}"
fi
;;
MODULE:hfcmulti*)
HFCMULTI_options=${line:16}
;;
MODULE:mISDN_dsp*)
MISDNDSP_options=${line:17}
;;
CARD:BN*)
curr='hfcmulti'
i=${#HFCMULTI_type[@]}
let "t = $(echo ${line} | ${SED} -n 's/.*type:\([^,]*\).*/\1/p')"
HFCMULTI_type[${i}]=$(printf "0x%x" ${t})
# this is for the BN2E1 card that needs two type numbers
t=$(echo ${line} | ${SED} -n 's/.*type:[^,]*,\([^ ]*\).*/\1/p')
if [ ! -z "${t}" ]; then
let "t = ${t}"
HFCMULTI_type[${i}]="${HFCMULTI_type[${i}]},$(printf "0x%x" ${t})"
fi
HFCMULTI_card[${i}]=$(echo ${line:5} | ${CUT} -d" " -f1)
;;
CARD:hfcpci*)
curr='hfcpci'
;;
CARD:avmfritz*)
curr='avmfritz'
;;
PORT*)
case "${curr}" in
hfcmulti)
let "p = $(echo ${line} | ${SED} -n 's/.*protocol:\([^ ]*\).*/\1/p')"
HFCMULTI_protocol[${i}]="${HFCMULTI_protocol[${i}]:+"${HFCMULTI_protocol[${i}]},"}$(printf "0x%x" ${p})"
let "l = $(echo ${line} | ${SED} -n 's/.*layermask:\([^ ]*\).*/\1/p')"
HFCMULTI_layermask[${i}]="${HFCMULTI_layermask[${i}]:+"${HFCMULTI_layermask[${i}]},"}$(printf "0x%x" ${l})"
;;
hfcpci)
let "p = $(echo ${line} | ${SED} -n 's/.*protocol:\([^ ]*\).*/\1/p')"
HFCPCI_protocol="${HFCPCI_protocol:+"${HFCPCI_protocol},"}$(printf "0x%x" ${p})"
let "l = $(echo ${line} | ${SED} -n 's/.*layermask:\([^ ]*\).*/\1/p')"
HFCPCI_layermask="${HFCPCI_layermask:+"${HFCPCI_layermask},"}$(printf "0x%x" ${l})"
;;
avmfritz)
let "p = $(echo ${line} | ${SED} -n 's/.*protocol:\([^ ]*\).*/\1/p')"
AVMFRITZ_protocol="${AVMFRITZ_protocol:+"${AVMFRITZ_protocol},"}$(printf "0x%x" ${p})"
let "l = $(echo ${line} | ${SED} -n 's/.*layermask:\([^ ]*\).*/\1/p')"
AVMFRITZ_layermask="${AVMFRITZ_layermask:+"${AVMFRITZ_layermask},"}$(printf "0x%x" ${l})"
;;
esac
;;
esac
done
if [ ! -z "${HFCMULTI_protocol[0]}" ]; then
tmpcmd="${MODPROBE} --ignore-install hfcmulti type=${HFCMULTI_type[0]}"
i=1
while [ ! -z "${HFCMULTI_type[${i}]}" ]; do
tmpcmd="${tmpcmd},${HFCMULTI_type[${i}]}"
let "i = ${i} + 1"
done
tmpcmd="${tmpcmd} protocol=${HFCMULTI_protocol[0]}"
i=1
while [ ! -z "${HFCMULTI_protocol[${i}]}" ]; do
tmpcmd="${tmpcmd},${HFCMULTI_protocol[${i}]}"
let "i = ${i} + 1"
done
tmpcmd="${tmpcmd} layermask=${HFCMULTI_layermask[0]}"
i=1
while [ ! -z "${HFCMULTI_layermask[${i}]}" ]; do
tmpcmd="${tmpcmd},${HFCMULTI_layermask[${i}]}"
let "i = ${i} + 1"
done
START_COMMANDS[${#START_COMMANDS[@]}]="${tmpcmd} ${HFCMULTI_options}"
fi
if [ ! -z "${HFCPCI_protocol}" ]; then
START_COMMANDS[${#START_COMMANDS[@]}]="${MODPROBE} --ignore-install hfcpci protocol=${HFCPCI_protocol} layermask=${HFCPCI_layermask}"
fi
if [ ! -z "${AVMFRITZ_protocol}" ]; then
START_COMMANDS[${#START_COMMANDS[@]}]="${MODPROBE} --ignore-install avmfritz protocol=${AVMFRITZ_protocol} layermask=${AVMFRITZ_layermask}"
fi
START_COMMANDS[${#START_COMMANDS[@]}]="${MODPROBE} --ignore-install mISDN_dsp ${MISDNDSP_options}"
}
function run_start_commands
{
local i=0
echo "-- Loading mISDN modules --"
while [ ! -z "${START_COMMANDS[${i}]}" ]; do
echo ">> ${START_COMMANDS[${i}]}"
eval "${START_COMMANDS[${i}]}"
let "i = ${i} + 1"
done
}
function run_stop_commands
{
local mod i=0
for mod in $(lsmod | ${SED} -ne '/Module/!{s/\([^ ]*\).*/\1/;p}'); do
case "${mod}" in
mISDN_capi | mISDN_dsp | l3udss1 | mISDN_l2 | mISDN_l1 | mISDN_isac | hfcmulti | avmfritz)
STOP_COMMANDS[0]="${STOP_COMMANDS[0]:-"${MODPROBE} -r --ignore-remove"} ${mod}"
;;
mISDN_core)
STOP_COMMANDS[1]="${MODPROBE} -r --ignore-remove mISDN_core"
;;
esac
done
echo "-- Unloading mISDN modules --"
while [ ! -z "${STOP_COMMANDS[${i}]}" ]; do
echo ">> ${STOP_COMMANDS[${i}]}"
eval "${STOP_COMMANDS[${i}]}"
let "i = ${i} + 1"
done
}
function scan_devices
{
local skipnext=0 IFS=$'\n'
local NL="
"
function addcard {
SCAN_card[${#SCAN_card[@]}]="${1}"
SCAN_opts[${#SCAN_opts[@]}]="${2}"
SCAN_num_ports[${#SCAN_num_ports[@]}]="${3}"
SCAN_port_opts[${#SCAN_port_opts[@]}]="${4}"
}
for line in $(${LSPCI} -n -d 0xd161:b410); do
addcard "BN4S0" "" 4 'mode="te" link="ptmp"'
done
for line in $(${LSPCI} -n | ${SED} -n 's/^\(0000:\|\)\([0-9a-f]\{2\}:[0-9a-f]\{2\}.[0-9a-f]\{1\}\)\( Class \| \)[0-9a-f]\{4\}: 1397:\([0-9a-f]\{4\}\).*$/\4 \2/p'); do
if [ ${skipnext} -eq 1 ]; then
skipnext=0
continue
fi
case "${line}" in
30b1*)
case "${line:5}" in
00*)
addcard "BN1E1" "" 1 'mode="nt" link="ptp"'
;;
*)
if [ $(${LSPCI} -n -s "${line:5:3}" | ${WC} -l) -eq 2 ]; then
addcard "BN2E1" "" 2 'mode="nt" link="ptp"'
skipnext=1
else
addcard "BN1E1" "" 1 'mode="nt" link="ptp"'
fi
;;
esac
;;
16b8*)
addcard "BN8S0" "" 8 'mode="te" link="ptmp"'
;;
08b4*)
if ${LSPCI} -n -v -s "${line:5}" | ${GREP} "Subsystem" | ${GREP} "1397:b567" > /dev/null ; then
addcard "BN1S0" "" 1 'mode="te" link="ptmp"'
elif ${LSPCI} -n -v -s "${line:5}" | ${GREP} "Subsystem" | ${GREP} "1397:b566\|1397:b569" > /dev/null ; then
addcard "BN2S0" "" 2 'mode="te" link="ptmp"'
else
addcard "BN4S0" "" 4 'mode="te" link="ptmp"'
fi
;;
esac
done
for line in $(${LSPCI} -n | ${GREP} "1397:\(2bd\(0\|6\|7\|8\|9\|a\|b\|c\)\|b100\)\|1043:0675\|0871:ffa\(1\|2\)\|1051:0100\|15b0:2bd0\|114f:007\(0\|1\|2\|3\)\|13d1:2bd1\|182d:3069"); do
addcard "hfcpci" "" 1 'mode="te" link="ptmp"'
done
for line in $(${LSPCI} -n | ${GREP} "1244:\(0a00\|0e00\)"); do
addcard "avmfritz" "" 1 'mode="te" link="ptmp"'
done
for line in $(${LSPCI} -n -d 1050:6692); do
addcard "w6692pci" "" 1 'mode="te" link="ptmp"'
done
if [ -e ${LSUSB} ]; then
for line in $(${LSUSB} | ${GREP} "0959:2bd0\|0675:1688\|07b0:0007\|0742:200\(7\|8\|9\|A\)\|08e3:0301\|07fa:084\(7\|8\)\|07ba:0006"); do
addcard "hfcsusb" "" 1 'mode="te" link="ptmp"'
done
fi
}
function write_mISDN_conf
{
local NL="
"
local TAB=" "
local HEADER="<?xml version=\"1.0\"?>
<!--
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Card Type: BN2S0, BN4S0, BN8S0
Card Attributes: ulaw=(yes|no), dtmf=(yes|no), pcm_slave=(yes|no),
ignore_pcm_frameclock=(yes|no), rxclock=(yes|no),
crystalclock=(yes|no), watchdog=(yes|no)
Port Attributes: mode=(te|nt), link=(ptp|ptmp), master-clock=(yes|no),
capi=(yes|no)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Card Type: BN2E1
Card Attributes: ulaw=(yes|no), dtmf=(yes|no), pcm_slave=(yes|no),
ignore_pcm_frameclock=(yes|no), rxclock=(yes|no),
crystalclock=(yes|no), watchdog=(yes|no)
Port Attributes: mode=(te|nt), link=(ptp|ptmp), optical=(yes|no), los=(yes|no),
ais=(yes|no), slip=(yes|no), nocrc4=(yes|no), capi=(yes|no)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Card Type: hfcmulti, avmfritz, w6692pci
Port Attributes: mode=(te|nt), link=(ptp|ptmp), capi=(yes|no)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Module: hfcmulti
Options: poll=<number>, pcm=<number>, debug=<number>, timer=(yes|no)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Module: mISDN_dsp
Options: debug=<number>, options=<number>, poll=<number>,
dtmfthreshold=<number>
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-->
<mISDNconf>
${TAB}<module poll=\"128\" debug=\"0\" timer=\"no\">hfcmulti</module>
${TAB}<module debug=\"0\" options=\"0\">mISDN_dsp</module>
${TAB}<devnode user=\"root\" group=\"root\" mode=\"644\">mISDN</devnode>"
local FOOTER="</mISDNconf>"
local i=0 j=0 MAIN=""
echo "Writing ${MISDN_CONF} for ${#SCAN_card[@]} mISDN compatible device(s):"
while [ ! -z "${SCAN_card[${i}]}" ]; do
echo ">> ${SCAN_card[${i}]}"
MAIN="${MAIN}${NL}${TAB}<card type=\"${SCAN_card[${i}]}\"${SCAN_opts[${i}]:+" ${SCAN_opts[${i}]}"}>"
j=1
while [ ${j} -le ${SCAN_num_ports[${i}]} ]; do
MAIN="${MAIN}${NL}${TAB}${TAB}<port${SCAN_port_opts[${i}]:+" ${SCAN_port_opts[${i}]}"}>${j}</port>"
let "j = ${j} + 1"
done
MAIN="${MAIN}${NL}${TAB}</card>"
let "i = ${i} + 1"
done
if [ -f ${MISDN_CONF} ]; then
echo "${MISDN_CONF} already present, saving a backup: ${MISDN_CONF}.bak"
${CP} "${MISDN_CONF}" "${MISDN_CONF}.bak" || die "Could not backup your existing ${MISDN_CONF}!"
fi
echo "${HEADER}${MAIN}${NL}${FOOTER}" > ${MISDN_CONF}
}
function print_scan_results
{
local i=0
echo "${#SCAN_card[@]} mISDN compatible device(s) found:"
while [ ! -z "${SCAN_card[${i}]}" ]; do
echo ">> ${SCAN_card[${i}]}"
let "i = ${i} + 1"
done
}
function mk_misdn_dev
{
if [ ! -e /dev/mISDN ]; then
echo "creating device node: /dev/mISDN"
${MKNOD} /dev/mISDN c 46 0
fi
${CHOWN} ${DEVNODE_user}:${DEVNODE_group} /dev/mISDN
${CHMOD} ${DEVNODE_mode} /dev/mISDN
}
#
# MAIN
#
case "${1}" in
start|--start)
check_misdn_conf
parse_config
run_start_commands
mk_misdn_dev
;;
stop|--stop)
run_stop_commands
;;
restart|--restart)
check_misdn_conf
parse_config
run_stop_commands
${SLEEP} 2
run_start_commands
mk_misdn_dev
;;
config|--config)
scan_devices
write_mISDN_conf
;;
scan|--scan)
scan_devices
print_scan_results
;;
help|--help)
echo "${USAGE}"
exit 0
;;
*)
echo "${USAGE}"
exit 2
;;
esac

13
config/mISDN.conf Normal file
View File

@ -0,0 +1,13 @@
<?xml version="1.0"?>
<mISDNconf>
<card type="BN8S0">
<port mode="nt" link="ptmp">1</port>
<port mode="nt" link="ptmp">2</port>
<port mode="te" link="ptmp">3</port>
<port mode="te" link="ptmp">4</port>
<port mode="nt" link="ptmp">5</port>
<port mode="nt" link="ptmp">6</port>
<port mode="te" link="ptmp">7</port>
<port mode="te" link="ptmp">8</port>
</card>
</mISDNconf>

230
config/mISDN.conf.bnx.xsl Normal file
View File

@ -0,0 +1,230 @@
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" version="1.0" encoding="UTF-8" indent="yes"/>
<!--
Card Type: BN2S0, BN4S0, BN8S0
Ports: 2, 4, 8
Card Attributes: ulaw=(yes|no), dtmf=(yes|no), pcm_slave=(yes|no), ignore_pcm_frameclock=(yes|no),
rxclock=(yes|no), crystalclock=(yes|no), watchdog=(yes|no)
Port Attributes: mode=(te|nt), link=(ptp|ptmp), master-clock=(yes|no), capi=(yes|no)
-->
<xsl:template name="type-options">
<xsl:param name="force-pcm-slave">no</xsl:param>
<xsl:call-template name="if-match">
<xsl:with-param name="val" select="@ulaw" />
<xsl:with-param name="val-true">(2**8)</xsl:with-param>
</xsl:call-template>
<xsl:text>+</xsl:text>
<xsl:call-template name="if-match">
<xsl:with-param name="val" select="@dtmf" />
<xsl:with-param name="val-true">(2**9)</xsl:with-param>
</xsl:call-template>
<xsl:text>+</xsl:text>
<xsl:choose>
<xsl:when test="$force-pcm-slave='yes'">
<xsl:text>(2**11)</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="if-match">
<xsl:with-param name="val" select="@pcm_slave" />
<xsl:with-param name="val-true">(2**11)</xsl:with-param>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
<xsl:text>+</xsl:text>
<xsl:call-template name="if-match">
<xsl:with-param name="val" select="@ignore_pcm_frameclock" />
<xsl:with-param name="val-true">(2**12)</xsl:with-param>
</xsl:call-template>
<xsl:text>+</xsl:text>
<xsl:call-template name="if-match">
<xsl:with-param name="val" select="@rxclock" />
<xsl:with-param name="val-true">(2**13)</xsl:with-param>
</xsl:call-template>
<xsl:text>+</xsl:text>
<xsl:call-template name="if-match">
<xsl:with-param name="val" select="@crystalclock" />
<xsl:with-param name="val-true">(2**18)</xsl:with-param>
</xsl:call-template>
<xsl:text>+</xsl:text>
<xsl:call-template name="if-match">
<xsl:with-param name="val" select="@watchdog" />
<xsl:with-param name="val-true">(2**19)</xsl:with-param>
</xsl:call-template>
</xsl:template>
<xsl:template name="BN2S0card">
<xsl:param name="type">4</xsl:param>
<xsl:value-of select="concat(' type:',$type,'+')" />
<xsl:call-template name="type-options" />
<xsl:text>
</xsl:text>
</xsl:template>
<xsl:template name="BN2S0port">
<xsl:text> layermask:</xsl:text>
<xsl:choose>
<xsl:when test="@mode='nt'">
<xsl:text>3</xsl:text>
</xsl:when>
<xsl:when test="@capi='yes'">
<xsl:text>0</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:text>15</xsl:text>
</xsl:otherwise>
</xsl:choose>
<xsl:text> protocol:</xsl:text>
<xsl:call-template name="if-match">
<xsl:with-param name="val" select="@mode" />
<xsl:with-param name="match-true">te</xsl:with-param>
<xsl:with-param name="match-false">nt</xsl:with-param>
<xsl:with-param name="val-true">34</xsl:with-param>
<xsl:with-param name="val-false">18</xsl:with-param>
<xsl:with-param name="val-default">34</xsl:with-param>
</xsl:call-template>
<xsl:text>+</xsl:text>
<xsl:if test="@mode!='nt'">
<xsl:call-template name="if-match">
<xsl:with-param name="val" select="@link" />
<xsl:with-param name="match-true">ptp</xsl:with-param>
<xsl:with-param name="match-false">ptmp</xsl:with-param>
<xsl:with-param name="val-true">0</xsl:with-param>
<xsl:with-param name="val-false">(-32)</xsl:with-param>
<xsl:with-param name="val-default">(-32)</xsl:with-param>
</xsl:call-template>
<xsl:text>+</xsl:text>
</xsl:if>
<xsl:call-template name="if-match">
<xsl:with-param name="val" select="@master-clock" />
<xsl:with-param name="val-true">(2**16)</xsl:with-param>
</xsl:call-template>
<xsl:text> capi:</xsl:text>
<xsl:call-template name="if-match">
<xsl:with-param name="val" select="@capi" />
<xsl:with-param name="val-true">yes</xsl:with-param>
<xsl:with-param name="val-false">no</xsl:with-param>
<xsl:with-param name="val-default">no</xsl:with-param>
</xsl:call-template>
<xsl:text>
</xsl:text>
</xsl:template>
<xsl:template name="BN4S0card">
<xsl:call-template name="BN2S0card">
<xsl:with-param name="type">4</xsl:with-param>
</xsl:call-template>
</xsl:template>
<xsl:template name="BN4S0port">
<xsl:call-template name="BN2S0port" />
</xsl:template>
<xsl:template name="BN8S0card">
<xsl:call-template name="BN2S0card">
<xsl:with-param name="type">8</xsl:with-param>
</xsl:call-template>
</xsl:template>
<xsl:template name="BN8S0port">
<xsl:call-template name="BN2S0port" />
</xsl:template>
<!--
Card Type: BN2E1
Ports: 2
Card Attributes: ulaw=(yes|no), dtmf=(yes|no), pcm_slave=(yes|no), ignore_pcm_frameclock=(yes|no),
rxclock=(yes|no), crystalclock=(yes|no), watchdog=(yes|no)
Port Attributes: mode=(te|nt), link=(ptp|ptmp), optical=(yes|no), los=(yes|no), ais=(yes|no),
slip=(yes|no), nocrc4=(yes|no), capi=(yes|no)
-->
<xsl:template name="BN2E1card">
<xsl:text> type:1+</xsl:text>
<xsl:call-template name="type-options" />
<xsl:text>,1+</xsl:text>
<xsl:call-template name="type-options">
<xsl:with-param name="force-pcm-slave">yes</xsl:with-param>
</xsl:call-template>
<xsl:text>
</xsl:text>
</xsl:template>
<xsl:template name="BN2E1port">
<xsl:text> layermask:</xsl:text>
<xsl:choose>
<xsl:when test="@mode='nt'">
<xsl:text>3</xsl:text>
</xsl:when>
<xsl:when test="@capi='yes'">
<xsl:text>0</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:text>15</xsl:text>
</xsl:otherwise>
</xsl:choose>
<xsl:text> protocol:</xsl:text>
<xsl:call-template name="if-match">
<xsl:with-param name="val" select="@mode" />
<xsl:with-param name="match-true">te</xsl:with-param>
<xsl:with-param name="match-false">nt</xsl:with-param>
<xsl:with-param name="val-true">34</xsl:with-param>
<xsl:with-param name="val-false">18</xsl:with-param>
<xsl:with-param name="val-default">34</xsl:with-param>
</xsl:call-template>
<xsl:text>+</xsl:text>
<xsl:if test="@mode!='nt'">
<xsl:call-template name="if-match">
<xsl:with-param name="val" select="@link" />
<xsl:with-param name="match-true">ptp</xsl:with-param>
<xsl:with-param name="match-false">ptmp</xsl:with-param>
<xsl:with-param name="val-true">0</xsl:with-param>
<xsl:with-param name="val-false">(-32)</xsl:with-param>
<xsl:with-param name="val-default">(-32)</xsl:with-param>
</xsl:call-template>
<xsl:text>+</xsl:text>
</xsl:if>
<xsl:call-template name="if-match">
<xsl:with-param name="val" select="@optical" />
<xsl:with-param name="val-true">(2**16)</xsl:with-param>
</xsl:call-template>
<xsl:text>+</xsl:text>
<xsl:call-template name="if-match">
<xsl:with-param name="val" select="@los" />
<xsl:with-param name="val-true">(2**18)</xsl:with-param>
</xsl:call-template>
<xsl:text>+</xsl:text>
<xsl:call-template name="if-match">
<xsl:with-param name="val" select="@ais" />
<xsl:with-param name="val-true">(2**19)</xsl:with-param>
</xsl:call-template>
<xsl:text>+</xsl:text>
<xsl:call-template name="if-match">
<xsl:with-param name="val" select="@slip" />
<xsl:with-param name="val-true">(2**21)</xsl:with-param>
</xsl:call-template>
<xsl:text>+</xsl:text>
<xsl:call-template name="if-match">
<xsl:with-param name="val" select="@nocrc4" />
<xsl:with-param name="val-true">(2**23)</xsl:with-param>
</xsl:call-template>
<xsl:text> capi:</xsl:text>
<xsl:call-template name="if-match">
<xsl:with-param name="val" select="@capi" />
<xsl:with-param name="val-true">yes</xsl:with-param>
<xsl:with-param name="val-false">no</xsl:with-param>
<xsl:with-param name="val-default">no</xsl:with-param>
</xsl:call-template>
<xsl:text>
</xsl:text>
</xsl:template>
</xsl:stylesheet>

View File

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" version="1.0" encoding="UTF-8" indent="yes"/>
<!--
Module: hfcmulti
Options: poll=<number>, pcm=<number>, debug=<number>, timer=(yes|no)
-->
<xsl:template name="HFCMULTImodule">
<xsl:call-template name="if-set">
<xsl:with-param name="prefix"> poll=</xsl:with-param>
<xsl:with-param name="val" select="@poll" />
<xsl:with-param name="val-default">128</xsl:with-param>
</xsl:call-template>
<xsl:call-template name="if-set">
<xsl:with-param name="prefix"> pcm=</xsl:with-param>
<xsl:with-param name="val" select="@pcm" />
</xsl:call-template>
<xsl:call-template name="if-set">
<xsl:with-param name="prefix"> debug=</xsl:with-param>
<xsl:with-param name="val" select="@debug" />
<xsl:with-param name="val-default">0</xsl:with-param>
</xsl:call-template>
<xsl:call-template name="if-set-match">
<xsl:with-param name="prefix"> timer=</xsl:with-param>
<xsl:with-param name="val" select="@timer" />
<xsl:with-param name="val-default">0</xsl:with-param>
<xsl:with-param name="val-true">1</xsl:with-param>
</xsl:call-template>
<xsl:text>
</xsl:text>
</xsl:template>
</xsl:stylesheet>

64
config/mISDN.conf.inc.xsl Normal file
View File

@ -0,0 +1,64 @@
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template name="if-set">
<xsl:param name="prefix"></xsl:param>
<xsl:param name="val"></xsl:param>
<xsl:param name="val-default"></xsl:param>
<xsl:choose>
<xsl:when test="$val!=''">
<xsl:value-of select="concat($prefix,$val)" />
</xsl:when>
<xsl:otherwise>
<xsl:if test="$val-default!=''">
<xsl:value-of select="concat($prefix,$val-default)" />
</xsl:if>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="if-set-match">
<xsl:param name="prefix"></xsl:param>
<xsl:param name="val"></xsl:param>
<xsl:param name="val-default"></xsl:param>
<xsl:param name="val-true">0</xsl:param>
<xsl:param name="val-false">0</xsl:param>
<xsl:param name="match-true">yes</xsl:param>
<xsl:param name="match-false">no</xsl:param>
<xsl:choose>
<xsl:when test="$val=$match-true">
<xsl:value-of select="concat($prefix,$val-true)" />
</xsl:when>
<xsl:when test="$val=$match-false">
<xsl:value-of select="concat($prefix,$val-false)" />
</xsl:when>
<xsl:otherwise>
<xsl:if test="$val-default!=''">
<xsl:value-of select="concat($prefix,$val-default)" />
</xsl:if>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="if-match">
<xsl:param name="val">no</xsl:param>
<xsl:param name="val-default">0</xsl:param>
<xsl:param name="val-true">0</xsl:param>
<xsl:param name="val-false">0</xsl:param>
<xsl:param name="match-true">yes</xsl:param>
<xsl:param name="match-false">no</xsl:param>
<xsl:choose>
<xsl:when test="$val=$match-true">
<xsl:value-of select="$val-true" />
</xsl:when>
<xsl:when test="$val=$match-false">
<xsl:value-of select="$val-false" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$val-default" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>

View File

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" version="1.0" encoding="UTF-8" indent="yes"/>
<!--
Module: mISDN_dsp
Options: debug=<number>, options=<number>, poll=<number>, dtmfthreshold=<number>
-->
<xsl:template name="MISDNDSPmodule">
<xsl:call-template name="if-set">
<xsl:with-param name="prefix"> debug=</xsl:with-param>
<xsl:with-param name="val" select="@debug" />
<xsl:with-param name="val-default">0</xsl:with-param>
</xsl:call-template>
<xsl:call-template name="if-set">
<xsl:with-param name="prefix"> options=</xsl:with-param>
<xsl:with-param name="val" select="@options" />
<xsl:with-param name="val-default">0</xsl:with-param>
</xsl:call-template>
<xsl:call-template name="if-set">
<xsl:with-param name="prefix"> poll=</xsl:with-param>
<xsl:with-param name="val" select="@poll" />
</xsl:call-template>
<xsl:call-template name="if-set">
<xsl:with-param name="prefix"> dtmfthreshold=</xsl:with-param>
<xsl:with-param name="val" select="@dtmfthreshold" />
</xsl:call-template>
<xsl:text>
</xsl:text>
</xsl:template>
</xsl:stylesheet>

View File

@ -0,0 +1,62 @@
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" version="1.0" encoding="UTF-8" indent="yes"/>
<!--
Card Type: hfcmulti, avmfritz, w6692pci
Ports: 1
Port Attributes: mode=(te|nt), link=(ptp|ptmp), capi=(yes|no)
-->
<xsl:template name="singlepcicard">
<xsl:text>
</xsl:text>
</xsl:template>
<xsl:template name="singlepciport">
<xsl:text> layermask:</xsl:text>
<xsl:choose>
<xsl:when test="@mode='nt'">
<xsl:text>3</xsl:text>
</xsl:when>
<xsl:when test="@capi='yes'">
<xsl:text>0</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:text>15</xsl:text>
</xsl:otherwise>
</xsl:choose>
<xsl:text> protocol:</xsl:text>
<xsl:call-template name="if-match">
<xsl:with-param name="val" select="@mode" />
<xsl:with-param name="match-true">te</xsl:with-param>
<xsl:with-param name="match-false">nt</xsl:with-param>
<xsl:with-param name="val-true">34</xsl:with-param>
<xsl:with-param name="val-false">18</xsl:with-param>
<xsl:with-param name="val-default">34</xsl:with-param>
</xsl:call-template>
<xsl:if test="@mode!='nt'">
<xsl:text>+</xsl:text>
<xsl:call-template name="if-match">
<xsl:with-param name="val" select="@link" />
<xsl:with-param name="match-true">ptp</xsl:with-param>
<xsl:with-param name="match-false">ptmp</xsl:with-param>
<xsl:with-param name="val-true">0</xsl:with-param>
<xsl:with-param name="val-false">(-32)</xsl:with-param>
<xsl:with-param name="val-default">(-32)</xsl:with-param>
</xsl:call-template>
</xsl:if>
<xsl:text> capi:</xsl:text>
<xsl:call-template name="if-match">
<xsl:with-param name="val" select="@capi" />
<xsl:with-param name="val-true">yes</xsl:with-param>
<xsl:with-param name="val-false">no</xsl:with-param>
<xsl:with-param name="val-default">no</xsl:with-param>
</xsl:call-template>
<xsl:text>
</xsl:text>
</xsl:template>
</xsl:stylesheet>

131
config/mISDN.conf.xsl Normal file
View File

@ -0,0 +1,131 @@
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:include href='mISDN.conf.inc.xsl' />
<xsl:include href='mISDN.conf.mISDN_dsp.xsl' />
<xsl:include href='mISDN.conf.hfcmulti.xsl' />
<xsl:include href='mISDN.conf.bnx.xsl' />
<xsl:include href='mISDN.conf.singlepci.xsl' />
<!--
Main mISDNconf Template
-->
<xsl:template match="mISDNconf">
<!-- module -->
<xsl:for-each select="module">
<xsl:choose>
<xsl:when test=".='hfcmulti'">
<xsl:value-of select="concat('MODULE:',.)" />
<xsl:call-template name="HFCMULTImodule" />
</xsl:when>
<xsl:when test=".='mISDN_dsp'">
<xsl:value-of select="concat('MODULE:',.)" />
<xsl:call-template name="MISDNDSPmodule" />
</xsl:when>
</xsl:choose>
</xsl:for-each>
<!-- devnode -->
<xsl:for-each select="devnode">
<xsl:choose>
<xsl:when test=".='mISDN'">
<xsl:value-of select="concat('DEVNODE:',.)" />
<xsl:call-template name="if-set">
<xsl:with-param name="prefix"> user:</xsl:with-param>
<xsl:with-param name="val" select="@user" />
<xsl:with-param name="val-default">root</xsl:with-param>
</xsl:call-template>
<xsl:call-template name="if-set">
<xsl:with-param name="prefix"> group:</xsl:with-param>
<xsl:with-param name="val" select="@group" />
<xsl:with-param name="val-default">root</xsl:with-param>
</xsl:call-template>
<xsl:call-template name="if-set">
<xsl:with-param name="prefix"> mode:</xsl:with-param>
<xsl:with-param name="val" select="@mode" />
<xsl:with-param name="val-default">644</xsl:with-param>
</xsl:call-template>
</xsl:when>
</xsl:choose>
<xsl:text>
</xsl:text>
</xsl:for-each>
<!-- card, port -->
<xsl:for-each select="card">
<xsl:choose>
<xsl:when test="@type='BN2S0'">
<xsl:value-of select="concat('CARD:',@type)" />
<xsl:call-template name="BN2S0card" />
<xsl:for-each select="port">
<xsl:sort data-type="number" />
<xsl:text>PORT:</xsl:text>
<xsl:value-of select="." />
<xsl:call-template name="BN2S0port" />
</xsl:for-each>
</xsl:when>
<xsl:when test="@type='BN4S0'">
<xsl:value-of select="concat('CARD:',@type)" />
<xsl:call-template name="BN4S0card" />
<xsl:for-each select="port">
<xsl:sort data-type="number" />
<xsl:text>PORT:</xsl:text>
<xsl:value-of select="." />
<xsl:call-template name="BN4S0port" />
</xsl:for-each>
</xsl:when>
<xsl:when test="@type='BN8S0'">
<xsl:value-of select="concat('CARD:',@type)" />
<xsl:call-template name="BN8S0card" />
<xsl:for-each select="port">
<xsl:sort data-type="number" />
<xsl:text>PORT:</xsl:text>
<xsl:value-of select="." />
<xsl:call-template name="BN8S0port" />
</xsl:for-each>
</xsl:when>
<xsl:when test="@type='BN2E1'">
<xsl:value-of select="concat('CARD:',@type)" />
<xsl:call-template name="BN2E1card" />
<xsl:for-each select="port">
<xsl:sort data-type="number" />
<xsl:text>PORT:</xsl:text>
<xsl:value-of select="." />
<xsl:call-template name="BN2E1port" />
</xsl:for-each>
</xsl:when>
<xsl:when test="@type='hfcpci' or @type='avmfritz' or @type='w6692pci'">
<xsl:value-of select="concat('CARD:',@type)" />
<xsl:call-template name="singlepcicard" />
<xsl:for-each select="port">
<xsl:sort data-type="number" />
<xsl:text>PORT:</xsl:text>
<xsl:value-of select="." />
<xsl:call-template name="singlepciport" />
</xsl:for-each>
</xsl:when>
</xsl:choose>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

177
drivers/isdn/Config.in.v2.4 Normal file
View File

@ -0,0 +1,177 @@
#
# ISDN device configuration
#
# only included if CONFIG_ISDN != n
define_bool CONFIG_ISDN_BOOL y
if [ "$CONFIG_INET" != "n" ]; then
bool ' Support synchronous PPP' CONFIG_ISDN_PPP
if [ "$CONFIG_ISDN_PPP" != "n" ]; then
bool ' Use VJ-compression with synchronous PPP' CONFIG_ISDN_PPP_VJ
bool ' Support generic MP (RFC 1717)' CONFIG_ISDN_MPP
dep_tristate ' Support BSD compression' CONFIG_ISDN_PPP_BSDCOMP $CONFIG_ISDN
fi
fi
bool ' Support audio via ISDN' CONFIG_ISDN_AUDIO
if [ "$CONFIG_ISDN_AUDIO" != "n" ]; then
bool ' Support AT-Fax Class 1 and 2 commands' CONFIG_ISDN_TTY_FAX
fi
if [ "$CONFIG_X25" != "n" ]; then
bool ' X.25 PLP on top of ISDN' CONFIG_ISDN_X25
fi
mainmenu_option next_comment
comment 'ISDN feature submodules'
dep_tristate 'isdnloop support' CONFIG_ISDN_DRV_LOOP $CONFIG_ISDN
dep_tristate 'Support isdn diversion services' CONFIG_ISDN_DIVERSION $CONFIG_ISDN
endmenu
comment 'low-level hardware drivers'
mainmenu_option next_comment
comment 'Passive ISDN cards'
dep_tristate 'HiSax SiemensChipSet driver support' CONFIG_ISDN_DRV_HISAX $CONFIG_ISDN
if [ "$CONFIG_ISDN_DRV_HISAX" != "n" ]; then
define_bool CONFIG_ISDN_HISAX y
comment ' D-channel protocol features'
bool ' HiSax Support for EURO/DSS1' CONFIG_HISAX_EURO
if [ "$CONFIG_HISAX_EURO" != "n" ]; then
bool ' Support for german chargeinfo' CONFIG_DE_AOC
bool ' Disable sending complete' CONFIG_HISAX_NO_SENDCOMPLETE
bool ' Disable sending low layer compatibility' CONFIG_HISAX_NO_LLC
bool ' Disable keypad protocol option' CONFIG_HISAX_NO_KEYPAD
fi
bool ' HiSax Support for german 1TR6' CONFIG_HISAX_1TR6
bool ' HiSax Support for US NI1' CONFIG_HISAX_NI1
int ' Maximum number of cards supported by HiSax' CONFIG_HISAX_MAX_CARDS 8
comment ' HiSax supported cards'
if [ "$CONFIG_ISA" != "n" ]; then
bool ' Teles 16.0/8.0' CONFIG_HISAX_16_0
bool ' Teles 16.3 or PNP or PCMCIA' CONFIG_HISAX_16_3
bool ' AVM A1 (Fritz)' CONFIG_HISAX_AVM_A1
bool ' ITK ix1-micro Revision 2' CONFIG_HISAX_IX1MICROR2
bool ' ASUSCOM ISA cards' CONFIG_HISAX_ASUSCOM
bool ' TELEINT cards' CONFIG_HISAX_TELEINT
bool ' HFC-S based cards' CONFIG_HISAX_HFCS
bool ' USR Sportster internal TA' CONFIG_HISAX_SPORTSTER
bool ' MIC card' CONFIG_HISAX_MIC
bool ' Siemens I-Surf card' CONFIG_HISAX_ISURF
bool ' HST Saphir card' CONFIG_HISAX_HSTSAPHIR
fi
bool ' Teles PCI' CONFIG_HISAX_TELESPCI
bool ' Teles S0Box' CONFIG_HISAX_S0BOX
bool ' AVM PnP/PCI (Fritz!PnP/PCI)' CONFIG_HISAX_FRITZPCI
bool ' AVM A1 PCMCIA (Fritz)' CONFIG_HISAX_AVM_A1_PCMCIA
bool ' Elsa cards' CONFIG_HISAX_ELSA
bool ' Eicon.Diehl Diva cards' CONFIG_HISAX_DIEHLDIVA
bool ' Sedlbauer cards' CONFIG_HISAX_SEDLBAUER
bool ' NETjet card' CONFIG_HISAX_NETJET
bool ' NETspider U card' CONFIG_HISAX_NETJET_U
bool ' Niccy PnP/PCI card' CONFIG_HISAX_NICCY
bool ' Telekom A4T card' CONFIG_HISAX_BKM_A4T
bool ' Scitel Quadro card' CONFIG_HISAX_SCT_QUADRO
bool ' Gazel cards' CONFIG_HISAX_GAZEL
bool ' HFC PCI-Bus cards' CONFIG_HISAX_HFC_PCI
bool ' Winbond W6692 based cards' CONFIG_HISAX_W6692
bool ' HFC-S+, HFC-SP, HFC-PCMCIA cards' CONFIG_HISAX_HFC_SX
if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
# bool ' TESTEMULATOR (EXPERIMENTAL)' CONFIG_HISAX_TESTEMU
bool ' Formula-n enter:now PCI card' CONFIG_HISAX_ENTERNOW_PCI
if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
bool ' Am7930' CONFIG_HISAX_AMD7930
fi
fi
bool ' HiSax debugging' CONFIG_HISAX_DEBUG
dep_tristate 'Sedlbauer PCMCIA cards' CONFIG_HISAX_SEDLBAUER_CS $CONFIG_ISDN_DRV_HISAX $CONFIG_PCMCIA
dep_tristate 'ELSA PCMCIA MicroLink cards' CONFIG_HISAX_ELSA_CS $CONFIG_ISDN_DRV_HISAX $CONFIG_PCMCIA
dep_tristate 'AVM A1 PCMCIA cards' CONFIG_HISAX_AVM_A1_CS $CONFIG_ISDN_DRV_HISAX $CONFIG_PCMCIA $CONFIG_HISAX_AVM_A1_PCMCIA
dep_tristate 'ST5481 USB ISDN modem (EXPERIMENTAL)' CONFIG_HISAX_ST5481 $CONFIG_ISDN_DRV_HISAX $CONFIG_EXPERIMENTAL
dep_tristate 'AVM Fritz!Card PCI/PCIv2/PnP support (EXPERIMENTAL)' CONFIG_HISAX_FRITZ_PCIPNP $CONFIG_ISDN_DRV_HISAX $CONFIG_EXPERIMENTAL
dep_tristate 'Auerswald devices ISDN support' CONFIG_USB_AUERISDN $CONFIG_ISDN_DRV_HISAX
fi
endmenu
### Active ISDN cards
mainmenu_option next_comment
comment 'Active ISDN cards'
dep_tristate 'ICN 2B and 4B support' CONFIG_ISDN_DRV_ICN $CONFIG_ISDN
dep_tristate 'PCBIT-D support' CONFIG_ISDN_DRV_PCBIT $CONFIG_ISDN
dep_tristate 'Spellcaster support' CONFIG_ISDN_DRV_SC $CONFIG_ISDN
dep_tristate 'IBM Active 2000 support' CONFIG_ISDN_DRV_ACT2000 $CONFIG_ISDN
bool 'Eicon active card support' CONFIG_ISDN_DRV_EICON
if [ "$CONFIG_ISDN_DRV_EICON" != "n" ]; then
if [ "$CONFIG_ISDN_DRV_EICON_OLD" != "y" ]; then
dep_tristate ' Build Eicon driver type standalone' CONFIG_ISDN_DRV_EICON_DIVAS $CONFIG_ISDN $CONFIG_PCI
fi
if [ "$CONFIG_ISDN_DRV_EICON_DIVAS" != "y" ]; then
dep_tristate ' Legacy Eicon driver' CONFIG_ISDN_DRV_EICON_OLD $CONFIG_ISDN
if [ "$CONFIG_ISDN_DRV_EICON_OLD" != "n" ]; then
dep_bool ' Eicon PCI DIVA Server BRI/PRI/4BRI support' CONFIG_ISDN_DRV_EICON_PCI $CONFIG_PCI
bool ' Eicon S,SX,SCOM,Quadro,S2M support' CONFIG_ISDN_DRV_EICON_ISA
fi
fi
fi
if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
dep_tristate 'Auvertech TurboPAM support' CONFIG_ISDN_DRV_TPAM $CONFIG_ISDN $CONFIG_PCI
fi
# CAPI subsystem
tristate 'CAPI2.0 support' CONFIG_ISDN_CAPI
if [ "$CONFIG_ISDN_CAPI" != "n" ]; then
bool ' Verbose reason code reporting (kernel size +=7K)' CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON
dep_bool ' CAPI2.0 Middleware support (EXPERIMENTAL)' CONFIG_ISDN_CAPI_MIDDLEWARE $CONFIG_EXPERIMENTAL
dep_tristate ' CAPI2.0 /dev/capi support' CONFIG_ISDN_CAPI_CAPI20 $CONFIG_ISDN_CAPI
if [ "$CONFIG_ISDN_CAPI_MIDDLEWARE" = "y" ]; then
dep_mbool ' CAPI2.0 filesystem support' CONFIG_ISDN_CAPI_CAPIFS_BOOL $CONFIG_ISDN_CAPI_CAPI20
if [ "$CONFIG_ISDN_CAPI_CAPIFS_BOOL" = "y" ]; then
define_tristate CONFIG_ISDN_CAPI_CAPIFS $CONFIG_ISDN_CAPI_CAPI20
else
define_tristate CONFIG_ISDN_CAPI_CAPIFS n
fi
fi
dep_tristate ' CAPI2.0 capidrv interface support' CONFIG_ISDN_CAPI_CAPIDRV $CONFIG_ISDN_CAPI $CONFIG_ISDN
fi
# CAPI drivers
if [ "$CONFIG_ISDN_CAPI" != "n" ]; then
dep_tristate ' AVM B1 ISA support' CONFIG_ISDN_DRV_AVMB1_B1ISA $CONFIG_ISDN_CAPI
dep_tristate ' AVM B1 PCI support' CONFIG_ISDN_DRV_AVMB1_B1PCI $CONFIG_ISDN_CAPI $CONFIG_PCI
dep_mbool ' AVM B1 PCI V4 support' CONFIG_ISDN_DRV_AVMB1_B1PCIV4 $CONFIG_ISDN_DRV_AVMB1_B1PCI
dep_tristate ' AVM T1/T1-B ISA support' CONFIG_ISDN_DRV_AVMB1_T1ISA $CONFIG_ISDN_CAPI
dep_tristate ' AVM B1/M1/M2 PCMCIA support' CONFIG_ISDN_DRV_AVMB1_B1PCMCIA $CONFIG_ISDN_CAPI
dep_tristate ' AVM B1/M1/M2 PCMCIA cs module' CONFIG_ISDN_DRV_AVMB1_AVM_CS $CONFIG_ISDN_DRV_AVMB1_B1PCMCIA $CONFIG_PCMCIA
dep_tristate ' AVM T1/T1-B PCI support' CONFIG_ISDN_DRV_AVMB1_T1PCI $CONFIG_ISDN_CAPI $CONFIG_PCI
dep_tristate ' AVM C4/C2 support' CONFIG_ISDN_DRV_AVMB1_C4 $CONFIG_ISDN_CAPI $CONFIG_PCI
fi
# HYSDN
dep_tristate ' Hypercope HYSDN cards (Champ, Ergo, Metro) support (module only)' CONFIG_HYSDN m $CONFIG_PROC_FS
dep_mbool ' HYSDN CAPI 2.0 support' CONFIG_HYSDN_CAPI $CONFIG_HYSDN $CONFIG_ISDN_CAPI
endmenu
mainmenu_option next_comment
comment 'modular ISDN driver'
dep_tristate ' mISDN support' CONFIG_MISDN_DRV $CONFIG_ISDN_CAPI
if [ "$CONFIG_MISDN_DRV" != "n" ]; then
comment ' mISDN supported cards'
bool ' AVM Fritz PCI and ISA PnP cards' CONFIG_MISDN_AVM_FRITZ
bool ' Cologne Chip Design HFC PCI cards' CONFIG_MISDN_HFCPCI
bool ' Cologne Chip Design HFC multiport cards' CONFIG_MISDN_HFCMULTI
bool ' Sedlbauer Speedfax + cards' CONFIG_MISDN_SPEEDFAX
bool ' Winbond W6692 cards' CONFIG_MISDN_W6692
comment ' mISDN supported features'
bool ' mISDN audio DSP module' CONFIG_MISDN_DSP
bool ' mISDN memory leak debug' CONFIG_MISDN_MEMDEBUG
fi
endmenu

View File

@ -0,0 +1,58 @@
# Makefile for the kernel ISDN subsystem and device drivers.
# The target object and module list name.
O_TARGET := vmlinux-obj.o
# Objects that export symbols.
export-objs := isdn_common.o
# Multipart objects.
list-multi := isdn.o
isdn-objs := isdn_net.o isdn_tty.o isdn_v110.o isdn_common.o
# Optional parts of multipart objects.
isdn-objs-$(CONFIG_ISDN_PPP) += isdn_ppp.o
isdn-objs-$(CONFIG_ISDN_X25) += isdn_concap.o isdn_x25iface.o
isdn-objs-$(CONFIG_ISDN_AUDIO) += isdn_audio.o
isdn-objs-$(CONFIG_ISDN_TTY_FAX) += isdn_ttyfax.o
isdn-objs-$(CONFIG_ISDN_WITH_ABC) += isdn_dwabc.o
isdn-objs += $(isdn-objs-y)
# Ordering constraints: isdn.o first, rest doesn't matter
# Each configuration option enables a list of files.
obj-$(CONFIG_ISDN) += isdn.o
obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o
# Object files in subdirectories
mod-subdirs := avmb1 eicon hisax
subdir-$(CONFIG_ISDN_DIVERSION) += divert
subdir-$(CONFIG_ISDN_HISAX) += hisax
subdir-$(CONFIG_ISDN_DRV_ICN) += icn
subdir-$(CONFIG_ISDN_DRV_PCBIT) += pcbit
subdir-$(CONFIG_ISDN_DRV_SC) += sc
subdir-$(CONFIG_ISDN_CAPI) += avmb1
subdir-$(CONFIG_ISDN_DRV_LOOP) += isdnloop
subdir-$(CONFIG_ISDN_DRV_ACT2000) += act2000
subdir-$(CONFIG_ISDN_DRV_EICON) += eicon
subdir-$(CONFIG_HYSDN) += hysdn
subdir-$(CONFIG_ISDN_DRV_TPAM) += tpam
subdir-$(CONFIG_MISDN_DRV) += hardware/mISDN
obj-y += $(addsuffix /vmlinux-obj.o, $(subdir-y))
# The global Rules.make.
include $(TOPDIR)/Rules.make
# Link rules for multi-part drivers.
isdn.o: $(isdn-objs)
$(LD) -r -o $@ $(isdn-objs)

View File

@ -0,0 +1,12 @@
#
# ISDN hardware drivers
#
comment "CAPI hardware drivers"
depends on NET && ISDN && ISDN_CAPI
source "drivers/isdn/hardware/avm/Kconfig"
source "drivers/isdn/hardware/eicon/Kconfig"
source "drivers/isdn/hardware/mISDN/Kconfig"

View File

@ -0,0 +1,7 @@
# Makefile for the CAPI hardware drivers
# Object files in subdirectories
obj-$(CONFIG_CAPI_AVM) += avm/
obj-$(CONFIG_CAPI_EICON) += eicon/
obj-$(CONFIG_MISDN_DRV) += mISDN/

View File

@ -0,0 +1,141 @@
#
# modularer ISDN driver
#
menu "Modular ISDN driver"
depends on NET && ISDN && ISDN_CAPI!=n
config MISDN_DRV
tristate "Support modular ISDN driver"
help
Enable support for the modular ISDN driver.
This driver is the successor of the famous HiSax driver.
if MISDN_DRV!=n
config MISDN_MEMDEBUG
bool "Enable memory leak debug for mISDN"
help
This option is for watching the use of several resources in mISDN.
It includes extra code to maintain list of allocated memory and
sk_buffs. On module unload you can see not freed resources an
their allocation orging and some object specific informations.
If unsure, say 'N'.
config MISDN_AVM_FRITZ
bool "Support for AVM Fritz!Cards"
depends on PCI || ISA
help
Enable support for AVM Fritz!Card PCI and PnP.
config MISDN_NETJET
bool "Support for NETJet cards"
depends on PCI
help
Enable support for Traverse Technologies' NETJet PCI cards.
config MISDN_HFCPCI
bool "Support for HFC PCI cards"
depends on PCI
help
Enable support for card with Cologne Chips Design HFC PCI based
cards.
config MISDN_HFCMULTI
bool "Support for HFC multiport cards (HFC-4S/8S/E1)"
depends on PCI
help
Enable support for card with Cologne Chip AG's HFC multiport
chip. There are three types of chips that are quite similar,
but the interface is different:
* HFC-4S (4 S/T interfaces on one chip)
* HFC-8S (8 S/T interfaces on one chip)
* HFC-E1 (E1 interface for 2Mbit ISDN)
if MISDN_HFCMULTI!=n
config HFCMULTI_PCIMEM
bool "HFC multiport driver with memory mapped IO"
depends on PCI
help
Use memory mapped PCI access rather than IO access.
This feature MIGHT be slightly faster, especially when
using hardware DTMF detection. Also it may cause trouble with some
PCI bridges.
If unsure, say 'N'.
endif
config MISDN_HFCUSB
bool "Support for HFC-S USB based TAs"
depends on USB && EXPERIMENTAL
help
Enable support for USB ISDN TAs with Cologne Chip AG's
HFC-S USB ISDN Controller
config MISDN_HFCMINI
bool "Support for 'HFC-S mini' based TAs"
depends on PCI
help
Enable support for Cologne Chip AG's 'HFC-S mini' Evaluation Card
config MISDN_XHFC
bool "Support for XHFC based cards"
depends on PCI
help
Enable support for Cologne Chips AG's XHFC Evaluation Card
config MISDN_SPEEDFAX
bool "Support for Sedlbauer Speedfax+"
depends on PCI || ISA
help
Enable support for Sedlbauer Speedfax+.
config MISDN_W6692
bool "Support for Winbond 6692 based cards"
depends on PCI
help
Enable support for Winbond 6692 PCI chip based cards.
config MISDN_DSP
bool "Digital Audio Processing of transparent data"
help
Enable support for digital audio processing capability.
This module may be used for special applications that require
cross connecting of bchannels, conferencing, dtmf decoding
echo cancelation, tone generation, and Blowfish encryption and
decryption.
It may use hardware features if available.
E.g. it is required for PBX4Linux. Go to http://isdn.eversberg.eu
and get more informations about this module and it's usage.
If unsure, say 'N'.
config MISDN_LOOP
bool "Loop device"
help
Enable support for loop device.
This module may be used for special applications that provide
bchannel data from user space. Applications can directly
access bchannels, so applications can be integrated into DSP
audio processing.
E.g. it is required for PBX4Linux. Go to http://isdn.eversberg.eu
and get more informations about this module and it's usage.
If unsure, say 'N'.
config MISDN_L1OIP
bool "ISDN over IP tunnel"
help
Enable support for ISDN over IP tunnel.
It features:
- layer 1 control via network keepalive frames
- dynamic IP exchange, if one or both peers have dynamic IPs
- channel bundeling for reduced IP overhead
- BRI (S0) and PRI (S2M) interface
NOTE: This protocol is called 'Layer 1 over IP' and is not
compatible with ISDNoIP (Agfeo) or TDMoIP.
endif
endmenu

View File

@ -1,113 +1,113 @@
L_OBJS :=
M_OBJS :=
LX_OBJS :=
MX_OBJS :=
O_OBJS :=
OX_OBJS :=
L_TARGET :=
O_TARGET := vmlinux-obj.o
# Makefile for the modular ISDN driver
#
EXTRA_CFLAGS += -ggdb
#
# EXTRA_CFLAGS += -S -g
ifdef MINCLUDES
CFLAGS += -I$(MINCLUDES) -g
endif
ifdef CONFIG_MISDN_MEMDEBUG
EXTRA_CFLAGS += -DMISDN_MEMDEBUG
endif
ifdef CONFIG_MISDN_NETDEV
EXTRA_CFLAGS += -DCONFIG_MISDN_NETDEV
endif
CFLAGS += -DMISDNVERSION=\"$(MISDNVERSION)\"
obj-$(CONFIG_MISDN_DRV) += mISDN_core.o
obj-$(CONFIG_MISDN_DRV) += mISDN_isac.o
obj-$(CONFIG_MISDN_DRV) += mISDN_l1.o
obj-$(CONFIG_MISDN_DRV) += mISDN_l2.o
obj-$(CONFIG_MISDN_DRV) += mISDN_x25dte.o
obj-$(CONFIG_MISDN_DRV) += l3udss1.o
obj-$(CONFIG_MISDN_DRV) += mISDN_capi.o
obj-$(CONFIG_MISDN_DRV) += mISDN_dtmf.o
ifdef CONFIG_MISDN_AVM_FRITZ
obj-$(CONFIG_MISDN_DRV) += avmfritz.o
endif
ifdef CONFIG_MISDN_NETJET
obj-$(CONFIG_MISDN_DRV) += netjetpci.o
endif
ifdef CONFIG_MISDN_HFCPCI
obj-$(CONFIG_MISDN_DRV) += hfcpci.o
endif
ifdef CONFIG_MISDN_HFCUSB
obj-$(CONFIG_MISDN_DRV) += hfcsusb.o
endif
ifdef CONFIG_MISDN_HFCMINI
obj-$(CONFIG_MISDN_DRV) += hfcsmini.o
endif
ifdef CONFIG_MISDN_SPEEDFAX
obj-$(CONFIG_MISDN_DRV) += sedlfax.o
# obj-$(CONFIG_MISDN_DRV) += faxl3.o
endif
ifdef CONFIG_MISDN_W6692
obj-$(CONFIG_MISDN_DRV) += w6692pci.o
endif
ifdef CONFIG_MISDN_HFCMULTI
obj-$(CONFIG_MISDN_DRV) += hfcmulti.o
endif
ifdef CONFIG_MISDN_XHFC
obj-$(CONFIG_MISDN_DRV) += xhfc.o
endif
ifdef CONFIG_MISDN_DSP
obj-$(CONFIG_MISDN_DRV) += mISDN_dsp.o
endif
ifdef CONFIG_MISDN_LOOP
obj-$(CONFIG_MISDN_DRV) += mISDN_loop.o
endif
ifdef CONFIG_I4L_CAPI_LAYER
obj-$(CONFIG_MISDN_DRV) += I4LmISDN.o
endif
# multi objects
sedlfax-objs := sedl_fax.o debug.o helper.o fsm.o isar.o dchannel.o bchannel.o
avmfritz-objs := avm_fritz.o debug.o helper.o fsm.o dchannel.o bchannel.o
hfcpci-objs := hfc_pci.o debug.o helper.o dchannel.o bchannel.o
mISDN_isac-objs := isac.o arcofi.o debug.o
mISDN_core-objs := core.o stack.o udevice.o helper.o
mISDN_l1-objs := layer1.o helper.o debug.o fsm.o
mISDN_l2-objs := layer2.o tei.o helper.o debug.o fsm.o
l3udss1-objs := layer3.o helper.o l3helper.o debug.o fsm.o l3_udss1.o
mISDN_capi-objs := capi.o contr.o listen.o appl.o plci.o cplci.o ncci.o asn1.o \
sedlfax-objs := sedl_fax.o isar.o
avmfritz-objs := avm_fritz.o
netjetpci-objs := netjet.o
hfcpci-objs := hfc_pci.o
hfcsusb-objs := hfcs_usb.o
hfcsmini-objs := hfcs_mini.o
w6692pci-objs := w6692.o
hfcmulti-objs := hfc_multi.o
xhfc-objs := xhfc_su.o xhfc_pci2pi.o
mISDN_isac-objs := isac.o arcofi.o
mISDN_core-objs := core.o stack.o udevice.o helper.o debug.o fsm.o \
channel.o l3helper.o \
sysfs_obj.o sysfs_inst.o sysfs_st.o
ifdef CONFIG_MISDN_NETDEV
mISDN_core-objs += netdev.o
endif
ifdef CONFIG_MISDN_MEMDEBUG
mISDN_core-objs += memdbg.o
endif
mISDN_l1-objs := layer1.o
mISDN_l2-objs := layer2.o tei.o
l3udss1-objs := layer3.o l3_udss1.o
mISDN_capi-objs := capi.o contr.o listen.o appl.o plci.o app_plci.o ncci.o asn1.o \
asn1_aoc.o asn1_comp.o asn1_generic.o asn1_diversion.o \
asn1_basic_service.o asn1_address.o asn1_enc.o capi_enc.o \
supp_serv.o helper.o l3helper.o debug.o fsm.o
mISDN_dtmf-objs := dtmf.o helper.o debug.o
ifdef CONFIG_I4L_CAPI_LAYER
I4LmISDN-objs := i4l_mISDN.o helper.o l3helper.o debug.o fsm.o
endif
LX_OBJS += core.o
ifdef MEMDBG
EXTRA_CFLAGS += -DMEMDBG
MX_OBJS += memdbg.o
endif
#ifeq ($(CONFIG_ISDN_DRV_mISDN),y)
# O_TARGET += mISDN.o
#else
# ifeq ($(CONFIG_ISDN_DRV_mISDN),m)
# O_TARGET += mISDN.o
# M_OBJS += mISDN.o
# endif
#endif
export-objs := core.o isac.o
obj-$(CONFIG_ISDN_DRV_mISDN) :=
obj-$(CONFIG_ISDN_DRV_mISDN) += mISDN_core.o
obj-$(CONFIG_ISDN_DRV_mISDN) += mISDN_isac.o
obj-$(CONFIG_ISDN_DRV_mISDN) += avmfritz.o
obj-$(CONFIG_ISDN_DRV_mISDN) += sedlfax.o
obj-$(CONFIG_ISDN_DRV_mISDN) += hfcpci.o
obj-$(CONFIG_ISDN_DRV_mISDN) += mISDN_l1.o
obj-$(CONFIG_ISDN_DRV_mISDN) += mISDN_l2.o
obj-$(CONFIG_ISDN_DRV_mISDN) += l3udss1.o
obj-$(CONFIG_ISDN_DRV_mISDN) += mISDN_capi.o
obj-$(CONFIG_ISDN_DRV_mISDN) += mISDN_dtmf.o
obj-$(CONFIG_ISDN_DRV_mISDN) += I4LmISDN.o
M_OBJS := $(obj-m)
include $(TOPDIR)/Rules.make
supp_serv.o
mISDN_dtmf-objs := dtmf.o
mISDN_dsp-objs := dsp_core.o dsp_cmx.o dsp_tones.o dsp_dtmf.o dsp_audio.o dsp_blowfish.o dsp_cancel.o
mISDN_loop-objs := loop.o
mISDN_x25dte-objs := x25_dte.o x25_l3.o
I4LmISDN-objs := i4l_mISDN.o
mISDN_core.o: $(mISDN_core-objs)
$(RM) $@
$(LD) -r -o $@ $(filter-out $(MODVERFILE) dummy ,$^)
mISDN_isac.o: $(mISDN_isac-objs)
$(RM) $@
$(LD) -r -o $@ $(filter-out $(MODVERFILE) dummy ,$^)
avmfritz.o: $(avmfritz-objs)
$(RM) $@
$(LD) -r -o $@ $(filter-out $(MODVERFILE) dummy ,$^)
sedlfax.o: $(sedlfax-objs)
$(RM) $@
$(LD) -r -o $@ $(filter-out $(MODVERFILE) dummy ,$^)
hfcpci.o: $(hfcpci-objs)
$(RM) $@
$(LD) -r -o $@ $(filter-out $(MODVERFILE) dummy ,$^)
mISDN_l1.o: $(mISDN_l1-objs)
$(RM) $@
$(LD) -r -o $@ $(filter-out $(MODVERFILE) dummy ,$^)
mISDN_l2.o: $(mISDN_l2-objs)
$(RM) $@
$(LD) -r -o $@ $(filter-out $(MODVERFILE) dummy ,$^)
l3udss1.o: $(l3udss1-objs)
$(RM) $@
$(LD) -r -o $@ $(filter-out $(MODVERFILE) dummy ,$^)
mISDN_capi.o: $(mISDN_capi-objs)
$(RM) $@
$(LD) -r -o $@ $(filter-out $(MODVERFILE) dummy ,$^)
mISDN_dtmf.o: $(mISDN_dtmf-objs)
$(RM) $@
$(LD) -r -o $@ $(filter-out $(MODVERFILE) dummy ,$^)
ifdef CONFIG_I4L_CAPI_LAYER
I4LmISDN.o: $(I4LmISDN-objs)
$(RM) $@
$(LD) -r -o $@ $(filter-out $(MODVERFILE) dummy ,$^)
endif

View File

@ -0,0 +1,74 @@
# Makefile for the modular ISDN driver
#
# EXTRA_CFLAGS += -S -g
#
ifdef CONFIG_MISDN_MEMDEBUG
EXTRA_CFLAGS += -DMISDN_MEMDEBUG
endif
EXTRA_CFLAGS += -I ../../avmb1
obj-$(CONFIG_MISDN_DRV) += mISDN_core.o
obj-$(CONFIG_MISDN_DRV) += mISDN_isac.o
obj-$(CONFIG_MISDN_DRV) += mISDN_l1.o
obj-$(CONFIG_MISDN_DRV) += mISDN_l2.o
obj-$(CONFIG_MISDN_DRV) += mISDN_x25dte.o
obj-$(CONFIG_MISDN_DRV) += l3udss1.o
obj-$(CONFIG_MISDN_DRV) += mISDN_capi.o
obj-$(CONFIG_MISDN_DRV) += mISDN_dtmf.o
ifdef CONFIG_MISDN_AVM_FRITZ
obj-$(CONFIG_MISDN_DRV) += avmfritz.o
endif
ifdef CONFIG_MISDN_HFCPCI
obj-$(CONFIG_MISDN_DRV) += hfcpci.o
endif
ifdef CONFIG_MISDN_SPEEDFAX
obj-$(CONFIG_MISDN_DRV) += sedlfax.o
endif
ifdef CONFIG_MISDN_W6692
obj-$(CONFIG_MISDN_DRV) += w6692pci.o
endif
ifdef CONFIG_MISDN_HFCMULTI
obj-$(CONFIG_MISDN_DRV) += hfcmulti.o
endif
ifdef CONFIG_MISDN_DSP
obj-$(CONFIG_MISDN_DRV) += mISDN_dsp.o
endif
ifdef CONFIG_I4L_CAPI_LAYER
obj-$(CONFIG_MISDN_DRV) += I4LmISDN.o
endif
# multi objects
sedlfax-objs := sedl_fax.o isar.o
avmfritz-objs := avm_fritz.o
hfcpci-objs := hfc_pci.o
w6692pci-objs := w6692.o
hfcmulti-objs := hfc_multi.o
mISDN_isac-objs := isac.o arcofi.o
mISDN_core-objs := core.o stack.o udevice.o helper.o debug.o fsm.o \
dchannel.o bchannel.o l3helper.o
ifdef CONFIG_MISDN_MEMDEBUG
mISDN_core-objs += memdbg.o
endif
mISDN_l1-objs := layer1.o
mISDN_l2-objs := layer2.o tei.o
l3udss1-objs := layer3.o l3_udss1.o
mISDN_capi-objs := capi.o contr.o listen.o appl.o plci.o app_plci.o ncci.o asn1.o \
asn1_aoc.o asn1_comp.o asn1_generic.o asn1_diversion.o \
asn1_basic_service.o asn1_address.o asn1_enc.o capi_enc.o \
supp_serv.o
mISDN_dtmf-objs := dtmf.o
mISDN_dsp-objs := dsp_core.o dsp_cmx.o dsp_tones.o dsp_dtmf.o dsp_audio.o dsp_blowfish.o
mISDN_x25dte-objs := x25_dte.o x25_l3.o
I4LmISDN-objs := i4l_mISDN.o
include Rules.mISDN

View File

@ -0,0 +1,113 @@
# Makefile for the modular ISDN driver
#
EXTRA_CFLAGS += -ggdb
#
ifdef MINCLUDES
CFLAGS += -I$(MINCLUDES) -g
endif
ifdef CONFIG_MISDN_MEMDEBUG
EXTRA_CFLAGS += -DMISDN_MEMDEBUG
endif
ifdef CONFIG_MISDN_NETDEV
EXTRA_CFLAGS += -DCONFIG_MISDN_NETDEV
endif
CFLAGS += -DMISDNVERSION=\"$(MISDNVERSION)\"
obj-$(CONFIG_MISDN_DRV) += mISDN_core.o
obj-$(CONFIG_MISDN_DRV) += mISDN_isac.o
obj-$(CONFIG_MISDN_DRV) += mISDN_l1.o
obj-$(CONFIG_MISDN_DRV) += mISDN_l2.o
obj-$(CONFIG_MISDN_DRV) += mISDN_x25dte.o
obj-$(CONFIG_MISDN_DRV) += l3udss1.o
obj-$(CONFIG_MISDN_DRV) += mISDN_capi.o
obj-$(CONFIG_MISDN_DRV) += mISDN_dtmf.o
ifdef CONFIG_MISDN_AVM_FRITZ
obj-$(CONFIG_MISDN_DRV) += avmfritz.o
endif
ifdef CONFIG_MISDN_NETJET
obj-$(CONFIG_MISDN_DRV) += netjetpci.o
endif
ifdef CONFIG_MISDN_HFCPCI
obj-$(CONFIG_MISDN_DRV) += hfcpci.o
endif
ifdef CONFIG_MISDN_HFCUSB
obj-$(CONFIG_MISDN_DRV) += hfcsusb.o
endif
ifdef CONFIG_MISDN_HFCMINI
obj-$(CONFIG_MISDN_DRV) += hfcsmini.o
endif
ifdef CONFIG_MISDN_SPEEDFAX
obj-$(CONFIG_MISDN_DRV) += sedlfax.o
# obj-$(CONFIG_MISDN_DRV) += faxl3.o
endif
ifdef CONFIG_MISDN_W6692
obj-$(CONFIG_MISDN_DRV) += w6692pci.o
endif
ifdef CONFIG_MISDN_HFCMULTI
obj-$(CONFIG_MISDN_DRV) += hfcmulti.o
endif
ifdef CONFIG_MISDN_XHFC
obj-$(CONFIG_MISDN_DRV) += xhfc.o
endif
ifdef CONFIG_MISDN_DSP
obj-$(CONFIG_MISDN_DRV) += mISDN_dsp.o
endif
ifdef CONFIG_MISDN_LOOP
obj-$(CONFIG_MISDN_DRV) += mISDN_loop.o
endif
ifdef CONFIG_I4L_CAPI_LAYER
obj-$(CONFIG_MISDN_DRV) += I4LmISDN.o
endif
# multi objects
sedlfax-objs := sedl_fax.o isar.o
avmfritz-objs := avm_fritz.o
netjetpci-objs := netjet.o
hfcpci-objs := hfc_pci.o
hfcsusb-objs := hfcs_usb.o
hfcsmini-objs := hfcs_mini.o
w6692pci-objs := w6692.o
hfcmulti-objs := hfc_multi.o
xhfc-objs := xhfc_su.o xhfc_pci2pi.o
mISDN_isac-objs := isac.o arcofi.o
mISDN_core-objs := core.o stack.o udevice.o helper.o debug.o fsm.o \
channel.o l3helper.o \
sysfs_obj.o sysfs_inst.o sysfs_st.o
ifdef CONFIG_MISDN_NETDEV
mISDN_core-objs += netdev.o
endif
ifdef CONFIG_MISDN_MEMDEBUG
mISDN_core-objs += memdbg.o
endif
mISDN_l1-objs := layer1.o
mISDN_l2-objs := layer2.o tei.o
l3udss1-objs := layer3.o l3_udss1.o
mISDN_capi-objs := capi.o contr.o listen.o appl.o plci.o app_plci.o ncci.o asn1.o \
asn1_aoc.o asn1_comp.o asn1_generic.o asn1_diversion.o \
asn1_basic_service.o asn1_address.o asn1_enc.o capi_enc.o \
supp_serv.o
mISDN_dtmf-objs := dtmf.o
mISDN_dsp-objs := dsp_core.o dsp_cmx.o dsp_tones.o dsp_dtmf.o dsp_audio.o dsp_blowfish.o dsp_cancel.o
mISDN_loop-objs := loop.o
mISDN_x25dte-objs := x25_dte.o x25_l3.o
I4LmISDN-objs := i4l_mISDN.o

View File

@ -0,0 +1,79 @@
#
# local Rules for 2.4
#
O_TARGET := vmlinux-obj.o
export-objs := core.o isac.o helper.o debug.o fsm.o dchannel.o bchannel.o \
l3helper.o
ifdef CONFIG_MISDN_MEMDEBUG
export-objs += memdbg.o
endif
M_OBJS := $(obj-m)
include $(TOPDIR)/Rules.make
mISDN_core.o: $(mISDN_core-objs)
$(RM) $@
$(LD) -r -o $@ $(filter-out $(MODVERFILE) dummy ,$^)
mISDN_isac.o: $(mISDN_isac-objs)
$(RM) $@
$(LD) -r -o $@ $(filter-out $(MODVERFILE) dummy ,$^)
avmfritz.o: $(avmfritz-objs)
$(RM) $@
$(LD) -r -o $@ $(filter-out $(MODVERFILE) dummy ,$^)
sedlfax.o: $(sedlfax-objs)
$(RM) $@
$(LD) -r -o $@ $(filter-out $(MODVERFILE) dummy ,$^)
w6692pci.o: $(w6692pci-objs)
$(RM) $@
$(LD) -r -o $@ $(filter-out $(MODVERFILE) dummy ,$^)
hfcpci.o: $(hfcpci-objs)
$(RM) $@
$(LD) -r -o $@ $(filter-out $(MODVERFILE) dummy ,$^)
hfcmulti.o: $(hfcmulti-objs)
$(RM) $@
$(LD) -r -o $@ $(filter-out $(MODVERFILE) dummy ,$^)
mISDN_l1.o: $(mISDN_l1-objs)
$(RM) $@
$(LD) -r -o $@ $(filter-out $(MODVERFILE) dummy ,$^)
mISDN_l2.o: $(mISDN_l2-objs)
$(RM) $@
$(LD) -r -o $@ $(filter-out $(MODVERFILE) dummy ,$^)
mISDN_x25dte.o: $(mISDN_x25dte-objs)
$(RM) $@
$(LD) -r -o $@ $(filter-out $(MODVERFILE) dummy ,$^)
l3udss1.o: $(l3udss1-objs)
$(RM) $@
$(LD) -r -o $@ $(filter-out $(MODVERFILE) dummy ,$^)
mISDN_capi.o: $(mISDN_capi-objs)
$(RM) $@
$(LD) -r -o $@ $(filter-out $(MODVERFILE) dummy ,$^)
mISDN_dtmf.o: $(mISDN_dtmf-objs)
$(RM) $@
$(LD) -r -o $@ $(filter-out $(MODVERFILE) dummy ,$^)
ifdef CONFIG_I4L_CAPI_LAYER
I4LmISDN.o: $(I4LmISDN-objs)
$(RM) $@
$(LD) -r -o $@ $(filter-out $(MODVERFILE) dummy ,$^)
endif
mISDN_dsp.o: $(mISDN_dsp-objs)
$(RM) $@
$(LD) -r -o $@ $(filter-out $(MODVERFILE) dummy ,$^)

File diff suppressed because it is too large Load Diff

View File

@ -1,76 +1,191 @@
/* $Id$
*
* Applications are owned by the controller and only
* handle this controller, multiplexing multiple
* controller with one application is done in the higher
* driver independ CAPI driver. The application contain
* the Listen state machine.
*
*/
#include "capi.h"
#include "m_capi.h"
#include "helper.h"
#include "debug.h"
#include "mISDNManufacturer.h"
#define applDebug(appl, lev, fmt, args...) \
capidebug(lev, fmt, ## args)
void applConstr(Appl_t *appl, Contr_t *contr, __u16 ApplId, capi_register_params *rp)
static struct list_head garbage_applications = LIST_HEAD_INIT(garbage_applications);
int
ApplicationConstr(Controller_t *contr, __u16 ApplId, capi_register_params *rp)
{
memset(appl, 0, sizeof(Appl_t));
Application_t *appl = kmalloc(sizeof(Application_t), GFP_ATOMIC);
if (!appl) {
return(-ENOMEM);
}
memset(appl, 0, sizeof(Application_t));
INIT_LIST_HEAD(&appl->head);
appl->contr = contr;
appl->maxplci = contr->maxplci;
appl->AppPlcis = kmalloc(appl->maxplci * sizeof(AppPlci_t *), GFP_ATOMIC);
if (!appl->AppPlcis) {
kfree(appl);
return(-ENOMEM);
}
memset(appl->AppPlcis, 0, appl->maxplci * sizeof(AppPlci_t *));
appl->ApplId = ApplId;
appl->MsgId = 1;
appl->NotificationMask = 0;
memcpy(&appl->rp, rp, sizeof(capi_register_params));
listenConstr(&appl->listen, contr, ApplId);
memcpy(&appl->reg_params, rp, sizeof(capi_register_params));
listenConstr(appl);
list_add(&appl->head, &contr->Applications);
test_and_set_bit(APPL_STATE_ACTIV, &appl->state);
return(0);
}
void applDestr(Appl_t *appl)
/*
* Destroy the Application
*
* depending who initiate this we cannot release imediatly, if
* any AppPlci is still in use.
*
* @who: 0 - a AppPlci is released in state APPL_STATE_RELEASE
* 1 - Application is released from CAPI application
* 2 - the controller is resetted
* 3 - the controller is removed
* 4 - the CAPI module will be unload
*/
int
ApplicationDestr(Application_t *appl, int who)
{
int i;
int i, used = 0;
AppPlci_t **aplci_p = appl->AppPlcis;
listenDestr(&appl->listen);
for (i = 0; i < CAPI_MAXPLCI; i++) {
if (appl->cplcis[i]) {
cplciDestr(appl->cplcis[i]);
kfree(appl->cplcis[i]);
appl->cplcis[i] = NULL;
if (test_and_set_bit(APPL_STATE_DESTRUCTOR, &appl->state)) {
// we are allready in this function
return(-EBUSY);
}
test_and_set_bit(APPL_STATE_RELEASE, &appl->state);
test_and_clear_bit(APPL_STATE_ACTIV, &appl->state);
listenDestr(appl);
if (who > 2) {
appl->contr = NULL;
}
if (aplci_p) {
for (i = 0; i < appl->maxplci; i++) {
if (*aplci_p) {
switch (who) {
case 4:
AppPlciDestr(*aplci_p);
*aplci_p = NULL;
break;
case 1:
case 2:
case 3:
AppPlciRelease(*aplci_p);
case 0:
if ((volatile AppPlci_t *)(*aplci_p))
used++;
break;
}
}
aplci_p++;
}
}
if (used) {
if (who == 3) {
list_del_init(&appl->head);
list_add(&appl->head, &garbage_applications);
}
test_and_clear_bit(APPL_STATE_DESTRUCTOR, &appl->state);
return(-EBUSY);
}
list_del_init(&appl->head);
appl->maxplci = 0;
kfree(appl->AppPlcis);
appl->AppPlcis = NULL;
kfree(appl);
return(0);
}
Cplci_t *applAdr2cplci(Appl_t *appl, __u32 adr)
AppPlci_t *
getAppPlci4addr(Application_t *appl, __u32 addr)
{
int i = (adr >> 8) & 0xff;
int plci_idx = (addr >> 8) & 0xff;
if ((i < 1) || (i > CAPI_MAXPLCI)) {
if ((plci_idx < 1) || (plci_idx >= appl->maxplci)) {
int_error();
return 0;
return NULL;
}
return appl->cplcis[i - 1];
return(appl->AppPlcis[plci_idx - 1]);
}
void applSendMessage(Appl_t *appl, struct sk_buff *skb)
static void
FacilityReq(Application_t *appl, struct sk_buff *skb)
{
_cmsg *cmsg;
AppPlci_t *aplci;
Ncci_t *ncci;
cmsg = cmsg_alloc();
if (!cmsg) {
int_error();
dev_kfree_skb(skb);
return;
}
capi_message2cmsg(cmsg, skb->data);
switch (cmsg->FacilitySelector) {
case 0x0000: // Handset
case 0x0001: // DTMF
aplci = getAppPlci4addr(appl, CAPIMSG_CONTROL(skb->data));
if (aplci) {
ncci = getNCCI4addr(aplci, CAPIMSG_NCCI(skb->data), GET_NCCI_PLCI);
if (ncci) {
ncciGetCmsg(ncci, cmsg);
break;
}
}
SendCmsgAnswer2Application(appl, cmsg, CapiIllContrPlciNcci);
break;
case 0x0003: // SupplementaryServices
SupplementaryFacilityReq(appl, cmsg);
break;
default:
int_error();
SendCmsgAnswer2Application(appl, cmsg, CapiFacilityNotSupported);
break;
}
dev_kfree_skb(skb);
}
void
ApplicationSendMessage(Application_t *appl, struct sk_buff *skb)
{
Plci_t *plci;
Cplci_t *cplci;
AppPlci_t *aplci;
__u16 ret;
switch (CAPICMD(CAPIMSG_COMMAND(skb->data), CAPIMSG_SUBCOMMAND(skb->data))) {
// for NCCI state machine
case CAPI_DATA_B3_REQ:
case CAPI_DATA_B3_RESP:
// new NCCI
case CAPI_CONNECT_B3_REQ:
case CAPI_CONNECT_B3_RESP:
case CAPI_CONNECT_B3_ACTIVE_RESP:
case CAPI_DISCONNECT_B3_REQ:
aplci = getAppPlci4addr(appl, CAPIMSG_CONTROL(skb->data));
if (!aplci) {
AnswerMessage2Application(appl, skb, CapiIllContrPlciNcci);
goto free;
}
ConnectB3Request(aplci, skb);
break;
// maybe already down NCCI
case CAPI_DISCONNECT_B3_RESP:
cplci = applAdr2cplci(appl, CAPIMSG_CONTROL(skb->data));
if (!cplci) {
contrAnswerMessage(appl->contr, skb, CapiIllContrPlciNcci);
aplci = getAppPlci4addr(appl, CAPIMSG_CONTROL(skb->data));
if (!aplci) {
AnswerMessage2Application(appl, skb, CapiIllContrPlciNcci);
goto free;
}
if (!cplci->ncci) {
int_error();
contrAnswerMessage(appl->contr, skb, CapiIllContrPlciNcci);
goto free;
}
ncciSendMessage(cplci->ncci, skb);
DisconnectB3Request(aplci, skb);
break;
// for PLCI state machine
case CAPI_INFO_REQ:
@ -80,36 +195,43 @@ void applSendMessage(Appl_t *appl, struct sk_buff *skb)
case CAPI_DISCONNECT_REQ:
case CAPI_DISCONNECT_RESP:
case CAPI_SELECT_B_PROTOCOL_REQ:
cplci = applAdr2cplci(appl, CAPIMSG_CONTROL(skb->data));
if (!cplci) {
contrAnswerMessage(appl->contr, skb, CapiIllContrPlciNcci);
aplci = getAppPlci4addr(appl, CAPIMSG_CONTROL(skb->data));
if (!aplci) {
AnswerMessage2Application(appl, skb, CapiIllContrPlciNcci);
goto free;
}
cplciSendMessage(cplci, skb);
ret = AppPlciSendMessage(aplci, skb);
if (ret) {
int_error();
}
break;
case CAPI_CONNECT_REQ:
plci = contrNewPlci(appl->contr);
if (!plci) {
contrAnswerMessage(appl->contr, skb, CapiNoPlciAvailable);
if (ControllerNewPlci(appl->contr, &plci, MISDN_ID_ANY)) {
AnswerMessage2Application(appl, skb, CapiNoPlciAvailable);
goto free;
}
cplci = applNewCplci(appl, plci);
if (!cplci) {
contrDelPlci(appl->contr, plci);
contrAnswerMessage(appl->contr, skb, CapiNoPlciAvailable);
aplci = ApplicationNewAppPlci(appl, plci);
if (!aplci) {
AnswerMessage2Application(appl, skb, CapiNoPlciAvailable);
goto free;
}
cplciSendMessage(cplci, skb);
ret = AppPlciSendMessage(aplci, skb);
if (ret) {
int_error();
}
break;
// for LISTEN state machine
case CAPI_LISTEN_REQ:
listenSendMessage(&appl->listen, skb);
ret = listenSendMessage(appl, skb);
if (ret) {
int_error();
}
break;
// other
case CAPI_FACILITY_REQ:
applFacilityReq(appl, skb);
FacilityReq(appl, skb);
break;
case CAPI_FACILITY_RESP:
goto free;
@ -121,203 +243,293 @@ void applSendMessage(Appl_t *appl, struct sk_buff *skb)
default:
applDebug(appl, CAPI_DBG_WARN, "applSendMessage: %#x %#x not handled!",
CAPIMSG_COMMAND(skb->data), CAPIMSG_SUBCOMMAND(skb->data));
if (CAPIMSG_SUBCOMMAND(skb->data) == CAPI_REQ)
contrAnswerMessage(appl->contr, skb,
CapiMessageNotSupportedInCurrentState);
goto free;
break;
}
return;
free:
dev_kfree_skb(skb);
}
void applFacilityReq(Appl_t *appl, struct sk_buff *skb)
{
_cmsg cmsg;
Cplci_t *cplci;
capi_message2cmsg(&cmsg, skb->data);
switch (cmsg.FacilitySelector) {
case 0x0001: // DTMF
cplci = applAdr2cplci(appl, CAPIMSG_CONTROL(skb->data));
if (cplci && cplci->ncci) {
ncciSendMessage(cplci->ncci, skb);
return;
}
contrAnswerMessage(appl->contr, skb, CapiIllContrPlciNcci);
AppPlci_t *
ApplicationNewAppPlci(Application_t *appl, Plci_t *plci)
{
AppPlci_t *aplci;
int plci_idx = (plci->addr >> 8) & 0xff;
if (test_bit(APPL_STATE_RELEASE, &appl->state))
return(NULL);
if ((plci_idx < 1) || (plci_idx >= appl->maxplci)) {
int_error();
return(NULL);
}
if (appl->AppPlcis[plci_idx - 1]) {
int_error();
return(NULL);
}
if (AppPlciConstr(&aplci, appl, plci)) {
int_error();
return(NULL);
}
applDebug(appl, CAPI_DBG_APPL_INFO, "ApplicationNewAppPlci: idx(%d) aplci(%p) appl(%p) plci(%p)",
plci_idx, aplci, appl, plci);
appl->AppPlcis[plci_idx - 1] = aplci;
plciAttachAppPlci(plci, aplci);
return(aplci);
}
void
ApplicationDelAppPlci(Application_t *appl, AppPlci_t *aplci)
{
int plci_idx = (aplci->addr >> 8) & 0xff;
if ((plci_idx < 1) || (plci_idx >= appl->maxplci)) {
int_error();
return;
}
if (appl->AppPlcis[plci_idx - 1] != aplci) {
int_error();
return;
}
appl->AppPlcis[plci_idx - 1] = NULL;
if (test_bit(APPL_STATE_RELEASE, &appl->state) &&
!test_bit(APPL_STATE_DESTRUCTOR, &appl->state))
ApplicationDestr(appl, 0);
}
void
SendCmsg2Application(Application_t *appl, _cmsg *cmsg)
{
struct sk_buff *skb;
if (test_bit(APPL_STATE_RELEASE, &appl->state)) {
/* Application is released and cannot receive messages
* anymore. To avoid stalls in the state machines we
* must answer INDICATIONS.
*/
AppPlci_t *aplci;
Ncci_t *ncci;
if (CAPI_IND != cmsg->Subcommand)
goto free;
switch(cmsg->Command) {
// for NCCI state machine
case CAPI_CONNECT_B3:
cmsg->Reject = 2;
case CAPI_CONNECT_B3_ACTIVE:
case CAPI_DISCONNECT_B3:
aplci = getAppPlci4addr(appl, (cmsg->adr.adrNCCI & 0xffff));
if (!aplci)
goto free;
ncci = getNCCI4addr(aplci, cmsg->adr.adrNCCI, GET_NCCI_EXACT);
if (!ncci) {
int_error();
goto free;
}
capi_cmsg_answer(cmsg);
ncciGetCmsg(ncci, cmsg);
break;
case 0x0003: // SupplementaryServices
applSuppFacilityReq(appl, &cmsg);
// for PLCI state machine
case CAPI_CONNECT:
cmsg->Reject = 2;
case CAPI_CONNECT_ACTIVE:
case CAPI_DISCONNECT:
aplci = getAppPlci4addr(appl, (cmsg->adr.adrPLCI & 0xffff));
if (!aplci)
goto free;
capi_cmsg_answer(cmsg);
AppPlciGetCmsg(aplci, cmsg);
break;
case CAPI_FACILITY:
case CAPI_MANUFACTURER:
case CAPI_INFO:
goto free;
default:
int_error();
contrAnswerMessage(appl->contr, skb, CapiFacilityNotSupported);
break;
goto free;
}
return;
}
if (!(skb = alloc_skb(CAPI_MSG_DEFAULT_LEN, GFP_ATOMIC))) {
printk(KERN_WARNING "%s: no mem for %d bytes\n", __FUNCTION__, CAPI_MSG_DEFAULT_LEN);
int_error();
goto free;
}
capi_cmsg2message(cmsg, skb->data);
applDebug(appl, CAPI_DBG_APPL_MSG, "%s: len(%d) applid(%x) %s msgnr(%d) addr(%08x)",
__FUNCTION__, CAPIMSG_LEN(skb->data), cmsg->ApplId, capi_cmd2str(cmsg->Command, cmsg->Subcommand),
cmsg->Messagenumber, cmsg->adr.adrController);
if (CAPI_MSG_DEFAULT_LEN < CAPIMSG_LEN(skb->data)) {
printk(KERN_ERR "%s: CAPI_MSG_DEFAULT_LEN overrun (%d/%d)\n", __FUNCTION__,
CAPIMSG_LEN(skb->data), CAPI_MSG_DEFAULT_LEN);
int_error();
dev_kfree_skb(skb);
goto free;
}
skb_put(skb, CAPIMSG_LEN(skb->data));
#ifdef OLDCAPI_DRIVER_INTERFACE
appl->contr->ctrl->handle_capimsg(appl->contr->ctrl, cmsg->ApplId, skb);
#else
capi_ctr_handle_message(appl->contr->ctrl, cmsg->ApplId, skb);
#endif
free:
cmsg_free(cmsg);
}
Cplci_t *applNewCplci(Appl_t *appl, Plci_t *plci)
void
SendCmsgAnswer2Application(Application_t *appl, _cmsg *cmsg, __u16 Info)
{
Cplci_t *cplci;
int i = (plci->adrPLCI >> 8);
if (appl->cplcis[i - 1]) {
int_error();
return 0;
}
cplci = kmalloc(sizeof(Cplci_t), GFP_ATOMIC);
cplciConstr(cplci, appl, plci);
appl->cplcis[i - 1] = cplci;
plciAttachCplci(plci, cplci);
return cplci;
capi_cmsg_answer(cmsg);
cmsg->Info = Info;
SendCmsg2Application(appl, cmsg);
}
void applDelCplci(Appl_t *appl, Cplci_t *cplci)
void
AnswerMessage2Application(Application_t *appl, struct sk_buff *skb, __u16 Info)
{
int i = cplci->adrPLCI >> 8;
_cmsg *cmsg;
if ((i < 1) || (i > CAPI_MAXPLCI)) {
int_error();
return;
}
if (appl->cplcis[i-1] != cplci) {
int_error();
return;
}
cplciDestr(cplci);
kfree(cplci);
appl->cplcis[i-1] = NULL;
CMSG_ALLOC(cmsg);
capi_message2cmsg(cmsg, skb->data);
SendCmsgAnswer2Application(appl, cmsg, Info);
}
#define CLASS_I4L 0x00
#define FUNCTION_I4L_LEASED_IN 0x01
#define FUNCTION_I4L_DEC_USE_COUNT 0x02
#define FUNCTION_I4L_INC_USE_COUNT 0x03
#define AVM_MANUFACTURER_ID 0x214D5641 /* "AVM!" */
#define CLASS_AVM 0x00
#define FUNCTION_AVM_D2_TRACE 0x01
struct I4LLeasedManuData {
__u8 Length;
__u8 BChannel;
};
struct AVMD2Trace {
__u8 Length;
__u8 data[4];
};
struct ManufacturerReq {
__u32 Class;
__u32 Function;
union {
struct I4LLeasedManuData leased;
struct AVMD2Trace d2trace;
} f;
};
void applManufacturerReqAVM(Appl_t *appl, struct sk_buff *skb)
void applManufacturerReqAVM(Application_t *appl, _cmsg *cmsg, struct sk_buff *skb)
{
struct ManufacturerReq *manuReq;
struct AVMD2Trace *at;
manuReq = (struct ManufacturerReq *)&skb->data[16];
if (manuReq->Class != CLASS_AVM) {
applDebug(appl, CAPI_DBG_APPL_INFO, "CAPI: unknown class %#x\n", manuReq->Class);
goto out;
if (cmsg->Class != CLASS_AVM) {
applDebug(appl, CAPI_DBG_APPL_INFO, "CAPI: unknown class %#x\n", cmsg->Class);
cmsg_free(cmsg);
dev_kfree_skb(skb);
return;
}
switch (manuReq->Function) {
switch (cmsg->Function) {
case FUNCTION_AVM_D2_TRACE:
if (skb->len != 16 + 8 + 5)
goto out;
if (manuReq->f.d2trace.Length != 4)
goto out;
if (memcmp(manuReq->f.d2trace.data, "\200\014\000\000", 4) == 0) {
test_and_set_bit(APPL_FLAG_D2TRACE, &appl->flags);
} else if (memcmp(manuReq->f.d2trace.data, "\000\000\000\000", 4) == 0) {
test_and_clear_bit(APPL_FLAG_D2TRACE, &appl->flags);
at = (struct AVMD2Trace *)cmsg->ManuData;
if (!at || at->Length != 4) {
int_error();
break;
}
if (memcmp(at->data, "\200\014\000\000", 4) == 0) {
test_and_set_bit(APPL_STATE_D2TRACE, &appl->state);
} else if (memcmp(at->data, "\000\000\000\000", 4) == 0) {
test_and_clear_bit(APPL_STATE_D2TRACE, &appl->state);
} else {
int_error();
}
break;
default:
applDebug(appl, CAPI_DBG_APPL_INFO, "CAPI: unknown function %#x\n", manuReq->Function);
applDebug(appl, CAPI_DBG_APPL_INFO, "CAPI: unknown function %#x\n", cmsg->Function);
}
out:
cmsg_free(cmsg);
dev_kfree_skb(skb);
}
void applManufacturerReqI4L(Appl_t *appl, struct sk_buff *skb)
void applManufacturerReqmISDN(Application_t *appl, _cmsg *cmsg, struct sk_buff *skb)
{
int bchannel;
struct ManufacturerReq *manuReq;
AppPlci_t *aplci;
Ncci_t *ncci;
manuReq = (struct ManufacturerReq *)&skb->data[16];
if (manuReq->Class != CLASS_I4L) {
applDebug(appl, CAPI_DBG_APPL_INFO, "CAPI: unknown class %#x\n", manuReq->Class);
goto out;
switch (cmsg->Class) {
case mISDN_MF_CLASS_HANDSET:
/* Note normally MANUFATURER messages are only defined for
* controller address we extent it here to PLCI/NCCI
*/
aplci = getAppPlci4addr(appl, CAPIMSG_CONTROL(skb->data));
if (aplci) {
ncci = getNCCI4addr(aplci, CAPIMSG_NCCI(skb->data), GET_NCCI_PLCI);
if (ncci) {
cmsg_free(cmsg);
ncciSendMessage(ncci, skb);
return;
}
switch (manuReq->Function) {
case FUNCTION_I4L_LEASED_IN:
if (skb->len < 16 + 8 + 2)
goto out;
if (manuReq->f.leased.Length != 2)
goto out;
bchannel = manuReq->f.leased.BChannel;
if (bchannel < 1 || bchannel > 2)
goto out;
// FIXME
// contrL4L3(appl->contr, CC_SETUP | INDICATION, &bchannel);
break;
case FUNCTION_I4L_DEC_USE_COUNT:
break;
case FUNCTION_I4L_INC_USE_COUNT:
}
SendCmsgAnswer2Application(appl, cmsg, CapiIllContrPlciNcci);
break;
default:
applDebug(appl, CAPI_DBG_APPL_INFO, "CAPI: unknown function %#x\n", manuReq->Function);
cmsg_free(cmsg);
break;
}
out:
dev_kfree_skb(skb);
}
void applManufacturerReq(Appl_t *appl, struct sk_buff *skb)
void
applManufacturerReq(Application_t *appl, struct sk_buff *skb)
{
_cmsg *cmsg;
if (skb->len < 16 + 8) {
dev_kfree_skb(skb);
return;
}
if (memcmp(&skb->data[12], "AVM!", 4) == 0) {
applManufacturerReqAVM(appl, skb);
}
if (memcmp(&skb->data[12], "I4L!", 4) == 0) {
applManufacturerReqI4L(appl, skb);
}
cmsg = cmsg_alloc();
if (!cmsg) {
int_error();
dev_kfree_skb(skb);
return;
}
capi_message2cmsg(cmsg, skb->data);
switch (cmsg->ManuID) {
case mISDN_MANUFACTURER_ID:
applManufacturerReqmISDN(appl, cmsg, skb);
break;
case AVM_MANUFACTURER_ID:
applManufacturerReqAVM(appl, cmsg, skb);
break;
default:
applDebug(appl, CAPI_DBG_APPL_INFO, "CAPI: unknown ManuID %#x\n", cmsg->ManuID);
cmsg_free(cmsg);
dev_kfree_skb(skb);
break;
}
}
void applD2Trace(Appl_t *appl, u_char *buf, int len)
void applD2Trace(Application_t *appl, u_char *buf, int len)
{
_cmsg cmsg;
_cmsg *cmsg;
__u8 manuData[255];
if (!test_bit(APPL_FLAG_D2TRACE, &appl->flags))
if (!test_bit(APPL_STATE_D2TRACE, &appl->state))
return;
memset(&cmsg, 0, sizeof(_cmsg));
capi_cmsg_header(&cmsg, appl->ApplId, CAPI_MANUFACTURER, CAPI_IND,
appl->MsgId++, appl->contr->adrController);
cmsg.ManuID = 0x214D5641; // "AVM!"
cmsg.Class = CLASS_AVM;
cmsg.Function = FUNCTION_AVM_D2_TRACE;
cmsg.ManuData = (_cstruct) &manuData;
CMSG_ALLOC(cmsg);
capi_cmsg_header(cmsg, appl->ApplId, CAPI_MANUFACTURER, CAPI_IND,
appl->MsgId++, appl->contr->addr);
cmsg->ManuID = AVM_MANUFACTURER_ID;
cmsg->Class = CLASS_AVM;
cmsg->Function = FUNCTION_AVM_D2_TRACE;
cmsg->ManuData = (_cstruct) &manuData;
manuData[0] = 2 + len; // length
manuData[1] = 0x80;
manuData[2] = 0x0f;
memcpy(&manuData[3], buf, len);
contrRecvCmsg(appl->contr, &cmsg);
SendCmsg2Application(appl, cmsg);
}
void
free_Application(void)
{
struct list_head *item, *next;
int n = 0;
if (list_empty(&garbage_applications)) {
printk(KERN_DEBUG "%s: no garbage\n", __FUNCTION__);
return;
}
list_for_each_safe(item, next, &garbage_applications) {
ApplicationDestr((Application_t *)item, 4);
n++;
}
printk(KERN_WARNING"%s: %d garbage items\n", __FUNCTION__, n);
}

View File

@ -8,20 +8,20 @@
*
*/
#define __NO_VERSION__
#include "dchannel.h"
#include "channel.h"
#include "layer1.h"
#include "isac.h"
#include "arcofi.h"
#include "debug.h"
#include "helper.h"
#define ARCOFI_TIMER_VALUE 20
static void
add_arcofi_timer(dchannel_t *dch) {
add_arcofi_timer(channel_t *dch) {
isac_chip_t *isac = dch->hw;
if (test_and_set_bit(FLG_ARCOFI_TIMER, &dch->DFlags)) {
if (test_and_set_bit(FLG_ARCOFI_TIMER, &dch->Flags)) {
del_timer(&isac->arcofitimer);
}
init_timer(&isac->arcofitimer);
@ -30,7 +30,7 @@ add_arcofi_timer(dchannel_t *dch) {
}
static void
send_arcofi(dchannel_t *dch) {
send_arcofi(channel_t *dch) {
u_char val;
isac_chip_t *isac = dch->hw;
@ -46,23 +46,23 @@ send_arcofi(dchannel_t *dch) {
}
isac->mocr &= 0x0f;
isac->mocr |= 0xa0;
dch->write_reg(dch->inst.data, ISAC_MOCR, isac->mocr);
val = dch->read_reg(dch->inst.data, ISAC_MOSR);
dch->write_reg(dch->inst.data, ISAC_MOX1, isac->mon_tx[isac->mon_txp++]);
dch->write_reg(dch->inst.privat, ISAC_MOCR, isac->mocr);
val = dch->read_reg(dch->inst.privat, ISAC_MOSR);
dch->write_reg(dch->inst.privat, ISAC_MOX1, isac->mon_tx[isac->mon_txp++]);
isac->mocr |= 0x10;
dch->write_reg(dch->inst.data, ISAC_MOCR, isac->mocr);
dch->write_reg(dch->inst.privat, ISAC_MOCR, isac->mocr);
}
int
arcofi_fsm(dchannel_t *dch, int event, void *data) {
arcofi_fsm(channel_t *dch, int event, void *data) {
isac_chip_t *isac = dch->hw;
if (dch->debug & L1_DEB_MONITOR) {
debugprint(&dch->inst, "arcofi state %d event %d", isac->arcofi_state, event);
mISDN_debugprint(&dch->inst, "arcofi state %d event %d", isac->arcofi_state, event);
}
if (event == ARCOFI_TIMEOUT) {
isac->arcofi_state = ARCOFI_NOP;
test_and_set_bit(FLG_ARCOFI_ERROR, &dch->DFlags);
test_and_set_bit(FLG_ARCOFI_ERROR, &dch->Flags);
wake_up(&isac->arcofi_wait);
return(1);
}
@ -85,7 +85,7 @@ arcofi_fsm(dchannel_t *dch, int event, void *data) {
isac->arcofi_list->next;
send_arcofi(dch);
} else {
if (test_and_clear_bit(FLG_ARCOFI_TIMER, &dch->DFlags)) {
if (test_and_clear_bit(FLG_ARCOFI_TIMER, &dch->Flags)) {
del_timer(&isac->arcofitimer);
}
isac->arcofi_state = ARCOFI_NOP;
@ -96,13 +96,20 @@ arcofi_fsm(dchannel_t *dch, int event, void *data) {
break;
case ARCOFI_RECEIVE:
if (event == ARCOFI_RX_END) {
struct sk_buff *skb = data;
// FIXME handle message
if (skb)
kfree_skb(skb);
else
int_error();
if (isac->arcofi_list->next) {
isac->arcofi_list =
isac->arcofi_list->next;
isac->arcofi_state = ARCOFI_TRANSMIT;
send_arcofi(dch);
} else {
if (test_and_clear_bit(FLG_ARCOFI_TIMER, &dch->DFlags)) {
if (test_and_clear_bit(FLG_ARCOFI_TIMER, &dch->Flags)) {
del_timer(&isac->arcofitimer);
}
isac->arcofi_state = ARCOFI_NOP;
@ -111,28 +118,28 @@ arcofi_fsm(dchannel_t *dch, int event, void *data) {
}
break;
default:
debugprint(&dch->inst, "Arcofi unknown state %x", isac->arcofi_state);
mISDN_debugprint(&dch->inst, "Arcofi unknown state %x", isac->arcofi_state);
return(2);
}
return(0);
}
static void
arcofi_timer(dchannel_t *dch) {
arcofi_timer(channel_t *dch) {
arcofi_fsm(dch, ARCOFI_TIMEOUT, NULL);
}
void
clear_arcofi(dchannel_t *dch) {
clear_arcofi(channel_t *dch) {
isac_chip_t *isac = dch->hw;
if (test_and_clear_bit(FLG_ARCOFI_TIMER, &dch->DFlags)) {
if (test_and_clear_bit(FLG_ARCOFI_TIMER, &dch->Flags)) {
del_timer(&isac->arcofitimer);
}
}
void
init_arcofi(dchannel_t *dch) {
init_arcofi(channel_t *dch) {
isac_chip_t *isac = dch->hw;
isac->arcofitimer.function = (void *) arcofi_timer;

View File

@ -27,6 +27,6 @@ struct arcofi_msg {
u_char msg[10];
};
extern int arcofi_fsm(dchannel_t *, int, void *);
extern void init_arcofi(dchannel_t *);
extern void clear_arcofi(dchannel_t *);
extern int arcofi_fsm(channel_t *, int, void *);
extern void init_arcofi(channel_t *);
extern void clear_arcofi(channel_t *);

View File

@ -45,8 +45,8 @@ ParseASN1(u_char *p, u_char *end, int level)
CallASN1(ret, p, end, ParseTag(p, end, &tag));
CallASN1(ret, p, end, ParseLen(p, end, &len));
#ifdef ASN1_DEBUG
for (j = 0; j < level*5; j++) print_msg(PRT_DEBUG_DECODE, " ");
print_msg(PRT_DEBUG_DECODE, "TAG 0x%02x LEN %3d\n", tag, len);
for (j = 0; j < level*5; j++) print_asn1msg(PRT_DEBUG_DECODE, " ");
print_asn1msg(PRT_DEBUG_DECODE, "TAG 0x%02x LEN %3d\n", tag, len);
#endif
if (tag & ASN1_TAG_CONSTRUCTED) {
@ -65,15 +65,15 @@ ParseASN1(u_char *p, u_char *end, int level)
}
}
} else {
for (j = 0; j < level*5; j++) print_msg(PRT_DEBUG_DECODE, " ");
for (j = 0; j < level*5; j++) print_asn1msg(PRT_DEBUG_DECODE, " ");
while (len--) {
print_msg(PRT_DEBUG_DECODE, "%02x ", *p);
print_asn1msg(PRT_DEBUG_DECODE, "%02x ", *p);
p++;
}
print_msg(PRT_DEBUG_DECODE, "\n");
print_asn1msg(PRT_DEBUG_DECODE, "\n");
}
for (j = 0; j < level*5; j++) print_msg(PRT_DEBUG_DECODE, " ");
print_msg(PRT_DEBUG_DECODE, "END (%d)\n", p - beg - 2);
for (j = 0; j < level*5; j++) print_asn1msg(PRT_DEBUG_DECODE, " ");
print_asn1msg(PRT_DEBUG_DECODE, "END (%d)\n", p - beg - 2);
return p - beg;
}

View File

@ -15,6 +15,13 @@ typedef enum {
reject = 4,
} asn1Component;
typedef enum {
GeneralP = 0,
InvokeP = 1,
ReturnResultP= 2,
ReturnErrorP = 3,
} asn1Problem;
struct PublicPartyNumber {
int publicTypeOfNumber;
char numberDigits[30];
@ -88,22 +95,30 @@ struct asn1ReturnError {
__u16 errorValue;
};
struct asn1Reject {
int invokeId;
asn1Problem problem;
__u16 problemValue;
};
struct asn1_parm {
asn1Component comp;
union {
struct asn1Invoke inv;
struct asn1ReturnResult retResult;
struct asn1ReturnError retError;
struct asn1Reject reject;
} u;
};
#undef ASN1_DEBUG
// #define ASN1_DEBUG
#ifdef ASN1_DEBUG
#define print_msg(dummy, fmt, args...) printk(fmt, ## args)
#define print_asn1msg(dummy, fmt, args...) printk(KERN_DEBUG fmt, ## args)
#else
#define print_msg(dummy, fmt, args...)
#define print_asn1msg(dummy, fmt, args...)
#endif
int ParseASN1(u_char *p, u_char *end, int level);
@ -146,7 +161,7 @@ int ParseLen(u_char *p, u_char *end, int *len);
int ret; \
u_char *beg; \
\
print_msg(PRT_DEBUG_DECODE, " DEBUG> %s\n", __FUNCTION__); \
print_asn1msg(PRT_DEBUG_DECODE, " DEBUG> %s\n", __FUNCTION__); \
beg = p; \
CallASN1(ret, p, end, ParseTag(p, end, &tag)); \
CallASN1(ret, p, end, ParseLen(p, end, &len)); \
@ -163,7 +178,7 @@ int ParseLen(u_char *p, u_char *end, int *len);
CallASN1(ret, p, end, todo(pc, p, end, arg1)); \
} else { \
if (!((the_tag) & ASN1_TAG_OPT)) { \
print_msg(PRT_DEBUG_DECODE, " DEBUG> err 1 %s:%d\n", __FUNCTION__, __LINE__); \
print_asn1msg(PRT_DEBUG_DECODE, " DEBUG> err 1 %s:%d\n", __FUNCTION__, __LINE__); \
return -1; \
} \
} \
@ -176,7 +191,7 @@ int ParseLen(u_char *p, u_char *end, int *len);
CallASN1(ret, p, end, todo(pc, p, end, arg1)); \
} else { \
if (!(the_tag) & ASN1_TAG_OPT) { \
print_msg(PRT_DEBUG_DECODE, " DEBUG> err 2 %s:%d\n", __FUNCTION__, __LINE__); \
print_asn1msg(PRT_DEBUG_DECODE, " DEBUG> err 2 %s:%d\n", __FUNCTION__, __LINE__); \
return -1; \
} \
} \
@ -185,7 +200,7 @@ int ParseLen(u_char *p, u_char *end, int *len);
CallASN1(ret, p, end, todo(pc, p, end, arg1)); \
} else { \
if (!(the_tag) & ASN1_TAG_OPT) { \
print_msg(PRT_DEBUG_DECODE, " DEBUG> err 3 %s:%d\n", __FUNCTION__, __LINE__); \
print_asn1msg(PRT_DEBUG_DECODE, " DEBUG> err 3 %s:%d\n", __FUNCTION__, __LINE__); \
return -1; \
} \
} \
@ -193,7 +208,7 @@ int ParseLen(u_char *p, u_char *end, int *len);
} \
} else { \
if (!(the_tag) & ASN1_TAG_OPT) { \
print_msg(PRT_DEBUG_DECODE, " DEBUG> err 4 %s:%d\n", __FUNCTION__, __LINE__); \
print_asn1msg(PRT_DEBUG_DECODE, " DEBUG> err 4 %s:%d\n", __FUNCTION__, __LINE__); \
return -1; \
} \
} \
@ -222,7 +237,7 @@ int ParseLen(u_char *p, u_char *end, int *len);
#define XCHOICE(todo, act_tag, the_tag) XCHOICE_1(todo, act_tag, the_tag, -1)
#define XCHOICE_DEFAULT do {\
print_msg(PRT_DEBUG_DECODE, " DEBUG> err 5 %s:%d\n", __FUNCTION__, __LINE__); \
print_asn1msg(PRT_DEBUG_DECODE, " DEBUG> err 5 %s:%d\n", __FUNCTION__, __LINE__); \
return -1; \
} while (0)

View File

@ -132,11 +132,73 @@ ParseReturnErrorComponent(struct asn1_parm *pc, u_char *p, u_char *end, int dumm
case 48: sprintf(error, "request already accepted"); break;
default: sprintf(error, "(%d)", errorValue); break;
}
print_msg(PRT_DEBUG_DECODE, "ReturnError: %s\n", error);
print_asn1msg(PRT_DEBUG_DECODE, "ReturnError: %s\n", error);
return p - beg;
}
int
ParseProblemValue(struct asn1_parm *pc, u_char *p, u_char *end, asn1Problem prob)
{
INIT;
pc->u.reject.problem = prob;
print_asn1msg(PRT_DEBUG_DECODE, "ParseProblemValue: %d %d\n", prob, *p);
pc->u.reject.problemValue = *p++;
return p - beg;
}
int
ParseRejectProblem(struct asn1_parm *pc, u_char *p, u_char *end)
{
INIT;
XCHOICE_1(ParseProblemValue, ASN1_TAG_CONTEXT_SPECIFIC, 0, GeneralP);
XCHOICE_1(ParseProblemValue, ASN1_TAG_CONTEXT_SPECIFIC, 1, InvokeP);
XCHOICE_1(ParseProblemValue, ASN1_TAG_CONTEXT_SPECIFIC, 2, ReturnResultP);
XCHOICE_1(ParseProblemValue, ASN1_TAG_CONTEXT_SPECIFIC, 3, ReturnErrorP);
XCHOICE_DEFAULT;
}
int
ParseRejectComponent(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
{
int invokeId = -1;
int rval;
INIT;
pc->comp = reject;
XSEQUENCE_OPT_1(ParseInvokeId, ASN1_TAG_INTEGER, ASN1_NOT_TAGGED, &invokeId);
XSEQUENCE_OPT(ParseNull, ASN1_TAG_NULL, ASN1_NOT_TAGGED);
print_asn1msg(PRT_DEBUG_DECODE, "ParseRejectComponent: invokeId %d\n", invokeId);
pc->u.reject.invokeId = invokeId;
rval = ParseRejectProblem(pc, p, end);
print_asn1msg(PRT_DEBUG_DECODE, "ParseRejectComponent: rval %d\n", rval);
if (rval > 0)
p += rval;
else
return(-1);
return p - beg;
}
int
ParseUnknownComponent(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
{
//int invokeId;
INIT;
pc->comp = tag;
return end - beg;
}
int
ParseComponent(struct asn1_parm *pc, u_char *p, u_char *end)
{
@ -145,7 +207,17 @@ ParseComponent(struct asn1_parm *pc, u_char *p, u_char *end)
XCHOICE(ParseInvokeComponent, ASN1_TAG_SEQUENCE, 1);
XCHOICE(ParseReturnResultComponent, ASN1_TAG_SEQUENCE, 2);
XCHOICE(ParseReturnErrorComponent, ASN1_TAG_SEQUENCE, 3);
// XCHOICE(ParseRejectComponent, ASN1_TAG_SEQUENCE, 4);
XCHOICE(ParseRejectComponent, ASN1_TAG_SEQUENCE, 4);
XCHOICE(ParseUnknownComponent, ASN1_TAG_SEQUENCE, 5);
XCHOICE(ParseUnknownComponent, ASN1_TAG_SEQUENCE, 6);
XCHOICE(ParseUnknownComponent, ASN1_TAG_SEQUENCE, 7);
XCHOICE(ParseUnknownComponent, ASN1_TAG_SEQUENCE, 8);
XCHOICE(ParseUnknownComponent, ASN1_TAG_SEQUENCE, 9);
XCHOICE(ParseUnknownComponent, ASN1_TAG_SEQUENCE, 10);
XCHOICE(ParseUnknownComponent, ASN1_TAG_SEQUENCE, 11);
XCHOICE(ParseUnknownComponent, ASN1_TAG_SEQUENCE, 12);
XCHOICE(ParseUnknownComponent, ASN1_TAG_SEQUENCE, 13);
XCHOICE(ParseUnknownComponent, ASN1_TAG_SEQUENCE, 14);
XCHOICE_DEFAULT;
}

View File

@ -39,7 +39,7 @@ ParseARGDeactivationDiversion(struct asn1_parm *pc, u_char *p, u_char *end, int
XSEQUENCE_1(ParseBasicService, ASN1_TAG_ENUM, ASN1_NOT_TAGGED, &basicService);
XSEQUENCE_1(ParseServedUserNr, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED, &servedUserNr);
print_msg(PRT_SHOWNUMBERS, "Deactivation Diversion %d (%d), \n",
print_asn1msg(PRT_SHOWNUMBERS, "Deactivation Diversion %d (%d), \n",
procedure, basicService);
return p - beg;
}
@ -82,7 +82,7 @@ ParseARGInterrogationDiversion(struct asn1_parm *pc, u_char *p, u_char *end, int
XSEQUENCE_1(ParseBasicService, ASN1_TAG_ENUM, ASN1_NOT_TAGGED, &basicService);
XSEQUENCE_1(ParseServedUserNr, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED, &servedUserNr);
print_msg(PRT_SHOWNUMBERS, "Interrogation Diversion %d (%d), \n",
print_asn1msg(PRT_SHOWNUMBERS, "Interrogation Diversion %d (%d), \n",
procedure, basicService);
return p - beg;
}
@ -91,7 +91,7 @@ ParseARGInterrogationDiversion(struct asn1_parm *pc, u_char *p, u_char *end, int
int
ParseRESInterrogationDiversion(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
{
print_msg(PRT_SHOWNUMBERS, "Interrogation Diversion Result\n");
print_asn1msg(PRT_SHOWNUMBERS, "Interrogation Diversion Result\n");
return ParseIntResultList(pc, p, end, &pc->u.retResult.o.resultList);
}
@ -99,7 +99,7 @@ ParseRESInterrogationDiversion(struct asn1_parm *pc, u_char *p, u_char *end, int
int
ParseARGInterrogateServedUserNumbers(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
{
print_msg(PRT_SHOWNUMBERS, "Interrogate Served User Numbers\n");
print_asn1msg(PRT_SHOWNUMBERS, "Interrogate Served User Numbers\n");
return 0;
}
#endif
@ -113,7 +113,7 @@ ParseRESInterrogateServedUserNumbers(struct asn1_parm *pc, u_char *p, u_char *en
if (ret < 0)
return ret;
print_msg(PRT_SHOWNUMBERS, "Interrogate Served User Numbers:\n");
print_asn1msg(PRT_SHOWNUMBERS, "Interrogate Served User Numbers:\n");
return ret;
}
@ -144,7 +144,7 @@ ParseARGDiversionInformation(struct asn1_parm *pc, u_char *p, u_char *end, int d
XSEQUENCE_OPT_1(ParsePresentedNumberUnscreened, ASN1_NOT_TAGGED, 2 | ASN1_TAG_EXPLICIT, lastDivertingNr);
XSEQUENCE_OPT_1(ParseDiversionReason, ASN1_TAG_ENUM, 3 | ASN1_TAG_EXPLICIT, lastDivertingReason);
// XSEQUENCE_OPT_1(ParseQ931InformationElement, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED, userInfo);
print_msg(PRT_SHOWNUMBERS, "Diversion Information %s(%d) %s\n"
print_asn1msg(PRT_SHOWNUMBERS, "Diversion Information %s(%d) %s\n"
" callingAddress %s originalCalled Nr %s\n"
" lastDivertingNr %s lastDiverting Reason %s\n",
diversionReason, basicService, servedUserSubaddress, callingAddress,

View File

@ -2,7 +2,7 @@
*
*/
#include "capi.h"
#include "m_capi.h"
#include "helper.h"
#include "asn1_enc.h"
@ -13,6 +13,14 @@ int encodeNull(__u8 *dest)
return 2;
}
int encodeBoolean(__u8 *dest, __u32 i)
{
dest[0] = 0x01; // BOOLEAN
dest[1] = 1; // length 1
dest[3] = i ? 1:0; // Value
return 3;
}
int encodeInt(__u8 *dest, __u32 i)
{
__u8 *p;
@ -176,3 +184,18 @@ int encodeInterrogationDiversion(__u8 *dest, struct FacReqCFInterrogateParameter
return p - dest;
}
int encodeInvokeDeflection(__u8 *dest, struct FacReqCDeflection *CD)
{
__u8 *p;
dest[0] = 0x30; // sequence
dest[1] = 0; // length
p = &dest[2];
p += encodeAddress(p, CD->DeflectedToNumber, CD->DeflectedToSubaddress);
p += encodeBoolean(p, CD->PresentationAllowed);
dest[1] = p - &dest[2];
return p - dest;
}

View File

@ -5,6 +5,7 @@
#include "asn1.h"
int encodeNull(__u8 *dest);
int encodeBoolean(__u8 *dest, __u32 i);
int encodeInt(__u8 *dest, __u32 i);
int encodeEnum(__u8 *dest, __u32 i);
int encodeNumberDigits(__u8 *dest, __u8 *nd, __u8 len);
@ -15,3 +16,4 @@ int encodeAddress(__u8 *dest, __u8 *facilityPartyNumber, __u8 *calledPartySubadd
int encodeActivationDiversion(__u8 *dest, struct FacReqCFActivate *CFActivate);
int encodeDeactivationDiversion(__u8 *dest,struct FacReqCFDeactivate *CFDeactivate);
int encodeInterrogationDiversion(__u8 *dest, struct FacReqCFInterrogateParameters *params);
int encodeInvokeDeflection(__u8 *dest, struct FacReqCDeflection *CD);

View File

@ -19,7 +19,7 @@ ParseBoolean(struct asn1_parm *pc, u_char *p, u_char *end, int *i)
*i = (*i >> 8) + *p;
p++;
}
print_msg(PRT_DEBUG_DECODE, " DEBUG> BOOL = %d %#x\n", *i, *i);
print_asn1msg(PRT_DEBUG_DECODE, " DEBUG> BOOL = %d %#x\n", *i, *i);
return p - beg;
}
@ -42,7 +42,7 @@ ParseInteger(struct asn1_parm *pc, u_char *p, u_char *end, int *i)
*i = (*i << 8) + *p;
p++;
}
print_msg(PRT_DEBUG_DECODE, " DEBUG> INT = %d %#x\n", *i, *i);
print_asn1msg(PRT_DEBUG_DECODE, " DEBUG> INT = %d %#x\n", *i, *i);
return p - beg;
}
@ -57,7 +57,7 @@ ParseEnum(struct asn1_parm *pc, u_char *p, u_char *end, int *i)
*i = (*i << 8) + *p;
p++;
}
print_msg(PRT_DEBUG_DECODE, " DEBUG> ENUM = %d %#x\n", *i, *i);
print_asn1msg(PRT_DEBUG_DECODE, " DEBUG> ENUM = %d %#x\n", *i, *i);
return p - beg;
}
@ -67,14 +67,14 @@ ParseIA5String(struct asn1_parm *pc, u_char *p, u_char *end, char *str)
{
INIT;
print_msg(PRT_DEBUG_DECODE, " DEBUG> IA5 = ");
print_asn1msg(PRT_DEBUG_DECODE, " DEBUG> IA5 = ");
while (len--) {
CHECK_P;
print_msg(PRT_DEBUG_DECODE, "%c", *p);
print_asn1msg(PRT_DEBUG_DECODE, "%c", *p);
*str++ = *p;
p++;
}
print_msg(PRT_DEBUG_DECODE, "\n");
print_asn1msg(PRT_DEBUG_DECODE, "\n");
*str = 0;
return p - beg;
}
@ -85,14 +85,14 @@ ParseNumericString(struct asn1_parm *pc, u_char *p, u_char *end, char *str)
{
INIT;
print_msg(PRT_DEBUG_DECODE, " DEBUG> NumStr = ");
print_asn1msg(PRT_DEBUG_DECODE, " DEBUG> NumStr = ");
while (len--) {
CHECK_P;
print_msg(PRT_DEBUG_DECODE, "%c", *p);
print_asn1msg(PRT_DEBUG_DECODE, "%c", *p);
*str++ = *p;
p++;
}
print_msg(PRT_DEBUG_DECODE, "\n");
print_asn1msg(PRT_DEBUG_DECODE, "\n");
*str = 0;
return p - beg;
}
@ -102,14 +102,14 @@ ParseOctetString(struct asn1_parm *pc, u_char *p, u_char *end, char *str)
{
INIT;
print_msg(PRT_DEBUG_DECODE, " DEBUG> Octets = ");
print_asn1msg(PRT_DEBUG_DECODE, " DEBUG> Octets = ");
while (len--) {
CHECK_P;
print_msg(PRT_DEBUG_DECODE, " %02x", *p);
print_asn1msg(PRT_DEBUG_DECODE, " %02x", *p);
*str++ = *p;
p++;
}
print_msg(PRT_DEBUG_DECODE, "\n");
print_asn1msg(PRT_DEBUG_DECODE, "\n");
*str = 0;
return p - beg;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,150 +0,0 @@
/* $Id$
*
* Author Karsten Keil (keil@isdn4linux.de)
*
* This file is (c) under GNU PUBLIC LICENSE
*
*/
#define __NO_VERSION__
#include <linux/mISDNif.h>
#include "layer1.h"
#include "bchannel.h"
#include "helper.h"
static void
bchannel_bh(bchannel_t *bch)
{
struct sk_buff *skb;
u_int pr;
int ret;
mISDN_head_t *hh;
mISDNif_t *hif;
if (!bch)
return;
if (!bch->inst.up.func) {
printk(KERN_WARNING "%s: without up.func\n", __FUNCTION__);
return;
}
#if 0
printk(KERN_DEBUG "%s: event %x\n", __FUNCTION__, bch->event);
if (bch->dev)
printk(KERN_DEBUG "%s: rpflg(%x) wpflg(%x)\n", __FUNCTION__,
bch->dev->rport.Flag, bch->dev->wport.Flag);
#endif
if (test_and_clear_bit(B_XMTBUFREADY, &bch->event)) {
skb = bch->next_skb;
if (skb) {
hh = mISDN_HEAD_P(skb);
bch->next_skb = NULL;
if (bch->inst.pid.protocol[2] == ISDN_PID_L2_B_TRANS)
pr = DL_DATA | CONFIRM;
else
pr = PH_DATA | CONFIRM;
if ((bch->inst.pid.protocol[2] == ISDN_PID_L2_B_RAWDEV)
&& bch->dev)
hif = &bch->dev->rport.pif;
else
hif = &bch->inst.up;
if (if_newhead(hif, pr, hh->dinfo, skb))
dev_kfree_skb(skb);
}
}
if (test_and_clear_bit(B_RCVBUFREADY, &bch->event)) {
if ((bch->inst.pid.protocol[2] == ISDN_PID_L2_B_RAWDEV)
&& bch->dev)
hif = &bch->dev->rport.pif;
else
hif = &bch->inst.up;
while ((skb = skb_dequeue(&bch->rqueue))) {
if (bch->inst.pid.protocol[2] == ISDN_PID_L2_B_TRANS)
pr = DL_DATA | INDICATION;
else
pr = PH_DATA | INDICATION;
ret = if_newhead(hif, pr, DINFO_SKB, skb);
if (ret < 0) {
printk(KERN_WARNING "%s: deliver err %d\n",
__FUNCTION__, ret);
dev_kfree_skb(skb);
}
}
}
if (bch->hw_bh)
bch->hw_bh(bch);
}
int
init_bchannel(bchannel_t *bch) {
int devtyp = mISDN_RAW_DEVICE;
if (!(bch->blog = kmalloc(MAX_BLOG_SPACE, GFP_ATOMIC))) {
printk(KERN_WARNING
"mISDN: No memory for blog\n");
return(-ENOMEM);
}
if (!(bch->rx_buf = kmalloc(MAX_DATA_MEM, GFP_ATOMIC))) {
printk(KERN_WARNING
"mISDN: No memory for bchannel rx_buf\n");
kfree(bch->blog);
bch->blog = NULL;
return (-ENOMEM);
}
if (!(bch->tx_buf = kmalloc(MAX_DATA_MEM, GFP_ATOMIC))) {
printk(KERN_WARNING
"mISDN: No memory for bchannel tx_buf\n");
kfree(bch->blog);
bch->blog = NULL;
kfree(bch->rx_buf);
bch->rx_buf = NULL;
return (-ENOMEM);
}
skb_queue_head_init(&bch->rqueue);
bch->next_skb = NULL;
bch->Flag = 0;
bch->event = 0;
bch->rx_idx = 0;
bch->tx_len = 0;
bch->tx_idx = 0;
bch->tqueue.data = bch;
bch->tqueue.routine = (void *) (void *) bchannel_bh;
bch->hw_bh = NULL;
if (!bch->dev) {
if (bch->inst.obj->ctrl(&bch->dev, MGR_GETDEVICE | REQUEST,
&devtyp)) {
printk(KERN_WARNING
"mISDN: no raw device for bchannel\n");
}
}
return(0);
}
int
free_bchannel(bchannel_t *bch) {
if (bch->tqueue.sync)
printk(KERN_ERR"free_bchannel tqueue.sync\n");
discard_queue(&bch->rqueue);
if (bch->blog) {
kfree(bch->blog);
bch->blog = NULL;
}
if (bch->rx_buf) {
kfree(bch->rx_buf);
bch->rx_buf = NULL;
}
if (bch->tx_buf) {
kfree(bch->tx_buf);
bch->tx_buf = NULL;
}
if (bch->next_skb) {
dev_kfree_skb(bch->next_skb);
bch->next_skb = NULL;
}
if (bch->inst.obj->ctrl(bch->dev, MGR_DELDEVICE | REQUEST, NULL)) {
printk(KERN_WARNING
"mISDN: del raw device error\n");
} else
bch->dev = NULL;
return(0);
}

View File

@ -1,81 +0,0 @@
/* $Id$
*
* Basic declarations, defines for Bchannel hardware
*
* This file is (c) under GNU PUBLIC LICENSE
*
*/
#include <linux/mISDNif.h>
#include <linux/tqueue.h>
#include <linux/smp.h>
#include <linux/ptrace.h>
#include <linux/interrupt.h>
#include <linux/timer.h>
#include <asm/io.h>
#include <linux/ioport.h>
#include <linux/skbuff.h>
#ifdef MEMDBG
#include "memdbg.h"
#endif
#define MAX_BLOG_SPACE 256
#define BC_FLG_INIT 1
#define BC_FLG_ACTIV 2
#define BC_FLG_TX_BUSY 3
#define BC_FLG_NOFRAME 4
#define BC_FLG_HALF 5
#define BC_FLG_EMPTY 6
#define BC_FLG_ORIG 7
#define BC_FLG_DLEETX 8
#define BC_FLG_LASTDLE 9
#define BC_FLG_FIRST 10
#define BC_FLG_LASTDATA 11
#define BC_FLG_NMD_DATA 12
#define BC_FLG_FTI_RUN 13
#define BC_FLG_LL_OK 14
#define BC_FLG_LL_CONN 15
#define BC_FLG_TX_NEXT 16
#define BC_FLG_DTMFSEND 17
typedef struct _bchannel_t {
int channel;
int protocol;
int Flag;
int debug;
mISDNstack_t *st;
mISDNinstance_t inst;
mISDNdevice_t *dev;
void *hw;
u_char (*Read_Reg)(void *, int, u_char);
void (*Write_Reg)(void *, int, u_char, u_char);
struct sk_buff *next_skb;
u_char *tx_buf;
int tx_idx;
int tx_len;
u_char *rx_buf;
int rx_idx;
struct sk_buff_head rqueue; /* B-Channel receive Queue */
u_char *blog;
u_char *conmsg;
struct timer_list transbusy;
struct tq_struct tqueue;
void (*hw_bh) (struct _bchannel_t *);
int event;
int err_crc;
int err_tx;
int err_rdo;
int err_inv;
} bchannel_t;
extern int init_bchannel(bchannel_t *);
extern int free_bchannel(bchannel_t *);
static inline void
bch_sched_event(bchannel_t *bch, int event)
{
test_and_set_bit(event, &bch->event);
queue_task(&bch->tqueue, &tq_immediate);
mark_bh(IMMEDIATE_BH);
}

View File

@ -3,9 +3,8 @@
*/
#include <linux/module.h>
#include <linux/vmalloc.h>
#include <asm/uaccess.h>
#include "capi.h"
#include "core.h"
#include "m_capi.h"
#include "helper.h"
#include "debug.h"
@ -14,7 +13,6 @@ static char *capi_revision = "$Revision$";
static int debug = 0;
static mISDNobject_t capi_obj;
static char MName[] = "mISDN Capi 2.0";
#ifdef MODULE
@ -22,8 +20,11 @@ MODULE_AUTHOR("Karsten Keil");
#ifdef MODULE_LICENSE
MODULE_LICENSE("GPL");
#endif
#ifdef OLD_MODULE_PARAM
MODULE_PARM(debug, "1i");
#define Capi20Init init_module
#else
module_param(debug, uint, S_IRUGO | S_IWUSR);
#endif
#endif
static char deb_buf[256];
@ -40,131 +41,271 @@ void capidebug(int level, char *fmt, ...)
}
}
// ---------------------------------------------------------------------------
// registration to kernelcapi
int mISDN_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
{
Contr_t *contr = ctrl->driverdata;
u_char *tmp;
int retval;
if (CAPI_DBG_INFO & debug) {
printk(KERN_INFO "%s: firm user(%d) len(%d)\n", __FUNCTION__,
data->firmware.user, data->firmware.len);
printk(KERN_INFO "%s: cfg user(%d) len(%d)\n", __FUNCTION__,
data->configuration.user, data->configuration.len);
}
if (data->firmware.user) {
tmp = vmalloc(data->firmware.len);
if (!tmp)
return(-ENOMEM);
retval = copy_from_user(tmp, data->firmware.data,
data->firmware.len);
if (retval)
return(retval);
} else
tmp = data->firmware.data;
contrLoadFirmware(contr, data->firmware.len, tmp);
if (data->firmware.user)
vfree(tmp);
return 0;
}
void mISDN_reset_ctr(struct capi_ctr *ctrl)
{
Contr_t *contr = ctrl->driverdata;
if (CAPI_DBG_INFO & debug)
printk(KERN_DEBUG "%s\n", __FUNCTION__);
contrReset(contr);
}
void mISDN_remove_ctr(struct capi_ctr *ctrl)
{
if (CAPI_DBG_INFO & debug)
printk(KERN_DEBUG "%s\n", __FUNCTION__);
}
static char *mISDN_procinfo(struct capi_ctr *ctrl)
{
Contr_t *contr = (ctrl->driverdata);
if (CAPI_DBG_INFO & debug)
printk(KERN_DEBUG "%s\n", __FUNCTION__);
if (!contr)
return "";
sprintf(contr->infobuf, "-");
return contr->infobuf;
}
void mISDN_register_appl(struct capi_ctr *ctrl,
__u16 ApplId, capi_register_params *rp)
{
Contr_t *contr = ctrl->driverdata;
if (CAPI_DBG_INFO & debug)
printk(KERN_DEBUG "%s\n", __FUNCTION__);
contrRegisterAppl(contr, ApplId, rp);
}
void mISDN_release_appl(struct capi_ctr *ctrl, __u16 ApplId)
{
Contr_t *contr = ctrl->driverdata;
if (CAPI_DBG_INFO & debug)
printk(KERN_DEBUG "%s\n", __FUNCTION__);
contrReleaseAppl(contr, ApplId);
}
void mISDN_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
{
Contr_t *contr = ctrl->driverdata;
contrSendMessage(contr, skb);
}
static int mISDN_read_proc(char *page, char **start, off_t off,
int count, int *eof, struct capi_ctr *ctrl)
{
int len = 0;
len += sprintf(page+len, "mISDN_read_proc\n");
if (off+count >= len)
*eof = 1;
if (len < off)
return 0;
*start = page + off;
return ((count < len-off) ? count : len-off);
};
#ifdef OLDCAPI_DRIVER_INTERFACE
struct capi_driver_interface *cdrv_if;
#endif
struct capi_driver mISDN_driver = {
"mISDN",
"0.01",
mISDN_load_firmware,
mISDN_reset_ctr,
mISDN_remove_ctr,
mISDN_register_appl,
mISDN_release_appl,
mISDN_send_message,
mISDN_procinfo,
mISDN_read_proc,
0,
0,
};
kmem_cache_t *mISDN_cmsg_cp;
kmem_cache_t *mISDN_AppPlci_cp;
kmem_cache_t *mISDN_ncci_cp;
kmem_cache_t *mISDN_sspc_cp;
int CapiNew(void)
#ifdef MISDN_KMEM_DEBUG
static struct list_head mISDN_kmem_garbage = LIST_HEAD_INIT(mISDN_kmem_garbage);
_cmsg *
_kd_cmsg_alloc(char *fn, int line)
{
printk(KERN_INFO "new %s instance\n", MName);
_kd_cmsg_t *ki = kmem_cache_alloc(mISDN_cmsg_cp, GFP_ATOMIC);
if (!ki)
return(NULL);
ki->kdi.typ = KM_DBG_TYP_CM;
INIT_LIST_HEAD(&ki->kdi.head);
ki->kdi.line = line;
ki->kdi.file = fn;
list_add_tail(&ki->kdi.head, &mISDN_kmem_garbage);
return(&ki->cm);
}
void
cmsg_free(_cmsg *cm)
{
km_dbg_item_t *kdi;
if (!cm) {
int_errtxt("zero pointer free at %p", __builtin_return_address(0));
return;
}
kdi = KDB_GET_KDI(cm);
list_del(&kdi->head);
kmem_cache_free(mISDN_cmsg_cp, kdi);
}
AppPlci_t *
_kd_AppPlci_alloc(char *fn, int line)
{
_kd_AppPlci_t *ki = kmem_cache_alloc(mISDN_AppPlci_cp, GFP_ATOMIC);
if (!ki)
return(NULL);
ki->kdi.typ = KM_DBG_TYP_AP;
INIT_LIST_HEAD(&ki->kdi.head);
ki->kdi.line = line;
ki->kdi.file = fn;
list_add_tail(&ki->kdi.head, &mISDN_kmem_garbage);
return(&ki->ap);
}
void
AppPlci_free(AppPlci_t *ap)
{
km_dbg_item_t *kdi;
if (!ap) {
int_errtxt("zero pointer free at %p", __builtin_return_address(0));
return;
}
kdi = KDB_GET_KDI(ap);
list_del(&kdi->head);
kmem_cache_free(mISDN_AppPlci_cp, kdi);
}
Ncci_t *
_kd_ncci_alloc(char *fn, int line)
{
_kd_Ncci_t *ki = kmem_cache_alloc(mISDN_ncci_cp, GFP_ATOMIC);
if (!ki)
return(NULL);
ki->kdi.typ = KM_DBG_TYP_NI;
INIT_LIST_HEAD(&ki->kdi.head);
ki->kdi.line = line;
ki->kdi.file = fn;
list_add_tail(&ki->kdi.head, &mISDN_kmem_garbage);
return(&ki->ni);
}
void
ncci_free(Ncci_t *ni)
{
km_dbg_item_t *kdi;
if (!ni) {
int_errtxt("zero pointer free at %p", __builtin_return_address(0));
return;
}
kdi = KDB_GET_KDI(ni);
list_del(&kdi->head);
kmem_cache_free(mISDN_ncci_cp, kdi);
}
SSProcess_t *
_kd_SSProcess_alloc(char *fn, int line)
{
_kd_SSProcess_t *ki = kmem_cache_alloc(mISDN_sspc_cp, GFP_ATOMIC);
if (!ki)
return(NULL);
ki->kdi.typ = KM_DBG_TYP_SP;
INIT_LIST_HEAD(&ki->kdi.head);
ki->kdi.line = line;
ki->kdi.file = fn;
list_add_tail(&ki->kdi.head, &mISDN_kmem_garbage);
return(&ki->sp);
}
void
SSProcess_free(SSProcess_t *sp)
{
km_dbg_item_t *kdi;
if (!sp) {
int_errtxt("zero pointer free at %p", __builtin_return_address(0));
return;
}
kdi = KDB_GET_KDI(sp);
list_del(&kdi->head);
kmem_cache_free(mISDN_sspc_cp, kdi);
}
static void
free_garbage(void)
{
struct list_head *item, *next;
_kd_all_t *kda;
list_for_each_safe(item, next, &mISDN_kmem_garbage) {
kda = (_kd_all_t *)item;
printk(KERN_DEBUG "garbage item found (%p <- %p -> %p) type%ld allocated at %s:%d\n",
kda->kdi.head.prev, item, kda->kdi.head.next, kda->kdi.typ, kda->kdi.file, kda->kdi.line);
list_del(item);
switch(kda->kdi.typ) {
case KM_DBG_TYP_CM:
printk(KERN_DEBUG "cmsg cmd(%x,%x) appl(%x) addr(%x) nr(%d)\n",
kda->a.cm.Command,
kda->a.cm.Subcommand,
kda->a.cm.ApplId,
kda->a.cm.adr.adrController,
kda->a.cm.Messagenumber);
kmem_cache_free(mISDN_cmsg_cp, item);
break;
case KM_DBG_TYP_AP:
printk(KERN_DEBUG "AppPlci: PLCI(%x) m.state(%x) appl(%p)\n",
kda->a.ap.addr,
kda->a.ap.plci_m.state,
kda->a.ap.appl);
kmem_cache_free(mISDN_AppPlci_cp, item);
break;
case KM_DBG_TYP_NI:
printk(KERN_DEBUG "Ncci: NCCI(%x) state(%lx) m.state(%x) aplci(%p)\n",
kda->a.ni.addr,
kda->a.ni.state,
kda->a.ni.ncci_m.state,
kda->a.ni.AppPlci);
kmem_cache_free(mISDN_ncci_cp, item);
break;
case KM_DBG_TYP_SP:
printk(KERN_DEBUG "SSPc: addr(%x) id(%x) apid(%x) func(%x)\n",
kda->a.sp.addr,
kda->a.sp.invokeId,
kda->a.sp.ApplId,
kda->a.sp.Function);
kmem_cache_free(mISDN_sspc_cp, item);
break;
default:
printk(KERN_DEBUG "unknown garbage item(%p) type %ld\n",
item, kda->kdi.typ);
break;
}
}
}
#endif
static void CapiCachesFree(void)
{
#ifdef MISDN_KMEM_DEBUG
free_garbage();
#endif
if (mISDN_cmsg_cp) {
kmem_cache_destroy(mISDN_cmsg_cp);
mISDN_cmsg_cp = NULL;
}
if (mISDN_AppPlci_cp) {
kmem_cache_destroy(mISDN_AppPlci_cp);
mISDN_AppPlci_cp = NULL;
}
if (mISDN_ncci_cp) {
kmem_cache_destroy(mISDN_ncci_cp);
mISDN_ncci_cp = NULL;
}
if (mISDN_sspc_cp) {
kmem_cache_destroy(mISDN_sspc_cp);
mISDN_sspc_cp = NULL;
}
}
static int CapiNew(void)
{
mISDN_cmsg_cp = NULL;
mISDN_AppPlci_cp = NULL;
mISDN_ncci_cp = NULL;
mISDN_sspc_cp = NULL;
mISDN_cmsg_cp = kmem_cache_create("mISDN_cmesg",
#ifdef MISDN_KMEM_DEBUG
sizeof(_kd_cmsg_t),
#else
sizeof(_cmsg),
#endif
0, 0, NULL, NULL);
if (!mISDN_cmsg_cp) {
CapiCachesFree();
return(-ENOMEM);
}
mISDN_AppPlci_cp = kmem_cache_create("mISDN_AppPlci",
#ifdef MISDN_KMEM_DEBUG
sizeof(_kd_AppPlci_t),
#else
sizeof(AppPlci_t),
#endif
0, 0, NULL, NULL);
if (!mISDN_AppPlci_cp) {
CapiCachesFree();
return(-ENOMEM);
}
mISDN_ncci_cp = kmem_cache_create("mISDN_Ncci",
#ifdef MISDN_KMEM_DEBUG
sizeof(_kd_Ncci_t),
#else
sizeof(Ncci_t),
#endif
0, 0, NULL, NULL);
if (!mISDN_ncci_cp) {
CapiCachesFree();
return(-ENOMEM);
}
mISDN_sspc_cp = kmem_cache_create("mISDN_SSProc",
#ifdef MISDN_KMEM_DEBUG
sizeof(_kd_SSProcess_t),
#else
sizeof(SSProcess_t),
#endif
0, 0, NULL, NULL);
if (!mISDN_sspc_cp) {
CapiCachesFree();
return(-ENOMEM);
}
#ifdef OLDCAPI_DRIVER_INTERFACE
cdrv_if = attach_capi_driver(&mISDN_driver);
if (!cdrv_if) {
CapiCachesFree();
printk(KERN_ERR "mISDN: failed to attach capi_driver\n");
return -EIO;
}
#endif
init_listen();
init_cplci();
init_AppPlci();
init_ncci();
return 0;
}
@ -173,87 +314,81 @@ static int
capi20_manager(void *data, u_int prim, void *arg) {
mISDNinstance_t *inst = data;
int found=0;
BInst_t *binst = NULL;
Contr_t *ctrl = (Contr_t *)capi_obj.ilist;
PLInst_t *plink = NULL;
Controller_t *ctrl;
u_long flags;
if (CAPI_DBG_INFO & debug)
printk(KERN_DEBUG "capi20_manager data:%p prim:%x arg:%p\n", data, prim, arg);
if (!data)
return(-EINVAL);
while(ctrl) {
spin_lock_irqsave(&capi_obj.lock, flags);
list_for_each_entry(ctrl, &capi_obj.ilist, list) {
if (&ctrl->inst == inst) {
found++;
break;
}
binst = ctrl->binst;
while(binst) {
if (&binst->inst == inst) {
list_for_each_entry(plink, &ctrl->linklist, list) {
if (&plink->inst == inst) {
found++;
break;
}
binst = binst->next;
}
if (found)
break;
ctrl = ctrl->next;
plink = NULL;
}
switch(prim) {
case MGR_NEWLAYER | REQUEST:
if (!(ctrl = newContr(&capi_obj, data, arg)))
return(-EINVAL);
else
if (&ctrl->list == &capi_obj.ilist)
ctrl = NULL;
spin_unlock_irqrestore(&capi_obj.lock, flags);
if (prim == (MGR_NEWLAYER | REQUEST)) {
int ret = ControllerConstr(&ctrl, data, arg, &capi_obj);
if (!ret)
ctrl->debug = debug;
break;
case MGR_CONNECT | REQUEST:
if (!ctrl) {
if (CAPI_DBG_WARN & debug)
printk(KERN_WARNING "capi20_manager connect no instance\n");
return(-EINVAL);
return(ret);
}
return(ConnectIF(inst, arg));
break;
case MGR_SETIF | INDICATION:
case MGR_SETIF | REQUEST:
if (!ctrl) {
if (CAPI_DBG_WARN & debug)
printk(KERN_WARNING "capi20_manager setif no instance\n");
return(-EINVAL);
}
if (&ctrl->inst == inst)
return(SetIF(inst, arg, prim, NULL, contrL3L4, ctrl));
else
return(SetIF(inst, arg, prim, NULL, ncci_l3l4, inst->data));
switch(prim) {
case MGR_NEWENTITY | CONFIRM:
ctrl->entity = (u_long)arg & 0xffffffff;
break;
#ifdef FIXME
case MGR_CONNECT | REQUEST:
return(mISDN_ConnectIF(inst, arg));
case MGR_SETIF | INDICATION:
case MGR_SETIF | REQUEST:
if (&ctrl->inst == inst)
return(mISDN_SetIF(inst, arg, prim, NULL, ControllerL3L4, ctrl));
else
return(AppPlcimISDN_SetIF(inst->data, prim, arg));
case MGR_DISCONNECT | REQUEST:
case MGR_DISCONNECT | INDICATION:
if (!ctrl) {
if (CAPI_DBG_WARN & debug)
printk(KERN_WARNING "capi20_manager disconnect no instance\n");
return(-EINVAL);
}
return(DisConnectIF(inst, arg));
break;
return(mISDN_DisConnectIF(inst, arg));
#endif
case MGR_SETSTACK | INDICATION:
if (!(&ctrl->inst == inst))
return(AppPlcimISDN_Active(inst->privat));
return(0);
case MGR_RELEASE | INDICATION:
if (ctrl) {
if (CAPI_DBG_INFO & debug)
printk(KERN_DEBUG "release_capi20 id %x\n", ctrl->inst.st->id);
contrDestr(ctrl);
kfree(ctrl);
} else if (CAPI_DBG_WARN & debug)
printk(KERN_WARNING "capi20_manager release no instance\n");
ControllerDestr(ctrl);
break;
case MGR_UNREGLAYER | REQUEST:
if (!ctrl) {
if (CAPI_DBG_WARN & debug)
printk(KERN_WARNING "capi20_manager unreglayer no instance\n");
return(-EINVAL);
}
if (binst) {
capi_obj.ctrl(binst->inst.down.peer, MGR_DISCONNECT | REQUEST,
&binst->inst.down);
capi_obj.ctrl(&binst->inst, MGR_UNREGLAYER | REQUEST, NULL);
if (plink) {
plink->inst.function = NULL;
mISDN_ctrl(&plink->inst, MGR_UNREGLAYER | REQUEST, NULL);
}
break;
case MGR_CTRLREADY | INDICATION:
if (CAPI_DBG_INFO & debug)
printk(KERN_DEBUG "ctrl %x ready\n", ctrl->inst.st->id);
ControllerRun(ctrl);
break;
default:
if (CAPI_DBG_WARN & debug)
printk(KERN_WARNING "capi20_manager prim %x not handled\n", prim);
@ -267,46 +402,59 @@ int Capi20Init(void)
int err;
printk(KERN_INFO "%s driver file version %s\n", MName, mISDN_getrev(capi_revision));
SET_MODULE_OWNER(&capi_obj);
#ifdef MODULE
capi_obj.owner = THIS_MODULE;
#endif
capi_obj.name = MName;
capi_obj.DPROTO.protocol[4] = ISDN_PID_L4_CAPI20;
capi_obj.BPROTO.protocol[4] = ISDN_PID_L4_B_CAPI20;
capi_obj.BPROTO.protocol[3] = ISDN_PID_L3_B_TRANS;
capi_obj.own_ctrl = capi20_manager;
capi_obj.prev = NULL;
capi_obj.next = NULL;
capi_obj.ilist = NULL;
spin_lock_init(&capi_obj.lock);
INIT_LIST_HEAD(&capi_obj.ilist);
if ((err = CapiNew()))
return(err);
if ((err = mISDN_register(&capi_obj))) {
printk(KERN_ERR "Can't register %s error(%d)\n", MName, err);
#ifdef OLDCAPI_DRIVER_INTERFACE
detach_capi_driver(&mISDN_driver);
#endif
CapiCachesFree();
free_listen();
free_cplci();
free_AppPlci();
free_ncci();
}
free_Application();
} else
mISDN_module_register(THIS_MODULE);
return(err);
}
#ifdef MODULE
void cleanup_module(void)
static void Capi20cleanup(void)
{
int err;
Contr_t *contr;
Controller_t *contr, *next;
mISDN_module_unregister(THIS_MODULE);
if ((err = mISDN_unregister(&capi_obj))) {
printk(KERN_ERR "Can't unregister User DSS1 error(%d)\n", err);
}
if (capi_obj.ilist) {
printk(KERN_WARNING "mISDNl3 contrlist not empty\n");
while((contr = capi_obj.ilist)) {
contrDestr(contr);
kfree(contr);
printk(KERN_ERR "Can't unregister CAPI20 error(%d)\n", err);
}
if (!list_empty(&capi_obj.ilist)) {
printk(KERN_WARNING "mISDN controller list not empty\n");
list_for_each_entry_safe(contr, next, &capi_obj.ilist, list)
ControllerDestr(contr);
}
#ifdef OLDCAPI_DRIVER_INTERFACE
detach_capi_driver(&mISDN_driver);
#endif
free_Application();
CapiCachesFree();
free_listen();
free_cplci();
free_AppPlci();
free_ncci();
}
module_init(Capi20Init);
module_exit(Capi20cleanup);
#endif

View File

@ -1,382 +0,0 @@
/* $Id$
*
*/
#ifndef __mISDN_CAPI_H__
#define __mISDN_CAPI_H__
#include <linux/mISDNif.h>
#include <linux/skbuff.h>
#include <linux/timer.h>
#include <linux/capi.h>
#include <linux/kernelcapi.h>
#include "../avmb1/capiutil.h"
#include "../avmb1/capicmd.h"
#include "../avmb1/capilli.h"
#include "asn1.h"
#include "fsm.h"
#ifdef MEMDBG
#include "memdbg.h"
#endif
// ---------------------------------------------------------------------------
// common stuff
#define CAPI_DBG_WARN 0x00000001
#define CAPI_DBG_INFO 0x00000004
#define CAPI_DBG_APPL 0x00000010
#define CAPI_DBG_APPL_INFO 0x00000040
#define CAPI_DBG_LISTEN 0x00000100
#define CAPI_DBG_LISTEN_STATE 0x00000200
#define CAPI_DBG_LISTEN_INFO 0x00000400
#define CAPI_DBG_CONTR 0x00010000
#define CAPI_DBG_PLCI 0x00100000
#define CAPI_DBG_PLCI_STATE 0x00200000
#define CAPI_DBG_PLCI_INFO 0x00400000
#define CAPI_DBG_PLCI_L3 0x00800000
#define CAPI_DBG_NCCI 0x01000000
#define CAPI_DBG_NCCI_STATE 0x02000000
#define CAPI_DBG_NCCI_INFO 0x04000000
#define CAPI_DBG_NCCI_L3 0x08000000
extern struct capi_driver_interface *cdrv_if;
extern struct capi_driver mISDN_driver;
void init_listen(void);
void init_cplci(void);
void init_ncci(void);
void free_listen(void);
void free_cplci(void);
void free_ncci(void);
void capidebug(int, char *, ...);
#define SuppServiceCF 0x00000010
#define SuppServiceTP 0x00000002
#define mISDNSupportedServices (SuppServiceCF | SuppServiceTP)
#define CAPIMSG_REQ_DATAHANDLE(m) (m[18] | (m[19]<<8))
#define CAPIMSG_RESP_DATAHANDLE(m) (m[12] | (m[13]<<8))
#define CMSGCMD(cmsg) CAPICMD((cmsg)->Command, (cmsg)->Subcommand)
#define CAPI_MAXPLCI 5
#define CAPI_MAXDUMMYPCS 16
struct Bprotocol {
__u16 B1protocol;
__u16 B2protocol;
__u16 B3protocol;
};
__u16 q931CIPValue(Q931_info_t *);
typedef struct _DummyProcess {
__u16 invokeId;
__u16 Function;
__u32 Handle;
__u32 adrDummy;
__u16 ApplId;
struct _Contr *contr;
struct timer_list tl;
__u8 buf[128];
} DummyProcess_t;
void dummyPcConstr(DummyProcess_t *dummy_pc, struct _Contr *contr, __u16 invokeId);
void dummyPcDestr(DummyProcess_t *dummy_pc);
void dummyPcAddTimer(DummyProcess_t *dummy_pc, int msec);
int capiEncodeFacIndSuspend(__u8 *dest, __u16 SupplementaryServiceReason);
struct FacReqListen {
__u32 NotificationMask;
};
struct FacReqSuspend {
__u8 *CallIdentity;
};
struct FacReqResume {
__u8 *CallIdentity;
};
struct FacReqCFActivate {
__u32 Handle;
__u16 Procedure;
__u16 BasicService;
__u8 *ServedUserNumber;
__u8 *ForwardedToNumber;
__u8 *ForwardedToSubaddress;
};
struct FacReqCFDeactivate {
__u32 Handle;
__u16 Procedure;
__u16 BasicService;
__u8 *ServedUserNumber;
};
#define FacReqCFInterrogateParameters FacReqCFDeactivate
struct FacReqCFInterrogateNumbers {
__u32 Handle;
};
struct FacReqParm {
__u16 Function;
union {
struct FacReqListen Listen;
struct FacReqSuspend Suspend;
struct FacReqResume Resume;
struct FacReqCFActivate CFActivate;
struct FacReqCFDeactivate CFDeactivate;
struct FacReqCFInterrogateParameters CFInterrogateParameters;
struct FacReqCFInterrogateNumbers CFInterrogateNumbers;
} u;
};
struct FacConfGetSupportedServices {
__u16 SupplementaryServiceInfo;
__u32 SupportedServices;
};
struct FacConfInfo {
__u16 SupplementaryServiceInfo;
};
struct FacConfParm {
__u16 Function;
union {
struct FacConfGetSupportedServices GetSupportedServices;
struct FacConfInfo Info;
} u;
};
// ---------------------------------------------------------------------------
// struct Contr
typedef struct _BInst {
struct _BInst *prev;
struct _BInst *next;
mISDNstack_t *bst;
mISDNinstance_t inst;
} BInst_t;
typedef struct _Contr {
struct _Contr *prev;
struct _Contr *next;
mISDNinstance_t inst;
BInst_t *binst;
struct capi_ctr *ctrl;
__u32 adrController;
int b3_mode;
u_int debug;
char infobuf[128];
char msgbuf[128];
struct _Plci *plcis[CAPI_MAXPLCI];
struct _Appl *appls[CAPI_MAXAPPL];
DummyProcess_t *dummy_pcs[CAPI_MAXDUMMYPCS];
__u16 lastInvokeId;
} Contr_t;
Contr_t *newContr(mISDNobject_t *, mISDNstack_t *, mISDN_pid_t *);
int contrConstr(Contr_t *, mISDNstack_t *, mISDN_pid_t *, mISDNobject_t *);
void contrDestr(Contr_t *contr);
void contrDebug(Contr_t *contr, __u32 level, char *fmt, ...);
void contrRegisterAppl(Contr_t *contr, __u16 ApplId, capi_register_params *rp);
void contrReleaseAppl(Contr_t *contr, __u16 ApplId);
void contrSendMessage(Contr_t *contr, struct sk_buff *skb);
void contrLoadFirmware(Contr_t *, int, void *);
void contrReset(Contr_t *contr);
void contrRecvCmsg(Contr_t *contr, _cmsg *cmsg);
void contrAnswerCmsg(Contr_t *contr, _cmsg *cmsg, __u16 Info);
void contrAnswerMessage(Contr_t *contr, struct sk_buff *skb, __u16 Info);
struct _Plci *contrNewPlci(Contr_t *contr);
struct _Appl *contrId2appl(Contr_t *contr, __u16 ApplId);
struct _Plci *contrAdr2plci(Contr_t *contr, __u32 adr);
void contrDelPlci(Contr_t *contr, struct _Plci *plci);
int contrDummyInd(Contr_t *, __u32, struct sk_buff *);
DummyProcess_t *contrNewDummyPc(Contr_t *contr);
DummyProcess_t *contrId2DummyPc(Contr_t *contr, __u16 invokeId);
int contrL4L3(Contr_t *, u_int, int, struct sk_buff *);
int contrL3L4(mISDNif_t *, struct sk_buff *);
BInst_t *contrSelChannel(Contr_t *, u_int);
// ---------------------------------------------------------------------------
// struct Listen
#define CAPI_INFOMASK_CAUSE (0x0001)
#define CAPI_INFOMASK_DATETIME (0x0002)
#define CAPI_INFOMASK_DISPLAY (0x0004)
#define CAPI_INFOMASK_USERUSER (0x0008)
#define CAPI_INFOMASK_PROGRESS (0x0010)
#define CAPI_INFOMASK_FACILITY (0x0020)
//#define CAPI_INFOMASK_CHARGE (0x0040)
//#define CAPI_INFOMASK_CALLEDPN (0x0080)
#define CAPI_INFOMASK_CHANNELID (0x0100)
#define CAPI_INFOMASK_EARLYB3 (0x0200)
//#define CAPI_INFOMASK_REDIRECT (0x0400)
typedef struct _Listen {
Contr_t *contr;
__u16 ApplId;
__u32 InfoMask;
__u32 CIPmask;
__u32 CIPmask2;
struct FsmInst listen_m;
} Listen_t;
void listenConstr(Listen_t *listen, Contr_t *contr, __u16 ApplId);
void listenDestr(Listen_t *listen);
void listenDebug(Listen_t *listen, __u32 level, char *fmt, ...);
void listenSendMessage(Listen_t *listen, struct sk_buff *skb);
int listenHandle(Listen_t *listen, __u16 CIPValue);
// ---------------------------------------------------------------------------
// struct Appl
#define APPL_FLAG_D2TRACE 1
typedef struct _Appl {
Contr_t *contr;
__u16 ApplId;
__u16 MsgId;
Listen_t listen;
struct _Cplci *cplcis[CAPI_MAXPLCI];
__u32 NotificationMask;
int flags;
capi_register_params rp;
} Appl_t;
void applConstr(Appl_t *appl, Contr_t *contr, __u16 ApplId, capi_register_params *rp);
void applDestr(Appl_t *appl);
void applDebug(Appl_t *appl, __u32 level, char *fmt, ...);
void applSendMessage(Appl_t *appl, struct sk_buff *skb);
void applFacilityReq(Appl_t *appl, struct sk_buff *skb);
void applSuppFacilityReq(Appl_t *appl, _cmsg *cmsg);
int applGetSupportedServices(Appl_t *appl, struct FacReqParm *facReqParm,
struct FacConfParm *facConfParm);
int applFacListen(Appl_t *appl, struct FacReqParm *facReqParm,
struct FacConfParm *facConfParm);
int applFacCFActivate(Appl_t *appl, struct FacReqParm *facReqParm,
struct FacConfParm *facConfParm);
int applFacCFDeactivate(Appl_t *appl, struct FacReqParm *facReqParm,
struct FacConfParm *facConfParm);
int applFacCFInterrogateNumbers(Appl_t *appl, struct FacReqParm *facReqParm,
struct FacConfParm *facConfParm);
int applFacCFInterrogateParameters(Appl_t *appl, struct FacReqParm *facReqParm,
struct FacConfParm *facConfParm);
void applManufacturerReq(Appl_t *appl, struct sk_buff *skb);
void applD2Trace(Appl_t *appl, u_char *buf, int len);
DummyProcess_t *applNewDummyPc(Appl_t *appl, __u16 Function, __u32 Handle);
struct _Cplci *applNewCplci(Appl_t *appl, struct _Plci *plci);
struct _Cplci *applAdr2cplci(Appl_t *appl, __u32 adr);
void applDelCplci(Appl_t *appl, struct _Cplci *cplci);
// ---------------------------------------------------------------------------
// struct Plci
#define PLCI_FLAG_ALERTING 1
#define PLCI_FLAG_OUTGOING 2
typedef struct _Plci {
Contr_t *contr;
__u32 adrPLCI;
int flags;
int nAppl;
struct _Cplci *cplcis[CAPI_MAXAPPL];
} Plci_t;
void plciConstr(Plci_t *plci, Contr_t *contr, __u32 adrPLCI);
void plciDestr(Plci_t *plci);
void plciDebug(Plci_t *plci, __u32 level, char *fmt, ...);
int plci_l3l4(Plci_t *, int, struct sk_buff *);
void plciAttachCplci(Plci_t *plci, struct _Cplci *cplci);
void plciDetachCplci(Plci_t *plci, struct _Cplci *cplci);
void plciNewCrInd(Plci_t *plci, void *);
void plciNewCrReq(Plci_t *plci);
int plciL4L3(Plci_t *, __u32, struct sk_buff *);
// ---------------------------------------------------------------------------
// struct Cplci
typedef struct _Cplci {
__u32 adrPLCI;
Plci_t *plci;
Appl_t *appl;
struct _Ncci *ncci;
Contr_t *contr;
struct FsmInst plci_m;
u_char cause[4]; // we may get a cause from l3 DISCONNECT message
// which we'll need send in DISCONNECT_IND caused by
// l3 RELEASE message
u_int bchannel;
struct Bprotocol Bprotocol;
} Cplci_t;
void cplciConstr(Cplci_t *cplci, Appl_t *appl, Plci_t *plci);
void cplciDestr(Cplci_t *cplci);
void cplciDebug(Cplci_t *cplci, __u32 level, char *fmt, ...);
void cplci_l3l4(Cplci_t *cplci, int pr, void *arg);
void cplciSendMessage(Cplci_t *cplci, struct sk_buff *skb);
void cplciClearOtherApps(Cplci_t *cplci);
void cplciInfoIndMsg(Cplci_t *, __u32, unsigned char);
void cplciInfoIndIE(Cplci_t *, unsigned char, __u32, Q931_info_t *);
void cplciRecvCmsg(Cplci_t *cplci, _cmsg *cmsg);
void cplciCmsgHeader(Cplci_t *cplci, _cmsg *cmsg, __u8 cmd, __u8 subcmd);
void cplciLinkUp(Cplci_t *cplci);
void cplciLinkDown(Cplci_t *cplci);
int cplciFacSuspendReq(Cplci_t *cplci, struct FacReqParm *facReqParm,
struct FacConfParm *facConfParm);
int cplciFacResumeReq(Cplci_t *cplci, struct FacReqParm *facReqParm,
struct FacConfParm *facConfParm);
// ---------------------------------------------------------------------------
// Ncci_t
typedef struct _Ncci {
BInst_t *binst;
__u32 adrNCCI;
Contr_t *contr;
Cplci_t *cplci;
Appl_t *appl;
struct FsmInst ncci_m;
int window;
u_long Flags;
struct {
struct sk_buff *skb;
__u16 DataHandle;
__u16 MsgId;
} xmit_skb_handles[CAPI_MAXDATAWINDOW];
struct sk_buff *recv_skb_handles[CAPI_MAXDATAWINDOW];
struct sk_buff_head squeue;
_cmsg tmpmsg;
} Ncci_t;
#define NCCI_FLG_FCTRL 1
#define NCCI_FLG_BUSY 2
void ncciConstr(Ncci_t *ncci, Cplci_t *cplci);
void ncciDestr(Ncci_t *ncci);
void ncciSendMessage(Ncci_t *, struct sk_buff *);
int ncci_l3l4(mISDNif_t *, struct sk_buff *);
void ncciLinkUp(Ncci_t *ncci);
void ncciLinkDown(Ncci_t *ncci);
void ncciInitSt(Ncci_t *ncci);
void ncciReleaseSt(Ncci_t *ncci);
__u16 ncciSelectBprotocol(Ncci_t *ncci);
void ncciRecvCmsg(Ncci_t *ncci, _cmsg *cmsg);
void ncciCmsgHeader(Ncci_t *ncci, _cmsg *cmsg, __u8 cmd, __u8 subcmd);
int capiEncodeWord(__u8 *dest, __u16 i);
int capiEncodeDWord(__u8 *dest, __u32 i);
int capiEncodeFacIndCFact(__u8 *dest, __u16 SupplementaryServiceReason, __u32 Handle);
int capiEncodeFacIndCFdeact(__u8 *dest, __u16 SupplementaryServiceReason, __u32 Handle);
int capiEncodeFacIndCFNotAct(__u8 *dest, struct ActDivNotification *actNot);
int capiEncodeFacIndCFNotDeact(__u8 *dest, struct DeactDivNotification *deactNot);
int capiEncodeFacIndCFinterParameters(__u8 *dest, __u16 SupplementaryServiceReason, __u32 Handle,
struct IntResultList *intResultList);
int capiEncodeFacIndCFinterNumbers(__u8 *dest, __u16 SupplementaryServiceReason, __u32 Handle,
struct ServedUserNumberList *list);
int capiEncodeFacConfParm(__u8 *dest, struct FacConfParm *facConfParm);
#endif

View File

@ -2,7 +2,7 @@
*
*/
#include "capi.h"
#include "m_capi.h"
#include "asn1.h"
int capiEncodeWord(__u8 *p, __u16 i)

View File

@ -0,0 +1,88 @@
/* $Id$
*
* Author (c) Karsten Keil <kkeil@suse.de>
*
* This file is released under the GPLv2
*
*/
#include <linux/module.h>
#include "channel.h"
#include "layer1.h"
int
mISDN_initchannel(channel_t *ch, ulong prop, int maxlen)
{
ch->log = kmalloc(MAX_LOG_SPACE, GFP_ATOMIC);
if (!ch->log) {
printk(KERN_WARNING
"mISDN: No memory for channel log\n");
return(-ENOMEM);
}
ch->Flags = prop;
ch->maxlen = maxlen;
ch->hw = NULL;
ch->rx_skb = NULL;
ch->tx_skb = NULL;
ch->tx_idx = 0;
ch->next_skb = NULL;
return(0);
}
int
mISDN_freechannel(channel_t *ch)
{
if (ch->tx_skb) {
dev_kfree_skb(ch->tx_skb);
ch->tx_skb = NULL;
}
if (ch->rx_skb) {
dev_kfree_skb(ch->rx_skb);
ch->rx_skb = NULL;
}
if (ch->next_skb) {
dev_kfree_skb(ch->next_skb);
ch->next_skb = NULL;
}
kfree(ch->log);
ch->log = NULL;
return(0);
}
/* need called with HW lock */
int
mISDN_setpara(channel_t *ch, mISDN_stPara_t *stp)
{
if (!stp) { // clear parameters
ch->maxlen = 0;
ch->up_headerlen = 0;
return(0);
}
if (stp->up_headerlen)
ch->up_headerlen = stp->up_headerlen;
if (stp->maxdatalen) {
if (ch->maxlen < stp->maxdatalen) {
if (ch->rx_skb) {
struct sk_buff *skb;
skb = alloc_skb(stp->maxdatalen +
ch->up_headerlen, GFP_ATOMIC);
if (!skb) {
int_errtxt("no skb for %d+%d", stp->maxdatalen, ch->up_headerlen);
return(-ENOMEM);
}
skb_reserve(skb, ch->up_headerlen);
memcpy(skb_put(skb, ch->rx_skb->len),
ch->rx_skb->data, ch->rx_skb->len);
dev_kfree_skb(ch->rx_skb);
ch->rx_skb = skb;
}
}
ch->maxlen = stp->maxdatalen;
}
return(0);
}
EXPORT_SYMBOL(mISDN_initchannel);
EXPORT_SYMBOL(mISDN_freechannel);
EXPORT_SYMBOL(mISDN_setpara);

View File

@ -0,0 +1,163 @@
/* $Id$
*
* Basic declarations for a mISDN HW channel
*
* Author (c) Karsten Keil <kkeil@suse.de>
*
* This file is released under the GPLv2
*
*/
#ifndef MISDN_CHANNEL_H
#define MISDN_CHANNEL_H
#include <linux/mISDNif.h>
#include <linux/timer.h>
#include <linux/skbuff.h>
#include "helper.h"
#ifdef MISDN_MEMDEBUG
#include "memdbg.h"
#endif
#ifdef CONFIG_MISDN_NETDEV
#include "core.h"
#endif
#define MAX_DFRAME_LEN_L1 300
#define MAX_MON_FRAME 32
#define MAX_LOG_SPACE 2048
#define MISDN_COPY_SIZE 32
/* channel->Flags bit field */
#define FLG_TX_BUSY 0 // tx_buf in use
#define FLG_TX_NEXT 1 // next_skb in use
#define FLG_L1_BUSY 2 // L1 is permanent busy
#define FLG_USED 5 // channel is in use
#define FLG_ACTIVE 6 // channel is activated
#define FLG_BUSY_TIMER 7
/* channel type */
#define FLG_DCHANNEL 8 // channel is D-channel
#define FLG_BCHANNEL 9 // channel is B-channel
#define FLG_ECHANNEL 10 // channel is E-channel
#define FLG_TRANSPARENT 12 // channel use transparent data
#define FLG_HDLC 13 // channel use hdlc data
#define FLG_L2DATA 14 // channel use L2 DATA primitivs
#define FLG_ORIGIN 15 // channel is on origin site
/* channel specific stuff */
/* arcofi specific */
#define FLG_ARCOFI_TIMER 16
#define FLG_ARCOFI_ERROR 17
/* isar specific */
#define FLG_INITIALIZED 16
#define FLG_DLEETX 17
#define FLG_LASTDLE 18
#define FLG_FIRST 19
#define FLG_LASTDATA 20
#define FLG_NMD_DATA 21
#define FLG_FTI_RUN 22
#define FLG_LL_OK 23
#define FLG_LL_CONN 24
#define FLG_DTMFSEND 25
#define MSK_INIT_DCHANNEL ((1<<FLG_DCHANNEL)|(1<<FLG_HDLC))
#define MSK_INIT_BCHANNEL (1<<FLG_BCHANNEL)
#define MSK_INIT_ECHANNEL (1<<FLG_ECHANNEL)
typedef struct _channel_t {
mISDNinstance_t inst;
int channel;
/* basic properties */
u_long Flags;
u_int type;
u_int state;
/* HW access */
u_char (*read_reg) (void *, u_char);
void (*write_reg) (void *, u_char, u_char);
void (*read_fifo) (void *, u_char *, int);
void (*write_fifo) (void *, u_char *, int);
void *hw;
struct timer_list timer;
/* receive data */
struct sk_buff *rx_skb;
int maxlen;
int up_headerlen;
/* send data */
struct sk_buff *next_skb;
struct sk_buff *tx_skb;
int tx_idx;
/* debug */
int debug;
char *log;
/* statistics */
int err_crc;
int err_tx;
int err_rx;
} channel_t;
extern int mISDN_initchannel(channel_t *, ulong, int);
extern int mISDN_freechannel(channel_t *);
extern int mISDN_setpara(channel_t *, mISDN_stPara_t *);
static inline void
queue_ch_frame(channel_t *ch, u_int pr, int dinfo, struct sk_buff *skb)
{
int err;
pr |= test_bit(FLG_L2DATA, &ch->Flags) ? DL_DATA : PH_DATA;
if (!skb) {
err = mISDN_queue_data(&ch->inst, FLG_MSG_UP, pr, dinfo, 0, NULL, ch->up_headerlen);
} else {
#ifdef CONFIG_MISDN_NETDEV
misdn_log_frame(ch->inst.st, skb->data, skb->len, FLG_MSG_UP);
#endif
err = mISDN_queueup_newhead(&ch->inst, 0, pr, dinfo, skb);
}
if (unlikely(err)) {
int_errtxt("err=%d", err);
if (skb)
dev_kfree_skb(skb);
}
}
static inline int
channel_senddata(channel_t *ch, int di, struct sk_buff *skb)
{
/* HW lock must be obtained */
/* check oversize */
if (skb->len <= 0) {
printk(KERN_WARNING "%s: skb too small\n", __FUNCTION__);
return(-EINVAL);
}
if (skb->len > ch->maxlen) {
printk(KERN_WARNING "%s: skb too large(%d/%d)\n",
__FUNCTION__, skb->len, ch->maxlen);
return(-EINVAL);
}
/* check for pending next_skb */
if (ch->next_skb) {
#ifdef DEBUG_NEXT_SKB_EXISTS
printk(KERN_WARNING "%s: next_skb exist ERROR (skb->len=%d next_skb->len=%d)\n",
__FUNCTION__, skb->len, ch->next_skb->len);
#endif
return(-EBUSY);
}
if (test_and_set_bit(FLG_TX_BUSY, &ch->Flags)) {
test_and_set_bit(FLG_TX_NEXT, &ch->Flags);
#ifdef CONFIG_MISDN_NETDEV
misdn_log_frame(ch->inst.st, skb->data, skb->len, FLG_MSG_DOWN);
#endif
ch->next_skb = skb;
return(0);
} else {
/* write to fifo */
ch->tx_skb = skb;
ch->tx_idx = 0;
#ifdef CONFIG_MISDN_NETDEV
misdn_log_frame(ch->inst.st, skb->data, skb->len, FLG_MSG_DOWN);
#endif
queue_ch_frame(ch, CONFIRM, di, NULL);
return(skb->len);
}
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -8,8 +8,8 @@
#include <linux/types.h>
#include <linux/stddef.h>
#include <linux/config.h>
#include <linux/module.h>
#include <linux/spinlock.h>
#include "core.h"
#ifdef CONFIG_KMOD
#include <linux/kmod.h>
@ -19,11 +19,24 @@
#endif
static char *mISDN_core_revision = "$Revision$";
static char *mISDN_core_version = MISDNVERSION ;
LIST_HEAD(mISDN_objectlist);
static rwlock_t mISDN_objects_lock = RW_LOCK_UNLOCKED;
LIST_HEAD(mISDN_modulelist);
static rwlock_t mISDN_modules_lock = RW_LOCK_UNLOCKED;
struct modulelist {
struct list_head list;
struct module *module;
};
mISDNobject_t *mISDN_objects = NULL;
int core_debug;
static int debug;
static u_char entityarray[MISDN_MAX_ENTITY/8];
static spinlock_t entity_lock = SPIN_LOCK_UNLOCKED;
static uint debug;
static int obj_id;
#ifdef MODULE
@ -31,10 +44,12 @@ MODULE_AUTHOR("Karsten Keil");
#ifdef MODULE_LICENSE
MODULE_LICENSE("GPL");
#endif
#ifdef OLD_MODULE_PARAM
MODULE_PARM(debug, "1i");
EXPORT_SYMBOL(mISDN_register);
EXPORT_SYMBOL(mISDN_unregister);
#define mISDNInit init_module
#else
module_param (debug, uint, S_IRUGO | S_IWUSR);
#endif
MODULE_PARM_DESC (debug, "mISDN core debug mask");
#endif
typedef struct _mISDN_thread {
@ -42,14 +57,14 @@ typedef struct _mISDN_thread {
struct task_struct *thread;
wait_queue_head_t waitq;
struct semaphore *notify;
u_int Flags;
u_long Flags;
struct sk_buff_head workq;
} mISDN_thread_t;
#define mISDN_TFLAGS_STARTED 1
#define mISDN_TFLAGS_RMMOD 2
#define mISDN_TFLAGS_ACTIV 3
#define mISDN_TFLAGS_TEST 4
#define mISDN_TFLAGS_STARTED 0
#define mISDN_TFLAGS_RMMOD 1
#define mISDN_TFLAGS_ACTIV 2
#define mISDN_TFLAGS_TEST 3
static mISDN_thread_t mISDN_thread;
@ -75,14 +90,13 @@ mISDNd(void *data)
#ifdef CONFIG_SMP
lock_kernel();
#endif
daemonize();
MAKEDAEMON("mISDNd");
sigfillset(&current->blocked);
strcpy(current->comm,"mISDNd");
hkt->thread = current;
#ifdef CONFIG_SMP
unlock_kernel();
#endif
printk(KERN_DEBUG "mISDNd: kernel daemon started\n");
printk(KERN_DEBUG "mISDNd: kernel daemon started (current:%p)\n", current);
test_and_set_bit(mISDN_TFLAGS_STARTED, &hkt->Flags);
@ -95,37 +109,40 @@ mISDNd(void *data)
break;
if (hkt->notify != NULL)
up(hkt->notify);
interruptible_sleep_on(&hkt->waitq);
wait_event_interruptible(hkt->waitq, ((!skb_queue_empty(&hkt->workq)) || (hkt->Flags & 0xfffffffe)));
if (test_and_clear_bit(mISDN_TFLAGS_RMMOD, &hkt->Flags))
break;
while ((skb = skb_dequeue(&hkt->workq))) {
test_and_set_bit(mISDN_TFLAGS_ACTIV, &hkt->Flags);
err = -EINVAL;
hhe=mISDN_HEADEXT_P(skb);
switch (hhe->what) {
switch (hhe->addr) {
case MGR_FUNCTION:
err=hhe->func.ctrl(hhe->data[0], hhe->prim, skb->data);
err = hhe->func.ctrl(hhe->data[0], hhe->prim,
skb->len ? skb->data : NULL);
if (err) {
printk(KERN_WARNING "mISDNd: what(%x) prim(%x) failed err(%x)\n",
hhe->what, hhe->prim, err);
printk(KERN_WARNING "mISDNd: addr(%x) prim(%x) failed err(%d)\n",
hhe->addr, hhe->prim, err);
} else {
if (debug)
printk(KERN_DEBUG "mISDNd: what(%x) prim(%x) success\n",
hhe->what, hhe->prim);
printk(KERN_DEBUG "mISDNd: addr(%x) prim(%x) success\n",
hhe->addr, hhe->prim);
err--; /* to free skb */
}
break;
#ifdef FIXME
case MGR_QUEUEIF:
err = hhe->func.iff(hhe->data[0], skb);
if (err) {
printk(KERN_WARNING "mISDNd: what(%x) prim(%x) failed err(%x)\n",
hhe->what, hhe->prim, err);
printk(KERN_WARNING "mISDNd: addr(%x) prim(%x) failed err(%d)\n",
hhe->addr, hhe->prim, err);
}
break;
#endif
default:
int_error();
printk(KERN_WARNING "mISDNd: what(%x) prim(%x) unknown\n",
hhe->what, hhe->prim);
printk(KERN_WARNING "mISDNd: addr(%x) prim(%x) unknown\n",
hhe->addr, hhe->prim);
err = -EINVAL;
break;
}
@ -137,7 +154,7 @@ mISDNd(void *data)
printk(KERN_DEBUG "mISDNd: test event done\n");
}
printk(KERN_DEBUG "mISDNd: daemon exit now\n");
printk(KERN_DEBUG "mISDNd: daemon exit now (current:%p)\n", current);
test_and_clear_bit(mISDN_TFLAGS_STARTED, &hkt->Flags);
test_and_clear_bit(mISDN_TFLAGS_ACTIV, &hkt->Flags);
discard_queue(&hkt->workq);
@ -149,37 +166,44 @@ mISDNd(void *data)
mISDNobject_t *
get_object(int id) {
mISDNobject_t *obj = mISDN_objects;
mISDNobject_t *obj;
while(obj) {
if (obj->id == id)
read_lock(&mISDN_objects_lock);
list_for_each_entry(obj, &mISDN_objectlist, list)
if (obj->id == id) {
read_unlock(&mISDN_objects_lock);
return(obj);
obj = obj->next;
}
read_unlock(&mISDN_objects_lock);
return(NULL);
}
static mISDNobject_t *
find_object(int protocol) {
mISDNobject_t *obj = mISDN_objects;
mISDNobject_t *obj;
int err;
while (obj) {
read_lock(&mISDN_objects_lock);
list_for_each_entry(obj, &mISDN_objectlist, list) {
err = obj->own_ctrl(NULL, MGR_HASPROTOCOL | REQUEST, &protocol);
if (!err)
return(obj);
goto unlock;
if (err != -ENOPROTOOPT) {
if (0 == HasProtocol(obj, protocol))
if (0 == mISDN_HasProtocol(obj, protocol))
goto unlock;
}
}
obj = NULL;
unlock:
read_unlock(&mISDN_objects_lock);
return(obj);
}
obj = obj->next;
}
return(NULL);
}
static mISDNobject_t *
find_object_module(int protocol) {
#ifdef CONFIG_KMOD
int err;
#endif
moditem_t *m = modlist;
mISDNobject_t *obj;
@ -188,8 +212,8 @@ find_object_module(int protocol) {
#ifdef CONFIG_KMOD
if (debug)
printk(KERN_DEBUG
"find_object_module %s - trying to load in_irq(%d)\n",
m->name, in_interrupt());
"find_object_module %s - trying to load\n",
m->name);
err=request_module(m->name);
if (debug)
printk(KERN_DEBUG "find_object_module: request_module(%s) returns(%d)\n",
@ -209,31 +233,7 @@ find_object_module(int protocol) {
return(NULL);
}
static void
remove_object(mISDNobject_t *obj) {
mISDNstack_t *st = mISDN_stacklist;
mISDNlayer_t *layer;
mISDNinstance_t *inst, *tmp;
while (st) {
layer = st->lstack;
while(layer) {
inst = layer->inst;
while (inst) {
if (inst->obj == obj) {
tmp = inst->next;
inst->obj->own_ctrl(st, MGR_RELEASE
| INDICATION, inst);
inst = tmp;
} else
inst = inst->next;
}
layer = layer->next;
}
st = st->next;
}
}
#ifdef FIXME
static int
dummy_if(mISDNif_t *hif, struct sk_buff *skb)
{
@ -251,6 +251,7 @@ dummy_if(mISDNif_t *hif, struct sk_buff *skb)
dev_kfree_skb_any(skb);
return(0);
}
#endif
mISDNinstance_t *
get_next_instance(mISDNstack_t *st, mISDN_pid_t *pid)
@ -260,7 +261,7 @@ get_next_instance(mISDNstack_t *st, mISDN_pid_t *pid)
int layer, proto;
mISDNobject_t *obj;
layer = get_lowlayer(pid->layermask);
layer = mISDN_get_lowlayer(pid->layermask);
proto = pid->protocol[layer];
next = get_instance(st, layer, proto);
if (!next) {
@ -305,26 +306,37 @@ sel_channel(mISDNstack_t *st, channel_info_t *ci)
printk(KERN_WARNING "%s: no mgr st(%p)\n", __FUNCTION__, st);
}
if (err) {
mISDNstack_t *cst = st->child;
int nr = 0;
mISDNstack_t *cst;
u_int nr = 0;
ci->st.p = NULL;
if (!(ci->channel & (~CHANNEL_NUMBER))) {
/* only number is set */
while(cst) {
struct list_head *head;
if (list_empty(&st->childlist)) {
if ((st->id & FLG_CLONE_STACK) &&
(st->childlist.prev != &st->childlist)) {
head = st->childlist.prev;
} else {
printk(KERN_WARNING "%s: invalid empty childlist (no clone) stid(%x) childlist(%p<-%p->%p)\n",
__FUNCTION__, st->id, st->childlist.prev, &st->childlist, st->childlist.next);
return(err);
}
} else
head = &st->childlist;
list_for_each_entry(cst, head, list) {
nr++;
if (nr == (ci->channel & 3)) {
ci->st.p = cst;
err = 0;
break;
return(0);
}
cst = cst->next;
}
}
}
return(err);
}
#ifdef FIXME
static int
disconnect_if(mISDNinstance_t *inst, u_int prim, mISDNif_t *hif) {
int err = 0;
@ -354,10 +366,14 @@ add_if(mISDNinstance_t *inst, u_int prim, mISDNif_t *hif) {
myif = &inst->up;
} else
return(-EINVAL);
APPEND_TO_LIST(hif, myif);
while(myif->clone)
myif = myif->clone;
myif->clone = hif;
hif->predecessor = myif;
inst->obj->own_ctrl(inst, prim, hif);
return(0);
}
#endif
static char tmpbuf[4096];
static int
@ -381,27 +397,132 @@ get_hdevice(mISDNdevice_t **dev, int *typ)
return(-EINVAL);
if (!typ)
return(-EINVAL);
#ifdef FIXME
if (*typ == mISDN_RAW_DEVICE) {
*dev = get_free_rawdevice();
if (!(*dev))
return(-ENODEV);
return(0);
}
#endif
return(-EINVAL);
}
#ifdef FIXME
static int
mgr_queue(void *data, u_int prim, struct sk_buff *skb)
{
mISDN_headext_t *hhe = mISDN_HEADEXT_P(skb);
hhe->what = prim;
hhe->addr = prim;
skb_queue_tail(&mISDN_thread.workq, skb);
wake_up_interruptible(&mISDN_thread.waitq);
return(0);
}
static int central_manager(void *data, u_int prim, void *arg) {
#endif
static int
set_stack_req(mISDNstack_t *st, mISDN_pid_t *pid)
{
struct sk_buff *skb;
mISDN_headext_t *hhe;
mISDN_pid_t *npid;
u_char *pbuf = NULL;
int err;
if (!(skb = alloc_skb(sizeof(mISDN_pid_t) + pid->maxplen, GFP_ATOMIC)))
return(-ENOMEM);
hhe = mISDN_HEADEXT_P(skb);
hhe->prim = MGR_SETSTACK_NW | REQUEST;
hhe->addr = MGR_FUNCTION;
hhe->data[0] = st;
npid = (mISDN_pid_t *)skb_put(skb, sizeof(mISDN_pid_t));
if (pid->maxplen)
pbuf = skb_put(skb, pid->maxplen);
err = copy_pid(npid, pid, pbuf);
if (err) // FIXME error handling
int_errtxt("copy_pid error %d", err);
hhe->func.ctrl = mISDN_ctrl;
skb_queue_tail(&mISDN_thread.workq, skb);
wake_up_interruptible(&mISDN_thread.waitq);
return(0);
}
static int
queue_ctrl_ready(mISDNstack_t *st, void *arg)
{
struct sk_buff *skb;
mISDN_headext_t *hhe;
if (!(skb = alloc_skb(4, GFP_ATOMIC)))
return(-ENOMEM);
if (arg) /* maybe changed for future enhancements */
return(-EINVAL);
hhe = mISDN_HEADEXT_P(skb);
hhe->prim = MGR_CTRLREADY | INDICATION;
hhe->addr = MGR_FUNCTION;
hhe->data[0] = st;
hhe->func.ctrl = do_for_all_layers;
skb_queue_tail(&mISDN_thread.workq, skb);
wake_up_interruptible(&mISDN_thread.waitq);
return(0);
}
int
mISDN_alloc_entity(int *entity)
{
u_long flags;
spin_lock_irqsave(&entity_lock, flags);
*entity = 1;
while(*entity < MISDN_MAX_ENTITY) {
if (!test_and_set_bit(*entity, (u_long *)&entityarray[0]))
break;
(*entity)++;
}
spin_unlock_irqrestore(&entity_lock, flags);
if (*entity == MISDN_MAX_ENTITY)
return(-EBUSY);
return(0);
}
int
mISDN_delete_entity(int entity)
{
u_long flags;
int ret = 0;
spin_lock_irqsave(&entity_lock, flags);
if (!test_and_clear_bit(entity, (u_long *)&entityarray[0])) {
printk(KERN_WARNING "mISDN: del_entity(%d) but entity not allocated\n", entity);
ret = -ENODEV;
}
spin_unlock_irqrestore(&entity_lock, flags);
return(ret);
}
static int
new_entity(mISDNinstance_t *inst)
{
int entity;
int ret;
if (!inst)
return(-EINVAL);
ret = mISDN_alloc_entity(&entity);
if (ret) {
printk(KERN_WARNING "mISDN: no more entity available(max %d)\n", MISDN_MAX_ENTITY);
return(ret);
}
ret = inst->obj->own_ctrl(inst, MGR_NEWENTITY | CONFIRM, (void *)((u_long)entity));
if (ret)
mISDN_delete_entity(entity);
return(ret);
}
int
mISDN_ctrl(void *data, u_int prim, void *arg) {
mISDNstack_t *st = data;
switch(prim) {
@ -409,6 +530,11 @@ static int central_manager(void *data, u_int prim, void *arg) {
if (!(st = new_stack(data, arg)))
return(-EINVAL);
return(0);
case MGR_NEWENTITY | REQUEST:
return(new_entity(data));
case MGR_DELENTITY | REQUEST:
case MGR_DELENTITY | INDICATION:
return(mISDN_delete_entity((u_long)arg & 0xffffffff));
case MGR_REGLAYER | INDICATION:
return(register_layer(st, arg));
case MGR_REGLAYER | REQUEST:
@ -419,49 +545,59 @@ static int central_manager(void *data, u_int prim, void *arg) {
return(-EINVAL);
case MGR_UNREGLAYER | REQUEST:
return(unregister_instance(data));
#ifdef FIXME
case MGR_DISCONNECT | REQUEST:
case MGR_DISCONNECT | INDICATION:
return(disconnect_if(data, prim, arg));
#endif
case MGR_GETDEVICE | REQUEST:
return(get_hdevice(data, arg));
case MGR_DELDEVICE | REQUEST:
return(free_device(data));
#ifdef FIXME
case MGR_QUEUEIF | REQUEST:
return(mgr_queue(data, MGR_QUEUEIF, arg));
#endif
}
if (!data)
return(-EINVAL);
switch(prim) {
case MGR_ADDLAYER | REQUEST:
return(preregister_layer(st, arg));
case MGR_SETSTACK | REQUEST:
/* can sleep in case of module reload */
if (in_interrupt()) {
struct sk_buff *skb;
mISDN_headext_t *hhe;
skb = alloc_skb(sizeof(mISDN_pid_t), GFP_ATOMIC);
hhe = mISDN_HEADEXT_P(skb);
hhe->prim = prim;
hhe->what = MGR_FUNCTION;
hhe->data[0] = st;
/* FIXME: handling of optional pid parameters */
memcpy(skb_put(skb, sizeof(mISDN_pid_t)), arg, sizeof(mISDN_pid_t));
hhe->func.ctrl = central_manager;
skb_queue_tail(&mISDN_thread.workq, skb);
wake_up_interruptible(&mISDN_thread.waitq);
return(0);
} else
#ifdef CONFIG_MISDN_NETDEV
misdn_netdev_addstack(st);
#endif
return(set_stack_req(st, arg));
case MGR_SETSTACK_NW | REQUEST:
return(set_stack(st, arg));
break;
case MGR_CLEARSTACK | REQUEST:
return(clear_stack(st));
return(clear_stack(st, arg ? 1 : 0));
case MGR_DELSTACK | REQUEST:
return(release_stack(st));
case MGR_SELCHANNEL | REQUEST:
return(sel_channel(st, arg));
case MGR_STOPSTACK | REQUEST:
return(mISDN_start_stop(st, 0));
case MGR_STARTSTACK | REQUEST:
return(mISDN_start_stop(st, 1));
#ifdef FIXME
case MGR_ADDIF | REQUEST:
return(add_if(data, prim, arg));
#endif
case MGR_CTRLREADY | INDICATION:
return(queue_ctrl_ready(st, arg));
case MGR_ADDSTPARA | REQUEST:
case MGR_CLRSTPARA | REQUEST:
return(change_stack_para(st, prim, arg));
#ifdef FIXME
case MGR_CONNECT | REQUEST:
return(ConnectIF(data, arg));
return(mISDN_ConnectIF(data, arg));
#endif
case MGR_EVALSTACK | REQUEST:
return(evaluate_stack_pids(data, arg));
case MGR_GLOBALOPT | REQUEST:
case MGR_LOADFIRM | REQUEST:
if (st->mgr && st->mgr->obj && st->mgr->obj->own_ctrl)
return(st->mgr->obj->own_ctrl(st->mgr, prim, arg));
@ -477,34 +613,89 @@ static int central_manager(void *data, u_int prim, void *arg) {
}
void
mISDNlock_core(void) {
#ifdef MODULE
MOD_INC_USE_COUNT;
#endif
mISDN_module_register(struct module *module)
{
struct modulelist *ml = kmalloc(sizeof(struct modulelist), GFP_KERNEL);
if (!ml) {
printk(KERN_DEBUG "mISDN_register_module: kmalloc failed!\n");
return;
}
ml->module = module;
write_lock(&mISDN_modules_lock);
list_add(&ml->list, &mISDN_modulelist);
write_unlock(&mISDN_modules_lock);
printk(KERN_DEBUG "mISDN_register_module(%p)\n", module);
}
void
mISDNunlock_core(void) {
#ifdef MODULE
MOD_DEC_USE_COUNT;
#endif
mISDN_module_unregister(struct module *module)
{
struct modulelist *ml, *mi;
write_lock(&mISDN_modules_lock);
list_for_each_entry_safe(ml, mi, &mISDN_modulelist, list)
if (ml->module == module) {
list_del(&ml->list);
kfree(ml);
write_unlock(&mISDN_modules_lock);
printk(KERN_DEBUG "mISDN_unregister_module(%p)\n", module);
return;
}
write_unlock(&mISDN_modules_lock);
}
void
mISDN_inc_usage(void)
{
struct modulelist *ml;
read_lock(&mISDN_modules_lock);
list_for_each_entry(ml, &mISDN_modulelist, list)
try_module_get(ml->module);
read_unlock(&mISDN_modules_lock);
}
void
mISDN_dec_usage(void)
{
struct modulelist *ml;
read_lock(&mISDN_modules_lock);
list_for_each_entry(ml, &mISDN_modulelist, list)
module_put(ml->module);
read_unlock(&mISDN_modules_lock);
}
int mISDN_register(mISDNobject_t *obj) {
u_long flags;
int retval;
if (!obj)
return(-EINVAL);
write_lock_irqsave(&mISDN_objects_lock, flags);
obj->id = obj_id++;
APPEND_TO_LIST(obj, mISDN_objects);
obj->ctrl = central_manager;
list_add_tail(&obj->list, &mISDN_objectlist);
write_unlock_irqrestore(&mISDN_objects_lock, flags);
// register_prop
if (debug)
printk(KERN_DEBUG "mISDN_register %s id %x\n", obj->name,
obj->id);
return(0);
if (core_debug & DEBUG_CORE_FUNC)
printk(KERN_DEBUG "mISDN_register: obj(%p)\n", obj);
retval = mISDN_register_sysfs_obj(obj);
if (retval) {
printk(KERN_ERR "mISDN_register class_device_register return(%d)\n", retval);
write_lock_irqsave(&mISDN_objects_lock, flags);
list_del(&obj->list);
write_unlock_irqrestore(&mISDN_objects_lock, flags);
}
return(retval);
}
int mISDN_unregister(mISDNobject_t *obj) {
u_long flags;
if (!obj)
return(-EINVAL);
@ -514,8 +705,15 @@ int mISDN_unregister(mISDNobject_t *obj) {
if (obj->DPROTO.protocol[0])
release_stacks(obj);
else
remove_object(obj);
REMOVE_FROM_LISTBASE(obj, mISDN_objects);
cleanup_object(obj);
write_lock_irqsave(&mISDN_objects_lock, flags);
list_del(&obj->list);
write_unlock_irqrestore(&mISDN_objects_lock, flags);
if (core_debug & DEBUG_CORE_FUNC)
printk(KERN_DEBUG "mISDN_unregister: mISDN_objectlist(%p<-%p->%p)\n",
mISDN_objectlist.prev, &mISDN_objectlist, mISDN_objectlist.next);
class_device_unregister(&obj->class_dev);
return(0);
}
@ -525,11 +723,25 @@ mISDNInit(void)
DECLARE_MUTEX_LOCKED(sem);
int err;
printk(KERN_INFO "Modular ISDN Stack core %s\n", mISDN_core_revision);
printk(KERN_INFO "Modular ISDN Stack core version (%s) revision (%s)\n", mISDN_core_version, mISDN_core_revision);
core_debug = debug;
err = init_mISDNdev(debug);
#ifdef MISDN_MEMDEBUG
err = __mid_init();
if (err)
return(err);
#endif
err = mISDN_sysfs_init();
if (err)
goto sysfs_fail;
err = init_mISDNdev(debug);
if (err)
goto dev_fail;
#ifdef CONFIG_MISDN_NETDEV
misdn_netdev_init();
#endif
init_waitqueue_head(&mISDN_thread.waitq);
skb_queue_head_init(&mISDN_thread.workq);
mISDN_thread.notify = &sem;
@ -539,13 +751,24 @@ mISDNInit(void)
test_and_set_bit(mISDN_TFLAGS_TEST, &mISDN_thread.Flags);
wake_up_interruptible(&mISDN_thread.waitq);
return(err);
dev_fail:
mISDN_sysfs_cleanup();
sysfs_fail:
#ifdef MISDN_MEMDEBUG
__mid_cleanup();
#endif
return(err);
}
#ifdef MODULE
void cleanup_module(void) {
void mISDN_cleanup(void) {
DECLARE_MUTEX_LOCKED(sem);
mISDNstack_t *st;
free_mISDNdev();
if (!list_empty(&mISDN_objectlist)) {
printk(KERN_WARNING "mISDNcore mISDN_objects not empty\n");
}
check_stacklist();
if (mISDN_thread.thread) {
/* abort mISDNd kernel thread */
mISDN_thread.notify = &sem;
@ -554,23 +777,29 @@ void cleanup_module(void) {
down(&sem);
mISDN_thread.notify = NULL;
}
free_mISDNdev();
if (mISDN_objects) {
printk(KERN_WARNING "mISDNcore mISDN_objects not empty\n");
}
if (mISDN_stacklist) {
printk(KERN_WARNING "mISDNcore mISDN_stacklist not empty\n");
st = mISDN_stacklist;
while (st) {
printk(KERN_WARNING "mISDNcore st %x in list\n",
st->id);
if (st == st->next) {
printk(KERN_WARNING "mISDNcore st == next\n");
break;
}
st = st->next;
}
}
#ifdef MISDN_MEMDEBUG
__mid_cleanup();
#endif
#ifdef CONFIG_MISDN_NETDEV
misdn_netdev_exit();
#endif
mISDN_sysfs_cleanup();
printk(KERN_DEBUG "mISDNcore unloaded\n");
}
module_init(mISDNInit);
module_exit(mISDN_cleanup);
EXPORT_SYMBOL(mISDN_module_register);
EXPORT_SYMBOL(mISDN_module_unregister);
EXPORT_SYMBOL(mISDN_inc_usage);
EXPORT_SYMBOL(mISDN_dec_usage);
EXPORT_SYMBOL(mISDN_ctrl);
EXPORT_SYMBOL(mISDN_register);
EXPORT_SYMBOL(mISDN_unregister);
#ifdef CONFIG_MISDN_NETDEV
EXPORT_SYMBOL(misdn_log_frame);
#endif

View File

@ -8,7 +8,7 @@
#include <linux/string.h>
#include <linux/mISDNif.h>
#include "helper.h"
#ifdef MEMDBG
#ifdef MISDN_MEMDEBUG
#include "memdbg.h"
#endif
@ -17,49 +17,91 @@
#define mISDN_MINOR_RAW_MIN 128
#define mISDN_MINOR_RAW_MAX 255
#define mISDN_DEVBUF_SIZE 8192
/* debugging */
#define DEBUG_CORE_FUNC 0x0001
#define DEBUG_DUMMY_FUNC 0x0002
//#define DEBUG_DUMMY_FUNC 0x0002
#define DEBUG_MSG_THREAD_ERR 0x0010
#define DEBUG_MSG_THREAD_INFO 0x0020
#define DEBUG_QUEUE_FUNC 0x0040
#define DEBUG_DEV_OP 0x0100
#define DEBUG_MGR_FUNC 0x0200
#define DEBUG_DEV_TIMER 0x0400
#define DEBUG_RDATA 0x1000
#define DEBUG_WDATA 0x2000
#define DEBUG_SYSFS 0x4000
#define DEBUG_THREADS 0x8000
/* from mISDN_dev.c */
/* from udevice.c */
extern int init_mISDNdev(int);
extern int free_mISDNdev(void);
extern mISDNdevice_t *get_free_rawdevice(void);
extern int free_device(mISDNdevice_t *dev);
/* from mISDN_stack.c */
extern mISDNstack_t *mISDN_stacklist;
extern mISDNinstance_t *mISDN_instlist;
extern void get_stack_info(iframe_t *);
/* from stack.c */
extern void get_stack_info(struct sk_buff *);
extern int get_stack_cnt(void);
extern mISDNstack_t *get_stack4id(int);
extern void check_stacklist(void);
extern void cleanup_object(mISDNobject_t *);
extern mISDNstack_t *get_stack4id(u_int);
extern int mISDN_start_stack_thread(mISDNstack_t *);
extern mISDNstack_t *new_stack(mISDNstack_t *, mISDNinstance_t *);
extern int mISDN_start_stop(mISDNstack_t *, int);
extern int release_stack(mISDNstack_t *);
extern int do_for_all_layers(void *, u_int, void *);
extern int change_stack_para(mISDNstack_t *, u_int, mISDN_stPara_t *);
extern void release_stacks(mISDNobject_t *);
extern int copy_pid(mISDN_pid_t *, mISDN_pid_t *, u_char *);
extern int set_stack(mISDNstack_t *, mISDN_pid_t *);
extern int clear_stack(mISDNstack_t *);
extern mISDNlayer_t *getlayer4lay(mISDNstack_t *, int);
extern int clear_stack(mISDNstack_t *, int);
extern int evaluate_stack_pids(mISDNstack_t *, mISDN_pid_t *);
extern mISDNinstance_t *getlayer4lay(mISDNstack_t *, int);
extern mISDNinstance_t *get_instance(mISDNstack_t *, int, int);
/* from mISDN_core.c */
/* from sysfs_obj.c */
extern int mISDN_register_sysfs_obj(mISDNobject_t *);
extern int mISDN_sysfs_init(void);
extern void mISDN_sysfs_cleanup(void);
extern mISDNobject_t *mISDN_objects;
/* from sysfs_inst.c */
extern int mISDN_register_sysfs_inst(mISDNinstance_t *);
extern void mISDN_unregister_sysfs_inst(mISDNinstance_t *);
extern int mISDN_sysfs_inst_init(void);
extern void mISDN_sysfs_inst_cleanup(void);
/* from sysfs_stack.c */
extern int mISDN_register_sysfs_stack(mISDNstack_t *);
extern void mISDN_unregister_sysfs_st(mISDNstack_t *);
extern int mISDN_sysfs_st_init(void);
extern void mISDN_sysfs_st_cleanup(void);
/* from core.c */
extern int core_debug;
extern void mISDNlock_core(void);
extern void mISDNunlock_core(void);
extern int register_layer(mISDNstack_t *, mISDNinstance_t *);
extern int preregister_layer(mISDNstack_t *, mISDNinstance_t *);
extern int unregister_instance(mISDNinstance_t *);
extern mISDNinstance_t *get_next_instance(mISDNstack_t *, mISDN_pid_t *);
extern mISDNobject_t *get_object(int);
extern mISDNinstance_t *get_instance4id(int);
extern mISDNinstance_t *get_instance4id(u_int);
extern int mISDN_alloc_entity(int *);
extern int mISDN_delete_entity(int);
extern void mISDN_module_register(struct module *);
extern void mISDN_module_unregister(struct module *);
extern void mISDN_inc_usage(void);
extern void mISDN_dec_usage(void);
#ifdef CONFIG_MISDN_NETDEV
/* from netdev_main.c */
void misdn_log_frame(mISDNstack_t *, /* Stack for which to log */
unsigned char *, /* frame to log */
int, /* frame len */
int ); /* direction (0=rx,1=tx) */
int misdn_netdev_addstack(mISDNstack_t *); /* create new netdevice by
stack */
int misdn_netdev_init(void); /* initialize netdevices */
void misdn_netdev_exit(void); /* exit netdeivces */
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,109 +0,0 @@
/* $Id$
*
* Author Karsten Keil (keil@isdn4linux.de)
*
* This file is (c) under GNU PUBLIC LICENSE
*
*/
#define __NO_VERSION__
#include <linux/mISDNif.h>
#include "layer1.h"
#include "helper.h"
#include "dchannel.h"
static void
dchannel_bh(dchannel_t *dch)
{
struct sk_buff *skb;
int err;
if (!dch)
return;
if (dch->debug)
printk(KERN_DEBUG "%s: event %x\n", __FUNCTION__, dch->event);
#if 0
if (test_and_clear_bit(D_CLEARBUSY, &dch->event)) {
if (dch->debug)
debugprint(&dch->inst, "D-Channel Busy cleared");
stptr = dch->stlist;
while (stptr != NULL) {
stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL);
stptr = stptr->next;
}
}
#endif
if (test_and_clear_bit(D_XMTBUFREADY, &dch->event)) {
if ((skb = dch->next_skb)) {
dch->next_skb = NULL;
skb_trim(skb, 0);
if (if_newhead(&dch->inst.up, PH_DATA_CNF, DINFO_SKB, skb))
dev_kfree_skb(skb);
}
}
if (test_and_clear_bit(D_RCVBUFREADY, &dch->event)) {
while ((skb = skb_dequeue(&dch->rqueue))) {
err = if_newhead(&dch->inst.up, PH_DATA_IND, DINFO_SKB, skb);
if (err < 0) {
printk(KERN_WARNING "%s: deliver err %d\n", __FUNCTION__, err);
dev_kfree_skb(skb);
}
}
}
if (dch->hw_bh)
dch->hw_bh(dch);
}
int
init_dchannel(dchannel_t *dch) {
if (!(dch->dlog = kmalloc(MAX_DLOG_SPACE, GFP_ATOMIC))) {
printk(KERN_WARNING
"mISDN: No memory for dlog\n");
return(-ENOMEM);
}
if (!(dch->tx_buf = kmalloc(MAX_DFRAME_LEN_L1, GFP_ATOMIC))) {
printk(KERN_WARNING
"mISDN: No memory for dchannel tx_buf\n");
kfree(dch->dlog);
dch->dlog = NULL;
return(-ENOMEM);
}
dch->hw = NULL;
dch->rx_skb = NULL;
dch->tx_idx = 0;
dch->next_skb = NULL;
dch->event = 0;
dch->tqueue.data = dch;
dch->tqueue.routine = (void *) (void *) dchannel_bh;
dch->hw_bh = NULL;
skb_queue_head_init(&dch->rqueue);
return(0);
}
int
free_dchannel(dchannel_t *dch) {
if (dch->tqueue.sync)
printk(KERN_ERR"free_dchannel tqueue.sync\n");
discard_queue(&dch->rqueue);
if (dch->rx_skb) {
dev_kfree_skb(dch->rx_skb);
dch->rx_skb = NULL;
}
if (dch->tx_buf) {
kfree(dch->tx_buf);
dch->tx_buf = NULL;
}
if (dch->next_skb) {
dev_kfree_skb(dch->next_skb);
dch->next_skb = NULL;
}
if (dch->dlog) {
kfree(dch->dlog);
dch->dlog = NULL;
}
return(0);
}

View File

@ -1,93 +0,0 @@
/* $Id$
*
* Basic declarations for dchannel HW
*
* This file is (c) under GNU PUBLIC LICENSE
*
*/
#include <linux/mISDNif.h>
#include <linux/tqueue.h>
#include <linux/smp.h>
#include <linux/ptrace.h>
#include <linux/interrupt.h>
#include <linux/timer.h>
#include <asm/io.h>
#include <linux/ioport.h>
#include <linux/skbuff.h>
#ifdef MEMDBG
#include "memdbg.h"
#endif
#define MAX_DFRAME_LEN_L1 300
#define MAX_MON_FRAME 32
#define MAX_DLOG_SPACE 2048
#define FLG_TWO_DCHAN 4
#define FLG_TX_BUSY 5
#define FLG_TX_NEXT 6
#define FLG_L1_DBUSY 7
#define FLG_DBUSY_TIMER 8
#define FLG_LOCK_ATOMIC 9
#define FLG_ARCOFI_TIMER 10
#define FLG_ARCOFI_ERROR 11
#define FLG_HW_L1_UINT 12
#define FLG_HW_INIT 13
typedef struct _dchannel_t {
mISDNinstance_t inst;
u_int DFlags;
u_int type;
u_int ph_state;
u_char (*read_reg) (void *, u_char);
void (*write_reg) (void *, u_char, u_char);
void (*read_fifo) (void *, u_char *, int);
void (*write_fifo) (void *, u_char *, int);
char *dlog;
int debug;
struct sk_buff *rx_skb;
struct sk_buff *next_skb;
u_char *tx_buf;
int tx_idx;
int tx_len;
int err_crc;
int err_tx;
int err_rx;
void *hw;
struct timer_list dbusytimer;
u_int event;
struct sk_buff_head rqueue; /* D-channel receive queue */
struct tq_struct tqueue;
void (*hw_bh) (struct _dchannel_t *);
} dchannel_t;
#define MON0_RX 1
#define MON1_RX 2
#define MON0_TX 4
#define MON1_TX 8
extern int init_dchannel(dchannel_t *);
extern int free_dchannel(dchannel_t *);
static inline void
dchannel_sched_event(dchannel_t *dch, int event)
{
test_and_set_bit(event, &dch->event);
queue_task(&dch->tqueue, &tq_immediate);
mark_bh(IMMEDIATE_BH);
}
#ifdef __powerpc__
#include <linux/pci.h>
static inline int pci_enable_device(struct pci_dev *dev)
{
u16 cmd;
pci_read_config_word(dev, PCI_COMMAND, &cmd);
cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_IO | PCI_COMMAND_SERR;
cmd &= ~PCI_COMMAND_FAST_BACK;
pci_write_config_word(dev, PCI_COMMAND, cmd);
return(0);
}
#else
#define pci_enable_device(dev) !dev
#endif /* __powerpc__ */

View File

@ -6,7 +6,7 @@
*
*/
#define __NO_VERSION__
#include <linux/module.h>
#include <linux/mISDNif.h>
#include <linux/kernel.h>
#include <linux/string.h>
@ -17,7 +17,7 @@
static char tmpbuf[mISDN_STATUS_BUFSIZE];
void
vmISDNdebug(int id, char *head, char *fmt, va_list args)
vmISDN_debug(int id, char *head, char *fmt, va_list args)
{
/* if head == NULL the fmt contains the full info */
char *p = tmpbuf;
@ -30,24 +30,24 @@ vmISDNdebug(int id, char *head, char *fmt, va_list args)
}
void
mISDNdebug(int id, char *head, char *fmt, ...)
mISDN_debug(int id, char *head, char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vmISDNdebug(id, head, fmt, args);
vmISDN_debug(id, head, fmt, args);
va_end(args);
}
void
debugprint(mISDNinstance_t *inst, char *fmt, ...)
mISDN_debugprint(mISDNinstance_t *inst, char *fmt, ...)
{
logdata_t log;
va_start(log.args, fmt);
log.head = inst->name;
log.fmt = fmt;
inst->obj->ctrl(inst, MGR_DEBUGDATA | REQUEST, &log);
mISDN_ctrl(inst, MGR_DEBUGDATA | REQUEST, &log);
va_end(log.args);
}
@ -60,6 +60,7 @@ mISDN_getrev(const char *revision)
if ((p = strchr(revision, ':'))) {
rev = p + 2;
p = strchr(rev, '$');
if (p)
*--p = 0;
} else
rev = "???";
@ -67,7 +68,7 @@ mISDN_getrev(const char *revision)
}
int
QuickHex(char *txt, u_char * p, int cnt)
mISDN_QuickHex(char *txt, u_char * p, int cnt)
{
register int i;
register char *t = txt;
@ -89,3 +90,9 @@ QuickHex(char *txt, u_char * p, int cnt)
*t++ = 0;
return (t - txt);
}
EXPORT_SYMBOL(vmISDN_debug);
EXPORT_SYMBOL(mISDN_debug);
EXPORT_SYMBOL(mISDN_getrev);
EXPORT_SYMBOL(mISDN_debugprint);
EXPORT_SYMBOL(mISDN_QuickHex);

View File

@ -5,9 +5,13 @@
* This file is (c) under GNU PUBLIC LICENSE
*
*/
#ifndef MISDN_DEBUG_H
extern void vmISDNdebug(int id, char *head, char *fmt, va_list args);
extern void mISDNdebug(int id, char *head, char *fmt, ...);
#define MISDN_DEBUG_MANAGER 0x10000
extern void vmISDN_debug(int id, char *head, char *fmt, va_list args);
extern void mISDN_debug(int id, char *head, char *fmt, ...);
extern char * mISDN_getrev(const char *revision);
extern void debugprint(mISDNinstance_t *inst, char *fmt, ...);
extern int QuickHex(char *, u_char *, int);
extern void mISDN_debugprint(mISDNinstance_t *inst, char *fmt, ...);
extern int mISDN_QuickHex(char *, u_char *, int);
#endif

View File

@ -0,0 +1,298 @@
/* $Id$
*
* Audio support data for ISDN4Linux.
*
* Copyright 2002/2003 by Andreas Eversberg (jolly@eversberg.eu)
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#define DEBUG_DSP_MGR 0x0001
#define DEBUG_DSP_CORE 0x0002
#define DEBUG_DSP_DTMF 0x0004
#define DEBUG_DSP_DTMFCOEFF 0x0008
#define DEBUG_DSP_CMX 0x0010
#define DEBUG_DSP_TONE 0x0020
#define DEBUG_DSP_BLOWFISH 0x0040
#define DEBUG_DSP_DELAY 0x0080
/* options may be:
*
* bit 0 = use ulaw instead of alaw
* bit 1 = enable hfc hardware accelleration for all channels
*
*/
#define DSP_OPT_ULAW (1<<0)
#define DSP_OPT_NOHARDWARE (1<<1)
#define FEAT_STATE_INIT 1
#define FEAT_STATE_WAIT 2
#define FEAT_STATE_RECEIVED 3
#include <linux/timer.h>
#ifdef MISDN_MEMDEBUG
#include "memdbg.h"
#endif
#include "dsp_ecdis.h"
/*
* You are now able to choose between the Mark2 and the
* kb1 Echo cancellor. Just comment the one and comment
* out the other.
*/
//#define AGGRESSIVE_SUPPRESSOR
//#include "dsp_mec2.h"
//#include "dsp_kb1ec.h"
#include "dsp_mg2ec.h"
/*
* uncomment this one to cancel echo more aggressive
*/
//#define AGGRESSIVE_SUPPRESSOR
extern int dsp_options;
extern int dsp_debug;
extern int dsp_poll;
extern int dsp_tics;
/***************
* audio stuff *
***************/
extern s32 dsp_audio_alaw_to_s32[256];
extern s32 dsp_audio_ulaw_to_s32[256];
extern s32 *dsp_audio_law_to_s32;
extern u8 dsp_audio_s16_to_law[65536];
extern u8 dsp_audio_alaw_to_ulaw[256];
extern u8 dsp_audio_mix_law[65536];
extern u8 dsp_audio_seven2law[128];
extern u8 dsp_audio_law2seven[256];
extern void dsp_audio_generate_s2law_table(void);
extern void dsp_audio_generate_seven(void);
extern void dsp_audio_generate_mix_table(void);
extern void dsp_audio_generate_ulaw_samples(void);
extern void dsp_audio_generate_volume_changes(void);
extern u8 dsp_silence;
/*************
* cmx stuff *
*************/
#define MAX_POLL 256 /* maximum number of send-chunks */
#define CMX_BUFF_SIZE 0x8000 /* must be 2**n (0x1000 about 1/2 second) */
#define CMX_BUFF_HALF 0x4000 /* CMX_BUFF_SIZE / 2 */
#define CMX_BUFF_MASK 0x7fff /* CMX_BUFF_SIZE - 1 */
/* how many seconds will we check the lowest delay until the jitter buffer
is reduced by that delay */
#define MAX_SECONDS_JITTER_CHECK 5
extern struct timer_list dsp_spl_tl;
extern u64 dsp_spl_jiffies;
/* the structure of conferences:
*
* each conference has a unique number, given by user space.
* the conferences are linked in a chain.
* each conference has members linked in a chain.
* each dsplayer points to a member, each member points to a dsplayer.
*/
/* all members within a conference (this is linked 1:1 with the dsp) */
struct _dsp;
typedef struct _conf_member {
struct list_head list;
struct _dsp *dsp;
} conf_member_t;
/* the list of all conferences */
typedef struct _conference {
struct list_head list;
u32 id; /* all cmx stacks with the same ID are connected */
struct list_head mlist;
int software; /* conf is processed by software */
int hardware; /* conf is processed by hardware */
} conference_t;
extern mISDNobject_t dsp_obj;
/**************
* DTMF stuff *
**************/
#define DSP_DTMF_NPOINTS 102
#define ECHOCAN_BUFLEN 4*128
typedef struct _dtmf_t {
int treshold; /* above this is dtmf (square of) */
int software; /* dtmf uses software decoding */
int hardware; /* dtmf uses hardware decoding */
int size; /* number of bytes in buffer */
signed short buffer[DSP_DTMF_NPOINTS]; /* buffers one full dtmf frame */
u8 lastwhat, lastdigit;
int count;
u8 digits[16]; /* just the dtmf result */
} dtmf_t;
/****************
* cancel stuff *
****************/
/***************
* tones stuff *
***************/
typedef struct _tone_t {
int software; /* tones are generated by software */
int hardware; /* tones are generated by hardware */
int tone;
void *pattern;
int count;
int index;
struct timer_list tl;
} tone_t;
/*****************
* general stuff *
*****************/
#define DELAY_CHECK 8000
struct dsp_features {
int hfc_id; /* unique id to identify the chip (or -1) */
int hfc_dtmf; /* set if HFCmulti card supports dtmf */
int hfc_loops; /* set if card supports tone loops */
int hfc_echocanhw; /* set if card supports echocancelation*/
int pcm_id; /* unique id to identify the pcm bus (or -1) */
int pcm_slots; /* number of slots on the pcm bus */
int pcm_banks; /* number of IO banks of pcm bus */
int has_jitter; /* data is jittered and unsorted */
};
typedef struct _dsp {
struct list_head list;
mISDNinstance_t inst;
int b_active;
int echo; /* echo is done by software */
int rx_disabled;
int tx_mix;
tone_t tone;
dtmf_t dtmf;
int queue_dtmf; /* flags enabled dtmf, prior feature reply */
int tx_volume, rx_volume;
/* conference stuff */
u32 conf_id;
conference_t *conf;
conf_member_t *member;
/* while we're waiting for the hw */
u32 queue_conf_id; /* stores conf id prior feature reply */
/* buffer stuff */
int rx_W; /* current write pos for data without timestamp */
int rx_R; /* current read pos for transmit clock */
int tx_W; /* current write pos for transmit data */
int tx_R; /* current read pos for transmit clock */
int delay[MAX_SECONDS_JITTER_CHECK];
u8 tx_buff[CMX_BUFF_SIZE];
u8 rx_buff[CMX_BUFF_SIZE];
/* hardware stuff */
struct dsp_features features; /* features */
struct timer_list feature_tl;
spinlock_t feature_lock;
int feature_state;
int pcm_slot_rx; /* current PCM slot (or -1) */
int pcm_bank_rx;
int pcm_slot_tx;
int pcm_bank_tx;
int hfc_conf; /* unique id of current conference (or -1) */
/* encryption stuff */
int bf_enable;
u32 bf_p[18];
u32 bf_s[1024];
int bf_crypt_pos;
u8 bf_data_in[9];
u8 bf_crypt_out[9];
int bf_decrypt_in_pos;
int bf_decrypt_out_pos;
u8 bf_crypt_inring[16];
u8 bf_data_out[9];
int bf_sync;
/* echo cancellation stuff */
int queue_cancel[3]; /* stores cancel values prior feature reply */
int cancel_enable;
int cancel_hardware; /*we are using hw echo canc*/
struct echo_can_state * ec; /**< == NULL: echo cancellation disabled;
!= NULL: echo cancellation enabled */
echo_can_disable_detector_state_t* ecdis_rd;
echo_can_disable_detector_state_t* ecdis_wr;
uint16_t echotimer;
uint16_t echostate;
uint16_t echolastupdate;
char txbuf[ECHOCAN_BUFLEN];
int txbuflen;
char rxbuf[ECHOCAN_BUFLEN];
int rxbuflen;
} dsp_t;
/* functions */
extern void dsp_change_volume(struct sk_buff *skb, int volume);
extern struct list_head Conf_list;
extern void dsp_cmx_debug(dsp_t *dsp);
extern void dsp_cmx_hardware(conference_t *conf, dsp_t *dsp);
extern int dsp_cmx_conf(dsp_t *dsp, u32 conf_id);
extern void dsp_cmx_receive(dsp_t *dsp, struct sk_buff *skb);
#ifdef OLDCMX
extern struct sk_buff *dsp_cmx_send(dsp_t *dsp, int len, int dinfo);
#else
extern void dsp_cmx_send(void *data);
#endif
extern void dsp_cmx_transmit(dsp_t *dsp, struct sk_buff *skb);
extern int dsp_cmx_del_conf_member(dsp_t *dsp);
extern int dsp_cmx_del_conf(conference_t *conf);
extern void dsp_dtmf_goertzel_init(dsp_t *dsp);
extern u8 *dsp_dtmf_goertzel_decode(dsp_t *dsp, u8 *data, int len, int fmt);
extern int dsp_tone(dsp_t *dsp, int tone);
extern void dsp_tone_copy(dsp_t *dsp, u8 *data, int len);
extern void dsp_tone_timeout(void *arg);
extern void dsp_bf_encrypt(dsp_t *dsp, u8 *data, int len);
extern void dsp_bf_decrypt(dsp_t *dsp, u8 *data, int len);
extern int dsp_bf_init(dsp_t *dsp, const u8 *key, unsigned int keylen);
extern void dsp_bf_cleanup(dsp_t *dsp);
extern void dsp_cancel_tx(dsp_t *dsp, u8 *data, int len);
extern void dsp_cancel_rx(dsp_t *dsp, u8 *data, int len);
extern int dsp_cancel_init(dsp_t *dsp, int taps, int training, int delay);

View File

@ -0,0 +1,347 @@
#ifndef _ZAPTEL_ARITH_H
#define _ZAPTEL_ARITH_H
/*
* Handy add/subtract functions to operate on chunks of shorts.
* Feel free to add customizations for additional architectures
*
*/
#ifdef CONFIG_ZAPTEL_MMX
#ifdef ZT_CHUNKSIZE
static inline void __ACSS(volatile short *dst, const short *src)
{
__asm__ __volatile__ (
"movq 0(%0), %%mm0;\n"
"movq 0(%1), %%mm1;\n"
"movq 8(%0), %%mm2;\n"
"movq 8(%1), %%mm3;\n"
"paddsw %%mm1, %%mm0;\n"
"paddsw %%mm3, %%mm2;\n"
"movq %%mm0, 0(%0);\n"
"movq %%mm2, 8(%0);\n"
: "=r" (dst)
: "r" (src), "0" (dst)
: "memory"
#if CLOBBERMMX
, "%mm0", "%mm1", "%mm2", "%mm3"
#endif
);
}
static inline void __SCSS(volatile short *dst, const short *src)
{
__asm__ __volatile__ (
"movq 0(%0), %%mm0;\n"
"movq 0(%1), %%mm1;\n"
"movq 8(%0), %%mm2;\n"
"movq 8(%1), %%mm3;\n"
"psubsw %%mm1, %%mm0;\n"
"psubsw %%mm3, %%mm2;\n"
"movq %%mm0, 0(%0);\n"
"movq %%mm2, 8(%0);\n"
: "=r" (dst)
: "r" (src), "0" (dst)
: "memory"
#if CLOBBERMMX
, "%mm0", "%mm1", "%mm2", "%mm3"
#endif
);
}
#if (ZT_CHUNKSIZE == 8)
#define ACSS(a,b) __ACSS(a,b)
#define SCSS(a,b) __SCSS(a,b)
#elif (ZT_CHUNKSIZE > 8)
static inline void ACSS(volatile short *dst, const short *src)
{
int x;
for (x=0;x<ZT_CHUNKSIZE;x+=8)
__ACSS(dst + x, src + x);
}
static inline void SCSS(volatile short *dst, const short *src)
{
int x;
for (x=0;x<ZT_CHUNKSIZE;x+=8)
__SCSS(dst + x, src + x);
}
#else
#error No MMX for ZT_CHUNKSIZE < 8
#endif
#endif
static inline int CONVOLVE(const int *coeffs, const short *hist, int len)
{
int sum;
/* Divide length by 16 */
len >>= 4;
/* Clear our accumulator, mm4 */
/*
For every set of eight...
Load 16 coefficients into four registers...
Shift each word right 16 to make them shorts...
Pack the resulting shorts into two registers...
With the coefficients now in mm0 and mm2, load the
history into mm1 and mm3...
Multiply/add mm1 into mm0, and mm3 into mm2...
Add mm2 into mm0 (without saturation, alas). Now we have two half-results.
Accumulate in mm4 (again, without saturation, alas)
*/
__asm__ (
"pxor %%mm4, %%mm4;\n"
"mov %1, %%edi;\n"
"mov %2, %%esi;\n"
"mov %3, %%ecx;\n"
"1:"
"movq 0(%%edi), %%mm0;\n"
"movq 8(%%edi), %%mm1;\n"
"movq 16(%%edi), %%mm2;\n"
"movq 24(%%edi), %%mm3;\n"
/* can't use 4/5 since 4 is the accumulator for us */
"movq 32(%%edi), %%mm6;\n"
"movq 40(%%edi), %%mm7;\n"
"psrad $16, %%mm0;\n"
"psrad $16, %%mm1;\n"
"psrad $16, %%mm2;\n"
"psrad $16, %%mm3;\n"
"psrad $16, %%mm6;\n"
"psrad $16, %%mm7;\n"
"packssdw %%mm1, %%mm0;\n"
"packssdw %%mm3, %%mm2;\n"
"packssdw %%mm7, %%mm6;\n"
"movq 0(%%esi), %%mm1;\n"
"movq 8(%%esi), %%mm3;\n"
"movq 16(%%esi), %%mm7;\n"
"pmaddwd %%mm1, %%mm0;\n"
"pmaddwd %%mm3, %%mm2;\n"
"pmaddwd %%mm7, %%mm6;\n"
"paddd %%mm6, %%mm4;\n"
"paddd %%mm2, %%mm4;\n"
"paddd %%mm0, %%mm4;\n"
/* Come back and do for the last few bytes */
"movq 48(%%edi), %%mm6;\n"
"movq 56(%%edi), %%mm7;\n"
"psrad $16, %%mm6;\n"
"psrad $16, %%mm7;\n"
"packssdw %%mm7, %%mm6;\n"
"movq 24(%%esi), %%mm7;\n"
"pmaddwd %%mm7, %%mm6;\n"
"paddd %%mm6, %%mm4;\n"
"add $64, %%edi;\n"
"add $32, %%esi;\n"
"dec %%ecx;\n"
"jnz 1b;\n"
"movq %%mm4, %%mm0;\n"
"psrlq $32, %%mm0;\n"
"paddd %%mm0, %%mm4;\n"
"movd %%mm4, %0;\n"
: "=r" (sum)
: "r" (coeffs), "r" (hist), "r" (len)
: "%ecx", "%edi", "%esi"
);
return sum;
}
static inline void UPDATE(volatile int *taps, const short *history, const int nsuppr, const int ntaps)
{
int i;
int correction;
for (i=0;i<ntaps;i++) {
correction = history[i] * nsuppr;
taps[i] += correction;
}
}
static inline void UPDATE2(volatile int *taps, volatile short *taps_short, const short *history, const int nsuppr, const int ntaps)
{
int i;
int correction;
#if 0
ntaps >>= 4;
/* First, load up taps, */
__asm__ (
"pxor %%mm4, %%mm4;\n"
"mov %0, %%edi;\n"
"mov %1, %%esi;\n"
"mov %3, %%ecx;\n"
"1:"
"jnz 1b;\n"
"movq %%mm4, %%mm0;\n"
"psrlq $32, %%mm0;\n"
"paddd %%mm0, %%mm4;\n"
"movd %%mm4, %0;\n"
: "=r" (taps), "=r" (taps_short)
: "r" (history), "r" (nsuppr), "r" (ntaps), "0" (taps)
: "%ecx", "%edi", "%esi"
);
#endif
#if 1
for (i=0;i<ntaps;i++) {
correction = history[i] * nsuppr;
taps[i] += correction;
taps_short[i] = taps[i] >> 16;
}
#endif
}
static inline int CONVOLVE2(const short *coeffs, const short *hist, int len)
{
int sum;
/* Divide length by 16 */
len >>= 4;
/* Clear our accumulator, mm4 */
/*
For every set of eight...
Load in eight coefficients and eight historic samples, multliply add and
accumulate the result
*/
__asm__ (
"pxor %%mm4, %%mm4;\n"
"mov %1, %%edi;\n"
"mov %2, %%esi;\n"
"mov %3, %%ecx;\n"
"1:"
"movq 0(%%edi), %%mm0;\n"
"movq 8(%%edi), %%mm2;\n"
"movq 0(%%esi), %%mm1;\n"
"movq 8(%%esi), %%mm3;\n"
"pmaddwd %%mm1, %%mm0;\n"
"pmaddwd %%mm3, %%mm2;\n"
"paddd %%mm2, %%mm4;\n"
"paddd %%mm0, %%mm4;\n"
"movq 16(%%edi), %%mm0;\n"
"movq 24(%%edi), %%mm2;\n"
"movq 16(%%esi), %%mm1;\n"
"movq 24(%%esi), %%mm3;\n"
"pmaddwd %%mm1, %%mm0;\n"
"pmaddwd %%mm3, %%mm2;\n"
"paddd %%mm2, %%mm4;\n"
"paddd %%mm0, %%mm4;\n"
"add $32, %%edi;\n"
"add $32, %%esi;\n"
"dec %%ecx;\n"
"jnz 1b;\n"
"movq %%mm4, %%mm0;\n"
"psrlq $32, %%mm0;\n"
"paddd %%mm0, %%mm4;\n"
"movd %%mm4, %0;\n"
: "=r" (sum)
: "r" (coeffs), "r" (hist), "r" (len)
: "%ecx", "%edi", "%esi"
);
return sum;
}
static inline short MAX16(const short *y, int len, int *pos)
{
int k;
short max = 0;
int bestpos = 0;
for (k=0;k<len;k++) {
if (max < y[k]) {
bestpos = k;
max = y[k];
}
}
*pos = (len - 1 - bestpos);
return max;
}
#else
#ifdef ZT_CHUNKSIZE
static inline void ACSS(short *dst, short *src)
{
int x,sum;
/* Add src to dst with saturation, storing in dst */
for (x=0;x<ZT_CHUNKSIZE;x++) {
sum = dst[x]+src[x];
if (sum > 32767)
sum = 32767;
else if (sum < -32768)
sum = -32768;
dst[x] = sum;
}
}
static inline void SCSS(short *dst, short *src)
{
int x,sum;
/* Add src to dst with saturation, storing in dst */
for (x=0;x<ZT_CHUNKSIZE;x++) {
sum = dst[x]-src[x];
if (sum > 32767)
sum = 32767;
else if (sum < -32768)
sum = -32768;
dst[x] = sum;
}
}
#endif /* ZT_CHUNKSIZE */
static inline int CONVOLVE(const int *coeffs, const short *hist, int len)
{
int x;
int sum = 0;
for (x=0;x<len;x++)
sum += (coeffs[x] >> 16) * hist[x];
return sum;
}
static inline int CONVOLVE2(const short *coeffs, const short *hist, int len)
{
int x;
int sum = 0;
for (x=0;x<len;x++)
sum += coeffs[x] * hist[x];
return sum;
}
static inline void UPDATE(int *taps, const short *history, const int nsuppr, const int ntaps)
{
int i;
int correction;
for (i=0;i<ntaps;i++) {
correction = history[i] * nsuppr;
taps[i] += correction;
}
}
static inline void UPDATE2(int *taps, short *taps_short, const short *history, const int nsuppr, const int ntaps)
{
int i;
int correction;
for (i=0;i<ntaps;i++) {
correction = history[i] * nsuppr;
taps[i] += correction;
taps_short[i] = taps[i] >> 16;
}
}
static inline short MAX16(const short *y, int len, int *pos)
{
int k;
short max = 0;
int bestpos = 0;
for (k=0;k<len;k++) {
if (max < y[k]) {
bestpos = k;
max = y[k];
}
}
*pos = (len - 1 - bestpos);
return max;
}
#endif /* MMX */
#endif /* _ZAPTEL_ARITH_H */

View File

@ -0,0 +1,583 @@
/* $Id$
*
* Audio support data for mISDN_dsp.
*
* Copyright 2002/2003 by Andreas Eversberg (jolly@eversberg.eu)
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#include "layer1.h"
#include "helper.h"
#include "debug.h"
#include "dsp.h"
/* ulaw[unsigned char] -> signed 16-bit */
s32 dsp_audio_ulaw_to_s32[256] =
{
0xffff8284, 0xffff8684, 0xffff8a84, 0xffff8e84,
0xffff9284, 0xffff9684, 0xffff9a84, 0xffff9e84,
0xffffa284, 0xffffa684, 0xffffaa84, 0xffffae84,
0xffffb284, 0xffffb684, 0xffffba84, 0xffffbe84,
0xffffc184, 0xffffc384, 0xffffc584, 0xffffc784,
0xffffc984, 0xffffcb84, 0xffffcd84, 0xffffcf84,
0xffffd184, 0xffffd384, 0xffffd584, 0xffffd784,
0xffffd984, 0xffffdb84, 0xffffdd84, 0xffffdf84,
0xffffe104, 0xffffe204, 0xffffe304, 0xffffe404,
0xffffe504, 0xffffe604, 0xffffe704, 0xffffe804,
0xffffe904, 0xffffea04, 0xffffeb04, 0xffffec04,
0xffffed04, 0xffffee04, 0xffffef04, 0xfffff004,
0xfffff0c4, 0xfffff144, 0xfffff1c4, 0xfffff244,
0xfffff2c4, 0xfffff344, 0xfffff3c4, 0xfffff444,
0xfffff4c4, 0xfffff544, 0xfffff5c4, 0xfffff644,
0xfffff6c4, 0xfffff744, 0xfffff7c4, 0xfffff844,
0xfffff8a4, 0xfffff8e4, 0xfffff924, 0xfffff964,
0xfffff9a4, 0xfffff9e4, 0xfffffa24, 0xfffffa64,
0xfffffaa4, 0xfffffae4, 0xfffffb24, 0xfffffb64,
0xfffffba4, 0xfffffbe4, 0xfffffc24, 0xfffffc64,
0xfffffc94, 0xfffffcb4, 0xfffffcd4, 0xfffffcf4,
0xfffffd14, 0xfffffd34, 0xfffffd54, 0xfffffd74,
0xfffffd94, 0xfffffdb4, 0xfffffdd4, 0xfffffdf4,
0xfffffe14, 0xfffffe34, 0xfffffe54, 0xfffffe74,
0xfffffe8c, 0xfffffe9c, 0xfffffeac, 0xfffffebc,
0xfffffecc, 0xfffffedc, 0xfffffeec, 0xfffffefc,
0xffffff0c, 0xffffff1c, 0xffffff2c, 0xffffff3c,
0xffffff4c, 0xffffff5c, 0xffffff6c, 0xffffff7c,
0xffffff88, 0xffffff90, 0xffffff98, 0xffffffa0,
0xffffffa8, 0xffffffb0, 0xffffffb8, 0xffffffc0,
0xffffffc8, 0xffffffd0, 0xffffffd8, 0xffffffe0,
0xffffffe8, 0xfffffff0, 0xfffffff8, 0xffffffff,
0x00007d7c, 0x0000797c, 0x0000757c, 0x0000717c,
0x00006d7c, 0x0000697c, 0x0000657c, 0x0000617c,
0x00005d7c, 0x0000597c, 0x0000557c, 0x0000517c,
0x00004d7c, 0x0000497c, 0x0000457c, 0x0000417c,
0x00003e7c, 0x00003c7c, 0x00003a7c, 0x0000387c,
0x0000367c, 0x0000347c, 0x0000327c, 0x0000307c,
0x00002e7c, 0x00002c7c, 0x00002a7c, 0x0000287c,
0x0000267c, 0x0000247c, 0x0000227c, 0x0000207c,
0x00001efc, 0x00001dfc, 0x00001cfc, 0x00001bfc,
0x00001afc, 0x000019fc, 0x000018fc, 0x000017fc,
0x000016fc, 0x000015fc, 0x000014fc, 0x000013fc,
0x000012fc, 0x000011fc, 0x000010fc, 0x00000ffc,
0x00000f3c, 0x00000ebc, 0x00000e3c, 0x00000dbc,
0x00000d3c, 0x00000cbc, 0x00000c3c, 0x00000bbc,
0x00000b3c, 0x00000abc, 0x00000a3c, 0x000009bc,
0x0000093c, 0x000008bc, 0x0000083c, 0x000007bc,
0x0000075c, 0x0000071c, 0x000006dc, 0x0000069c,
0x0000065c, 0x0000061c, 0x000005dc, 0x0000059c,
0x0000055c, 0x0000051c, 0x000004dc, 0x0000049c,
0x0000045c, 0x0000041c, 0x000003dc, 0x0000039c,
0x0000036c, 0x0000034c, 0x0000032c, 0x0000030c,
0x000002ec, 0x000002cc, 0x000002ac, 0x0000028c,
0x0000026c, 0x0000024c, 0x0000022c, 0x0000020c,
0x000001ec, 0x000001cc, 0x000001ac, 0x0000018c,
0x00000174, 0x00000164, 0x00000154, 0x00000144,
0x00000134, 0x00000124, 0x00000114, 0x00000104,
0x000000f4, 0x000000e4, 0x000000d4, 0x000000c4,
0x000000b4, 0x000000a4, 0x00000094, 0x00000084,
0x00000078, 0x00000070, 0x00000068, 0x00000060,
0x00000058, 0x00000050, 0x00000048, 0x00000040,
0x00000038, 0x00000030, 0x00000028, 0x00000020,
0x00000018, 0x00000010, 0x00000008, 0x00000000
};
/* alaw[unsigned char] -> signed 16-bit */
s32 dsp_audio_alaw_to_s32[256] =
{
0x000013fc, 0xffffec04, 0x00000144, 0xfffffebc,
0x0000517c, 0xffffae84, 0x0000051c, 0xfffffae4,
0x00000a3c, 0xfffff5c4, 0x00000048, 0xffffffb8,
0x0000287c, 0xffffd784, 0x0000028c, 0xfffffd74,
0x00001bfc, 0xffffe404, 0x000001cc, 0xfffffe34,
0x0000717c, 0xffff8e84, 0x0000071c, 0xfffff8e4,
0x00000e3c, 0xfffff1c4, 0x000000c4, 0xffffff3c,
0x0000387c, 0xffffc784, 0x0000039c, 0xfffffc64,
0x00000ffc, 0xfffff004, 0x00000104, 0xfffffefc,
0x0000417c, 0xffffbe84, 0x0000041c, 0xfffffbe4,
0x0000083c, 0xfffff7c4, 0x00000008, 0xfffffff8,
0x0000207c, 0xffffdf84, 0x0000020c, 0xfffffdf4,
0x000017fc, 0xffffe804, 0x0000018c, 0xfffffe74,
0x0000617c, 0xffff9e84, 0x0000061c, 0xfffff9e4,
0x00000c3c, 0xfffff3c4, 0x00000084, 0xffffff7c,
0x0000307c, 0xffffcf84, 0x0000030c, 0xfffffcf4,
0x000015fc, 0xffffea04, 0x00000164, 0xfffffe9c,
0x0000597c, 0xffffa684, 0x0000059c, 0xfffffa64,
0x00000b3c, 0xfffff4c4, 0x00000068, 0xffffff98,
0x00002c7c, 0xffffd384, 0x000002cc, 0xfffffd34,
0x00001dfc, 0xffffe204, 0x000001ec, 0xfffffe14,
0x0000797c, 0xffff8684, 0x000007bc, 0xfffff844,
0x00000f3c, 0xfffff0c4, 0x000000e4, 0xffffff1c,
0x00003c7c, 0xffffc384, 0x000003dc, 0xfffffc24,
0x000011fc, 0xffffee04, 0x00000124, 0xfffffedc,
0x0000497c, 0xffffb684, 0x0000049c, 0xfffffb64,
0x0000093c, 0xfffff6c4, 0x00000028, 0xffffffd8,
0x0000247c, 0xffffdb84, 0x0000024c, 0xfffffdb4,
0x000019fc, 0xffffe604, 0x000001ac, 0xfffffe54,
0x0000697c, 0xffff9684, 0x0000069c, 0xfffff964,
0x00000d3c, 0xfffff2c4, 0x000000a4, 0xffffff5c,
0x0000347c, 0xffffcb84, 0x0000034c, 0xfffffcb4,
0x000012fc, 0xffffed04, 0x00000134, 0xfffffecc,
0x00004d7c, 0xffffb284, 0x000004dc, 0xfffffb24,
0x000009bc, 0xfffff644, 0x00000038, 0xffffffc8,
0x0000267c, 0xffffd984, 0x0000026c, 0xfffffd94,
0x00001afc, 0xffffe504, 0x000001ac, 0xfffffe54,
0x00006d7c, 0xffff9284, 0x000006dc, 0xfffff924,
0x00000dbc, 0xfffff244, 0x000000b4, 0xffffff4c,
0x0000367c, 0xffffc984, 0x0000036c, 0xfffffc94,
0x00000f3c, 0xfffff0c4, 0x000000f4, 0xffffff0c,
0x00003e7c, 0xffffc184, 0x000003dc, 0xfffffc24,
0x000007bc, 0xfffff844, 0x00000008, 0xfffffff8,
0x00001efc, 0xffffe104, 0x000001ec, 0xfffffe14,
0x000016fc, 0xffffe904, 0x00000174, 0xfffffe8c,
0x00005d7c, 0xffffa284, 0x000005dc, 0xfffffa24,
0x00000bbc, 0xfffff444, 0x00000078, 0xffffff88,
0x00002e7c, 0xffffd184, 0x000002ec, 0xfffffd14,
0x000014fc, 0xffffeb04, 0x00000154, 0xfffffeac,
0x0000557c, 0xffffaa84, 0x0000055c, 0xfffffaa4,
0x00000abc, 0xfffff544, 0x00000058, 0xffffffa8,
0x00002a7c, 0xffffd584, 0x000002ac, 0xfffffd54,
0x00001cfc, 0xffffe304, 0x000001cc, 0xfffffe34,
0x0000757c, 0xffff8a84, 0x0000075c, 0xfffff8a4,
0x00000ebc, 0xfffff144, 0x000000d4, 0xffffff2c,
0x00003a7c, 0xffffc584, 0x0000039c, 0xfffffc64,
0x000010fc, 0xffffef04, 0x00000114, 0xfffffeec,
0x0000457c, 0xffffba84, 0x0000045c, 0xfffffba4,
0x000008bc, 0xfffff744, 0x00000018, 0xffffffe8,
0x0000227c, 0xffffdd84, 0x0000022c, 0xfffffdd4,
0x000018fc, 0xffffe704, 0x0000018c, 0xfffffe74,
0x0000657c, 0xffff9a84, 0x0000065c, 0xfffff9a4,
0x00000cbc, 0xfffff344, 0x00000094, 0xffffff6c,
0x0000327c, 0xffffcd84, 0x0000032c, 0xfffffcd4
};
s32 *dsp_audio_law_to_s32;
/* signed 16-bit -> law */
u8 dsp_audio_s16_to_law[65536];
/* table is used to generate s16_to_alaw */
static short dsp_audio_alaw_relations[512] =
{
0x8684, 0x55, 0x8a84, 0xd5, 0x8e84, 0x15, 0x9284, 0x95,
0x9684, 0x75, 0x9a84, 0xf5, 0x9e84, 0x35, 0xa284, 0xb5,
0xa684, 0x45, 0xaa84, 0xc5, 0xae84, 0x05, 0xb284, 0x85,
0xb684, 0x65, 0xba84, 0xe5, 0xbe84, 0x25, 0xc184, 0xa5,
0xc384, 0x5d, 0xc584, 0xdd, 0xc784, 0x1d, 0xc984, 0x9d,
0xcb84, 0x7d, 0xcd84, 0xfd, 0xcf84, 0x3d, 0xd184, 0xbd,
0xd384, 0x4d, 0xd584, 0xcd, 0xd784, 0x0d, 0xd984, 0x8d,
0xdb84, 0x6d, 0xdd84, 0xed, 0xdf84, 0x2d, 0xe104, 0xad,
0xe204, 0x51, 0xe304, 0xd1, 0xe404, 0x11, 0xe504, 0x91,
0xe604, 0x71, 0xe704, 0xf1, 0xe804, 0x31, 0xe904, 0xb1,
0xea04, 0x41, 0xeb04, 0xc1, 0xec04, 0x01, 0xed04, 0x81,
0xee04, 0x61, 0xef04, 0xe1, 0xf004, 0x21, 0xf0c4, 0x59,
0xf0c4, 0xa1, 0xf144, 0xd9, 0xf1c4, 0x19, 0xf244, 0x99,
0xf2c4, 0x79, 0xf344, 0xf9, 0xf3c4, 0x39, 0xf444, 0xb9,
0xf4c4, 0x49, 0xf544, 0xc9, 0xf5c4, 0x09, 0xf644, 0x89,
0xf6c4, 0x69, 0xf744, 0xe9, 0xf7c4, 0x29, 0xf844, 0x57,
0xf844, 0xa9, 0xf8a4, 0xd7, 0xf8e4, 0x17, 0xf924, 0x97,
0xf964, 0x77, 0xf9a4, 0xf7, 0xf9e4, 0x37, 0xfa24, 0xb7,
0xfa64, 0x47, 0xfaa4, 0xc7, 0xfae4, 0x07, 0xfb24, 0x87,
0xfb64, 0x67, 0xfba4, 0xe7, 0xfbe4, 0x27, 0xfc24, 0x5f,
0xfc24, 0xa7, 0xfc64, 0x1f, 0xfc64, 0xdf, 0xfc94, 0x9f,
0xfcb4, 0x7f, 0xfcd4, 0xff, 0xfcf4, 0x3f, 0xfd14, 0xbf,
0xfd34, 0x4f, 0xfd54, 0xcf, 0xfd74, 0x0f, 0xfd94, 0x8f,
0xfdb4, 0x6f, 0xfdd4, 0xef, 0xfdf4, 0x2f, 0xfe14, 0x53,
0xfe14, 0xaf, 0xfe34, 0x13, 0xfe34, 0xd3, 0xfe54, 0x73,
0xfe54, 0x93, 0xfe74, 0x33, 0xfe74, 0xf3, 0xfe8c, 0xb3,
0xfe9c, 0x43, 0xfeac, 0xc3, 0xfebc, 0x03, 0xfecc, 0x83,
0xfedc, 0x63, 0xfeec, 0xe3, 0xfefc, 0x23, 0xff0c, 0xa3,
0xff1c, 0x5b, 0xff2c, 0xdb, 0xff3c, 0x1b, 0xff4c, 0x9b,
0xff5c, 0x7b, 0xff6c, 0xfb, 0xff7c, 0x3b, 0xff88, 0xbb,
0xff98, 0x4b, 0xffa8, 0xcb, 0xffb8, 0x0b, 0xffc8, 0x8b,
0xffd8, 0x6b, 0xffe8, 0xeb, 0xfff8, 0x2b, 0xfff8, 0xab,
0x0008, 0x2a, 0x0008, 0xaa, 0x0018, 0xea, 0x0028, 0x6a,
0x0038, 0x8a, 0x0048, 0x0a, 0x0058, 0xca, 0x0068, 0x4a,
0x0078, 0xba, 0x0084, 0x3a, 0x0094, 0xfa, 0x00a4, 0x7a,
0x00b4, 0x9a, 0x00c4, 0x1a, 0x00d4, 0xda, 0x00e4, 0x5a,
0x00f4, 0xa2, 0x0104, 0x22, 0x0114, 0xe2, 0x0124, 0x62,
0x0134, 0x82, 0x0144, 0x02, 0x0154, 0xc2, 0x0164, 0x42,
0x0174, 0xb2, 0x018c, 0x32, 0x018c, 0xf2, 0x01ac, 0x72,
0x01ac, 0x92, 0x01cc, 0x12, 0x01cc, 0xd2, 0x01ec, 0x52,
0x01ec, 0xae, 0x020c, 0x2e, 0x022c, 0xee, 0x024c, 0x6e,
0x026c, 0x8e, 0x028c, 0x0e, 0x02ac, 0xce, 0x02cc, 0x4e,
0x02ec, 0xbe, 0x030c, 0x3e, 0x032c, 0xfe, 0x034c, 0x7e,
0x036c, 0x9e, 0x039c, 0x1e, 0x039c, 0xde, 0x03dc, 0x5e,
0x03dc, 0xa6, 0x041c, 0x26, 0x045c, 0xe6, 0x049c, 0x66,
0x04dc, 0x86, 0x051c, 0x06, 0x055c, 0xc6, 0x059c, 0x46,
0x05dc, 0xb6, 0x061c, 0x36, 0x065c, 0xf6, 0x069c, 0x76,
0x06dc, 0x96, 0x071c, 0x16, 0x075c, 0xd6, 0x07bc, 0x56,
0x07bc, 0xa8, 0x083c, 0x28, 0x08bc, 0xe8, 0x093c, 0x68,
0x09bc, 0x88, 0x0a3c, 0x08, 0x0abc, 0xc8, 0x0b3c, 0x48,
0x0bbc, 0xb8, 0x0c3c, 0x38, 0x0cbc, 0xf8, 0x0d3c, 0x78,
0x0dbc, 0x98, 0x0e3c, 0x18, 0x0ebc, 0xd8, 0x0f3c, 0x58,
0x0f3c, 0xa0, 0x0ffc, 0x20, 0x10fc, 0xe0, 0x11fc, 0x60,
0x12fc, 0x80, 0x13fc, 0x00, 0x14fc, 0xc0, 0x15fc, 0x40,
0x16fc, 0xb0, 0x17fc, 0x30, 0x18fc, 0xf0, 0x19fc, 0x70,
0x1afc, 0x90, 0x1bfc, 0x10, 0x1cfc, 0xd0, 0x1dfc, 0x50,
0x1efc, 0xac, 0x207c, 0x2c, 0x227c, 0xec, 0x247c, 0x6c,
0x267c, 0x8c, 0x287c, 0x0c, 0x2a7c, 0xcc, 0x2c7c, 0x4c,
0x2e7c, 0xbc, 0x307c, 0x3c, 0x327c, 0xfc, 0x347c, 0x7c,
0x367c, 0x9c, 0x387c, 0x1c, 0x3a7c, 0xdc, 0x3c7c, 0x5c,
0x3e7c, 0xa4, 0x417c, 0x24, 0x457c, 0xe4, 0x497c, 0x64,
0x4d7c, 0x84, 0x517c, 0x04, 0x557c, 0xc4, 0x597c, 0x44,
0x5d7c, 0xb4, 0x617c, 0x34, 0x657c, 0xf4, 0x697c, 0x74,
0x6d7c, 0x94, 0x717c, 0x14, 0x757c, 0xd4, 0x797c, 0x54
};
/* alaw -> ulaw */
u8 dsp_audio_alaw_to_ulaw[256] =
{
0xab, 0x2b, 0xe3, 0x63, 0x8b, 0x0b, 0xc9, 0x49,
0xba, 0x3a, 0xf6, 0x76, 0x9b, 0x1b, 0xd7, 0x57,
0xa3, 0x23, 0xdd, 0x5d, 0x83, 0x03, 0xc1, 0x41,
0xb2, 0x32, 0xeb, 0x6b, 0x93, 0x13, 0xcf, 0x4f,
0xaf, 0x2f, 0xe7, 0x67, 0x8f, 0x0f, 0xcd, 0x4d,
0xbe, 0x3e, 0xfe, 0x7e, 0x9f, 0x1f, 0xdb, 0x5b,
0xa7, 0x27, 0xdf, 0x5f, 0x87, 0x07, 0xc5, 0x45,
0xb6, 0x36, 0xef, 0x6f, 0x97, 0x17, 0xd3, 0x53,
0xa9, 0x29, 0xe1, 0x61, 0x89, 0x09, 0xc7, 0x47,
0xb8, 0x38, 0xf2, 0x72, 0x99, 0x19, 0xd5, 0x55,
0xa1, 0x21, 0xdc, 0x5c, 0x81, 0x01, 0xbf, 0x3f,
0xb0, 0x30, 0xe9, 0x69, 0x91, 0x11, 0xce, 0x4e,
0xad, 0x2d, 0xe5, 0x65, 0x8d, 0x0d, 0xcb, 0x4b,
0xbc, 0x3c, 0xfa, 0x7a, 0x9d, 0x1d, 0xd9, 0x59,
0xa5, 0x25, 0xde, 0x5e, 0x85, 0x05, 0xc3, 0x43,
0xb4, 0x34, 0xed, 0x6d, 0x95, 0x15, 0xd1, 0x51,
0xac, 0x2c, 0xe4, 0x64, 0x8c, 0x0c, 0xca, 0x4a,
0xbb, 0x3b, 0xf8, 0x78, 0x9c, 0x1c, 0xd8, 0x58,
0xa4, 0x24, 0xde, 0x5e, 0x84, 0x04, 0xc2, 0x42,
0xb3, 0x33, 0xec, 0x6c, 0x94, 0x14, 0xd0, 0x50,
0xb0, 0x30, 0xe8, 0x68, 0x90, 0x10, 0xce, 0x4e,
0xbf, 0x3f, 0xfe, 0x7e, 0xa0, 0x20, 0xdc, 0x5c,
0xa8, 0x28, 0xe0, 0x60, 0x88, 0x08, 0xc6, 0x46,
0xb7, 0x37, 0xf0, 0x70, 0x98, 0x18, 0xd4, 0x54,
0xaa, 0x2a, 0xe2, 0x62, 0x8a, 0x0a, 0xc8, 0x48,
0xb9, 0x39, 0xf4, 0x74, 0x9a, 0x1a, 0xd6, 0x56,
0xa2, 0x22, 0xdd, 0x5d, 0x82, 0x02, 0xc0, 0x40,
0xb1, 0x31, 0xea, 0x6a, 0x92, 0x12, 0xcf, 0x4f,
0xae, 0x2e, 0xe6, 0x66, 0x8e, 0x0e, 0xcc, 0x4c,
0xbd, 0x3d, 0xfc, 0x7c, 0x9e, 0x1e, 0xda, 0x5a,
0xa6, 0x26, 0xdf, 0x5f, 0x86, 0x06, 0xc4, 0x44,
0xb5, 0x35, 0xee, 0x6e, 0x96, 0x16, 0xd2, 0x52
};
/* ulaw -> alaw */
u8 dsp_audio_ulaw_to_alaw[256] =
{
0xab, 0x55, 0xd5, 0x15, 0x95, 0x75, 0xf5, 0x35,
0xb5, 0x45, 0xc5, 0x05, 0x85, 0x65, 0xe5, 0x25,
0xa5, 0x5d, 0xdd, 0x1d, 0x9d, 0x7d, 0xfd, 0x3d,
0xbd, 0x4d, 0xcd, 0x0d, 0x8d, 0x6d, 0xed, 0x2d,
0xad, 0x51, 0xd1, 0x11, 0x91, 0x71, 0xf1, 0x31,
0xb1, 0x41, 0xc1, 0x01, 0x81, 0x61, 0xe1, 0x21,
0x59, 0xd9, 0x19, 0x99, 0x79, 0xf9, 0x39, 0xb9,
0x49, 0xc9, 0x09, 0x89, 0x69, 0xe9, 0x29, 0xa9,
0xd7, 0x17, 0x97, 0x77, 0xf7, 0x37, 0xb7, 0x47,
0xc7, 0x07, 0x87, 0x67, 0xe7, 0x27, 0xa7, 0xdf,
0x9f, 0x7f, 0xff, 0x3f, 0xbf, 0x4f, 0xcf, 0x0f,
0x8f, 0x6f, 0xef, 0x2f, 0x53, 0x13, 0x73, 0x33,
0xb3, 0x43, 0xc3, 0x03, 0x83, 0x63, 0xe3, 0x23,
0xa3, 0x5b, 0xdb, 0x1b, 0x9b, 0x7b, 0xfb, 0x3b,
0xbb, 0xbb, 0x4b, 0x4b, 0xcb, 0xcb, 0x0b, 0x0b,
0x8b, 0x8b, 0x6b, 0x6b, 0xeb, 0xeb, 0x2b, 0x2b,
0xab, 0x54, 0xd4, 0x14, 0x94, 0x74, 0xf4, 0x34,
0xb4, 0x44, 0xc4, 0x04, 0x84, 0x64, 0xe4, 0x24,
0xa4, 0x5c, 0xdc, 0x1c, 0x9c, 0x7c, 0xfc, 0x3c,
0xbc, 0x4c, 0xcc, 0x0c, 0x8c, 0x6c, 0xec, 0x2c,
0xac, 0x50, 0xd0, 0x10, 0x90, 0x70, 0xf0, 0x30,
0xb0, 0x40, 0xc0, 0x00, 0x80, 0x60, 0xe0, 0x20,
0x58, 0xd8, 0x18, 0x98, 0x78, 0xf8, 0x38, 0xb8,
0x48, 0xc8, 0x08, 0x88, 0x68, 0xe8, 0x28, 0xa8,
0xd6, 0x16, 0x96, 0x76, 0xf6, 0x36, 0xb6, 0x46,
0xc6, 0x06, 0x86, 0x66, 0xe6, 0x26, 0xa6, 0xde,
0x9e, 0x7e, 0xfe, 0x3e, 0xbe, 0x4e, 0xce, 0x0e,
0x8e, 0x6e, 0xee, 0x2e, 0x52, 0x12, 0x72, 0x32,
0xb2, 0x42, 0xc2, 0x02, 0x82, 0x62, 0xe2, 0x22,
0xa2, 0x5a, 0xda, 0x1a, 0x9a, 0x7a, 0xfa, 0x3a,
0xba, 0xba, 0x4a, 0x4a, 0xca, 0xca, 0x0a, 0x0a,
0x8a, 0x8a, 0x6a, 0x6a, 0xea, 0xea, 0x2a, 0x2a
};
u8 dsp_silence;
/*****************************************************
* generate table for conversion of s16 to alaw/ulaw *
*****************************************************/
void
dsp_audio_generate_s2law_table(void)
{
int i, j;
if (dsp_options & DSP_OPT_ULAW) {
/* generating ulaw-table */
i = j = 0;
while(i < 32768) {
if (i-32768 > dsp_audio_law_to_s32[j])
j++;
dsp_audio_s16_to_law[(i-32768) & 0xffff] = j;
i++;
}
j = 255;
while(i < 65536) {
if (i-32768 > dsp_audio_law_to_s32[j])
j--;
dsp_audio_s16_to_law[(i-32768) & 0xffff] = j;
i++;
}
} else {
/* generating alaw-table */
i = j = 0;
while(i < 65536) {
if (i-32768 > dsp_audio_alaw_relations[j<<1])
j++;
if (j>255)
j=255;
dsp_audio_s16_to_law[(i-32768) & 0xffff]
= dsp_audio_alaw_relations[(j<<1)|1];
i++;
}
}
}
/*
* the seven bit sample is the number of every second alaw-sample ordered by
* aplitude. 0x00 is negative, 0x7f is positive amplitude.
*/
u8 dsp_audio_seven2law[128];
u8 dsp_audio_law2seven[256];
/********************************************************************
* generate table for conversion law from/to 7-bit alaw-like sample *
********************************************************************/
void
dsp_audio_generate_seven(void)
{
int i, j;
u8 spl;
/* conversion from law to seven bit audio */
i = 0;
while(i < 256) {
/* spl is the source: the law-sample (converted to alaw) */
spl = i;
if (dsp_options & DSP_OPT_ULAW)
spl = dsp_audio_ulaw_to_alaw[i];
/* find the 7-bit-sample */
j = 0;
while(j < 256) {
if (dsp_audio_alaw_relations[(j<<1)|1] == spl)
break;
j++;
}
if (j == 256) {
printk(KERN_WARNING "fatal error in %s: alaw-sample '0x%2x' not found in relations-table.\n", __FUNCTION__, spl);
}
/* write 7-bit audio value */
dsp_audio_law2seven[i] = j >> 1;
i++;
}
/* conversion from seven bit audio to law */
i = 0;
while(i < 128) {
/* find alaw-spl */
spl = dsp_audio_alaw_relations[(i<<2)|1];
/* convert to ulaw, if required */
if (dsp_options & DSP_OPT_ULAW)
spl = dsp_audio_alaw_to_ulaw[spl];
/* write 8-bit law sample */
dsp_audio_seven2law[i] = spl;
i++;
}
}
/* mix 2*law -> law */
u8 dsp_audio_mix_law[65536];
/******************************************************
* generate mix table to mix two law samples into one *
******************************************************/
void
dsp_audio_generate_mix_table(void)
{
int i, j;
s32 sample;
i = 0;
while(i < 256) {
j = 0;
while(j < 256) {
sample = dsp_audio_law_to_s32[i];
sample += dsp_audio_law_to_s32[j];
if (sample > 32767)
sample = 32767;
if (sample < -32768)
sample = -32768;
dsp_audio_mix_law[(i<<8)|j] = dsp_audio_s16_to_law[sample & 0xffff];
j++;
}
i++;
}
}
/*************************************
* generate different volume changes *
*************************************/
static u8 dsp_audio_reduce8[256];
static u8 dsp_audio_reduce7[256];
static u8 dsp_audio_reduce6[256];
static u8 dsp_audio_reduce5[256];
static u8 dsp_audio_reduce4[256];
static u8 dsp_audio_reduce3[256];
static u8 dsp_audio_reduce2[256];
static u8 dsp_audio_reduce1[256];
static u8 dsp_audio_increase1[256];
static u8 dsp_audio_increase2[256];
static u8 dsp_audio_increase3[256];
static u8 dsp_audio_increase4[256];
static u8 dsp_audio_increase5[256];
static u8 dsp_audio_increase6[256];
static u8 dsp_audio_increase7[256];
static u8 dsp_audio_increase8[256];
static u8 *dsp_audio_volume_change[16] = {
dsp_audio_reduce8,
dsp_audio_reduce7,
dsp_audio_reduce6,
dsp_audio_reduce5,
dsp_audio_reduce4,
dsp_audio_reduce3,
dsp_audio_reduce2,
dsp_audio_reduce1,
dsp_audio_increase1,
dsp_audio_increase2,
dsp_audio_increase3,
dsp_audio_increase4,
dsp_audio_increase5,
dsp_audio_increase6,
dsp_audio_increase7,
dsp_audio_increase8,
};
void
dsp_audio_generate_volume_changes(void)
{
register s32 sample;
int i;
i = 0;
while(i < 256) {
dsp_audio_reduce8[i] = dsp_audio_s16_to_law[(dsp_audio_law_to_s32[i]>>8) & 0xffff];
dsp_audio_reduce7[i] = dsp_audio_s16_to_law[(dsp_audio_law_to_s32[i]>>7) & 0xffff];
dsp_audio_reduce6[i] = dsp_audio_s16_to_law[(dsp_audio_law_to_s32[i]>>6) & 0xffff];
dsp_audio_reduce5[i] = dsp_audio_s16_to_law[(dsp_audio_law_to_s32[i]>>5) & 0xffff];
dsp_audio_reduce4[i] = dsp_audio_s16_to_law[(dsp_audio_law_to_s32[i]>>4) & 0xffff];
dsp_audio_reduce3[i] = dsp_audio_s16_to_law[(dsp_audio_law_to_s32[i]>>3) & 0xffff];
dsp_audio_reduce2[i] = dsp_audio_s16_to_law[(dsp_audio_law_to_s32[i]>>2) & 0xffff];
dsp_audio_reduce1[i] = dsp_audio_s16_to_law[(dsp_audio_law_to_s32[i]>>1) & 0xffff];
sample = dsp_audio_law_to_s32[i] << 1;
if (sample < -32768)
sample = -32768;
else if (sample > 32767)
sample = 32767;
dsp_audio_increase1[i] = dsp_audio_s16_to_law[sample & 0xffff];
sample = dsp_audio_law_to_s32[i] << 2;
if (sample < -32768)
sample = -32768;
else if (sample > 32767)
sample = 32767;
dsp_audio_increase2[i] = dsp_audio_s16_to_law[sample & 0xffff];
sample = dsp_audio_law_to_s32[i] << 3;
if (sample < -32768)
sample = -32768;
else if (sample > 32767)
sample = 32767;
dsp_audio_increase3[i] = dsp_audio_s16_to_law[sample & 0xffff];
sample = dsp_audio_law_to_s32[i] << 4;
if (sample < -32768)
sample = -32768;
else if (sample > 32767)
sample = 32767;
dsp_audio_increase4[i] = dsp_audio_s16_to_law[sample & 0xffff];
sample = dsp_audio_law_to_s32[i] << 5;
if (sample < -32768)
sample = -32768;
else if (sample > 32767)
sample = 32767;
dsp_audio_increase5[i] = dsp_audio_s16_to_law[sample & 0xffff];
sample = dsp_audio_law_to_s32[i] << 6;
if (sample < -32768)
sample = -32768;
else if (sample > 32767)
sample = 32767;
dsp_audio_increase6[i] = dsp_audio_s16_to_law[sample & 0xffff];
sample = dsp_audio_law_to_s32[i] << 7;
if (sample < -32768)
sample = -32768;
else if (sample > 32767)
sample = 32767;
dsp_audio_increase7[i] = dsp_audio_s16_to_law[sample & 0xffff];
sample = dsp_audio_law_to_s32[i] << 8;
if (sample < -32768)
sample = -32768;
else if (sample > 32767)
sample = 32767;
dsp_audio_increase8[i] = dsp_audio_s16_to_law[sample & 0xffff];
i++;
}
}
/**************************************
* change the volume of the given skb *
**************************************/
/* this is a helper function for changing volume of skb. the range may be
* -8 to 8, which is a shift to the power of 2. 0 == no volume, 3 == volume*8
*/
void
dsp_change_volume(struct sk_buff *skb, int volume)
{
u8 *volume_change;
int i, ii;
u8 *p;
int shift;
if (volume == 0)
return;
/* get correct conversion table */
if (volume < 0) {
shift = volume + 8;
if (shift < 0)
shift = 0;
} else {
shift = volume + 7;
if (shift > 15)
shift = 15;
}
volume_change = dsp_audio_volume_change[shift];
i = 0;
ii = skb->len;
p = skb->data;
/* change volume */
while(i < ii) {
*p = volume_change[*p];
p++;
i++;
}
}

View File

@ -0,0 +1,73 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* biquad.h - General telephony bi-quad section routines (currently this just
* handles canonic/type 2 form)
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2001 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
typedef struct
{
int32_t gain;
int32_t a1;
int32_t a2;
int32_t b1;
int32_t b2;
int32_t z1;
int32_t z2;
} biquad2_state_t;
static inline void biquad2_init (biquad2_state_t *bq,
int32_t gain,
int32_t a1,
int32_t a2,
int32_t b1,
int32_t b2)
{
bq->gain = gain;
bq->a1 = a1;
bq->a2 = a2;
bq->b1 = b1;
bq->b2 = b2;
bq->z1 = 0;
bq->z2 = 0;
}
/*- End of function --------------------------------------------------------*/
static inline int16_t biquad2 (biquad2_state_t *bq, int16_t sample)
{
int32_t y;
int32_t z0;
z0 = sample*bq->gain + bq->z1*bq->a1 + bq->z2*bq->a2;
y = z0 + bq->z1*bq->b1 + bq->z2*bq->b2;
bq->z2 = bq->z1;
bq->z1 = z0 >> 15;
y >>= 15;
return y;
}
/*- End of function --------------------------------------------------------*/
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,658 @@
/* $Id$
*
* Blowfish encryption/decryption for mISDN_dsp.
*
* Copyright Andreas Eversberg (jolly@eversberg.eu)
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#include "layer1.h"
#include "helper.h"
#include "debug.h"
#include "dsp.h"
/*
* how to encode a sample stream to 64-bit blocks that will be encryped
*
* first of all, data is collected until a block of 9 samples are received.
* of course, a packet may have much more than 9 sample, but is may have
* not excacly the multiple of 9 samples. if there is a rest, the next
* received data will complete the block.
*
* the block is then converted to 9 uLAW samples without the least sigificant
* bit. the result is a 7-bit encoded sample.
*
* the samples will be reoganised to form 8 bytes of data:
* (5(6) means: encoded sample no. 5, bit 6)
*
* 0(6) 0(5) 0(4) 0(3) 0(2) 0(1) 0(0) 1(6)
* 1(5) 1(4) 1(3) 1(2) 1(1) 1(0) 2(6) 2(5)
* 2(4) 2(3) 2(2) 2(1) 2(0) 3(6) 3(5) 3(4)
* 3(3) 3(2) 3(1) 3(0) 4(6) 4(5) 4(4) 4(3)
* 4(2) 4(1) 4(0) 5(6) 5(5) 5(4) 5(3) 5(2)
* 5(1) 5(0) 6(6) 6(5) 6(4) 6(3) 6(2) 6(1)
* 6(0) 7(6) 7(5) 7(4) 7(3) 7(2) 7(1) 7(0)
* 8(6) 8(5) 8(4) 8(3) 8(2) 8(1) 8(0)
*
* the missing bit 0 of the last byte is filled with some
* random noise, to fill all 8 bytes.
*
* the 8 bytes will be encrypted using blowfish.
*
* the result will be converted into 9 bytes. the bit 7 is used for
* checksumme (CS) for sync (0, 1) and for the last bit:
* (5(6) means: crypted byte 5, bit 6)
*
* 1 0(7) 0(6) 0(5) 0(4) 0(3) 0(2) 0(1)
* 0 0(0) 1(7) 1(6) 1(5) 1(4) 1(3) 1(2)
* 0 1(1) 1(0) 2(7) 2(6) 2(5) 2(4) 2(3)
* 0 2(2) 2(1) 2(0) 3(7) 3(6) 3(5) 3(4)
* 0 3(3) 3(2) 3(1) 3(0) 4(7) 4(6) 4(5)
* CS 4(4) 4(3) 4(2) 4(1) 4(0) 5(7) 5(6)
* CS 5(5) 5(4) 5(3) 5(2) 5(1) 5(0) 6(7)
* CS 6(6) 6(5) 6(4) 6(3) 6(2) 6(1) 6(0)
* 7(0) 7(6) 7(5) 7(4) 7(3) 7(2) 7(1) 7(0)
*
* the checksum is used to detect transmission errors and frame drops.
*
* synchronisation of received block is done by shifting the upper bit of each
* byte (bit 7) to a shift register. if the rigister has the first five bits
* (10000), this is used to find the sync. only if sync has been found, the
* current block of 9 received bytes are decrypted. before that the check
* sum is calculated. if it is incorrect the block is dropped.
* this will avoid loud noise due to corrupt encrypted data.
*
* if the last block is corrupt, the current decoded block is repeated
* until a valid block has been received.
*/
/* some blowfish parts are taken from the crypto-api for faster implementation
*/
struct bf_ctx {
u32 p[18];
u32 s[1024];
};
static const u32 bf_pbox[16 + 2] = {
0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344,
0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89,
0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917,
0x9216d5d9, 0x8979fb1b,
};
static const u32 bf_sbox[256 * 4] = {
0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7,
0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99,
0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e,
0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee,
0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef,
0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e,
0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440,
0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce,
0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e,
0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677,
0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032,
0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88,
0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e,
0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0,
0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98,
0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88,
0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6,
0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d,
0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7,
0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba,
0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f,
0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09,
0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb,
0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279,
0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab,
0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82,
0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573,
0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0,
0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790,
0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8,
0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0,
0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7,
0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad,
0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1,
0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9,
0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477,
0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49,
0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af,
0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5,
0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41,
0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400,
0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915,
0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a,
0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623,
0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266,
0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1,
0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e,
0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6,
0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e,
0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1,
0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737,
0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8,
0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff,
0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701,
0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7,
0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41,
0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331,
0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf,
0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e,
0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87,
0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c,
0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2,
0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16,
0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b,
0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509,
0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e,
0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3,
0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f,
0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4,
0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960,
0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66,
0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28,
0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802,
0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510,
0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf,
0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,
0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e,
0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50,
0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8,
0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281,
0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99,
0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696,
0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128,
0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0,
0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0,
0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105,
0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250,
0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3,
0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00,
0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061,
0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb,
0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e,
0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735,
0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9,
0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340,
0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20,
0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7,
0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934,
0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068,
0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af,
0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840,
0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45,
0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a,
0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb,
0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee,
0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6,
0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42,
0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2,
0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb,
0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527,
0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b,
0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33,
0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3,
0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc,
0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17,
0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564,
0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b,
0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922,
0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728,
0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0,
0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e,
0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37,
0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804,
0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b,
0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3,
0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb,
0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d,
0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350,
0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9,
0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,
0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe,
0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d,
0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f,
0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61,
0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2,
0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9,
0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2,
0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e,
0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633,
0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10,
0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169,
0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52,
0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5,
0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62,
0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634,
0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76,
0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24,
0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4,
0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c,
0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837,
0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0,
0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b,
0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe,
0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4,
0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8,
0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304,
0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22,
0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6,
0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9,
0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593,
0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51,
0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c,
0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b,
0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c,
0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd,
0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319,
0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb,
0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991,
0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32,
0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166,
0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae,
0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5,
0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47,
0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d,
0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84,
0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8,
0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd,
0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7,
0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38,
0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c,
0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525,
0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442,
0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964,
0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8,
0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d,
0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299,
0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02,
0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614,
0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a,
0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b,
0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0,
0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e,
0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9,
0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6,
};
/*
* Round loop unrolling macros, S is a pointer to a S-Box array
* organized in 4 unsigned longs at a row.
*/
#define GET32_3(x) (((x) & 0xff))
#define GET32_2(x) (((x) >> (8)) & (0xff))
#define GET32_1(x) (((x) >> (16)) & (0xff))
#define GET32_0(x) (((x) >> (24)) & (0xff))
#define bf_F(x) (((S[GET32_0(x)] + S[256 + GET32_1(x)]) ^ \
S[512 + GET32_2(x)]) + S[768 + GET32_3(x)])
#define EROUND(a, b, n) b ^= P[n]; a ^= bf_F (b)
#define DROUND(a, b, n) a ^= bf_F (b); b ^= P[n]
/*
* encrypt isdn data frame
* every block with 9 samples is encrypted
*/
void
dsp_bf_encrypt(dsp_t *dsp, u8 *data, int len)
{
int i = 0, j = dsp->bf_crypt_pos;
u8 *bf_data_in = dsp->bf_data_in;
u8 *bf_crypt_out = dsp->bf_crypt_out;
u32 *P = dsp->bf_p;
u32 *S = dsp->bf_s;
u32 yl, yr;
u32 cs;
u8 nibble;
while(i < len) {
/* collect a block of 9 samples */
if (j < 9) {
bf_data_in[j] = *data;
*data++ = bf_crypt_out[j++];
i++;
continue;
}
j = 0;
/* transcode 9 samples xlaw to 8 bytes */
yl = dsp_audio_law2seven[bf_data_in[0]];
yl = (yl<<7) | dsp_audio_law2seven[bf_data_in[1]];
yl = (yl<<7) | dsp_audio_law2seven[bf_data_in[2]];
yl = (yl<<7) | dsp_audio_law2seven[bf_data_in[3]];
yr = nibble = dsp_audio_law2seven[bf_data_in[4]];
yl = (yl<<4) | (nibble>>3);
yr = (yr<<7) | dsp_audio_law2seven[bf_data_in[5]];
yr = (yr<<7) | dsp_audio_law2seven[bf_data_in[6]];
yr = (yr<<7) | dsp_audio_law2seven[bf_data_in[7]];
yr = (yr<<7) | dsp_audio_law2seven[bf_data_in[8]];
yr = (yr<<1) | (bf_data_in[0] & 1); /* fill unused bit with random noise of audio input */
/* encrypt */
EROUND(yr, yl, 0);
EROUND(yl, yr, 1);
EROUND(yr, yl, 2);
EROUND(yl, yr, 3);
EROUND(yr, yl, 4);
EROUND(yl, yr, 5);
EROUND(yr, yl, 6);
EROUND(yl, yr, 7);
EROUND(yr, yl, 8);
EROUND(yl, yr, 9);
EROUND(yr, yl, 10);
EROUND(yl, yr, 11);
EROUND(yr, yl, 12);
EROUND(yl, yr, 13);
EROUND(yr, yl, 14);
EROUND(yl, yr, 15);
yl ^= P[16];
yr ^= P[17];
/* calculate 3-bit checksumme */
cs = yl ^ (yl>>3) ^ (yl>>6) ^ (yl>>9) ^ (yl>>12) ^ (yl>>15)
^ (yl>>18) ^ (yl>>21) ^ (yl>>24) ^ (yl>>27) ^ (yl>>30)
^ (yr<<2) ^ (yr>>1) ^ (yr>>4) ^ (yr>>7) ^ (yr>>10)
^ (yr>>13) ^ (yr>>16) ^ (yr>>19) ^ (yr>>22) ^ (yr>>25)
^ (yr>>28) ^ (yr>>31);
/* transcode 8 crypted bytes to 9 data bytes with sync
* and checksum information
*/
bf_crypt_out[0] = (yl>>25) | 0x80;
bf_crypt_out[1] = (yl>>18) & 0x7f;
bf_crypt_out[2] = (yl>>11) & 0x7f;
bf_crypt_out[3] = (yl>>4) & 0x7f;
bf_crypt_out[4] = ((yl<<3) & 0x78) | ((yr>>29) & 0x07);
bf_crypt_out[5] = ((yr>>22) & 0x7f) | ((cs<<5) & 0x80);
bf_crypt_out[6] = ((yr>>15) & 0x7f) | ((cs<<6) & 0x80);
bf_crypt_out[7] = ((yr>>8) & 0x7f) | (cs<<7);
bf_crypt_out[8] = yr;
}
/* write current count */
dsp->bf_crypt_pos = j;
}
/*
* decrypt isdn data frame
* every block with 9 bytes is decrypted
*/
void
dsp_bf_decrypt(dsp_t *dsp, u8 *data, int len)
{
int i = 0;
u8 j = dsp->bf_decrypt_in_pos;
u8 k = dsp->bf_decrypt_out_pos;
u8 *bf_crypt_inring = dsp->bf_crypt_inring;
u8 *bf_data_out = dsp->bf_data_out;
u16 sync = dsp->bf_sync;
u32 *P = dsp->bf_p;
u32 *S = dsp->bf_s;
u32 yl, yr;
u8 nibble;
u8 cs, cs0,cs1,cs2;
while(i < len) {
/* shift upper bit and rotate data to buffer ring
* send current decrypted data
*/
sync = (sync<<1) | ((*data)>>7);
bf_crypt_inring[j++ & 15] = *data;
*data++ = bf_data_out[k++];
i++;
if (k == 9)
k = 0; /* repeat if no sync has been found */
/* check if not in sync */
if ((sync&0x1f0) != 0x100)
continue;
j -= 9;
/* transcode receive data to 64 bit block of encrypted data */
yl = bf_crypt_inring[j++ & 15];
yl = (yl<<7) | bf_crypt_inring[j++ & 15]; /* bit7 = 0 */
yl = (yl<<7) | bf_crypt_inring[j++ & 15]; /* bit7 = 0 */
yl = (yl<<7) | bf_crypt_inring[j++ & 15]; /* bit7 = 0 */
yr = nibble = bf_crypt_inring[j++ & 15]; /* bit7 = 0 */
yl = (yl<<4) | (nibble>>3);
cs2 = bf_crypt_inring[j++ & 15];
yr = (yr<<7) | (cs2 & 0x7f);
cs1 = bf_crypt_inring[j++ & 15];
yr = (yr<<7) | (cs1 & 0x7f);
cs0 = bf_crypt_inring[j++ & 15];
yr = (yr<<7) | (cs0 & 0x7f);
yr = (yr<<8) | bf_crypt_inring[j++ & 15];
/* calculate 3-bit checksumme */
cs = yl ^ (yl>>3) ^ (yl>>6) ^ (yl>>9) ^ (yl>>12) ^ (yl>>15)
^ (yl>>18) ^ (yl>>21) ^ (yl>>24) ^ (yl>>27) ^ (yl>>30)
^ (yr<<2) ^ (yr>>1) ^ (yr>>4) ^ (yr>>7) ^ (yr>>10)
^ (yr>>13) ^ (yr>>16) ^ (yr>>19) ^ (yr>>22) ^ (yr>>25)
^ (yr>>28) ^ (yr>>31);
/* check if frame is valid */
if ((cs&0x7) != (((cs2>>5)&4) | ((cs1>>6)&2) | (cs0 >> 7)))
{
if (dsp_debug & DEBUG_DSP_BLOWFISH)
printk(KERN_DEBUG "DSP BLOWFISH: received corrupt frame, checksumme is not correct\n");
continue;
}
/* decrypt */
yr ^= P[17];
yl ^= P[16];
DROUND(yl, yr, 15);
DROUND(yr, yl, 14);
DROUND(yl, yr, 13);
DROUND(yr, yl, 12);
DROUND(yl, yr, 11);
DROUND(yr, yl, 10);
DROUND(yl, yr, 9);
DROUND(yr, yl, 8);
DROUND(yl, yr, 7);
DROUND(yr, yl, 6);
DROUND(yl, yr, 5);
DROUND(yr, yl, 4);
DROUND(yl, yr, 3);
DROUND(yr, yl, 2);
DROUND(yl, yr, 1);
DROUND(yr, yl, 0);
/* transcode 8 crypted bytes to 9 sample bytes */
bf_data_out[0] = dsp_audio_seven2law[(yl>>25) & 0x7f];
bf_data_out[1] = dsp_audio_seven2law[(yl>>18) & 0x7f];
bf_data_out[2] = dsp_audio_seven2law[(yl>>11) & 0x7f];
bf_data_out[3] = dsp_audio_seven2law[(yl>>4) & 0x7f];
bf_data_out[4] = dsp_audio_seven2law[((yl<<3) & 0x78) | ((yr>>29) & 0x07)];
bf_data_out[5] = dsp_audio_seven2law[(yr>>22) & 0x7f];
bf_data_out[6] = dsp_audio_seven2law[(yr>>15) & 0x7f];
bf_data_out[7] = dsp_audio_seven2law[(yr>>8) & 0x7f];
bf_data_out[8] = dsp_audio_seven2law[(yr>>1) & 0x7f];
k = 0; /* start with new decoded frame */
}
/* write current count and sync */
dsp->bf_decrypt_in_pos = j;
dsp->bf_decrypt_out_pos = k;
dsp->bf_sync = sync;
}
/* used to encrypt S and P boxes */
static inline void
encrypt_block(const u32 *P, const u32 *S, u32 *dst, u32 *src)
{
u32 yl = src[0];
u32 yr = src[1];
EROUND(yr, yl, 0);
EROUND(yl, yr, 1);
EROUND(yr, yl, 2);
EROUND(yl, yr, 3);
EROUND(yr, yl, 4);
EROUND(yl, yr, 5);
EROUND(yr, yl, 6);
EROUND(yl, yr, 7);
EROUND(yr, yl, 8);
EROUND(yl, yr, 9);
EROUND(yr, yl, 10);
EROUND(yl, yr, 11);
EROUND(yr, yl, 12);
EROUND(yl, yr, 13);
EROUND(yr, yl, 14);
EROUND(yl, yr, 15);
yl ^= P[16];
yr ^= P[17];
dst[0] = yr;
dst[1] = yl;
}
/*
* initialize the dsp for encryption and decryption using the same key
* Calculates the blowfish S and P boxes for encryption and decryption.
* The margin of keylen must be 4-56 bytes.
* returns 0 if ok.
*/
int
dsp_bf_init(dsp_t *dsp, const u8 *key, uint keylen)
{
short i, j, count;
u32 data[2], temp;
u32 *P = (u32 *)dsp->bf_p;
u32 *S = (u32 *)dsp->bf_s;
if (keylen<4 || keylen>56)
return(1);
/* Set dsp states */
i = 0;
while(i < 9)
{
dsp->bf_crypt_out[i] = 0xff;
dsp->bf_data_out[i] = dsp_silence;
i++;
}
dsp->bf_crypt_pos = 0;
dsp->bf_decrypt_in_pos = 0;
dsp->bf_decrypt_out_pos = 0;
dsp->bf_sync = 0x1ff;
dsp->bf_enable = 1;
/* Copy the initialization s-boxes */
for (i = 0, count = 0; i < 256; i++)
for (j = 0; j < 4; j++, count++)
S[count] = bf_sbox[count];
/* Set the p-boxes */
for (i = 0; i < 16 + 2; i++)
P[i] = bf_pbox[i];
/* Actual subkey generation */
for (j = 0, i = 0; i < 16 + 2; i++) {
temp = (((u32 )key[j] << 24) |
((u32 )key[(j + 1) % keylen] << 16) |
((u32 )key[(j + 2) % keylen] << 8) |
((u32 )key[(j + 3) % keylen]));
P[i] = P[i] ^ temp;
j = (j + 4) % keylen;
}
data[0] = 0x00000000;
data[1] = 0x00000000;
for (i = 0; i < 16 + 2; i += 2) {
encrypt_block(P, S, data, data);
P[i] = data[0];
P[i + 1] = data[1];
}
for (i = 0; i < 4; i++) {
for (j = 0, count = i * 256; j < 256; j += 2, count += 2) {
encrypt_block(P, S, data, data);
S[count] = data[0];
S[count + 1] = data[1];
}
}
return(0);
}
/* turn encryption off
*/
void
dsp_bf_cleanup(dsp_t *dsp)
{
dsp->bf_enable = 0;
}

View File

@ -0,0 +1,350 @@
/*
*
* Simple but fast Echo cancellation for mISDN_dsp.
*
* Copyright Chrisian Richter
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#include "layer1.h"
#include "helper.h"
#include "debug.h"
#include "dsp.h"
#ifdef ARCH_I386
#include <asm/i387.h>
#else
#define kernel_fpu_begin()
#define kernel_fpu_end()
#endif
/*
* how this works:
*
*
*
*/
/*
* send HW message to hfc card
*/
static void
dsp_cancel_hw_message(dsp_t *dsp, u32 message, u32 param)
{
struct sk_buff *nskb;
nskb = create_link_skb(PH_CONTROL | REQUEST, message, sizeof(param), &param, 0);
if (!nskb) {
printk(KERN_ERR "%s: No mem for skb.\n", __FUNCTION__);
return;
}
/* unlocking is not required, because we don't expect a response */
if (mISDN_queue_down(&dsp->inst, 0, nskb))
dev_kfree_skb(nskb);
}
void bchdev_echocancel_chunk(dsp_t* dev, uint8_t *rxchunk, uint8_t *txchunk, uint16_t size);
int bchdev_echocancel_activate(dsp_t* dev, int deftaps, int train);
void bchdev_echocancel_deactivate(dsp_t* dev);
void
dsp_cancel_tx(dsp_t *dsp, u8 *data, int len)
{
if (!dsp ) return ;
if (!data) return;
if (dsp->txbuflen + len < ECHOCAN_BUFLEN) {
memcpy(&dsp->txbuf[dsp->txbuflen],data,len);
dsp->txbuflen+=len;
} else {
static int i=0;
if(i==4000) {
printk("ECHOCAN: i:%d TXBUF Overflow txbuflen:%d txcancellen:%d\n", i, dsp->txbuflen,len);
i=0;
}
i+=len;
dsp->txbuflen=0;
}
}
void
dsp_cancel_rx(dsp_t *dsp, u8 *data, int len)
{
if (!dsp ) return ;
if (!data) return;
if (len <= dsp->txbuflen) {
char tmp[ECHOCAN_BUFLEN];
int delta=dsp->txbuflen-len;
memcpy(tmp,&dsp->txbuf[len],delta);
kernel_fpu_begin();
bchdev_echocancel_chunk(dsp, data, dsp->txbuf, len);
kernel_fpu_end();
memcpy(dsp->txbuf,tmp,delta);
dsp->txbuflen=delta;
} else {
static int i=0;
if(i==4000) {
printk("ECHOCAN: i:%d TXBUF Underrun txbuflen:%d rxcancellen:%d\n",i,dsp->txbuflen,len);
i=0;
}
i+=len;
}
}
int
dsp_cancel_init(dsp_t *dsp, int deftaps, int training, int delay)
{
if (!dsp) return -1;
if (dsp->feature_state != FEAT_STATE_RECEIVED) {
dsp->queue_cancel[0]=deftaps;
dsp->queue_cancel[1]=training;
dsp->queue_cancel[2]=delay;
return 0;
}
//printk("DSP_CANCEL_INIT called\n");
if (delay < 0)
{
//printk(KERN_NOTICE "Disabling EC\n");
dsp->cancel_enable = 0;
dsp->txbuflen=0;
if (dsp->features.hfc_echocanhw) {
//printk(KERN_NOTICE "Disabling Hardware EC\n");
dsp_cancel_hw_message(dsp, HW_ECHOCAN_OFF, deftaps);
} else {
bchdev_echocancel_deactivate(dsp);
}
return(0);
}
if (dsp->features.hfc_echocanhw) {
//printk(KERN_NOTICE "Using Hardware EC taps [%d]\n",deftaps);
dsp_cancel_hw_message(dsp, HW_ECHOCAN_ON, deftaps);
return 0;
}
dsp->txbuflen=0;
dsp->rxbuflen=0;
bchdev_echocancel_activate(dsp,deftaps, training);
//printk("Enabling EC\n");
dsp->cancel_enable = 1;
return(0);
}
/*****************************************************/
#define __ECHO_STATE_MUTE (1 << 8)
#define ECHO_STATE_IDLE (0)
#define ECHO_STATE_PRETRAINING (1 | (__ECHO_STATE_MUTE))
#define ECHO_STATE_STARTTRAINING (2 | (__ECHO_STATE_MUTE))
#define ECHO_STATE_AWAITINGECHO (3 | (__ECHO_STATE_MUTE))
#define ECHO_STATE_TRAINING (4 | (__ECHO_STATE_MUTE))
#define ECHO_STATE_ACTIVE (5)
#define AMI_MASK 0x55
/** @return string of given echo cancellation state */
char* bchdev_echocancel_statestr(uint16_t state)
{
switch(state) {
case ECHO_STATE_IDLE:
return "idle";
break;
case ECHO_STATE_PRETRAINING:
return "pre-training";
break;
case ECHO_STATE_STARTTRAINING:
return "transmit impulse";
break;
case ECHO_STATE_AWAITINGECHO:
return "awaiting echo";
break;
case ECHO_STATE_TRAINING:
return "training start";
break;
case ECHO_STATE_ACTIVE:
return "training finished";
break;
default:
return "unknown";
}
}
/** Changes state of echo cancellation to given state */
void bchdev_echocancel_setstate(dsp_t* dev, uint16_t state)
{
#if 0
char* statestr = bchdev_echocancel_statestr(state);
printk("bchdev: echo cancel state %d (%s)\n", state & 0xff, statestr);
if (state == ECHO_STATE_ACTIVE)
printk("bchdev: %d taps trained\n", dev->echolastupdate);
#endif
dev->echostate = state;
}
static int buf_size=0;
static int ec_timer=2000;
//static int ec_timer=1000;
/** Activates echo cancellation for the given bch_dev, device must have been locked before! */
int bchdev_echocancel_activate(dsp_t* dev, int deftaps, int training)
{
int taps;
if (! dev) return -EINVAL;
if (dev->ec && dev->ecdis_rd && dev->ecdis_wr) {
// already active
return 0;
}
if (deftaps>0) {
taps=deftaps;
} else {
taps=128;
}
switch (buf_size) {
case 0: taps += 0; break;
case 1: taps += 256-128; break;
case 2: taps += 512-128; break;
default: taps += 1024-128;
}
if (!dev->ec) dev->ec = echo_can_create(taps, 0);
if (!dev->ec) {
return -ENOMEM;
}
dev->echolastupdate = 0;
if (!training) {
dev->echotimer=0;
bchdev_echocancel_setstate(dev, ECHO_STATE_IDLE);
} else {
if (training<10)
training= ec_timer;
dev->echotimer = training;
bchdev_echocancel_setstate(dev, ECHO_STATE_PRETRAINING);
}
if (!dev->ecdis_rd) dev->ecdis_rd = kmalloc(sizeof(echo_can_disable_detector_state_t), GFP_ATOMIC);
if (!dev->ecdis_rd) {
kfree(dev->ec); dev->ec = NULL;
return -ENOMEM;
}
echo_can_disable_detector_init(dev->ecdis_rd);
if (!dev->ecdis_wr) dev->ecdis_wr = kmalloc(sizeof(echo_can_disable_detector_state_t), GFP_ATOMIC);
if (!dev->ecdis_wr) {
kfree(dev->ec); dev->ec = NULL;
kfree(dev->ecdis_rd); dev->ecdis_rd = NULL;
return -ENOMEM;
}
echo_can_disable_detector_init(dev->ecdis_wr);
return 0;
}
/** Deactivates echo cancellation for the given bch_dev, device must have been locked before! */
void bchdev_echocancel_deactivate(dsp_t* dev)
{
if (! dev) return;
//chan_misdn_log("bchdev: deactivating echo cancellation on port=%04x, chan=%02x\n", dev->stack->port, dev->channel);
if (dev->ec) echo_can_free(dev->ec);
dev->ec = NULL;
dev->echolastupdate = 0;
dev->echotimer = 0;
bchdev_echocancel_setstate(dev, ECHO_STATE_IDLE);
if (dev->ecdis_rd) kfree(dev->ecdis_rd);
dev->ecdis_rd = NULL;
if (dev->ecdis_wr) kfree(dev->ecdis_wr);
dev->ecdis_wr = NULL;
}
/** Processes one TX- and one RX-packet with echocancellation */
void bchdev_echocancel_chunk(dsp_t* ss, uint8_t *rxchunk, uint8_t *txchunk, uint16_t size)
{
int16_t rxlin, txlin;
uint16_t x;
/* Perform echo cancellation on a chunk if requested */
if (ss->ec) {
if (ss->echostate & __ECHO_STATE_MUTE) {
/* Special stuff for training the echo can */
for (x=0;x<size;x++) {
rxlin = dsp_audio_law_to_s32[rxchunk[x]];
txlin = dsp_audio_law_to_s32[txchunk[x]];
if (ss->echostate == ECHO_STATE_PRETRAINING) {
if (--ss->echotimer <= 0) {
ss->echotimer = 0;
ss->echostate = ECHO_STATE_STARTTRAINING;
}
}
if ((ss->echostate == ECHO_STATE_AWAITINGECHO) && (txlin > 8000)) {
ss->echolastupdate = 0;
ss->echostate = ECHO_STATE_TRAINING;
}
if (ss->echostate == ECHO_STATE_TRAINING) {
if (echo_can_traintap(ss->ec, ss->echolastupdate++, rxlin)) {
#if 0
printk("Finished training (%d taps trained)!\n", ss->echolastupdate);
#endif
ss->echostate = ECHO_STATE_ACTIVE;
}
}
rxlin = 0;
rxchunk[x] = dsp_audio_s16_to_law[(int)rxlin];
}
} else {
for (x=0;x<size;x++) {
rxlin = dsp_audio_law_to_s32[rxchunk[x]&0xff];
txlin = dsp_audio_law_to_s32[txchunk[x]&0xff];
rxlin = echo_can_update(ss->ec, txlin, rxlin);
rxchunk[x] = dsp_audio_s16_to_law[rxlin &0xffff];
}
}
}
}
/******************************************************/

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,249 @@
/* $Id$
*
* DTMF decoder.
*
* Copyright by Andreas Eversberg (jolly@eversberg.eu)
* based on different decoders such as ISDN4Linux
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#include "layer1.h"
#include "helper.h"
#include "debug.h"
#include "dsp.h"
#define NCOEFF 8 /* number of frequencies to be analyzed */
/* For DTMF recognition:
* 2 * cos(2 * PI * k / N) precalculated for all k
*/
static u64 cos2pik[NCOEFF] =
{
/* k << 15 (source: hfc-4s/8s documentation (www.colognechip.de)) */
55960, 53912, 51402, 48438, 38146, 32650, 26170, 18630
};
/* digit matrix */
static char dtmf_matrix[4][4] =
{
{'1', '2', '3', 'A'},
{'4', '5', '6', 'B'},
{'7', '8', '9', 'C'},
{'*', '0', '#', 'D'}
};
/* dtmf detection using goertzel algorithm
* init function
*/
void dsp_dtmf_goertzel_init(dsp_t *dsp)
{
dsp->dtmf.size = 0;
dsp->dtmf.lastwhat = '\0';
dsp->dtmf.lastdigit = '\0';
dsp->dtmf.count = 0;
}
/*************************************************************
* calculate the coefficients of the given sample and decode *
*************************************************************/
/* the given sample is decoded. if the sample is not long enough for a
* complete frame, the decoding is finished and continued with the next
* call of this function.
*
* the algorithm is very good for detection with a minimum of errors. i
* tested it allot. it even works with very short tones (40ms). the only
* disadvantage is, that it doesn't work good with different volumes of both
* tones. this will happen, if accoustically coupled dialers are used.
* it sometimes detects tones during speach, which is normal for decoders.
* use sequences to given commands during calls.
*
* dtmf - points to a structure of the current dtmf state
* spl and len - the sample
* fmt - 0 = alaw, 1 = ulaw, 2 = coefficients from HFC DTMF hw-decoder
*/
u8
*dsp_dtmf_goertzel_decode(dsp_t *dsp, u8 *data, int len, int fmt)
{
u8 what;
int size;
signed short *buf;
s32 sk, sk1, sk2;
int k, n, i;
s32 *hfccoeff;
s32 result[NCOEFF], tresh, treshl;
int lowgroup, highgroup;
s64 cos2pik_;
dsp->dtmf.digits[0] = '\0';
/* note: the function will loop until the buffer are not enough samples
* left to decode a full frame
*/
again:
/* convert samples */
size = dsp->dtmf.size;
buf = dsp->dtmf.buffer;
switch(fmt) {
case 0: /* alaw */
case 1: /* ulaw */
while(size<DSP_DTMF_NPOINTS && len) {
buf[size++] = dsp_audio_law_to_s32[*data++];
len--;
}
break;
case 2: /* HFC coefficients */
default:
if (len < 64) {
if (len > 0)
printk(KERN_ERR "%s: coefficients have invalid size. (is=%d < must=%d)\n",
__FUNCTION__, len, 64);
return(dsp->dtmf.digits);
}
hfccoeff = (s32 *)data;
for (k = 0; k < NCOEFF; k++) {
sk2 = (*hfccoeff++)>>4;
sk = (*hfccoeff++)>>4;
if (sk>32767 || sk<-32767 || sk2>32767 || sk2<-32767)
printk(KERN_WARNING "DTMF-Detection overflow\n");
/* compute |X(k)|**2 */
result[k] =
(sk * sk) -
(((cos2pik[k] * sk) >> 15) * sk2) +
(sk2 * sk2);
}
data += 64;
len -= 64;
goto coefficients;
break;
}
dsp->dtmf.size = size;
if (size < DSP_DTMF_NPOINTS)
return(dsp->dtmf.digits);
dsp->dtmf.size = 0;
/* now we have a full buffer of signed long samples - we do goertzel */
for (k = 0; k < NCOEFF; k++) {
sk = sk1 = sk2 = 0;
buf = dsp->dtmf.buffer;
cos2pik_ = cos2pik[k];
for (n = 0; n < DSP_DTMF_NPOINTS; n++) {
sk = ((cos2pik_*sk1)>>15) - sk2 + (*buf++);
sk2 = sk1;
sk1 = sk;
}
sk>>=8;
sk2>>=8;
if (sk>32767 || sk<-32767 || sk2>32767 || sk2<-32767)
printk(KERN_WARNING "DTMF-Detection overflow\n");
/* compute |X(k)|**2 */
result[k] =
(sk * sk) -
(((cos2pik[k] * sk) >> 15) * sk2) +
(sk2 * sk2);
}
/* our (squared) coefficients have been calculated, we need to process
* them.
*/
coefficients:
tresh = 0;
for (i = 0; i < NCOEFF; i++) {
if (result[i] < 0)
result[i] = 0;
if (result[i] > dsp->dtmf.treshold) {
if (result[i] > tresh)
tresh = result[i];
}
}
if (tresh == 0) {
what = 0;
goto storedigit;
}
if (dsp_debug & DEBUG_DSP_DTMFCOEFF)
printk(KERN_DEBUG "a %3d %3d %3d %3d %3d %3d %3d %3d"
" tr:%3d r %3d %3d %3d %3d %3d %3d %3d %3d\n",
result[0]/10000, result[1]/10000, result[2]/10000,
result[3]/10000, result[4]/10000, result[5]/10000,
result[6]/10000, result[7]/10000, tresh/10000,
result[0]/(tresh/100), result[1]/(tresh/100),
result[2]/(tresh/100), result[3]/(tresh/100),
result[4]/(tresh/100), result[5]/(tresh/100),
result[6]/(tresh/100), result[7]/(tresh/100));
/* calc digit (lowgroup/highgroup) */
lowgroup = highgroup = -1;
treshl = tresh >> 3; /* tones which are not on, must be below 9 dB */
tresh = tresh >> 2; /* touchtones must match within 6 dB */
for (i = 0; i < NCOEFF; i++) {
if (result[i] < treshl)
continue; /* ignore */
if (result[i] < tresh) {
lowgroup = highgroup = -1;
break; /* noise inbetween */
}
/* good level found. This is allowed only one time per group */
if (i < NCOEFF/2) {
/* lowgroup*/
if (lowgroup >= 0) {
// Bad. Another tone found. */
lowgroup = -1;
break;
} else
lowgroup = i;
} else {
/* higroup */
if (highgroup >= 0) {
// Bad. Another tone found. */
highgroup = -1;
break;
} else
highgroup = i-(NCOEFF/2);
}
}
/* get digit or null */
what = 0;
if (lowgroup>=0 && highgroup>=0)
what = dtmf_matrix[lowgroup][highgroup];
storedigit:
if (what && (dsp_debug & DEBUG_DSP_DTMF))
printk(KERN_DEBUG "DTMF what: %c\n", what);
if (dsp->dtmf.lastwhat!=what)
dsp->dtmf.count = 0;
/* the tone (or no tone) must remain 3 times without change */
if (dsp->dtmf.count == 2) {
if (dsp->dtmf.lastdigit!=what) {
dsp->dtmf.lastdigit = what;
if (what) {
if (dsp_debug & DEBUG_DSP_DTMF)
printk(KERN_DEBUG "DTMF digit: %c\n",
what);
if ((strlen(dsp->dtmf.digits)+1) <sizeof(dsp->dtmf.digits)) {
dsp->dtmf.digits[strlen(dsp->dtmf.digits)+1] = '\0';
dsp->dtmf.digits[strlen(dsp->dtmf.digits)] = what;
}
}
}
} else
dsp->dtmf.count++;
dsp->dtmf.lastwhat = what;
goto again;
}

View File

@ -0,0 +1,118 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* ec_disable_detector.h - A detector which should eventually meet the
* G.164/G.165 requirements for detecting the
* 2100Hz echo cancellor disable tone.
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2001 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include "dsp_biquad.h"
typedef struct
{
biquad2_state_t notch;
int notch_level;
int channel_level;
int tone_present;
int tone_cycle_duration;
int good_cycles;
int hit;
} echo_can_disable_detector_state_t;
#define FALSE 0
#define TRUE (!FALSE)
static inline void echo_can_disable_detector_init (echo_can_disable_detector_state_t *det)
{
/* Elliptic notch */
/* This is actually centred at 2095Hz, but gets the balance we want, due
to the asymmetric walls of the notch */
biquad2_init (&det->notch,
(int32_t) (-0.7600000*32768.0),
(int32_t) (-0.1183852*32768.0),
(int32_t) (-0.5104039*32768.0),
(int32_t) ( 0.1567596*32768.0),
(int32_t) ( 1.0000000*32768.0));
det->channel_level = 0;
det->notch_level = 0;
det->tone_present = FALSE;
det->tone_cycle_duration = 0;
det->good_cycles = 0;
det->hit = 0;
}
/*- End of function --------------------------------------------------------*/
static inline int echo_can_disable_detector_update (echo_can_disable_detector_state_t *det,
int16_t amp)
{
int16_t notched;
notched = biquad2 (&det->notch, amp);
/* Estimate the overall energy in the channel, and the energy in
the notch (i.e. overall channel energy - tone energy => noise).
Use abs instead of multiply for speed (is it really faster?).
Damp the overall energy a little more for a stable result.
Damp the notch energy a little less, so we don't damp out the
blip every time the phase reverses */
det->channel_level += ((abs(amp) - det->channel_level) >> 5);
det->notch_level += ((abs(notched) - det->notch_level) >> 4);
if (det->channel_level > 280)
{
/* There is adequate energy in the channel. Is it mostly at 2100Hz? */
if (det->notch_level*6 < det->channel_level)
{
/* The notch says yes, so we have the tone. */
if (!det->tone_present)
{
/* Do we get a kick every 450+-25ms? */
if (det->tone_cycle_duration >= 425*8
&&
det->tone_cycle_duration <= 475*8)
{
det->good_cycles++;
if (det->good_cycles > 2)
det->hit = TRUE;
}
det->tone_cycle_duration = 0;
}
det->tone_present = TRUE;
}
else
{
det->tone_present = FALSE;
}
det->tone_cycle_duration++;
}
else
{
det->tone_present = FALSE;
det->tone_cycle_duration = 0;
det->good_cycles = 0;
}
return det->hit;
}
/*- End of function --------------------------------------------------------*/
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,574 @@
/*
* ECHO_CAN_KB1
*
* by Kris Boutilier
*
* Based upon mech2.h
*
* Copyright (C) 2002, Digium, Inc.
*
* This program is free software and may be used and
* distributed according to the terms of the GNU
* General Public License, incorporated herein by
* reference.
*
* Additional background on the techniques used in this code can be found in:
*
* Messerschmitt, David; Hedberg, David; Cole, Christopher; Haoui, Amine;
* Winship, Peter; "Digital Voice Echo Canceller with a TMS32020,"
* in Digital Signal Processing Applications with the TMS320 Family,
* pp. 415-437, Texas Instruments, Inc., 1986.
*
* A pdf of which is available by searching on the document title at http://www.ti.com/
*
*/
#ifndef _MARK2_ECHO_H
#define _MARK2_ECHO_H
#define EC_TYPE "KB1"
#ifdef __KERNEL__
#include <linux/kernel.h>
#include <linux/slab.h>
#define MALLOC(a) kmalloc((a), GFP_ATOMIC)
#define FREE(a) kfree(a)
#else
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>
#include <string.h>
#include <math.h>
#define MALLOC(a) malloc(a)
#define FREE(a) free(a)
#endif
/* Uncomment to provide summary statistics for overall echo can performance every 4000 samples */
/* #define MEC2_STATS 4000 */
/* Uncomment to generate per-sample statistics - this will severely degrade system performance and audio quality */
/* #define MEC2_STATS_DETAILED */
/* Get optimized routines for math */
#include "dsp_arith.h"
/* Bring in definitions for the various constants and thresholds */
#include "dsp_kb1ec_const.h"
#ifndef NULL
#define NULL 0
#endif
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE (!FALSE)
#endif
/* Generic circular buffer definition */
typedef struct {
/* Pointer to the relative 'start' of the buffer */
int idx_d;
/* The absolute size of the buffer */
int size_d;
/* The actual sample - twice as large as we need, however we do store values at idx_d and idx_d+size_d */
short *buf_d;
} echo_can_cb_s;
/* Echo canceller definition */
struct echo_can_state {
/* an arbitrary ID for this echo can - this really should be settable from the calling channel... */
int id;
/* absolute time - aka. sample number index - essentially the number of samples since this can was init'ed */
int i_d;
/* Pre-computed constants */
/* ---------------------- */
/* Number of filter coefficents */
int N_d;
/* Rate of adaptation of filter */
int beta2_i;
/* Accumulators for power computations */
/* ----------------------------------- */
/* reference signal power estimate - aka. Average absolute value of y(k) */
int Ly_i;
/* ... */
int Lu_i;
/* Accumulators for signal detectors */
/* --------------------------------- */
/* Power estimate of the recent past of the near-end hybrid signal - aka. Short-time average of: 2 x |s(i)| */
int s_tilde_i;
/* Power estimate of the recent past of the far-end receive signal - aka. Short-time average of: |y(i)| */
int y_tilde_i;
/* Near end speech detection counter - stores Hangover counter time remaining, in samples */
int HCNTR_d;
/* Circular buffers and coefficients */
/* --------------------------------- */
/* ... */
int *a_i;
/* ... */
short *a_s;
/* Reference samples of far-end receive signal */
echo_can_cb_s y_s;
/* Reference samples of near-end signal */
echo_can_cb_s s_s;
/* Reference samples of near-end signal minus echo estimate */
echo_can_cb_s u_s;
/* Reference samples of far-end receive signal used to calculate short-time average */
echo_can_cb_s y_tilde_s;
/* Peak far-end receive signal */
/* --------------------------- */
/* Highest y_tilde value in the sample buffer */
short max_y_tilde;
/* Index of the sample containing the max_y_tilde value */
int max_y_tilde_pos;
#ifdef MEC2_STATS
/* Storage for performance statistics */
int cntr_nearend_speech_frames;
int cntr_residualcorrected_frames;
int cntr_residualcorrected_framesskipped;
int cntr_coeff_updates;
int cntr_coeff_missedupdates;
int avg_Lu_i_toolow;
int avg_Lu_i_ok;
#endif
};
static inline void init_cb_s(echo_can_cb_s *cb, int len, void *where)
{
cb->buf_d = (short *)where;
cb->idx_d = 0;
cb->size_d = len;
}
static inline void add_cc_s(echo_can_cb_s *cb, short newval)
{
/* Can't use modulus because N+M isn't a power of two (generally) */
cb->idx_d--;
if (cb->idx_d < (int)0)
/* Whoops - the pointer to the 'start' wrapped around so reset it to the top of the buffer */
cb->idx_d += cb->size_d;
/* Load two copies into memory */
cb->buf_d[cb->idx_d] = newval;
cb->buf_d[cb->idx_d + cb->size_d] = newval;
}
static inline short get_cc_s(echo_can_cb_s *cb, int pos)
{
/* Load two copies into memory */
return cb->buf_d[cb->idx_d + pos];
}
static inline void init_cc(struct echo_can_state *ec, int N, int maxy, int maxu)
{
void *ptr = ec;
unsigned long tmp;
/* Double-word align past end of state */
ptr += sizeof(struct echo_can_state);
tmp = (unsigned long)ptr;
tmp += 3;
tmp &= ~3L;
ptr = (void *)tmp;
/* Reset parameters */
ec->N_d = N;
ec->beta2_i = DEFAULT_BETA1_I;
/* Allocate coefficient memory */
ec->a_i = ptr;
ptr += (sizeof(int) * ec->N_d);
ec->a_s = ptr;
ptr += (sizeof(short) * ec->N_d);
/* Reset Y circular buffer (short version) */
init_cb_s(&ec->y_s, maxy, ptr);
ptr += (sizeof(short) * (maxy) * 2);
/* Reset Sigma circular buffer (short version for FIR filter) */
init_cb_s(&ec->s_s, (1 << DEFAULT_ALPHA_ST_I), ptr);
ptr += (sizeof(short) * (1 << DEFAULT_ALPHA_ST_I) * 2);
init_cb_s(&ec->u_s, maxu, ptr);
ptr += (sizeof(short) * maxu * 2);
/* Allocate a buffer for the reference signal power computation */
init_cb_s(&ec->y_tilde_s, ec->N_d, ptr);
/* Reset the absolute time index */
ec->i_d = (int)0;
/* Reset the power computations (for y and u) */
ec->Ly_i = DEFAULT_CUTOFF_I;
ec->Lu_i = DEFAULT_CUTOFF_I;
#ifdef MEC2_STATS
/* set the identity */
ec->id = (int)&ptr;
/* Reset performance stats */
ec->cntr_nearend_speech_frames = (int)0;
ec->cntr_residualcorrected_frames = (int)0;
ec->cntr_residualcorrected_framesskipped = (int)0;
ec->cntr_coeff_updates = (int)0;
ec->cntr_coeff_missedupdates = (int)0;
ec->avg_Lu_i_toolow = (int)0;
ec->avg_Lu_i_ok = (int)0;
#endif
/* Reset the near-end speech detector */
ec->s_tilde_i = (int)0;
ec->y_tilde_i = (int)0;
ec->HCNTR_d = (int)0;
}
static inline void echo_can_free(struct echo_can_state *ec)
{
FREE(ec);
}
static inline short echo_can_update(struct echo_can_state *ec, short iref, short isig)
{
/* Declare local variables that are used more than once */
/* ... */
int k;
/* ... */
int rs;
/* ... */
short u;
/* ... */
int Py_i;
/* ... */
int two_beta_i;
/* flow A on pg. 428 */
/* eq. (16): high-pass filter the input to generate the next value;
* push the current value into the circular buffer
*
* sdc_im1_d = sdc_d;
* sdc_d = sig;
* s_i_d = sdc_d;
* s_d = s_i_d;
* s_i_d = (float)(1.0 - gamma_d) * s_i_d
* + (float)(0.5 * (1.0 - gamma_d)) * (sdc_d - sdc_im1_d);
*/
/* Update the Far-end receive signal circular buffers and accumulators */
/* ------------------------------------------------------------------- */
/* Delete the oldest sample from the power estimate accumulator */
ec->y_tilde_i -= abs(get_cc_s(&ec->y_s, (1 << DEFAULT_ALPHA_YT_I) - 1 )) >> DEFAULT_ALPHA_YT_I;
/* Add the new sample to the power estimate accumulator */
ec->y_tilde_i += abs(iref) >> DEFAULT_ALPHA_ST_I;
/* Push a copy of the new sample into its circular buffer */
add_cc_s(&ec->y_s, iref);
/* eq. (2): compute r in fixed-point */
rs = CONVOLVE2(ec->a_s,
ec->y_s.buf_d + ec->y_s.idx_d,
ec->N_d);
rs >>= 15;
/* eq. (3): compute the output value (see figure 3) and the error
* note: the error is the same as the output signal when near-end
* speech is not present
*/
u = isig - rs;
/* Push a copy of the output value sample into its circular buffer */
add_cc_s(&ec->u_s, u);
/* Update the Near-end hybrid signal circular buffers and accumulators */
/* ------------------------------------------------------------------- */
/* Delete the oldest sample from the power estimate accumulator */
ec->s_tilde_i -= abs(get_cc_s(&ec->s_s, (1 << DEFAULT_ALPHA_ST_I) - 1 ));
/* Add the new sample to the power estimate accumulator */
ec->s_tilde_i += abs(isig);
/* Push a copy of the new sample into it's circular buffer */
add_cc_s(&ec->s_s, isig);
/* Push a copy of the current short-time average of the far-end receive signal into it's circular buffer */
add_cc_s(&ec->y_tilde_s, ec->y_tilde_i);
/* flow B on pg. 428 */
/* If the hangover timer isn't running then compute the new convergence factor, otherwise set Py_i to 32768 */
if (!ec->HCNTR_d) {
Py_i = (ec->Ly_i >> DEFAULT_SIGMA_LY_I) * (ec->Ly_i >> DEFAULT_SIGMA_LY_I);
Py_i >>= 15;
} else {
Py_i = (1 << 15);
}
#if 0
/* Vary rate of adaptation depending on position in the file
* Do not do this for the first (DEFAULT_UPDATE_TIME) secs after speech
* has begun of the file to allow the echo cancellor to estimate the
* channel accurately
* Still needs conversion!
*/
if (ec->start_speech_d != 0 ){
if ( ec->i_d > (DEFAULT_T0 + ec->start_speech_d)*(SAMPLE_FREQ) ){
ec->beta2_d = max_cc_float(MIN_BETA, DEFAULT_BETA1 * exp((-1/DEFAULT_TAU)*((ec->i_d/(float)SAMPLE_FREQ) - DEFAULT_T0 - ec->start_speech_d)));
}
} else {
ec->beta2_d = DEFAULT_BETA1;
}
#endif
/* Fixed point, inverted */
ec->beta2_i = DEFAULT_BETA1_I;
/* Fixed point version, inverted */
two_beta_i = (ec->beta2_i * Py_i) >> 15;
if (!two_beta_i)
two_beta_i++;
/* Update the Suppressed signal power estimate accumulator */
/* ------------------------------------------------------- */
/* Delete the oldest sample from the power estimate accumulator */
ec->Lu_i -= abs(get_cc_s(&ec->u_s, (1 << DEFAULT_SIGMA_LU_I) - 1 )) ;
/* Add the new sample to the power estimate accumulator */
ec->Lu_i += abs(u);
/* Update the Far-end reference signal power estimate accumulator */
/* -------------------------------------------------------------- */
/* eq. (10): update power estimate of the reference */
/* Delete the oldest sample from the power estimate accumulator */
ec->Ly_i -= abs(get_cc_s(&ec->y_s, (1 << DEFAULT_SIGMA_LY_I) - 1)) ;
/* Add the new sample to the power estimate accumulator */
ec->Ly_i += abs(iref);
if (ec->Ly_i < DEFAULT_CUTOFF_I)
ec->Ly_i = DEFAULT_CUTOFF_I;
/* Update the Peak far-end receive signal detected */
/* ----------------------------------------------- */
if (ec->y_tilde_i > ec->max_y_tilde) {
/* New highest y_tilde with full life */
ec->max_y_tilde = ec->y_tilde_i;
ec->max_y_tilde_pos = ec->N_d - 1;
} else if (--ec->max_y_tilde_pos < 0) {
/* Time to find new max y tilde... */
ec->max_y_tilde = MAX16(ec->y_tilde_s.buf_d + ec->y_tilde_s.idx_d, ec->N_d, &ec->max_y_tilde_pos);
}
/* Determine if near end speech was detected in this sample */
/* -------------------------------------------------------- */
if (((ec->s_tilde_i >> (DEFAULT_ALPHA_ST_I - 1)) > ec->max_y_tilde)
&& (ec->max_y_tilde > 0)) {
/* Then start the Hangover counter */
ec->HCNTR_d = DEFAULT_HANGT;
#ifdef MEC2_STATS_DETAILED
printk(KERN_INFO "Reset near end speech timer with: s_tilde_i %d, stmnt %d, max_y_tilde %d\n", ec->s_tilde_i, (ec->s_tilde_i >> (DEFAULT_ALPHA_ST_I - 1)), ec->max_y_tilde);
#endif
#ifdef MEC2_STATS
++ec->cntr_nearend_speech_frames;
#endif
} else if (ec->HCNTR_d > (int)0) {
/* otherwise, if it's still non-zero, decrement the Hangover counter by one sample */
#ifdef MEC2_STATS
++ec->cntr_nearend_speech_frames;
#endif
ec->HCNTR_d--;
}
/* Update coefficients if no near-end speech in this sample (ie. HCNTR_d = 0)
* and we have enough signal to bother trying to update.
* --------------------------------------------------------------------------
*/
if (!ec->HCNTR_d && /* no near-end speech present */
!(ec->i_d % DEFAULT_M)) { /* we only update on every DEFAULM_M'th sample from the stream */
if (ec->Lu_i > MIN_UPDATE_THRESH_I) { /* there is sufficient energy above the noise floor to contain meaningful data */
/* so loop over all the filter coefficients */
#ifdef MEC2_STATS_DETAILED
printk( KERN_INFO "updating coefficients with: ec->Lu_i %9d\n", ec->Lu_i);
#endif
#ifdef MEC2_STATS
ec->avg_Lu_i_ok = ec->avg_Lu_i_ok + ec->Lu_i;
++ec->cntr_coeff_updates;
#endif
for (k=0; k < ec->N_d; k++) {
/* eq. (7): compute an expectation over M_d samples */
int grad2;
grad2 = CONVOLVE2(ec->u_s.buf_d + ec->u_s.idx_d,
ec->y_s.buf_d + ec->y_s.idx_d + k,
DEFAULT_M);
/* eq. (7): update the coefficient */
ec->a_i[k] += grad2 / two_beta_i;
ec->a_s[k] = ec->a_i[k] >> 16;
}
} else {
#ifdef MEC2_STATS_DETAILED
printk( KERN_INFO "insufficient signal to update coefficients ec->Lu_i %5d < %5d\n", ec->Lu_i, MIN_UPDATE_THRESH_I);
#endif
#ifdef MEC2_STATS
ec->avg_Lu_i_toolow = ec->avg_Lu_i_toolow + ec->Lu_i;
++ec->cntr_coeff_missedupdates;
#endif
}
}
/* paragraph below eq. (15): if no near-end speech in the sample and
* the reference signal power estimate > cutoff threshold
* then perform residual error suppression
*/
#ifdef MEC2_STATS_DETAILED
if (ec->HCNTR_d == 0)
printk( KERN_INFO "possibily correcting frame with ec->Ly_i %9d ec->Lu_i %9d and expression %d\n", ec->Ly_i, ec->Lu_i, (ec->Ly_i/(ec->Lu_i + 1)));
#endif
#ifndef NO_ECHO_SUPPRESSOR
#ifdef AGGRESSIVE_SUPPRESSOR
if ((ec->HCNTR_d < AGGRESSIVE_HCNTR) && (ec->Ly_i > (ec->Lu_i << 1))) {
for (k=0; k < RESIDUAL_SUPRESSION_PASSES; k++) {
u = u * (ec->Lu_i >> DEFAULT_SIGMA_LU_I) / ((ec->Ly_i >> (DEFAULT_SIGMA_LY_I)) + 1);
}
#ifdef MEC2_STATS_DETAILED
printk( KERN_INFO "aggresively correcting frame with ec->Ly_i %9d ec->Lu_i %9d expression %d\n", ec->Ly_i, ec->Lu_i, (ec->Ly_i/(ec->Lu_i + 1)));
#endif
#ifdef MEC2_STATS
++ec->cntr_residualcorrected_frames;
#endif
}
#else
if (ec->HCNTR_d == 0) {
if ((ec->Ly_i/(ec->Lu_i + 1)) > DEFAULT_SUPPR_I) {
for (k=0; k < RESIDUAL_SUPRESSION_PASSES; k++) {
u = u * (ec->Lu_i >> DEFAULT_SIGMA_LU_I) / ((ec->Ly_i >> (DEFAULT_SIGMA_LY_I + 2)) + 1);
}
#ifdef MEC2_STATS_DETAILED
printk( KERN_INFO "correcting frame with ec->Ly_i %9d ec->Lu_i %9d expression %d\n", ec->Ly_i, ec->Lu_i, (ec->Ly_i/(ec->Lu_i + 1)));
#endif
#ifdef MEC2_STATS
++ec->cntr_residualcorrected_frames;
#endif
}
#ifdef MEC2_STATS
else {
++ec->cntr_residualcorrected_framesskipped;
}
#endif
}
#endif
#endif
#if 0
/* This will generate a non-linear supression factor, once converted */
if ((ec->HCNTR_d == 0) &&
((ec->Lu_d/ec->Ly_d) < DEFAULT_SUPPR) &&
(ec->Lu_d/ec->Ly_d > EC_MIN_DB_VALUE)) {
suppr_factor = (10 / (float)(SUPPR_FLOOR - SUPPR_CEIL)) * log(ec->Lu_d/ec->Ly_d)
- SUPPR_CEIL / (float)(SUPPR_FLOOR - SUPPR_CEIL);
u_suppr = pow(10.0, (suppr_factor) * RES_SUPR_FACTOR / 10.0) * u_suppr;
}
#endif
#ifdef MEC2_STATS
/* Periodically dump performance stats */
if ((ec->i_d % MEC2_STATS) == 0) {
/* make sure to avoid div0's! */
if (ec->cntr_coeff_missedupdates > 0)
ec->avg_Lu_i_toolow = (int)(ec->avg_Lu_i_toolow / ec->cntr_coeff_missedupdates);
else
ec->avg_Lu_i_toolow = -1;
if (ec->cntr_coeff_updates > 0)
ec->avg_Lu_i_ok = (ec->avg_Lu_i_ok / ec->cntr_coeff_updates);
else
ec->avg_Lu_i_ok = -1;
printk( KERN_INFO "%d: Near end speech: %5d Residuals corrected/skipped: %5d/%5d Coefficients updated ok/low sig: %3d/%3d Lu_i avg ok/low sig %6d/%5d\n",
ec->id,
ec->cntr_nearend_speech_frames,
ec->cntr_residualcorrected_frames, ec->cntr_residualcorrected_framesskipped,
ec->cntr_coeff_updates, ec->cntr_coeff_missedupdates,
ec->avg_Lu_i_ok, ec->avg_Lu_i_toolow);
ec->cntr_nearend_speech_frames = 0;
ec->cntr_residualcorrected_frames = 0;
ec->cntr_residualcorrected_framesskipped = 0;
ec->cntr_coeff_updates = 0;
ec->cntr_coeff_missedupdates = 0;
ec->avg_Lu_i_ok = 0;
ec->avg_Lu_i_toolow = 0;
}
#endif
/* Increment the sample index and return the corrected sample */
ec->i_d++;
return u;
}
static inline struct echo_can_state *echo_can_create(int len, int adaption_mode)
{
struct echo_can_state *ec;
int maxy;
int maxu;
maxy = len + DEFAULT_M;
maxu = DEFAULT_M;
if (maxy < (1 << DEFAULT_ALPHA_YT_I))
maxy = (1 << DEFAULT_ALPHA_YT_I);
if (maxy < (1 << DEFAULT_SIGMA_LY_I))
maxy = (1 << DEFAULT_SIGMA_LY_I);
if (maxu < (1 << DEFAULT_SIGMA_LU_I))
maxu = (1 << DEFAULT_SIGMA_LU_I);
ec = (struct echo_can_state *)MALLOC(sizeof(struct echo_can_state) +
4 + /* align */
sizeof(int) * len + /* a_i */
sizeof(short) * len + /* a_s */
2 * sizeof(short) * (maxy) + /* y_s */
2 * sizeof(short) * (1 << DEFAULT_ALPHA_ST_I) + /* s_s */
2 * sizeof(short) * (maxu) + /* u_s */
2 * sizeof(short) * len); /* y_tilde_s */
if (ec) {
memset(ec, 0, sizeof(struct echo_can_state) +
4 + /* align */
sizeof(int) * len + /* a_i */
sizeof(short) * len + /* a_s */
2 * sizeof(short) * (maxy) + /* y_s */
2 * sizeof(short) * (1 << DEFAULT_ALPHA_ST_I) + /* s_s */
2 * sizeof(short) * (maxu) + /* u_s */
2 * sizeof(short) * len); /* y_tilde_s */
init_cc(ec, len, maxy, maxu);
}
return ec;
}
static inline int echo_can_traintap(struct echo_can_state *ec, int pos, short val)
{
/* Set the hangover counter to the length of the can to
* avoid adjustments occuring immediately after initial forced training
*/
ec->HCNTR_d = ec->N_d << 1;
if (pos >= ec->N_d)
return 1;
ec->a_i[pos] = val << 17;
ec->a_s[pos] = val << 1;
if (++pos >= ec->N_d)
return 1;
return 0;
}
#endif

View File

@ -0,0 +1,81 @@
/*
Important constants for tuning kb1 echo can
*/
#ifndef _MEC2_CONST_H
#define _MEC2_CONST_H
/* Convergence (aka. adaptation) speed -- higher means slower */
#define DEFAULT_BETA1_I 2048
/* Constants for various power computations */
#define DEFAULT_SIGMA_LY_I 7
#define DEFAULT_SIGMA_LU_I 7
#define DEFAULT_ALPHA_ST_I 5 /* near-end speech detection sensitivity factor */
#define DEFAULT_ALPHA_YT_I 5
#define DEFAULT_CUTOFF_I 128
/* Define the near-end speech hangover counter: if near-end speech
* is declared, hcntr is set equal to hangt (see pg. 432)
*/
#define DEFAULT_HANGT 600 /* in samples, so 600 samples = 75ms */
/* define the residual error suppression threshold */
#define DEFAULT_SUPPR_I 16 /* 16 = -24db */
/* This is the minimum reference signal power estimate level
* that will result in filter adaptation.
* If this is too low then background noise will cause the filter
* coefficients to constantly be updated.
*/
#define MIN_UPDATE_THRESH_I 4096
/* The number of samples used to update coefficients using the
* the block update method (M). It should be related back to the
* length of the echo can.
* ie. it only updates coefficients when (sample number MOD default_m) = 0
*
* Getting this wrong may cause an oops. Consider yourself warned!
*/
#define DEFAULT_M 16 /* every 16th sample */
/* If AGGRESSIVE supression is enabled, then we start cancelling residual
* echos again even while there is potentially the very end of a near-side
* signal present.
* This defines how many samples of DEFAULT_HANGT can remain before we
* kick back in
*/
#define AGGRESSIVE_HCNTR 160 /* in samples, so 160 samples = 20ms */
/* This knob controls the number of passes the residual echo supression
* algorithm makes.
*/
#ifdef AGGRESSIVE_SUPPRESSOR
#define RESIDUAL_SUPRESSION_PASSES 2
#else
#define RESIDUAL_SUPRESSION_PASSES 1
#endif
/***************************************************************/
/* The following knobs are not implemented in the current code */
/* we need a dynamic level of suppression varying with the ratio of the
power of the echo to the power of the reference signal this is
done so that we have a smoother background.
we have a higher suppression when the power ratio is closer to
suppr_ceil and reduces logarithmically as we approach suppr_floor.
*/
#define SUPPR_FLOOR -64
#define SUPPR_CEIL -24
/* in a second departure, we calculate the residual error suppression
* as a percentage of the reference signal energy level. The threshold
* is defined in terms of dB below the reference signal.
*/
#define RES_SUPR_FACTOR -20
#endif /* _MEC2_CONST_H */

View File

@ -0,0 +1,424 @@
/*
* Mark's Second Echo Canceller
*
* Copyright (C) 2002, Digium, Inc.
*
* This program is free software and may be used and
* distributed according to the terms of the GNU
* General Public License, incorporated herein by
* reference.
*
*/
#ifndef _MARK2_ECHO_H
#define _MARK2_ECHO_H
#define EC_TYPE "MARK2"
#ifdef __KERNEL__
#include <linux/kernel.h>
#include <linux/slab.h>
#define MALLOC(a) kmalloc((a), GFP_ATOMIC)
#define FREE(a) kfree(a)
#else
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>
#include <string.h>
#include <math.h>
#define MALLOC(a) malloc(a)
#define FREE(a) free(a)
#endif
/* Get optimized routines for math */
#include "dsp_arith.h"
#ifndef NULL
#define NULL 0
#endif
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE (!FALSE)
#endif
#include "dsp_mec2_const.h"
/* Circular buffer definition */
typedef struct {
int idx_d;
int size_d;
short *buf_d; /* Twice as large as we need */
} echo_can_cb_s;
// class definition
//
struct echo_can_state {
/* Echo canceller definition */
/* absolute time */
int i_d;
/* pre-computed constants */
int N_d;
int beta2_i;
// declare accumulators for power computations
//
int Ly_i;
int Lu_i;
// declare an accumulator for the near-end signal detector
//
int s_tilde_i;
int HCNTR_d;
// circular buffers and coefficients
//
int *a_i;
short *a_s;
echo_can_cb_s y_s;
echo_can_cb_s s_s;
echo_can_cb_s u_s;
echo_can_cb_s y_tilde_s;
int y_tilde_i;
/* Max memory */
short max_y_tilde;
int max_y_tilde_pos;
};
static inline void init_cb_s(echo_can_cb_s *cb, int len, void *where)
{
cb->buf_d = (short *)where;
cb->idx_d = 0;
cb->size_d = len;
}
static inline void add_cc_s(echo_can_cb_s *cb, short newval)
{
/* Can't use modulus because N+M isn't a power of two (generally) */
cb->idx_d--;
if (cb->idx_d < (int)0)
{cb->idx_d += cb->size_d;}
/* Load two copies into memory */
cb->buf_d[cb->idx_d] = newval;
cb->buf_d[cb->idx_d + cb->size_d] = newval;
}
static inline short get_cc_s(echo_can_cb_s *cb, int pos)
{
/* Load two copies into memory */
return cb->buf_d[cb->idx_d + pos];
}
static inline void init_cc(struct echo_can_state *ec, int N, int maxy, int maxu) {
void *ptr = ec;
unsigned long tmp;
/* double-word align past end of state */
ptr += sizeof(struct echo_can_state);
tmp = (unsigned long)ptr;
tmp += 3;
tmp &= ~3L;
ptr = (void *)tmp;
// reset parameters
//
ec->N_d = N;
ec->beta2_i = DEFAULT_BETA1_I;
// allocate coefficient memory
//
ec->a_i = ptr;
ptr += (sizeof(int) * ec->N_d);
ec->a_s = ptr;
ptr += (sizeof(short) * ec->N_d);
/* Reset Y circular buffer (short version) */
init_cb_s(&ec->y_s, maxy, ptr);
ptr += (sizeof(short) * (maxy) * 2);
/* Reset Sig circular buffer (short version for FIR filter) */
init_cb_s(&ec->s_s, (1 << DEFAULT_ALPHA_ST_I), ptr);
ptr += (sizeof(short) * (1 << DEFAULT_ALPHA_ST_I) * 2);
init_cb_s(&ec->u_s, maxu, ptr);
ptr += (sizeof(short) * maxu * 2);
// allocate a buffer for the reference signal power computation
//
init_cb_s(&ec->y_tilde_s, ec->N_d, ptr);
// reset absolute time
//
ec->i_d = (int)0;
// reset the power computations (for y and u)
//
ec->Ly_i = DEFAULT_CUTOFF_I;
ec->Lu_i = DEFAULT_CUTOFF_I;
// reset the near-end speech detector
//
ec->s_tilde_i = 0;
ec->y_tilde_i = 0;
ec->HCNTR_d = (int)0;
// exit gracefully
//
}
static inline void echo_can_free(struct echo_can_state *ec)
{
FREE(ec);
}
static inline short echo_can_update(struct echo_can_state *ec, short iref, short isig) {
/* declare local variables that are used more than once
*/
int k;
int rs;
short u;
int Py_i;
int two_beta_i;
/***************************************************************************
//
// flow A on pg. 428
//
***************************************************************************/
/* eq. (16): high-pass filter the input to generate the next value;
// push the current value into the circular buffer
//
// sdc_im1_d = sdc_d;
// sdc_d = sig;
// s_i_d = sdc_d;
// s_d = s_i_d;
// s_i_d = (float)(1.0 - gamma_d) * s_i_d
+ (float)(0.5 * (1.0 - gamma_d)) * (sdc_d - sdc_im1_d); */
/* Delete last sample from power estimate */
ec->y_tilde_i -= abs(get_cc_s(&ec->y_s, (1 << DEFAULT_ALPHA_YT_I) - 1 )) >> DEFAULT_ALPHA_YT_I;
/* push the reference data onto the circular buffer */
add_cc_s(&ec->y_s, iref);
/* eq. (2): compute r in fixed-point */
rs = CONVOLVE2(ec->a_s, ec->y_s.buf_d + ec->y_s.idx_d, ec->N_d);
rs >>= 15;
/* eq. (3): compute the output value (see figure 3) and the error
// note: the error is the same as the output signal when near-end
// speech is not present
*/
u = isig - rs;
add_cc_s(&ec->u_s, u);
/* Delete oldest part of received s_tilde */
ec->s_tilde_i -= abs(get_cc_s(&ec->s_s, (1 << DEFAULT_ALPHA_ST_I) - 1 ));
/* push the signal on the circular buffer, too */
add_cc_s(&ec->s_s, isig);
ec->s_tilde_i += abs(isig);
ec->y_tilde_i += abs(iref) >> DEFAULT_ALPHA_YT_I;
/* Add to our list of recent y_tilde's */
add_cc_s(&ec->y_tilde_s, ec->y_tilde_i);
/****************************************************************************
//
// flow B on pg. 428
//
****************************************************************************/
/* compute the new convergence factor
*/
if (!ec->HCNTR_d) {
Py_i = (ec->Ly_i >> DEFAULT_SIGMA_LY_I) * (ec->Ly_i >> DEFAULT_SIGMA_LY_I);
Py_i >>= 15;
} else {
Py_i = (1 << 15);
}
#if 0
printf("Py: %e, Py_i: %e\n", Py, Py_i * AMPL_SCALE_1);
#endif
/* Vary rate of adaptation depending on position in the file
// Do not do this for the first (DEFAULT_UPDATE_TIME) secs after speech
// has begun of the file to allow the echo cancellor to estimate the
// channel accurately
*/
#if 0
if (ec->start_speech_d != 0 ){
if ( ec->i_d > (DEFAULT_T0 + ec->start_speech_d)*(SAMPLE_FREQ) ){
ec->beta2_d = max_cc_float(MIN_BETA,
DEFAULT_BETA1 * exp((-1/DEFAULT_TAU)*((ec->i_d/(float)SAMPLE_FREQ) -
DEFAULT_T0 -
ec->start_speech_d)));
}
}
else {ec->beta2_d = DEFAULT_BETA1;}
#endif
ec->beta2_i = DEFAULT_BETA1_I; /* Fixed point, inverted */
two_beta_i = (ec->beta2_i * Py_i) >> 15; /* Fixed point version, inverted */
if (!two_beta_i)
two_beta_i++;
/* Update Lu_i (Suppressed power estimate) */
ec->Lu_i -= abs(get_cc_s(&ec->u_s, (1 << DEFAULT_SIGMA_LU_I) - 1 )) ;
ec->Lu_i += abs(u);
/* eq. (10): update power estimate of the reference
*/
ec->Ly_i -= abs(get_cc_s(&ec->y_s, (1 << DEFAULT_SIGMA_LY_I) - 1)) ;
ec->Ly_i += abs(iref);
if (ec->Ly_i < DEFAULT_CUTOFF_I)
ec->Ly_i = DEFAULT_CUTOFF_I;
#if 0
printf("Float: %e, Int: %e\n", ec->Ly_d, (ec->Ly_i >> DEFAULT_SIGMA_LY_I) * AMPL_SCALE_1);
#endif
if (ec->y_tilde_i > ec->max_y_tilde) {
/* New highest y_tilde with full life */
ec->max_y_tilde = ec->y_tilde_i;
ec->max_y_tilde_pos = ec->N_d - 1;
} else if (--ec->max_y_tilde_pos < 0) {
/* Time to find new max y tilde... */
ec->max_y_tilde = MAX16(ec->y_tilde_s.buf_d + ec->y_tilde_s.idx_d, ec->N_d, &ec->max_y_tilde_pos);
}
if ((ec->s_tilde_i >> (DEFAULT_ALPHA_ST_I - 1)) > ec->max_y_tilde)
{
ec->HCNTR_d = DEFAULT_HANGT;
}
else if (ec->HCNTR_d > (int)0)
{
ec->HCNTR_d--;
}
/* update coefficients if no near-end speech and we have enough signal
* to bother trying to update.
*/
if (!ec->HCNTR_d && !(ec->i_d % DEFAULT_M) &&
(ec->Lu_i > MIN_UPDATE_THRESH_I)) {
// loop over all filter coefficients
//
for (k=0; k<ec->N_d; k++) {
// eq. (7): compute an expectation over M_d samples
//
int grad2;
grad2 = CONVOLVE2(ec->u_s.buf_d + ec->u_s.idx_d,
ec->y_s.buf_d + ec->y_s.idx_d + k, DEFAULT_M);
// eq. (7): update the coefficient
//
ec->a_i[k] += grad2 / two_beta_i;
ec->a_s[k] = ec->a_i[k] >> 16;
}
}
/* paragraph below eq. (15): if no near-end speech,
// check for residual error suppression
*/
#ifndef NO_ECHO_SUPPRESSOR
#ifdef AGGRESSIVE_SUPPRESSOR
#ifdef AGGRESSIVE_TIMELIMIT /* This allows the aggressive suppressor to turn off after set amount of time */
if (ec->i_d > AGGRESSIVE_TIMELIMIT ) {
if ((ec->HCNTR_d == 0) && ((ec->Ly_i/(ec->Lu_i + 1)) > DEFAULT_SUPPR_I)) {
u = u * (ec->Lu_i >> DEFAULT_SIGMA_LU_I) / ((ec->Ly_i >> (DEFAULT_SIGMA_LY_I + 2)) + 1);
}
}
else {
#endif
if ((ec->HCNTR_d < AGGRESSIVE_HCNTR) && (ec->Ly_i > (ec->Lu_i << 1))) {
u = u * (ec->Lu_i >> DEFAULT_SIGMA_LU_I) / ((ec->Ly_i >> (DEFAULT_SIGMA_LY_I)) + 1);
u = u * (ec->Lu_i >> DEFAULT_SIGMA_LU_I) / ((ec->Ly_i >> (DEFAULT_SIGMA_LY_I)) + 1);
}
#ifdef AGGRESSIVE_TIMELIMIT
}
#endif
#else
if ((ec->HCNTR_d == 0) && ((ec->Ly_i/(ec->Lu_i + 1)) > DEFAULT_SUPPR_I)) {
u = u * (ec->Lu_i >> DEFAULT_SIGMA_LU_I) / ((ec->Ly_i >> (DEFAULT_SIGMA_LY_I + 2)) + 1);
}
#endif
#endif
#if 0
if ((ec->HCNTR_d == 0) && ((ec->Lu_d/ec->Ly_d) < DEFAULT_SUPPR) &&
(ec->Lu_d/ec->Ly_d > EC_MIN_DB_VALUE)) {
suppr_factor = (10/(float)(SUPPR_FLOOR-SUPPR_CEIL))*log(ec->Lu_d/ec->Ly_d)
- SUPPR_CEIL/(float)(SUPPR_FLOOR - SUPPR_CEIL);
u_suppr = pow(10.0,(suppr_factor)*RES_SUPR_FACTOR/10.0)*u_suppr;
}
#endif
ec->i_d++;
return u;
}
static inline struct echo_can_state *echo_can_create(int len, int adaption_mode)
{
struct echo_can_state *ec;
int maxy;
int maxu;
maxy = len + DEFAULT_M;
maxu = DEFAULT_M;
if (maxy < (1 << DEFAULT_ALPHA_YT_I))
maxy = (1 << DEFAULT_ALPHA_YT_I);
if (maxy < (1 << DEFAULT_SIGMA_LY_I))
maxy = (1 << DEFAULT_SIGMA_LY_I);
if (maxu < (1 << DEFAULT_SIGMA_LU_I))
maxu = (1 << DEFAULT_SIGMA_LU_I);
ec = (struct echo_can_state *)MALLOC(sizeof(struct echo_can_state) +
4 + /* align */
sizeof(int) * len + /* a_i */
sizeof(short) * len + /* a_s */
2 * sizeof(short) * (maxy) + /* y_s */
2 * sizeof(short) * (1 << DEFAULT_ALPHA_ST_I) + /* s_s */
2 * sizeof(short) * (maxu) + /* u_s */
2 * sizeof(short) * len); /* y_tilde_s */
if (ec) {
memset(ec, 0, sizeof(struct echo_can_state) +
4 + /* align */
sizeof(int) * len + /* a_i */
sizeof(short) * len + /* a_s */
2 * sizeof(short) * (maxy) + /* y_s */
2 * sizeof(short) * (1 << DEFAULT_ALPHA_ST_I) + /* s_s */
2 * sizeof(short) * (maxu) + /* u_s */
2 * sizeof(short) * len); /* y_tilde_s */
init_cc(ec, len, maxy, maxu);
}
return ec;
}
static inline int echo_can_traintap(struct echo_can_state *ec, int pos, short val)
{
/* Reset hang counter to avoid adjustments after
initial forced training */
ec->HCNTR_d = ec->N_d << 1;
if (pos >= ec->N_d)
return 1;
ec->a_i[pos] = val << 17;
ec->a_s[pos] = val << 1;
if (++pos >= ec->N_d)
return 1;
return 0;
}
#endif

View File

@ -0,0 +1,28 @@
/*
Important constants for tuning mec2 echo can
*/
#ifndef _MEC2_CONST_H
#define _MEC2_CONST_H
/* Convergence speed -- higher means slower */
#define DEFAULT_BETA1_I 2048
#define DEFAULT_SIGMA_LY_I 7
#define DEFAULT_SIGMA_LU_I 7
#define DEFAULT_ALPHA_ST_I 5
#define DEFAULT_ALPHA_YT_I 5
#define DEFAULT_CUTOFF_I 128
#define DEFAULT_HANGT 600
#define DEFAULT_SUPPR_I 16
#define MIN_UPDATE_THRESH_I 4096
#define DEFAULT_M 16
#define SUPPR_FLOOR -64
#define SUPPR_CEIL -24
#define RES_SUPR_FACTOR -20
#define AGGRESSIVE_HCNTR 160 /* 20ms */
/* Only use agressive echo cancellation for this amount of time then go back to normal cancelation */
/* #define AGGRESSIVE_TIMELIMIT 150000 */ /* 8 = 1ms */
#endif /* _MEC2_CONST_H */

View File

@ -0,0 +1,705 @@
/*
* ECHO_CAN_MG2
*
* by Michael Gernoth
*
* Based upon kb1ec.h and mec2.h
*
* Copyright (C) 2002, Digium, Inc.
*
* This program is free software and may be used and
* distributed according to the terms of the GNU
* General Public License, incorporated herein by
* reference.
*
* Additional background on the techniques used in this code can be found in:
*
* Messerschmitt, David; Hedberg, David; Cole, Christopher; Haoui, Amine;
* Winship, Peter; "Digital Voice Echo Canceller with a TMS32020,"
* in Digital Signal Processing Applications with the TMS320 Family,
* pp. 415-437, Texas Instruments, Inc., 1986.
*
* A pdf of which is available by searching on the document title at http://www.ti.com/
*
*/
#ifndef _MG2_ECHO_H
#define _MG2_ECHO_H
#define EC_TYPE "MG2"
#ifdef __KERNEL__
#include <linux/kernel.h>
#include <linux/slab.h>
#define MALLOC(a) kmalloc((a), GFP_ATOMIC)
#define FREE(a) kfree(a)
#else
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>
#include <string.h>
#include <math.h>
#define MALLOC(a) malloc(a)
#define FREE(a) free(a)
#endif
#define ABS(a) abs(a!=-32768?a:-32767)
#define RESTORE_COEFFS {\
int x;\
memcpy(ec->a_i, ec->c_i, ec->N_d*sizeof(int));\
for (x=0;x<ec->N_d;x++) {\
ec->a_s[x] = ec->a_i[x] >> 16;\
}\
ec->backup = BACKUP;\
}
/* Uncomment to provide summary statistics for overall echo can performance every 4000 samples */
/* #define MEC2_STATS 4000 */
/* Uncomment to generate per-sample statistics - this will severely degrade system performance and audio quality */
/* #define MEC2_STATS_DETAILED */
/* Uncomment to generate per-call DC bias offset messages */
/* #define MEC2_DCBIAS_MESSAGE */
/* Get optimized routines for math */
#include "dsp_arith.h"
/* Bring in definitions for the various constants and thresholds */
#include "dsp_mg2ec_const.h"
#define DC_NORMALIZE
#ifndef NULL
#define NULL 0
#endif
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE (!FALSE)
#endif
/* Generic circular buffer definition */
typedef struct {
/* Pointer to the relative 'start' of the buffer */
int idx_d;
/* The absolute size of the buffer */
int size_d;
/* The actual sample - twice as large as we need, however we do store values at idx_d and idx_d+size_d */
short *buf_d;
} echo_can_cb_s;
/* Echo canceller definition */
struct echo_can_state {
/* an arbitrary ID for this echo can - this really should be settable from the calling channel... */
int id;
/* absolute time - aka. sample number index - essentially the number of samples since this can was init'ed */
int i_d;
/* Pre-computed constants */
/* ---------------------- */
/* Number of filter coefficents */
int N_d;
/* Rate of adaptation of filter */
int beta2_i;
/* Accumulators for power computations */
/* ----------------------------------- */
/* reference signal power estimate - aka. Average absolute value of y(k) */
int Ly_i;
/* ... */
int Lu_i;
/* Accumulators for signal detectors */
/* --------------------------------- */
/* Power estimate of the recent past of the near-end hybrid signal - aka. Short-time average of: 2 x |s(i)| */
int s_tilde_i;
/* Power estimate of the recent past of the far-end receive signal - aka. Short-time average of: |y(i)| */
int y_tilde_i;
/* Near end speech detection counter - stores Hangover counter time remaining, in samples */
int HCNTR_d;
/* Circular buffers and coefficients */
/* --------------------------------- */
/* ... */
int *a_i;
/* ... */
short *a_s;
/* Backups */
int *b_i;
int *c_i;
/* Reference samples of far-end receive signal */
echo_can_cb_s y_s;
/* Reference samples of near-end signal */
echo_can_cb_s s_s;
/* Reference samples of near-end signal minus echo estimate */
echo_can_cb_s u_s;
/* Reference samples of far-end receive signal used to calculate short-time average */
echo_can_cb_s y_tilde_s;
/* Peak far-end receive signal */
/* --------------------------- */
/* Highest y_tilde value in the sample buffer */
short max_y_tilde;
/* Index of the sample containing the max_y_tilde value */
int max_y_tilde_pos;
#ifdef MEC2_STATS
/* Storage for performance statistics */
int cntr_nearend_speech_frames;
int cntr_residualcorrected_frames;
int cntr_residualcorrected_framesskipped;
int cntr_coeff_updates;
int cntr_coeff_missedupdates;
int avg_Lu_i_toolow;
int avg_Lu_i_ok;
#endif
short lastsig;
int lastcount;
int backup;
#ifdef DC_NORMALIZE
int dc_estimate;
#endif
};
static inline void init_cb_s(echo_can_cb_s *cb, int len, void *where)
{
cb->buf_d = (short *)where;
cb->idx_d = 0;
cb->size_d = len;
}
static inline void add_cc_s(echo_can_cb_s *cb, short newval)
{
/* Can't use modulus because N+M isn't a power of two (generally) */
cb->idx_d--;
if (cb->idx_d < (int)0)
/* Whoops - the pointer to the 'start' wrapped around so reset it to the top of the buffer */
cb->idx_d += cb->size_d;
/* Load two copies into memory */
cb->buf_d[cb->idx_d] = newval;
cb->buf_d[cb->idx_d + cb->size_d] = newval;
}
static inline short get_cc_s(echo_can_cb_s *cb, int pos)
{
/* Load two copies into memory */
return cb->buf_d[cb->idx_d + pos];
}
static inline void init_cc(struct echo_can_state *ec, int N, int maxy, int maxu)
{
void *ptr = ec;
unsigned long tmp;
/* Double-word align past end of state */
ptr += sizeof(struct echo_can_state);
tmp = (unsigned long)ptr;
tmp += 3;
tmp &= ~3L;
ptr = (void *)tmp;
/* Reset parameters */
ec->N_d = N;
ec->beta2_i = DEFAULT_BETA1_I;
/* Allocate coefficient memory */
ec->a_i = ptr;
ptr += (sizeof(int) * ec->N_d);
ec->a_s = ptr;
ptr += (sizeof(short) * ec->N_d);
/* Allocate backup memory */
ec->b_i = ptr;
ptr += (sizeof(int) * ec->N_d);
ec->c_i = ptr;
ptr += (sizeof(int) * ec->N_d);
/* Reset Y circular buffer (short version) */
init_cb_s(&ec->y_s, maxy, ptr);
ptr += (sizeof(short) * (maxy) * 2);
/* Reset Sigma circular buffer (short version for FIR filter) */
init_cb_s(&ec->s_s, (1 << DEFAULT_ALPHA_ST_I), ptr);
ptr += (sizeof(short) * (1 << DEFAULT_ALPHA_ST_I) * 2);
init_cb_s(&ec->u_s, maxu, ptr);
ptr += (sizeof(short) * maxu * 2);
/* Allocate a buffer for the reference signal power computation */
init_cb_s(&ec->y_tilde_s, ec->N_d, ptr);
/* Reset the absolute time index */
ec->i_d = (int)0;
/* Reset the power computations (for y and u) */
ec->Ly_i = DEFAULT_CUTOFF_I;
ec->Lu_i = DEFAULT_CUTOFF_I;
#ifdef MEC2_STATS
/* set the identity */
ec->id = (int)&ptr;
/* Reset performance stats */
ec->cntr_nearend_speech_frames = (int)0;
ec->cntr_residualcorrected_frames = (int)0;
ec->cntr_residualcorrected_framesskipped = (int)0;
ec->cntr_coeff_updates = (int)0;
ec->cntr_coeff_missedupdates = (int)0;
ec->avg_Lu_i_toolow = (int)0;
ec->avg_Lu_i_ok = (int)0;
#endif
/* Reset the near-end speech detector */
ec->s_tilde_i = (int)0;
ec->y_tilde_i = (int)0;
ec->HCNTR_d = (int)0;
}
static inline void echo_can_free(struct echo_can_state *ec)
{
#if defined(DC_NORMALIZE) && defined(MEC2_DCBIAS_MESSAGE)
printk("EC: DC bias calculated: %d V\n", ec->dc_estimate >> 15);
#endif
FREE(ec);
}
#ifdef DC_NORMALIZE
static short inline dc_removal(int *dc_estimate, short samp)
{
*dc_estimate += ((((int)samp << 15) - *dc_estimate) >> 9);
return samp - (*dc_estimate >> 15);
}
#endif
static inline short echo_can_update(struct echo_can_state *ec, short iref, short isig)
{
/* Declare local variables that are used more than once */
/* ... */
int k;
/* ... */
int rs;
/* ... */
short u;
/* ... */
int Py_i;
/* ... */
int two_beta_i;
#ifdef DC_NORMALIZE
isig = dc_removal(&ec->dc_estimate, isig);
#endif
/* flow A on pg. 428 */
/* eq. (16): high-pass filter the input to generate the next value;
* push the current value into the circular buffer
*
* sdc_im1_d = sdc_d;
* sdc_d = sig;
* s_i_d = sdc_d;
* s_d = s_i_d;
* s_i_d = (float)(1.0 - gamma_d) * s_i_d
* + (float)(0.5 * (1.0 - gamma_d)) * (sdc_d - sdc_im1_d);
*/
/* Update the Far-end receive signal circular buffers and accumulators */
/* ------------------------------------------------------------------- */
/* Delete the oldest sample from the power estimate accumulator */
ec->y_tilde_i -= abs(get_cc_s(&ec->y_s, (1 << DEFAULT_ALPHA_YT_I) - 1 )) >> DEFAULT_ALPHA_YT_I;
/* Add the new sample to the power estimate accumulator */
ec->y_tilde_i += abs(iref) >> DEFAULT_ALPHA_ST_I;
/* Push a copy of the new sample into its circular buffer */
add_cc_s(&ec->y_s, iref);
/* eq. (2): compute r in fixed-point */
rs = CONVOLVE2(ec->a_s,
ec->y_s.buf_d + ec->y_s.idx_d,
ec->N_d);
rs >>= 15;
if (ec->lastsig == isig) {
ec->lastcount++;
} else {
ec->lastcount = 0;
ec->lastsig = isig;
}
if (isig == 0) {
u = 0;
} else if (ec->lastcount > 255) {
/* We have seen the same input-signal more than 255 times,
* we should pass it through uncancelled, as we are likely on hold */
u = isig;
} else {
if (rs < -32768) {
rs = -32768;
ec->HCNTR_d = DEFAULT_HANGT;
RESTORE_COEFFS;
} else if (rs > 32767) {
rs = 32767;
ec->HCNTR_d = DEFAULT_HANGT;
RESTORE_COEFFS;
}
if (ABS(ABS(rs)-ABS(isig)) > MAX_SIGN_ERROR)
{
rs = 0;
RESTORE_COEFFS;
}
/* eq. (3): compute the output value (see figure 3) and the error
* note: the error is the same as the output signal when near-end
* speech is not present
*/
u = isig - rs;
if (u / isig < 0)
u = isig - (rs >> 1);
}
/* Push a copy of the output value sample into its circular buffer */
add_cc_s(&ec->u_s, u);
if (!ec->backup) {
/* Backup coefficients periodically */
ec->backup = BACKUP;
memcpy(ec->c_i,ec->b_i,ec->N_d*sizeof(int));
memcpy(ec->b_i,ec->a_i,ec->N_d*sizeof(int));
} else
ec->backup--;
/* Update the Near-end hybrid signal circular buffers and accumulators */
/* ------------------------------------------------------------------- */
/* Delete the oldest sample from the power estimate accumulator */
ec->s_tilde_i -= abs(get_cc_s(&ec->s_s, (1 << DEFAULT_ALPHA_ST_I) - 1 ));
/* Add the new sample to the power estimate accumulator */
ec->s_tilde_i += abs(isig);
/* Push a copy of the new sample into it's circular buffer */
add_cc_s(&ec->s_s, isig);
/* Push a copy of the current short-time average of the far-end receive signal into it's circular buffer */
add_cc_s(&ec->y_tilde_s, ec->y_tilde_i);
/* flow B on pg. 428 */
/* If the hangover timer isn't running then compute the new convergence factor, otherwise set Py_i to 32768 */
if (!ec->HCNTR_d) {
Py_i = (ec->Ly_i >> DEFAULT_SIGMA_LY_I) * (ec->Ly_i >> DEFAULT_SIGMA_LY_I);
Py_i >>= 15;
} else {
Py_i = (1 << 15);
}
#if 0
/* Vary rate of adaptation depending on position in the file
* Do not do this for the first (DEFAULT_UPDATE_TIME) secs after speech
* has begun of the file to allow the echo cancellor to estimate the
* channel accurately
* Still needs conversion!
*/
if (ec->start_speech_d != 0 ){
if ( ec->i_d > (DEFAULT_T0 + ec->start_speech_d)*(SAMPLE_FREQ) ){
ec->beta2_d = max_cc_float(MIN_BETA, DEFAULT_BETA1 * exp((-1/DEFAULT_TAU)*((ec->i_d/(float)SAMPLE_FREQ) - DEFAULT_T0 - ec->start_speech_d)));
}
} else {
ec->beta2_d = DEFAULT_BETA1;
}
#endif
/* Fixed point, inverted */
ec->beta2_i = DEFAULT_BETA1_I;
/* Fixed point version, inverted */
two_beta_i = (ec->beta2_i * Py_i) >> 15;
if (!two_beta_i)
two_beta_i++;
/* Update the Suppressed signal power estimate accumulator */
/* ------------------------------------------------------- */
/* Delete the oldest sample from the power estimate accumulator */
ec->Lu_i -= abs(get_cc_s(&ec->u_s, (1 << DEFAULT_SIGMA_LU_I) - 1 )) ;
/* Add the new sample to the power estimate accumulator */
ec->Lu_i += abs(u);
/* Update the Far-end reference signal power estimate accumulator */
/* -------------------------------------------------------------- */
/* eq. (10): update power estimate of the reference */
/* Delete the oldest sample from the power estimate accumulator */
ec->Ly_i -= abs(get_cc_s(&ec->y_s, (1 << DEFAULT_SIGMA_LY_I) - 1)) ;
/* Add the new sample to the power estimate accumulator */
ec->Ly_i += abs(iref);
if (ec->Ly_i < DEFAULT_CUTOFF_I)
ec->Ly_i = DEFAULT_CUTOFF_I;
/* Update the Peak far-end receive signal detected */
/* ----------------------------------------------- */
if (ec->y_tilde_i > ec->max_y_tilde) {
/* New highest y_tilde with full life */
ec->max_y_tilde = ec->y_tilde_i;
ec->max_y_tilde_pos = ec->N_d - 1;
} else if (--ec->max_y_tilde_pos < 0) {
/* Time to find new max y tilde... */
ec->max_y_tilde = MAX16(ec->y_tilde_s.buf_d + ec->y_tilde_s.idx_d, ec->N_d, &ec->max_y_tilde_pos);
}
/* Determine if near end speech was detected in this sample */
/* -------------------------------------------------------- */
if (((ec->s_tilde_i >> (DEFAULT_ALPHA_ST_I - 1)) > ec->max_y_tilde)
&& (ec->max_y_tilde > 0)) {
/* Then start the Hangover counter */
ec->HCNTR_d = DEFAULT_HANGT;
RESTORE_COEFFS;
#ifdef MEC2_STATS_DETAILED
printk(KERN_INFO "Reset near end speech timer with: s_tilde_i %d, stmnt %d, max_y_tilde %d\n", ec->s_tilde_i, (ec->s_tilde_i >> (DEFAULT_ALPHA_ST_I - 1)), ec->max_y_tilde);
#endif
#ifdef MEC2_STATS
++ec->cntr_nearend_speech_frames;
#endif
} else if (ec->HCNTR_d > (int)0) {
/* otherwise, if it's still non-zero, decrement the Hangover counter by one sample */
#ifdef MEC2_STATS
++ec->cntr_nearend_speech_frames;
#endif
ec->HCNTR_d--;
}
/* Update coefficients if no near-end speech in this sample (ie. HCNTR_d = 0)
* and we have enough signal to bother trying to update.
* --------------------------------------------------------------------------
*/
if (!ec->HCNTR_d && /* no near-end speech present */
!(ec->i_d % DEFAULT_M)) { /* we only update on every DEFAULM_M'th sample from the stream */
if (ec->Lu_i > MIN_UPDATE_THRESH_I) { /* there is sufficient energy above the noise floor to contain meaningful data */
/* so loop over all the filter coefficients */
#ifdef USED_COEFFS
int max_coeffs[USED_COEFFS];
int *pos;
if (ec->N_d > USED_COEFFS)
memset(max_coeffs, 0, USED_COEFFS*sizeof(int));
#endif
#ifdef MEC2_STATS_DETAILED
printk( KERN_INFO "updating coefficients with: ec->Lu_i %9d\n", ec->Lu_i);
#endif
#ifdef MEC2_STATS
ec->avg_Lu_i_ok = ec->avg_Lu_i_ok + ec->Lu_i;
++ec->cntr_coeff_updates;
#endif
for (k=0; k < ec->N_d; k++) {
/* eq. (7): compute an expectation over M_d samples */
int grad2;
grad2 = CONVOLVE2(ec->u_s.buf_d + ec->u_s.idx_d,
ec->y_s.buf_d + ec->y_s.idx_d + k,
DEFAULT_M);
/* eq. (7): update the coefficient */
ec->a_i[k] += grad2 / two_beta_i;
ec->a_s[k] = ec->a_i[k] >> 16;
#ifdef USED_COEFFS
if (ec->N_d > USED_COEFFS) {
if (abs(ec->a_i[k]) > max_coeffs[USED_COEFFS-1]) {
/* More or less insertion-sort... */
pos = max_coeffs;
while (*pos > abs(ec->a_i[k]))
pos++;
if (*pos > max_coeffs[USED_COEFFS-1])
memmove(pos+1, pos, (USED_COEFFS-(pos-max_coeffs)-1)*sizeof(int));
*pos = abs(ec->a_i[k]);
}
}
#endif
}
#ifdef USED_COEFFS
/* Filter out irrelevant coefficients */
if (ec->N_d > USED_COEFFS)
for (k=0; k < ec->N_d; k++)
if (abs(ec->a_i[k]) < max_coeffs[USED_COEFFS-1])
ec->a_i[k] = ec->a_s[k] = 0;
#endif
} else {
#ifdef MEC2_STATS_DETAILED
printk( KERN_INFO "insufficient signal to update coefficients ec->Lu_i %5d < %5d\n", ec->Lu_i, MIN_UPDATE_THRESH_I);
#endif
#ifdef MEC2_STATS
ec->avg_Lu_i_toolow = ec->avg_Lu_i_toolow + ec->Lu_i;
++ec->cntr_coeff_missedupdates;
#endif
}
}
/* paragraph below eq. (15): if no near-end speech in the sample and
* the reference signal power estimate > cutoff threshold
* then perform residual error suppression
*/
#ifdef MEC2_STATS_DETAILED
if (ec->HCNTR_d == 0)
printk( KERN_INFO "possibily correcting frame with ec->Ly_i %9d ec->Lu_i %9d and expression %d\n", ec->Ly_i, ec->Lu_i, (ec->Ly_i/(ec->Lu_i + 1)));
#endif
#ifndef NO_ECHO_SUPPRESSOR
#ifdef AGGRESSIVE_SUPPRESSOR
if ((ec->HCNTR_d < AGGRESSIVE_HCNTR) && (ec->Ly_i > (ec->Lu_i << 1))) {
for (k=0; k < RESIDUAL_SUPRESSION_PASSES; k++) {
u = u * (ec->Lu_i >> DEFAULT_SIGMA_LU_I) / ((ec->Ly_i >> (DEFAULT_SIGMA_LY_I)) + 1);
}
#ifdef MEC2_STATS_DETAILED
printk( KERN_INFO "aggresively correcting frame with ec->Ly_i %9d ec->Lu_i %9d expression %d\n", ec->Ly_i, ec->Lu_i, (ec->Ly_i/(ec->Lu_i + 1)));
#endif
#ifdef MEC2_STATS
++ec->cntr_residualcorrected_frames;
#endif
}
#else
if (ec->HCNTR_d == 0) {
if ((ec->Ly_i/(ec->Lu_i + 1)) > DEFAULT_SUPPR_I) {
for (k=0; k < RESIDUAL_SUPRESSION_PASSES; k++) {
u = u * (ec->Lu_i >> DEFAULT_SIGMA_LU_I) / ((ec->Ly_i >> (DEFAULT_SIGMA_LY_I + 2)) + 1);
}
#ifdef MEC2_STATS_DETAILED
printk( KERN_INFO "correcting frame with ec->Ly_i %9d ec->Lu_i %9d expression %d\n", ec->Ly_i, ec->Lu_i, (ec->Ly_i/(ec->Lu_i + 1)));
#endif
#ifdef MEC2_STATS
++ec->cntr_residualcorrected_frames;
#endif
}
#ifdef MEC2_STATS
else {
++ec->cntr_residualcorrected_framesskipped;
}
#endif
}
#endif
#endif
#if 0
/* This will generate a non-linear supression factor, once converted */
if ((ec->HCNTR_d == 0) &&
((ec->Lu_d/ec->Ly_d) < DEFAULT_SUPPR) &&
(ec->Lu_d/ec->Ly_d > EC_MIN_DB_VALUE)) {
suppr_factor = (10 / (float)(SUPPR_FLOOR - SUPPR_CEIL)) * log(ec->Lu_d/ec->Ly_d)
- SUPPR_CEIL / (float)(SUPPR_FLOOR - SUPPR_CEIL);
u_suppr = pow(10.0, (suppr_factor) * RES_SUPR_FACTOR / 10.0) * u_suppr;
}
#endif
#ifdef MEC2_STATS
/* Periodically dump performance stats */
if ((ec->i_d % MEC2_STATS) == 0) {
/* make sure to avoid div0's! */
if (ec->cntr_coeff_missedupdates > 0)
ec->avg_Lu_i_toolow = (int)(ec->avg_Lu_i_toolow / ec->cntr_coeff_missedupdates);
else
ec->avg_Lu_i_toolow = -1;
if (ec->cntr_coeff_updates > 0)
ec->avg_Lu_i_ok = (ec->avg_Lu_i_ok / ec->cntr_coeff_updates);
else
ec->avg_Lu_i_ok = -1;
printk( KERN_INFO "%d: Near end speech: %5d Residuals corrected/skipped: %5d/%5d Coefficients updated ok/low sig: %3d/%3d Lu_i avg ok/low sig %6d/%5d\n",
ec->id,
ec->cntr_nearend_speech_frames,
ec->cntr_residualcorrected_frames, ec->cntr_residualcorrected_framesskipped,
ec->cntr_coeff_updates, ec->cntr_coeff_missedupdates,
ec->avg_Lu_i_ok, ec->avg_Lu_i_toolow);
ec->cntr_nearend_speech_frames = 0;
ec->cntr_residualcorrected_frames = 0;
ec->cntr_residualcorrected_framesskipped = 0;
ec->cntr_coeff_updates = 0;
ec->cntr_coeff_missedupdates = 0;
ec->avg_Lu_i_ok = 0;
ec->avg_Lu_i_toolow = 0;
}
#endif
/* Increment the sample index and return the corrected sample */
ec->i_d++;
return u;
}
static inline struct echo_can_state *echo_can_create(int len, int adaption_mode)
{
struct echo_can_state *ec;
int maxy;
int maxu;
maxy = len + DEFAULT_M;
maxu = DEFAULT_M;
if (maxy < (1 << DEFAULT_ALPHA_YT_I))
maxy = (1 << DEFAULT_ALPHA_YT_I);
if (maxy < (1 << DEFAULT_SIGMA_LY_I))
maxy = (1 << DEFAULT_SIGMA_LY_I);
if (maxu < (1 << DEFAULT_SIGMA_LU_I))
maxu = (1 << DEFAULT_SIGMA_LU_I);
ec = (struct echo_can_state *)MALLOC(sizeof(struct echo_can_state) +
4 + /* align */
sizeof(int) * len + /* a_i */
sizeof(short) * len + /* a_s */
sizeof(int) * len + /* b_i */
sizeof(int) * len + /* c_i */
2 * sizeof(short) * (maxy) + /* y_s */
2 * sizeof(short) * (1 << DEFAULT_ALPHA_ST_I) + /* s_s */
2 * sizeof(short) * (maxu) + /* u_s */
2 * sizeof(short) * len); /* y_tilde_s */
if (ec) {
memset(ec, 0, sizeof(struct echo_can_state) +
4 + /* align */
sizeof(int) * len + /* a_i */
sizeof(short) * len + /* a_s */
sizeof(int) * len + /* b_i */
sizeof(int) * len + /* c_i */
2 * sizeof(short) * (maxy) + /* y_s */
2 * sizeof(short) * (1 << DEFAULT_ALPHA_ST_I) + /* s_s */
2 * sizeof(short) * (maxu) + /* u_s */
2 * sizeof(short) * len); /* y_tilde_s */
init_cc(ec, len, maxy, maxu);
}
return ec;
}
static inline int echo_can_traintap(struct echo_can_state *ec, int pos, short val)
{
/* Set the hangover counter to the length of the can to
* avoid adjustments occuring immediately after initial forced training
*/
ec->HCNTR_d = ec->N_d << 1;
if (pos >= ec->N_d) {
memcpy(ec->b_i,ec->a_i,ec->N_d*sizeof(int));
memcpy(ec->c_i,ec->a_i,ec->N_d*sizeof(int));
return 1;
}
ec->a_i[pos] = val << 17;
ec->a_s[pos] = val << 1;
if (++pos >= ec->N_d) {
memcpy(ec->b_i,ec->a_i,ec->N_d*sizeof(int));
memcpy(ec->c_i,ec->a_i,ec->N_d*sizeof(int));
return 1;
}
return 0;
}
#endif

View File

@ -0,0 +1,97 @@
/*
Important constants for tuning mg2 echo can
*/
#ifndef _MG2_CONST_H
#define _MG2_CONST_H
/* Convergence (aka. adaptation) speed -- higher means slower */
#define DEFAULT_BETA1_I 2048
/* Constants for various power computations */
#define DEFAULT_SIGMA_LY_I 7
#define DEFAULT_SIGMA_LU_I 7
#define DEFAULT_ALPHA_ST_I 5 /* near-end speech detection sensitivity factor */
#define DEFAULT_ALPHA_YT_I 5
#define DEFAULT_CUTOFF_I 128
/* Define the near-end speech hangover counter: if near-end speech
* is declared, hcntr is set equal to hangt (see pg. 432)
*/
#define DEFAULT_HANGT 600 /* in samples, so 600 samples = 75ms */
/* define the residual error suppression threshold */
#define DEFAULT_SUPPR_I 16 /* 16 = -24db */
/* This is the minimum reference signal power estimate level
* that will result in filter adaptation.
* If this is too low then background noise will cause the filter
* coefficients to constantly be updated.
*/
#define MIN_UPDATE_THRESH_I 4096
/* The number of samples used to update coefficients using the
* the block update method (M). It should be related back to the
* length of the echo can.
* ie. it only updates coefficients when (sample number MOD default_m) = 0
*
* Getting this wrong may cause an oops. Consider yourself warned!
*/
#define DEFAULT_M 16 /* every 16th sample */
/* If AGGRESSIVE supression is enabled, then we start cancelling residual
* echos again even while there is potentially the very end of a near-side
* signal present.
* This defines how many samples of DEFAULT_HANGT can remain before we
* kick back in
*/
#define AGGRESSIVE_HCNTR 160 /* in samples, so 160 samples = 20ms */
/* This knob controls the number of passes the residual echo supression
* algorithm makes.
*/
#ifdef AGGRESSIVE_SUPPRESSOR
#define RESIDUAL_SUPRESSION_PASSES 2
#else
#define RESIDUAL_SUPRESSION_PASSES 1
#endif
/* Treat sample as error if it has a different sign as the
* input signal and is this number larger in ABS() as
* the input-signal */
#define MAX_SIGN_ERROR 3000
/* Number of coefficients really used for calculating the
* simulated echo. The value specifies how many of the
* biggest coefficients are used for calculating rs.
* This helps on long echo-tails by artificially limiting
* the number of coefficients for the calculation and
* preventing overflows.
* Comment this to deactivate the code */
#define USED_COEFFS 64
/* Backup coefficients every this number of samples */
#define BACKUP 256
/***************************************************************/
/* The following knobs are not implemented in the current code */
/* we need a dynamic level of suppression varying with the ratio of the
power of the echo to the power of the reference signal this is
done so that we have a smoother background.
we have a higher suppression when the power ratio is closer to
suppr_ceil and reduces logarithmically as we approach suppr_floor.
*/
#define SUPPR_FLOOR -64
#define SUPPR_CEIL -24
/* in a second departure, we calculate the residual error suppression
* as a percentage of the reference signal energy level. The threshold
* is defined in terms of dB below the reference signal.
*/
#define RES_SUPR_FACTOR -20
#endif /* _MG2_CONST_H */

View File

@ -0,0 +1,546 @@
/* $Id$
*
* Audio support data for ISDN4Linux.
*
* Copyright Andreas Eversberg (jolly@eversberg.eu)
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#include "layer1.h"
#include "helper.h"
#include "debug.h"
#include "dsp.h"
#define DATA_S sample_silence
#define SIZE_S &sizeof_silence
#define DATA_GA sample_german_all
#define SIZE_GA &sizeof_german_all
#define DATA_GO sample_german_old
#define SIZE_GO &sizeof_german_old
#define DATA_DT sample_american_dialtone
#define SIZE_DT &sizeof_american_dialtone
#define DATA_RI sample_american_ringing
#define SIZE_RI &sizeof_american_ringing
#define DATA_BU sample_american_busy
#define SIZE_BU &sizeof_american_busy
#define DATA_S1 sample_special1
#define SIZE_S1 &sizeof_special1
#define DATA_S2 sample_special2
#define SIZE_S2 &sizeof_special2
#define DATA_S3 sample_special3
#define SIZE_S3 &sizeof_special3
/***************/
/* tones loops */
/***************/
/* all tones are alaw encoded */
/* the last sample+1 is in phase with the first sample. the error is low */
static u8 sample_german_all[]= {
0x80,0xab,0x81,0x6d,0xfd,0xdd,0x5d,0x9d,
0x4d,0xd1,0x89,0x88,0xd0,0x4c,0x9c,0x5c,
0xdc,0xfc,0x6c,
0x80,0xab,0x81,0x6d,0xfd,0xdd,0x5d,0x9d,
0x4d,0xd1,0x89,0x88,0xd0,0x4c,0x9c,0x5c,
0xdc,0xfc,0x6c,
0x80,0xab,0x81,0x6d,0xfd,0xdd,0x5d,0x9d,
0x4d,0xd1,0x89,0x88,0xd0,0x4c,0x9c,0x5c,
0xdc,0xfc,0x6c,
0x80,0xab,0x81,0x6d,0xfd,0xdd,0x5d,0x9d,
0x4d,0xd1,0x89,0x88,0xd0,0x4c,0x9c,0x5c,
0xdc,0xfc,0x6c,
};
static u32 sizeof_german_all = sizeof(sample_german_all);
static u8 sample_german_old[]= {
0xec,0x68,0xe1,0x6d,0x6d,0x91,0x51,0xed,
0x6d,0x01,0x1e,0x10,0x0c,0x90,0x60,0x70,
0x8c,
0xec,0x68,0xe1,0x6d,0x6d,0x91,0x51,0xed,
0x6d,0x01,0x1e,0x10,0x0c,0x90,0x60,0x70,
0x8c,
0xec,0x68,0xe1,0x6d,0x6d,0x91,0x51,0xed,
0x6d,0x01,0x1e,0x10,0x0c,0x90,0x60,0x70,
0x8c,
0xec,0x68,0xe1,0x6d,0x6d,0x91,0x51,0xed,
0x6d,0x01,0x1e,0x10,0x0c,0x90,0x60,0x70,
0x8c,
};
static u32 sizeof_german_old = sizeof(sample_german_old);
static u8 sample_american_dialtone[]= {
0x2a,0x18,0x90,0x6c,0x4c,0xbc,0x4c,0x6c,
0x10,0x58,0x32,0xb9,0x31,0x2d,0x8d,0x0d,
0x8d,0x2d,0x31,0x99,0x0f,0x28,0x60,0xf0,
0xd0,0x50,0xd0,0x30,0x60,0x08,0x8e,0x67,
0x09,0x19,0x21,0xe1,0xd9,0xb9,0x29,0x67,
0x83,0x02,0xce,0xbe,0xee,0x1a,0x1b,0xef,
0xbf,0xcf,0x03,0x82,0x66,0x28,0xb8,0xd8,
0xe0,0x20,0x18,0x08,0x66,0x8f,0x09,0x61,
0x31,0xd1,0x51,0xd1,0xf1,0x61,0x29,0x0e,
0x98,0x30,0x2c,0x8c,0x0c,0x8c,0x2c,0x30,
0xb8,0x33,0x59,0x11,0x6d,0x4d,0xbd,0x4d,
0x6d,0x91,0x19,
};
static u32 sizeof_american_dialtone = sizeof(sample_american_dialtone);
static u8 sample_american_ringing[]= {
0x2a,0xe0,0xac,0x0c,0xbc,0x4c,0x8c,0x90,
0x48,0xc7,0xc1,0xed,0xcd,0x4d,0xcd,0xed,
0xc1,0xb7,0x08,0x30,0xec,0xcc,0xcc,0x8c,
0x10,0x58,0x1a,0x99,0x71,0xed,0x8d,0x8d,
0x2d,0x41,0x89,0x9e,0x20,0x70,0x2c,0xec,
0x2c,0x70,0x20,0x86,0x77,0xe1,0x31,0x11,
0xd1,0xf1,0x81,0x09,0xa3,0x56,0x58,0x00,
0x40,0xc0,0x60,0x38,0x46,0x43,0x57,0x39,
0xd9,0x59,0x99,0xc9,0x77,0x2f,0x2e,0xc6,
0xd6,0x28,0xd6,0x36,0x26,0x2e,0x8a,0xa3,
0x43,0x63,0x4b,0x4a,0x62,0x42,0xa2,0x8b,
0x2f,0x27,0x37,0xd7,0x29,0xd7,0xc7,0x2f,
0x2e,0x76,0xc8,0x98,0x58,0xd8,0x38,0x56,
0x42,0x47,0x39,0x61,0xc1,0x41,0x01,0x59,
0x57,0xa2,0x08,0x80,0xf0,0xd0,0x10,0x30,
0xe0,0x76,0x87,0x21,0x71,0x2d,0xed,0x2d,
0x71,0x21,0x9f,0x88,0x40,0x2c,0x8c,0x8c,
0xec,0x70,0x98,0x1b,0x59,0x11,0x8d,0xcd,
0xcd,0xed,0x31,0x09,0xb6,0xc0,0xec,0xcc,
0x4c,0xcc,0xec,0xc0,0xc6,0x49,0x91,0x8d,
0x4d,0xbd,0x0d,0xad,0xe1,
};
static u32 sizeof_american_ringing = sizeof(sample_american_ringing);
static u8 sample_american_busy[]= {
0x2a,0x00,0x6c,0x4c,0x4c,0x6c,0xb0,0x66,
0x99,0x11,0x6d,0x8d,0x2d,0x41,0xd7,0x96,
0x60,0xf0,0x70,0x40,0x58,0xf6,0x53,0x57,
0x09,0x89,0xd7,0x5f,0xe3,0x2a,0xe3,0x5f,
0xd7,0x89,0x09,0x57,0x53,0xf6,0x58,0x40,
0x70,0xf0,0x60,0x96,0xd7,0x41,0x2d,0x8d,
0x6d,0x11,0x99,0x66,0xb0,0x6c,0x4c,0x4c,
0x6c,0x00,0x2a,0x01,0x6d,0x4d,0x4d,0x6d,
0xb1,0x67,0x98,0x10,0x6c,0x8c,0x2c,0x40,
0xd6,0x97,0x61,0xf1,0x71,0x41,0x59,0xf7,
0x52,0x56,0x08,0x88,0xd6,0x5e,0xe2,0x2a,
0xe2,0x5e,0xd6,0x88,0x08,0x56,0x52,0xf7,
0x59,0x41,0x71,0xf1,0x61,0x97,0xd6,0x40,
0x2c,0x8c,0x6c,0x10,0x98,0x67,0xb1,0x6d,
0x4d,0x4d,0x6d,0x01,
};
static u32 sizeof_american_busy = sizeof(sample_american_busy);
static u8 sample_special1[]= {
0x2a,0x2c,0xbc,0x6c,0xd6,0x71,0xbd,0x0d,
0xd9,0x80,0xcc,0x4c,0x40,0x39,0x0d,0xbd,
0x11,0x86,0xec,0xbc,0xec,0x0e,0x51,0xbd,
0x8d,0x89,0x30,0x4c,0xcc,0xe0,0xe1,0xcd,
0x4d,0x31,0x88,0x8c,0xbc,0x50,0x0f,0xed,
0xbd,0xed,0x87,0x10,0xbc,0x0c,0x38,0x41,
0x4d,0xcd,0x81,0xd8,0x0c,0xbc,0x70,0xd7,
0x6d,0xbd,0x2d,
};
static u32 sizeof_special1 = sizeof(sample_special1);
static u8 sample_special2[]= {
0x2a,0xcc,0x8c,0xd7,0x4d,0x2d,0x18,0xbc,
0x10,0xc1,0xbd,0xc1,0x10,0xbc,0x18,0x2d,
0x4d,0xd7,0x8c,0xcc,0x2a,0xcd,0x8d,0xd6,
0x4c,0x2c,0x19,0xbd,0x11,0xc0,0xbc,0xc0,
0x11,0xbd,0x19,0x2c,0x4c,0xd6,0x8d,0xcd,
0x2a,0xcc,0x8c,0xd7,0x4d,0x2d,0x18,0xbc,
0x10,0xc1,0xbd,0xc1,0x10,0xbc,0x18,0x2d,
0x4d,0xd7,0x8c,0xcc,0x2a,0xcd,0x8d,0xd6,
0x4c,0x2c,0x19,0xbd,0x11,0xc0,0xbc,0xc0,
0x11,0xbd,0x19,0x2c,0x4c,0xd6,0x8d,0xcd,
};
static u32 sizeof_special2 = sizeof(sample_special2);
static u8 sample_special3[]= {
0x2a,0xbc,0x18,0xcd,0x11,0x2c,0x8c,0xc1,
0x4d,0xd6,0xbc,0xd6,0x4d,0xc1,0x8c,0x2c,
0x11,0xcd,0x18,0xbc,0x2a,0xbd,0x19,0xcc,
0x10,0x2d,0x8d,0xc0,0x4c,0xd7,0xbd,0xd7,
0x4c,0xc0,0x8d,0x2d,0x10,0xcc,0x19,0xbd,
0x2a,0xbc,0x18,0xcd,0x11,0x2c,0x8c,0xc1,
0x4d,0xd6,0xbc,0xd6,0x4d,0xc1,0x8c,0x2c,
0x11,0xcd,0x18,0xbc,0x2a,0xbd,0x19,0xcc,
0x10,0x2d,0x8d,0xc0,0x4c,0xd7,0xbd,0xd7,
0x4c,0xc0,0x8d,0x2d,0x10,0xcc,0x19,0xbd,
};
static u32 sizeof_special3 = sizeof(sample_special3);
static u8 sample_silence[]= {
0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,
0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,
0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,
0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,
0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,
0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,
0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,
0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,
0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,
0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,
0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,
0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,
};
static u32 sizeof_silence = sizeof(sample_silence);
struct tones_samples {
u32 *len;
u8 *data;
};
static struct
tones_samples samples[] = {
{&sizeof_german_all, sample_german_all},
{&sizeof_german_old, sample_german_old},
{&sizeof_american_dialtone, sample_american_dialtone},
{&sizeof_american_ringing, sample_american_ringing},
{&sizeof_american_busy, sample_american_busy},
{&sizeof_special1, sample_special1},
{&sizeof_special2, sample_special2},
{&sizeof_special3, sample_special3},
{NULL, NULL},
};
/***********************************
* generate ulaw from alaw samples *
***********************************/
void
dsp_audio_generate_ulaw_samples(void)
{
int i,j;
i = 0;
while(samples[i].len) {
j = 0;
while(j < (*samples[i].len)) {
samples[i].data[j] =
dsp_audio_alaw_to_ulaw[samples[i].data[j]];
j++;
}
i++;
}
}
/****************************
* tone sequence definition *
****************************/
struct pattern {
int tone;
u8 *data[10];
u32 *siz[10];
u32 seq[10];
} pattern[] = {
{TONE_GERMAN_DIALTONE,
{DATA_GA,0,0,0,0,0,0,0,0,0},
{SIZE_GA,0,0,0,0,0,0,0,0,0},
{1900,0,0,0,0,0,0,0,0,0}},
{TONE_GERMAN_OLDDIALTONE,
{DATA_GO,0,0,0,0,0,0,0,0,0},
{SIZE_GO,0,0,0,0,0,0,0,0,0},
{1998,0,0,0,0,0,0,0,0,0}},
{TONE_AMERICAN_DIALTONE,
{DATA_DT,0,0,0,0,0,0,0,0,0},
{SIZE_DT,0,0,0,0,0,0,0,0,0},
{8000,0,0,0,0,0,0,0,0,0}},
{TONE_GERMAN_DIALPBX,
{DATA_GA,DATA_S,DATA_GA,DATA_S,DATA_GA,DATA_S,0,0,0,0},
{SIZE_GA,SIZE_S,SIZE_GA,SIZE_S,SIZE_GA,SIZE_S,0,0,0,0},
{2000,2000,2000,2000,2000,12000,0,0,0,0}},
{TONE_GERMAN_OLDDIALPBX,
{DATA_GO,DATA_S,DATA_GO,DATA_S,DATA_GO,DATA_S,0,0,0,0},
{SIZE_GO,SIZE_S,SIZE_GO,SIZE_S,SIZE_GO,SIZE_S,0,0,0,0},
{2000,2000,2000,2000,2000,12000,0,0,0,0}},
{TONE_AMERICAN_DIALPBX,
{DATA_DT,DATA_S,DATA_DT,DATA_S,DATA_DT,DATA_S,0,0,0,0},
{SIZE_DT,SIZE_S,SIZE_DT,SIZE_S,SIZE_DT,SIZE_S,0,0,0,0},
{2000,2000,2000,2000,2000,12000,0,0,0,0}},
{TONE_GERMAN_RINGING,
{DATA_GA,DATA_S,0,0,0,0,0,0,0,0},
{SIZE_GA,SIZE_S,0,0,0,0,0,0,0,0},
{8000,32000,0,0,0,0,0,0,0,0}},
{TONE_GERMAN_OLDRINGING,
{DATA_GO,DATA_S,0,0,0,0,0,0,0,0},
{SIZE_GO,SIZE_S,0,0,0,0,0,0,0,0},
{8000,40000,0,0,0,0,0,0,0,0}},
{TONE_AMERICAN_RINGING,
{DATA_RI,DATA_S,0,0,0,0,0,0,0,0},
{SIZE_RI,SIZE_S,0,0,0,0,0,0,0,0},
{8000,32000,0,0,0,0,0,0,0,0}},
{TONE_GERMAN_RINGPBX,
{DATA_GA,DATA_S,DATA_GA,DATA_S,0,0,0,0,0,0},
{SIZE_GA,SIZE_S,SIZE_GA,SIZE_S,0,0,0,0,0,0},
{4000,4000,4000,28000,0,0,0,0,0,0}},
{TONE_GERMAN_OLDRINGPBX,
{DATA_GO,DATA_S,DATA_GO,DATA_S,0,0,0,0,0,0},
{SIZE_GO,SIZE_S,SIZE_GO,SIZE_S,0,0,0,0,0,0},
{4000,4000,4000,28000,0,0,0,0,0,0}},
{TONE_AMERICAN_RINGPBX,
{DATA_RI,DATA_S,DATA_RI,DATA_S,0,0,0,0,0,0},
{SIZE_RI,SIZE_S,SIZE_RI,SIZE_S,0,0,0,0,0,0},
{4000,4000,4000,28000,0,0,0,0,0,0}},
{TONE_GERMAN_BUSY,
{DATA_GA,DATA_S,0,0,0,0,0,0,0,0},
{SIZE_GA,SIZE_S,0,0,0,0,0,0,0,0},
{4000,4000,0,0,0,0,0,0,0,0}},
{TONE_GERMAN_OLDBUSY,
{DATA_GO,DATA_S,0,0,0,0,0,0,0,0},
{SIZE_GO,SIZE_S,0,0,0,0,0,0,0,0},
{1000,5000,0,0,0,0,0,0,0,0}},
{TONE_AMERICAN_BUSY,
{DATA_BU,DATA_S,0,0,0,0,0,0,0,0},
{SIZE_BU,SIZE_S,0,0,0,0,0,0,0,0},
{4000,4000,0,0,0,0,0,0,0,0}},
{TONE_GERMAN_HANGUP,
{DATA_GA,DATA_S,0,0,0,0,0,0,0,0},
{SIZE_GA,SIZE_S,0,0,0,0,0,0,0,0},
{4000,4000,0,0,0,0,0,0,0,0}},
{TONE_GERMAN_OLDHANGUP,
{DATA_GO,DATA_S,0,0,0,0,0,0,0,0},
{SIZE_GO,SIZE_S,0,0,0,0,0,0,0,0},
{1000,5000,0,0,0,0,0,0,0,0}},
{TONE_AMERICAN_HANGUP,
{DATA_DT,0,0,0,0,0,0,0,0,0},
{SIZE_DT,0,0,0,0,0,0,0,0,0},
{8000,0,0,0,0,0,0,0,0,0}},
{TONE_SPECIAL_INFO,
{DATA_S1,DATA_S2,DATA_S3,DATA_S,0,0,0,0,0,0},
{SIZE_S1,SIZE_S2,SIZE_S3,SIZE_S,0,0,0,0,0,0},
{2666,2666,2666,8002,0,0,0,0,0,0}},
{TONE_GERMAN_GASSENBESETZT,
{DATA_GA,DATA_S,0,0,0,0,0,0,0,0},
{SIZE_GA,SIZE_S,0,0,0,0,0,0,0,0},
{2000,2000,0,0,0,0,0,0,0,0}},
{TONE_GERMAN_AUFSCHALTTON,
{DATA_GO,DATA_S,DATA_GO,DATA_S,0,0,0,0,0,0},
{SIZE_GO,SIZE_S,SIZE_GO,SIZE_S,0,0,0,0,0,0},
{1000,5000,1000,17000,0,0,0,0,0,0}},
{0,
{0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0}},
};
/******************
* copy tone data *
******************/
/* an sk_buff is generated from the number of samples needed.
* the count will be changed and may begin from 0 each pattern period.
* the clue is to precalculate the pointers and legths to use only one
* memcpy per function call, or two memcpy if the tone sequence changes.
*
* pattern - the type of the pattern
* count - the sample from the beginning of the pattern (phase)
* len - the number of bytes
*
* return - the sk_buff with the sample
*
* if tones has finished (e.g. knocking tone), dsp->tones is turned off
*/
void dsp_tone_copy(dsp_t *dsp, u8 *data, int len)
{
int index, count, start, num;
struct pattern *pat;
tone_t *tone = &dsp->tone;
/* if we have no tone, we copy silence */
if (!tone->tone) {
memset(data, dsp_silence, len);
return;
}
/* process pattern */
pat = (struct pattern *)tone->pattern; /* points to the current pattern */
index = tone->index; /* gives current sequence index */
count = tone->count; /* gives current sample */
/* copy sample */
while(len) {
/* find sample to start with */
while(42) {
/* warp arround */
if (!pat->seq[index]) {
count = 0;
index = 0;
}
/* check if we are currently playing this tone */
if (count < pat->seq[index]) {
break;
}
if (dsp_debug & DEBUG_DSP_TONE)
printk(KERN_DEBUG "%s: reaching next sequence (index=%d)\n", __FUNCTION__, index);
count -= pat->seq[index];
index++;
}
/* calculate start and number of samples */
start = count % (*(pat->siz[index]));
num = len;
if (num+count > pat->seq[index])
num = pat->seq[index] - count;
if (num+start > (*(pat->siz[index])))
num = (*(pat->siz[index])) - start;
/* copy memory */
memcpy(data, pat->data[index]+start, num);
/* reduce length */
data += num;
count += num;
len -= num;
}
tone->index = index;
tone->count = count;
/* return sk_buff */
return;
}
/*******************************
* send HW message to hfc card *
*******************************/
static void
dsp_tone_hw_message(dsp_t *dsp, u8 *sample, int len)
{
struct sk_buff *nskb;
nskb = create_link_skb(PH_CONTROL | REQUEST, (len)?HW_SPL_LOOP_ON:HW_SPL_LOOP_OFF, len, sample, 0);
if (!nskb) {
printk(KERN_ERR "%s: No mem for skb.\n", __FUNCTION__);
return;
}
/* unlocking is not required, because we don't expect a response */
if (mISDN_queue_down(&dsp->inst, 0, nskb))
dev_kfree_skb(nskb);
}
/*****************
* timer expires *
*****************/
void
dsp_tone_timeout(void *arg)
{
dsp_t *dsp = arg;
tone_t *tone = &dsp->tone;
struct pattern *pat = (struct pattern *)tone->pattern;
int index = tone->index;
if (!tone->tone)
return;
index++;
if (!pat->seq[index])
index = 0;
tone->index = index;
/* set next tone */
if (pat->data[index] == DATA_S)
dsp_tone_hw_message(dsp, 0, 0);
else
dsp_tone_hw_message(dsp, pat->data[index], *(pat->siz[index]));
/* set timer */
init_timer(&tone->tl);
tone->tl.expires = jiffies + (pat->seq[index] * HZ) / 8000;
add_timer(&tone->tl);
}
/********************
* set/release tone *
********************/
/*
* tones are relaized by streaming or by special loop commands if supported
* by hardware. when hardware is used, the patterns will be controlled by
* timers.
*/
int
dsp_tone(dsp_t *dsp, int tone)
{
struct pattern *pat;
int i;
tone_t *tonet = &dsp->tone;
tonet->software = 0;
tonet->hardware = 0;
/* we turn off the tone */
if (!tone) {
if (dsp->features.hfc_loops)
if (timer_pending(&tonet->tl))
del_timer(&tonet->tl);
if (dsp->features.hfc_loops)
dsp_tone_hw_message(dsp, NULL, 0);
tonet->tone = 0;
return(0);
}
pat = NULL;
i = 0;
while(pattern[i].tone) {
if (pattern[i].tone == tone) {
pat = &pattern[i];
break;
}
i++;
}
if (!pat) {
printk(KERN_WARNING "dsp: given tone 0x%x is invalid\n", tone);
return(-EINVAL);
}
if (dsp_debug & DEBUG_DSP_TONE)
printk(KERN_DEBUG "%s: now starting tone %d (index=%d)\n", __FUNCTION__, tone, 0);
tonet->tone = tone;
tonet->pattern = pat;
tonet->index = 0;
tonet->count = 0;
if (dsp->features.hfc_loops) {
tonet->hardware = 1;
/* set first tone */
dsp_tone_hw_message(dsp, pat->data[0], *(pat->siz[0]));
/* set timer */
if (timer_pending(&tonet->tl))
del_timer(&tonet->tl);
init_timer(&tonet->tl);
tonet->tl.expires = jiffies + (pat->seq[0] * HZ) / 8000;
add_timer(&tonet->tl);
} else {
tonet->software = 1;
}
return(0);
}

View File

@ -16,13 +16,18 @@
/* for layer 1 certification T309 < layer1 T3 (e.g. 4000) */
/* This makes some tests easier and quicker */
#define T309 40000
#define T310 30000
/* T310 can be between 30-120 Seconds. We use 120 Seconds so the user can hear
the inband messages */
#define T310 120000
#define T313 4000
#define T318 4000
#define T319 4000
#define N303 1
#define T_CTRL 180000
#define THOLD 4000
#define TRETRIEVE 4000
/* private TIMER events */
#define CC_T302 0x030201
#define CC_T303 0x030301
@ -36,6 +41,8 @@
#define CC_T318 0x031801
#define CC_T319 0x031901
#define CC_TCTRL 0x031f01
#define CC_THOLD 0x03a001
#define CC_TRETRIEVE 0x03a101
/*
* Message-Types
*/
@ -47,6 +54,12 @@
#define MT_PROGRESS 0x03
#define MT_SETUP 0x05
#define MT_SETUP_ACKNOWLEDGE 0x0d
#define MT_HOLD 0x24
#define MT_HOLD_ACKNOWLEDGE 0x28
#define MT_HOLD_REJECT 0x30
#define MT_RETRIEVE 0x31
#define MT_RETRIEVE_ACKNOWLEDGE 0x33
#define MT_RETRIEVE_REJECT 0x37
#define MT_RESUME 0x26
#define MT_RESUME_ACKNOWLEDGE 0x2e
#define MT_RESUME_REJECT 0x22
@ -96,6 +109,7 @@
#define IE_CALLED_PN 0x70
#define IE_CALLED_SUB 0x71
#define IE_REDIR_NR 0x74
#define IE_REDIR_DN 0x76
#define IE_TRANS_SEL 0x78
#define IE_RESTART_IND 0x79
#define IE_LLC 0x7c
@ -106,6 +120,7 @@
#define IE_MORE_DATA 0xa0
#define IE_COMPLETE 0xa1
#define IE_CONGESTION 0xb0
#define IE_COMPR_REQ 0x01
#define IE_REPEAT 0xd0
#define IE_MANDATORY 0x0100
@ -137,6 +152,16 @@
#define NO_CAUSE 254
#define AUX_IDLE 0
#define AUX_HOLD_REQ 1
#define AUX_CALL_HELD 2
#define AUX_RETRIEVE_REQ 3
#define AUX_HOLD_IND 4
#define AUX_RETRIEVE_IND 5
#define VALID_HOLD_STATES_PTMP (SBIT(3) | SBIT(4) | SBIT(10))
#define VALID_HOLD_STATES_PTP (SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10))
#else /* only l3dss1_process */
/* l3dss1 specific data in l3 process */

View File

@ -15,8 +15,8 @@
*
*/
#include <linux/config.h>
#include <linux/module.h>
#include "core.h"
#include "layer1.h"
#include "helper.h"
#include "debug.h"
@ -24,9 +24,8 @@
#define DTMF_NPOINTS 205 /* Number of samples for DTMF recognition */
typedef struct _dtmf {
struct _dtmf *prev;
struct _dtmf *next;
int Flags;
struct list_head list;
u_long Flags;
int debug;
char last;
int idx;
@ -37,7 +36,7 @@ typedef struct _dtmf {
#define FLG_DTMF_ULAW 1
#define FLG_DTMF_ACTIV 2
static int debug = 0;
static u_int debug = 0;
#define DEBUG_DTMF_MGR 0x001
#define DEBUG_DTMF_TONE 0x010
@ -351,7 +350,7 @@ isdn_audio_goertzel(dtmf_t *dtmf)
if (dtmf->debug & DEBUG_DTMF_TONE)
printk(KERN_DEBUG "DTMF: tone='%c'\n", what);
k = what | DTMF_TONE_VAL;
if_link(&dtmf->inst.up, PH_CONTROL | INDICATION,
mISDN_queue_data(&dtmf->inst, FLG_MSG_UP, PH_CONTROL | INDICATION,
0, sizeof(int), &k, 0);
}
dtmf->last = what;
@ -398,24 +397,20 @@ dtmf_reset(dtmf_t *dtmf)
dtmf->idx = 0;
}
#ifdef OBSOLETE
static int
dtmf_from_up(mISDNif_t *hif, struct sk_buff *skb)
dtmf_from_up(mISDNinstance_t *inst, struct sk_buff *skb)
{
dtmf_t *dtmf;
mISDN_head_t *hh;
int *data;
int err = 0;
if (!hif || !hif->fdata || !skb)
return(-EINVAL);
dtmf = hif->fdata;
if (!dtmf->inst.down.func) {
return(-ENXIO);
}
dtmf = inst->privat;
hh = mISDN_HEAD_P(skb);
switch(hh->prim) {
case (PH_CONTROL | REQUEST):
if (skb->len >= sizeof(int)) {
if ((hh->dinfo == 0) && (skb->len >= sizeof(int))) {
data = (int *)skb->data;
if (dtmf->debug & DEBUG_DTMF_CTRL)
printk(KERN_DEBUG "DTMF: PH_CONTROL REQ data %04x\n",
@ -423,34 +418,30 @@ dtmf_from_up(mISDNif_t *hif, struct sk_buff *skb)
if (*data == DTMF_TONE_START) {
test_and_set_bit(FLG_DTMF_ACTIV, &dtmf->Flags);
dtmf_reset(dtmf);
break;
} else if (*data == DTMF_TONE_STOP) {
test_and_clear_bit(FLG_DTMF_ACTIV, &dtmf->Flags);
dtmf_reset(dtmf);
}
break;
} else
printk(KERN_ERR "dtmf_from_up: skb too shoort %d\n",
skb->len);
}
}
/* Fall trough in case of not handled function */
default:
return(dtmf->inst.down.func(&dtmf->inst.down, skb));
return(mISDN_queue_down(inst, 0, skb));
}
if (!err)
dev_kfree_skb(skb);
return(err);
}
#endif
static int
dtmf_from_down(mISDNif_t *hif, struct sk_buff *skb)
dtmf_function(mISDNinstance_t *inst, struct sk_buff *skb)
{
dtmf_t *dtmf;
mISDN_head_t *hh;
if (!hif || !hif->fdata || !skb)
return(-EINVAL);
dtmf = hif->fdata;
if (!dtmf->inst.up.func) {
return(-ENXIO);
}
dtmf = inst->privat;
hh = mISDN_HEAD_P(skb);
switch(hh->prim) {
case (PH_DATA | CONFIRM):
@ -462,6 +453,25 @@ dtmf_from_down(mISDNif_t *hif, struct sk_buff *skb)
isdn_audio_calc_dtmf(dtmf, skb);
hh->prim = DL_DATA_IND;
break;
case (PH_CONTROL | REQUEST):
if ((hh->dinfo == 0) && (skb->len >= sizeof(int))) {
int *data = (int *)skb->data;
if (dtmf->debug & DEBUG_DTMF_CTRL)
printk(KERN_DEBUG "DTMF: PH_CONTROL REQ data %04x\n",
*data);
if (*data == DTMF_TONE_START) {
test_and_set_bit(FLG_DTMF_ACTIV, &dtmf->Flags);
dtmf_reset(dtmf);
dev_kfree_skb(skb);
return(0);
} else if (*data == DTMF_TONE_STOP) {
test_and_clear_bit(FLG_DTMF_ACTIV, &dtmf->Flags);
dtmf_reset(dtmf);
dev_kfree_skb(skb);
return(0);
}
}
break;
case (PH_ACTIVATE | CONFIRM):
hh->prim = DL_ESTABLISH | CONFIRM;
break;
@ -475,23 +485,18 @@ dtmf_from_down(mISDNif_t *hif, struct sk_buff *skb)
hh->prim = DL_RELEASE | INDICATION;
break;
}
return(dtmf->inst.up.func(&dtmf->inst.up, skb));
return(mISDN_queue_message(inst, hh->addr & MSG_DIR_MASK, skb));
}
static void
release_dtmf(dtmf_t *dtmf) {
mISDNinstance_t *inst = &dtmf->inst;
u_long flags;
if (inst->up.peer) {
inst->up.peer->obj->ctrl(inst->up.peer,
MGR_DISCONNECT | REQUEST, &inst->up);
}
if (inst->down.peer) {
inst->down.peer->obj->ctrl(inst->down.peer,
MGR_DISCONNECT | REQUEST, &inst->down);
}
REMOVE_FROM_LISTBASE(dtmf, ((dtmf_t *)dtmf_obj.ilist));
dtmf_obj.ctrl(inst, MGR_UNREGLAYER | REQUEST, NULL);
spin_lock_irqsave(&dtmf_obj.lock, flags);
list_del(&dtmf->list);
spin_unlock_irqrestore(&dtmf_obj.lock, flags);
mISDN_ctrl(inst, MGR_UNREGLAYER | REQUEST, NULL);
kfree(dtmf);
}
@ -499,6 +504,7 @@ static int
new_dtmf(mISDNstack_t *st, mISDN_pid_t *pid) {
dtmf_t *n_dtmf;
int err;
u_long flags;
if (!st || !pid)
return(-EINVAL);
@ -508,19 +514,19 @@ new_dtmf(mISDNstack_t *st, mISDN_pid_t *pid) {
}
memset(n_dtmf, 0, sizeof(dtmf_t));
memcpy(&n_dtmf->inst.pid, pid, sizeof(mISDN_pid_t));
n_dtmf->inst.obj = &dtmf_obj;
n_dtmf->inst.data = n_dtmf;
if (!SetHandledPID(&dtmf_obj, &n_dtmf->inst.pid)) {
mISDN_init_instance(&n_dtmf->inst, &dtmf_obj, n_dtmf, dtmf_function);
if (!mISDN_SetHandledPID(&dtmf_obj, &n_dtmf->inst.pid)) {
int_error();
kfree(n_dtmf);
return(-ENOPROTOOPT);
}
n_dtmf->debug = debug;
n_dtmf->inst.up.owner = &n_dtmf->inst;
n_dtmf->inst.down.owner = &n_dtmf->inst;
APPEND_TO_LIST(n_dtmf, ((dtmf_t *)dtmf_obj.ilist));
err = dtmf_obj.ctrl(st, MGR_REGLAYER | INDICATION, &n_dtmf->inst);
spin_lock_irqsave(&dtmf_obj.lock, flags);
list_add_tail(&n_dtmf->list, &dtmf_obj.ilist);
spin_unlock_irqrestore(&dtmf_obj.lock, flags);
err = mISDN_ctrl(st, MGR_REGLAYER | INDICATION, &n_dtmf->inst);
if (err) {
REMOVE_FROM_LISTBASE(n_dtmf, ((dtmf_t *)dtmf_obj.ilist));
list_del(&n_dtmf->list);
kfree(n_dtmf);
}
return(err);
@ -553,7 +559,12 @@ static char MName[] = "DTMF";
#ifdef MODULE
MODULE_AUTHOR("Karsten Keil");
#ifdef OLD_MODULE_PARAM
MODULE_PARM(debug, "1i");
#else
module_param (debug, uint, S_IRUGO | S_IWUSR);
#endif
MODULE_PARM_DESC (debug, "dtmf debug mask");
#ifdef MODULE_LICENSE
MODULE_LICENSE("GPL");
#endif
@ -562,54 +573,50 @@ MODULE_LICENSE("GPL");
static int
dtmf_manager(void *data, u_int prim, void *arg) {
mISDNinstance_t *inst = data;
dtmf_t *dtmf_l = dtmf_obj.ilist;
dtmf_t *dtmf_l;
int ret = -EINVAL;
u_long flags;
if (debug & DEBUG_DTMF_MGR)
printk(KERN_DEBUG "dtmf_manager data:%p prim:%x arg:%p\n", data, prim, arg);
if (!data)
return(-EINVAL);
while(dtmf_l) {
if (&dtmf_l->inst == inst)
return(ret);
spin_lock_irqsave(&dtmf_obj.lock, flags);
list_for_each_entry(dtmf_l, &dtmf_obj.ilist, list) {
if (&dtmf_l->inst == inst) {
ret = 0;
break;
dtmf_l = dtmf_l->next;
}
}
spin_unlock_irqrestore(&dtmf_obj.lock, flags);
if (prim == (MGR_NEWLAYER | REQUEST))
return(new_dtmf(data, arg));
if (ret) {
printk(KERN_WARNING "dtmf_manager prim(%x) no instance\n", prim);
return(ret);
}
switch(prim) {
case MGR_NEWLAYER | REQUEST:
return(new_dtmf(data, arg));
case MGR_CLRSTPARA | INDICATION:
break;
#ifdef OBSOLETE
case MGR_CLONELAYER | REQUEST:
break;
case MGR_CONNECT | REQUEST:
if (!dtmf_l) {
printk(KERN_WARNING "dtmf_manager connect no instance\n");
return(-EINVAL);
}
return(ConnectIF(inst, arg));
return(mISDN_ConnectIF(inst, arg));
case MGR_SETIF | REQUEST:
case MGR_SETIF | INDICATION:
if (!dtmf_l) {
printk(KERN_WARNING "dtmf_manager setif no instance\n");
return(-EINVAL);
}
return(SetIF(inst, arg, prim, dtmf_from_up, dtmf_from_down, dtmf_l));
return(mISDN_SetIF(inst, arg, prim, dtmf_from_up, dtmf_from_down, dtmf_l));
case MGR_DISCONNECT | REQUEST:
case MGR_DISCONNECT | INDICATION:
if (!dtmf_l) {
printk(KERN_WARNING "dtmf_manager disconnect no instance\n");
return(-EINVAL);
}
return(DisConnectIF(inst, arg));
return(mISDN_DisConnectIF(inst, arg));
#endif
case MGR_UNREGLAYER | REQUEST:
case MGR_RELEASE | INDICATION:
if (dtmf_l) {
if (debug & DEBUG_DTMF_MGR)
printk(KERN_DEBUG "release_dtmf id %x\n", dtmf_l->inst.st->id);
release_dtmf(dtmf_l);
} else
printk(KERN_WARNING "dtmf_manager release no instance\n");
break;
// case MGR_STATUS | REQUEST:
// if (!dtmf_l) {
// printk(KERN_WARNING "dtmf_manager status dtmf no instance\n");
// return(-EINVAL);
// }
// return(dtmf_status(dtmf_l, arg));
default:
if (debug & DEBUG_DTMF_MGR)
@ -624,30 +631,35 @@ static int dtmf_init(void)
int err;
printk(KERN_INFO "DTMF modul version %s\n", mISDN_getrev(mISDN_dtmf_revision));
SET_MODULE_OWNER(&dtmf_obj);
#ifdef MODULE
dtmf_obj.owner = THIS_MODULE;
#endif
dtmf_obj.name = MName;
dtmf_obj.BPROTO.protocol[2] = ISDN_PID_L2_B_TRANSDTMF;
dtmf_obj.own_ctrl = dtmf_manager;
dtmf_obj.prev = NULL;
dtmf_obj.next = NULL;
dtmf_obj.ilist = NULL;
spin_lock_init(&dtmf_obj.lock);
INIT_LIST_HEAD(&dtmf_obj.ilist);
if ((err = mISDN_register(&dtmf_obj))) {
printk(KERN_ERR "Can't register %s error(%d)\n", MName, err);
}
} else
mISDN_module_register(THIS_MODULE);
return(err);
}
static void dtmf_cleanup(void)
{
int err;
dtmf_t *dtmf, *nd;
mISDN_module_unregister(THIS_MODULE);
if ((err = mISDN_unregister(&dtmf_obj))) {
printk(KERN_ERR "Can't unregister DTMF error(%d)\n", err);
}
if(dtmf_obj.ilist) {
if (!list_empty(&dtmf_obj.ilist)) {
printk(KERN_WARNING "dtmf inst list not empty\n");
while(dtmf_obj.ilist)
release_dtmf(dtmf_obj.ilist);
list_for_each_entry_safe(dtmf, nd, &dtmf_obj.ilist, list)
release_dtmf(dtmf);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -8,15 +8,20 @@
* This file is (c) under GNU PUBLIC LICENSE
*
*/
#define __NO_VERSION__
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/isdn_compat.h>
#ifdef NEED_JIFFIES_INCLUDE
#include <linux/jiffies.h>
#endif
#include <linux/string.h>
#include "fsm.h"
#define FSM_TIMER_DEBUG 0
void
FsmNew(struct Fsm *fsm,
mISDN_FsmNew(struct Fsm *fsm,
struct FsmNode *fnlist, int fncount)
{
int i;
@ -27,7 +32,7 @@ FsmNew(struct Fsm *fsm,
for (i = 0; i < fncount; i++)
if ((fnlist[i].state>=fsm->state_count) || (fnlist[i].event>=fsm->event_count)) {
printk(KERN_ERR "FsmNew Error line %d st(%ld/%ld) ev(%ld/%ld)\n",
printk(KERN_ERR "mISDN_FsmNew Error line %d st(%ld/%ld) ev(%ld/%ld)\n",
i,(long)fnlist[i].state,(long)fsm->state_count,
(long)fnlist[i].event,(long)fsm->event_count);
} else
@ -36,18 +41,18 @@ FsmNew(struct Fsm *fsm,
}
void
FsmFree(struct Fsm *fsm)
mISDN_FsmFree(struct Fsm *fsm)
{
kfree((void *) fsm->jumpmatrix);
}
int
FsmEvent(struct FsmInst *fi, int event, void *arg)
mISDN_FsmEvent(struct FsmInst *fi, int event, void *arg)
{
FSMFNPTR r;
if ((fi->state>=fi->fsm->state_count) || (event >= fi->fsm->event_count)) {
printk(KERN_ERR "FsmEvent Error st(%ld/%ld) ev(%d/%ld)\n",
printk(KERN_ERR "mISDN_FsmEvent Error st(%ld/%ld) ev(%d/%ld)\n",
(long)fi->state,(long)fi->fsm->state_count,event,(long)fi->fsm->event_count);
return(1);
}
@ -69,7 +74,7 @@ FsmEvent(struct FsmInst *fi, int event, void *arg)
}
void
FsmChangeState(struct FsmInst *fi, int newstate)
mISDN_FsmChangeState(struct FsmInst *fi, int newstate)
{
fi->state = newstate;
if (fi->debug)
@ -84,46 +89,48 @@ FsmExpireTimer(struct FsmTimer *ft)
if (ft->fi->debug)
ft->fi->printdebug(ft->fi, "FsmExpireTimer %lx", (long) ft);
#endif
FsmEvent(ft->fi, ft->event, ft->arg);
mISDN_FsmEvent(ft->fi, ft->event, ft->arg);
}
void
FsmInitTimer(struct FsmInst *fi, struct FsmTimer *ft)
mISDN_FsmInitTimer(struct FsmInst *fi, struct FsmTimer *ft)
{
ft->fi = fi;
ft->tl.function = (void *) FsmExpireTimer;
ft->tl.data = (long) ft;
#if FSM_TIMER_DEBUG
if (ft->fi->debug)
ft->fi->printdebug(ft->fi, "FsmInitTimer %lx", (long) ft);
ft->fi->printdebug(ft->fi, "mISDN_FsmInitTimer %lx", (long) ft);
#endif
init_timer(&ft->tl);
}
void
FsmDelTimer(struct FsmTimer *ft, int where)
mISDN_FsmDelTimer(struct FsmTimer *ft, int where)
{
#if FSM_TIMER_DEBUG
if (ft->fi->debug)
ft->fi->printdebug(ft->fi, "FsmDelTimer %lx %d", (long) ft, where);
ft->fi->printdebug(ft->fi, "mISDN_FsmDelTimer %lx %d", (long) ft, where);
#endif
del_timer(&ft->tl);
}
int
FsmAddTimer(struct FsmTimer *ft,
mISDN_FsmAddTimer(struct FsmTimer *ft,
int millisec, int event, void *arg, int where)
{
#if FSM_TIMER_DEBUG
if (ft->fi->debug)
ft->fi->printdebug(ft->fi, "FsmAddTimer %lx %d %d",
ft->fi->printdebug(ft->fi, "mISDN_FsmAddTimer %lx %d %d",
(long) ft, millisec, where);
#endif
if (timer_pending(&ft->tl)) {
printk(KERN_WARNING "FsmAddTimer: timer already active!\n");
ft->fi->printdebug(ft->fi, "FsmAddTimer already active!");
if (ft->fi->debug) {
printk(KERN_WARNING "mISDN_FsmAddTimer: timer already active!\n");
ft->fi->printdebug(ft->fi, "mISDN_FsmAddTimer already active!");
}
return -1;
}
init_timer(&ft->tl);
@ -135,13 +142,13 @@ FsmAddTimer(struct FsmTimer *ft,
}
void
FsmRestartTimer(struct FsmTimer *ft,
mISDN_FsmRestartTimer(struct FsmTimer *ft,
int millisec, int event, void *arg, int where)
{
#if FSM_TIMER_DEBUG
if (ft->fi->debug)
ft->fi->printdebug(ft->fi, "FsmRestartTimer %lx %d %d",
ft->fi->printdebug(ft->fi, "mISDN_FsmRestartTimer %lx %d %d",
(long) ft, millisec, where);
#endif
@ -153,3 +160,12 @@ FsmRestartTimer(struct FsmTimer *ft,
ft->tl.expires = jiffies + (millisec * HZ) / 1000;
add_timer(&ft->tl);
}
EXPORT_SYMBOL(mISDN_FsmNew);
EXPORT_SYMBOL(mISDN_FsmFree);
EXPORT_SYMBOL(mISDN_FsmEvent);
EXPORT_SYMBOL(mISDN_FsmChangeState);
EXPORT_SYMBOL(mISDN_FsmInitTimer);
EXPORT_SYMBOL(mISDN_FsmAddTimer);
EXPORT_SYMBOL(mISDN_FsmRestartTimer);
EXPORT_SYMBOL(mISDN_FsmDelTimer);

View File

@ -4,6 +4,9 @@
*
*/
#ifndef _MISDN_FSM_H
#define _MISDN_FSM_H
#include <linux/timer.h>
/* Statemachine */
@ -39,11 +42,13 @@ struct FsmTimer {
void *arg;
};
extern void FsmNew(struct Fsm *, struct FsmNode *, int);
extern void FsmFree(struct Fsm *);
extern int FsmEvent(struct FsmInst *, int , void *);
extern void FsmChangeState(struct FsmInst *, int);
extern void FsmInitTimer(struct FsmInst *, struct FsmTimer *);
extern int FsmAddTimer(struct FsmTimer *, int, int, void *, int);
extern void FsmRestartTimer(struct FsmTimer *, int, int, void *, int);
extern void FsmDelTimer(struct FsmTimer *, int);
extern void mISDN_FsmNew(struct Fsm *, struct FsmNode *, int);
extern void mISDN_FsmFree(struct Fsm *);
extern int mISDN_FsmEvent(struct FsmInst *, int , void *);
extern void mISDN_FsmChangeState(struct FsmInst *, int);
extern void mISDN_FsmInitTimer(struct FsmInst *, struct FsmTimer *);
extern int mISDN_FsmAddTimer(struct FsmTimer *, int, int, void *, int);
extern void mISDN_FsmRestartTimer(struct FsmTimer *, int, int, void *, int);
extern void mISDN_FsmDelTimer(struct FsmTimer *, int);
#endif

View File

@ -6,7 +6,7 @@
*
*/
#define __NO_VERSION__
#include <linux/module.h>
#include <linux/mISDNif.h>
#include "helper.h"
@ -14,7 +14,7 @@
#undef DEBUG_IF
void
set_dchannel_pid(mISDN_pid_t *pid, int protocol, int layermask)
mISDN_set_dchannel_pid(mISDN_pid_t *pid, int protocol, int layermask)
{
if (!layermask)
layermask = ISDN_LAYER(0)| ISDN_LAYER(1) | ISDN_LAYER(2) |
@ -26,36 +26,78 @@ set_dchannel_pid(mISDN_pid_t *pid, int protocol, int layermask)
pid->protocol[0] = ISDN_PID_L0_TE_S0;
if (layermask & ISDN_LAYER(1))
pid->protocol[1] = ISDN_PID_L1_TE_S0;
if (layermask & ISDN_LAYER(2))
if (layermask & ISDN_LAYER(2)) {
pid->protocol[2] = ISDN_PID_L2_LAPD;
if (protocol & 0x20)
pid->protocol[2] |= ISDN_PID_L2_DF_PTP;
}
if (layermask & ISDN_LAYER(3)) {
if (protocol == 2)
if ((protocol & 0xf) == 2)
pid->protocol[3] = ISDN_PID_L3_DSS1USER;
if (protocol & 0x20)
pid->protocol[3] |= ISDN_PID_L3_DF_PTP;
}
if (layermask & ISDN_LAYER(4))
pid->protocol[4] = ISDN_PID_L4_CAPI20;
}
int
bprotocol2pid(void *bp, mISDN_pid_t *pid)
mISDN_add_pid_parameter(mISDN_pid_t *pid, int layer, u_char *para)
{
__u8 *p = bp;
__u16 *w = bp;
int i;
u16 l;
if (para == NULL || *para == 0) {
pid->param[layer] = 0;
return 0;
}
l = 1 + *para; /* including length itself */
if (!pid->pbuf) {
pid->maxplen = l + 1; /* pbuf[0] is never used */
if (l < 63)
pid->maxplen = 64;
pid->pbuf = kzalloc(pid->maxplen, GFP_ATOMIC);
pid->pidx = 1;
if (!pid->pbuf) {
pid->maxplen = 0;
return -ENOMEM;
}
} else if ((pid->pidx + l) > pid->maxplen) {
u_char *tbuf;
tbuf = kmalloc(pid->pidx + l, GFP_ATOMIC);
if (!tbuf)
return -ENOMEM;
memcpy(tbuf, pid->pbuf, pid->pidx);
kfree(pid->pbuf);
pid->pbuf = tbuf;
pid->maxplen = pid->pidx + l;
}
pid->param[layer] = pid->pidx;
memcpy(&pid->pbuf[pid->pidx], para, l);
pid->pidx += l;
return 0;
}
int
mISDN_bprotocol2pid(void *bp, mISDN_pid_t *pid)
{
u8 *p = bp;
u16 *w = bp;
int i, ret;
p += 6;
for (i=1; i<=3; i++) {
if (*w > 23) {
int_errtxt("L%d pid %x\n",i,*w);
return(-EINVAL);
return -EINVAL;
}
pid->protocol[i] = (1 <<*w) | ISDN_PID_LAYER(i) |
ISDN_PID_BCHANNEL_BIT;
if (*p)
pid->param[i] = p;
else
pid->param[i] = NULL;
ret = mISDN_add_pid_parameter(pid, i, p);
if (ret)
return ret;
w++;
p += *p;
p++;
@ -63,17 +105,17 @@ bprotocol2pid(void *bp, mISDN_pid_t *pid)
pid->global = 0;
if (*p == 2) { // len of 1 word
p++;
w = (__u16 *)p;
w = (u16 *)p;
pid->global = *w;
}
return(0);
return 0;
}
int
HasProtocol(mISDNobject_t *obj, int protocol)
mISDN_HasProtocol(mISDNobject_t *obj, u_int protocol)
{
int layer;
int pmask;
u_int pmask;
if (!obj) {
int_error();
@ -97,7 +139,7 @@ HasProtocol(mISDNobject_t *obj, int protocol)
}
int
SetHandledPID(mISDNobject_t *obj, mISDN_pid_t *pid)
mISDN_SetHandledPID(mISDNobject_t *obj, mISDN_pid_t *pid)
{
int layer;
int ret = 0;
@ -112,6 +154,9 @@ SetHandledPID(mISDNobject_t *obj, mISDN_pid_t *pid)
#endif
memcpy(&sav, pid, sizeof(mISDN_pid_t));
memset(pid, 0, sizeof(mISDN_pid_t));
pid->pbuf = sav.pbuf;
pid->maxplen = sav.maxplen;
pid->pidx = sav.pidx;
pid->global = sav.global;
if (!sav.layermask) {
printk(KERN_WARNING "%s: no layermask in pid\n", __FUNCTION__);
@ -124,7 +169,7 @@ SetHandledPID(mISDNobject_t *obj, mISDN_pid_t *pid)
else
continue;
}
if (0 == HasProtocol(obj, sav.protocol[layer])) {
if (0 == mISDN_HasProtocol(obj, sav.protocol[layer])) {
ret++;
pid->protocol[layer] = sav.protocol[layer];
pid->param[layer] = sav.param[layer];
@ -136,7 +181,7 @@ SetHandledPID(mISDNobject_t *obj, mISDN_pid_t *pid)
}
void
RemoveUsedPID(mISDN_pid_t *pid, mISDN_pid_t *used)
mISDN_RemoveUsedPID(mISDN_pid_t *pid, mISDN_pid_t *used)
{
int layer;
@ -151,13 +196,13 @@ RemoveUsedPID(mISDN_pid_t *pid, mISDN_pid_t *used)
if (!(ISDN_LAYER(layer) & used->layermask))
continue;
pid->protocol[layer] = ISDN_PID_NONE;
pid->param[layer] = NULL;
pid->param[layer] = 0;
pid->layermask &= ~(ISDN_LAYER(layer));
}
}
int
layermask2layer(int layermask) {
mISDN_layermask2layer(int layermask) {
switch(layermask) {
case ISDN_LAYER(0): return(0);
case ISDN_LAYER(1): return(1);
@ -173,7 +218,7 @@ layermask2layer(int layermask) {
}
int
get_protocol(mISDNstack_t *st, int layer)
mISDN_get_protocol(mISDNstack_t *st, int layer)
{
if (!st){
@ -188,7 +233,7 @@ get_protocol(mISDNstack_t *st, int layer)
}
int
get_lowlayer(int layermask)
mISDN_get_lowlayer(int layermask)
{
int layer;
@ -201,7 +246,7 @@ get_lowlayer(int layermask)
}
int
get_down_layer(int layermask)
mISDN_get_down_layer(int layermask)
{
int downlayer = 1;
@ -218,7 +263,8 @@ get_down_layer(int layermask)
return(downlayer);
}
int get_up_layer(int layermask) {
int
mISDN_get_up_layer(int layermask) {
int uplayer = MAX_LAYER_NR;
if (layermask>=128) {
@ -234,8 +280,9 @@ int get_up_layer(int layermask) {
return(uplayer);
}
#ifdef OBSOLETE
int
SetIF(mISDNinstance_t *owner, mISDNif_t *hif, u_int prim, void *upfunc,
mISDN_SetIF(mISDNinstance_t *owner, mISDNif_t *hif, u_int prim, void *upfunc,
void *downfunc, void *data)
{
mISDNif_t *own_hif;
@ -284,7 +331,7 @@ SetIF(mISDNinstance_t *owner, mISDNif_t *hif, u_int prim, void *upfunc,
}
int
ConnectIF(mISDNinstance_t *owner, mISDNinstance_t *peer)
mISDN_ConnectIF(mISDNinstance_t *owner, mISDNinstance_t *peer)
{
mISDNif_t *hif;
@ -312,12 +359,13 @@ ConnectIF(mISDNinstance_t *owner, mISDNinstance_t *peer)
return(peer->obj->own_ctrl(peer, MGR_SETIF | REQUEST, hif));
}
int DisConnectIF(mISDNinstance_t *inst, mISDNif_t *hif) {
int
mISDN_DisConnectIF(mISDNinstance_t *inst, mISDNif_t *hif) {
if (hif) {
if (hif->next && hif->next->owner) {
hif->next->owner->obj->ctrl(hif->next->owner,
MGR_DISCONNECT | REQUEST, hif->next);
if (hif->clone) {
if (hif->clone->owner)
hif->clone->owner->obj->ctrl(hif->clone->owner,
MGR_DISCONNECT | REQUEST, hif->clone);
}
if (inst->up.peer) {
if (inst->up.peer == hif->owner)
@ -332,4 +380,33 @@ int DisConnectIF(mISDNinstance_t *inst, mISDNif_t *hif) {
}
return(0);
}
#endif
void
mISDN_init_instance(mISDNinstance_t *inst, mISDNobject_t *obj, void *data, if_func_t *function)
{
if (!obj) {
int_error();
return;
}
INIT_LIST_HEAD(&inst->list);
inst->obj = obj;
inst->privat = data;
inst->function = function;
}
EXPORT_SYMBOL(mISDN_set_dchannel_pid);
EXPORT_SYMBOL(mISDN_get_lowlayer);
EXPORT_SYMBOL(mISDN_get_up_layer);
EXPORT_SYMBOL(mISDN_get_down_layer);
EXPORT_SYMBOL(mISDN_layermask2layer);
EXPORT_SYMBOL(mISDN_get_protocol);
EXPORT_SYMBOL(mISDN_HasProtocol);
EXPORT_SYMBOL(mISDN_SetHandledPID);
EXPORT_SYMBOL(mISDN_RemoveUsedPID);
EXPORT_SYMBOL(mISDN_init_instance);
// EXPORT_SYMBOL(mISDN_SetIF);
// EXPORT_SYMBOL(mISDN_ConnectIF);
// EXPORT_SYMBOL(mISDN_DisConnectIF);
EXPORT_SYMBOL(mISDN_add_pid_parameter);
EXPORT_SYMBOL(mISDN_bprotocol2pid);

View File

@ -2,60 +2,27 @@
*
* Basic declarations, defines and prototypes
*
* This file is (c) under GNU PUBLIC LICENSE
* This file is released under the GPLv2
*
*/
#ifndef _mISDN_HELPER_H
#define _mISDN_HELPER_H
#include <linux/kernel.h>
#ifdef MEMDBG
#ifdef MISDN_MEMDEBUG
#include "memdbg.h"
#endif
/* shortcut to report errors locations, sometime also used for debugging !FIXME! */
#define int_error() \
printk(KERN_ERR "mISDN: INTERNAL ERROR in %s:%d\n", \
__FILE__, __LINE__)
/* shortcut to report errors locations with an additional message text */
#define int_errtxt(fmt, arg...) \
printk(KERN_ERR "mISDN: INTERNAL ERROR in %s:%d " fmt "\n", \
__FILE__, __LINE__, ## arg)
#define APPEND_TO_LIST(item,base) \
if (item->prev || item->next) \
int_errtxt("APPEND not clean %p<-%p->%p", \
item->prev, item, item->next); \
item->next = NULL; \
item->prev = base; \
while (item->prev && item->prev->next) \
item->prev = item->prev->next; \
if (item->prev == item) { \
int_errtxt("APPEND DUP %p", item); \
} else \
if (base) { \
item->prev->next = item; \
} else \
base = item
#define INSERT_INTO_LIST(newi,nexti,base) \
newi->next = nexti; \
newi->prev = nexti->prev; \
if (newi->prev) \
newi->prev->next = newi; \
nexti->prev = newi; \
if (base == nexti) \
base = newi
#define REMOVE_FROM_LIST(item) \
if (item->prev) \
item->prev->next = item->next; \
if (item->next) \
item->next->prev = item->prev
#define REMOVE_FROM_LISTBASE(item,base) \
REMOVE_FROM_LIST(item); \
if (item == base) \
base = item->next
/* cleanup SKB queues, return count of dropped packets */
static inline int
discard_queue(struct sk_buff_head *q)
{
@ -69,39 +36,139 @@ discard_queue(struct sk_buff_head *q)
return(ret);
}
/* allocate a SKB for DATA packets in the mISDN stack with enough headroom
* the MEMDEBUG version is for debugging memory leaks in the mISDN stack
*/
#ifdef MISDN_MEMDEBUG
#define alloc_stack_skb(s, r) __mid_alloc_stack_skb(s, r, __FILE__, __LINE__)
static inline struct sk_buff *
alloc_uplinkD_skb(size_t size)
__mid_alloc_stack_skb(u_int size, u_int reserve, char *fn, int line)
{
struct sk_buff *skb;
if (!(skb = alloc_skb(size + L3_EXTRA_SIZE, GFP_ATOMIC)))
printk(KERN_WARNING "%s(%d): no skb size\n", __FUNCTION__,
size);
if (!(skb = __mid_alloc_skb(size + reserve, GFP_ATOMIC, fn, line)))
#else
static inline struct sk_buff *
alloc_stack_skb(u_int size, u_int reserve)
{
struct sk_buff *skb;
if (!(skb = alloc_skb(size + reserve, GFP_ATOMIC)))
#endif
printk(KERN_WARNING "%s(%d,%d): no skb size\n", __FUNCTION__,
size, reserve);
else
skb_reserve(skb, L3_EXTRA_SIZE);
skb_reserve(skb, reserve);
return(skb);
}
extern void set_dchannel_pid(mISDN_pid_t *, int, int);
extern int get_lowlayer(int);
extern int get_up_layer(int);
extern int get_down_layer(int);
extern int layermask2layer(int);
extern int get_protocol(mISDNstack_t *, int);
extern int HasProtocol(mISDNobject_t *, int);
extern int SetHandledPID(mISDNobject_t *, mISDN_pid_t *);
extern void RemoveUsedPID(mISDN_pid_t *, mISDN_pid_t *);
/*
* mISDN_set_dchannel_pid(mISDN_pid_t *pid, int protocol, int layermask)
*
* set default values for the D-channel protocol ID struct
*
* layermask - bitmask which layers should be set (default 0,1,2,3,4)
* protocol - bitmask for special L2/L3 option (from protocol module parameter of L0 modules)
*/
extern void mISDN_set_dchannel_pid(mISDN_pid_t *, int, int);
static inline int HasProtocolP(mISDNobject_t *obj, int *PP)
/*
* int mISDN_get_lowlayer(int layermask)
*
* get the lowest layer number of a layermask
* e.g layermask=0x0c returns 2
*/
extern int mISDN_get_lowlayer(int);
/*
* int mISDN_get_up_layer(int layermask)
*
* get the next higher layer number, which is not part of the given layermask
*/
extern int mISDN_get_up_layer(int);
/*
* int mISDN_get_down_layer(int layermask)
*
* get the next lower layer number, which is not part of the given layermask
*/
extern int mISDN_get_down_layer(int);
/*
* int mISDN_layermask2layer(int layermask)
*
* translate bit position in layermask into the layernumber
* only valid if only one bit in the mask was set
*/
extern int mISDN_layermask2layer(int);
/*
* int mISDN_get_protocol(mISDNstack_t *st, int layer)
*
* get the protocol value of layer <layer> in stack <st>
*/
extern int mISDN_get_protocol(mISDNstack_t *, int);
/*
* int mISDN_HasProtocol(mISDNobject_t *obj, u_int protocol)
*
* test if given object can handle protocol <protocol>
*
* return 0 if yes
*
*/
extern int mISDN_HasProtocol(mISDNobject_t *, u_int);
/*
* int mISDN_SetHandledPID(mISDNobject_t *obj, mISDN_pid_t *pid)
*
* returns the layermask of the supported protocols of object <obj>
* from the protocol ID struct <pid>
*/
extern int mISDN_SetHandledPID(mISDNobject_t *, mISDN_pid_t *);
/*
* mISDN_RemoveUsedPID(mISDN_pid_t *pid, mISDN_pid_t *used)
*
* remove the protocol values from <pid> struct which are also in the
* <used> struct
*/
extern void mISDN_RemoveUsedPID(mISDN_pid_t *, mISDN_pid_t *);
/*
* mISDN_init_instance(mISDNinstance_t *inst, mISDNobject_t *obj, void *data)
*
* initialisize the mISDNinstance_t struct <inst>
*/
extern void mISDN_init_instance(mISDNinstance_t *, mISDNobject_t *, void *, if_func_t *);
/* returns the member count of a list */
static inline int
count_list_member(struct list_head *head)
{
int cnt = 0;
struct list_head *m;
list_for_each(m, head)
cnt++;
return(cnt);
}
/* same as mISDN_HasProtocol, but for a pointer */
static inline int
mISDN_HasProtocolP(mISDNobject_t *obj, int *PP)
{
if (!PP) {
int_error();
return(-EINVAL);
}
return(HasProtocol(obj, *PP));
return(mISDN_HasProtocol(obj, *PP));
}
extern __inline__ void mISDN_sethead(u_int prim, int dinfo, struct sk_buff *skb)
/* set primitiv and dinfo field of a internal (SKB) mISDN message */
static inline void
mISDN_sethead(u_int prim, int dinfo, struct sk_buff *skb)
{
mISDN_head_t *hh = mISDN_HEAD_P(skb);
@ -109,45 +176,89 @@ extern __inline__ void mISDN_sethead(u_int prim, int dinfo, struct sk_buff *skb)
hh->dinfo = dinfo;
}
extern __inline__ int if_newhead(mISDNif_t *i, u_int prim, int dinfo,
struct sk_buff *skb)
#define mISDN_queue_up(i, a, s) mISDN_queue_message(i, a | FLG_MSG_UP, s)
#define mISDN_queue_down(i, a, s) mISDN_queue_message(i, a | FLG_MSG_DOWN, s)
static inline int
mISDN_queueup_newhead(mISDNinstance_t *inst, u_int aflag, u_int prim, int dinfo, struct sk_buff *skb)
{
if (!i->func || !skb)
return(-ENXIO);
mISDN_sethead(prim, dinfo, skb);
return(i->func(i, skb));
mISDN_head_t *hh = mISDN_HEAD_P(skb);
hh->prim = prim;
hh->dinfo = dinfo;
return(mISDN_queue_up(inst, aflag, skb));
}
static inline int
mISDN_queuedown_newhead(mISDNinstance_t *inst, u_int aflag, u_int prim, int dinfo, struct sk_buff *skb)
{
mISDN_head_t *hh = mISDN_HEAD_P(skb);
hh->prim = prim;
hh->dinfo = dinfo;
return(mISDN_queue_down(inst, aflag, skb));
}
extern __inline__ struct sk_buff *create_link_skb(u_int prim, int dinfo,
int len, void *arg, int reserve)
/* allocate a mISDN message SKB with enough headroom and set the header fields
* the MEMDEBUG version is for debugging memory leaks in the mISDN stack
*/
#ifdef MISDN_MEMDEBUG
#define create_link_skb(p, d, l, dp, r) __mid_create_link_skb(p, d, l, dp, r, __FILE__, __LINE__)
static inline struct sk_buff *
__mid_create_link_skb(u_int prim, int dinfo, u_int len, void *dp, u_int reserve, char *fn, int line)
{
struct sk_buff *skb;
mISDN_head_t *hh;
if (!(skb = __mid_alloc_skb(len + reserve, GFP_ATOMIC, fn, line))) {
#else
static inline struct sk_buff *
create_link_skb(u_int prim, int dinfo, u_int len, void *dp, u_int reserve)
{
struct sk_buff *skb;
mISDN_head_t *hh;
if (!(skb = alloc_skb(len + reserve, GFP_ATOMIC))) {
#endif
printk(KERN_WARNING "%s: no skb size %d+%d\n",
__FUNCTION__, len, reserve);
return(NULL);
} else
skb_reserve(skb, reserve);
if (len)
memcpy(skb_put(skb, len), arg, len);
mISDN_sethead(prim, dinfo, skb);
memcpy(skb_put(skb, len), dp, len);
hh = mISDN_HEAD_P(skb);
hh->prim = prim;
hh->dinfo = dinfo;
hh->len = len;
return(skb);
}
extern __inline__ int if_link(mISDNif_t *i, u_int prim, int dinfo, int len,
void *arg, int reserve)
/* allocate a SKB for a mISDN message with enough headroom
* fill mesage data into this SKB and send it trough the interface
* the MEMDEBUG version is for debugging memory leaks in the mISDN stack
*/
#ifdef MISDN_MEMDEBUG
#define mISDN_queue_data(i, a, p, d, l, dp, r) __mid_queue_data(i, a, p, d, l, dp, r, __FILE__, __LINE__)
static inline int
__mid_queue_data(mISDNinstance_t *inst, u_int aflag, u_int prim, int dinfo, u_int len, void *dp, u_int reserve, char *fn, int line)
{
struct sk_buff *skb;
int err;
if (!(skb = create_link_skb(prim, dinfo, len, arg, reserve)))
if (!(skb = __mid_create_link_skb(prim, dinfo, len, dp, reserve, fn, line)))
#else
static inline int
mISDN_queue_data(mISDNinstance_t *inst, u_int aflag, u_int prim, int dinfo, u_int len, void *dp, u_int reserve)
{
struct sk_buff *skb;
int err;
if (!(skb = create_link_skb(prim, dinfo, len, dp, reserve)))
#endif
return(-ENOMEM);
if (!i)
err = -ENXIO;
else
err = i->func(i, skb);
err = mISDN_queue_message(inst, aflag, skb);
if (err)
kfree_skb(skb);
return(err);
@ -155,12 +266,33 @@ extern __inline__ int if_link(mISDNif_t *i, u_int prim, int dinfo, int len,
/* L3 data struct helper functions */
extern signed int l3_ie2pos(u_char);
extern unsigned char l3_pos2ie(int);
extern void initQ931_info(Q931_info_t *);
extern struct sk_buff *alloc_l3msg(int, u_char);
extern void AddvarIE(struct sk_buff *, u_char *);
extern void AddIE(struct sk_buff *, u_char, u_char *);
extern void LogL3Msg(struct sk_buff *);
extern signed int mISDN_l3_ie2pos(u_char);
extern unsigned char mISDN_l3_pos2ie(int);
extern void mISDN_initQ931_info(Q931_info_t *);
#ifdef MISDN_MEMDEBUG
#define mISDN_alloc_l3msg(a, b) __mid_alloc_l3msg(a, b, __FILE__, __LINE__)
extern struct sk_buff *__mid_alloc_l3msg(int, u_char, char *, int);
#else
extern struct sk_buff *mISDN_alloc_l3msg(int, u_char);
#endif
extern void mISDN_AddvarIE(struct sk_buff *, u_char *);
extern void mISDN_AddIE(struct sk_buff *, u_char, u_char *);
extern ie_info_t *mISDN_get_last_repeated_ie(Q931_info_t *, ie_info_t *);
extern int mISDN_get_free_ext_ie(Q931_info_t *);
extern void mISDN_LogL3Msg(struct sk_buff *);
extern int mISDN_add_pid_parameter(mISDN_pid_t *, int, u_char *);
/* manager default handler helper macros */
#define PRIM_NOT_HANDLED(p) case p: break
#define MGR_HASPROTOCOL_HANDLER(p,a,o) \
if ((MGR_HASPROTOCOL | REQUEST) == p) {\
if (a) {\
int prot = *((int *)a);\
return(mISDN_HasProtocol(o, prot));\
} else \
return(-EINVAL);\
}
#endif /* _mISDN_HELPER_H */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,187 @@
/* $Id$
*
* mISDN driver for Colognechip HFC-S mini Evaluation Card
*
* Authors : Martin Bachem, Joerg Ciesielski
* Contact : info@colognechip.com
*
* 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, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#ifndef __HFCMINI_H__
#define __HFCMINI_H__
#include "channel.h"
#include "hfcsmcc.h"
#define BRIDGE_UNKWOWN 0
#define BRIDGE_HFCPCI 1
/* use HFC-S PCI as PCI Bridge */
#define HFCBRIDGE BRIDGE_HFCPCI
#define SPIN_LOCK_HFCSMINI_REGISTER
#define DRIVER_NAME "HFCMINI"
#define CHIP_ID_HFCSMINI CHIP_ID
#define MAX_CHAN 4 /* D, B1, B2, PCM */
/* flags in _u16 port mode */
#define PORT_UNUSED 0x0000
#define PORT_MODE_NT 0x0001
#define PORT_MODE_TE 0x0002
#define PORT_MODE_BUS_MASTER 0x0004
#define PORT_MODE_UP 0x0008
#define PORT_MODE_EXCH_POL 0x0010
#define PORT_MODE_LOOP 0x0020
#define NT_TIMER 0x8000
/* NT / TE defines */
#define NT_T1_COUNT 12 /* number of 8ms interrupts for G2 timeout */
#define CLK_DLY_TE 0x0e /* CLKDEL in TE mode */
#define CLK_DLY_NT 0x6c /* CLKDEL in NT mode */
#define STA_ACTIVATE 0x60 /* start activation in A_SU_WR_STA */
#define STA_DEACTIVATE 0x40 /* start deactivation in A_SU_WR_STA */
#define LIF_MODE_NT 0x04 /* Line Interface NT mode */
/* HFC-S mini Layer1 physical commands */
#define HFC_L1_ACTIVATE_TE 0x01
#define HFC_L1_FORCE_DEACTIVATE_TE 0x02
#define HFC_L1_ACTIVATE_NT 0x03
#define HFC_L1_DEACTIVATE_NT 0x04
#define HFC_L1_TESTLOOP_B1 0x05
#define HFC_L1_TESTLOOP_B2 0x06
/* FIFO handling support values */
#define FIFO_IRQ_OFF 0
#define FIFO_IRQ_ON 1
#define FIFO_DISABLE 0
#define FIFO_ENABLE 1
#define FIFO_MASK_TX 0x55
#define FIFO_MASK_RX 0xAA
#define HDLC_PAR_BCH 0 /* init value for all B-channel fifos */
#define HDLC_PAR_DCH (M1_BIT_CNT*2) /* same for D- and E-channel */
#define CON_HDLC_B_TRANS (M_HDLC_TRP | M1_TRP_IRQ*2) /* transparent mode B-channel 32 byte threshold */
#define CON_HDLC_B_HDLC (M1_TRP_IRQ*2) /* HDLC mode b-channel */
#define CON_HDLC_D_HDLC (M1_TRP_IRQ*2 | M_IFF) /* HDLC mode D-channel, 1 fill mode */
#define CON_HDLC_B_LOOP (M1_TRP_IRQ*2 | M1_DATA_FLOW*6) /* B-channel loopback mode */
#define HFCSMINI_RX_THRESHOLD 32
#define HFCSMINI_TX_THRESHOLD 96
#define DCH_RX_SIZE 267
#define BCH_RX_SIZE 2051
#define BCH_RX_SIZE_TRANS 64
/* DEBUG flags, use combined value for module parameter debug=x */
#define DEBUG_HFC_INIT 0x0001
#define DEBUG_HFC_MODE 0x0002
#define DEBUG_HFC_S0_STATES 0x0004
#define DEBUG_HFC_IRQ 0x0008
#define DEBUG_HFC_FIFO_ERR 0x0010
#define DEBUG_HFC_DTRACE 0x2000
#define DEBUG_HFC_BTRACE 0x4000 /* very(!) heavy messageslog load */
#define DEBUG_HFC_FIFO 0x8000 /* very(!) heavy messageslog load */
/* private driver_data */
typedef struct {
int chip_id;
char *device_name;
} hfcsmini_param;
struct _hfcmini_hw;
/**********************/
/* hardware structure */
/**********************/
typedef struct _hfcmini_hw {
struct list_head list;
__u32 irq_cnt; /* count irqs */
struct tasklet_struct tasklet; /* interrupt bottom half */
spinlock_t mlock; /* mISDN mq lock */
spinlock_t rlock; /* register access lock */
int cardnum;
__u8 param_idx; /* used to access module param arrays */
__u8 testirq;
int irq;
int iobase;
u_char *membase;
u_char *hw_membase;
struct pci_dev *pdev;
hfcsmini_param driver_data;
char card_name[60];
int max_fifo; /* always 4 fifos per port */
__u8 max_z; /* fifo depth -1 */
channel_t chan[MAX_CHAN]; /* line interfaces */
__u8 fifomask;
/* HFC-S MINI regsister */
reg_r_chip_id chip_id; /* Chip ID */
reg_r_pcm_md0 pcm_md0; /* PCM config */
reg_r_pcm_md1 pcm_md1; /* PCM config */
reg_r_pcm_md2 pcm_md2; /* PCM config */
reg_r_ti ti; /* timer interrupt configuration */
reg_r_fifo_irqmsk fifo_irqmsk; /* FIFO interrupt mask */
reg_r_fifo_irq fifo_irq; /* FIFO interrupt state */
reg_r_misc_irqmsk misc_irqmsk; /* MISC interrupt mask */
reg_r_misc_irq misc_irq; /* MISC interrupt state */
reg_r_st_ctrl0 st_ctrl0;
reg_r_st_ctrl2 st_ctrl2;
int nt_timer;
__u8 dpid; /* DChannel Protocoll ID */
__u16 portmode; /* NT/TE */
} hfcsmini_hw;
/* function prototypes */
int setup_channel(hfcsmini_hw * hw, __u8 channel, int protocol);
void hfcsmini_write_fifo(hfcsmini_hw * hw, __u8 channel);
void hfcsmini_read_fifo(hfcsmini_hw * hw, __u8 channel);
void print_fc(hfcsmini_hw * hw, __u8 fifo);
void setup_fifo(hfcsmini_hw * hw, int fifo, __u8 hdlcreg, __u8 con_reg, __u8 irq_enable, __u8 enable);
void setup_s(hfcsmini_hw * hw, __u8 bc, __u8 enable);
void disable_interrupts(hfcsmini_hw * hw);
void enable_interrupts(hfcsmini_hw * hw);
static void release_card(hfcsmini_hw * hw);
#if HFCBRIDGE == BRIDGE_HFCPCI
int init_pci_bridge(hfcsmini_hw * hw);
#endif
/* HFC-S MINI register access functions */
static inline void hfcsmini_sel_reg(hfcsmini_hw * hw, __u8 reg_addr);
static inline __u8 read_hfcsmini(hfcsmini_hw * hw, __u8 reg_addr);
static inline __u8 read_hfcsmini_irq(hfcsmini_hw * hw, __u8 reg_addr);
static inline __u8 read_hfcsmini_stable(hfcsmini_hw * hw, __u8 reg_addr);
static inline void write_hfcsmini(hfcsmini_hw * hw, __u8 reg_addr, __u8 value);
#endif /* __hfcsmini_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,263 @@
/*
* hfcs_usb.h, HFC-S USB mISDN driver
* $Id$
*
*/
#ifndef __HFCS_USB_H__
#define __HFCS_USB_H__
#define DRIVER_AUTHOR "Martin Bachem / Peter Sprenger"
#define DRIVER_DESC "HFC-S USB based HiSAX ISDN driver"
/* DEBUG flags, use combined value for module parameter debug=x */
#define DEBUG_HFC_INIT 0x0001
#define DEBUG_HFC_MODE 0x0002
#define DEBUG_HFC_S0_STATES 0x0004
#define DEBUG_HFC_IRQ 0x0008
#define DEBUG_HFC_FIFO_ERR 0x0010
#define DEBUG_HFC_DTRACE 0x2000
#define DEBUG_HFC_BTRACE 0x4000 /* very(!) heavy messageslog load */
#define DEBUG_HFC_FIFO 0x8000 /* very(!) heavy messageslog load */
/***********/
/* defines */
/***********/
#define HFC_CTRL_TIMEOUT 20 /* 5ms timeout writing/reading regs */
#define CLKDEL_TE 0x0f /* CLKDEL in TE mode */
#define CLKDEL_NT 0x6c /* CLKDEL in NT mode */
/* hfcsusb Layer1 commands */
#define HFC_L1_ACTIVATE_TE 0x01
#define HFC_L1_ACTIVATE_NT 0x02
#define HFC_L1_DEACTIVATE_NT 0x03
#define HFC_L1_FORCE_DEACTIVATE_TE 0x04
/* cmd FLAGS in HFCUSB_STATES register */
#define HFCUSB_LOAD_STATE 0x10
#define HFCUSB_ACTIVATE 0x20
#define HFCUSB_DO_ACTION 0x40
#define HFCUSB_NT_G2_G3 0x80
/* bits in hw_mode */
#define PORT_MODE_TE 0x01
#define PORT_MODE_NT 0x02
#define NT_ACTIVATION_TIMER 0x04 /* enables NT mode activation Timer */
#define NT_T1_COUNT 10
#define MAX_BCH_SIZE 2048 /* allowed B-channel packet size */
#define HFCUSB_RX_THRESHOLD 64 /* threshold for fifo report bit rx */
#define HFCUSB_TX_THRESHOLD 64 /* threshold for fifo report bit tx */
#define HFCUSB_CHIP_ID 0x16 /* Chip ID register index */
#define HFCUSB_CIRM 0x00 /* cirm register index */
#define HFCUSB_USB_SIZE 0x07 /* int length register */
#define HFCUSB_USB_SIZE_I 0x06 /* iso length register */
#define HFCUSB_F_CROSS 0x0b /* bit order register */
#define HFCUSB_CLKDEL 0x37 /* bit delay register */
#define HFCUSB_CON_HDLC 0xfa /* channel connect register */
#define HFCUSB_HDLC_PAR 0xfb
#define HFCUSB_SCTRL 0x31 /* S-bus control register (tx) */
#define HFCUSB_SCTRL_E 0x32 /* same for E and special funcs */
#define HFCUSB_SCTRL_R 0x33 /* S-bus control register (rx) */
#define HFCUSB_F_THRES 0x0c /* threshold register */
#define HFCUSB_FIFO 0x0f /* fifo select register */
#define HFCUSB_F_USAGE 0x1a /* fifo usage register */
#define HFCUSB_MST_MODE0 0x14
#define HFCUSB_MST_MODE1 0x15
#define HFCUSB_P_DATA 0x1f
#define HFCUSB_INC_RES_F 0x0e
#define HFCUSB_STATES 0x30
#define HFCUSB_CHIPID 0x40 /* ID value of HFC-S USB */
/******************/
/* fifo registers */
/******************/
#define HFCUSB_NUM_FIFOS 8 /* maximum number of fifos */
#define HFCUSB_B1_TX 0 /* index for B1 transmit bulk/int */
#define HFCUSB_B1_RX 1 /* index for B1 receive bulk/int */
#define HFCUSB_B2_TX 2
#define HFCUSB_B2_RX 3
#define HFCUSB_D_TX 4
#define HFCUSB_D_RX 5
#define HFCUSB_PCM_TX 6
#define HFCUSB_PCM_RX 7
/*************/
/* Chan idx */
/*************/
#define B1 0
#define B2 1
#define D 2
#define PCM 3
#define MAX_CHAN 4
/*
* used to switch snd_transfer_mode for different TA modes e.g. the Billion USB TA just
* supports ISO out, while the Cologne Chip EVAL TA just supports BULK out
*/
#define USB_INT 0
#define USB_BULK 1
#define USB_ISOC 2
#define ISOC_PACKETS_D 8
#define ISOC_PACKETS_B 8
#define ISO_BUFFER_SIZE 128
/* defines how much ISO packets are handled in one URB */
static int iso_packets[8] =
{ ISOC_PACKETS_B, ISOC_PACKETS_B, ISOC_PACKETS_B, ISOC_PACKETS_B,
ISOC_PACKETS_D, ISOC_PACKETS_D, ISOC_PACKETS_D, ISOC_PACKETS_D
};
// ISO send definitions
#define SINK_MAX 68
#define SINK_MIN 48
#define SINK_DMIN 12
#define SINK_DMAX 18
#define BITLINE_INF (-64*8)
/**********/
/* macros */
/**********/
#define write_usb(a,b,c)usb_control_msg((a)->dev,(a)->ctrl_out_pipe,0,0x40,(c),(b),0,0,HFC_CTRL_TIMEOUT)
#define read_usb(a,b,c) usb_control_msg((a)->dev,(a)->ctrl_in_pipe,1,0xC0,0,(b),(c),1,HFC_CTRL_TIMEOUT)
/*******************/
/* Debugging Flags */
/*******************/
#define USB_DBG 1
#define ISDN_DBG 2
/* *********************/
/* USB related defines */
/***********************/
#define HFC_CTRL_BUFSIZE 32
/*************************************************/
/* entry and size of output/input control buffer */
/*************************************************/
typedef struct {
__u8 hfcs_reg; /* register number */
__u8 reg_val; /* value to be written (or read) */
} ctrl_buft;
/********************/
/* URB error codes: */
/********************/
/* Used to represent a list of values and their respective symbolic names */
struct hfcusb_symbolic_list {
const int num;
const char *name;
};
static struct hfcusb_symbolic_list urb_errlist[] = {
{-ENOMEM, "No memory for allocation of internal structures"},
{-ENOSPC, "The host controller's bandwidth is already consumed"},
{-ENOENT, "URB was canceled by unlink_urb"},
{-EXDEV, "ISO transfer only partially completed"},
{-EAGAIN, "Too match scheduled for the future"},
{-ENXIO, "URB already queued"},
{-EFBIG, "Too much ISO frames requested"},
{-ENOSR, "Buffer error (overrun)"},
{-EPIPE, "Specified endpoint is stalled (device not responding)"},
{-EOVERFLOW, "Babble (bad cable?)"},
{-EPROTO, "Bit-stuff error (bad cable?)"},
{-EILSEQ, "CRC/Timeout"},
{-ETIMEDOUT, "NAK (device does not respond)"},
{-ESHUTDOWN, "Device unplugged"},
{-1, NULL}
};
static inline const char *
symbolic(struct hfcusb_symbolic_list list[], const int num)
{
int i;
for (i = 0; list[i].name != NULL; i++)
if (list[i].num == num)
return (list[i].name);
return "<unkown>";
}
/*****************************************************/
/* device dependant information to support different */
/* ISDN Ta's using the HFC-S USB chip */
/*****************************************************/
/* USB descriptor need to contain one of the following EndPoint combination: */
#define CNF_4INT3ISO 1 // 4 INT IN, 3 ISO OUT
#define CNF_3INT3ISO 2 // 3 INT IN, 3 ISO OUT
#define CNF_4ISO3ISO 3 // 4 ISO IN, 3 ISO OUT
#define CNF_3ISO3ISO 4 // 3 ISO IN, 3 ISO OUT
#define EP_NUL 1 // Endpoint at this position not allowed
#define EP_NOP 2 // all type of endpoints allowed at this position
#define EP_ISO 3 // Isochron endpoint mandatory at this position
#define EP_BLK 4 // Bulk endpoint mandatory at this position
#define EP_INT 5 // Interrupt endpoint mandatory at this position
/* this array represents all endpoints possible in the HCF-USB the last
* 3 entries are the configuration number, the minimum interval for
* Interrupt endpoints & boolean if E-channel logging possible
*/
int validconf[][19] = {
// INT in, ISO out config
{EP_NUL, EP_INT, EP_NUL, EP_INT, EP_NUL, EP_INT, EP_NOP, EP_INT,
EP_ISO, EP_NUL, EP_ISO, EP_NUL, EP_ISO, EP_NUL, EP_NUL, EP_NUL,
CNF_4INT3ISO, 2, 1},
{EP_NUL, EP_INT, EP_NUL, EP_INT, EP_NUL, EP_INT, EP_NUL, EP_NUL,
EP_ISO, EP_NUL, EP_ISO, EP_NUL, EP_ISO, EP_NUL, EP_NUL, EP_NUL,
CNF_3INT3ISO, 2, 0},
// ISO in, ISO out config
{EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL,
EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_NOP, EP_ISO,
CNF_4ISO3ISO, 2, 1},
{EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL,
EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_NUL, EP_NUL,
CNF_3ISO3ISO, 2, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} // EOL element
};
// string description of chosen config
char *conf_str[] = {
"4 Interrupt IN + 3 Isochron OUT",
"3 Interrupt IN + 3 Isochron OUT",
"4 Isochron IN + 3 Isochron OUT",
"3 Isochron IN + 3 Isochron OUT"
};
#define LED_OFF 0 // no LED support
#define LED_SCHEME1 1 // LED standard scheme
#define LED_SCHEME2 2 // not used yet...
#define LED_POWER_ON 1
#define LED_POWER_OFF 2
#define LED_S0_ON 3
#define LED_S0_OFF 4
#define LED_B1_ON 5
#define LED_B1_OFF 6
#define LED_B1_DATA 7
#define LED_B2_ON 8
#define LED_B2_OFF 9
#define LED_B2_DATA 10
#define LED_NORMAL 0 // LEDs are normal
#define LED_INVERTED 1 // LEDs are inverted
/* time in ms to perform a Flashing LED when B-Channel has traffic */
#define LED_TIME 250
#endif /* __HFCS_USB_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -1,182 +0,0 @@
/* $Id$
*
* hw_lock.h Hardware locking inline routines
*
* Author Karsten Keil (keil@isdn4linux.de)
*
* This file is (c) under GNU PUBLIC LICENSE
*
*/
/* Description of the locking mechanism
*
* The locking must grant serialisized and atomic
* access to the ISDN hardware registers, if the lock
* is aquired no other process or IRQ is alloed to
* access ISDN hardware registers.
*
* In general here are 3 possible entry points:
* 1. the ISDN interrupt routine
* 2. ISDN timer routines in the hardware module
* 3. messages that came from upper layers
*
* Since most work must be do in the interrupt routine
* (to grant minimum IRQ latency) and only few things with
* need direct HW access must be done for messages from upper
* layers, we should allow other IRQs in our IRQ routines and
* only block our own routines in this case. Since the common IRQ
* routines allready mask the same IRQ, we only need to protect us
* from timer and uper layers. The disadvantage is, that we need to
* disable local IRQ for the 2. and 3. points, but since the routines
* which need hardware access are well known and small, the impact
* is very small.
*
* We have a two stage locking to make this working:
* A spinlock which protect the state LOCK Flag (STATE_FLAG_BUSY) and
* also protect us from local IRQs from the entry points 2 and 3.
*
* In the hardware IRQ we aquire the spinlock, set the STATE_FLAG_BUSY
* LOCK Flag and then release the spinlock. It can never happen that
* the STATE_FLAG_BUSY is allready set in this case, see later.
*
* In the other cases (from timer or upper layers) we aquire the spinlock
* test_and_set the STATE_FLAG_BUSY LOCK Flag, if it was allready set
* (a ISDN IRQ is running on the other CPU) we schedule timeout or add a other
* small timeout.
* If it was not set, we have the lock and we don't release the spinlock until we have
* done the harware work.
*
* To avoid any kind of deadlocking, it is important that we release the lock
* before we call functions that deliver to upper layers.
* To leave the impact of disabled local IRQ small, it is important to only protect
* small areas where hardware is accessed.
*
* The following routines handle the lock in the entry point from upper layers and other
* none IRQ cases (module init/exit stuff).
*
* They never called directly, but via the wrappers assigned to the instance
* inst.lock / inst.unlock pointers.
*
* Here are two defines which can be used for DEBUGING and PROFILING
* SPIN_DEBUG and LOCK_STATISTIC
*
*/
#ifndef __hw_lock__
#define __hw_lock__
typedef struct _mISDN_HWlock {
u_long flags;
spinlock_t lock;
#ifdef SPIN_DEBUG
void *spin_adr;
void *busy_adr;
#endif
volatile u_int state;
#ifdef LOCK_STATISTIC
u_int try_ok;
u_int try_wait;
u_int try_inirq;
u_int try_mult;
u_int irq_ok;
u_int irq_fail;
#endif
} mISDN_HWlock_t;
#define STATE_FLAG_BUSY 1
#define STATE_FLAG_INIRQ 2
/*
* returns 0 if the lock was aquired
* returns 1 if nowait != 0 and the lock is not aquired
*/
static inline int lock_HW(mISDN_HWlock_t *lock, int nowait)
{
register u_long flags;
#ifdef LOCK_STATISTIC
int wait = 0;
#endif
spin_lock_irqsave(&lock->lock, flags);
#ifdef SPIN_DEBUG
lock->spin_adr = __builtin_return_address(0);
#endif
while (test_and_set_bit(STATE_FLAG_BUSY, &lock->state)) {
/* allready busy so we delay */
spin_unlock_irqrestore(&lock->lock, flags);
#ifdef SPIN_DEBUG
lock->spin_adr = NULL;
#endif
if (nowait) {
#ifdef LOCK_STATISTIC
lock->try_wait++;
#endif
return(1);
}
/* delay 1 jiffie is enought */
if (in_interrupt()) {
/* Should never happen */
#ifdef LOCK_STATISTIC
lock->try_inirq++;
#endif
printk(KERN_ERR "lock_HW: try to schedule in IRQ state(%x)\n",
lock->state);
mdelay(1);
} else {
#ifdef LOCK_STATISTIC
if (wait++)
lock->try_mult++;
else
lock->try_wait++;
#endif
schedule_timeout(1);
}
spin_lock_irqsave(&lock->lock, flags);
#ifdef SPIN_DEBUG
lock->spin_adr = __builtin_return_address(0);
#endif
}
/* get the LOCK */
lock->flags = flags;
#ifdef SPIN_DEBUG
lock->busy_adr = __builtin_return_address(0);
#endif
#ifdef LOCK_STATISTIC
if (!wait)
lock->try_ok++;
#endif
return(0);
}
static inline void unlock_HW(mISDN_HWlock_t *lock)
{
if (!test_and_clear_bit(STATE_FLAG_BUSY, &lock->state)) {
printk(KERN_ERR "lock_HW: STATE_FLAG_BUSY not locked state(%x)\n",
lock->state);
}
#ifdef SPIN_DEBUG
lock->busy_adr = NULL;
lock->spin_adr = NULL;
#endif
spin_unlock_irqrestore(&lock->lock, lock->flags);
}
static inline void lock_HW_init(mISDN_HWlock_t *lock)
{
spin_lock_init(&lock->lock);
lock->state = 0;
#ifdef SPIN_DEBUG
lock->busy_adr = NULL;
lock->spin_adr = NULL;
#endif
#ifdef LOCK_STATISTIC
lock->try_ok = 0;
lock->try_wait = 0;
lock->try_inirq = 0;
lock->try_mult = 0;
lock->irq_ok = 0;
lock->irq_fail = 0;
#endif
}
#endif

View File

@ -10,7 +10,6 @@
*
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/isdnif.h>
#include <linux/delay.h>
@ -157,7 +156,7 @@ MODULE_AUTHOR("Karsten Keil");
#ifdef MODULE_LICENSE
MODULE_LICENSE("GPL");
#endif
MODULE_PARM(debug, "1i");
module_param(debug, uint, S_IRUGO | S_IWUSR);
#endif
static void
@ -217,7 +216,7 @@ init_channel(i4l_capi_t *ic, int nr)
ch->inst.pid.layermask = ISDN_LAYER(0);
ch->inst.up.owner = &ch->inst;
ch->inst.down.owner = &ch->inst;
I4Lcapi.ctrl(NULL, MGR_DISCONNECT | REQUEST, &ch->inst.down);
mISDN_ctrl(NULL, MGR_DISCONNECT | REQUEST, &ch->inst.down);
sprintf(ch->inst.name, "%s B%d", ic->inst.name, nr+1);
}
@ -283,7 +282,7 @@ sendup(i4l_channel_t *ch, int Dchannel, int prim, struct sk_buff *skb)
hhe->prim = prim;
hhe->dinfo = ch->l4id;
if (ch->drv->debug & 0x4)
LogL3Msg(skb);
mISDN_LogL3Msg(skb);
if (Dchannel)
I = &ch->drv->inst;
else
@ -516,7 +515,7 @@ i4l_l1err(struct FsmInst *fi, int event, void *arg)
sendup(ch, 1, DL_RELEASE | INDICATION, NULL);
reset_channel(ch);
FsmChangeState(fi, ST_NULL);
mISDN_FsmChangeState(fi, ST_NULL);
}
static void
@ -526,7 +525,7 @@ i4l_dhup(struct FsmInst *fi, int event, void *arg)
struct sk_buff *skb;
u_char tmp[8];
skb = alloc_l3msg(8, MT_RELEASE);
skb = mISDN_alloc_l3msg(8, MT_RELEASE);
if (!skb)
return;
@ -539,10 +538,10 @@ i4l_dhup(struct FsmInst *fi, int event, void *arg)
tmp[2] = 0x80;
tmp[3] = 0x9f; /* normal, unspecified */
}
AddvarIE(skb, tmp);
mISDN_AddvarIE(skb, tmp);
sendup(ch, 1, CC_RELEASE | INDICATION, skb);
reset_channel(ch);
FsmChangeState(fi, ST_NULL);
mISDN_FsmChangeState(fi, ST_NULL);
}
static void
@ -572,7 +571,7 @@ i4l_icall(struct FsmInst *fi, int event, void *arg)
printk(KERN_DEBUG "%s: l4id(%x) ch(%p)->nr %d\n", __FUNCTION__, ch->l4id, ch, ch->nr);
} else
return;
skb = alloc_l3msg(260, MT_SETUP);
skb = mISDN_alloc_l3msg(260, MT_SETUP);
if (!skb)
return;
p = tmp;
@ -593,11 +592,11 @@ i4l_icall(struct FsmInst *fi, int event, void *arg)
*p++ = 0x90; /* Circuit-Mode 64kbps */
break;
}
AddvarIE(skb, tmp);
mISDN_AddvarIE(skb, tmp);
tmp[0] = IE_CHANNEL_ID;
tmp[1] = 1;
tmp[2] = 0x85 + ch->nr;
AddvarIE(skb, tmp);
mISDN_AddvarIE(skb, tmp);
if (setup->phone[0]) {
i = 1;
if (setup->plan) {
@ -613,7 +612,7 @@ i4l_icall(struct FsmInst *fi, int event, void *arg)
tmp[i++] = setup->phone[j++];
}
tmp[0] = i-1;
AddIE(skb, IE_CALLING_PN, tmp);
mISDN_AddIE(skb, IE_CALLING_PN, tmp);
if (setup->phone[j] == '.') {
i = 1;
tmp[i++] = 0x80;
@ -621,7 +620,7 @@ i4l_icall(struct FsmInst *fi, int event, void *arg)
while (setup->phone[j])
tmp[i++] = setup->phone[j++];
tmp[0] = i-1;
AddIE(skb, IE_CALLING_SUB, tmp);
mISDN_AddIE(skb, IE_CALLING_SUB, tmp);
}
}
if (setup->eazmsn[0]) {
@ -634,7 +633,7 @@ i4l_icall(struct FsmInst *fi, int event, void *arg)
tmp[i++] = setup->eazmsn[j++];
}
tmp[0] = i-1;
AddIE(skb, IE_CALLED_PN, tmp);
mISDN_AddIE(skb, IE_CALLED_PN, tmp);
if (setup->eazmsn[j] == '.') {
i = 1;
tmp[i++] = 0x80;
@ -642,7 +641,7 @@ i4l_icall(struct FsmInst *fi, int event, void *arg)
while (setup->eazmsn[j])
tmp[i++] = setup->eazmsn[j++];
tmp[0] = i-1;
AddIE(skb, IE_CALLED_SUB, tmp);
mISDN_AddIE(skb, IE_CALLED_SUB, tmp);
}
}
p = tmp;
@ -688,8 +687,8 @@ i4l_icall(struct FsmInst *fi, int event, void *arg)
break;
}
}
AddvarIE(skb, tmp);
FsmChangeState(fi, ST_ICALL);
mISDN_AddvarIE(skb, tmp);
mISDN_FsmChangeState(fi, ST_ICALL);
sendup(ch, 1, CC_SETUP | INDICATION, skb);
}
@ -700,16 +699,16 @@ i4l_dconn_out(struct FsmInst *fi, int event, void *arg)
struct sk_buff *skb;
u_char tmp[4];
skb = alloc_l3msg(4, MT_CONNECT);
skb = mISDN_alloc_l3msg(4, MT_CONNECT);
if (!skb)
return;
tmp[0] = IE_CHANNEL_ID;
tmp[1] = 1;
tmp[2] = 0x85 + ch->nr;
AddvarIE(skb, tmp);
mISDN_AddvarIE(skb, tmp);
sendup(ch, 1, CC_CONNECT | INDICATION, skb);
FsmChangeState(fi, ST_ACTIVD);
mISDN_FsmChangeState(fi, ST_ACTIVD);
}
static void
@ -718,7 +717,7 @@ i4l_dconn_in(struct FsmInst *fi, int event, void *arg)
i4l_channel_t *ch = fi->userdata;
sendup(ch, 1, CC_CONNECT_ACKNOWLEDGE | INDICATION, NULL);
FsmChangeState(fi, ST_ACTIVD);
mISDN_FsmChangeState(fi, ST_ACTIVD);
}
static void
@ -737,7 +736,7 @@ i4l_bconn(struct FsmInst *fi, int event, void *arg)
sendup(ch, 0, prim | INDICATION, NULL);
test_and_set_bit(I4L_FLG_BCONN, &ch->Flags);
FsmChangeState(fi, ST_ACTIVB);
mISDN_FsmChangeState(fi, ST_ACTIVB);
if (skb_queue_len(&ch->sendq))
sendqueued(ch);
}
@ -748,7 +747,7 @@ i4l_bhup(struct FsmInst *fi, int event, void *arg)
i4l_channel_t *ch = fi->userdata;
int prim = test_bit(I4L_FLG_LAYER1, &ch->Flags) ? PH_DEACTIVATE : DL_RELEASE;
FsmChangeState(fi, ST_ACTIVD);
mISDN_FsmChangeState(fi, ST_ACTIVD);
sendup(ch, 0, prim | INDICATION, NULL);
}
@ -757,10 +756,10 @@ stackready(struct FsmInst *fi, int event, void *arg)
{
i4l_channel_t *ch = fi->userdata;
FsmChangeState(fi, ST_BREADY);
mISDN_FsmChangeState(fi, ST_BREADY);
test_and_set_bit(I4L_FLG_BREADY, &ch->Flags);
if (test_bit(I4L_FLG_BCONN, &ch->Flags))
FsmEvent(&ch->i4lm, EV_I4L_BCONN, NULL);
mISDN_FsmEvent(&ch->i4lm, EV_I4L_BCONN, NULL);
}
static void
@ -773,7 +772,7 @@ capi_ocall(struct FsmInst *fi, int event, void *arg)
isdn_ctrl ctrl;
int i,l;
FsmChangeState(fi, ST_OCALL);
mISDN_FsmChangeState(fi, ST_OCALL);
test_and_set_bit(I4L_FLG_LOCK, &ch->Flags);
i4l_lock_drv(ch->drv);
ps += L3_EXTRA_SIZE;
@ -894,7 +893,7 @@ capi_alert(struct FsmInst *fi, int event, void *arg)
i4l_channel_t *ch = fi->userdata;
struct sk_buff *skb = arg;
FsmChangeState(fi, ST_ALERT);
mISDN_FsmChangeState(fi, ST_ALERT);
i4l_cmd(ch->drv, ch->nr, ISDN_CMD_ALERT);
if (skb)
dev_kfree_skb(skb);
@ -913,7 +912,7 @@ capi_connect(struct FsmInst *fi, int event, void *arg)
i4l_cmd(ch->drv, ch->nr | (ISDN_PROTO_L2_HDLC << 8), ISDN_CMD_SETL2);
i4l_cmd(ch->drv, ch->nr | (ISDN_PROTO_L3_TRANS << 8), ISDN_CMD_SETL3);
}
FsmChangeState(fi, ST_WAITDCONN);
mISDN_FsmChangeState(fi, ST_WAITDCONN);
i4l_cmd(ch->drv, ch->nr, ISDN_CMD_ACCEPTD);
if (skb)
dev_kfree_skb(skb);
@ -925,7 +924,7 @@ capi_disconnect(struct FsmInst *fi, int event, void *arg)
i4l_channel_t *ch = fi->userdata;
struct sk_buff *skb = arg;
FsmChangeState(fi, ST_HANGUP);
mISDN_FsmChangeState(fi, ST_HANGUP);
test_and_set_bit(I4L_FLG_HANGUP, &ch->Flags);
i4l_cmd(ch->drv, ch->nr, ISDN_CMD_HANGUP);
if (skb)
@ -943,7 +942,7 @@ capi_release(struct FsmInst *fi, int event, void *arg)
if (skb)
dev_kfree_skb(skb);
reset_channel(ch);
FsmChangeState(fi, ST_NULL);
mISDN_FsmChangeState(fi, ST_NULL);
}
static void
@ -960,7 +959,7 @@ capi_releaseb(struct FsmInst *fi, int event, void *arg)
i4l_channel_t *ch = fi->userdata;
test_and_clear_bit(I4L_FLG_BREADY, &ch->Flags);
FsmChangeState(fi, ST_ACTIVD);
mISDN_FsmChangeState(fi, ST_ACTIVD);
}
static int
@ -1018,23 +1017,23 @@ Dchannel_i4l(mISDNif_t *hif, struct sk_buff *skb)
return(ret);
}
if (ch->drv->debug & 0x4)
LogL3Msg(skb);
mISDN_LogL3Msg(skb);
switch(hh->prim) {
case CC_SETUP | REQUEST:
ret = FsmEvent(&ch->i4lm, EV_CAPI_OCALL, skb);
ret = mISDN_FsmEvent(&ch->i4lm, EV_CAPI_OCALL, skb);
break;
case CC_ALERTING | REQUEST:
ret = FsmEvent(&ch->i4lm, EV_CAPI_ALERT, skb);
ret = mISDN_FsmEvent(&ch->i4lm, EV_CAPI_ALERT, skb);
break;
case CC_CONNECT | REQUEST:
ret = FsmEvent(&ch->i4lm, EV_CAPI_DCONNECT, skb);
ret = mISDN_FsmEvent(&ch->i4lm, EV_CAPI_DCONNECT, skb);
break;
case CC_DISCONNECT | REQUEST:
case CC_RELEASE | REQUEST:
ret = FsmEvent(&ch->i4lm, EV_CAPI_DISCONNECT, skb);
ret = mISDN_FsmEvent(&ch->i4lm, EV_CAPI_DISCONNECT, skb);
break;
case CC_RELEASE_COMPLETE | REQUEST:
ret = FsmEvent(&ch->i4lm, EV_CAPI_RELEASE, skb);
ret = mISDN_FsmEvent(&ch->i4lm, EV_CAPI_RELEASE, skb);
break;
default:
if (debug)
@ -1061,13 +1060,13 @@ Bchannel_i4l(mISDNif_t *hif, struct sk_buff *skb)
switch(hh->prim) {
case PH_ACTIVATE | REQUEST:
case DL_ESTABLISH | REQUEST:
FsmEvent(&ch->i4lm, EV_CAPI_ESTABLISHB, NULL);
mISDN_FsmEvent(&ch->i4lm, EV_CAPI_ESTABLISHB, NULL);
skb_trim(skb, 0);
ret = if_newhead(&ch->inst.up, hh->prim | CONFIRM, 0, skb);
break;
case PH_DEACTIVATE | REQUEST:
case DL_RELEASE | REQUEST:
FsmEvent(&ch->i4lm, EV_CAPI_RELEASEB, NULL);
mISDN_FsmEvent(&ch->i4lm, EV_CAPI_RELEASEB, NULL);
skb_trim(skb, 0);
ret = if_newhead(&ch->inst.up, hh->prim | CONFIRM, 0, skb);
break;
@ -1128,10 +1127,10 @@ static int
i4l_stat_run(i4l_capi_t *ic) {
int err;
err = I4Lcapi.ctrl(ic->inst.st, MGR_SETSTACK | REQUEST, &ic->pid);
err = mISDN_ctrl(ic->inst.st, MGR_SETSTACK | REQUEST, &ic->pid);
if (err) {
printk(KERN_ERR "MGR_SETSTACK REQUEST dch err(%d)\n", err);
I4Lcapi.ctrl(ic->inst.st, MGR_DELSTACK | REQUEST, NULL);
mISDN_ctrl(ic->inst.st, MGR_DELSTACK | REQUEST, NULL);
return(err);
}
return(0);
@ -1225,7 +1224,7 @@ I4Lcapi_status_callback(isdn_ctrl *c)
if (c->arg < 0)
return -1;
ch += c->arg;
ret = FsmEvent(&ch->i4lm, EV_I4L_ICALL, &c->parm.setup);
ret = mISDN_FsmEvent(&ch->i4lm, EV_I4L_ICALL, &c->parm.setup);
break;
case ISDN_STAT_CINF:
if (c->arg < 0)
@ -1257,32 +1256,32 @@ I4Lcapi_status_callback(isdn_ctrl *c)
if (c->arg < 0)
return -1;
ch += c->arg;
ret = FsmEvent(&ch->i4lm, EV_I4L_DCONN, NULL);
ret = mISDN_FsmEvent(&ch->i4lm, EV_I4L_DCONN, NULL);
break;
case ISDN_STAT_DHUP:
if (c->arg < 0)
return -1;
ch += c->arg;
ret = FsmEvent(&ch->i4lm, EV_I4L_DHUP, NULL);
ret = mISDN_FsmEvent(&ch->i4lm, EV_I4L_DHUP, NULL);
break;
case ISDN_STAT_BCONN:
if (c->arg < 0)
return -1;
ch += c->arg;
ret = FsmEvent(&ch->i4lm, EV_I4L_BCONN, NULL);
ret = mISDN_FsmEvent(&ch->i4lm, EV_I4L_BCONN, NULL);
break;
case ISDN_STAT_BHUP:
if (c->arg < 0)
return -1;
ch += c->arg;
ret = FsmEvent(&ch->i4lm, EV_I4L_BHUP, NULL);
ret = mISDN_FsmEvent(&ch->i4lm, EV_I4L_BHUP, NULL);
break;
case ISDN_STAT_NODCH:
case ISDN_STAT_L1ERR:
if (c->arg < 0)
return -1;
ch += c->arg;
ret = FsmEvent(&ch->i4lm, EV_I4L_L1ERR, NULL);
ret = mISDN_FsmEvent(&ch->i4lm, EV_I4L_L1ERR, NULL);
break;
case ISDN_STAT_ADDCH:
case ISDN_STAT_DISCH:
@ -1290,7 +1289,7 @@ I4Lcapi_status_callback(isdn_ctrl *c)
ret = 0;
break;
case ISDN_STAT_UNLOAD:
ret = I4Lcapi.ctrl(drv->inst.st, MGR_DELSTACK | REQUEST, NULL);
ret = mISDN_ctrl(drv->inst.st, MGR_DELSTACK | REQUEST, NULL);
MOD_DEC_USE_COUNT;
break;
case CAPI_PUT_MESSAGE:
@ -1323,7 +1322,7 @@ I4Lcapi_manager(void *data, u_int prim, void *arg) {
printk(KERN_DEBUG "%s: data:%p prim:%x arg:%p\n",
__FUNCTION__, data, prim, arg);
if (prim == (MGR_HASPROTOCOL | REQUEST))
return(HasProtocolP(&I4Lcapi, arg));
return(mISDN_HasProtocolP(&I4Lcapi, arg));
if (!data) {
printk(KERN_ERR "I4Lcapi_manager no data prim %x arg %p\n",
prim, arg);
@ -1355,8 +1354,8 @@ I4Lcapi_manager(void *data, u_int prim, void *arg) {
case MGR_REGLAYER | CONFIRM:
break;
case MGR_UNREGLAYER | REQUEST:
I4Lcapi.ctrl(inst->up.peer, MGR_DISCONNECT | REQUEST, &inst->up);
I4Lcapi.ctrl(inst, MGR_UNREGLAYER | REQUEST, NULL);
mISDN_ctrl(inst->up.peer, MGR_DISCONNECT | REQUEST, &inst->up);
mISDN_ctrl(inst, MGR_UNREGLAYER | REQUEST, NULL);
break;
case MGR_RELEASE | INDICATION:
if (nr_ch == -1) {
@ -1366,21 +1365,21 @@ I4Lcapi_manager(void *data, u_int prim, void *arg) {
}
break;
case MGR_CONNECT | REQUEST:
return(ConnectIF(inst, arg));
return(mISDN_ConnectIF(inst, arg));
case MGR_SETIF | REQUEST:
case MGR_SETIF | INDICATION:
if (nr_ch == -1)
return(SetIF(inst, arg, prim, Dchannel_i4l, NULL, card));
return(mISDN_SetIF(inst, arg, prim, Dchannel_i4l, NULL, card));
else
return(SetIF(inst, arg, prim, Bchannel_i4l, NULL, channel));
return(mISDN_SetIF(inst, arg, prim, Bchannel_i4l, NULL, channel));
case MGR_DISCONNECT | REQUEST:
case MGR_DISCONNECT | INDICATION:
return(DisConnectIF(inst, arg));
case MGR_SETSTACK | CONFIRM:
return(mISDN_DisConnectIF(inst, arg));
case MGR_SETSTACK | INDICATION:
if (nr_ch >= 0) {
if (inst->pid.protocol[2] != ISDN_PID_L2_B_TRANS)
test_and_set_bit(I4L_FLG_LAYER1, &channel->Flags);
FsmEvent(&channel->i4lm, EV_STACKREADY, NULL);
mISDN_FsmEvent(&channel->i4lm, EV_STACKREADY, NULL);
}
break;
default:
@ -1435,32 +1434,28 @@ I4Lcapi_register(isdn_if *iif)
APPEND_TO_LIST(drvmap[drvidx], ((i4l_capi_t *)I4Lcapi.ilist));
drvmap[drvidx]->debug = debug;
drvmap[drvidx]->inst.obj = &I4Lcapi;
drvmap[drvidx]->inst.data = drvmap[drvidx];
drvmap[drvidx]->inst.pid.layermask = ISDN_LAYER(0) | ISDN_LAYER(1) | ISDN_LAYER(2) | ISDN_LAYER(3);
drvmap[drvidx]->inst.pid.protocol[0] = ISDN_PID_L0_TE_S0;
drvmap[drvidx]->inst.pid.protocol[1] = ISDN_PID_L1_TE_S0;
drvmap[drvidx]->inst.pid.protocol[2] = ISDN_PID_L2_LAPD;
drvmap[drvidx]->inst.pid.protocol[3] = ISDN_PID_L3_DSS1USER;
drvmap[drvidx]->inst.up.owner = &drvmap[drvidx]->inst;
drvmap[drvidx]->inst.down.owner = &drvmap[drvidx]->inst;
I4Lcapi.ctrl(NULL, MGR_DISCONNECT | REQUEST, &drvmap[drvidx]->inst.down);
mISDN_init_instance(&drvmap[drvidx]->inst, &I4Lcapi, drvmap[drvidx]);
sprintf(drvmap[drvidx]->inst.name, "Fritz%d", drvidx+1);
set_dchannel_pid(&drvmap[drvidx]->pid, 2, 0);
mISDN_set_dchannel_pid(&drvmap[drvidx]->pid, 2, 0);
for (i=0; i < drvmap[drvidx]->nr_ch; i++) {
init_channel(drvmap[drvidx], i);
}
err = I4Lcapi.ctrl(NULL, MGR_NEWSTACK | REQUEST, &drvmap[drvidx]->inst);
err = mISDN_ctrl(NULL, MGR_NEWSTACK | REQUEST, &drvmap[drvidx]->inst);
if (err) {
release_card(drvidx);
return(err);
}
ch = drvmap[drvidx]->ch;
for (i=0; i < drvmap[drvidx]->nr_ch; i++) {
err = I4Lcapi.ctrl(drvmap[drvidx]->inst.st, MGR_NEWSTACK | REQUEST, &ch->inst);
err = mISDN_ctrl(drvmap[drvidx]->inst.st, MGR_NEWSTACK | REQUEST, &ch->inst);
if (err) {
printk(KERN_ERR "MGR_ADDSTACK bchan error %d\n", err);
I4Lcapi.ctrl(drvmap[drvidx]->inst.st, MGR_DELSTACK | REQUEST, NULL);
mISDN_ctrl(drvmap[drvidx]->inst.st, MGR_DELSTACK | REQUEST, NULL);
return(err);
}
ch++;
@ -1534,7 +1529,9 @@ I4Lcapi_init(void)
int err;
printk(KERN_INFO "I4L CAPI interface modul version %s\n", mISDN_getrev(i4lcapi_revision));
SET_MODULE_OWNER(&I4Lcapi);
#ifdef MODULE
I4Lcapi.owner = THIS_MODULE;
#endif
I4Lcapi.name = I4L_capi_name;
I4Lcapi.own_ctrl = I4Lcapi_manager;
I4Lcapi.DPROTO.protocol[0] = ISDN_PID_L0_TE_S0;
@ -1550,10 +1547,10 @@ I4Lcapi_init(void)
i4lfsm_s.event_count = EVENT_COUNT;
i4lfsm_s.strEvent = strI4LEvent;
i4lfsm_s.strState = strI4LState;
FsmNew(&i4lfsm_s, I4LFnList, I4L_FN_COUNT);
mISDN_FsmNew(&i4lfsm_s, I4LFnList, I4L_FN_COUNT);
if ((err = mISDN_register(&I4Lcapi))) {
printk(KERN_ERR "Can't register I4L CAPI error(%d)\n", err);
FsmFree(&i4lfsm_s);
mISDN_FsmFree(&i4lfsm_s);
return(err);
}
I4Lcapireg.register_func = I4Lcapi_register;
@ -1578,7 +1575,7 @@ I4Lcapi_cleanup(void)
I4Lcapi.refcnt);
release_card(((i4l_capi_t *)I4Lcapi.ilist)->idx);
}
FsmFree(&i4lfsm_s);
mISDN_FsmFree(&i4lfsm_s);
unregister_i4lcapi();
return;
}

File diff suppressed because it is too large Load Diff

View File

@ -128,9 +128,9 @@ typedef struct isac_chip {
/* interface for the isac module */
extern int ISAC_init(dchannel_t *);
extern void ISAC_free(dchannel_t *);
extern int mISDN_isac_init(channel_t *);
extern void mISDN_isac_free(channel_t *);
extern void ISAC_interrupt(dchannel_t *, u_char);
extern void ISAC_clear_pending_ints(dchannel_t *);
extern int ISAC_l1hw(mISDNif_t *, struct sk_buff *);
extern void mISDN_isac_interrupt(channel_t *, u_char);
extern void mISDN_clear_isac(channel_t *);
extern int mISDN_ISAC_l1hw(mISDNinstance_t *, struct sk_buff *);

File diff suppressed because it is too large Load Diff

View File

@ -9,7 +9,7 @@
*/
typedef struct _isar_reg {
unsigned int Flags;
unsigned long Flags;
volatile u_char bstat;
volatile u_char iis;
volatile u_char cmsb;
@ -230,9 +230,9 @@ typedef struct _isar_hw {
#define STFAX_ESCAPE 5
#define STFAX_SILDET 6
extern int ISARVersion(bchannel_t *bch, char *s);
extern void isar_int_main(bchannel_t *bch);
extern int init_isar(bchannel_t *bch);
extern void free_isar(bchannel_t *bch);
extern int isar_down(mISDNif_t *, struct sk_buff *);
extern int isar_load_firmware(bchannel_t *bch, u_char *buf, int size);
extern int ISARVersion(channel_t *bch, char *s);
extern void isar_int_main(channel_t *bch);
extern int init_isar(channel_t *bch);
extern void free_isar(channel_t *bch);
extern int isar_down(mISDNinstance_t *, struct sk_buff *);
extern int isar_load_firmware(channel_t *bch, u_char *buf, int size);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -8,13 +8,13 @@
*
*/
#define __NO_VERSION__
#include <linux/module.h>
#include <linux/mISDNif.h>
#include "dss1.h"
#include "helper.h"
static signed char _l3_ie2pos[128] = {
static signed char _mISDN_l3_ie2pos[128] = {
-1,-1,-1,-1, 0,-1,-1,-1, 1,-1,-1,-1,-1,-1,-1,-1,
2,-1,-1,-1, 3,-1,-1,-1, 4,-1,-1,-1, 5,-1, 6,-1,
7,-1,-1,-1,-1,-1,-1, 8, 9,10,-1,-1,11,-1,-1,-1,
@ -22,56 +22,64 @@ static signed char _l3_ie2pos[128] = {
13,-1,14,15,16,17,18,19,-1,-1,-1,-1,20,21,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,22,23,-1,-1,
24,25,-1,-1,26,-1,-1,-1,27,28,-1,-1,29,30,31,-1
24,25,-1,-1,26,-1,27,-1,28,29,-1,-1,30,31,32,-1
};
static unsigned char _l3_pos2ie[32] = {
static unsigned char _mISDN_l3_pos2ie[33] = {
0x04, 0x08, 0x10, 0x14, 0x18, 0x1c, 0x1e, 0x20,
0x27, 0x28, 0x29, 0x2c, 0x34, 0x40, 0x42, 0x43,
0x44, 0x45, 0x46, 0x47, 0x4c, 0x4d, 0x6c, 0x6d,
0x70, 0x71, 0x74, 0x78, 0x79, 0x7c, 0x7d, 0x7e
0x70, 0x71, 0x74, 0x76, 0x78, 0x79, 0x7c, 0x7d,
0x7e
};
signed int
l3_ie2pos(u_char c)
mISDN_l3_ie2pos(u_char c)
{
if (c>0x7f)
return(-1);
return(_l3_ie2pos[c]);
return(_mISDN_l3_ie2pos[c]);
}
unsigned char
l3_pos2ie(int pos)
mISDN_l3_pos2ie(int pos)
{
return(_l3_pos2ie[pos]);
return(_mISDN_l3_pos2ie[pos]);
}
void
initQ931_info(Q931_info_t *qi) {
mISDN_initQ931_info(Q931_info_t *qi) {
memset(qi, 0, sizeof(Q931_info_t));
};
struct sk_buff *
alloc_l3msg(int len, u_char type)
#ifdef MISDN_MEMDEBUG
__mid_alloc_l3msg(int len, u_char type, char *fn, int line)
#else
mISDN_alloc_l3msg(int len, u_char type)
#endif
{
struct sk_buff *skb;
Q931_info_t *qi;
if (!(skb = alloc_skb(len + MAX_HEADER_LEN + L3_EXTRA_SIZE, GFP_ATOMIC))) {
#ifdef MISDN_MEMDEBUG
if (!(skb = __mid_alloc_skb(len + L3_EXTRA_SIZE +1, GFP_ATOMIC, fn, line))) {
#else
if (!(skb = alloc_skb(len + L3_EXTRA_SIZE +1, GFP_ATOMIC))) {
#endif
printk(KERN_WARNING "mISDN: No skb for L3\n");
return (NULL);
}
skb_reserve(skb, MAX_HEADER_LEN);
qi = (Q931_info_t *)skb_put(skb, L3_EXTRA_SIZE +1);
initQ931_info(qi);
mISDN_initQ931_info(qi);
qi->type = type;
return (skb);
}
void AddvarIE(struct sk_buff *skb, u_char *ie)
void mISDN_AddvarIE(struct sk_buff *skb, u_char *ie)
{
u_char *p, *ps;
u16 *ies;
ie_info_t *ies;
int l;
Q931_info_t *qi = (Q931_info_t *)skb->data;
@ -89,24 +97,43 @@ void AddvarIE(struct sk_buff *skb, u_char *ie)
int_error();
return;
}
l = 1;
} else {
if (_l3_ie2pos[*ie]<0) {
if (ies->off) { /* already used, no dupes for single octett */
int_error();
return;
}
ies += _l3_ie2pos[*ie];
l = 1;
} else {
if (_mISDN_l3_ie2pos[*ie]<0) {
int_error();
return;
}
ies += _mISDN_l3_ie2pos[*ie];
if (ies->off) {
if (ies->repeated)
ies = mISDN_get_last_repeated_ie(qi, ies);
l = mISDN_get_free_ext_ie(qi);
if (l < 0) { // overflow
int_error();
return;
}
ies->ridx = l;
ies->repeated = 1;
ies = &qi->ext[l].ie;
ies->cs_flg = 0;
qi->ext[l].v.codeset = 0;
qi->ext[l].v.val = *ie;
}
l = ie[1] + 2;
}
p = skb_put(skb, l);
*ies = (u16)(p - ps);
ies->off = (u16)(p - ps);
memcpy(p, ie, l);
}
void AddIE(struct sk_buff *skb, u_char ie, u_char *iep)
void mISDN_AddIE(struct sk_buff *skb, u_char ie, u_char *iep)
{
u_char *p, *ps;
u16 *ies;
ie_info_t *ies;
int l;
Q931_info_t *qi = (Q931_info_t *)skb->data;
@ -121,31 +148,69 @@ void AddIE(struct sk_buff *skb, u_char ie, u_char *iep)
int_error();
return;
}
if (ies->off) { /* already used, no dupes for single octett */
int_error();
return;
}
l = 0;
} else {
if (!iep || !iep[0])
return;
ies = &qi->bearer_capability;
if (_l3_ie2pos[ie]<0) {
if (_mISDN_l3_ie2pos[ie]<0) {
int_error();
return;
}
ies += _l3_ie2pos[ie];
ies += _mISDN_l3_ie2pos[ie];
if (ies->off) {
if (ies->repeated)
ies = mISDN_get_last_repeated_ie(qi, ies);
l = mISDN_get_free_ext_ie(qi);
if (l < 0) { // overflow
int_error();
return;
}
ies->ridx = l;
ies->repeated = 1;
ies = &qi->ext[l].ie;
ies->cs_flg = 0;
qi->ext[l].v.codeset = 0;
qi->ext[l].v.val = ie;
}
l = iep[0] + 1;
}
ps = (u_char *) qi;
ps += L3_EXTRA_SIZE;
p = skb_put(skb, l+1);
*ies = (u16)(p - ps);
ies->off = (u16)(p - ps);
*p++ = ie;
if (l)
memcpy(p, iep, l);
}
void LogL3Msg(struct sk_buff *skb)
ie_info_t *mISDN_get_last_repeated_ie(Q931_info_t *qi, ie_info_t *ie)
{
u_char *p,*ps, *t, tmp[32];
u16 *ies;
while(ie->repeated) {
ie = &qi->ext[ie->ridx].ie;
}
return(ie);
}
int mISDN_get_free_ext_ie(Q931_info_t *qi)
{
int i;
for (i = 0; i < 8; i++) {
if (qi->ext[i].ie.off == 0)
return(i);
}
return (-1);
}
void mISDN_LogL3Msg(struct sk_buff *skb)
{
u_char *p,*ps, *t, tmp[128];
ie_info_t *ies;
int i,j;
Q931_info_t *qi = (Q931_info_t *)skb->data;
mISDN_head_t *hh;
@ -160,19 +225,64 @@ void LogL3Msg(struct sk_buff *skb)
ps += L3_EXTRA_SIZE;
printk(KERN_DEBUG "L3Msg type(%02x) qi(%p) ies(%p) ps(%p)\n",
qi->type, qi, ies, ps);
for (i=0;i<32;i++) {
if (ies[i]) {
p = ps + ies[i];
for (i=0;i<33;i++) {
if (ies[i].off) {
p = ps + ies[i].off;
t = tmp;
*t = 0;
for (j=0; j<p[1]; j++) {
if (j>9) {
if (j>40) {
sprintf(t, " ...");
break;
}
t += sprintf(t, " %02x", p[j+2]);
}
printk(KERN_DEBUG "L3Msg ies[%d] off(%d) ie(%02x/%02x) len(%d) %s\n",
i, ies[i], _l3_pos2ie[i], *p, p[1], tmp);
printk(KERN_DEBUG "L3Msg ies[%d] off(%d) rep(%d) ridx(%d) ie(%02x/%02x) len(%d)%s\n",
i, ies[i].off, ies[i].repeated, ies[i].ridx, _mISDN_l3_pos2ie[i], *p, p[1], tmp);
}
}
for (i=0;i<8;i++) {
if (qi->ext[i].ie.off) {
p = ps + qi->ext[i].ie.off;
t = tmp;
*t = 0;
if (qi->ext[i].ie.cs_flg) {
for (j=0; j<qi->ext[i].cs.len; j++) {
if (j>40) {
sprintf(t, " ...");
break;
}
t += sprintf(t, " %02x", p[j]);
}
printk(KERN_DEBUG "L3Msg ext[%d] off(%d) locked(%d) cs(%d) len(%d)%s\n",
i, qi->ext[i].ie.off, qi->ext[i].cs.locked, qi->ext[i].cs.codeset,
qi->ext[i].cs.len, tmp);
} else {
for (j=0; j<p[1]; j++) {
if (j>40) {
sprintf(t, " ...");
break;
}
t += sprintf(t, " %02x", p[j+2]);
}
printk(KERN_DEBUG "L3Msg ext[%d] off(%d) rep(%d) ridx(%d) cs(%d) ie(%02x/%02x) len(%d) %s\n",
i, qi->ext[i].ie.off, qi->ext[i].ie.repeated, qi->ext[i].ie.ridx,
qi->ext[i].v.codeset, qi->ext[i].v.val, *p, p[1], tmp);
}
}
}
}
EXPORT_SYMBOL(mISDN_l3_pos2ie);
EXPORT_SYMBOL(mISDN_l3_ie2pos);
EXPORT_SYMBOL(mISDN_initQ931_info);
#ifdef MISDN_MEMDEBUG
EXPORT_SYMBOL(__mid_alloc_l3msg);
#else
EXPORT_SYMBOL(mISDN_alloc_l3msg);
#endif
EXPORT_SYMBOL(mISDN_AddvarIE);
EXPORT_SYMBOL(mISDN_AddIE);
EXPORT_SYMBOL(mISDN_get_last_repeated_ie);
EXPORT_SYMBOL(mISDN_get_free_ext_ie);
EXPORT_SYMBOL(mISDN_LogL3Msg);

View File

@ -0,0 +1,345 @@
/*
* vISDN LAPD/q.921 protocol implementation
*
* Copyright (C) 2004-2006 Daniele Orlandi
*
* Authors: Daniele "Vihai" Orlandi <daniele@orlandi.com>
*
* This program is free software and may be modified and distributed
* under the terms and conditions of the GNU General Public License.
*
*/
#ifndef _LAPD_H
#define _LAPD_H
#include <linux/types.h>
#ifdef __KERNEL__
#include <linux/socket.h>
#else
#include <sys/socket.h>
#endif
#ifndef ARPHRD_LAPD
#define ARPHRD_LAPD 8445
#endif
#ifndef ETH_P_LAPD
#define ETH_P_LAPD 0x0030 /* LAPD pseudo type */
#endif
#ifndef AF_LAPD
#define AF_LAPD 30
#endif
#ifndef PF_LAPD
#define PF_LAPD AF_LAPD
#endif
#ifndef SOL_LAPD
#define SOL_LAPD 300
#endif
#define LAPD_SAPI_Q931 0x00
#define LAPD_SAPI_X25 0x0f
#define LAPD_SAPI_MGMT 0x10
#define LAPD_BROADCAST_TEI 127
#define LAPD_DYNAMIC_TEI 255
#define LAPD_DEV_IOC_ACTIVATE _IOR(0xd0, 0x00, unsigned int)
#define LAPD_DEV_IOC_DEACTIVATE _IOR(0xd0, 0x01, unsigned int)
enum
{
LAPD_INTF_TYPE = 0,
LAPD_INTF_MODE = 1,
LAPD_INTF_ROLE = 2,
LAPD_TEI = 3,
LAPD_SAPI = 4,
LAPD_TEI_MGMT_STATUS = 5,
LAPD_TEI_MGMT_T201 = 6,
LAPD_TEI_MGMT_N202 = 7,
LAPD_TEI_MGMT_T202 = 8,
LAPD_DLC_STATE = 9,
LAPD_T200 = 10,
LAPD_N200 = 11,
LAPD_T203 = 12,
LAPD_N201 = 13,
LAPD_K = 14,
};
enum lapd_intf_type
{
LAPD_INTF_TYPE_BRA = 0,
LAPD_INTF_TYPE_PRA = 1,
};
enum lapd_intf_mode
{
LAPD_INTF_MODE_POINT_TO_POINT = 0,
LAPD_INTF_MODE_MULTIPOINT = 1
};
enum lapd_intf_role
{
LAPD_INTF_ROLE_TE = 0,
LAPD_INTF_ROLE_NT = 1
};
struct sockaddr_lapd
{
sa_family_t sal_family;
__u8 sal_tei;
};
enum lapd_primitive_type
{
LAPD_PH_DATA_REQUEST = 1,
LAPD_PH_DATA_INDICATION,
LAPD_PH_ACTIVATE_INDICATION,
LAPD_PH_DEACTIVATE_INDICATION,
LAPD_PH_ACTIVATE_REQUEST,
LAPD_MPH_ERROR_INDICATION,
LAPD_MPH_ACTIVATE_INDICATION,
LAPD_MPH_DEACTIVATE_INDICATION,
LAPD_MPH_DEACTIVATE_REQUEST,
LAPD_MPH_INFORMATION_INDICATION,
};
enum lapd_mph_information_indication
{
LAPD_MPH_II_CONNECTED,
LAPD_MPH_II_DISCONNECTED,
};
struct lapd_prim_hdr
{
__u8 primitive_type;
__u8 reserved[3];
};
struct lapd_ctrl_hdr
{
__u8 param;
};
#ifdef __KERNEL__
#include <asm/atomic.h>
#include <linux/types.h>
#include <linux/netdevice.h>
#include <linux/version.h>
#include <net/sock.h>
#define lapd_MODULE_NAME "lapd"
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#define LAPD_HASHBITS 8
#define LAPD_HASHSIZE ((1 << LAPD_HASHBITS) - 1)
#define LAPD_SK_STATE_NULL TCP_LAST_ACK
#define LAPD_SK_STATE_LISTEN TCP_LISTEN
#define LAPD_SK_STATE_NORMAL_DLC TCP_ESTABLISHED
#define LAPD_SK_STATE_NORMAL_DLC_CLOSING TCP_CLOSING
#define LAPD_SK_STATE_BROADCAST_DLC TCP_SYN_SENT
#define LAPD_SK_STATE_MGMT TCP_SYN_RECV
#define LAPD_SK_STATE_CLOSE TCP_CLOSE
#ifdef DEBUG_CODE
#define lapd_debug(format, arg...) \
printk(KERN_DEBUG \
"lapd: " \
format, \
## arg)
#define lapd_debug_ls(ls, format, arg...) \
SOCK_DEBUG(&ls->sk, \
"lapd: " \
"%s " \
format, \
(ls)->dev ? (ls)->dev->dev->name : "", \
## arg)
#else
#define lapd_debug(ls, format, arg...) do { } while (0)
#define lapd_debug_ls(ls, format, arg...) do { } while (0)
#define lapd_debug_dev(ls, format, arg...) do { } while (0)
#endif
#define lapd_msg(lvl, format, arg...) \
printk(lvl "lapd: " \
format, \
## arg)
#define lapd_msg_ls(ls, lvl, format, arg...) \
printk(lvl "lapd: " \
"%s: " \
format, \
(ls)->dev ? (ls)->dev->dev->name : "", \
## arg)
extern struct hlist_head lapd_hash[LAPD_HASHSIZE];
extern rwlock_t lapd_hash_lock;
// Do not changes these values, user mode binary compatibility needs them
enum lapd_datalink_state
{
LAPD_DLS_NULL = 0,
LAPD_DLS_1_TEI_UNASSIGNED = 1,
LAPD_DLS_2_AWAITING_TEI = 2,
LAPD_DLS_3_ESTABLISH_AWAITING_TEI = 3,
LAPD_DLS_4_TEI_ASSIGNED = 4,
LAPD_DLS_5_AWAITING_ESTABLISH = 5,
LAPD_DLS_6_AWAITING_RELEASE = 6,
LAPD_DLS_7_LINK_CONNECTION_ESTABLISHED = 7,
LAPD_DLS_8_TIMER_RECOVERY = 8,
LAPD_DLS_LISTENING = 0xFF,
};
enum lapd_mdl_error_indications
{
LAPD_MDL_ERROR_INDICATION_A = (1 << 0),
LAPD_MDL_ERROR_INDICATION_B = (1 << 1),
LAPD_MDL_ERROR_INDICATION_C = (1 << 2),
LAPD_MDL_ERROR_INDICATION_D = (1 << 3),
LAPD_MDL_ERROR_INDICATION_E = (1 << 4),
LAPD_MDL_ERROR_INDICATION_F = (1 << 5),
LAPD_MDL_ERROR_INDICATION_G = (1 << 6),
LAPD_MDL_ERROR_INDICATION_H = (1 << 7),
LAPD_MDL_ERROR_INDICATION_I = (1 << 8),
LAPD_MDL_ERROR_INDICATION_J = (1 << 9),
LAPD_MDL_ERROR_INDICATION_K = (1 << 10),
LAPD_MDL_ERROR_INDICATION_L = (1 << 11),
LAPD_MDL_ERROR_INDICATION_M = (1 << 12),
LAPD_MDL_ERROR_INDICATION_N = (1 << 13),
LAPD_MDL_ERROR_INDICATION_O = (1 << 14),
};
enum lapd_format_errors
{
LAPD_FE_LENGTH,
LAPD_FE_N201,
LAPD_FE_UNDEFINED_COMMAND,
LAPD_FE_I_FIELD_NOT_PERMITTED,
};
struct lapd_sap
{
atomic_t refcnt;
// SAP parameters
int k;
int N200;
int N201;
int T200;
int T203;
};
//#include "device.h"
struct lapd_new_dlc
{
struct hlist_node node;
struct lapd_sock *lapd_sock;
};
static inline struct lapd_sap *lapd_sap_alloc(void)
{
return kmalloc(sizeof(struct lapd_sap), GFP_ATOMIC);
}
static inline void lapd_sap_hold(
struct lapd_sap *entity)
{
atomic_inc(&entity->refcnt);
}
static inline void lapd_sap_put(
struct lapd_sap *entity)
{
if (atomic_dec_and_test(&entity->refcnt))
kfree(entity);
}
struct lapd_sock
{
struct sock sk;
struct lapd_device *dev;
struct sk_buff_head u_queue;
int retrans_cnt;
struct timer_list timer_T200;
struct timer_list timer_T203;
u8 v_s;
u8 v_r;
u8 v_a;
enum lapd_datalink_state state;
int peer_receiver_busy;
int own_receiver_busy;
int reject_exception;
int acknowledge_pending;
int layer_3_initiated;
// ------------------
struct lapd_sap *sap;
struct lapd_utme *usr_tme;
int tei;
int sapi;
struct hlist_head new_dlcs;
};
#define to_lapd_sock(obj) container_of(obj, struct lapd_sock, sk)
enum lapd_dl_primitive_type
{
LAPD_DL_RELEASE_INDICATION,
LAPD_DL_RELEASE_CONFIRM,
LAPD_DL_ESTABLISH_INDICATION,
LAPD_DL_ESTABLISH_CONFIRM,
};
struct lapd_dl_primitive
{
enum lapd_dl_primitive_type type;
int param;
};
struct lapd_sock *lapd_new_sock(
struct lapd_sock *parent_lapd_sock,
u8 tei, int sapi);
void lapd_mdl_error_indication(
struct lapd_sock *lapd_sock,
unsigned long indication);
void lapd_dl_primitive(
struct lapd_sock *lapd_sock,
enum lapd_dl_primitive_type type,
int param);
int lapd_dl_unit_data_indication(
struct lapd_sock *lapd_sock,
struct sk_buff *skb);
void lapd_dl_data_indication(
struct lapd_sock *lapd_sock,
struct sk_buff *skb);
#endif
#endif

View File

@ -1,27 +1,24 @@
/* $Id$
*
* mISDN_l1.c common low level stuff for I.430 layer1
* mISDN_l1.c common low level stuff for I.430 layer1 TE mode
*
* Author Karsten Keil (keil@isdn4linux.de)
*
* This file is (c) under GNU PUBLIC LICENSE
* For changes and modifications please read
* ../../../Documentation/isdn/mISDN.cert
* This file is released under the GPLv2
*
*/
static char *l1_revision = "$Revision$";
#include <linux/config.h>
#include <linux/module.h>
#include "core.h"
#include "layer1.h"
#include "helper.h"
#include "debug.h"
typedef struct _layer1 {
struct _layer1 *prev;
struct _layer1 *next;
int Flags;
struct list_head list;
u_long Flags;
struct FsmInst l1m;
struct FsmTimer timer;
int debug;
@ -36,7 +33,7 @@ typedef struct _status_info_l1 {
int protocol;
int status;
int state;
int Flags;
u_long Flags;
int T3;
int delay;
int debug;
@ -47,9 +44,11 @@ static mISDNobject_t isdnl1;
#define TIMER3_VALUE 7000
#ifdef OBSOLETE
static
struct Fsm l1fsm_b =
{NULL, 0, 0, NULL, NULL};
#endif
static
struct Fsm l1fsm_s =
@ -101,6 +100,7 @@ static char *strL1UState[] =
};
#endif
#ifdef OBSOLETE
enum {
ST_L1_NULL,
ST_L1_WAIT_ACT,
@ -117,7 +117,7 @@ static char *strL1BState[] =
"ST_L1_WAIT_DEACT",
"ST_L1_ACTIV",
};
#endif
enum {
EV_PH_ACTIVATE,
EV_PH_DEACTIVATE,
@ -160,26 +160,26 @@ l1m_debug(struct FsmInst *fi, char *fmt, ...)
va_start(log.args, fmt);
log.fmt = fmt;
log.head = l1->inst.name;
l1->inst.obj->ctrl(&l1->inst, MGR_DEBUGDATA | REQUEST, &log);
mISDN_ctrl(&l1->inst, MGR_DEBUGDATA | REQUEST, &log);
va_end(log.args);
}
static int
l1up(layer1_t *l1, u_int prim, int dinfo, int len, void *arg)
{
return(if_link(&l1->inst.up, prim, dinfo, len, arg, 0));
return(mISDN_queue_data(&l1->inst, FLG_MSG_UP, prim, dinfo, len, arg, 0));
}
static int
l1down(layer1_t *l1, u_int prim, int dinfo, int len, void *arg)
{
return(if_link(&l1->inst.down, prim, dinfo, len, arg, 0));
return(mISDN_queue_data(&l1->inst, FLG_MSG_DOWN, prim, dinfo, len, arg, 0));
}
static void
l1_reset(struct FsmInst *fi, int event, void *arg)
{
FsmChangeState(fi, ST_L1_F3);
mISDN_FsmChangeState(fi, ST_L1_F3);
}
static void
@ -187,7 +187,7 @@ l1_deact_cnf(struct FsmInst *fi, int event, void *arg)
{
layer1_t *l1 = fi->userdata;
FsmChangeState(fi, ST_L1_F3);
mISDN_FsmChangeState(fi, ST_L1_F3);
if (test_bit(FLG_L1_ACTIVATING, &l1->Flags))
l1down(l1, PH_CONTROL | REQUEST, HW_POWERUP, 0, NULL);
}
@ -197,8 +197,8 @@ l1_deact_req_s(struct FsmInst *fi, int event, void *arg)
{
layer1_t *l1 = fi->userdata;
FsmChangeState(fi, ST_L1_F3);
FsmRestartTimer(&l1->timer, 550, EV_TIMER_DEACT, NULL, 2);
mISDN_FsmChangeState(fi, ST_L1_F3);
mISDN_FsmRestartTimer(&l1->timer, 550, EV_TIMER_DEACT, NULL, 2);
test_and_set_bit(FLG_L1_DEACTTIMER, &l1->Flags);
}
@ -208,24 +208,22 @@ l1_power_up_s(struct FsmInst *fi, int event, void *arg)
layer1_t *l1 = fi->userdata;
if (test_bit(FLG_L1_ACTIVATING, &l1->Flags)) {
FsmChangeState(fi, ST_L1_F4);
mISDN_FsmChangeState(fi, ST_L1_F4);
l1down(l1, PH_SIGNAL | REQUEST, INFO3_P8, 0, NULL);
FsmRestartTimer(&l1->timer, TIMER3_VALUE, EV_TIMER3, NULL, 2);
test_and_set_bit(FLG_L1_T3RUN, &l1->Flags);
} else
FsmChangeState(fi, ST_L1_F3);
mISDN_FsmChangeState(fi, ST_L1_F3);
}
static void
l1_go_F5(struct FsmInst *fi, int event, void *arg)
{
FsmChangeState(fi, ST_L1_F5);
mISDN_FsmChangeState(fi, ST_L1_F5);
}
static void
l1_go_F8(struct FsmInst *fi, int event, void *arg)
{
FsmChangeState(fi, ST_L1_F8);
mISDN_FsmChangeState(fi, ST_L1_F8);
}
static void
@ -235,10 +233,10 @@ l1_info2_ind(struct FsmInst *fi, int event, void *arg)
#ifdef mISDN_UINTERFACE
if (test_bit(FLG_L1_UINT, &l1->Flags))
FsmChangeState(fi, ST_L1_SYNC2);
mISDN_FsmChangeState(fi, ST_L1_SYNC2);
else
#endif
FsmChangeState(fi, ST_L1_F6);
mISDN_FsmChangeState(fi, ST_L1_F6);
l1down(l1, PH_SIGNAL | REQUEST, INFO3_P8, 0, NULL);
}
@ -249,17 +247,17 @@ l1_info4_ind(struct FsmInst *fi, int event, void *arg)
#ifdef mISDN_UINTERFACE
if (test_bit(FLG_L1_UINT, &l1->Flags))
FsmChangeState(fi, ST_L1_TRANS);
mISDN_FsmChangeState(fi, ST_L1_TRANS);
else
#endif
FsmChangeState(fi, ST_L1_F7);
mISDN_FsmChangeState(fi, ST_L1_F7);
l1down(l1, PH_SIGNAL | REQUEST, INFO3_P8, 0, NULL);
if (test_and_clear_bit(FLG_L1_DEACTTIMER, &l1->Flags))
FsmDelTimer(&l1->timer, 4);
mISDN_FsmDelTimer(&l1->timer, 4);
if (!test_bit(FLG_L1_ACTIVATED, &l1->Flags)) {
if (test_and_clear_bit(FLG_L1_T3RUN, &l1->Flags))
FsmDelTimer(&l1->timer, 3);
FsmRestartTimer(&l1->timer, 110, EV_TIMER_ACT, NULL, 2);
mISDN_FsmDelTimer(&l1->timer, 3);
mISDN_FsmRestartTimer(&l1->timer, 110, EV_TIMER_ACT, NULL, 2);
test_and_set_bit(FLG_L1_ACTTIMER, &l1->Flags);
}
}
@ -275,12 +273,15 @@ l1_timer3(struct FsmInst *fi, int event, void *arg)
if (test_and_clear_bit(FLG_L1_DBLOCKED, &l1->Flags))
l1up(l1, PH_CONTROL | INDICATION, 0, 4, &db);
l1up(l1, PH_DEACTIVATE | INDICATION, 0, 0, NULL);
mISDN_queue_data(&l1->inst, l1->inst.id | MSG_BROADCAST,
MGR_SHORTSTATUS | INDICATION, SSTATUS_L1_DEACTIVATED,
0, NULL, 0);
}
#ifdef mISDN_UINTERFACE
if (!test_bit(FLG_L1_UINT, &l1->Flags))
#endif
if (l1->l1m.state != ST_L1_F6) {
FsmChangeState(fi, ST_L1_F3);
mISDN_FsmChangeState(fi, ST_L1_F3);
l1down(l1, PH_CONTROL | REQUEST, HW_POWERUP, 0, NULL);
}
}
@ -296,6 +297,9 @@ l1_timer_act(struct FsmInst *fi, int event, void *arg)
l1up(l1, PH_ACTIVATE | CONFIRM, 0, 0, NULL);
else
l1up(l1, PH_ACTIVATE | INDICATION, 0, 0, NULL);
mISDN_queue_data(&l1->inst, l1->inst.id | MSG_BROADCAST,
MGR_SHORTSTATUS | INDICATION, SSTATUS_L1_ACTIVATED,
0, NULL, 0);
}
static void
@ -310,6 +314,9 @@ l1_timer_deact(struct FsmInst *fi, int event, void *arg)
l1up(l1, PH_CONTROL | INDICATION, 0, 4, &db);
l1up(l1, PH_DEACTIVATE | INDICATION, 0, 0, NULL);
l1down(l1, PH_CONTROL | REQUEST, HW_DEACTIVATE, 0, NULL);
mISDN_queue_data(&l1->inst, l1->inst.id | MSG_BROADCAST,
MGR_SHORTSTATUS | INDICATION, SSTATUS_L1_DEACTIVATED,
0, NULL, 0);
}
static void
@ -317,6 +324,8 @@ l1_activate_s(struct FsmInst *fi, int event, void *arg)
{
layer1_t *l1 = fi->userdata;
mISDN_FsmRestartTimer(&l1->timer, TIMER3_VALUE, EV_TIMER3, NULL, 2);
test_and_set_bit(FLG_L1_T3RUN, &l1->Flags);
l1down(l1, PH_CONTROL | REQUEST, HW_RESET, 0, NULL);
}
@ -390,8 +399,8 @@ l1_deact_req_u(struct FsmInst *fi, int event, void *arg)
{
layer1_t *l1 = fi->userdata;
FsmChangeState(fi, ST_L1_RESET);
FsmRestartTimer(&l1->timer, 550, EV_TIMER_DEACT, NULL, 2);
mISDN_FsmChangeState(fi, ST_L1_RESET);
mISDN_FsmRestartTimer(&l1->timer, 550, EV_TIMER_DEACT, NULL, 2);
test_and_set_bit(FLG_L1_DEACTTIMER, &l1->Flags);
l1down(l1, PH_CONTROL | REQUEST, HW_POWERUP, 0, NULL);
}
@ -401,14 +410,14 @@ l1_power_up_u(struct FsmInst *fi, int event, void *arg)
{
layer1_t *l1 = fi->userdata;
FsmRestartTimer(&l1->timer, TIMER3_VALUE, EV_TIMER3, NULL, 2);
mISDN_FsmRestartTimer(&l1->timer, TIMER3_VALUE, EV_TIMER3, NULL, 2);
test_and_set_bit(FLG_L1_T3RUN, &l1->Flags);
}
static void
l1_info0_ind(struct FsmInst *fi, int event, void *arg)
{
FsmChangeState(fi, ST_L1_DEACT);
mISDN_FsmChangeState(fi, ST_L1_DEACT);
}
static void
@ -444,14 +453,14 @@ static struct FsmNode L1UFnList[] =
#define L1U_FN_COUNT (sizeof(L1UFnList)/sizeof(struct FsmNode))
#endif
#ifdef OBSOLETE
static void
l1b_activate(struct FsmInst *fi, int event, void *arg)
{
layer1_t *l1 = fi->userdata;
FsmChangeState(fi, ST_L1_WAIT_ACT);
FsmRestartTimer(&l1->timer, l1->delay, EV_TIMER_ACT, NULL, 2);
mISDN_FsmChangeState(fi, ST_L1_WAIT_ACT);
mISDN_FsmRestartTimer(&l1->timer, l1->delay, EV_TIMER_ACT, NULL, 2);
}
static void
@ -459,8 +468,8 @@ l1b_deactivate(struct FsmInst *fi, int event, void *arg)
{
layer1_t *l1 = fi->userdata;
FsmChangeState(fi, ST_L1_WAIT_DEACT);
FsmRestartTimer(&l1->timer, 10, EV_TIMER_DEACT, NULL, 2);
mISDN_FsmChangeState(fi, ST_L1_WAIT_DEACT);
mISDN_FsmRestartTimer(&l1->timer, 10, EV_TIMER_DEACT, NULL, 2);
}
static void
@ -468,7 +477,7 @@ l1b_timer_act(struct FsmInst *fi, int event, void *arg)
{
layer1_t *l1 = fi->userdata;
FsmChangeState(fi, ST_L1_ACTIV);
mISDN_FsmChangeState(fi, ST_L1_ACTIV);
l1up(l1, PH_ACTIVATE | CONFIRM, 0, 0, NULL);
}
@ -477,7 +486,7 @@ l1b_timer_deact(struct FsmInst *fi, int event, void *arg)
{
layer1_t *l1 = fi->userdata;
FsmChangeState(fi, ST_L1_NULL);
mISDN_FsmChangeState(fi, ST_L1_NULL);
l1up(l1, PH_DEACTIVATE | CONFIRM, 0, 0, NULL);
}
@ -490,44 +499,32 @@ static struct FsmNode L1BFnList[] =
};
#define L1B_FN_COUNT (sizeof(L1BFnList)/sizeof(struct FsmNode))
#endif
static int
l1from_up(mISDNif_t *hif, struct sk_buff *skb)
l1from_up(layer1_t *l1, struct sk_buff *skb, mISDN_head_t *hh)
{
layer1_t *l1;
mISDN_head_t *hh;
int err = 0;
if (!hif || !hif->fdata || !skb)
return(-EINVAL);
l1 = hif->fdata;
hh = mISDN_HEAD_P(skb);
switch(hh->prim) {
case (PH_DATA | REQUEST):
case (PH_CONTROL | REQUEST):
if (l1->inst.down.func)
return(l1->inst.down.func(&l1->inst.down,
skb));
else
err = -ENXIO;
return(mISDN_queue_down(&l1->inst, 0, skb));
break;
case (PH_ACTIVATE | REQUEST):
if (test_bit(FLG_L1_ACTIVATED, &l1->Flags))
l1up(l1, PH_ACTIVATE | CONFIRM, 0, 0, NULL);
else {
test_and_set_bit(FLG_L1_ACTIVATING, &l1->Flags);
FsmEvent(&l1->l1m, EV_PH_ACTIVATE, NULL);
mISDN_FsmEvent(&l1->l1m, EV_PH_ACTIVATE, NULL);
}
break;
case (MDL_FINDTEI | REQUEST):
if (l1->inst.up.func)
return(l1->inst.up.func(&l1->inst.up, skb));
else
err = -ENXIO;
return(mISDN_queue_up(&l1->inst, 0, skb));
break;
default:
if (l1->debug)
mISDNdebug(l1->inst.st->id, NULL,
mISDN_debug(l1->inst.st->id, NULL,
"l1from_up msg %x unhandled", hh->prim);
err = -EINVAL;
break;
@ -538,61 +535,49 @@ l1from_up(mISDNif_t *hif, struct sk_buff *skb)
}
static int
l1from_down(mISDNif_t *hif, struct sk_buff *skb)
l1from_down(layer1_t *l1, struct sk_buff *skb, mISDN_head_t *hh)
{
layer1_t *l1;
mISDN_head_t *hh;
int err = 0;
if (!hif || !hif->fdata || !skb)
return(-EINVAL);
l1 = hif->fdata;
hh = mISDN_HEAD_P(skb);
if (hh->prim == PH_DATA_IND) {
if (test_bit(FLG_L1_ACTTIMER, &l1->Flags))
FsmEvent(&l1->l1m, EV_TIMER_ACT, NULL);
if (l1->inst.up.func)
return(l1->inst.up.func(&l1->inst.up, skb));
else
err = -ENXIO;
mISDN_FsmEvent(&l1->l1m, EV_TIMER_ACT, NULL);
return(mISDN_queue_up(&l1->inst, 0, skb));
} else if (hh->prim == PH_DATA_CNF) {
if (l1->inst.up.func)
return(l1->inst.up.func(&l1->inst.up, skb));
else
err = -ENXIO;
return(mISDN_queue_up(&l1->inst, 0, skb));
} else if (hh->prim == (PH_CONTROL | INDICATION)) {
if (hh->dinfo == HW_RESET)
FsmEvent(&l1->l1m, EV_RESET_IND, NULL);
mISDN_FsmEvent(&l1->l1m, EV_RESET_IND, NULL);
else if (hh->dinfo == HW_DEACTIVATE)
FsmEvent(&l1->l1m, EV_DEACT_IND, NULL);
mISDN_FsmEvent(&l1->l1m, EV_DEACT_IND, NULL);
else if (hh->dinfo == HW_POWERUP)
FsmEvent(&l1->l1m, EV_POWER_UP, NULL);
mISDN_FsmEvent(&l1->l1m, EV_POWER_UP, NULL);
else if (l1->debug)
mISDNdebug(l1->inst.st->id, NULL,
mISDN_debug(l1->inst.st->id, NULL,
"l1from_down ctrl ind %x unhandled", hh->dinfo);
} else if (hh->prim == (PH_CONTROL | CONFIRM)) {
if (hh->dinfo == HW_DEACTIVATE)
FsmEvent(&l1->l1m, EV_DEACT_CNF, NULL);
mISDN_FsmEvent(&l1->l1m, EV_DEACT_CNF, NULL);
else if (l1->debug)
mISDNdebug(l1->inst.st->id, NULL,
mISDN_debug(l1->inst.st->id, NULL,
"l1from_down ctrl cnf %x unhandled", hh->dinfo);
} else if (hh->prim == (PH_SIGNAL | INDICATION)) {
if (hh->dinfo == ANYSIGNAL)
FsmEvent(&l1->l1m, EV_ANYSIG_IND, NULL);
mISDN_FsmEvent(&l1->l1m, EV_ANYSIG_IND, NULL);
else if (hh->dinfo == LOSTFRAMING)
FsmEvent(&l1->l1m, EV_ANYSIG_IND, NULL);
mISDN_FsmEvent(&l1->l1m, EV_ANYSIG_IND, NULL);
else if (hh->dinfo == INFO2)
FsmEvent(&l1->l1m, EV_INFO2_IND, NULL);
mISDN_FsmEvent(&l1->l1m, EV_INFO2_IND, NULL);
else if (hh->dinfo == INFO4_P8)
FsmEvent(&l1->l1m, EV_INFO4_IND, NULL);
mISDN_FsmEvent(&l1->l1m, EV_INFO4_IND, NULL);
else if (hh->dinfo == INFO4_P10)
FsmEvent(&l1->l1m, EV_INFO4_IND, NULL);
mISDN_FsmEvent(&l1->l1m, EV_INFO4_IND, NULL);
else if (l1->debug)
mISDNdebug(l1->inst.st->id, NULL,
mISDN_debug(l1->inst.st->id, NULL,
"l1from_down sig %x unhandled", hh->dinfo);
} else {
if (l1->debug)
mISDNdebug(l1->inst.st->id, NULL,
mISDN_debug(l1->inst.st->id, NULL,
"l1from_down msg %x unhandled", hh->prim);
err = -EINVAL;
}
@ -601,11 +586,67 @@ l1from_down(mISDNif_t *hif, struct sk_buff *skb)
return(err);
}
static int
l1_shortstatus(layer1_t *l1, struct sk_buff *skb, mISDN_head_t *hh)
{
u_int temp;
if (hh->prim == (MGR_SHORTSTATUS | REQUEST)) {
temp = hh->dinfo & SSTATUS_ALL;
if (temp == SSTATUS_ALL || temp == SSTATUS_L1) {
skb_trim(skb, 0);
if (hh->dinfo & SSTATUS_BROADCAST_BIT)
temp = l1->inst.id | MSG_BROADCAST;
else
temp = hh->addr | FLG_MSG_TARGET;
hh->dinfo = (l1->l1m.state == ST_L1_F7) ?
SSTATUS_L1_ACTIVATED : SSTATUS_L1_DEACTIVATED;
hh->prim = MGR_SHORTSTATUS | CONFIRM;
return(mISDN_queue_message(&l1->inst, temp, skb));
}
}
return(-EOPNOTSUPP);
}
static int
l1_function(mISDNinstance_t *inst, struct sk_buff *skb)
{
layer1_t *l1 = inst->privat;
mISDN_head_t *hh = mISDN_HEAD_P(skb);
int ret = -EINVAL;
if (debug)
printk(KERN_DEBUG "%s: addr(%08x) prim(%x)\n", __FUNCTION__, hh->addr, hh->prim);
if (unlikely((hh->prim & MISDN_CMD_MASK) == MGR_SHORTSTATUS))
return(l1_shortstatus(l1, skb, hh));
switch(hh->addr & MSG_DIR_MASK) {
case FLG_MSG_DOWN:
ret = l1from_up(l1, skb, hh);
break;
case FLG_MSG_UP:
ret = l1from_down(l1, skb, hh);
break;
case MSG_TO_OWNER:
/* FIXME: must be handled depending on type */
int_errtxt("not implemented yet");
break;
default:
/* FIXME: must be handled depending on type */
int_errtxt("not implemented yet");
break;
}
return(ret);
}
static void
release_l1(layer1_t *l1) {
mISDNinstance_t *inst = &l1->inst;
u_long flags;
FsmDelTimer(&l1->timer, 0);
mISDN_FsmDelTimer(&l1->timer, 0);
#ifdef OBSOLETE
if (inst->up.peer) {
inst->up.peer->obj->ctrl(inst->up.peer,
MGR_DISCONNECT | REQUEST, &inst->up);
@ -614,8 +655,11 @@ release_l1(layer1_t *l1) {
inst->down.peer->obj->ctrl(inst->down.peer,
MGR_DISCONNECT | REQUEST, &inst->down);
}
REMOVE_FROM_LISTBASE(l1, ((layer1_t *)isdnl1.ilist));
isdnl1.ctrl(inst, MGR_UNREGLAYER | REQUEST, NULL);
#endif
spin_lock_irqsave(&isdnl1.lock, flags);
list_del(&l1->list);
spin_unlock_irqrestore(&isdnl1.lock, flags);
mISDN_ctrl(inst, MGR_UNREGLAYER | REQUEST, NULL);
kfree(l1);
}
@ -623,6 +667,7 @@ static int
new_l1(mISDNstack_t *st, mISDN_pid_t *pid) {
layer1_t *nl1;
int err;
u_long flags;
if (!st || !pid)
return(-EINVAL);
@ -632,15 +677,14 @@ new_l1(mISDNstack_t *st, mISDN_pid_t *pid) {
}
memset(nl1, 0, sizeof(layer1_t));
memcpy(&nl1->inst.pid, pid, sizeof(mISDN_pid_t));
nl1->inst.obj = &isdnl1;
nl1->inst.data = nl1;
if (!SetHandledPID(&isdnl1, &nl1->inst.pid)) {
mISDN_init_instance(&nl1->inst, &isdnl1, nl1, l1_function);
if (!mISDN_SetHandledPID(&isdnl1, &nl1->inst.pid)) {
int_error();
return(-ENOPROTOOPT);
}
switch(pid->protocol[1]) {
case ISDN_PID_L1_TE_S0:
sprintf(nl1->inst.name, "l1TES0 %d", st->id);
sprintf(nl1->inst.name, "l1TES0 %x", st->id >> 8);
nl1->l1m.fsm = &l1fsm_s;
nl1->l1m.state = ST_L1_F3;
nl1->Flags = 0;
@ -656,14 +700,14 @@ new_l1(mISDNstack_t *st, mISDN_pid_t *pid) {
nl1->l1m.userdata = nl1;
nl1->l1m.userint = 0;
nl1->l1m.printdebug = l1m_debug;
FsmInitTimer(&nl1->l1m, &nl1->timer);
nl1->inst.up.owner = &nl1->inst;
nl1->inst.down.owner = &nl1->inst;
APPEND_TO_LIST(nl1, ((layer1_t *)isdnl1.ilist));
err = isdnl1.ctrl(st, MGR_REGLAYER | INDICATION, &nl1->inst);
mISDN_FsmInitTimer(&nl1->l1m, &nl1->timer);
spin_lock_irqsave(&isdnl1.lock, flags);
list_add_tail(&nl1->list, &isdnl1.ilist);
spin_unlock_irqrestore(&isdnl1.lock, flags);
err = mISDN_ctrl(st, MGR_REGLAYER | INDICATION, &nl1->inst);
if (err) {
FsmDelTimer(&nl1->timer, 0);
REMOVE_FROM_LISTBASE(nl1, ((layer1_t *)isdnl1.ilist));
mISDN_FsmDelTimer(&nl1->timer, 0);
list_del(&nl1->list);
kfree(nl1);
}
return(err);
@ -693,7 +737,11 @@ static char MName[] = "ISDNL1";
#ifdef MODULE
MODULE_AUTHOR("Karsten Keil");
#ifdef OLD_MODULE_PARAM
MODULE_PARM(debug, "1i");
#else
module_param(debug, uint, S_IRUGO | S_IWUSR);
#endif
#ifdef MODULE_LICENSE
MODULE_LICENSE("GPL");
#endif
@ -703,61 +751,63 @@ MODULE_LICENSE("GPL");
static int
l1_manager(void *data, u_int prim, void *arg) {
mISDNinstance_t *inst = data;
layer1_t *l1l = isdnl1.ilist;
layer1_t *l1l;
int err = -EINVAL;
u_long flags;
printk(KERN_DEBUG "l1_manager data:%p prim:%x arg:%p\n", data, prim, arg);
if (debug & 0x10000)
printk(KERN_DEBUG "%s: data(%p) prim(%x) arg(%p)\n",
__FUNCTION__, data, prim, arg);
if (!data)
return(-EINVAL);
while(l1l) {
if (&l1l->inst == inst)
return(err);
spin_lock_irqsave(&isdnl1.lock, flags);
list_for_each_entry(l1l, &isdnl1.ilist, list) {
if (&l1l->inst == inst) {
err = 0;
break;
l1l = l1l->next;
}
}
spin_unlock_irqrestore(&isdnl1.lock, flags);
if (err && (prim != (MGR_NEWLAYER | REQUEST))) {
if (debug)
printk(KERN_WARNING "l1_manager connect no instance\n");
return(err);
}
switch(prim) {
case MGR_NEWLAYER | REQUEST:
return(new_l1(data, arg));
err = new_l1(data, arg);
break;
#ifdef OBSOLETE
case MGR_CONNECT | REQUEST:
if (!l1l) {
printk(KERN_WARNING "l1_manager connect no instance\n");
return(-EINVAL);
}
return(ConnectIF(inst, arg));
err = mISDN_ConnectIF(inst, arg);
break;
case MGR_SETIF | REQUEST:
case MGR_SETIF | INDICATION:
if (!l1l) {
printk(KERN_WARNING "l1_manager setif no instance\n");
return(-EINVAL);
}
return(SetIF(inst, arg, prim, l1from_up, l1from_down, l1l));
err = mISDN_SetIF(inst, arg, prim, l1from_up, l1from_down, l1l);
break;
case MGR_DISCONNECT | REQUEST:
case MGR_DISCONNECT | INDICATION:
if (!l1l) {
printk(KERN_WARNING "l1_manager disconnect no instance\n");
return(-EINVAL);
}
return(DisConnectIF(inst, arg));
err = mISDN_DisConnectIF(inst, arg);
break;
#endif
case MGR_UNREGLAYER | REQUEST:
case MGR_RELEASE | INDICATION:
if (l1l) {
printk(KERN_DEBUG "release_l1 id %x\n", l1l->inst.st->id);
release_l1(l1l);
} else
printk(KERN_WARNING "l1_manager release no instance\n");
break;
case MGR_STATUS | REQUEST:
if (!l1l) {
printk(KERN_WARNING "l1_manager status l1 no instance\n");
return(-EINVAL);
}
return(l1_status(l1l, arg));
err = l1_status(l1l, arg);
break;
PRIM_NOT_HANDLED(MGR_CTRLREADY|INDICATION);
PRIM_NOT_HANDLED(MGR_ADDSTPARA|INDICATION);
PRIM_NOT_HANDLED(MGR_SETSTACK|INDICATION);
default:
printk(KERN_WARNING "l1_manager prim %x not handled\n", prim);
return(-EINVAL);
err = -EINVAL;
break;
}
return(0);
return(err);
}
int Isdnl1Init(void)
@ -765,39 +815,45 @@ int Isdnl1Init(void)
int err;
printk(KERN_INFO "ISDN L1 driver version %s\n", mISDN_getrev(l1_revision));
SET_MODULE_OWNER(&isdnl1);
#ifdef MODULE
isdnl1.owner = THIS_MODULE;
#endif
isdnl1.name = MName;
isdnl1.DPROTO.protocol[1] = ISDN_PID_L1_TE_S0;
isdnl1.own_ctrl = l1_manager;
isdnl1.prev = NULL;
isdnl1.next = NULL;
isdnl1.ilist = NULL;
spin_lock_init(&isdnl1.lock);
INIT_LIST_HEAD(&isdnl1.ilist);
#ifdef mISDN_UINTERFACE
isdnl1.DPROTO.protocol[1] |= ISDN_PID_L1_TE_U;
l1fsm_u.state_count = L1U_STATE_COUNT;
l1fsm_u.event_count = L1_EVENT_COUNT;
l1fsm_u.strEvent = strL1Event;
l1fsm_u.strState = strL1UState;
FsmNew(&l1fsm_u, L1UFnList, L1U_FN_COUNT);
mISDN_FsmNew(&l1fsm_u, L1UFnList, L1U_FN_COUNT);
#endif
l1fsm_s.state_count = L1S_STATE_COUNT;
l1fsm_s.event_count = L1_EVENT_COUNT;
l1fsm_s.strEvent = strL1Event;
l1fsm_s.strState = strL1SState;
FsmNew(&l1fsm_s, L1SFnList, L1S_FN_COUNT);
mISDN_FsmNew(&l1fsm_s, L1SFnList, L1S_FN_COUNT);
#ifdef OBSOLETE
l1fsm_b.state_count = L1B_STATE_COUNT;
l1fsm_b.event_count = L1_EVENT_COUNT;
l1fsm_b.strEvent = strL1Event;
l1fsm_b.strState = strL1BState;
FsmNew(&l1fsm_b, L1BFnList, L1B_FN_COUNT);
mISDN_FsmNew(&l1fsm_b, L1BFnList, L1B_FN_COUNT);
#endif
if ((err = mISDN_register(&isdnl1))) {
printk(KERN_ERR "Can't register %s error(%d)\n", MName, err);
#ifdef mISDN_UINTERFACE
FsmFree(&l1fsm_u);
mISDN_FsmFree(&l1fsm_u);
#endif
FsmFree(&l1fsm_s);
FsmFree(&l1fsm_b);
}
mISDN_FsmFree(&l1fsm_s);
#ifdef OBSOLETE
mISDN_FsmFree(&l1fsm_b);
#endif
} else
mISDN_module_register(THIS_MODULE);
return(err);
}
@ -805,19 +861,24 @@ int Isdnl1Init(void)
void cleanup_module(void)
{
int err;
layer1_t *l1, *nl1;
mISDN_module_unregister(THIS_MODULE);
if ((err = mISDN_unregister(&isdnl1))) {
printk(KERN_ERR "Can't unregister ISDN layer 1 error(%d)\n", err);
}
if(isdnl1.ilist) {
if(!list_empty(&isdnl1.ilist)) {
printk(KERN_WARNING "mISDNl1 inst list not empty\n");
while(isdnl1.ilist)
release_l1(isdnl1.ilist);
list_for_each_entry_safe(l1, nl1, &isdnl1.ilist, list)
release_l1(l1);
}
#ifdef mISDN_UINTERFACE
FsmFree(&l1fsm_u);
mISDN_FsmFree(&l1fsm_u);
#endif
mISDN_FsmFree(&l1fsm_s);
#ifdef OBSOLETE
mISDN_FsmFree(&l1fsm_b);
#endif
FsmFree(&l1fsm_s);
FsmFree(&l1fsm_b);
}
#endif

View File

@ -8,10 +8,11 @@
#include <linux/mISDNif.h>
#include "fsm.h"
#ifdef MEMDBG
#ifdef MISDN_MEMDEBUG
#include "memdbg.h"
#endif
#ifdef OBSOLETE
#define D_RCVBUFREADY 0
#define D_XMTBUFREADY 1
#define D_L1STATECHANGE 2
@ -21,10 +22,18 @@
#define D_TX_MON0 6
#define D_TX_MON1 7
#define D_BLOCKEDATOMIC 8
#define D_LOS 9
#define D_LOS_OFF 10
#define D_AIS 11
#define D_AIS_OFF 12
#define D_SLIP_TX 13
#define D_SLIP_RX 14
#define B_RCVBUFREADY 0
#define B_XMTBUFREADY 1
#define B_BLOCKEDATOMIC 2
#define B_DTMFREADY 3
#endif
#define FLG_L1_ACTIVATING 1
#define FLG_L1_ACTIVATED 2

File diff suppressed because it is too large Load Diff

View File

@ -9,7 +9,7 @@
#include <linux/mISDNif.h>
#include <linux/skbuff.h>
#include "fsm.h"
#ifdef MEMDBG
#ifdef MISDN_MEMDEBUG
#include "memdbg.h"
#endif
@ -30,29 +30,31 @@ typedef struct _laddr {
} laddr_t;
typedef struct _layer2 {
struct _layer2 *prev;
struct _layer2 *next;
struct list_head list;
int sapi;
int tei;
laddr_t addr;
int maxlen;
u_int maxlen;
teimgr_t *tm;
u_int flag;
u_long flag;
u_int vs, va, vr;
int rc;
u_int window;
u_int sow;
int entity;
struct FsmInst l2m;
struct FsmTimer t200, t203;
int T200, N200, T203;
int debug;
mISDNinstance_t inst;
mISDNif_t *cloneif;
// mISDNif_t *cloneif;
int next_id;
u_int down_id;
struct sk_buff *windowar[MAX_WINDOW];
struct sk_buff *down_skb;
struct sk_buff_head i_queue;
struct sk_buff_head ui_queue;
struct sk_buff_head down_queue;
struct sk_buff_head tmp_queue;
} layer2_t;
/* l2 status_info */
@ -64,8 +66,8 @@ typedef struct _status_info_l2 {
int sapi;
int tei;
laddr_t addr;
int maxlen;
u_int flag;
u_int maxlen;
u_long flag;
u_int vs;
u_int va;
u_int vr;

View File

@ -10,9 +10,9 @@
* Fritz Elfert
*
*/
#define __NO_VERSION__
#include "layer3.h"
#include "helper.h"
#include "dss1.h"
const char *l3_revision = "$Revision$";
@ -70,7 +70,7 @@ l3m_debug(struct FsmInst *fi, char *fmt, ...)
va_start(log.args, fmt);
log.fmt = fmt;
log.head = l3->inst.name;
l3->inst.obj->ctrl(&l3->inst, MGR_DEBUGDATA | REQUEST, &log);
mISDN_ctrl(&l3->inst, MGR_DEBUGDATA | REQUEST, &log);
va_end(log.args);
}
@ -82,10 +82,22 @@ l3_debug(layer3_t *l3, char *fmt, ...)
va_start(log.args, fmt);
log.fmt = fmt;
log.head = l3->inst.name;
l3->inst.obj->ctrl(&l3->inst, MGR_DEBUGDATA | REQUEST, &log);
mISDN_ctrl(&l3->inst, MGR_DEBUGDATA | REQUEST, &log);
va_end(log.args);
}
static int
l3_newid(layer3_t *l3)
{
int id;
id = l3->next_id++;
if (id == 0x7fff)
l3->next_id = 1;
id |= (l3->entity << 16);
return(id);
}
u_char *
findie(u_char * p, int size, u_char ie, int wanted_set)
{
@ -146,16 +158,19 @@ getcallref(u_char * p)
return (cr);
}
static int OrigCallRef = 0;
int
newcallref(void)
newcallref(layer3_t *l3)
{
if (OrigCallRef == 127)
OrigCallRef = 1;
int max = 127;
if (test_bit(FLG_CRLEN2, &l3->Flag))
max = 32767;
if (l3->OrigCallRef >= max)
l3->OrigCallRef = 1;
else
OrigCallRef++;
return (OrigCallRef);
l3->OrigCallRef++;
return (l3->OrigCallRef);
}
void
@ -214,18 +229,6 @@ StopAllL3Timer(l3_process_t *pc)
}
}
struct sk_buff *
l3_alloc_skb(int len)
{
struct sk_buff *skb;
if (!(skb = alloc_skb(len + MAX_HEADER_LEN + IFRAME_HEAD_SIZE, GFP_ATOMIC))) {
printk(KERN_WARNING "mISDN: No skb for D-channel\n");
return (NULL);
}
skb_reserve(skb, MAX_HEADER_LEN + IFRAME_HEAD_SIZE);
return (skb);
}
/*
static void
no_l3_proto(struct PStack *st, int pr, void *arg)
@ -249,44 +252,74 @@ no_l3_proto_spec(struct PStack *st, isdn_ctrl *ic)
l3_process_t
*getl3proc(layer3_t *l3, int cr)
{
l3_process_t *p = l3->proc;
l3_process_t *p;
while (p)
list_for_each_entry(p, &l3->plist, list)
if (p->callref == cr)
return (p);
else
p = p->next;
return (NULL);
}
l3_process_t
*getl3proc4id(layer3_t *l3, int id)
{
l3_process_t *p = l3->proc;
while (p)
if (p->id == id)
return (p);
else
p = p->next;
return (NULL);
}
l3_process_t
*new_l3_process(layer3_t *l3, int cr, int n303)
*getl3proc4id(layer3_t *l3, u_int id)
{
l3_process_t *p;
list_for_each_entry(p, &l3->plist, list)
if (p->id == id)
return (p);
return (NULL);
}
l3_process_t
*new_l3_process(layer3_t *l3, int cr, int n303, u_int id)
{
l3_process_t *p = NULL;
if (id == MISDN_ID_ANY) {
if (l3->entity == MISDN_ENTITY_NONE) {
printk(KERN_WARNING "%s: no entity allocated for l3(%x)\n",
__FUNCTION__, l3->id);
return (NULL);
}
if (l3->pid_cnt == 0x7FFF)
l3->pid_cnt = 0;
while(l3->pid_cnt <= 0x7FFF) {
l3->pid_cnt++;
id = l3->pid_cnt | (l3->entity << 16);
p = getl3proc4id(l3, id);
if (!p)
break;
}
if (p) {
printk(KERN_WARNING "%s: no free process_id for l3(%x) entity(%x)\n",
__FUNCTION__, l3->id, l3->entity);
return (NULL);
}
} else {
/* id from other entity */
p = getl3proc4id(l3, id);
if (p) {
printk(KERN_WARNING "%s: process_id(%x) allready in use in l3(%x)\n",
__FUNCTION__, id, l3->id);
return (NULL);
}
}
if (!(p = kmalloc(sizeof(l3_process_t), GFP_ATOMIC))) {
printk(KERN_ERR "mISDN can't get memory for cr %d\n", cr);
return (NULL);
}
memset(p, 0, sizeof(l3_process_t));
p->cause=NO_CAUSE;
p->l3 = l3;
p->id = id;
p->callref = cr;
p->n303 = n303;
L3InitTimer(p, &p->timer);
APPEND_TO_LIST(p, l3->proc);
L3InitTimer(p, &p->aux_timer);
list_add_tail(&p->list, &l3->plist);
return (p);
};
@ -299,16 +332,16 @@ release_l3_process(l3_process_t *p)
return;
l3 = p->l3;
mISDN_l3up(p, CC_RELEASE_CR | INDICATION, NULL);
REMOVE_FROM_LISTBASE(p, l3->proc);
list_del(&p->list);
StopAllL3Timer(p);
kfree(p);
if (!l3->proc && !test_bit(FLG_PTP, &l3->Flag)) {
if (list_empty(&l3->plist) && !test_bit(FLG_PTP, &l3->Flag)) {
if (l3->debug)
l3_debug(l3, "release_l3_process: last process");
if (!skb_queue_len(&l3->squeue)) {
if (l3->debug)
l3_debug(l3, "release_l3_process: release link");
FsmEvent(&l3->l3m, EV_RELEASE_REQ, NULL);
mISDN_FsmEvent(&l3->l3m, EV_RELEASE_REQ, NULL);
} else {
if (l3->debug)
l3_debug(l3, "release_l3_process: not release link");
@ -319,15 +352,10 @@ release_l3_process(l3_process_t *p)
static void
l3ml3p(layer3_t *l3, int pr)
{
l3_process_t *p = l3->proc;
l3_process_t *np;
l3_process_t *p, *np;
while (p) {
/* p might be kfreed under us, so we need to save where we want to go on */
np = p->next;
list_for_each_entry_safe(p, np, &l3->plist, list)
l3->p_mgr(p, pr, NULL);
p = np;
}
}
int
@ -340,9 +368,9 @@ mISDN_l3up(l3_process_t *l3p, u_int prim, struct sk_buff *skb)
return(-EINVAL);
l3 = l3p->l3;
if (!skb)
err = if_link(&l3->inst.up, prim, l3p->id, 0, NULL, 0);
err = mISDN_queue_data(&l3->inst, FLG_MSG_UP, prim, l3p->id, 0, NULL, 0);
else
err = if_newhead(&l3->inst.up, prim, l3p->id, skb);
err = mISDN_queueup_newhead(&l3->inst, 0, prim, l3p->id, skb);
return(err);
}
@ -351,9 +379,9 @@ l3down(layer3_t *l3, u_int prim, int dinfo, struct sk_buff *skb) {
int err = -EINVAL;
if (!skb)
err = if_link(&l3->inst.down, prim, dinfo, 0, NULL, 0);
err = mISDN_queue_data(&l3->inst, FLG_MSG_DOWN, prim, dinfo, 0, NULL, 0);
else
err = if_newhead(&l3->inst.down, prim, dinfo, skb);
err = mISDN_queuedown_newhead(&l3->inst, 0, prim, dinfo, skb);
return(err);
}
@ -364,7 +392,7 @@ lc_activate(struct FsmInst *fi, int event, void *arg)
{
layer3_t *l3 = fi->userdata;
FsmChangeState(fi, ST_L3_LC_ESTAB_WAIT);
mISDN_FsmChangeState(fi, ST_L3_LC_ESTAB_WAIT);
l3down(l3, DL_ESTABLISH | REQUEST, 0, NULL);
}
@ -375,16 +403,16 @@ lc_connect(struct FsmInst *fi, int event, void *arg)
struct sk_buff *skb;
int dequeued = 0;
FsmChangeState(fi, ST_L3_LC_ESTAB);
mISDN_FsmChangeState(fi, ST_L3_LC_ESTAB);
while ((skb = skb_dequeue(&l3->squeue))) {
if (l3down(l3, DL_DATA | REQUEST, DINFO_SKB, skb))
if (l3down(l3, DL_DATA | REQUEST, l3_newid(l3), skb))
dev_kfree_skb(skb);
dequeued++;
}
if ((!l3->proc) && dequeued) {
if (list_empty(&l3->plist) && dequeued) {
if (l3->debug)
l3m_debug(fi, "lc_connect: release link");
FsmEvent(&l3->l3m, EV_RELEASE_REQ, NULL);
mISDN_FsmEvent(&l3->l3m, EV_RELEASE_REQ, NULL);
} else
l3ml3p(l3, DL_ESTABLISH | INDICATION);
}
@ -396,17 +424,17 @@ lc_connected(struct FsmInst *fi, int event, void *arg)
struct sk_buff *skb;
int dequeued = 0;
FsmDelTimer(&l3->l3m_timer, 51);
FsmChangeState(fi, ST_L3_LC_ESTAB);
mISDN_FsmDelTimer(&l3->l3m_timer, 51);
mISDN_FsmChangeState(fi, ST_L3_LC_ESTAB);
while ((skb = skb_dequeue(&l3->squeue))) {
if (l3down(l3, DL_DATA | REQUEST, DINFO_SKB, skb))
if (l3down(l3, DL_DATA | REQUEST, l3_newid(l3), skb))
dev_kfree_skb(skb);
dequeued++;
}
if ((!l3->proc) && dequeued) {
if (list_empty(&l3->plist) && dequeued) {
if (l3->debug)
l3m_debug(fi, "lc_connected: release link");
FsmEvent(&l3->l3m, EV_RELEASE_REQ, NULL);
mISDN_FsmEvent(&l3->l3m, EV_RELEASE_REQ, NULL);
} else
l3ml3p(l3, DL_ESTABLISH | CONFIRM);
}
@ -416,8 +444,8 @@ lc_start_delay(struct FsmInst *fi, int event, void *arg)
{
layer3_t *l3 = fi->userdata;
FsmChangeState(fi, ST_L3_LC_REL_DELAY);
FsmAddTimer(&l3->l3m_timer, DREL_TIMER_VALUE, EV_TIMEOUT, NULL, 50);
mISDN_FsmChangeState(fi, ST_L3_LC_REL_DELAY);
mISDN_FsmAddTimer(&l3->l3m_timer, DREL_TIMER_VALUE, EV_TIMEOUT, NULL, 50);
}
static void
@ -429,9 +457,9 @@ lc_release_req(struct FsmInst *fi, int event, void *arg)
if (l3->debug)
l3m_debug(fi, "lc_release_req: l2 blocked");
/* restart release timer */
FsmAddTimer(&l3->l3m_timer, DREL_TIMER_VALUE, EV_TIMEOUT, NULL, 51);
mISDN_FsmAddTimer(&l3->l3m_timer, DREL_TIMER_VALUE, EV_TIMEOUT, NULL, 51);
} else {
FsmChangeState(fi, ST_L3_LC_REL_WAIT);
mISDN_FsmChangeState(fi, ST_L3_LC_REL_WAIT);
l3down(l3, DL_RELEASE | REQUEST, 0, NULL);
}
}
@ -441,8 +469,8 @@ lc_release_ind(struct FsmInst *fi, int event, void *arg)
{
layer3_t *l3 = fi->userdata;
FsmDelTimer(&l3->l3m_timer, 52);
FsmChangeState(fi, ST_L3_LC_REL);
mISDN_FsmDelTimer(&l3->l3m_timer, 52);
mISDN_FsmChangeState(fi, ST_L3_LC_REL);
discard_queue(&l3->squeue);
l3ml3p(l3, DL_RELEASE | INDICATION);
}
@ -452,7 +480,7 @@ lc_release_cnf(struct FsmInst *fi, int event, void *arg)
{
layer3_t *l3 = fi->userdata;
FsmChangeState(fi, ST_L3_LC_REL);
mISDN_FsmChangeState(fi, ST_L3_LC_REL);
discard_queue(&l3->squeue);
l3ml3p(l3, DL_RELEASE | CONFIRM);
}
@ -485,33 +513,33 @@ l3_msg(layer3_t *l3, u_int pr, int dinfo, int len, void *arg)
switch (pr) {
case (DL_DATA | REQUEST):
if (l3->l3m.state == ST_L3_LC_ESTAB) {
return(l3down(l3, pr, dinfo, arg));
return(l3down(l3, pr, l3_newid(l3), arg));
} else {
struct sk_buff *skb = arg;
// printk(KERN_DEBUG "%s: queue skb %p len(%d)\n",
// __FUNCTION__, skb, skb->len);
skb_queue_tail(&l3->squeue, skb);
FsmEvent(&l3->l3m, EV_ESTABLISH_REQ, NULL);
mISDN_FsmEvent(&l3->l3m, EV_ESTABLISH_REQ, NULL);
}
break;
case (DL_ESTABLISH | REQUEST):
FsmEvent(&l3->l3m, EV_ESTABLISH_REQ, NULL);
mISDN_FsmEvent(&l3->l3m, EV_ESTABLISH_REQ, NULL);
break;
case (DL_ESTABLISH | CONFIRM):
FsmEvent(&l3->l3m, EV_ESTABLISH_CNF, NULL);
mISDN_FsmEvent(&l3->l3m, EV_ESTABLISH_CNF, NULL);
break;
case (DL_ESTABLISH | INDICATION):
FsmEvent(&l3->l3m, EV_ESTABLISH_IND, NULL);
mISDN_FsmEvent(&l3->l3m, EV_ESTABLISH_IND, NULL);
break;
case (DL_RELEASE | INDICATION):
FsmEvent(&l3->l3m, EV_RELEASE_IND, NULL);
mISDN_FsmEvent(&l3->l3m, EV_RELEASE_IND, NULL);
break;
case (DL_RELEASE | CONFIRM):
FsmEvent(&l3->l3m, EV_RELEASE_CNF, NULL);
mISDN_FsmEvent(&l3->l3m, EV_RELEASE_CNF, NULL);
break;
case (DL_RELEASE | REQUEST):
FsmEvent(&l3->l3m, EV_RELEASE_REQ, NULL);
mISDN_FsmEvent(&l3->l3m, EV_RELEASE_REQ, NULL);
break;
}
return(0);
@ -520,27 +548,32 @@ l3_msg(layer3_t *l3, u_int pr, int dinfo, int len, void *arg)
void
init_l3(layer3_t *l3)
{
l3->proc = NULL;
INIT_LIST_HEAD(&l3->plist);
l3->global = NULL;
l3->dummy = NULL;
l3->entity = MISDN_ENTITY_NONE;
l3->next_id = 1;
skb_queue_head_init(&l3->squeue);
l3->l3m.fsm = &l3fsm;
l3->l3m.state = ST_L3_LC_REL;
l3->l3m.debug = 1;
l3->l3m.debug = l3->debug;
l3->l3m.userdata = l3;
l3->l3m.userint = 0;
l3->l3m.printdebug = l3m_debug;
FsmInitTimer(&l3->l3m, &l3->l3m_timer);
mISDN_FsmInitTimer(&l3->l3m, &l3->l3m_timer);
}
void
release_l3(layer3_t *l3)
{
printk(KERN_DEBUG "release_l3(%p) proc(%p) global(%p) dummy(%p)\n",
l3, l3->proc, l3->global, l3->dummy);
while (l3->proc)
release_l3_process(l3->proc);
l3_process_t *p, *np;
if (l3->l3m.debug)
printk(KERN_DEBUG "release_l3(%p) plist(%s) global(%p) dummy(%p)\n",
l3, list_empty(&l3->plist) ? "no" : "yes", l3->global, l3->dummy);
list_for_each_entry_safe(p, np, &l3->plist, list)
release_l3_process(p);
if (l3->global) {
StopAllL3Timer(l3->global);
kfree(l3->global);
@ -551,7 +584,7 @@ release_l3(layer3_t *l3)
kfree(l3->dummy);
l3->dummy = NULL;
}
FsmDelTimer(&l3->l3m_timer, 54);
mISDN_FsmDelTimer(&l3->l3m_timer, 54);
discard_queue(&l3->squeue);
}
@ -562,11 +595,11 @@ mISDNl3New(void)
l3fsm.event_count = L3_EVENT_COUNT;
l3fsm.strEvent = strL3Event;
l3fsm.strState = strL3State;
FsmNew(&l3fsm, L3FnList, L3_FN_COUNT);
mISDN_FsmNew(&l3fsm, L3FnList, L3_FN_COUNT);
}
void
mISDNl3Free(void)
{
FsmFree(&l3fsm);
mISDN_FsmFree(&l3fsm);
}

View File

@ -7,7 +7,7 @@
#include <linux/mISDNif.h>
#include <linux/skbuff.h>
#include "fsm.h"
#ifdef MEMDBG
#ifdef MISDN_MEMDEBUG
#include "memdbg.h"
#endif
@ -22,6 +22,7 @@
#define L3_DEB_CHARGE 0x08
#define L3_DEB_CHECK 0x10
#define L3_DEB_SI 0x20
#define L3_DEB_MSG 0x80000000
#define FLG_L2BLOCK 1
#define FLG_PTP 2
@ -35,43 +36,49 @@ typedef struct _L3Timer {
} L3Timer_t;
typedef struct _l3_process {
struct _l3_process *prev;
struct _l3_process *next;
struct list_head list;
struct _layer3 *l3;
int callref;
int state;
L3Timer_t timer;
int n303;
int cause;
struct sk_buff *t303skb;
u_int id;
int bc;
int real_bc;
int err;
int aux_state;
L3Timer_t aux_timer;
} l3_process_t;
typedef struct _layer3 {
struct _layer3 *prev;
struct _layer3 *next;
struct list_head list;
struct FsmInst l3m;
struct FsmTimer l3m_timer;
l3_process_t *proc;
int entity;
int pid_cnt;
int next_id;
struct list_head plist;
l3_process_t *global;
l3_process_t *dummy;
int (*p_mgr)(l3_process_t *, u_int, void *);
int down_headerlen;
u_int id;
int debug;
u_int Flag;
u_long Flag;
mISDNinstance_t inst;
struct sk_buff_head squeue;
int OrigCallRef;
} layer3_t;
struct stateentry {
int state;
int primitive;
u_int primitive;
void (*rout) (l3_process_t *, u_char, void *);
};
extern int l3_msg(layer3_t *, u_int, int, int, void *);
extern struct sk_buff *l3_alloc_skb(int);
extern void newl3state(l3_process_t *, int);
extern void L3InitTimer(l3_process_t *, L3Timer_t *);
extern void L3DelTimer(L3Timer_t *);
@ -79,12 +86,12 @@ extern int L3AddTimer(L3Timer_t *, int, int);
extern void StopAllL3Timer(l3_process_t *);
extern void release_l3_process(l3_process_t *);
extern l3_process_t *getl3proc(layer3_t *, int);
extern l3_process_t *getl3proc4id(layer3_t *, int);
extern l3_process_t *new_l3_process(layer3_t *, int, int);
extern l3_process_t *getl3proc4id(layer3_t *, u_int);
extern l3_process_t *new_l3_process(layer3_t *, int, int, u_int);
extern u_char *findie(u_char *, int, u_char, int);
extern int mISDN_l3up(l3_process_t *, u_int, struct sk_buff *);
extern int getcallref(u_char * p);
extern int newcallref(void);
extern int newcallref(layer3_t *);
extern void init_l3(layer3_t *);
extern void release_l3(layer3_t *);
extern void mISDNl3New(void);

View File

@ -2,7 +2,7 @@
*
*/
#include "capi.h"
#include "m_capi.h"
#include "helper.h"
#include "debug.h"
@ -43,77 +43,87 @@ static char* str_ev_listen[] = {
static struct Fsm listen_fsm =
{ 0, 0, 0, 0, 0 };
static void listen_debug(struct FsmInst *fi, char *fmt, ...)
static void
listen_debug(struct FsmInst *fi, char *fmt, ...)
{
char tmp[128];
char *p = tmp;
va_list args;
Listen_t *listen = fi->userdata;
Application_t *app = fi->userdata;
if (!fi->debug)
return;
va_start(args, fmt);
p += sprintf(p, "Controller 0x%x ApplId %d listen ",
listen->contr->adrController, listen->ApplId);
app->contr->addr, app->ApplId);
p += vsprintf(p, fmt, args);
*p = 0;
listenDebug(listen, CAPI_DBG_LISTEN_STATE, tmp);
listenDebug(app, CAPI_DBG_LISTEN_STATE, tmp);
va_end(args);
}
static void listen_req_l_x(struct FsmInst *fi, int event, void *arg, int state)
static void
listen_req_l_x(struct FsmInst *fi, int event, void *arg, int state)
{
Listen_t *listen = fi->userdata;
Application_t *app = fi->userdata;
_cmsg *cmsg = arg;
FsmChangeState(fi, state);
mISDN_FsmChangeState(fi, state);
listen->InfoMask = cmsg->InfoMask;
listen->CIPmask = cmsg->CIPmask;
listen->CIPmask2 = cmsg->CIPmask2;
listenDebug(listen, CAPI_DBG_LISTEN_INFO, "set InfoMask to 0x%x", listen->InfoMask);
listenDebug(listen, CAPI_DBG_LISTEN_INFO, "set CIP to 0x%x,0x%x", listen->CIPmask,
listen->CIPmask2);
app->InfoMask = cmsg->InfoMask;
app->CIPmask = cmsg->CIPmask;
app->CIPmask2 = cmsg->CIPmask2;
listenDebug(app, CAPI_DBG_LISTEN_INFO, "set InfoMask to 0x%x", app->InfoMask);
listenDebug(app, CAPI_DBG_LISTEN_INFO, "set CIP to 0x%x,0x%x", app->CIPmask,
app->CIPmask2);
capi_cmsg_answer(cmsg);
cmsg->Info = CAPI_NOERROR;
FsmEvent(&listen->listen_m, EV_LISTEN_CONF, cmsg);
contrRecvCmsg(listen->contr, cmsg);
if (mISDN_FsmEvent(&app->listen_m, EV_LISTEN_CONF, cmsg))
cmsg_free(cmsg);
}
static void listen_req_l_0(struct FsmInst *fi, int event, void *arg)
static void
listen_req_l_0(struct FsmInst *fi, int event, void *arg)
{
listen_req_l_x(fi, event, arg, ST_LISTEN_L_0_1);
}
static void listen_req_l_1(struct FsmInst *fi, int event, void *arg)
static void
listen_req_l_1(struct FsmInst *fi, int event, void *arg)
{
listen_req_l_x(fi, event, arg, ST_LISTEN_L_1_1);
}
static void listen_conf_l_x_1(struct FsmInst *fi, int event, void *arg,
int state)
static void
listen_conf_l_x_1(struct FsmInst *fi, int event, void *arg, int state)
{
Listen_t *listen = fi->userdata;
Application_t *app = fi->userdata;
_cmsg *cmsg = arg;
if (cmsg->Info != CAPI_NOERROR) {
FsmChangeState(fi, state);
mISDN_FsmChangeState(fi, state);
} else { // Info == 0
if (listen->CIPmask == 0)
FsmChangeState(fi, ST_LISTEN_L_0);
else
FsmChangeState(fi, ST_LISTEN_L_1);
if (app->CIPmask == 0) {
test_and_clear_bit(APPL_STATE_LISTEN, &app->state);
mISDN_FsmChangeState(fi, ST_LISTEN_L_0);
} else {
test_and_set_bit(APPL_STATE_LISTEN, &app->state);
mISDN_FsmChangeState(fi, ST_LISTEN_L_1);
}
}
SendCmsg2Application(app, cmsg);
}
static void listen_conf_l_0_1(struct FsmInst *fi, int event, void *arg)
static void
listen_conf_l_0_1(struct FsmInst *fi, int event, void *arg)
{
listen_conf_l_x_1(fi, event, arg, ST_LISTEN_L_0);
}
static void listen_conf_l_1_1(struct FsmInst *fi, int event, void *arg)
static void
listen_conf_l_1_1(struct FsmInst *fi, int event, void *arg)
{
listen_conf_l_x_1(fi, event, arg, ST_LISTEN_L_1);
}
@ -131,53 +141,56 @@ const int FN_LISTEN_COUNT = sizeof(fn_listen_list)/sizeof(struct FsmNode);
// ----------------------------------------------------------------------
// Methods
void listenConstr(Listen_t *listen, Contr_t *contr, __u16 ApplId)
void listenConstr(Application_t *app)
{
listen->listen_m.fsm = &listen_fsm;
listen->listen_m.state = ST_LISTEN_L_0;
listen->listen_m.debug = contr->debug & CAPI_DBG_LISTEN_STATE;
listen->listen_m.userdata = listen;
listen->listen_m.printdebug = listen_debug;
listen->contr = contr;
listen->ApplId = ApplId;
listen->InfoMask = 0;
listen->CIPmask = 0;
listen->CIPmask2 = 0;
app->listen_m.fsm = &listen_fsm;
app->listen_m.state = ST_LISTEN_L_0;
app->listen_m.debug = app->contr->debug & CAPI_DBG_LISTEN_STATE;
app->listen_m.userdata = app;
app->listen_m.printdebug = listen_debug;
app->InfoMask = 0;
app->CIPmask = 0;
app->CIPmask2 = 0;
}
void listenDestr(Listen_t *listen)
void listenDestr(Application_t *app)
{
listenDebug(listen, CAPI_DBG_LISTEN, "%s\n", __FUNCTION__);
test_and_clear_bit(APPL_STATE_LISTEN, &app->state);
listenDebug(app, CAPI_DBG_LISTEN, "%s", __FUNCTION__);
}
void listenSendMessage(Listen_t *listen, struct sk_buff *skb)
__u16
listenSendMessage(Application_t *app, struct sk_buff *skb)
{
_cmsg cmsg;
capi_message2cmsg(&cmsg, skb->data);
_cmsg *cmsg;
switch (CMSGCMD(&cmsg)) {
cmsg = cmsg_alloc();
if (!cmsg) {
int_error();
return (CAPI_MSGOSRESOURCEERR);
}
capi_message2cmsg(cmsg, skb->data);
switch (CMSGCMD(cmsg)) {
case CAPI_LISTEN_REQ:
FsmEvent(&listen->listen_m, EV_LISTEN_REQ, &cmsg);
if (mISDN_FsmEvent(&app->listen_m, EV_LISTEN_REQ, cmsg))
cmsg_free(cmsg);
break;
default:
int_error();
cmsg_free(cmsg);
}
dev_kfree_skb(skb);
return(CAPI_NOERROR);
}
int listenHandle(Listen_t *listen, __u16 CIPValue)
int listenHandle(Application_t *app, __u16 CIPValue)
{
if ((listen->CIPmask & 1) ||
(listen -> CIPmask & (1 << CIPValue)))
if ((app->CIPmask & 1) ||
(app->CIPmask & (1 << CIPValue)))
return 1;
return 0;
}
// ---------------------------------------------------------------------
//
void init_listen(void)
{
listen_fsm.state_count = ST_LISTEN_COUNT;
@ -185,10 +198,10 @@ void init_listen(void)
listen_fsm.strEvent = str_ev_listen;
listen_fsm.strState = str_st_listen;
FsmNew(&listen_fsm, fn_listen_list, FN_LISTEN_COUNT);
mISDN_FsmNew(&listen_fsm, fn_listen_list, FN_LISTEN_COUNT);
}
void free_listen(void)
{
FsmFree(&listen_fsm);
mISDN_FsmFree(&listen_fsm);
}

View File

@ -0,0 +1,597 @@
/*
* loop.c loop driver for looped bchannel pairs
*
* Author Andreas Eversberg (jolly@eversberg.eu)
*
* 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, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
/* module parameters:
* interfaces:
Number of loop interfaces. Default is 1.
*/
#include <linux/module.h>
#include <linux/delay.h>
#include "channel.h"
#include "layer1.h"
#include "debug.h"
#include <linux/isdn_compat.h>
#include "loop.h"
static const char *loop_revision = "$Revision$";
static int loop_cnt;
static mISDNobject_t loop_obj;
static char LoopName[] = "loop";
/****************/
/* module stuff */
/****************/
static int interfaces;
static int debug;
#ifdef MODULE
MODULE_AUTHOR("Andreas Eversberg");
#ifdef MODULE_LICENSE
MODULE_LICENSE("GPL");
#endif
module_param(interfaces, uint, S_IRUGO | S_IWUSR);
module_param(debug, uint, S_IRUGO | S_IWUSR);
#endif
/****************************/
/* Layer 1 D-channel access */
/****************************/
/* message transfer from layer 1.
*/
static int loop_l1hw(mISDNinstance_t *inst, struct sk_buff *skb)
{
channel_t *dch = container_of(inst, channel_t, inst);
loop_t *hc;
int ret = 0;
mISDN_head_t *hh;
hh = mISDN_HEAD_P(skb);
hc = dch->inst.privat;
if (debug & DEBUG_LOOP_MSG)
printk(KERN_DEBUG "%s: unsupported prim %x\n", __FUNCTION__, hh->prim);
ret = -EINVAL;
if (!ret)
dev_kfree_skb(skb);
return(ret);
}
/******************************/
/* Layer2 -> Layer 1 Transfer */
/******************************/
/* messages from layer 2 to layer 1 are processed here.
*/
static int
loop_l2l1(mISDNinstance_t *inst, struct sk_buff *skb)
{
int ch;
channel_t *bch = container_of(inst, channel_t, inst);
int ret = -EINVAL;
mISDN_head_t *hh;
loop_t *hc;
struct sk_buff *nskb;
hh = mISDN_HEAD_P(skb);
hc = bch->inst.privat;
ch = bch->channel;
if ((hh->prim == PH_DATA_REQ)
|| (hh->prim == (DL_DATA | REQUEST))) {
if (skb->len <= 0) {
printk(KERN_WARNING "%s: skb too small\n", __FUNCTION__);
return(-EINVAL);
}
if (skb->len > MAX_DATA_MEM) {
printk(KERN_WARNING "%s: skb too large\n", __FUNCTION__);
return(-EINVAL);
}
if ((nskb = skb_clone(skb, GFP_ATOMIC)))
queue_ch_frame(hc->bch[ch^1], INDICATION, MISDN_ID_ANY, nskb);
skb_trim(skb, 0);
return(mISDN_queueup_newhead(inst, 0, hh->prim | CONFIRM, hh->dinfo, skb));
} else if ((hh->prim == (PH_ACTIVATE | REQUEST))
|| (hh->prim == (DL_ESTABLISH | REQUEST))) {
/* activate B-channel if not already activated */
skb_trim(skb, 0);
return(mISDN_queueup_newhead(inst, 0, hh->prim | CONFIRM, ret, skb));
} else if ((hh->prim == (PH_DEACTIVATE | REQUEST))
|| (hh->prim == (DL_RELEASE | REQUEST))
|| ((hh->prim == (PH_CONTROL | REQUEST) && (hh->dinfo == HW_DEACTIVATE)))) {
skb_trim(skb, 0);
return(mISDN_queueup_newhead(inst, 0, hh->prim | CONFIRM, ret, skb));
} else
if (hh->prim == (PH_CONTROL | REQUEST)) {
switch (hh->dinfo) {
default:
printk(KERN_DEBUG "%s: unknown PH_CONTROL info %x\n", __FUNCTION__, hh->dinfo);
ret = -EINVAL;
}
} else {
printk(KERN_WARNING "%s: unknown prim(%x)\n", __FUNCTION__, hh->prim);
ret = -EINVAL;
}
if (!ret) {
dev_kfree_skb(skb);
}
return(ret);
}
/**************************
* remove card from stack *
**************************/
static void
loop_delete(loop_t *hc)
{
int ch;
u_long flags;
if (debug & DEBUG_LOOP_INIT)
printk(KERN_DEBUG "%s: entered\n", __FUNCTION__);
/* free channels */
if (hc->dch) {
if (debug & DEBUG_LOOP_INIT)
printk(KERN_DEBUG "%s: free D-channel\n", __FUNCTION__);
mISDN_freechannel(hc->dch);
kfree(hc->dch);
hc->dch = NULL;
}
ch = 0;
while(ch < LOOP_CHANNELS) {
if (hc->bch[ch]) {
if (debug & DEBUG_LOOP_INIT)
printk(KERN_DEBUG "%s: free B-channel %d\n", __FUNCTION__, ch);
mISDN_freechannel(hc->bch[ch]);
kfree(hc->bch[ch]);
hc->bch[ch] = NULL;
}
ch++;
}
/* remove us from list and delete */
if (debug & DEBUG_LOOP_INIT)
printk(KERN_WARNING "%s: remove instance from list\n", __FUNCTION__);
spin_lock_irqsave(&loop_obj.lock, flags);
list_del(&hc->list);
spin_unlock_irqrestore(&loop_obj.lock, flags);
if (debug & DEBUG_LOOP_INIT)
printk(KERN_WARNING "%s: delete instance\n", __FUNCTION__);
kfree(hc);
loop_cnt--;
if (debug & DEBUG_LOOP_INIT)
printk(KERN_WARNING "%s: card successfully removed\n", __FUNCTION__);
}
static int
loop_manager(void *data, u_int prim, void *arg)
{
loop_t *hc;
mISDNinstance_t *inst = data;
struct sk_buff *skb;
channel_t *dch = NULL;
channel_t *bch = NULL;
int ch = 0;
u_long flags;
if (!data) {
MGR_HASPROTOCOL_HANDLER(prim,arg,&loop_obj)
printk(KERN_ERR "%s: no data prim %x arg %p\n", __FUNCTION__, prim, arg);
return(-EINVAL);
}
/* find channel and card */
spin_lock_irqsave(&loop_obj.lock, flags);
list_for_each_entry(hc, &loop_obj.ilist, list) {
if (hc->dch) if (&hc->dch->inst == inst) {
dch = hc->dch;
spin_unlock_irqrestore(&loop_obj.lock, flags);
if (debug & DEBUG_LOOP_MGR)
printk(KERN_DEBUG "%s: D-channel data %p prim %x arg %p\n", __FUNCTION__, data, prim, arg);
goto found;
}
ch = 0;
while(ch < LOOP_CHANNELS) {
if (hc->bch[ch]) if (&hc->bch[ch]->inst == inst) {
bch = hc->bch[ch];
spin_unlock_irqrestore(&loop_obj.lock, flags);
if (debug & DEBUG_LOOP_MGR)
printk(KERN_DEBUG "%s: B-channel %d (0..%d) data %p prim %x arg %p\n", __FUNCTION__, ch, LOOP_CHANNELS-1, data, prim, arg);
goto found;
}
}
}
spin_unlock_irqrestore(&loop_obj.lock, flags);
printk(KERN_ERR "%s: no card/channel found data %p prim %x arg %p\n", __FUNCTION__, data, prim, arg);
return(-EINVAL);
found:
switch(prim) {
case MGR_REGLAYER | CONFIRM:
if (debug & DEBUG_LOOP_MGR)
printk(KERN_DEBUG "%s: MGR_REGLAYER\n", __FUNCTION__);
mISDN_setpara(dch, &inst->st->para);
break;
case MGR_UNREGLAYER | REQUEST:
if (debug & DEBUG_LOOP_MGR)
printk(KERN_DEBUG "%s: MGR_UNREGLAYER\n", __FUNCTION__);
if (dch) {
if ((skb = create_link_skb(PH_CONTROL | REQUEST, HW_DEACTIVATE, 0, NULL, 0))) {
if (loop_l1hw(inst, skb)) dev_kfree_skb(skb);
}
} else
if (bch) {
if ((skb = create_link_skb(PH_CONTROL | REQUEST, 0, 0, NULL, 0))) {
if (loop_l2l1(inst, skb)) dev_kfree_skb(skb);
}
}
mISDN_ctrl(inst, MGR_UNREGLAYER | REQUEST, NULL);
break;
case MGR_CLRSTPARA | INDICATION:
arg = NULL;
// fall through
case MGR_ADDSTPARA | INDICATION:
if (debug & DEBUG_LOOP_MGR)
printk(KERN_DEBUG "%s: MGR_***STPARA\n", __FUNCTION__);
mISDN_setpara(dch, arg);
break;
case MGR_RELEASE | INDICATION:
if (debug & DEBUG_LOOP_MGR)
printk(KERN_DEBUG "%s: MGR_RELEASE = remove port from mISDN\n", __FUNCTION__);
if (dch) {
loop_delete(hc); /* hc is free */
}
break;
#ifdef FIXME
case MGR_CONNECT | REQUEST:
if (debug & DEBUG_LOOP_MGR)
printk(KERN_DEBUG "%s: MGR_CONNECT\n", __FUNCTION__);
return(mISDN_ConnectIF(inst, arg));
case MGR_SETIF | REQUEST:
case MGR_SETIF | INDICATION:
if (debug & DEBUG_LOOP_MGR)
printk(KERN_DEBUG "%s: MGR_SETIF\n", __FUNCTION__);
if (dch)
return(mISDN_SetIF(inst, arg, prim, loop_l1hw, NULL, dch));
if (bch)
return(mISDN_SetIF(inst, arg, prim, loop_l2l1, NULL, bch));
break;
case MGR_DISCONNECT | REQUEST:
case MGR_DISCONNECT | INDICATION:
if (debug & DEBUG_LOOP_MGR)
printk(KERN_DEBUG "%s: MGR_DISCONNECT\n", __FUNCTION__);
return(mISDN_DisConnectIF(inst, arg));
#endif
#if 0
case MGR_SELCHANNEL | REQUEST:
if (debug & DEBUG_LOOP_MGR)
printk(KERN_DEBUG "%s: MGR_SELCHANNEL\n", __FUNCTION__);
if (!dch) {
printk(KERN_WARNING "%s(MGR_SELCHANNEL|REQUEST): selchannel not dinst\n", __FUNCTION__);
return(-EINVAL);
}
return(SelFreeBChannel(hc, ch, arg));
#endif
case MGR_SETSTACK | INDICATION:
if (debug & DEBUG_LOOP_MGR)
printk(KERN_DEBUG "%s: MGR_SETSTACK\n", __FUNCTION__);
if (bch && inst->pid.global==2) {
if ((skb = create_link_skb(PH_ACTIVATE | REQUEST, 0, 0, NULL, 0))) {
if (loop_l2l1(inst, skb)) dev_kfree_skb(skb);
}
if (inst->pid.protocol[2] == ISDN_PID_L2_B_TRANS)
mISDN_queue_data(inst, FLG_MSG_UP, DL_ESTABLISH | INDICATION, 0, 0, NULL, 0);
else mISDN_queue_data(inst, FLG_MSG_UP, PH_ACTIVATE | INDICATION, 0, 0, NULL, 0);
}
break;
PRIM_NOT_HANDLED(MGR_CTRLREADY | INDICATION);
PRIM_NOT_HANDLED(MGR_GLOBALOPT | REQUEST);
default:
printk(KERN_WARNING "%s: prim %x not handled\n", __FUNCTION__, prim);
return(-EINVAL);
}
return(0);
}
/*************************
* create cards instance *
*************************/
static int __devinit loop_new(void)
{
int ret_err=0;
int ch;
loop_t *hc;
mISDN_pid_t pid;
mISDNstack_t *dst = NULL; /* make gcc happy */
channel_t *dch;
channel_t *bch;
u_long flags;
if (debug & DEBUG_LOOP_INIT)
printk(KERN_DEBUG "%s: Registering loop driver #%d\n", __FUNCTION__, loop_cnt+1);
/* allocate structure */
if (!(hc = kmalloc(sizeof(loop_t), GFP_ATOMIC))) {
printk(KERN_ERR "No kmem for loop driver\n");
ret_err = -ENOMEM;
goto free_object;
}
memset(hc, 0, sizeof(loop_t));
hc->idx = loop_cnt;
hc->id = loop_cnt + 1;
sprintf(hc->name, "LOOP#%d", loop_cnt+1);
if (debug & DEBUG_LOOP_INIT)
printk(KERN_DEBUG "%s: (after APPEND_TO_LIST)\n", __FUNCTION__);
spin_lock_irqsave(&loop_obj.lock, flags);
list_add_tail(&hc->list, &loop_obj.ilist);
spin_unlock_irqrestore(&loop_obj.lock, flags);
if (debug & DEBUG_LOOP_INIT)
printk(KERN_DEBUG "%s: (after APPEND_TO_LIST)\n", __FUNCTION__);
spin_lock_init(&hc->lock);
if (debug & DEBUG_LOOP_INIT)
printk(KERN_DEBUG "%s: Registering D-channel, card(%d)\n", __FUNCTION__, loop_cnt+1);
dch = kmalloc(sizeof(channel_t), GFP_ATOMIC);
if (!dch) {
ret_err = -ENOMEM;
goto free_channels;
}
memset(dch, 0, sizeof(channel_t));
dch->channel = 0;
//dch->debug = debug;
dch->inst.obj = &loop_obj;
dch->inst.hwlock = &hc->lock;
mISDN_init_instance(&dch->inst, &loop_obj, hc, loop_l1hw);
dch->inst.pid.layermask = ISDN_LAYER(0);
sprintf(dch->inst.name, "LOOP%d", loop_cnt+1);
if (mISDN_initchannel(dch, MSK_INIT_DCHANNEL, MAX_DATA_MEM)) {
ret_err = -ENOMEM;
goto free_channels;
}
hc->dch = dch;
ch=0;
while(ch < LOOP_CHANNELS) {
if (debug & DEBUG_LOOP_INIT)
printk(KERN_DEBUG "%s: Registering B-channel, card(%d) ch(%d)\n", __FUNCTION__, loop_cnt+1, ch);
bch = kmalloc(sizeof(channel_t), GFP_ATOMIC);
if (!bch) {
ret_err = -ENOMEM;
goto free_channels;
}
memset(bch, 0, sizeof(channel_t));
bch->channel = ch;
mISDN_init_instance(&bch->inst, &loop_obj, hc, loop_l2l1);
bch->inst.pid.layermask = ISDN_LAYER(0);
bch->inst.hwlock = &hc->lock;
//bch->debug = debug;
sprintf(bch->inst.name, "%s B%d",
dch->inst.name, ch+1);
if (mISDN_initchannel(bch, MSK_INIT_BCHANNEL, MAX_DATA_MEM)) {
kfree(bch);
ret_err = -ENOMEM;
goto free_channels;
}
hc->bch[ch] = bch;
#ifdef FIXME // TODO
if (bch->dev) {
bch->dev->wport.pif.func = loop_l2l1;
bch->dev->wport.pif.fdata = bch;
}
#endif
ch++;
}
/* set D-channel */
mISDN_set_dchannel_pid(&pid, 0x00, ISDN_LAYER(0));
pid.protocol[0] = ISDN_PID_L0_LOOP;
pid.layermask = ISDN_LAYER(0);
/* add stacks */
if (debug & DEBUG_LOOP_INIT)
printk(KERN_DEBUG "%s: Adding d-stack: card(%d)\n", __FUNCTION__, loop_cnt+1);
if ((ret_err = mISDN_ctrl(NULL, MGR_NEWSTACK | REQUEST, &dch->inst))) {
printk(KERN_ERR "MGR_ADDSTACK REQUEST dch err(%d)\n", ret_err);
free_release:
loop_delete(hc); /* hc is free */
goto free_object;
}
dst = dch->inst.st;
ch = 0;
while(ch < LOOP_CHANNELS) {
if (debug & DEBUG_LOOP_INIT)
printk(KERN_DEBUG "%s: Adding b-stack: card(%d) B-channel(%d)\n", __FUNCTION__, loop_cnt+1, ch+1);
bch = hc->bch[ch];
if ((ret_err = mISDN_ctrl(dst, MGR_NEWSTACK | REQUEST, &bch->inst))) {
printk(KERN_ERR "MGR_ADDSTACK bchan error %d\n", ret_err);
free_delstack:
mISDN_ctrl(dst, MGR_DELSTACK | REQUEST, NULL);
goto free_release;
}
ch++;
}
if (debug & DEBUG_LOOP_INIT)
printk(KERN_DEBUG "%s: (before MGR_SETSTACK REQUEST) layermask=0x%x\n", __FUNCTION__, pid.layermask);
if ((ret_err = mISDN_ctrl(dst, MGR_SETSTACK | REQUEST, &pid))) {
printk(KERN_ERR "MGR_SETSTACK REQUEST dch err(%d)\n", ret_err);
goto free_delstack;
}
if (debug & DEBUG_LOOP_INIT)
printk(KERN_DEBUG "%s: (after MGR_SETSTACK REQUEST)\n", __FUNCTION__);
/* delay some time */
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((100*HZ)/1000); /* Timeout 100ms */
/* tell stack, that we are ready */
mISDN_ctrl(dst, MGR_CTRLREADY | INDICATION, NULL);
loop_cnt++;
return(0);
/* if an error ocurred */
free_channels:
if (hc->dch) {
if (debug & DEBUG_LOOP_INIT)
printk(KERN_DEBUG "%s: free D-channel\n", __FUNCTION__);
mISDN_freechannel(hc->dch);
kfree(hc->dch);
hc->dch = NULL;
}
ch = 0;
while(ch < LOOP_CHANNELS) {
if (hc->bch[ch]) {
if (debug & DEBUG_LOOP_INIT)
printk(KERN_DEBUG "%s: free B-channel %d\n", __FUNCTION__, ch);
mISDN_freechannel(hc->bch[ch]);
kfree(hc->bch[ch]);
hc->bch[ch] = NULL;
}
ch++;
}
if (debug & DEBUG_LOOP_INIT)
printk(KERN_DEBUG "%s: before REMOVE_FROM_LIST (refcnt = %d)\n", __FUNCTION__, loop_obj.refcnt);
spin_lock_irqsave(&loop_obj.lock, flags);
list_del(&hc->list);
spin_unlock_irqrestore(&loop_obj.lock, flags);
if (debug & DEBUG_LOOP_INIT)
printk(KERN_DEBUG "%s: after REMOVE_FROM_LIST (refcnt = %d)\n", __FUNCTION__, loop_obj.refcnt);
kfree(hc);
free_object:
return(ret_err);
}
static void __exit
loop_cleanup(void)
{
loop_t *hc,*next;
int err;
/* unregister mISDN object */
if (debug & DEBUG_LOOP_INIT)
printk(KERN_DEBUG "%s: entered (refcnt = %d loop_cnt = %d)\n", __FUNCTION__, loop_obj.refcnt, loop_cnt);
if ((err = mISDN_unregister(&loop_obj))) {
printk(KERN_ERR "Can't unregister Loop cards error(%d)\n", err);
}
/* remove remaining devices, but this should never happen */
if (debug & DEBUG_LOOP_INIT)
printk(KERN_DEBUG "%s: now checking ilist (refcnt = %d)\n", __FUNCTION__, loop_obj.refcnt);
list_for_each_entry_safe(hc, next, &loop_obj.ilist, list) {
printk(KERN_ERR "Loop card struct not empty refs %d\n", loop_obj.refcnt);
loop_delete(hc);
}
if (debug & DEBUG_LOOP_INIT)
printk(KERN_DEBUG "%s: done (refcnt = %d loop_cnt = %d)\n", __FUNCTION__, loop_obj.refcnt, loop_cnt);
}
static int __init
loop_init(void)
{
int err;
char tmpstr[64];
if (debug & DEBUG_LOOP_INIT)
printk(KERN_DEBUG "%s: init entered\n", __FUNCTION__);
strcpy(tmpstr, loop_revision);
printk(KERN_INFO "mISDN: loop-driver Rev. %s\n", mISDN_getrev(tmpstr));
memset(&loop_obj, 0, sizeof(loop_obj));
#ifdef MODULE
loop_obj.owner = THIS_MODULE;
#endif
spin_lock_init(&loop_obj.lock);
INIT_LIST_HEAD(&loop_obj.ilist);
loop_obj.name = LoopName;
loop_obj.own_ctrl = loop_manager;
loop_obj.DPROTO.protocol[0] = ISDN_PID_L0_LOOP;
loop_obj.BPROTO.protocol[1] = ISDN_PID_L1_B_64TRANS | ISDN_PID_L1_B_64HDLC;
loop_obj.BPROTO.protocol[2] = ISDN_PID_L2_B_TRANS | ISDN_PID_L2_B_RAWDEV;
if (debug & DEBUG_LOOP_INIT)
printk(KERN_DEBUG "%s: registering loop_obj\n", __FUNCTION__);
if ((err = mISDN_register(&loop_obj))) {
printk(KERN_ERR "Can't register Loop cards error(%d)\n", err);
return(err);
}
if (debug & DEBUG_LOOP_INIT)
printk(KERN_DEBUG "%s: new mISDN object (refcnt = %d)\n", __FUNCTION__, loop_obj.refcnt);
if (interfaces < 1)
interfaces = 1;
loop_cnt = 0;
while(loop_cnt < interfaces)
{
if ((err = loop_new()))
break;
}
if (err)
{
printk(KERN_ERR "error registering pci driver:%x\n",err);
loop_cleanup();
return(err);
}
printk(KERN_INFO "%d devices registered\n", loop_cnt);
return(0);
}
#ifdef MODULE
module_init(loop_init);
module_exit(loop_cleanup);
#endif

Some files were not shown because too many files have changed in this diff Show More