Compare commits

...

71 Commits

Author SHA1 Message Date
Shaun Ruffell
a951dd5e32 wcte43x: Do not reconfigure framer when span lineconfig is not changed.
If dahdi_span_ops.spanconfig is called multiple times in a row (like when
running dahdi_cfg; dahdi_cfg ) the tx signaling bits would go through a spurious
state that some far side devices would respond to.

Now, if the dahdi_span_ops.spanconfig callback is called, and the configuration
matches the existing configuration, we will not touch the framer.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2014-07-11 14:14:15 -05:00
Shaun Ruffell
8210fea5b3 wcte13xp: Do not reconfigure framer when span lineconfig is not changed.
If dahdi_span_ops.spanconfig is called multiple times in a row (like when
running dahdi_cfg; dahdi_cfg ) the tx signaling bits would go through a spurious
state that some far side devices would respond to.

Now, if the dahdi_span_ops.spanconfig callback is called, and the configuration
matches the existing configuration, we will not touch the framer.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2014-07-11 14:14:15 -05:00
Shaun Ruffell
a1ff3cb0c0 dahdi: Stop tones on channel when updating tone zone.
If a channel is currently playing a tone when the tone zone is updated, the
existing tone zone could be freed while the channel keeps a reference to the
current tone (curtone) that points into the freed zone.

If the newly freed tone is then modified, there was a window where it was
possible to  corrupt 'struct dahdi_chan' (by overrunning swritechunk[])
resulting in a "BUG: unable to handle kernel paging request at virtual address"
panic in the context of __dahdi_transmit_chunk().

Reported-and-Tested-by: Matt Behrens <matt@zigg.com>
Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2014-07-07 12:25:36 -05:00
Shaun Ruffell
089b593b56 wct4xxp: Report rx signalling bit changes after spanconfig.
This fixes a long standing issue where, for CAS signaling, the RX bits were
sometimes misreported after span configuration before the first detected state
change.

The logic in the wct4xxp driver now matches that in the wcte43x driver and
wcte13xp drivers. The wcte12xp driver always polls the sigbits due to how
voicebus works and is not affected by this.

Internal-Issue-ID: DAHDI-1081
Signed-off-by: Shaun Ruffell <sruffell@digium.com>
2014-06-27 22:40:28 -05:00
Shaun Ruffell
71867c3de7 wcte43x: Do not get stuck in "Not Open" state when DAHDI_CONFIG_NOTOPEN is set.
This is the same change for the wcte13xp driver but applied to the other
xbus-based digital card.

If dahdi_cfg set the DAHDI_CONFIG_NOTOPEN setting on the span, which it does
when the "yellow" flag is added to the span config line, then it was possible
for the span to get stuck with DAHDI_ALARM_NOTOPEN (NOP).

This is because the driver only updates the alarm state when the framer reports
that the span alarm has changed. Therefore, unless the framer goes through an
alarm transition, the fact that channels are opened was never noticed by alarm
handling routine.

Now check the alarm state directly when the first channel is opened, and the
last channel is closed.

Internal-Issue-ID: DAHDI-1103
Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2014-06-20 13:01:27 -05:00
Shaun Ruffell
61aeaf13ae wcte43x: Change span flags to atomic bitfield.
This will facilitate adding another flag for open channels on a span without
needing to add a lock on the span, or taking the global lock. Currently the span
flags are protected by the global reglock. This is not longer required.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2014-06-20 13:01:27 -05:00
Shaun Ruffell
f35e8aafb0 wcte13xp: Do not get stuck in "Not Open" state when DAHDI_CONFIG_NOTOPEN is set.
If dahdi_cfg set the DAHDI_CONFIG_NOTOPEN setting on the span, which it does
when the "yellow" flag is added to the span config line, then it was possible
for the span to get stuck with DAHDI_ALARM_NOTOPEN (NOP).

This is because the wcte13xp driver only updates the alarm state when the framer
reports that the span alarm has changed. Therefore, unless the framer goes
through an alarm transition, the fact that channels are opened was never noticed
by alarm handling routine.

Now check the alarm state directly when the first channel is opened, and the
last channel is closed.

Internal-Issue-ID: DAHDI-1103
Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2014-06-20 13:01:27 -05:00
Shaun Ruffell
b3a6b91858 Do not call dahdi_span_ops.open with spinlock held.
This makes the open symmetrical with the close. It is also considered good
practice to not call through callbacks with spinlocks held.

I modified all the drivers where I could not tell whether it was necessary to
hold the chan->lock with interrupts disabled to simply take the lock inside the
callback.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2014-06-20 13:01:27 -05:00
Shaun Ruffell
2e33bdc7b5 tor2: Remove unused open/close callbacks.
Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2014-06-20 13:01:27 -05:00
Shaun Ruffell
3755ec9bf2 wct4xxp: Remove unused open/close span_ops callbacks.
Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2014-06-20 13:01:27 -05:00
Doug Bailey
47f0fde0f1 wct4xxp: AMI w/CAS errata applies to octal card as well.
Fixes inability to reliably get CAS (robbed-bits) when using AMI line encoding
on the TE820 card.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2014-06-20 13:01:27 -05:00
Shaun Ruffell
180a17a39c wct4xxp: Trivial kmalloc + memset -> kzalloc.
Just a minor cleanup.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2014-06-20 13:01:27 -05:00
Shaun Ruffell
d1afa1b101 oct612x: Implement the SerializationObject callbacks.
When originally implemented, the octasic calls where protected by the big kernel
lock. This change now allows the octasic library to control it's synchronization
as originally intended.

It would still be worthwhile to completely make the oct612x library
kernel-compliant.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2014-06-20 13:01:27 -05:00
Shaun Ruffell
b4941f35ad wct4xxp: Move bottom half processing from tasklet to workqueue.
I am primarily making this change in order that the oct612x API can use a mutex as
a synchronization primitive. Mutexes can only be aquired in process context and
the wct4xxp driver calls the Oct61000InterruptServiceRoutine (which grabs a
serialization object) when tone detection is enabled.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2014-06-20 13:01:27 -05:00
Shaun Ruffell
a3578ca156 dahdi: dahdi_chan.ec_factory can be protected with the mutex.
This is never accessed or modified in interrupt context. This closes a potential
race if the echocan is being changed on a channel while enabling disabling is
hapening on another thread.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2014-06-20 13:01:27 -05:00
Shaun Ruffell
761e02da52 dahdi: Protect echocan creation/destruction with mutex.
This closes a reference and memory leak when multiple CPUs are enabling echocan
on a single channel in parallel.

The essential problem is that the call to try_module_get() is not serialized.
Two separate threads can come into ioctl_echocan() on the same channel, they
coordinate via the dahdi_chan.lock to release any current echocan, but then both
create a new echocan state, bump the reference on the module, and the last one
through will actually attach the new state to the channel. The earlier reference
/ memory is leaked.

I tried to conceive of a way to fix this leak without adding a new lock, but the
choices where calling throught the function pointers with dahdi_chan.lock.
Otherwise I needed to change the semantics of echocan_create /free which would
ripple through the hardware echocan modules.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2014-06-20 13:01:27 -05:00
Shaun Ruffell
cb50ae1500 wctc4xxp: spin_lock() -> spin_lock_irqsave() in wctc4xxp_watchdog()
Since commit (e10f740 "wctc4xxp: Service tx ring in interrupt handler."), it
was possible to deadlock the system if the interrupt fires while the
watchdog function is running in the context of the system timer.

This was reported by lockdep.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2014-06-10 11:33:00 -05:00
Shaun Ruffell
e9ec13dfa0 wctc4xxp: Trivial reduction of indentation level in wctc4xxp_watchdog()
Now use a continue after the check for cmd->timeout. This change is because I
need to make another change but the deep indentation level would make it hard to
stay within the 80 column limit.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2014-06-10 11:33:00 -05:00
Shaun Ruffell
dfa8a0ebd3 wctc4xxp: Trivial removal of unused structure members.
These were left over from recent developments and are not used by the driver.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2014-06-05 11:35:42 -05:00
Shaun Ruffell
6e10dbdfb6 wctc4xxp: Constrain RTP payload to 500 bytes.
This is a limitation of the DTE firmware that normally would result in dropped
packets on the firmware. If the driver knows it is going to be dropped it should
drop it.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2014-06-05 11:35:42 -05:00
Shaun Ruffell
2010bc6433 wctc4xxp: Reload the firmware if a fatal alert was received.
The driver will now automatically reload the firmware when there are no open
channels if the firmware reports a fatal error. If the firmware reports an
error, but it was not fatal, it will leave things running and try to reload when
all channels are shut down. The driver will also halt channel processing and
reload the firmware if a channel ever failed to be created.

The thought is that if the DTE reports a non-fatal error, I cannot be certain
what the state is, and it should be reset when possible without impacting
otherwise functioning card.  If there are problems, presumably all users would
hang up and the driver will then reload the firmware.

If the error is fatal, then all processing is halted to encourage everyone to
hang up. The card is probably not working at this point anyway, so there is no
point in trying to communicate with it.

Also included in this change is a compile-time selectable debug sysfs attribute
that will allow forcing an alert condition for testing the recovery.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2014-06-05 11:35:42 -05:00
Shaun Ruffell
624f30bbf6 wctc4xxp: Trivial fix typo that was preventing firmware load.
The interrupt handler was not schedulding the deferred processing routine when
there was packets to process. I did not test the actual master branch after
editing for checkpatch compliance. Sorry.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
2014-06-02 06:08:08 -05:00
Shaun Ruffell
d7c0b0aba1 wctc4xxp: Prevent exhausting memory in firmware.
If the host system sends to many packets to the DTE to process, the on-card
memory can be exhausted which will result in an out of memory alert. In commit
2ac2338247, the driver will halt all communication
with the card and request a reload if any alert is received.

Now the driver will silently drop any "burst" traffic that was sent to the
transcoder as opposed to expecting the firmware to do it. There is currently a
limit of 640 samples (80ms of audio) in flight to the firmware at any one time
allowed.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2014-05-30 15:07:20 -05:00
Shaun Ruffell
e10f740476 wctc4xxp: Service tx ring in interrupt handler.
This helps to keep the tx descriptor ring at max capacity when the system is
otherwise loaded. Now ready packets are moved from cmd_list to the transmit
descriptor ring directly in the interrupt handler and not when the deferred
function runs.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2014-05-30 15:07:20 -05:00
Shaun Ruffell
dc92bf05cd wctc4xxp: Fix the timestamp calculation for the RTP stream.
I do not have any evidence that this made a difference, but hopefully it will
clear things up for people in the future who might be wondering why the
timestamp does not increase with the number of samples actually sent.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2014-05-30 15:07:20 -05:00
Shaun Ruffell
8557bb6786 wctc4xxp: Speed up the rate of polling.
The polling interval was not fast enough to keep the tx ring full on a loaded
card. This fixes a regression introduced in commits
ba05e31c8a and
354d88cd41.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2014-05-30 15:07:20 -05:00
Shaun Ruffell
5981b152de wctc4xxp: Handle all known interrupts regardless of mask.
When switching to polling mode it was possible that we would mask off the
receive complete interrupt until the next timer fired. Now go ahead and handle
anything we know how to handle regardless of the current mask.

Also, no need to update the reg local anymore since it isn't used to ack any
interrupts. We now always ack all the interrupts first and inspect them all.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2014-05-30 15:07:20 -05:00
Oron Peled
cbe92363ea xpp: re-organize calls so worker_reset()
re-organize calls so worker_reset() isn't called twice
(was called from xbus_disconnect() and worker_destroy())

Signed-off-by: Tzafrir Cohen <tzafrir.cohen@xorcom.com>
2014-05-27 14:04:48 +03:00
Oron Peled
43a3dbb484 xpp: demote some NOTICE() to DBG()
Signed-off-by: Tzafrir Cohen <tzafrir.cohen@xorcom.com>
2014-05-27 14:04:48 +03:00
Oron Peled
9a00fc6321 xpp: stability -- better xbus shut down
* Maintain a "shutting_down" flag per-xbus
* Use it to prevent xbus dereferencing (via xbus_get()/xbus_put())
  during an xbus shutdown.
* Also, remove xbus from global array earlier.

Signed-off-by: Tzafrir Cohen <tzafrir.cohen@xorcom.com>
2014-05-27 14:04:48 +03:00
Oron Peled
db07e1b74d xpp: stability -- deadlock in waitfor_xpds()
waitfor_xpds xbus sysfs file should not take an xbus refcount:

* It is called from sysfs which maintain its own device refcount.
* If put_xbus() calls xbus_destroy() than down the call chain it will
  try to release an object that is held by sysfs.
* This will create a deadlock.

Signed-off-by: Tzafrir Cohen <tzafrir.cohen@xorcom.com>
2014-05-27 14:04:48 +03:00
Oron Peled
235d530fee xpp: stability -- better debug information
Signed-off-by: Tzafrir Cohen <tzafrir.cohen@xorcom.com>
2014-05-27 14:04:48 +03:00
Oron Peled
dfa7304f51 xpp: stability -- cleaner xpp_open/close
* No need to use spinlock.
 * Just correctly use the atomic open_counter.

Signed-off-by: Tzafrir Cohen <tzafrir.cohen@xorcom.com>
2014-05-27 14:04:48 +03:00
Oron Peled
08127e14f7 xpp: stability fixes - xusb mutex
* Replace old semaphore with mutex
 * Use this mutex for BOTH usb probe/disconnect

Signed-off-by: Tzafrir Cohen <tzafrir.cohen@xorcom.com>
2014-05-27 14:04:48 +03:00
Shaun Ruffell
6e2698f4c1 wctc4xxp: Speed up channel setup / tear-down.
1) Enabling multiple csm_encaps channel commands in a single packet.
2) Sending commands to separate channels in parallel.

This reduces the time waiting for the responses to the commands and brings in
the channel setup from 50ms to under 10ms.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2014-05-20 11:36:23 -05:00
Shaun Ruffell
c9481d30bb pciradio: interruptible_sleep_on_timeout() -> msleep_interruptible()
interruptible_sleep_on_timeout() has been deprecated for awhile and was finally
removed in Linux 3.15. Since interruptible_sleep_on_timeout() uses jiffies for
the delay, I assumed that each jiffy equated to 10ms given the age of the
driver.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Acked-by: Tzafrir Cohen <tzafrir.cohen@xorcom.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2014-05-20 11:36:23 -05:00
Shaun Ruffell
779d62791c Add #include <linux/slab.h> to all files that call kzalloc|kmalloc|kfree.
Some architectures, like arm, do not automatically pull in the definitions for
kzalloc and friends. This allows DAHDI to build on those platforms.

Originally reported to the asterisk-users mailing list here
http://lists.digium.com/pipermail/asterisk-users/2014-February/282338.html

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Acked-by: Tzafrir Cohen <tzafrir.cohen@xorcom.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2014-05-20 11:36:23 -05:00
Shaun Ruffell
8342a3d21b wctc4xxp: Add debug option to print channel stats to kernel log.
This patch does a couple of things. It adds a new DEBUG mode where packet
statistics are printed when channels are closed which can be used to track where
packets might be lost in the transcoding chain.

This patch will also print to the kernel log if the AN983 has detected any
errored received packets. Problems of this type are typically system problems,
like when the card is having trouble DMAing packets.

Internal-Issue-ID: DAHDI-1071
Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2014-05-16 12:06:58 -05:00
Shaun Ruffell
ba05e31c8a wctc4xxp: Allow the tx and rx descriptor rings to be different sizes
Keeping the transmit descriptor ring shorter reduces the time it takes to send
CSM_ENCAP commands to the transcoding engine when the card is otherwise busy.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2014-05-16 12:06:58 -05:00
Shaun Ruffell
b6a8623203 wctc4xxp: channel count does not need to be atomic.
It is only modified under the chanlock anyway.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2014-05-16 12:06:58 -05:00
Shaun Ruffell
354d88cd41 wctc4xxp: Use hardware timer for polling and not kernel timer
Simplifies the logic when polling is enabled. No need to worry about any system
factors when scheduling the default kernel timer.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2014-05-16 12:06:58 -05:00
Shaun Ruffell
0efce00a09 wctc4xxp: Make sure csm_encaps commands are sent before RTP.
Otherwise, if there are many RTP commands queued on the command list, some of
the CSM_ENCAP packets, like ACKS, weren't being sent to the firmware within the
timeout value.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2014-05-16 12:06:58 -05:00
Shaun Ruffell
67e422c1ef wctc4xxp: Reduce the number of locks grabbed when sending commands
Not only does this make it atomic when moving commands from the
waiting_for_response_list to the command_list if the descriptor is full, it will
also make the entire process of submitting a packet the packet transmission
logic atomic.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2014-05-16 12:06:58 -05:00
Shaun Ruffell
cbe4825d1a wctc4xxp: Trivial removal of the receiveprep function.
This was more a holdover when the AN983 interface was brought over from the
voicebus driver.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2014-05-16 12:06:58 -05:00
Shaun Ruffell
b5ac763f29 wctc4xxp: Cleanup RTP for unopened channels.
When we start the shutdown sequence for a channel, there is no need to submit
any RTP packets that are queued on the command list. Under extreme load with
many backed up RTP packets it was possible to have RTP packets submitted after
the channel shutdown process started.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2014-05-16 12:06:58 -05:00
Shaun Ruffell
6341783cc8 wctc4xxp: All the commands do not need to have completions embedded in them.
A small percentage of the total packets sent to the DTE ever wait for
completions. This will save on the need to keep the completion around in all the
packets.

Also, since we can use the presence of the completion as the flag whether we
intend to auto free, we can simplify the flags as well.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2014-05-16 12:06:58 -05:00
Shaun Ruffell
ea04099e77 wctc4xxp: Encode the function in the ACK.
While not required by the protocol to the DTE, this does help when debugging the
trace files.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2014-05-16 12:06:58 -05:00
Shaun Ruffell
bc274e1b5d wctc4xxp: We always want to ack the responses.
Furthermore, do it as soon as we know we should to prevent the ack from
potentially going out after another CSM_ENCAPS packet on another CPU.

Previously, we would not send ACKS to responses we believed we already responded
to.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2014-05-16 12:06:58 -05:00
Shaun Ruffell
44a33126e0 wctc4xxp: Only capture commands once they are on the descriptor ring.
Eliminates some cases where there are duplicated packets in the capture if the
hardware descriptor ring was already full.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2014-05-16 12:06:57 -05:00
Shaun Ruffell
3446cdca8f wctc4xxp: Do not allow duplicated sequence numbers to be received for the channels.
Makes the channels themselves behave like the supervisor channel. This only
protects the driver in the case the commands were severly backed up, like when
there was high packet loss.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2014-05-16 12:06:57 -05:00
Shaun Ruffell
391ca2b7aa wctc4xxp: Do not need locks on the transcoder buffers.
They are sufficiently protected by the list locks. This also cleans up a case
where the tcp was unlocked after already completing it, which was corrupting the
list.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2014-05-16 12:06:57 -05:00
Shaun Ruffell
ec9d162344 wctc4xxp: Check for shutdown after acquiring the mutex lock.
In case we missed an alert, this will allow for rapid shutdown of Asterisk.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2014-05-16 12:06:57 -05:00
Shaun Ruffell
7168b87cb5 wctc4xxp: Always ack a response packet.
Even if it is duplicated or we don't have an outbound message waiting, we should
ack it so that the firmware does not keep trying to send it to the host.
Otherwise the firmware could get into situations where it was constantly
retrying to send packets for which it did not receive our previous ACK and
exhaust memory.

I was only seeing this on platforms were packets were going missing in the
stream, increasing the probability that the driver would miss early responses.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2014-05-16 12:06:57 -05:00
Shaun Ruffell
f8a6f55e80 wctc4xxp: Enable the fatal bus error interrupt.
The kernel log will now contain reports if there are bus errors.
This is a troubleshooting aide on systems with bus issues.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2014-05-16 12:06:57 -05:00
Shaun Ruffell
6c796d0774 wctc4xxp: Replace channel semaphore with channel mutex.
Clarifies that the semaphore was being used as a mutex. Mutexes are also more
efficient and allow better debugging checks.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2014-05-16 12:06:57 -05:00
Shaun Ruffell
9c65971863 wctc4xxp: Remove unused debug ioctl interface.
The ioctls for the debug network interface on the tc400b0 has not been used for
a long time. It is now gone.

This will also allow the sempahore set in the ioctl to be changed into a mutex
which provides enhanced debugging checks.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2014-05-16 12:06:57 -05:00
Shaun Ruffell
2ac2338247 wctc4xxp: Halt the card when an alert is received.
When an unsolicited alert is received, we'll flag the card as halted so that
commands will not be retried. This is because often times the firmware will no
longer process any commands in this state and the driver will hold processes in
the dstate while waiting to retry the commands.

This is a debugging aide in that it simplies unloading the driver if the card /
driver is currently in a failed state.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2014-05-16 12:06:57 -05:00
Shaun Ruffell
3096ffe955 wctc4xxp: Disable read-line and read-line-multiple PCI commands.
The read-line-multiple command was already disabled on the voicebus cards, which
use the same interface, in commit 4de462c3e0. This
does the same thing for the transcoder card and also disables the read line
command.

I've seen this change directly correlated to problems with the AN983 receiving
packets from the onboard DSP on some platforms.

Internal-Issue-ID: DAHDI-1071
Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2014-05-16 12:06:57 -05:00
Shaun Ruffell
039daca12e wctc4xxp: Make sure we call the pci_enable_mwi() function.
I've not seen this directly tied to any issue, but it's enabled on the voicebus
cards and so brings the wctc4xxp driver in line.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
2014-05-16 12:06:57 -05:00
Tzafrir Cohen
15ff405dc8 xpp: pri: Fix more than a single CAS/R2 call
Fixes regression from bb63d03bba (before
v2.7.0). This failed to set the PCM mask on a CAS span when
DAHDI_AUDIO_NOTIFY was not set.

As the first channel of each xbus would be enabled (for
synchronization), a single call may still have passed.

This patch sets the PCM mask on any CAS channel explicitly.

Signed-off-by: Tzafrir Cohen <tzafrir.cohen@xorcom.com>
2014-04-30 22:44:46 +03:00
Oron Peled
5e24d501c5 xpp: prevent double dahdi un-registration
* It's currently harmless (just re-run the pre/post XPD registrations)
* But it's cleaner this way (as with xbus_register_dahdi_device())

Signed-off-by: Tzafrir Cohen <tzafrir.cohen@xorcom.com>
2014-04-30 22:44:46 +03:00
Oron Peled
193c9e59a8 xpp: new xbus attribute: dahdi_registration
XPP devices have implicit support for device registration and
unregistration. Even though it is only used for the legacy (non-hotplug)
configuration case, we still prefer to make it explicit.

This attribute would later allow a simpler implementation of the user
space (xpp-specific) tool dahdi_registration.

Signed-off-by: Tzafrir Cohen <tzafrir.cohen@xorcom.com>
2014-04-30 22:44:46 +03:00
Oron Peled
606dd58a47 xpp: fix failed multi-PRI E1<->T1 transition
In an Astribank with >= 2 PRI ports, switching from E1 to T1 at run-time
may fail at the DAHDI_CHANCONFIG ioctl on the first channel in a span,
That is, on first run of dahdi_cfg, it fails on second span, on second:
it fails on third span, etc.

The code clears the D-channel information on the DAHDI_CHANCONFIG call
for the first channel in the span.

However The code tested for the global "channo" rather than the per-span
"chanpos" to check for the first channel in the span. This the test
failed.

Signed-off-by: Tzafrir Cohen <tzafrir.cohen@xorcom.com>
2014-04-30 22:44:46 +03:00
Tzafrir Cohen
adfd0910b7 Don't install firmware to /usr/lib/hotplug/firmware
/usr/lib/hotplug/firmware is an old location not used since the move
from the old hotplug system. We no longer need to support it. No need to
keep two copies of the firmware files.

Acked-by: Russ Meyerriecks <rmeyerriecks@digium.com>
Signed-off-by: Shaun Ruffell <sruffell@digium.com>
2014-04-30 13:58:07 -05:00
Shaun Ruffell
a66db43356 wcte43x: Build against 2.6.18 and CentOS 5.5
This is to support users who are unable to update to the lastest CentOS 5.x.
There is no change for most users on the latest releases of their distribution.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
2014-04-30 13:58:07 -05:00
Shaun Ruffell
6649a3a166 wcte43x: Trivial fix of 'source' in comment.
Signed-off-by: Shaun Ruffell <sruffell@digium.com>
2014-04-30 13:58:02 -05:00
Shaun Ruffell
8256ba602e wctc4xxp: Trivial. Remove unused timer_list from struct tcb.
The timer_list member of the transcoder buffer has not been used for a long
time. Saves some space in the buffer in addition to removing any future
curiosity about what it is for.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
2014-04-30 13:34:58 -05:00
Shaun Ruffell
c8b0d91972 dahdi: Define pf_fmt() globally in kernel.h
Normally the board drivers should define this, but if they do not we will
provide a suitable default. This allows compilation with vanilla Linux 2.6.18.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
2014-04-30 13:34:29 -05:00
Shaun Ruffell
b6eb7ae6d8 wcte43xp: Close potential unbalanced call to enable_irq().
If the memory allocation for the new channel array fails, it would be possible
to call enable_irq() without the corresponding call to disable_irq().

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
2014-04-01 11:53:00 -05:00
Shaun Ruffell
f6edaf5cea wcte13xp: Remove redundant call to synchronize_irq().
disable_irq() already synchronizes with any running handlers.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
2014-04-01 11:46:46 -05:00
Shaun Ruffell
f2a3c1c963 wcte13xp: Trivial. Remove duplicate pointer to "struct pci_dev".
This pointer was left over during the switch to the wcxb library.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
2014-04-01 10:45:36 -05:00
37 changed files with 1733 additions and 837 deletions

View File

@@ -5,16 +5,14 @@
FIRMWARE_PATTERN=$1
FIRMWARE_VERSION=$2
DESTDIR=$3
target="$DESTDIR/lib/firmware"
if ! test -f ${DESTDIR}/usr/lib/hotplug/firmware/.${FIRMWARE_PATTERN}-${FIRMWARE_VERSION} || ! test -f ${DESTDIR}/lib/firmware/.${FIRMWARE_PATTERN}-${FIRMWARE_VERSION}; then
echo "Installing ${FIRMWARE_PATTERN}.bin to hotplug firmware directories"
if ! test -f $target/.${FIRMWARE_PATTERN}-${FIRMWARE_VERSION}; then
echo "Installing ${FIRMWARE_PATTERN}.bin to $target"
tar --no-same-owner -xf ${FIRMWARE_PATTERN}-${FIRMWARE_VERSION}.tar.gz || exit 1
install -m 644 ${FIRMWARE_PATTERN}.bin ${DESTDIR}/usr/lib/hotplug/firmware || exit 1
rm -rf ${DESTDIR}/usr/lib/hotplug/firmware/.${FIRMWARE_PATTERN}-*
touch ${DESTDIR}/usr/lib/hotplug/firmware/.${FIRMWARE_PATTERN}-${FIRMWARE_VERSION}
install -m 644 ${FIRMWARE_PATTERN}.bin ${DESTDIR}/lib/firmware || exit 1
rm -rf ${DESTDIR}/lib/firmware/.${FIRMWARE_PATTERN}-*
touch ${DESTDIR}/lib/firmware/.${FIRMWARE_PATTERN}-${FIRMWARE_VERSION}
install -m 644 ${FIRMWARE_PATTERN}.bin $target || exit 1
rm -rf $target/.${FIRMWARE_PATTERN}-*
touch $target/.${FIRMWARE_PATTERN}-${FIRMWARE_VERSION}
# Remove the .bin file so that if the version is reverted, it will not
# be installed with a non-matching ${FIRMARE_VERSION} file.
rm ${FIRMWARE_PATTERN}.bin

View File

@@ -51,6 +51,7 @@
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/ktime.h>
#include <linux/slab.h>
#if defined(HAVE_UNLOCKED_IOCTL) && defined(CONFIG_BKL)
#include <linux/smp_lock.h>
@@ -990,10 +991,13 @@ static int dahdi_seq_show(struct seq_file *sfile, void *data)
seq_fill_alarm_string(sfile, chan->chan_alarms);
if (chan->ec_factory)
mutex_lock(&chan->mutex);
if (chan->ec_factory) {
seq_printf(sfile, "(EC: %s - %s) ",
chan->ec_factory->get_name(chan),
chan->ec_state ? "ACTIVE" : "INACTIVE");
}
mutex_unlock(&chan->mutex);
seq_printf(sfile, "\n");
}
@@ -1488,14 +1492,13 @@ static const struct dahdi_echocan_factory hwec_factory = {
static int dahdi_enable_hw_preechocan(struct dahdi_chan *chan)
{
int res;
unsigned long flags;
spin_lock_irqsave(&chan->lock, flags);
mutex_lock(&chan->mutex);
if (chan->ec_factory != &hwec_factory)
res = -ENODEV;
else
res = 0;
spin_unlock_irqrestore(&chan->lock, flags);
mutex_unlock(&chan->mutex);
if (-ENODEV == res)
return 0;
@@ -1808,6 +1811,17 @@ static int start_tone(struct dahdi_chan *chan, int tone)
return res;
}
/**
* stop_tone - Stops any tones on a channel.
*
* Must be called with chan->lock held.
*
*/
static inline int stop_tone(struct dahdi_chan *chan)
{
return start_tone(chan, -1);
}
static int set_tone_zone(struct dahdi_chan *chan, int zone)
{
int res = 0;
@@ -1835,6 +1849,9 @@ static int set_tone_zone(struct dahdi_chan *chan, int zone)
return -ENODATA;
spin_lock_irqsave(&chan->lock, flags);
stop_tone(chan);
if (chan->curzone) {
struct dahdi_zone *zone = chan->curzone;
chan->curzone = NULL;
@@ -1883,6 +1900,7 @@ static void __dahdi_init_chan(struct dahdi_chan *chan)
might_sleep();
spin_lock_init(&chan->lock);
mutex_init(&chan->mutex);
init_waitqueue_head(&chan->waitq);
if (!chan->master)
chan->master = chan;
@@ -2301,10 +2319,10 @@ static void dahdi_chan_unreg(struct dahdi_chan *chan)
*/
}
spin_lock_irqsave(&chan->lock, flags);
mutex_lock(&chan->mutex);
release_echocan(chan->ec_factory);
chan->ec_factory = NULL;
spin_unlock_irqrestore(&chan->lock, flags);
mutex_unlock(&chan->mutex);
#ifdef CONFIG_DAHDI_NET
if (dahdi_have_netdev(chan)) {
@@ -3053,57 +3071,64 @@ static const struct file_operations dahdi_chan_fops;
static int dahdi_specchan_open(struct file *file)
{
int res = 0;
int res = -ENXIO;
struct dahdi_chan *const chan = chan_from_file(file);
if (chan && chan->sig) {
/* Make sure we're not already open, a net device, or a slave device */
if (dahdi_have_netdev(chan))
res = -EBUSY;
else if (chan->master != chan)
res = -EBUSY;
else if ((chan->sig & __DAHDI_SIG_DACS) == __DAHDI_SIG_DACS)
res = -EBUSY;
else if (!test_and_set_bit(DAHDI_FLAGBIT_OPEN, &chan->flags)) {
unsigned long flags;
res = initialize_channel(chan);
if (res) {
/* Reallocbufs must have failed */
clear_bit(DAHDI_FLAGBIT_OPEN, &chan->flags);
return res;
}
spin_lock_irqsave(&chan->lock, flags);
if (is_pseudo_chan(chan))
chan->flags |= DAHDI_FLAG_AUDIO;
if (chan->span) {
const struct dahdi_span_ops *const ops =
chan->span->ops;
if (!try_module_get(ops->owner)) {
res = -ENXIO;
} else if (ops->open) {
res = ops->open(chan);
if (res)
module_put(ops->owner);
}
}
if (!res) {
chan->file = file;
file->private_data = chan;
/* Since we know we're a channel now, we can
* update the f_op pointer and bypass a few of
* the checks on the minor number. */
file->f_op = &dahdi_chan_fops;
spin_unlock_irqrestore(&chan->lock, flags);
} else {
spin_unlock_irqrestore(&chan->lock, flags);
close_channel(chan);
clear_bit(DAHDI_FLAGBIT_OPEN, &chan->flags);
}
} else {
res = -EBUSY;
if (!chan || !chan->sig)
return -ENXIO;
/* Make sure we're not already open, a net device, or a slave
* device */
if (dahdi_have_netdev(chan))
res = -EBUSY;
else if (chan->master != chan)
res = -EBUSY;
else if ((chan->sig & __DAHDI_SIG_DACS) == __DAHDI_SIG_DACS)
res = -EBUSY;
else if (!test_and_set_bit(DAHDI_FLAGBIT_OPEN, &chan->flags)) {
unsigned long flags;
const struct dahdi_span_ops *const ops =
(!is_pseudo_chan(chan)) ? chan->span->ops : NULL;
if (ops && !try_module_get(ops->owner)) {
clear_bit(DAHDI_FLAGBIT_OPEN, &chan->flags);
return -ENXIO;
}
} else
res = -ENXIO;
res = initialize_channel(chan);
if (res) {
/* Reallocbufs must have failed */
clear_bit(DAHDI_FLAGBIT_OPEN, &chan->flags);
return res;
}
spin_lock_irqsave(&chan->lock, flags);
if (is_pseudo_chan(chan))
chan->flags |= DAHDI_FLAG_AUDIO;
chan->file = file;
file->private_data = chan;
/* Since we know we're a channel now, we can
* update the f_op pointer and bypass a few of
* the checks on the minor number. */
file->f_op = &dahdi_chan_fops;
spin_unlock_irqrestore(&chan->lock, flags);
if (ops && ops->open) {
res = ops->open(chan);
if (res) {
spin_lock_irqsave(&chan->lock, flags);
chan->file = NULL;
file->private_data = NULL;
spin_unlock_irqrestore(&chan->lock, flags);
module_put(ops->owner);
close_channel(chan);
clear_bit(DAHDI_FLAGBIT_OPEN,
&chan->flags);
}
}
} else {
res = -EBUSY;
}
return res;
}
@@ -5225,7 +5250,6 @@ static bool dahdi_is_hwec_available(const struct dahdi_chan *chan)
static int dahdi_ioctl_attach_echocan(unsigned long data)
{
unsigned long flags;
struct dahdi_chan *chan;
struct dahdi_attach_echocan ae;
const struct dahdi_echocan_factory *new = NULL, *old;
@@ -5267,10 +5291,10 @@ static int dahdi_ioctl_attach_echocan(unsigned long data)
}
}
spin_lock_irqsave(&chan->lock, flags);
mutex_lock(&chan->mutex);
old = chan->ec_factory;
chan->ec_factory = new;
spin_unlock_irqrestore(&chan->lock, flags);
mutex_unlock(&chan->mutex);
if (old)
release_echocan(old);
@@ -6330,6 +6354,7 @@ ioctl_echocancel(struct dahdi_chan *chan, struct dahdi_echocanparams *ecp,
if (ecp->tap_length == 0) {
/* disable mode, don't need to inspect params */
mutex_lock(&chan->mutex);
spin_lock_irqsave(&chan->lock, flags);
ec_state = chan->ec_state;
chan->ec_state = NULL;
@@ -6340,7 +6365,7 @@ ioctl_echocancel(struct dahdi_chan *chan, struct dahdi_echocanparams *ecp,
ec_state->ops->echocan_free(chan, ec_state);
release_echocan(ec_current);
}
mutex_unlock(&chan->mutex);
return 0;
}
@@ -6357,6 +6382,7 @@ ioctl_echocancel(struct dahdi_chan *chan, struct dahdi_echocanparams *ecp,
goto exit_with_free;
}
mutex_lock(&chan->mutex);
/* free any echocan that may be on the channel already */
spin_lock_irqsave(&chan->lock, flags);
ec_state = chan->ec_state;
@@ -6427,6 +6453,7 @@ ioctl_echocancel(struct dahdi_chan *chan, struct dahdi_echocanparams *ecp,
}
exit_with_free:
mutex_unlock(&chan->mutex);
kfree(params);
return ret;

View File

@@ -168,8 +168,9 @@ static void dtc_release(struct dahdi_transcoder_channel *chan)
BUG_ON(!chan);
if (chan->parent && chan->parent->release) {
chan->parent->release(chan);
} else {
dahdi_tc_clear_busy(chan);
}
dahdi_tc_clear_busy(chan);
}
static int dahdi_tc_release(struct inode *inode, struct file *file)

View File

@@ -51,6 +51,7 @@
#include <linux/pkt_sched.h>
#include <linux/spinlock.h>
#include <linux/rcupdate.h>
#include <linux/slab.h>
#include <net/syncppp.h>

View File

@@ -129,7 +129,7 @@ $Octasic_Revision: 16 $
/***************************** TYPES ***************************************/
/*Change this type if your platform uses 64bits semaphores/locks */
typedef UINT32 tOCT6100_USER_SERIAL_OBJECT;
typedef void* tOCT6100_USER_SERIAL_OBJECT;
typedef struct _OCT6100_GET_TIME_
{

View File

@@ -59,29 +59,38 @@ UINT32 Oct6100UserMemCopy(PVOID f_pDestination, const void *f_pSource,
UINT32 Oct6100UserCreateSerializeObject(
tPOCT6100_CREATE_SERIALIZE_OBJECT f_pCreate)
{
struct oct612x_context *context = f_pCreate->pProcessContext;
struct mutex *lock = kzalloc(sizeof(*lock), GFP_KERNEL);
if (!lock) {
dev_err(context->dev, "Out of memory in %s.\n", __func__);
return cOCT6100_ERR_BASE;
}
mutex_init(lock);
f_pCreate->ulSerialObjHndl = lock;
return cOCT6100_ERR_OK;
}
UINT32 Oct6100UserDestroySerializeObject(
tPOCT6100_DESTROY_SERIALIZE_OBJECT f_pDestroy)
{
#ifdef OCTASIC_DEBUG
pr_debug("I should never be called! (destroy serialize object)\n");
#endif
struct mutex *lock = f_pDestroy->ulSerialObjHndl;
kfree(lock);
return cOCT6100_ERR_OK;
}
UINT32 Oct6100UserSeizeSerializeObject(
tPOCT6100_SEIZE_SERIALIZE_OBJECT f_pSeize)
{
/* Not needed */
struct mutex *lock = f_pSeize->ulSerialObjHndl;
mutex_lock(lock);
return cOCT6100_ERR_OK;
}
UINT32 Oct6100UserReleaseSerializeObject(
tPOCT6100_RELEASE_SERIALIZE_OBJECT f_pRelease)
{
/* Not needed */
struct mutex *lock = f_pRelease->ulSerialObjHndl;
mutex_unlock(lock);
return cOCT6100_ERR_OK;
}

View File

@@ -51,6 +51,8 @@ With driver: 303826 (1.5 %)
#include <linux/interrupt.h>
#include <linux/moduleparam.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <asm/io.h>
#include <asm/delay.h>
@@ -480,8 +482,6 @@ static void rbi_out(struct pciradio *rad, int n, unsigned char *rbicmd)
{
unsigned long flags;
int x;
DECLARE_WAIT_QUEUE_HEAD(mywait);
for(;;)
{
@@ -489,7 +489,8 @@ DECLARE_WAIT_QUEUE_HEAD(mywait);
x = rad->remote_locked || (__pciradio_getcreg(rad,0xc) & 2);
if (!x) rad->remote_locked = 1;
spin_unlock_irqrestore(&rad->lock,flags);
if (x) interruptible_sleep_on_timeout(&mywait,2);
if (x)
msleep_interruptible(20);
else break;
}
spin_lock_irqsave(&rad->lock,flags);
@@ -526,7 +527,6 @@ static void mx828_command(struct pciradio *rad,int channel, unsigned char comman
static void mx828_command_wait(struct pciradio *rad,int channel, unsigned char command, unsigned char *byte1, unsigned char *byte2)
{
DECLARE_WAIT_QUEUE_HEAD(mywait);
unsigned long flags;
@@ -534,7 +534,7 @@ unsigned long flags;
while(rad->encdec.state)
{
spin_unlock_irqrestore(&rad->lock,flags);
interruptible_sleep_on_timeout(&mywait,2);
msleep_interruptible(20);
spin_lock_irqsave(&rad->lock,flags);
}
rad->encdec.lastcmd = jiffies + 1000;
@@ -966,7 +966,6 @@ static int pciradio_ioctl(struct dahdi_chan *chan, unsigned int cmd, unsigned lo
} stack;
struct pciradio *rad = chan->pvt;
DECLARE_WAIT_QUEUE_HEAD(mywait);
switch (cmd) {
case DAHDI_RADIO_GETPARAM:
@@ -1254,7 +1253,7 @@ static int pciradio_ioctl(struct dahdi_chan *chan, unsigned int cmd, unsigned lo
__pciradio_setcreg(rad,8,byte2);
spin_unlock_irqrestore(&rad->lock,flags);
if (i || (jiffies < rad->lastremcmd + 10))
interruptible_sleep_on_timeout(&mywait,10);
msleep_interruptible(100);
rad->lastremcmd = jiffies;
rbi_out(rad,chan->chanpos - 1,(unsigned char *)&stack.p.data);
spin_lock_irqsave(&rad->lock,flags);
@@ -1269,7 +1268,8 @@ static int pciradio_ioctl(struct dahdi_chan *chan, unsigned int cmd, unsigned lo
x = rad->remote_locked || (__pciradio_getcreg(rad,0xc) & 2);
if (!x) rad->remote_locked = 1;
spin_unlock_irqrestore(&rad->lock,flags);
if (x) interruptible_sleep_on_timeout(&mywait,2);
if (x)
msleep_interruptible(20);
else break;
}
spin_lock_irqsave(&rad->lock,flags);
@@ -1286,14 +1286,14 @@ static int pciradio_ioctl(struct dahdi_chan *chan, unsigned int cmd, unsigned lo
__pciradio_setcreg(rad,8,byte2);
spin_unlock_irqrestore(&rad->lock,flags);
if (byte1 != byte2)
interruptible_sleep_on_timeout(&mywait,3);
msleep_interruptible(30);
while (jiffies < rad->lastremcmd + 10)
interruptible_sleep_on_timeout(&mywait,10);
msleep_interruptible(100);
rad->lastremcmd = jiffies;
for(;;)
{
if (!(__pciradio_getcreg(rad,0xc) & 2)) break;
interruptible_sleep_on_timeout(&mywait,2);
msleep_interruptible(20);
}
spin_lock_irqsave(&rad->lock,flags);
/* enable and address async serializer */
@@ -1315,7 +1315,7 @@ static int pciradio_ioctl(struct dahdi_chan *chan, unsigned int cmd, unsigned lo
(!strchr((char *)rad->rxbuf,'\r'))))
{
spin_unlock_irqrestore(&rad->lock,flags);
interruptible_sleep_on_timeout(&mywait,2);
msleep_interruptible(20);
spin_lock_irqsave(&rad->lock,flags);
continue;
}
@@ -1335,7 +1335,7 @@ static int pciradio_ioctl(struct dahdi_chan *chan, unsigned int cmd, unsigned lo
while(rad->txlen && (rad->txindex < rad->txlen))
{
spin_unlock_irqrestore(&rad->lock,flags);
interruptible_sleep_on_timeout(&mywait,2);
msleep_interruptible(20);
spin_lock_irqsave(&rad->lock,flags);
}
/* disable and un-address async serializer */
@@ -1344,7 +1344,7 @@ static int pciradio_ioctl(struct dahdi_chan *chan, unsigned int cmd, unsigned lo
rad->remote_locked = 0;
spin_unlock_irqrestore(&rad->lock,flags);
if (rad->remmode[chan->chanpos - 1] == DAHDI_RADPAR_REM_SERIAL_ASCII)
interruptible_sleep_on_timeout(&mywait,100);
msleep_interruptible(1000);
if (copy_to_user((__user void *) data, &stack.p, sizeof(stack.p))) return -EFAULT;
return 0;
default:

View File

@@ -31,6 +31,7 @@
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <dahdi/kernel.h>
#define NEED_PCI_IDS
@@ -253,16 +254,6 @@ static int tor2_chanconfig(struct file *file,
return 0;
}
static int tor2_open(struct dahdi_chan *chan)
{
return 0;
}
static int tor2_close(struct dahdi_chan *chan)
{
return 0;
}
static const struct dahdi_span_ops tor2_span_ops = {
.owner = THIS_MODULE,
.spanconfig = tor2_spanconfig,
@@ -271,8 +262,6 @@ static const struct dahdi_span_ops tor2_span_ops = {
.shutdown = tor2_shutdown,
.rbsbits = tor2_rbsbits,
.maint = tor2_maint,
.open = tor2_open,
.close = tor2_close,
.ioctl = tor2_ioctl,
};

View File

@@ -38,6 +38,7 @@
#else
#include <asm/semaphore.h>
#endif
#include <linux/slab.h>
#include <dahdi/kernel.h>
#include <dahdi/user.h>

View File

@@ -27,6 +27,7 @@
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <dahdi/kernel.h>

View File

@@ -26,6 +26,7 @@
#include <linux/delay.h>
#include <linux/sched.h>
#include <linux/crc32.h>
#include <linux/slab.h>
#include "voicebus/vpmoct.h"
#include "linux/firmware.h"

View File

@@ -23,6 +23,7 @@
#include <linux/ctype.h>
#include <linux/moduleparam.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <dahdi/kernel.h>

View File

@@ -40,6 +40,7 @@
#include <linux/timer.h> /* timer_struct */
#include <linux/moduleparam.h>
#include <linux/proc_fs.h>
#include <linux/slab.h>
#include <dahdi/kernel.h>
@@ -2429,7 +2430,7 @@ b4xxp_chanconfig(struct file *file, struct dahdi_chan *chan, int sigtype)
return 0;
}
static int b4xxp_open(struct dahdi_chan *chan)
static int _b4xxp_open(struct dahdi_chan *chan)
{
struct b4xxp *b4 = chan->pvt;
struct b4xxp_span *bspan = &b4->spans[chan->span->offset];
@@ -2443,6 +2444,15 @@ static int b4xxp_open(struct dahdi_chan *chan)
return 0;
}
static int b4xxp_open(struct dahdi_chan *chan)
{
unsigned long flags;
int res;
spin_lock_irqsave(&chan->lock, flags);
res = _b4xxp_open(chan);
spin_unlock_irqrestore(&chan->lock, flags);
return res;
}
static int b4xxp_close(struct dahdi_chan *chan)
{

View File

@@ -31,6 +31,7 @@
#include <linux/pci.h>
#include <asm/io.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <dahdi/kernel.h>
@@ -569,7 +570,7 @@ static inline struct wcfxo *wcfxo_from_span(struct dahdi_span *span)
return container_of(span, struct wcfxo, span);
}
static int wcfxo_open(struct dahdi_chan *chan)
static int _wcfxo_open(struct dahdi_chan *chan)
{
struct wcfxo *wc = chan->pvt;
if (wc->dead)
@@ -578,6 +579,16 @@ static int wcfxo_open(struct dahdi_chan *chan)
return 0;
}
static int wcfxo_open(struct dahdi_chan *chan)
{
int res;
unsigned long flags;
spin_lock_irqsave(&chan->lock, flags);
res = _wcfxo_open(chan);
spin_unlock_irqrestore(&chan->lock, flags);
return res;
}
static int wcfxo_watchdog(struct dahdi_span *span, int event)
{
printk(KERN_INFO "FXO: Restarting DMA\n");

View File

@@ -32,6 +32,7 @@
#include <linux/pci.h>
#include <linux/spinlock.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <dahdi/kernel.h>

View File

@@ -40,6 +40,7 @@
#include <linux/delay.h>
#include <linux/moduleparam.h>
#include <linux/crc32.h>
#include <linux/slab.h>
#include <stdbool.h>
#include <dahdi/kernel.h>
@@ -370,9 +371,14 @@ struct t4 {
dma_addr_t writedma;
void __iomem *membase; /* Base address of card */
/* Flags for our bottom half */
#define T4_CHECK_VPM 0
#define T4_LOADING_FW 1
#define T4_STOP_DMA 2
#define T4_CHECK_TIMING 3
#define T4_CHANGE_LATENCY 4
#define T4_IGNORE_LATENCY 5
unsigned long checkflag;
struct tasklet_struct t4_tlet;
struct work_struct bh_work;
/* Latency related additions */
unsigned char rxident;
unsigned char lastindex;
@@ -548,8 +554,6 @@ static void t4_check_sigbits(struct t4 *wc, int span);
#define MAX_T4_CARDS 64
static void t4_isr_bh(unsigned long data);
static struct t4 *cards[MAX_T4_CARDS];
struct t8_firm_header {
@@ -1828,16 +1832,6 @@ t4_chanconfig(struct file *file, struct dahdi_chan *chan, int sigtype)
return 0;
}
static int t4_open(struct dahdi_chan *chan)
{
return 0;
}
static int t4_close(struct dahdi_chan *chan)
{
return 0;
}
static int set_span_devicetype(struct t4 *wc)
{
#ifdef VPM_SUPPORT
@@ -2115,6 +2109,8 @@ static void free_wc(struct t4 *wc)
{
unsigned int x, y;
flush_scheduled_work();
for (x = 0; x < ARRAY_SIZE(wc->tspans); x++) {
if (!wc->tspans[x])
continue;
@@ -2328,8 +2324,6 @@ static const struct dahdi_span_ops t4_gen1_span_ops = {
.shutdown = t4_shutdown,
.rbsbits = t4_rbsbits,
.maint = t4_maint,
.open = t4_open,
.close = t4_close,
.ioctl = t4_ioctl,
.hdlc_hard_xmit = t4_hdlc_hard_xmit,
.assigned = t4_span_assigned,
@@ -2344,8 +2338,6 @@ static const struct dahdi_span_ops t4_gen2_span_ops = {
.shutdown = t4_shutdown,
.rbsbits = t4_rbsbits,
.maint = t4_maint,
.open = t4_open,
.close = t4_close,
.ioctl = t4_ioctl,
.hdlc_hard_xmit = t4_hdlc_hard_xmit,
.dacs = t4_dacs,
@@ -2718,7 +2710,7 @@ static void __t4_configure_t1(struct t4 *wc, int unit, int lineconfig, int txlev
if (lineconfig & DAHDI_CONFIG_AMI) {
line = "AMI";
/* workaround for errata #2 in ES v3 09-10-16 */
fmr0 = (wc->falc31) ? 0xb0 : 0xa0;
fmr0 = (is_octal(wc) || wc->falc31) ? 0xb0 : 0xa0;
} else {
line = "B8ZS";
fmr0 = 0xf0;
@@ -2817,7 +2809,7 @@ static void __t4_configure_e1(struct t4 *wc, int unit, int lineconfig)
if (lineconfig & DAHDI_CONFIG_AMI) {
line = "AMI";
/* workaround for errata #2 in ES v3 09-10-16 */
fmr0 = (wc->falc31) ? 0xb0 : 0xa0;
fmr0 = (is_octal(wc) || wc->falc31) ? 0xb0 : 0xa0;
} else {
line = "HDB3";
fmr0 = 0xf0;
@@ -3304,8 +3296,6 @@ static void t4_check_sigbits(struct t4 *wc, int span)
dev_notice(&wc->dev->dev, "Checking sigbits on span %d\n",
span + 1);
if (!(ts->span.flags & DAHDI_FLAG_RUNNING))
return;
if (E1 == ts->linemode) {
for (i = 0; i < 15; i++) {
a = t4_framer_in(wc, span, 0x71 + i);
@@ -3695,6 +3685,7 @@ static inline void t4_framer_interrupt(struct t4 *wc, int span)
struct t4_span *ts = wc->tspans[span];
struct dahdi_chan *sigchan;
unsigned long flags;
bool recheck_sigbits = false;
/* 1st gen cards isn't used interrupts */
@@ -3720,6 +3711,8 @@ static inline void t4_framer_interrupt(struct t4 *wc, int span)
ts->span.count.ebit += __t4_framer_in(wc, span, EBCL_T);
ts->span.count.be += __t4_framer_in(wc, span, BECL_T);
ts->span.count.prbs = __t4_framer_in(wc, span, FRS1_T);
if (DAHDI_RXSIG_INITIAL == ts->span.chans[0]->rxhooksig)
recheck_sigbits = true;
}
spin_unlock_irqrestore(&wc->reglock, flags);
@@ -3728,7 +3721,7 @@ static inline void t4_framer_interrupt(struct t4 *wc, int span)
ts->span.count.errsec += 1;
}
if (isr0)
if (isr0 & 0x08 || recheck_sigbits)
t4_check_sigbits(wc, span);
if (E1 == ts->linemode) {
@@ -4055,9 +4048,15 @@ static void t4_increase_latency(struct t4 *wc, int newlatency)
}
static void t4_isr_bh(unsigned long data)
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
static void t4_work_func(void *data)
{
struct t4 *wc = (struct t4 *)data;
struct t4 *wc = data;
#else
static void t4_work_func(struct work_struct *work)
{
struct t4 *wc = container_of(work, struct t4, bh_work);
#endif
if (test_bit(T4_CHANGE_LATENCY, &wc->checkflag)) {
if (wc->needed_latency != wc->numbufs) {
@@ -4264,7 +4263,7 @@ static irqreturn_t _t4_interrupt_gen2(int irq, void *dev_id)
out:
if (unlikely(test_bit(T4_CHANGE_LATENCY, &wc->checkflag) || test_bit(T4_CHECK_VPM, &wc->checkflag)))
tasklet_schedule(&wc->t4_tlet);
schedule_work(&wc->bh_work);
#ifndef ENABLE_WORKQUEUES
__t4_pci_out(wc, WC_INTR, 0);
@@ -5145,7 +5144,11 @@ static int __devinit t4_launch(struct t4 *wc)
&wc->ddev->spans);
}
tasklet_init(&wc->t4_tlet, t4_isr_bh, (unsigned long)wc);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
INIT_WORK(&wc->bh_work, t4_work_func, wc);
#else
INIT_WORK(&wc->bh_work, t4_work_func);
#endif
res = dahdi_register_device(wc->ddev, &wc->dev->dev);
if (res) {

View File

@@ -239,7 +239,7 @@ static void vpm450m_setecmode(struct vpm450m *vpm450m, int channel, int mode)
if (vpm450m->ecmode[channel] == mode)
return;
modify = kmalloc(sizeof(tOCT6100_CHANNEL_MODIFY), GFP_ATOMIC);
modify = kzalloc(sizeof(*modify), GFP_ATOMIC);
if (!modify) {
printk(KERN_NOTICE "wct4xxp: Unable to allocate memory for setec!\n");
return;
@@ -269,7 +269,7 @@ void vpm450m_setdtmf(struct vpm450m *vpm450m, int channel, int detect, int mute)
return;
}
modify = kmalloc(sizeof(tOCT6100_CHANNEL_MODIFY), GFP_KERNEL);
modify = kzalloc(sizeof(*modify), GFP_KERNEL);
if (!modify) {
printk(KERN_NOTICE "wct4xxp: Unable to allocate memory for setdtmf!\n");
return;
@@ -454,28 +454,27 @@ struct vpm450m *init_vpm450m(struct device *device, int *isalaw,
struct vpm450m *vpm450m;
int x,y,law;
if (!(vpm450m = kmalloc(sizeof(struct vpm450m), GFP_KERNEL)))
vpm450m = kzalloc(sizeof(*vpm450m), GFP_KERNEL);
if (!vpm450m)
return NULL;
memset(vpm450m, 0, sizeof(struct vpm450m));
vpm450m->context.dev = device;
vpm450m->context.ops = &wct4xxp_oct612x_ops;
if (!(ChipOpen = kmalloc(sizeof(tOCT6100_CHIP_OPEN), GFP_KERNEL))) {
ChipOpen = kzalloc(sizeof(*ChipOpen), GFP_KERNEL);
if (!ChipOpen) {
kfree(vpm450m);
kfree(vpm450m);
return NULL;
}
memset(ChipOpen, 0, sizeof(tOCT6100_CHIP_OPEN));
if (!(ChannelOpen = kmalloc(sizeof(tOCT6100_CHANNEL_OPEN), GFP_KERNEL))) {
ChannelOpen = kzalloc(sizeof(*ChannelOpen), GFP_KERNEL);
if (!ChannelOpen) {
kfree(vpm450m);
kfree(ChipOpen);
return NULL;
}
memset(ChannelOpen, 0, sizeof(tOCT6100_CHANNEL_OPEN));
for (x = 0; x < ARRAY_SIZE(vpm450m->ecmode); x++)
vpm450m->ecmode[x] = -1;

View File

@@ -131,13 +131,6 @@ struct t4_reg {
unsigned int val;
};
#define T4_CHECK_VPM 0
#define T4_LOADING_FW 1
#define T4_STOP_DMA 2
#define T4_CHECK_TIMING 3
#define T4_CHANGE_LATENCY 4
#define T4_IGNORE_LATENCY 5
#define WCT4_GET_REGS _IOW(DAHDI_CODE, 60, struct t4_regs)
#define WCT4_GET_REG _IOW(DAHDI_CODE, 61, struct t4_reg)
#define WCT4_SET_REG _IOW(DAHDI_CODE, 62, struct t4_reg)

File diff suppressed because it is too large Load Diff

View File

@@ -31,6 +31,7 @@
#include <linux/interrupt.h>
#include <linux/moduleparam.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <asm/io.h>
#include "proslic.h"
@@ -2143,7 +2144,7 @@ static int wctdm_ioctl(struct dahdi_chan *chan, unsigned int cmd, unsigned long
}
static int wctdm_open(struct dahdi_chan *chan)
static int _wctdm_open(struct dahdi_chan *chan)
{
struct wctdm *wc = chan->pvt;
if (!(wc->cardflag & (1 << (chan->chanpos - 1))))
@@ -2154,6 +2155,16 @@ static int wctdm_open(struct dahdi_chan *chan)
return 0;
}
static int wctdm_open(struct dahdi_chan *chan)
{
unsigned long flags;
int res;
spin_lock_irqsave(&chan->lock, flags);
res = _wctdm_open(chan);
spin_unlock_irqrestore(&chan->lock, flags);
return res;
}
static inline struct wctdm *wctdm_from_span(struct dahdi_span *span)
{
return container_of(span, struct wctdm, span);

View File

@@ -55,6 +55,7 @@ Tx Gain - W/Pre-Emphasis: -23.99 to 0.00 db
#include <asm/semaphore.h>
#endif
#include <linux/crc32.h>
#include <linux/slab.h>
#include <stdbool.h>

View File

@@ -25,6 +25,7 @@
#include <linux/ppp_defs.h>
#include <linux/delay.h>
#include <linux/sched.h>
#include <linux/slab.h>
#define FAST_HDLC_NEED_TABLES
#include <dahdi/kernel.h>

View File

@@ -31,6 +31,7 @@
#include <linux/pci.h>
#include <linux/spinlock.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <dahdi/kernel.h>
@@ -224,7 +225,7 @@ static inline void __select_control(struct t1 *wc)
}
}
static int t1xxp_open(struct dahdi_chan *chan)
static int _t1xxp_open(struct dahdi_chan *chan)
{
struct t1 *wc = chan->pvt;
if (wc->dead)
@@ -234,6 +235,16 @@ static int t1xxp_open(struct dahdi_chan *chan)
return 0;
}
static int t1xxp_open(struct dahdi_chan *chan)
{
unsigned long flags;
int res;
spin_lock_irqsave(&chan->lock, flags);
res = _t1xxp_open(chan);
spin_unlock_irqrestore(&chan->lock, flags);
return res;
}
static int __control_set_reg(struct t1 *wc, int reg, unsigned char val)
{
__select_control(wc);

View File

@@ -40,6 +40,7 @@
#include <linux/workqueue.h>
#include <linux/delay.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <stdbool.h>
#include <dahdi/kernel.h>

View File

@@ -73,7 +73,6 @@ enum linemode {
#define FALC_INT (1<<3)
struct t13x {
struct pci_dev *dev;
spinlock_t reglock;
u8 latency;
@@ -93,9 +92,10 @@ struct t13x {
unsigned long loopuptimer;
unsigned long loopdntimer;
const char *name;
#define INITIALIZED 1
#define SHUTDOWN 2
#define READY 3
#define INITIALIZED 1
#define SHUTDOWN 2
#define READY 3
#define HAVE_OPEN_CHANNELS 4
unsigned long bit_flags;
u32 ledstate;
struct dahdi_device *ddev;
@@ -110,6 +110,7 @@ struct t13x {
struct vpm450m *vpm;
struct mutex lock;
struct wcxb xb;
u32 lineconfig_fingerprint;
};
static void te13x_handle_transmit(struct wcxb *xb, void *vfp);
@@ -538,23 +539,23 @@ static struct vpm450m *init_vpm450m(struct t13x *wc, int isalaw,
vpm450m = kzalloc(sizeof(struct vpm450m), GFP_KERNEL);
if (!vpm450m) {
dev_info(&wc->dev->dev, "Unable to allocate vpm450m struct\n");
dev_info(&wc->xb.pdev->dev, "Unable to allocate vpm450m struct\n");
return NULL;
}
vpm450m->context.dev = &wc->dev->dev;
vpm450m->context.dev = &wc->xb.pdev->dev;
vpm450m->context.ops = &t13x_oct612x_ops;
ChipOpen = kzalloc(sizeof(tOCT6100_CHIP_OPEN), GFP_KERNEL);
if (!ChipOpen) {
dev_info(&wc->dev->dev, "Unable to allocate ChipOpen\n");
dev_info(&wc->xb.pdev->dev, "Unable to allocate ChipOpen\n");
kfree(vpm450m);
return NULL;
}
ChannelOpen = kzalloc(sizeof(tOCT6100_CHANNEL_OPEN), GFP_KERNEL);
if (!ChannelOpen) {
dev_info(&wc->dev->dev, "Unable to allocate ChannelOpen\n");
dev_info(&wc->xb.pdev->dev, "Unable to allocate ChannelOpen\n");
kfree(vpm450m);
kfree(ChipOpen);
return NULL;
@@ -563,7 +564,7 @@ static struct vpm450m *init_vpm450m(struct t13x *wc, int isalaw,
for (x = 0; x < ARRAY_SIZE(vpm450m->ecmode); x++)
vpm450m->ecmode[x] = -1;
dev_info(&wc->dev->dev, "Echo cancellation for %d channels\n",
dev_info(&wc->xb.pdev->dev, "Echo cancellation for %d channels\n",
ECHOCAN_NUM_CHANS);
Oct6100ChipOpenDef(ChipOpen);
@@ -625,14 +626,14 @@ static struct vpm450m *init_vpm450m(struct t13x *wc, int isalaw,
/* Get the size of the OCT6100 instance structure. */
ulResult = Oct6100GetInstanceSize(ChipOpen, &InstanceSize);
if (ulResult != cOCT6100_ERR_OK) {
dev_info(&wc->dev->dev, "Unable to get instance size: %x\n",
dev_info(&wc->xb.pdev->dev, "Unable to get instance size: %x\n",
ulResult);
return NULL;
}
vpm450m->pApiInstance = vmalloc(InstanceSize.ulApiInstanceSize);
if (!vpm450m->pApiInstance) {
dev_info(&wc->dev->dev,
dev_info(&wc->xb.pdev->dev,
"Out of memory (can't allocate %d bytes)!\n",
InstanceSize.ulApiInstanceSize);
return NULL;
@@ -642,7 +643,7 @@ static struct vpm450m *init_vpm450m(struct t13x *wc, int isalaw,
oct_enable_dram(wc);
ulResult = Oct6100ChipOpen(vpm450m->pApiInstance, ChipOpen);
if (ulResult != cOCT6100_ERR_OK) {
dev_info(&wc->dev->dev, "Unable to Oct6100ChipOpen: %x\n",
dev_info(&wc->xb.pdev->dev, "Unable to Oct6100ChipOpen: %x\n",
ulResult);
return NULL;
}
@@ -652,7 +653,7 @@ static struct vpm450m *init_vpm450m(struct t13x *wc, int isalaw,
for (i = 0; i < ECHOCAN_NUM_CHANS; i++) {
ulResult = echocan_initialize_channel(vpm450m, i, isalaw);
if (0 != ulResult) {
dev_info(&wc->dev->dev,
dev_info(&wc->xb.pdev->dev,
"Unable to echocan_initialize_channel: %x\n",
ulResult);
return NULL;
@@ -714,7 +715,7 @@ static int t13x_echocan_create(struct dahdi_chan *chan,
features = &vpm_ec_features;
if (ecp->param_count > 0) {
dev_warn(&wc->dev->dev, "%s echo canceller does not support parameters; failing request\n",
dev_warn(&wc->xb.pdev->dev, "%s echo canceller does not support parameters; failing request\n",
chan->ec_factory->get_name(chan));
return -EINVAL;
}
@@ -752,14 +753,14 @@ static void t13x_vpm_init(struct t13x *wc)
#endif
if (!vpmsupport) {
dev_info(&wc->dev->dev, "VPM450: Support Disabled\n");
dev_info(&wc->xb.pdev->dev, "VPM450: Support Disabled\n");
return;
}
#if defined(HOTPLUG_FIRMWARE)
if ((request_firmware(&firmware, oct032_firmware, &wc->dev->dev) != 0)
|| !firmware) {
dev_notice(&wc->dev->dev, "VPM450: firmware %s not available from userspace\n",
if ((request_firmware(&firmware, oct032_firmware,
&wc->xb.pdev->dev) != 0) || !firmware) {
dev_notice(&wc->xb.pdev->dev, "VPM450: firmware %s not available from userspace\n",
oct032_firmware);
return;
}
@@ -778,7 +779,7 @@ static void t13x_vpm_init(struct t13x *wc)
wc->vpm = init_vpm450m(wc, companding, firmware);
if (!wc->vpm) {
dev_notice(&wc->dev->dev, "VPM450: Failed to initialize\n");
dev_notice(&wc->xb.pdev->dev, "VPM450: Failed to initialize\n");
if (firmware != &embedded_firmware)
release_firmware(firmware);
return;
@@ -787,7 +788,7 @@ static void t13x_vpm_init(struct t13x *wc)
if (firmware != &embedded_firmware)
release_firmware(firmware);
dev_info(&wc->dev->dev,
dev_info(&wc->xb.pdev->dev,
"VPM450: Present and operational servicing %d span\n", 1);
}
@@ -1138,7 +1139,7 @@ static void t13x_configure_t1(struct t13x *wc, int lineconfig, int txlevel)
__t13x_framer_set(wc, 0x18, 0x3f); /* IMR4: Slips on transmit */
spin_unlock_irqrestore(&wc->reglock, flags);
dev_info(&wc->dev->dev, "Span configured for %s/%s\n", framing, line);
dev_info(&wc->xb.pdev->dev, "Span configured for %s/%s\n", framing, line);
}
static void t13x_configure_e1(struct t13x *wc, int lineconfig)
@@ -1237,7 +1238,7 @@ static void t13x_configure_e1(struct t13x *wc, int lineconfig)
transmit */
spin_unlock_irqrestore(&wc->reglock, flags);
dev_info(&wc->dev->dev,
dev_info(&wc->xb.pdev->dev,
"Span configured for %s/%s%s\n", framing, line, crc4);
}
@@ -1275,7 +1276,7 @@ static int te13xp_check_for_interrupts(struct t13x *wc)
spin_unlock_irqrestore(&wc->reglock, flags);
if (time_after(jiffies, stop_time)) {
wc->span.alarms = DAHDI_ALARM_RED;
dev_err(&wc->dev->dev, "Interrupts not detected.\n");
dev_err(&wc->xb.pdev->dev, "Interrupts not detected.\n");
return -EIO;
}
msleep(100);
@@ -1286,6 +1287,18 @@ static int te13xp_check_for_interrupts(struct t13x *wc)
return 0;
}
static bool have_open_channels(const struct t13x *wc)
{
int x, j;
for (x = 0, j = 0; x < wc->span.channels; x++) {
const struct dahdi_chan *chan = wc->span.chans[x];
if (test_bit(DAHDI_FLAGBIT_OPEN, &chan->flags) ||
dahdi_have_netdev(chan))
return true;
}
return false;
}
static int t13x_startup(struct file *file, struct dahdi_span *span)
{
struct t13x *wc = container_of(span, struct t13x, span);
@@ -1296,7 +1309,7 @@ static int t13x_startup(struct file *file, struct dahdi_span *span)
wcxb_stop_dma(&wc->xb);
ret = wcxb_wait_for_stop(&wc->xb, 50);
if (ret) {
dev_err(&wc->dev->dev, "Timeout waiting for DMA to stop.\n");
dev_err(&wc->xb.pdev->dev, "Timeout waiting for DMA to stop.\n");
return ret;
}
@@ -1313,9 +1326,15 @@ static int t13x_startup(struct file *file, struct dahdi_span *span)
if (ret)
return ret;
dev_info(&wc->dev->dev,
dev_info(&wc->xb.pdev->dev,
"Calling startup (flags is %lu)\n", span->flags);
/* Check for "open channels" here in case some channels have netdev. */
if (have_open_channels(wc))
clear_bit(HAVE_OPEN_CHANNELS, &wc->bit_flags);
else
set_bit(HAVE_OPEN_CHANNELS, &wc->bit_flags);
/* Get this party started */
local_irq_save(flags);
t13x_check_alarms(wc);
@@ -1474,11 +1493,11 @@ static int t13x_maint(struct dahdi_span *span, int cmd)
switch (cmd) {
case DAHDI_MAINT_NONE:
dev_info(&wc->dev->dev, "Clearing all maint modes\n");
dev_info(&wc->xb.pdev->dev, "Clearing all maint modes\n");
t13x_clear_maint(span);
break;
case DAHDI_MAINT_LOCALLOOP:
dev_info(&wc->dev->dev, "Turning on local loopback\n");
dev_info(&wc->xb.pdev->dev, "Turning on local loopback\n");
t13x_clear_maint(span);
spin_lock_irqsave(&wc->reglock, flags);
reg = __t13x_framer_get(wc, LIM0);
@@ -1486,7 +1505,7 @@ static int t13x_maint(struct dahdi_span *span, int cmd)
spin_unlock_irqrestore(&wc->reglock, flags);
break;
case DAHDI_MAINT_NETWORKLINELOOP:
dev_info(&wc->dev->dev,
dev_info(&wc->xb.pdev->dev,
"Turning on network line loopback\n");
t13x_clear_maint(span);
spin_lock_irqsave(&wc->reglock, flags);
@@ -1495,7 +1514,7 @@ static int t13x_maint(struct dahdi_span *span, int cmd)
spin_unlock_irqrestore(&wc->reglock, flags);
break;
case DAHDI_MAINT_NETWORKPAYLOADLOOP:
dev_info(&wc->dev->dev,
dev_info(&wc->xb.pdev->dev,
"Turning on network payload loopback\n");
t13x_clear_maint(span);
spin_lock_irqsave(&wc->reglock, flags);
@@ -1504,7 +1523,7 @@ static int t13x_maint(struct dahdi_span *span, int cmd)
spin_unlock_irqrestore(&wc->reglock, flags);
break;
case DAHDI_MAINT_LOOPUP:
dev_info(&wc->dev->dev, "Transmitting loopup code\n");
dev_info(&wc->xb.pdev->dev, "Transmitting loopup code\n");
t13x_clear_maint(span);
if (dahdi_is_e1_span(&wc->span)) {
spin_lock_irqsave(&wc->reglock, flags);
@@ -1519,7 +1538,7 @@ static int t13x_maint(struct dahdi_span *span, int cmd)
}
break;
case DAHDI_MAINT_LOOPDOWN:
dev_info(&wc->dev->dev, "Transmitting loopdown code\n");
dev_info(&wc->xb.pdev->dev, "Transmitting loopdown code\n");
t13x_clear_maint(span);
if (dahdi_is_e1_span(&wc->span)) {
spin_lock_irqsave(&wc->reglock, flags);
@@ -1555,7 +1574,7 @@ static int t13x_maint(struct dahdi_span *span, int cmd)
t13x_reset_counters(span);
break;
default:
dev_info(&wc->dev->dev,
dev_info(&wc->xb.pdev->dev,
"Unknown maint command: %d\n", cmd);
return -ENOSYS;
}
@@ -1657,12 +1676,37 @@ static void t13x_chan_set_sigcap(struct dahdi_span *span, int x)
}
}
static bool t13x_lineconfig_changed(struct t13x *wc,
const struct dahdi_lineconfig *lc)
{
unsigned long flags;
bool result;
u32 crc = crc32(~0, lc, sizeof(*lc));
spin_lock_irqsave(&wc->reglock, flags);
result = (crc != wc->lineconfig_fingerprint);
spin_unlock_irqrestore(&wc->reglock, flags);
return result;
}
static void t13x_save_lineconfig(struct t13x *wc,
const struct dahdi_lineconfig *lc)
{
unsigned long flags;
u32 crc = crc32(~0, lc, sizeof(*lc));
spin_lock_irqsave(&wc->reglock, flags);
wc->lineconfig_fingerprint = crc;
spin_unlock_irqrestore(&wc->reglock, flags);
}
static int
t13x_spanconfig(struct file *file, struct dahdi_span *span,
struct dahdi_lineconfig *lc)
{
struct t13x *wc = container_of(span, struct t13x, span);
int i;
int res = 0;
if (file->f_flags & O_NONBLOCK)
return -EAGAIN;
@@ -1675,10 +1719,13 @@ t13x_spanconfig(struct file *file, struct dahdi_span *span,
t13x_chan_set_sigcap(span, i);
/* If already running, apply changes immediately */
if (test_bit(DAHDI_FLAGBIT_RUNNING, &span->flags))
return t13x_startup(file, span);
return 0;
if (test_bit(DAHDI_FLAGBIT_RUNNING, &span->flags) &&
t13x_lineconfig_changed(wc, lc)) {
res = t13x_startup(file, span);
if (!res)
t13x_save_lineconfig(wc, lc);
}
return res;
}
/**
@@ -1748,7 +1795,7 @@ static int t13x_software_init(struct t13x *wc, enum linemode type)
spin_unlock_irqrestore(&wc->reglock, flags);
dev_info(&wc->dev->dev, "Setting up global serial parameters for %s\n",
dev_info(&wc->xb.pdev->dev, "Setting up global serial parameters for %s\n",
dahdi_spantype2str(wc->span.spantype));
t13x_serial_setup(wc);
@@ -1798,7 +1845,6 @@ static int t13x_set_linemode(struct dahdi_span *span, enum spantypes linemode)
clear_bit(INITIALIZED, &wc->bit_flags);
disable_irq(wc->xb.pdev->irq);
synchronize_irq(wc->dev->irq);
smp_mb__after_clear_bit();
del_timer_sync(&wc->timer);
flush_workqueue(wc->wq);
@@ -1808,24 +1854,24 @@ static int t13x_set_linemode(struct dahdi_span *span, enum spantypes linemode)
switch (linemode) {
case SPANTYPE_DIGITAL_T1:
dev_info(&wc->dev->dev,
dev_info(&wc->xb.pdev->dev,
"Changing from %s to T1 line mode.\n",
dahdi_spantype2str(wc->span.spantype));
res = t13x_software_init(wc, T1);
break;
case SPANTYPE_DIGITAL_E1:
dev_info(&wc->dev->dev,
dev_info(&wc->xb.pdev->dev,
"Changing from %s to E1 line mode.\n",
dahdi_spantype2str(wc->span.spantype));
res = t13x_software_init(wc, E1);
break;
case SPANTYPE_DIGITAL_J1:
dev_info(&wc->dev->dev,
dev_info(&wc->xb.pdev->dev,
"Changing from %s to E1 line mode.\n",
dahdi_spantype2str(wc->span.spantype));
res = t13x_software_init(wc, J1);
default:
dev_err(&wc->dev->dev,
dev_err(&wc->xb.pdev->dev,
"Got invalid linemode '%s' from dahdi\n",
dahdi_spantype2str(linemode));
res = -EINVAL;
@@ -1858,14 +1904,14 @@ static int t13x_hardware_post_init(struct t13x *wc, enum linemode *type)
} else if (!strcasecmp(default_linemode, "j1")) {
*type = J1;
} else {
dev_warn(&wc->dev->dev,
dev_warn(&wc->xb.pdev->dev,
"'%s' is an unknown linemode. Defaulting to 't1'\n",
default_linemode);
*type = T1;
}
if (debug) {
dev_info(&wc->dev->dev, "linemode: %s\n",
dev_info(&wc->xb.pdev->dev, "linemode: %s\n",
(*type == T1) ? "T1" : ((J1 == *type) ? "J1" : "E1"));
}
@@ -1873,23 +1919,23 @@ static int t13x_hardware_post_init(struct t13x *wc, enum linemode *type)
wcxb_gpio_set(&wc->xb, FALC_CPU_RESET);
reg = t13x_framer_get(wc, 0x4a);
if (reg < 0) {
dev_info(&wc->dev->dev,
dev_info(&wc->xb.pdev->dev,
"Failed to read FALC version (%x)\n", reg);
return -EIO;
}
dev_info(&wc->dev->dev, "FALC version: %1x\n", reg);
dev_info(&wc->xb.pdev->dev, "FALC version: %1x\n", reg);
/* make sure reads and writes work */
for (x = 0; x < 256; x++) {
t13x_framer_set(wc, 0x14, x);
reg = t13x_framer_get(wc, 0x14);
if (reg < 0) {
dev_info(&wc->dev->dev,
dev_info(&wc->xb.pdev->dev,
"Failed register read (%d)\n", reg);
return -EIO;
}
if (reg != x) {
dev_info(&wc->dev->dev,
dev_info(&wc->xb.pdev->dev,
"Register test failed. Wrote '%x' but read '%x'\n",
x, reg);
return -EIO;
@@ -1906,7 +1952,6 @@ static void t13x_check_alarms(struct t13x *wc)
{
unsigned char c, d;
int alarms;
int x, j;
if (!(test_bit(DAHDI_FLAGBIT_RUNNING, &wc->span.flags)))
return;
@@ -1928,7 +1973,7 @@ static void t13x_check_alarms(struct t13x *wc)
/* LIM0: Force RAI High */
__t13x_framer_set(wc, 0x20, 0x9f | 0x20);
wc->flags.nmf = 1;
dev_info(&wc->dev->dev, "NMF workaround on!\n");
dev_info(&wc->xb.pdev->dev, "NMF workaround on!\n");
}
__t13x_framer_set(wc, 0x1e, 0xc3); /* Reset to CRC4 mode */
__t13x_framer_set(wc, 0x1c, 0xf2); /* Force Resync */
@@ -1938,18 +1983,14 @@ static void t13x_check_alarms(struct t13x *wc)
/* LIM0: Clear forced RAI */
__t13x_framer_set(wc, 0x20, 0x9f);
wc->flags.nmf = 0;
dev_info(&wc->dev->dev,
dev_info(&wc->xb.pdev->dev,
"NMF workaround off!\n");
}
}
}
if (wc->span.lineconfig & DAHDI_CONFIG_NOTOPEN) {
for (x = 0, j = 0; x < wc->span.channels; x++)
if ((wc->span.chans[x]->flags & DAHDI_FLAG_OPEN) ||
dahdi_have_netdev(wc->span.chans[x]))
j++;
if (!j)
if (!test_bit(HAVE_OPEN_CHANNELS, &wc->bit_flags))
alarms |= DAHDI_ALARM_NOTOPEN;
else
alarms &= ~DAHDI_ALARM_NOTOPEN;
@@ -2047,31 +2088,31 @@ static void t13x_debounce_alarms(struct t13x *wc)
if (wc->lofalarmtimer && time_after(jiffies, wc->lofalarmtimer)) {
alarms |= DAHDI_ALARM_RED;
wc->lofalarmtimer = 0;
dev_info(&wc->dev->dev, "LOF alarm detected\n");
dev_info(&wc->xb.pdev->dev, "LOF alarm detected\n");
}
if (wc->losalarmtimer && time_after(jiffies, wc->losalarmtimer)) {
alarms |= DAHDI_ALARM_RED;
wc->losalarmtimer = 0;
dev_info(&wc->dev->dev, "LOS alarm detected\n");
dev_info(&wc->xb.pdev->dev, "LOS alarm detected\n");
}
if (wc->aisalarmtimer && time_after(jiffies, wc->aisalarmtimer)) {
alarms |= DAHDI_ALARM_BLUE;
wc->aisalarmtimer = 0;
dev_info(&wc->dev->dev, "AIS alarm detected\n");
dev_info(&wc->xb.pdev->dev, "AIS alarm detected\n");
}
if (wc->yelalarmtimer && time_after(jiffies, wc->yelalarmtimer)) {
alarms |= DAHDI_ALARM_YELLOW;
wc->yelalarmtimer = 0;
dev_info(&wc->dev->dev, "YEL alarm detected\n");
dev_info(&wc->xb.pdev->dev, "YEL alarm detected\n");
}
if (wc->recoverytimer && time_after(jiffies, wc->recoverytimer)) {
alarms &= ~(DAHDI_ALARM_RECOVER);
wc->recoverytimer = 0;
dev_info(&wc->dev->dev, "Alarms cleared\n");
dev_info(&wc->xb.pdev->dev, "Alarms cleared\n");
}
if (alarms != wc->span.alarms) {
@@ -2085,7 +2126,7 @@ static void t13x_debounce_alarms(struct t13x *wc)
if (alarms & (DAHDI_ALARM_RED|DAHDI_ALARM_BLUE|
DAHDI_ALARM_NOTOPEN|DAHDI_ALARM_RECOVER)) {
if (!wc->flags.sendingyellow) {
dev_info(&wc->dev->dev, "Setting yellow alarm\n");
dev_info(&wc->xb.pdev->dev, "Setting yellow alarm\n");
/* We manually do yellow alarm to handle RECOVER
* and NOTOPEN, otherwise it's auto anyway */
fmr4 = __t13x_framer_get(wc, 0x20);
@@ -2094,7 +2135,7 @@ static void t13x_debounce_alarms(struct t13x *wc)
}
} else {
if (wc->flags.sendingyellow) {
dev_info(&wc->dev->dev, "Clearing yellow alarm\n");
dev_info(&wc->xb.pdev->dev, "Clearing yellow alarm\n");
/* We manually do yellow alarm to handle RECOVER */
fmr4 = __t13x_framer_get(wc, 0x20);
__t13x_framer_set(wc, 0x20, fmr4 & ~0x20);
@@ -2112,7 +2153,7 @@ static void t13x_debounce_loopcodes(struct t13x *wc)
spin_lock_irqsave(&wc->reglock, flags);
if (wc->loopuptimer && time_after(jiffies, wc->loopuptimer)) {
/* Loop-up code debounced */
dev_info(&wc->dev->dev, "Loopup detected, enabling remote loop\n");
dev_info(&wc->xb.pdev->dev, "Loopup detected, enabling remote loop\n");
__t13x_framer_set(wc, 0x36, 0x08); /* LIM0: Disable
any local loop */
__t13x_framer_set(wc, 0x37, 0xf6); /* LIM1: Enable
@@ -2126,7 +2167,7 @@ static void t13x_debounce_loopcodes(struct t13x *wc)
if (wc->loopdntimer && time_after(jiffies, wc->loopdntimer)) {
/* Loop-down code debounced */
dev_info(&wc->dev->dev, "Loopdown detected, disabling remote loop\n");
dev_info(&wc->xb.pdev->dev, "Loopdown detected, disabling remote loop\n");
__t13x_framer_set(wc, 0x36, 0x08); /* LIM0: Disable
any local loop */
__t13x_framer_set(wc, 0x37, 0xf0); /* LIM1: Disable
@@ -2238,7 +2279,8 @@ static void timer_work_func(struct work_struct *work)
static int work_count;
if (debug)
dev_notice(&wc->dev->dev, "Timer work: %d!\n", ++work_count);
dev_notice(&wc->xb.pdev->dev, "Timer work: %d!\n",
++work_count);
t13x_debounce_alarms(wc);
if (!dahdi_is_e1_span(&wc->span))
@@ -2270,7 +2312,7 @@ static void handle_falc_int(struct t13x *wc)
isr4 = (gis & FRMR_GIS_ISR4) ? __t13x_framer_get(wc, FRMR_ISR4) : 0;
if ((debug) && !(isr3 & ISR3_SEC)) {
dev_info(&wc->dev->dev, "gis: %02x, isr0: %02x, isr1: %02x, "\
dev_info(&wc->xb.pdev->dev, "gis: %02x, isr0: %02x, isr1: %02x, "\
"isr2: %02x, isr3: %02x, isr4: %02x, intcount=%u\n",
gis, isr0, isr1, isr2, isr3, isr4, intcount);
}
@@ -2349,6 +2391,41 @@ static void te13xp_timer(unsigned long data)
static inline void create_sysfs_files(struct t13x *wc) { return; }
static inline void remove_sysfs_files(struct t13x *wc) { return; }
static int t13x_open(struct dahdi_chan *chan)
{
struct t13x *wc = chan->pvt;
unsigned long flags;
if (!(wc->span.lineconfig & DAHDI_CONFIG_NOTOPEN))
return 0;
if (!test_and_set_bit(HAVE_OPEN_CHANNELS, &wc->bit_flags)) {
local_irq_save(flags);
t13x_check_alarms(wc);
local_irq_restore(flags);
}
return 0;
}
static int t13x_close(struct dahdi_chan *chan)
{
struct t13x *wc = chan->pvt;
unsigned long flags;
if (!(wc->span.lineconfig & DAHDI_CONFIG_NOTOPEN))
return 0;
if (!have_open_channels(wc)) {
if (test_and_clear_bit(HAVE_OPEN_CHANNELS, &wc->bit_flags)) {
local_irq_save(flags);
t13x_check_alarms(wc);
local_irq_restore(flags);
}
}
return 0;
}
static const struct dahdi_span_ops t13x_span_ops = {
.owner = THIS_MODULE,
.spanconfig = t13x_spanconfig,
@@ -2360,6 +2437,8 @@ static const struct dahdi_span_ops t13x_span_ops = {
.set_spantype = t13x_set_linemode,
.echocan_create = t13x_echocan_create,
.echocan_name = t13x_echocan_name,
.open = t13x_open,
.close = t13x_close,
};
#define SPI_BASE 0x200
@@ -2485,7 +2564,6 @@ static int __devinit te13xp_init_one(struct pci_dev *pdev,
return -ENOMEM;
}
wc->dev = pdev;
wc->devtype = d;
dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
@@ -2544,7 +2622,7 @@ static int __devinit te13xp_init_one(struct pci_dev *pdev,
wc->ddev->hardware_id = t13x_read_serial(wc);
if (!wc->ddev->hardware_id) {
dev_info(&wc->dev->dev, "No serial number found.\n");
dev_info(&wc->xb.pdev->dev, "No serial number found.\n");
res = -EIO;
goto fail_exit;
}
@@ -2566,11 +2644,11 @@ static int __devinit te13xp_init_one(struct pci_dev *pdev,
if (latency > 0 && latency < DRING_SIZE) {
wcxb_set_minlatency(&wc->xb, latency);
if (WCXB_DEFAULT_LATENCY != latency)
dev_info(&wc->dev->dev,
dev_info(&wc->xb.pdev->dev,
"latency manually overridden to %d\n",
latency);
} else {
dev_info(&wc->dev->dev,
dev_info(&wc->xb.pdev->dev,
"latency module parameter must be between 1 and %d\n",
DRING_SIZE);
res = -EPERM;
@@ -2608,9 +2686,9 @@ static int __devinit te13xp_init_one(struct pci_dev *pdev,
/* Span is in red alarm by default */
wc->span.alarms = DAHDI_ALARM_NONE;
res = dahdi_register_device(wc->ddev, &wc->dev->dev);
res = dahdi_register_device(wc->ddev, &wc->xb.pdev->dev);
if (res) {
dev_info(&wc->dev->dev, "Unable to register with DAHDI\n");
dev_info(&wc->xb.pdev->dev, "Unable to register with DAHDI\n");
goto fail_exit;
}
@@ -2618,10 +2696,10 @@ static int __devinit te13xp_init_one(struct pci_dev *pdev,
mod_timer(&wc->timer, jiffies + HZ/5);
if (wc->ddev->hardware_id) {
dev_info(&wc->dev->dev, "Found a %s (SN: %s)\n",
dev_info(&wc->xb.pdev->dev, "Found a %s (SN: %s)\n",
wc->devtype->name, wc->ddev->hardware_id);
} else {
dev_info(&wc->dev->dev, "Found a %s\n",
dev_info(&wc->xb.pdev->dev, "Found a %s\n",
wc->devtype->name);
}
@@ -2638,7 +2716,7 @@ fail_exit:
static void __devexit te13xp_remove_one(struct pci_dev *pdev)
{
struct t13x *wc = pci_get_drvdata(pdev);
dev_info(&wc->dev->dev, "Removing a Wildcard TE13xP.\n");
dev_info(&wc->xb.pdev->dev, "Removing a Wildcard TE13xP.\n");
if (!wc)
return;
@@ -2679,7 +2757,7 @@ static DEFINE_PCI_DEVICE_TABLE(te13xp_pci_tbl) = {
static void te13xp_shutdown(struct pci_dev *pdev)
{
struct t13x *wc = pci_get_drvdata(pdev);
dev_info(&wc->dev->dev, "Quiescing a Wildcard TE13xP.\n");
dev_info(&wc->xb.pdev->dev, "Quiescing a Wildcard TE13xP.\n");
if (!wc)
return;

View File

@@ -34,8 +34,8 @@
#include <linux/delay.h>
#include <linux/sched.h>
#include <linux/crc32.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/string.h>
#include <linux/time.h>
@@ -51,6 +51,19 @@
#include "wcxb_spi.h"
#include "wcxb_flash.h"
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
# ifdef RHEL_RELEASE_VERSION
# if RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(5, 6)
# define T43X_HAVE_CANCEL_WORK_SYNC
# endif
# else
static inline int delayed_work_pending(struct work_struct *work)
{
return test_bit(0, &work->pending);
}
# endif
#endif
static const char *TE435_FW_FILENAME = "dahdi-fw-te435.bin";
static const u32 TE435_VERSION = 0xe0019;
@@ -78,10 +91,10 @@ struct t43x;
struct t43x_span {
struct t43x *owner;
struct dahdi_span span;
struct {
unsigned int nmf:1;
unsigned int sendingyellow:1;
} flags;
#define NMF_FLAGBIT 1
#define SENDINGYELLOW_FLAGBIT 2
#define HAVE_OPEN_CHANNELS_FLAGBIT 3
unsigned long bit_flags;
unsigned char txsigs[16]; /* Copy of tx sig registers */
unsigned long lofalarmtimer;
unsigned long losalarmtimer;
@@ -97,6 +110,7 @@ struct t43x_span {
bool debounce;
int syncpos;
int sync;
u32 lineconfig_fingerprint;
};
struct t43x_clksrc_work {
@@ -1210,7 +1224,7 @@ static void t43x_clksrc_work_fn(struct work_struct *data)
* @mode: The clock mode that we would like to move to.
* @master: If true, drive the clock on the timing header.
*
* The clock srouce cannot be changed while DMA is active, so this function
* The clock source cannot be changed while DMA is active, so this function
* will stop the DMA, then queue a delayed work item in order to come back and
* check that DMA was actually stopped before changing the source of the clock.
*
@@ -1707,10 +1721,21 @@ static void t43x_configure_e1(struct t43x *wc, int span_idx, int lineconfig)
framing, line, crc4);
}
static bool have_open_channels(const struct t43x_span *ts)
{
int x, j;
for (x = 0, j = 0; x < ts->span.channels; x++) {
const struct dahdi_chan *chan = ts->span.chans[x];
if (test_bit(DAHDI_FLAGBIT_OPEN, &chan->flags) ||
dahdi_have_netdev(chan))
return true;
}
return false;
}
static void t43x_framer_start(struct t43x *wc)
{
int unit;
struct t43x_span *ts;
unsigned long flags;
int res;
@@ -1727,7 +1752,7 @@ static void t43x_framer_start(struct t43x *wc)
dev_warn(&wc->xb.pdev->dev, "DMA engine did not stop.\n");
for (unit = 0; unit < wc->numspans; unit++) {
ts = wc->tspans[unit];
struct t43x_span *ts = wc->tspans[unit];
if (dahdi_is_e1_span(&ts->span)) {
t43x_configure_e1(wc, unit, ts->span.lineconfig);
} else { /* is a T1 card */
@@ -1741,6 +1766,15 @@ static void t43x_framer_start(struct t43x *wc)
for (unit = 0; unit < wc->numspans; unit++) {
/* Get this party started */
struct t43x_span *ts = wc->tspans[unit];
/* Check for "open channels" here in case some channels have
* netdev. */
if (have_open_channels(ts))
clear_bit(HAVE_OPEN_CHANNELS_FLAGBIT, &ts->bit_flags);
else
set_bit(HAVE_OPEN_CHANNELS_FLAGBIT, &ts->bit_flags);
local_irq_save(flags);
t43x_check_alarms(wc, unit);
t43x_check_sigbits(wc, unit);
@@ -1762,7 +1796,7 @@ static void t43x_framer_start(struct t43x *wc)
/* Clear all counters */
for (unit = 0; unit < wc->numspans; unit++) {
ts = wc->tspans[unit];
struct t43x_span *ts = wc->tspans[unit];
memset(&ts->span.count, 0, sizeof(ts->span.count));
}
@@ -2344,6 +2378,30 @@ static void t43x_chan_set_sigcap(struct dahdi_span *span, int x)
}
}
static bool t43x_lineconfig_changed(struct t43x_span *ts,
const struct dahdi_lineconfig *lc)
{
unsigned long flags;
bool result;
u32 crc = crc32(~0, lc, sizeof(*lc));
spin_lock_irqsave(&ts->owner->reglock, flags);
result = (crc != ts->lineconfig_fingerprint);
spin_unlock_irqrestore(&ts->owner->reglock, flags);
return result;
}
static void t43x_save_lineconfig(struct t43x_span *ts,
const struct dahdi_lineconfig *lc)
{
unsigned long flags;
u32 crc = crc32(~0, lc, sizeof(*lc));
spin_lock_irqsave(&ts->owner->reglock, flags);
ts->lineconfig_fingerprint = crc;
spin_unlock_irqrestore(&ts->owner->reglock, flags);
}
static int
t43x_spanconfig(struct file *file, struct dahdi_span *span,
struct dahdi_lineconfig *lc)
@@ -2351,6 +2409,7 @@ t43x_spanconfig(struct file *file, struct dahdi_span *span,
struct t43x_span *ts = container_of(span, struct t43x_span, span);
struct t43x *wc = ts->owner;
int i;
int res = 0;
if (debug)
dev_info(&wc->xb.pdev->dev, "%s\n", __func__);
@@ -2387,10 +2446,13 @@ t43x_spanconfig(struct file *file, struct dahdi_span *span,
t43x_chan_set_sigcap(span, i);
/* If already running, apply changes immediately */
if (test_bit(DAHDI_FLAGBIT_RUNNING, &span->flags))
return t43x_startup(file, span);
return 0;
if (test_bit(DAHDI_FLAGBIT_RUNNING, &span->flags) &&
t43x_lineconfig_changed(ts, lc)) {
res = t43x_startup(file, span);
if (!res)
t43x_save_lineconfig(ts, lc);
}
return res;
}
/*
@@ -2454,6 +2516,7 @@ t43x_init_one_span(struct t43x *wc, struct t43x_span *ts, enum linemode type)
default:
spin_unlock_irqrestore(&wc->reglock, flags);
res = -EINVAL;
enable_irq(wc->xb.pdev->irq);
goto error_exit;
}
@@ -2476,7 +2539,6 @@ t43x_init_one_span(struct t43x *wc, struct t43x_span *ts, enum linemode type)
return 0;
error_exit:
enable_irq(wc->xb.pdev->irq);
for (x = 0; x < ARRAY_SIZE(chans); ++x) {
kfree(chans[x]);
@@ -2645,7 +2707,6 @@ static void t43x_check_alarms(struct t43x *wc, int span_idx)
struct t43x_span *ts = wc->tspans[span_idx];
unsigned char c, d;
int alarms;
int x, j;
int fidx = (wc->numspans == 2) ? span_idx+1 : span_idx;
if (!(test_bit(DAHDI_FLAGBIT_RUNNING, &ts->span.flags)))
@@ -2664,10 +2725,9 @@ static void t43x_check_alarms(struct t43x *wc, int span_idx)
/* No multiframe found, force RAI high after 400ms only
* if we haven't found a multiframe since last loss of
* frame */
if (!ts->flags.nmf) {
if (!test_and_set_bit(NMF_FLAGBIT, &ts->bit_flags)) {
/* LIM0: Force RAI High */
__t43x_framer_set(wc, fidx, 0x20, 0x9f | 0x20);
ts->flags.nmf = 1;
dev_info(&wc->xb.pdev->dev,
"NMF workaround on!\n");
}
@@ -2678,10 +2738,9 @@ static void t43x_check_alarms(struct t43x *wc, int span_idx)
/* Force Resync */
__t43x_framer_set(wc, fidx, 0x1c, 0xf0);
} else if (!(c & 0x02)) {
if (ts->flags.nmf) {
if (test_and_clear_bit(NMF_FLAGBIT, &ts->bit_flags)) {
/* LIM0: Clear forced RAI */
__t43x_framer_set(wc, fidx, 0x20, 0x9f);
ts->flags.nmf = 0;
dev_info(&wc->xb.pdev->dev,
"NMF workaround off!\n");
}
@@ -2689,11 +2748,7 @@ static void t43x_check_alarms(struct t43x *wc, int span_idx)
}
if (ts->span.lineconfig & DAHDI_CONFIG_NOTOPEN) {
for (x = 0, j = 0; x < ts->span.channels; x++)
if ((ts->chans[x]->flags & DAHDI_FLAG_OPEN) ||
dahdi_have_netdev(ts->chans[x]))
j++;
if (!j)
if (!test_bit(HAVE_OPEN_CHANNELS_FLAGBIT, &ts->bit_flags))
alarms |= DAHDI_ALARM_NOTOPEN;
else
alarms &= ~DAHDI_ALARM_NOTOPEN;
@@ -2855,21 +2910,19 @@ static void t43x_debounce_alarms(struct t43x *wc, int span_idx)
/* If receiving alarms (except Yellow), go into Yellow alarm state */
if (alarms & (DAHDI_ALARM_RED|DAHDI_ALARM_BLUE|
DAHDI_ALARM_NOTOPEN|DAHDI_ALARM_RECOVER)) {
if (!ts->flags.sendingyellow) {
if (!test_and_set_bit(SENDINGYELLOW_FLAGBIT, &ts->bit_flags)) {
dev_info(&wc->xb.pdev->dev, "Setting yellow alarm\n");
/* We manually do yellow alarm to handle RECOVER
* and NOTOPEN, otherwise it's auto anyway */
fmr4 = __t43x_framer_get(wc, fidx, 0x20);
__t43x_framer_set(wc, fidx, 0x20, fmr4 | 0x20);
ts->flags.sendingyellow = 1;
}
} else {
if (ts->flags.sendingyellow) {
if (test_and_clear_bit(SENDINGYELLOW_FLAGBIT, &ts->bit_flags)) {
dev_info(&wc->xb.pdev->dev, "Clearing yellow alarm\n");
/* We manually do yellow alarm to handle RECOVER */
fmr4 = __t43x_framer_get(wc, fidx, 0x20);
__t43x_framer_set(wc, fidx, 0x20, fmr4 & ~0x20);
ts->flags.sendingyellow = 0;
}
}
@@ -3149,6 +3202,45 @@ static void t43x_timer(unsigned long data)
return;
}
static int t43x_open(struct dahdi_chan *chan)
{
struct t43x *wc = chan->pvt;
struct t43x_span *ts = container_of(chan->span, struct t43x_span, span);
unsigned long flags;
if (!(ts->span.lineconfig & DAHDI_CONFIG_NOTOPEN))
return 0;
if (!test_and_set_bit(HAVE_OPEN_CHANNELS_FLAGBIT, &ts->bit_flags)) {
local_irq_save(flags);
t43x_check_alarms(wc, ts->span.offset);
local_irq_restore(flags);
}
return 0;
}
static int t43x_close(struct dahdi_chan *chan)
{
struct t43x *wc = chan->pvt;
struct t43x_span *ts = container_of(chan->span, struct t43x_span, span);
unsigned long flags;
if (!(ts->span.lineconfig & DAHDI_CONFIG_NOTOPEN))
return 0;
if (have_open_channels(ts))
return 0;
if (!test_and_set_bit(HAVE_OPEN_CHANNELS_FLAGBIT, &ts->bit_flags)) {
local_irq_save(flags);
t43x_check_alarms(wc, ts->span.offset);
local_irq_restore(flags);
}
return 0;
}
static const struct dahdi_span_ops t43x_span_ops = {
.owner = THIS_MODULE,
.spanconfig = t43x_spanconfig,
@@ -3161,6 +3253,8 @@ static const struct dahdi_span_ops t43x_span_ops = {
.set_spantype = t43x_set_linemode,
.echocan_create = t43x_echocan_create,
.echocan_name = t43x_echocan_name,
.open = t43x_open,
.close = t43x_close,
};
/**
@@ -3477,7 +3571,12 @@ static void __devexit t43x_remove_one(struct pci_dev *pdev)
wc->vpm = NULL;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
# ifdef T43X_HAVE_CANCEL_WORK_SYNC
cancel_work_sync(&wc->clksrc_work.work);
# else
cancel_delayed_work(&wc->clksrc_work.work);
flush_workqueue(wc->wq);
# endif
#else
cancel_delayed_work_sync(&wc->clksrc_work.work);
#endif

View File

@@ -29,6 +29,7 @@
#include <linux/crc32.h>
#include <linux/delay.h>
#include <linux/version.h>
#include <linux/slab.h>
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 26)
#define HAVE_RATELIMIT

View File

@@ -28,6 +28,7 @@
#include <linux/completion.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/io.h>

View File

@@ -1957,7 +1957,7 @@ static DEVICE_ATTR_WRITER(fxs_ring_registers_store, dev, buf, count)
regno);
goto invalid_input;
}
XPD_INFO(xpd, "%s Indirect 0x%X <=== 0x%X 0x%X\n",
XPD_DBG(SIGNAL, xpd, "%s Indirect 0x%X <=== 0x%X 0x%X\n",
rtype_name, regno, h_val, l_val);
} else {
if (ret != 3) {
@@ -1968,7 +1968,7 @@ static DEVICE_ATTR_WRITER(fxs_ring_registers_store, dev, buf, count)
}
l_val = h_val;
h_val = 0;
XPD_INFO(xpd, "%s Direct 0x%X <=== 0x%X\n",
XPD_DBG(SIGNAL, xpd, "%s Direct 0x%X <=== 0x%X\n",
rtype_name, regno, h_val);
}
spin_lock_irqsave(&xpd->lock, flags);

View File

@@ -524,9 +524,12 @@ static void PRI_card_pcm_recompute(xpd_t *xpd, xpp_line_t pcm_mask)
//XPD_DBG(SIGNAL, xpd, "pcm_mask=0x%X\n", pcm_mask);
/* Add/remove all the trivial cases */
pcm_mask |= PHONEDEV(xpd).offhook_state;
if (priv->is_cas)
pcm_mask |= BITMASK(PHONEDEV(xpd).channels);
for_each_line(xpd, i)
if (IS_SET(pcm_mask, i))
line_count++;
else
if (priv->is_cas) {
if (priv->pri_protocol == PRI_PROTO_E1) {
/* CAS: Don't send PCM to D-Channel */
@@ -1231,7 +1234,7 @@ static int pri_chanconfig(struct file *file, struct dahdi_chan *chan,
if (priv->pri_protocol != PRI_PROTO_E1 && priv->is_cas != 0)
set_mode_cas(xpd, 0);
} else {
if (chan->channo == 1) {
if (chan->chanpos == 1) {
XPD_DBG(GENERAL, xpd,
"channel %d (%s) marked a not DChan\n",
chan->channo, chan->name);

View File

@@ -4,6 +4,7 @@
#include <linux/proc_fs.h>
#include <linux/interrupt.h>
#include <linux/firmware.h>
#include <linux/slab.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/blackfin.h>

View File

@@ -27,6 +27,7 @@
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
#ifdef PROTOCOL_DEBUG
#include <linux/ctype.h>
#endif
@@ -79,8 +80,14 @@ static struct proc_dir_entry *proc_xbuses;
static struct xbus_desc {
xbus_t *xbus;
int shutting_down;
} xbuses_array[MAX_BUSES];
static int xbus_is_shutting_down(int num)
{
return xbuses_array[num].shutting_down;
}
static xbus_t *xbus_byhwid(const char *hwid)
{
int i;
@@ -148,6 +155,8 @@ static void init_xbus(uint num, xbus_t *xbus)
BUG_ON(num >= ARRAY_SIZE(xbuses_array));
desc = &xbuses_array[num];
desc->xbus = xbus;
if (xbus)
desc->shutting_down = 0;
}
xbus_t *xbus_num(uint num)
@@ -187,9 +196,12 @@ static void finalize_xbuses_array(void)
static void xbus_destroy(struct kref *kref)
{
xbus_t *xbus;
int num;
xbus = kref_to_xbus(kref);
XBUS_NOTICE(xbus, "%s\n", __func__);
XBUS_DBG(DEVICES, xbus, "%s\n", __func__);
num = xbus->num;
xbuses_array[num].shutting_down = 1;
xbus_sysfs_remove(xbus);
}
@@ -198,6 +210,11 @@ xbus_t *get_xbus(const char *msg, uint num)
unsigned long flags;
xbus_t *xbus;
if (xbus_is_shutting_down(num)) {
DBG(DEVICES, "%s(%s): XBUS-%d: shutting down\n", __func__,
msg, num);
return NULL;
}
spin_lock_irqsave(&xbuses_lock, flags);
xbus = xbus_num(num);
if (xbus != NULL) {
@@ -211,6 +228,13 @@ xbus_t *get_xbus(const char *msg, uint num)
void put_xbus(const char *msg, xbus_t *xbus)
{
if (xbus_is_shutting_down(xbus->num)) {
if (!refcount_xbus(xbus)) {
DBG(DEVICES, "%s(%s): XBUS-%d: shutting down\n",
__func__, msg, xbus->num);
return;
}
}
XBUS_DBG(DEVICES, xbus, "%s: refcount_xbus=%d\n", msg,
refcount_xbus(xbus));
kref_put(&xbus->kref, xbus_destroy);
@@ -560,6 +584,14 @@ static void receive_tasklet_func(unsigned long data)
void xbus_receive_xframe(xbus_t *xbus, xframe_t *xframe)
{
BUG_ON(!xbus);
if (xbus_is_shutting_down(xbus->num)) {
static int rate_limit;
if ((rate_limit++ % 1000) == 0)
XBUS_NOTICE(xbus, "%s: during shutdown (%d)\n",
__func__, rate_limit);
return;
}
if (rx_tasklet) {
xframe_enqueue_recv(xbus, xframe);
} else {
@@ -1034,26 +1066,34 @@ void xbus_unregister_dahdi_device(xbus_t *xbus)
int i;
int ret;
XBUS_NOTICE(xbus, "%s\n", __func__);
XBUS_DBG(DEVICES, xbus, "%s\n", __func__);
ret = mutex_lock_interruptible(&dahdi_registration_mutex);
if (ret < 0) {
XBUS_ERR(xbus, "dahdi_registration_mutex already taken\n");
return;
}
if (!xbus_is_registered(xbus)) {
/*
* Ignore duplicate unregistrations
*/
XBUS_DBG(DEVICES, xbus, "Already unregistered to DAHDI\n");
goto err;
}
for (i = 0; i < MAX_XPDS; i++) {
xpd_t *xpd = xpd_of(xbus, i);
xpd_dahdi_preunregister(xpd);
}
if (xbus->ddev) {
dahdi_unregister_device(xbus->ddev);
XBUS_NOTICE(xbus, "%s: finished dahdi_unregister_device()\n",
__func__);
XBUS_DBG(DEVICES, xbus,
"%s: finished dahdi_unregister_device()\n", __func__);
xbus_free_ddev(xbus);
}
for (i = 0; i < MAX_XPDS; i++) {
xpd_t *xpd = xpd_of(xbus, i);
xpd_dahdi_postunregister(xpd);
}
err:
mutex_unlock(&dahdi_registration_mutex);
}
@@ -1180,8 +1220,7 @@ static void worker_reset(xbus_t *xbus)
name = (xbus) ? xbus->busname : "detached";
DBG(DEVICES, "%s\n", name);
if (!worker->xpds_init_done) {
NOTICE("%s: worker(%s)->xpds_init_done=%d\n", __func__, name,
worker->xpds_init_done);
XBUS_NOTICE(xbus, "XPDS initialization was not finished\n");
}
spin_lock_irqsave(&worker->worker_lock, flags);
list_for_each_safe(card, next_card, &worker->card_list) {
@@ -1199,13 +1238,15 @@ static void worker_reset(xbus_t *xbus)
spin_unlock_irqrestore(&worker->worker_lock, flags);
}
/*
* Called only after worker_reset(xbus)
*/
static void worker_destroy(xbus_t *xbus)
{
struct xbus_workqueue *worker;
BUG_ON(!xbus);
worker = &xbus->worker;
worker_reset(xbus);
XBUS_DBG(DEVICES, xbus, "Waiting for worker to finish...\n");
down(&worker->running_initialization);
XBUS_DBG(DEVICES, xbus, "Waiting for worker to finish -- done\n");
@@ -1258,6 +1299,7 @@ static int worker_run(xbus_t *xbus)
}
return 1;
err:
worker_reset(xbus);
worker_destroy(xbus);
return 0;
}
@@ -1425,6 +1467,7 @@ void xbus_disconnect(xbus_t *xbus)
del_timer_sync(&xbus->command_timer);
transportops_put(xbus);
transport_destroy(xbus);
/* worker_reset(xbus) was called in xbus_deactivate(xbus) */
worker_destroy(xbus);
XBUS_DBG(DEVICES, xbus, "Deactivated refcount_xbus=%d\n",
refcount_xbus(xbus));
@@ -1474,6 +1517,7 @@ void xbus_free(xbus_t *xbus)
num = xbus->num;
BUG_ON(!xbuses_array[num].xbus);
BUG_ON(xbus != xbuses_array[num].xbus);
init_xbus(num, NULL);
spin_unlock_irqrestore(&xbuses_lock, flags);
#ifdef CONFIG_PROC_FS
if (xbus->proc_xbus_dir) {
@@ -1500,7 +1544,6 @@ void xbus_free(xbus_t *xbus)
#endif
spin_lock_irqsave(&xbuses_lock, flags);
XBUS_DBG(DEVICES, xbus, "Going to free...\n");
init_xbus(num, NULL);
spin_unlock_irqrestore(&xbuses_lock, flags);
KZFREE(xbus);
}
@@ -1631,10 +1674,6 @@ int waitfor_xpds(xbus_t *xbus, char *buf)
* FIXME: worker is created before ?????
* So by now it exists and initialized.
*/
/* until end of waitfor_xpds_show(): */
xbus = get_xbus(__func__, xbus->num);
if (!xbus)
return -ENODEV;
worker = &xbus->worker;
BUG_ON(!worker);
if (!worker->wq) {
@@ -1673,7 +1712,6 @@ int waitfor_xpds(xbus_t *xbus, char *buf)
spin_unlock_irqrestore(&xbus->lock, flags);
}
out:
put_xbus(__func__, xbus); /* from start of waitfor_xpds_show() */
return len;
}

View File

@@ -30,6 +30,7 @@
#include <linux/workqueue.h>
#include <linux/device.h>
#include <linux/delay.h> /* for msleep() to debug */
#include <linux/sched.h>
#include "xpd.h"
#include "xpp_dahdi.h"
#include "xbus-core.h"
@@ -302,6 +303,42 @@ field##_show(struct device *dev, struct device_attribute *attr, char *buf) \
xbus_attr(connector, "%s\n");
xbus_attr(label, "%s\n");
static DEVICE_ATTR_WRITER(dahdi_registration_store, dev, buf, count)
{
xbus_t *xbus;
int dahdi_reg;
int ret;
xbus = dev_to_xbus(dev);
if (!xbus)
return -ENODEV;
ret = sscanf(buf, "%d", &dahdi_reg);
if (ret != 1)
return -EINVAL;
if (dahdi_reg) {
ret = xbus_register_dahdi_device(xbus);
if (ret < 0) {
XBUS_ERR(xbus,
"xbus_register_dahdi_device() failed (ret = %d)\n",
ret);
return ret;
}
} else {
xbus_unregister_dahdi_device(xbus);
}
return count;
}
static DEVICE_ATTR_READER(dahdi_registration_show, dev, buf)
{
xbus_t *xbus;
int len;
xbus = dev_to_xbus(dev);
len = sprintf(buf, "%d\n", xbus_is_registered(xbus));
return len;
}
static struct device_attribute xbus_dev_attrs[] = {
__ATTR_RO(connector),
__ATTR_RO(label),
@@ -316,6 +353,9 @@ static struct device_attribute xbus_dev_attrs[] = {
#ifdef SAMPLE_TICKS
__ATTR(samples, S_IWUSR | S_IRUGO, samples_show, samples_store),
#endif
__ATTR(dahdi_registration, S_IRUGO | S_IWUSR,
dahdi_registration_show,
dahdi_registration_store),
__ATTR_NULL,
};
@@ -928,10 +968,13 @@ void xbus_sysfs_remove(xbus_t *xbus)
struct device *astribank;
BUG_ON(!xbus);
XBUS_DBG(DEVICES, xbus, "\n");
astribank = &xbus->astribank;
if (!dev_get_drvdata(astribank))
if (!dev_get_drvdata(astribank)) {
XBUS_NOTICE(xbus, "%s: already removed\n", __func__);
return;
}
XBUS_DBG(DEVICES, xbus, "going to unregister: refcount=%d\n",
atomic_read(&astribank->kobj.kref.refcount));
BUG_ON(dev_get_drvdata(astribank) != xbus);
device_unregister(astribank);
dev_set_drvdata(astribank, NULL);

View File

@@ -31,6 +31,7 @@
#include <linux/device.h>
#include <linux/version.h>
#include <asm/atomic.h>
#include <linux/slab.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
#include <linux/semaphore.h>
#else

View File

@@ -476,7 +476,7 @@ int phonedev_alloc_channels(xpd_t *xpd, int channels)
int old_channels = phonedev->channels;
unsigned int x;
XPD_NOTICE(xpd, "Reallocating channels: %d -> %d\n",
XPD_DBG(DEVICES, xpd, "Reallocating channels: %d -> %d\n",
old_channels, channels);
phonedev_cleanup(xpd);
phonedev->channels = channels;
@@ -714,15 +714,15 @@ EXPORT_SYMBOL(hookstate_changed);
/*------------------------- Dahdi Interfaces -----------------------*/
/*
* Called from dahdi with spinlock held on chan. Must not call back
* Called with spinlock held on chan. Must not call back
* dahdi functions.
*/
int xpp_open(struct dahdi_chan *chan)
static int _xpp_open(struct dahdi_chan *chan)
{
xpd_t *xpd;
xbus_t *xbus;
int pos;
unsigned long flags;
int open_counter;
if (!chan) {
NOTICE("open called on a null chan\n");
@@ -743,31 +743,37 @@ int xpp_open(struct dahdi_chan *chan)
LINE_NOTICE(xpd, pos, "Cannot open -- device not ready\n");
return -ENODEV;
}
spin_lock_irqsave(&xbus->lock, flags);
atomic_inc(&PHONEDEV(xpd).open_counter);
open_counter = atomic_inc_return(&PHONEDEV(xpd).open_counter);
LINE_DBG(DEVICES, xpd, pos, "%s[%d]: open_counter=%d\n", current->comm,
current->pid, atomic_read(&PHONEDEV(xpd).open_counter));
spin_unlock_irqrestore(&xbus->lock, flags);
current->pid, open_counter);
if (PHONE_METHOD(card_open, xpd))
CALL_PHONE_METHOD(card_open, xpd, pos);
return 0;
}
int xpp_open(struct dahdi_chan *chan)
{
unsigned long flags;
int res;
spin_lock_irqsave(&chan->lock, flags);
res = _xpp_open(chan);
spin_unlock_irqrestore(&chan->lock, flags);
return res;
}
EXPORT_SYMBOL(xpp_open);
int xpp_close(struct dahdi_chan *chan)
{
xpd_t *xpd = chan->pvt;
xbus_t *xbus = xpd->xbus;
int pos = chan->chanpos - 1;
unsigned long flags;
int open_counter;
spin_lock_irqsave(&xbus->lock, flags);
spin_unlock_irqrestore(&xbus->lock, flags);
if (PHONE_METHOD(card_close, xpd))
CALL_PHONE_METHOD(card_close, xpd, pos);
/* from xpp_open(): */
open_counter = atomic_dec_return(&PHONEDEV(xpd).open_counter);
LINE_DBG(DEVICES, xpd, pos, "%s[%d]: open_counter=%d\n", current->comm,
current->pid, atomic_read(&PHONEDEV(xpd).open_counter));
atomic_dec(&PHONEDEV(xpd).open_counter); /* from xpp_open() */
current->pid, open_counter);
return 0;
}
EXPORT_SYMBOL(xpp_close);

View File

@@ -211,7 +211,7 @@ static xusb_t *xusb_array[MAX_BUSES] = { };
static unsigned bus_count;
/* prevent races between open() and disconnect() */
static DEFINE_SEMAPHORE(disconnect_sem);
static DEFINE_MUTEX(protect_xusb_devices);
/*
* AsteriskNow kernel has backported the "lean" callback from 2.6.20
@@ -652,6 +652,7 @@ static int xusb_probe(struct usb_interface *interface,
iface_desc->desc.bInterfaceNumber, model_info->iface_num);
return -ENODEV;
}
mutex_lock(&protect_xusb_devices);
if ((retval = usb_reset_device(udev)) < 0) {
ERR("usb_reset_device failed: %d\n", retval);
goto probe_failed;
@@ -759,6 +760,7 @@ static int xusb_probe(struct usb_interface *interface,
for (i = 0; i < 10; i++)
xusb_listen(xusb);
xbus_connect(xbus);
mutex_unlock(&protect_xusb_devices);
return retval;
probe_failed:
ERR("Failed to initialize xpp usb bus: %d\n", retval);
@@ -785,6 +787,7 @@ probe_failed:
ERR("Calling xbus_disconnect()\n");
xbus_disconnect(xbus); // Blocking until fully deactivated!
}
mutex_unlock(&protect_xusb_devices);
return retval;
}
@@ -810,7 +813,7 @@ static void xusb_disconnect(struct usb_interface *interface)
DBG(DEVICES, "CALLED on interface #%d\n",
iface_desc->desc.bInterfaceNumber);
/* prevent races with open() */
down(&disconnect_sem);
mutex_lock(&protect_xusb_devices);
xusb = usb_get_intfdata(interface);
usb_set_intfdata(interface, NULL);
@@ -844,7 +847,7 @@ static void xusb_disconnect(struct usb_interface *interface)
XUSB_INFO(xusb, "now disconnected\n");
KZFREE(xusb);
up(&disconnect_sem);
mutex_unlock(&protect_xusb_devices);
}
static void xpp_send_callback(USB_PASS_CB(urb))

View File

@@ -425,6 +425,7 @@ struct dahdi_chan {
int lastnumbufs;
#endif
spinlock_t lock;
struct mutex mutex;
char name[40];
/* Specified by DAHDI */
/*! \brief DAHDI channel number */
@@ -1592,6 +1593,10 @@ struct mutex {
#define chan_err(chan, fmt, ...) chan_printk(ERR, "", chan, fmt, \
## __VA_ARGS__)
#ifndef pr_fmt
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#endif
#ifndef pr_err
#define pr_err(fmt, ...) \
printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__)