Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6

* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6: (1815 commits)
  mac80211: fix reorder buffer release
  iwmc3200wifi: Enable wimax core through module parameter
  iwmc3200wifi: Add wifi-wimax coexistence mode as a module parameter
  iwmc3200wifi: Coex table command does not expect a response
  iwmc3200wifi: Update wiwi priority table
  iwlwifi: driver version track kernel version
  iwlwifi: indicate uCode type when fail dump error/event log
  iwl3945: remove duplicated event logging code
  b43: fix two warnings
  ipw2100: fix rebooting hang with driver loaded
  cfg80211: indent regulatory messages with spaces
  iwmc3200wifi: fix NULL pointer dereference in pmkid update
  mac80211: Fix TX status reporting for injected data frames
  ath9k: enable 2GHz band only if the device supports it
  airo: Fix integer overflow warning
  rt2x00: Fix padding bug on L2PAD devices.
  WE: Fix set events not propagated
  b43legacy: avoid PPC fault during resume
  b43: avoid PPC fault during resume
  tcp: fix a timewait refcnt race
  ...

Fix up conflicts due to sysctl cleanups (dead sysctl_check code and
CTL_UNNUMBERED removed) in
	kernel/sysctl_check.c
	net/ipv4/sysctl_net_ipv4.c
	net/ipv6/addrconf.c
	net/sctp/sysctl.c
This commit is contained in:
Linus Torvalds 2009-12-08 07:55:01 -08:00
commit d7fc02c7ba
1394 changed files with 113401 additions and 70636 deletions

View File

@ -317,18 +317,6 @@ Who: ocfs2-devel@oss.oracle.com
--------------------------- ---------------------------
What: SCTP_GET_PEER_ADDRS_NUM_OLD, SCTP_GET_PEER_ADDRS_OLD,
SCTP_GET_LOCAL_ADDRS_NUM_OLD, SCTP_GET_LOCAL_ADDRS_OLD
When: June 2009
Why: A newer version of the options have been introduced in 2005 that
removes the limitions of the old API. The sctp library has been
converted to use these new options at the same time. Any user
space app that directly uses the old options should convert to using
the new options.
Who: Vlad Yasevich <vladislav.yasevich@hp.com>
---------------------------
What: Ability for non root users to shm_get hugetlb pages based on mlock What: Ability for non root users to shm_get hugetlb pages based on mlock
resource limits resource limits
When: 2.6.31 When: 2.6.31

View File

@ -5,7 +5,7 @@ GigaSet 307x Device Driver
------------ ------------
1.1. Hardware 1.1. Hardware
-------- --------
This release supports the connection of the Gigaset 307x/417x family of This driver supports the connection of the Gigaset 307x/417x family of
ISDN DECT bases via Gigaset M101 Data, Gigaset M105 Data or direct USB ISDN DECT bases via Gigaset M101 Data, Gigaset M105 Data or direct USB
connection. The following devices are reported to be compatible: connection. The following devices are reported to be compatible:
@ -33,7 +33,7 @@ GigaSet 307x Device Driver
http://gigaset307x.sourceforge.net/ http://gigaset307x.sourceforge.net/
We had also reports from users of Gigaset M105 who could use the drivers We had also reports from users of Gigaset M105 who could use the drivers
with SX 100 and CX 100 ISDN bases (only in unimodem mode, see section 2.4.) with SX 100 and CX 100 ISDN bases (only in unimodem mode, see section 2.5.)
If you have another device that works with our driver, please let us know. If you have another device that works with our driver, please let us know.
Chances of getting an USB device to work are good if the output of Chances of getting an USB device to work are good if the output of
@ -49,7 +49,7 @@ GigaSet 307x Device Driver
-------- --------
The driver works with ISDN4linux and so can be used with any software The driver works with ISDN4linux and so can be used with any software
which is able to use ISDN4linux for ISDN connections (voice or data). which is able to use ISDN4linux for ISDN connections (voice or data).
CAPI4Linux support is planned but not yet available. Experimental Kernel CAPI support is available as a compilation option.
There are some user space tools available at There are some user space tools available at
http://sourceforge.net/projects/gigaset307x/ http://sourceforge.net/projects/gigaset307x/
@ -102,20 +102,28 @@ GigaSet 307x Device Driver
2.3. ISDN4linux 2.3. ISDN4linux
---------- ----------
This is the "normal" mode of operation. After loading the module you can This is the "normal" mode of operation. After loading the module you can
set up the ISDN system just as you'd do with any ISDN card. set up the ISDN system just as you'd do with any ISDN card supported by
Your distribution should provide some configuration utility. the ISDN4Linux subsystem. Most distributions provide some configuration
If not, you can use some HOWTOs like utility. If not, you can use some HOWTOs like
http://www.linuxhaven.de/dlhp/HOWTO/DE-ISDN-HOWTO-5.html http://www.linuxhaven.de/dlhp/HOWTO/DE-ISDN-HOWTO-5.html
If this doesn't work, because you have some recent device like SX100 where If this doesn't work, because you have some device like SX100 where
debug output (see section 3.2.) shows something like this when dialing debug output (see section 3.2.) shows something like this when dialing
CMD Received: ERROR CMD Received: ERROR
Available Params: 0 Available Params: 0
Connection State: 0, Response: -1 Connection State: 0, Response: -1
gigaset_process_response: resp_code -1 in ConState 0 ! gigaset_process_response: resp_code -1 in ConState 0 !
Timeout occurred Timeout occurred
you might need to use unimodem mode: you might need to use unimodem mode. (see section 2.5.)
2.4. Unimodem mode 2.4. CAPI
----
If the driver is compiled with CAPI support (kernel configuration option
GIGASET_CAPI, experimental) it can also be used with CAPI 2.0 kernel and
user space applications. ISDN4Linux is supported in this configuration
via the capidrv compatibility driver. The kernel module capidrv.ko must
be loaded explicitly ("modprobe capidrv") if needed.
2.5. Unimodem mode
------------- -------------
This is needed for some devices [e.g. SX100] as they have problems with This is needed for some devices [e.g. SX100] as they have problems with
the "normal" commands. the "normal" commands.
@ -160,7 +168,7 @@ GigaSet 307x Device Driver
configuration file like /etc/modprobe.conf.local, configuration file like /etc/modprobe.conf.local,
using that should be preferred. using that should be preferred.
2.5. Call-ID (CID) mode 2.6. Call-ID (CID) mode
------------------ ------------------
Call-IDs are numbers used to tag commands to, and responses from, the Call-IDs are numbers used to tag commands to, and responses from, the
Gigaset base in order to support the simultaneous handling of multiple Gigaset base in order to support the simultaneous handling of multiple
@ -188,7 +196,7 @@ GigaSet 307x Device Driver
You can also use /sys/class/tty/ttyGxy/cidmode for changing the CID mode You can also use /sys/class/tty/ttyGxy/cidmode for changing the CID mode
setting (ttyGxy is ttyGU0 or ttyGB0). setting (ttyGxy is ttyGU0 or ttyGB0).
2.6. Unregistered Wireless Devices (M101/M105) 2.7. Unregistered Wireless Devices (M101/M105)
----------------------------------------- -----------------------------------------
The main purpose of the ser_gigaset and usb_gigaset drivers is to allow The main purpose of the ser_gigaset and usb_gigaset drivers is to allow
the M101 and M105 wireless devices to be used as ISDN devices for ISDN the M101 and M105 wireless devices to be used as ISDN devices for ISDN
@ -228,7 +236,7 @@ GigaSet 307x Device Driver
You have two or more DECT data adapters (M101/M105) and only the You have two or more DECT data adapters (M101/M105) and only the
first one you turn on works. first one you turn on works.
Solution: Solution:
Select Unimodem mode for all DECT data adapters. (see section 2.4.) Select Unimodem mode for all DECT data adapters. (see section 2.5.)
Problem: Problem:
Messages like this: Messages like this:
@ -236,7 +244,7 @@ GigaSet 307x Device Driver
appear in your syslog. appear in your syslog.
Solution: Solution:
Check whether your M10x wireless device is correctly registered to the Check whether your M10x wireless device is correctly registered to the
Gigaset base. (see section 2.6.) Gigaset base. (see section 2.7.)
3.2. Telling the driver to provide more information 3.2. Telling the driver to provide more information
---------------------------------------------- ----------------------------------------------

View File

@ -2605,6 +2605,9 @@ and is between 256 and 4096 characters. It is defined in the file
uart6850= [HW,OSS] uart6850= [HW,OSS]
Format: <io>,<irq> Format: <io>,<irq>
uhash_entries= [KNL,NET]
Set number of hash buckets for UDP/UDP-Lite connections
uhci-hcd.ignore_oc= uhci-hcd.ignore_oc=
[USB] Ignore overcurrent events (default N). [USB] Ignore overcurrent events (default N).
Some badly-designed motherboards generate lots of Some badly-designed motherboards generate lots of

View File

@ -1,7 +1,7 @@
Linux Ethernet Bonding Driver HOWTO Linux Ethernet Bonding Driver HOWTO
Latest update: 12 November 2007 Latest update: 23 September 2009
Initial release : Thomas Davis <tadavis at lbl.gov> Initial release : Thomas Davis <tadavis at lbl.gov>
Corrections, HA extensions : 2000/10/03-15 : Corrections, HA extensions : 2000/10/03-15 :
@ -614,6 +614,46 @@ primary
The primary option is only valid for active-backup mode. The primary option is only valid for active-backup mode.
primary_reselect
Specifies the reselection policy for the primary slave. This
affects how the primary slave is chosen to become the active slave
when failure of the active slave or recovery of the primary slave
occurs. This option is designed to prevent flip-flopping between
the primary slave and other slaves. Possible values are:
always or 0 (default)
The primary slave becomes the active slave whenever it
comes back up.
better or 1
The primary slave becomes the active slave when it comes
back up, if the speed and duplex of the primary slave is
better than the speed and duplex of the current active
slave.
failure or 2
The primary slave becomes the active slave only if the
current active slave fails and the primary slave is up.
The primary_reselect setting is ignored in two cases:
If no slaves are active, the first slave to recover is
made the active slave.
When initially enslaved, the primary slave is always made
the active slave.
Changing the primary_reselect policy via sysfs will cause an
immediate selection of the best active slave according to the new
policy. This may or may not result in a change of the active
slave, depending upon the circumstances.
This option was added for bonding version 3.6.0.
updelay updelay
Specifies the time, in milliseconds, to wait before enabling a Specifies the time, in milliseconds, to wait before enabling a

View File

@ -164,6 +164,14 @@ tcp_congestion_control - STRING
additional choices may be available based on kernel configuration. additional choices may be available based on kernel configuration.
Default is set as part of kernel configuration. Default is set as part of kernel configuration.
tcp_cookie_size - INTEGER
Default size of TCP Cookie Transactions (TCPCT) option, that may be
overridden on a per socket basis by the TCPCT socket option.
Values greater than the maximum (16) are interpreted as the maximum.
Values greater than zero and less than the minimum (8) are interpreted
as the minimum. Odd values are interpreted as the next even value.
Default: 0 (off).
tcp_dsack - BOOLEAN tcp_dsack - BOOLEAN
Allows TCP to send "duplicate" SACKs. Allows TCP to send "duplicate" SACKs.
@ -723,6 +731,12 @@ accept_source_route - BOOLEAN
default TRUE (router) default TRUE (router)
FALSE (host) FALSE (host)
accept_local - BOOLEAN
Accept packets with local source addresses. In combination with
suitable routing, this can be used to direct packets between two
local interfaces over the wire and have them accepted properly.
default FALSE
rp_filter - INTEGER rp_filter - INTEGER
0 - No source validation. 0 - No source validation.
1 - Strict mode as defined in RFC3704 Strict Reverse Path 1 - Strict mode as defined in RFC3704 Strict Reverse Path
@ -738,8 +752,8 @@ rp_filter - INTEGER
to prevent IP spoofing from DDos attacks. If using asymmetric routing to prevent IP spoofing from DDos attacks. If using asymmetric routing
or other complicated routing, then loose mode is recommended. or other complicated routing, then loose mode is recommended.
conf/all/rp_filter must also be set to non-zero to do source validation The max value from conf/{all,interface}/rp_filter is used
on the interface when doing source validation on the {interface}.
Default value is 0. Note that some distributions enable it Default value is 0. Note that some distributions enable it
in startup scripts. in startup scripts.
@ -1086,6 +1100,24 @@ accept_dad - INTEGER
2: Enable DAD, and disable IPv6 operation if MAC-based duplicate 2: Enable DAD, and disable IPv6 operation if MAC-based duplicate
link-local address has been found. link-local address has been found.
force_tllao - BOOLEAN
Enable sending the target link-layer address option even when
responding to a unicast neighbor solicitation.
Default: FALSE
Quoting from RFC 2461, section 4.4, Target link-layer address:
"The option MUST be included for multicast solicitations in order to
avoid infinite Neighbor Solicitation "recursion" when the peer node
does not have a cache entry to return a Neighbor Advertisements
message. When responding to unicast solicitations, the option can be
omitted since the sender of the solicitation has the correct link-
layer address; otherwise it would not have be able to send the unicast
solicitation in the first place. However, including the link-layer
address in this case adds little overhead and eliminates a potential
race condition where the sender deletes the cached link-layer address
prior to receiving a response to a previous solicitation."
icmp/*: icmp/*:
ratelimit - INTEGER ratelimit - INTEGER
Limit the maximal rates for sending ICMPv6 packets. Limit the maximal rates for sending ICMPv6 packets.

View File

@ -178,3 +178,13 @@ External interrupts:
external irq3: interrupts = <1 3 n>; external irq3: interrupts = <1 3 n>;
'n' is sense (0: level high, 1: edge rising, 2: edge falling 3: level low) 'n' is sense (0: level high, 1: edge rising, 2: edge falling 3: level low)
fsl,mpc5200-mscan nodes
-----------------------
In addition to the required compatible-, reg- and interrupt-properites, you can
also specify which clock source shall be used for the controller:
- fsl,mscan-clock-source- a string describing the clock source. Valid values
are: "ip" for ip bus clock
"ref" for reference clock (XTAL)
"ref" is default in case this property is not
present.

View File

@ -1120,7 +1120,6 @@ F: include/net/ax25.h
F: net/ax25/ F: net/ax25/
B43 WIRELESS DRIVER B43 WIRELESS DRIVER
M: Michael Buesch <mb@bu3sch.de>
M: Stefano Brivio <stefano.brivio@polimi.it> M: Stefano Brivio <stefano.brivio@polimi.it>
L: linux-wireless@vger.kernel.org L: linux-wireless@vger.kernel.org
W: http://linuxwireless.org/en/users/Drivers/b43 W: http://linuxwireless.org/en/users/Drivers/b43
@ -2817,6 +2816,15 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-2.6.git
S: Supported S: Supported
F: drivers/net/wireless/iwlwifi/ F: drivers/net/wireless/iwlwifi/
INTEL WIRELESS MULTICOMM 3200 WIFI (iwmc3200wifi)
M: Samuel Ortiz <samuel.ortiz@intel.com>
M: Zhu Yi <yi.zhu@intel.com>
M: Intel Linux Wireless <ilw@linux.intel.com>
L: linux-wireless@vger.kernel.org
S: Supported
W: http://wireless.kernel.org/en/users/Drivers/iwmc3200wifi
F: drivers/net/wireless/iwmc3200wifi/
IOC3 ETHERNET DRIVER IOC3 ETHERNET DRIVER
M: Ralf Baechle <ralf@linux-mips.org> M: Ralf Baechle <ralf@linux-mips.org>
L: linux-mips@linux-mips.org L: linux-mips@linux-mips.org
@ -3741,9 +3749,9 @@ F: include/linux/if_*
F: include/linux/*device.h F: include/linux/*device.h
NETXEN (1/10) GbE SUPPORT NETXEN (1/10) GbE SUPPORT
M: Dhananjay Phadke <dhananjay@netxen.com> M: Amit Kumar Salecha <amit.salecha@qlogic.com>
L: netdev@vger.kernel.org L: netdev@vger.kernel.org
W: http://www.netxen.com W: http://www.qlogic.com
S: Supported S: Supported
F: drivers/net/netxen/ F: drivers/net/netxen/

View File

@ -67,6 +67,8 @@
#define SO_TIMESTAMPING 37 #define SO_TIMESTAMPING 37
#define SCM_TIMESTAMPING SO_TIMESTAMPING #define SCM_TIMESTAMPING SO_TIMESTAMPING
#define SO_RXQ_OVFL 40
/* O_NONBLOCK clashes with the bits used for socket types. Therefore we /* O_NONBLOCK clashes with the bits used for socket types. Therefore we
* have to define SOCK_NONBLOCK to a different value here. * have to define SOCK_NONBLOCK to a different value here.
*/ */

View File

@ -433,10 +433,11 @@
#define __NR_signalfd 476 #define __NR_signalfd 476
#define __NR_timerfd 477 #define __NR_timerfd 477
#define __NR_eventfd 478 #define __NR_eventfd 478
#define __NR_recvmmsg 479
#ifdef __KERNEL__ #ifdef __KERNEL__
#define NR_SYSCALLS 479 #define NR_SYSCALLS 480
#define __ARCH_WANT_IPC_PARSE_VERSION #define __ARCH_WANT_IPC_PARSE_VERSION
#define __ARCH_WANT_OLD_READDIR #define __ARCH_WANT_OLD_READDIR

View File

@ -497,6 +497,7 @@ sys_call_table:
.quad sys_signalfd .quad sys_signalfd
.quad sys_ni_syscall .quad sys_ni_syscall
.quad sys_eventfd .quad sys_eventfd
.quad sys_recvmmsg
.size sys_call_table, . - sys_call_table .size sys_call_table, . - sys_call_table
.type sys_call_table, @object .type sys_call_table, @object

View File

@ -60,4 +60,6 @@
#define SO_PROTOCOL 38 #define SO_PROTOCOL 38
#define SO_DOMAIN 39 #define SO_DOMAIN 39
#define SO_RXQ_OVFL 40
#endif /* _ASM_SOCKET_H */ #endif /* _ASM_SOCKET_H */

View File

@ -374,6 +374,7 @@
CALL(sys_pwritev) CALL(sys_pwritev)
CALL(sys_rt_tgsigqueueinfo) CALL(sys_rt_tgsigqueueinfo)
CALL(sys_perf_event_open) CALL(sys_perf_event_open)
/* 365 */ CALL(sys_recvmmsg)
#ifndef syscalls_counted #ifndef syscalls_counted
.equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls .equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls
#define syscalls_counted #define syscalls_counted

View File

@ -60,4 +60,6 @@
#define SO_PROTOCOL 38 #define SO_PROTOCOL 38
#define SO_DOMAIN 39 #define SO_DOMAIN 39
#define SO_RXQ_OVFL 40
#endif /* __ASM_AVR32_SOCKET_H */ #endif /* __ASM_AVR32_SOCKET_H */

View File

@ -295,4 +295,5 @@ sys_call_table:
.long sys_signalfd .long sys_signalfd
.long sys_ni_syscall /* 280, was sys_timerfd */ .long sys_ni_syscall /* 280, was sys_timerfd */
.long sys_eventfd .long sys_eventfd
.long sys_recvmmsg
.long sys_ni_syscall /* r8 is saturated at nr_syscalls */ .long sys_ni_syscall /* r8 is saturated at nr_syscalls */

View File

@ -1600,6 +1600,7 @@ ENTRY(_sys_call_table)
.long _sys_pwritev .long _sys_pwritev
.long _sys_rt_tgsigqueueinfo .long _sys_rt_tgsigqueueinfo
.long _sys_perf_event_open .long _sys_perf_event_open
.long _sys_recvmmsg /* 370 */
.rept NR_syscalls-(.-_sys_call_table)/4 .rept NR_syscalls-(.-_sys_call_table)/4
.long _sys_ni_syscall .long _sys_ni_syscall

View File

@ -62,6 +62,8 @@
#define SO_PROTOCOL 38 #define SO_PROTOCOL 38
#define SO_DOMAIN 39 #define SO_DOMAIN 39
#define SO_RXQ_OVFL 40
#endif /* _ASM_SOCKET_H */ #endif /* _ASM_SOCKET_H */

View File

@ -60,5 +60,7 @@
#define SO_PROTOCOL 38 #define SO_PROTOCOL 38
#define SO_DOMAIN 39 #define SO_DOMAIN 39
#define SO_RXQ_OVFL 40
#endif /* _ASM_SOCKET_H */ #endif /* _ASM_SOCKET_H */

View File

@ -60,4 +60,6 @@
#define SO_PROTOCOL 38 #define SO_PROTOCOL 38
#define SO_DOMAIN 39 #define SO_DOMAIN 39
#define SO_RXQ_OVFL 40
#endif /* _ASM_SOCKET_H */ #endif /* _ASM_SOCKET_H */

View File

@ -69,4 +69,6 @@
#define SO_PROTOCOL 38 #define SO_PROTOCOL 38
#define SO_DOMAIN 39 #define SO_DOMAIN 39
#define SO_RXQ_OVFL 40
#endif /* _ASM_IA64_SOCKET_H */ #endif /* _ASM_IA64_SOCKET_H */

View File

@ -311,11 +311,12 @@
#define __NR_preadv 1319 #define __NR_preadv 1319
#define __NR_pwritev 1320 #define __NR_pwritev 1320
#define __NR_rt_tgsigqueueinfo 1321 #define __NR_rt_tgsigqueueinfo 1321
#define __NR_rt_recvmmsg 1322
#ifdef __KERNEL__ #ifdef __KERNEL__
#define NR_syscalls 298 /* length of syscall table */ #define NR_syscalls 299 /* length of syscall table */
/* /*
* The following defines stop scripts/checksyscalls.sh from complaining about * The following defines stop scripts/checksyscalls.sh from complaining about

View File

@ -1806,6 +1806,7 @@ sys_call_table:
data8 sys_preadv data8 sys_preadv
data8 sys_pwritev // 1320 data8 sys_pwritev // 1320
data8 sys_rt_tgsigqueueinfo data8 sys_rt_tgsigqueueinfo
data8 sys_recvmmsg
.org sys_call_table + 8*NR_syscalls // guard against failures to increase NR_syscalls .org sys_call_table + 8*NR_syscalls // guard against failures to increase NR_syscalls
#endif /* __IA64_ASM_PARAVIRTUALIZED_NATIVE */ #endif /* __IA64_ASM_PARAVIRTUALIZED_NATIVE */

View File

@ -60,4 +60,6 @@
#define SO_PROTOCOL 38 #define SO_PROTOCOL 38
#define SO_DOMAIN 39 #define SO_DOMAIN 39
#define SO_RXQ_OVFL 40
#endif /* _ASM_M32R_SOCKET_H */ #endif /* _ASM_M32R_SOCKET_H */

View File

@ -60,4 +60,6 @@
#define SO_PROTOCOL 38 #define SO_PROTOCOL 38
#define SO_DOMAIN 39 #define SO_DOMAIN 39
#define SO_RXQ_OVFL 40
#endif /* _ASM_SOCKET_H */ #endif /* _ASM_SOCKET_H */

View File

@ -371,3 +371,4 @@ ENTRY(sys_call_table)
.long sys_ni_syscall .long sys_ni_syscall
.long sys_rt_tgsigqueueinfo /* 365 */ .long sys_rt_tgsigqueueinfo /* 365 */
.long sys_perf_event_open .long sys_perf_event_open
.long sys_recvmmsg

View File

@ -80,6 +80,8 @@ To add: #define SO_REUSEPORT 0x0200 /* Allow local address and port reuse. */
#define SO_TIMESTAMPING 37 #define SO_TIMESTAMPING 37
#define SCM_TIMESTAMPING SO_TIMESTAMPING #define SCM_TIMESTAMPING SO_TIMESTAMPING
#define SO_RXQ_OVFL 40
#ifdef __KERNEL__ #ifdef __KERNEL__
/** sock_type - Socket types /** sock_type - Socket types

View File

@ -355,16 +355,17 @@
#define __NR_rt_tgsigqueueinfo (__NR_Linux + 332) #define __NR_rt_tgsigqueueinfo (__NR_Linux + 332)
#define __NR_perf_event_open (__NR_Linux + 333) #define __NR_perf_event_open (__NR_Linux + 333)
#define __NR_accept4 (__NR_Linux + 334) #define __NR_accept4 (__NR_Linux + 334)
#define __NR_recvmmsg (__NR_Linux + 335)
/* /*
* Offset of the last Linux o32 flavoured syscall * Offset of the last Linux o32 flavoured syscall
*/ */
#define __NR_Linux_syscalls 334 #define __NR_Linux_syscalls 335
#endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */ #endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */
#define __NR_O32_Linux 4000 #define __NR_O32_Linux 4000
#define __NR_O32_Linux_syscalls 334 #define __NR_O32_Linux_syscalls 335
#if _MIPS_SIM == _MIPS_SIM_ABI64 #if _MIPS_SIM == _MIPS_SIM_ABI64
@ -666,16 +667,17 @@
#define __NR_rt_tgsigqueueinfo (__NR_Linux + 291) #define __NR_rt_tgsigqueueinfo (__NR_Linux + 291)
#define __NR_perf_event_open (__NR_Linux + 292) #define __NR_perf_event_open (__NR_Linux + 292)
#define __NR_accept4 (__NR_Linux + 293) #define __NR_accept4 (__NR_Linux + 293)
#define __NR_recvmmsg (__NR_Linux + 294)
/* /*
* Offset of the last Linux 64-bit flavoured syscall * Offset of the last Linux 64-bit flavoured syscall
*/ */
#define __NR_Linux_syscalls 293 #define __NR_Linux_syscalls 294
#endif /* _MIPS_SIM == _MIPS_SIM_ABI64 */ #endif /* _MIPS_SIM == _MIPS_SIM_ABI64 */
#define __NR_64_Linux 5000 #define __NR_64_Linux 5000
#define __NR_64_Linux_syscalls 293 #define __NR_64_Linux_syscalls 294
#if _MIPS_SIM == _MIPS_SIM_NABI32 #if _MIPS_SIM == _MIPS_SIM_NABI32
@ -981,16 +983,17 @@
#define __NR_rt_tgsigqueueinfo (__NR_Linux + 295) #define __NR_rt_tgsigqueueinfo (__NR_Linux + 295)
#define __NR_perf_event_open (__NR_Linux + 296) #define __NR_perf_event_open (__NR_Linux + 296)
#define __NR_accept4 (__NR_Linux + 297) #define __NR_accept4 (__NR_Linux + 297)
#define __NR_recvmmsg (__NR_Linux + 298)
/* /*
* Offset of the last N32 flavoured syscall * Offset of the last N32 flavoured syscall
*/ */
#define __NR_Linux_syscalls 297 #define __NR_Linux_syscalls 298
#endif /* _MIPS_SIM == _MIPS_SIM_NABI32 */ #endif /* _MIPS_SIM == _MIPS_SIM_NABI32 */
#define __NR_N32_Linux 6000 #define __NR_N32_Linux 6000
#define __NR_N32_Linux_syscalls 297 #define __NR_N32_Linux_syscalls 298
#ifdef __KERNEL__ #ifdef __KERNEL__

View File

@ -583,6 +583,7 @@ einval: li v0, -ENOSYS
sys sys_rt_tgsigqueueinfo 4 sys sys_rt_tgsigqueueinfo 4
sys sys_perf_event_open 5 sys sys_perf_event_open 5
sys sys_accept4 4 sys sys_accept4 4
sys sys_recvmmsg 5
.endm .endm
/* We pre-compute the number of _instruction_ bytes needed to /* We pre-compute the number of _instruction_ bytes needed to

View File

@ -420,4 +420,5 @@ sys_call_table:
PTR sys_rt_tgsigqueueinfo PTR sys_rt_tgsigqueueinfo
PTR sys_perf_event_open PTR sys_perf_event_open
PTR sys_accept4 PTR sys_accept4
PTR sys_recvmmsg
.size sys_call_table,.-sys_call_table .size sys_call_table,.-sys_call_table

View File

@ -418,4 +418,5 @@ EXPORT(sysn32_call_table)
PTR compat_sys_rt_tgsigqueueinfo /* 5295 */ PTR compat_sys_rt_tgsigqueueinfo /* 5295 */
PTR sys_perf_event_open PTR sys_perf_event_open
PTR sys_accept4 PTR sys_accept4
PTR compat_sys_recvmmsg
.size sysn32_call_table,.-sysn32_call_table .size sysn32_call_table,.-sysn32_call_table

View File

@ -538,4 +538,5 @@ sys_call_table:
PTR compat_sys_rt_tgsigqueueinfo PTR compat_sys_rt_tgsigqueueinfo
PTR sys_perf_event_open PTR sys_perf_event_open
PTR sys_accept4 PTR sys_accept4
PTR compat_sys_recvmmsg
.size sys_call_table,.-sys_call_table .size sys_call_table,.-sys_call_table

View File

@ -60,4 +60,6 @@
#define SO_PROTOCOL 38 #define SO_PROTOCOL 38
#define SO_DOMAIN 39 #define SO_DOMAIN 39
#define SO_RXQ_OVFL 40
#endif /* _ASM_SOCKET_H */ #endif /* _ASM_SOCKET_H */

View File

@ -59,6 +59,8 @@
#define SO_TIMESTAMPING 0x4020 #define SO_TIMESTAMPING 0x4020
#define SCM_TIMESTAMPING SO_TIMESTAMPING #define SCM_TIMESTAMPING SO_TIMESTAMPING
#define SO_RXQ_OVFL 0x4021
/* O_NONBLOCK clashes with the bits used for socket types. Therefore we /* O_NONBLOCK clashes with the bits used for socket types. Therefore we
* have to define SOCK_NONBLOCK to a different value here. * have to define SOCK_NONBLOCK to a different value here.
*/ */

View File

@ -67,4 +67,6 @@
#define SO_PROTOCOL 38 #define SO_PROTOCOL 38
#define SO_DOMAIN 39 #define SO_DOMAIN 39
#define SO_RXQ_OVFL 40
#endif /* _ASM_POWERPC_SOCKET_H */ #endif /* _ASM_POWERPC_SOCKET_H */

View File

@ -83,8 +83,9 @@ static void appldata_get_net_sum_data(void *data)
rx_dropped = 0; rx_dropped = 0;
tx_dropped = 0; tx_dropped = 0;
collisions = 0; collisions = 0;
read_lock(&dev_base_lock);
for_each_netdev(&init_net, dev) { rcu_read_lock();
for_each_netdev_rcu(&init_net, dev) {
const struct net_device_stats *stats = dev_get_stats(dev); const struct net_device_stats *stats = dev_get_stats(dev);
rx_packets += stats->rx_packets; rx_packets += stats->rx_packets;
@ -98,7 +99,8 @@ static void appldata_get_net_sum_data(void *data)
collisions += stats->collisions; collisions += stats->collisions;
i++; i++;
} }
read_unlock(&dev_base_lock); rcu_read_unlock();
net_data->nr_interfaces = i; net_data->nr_interfaces = i;
net_data->rx_packets = rx_packets; net_data->rx_packets = rx_packets;
net_data->tx_packets = tx_packets; net_data->tx_packets = tx_packets;

View File

@ -68,4 +68,6 @@
#define SO_PROTOCOL 38 #define SO_PROTOCOL 38
#define SO_DOMAIN 39 #define SO_DOMAIN 39
#define SO_RXQ_OVFL 40
#endif /* _ASM_SOCKET_H */ #endif /* _ASM_SOCKET_H */

View File

@ -7,6 +7,7 @@ struct sh_eth_plat_data {
int phy; int phy;
int edmac_endian; int edmac_endian;
unsigned char mac_addr[6];
unsigned no_ether_link:1; unsigned no_ether_link:1;
unsigned ether_link_active_low:1; unsigned ether_link_active_low:1;
}; };

View File

@ -391,3 +391,4 @@ sys_call_table:
.long sys_pwritev .long sys_pwritev
.long sys_rt_tgsigqueueinfo .long sys_rt_tgsigqueueinfo
.long sys_perf_event_open .long sys_perf_event_open
.long sys_recvmmsg /* 365 */

View File

@ -56,6 +56,8 @@
#define SO_TIMESTAMPING 0x0023 #define SO_TIMESTAMPING 0x0023
#define SCM_TIMESTAMPING SO_TIMESTAMPING #define SCM_TIMESTAMPING SO_TIMESTAMPING
#define SO_RXQ_OVFL 0x0024
/* Security levels - as per NRL IPv6 - don't actually do anything */ /* Security levels - as per NRL IPv6 - don't actually do anything */
#define SO_SECURITY_AUTHENTICATION 0x5001 #define SO_SECURITY_AUTHENTICATION 0x5001
#define SO_SECURITY_ENCRYPTION_TRANSPORT 0x5002 #define SO_SECURITY_ENCRYPTION_TRANSPORT 0x5002

View File

@ -396,8 +396,9 @@
#define __NR_pwritev 325 #define __NR_pwritev 325
#define __NR_rt_tgsigqueueinfo 326 #define __NR_rt_tgsigqueueinfo 326
#define __NR_perf_event_open 327 #define __NR_perf_event_open 327
#define __NR_recvmmsg 328
#define NR_SYSCALLS 328 #define NR_SYSCALLS 329
#ifdef __32bit_syscall_numbers__ #ifdef __32bit_syscall_numbers__
/* Sparc 32-bit only has the "setresuid32", "getresuid32" variants, /* Sparc 32-bit only has the "setresuid32", "getresuid32" variants,

View File

@ -82,5 +82,5 @@ sys_call_table:
/*310*/ .long sys_utimensat, sys_signalfd, sys_timerfd_create, sys_eventfd, sys_fallocate /*310*/ .long sys_utimensat, sys_signalfd, sys_timerfd_create, sys_eventfd, sys_fallocate
/*315*/ .long sys_timerfd_settime, sys_timerfd_gettime, sys_signalfd4, sys_eventfd2, sys_epoll_create1 /*315*/ .long sys_timerfd_settime, sys_timerfd_gettime, sys_signalfd4, sys_eventfd2, sys_epoll_create1
/*320*/ .long sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, sys_preadv /*320*/ .long sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, sys_preadv
/*325*/ .long sys_pwritev, sys_rt_tgsigqueueinfo, sys_perf_event_open /*325*/ .long sys_pwritev, sys_rt_tgsigqueueinfo, sys_perf_event_open, sys_recvmmsg

View File

@ -83,7 +83,7 @@ sys_call_table32:
/*310*/ .word compat_sys_utimensat, compat_sys_signalfd, sys_timerfd_create, sys_eventfd, compat_sys_fallocate /*310*/ .word compat_sys_utimensat, compat_sys_signalfd, sys_timerfd_create, sys_eventfd, compat_sys_fallocate
.word compat_sys_timerfd_settime, compat_sys_timerfd_gettime, compat_sys_signalfd4, sys_eventfd2, sys_epoll_create1 .word compat_sys_timerfd_settime, compat_sys_timerfd_gettime, compat_sys_signalfd4, sys_eventfd2, sys_epoll_create1
/*320*/ .word sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, compat_sys_preadv /*320*/ .word sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, compat_sys_preadv
.word compat_sys_pwritev, compat_sys_rt_tgsigqueueinfo, sys_perf_event_open .word compat_sys_pwritev, compat_sys_rt_tgsigqueueinfo, sys_perf_event_open, compat_sys_recvmmsg
#endif /* CONFIG_COMPAT */ #endif /* CONFIG_COMPAT */
@ -158,4 +158,4 @@ sys_call_table:
/*310*/ .word sys_utimensat, sys_signalfd, sys_timerfd_create, sys_eventfd, sys_fallocate /*310*/ .word sys_utimensat, sys_signalfd, sys_timerfd_create, sys_eventfd, sys_fallocate
.word sys_timerfd_settime, sys_timerfd_gettime, sys_signalfd4, sys_eventfd2, sys_epoll_create1 .word sys_timerfd_settime, sys_timerfd_gettime, sys_signalfd4, sys_eventfd2, sys_epoll_create1
/*320*/ .word sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, sys_preadv /*320*/ .word sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, sys_preadv
.word sys_pwritev, sys_rt_tgsigqueueinfo, sys_perf_event_open .word sys_pwritev, sys_rt_tgsigqueueinfo, sys_perf_event_open, sys_recvmmsg

View File

@ -841,4 +841,5 @@ ia32_sys_call_table:
.quad compat_sys_pwritev .quad compat_sys_pwritev
.quad compat_sys_rt_tgsigqueueinfo /* 335 */ .quad compat_sys_rt_tgsigqueueinfo /* 335 */
.quad sys_perf_event_open .quad sys_perf_event_open
.quad compat_sys_recvmmsg
ia32_syscall_end: ia32_syscall_end:

View File

@ -342,10 +342,11 @@
#define __NR_pwritev 334 #define __NR_pwritev 334
#define __NR_rt_tgsigqueueinfo 335 #define __NR_rt_tgsigqueueinfo 335
#define __NR_perf_event_open 336 #define __NR_perf_event_open 336
#define __NR_recvmmsg 337
#ifdef __KERNEL__ #ifdef __KERNEL__
#define NR_syscalls 337 #define NR_syscalls 338
#define __ARCH_WANT_IPC_PARSE_VERSION #define __ARCH_WANT_IPC_PARSE_VERSION
#define __ARCH_WANT_OLD_READDIR #define __ARCH_WANT_OLD_READDIR

View File

@ -661,6 +661,8 @@ __SYSCALL(__NR_pwritev, sys_pwritev)
__SYSCALL(__NR_rt_tgsigqueueinfo, sys_rt_tgsigqueueinfo) __SYSCALL(__NR_rt_tgsigqueueinfo, sys_rt_tgsigqueueinfo)
#define __NR_perf_event_open 298 #define __NR_perf_event_open 298
__SYSCALL(__NR_perf_event_open, sys_perf_event_open) __SYSCALL(__NR_perf_event_open, sys_perf_event_open)
#define __NR_recvmmsg 299
__SYSCALL(__NR_recvmmsg, sys_recvmmsg)
#ifndef __NO_STUBS #ifndef __NO_STUBS
#define __ARCH_WANT_OLD_READDIR #define __ARCH_WANT_OLD_READDIR

View File

@ -336,3 +336,4 @@ ENTRY(sys_call_table)
.long sys_pwritev .long sys_pwritev
.long sys_rt_tgsigqueueinfo /* 335 */ .long sys_rt_tgsigqueueinfo /* 335 */
.long sys_perf_event_open .long sys_perf_event_open
.long sys_recvmmsg

View File

@ -71,4 +71,6 @@
#define SO_PROTOCOL 38 #define SO_PROTOCOL 38
#define SO_DOMAIN 39 #define SO_DOMAIN 39
#define SO_RXQ_OVFL 40
#endif /* _XTENSA_SOCKET_H */ #endif /* _XTENSA_SOCKET_H */

View File

@ -681,8 +681,10 @@ __SYSCALL(304, sys_signalfd, 3)
__SYSCALL(305, sys_ni_syscall, 0) __SYSCALL(305, sys_ni_syscall, 0)
#define __NR_eventfd 306 #define __NR_eventfd 306
__SYSCALL(306, sys_eventfd, 1) __SYSCALL(306, sys_eventfd, 1)
#define __NR_recvmmsg 307
__SYSCALL(307, sys_recvmmsg, 5)
#define __NR_syscall_count 307 #define __NR_syscall_count 308
/* /*
* sysxtensa syscall handler * sysxtensa syscall handler

View File

@ -2351,6 +2351,7 @@ static void __init amb_check_args (void) {
MODULE_AUTHOR(maintainer_string); MODULE_AUTHOR(maintainer_string);
MODULE_DESCRIPTION(description_string); MODULE_DESCRIPTION(description_string);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_FIRMWARE("atmsar11.fw");
module_param(debug, ushort, 0644); module_param(debug, ushort, 0644);
module_param(cmds, uint, 0); module_param(cmds, uint, 0);
module_param(txs, uint, 0); module_param(txs, uint, 0);

View File

@ -2906,8 +2906,8 @@ fore200e_proc_read(struct atm_dev *dev, loff_t* pos, char* page)
u32 media_index = FORE200E_MEDIA_INDEX(fore200e->bus->read(&fore200e->cp_queues->media_type)); u32 media_index = FORE200E_MEDIA_INDEX(fore200e->bus->read(&fore200e->cp_queues->media_type));
u32 oc3_index; u32 oc3_index;
if ((media_index < 0) || (media_index > 4)) if (media_index > 4)
media_index = 5; media_index = 5;
switch (fore200e->loop_mode) { switch (fore200e->loop_mode) {
case ATM_LM_NONE: oc3_index = 0; case ATM_LM_NONE: oc3_index = 0;

View File

@ -2739,7 +2739,7 @@ he_ioctl(struct atm_dev *atm_dev, unsigned int cmd, void __user *arg)
spin_lock_irqsave(&he_dev->global_lock, flags); spin_lock_irqsave(&he_dev->global_lock, flags);
switch (reg.type) { switch (reg.type) {
case HE_REGTYPE_PCI: case HE_REGTYPE_PCI:
if (reg.addr < 0 || reg.addr >= HE_REGMAP_SIZE) { if (reg.addr >= HE_REGMAP_SIZE) {
err = -EINVAL; err = -EINVAL;
break; break;
} }

View File

@ -142,6 +142,9 @@ MODULE_AUTHOR("Traverse Technologies <support@traverse.com.au>");
MODULE_DESCRIPTION("Solos PCI driver"); MODULE_DESCRIPTION("Solos PCI driver");
MODULE_VERSION(VERSION); MODULE_VERSION(VERSION);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_FIRMWARE("solos-FPGA.bin");
MODULE_FIRMWARE("solos-Firmware.bin");
MODULE_FIRMWARE("solos-db-FPGA.bin");
MODULE_PARM_DESC(reset, "Reset Solos chips on startup"); MODULE_PARM_DESC(reset, "Reset Solos chips on startup");
MODULE_PARM_DESC(atmdebug, "Print ATM data"); MODULE_PARM_DESC(atmdebug, "Print ATM data");
MODULE_PARM_DESC(firmware_upgrade, "Initiate Solos firmware upgrade"); MODULE_PARM_DESC(firmware_upgrade, "Initiate Solos firmware upgrade");
@ -528,34 +531,37 @@ static int flash_upgrade(struct solos_card *card, int chip)
int numblocks = 0; int numblocks = 0;
int offset; int offset;
if (chip == 0) { switch (chip) {
case 0:
fw_name = "solos-FPGA.bin"; fw_name = "solos-FPGA.bin";
blocksize = FPGA_BLOCK; blocksize = FPGA_BLOCK;
} break;
case 1:
if (chip == 1) {
fw_name = "solos-Firmware.bin"; fw_name = "solos-Firmware.bin";
blocksize = SOLOS_BLOCK; blocksize = SOLOS_BLOCK;
} break;
case 2:
if (chip == 2){
if (card->fpga_version > LEGACY_BUFFERS){ if (card->fpga_version > LEGACY_BUFFERS){
fw_name = "solos-db-FPGA.bin"; fw_name = "solos-db-FPGA.bin";
blocksize = FPGA_BLOCK; blocksize = FPGA_BLOCK;
} else { } else {
dev_info(&card->dev->dev, "FPGA version doesn't support daughter board upgrades\n"); dev_info(&card->dev->dev, "FPGA version doesn't support"
" daughter board upgrades\n");
return -EPERM; return -EPERM;
} }
} break;
case 3:
if (chip == 3){
if (card->fpga_version > LEGACY_BUFFERS){ if (card->fpga_version > LEGACY_BUFFERS){
fw_name = "solos-Firmware.bin"; fw_name = "solos-Firmware.bin";
blocksize = SOLOS_BLOCK; blocksize = SOLOS_BLOCK;
} else { } else {
dev_info(&card->dev->dev, "FPGA version doesn't support daughter board upgrades\n"); dev_info(&card->dev->dev, "FPGA version doesn't support"
return -EPERM; " daughter board upgrades\n");
return -EPERM;
} }
break;
default:
return -ENODEV;
} }
if (request_firmware(&fw, fw_name, &card->dev->dev)) if (request_firmware(&fw, fw_name, &card->dev->dev))

View File

@ -29,7 +29,6 @@ struct btmrvl_debugfs_data {
struct dentry *root_dir, *config_dir, *status_dir; struct dentry *root_dir, *config_dir, *status_dir;
/* config */ /* config */
struct dentry *drvdbg;
struct dentry *psmode; struct dentry *psmode;
struct dentry *pscmd; struct dentry *pscmd;
struct dentry *hsmode; struct dentry *hsmode;

View File

@ -131,6 +131,7 @@ void btmrvl_check_evtpkt(struct btmrvl_private *priv, struct sk_buff *skb);
int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb); int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb);
int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd); int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd);
int btmrvl_enable_ps(struct btmrvl_private *priv);
int btmrvl_prepare_command(struct btmrvl_private *priv); int btmrvl_prepare_command(struct btmrvl_private *priv);
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS

View File

@ -189,6 +189,38 @@ int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd)
} }
EXPORT_SYMBOL_GPL(btmrvl_send_module_cfg_cmd); EXPORT_SYMBOL_GPL(btmrvl_send_module_cfg_cmd);
int btmrvl_enable_ps(struct btmrvl_private *priv)
{
struct sk_buff *skb;
struct btmrvl_cmd *cmd;
skb = bt_skb_alloc(sizeof(*cmd), GFP_ATOMIC);
if (skb == NULL) {
BT_ERR("No free skb");
return -ENOMEM;
}
cmd = (struct btmrvl_cmd *) skb_put(skb, sizeof(*cmd));
cmd->ocf_ogf = cpu_to_le16(hci_opcode_pack(OGF,
BT_CMD_AUTO_SLEEP_MODE));
cmd->length = 1;
if (priv->btmrvl_dev.psmode)
cmd->data[0] = BT_PS_ENABLE;
else
cmd->data[0] = BT_PS_DISABLE;
bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT;
skb->dev = (void *) priv->btmrvl_dev.hcidev;
skb_queue_head(&priv->adapter->tx_queue, skb);
BT_DBG("Queue PSMODE Command:%d", cmd->data[0]);
return 0;
}
EXPORT_SYMBOL_GPL(btmrvl_enable_ps);
static int btmrvl_enable_hs(struct btmrvl_private *priv) static int btmrvl_enable_hs(struct btmrvl_private *priv)
{ {
struct sk_buff *skb; struct sk_buff *skb;
@ -258,28 +290,7 @@ int btmrvl_prepare_command(struct btmrvl_private *priv)
if (priv->btmrvl_dev.pscmd) { if (priv->btmrvl_dev.pscmd) {
priv->btmrvl_dev.pscmd = 0; priv->btmrvl_dev.pscmd = 0;
btmrvl_enable_ps(priv);
skb = bt_skb_alloc(sizeof(*cmd), GFP_ATOMIC);
if (skb == NULL) {
BT_ERR("No free skb");
return -ENOMEM;
}
cmd = (struct btmrvl_cmd *) skb_put(skb, sizeof(*cmd));
cmd->ocf_ogf = cpu_to_le16(hci_opcode_pack(OGF, BT_CMD_AUTO_SLEEP_MODE));
cmd->length = 1;
if (priv->btmrvl_dev.psmode)
cmd->data[0] = BT_PS_ENABLE;
else
cmd->data[0] = BT_PS_DISABLE;
bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT;
skb->dev = (void *) priv->btmrvl_dev.hcidev;
skb_queue_head(&priv->adapter->tx_queue, skb);
BT_DBG("Queue PSMODE Command:%d", cmd->data[0]);
} }
if (priv->btmrvl_dev.hscmd) { if (priv->btmrvl_dev.hscmd) {

View File

@ -930,6 +930,8 @@ static int btmrvl_sdio_probe(struct sdio_func *func,
priv->hw_wakeup_firmware = btmrvl_sdio_wakeup_fw; priv->hw_wakeup_firmware = btmrvl_sdio_wakeup_fw;
btmrvl_send_module_cfg_cmd(priv, MODULE_BRINGUP_REQ); btmrvl_send_module_cfg_cmd(priv, MODULE_BRINGUP_REQ);
priv->btmrvl_dev.psmode = 1;
btmrvl_enable_ps(priv);
return 0; return 0;
@ -1001,3 +1003,5 @@ MODULE_AUTHOR("Marvell International Ltd.");
MODULE_DESCRIPTION("Marvell BT-over-SDIO driver ver " VERSION); MODULE_DESCRIPTION("Marvell BT-over-SDIO driver ver " VERSION);
MODULE_VERSION(VERSION); MODULE_VERSION(VERSION);
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
MODULE_FIRMWARE("sd8688_helper.bin");
MODULE_FIRMWARE("sd8688.bin");

View File

@ -41,8 +41,6 @@
#define VERSION "1.3" #define VERSION "1.3"
static int minor = MISC_DYNAMIC_MINOR;
struct vhci_data { struct vhci_data {
struct hci_dev *hdev; struct hci_dev *hdev;
@ -218,12 +216,6 @@ static unsigned int vhci_poll(struct file *file, poll_table *wait)
return POLLOUT | POLLWRNORM; return POLLOUT | POLLWRNORM;
} }
static int vhci_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
return -EINVAL;
}
static int vhci_open(struct inode *inode, struct file *file) static int vhci_open(struct inode *inode, struct file *file)
{ {
struct vhci_data *data; struct vhci_data *data;
@ -284,10 +276,10 @@ static int vhci_release(struct inode *inode, struct file *file)
} }
static const struct file_operations vhci_fops = { static const struct file_operations vhci_fops = {
.owner = THIS_MODULE,
.read = vhci_read, .read = vhci_read,
.write = vhci_write, .write = vhci_write,
.poll = vhci_poll, .poll = vhci_poll,
.ioctl = vhci_ioctl,
.open = vhci_open, .open = vhci_open,
.release = vhci_release, .release = vhci_release,
}; };
@ -302,18 +294,12 @@ static int __init vhci_init(void)
{ {
BT_INFO("Virtual HCI driver ver %s", VERSION); BT_INFO("Virtual HCI driver ver %s", VERSION);
if (misc_register(&vhci_miscdev) < 0) { return misc_register(&vhci_miscdev);
BT_ERR("Can't register misc device with minor %d", minor);
return -EIO;
}
return 0;
} }
static void __exit vhci_exit(void) static void __exit vhci_exit(void)
{ {
if (misc_deregister(&vhci_miscdev) < 0) misc_deregister(&vhci_miscdev);
BT_ERR("Can't unregister misc device with minor %d", minor);
} }
module_init(vhci_init); module_init(vhci_init);

View File

@ -32,9 +32,29 @@
#include <net/nl802154.h> #include <net/nl802154.h>
#include <net/wpan-phy.h> #include <net/wpan-phy.h>
struct wpan_phy *net_to_phy(struct net_device *dev) struct fakehard_priv {
struct wpan_phy *phy;
};
static struct wpan_phy *fake_to_phy(const struct net_device *dev)
{ {
return container_of(dev->dev.parent, struct wpan_phy, dev); struct fakehard_priv *priv = netdev_priv(dev);
return priv->phy;
}
/**
* fake_get_phy - Return a phy corresponding to this device.
* @dev: The network device for which to return the wan-phy object
*
* This function returns a wpan-phy object corresponding to the passed
* network device. Reference counter for wpan-phy object is incremented,
* so when the wpan-phy isn't necessary, you should drop the reference
* via @wpan_phy_put() call.
*/
static struct wpan_phy *fake_get_phy(const struct net_device *dev)
{
struct wpan_phy *phy = fake_to_phy(dev);
return to_phy(get_device(&phy->dev));
} }
/** /**
@ -43,7 +63,7 @@ struct wpan_phy *net_to_phy(struct net_device *dev)
* *
* Return the ID of the PAN from the PIB. * Return the ID of the PAN from the PIB.
*/ */
static u16 fake_get_pan_id(struct net_device *dev) static u16 fake_get_pan_id(const struct net_device *dev)
{ {
BUG_ON(dev->type != ARPHRD_IEEE802154); BUG_ON(dev->type != ARPHRD_IEEE802154);
@ -58,7 +78,7 @@ static u16 fake_get_pan_id(struct net_device *dev)
* device. If the device has not yet had a short address assigned * device. If the device has not yet had a short address assigned
* then this should return 0xFFFF to indicate a lack of association. * then this should return 0xFFFF to indicate a lack of association.
*/ */
static u16 fake_get_short_addr(struct net_device *dev) static u16 fake_get_short_addr(const struct net_device *dev)
{ {
BUG_ON(dev->type != ARPHRD_IEEE802154); BUG_ON(dev->type != ARPHRD_IEEE802154);
@ -78,7 +98,7 @@ static u16 fake_get_short_addr(struct net_device *dev)
* Note: This is in section 7.2.1.2 of the IEEE 802.15.4-2006 * Note: This is in section 7.2.1.2 of the IEEE 802.15.4-2006
* document. * document.
*/ */
static u8 fake_get_dsn(struct net_device *dev) static u8 fake_get_dsn(const struct net_device *dev)
{ {
BUG_ON(dev->type != ARPHRD_IEEE802154); BUG_ON(dev->type != ARPHRD_IEEE802154);
@ -98,7 +118,7 @@ static u8 fake_get_dsn(struct net_device *dev)
* Note: This is in section 7.2.1.2 of the IEEE 802.15.4-2006 * Note: This is in section 7.2.1.2 of the IEEE 802.15.4-2006
* document. * document.
*/ */
static u8 fake_get_bsn(struct net_device *dev) static u8 fake_get_bsn(const struct net_device *dev)
{ {
BUG_ON(dev->type != ARPHRD_IEEE802154); BUG_ON(dev->type != ARPHRD_IEEE802154);
@ -121,7 +141,7 @@ static u8 fake_get_bsn(struct net_device *dev)
static int fake_assoc_req(struct net_device *dev, static int fake_assoc_req(struct net_device *dev,
struct ieee802154_addr *addr, u8 channel, u8 page, u8 cap) struct ieee802154_addr *addr, u8 channel, u8 page, u8 cap)
{ {
struct wpan_phy *phy = net_to_phy(dev); struct wpan_phy *phy = fake_to_phy(dev);
mutex_lock(&phy->pib_lock); mutex_lock(&phy->pib_lock);
phy->current_channel = channel; phy->current_channel = channel;
@ -196,7 +216,7 @@ static int fake_start_req(struct net_device *dev, struct ieee802154_addr *addr,
u8 bcn_ord, u8 sf_ord, u8 pan_coord, u8 blx, u8 bcn_ord, u8 sf_ord, u8 pan_coord, u8 blx,
u8 coord_realign) u8 coord_realign)
{ {
struct wpan_phy *phy = net_to_phy(dev); struct wpan_phy *phy = fake_to_phy(dev);
mutex_lock(&phy->pib_lock); mutex_lock(&phy->pib_lock);
phy->current_channel = channel; phy->current_channel = channel;
@ -239,6 +259,8 @@ static struct ieee802154_mlme_ops fake_mlme = {
.start_req = fake_start_req, .start_req = fake_start_req,
.scan_req = fake_scan_req, .scan_req = fake_scan_req,
.get_phy = fake_get_phy,
.get_pan_id = fake_get_pan_id, .get_pan_id = fake_get_pan_id,
.get_short_addr = fake_get_short_addr, .get_short_addr = fake_get_short_addr,
.get_dsn = fake_get_dsn, .get_dsn = fake_get_dsn,
@ -310,7 +332,7 @@ static const struct net_device_ops fake_ops = {
static void ieee802154_fake_destruct(struct net_device *dev) static void ieee802154_fake_destruct(struct net_device *dev)
{ {
struct wpan_phy *phy = net_to_phy(dev); struct wpan_phy *phy = fake_to_phy(dev);
wpan_phy_unregister(phy); wpan_phy_unregister(phy);
free_netdev(dev); free_netdev(dev);
@ -335,13 +357,14 @@ static void ieee802154_fake_setup(struct net_device *dev)
static int __devinit ieee802154fake_probe(struct platform_device *pdev) static int __devinit ieee802154fake_probe(struct platform_device *pdev)
{ {
struct net_device *dev; struct net_device *dev;
struct fakehard_priv *priv;
struct wpan_phy *phy = wpan_phy_alloc(0); struct wpan_phy *phy = wpan_phy_alloc(0);
int err; int err;
if (!phy) if (!phy)
return -ENOMEM; return -ENOMEM;
dev = alloc_netdev(0, "hardwpan%d", ieee802154_fake_setup); dev = alloc_netdev(sizeof(struct fakehard_priv), "hardwpan%d", ieee802154_fake_setup);
if (!dev) { if (!dev) {
wpan_phy_free(phy); wpan_phy_free(phy);
return -ENOMEM; return -ENOMEM;
@ -353,12 +376,23 @@ static int __devinit ieee802154fake_probe(struct platform_device *pdev)
dev->addr_len); dev->addr_len);
memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
phy->channels_supported = (1 << 27) - 1; /*
* For now we'd like to emulate 2.4 GHz-only device,
* both O-QPSK and CSS
*/
/* 2.4 GHz O-QPSK 802.15.4-2003 */
phy->channels_supported[0] |= 0x7FFF800;
/* 2.4 GHz CSS 802.15.4a-2007 */
phy->channels_supported[3] |= 0x3fff;
phy->transmit_power = 0xbf; phy->transmit_power = 0xbf;
dev->netdev_ops = &fake_ops; dev->netdev_ops = &fake_ops;
dev->ml_priv = &fake_mlme; dev->ml_priv = &fake_mlme;
priv = netdev_priv(dev);
priv->phy = phy;
/* /*
* If the name is a format string the caller wants us to do a * If the name is a format string the caller wants us to do a
* name allocation. * name allocation.
@ -369,11 +403,12 @@ static int __devinit ieee802154fake_probe(struct platform_device *pdev)
goto out; goto out;
} }
wpan_phy_set_dev(phy, &pdev->dev);
SET_NETDEV_DEV(dev, &phy->dev); SET_NETDEV_DEV(dev, &phy->dev);
platform_set_drvdata(pdev, dev); platform_set_drvdata(pdev, dev);
err = wpan_phy_register(&pdev->dev, phy); err = wpan_phy_register(phy);
if (err) if (err)
goto out; goto out;

View File

@ -1080,11 +1080,14 @@ static int nes_netdev_set_rx_csum(struct net_device *netdev, u32 enable)
/** /**
* nes_netdev_get_stats_count * nes_netdev_get_sset_count
*/ */
static int nes_netdev_get_stats_count(struct net_device *netdev) static int nes_netdev_get_sset_count(struct net_device *netdev, int stringset)
{ {
return NES_ETHTOOL_STAT_COUNT; if (stringset == ETH_SS_STATS)
return NES_ETHTOOL_STAT_COUNT;
else
return -EINVAL;
} }
@ -1264,7 +1267,6 @@ static void nes_netdev_get_drvinfo(struct net_device *netdev,
sprintf(drvinfo->fw_version, "%u.%u", nesadapter->firmware_version>>16, sprintf(drvinfo->fw_version, "%u.%u", nesadapter->firmware_version>>16,
nesadapter->firmware_version & 0x000000ff); nesadapter->firmware_version & 0x000000ff);
strcpy(drvinfo->version, DRV_VERSION); strcpy(drvinfo->version, DRV_VERSION);
drvinfo->n_stats = nes_netdev_get_stats_count(netdev);
drvinfo->testinfo_len = 0; drvinfo->testinfo_len = 0;
drvinfo->eedump_len = 0; drvinfo->eedump_len = 0;
drvinfo->regdump_len = 0; drvinfo->regdump_len = 0;
@ -1516,7 +1518,7 @@ static const struct ethtool_ops nes_ethtool_ops = {
.get_rx_csum = nes_netdev_get_rx_csum, .get_rx_csum = nes_netdev_get_rx_csum,
.get_sg = ethtool_op_get_sg, .get_sg = ethtool_op_get_sg,
.get_strings = nes_netdev_get_strings, .get_strings = nes_netdev_get_strings,
.get_stats_count = nes_netdev_get_stats_count, .get_sset_count = nes_netdev_get_sset_count,
.get_ethtool_stats = nes_netdev_get_ethtool_stats, .get_ethtool_stats = nes_netdev_get_ethtool_stats,
.get_drvinfo = nes_netdev_get_drvinfo, .get_drvinfo = nes_netdev_get_drvinfo,
.get_coalesce = nes_netdev_get_coalesce, .get_coalesce = nes_netdev_get_coalesce,

View File

@ -1,6 +1,5 @@
menuconfig ISDN_DRV_GIGASET menuconfig ISDN_DRV_GIGASET
tristate "Siemens Gigaset support" tristate "Siemens Gigaset support"
depends on ISDN_I4L
select CRC_CCITT select CRC_CCITT
select BITREVERSE select BITREVERSE
help help
@ -11,9 +10,33 @@ menuconfig ISDN_DRV_GIGASET
If you have one of these devices, say M here and for at least If you have one of these devices, say M here and for at least
one of the connection specific parts that follow. one of the connection specific parts that follow.
This will build a module called "gigaset". This will build a module called "gigaset".
Note: If you build your ISDN subsystem (ISDN_CAPI or ISDN_I4L)
as a module, you have to build this driver as a module too,
otherwise the Gigaset device won't show up as an ISDN device.
if ISDN_DRV_GIGASET if ISDN_DRV_GIGASET
config GIGASET_CAPI
bool "Gigaset CAPI support (EXPERIMENTAL)"
depends on EXPERIMENTAL
depends on ISDN_CAPI='y'||(ISDN_CAPI='m'&&ISDN_DRV_GIGASET='m')
default ISDN_I4L='n'
help
Build the Gigaset driver as a CAPI 2.0 driver interfacing with
the Kernel CAPI subsystem. To use it with the old ISDN4Linux
subsystem you'll have to enable the capidrv glue driver.
(select ISDN_CAPI_CAPIDRV.)
Say N to build the old native ISDN4Linux variant.
config GIGASET_I4L
bool
depends on ISDN_I4L='y'||(ISDN_I4L='m'&&ISDN_DRV_GIGASET='m')
default !GIGASET_CAPI
config GIGASET_DUMMYLL
bool
default !GIGASET_CAPI&&!GIGASET_I4L
config GIGASET_BASE config GIGASET_BASE
tristate "Gigaset base station support" tristate "Gigaset base station support"
depends on USB depends on USB

View File

@ -1,4 +1,7 @@
gigaset-y := common.o interface.o proc.o ev-layer.o i4l.o asyncdata.o gigaset-y := common.o interface.o proc.o ev-layer.o asyncdata.o
gigaset-$(CONFIG_GIGASET_CAPI) += capi.o
gigaset-$(CONFIG_GIGASET_I4L) += i4l.o
gigaset-$(CONFIG_GIGASET_DUMMYLL) += dummyll.o
usb_gigaset-y := usb-gigaset.o usb_gigaset-y := usb-gigaset.o
ser_gigaset-y := ser-gigaset.o ser_gigaset-y := ser-gigaset.o
bas_gigaset-y := bas-gigaset.o isocdata.o bas_gigaset-y := bas-gigaset.o isocdata.o

View File

@ -19,7 +19,7 @@
/* check if byte must be stuffed/escaped /* check if byte must be stuffed/escaped
* I'm not sure which data should be encoded. * I'm not sure which data should be encoded.
* Therefore I will go the hard way and decode every value * Therefore I will go the hard way and encode every value
* less than 0x20, the flag sequence and the control escape char. * less than 0x20, the flag sequence and the control escape char.
*/ */
static inline int muststuff(unsigned char c) static inline int muststuff(unsigned char c)
@ -35,303 +35,383 @@ static inline int muststuff(unsigned char c)
/* == data input =========================================================== */ /* == data input =========================================================== */
/* process a block of received bytes in command mode (modem response) /* process a block of received bytes in command mode
* (mstate != MS_LOCKED && (inputstate & INS_command))
* Append received bytes to the command response buffer and forward them
* line by line to the response handler. Exit whenever a mode/state change
* might have occurred.
* Return value: * Return value:
* number of processed bytes * number of processed bytes
*/ */
static inline int cmd_loop(unsigned char c, unsigned char *src, int numbytes, static unsigned cmd_loop(unsigned numbytes, struct inbuf_t *inbuf)
struct inbuf_t *inbuf)
{ {
unsigned char *src = inbuf->data + inbuf->head;
struct cardstate *cs = inbuf->cs; struct cardstate *cs = inbuf->cs;
unsigned cbytes = cs->cbytes; unsigned cbytes = cs->cbytes;
int inputstate = inbuf->inputstate; unsigned procbytes = 0;
int startbytes = numbytes; unsigned char c;
for (;;) { while (procbytes < numbytes) {
cs->respdata[cbytes] = c; c = *src++;
if (c == 10 || c == 13) { procbytes++;
gig_dbg(DEBUG_TRANSCMD, "%s: End of Command (%d Bytes)",
__func__, cbytes);
cs->cbytes = cbytes;
gigaset_handle_modem_response(cs); /* can change
cs->dle */
cbytes = 0;
if (cs->dle && switch (c) {
!(inputstate & INS_DLE_command)) { case '\n':
inputstate &= ~INS_command; if (cbytes == 0 && cs->respdata[0] == '\r') {
/* collapse LF with preceding CR */
cs->respdata[0] = 0;
break; break;
} }
} else { /* --v-- fall through --v-- */
/* advance in line buffer, checking for overflow */ case '\r':
if (cbytes < MAX_RESP_SIZE - 1) /* end of message line, pass to response handler */
cbytes++; gig_dbg(DEBUG_TRANSCMD, "%s: End of Message (%d Bytes)",
else __func__, cbytes);
dev_warn(cs->dev, "response too large\n"); if (cbytes >= MAX_RESP_SIZE) {
} dev_warn(cs->dev, "response too large (%d)\n",
cbytes);
cbytes = MAX_RESP_SIZE;
}
cs->cbytes = cbytes;
gigaset_handle_modem_response(cs);
cbytes = 0;
if (!numbytes) /* store EOL byte for CRLF collapsing */
break; cs->respdata[0] = c;
c = *src++;
--numbytes; /* cs->dle may have changed */
if (c == DLE_FLAG && if (cs->dle && !(inbuf->inputstate & INS_DLE_command))
(cs->dle || inputstate & INS_DLE_command)) { inbuf->inputstate &= ~INS_command;
inputstate |= INS_DLE_char;
break; /* return for reevaluating state */
goto exit;
case DLE_FLAG:
if (inbuf->inputstate & INS_DLE_char) {
/* quoted DLE: clear quote flag */
inbuf->inputstate &= ~INS_DLE_char;
} else if (cs->dle ||
(inbuf->inputstate & INS_DLE_command)) {
/* DLE escape, pass up for handling */
inbuf->inputstate |= INS_DLE_char;
goto exit;
}
/* quoted or not in DLE mode: treat as regular data */
/* --v-- fall through --v-- */
default:
/* append to line buffer if possible */
if (cbytes < MAX_RESP_SIZE)
cs->respdata[cbytes] = c;
cbytes++;
} }
} }
exit:
cs->cbytes = cbytes; cs->cbytes = cbytes;
inbuf->inputstate = inputstate; return procbytes;
return startbytes - numbytes;
} }
/* process a block of received bytes in lock mode (tty i/f) /* process a block of received bytes in lock mode
* All received bytes are passed unmodified to the tty i/f.
* Return value: * Return value:
* number of processed bytes * number of processed bytes
*/ */
static inline int lock_loop(unsigned char *src, int numbytes, static unsigned lock_loop(unsigned numbytes, struct inbuf_t *inbuf)
struct inbuf_t *inbuf)
{ {
struct cardstate *cs = inbuf->cs; unsigned char *src = inbuf->data + inbuf->head;
gigaset_dbg_buffer(DEBUG_LOCKCMD, "received response",
numbytes, src);
gigaset_if_receive(cs, src, numbytes);
gigaset_dbg_buffer(DEBUG_LOCKCMD, "received response", numbytes, src);
gigaset_if_receive(inbuf->cs, src, numbytes);
return numbytes; return numbytes;
} }
/* set up next receive skb for data mode
*/
static void new_rcv_skb(struct bc_state *bcs)
{
struct cardstate *cs = bcs->cs;
unsigned short hw_hdr_len = cs->hw_hdr_len;
if (bcs->ignore) {
bcs->skb = NULL;
return;
}
bcs->skb = dev_alloc_skb(SBUFSIZE + hw_hdr_len);
if (bcs->skb == NULL) {
dev_warn(cs->dev, "could not allocate new skb\n");
return;
}
skb_reserve(bcs->skb, hw_hdr_len);
}
/* process a block of received bytes in HDLC data mode /* process a block of received bytes in HDLC data mode
* (mstate != MS_LOCKED && !(inputstate & INS_command) && proto2 == L2_HDLC)
* Collect HDLC frames, undoing byte stuffing and watching for DLE escapes. * Collect HDLC frames, undoing byte stuffing and watching for DLE escapes.
* When a frame is complete, check the FCS and pass valid frames to the LL. * When a frame is complete, check the FCS and pass valid frames to the LL.
* If DLE is encountered, return immediately to let the caller handle it. * If DLE is encountered, return immediately to let the caller handle it.
* Return value: * Return value:
* number of processed bytes * number of processed bytes
* numbytes (all bytes processed) on error --FIXME
*/ */
static inline int hdlc_loop(unsigned char c, unsigned char *src, int numbytes, static unsigned hdlc_loop(unsigned numbytes, struct inbuf_t *inbuf)
struct inbuf_t *inbuf)
{ {
struct cardstate *cs = inbuf->cs; struct cardstate *cs = inbuf->cs;
struct bc_state *bcs = inbuf->bcs; struct bc_state *bcs = cs->bcs;
int inputstate = bcs->inputstate; int inputstate = bcs->inputstate;
__u16 fcs = bcs->fcs; __u16 fcs = bcs->fcs;
struct sk_buff *skb = bcs->skb; struct sk_buff *skb = bcs->skb;
unsigned char error; unsigned char *src = inbuf->data + inbuf->head;
struct sk_buff *compskb; unsigned procbytes = 0;
int startbytes = numbytes; unsigned char c;
int l;
if (unlikely(inputstate & INS_byte_stuff)) { if (inputstate & INS_byte_stuff) {
if (!numbytes)
return 0;
inputstate &= ~INS_byte_stuff; inputstate &= ~INS_byte_stuff;
goto byte_stuff; goto byte_stuff;
} }
for (;;) {
if (unlikely(c == PPP_ESCAPE)) { while (procbytes < numbytes) {
if (unlikely(!numbytes)) { c = *src++;
inputstate |= INS_byte_stuff; procbytes++;
if (c == DLE_FLAG) {
if (inputstate & INS_DLE_char) {
/* quoted DLE: clear quote flag */
inputstate &= ~INS_DLE_char;
} else if (cs->dle || (inputstate & INS_DLE_command)) {
/* DLE escape, pass up for handling */
inputstate |= INS_DLE_char;
break; break;
} }
c = *src++; }
--numbytes;
if (unlikely(c == DLE_FLAG && if (c == PPP_ESCAPE) {
(cs->dle || /* byte stuffing indicator: pull in next byte */
inbuf->inputstate & INS_DLE_command))) { if (procbytes >= numbytes) {
inbuf->inputstate |= INS_DLE_char; /* end of buffer, save for later processing */
inputstate |= INS_byte_stuff; inputstate |= INS_byte_stuff;
break; break;
} }
byte_stuff: byte_stuff:
c = *src++;
procbytes++;
if (c == DLE_FLAG) {
if (inputstate & INS_DLE_char) {
/* quoted DLE: clear quote flag */
inputstate &= ~INS_DLE_char;
} else if (cs->dle ||
(inputstate & INS_DLE_command)) {
/* DLE escape, pass up for handling */
inputstate |=
INS_DLE_char | INS_byte_stuff;
break;
}
}
c ^= PPP_TRANS; c ^= PPP_TRANS;
if (unlikely(!muststuff(c))) #ifdef CONFIG_GIGASET_DEBUG
if (!muststuff(c))
gig_dbg(DEBUG_HDLC, "byte stuffed: 0x%02x", c); gig_dbg(DEBUG_HDLC, "byte stuffed: 0x%02x", c);
} else if (unlikely(c == PPP_FLAG)) {
if (unlikely(inputstate & INS_skip_frame)) {
#ifdef CONFIG_GIGASET_DEBUG
if (!(inputstate & INS_have_data)) { /* 7E 7E */
++bcs->emptycount;
} else
gig_dbg(DEBUG_HDLC,
"7e----------------------------");
#endif #endif
} else if (c == PPP_FLAG) {
/* end of frame */ /* end of frame: process content if any */
error = 1; if (inputstate & INS_have_data) {
gigaset_rcv_error(NULL, cs, bcs);
} else if (!(inputstate & INS_have_data)) { /* 7E 7E */
#ifdef CONFIG_GIGASET_DEBUG
++bcs->emptycount;
#endif
break;
} else {
gig_dbg(DEBUG_HDLC, gig_dbg(DEBUG_HDLC,
"7e----------------------------"); "7e----------------------------");
/* end of frame */ /* check and pass received frame */
error = 0; if (!skb) {
/* skipped frame */
if (unlikely(fcs != PPP_GOODFCS)) { gigaset_isdn_rcv_err(bcs);
} else if (skb->len < 2) {
/* frame too short for FCS */
dev_warn(cs->dev,
"short frame (%d)\n",
skb->len);
gigaset_isdn_rcv_err(bcs);
dev_kfree_skb_any(skb);
} else if (fcs != PPP_GOODFCS) {
/* frame check error */
dev_err(cs->dev, dev_err(cs->dev,
"Checksum failed, %u bytes corrupted!\n", "Checksum failed, %u bytes corrupted!\n",
skb->len); skb->len);
compskb = NULL; gigaset_isdn_rcv_err(bcs);
gigaset_rcv_error(compskb, cs, bcs); dev_kfree_skb_any(skb);
error = 1;
} else { } else {
if (likely((l = skb->len) > 2)) { /* good frame */
skb->tail -= 2; __skb_trim(skb, skb->len - 2);
skb->len -= 2; gigaset_skb_rcvd(bcs, skb);
} else { }
dev_kfree_skb(skb);
skb = NULL; /* prepare reception of next frame */
inputstate |= INS_skip_frame; inputstate &= ~INS_have_data;
if (l == 1) { new_rcv_skb(bcs);
dev_err(cs->dev, skb = bcs->skb;
"invalid packet size (1)!\n"); } else {
error = 1; /* empty frame (7E 7E) */
gigaset_rcv_error(NULL, #ifdef CONFIG_GIGASET_DEBUG
cs, bcs); ++bcs->emptycount;
} #endif
} if (!skb) {
if (likely(!(error || /* skipped (?) */
(inputstate & gigaset_isdn_rcv_err(bcs);
INS_skip_frame)))) { new_rcv_skb(bcs);
gigaset_rcv_skb(skb, cs, bcs); skb = bcs->skb;
}
} }
} }
if (unlikely(error))
if (skb)
dev_kfree_skb(skb);
fcs = PPP_INITFCS; fcs = PPP_INITFCS;
inputstate &= ~(INS_have_data | INS_skip_frame); continue;
if (unlikely(bcs->ignore)) { #ifdef CONFIG_GIGASET_DEBUG
inputstate |= INS_skip_frame; } else if (muststuff(c)) {
skb = NULL;
} else if (likely((skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL)) {
skb_reserve(skb, HW_HDR_LEN);
} else {
dev_warn(cs->dev,
"could not allocate new skb\n");
inputstate |= INS_skip_frame;
}
break;
} else if (unlikely(muststuff(c))) {
/* Should not happen. Possible after ZDLE=1<CR><LF>. */ /* Should not happen. Possible after ZDLE=1<CR><LF>. */
gig_dbg(DEBUG_HDLC, "not byte stuffed: 0x%02x", c); gig_dbg(DEBUG_HDLC, "not byte stuffed: 0x%02x", c);
#endif
} }
/* add character */ /* regular data byte, append to skb */
#ifdef CONFIG_GIGASET_DEBUG #ifdef CONFIG_GIGASET_DEBUG
if (unlikely(!(inputstate & INS_have_data))) { if (!(inputstate & INS_have_data)) {
gig_dbg(DEBUG_HDLC, "7e (%d x) ================", gig_dbg(DEBUG_HDLC, "7e (%d x) ================",
bcs->emptycount); bcs->emptycount);
bcs->emptycount = 0; bcs->emptycount = 0;
} }
#endif #endif
inputstate |= INS_have_data; inputstate |= INS_have_data;
if (skb) {
if (likely(!(inputstate & INS_skip_frame))) { if (skb->len == SBUFSIZE) {
if (unlikely(skb->len == SBUFSIZE)) {
dev_warn(cs->dev, "received packet too long\n"); dev_warn(cs->dev, "received packet too long\n");
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
skb = NULL; /* skip remainder of packet */
inputstate |= INS_skip_frame; bcs->skb = skb = NULL;
break; } else {
*__skb_put(skb, 1) = c;
fcs = crc_ccitt_byte(fcs, c);
} }
*__skb_put(skb, 1) = c;
fcs = crc_ccitt_byte(fcs, c);
}
if (unlikely(!numbytes))
break;
c = *src++;
--numbytes;
if (unlikely(c == DLE_FLAG &&
(cs->dle ||
inbuf->inputstate & INS_DLE_command))) {
inbuf->inputstate |= INS_DLE_char;
break;
} }
} }
bcs->inputstate = inputstate; bcs->inputstate = inputstate;
bcs->fcs = fcs; bcs->fcs = fcs;
bcs->skb = skb; return procbytes;
return startbytes - numbytes;
} }
/* process a block of received bytes in transparent data mode /* process a block of received bytes in transparent data mode
* (mstate != MS_LOCKED && !(inputstate & INS_command) && proto2 != L2_HDLC)
* Invert bytes, undoing byte stuffing and watching for DLE escapes. * Invert bytes, undoing byte stuffing and watching for DLE escapes.
* If DLE is encountered, return immediately to let the caller handle it. * If DLE is encountered, return immediately to let the caller handle it.
* Return value: * Return value:
* number of processed bytes * number of processed bytes
* numbytes (all bytes processed) on error --FIXME
*/ */
static inline int iraw_loop(unsigned char c, unsigned char *src, int numbytes, static unsigned iraw_loop(unsigned numbytes, struct inbuf_t *inbuf)
struct inbuf_t *inbuf)
{ {
struct cardstate *cs = inbuf->cs; struct cardstate *cs = inbuf->cs;
struct bc_state *bcs = inbuf->bcs; struct bc_state *bcs = cs->bcs;
int inputstate = bcs->inputstate; int inputstate = bcs->inputstate;
struct sk_buff *skb = bcs->skb; struct sk_buff *skb = bcs->skb;
int startbytes = numbytes; unsigned char *src = inbuf->data + inbuf->head;
unsigned procbytes = 0;
unsigned char c;
for (;;) { if (!skb) {
/* add character */ /* skip this block */
inputstate |= INS_have_data; new_rcv_skb(bcs);
return numbytes;
}
if (likely(!(inputstate & INS_skip_frame))) { while (procbytes < numbytes && skb->len < SBUFSIZE) {
if (unlikely(skb->len == SBUFSIZE)) { c = *src++;
//FIXME just pass skb up and allocate a new one procbytes++;
dev_warn(cs->dev, "received packet too long\n");
dev_kfree_skb_any(skb); if (c == DLE_FLAG) {
skb = NULL; if (inputstate & INS_DLE_char) {
inputstate |= INS_skip_frame; /* quoted DLE: clear quote flag */
inputstate &= ~INS_DLE_char;
} else if (cs->dle || (inputstate & INS_DLE_command)) {
/* DLE escape, pass up for handling */
inputstate |= INS_DLE_char;
break; break;
} }
*__skb_put(skb, 1) = bitrev8(c);
} }
if (unlikely(!numbytes)) /* regular data byte: append to current skb */
break; inputstate |= INS_have_data;
c = *src++; *__skb_put(skb, 1) = bitrev8(c);
--numbytes;
if (unlikely(c == DLE_FLAG &&
(cs->dle ||
inbuf->inputstate & INS_DLE_command))) {
inbuf->inputstate |= INS_DLE_char;
break;
}
} }
/* pass data up */ /* pass data up */
if (likely(inputstate & INS_have_data)) { if (inputstate & INS_have_data) {
if (likely(!(inputstate & INS_skip_frame))) { gigaset_skb_rcvd(bcs, skb);
gigaset_rcv_skb(skb, cs, bcs); inputstate &= ~INS_have_data;
} new_rcv_skb(bcs);
inputstate &= ~(INS_have_data | INS_skip_frame);
if (unlikely(bcs->ignore)) {
inputstate |= INS_skip_frame;
skb = NULL;
} else if (likely((skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN))
!= NULL)) {
skb_reserve(skb, HW_HDR_LEN);
} else {
dev_warn(cs->dev, "could not allocate new skb\n");
inputstate |= INS_skip_frame;
}
} }
bcs->inputstate = inputstate; bcs->inputstate = inputstate;
bcs->skb = skb; return procbytes;
return startbytes - numbytes; }
/* process DLE escapes
* Called whenever a DLE sequence might be encountered in the input stream.
* Either processes the entire DLE sequence or, if that isn't possible,
* notes the fact that an initial DLE has been received in the INS_DLE_char
* inputstate flag and resumes processing of the sequence on the next call.
*/
static void handle_dle(struct inbuf_t *inbuf)
{
struct cardstate *cs = inbuf->cs;
if (cs->mstate == MS_LOCKED)
return; /* no DLE processing in lock mode */
if (!(inbuf->inputstate & INS_DLE_char)) {
/* no DLE pending */
if (inbuf->data[inbuf->head] == DLE_FLAG &&
(cs->dle || inbuf->inputstate & INS_DLE_command)) {
/* start of DLE sequence */
inbuf->head++;
if (inbuf->head == inbuf->tail ||
inbuf->head == RBUFSIZE) {
/* end of buffer, save for later processing */
inbuf->inputstate |= INS_DLE_char;
return;
}
} else {
/* regular data byte */
return;
}
}
/* consume pending DLE */
inbuf->inputstate &= ~INS_DLE_char;
switch (inbuf->data[inbuf->head]) {
case 'X': /* begin of event message */
if (inbuf->inputstate & INS_command)
dev_notice(cs->dev,
"received <DLE>X in command mode\n");
inbuf->inputstate |= INS_command | INS_DLE_command;
inbuf->head++; /* byte consumed */
break;
case '.': /* end of event message */
if (!(inbuf->inputstate & INS_DLE_command))
dev_notice(cs->dev,
"received <DLE>. without <DLE>X\n");
inbuf->inputstate &= ~INS_DLE_command;
/* return to data mode if in DLE mode */
if (cs->dle)
inbuf->inputstate &= ~INS_command;
inbuf->head++; /* byte consumed */
break;
case DLE_FLAG: /* DLE in data stream */
/* mark as quoted */
inbuf->inputstate |= INS_DLE_char;
if (!(cs->dle || inbuf->inputstate & INS_DLE_command))
dev_notice(cs->dev,
"received <DLE><DLE> not in DLE mode\n");
break; /* quoted byte left in buffer */
default:
dev_notice(cs->dev, "received <DLE><%02x>\n",
inbuf->data[inbuf->head]);
/* quoted byte left in buffer */
}
} }
/** /**
@ -345,94 +425,39 @@ static inline int iraw_loop(unsigned char c, unsigned char *src, int numbytes,
*/ */
void gigaset_m10x_input(struct inbuf_t *inbuf) void gigaset_m10x_input(struct inbuf_t *inbuf)
{ {
struct cardstate *cs; struct cardstate *cs = inbuf->cs;
unsigned tail, head, numbytes; unsigned numbytes, procbytes;
unsigned char *src, c;
int procbytes;
head = inbuf->head; gig_dbg(DEBUG_INTR, "buffer state: %u -> %u", inbuf->head, inbuf->tail);
tail = inbuf->tail;
gig_dbg(DEBUG_INTR, "buffer state: %u -> %u", head, tail);
if (head != tail) { while (inbuf->head != inbuf->tail) {
cs = inbuf->cs; /* check for DLE escape */
src = inbuf->data + head; handle_dle(inbuf);
numbytes = (head > tail ? RBUFSIZE : tail) - head;
/* process a contiguous block of bytes */
numbytes = (inbuf->head > inbuf->tail ?
RBUFSIZE : inbuf->tail) - inbuf->head;
gig_dbg(DEBUG_INTR, "processing %u bytes", numbytes); gig_dbg(DEBUG_INTR, "processing %u bytes", numbytes);
/*
* numbytes may be 0 if handle_dle() ate the last byte.
* This does no harm, *_loop() will just return 0 immediately.
*/
while (numbytes) { if (cs->mstate == MS_LOCKED)
if (cs->mstate == MS_LOCKED) { procbytes = lock_loop(numbytes, inbuf);
procbytes = lock_loop(src, numbytes, inbuf); else if (inbuf->inputstate & INS_command)
src += procbytes; procbytes = cmd_loop(numbytes, inbuf);
numbytes -= procbytes; else if (cs->bcs->proto2 == L2_HDLC)
} else { procbytes = hdlc_loop(numbytes, inbuf);
c = *src++; else
--numbytes; procbytes = iraw_loop(numbytes, inbuf);
if (c == DLE_FLAG && (cs->dle || inbuf->head += procbytes;
inbuf->inputstate & INS_DLE_command)) {
if (!(inbuf->inputstate & INS_DLE_char)) {
inbuf->inputstate |= INS_DLE_char;
goto nextbyte;
}
/* <DLE> <DLE> => <DLE> in data stream */
inbuf->inputstate &= ~INS_DLE_char;
}
if (!(inbuf->inputstate & INS_DLE_char)) { /* check for buffer wraparound */
if (inbuf->head >= RBUFSIZE)
inbuf->head = 0;
/* FIXME use function pointers? */ gig_dbg(DEBUG_INTR, "head set to %u", inbuf->head);
if (inbuf->inputstate & INS_command)
procbytes = cmd_loop(c, src, numbytes, inbuf);
else if (inbuf->bcs->proto2 == ISDN_PROTO_L2_HDLC)
procbytes = hdlc_loop(c, src, numbytes, inbuf);
else
procbytes = iraw_loop(c, src, numbytes, inbuf);
src += procbytes;
numbytes -= procbytes;
} else { /* DLE char */
inbuf->inputstate &= ~INS_DLE_char;
switch (c) {
case 'X': /*begin of command*/
if (inbuf->inputstate & INS_command)
dev_warn(cs->dev,
"received <DLE> 'X' in command mode\n");
inbuf->inputstate |=
INS_command | INS_DLE_command;
break;
case '.': /*end of command*/
if (!(inbuf->inputstate & INS_command))
dev_warn(cs->dev,
"received <DLE> '.' in hdlc mode\n");
inbuf->inputstate &= cs->dle ?
~(INS_DLE_command|INS_command)
: ~INS_DLE_command;
break;
//case DLE_FLAG: /*DLE_FLAG in data stream*/ /* schon oben behandelt! */
default:
dev_err(cs->dev,
"received 0x10 0x%02x!\n",
(int) c);
/* FIXME: reset driver?? */
}
}
}
nextbyte:
if (!numbytes) {
/* end of buffer, check for wrap */
if (head > tail) {
head = 0;
src = inbuf->data;
numbytes = tail;
} else {
head = tail;
break;
}
}
}
gig_dbg(DEBUG_INTR, "setting head to %u", head);
inbuf->head = head;
} }
} }
EXPORT_SYMBOL_GPL(gigaset_m10x_input); EXPORT_SYMBOL_GPL(gigaset_m10x_input);
@ -440,16 +465,16 @@ EXPORT_SYMBOL_GPL(gigaset_m10x_input);
/* == data output ========================================================== */ /* == data output ========================================================== */
/* Encoding of a PPP packet into an octet stuffed HDLC frame /*
* with FCS, opening and closing flags. * Encode a data packet into an octet stuffed HDLC frame with FCS,
* opening and closing flags, preserving headroom data.
* parameters: * parameters:
* skb skb containing original packet (freed upon return) * skb skb containing original packet (freed upon return)
* head number of headroom bytes to allocate in result skb
* tail number of tailroom bytes to allocate in result skb
* Return value: * Return value:
* pointer to newly allocated skb containing the result frame * pointer to newly allocated skb containing the result frame
* and the original link layer header, NULL on error
*/ */
static struct sk_buff *HDLC_Encode(struct sk_buff *skb, int head, int tail) static struct sk_buff *HDLC_Encode(struct sk_buff *skb)
{ {
struct sk_buff *hdlc_skb; struct sk_buff *hdlc_skb;
__u16 fcs; __u16 fcs;
@ -471,16 +496,19 @@ static struct sk_buff *HDLC_Encode(struct sk_buff *skb, int head, int tail)
/* size of new buffer: original size + number of stuffing bytes /* size of new buffer: original size + number of stuffing bytes
* + 2 bytes FCS + 2 stuffing bytes for FCS (if needed) + 2 flag bytes * + 2 bytes FCS + 2 stuffing bytes for FCS (if needed) + 2 flag bytes
* + room for link layer header
*/ */
hdlc_skb = dev_alloc_skb(skb->len + stuf_cnt + 6 + tail + head); hdlc_skb = dev_alloc_skb(skb->len + stuf_cnt + 6 + skb->mac_len);
if (!hdlc_skb) { if (!hdlc_skb) {
dev_kfree_skb(skb); dev_kfree_skb_any(skb);
return NULL; return NULL;
} }
skb_reserve(hdlc_skb, head);
/* Copy acknowledge request into new skb */ /* Copy link layer header into new skb */
memcpy(hdlc_skb->head, skb->head, 2); skb_reset_mac_header(hdlc_skb);
skb_reserve(hdlc_skb, skb->mac_len);
memcpy(skb_mac_header(hdlc_skb), skb_mac_header(skb), skb->mac_len);
hdlc_skb->mac_len = skb->mac_len;
/* Add flag sequence in front of everything.. */ /* Add flag sequence in front of everything.. */
*(skb_put(hdlc_skb, 1)) = PPP_FLAG; *(skb_put(hdlc_skb, 1)) = PPP_FLAG;
@ -511,33 +539,42 @@ static struct sk_buff *HDLC_Encode(struct sk_buff *skb, int head, int tail)
*(skb_put(hdlc_skb, 1)) = PPP_FLAG; *(skb_put(hdlc_skb, 1)) = PPP_FLAG;
dev_kfree_skb(skb); dev_kfree_skb_any(skb);
return hdlc_skb; return hdlc_skb;
} }
/* Encoding of a raw packet into an octet stuffed bit inverted frame /*
* Encode a data packet into an octet stuffed raw bit inverted frame,
* preserving headroom data.
* parameters: * parameters:
* skb skb containing original packet (freed upon return) * skb skb containing original packet (freed upon return)
* head number of headroom bytes to allocate in result skb
* tail number of tailroom bytes to allocate in result skb
* Return value: * Return value:
* pointer to newly allocated skb containing the result frame * pointer to newly allocated skb containing the result frame
* and the original link layer header, NULL on error
*/ */
static struct sk_buff *iraw_encode(struct sk_buff *skb, int head, int tail) static struct sk_buff *iraw_encode(struct sk_buff *skb)
{ {
struct sk_buff *iraw_skb; struct sk_buff *iraw_skb;
unsigned char c; unsigned char c;
unsigned char *cp; unsigned char *cp;
int len; int len;
/* worst case: every byte must be stuffed */ /* size of new buffer (worst case = every byte must be stuffed):
iraw_skb = dev_alloc_skb(2*skb->len + tail + head); * 2 * original size + room for link layer header
*/
iraw_skb = dev_alloc_skb(2*skb->len + skb->mac_len);
if (!iraw_skb) { if (!iraw_skb) {
dev_kfree_skb(skb); dev_kfree_skb_any(skb);
return NULL; return NULL;
} }
skb_reserve(iraw_skb, head);
/* copy link layer header into new skb */
skb_reset_mac_header(iraw_skb);
skb_reserve(iraw_skb, skb->mac_len);
memcpy(skb_mac_header(iraw_skb), skb_mac_header(skb), skb->mac_len);
iraw_skb->mac_len = skb->mac_len;
/* copy and stuff data */
cp = skb->data; cp = skb->data;
len = skb->len; len = skb->len;
while (len--) { while (len--) {
@ -546,7 +583,7 @@ static struct sk_buff *iraw_encode(struct sk_buff *skb, int head, int tail)
*(skb_put(iraw_skb, 1)) = c; *(skb_put(iraw_skb, 1)) = c;
*(skb_put(iraw_skb, 1)) = c; *(skb_put(iraw_skb, 1)) = c;
} }
dev_kfree_skb(skb); dev_kfree_skb_any(skb);
return iraw_skb; return iraw_skb;
} }
@ -555,8 +592,10 @@ static struct sk_buff *iraw_encode(struct sk_buff *skb, int head, int tail)
* @bcs: B channel descriptor structure. * @bcs: B channel descriptor structure.
* @skb: data to send. * @skb: data to send.
* *
* Called by i4l.c to encode and queue an skb for sending, and start * Called by LL to encode and queue an skb for sending, and start
* transmission if necessary. * transmission if necessary.
* Once the payload data has been transmitted completely, gigaset_skb_sent()
* will be called with the skb's link layer header preserved.
* *
* Return value: * Return value:
* number of bytes accepted for sending (skb->len) if ok, * number of bytes accepted for sending (skb->len) if ok,
@ -564,24 +603,25 @@ static struct sk_buff *iraw_encode(struct sk_buff *skb, int head, int tail)
*/ */
int gigaset_m10x_send_skb(struct bc_state *bcs, struct sk_buff *skb) int gigaset_m10x_send_skb(struct bc_state *bcs, struct sk_buff *skb)
{ {
struct cardstate *cs = bcs->cs;
unsigned len = skb->len; unsigned len = skb->len;
unsigned long flags; unsigned long flags;
if (bcs->proto2 == ISDN_PROTO_L2_HDLC) if (bcs->proto2 == L2_HDLC)
skb = HDLC_Encode(skb, HW_HDR_LEN, 0); skb = HDLC_Encode(skb);
else else
skb = iraw_encode(skb, HW_HDR_LEN, 0); skb = iraw_encode(skb);
if (!skb) { if (!skb) {
dev_err(bcs->cs->dev, dev_err(cs->dev,
"unable to allocate memory for encoding!\n"); "unable to allocate memory for encoding!\n");
return -ENOMEM; return -ENOMEM;
} }
skb_queue_tail(&bcs->squeue, skb); skb_queue_tail(&bcs->squeue, skb);
spin_lock_irqsave(&bcs->cs->lock, flags); spin_lock_irqsave(&cs->lock, flags);
if (bcs->cs->connected) if (cs->connected)
tasklet_schedule(&bcs->cs->write_tasklet); tasklet_schedule(&cs->write_tasklet);
spin_unlock_irqrestore(&bcs->cs->lock, flags); spin_unlock_irqrestore(&cs->lock, flags);
return len; /* ok so far */ return len; /* ok so far */
} }

View File

@ -57,7 +57,7 @@ MODULE_PARM_DESC(cidmode, "Call-ID mode");
#define USB_SX353_PRODUCT_ID 0x0022 #define USB_SX353_PRODUCT_ID 0x0022
/* table of devices that work with this driver */ /* table of devices that work with this driver */
static const struct usb_device_id gigaset_table [] = { static const struct usb_device_id gigaset_table[] = {
{ USB_DEVICE(USB_GIGA_VENDOR_ID, USB_3070_PRODUCT_ID) }, { USB_DEVICE(USB_GIGA_VENDOR_ID, USB_3070_PRODUCT_ID) },
{ USB_DEVICE(USB_GIGA_VENDOR_ID, USB_3075_PRODUCT_ID) }, { USB_DEVICE(USB_GIGA_VENDOR_ID, USB_3075_PRODUCT_ID) },
{ USB_DEVICE(USB_GIGA_VENDOR_ID, USB_SX303_PRODUCT_ID) }, { USB_DEVICE(USB_GIGA_VENDOR_ID, USB_SX303_PRODUCT_ID) },
@ -137,7 +137,7 @@ struct bas_cardstate {
#define BS_RESETTING 0x200 /* waiting for HD_RESET_INTERRUPT_PIPE_ACK */ #define BS_RESETTING 0x200 /* waiting for HD_RESET_INTERRUPT_PIPE_ACK */
static struct gigaset_driver *driver = NULL; static struct gigaset_driver *driver;
/* usb specific object needed to register this driver with the usb subsystem */ /* usb specific object needed to register this driver with the usb subsystem */
static struct usb_driver gigaset_usb_driver = { static struct usb_driver gigaset_usb_driver = {
@ -601,11 +601,12 @@ static int atread_submit(struct cardstate *cs, int timeout)
ucs->dr_cmd_in.wLength = cpu_to_le16(ucs->rcvbuf_size); ucs->dr_cmd_in.wLength = cpu_to_le16(ucs->rcvbuf_size);
usb_fill_control_urb(ucs->urb_cmd_in, ucs->udev, usb_fill_control_urb(ucs->urb_cmd_in, ucs->udev,
usb_rcvctrlpipe(ucs->udev, 0), usb_rcvctrlpipe(ucs->udev, 0),
(unsigned char*) & ucs->dr_cmd_in, (unsigned char *) &ucs->dr_cmd_in,
ucs->rcvbuf, ucs->rcvbuf_size, ucs->rcvbuf, ucs->rcvbuf_size,
read_ctrl_callback, cs->inbuf); read_ctrl_callback, cs->inbuf);
if ((ret = usb_submit_urb(ucs->urb_cmd_in, GFP_ATOMIC)) != 0) { ret = usb_submit_urb(ucs->urb_cmd_in, GFP_ATOMIC);
if (ret != 0) {
update_basstate(ucs, 0, BS_ATRDPEND); update_basstate(ucs, 0, BS_ATRDPEND);
dev_err(cs->dev, "could not submit HD_READ_ATMESSAGE: %s\n", dev_err(cs->dev, "could not submit HD_READ_ATMESSAGE: %s\n",
get_usb_rcmsg(ret)); get_usb_rcmsg(ret));
@ -652,13 +653,11 @@ static void read_int_callback(struct urb *urb)
return; return;
case -ENODEV: /* device removed */ case -ENODEV: /* device removed */
case -ESHUTDOWN: /* device shut down */ case -ESHUTDOWN: /* device shut down */
//FIXME use this as disconnect indicator?
gig_dbg(DEBUG_USBREQ, "%s: device disconnected", __func__); gig_dbg(DEBUG_USBREQ, "%s: device disconnected", __func__);
return; return;
default: /* severe trouble */ default: /* severe trouble */
dev_warn(cs->dev, "interrupt read: %s\n", dev_warn(cs->dev, "interrupt read: %s\n",
get_usb_statmsg(status)); get_usb_statmsg(status));
//FIXME corrective action? resubmission always ok?
goto resubmit; goto resubmit;
} }
@ -742,7 +741,8 @@ static void read_int_callback(struct urb *urb)
kfree(ucs->rcvbuf); kfree(ucs->rcvbuf);
ucs->rcvbuf_size = 0; ucs->rcvbuf_size = 0;
} }
if ((ucs->rcvbuf = kmalloc(l, GFP_ATOMIC)) == NULL) { ucs->rcvbuf = kmalloc(l, GFP_ATOMIC);
if (ucs->rcvbuf == NULL) {
spin_unlock_irqrestore(&cs->lock, flags); spin_unlock_irqrestore(&cs->lock, flags);
dev_err(cs->dev, "out of memory receiving AT data\n"); dev_err(cs->dev, "out of memory receiving AT data\n");
error_reset(cs); error_reset(cs);
@ -750,12 +750,12 @@ static void read_int_callback(struct urb *urb)
} }
ucs->rcvbuf_size = l; ucs->rcvbuf_size = l;
ucs->retry_cmd_in = 0; ucs->retry_cmd_in = 0;
if ((rc = atread_submit(cs, BAS_TIMEOUT)) < 0) { rc = atread_submit(cs, BAS_TIMEOUT);
if (rc < 0) {
kfree(ucs->rcvbuf); kfree(ucs->rcvbuf);
ucs->rcvbuf = NULL; ucs->rcvbuf = NULL;
ucs->rcvbuf_size = 0; ucs->rcvbuf_size = 0;
if (rc != -ENODEV) { if (rc != -ENODEV) {
//FIXME corrective action?
spin_unlock_irqrestore(&cs->lock, flags); spin_unlock_irqrestore(&cs->lock, flags);
error_reset(cs); error_reset(cs);
break; break;
@ -911,7 +911,7 @@ static int starturbs(struct bc_state *bcs)
int rc; int rc;
/* initialize L2 reception */ /* initialize L2 reception */
if (bcs->proto2 == ISDN_PROTO_L2_HDLC) if (bcs->proto2 == L2_HDLC)
bcs->inputstate |= INS_flag_hunt; bcs->inputstate |= INS_flag_hunt;
/* submit all isochronous input URBs */ /* submit all isochronous input URBs */
@ -940,7 +940,8 @@ static int starturbs(struct bc_state *bcs)
} }
dump_urb(DEBUG_ISO, "Initial isoc read", urb); dump_urb(DEBUG_ISO, "Initial isoc read", urb);
if ((rc = usb_submit_urb(urb, GFP_ATOMIC)) != 0) rc = usb_submit_urb(urb, GFP_ATOMIC);
if (rc != 0)
goto error; goto error;
} }
@ -1045,7 +1046,8 @@ static int submit_iso_write_urb(struct isow_urbctx_t *ucx)
/* compute frame length according to flow control */ /* compute frame length according to flow control */
ifd->length = BAS_NORMFRAME; ifd->length = BAS_NORMFRAME;
if ((corrbytes = atomic_read(&ubc->corrbytes)) != 0) { corrbytes = atomic_read(&ubc->corrbytes);
if (corrbytes != 0) {
gig_dbg(DEBUG_ISO, "%s: corrbytes=%d", gig_dbg(DEBUG_ISO, "%s: corrbytes=%d",
__func__, corrbytes); __func__, corrbytes);
if (corrbytes > BAS_HIGHFRAME - BAS_NORMFRAME) if (corrbytes > BAS_HIGHFRAME - BAS_NORMFRAME)
@ -1064,7 +1066,7 @@ static int submit_iso_write_urb(struct isow_urbctx_t *ucx)
"%s: buffer busy at frame %d", "%s: buffer busy at frame %d",
__func__, nframe); __func__, nframe);
/* tasklet will be restarted from /* tasklet will be restarted from
gigaset_send_skb() */ gigaset_isoc_send_skb() */
} else { } else {
dev_err(ucx->bcs->cs->dev, dev_err(ucx->bcs->cs->dev,
"%s: buffer error %d at frame %d\n", "%s: buffer error %d at frame %d\n",
@ -1284,7 +1286,8 @@ static void read_iso_tasklet(unsigned long data)
for (;;) { for (;;) {
/* retrieve URB */ /* retrieve URB */
spin_lock_irqsave(&ubc->isoinlock, flags); spin_lock_irqsave(&ubc->isoinlock, flags);
if (!(urb = ubc->isoindone)) { urb = ubc->isoindone;
if (!urb) {
spin_unlock_irqrestore(&ubc->isoinlock, flags); spin_unlock_irqrestore(&ubc->isoinlock, flags);
return; return;
} }
@ -1371,7 +1374,7 @@ static void read_iso_tasklet(unsigned long data)
"isochronous read: %d data bytes missing\n", "isochronous read: %d data bytes missing\n",
totleft); totleft);
error: error:
/* URB processed, resubmit */ /* URB processed, resubmit */
for (frame = 0; frame < BAS_NUMFRAMES; frame++) { for (frame = 0; frame < BAS_NUMFRAMES; frame++) {
urb->iso_frame_desc[frame].status = 0; urb->iso_frame_desc[frame].status = 0;
@ -1568,7 +1571,7 @@ static int req_submit(struct bc_state *bcs, int req, int val, int timeout)
ucs->dr_ctrl.wLength = 0; ucs->dr_ctrl.wLength = 0;
usb_fill_control_urb(ucs->urb_ctrl, ucs->udev, usb_fill_control_urb(ucs->urb_ctrl, ucs->udev,
usb_sndctrlpipe(ucs->udev, 0), usb_sndctrlpipe(ucs->udev, 0),
(unsigned char*) &ucs->dr_ctrl, NULL, 0, (unsigned char *) &ucs->dr_ctrl, NULL, 0,
write_ctrl_callback, ucs); write_ctrl_callback, ucs);
ucs->retry_ctrl = 0; ucs->retry_ctrl = 0;
ret = usb_submit_urb(ucs->urb_ctrl, GFP_ATOMIC); ret = usb_submit_urb(ucs->urb_ctrl, GFP_ATOMIC);
@ -1621,7 +1624,8 @@ static int gigaset_init_bchannel(struct bc_state *bcs)
return -EHOSTUNREACH; return -EHOSTUNREACH;
} }
if ((ret = starturbs(bcs)) < 0) { ret = starturbs(bcs);
if (ret < 0) {
dev_err(cs->dev, dev_err(cs->dev,
"could not start isochronous I/O for channel B%d: %s\n", "could not start isochronous I/O for channel B%d: %s\n",
bcs->channel + 1, bcs->channel + 1,
@ -1633,7 +1637,8 @@ static int gigaset_init_bchannel(struct bc_state *bcs)
} }
req = bcs->channel ? HD_OPEN_B2CHANNEL : HD_OPEN_B1CHANNEL; req = bcs->channel ? HD_OPEN_B2CHANNEL : HD_OPEN_B1CHANNEL;
if ((ret = req_submit(bcs, req, 0, BAS_TIMEOUT)) < 0) { ret = req_submit(bcs, req, 0, BAS_TIMEOUT);
if (ret < 0) {
dev_err(cs->dev, "could not open channel B%d\n", dev_err(cs->dev, "could not open channel B%d\n",
bcs->channel + 1); bcs->channel + 1);
stopurbs(bcs->hw.bas); stopurbs(bcs->hw.bas);
@ -1677,7 +1682,8 @@ static int gigaset_close_bchannel(struct bc_state *bcs)
/* channel running: tell device to close it */ /* channel running: tell device to close it */
req = bcs->channel ? HD_CLOSE_B2CHANNEL : HD_CLOSE_B1CHANNEL; req = bcs->channel ? HD_CLOSE_B2CHANNEL : HD_CLOSE_B1CHANNEL;
if ((ret = req_submit(bcs, req, 0, BAS_TIMEOUT)) < 0) ret = req_submit(bcs, req, 0, BAS_TIMEOUT);
if (ret < 0)
dev_err(cs->dev, "closing channel B%d failed\n", dev_err(cs->dev, "closing channel B%d failed\n",
bcs->channel + 1); bcs->channel + 1);
@ -1703,10 +1709,12 @@ static void complete_cb(struct cardstate *cs)
gig_dbg(DEBUG_TRANSCMD|DEBUG_LOCKCMD, gig_dbg(DEBUG_TRANSCMD|DEBUG_LOCKCMD,
"write_command: sent %u bytes, %u left", "write_command: sent %u bytes, %u left",
cs->curlen, cs->cmdbytes); cs->curlen, cs->cmdbytes);
if ((cs->cmdbuf = cb->next) != NULL) { if (cb->next != NULL) {
cs->cmdbuf = cb->next;
cs->cmdbuf->prev = NULL; cs->cmdbuf->prev = NULL;
cs->curlen = cs->cmdbuf->len; cs->curlen = cs->cmdbuf->len;
} else { } else {
cs->cmdbuf = NULL;
cs->lastcmdbuf = NULL; cs->lastcmdbuf = NULL;
cs->curlen = 0; cs->curlen = 0;
} }
@ -1833,7 +1841,7 @@ static int atwrite_submit(struct cardstate *cs, unsigned char *buf, int len)
ucs->dr_cmd_out.wLength = cpu_to_le16(len); ucs->dr_cmd_out.wLength = cpu_to_le16(len);
usb_fill_control_urb(ucs->urb_cmd_out, ucs->udev, usb_fill_control_urb(ucs->urb_cmd_out, ucs->udev,
usb_sndctrlpipe(ucs->udev, 0), usb_sndctrlpipe(ucs->udev, 0),
(unsigned char*) &ucs->dr_cmd_out, buf, len, (unsigned char *) &ucs->dr_cmd_out, buf, len,
write_command_callback, cs); write_command_callback, cs);
rc = usb_submit_urb(ucs->urb_cmd_out, GFP_ATOMIC); rc = usb_submit_urb(ucs->urb_cmd_out, GFP_ATOMIC);
if (unlikely(rc)) { if (unlikely(rc)) {
@ -1953,7 +1961,8 @@ static int gigaset_write_cmd(struct cardstate *cs,
if (len > IF_WRITEBUF) if (len > IF_WRITEBUF)
len = IF_WRITEBUF; len = IF_WRITEBUF;
if (!(cb = kmalloc(sizeof(struct cmdbuf_t) + len, GFP_ATOMIC))) { cb = kmalloc(sizeof(struct cmdbuf_t) + len, GFP_ATOMIC);
if (!cb) {
dev_err(cs->dev, "%s: out of memory\n", __func__); dev_err(cs->dev, "%s: out of memory\n", __func__);
rc = -ENOMEM; rc = -ENOMEM;
goto notqueued; goto notqueued;
@ -2100,14 +2109,15 @@ static int gigaset_initbcshw(struct bc_state *bcs)
} }
ubc->isooutdone = ubc->isooutfree = ubc->isooutovfl = NULL; ubc->isooutdone = ubc->isooutfree = ubc->isooutovfl = NULL;
ubc->numsub = 0; ubc->numsub = 0;
if (!(ubc->isooutbuf = kmalloc(sizeof(struct isowbuf_t), GFP_KERNEL))) { ubc->isooutbuf = kmalloc(sizeof(struct isowbuf_t), GFP_KERNEL);
if (!ubc->isooutbuf) {
pr_err("out of memory\n"); pr_err("out of memory\n");
kfree(ubc); kfree(ubc);
bcs->hw.bas = NULL; bcs->hw.bas = NULL;
return 0; return 0;
} }
tasklet_init(&ubc->sent_tasklet, tasklet_init(&ubc->sent_tasklet,
&write_iso_tasklet, (unsigned long) bcs); write_iso_tasklet, (unsigned long) bcs);
spin_lock_init(&ubc->isoinlock); spin_lock_init(&ubc->isoinlock);
for (i = 0; i < BAS_INURBS; ++i) for (i = 0; i < BAS_INURBS; ++i)
@ -2128,7 +2138,7 @@ static int gigaset_initbcshw(struct bc_state *bcs)
ubc->shared0s = 0; ubc->shared0s = 0;
ubc->stolen0s = 0; ubc->stolen0s = 0;
tasklet_init(&ubc->rcvd_tasklet, tasklet_init(&ubc->rcvd_tasklet,
&read_iso_tasklet, (unsigned long) bcs); read_iso_tasklet, (unsigned long) bcs);
return 1; return 1;
} }
@ -2252,7 +2262,8 @@ static int gigaset_probe(struct usb_interface *interface,
gig_dbg(DEBUG_ANY, gig_dbg(DEBUG_ANY,
"%s: wrong alternate setting %d - trying to switch", "%s: wrong alternate setting %d - trying to switch",
__func__, hostif->desc.bAlternateSetting); __func__, hostif->desc.bAlternateSetting);
if (usb_set_interface(udev, hostif->desc.bInterfaceNumber, 3) < 0) { if (usb_set_interface(udev, hostif->desc.bInterfaceNumber, 3)
< 0) {
dev_warn(&udev->dev, "usb_set_interface failed, " dev_warn(&udev->dev, "usb_set_interface failed, "
"device %d interface %d altsetting %d\n", "device %d interface %d altsetting %d\n",
udev->devnum, hostif->desc.bInterfaceNumber, udev->devnum, hostif->desc.bInterfaceNumber,
@ -2321,14 +2332,16 @@ static int gigaset_probe(struct usb_interface *interface,
(endpoint->bEndpointAddress) & 0x0f), (endpoint->bEndpointAddress) & 0x0f),
ucs->int_in_buf, IP_MSGSIZE, read_int_callback, cs, ucs->int_in_buf, IP_MSGSIZE, read_int_callback, cs,
endpoint->bInterval); endpoint->bInterval);
if ((rc = usb_submit_urb(ucs->urb_int_in, GFP_KERNEL)) != 0) { rc = usb_submit_urb(ucs->urb_int_in, GFP_KERNEL);
if (rc != 0) {
dev_err(cs->dev, "could not submit interrupt URB: %s\n", dev_err(cs->dev, "could not submit interrupt URB: %s\n",
get_usb_rcmsg(rc)); get_usb_rcmsg(rc));
goto error; goto error;
} }
/* tell the device that the driver is ready */ /* tell the device that the driver is ready */
if ((rc = req_submit(cs->bcs, HD_DEVICE_INIT_ACK, 0, 0)) != 0) rc = req_submit(cs->bcs, HD_DEVICE_INIT_ACK, 0, 0);
if (rc != 0)
goto error; goto error;
/* tell common part that the device is ready */ /* tell common part that the device is ready */
@ -2524,9 +2537,10 @@ static int __init bas_gigaset_init(void)
int result; int result;
/* allocate memory for our driver state and intialize it */ /* allocate memory for our driver state and intialize it */
if ((driver = gigaset_initdriver(GIGASET_MINOR, GIGASET_MINORS, driver = gigaset_initdriver(GIGASET_MINOR, GIGASET_MINORS,
GIGASET_MODULENAME, GIGASET_DEVNAME, GIGASET_MODULENAME, GIGASET_DEVNAME,
&gigops, THIS_MODULE)) == NULL) &gigops, THIS_MODULE);
if (driver == NULL)
goto error; goto error;
/* register this driver with the USB subsystem */ /* register this driver with the USB subsystem */

2292
drivers/isdn/gigaset/capi.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -108,7 +108,7 @@ int gigaset_enterconfigmode(struct cardstate *cs)
{ {
int i, r; int i, r;
cs->control_state = TIOCM_RTS; //FIXME cs->control_state = TIOCM_RTS;
r = setflags(cs, TIOCM_DTR, 200); r = setflags(cs, TIOCM_DTR, 200);
if (r < 0) if (r < 0)
@ -132,10 +132,10 @@ int gigaset_enterconfigmode(struct cardstate *cs)
error: error:
dev_err(cs->dev, "error %d on setuartbits\n", -r); dev_err(cs->dev, "error %d on setuartbits\n", -r);
cs->control_state = TIOCM_RTS|TIOCM_DTR; // FIXME is this a good value? cs->control_state = TIOCM_RTS|TIOCM_DTR;
cs->ops->set_modem_ctrl(cs, 0, TIOCM_RTS|TIOCM_DTR); cs->ops->set_modem_ctrl(cs, 0, TIOCM_RTS|TIOCM_DTR);
return -1; //r return -1;
} }
static int test_timeout(struct at_state_t *at_state) static int test_timeout(struct at_state_t *at_state)
@ -150,10 +150,9 @@ static int test_timeout(struct at_state_t *at_state)
} }
if (!gigaset_add_event(at_state->cs, at_state, EV_TIMEOUT, NULL, if (!gigaset_add_event(at_state->cs, at_state, EV_TIMEOUT, NULL,
at_state->timer_index, NULL)) { at_state->timer_index, NULL))
//FIXME what should we do? dev_err(at_state->cs->dev, "%s: out of memory\n",
} __func__);
return 1; return 1;
} }
@ -207,6 +206,32 @@ int gigaset_get_channel(struct bc_state *bcs)
return 1; return 1;
} }
struct bc_state *gigaset_get_free_channel(struct cardstate *cs)
{
unsigned long flags;
int i;
spin_lock_irqsave(&cs->lock, flags);
if (!try_module_get(cs->driver->owner)) {
gig_dbg(DEBUG_ANY,
"could not get module for allocating channel");
spin_unlock_irqrestore(&cs->lock, flags);
return NULL;
}
for (i = 0; i < cs->channels; ++i)
if (!cs->bcs[i].use_count) {
++cs->bcs[i].use_count;
cs->bcs[i].busy = 1;
spin_unlock_irqrestore(&cs->lock, flags);
gig_dbg(DEBUG_ANY, "allocated channel %d", i);
return cs->bcs + i;
}
module_put(cs->driver->owner);
spin_unlock_irqrestore(&cs->lock, flags);
gig_dbg(DEBUG_ANY, "no free channel");
return NULL;
}
void gigaset_free_channel(struct bc_state *bcs) void gigaset_free_channel(struct bc_state *bcs)
{ {
unsigned long flags; unsigned long flags;
@ -367,16 +392,15 @@ static void gigaset_freebcs(struct bc_state *bcs)
int i; int i;
gig_dbg(DEBUG_INIT, "freeing bcs[%d]->hw", bcs->channel); gig_dbg(DEBUG_INIT, "freeing bcs[%d]->hw", bcs->channel);
if (!bcs->cs->ops->freebcshw(bcs)) { if (!bcs->cs->ops->freebcshw(bcs))
gig_dbg(DEBUG_INIT, "failed"); gig_dbg(DEBUG_INIT, "failed");
}
gig_dbg(DEBUG_INIT, "clearing bcs[%d]->at_state", bcs->channel); gig_dbg(DEBUG_INIT, "clearing bcs[%d]->at_state", bcs->channel);
clear_at_state(&bcs->at_state); clear_at_state(&bcs->at_state);
gig_dbg(DEBUG_INIT, "freeing bcs[%d]->skb", bcs->channel); gig_dbg(DEBUG_INIT, "freeing bcs[%d]->skb", bcs->channel);
dev_kfree_skb(bcs->skb);
bcs->skb = NULL;
if (bcs->skb)
dev_kfree_skb(bcs->skb);
for (i = 0; i < AT_NUM; ++i) { for (i = 0; i < AT_NUM; ++i) {
kfree(bcs->commands[i]); kfree(bcs->commands[i]);
bcs->commands[i] = NULL; bcs->commands[i] = NULL;
@ -463,6 +487,12 @@ void gigaset_freecs(struct cardstate *cs)
switch (cs->cs_init) { switch (cs->cs_init) {
default: default:
/* clear B channel structures */
for (i = 0; i < cs->channels; ++i) {
gig_dbg(DEBUG_INIT, "clearing bcs[%d]", i);
gigaset_freebcs(cs->bcs + i);
}
/* clear device sysfs */ /* clear device sysfs */
gigaset_free_dev_sysfs(cs); gigaset_free_dev_sysfs(cs);
@ -471,28 +501,20 @@ void gigaset_freecs(struct cardstate *cs)
gig_dbg(DEBUG_INIT, "clearing hw"); gig_dbg(DEBUG_INIT, "clearing hw");
cs->ops->freecshw(cs); cs->ops->freecshw(cs);
//FIXME cmdbuf
/* fall through */ /* fall through */
case 2: /* error in initcshw */ case 2: /* error in initcshw */
/* Deregister from LL */ /* Deregister from LL */
make_invalid(cs, VALID_ID); make_invalid(cs, VALID_ID);
gig_dbg(DEBUG_INIT, "clearing iif"); gigaset_isdn_unregister(cs);
gigaset_i4l_cmd(cs, ISDN_STAT_UNLOAD);
/* fall through */ /* fall through */
case 1: /* error when regestering to LL */ case 1: /* error when registering to LL */
gig_dbg(DEBUG_INIT, "clearing at_state"); gig_dbg(DEBUG_INIT, "clearing at_state");
clear_at_state(&cs->at_state); clear_at_state(&cs->at_state);
dealloc_at_states(cs); dealloc_at_states(cs);
/* fall through */ /* fall through */
case 0: /* error in one call to initbcs */ case 0: /* error in basic setup */
for (i = 0; i < cs->channels; ++i) {
gig_dbg(DEBUG_INIT, "clearing bcs[%d]", i);
gigaset_freebcs(cs->bcs + i);
}
clear_events(cs); clear_events(cs);
gig_dbg(DEBUG_INIT, "freeing inbuf"); gig_dbg(DEBUG_INIT, "freeing inbuf");
kfree(cs->inbuf); kfree(cs->inbuf);
@ -534,16 +556,13 @@ void gigaset_at_init(struct at_state_t *at_state, struct bc_state *bcs,
} }
static void gigaset_inbuf_init(struct inbuf_t *inbuf, struct bc_state *bcs, static void gigaset_inbuf_init(struct inbuf_t *inbuf, struct cardstate *cs)
struct cardstate *cs, int inputstate)
/* inbuf->read must be allocated before! */ /* inbuf->read must be allocated before! */
{ {
inbuf->head = 0; inbuf->head = 0;
inbuf->tail = 0; inbuf->tail = 0;
inbuf->cs = cs; inbuf->cs = cs;
inbuf->bcs = bcs; /*base driver: NULL*/ inbuf->inputstate = INS_command;
inbuf->rcvbuf = NULL;
inbuf->inputstate = inputstate;
} }
/** /**
@ -599,7 +618,7 @@ static struct bc_state *gigaset_initbcs(struct bc_state *bcs,
{ {
int i; int i;
bcs->tx_skb = NULL; //FIXME -> hw part bcs->tx_skb = NULL;
skb_queue_head_init(&bcs->squeue); skb_queue_head_init(&bcs->squeue);
@ -618,13 +637,13 @@ static struct bc_state *gigaset_initbcs(struct bc_state *bcs,
bcs->fcs = PPP_INITFCS; bcs->fcs = PPP_INITFCS;
bcs->inputstate = 0; bcs->inputstate = 0;
if (cs->ignoreframes) { if (cs->ignoreframes) {
bcs->inputstate |= INS_skip_frame;
bcs->skb = NULL; bcs->skb = NULL;
} else if ((bcs->skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL) } else {
skb_reserve(bcs->skb, HW_HDR_LEN); bcs->skb = dev_alloc_skb(SBUFSIZE + cs->hw_hdr_len);
else { if (bcs->skb != NULL)
pr_err("out of memory\n"); skb_reserve(bcs->skb, cs->hw_hdr_len);
bcs->inputstate |= INS_skip_frame; else
pr_err("out of memory\n");
} }
bcs->channel = channel; bcs->channel = channel;
@ -645,8 +664,8 @@ static struct bc_state *gigaset_initbcs(struct bc_state *bcs,
gig_dbg(DEBUG_INIT, " failed"); gig_dbg(DEBUG_INIT, " failed");
gig_dbg(DEBUG_INIT, " freeing bcs[%d]->skb", channel); gig_dbg(DEBUG_INIT, " freeing bcs[%d]->skb", channel);
if (bcs->skb) dev_kfree_skb(bcs->skb);
dev_kfree_skb(bcs->skb); bcs->skb = NULL;
return NULL; return NULL;
} }
@ -673,12 +692,13 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels,
int onechannel, int ignoreframes, int onechannel, int ignoreframes,
int cidmode, const char *modulename) int cidmode, const char *modulename)
{ {
struct cardstate *cs = NULL; struct cardstate *cs;
unsigned long flags; unsigned long flags;
int i; int i;
gig_dbg(DEBUG_INIT, "allocating cs"); gig_dbg(DEBUG_INIT, "allocating cs");
if (!(cs = alloc_cs(drv))) { cs = alloc_cs(drv);
if (!cs) {
pr_err("maximum number of devices exceeded\n"); pr_err("maximum number of devices exceeded\n");
return NULL; return NULL;
} }
@ -707,7 +727,7 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels,
cs->ev_tail = 0; cs->ev_tail = 0;
cs->ev_head = 0; cs->ev_head = 0;
tasklet_init(&cs->event_tasklet, &gigaset_handle_event, tasklet_init(&cs->event_tasklet, gigaset_handle_event,
(unsigned long) cs); (unsigned long) cs);
cs->commands_pending = 0; cs->commands_pending = 0;
cs->cur_at_seq = 0; cs->cur_at_seq = 0;
@ -726,14 +746,6 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels,
cs->mode = M_UNKNOWN; cs->mode = M_UNKNOWN;
cs->mstate = MS_UNINITIALIZED; cs->mstate = MS_UNINITIALIZED;
for (i = 0; i < channels; ++i) {
gig_dbg(DEBUG_INIT, "setting up bcs[%d].read", i);
if (!gigaset_initbcs(cs->bcs + i, cs, i)) {
pr_err("could not allocate channel %d data\n", i);
goto error;
}
}
++cs->cs_init; ++cs->cs_init;
gig_dbg(DEBUG_INIT, "setting up at_state"); gig_dbg(DEBUG_INIT, "setting up at_state");
@ -743,10 +755,7 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels,
cs->cbytes = 0; cs->cbytes = 0;
gig_dbg(DEBUG_INIT, "setting up inbuf"); gig_dbg(DEBUG_INIT, "setting up inbuf");
if (onechannel) { //FIXME distinction necessary? gigaset_inbuf_init(cs->inbuf, cs);
gigaset_inbuf_init(cs->inbuf, cs->bcs, cs, INS_command);
} else
gigaset_inbuf_init(cs->inbuf, NULL, cs, INS_command);
cs->connected = 0; cs->connected = 0;
cs->isdn_up = 0; cs->isdn_up = 0;
@ -758,7 +767,7 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels,
cs->cmdbytes = 0; cs->cmdbytes = 0;
gig_dbg(DEBUG_INIT, "setting up iif"); gig_dbg(DEBUG_INIT, "setting up iif");
if (!gigaset_register_to_LL(cs, modulename)) { if (!gigaset_isdn_register(cs, modulename)) {
pr_err("error registering ISDN device\n"); pr_err("error registering ISDN device\n");
goto error; goto error;
} }
@ -777,6 +786,15 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels,
/* set up device sysfs */ /* set up device sysfs */
gigaset_init_dev_sysfs(cs); gigaset_init_dev_sysfs(cs);
/* set up channel data structures */
for (i = 0; i < channels; ++i) {
gig_dbg(DEBUG_INIT, "setting up bcs[%d]", i);
if (!gigaset_initbcs(cs->bcs + i, cs, i)) {
pr_err("could not allocate channel %d data\n", i);
goto error;
}
}
spin_lock_irqsave(&cs->lock, flags); spin_lock_irqsave(&cs->lock, flags);
cs->running = 1; cs->running = 1;
spin_unlock_irqrestore(&cs->lock, flags); spin_unlock_irqrestore(&cs->lock, flags);
@ -824,9 +842,10 @@ void gigaset_bcs_reinit(struct bc_state *bcs)
bcs->chstate = 0; bcs->chstate = 0;
bcs->ignore = cs->ignoreframes; bcs->ignore = cs->ignoreframes;
if (bcs->ignore) if (bcs->ignore) {
bcs->inputstate |= INS_skip_frame; dev_kfree_skb(bcs->skb);
bcs->skb = NULL;
}
cs->ops->reinitbcshw(bcs); cs->ops->reinitbcshw(bcs);
} }
@ -847,8 +866,6 @@ static void cleanup_cs(struct cardstate *cs)
free_strings(&cs->at_state); free_strings(&cs->at_state);
gigaset_at_init(&cs->at_state, NULL, cs, 0); gigaset_at_init(&cs->at_state, NULL, cs, 0);
kfree(cs->inbuf->rcvbuf);
cs->inbuf->rcvbuf = NULL;
cs->inbuf->inputstate = INS_command; cs->inbuf->inputstate = INS_command;
cs->inbuf->head = 0; cs->inbuf->head = 0;
cs->inbuf->tail = 0; cs->inbuf->tail = 0;
@ -911,15 +928,13 @@ int gigaset_start(struct cardstate *cs)
cs->ops->baud_rate(cs, B115200); cs->ops->baud_rate(cs, B115200);
cs->ops->set_line_ctrl(cs, CS8); cs->ops->set_line_ctrl(cs, CS8);
cs->control_state = TIOCM_DTR|TIOCM_RTS; cs->control_state = TIOCM_DTR|TIOCM_RTS;
} else {
//FIXME use some saved values?
} }
cs->waiting = 1; cs->waiting = 1;
if (!gigaset_add_event(cs, &cs->at_state, EV_START, NULL, 0, NULL)) { if (!gigaset_add_event(cs, &cs->at_state, EV_START, NULL, 0, NULL)) {
cs->waiting = 0; cs->waiting = 0;
//FIXME what should we do? dev_err(cs->dev, "%s: out of memory\n", __func__);
goto error; goto error;
} }
@ -959,7 +974,7 @@ int gigaset_shutdown(struct cardstate *cs)
cs->waiting = 1; cs->waiting = 1;
if (!gigaset_add_event(cs, &cs->at_state, EV_SHUTDOWN, NULL, 0, NULL)) { if (!gigaset_add_event(cs, &cs->at_state, EV_SHUTDOWN, NULL, 0, NULL)) {
//FIXME what should we do? dev_err(cs->dev, "%s: out of memory\n", __func__);
goto exit; goto exit;
} }
@ -990,7 +1005,7 @@ void gigaset_stop(struct cardstate *cs)
cs->waiting = 1; cs->waiting = 1;
if (!gigaset_add_event(cs, &cs->at_state, EV_STOP, NULL, 0, NULL)) { if (!gigaset_add_event(cs, &cs->at_state, EV_STOP, NULL, 0, NULL)) {
//FIXME what should we do? dev_err(cs->dev, "%s: out of memory\n", __func__);
goto exit; goto exit;
} }

View File

@ -0,0 +1,68 @@
/*
* Dummy LL interface for the Gigaset driver
*
* Copyright (c) 2009 by Tilman Schmidt <tilman@imap.cc>.
*
* =====================================================================
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
* =====================================================================
*/
#include "gigaset.h"
void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb)
{
}
EXPORT_SYMBOL_GPL(gigaset_skb_sent);
void gigaset_skb_rcvd(struct bc_state *bcs, struct sk_buff *skb)
{
}
EXPORT_SYMBOL_GPL(gigaset_skb_rcvd);
void gigaset_isdn_rcv_err(struct bc_state *bcs)
{
}
EXPORT_SYMBOL_GPL(gigaset_isdn_rcv_err);
int gigaset_isdn_icall(struct at_state_t *at_state)
{
return ICALL_IGNORE;
}
void gigaset_isdn_connD(struct bc_state *bcs)
{
}
void gigaset_isdn_hupD(struct bc_state *bcs)
{
}
void gigaset_isdn_connB(struct bc_state *bcs)
{
}
void gigaset_isdn_hupB(struct bc_state *bcs)
{
}
void gigaset_isdn_start(struct cardstate *cs)
{
}
void gigaset_isdn_stop(struct cardstate *cs)
{
}
int gigaset_isdn_register(struct cardstate *cs, const char *isdnid)
{
pr_info("no ISDN subsystem interface\n");
return 1;
}
void gigaset_isdn_unregister(struct cardstate *cs)
{
}

View File

@ -40,8 +40,8 @@
/* Possible ASCII responses */ /* Possible ASCII responses */
#define RSP_OK 0 #define RSP_OK 0
//#define RSP_BUSY 1 #define RSP_BUSY 1
//#define RSP_CONNECT 2 #define RSP_CONNECT 2
#define RSP_ZGCI 3 #define RSP_ZGCI 3
#define RSP_RING 4 #define RSP_RING 4
#define RSP_ZAOC 5 #define RSP_ZAOC 5
@ -68,7 +68,6 @@
#define RSP_ZHLC (RSP_STR + STR_ZHLC) #define RSP_ZHLC (RSP_STR + STR_ZHLC)
#define RSP_ERROR -1 /* ERROR */ #define RSP_ERROR -1 /* ERROR */
#define RSP_WRONG_CID -2 /* unknown cid in cmd */ #define RSP_WRONG_CID -2 /* unknown cid in cmd */
//#define RSP_EMPTY -3
#define RSP_UNKNOWN -4 /* unknown response */ #define RSP_UNKNOWN -4 /* unknown response */
#define RSP_FAIL -5 /* internal error */ #define RSP_FAIL -5 /* internal error */
#define RSP_INVAL -6 /* invalid response */ #define RSP_INVAL -6 /* invalid response */
@ -76,9 +75,9 @@
#define RSP_NONE -19 #define RSP_NONE -19
#define RSP_STRING -20 #define RSP_STRING -20
#define RSP_NULL -21 #define RSP_NULL -21
//#define RSP_RETRYFAIL -22 #define RSP_RETRYFAIL -22
//#define RSP_RETRY -23 #define RSP_RETRY -23
//#define RSP_SKIP -24 #define RSP_SKIP -24
#define RSP_INIT -27 #define RSP_INIT -27
#define RSP_ANY -26 #define RSP_ANY -26
#define RSP_LAST -28 #define RSP_LAST -28
@ -127,7 +126,6 @@
#define ACT_NOTIFY_BC_UP 39 #define ACT_NOTIFY_BC_UP 39
#define ACT_DIAL 40 #define ACT_DIAL 40
#define ACT_ACCEPT 41 #define ACT_ACCEPT 41
#define ACT_PROTO_L2 42
#define ACT_HUP 43 #define ACT_HUP 43
#define ACT_IF_LOCK 44 #define ACT_IF_LOCK 44
#define ACT_START 45 #define ACT_START 45
@ -159,229 +157,229 @@
#define SEQ_UMMODE 11 #define SEQ_UMMODE 11
// 100: init, 200: dle0, 250:dle1, 300: get cid (dial), 350: "hup" (no cid), 400: hup, 500: reset, 600: dial, 700: ring /* 100: init, 200: dle0, 250:dle1, 300: get cid (dial), 350: "hup" (no cid),
* 400: hup, 500: reset, 600: dial, 700: ring */
struct reply_t gigaset_tab_nocid[] = struct reply_t gigaset_tab_nocid[] =
{ {
/* resp_code, min_ConState, max_ConState, parameter, new_ConState, timeout, action, command */ /* resp_code, min_ConState, max_ConState, parameter, new_ConState, timeout,
* action, command */
/* initialize device, set cid mode if possible */ /* initialize device, set cid mode if possible */
//{RSP_INIT, -1, -1,100, 900, 0, {ACT_TEST}}, {RSP_INIT, -1, -1, SEQ_INIT, 100, 1, {ACT_TIMEOUT} },
//{RSP_ERROR, 900,900, -1, 0, 0, {ACT_FAILINIT}},
//{RSP_OK, 900,900, -1, 100, INIT_TIMEOUT,
// {ACT_TIMEOUT}},
{RSP_INIT, -1, -1,SEQ_INIT, 100, INIT_TIMEOUT, {EV_TIMEOUT, 100, 100, -1, 101, 3, {0}, "Z\r"},
{ACT_TIMEOUT}}, /* wait until device is ready */ {RSP_OK, 101, 103, -1, 120, 5, {ACT_GETSTRING},
"+GMR\r"},
{EV_TIMEOUT, 100,100, -1, 101, 3, {0}, "Z\r"}, /* device in transparent mode? try to initialize it. */ {EV_TIMEOUT, 101, 101, -1, 102, 5, {0}, "Z\r"},
{RSP_OK, 101,103, -1, 120, 5, {ACT_GETSTRING}, "+GMR\r"}, /* get version */ {RSP_ERROR, 101, 101, -1, 102, 5, {0}, "Z\r"},
{EV_TIMEOUT, 101,101, -1, 102, 5, {0}, "Z\r"}, /* timeout => try once again. */ {EV_TIMEOUT, 102, 102, -1, 108, 5, {ACT_SETDLE1},
{RSP_ERROR, 101,101, -1, 102, 5, {0}, "Z\r"}, /* error => try once again. */ "^SDLE=0\r"},
{RSP_OK, 108, 108, -1, 104, -1},
{RSP_ZDLE, 104, 104, 0, 103, 5, {0}, "Z\r"},
{EV_TIMEOUT, 104, 104, -1, 0, 0, {ACT_FAILINIT} },
{RSP_ERROR, 108, 108, -1, 0, 0, {ACT_FAILINIT} },
{EV_TIMEOUT, 102,102, -1, 108, 5, {ACT_SETDLE1}, "^SDLE=0\r"}, /* timeout => try again in DLE mode. */ {EV_TIMEOUT, 108, 108, -1, 105, 2, {ACT_SETDLE0,
{RSP_OK, 108,108, -1, 104,-1}, ACT_HUPMODEM,
{RSP_ZDLE, 104,104, 0, 103, 5, {0}, "Z\r"}, ACT_TIMEOUT} },
{EV_TIMEOUT, 104,104, -1, 0, 0, {ACT_FAILINIT}}, {EV_TIMEOUT, 105, 105, -1, 103, 5, {0}, "Z\r"},
{RSP_ERROR, 108,108, -1, 0, 0, {ACT_FAILINIT}},
{EV_TIMEOUT, 108,108, -1, 105, 2, {ACT_SETDLE0, {RSP_ERROR, 102, 102, -1, 107, 5, {0}, "^GETPRE\r"},
ACT_HUPMODEM, {RSP_OK, 107, 107, -1, 0, 0, {ACT_CONFIGMODE} },
ACT_TIMEOUT}}, /* still timeout => connection in unimodem mode? */ {RSP_ERROR, 107, 107, -1, 0, 0, {ACT_FAILINIT} },
{EV_TIMEOUT, 105,105, -1, 103, 5, {0}, "Z\r"}, {EV_TIMEOUT, 107, 107, -1, 0, 0, {ACT_FAILINIT} },
{RSP_ERROR, 102,102, -1, 107, 5, {0}, "^GETPRE\r"}, /* ERROR on ATZ => maybe in config mode? */ {RSP_ERROR, 103, 103, -1, 0, 0, {ACT_FAILINIT} },
{RSP_OK, 107,107, -1, 0, 0, {ACT_CONFIGMODE}}, {EV_TIMEOUT, 103, 103, -1, 0, 0, {ACT_FAILINIT} },
{RSP_ERROR, 107,107, -1, 0, 0, {ACT_FAILINIT}},
{EV_TIMEOUT, 107,107, -1, 0, 0, {ACT_FAILINIT}},
{RSP_ERROR, 103,103, -1, 0, 0, {ACT_FAILINIT}}, {RSP_STRING, 120, 120, -1, 121, -1, {ACT_SETVER} },
{EV_TIMEOUT, 103,103, -1, 0, 0, {ACT_FAILINIT}},
{RSP_STRING, 120,120, -1, 121,-1, {ACT_SETVER}}, {EV_TIMEOUT, 120, 121, -1, 0, 0, {ACT_FAILVER,
ACT_INIT} },
{RSP_ERROR, 120, 121, -1, 0, 0, {ACT_FAILVER,
ACT_INIT} },
{RSP_OK, 121, 121, -1, 0, 0, {ACT_GOTVER,
ACT_INIT} },
{EV_TIMEOUT, 120,121, -1, 0, 0, {ACT_FAILVER, ACT_INIT}}, /* leave dle mode */
{RSP_ERROR, 120,121, -1, 0, 0, {ACT_FAILVER, ACT_INIT}}, {RSP_INIT, 0, 0, SEQ_DLE0, 201, 5, {0}, "^SDLE=0\r"},
{RSP_OK, 121,121, -1, 0, 0, {ACT_GOTVER, ACT_INIT}}, {RSP_OK, 201, 201, -1, 202, -1},
{RSP_ZDLE, 202, 202, 0, 0, 0, {ACT_DLE0} },
{RSP_NODEV, 200, 249, -1, 0, 0, {ACT_FAKEDLE0} },
{RSP_ERROR, 200, 249, -1, 0, 0, {ACT_FAILDLE0} },
{EV_TIMEOUT, 200, 249, -1, 0, 0, {ACT_FAILDLE0} },
/* leave dle mode */ /* enter dle mode */
{RSP_INIT, 0, 0,SEQ_DLE0, 201, 5, {0}, "^SDLE=0\r"}, {RSP_INIT, 0, 0, SEQ_DLE1, 251, 5, {0}, "^SDLE=1\r"},
{RSP_OK, 201,201, -1, 202,-1}, {RSP_OK, 251, 251, -1, 252, -1},
{RSP_ZDLE, 202,202, 0, 0, 0, {ACT_DLE0}}, {RSP_ZDLE, 252, 252, 1, 0, 0, {ACT_DLE1} },
{RSP_NODEV, 200,249, -1, 0, 0, {ACT_FAKEDLE0}}, {RSP_ERROR, 250, 299, -1, 0, 0, {ACT_FAILDLE1} },
{RSP_ERROR, 200,249, -1, 0, 0, {ACT_FAILDLE0}}, {EV_TIMEOUT, 250, 299, -1, 0, 0, {ACT_FAILDLE1} },
{EV_TIMEOUT, 200,249, -1, 0, 0, {ACT_FAILDLE0}},
/* enter dle mode */ /* incoming call */
{RSP_INIT, 0, 0,SEQ_DLE1, 251, 5, {0}, "^SDLE=1\r"}, {RSP_RING, -1, -1, -1, -1, -1, {ACT_RING} },
{RSP_OK, 251,251, -1, 252,-1},
{RSP_ZDLE, 252,252, 1, 0, 0, {ACT_DLE1}},
{RSP_ERROR, 250,299, -1, 0, 0, {ACT_FAILDLE1}},
{EV_TIMEOUT, 250,299, -1, 0, 0, {ACT_FAILDLE1}},
/* incoming call */ /* get cid */
{RSP_RING, -1, -1, -1, -1,-1, {ACT_RING}}, {RSP_INIT, 0, 0, SEQ_CID, 301, 5, {0}, "^SGCI?\r"},
{RSP_OK, 301, 301, -1, 302, -1},
{RSP_ZGCI, 302, 302, -1, 0, 0, {ACT_CID} },
{RSP_ERROR, 301, 349, -1, 0, 0, {ACT_FAILCID} },
{EV_TIMEOUT, 301, 349, -1, 0, 0, {ACT_FAILCID} },
/* get cid */ /* enter cid mode */
//{RSP_INIT, 0, 0,300, 901, 0, {ACT_TEST}}, {RSP_INIT, 0, 0, SEQ_CIDMODE, 150, 5, {0}, "^SGCI=1\r"},
//{RSP_ERROR, 901,901, -1, 0, 0, {ACT_FAILCID}}, {RSP_OK, 150, 150, -1, 0, 0, {ACT_CMODESET} },
//{RSP_OK, 901,901, -1, 301, 5, {0}, "^SGCI?\r"}, {RSP_ERROR, 150, 150, -1, 0, 0, {ACT_FAILCMODE} },
{EV_TIMEOUT, 150, 150, -1, 0, 0, {ACT_FAILCMODE} },
{RSP_INIT, 0, 0,SEQ_CID, 301, 5, {0}, "^SGCI?\r"}, /* leave cid mode */
{RSP_OK, 301,301, -1, 302,-1}, {RSP_INIT, 0, 0, SEQ_UMMODE, 160, 5, {0}, "Z\r"},
{RSP_ZGCI, 302,302, -1, 0, 0, {ACT_CID}}, {RSP_OK, 160, 160, -1, 0, 0, {ACT_UMODESET} },
{RSP_ERROR, 301,349, -1, 0, 0, {ACT_FAILCID}}, {RSP_ERROR, 160, 160, -1, 0, 0, {ACT_FAILUMODE} },
{EV_TIMEOUT, 301,349, -1, 0, 0, {ACT_FAILCID}}, {EV_TIMEOUT, 160, 160, -1, 0, 0, {ACT_FAILUMODE} },
/* enter cid mode */ /* abort getting cid */
{RSP_INIT, 0, 0,SEQ_CIDMODE, 150, 5, {0}, "^SGCI=1\r"}, {RSP_INIT, 0, 0, SEQ_NOCID, 0, 0, {ACT_ABORTCID} },
{RSP_OK, 150,150, -1, 0, 0, {ACT_CMODESET}},
{RSP_ERROR, 150,150, -1, 0, 0, {ACT_FAILCMODE}},
{EV_TIMEOUT, 150,150, -1, 0, 0, {ACT_FAILCMODE}},
/* leave cid mode */ /* reset */
//{RSP_INIT, 0, 0,SEQ_UMMODE, 160, 5, {0}, "^SGCI=0\r"}, {RSP_INIT, 0, 0, SEQ_SHUTDOWN, 504, 5, {0}, "Z\r"},
{RSP_INIT, 0, 0,SEQ_UMMODE, 160, 5, {0}, "Z\r"}, {RSP_OK, 504, 504, -1, 0, 0, {ACT_SDOWN} },
{RSP_OK, 160,160, -1, 0, 0, {ACT_UMODESET}}, {RSP_ERROR, 501, 599, -1, 0, 0, {ACT_FAILSDOWN} },
{RSP_ERROR, 160,160, -1, 0, 0, {ACT_FAILUMODE}}, {EV_TIMEOUT, 501, 599, -1, 0, 0, {ACT_FAILSDOWN} },
{EV_TIMEOUT, 160,160, -1, 0, 0, {ACT_FAILUMODE}}, {RSP_NODEV, 501, 599, -1, 0, 0, {ACT_FAKESDOWN} },
/* abort getting cid */ {EV_PROC_CIDMODE, -1, -1, -1, -1, -1, {ACT_PROC_CIDMODE} },
{RSP_INIT, 0, 0,SEQ_NOCID, 0, 0, {ACT_ABORTCID}}, {EV_IF_LOCK, -1, -1, -1, -1, -1, {ACT_IF_LOCK} },
{EV_IF_VER, -1, -1, -1, -1, -1, {ACT_IF_VER} },
{EV_START, -1, -1, -1, -1, -1, {ACT_START} },
{EV_STOP, -1, -1, -1, -1, -1, {ACT_STOP} },
{EV_SHUTDOWN, -1, -1, -1, -1, -1, {ACT_SHUTDOWN} },
/* reset */ /* misc. */
{RSP_INIT, 0, 0,SEQ_SHUTDOWN, 504, 5, {0}, "Z\r"}, {RSP_ERROR, -1, -1, -1, -1, -1, {ACT_ERROR} },
{RSP_OK, 504,504, -1, 0, 0, {ACT_SDOWN}}, {RSP_ZCFGT, -1, -1, -1, -1, -1, {ACT_DEBUG} },
{RSP_ERROR, 501,599, -1, 0, 0, {ACT_FAILSDOWN}}, {RSP_ZCFG, -1, -1, -1, -1, -1, {ACT_DEBUG} },
{EV_TIMEOUT, 501,599, -1, 0, 0, {ACT_FAILSDOWN}}, {RSP_ZLOG, -1, -1, -1, -1, -1, {ACT_DEBUG} },
{RSP_NODEV, 501,599, -1, 0, 0, {ACT_FAKESDOWN}}, {RSP_ZMWI, -1, -1, -1, -1, -1, {ACT_DEBUG} },
{RSP_ZABINFO, -1, -1, -1, -1, -1, {ACT_DEBUG} },
{RSP_ZSMLSTCHG, -1, -1, -1, -1, -1, {ACT_DEBUG} },
{EV_PROC_CIDMODE,-1, -1, -1, -1,-1, {ACT_PROC_CIDMODE}}, //FIXME {RSP_ZCAU, -1, -1, -1, -1, -1, {ACT_ZCAU} },
{EV_IF_LOCK, -1, -1, -1, -1,-1, {ACT_IF_LOCK}}, //FIXME {RSP_NONE, -1, -1, -1, -1, -1, {ACT_DEBUG} },
{EV_IF_VER, -1, -1, -1, -1,-1, {ACT_IF_VER}}, //FIXME {RSP_ANY, -1, -1, -1, -1, -1, {ACT_WARN} },
{EV_START, -1, -1, -1, -1,-1, {ACT_START}}, //FIXME {RSP_LAST}
{EV_STOP, -1, -1, -1, -1,-1, {ACT_STOP}}, //FIXME
{EV_SHUTDOWN, -1, -1, -1, -1,-1, {ACT_SHUTDOWN}}, //FIXME
/* misc. */
{RSP_ERROR, -1, -1, -1, -1, -1, {ACT_ERROR} },
{RSP_EMPTY, -1, -1, -1, -1,-1, {ACT_DEBUG}}, //FIXME
{RSP_ZCFGT, -1, -1, -1, -1,-1, {ACT_DEBUG}}, //FIXME
{RSP_ZCFG, -1, -1, -1, -1,-1, {ACT_DEBUG}}, //FIXME
{RSP_ZLOG, -1, -1, -1, -1,-1, {ACT_DEBUG}}, //FIXME
{RSP_ZMWI, -1, -1, -1, -1,-1, {ACT_DEBUG}}, //FIXME
{RSP_ZABINFO, -1, -1, -1, -1,-1, {ACT_DEBUG}}, //FIXME
{RSP_ZSMLSTCHG,-1, -1, -1, -1,-1, {ACT_DEBUG}}, //FIXME
{RSP_ZCAU, -1, -1, -1, -1,-1, {ACT_ZCAU}},
{RSP_NONE, -1, -1, -1, -1,-1, {ACT_DEBUG}},
{RSP_ANY, -1, -1, -1, -1,-1, {ACT_WARN}},
{RSP_LAST}
}; };
// 600: start dialing, 650: dial in progress, 800: connection is up, 700: ring, 400: hup, 750: accepted icall /* 600: start dialing, 650: dial in progress, 800: connection is up, 700: ring,
* 400: hup, 750: accepted icall */
struct reply_t gigaset_tab_cid[] = struct reply_t gigaset_tab_cid[] =
{ {
/* resp_code, min_ConState, max_ConState, parameter, new_ConState, timeout, action, command */ /* resp_code, min_ConState, max_ConState, parameter, new_ConState, timeout,
* action, command */
/* dial */ /* dial */
{EV_DIAL, -1, -1, -1, -1,-1, {ACT_DIAL}}, //FIXME {EV_DIAL, -1, -1, -1, -1, -1, {ACT_DIAL} },
{RSP_INIT, 0, 0,SEQ_DIAL, 601, 5, {ACT_CMD+AT_BC}}, {RSP_INIT, 0, 0, SEQ_DIAL, 601, 5, {ACT_CMD+AT_BC} },
{RSP_OK, 601,601, -1, 602, 5, {ACT_CMD+AT_HLC}}, {RSP_OK, 601, 601, -1, 602, 5, {ACT_CMD+AT_HLC} },
{RSP_NULL, 602,602, -1, 603, 5, {ACT_CMD+AT_PROTO}}, {RSP_NULL, 602, 602, -1, 603, 5, {ACT_CMD+AT_PROTO} },
{RSP_OK, 602,602, -1, 603, 5, {ACT_CMD+AT_PROTO}}, {RSP_OK, 602, 602, -1, 603, 5, {ACT_CMD+AT_PROTO} },
{RSP_OK, 603,603, -1, 604, 5, {ACT_CMD+AT_TYPE}}, {RSP_OK, 603, 603, -1, 604, 5, {ACT_CMD+AT_TYPE} },
{RSP_OK, 604,604, -1, 605, 5, {ACT_CMD+AT_MSN}}, {RSP_OK, 604, 604, -1, 605, 5, {ACT_CMD+AT_MSN} },
{RSP_OK, 605,605, -1, 606, 5, {ACT_CMD+AT_ISO}}, {RSP_NULL, 605, 605, -1, 606, 5, {ACT_CMD+AT_CLIP} },
{RSP_NULL, 605,605, -1, 606, 5, {ACT_CMD+AT_ISO}}, {RSP_OK, 605, 605, -1, 606, 5, {ACT_CMD+AT_CLIP} },
{RSP_OK, 606,606, -1, 607, 5, {0}, "+VLS=17\r"}, {RSP_NULL, 606, 606, -1, 607, 5, {ACT_CMD+AT_ISO} },
{RSP_OK, 607,607, -1, 608,-1}, {RSP_OK, 606, 606, -1, 607, 5, {ACT_CMD+AT_ISO} },
{RSP_ZSAU, 608,608,ZSAU_PROCEEDING, 609, 5, {ACT_CMD+AT_DIAL}}, {RSP_OK, 607, 607, -1, 608, 5, {0}, "+VLS=17\r"},
{RSP_OK, 609,609, -1, 650, 0, {ACT_DIALING}}, {RSP_OK, 608, 608, -1, 609, -1},
{RSP_ZSAU, 609, 609, ZSAU_PROCEEDING, 610, 5, {ACT_CMD+AT_DIAL} },
{RSP_OK, 610, 610, -1, 650, 0, {ACT_DIALING} },
{RSP_ERROR, 601,609, -1, 0, 0, {ACT_ABORTDIAL}}, {RSP_ERROR, 601, 610, -1, 0, 0, {ACT_ABORTDIAL} },
{EV_TIMEOUT, 601,609, -1, 0, 0, {ACT_ABORTDIAL}}, {EV_TIMEOUT, 601, 610, -1, 0, 0, {ACT_ABORTDIAL} },
/* optional dialing responses */ /* optional dialing responses */
{EV_BC_OPEN, 650,650, -1, 651,-1}, {EV_BC_OPEN, 650, 650, -1, 651, -1},
{RSP_ZVLS, 608,651, 17, -1,-1, {ACT_DEBUG}}, {RSP_ZVLS, 609, 651, 17, -1, -1, {ACT_DEBUG} },
{RSP_ZCTP, 609,651, -1, -1,-1, {ACT_DEBUG}}, {RSP_ZCTP, 610, 651, -1, -1, -1, {ACT_DEBUG} },
{RSP_ZCPN, 609,651, -1, -1,-1, {ACT_DEBUG}}, {RSP_ZCPN, 610, 651, -1, -1, -1, {ACT_DEBUG} },
{RSP_ZSAU, 650,651,ZSAU_CALL_DELIVERED, -1,-1, {ACT_DEBUG}}, {RSP_ZSAU, 650, 651, ZSAU_CALL_DELIVERED, -1, -1, {ACT_DEBUG} },
/* connect */ /* connect */
{RSP_ZSAU, 650,650,ZSAU_ACTIVE, 800,-1, {ACT_CONNECT}}, {RSP_ZSAU, 650, 650, ZSAU_ACTIVE, 800, -1, {ACT_CONNECT} },
{RSP_ZSAU, 651,651,ZSAU_ACTIVE, 800,-1, {ACT_CONNECT, {RSP_ZSAU, 651, 651, ZSAU_ACTIVE, 800, -1, {ACT_CONNECT,
ACT_NOTIFY_BC_UP}}, ACT_NOTIFY_BC_UP} },
{RSP_ZSAU, 750,750,ZSAU_ACTIVE, 800,-1, {ACT_CONNECT}}, {RSP_ZSAU, 750, 750, ZSAU_ACTIVE, 800, -1, {ACT_CONNECT} },
{RSP_ZSAU, 751,751,ZSAU_ACTIVE, 800,-1, {ACT_CONNECT, {RSP_ZSAU, 751, 751, ZSAU_ACTIVE, 800, -1, {ACT_CONNECT,
ACT_NOTIFY_BC_UP}}, ACT_NOTIFY_BC_UP} },
{EV_BC_OPEN, 800,800, -1, 800,-1, {ACT_NOTIFY_BC_UP}}, {EV_BC_OPEN, 800, 800, -1, 800, -1, {ACT_NOTIFY_BC_UP} },
/* remote hangup */ /* remote hangup */
{RSP_ZSAU, 650,651,ZSAU_DISCONNECT_IND, 0, 0, {ACT_REMOTEREJECT}}, {RSP_ZSAU, 650, 651, ZSAU_DISCONNECT_IND, 0, 0, {ACT_REMOTEREJECT} },
{RSP_ZSAU, 750,751,ZSAU_DISCONNECT_IND, 0, 0, {ACT_REMOTEHUP}}, {RSP_ZSAU, 750, 751, ZSAU_DISCONNECT_IND, 0, 0, {ACT_REMOTEHUP} },
{RSP_ZSAU, 800,800,ZSAU_DISCONNECT_IND, 0, 0, {ACT_REMOTEHUP}}, {RSP_ZSAU, 800, 800, ZSAU_DISCONNECT_IND, 0, 0, {ACT_REMOTEHUP} },
/* hangup */ /* hangup */
{EV_HUP, -1, -1, -1, -1,-1, {ACT_HUP}}, //FIXME {EV_HUP, -1, -1, -1, -1, -1, {ACT_HUP} },
{RSP_INIT, -1, -1,SEQ_HUP, 401, 5, {0}, "+VLS=0\r"}, /* hang up */ //-1,-1? {RSP_INIT, -1, -1, SEQ_HUP, 401, 5, {0}, "+VLS=0\r"},
{RSP_OK, 401,401, -1, 402, 5}, {RSP_OK, 401, 401, -1, 402, 5},
{RSP_ZVLS, 402,402, 0, 403, 5}, {RSP_ZVLS, 402, 402, 0, 403, 5},
{RSP_ZSAU, 403, 403, ZSAU_DISCONNECT_REQ, -1, -1, {ACT_DEBUG} }, {RSP_ZSAU, 403, 403, ZSAU_DISCONNECT_REQ, -1, -1, {ACT_DEBUG} },
{RSP_ZSAU, 403, 403, ZSAU_NULL, 0, 0, {ACT_DISCONNECT} }, {RSP_ZSAU, 403, 403, ZSAU_NULL, 0, 0, {ACT_DISCONNECT} },
{RSP_NODEV, 401, 403, -1, 0, 0, {ACT_FAKEHUP} }, {RSP_NODEV, 401, 403, -1, 0, 0, {ACT_FAKEHUP} },
{RSP_ERROR, 401,401, -1, 0, 0, {ACT_ABORTHUP}}, {RSP_ERROR, 401, 401, -1, 0, 0, {ACT_ABORTHUP} },
{EV_TIMEOUT, 401,403, -1, 0, 0, {ACT_ABORTHUP}}, {EV_TIMEOUT, 401, 403, -1, 0, 0, {ACT_ABORTHUP} },
{EV_BC_CLOSED, 0, 0, -1, 0,-1, {ACT_NOTIFY_BC_DOWN}}, //FIXME new constate + timeout {EV_BC_CLOSED, 0, 0, -1, 0, -1, {ACT_NOTIFY_BC_DOWN} },
/* ring */ /* ring */
{RSP_ZBC, 700,700, -1, -1,-1, {0}}, {RSP_ZBC, 700, 700, -1, -1, -1, {0} },
{RSP_ZHLC, 700,700, -1, -1,-1, {0}}, {RSP_ZHLC, 700, 700, -1, -1, -1, {0} },
{RSP_NMBR, 700,700, -1, -1,-1, {0}}, {RSP_NMBR, 700, 700, -1, -1, -1, {0} },
{RSP_ZCPN, 700,700, -1, -1,-1, {0}}, {RSP_ZCPN, 700, 700, -1, -1, -1, {0} },
{RSP_ZCTP, 700,700, -1, -1,-1, {0}}, {RSP_ZCTP, 700, 700, -1, -1, -1, {0} },
{EV_TIMEOUT, 700,700, -1, 720,720, {ACT_ICALL}}, {EV_TIMEOUT, 700, 700, -1, 720, 720, {ACT_ICALL} },
{EV_BC_CLOSED,720,720, -1, 0,-1, {ACT_NOTIFY_BC_DOWN}}, {EV_BC_CLOSED, 720, 720, -1, 0, -1, {ACT_NOTIFY_BC_DOWN} },
/*accept icall*/ /*accept icall*/
{EV_ACCEPT, -1, -1, -1, -1,-1, {ACT_ACCEPT}}, //FIXME {EV_ACCEPT, -1, -1, -1, -1, -1, {ACT_ACCEPT} },
{RSP_INIT, 720,720,SEQ_ACCEPT, 721, 5, {ACT_CMD+AT_PROTO}}, {RSP_INIT, 720, 720, SEQ_ACCEPT, 721, 5, {ACT_CMD+AT_PROTO} },
{RSP_OK, 721,721, -1, 722, 5, {ACT_CMD+AT_ISO}}, {RSP_OK, 721, 721, -1, 722, 5, {ACT_CMD+AT_ISO} },
{RSP_OK, 722,722, -1, 723, 5, {0}, "+VLS=17\r"}, /* set "Endgeraetemodus" */ {RSP_OK, 722, 722, -1, 723, 5, {0}, "+VLS=17\r"},
{RSP_OK, 723,723, -1, 724, 5, {0}}, {RSP_OK, 723, 723, -1, 724, 5, {0} },
{RSP_ZVLS, 724,724, 17, 750,50, {ACT_ACCEPTED}}, {RSP_ZVLS, 724, 724, 17, 750, 50, {ACT_ACCEPTED} },
{RSP_ERROR, 721,729, -1, 0, 0, {ACT_ABORTACCEPT}}, {RSP_ERROR, 721, 729, -1, 0, 0, {ACT_ABORTACCEPT} },
{EV_TIMEOUT, 721,729, -1, 0, 0, {ACT_ABORTACCEPT}}, {EV_TIMEOUT, 721, 729, -1, 0, 0, {ACT_ABORTACCEPT} },
{RSP_ZSAU, 700,729,ZSAU_NULL, 0, 0, {ACT_ABORTACCEPT}}, {RSP_ZSAU, 700, 729, ZSAU_NULL, 0, 0, {ACT_ABORTACCEPT} },
{RSP_ZSAU, 700,729,ZSAU_ACTIVE, 0, 0, {ACT_ABORTACCEPT}}, {RSP_ZSAU, 700, 729, ZSAU_ACTIVE, 0, 0, {ACT_ABORTACCEPT} },
{RSP_ZSAU, 700,729,ZSAU_DISCONNECT_IND, 0, 0, {ACT_ABORTACCEPT}}, {RSP_ZSAU, 700, 729, ZSAU_DISCONNECT_IND, 0, 0, {ACT_ABORTACCEPT} },
{EV_BC_OPEN, 750,750, -1, 751,-1}, {EV_BC_OPEN, 750, 750, -1, 751, -1},
{EV_TIMEOUT, 750,751, -1, 0, 0, {ACT_CONNTIMEOUT}}, {EV_TIMEOUT, 750, 751, -1, 0, 0, {ACT_CONNTIMEOUT} },
/* B channel closed (general case) */ /* B channel closed (general case) */
{EV_BC_CLOSED, -1, -1, -1, -1,-1, {ACT_NOTIFY_BC_DOWN}}, //FIXME {EV_BC_CLOSED, -1, -1, -1, -1, -1, {ACT_NOTIFY_BC_DOWN} },
/* misc. */ /* misc. */
{EV_PROTO_L2, -1, -1, -1, -1,-1, {ACT_PROTO_L2}}, //FIXME {RSP_ZCON, -1, -1, -1, -1, -1, {ACT_DEBUG} },
{RSP_ZCCR, -1, -1, -1, -1, -1, {ACT_DEBUG} },
{RSP_ZAOC, -1, -1, -1, -1, -1, {ACT_DEBUG} },
{RSP_ZCSTR, -1, -1, -1, -1, -1, {ACT_DEBUG} },
{RSP_ZCON, -1, -1, -1, -1,-1, {ACT_DEBUG}}, //FIXME {RSP_ZCAU, -1, -1, -1, -1, -1, {ACT_ZCAU} },
{RSP_ZCCR, -1, -1, -1, -1,-1, {ACT_DEBUG}}, //FIXME {RSP_NONE, -1, -1, -1, -1, -1, {ACT_DEBUG} },
{RSP_ZAOC, -1, -1, -1, -1,-1, {ACT_DEBUG}}, //FIXME {RSP_ANY, -1, -1, -1, -1, -1, {ACT_WARN} },
{RSP_ZCSTR, -1, -1, -1, -1,-1, {ACT_DEBUG}}, //FIXME {RSP_LAST}
{RSP_ZCAU, -1, -1, -1, -1,-1, {ACT_ZCAU}},
{RSP_NONE, -1, -1, -1, -1,-1, {ACT_DEBUG}},
{RSP_ANY, -1, -1, -1, -1,-1, {ACT_WARN}},
{RSP_LAST}
}; };
static const struct resp_type_t resp_type[] = static const struct resp_type_t {
unsigned char *response;
int resp_code;
int type;
} resp_type[] =
{ {
/*{"", RSP_EMPTY, RT_NOTHING},*/
{"OK", RSP_OK, RT_NOTHING}, {"OK", RSP_OK, RT_NOTHING},
{"ERROR", RSP_ERROR, RT_NOTHING}, {"ERROR", RSP_ERROR, RT_NOTHING},
{"ZSAU", RSP_ZSAU, RT_ZSAU}, {"ZSAU", RSP_ZSAU, RT_ZSAU},
@ -405,7 +403,21 @@ static const struct resp_type_t resp_type[] =
{"ZLOG", RSP_ZLOG, RT_NOTHING}, {"ZLOG", RSP_ZLOG, RT_NOTHING},
{"ZABINFO", RSP_ZABINFO, RT_NOTHING}, {"ZABINFO", RSP_ZABINFO, RT_NOTHING},
{"ZSMLSTCHG", RSP_ZSMLSTCHG, RT_NOTHING}, {"ZSMLSTCHG", RSP_ZSMLSTCHG, RT_NOTHING},
{NULL,0,0} {NULL, 0, 0}
};
static const struct zsau_resp_t {
unsigned char *str;
int code;
} zsau_resp[] =
{
{"OUTGOING_CALL_PROCEEDING", ZSAU_OUTGOING_CALL_PROCEEDING},
{"CALL_DELIVERED", ZSAU_CALL_DELIVERED},
{"ACTIVE", ZSAU_ACTIVE},
{"DISCONNECT_IND", ZSAU_DISCONNECT_IND},
{"NULL", ZSAU_NULL},
{"DISCONNECT_REQ", ZSAU_DISCONNECT_REQ},
{NULL, ZSAU_UNKNOWN}
}; };
/* /*
@ -470,7 +482,6 @@ static int cid_of_response(char *s)
if (cid < 1 || cid > 65535) if (cid < 1 || cid > 65535)
return -1; /* CID out of range */ return -1; /* CID out of range */
return cid; return cid;
//FIXME is ;<digit>+ at end of non-CID response really impossible?
} }
/** /**
@ -487,6 +498,7 @@ void gigaset_handle_modem_response(struct cardstate *cs)
int params; int params;
int i, j; int i, j;
const struct resp_type_t *rt; const struct resp_type_t *rt;
const struct zsau_resp_t *zr;
int curarg; int curarg;
unsigned long flags; unsigned long flags;
unsigned next, tail, head; unsigned next, tail, head;
@ -613,24 +625,14 @@ void gigaset_handle_modem_response(struct cardstate *cs)
event->parameter = ZSAU_NONE; event->parameter = ZSAU_NONE;
break; break;
} }
if (!strcmp(argv[curarg], "OUTGOING_CALL_PROCEEDING")) for (zr = zsau_resp; zr->str; ++zr)
event->parameter = ZSAU_OUTGOING_CALL_PROCEEDING; if (!strcmp(argv[curarg], zr->str))
else if (!strcmp(argv[curarg], "CALL_DELIVERED")) break;
event->parameter = ZSAU_CALL_DELIVERED; event->parameter = zr->code;
else if (!strcmp(argv[curarg], "ACTIVE")) if (!zr->str)
event->parameter = ZSAU_ACTIVE;
else if (!strcmp(argv[curarg], "DISCONNECT_IND"))
event->parameter = ZSAU_DISCONNECT_IND;
else if (!strcmp(argv[curarg], "NULL"))
event->parameter = ZSAU_NULL;
else if (!strcmp(argv[curarg], "DISCONNECT_REQ"))
event->parameter = ZSAU_DISCONNECT_REQ;
else {
event->parameter = ZSAU_UNKNOWN;
dev_warn(cs->dev, dev_warn(cs->dev,
"%s: unknown parameter %s after ZSAU\n", "%s: unknown parameter %s after ZSAU\n",
__func__, argv[curarg]); __func__, argv[curarg]);
}
++curarg; ++curarg;
break; break;
case RT_STRING: case RT_STRING:
@ -714,7 +716,7 @@ static void disconnect(struct at_state_t **at_state_p)
/* notify LL */ /* notify LL */
if (bcs->chstate & (CHS_D_UP | CHS_NOTIFY_LL)) { if (bcs->chstate & (CHS_D_UP | CHS_NOTIFY_LL)) {
bcs->chstate &= ~(CHS_D_UP | CHS_NOTIFY_LL); bcs->chstate &= ~(CHS_D_UP | CHS_NOTIFY_LL);
gigaset_i4l_channel_cmd(bcs, ISDN_STAT_DHUP); gigaset_isdn_hupD(bcs);
} }
} else { } else {
/* no B channel assigned: just deallocate */ /* no B channel assigned: just deallocate */
@ -872,12 +874,12 @@ static void bchannel_down(struct bc_state *bcs)
{ {
if (bcs->chstate & CHS_B_UP) { if (bcs->chstate & CHS_B_UP) {
bcs->chstate &= ~CHS_B_UP; bcs->chstate &= ~CHS_B_UP;
gigaset_i4l_channel_cmd(bcs, ISDN_STAT_BHUP); gigaset_isdn_hupB(bcs);
} }
if (bcs->chstate & (CHS_D_UP | CHS_NOTIFY_LL)) { if (bcs->chstate & (CHS_D_UP | CHS_NOTIFY_LL)) {
bcs->chstate &= ~(CHS_D_UP | CHS_NOTIFY_LL); bcs->chstate &= ~(CHS_D_UP | CHS_NOTIFY_LL);
gigaset_i4l_channel_cmd(bcs, ISDN_STAT_DHUP); gigaset_isdn_hupD(bcs);
} }
gigaset_free_channel(bcs); gigaset_free_channel(bcs);
@ -894,15 +896,17 @@ static void bchannel_up(struct bc_state *bcs)
} }
bcs->chstate |= CHS_B_UP; bcs->chstate |= CHS_B_UP;
gigaset_i4l_channel_cmd(bcs, ISDN_STAT_BCONN); gigaset_isdn_connB(bcs);
} }
static void start_dial(struct at_state_t *at_state, void *data, unsigned seq_index) static void start_dial(struct at_state_t *at_state, void *data,
unsigned seq_index)
{ {
struct bc_state *bcs = at_state->bcs; struct bc_state *bcs = at_state->bcs;
struct cardstate *cs = at_state->cs; struct cardstate *cs = at_state->cs;
int retval; char **commands = data;
unsigned long flags; unsigned long flags;
int i;
bcs->chstate |= CHS_NOTIFY_LL; bcs->chstate |= CHS_NOTIFY_LL;
@ -913,10 +917,10 @@ static void start_dial(struct at_state_t *at_state, void *data, unsigned seq_ind
} }
spin_unlock_irqrestore(&cs->lock, flags); spin_unlock_irqrestore(&cs->lock, flags);
retval = gigaset_isdn_setup_dial(at_state, data); for (i = 0; i < AT_NUM; ++i) {
if (retval != 0) kfree(bcs->commands[i]);
goto error; bcs->commands[i] = commands[i];
}
at_state->pending_commands |= PC_CID; at_state->pending_commands |= PC_CID;
gig_dbg(DEBUG_CMD, "Scheduling PC_CID"); gig_dbg(DEBUG_CMD, "Scheduling PC_CID");
@ -924,6 +928,10 @@ static void start_dial(struct at_state_t *at_state, void *data, unsigned seq_ind
return; return;
error: error:
for (i = 0; i < AT_NUM; ++i) {
kfree(commands[i]);
commands[i] = NULL;
}
at_state->pending_commands |= PC_NOCID; at_state->pending_commands |= PC_NOCID;
gig_dbg(DEBUG_CMD, "Scheduling PC_NOCID"); gig_dbg(DEBUG_CMD, "Scheduling PC_NOCID");
cs->commands_pending = 1; cs->commands_pending = 1;
@ -933,20 +941,31 @@ error:
static void start_accept(struct at_state_t *at_state) static void start_accept(struct at_state_t *at_state)
{ {
struct cardstate *cs = at_state->cs; struct cardstate *cs = at_state->cs;
int retval; struct bc_state *bcs = at_state->bcs;
int i;
retval = gigaset_isdn_setup_accept(at_state); for (i = 0; i < AT_NUM; ++i) {
kfree(bcs->commands[i]);
bcs->commands[i] = NULL;
}
if (retval == 0) { bcs->commands[AT_PROTO] = kmalloc(9, GFP_ATOMIC);
at_state->pending_commands |= PC_ACCEPT; bcs->commands[AT_ISO] = kmalloc(9, GFP_ATOMIC);
gig_dbg(DEBUG_CMD, "Scheduling PC_ACCEPT"); if (!bcs->commands[AT_PROTO] || !bcs->commands[AT_ISO]) {
cs->commands_pending = 1; dev_err(at_state->cs->dev, "out of memory\n");
} else {
/* error reset */ /* error reset */
at_state->pending_commands |= PC_HUP; at_state->pending_commands |= PC_HUP;
gig_dbg(DEBUG_CMD, "Scheduling PC_HUP"); gig_dbg(DEBUG_CMD, "Scheduling PC_HUP");
cs->commands_pending = 1; cs->commands_pending = 1;
return;
} }
snprintf(bcs->commands[AT_PROTO], 9, "^SBPR=%u\r", bcs->proto2);
snprintf(bcs->commands[AT_ISO], 9, "^SISO=%u\r", bcs->channel + 1);
at_state->pending_commands |= PC_ACCEPT;
gig_dbg(DEBUG_CMD, "Scheduling PC_ACCEPT");
cs->commands_pending = 1;
} }
static void do_start(struct cardstate *cs) static void do_start(struct cardstate *cs)
@ -957,9 +976,7 @@ static void do_start(struct cardstate *cs)
schedule_init(cs, MS_INIT); schedule_init(cs, MS_INIT);
cs->isdn_up = 1; cs->isdn_up = 1;
gigaset_i4l_cmd(cs, ISDN_STAT_RUN); gigaset_isdn_start(cs);
// FIXME: not in locked mode
// FIXME 2: only after init sequence
cs->waiting = 0; cs->waiting = 0;
wake_up(&cs->waitqueue); wake_up(&cs->waitqueue);
@ -975,7 +992,7 @@ static void finish_shutdown(struct cardstate *cs)
/* Tell the LL that the device is not available .. */ /* Tell the LL that the device is not available .. */
if (cs->isdn_up) { if (cs->isdn_up) {
cs->isdn_up = 0; cs->isdn_up = 0;
gigaset_i4l_cmd(cs, ISDN_STAT_STOP); gigaset_isdn_stop(cs);
} }
/* The rest is done by cleanup_cs () in user mode. */ /* The rest is done by cleanup_cs () in user mode. */
@ -1113,7 +1130,6 @@ static int do_lock(struct cardstate *cs)
break; break;
case MS_LOCKED: case MS_LOCKED:
//retval = -EACCES;
break; break;
default: default:
return -EBUSY; return -EBUSY;
@ -1276,7 +1292,7 @@ static void do_action(int action, struct cardstate *cs,
break; break;
} }
bcs->chstate |= CHS_D_UP; bcs->chstate |= CHS_D_UP;
gigaset_i4l_channel_cmd(bcs, ISDN_STAT_DCONN); gigaset_isdn_connD(bcs);
cs->ops->init_bchannel(bcs); cs->ops->init_bchannel(bcs);
break; break;
case ACT_DLE1: case ACT_DLE1:
@ -1284,7 +1300,7 @@ static void do_action(int action, struct cardstate *cs,
bcs = cs->bcs + cs->curchannel; bcs = cs->bcs + cs->curchannel;
bcs->chstate |= CHS_D_UP; bcs->chstate |= CHS_D_UP;
gigaset_i4l_channel_cmd(bcs, ISDN_STAT_DCONN); gigaset_isdn_connD(bcs);
cs->ops->init_bchannel(bcs); cs->ops->init_bchannel(bcs);
break; break;
case ACT_FAKEHUP: case ACT_FAKEHUP:
@ -1369,7 +1385,7 @@ static void do_action(int action, struct cardstate *cs,
cs->cur_at_seq = SEQ_NONE; cs->cur_at_seq = SEQ_NONE;
break; break;
case ACT_ABORTACCEPT: /* hangup/error/timeout during ICALL processing */ case ACT_ABORTACCEPT: /* hangup/error/timeout during ICALL procssng */
disconnect(p_at_state); disconnect(p_at_state);
break; break;
@ -1443,17 +1459,6 @@ static void do_action(int action, struct cardstate *cs,
__func__, at_state->ConState); __func__, at_state->ConState);
cs->cur_at_seq = SEQ_NONE; cs->cur_at_seq = SEQ_NONE;
break; break;
#ifdef CONFIG_GIGASET_DEBUG
case ACT_TEST:
{
static int count = 3; //2; //1;
*p_genresp = 1;
*p_resp_code = count ? RSP_ERROR : RSP_OK;
if (count > 0)
--count;
}
break;
#endif
case ACT_DEBUG: case ACT_DEBUG:
gig_dbg(DEBUG_ANY, "%s: resp_code %d in ConState %d", gig_dbg(DEBUG_ANY, "%s: resp_code %d in ConState %d",
__func__, ev->type, at_state->ConState); __func__, ev->type, at_state->ConState);
@ -1474,11 +1479,6 @@ static void do_action(int action, struct cardstate *cs,
case ACT_ACCEPT: case ACT_ACCEPT:
start_accept(at_state); start_accept(at_state);
break; break;
case ACT_PROTO_L2:
gig_dbg(DEBUG_CMD, "set protocol to %u",
(unsigned) ev->parameter);
at_state->bcs->proto2 = ev->parameter;
break;
case ACT_HUP: case ACT_HUP:
at_state->pending_commands |= PC_HUP; at_state->pending_commands |= PC_HUP;
cs->commands_pending = 1; cs->commands_pending = 1;
@ -1493,7 +1493,7 @@ static void do_action(int action, struct cardstate *cs,
do_start(cs); do_start(cs);
break; break;
/* events from the interface */ // FIXME without ACT_xxxx? /* events from the interface */
case ACT_IF_LOCK: case ACT_IF_LOCK:
cs->cmd_result = ev->parameter ? do_lock(cs) : do_unlock(cs); cs->cmd_result = ev->parameter ? do_lock(cs) : do_unlock(cs);
cs->waiting = 0; cs->waiting = 0;
@ -1512,7 +1512,7 @@ static void do_action(int action, struct cardstate *cs,
wake_up(&cs->waitqueue); wake_up(&cs->waitqueue);
break; break;
/* events from the proc file system */ // FIXME without ACT_xxxx? /* events from the proc file system */
case ACT_PROC_CIDMODE: case ACT_PROC_CIDMODE:
spin_lock_irqsave(&cs->lock, flags); spin_lock_irqsave(&cs->lock, flags);
if (ev->parameter != cs->cidmode) { if (ev->parameter != cs->cidmode) {
@ -1649,7 +1649,8 @@ static void process_event(struct cardstate *cs, struct event_t *ev)
for (curact = 0; curact < MAXACT; ++curact) { for (curact = 0; curact < MAXACT; ++curact) {
/* The row tells us what we should do .. /* The row tells us what we should do ..
*/ */
do_action(rep->action[curact], cs, bcs, &at_state, &p_command, &genresp, &resp_code, ev); do_action(rep->action[curact], cs, bcs, &at_state, &p_command,
&genresp, &resp_code, ev);
if (!at_state) if (!at_state)
break; /* may be freed after disconnect */ break; /* may be freed after disconnect */
} }
@ -1661,13 +1662,14 @@ static void process_event(struct cardstate *cs, struct event_t *ev)
if (genresp) { if (genresp) {
spin_lock_irqsave(&cs->lock, flags); spin_lock_irqsave(&cs->lock, flags);
at_state->timer_expires = 0; //FIXME at_state->timer_expires = 0;
at_state->timer_active = 0; //FIXME at_state->timer_active = 0;
spin_unlock_irqrestore(&cs->lock, flags); spin_unlock_irqrestore(&cs->lock, flags);
gigaset_add_event(cs, at_state, resp_code, NULL, 0, NULL); gigaset_add_event(cs, at_state, resp_code,
NULL, 0, NULL);
} else { } else {
/* Send command to modem if not NULL... */ /* Send command to modem if not NULL... */
if (p_command/*rep->command*/) { if (p_command) {
if (cs->connected) if (cs->connected)
send_command(cs, p_command, send_command(cs, p_command,
sendcid, cs->dle, sendcid, cs->dle,
@ -1754,7 +1756,8 @@ static void process_command_flags(struct cardstate *cs)
} }
} }
/* only switch back to unimodem mode, if no commands are pending and no channels are up */ /* only switch back to unimodem mode if no commands are pending and
* no channels are up */
spin_lock_irqsave(&cs->lock, flags); spin_lock_irqsave(&cs->lock, flags);
if (cs->at_state.pending_commands == PC_UMMODE if (cs->at_state.pending_commands == PC_UMMODE
&& !cs->cidmode && !cs->cidmode
@ -1813,9 +1816,8 @@ static void process_command_flags(struct cardstate *cs)
if (cs->at_state.pending_commands & PC_INIT) { if (cs->at_state.pending_commands & PC_INIT) {
cs->at_state.pending_commands &= ~PC_INIT; cs->at_state.pending_commands &= ~PC_INIT;
cs->dle = 0; //FIXME cs->dle = 0;
cs->inbuf->inputstate = INS_command; cs->inbuf->inputstate = INS_command;
//FIXME reset card state (or -> LOCK0)?
schedule_sequence(cs, &cs->at_state, SEQ_INIT); schedule_sequence(cs, &cs->at_state, SEQ_INIT);
return; return;
} }

View File

@ -23,7 +23,6 @@
#include <linux/compiler.h> #include <linux/compiler.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/isdnif.h>
#include <linux/usb.h> #include <linux/usb.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
@ -35,12 +34,11 @@
#include <linux/list.h> #include <linux/list.h>
#include <asm/atomic.h> #include <asm/atomic.h>
#define GIG_VERSION {0,5,0,0} #define GIG_VERSION {0, 5, 0, 0}
#define GIG_COMPAT {0,4,0,0} #define GIG_COMPAT {0, 4, 0, 0}
#define MAX_REC_PARAMS 10 /* Max. number of params in response string */ #define MAX_REC_PARAMS 10 /* Max. number of params in response string */
#define MAX_RESP_SIZE 512 /* Max. size of a response string */ #define MAX_RESP_SIZE 512 /* Max. size of a response string */
#define HW_HDR_LEN 2 /* Header size used to store ack info */
#define MAX_EVENTS 64 /* size of event queue */ #define MAX_EVENTS 64 /* size of event queue */
@ -135,35 +133,32 @@ void gigaset_dbg_buffer(enum debuglevel level, const unsigned char *msg,
#define OUT_VENDOR_REQ (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT) #define OUT_VENDOR_REQ (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT)
#define IN_VENDOR_REQ (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT) #define IN_VENDOR_REQ (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT)
/* int-in-events 3070 */ /* interrupt pipe messages */
#define HD_B1_FLOW_CONTROL 0x80 #define HD_B1_FLOW_CONTROL 0x80
#define HD_B2_FLOW_CONTROL 0x81 #define HD_B2_FLOW_CONTROL 0x81
#define HD_RECEIVEATDATA_ACK (0x35) // 3070 #define HD_RECEIVEATDATA_ACK (0x35) /* 3070 */
// att: HD_RECEIVE>>AT<<DATA_ACK #define HD_READY_SEND_ATDATA (0x36) /* 3070 */
#define HD_READY_SEND_ATDATA (0x36) // 3070 #define HD_OPEN_ATCHANNEL_ACK (0x37) /* 3070 */
#define HD_OPEN_ATCHANNEL_ACK (0x37) // 3070 #define HD_CLOSE_ATCHANNEL_ACK (0x38) /* 3070 */
#define HD_CLOSE_ATCHANNEL_ACK (0x38) // 3070 #define HD_DEVICE_INIT_OK (0x11) /* ISurf USB + 3070 */
#define HD_DEVICE_INIT_OK (0x11) // ISurf USB + 3070 #define HD_OPEN_B1CHANNEL_ACK (0x51) /* ISurf USB + 3070 */
#define HD_OPEN_B1CHANNEL_ACK (0x51) // ISurf USB + 3070 #define HD_OPEN_B2CHANNEL_ACK (0x52) /* ISurf USB + 3070 */
#define HD_OPEN_B2CHANNEL_ACK (0x52) // ISurf USB + 3070 #define HD_CLOSE_B1CHANNEL_ACK (0x53) /* ISurf USB + 3070 */
#define HD_CLOSE_B1CHANNEL_ACK (0x53) // ISurf USB + 3070 #define HD_CLOSE_B2CHANNEL_ACK (0x54) /* ISurf USB + 3070 */
#define HD_CLOSE_B2CHANNEL_ACK (0x54) // ISurf USB + 3070 #define HD_SUSPEND_END (0x61) /* ISurf USB */
// Powermangment #define HD_RESET_INTERRUPT_PIPE_ACK (0xFF) /* ISurf USB + 3070 */
#define HD_SUSPEND_END (0x61) // ISurf USB
// Configuration
#define HD_RESET_INTERRUPT_PIPE_ACK (0xFF) // ISurf USB + 3070
/* control requests 3070 */ /* control requests */
#define HD_OPEN_B1CHANNEL (0x23) // ISurf USB + 3070 #define HD_OPEN_B1CHANNEL (0x23) /* ISurf USB + 3070 */
#define HD_CLOSE_B1CHANNEL (0x24) // ISurf USB + 3070 #define HD_CLOSE_B1CHANNEL (0x24) /* ISurf USB + 3070 */
#define HD_OPEN_B2CHANNEL (0x25) // ISurf USB + 3070 #define HD_OPEN_B2CHANNEL (0x25) /* ISurf USB + 3070 */
#define HD_CLOSE_B2CHANNEL (0x26) // ISurf USB + 3070 #define HD_CLOSE_B2CHANNEL (0x26) /* ISurf USB + 3070 */
#define HD_RESET_INTERRUPT_PIPE (0x27) // ISurf USB + 3070 #define HD_RESET_INTERRUPT_PIPE (0x27) /* ISurf USB + 3070 */
#define HD_DEVICE_INIT_ACK (0x34) // ISurf USB + 3070 #define HD_DEVICE_INIT_ACK (0x34) /* ISurf USB + 3070 */
#define HD_WRITE_ATMESSAGE (0x12) // 3070 #define HD_WRITE_ATMESSAGE (0x12) /* 3070 */
#define HD_READ_ATMESSAGE (0x13) // 3070 #define HD_READ_ATMESSAGE (0x13) /* 3070 */
#define HD_OPEN_ATCHANNEL (0x28) // 3070 #define HD_OPEN_ATCHANNEL (0x28) /* 3070 */
#define HD_CLOSE_ATCHANNEL (0x29) // 3070 #define HD_CLOSE_ATCHANNEL (0x29) /* 3070 */
/* number of B channels supported by base driver */ /* number of B channels supported by base driver */
#define BAS_CHANNELS 2 #define BAS_CHANNELS 2
@ -193,7 +188,9 @@ void gigaset_dbg_buffer(enum debuglevel level, const unsigned char *msg,
#define AT_PROTO 4 #define AT_PROTO 4
#define AT_TYPE 5 #define AT_TYPE 5
#define AT_HLC 6 #define AT_HLC 6
#define AT_NUM 7 #define AT_CLIP 7
/* total number */
#define AT_NUM 8
/* variables in struct at_state_t */ /* variables in struct at_state_t */
#define VAR_ZSAU 0 #define VAR_ZSAU 0
@ -216,7 +213,6 @@ void gigaset_dbg_buffer(enum debuglevel level, const unsigned char *msg,
#define EV_START -110 #define EV_START -110
#define EV_STOP -111 #define EV_STOP -111
#define EV_IF_LOCK -112 #define EV_IF_LOCK -112
#define EV_PROTO_L2 -113
#define EV_ACCEPT -114 #define EV_ACCEPT -114
#define EV_DIAL -115 #define EV_DIAL -115
#define EV_HUP -116 #define EV_HUP -116
@ -224,12 +220,11 @@ void gigaset_dbg_buffer(enum debuglevel level, const unsigned char *msg,
#define EV_BC_CLOSED -118 #define EV_BC_CLOSED -118
/* input state */ /* input state */
#define INS_command 0x0001 #define INS_command 0x0001 /* receiving messages (not payload data) */
#define INS_DLE_char 0x0002 #define INS_DLE_char 0x0002 /* DLE flag received (in DLE mode) */
#define INS_byte_stuff 0x0004 #define INS_byte_stuff 0x0004
#define INS_have_data 0x0008 #define INS_have_data 0x0008
#define INS_skip_frame 0x0010 #define INS_DLE_command 0x0020 /* DLE message start (<DLE> X) received */
#define INS_DLE_command 0x0020
#define INS_flag_hunt 0x0040 #define INS_flag_hunt 0x0040
/* channel state */ /* channel state */
@ -259,6 +254,11 @@ void gigaset_dbg_buffer(enum debuglevel level, const unsigned char *msg,
#define SM_LOCKED 0 #define SM_LOCKED 0
#define SM_ISDN 1 /* default */ #define SM_ISDN 1 /* default */
/* layer 2 protocols (AT^SBPR=...) */
#define L2_BITSYNC 0
#define L2_HDLC 1
#define L2_VOICE 2
struct gigaset_ops; struct gigaset_ops;
struct gigaset_driver; struct gigaset_driver;
@ -286,8 +286,6 @@ extern struct reply_t gigaset_tab_cid[];
extern struct reply_t gigaset_tab_nocid[]; extern struct reply_t gigaset_tab_nocid[];
struct inbuf_t { struct inbuf_t {
unsigned char *rcvbuf; /* usb-gigaset receive buffer */
struct bc_state *bcs;
struct cardstate *cs; struct cardstate *cs;
int inputstate; int inputstate;
int head, tail; int head, tail;
@ -359,12 +357,6 @@ struct at_state_t {
struct bc_state *bcs; struct bc_state *bcs;
}; };
struct resp_type_t {
unsigned char *response;
int resp_code; /* RSP_XXXX */
int type; /* RT_XXXX */
};
struct event_t { struct event_t {
int type; int type;
void *ptr, *arg; void *ptr, *arg;
@ -395,7 +387,7 @@ struct bc_state {
unsigned chstate; /* bitmap (CHS_*) */ unsigned chstate; /* bitmap (CHS_*) */
int ignore; int ignore;
unsigned proto2; /* Layer 2 protocol (ISDN_PROTO_L2_*) */ unsigned proto2; /* layer 2 protocol (L2_*) */
char *commands[AT_NUM]; /* see AT_XXXX */ char *commands[AT_NUM]; /* see AT_XXXX */
#ifdef CONFIG_GIGASET_DEBUG #ifdef CONFIG_GIGASET_DEBUG
@ -410,6 +402,8 @@ struct bc_state {
struct usb_bc_state *usb; /* usb hardware driver (m105) */ struct usb_bc_state *usb; /* usb hardware driver (m105) */
struct bas_bc_state *bas; /* usb hardware driver (base) */ struct bas_bc_state *bas; /* usb hardware driver (base) */
} hw; } hw;
void *ap; /* LL application structure */
}; };
struct cardstate { struct cardstate {
@ -456,12 +450,13 @@ struct cardstate {
unsigned running; /* !=0 if events are handled */ unsigned running; /* !=0 if events are handled */
unsigned connected; /* !=0 if hardware is connected */ unsigned connected; /* !=0 if hardware is connected */
unsigned isdn_up; /* !=0 after ISDN_STAT_RUN */ unsigned isdn_up; /* !=0 after gigaset_isdn_start() */
unsigned cidmode; unsigned cidmode;
int myid; /* id for communication with LL */ int myid; /* id for communication with LL */
isdn_if iif; void *iif; /* LL interface structure */
unsigned short hw_hdr_len; /* headroom needed in data skbs */
struct reply_t *tabnocid; struct reply_t *tabnocid;
struct reply_t *tabcid; struct reply_t *tabcid;
@ -476,8 +471,8 @@ struct cardstate {
struct timer_list timer; struct timer_list timer;
int retry_count; int retry_count;
int dle; /* !=0 if modem commands/responses are int dle; /* !=0 if DLE mode is active
dle encoded */ (ZDLE=1 received -- M10x only) */
int cur_at_seq; /* sequence of AT commands being int cur_at_seq; /* sequence of AT commands being
processed */ processed */
int curchannel; /* channel those commands are meant int curchannel; /* channel those commands are meant
@ -616,7 +611,9 @@ struct gigaset_ops {
int (*baud_rate)(struct cardstate *cs, unsigned cflag); int (*baud_rate)(struct cardstate *cs, unsigned cflag);
int (*set_line_ctrl)(struct cardstate *cs, unsigned cflag); int (*set_line_ctrl)(struct cardstate *cs, unsigned cflag);
/* Called from i4l.c to put an skb into the send-queue. */ /* Called from LL interface to put an skb into the send-queue.
* After sending is completed, gigaset_skb_sent() must be called
* with the skb's link layer header preserved. */
int (*send_skb)(struct bc_state *bcs, struct sk_buff *skb); int (*send_skb)(struct bc_state *bcs, struct sk_buff *skb);
/* Called from ev-layer.c to process a block of data /* Called from ev-layer.c to process a block of data
@ -625,7 +622,8 @@ struct gigaset_ops {
}; };
/* = Common structures and definitions ======================================= */ /* = Common structures and definitions =======================================
*/
/* Parser states for DLE-Event: /* Parser states for DLE-Event:
* <DLE-EVENT>: <DLE_FLAG> "X" <EVENT> <DLE_FLAG> "." * <DLE-EVENT>: <DLE_FLAG> "X" <EVENT> <DLE_FLAG> "."
@ -638,8 +636,7 @@ struct gigaset_ops {
* Functions implemented in asyncdata.c * Functions implemented in asyncdata.c
*/ */
/* Called from i4l.c to put an skb into the send-queue. /* Called from LL interface to put an skb into the send queue. */
* After sending gigaset_skb_sent() should be called. */
int gigaset_m10x_send_skb(struct bc_state *bcs, struct sk_buff *skb); int gigaset_m10x_send_skb(struct bc_state *bcs, struct sk_buff *skb);
/* Called from ev-layer.c to process a block of data /* Called from ev-layer.c to process a block of data
@ -650,8 +647,7 @@ void gigaset_m10x_input(struct inbuf_t *inbuf);
* Functions implemented in isocdata.c * Functions implemented in isocdata.c
*/ */
/* Called from i4l.c to put an skb into the send-queue. /* Called from LL interface to put an skb into the send queue. */
* After sending gigaset_skb_sent() should be called. */
int gigaset_isoc_send_skb(struct bc_state *bcs, struct sk_buff *skb); int gigaset_isoc_send_skb(struct bc_state *bcs, struct sk_buff *skb);
/* Called from ev-layer.c to process a block of data /* Called from ev-layer.c to process a block of data
@ -674,36 +670,26 @@ void gigaset_isowbuf_init(struct isowbuf_t *iwb, unsigned char idle);
int gigaset_isowbuf_getbytes(struct isowbuf_t *iwb, int size); int gigaset_isowbuf_getbytes(struct isowbuf_t *iwb, int size);
/* =========================================================================== /* ===========================================================================
* Functions implemented in i4l.c/gigaset.h * Functions implemented in LL interface
*/ */
/* Called by gigaset_initcs() for setting up with the isdn4linux subsystem */ /* Called from common.c for setting up/shutting down with the ISDN subsystem */
int gigaset_register_to_LL(struct cardstate *cs, const char *isdnid); int gigaset_isdn_register(struct cardstate *cs, const char *isdnid);
void gigaset_isdn_unregister(struct cardstate *cs);
/* Called from xxx-gigaset.c to indicate completion of sending an skb */ /* Called from hardware module to indicate completion of an skb */
void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb); void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb);
void gigaset_skb_rcvd(struct bc_state *bcs, struct sk_buff *skb);
void gigaset_isdn_rcv_err(struct bc_state *bcs);
/* Called from common.c/ev-layer.c to indicate events relevant to the LL */ /* Called from common.c/ev-layer.c to indicate events relevant to the LL */
void gigaset_isdn_start(struct cardstate *cs);
void gigaset_isdn_stop(struct cardstate *cs);
int gigaset_isdn_icall(struct at_state_t *at_state); int gigaset_isdn_icall(struct at_state_t *at_state);
int gigaset_isdn_setup_accept(struct at_state_t *at_state); void gigaset_isdn_connD(struct bc_state *bcs);
int gigaset_isdn_setup_dial(struct at_state_t *at_state, void *data); void gigaset_isdn_hupD(struct bc_state *bcs);
void gigaset_isdn_connB(struct bc_state *bcs);
void gigaset_i4l_cmd(struct cardstate *cs, int cmd); void gigaset_isdn_hupB(struct bc_state *bcs);
void gigaset_i4l_channel_cmd(struct bc_state *bcs, int cmd);
static inline void gigaset_isdn_rcv_err(struct bc_state *bcs)
{
isdn_ctrl response;
/* error -> LL */
gig_dbg(DEBUG_CMD, "sending L1ERR");
response.driver = bcs->cs->myid;
response.command = ISDN_STAT_L1ERR;
response.arg = bcs->channel;
response.parm.errcode = ISDN_STAT_L1ERR_RECV;
bcs->cs->iif.statcallb(&response);
}
/* =========================================================================== /* ===========================================================================
* Functions implemented in ev-layer.c * Functions implemented in ev-layer.c
@ -732,6 +718,7 @@ void gigaset_bcs_reinit(struct bc_state *bcs);
void gigaset_at_init(struct at_state_t *at_state, struct bc_state *bcs, void gigaset_at_init(struct at_state_t *at_state, struct bc_state *bcs,
struct cardstate *cs, int cid); struct cardstate *cs, int cid);
int gigaset_get_channel(struct bc_state *bcs); int gigaset_get_channel(struct bc_state *bcs);
struct bc_state *gigaset_get_free_channel(struct cardstate *cs);
void gigaset_free_channel(struct bc_state *bcs); void gigaset_free_channel(struct bc_state *bcs);
int gigaset_get_channels(struct cardstate *cs); int gigaset_get_channels(struct cardstate *cs);
void gigaset_free_channels(struct cardstate *cs); void gigaset_free_channels(struct cardstate *cs);
@ -781,7 +768,7 @@ struct event_t *gigaset_add_event(struct cardstate *cs,
void *ptr, int parameter, void *arg); void *ptr, int parameter, void *arg);
/* Called on CONFIG1 command from frontend. */ /* Called on CONFIG1 command from frontend. */
int gigaset_enterconfigmode(struct cardstate *cs); //0: success <0: errorcode int gigaset_enterconfigmode(struct cardstate *cs);
/* cs->lock must not be locked */ /* cs->lock must not be locked */
static inline void gigaset_schedule_event(struct cardstate *cs) static inline void gigaset_schedule_event(struct cardstate *cs)
@ -816,35 +803,6 @@ static inline void gigaset_bchannel_up(struct bc_state *bcs)
/* handling routines for sk_buff */ /* handling routines for sk_buff */
/* ============================= */ /* ============================= */
/* pass received skb to LL
* Warning: skb must not be accessed anymore!
*/
static inline void gigaset_rcv_skb(struct sk_buff *skb,
struct cardstate *cs,
struct bc_state *bcs)
{
cs->iif.rcvcallb_skb(cs->myid, bcs->channel, skb);
bcs->trans_down++;
}
/* handle reception of corrupted skb
* Warning: skb must not be accessed anymore!
*/
static inline void gigaset_rcv_error(struct sk_buff *procskb,
struct cardstate *cs,
struct bc_state *bcs)
{
if (procskb)
dev_kfree_skb(procskb);
if (bcs->ignore)
--bcs->ignore;
else {
++bcs->corrupted;
gigaset_isdn_rcv_err(bcs);
}
}
/* append received bytes to inbuf */ /* append received bytes to inbuf */
int gigaset_fill_inbuf(struct inbuf_t *inbuf, const unsigned char *src, int gigaset_fill_inbuf(struct inbuf_t *inbuf, const unsigned char *src,
unsigned numbytes); unsigned numbytes);

View File

@ -14,6 +14,9 @@
*/ */
#include "gigaset.h" #include "gigaset.h"
#include <linux/isdnif.h>
#define HW_HDR_LEN 2 /* Header size used to store ack info */
/* == Handling of I4L IO =====================================================*/ /* == Handling of I4L IO =====================================================*/
@ -36,12 +39,12 @@
static int writebuf_from_LL(int driverID, int channel, int ack, static int writebuf_from_LL(int driverID, int channel, int ack,
struct sk_buff *skb) struct sk_buff *skb)
{ {
struct cardstate *cs; struct cardstate *cs = gigaset_get_cs_by_id(driverID);
struct bc_state *bcs; struct bc_state *bcs;
unsigned char *ack_header;
unsigned len; unsigned len;
unsigned skblen;
if (!(cs = gigaset_get_cs_by_id(driverID))) { if (!cs) {
pr_err("%s: invalid driver ID (%d)\n", __func__, driverID); pr_err("%s: invalid driver ID (%d)\n", __func__, driverID);
return -ENODEV; return -ENODEV;
} }
@ -75,11 +78,23 @@ static int writebuf_from_LL(int driverID, int channel, int ack,
return -EINVAL; return -EINVAL;
} }
skblen = ack ? len : 0; /* set up acknowledgement header */
skb->head[0] = skblen & 0xff; if (skb_headroom(skb) < HW_HDR_LEN) {
skb->head[1] = skblen >> 8; /* should never happen */
gig_dbg(DEBUG_MCMD, "skb: len=%u, skblen=%u: %02x %02x", dev_err(cs->dev, "%s: insufficient skb headroom\n", __func__);
len, skblen, (unsigned) skb->head[0], (unsigned) skb->head[1]); return -ENOMEM;
}
skb_set_mac_header(skb, -HW_HDR_LEN);
skb->mac_len = HW_HDR_LEN;
ack_header = skb_mac_header(skb);
if (ack) {
ack_header[0] = len & 0xff;
ack_header[1] = len >> 8;
} else {
ack_header[0] = ack_header[1] = 0;
}
gig_dbg(DEBUG_MCMD, "skb: len=%u, ack=%d: %02x %02x",
len, ack, ack_header[0], ack_header[1]);
/* pass to device-specific module */ /* pass to device-specific module */
return cs->ops->send_skb(bcs, skb); return cs->ops->send_skb(bcs, skb);
@ -95,6 +110,8 @@ static int writebuf_from_LL(int driverID, int channel, int ack,
*/ */
void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb) void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb)
{ {
isdn_if *iif = bcs->cs->iif;
unsigned char *ack_header = skb_mac_header(skb);
unsigned len; unsigned len;
isdn_ctrl response; isdn_ctrl response;
@ -104,8 +121,7 @@ void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb)
dev_warn(bcs->cs->dev, "%s: skb->len==%d\n", dev_warn(bcs->cs->dev, "%s: skb->len==%d\n",
__func__, skb->len); __func__, skb->len);
len = (unsigned char) skb->head[0] | len = ack_header[0] + ((unsigned) ack_header[1] << 8);
(unsigned) (unsigned char) skb->head[1] << 8;
if (len) { if (len) {
gig_dbg(DEBUG_MCMD, "ACKing to LL (id: %d, ch: %d, sz: %u)", gig_dbg(DEBUG_MCMD, "ACKing to LL (id: %d, ch: %d, sz: %u)",
bcs->cs->myid, bcs->channel, len); bcs->cs->myid, bcs->channel, len);
@ -114,71 +130,177 @@ void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb)
response.command = ISDN_STAT_BSENT; response.command = ISDN_STAT_BSENT;
response.arg = bcs->channel; response.arg = bcs->channel;
response.parm.length = len; response.parm.length = len;
bcs->cs->iif.statcallb(&response); iif->statcallb(&response);
} }
} }
EXPORT_SYMBOL_GPL(gigaset_skb_sent); EXPORT_SYMBOL_GPL(gigaset_skb_sent);
/**
* gigaset_skb_rcvd() - pass received skb to LL
* @bcs: B channel descriptor structure.
* @skb: received data.
*
* Called by hardware module {bas,ser,usb}_gigaset when user data has
* been successfully received, for passing to the LL.
* Warning: skb must not be accessed anymore!
*/
void gigaset_skb_rcvd(struct bc_state *bcs, struct sk_buff *skb)
{
isdn_if *iif = bcs->cs->iif;
iif->rcvcallb_skb(bcs->cs->myid, bcs->channel, skb);
bcs->trans_down++;
}
EXPORT_SYMBOL_GPL(gigaset_skb_rcvd);
/**
* gigaset_isdn_rcv_err() - signal receive error
* @bcs: B channel descriptor structure.
*
* Called by hardware module {bas,ser,usb}_gigaset when a receive error
* has occurred, for signalling to the LL.
*/
void gigaset_isdn_rcv_err(struct bc_state *bcs)
{
isdn_if *iif = bcs->cs->iif;
isdn_ctrl response;
/* if currently ignoring packets, just count down */
if (bcs->ignore) {
bcs->ignore--;
return;
}
/* update statistics */
bcs->corrupted++;
/* error -> LL */
gig_dbg(DEBUG_CMD, "sending L1ERR");
response.driver = bcs->cs->myid;
response.command = ISDN_STAT_L1ERR;
response.arg = bcs->channel;
response.parm.errcode = ISDN_STAT_L1ERR_RECV;
iif->statcallb(&response);
}
EXPORT_SYMBOL_GPL(gigaset_isdn_rcv_err);
/* This function will be called by LL to send commands /* This function will be called by LL to send commands
* NOTE: LL ignores the returned value, for commands other than ISDN_CMD_IOCTL, * NOTE: LL ignores the returned value, for commands other than ISDN_CMD_IOCTL,
* so don't put too much effort into it. * so don't put too much effort into it.
*/ */
static int command_from_LL(isdn_ctrl *cntrl) static int command_from_LL(isdn_ctrl *cntrl)
{ {
struct cardstate *cs = gigaset_get_cs_by_id(cntrl->driver); struct cardstate *cs;
struct bc_state *bcs; struct bc_state *bcs;
int retval = 0; int retval = 0;
struct setup_parm *sp; char **commands;
int ch;
int i;
size_t l;
gigaset_debugdrivers(); gigaset_debugdrivers();
if (!cs) { gig_dbg(DEBUG_CMD, "driver: %d, command: %d, arg: 0x%lx",
cntrl->driver, cntrl->command, cntrl->arg);
cs = gigaset_get_cs_by_id(cntrl->driver);
if (cs == NULL) {
pr_err("%s: invalid driver ID (%d)\n", __func__, cntrl->driver); pr_err("%s: invalid driver ID (%d)\n", __func__, cntrl->driver);
return -ENODEV; return -ENODEV;
} }
ch = cntrl->arg & 0xff;
switch (cntrl->command) { switch (cntrl->command) {
case ISDN_CMD_IOCTL: case ISDN_CMD_IOCTL:
gig_dbg(DEBUG_ANY, "ISDN_CMD_IOCTL (driver: %d, arg: %ld)",
cntrl->driver, cntrl->arg);
dev_warn(cs->dev, "ISDN_CMD_IOCTL not supported\n"); dev_warn(cs->dev, "ISDN_CMD_IOCTL not supported\n");
return -EINVAL; return -EINVAL;
case ISDN_CMD_DIAL: case ISDN_CMD_DIAL:
gig_dbg(DEBUG_ANY, gig_dbg(DEBUG_ANY,
"ISDN_CMD_DIAL (driver: %d, ch: %ld, " "ISDN_CMD_DIAL (phone: %s, msn: %s, si1: %d, si2: %d)",
"phone: %s, ownmsn: %s, si1: %d, si2: %d)",
cntrl->driver, cntrl->arg,
cntrl->parm.setup.phone, cntrl->parm.setup.eazmsn, cntrl->parm.setup.phone, cntrl->parm.setup.eazmsn,
cntrl->parm.setup.si1, cntrl->parm.setup.si2); cntrl->parm.setup.si1, cntrl->parm.setup.si2);
if (cntrl->arg >= cs->channels) { if (ch >= cs->channels) {
dev_err(cs->dev, dev_err(cs->dev,
"ISDN_CMD_DIAL: invalid channel (%d)\n", "ISDN_CMD_DIAL: invalid channel (%d)\n", ch);
(int) cntrl->arg);
return -EINVAL; return -EINVAL;
} }
bcs = cs->bcs + ch;
bcs = cs->bcs + cntrl->arg;
if (!gigaset_get_channel(bcs)) { if (!gigaset_get_channel(bcs)) {
dev_err(cs->dev, "ISDN_CMD_DIAL: channel not free\n"); dev_err(cs->dev, "ISDN_CMD_DIAL: channel not free\n");
return -EBUSY; return -EBUSY;
} }
sp = kmalloc(sizeof *sp, GFP_ATOMIC); commands = kzalloc(AT_NUM*(sizeof *commands), GFP_ATOMIC);
if (!sp) { if (!commands) {
gigaset_free_channel(bcs); gigaset_free_channel(bcs);
dev_err(cs->dev, "ISDN_CMD_DIAL: out of memory\n"); dev_err(cs->dev, "ISDN_CMD_DIAL: out of memory\n");
return -ENOMEM; return -ENOMEM;
} }
*sp = cntrl->parm.setup;
if (!gigaset_add_event(cs, &bcs->at_state, EV_DIAL, sp, l = 3 + strlen(cntrl->parm.setup.phone);
commands[AT_DIAL] = kmalloc(l, GFP_ATOMIC);
if (!commands[AT_DIAL])
goto oom;
if (cntrl->parm.setup.phone[0] == '*' &&
cntrl->parm.setup.phone[1] == '*') {
/* internal call: translate ** prefix to CTP value */
commands[AT_TYPE] = kstrdup("^SCTP=0\r", GFP_ATOMIC);
if (!commands[AT_TYPE])
goto oom;
snprintf(commands[AT_DIAL], l,
"D%s\r", cntrl->parm.setup.phone+2);
} else {
commands[AT_TYPE] = kstrdup("^SCTP=1\r", GFP_ATOMIC);
if (!commands[AT_TYPE])
goto oom;
snprintf(commands[AT_DIAL], l,
"D%s\r", cntrl->parm.setup.phone);
}
l = strlen(cntrl->parm.setup.eazmsn);
if (l) {
l += 8;
commands[AT_MSN] = kmalloc(l, GFP_ATOMIC);
if (!commands[AT_MSN])
goto oom;
snprintf(commands[AT_MSN], l, "^SMSN=%s\r",
cntrl->parm.setup.eazmsn);
}
switch (cntrl->parm.setup.si1) {
case 1: /* audio */
/* BC = 9090A3: 3.1 kHz audio, A-law */
commands[AT_BC] = kstrdup("^SBC=9090A3\r", GFP_ATOMIC);
if (!commands[AT_BC])
goto oom;
break;
case 7: /* data */
default: /* hope the app knows what it is doing */
/* BC = 8890: unrestricted digital information */
commands[AT_BC] = kstrdup("^SBC=8890\r", GFP_ATOMIC);
if (!commands[AT_BC])
goto oom;
}
/* ToDo: other si1 values, inspect si2, set HLC/LLC */
commands[AT_PROTO] = kmalloc(9, GFP_ATOMIC);
if (!commands[AT_PROTO])
goto oom;
snprintf(commands[AT_PROTO], 9, "^SBPR=%u\r", bcs->proto2);
commands[AT_ISO] = kmalloc(9, GFP_ATOMIC);
if (!commands[AT_ISO])
goto oom;
snprintf(commands[AT_ISO], 9, "^SISO=%u\r",
(unsigned) bcs->channel + 1);
if (!gigaset_add_event(cs, &bcs->at_state, EV_DIAL, commands,
bcs->at_state.seq_index, NULL)) { bcs->at_state.seq_index, NULL)) {
//FIXME what should we do? for (i = 0; i < AT_NUM; ++i)
kfree(sp); kfree(commands[i]);
kfree(commands);
gigaset_free_channel(bcs); gigaset_free_channel(bcs);
return -ENOMEM; return -ENOMEM;
} }
@ -186,115 +308,102 @@ static int command_from_LL(isdn_ctrl *cntrl)
gig_dbg(DEBUG_CMD, "scheduling DIAL"); gig_dbg(DEBUG_CMD, "scheduling DIAL");
gigaset_schedule_event(cs); gigaset_schedule_event(cs);
break; break;
case ISDN_CMD_ACCEPTD: //FIXME case ISDN_CMD_ACCEPTD:
gig_dbg(DEBUG_ANY, "ISDN_CMD_ACCEPTD"); if (ch >= cs->channels) {
if (cntrl->arg >= cs->channels) {
dev_err(cs->dev, dev_err(cs->dev,
"ISDN_CMD_ACCEPTD: invalid channel (%d)\n", "ISDN_CMD_ACCEPTD: invalid channel (%d)\n", ch);
(int) cntrl->arg);
return -EINVAL; return -EINVAL;
} }
bcs = cs->bcs + ch;
if (!gigaset_add_event(cs, &cs->bcs[cntrl->arg].at_state, if (!gigaset_add_event(cs, &bcs->at_state,
EV_ACCEPT, NULL, 0, NULL)) { EV_ACCEPT, NULL, 0, NULL))
//FIXME what should we do?
return -ENOMEM; return -ENOMEM;
}
gig_dbg(DEBUG_CMD, "scheduling ACCEPT"); gig_dbg(DEBUG_CMD, "scheduling ACCEPT");
gigaset_schedule_event(cs); gigaset_schedule_event(cs);
break; break;
case ISDN_CMD_ACCEPTB: case ISDN_CMD_ACCEPTB:
gig_dbg(DEBUG_ANY, "ISDN_CMD_ACCEPTB");
break; break;
case ISDN_CMD_HANGUP: case ISDN_CMD_HANGUP:
gig_dbg(DEBUG_ANY, "ISDN_CMD_HANGUP (ch: %d)", if (ch >= cs->channels) {
(int) cntrl->arg);
if (cntrl->arg >= cs->channels) {
dev_err(cs->dev, dev_err(cs->dev,
"ISDN_CMD_HANGUP: invalid channel (%d)\n", "ISDN_CMD_HANGUP: invalid channel (%d)\n", ch);
(int) cntrl->arg);
return -EINVAL; return -EINVAL;
} }
bcs = cs->bcs + ch;
if (!gigaset_add_event(cs, &cs->bcs[cntrl->arg].at_state, if (!gigaset_add_event(cs, &bcs->at_state,
EV_HUP, NULL, 0, NULL)) { EV_HUP, NULL, 0, NULL))
//FIXME what should we do?
return -ENOMEM; return -ENOMEM;
}
gig_dbg(DEBUG_CMD, "scheduling HUP"); gig_dbg(DEBUG_CMD, "scheduling HUP");
gigaset_schedule_event(cs); gigaset_schedule_event(cs);
break; break;
case ISDN_CMD_CLREAZ: /* Do not signal incoming signals */ //FIXME case ISDN_CMD_CLREAZ: /* Do not signal incoming signals */
gig_dbg(DEBUG_ANY, "ISDN_CMD_CLREAZ"); dev_info(cs->dev, "ignoring ISDN_CMD_CLREAZ\n");
break; break;
case ISDN_CMD_SETEAZ: /* Signal incoming calls for given MSN */ //FIXME case ISDN_CMD_SETEAZ: /* Signal incoming calls for given MSN */
gig_dbg(DEBUG_ANY, dev_info(cs->dev, "ignoring ISDN_CMD_SETEAZ (%s)\n",
"ISDN_CMD_SETEAZ (id: %d, ch: %ld, number: %s)", cntrl->parm.num);
cntrl->driver, cntrl->arg, cntrl->parm.num);
break; break;
case ISDN_CMD_SETL2: /* Set L2 to given protocol */ case ISDN_CMD_SETL2: /* Set L2 to given protocol */
gig_dbg(DEBUG_ANY, "ISDN_CMD_SETL2 (ch: %ld, proto: %lx)", if (ch >= cs->channels) {
cntrl->arg & 0xff, (cntrl->arg >> 8));
if ((cntrl->arg & 0xff) >= cs->channels) {
dev_err(cs->dev, dev_err(cs->dev,
"ISDN_CMD_SETL2: invalid channel (%d)\n", "ISDN_CMD_SETL2: invalid channel (%d)\n", ch);
(int) cntrl->arg & 0xff);
return -EINVAL; return -EINVAL;
} }
bcs = cs->bcs + ch;
if (!gigaset_add_event(cs, &cs->bcs[cntrl->arg & 0xff].at_state, if (bcs->chstate & CHS_D_UP) {
EV_PROTO_L2, NULL, cntrl->arg >> 8, dev_err(cs->dev,
NULL)) { "ISDN_CMD_SETL2: channel active (%d)\n", ch);
//FIXME what should we do? return -EINVAL;
return -ENOMEM; }
switch (cntrl->arg >> 8) {
case ISDN_PROTO_L2_HDLC:
gig_dbg(DEBUG_CMD, "ISDN_CMD_SETL2: setting L2_HDLC");
bcs->proto2 = L2_HDLC;
break;
case ISDN_PROTO_L2_TRANS:
gig_dbg(DEBUG_CMD, "ISDN_CMD_SETL2: setting L2_VOICE");
bcs->proto2 = L2_VOICE;
break;
default:
dev_err(cs->dev,
"ISDN_CMD_SETL2: unsupported protocol (%lu)\n",
cntrl->arg >> 8);
return -EINVAL;
} }
gig_dbg(DEBUG_CMD, "scheduling PROTO_L2");
gigaset_schedule_event(cs);
break; break;
case ISDN_CMD_SETL3: /* Set L3 to given protocol */ case ISDN_CMD_SETL3: /* Set L3 to given protocol */
gig_dbg(DEBUG_ANY, "ISDN_CMD_SETL3 (ch: %ld, proto: %lx)", if (ch >= cs->channels) {
cntrl->arg & 0xff, (cntrl->arg >> 8));
if ((cntrl->arg & 0xff) >= cs->channels) {
dev_err(cs->dev, dev_err(cs->dev,
"ISDN_CMD_SETL3: invalid channel (%d)\n", "ISDN_CMD_SETL3: invalid channel (%d)\n", ch);
(int) cntrl->arg & 0xff);
return -EINVAL; return -EINVAL;
} }
if (cntrl->arg >> 8 != ISDN_PROTO_L3_TRANS) { if (cntrl->arg >> 8 != ISDN_PROTO_L3_TRANS) {
dev_err(cs->dev, dev_err(cs->dev,
"ISDN_CMD_SETL3: invalid protocol %lu\n", "ISDN_CMD_SETL3: unsupported protocol (%lu)\n",
cntrl->arg >> 8); cntrl->arg >> 8);
return -EINVAL; return -EINVAL;
} }
break; break;
case ISDN_CMD_PROCEED: case ISDN_CMD_PROCEED:
gig_dbg(DEBUG_ANY, "ISDN_CMD_PROCEED"); //FIXME gig_dbg(DEBUG_ANY, "ISDN_CMD_PROCEED");
break; break;
case ISDN_CMD_ALERT: case ISDN_CMD_ALERT:
gig_dbg(DEBUG_ANY, "ISDN_CMD_ALERT"); //FIXME gig_dbg(DEBUG_ANY, "ISDN_CMD_ALERT");
if (cntrl->arg >= cs->channels) { if (cntrl->arg >= cs->channels) {
dev_err(cs->dev, dev_err(cs->dev,
"ISDN_CMD_ALERT: invalid channel (%d)\n", "ISDN_CMD_ALERT: invalid channel (%d)\n",
(int) cntrl->arg); (int) cntrl->arg);
return -EINVAL; return -EINVAL;
} }
//bcs = cs->bcs + cntrl->arg;
//bcs->proto2 = -1;
// FIXME
break; break;
case ISDN_CMD_REDIR: case ISDN_CMD_REDIR:
gig_dbg(DEBUG_ANY, "ISDN_CMD_REDIR"); //FIXME gig_dbg(DEBUG_ANY, "ISDN_CMD_REDIR");
break; break;
case ISDN_CMD_PROT_IO: case ISDN_CMD_PROT_IO:
gig_dbg(DEBUG_ANY, "ISDN_CMD_PROT_IO"); gig_dbg(DEBUG_ANY, "ISDN_CMD_PROT_IO");
@ -324,149 +433,34 @@ static int command_from_LL(isdn_ctrl *cntrl)
} }
return retval; return retval;
oom:
dev_err(bcs->cs->dev, "out of memory\n");
for (i = 0; i < AT_NUM; ++i)
kfree(commands[i]);
return -ENOMEM;
} }
void gigaset_i4l_cmd(struct cardstate *cs, int cmd) static void gigaset_i4l_cmd(struct cardstate *cs, int cmd)
{ {
isdn_if *iif = cs->iif;
isdn_ctrl command; isdn_ctrl command;
command.driver = cs->myid; command.driver = cs->myid;
command.command = cmd; command.command = cmd;
command.arg = 0; command.arg = 0;
cs->iif.statcallb(&command); iif->statcallb(&command);
} }
void gigaset_i4l_channel_cmd(struct bc_state *bcs, int cmd) static void gigaset_i4l_channel_cmd(struct bc_state *bcs, int cmd)
{ {
isdn_if *iif = bcs->cs->iif;
isdn_ctrl command; isdn_ctrl command;
command.driver = bcs->cs->myid; command.driver = bcs->cs->myid;
command.command = cmd; command.command = cmd;
command.arg = bcs->channel; command.arg = bcs->channel;
bcs->cs->iif.statcallb(&command); iif->statcallb(&command);
}
int gigaset_isdn_setup_dial(struct at_state_t *at_state, void *data)
{
struct bc_state *bcs = at_state->bcs;
unsigned proto;
const char *bc;
size_t length[AT_NUM];
size_t l;
int i;
struct setup_parm *sp = data;
switch (bcs->proto2) {
case ISDN_PROTO_L2_HDLC:
proto = 1; /* 0: Bitsynchron, 1: HDLC, 2: voice */
break;
case ISDN_PROTO_L2_TRANS:
proto = 2; /* 0: Bitsynchron, 1: HDLC, 2: voice */
break;
default:
dev_err(bcs->cs->dev, "%s: invalid L2 protocol: %u\n",
__func__, bcs->proto2);
return -EINVAL;
}
switch (sp->si1) {
case 1: /* audio */
bc = "9090A3"; /* 3.1 kHz audio, A-law */
break;
case 7: /* data */
default: /* hope the app knows what it is doing */
bc = "8890"; /* unrestricted digital information */
}
//FIXME add missing si1 values from 1TR6, inspect si2, set HLC/LLC
length[AT_DIAL ] = 1 + strlen(sp->phone) + 1 + 1;
l = strlen(sp->eazmsn);
length[AT_MSN ] = l ? 6 + l + 1 + 1 : 0;
length[AT_BC ] = 5 + strlen(bc) + 1 + 1;
length[AT_PROTO] = 6 + 1 + 1 + 1; /* proto: 1 character */
length[AT_ISO ] = 6 + 1 + 1 + 1; /* channel: 1 character */
length[AT_TYPE ] = 6 + 1 + 1 + 1; /* call type: 1 character */
length[AT_HLC ] = 0;
for (i = 0; i < AT_NUM; ++i) {
kfree(bcs->commands[i]);
bcs->commands[i] = NULL;
if (length[i] &&
!(bcs->commands[i] = kmalloc(length[i], GFP_ATOMIC))) {
dev_err(bcs->cs->dev, "out of memory\n");
return -ENOMEM;
}
}
/* type = 1: extern, 0: intern, 2: recall, 3: door, 4: centrex */
if (sp->phone[0] == '*' && sp->phone[1] == '*') {
/* internal call: translate ** prefix to CTP value */
snprintf(bcs->commands[AT_DIAL], length[AT_DIAL],
"D%s\r", sp->phone+2);
strncpy(bcs->commands[AT_TYPE], "^SCTP=0\r", length[AT_TYPE]);
} else {
snprintf(bcs->commands[AT_DIAL], length[AT_DIAL],
"D%s\r", sp->phone);
strncpy(bcs->commands[AT_TYPE], "^SCTP=1\r", length[AT_TYPE]);
}
if (bcs->commands[AT_MSN])
snprintf(bcs->commands[AT_MSN], length[AT_MSN],
"^SMSN=%s\r", sp->eazmsn);
snprintf(bcs->commands[AT_BC ], length[AT_BC ],
"^SBC=%s\r", bc);
snprintf(bcs->commands[AT_PROTO], length[AT_PROTO],
"^SBPR=%u\r", proto);
snprintf(bcs->commands[AT_ISO ], length[AT_ISO ],
"^SISO=%u\r", (unsigned)bcs->channel + 1);
return 0;
}
int gigaset_isdn_setup_accept(struct at_state_t *at_state)
{
unsigned proto;
size_t length[AT_NUM];
int i;
struct bc_state *bcs = at_state->bcs;
switch (bcs->proto2) {
case ISDN_PROTO_L2_HDLC:
proto = 1; /* 0: Bitsynchron, 1: HDLC, 2: voice */
break;
case ISDN_PROTO_L2_TRANS:
proto = 2; /* 0: Bitsynchron, 1: HDLC, 2: voice */
break;
default:
dev_err(at_state->cs->dev, "%s: invalid protocol: %u\n",
__func__, bcs->proto2);
return -EINVAL;
}
length[AT_DIAL ] = 0;
length[AT_MSN ] = 0;
length[AT_BC ] = 0;
length[AT_PROTO] = 6 + 1 + 1 + 1; /* proto: 1 character */
length[AT_ISO ] = 6 + 1 + 1 + 1; /* channel: 1 character */
length[AT_TYPE ] = 0;
length[AT_HLC ] = 0;
for (i = 0; i < AT_NUM; ++i) {
kfree(bcs->commands[i]);
bcs->commands[i] = NULL;
if (length[i] &&
!(bcs->commands[i] = kmalloc(length[i], GFP_ATOMIC))) {
dev_err(at_state->cs->dev, "out of memory\n");
return -ENOMEM;
}
}
snprintf(bcs->commands[AT_PROTO], length[AT_PROTO],
"^SBPR=%u\r", proto);
snprintf(bcs->commands[AT_ISO ], length[AT_ISO ],
"^SISO=%u\r", (unsigned) bcs->channel + 1);
return 0;
} }
/** /**
@ -482,13 +476,14 @@ int gigaset_isdn_icall(struct at_state_t *at_state)
{ {
struct cardstate *cs = at_state->cs; struct cardstate *cs = at_state->cs;
struct bc_state *bcs = at_state->bcs; struct bc_state *bcs = at_state->bcs;
isdn_if *iif = cs->iif;
isdn_ctrl response; isdn_ctrl response;
int retval; int retval;
/* fill ICALL structure */ /* fill ICALL structure */
response.parm.setup.si1 = 0; /* default: unknown */ response.parm.setup.si1 = 0; /* default: unknown */
response.parm.setup.si2 = 0; response.parm.setup.si2 = 0;
response.parm.setup.screen = 0; //FIXME how to set these? response.parm.setup.screen = 0;
response.parm.setup.plan = 0; response.parm.setup.plan = 0;
if (!at_state->str_var[STR_ZBC]) { if (!at_state->str_var[STR_ZBC]) {
/* no BC (internal call): assume speech, A-law */ /* no BC (internal call): assume speech, A-law */
@ -509,29 +504,27 @@ int gigaset_isdn_icall(struct at_state_t *at_state)
return ICALL_IGNORE; return ICALL_IGNORE;
} }
if (at_state->str_var[STR_NMBR]) { if (at_state->str_var[STR_NMBR]) {
strncpy(response.parm.setup.phone, at_state->str_var[STR_NMBR], strlcpy(response.parm.setup.phone, at_state->str_var[STR_NMBR],
sizeof response.parm.setup.phone - 1); sizeof response.parm.setup.phone);
response.parm.setup.phone[sizeof response.parm.setup.phone - 1] = 0;
} else } else
response.parm.setup.phone[0] = 0; response.parm.setup.phone[0] = 0;
if (at_state->str_var[STR_ZCPN]) { if (at_state->str_var[STR_ZCPN]) {
strncpy(response.parm.setup.eazmsn, at_state->str_var[STR_ZCPN], strlcpy(response.parm.setup.eazmsn, at_state->str_var[STR_ZCPN],
sizeof response.parm.setup.eazmsn - 1); sizeof response.parm.setup.eazmsn);
response.parm.setup.eazmsn[sizeof response.parm.setup.eazmsn - 1] = 0;
} else } else
response.parm.setup.eazmsn[0] = 0; response.parm.setup.eazmsn[0] = 0;
if (!bcs) { if (!bcs) {
dev_notice(cs->dev, "no channel for incoming call\n"); dev_notice(cs->dev, "no channel for incoming call\n");
response.command = ISDN_STAT_ICALLW; response.command = ISDN_STAT_ICALLW;
response.arg = 0; //FIXME response.arg = 0;
} else { } else {
gig_dbg(DEBUG_CMD, "Sending ICALL"); gig_dbg(DEBUG_CMD, "Sending ICALL");
response.command = ISDN_STAT_ICALL; response.command = ISDN_STAT_ICALL;
response.arg = bcs->channel; //FIXME response.arg = bcs->channel;
} }
response.driver = cs->myid; response.driver = cs->myid;
retval = cs->iif.statcallb(&response); retval = iif->statcallb(&response);
gig_dbg(DEBUG_CMD, "Response: %d", retval); gig_dbg(DEBUG_CMD, "Response: %d", retval);
switch (retval) { switch (retval) {
case 0: /* no takers */ case 0: /* no takers */
@ -560,16 +553,109 @@ int gigaset_isdn_icall(struct at_state_t *at_state)
} }
} }
/* Set Callback function pointer */ /**
int gigaset_register_to_LL(struct cardstate *cs, const char *isdnid) * gigaset_isdn_connD() - signal D channel connect
* @bcs: B channel descriptor structure.
*
* Called by main module to notify the LL that the D channel connection has
* been established.
*/
void gigaset_isdn_connD(struct bc_state *bcs)
{ {
isdn_if *iif = &cs->iif; gig_dbg(DEBUG_CMD, "sending DCONN");
gigaset_i4l_channel_cmd(bcs, ISDN_STAT_DCONN);
}
gig_dbg(DEBUG_ANY, "Register driver capabilities to LL"); /**
* gigaset_isdn_hupD() - signal D channel hangup
* @bcs: B channel descriptor structure.
*
* Called by main module to notify the LL that the D channel connection has
* been shut down.
*/
void gigaset_isdn_hupD(struct bc_state *bcs)
{
gig_dbg(DEBUG_CMD, "sending DHUP");
gigaset_i4l_channel_cmd(bcs, ISDN_STAT_DHUP);
}
/**
* gigaset_isdn_connB() - signal B channel connect
* @bcs: B channel descriptor structure.
*
* Called by main module to notify the LL that the B channel connection has
* been established.
*/
void gigaset_isdn_connB(struct bc_state *bcs)
{
gig_dbg(DEBUG_CMD, "sending BCONN");
gigaset_i4l_channel_cmd(bcs, ISDN_STAT_BCONN);
}
/**
* gigaset_isdn_hupB() - signal B channel hangup
* @bcs: B channel descriptor structure.
*
* Called by main module to notify the LL that the B channel connection has
* been shut down.
*/
void gigaset_isdn_hupB(struct bc_state *bcs)
{
gig_dbg(DEBUG_CMD, "sending BHUP");
gigaset_i4l_channel_cmd(bcs, ISDN_STAT_BHUP);
}
/**
* gigaset_isdn_start() - signal device availability
* @cs: device descriptor structure.
*
* Called by main module to notify the LL that the device is available for
* use.
*/
void gigaset_isdn_start(struct cardstate *cs)
{
gig_dbg(DEBUG_CMD, "sending RUN");
gigaset_i4l_cmd(cs, ISDN_STAT_RUN);
}
/**
* gigaset_isdn_stop() - signal device unavailability
* @cs: device descriptor structure.
*
* Called by main module to notify the LL that the device is no longer
* available for use.
*/
void gigaset_isdn_stop(struct cardstate *cs)
{
gig_dbg(DEBUG_CMD, "sending STOP");
gigaset_i4l_cmd(cs, ISDN_STAT_STOP);
}
/**
* gigaset_isdn_register() - register to LL
* @cs: device descriptor structure.
* @isdnid: device name.
*
* Called by main module to register the device with the LL.
*
* Return value: 1 for success, 0 for failure
*/
int gigaset_isdn_register(struct cardstate *cs, const char *isdnid)
{
isdn_if *iif;
pr_info("ISDN4Linux interface\n");
iif = kmalloc(sizeof *iif, GFP_KERNEL);
if (!iif) {
pr_err("out of memory\n");
return 0;
}
if (snprintf(iif->id, sizeof iif->id, "%s_%u", isdnid, cs->minor_index) if (snprintf(iif->id, sizeof iif->id, "%s_%u", isdnid, cs->minor_index)
>= sizeof iif->id) { >= sizeof iif->id) {
pr_err("ID too long: %s\n", isdnid); pr_err("ID too long: %s\n", isdnid);
kfree(iif);
return 0; return 0;
} }
@ -593,9 +679,26 @@ int gigaset_register_to_LL(struct cardstate *cs, const char *isdnid)
if (!register_isdn(iif)) { if (!register_isdn(iif)) {
pr_err("register_isdn failed\n"); pr_err("register_isdn failed\n");
kfree(iif);
return 0; return 0;
} }
cs->iif = iif;
cs->myid = iif->channels; /* Set my device id */ cs->myid = iif->channels; /* Set my device id */
cs->hw_hdr_len = HW_HDR_LEN;
return 1; return 1;
} }
/**
* gigaset_isdn_unregister() - unregister from LL
* @cs: device descriptor structure.
*
* Called by main module to unregister the device from the LL.
*/
void gigaset_isdn_unregister(struct cardstate *cs)
{
gig_dbg(DEBUG_CMD, "sending UNLOAD");
gigaset_i4l_cmd(cs, ISDN_STAT_UNLOAD);
kfree(cs->iif);
cs->iif = NULL;
}

View File

@ -162,7 +162,7 @@ static int if_open(struct tty_struct *tty, struct file *filp)
return -ENODEV; return -ENODEV;
if (mutex_lock_interruptible(&cs->mutex)) if (mutex_lock_interruptible(&cs->mutex))
return -ERESTARTSYS; // FIXME -EINTR? return -ERESTARTSYS;
tty->driver_data = cs; tty->driver_data = cs;
++cs->open_count; ++cs->open_count;
@ -171,7 +171,7 @@ static int if_open(struct tty_struct *tty, struct file *filp)
spin_lock_irqsave(&cs->lock, flags); spin_lock_irqsave(&cs->lock, flags);
cs->tty = tty; cs->tty = tty;
spin_unlock_irqrestore(&cs->lock, flags); spin_unlock_irqrestore(&cs->lock, flags);
tty->low_latency = 1; //FIXME test tty->low_latency = 1;
} }
mutex_unlock(&cs->mutex); mutex_unlock(&cs->mutex);
@ -228,7 +228,7 @@ static int if_ioctl(struct tty_struct *tty, struct file *file,
gig_dbg(DEBUG_IF, "%u: %s(0x%x)", cs->minor_index, __func__, cmd); gig_dbg(DEBUG_IF, "%u: %s(0x%x)", cs->minor_index, __func__, cmd);
if (mutex_lock_interruptible(&cs->mutex)) if (mutex_lock_interruptible(&cs->mutex))
return -ERESTARTSYS; // FIXME -EINTR? return -ERESTARTSYS;
if (!cs->connected) { if (!cs->connected) {
gig_dbg(DEBUG_IF, "not connected"); gig_dbg(DEBUG_IF, "not connected");
@ -299,9 +299,8 @@ static int if_tiocmget(struct tty_struct *tty, struct file *file)
gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__); gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
if (mutex_lock_interruptible(&cs->mutex)) if (mutex_lock_interruptible(&cs->mutex))
return -ERESTARTSYS; // FIXME -EINTR? return -ERESTARTSYS;
// FIXME read from device?
retval = cs->control_state & (TIOCM_RTS|TIOCM_DTR); retval = cs->control_state & (TIOCM_RTS|TIOCM_DTR);
mutex_unlock(&cs->mutex); mutex_unlock(&cs->mutex);
@ -326,7 +325,7 @@ static int if_tiocmset(struct tty_struct *tty, struct file *file,
cs->minor_index, __func__, set, clear); cs->minor_index, __func__, set, clear);
if (mutex_lock_interruptible(&cs->mutex)) if (mutex_lock_interruptible(&cs->mutex))
return -ERESTARTSYS; // FIXME -EINTR? return -ERESTARTSYS;
if (!cs->connected) { if (!cs->connected) {
gig_dbg(DEBUG_IF, "not connected"); gig_dbg(DEBUG_IF, "not connected");
@ -356,7 +355,7 @@ static int if_write(struct tty_struct *tty, const unsigned char *buf, int count)
gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__); gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
if (mutex_lock_interruptible(&cs->mutex)) if (mutex_lock_interruptible(&cs->mutex))
return -ERESTARTSYS; // FIXME -EINTR? return -ERESTARTSYS;
if (!cs->connected) { if (!cs->connected) {
gig_dbg(DEBUG_IF, "not connected"); gig_dbg(DEBUG_IF, "not connected");
@ -390,7 +389,7 @@ static int if_write_room(struct tty_struct *tty)
gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__); gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
if (mutex_lock_interruptible(&cs->mutex)) if (mutex_lock_interruptible(&cs->mutex))
return -ERESTARTSYS; // FIXME -EINTR? return -ERESTARTSYS;
if (!cs->connected) { if (!cs->connected) {
gig_dbg(DEBUG_IF, "not connected"); gig_dbg(DEBUG_IF, "not connected");
@ -455,9 +454,8 @@ static void if_throttle(struct tty_struct *tty)
gig_dbg(DEBUG_IF, "not connected"); /* nothing to do */ gig_dbg(DEBUG_IF, "not connected"); /* nothing to do */
else if (!cs->open_count) else if (!cs->open_count)
dev_warn(cs->dev, "%s: device not opened\n", __func__); dev_warn(cs->dev, "%s: device not opened\n", __func__);
else { else
//FIXME gig_dbg(DEBUG_ANY, "%s: not implemented\n", __func__);
}
mutex_unlock(&cs->mutex); mutex_unlock(&cs->mutex);
} }
@ -480,9 +478,8 @@ static void if_unthrottle(struct tty_struct *tty)
gig_dbg(DEBUG_IF, "not connected"); /* nothing to do */ gig_dbg(DEBUG_IF, "not connected"); /* nothing to do */
else if (!cs->open_count) else if (!cs->open_count)
dev_warn(cs->dev, "%s: device not opened\n", __func__); dev_warn(cs->dev, "%s: device not opened\n", __func__);
else { else
//FIXME gig_dbg(DEBUG_ANY, "%s: not implemented\n", __func__);
}
mutex_unlock(&cs->mutex); mutex_unlock(&cs->mutex);
} }
@ -515,10 +512,9 @@ static void if_set_termios(struct tty_struct *tty, struct ktermios *old)
goto out; goto out;
} }
// stolen from mct_u232.c
iflag = tty->termios->c_iflag; iflag = tty->termios->c_iflag;
cflag = tty->termios->c_cflag; cflag = tty->termios->c_cflag;
old_cflag = old ? old->c_cflag : cflag; //FIXME? old_cflag = old ? old->c_cflag : cflag;
gig_dbg(DEBUG_IF, "%u: iflag %x cflag %x old %x", gig_dbg(DEBUG_IF, "%u: iflag %x cflag %x old %x",
cs->minor_index, iflag, cflag, old_cflag); cs->minor_index, iflag, cflag, old_cflag);
@ -588,7 +584,7 @@ void gigaset_if_init(struct cardstate *cs)
if (!drv->have_tty) if (!drv->have_tty)
return; return;
tasklet_init(&cs->if_wake_tasklet, &if_wake, (unsigned long) cs); tasklet_init(&cs->if_wake_tasklet, if_wake, (unsigned long) cs);
mutex_lock(&cs->mutex); mutex_lock(&cs->mutex);
cs->tty_dev = tty_register_device(drv->tty, cs->minor_index, NULL); cs->tty_dev = tty_register_device(drv->tty, cs->minor_index, NULL);
@ -632,7 +628,8 @@ void gigaset_if_receive(struct cardstate *cs,
struct tty_struct *tty; struct tty_struct *tty;
spin_lock_irqsave(&cs->lock, flags); spin_lock_irqsave(&cs->lock, flags);
if ((tty = cs->tty) == NULL) tty = cs->tty;
if (tty == NULL)
gig_dbg(DEBUG_ANY, "receive on closed device"); gig_dbg(DEBUG_ANY, "receive on closed device");
else { else {
tty_buffer_request_room(tty, len); tty_buffer_request_room(tty, len);
@ -659,9 +656,9 @@ void gigaset_if_initdriver(struct gigaset_driver *drv, const char *procname,
drv->have_tty = 0; drv->have_tty = 0;
if ((drv->tty = alloc_tty_driver(minors)) == NULL) drv->tty = tty = alloc_tty_driver(minors);
if (tty == NULL)
goto enomem; goto enomem;
tty = drv->tty;
tty->magic = TTY_DRIVER_MAGIC, tty->magic = TTY_DRIVER_MAGIC,
tty->major = GIG_MAJOR, tty->major = GIG_MAJOR,
@ -676,8 +673,8 @@ void gigaset_if_initdriver(struct gigaset_driver *drv, const char *procname,
tty->owner = THIS_MODULE; tty->owner = THIS_MODULE;
tty->init_termios = tty_std_termios; //FIXME tty->init_termios = tty_std_termios;
tty->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; //FIXME tty->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
tty_set_operations(tty, &if_ops); tty_set_operations(tty, &if_ops);
ret = tty_register_driver(tty); ret = tty_register_driver(tty);

View File

@ -41,7 +41,8 @@ static inline int isowbuf_freebytes(struct isowbuf_t *iwb)
read = iwb->read; read = iwb->read;
write = iwb->write; write = iwb->write;
if ((freebytes = read - write) > 0) { freebytes = read - write;
if (freebytes > 0) {
/* no wraparound: need padding space within regular area */ /* no wraparound: need padding space within regular area */
return freebytes - BAS_OUTBUFPAD; return freebytes - BAS_OUTBUFPAD;
} else if (read < BAS_OUTBUFPAD) { } else if (read < BAS_OUTBUFPAD) {
@ -53,29 +54,6 @@ static inline int isowbuf_freebytes(struct isowbuf_t *iwb)
} }
} }
/* compare two offsets within the buffer
* The buffer is seen as circular, with the read position as start
* returns -1/0/1 if position a </=/> position b without crossing 'read'
*/
static inline int isowbuf_poscmp(struct isowbuf_t *iwb, int a, int b)
{
int read;
if (a == b)
return 0;
read = iwb->read;
if (a < b) {
if (a < read && read <= b)
return +1;
else
return -1;
} else {
if (b < read && read <= a)
return -1;
else
return +1;
}
}
/* start writing /* start writing
* acquire the write semaphore * acquire the write semaphore
* return true if acquired, false if busy * return true if acquired, false if busy
@ -271,7 +249,7 @@ static inline void dump_bytes(enum debuglevel level, const char *tag,
* bit 14..13 = number of bits added by stuffing * bit 14..13 = number of bits added by stuffing
*/ */
static const u16 stufftab[5 * 256] = { static const u16 stufftab[5 * 256] = {
// previous 1s = 0: /* previous 1s = 0: */
0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x201f, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x201f,
0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
@ -289,7 +267,7 @@ static const u16 stufftab[5 * 256] = {
0x0ce0, 0x0ce1, 0x0ce2, 0x0ce3, 0x0ce4, 0x0ce5, 0x0ce6, 0x0ce7, 0x0ce8, 0x0ce9, 0x0cea, 0x0ceb, 0x0cec, 0x0ced, 0x0cee, 0x0cef, 0x0ce0, 0x0ce1, 0x0ce2, 0x0ce3, 0x0ce4, 0x0ce5, 0x0ce6, 0x0ce7, 0x0ce8, 0x0ce9, 0x0cea, 0x0ceb, 0x0cec, 0x0ced, 0x0cee, 0x0cef,
0x10f0, 0x10f1, 0x10f2, 0x10f3, 0x10f4, 0x10f5, 0x10f6, 0x10f7, 0x20f8, 0x20f9, 0x20fa, 0x20fb, 0x257c, 0x257d, 0x29be, 0x2ddf, 0x10f0, 0x10f1, 0x10f2, 0x10f3, 0x10f4, 0x10f5, 0x10f6, 0x10f7, 0x20f8, 0x20f9, 0x20fa, 0x20fb, 0x257c, 0x257d, 0x29be, 0x2ddf,
// previous 1s = 1: /* previous 1s = 1: */
0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x200f, 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x200f,
0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x202f, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x202f,
0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x204f, 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x204f,
@ -307,7 +285,7 @@ static const u16 stufftab[5 * 256] = {
0x0ce0, 0x0ce1, 0x0ce2, 0x0ce3, 0x0ce4, 0x0ce5, 0x0ce6, 0x0ce7, 0x0ce8, 0x0ce9, 0x0cea, 0x0ceb, 0x0cec, 0x0ced, 0x0cee, 0x2dcf, 0x0ce0, 0x0ce1, 0x0ce2, 0x0ce3, 0x0ce4, 0x0ce5, 0x0ce6, 0x0ce7, 0x0ce8, 0x0ce9, 0x0cea, 0x0ceb, 0x0cec, 0x0ced, 0x0cee, 0x2dcf,
0x10f0, 0x10f1, 0x10f2, 0x10f3, 0x10f4, 0x10f5, 0x10f6, 0x10f7, 0x20f8, 0x20f9, 0x20fa, 0x20fb, 0x257c, 0x257d, 0x29be, 0x31ef, 0x10f0, 0x10f1, 0x10f2, 0x10f3, 0x10f4, 0x10f5, 0x10f6, 0x10f7, 0x20f8, 0x20f9, 0x20fa, 0x20fb, 0x257c, 0x257d, 0x29be, 0x31ef,
// previous 1s = 2: /* previous 1s = 2: */
0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x2007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x2017, 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x2007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x2017,
0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x2027, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x2037, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x2027, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x2037,
0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x2047, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x2057, 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x2047, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x2057,
@ -325,7 +303,7 @@ static const u16 stufftab[5 * 256] = {
0x0ce0, 0x0ce1, 0x0ce2, 0x0ce3, 0x0ce4, 0x0ce5, 0x0ce6, 0x2dc7, 0x0ce8, 0x0ce9, 0x0cea, 0x0ceb, 0x0cec, 0x0ced, 0x0cee, 0x2dd7, 0x0ce0, 0x0ce1, 0x0ce2, 0x0ce3, 0x0ce4, 0x0ce5, 0x0ce6, 0x2dc7, 0x0ce8, 0x0ce9, 0x0cea, 0x0ceb, 0x0cec, 0x0ced, 0x0cee, 0x2dd7,
0x10f0, 0x10f1, 0x10f2, 0x10f3, 0x10f4, 0x10f5, 0x10f6, 0x31e7, 0x20f8, 0x20f9, 0x20fa, 0x20fb, 0x257c, 0x257d, 0x29be, 0x41f7, 0x10f0, 0x10f1, 0x10f2, 0x10f3, 0x10f4, 0x10f5, 0x10f6, 0x31e7, 0x20f8, 0x20f9, 0x20fa, 0x20fb, 0x257c, 0x257d, 0x29be, 0x41f7,
// previous 1s = 3: /* previous 1s = 3: */
0x0000, 0x0001, 0x0002, 0x2003, 0x0004, 0x0005, 0x0006, 0x200b, 0x0008, 0x0009, 0x000a, 0x2013, 0x000c, 0x000d, 0x000e, 0x201b, 0x0000, 0x0001, 0x0002, 0x2003, 0x0004, 0x0005, 0x0006, 0x200b, 0x0008, 0x0009, 0x000a, 0x2013, 0x000c, 0x000d, 0x000e, 0x201b,
0x0010, 0x0011, 0x0012, 0x2023, 0x0014, 0x0015, 0x0016, 0x202b, 0x0018, 0x0019, 0x001a, 0x2033, 0x001c, 0x001d, 0x001e, 0x203b, 0x0010, 0x0011, 0x0012, 0x2023, 0x0014, 0x0015, 0x0016, 0x202b, 0x0018, 0x0019, 0x001a, 0x2033, 0x001c, 0x001d, 0x001e, 0x203b,
0x0020, 0x0021, 0x0022, 0x2043, 0x0024, 0x0025, 0x0026, 0x204b, 0x0028, 0x0029, 0x002a, 0x2053, 0x002c, 0x002d, 0x002e, 0x205b, 0x0020, 0x0021, 0x0022, 0x2043, 0x0024, 0x0025, 0x0026, 0x204b, 0x0028, 0x0029, 0x002a, 0x2053, 0x002c, 0x002d, 0x002e, 0x205b,
@ -343,7 +321,7 @@ static const u16 stufftab[5 * 256] = {
0x0ce0, 0x0ce1, 0x0ce2, 0x2dc3, 0x0ce4, 0x0ce5, 0x0ce6, 0x2dcb, 0x0ce8, 0x0ce9, 0x0cea, 0x2dd3, 0x0cec, 0x0ced, 0x0cee, 0x2ddb, 0x0ce0, 0x0ce1, 0x0ce2, 0x2dc3, 0x0ce4, 0x0ce5, 0x0ce6, 0x2dcb, 0x0ce8, 0x0ce9, 0x0cea, 0x2dd3, 0x0cec, 0x0ced, 0x0cee, 0x2ddb,
0x10f0, 0x10f1, 0x10f2, 0x31e3, 0x10f4, 0x10f5, 0x10f6, 0x31eb, 0x20f8, 0x20f9, 0x20fa, 0x41f3, 0x257c, 0x257d, 0x29be, 0x46fb, 0x10f0, 0x10f1, 0x10f2, 0x31e3, 0x10f4, 0x10f5, 0x10f6, 0x31eb, 0x20f8, 0x20f9, 0x20fa, 0x41f3, 0x257c, 0x257d, 0x29be, 0x46fb,
// previous 1s = 4: /* previous 1s = 4: */
0x0000, 0x2001, 0x0002, 0x2005, 0x0004, 0x2009, 0x0006, 0x200d, 0x0008, 0x2011, 0x000a, 0x2015, 0x000c, 0x2019, 0x000e, 0x201d, 0x0000, 0x2001, 0x0002, 0x2005, 0x0004, 0x2009, 0x0006, 0x200d, 0x0008, 0x2011, 0x000a, 0x2015, 0x000c, 0x2019, 0x000e, 0x201d,
0x0010, 0x2021, 0x0012, 0x2025, 0x0014, 0x2029, 0x0016, 0x202d, 0x0018, 0x2031, 0x001a, 0x2035, 0x001c, 0x2039, 0x001e, 0x203d, 0x0010, 0x2021, 0x0012, 0x2025, 0x0014, 0x2029, 0x0016, 0x202d, 0x0018, 0x2031, 0x001a, 0x2035, 0x001c, 0x2039, 0x001e, 0x203d,
0x0020, 0x2041, 0x0022, 0x2045, 0x0024, 0x2049, 0x0026, 0x204d, 0x0028, 0x2051, 0x002a, 0x2055, 0x002c, 0x2059, 0x002e, 0x205d, 0x0020, 0x2041, 0x0022, 0x2045, 0x0024, 0x2049, 0x0026, 0x204d, 0x0028, 0x2051, 0x002a, 0x2055, 0x002c, 0x2059, 0x002e, 0x205d,
@ -367,7 +345,8 @@ static const u16 stufftab[5 * 256] = {
* parameters: * parameters:
* cin input byte * cin input byte
* ones number of trailing '1' bits in result before this step * ones number of trailing '1' bits in result before this step
* iwb pointer to output buffer structure (write semaphore must be held) * iwb pointer to output buffer structure
* (write semaphore must be held)
* return value: * return value:
* number of trailing '1' bits in result after this step * number of trailing '1' bits in result after this step
*/ */
@ -408,7 +387,8 @@ static inline int hdlc_bitstuff_byte(struct isowbuf_t *iwb, unsigned char cin,
* parameters: * parameters:
* in input buffer * in input buffer
* count number of bytes in input buffer * count number of bytes in input buffer
* iwb pointer to output buffer structure (write semaphore must be held) * iwb pointer to output buffer structure
* (write semaphore must be held)
* return value: * return value:
* position of end of packet in output buffer on success, * position of end of packet in output buffer on success,
* -EAGAIN if write semaphore busy or buffer full * -EAGAIN if write semaphore busy or buffer full
@ -440,7 +420,8 @@ static inline int hdlc_buildframe(struct isowbuf_t *iwb,
fcs = crc_ccitt_byte(fcs, c); fcs = crc_ccitt_byte(fcs, c);
} }
/* bitstuff and append FCS (complemented, least significant byte first) */ /* bitstuff and append FCS
* (complemented, least significant byte first) */
fcs ^= 0xffff; fcs ^= 0xffff;
ones = hdlc_bitstuff_byte(iwb, fcs & 0x00ff, ones); ones = hdlc_bitstuff_byte(iwb, fcs & 0x00ff, ones);
ones = hdlc_bitstuff_byte(iwb, (fcs >> 8) & 0x00ff, ones); ones = hdlc_bitstuff_byte(iwb, (fcs >> 8) & 0x00ff, ones);
@ -459,7 +440,8 @@ static inline int hdlc_buildframe(struct isowbuf_t *iwb,
* parameters: * parameters:
* in input buffer * in input buffer
* count number of bytes in input buffer * count number of bytes in input buffer
* iwb pointer to output buffer structure (write semaphore must be held) * iwb pointer to output buffer structure
* (write semaphore must be held)
* return value: * return value:
* position of end of packet in output buffer on success, * position of end of packet in output buffer on success,
* -EAGAIN if write semaphore busy or buffer full * -EAGAIN if write semaphore busy or buffer full
@ -500,7 +482,7 @@ int gigaset_isoc_buildframe(struct bc_state *bcs, unsigned char *in, int len)
int result; int result;
switch (bcs->proto2) { switch (bcs->proto2) {
case ISDN_PROTO_L2_HDLC: case L2_HDLC:
result = hdlc_buildframe(bcs->hw.bas->isooutbuf, in, len); result = hdlc_buildframe(bcs->hw.bas->isooutbuf, in, len);
gig_dbg(DEBUG_ISO, "%s: %d bytes HDLC -> %d", gig_dbg(DEBUG_ISO, "%s: %d bytes HDLC -> %d",
__func__, len, result); __func__, len, result);
@ -542,8 +524,9 @@ static inline void hdlc_flush(struct bc_state *bcs)
if (likely(bcs->skb != NULL)) if (likely(bcs->skb != NULL))
skb_trim(bcs->skb, 0); skb_trim(bcs->skb, 0);
else if (!bcs->ignore) { else if (!bcs->ignore) {
if ((bcs->skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL) bcs->skb = dev_alloc_skb(SBUFSIZE + bcs->cs->hw_hdr_len);
skb_reserve(bcs->skb, HW_HDR_LEN); if (bcs->skb)
skb_reserve(bcs->skb, bcs->cs->hw_hdr_len);
else else
dev_err(bcs->cs->dev, "could not allocate skb\n"); dev_err(bcs->cs->dev, "could not allocate skb\n");
} }
@ -557,43 +540,46 @@ static inline void hdlc_flush(struct bc_state *bcs)
*/ */
static inline void hdlc_done(struct bc_state *bcs) static inline void hdlc_done(struct bc_state *bcs)
{ {
struct cardstate *cs = bcs->cs;
struct sk_buff *procskb; struct sk_buff *procskb;
unsigned int len;
if (unlikely(bcs->ignore)) { if (unlikely(bcs->ignore)) {
bcs->ignore--; bcs->ignore--;
hdlc_flush(bcs); hdlc_flush(bcs);
return; return;
} }
procskb = bcs->skb;
if ((procskb = bcs->skb) == NULL) { if (procskb == NULL) {
/* previous error */ /* previous error */
gig_dbg(DEBUG_ISO, "%s: skb=NULL", __func__); gig_dbg(DEBUG_ISO, "%s: skb=NULL", __func__);
gigaset_rcv_error(NULL, bcs->cs, bcs); gigaset_isdn_rcv_err(bcs);
} else if (procskb->len < 2) { } else if (procskb->len < 2) {
dev_notice(bcs->cs->dev, "received short frame (%d octets)\n", dev_notice(cs->dev, "received short frame (%d octets)\n",
procskb->len); procskb->len);
bcs->hw.bas->runts++; bcs->hw.bas->runts++;
gigaset_rcv_error(procskb, bcs->cs, bcs); dev_kfree_skb_any(procskb);
gigaset_isdn_rcv_err(bcs);
} else if (bcs->fcs != PPP_GOODFCS) { } else if (bcs->fcs != PPP_GOODFCS) {
dev_notice(bcs->cs->dev, "frame check error (0x%04x)\n", dev_notice(cs->dev, "frame check error (0x%04x)\n", bcs->fcs);
bcs->fcs);
bcs->hw.bas->fcserrs++; bcs->hw.bas->fcserrs++;
gigaset_rcv_error(procskb, bcs->cs, bcs); dev_kfree_skb_any(procskb);
gigaset_isdn_rcv_err(bcs);
} else { } else {
procskb->len -= 2; /* subtract FCS */ len = procskb->len;
procskb->tail -= 2; __skb_trim(procskb, len -= 2); /* subtract FCS */
gig_dbg(DEBUG_ISO, "%s: good frame (%d octets)", gig_dbg(DEBUG_ISO, "%s: good frame (%d octets)", __func__, len);
__func__, procskb->len);
dump_bytes(DEBUG_STREAM_DUMP, dump_bytes(DEBUG_STREAM_DUMP,
"rcv data", procskb->data, procskb->len); "rcv data", procskb->data, len);
bcs->hw.bas->goodbytes += procskb->len; bcs->hw.bas->goodbytes += len;
gigaset_rcv_skb(procskb, bcs->cs, bcs); gigaset_skb_rcvd(bcs, procskb);
} }
if ((bcs->skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL) bcs->skb = dev_alloc_skb(SBUFSIZE + cs->hw_hdr_len);
skb_reserve(bcs->skb, HW_HDR_LEN); if (bcs->skb)
skb_reserve(bcs->skb, cs->hw_hdr_len);
else else
dev_err(bcs->cs->dev, "could not allocate skb\n"); dev_err(cs->dev, "could not allocate skb\n");
bcs->fcs = PPP_INITFCS; bcs->fcs = PPP_INITFCS;
} }
@ -610,12 +596,8 @@ static inline void hdlc_frag(struct bc_state *bcs, unsigned inbits)
dev_notice(bcs->cs->dev, "received partial byte (%d bits)\n", inbits); dev_notice(bcs->cs->dev, "received partial byte (%d bits)\n", inbits);
bcs->hw.bas->alignerrs++; bcs->hw.bas->alignerrs++;
gigaset_rcv_error(bcs->skb, bcs->cs, bcs); gigaset_isdn_rcv_err(bcs);
__skb_trim(bcs->skb, 0);
if ((bcs->skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL)
skb_reserve(bcs->skb, HW_HDR_LEN);
else
dev_err(bcs->cs->dev, "could not allocate skb\n");
bcs->fcs = PPP_INITFCS; bcs->fcs = PPP_INITFCS;
} }
@ -646,10 +628,10 @@ static const unsigned char bitcounts[256] = {
}; };
/* hdlc_unpack /* hdlc_unpack
* perform HDLC frame processing (bit unstuffing, flag detection, FCS calculation) * perform HDLC frame processing (bit unstuffing, flag detection, FCS
* on a sequence of received data bytes (8 bits each, LSB first) * calculation) on a sequence of received data bytes (8 bits each, LSB first)
* pass on successfully received, complete frames as SKBs via gigaset_rcv_skb * pass on successfully received, complete frames as SKBs via gigaset_skb_rcvd
* notify of errors via gigaset_rcv_error * notify of errors via gigaset_isdn_rcv_err
* tally frames, errors etc. in BC structure counters * tally frames, errors etc. in BC structure counters
* parameters: * parameters:
* src received data * src received data
@ -665,9 +647,12 @@ static inline void hdlc_unpack(unsigned char *src, unsigned count,
/* load previous state: /* load previous state:
* inputstate = set of flag bits: * inputstate = set of flag bits:
* - INS_flag_hunt: no complete opening flag received since connection setup or last abort * - INS_flag_hunt: no complete opening flag received since connection
* - INS_have_data: at least one complete data byte received since last flag * setup or last abort
* seqlen = number of consecutive '1' bits in last 7 input stream bits (0..7) * - INS_have_data: at least one complete data byte received since last
* flag
* seqlen = number of consecutive '1' bits in last 7 input stream bits
* (0..7)
* inbyte = accumulated partial data byte (if !INS_flag_hunt) * inbyte = accumulated partial data byte (if !INS_flag_hunt)
* inbits = number of valid bits in inbyte, starting at LSB (0..6) * inbits = number of valid bits in inbyte, starting at LSB (0..6)
*/ */
@ -701,9 +686,11 @@ static inline void hdlc_unpack(unsigned char *src, unsigned count,
inbyte = c >> (lead1 + 1); inbyte = c >> (lead1 + 1);
inbits = 7 - lead1; inbits = 7 - lead1;
if (trail1 >= 8) { if (trail1 >= 8) {
/* interior stuffing: omitting the MSB handles most cases */ /* interior stuffing:
* omitting the MSB handles most cases,
* correct the incorrectly handled
* cases individually */
inbits--; inbits--;
/* correct the incorrectly handled cases individually */
switch (c) { switch (c) {
case 0xbe: case 0xbe:
inbyte = 0x3f; inbyte = 0x3f;
@ -729,13 +716,14 @@ static inline void hdlc_unpack(unsigned char *src, unsigned count,
hdlc_flush(bcs); hdlc_flush(bcs);
inputstate |= INS_flag_hunt; inputstate |= INS_flag_hunt;
} else if (seqlen == 6) { } else if (seqlen == 6) {
/* closing flag, including (6 - lead1) '1's and one '0' from inbits */ /* closing flag, including (6 - lead1) '1's
* and one '0' from inbits */
if (inbits > 7 - lead1) { if (inbits > 7 - lead1) {
hdlc_frag(bcs, inbits + lead1 - 7); hdlc_frag(bcs, inbits + lead1 - 7);
inputstate &= ~INS_have_data; inputstate &= ~INS_have_data;
} else { } else {
if (inbits < 7 - lead1) if (inbits < 7 - lead1)
ubc->stolen0s ++; ubc->stolen0s++;
if (inputstate & INS_have_data) { if (inputstate & INS_have_data) {
hdlc_done(bcs); hdlc_done(bcs);
inputstate &= ~INS_have_data; inputstate &= ~INS_have_data;
@ -744,7 +732,7 @@ static inline void hdlc_unpack(unsigned char *src, unsigned count,
if (c == PPP_FLAG) { if (c == PPP_FLAG) {
/* complete flag, LSB overlaps preceding flag */ /* complete flag, LSB overlaps preceding flag */
ubc->shared0s ++; ubc->shared0s++;
inbits = 0; inbits = 0;
inbyte = 0; inbyte = 0;
} else if (trail1 != 7) { } else if (trail1 != 7) {
@ -752,9 +740,11 @@ static inline void hdlc_unpack(unsigned char *src, unsigned count,
inbyte = c >> (lead1 + 1); inbyte = c >> (lead1 + 1);
inbits = 7 - lead1; inbits = 7 - lead1;
if (trail1 >= 8) { if (trail1 >= 8) {
/* interior stuffing: omitting the MSB handles most cases */ /* interior stuffing:
* omitting the MSB handles most cases,
* correct the incorrectly handled
* cases individually */
inbits--; inbits--;
/* correct the incorrectly handled cases individually */
switch (c) { switch (c) {
case 0xbe: case 0xbe:
inbyte = 0x3f; inbyte = 0x3f;
@ -762,7 +752,8 @@ static inline void hdlc_unpack(unsigned char *src, unsigned count,
} }
} }
} else { } else {
/* abort sequence follows, skb already empty anyway */ /* abort sequence follows,
* skb already empty anyway */
ubc->aborts++; ubc->aborts++;
inputstate |= INS_flag_hunt; inputstate |= INS_flag_hunt;
} }
@ -787,14 +778,17 @@ static inline void hdlc_unpack(unsigned char *src, unsigned count,
} else { } else {
/* stuffed data */ /* stuffed data */
if (trail1 < 7) { /* => seqlen == 5 */ if (trail1 < 7) { /* => seqlen == 5 */
/* stuff bit at position lead1, no interior stuffing */ /* stuff bit at position lead1,
* no interior stuffing */
unsigned char mask = (1 << lead1) - 1; unsigned char mask = (1 << lead1) - 1;
c = (c & mask) | ((c & ~mask) >> 1); c = (c & mask) | ((c & ~mask) >> 1);
inbyte |= c << inbits; inbyte |= c << inbits;
inbits += 7; inbits += 7;
} else if (seqlen < 5) { /* trail1 >= 8 */ } else if (seqlen < 5) { /* trail1 >= 8 */
/* interior stuffing: omitting the MSB handles most cases */ /* interior stuffing:
/* correct the incorrectly handled cases individually */ * omitting the MSB handles most cases,
* correct the incorrectly handled
* cases individually */
switch (c) { switch (c) {
case 0xbe: case 0xbe:
c = 0x7e; c = 0x7e;
@ -804,8 +798,9 @@ static inline void hdlc_unpack(unsigned char *src, unsigned count,
inbits += 7; inbits += 7;
} else { /* seqlen == 5 && trail1 >= 8 */ } else { /* seqlen == 5 && trail1 >= 8 */
/* stuff bit at lead1 *and* interior stuffing */ /* stuff bit at lead1 *and* interior
switch (c) { /* unstuff individually */ * stuffing -- unstuff individually */
switch (c) {
case 0x7d: case 0x7d:
c = 0x3f; c = 0x3f;
break; break;
@ -841,7 +836,7 @@ static inline void hdlc_unpack(unsigned char *src, unsigned count,
} }
/* trans_receive /* trans_receive
* pass on received USB frame transparently as SKB via gigaset_rcv_skb * pass on received USB frame transparently as SKB via gigaset_skb_rcvd
* invert bytes * invert bytes
* tally frames, errors etc. in BC structure counters * tally frames, errors etc. in BC structure counters
* parameters: * parameters:
@ -852,6 +847,7 @@ static inline void hdlc_unpack(unsigned char *src, unsigned count,
static inline void trans_receive(unsigned char *src, unsigned count, static inline void trans_receive(unsigned char *src, unsigned count,
struct bc_state *bcs) struct bc_state *bcs)
{ {
struct cardstate *cs = bcs->cs;
struct sk_buff *skb; struct sk_buff *skb;
int dobytes; int dobytes;
unsigned char *dst; unsigned char *dst;
@ -861,13 +857,14 @@ static inline void trans_receive(unsigned char *src, unsigned count,
hdlc_flush(bcs); hdlc_flush(bcs);
return; return;
} }
if (unlikely((skb = bcs->skb) == NULL)) { skb = bcs->skb;
bcs->skb = skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN); if (unlikely(skb == NULL)) {
bcs->skb = skb = dev_alloc_skb(SBUFSIZE + cs->hw_hdr_len);
if (!skb) { if (!skb) {
dev_err(bcs->cs->dev, "could not allocate skb\n"); dev_err(cs->dev, "could not allocate skb\n");
return; return;
} }
skb_reserve(skb, HW_HDR_LEN); skb_reserve(skb, cs->hw_hdr_len);
} }
bcs->hw.bas->goodbytes += skb->len; bcs->hw.bas->goodbytes += skb->len;
dobytes = TRANSBUFSIZE - skb->len; dobytes = TRANSBUFSIZE - skb->len;
@ -881,23 +878,24 @@ static inline void trans_receive(unsigned char *src, unsigned count,
if (dobytes == 0) { if (dobytes == 0) {
dump_bytes(DEBUG_STREAM_DUMP, dump_bytes(DEBUG_STREAM_DUMP,
"rcv data", skb->data, skb->len); "rcv data", skb->data, skb->len);
gigaset_rcv_skb(skb, bcs->cs, bcs); gigaset_skb_rcvd(bcs, skb);
bcs->skb = skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN); bcs->skb = skb =
dev_alloc_skb(SBUFSIZE + cs->hw_hdr_len);
if (!skb) { if (!skb) {
dev_err(bcs->cs->dev, dev_err(cs->dev, "could not allocate skb\n");
"could not allocate skb\n");
return; return;
} }
skb_reserve(bcs->skb, HW_HDR_LEN); skb_reserve(skb, cs->hw_hdr_len);
dobytes = TRANSBUFSIZE; dobytes = TRANSBUFSIZE;
} }
} }
} }
void gigaset_isoc_receive(unsigned char *src, unsigned count, struct bc_state *bcs) void gigaset_isoc_receive(unsigned char *src, unsigned count,
struct bc_state *bcs)
{ {
switch (bcs->proto2) { switch (bcs->proto2) {
case ISDN_PROTO_L2_HDLC: case L2_HDLC:
hdlc_unpack(src, count, bcs); hdlc_unpack(src, count, bcs);
break; break;
default: /* assume transparent */ default: /* assume transparent */
@ -981,8 +979,10 @@ void gigaset_isoc_input(struct inbuf_t *inbuf)
* @bcs: B channel descriptor structure. * @bcs: B channel descriptor structure.
* @skb: data to send. * @skb: data to send.
* *
* Called by i4l.c to queue an skb for sending, and start transmission if * Called by LL to queue an skb for sending, and start transmission if
* necessary. * necessary.
* Once the payload data has been transmitted completely, gigaset_skb_sent()
* will be called with the skb's link layer header preserved.
* *
* Return value: * Return value:
* number of bytes accepted for sending (skb->len) if ok, * number of bytes accepted for sending (skb->len) if ok,

View File

@ -39,7 +39,7 @@ static ssize_t set_cidmode(struct device *dev, struct device_attribute *attr,
return -EINVAL; return -EINVAL;
if (mutex_lock_interruptible(&cs->mutex)) if (mutex_lock_interruptible(&cs->mutex))
return -ERESTARTSYS; // FIXME -EINTR? return -ERESTARTSYS;
cs->waiting = 1; cs->waiting = 1;
if (!gigaset_add_event(cs, &cs->at_state, EV_PROC_CIDMODE, if (!gigaset_add_event(cs, &cs->at_state, EV_PROC_CIDMODE,

View File

@ -164,9 +164,15 @@ static void gigaset_modem_fill(unsigned long data)
{ {
struct cardstate *cs = (struct cardstate *) data; struct cardstate *cs = (struct cardstate *) data;
struct bc_state *bcs; struct bc_state *bcs;
struct sk_buff *nextskb;
int sent = 0; int sent = 0;
if (!cs || !(bcs = cs->bcs)) { if (!cs) {
gig_dbg(DEBUG_OUTPUT, "%s: no cardstate", __func__);
return;
}
bcs = cs->bcs;
if (!bcs) {
gig_dbg(DEBUG_OUTPUT, "%s: no cardstate", __func__); gig_dbg(DEBUG_OUTPUT, "%s: no cardstate", __func__);
return; return;
} }
@ -179,9 +185,11 @@ static void gigaset_modem_fill(unsigned long data)
return; return;
/* no command to send; get skb */ /* no command to send; get skb */
if (!(bcs->tx_skb = skb_dequeue(&bcs->squeue))) nextskb = skb_dequeue(&bcs->squeue);
if (!nextskb)
/* no skb either, nothing to do */ /* no skb either, nothing to do */
return; return;
bcs->tx_skb = nextskb;
gig_dbg(DEBUG_INTR, "Dequeued skb (Adr: %lx)", gig_dbg(DEBUG_INTR, "Dequeued skb (Adr: %lx)",
(unsigned long) bcs->tx_skb); (unsigned long) bcs->tx_skb);
@ -236,19 +244,20 @@ static void flush_send_queue(struct cardstate *cs)
* number of bytes queued, or error code < 0 * number of bytes queued, or error code < 0
*/ */
static int gigaset_write_cmd(struct cardstate *cs, const unsigned char *buf, static int gigaset_write_cmd(struct cardstate *cs, const unsigned char *buf,
int len, struct tasklet_struct *wake_tasklet) int len, struct tasklet_struct *wake_tasklet)
{ {
struct cmdbuf_t *cb; struct cmdbuf_t *cb;
unsigned long flags; unsigned long flags;
gigaset_dbg_buffer(cs->mstate != MS_LOCKED ? gigaset_dbg_buffer(cs->mstate != MS_LOCKED ?
DEBUG_TRANSCMD : DEBUG_LOCKCMD, DEBUG_TRANSCMD : DEBUG_LOCKCMD,
"CMD Transmit", len, buf); "CMD Transmit", len, buf);
if (len <= 0) if (len <= 0)
return 0; return 0;
if (!(cb = kmalloc(sizeof(struct cmdbuf_t) + len, GFP_ATOMIC))) { cb = kmalloc(sizeof(struct cmdbuf_t) + len, GFP_ATOMIC);
if (!cb) {
dev_err(cs->dev, "%s: out of memory!\n", __func__); dev_err(cs->dev, "%s: out of memory!\n", __func__);
return -ENOMEM; return -ENOMEM;
} }
@ -392,7 +401,6 @@ static void gigaset_device_release(struct device *dev)
struct platform_device *pdev = to_platform_device(dev); struct platform_device *pdev = to_platform_device(dev);
/* adapted from platform_device_release() in drivers/base/platform.c */ /* adapted from platform_device_release() in drivers/base/platform.c */
//FIXME is this actually necessary?
kfree(dev->platform_data); kfree(dev->platform_data);
kfree(pdev->resource); kfree(pdev->resource);
} }
@ -404,16 +412,20 @@ static void gigaset_device_release(struct device *dev)
static int gigaset_initcshw(struct cardstate *cs) static int gigaset_initcshw(struct cardstate *cs)
{ {
int rc; int rc;
struct ser_cardstate *scs;
if (!(cs->hw.ser = kzalloc(sizeof(struct ser_cardstate), GFP_KERNEL))) { scs = kzalloc(sizeof(struct ser_cardstate), GFP_KERNEL);
if (!scs) {
pr_err("out of memory\n"); pr_err("out of memory\n");
return 0; return 0;
} }
cs->hw.ser = scs;
cs->hw.ser->dev.name = GIGASET_MODULENAME; cs->hw.ser->dev.name = GIGASET_MODULENAME;
cs->hw.ser->dev.id = cs->minor_index; cs->hw.ser->dev.id = cs->minor_index;
cs->hw.ser->dev.dev.release = gigaset_device_release; cs->hw.ser->dev.dev.release = gigaset_device_release;
if ((rc = platform_device_register(&cs->hw.ser->dev)) != 0) { rc = platform_device_register(&cs->hw.ser->dev);
if (rc != 0) {
pr_err("error %d registering platform device\n", rc); pr_err("error %d registering platform device\n", rc);
kfree(cs->hw.ser); kfree(cs->hw.ser);
cs->hw.ser = NULL; cs->hw.ser = NULL;
@ -422,7 +434,7 @@ static int gigaset_initcshw(struct cardstate *cs)
dev_set_drvdata(&cs->hw.ser->dev.dev, cs); dev_set_drvdata(&cs->hw.ser->dev.dev, cs);
tasklet_init(&cs->write_tasklet, tasklet_init(&cs->write_tasklet,
&gigaset_modem_fill, (unsigned long) cs); gigaset_modem_fill, (unsigned long) cs);
return 1; return 1;
} }
@ -434,7 +446,8 @@ static int gigaset_initcshw(struct cardstate *cs)
* Called by "gigaset_start" and "gigaset_enterconfigmode" in common.c * Called by "gigaset_start" and "gigaset_enterconfigmode" in common.c
* and by "if_lock" and "if_termios" in interface.c * and by "if_lock" and "if_termios" in interface.c
*/ */
static int gigaset_set_modem_ctrl(struct cardstate *cs, unsigned old_state, unsigned new_state) static int gigaset_set_modem_ctrl(struct cardstate *cs, unsigned old_state,
unsigned new_state)
{ {
struct tty_struct *tty = cs->hw.ser->tty; struct tty_struct *tty = cs->hw.ser->tty;
unsigned int set, clear; unsigned int set, clear;
@ -520,8 +533,8 @@ gigaset_tty_open(struct tty_struct *tty)
} }
/* allocate memory for our device state and intialize it */ /* allocate memory for our device state and intialize it */
if (!(cs = gigaset_initcs(driver, 1, 1, 0, cidmode, cs = gigaset_initcs(driver, 1, 1, 0, cidmode, GIGASET_MODULENAME);
GIGASET_MODULENAME))) if (!cs)
goto error; goto error;
cs->dev = &cs->hw.ser->dev.dev; cs->dev = &cs->hw.ser->dev.dev;
@ -690,7 +703,8 @@ gigaset_tty_receive(struct tty_struct *tty, const unsigned char *buf,
if (!cs) if (!cs)
return; return;
if (!(inbuf = cs->inbuf)) { inbuf = cs->inbuf;
if (!inbuf) {
dev_err(cs->dev, "%s: no inbuf\n", __func__); dev_err(cs->dev, "%s: no inbuf\n", __func__);
cs_put(cs); cs_put(cs);
return; return;
@ -770,18 +784,21 @@ static int __init ser_gigaset_init(void)
int rc; int rc;
gig_dbg(DEBUG_INIT, "%s", __func__); gig_dbg(DEBUG_INIT, "%s", __func__);
if ((rc = platform_driver_register(&device_driver)) != 0) { rc = platform_driver_register(&device_driver);
if (rc != 0) {
pr_err("error %d registering platform driver\n", rc); pr_err("error %d registering platform driver\n", rc);
return rc; return rc;
} }
/* allocate memory for our driver state and intialize it */ /* allocate memory for our driver state and intialize it */
if (!(driver = gigaset_initdriver(GIGASET_MINOR, GIGASET_MINORS, driver = gigaset_initdriver(GIGASET_MINOR, GIGASET_MINORS,
GIGASET_MODULENAME, GIGASET_DEVNAME, GIGASET_MODULENAME, GIGASET_DEVNAME,
&ops, THIS_MODULE))) &ops, THIS_MODULE);
if (!driver)
goto error; goto error;
if ((rc = tty_register_ldisc(N_GIGASET_M101, &gigaset_ldisc)) != 0) { rc = tty_register_ldisc(N_GIGASET_M101, &gigaset_ldisc);
if (rc != 0) {
pr_err("error %d registering line discipline\n", rc); pr_err("error %d registering line discipline\n", rc);
goto error; goto error;
} }
@ -808,7 +825,8 @@ static void __exit ser_gigaset_exit(void)
driver = NULL; driver = NULL;
} }
if ((rc = tty_unregister_ldisc(N_GIGASET_M101)) != 0) rc = tty_unregister_ldisc(N_GIGASET_M101);
if (rc != 0)
pr_err("error %d unregistering line discipline\n", rc); pr_err("error %d unregistering line discipline\n", rc);
platform_driver_unregister(&device_driver); platform_driver_unregister(&device_driver);

View File

@ -43,14 +43,14 @@ MODULE_PARM_DESC(cidmode, "Call-ID mode");
#define GIGASET_MODULENAME "usb_gigaset" #define GIGASET_MODULENAME "usb_gigaset"
#define GIGASET_DEVNAME "ttyGU" #define GIGASET_DEVNAME "ttyGU"
#define IF_WRITEBUF 2000 //FIXME // WAKEUP_CHARS: 256 #define IF_WRITEBUF 2000 /* arbitrary limit */
/* Values for the Gigaset M105 Data */ /* Values for the Gigaset M105 Data */
#define USB_M105_VENDOR_ID 0x0681 #define USB_M105_VENDOR_ID 0x0681
#define USB_M105_PRODUCT_ID 0x0009 #define USB_M105_PRODUCT_ID 0x0009
/* table of devices that work with this driver */ /* table of devices that work with this driver */
static const struct usb_device_id gigaset_table [] = { static const struct usb_device_id gigaset_table[] = {
{ USB_DEVICE(USB_M105_VENDOR_ID, USB_M105_PRODUCT_ID) }, { USB_DEVICE(USB_M105_VENDOR_ID, USB_M105_PRODUCT_ID) },
{ } /* Terminating entry */ { } /* Terminating entry */
}; };
@ -97,8 +97,8 @@ MODULE_DEVICE_TABLE(usb, gigaset_table);
* 41 19 -- -- -- -- 06 00 00 00 00 xx 11 13 * 41 19 -- -- -- -- 06 00 00 00 00 xx 11 13
* Used after every "configuration sequence" (RQ 12, RQs 01/03/13). * Used after every "configuration sequence" (RQ 12, RQs 01/03/13).
* xx is usually 0x00 but was 0x7e before starting data transfer * xx is usually 0x00 but was 0x7e before starting data transfer
* in unimodem mode. So, this might be an array of characters that need * in unimodem mode. So, this might be an array of characters that
* special treatment ("commit all bufferd data"?), 11=^Q, 13=^S. * need special treatment ("commit all bufferd data"?), 11=^Q, 13=^S.
* *
* Unimodem mode: use "modprobe ppp_async flag_time=0" as the device _needs_ two * Unimodem mode: use "modprobe ppp_async flag_time=0" as the device _needs_ two
* flags per packet. * flags per packet.
@ -114,7 +114,7 @@ static int gigaset_suspend(struct usb_interface *intf, pm_message_t message);
static int gigaset_resume(struct usb_interface *intf); static int gigaset_resume(struct usb_interface *intf);
static int gigaset_pre_reset(struct usb_interface *intf); static int gigaset_pre_reset(struct usb_interface *intf);
static struct gigaset_driver *driver = NULL; static struct gigaset_driver *driver;
/* usb specific object needed to register this driver with the usb subsystem */ /* usb specific object needed to register this driver with the usb subsystem */
static struct usb_driver gigaset_usb_driver = { static struct usb_driver gigaset_usb_driver = {
@ -141,6 +141,7 @@ struct usb_cardstate {
struct urb *bulk_out_urb; struct urb *bulk_out_urb;
/* Input buffer */ /* Input buffer */
unsigned char *rcvbuf;
int rcvbuf_size; int rcvbuf_size;
struct urb *read_urb; struct urb *read_urb;
__u8 int_in_endpointAddr; __u8 int_in_endpointAddr;
@ -164,13 +165,11 @@ static int gigaset_set_modem_ctrl(struct cardstate *cs, unsigned old_state,
val = tiocm_to_gigaset(new_state); val = tiocm_to_gigaset(new_state);
gig_dbg(DEBUG_USBREQ, "set flags 0x%02x with mask 0x%02x", val, mask); gig_dbg(DEBUG_USBREQ, "set flags 0x%02x with mask 0x%02x", val, mask);
// don't use this in an interrupt/BH
r = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 7, 0x41, r = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 7, 0x41,
(val & 0xff) | ((mask & 0xff) << 8), 0, (val & 0xff) | ((mask & 0xff) << 8), 0,
NULL, 0, 2000 /* timeout? */); NULL, 0, 2000 /* timeout? */);
if (r < 0) if (r < 0)
return r; return r;
//..
return 0; return 0;
} }
@ -220,7 +219,6 @@ static int gigaset_baud_rate(struct cardstate *cs, unsigned cflag)
cflag &= CBAUD; cflag &= CBAUD;
switch (cflag) { switch (cflag) {
//FIXME more values?
case B300: rate = 300; break; case B300: rate = 300; break;
case B600: rate = 600; break; case B600: rate = 600; break;
case B1200: rate = 1200; break; case B1200: rate = 1200; break;
@ -273,7 +271,7 @@ static int gigaset_set_line_ctrl(struct cardstate *cs, unsigned cflag)
/* set the number of stop bits */ /* set the number of stop bits */
if (cflag & CSTOPB) { if (cflag & CSTOPB) {
if ((cflag & CSIZE) == CS5) if ((cflag & CSIZE) == CS5)
val |= 1; /* 1.5 stop bits */ //FIXME is this okay? val |= 1; /* 1.5 stop bits */
else else
val |= 2; /* 2 stop bits */ val |= 2; /* 2 stop bits */
} }
@ -282,7 +280,7 @@ static int gigaset_set_line_ctrl(struct cardstate *cs, unsigned cflag)
} }
/*================================================================================================================*/ /*============================================================================*/
static int gigaset_init_bchannel(struct bc_state *bcs) static int gigaset_init_bchannel(struct bc_state *bcs)
{ {
/* nothing to do for M10x */ /* nothing to do for M10x */
@ -344,7 +342,6 @@ static void gigaset_modem_fill(unsigned long data)
if (write_modem(cs) < 0) { if (write_modem(cs) < 0) {
gig_dbg(DEBUG_OUTPUT, gig_dbg(DEBUG_OUTPUT,
"modem_fill: write_modem failed"); "modem_fill: write_modem failed");
// FIXME should we tell the LL?
again = 1; /* no callback will be called! */ again = 1; /* no callback will be called! */
} }
} }
@ -356,8 +353,8 @@ static void gigaset_modem_fill(unsigned long data)
*/ */
static void gigaset_read_int_callback(struct urb *urb) static void gigaset_read_int_callback(struct urb *urb)
{ {
struct inbuf_t *inbuf = urb->context; struct cardstate *cs = urb->context;
struct cardstate *cs = inbuf->cs; struct inbuf_t *inbuf = cs->inbuf;
int status = urb->status; int status = urb->status;
int r; int r;
unsigned numbytes; unsigned numbytes;
@ -368,7 +365,7 @@ static void gigaset_read_int_callback(struct urb *urb)
numbytes = urb->actual_length; numbytes = urb->actual_length;
if (numbytes) { if (numbytes) {
src = inbuf->rcvbuf; src = cs->hw.usb->rcvbuf;
if (unlikely(*src)) if (unlikely(*src))
dev_warn(cs->dev, dev_warn(cs->dev,
"%s: There was no leading 0, but 0x%02x!\n", "%s: There was no leading 0, but 0x%02x!\n",
@ -440,7 +437,7 @@ static int send_cb(struct cardstate *cs, struct cmdbuf_t *cb)
struct cmdbuf_t *tcb; struct cmdbuf_t *tcb;
unsigned long flags; unsigned long flags;
int count; int count;
int status = -ENOENT; // FIXME int status = -ENOENT;
struct usb_cardstate *ucs = cs->hw.usb; struct usb_cardstate *ucs = cs->hw.usb;
do { do {
@ -480,7 +477,9 @@ static int send_cb(struct cardstate *cs, struct cmdbuf_t *cb)
ucs->busy = 1; ucs->busy = 1;
spin_lock_irqsave(&cs->lock, flags); spin_lock_irqsave(&cs->lock, flags);
status = cs->connected ? usb_submit_urb(ucs->bulk_out_urb, GFP_ATOMIC) : -ENODEV; status = cs->connected ?
usb_submit_urb(ucs->bulk_out_urb, GFP_ATOMIC) :
-ENODEV;
spin_unlock_irqrestore(&cs->lock, flags); spin_unlock_irqrestore(&cs->lock, flags);
if (status) { if (status) {
@ -510,8 +509,8 @@ static int gigaset_write_cmd(struct cardstate *cs, const unsigned char *buf,
if (len <= 0) if (len <= 0)
return 0; return 0;
cb = kmalloc(sizeof(struct cmdbuf_t) + len, GFP_ATOMIC);
if (!(cb = kmalloc(sizeof(struct cmdbuf_t) + len, GFP_ATOMIC))) { if (!cb) {
dev_err(cs->dev, "%s: out of memory\n", __func__); dev_err(cs->dev, "%s: out of memory\n", __func__);
return -ENOMEM; return -ENOMEM;
} }
@ -615,7 +614,7 @@ static int gigaset_initcshw(struct cardstate *cs)
ucs->bulk_out_urb = NULL; ucs->bulk_out_urb = NULL;
ucs->read_urb = NULL; ucs->read_urb = NULL;
tasklet_init(&cs->write_tasklet, tasklet_init(&cs->write_tasklet,
&gigaset_modem_fill, (unsigned long) cs); gigaset_modem_fill, (unsigned long) cs);
return 1; return 1;
} }
@ -637,9 +636,7 @@ static int write_modem(struct cardstate *cs)
return -EINVAL; return -EINVAL;
} }
/* Copy data to bulk out buffer and // FIXME copying not necessary /* Copy data to bulk out buffer and transmit data */
* transmit data
*/
count = min(bcs->tx_skb->len, (unsigned) ucs->bulk_out_size); count = min(bcs->tx_skb->len, (unsigned) ucs->bulk_out_size);
skb_copy_from_linear_data(bcs->tx_skb, ucs->bulk_out_buffer, count); skb_copy_from_linear_data(bcs->tx_skb, ucs->bulk_out_buffer, count);
skb_pull(bcs->tx_skb, count); skb_pull(bcs->tx_skb, count);
@ -650,7 +647,8 @@ static int write_modem(struct cardstate *cs)
if (cs->connected) { if (cs->connected) {
usb_fill_bulk_urb(ucs->bulk_out_urb, ucs->udev, usb_fill_bulk_urb(ucs->bulk_out_urb, ucs->udev,
usb_sndbulkpipe(ucs->udev, usb_sndbulkpipe(ucs->udev,
ucs->bulk_out_endpointAddr & 0x0f), ucs->bulk_out_endpointAddr &
0x0f),
ucs->bulk_out_buffer, count, ucs->bulk_out_buffer, count,
gigaset_write_bulk_callback, cs); gigaset_write_bulk_callback, cs);
ret = usb_submit_urb(ucs->bulk_out_urb, GFP_ATOMIC); ret = usb_submit_urb(ucs->bulk_out_urb, GFP_ATOMIC);
@ -666,7 +664,7 @@ static int write_modem(struct cardstate *cs)
if (!bcs->tx_skb->len) { if (!bcs->tx_skb->len) {
/* skb sent completely */ /* skb sent completely */
gigaset_skb_sent(bcs, bcs->tx_skb); //FIXME also, when ret<0? gigaset_skb_sent(bcs, bcs->tx_skb);
gig_dbg(DEBUG_INTR, "kfree skb (Adr: %lx)!", gig_dbg(DEBUG_INTR, "kfree skb (Adr: %lx)!",
(unsigned long) bcs->tx_skb); (unsigned long) bcs->tx_skb);
@ -763,8 +761,8 @@ static int gigaset_probe(struct usb_interface *interface,
buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
ucs->rcvbuf_size = buffer_size; ucs->rcvbuf_size = buffer_size;
ucs->int_in_endpointAddr = endpoint->bEndpointAddress; ucs->int_in_endpointAddr = endpoint->bEndpointAddress;
cs->inbuf[0].rcvbuf = kmalloc(buffer_size, GFP_KERNEL); ucs->rcvbuf = kmalloc(buffer_size, GFP_KERNEL);
if (!cs->inbuf[0].rcvbuf) { if (!ucs->rcvbuf) {
dev_err(cs->dev, "Couldn't allocate rcvbuf\n"); dev_err(cs->dev, "Couldn't allocate rcvbuf\n");
retval = -ENOMEM; retval = -ENOMEM;
goto error; goto error;
@ -773,9 +771,9 @@ static int gigaset_probe(struct usb_interface *interface,
usb_fill_int_urb(ucs->read_urb, udev, usb_fill_int_urb(ucs->read_urb, udev,
usb_rcvintpipe(udev, usb_rcvintpipe(udev,
endpoint->bEndpointAddress & 0x0f), endpoint->bEndpointAddress & 0x0f),
cs->inbuf[0].rcvbuf, buffer_size, ucs->rcvbuf, buffer_size,
gigaset_read_int_callback, gigaset_read_int_callback,
cs->inbuf + 0, endpoint->bInterval); cs, endpoint->bInterval);
retval = usb_submit_urb(ucs->read_urb, GFP_KERNEL); retval = usb_submit_urb(ucs->read_urb, GFP_KERNEL);
if (retval) { if (retval) {
@ -789,7 +787,7 @@ static int gigaset_probe(struct usb_interface *interface,
if (!gigaset_start(cs)) { if (!gigaset_start(cs)) {
tasklet_kill(&cs->write_tasklet); tasklet_kill(&cs->write_tasklet);
retval = -ENODEV; //FIXME retval = -ENODEV;
goto error; goto error;
} }
return 0; return 0;
@ -798,11 +796,11 @@ error:
usb_kill_urb(ucs->read_urb); usb_kill_urb(ucs->read_urb);
kfree(ucs->bulk_out_buffer); kfree(ucs->bulk_out_buffer);
usb_free_urb(ucs->bulk_out_urb); usb_free_urb(ucs->bulk_out_urb);
kfree(cs->inbuf[0].rcvbuf); kfree(ucs->rcvbuf);
usb_free_urb(ucs->read_urb); usb_free_urb(ucs->read_urb);
usb_set_intfdata(interface, NULL); usb_set_intfdata(interface, NULL);
ucs->read_urb = ucs->bulk_out_urb = NULL; ucs->read_urb = ucs->bulk_out_urb = NULL;
cs->inbuf[0].rcvbuf = ucs->bulk_out_buffer = NULL; ucs->rcvbuf = ucs->bulk_out_buffer = NULL;
usb_put_dev(ucs->udev); usb_put_dev(ucs->udev);
ucs->udev = NULL; ucs->udev = NULL;
ucs->interface = NULL; ucs->interface = NULL;
@ -831,10 +829,10 @@ static void gigaset_disconnect(struct usb_interface *interface)
kfree(ucs->bulk_out_buffer); kfree(ucs->bulk_out_buffer);
usb_free_urb(ucs->bulk_out_urb); usb_free_urb(ucs->bulk_out_urb);
kfree(cs->inbuf[0].rcvbuf); kfree(ucs->rcvbuf);
usb_free_urb(ucs->read_urb); usb_free_urb(ucs->read_urb);
ucs->read_urb = ucs->bulk_out_urb = NULL; ucs->read_urb = ucs->bulk_out_urb = NULL;
cs->inbuf[0].rcvbuf = ucs->bulk_out_buffer = NULL; ucs->rcvbuf = ucs->bulk_out_buffer = NULL;
usb_put_dev(ucs->udev); usb_put_dev(ucs->udev);
ucs->interface = NULL; ucs->interface = NULL;
@ -916,9 +914,10 @@ static int __init usb_gigaset_init(void)
int result; int result;
/* allocate memory for our driver state and intialize it */ /* allocate memory for our driver state and intialize it */
if ((driver = gigaset_initdriver(GIGASET_MINOR, GIGASET_MINORS, driver = gigaset_initdriver(GIGASET_MINOR, GIGASET_MINORS,
GIGASET_MODULENAME, GIGASET_DEVNAME, GIGASET_MODULENAME, GIGASET_DEVNAME,
&ops, THIS_MODULE)) == NULL) &ops, THIS_MODULE);
if (driver == NULL)
goto error; goto error;
/* register this driver with the USB subsystem */ /* register this driver with the USB subsystem */

View File

@ -110,6 +110,7 @@ set_debug(const char *val, struct kernel_param *kp)
MODULE_AUTHOR("Karsten Keil"); MODULE_AUTHOR("Karsten Keil");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
MODULE_VERSION(SPEEDFAX_REV); MODULE_VERSION(SPEEDFAX_REV);
MODULE_FIRMWARE("isdn/ISAR.BIN");
module_param_call(debug, set_debug, param_get_uint, &debug, S_IRUGO | S_IWUSR); module_param_call(debug, set_debug, param_get_uint, &debug, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "Speedfax debug mask"); MODULE_PARM_DESC(debug, "Speedfax debug mask");
module_param(irqloops, uint, S_IRUGO | S_IWUSR); module_param(irqloops, uint, S_IRUGO | S_IWUSR);

View File

@ -779,7 +779,7 @@ base_sock_create(struct net *net, struct socket *sock, int protocol)
} }
static int static int
mISDN_sock_create(struct net *net, struct socket *sock, int proto) mISDN_sock_create(struct net *net, struct socket *sock, int proto, int kern)
{ {
int err = -EPROTONOSUPPORT; int err = -EPROTONOSUPPORT;
@ -808,8 +808,7 @@ mISDN_sock_create(struct net *net, struct socket *sock, int proto)
return err; return err;
} }
static struct static const struct net_proto_family mISDN_sock_family_ops = {
net_proto_family mISDN_sock_family_ops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.family = PF_ISDN, .family = PF_ISDN,
.create = mISDN_sock_create, .create = mISDN_sock_create,

View File

@ -249,5 +249,6 @@ config EP93XX_PWM
source "drivers/misc/c2port/Kconfig" source "drivers/misc/c2port/Kconfig"
source "drivers/misc/eeprom/Kconfig" source "drivers/misc/eeprom/Kconfig"
source "drivers/misc/cb710/Kconfig" source "drivers/misc/cb710/Kconfig"
source "drivers/misc/iwmc3200top/Kconfig"
endif # MISC_DEVICES endif # MISC_DEVICES

View File

@ -21,5 +21,6 @@ obj-$(CONFIG_HP_ILO) += hpilo.o
obj-$(CONFIG_ISL29003) += isl29003.o obj-$(CONFIG_ISL29003) += isl29003.o
obj-$(CONFIG_EP93XX_PWM) += ep93xx_pwm.o obj-$(CONFIG_EP93XX_PWM) += ep93xx_pwm.o
obj-$(CONFIG_C2PORT) += c2port/ obj-$(CONFIG_C2PORT) += c2port/
obj-$(CONFIG_IWMC3200TOP) += iwmc3200top/
obj-y += eeprom/ obj-y += eeprom/
obj-y += cb710/ obj-y += cb710/

View File

@ -0,0 +1,20 @@
config IWMC3200TOP
tristate "Intel Wireless MultiCom Top Driver"
depends on MMC && EXPERIMENTAL
select FW_LOADER
---help---
Intel Wireless MultiCom 3200 Top driver is responsible for
for firmware load and enabled coms enumeration
config IWMC3200TOP_DEBUG
bool "Enable full debug output of iwmc3200top Driver"
depends on IWMC3200TOP
---help---
Enable full debug output of iwmc3200top Driver
config IWMC3200TOP_DEBUGFS
bool "Enable Debugfs debugging interface for iwmc3200top"
depends on IWMC3200TOP
---help---
Enable creation of debugfs files for iwmc3200top

View File

@ -0,0 +1,29 @@
# iwmc3200top - Intel Wireless MultiCom 3200 Top Driver
# drivers/misc/iwmc3200top/Makefile
#
# Copyright (C) 2009 Intel Corporation. All rights reserved.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version
# 2 as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.
#
#
# Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com>
# -
#
#
obj-$(CONFIG_IWMC3200TOP) += iwmc3200top.o
iwmc3200top-objs := main.o fw-download.o
iwmc3200top-$(CONFIG_IWMC3200TOP_DEBUG) += log.o
iwmc3200top-$(CONFIG_IWMC3200TOP_DEBUGFS) += debugfs.o

View File

@ -0,0 +1,133 @@
/*
* iwmc3200top - Intel Wireless MultiCom 3200 Top Driver
* drivers/misc/iwmc3200top/debufs.c
*
* Copyright (C) 2009 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
*
* Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com>
* -
*
*/
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/ctype.h>
#include <linux/mmc/sdio_func.h>
#include <linux/mmc/sdio.h>
#include <linux/debugfs.h>
#include "iwmc3200top.h"
#include "fw-msg.h"
#include "log.h"
#include "debugfs.h"
/* Constants definition */
#define HEXADECIMAL_RADIX 16
/* Functions definition */
#define DEBUGFS_ADD(name, parent) do { \
dbgfs->dbgfs_##parent##_files.file_##name = \
debugfs_create_file(#name, 0644, dbgfs->dir_##parent, priv, \
&iwmct_dbgfs_##name##_ops); \
} while (0)
#define DEBUGFS_RM(name) do { \
debugfs_remove(name); \
name = NULL; \
} while (0)
#define DEBUGFS_READ_FUNC(name) \
ssize_t iwmct_dbgfs_##name##_read(struct file *file, \
char __user *user_buf, \
size_t count, loff_t *ppos);
#define DEBUGFS_WRITE_FUNC(name) \
ssize_t iwmct_dbgfs_##name##_write(struct file *file, \
const char __user *user_buf, \
size_t count, loff_t *ppos);
#define DEBUGFS_READ_FILE_OPS(name) \
DEBUGFS_READ_FUNC(name) \
static const struct file_operations iwmct_dbgfs_##name##_ops = { \
.read = iwmct_dbgfs_##name##_read, \
.open = iwmct_dbgfs_open_file_generic, \
};
#define DEBUGFS_WRITE_FILE_OPS(name) \
DEBUGFS_WRITE_FUNC(name) \
static const struct file_operations iwmct_dbgfs_##name##_ops = { \
.write = iwmct_dbgfs_##name##_write, \
.open = iwmct_dbgfs_open_file_generic, \
};
#define DEBUGFS_READ_WRITE_FILE_OPS(name) \
DEBUGFS_READ_FUNC(name) \
DEBUGFS_WRITE_FUNC(name) \
static const struct file_operations iwmct_dbgfs_##name##_ops = {\
.write = iwmct_dbgfs_##name##_write, \
.read = iwmct_dbgfs_##name##_read, \
.open = iwmct_dbgfs_open_file_generic, \
};
/* Debugfs file ops definitions */
/*
* Create the debugfs files and directories
*
*/
void iwmct_dbgfs_register(struct iwmct_priv *priv, const char *name)
{
struct iwmct_debugfs *dbgfs;
dbgfs = kzalloc(sizeof(struct iwmct_debugfs), GFP_KERNEL);
if (!dbgfs) {
LOG_ERROR(priv, DEBUGFS, "failed to allocate %zd bytes\n",
sizeof(struct iwmct_debugfs));
return;
}
priv->dbgfs = dbgfs;
dbgfs->name = name;
dbgfs->dir_drv = debugfs_create_dir(name, NULL);
if (!dbgfs->dir_drv) {
LOG_ERROR(priv, DEBUGFS, "failed to create debugfs dir\n");
return;
}
return;
}
/**
* Remove the debugfs files and directories
*
*/
void iwmct_dbgfs_unregister(struct iwmct_debugfs *dbgfs)
{
if (!dbgfs)
return;
DEBUGFS_RM(dbgfs->dir_drv);
kfree(dbgfs);
dbgfs = NULL;
}

View File

@ -0,0 +1,58 @@
/*
* iwmc3200top - Intel Wireless MultiCom 3200 Top Driver
* drivers/misc/iwmc3200top/debufs.h
*
* Copyright (C) 2009 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
*
* Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com>
* -
*
*/
#ifndef __DEBUGFS_H__
#define __DEBUGFS_H__
#ifdef CONFIG_IWMC3200TOP_DEBUGFS
struct iwmct_debugfs {
const char *name;
struct dentry *dir_drv;
struct dir_drv_files {
} dbgfs_drv_files;
};
void iwmct_dbgfs_register(struct iwmct_priv *priv, const char *name);
void iwmct_dbgfs_unregister(struct iwmct_debugfs *dbgfs);
#else /* CONFIG_IWMC3200TOP_DEBUGFS */
struct iwmct_debugfs;
static inline void
iwmct_dbgfs_register(struct iwmct_priv *priv, const char *name)
{}
static inline void
iwmct_dbgfs_unregister(struct iwmct_debugfs *dbgfs)
{}
#endif /* CONFIG_IWMC3200TOP_DEBUGFS */
#endif /* __DEBUGFS_H__ */

View File

@ -0,0 +1,355 @@
/*
* iwmc3200top - Intel Wireless MultiCom 3200 Top Driver
* drivers/misc/iwmc3200top/fw-download.c
*
* Copyright (C) 2009 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
*
* Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com>
* -
*
*/
#include <linux/firmware.h>
#include <linux/mmc/sdio_func.h>
#include <asm/unaligned.h>
#include "iwmc3200top.h"
#include "log.h"
#include "fw-msg.h"
#define CHECKSUM_BYTES_NUM sizeof(u32)
/**
init parser struct with file
*/
static int iwmct_fw_parser_init(struct iwmct_priv *priv, const u8 *file,
size_t file_size, size_t block_size)
{
struct iwmct_parser *parser = &priv->parser;
struct iwmct_fw_hdr *fw_hdr = &parser->versions;
LOG_INFOEX(priv, INIT, "-->\n");
LOG_INFO(priv, FW_DOWNLOAD, "file_size=%zd\n", file_size);
parser->file = file;
parser->file_size = file_size;
parser->cur_pos = 0;
parser->buf = NULL;
parser->buf = kzalloc(block_size, GFP_KERNEL);
if (!parser->buf) {
LOG_ERROR(priv, FW_DOWNLOAD, "kzalloc error\n");
return -ENOMEM;
}
parser->buf_size = block_size;
/* extract fw versions */
memcpy(fw_hdr, parser->file, sizeof(struct iwmct_fw_hdr));
LOG_INFO(priv, FW_DOWNLOAD, "fw versions are:\n"
"top %u.%u.%u gps %u.%u.%u bt %u.%u.%u tic %s\n",
fw_hdr->top_major, fw_hdr->top_minor, fw_hdr->top_revision,
fw_hdr->gps_major, fw_hdr->gps_minor, fw_hdr->gps_revision,
fw_hdr->bt_major, fw_hdr->bt_minor, fw_hdr->bt_revision,
fw_hdr->tic_name);
parser->cur_pos += sizeof(struct iwmct_fw_hdr);
LOG_INFOEX(priv, INIT, "<--\n");
return 0;
}
static bool iwmct_checksum(struct iwmct_priv *priv)
{
struct iwmct_parser *parser = &priv->parser;
__le32 *file = (__le32 *)parser->file;
int i, pad, steps;
u32 accum = 0;
u32 checksum;
u32 mask = 0xffffffff;
pad = (parser->file_size - CHECKSUM_BYTES_NUM) % 4;
steps = (parser->file_size - CHECKSUM_BYTES_NUM) / 4;
LOG_INFO(priv, FW_DOWNLOAD, "pad=%d steps=%d\n", pad, steps);
for (i = 0; i < steps; i++)
accum += le32_to_cpu(file[i]);
if (pad) {
mask <<= 8 * (4 - pad);
accum += le32_to_cpu(file[steps]) & mask;
}
checksum = get_unaligned_le32((__le32 *)(parser->file +
parser->file_size - CHECKSUM_BYTES_NUM));
LOG_INFO(priv, FW_DOWNLOAD,
"compare checksum accum=0x%x to checksum=0x%x\n",
accum, checksum);
return checksum == accum;
}
static int iwmct_parse_next_section(struct iwmct_priv *priv, const u8 **p_sec,
size_t *sec_size, __le32 *sec_addr)
{
struct iwmct_parser *parser = &priv->parser;
struct iwmct_dbg *dbg = &priv->dbg;
struct iwmct_fw_sec_hdr *sec_hdr;
LOG_INFOEX(priv, INIT, "-->\n");
while (parser->cur_pos + sizeof(struct iwmct_fw_sec_hdr)
<= parser->file_size) {
sec_hdr = (struct iwmct_fw_sec_hdr *)
(parser->file + parser->cur_pos);
parser->cur_pos += sizeof(struct iwmct_fw_sec_hdr);
LOG_INFO(priv, FW_DOWNLOAD,
"sec hdr: type=%s addr=0x%x size=%d\n",
sec_hdr->type, sec_hdr->target_addr,
sec_hdr->data_size);
if (strcmp(sec_hdr->type, "ENT") == 0)
parser->entry_point = le32_to_cpu(sec_hdr->target_addr);
else if (strcmp(sec_hdr->type, "LBL") == 0)
strcpy(dbg->label_fw, parser->file + parser->cur_pos);
else if (((strcmp(sec_hdr->type, "TOP") == 0) &&
(priv->barker & BARKER_DNLOAD_TOP_MSK)) ||
((strcmp(sec_hdr->type, "GPS") == 0) &&
(priv->barker & BARKER_DNLOAD_GPS_MSK)) ||
((strcmp(sec_hdr->type, "BTH") == 0) &&
(priv->barker & BARKER_DNLOAD_BT_MSK))) {
*sec_addr = sec_hdr->target_addr;
*sec_size = le32_to_cpu(sec_hdr->data_size);
*p_sec = parser->file + parser->cur_pos;
parser->cur_pos += le32_to_cpu(sec_hdr->data_size);
return 1;
} else if (strcmp(sec_hdr->type, "LOG") != 0)
LOG_WARNING(priv, FW_DOWNLOAD,
"skipping section type %s\n",
sec_hdr->type);
parser->cur_pos += le32_to_cpu(sec_hdr->data_size);
LOG_INFO(priv, FW_DOWNLOAD,
"finished with section cur_pos=%zd\n", parser->cur_pos);
}
LOG_INFOEX(priv, INIT, "<--\n");
return 0;
}
static int iwmct_download_section(struct iwmct_priv *priv, const u8 *p_sec,
size_t sec_size, __le32 addr)
{
struct iwmct_parser *parser = &priv->parser;
struct iwmct_fw_load_hdr *hdr = (struct iwmct_fw_load_hdr *)parser->buf;
const u8 *cur_block = p_sec;
size_t sent = 0;
int cnt = 0;
int ret = 0;
u32 cmd = 0;
LOG_INFOEX(priv, INIT, "-->\n");
LOG_INFO(priv, FW_DOWNLOAD, "Download address 0x%x size 0x%zx\n",
addr, sec_size);
while (sent < sec_size) {
int i;
u32 chksm = 0;
u32 reset = atomic_read(&priv->reset);
/* actual FW data */
u32 data_size = min(parser->buf_size - sizeof(*hdr),
sec_size - sent);
/* Pad to block size */
u32 trans_size = (data_size + sizeof(*hdr) +
IWMC_SDIO_BLK_SIZE - 1) &
~(IWMC_SDIO_BLK_SIZE - 1);
++cnt;
/* in case of reset, interrupt FW DOWNLAOD */
if (reset) {
LOG_INFO(priv, FW_DOWNLOAD,
"Reset detected. Abort FW download!!!");
ret = -ECANCELED;
goto exit;
}
memset(parser->buf, 0, parser->buf_size);
cmd |= IWMC_OPCODE_WRITE << CMD_HDR_OPCODE_POS;
cmd |= IWMC_CMD_SIGNATURE << CMD_HDR_SIGNATURE_POS;
cmd |= (priv->dbg.direct ? 1 : 0) << CMD_HDR_DIRECT_ACCESS_POS;
cmd |= (priv->dbg.checksum ? 1 : 0) << CMD_HDR_USE_CHECKSUM_POS;
hdr->data_size = cpu_to_le32(data_size);
hdr->target_addr = addr;
/* checksum is allowed for sizes divisible by 4 */
if (data_size & 0x3)
cmd &= ~CMD_HDR_USE_CHECKSUM_MSK;
memcpy(hdr->data, cur_block, data_size);
if (cmd & CMD_HDR_USE_CHECKSUM_MSK) {
chksm = data_size + le32_to_cpu(addr) + cmd;
for (i = 0; i < data_size >> 2; i++)
chksm += ((u32 *)cur_block)[i];
hdr->block_chksm = cpu_to_le32(chksm);
LOG_INFO(priv, FW_DOWNLOAD, "Checksum = 0x%X\n",
hdr->block_chksm);
}
LOG_INFO(priv, FW_DOWNLOAD, "trans#%d, len=%d, sent=%zd, "
"sec_size=%zd, startAddress 0x%X\n",
cnt, trans_size, sent, sec_size, addr);
if (priv->dbg.dump)
LOG_HEXDUMP(FW_DOWNLOAD, parser->buf, trans_size);
hdr->cmd = cpu_to_le32(cmd);
/* send it down */
/* TODO: add more proper sending and error checking */
ret = iwmct_tx(priv, 0, parser->buf, trans_size);
if (ret != 0) {
LOG_INFO(priv, FW_DOWNLOAD,
"iwmct_tx returned %d\n", ret);
goto exit;
}
addr = cpu_to_le32(le32_to_cpu(addr) + data_size);
sent += data_size;
cur_block = p_sec + sent;
if (priv->dbg.blocks && (cnt + 1) >= priv->dbg.blocks) {
LOG_INFO(priv, FW_DOWNLOAD,
"Block number limit is reached [%d]\n",
priv->dbg.blocks);
break;
}
}
if (sent < sec_size)
ret = -EINVAL;
exit:
LOG_INFOEX(priv, INIT, "<--\n");
return ret;
}
static int iwmct_kick_fw(struct iwmct_priv *priv, bool jump)
{
struct iwmct_parser *parser = &priv->parser;
struct iwmct_fw_load_hdr *hdr = (struct iwmct_fw_load_hdr *)parser->buf;
int ret;
u32 cmd;
LOG_INFOEX(priv, INIT, "-->\n");
memset(parser->buf, 0, parser->buf_size);
cmd = IWMC_CMD_SIGNATURE << CMD_HDR_SIGNATURE_POS;
if (jump) {
cmd |= IWMC_OPCODE_JUMP << CMD_HDR_OPCODE_POS;
hdr->target_addr = cpu_to_le32(parser->entry_point);
LOG_INFO(priv, FW_DOWNLOAD, "jump address 0x%x\n",
parser->entry_point);
} else {
cmd |= IWMC_OPCODE_LAST_COMMAND << CMD_HDR_OPCODE_POS;
LOG_INFO(priv, FW_DOWNLOAD, "last command\n");
}
hdr->cmd = cpu_to_le32(cmd);
LOG_HEXDUMP(FW_DOWNLOAD, parser->buf, sizeof(*hdr));
/* send it down */
/* TODO: add more proper sending and error checking */
ret = iwmct_tx(priv, 0, parser->buf, IWMC_SDIO_BLK_SIZE);
if (ret)
LOG_INFO(priv, FW_DOWNLOAD, "iwmct_tx returned %d", ret);
LOG_INFOEX(priv, INIT, "<--\n");
return 0;
}
int iwmct_fw_load(struct iwmct_priv *priv)
{
const u8 *fw_name = FW_NAME(FW_API_VER);
const struct firmware *raw;
const u8 *pdata;
size_t len;
__le32 addr;
int ret;
/* clear parser struct */
memset(&priv->parser, 0, sizeof(struct iwmct_parser));
/* get the firmware */
ret = request_firmware(&raw, fw_name, &priv->func->dev);
if (ret < 0) {
LOG_ERROR(priv, FW_DOWNLOAD, "%s request_firmware failed %d\n",
fw_name, ret);
goto exit;
}
if (raw->size < sizeof(struct iwmct_fw_sec_hdr)) {
LOG_ERROR(priv, FW_DOWNLOAD, "%s smaller then (%zd) (%zd)\n",
fw_name, sizeof(struct iwmct_fw_sec_hdr), raw->size);
goto exit;
}
LOG_INFO(priv, FW_DOWNLOAD, "Read firmware '%s'\n", fw_name);
ret = iwmct_fw_parser_init(priv, raw->data, raw->size, priv->trans_len);
if (ret < 0) {
LOG_ERROR(priv, FW_DOWNLOAD,
"iwmct_parser_init failed: Reason %d\n", ret);
goto exit;
}
/* checksum */
if (!iwmct_checksum(priv)) {
LOG_ERROR(priv, FW_DOWNLOAD, "checksum error\n");
ret = -EINVAL;
goto exit;
}
/* download firmware to device */
while (iwmct_parse_next_section(priv, &pdata, &len, &addr)) {
if (iwmct_download_section(priv, pdata, len, addr)) {
LOG_ERROR(priv, FW_DOWNLOAD,
"%s download section failed\n", fw_name);
ret = -EIO;
goto exit;
}
}
iwmct_kick_fw(priv, !!(priv->barker & BARKER_DNLOAD_JUMP_MSK));
exit:
kfree(priv->parser.buf);
if (raw)
release_firmware(raw);
raw = NULL;
return ret;
}

View File

@ -0,0 +1,113 @@
/*
* iwmc3200top - Intel Wireless MultiCom 3200 Top Driver
* drivers/misc/iwmc3200top/fw-msg.h
*
* Copyright (C) 2009 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
*
* Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com>
* -
*
*/
#ifndef __FWMSG_H__
#define __FWMSG_H__
#define COMM_TYPE_D2H 0xFF
#define COMM_TYPE_H2D 0xEE
#define COMM_CATEGORY_OPERATIONAL 0x00
#define COMM_CATEGORY_DEBUG 0x01
#define COMM_CATEGORY_TESTABILITY 0x02
#define COMM_CATEGORY_DIAGNOSTICS 0x03
#define OP_DBG_ZSTR_MSG cpu_to_le16(0x1A)
#define FW_LOG_SRC_MAX 32
#define FW_LOG_SRC_ALL 255
#define FW_STRING_TABLE_ADDR cpu_to_le32(0x0C000000)
#define CMD_DBG_LOG_LEVEL cpu_to_le16(0x0001)
#define CMD_TST_DEV_RESET cpu_to_le16(0x0060)
#define CMD_TST_FUNC_RESET cpu_to_le16(0x0062)
#define CMD_TST_IFACE_RESET cpu_to_le16(0x0064)
#define CMD_TST_CPU_UTILIZATION cpu_to_le16(0x0065)
#define CMD_TST_TOP_DEEP_SLEEP cpu_to_le16(0x0080)
#define CMD_TST_WAKEUP cpu_to_le16(0x0081)
#define CMD_TST_FUNC_WAKEUP cpu_to_le16(0x0082)
#define CMD_TST_FUNC_DEEP_SLEEP_REQUEST cpu_to_le16(0x0083)
#define CMD_TST_GET_MEM_DUMP cpu_to_le16(0x0096)
#define OP_OPR_ALIVE cpu_to_le16(0x0010)
#define OP_OPR_CMD_ACK cpu_to_le16(0x001F)
#define OP_OPR_CMD_NACK cpu_to_le16(0x0020)
#define OP_TST_MEM_DUMP cpu_to_le16(0x0043)
#define CMD_FLAG_PADDING_256 0x80
#define FW_HCMD_BLOCK_SIZE 256
struct msg_hdr {
u8 type;
u8 category;
__le16 opcode;
u8 seqnum;
u8 flags;
__le16 length;
} __attribute__((__packed__));
struct log_hdr {
__le32 timestamp;
u8 severity;
u8 logsource;
__le16 reserved;
} __attribute__((__packed__));
struct mdump_hdr {
u8 dmpid;
u8 frag;
__le16 size;
__le32 addr;
} __attribute__((__packed__));
struct top_msg {
struct msg_hdr hdr;
union {
/* D2H messages */
struct {
struct log_hdr log_hdr;
u8 data[1];
} __attribute__((__packed__)) log;
struct {
struct log_hdr log_hdr;
struct mdump_hdr md_hdr;
u8 data[1];
} __attribute__((__packed__)) mdump;
/* H2D messages */
struct {
u8 logsource;
u8 sevmask;
} __attribute__((__packed__)) logdefs[FW_LOG_SRC_MAX];
struct mdump_hdr mdump_req;
} u;
} __attribute__((__packed__));
#endif /* __FWMSG_H__ */

View File

@ -0,0 +1,209 @@
/*
* iwmc3200top - Intel Wireless MultiCom 3200 Top Driver
* drivers/misc/iwmc3200top/iwmc3200top.h
*
* Copyright (C) 2009 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
*
* Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com>
* -
*
*/
#ifndef __IWMC3200TOP_H__
#define __IWMC3200TOP_H__
#include <linux/workqueue.h>
#define DRV_NAME "iwmc3200top"
#define FW_API_VER 1
#define _FW_NAME(api) DRV_NAME "." #api ".fw"
#define FW_NAME(api) _FW_NAME(api)
#define IWMC_SDIO_BLK_SIZE 256
#define IWMC_DEFAULT_TR_BLK 64
#define IWMC_SDIO_DATA_ADDR 0x0
#define IWMC_SDIO_INTR_ENABLE_ADDR 0x14
#define IWMC_SDIO_INTR_STATUS_ADDR 0x13
#define IWMC_SDIO_INTR_CLEAR_ADDR 0x13
#define IWMC_SDIO_INTR_GET_SIZE_ADDR 0x2C
#define COMM_HUB_HEADER_LENGTH 16
#define LOGGER_HEADER_LENGTH 10
#define BARKER_DNLOAD_BT_POS 0
#define BARKER_DNLOAD_BT_MSK BIT(BARKER_DNLOAD_BT_POS)
#define BARKER_DNLOAD_GPS_POS 1
#define BARKER_DNLOAD_GPS_MSK BIT(BARKER_DNLOAD_GPS_POS)
#define BARKER_DNLOAD_TOP_POS 2
#define BARKER_DNLOAD_TOP_MSK BIT(BARKER_DNLOAD_TOP_POS)
#define BARKER_DNLOAD_RESERVED1_POS 3
#define BARKER_DNLOAD_RESERVED1_MSK BIT(BARKER_DNLOAD_RESERVED1_POS)
#define BARKER_DNLOAD_JUMP_POS 4
#define BARKER_DNLOAD_JUMP_MSK BIT(BARKER_DNLOAD_JUMP_POS)
#define BARKER_DNLOAD_SYNC_POS 5
#define BARKER_DNLOAD_SYNC_MSK BIT(BARKER_DNLOAD_SYNC_POS)
#define BARKER_DNLOAD_RESERVED2_POS 6
#define BARKER_DNLOAD_RESERVED2_MSK (0x3 << BARKER_DNLOAD_RESERVED2_POS)
#define BARKER_DNLOAD_BARKER_POS 8
#define BARKER_DNLOAD_BARKER_MSK (0xffffff << BARKER_DNLOAD_BARKER_POS)
#define IWMC_BARKER_REBOOT (0xdeadbe << BARKER_DNLOAD_BARKER_POS)
/* whole field barker */
#define IWMC_BARKER_ACK 0xfeedbabe
#define IWMC_CMD_SIGNATURE 0xcbbc
#define CMD_HDR_OPCODE_POS 0
#define CMD_HDR_OPCODE_MSK_MSK (0xf << CMD_HDR_OPCODE_MSK_POS)
#define CMD_HDR_RESPONSE_CODE_POS 4
#define CMD_HDR_RESPONSE_CODE_MSK (0xf << CMD_HDR_RESPONSE_CODE_POS)
#define CMD_HDR_USE_CHECKSUM_POS 8
#define CMD_HDR_USE_CHECKSUM_MSK BIT(CMD_HDR_USE_CHECKSUM_POS)
#define CMD_HDR_RESPONSE_REQUIRED_POS 9
#define CMD_HDR_RESPONSE_REQUIRED_MSK BIT(CMD_HDR_RESPONSE_REQUIRED_POS)
#define CMD_HDR_DIRECT_ACCESS_POS 10
#define CMD_HDR_DIRECT_ACCESS_MSK BIT(CMD_HDR_DIRECT_ACCESS_POS)
#define CMD_HDR_RESERVED_POS 11
#define CMD_HDR_RESERVED_MSK BIT(0x1f << CMD_HDR_RESERVED_POS)
#define CMD_HDR_SIGNATURE_POS 16
#define CMD_HDR_SIGNATURE_MSK BIT(0xffff << CMD_HDR_SIGNATURE_POS)
enum {
IWMC_OPCODE_PING = 0,
IWMC_OPCODE_READ = 1,
IWMC_OPCODE_WRITE = 2,
IWMC_OPCODE_JUMP = 3,
IWMC_OPCODE_REBOOT = 4,
IWMC_OPCODE_PERSISTENT_WRITE = 5,
IWMC_OPCODE_PERSISTENT_READ = 6,
IWMC_OPCODE_READ_MODIFY_WRITE = 7,
IWMC_OPCODE_LAST_COMMAND = 15
};
struct iwmct_fw_load_hdr {
__le32 cmd;
__le32 target_addr;
__le32 data_size;
__le32 block_chksm;
u8 data[0];
};
/**
* struct iwmct_fw_hdr
* holds all sw components versions
*/
struct iwmct_fw_hdr {
u8 top_major;
u8 top_minor;
u8 top_revision;
u8 gps_major;
u8 gps_minor;
u8 gps_revision;
u8 bt_major;
u8 bt_minor;
u8 bt_revision;
u8 tic_name[31];
};
/**
* struct iwmct_fw_sec_hdr
* @type: function type
* @data_size: section's data size
* @target_addr: download address
*/
struct iwmct_fw_sec_hdr {
u8 type[4];
__le32 data_size;
__le32 target_addr;
};
/**
* struct iwmct_parser
* @file: fw image
* @file_size: fw size
* @cur_pos: position in file
* @buf: temp buf for download
* @buf_size: size of buf
* @entry_point: address to jump in fw kick-off
*/
struct iwmct_parser {
const u8 *file;
size_t file_size;
size_t cur_pos;
u8 *buf;
size_t buf_size;
u32 entry_point;
struct iwmct_fw_hdr versions;
};
struct iwmct_work_struct {
struct list_head list;
ssize_t iosize;
};
struct iwmct_dbg {
int blocks;
bool dump;
bool jump;
bool direct;
bool checksum;
bool fw_download;
int block_size;
int download_trans_blks;
char label_fw[256];
};
struct iwmct_debugfs;
struct iwmct_priv {
struct sdio_func *func;
struct iwmct_debugfs *dbgfs;
struct iwmct_parser parser;
atomic_t reset;
atomic_t dev_sync;
u32 trans_len;
u32 barker;
struct iwmct_dbg dbg;
/* drivers work queue */
struct workqueue_struct *wq;
struct workqueue_struct *bus_rescan_wq;
struct work_struct bus_rescan_worker;
struct work_struct isr_worker;
/* drivers wait queue */
wait_queue_head_t wait_q;
/* rx request list */
struct list_head read_req_list;
};
extern int iwmct_tx(struct iwmct_priv *priv, unsigned int addr,
void *src, int count);
extern int iwmct_fw_load(struct iwmct_priv *priv);
extern void iwmct_dbg_init_params(struct iwmct_priv *drv);
extern void iwmct_dbg_init_drv_attrs(struct device_driver *drv);
extern void iwmct_dbg_remove_drv_attrs(struct device_driver *drv);
extern int iwmct_send_hcmd(struct iwmct_priv *priv, u8 *cmd, u16 len);
#endif /* __IWMC3200TOP_H__ */

View File

@ -0,0 +1,347 @@
/*
* iwmc3200top - Intel Wireless MultiCom 3200 Top Driver
* drivers/misc/iwmc3200top/log.c
*
* Copyright (C) 2009 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
*
* Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com>
* -
*
*/
#include <linux/kernel.h>
#include <linux/mmc/sdio_func.h>
#include <linux/ctype.h>
#include "fw-msg.h"
#include "iwmc3200top.h"
#include "log.h"
/* Maximal hexadecimal string size of the FW memdump message */
#define LOG_MSG_SIZE_MAX 12400
/* iwmct_logdefs is a global used by log macros */
u8 iwmct_logdefs[LOG_SRC_MAX];
static u8 iwmct_fw_logdefs[FW_LOG_SRC_MAX];
static int _log_set_log_filter(u8 *logdefs, int size, u8 src, u8 logmask)
{
int i;
if (src < size)
logdefs[src] = logmask;
else if (src == LOG_SRC_ALL)
for (i = 0; i < size; i++)
logdefs[i] = logmask;
else
return -1;
return 0;
}
int iwmct_log_set_filter(u8 src, u8 logmask)
{
return _log_set_log_filter(iwmct_logdefs, LOG_SRC_MAX, src, logmask);
}
int iwmct_log_set_fw_filter(u8 src, u8 logmask)
{
return _log_set_log_filter(iwmct_fw_logdefs,
FW_LOG_SRC_MAX, src, logmask);
}
static int log_msg_format_hex(char *str, int slen, u8 *ibuf,
int ilen, char *pref)
{
int pos = 0;
int i;
int len;
for (pos = 0, i = 0; pos < slen - 2 && pref[i] != '\0'; i++, pos++)
str[pos] = pref[i];
for (i = 0; pos < slen - 2 && i < ilen; pos += len, i++)
len = snprintf(&str[pos], slen - pos - 1, " %2.2X", ibuf[i]);
if (i < ilen)
return -1;
return 0;
}
/* NOTE: This function is not thread safe.
Currently it's called only from sdio rx worker - no race there
*/
void iwmct_log_top_message(struct iwmct_priv *priv, u8 *buf, int len)
{
struct top_msg *msg;
static char logbuf[LOG_MSG_SIZE_MAX];
msg = (struct top_msg *)buf;
if (len < sizeof(msg->hdr) + sizeof(msg->u.log.log_hdr)) {
LOG_ERROR(priv, FW_MSG, "Log message from TOP "
"is too short %d (expected %zd)\n",
len, sizeof(msg->hdr) + sizeof(msg->u.log.log_hdr));
return;
}
if (!(iwmct_fw_logdefs[msg->u.log.log_hdr.logsource] &
BIT(msg->u.log.log_hdr.severity)) ||
!(iwmct_logdefs[LOG_SRC_FW_MSG] & BIT(msg->u.log.log_hdr.severity)))
return;
switch (msg->hdr.category) {
case COMM_CATEGORY_TESTABILITY:
if (!(iwmct_logdefs[LOG_SRC_TST] &
BIT(msg->u.log.log_hdr.severity)))
return;
if (log_msg_format_hex(logbuf, LOG_MSG_SIZE_MAX, buf,
le16_to_cpu(msg->hdr.length) +
sizeof(msg->hdr), "<TST>"))
LOG_WARNING(priv, TST,
"TOP TST message is too long, truncating...");
LOG_WARNING(priv, TST, "%s\n", logbuf);
break;
case COMM_CATEGORY_DEBUG:
if (msg->hdr.opcode == OP_DBG_ZSTR_MSG)
LOG_INFO(priv, FW_MSG, "%s %s", "<DBG>",
((u8 *)msg) + sizeof(msg->hdr)
+ sizeof(msg->u.log.log_hdr));
else {
if (log_msg_format_hex(logbuf, LOG_MSG_SIZE_MAX, buf,
le16_to_cpu(msg->hdr.length)
+ sizeof(msg->hdr),
"<DBG>"))
LOG_WARNING(priv, FW_MSG,
"TOP DBG message is too long,"
"truncating...");
LOG_WARNING(priv, FW_MSG, "%s\n", logbuf);
}
break;
default:
break;
}
}
static int _log_get_filter_str(u8 *logdefs, int logdefsz, char *buf, int size)
{
int i, pos, len;
for (i = 0, pos = 0; (pos < size-1) && (i < logdefsz); i++) {
len = snprintf(&buf[pos], size - pos - 1, "0x%02X%02X,",
i, logdefs[i]);
pos += len;
}
buf[pos-1] = '\n';
buf[pos] = '\0';
if (i < logdefsz)
return -1;
return 0;
}
int log_get_filter_str(char *buf, int size)
{
return _log_get_filter_str(iwmct_logdefs, LOG_SRC_MAX, buf, size);
}
int log_get_fw_filter_str(char *buf, int size)
{
return _log_get_filter_str(iwmct_fw_logdefs, FW_LOG_SRC_MAX, buf, size);
}
#define HEXADECIMAL_RADIX 16
#define LOG_SRC_FORMAT 7 /* log level is in format of "0xXXXX," */
ssize_t show_iwmct_log_level(struct device *d,
struct device_attribute *attr, char *buf)
{
struct iwmct_priv *priv = dev_get_drvdata(d);
char *str_buf;
int buf_size;
ssize_t ret;
buf_size = (LOG_SRC_FORMAT * LOG_SRC_MAX) + 1;
str_buf = kzalloc(buf_size, GFP_KERNEL);
if (!str_buf) {
LOG_ERROR(priv, DEBUGFS,
"failed to allocate %d bytes\n", buf_size);
ret = -ENOMEM;
goto exit;
}
if (log_get_filter_str(str_buf, buf_size) < 0) {
ret = -EINVAL;
goto exit;
}
ret = sprintf(buf, "%s", str_buf);
exit:
kfree(str_buf);
return ret;
}
ssize_t store_iwmct_log_level(struct device *d,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct iwmct_priv *priv = dev_get_drvdata(d);
char *token, *str_buf = NULL;
long val;
ssize_t ret = count;
u8 src, mask;
if (!count)
goto exit;
str_buf = kzalloc(count, GFP_KERNEL);
if (!str_buf) {
LOG_ERROR(priv, DEBUGFS,
"failed to allocate %zd bytes\n", count);
ret = -ENOMEM;
goto exit;
}
memcpy(str_buf, buf, count);
while ((token = strsep(&str_buf, ",")) != NULL) {
while (isspace(*token))
++token;
if (strict_strtol(token, HEXADECIMAL_RADIX, &val)) {
LOG_ERROR(priv, DEBUGFS,
"failed to convert string to long %s\n",
token);
ret = -EINVAL;
goto exit;
}
mask = val & 0xFF;
src = (val & 0XFF00) >> 8;
iwmct_log_set_filter(src, mask);
}
exit:
kfree(str_buf);
return ret;
}
ssize_t show_iwmct_log_level_fw(struct device *d,
struct device_attribute *attr, char *buf)
{
struct iwmct_priv *priv = dev_get_drvdata(d);
char *str_buf;
int buf_size;
ssize_t ret;
buf_size = (LOG_SRC_FORMAT * FW_LOG_SRC_MAX) + 2;
str_buf = kzalloc(buf_size, GFP_KERNEL);
if (!str_buf) {
LOG_ERROR(priv, DEBUGFS,
"failed to allocate %d bytes\n", buf_size);
ret = -ENOMEM;
goto exit;
}
if (log_get_fw_filter_str(str_buf, buf_size) < 0) {
ret = -EINVAL;
goto exit;
}
ret = sprintf(buf, "%s", str_buf);
exit:
kfree(str_buf);
return ret;
}
ssize_t store_iwmct_log_level_fw(struct device *d,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct iwmct_priv *priv = dev_get_drvdata(d);
struct top_msg cmd;
char *token, *str_buf = NULL;
ssize_t ret = count;
u16 cmdlen = 0;
int i;
long val;
u8 src, mask;
if (!count)
goto exit;
str_buf = kzalloc(count, GFP_KERNEL);
if (!str_buf) {
LOG_ERROR(priv, DEBUGFS,
"failed to allocate %zd bytes\n", count);
ret = -ENOMEM;
goto exit;
}
memcpy(str_buf, buf, count);
cmd.hdr.type = COMM_TYPE_H2D;
cmd.hdr.category = COMM_CATEGORY_DEBUG;
cmd.hdr.opcode = CMD_DBG_LOG_LEVEL;
for (i = 0; ((token = strsep(&str_buf, ",")) != NULL) &&
(i < FW_LOG_SRC_MAX); i++) {
while (isspace(*token))
++token;
if (strict_strtol(token, HEXADECIMAL_RADIX, &val)) {
LOG_ERROR(priv, DEBUGFS,
"failed to convert string to long %s\n",
token);
ret = -EINVAL;
goto exit;
}
mask = val & 0xFF; /* LSB */
src = (val & 0XFF00) >> 8; /* 2nd least significant byte. */
iwmct_log_set_fw_filter(src, mask);
cmd.u.logdefs[i].logsource = src;
cmd.u.logdefs[i].sevmask = mask;
}
cmd.hdr.length = cpu_to_le16(i * sizeof(cmd.u.logdefs[0]));
cmdlen = (i * sizeof(cmd.u.logdefs[0]) + sizeof(cmd.hdr));
ret = iwmct_send_hcmd(priv, (u8 *)&cmd, cmdlen);
if (ret) {
LOG_ERROR(priv, DEBUGFS,
"Failed to send %d bytes of fwcmd, ret=%zd\n",
cmdlen, ret);
goto exit;
} else
LOG_INFO(priv, DEBUGFS, "fwcmd sent (%d bytes)\n", cmdlen);
ret = count;
exit:
kfree(str_buf);
return ret;
}

View File

@ -0,0 +1,158 @@
/*
* iwmc3200top - Intel Wireless MultiCom 3200 Top Driver
* drivers/misc/iwmc3200top/log.h
*
* Copyright (C) 2009 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
*
* Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com>
* -
*
*/
#ifndef __LOG_H__
#define __LOG_H__
/* log severity:
* The log levels here match FW log levels
* so values need to stay as is */
#define LOG_SEV_CRITICAL 0
#define LOG_SEV_ERROR 1
#define LOG_SEV_WARNING 2
#define LOG_SEV_INFO 3
#define LOG_SEV_INFOEX 4
#define LOG_SEV_FILTER_ALL \
(BIT(LOG_SEV_CRITICAL) | \
BIT(LOG_SEV_ERROR) | \
BIT(LOG_SEV_WARNING) | \
BIT(LOG_SEV_INFO) | \
BIT(LOG_SEV_INFOEX))
/* log source */
#define LOG_SRC_INIT 0
#define LOG_SRC_DEBUGFS 1
#define LOG_SRC_FW_DOWNLOAD 2
#define LOG_SRC_FW_MSG 3
#define LOG_SRC_TST 4
#define LOG_SRC_IRQ 5
#define LOG_SRC_MAX 6
#define LOG_SRC_ALL 0xFF
/**
* Default intitialization runtime log level
*/
#ifndef LOG_SEV_FILTER_RUNTIME
#define LOG_SEV_FILTER_RUNTIME \
(BIT(LOG_SEV_CRITICAL) | \
BIT(LOG_SEV_ERROR) | \
BIT(LOG_SEV_WARNING))
#endif
#ifndef FW_LOG_SEV_FILTER_RUNTIME
#define FW_LOG_SEV_FILTER_RUNTIME LOG_SEV_FILTER_ALL
#endif
#ifdef CONFIG_IWMC3200TOP_DEBUG
/**
* Log macros
*/
#define priv2dev(priv) (&(priv->func)->dev)
#define LOG_CRITICAL(priv, src, fmt, args...) \
do { \
if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_CRITICAL)) \
dev_crit(priv2dev(priv), "%s %d: " fmt, \
__func__, __LINE__, ##args); \
} while (0)
#define LOG_ERROR(priv, src, fmt, args...) \
do { \
if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_ERROR)) \
dev_err(priv2dev(priv), "%s %d: " fmt, \
__func__, __LINE__, ##args); \
} while (0)
#define LOG_WARNING(priv, src, fmt, args...) \
do { \
if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_WARNING)) \
dev_warn(priv2dev(priv), "%s %d: " fmt, \
__func__, __LINE__, ##args); \
} while (0)
#define LOG_INFO(priv, src, fmt, args...) \
do { \
if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_INFO)) \
dev_info(priv2dev(priv), "%s %d: " fmt, \
__func__, __LINE__, ##args); \
} while (0)
#define LOG_INFOEX(priv, src, fmt, args...) \
do { \
if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_INFOEX)) \
dev_dbg(priv2dev(priv), "%s %d: " fmt, \
__func__, __LINE__, ##args); \
} while (0)
#define LOG_HEXDUMP(src, ptr, len) \
do { \
if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_INFOEX)) \
print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_NONE, \
16, 1, ptr, len, false); \
} while (0)
void iwmct_log_top_message(struct iwmct_priv *priv, u8 *buf, int len);
extern u8 iwmct_logdefs[];
int iwmct_log_set_filter(u8 src, u8 logmask);
int iwmct_log_set_fw_filter(u8 src, u8 logmask);
ssize_t show_iwmct_log_level(struct device *d,
struct device_attribute *attr, char *buf);
ssize_t store_iwmct_log_level(struct device *d,
struct device_attribute *attr,
const char *buf, size_t count);
ssize_t show_iwmct_log_level_fw(struct device *d,
struct device_attribute *attr, char *buf);
ssize_t store_iwmct_log_level_fw(struct device *d,
struct device_attribute *attr,
const char *buf, size_t count);
#else
#define LOG_CRITICAL(priv, src, fmt, args...)
#define LOG_ERROR(priv, src, fmt, args...)
#define LOG_WARNING(priv, src, fmt, args...)
#define LOG_INFO(priv, src, fmt, args...)
#define LOG_INFOEX(priv, src, fmt, args...)
#define LOG_HEXDUMP(src, ptr, len)
static inline void iwmct_log_top_message(struct iwmct_priv *priv,
u8 *buf, int len) {}
static inline int iwmct_log_set_filter(u8 src, u8 logmask) { return 0; }
static inline int iwmct_log_set_fw_filter(u8 src, u8 logmask) { return 0; }
#endif /* CONFIG_IWMC3200TOP_DEBUG */
int log_get_filter_str(char *buf, int size);
int log_get_fw_filter_str(char *buf, int size);
#endif /* __LOG_H__ */

View File

@ -0,0 +1,678 @@
/*
* iwmc3200top - Intel Wireless MultiCom 3200 Top Driver
* drivers/misc/iwmc3200top/main.c
*
* Copyright (C) 2009 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
*
* Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com>
* -
*
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/debugfs.h>
#include <linux/mmc/sdio_ids.h>
#include <linux/mmc/sdio_func.h>
#include <linux/mmc/sdio.h>
#include "iwmc3200top.h"
#include "log.h"
#include "fw-msg.h"
#include "debugfs.h"
#define DRIVER_DESCRIPTION "Intel(R) IWMC 3200 Top Driver"
#define DRIVER_COPYRIGHT "Copyright (c) 2008 Intel Corporation."
#define DRIVER_VERSION "0.1.62"
MODULE_DESCRIPTION(DRIVER_DESCRIPTION);
MODULE_VERSION(DRIVER_VERSION);
MODULE_LICENSE("GPL");
MODULE_AUTHOR(DRIVER_COPYRIGHT);
MODULE_FIRMWARE(FW_NAME(FW_API_VER));
/*
* This workers main task is to wait for OP_OPR_ALIVE
* from TOP FW until ALIVE_MSG_TIMOUT timeout is elapsed.
* When OP_OPR_ALIVE received it will issue
* a call to "bus_rescan_devices".
*/
static void iwmct_rescan_worker(struct work_struct *ws)
{
struct iwmct_priv *priv;
int ret;
priv = container_of(ws, struct iwmct_priv, bus_rescan_worker);
LOG_INFO(priv, FW_MSG, "Calling bus_rescan\n");
ret = bus_rescan_devices(priv->func->dev.bus);
if (ret < 0)
LOG_INFO(priv, FW_DOWNLOAD, "bus_rescan_devices FAILED!!!\n");
}
static void op_top_message(struct iwmct_priv *priv, struct top_msg *msg)
{
switch (msg->hdr.opcode) {
case OP_OPR_ALIVE:
LOG_INFO(priv, FW_MSG, "Got ALIVE from device, wake rescan\n");
queue_work(priv->bus_rescan_wq, &priv->bus_rescan_worker);
break;
default:
LOG_INFO(priv, FW_MSG, "Received msg opcode 0x%X\n",
msg->hdr.opcode);
break;
}
}
static void handle_top_message(struct iwmct_priv *priv, u8 *buf, int len)
{
struct top_msg *msg;
msg = (struct top_msg *)buf;
if (msg->hdr.type != COMM_TYPE_D2H) {
LOG_ERROR(priv, FW_MSG,
"Message from TOP with invalid message type 0x%X\n",
msg->hdr.type);
return;
}
if (len < sizeof(msg->hdr)) {
LOG_ERROR(priv, FW_MSG,
"Message from TOP is too short for message header "
"received %d bytes, expected at least %zd bytes\n",
len, sizeof(msg->hdr));
return;
}
if (len < le16_to_cpu(msg->hdr.length) + sizeof(msg->hdr)) {
LOG_ERROR(priv, FW_MSG,
"Message length (%d bytes) is shorter than "
"in header (%d bytes)\n",
len, le16_to_cpu(msg->hdr.length));
return;
}
switch (msg->hdr.category) {
case COMM_CATEGORY_OPERATIONAL:
op_top_message(priv, (struct top_msg *)buf);
break;
case COMM_CATEGORY_DEBUG:
case COMM_CATEGORY_TESTABILITY:
case COMM_CATEGORY_DIAGNOSTICS:
iwmct_log_top_message(priv, buf, len);
break;
default:
LOG_ERROR(priv, FW_MSG,
"Message from TOP with unknown category 0x%X\n",
msg->hdr.category);
break;
}
}
int iwmct_send_hcmd(struct iwmct_priv *priv, u8 *cmd, u16 len)
{
int ret;
u8 *buf;
LOG_INFOEX(priv, FW_MSG, "Sending hcmd:\n");
/* add padding to 256 for IWMC */
((struct top_msg *)cmd)->hdr.flags |= CMD_FLAG_PADDING_256;
LOG_HEXDUMP(FW_MSG, cmd, len);
if (len > FW_HCMD_BLOCK_SIZE) {
LOG_ERROR(priv, FW_MSG, "size %d exceeded hcmd max size %d\n",
len, FW_HCMD_BLOCK_SIZE);
return -1;
}
buf = kzalloc(FW_HCMD_BLOCK_SIZE, GFP_KERNEL);
if (!buf) {
LOG_ERROR(priv, FW_MSG, "kzalloc error, buf size %d\n",
FW_HCMD_BLOCK_SIZE);
return -1;
}
memcpy(buf, cmd, len);
sdio_claim_host(priv->func);
ret = sdio_memcpy_toio(priv->func, IWMC_SDIO_DATA_ADDR, buf,
FW_HCMD_BLOCK_SIZE);
sdio_release_host(priv->func);
kfree(buf);
return ret;
}
int iwmct_tx(struct iwmct_priv *priv, unsigned int addr,
void *src, int count)
{
int ret;
sdio_claim_host(priv->func);
ret = sdio_memcpy_toio(priv->func, addr, src, count);
sdio_release_host(priv->func);
return ret;
}
static void iwmct_irq_read_worker(struct work_struct *ws)
{
struct iwmct_priv *priv;
struct iwmct_work_struct *read_req;
__le32 *buf = NULL;
int ret;
int iosize;
u32 barker;
bool is_barker;
priv = container_of(ws, struct iwmct_priv, isr_worker);
LOG_INFO(priv, IRQ, "enter iwmct_irq_read_worker %p\n", ws);
/* --------------------- Handshake with device -------------------- */
sdio_claim_host(priv->func);
/* all list manipulations have to be protected by
* sdio_claim_host/sdio_release_host */
if (list_empty(&priv->read_req_list)) {
LOG_ERROR(priv, IRQ, "read_req_list empty in read worker\n");
goto exit_release;
}
read_req = list_entry(priv->read_req_list.next,
struct iwmct_work_struct, list);
list_del(&read_req->list);
iosize = read_req->iosize;
kfree(read_req);
buf = kzalloc(iosize, GFP_KERNEL);
if (!buf) {
LOG_ERROR(priv, IRQ, "kzalloc error, buf size %d\n", iosize);
goto exit_release;
}
LOG_INFO(priv, IRQ, "iosize=%d, buf=%p, func=%d\n",
iosize, buf, priv->func->num);
/* read from device */
ret = sdio_memcpy_fromio(priv->func, buf, IWMC_SDIO_DATA_ADDR, iosize);
if (ret) {
LOG_ERROR(priv, IRQ, "error %d reading buffer\n", ret);
goto exit_release;
}
LOG_HEXDUMP(IRQ, (u8 *)buf, iosize);
barker = le32_to_cpu(buf[0]);
/* Verify whether it's a barker and if not - treat as regular Rx */
if (barker == IWMC_BARKER_ACK ||
(barker & BARKER_DNLOAD_BARKER_MSK) == IWMC_BARKER_REBOOT) {
/* Valid Barker is equal on first 4 dwords */
is_barker = (buf[1] == buf[0]) &&
(buf[2] == buf[0]) &&
(buf[3] == buf[0]);
if (!is_barker) {
LOG_WARNING(priv, IRQ,
"Potentially inconsistent barker "
"%08X_%08X_%08X_%08X\n",
le32_to_cpu(buf[0]), le32_to_cpu(buf[1]),
le32_to_cpu(buf[2]), le32_to_cpu(buf[3]));
}
} else {
is_barker = false;
}
/* Handle Top CommHub message */
if (!is_barker) {
sdio_release_host(priv->func);
handle_top_message(priv, (u8 *)buf, iosize);
goto exit;
} else if (barker == IWMC_BARKER_ACK) { /* Handle barkers */
if (atomic_read(&priv->dev_sync) == 0) {
LOG_ERROR(priv, IRQ,
"ACK barker arrived out-of-sync\n");
goto exit_release;
}
/* Continuing to FW download (after Sync is completed)*/
atomic_set(&priv->dev_sync, 0);
LOG_INFO(priv, IRQ, "ACK barker arrived "
"- starting FW download\n");
} else { /* REBOOT barker */
LOG_INFO(priv, IRQ, "Recieved reboot barker: %x\n", barker);
priv->barker = barker;
if (barker & BARKER_DNLOAD_SYNC_MSK) {
/* Send the same barker back */
ret = sdio_memcpy_toio(priv->func, IWMC_SDIO_DATA_ADDR,
buf, iosize);
if (ret) {
LOG_ERROR(priv, IRQ,
"error %d echoing barker\n", ret);
goto exit_release;
}
LOG_INFO(priv, IRQ, "Echoing barker to device\n");
atomic_set(&priv->dev_sync, 1);
goto exit_release;
}
/* Continuing to FW download (without Sync) */
LOG_INFO(priv, IRQ, "No sync requested "
"- starting FW download\n");
}
sdio_release_host(priv->func);
LOG_INFO(priv, IRQ, "barker download request 0x%x is:\n", priv->barker);
LOG_INFO(priv, IRQ, "******* Top FW %s requested ********\n",
(priv->barker & BARKER_DNLOAD_TOP_MSK) ? "was" : "not");
LOG_INFO(priv, IRQ, "******* GPS FW %s requested ********\n",
(priv->barker & BARKER_DNLOAD_GPS_MSK) ? "was" : "not");
LOG_INFO(priv, IRQ, "******* BT FW %s requested ********\n",
(priv->barker & BARKER_DNLOAD_BT_MSK) ? "was" : "not");
if (priv->dbg.fw_download)
iwmct_fw_load(priv);
else
LOG_ERROR(priv, IRQ, "FW download not allowed\n");
goto exit;
exit_release:
sdio_release_host(priv->func);
exit:
kfree(buf);
LOG_INFO(priv, IRQ, "exit iwmct_irq_read_worker\n");
}
static void iwmct_irq(struct sdio_func *func)
{
struct iwmct_priv *priv;
int val, ret;
int iosize;
int addr = IWMC_SDIO_INTR_GET_SIZE_ADDR;
struct iwmct_work_struct *read_req;
priv = sdio_get_drvdata(func);
LOG_INFO(priv, IRQ, "enter iwmct_irq\n");
/* read the function's status register */
val = sdio_readb(func, IWMC_SDIO_INTR_STATUS_ADDR, &ret);
LOG_INFO(priv, IRQ, "iir value = %d, ret=%d\n", val, ret);
if (!val) {
LOG_ERROR(priv, IRQ, "iir = 0, exiting ISR\n");
goto exit_clear_intr;
}
/*
* read 2 bytes of the transaction size
* IMPORTANT: sdio transaction size has to be read before clearing
* sdio interrupt!!!
*/
val = sdio_readb(priv->func, addr++, &ret);
iosize = val;
val = sdio_readb(priv->func, addr++, &ret);
iosize += val << 8;
LOG_INFO(priv, IRQ, "READ size %d\n", iosize);
if (iosize == 0) {
LOG_ERROR(priv, IRQ, "READ size %d, exiting ISR\n", iosize);
goto exit_clear_intr;
}
/* allocate a work structure to pass iosize to the worker */
read_req = kzalloc(sizeof(struct iwmct_work_struct), GFP_KERNEL);
if (!read_req) {
LOG_ERROR(priv, IRQ, "failed to allocate read_req, exit ISR\n");
goto exit_clear_intr;
}
INIT_LIST_HEAD(&read_req->list);
read_req->iosize = iosize;
list_add_tail(&priv->read_req_list, &read_req->list);
/* clear the function's interrupt request bit (write 1 to clear) */
sdio_writeb(func, 1, IWMC_SDIO_INTR_CLEAR_ADDR, &ret);
queue_work(priv->wq, &priv->isr_worker);
LOG_INFO(priv, IRQ, "exit iwmct_irq\n");
return;
exit_clear_intr:
/* clear the function's interrupt request bit (write 1 to clear) */
sdio_writeb(func, 1, IWMC_SDIO_INTR_CLEAR_ADDR, &ret);
}
static int blocks;
module_param(blocks, int, 0604);
MODULE_PARM_DESC(blocks, "max_blocks_to_send");
static int dump;
module_param(dump, bool, 0604);
MODULE_PARM_DESC(dump, "dump_hex_content");
static int jump = 1;
module_param(jump, bool, 0604);
static int direct = 1;
module_param(direct, bool, 0604);
static int checksum = 1;
module_param(checksum, bool, 0604);
static int fw_download = 1;
module_param(fw_download, bool, 0604);
static int block_size = IWMC_SDIO_BLK_SIZE;
module_param(block_size, int, 0404);
static int download_trans_blks = IWMC_DEFAULT_TR_BLK;
module_param(download_trans_blks, int, 0604);
static int rubbish_barker;
module_param(rubbish_barker, bool, 0604);
#ifdef CONFIG_IWMC3200TOP_DEBUG
static int log_level[LOG_SRC_MAX];
static unsigned int log_level_argc;
module_param_array(log_level, int, &log_level_argc, 0604);
MODULE_PARM_DESC(log_level, "log_level");
static int log_level_fw[FW_LOG_SRC_MAX];
static unsigned int log_level_fw_argc;
module_param_array(log_level_fw, int, &log_level_fw_argc, 0604);
MODULE_PARM_DESC(log_level_fw, "log_level_fw");
#endif
void iwmct_dbg_init_params(struct iwmct_priv *priv)
{
#ifdef CONFIG_IWMC3200TOP_DEBUG
int i;
for (i = 0; i < log_level_argc; i++) {
dev_notice(&priv->func->dev, "log_level[%d]=0x%X\n",
i, log_level[i]);
iwmct_log_set_filter((log_level[i] >> 8) & 0xFF,
log_level[i] & 0xFF);
}
for (i = 0; i < log_level_fw_argc; i++) {
dev_notice(&priv->func->dev, "log_level_fw[%d]=0x%X\n",
i, log_level_fw[i]);
iwmct_log_set_fw_filter((log_level_fw[i] >> 8) & 0xFF,
log_level_fw[i] & 0xFF);
}
#endif
priv->dbg.blocks = blocks;
LOG_INFO(priv, INIT, "blocks=%d\n", blocks);
priv->dbg.dump = (bool)dump;
LOG_INFO(priv, INIT, "dump=%d\n", dump);
priv->dbg.jump = (bool)jump;
LOG_INFO(priv, INIT, "jump=%d\n", jump);
priv->dbg.direct = (bool)direct;
LOG_INFO(priv, INIT, "direct=%d\n", direct);
priv->dbg.checksum = (bool)checksum;
LOG_INFO(priv, INIT, "checksum=%d\n", checksum);
priv->dbg.fw_download = (bool)fw_download;
LOG_INFO(priv, INIT, "fw_download=%d\n", fw_download);
priv->dbg.block_size = block_size;
LOG_INFO(priv, INIT, "block_size=%d\n", block_size);
priv->dbg.download_trans_blks = download_trans_blks;
LOG_INFO(priv, INIT, "download_trans_blks=%d\n", download_trans_blks);
}
/*****************************************************************************
*
* sysfs attributes
*
*****************************************************************************/
static ssize_t show_iwmct_fw_version(struct device *d,
struct device_attribute *attr, char *buf)
{
struct iwmct_priv *priv = dev_get_drvdata(d);
return sprintf(buf, "%s\n", priv->dbg.label_fw);
}
static DEVICE_ATTR(cc_label_fw, S_IRUGO, show_iwmct_fw_version, NULL);
#ifdef CONFIG_IWMC3200TOP_DEBUG
static DEVICE_ATTR(log_level, S_IWUSR | S_IRUGO,
show_iwmct_log_level, store_iwmct_log_level);
static DEVICE_ATTR(log_level_fw, S_IWUSR | S_IRUGO,
show_iwmct_log_level_fw, store_iwmct_log_level_fw);
#endif
static struct attribute *iwmct_sysfs_entries[] = {
&dev_attr_cc_label_fw.attr,
#ifdef CONFIG_IWMC3200TOP_DEBUG
&dev_attr_log_level.attr,
&dev_attr_log_level_fw.attr,
#endif
NULL
};
static struct attribute_group iwmct_attribute_group = {
.name = NULL, /* put in device directory */
.attrs = iwmct_sysfs_entries,
};
static int iwmct_probe(struct sdio_func *func,
const struct sdio_device_id *id)
{
struct iwmct_priv *priv;
int ret;
int val = 1;
int addr = IWMC_SDIO_INTR_ENABLE_ADDR;
dev_dbg(&func->dev, "enter iwmct_probe\n");
dev_dbg(&func->dev, "IRQ polling period id %u msecs, HZ is %d\n",
jiffies_to_msecs(2147483647), HZ);
priv = kzalloc(sizeof(struct iwmct_priv), GFP_KERNEL);
if (!priv) {
dev_err(&func->dev, "kzalloc error\n");
return -ENOMEM;
}
priv->func = func;
sdio_set_drvdata(func, priv);
/* create drivers work queue */
priv->wq = create_workqueue(DRV_NAME "_wq");
priv->bus_rescan_wq = create_workqueue(DRV_NAME "_rescan_wq");
INIT_WORK(&priv->bus_rescan_worker, iwmct_rescan_worker);
INIT_WORK(&priv->isr_worker, iwmct_irq_read_worker);
init_waitqueue_head(&priv->wait_q);
sdio_claim_host(func);
/* FIXME: Remove after it is fixed in the Boot ROM upgrade */
func->enable_timeout = 10;
/* In our HW, setting the block size also wakes up the boot rom. */
ret = sdio_set_block_size(func, priv->dbg.block_size);
if (ret) {
LOG_ERROR(priv, INIT,
"sdio_set_block_size() failure: %d\n", ret);
goto error_sdio_enable;
}
ret = sdio_enable_func(func);
if (ret) {
LOG_ERROR(priv, INIT, "sdio_enable_func() failure: %d\n", ret);
goto error_sdio_enable;
}
/* init reset and dev_sync states */
atomic_set(&priv->reset, 0);
atomic_set(&priv->dev_sync, 0);
/* init read req queue */
INIT_LIST_HEAD(&priv->read_req_list);
/* process configurable parameters */
iwmct_dbg_init_params(priv);
ret = sysfs_create_group(&func->dev.kobj, &iwmct_attribute_group);
if (ret) {
LOG_ERROR(priv, INIT, "Failed to register attributes and "
"initialize module_params\n");
goto error_dev_attrs;
}
iwmct_dbgfs_register(priv, DRV_NAME);
if (!priv->dbg.direct && priv->dbg.download_trans_blks > 8) {
LOG_INFO(priv, INIT,
"Reducing transaction to 8 blocks = 2K (from %d)\n",
priv->dbg.download_trans_blks);
priv->dbg.download_trans_blks = 8;
}
priv->trans_len = priv->dbg.download_trans_blks * priv->dbg.block_size;
LOG_INFO(priv, INIT, "Transaction length = %d\n", priv->trans_len);
ret = sdio_claim_irq(func, iwmct_irq);
if (ret) {
LOG_ERROR(priv, INIT, "sdio_claim_irq() failure: %d\n", ret);
goto error_claim_irq;
}
/* Enable function's interrupt */
sdio_writeb(priv->func, val, addr, &ret);
if (ret) {
LOG_ERROR(priv, INIT, "Failure writing to "
"Interrupt Enable Register (%d): %d\n", addr, ret);
goto error_enable_int;
}
sdio_release_host(func);
LOG_INFO(priv, INIT, "exit iwmct_probe\n");
return ret;
error_enable_int:
sdio_release_irq(func);
error_claim_irq:
sdio_disable_func(func);
error_dev_attrs:
iwmct_dbgfs_unregister(priv->dbgfs);
sysfs_remove_group(&func->dev.kobj, &iwmct_attribute_group);
error_sdio_enable:
sdio_release_host(func);
return ret;
}
static void iwmct_remove(struct sdio_func *func)
{
struct iwmct_work_struct *read_req;
struct iwmct_priv *priv = sdio_get_drvdata(func);
priv = sdio_get_drvdata(func);
LOG_INFO(priv, INIT, "enter\n");
sdio_claim_host(func);
sdio_release_irq(func);
sdio_release_host(func);
/* Safely destroy osc workqueue */
destroy_workqueue(priv->bus_rescan_wq);
destroy_workqueue(priv->wq);
sdio_claim_host(func);
sdio_disable_func(func);
sysfs_remove_group(&func->dev.kobj, &iwmct_attribute_group);
iwmct_dbgfs_unregister(priv->dbgfs);
sdio_release_host(func);
/* free read requests */
while (!list_empty(&priv->read_req_list)) {
read_req = list_entry(priv->read_req_list.next,
struct iwmct_work_struct, list);
list_del(&read_req->list);
kfree(read_req);
}
kfree(priv);
}
static const struct sdio_device_id iwmct_ids[] = {
/* Intel Wireless MultiCom 3200 Top Driver */
{ SDIO_DEVICE(SDIO_VENDOR_ID_INTEL, 0x1404)},
{ }, /* Terminating entry */
};
MODULE_DEVICE_TABLE(sdio, iwmct_ids);
static struct sdio_driver iwmct_driver = {
.probe = iwmct_probe,
.remove = iwmct_remove,
.name = DRV_NAME,
.id_table = iwmct_ids,
};
static int __init iwmct_init(void)
{
int rc;
/* Default log filter settings */
iwmct_log_set_filter(LOG_SRC_ALL, LOG_SEV_FILTER_RUNTIME);
iwmct_log_set_filter(LOG_SRC_FW_MSG, LOG_SEV_FILTER_ALL);
iwmct_log_set_fw_filter(LOG_SRC_ALL, FW_LOG_SEV_FILTER_RUNTIME);
rc = sdio_register_driver(&iwmct_driver);
return rc;
}
static void __exit iwmct_exit(void)
{
sdio_unregister_driver(&iwmct_driver);
}
module_init(iwmct_init);
module_exit(iwmct_exit);

View File

@ -249,11 +249,11 @@ static int __init el1_probe1(struct net_device *dev, int ioaddr)
* for the Sager NP943 prefix. * for the Sager NP943 prefix.
*/ */
if (station_addr[0] == 0x02 && station_addr[1] == 0x60 if (station_addr[0] == 0x02 && station_addr[1] == 0x60 &&
&& station_addr[2] == 0x8c) station_addr[2] == 0x8c)
mname = "3c501"; mname = "3c501";
else if (station_addr[0] == 0x00 && station_addr[1] == 0x80 else if (station_addr[0] == 0x00 && station_addr[1] == 0x80 &&
&& station_addr[2] == 0xC8) station_addr[2] == 0xC8)
mname = "NP943"; mname = "NP943";
else { else {
release_region(ioaddr, EL1_IO_EXTENT); release_region(ioaddr, EL1_IO_EXTENT);
@ -345,7 +345,7 @@ static int el_open(struct net_device *dev)
if (el_debug > 2) if (el_debug > 2)
pr_debug("%s: Doing el_open()...\n", dev->name); pr_debug("%s: Doing el_open()...\n", dev->name);
retval = request_irq(dev->irq, &el_interrupt, 0, dev->name, dev); retval = request_irq(dev->irq, el_interrupt, 0, dev->name, dev);
if (retval) if (retval)
return retval; return retval;

View File

@ -214,8 +214,8 @@ el2_probe1(struct net_device *dev, int ioaddr)
iobase_reg = inb(ioaddr+0x403); iobase_reg = inb(ioaddr+0x403);
membase_reg = inb(ioaddr+0x404); membase_reg = inb(ioaddr+0x404);
/* ASIC location registers should be 0 or have only a single bit set. */ /* ASIC location registers should be 0 or have only a single bit set. */
if ( (iobase_reg & (iobase_reg - 1)) if ((iobase_reg & (iobase_reg - 1)) ||
|| (membase_reg & (membase_reg - 1))) { (membase_reg & (membase_reg - 1))) {
retval = -ENODEV; retval = -ENODEV;
goto out1; goto out1;
} }
@ -291,8 +291,8 @@ el2_probe1(struct net_device *dev, int ioaddr)
writel(0xba5eba5e, mem_base); writel(0xba5eba5e, mem_base);
for (i = sizeof(test_val); i < EL2_MEMSIZE; i+=sizeof(test_val)) { for (i = sizeof(test_val); i < EL2_MEMSIZE; i+=sizeof(test_val)) {
writel(test_val, mem_base + i); writel(test_val, mem_base + i);
if (readl(mem_base) != 0xba5eba5e if (readl(mem_base) != 0xba5eba5e ||
|| readl(mem_base + i) != test_val) { readl(mem_base + i) != test_val) {
pr_warning("3c503: memory failure or memory address conflict.\n"); pr_warning("3c503: memory failure or memory address conflict.\n");
dev->mem_start = 0; dev->mem_start = 0;
ei_status.name = "3c503-PIO"; ei_status.name = "3c503-PIO";
@ -397,9 +397,10 @@ el2_open(struct net_device *dev)
unsigned long cookie = probe_irq_on(); unsigned long cookie = probe_irq_on();
outb_p(0x04 << ((*irqp == 9) ? 2 : *irqp), E33G_IDCFR); outb_p(0x04 << ((*irqp == 9) ? 2 : *irqp), E33G_IDCFR);
outb_p(0x00, E33G_IDCFR); outb_p(0x00, E33G_IDCFR);
if (*irqp == probe_irq_off(cookie) /* It's a good IRQ line! */ if (*irqp == probe_irq_off(cookie) && /* It's a good IRQ line! */
&& ((retval = request_irq(dev->irq = *irqp, ((retval = request_irq(dev->irq = *irqp,
eip_interrupt, 0, dev->name, dev)) == 0)) eip_interrupt, 0,
dev->name, dev)) == 0))
break; break;
} else { } else {
if (retval != -EBUSY) if (retval != -EBUSY)

View File

@ -886,7 +886,7 @@ static int elp_open(struct net_device *dev)
/* /*
* install our interrupt service routine * install our interrupt service routine
*/ */
if ((retval = request_irq(dev->irq, &elp_interrupt, 0, dev->name, dev))) { if ((retval = request_irq(dev->irq, elp_interrupt, 0, dev->name, dev))) {
pr_err("%s: could not allocate IRQ%d\n", dev->name, dev->irq); pr_err("%s: could not allocate IRQ%d\n", dev->name, dev->irq);
return retval; return retval;
} }

View File

@ -399,7 +399,7 @@ static int __init el16_probe1(struct net_device *dev, int ioaddr)
irq = inb(ioaddr + IRQ_CONFIG) & 0x0f; irq = inb(ioaddr + IRQ_CONFIG) & 0x0f;
irqval = request_irq(irq, &el16_interrupt, 0, DRV_NAME, dev); irqval = request_irq(irq, el16_interrupt, 0, DRV_NAME, dev);
if (irqval) { if (irqval) {
pr_cont("\n"); pr_cont("\n");
pr_err("3c507: unable to get IRQ %d (irqval=%d).\n", irq, irqval); pr_err("3c507: unable to get IRQ %d (irqval=%d).\n", irq, irqval);
@ -836,8 +836,8 @@ static void el16_rx(struct net_device *dev)
void __iomem *data_frame = lp->base + data_buffer_addr; void __iomem *data_frame = lp->base + data_buffer_addr;
ushort pkt_len = readw(data_frame); ushort pkt_len = readw(data_frame);
if (rfd_cmd != 0 || data_buffer_addr != rx_head + 22 if (rfd_cmd != 0 || data_buffer_addr != rx_head + 22 ||
|| (pkt_len & 0xC000) != 0xC000) { (pkt_len & 0xC000) != 0xC000) {
pr_err("%s: Rx frame at %#x corrupted, " pr_err("%s: Rx frame at %#x corrupted, "
"status %04x cmd %04x next %04x " "status %04x cmd %04x next %04x "
"data-buf @%04x %04x.\n", "data-buf @%04x %04x.\n",

View File

@ -253,9 +253,9 @@ static int el3_isa_id_sequence(__be16 *phys_addr)
This check is needed in order not to register them twice. */ This check is needed in order not to register them twice. */
for (i = 0; i < el3_cards; i++) { for (i = 0; i < el3_cards; i++) {
struct el3_private *lp = netdev_priv(el3_devs[i]); struct el3_private *lp = netdev_priv(el3_devs[i]);
if (lp->type == EL3_PNP if (lp->type == EL3_PNP &&
&& !memcmp(phys_addr, el3_devs[i]->dev_addr, !memcmp(phys_addr, el3_devs[i]->dev_addr,
ETH_ALEN)) { ETH_ALEN)) {
if (el3_debug > 3) if (el3_debug > 3)
pr_debug("3c509 with address %02x %02x %02x %02x %02x %02x was found by ISAPnP\n", pr_debug("3c509 with address %02x %02x %02x %02x %02x %02x was found by ISAPnP\n",
phys_addr[0] & 0xff, phys_addr[0] >> 8, phys_addr[0] & 0xff, phys_addr[0] >> 8,
@ -780,7 +780,7 @@ el3_open(struct net_device *dev)
outw(RxReset, ioaddr + EL3_CMD); outw(RxReset, ioaddr + EL3_CMD);
outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD); outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD);
i = request_irq(dev->irq, &el3_interrupt, 0, dev->name, dev); i = request_irq(dev->irq, el3_interrupt, 0, dev->name, dev);
if (i) if (i)
return i; return i;
@ -835,8 +835,8 @@ el3_start_xmit(struct sk_buff *skb, struct net_device *dev)
#ifndef final_version #ifndef final_version
{ /* Error-checking code, delete someday. */ { /* Error-checking code, delete someday. */
ushort status = inw(ioaddr + EL3_STATUS); ushort status = inw(ioaddr + EL3_STATUS);
if (status & 0x0001 /* IRQ line active, missed one. */ if (status & 0x0001 && /* IRQ line active, missed one. */
&& inw(ioaddr + EL3_STATUS) & 1) { /* Make sure. */ inw(ioaddr + EL3_STATUS) & 1) { /* Make sure. */
pr_debug("%s: Missed interrupt, status then %04x now %04x" pr_debug("%s: Missed interrupt, status then %04x now %04x"
" Tx %2.2x Rx %4.4x.\n", dev->name, status, " Tx %2.2x Rx %4.4x.\n", dev->name, status,
inw(ioaddr + EL3_STATUS), inb(ioaddr + TX_STATUS), inw(ioaddr + EL3_STATUS), inb(ioaddr + TX_STATUS),

View File

@ -764,13 +764,14 @@ static int corkscrew_open(struct net_device *dev)
/* Use the now-standard shared IRQ implementation. */ /* Use the now-standard shared IRQ implementation. */
if (vp->capabilities == 0x11c7) { if (vp->capabilities == 0x11c7) {
/* Corkscrew: Cannot share ISA resources. */ /* Corkscrew: Cannot share ISA resources. */
if (dev->irq == 0 if (dev->irq == 0 ||
|| dev->dma == 0 dev->dma == 0 ||
|| request_irq(dev->irq, &corkscrew_interrupt, 0, request_irq(dev->irq, corkscrew_interrupt, 0,
vp->product_name, dev)) return -EAGAIN; vp->product_name, dev))
return -EAGAIN;
enable_dma(dev->dma); enable_dma(dev->dma);
set_dma_mode(dev->dma, DMA_MODE_CASCADE); set_dma_mode(dev->dma, DMA_MODE_CASCADE);
} else if (request_irq(dev->irq, &corkscrew_interrupt, IRQF_SHARED, } else if (request_irq(dev->irq, corkscrew_interrupt, IRQF_SHARED,
vp->product_name, dev)) { vp->product_name, dev)) {
return -EAGAIN; return -EAGAIN;
} }
@ -1368,8 +1369,8 @@ static int boomerang_rx(struct net_device *dev)
/* Check if the packet is long enough to just accept without /* Check if the packet is long enough to just accept without
copying to a properly sized skbuff. */ copying to a properly sized skbuff. */
if (pkt_len < rx_copybreak if (pkt_len < rx_copybreak &&
&& (skb = dev_alloc_skb(pkt_len + 4)) != NULL) { (skb = dev_alloc_skb(pkt_len + 4)) != NULL) {
skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
/* 'skb_put()' points to the start of sk_buff data area. */ /* 'skb_put()' points to the start of sk_buff data area. */
memcpy(skb_put(skb, pkt_len), memcpy(skb_put(skb, pkt_len),

View File

@ -288,7 +288,7 @@ static int elmc_open(struct net_device *dev)
elmc_id_attn586(); /* disable interrupts */ elmc_id_attn586(); /* disable interrupts */
ret = request_irq(dev->irq, &elmc_interrupt, IRQF_SHARED | IRQF_SAMPLE_RANDOM, ret = request_irq(dev->irq, elmc_interrupt, IRQF_SHARED | IRQF_SAMPLE_RANDOM,
dev->name, dev); dev->name, dev);
if (ret) { if (ret) {
pr_err("%s: couldn't get irq %d\n", dev->name, dev->irq); pr_err("%s: couldn't get irq %d\n", dev->name, dev->irq);

View File

@ -443,7 +443,7 @@ static int __init mc32_probe1(struct net_device *dev, int slot)
* Grab the IRQ * Grab the IRQ
*/ */
err = request_irq(dev->irq, &mc32_interrupt, IRQF_SHARED | IRQF_SAMPLE_RANDOM, DRV_NAME, dev); err = request_irq(dev->irq, mc32_interrupt, IRQF_SHARED | IRQF_SAMPLE_RANDOM, DRV_NAME, dev);
if (err) { if (err) {
release_region(dev->base_addr, MC32_IO_EXTENT); release_region(dev->base_addr, MC32_IO_EXTENT);
pr_err("%s: unable to get IRQ %d.\n", DRV_NAME, dev->irq); pr_err("%s: unable to get IRQ %d.\n", DRV_NAME, dev->irq);
@ -1168,8 +1168,8 @@ static void mc32_rx_ring(struct net_device *dev)
/* Try to save time by avoiding a copy on big frames */ /* Try to save time by avoiding a copy on big frames */
if ((length > RX_COPYBREAK) if ((length > RX_COPYBREAK) &&
&& ((newskb=dev_alloc_skb(1532)) != NULL)) ((newskb=dev_alloc_skb(1532)) != NULL))
{ {
skb=lp->rx_ring[rx_ring_tail].skb; skb=lp->rx_ring[rx_ring_tail].skb;
skb_put(skb, length); skb_put(skb, length);

View File

@ -1942,8 +1942,8 @@ vortex_error(struct net_device *dev, int status)
if (status & TxComplete) { /* Really "TxError" for us. */ if (status & TxComplete) { /* Really "TxError" for us. */
tx_status = ioread8(ioaddr + TxStatus); tx_status = ioread8(ioaddr + TxStatus);
/* Presumably a tx-timeout. We must merely re-enable. */ /* Presumably a tx-timeout. We must merely re-enable. */
if (vortex_debug > 2 if (vortex_debug > 2 ||
|| (tx_status != 0x88 && vortex_debug > 0)) { (tx_status != 0x88 && vortex_debug > 0)) {
pr_err("%s: Transmit error, Tx status register %2.2x.\n", pr_err("%s: Transmit error, Tx status register %2.2x.\n",
dev->name, tx_status); dev->name, tx_status);
if (tx_status == 0x82) { if (tx_status == 0x82) {
@ -2560,7 +2560,7 @@ boomerang_rx(struct net_device *dev)
struct sk_buff *skb; struct sk_buff *skb;
entry = vp->dirty_rx % RX_RING_SIZE; entry = vp->dirty_rx % RX_RING_SIZE;
if (vp->rx_skbuff[entry] == NULL) { if (vp->rx_skbuff[entry] == NULL) {
skb = netdev_alloc_skb(dev, PKT_BUF_SZ + NET_IP_ALIGN); skb = netdev_alloc_skb_ip_align(dev, PKT_BUF_SZ);
if (skb == NULL) { if (skb == NULL) {
static unsigned long last_jif; static unsigned long last_jif;
if (time_after(jiffies, last_jif + 10 * HZ)) { if (time_after(jiffies, last_jif + 10 * HZ)) {
@ -2572,7 +2572,6 @@ boomerang_rx(struct net_device *dev)
break; /* Bad news! */ break; /* Bad news! */
} }
skb_reserve(skb, NET_IP_ALIGN);
vp->rx_ring[entry].addr = cpu_to_le32(pci_map_single(VORTEX_PCI(vp), skb->data, PKT_BUF_SZ, PCI_DMA_FROMDEVICE)); vp->rx_ring[entry].addr = cpu_to_le32(pci_map_single(VORTEX_PCI(vp), skb->data, PKT_BUF_SZ, PCI_DMA_FROMDEVICE));
vp->rx_skbuff[entry] = skb; vp->rx_skbuff[entry] = skb;
} }

View File

@ -549,14 +549,12 @@ rx_status_loop:
pr_debug("%s: rx slot %d status 0x%x len %d\n", pr_debug("%s: rx slot %d status 0x%x len %d\n",
dev->name, rx_tail, status, len); dev->name, rx_tail, status, len);
new_skb = netdev_alloc_skb(dev, buflen + NET_IP_ALIGN); new_skb = netdev_alloc_skb_ip_align(dev, buflen);
if (!new_skb) { if (!new_skb) {
dev->stats.rx_dropped++; dev->stats.rx_dropped++;
goto rx_next; goto rx_next;
} }
skb_reserve(new_skb, NET_IP_ALIGN);
dma_unmap_single(&cp->pdev->dev, mapping, dma_unmap_single(&cp->pdev->dev, mapping,
buflen, PCI_DMA_FROMDEVICE); buflen, PCI_DMA_FROMDEVICE);
@ -911,8 +909,8 @@ static void __cp_set_rx_mode (struct net_device *dev)
AcceptBroadcast | AcceptMulticast | AcceptMyPhys | AcceptBroadcast | AcceptMulticast | AcceptMyPhys |
AcceptAllPhys; AcceptAllPhys;
mc_filter[1] = mc_filter[0] = 0xffffffff; mc_filter[1] = mc_filter[0] = 0xffffffff;
} else if ((dev->mc_count > multicast_filter_limit) } else if ((dev->mc_count > multicast_filter_limit) ||
|| (dev->flags & IFF_ALLMULTI)) { (dev->flags & IFF_ALLMULTI)) {
/* Too many to filter perfectly -- accept all multicasts. */ /* Too many to filter perfectly -- accept all multicasts. */
rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
mc_filter[1] = mc_filter[0] = 0xffffffff; mc_filter[1] = mc_filter[0] = 0xffffffff;
@ -1057,12 +1055,10 @@ static int cp_refill_rx(struct cp_private *cp)
struct sk_buff *skb; struct sk_buff *skb;
dma_addr_t mapping; dma_addr_t mapping;
skb = netdev_alloc_skb(dev, cp->rx_buf_sz + NET_IP_ALIGN); skb = netdev_alloc_skb_ip_align(dev, cp->rx_buf_sz);
if (!skb) if (!skb)
goto err_out; goto err_out;
skb_reserve(skb, NET_IP_ALIGN);
mapping = dma_map_single(&cp->pdev->dev, skb->data, mapping = dma_map_single(&cp->pdev->dev, skb->data,
cp->rx_buf_sz, PCI_DMA_FROMDEVICE); cp->rx_buf_sz, PCI_DMA_FROMDEVICE);
cp->rx_skb[i] = skb; cp->rx_skb[i] = skb;

View File

@ -1549,8 +1549,8 @@ static inline void rtl8139_thread_iter (struct net_device *dev,
mii_lpa = mdio_read (dev, tp->phys[0], MII_LPA); mii_lpa = mdio_read (dev, tp->phys[0], MII_LPA);
if (!tp->mii.force_media && mii_lpa != 0xffff) { if (!tp->mii.force_media && mii_lpa != 0xffff) {
int duplex = (mii_lpa & LPA_100FULL) int duplex = ((mii_lpa & LPA_100FULL) ||
|| (mii_lpa & 0x01C0) == 0x0040; (mii_lpa & 0x01C0) == 0x0040);
if (tp->mii.full_duplex != duplex) { if (tp->mii.full_duplex != duplex) {
tp->mii.full_duplex = duplex; tp->mii.full_duplex = duplex;
@ -1936,8 +1936,8 @@ static int rtl8139_rx(struct net_device *dev, struct rtl8139_private *tp,
RTL_R16 (RxBufAddr), RTL_R16 (RxBufAddr),
RTL_R16 (RxBufPtr), RTL_R8 (ChipCmd)); RTL_R16 (RxBufPtr), RTL_R8 (ChipCmd));
while (netif_running(dev) && received < budget while (netif_running(dev) && received < budget &&
&& (RTL_R8 (ChipCmd) & RxBufEmpty) == 0) { (RTL_R8 (ChipCmd) & RxBufEmpty) == 0) {
u32 ring_offset = cur_rx % RX_BUF_LEN; u32 ring_offset = cur_rx % RX_BUF_LEN;
u32 rx_status; u32 rx_status;
unsigned int pkt_size; unsigned int pkt_size;
@ -2004,9 +2004,8 @@ no_early_rx:
/* Malloc up new buffer, compatible with net-2e. */ /* Malloc up new buffer, compatible with net-2e. */
/* Omit the four octet CRC from the length. */ /* Omit the four octet CRC from the length. */
skb = netdev_alloc_skb(dev, pkt_size + NET_IP_ALIGN); skb = netdev_alloc_skb_ip_align(dev, pkt_size);
if (likely(skb)) { if (likely(skb)) {
skb_reserve (skb, NET_IP_ALIGN); /* 16 byte align the IP fields. */
#if RX_BUF_IDX == 3 #if RX_BUF_IDX == 3
wrap_copy(skb, rx_ring, ring_offset+4, pkt_size); wrap_copy(skb, rx_ring, ring_offset+4, pkt_size);
#else #else
@ -2522,8 +2521,8 @@ static void __set_rx_mode (struct net_device *dev)
AcceptBroadcast | AcceptMulticast | AcceptMyPhys | AcceptBroadcast | AcceptMulticast | AcceptMyPhys |
AcceptAllPhys; AcceptAllPhys;
mc_filter[1] = mc_filter[0] = 0xffffffff; mc_filter[1] = mc_filter[0] = 0xffffffff;
} else if ((dev->mc_count > multicast_filter_limit) } else if ((dev->mc_count > multicast_filter_limit) ||
|| (dev->flags & IFF_ALLMULTI)) { (dev->flags & IFF_ALLMULTI)) {
/* Too many to filter perfectly -- accept all multicasts. */ /* Too many to filter perfectly -- accept all multicasts. */
rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
mc_filter[1] = mc_filter[0] = 0xffffffff; mc_filter[1] = mc_filter[0] = 0xffffffff;

View File

@ -1001,7 +1001,7 @@ config SMC911X
config SMSC911X config SMSC911X
tristate "SMSC LAN911x/LAN921x families embedded ethernet support" tristate "SMSC LAN911x/LAN921x families embedded ethernet support"
depends on ARM || SUPERH || BLACKFIN depends on ARM || SUPERH || BLACKFIN || MIPS
select CRC32 select CRC32
select MII select MII
select PHYLIB select PHYLIB
@ -3235,7 +3235,7 @@ config VIRTIO_NET
config VMXNET3 config VMXNET3
tristate "VMware VMXNET3 ethernet driver" tristate "VMware VMXNET3 ethernet driver"
depends on PCI && X86 && INET depends on PCI && INET
help help
This driver supports VMware's vmxnet3 virtual ethernet NIC. This driver supports VMware's vmxnet3 virtual ethernet NIC.
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the

View File

@ -328,7 +328,7 @@ static int __init cops_probe1(struct net_device *dev, int ioaddr)
/* Reserve any actual interrupt. */ /* Reserve any actual interrupt. */
if (dev->irq) { if (dev->irq) {
retval = request_irq(dev->irq, &cops_interrupt, 0, dev->name, dev); retval = request_irq(dev->irq, cops_interrupt, 0, dev->name, dev);
if (retval) if (retval)
goto err_out; goto err_out;
} }

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