Compare commits

...

67 Commits

Author SHA1 Message Date
Russ Meyerriecks
ce3f1f2650 wcte13xp: Workaround rare nmi on modprobe on select systems
With certain pci controllers that support pci hotplug, during the reset
sequence of the fpga, the host controller can get confused about the state of
the card and throw an nmi.

Known affected systems:
 HP proliant DL160 & DL360p
 Dell poweredge R520
 Super Micro X7SPA-HF

This patch attempts to work around that by removing the fpga reset sequence
from the driver startup, then setting various control registers to known
starting state values.

This patch removes the field upgradeable firmware logic temporarily for the
te133 card to prevent fpga reset.

Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2013-08-16 15:28:24 -05:00
Oron Peled
2ad4dc555f xpp: fix waitfor_xpds race at startup
* If userspace would run
    modprobe xpp_usb && cat /sys/bus/astribanks/devices/xbus-00/waitfor_xpds
  it would return immediately rather than wait for the Astribank to
  initialize.
* We sometimes managed to read before getting the reply from the
  astribank.
* Now we don't trust unit count at such an early stage.
* Instread we wait for the Astribank to reach a stable state (READY or FAIL)
  before finish waiting for this astribank.

Internal-Issue-ID: Xorcom-1502
Signed-off-by: Tzafrir Cohen <tzafrir.cohen@xorcom.com>
2013-07-30 15:04:00 +03:00
Shaun Ruffell
0469efb733 build_tools/make_version: Fix typo in build_tools/make_version.
The make_version script would test for a .version file in the proper location,
but then would not properly read it. Since make_version is always reading the
.version script correctly now, the Makefile can be slightly simpilfied and
always defer to it.

This has no user impact since build_tools/make_version was never used to read
the .version file previously but will allow external scripts to use the
make_version script.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2013-06-26 14:32:15 -05:00
Oron Peled
8ea23535dc sysfs: bugfix: shorten too long file names
* In old kernels (e.g: 2.6.18) sysfs file names must be shorter
  then KOBJ_NAME_LEN.

* Longer names are truncated and this leads to duplicate names
  which fails device_register()
  Examples: "dahdi!channels!10!10" is truncated to "dahdi!channels!10!1"

* The fix shorten the names and make them fixed length. Example:
            "dahdi!chan!010!010"

* It seems no current userspace tools rely on that name or on
  /dev/dahdi/channels .

Signed-off-by: Tzafrir Cohen <tzafrir.cohen@xorcom.com>
2013-06-23 22:12:33 +03:00
Russ Meyerriecks
431571b5fc wcte13xp: Start the span in unconfigured, instead of red state
This was causing inconsistancies with dahdi_scan showing an "UNCONFIGURED" span
in the "RED" state.

Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2013-06-14 14:55:37 -05:00
Shaun Ruffell
ab927f796b dahdi: Do not set rxbufpolicy when opening dahdi net device.
This fixes a regression introduced in 2.7.0 in commit
(da8b96d725 "dahdi: Remove unused 'rxbufpolicy'
and 'rxdisable' from dahdi_chan.") when CONFIG_DAHDI_NET is defined in
include/dahdi/dahdi_config.h.

rxbufpolicy was always hardcoded to immediate policy and was removed from the
channel structure. There is no longer any need to set it in dahdi_net_open.

Reported-by: Dave Fullerton <dfullertasterisk@shorelinecontainer.com>
Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2013-06-11 10:25:10 -05:00
Shaun Ruffell
040ba6f43a wctc4xxp: Ensure the descriptors are zeroed out on start.
If system conditions prevent the card from loading the firmware without
touching all the descriptors in the ring, it's possible for
wctc4xxp_cleanup_descriptor_ring to attempt cleanup of a command that was never
submitted resulting in the following BUG.

  wctc4xxp 0000:02:0a.0: Failed to load firmware.
  BUG: unable to handle kernel paging request at c109556c
  IP: [<f9faa83e>] wctc4xxp_cleanup_descriptor_ring+0x8c/0x148 [wctc4xxp]

Reported-by: Xavier Carcelle <xcarcelle@avencall.com>
Signed-off-by: Shaun Ruffell <sruffell@digium.com>
2013-05-31 12:10:49 -05:00
Russ Meyerriecks
e2f492595c wcte13xp: New driver for digium's te13x product range
This patch adds support for Digium's new single span T1/E1 cards with built-in
octasic echo canceler.

PCI IDs:
d161:800a te133 - pci express
d161:800b te134 - pci

Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2013-05-28 16:53:38 -05:00
Shaun Ruffell
1f20b5f8fa xpp: Don't use create_proc_read_entry()
Don't use create_proc_read_entry() as that is deprecated, but rather use
proc_create_data() and seq_file instead.

This is needed to compile against Linux 3.10.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
[tzafrir.cohen@xorcom.com: fixed passing /proc/xpp/XPD/summary xbus number]
Acked-by: Tzafrir Cohen <tzafrir.cohen@xorcom.com>
Cc: Russ Meyerriecks <rmeyerriecks@digium.com>
Cc: Oron Peled <oron.peled@xorcom.com>
2013-05-24 00:30:33 +03:00
Shaun Ruffell
ba2fdf2dac dahdi_dynamic_ethmf: Don't use create_proc_read_entry()
Don't use create_proc_read_entry() as that is deprecated, but rather use
proc_create_data() and seq_file instead.

This is needed to compile against Linux 3.10.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Acked-by: Tzafrir Cohen <tzafrir.cohen@xorcom.com>
Cc: Russ Meyerriecks <rmeyerriecks@digium.com>
Cc: Oron Peled <oron.peled@xorcom.com>
2013-05-24 00:30:33 +03:00
Shaun Ruffell
84ccc652b6 dahdi: Replace create_proc_entry() with proc_create_data()
create_proc_entry() was deprecated and replace with proc_create_data() since
it's open to a race condition where the proc entry is visible before the file
operations have been set for it.

The PDE() macro also is no longer available as of Linux 3.10 and is replaced
with PDE_DATA() to get the data member from a proc entry. This is due to the
fact that 'struct proc_dir_entry' is now private to the proc_fs.

This commit changes the core of DAHDI and also introduces proc_create_data() and
PDE_DATA() for older kernels.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Acked-by: Tzafrir Cohen <tzafrir.cohen@xorcom.com>
Cc: Russ Meyerriecks <rmeyerriecks@digium.com>
Cc: Oron Peled <oron.peled@xorcom.com>
2013-05-24 00:30:33 +03:00
Tzafrir Cohen
40da50faed xpp: FXO: fix firmware pol-rev detection
PIC_TYPE_2 rev. 11078 fixes the polarity reversal detection support added
in rev. 11039 (949aa4958f).

Signed-off-by: Tzafrir Cohen <tzafrir.cohen@xorcom.com>
2013-05-23 14:50:31 +03:00
Oron Peled
ef71ce476c xpp: FXO: add a "squelch_polrev" parameter
* This will prevent *ANY* polarity reversal reporting to DAHDI.
* False by default.
* Used in some rare sites with really bad line quality.

Signed-off-by: Tzafrir Cohen <tzafrir.cohen@xorcom.com>
2013-05-23 14:50:30 +03:00
Oron Peled
e3e35d031d xpp: FXO: common function for POLREV reporting
Refactor the XPP FXO POLREV reporting into a common function.

Signed-off-by: Tzafrir Cohen <tzafrir.cohen@xorcom.com>
2013-05-23 14:50:30 +03:00
Shaun Ruffell
2b0cca777f oct612x: Fix confusing compile error when kernel source is not present
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2013-05-20 17:19:55 -05:00
Shaun Ruffell
96652d88c6 wcte12xp: Reset all the framer registers when switching linemodes.
If a span was fully configured before unassigning and reassigning to a new span
type it was possible for stale values to be present in the register. When
switching from T1 to E1 via the spantype sysfs attribute this could result in a
test pattern being written.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2013-05-20 17:11:21 -05:00
Shaun Ruffell
c4a17f9442 wcte12xp: Allow non-interrupting cards to unload faster.
If a card stops generating interrupts for any reason, it can take awhile to
unload the driver while waiting for the commands to timeout. Now if there is a
problem, immediately set a bit that the card is failed so that no new commands
will be submitted.

Also, do not free and commands in submit since all commands are freed in get
results now. This prevents list/memory corruption when commands time out.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2013-05-20 17:11:21 -05:00
Shaun Ruffell
9b11847aee dahdi: Completely stop spans when unassigning.
When spans are unassigned, dahdi_span_ops.shutdown was called, but the RUNNING
flag was never cleared. Now make sure all calls to the shutdown span ops
callback are the same.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2013-05-20 17:11:21 -05:00
Shaun Ruffell
a3ad32c370 dahdi: Prevent potential error when only switching spantype of single span.
If you have a multiple span system configured for t1 mode, and you try to change
only the first span from t1 to e1 via sysfs, you could get an error in the
kernel log about trying to create duplicate channel.

The problem is that the check for whether there was enough room for the all the
channels of the switched span was wrong.

Reported-by: James Brown <jbrown@digium.com>
Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2013-05-13 14:34:49 -05:00
Shaun Ruffell
9a7db0943b wcte12xp: Look for multiple loopup codes before setting looping up the framer.
This brings the wcte12xp driver in line with the wct4xxp driver. It also
eliminates the chance that the local side will errouneously go into loopup when
switched from E1 to T1 mode via the spantype sysfs attribute.

Internal-Issue-ID: DAHDI-1038
Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2013-05-13 14:34:49 -05:00
Shaun Ruffell
db040e5cd7 wct4xxp: Allow vpm450m.c to compile against vanilla 2.6.18.
This adds definitions for bool and pr_fmt which are needed when compiling
against vanilla 2.6.18.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2013-05-09 12:53:21 -05:00
Shaun Ruffell
244f621eb1 wctdm24xxp: Fix FXO failure to detect battery CO disconnects.
In 2.6.2 I introduced an error in (41639330a "wctdm24xxp: Eliminate chance for
channel to be stuck in RED alarm.") which would get an FXO stuck in detecting an
ONHOOK event from the remote side.  An FXO port could go into the
BATTERY_DEBOUNCING_LOST_ALARM state and then back to the BATTERY_PRESENT state
without sending the dahdi_hooksig up to Asterisk.  Therefore, Asterisk would
never detect the state changes needed for a remote side disconnect.

This change adds two more states, BATTERY_DEBOUNCING_PRESENT_FROM_LOST_ALARM and
BATTERY_DEBOUNCING_LOST_FROM_PRESENT_ALARM so that the state machine does not
miss any needed transitions when going back to BATTERY_PRESENT or BATTERY_LOST
regardless of why the debounce was started.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2013-05-09 11:35:04 -05:00
Shaun Ruffell
bb5eeccef3 dahdi: Prevent memory corruption on device unload.
The channels now have embedded 'struct devices' that contain a device_private
pointer in which to store the device private data. When a device is
unregistered in the system the device privata data is freed by the device core,
even though the chan_release function doesn't free the memory
associated with the device, So when dev_set_drvdata() is called,
it's writing into freed memory.

We also need zero out the embedded struct device before registration,
since we do not have any guarantee that it points to valid memory (or, if a
channel was unregisterd with sysfs, and then reregistered without being cleared
out).  Otherwise the core could try to use the previously freed private
data again.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2013-05-08 11:48:28 -05:00
Shaun Ruffell
4641d5b396 wct4xxp: Companding on VPM needs to be changed when switching linemodes.
If a user switches linemode with sysfs, the VPM would never switch the
companding mode to alaw, and the result would be extreme static on all channels
of the span when the VPM is enabeld.

Now if the deflaw of the span has changed when an echocan is created, the
companding mode of the VPM channel is changed.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
2013-05-06 15:42:33 -05:00
Shaun Ruffell
f65299e8b2 oct612x: Break the oct612x out into a separate library.
Soon there will be more than one driver in the source tree that will want to use
these files. Compiling it as a library speeds the build since it won't have to
be built for each driver that wants to link it in.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2013-05-06 15:42:33 -05:00
Shaun Ruffell
f4d9cbbfb1 dahdi: Save the current maintstat in the span before calling into the drivers.
Some of the card callbacks needed maintstat set when processing loopup codes
from the remote side. This change is a modification of commit: (6c02c3c
"dahdi-base: Minor maint mode error")

Without this change cetain cards would not properly process the loopup /
loopdown codes (I know I should have more specific information here but the
details escape me at the moment).

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
2013-05-06 15:42:33 -05:00
Russ Meyerriecks
a8788692a1 dahdi: Do not define trace_printk if CONFIG_TRACING is not defined.
This was an accidental commit that slipped in as part of (a682401 "dahdi: Expose
dahdi devices in sysfs.")

Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
Signed-off-by: Shaun Ruffell <sruffell@digium.com>
2013-05-06 15:42:33 -05:00
Tzafrir Cohen
be904538c7 README: xpp: xpd_fxo param use_polrev_firmware
Signed-off-by: Tzafrir Cohen <tzafrir.cohen@xorcom.com>
2013-04-11 10:00:48 -05:00
Tzafrir Cohen
76dda31533 README: xpp: xpd_fxo: new value of caller_id_style
Signed-off-by: Tzafrir Cohen <tzafrir.cohen@xorcom.com>
2013-04-11 10:00:48 -05:00
Tzafrir Cohen
8f07b4e019 Copy xpp module docs from README.Astribank
Copy xpp module documenttation from README.Astribank in dahdi-tools.

Signed-off-by: Tzafrir Cohen <tzafrir.cohen@xorcom.com>
2013-04-11 10:00:48 -05:00
Tzafrir Cohen
9c031f66a0 README: subsections for module parameters docs
Signed-off-by: Tzafrir Cohen <tzafrir.cohen@xorcom.com>
2013-04-11 10:00:48 -05:00
Oron Peled
300446b1a1 xpp: FXO: new CID style -- passthrough
Adds support for setting a value of 3 to the module parameter
caller_id_style: passthrough - always pass and don't try to emulate
DTMFs.

Signed-off-by: Tzafrir Cohen <tzafrir.cohen@xorcom.com>
2013-03-28 21:06:47 +02:00
Oron Peled
949aa4958f xpp: FXO: in-firmware polarity-reversal detection
PIC_TYPE_2 rev.11039 adds support for polarity reversal detection. Support
those messages.

Signed-off-by: Tzafrir Cohen <tzafrir.cohen@xorcom.com>
2013-03-28 21:06:34 +02:00
Russ Meyerriecks
a34b846f61 dahdi: Fix unused variable compile warning
An unset conditional compile flag was triggering the unused variable compile
warning. Added the condition around the variable define.

Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2013-03-13 16:52:03 -05:00
Russ Meyerriecks
f09daed735 Kbuild: Fix OSLEC build error
Fixes up the kbuild to work with compiling OSLEC from the kernel source. See
HOWTO here: http://forums.digium.com/viewtopic.php?t=67164

Internal-Issue-ID: DAHLIN-317
Reported-By: Vladimir Mikhelson
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2013-03-13 16:51:53 -05:00
Shaun Ruffell
7714d5d94e build_tools/make_version: Only strip 'v' if followed by a digit.
Do not want to accidentally change the tag "very_cool" to "ery_cool".

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
2013-03-08 12:09:18 -06:00
Shaun Ruffell
9b0d19c054 build_tools/make_version: Strip off the leading 'v' in the version string.
Quote: "It's a change. People hate change"

Make the version string say something like 2.6.2 instead of v2.6.2.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
2013-03-08 11:30:44 -06:00
Shaun Ruffell
d5e5b19a02 dahdi: Tear down conference links when conferences are emptied out.
Otherwise, it's possible for a link to remain in use if a process quits without
unlinking the conferences. Now when all the channels are removed from the
conference, any links are also cleaned up.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
2013-03-07 16:19:05 -06:00
Shaun Ruffell
a4feafc124 dahdi: Restore DAHDI_CONFLINK functionality as compile time option.
This is mostly a revert of commit r9463. If you need to use DAHDI_CONFLINK
ioctl, make sure to define CONFIG_DAHDI_CONFLINK in
include/dahdi/dahdi_config.h. Apparently there were some users of CONFLINK out
there still.

It's a compile time option now since most users won't need to run the test for
conflinks in the hot-path that is the process_masterspan function.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Tested-by: Ted Gerold <ted@twg.org>
2013-03-07 16:19:05 -06:00
Shaun Ruffell
0498450db0 dahdi: Give timers their own file_operations
Trades the memory of a file_operations structure to eliminate some tests in the
timer operations.

Internal-Issue-ID: ABE-2904
Signed-off-by: Shaun Ruffell <sruffell@digium.com>
2013-03-07 16:19:05 -06:00
Shaun Ruffell
b6f6232441 dahdi: Decrease dahdi_timer_lock contention.
On SMP systems there isn't a need for all dahdi timers to
synchronize on dahdi_timer_lock. Instead give each timer it's own
lock to synchronize with process_timers and use dahdi_timer_lock to
protect the global list of locks.

Also, the dahdi_timers list now only contains timers that are set to
fire. This eliminates a test for each timer in the hot path of the
process_masterspan context.

Reduces system load on many-core systems which are heavy users of
DAHDI timers.

Internal-Issue-ID: ABE-2904
Signed-off-by: Shaun Ruffell <sruffell@digium.com>
2013-03-07 16:19:05 -06:00
Shaun Ruffell
37a783b0fe dahdi: Remove call to lock_kernel when calling unlocked_ioctl.
The Big Kernel Lock removal is no longer experimental so we can eliminate the
call to lock_kernel when calling unlock_ioctl.

Internal-Issue-ID: ABE-2904
Signed-off-by: Shaun Ruffell <sruffell@digium.com>
2013-03-07 16:19:05 -06:00
Shaun Ruffell
37371f19e9 build_tools/make_version: If making from a tag show only the tag in the version.
Also, if there is no other version information use the directory name. Downloads
from gitweb will include the sha information in the build and otherwise a user
could locate the source directory via the embedded version information. I
believe this is better than an empty string.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
2013-03-07 16:17:48 -06:00
Tzafrir Cohen
66a300f338 Redefine the removed __dev* for now
The __dev* directives and functions were removed in 3.8, as they
are no-ops. We still have use of them for older versions, thus
we should define them (as noops) if they don't exist.

Signed-off-by: Tzafrir Cohen <tzafrir.cohen@xorcom.com>
2013-01-28 10:18:56 -06:00
Shaun Ruffell
8bf0434896 wctdm24xxp: Eliminate chance for channel to be stuck in RED alarm.
There was a code patch where it was possible to get stuck in RED ALARM on a
channel when debouncing the battery states. The state transitions would look
like this:

BATTERY_PRESENT -> BATTERY_DEBOUNCING_LOST -> BATTERY_DEBOUNCING_LOST_ALARM --
(send alarm up to asterisk) --> BATTERY_LOST -> BATTERY_DEBOUNCING_PRESENT ->
BATTERY_DEBOUNCING_PRESENT_ALARM -> BATTERY_DEBOUNCING_LOST -> BATTERY_PRESENT

In the above sequence there was never any transition from
BATTERY_DEBOUNCING_PRESENT_ALARM to BATTERY_PRESENT so the alarm to Asterisk was
never cleared and the channel stayed stuck.

Now when you loose battery when in the BATTERY_DEBOUNCING_PRESENT_ALARM go all
the way back to the BATTERY_LOST state instead of the BATTERY_DEBOUNCING_LOST
state so that all the events are properly sent up.

This fixes a regression introduced in 2.6.0 with commit (r10169 "wctdm24xxp: Use
interval for debouncing FXO battery." 874b76bd22).

Internal-Issue-ID: DAHDI-1019
Signed-off-by: Shaun Ruffell <sruffell@digium.com>
2013-01-25 11:43:54 -06:00
Shaun Ruffell
a6be603590 wctdm24xxp: Use framecount and not jiffies when looking for battery present.
The logic to check for battery lost and battery present were using different
time bases. One was using jiffies and the other was using framecount. Since
framecount is always in milliseconds, let's use that to stay consistent.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
2013-01-25 11:43:52 -06:00
Shaun Ruffell
85e6cdde83 wcb4xxp: Allocate memory in hfc_decode_st_state() with GFP_ATOMIC.
hfc_decode_st_state() will be called from interrupt context when the debug flag
is set to 32. Therefore, must use GFP_ATOMIC when allocating memory.

Only affects the wcb4xxp driver when called with particular debug flags set.

Internal-Issue-ID: DAHLIN-314
Reported-by: Gerald Schnabel
Signed-off-by: Shaun Ruffell <sruffell@digium.com>
2013-01-23 16:14:07 -06:00
Shaun Ruffell
69fb09d011 dahdi: Initialize the channels cdev structure.
This is necessary to prevent a crash when opening files by the new
device files, which do not have a valid file_operations structure.
This fixes a problem does not exist in any releases of DAHDI.

Since none of the existing tools or applications open files from the
new location of /dev/dahdi/channels/<span>/<offset>, this wasn't
seen until just recently.

Reported-by: Ted Gerold <ted@twg.org>
Signed-off-by: Shaun Ruffell <sruffell@digium.com>
2013-01-22 10:08:02 -06:00
Shaun Ruffell
da0aa6f231 xpp: Do not typedef bool on RHEL 5.2 or later.
Without digging into the specifics, it looks like Red Hat Linux 5.9
removed the hex_asc definition that was previously used to determine
if the bool definition was backported.

We can simply use the RHEL_RELEASE_CODE now since we do not support any
releases before the 5 series now.

Reported-By: Vladimir Mikhelson
Internal-Issue-ID: DAHLIN-312
Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Acked-By: Tzafrir Cohen <tzafrir.cohen@xorcom.com>
2013-01-22 10:05:23 -06:00
Tzafrir Cohen
a46f906a0d Only use bus and no class for channel devices
It's wrong (and explicit oops with kernel >= 2.6.19) to set both
bus and class for the same device. But setting the class is not needed
in order to create a device. So just remove our dynamic devices from the
dahdi_class. It will only contain the fixed-named devices.

This fixes regression from cb4e4d0068.

Signed-off-by: Tzafrir Cohen <tzafrir.cohen@xorcom.com>
2012-12-21 13:36:51 -06:00
Shaun Ruffell
9de213b104 wct4xxp: t4_serial_setup() was called more often than necessary.
The driver iterates through all the spans on a given device during assignment,
checking for unassigned spans, but it was erroneously testing the span on which
assigned was called.

This just removes some unexpected behavior and provides a slight performance
increase on load and does not impact the functionality of the driver as far as
I'm aware.

Reported-by: Doug Bailey <dbailey@digium.com>
Signed-off-by: Shaun Ruffell <sruffell@digium.com>
2012-12-21 13:22:37 -06:00
Shaun Ruffell
19cef998bd sysfs: Remove signed one-bit fields.
Eliminates the following warning from sparse:
  drivers/dahdi/dahdi-sysfs-chan.c:50:29: error: dubious one-bit signed bitfield

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
2012-12-21 13:22:37 -06:00
Shaun Ruffell
82cf3c7b13 dahdi: Trivial change of '__u32' -> 'u32' in struct dahdi_count.
struct dahdi_count is not directly exposed to user space, so we can use the
native u32 type instead of __u32 to clarify that.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
2012-12-21 13:22:37 -06:00
Shaun Ruffell
f916f1e91f dahdi: Move 'timingslips' in with the other maintenance counters.
This allows timingslips to be reset along with the other counters and clarifies
the intended use.

This came up when Doug Bailey asked why he couldn't use dahdi_maint to clear
timing slips in addition to the other counters.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
2012-12-21 13:22:37 -06:00
Tzafrir Cohen
a8dfd61e53 gitignore: Add README.html to git ignore list
Signed-off-by: Tzafrir Cohen <tzafrir.cohen@xorcom.com>
Acked-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2012-12-12 14:18:48 -06:00
Russ Meyerriecks
6846663d1e Merge tag 'review-sysfs-chan' of http://git.tzafrir.org.il/git/dahdi-linux into for-trunk
SysFS Channel representation changes

* Kernel (and SysFS) objects for channels.
* A bus of their own.
* Dynamically allocate a minor (no conflict with /dev/dahdi/timer et. al.).
* Device files located under /dev/dahdi/channels instead of
  /dev/dahdi/spans [e.g: /dev/dahdi/channels/2/4)
  - A link back should is doable with a simple udev rule.
* Bus name is dahdi_channels instead of dahdi_chans
  [e.g: /sys/bus/dahdi_channels]
* Driver name is dahdi instead of dahdi_chans
  [e.g: /sys/bus/dahdi_channels/drivers/dahdi]
* Attributes are all strings (or lists of strings), including 'sig' and
  'sigcap'.
2012-12-12 14:06:11 -06:00
Tzafrir Cohen
e1245b9dd6 Document new channel sysfs interface
Document the new sysfs interface and the changes to /dev .

Signed-off-by: Tzafrir Cohen <tzafrir.cohen@xorcom.com>
2012-12-12 19:23:38 +02:00
Oron Peled
00221e8bfd sysfs: new channel attr (ec_factory, ec_state)
Signed-off-by: Oron Peled <oron.peled@xorcom.com>
2012-12-12 00:18:49 +02:00
Oron Peled
4da324d4df sysfs: stringify channels 'sigcap' attribute
Signed-off-by: Oron Peled <oron.peled@xorcom.com>
Signed-off-by: Tzafrir Cohen <tzafrir.cohen@xorcom.com>
2012-12-12 00:18:49 +02:00
Oron Peled
d863af110f dahdi: sysfs: add channel attributes
Signed-off-by: Oron Peled <oron.peled@xorcom.com>
2012-12-12 00:18:49 +02:00
Oron Peled
cb4e4d0068 dahdi: sysfs: use dynamically allocated chrdev's
* Channels have their own dynamically allocated major number
* No arbitrary limit of minor < 250 (no collision with /dev/timer, etc)
* We still have arbitrary limit of channo < DAHDI_MAX_CHANNELS
  (should be raised?)
* FIXME: need to check to FIXME's

Signed-off-by: Oron Peled <oron.peled@xorcom.com>
2012-12-12 00:18:49 +02:00
Oron Peled
3a94ac322d dahdi: sysfs: chrdev region (not usefull yet)
Signed-off-by: Oron Peled <oron.peled@xorcom.com>
2012-12-12 00:18:49 +02:00
Oron Peled
53219879c8 dahdi: sysfs: a channel bus (not usefull yet)
* Added minimal infrastructure:
  - A 'chan_device' member to struct dahdi_chan
  - An empty 'device_attribute' array
  - A 'bus_type' with its methods
  - A 'device_driver' with its methods
  - Initialization/Cleanup code

Signed-off-by: Oron Peled <oron.peled@xorcom.com>
2012-12-12 00:18:49 +02:00
Shaun Ruffell
5f7ebe98da dahdi: Only watch transitions of ABIT when using E&M signalling.
This resolves an issue with a Glenayre GL3000 Paging Terminal with v8.000
software. The Glenayre would change both A and B bits to signal on/off hook
states, but there were a couple of milliseconds between when those bits changed.
This resulted in DAHDI generating an on-hook event to Asterisk before generating
the off-hook event and therefore Asterisk terminated the call prematurely.

Looking the A and B bits before this patch:

Asterisk (AB)   Glenayre (AB)
00              00                 Both sides on-hook
11              00                 Asterisk goes off hook to sieze line.
11              01                 Glenayre starts going-offhook. On-hook event
                                     sent to Asterisk from drivers since bits
                                     changed but ABIT was still 0.
11              11                 Glenayre finishes going off-hook. Off-hook
                                     event sent to Asterisk since ABIT changed
                                     from 0 to 1.
00              11                 Asterisk, processes on-hook event and goes
                                     on-hook itself to release line.
00              00                 Glenayre releases line. Call fails.

After this patch:

Asterisk (AB)   Glenayre (AB)
00              00                 Both sides on-hook
11              00                 Asterisk initiates call
11              01                 Glenayre starts handling call. No event is
                                     sent to Asterisk since only ABIT is checked.
11              11                 Glanayre finishes going off-hook. Call
                                     proceeds normally.

Internal-Issue-ID: DAHDI-1009
Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2012-12-11 10:27:57 -06:00
Shaun Ruffell
ef065a5e2a Revert "dahdi_dynamic_eth: Move tx packet flushing to process context."
dahdi_dynamic now always calls the flush function in softirq context so packet
flushing no longer needs to be pushed off to process context since interrupts
are enabled.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2012-12-11 10:27:56 -06:00
Shaun Ruffell
f44b252472 dahdi_dynamic: Use a tasklet for flushing dynamic drivers.
Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2012-12-11 10:27:56 -06:00
Tzafrir Cohen
d889fb39d3 Add .gitignore file
Allows 'git status' command to better show untracked files which one may be
interested in.

Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
Acked-by: Shaun Ruffell <sruffell@digium.com>
Acked-by: Tzafrir Cohen <tzafrir.cohen@xorcom.com>
2012-12-10 16:21:19 -06:00
35 changed files with 5525 additions and 1130 deletions

41
.gitignore vendored Normal file
View File

@@ -0,0 +1,41 @@
# Files that are generated as part of the build process which we do not want git
# to track.
*.[oa]
*.mod
*.mod.[oc]
*.ko
*.cmd
*.order
*.tar.gz
tags
cscope.*
*.symvers
*.markers
.*.o.d
README.html
modules.order
Module.markers
build_tools/checkpatch.pl
drivers/dahdi/xpp/*.verified
drivers/dahdi/.tmp_versions/
drivers/dahdi/Module.symvers
drivers/dahdi/makefw
drivers/dahdi/radfw.h
drivers/dahdi/tor2fw.h
drivers/dahdi/xpp/init_fxo_modes
drivers/dahdi/xpp/print_fxo_modes
drivers/dahdi/xpp/xpp_version.h
include/dahdi/version.h
drivers/dahdi/vpmadt032_loader/vpmadt032_loader.h
drivers/dahdi/vpmadt032_loader/vpmadt032_x86_32.o_shipped
drivers/dahdi/vpmadt032_loader/vpmadt032_x86_64.o_shipped
drivers/dahdi/firmware/dahdi-fw-hx8.bin
drivers/dahdi/firmware/dahdi-fw-oct6114-064.bin
drivers/dahdi/firmware/dahdi-fw-oct6114-128.bin
drivers/dahdi/firmware/dahdi-fw-oct6114-256.bin
drivers/dahdi/firmware/dahdi-fw-tc400m.bin
drivers/dahdi/firmware/dahdi-fw-te820.bin
drivers/dahdi/firmware/dahdi-fw-vpmoct032.bin
drivers/dahdi/firmware/make_firmware_object

View File

@@ -64,17 +64,7 @@ ASCIIDOC_CMD:=$(ASCIIDOC) -n -a toc -a toclevels=4
GENERATED_DOCS:=README.html
ifneq ($(wildcard .version),)
DAHDIVERSION:=$(shell cat .version)
else
ifneq ($(wildcard .svn),)
DAHDIVERSION:=$(shell build_tools/make_version . dahdi/linux)
else
ifneq ($(wildcard .git),)
DAHDIVERSION:=$(shell build_tools/make_version . dahdi/linux)
endif
endif
endif
DAHDIVERSION:=$(shell build_tools/make_version . dahdi/linux)
all: modules
@@ -92,7 +82,7 @@ include/dahdi/version.h: FORCE
fi
@rm -f $@.tmp
prereq: include/dahdi/version.h firmware-loaders
prereq: include/dahdi/version.h firmware-loaders oct612x-lib
stackcheck: $(CHECKSTACK) modules
objdump -d drivers/dahdi/*.ko drivers/dahdi/*/*.ko | $(CHECKSTACK)
@@ -128,6 +118,13 @@ uninstall-firmware:
firmware-loaders:
$(MAKE) -C drivers/dahdi/firmware firmware-loaders
oct612x-lib:
ifeq (no,$(HAS_KSRC))
@echo "You do not appear to have the sources for the $(KVERS) kernel installed."
@exit 1
endif
$(MAKE) -C $(KSRC) M='$(PWD)/drivers/dahdi/oct612x'
install-include:
for hdr in $(INST_HEADERS); do \
install -D -m 644 include/dahdi/$$hdr $(DESTDIR)/usr/include/dahdi/$$hdr; \
@@ -195,6 +192,7 @@ ifneq (no,$(HAS_KSRC))
endif
@rm -f $(GENERATED_DOCS)
$(MAKE) -C drivers/dahdi/firmware clean
$(MAKE) -C $(KSRC) M='$(PWD)/drivers/dahdi/oct612x' clean
distclean: dist-clean

284
README
View File

@@ -445,57 +445,17 @@ reside directly under /sys/module/'module_name' .
Useful module parameters:
debug (most modules)::
Sets debug mode / debug level. With most modules 'debug' can be either
disabled (0, the default value) or enabled (any other value).
+
+
wctdm and wcte1xp print several extra debugging messages if the value
of debug is more than 1.
+
+
Some modules have "debugging flags" bits - the value of debug is a
bitmask and several messages are printed if some bits are set:
- wctdm24xxp:
* 1: DEBUG_CARD
* 2: DEBUG_ECHOCAN
- wct4xxp:
* 1: DEBUG_MAIN
* 2: DEBUG_DTMF
* 4: DEBUG_REGS
* 8: DEBUG_TSI
* 16: DEBUG_ECHOCAN
* 32: DEBUG_RBS
* 64: DEBUG_FRAMER
- xpp: See also README.Astribank:
* 1: GENERAL - General debug comments.
* 2: PCM - PCM-related messages. Tend to flood logs.
* 4: LEDS - Anything related to the LEDs status control. The driver
produces a lot of messages when the option is enabled.
* 8: SYNC - Synchronization related messages.
* 16: SIGNAL - DAHDI signalling related messages.
* 32: PROC - Messages related to the procfs interface.
* 64: REGS - Reading and writing to chip registers. Tends to flood
logs.
* 128: DEVICES - Device instantiation, destruction and such.
* 256 - COMMANDS - Protocol commands. Tends to flood logs.
=== debug
(most modules)
deftaps (dahdi)::
The default size for the echo canceller. The number is in "taps", that
is "samples", 1/8 ms. The default is 64 - for a tail size of 8 ms.
+
+
Asterisk's chan_dahdi tends to pass its own value anyway, with a
different default size. So normally setting this doesn't change
anything.
Sets debug mode / debug level. With most modules 'debug' can be either
disabled (0, the default value) or enabled (any other value).
max_pseudo_channels (dahdi)::
The maximum number of pseudo channels that dahdi will allow userspace to
create. Pseudo channels are used when conferencing channels together.
The default is 512.
wctdm and wcte1xp print several extra debugging messages if the value
of debug is more than 1.
auto_assign_spans (dahdi)::
See <<_span_assignments,Span Assignments>> below.
Some modules have "debugging flags" bits - the value of debug is a
bitmask and several messages are printed if some bits are set:
To get a list of parameters supported by a module, use
@@ -503,13 +463,178 @@ To get a list of parameters supported by a module, use
Or, for a module you have just built:
modinfo ./module_name.ko
modinfo ./drivers/dahdi/module_name.ko
For the xpp modules this will also include the description and default
value of the module. You can find a list of useful xpp module parameters
in README.Astribank .
- wctdm24xxp:
* 1: DEBUG_CARD
* 2: DEBUG_ECHOCAN
- wct4xxp:
* 1: DEBUG_MAIN
* 2: DEBUG_DTMF
* 4: DEBUG_REGS
* 8: DEBUG_TSI
* 16: DEBUG_ECHOCAN
* 32: DEBUG_RBS
* 64: DEBUG_FRAMER
- xpp: See also README.Astribank:
* 1: GENERAL - General debug comments.
* 2: PCM - PCM-related messages. Tend to flood logs.
* 4: LEDS - Anything related to the LEDs status control. The driver
produces a lot of messages when the option is enabled.
* 8: SYNC - Synchronization related messages.
* 16: SIGNAL - DAHDI signalling related messages.
* 32: PROC - Messages related to the procfs interface.
* 64: REGS - Reading and writing to chip registers. Tends to flood
logs.
* 128: DEVICES - Device instantiation, destruction and such.
* 256 - COMMANDS - Protocol commands. Tends to flood logs.
+
+
The script xpp_debug in the source tree can help settting them at run
time.
=== deftaps
(dahdi)
The default size for the echo canceller. The number is in "taps", that
is "samples", 1/8 ms. The default is 64 - for a tail size of 8 ms.
Asterisk's chan_dahdi tends to pass its own value anyway, with a
different default size. So normally setting this doesn't change
anything.
=== max_pseudo_channels
(dahdi)
The maximum number of pseudo channels that dahdi will allow userspace to
create. Pseudo channels are used when conferencing channels together.
The default is 512.
=== auto_assign_spans
(dahdi)
See <<_span_assignments,Span Assignments>> below.
XPP (Astribank) module parameters
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
==== debug
(all modules) - see above.
==== dahdi_autoreg
(xpp)
Register spans automatically (1) or not (0). Default: 0.
Setting it simplifies operations with a single Astribank and no other
DAHDI hardware. However if you have such systems, automatic
registration can cause the order of spans to be unpredictable.
The standard startup scripts use 'dahdi_registration on' instead of this.
==== initdir
(xpp)
This is the directory containing the initialization scripts.
The default is /usr/share/dahdi .
Setting this value could be useful if that location is inconvenient for you.
==== rx_tasklet
(xpp)
Enable (1) or disable (0) doing most of the packets processing in
separate tasklets. This should probably help on higher-end systems with
multiple Astribanks.
==== vmwi_ioctl
(xpd_fxs)
Does userspace support VMWI notification via ioctl? Default: 1 (yes).
Disable this (0) to have the driver attempt to detect the voicemail
message waiting indication status for this port from FSK messages
userspace (Asterisk) sends. Set the ports to use AC neon-lamp style
message waiting indication. The detection from the FSK messages takes
extra CPU cycles but is required with e.g. Asterisk < 1.6.0 .
Also note that in order for this parameter to take effect, it must be
set before the span is registered. This practically means that it
should be set through modprobe.d files.
See also Voicemail Indication in README.Astribank.
==== usb1
(xpp_usb)
Enable (1) or disable (0) support of USB1 devices. Disabled by default.
USB1 devices are not well-tested. It seems that they don't work at all
for Astribank BRI. Generally they should work with the current code, but
we expect the voice quality issues. Hence we would like to make it
very clear that you if you have a USB1 port (rather than a USB2 one, as
recommended) you will have to take an action to enable the device.
==== poll intervals
(various)
There are various values which the driver occasionally polls the
device for. For instance, the parameter poll_battery_interval for
xpd_fxo to poll the battery, in order to know if the telco line is
actually connected.
The value of those parameters is typically a number in milliseconds.
0 is used to disable polling. Under normal operation there should be
no reason to play with those parameters.
==== dtmf_detection
(xpd_fxs)
Enable (1) or disable (0) support of hardware DTMF detection by the
Astribank.
==== caller_id_style
(xpd_fxo)
Various types of caller ID signalling styles require knowing the PCM
even when the line is on-hook (which is usually a waste of CPU and
bandwidth). This parameter allows fine-tuning the behaviour here:
* 0 (default) - Don't pass extra PCM when on-hook.
* 1 ETSI-FSK: Wait for polarity reversal to come before a ring and
then start passing PCM until the caller ID has been passed.
* 2 ETSI-DTMF: Always pass PCM and generate a DTMF if polarity reversal is
detected before ring.
* 3 Passthrough: Always pass PCM as-is.
This parameter is read-only. It cannot be changed at run-time.
==== battery_threshold
(xpd_fxo)
Minimum voltage that shows there is battery. Defaults to 3. Normally you
should not need to change this, unless dealing with a funky PSTN
provider.
==== battery_debounce
(xpd_fxo)
Minimum interval (msec) for detection of battery off (as opposed to e.g.
a temporary power denial to signal a hangup). Defaults to 1000. As with
battery_threshold above, there's normally no need to tweak it.
==== use_polrev_firmware
(xpd_fxo)
Enable (1, default) or disable (0) support for polarity reversal
detection in the hardware. Only has effect with PIC_TYPE_2.hex rev. >=
11039 and with the initialization changes (init_card_2_30) in rev.
949aa49.
This parameter is read-only. It cannot be changed at run-time.
Internals
---------
DAHDI Device Files
@@ -521,9 +646,14 @@ or dynamically through the udev system.
* /dev/dahdi/ctl (196:0) - a general device file for various information and
control operations on the DAHDI channels.
* /dev/dahdi/chan/N/M - A device file for channel M in span N
- Both N and M are zero padded 3 digit numbers
- Both N and M start at 001
- M is chanpos - numbering relative to the current span.
* /dev/dahdi/NNN (196:NNN) - for NNN in the range 1-249. A device file for
DAHDI channel NNN. It can be used to read data from the channel
and write data to the channel.
and write data to the channel. It is not generated by default but may
be generated as a symlink using udev rules.
* /dev/dahdi/transcode (196:250) - Used to connect to a DAHDI transcoding
device.
* /dev/dahdi/timer (196:253) - Allows setting timers. Used anywhere?
@@ -851,6 +981,60 @@ A very short type string.
Current sync source.
Channels Bus
^^^^^^^^^^^^
Each DAHDI channel is represented by a node under
/sys/bus/dahdi_channels/devices with the name 'dahdi!channels!N!M'
(where N is the number of the span and M is the number of the channel
in the span - chanpos). Channels of each span also reside under the node
of the span.
Useful attributes in the channel node (All attributed listed below are
read-only):
===== /sys/bus/dahdi_spans/devices/span-N/dahdi!channels!N!M/alarms
List of names of the current active alarms (space separated). Normally
(no alarms) empty. Example:
RED YELLOW
===== /sys/bus/dahdi_spans/devices/span-N/dahdi!channels!N!M/blocksize
The block size set by userspace.
===== /sys/bus/dahdi_spans/devices/span-N/dahdi!channels!N!M/channo
The (global) channel number.
===== /sys/bus/dahdi_spans/devices/span-N/dahdi!channels!N!M/chanpos
The channel number within the span.
===== /sys/bus/dahdi_spans/devices/span-N/dahdi!channels!N!M/dev
Major and minor device numbers.
===== /sys/bus/dahdi_spans/devices/span-N/dahdi!channels!N!M/ec_factory
The name of the echo canceller to be used in the channel, if one is
configured. Example:
MG2
===== /sys/bus/dahdi_spans/devices/span-N/dahdi!channels!N!M/ec_state
State of the echo canceller. ACTIVE: configured and inuse. INACTIVE
otherwise.
===== /sys/bus/dahdi_spans/devices/span-N/dahdi!channels!N!M/in_use
1 if the channel is in use (was opepend by userspace), 0 otherwise.
===== /sys/bus/dahdi_spans/devices/span-N/dahdi!channels!N!M/name
A name string for the channel
===== /sys/bus/dahdi_spans/devices/span-N/dahdi!channels!N!M/sig
The signalling types set for the channel. A space-separated list of
signalling types.
===== /sys/bus/dahdi_spans/devices/span-N/dahdi!channels!N!M/sigcap
The signalling types this channel may be configured to handle. A space-
separated list of signalling types.
User-space Interface
~~~~~~~~~~~~~~~~~~~~
User-space programs can only work with DAHDI channels. The basic

View File

@@ -1,7 +1,7 @@
#!/bin/sh
if [ -f ${1}/.version ]; then
cat ${1}.version
cat ${1}/.version
elif [ -f ${1}/.svnrevision ]; then
echo SVN-`cat ${1}/.svnbranch`-r`cat ${1}/.svnrevision`
elif [ -d ${1}/.svn ]; then
@@ -59,7 +59,7 @@ elif [ -d ${1}/.git ]; then
MODIFIED=""
SVN_REV=`git log --pretty=full -1 | grep -F "git-svn-id:" | sed -e "s/.*\@\([^\s]*\)\s.*/\1/g"`
if [ -z "$SVN_REV" ]; then
VERSION=`git describe --long --always --tags --dirty=M 2> /dev/null`
VERSION=`git describe --tags --dirty=M 2> /dev/null | sed -e "s/^v\([0-9]\)/\1/"`
if [ $? -ne 0 ]; then
if [ "`git ls-files -m | wc -l`" != "0" ]; then
MODIFIED="M"
@@ -115,4 +115,8 @@ elif [ -d ${1}/.git ]; then
echo SVN-${RESULT##-}-r${SVN_REV}${MODIFIED}
fi
else
# Use the directory information in the absence of any other version
# information
pwd -P
fi

View File

@@ -11,6 +11,14 @@ obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_WCT4XXP) += wct4xxp/
obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_WCTC4XXP) += wctc4xxp/
obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_WCTDM24XXP) += wctdm24xxp/
obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_WCTE12XP) += wcte12xp/
obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_WCTE13XP) += wcte13xp.o
wcte13xp-objs := wcte13xp-base.o oct612x/lib.a
CFLAGS_wcte13xp-base.o += -I$(src)/oct612x/include -I$(src)/oct612x/octdeviceapi -I$(src)/oct612x/octdeviceapi/oct6100api
ifeq ($(HOTPLUG_FIRMWARE),yes)
CFLAGS_wcte13xp-base.o += -DHOTPLUG_FIRMWARE
endif
obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_WCTDM) += wctdm.o
obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_VOICEBUS) += voicebus/
obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_WCB4XXP) += wcb4xxp/
@@ -38,7 +46,7 @@ obj-m += $(DAHDI_MODULES_EXTRA)
# well:
ifneq (,$(wildcard $(src)/../staging/echo/echo.c))
obj-m += dahdi_echocan_oslec.o
obj-m += ../staging/echo/
obj-m += ../staging/echo/echo.o
endif
CFLAGS_MODULE += -I$(DAHDI_INCLUDE) -I$(src)

View File

@@ -176,6 +176,17 @@ static sumtype *conf_sums_prev;
static struct dahdi_span *master;
struct file_operations *dahdi_transcode_fops = NULL;
#ifdef CONFIG_DAHDI_CONFLINK
static struct {
int src; /* source conf number */
int dst; /* dst conf number */
} conf_links[DAHDI_MAX_CONF + 1];
static int maxlinks;
#endif
#ifdef CONFIG_DAHDI_CORE_TIMER
static struct core_timer {
@@ -283,6 +294,7 @@ static inline void dahdi_kernel_fpu_end(void)
#endif
struct dahdi_timer {
spinlock_t lock;
int ms; /* Countdown */
int pos; /* Position */
int ping; /* Whether we've been ping'd */
@@ -811,7 +823,7 @@ ssize_t lineconfig_str(int lineconfig, char buf[], size_t size)
EXPORT_SYMBOL(lineconfig_str);
#ifdef CONFIG_PROC_FS
static const char *sigstr(int sig)
const char *sigstr(int sig)
{
switch (sig) {
case DAHDI_SIG_FXSLS:
@@ -858,7 +870,7 @@ static const char *sigstr(int sig)
}
}
static int fill_alarm_string(char *buf, int count, int alarms)
int fill_alarm_string(char *buf, int count, int alarms)
{
int len;
@@ -888,7 +900,7 @@ static void seq_fill_alarm_string(struct seq_file *sfile, int alarms)
seq_printf(sfile, "%s", tmp);
}
static int dahdi_seq_show(struct seq_file *sfile, void *v)
static int dahdi_seq_show(struct seq_file *sfile, void *data)
{
long spanno = (long)sfile->private;
int x;
@@ -932,8 +944,8 @@ static int dahdi_seq_show(struct seq_file *sfile, void *v)
seq_printf(sfile, "\tFAS error count: %d\n", s->count.fas);
if (s->parent->irqmisses)
seq_printf(sfile, "\tIRQ misses: %d\n", s->parent->irqmisses);
if (s->timingslips)
seq_printf(sfile, "\tTiming slips: %d\n", s->timingslips);
if (s->count.timingslips)
seq_printf(sfile, "\tTiming slips: %d\n", s->count.timingslips);
seq_printf(sfile, "\n");
for (x = 0; x < s->channels; x++) {
@@ -980,7 +992,7 @@ static int dahdi_seq_show(struct seq_file *sfile, void *v)
static int dahdi_proc_open(struct inode *inode, struct file *file)
{
return single_open(file, dahdi_seq_show, PDE(inode)->data);
return single_open(file, dahdi_seq_show, PDE_DATA(inode));
}
static const struct file_operations dahdi_proc_ops = {
@@ -1060,10 +1072,29 @@ static unsigned long _chan_in_conf(struct dahdi_chan *chan, unsigned long x)
confmode == DAHDI_CONF_REALANDPSEUDO)) ? 1 : 0;
}
#ifdef CONFIG_DAHDI_CONFLINK
static void recalc_maxlinks(void)
{
int x;
for (x = DAHDI_MAX_CONF - 1; x > 0; x--) {
if (conf_links[x].src || conf_links[x].dst) {
maxlinks = x + 1;
return;
}
}
maxlinks = 0;
}
#endif
static void dahdi_check_conf(int x)
{
unsigned long res;
unsigned long flags;
#ifdef CONFIG_DAHDI_CONFLINK
int i;
#endif
/* return if no valid conf number */
if (x <= 0)
@@ -1086,6 +1117,17 @@ static void dahdi_check_conf(int x)
/* Highest conference may have changed */
recalc_maxconfs();
#ifdef CONFIG_DAHDI_CONFLINK
/* And unlink it from any conflinks */
for (i = DAHDI_MAX_CONF - 1; i > 0; i--) {
if (conf_links[i].src == x)
conf_links[i].src = 0;
if (conf_links[i].dst == x)
conf_links[i].dst = 0;
}
recalc_maxlinks();
#endif
}
/* enqueue an event on a channel */
@@ -1922,7 +1964,6 @@ static int dahdi_net_open(struct net_device *dev)
return -EINVAL;
}
ms->txbufpolicy = DAHDI_POLICY_IMMEDIATE;
ms->rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
res = dahdi_reallocbufs(ms, DAHDI_DEFAULT_MTU_MRU, DAHDI_DEFAULT_NUM_BUFS);
if (res)
@@ -2957,50 +2998,42 @@ static int initialize_channel(struct dahdi_chan *chan)
return 0;
}
static int dahdi_timing_open(struct file *file)
static const struct file_operations dahdi_timer_fops;
static int dahdi_timer_open(struct file *file)
{
struct dahdi_timer *t;
unsigned long flags;
if (!(t = kzalloc(sizeof(*t), GFP_KERNEL)))
struct dahdi_timer *t = kzalloc(sizeof(*t), GFP_KERNEL);
if (!t)
return -ENOMEM;
init_waitqueue_head(&t->sel);
INIT_LIST_HEAD(&t->list);
init_waitqueue_head(&t->sel);
file->private_data = t;
spin_lock_irqsave(&dahdi_timer_lock, flags);
list_add(&t->list, &dahdi_timers);
spin_unlock_irqrestore(&dahdi_timer_lock, flags);
spin_lock_init(&t->lock);
file->f_op = &dahdi_timer_fops;
return 0;
}
static int dahdi_timer_release(struct file *file)
static int dahdi_timer_release(struct inode *inode, struct file *file)
{
struct dahdi_timer *t, *cur, *next;
struct dahdi_timer *timer = file->private_data;
unsigned long flags;
if (!(t = file->private_data))
if (!timer)
return 0;
spin_lock_irqsave(&dahdi_timer_lock, flags);
list_for_each_entry_safe(cur, next, &dahdi_timers, list) {
if (t == cur) {
list_del(&cur->list);
break;
}
spin_lock_irqsave(&timer->lock, flags);
if (!list_empty(&timer->list)) {
spin_unlock(&timer->lock);
spin_lock(&dahdi_timer_lock);
spin_lock(&timer->lock);
list_del_init(&timer->list);
spin_unlock(&dahdi_timer_lock);
}
file->private_data = NULL;
spin_unlock_irqrestore(&timer->lock, flags);
spin_unlock_irqrestore(&dahdi_timer_lock, flags);
if (!cur) {
module_printk(KERN_NOTICE, "Timer: Not on list??\n");
return 0;
}
kfree(cur);
kfree(timer);
return 0;
}
@@ -3238,7 +3271,7 @@ static int dahdi_open(struct inode *inode, struct file *file)
}
if (unit == DAHDI_TIMER) {
if (can_open_timer()) {
return dahdi_timing_open(file);
return dahdi_timer_open(file);
} else {
return -ENXIO;
}
@@ -3740,7 +3773,7 @@ static int dahdi_release(struct inode *inode, struct file *file)
if (unit == DAHDI_CTL)
return dahdi_ctl_release(file);
if (unit == DAHDI_TIMER) {
return dahdi_timer_release(file);
return dahdi_timer_release(inode, file);
}
if (unit == DAHDI_TRANSCODE) {
/* We should not be here because the dahdi_transcode.ko module
@@ -3890,48 +3923,74 @@ void dahdi_alarm_notify(struct dahdi_span *span)
}
}
static int dahdi_timer_ioctl(struct file *file, unsigned int cmd, unsigned long data, struct dahdi_timer *timer)
static long
dahdi_timer_unlocked_ioctl(struct file *file, unsigned int cmd,
unsigned long data)
{
int j;
unsigned long flags;
struct dahdi_timer *const timer = file->private_data;
switch(cmd) {
case DAHDI_TIMERCONFIG:
get_user(j, (int __user *)data);
if (j < 0)
j = 0;
spin_lock_irqsave(&dahdi_timer_lock, flags);
timer->ms = timer->pos = j;
spin_unlock_irqrestore(&dahdi_timer_lock, flags);
spin_lock_irqsave(&timer->lock, flags);
if (timer->ms != j) {
if (j && list_empty(&timer->list)) {
/* The timer is being activated so add to the
* global timer list. */
spin_unlock(&timer->lock);
spin_lock(&dahdi_timer_lock);
spin_lock(&timer->lock);
timer->ms = timer->pos = j;
list_add(&timer->list, &dahdi_timers);
spin_unlock(&dahdi_timer_lock);
} else if (!j && !list_empty(&timer->list)) {
/* The timer is being disabled so we can remove
* from the global timer list. */
spin_unlock(&timer->lock);
spin_lock(&dahdi_timer_lock);
spin_lock(&timer->lock);
list_del_init(&timer->list);
timer->ms = timer->pos = j;
spin_unlock(&dahdi_timer_lock);
} else {
timer->ms = timer->pos = j;
}
}
spin_unlock_irqrestore(&timer->lock, flags);
break;
case DAHDI_TIMERACK:
get_user(j, (int __user *)data);
spin_lock_irqsave(&dahdi_timer_lock, flags);
spin_lock_irqsave(&timer->lock, flags);
if ((j < 1) || (j > timer->tripped))
j = timer->tripped;
timer->tripped -= j;
spin_unlock_irqrestore(&dahdi_timer_lock, flags);
spin_unlock_irqrestore(&timer->lock, flags);
break;
case DAHDI_GETEVENT: /* Get event on queue */
j = DAHDI_EVENT_NONE;
spin_lock_irqsave(&dahdi_timer_lock, flags);
spin_lock_irqsave(&timer->lock, flags);
/* set up for no event */
if (timer->tripped)
j = DAHDI_EVENT_TIMER_EXPIRED;
if (timer->ping)
j = DAHDI_EVENT_TIMER_PING;
spin_unlock_irqrestore(&dahdi_timer_lock, flags);
spin_unlock_irqrestore(&timer->lock, flags);
put_user(j, (int __user *)data);
break;
case DAHDI_TIMERPING:
spin_lock_irqsave(&dahdi_timer_lock, flags);
spin_lock_irqsave(&timer->lock, flags);
timer->ping = 1;
wake_up_interruptible(&timer->sel);
spin_unlock_irqrestore(&dahdi_timer_lock, flags);
spin_unlock_irqrestore(&timer->lock, flags);
break;
case DAHDI_TIMERPONG:
spin_lock_irqsave(&dahdi_timer_lock, flags);
spin_lock_irqsave(&timer->lock, flags);
timer->ping = 0;
spin_unlock_irqrestore(&dahdi_timer_lock, flags);
spin_unlock_irqrestore(&timer->lock, flags);
break;
default:
return -ENOTTY;
@@ -3939,6 +3998,14 @@ static int dahdi_timer_ioctl(struct file *file, unsigned int cmd, unsigned long
return 0;
}
#ifndef HAVE_UNLOCKED_IOCTL
static int dahdi_timer_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long data)
{
return dahdi_timer_unlocked_ioctl(file, cmd, data);
}
#endif
static int dahdi_ioctl_getgains(struct file *file, unsigned long data)
{
int res = 0;
@@ -4480,6 +4547,90 @@ static int dahdi_ioctl_spanstat_v1(struct file *file, unsigned long data)
return ret;
}
#ifdef CONFIG_DAHDI_CONFLINK
static int dahdi_ioctl_conflink(struct file *file, unsigned long data)
{
struct dahdi_chan *chan;
struct dahdi_confinfo conf;
unsigned long flags;
int res = 0;
int i;
chan = chan_from_file(file);
if (!chan)
return -EINVAL;
if (!(chan->flags & DAHDI_FLAG_AUDIO))
return -EINVAL;
if (copy_from_user(&conf, (void __user *)data, sizeof(conf)))
return -EFAULT;
/* check sanity of arguments */
if ((conf.chan < 0) || (conf.chan > DAHDI_MAX_CONF))
return -EINVAL;
if ((conf.confno < 0) || (conf.confno > DAHDI_MAX_CONF))
return -EINVAL;
/* cant listen to self!! */
if (conf.chan && (conf.chan == conf.confno))
return -EINVAL;
spin_lock_irqsave(&chan_lock, flags);
spin_lock(&chan->lock);
/* if to clear all links */
if ((!conf.chan) && (!conf.confno)) {
/* clear all the links */
memset(conf_links, 0, sizeof(conf_links));
recalc_maxlinks();
spin_unlock(&chan->lock);
spin_unlock_irqrestore(&chan_lock, flags);
return 0;
}
/* look for already existant specified combination */
for (i = 1; i <= DAHDI_MAX_CONF; i++) {
/* if found, exit */
if ((conf_links[i].src == conf.chan) &&
(conf_links[i].dst == conf.confno))
break;
}
if (i <= DAHDI_MAX_CONF) { /* if found */
if (!conf.confmode) { /* if to remove link */
conf_links[i].src = 0;
conf_links[i].dst = 0;
} else { /* if to add and already there, error */
res = -EEXIST;
}
} else { /* if not found */
if (conf.confmode) { /* if to add link */
/* look for empty location */
for (i = 1; i <= DAHDI_MAX_CONF; i++) {
/* if empty, exit loop */
if ((!conf_links[i].src) &&
(!conf_links[i].dst))
break;
}
/* if empty spot found */
if (i <= DAHDI_MAX_CONF) {
conf_links[i].src = conf.chan;
conf_links[i].dst = conf.confno;
} else { /* if no empties -- error */
res = -ENOSPC;
}
} else { /* if to remove, and not found -- error */
res = -ENOENT;
}
}
recalc_maxlinks();
spin_unlock(&chan->lock);
spin_unlock_irqrestore(&chan_lock, flags);
return res;
}
#else
static int dahdi_ioctl_conflink(struct file *file, unsigned long data)
{
return -ENOSYS;
}
#endif
static int dahdi_common_ioctl(struct file *file, unsigned int cmd,
unsigned long data)
{
@@ -4508,6 +4659,10 @@ static int dahdi_common_ioctl(struct file *file, unsigned int cmd,
case DAHDI_CHANDIAG_V1: /* Intentional drop through. */
case DAHDI_CHANDIAG:
return dahdi_ioctl_chandiag(file, data);
case DAHDI_CONFLINK:
return dahdi_ioctl_conflink(file, data);
default:
return -ENOTTY;
}
@@ -4981,11 +5136,28 @@ static int dahdi_ioctl_startup(struct file *file, unsigned long data)
return res;
}
static int dahdi_shutdown_span(struct dahdi_span *s)
{
int res = 0;
int x;
/* Unconfigure channels */
for (x = 0; x < s->channels; x++)
s->chans[x]->sig = 0;
if (s->ops->shutdown)
res = s->ops->shutdown(s);
clear_bit(DAHDI_FLAGBIT_RUNNING, &s->flags);
return res;
}
static int dahdi_ioctl_shutdown(unsigned long data)
{
int res;
/* I/O CTL's for control interface */
int j;
int x;
struct dahdi_span *s;
if (get_user(j, (int __user *)data))
@@ -4993,22 +5165,9 @@ static int dahdi_ioctl_shutdown(unsigned long data)
s = span_find_and_get(j);
if (!s)
return -ENXIO;
/* Unconfigure channels */
for (x = 0; x < s->channels; x++)
s->chans[x]->sig = 0;
if (s->ops->shutdown) {
int res = s->ops->shutdown(s);
if (res) {
put_span(s);
return res;
}
}
s->flags &= ~DAHDI_FLAG_RUNNING;
res = dahdi_shutdown_span(s);
put_span(s);
return 0;
return res;
}
/**
@@ -5210,7 +5369,8 @@ static int dahdi_ioctl_maint(unsigned long data)
spin_lock_irqsave(&s->lock, flags);
/* save current maint state */
i = s->maintstat;
/* set maint mode */
s->maintstat = maint.command;
switch (maint.command) {
case DAHDI_MAINT_NONE:
case DAHDI_MAINT_LOCALLOOP:
@@ -5223,6 +5383,8 @@ static int dahdi_ioctl_maint(unsigned long data)
spin_unlock_irqrestore(&s->lock, flags);
if (rv) {
put_span(s);
/* Restore the state on error */
s->maintstat = i;
return rv;
}
spin_lock_irqsave(&s->lock, flags);
@@ -5234,6 +5396,8 @@ static int dahdi_ioctl_maint(unsigned long data)
spin_unlock_irqrestore(&s->lock, flags);
if (rv) {
put_span(s);
/* Restore the state on error */
s->maintstat = i;
return rv;
}
spin_lock_irqsave(&s->lock, flags);
@@ -5257,6 +5421,8 @@ static int dahdi_ioctl_maint(unsigned long data)
spin_unlock_irqrestore(&s->lock, flags);
if (rv) {
put_span(s);
/* Restore the state on error */
s->maintstat = i;
return rv;
}
spin_lock_irqsave(&s->lock, flags);
@@ -5267,12 +5433,10 @@ static int dahdi_ioctl_maint(unsigned long data)
"Unknown maintenance event: %d\n",
maint.command);
put_span(s);
/* Restore the state on error */
s->maintstat = i;
return -ENOSYS;
}
/* set maint mode */
s->maintstat = maint.command;
dahdi_alarm_notify(s); /* process alarm-related events */
spin_unlock_irqrestore(&s->lock, flags);
put_span(s);
@@ -5580,10 +5744,10 @@ static int dahdi_ioctl_confdiag(struct file *file, unsigned long data)
for (i = ((j) ? j : 1); i <= ((j) ? j : DAHDI_MAX_CONF); i++) {
struct dahdi_span *s;
struct pseudo_chan *pseudo;
int k;
c = 0;
spin_lock_irqsave(&chan_lock, flags);
list_for_each_entry(s, &span_list, spans_node) {
int k;
for (k = 0; k < s->channels; k++) {
chan = s->chans[k];
if (chan->confna != i)
@@ -5605,6 +5769,29 @@ static int dahdi_ioctl_confdiag(struct file *file, unsigned long data)
module_printk(KERN_NOTICE, "chan %d, mode %x\n",
pseudo->chan.channo, pseudo->chan.confmode);
}
#ifdef CONFIG_DAHDI_CONFLINK
{
int rv;
rv = 0;
for (k = 1; k <= DAHDI_MAX_CONF; k++) {
if (conf_links[k].dst == i) {
if (!c) {
c = 1;
module_printk(KERN_NOTICE,
"Conf #%d:\n", i);
}
if (!rv) {
rv = 1;
module_printk(KERN_NOTICE,
"Snooping on:\n");
}
module_printk(KERN_NOTICE, "conf %d\n",
conf_links[k].src);
}
}
}
#endif
spin_unlock_irqrestore(&chan_lock, flags);
if (c)
module_printk(KERN_NOTICE, "\n");
@@ -6704,16 +6891,11 @@ static long
dahdi_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long data)
{
int unit = UNIT(file);
struct dahdi_timer *timer;
int ret;
#if defined(HAVE_UNLOCKED_IOCTL) && defined(CONFIG_BKL)
lock_kernel();
#endif
if (unit == DAHDI_CTL) {
ret = dahdi_ctl_ioctl(file, cmd, data);
goto unlock_exit;
goto exit;
}
if (unit == DAHDI_TRANSCODE) {
@@ -6721,45 +6903,41 @@ dahdi_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long data)
* this file object on open, so we shouldn't be here. */
WARN_ON(1);
ret = -EFAULT;
goto unlock_exit;
goto exit;
}
if (unit == DAHDI_TIMER) {
timer = file->private_data;
if (timer)
ret = dahdi_timer_ioctl(file, cmd, data, timer);
else
ret = -EINVAL;
goto unlock_exit;
/* The file operations for a timer device should have been
* updated. */
WARN_ON(1);
ret = -EFAULT;
goto exit;
}
if (unit == DAHDI_CHANNEL) {
if (file->private_data)
ret = dahdi_chan_ioctl(file, cmd, data);
else
ret = dahdi_prechan_ioctl(file, cmd, data);
goto unlock_exit;
goto exit;
}
if (unit == DAHDI_PSEUDO) {
if (!file->private_data) {
module_printk(KERN_NOTICE, "No pseudo channel structure to read?\n");
ret = -EINVAL;
goto unlock_exit;
goto exit;
}
ret = dahdi_chanandpseudo_ioctl(file, cmd, data);
goto unlock_exit;
goto exit;
}
if (!file->private_data) {
ret = -ENXIO;
goto unlock_exit;
goto exit;
}
ret = dahdi_chan_ioctl(file, cmd, data);
unlock_exit:
#if defined(HAVE_UNLOCKED_IOCTL) && defined(CONFIG_BKL)
unlock_kernel();
#endif
exit:
return ret;
}
@@ -6843,7 +7021,7 @@ static int _assign_spanno_and_basechan(struct dahdi_span *span)
}
next_channo = _get_next_channo(pos);
if ((basechan + span->channels) >= next_channo)
if ((basechan + span->channels) <= next_channo)
break;
/* We can't fit here, let's look at the next location. */
@@ -7081,15 +7259,14 @@ static int _dahdi_assign_span(struct dahdi_span *span, unsigned int spanno,
{
char tempfile[17];
snprintf(tempfile, sizeof(tempfile), "%d", span->spanno);
span->proc_entry = create_proc_entry(tempfile, 0444,
root_proc_entry);
span->proc_entry = proc_create_data(tempfile, 0444,
root_proc_entry, &dahdi_proc_ops,
(void *)((unsigned long)span->spanno));
if (!span->proc_entry) {
res = -EFAULT;
span_err(span, "Error creating procfs entry\n");
goto cleanup;
}
span->proc_entry->data = (void *)(long)span->spanno;
span->proc_entry->proc_fops = &dahdi_proc_ops;
}
#endif
@@ -7237,6 +7414,15 @@ static void disable_span(struct dahdi_span *span)
module_printk(KERN_INFO, "%s: span %d\n", __func__, span->spanno);
}
#ifdef CONFIG_PROC_FS
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0)
static inline void proc_remove(struct proc_dir_entry *proc_entry)
{
remove_proc_entry(proc_entry->name, root_proc_entry);
}
#endif
#endif
/**
* _dahdi_unassign_span() - unassign a DAHDI span
* @span: the DAHDI span
@@ -7249,6 +7435,7 @@ static void disable_span(struct dahdi_span *span)
*/
static int _dahdi_unassign_span(struct dahdi_span *span)
{
int res;
int x;
struct dahdi_span *new_master, *s;
unsigned long flags;
@@ -7265,15 +7452,19 @@ static int _dahdi_unassign_span(struct dahdi_span *span)
span->spanno = 0;
clear_bit(DAHDI_FLAGBIT_REGISTERED, &span->flags);
/* Shutdown the span if it's running */
if ((span->flags & DAHDI_FLAG_RUNNING) && span->ops->shutdown)
span->ops->shutdown(span);
res = dahdi_shutdown_span(span);
if (res) {
dev_err(span_device(span),
"Failed to shutdown when unassigning.\n");
}
if (debug & DEBUG_MAIN)
module_printk(KERN_NOTICE, "Unassigning Span '%s' with %d channels\n", span->name, span->channels);
#ifdef CONFIG_PROC_FS
if (span->proc_entry)
remove_proc_entry(span->proc_entry->name, root_proc_entry);
if (span->proc_entry) {
proc_remove(span->proc_entry);
span->proc_entry = NULL;
}
#endif /* CONFIG_PROC_FS */
span_sysfs_remove(span);
@@ -8353,7 +8544,6 @@ void dahdi_rbsbits(struct dahdi_chan *chan, int cursig)
break;
}
/* Fall through */
case DAHDI_SIG_EM: /* E and M */
case DAHDI_SIG_EM_E1:
case DAHDI_SIG_FXOLS: /* FXO Loopstart */
case DAHDI_SIG_FXOKS: /* FXO Kewlstart */
@@ -8362,7 +8552,13 @@ void dahdi_rbsbits(struct dahdi_chan *chan, int cursig)
else /* on hook */
__dahdi_hooksig_pvt(chan,DAHDI_RXSIG_ONHOOK);
break;
case DAHDI_SIG_EM: /* E and M */
/* Watch only the ABIT for changes. */
if ((cursig & DAHDI_ABIT) == (chan->rxsig & DAHDI_ABIT))
break;
__dahdi_hooksig_pvt(chan, (cursig & DAHDI_ABIT) ?
DAHDI_RXSIG_OFFHOOK : DAHDI_RXSIG_ONHOOK);
break;
case DAHDI_SIG_FXSKS: /* FXS Kewlstart */
case DAHDI_SIG_FXSGS: /* FXS Groundstart */
/* Fall through */
@@ -9302,14 +9498,14 @@ static void process_timers(void)
spin_lock(&dahdi_timer_lock);
list_for_each_entry(cur, &dahdi_timers, list) {
if (cur->ms) {
cur->pos -= DAHDI_CHUNKSIZE;
if (cur->pos <= 0) {
cur->tripped++;
cur->pos = cur->ms;
wake_up_interruptible(&cur->sel);
}
spin_lock(&cur->lock);
cur->pos -= DAHDI_CHUNKSIZE;
if (cur->pos <= 0) {
cur->tripped++;
cur->pos = cur->ms;
wake_up_interruptible(&cur->sel);
}
spin_unlock(&cur->lock);
}
spin_unlock(&dahdi_timer_lock);
}
@@ -9321,10 +9517,10 @@ static unsigned int dahdi_timer_poll(struct file *file, struct poll_table_struct
int ret = 0;
if (timer) {
poll_wait(file, &timer->sel, wait_table);
spin_lock_irqsave(&dahdi_timer_lock, flags);
spin_lock_irqsave(&timer->lock, flags);
if (timer->tripped || timer->ping)
ret |= POLLPRI;
spin_unlock_irqrestore(&dahdi_timer_lock, flags);
spin_unlock_irqrestore(&timer->lock, flags);
} else {
/*
* This should never happen. Surprise device removal
@@ -9691,6 +9887,29 @@ static void _process_masterspan(void)
spin_unlock(&pseudo->chan.lock);
}
#ifdef CONFIG_DAHDI_CONFLINK
if (maxlinks) {
int z;
int y;
#ifdef CONFIG_DAHDI_MMX
dahdi_kernel_fpu_begin();
#endif
/* process all the conf links */
for (x = 1; x <= maxlinks; x++) {
/* if we have a destination conf */
z = confalias[conf_links[x].dst];
if (z) {
y = confalias[conf_links[x].src];
if (y)
ACSS(conf_sums[z], conf_sums[y]);
}
}
#ifdef CONFIG_DAHDI_MMX
dahdi_kernel_fpu_end();
#endif
}
#endif /* CONFIG_DAHDI_CONFLINK */
/* do all the pseudo/conferenced channel transmits (putbuf's) */
list_for_each_entry(pseudo, &pseudo_chans, node) {
pseudo_rx_audio(&pseudo->chan);
@@ -9996,6 +10215,20 @@ static const struct file_operations dahdi_fops = {
.poll = dahdi_poll,
};
static const struct file_operations dahdi_timer_fops = {
.owner = THIS_MODULE,
.release = dahdi_timer_release,
#ifdef HAVE_UNLOCKED_IOCTL
.unlocked_ioctl = dahdi_timer_unlocked_ioctl,
#ifdef HAVE_COMPAT_IOCTL
.compat_ioctl = dahdi_timer_unlocked_ioctl,
#endif
#else
.ioctl = dahdi_timer_ioctl,
#endif
.poll = dahdi_timer_poll,
};
/*
* DAHDI stability should not depend on the calling process behaviour.
* In case of suprise device removal, we should be able to return

View File

@@ -26,6 +26,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/ctype.h>
#include <dahdi/kernel.h>
#include "dahdi.h"
#include "dahdi-sysfs.h"
@@ -38,22 +39,222 @@
static struct class *dahdi_class;
static dev_t dahdi_channels_devt; /*!< Device number of first channel */
static struct cdev dahdi_channels_cdev; /*!< Channels chardev's */
/*
* Flags to remember what initializations already
* succeeded.
*/
static struct {
u32 channel_driver:1;
u32 channels_bus:1;
u32 cdev:1;
} should_cleanup;
#define chan_attr(field, format_string) \
static BUS_ATTR_READER(field##_show, dev, buf) \
{ \
struct dahdi_chan *chan; \
\
chan = dev_to_chan(dev); \
return sprintf(buf, format_string, chan->field); \
}
chan_attr(name, "%s\n");
chan_attr(channo, "%d\n");
chan_attr(chanpos, "%d\n");
chan_attr(blocksize, "%d\n");
#ifdef OPTIMIZE_CHANMUTE
chan_attr(chanmute, "%d\n");
#endif
static BUS_ATTR_READER(sigcap_show, dev, buf)
{
struct dahdi_chan *chan;
int len = 0;
int i;
uint sigtypes[] = {
DAHDI_SIG_FXSLS,
DAHDI_SIG_FXSGS,
DAHDI_SIG_FXSKS,
DAHDI_SIG_FXOLS,
DAHDI_SIG_FXOGS,
DAHDI_SIG_FXOKS,
DAHDI_SIG_EM,
DAHDI_SIG_CLEAR,
DAHDI_SIG_HDLCRAW,
DAHDI_SIG_HDLCFCS,
DAHDI_SIG_HDLCNET,
DAHDI_SIG_SLAVE,
DAHDI_SIG_SF,
DAHDI_SIG_CAS,
DAHDI_SIG_EM_E1,
DAHDI_SIG_DACS_RBS,
DAHDI_SIG_HARDHDLC,
DAHDI_SIG_MTP2,
};
chan = dev_to_chan(dev);
for (i = 0; i < ARRAY_SIZE(sigtypes); i++) {
uint x = chan->sigcap & sigtypes[i];
if (x == sigtypes[i])
len += sprintf(buf + len, "%s ", sigstr(x));
}
while (len > 0 && isspace(buf[len - 1])) /* trim */
len--;
len += sprintf(buf + len, "\n");
return len;
}
static BUS_ATTR_READER(sig_show, dev, buf)
{
struct dahdi_chan *chan;
chan = dev_to_chan(dev);
return sprintf(buf, "%s\n", sigstr(chan->sig));
}
static BUS_ATTR_READER(in_use_show, dev, buf)
{
struct dahdi_chan *chan;
chan = dev_to_chan(dev);
return sprintf(buf, "%d\n", test_bit(DAHDI_FLAGBIT_OPEN, &chan->flags));
}
static BUS_ATTR_READER(alarms_show, dev, buf)
{
struct dahdi_chan *chan;
int len;
chan = dev_to_chan(dev);
len = fill_alarm_string(buf, PAGE_SIZE, chan->chan_alarms);
buf[len++] = '\n';
return len;
}
static BUS_ATTR_READER(ec_factory_show, dev, buf)
{
struct dahdi_chan *chan;
int len = 0;
chan = dev_to_chan(dev);
if (chan->ec_factory)
len += sprintf(buf, "%s", chan->ec_factory->get_name(chan));
buf[len++] = '\n';
return len;
}
static BUS_ATTR_READER(ec_state_show, dev, buf)
{
struct dahdi_chan *chan;
int len = 0;
chan = dev_to_chan(dev);
if (chan->ec_factory)
len += sprintf(buf, "%sACTIVE", (chan->ec_state) ? "" : "IN");
buf[len++] = '\n';
return len;
}
static struct device_attribute chan_dev_attrs[] = {
__ATTR_RO(name),
__ATTR_RO(channo),
__ATTR_RO(chanpos),
__ATTR_RO(sig),
__ATTR_RO(sigcap),
__ATTR_RO(alarms),
__ATTR_RO(ec_factory),
__ATTR_RO(ec_state),
__ATTR_RO(blocksize),
#ifdef OPTIMIZE_CHANMUTE
__ATTR_RO(chanmute),
#endif
__ATTR_RO(in_use),
__ATTR_NULL,
};
static void chan_release(struct device *dev)
{
struct dahdi_chan *chan;
BUG_ON(!dev);
chan = dev_to_chan(dev);
chan_dbg(DEVICES, chan, "SYSFS\n");
}
static int chan_match(struct device *dev, struct device_driver *driver)
{
struct dahdi_chan *chan;
chan = dev_to_chan(dev);
chan_dbg(DEVICES, chan, "SYSFS\n");
return 1;
}
static struct bus_type chan_bus_type = {
.name = "dahdi_channels",
.match = chan_match,
.dev_attrs = chan_dev_attrs,
};
static int chan_probe(struct device *dev)
{
struct dahdi_chan *chan;
chan = dev_to_chan(dev);
chan_dbg(DEVICES, chan, "SYSFS\n");
return 0;
}
static int chan_remove(struct device *dev)
{
struct dahdi_chan *chan;
chan = dev_to_chan(dev);
chan_dbg(DEVICES, chan, "SYSFS\n");
return 0;
}
static struct device_driver chan_driver = {
.name = "dahdi",
.bus = &chan_bus_type,
#ifndef OLD_HOTPLUG_SUPPORT
.owner = THIS_MODULE,
#endif
.probe = chan_probe,
.remove = chan_remove
};
int chan_sysfs_create(struct dahdi_chan *chan)
{
char chan_name[32];
void *dummy;
int res = 0;
struct device *dev;
struct dahdi_span *span;
int res;
dev_t devt;
if (chan->channo >= 250)
return 0;
chan_dbg(DEVICES, chan, "Creating channel %d\n", chan->channo);
if (test_bit(DAHDI_FLAGBIT_DEVFILE, &chan->flags))
return 0;
snprintf(chan_name, sizeof(chan_name), "dahdi!%d", chan->channo);
dummy = (void *)MAKE_DAHDI_DEV(chan->channo, chan_name);
if (IS_ERR(dummy)) {
res = PTR_ERR(dummy);
chan_err(chan, "Failed creating sysfs device: %d\n",
res);
span = chan->span;
devt = MKDEV(MAJOR(dahdi_channels_devt), chan->channo);
dev = &chan->chan_device;
memset(dev, 0, sizeof(*dev));
dev->devt = devt;
dev->bus = &chan_bus_type;
dev->parent = span->span_device;
/*
* FIXME: the name cannot be longer than KOBJ_NAME_LEN
*/
dev_set_name(dev, "dahdi!chan!%03d!%03d", span->spanno, chan->chanpos);
dev_set_drvdata(dev, chan);
dev->release = chan_release;
res = device_register(dev);
if (res) {
chan_err(chan, "%s: device_register failed: %d\n",
__func__, res);
put_device(dev);
return res;
}
set_bit(DAHDI_FLAGBIT_DEVFILE, &chan->flags);
@@ -62,9 +263,18 @@ int chan_sysfs_create(struct dahdi_chan *chan)
void chan_sysfs_remove(struct dahdi_chan *chan)
{
struct device *dev = &chan->chan_device;
chan_dbg(DEVICES, chan, "Destroying channel %d\n", chan->channo);
if (!dev_get_drvdata(dev))
return;
if (!test_bit(DAHDI_FLAGBIT_DEVFILE, &chan->flags))
return;
DEL_DAHDI_DEV(chan->channo);
dev = &chan->chan_device;
BUG_ON(dev_get_drvdata(dev) != chan);
device_unregister(dev);
/* FIXME: should have been done earlier in dahdi_chan_unreg */
chan->channo = -1;
clear_bit(DAHDI_FLAGBIT_DEVFILE, &chan->flags);
}
@@ -77,7 +287,7 @@ int dahdi_register_chardev(struct dahdi_chardev *dev)
char *udevname;
udevname = kzalloc(strlen(dev->name) + sizeof(DAHDI_STRING) + 1,
GFP_KERNEL);
GFP_KERNEL);
if (!udevname)
return -ENOMEM;
@@ -181,28 +391,86 @@ cleanup:
*/
static void sysfs_channels_cleanup(void)
{
if (should_cleanup.cdev) {
dahdi_dbg(DEVICES, "removing channels cdev\n");
cdev_del(&dahdi_channels_cdev);
should_cleanup.cdev = 0;
}
if (dahdi_channels_devt) {
dahdi_dbg(DEVICES, "unregistering chrdev_region\n");
unregister_chrdev_region(dahdi_channels_devt,
DAHDI_MAX_CHANNELS);
}
fixed_devfiles_remove();
if (dahdi_class) {
dahdi_dbg(DEVICES, "Destroying DAHDI class:\n");
class_destroy(dahdi_class);
dahdi_class = NULL;
}
if (should_cleanup.channel_driver) {
dahdi_dbg(DEVICES, "Removing channel driver\n");
driver_unregister(&chan_driver);
should_cleanup.channel_driver = 0;
}
if (should_cleanup.channels_bus) {
dahdi_dbg(DEVICES, "Removing channels bus\n");
bus_unregister(&chan_bus_type);
should_cleanup.channels_bus = 0;
}
}
int __init dahdi_sysfs_chan_init(const struct file_operations *fops)
{
int res = 0;
dahdi_dbg(DEVICES, "Registering channels bus\n");
res = bus_register(&chan_bus_type);
if (res) {
dahdi_err("%s: bus_register(%s) failed. Error number %d\n",
__func__, chan_bus_type.name, res);
goto cleanup;
}
should_cleanup.channels_bus = 1;
dahdi_dbg(DEVICES, "Registering channel driver\n");
res = driver_register(&chan_driver);
if (res) {
dahdi_err("%s: driver_register(%s) failed. Error number %d",
__func__, chan_driver.name, res);
goto cleanup;
}
should_cleanup.channel_driver = 1;
dahdi_class = class_create(THIS_MODULE, "dahdi");
if (IS_ERR(dahdi_class)) {
res = PTR_ERR(dahdi_class);
dahdi_err("%s: class_create(dahi_chan) failed. Error: %d\n",
__func__, res);
__func__, res);
goto cleanup;
}
res = fixed_devfiles_create();
if (res)
goto cleanup;
dahdi_dbg(DEVICES, "allocating chrdev_region\n");
res = alloc_chrdev_region(&dahdi_channels_devt,
0,
DAHDI_MAX_CHANNELS,
"dahdi_channels");
if (res) {
dahdi_err("%s: Failed allocating chrdev for %d channels (%d)",
__func__, DAHDI_MAX_CHANNELS, res);
goto cleanup;
}
dahdi_dbg(DEVICES, "adding channels cdev\n");
cdev_init(&dahdi_channels_cdev, fops);
res = cdev_add(&dahdi_channels_cdev, dahdi_channels_devt,
DAHDI_MAX_CHANNELS);
if (res) {
dahdi_err("%s: cdev_add() failed (%d)", __func__, res);
goto cleanup;
}
should_cleanup.cdev = 1;
return 0;
cleanup:
sysfs_channels_cleanup();

View File

@@ -88,6 +88,8 @@ static int txerrors;
static struct tasklet_struct dahdi_dynamic_tlet;
static void dahdi_dynamic_tasklet(unsigned long data);
#else
static struct tasklet_struct dahdi_dynamic_flush_tlet;
#endif
static DEFINE_MUTEX(dspan_mutex);
@@ -208,12 +210,25 @@ static void __dahdi_dynamic_run(void)
dahdi_dynamic_sendmessage(d);
}
#ifdef ENABLE_TASKLETS
/* If tasklets are not enabled, the above section will be called in
* interrupt context and the flushing of each driver will be called in a
* separate tasklet that only handles that. This is necessary since some
* of the dynamic spans need to call functions that require interrupts
* to be enabled but dahdi_transmit / ...sendmessage needs to be called
* each time the masterspan is processed which happens with interrupts
* disabled.
*
*/
tasklet_hi_schedule(&dahdi_dynamic_flush_tlet);
#else
list_for_each_entry_rcu(drv, &driver_list, list) {
/* Flush any traffic still pending in the driver */
if (drv->flush) {
drv->flush();
}
}
#endif
rcu_read_unlock();
}
@@ -708,6 +723,20 @@ static void dahdi_dynamic_tasklet(unsigned long data)
}
taskletpending = 0;
}
#else
static void dahdi_dynamic_flush_tasklet(unsigned long data)
{
struct dahdi_dynamic_driver *drv;
rcu_read_lock();
list_for_each_entry_rcu(drv, &driver_list, list) {
/* Flush any traffic still pending in the driver */
if (drv->flush) {
drv->flush();
}
}
rcu_read_unlock();
}
#endif
static int dahdi_dynamic_ioctl(unsigned int cmd, unsigned long data)
@@ -840,6 +869,8 @@ static int dahdi_dynamic_init(void)
mod_timer(&alarmcheck, jiffies + 1 * HZ);
#ifdef ENABLE_TASKLETS
tasklet_init(&dahdi_dynamic_tlet, dahdi_dynamic_tasklet, 0);
#else
tasklet_init(&dahdi_dynamic_flush_tlet, dahdi_dynamic_flush_tasklet, 0);
#endif
dahdi_set_dynamic_ops(&dahdi_dynamic_ops);
@@ -856,6 +887,9 @@ static void dahdi_dynamic_cleanup(void)
tasklet_disable(&dahdi_dynamic_tlet);
tasklet_kill(&dahdi_dynamic_tlet);
}
#else
tasklet_disable(&dahdi_dynamic_flush_tlet);
tasklet_kill(&dahdi_dynamic_flush_tlet);
#endif
del_timer_sync(&alarmcheck);
/* Must call again in case it was running before and rescheduled

View File

@@ -185,44 +185,16 @@ static void ztdeth_transmit(struct dahdi_dynamic *dyn, u8 *msg, size_t msglen)
spin_unlock_irqrestore(&zlock, flags);
}
/**
* dahdi_dynamic_flush_work_fn - Flush all pending transactions.
*
* This function is run in a work queue since we can't guarantee interrupts
* will be enabled when we're called, and dev_queue_xmit() requires that
* interrupts be enabled.
*
*/
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
static void dahdi_dynamic_flush_work_fn(void *data)
#else
static void dahdi_dynamic_flush_work_fn(struct work_struct *work)
#endif
{
struct sk_buff *skb;
/* Handle all transmissions now */
while ((skb = skb_dequeue(&skbs))) {
dev_queue_xmit(skb);
}
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
static DECLARE_WORK(dahdi_dynamic_eth_flush_work,
dahdi_dynamic_flush_work_fn, NULL);
#else
static DECLARE_WORK(dahdi_dynamic_eth_flush_work,
dahdi_dynamic_flush_work_fn);
#endif
/**
* ztdeth_flush - Flush all pending transactions.
*
* This function is called in interrupt context while processing the master
* span.
* This function is always called in softirq context.
*/
static int ztdeth_flush(void)
{
schedule_work(&dahdi_dynamic_eth_flush_work);
struct sk_buff *skb;
while ((skb = skb_dequeue(&skbs)))
dev_queue_xmit(skb);
return 0;
}
@@ -446,11 +418,6 @@ static int __init ztdeth_init(void)
static void __exit ztdeth_exit(void)
{
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
flush_scheduled_work();
#else
cancel_work_sync(&dahdi_dynamic_eth_flush_work);
#endif
dahdi_dynamic_unregister_driver(&ztd_eth);
unregister_netdevice_notifier(&ztdeth_nblock);
dev_remove_pack(&ztdeth_ptype);

View File

@@ -36,6 +36,7 @@
#include <linux/netdevice.h>
#include <linux/notifier.h>
#include <linux/crc32.h>
#include <linux/seq_file.h>
/**
* Undefine USE_PROC_FS, if you do not want the /proc/dahdi/dynamic-ethmf
@@ -696,71 +697,69 @@ static void timer_callback(unsigned long param)
#ifdef USE_PROC_FS
static struct proc_dir_entry *proc_entry;
static const char *ztdethmf_procname = "dahdi/dynamic-ethmf";
static int ztdethmf_proc_read(char *page, char **start, off_t off, int count,
int *eof, void *data)
static int ztdethmf_proc_show(struct seq_file *sfile, void *not_used)
{
struct ztdeth *z = NULL;
int len = 0, i = 0;
int i = 0;
unsigned int group = 0, c = 0;
rcu_read_lock();
len += sprintf(page + len, "Errors: %d\n\n", atomic_read(&errcount));
seq_printf(sfile, "Errors: %d\n\n", atomic_read(&errcount));
for (group = 0; group < ETHMF_MAX_GROUPS; ++group) {
if (atomic_read(&(ethmf_groups[group].spans))) {
len += sprintf(page + len, "Group #%d (0x%x)\n", i++, ethmf_groups[group].hash_addr);
len += sprintf(page + len, " Spans: %d\n",
atomic_read(&(ethmf_groups[group].spans)));
seq_printf(sfile, "Group #%d (0x%x)\n", i++,
ethmf_groups[group].hash_addr);
seq_printf(sfile, "Spans: %d\n",
atomic_read(&(ethmf_groups[group].spans)));
c = 1;
list_for_each_entry_rcu(z, &ethmf_list, list) {
if (z->addr_hash == ethmf_groups[group].hash_addr) {
if (c == 1) {
len += sprintf(page + len,
seq_printf(sfile,
" Device: %s (MAC: %02x:%02x:%02x:%02x:%02x:%02x)\n",
z->ethdev,
z->addr[0], z->addr[1], z->addr[2],
z->addr[3], z->addr[4], z->addr[5]);
}
len += sprintf(page + len, " Span %d: subaddr=%u ready=%d delay=%d real_channels=%d no_front_padding=%d\n",
seq_printf(sfile, " Span %d: subaddr=%u ready=%d delay=%d real_channels=%d no_front_padding=%d\n",
c++, ntohs(z->subaddr),
atomic_read(&z->ready), atomic_read(&z->delay),
z->real_channels, atomic_read(&z->no_front_padding));
}
}
len += sprintf(page + len, " Device UPs: %u\n",
seq_printf(sfile, " Device UPs: %u\n",
atomic_read(&(ethmf_groups[group].devupcount)));
len += sprintf(page + len, " Device DOWNs: %u\n",
seq_printf(sfile, " Device DOWNs: %u\n",
atomic_read(&(ethmf_groups[group].devdowncount)));
len += sprintf(page + len, " Rx Frames: %u\n",
seq_printf(sfile, " Rx Frames: %u\n",
atomic_read(&(ethmf_groups[group].rxframecount)));
len += sprintf(page + len, " Tx Frames: %u\n",
seq_printf(sfile, " Tx Frames: %u\n",
atomic_read(&(ethmf_groups[group].txframecount)));
len += sprintf(page + len, " Rx Bytes: %u\n",
seq_printf(sfile, " Rx Bytes: %u\n",
atomic_read(&(ethmf_groups[group].rxbytecount)));
len += sprintf(page + len, " Tx Bytes: %u\n",
seq_printf(sfile, " Tx Bytes: %u\n",
atomic_read(&(ethmf_groups[group].txbytecount)));
if (len <= off) {
off -= len;
len = 0;
}
if (len > off+count)
break;
}
}
rcu_read_unlock();
if (len <= off) {
off -= len;
len = 0;
}
*start = page + off;
len -= off;
if (len > count)
len = count;
return len;
return 0;
}
static int ztdethmf_proc_open(struct inode *inode, struct file *file)
{
return single_open(file, ztdethmf_proc_show, NULL);
}
static const struct file_operations ztdethmf_proc_fops = {
.open = ztdethmf_proc_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
#endif
static int __init ztdethmf_init(void)
@@ -778,8 +777,8 @@ static int __init ztdethmf_init(void)
skb_queue_head_init(&skbs);
#ifdef USE_PROC_FS
proc_entry = create_proc_read_entry(ztdethmf_procname, 0444, NULL,
ztdethmf_proc_read, NULL);
proc_entry = proc_create_data(ztdethmf_procname, 0444, NULL,
&ztdethmf_proc_fops, NULL);
if (!proc_entry) {
printk(KERN_ALERT "create_proc_read_entry failed.\n");
}

View File

@@ -22,6 +22,7 @@
.PHONY: dist-clean clean all uninstall have_download install object-build hotplug-install hotplug-dirs hotplug-uninstall make_firmware_object firmware-loaders
OCT6114_032_VERSION:=1.05.01
OCT6114_064_VERSION:=1.05.01
OCT6114_128_VERSION:=1.05.01
OCT6114_256_VERSION:=1.05.01
@@ -30,10 +31,12 @@ VPMADT032_VERSION:=1.25.0
HX8_VERSION:=2.06
VPMOCT032_VERSION:=1.12.0
WCT820_VERSION:=1.76
TE133_VERSION:=6f0017
TE134_VERSION:=6f0017
FIRMWARE_URL:=http://downloads.digium.com/pub/telephony/firmware/releases
ALL_FIRMWARE=FIRMWARE-OCT6114-064 FIRMWARE-OCT6114-128 FIRMWARE-OCT6114-256 FIRMWARE-TC400M FIRMWARE-HX8 FIRMWARE-VPMOCT032 FIRMWARE-TE820
ALL_FIRMWARE=FIRMWARE-OCT6114-032 FIRMWARE-OCT6114-064 FIRMWARE-OCT6114-128 FIRMWARE-OCT6114-256 FIRMWARE-TC400M FIRMWARE-HX8 FIRMWARE-VPMOCT032 FIRMWARE-TE820 FIRMWARE-TE133 FIRMWARE-TE134
# Firmware files should use the naming convention: dahdi-fw-<base name>-<sub name>-<version> or dahdi-fw-<base name>-<version>
# First example: dahdi-fw-oct6114-064-1.05.01
@@ -42,17 +45,21 @@ ALL_FIRMWARE=FIRMWARE-OCT6114-064 FIRMWARE-OCT6114-128 FIRMWARE-OCT6114-256 FIRM
# This means this is version MR5.6 of the tc400m firmware
# Build a list of firmware package filenames we need
FIRMWARE:=$(ALL_FIRMWARE:FIRMWARE-OCT6114-064=dahdi-fw-oct6114-064-$(OCT6114_064_VERSION).tar.gz)
FIRMWARE:=$(ALL_FIRMWARE:FIRMWARE-OCT6114-032=dahdi-fw-oct6114-032-$(OCT6114_032_VERSION).tar.gz)
FIRMWARE:=$(FIRMWARE:FIRMWARE-OCT6114-064=dahdi-fw-oct6114-064-$(OCT6114_064_VERSION).tar.gz)
FIRMWARE:=$(FIRMWARE:FIRMWARE-OCT6114-128=dahdi-fw-oct6114-128-$(OCT6114_128_VERSION).tar.gz)
FIRMWARE:=$(FIRMWARE:FIRMWARE-OCT6114-256=dahdi-fw-oct6114-256-$(OCT6114_256_VERSION).tar.gz)
FIRMWARE:=$(FIRMWARE:FIRMWARE-TC400M=dahdi-fw-tc400m-$(TC400M_VERSION).tar.gz)
FIRMWARE:=$(FIRMWARE:FIRMWARE-HX8=dahdi-fw-hx8-$(HX8_VERSION).tar.gz)
FIRMWARE:=$(FIRMWARE:FIRMWARE-VPMOCT032=dahdi-fw-vpmoct032-$(VPMOCT032_VERSION).tar.gz)
FIRMWARE:=$(FIRMWARE:FIRMWARE-TE820=dahdi-fw-te820-$(WCT820_VERSION).tar.gz)
FIRMWARE:=$(FIRMWARE:FIRMWARE-TE133=dahdi-fw-te133-$(TE133_VERSION).tar.gz)
FIRMWARE:=$(FIRMWARE:FIRMWARE-TE134=dahdi-fw-te134-$(TE134_VERSION).tar.gz)
FWLOADERS:=dahdi-fwload-vpmadt032-$(VPMADT032_VERSION).tar.gz
# Build a list of object files if hotplug will not be used
OBJECT_FILES:=$(ALL_FIRMWARE:FIRMWARE-OCT6114-032=dahdi-fw-oct6114-032.o)
OBJECT_FILES:=$(ALL_FIRMWARE:FIRMWARE-OCT6114-064=dahdi-fw-oct6114-064.o)
OBJECT_FILES:=$(OBJECT_FILES:FIRMWARE-OCT6114-128=dahdi-fw-oct6114-128.o)
OBJECT_FILES:=$(OBJECT_FILES:FIRMWARE-OCT6114-256=dahdi-fw-oct6114-256.o)
@@ -107,6 +114,17 @@ $(DESTDIR)/usr/lib/hotplug/firmware $(DESTDIR)/lib/firmware:
# Install all downloaded firmware images for hotplug usage
hotplug-install: $(DESTDIR)/usr/lib/hotplug/firmware $(DESTDIR)/lib/firmware $(FIRMWARE)
ifeq ($(shell if ( [ -f $(DESTDIR)/usr/lib/hotplug/firmware/.dahdi-fw-oct6114-032-$(OCT6114_032_VERSION) ] ) && ( [ -f $(DESTDIR)/lib/firmware/.dahdi-fw-oct6114-032-$(OCT6114_032_VERSION) ] ); then echo "no"; else echo "yes"; fi),yes)
@echo "Installing dahdi-fw-oct6114-032.bin to hotplug firmware directories"
@install -m 644 dahdi-fw-oct6114-032.bin $(DESTDIR)/usr/lib/hotplug/firmware
@rm -rf $(DESTDIR)/usr/lib/hotplug/firmware/.dahdi-fw-oct6114-032-*
@touch $(DESTDIR)/usr/lib/hotplug/firmware/.dahdi-fw-oct6114-032-$(OCT6114_032_VERSION)
@install -m 644 dahdi-fw-oct6114-032.bin $(DESTDIR)/lib/firmware
@rm -rf $(DESTDIR)/lib/firmware/.dahdi-fw-oct6114-032-*
@touch $(DESTDIR)/lib/firmware/.dahdi-fw-oct6114-032-$(OCT6114_032_VERSION)
else
@echo "Firmware dahdi-fw-oct6114-032.bin is already installed with required version $(OCT6114_032_VERSION)"
endif
ifeq ($(shell if ( [ -f $(DESTDIR)/usr/lib/hotplug/firmware/.dahdi-fw-oct6114-064-$(OCT6114_064_VERSION) ] ) && ( [ -f $(DESTDIR)/lib/firmware/.dahdi-fw-oct6114-064-$(OCT6114_064_VERSION) ] ); then echo "no"; else echo "yes"; fi),yes)
@echo "Installing dahdi-fw-oct6114-064.bin to hotplug firmware directories"
@install -m 644 dahdi-fw-oct6114-064.bin $(DESTDIR)/usr/lib/hotplug/firmware
@@ -185,6 +203,29 @@ else
@echo "Firmware dahdi-fw-te820.bin is already installed with required version $(WCT820_VERSION)"
endif
ifeq ($(shell if ( [ -f $(DESTDIR)/usr/lib/hotplug/firmware/.dahdi-fw-te133-$(TE133_VERSION) ] ) && ( [ -f $(DESTDIR)/lib/firmware/.dahdi-fw-te133-$(TE133_VERSION) ] ); then echo "no"; else echo "yes"; fi),yes)
@echo "Installing dahdi-fw-te133.bin to hotplug firmware directories"
@install -m 644 dahdi-fw-te133.bin $(DESTDIR)/usr/lib/hotplug/firmware
@rm -rf $(DESTDIR)/usr/lib/hotplug/firmware/.dahdi-fw-te133-*
@touch $(DESTDIR)/usr/lib/hotplug/firmware/.dahdi-fw-te133-$(TE133_VERSION)
@install -m 644 dahdi-fw-te133.bin $(DESTDIR)/lib/firmware
@rm -rf $(DESTDIR)/lib/firmware/.dahdi-fw-te133-*
@touch $(DESTDIR)/lib/firmware/.dahdi-fw-te133-$(TE133_VERSION)
else
@echo "Firmware dahdi-fw-te133.bin is already installed with required version $(TE133_VERSION)"
endif
ifeq ($(shell if ( [ -f $(DESTDIR)/usr/lib/hotplug/firmware/.dahdi-fw-te134-$(TE134_VERSION) ] ) && ( [ -f $(DESTDIR)/lib/firmware/.dahdi-fw-te134-$(TE134_VERSION) ] ); then echo "no"; else echo "yes"; fi),yes)
@echo "Installing dahdi-fw-te134.bin to hotplug firmware directories"
@install -m 644 dahdi-fw-te134.bin $(DESTDIR)/usr/lib/hotplug/firmware
@rm -rf $(DESTDIR)/usr/lib/hotplug/firmware/.dahdi-fw-te134-*
@touch $(DESTDIR)/usr/lib/hotplug/firmware/.dahdi-fw-te134-$(TE134_VERSION)
@install -m 644 dahdi-fw-te134.bin $(DESTDIR)/lib/firmware
@rm -rf $(DESTDIR)/lib/firmware/.dahdi-fw-te134-*
@touch $(DESTDIR)/lib/firmware/.dahdi-fw-te134-$(TE134_VERSION)
else
@echo "Firmware dahdi-fw-te134.bin is already installed with required version $(TE134_VERSION)"
endif
# Uninstall any installed dahdi firmware images from hotplug firmware directories
hotplug-uninstall:
if [ -d $(DESTDIR)/usr/lib/hotplug/firmware ]; then \
@@ -202,6 +243,11 @@ make_firmware_object: make_firmware_object.in ../dahdi-base.o
sed -e s/BFDNAME/$${BFDNAME}/ -e s/BFDARCH/$${BFDARCH}/ $< > $@
@chmod +x $@
# Build object file of an oct6114 032 firmware image for linking
dahdi-fw-oct6114-032.o: dahdi-fw-oct6114-032-$(OCT6114_032_VERSION).tar.gz dahdi-fw-oct6114-032.bin make_firmware_object
@echo Making firmware object file for dahdi-fw-oct6114-032.bin
./make_firmware_object dahdi-fw-oct6114-032.bin $@
# Build object file of an oct6114 064 firmware image for linking
dahdi-fw-oct6114-064.o: dahdi-fw-oct6114-064-$(OCT6114_064_VERSION).tar.gz dahdi-fw-oct6114-064.bin make_firmware_object
@echo Making firmware object file for dahdi-fw-oct6114-064.bin

View File

@@ -1,38 +1,30 @@
CFLAGS=-V3.4 -ffunction-sections -I/lib/modules/$(shell uname -r)/build/include -Iinclude -Ioctdeviceapi -Ioctdeviceapi/oct6100api -DGFP_ATOMIC=0 -Dkmalloc=calloc -Dkfree=free
LDFLAGS=-V3.4 -Wl,-Map -Wl,test.map -Wl,--gc-sections
#
# Produces the oct612x library
#
octapi_files = octdeviceapi/oct6100api/oct6100_api/oct6100_adpcm_chan.o \
octdeviceapi/oct6100api/oct6100_api/oct6100_channel.o \
octdeviceapi/oct6100api/oct6100_api/oct6100_chip_open.o \
octdeviceapi/oct6100api/oct6100_api/oct6100_chip_stats.o \
octdeviceapi/oct6100api/oct6100_api/oct6100_conf_bridge.o \
octdeviceapi/oct6100api/oct6100_api/oct6100_debug.o \
octdeviceapi/oct6100api/oct6100_api/oct6100_events.o \
octdeviceapi/oct6100api/oct6100_api/oct6100_interrupts.o \
octdeviceapi/oct6100api/oct6100_api/oct6100_memory.o \
octdeviceapi/oct6100api/oct6100_api/oct6100_miscellaneous.o \
octdeviceapi/oct6100api/oct6100_api/oct6100_mixer.o \
octdeviceapi/oct6100api/oct6100_api/oct6100_phasing_tsst.o \
octdeviceapi/oct6100api/oct6100_api/oct6100_playout_buf.o \
octdeviceapi/oct6100api/oct6100_api/oct6100_remote_debug.o \
octdeviceapi/oct6100api/oct6100_api/oct6100_tlv.o \
octdeviceapi/oct6100api/oct6100_api/oct6100_tone_detection.o \
octdeviceapi/oct6100api/oct6100_api/oct6100_tsi_cnct.o \
octdeviceapi/oct6100api/oct6100_api/oct6100_tsst.o \
apilib/bt/octapi_bt0.o \
apilib/largmath/octapi_largmath.o \
apilib/llman/octapi_llman.o
APIDIR=octdeviceapi/oct6100api/oct6100_api
OCTASIC_OBJS=$(APIDIR)/oct6100_adpcm_chan.o \
$(APIDIR)/oct6100_channel.o \
$(APIDIR)/oct6100_chip_open.o \
$(APIDIR)/oct6100_chip_stats.o \
$(APIDIR)/oct6100_conf_bridge.o \
$(APIDIR)/oct6100_debug.o \
$(APIDIR)/oct6100_events.o \
$(APIDIR)/oct6100_interrupts.o \
$(APIDIR)/oct6100_memory.o \
$(APIDIR)/oct6100_miscellaneous.o \
$(APIDIR)/oct6100_mixer.o \
$(APIDIR)/oct6100_phasing_tsst.o \
$(APIDIR)/oct6100_playout_buf.o \
$(APIDIR)/oct6100_remote_debug.o \
$(APIDIR)/oct6100_tlv.o \
$(APIDIR)/oct6100_tone_detection.o \
$(APIDIR)/oct6100_tsi_cnct.o \
$(APIDIR)/oct6100_tsst.o \
$(APIDIR)/oct6100_user.o \
apilib/bt/octapi_bt0.o \
apilib/largmath/octapi_largmath.o \
apilib/llman/octapi_llman.o
all: test
test.o: test.c
test: test.o $(OCTASIC_OBJS)
clean:
rm -rf test test.o
rm -rf $(OCTASIC_OBJS)
# TODO: ccflags was added in 2.6.24 in commit f77bf01425b11947eeb3b5b54. This
# should be changed to a conditional compilation based on the Kernel Version.
# ccflags-y := -I$(src)/.. -Wno-undef -I$(src)/include -I$(src)/octdeviceapi -I$(src)/octdeviceapi/oct6100api
EXTRA_CFLAGS = -I$(src)/.. -Wno-undef -I$(src)/include -I$(src)/octdeviceapi -I$(src)/octdeviceapi/oct6100api
lib-y := $(octapi_files)

View File

@@ -1242,7 +1242,8 @@ static char *hfc_decode_st_state(struct b4xxp *b4, int port, unsigned char state
"?", "?", "?", "?", "?", "?", "?", "?" }
};
if (!(str = kmalloc(256, GFP_KERNEL))) {
str = kmalloc(256, GFP_ATOMIC);
if (!str) {
dev_warn(&b4->pdev->dev, "could not allocate mem for ST state decode string!\n");
return NULL;
}

View File

@@ -14,7 +14,7 @@ ifeq ($(HOTPLUG_FIRMWARE),yes)
EXTRA_CFLAGS+=-DHOTPLUG_FIRMWARE
endif
wct4xxp-objs := base.o vpm450m.o $(shell $(src)/../oct612x/octasic-helper objects ../oct612x)
wct4xxp-objs := base.o vpm450m.o ../oct612x/lib.a
ifneq ($(HOTPLUG_FIRMWARE),yes)
wct4xxp-objs += $(FIRM_DIR)/dahdi-fw-oct6114-064.o $(FIRM_DIR)/dahdi-fw-oct6114-128.o $(FIRM_DIR)/dahdi-fw-oct6114-256.o

View File

@@ -390,7 +390,7 @@ static inline bool is_pcie(const struct t4 *wc)
static inline bool has_e1_span(const struct t4 *wc)
{
return (wc->t1e1) != 0;
return (wc->t1e1 > 0);
}
static inline bool is_octal(const struct t4 *wc)
@@ -1121,6 +1121,7 @@ static int t4_echocan_create(struct dahdi_chan *chan,
int channel;
const struct dahdi_echocan_ops *ops;
const struct dahdi_echocan_features *features;
const bool alaw = (chan->span->deflaw == 2);
if (!vpmsupport || !wc->vpm)
return -ENODEV;
@@ -1141,19 +1142,19 @@ static int t4_echocan_create(struct dahdi_chan *chan,
channel = has_e1_span(wc) ? chan->chanpos : chan->chanpos + 4;
if (wc->vpm) {
if (is_octal(wc))
channel = channel << 3;
else
channel = channel << 2;
channel |= chan->span->offset;
if (debug & DEBUG_ECHOCAN)
dev_notice(&wc->dev->dev, "echocan: Card is %d, "
"Channel is %d, Span is %d, offset is %d "
"length %d\n", wc->num, chan->chanpos,
chan->span->offset, channel, ecp->tap_length);
vpm450m_setec(wc->vpm, channel, ecp->tap_length);
if (is_octal(wc))
channel = channel << 3;
else
channel = channel << 2;
channel |= chan->span->offset;
if (debug & DEBUG_ECHOCAN) {
dev_notice(&wc->dev->dev,
"echocan: Card is %d, Channel is %d, Span is %d, offset is %d length %d\n",
wc->num, chan->chanpos, chan->span->offset,
channel, ecp->tap_length);
}
vpm450m_set_alaw_companding(wc->vpm, channel, alaw);
vpm450m_setec(wc->vpm, channel, ecp->tap_length);
return 0;
}
@@ -1162,23 +1163,23 @@ static void echocan_free(struct dahdi_chan *chan, struct dahdi_echocan_state *ec
struct t4 *wc = chan->pvt;
int channel;
memset(ec, 0, sizeof(*ec));
if (!wc->vpm)
return;
memset(ec, 0, sizeof(*ec));
channel = has_e1_span(wc) ? chan->chanpos : chan->chanpos + 4;
if (wc->vpm) {
if (is_octal(wc))
channel = channel << 3;
else
channel = channel << 2;
channel |= chan->span->offset;
if (debug & DEBUG_ECHOCAN)
dev_notice(&wc->dev->dev, "echocan: Card is %d, "
"Channel is %d, Span is %d, offset is %d "
"length 0\n", wc->num, chan->chanpos,
chan->span->offset, channel);
vpm450m_setec(wc->vpm, channel, 0);
if (is_octal(wc))
channel = channel << 3;
else
channel = channel << 2;
channel |= chan->span->offset;
if (debug & DEBUG_ECHOCAN) {
dev_notice(&wc->dev->dev,
"echocan: Card is %d, Channel is %d, Span is %d, offset is %d length 0\n",
wc->num, chan->chanpos, chan->span->offset, channel);
}
vpm450m_setec(wc->vpm, channel, 0);
}
#endif
@@ -2059,7 +2060,7 @@ static void t4_span_assigned(struct dahdi_span *span)
/* We use this to make sure all the spans are assigned before
* running the serial setup. */
list_for_each_entry(pos, &wc->ddev->spans, device_node) {
if (!test_bit(DAHDI_FLAGBIT_REGISTERED, &span->flags))
if (!test_bit(DAHDI_FLAGBIT_REGISTERED, &pos->flags))
++unassigned_spans;
}
@@ -2225,6 +2226,7 @@ static int t4_set_linemode(struct dahdi_span *span, enum spantypes linemode)
int res = 0;
enum linemode mode;
const char *old_name;
static DEFINE_MUTEX(linemode_lock);
dev_dbg(&wc->dev->dev, "Setting '%s' to '%s'\n", span->name,
dahdi_spantype2str(linemode));
@@ -2232,22 +2234,27 @@ static int t4_set_linemode(struct dahdi_span *span, enum spantypes linemode)
if (span->spantype == linemode)
return 0;
/* Do not allow the t1e1 member to be changed by multiple threads. */
mutex_lock(&linemode_lock);
old_name = dahdi_spantype2str(span->spantype);
switch (linemode) {
case SPANTYPE_DIGITAL_T1:
dev_info(&wc->dev->dev,
"Changing from %s to T1 line mode.\n", old_name);
mode = T1;
wc->t1e1 &= ~(1 << span->offset);
break;
case SPANTYPE_DIGITAL_E1:
dev_info(&wc->dev->dev,
"Changing from %s to E1 line mode.\n", old_name);
mode = E1;
wc->t1e1 |= (1 << span->offset);
break;
case SPANTYPE_DIGITAL_J1:
dev_info(&wc->dev->dev,
"Changing from %s to J1 line mode.\n", old_name);
mode = J1;
wc->t1e1 &= ~(1 << span->offset);
break;
default:
dev_err(&wc->dev->dev,
@@ -2261,6 +2268,7 @@ static int t4_set_linemode(struct dahdi_span *span, enum spantypes linemode)
dahdi_init_span(span);
}
mutex_unlock(&linemode_lock);
return res;
}
@@ -3682,7 +3690,7 @@ static inline void t4_framer_interrupt(struct t4 *wc, int span)
}
if (!ts->span.alarms) {
if ((isr3 & 0x3) || (isr4 & 0xc0))
ts->span.timingslips++;
ts->span.count.timingslips++;
if (debug & DEBUG_MAIN) {
if (isr3 & 0x02)
@@ -3703,7 +3711,7 @@ static inline void t4_framer_interrupt(struct t4 *wc, int span)
wc->numspans, span + 1);
}
} else
ts->span.timingslips = 0;
ts->span.count.timingslips = 0;
spin_lock_irqsave(&wc->reglock, flags);
/* HDLC controller checks - receive side */

View File

@@ -19,12 +19,17 @@
* this program for more details.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/string.h>
#include <linux/time.h>
#include <linux/version.h>
#include <dahdi/kernel.h>
#include <stdbool.h>
#include "vpm450m.h"
#include "oct6100api/oct6100_api.h"
@@ -177,6 +182,7 @@ struct vpm450m {
#define FLAG_DTMF (1 << 0)
#define FLAG_MUTE (1 << 1)
#define FLAG_ECHO (1 << 2)
#define FLAG_ALAW (1 << 3)
static unsigned int tones[] = {
SOUT_DTMF_1,
@@ -216,6 +222,50 @@ static unsigned int tones[] = {
ROUT_G168_1100GB_ON,
};
void vpm450m_set_alaw_companding(struct vpm450m *vpm450m, int channel,
bool alaw)
{
tOCT6100_CHANNEL_MODIFY *modify;
UINT32 ulResult;
UINT32 law_to_use = (alaw) ? cOCT6100_PCM_A_LAW :
cOCT6100_PCM_U_LAW;
if (channel >= ARRAY_SIZE(vpm450m->chanflags)) {
pr_err("Channel out of bounds in %s\n", __func__);
return;
}
/* If we're already in this companding mode, no need to do anything. */
if (alaw == ((vpm450m->chanflags[channel] & FLAG_ALAW) > 0))
return;
modify = kzalloc(sizeof(tOCT6100_CHANNEL_MODIFY), GFP_ATOMIC);
if (!modify) {
pr_notice("Unable to allocate memory for setec!\n");
return;
}
Oct6100ChannelModifyDef(modify);
modify->ulChannelHndl = vpm450m->aulEchoChanHndl[channel];
modify->fTdmConfigModified = TRUE;
modify->TdmConfig.ulSinPcmLaw = law_to_use;
modify->TdmConfig.ulRinPcmLaw = law_to_use;
modify->TdmConfig.ulSoutPcmLaw = law_to_use;
modify->TdmConfig.ulRoutPcmLaw = law_to_use;
ulResult = Oct6100ChannelModify(vpm450m->pApiInstance, modify);
if (ulResult != GENERIC_OK) {
pr_notice("Failed to apply echo can changes on channel %d %d %08x!\n",
vpm450m->aulEchoChanHndl[channel], channel, ulResult);
} else {
pr_info("Changed companding on channel %d to %s.\n", channel,
(alaw) ? "alaw" : "ulaw");
if (alaw)
vpm450m->chanflags[channel] |= FLAG_ALAW;
else
vpm450m->chanflags[channel] &= ~(FLAG_ALAW);
}
kfree(modify);
}
static void vpm450m_setecmode(struct vpm450m *vpm450m, int channel, int mode)
{
tOCT6100_CHANNEL_MODIFY *modify;
@@ -248,6 +298,11 @@ void vpm450m_setdtmf(struct vpm450m *vpm450m, int channel, int detect, int mute)
tOCT6100_CHANNEL_MODIFY *modify;
UINT32 ulResult;
if (channel >= ARRAY_SIZE(vpm450m->chanflags)) {
pr_err("Channel out of bounds in %s\n", __func__);
return;
}
modify = kmalloc(sizeof(tOCT6100_CHANNEL_MODIFY), GFP_KERNEL);
if (!modify) {
printk(KERN_NOTICE "wct4xxp: Unable to allocate memory for setdtmf!\n");
@@ -286,6 +341,11 @@ void vpm450m_setdtmf(struct vpm450m *vpm450m, int channel, int detect, int mute)
void vpm450m_setec(struct vpm450m *vpm450m, int channel, int eclen)
{
if (channel >= ARRAY_SIZE(vpm450m->chanflags)) {
pr_err("Channel out of bounds in %s\n", __func__);
return;
}
if (eclen) {
vpm450m->chanflags[channel] |= FLAG_ECHO;
vpm450m_setecmode(vpm450m, channel, cOCT6100_ECHO_OP_MODE_HT_RESET);
@@ -524,10 +584,13 @@ struct vpm450m *init_vpm450m(void *wc, int *isalaw, int numspans, const struct f
* therefore, the lower 2 bits tell us which span this
* timeslot/channel
*/
if (isalaw[x & mask])
if (isalaw[x & mask]) {
law = cOCT6100_PCM_A_LAW;
else
vpm450m->chanflags[x] |= FLAG_ALAW;
} else {
law = cOCT6100_PCM_U_LAW;
vpm450m->chanflags[x] &= ~(FLAG_ALAW);
}
Oct6100ChannelOpenDef(ChannelOpen);
ChannelOpen->pulChannelHndl = &vpm450m->aulEchoChanHndl[x];
ChannelOpen->ulUserChanId = x;

View File

@@ -39,5 +39,7 @@ void vpm450m_setdtmf(struct vpm450m *instance, int channel, int dtmfdetect, int
int vpm450m_checkirq(struct vpm450m *vpm450m);
int vpm450m_getdtmf(struct vpm450m *vpm450m, int *channel, int *tone, int *start);
void release_vpm450m(struct vpm450m *instance);
void vpm450m_set_alaw_companding(struct vpm450m *vpm450m,
int channel, bool alaw);
#endif

View File

@@ -866,6 +866,7 @@ wctc4xxp_initialize_descriptor_ring(struct pci_dev *pdev,
memset(dr->desc, 0, (sizeof(*d) + dr->padding) * DRING_SIZE);
for (i = 0; i < DRING_SIZE; ++i) {
d = wctc4xxp_descriptor(dr, i);
memset(d, 0, sizeof(*d));
d->des1 = cpu_to_le32(des1);
}

View File

@@ -1961,19 +1961,26 @@ wctdm_check_battery_lost(struct wctdm *wc, struct wctdm_module *const mod)
battery present or unknown, debounce timer (going to battery lost)
*/
switch (fxo->battery_state) {
case BATTERY_DEBOUNCING_PRESENT_ALARM:
fxo->battery_state = BATTERY_DEBOUNCING_LOST_FROM_PRESENT_ALARM;
fxo->battdebounce_timer = wc->framecount + battdebounce;
break;
case BATTERY_DEBOUNCING_PRESENT:
/* we were going to BATTERY_PRESENT, but
* battery was lost again. */
fxo->battery_state = BATTERY_LOST;
break;
case BATTERY_DEBOUNCING_PRESENT_FROM_LOST_ALARM:
fxo->battery_state = BATTERY_DEBOUNCING_LOST_ALARM;
fxo->battdebounce_timer = wc->framecount +
battalarm - battdebounce;
break;
case BATTERY_UNKNOWN:
mod_hooksig(wc, mod, DAHDI_RXSIG_ONHOOK);
case BATTERY_DEBOUNCING_PRESENT_ALARM: /* intentional drop through */
case BATTERY_PRESENT:
fxo->battery_state = BATTERY_DEBOUNCING_LOST;
fxo->battdebounce_timer = wc->framecount + battdebounce;
break;
case BATTERY_DEBOUNCING_LOST:
case BATTERY_DEBOUNCING_LOST_FROM_PRESENT_ALARM:
case BATTERY_DEBOUNCING_LOST: /* Intentional drop through */
if (time_after(wc->framecount, fxo->battdebounce_timer)) {
if (debug) {
dev_info(&wc->vb.pdev->dev,
@@ -2022,8 +2029,9 @@ wctdm_check_battery_present(struct wctdm *wc, struct wctdm_module *const mod)
struct fxo *const fxo = &mod->mod.fxo;
switch (fxo->battery_state) {
case BATTERY_DEBOUNCING_PRESENT:
if (time_after(jiffies, fxo->battdebounce_timer)) {
case BATTERY_DEBOUNCING_PRESENT_FROM_LOST_ALARM:
case BATTERY_DEBOUNCING_PRESENT: /* intentional drop through */
if (time_after(wc->framecount, fxo->battdebounce_timer)) {
if (debug) {
dev_info(&wc->vb.pdev->dev,
"BATTERY on %d/%d (%s)!\n",
@@ -2048,12 +2056,12 @@ wctdm_check_battery_present(struct wctdm *wc, struct wctdm_module *const mod)
* of its time period has already passed while
* debouncing occurred */
fxo->battery_state = BATTERY_DEBOUNCING_PRESENT_ALARM;
fxo->battdebounce_timer = jiffies +
msecs_to_jiffies(battalarm - battdebounce);
fxo->battdebounce_timer = wc->framecount +
battalarm - battdebounce;
}
break;
case BATTERY_DEBOUNCING_PRESENT_ALARM:
if (time_after(jiffies, fxo->battdebounce_timer)) {
if (time_after(wc->framecount, fxo->battdebounce_timer)) {
fxo->battery_state = BATTERY_PRESENT;
dahdi_alarm_channel(get_dahdi_chan(wc, mod),
DAHDI_ALARM_NONE);
@@ -2061,18 +2069,23 @@ wctdm_check_battery_present(struct wctdm *wc, struct wctdm_module *const mod)
break;
case BATTERY_PRESENT:
break;
case BATTERY_DEBOUNCING_LOST_ALARM:
fxo->battery_state = BATTERY_DEBOUNCING_PRESENT_FROM_LOST_ALARM;
fxo->battdebounce_timer = wc->framecount + battdebounce;
break;
case BATTERY_DEBOUNCING_LOST_FROM_PRESENT_ALARM:
fxo->battery_state = BATTERY_DEBOUNCING_PRESENT_ALARM;
fxo->battdebounce_timer = wc->framecount +
battalarm - battdebounce;
break;
case BATTERY_DEBOUNCING_LOST:
/* we were going to BATTERY_LOST, but battery appeared again,
* so clear the debounce timer */
fxo->battery_state = BATTERY_PRESENT;
break;
case BATTERY_UNKNOWN:
mod_hooksig(wc, mod, DAHDI_RXSIG_OFFHOOK);
case BATTERY_LOST: /* intentional drop through */
case BATTERY_DEBOUNCING_LOST_ALARM:
fxo->battery_state = BATTERY_DEBOUNCING_PRESENT;
fxo->battdebounce_timer = jiffies +
msecs_to_jiffies(battdebounce);
fxo->battdebounce_timer = wc->framecount + battdebounce;
break;
}
}

View File

@@ -106,9 +106,11 @@ struct calregs {
enum battery_state {
BATTERY_UNKNOWN = 0,
BATTERY_DEBOUNCING_PRESENT,
BATTERY_DEBOUNCING_PRESENT_FROM_LOST_ALARM,
BATTERY_DEBOUNCING_PRESENT_ALARM,
BATTERY_PRESENT,
BATTERY_DEBOUNCING_LOST,
BATTERY_DEBOUNCING_LOST_FROM_PRESENT_ALARM,
BATTERY_DEBOUNCING_LOST_ALARM,
BATTERY_LOST,
};

View File

@@ -658,6 +658,17 @@ static int __t1_getresult(struct t1 *wc, struct command *cmd)
might_sleep();
if (test_bit(IOERROR, &wc->bit_flags)) {
spin_lock_irqsave(&wc->reglock, flags);
list_del_init(&cmd->node);
spin_unlock_irqrestore(&wc->reglock, flags);
if (printk_ratelimit()) {
dev_warn(&wc->vb.pdev->dev,
"Timeout in %s\n", __func__);
}
return -EIO;
}
ret = wait_for_completion_interruptible_timeout(&cmd->complete, HZ*10);
if (unlikely(!ret)) {
spin_lock_irqsave(&wc->reglock, flags);
@@ -666,13 +677,13 @@ static int __t1_getresult(struct t1 *wc, struct command *cmd)
* can go ahead and free it right away. */
list_del_init(&cmd->node);
spin_unlock_irqrestore(&wc->reglock, flags);
free_cmd(wc, cmd);
if (-ERESTARTSYS != ret) {
if (printk_ratelimit()) {
dev_warn(&wc->vb.pdev->dev,
"Timeout in %s\n", __func__);
}
ret = -EIO;
set_bit(IOERROR, &wc->bit_flags);
}
return ret;
} else {
@@ -683,7 +694,6 @@ static int __t1_getresult(struct t1 *wc, struct command *cmd)
ret = wait_for_completion_timeout(&cmd->complete, HZ*2);
WARN_ON(!ret);
ret = cmd->data;
free_cmd(wc, cmd);
return ret;
}
}
@@ -841,6 +851,75 @@ static void free_wc(struct t1 *wc)
kfree(wc);
}
/**
* t1_reset_registers - Put register back to their default values
*
* Since the card does not have an ability to reset just the framer
* specifically, we need to write all the default values to the framer.
*
*/
static void t1_reset_registers(struct t1 *wc)
{
int i;
struct t1_reg {
u8 address;
u8 value;
} __attribute__((packed));
struct t1_reg *reg;
static struct t1_reg DEFAULT_REGS[] = {
{0x00, 0x7d}, {0x01, 0x7d}, {0x02, 0x00}, {0x03, 0x00},
{0x04, 0xfd}, {0x05, 0xff}, {0x06, 0xff}, {0x07, 0xff},
{0x08, 0x05}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00},
{0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
{0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
{0x14, 0xff}, {0x15, 0xff}, {0x16, 0xff}, {0x17, 0xff},
{0x18, 0xff}, {0x19, 0xff}, {0x1a, 0x00}, {0x1b, 0x00},
{0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
{0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x04},
{0x24, 0x00}, {0x25, 0x05}, {0x26, 0x7b}, {0x27, 0x03},
{0x28, 0x40}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00},
{0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00},
{0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
{0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x80},
{0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x20}, {0x3b, 0x00},
{0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x0a}, {0x3f, 0x00},
{0x40, 0x04}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
{0x44, 0x30}, {0x45, 0x00}, {0x46, 0xc0}, {0x47, 0xff},
{0x48, 0x00}, {0x49, 0x1c}, {0x4a, 0x05}, {0x4b, 0x03},
{0x4c, 0xa3}, {0x4d, 0x28}, {0x4e, 0x00}, {0x4f, 0xc0},
{0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
{0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
{0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00},
{0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00},
{0x60, 0x00}, {0x61, 0x20}, {0x62, 0x00}, {0x63, 0x00},
{0x64, 0x5a}, {0x65, 0x02}, {0x66, 0x00}, {0x67, 0x00},
{0x68, 0x10}, {0x69, 0x09}, {0x6a, 0x00}, {0x6b, 0x03},
{0x6c, 0x00}, {0x6d, 0xc0}, {0x6e, 0x40}, {0x6f, 0x00},
{0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
{0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
{0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00},
{0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00},
{0x80, 0x00}, {0x81, 0x22}, {0x82, 0x65}, {0x83, 0x35},
{0x84, 0x31}, {0x85, 0x60}, {0x86, 0x03}, {0x87, 0x00},
{0x88, 0x00}, {0x89, 0x00}, {0x8a, 0x00}, {0x8b, 0x00},
{0x8c, 0x00}, {0x8d, 0x00}, {0x8e, 0x00}, {0x8f, 0x00},
{0x90, 0x00}, {0x91, 0x00}, {0x92, 0x00}, {0x93, 0x18},
{0x94, 0xfb}, {0x95, 0x0b}, {0x96, 0x00}, {0x97, 0x0b},
{0x98, 0xdb}, {0x99, 0xdf}, {0x9a, 0x48}, {0x9b, 0x00},
{0x9c, 0x3f}, {0x9d, 0x3f}, {0x9e, 0x77}, {0x9f, 0x77},
{0xa0, 0x00}, {0xa1, 0xff}, {0xa2, 0xff}, {0xa3, 0xff},
{0xa4, 0x00}, {0xa5, 0x00}, {0xa6, 0x00}, {0xa7, 0x00},
{0xa8, 0x00}
};
for (i = 0; i < ARRAY_SIZE(DEFAULT_REGS); ++i) {
reg = &DEFAULT_REGS[i];
t1_setreg(wc, reg->address, reg->value);
}
/* Flush previous writes. */
t1_getreg(wc, 0x1d);
}
static void t4_serial_setup(struct t1 *wc)
{
t1_setreg(wc, 0x85, 0xe0); /* GPC1: Multiplex mode enabled, FSC is output, active low, RCLK from channel 0 */
@@ -2029,10 +2108,13 @@ static int t1xxp_set_linemode(struct dahdi_span *span, enum spantypes linemode)
/* Stop the processing of the channels since we're going to change
* them. */
clear_bit(INITIALIZED, &wc->bit_flags);
synchronize_irq(wc->vb.pdev->irq);
smp_mb__after_clear_bit();
del_timer_sync(&wc->timer);
flush_workqueue(wc->wq);
t1_reset_registers(wc);
switch (linemode) {
case SPANTYPE_DIGITAL_T1:
dev_info(&wc->vb.pdev->dev,
@@ -2206,27 +2288,32 @@ static void t1_check_alarms(struct t1 *wc)
/* Detect loopup code if we're not sending one */
if ((!wc->span.mainttimer) && (d & 0x08)) {
/* Loop-up code detected */
if ((wc->span.maintstat != DAHDI_MAINT_REMOTELOOP)) {
if ((++wc->loopupcnt > 80) &&
(wc->span.maintstat != DAHDI_MAINT_REMOTELOOP)) {
t1_notice(wc, "Loopup detected,"\
" enabling remote loop\n");
t1_setreg(wc, 0x36, 0x08); /* LIM0: Disable any local loop */
t1_setreg(wc, 0x37, 0xf6); /* LIM1: Enable remote loop */
wc->span.maintstat = DAHDI_MAINT_REMOTELOOP;
}
} else
} else {
wc->loopupcnt = 0;
}
/* Same for loopdown code */
if ((!wc->span.mainttimer) && (d & 0x10)) {
/* Loop-down code detected */
if ((wc->span.maintstat == DAHDI_MAINT_REMOTELOOP)) {
if ((++wc->loopdowncnt > 80) &&
(wc->span.maintstat == DAHDI_MAINT_REMOTELOOP)) {
t1_notice(wc, "Loopdown detected,"\
" disabling remote loop\n");
t1_setreg(wc, 0x36, 0x08); /* LIM0: Disable any local loop */
t1_setreg(wc, 0x37, 0xf0); /* LIM1: Disable remote loop */
wc->span.maintstat = DAHDI_MAINT_NONE;
}
} else
} else {
wc->loopdowncnt = 0;
}
}
if (wc->span.lineconfig & DAHDI_CONFIG_NOTOPEN) {

View File

@@ -114,6 +114,7 @@ struct t1 {
#define INITIALIZED 1
#define SHUTDOWN 2
#define READY 3
#define IOERROR 4
unsigned long bit_flags;
unsigned long alarmtimer;
unsigned char ledstate;

File diff suppressed because it is too large Load Diff

View File

@@ -26,6 +26,7 @@
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/delay.h>
#include <linux/seq_file.h>
#include "xpd.h"
#include "xproto.h"
#include "xpp_dahdi.h"
@@ -152,8 +153,7 @@ static int write_state_register(xpd_t *xpd, __u8 value);
static bool bri_packet_is_valid(xpacket_t *pack);
static void bri_packet_dump(const char *msg, xpacket_t *pack);
#ifdef CONFIG_PROC_FS
static int proc_bri_info_read(char *page, char **start, off_t off, int count,
int *eof, void *data);
static const struct file_operations proc_bri_info_ops;
#endif
static int bri_spanconfig(struct file *file, struct dahdi_span *span,
struct dahdi_lineconfig *lc);
@@ -673,9 +673,8 @@ static int bri_proc_create(xbus_t *xbus, xpd_t *xpd)
XPD_DBG(PROC, xpd, "\n");
#ifdef CONFIG_PROC_FS
XPD_DBG(PROC, xpd, "Creating '%s'\n", PROC_BRI_INFO_FNAME);
priv->bri_info =
create_proc_read_entry(PROC_BRI_INFO_FNAME, 0444, xpd->proc_xpd_dir,
proc_bri_info_read, xpd);
priv->bri_info = proc_create_data(PROC_BRI_INFO_FNAME, 0444,
xpd->proc_xpd_dir, &proc_bri_info_ops, xpd);
if (!priv->bri_info) {
XPD_ERR(xpd, "Failed to create proc file '%s'\n",
PROC_BRI_INFO_FNAME);
@@ -1667,12 +1666,10 @@ static void bri_packet_dump(const char *msg, xpacket_t *pack)
/*------------------------- REGISTER Handling --------------------------*/
#ifdef CONFIG_PROC_FS
static int proc_bri_info_read(char *page, char **start, off_t off, int count,
int *eof, void *data)
static int proc_bri_info_show(struct seq_file *sfile, void *not_used)
{
int len = 0;
unsigned long flags;
xpd_t *xpd = data;
xpd_t *xpd = sfile->private;
struct BRI_priv_data *priv;
DBG(PROC, "\n");
@@ -1681,69 +1678,65 @@ static int proc_bri_info_read(char *page, char **start, off_t off, int count,
spin_lock_irqsave(&xpd->lock, flags);
priv = xpd->priv;
BUG_ON(!priv);
len += sprintf(page + len, "%05d Layer 1: ", priv->poll_counter);
seq_printf(sfile, "%05d Layer 1: ", priv->poll_counter);
if (priv->reg30_good) {
len +=
sprintf(page + len, "%-5s ",
(priv->layer1_up) ? "UP" : "DOWN");
len +=
sprintf(page + len,
"%c%d %-15s -- fr_sync=%d t2_exp=%d info0=%d g2_g3=%d\n",
IS_NT(xpd) ? 'G' : 'F',
priv->state_register.bits.v_su_sta,
xhfc_state_name(IS_NT(xpd),
priv->state_register.bits.v_su_sta),
priv->state_register.bits.v_su_fr_sync,
priv->state_register.bits.v_su_t2_exp,
priv->state_register.bits.v_su_info0,
priv->state_register.bits.v_g2_g3);
} else
len += sprintf(page + len, "Unknown\n");
seq_printf(sfile, "%-5s ", (priv->layer1_up) ? "UP" : "DOWN");
seq_printf(sfile,
"%c%d %-15s -- fr_sync=%d t2_exp=%d info0=%d g2_g3=%d\n",
IS_NT(xpd) ? 'G' : 'F',
priv->state_register.bits.v_su_sta,
xhfc_state_name(IS_NT(xpd),
priv->state_register.bits.v_su_sta),
priv->state_register.bits.v_su_fr_sync,
priv->state_register.bits.v_su_t2_exp,
priv->state_register.bits.v_su_info0,
priv->state_register.bits.v_g2_g3);
} else {
seq_printf(sfile, "Unknown\n");
}
if (IS_NT(xpd))
len += sprintf(page + len, "T1 Timer: %d\n", priv->t1);
seq_printf(sfile, "T1 Timer: %d\n", priv->t1);
else
len += sprintf(page + len, "T3 Timer: %d\n", priv->t3);
len += sprintf(page + len, "Tick Counter: %d\n", priv->tick_counter);
len +=
sprintf(page + len, "Last Poll Reply: %d ticks ago\n",
seq_printf(sfile, "T3 Timer: %d\n", priv->t3);
seq_printf(sfile, "Tick Counter: %d\n", priv->tick_counter);
seq_printf(sfile, "Last Poll Reply: %d ticks ago\n",
priv->reg30_ticks);
len += sprintf(page + len, "reg30_good=%d\n", priv->reg30_good);
len +=
sprintf(page + len, "D-Channel: TX=[%5d] RX=[%5d] BAD=[%5d] ",
seq_printf(sfile, "reg30_good=%d\n", priv->reg30_good);
seq_printf(sfile, "D-Channel: TX=[%5d] RX=[%5d] BAD=[%5d] ",
priv->dchan_tx_counter, priv->dchan_rx_counter,
priv->dchan_rx_drops);
if (priv->dchan_alive) {
len +=
sprintf(page + len, "(alive %d K-ticks)\n",
seq_printf(sfile, "(alive %d K-ticks)\n",
priv->dchan_alive_ticks / 1000);
} else {
len += sprintf(page + len, "(dead)\n");
seq_printf(sfile, "(dead)\n");
}
len +=
sprintf(page + len, "dchan_notx_ticks: %d\n",
seq_printf(sfile, "dchan_notx_ticks: %d\n",
priv->dchan_notx_ticks);
len +=
sprintf(page + len, "dchan_norx_ticks: %d\n",
seq_printf(sfile, "dchan_norx_ticks: %d\n",
priv->dchan_norx_ticks);
len +=
sprintf(page + len, "LED: %-10s = %d\n", "GREEN",
seq_printf(sfile, "LED: %-10s = %d\n", "GREEN",
priv->ledstate[GREEN_LED]);
len +=
sprintf(page + len, "LED: %-10s = %d\n", "RED",
seq_printf(sfile, "LED: %-10s = %d\n", "RED",
priv->ledstate[RED_LED]);
len += sprintf(page + len, "\nDCHAN:\n");
len += sprintf(page + len, "\n");
seq_printf(sfile, "\nDCHAN:\n");
seq_printf(sfile, "\n");
spin_unlock_irqrestore(&xpd->lock, flags);
if (len <= off + count)
*eof = 1;
*start = page + off;
len -= off;
if (len > count)
len = count;
if (len < 0)
len = 0;
return len;
return 0;
}
static int proc_bri_info_open(struct inode *inode, struct file *file)
{
return single_open(file, proc_bri_info_show, PDE_DATA(inode));
}
static const struct file_operations proc_bri_info_ops = {
.owner = THIS_MODULE,
.open = proc_bri_info_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
#endif
static int bri_xpd_probe(struct device *dev)

View File

@@ -24,6 +24,8 @@
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/delay.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include "xpd.h"
#include "xproto.h"
#include "xpp_dahdi.h"
@@ -36,6 +38,10 @@ static const char rcsid[] = "$Id$";
static DEF_PARM(int, debug, 0, 0644, "Print DBG statements");
static DEF_PARM(uint, poll_battery_interval, 500, 0644,
"Poll battery interval in milliseconds (0 - disable)");
static DEF_PARM_BOOL(use_polrev_firmware, 1, 0444,
"Use firmware reports of polarity reversal");
static DEF_PARM_BOOL(squelch_polrev, 0, 0644,
"Never report polarity reversal");
#ifdef WITH_METERING
static DEF_PARM(uint, poll_metering_interval, 500, 0644,
"Poll metering interval in milliseconds (0 - disable)");
@@ -43,7 +49,11 @@ static DEF_PARM(uint, poll_metering_interval, 500, 0644,
static DEF_PARM(int, ring_debounce, 50, 0644,
"Number of ticks to debounce a false RING indication");
static DEF_PARM(int, caller_id_style, 0, 0444,
"Caller-Id detection style: 0 - [BELL], 1 - [ETSI_FSK], 2 - [ETSI_DTMF]");
"Caller-Id detection style: "
"0 - [BELL], "
"1 - [ETSI_FSK], "
"2 - [ETSI_DTMF], "
"3 - [PASSTHROUGH]");
static DEF_PARM(int, power_denial_safezone, 650, 0644,
"msec after offhook to ignore power-denial ( (0 - disable power-denial)");
static DEF_PARM(int, power_denial_minlen, 80, 0644,
@@ -57,6 +67,8 @@ enum cid_style {
CID_STYLE_BELL = 0, /* E.g: US (Bellcore) */
CID_STYLE_ETSI_FSK = 1, /* E.g: UK (British Telecom) */
CID_STYLE_ETSI_DTMF = 2, /* E.g: DK, Russia */
CID_STYLE_PASSTHROUGH = 3, /* No change: Let asterisk */
/* (>= 1.8) DSP handle this */
};
/* Signaling is opposite (fxs signalling for fxo card) */
@@ -95,14 +107,13 @@ enum fxo_leds {
static bool fxo_packet_is_valid(xpacket_t *pack);
static void fxo_packet_dump(const char *msg, xpacket_t *pack);
#ifdef CONFIG_PROC_FS
static int proc_fxo_info_read(char *page, char **start, off_t off, int count,
int *eof, void *data);
static const struct file_operations proc_fxo_info_ops;
#ifdef WITH_METERING
static int proc_xpd_metering_read(char *page, char **start, off_t off,
int count, int *eof, void *data);
static const struct file_operations proc_xpd_metering_ops;
#endif
#endif
static void dahdi_report_battery(xpd_t *xpd, lineno_t chan);
static void report_polarity_reversal(xpd_t *xpd, xportno_t portno, char *msg);
#define PROC_REGISTER_FNAME "slics"
#define PROC_FXO_INFO_FNAME "fxo_info"
@@ -110,6 +121,10 @@ static void dahdi_report_battery(xpd_t *xpd, lineno_t chan);
#define PROC_METERING_FNAME "metering_read"
#endif
#define REG_INTERRUPT_SRC 0x04 /* 4 - Interrupt Source */
#define REG_INTERRUPT_SRC_POLI BIT(0) /* Polarity Reversal Detect Interrupt*/
#define REG_INTERRUPT_SRC_RING BIT(7) /* Ring Detect Interrupt */
#define REG_DAA_CONTROL1 0x05 /* 5 - DAA Control 1 */
#define REG_DAA_CONTROL1_OH BIT(0) /* Off-Hook. */
#define REG_DAA_CONTROL1_ONHM BIT(3) /* On-Hook Line Monitor */
@@ -148,6 +163,9 @@ struct FXO_priv_data {
ushort nobattery_debounce[CHANNELS_PERXPD];
enum polarity_state polarity[CHANNELS_PERXPD];
ushort polarity_debounce[CHANNELS_PERXPD];
int polarity_last_interval[CHANNELS_PERXPD];
#define POLARITY_LAST_INTERVAL_NONE (-1)
#define POLARITY_LAST_INTERVAL_MAX 40
enum power_state power[CHANNELS_PERXPD];
ushort power_denial_delay[CHANNELS_PERXPD];
ushort power_denial_length[CHANNELS_PERXPD];
@@ -345,6 +363,7 @@ static void mark_ring(xpd_t *xpd, lineno_t pos, bool on, bool update_dahdi)
MARK_BLINK(priv, pos, LED_GREEN, 0);
if (update_dahdi)
update_dahdi_ring(xpd, pos, on);
priv->polarity_last_interval[pos] = POLARITY_LAST_INTERVAL_NONE;
}
}
@@ -382,8 +401,14 @@ static int do_sethook(xpd_t *xpd, int pos, bool to_offhook)
DAA_DIRECT_REQUEST(xbus, xpd, pos, DAA_WRITE, REG_DAA_CONTROL1,
value);
mark_offhook(xpd, pos, to_offhook);
if (caller_id_style != CID_STYLE_ETSI_DTMF)
switch (caller_id_style) {
case CID_STYLE_ETSI_DTMF:
case CID_STYLE_PASSTHROUGH:
break;
default:
oht_pcm(xpd, pos, 0);
break;
}
#ifdef WITH_METERING
priv->metering_count[pos] = 0;
priv->metering_tone_state = 0L;
@@ -415,7 +440,6 @@ static void fxo_proc_remove(xbus_t *xbus, xpd_t *xpd)
#ifdef WITH_METERING
if (priv->meteringfile) {
XPD_DBG(PROC, xpd, "Removing xpd metering tone file\n");
priv->meteringfile->data = NULL;
remove_proc_entry(PROC_METERING_FNAME, xpd->proc_xpd_dir);
priv->meteringfile = NULL;
}
@@ -436,9 +460,9 @@ static int fxo_proc_create(xbus_t *xbus, xpd_t *xpd)
priv = xpd->priv;
#ifdef CONFIG_PROC_FS
XPD_DBG(PROC, xpd, "Creating FXO_INFO file\n");
priv->fxo_info =
create_proc_read_entry(PROC_FXO_INFO_FNAME, 0444, xpd->proc_xpd_dir,
proc_fxo_info_read, xpd);
priv->fxo_info = proc_create_data(PROC_FXO_INFO_FNAME, 0444,
xpd->proc_xpd_dir,
&proc_fxo_info_ops, xpd);
if (!priv->fxo_info) {
XPD_ERR(xpd, "Failed to create proc file '%s'\n",
PROC_FXO_INFO_FNAME);
@@ -448,9 +472,9 @@ static int fxo_proc_create(xbus_t *xbus, xpd_t *xpd)
SET_PROC_DIRENTRY_OWNER(priv->fxo_info);
#ifdef WITH_METERING
XPD_DBG(PROC, xpd, "Creating Metering tone file\n");
priv->meteringfile =
create_proc_read_entry(PROC_METERING_FNAME, 0444, xpd->proc_xpd_dir,
proc_xpd_metering_read, xpd);
priv->meteringfile = proc_create_data(PROC_METERING_FNAME, 0444,
xpd->proc_xpd_dir,
&proc_xpd_metering_ops, xpd);
if (!priv->meteringfile) {
XPD_ERR(xpd, "Failed to create proc file '%s'\n",
PROC_METERING_FNAME);
@@ -513,8 +537,13 @@ static int FXO_card_init(xbus_t *xbus, xpd_t *xpd)
priv->battery[i] = BATTERY_UNKNOWN;
/* will be updated on next battery sample */
priv->power[i] = POWER_UNKNOWN;
if (caller_id_style == CID_STYLE_ETSI_DTMF)
switch (caller_id_style) {
case CID_STYLE_ETSI_DTMF:
case CID_STYLE_PASSTHROUGH:
oht_pcm(xpd, i, 1);
break;
}
priv->polarity_last_interval[i] = POLARITY_LAST_INTERVAL_NONE;
}
XPD_DBG(GENERAL, xpd, "done\n");
for_each_line(xpd, i) {
@@ -684,6 +713,19 @@ static void handle_fxo_ring(xpd_t *xpd)
priv = xpd->priv;
for_each_line(xpd, i) {
if (likely(use_polrev_firmware)) {
int *t = &priv->polarity_last_interval[i];
if (*t != POLARITY_LAST_INTERVAL_NONE) {
(*t)++;
if (*t > POLARITY_LAST_INTERVAL_MAX) {
LINE_DBG(SIGNAL, xpd, i,
"polrev(GOOD): %d msec\n", *t);
*t = POLARITY_LAST_INTERVAL_NONE;
report_polarity_reversal(xpd,
i, "firmware");
}
}
}
if (atomic_read(&priv->ring_debounce[i]) > 0) {
/* Maybe start ring */
if (atomic_dec_and_test(&priv->ring_debounce[i]))
@@ -799,9 +841,9 @@ static void check_etsi_dtmf(xpd_t *xpd)
priv->cidtimer[portno] = timer_count;
BIT_SET(priv->cidfound, portno);
LINE_DBG(SIGNAL, xpd, portno,
"Found DTMF CLIP (%d)\n", i);
dahdi_qevent_lock(chan,
DAHDI_EVENT_POLARITY);
"Found DTMF CLIP (%d)\n", i);
report_polarity_reversal(xpd, portno,
"fake");
break;
}
}
@@ -951,6 +993,28 @@ HANDLER_DEF(FXO, SIG_CHANGED)
return 0;
}
static void report_polarity_reversal(xpd_t *xpd, xportno_t portno, char *msg)
{
/*
* Inform dahdi/Asterisk:
* 1. Maybe used for hangup detection during offhook
* 2. In some countries used to report caller-id
* during onhook but before first ring.
*/
if (caller_id_style == CID_STYLE_ETSI_FSK)
/* will be cleared on ring/offhook */
oht_pcm(xpd, portno, 1);
if (SPAN_REGISTERED(xpd)) {
LINE_DBG(SIGNAL, xpd, portno,
"%s DAHDI_EVENT_POLARITY (%s)\n",
(squelch_polrev) ? "Squelch" : "Send",
msg);
if (!squelch_polrev)
dahdi_qevent_lock(XPD_CHAN(xpd, portno),
DAHDI_EVENT_POLARITY);
}
}
static void update_battery_voltage(xpd_t *xpd, __u8 data_low,
xportno_t portno)
{
@@ -1048,22 +1112,8 @@ static void update_battery_voltage(xpd_t *xpd, __u8 data_low,
BUG();
LINE_DBG(SIGNAL, xpd, portno,
"Polarity changed to %s\n", polname);
/*
* Inform dahdi/Asterisk:
* 1. Maybe used for hangup detection during offhook
* 2. In some countries used to report caller-id
* during onhook but before first ring.
*/
if (caller_id_style == CID_STYLE_ETSI_FSK)
/* will be cleared on ring/offhook */
oht_pcm(xpd, portno, 1);
if (SPAN_REGISTERED(xpd)) {
LINE_DBG(SIGNAL, xpd, portno,
"Send DAHDI_EVENT_POLARITY: %s\n",
polname);
dahdi_qevent_lock(XPD_CHAN(xpd, portno),
DAHDI_EVENT_POLARITY);
}
if (!use_polrev_firmware)
report_polarity_reversal(xpd, portno, polname);
}
priv->polarity[portno] = pol;
}
@@ -1146,6 +1196,50 @@ static void update_metering_state(xpd_t *xpd, __u8 data_low, lineno_t portno)
}
#endif
static void got_chip_interrupt(xpd_t *xpd, __u8 data_low,
xportno_t portno)
{
struct FXO_priv_data *priv;
int t;
if (!use_polrev_firmware)
return;
priv = xpd->priv;
LINE_DBG(SIGNAL, xpd, portno, "mask=0x%X\n", data_low);
if (!(data_low & REG_INTERRUPT_SRC_POLI))
return;
t = priv->polarity_last_interval[portno];
if (PHONEDEV(xpd).ringing[portno]) {
priv->polarity_last_interval[portno] =
POLARITY_LAST_INTERVAL_NONE;
LINE_DBG(SIGNAL, xpd, portno,
"polrev(false): %d msec (while ringing)\n", t);
} else if (data_low & REG_INTERRUPT_SRC_RING) {
priv->polarity_last_interval[portno] =
POLARITY_LAST_INTERVAL_NONE;
LINE_DBG(SIGNAL, xpd, portno,
"polrev(false): %d msec (with chip-interrupt ring)\n",
t);
} else if (t == POLARITY_LAST_INTERVAL_NONE) {
priv->polarity_last_interval[portno] = 0;
LINE_DBG(SIGNAL, xpd, portno,
"polrev(start)\n");
} else if (t < POLARITY_LAST_INTERVAL_MAX) {
/*
* Start counting upward from -POLARITY_LAST_INTERVAL_MAX
* Until we reach POLARITY_LAST_INTERVAL_NONE.
* This way we filter bursts of false reports we get
* during ringing.
*/
priv->polarity_last_interval[portno] =
POLARITY_LAST_INTERVAL_NONE -
POLARITY_LAST_INTERVAL_MAX;
LINE_DBG(SIGNAL, xpd, portno,
"polrev(false): %d msec (interval shorter than %d)\n",
t, POLARITY_LAST_INTERVAL_MAX);
}
}
static int FXO_card_register_reply(xbus_t *xbus, xpd_t *xpd, reg_cmd_t *info)
{
struct FXO_priv_data *priv;
@@ -1155,6 +1249,9 @@ static int FXO_card_register_reply(xbus_t *xbus, xpd_t *xpd, reg_cmd_t *info)
BUG_ON(!priv);
portno = info->portnum;
switch (REG_FIELD(info, regnum)) {
case REG_INTERRUPT_SRC:
got_chip_interrupt(xpd, REG_FIELD(info, data_low), portno);
break;
case DAA_REG_VBAT:
update_battery_voltage(xpd, REG_FIELD(info, data_low), portno);
break;
@@ -1249,12 +1346,10 @@ static void fxo_packet_dump(const char *msg, xpacket_t *pack)
/*------------------------- DAA Handling --------------------------*/
#ifdef CONFIG_PROC_FS
static int proc_fxo_info_read(char *page, char **start, off_t off, int count,
int *eof, void *data)
static int proc_fxo_info_show(struct seq_file *sfile, void *not_used)
{
int len = 0;
unsigned long flags;
xpd_t *xpd = data;
xpd_t *xpd = sfile->private;
struct FXO_priv_data *priv;
int i;
@@ -1263,42 +1358,43 @@ static int proc_fxo_info_read(char *page, char **start, off_t off, int count,
spin_lock_irqsave(&xpd->lock, flags);
priv = xpd->priv;
BUG_ON(!priv);
len += sprintf(page + len, "\t%-17s: ", "Channel");
seq_printf(sfile, "\t%-17s: ", "Channel");
for_each_line(xpd, i) {
if (!IS_SET(PHONEDEV(xpd).digital_outputs, i)
&& !IS_SET(PHONEDEV(xpd).digital_inputs, i))
len += sprintf(page + len, "%4d ", i % 10);
&& !IS_SET(PHONEDEV(xpd).digital_inputs, i)) {
seq_printf(sfile, "%4d ", i % 10);
}
}
len += sprintf(page + len, "\nLeds:");
len += sprintf(page + len, "\n\t%-17s: ", "state");
seq_printf(sfile, "\nLeds:");
seq_printf(sfile, "\n\t%-17s: ", "state");
for_each_line(xpd, i) {
if (!IS_SET(PHONEDEV(xpd).digital_outputs, i)
&& !IS_SET(PHONEDEV(xpd).digital_inputs, i))
len +=
sprintf(page + len, " %d%d ",
IS_SET(priv->ledstate[LED_GREEN], i),
IS_SET(priv->ledstate[LED_RED], i));
&& !IS_SET(PHONEDEV(xpd).digital_inputs, i)) {
seq_printf(sfile, " %d%d ",
IS_SET(priv->ledstate[LED_GREEN], i),
IS_SET(priv->ledstate[LED_RED], i));
}
}
len += sprintf(page + len, "\n\t%-17s: ", "blinking");
seq_printf(sfile, "\n\t%-17s: ", "blinking");
for_each_line(xpd, i) {
if (!IS_SET(PHONEDEV(xpd).digital_outputs, i)
&& !IS_SET(PHONEDEV(xpd).digital_inputs, i))
len +=
sprintf(page + len, " %d%d ",
IS_BLINKING(priv, i, LED_GREEN),
IS_BLINKING(priv, i, LED_RED));
&& !IS_SET(PHONEDEV(xpd).digital_inputs, i)) {
seq_printf(sfile, " %d%d ",
IS_BLINKING(priv, i, LED_GREEN),
IS_BLINKING(priv, i, LED_RED));
}
}
len += sprintf(page + len, "\nBattery-Data:");
len += sprintf(page + len, "\n\t%-17s: ", "voltage");
seq_printf(sfile, "\nBattery-Data:");
seq_printf(sfile, "\n\t%-17s: ", "voltage");
for_each_line(xpd, i) {
len += sprintf(page + len, "%4d ", priv->battery_voltage[i]);
seq_printf(sfile, "%4d ", priv->battery_voltage[i]);
}
len += sprintf(page + len, "\n\t%-17s: ", "current");
seq_printf(sfile, "\n\t%-17s: ", "current");
for_each_line(xpd, i) {
len += sprintf(page + len, "%4d ", priv->battery_current[i]);
seq_printf(sfile, "%4d ", priv->battery_current[i]);
}
len += sprintf(page + len, "\nBattery:");
len += sprintf(page + len, "\n\t%-17s: ", "on");
seq_printf(sfile, "\nBattery:");
seq_printf(sfile, "\n\t%-17s: ", "on");
for_each_line(xpd, i) {
char *bat;
@@ -1308,14 +1404,14 @@ static int proc_fxo_info_read(char *page, char **start, off_t off, int count,
bat = "-";
else
bat = ".";
len += sprintf(page + len, "%4s ", bat);
seq_printf(sfile, "%4s ", bat);
}
len += sprintf(page + len, "\n\t%-17s: ", "debounce");
seq_printf(sfile, "\n\t%-17s: ", "debounce");
for_each_line(xpd, i) {
len += sprintf(page + len, "%4d ", priv->nobattery_debounce[i]);
seq_printf(sfile, "%4d ", priv->nobattery_debounce[i]);
}
len += sprintf(page + len, "\nPolarity-Reverse:");
len += sprintf(page + len, "\n\t%-17s: ", "polarity");
seq_printf(sfile, "\nPolarity-Reverse:");
seq_printf(sfile, "\n\t%-17s: ", "polarity");
for_each_line(xpd, i) {
char *polname;
@@ -1325,14 +1421,14 @@ static int proc_fxo_info_read(char *page, char **start, off_t off, int count,
polname = "-";
else
polname = ".";
len += sprintf(page + len, "%4s ", polname);
seq_printf(sfile, "%4s ", polname);
}
len += sprintf(page + len, "\n\t%-17s: ", "debounce");
seq_printf(sfile, "\n\t%-17s: ", "debounce");
for_each_line(xpd, i) {
len += sprintf(page + len, "%4d ", priv->polarity_debounce[i]);
seq_printf(sfile, "%4d ", priv->polarity_debounce[i]);
}
len += sprintf(page + len, "\nPower-Denial:");
len += sprintf(page + len, "\n\t%-17s: ", "power");
seq_printf(sfile, "\nPower-Denial:");
seq_printf(sfile, "\n\t%-17s: ", "power");
for_each_line(xpd, i) {
char *curr;
@@ -1342,45 +1438,46 @@ static int proc_fxo_info_read(char *page, char **start, off_t off, int count,
curr = "-";
else
curr = ".";
len += sprintf(page + len, "%4s ", curr);
seq_printf(sfile, "%4s ", curr);
}
len += sprintf(page + len, "\n\t%-17s: ", "safezone");
seq_printf(sfile, "\n\t%-17s: ", "safezone");
for_each_line(xpd, i) {
len +=
sprintf(page + len, "%4d ", priv->power_denial_safezone[i]);
seq_printf(sfile, "%4d ", priv->power_denial_safezone[i]);
}
len += sprintf(page + len, "\n\t%-17s: ", "delay");
seq_printf(sfile, "\n\t%-17s: ", "delay");
for_each_line(xpd, i) {
len += sprintf(page + len, "%4d ", priv->power_denial_delay[i]);
seq_printf(sfile, "%4d ", priv->power_denial_delay[i]);
}
#ifdef WITH_METERING
len += sprintf(page + len, "\nMetering:");
len += sprintf(page + len, "\n\t%-17s: ", "count");
seq_printf(sfile, "\nMetering:");
seq_printf(sfile, "\n\t%-17s: ", "count");
for_each_line(xpd, i) {
len += sprintf(page + len, "%4d ", priv->metering_count[i]);
seq_printf(sfile, "%4d ", priv->metering_count[i]);
}
#endif
len += sprintf(page + len, "\n");
seq_printf(sfile, "\n");
spin_unlock_irqrestore(&xpd->lock, flags);
if (len <= off + count)
*eof = 1;
*start = page + off;
len -= off;
if (len > count)
len = count;
if (len < 0)
len = 0;
return len;
return 0;
}
#endif
static int proc_fxo_info_open(struct inode *inode, struct file *file)
{
return single_open(file, proc_fxo_info_show, PDE_DATA(inode));
}
static const struct file_operations proc_fxo_info_ops = {
.owner = THIS_MODULE,
.open = proc_fxo_info_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
#ifdef WITH_METERING
static int proc_xpd_metering_read(char *page, char **start, off_t off,
int count, int *eof, void *data)
static int proc_xpd_metering_show(struct seq_file *sfile, void *not_used)
{
int len = 0;
unsigned long flags;
xpd_t *xpd = data;
xpd_t *xpd = sfile->private;
struct FXO_priv_data *priv;
int i;
@@ -1389,25 +1486,31 @@ static int proc_xpd_metering_read(char *page, char **start, off_t off,
priv = xpd->priv;
BUG_ON(!priv);
spin_lock_irqsave(&xpd->lock, flags);
len += sprintf(page + len, "# Chan\tMeter (since last read)\n");
seq_printf(sfile, "# Chan\tMeter (since last read)\n");
for_each_line(xpd, i) {
len +=
sprintf(page + len, "%d\t%d\n", i, priv->metering_count[i]);
seq_printf(sfile, "%d\t%d\n", i, priv->metering_count[i]);
}
spin_unlock_irqrestore(&xpd->lock, flags);
if (len <= off + count)
*eof = 1;
*start = page + off;
len -= off;
if (len > count)
len = count;
if (len < 0)
len = 0;
/* Zero meters */
for_each_line(xpd, i)
priv->metering_count[i] = 0;
return len;
return 0;
}
static int proc_xpd_metering_open(struct inode *inode, struct file *file)
{
return single_open(file, proc_xpd_metering_show, PDE_DATA(inode));
}
static const struct file_operations proc_xpd_metering_ops = {
.owner = THIS_MODULE,
.open = proc_xpd_metering_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
#endif
#endif
static DEVICE_ATTR_READER(fxo_battery_show, dev, buf)

View File

@@ -24,6 +24,7 @@
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/delay.h>
#include <linux/seq_file.h>
#include "xpd.h"
#include "xproto.h"
#include "xpp_dahdi.h"
@@ -120,11 +121,9 @@ enum fxs_state {
static bool fxs_packet_is_valid(xpacket_t *pack);
static void fxs_packet_dump(const char *msg, xpacket_t *pack);
#ifdef CONFIG_PROC_FS
static int proc_fxs_info_read(char *page, char **start, off_t off, int count,
int *eof, void *data);
static const struct file_operations proc_fxs_info_ops;
#ifdef WITH_METERING
static int proc_xpd_metering_write(struct file *file,
const char __user *buffer, unsigned long count, void *data);
static const struct file_operations proc_xpd_metering_ops;
#endif
#endif
static void start_stop_vm_led(xbus_t *xbus, xpd_t *xpd, lineno_t pos);
@@ -399,7 +398,6 @@ static void fxs_proc_remove(xbus_t *xbus, xpd_t *xpd)
#ifdef WITH_METERING
if (priv->meteringfile) {
XPD_DBG(PROC, xpd, "Removing xpd metering tone file\n");
priv->meteringfile->data = NULL;
remove_proc_entry(PROC_METERING_FNAME, xpd->proc_xpd_dir);
priv->meteringfile = NULL;
}
@@ -421,9 +419,9 @@ static int fxs_proc_create(xbus_t *xbus, xpd_t *xpd)
#ifdef CONFIG_PROC_FS
XPD_DBG(PROC, xpd, "Creating FXS_INFO file\n");
priv->fxs_info =
create_proc_read_entry(PROC_FXS_INFO_FNAME, 0444, xpd->proc_xpd_dir,
proc_fxs_info_read, xpd);
priv->fxs_info = proc_create_data(PROC_FXS_INFO_FNAME, 0444,
xpd->proc_xpd_dir,
&proc_fxs_info_ops, xpd);
if (!priv->fxs_info) {
XPD_ERR(xpd, "Failed to create proc file '%s'\n",
PROC_FXS_INFO_FNAME);
@@ -433,18 +431,15 @@ static int fxs_proc_create(xbus_t *xbus, xpd_t *xpd)
SET_PROC_DIRENTRY_OWNER(priv->fxs_info);
#ifdef WITH_METERING
XPD_DBG(PROC, xpd, "Creating Metering tone file\n");
priv->meteringfile =
create_proc_entry(PROC_METERING_FNAME, 0200, xpd->proc_xpd_dir);
priv->meteringfile = proc_create_data(PROC_METERING_FNAME, 0200,
xpd->proc_xpd_dir,
&proc_xpd_metering_ops, xpd);
if (!priv->meteringfile) {
XPD_ERR(xpd, "Failed to create proc file '%s'\n",
PROC_METERING_FNAME);
fxs_proc_remove(xbus, xpd);
return -EINVAL;
}
SET_PROC_DIRENTRY_OWNER(priv->meteringfile);
priv->meteringfile->write_proc = proc_xpd_metering_write;
priv->meteringfile->read_proc = NULL;
priv->meteringfile->data = xpd;
#endif
#endif
return 0;
@@ -1691,12 +1686,10 @@ static void fxs_packet_dump(const char *msg, xpacket_t *pack)
/*------------------------- SLIC Handling --------------------------*/
#ifdef CONFIG_PROC_FS
static int proc_fxs_info_read(char *page, char **start, off_t off, int count,
int *eof, void *data)
static int proc_fxs_info_show(struct seq_file *sfile, void *not_used)
{
int len = 0;
unsigned long flags;
xpd_t *xpd = data;
xpd_t *xpd = sfile->private;
struct FXS_priv_data *priv;
int i;
int led;
@@ -1706,11 +1699,11 @@ static int proc_fxs_info_read(char *page, char **start, off_t off, int count,
spin_lock_irqsave(&xpd->lock, flags);
priv = xpd->priv;
BUG_ON(!priv);
len += sprintf(page + len, "%-12s", "Channel:");
seq_printf(sfile, "%-12s", "Channel:");
for_each_line(xpd, i) {
len += sprintf(page + len, "%4d", i);
seq_printf(sfile, "%4d", i);
}
len += sprintf(page + len, "\n%-12s", "");
seq_printf(sfile, "\n%-12s", "");
for_each_line(xpd, i) {
char *chan_type;
@@ -1720,84 +1713,85 @@ static int proc_fxs_info_read(char *page, char **start, off_t off, int count,
chan_type = "in";
else
chan_type = "";
len += sprintf(page + len, "%4s", chan_type);
seq_printf(sfile, "%4s", chan_type);
}
len += sprintf(page + len, "\n%-12s", "idletxhook:");
seq_printf(sfile, "\n%-12s", "idletxhook:");
for_each_line(xpd, i) {
len += sprintf(page + len, "%4d", priv->idletxhookstate[i]);
seq_printf(sfile, "%4d", priv->idletxhookstate[i]);
}
len += sprintf(page + len, "\n%-12s", "lasttxhook:");
seq_printf(sfile, "\n%-12s", "lasttxhook:");
for_each_line(xpd, i) {
len += sprintf(page + len, "%4d", priv->lasttxhook[i]);
seq_printf(sfile, "%4d", priv->lasttxhook[i]);
}
len += sprintf(page + len, "\n%-12s", "ohttimer:");
seq_printf(sfile, "\n%-12s", "ohttimer:");
for_each_line(xpd, i) {
len += sprintf(page + len, "%4d", priv->ohttimer[i]);
seq_printf(sfile, "%4d", priv->ohttimer[i]);
}
len += sprintf(page + len, "\n%-12s", "neon_blink:");
seq_printf(sfile, "\n%-12s", "neon_blink:");
for_each_line(xpd, i) {
len += sprintf(page + len, "%4d",
seq_printf(sfile, "%4d",
IS_SET(priv->neon_blinking, i));
}
len += sprintf(page + len, "\n%-12s", "search_fsk:");
seq_printf(sfile, "\n%-12s", "search_fsk:");
for_each_line(xpd, i) {
len += sprintf(page + len, "%4d",
seq_printf(sfile, "%4d",
IS_SET(priv->search_fsk_pattern, i));
}
len += sprintf(page + len, "\n%-12s", "vbat_h:");
seq_printf(sfile, "\n%-12s", "vbat_h:");
for_each_line(xpd, i) {
len += sprintf(page + len, "%4d",
seq_printf(sfile, "%4d",
test_bit(i, (unsigned long *)&priv->vbat_h));
}
len += sprintf(page + len, "\n");
seq_printf(sfile, "\n");
for (led = 0; led < NUM_LEDS; led++) {
len += sprintf(page + len, "\nLED #%d\t%-12s: ",
seq_printf(sfile, "\nLED #%d\t%-12s: ",
led, "ledstate");
for_each_line(xpd, i) {
if (!IS_SET(PHONEDEV(xpd).digital_outputs, i)
&& !IS_SET(PHONEDEV(xpd).digital_inputs, i))
len +=
sprintf(page + len, "%d ",
seq_printf(sfile, "%d ",
IS_SET(priv->ledstate[led], i));
}
len += sprintf(page + len, "\nLED #%d\t%-12s: ",
seq_printf(sfile, "\nLED #%d\t%-12s: ",
led, "ledcontrol");
for_each_line(xpd, i) {
if (!IS_SET(PHONEDEV(xpd).digital_outputs, i)
&& !IS_SET(PHONEDEV(xpd).digital_inputs, i))
len +=
sprintf(page + len, "%d ",
seq_printf(sfile, "%d ",
IS_SET(priv->ledcontrol[led], i));
}
len += sprintf(page + len, "\nLED #%d\t%-12s: ",
seq_printf(sfile, "\nLED #%d\t%-12s: ",
led, "led_counter");
for_each_line(xpd, i) {
if (!IS_SET(PHONEDEV(xpd).digital_outputs, i)
&& !IS_SET(PHONEDEV(xpd).digital_inputs, i))
len +=
sprintf(page + len, "%d ",
seq_printf(sfile, "%d ",
LED_COUNTER(priv, i, led));
}
}
len += sprintf(page + len, "\n");
seq_printf(sfile, "\n");
spin_unlock_irqrestore(&xpd->lock, flags);
if (len <= off + count)
*eof = 1;
*start = page + off;
len -= off;
if (len > count)
len = count;
if (len < 0)
len = 0;
return len;
return 0;
}
#endif
static int proc_fxs_info_open(struct inode *inode, struct file *file)
{
return single_open(file, proc_fxs_info_show, PDE_DATA(inode));
}
static const struct file_operations proc_fxs_info_ops = {
.owner = THIS_MODULE,
.open = proc_fxs_info_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
#ifdef WITH_METERING
static int proc_xpd_metering_write(struct file *file, const char
__user *buffer, unsigned long count, void *data)
static ssize_t proc_xpd_metering_write(struct file *file,
const char __user *buffer, size_t count, loff_t *offset)
{
xpd_t *xpd = data;
xpd_t *xpd = file->private_data;
char buf[MAX_PROC_WRITE];
lineno_t chan;
int num;
@@ -1806,7 +1800,7 @@ static int proc_xpd_metering_write(struct file *file, const char
if (!xpd)
return -ENODEV;
if (count >= MAX_PROC_WRITE - 1) {
XPD_ERR(xpd, "Metering string too long (%lu)\n", count);
XPD_ERR(xpd, "Metering string too long (%zu)\n", count);
return -EINVAL;
}
if (copy_from_user(&buf, buffer, count))
@@ -1829,6 +1823,19 @@ static int proc_xpd_metering_write(struct file *file, const char
}
return count;
}
static int proc_xpd_metering_open(struct inode *inode, struct file *file)
{
file->private_data = PDE_DATA(inode);
}
static const struct file_operations proc_xpd_metering_ops = {
.owner = THIS_MODULE,
.open = proc_xpd_metering_open,
.write = proc_xpd_metering_write,
.release = single_release,
};
#endif
#endif
static int fxs_xpd_probe(struct device *dev)

View File

@@ -1,7 +1,7 @@
#
# $Id: PIC_TYPE_2.hex 9732 2011-08-24 19:13:55Z dima $
# $Id: PIC_TYPE_2.hex 11078 2013-04-11 16:52:37Z dima $
#
:03000000A57A4896
:03000000A5DA4836
:03000100C41C41DB
:030002000390392F
:0300030067967984
@@ -42,319 +42,375 @@
:03002600CFC9013E
:030027001652026C
:0300280064403001
:03002900A3290107
:03002900A38901A7
:03002A00704C40D7
:03002B00A41FFF10
:03002C00C011659B
:03002D001E1C0294
:03002E00C03FFFD1
:03002F0016115057
:030030002016B9DE
:03003100125D025B
:0300320020A022E9
:03003300643C0228
:03003400A3AD0178
:03003500365162DF
:030036003652053A
:030037002C8030EA
:03003800D00901EB
:03003900A33204EB
:03003A0020503023
:03003B0072490106
:03003C00A3E2023A
:03003D00A40030EC
:03003E0002D901E3
:03003F00A4180002
:0300400002E214C5
:03004100800E70BE
:030042000223088E
:030043002063082F
:030044006433081A
:03004500A4A30869
:0300460032203F26
:030047002C880002
:03004800D00C00D9
:03004900A4403997
:03004A00CFE038CC
:03004B00162C0769
:03004C00C01D4094
:03004D00604034DC
:03004E00122C0869
:03004F00206038F6
:03005000643219FE
:03005100A56E0792
:0300520036202035
:030053002C83609B
:03005400D0036076
:03005500A50360A0
:03005600800360C4
:03005700C07C105A
:03005800166038F7
:03005900743219E5
:03005A00A5FE07F9
:03005B00C01120B1
:03005C001CCC2099
:03005D00E07180CF
:03005E0002CE705F
:03005F00206743D4
:0300600090AA70F3
:03006100205C021E
:03006200D2018048
:03006300D40E07B1
:0300640003D6437D
:03006500C1CA739A
:03002B00A47FFFB0
:03002C00C40165A7
:03002D00150C02AD
:03002E00743FFF1D
:03002F00A32150BA
:03003000C026B92E
:03003100A33D02EA
:03003200C01022D9
:03003300121C029A
:03003400C03D01CB
:030035001611623F
:0300360020120590
:0300370012503034
:0300380020A901FB
:030039006432042A
:03003A00A40030EF
:03003B0036590132
:03003C0036520237
:03003D002C8030E4
:03003E00D00901E5
:03003F00A3980083
:0300400020521437
:03004100724E708C
:03004200A44308CC
:03004300A46308AB
:0300440002D308DC
:03004500A4730899
:0300460002E03F96
:030047008008002E
:03004800022C0087
:03004900206039FB
:03004A00643038E7
:03004B00A50C07FA
:03004C00322D4012
:03004D002C8034D0
:03004E00D00C08CB
:03004F00A4A03832
:03005000CFE219E3
:03005100162E0761
:03005200C01020BB
:03005300604360A7
:0300540012236014
:03005500206360C5
:03005600643360B0
:03005700A5CC1025
:0300580036203817
:030059002C8219DD
:03005A00D00E07BE
:03005B00A561207C
:03005C00800C20F5
:03005D00C07180EF
:03005E00166E70AB
:03005F00743743B0
:03006000A65A702D
:03006100C01C02BE
:030062001CC1803E
:03006300E07E0735
:0300640002C6438E
:03006500200A73FB
:03006600022C0366
:03006700C0018055
:03006800024E073E
:0300690021D6435A
:03006A00030A7313
:03006B00901C04E2
:03006C00202180D0
:03006D00030E0778
:03006E00901643A6
:03006F00204A73B1
:03007000030C017D
:03007100901038B4
:03007200210A72EE
:03007300024C1824
:03007400C0303861
:0300750008421925
:03007600603E0FDA
:03007700A7A0221D
:03007800209C00C9
:03007900A7C038E5
:0300670020618095
:03006800643E07EC
:03006900A6E643C5
:03006A00322A73C4
:03006B002C8C04D6
:03006C00D0018040
:03006D00A68E0755
:03006E00C0164376
:03006F00142A73DD
:03007000743C01DC
:03007100ACB038F8
:03007200206A728F
:0300730090AC1836
:03007400205038E1
:03007500D202199B
:03007600D40E0F96
:0300770003D02291
:03007800C04C0079
:030079000220382A
:03007A00C00200C1
:03007B00A7CE0706
:03007C00187F02E8
:03007D0014974392
:03007E00643A835E
:03007F00AABC0018
:030080001A7031C2
:03008100C50C1299
:03008200039A904E
:030083007992006F
:03008400A83E078C
:0300850020BF0396
:03008600D007435D
:03008700038A8C5D
:03008800219C00B8
:03008900E07031F3
:03008A00348C189B
:03008B00348A9024
:03008C00348C00B1
:03008D003480318B
:03008E00030C164A
:03008F00206A9054
:0300900034803B7E
:03009100348E0F9B
:0300920034808235
:03009300348703AC
:03009400D05A9AA5
:03009500031C0F3A
:03009600C00FFF99
:0300970003215BE7
:030098000331022F
:03009900C70A9BF8
:03009A0003921BB3
:03009B00C500306D
:03009C00039E0FB1
:03009D00C1C03BA4
:03009E00030C024E
:03009F00C0003965
:0300A000031C003E
:0300A100204039C3
:0300A200032C80AC
:03007B00024E072B
:03007C0021DF027F
:03007D0003074333
:03007E00901A8352
:03007F00202C0032
:0300800003003149
:03008100901C12BE
:03008200204A9081
:0300830003020075
:03008400901E07C4
:03008500210F0345
:03008600E017433D
:03008700643A8C4C
:03008800ACBC000D
:0300890021003122
:03008A00024C180D
:03008B00E80A90F0
:03008C00743C00C1
:03008D00AB803114
:03008E00C50C1688
:03008F00039A9041
:0300900079903B29
:03009100A90E0FA6
:0300920020B08219
:03009300D0070390
:03009400038A9A42
:03009500219C0F9C
:03009600E07FFF09
:0300970034815B56
:03009800348102AE
:03009900348A9B0B
:03009A0034821B92
:03009B000300302F
:03009C00206E0FC4
:03009D0034803B71
:03009E00348C029D
:03009F0034803971
:0300A000348C009D
:0300A100D0503903
:0300A200031C80BC
:0300A300C00D0885
:0300A400033039ED
:0300A500C70C0085
:0300A6000390398B
:0300A700C50C4045
:0300A80003903989
:0300A900C407D9B0
:0300AA00039AA90D
:0300AB0020CC0066
:0300AC0074302687
:0300AD00B1702708
:0300AE00C0002B64
:0300AF00024020EC
:0300B000C05C032E
:0300B10002202CFE
:0300B200205C20AF
:0300B300D20D80EB
:0300B400D4002550
:0300B50003DC2049
:0300B60021D02432
:0300B700030C0037
:0300B80090102283
:0300B900202205FD
:0300BA0003003010
:0300BB0090190198
:0300BC00204204DB
:0300BD000300300D
:0300BE0090190195
:0300BF00C012026A
:0300A400032039FD
:0300A500033C0019
:0300A600C7003957
:0300A700039C4077
:0300A800C5003957
:0300A9000397D9E1
:0300AA00C04AA9A0
:0300AB00030C0043
:0300AC00C000266B
:0300AD0003102716
:0300AE0020402BC4
:0300AF000320200B
:0300B000C00C037E
:0300B10003302CED
:0300B200C70C2058
:0300B300039D802A
:0300B400C500255F
:0300B500039C2089
:0300B600C400245F
:0300B700039C00A7
:0300B800C400225F
:0300B900FFF2054E
:0300BA00165030AD
:0300BB00D2090166
:0300BC0003D20468
:0300BD00C0403010
:0300BE0002290113
:0300BF00C002027A
:0300C000150030F8
:0300C100024901F0
:0300C20021AC402E
:0300C3009420394D
:0300C400202C01EC
:0300C50003A0375E
:0300C600206C604B
:0300C7007432C8C8
:0300C800AD5AC767
:0300C900C9FC006F
:0300CA0016B03736
:0300CB00C006D993
:0300CC006B0AD0EC
:0300CD00D206F95F
:0300CE006D0B4D6A
:0300C20021DC40FE
:0300C300030039FE
:0300C400901C018C
:0300C500202037C1
:0300C600030C60C8
:0300C7009012C8CC
:0300C800204AC704
:0300C900030C0025
:0300CA009010375C
:0300CB002066D9D3
:0300CC0090AAD027
:0300CD002056F9C1
:0300CE00D20B4D05
:0300CF00D40ACB85
:0300D00012B94022
:0300D100C80C2038
:0300D2001AB195CB
:0300D30020B64311
:0300D400038ADFBD
:0300D500206C019B
:0300D60002A1DFA5
:0300D700C0409B8B
:0300D800086703B3
:0300D900703ADF9B
:0300DA00ADE7D3BC
:0300DB00C00B480F
:0300DC00024CFFD4
:0300DD00AE202230
:0300DE00C04B2AEA
:0300DF000AA21F53
:0300E000C0290A2A
:0300E100024C20AE
:0300E200917125F4
:0300E300C016D371
:0300E40003EAEA42
:0300E500206C206C
:0300E600643095EE
:0300E700AEB6436F
:0300E80037EAF202
:0300E9002C8AEF6F
:0300EA00AE8C4099
:0300EB00C6012526
:0300EC00150C00F0
:0300ED0074302448
:0300EE00AFFB1A4B
:0300EF0021E217F4
:0300F0001AF024DF
:0300F10014FB1AE3
:0300F200743C401B
:0300F300B17105E3
:0300F400C0403DCC
:0300F500124C00AA
:0300F600917024E2
:0300F700C0021D27
:0300F80002403093
:0300F900200901DA
:0300FA0094221538
:0300FB0020203092
:0300FC00020901F5
:0300FD00035204A7
:0300FE00B17030AE
:0300FF00CFF90135
:0301000019E210F1
:0301010016F024D1
:03010200C037F70C
:03010300081B0BCB
:03010400743C0246
:03010500B0EFFF59
:03010600C01164C1
:03010700024C02A5
:030108002001577C
:030109009421241A
:03010A00202B1790
:03010B000207D711
:03010C00035B177B
:03010D00B17C01C1
:03010E00C00FFF20
:03010F0018116460
:03011000643C014B
:030111006B015728
:03011200B14124D4
:03011300B17B17A6
:03011400C01217FF
:0301150012402471
:03011600917B17C3
:03011700369C0211
:03011800C01D0106
:030119001E616400
:03011A0021BC8085
:03011B000866F380
:03011C0074312516
:03011D00A57205C3
:03011E000260304C
:03011F00C02901F3
:03012000FFF215D6
:0301210016B030E5
:03012200C02901F0
:0301230023A20410
:0301240074303004
:0301250012B9010B
:0301260020B7D32C
:03012700038B48FF
:03012800C44210BE
:030129000390221E
:03012A00C40C50B2
:03012B0003903905
:03012C00C0079970
:03012D00023B2C66
:03012E00AC2212EE
:03012F00B2F030FB
:03013000000214B6
:030131000000319A
:03013200000213B5
:0301330000003297
:03013400000C00BC
:0301350000003394
:03013600000C704A
:030137000000398C
:03013800000C5068
:030139000000398A
:03013A00000215AB
:03013B0000003091
:03013C00000C00B4
:03013D000000318E
:03013E00000202BA
:03013F000000328B
:03014000000C00B0
:0301410000003388
:03014200000C703E
:0301430000003980
:03014400000C505C
:030145000000397E
:03014600000C406A
:030147000000397C
:03014800000C00A8
:030149000000397A
:03014A00000C00A6
:03014B00000C00A5
:03014C00000AC2E4
:03014D00000C00A3
:03014E0000002589
:03014F00000C1091
:0301500000003D6F
:030151000009178B
:03015200000C049A
:0301530000002584
:03015400000C009C
:0301550000003D6A
:0301560000091786
:03015700000C0297
:030158000000257F
:03015900000C088F
:03015A0000003D65
:03015B0000091781
:03015C00000C0094
:03015D0000002679
:03015E00000C0191
:03015F0000002974
:03016000000C2070
:0301610000002378
:03016200000A0090
:03016300000B632B
:0300D00003D94011
:0300D100C1CC207F
:0300D20002219573
:0300D300C0064321
:0300D400024ADFFE
:0300D50021DC012A
:0300D6000301DF44
:0300D70090109BEB
:0300D800202703DB
:0300D900030ADF38
:0300DA009017D3A9
:0300DB00204B486F
:0300DC00030CFF13
:0300DD009010225E
:0300DE00210B2AC9
:0300DF0002421FBB
:0300E000C0390A1A
:0300E100084C20A8
:0300E20060312565
:0300E300AE66D333
:0300E400209AEA75
:0300E500AE8C20BE
:0300E600C00095C2
:0300E700AE86439F
:0300E800187AF291
:0300E900149AEF77
:0300EA00643C4033
:0300EB00B17125CB
:0300EC001A7C007B
:0300ED00C5002427
:0300EE00039B1A57
:0300EF00799217EC
:0300F000AEF0244B
:0300F10020BB1A17
:0300F200D00C40EF
:0300F30003810581
:0300F40021903D1B
:0300F500E07C00AC
:0300F6003480242F
:0300F70034821D33
:0300F80034803021
:0300F90034890146
:0300FA00030215E9
:0300FB0020603052
:0300FC0034890143
:0300FD0034820446
:0300FE003480301B
:0300FF0034890140
:03010000D05210CA
:03010100031024C4
:03010200C007F73C
:03010300032B0BC0
:03010400033C02B7
:03010500C70FFF22
:03010600039164FE
:03010700C50C0222
:0301080003915709
:03010900C1C1244D
:03010A00030B17CD
:03010B00C007D753
:03010C00031B17BB
:03010D00204C0182
:03010E00032FFFBD
:03010F00C00164C8
:03011000033C01AC
:03011100C70157CC
:0301120003912432
:03011300C50B1702
:030114000392173C
:03011500C40024FF
:03011600039B1731
:0301170020CC02F7
:03011800743D0132
:03011900B8316496
:03011A00C00C8096
:03011B000246F3A6
:03011C00C05125AA
:03011D00022205B6
:03011E002050303E
:03011F00D2090101
:03012000D40215F1
:0301210003D030D8
:0301220021D901DF
:03012300030204D0
:0301240090103008
:030125002029018D
:030126000307D3F9
:03012700901B48E2
:0301280020421062
:03012900030022AE
:03012A00901C50D6
:03012B00C01039C8
:03012C001507991B
:03012D00024B2C56
:03012E0021A212F9
:03012F0094803089
:0301300020221476
:0301310003A031F7
:0301320020621335
:03013300743032F3
:03013400B41C00F8
:03013500C9F033DB
:0301360016BC7084
:03013700C00039CC
:030138006B0C50FD
:03013900D20039B8
:03013A006D02153E
:03013B00D40030BD
:03013C0012BC00F2
:03013D00C80031C6
:03013E001AB202F0
:03013F0020B032BB
:03014000038C002D
:0301410020603308
:0301420002AC709C
:03014300C0403980
:03014400086C50F4
:03014500703039DE
:03014600B4AC4016
:03014700C00039BC
:03014800024C0066
:03014900B4E039E6
:03014A00C04C00A6
:03014B000AAC00FB
:03014C00C02AC204
:03014D00024C0061
:03014E0091702588
:03014F00C01C10C1
:0301500003E03D8C
:030151002069170B
:03015200643C0406
:03015300B570255F
:0301540037EC0085
:030155002C803DBE
:03015600B5491791
:03015700C60C02D1
:030158001500256A
:03015900743C08EB
:03015A00B6B03DFF
:03015B0021E91780
:03015C001AFC008A
:03015D0014F02675
:03015E00743C01ED
:03015F00B830298C
:03016000C04C2070
:0301610012402326
:03016200917A008F
:03016300C00B636B
:0301640002400056
:0301650020000077
:0301660094800082
:0301670020200055
:0301680002000092
:0301690003500040
:03016A00B83000AA
:03016B00CFF000D2
:03016C0019E00097
:03016D0016F00089
:03016E00C030009E
:03016F0008100075
:03017000743000E8
:03017100B7A00034
:03017200C01000BA
:0301730002400047
:0301740020000068
:0301750094800073
:0301760020200046
:0301770002000083
:0301780003500031
:03017900B830009B
:03017A00C00000C2
:03017B0018100059
:03017C00643000EC
:03017D006B000014
:03017E00B80000C6
:03017F00B8300095
:03018000C01000AC
:0301810012400029
:0301820091700079
:03018300369000B3
:03018400C01000A8
:030185001E6000F9
:0301860021B000A5
:030187000860000D
:03018800743000D0
:03018900A5D000FE
:03018A0002600010
:03018B00C0200091
:03018C00FFF00081
:03018D0016B000A9
:03018E00C020008E
:03018F0023A000AA
:03019000743000C8
:0301910012B000A9
:0301920020B0009A
:03019300038000E6
:03019400C4400064
:03019500039000D4
:03019600C40000A2
:03019700039000D2
:03019800C00000A4
:0301990002300031
:03019A00AC200096
:03019B00B9B000F8
:00000001FF

View File

@@ -415,6 +415,9 @@ close STDERR;
exit 0;
__DATA__
* WD 12 02 # Full wave rectified ring detection
* WD 03 01 # Polarity reversal detect mask
* WD 04 00 # Clear interrupt status
* WD 21 08 # Disable PCM transfers
* WD 18 99
* WD 06 00

View File

@@ -25,6 +25,7 @@
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#ifdef PROTOCOL_DEBUG
#include <linux/ctype.h>
#endif
@@ -47,8 +48,7 @@ static const char rcsid[] = "$Id$";
#ifdef PROTOCOL_DEBUG
#ifdef CONFIG_PROC_FS
#define PROC_XBUS_COMMAND "command"
static int proc_xbus_command_write(struct file *file,
const char __user *buffer, unsigned long count, void *data);
static const struct file_operations proc_xbus_command_ops;
#endif
#endif
@@ -63,8 +63,7 @@ static DEF_PARM_BOOL(dahdi_autoreg, 0, 0644,
"Register devices automatically (1) or not (0)");
#ifdef CONFIG_PROC_FS
static int xbus_read_proc(char *page, char **start, off_t off, int count,
int *eof, void *data);
static const struct file_operations xbus_read_proc_ops;
#endif
static void transport_init(xbus_t *xbus, struct xbus_ops *ops,
ushort max_send_size,
@@ -1532,29 +1531,26 @@ xbus_t *xbus_new(struct xbus_ops *ops, ushort max_send_size,
err = -EIO;
goto nobus;
}
xbus->proc_xbus_summary =
create_proc_read_entry(PROC_XBUS_SUMMARY, 0444, xbus->proc_xbus_dir,
xbus_read_proc,
(void *)((unsigned long)(xbus->num)));
xbus->proc_xbus_summary = proc_create_data(PROC_XBUS_SUMMARY, 0444,
xbus->proc_xbus_dir,
&xbus_read_proc_ops,
(void *)((unsigned long)xbus->num));
if (!xbus->proc_xbus_summary) {
XBUS_ERR(xbus, "Failed to create proc file '%s'\n",
PROC_XBUS_SUMMARY);
err = -EIO;
goto nobus;
}
SET_PROC_DIRENTRY_OWNER(xbus->proc_xbus_summary);
#ifdef PROTOCOL_DEBUG
xbus->proc_xbus_command =
create_proc_entry(PROC_XBUS_COMMAND, 0200, xbus->proc_xbus_dir);
xbus->proc_xbus_command = proc_create_data(PROC_XBUS_COMMAND, 0200,
xbus->proc_xbus_dir,
&proc_xbus_command_ops, xbus);
if (!xbus->proc_xbus_command) {
XBUS_ERR(xbus, "Failed to create proc file '%s'\n",
PROC_XBUS_COMMAND);
err = -EIO;
goto nobus;
}
xbus->proc_xbus_command->write_proc = proc_xbus_command_write;
xbus->proc_xbus_command->data = xbus;
SET_PROC_DIRENTRY_OWNER(xbus->proc_xbus_command);
#endif
#endif
xframe_queue_init(&xbus->command_queue, 10, command_queue_length,
@@ -1596,8 +1592,6 @@ static bool xpds_done(xbus_t *xbus)
{
if (XBUS_IS(xbus, FAIL))
return 1; /* Nothing to wait for */
if (!XBUS_IS(xbus, RECVD_DESC))
return 1; /* We are not in the initialization phase */
if (xbus->worker.xpds_init_done)
return 1; /* All good */
/* Keep waiting */
@@ -1626,14 +1620,9 @@ int waitfor_xpds(xbus_t *xbus, char *buf)
len = -ENODEV;
goto out;
}
if (worker->num_units == 0) {
XBUS_ERR(xbus, "No cards. Skipping.\n");
goto out;
}
XBUS_DBG(DEVICES, xbus,
"Waiting for card init of %d XPD's max %d seconds (%p)\n",
worker->num_units, INITIALIZATION_TIMEOUT / HZ,
&worker->wait_for_xpd_initialization);
"Waiting for card init of XPDs max %d seconds\n",
INITIALIZATION_TIMEOUT / HZ);
ret =
wait_event_interruptible_timeout(worker->
wait_for_xpd_initialization,
@@ -1668,106 +1657,96 @@ out:
#ifdef CONFIG_PROC_FS
static int xbus_fill_proc_queue(char *p, struct xframe_queue *q)
static void xbus_fill_proc_queue(struct seq_file *sfile, struct xframe_queue *q)
{
int len;
len = sprintf(p,
seq_printf(sfile,
"%-15s: counts %3d, %3d, %3d worst %3d, overflows %3d "
"worst_lag %02ld.%ld ms\n",
q->name, q->steady_state_count, q->count, q->max_count,
q->worst_count, q->overflows, q->worst_lag_usec / 1000,
q->worst_lag_usec % 1000);
xframe_queue_clearstats(q);
return len;
}
static int xbus_read_proc(char *page, char **start, off_t off, int count,
int *eof, void *data)
static int xbus_proc_show(struct seq_file *sfile, void *data)
{
xbus_t *xbus;
unsigned long flags;
int len = 0;
int i = (int)((unsigned long)data);
int i = (int)((unsigned long)sfile->private);
xbus = get_xbus(__func__, i); /* until end of xbus_read_proc */
xbus = get_xbus(__func__, i); /* until end of xbus_proc_show() */
if (!xbus)
goto out;
return -EINVAL;
spin_lock_irqsave(&xbus->lock, flags);
len +=
sprintf(page + len, "%s: CONNECTOR=%s LABEL=[%s] STATUS=%s\n",
seq_printf(sfile, "%s: CONNECTOR=%s LABEL=[%s] STATUS=%s\n",
xbus->busname, xbus->connector, xbus->label,
(XBUS_FLAGS(xbus, CONNECTED)) ? "connected" : "missing");
len += xbus_fill_proc_queue(page + len, &xbus->send_pool);
len += xbus_fill_proc_queue(page + len, &xbus->receive_pool);
len += xbus_fill_proc_queue(page + len, &xbus->command_queue);
len += xbus_fill_proc_queue(page + len, &xbus->receive_queue);
len += xbus_fill_proc_queue(page + len, &xbus->pcm_tospan);
xbus_fill_proc_queue(sfile, &xbus->send_pool);
xbus_fill_proc_queue(sfile, &xbus->receive_pool);
xbus_fill_proc_queue(sfile, &xbus->command_queue);
xbus_fill_proc_queue(sfile, &xbus->receive_queue);
xbus_fill_proc_queue(sfile, &xbus->pcm_tospan);
if (rx_tasklet) {
len += sprintf(page + len, "\ncpu_rcv_intr: ");
seq_printf(sfile, "\ncpu_rcv_intr: ");
for_each_online_cpu(i)
len += sprintf(page + len, "%5d ", xbus->cpu_rcv_intr[i]);
len += sprintf(page + len, "\ncpu_rcv_tasklet: ");
seq_printf(sfile, "%5d ", xbus->cpu_rcv_intr[i]);
seq_printf(sfile, "\ncpu_rcv_tasklet: ");
for_each_online_cpu(i)
len +=
sprintf(page + len, "%5d ", xbus->cpu_rcv_tasklet[i]);
len += sprintf(page + len, "\n");
seq_printf(sfile, "%5d ", xbus->cpu_rcv_tasklet[i]);
seq_printf(sfile, "\n");
}
len +=
sprintf(page + len, "self_ticking: %d (last_tick at %ld)\n",
seq_printf(sfile, "self_ticking: %d (last_tick at %ld)\n",
xbus->self_ticking, xbus->ticker.last_sample.tv.tv_sec);
len +=
sprintf(page + len, "command_tick: %d\n",
seq_printf(sfile, "command_tick: %d\n",
xbus->command_tick_counter);
len += sprintf(page + len, "usec_nosend: %d\n", xbus->usec_nosend);
len +=
sprintf(page + len, "xbus: pcm_rx_counter = %d, frag = %d\n",
seq_printf(sfile, "usec_nosend: %d\n", xbus->usec_nosend);
seq_printf(sfile, "xbus: pcm_rx_counter = %d, frag = %d\n",
atomic_read(&xbus->pcm_rx_counter), xbus->xbus_frag_count);
len +=
sprintf(page + len, "max_rx_process = %2ld.%ld ms\n",
seq_printf(sfile, "max_rx_process = %2ld.%ld ms\n",
xbus->max_rx_process / 1000, xbus->max_rx_process % 1000);
xbus->max_rx_process = 0;
len +=
sprintf(page + len, "\nTRANSPORT: max_send_size=%d refcount=%d\n",
seq_printf(sfile, "\nTRANSPORT: max_send_size=%d refcount=%d\n",
MAX_SEND_SIZE(xbus),
atomic_read(&xbus->transport.transport_refcount)
);
len += sprintf(page + len, "PCM Metrices:\n");
len +=
sprintf(page + len, "\tPCM TX: min=%ld max=%ld\n",
seq_printf(sfile, "PCM Metrices:\n");
seq_printf(sfile, "\tPCM TX: min=%ld max=%ld\n",
xbus->min_tx_sync, xbus->max_tx_sync);
len +=
sprintf(page + len, "\tPCM RX: min=%ld max=%ld\n",
seq_printf(sfile, "\tPCM RX: min=%ld max=%ld\n",
xbus->min_rx_sync, xbus->max_rx_sync);
len += sprintf(page + len, "COUNTERS:\n");
seq_printf(sfile, "COUNTERS:\n");
for (i = 0; i < XBUS_COUNTER_MAX; i++) {
len +=
sprintf(page + len, "\t%-15s = %d\n", xbus_counters[i].name,
seq_printf(sfile, "\t%-15s = %d\n", xbus_counters[i].name,
xbus->counters[i]);
}
len += sprintf(page + len, "<-- len=%d\n", len);
seq_printf(sfile, "<-- len=%d\n", len);
spin_unlock_irqrestore(&xbus->lock, flags);
put_xbus(__func__, xbus); /* from xbus_read_proc() */
out:
if (len <= off + count)
*eof = 1;
*start = page + off;
len -= off;
if (len > count)
len = count;
if (len < 0)
len = 0;
return len;
put_xbus(__func__, xbus); /* from xbus_proc_show() */
return 0;
}
static int xbus_read_proc_open(struct inode *inode, struct file *file)
{
return single_open(file, xbus_proc_show, PDE_DATA(inode));
}
static const struct file_operations xbus_read_proc_ops = {
.owner = THIS_MODULE,
.open = xbus_read_proc_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
#ifdef PROTOCOL_DEBUG
static int proc_xbus_command_write(struct file *file,
const char __user *buffer, unsigned long count, void *data)
static ssize_t proc_xbus_command_write(struct file *file,
const char __user *buffer, size_t count, loff_t *offset)
{
char *buf;
xbus_t *xbus = data;
xbus_t *xbus = file->private_data;
char *p;
__u8 *pack_start;
__u8 *q;
@@ -1777,7 +1756,7 @@ static int proc_xbus_command_write(struct file *file,
const size_t max_text = max_len * 3 + 10;
if (count > max_text) {
XBUS_ERR(xbus, "%s: line too long (%ld > %zd)\n", __func__,
XBUS_ERR(xbus, "%s: line too long (%zd > %zd)\n", __func__,
count, max_len);
return -EFBIG;
}
@@ -1790,7 +1769,7 @@ static int proc_xbus_command_write(struct file *file,
goto out;
}
buf[count] = '\0';
XBUS_DBG(GENERAL, xbus, "count=%ld\n", count);
XBUS_DBG(GENERAL, xbus, "count=%zd\n", count);
/*
* We replace the content of buf[] from
* ascii representation to packet content
@@ -1846,20 +1825,29 @@ out:
kfree(buf);
return count;
}
static int proc_xbus_command_open(struct inode *inode, struct file *file)
{
file->private_data = PDE_DATA(inode);
return 0;
}
static const struct file_operations proc_xbus_command_ops = {
.owner = THIS_MODULE,
.open = proc_xbus_command_open,
.write = proc_xbus_command_write,
};
#endif
static int read_proc_xbuses(char *page, char **start, off_t off, int count,
int *eof, void *data)
static int xpp_proc_read_show(struct seq_file *sfile, void *data)
{
int len = 0;
int i;
for (i = 0; i < MAX_BUSES; i++) {
xbus_t *xbus = get_xbus(__func__, i);
if (xbus) {
len +=
sprintf(page + len,
seq_printf(sfile,
"%s: CONNECTOR=%s LABEL=[%s] STATUS=%s\n",
xbus->busname, xbus->connector, xbus->label,
(XBUS_FLAGS(xbus, CONNECTED)) ? "connected"
@@ -1868,19 +1856,24 @@ static int read_proc_xbuses(char *page, char **start, off_t off, int count,
}
}
#if 0
len += sprintf(page + len, "<-- len=%d\n", len);
seq_printf(sfile, "<-- len=%d\n", len);
#endif
if (len <= off + count)
*eof = 1;
*start = page + off;
len -= off;
if (len > count)
len = count;
if (len < 0)
len = 0;
return len;
return 0;
}
static int xpp_proc_read_open(struct inode *inode, struct file *file)
{
return single_open(file, xpp_proc_read_show, PDE_DATA(inode));
}
static const struct file_operations xpp_proc_read_ops = {
.owner = THIS_MODULE,
.open = xpp_proc_read_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
#endif
static void transport_init(xbus_t *xbus, struct xbus_ops *ops,
@@ -1971,15 +1964,13 @@ int __init xbus_core_init(void)
INFO("FEATURE: with PROTOCOL_DEBUG\n");
#endif
#ifdef CONFIG_PROC_FS
proc_xbuses =
create_proc_read_entry(PROC_XBUSES, 0444, xpp_proc_toplevel,
read_proc_xbuses, NULL);
proc_xbuses = proc_create_data(PROC_XBUSES, 0444, xpp_proc_toplevel,
&xpp_proc_read_ops, NULL);
if (!proc_xbuses) {
ERR("Failed to create proc file %s\n", PROC_XBUSES);
ret = -EFAULT;
goto err;
}
SET_PROC_DIRENTRY_OWNER(proc_xbuses);
#endif
if ((ret = xpp_driver_init()) < 0)
goto err;

View File

@@ -145,10 +145,12 @@ typedef char *charp;
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
/* Also don't define this for later RHEL >= 5.2 . hex_asc is from the
* same linux-2.6-net-infrastructure-updates-to-mac80211-iwl4965.patch
* as is the bool typedef. */
#if LINUX_VERSION_CODE != KERNEL_VERSION(2, 6, 18) || !defined(hex_asc)
/* Also don't define this for later RHEL >= 5.2. */
#if defined(RHEL_RELEASE_CODE) && defined(RHEL_RELEASE_VERSION)
#if RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(5, 3)
typedef int bool;
#endif
#else
typedef int bool;
#endif
#endif

View File

@@ -34,6 +34,7 @@
#include <linux/delay.h> /* for udelay */
#include <linux/interrupt.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <dahdi/kernel.h>
#include "xbus-core.h"
#include "xproto.h"
@@ -102,8 +103,7 @@ int total_registered_spans(void)
}
#ifdef CONFIG_PROC_FS
static int xpd_read_proc(char *page, char **start, off_t off, int count,
int *eof, void *data);
static const struct file_operations xpd_read_proc_ops;
#endif
/*------------------------- XPD Management -------------------------*/
@@ -169,9 +169,9 @@ static int xpd_proc_create(xbus_t *xbus, xpd_t *xpd)
XPD_ERR(xpd, "Failed to create proc directory\n");
goto err;
}
xpd->proc_xpd_summary =
create_proc_read_entry(PROC_XPD_SUMMARY, 0444, xpd->proc_xpd_dir,
xpd_read_proc, xpd);
xpd->proc_xpd_summary = proc_create_data(PROC_XPD_SUMMARY, 0444,
xpd->proc_xpd_dir,
&xpd_read_proc_ops, xpd);
if (!xpd->proc_xpd_summary) {
XPD_ERR(xpd, "Failed to create proc file '%s'\n",
PROC_XPD_SUMMARY);
@@ -254,89 +254,72 @@ EXPORT_SYMBOL(create_xpd);
/**
* Prints a general procfs entry for the bus, under xpp/BUSNAME/summary
* @page TODO: figure out procfs
* @start TODO: figure out procfs
* @off TODO: figure out procfs
* @count TODO: figure out procfs
* @eof TODO: figure out procfs
* @data an xbus_t pointer with the bus data.
*/
static int xpd_read_proc(char *page, char **start, off_t off, int count,
int *eof, void *data)
static int xpd_read_proc_show(struct seq_file *sfile, void *data)
{
int len = 0;
xpd_t *xpd = data;
xpd_t *xpd = sfile->private;
int i;
if (!xpd)
goto out;
return -EINVAL;
len +=
sprintf(page + len,
seq_printf(sfile,
"%s (%s, card %s, span %d)\n" "timing_priority: %d\n"
"timer_count: %d span->mainttimer=%d\n", xpd->xpdname,
xpd->type_name, (xpd->card_present) ? "present" : "missing",
(SPAN_REGISTERED(xpd)) ? PHONEDEV(xpd).span.spanno : 0,
PHONEDEV(xpd).timing_priority, xpd->timer_count,
PHONEDEV(xpd).span.mainttimer);
len +=
sprintf(page + len, "xpd_state: %s (%d)\n",
seq_printf(sfile, "xpd_state: %s (%d)\n",
xpd_statename(xpd->xpd_state), xpd->xpd_state);
len +=
sprintf(page + len, "open_counter=%d refcount=%d\n",
seq_printf(sfile, "open_counter=%d refcount=%d\n",
atomic_read(&PHONEDEV(xpd).open_counter),
refcount_xpd(xpd));
len +=
sprintf(page + len, "Address: U=%d S=%d\n", xpd->addr.unit,
seq_printf(sfile, "Address: U=%d S=%d\n", xpd->addr.unit,
xpd->addr.subunit);
len += sprintf(page + len, "Subunits: %d\n", xpd->subunits);
len += sprintf(page + len, "Type: %d.%d\n\n", xpd->type, xpd->subtype);
len += sprintf(page + len, "pcm_len=%d\n\n", PHONEDEV(xpd).pcm_len);
len +=
sprintf(page + len, "wanted_pcm_mask=0x%04X\n\n",
seq_printf(sfile, "Subunits: %d\n", xpd->subunits);
seq_printf(sfile, "Type: %d.%d\n\n", xpd->type, xpd->subtype);
seq_printf(sfile, "pcm_len=%d\n\n", PHONEDEV(xpd).pcm_len);
seq_printf(sfile, "wanted_pcm_mask=0x%04X\n\n",
PHONEDEV(xpd).wanted_pcm_mask);
len +=
sprintf(page + len, "mute_dtmf=0x%04X\n\n",
seq_printf(sfile, "mute_dtmf=0x%04X\n\n",
PHONEDEV(xpd).mute_dtmf);
len += sprintf(page + len, "STATES:");
len += sprintf(page + len, "\n\t%-17s: ", "output_relays");
seq_printf(sfile, "STATES:");
seq_printf(sfile, "\n\t%-17s: ", "output_relays");
for_each_line(xpd, i) {
len +=
sprintf(page + len, "%d ",
seq_printf(sfile, "%d ",
IS_SET(PHONEDEV(xpd).digital_outputs, i));
}
len += sprintf(page + len, "\n\t%-17s: ", "input_relays");
seq_printf(sfile, "\n\t%-17s: ", "input_relays");
for_each_line(xpd, i) {
len +=
sprintf(page + len, "%d ",
seq_printf(sfile, "%d ",
IS_SET(PHONEDEV(xpd).digital_inputs, i));
}
len += sprintf(page + len, "\n\t%-17s: ", "offhook");
seq_printf(sfile, "\n\t%-17s: ", "offhook");
for_each_line(xpd, i) {
len += sprintf(page + len, "%d ", IS_OFFHOOK(xpd, i));
seq_printf(sfile, "%d ", IS_OFFHOOK(xpd, i));
}
len += sprintf(page + len, "\n\t%-17s: ", "oht_pcm_pass");
seq_printf(sfile, "\n\t%-17s: ", "oht_pcm_pass");
for_each_line(xpd, i) {
len +=
sprintf(page + len, "%d ",
seq_printf(sfile, "%d ",
IS_SET(PHONEDEV(xpd).oht_pcm_pass, i));
}
len += sprintf(page + len, "\n\t%-17s: ", "msg_waiting");
seq_printf(sfile, "\n\t%-17s: ", "msg_waiting");
for_each_line(xpd, i) {
len += sprintf(page + len, "%d ", PHONEDEV(xpd).msg_waiting[i]);
seq_printf(sfile, "%d ", PHONEDEV(xpd).msg_waiting[i]);
}
len += sprintf(page + len, "\n\t%-17s: ", "ringing");
seq_printf(sfile, "\n\t%-17s: ", "ringing");
for_each_line(xpd, i) {
len += sprintf(page + len, "%d ", PHONEDEV(xpd).ringing[i]);
seq_printf(sfile, "%d ", PHONEDEV(xpd).ringing[i]);
}
len += sprintf(page + len, "\n\t%-17s: ", "no_pcm");
seq_printf(sfile, "\n\t%-17s: ", "no_pcm");
for_each_line(xpd, i) {
len +=
sprintf(page + len, "%d ", IS_SET(PHONEDEV(xpd).no_pcm, i));
seq_printf(sfile, "%d ", IS_SET(PHONEDEV(xpd).no_pcm, i));
}
#if 1
if (SPAN_REGISTERED(xpd)) {
len += sprintf(page + len,
seq_printf(sfile,
"\nPCM:\n |"
" [readchunk] |"
" [writechunk] | W D");
@@ -358,16 +341,16 @@ static int xpd_read_proc(char *page, char **start, off_t off, int count,
wp = chan->writechunk;
memcpy(rchunk, rp, DAHDI_CHUNKSIZE);
memcpy(wchunk, wp, DAHDI_CHUNKSIZE);
len += sprintf(page + len, "\n port %2d> | ", i);
seq_printf(sfile, "\n port %2d> | ", i);
for (j = 0; j < DAHDI_CHUNKSIZE; j++)
len += sprintf(page + len, "%02X ", rchunk[j]);
len += sprintf(page + len, " | ");
seq_printf(sfile, "%02X ", rchunk[j]);
seq_printf(sfile, " | ");
for (j = 0; j < DAHDI_CHUNKSIZE; j++)
len += sprintf(page + len, "%02X ", wchunk[j]);
len += sprintf(page + len, " | %c",
seq_printf(sfile, "%02X ", wchunk[j]);
seq_printf(sfile, " | %c",
(IS_SET(PHONEDEV(xpd).wanted_pcm_mask, i))
? '+' : ' ');
len += sprintf(page + len, " %c",
seq_printf(sfile, " %c",
(IS_SET(PHONEDEV(xpd).mute_dtmf, i))
? '-' : ' ');
}
@@ -375,36 +358,37 @@ static int xpd_read_proc(char *page, char **start, off_t off, int count,
#endif
#if 0
if (SPAN_REGISTERED(xpd)) {
len += sprintf(page + len, "\nSignalling:\n");
seq_printf(sfile, "\nSignalling:\n");
for_each_line(xpd, i) {
struct dahdi_chan *chan = XPD_CHAN(xpd, i);
len +=
sprintf(page + len,
seq_printf(sfile,
"\t%2d> sigcap=0x%04X sig=0x%04X\n", i,
chan->sigcap, chan->sig);
}
}
#endif
len += sprintf(page + len, "\nCOUNTERS:\n");
seq_printf(sfile, "\nCOUNTERS:\n");
for (i = 0; i < XPD_COUNTER_MAX; i++) {
len +=
sprintf(page + len, "\t\t%-20s = %d\n",
seq_printf(sfile, "\t\t%-20s = %d\n",
xpd_counters[i].name, xpd->counters[i]);
}
len += sprintf(page + len, "<-- len=%d\n", len);
out:
if (len <= off + count)
*eof = 1;
*start = page + off;
len -= off;
if (len > count)
len = count;
if (len < 0)
len = 0;
return len;
seq_printf(sfile, "<-- len=%d\n", len);
return 0;
}
static int xpd_read_proc_open(struct inode *inode, struct file *file)
{
return single_open(file, xpd_read_proc_show, PDE_DATA(inode));
}
static const struct file_operations xpd_read_proc_ops = {
.owner = THIS_MODULE,
.open = xpd_read_proc_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
#endif
const char *xpd_statename(enum xpd_state st)

View File

@@ -231,8 +231,7 @@ static int xusb_probe(struct usb_interface *interface,
const struct usb_device_id *id);
static void xusb_disconnect(struct usb_interface *interface);
#ifdef CONFIG_PROC_FS
static int xusb_read_proc(char *page, char **start, off_t off, int count,
int *eof, void *data);
static const struct file_operations xusb_read_proc_ops;
#endif
/*------------------------------------------------------------------*/
@@ -743,9 +742,9 @@ static int xusb_probe(struct usb_interface *interface,
#ifdef CONFIG_PROC_FS
DBG(PROC,
"Creating proc entry " PROC_USBXPP_SUMMARY " in bus proc dir.\n");
procsummary =
create_proc_read_entry(PROC_USBXPP_SUMMARY, 0444,
xbus->proc_xbus_dir, xusb_read_proc, xusb);
procsummary = proc_create_data(PROC_USBXPP_SUMMARY, 0444,
xbus->proc_xbus_dir, &xusb_read_proc_ops,
xusb);
if (!procsummary) {
XBUS_ERR(xbus, "Failed to create proc file '%s'\n",
PROC_USBXPP_SUMMARY);
@@ -753,7 +752,6 @@ static int xusb_probe(struct usb_interface *interface,
retval = -EIO;
goto probe_failed;
}
SET_PROC_DIRENTRY_OWNER(procsummary);
#endif
bus_count++;
xusb->xbus_num = xbus->num;
@@ -1020,90 +1018,83 @@ static void __exit xpp_usb_shutdown(void)
#ifdef CONFIG_PROC_FS
static int xusb_read_proc(char *page, char **start, off_t off, int count,
int *eof, void *data)
static int xusb_read_proc_show(struct seq_file *sfile, void *data)
{
int len = 0;
unsigned long flags;
int i;
//unsigned long stamp = jiffies;
xusb_t *xusb = data;
xusb_t *xusb = sfile->private;
uint usb_tx_delay[NUM_BUCKETS];
const int mark_limit = tx_sluggish / USEC_BUCKET;
if (!xusb)
goto out;
return 0;
// TODO: probably needs a per-xusb lock:
spin_lock_irqsave(&xusb_lock, flags);
len +=
sprintf(page + len, "Device: %03d/%03d\n", xusb->udev->bus->busnum,
seq_printf(sfile, "Device: %03d/%03d\n", xusb->udev->bus->busnum,
xusb->udev->devnum);
len +=
sprintf(page + len, "USB: manufacturer=%s\n", xusb->manufacturer);
len += sprintf(page + len, "USB: product=%s\n", xusb->product);
len += sprintf(page + len, "USB: serial=%s\n", xusb->serial);
len +=
sprintf(page + len, "Minor: %d\nModel Info: %s\n", xusb->minor,
seq_printf(sfile, "USB: manufacturer=%s\n", xusb->manufacturer);
seq_printf(sfile, "USB: product=%s\n", xusb->product);
seq_printf(sfile, "USB: serial=%s\n", xusb->serial);
seq_printf(sfile, "Minor: %d\nModel Info: %s\n", xusb->minor,
xusb->model_info->desc);
len +=
sprintf(page + len,
seq_printf(sfile,
"Endpoints:\n" "\tIn: 0x%02X - Size: %d)\n"
"\tOut: 0x%02X - Size: %d)\n",
xusb->endpoints[XUSB_RECV].ep_addr,
xusb->endpoints[XUSB_RECV].max_size,
xusb->endpoints[XUSB_SEND].ep_addr,
xusb->endpoints[XUSB_SEND].max_size);
len +=
sprintf(page + len, "\npending_writes=%d\n",
seq_printf(sfile, "\npending_writes=%d\n",
atomic_read(&xusb->pending_writes));
len +=
sprintf(page + len, "pending_reads=%d\n",
seq_printf(sfile, "pending_reads=%d\n",
atomic_read(&xusb->pending_reads));
len += sprintf(page + len, "max_tx_delay=%d\n", xusb->max_tx_delay);
seq_printf(sfile, "max_tx_delay=%d\n", xusb->max_tx_delay);
xusb->max_tx_delay = 0;
#ifdef DEBUG_PCM_TIMING
len +=
sprintf(page + len,
seq_printf(sfile,
"\nstamp_last_pcm_read=%lld accumulate_diff=%lld\n",
stamp_last_pcm_read, accumulate_diff);
#endif
memcpy(usb_tx_delay, xusb->usb_tx_delay, sizeof(usb_tx_delay));
len +=
sprintf(page + len, "usb_tx_delay[%d,%d,%d]: ", USEC_BUCKET,
seq_printf(sfile, "usb_tx_delay[%d,%d,%d]: ", USEC_BUCKET,
BUCKET_START, NUM_BUCKETS);
for (i = BUCKET_START; i < NUM_BUCKETS; i++) {
len += sprintf(page + len, "%6d ", usb_tx_delay[i]);
seq_printf(sfile, "%6d ", usb_tx_delay[i]);
if (i == mark_limit)
len += sprintf(page + len, "| ");
seq_printf(sfile, "| ");
}
len +=
sprintf(page + len, "\nPCM_TX_DROPS: %5d (sluggish: %d)\n",
seq_printf(sfile, "\nPCM_TX_DROPS: %5d (sluggish: %d)\n",
atomic_read(&xusb->pcm_tx_drops),
atomic_read(&xusb->usb_sluggish_count)
);
len += sprintf(page + len, "\nCOUNTERS:\n");
seq_printf(sfile, "\nCOUNTERS:\n");
for (i = 0; i < XUSB_COUNTER_MAX; i++) {
len +=
sprintf(page + len, "\t%-15s = %d\n", xusb_counters[i].name,
seq_printf(sfile, "\t%-15s = %d\n", xusb_counters[i].name,
xusb->counters[i]);
}
#if 0
len += sprintf(page + len, "<-- len=%d\n", len);
seq_printf(sfile, "<-- len=%d\n", len);
#endif
spin_unlock_irqrestore(&xusb_lock, flags);
out:
if (len <= off + count)
*eof = 1;
*start = page + off;
len -= off;
if (len > count)
len = count;
if (len < 0)
len = 0;
return len;
return 0;
}
static int xusb_read_proc_open(struct inode *inode, struct file *file)
{
return single_open(file, xusb_read_proc_show, PDE_DATA(inode));
}
static const struct file_operations xusb_read_proc_ops = {
.owner = THIS_MODULE,
.open = xusb_read_proc_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
#endif
MODULE_DESCRIPTION("XPP USB Transport Driver");

View File

@@ -190,4 +190,10 @@
*/
/* #define CONFIG_DAHDI_MIRROR */
/*
* Adds support for conference links. There are some non-Asterisk users of this
* functionality.
*/
/* #define CONFIG_DAHDI_CONFLINK */
#endif

View File

@@ -40,6 +40,7 @@
#include <linux/version.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/module.h>
#include <linux/ioctl.h>
@@ -100,6 +101,14 @@
# endif
#endif
/* __dev* were removed in 3.8. They still have effect in 2.6.18. */
#ifndef __devinit
# define __devinit
# define __devinitdata
# define __devexit
# define __devexit_p(x) x
#endif
/*! Default chunk size for conferences and such -- static right now, might make
variable sometime. 8 samples = 1 ms = most frequent service interval possible
for a USB device */
@@ -605,6 +614,8 @@ struct dahdi_chan {
#else
unsigned char *lin2x;
#endif
struct device chan_device; /*!< Kernel object for this chan */
#define dev_to_chan(dev) container_of(dev, struct dahdi_chan, chan_device)
};
#ifdef CONFIG_DAHDI_NET
@@ -738,15 +749,16 @@ static inline int dahdi_have_netdev(const struct dahdi_chan *chan) { return 0; }
#endif
struct dahdi_count {
__u32 fe; /*!< Framing error counter */
__u32 cv; /*!< Coding violations counter */
__u32 bpv; /*!< Bipolar Violation counter */
__u32 crc4; /*!< CRC4 error counter */
__u32 ebit; /*!< current E-bit error count */
__u32 fas; /*!< current FAS error count */
__u32 be; /*!< current bit error count */
__u32 prbs; /*!< current PRBS detected pattern */
__u32 errsec; /*!< errored seconds */
u32 fe; /*!< Framing error counter */
u32 cv; /*!< Coding violations counter */
u32 bpv; /*!< Bipolar Violation counter */
u32 crc4; /*!< CRC4 error counter */
u32 ebit; /*!< current E-bit error count */
u32 fas; /*!< current FAS error count */
u32 be; /*!< current bit error count */
u32 prbs; /*!< current PRBS detected pattern */
u32 errsec; /*!< errored seconds */
u32 timingslips; /*!< Clock slips */
};
/* map flagbits to flag masks */
@@ -952,8 +964,6 @@ struct dahdi_span {
int maintstat; /*!< Maintenance state */
int mainttimer; /*!< Maintenance timer */
int timingslips; /*!< Clock slips */
struct dahdi_chan **chans; /*!< Member channel structures */
const struct dahdi_span_ops *ops; /*!< span callbacks. */
@@ -1227,6 +1237,12 @@ void dahdi_init_tone_state(struct dahdi_tone_state *ts, struct dahdi_tone *zt);
/*! \brief Get a given MF tone struct, suitable for dahdi_tone_nextsample. */
struct dahdi_tone *dahdi_mf_tone(const struct dahdi_chan *chan, char digit, int digitmode);
/*! \brief Convert signalling bits to human readable string */
const char *sigstr(int sig);
/*! \brief Convert alarm bits to human readable string */
int fill_alarm_string(char *buf, int count, int alarms);
/* Echo cancel a receive and transmit chunk for a given channel. This
should be called by the low-level driver as close to the interface
as possible. ECHO CANCELLATION IS NO LONGER AUTOMATICALLY DONE
@@ -1385,9 +1401,33 @@ static inline short dahdi_txtone_nextsample(struct dahdi_chan *ss)
/*! Maximum audio mask */
#define DAHDI_FORMAT_AUDIO_MASK ((1 << 16) - 1)
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0)
#ifdef CONFIG_PROC_FS
#include <linux/proc_fs.h>
static inline void *PDE_DATA(const struct inode *inode)
{
return PDE(inode)->data;
}
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)
#define KERN_CONT ""
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
#ifdef CONFIG_PROC_FS
#include <linux/proc_fs.h>
static inline struct proc_dir_entry *proc_create_data(const char *name,
mode_t mode,
struct proc_dir_entry *parent,
const struct file_operations *proc_fops,
void *data)
{
struct proc_dir_entry *pde = create_proc_entry(name, mode, parent);
if (!pde)
return NULL;
pde->proc_fops = proc_fops;
pde->data = data;
return pde;
}
#endif /* CONFIG_PROC_FS */
#ifndef clamp
#define clamp(x, low, high) min(max(low, x), high)
#endif
@@ -1440,10 +1480,7 @@ static inline int strcasecmp(const char *s1, const char *s2)
#endif /* 2.6.25 */
#endif /* 2.6.26 */
#endif /* 2.6.31 */
#ifndef CONFIG_TRACING
#define trace_printk printk
#endif
#endif /* 3.10.0 */
#ifndef DEFINE_SPINLOCK
#define DEFINE_SPINLOCK(x) spinlock_t x = SPIN_LOCK_UNLOCKED

View File

@@ -636,6 +636,11 @@ struct dahdi_confinfo {
#define DAHDI_SETCONF_V1 _IOW(DAHDI_CODE, 12, struct dahdi_confinfo)
#define DAHDI_SETCONF _IOWR(DAHDI_CODE, 13, struct dahdi_confinfo)
/*
* Setup or Remove Conference Link
*/
#define DAHDI_CONFLINK _IOW(DAHDI_CODE, 14, struct dahdi_confinfo)
/*
* Display Conference Diagnostic Information on Console
*/